/*
* Copyright (C) 2016 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2017 NXP.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#include <linux/backlight.h>
#include <linux/of_device.h>
#include <linux/of_address.h>
+#include <linux/of_graph.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <video/mipi_display.h>
+#include <video/mxc_edid.h>
#include <linux/mfd/syscon.h>
#include "mipi_dsi.h"
static int mipi_dsi_lcd_init(struct mipi_dsi_info *mipi_dsi,
struct mxc_dispdrv_setting *setting)
{
- int i, size, err;
+ u32 data_lane_num, max_data_rate;
+ int i, size, err = 0;
struct fb_videomode *mipi_lcd_modedb;
struct fb_videomode mode;
struct device *dev = &mipi_dsi->pdev->dev;
+ if (mipi_dsi->encoder) {
+ err = of_property_read_u32(dev->of_node,
+ "data-lanes-num", &data_lane_num);
+ if (err)
+ goto err0;
+
+ err = of_property_read_u32(dev->of_node,
+ "max-data-rate", &max_data_rate);
+ if (err)
+ goto err0;
+
+ mipi_dsi->lcd_config->virtual_ch = 0;
+ mipi_dsi->lcd_config->data_lane_num = data_lane_num;
+ mipi_dsi->lcd_config->max_phy_clk = max_data_rate;
+ mipi_dsi->lcd_config->dpi_fmt = MIPI_RGB888;
+ setting->fbi->var.bits_per_pixel = 32;
+
+ /* TODO Add bandwidth check */
+
+ if (setting->fbi->fbops->fb_check_var)
+ err = setting->fbi->fbops->fb_check_var(&setting->fbi->var,
+ setting->fbi);
+ if (err)
+ goto err0;
+
+ err = fb_add_videomode(mipi_dsi->mode,
+ &setting->fbi->modelist);
+ if (err)
+ goto err0;
+
+ fb_videomode_to_var(&setting->fbi->var, mipi_dsi->mode);
+ setting->fbi->mode = mipi_dsi->mode;
+ err0:
+ return err;
+ }
+
for (i = 0; i < ARRAY_SIZE(mipi_dsi_lcd_db); i++) {
if (!strcmp(mipi_dsi->lcd_panel,
mipi_dsi_lcd_db[i].lcd_panel)) {
return -EINVAL;
}
+ if (mipi_dsi->encoder) {
+ if (req_bit_clk > lcd_config->max_phy_clk)
+ return -EINVAL;
+ }
+
/* PLL out clock = refclk * CM / (CN * CO)
* refclock = 24MHz
* pll vco = 24 * 40 / (3 * 1) = 320MHz
}
writel(lane_num, mipi_dsi->mmio_base + HOST_CFG_NUM_LANES);
- writel(0x1, mipi_dsi->mmio_base + HOST_CFG_NONCONTINUOUS_CLK);
+ writel(mipi_dsi->encoder ? 0x0 : 0x1,
+ mipi_dsi->mmio_base + HOST_CFG_NONCONTINUOUS_CLK);
writel(0x1, mipi_dsi->mmio_base + HOST_CFG_T_PRE);
writel(52, mipi_dsi->mmio_base + HOST_CFG_T_POST);
writel(13, mipi_dsi->mmio_base + HOST_CFG_TX_GAP);
- writel(0x1, mipi_dsi->mmio_base + HOST_CFG_AUTOINSERT_EOTP);
+ writel(mipi_dsi->encoder ? 0x0 : 0x1,
+ mipi_dsi->mmio_base + HOST_CFG_AUTOINSERT_EOTP);
writel(0x0, mipi_dsi->mmio_base + HOST_CFG_EXTRA_CMDS_AFTER_EOTP);
writel(0x0, mipi_dsi->mmio_base + HOST_CFG_HTX_TO_COUNT);
writel(0x0, mipi_dsi->mmio_base + HOST_CFG_LRX_H_TO_COUNT);
writel(pixel_fmt, mipi_dsi->mmio_base + DPI_PIXEL_FORMAT);
writel(0x0, mipi_dsi->mmio_base + DPI_VSYNC_POLARITY);
writel(0x0, mipi_dsi->mmio_base + DPI_HSYNC_POLARITY);
- writel(0x2, mipi_dsi->mmio_base + DPI_VIDEO_MODE);
+ writel(mipi_dsi->encoder ? 0x0 : 0x2,
+ mipi_dsi->mmio_base + DPI_VIDEO_MODE);
writel(mode->right_margin * (bpp >> 3), mipi_dsi->mmio_base + DPI_HFP);
writel(mode->left_margin * (bpp >> 3), mipi_dsi->mmio_base + DPI_HBP);
DSI_CM, 0x0);
msleep(20);
- ret = device_reset(&mipi_dsi->pdev->dev);
- if (ret) {
- dev_err(&mipi_dsi->pdev->dev,
- "failed to reset device: %d\n", ret);
- return -EINVAL;
- }
- msleep(60);
+ if (!mipi_dsi->encoder) {
+ ret = device_reset(&mipi_dsi->pdev->dev);
+ if (ret) {
+ dev_err(&mipi_dsi->pdev->dev,
+ "failed to reset device: %d\n", ret);
+ return -EINVAL;
+ }
+ msleep(60);
- mipi_dsi_init_interrupt(mipi_dsi);
+ mipi_dsi_init_interrupt(mipi_dsi);
- ret = mipi_dsi->lcd_callback->mipi_lcd_setup(mipi_dsi);
- if (ret < 0) {
- dev_err(&mipi_dsi->pdev->dev,
- "failed to init mipi lcd.\n");
- return ret;
+ ret = mipi_dsi->lcd_callback->mipi_lcd_setup(mipi_dsi);
+ if (ret < 0) {
+ dev_err(&mipi_dsi->pdev->dev,
+ "failed to init mipi lcd.\n");
+ return ret;
+ }
+ mipi_dsi_set_mode(mipi_dsi, DSI_HS_MODE);
}
- mipi_dsi_set_mode(mipi_dsi, DSI_HS_MODE);
mipi_dsi->lcd_inited = 1;
} else {
reset_dsi_domains(mipi_dsi, 0);
- ret = mipi_display_exit_sleep(mipi_dsi->disp_mipi);
- if (ret) {
- dev_err(&mipi_dsi->pdev->dev, "exit sleep failed\n");
- return -EINVAL;
+ if (!mipi_dsi->encoder) {
+ ret = mipi_display_exit_sleep(mipi_dsi->disp_mipi);
+ if (ret) {
+ dev_err(&mipi_dsi->pdev->dev, "exit sleep failed\n");
+ return -EINVAL;
+ }
}
}
{
struct mipi_dsi_info *mipi_dsi = mxc_dispdrv_getdata(disp);
- mipi_display_enter_sleep(mipi_dsi->disp_mipi);
+ if (!mipi_dsi->encoder)
+ mipi_display_enter_sleep(mipi_dsi->disp_mipi);
if (fbi->state == FBINFO_STATE_SUSPENDED) {
writel(0x1, mipi_dsi->mmio_base + DPHY_PD_PLL);
{
struct device_node *np = pdev->dev.of_node;
struct mipi_dsi_info *mipi_dsi;
+ struct device_node *endpoint = NULL, *remote;
struct resource *res;
const char *lcd_panel;
int ret = 0;
+ u32 vmode_index;
mipi_dsi = devm_kzalloc(&pdev->dev, sizeof(*mipi_dsi), GFP_KERNEL);
if (!mipi_dsi)
return -EINVAL;
}
+ /* check whether an encoder exists */
+ endpoint = of_graph_get_next_endpoint(np, NULL);
+ if (endpoint) {
+ remote = of_graph_get_remote_port_parent(endpoint);
+ if (!remote)
+ return -EINVAL;
+
+ ret = of_property_read_u32(remote, "video-mode", &vmode_index);
+ if ((ret < 0) || (vmode_index >= ARRAY_SIZE(mxc_cea_mode)))
+ return -EINVAL;
+
+ mipi_dsi->mode = devm_kzalloc(&pdev->dev,
+ sizeof(struct fb_videomode),
+ GFP_KERNEL);
+ if (!mipi_dsi->mode)
+ return -ENOMEM;
+
+ memcpy(mipi_dsi->mode, &mxc_cea_mode[vmode_index],
+ sizeof(struct fb_videomode));
+
+ mipi_dsi->lcd_config = devm_kzalloc(&pdev->dev,
+ sizeof(struct mipi_lcd_config),
+ GFP_KERNEL);
+ if (!mipi_dsi->lcd_config) {
+ kfree(mipi_dsi->mode);
+ return -ENOMEM;
+ }
+
+ mipi_dsi->encoder = 1;
+ }
+
ret = of_property_read_string(np, "lcd_panel", &lcd_panel);
if (ret) {
dev_err(&pdev->dev, "failed to read lcd_panel property\n");
if (mipi_dsi->lcd_inited) {
clk_prepare_enable(mipi_dsi->esc_clk);
- mipi_display_enter_sleep(mipi_dsi->disp_mipi);
+ if (!mipi_dsi->encoder)
+ mipi_display_enter_sleep(mipi_dsi->disp_mipi);
writel(0x1, mipi_dsi->mmio_base + DPHY_PD_PLL);
writel(0x1, mipi_dsi->mmio_base + DPHY_PD_DPHY);