Updating Wfdcfg source (adding extensions)

You may want to update your Wfdcfg source if your display supports specific options that you want to control.

For most part, other than the timing parameters, there's no need to update the Wfdcfg source. However, some displays on some platforms may support specific options that require extensions on the structures or implementation of callbacks. Not all display drivers support the use of callback functions.

Extensions are added by defining an array of wfdcfg_keyval structures. Each extension is identified through a name (key) and data that is associated with it.
struct wfdcfg_keyval {
    const char *key;    /**< Identifier of extension */
    long i;             /**< Data associated to extension */
    void *p;            /**< Data associated to extension */
};
            

Usually, when there are extensions that are platform-specific, these extensions are declared in a separate header file that is not wfdcfg.h. Conventionally, the header file is named wfdcfg_platform.h where platform refers to the platform of your target hardware.

Declaring extensions

If your display can support additional configuration or settings, then you'll declare these extensions as constants in the source header file. Extensions can be added for:
  • devices (wfdcfg_device)
  • ports(wfdcfg_port)
  • modes (wfdcfg_timing)
  • mode lists (wfdcfg_mode_list)
Callback functions

An extension that provides the display driver a function to call when appropriate. An extension for a callback function needs declaration of the following:

  • the name of the extension
  • the prototype of the callback function

For example, the following is a declaration of a callback function extension. This function initializes the port and is to be called when the wfdcfg_port is created.

/**
 * Port initialisation.  If this port extension exists, the WFD driver
 * will call the given function when the port is created.
 *  .p  (of is a pointer to a function of type wfdcfg_ext_fn_port_init_t
 *      (which returns EOK on success or another errno code on failure)
 *  .i must be zero
 */
#define WFDCFG_EXT_FN_PORT_INIT "port_init"
typedef int (wfdcfg_ext_fn_port_init_t)(struct wfdcfg_port*);
                        
Attributes

An extension that provides information for the configuration of the display hardware.

The following are examples of such an extension:

/**
 *  The HSP clock frequency in kHz.  This is a device extension.
 *  .p must be NULL
 *  .i gives the clock speed in kHz.
 */
#define WFDCFG_EXT_HSP_CLOCK_KHZ "hsp_clock_kHz"

/**
 * Specifies the output format.  This is a port extension.
 *  .p must be NULL
 *  .i is a value from enum imx5x_output_formats (default: RGB888)
 */
#define WFDCFG_EXT_OUTPUT_FORMAT "output_format"
enum imx5x_output_formats {
    /* 24 bits (use for 18-bit SPWG too) */
    WFDCFG_OUTPUT_FORMAT_RGB888 = 24,

    /* 18 bits (parallel LCD panels, not LVDS) */
    WFDCFG_OUTPUT_FORMAT_RGB666_PACKED = 18,

    /* 18 bits (LVDS) */
    WFDCFG_OUTPUT_FORMAT_RGB666_SPWG18 = 19,

    /* 16 bits (parallel LCD panels) */
    WFDCFG_OUTPUT_FORMAT_RGB565 = 16,
};
                        

Defining extensions

Definitions of the extensions are usually added to the source file wfdcfg.c. However, you can define them where you see fit, as long as you maintain binary compatibility.

It's generally expected that there are separate lists for the different types of extensions. That is, you'll have one list for each of device, port, mode, and mode list extensions.

The following are examples of different extension definitions:

static const struct wfdcfg_keyval device_exts[] = {
    { WFDCFG_EXT_HSP_CLOCK_KHZ, .i = 200000 },
    { NULL },   // marks end of list
};

static int port_init(struct wfdcfg_port*);

static const struct wfdcfg_keyval port_exts[] = {
    { WFDCFG_EXT_FN_PORT_INIT, .p = WFDCFG_FNPTR(
            &port_init, wfdcfg_ext_fn_port_init_t*) },
    { NULL },   // marks end of list
};

static int
port_init(struct wfdcfg_port *port)
{
    (void)port;
    return EOK;
}

static const struct mode modes[] = {
    {
        // 800x480 @ 60.49 Hz
        .timing = {
            .pixel_clock_kHz = 32264,
            .hpixels = 800, .hfp= 60, .hsw=124, .hbp= 32,  // 1016 total
            .vlines  = 480, .vfp= 33, .vsw=  2, .vbp= 10,  //  525 total
            .flags = WFDCFG_INVERT_VSYNC | WFDCFG_INVERT_HSYNC,
            },
        .ext_list = NULL,
    },
    { .timing = { .pixel_clock_kHz = 0 } }  // marks end of list
};