diff options
Diffstat (limited to 'drivers/video/imx-ipu-v3/imx-ldb.c')
-rw-r--r-- | drivers/video/imx-ipu-v3/imx-ldb.c | 116 |
1 files changed, 88 insertions, 28 deletions
diff --git a/drivers/video/imx-ipu-v3/imx-ldb.c b/drivers/video/imx-ipu-v3/imx-ldb.c index a05bfad8c0..db5f8b631d 100644 --- a/drivers/video/imx-ipu-v3/imx-ldb.c +++ b/drivers/video/imx-ipu-v3/imx-ldb.c @@ -21,10 +21,13 @@ #include <common.h> #include <fb.h> #include <io.h> +#include <of_graph.h> #include <driver.h> #include <malloc.h> #include <errno.h> #include <init.h> +#include <video/vpl.h> +#include <mfd/imx6q-iomuxc-gpr.h> #include <linux/clk.h> #include <linux/err.h> #include <asm-generic/div64.h> @@ -57,13 +60,17 @@ struct imx_ldb_channel { int chno; int mode_valid; struct display_timings *modes; - struct ipu_output output; + struct device_node *remote; + struct vpl vpl; + int output_port; + int datawidth; }; struct imx_ldb_data { void __iomem *base; int (*prepare)(struct imx_ldb_channel *imx_ldb_ch, int di); unsigned ipu_mask; + int have_mux; }; struct imx_ldb { @@ -102,16 +109,11 @@ static const int of_get_data_mapping(struct device_node *np) return -EINVAL; } -static int imx_ldb_prepare(struct ipu_output *output, struct fb_videomode *mode, int di) +static int imx_ldb_prepare(struct imx_ldb_channel *imx_ldb_ch, struct fb_videomode *mode, + int di) { - struct imx_ldb_channel *imx_ldb_ch = container_of(output, struct imx_ldb_channel, output); struct imx_ldb *ldb = imx_ldb_ch->ldb; - if (PICOS2KHZ(mode->pixclock) > 85000) { - dev_warn(ldb->dev, - "%s: mode exceeds 85 MHz pixel clock\n", __func__); - } - ldb->soc_data->prepare(imx_ldb_ch, di); /* FIXME - assumes straight connections DI0 --> CH0, DI1 --> CH1 */ @@ -141,7 +143,20 @@ static int imx_ldb_prepare(struct ipu_output *output, struct fb_videomode *mode, writel(ldb->ldb_ctrl, ldb->base); - return 0; + return vpl_ioctl(&imx_ldb_ch->vpl, imx_ldb_ch->output_port, + VPL_PREPARE, NULL); +} + +static int imx_ldb_enable(struct imx_ldb_channel *imx_ldb_ch, int di) +{ + return vpl_ioctl(&imx_ldb_ch->vpl, imx_ldb_ch->output_port, + VPL_ENABLE, NULL); +} + +static int imx_ldb_disable(struct imx_ldb_channel *imx_ldb_ch, int di) +{ + return vpl_ioctl(&imx_ldb_ch->vpl, imx_ldb_ch->output_port, + VPL_DISABLE, NULL); } static int imx6q_ldb_prepare(struct imx_ldb_channel *imx_ldb_ch, int di) @@ -226,6 +241,7 @@ static struct imx_ldb_data imx_ldb_data_imx6q = { .base = (void *)MX6_IOMUXC_BASE_ADDR + 0x8, .prepare = imx6q_ldb_prepare, .ipu_mask = 0xf, + .have_mux = 1, }; static struct imx_ldb_data imx_ldb_data_imx53 = { @@ -234,9 +250,42 @@ static struct imx_ldb_data imx_ldb_data_imx53 = { .ipu_mask = 0x3, }; -static struct ipu_output_ops imx_ldb_ops = { - .prepare = imx_ldb_prepare, -}; +static int imx_ldb_ioctl(struct vpl *vpl, unsigned int port, + unsigned int cmd, void *data) +{ + struct imx_ldb_channel *imx_ldb_ch = container_of(vpl, + struct imx_ldb_channel, vpl); + int ret; + struct ipu_di_mode *mode; + + switch (cmd) { + case VPL_ENABLE: + ret = vpl_ioctl(vpl, imx_ldb_ch->output_port, cmd, data); + if (ret) + return ret; + return imx_ldb_enable(imx_ldb_ch, port); + case VPL_DISABLE: + ret = vpl_ioctl(vpl, imx_ldb_ch->output_port, cmd, data); + if (ret) + return ret; + return imx_ldb_disable(imx_ldb_ch, port); + case VPL_PREPARE: + ret = vpl_ioctl(vpl, imx_ldb_ch->output_port, cmd, data); + if (ret) + return ret; + return imx_ldb_prepare(imx_ldb_ch, data, port); + case IMX_IPU_VPL_DI_MODE: + mode = data; + + mode->di_clkflags = IPU_DI_CLKMODE_EXT | IPU_DI_CLKMODE_SYNC; + mode->interface_pix_fmt = (imx_ldb_ch->datawidth == 24) ? + V4L2_PIX_FMT_RGB24 : V4L2_PIX_FMT_BGR666; + + return 0; + default: + return vpl_ioctl(vpl, imx_ldb_ch->output_port, cmd, data); + } +} static int imx_ldb_probe(struct device_d *dev) { @@ -245,7 +294,6 @@ static int imx_ldb_probe(struct device_d *dev) struct imx_ldb *imx_ldb; int ret, i; int dual = 0; - int datawidth; int mapping; const struct imx_ldb_data *devtype; @@ -259,6 +307,8 @@ static int imx_ldb_probe(struct device_d *dev) for_each_child_of_node(np, child) { struct imx_ldb_channel *channel; + struct device_node *port; + struct device_node *endpoint; ret = of_property_read_u32(child, "reg", &i); if (ret || i < 0 || i > 1) @@ -275,17 +325,37 @@ static int imx_ldb_probe(struct device_d *dev) channel = &imx_ldb->channel[i]; channel->ldb = imx_ldb; channel->chno = i; + channel->output_port = imx_ldb->soc_data->have_mux ? 4 : 1; + + /* The output port is port@4 with mux or port@1 without mux */ + port = of_graph_get_port_by_id(child, channel->output_port); + if (!port) { + dev_warn(dev, "No port found for %s\n", child->full_name); + continue; + } - ret = of_property_read_u32(child, "fsl,data-width", &datawidth); + endpoint = of_get_child_by_name(port, "endpoint"); + if (!endpoint) { + dev_warn(dev, "No endpoint found on %s\n", port->full_name); + continue; + } + + channel->vpl.node = child; + channel->vpl.ioctl = &imx_ldb_ioctl; + ret = vpl_register(&channel->vpl); + if (ret) + return ret; + + ret = of_property_read_u32(child, "fsl,data-width", &channel->datawidth); if (ret) - datawidth = 0; - else if (datawidth != 18 && datawidth != 24) + channel->datawidth = 0; + else if (channel->datawidth != 18 && channel->datawidth != 24) return -EINVAL; mapping = of_get_data_mapping(child); switch (mapping) { case LVDS_BIT_MAP_SPWG: - if (datawidth == 24) { + if (channel->datawidth == 24) { if (i == 0 || dual) imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24; if (i == 1 || dual) @@ -293,7 +363,7 @@ static int imx_ldb_probe(struct device_d *dev) } break; case LVDS_BIT_MAP_JEIDA: - if (datawidth == 18) { + if (channel->datawidth == 18) { dev_err(dev, "JEIDA standard only supported in 24 bit\n"); return -EINVAL; } @@ -306,16 +376,6 @@ static int imx_ldb_probe(struct device_d *dev) dev_err(dev, "data mapping not specified or invalid\n"); return -EINVAL; } - - channel->output.ops = &imx_ldb_ops; - channel->output.di_clkflags = IPU_DI_CLKMODE_EXT | IPU_DI_CLKMODE_SYNC; - channel->output.out_pixel_fmt = (datawidth == 24) ? - V4L2_PIX_FMT_RGB24 : V4L2_PIX_FMT_BGR666; - channel->output.modes = of_get_display_timings(child); - channel->output.name = asprintf("ldb-%d", i); - channel->output.ipu_mask = devtype->ipu_mask; - - ipu_register_output(&channel->output); } return 0; |