Enable MIPI/DSI support for inteldrm(4). Makes the display on my ASUS
authorkettenis <kettenis@openbsd.org>
Sun, 2 Jul 2017 20:58:55 +0000 (20:58 +0000)
committerkettenis <kettenis@openbsd.org>
Sun, 2 Jul 2017 20:58:55 +0000 (20:58 +0000)
Transformer Book T100HA work (with some ugly error/warning messages).

12 files changed:
sys/dev/pci/drm/drm_linux.h
sys/dev/pci/drm/drm_mipi_dsi.c [new file with mode: 0644]
sys/dev/pci/drm/drm_mipi_dsi.h
sys/dev/pci/drm/drm_panel.c
sys/dev/pci/drm/drm_panel.h
sys/dev/pci/drm/files.drm
sys/dev/pci/drm/i915/intel_bios.c
sys/dev/pci/drm/i915/intel_display.c
sys/dev/pci/drm/i915/intel_dsi.c
sys/dev/pci/drm/i915/intel_dsi.h
sys/dev/pci/drm/i915/intel_dsi_panel_vbt.c
sys/dev/pci/drm/i915/intel_dsi_pll.c

index 2c289e3..8291049 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: drm_linux.h,v 1.51 2017/07/01 16:14:10 kettenis Exp $ */
+/*     $OpenBSD: drm_linux.h,v 1.52 2017/07/02 20:58:55 kettenis Exp $ */
 /*
  * Copyright (c) 2013, 2014, 2015 Mark Kettenis
  *
@@ -266,6 +266,8 @@ bitmap_weight(void *p, u_int n)
 
 #define IS_BUILTIN(x) 1
 
+struct device_node;
+
 struct device_driver {
        struct device *dev;
 };
@@ -505,6 +507,7 @@ PTR_ERR_OR_ZERO(const void *ptr)
 typedef struct rwlock rwlock_t;
 typedef struct mutex spinlock_t;
 #define DEFINE_SPINLOCK(x)     struct mutex x
+#define DEFINE_MUTEX(x)                struct rwlock x
 
 static inline void
 spin_lock_irqsave(struct mutex *mtxp, __unused unsigned long flags)
@@ -1897,6 +1900,14 @@ acpi_status acpi_get_table_with_size(const char *, int, struct acpi_table_header
 #define acpi_video_register()
 #define acpi_video_unregister()
 
+#define MIPI_DSI_V_SYNC_START                  0x01
+#define MIPI_DSI_V_SYNC_END                    0x11
+#define MIPI_DSI_H_SYNC_START                  0x21
+#define MIPI_DSI_H_SYNC_END                    0x31
+#define MIPI_DSI_COLOR_MODE_OFF                        0x02
+#define MIPI_DSI_COLOR_MODE_ON                 0x12
+#define MIPI_DSI_SHUTDOWN_PERIPHERAL           0x22
+#define MIPI_DSI_TURN_ON_PERIPHERAL            0x32
 #define MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM   0x03
 #define MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM   0x13
 #define MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM   0x23
@@ -1906,8 +1917,36 @@ acpi_status acpi_get_table_with_size(const char *, int, struct acpi_table_header
 #define MIPI_DSI_DCS_SHORT_WRITE               0x05
 #define MIPI_DSI_DCS_SHORT_WRITE_PARAM         0x15
 #define MIPI_DSI_DCS_READ                      0x06
+#define MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE        0x37
+#define MIPI_DSI_END_OF_TRANSMISSION           0x08
+#define MIPI_DSI_NULL_PACKET                   0x09
+#define MIPI_DSI_BLANKING_PACKET               0x19
 #define MIPI_DSI_GENERIC_LONG_WRITE            0x29
 #define MIPI_DSI_DCS_LONG_WRITE                        0x39
+#define MIPI_DSI_LOOSELY_PACKED_PIXEL_STREAM_YCBCR20   0x0c
+#define MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR24   0x1c
+#define MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16   0x2c
+#define MIPI_DSI_PACKED_PIXEL_STREAM_30                0x0d
+#define MIPI_DSI_PACKED_PIXEL_STREAM_36                0x1d
+#define MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12   0x3d
+#define MIPI_DSI_PACKED_PIXEL_STREAM_16                0x0e
+#define MIPI_DSI_PACKED_PIXEL_STREAM_18                0x1e
+#define MIPI_DSI_PIXEL_STREAM_3BYTE_18         0x2e
+#define MIPI_DSI_PACKED_PIXEL_STREAM_24                0x3e
+
+#define MIPI_DCS_NOP                           0x00
+#define MIPI_DCS_SOFT_RESET                    0x01
+#define MIPI_DCS_GET_POWER_MODE                        0x0a
+#define MIPI_DCS_GET_PIXEL_FORMAT              0x0c
+#define MIPI_DCS_ENTER_SLEEP_MODE              0x10
+#define MIPI_DCS_EXIT_SLEEP_MODE               0x11
+#define MIPI_DCS_SET_DISPLAY_OFF               0x28
+#define MIPI_DCS_SET_DISPLAY_ON                        0x29
+#define MIPI_DCS_SET_COLUMN_ADDRESS            0x2a
+#define MIPI_DCS_SET_PAGE_ADDRESS              0x2b
+#define MIPI_DCS_SET_TEAR_OFF                  0x34
+#define MIPI_DCS_SET_TEAR_ON                   0x35
+#define MIPI_DCS_SET_PIXEL_FORMAT              0x3a
 
 struct pwm_device;
 
diff --git a/sys/dev/pci/drm/drm_mipi_dsi.c b/sys/dev/pci/drm/drm_mipi_dsi.c
new file mode 100644 (file)
index 0000000..b256b12
--- /dev/null
@@ -0,0 +1,944 @@
+/*
+ * MIPI DSI Bus
+ *
+ * Copyright (C) 2012-2013, Samsung Electronics, Co., Ltd.
+ * Andrzej Hajda <a.hajda@samsung.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <dev/pci/drm/drm_linux.h>
+#include <dev/pci/drm/drm_mipi_dsi.h>
+
+#ifdef __linux__
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+
+#include <video/mipi_display.h>
+#endif
+
+/**
+ * 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.
+ */
+
+#ifdef notyet
+
+static int mipi_dsi_device_match(struct device *dev, struct device_driver *drv)
+{
+       return of_driver_match_device(dev, drv);
+}
+
+static const struct dev_pm_ops mipi_dsi_device_pm_ops = {
+       .runtime_suspend = pm_generic_runtime_suspend,
+       .runtime_resume = pm_generic_runtime_resume,
+       .suspend = pm_generic_suspend,
+       .resume = pm_generic_resume,
+       .freeze = pm_generic_freeze,
+       .thaw = pm_generic_thaw,
+       .poweroff = pm_generic_poweroff,
+       .restore = pm_generic_restore,
+};
+
+static struct bus_type mipi_dsi_bus_type = {
+       .name = "mipi-dsi",
+       .match = mipi_dsi_device_match,
+       .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);
+
+       of_node_put(dev->of_node);
+       kfree(dsi);
+}
+
+static const struct device_type mipi_dsi_device_type = {
+       .release = mipi_dsi_dev_release,
+};
+
+static struct mipi_dsi_device *mipi_dsi_device_alloc(struct mipi_dsi_host *host)
+{
+       struct mipi_dsi_device *dsi;
+
+       dsi = kzalloc(sizeof(*dsi), GFP_KERNEL);
+       if (!dsi)
+               return ERR_PTR(-ENOMEM);
+
+       dsi->host = host;
+       dsi->dev.bus = &mipi_dsi_bus_type;
+       dsi->dev.parent = host->dev;
+       dsi->dev.type = &mipi_dsi_device_type;
+
+       device_initialize(&dsi->dev);
+
+       return dsi;
+}
+
+static int mipi_dsi_device_add(struct mipi_dsi_device *dsi)
+{
+       struct mipi_dsi_host *host = dsi->host;
+
+       dev_set_name(&dsi->dev, "%s.%d", dev_name(host->dev),  dsi->channel);
+
+       return device_add(&dsi->dev);
+}
+
+static struct mipi_dsi_device *
+of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node)
+{
+       struct mipi_dsi_device *dsi;
+       struct device *dev = host->dev;
+       int ret;
+       u32 reg;
+
+       ret = of_property_read_u32(node, "reg", &reg);
+       if (ret) {
+               dev_err(dev, "device node %s has no valid reg property: %d\n",
+                       node->full_name, ret);
+               return ERR_PTR(-EINVAL);
+       }
+
+       if (reg > 3) {
+               dev_err(dev, "device node %s has invalid reg property: %u\n",
+                       node->full_name, reg);
+               return ERR_PTR(-EINVAL);
+       }
+
+       dsi = mipi_dsi_device_alloc(host);
+       if (IS_ERR(dsi)) {
+               dev_err(dev, "failed to allocate DSI device %s: %ld\n",
+                       node->full_name, PTR_ERR(dsi));
+               return dsi;
+       }
+
+       dsi->dev.of_node = of_node_get(node);
+       dsi->channel = reg;
+
+       ret = mipi_dsi_device_add(dsi);
+       if (ret) {
+               dev_err(dev, "failed to add DSI device %s: %d\n",
+                       node->full_name, ret);
+               kfree(dsi);
+               return ERR_PTR(ret);
+       }
+
+       return dsi;
+}
+
+int mipi_dsi_host_register(struct mipi_dsi_host *host)
+{
+       struct device_node *node;
+
+       for_each_available_child_of_node(host->dev->of_node, node) {
+               /* skip nodes without reg property */
+               if (!of_find_property(node, "reg", NULL))
+                       continue;
+               of_mipi_dsi_device_add(host, node);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(mipi_dsi_host_register);
+
+static int mipi_dsi_remove_device_fn(struct device *dev, void *priv)
+{
+       struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev);
+
+       device_unregister(&dsi->dev);
+
+       return 0;
+}
+
+void mipi_dsi_host_unregister(struct mipi_dsi_host *host)
+{
+       device_for_each_child(host->dev, NULL, mipi_dsi_remove_device_fn);
+}
+EXPORT_SYMBOL(mipi_dsi_host_unregister);
+
+#endif
+
+/**
+ * mipi_dsi_attach - attach a DSI device to its DSI host
+ * @dsi: DSI peripheral
+ */
+int mipi_dsi_attach(struct mipi_dsi_device *dsi)
+{
+       const struct mipi_dsi_host_ops *ops = dsi->host->ops;
+
+       if (!ops || !ops->attach)
+               return -ENOSYS;
+
+       return ops->attach(dsi->host, dsi);
+}
+EXPORT_SYMBOL(mipi_dsi_attach);
+
+/**
+ * mipi_dsi_detach - detach a DSI device from its DSI host
+ * @dsi: DSI peripheral
+ */
+int mipi_dsi_detach(struct mipi_dsi_device *dsi)
+{
+       const struct mipi_dsi_host_ops *ops = dsi->host->ops;
+
+       if (!ops || !ops->detach)
+               return -ENOSYS;
+
+       return ops->detach(dsi->host, 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_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.
+ */
+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)
+{
+       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 = msg->tx_buf;
+       } else {
+               const u8 *tx = msg->tx_buf;
+
+               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)
+{
+       struct mipi_dsi_msg msg = {
+               .channel = dsi->channel,
+               .tx_buf = data,
+               .tx_len = len
+       };
+
+       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;
+       }
+
+       return mipi_dsi_device_transfer(dsi, &msg);
+}
+EXPORT_SYMBOL(mipi_dsi_dcs_write_buffer);
+
+/**
+ * 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 peripheral device
+ * @cmd: DCS command
+ * @data: buffer in which to receive data
+ * @len: size of receive buffer
+ *
+ * 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)
+{
+       struct mipi_dsi_msg msg = {
+               .channel = dsi->channel,
+               .type = MIPI_DSI_DCS_READ,
+               .tx_buf = &cmd,
+               .tx_len = 1,
+               .rx_buf = data,
+               .rx_len = len
+       };
+
+       return mipi_dsi_device_transfer(dsi, &msg);
+}
+EXPORT_SYMBOL(mipi_dsi_dcs_read);
+
+/**
+ * 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 0;
+}
+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);
+
+#ifdef notyet
+
+static int mipi_dsi_drv_probe(struct device *dev)
+{
+       struct mipi_dsi_driver *drv = to_mipi_dsi_driver(dev->driver);
+       struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev);
+
+       return drv->probe(dsi);
+}
+
+static int mipi_dsi_drv_remove(struct device *dev)
+{
+       struct mipi_dsi_driver *drv = to_mipi_dsi_driver(dev->driver);
+       struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev);
+
+       return drv->remove(dsi);
+}
+
+static void mipi_dsi_drv_shutdown(struct device *dev)
+{
+       struct mipi_dsi_driver *drv = to_mipi_dsi_driver(dev->driver);
+       struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev);
+
+       drv->shutdown(dsi);
+}
+
+/**
+ * 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_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)
+               drv->driver.remove = mipi_dsi_drv_remove;
+       if (drv->shutdown)
+               drv->driver.shutdown = mipi_dsi_drv_shutdown;
+
+       return driver_register(&drv->driver);
+}
+EXPORT_SYMBOL(mipi_dsi_driver_register_full);
+
+/**
+ * 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)
+{
+       driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL(mipi_dsi_driver_unregister);
+
+static int __init mipi_dsi_bus_init(void)
+{
+       return bus_register(&mipi_dsi_bus_type);
+}
+postcore_initcall(mipi_dsi_bus_init);
+
+MODULE_AUTHOR("Andrzej Hajda <a.hajda@samsung.com>");
+MODULE_DESCRIPTION("MIPI DSI Bus");
+MODULE_LICENSE("GPL and additional rights");
+
+#endif
index f1d8d0d..dc0ff9f 100644 (file)
@@ -12,7 +12,9 @@
 #ifndef __DRM_MIPI_DSI_H__
 #define __DRM_MIPI_DSI_H__
 
+#ifdef __linux__
 #include <linux/device.h>
+#endif
 
 struct mipi_dsi_host;
 struct mipi_dsi_device;
index 2ef988e..8eac0f2 100644 (file)
  * DEALINGS IN THE SOFTWARE.
  */
 
+#ifdef __linux__
 #include <linux/err.h>
 #include <linux/module.h>
+#endif
 
-#include <drm/drm_crtc.h>
-#include <drm/drm_panel.h>
+#include <dev/pci/drm/drmP.h>
+#include <dev/pci/drm/drm_crtc.h>
+#include <dev/pci/drm/drm_panel.h>
 
 static DEFINE_MUTEX(panel_lock);
-static LIST_HEAD(panel_list);
+static DRM_LIST_HEAD(panel_list);
 
 void drm_panel_init(struct drm_panel *panel)
 {
index 13ff44b..110023f 100644 (file)
@@ -24,7 +24,7 @@
 #ifndef __DRM_PANEL_H__
 #define __DRM_PANEL_H__
 
-#include <linux/list.h>
+#include <dev/pci/drm/drm_linux_list.h>
 
 struct drm_connector;
 struct drm_device;
index 7e198bb..0e3acac 100644 (file)
@@ -1,5 +1,5 @@
 # $NetBSD: files.drm,v 1.2 2007/03/28 11:29:37 jmcneill Exp $
-# $OpenBSD: files.drm,v 1.36 2017/07/01 16:14:10 kettenis Exp $
+# $OpenBSD: files.drm,v 1.37 2017/07/02 20:58:55 kettenis Exp $
 
 # direct rendering modules
 define drmbase {[console = -1]}
@@ -29,8 +29,9 @@ file  dev/pci/drm/drm_gem.c                   drm
 file   dev/pci/drm/drm_vma_manager.c           drm
 file   dev/pci/drm/drm_linux.c                 drm
 file   dev/pci/drm/drm_cache.c                 drm & inteldrm
-#file  dev/pci/drm/drm_panel.c                 drm
+file   dev/pci/drm/drm_panel.c                 drm & inteldrm
 file   dev/pci/drm/drm_dp_mst_topology.c       drm
+file   dev/pci/drm/drm_mipi_dsi.c              drm & inteldrm
 file   dev/pci/drm/linux_hdmi.c                drm
 file   dev/pci/drm/linux_list_sort.c           drm
 
@@ -79,9 +80,9 @@ file  dev/pci/drm/i915/intel_ddi.c            inteldrm
 file   dev/pci/drm/i915/intel_display.c        inteldrm
 file   dev/pci/drm/i915/intel_dp.c             inteldrm
 file   dev/pci/drm/i915/intel_dp_mst.c         inteldrm
-#file  dev/pci/drm/i915/intel_dsi.c            inteldrm
-#file  dev/pci/drm/i915/intel_dsi_panel_vbt.c  inteldrm
-#file  dev/pci/drm/i915/intel_dsi_pll.c        inteldrm
+file   dev/pci/drm/i915/intel_dsi.c            inteldrm
+file   dev/pci/drm/i915/intel_dsi_panel_vbt.c  inteldrm
+file   dev/pci/drm/i915/intel_dsi_pll.c        inteldrm
 file   dev/pci/drm/i915/intel_dvo.c            inteldrm
 file   dev/pci/drm/i915/intel_fbc.c            inteldrm
 file   dev/pci/drm/i915/intel_fbdev.c          inteldrm
index 22bd406..ed4807f 100644 (file)
@@ -678,8 +678,6 @@ parse_psr(struct drm_i915_private *dev_priv, const struct bdb_header *bdb)
        dev_priv->vbt.psr.tp2_tp3_wakeup_time = psr_table->tp2_tp3_wakeup_time;
 }
 
-#ifdef notyet
-
 static u8 *goto_next_sequence(u8 *data, int *size)
 {
        u16 len;
@@ -904,8 +902,6 @@ err:
        memset(dev_priv->vbt.dsi.sequence, 0, sizeof(dev_priv->vbt.dsi.sequence));
 }
 
-#endif
-
 static u8 translate_iboost(u8 val)
 {
        static const u8 mapping[] = { 1, 3, 7 }; /* See VBT spec */
@@ -1155,7 +1151,6 @@ parse_device_mapping(struct drm_i915_private *dev_priv,
                        continue;
                }
 
-#ifdef notyet
                if (p_child->common.dvo_port >= DVO_PORT_MIPIA
                    && p_child->common.dvo_port <= DVO_PORT_MIPID
                    &&p_child->common.device_type & DEVICE_TYPE_MIPI_OUTPUT) {
@@ -1163,7 +1158,6 @@ parse_device_mapping(struct drm_i915_private *dev_priv,
                        dev_priv->vbt.has_mipi = 1;
                        dev_priv->vbt.dsi.port = p_child->common.dvo_port;
                }
-#endif
 
                child_dev_ptr = dev_priv->vbt.child_dev + count;
                count++;
@@ -1370,9 +1364,7 @@ intel_parse_bios(struct drm_device *dev)
        parse_driver_features(dev_priv, bdb);
        parse_edp(dev_priv, bdb);
        parse_psr(dev_priv, bdb);
-#ifdef notyet
        parse_mipi(dev_priv, bdb);
-#endif
        parse_ddi_ports(dev_priv, bdb);
 
 #ifdef __linux__
index f48131e..a77cd1f 100644 (file)
@@ -14218,9 +14218,7 @@ static void intel_setup_outputs(struct drm_device *dev)
                                intel_hdmi_init(dev, CHV_HDMID, PORT_D);
                }
 
-#ifdef notyet
                intel_dsi_init(dev);
-#endif
        } else if (!IS_GEN2(dev) && !IS_PINEVIEW(dev)) {
                bool found = false;
 
index 49335f8..3d06538 100644 (file)
  * Author: Jani Nikula <jani.nikula@intel.com>
  */
 
-#include <drm/drmP.h>
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_edid.h>
-#include <drm/i915_drm.h>
-#include <drm/drm_panel.h>
-#include <drm/drm_mipi_dsi.h>
+#include <dev/pci/drm/drmP.h>
+#include <dev/pci/drm/drm_atomic_helper.h>
+#include <dev/pci/drm/drm_crtc.h>
+#include <dev/pci/drm/drm_edid.h>
+#include <dev/pci/drm/i915_drm.h>
+#include <dev/pci/drm/drm_panel.h>
+#include <dev/pci/drm/drm_mipi_dsi.h>
+#ifdef __linux__
 #include <linux/slab.h>
 #include <linux/gpio/consumer.h>
+#endif
 #include "i915_drv.h"
 #include "intel_drv.h"
 #include "intel_dsi.h"
index e6cb252..7ebbda2 100644 (file)
@@ -24,9 +24,9 @@
 #ifndef _INTEL_DSI_H
 #define _INTEL_DSI_H
 
-#include <drm/drmP.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_mipi_dsi.h>
+#include <dev/pci/drm/drmP.h>
+#include <dev/pci/drm/drm_crtc.h>
+#include <dev/pci/drm/drm_mipi_dsi.h>
 #include "intel_drv.h"
 
 /* Dual Link support */
index a8912ae..066a74d 100644 (file)
  *
  */
 
-#include <drm/drmP.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_edid.h>
-#include <drm/i915_drm.h>
-#include <drm/drm_panel.h>
+#include <dev/pci/drm/drmP.h>
+#include <dev/pci/drm/drm_crtc.h>
+#include <dev/pci/drm/drm_edid.h>
+#include <dev/pci/drm/i915_drm.h>
+#include <dev/pci/drm/drm_panel.h>
+#ifdef __linux__
 #include <linux/slab.h>
 #include <video/mipi_display.h>
 #include <asm/intel-mid.h>
 #include <video/mipi_display.h>
+#endif
 #include "i915_drv.h"
 #include "intel_drv.h"
 #include "intel_dsi.h"
index cb3cf39..6e48f72 100644 (file)
@@ -25,7 +25,9 @@
  *     Yogesh Mohan Marimuthu <yogesh.mohan.marimuthu@intel.com>
  */
 
+#ifdef __linux__
 #include <linux/kernel.h>
+#endif
 #include "intel_drv.h"
 #include "i915_drv.h"
 #include "intel_dsi.h"