diff options
author | Dave Airlie <airlied@redhat.com> | 2014-11-15 09:36:13 +1000 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2014-11-15 09:36:13 +1000 |
commit | 8aa3dc3c17f886c14ef6bcb62720832409ded0a6 (patch) | |
tree | 23d14adf55a6522107c8492507cd2acfcf172c99 /drivers/gpu/drm | |
parent | fd172d0c47fddff801d998e38c3efdd236ed082f (diff) | |
parent | 1976dbca047ed73888f9e7a533df899e961e1dc0 (diff) |
Merge tag 'drm/panel/for-3.19-rc1' of git://people.freedesktop.org/~tagr/linux into drm-next
drm/panel: Changes for v3.19-rc1
This contains support for a couple of new panels, updates for some GPIO
API changes and a bunch of updates to the MIPI DSI support that should
make it easier to write panel drivers in the future.
* tag 'drm/panel/for-3.19-rc1' of git://people.freedesktop.org/~tagr/linux: (31 commits)
drm/panel: Add Sharp LQ101R1SX01 support
drm/dsi: Do not require .owner field to be set
drm/dsi: Resolve MIPI DSI device from phandle
drm/dsi: Implement DCS set_{column,page}_address commands
drm/dsi: Implement DCS {get,set}_pixel_format commands
drm/dsi: Implement DCS get_power_mode command
drm/dsi: Implement DCS soft_reset command
drm/dsi: Implement DCS nop command
drm/dsi: Add to DocBook documentation
drm/dsi: Implement some standard DCS commands
drm/dsi: Implement generic read and write commands
drm/panel: s6e8aa0: Use standard MIPI DSI function
drm/dsi: Add mipi_dsi_set_maximum_return_packet_size() helper
drm/dsi: Constify mipi_dsi_msg
drm/dsi: Make mipi_dsi_dcs_{read,write}() symmetrical
drm/dsi: Add DSI transfer helper
drm/dsi: Add message to packet translator
drm/dsi: Introduce packet format helpers
drm/panel: s6e8aa0: Fix build warnings on 64-bit
drm/panel: ld9040: Fix build warnings on 64-bit
...
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r-- | drivers/gpu/drm/drm_mipi_dsi.c | 660 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_dsi.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/Kconfig | 13 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/panel-ld9040.c | 13 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/panel-s6e8aa0.c | 30 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c | 464 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/panel-simple.c | 133 |
8 files changed, 1236 insertions, 80 deletions
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index eb6dfe52cab2..c0644bb865f2 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -35,6 +35,16 @@ #include <video/mipi_display.h> +/** + * DOC: dsi helpers + * + * These functions contain some common logic and helpers to deal with MIPI DSI + * peripherals. + * + * Helpers are provided for a number of standard MIPI DSI command as well as a + * subset of the MIPI DCS command set. + */ + static int mipi_dsi_device_match(struct device *dev, struct device_driver *drv) { return of_driver_match_device(dev, drv); @@ -57,6 +67,29 @@ static struct bus_type mipi_dsi_bus_type = { .pm = &mipi_dsi_device_pm_ops, }; +static int of_device_match(struct device *dev, void *data) +{ + return dev->of_node == data; +} + +/** + * of_find_mipi_dsi_device_by_node() - find the MIPI DSI device matching a + * device tree node + * @np: device tree node + * + * Return: A pointer to the MIPI DSI device corresponding to @np or NULL if no + * such device exists (or has not been registered yet). + */ +struct mipi_dsi_device *of_find_mipi_dsi_device_by_node(struct device_node *np) +{ + struct device *dev; + + dev = bus_find_device(&mipi_dsi_bus_type, NULL, np, of_device_match); + + return dev ? to_mipi_dsi_device(dev) : NULL; +} +EXPORT_SYMBOL(of_find_mipi_dsi_device_by_node); + static void mipi_dsi_dev_release(struct device *dev) { struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev); @@ -198,59 +231,351 @@ int mipi_dsi_detach(struct mipi_dsi_device *dsi) } EXPORT_SYMBOL(mipi_dsi_detach); +static ssize_t mipi_dsi_device_transfer(struct mipi_dsi_device *dsi, + struct mipi_dsi_msg *msg) +{ + const struct mipi_dsi_host_ops *ops = dsi->host->ops; + + if (!ops || !ops->transfer) + return -ENOSYS; + + if (dsi->mode_flags & MIPI_DSI_MODE_LPM) + msg->flags |= MIPI_DSI_MSG_USE_LPM; + + return ops->transfer(dsi->host, msg); +} + /** - * mipi_dsi_dcs_write - send DCS write command - * @dsi: DSI device - * @data: pointer to the command followed by parameters - * @len: length of @data + * mipi_dsi_packet_format_is_short - check if a packet is of the short format + * @type: MIPI DSI data type of the packet + * + * Return: true if the packet for the given data type is a short packet, false + * otherwise. */ -ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, const void *data, - size_t len) +bool mipi_dsi_packet_format_is_short(u8 type) +{ + switch (type) { + case MIPI_DSI_V_SYNC_START: + case MIPI_DSI_V_SYNC_END: + case MIPI_DSI_H_SYNC_START: + case MIPI_DSI_H_SYNC_END: + case MIPI_DSI_END_OF_TRANSMISSION: + case MIPI_DSI_COLOR_MODE_OFF: + case MIPI_DSI_COLOR_MODE_ON: + case MIPI_DSI_SHUTDOWN_PERIPHERAL: + case MIPI_DSI_TURN_ON_PERIPHERAL: + case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM: + case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM: + case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM: + case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM: + case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM: + case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM: + case MIPI_DSI_DCS_SHORT_WRITE: + case MIPI_DSI_DCS_SHORT_WRITE_PARAM: + case MIPI_DSI_DCS_READ: + case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE: + return true; + } + + return false; +} +EXPORT_SYMBOL(mipi_dsi_packet_format_is_short); + +/** + * mipi_dsi_packet_format_is_long - check if a packet is of the long format + * @type: MIPI DSI data type of the packet + * + * Return: true if the packet for the given data type is a long packet, false + * otherwise. + */ +bool mipi_dsi_packet_format_is_long(u8 type) +{ + switch (type) { + case MIPI_DSI_NULL_PACKET: + case MIPI_DSI_BLANKING_PACKET: + case MIPI_DSI_GENERIC_LONG_WRITE: + case MIPI_DSI_DCS_LONG_WRITE: + case MIPI_DSI_LOOSELY_PACKED_PIXEL_STREAM_YCBCR20: + case MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR24: + case MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16: + case MIPI_DSI_PACKED_PIXEL_STREAM_30: + case MIPI_DSI_PACKED_PIXEL_STREAM_36: + case MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12: + case MIPI_DSI_PACKED_PIXEL_STREAM_16: + case MIPI_DSI_PACKED_PIXEL_STREAM_18: + case MIPI_DSI_PIXEL_STREAM_3BYTE_18: + case MIPI_DSI_PACKED_PIXEL_STREAM_24: + return true; + } + + return false; +} +EXPORT_SYMBOL(mipi_dsi_packet_format_is_long); + +/** + * mipi_dsi_create_packet - create a packet from a message according to the + * DSI protocol + * @packet: pointer to a DSI packet structure + * @msg: message to translate into a packet + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_create_packet(struct mipi_dsi_packet *packet, + const struct mipi_dsi_msg *msg) +{ + const u8 *tx = msg->tx_buf; + + if (!packet || !msg) + return -EINVAL; + + /* do some minimum sanity checking */ + if (!mipi_dsi_packet_format_is_short(msg->type) && + !mipi_dsi_packet_format_is_long(msg->type)) + return -EINVAL; + + if (msg->channel > 3) + return -EINVAL; + + memset(packet, 0, sizeof(*packet)); + packet->header[0] = ((msg->channel & 0x3) << 6) | (msg->type & 0x3f); + + /* TODO: compute ECC if hardware support is not available */ + + /* + * Long write packets contain the word count in header bytes 1 and 2. + * The payload follows the header and is word count bytes long. + * + * Short write packets encode up to two parameters in header bytes 1 + * and 2. + */ + if (mipi_dsi_packet_format_is_long(msg->type)) { + packet->header[1] = (msg->tx_len >> 0) & 0xff; + packet->header[2] = (msg->tx_len >> 8) & 0xff; + + packet->payload_length = msg->tx_len; + packet->payload = tx; + } else { + packet->header[1] = (msg->tx_len > 0) ? tx[0] : 0; + packet->header[2] = (msg->tx_len > 1) ? tx[1] : 0; + } + + packet->size = sizeof(packet->header) + packet->payload_length; + + return 0; +} +EXPORT_SYMBOL(mipi_dsi_create_packet); + +/* + * mipi_dsi_set_maximum_return_packet_size() - specify the maximum size of the + * the payload in a long packet transmitted from the peripheral back to the + * host processor + * @dsi: DSI peripheral device + * @value: the maximum size of the payload + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_set_maximum_return_packet_size(struct mipi_dsi_device *dsi, + u16 value) +{ + u8 tx[2] = { value & 0xff, value >> 8 }; + struct mipi_dsi_msg msg = { + .channel = dsi->channel, + .type = MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, + .tx_len = sizeof(tx), + .tx_buf = tx, + }; + + return mipi_dsi_device_transfer(dsi, &msg); +} +EXPORT_SYMBOL(mipi_dsi_set_maximum_return_packet_size); + +/** + * mipi_dsi_generic_write() - transmit data using a generic write packet + * @dsi: DSI peripheral device + * @payload: buffer containing the payload + * @size: size of payload buffer + * + * This function will automatically choose the right data type depending on + * the payload length. + * + * Return: The number of bytes transmitted on success or a negative error code + * on failure. + */ +ssize_t mipi_dsi_generic_write(struct mipi_dsi_device *dsi, const void *payload, + size_t size) +{ + struct mipi_dsi_msg msg = { + .channel = dsi->channel, + .tx_buf = payload, + .tx_len = size + }; + + switch (size) { + case 0: + msg.type = MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM; + break; + + case 1: + msg.type = MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM; + break; + + case 2: + msg.type = MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM; + break; + + default: + msg.type = MIPI_DSI_GENERIC_LONG_WRITE; + break; + } + + return mipi_dsi_device_transfer(dsi, &msg); +} +EXPORT_SYMBOL(mipi_dsi_generic_write); + +/** + * mipi_dsi_generic_read() - receive data using a generic read packet + * @dsi: DSI peripheral device + * @params: buffer containing the request parameters + * @num_params: number of request parameters + * @data: buffer in which to return the received data + * @size: size of receive buffer + * + * This function will automatically choose the right data type depending on + * the number of parameters passed in. + * + * Return: The number of bytes successfully read or a negative error code on + * failure. + */ +ssize_t mipi_dsi_generic_read(struct mipi_dsi_device *dsi, const void *params, + size_t num_params, void *data, size_t size) +{ + struct mipi_dsi_msg msg = { + .channel = dsi->channel, + .tx_len = num_params, + .tx_buf = params, + .rx_len = size, + .rx_buf = data + }; + + switch (num_params) { + case 0: + msg.type = MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM; + break; + + case 1: + msg.type = MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM; + break; + + case 2: + msg.type = MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM; + break; + + default: + return -EINVAL; + } + + return mipi_dsi_device_transfer(dsi, &msg); +} +EXPORT_SYMBOL(mipi_dsi_generic_read); + +/** + * mipi_dsi_dcs_write_buffer() - transmit a DCS command with payload + * @dsi: DSI peripheral device + * @data: buffer containing data to be transmitted + * @len: size of transmission buffer + * + * This function will automatically choose the right data type depending on + * the command payload length. + * + * Return: The number of bytes successfully transmitted or a negative error + * code on failure. + */ +ssize_t mipi_dsi_dcs_write_buffer(struct mipi_dsi_device *dsi, + const void *data, size_t len) { - const struct mipi_dsi_host_ops *ops = dsi->host->ops; struct mipi_dsi_msg msg = { .channel = dsi->channel, .tx_buf = data, .tx_len = len }; - if (!ops || !ops->transfer) - return -ENOSYS; - switch (len) { case 0: return -EINVAL; + case 1: msg.type = MIPI_DSI_DCS_SHORT_WRITE; break; + case 2: msg.type = MIPI_DSI_DCS_SHORT_WRITE_PARAM; break; + default: msg.type = MIPI_DSI_DCS_LONG_WRITE; break; } - if (dsi->mode_flags & MIPI_DSI_MODE_LPM) - msg.flags = MIPI_DSI_MSG_USE_LPM; + return mipi_dsi_device_transfer(dsi, &msg); +} +EXPORT_SYMBOL(mipi_dsi_dcs_write_buffer); - return ops->transfer(dsi->host, &msg); +/** + * mipi_dsi_dcs_write() - send DCS write command + * @dsi: DSI peripheral device + * @cmd: DCS command + * @data: buffer containing the command payload + * @len: command payload length + * + * This function will automatically choose the right data type depending on + * the command payload length. + * + * Return: The number of bytes successfully transmitted or a negative error + * code on failure. + */ +ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, u8 cmd, + const void *data, size_t len) +{ + ssize_t err; + size_t size; + u8 *tx; + + if (len > 0) { + size = 1 + len; + + tx = kmalloc(size, GFP_KERNEL); + if (!tx) + return -ENOMEM; + + /* concatenate the DCS command byte and the payload */ + tx[0] = cmd; + memcpy(&tx[1], data, len); + } else { + tx = &cmd; + size = 1; + } + + err = mipi_dsi_dcs_write_buffer(dsi, tx, size); + + if (len > 0) + kfree(tx); + + return err; } EXPORT_SYMBOL(mipi_dsi_dcs_write); /** - * mipi_dsi_dcs_read - send DCS read request command - * @dsi: DSI device - * @cmd: DCS read command - * @data: pointer to read buffer - * @len: length of @data + * mipi_dsi_dcs_read() - send DCS read request command + * @dsi: DSI peripheral device + * @cmd: DCS command + * @data: buffer in which to receive data + * @len: size of receive buffer * - * Function returns number of read bytes or error code. + * Return: The number of bytes read or a negative error code on failure. */ ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, u8 cmd, void *data, size_t len) { - const struct mipi_dsi_host_ops *ops = dsi->host->ops; struct mipi_dsi_msg msg = { .channel = dsi->channel, .type = MIPI_DSI_DCS_READ, @@ -260,15 +585,282 @@ ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, u8 cmd, void *data, .rx_len = len }; - if (!ops || !ops->transfer) - return -ENOSYS; + return mipi_dsi_device_transfer(dsi, &msg); +} +EXPORT_SYMBOL(mipi_dsi_dcs_read); - if (dsi->mode_flags & MIPI_DSI_MODE_LPM) - msg.flags = MIPI_DSI_MSG_USE_LPM; +/** + * mipi_dsi_dcs_nop() - send DCS nop packet + * @dsi: DSI peripheral device + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_nop(struct mipi_dsi_device *dsi) +{ + ssize_t err; + + err = mipi_dsi_dcs_write(dsi, MIPI_DCS_NOP, NULL, 0); + if (err < 0) + return err; - return ops->transfer(dsi->host, &msg); + return 0; } -EXPORT_SYMBOL(mipi_dsi_dcs_read); +EXPORT_SYMBOL(mipi_dsi_dcs_nop); + +/** + * mipi_dsi_dcs_soft_reset() - perform a software reset of the display module + * @dsi: DSI peripheral device + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_soft_reset(struct mipi_dsi_device *dsi) +{ + ssize_t err; + + err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SOFT_RESET, NULL, 0); + if (err < 0) + return err; + + return 0; +} +EXPORT_SYMBOL(mipi_dsi_dcs_soft_reset); + +/** + * mipi_dsi_dcs_get_power_mode() - query the display module's current power + * mode + * @dsi: DSI peripheral device + * @mode: return location for the current power mode + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_get_power_mode(struct mipi_dsi_device *dsi, u8 *mode) +{ + ssize_t err; + + err = mipi_dsi_dcs_read(dsi, MIPI_DCS_GET_POWER_MODE, mode, + sizeof(*mode)); + if (err <= 0) { + if (err == 0) + err = -ENODATA; + + return err; + } + + return 0; +} +EXPORT_SYMBOL(mipi_dsi_dcs_get_power_mode); + +/** + * mipi_dsi_dcs_get_pixel_format() - gets the pixel format for the RGB image + * data used by the interface + * @dsi: DSI peripheral device + * @format: return location for the pixel format + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_get_pixel_format(struct mipi_dsi_device *dsi, u8 *format) +{ + ssize_t err; + + err = mipi_dsi_dcs_read(dsi, MIPI_DCS_GET_PIXEL_FORMAT, format, + sizeof(*format)); + if (err <= 0) { + if (err == 0) + err = -ENODATA; + + return err; + } + + return 0; +} +EXPORT_SYMBOL(mipi_dsi_dcs_get_pixel_format); + +/** + * mipi_dsi_dcs_enter_sleep_mode() - disable all unnecessary blocks inside the + * display module except interface communication + * @dsi: DSI peripheral device + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_enter_sleep_mode(struct mipi_dsi_device *dsi) +{ + ssize_t err; + + err = mipi_dsi_dcs_write(dsi, MIPI_DCS_ENTER_SLEEP_MODE, NULL, 0); + if (err < 0) + return err; + + return 0; +} +EXPORT_SYMBOL(mipi_dsi_dcs_enter_sleep_mode); + +/** + * mipi_dsi_dcs_exit_sleep_mode() - enable all blocks inside the display + * module + * @dsi: DSI peripheral device + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_exit_sleep_mode(struct mipi_dsi_device *dsi) +{ + ssize_t err; + + err = mipi_dsi_dcs_write(dsi, MIPI_DCS_EXIT_SLEEP_MODE, NULL, 0); + if (err < 0) + return err; + + return 0; +} +EXPORT_SYMBOL(mipi_dsi_dcs_exit_sleep_mode); + +/** + * mipi_dsi_dcs_set_display_off() - stop displaying the image data on the + * display device + * @dsi: DSI peripheral device + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_set_display_off(struct mipi_dsi_device *dsi) +{ + ssize_t err; + + err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_OFF, NULL, 0); + if (err < 0) + return err; + + return 0; +} +EXPORT_SYMBOL(mipi_dsi_dcs_set_display_off); + +/** + * mipi_dsi_dcs_set_display_on() - start displaying the image data on the + * display device + * @dsi: DSI peripheral device + * + * Return: 0 on success or a negative error code on failure + */ +int mipi_dsi_dcs_set_display_on(struct mipi_dsi_device *dsi) +{ + ssize_t err; + + err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_ON, NULL, 0); + if (err < 0) + return err; + + return 0; +} +EXPORT_SYMBOL(mipi_dsi_dcs_set_display_on); + +/** + * mipi_dsi_dcs_set_column_address() - define the column extent of the frame + * memory accessed by the host processor + * @dsi: DSI peripheral device + * @start: first column of frame memory + * @end: last column of frame memory + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_set_column_address(struct mipi_dsi_device *dsi, u16 start, + u16 end) +{ + u8 payload[4] = { start >> 8, start & 0xff, end >> 8, end & 0xff }; + ssize_t err; + + err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_COLUMN_ADDRESS, payload, + sizeof(payload)); + if (err < 0) + return err; + + return 0; +} +EXPORT_SYMBOL(mipi_dsi_dcs_set_column_address); + +/** + * mipi_dsi_dcs_set_page_address() - define the page extent of the frame + * memory accessed by the host processor + * @dsi: DSI peripheral device + * @start: first page of frame memory + * @end: last page of frame memory + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_set_page_address(struct mipi_dsi_device *dsi, u16 start, + u16 end) +{ + u8 payload[4] = { start >> 8, start & 0xff, end >> 8, end & 0xff }; + ssize_t err; + + err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_PAGE_ADDRESS, payload, + sizeof(payload)); + if (err < 0) + return err; + + return 0; +} +EXPORT_SYMBOL(mipi_dsi_dcs_set_page_address); + +/** + * mipi_dsi_dcs_set_tear_off() - turn off the display module's Tearing Effect + * output signal on the TE signal line + * @dsi: DSI peripheral device + * + * Return: 0 on success or a negative error code on failure + */ +int mipi_dsi_dcs_set_tear_off(struct mipi_dsi_device *dsi) +{ + ssize_t err; + + err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_TEAR_OFF, NULL, 0); + if (err < 0) + return err; + + return 0; +} +EXPORT_SYMBOL(mipi_dsi_dcs_set_tear_off); + +/** + * mipi_dsi_dcs_set_tear_on() - turn on the display module's Tearing Effect + * output signal on the TE signal line. + * @dsi: DSI peripheral device + * @mode: the Tearing Effect Output Line mode + * + * Return: 0 on success or a negative error code on failure + */ +int mipi_dsi_dcs_set_tear_on(struct mipi_dsi_device *dsi, + enum mipi_dsi_dcs_tear_mode mode) +{ + u8 value = mode; + ssize_t err; + + err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_TEAR_ON, &value, + sizeof(value)); + if (err < 0) + return err; + + return 0; +} +EXPORT_SYMBOL(mipi_dsi_dcs_set_tear_on); + +/** + * mipi_dsi_dcs_set_pixel_format() - sets the pixel format for the RGB image + * data used by the interface + * @dsi: DSI peripheral device + * @format: pixel format + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_set_pixel_format(struct mipi_dsi_device *dsi, u8 format) +{ + ssize_t err; + + err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_PIXEL_FORMAT, &format, + sizeof(format)); + if (err < 0) + return err; + + return 0; +} +EXPORT_SYMBOL(mipi_dsi_dcs_set_pixel_format); static int mipi_dsi_drv_probe(struct device *dev) { @@ -295,12 +887,18 @@ static void mipi_dsi_drv_shutdown(struct device *dev) } /** - * mipi_dsi_driver_register - register a driver for DSI devices + * mipi_dsi_driver_register_full() - register a driver for DSI devices * @drv: DSI driver structure + * @owner: owner module + * + * Return: 0 on success or a negative error code on failure. */ -int mipi_dsi_driver_register(struct mipi_dsi_driver *drv) +int mipi_dsi_driver_register_full(struct mipi_dsi_driver *drv, + struct module *owner) { drv->driver.bus = &mipi_dsi_bus_type; + drv->driver.owner = owner; + if (drv->probe) drv->driver.probe = mipi_dsi_drv_probe; if (drv->remove) @@ -310,11 +908,13 @@ int mipi_dsi_driver_register(struct mipi_dsi_driver *drv) return driver_register(&drv->driver); } -EXPORT_SYMBOL(mipi_dsi_driver_register); +EXPORT_SYMBOL(mipi_dsi_driver_register_full); /** - * mipi_dsi_driver_unregister - unregister a driver for DSI devices + * mipi_dsi_driver_unregister() - unregister a driver for DSI devices * @drv: DSI driver structure + * + * Return: 0 on success or a negative error code on failure. */ void mipi_dsi_driver_unregister(struct mipi_dsi_driver *drv) { diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index acf7e9e39dcd..f43d25896f3b 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -1236,7 +1236,7 @@ static bool exynos_dsi_is_short_dsi_type(u8 type) } static ssize_t exynos_dsi_host_transfer(struct mipi_dsi_host *host, - struct mipi_dsi_msg *msg) + const struct mipi_dsi_msg *msg) { struct exynos_dsi *dsi = host_to_dsi(host); struct exynos_dsi_transfer xfer; diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index bee9f72b3a93..024e98ef8e4d 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -27,4 +27,17 @@ config DRM_PANEL_S6E8AA0 select DRM_MIPI_DSI select VIDEOMODE_HELPERS +config DRM_PANEL_SHARP_LQ101R1SX01 + tristate "Sharp LQ101R1SX01 panel" + depends on OF + depends on DRM_MIPI_DSI + help + Say Y here if you want to enable support for Sharp LQ101R1SX01 + TFT-LCD modules. The panel has a 2560x1600 resolution and uses + 24 bit RGB per pixel. It provides a dual MIPI DSI interface to + the host and has a built-in LED backlight. + + To compile this driver as a module, choose M here: the module + will be called panel-sharp-lq101r1sx01. + endmenu diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index 8b929212fad7..4b2a0430804b 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o obj-$(CONFIG_DRM_PANEL_LD9040) += panel-ld9040.o obj-$(CONFIG_DRM_PANEL_S6E8AA0) += panel-s6e8aa0.o +obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o diff --git a/drivers/gpu/drm/panel/panel-ld9040.c b/drivers/gpu/drm/panel/panel-ld9040.c index 42ac67b21e9f..08cf2c588c3d 100644 --- a/drivers/gpu/drm/panel/panel-ld9040.c +++ b/drivers/gpu/drm/panel/panel-ld9040.c @@ -145,7 +145,7 @@ static void ld9040_dcs_write(struct ld9040 *ctx, const u8 *data, size_t len) if (ctx->error < 0 || len == 0) return; - dev_dbg(ctx->dev, "writing dcs seq: %*ph\n", len, data); + dev_dbg(ctx->dev, "writing dcs seq: %*ph\n", (int)len, data); ret = ld9040_spi_write_word(ctx, *data); while (!ret && --len) { @@ -154,8 +154,8 @@ static void ld9040_dcs_write(struct ld9040 *ctx, const u8 *data, size_t len) } if (ret) { - dev_err(ctx->dev, "error %d writing dcs seq: %*ph\n", ret, len, - data); + dev_err(ctx->dev, "error %d writing dcs seq: %*ph\n", ret, + (int)len, data); ctx->error = ret; } @@ -336,17 +336,12 @@ static int ld9040_probe(struct spi_device *spi) if (ret < 0) return ret; - ctx->reset_gpio = devm_gpiod_get(dev, "reset"); + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(ctx->reset_gpio)) { dev_err(dev, "cannot get reset-gpios %ld\n", PTR_ERR(ctx->reset_gpio)); return PTR_ERR(ctx->reset_gpio); } - ret = gpiod_direction_output(ctx->reset_gpio, 1); - if (ret < 0) { - dev_err(dev, "cannot configure reset-gpios %d\n", ret); - return ret; - } spi->bits_per_word = 9; ret = spi_setup(spi); diff --git a/drivers/gpu/drm/panel/panel-s6e8aa0.c b/drivers/gpu/drm/panel/panel-s6e8aa0.c index b5217fe37f02..144b2733e3d7 100644 --- a/drivers/gpu/drm/panel/panel-s6e8aa0.c +++ b/drivers/gpu/drm/panel/panel-s6e8aa0.c @@ -141,10 +141,10 @@ static void s6e8aa0_dcs_write(struct s6e8aa0 *ctx, const void *data, size_t len) if (ctx->error < 0) return; - ret = mipi_dsi_dcs_write(dsi, data, len); + ret = mipi_dsi_dcs_write_buffer(dsi, data, len); if (ret < 0) { - dev_err(ctx->dev, "error %zd writing dcs seq: %*ph\n", ret, len, - data); + dev_err(ctx->dev, "error %zd writing dcs seq: %*ph\n", ret, + (int)len, data); ctx->error = ret; } } @@ -800,27 +800,15 @@ static void s6e8aa0_panel_init(struct s6e8aa0 *ctx) } static void s6e8aa0_set_maximum_return_packet_size(struct s6e8aa0 *ctx, - int size) + u16 size) { struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); - const struct mipi_dsi_host_ops *ops = dsi->host->ops; - u8 buf[] = {size, 0}; - struct mipi_dsi_msg msg = { - .channel = dsi->channel, - .type = MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, - .tx_len = sizeof(buf), - .tx_buf = buf - }; int ret; if (ctx->error < 0) return; - if (!ops || !ops->transfer) - ret = -EIO; - else - ret = ops->transfer(dsi->host, &msg); - + ret = mipi_dsi_set_maximum_return_packet_size(dsi, size); if (ret < 0) { dev_err(ctx->dev, "error %d setting maximum return packet size to %d\n", @@ -1019,17 +1007,12 @@ static int s6e8aa0_probe(struct mipi_dsi_device *dsi) return ret; } - ctx->reset_gpio = devm_gpiod_get(dev, "reset"); + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(ctx->reset_gpio)) { dev_err(dev, "cannot get reset-gpios %ld\n", PTR_ERR(ctx->reset_gpio)); return PTR_ERR(ctx->reset_gpio); } - ret = gpiod_direction_output(ctx->reset_gpio, 1); - if (ret < 0) { - dev_err(dev, "cannot configure reset-gpios %d\n", ret); - return ret; - } ctx->brightness = GAMMA_LEVEL_NUM - 1; @@ -1069,7 +1052,6 @@ static struct mipi_dsi_driver s6e8aa0_driver = { .remove = s6e8aa0_remove, .driver = { .name = "panel_s6e8aa0", - .owner = THIS_MODULE, .of_match_table = s6e8aa0_of_match, }, }; diff --git a/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c b/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c new file mode 100644 index 000000000000..9d81759d82fc --- /dev/null +++ b/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c @@ -0,0 +1,464 @@ +/* + * Copyright (C) 2014 NVIDIA Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/backlight.h> +#include <linux/gpio/consumer.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/regulator/consumer.h> + +#include <drm/drmP.h> +#include <drm/drm_crtc.h> +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_panel.h> + +#include <video/mipi_display.h> + +#include <linux/host1x.h> + +struct sharp_panel { + struct drm_panel base; + /* the datasheet refers to them as DSI-LINK1 and DSI-LINK2 */ + struct mipi_dsi_device *link1; + struct mipi_dsi_device *link2; + + struct backlight_device *backlight; + struct regulator *supply; + + bool prepared; + bool enabled; + + const struct drm_display_mode *mode; +}; + +static inline struct sharp_panel *to_sharp_panel(struct drm_panel *panel) +{ + return container_of(panel, struct sharp_panel, base); +} + +static int sharp_panel_write(struct sharp_panel *sharp, u16 offset, u8 value) +{ + u8 payload[3] = { offset >> 8, offset & 0xff, value }; + struct mipi_dsi_device *dsi = sharp->link1; + ssize_t err; + + err = mipi_dsi_generic_write(dsi, payload, sizeof(payload)); + if (err < 0) { + dev_err(&dsi->dev, "failed to write %02x to %04x: %zd\n", + value, offset, err); + return err; + } + + err = mipi_dsi_dcs_nop(dsi); + if (err < 0) { + dev_err(&dsi->dev, "failed to send DCS nop: %zd\n", err); + return err; + } + + usleep_range(10, 20); + + return 0; +} + +static __maybe_unused int sharp_panel_read(struct sharp_panel *sharp, + u16 offset, u8 *value) +{ + ssize_t err; + + cpu_to_be16s(&offset); + + err = mipi_dsi_generic_read(sharp->link1, &offset, sizeof(offset), + value, sizeof(*value)); + if (err < 0) + dev_err(&sharp->link1->dev, "failed to read from %04x: %zd\n", + offset, err); + + return err; +} + +static int sharp_panel_disable(struct drm_panel *panel) +{ + struct sharp_panel *sharp = to_sharp_panel(panel); + + if (!sharp->enabled) + return 0; + + if (sharp->backlight) { + sharp->backlight->props.power = FB_BLANK_POWERDOWN; + backlight_update_status(sharp->backlight); + } + + sharp->enabled = false; + + return 0; +} + +static int sharp_panel_unprepare(struct drm_panel *panel) +{ + struct sharp_panel *sharp = to_sharp_panel(panel); + int err; + + if (!sharp->prepared) + return 0; + + err = mipi_dsi_dcs_set_display_off(sharp->link1); + if (err < 0) + dev_err(panel->dev, "failed to set display off: %d\n", err); + + err = mipi_dsi_dcs_enter_sleep_mode(sharp->link1); + if (err < 0) + dev_err(panel->dev, "failed to enter sleep mode: %d\n", err); + + msleep(120); + + regulator_disable(sharp->supply); + + sharp->prepared = false; + + return 0; +} + +static int sharp_setup_symmetrical_split(struct mipi_dsi_device *left, + struct mipi_dsi_device *right, + const struct drm_display_mode *mode) +{ + int err; + + err = mipi_dsi_dcs_set_column_address(left, 0, mode->hdisplay / 2 - 1); + if (err < 0) { + dev_err(&left->dev, "failed to set column address: %d\n", err); + return err; + } + + err = mipi_dsi_dcs_set_page_address(left, 0, mode->vdisplay - 1); + if (err < 0) { + dev_err(&left->dev, "failed to set page address: %d\n", err); + return err; + } + + err = mipi_dsi_dcs_set_column_address(right, mode->hdisplay / 2, + mode->hdisplay - 1); + if (err < 0) { + dev_err(&right->dev, "failed to set column address: %d\n", err); + return err; + } + + err = mipi_dsi_dcs_set_page_address(right, 0, mode->vdisplay - 1); + if (err < 0) { + dev_err(&right->dev, "failed to set page address: %d\n", err); + return err; + } + + return 0; +} + +static int sharp_panel_prepare(struct drm_panel *panel) +{ + struct sharp_panel *sharp = to_sharp_panel(panel); + u8 format = MIPI_DCS_PIXEL_FMT_24BIT; + int err; + + if (sharp->prepared) + return 0; + + err = regulator_enable(sharp->supply); + if (err < 0) + return err; + + usleep_range(10000, 20000); + + err = mipi_dsi_dcs_soft_reset(sharp->link1); + if (err < 0) { + dev_err(panel->dev, "soft reset failed: %d\n", err); + goto poweroff; + } + + msleep(120); + + err = mipi_dsi_dcs_exit_sleep_mode(sharp->link1); + if (err < 0) { + dev_err(panel->dev, "failed to exit sleep mode: %d\n", err); + goto poweroff; + } + + /* + * The MIPI DCS specification mandates this delay only between the + * exit_sleep_mode and enter_sleep_mode commands, so it isn't strictly + * necessary here. + */ + /* + msleep(120); + */ + + /* set left-right mode */ + err = sharp_panel_write(sharp, 0x1000, 0x2a); + if (err < 0) { + dev_err(panel->dev, "failed to set left-right mode: %d\n", err); + goto poweroff; + } + + /* enable command mode */ + err = sharp_panel_write(sharp, 0x1001, 0x01); + if (err < 0) { + dev_err(panel->dev, "failed to enable command mode: %d\n", err); + goto poweroff; + } + + err = mipi_dsi_dcs_set_pixel_format(sharp->link1, format); + if (err < 0) { + dev_err(panel->dev, "failed to set pixel format: %d\n", err); + goto poweroff; + } + + /* + * TODO: The device supports both left-right and even-odd split + * configurations, but this driver currently supports only the left- + * right split. To support a different mode a mechanism needs to be + * put in place to communicate the configuration back to the DSI host + * controller. + */ + err = sharp_setup_symmetrical_split(sharp->link1, sharp->link2, + sharp->mode); + if (err < 0) { + dev_err(panel->dev, "failed to set up symmetrical split: %d\n", + err); + goto poweroff; + } + + err = mipi_dsi_dcs_set_display_on(sharp->link1); + if (err < 0) { + dev_err(panel->dev, "failed to set display on: %d\n", err); + goto poweroff; + } + + sharp->prepared = true; + + return 0; + +poweroff: + regulator_disable(sharp->supply); + return err; +} + +static int sharp_panel_enable(struct drm_panel *panel) +{ + struct sharp_panel *sharp = to_sharp_panel(panel); + + if (sharp->enabled) + return 0; + + if (sharp->backlight) { + sharp->backlight->props.power = FB_BLANK_UNBLANK; + backlight_update_status(sharp->backlight); + } + + sharp->enabled = true; + + return 0; +} + +static const struct drm_display_mode default_mode = { + .clock = 278000, + .hdisplay = 2560, + .hsync_start = 2560 + 128, + .hsync_end = 2560 + 128 + 64, + .htotal = 2560 + 128 + 64 + 64, + .vdisplay = 1600, + .vsync_start = 1600 + 4, + .vsync_end = 1600 + 4 + 8, + .vtotal = 1600 + 4 + 8 + 32, + .vrefresh = 60, +}; + +static int sharp_panel_get_modes(struct drm_panel *panel) +{ + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(panel->drm, &default_mode); + if (!mode) { + dev_err(panel->drm->dev, "failed to add mode %ux%ux@%u\n", + default_mode.hdisplay, default_mode.vdisplay, + default_mode.vrefresh); + return -ENOMEM; + } + + drm_mode_set_name(mode); + + drm_mode_probed_add(panel->connector, mode); + + panel->connector->display_info.width_mm = 217; + panel->connector->display_info.height_mm = 136; + + return 1; +} + +static const struct drm_panel_funcs sharp_panel_funcs = { + .disable = sharp_panel_disable, + .unprepare = sharp_panel_unprepare, + .prepare = sharp_panel_prepare, + .enable = sharp_panel_enable, + .get_modes = sharp_panel_get_modes, +}; + +static const struct of_device_id sharp_of_match[] = { + { .compatible = "sharp,lq101r1sx01", }, + { } +}; +MODULE_DEVICE_TABLE(of, sharp_of_match); + +static int sharp_panel_add(struct sharp_panel *sharp) +{ + struct device_node *np; + int err; + + sharp->mode = &default_mode; + + sharp->supply = devm_regulator_get(&sharp->link1->dev, "power"); + if (IS_ERR(sharp->supply)) + return PTR_ERR(sharp->supply); + + np = of_parse_phandle(sharp->link1->dev.of_node, "backlight", 0); + if (np) { + sharp->backlight = of_find_backlight_by_node(np); + of_node_put(np); + + if (!sharp->backlight) + return -EPROBE_DEFER; + } + + drm_panel_init(&sharp->base); + sharp->base.funcs = &sharp_panel_funcs; + sharp->base.dev = &sharp->link1->dev; + + err = drm_panel_add(&sharp->base); + if (err < 0) + goto put_backlight; + + return 0; + +put_backlight: + if (sharp->backlight) + put_device(&sharp->backlight->dev); + + return err; +} + +static void sharp_panel_del(struct sharp_panel *sharp) +{ + if (sharp->base.dev) + drm_panel_remove(&sharp->base); + + if (sharp->backlight) + put_device(&sharp->backlight->dev); + + if (sharp->link2) + put_device(&sharp->link2->dev); +} + +static int sharp_panel_probe(struct mipi_dsi_device *dsi) +{ + struct mipi_dsi_device *secondary = NULL; + struct sharp_panel *sharp; + struct device_node *np; + int err; + + dsi->lanes = 4; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->mode_flags = MIPI_DSI_MODE_LPM; + + /* Find DSI-LINK1 */ + np = of_parse_phandle(dsi->dev.of_node, "link2", 0); + if (np) { + secondary = of_find_mipi_dsi_device_by_node(np); + of_node_put(np); + + if (!secondary) + return -EPROBE_DEFER; + } + + /* register a panel for only the DSI-LINK1 interface */ + if (secondary) { + sharp = devm_kzalloc(&dsi->dev, sizeof(*sharp), GFP_KERNEL); + if (!sharp) { + put_device(&secondary->dev); + return -ENOMEM; + } + + mipi_dsi_set_drvdata(dsi, sharp); + + sharp->link2 = secondary; + sharp->link1 = dsi; + + err = sharp_panel_add(sharp); + if (err < 0) { + put_device(&secondary->dev); + return err; + } + } + + err = mipi_dsi_attach(dsi); + if (err < 0) { + if (secondary) + sharp_panel_del(sharp); + + return err; + } + + return 0; +} + +static int sharp_panel_remove(struct mipi_dsi_device *dsi) +{ + struct sharp_panel *sharp = mipi_dsi_get_drvdata(dsi); + int err; + + /* only detach from host for the DSI-LINK2 interface */ + if (!sharp) { + mipi_dsi_detach(dsi); + return 0; + } + + err = sharp_panel_disable(&sharp->base); + if (err < 0) + dev_err(&dsi->dev, "failed to disable panel: %d\n", err); + + err = mipi_dsi_detach(dsi); + if (err < 0) + dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err); + + drm_panel_detach(&sharp->base); + sharp_panel_del(sharp); + + return 0; +} + +static void sharp_panel_shutdown(struct mipi_dsi_device *dsi) +{ + struct sharp_panel *sharp = mipi_dsi_get_drvdata(dsi); + + /* nothing to do for DSI-LINK2 */ + if (!sharp) + return; + + sharp_panel_disable(&sharp->base); +} + +static struct mipi_dsi_driver sharp_panel_driver = { + .driver = { + .name = "panel-sharp-lq101r1sx01", + .of_match_table = sharp_of_match, + }, + .probe = sharp_panel_probe, + .remove = sharp_panel_remove, + .shutdown = sharp_panel_shutdown, +}; +module_mipi_dsi_driver(sharp_panel_driver); + +MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>"); +MODULE_DESCRIPTION("Sharp LQ101R1SX01 panel driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 23de22f8c820..c4b6167a8bf3 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -247,21 +247,14 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) if (IS_ERR(panel->supply)) return PTR_ERR(panel->supply); - panel->enable_gpio = devm_gpiod_get_optional(dev, "enable"); + panel->enable_gpio = devm_gpiod_get_optional(dev, "enable", + GPIOD_OUT_LOW); if (IS_ERR(panel->enable_gpio)) { err = PTR_ERR(panel->enable_gpio); dev_err(dev, "failed to request GPIO: %d\n", err); return err; } - if (panel->enable_gpio) { - err = gpiod_direction_output(panel->enable_gpio, 0); - if (err < 0) { - dev_err(dev, "failed to setup GPIO: %d\n", err); - return err; - } - } - backlight = of_parse_phandle(dev->of_node, "backlight", 0); if (backlight) { panel->backlight = of_find_backlight_by_node(backlight); @@ -376,6 +369,29 @@ static const struct panel_desc auo_b101xtn01 = { }, }; +static const struct drm_display_mode auo_b116xw03_mode = { + .clock = 70589, + .hdisplay = 1366, + .hsync_start = 1366 + 40, + .hsync_end = 1366 + 40 + 40, + .htotal = 1366 + 40 + 40 + 32, + .vdisplay = 768, + .vsync_start = 768 + 10, + .vsync_end = 768 + 10 + 12, + .vtotal = 768 + 10 + 12 + 6, + .vrefresh = 60, +}; + +static const struct panel_desc auo_b116xw03 = { + .modes = &auo_b116xw03_mode, + .num_modes = 1, + .bpc = 6, + .size = { + .width = 256, + .height = 144, + }, +}; + static const struct drm_display_mode auo_b133xtn01_mode = { .clock = 69500, .hdisplay = 1366, @@ -415,6 +431,7 @@ static const struct drm_display_mode auo_b133htn01_mode = { static const struct panel_desc auo_b133htn01 = { .modes = &auo_b133htn01_mode, .num_modes = 1, + .bpc = 6, .size = { .width = 293, .height = 165, @@ -536,22 +553,92 @@ static const struct drm_display_mode foxlink_fl500wvr00_a0t_mode = { static const struct panel_desc foxlink_fl500wvr00_a0t = { .modes = &foxlink_fl500wvr00_a0t_mode, .num_modes = 1, + .bpc = 8, .size = { .width = 108, .height = 65, }, }; -static const struct drm_display_mode innolux_n116bge_mode = { +static const struct drm_display_mode hannstar_hsd070pww1_mode = { + .clock = 71100, + .hdisplay = 1280, + .hsync_start = 1280 + 1, + .hsync_end = 1280 + 1 + 158, + .htotal = 1280 + 1 + 158 + 1, + .vdisplay = 800, + .vsync_start = 800 + 1, + .vsync_end = 800 + 1 + 21, + .vtotal = 800 + 1 + 21 + 1, + .vrefresh = 60, +}; + +static const struct panel_desc hannstar_hsd070pww1 = { + .modes = &hannstar_hsd070pww1_mode, + .num_modes = 1, + .bpc = 6, + .size = { + .width = 151, + .height = 94, + }, +}; + +static const struct drm_display_mode hitachi_tx23d38vm0caa_mode = { + .clock = 33333, + .hdisplay = 800, + .hsync_start = 800 + 85, + .hsync_end = 800 + 85 + 86, + .htotal = 800 + 85 + 86 + 85, + .vdisplay = 480, + .vsync_start = 480 + 16, + .vsync_end = 480 + 16 + 13, + .vtotal = 480 + 16 + 13 + 16, + .vrefresh = 60, +}; + +static const struct panel_desc hitachi_tx23d38vm0caa = { + .modes = &hitachi_tx23d38vm0caa_mode, + .num_modes = 1, + .bpc = 6, + .size = { + .width = 195, + .height = 117, + }, +}; + +static const struct drm_display_mode innolux_g121i1_l01_mode = { .clock = 71000, + .hdisplay = 1280, + .hsync_start = 1280 + 64, + .hsync_end = 1280 + 64 + 32, + .htotal = 1280 + 64 + 32 + 64, + .vdisplay = 800, + .vsync_start = 800 + 9, + .vsync_end = 800 + 9 + 6, + .vtotal = 800 + 9 + 6 + 9, + .vrefresh = 60, +}; + +static const struct panel_desc innolux_g121i1_l01 = { + .modes = &innolux_g121i1_l01_mode, + .num_modes = 1, + .bpc = 6, + .size = { + .width = 261, + .height = 163, + }, +}; + +static const struct drm_display_mode innolux_n116bge_mode = { + .clock = 76420, .hdisplay = 1366, - .hsync_start = 1366 + 64, - .hsync_end = 1366 + 64 + 6, - .htotal = 1366 + 64 + 6 + 64, + .hsync_start = 1366 + 136, + .hsync_end = 1366 + 136 + 30, + .htotal = 1366 + 136 + 30 + 60, .vdisplay = 768, .vsync_start = 768 + 8, - .vsync_end = 768 + 8 + 4, - .vtotal = 768 + 8 + 4 + 8, + .vsync_end = 768 + 8 + 12, + .vtotal = 768 + 8 + 12 + 12, .vrefresh = 60, .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, }; @@ -643,6 +730,9 @@ static const struct of_device_id platform_of_match[] = { .compatible = "auo,b101xtn01", .data = &auo_b101xtn01, }, { + .compatible = "auo,b116xw03", + .data = &auo_b116xw03, + }, { .compatible = "auo,b133htn01", .data = &auo_b133htn01, }, { @@ -667,6 +757,15 @@ static const struct of_device_id platform_of_match[] = { .compatible = "foxlink,fl500wvr00-a0t", .data = &foxlink_fl500wvr00_a0t, }, { + .compatible = "hannstar,hsd070pww1", + .data = &hannstar_hsd070pww1, + }, { + .compatible = "hit,tx23d38vm0caa", + .data = &hitachi_tx23d38vm0caa + }, { + .compatible ="innolux,g121i1-l01", + .data = &innolux_g121i1_l01 + }, { .compatible = "innolux,n116bge", .data = &innolux_n116bge, }, { @@ -741,6 +840,7 @@ static const struct panel_desc_dsi lg_ld070wx3_sl01 = { .desc = { .modes = &lg_ld070wx3_sl01_mode, .num_modes = 1, + .bpc = 8, .size = { .width = 94, .height = 151, @@ -768,6 +868,7 @@ static const struct panel_desc_dsi lg_lh500wx1_sd03 = { .desc = { .modes = &lg_lh500wx1_sd03_mode, .num_modes = 1, + .bpc = 8, .size = { .width = 62, .height = 110, @@ -795,6 +896,7 @@ static const struct panel_desc_dsi panasonic_vvx10f004b00 = { .desc = { .modes = &panasonic_vvx10f004b00_mode, .num_modes = 1, + .bpc = 8, .size = { .width = 217, .height = 136, @@ -864,7 +966,6 @@ static void panel_simple_dsi_shutdown(struct mipi_dsi_device *dsi) static struct mipi_dsi_driver panel_simple_dsi_driver = { .driver = { .name = "panel-simple-dsi", - .owner = THIS_MODULE, .of_match_table = dsi_of_match, }, .probe = panel_simple_dsi_probe, |