Implement a DPI host in the HLCDC driver. Signed-off-by: Boris Brezillon <boris.brezillon@xxxxxxxxxxxxxxxxxx> --- drivers/gpu/drm/atmel-hlcdc/Kconfig | 1 + drivers/gpu/drm/atmel-hlcdc/Makefile | 1 + drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dpi.c | 212 ++++++++++++++++++++++++++ 3 files changed, 214 insertions(+) create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dpi.c diff --git a/drivers/gpu/drm/atmel-hlcdc/Kconfig b/drivers/gpu/drm/atmel-hlcdc/Kconfig index 942407f..af660e2 100644 --- a/drivers/gpu/drm/atmel-hlcdc/Kconfig +++ b/drivers/gpu/drm/atmel-hlcdc/Kconfig @@ -5,6 +5,7 @@ config DRM_ATMEL_HLCDC select DRM_KMS_HELPER select DRM_KMS_FB_HELPER select DRM_KMS_CMA_HELPER + select DRM_MIPI_DPI select DRM_PANEL select MFD_ATMEL_HLCDC depends on OF diff --git a/drivers/gpu/drm/atmel-hlcdc/Makefile b/drivers/gpu/drm/atmel-hlcdc/Makefile index 10ae426..979e431 100644 --- a/drivers/gpu/drm/atmel-hlcdc/Makefile +++ b/drivers/gpu/drm/atmel-hlcdc/Makefile @@ -1,5 +1,6 @@ atmel-hlcdc-dc-y := atmel_hlcdc_crtc.o \ atmel_hlcdc_dc.o \ + atmel_hlcdc_dpi.o \ atmel_hlcdc_layer.o \ atmel_hlcdc_output.o \ atmel_hlcdc_plane.o diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dpi.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dpi.c new file mode 100644 index 0000000..b563dfc --- /dev/null +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dpi.c @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2014 Free Electrons + * Copyright (C) 2014 Atmel + * + * Author: Boris BREZILLON <boris.brezillon@xxxxxxxxxxxxxxxxxx> + * + * 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. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/of_graph.h> + +#include <drm/drmP.h> +#include <drm/drm_mipi_dpi.h> + +#include "atmel_hlcdc_dc.h" + +enum atmel_hlcdc_output_mode { + ATMEL_HLCDC_OUTPUT_FMT_RGB444, + ATMEL_HLCDC_OUTPUT_FMT_RGB565, + ATMEL_HLCDC_OUTPUT_FMT_RGB666, + ATMEL_HLCDC_OUTPUT_FMT_RGB888, +}; + +struct atmel_hlcdc_dpi_host { + struct mipi_dpi_host base; + struct atmel_hlcdc_dc *dc; +}; + +static inline struct atmel_hlcdc_dpi_host * +to_atmel_hlcdc_dpi_host(struct mipi_dpi_host *host) +{ + return container_of(host, struct atmel_hlcdc_dpi_host, base); +} + +static int atmel_hlcdc_dpi_attach(struct mipi_dpi_host *host, + struct mipi_dpi_device *dpi) +{ + return 0; +} + +static int atmel_hlcdc_dpi_detach(struct mipi_dpi_host *host, + struct mipi_dpi_device *dpi) +{ + return 0; +} + +static int atmel_hlcdc_dpi_best_format_exclusive(struct mipi_dpi_host *host, + enum video_bus_format *format) +{ + struct mipi_dpi_device *dpi; + bool agreed = false; + int i; + + for (i = 0; i < host->num_supported_formats; i++) { + enum video_bus_format hfmt = host->supported_formats[i]; + agreed = true; + + list_for_each_entry(dpi, &host->devices, node) { + int j; + + if (!dpi->enabled) + continue; + + for (j = 0; j < dpi->num_supported_formats; j++) { + if (hfmt == dpi->supported_formats[j]) + break; + } + + if (j == dpi->num_supported_formats) { + agreed = false; + break; + } + } + + if (agreed) { + *format = hfmt; + break; + } + } + + if (!agreed) + return -EINVAL; + + list_for_each_entry(dpi, &host->devices, node) { + if (!dpi->enabled) + continue; + + dpi->next_format = *format; + } + + return 0; +} + +static int +atmel_hlcdc_dpi_best_format_non_exclusive(struct mipi_dpi_host *host, + enum video_bus_format *format) +{ + struct mipi_dpi_device *dpi; + int best_format_index = 0; + + list_for_each_entry(dpi, &host->devices, node) { + int i, j; + + if (!dpi->enabled) + continue; + + for (i = 0; i < host->num_supported_formats; i++) { + enum video_bus_format hfmt = host->supported_formats[i]; + for (j = 0; j < dpi->num_supported_formats; j++) { + if (hfmt == dpi->supported_formats[j]) + break; + } + + if (j < dpi->num_supported_formats) { + dpi->next_format = hfmt; + break; + } + } + + if (i > best_format_index) + best_format_index = i; + } + + *format = host->supported_formats[best_format_index]; + + return 0; +} + +static int atmel_hlcdc_dpi_set_format(struct mipi_dpi_host *h, + enum video_bus_format fmt) +{ + struct atmel_hlcdc_dpi_host *host = to_atmel_hlcdc_dpi_host(h); + unsigned int cfg; + + switch (fmt) { + case VIDEO_BUS_FMT_RGB888_1X24: + cfg = ATMEL_HLCDC_OUTPUT_FMT_RGB888; + break; + case VIDEO_BUS_FMT_RGB666_1X18: + cfg = ATMEL_HLCDC_OUTPUT_FMT_RGB666; + break; + case VIDEO_BUS_FMT_RGB565_1X16: + cfg = ATMEL_HLCDC_OUTPUT_FMT_RGB565; + break; + case VIDEO_BUS_FMT_RGB444_1X12: + cfg = ATMEL_HLCDC_OUTPUT_FMT_RGB444; + break; + default: + return -EINVAL; + } + + regmap_update_bits(host->dc->hlcdc->regmap, ATMEL_HLCDC_CFG(5), + ATMEL_HLCDC_MODE_MASK, + cfg << 8); + + return 0; +} + +static const struct mipi_dpi_host_ops atmel_hlcdc_dpi_host_ops = { + .attach = atmel_hlcdc_dpi_attach, + .detach = atmel_hlcdc_dpi_detach, + .best_format = atmel_hlcdc_dpi_best_format_exclusive, + .set_format = atmel_hlcdc_dpi_set_format, +}; + +static const enum video_bus_format atmel_hlcdc_dpi_supported_formats[] = { + VIDEO_BUS_FMT_RGB888_1X24, + VIDEO_BUS_FMT_RGB666_1X18, + VIDEO_BUS_FMT_RGB565_1X16, + VIDEO_BUS_FMT_RGB444_1X12, +}; + +int atmel_hlcdc_dpi_create(struct drm_device *dev) +{ + struct atmel_hlcdc_dc *dc = dev->dev_private; + struct atmel_hlcdc_dpi_host *dpi; + int ret; + + dpi = devm_kzalloc(dev->dev, sizeof(*dpi), GFP_KERNEL); + if (!dpi) + return -ENOMEM; + + mipi_dpi_host_init(&dpi->base); + + dpi->dc = dc; + dpi->base.ddev = dev; + dpi->base.dev = dev->dev; + dpi->base.supported_formats = atmel_hlcdc_dpi_supported_formats; + dpi->base.num_supported_formats = + ARRAY_SIZE(atmel_hlcdc_dpi_supported_formats); + dpi->base.ops = &atmel_hlcdc_dpi_host_ops; + dpi->base.of_node = of_get_child_by_name(dev->dev->of_node, "dpi"); + dpi->base.possible_crtcs = 0x1; + + ret = mipi_dpi_host_register(&dpi->base); + if (ret) + return ret; + + dc->dpi = &dpi->base; + + return 0; +} -- 1.9.1 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel