msm: mdss: rgb: adding rgb interface driver for qcs405

Add mdss_rgb driver to drive RGB parallel interface
required on qcs405 target. Also added an SPI controller
to transfer panel on/off sequences to RGB panel.

Change-Id: I5479a05aa9e0fbc922dabed9a4b85cec1fa167d3
Signed-off-by: Rashi Bindra <rbindra@codeaurora.org>
Signed-off-by: Narender Ankam <nankam@codeaurora.org>
tirimbino
Narender Ankam 7 years ago
parent 4b54d9aab0
commit f86f7bcd2c
  1. 153
      Documentation/devicetree/bindings/fb/mdss-rgb.txt
  2. 9
      drivers/video/fbdev/msm/Kconfig
  3. 2
      drivers/video/fbdev/msm/Makefile
  4. 4
      drivers/video/fbdev/msm/mdss_dsi.c
  5. 5
      drivers/video/fbdev/msm/mdss_dsi.h
  6. 94
      drivers/video/fbdev/msm/mdss_dsi_clk.c
  7. 42
      drivers/video/fbdev/msm/mdss_dsi_clk.h
  8. 3
      drivers/video/fbdev/msm/mdss_fb.c
  9. 3
      drivers/video/fbdev/msm/mdss_mdp.c
  10. 3
      drivers/video/fbdev/msm/mdss_mdp.h
  11. 35
      drivers/video/fbdev/msm/mdss_mdp_ctl.c
  12. 1
      drivers/video/fbdev/msm/mdss_mdp_hwio.h
  13. 4
      drivers/video/fbdev/msm/mdss_mdp_intf_video.c
  14. 2
      drivers/video/fbdev/msm/mdss_panel.h
  15. 1166
      drivers/video/fbdev/msm/mdss_rgb.c
  16. 104
      drivers/video/fbdev/msm/mdss_rgb.h
  17. 458
      drivers/video/fbdev/msm/mdss_rgb_panel.c

@ -0,0 +1,153 @@
Qualcomm Technologies, Inc. mdss-rgb
mdss-rgb is the master RGB device which supports software RGB interface.
Required properties:
- compatible: Must be "qcom,mdss-rgb"
- ranges: The standard property which specifies the child address
- reg: Base address and length of the different register
regions(s) required for RGB functionality.
- reg-names: A list of strings that map in order to the list of regs.
"dsi_phy" - MDSS DSI PHY register region
"dsi_phy_regulator" - MDSS DSI PHY REGULATOR region
"mmss_misc_phys" - Register region for MMSS DSI clamps
- vdda-supply: Phandle for vdda regulator device node.
- vddio-supply: Phandle for vddio regulator device node.
- qcom,mdss-mdp: pHandle that specifies the mdss-mdp device.
- qcom,mdss-fb-map: pHandle that specifies the framebuffer to which the
- qcom,platform-reset-gpio: Specifies the panel reset gpio.
- pinctrl-names: List of names to assign mdss pin states defined in pinctrl device node
Refer to pinctrl-bindings.txt
- pinctrl-<0..n>: Lists phandles each pointing to the pin configuration node within a pin
controller. These pin configurations are installed in the pinctrl
device node. Refer to pinctrl-bindings.txt
- qcom,<type>-supply-entries: A node that lists the elements of the supply used by the
a particular "type" of RGB modulee. The module "types"
can be "core", "ctrl", and "phy". Within the same type,
there can be more than one instance of this binding,
in which case the entry would be appended with the
supply entry index.
e.g. qcom,ctrl-supply-entry@0
-- qcom,supply-name: name of the supply (vdd/vdda/vddio)
-- qcom,supply-min-voltage: minimum voltage level (uV)
-- qcom,supply-max-voltage: maximum voltage level (uV)
-- qcom,supply-enable-load: load drawn (uA) from enabled supply
-- qcom,supply-disable-load: load drawn (uA) from disabled supply
-- qcom,supply-ulp-load: load drawn (uA) from supply in ultra-low power mode
-- qcom,supply-pre-on-sleep: time to sleep (ms) before turning on
-- qcom,supply-post-on-sleep: time to sleep (ms) after turning on
-- qcom,supply-pre-off-sleep: time to sleep (ms) before turning off
-- qcom,supply-post-off-sleep: time to sleep (ms) after turning off
Example:
mdss_rgb: qcom,mdss_rgb {
compatible = "qcom,mdss-rgb";
#address-cells = <1>;
#size-cells = <1>;
ranges = <0x1a94400 0x1a94400 0x280
0x1a94b80 0x1a94b80 0x30
0x193e000 0x193e000 0x30>;
reg = <0x1a94400 0x280>,
<0x1a94b80 0x30>,
<0x193e000 0x30>;
reg-names = "dsi_phy",
"dsi_phy_regulator", "mmss_misc_phys";
gdsc-supply = <&gdsc_mdss>;
vdda-1p2-supply = <&pms405_l4>;
vdda-1p8-supply = <&pms405_l5>;
vddio-supply = <&pms405_l6>;
qcom,mdss-fb-map = <&mdss_fb0>;
qcom,mdss-mdp = <&mdss_mdp>;
pinctrl-names = "mdss_default", "mdss_sleep";
pinctrl-0 = <&mdss_rgb_active &mdss_rgb_data0_active
&mdss_rgb_data1_active &mdss_rgb_data2_active
&mdss_rgb_data3_active &mdss_rgb_data4_active
&mdss_rgb_data5_active &mdss_rgb_data_b0_active
&mdss_rgb_data_b1_active &mdss_rgb_data_b2_active
&mdss_rgb_data_b3_active &mdss_rgb_data_b4_active
&mdss_rgb_data_b5_active &mdss_rgb_hsync_active
&mdss_rgb_vsync_active &mdss_rgb_de_active
&mdss_rgb_clk_active>;
pinctrl-1 = <&mdss_rgb_suspend &mdss_rgb_data0_suspend
&mdss_rgb_data1_suspend &mdss_rgb_data2_suspend
&mdss_rgb_data3_suspend &mdss_rgb_data4_suspend
&mdss_rgb_data5_suspend &mdss_rgb_data_b0_suspend
&mdss_rgb_data_b1_suspend &mdss_rgb_data_b2_suspend
&mdss_rgb_data_b3_suspend &mdss_rgb_data_b4_suspend
&mdss_rgb_data_b5_suspend &mdss_rgb_hsync_suspend
&mdss_rgb_vsync_suspend &mdss_rgb_de_suspend
&mdss_rgb_clk_suspend>;
qcom,platform-reset-gpio = <&tlmm 58 0>;
qcom,core-supply-entries {
#address-cells = <1>;
#size-cells = <0>;
qcom,core-supply-entry@0 {
reg = <0>;
qcom,supply-name = "gdsc";
qcom,supply-min-voltage = <0>;
qcom,supply-max-voltage = <0>;
qcom,supply-enable-load = <0>;
qcom,supply-disable-load = <0>;
};
};
qcom,ctrl-supply-entries {
#address-cells = <1>;
#size-cells = <0>;
qcom,ctrl-supply-entry@0 {
reg = <0>;
qcom,supply-name = "vdda-1p2";
qcom,supply-min-voltage = <1200000>;
qcom,supply-max-voltage = <1200000>;
qcom,supply-enable-load = <100000>;
qcom,supply-disable-load = <100>;
qcom,supply-post-on-sleep = <20>;
};
};
qcom,phy-supply-entries {
#address-cells = <1>;
#size-cells = <0>;
qcom,phy-supply-entry@0 {
reg = <0>;
qcom,supply-name = "vdda-1p8";
qcom,supply-min-voltage = <1800000>;
qcom,supply-max-voltage = <1800000>;
qcom,supply-enable-load = <100000>;
qcom,supply-disable-load = <100>;
};
};
};
mdss-rgb-spi is the SPI controller for RGB device which supports control
commands communication with RGB panel.
Required properties:
- compatible: Must be "qcom,mdss-rgb-spi"
- spi-max-frequency : Maximum SPI clocking speed of device in Hz
Optional properties:
- label: A string used to describe the controller used.
- spi-cpol : Empty property indicating device requires inverse
clock polarity (CPOL) mode
- spi-cpha : Empty property indicating device requires shifted
clock phase (CPHA) mode
Example:
mdss_rgb_spi: qcom,mdss_rgb_spi {
compatible = "qcom,mdss-rgb-spi";
label = "MDSS SPI QUP1 CLIENT";
spi-max-frequency = <5000000>;
}

@ -91,6 +91,15 @@ config FB_MSM_MDSS_SPI_PANEL
the current max fps only reach to ~30 fps with 240x240 resolution, and
limited by MDP hardware architecture only supply GPU compostition.
config FB_MSM_MDSS_RGB_PANEL
depends on FB_MSM_MDSS
bool "Support RGB panel feature"
---help---
The MDSS RGB Panel provides support for transmitting
MDSS frame buffer data over RGB parallel interface
connected to RGB panel. Panel on/off sequence commands
are sent to RGB Panel through an SPI interface.
config FB_MSM_MDSS_MHL3
depends on FB_MSM_MDSS_HDMI_PANEL
bool "MHL3 SII8620 Support"

@ -69,6 +69,8 @@ obj-$(CONFIG_FB_MSM_MDSS_SPI_PANEL) += mdss_spi_display.o
obj-$(CONFIG_FB_MSM_MDSS_SPI_PANEL) += mdss_spi_client.o
obj-$(CONFIG_FB_MSM_MDSS_SPI_PANEL) += mdss_spi_panel.o
obj-$(CONFIG_FB_MSM_MDSS_RGB_PANEL) += mdss_rgb.o mdss_rgb_panel.o
obj-$(CONFIG_FB_MSM_MDSS_WRITEBACK) += mdss_wb.o
mdss-qpic-objs := mdss_qpic.o mdss_fb.o mdss_qpic_panel.o mdss_sync.o

@ -477,7 +477,7 @@ end:
return ret;
}
static void mdss_dsi_put_dt_vreg_data(struct device *dev,
void mdss_dsi_put_dt_vreg_data(struct device *dev,
struct dss_module_power *module_power)
{
if (!module_power) {
@ -492,7 +492,7 @@ static void mdss_dsi_put_dt_vreg_data(struct device *dev,
module_power->num_vreg = 0;
}
static int mdss_dsi_get_dt_vreg_data(struct device *dev,
int mdss_dsi_get_dt_vreg_data(struct device *dev,
struct device_node *of_node, struct dss_module_power *mp,
enum dsi_pm_type module)
{

@ -681,6 +681,11 @@ void mdss_dsi_set_reg(struct mdss_dsi_ctrl_pdata *ctrl, int off,
u32 mask, u32 val);
int mdss_dsi_phy_pll_reset_status(struct mdss_dsi_ctrl_pdata *ctrl);
int mdss_dsi_panel_power_ctrl(struct mdss_panel_data *pdata, int power_state);
int mdss_dsi_get_dt_vreg_data(struct device *dev,
struct device_node *of_node, struct dss_module_power *mp,
enum dsi_pm_type module);
void mdss_dsi_put_dt_vreg_data(struct device *dev,
struct dss_module_power *module_power);
static inline const char *__mdss_dsi_pm_name(enum dsi_pm_type module)
{

@ -1,4 +1,4 @@
/* Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -18,50 +18,9 @@
#include "mdss_dsi_clk.h"
#include "mdss_dsi.h"
#include "mdss_debug.h"
#include "mdss_rgb.h"
#define MAX_CLIENT_NAME_LEN 20
struct dsi_core_clks {
struct mdss_dsi_core_clk_info clks;
u32 current_clk_state;
};
struct dsi_link_clks {
struct mdss_dsi_link_hs_clk_info hs_clks;
struct mdss_dsi_link_lp_clk_info lp_clks;
u32 current_clk_state;
};
struct mdss_dsi_clk_mngr {
char name[DSI_CLK_NAME_LEN];
struct dsi_core_clks core_clks;
struct dsi_link_clks link_clks;
struct reg_bus_client *reg_bus_clt;
pre_clockoff_cb pre_clkoff_cb;
post_clockoff_cb post_clkoff_cb;
post_clockon_cb post_clkon_cb;
pre_clockon_cb pre_clkon_cb;
struct list_head client_list;
struct mutex clk_mutex;
void *priv_data;
};
struct mdss_dsi_clk_client_info {
char name[MAX_CLIENT_NAME_LEN];
u32 core_refcount;
u32 link_refcount;
u32 core_clk_state;
u32 link_clk_state;
struct list_head list;
struct mdss_dsi_clk_mngr *mngr;
};
static int dsi_core_clk_start(struct dsi_core_clks *c_clks)
int dsi_core_clk_start(struct dsi_core_clks *c_clks)
{
int rc = 0;
struct mdss_dsi_clk_mngr *mngr;
@ -248,7 +207,7 @@ static int dsi_link_hs_clk_disable(
}
static int dsi_link_hs_clk_start(
int dsi_link_hs_clk_start(
struct mdss_dsi_link_hs_clk_info *link_hs_clks,
enum mdss_dsi_link_clk_op_type op_type)
{
@ -291,7 +250,7 @@ error:
return rc;
}
static int dsi_link_lp_clk_start(
int dsi_link_lp_clk_start(
struct mdss_dsi_link_lp_clk_info *link_lp_clks)
{
int rc = 0;
@ -377,6 +336,10 @@ static int dsi_update_clk_state(struct dsi_core_clks *c_clks, u32 c_state,
{
int rc = 0;
struct mdss_dsi_clk_mngr *mngr;
struct mdss_rgb_data *sdata;
struct dss_vreg *vreg;
unsigned int num;
int i = 0;
bool l_c_on = false;
if (c_clks) {
@ -392,6 +355,8 @@ static int dsi_update_clk_state(struct dsi_core_clks *c_clks, u32 c_state,
if (!mngr)
return -EINVAL;
sdata = mngr->priv_data;
pr_debug("%s: c_state = %d, l_state = %d\n", mngr ? mngr->name : "NA",
c_clks ? c_state : -1, l_clks ? l_state : -1);
/*
@ -401,12 +366,37 @@ static int dsi_update_clk_state(struct dsi_core_clks *c_clks, u32 c_state,
*/
if (c_clks && (c_state == MDSS_DSI_CLK_ON)) {
if (c_clks->current_clk_state == MDSS_DSI_CLK_OFF) {
rc = mngr->pre_clkon_cb(mngr->priv_data,
MDSS_DSI_CORE_CLK, MDSS_DSI_LINK_NONE,
MDSS_DSI_CLK_ON);
if (rc) {
pr_err("failed to turn on MDP FS rc= %d\n", rc);
goto error;
if (mngr->pre_clkon_cb == NULL) {
if (!sdata) {
pr_debug("invalid rgb data\n");
goto error;
}
for (i = DSI_CORE_PM; i < DSI_MAX_PM; i++) {
vreg = sdata->power_data[i].vreg_config;
num = sdata->power_data[i].num_vreg;
rc = msm_dss_enable_vreg(vreg, num, 1);
if (rc) {
pr_err("%s: failed to enable vregs for %s\n",
__func__,
__mdss_dsi_pm_name(i));
goto error;
} else {
pr_debug("%s: enabled vregs for %s\n",
__func__,
__mdss_dsi_pm_name(i));
sdata->core_power = true;
}
}
} else {
rc = mngr->pre_clkon_cb(mngr->priv_data,
MDSS_DSI_CORE_CLK, MDSS_DSI_LINK_NONE,
MDSS_DSI_CLK_ON);
if (rc) {
pr_err("failed to turn on MDP FS rc= %d\n",
rc);
goto error;
}
}
}
rc = dsi_core_clk_start(c_clks);

@ -18,6 +18,7 @@
#include <linux/list.h>
#define DSI_CLK_NAME_LEN 20
#define MAX_CLIENT_NAME_LEN 20
#define MDSS_DSI_CLK_UPDATE_CLK_RATE_AT_ON 0x1
@ -166,6 +167,47 @@ struct mdss_dsi_clk_client {
char *client_name;
};
struct dsi_core_clks {
struct mdss_dsi_core_clk_info clks;
u32 current_clk_state;
};
struct dsi_link_clks {
struct mdss_dsi_link_hs_clk_info hs_clks;
struct mdss_dsi_link_lp_clk_info lp_clks;
u32 current_clk_state;
};
struct mdss_dsi_clk_mngr {
char name[DSI_CLK_NAME_LEN];
struct dsi_core_clks core_clks;
struct dsi_link_clks link_clks;
struct reg_bus_client *reg_bus_clt;
pre_clockoff_cb pre_clkoff_cb;
post_clockoff_cb post_clkoff_cb;
post_clockon_cb post_clkon_cb;
pre_clockon_cb pre_clkon_cb;
struct list_head client_list;
struct mutex clk_mutex;
void *priv_data;
};
struct mdss_dsi_clk_client_info {
char name[MAX_CLIENT_NAME_LEN];
u32 core_refcount;
u32 link_refcount;
u32 core_clk_state;
u32 link_clk_state;
struct list_head list;
struct mdss_dsi_clk_mngr *mngr;
};
/**
* mdss_dsi_clk_init() - Initializes clock manager
* @info: Clock information to be managed by the clock manager.

@ -365,6 +365,9 @@ static ssize_t mdss_fb_get_type(struct device *dev,
case SPI_PANEL:
ret = snprintf(buf, PAGE_SIZE, "spi panel\n");
break;
case RGB_PANEL:
ret = snprintf(buf, PAGE_SIZE, "rgb panel\n");
break;
default:
ret = snprintf(buf, PAGE_SIZE, "unknown panel\n");
break;

@ -99,6 +99,7 @@ static struct mdss_panel_intf pan_types[] = {
{"dsi", MDSS_PANEL_INTF_DSI},
{"edp", MDSS_PANEL_INTF_EDP},
{"hdmi", MDSS_PANEL_INTF_HDMI},
{"rgb", MDSS_PANEL_INTF_RGB},
};
static char mdss_mdp_panel[MDSS_MAX_PANEL_LEN];
@ -2688,6 +2689,8 @@ int mdss_panel_get_intf_status(u32 disp_num, u32 intf_type)
rc = (intf_status & MDSS_MDP_INTF_DSI1_SEL);
else
rc = 0;
} else if (intf_type == MDSS_PANEL_INTF_RGB) {
rc = (intf_status & MDSS_MDP_INTF_DSI0_SEL);
} else if (intf_type == MDSS_PANEL_INTF_EDP) {
intf_status &= MDSS_MDP_INTF_EDP_SEL;
rc = (intf_status == MDSS_MDP_INTF_EDP_SEL);

@ -652,6 +652,9 @@ struct mdss_mdp_ctl {
/* vsync handler for FRC */
struct mdss_mdp_vsync_handler frc_vsync_handler;
bool need_vsync_on;
/* pack alignment for DSI or RGB Panels */
bool pack_align_msb;
};
struct mdss_mdp_mixer {

@ -2485,6 +2485,7 @@ int mdss_mdp_ctl_free(struct mdss_mdp_ctl *ctl)
ctl->ref_cnt--;
ctl->intf_num = MDSS_MDP_NO_INTF;
ctl->intf_type = MDSS_MDP_NO_INTF;
ctl->pack_align_msb = false;
ctl->is_secure = false;
ctl->power_state = MDSS_PANEL_POWER_OFF;
ctl->mixer_left = NULL;
@ -3711,15 +3712,24 @@ int mdss_mdp_ctl_reconfig(struct mdss_mdp_ctl *ctl,
case MIPI_VIDEO_PANEL:
ctl->is_video_mode = true;
ctl->intf_type = MDSS_INTF_DSI;
ctl->pack_align_msb = true;
ctl->opmode = MDSS_MDP_CTL_OP_VIDEO_MODE;
ctl->ops.start_fnc = mdss_mdp_video_start;
break;
case MIPI_CMD_PANEL:
ctl->is_video_mode = false;
ctl->intf_type = MDSS_INTF_DSI;
ctl->pack_align_msb = true;
ctl->opmode = MDSS_MDP_CTL_OP_CMD_MODE;
ctl->ops.start_fnc = mdss_mdp_cmd_start;
break;
case RGB_PANEL:
ctl->is_video_mode = true;
ctl->intf_type = MDSS_INTF_DSI;
ctl->pack_align_msb = false;
ctl->opmode = MDSS_MDP_CTL_OP_VIDEO_MODE;
ctl->ops.start_fnc = mdss_mdp_video_start;
break;
}
ctl->is_secure = false;
@ -3835,6 +3845,7 @@ struct mdss_mdp_ctl *mdss_mdp_ctl_init(struct mdss_panel_data *pdata,
ctl->intf_num = mdp5_data->mixer_swap ? MDSS_MDP_INTF1 :
MDSS_MDP_INTF2;
ctl->intf_type = MDSS_INTF_DSI;
ctl->pack_align_msb = true;
ctl->opmode = MDSS_MDP_CTL_OP_VIDEO_MODE;
ctl->ops.start_fnc = mdss_mdp_video_start;
break;
@ -3846,6 +3857,7 @@ struct mdss_mdp_ctl *mdss_mdp_ctl_init(struct mdss_panel_data *pdata,
ctl->intf_num = mdp5_data->mixer_swap ? MDSS_MDP_INTF1 :
MDSS_MDP_INTF2;
ctl->intf_type = MDSS_INTF_DSI;
ctl->pack_align_msb = true;
ctl->opmode = MDSS_MDP_CTL_OP_CMD_MODE;
ctl->ops.start_fnc = mdss_mdp_cmd_start;
INIT_WORK(&ctl->cpu_pm_work, __cpu_pm_work_handler);
@ -3861,6 +3873,19 @@ struct mdss_mdp_ctl *mdss_mdp_ctl_init(struct mdss_panel_data *pdata,
ctl->intf_num = MDSS_MDP_NO_INTF;
ctl->ops.start_fnc = mdss_mdp_writeback_start;
break;
case RGB_PANEL:
ctl->is_video_mode = true;
if (pdata->panel_info.pdest == DISPLAY_1)
ctl->intf_num = mdp5_data->mixer_swap ? MDSS_MDP_INTF2 :
MDSS_MDP_INTF1;
else
ctl->intf_num = mdp5_data->mixer_swap ? MDSS_MDP_INTF1 :
MDSS_MDP_INTF2;
ctl->intf_type = MDSS_INTF_DSI;
ctl->pack_align_msb = false;
ctl->opmode = MDSS_MDP_CTL_OP_VIDEO_MODE;
ctl->ops.start_fnc = mdss_mdp_video_start;
break;
default:
pr_err("unsupported panel type (%d)\n", pdata->panel_info.type);
ret = -EINVAL;
@ -3874,7 +3899,15 @@ struct mdss_mdp_ctl *mdss_mdp_ctl_init(struct mdss_panel_data *pdata,
} else {
switch (pdata->panel_info.bpp) {
case 18:
if (ctl->intf_type == MDSS_INTF_DSI)
/*
* Both DSI and RGB Panels share same MDSS_INTF_DSI
* interface type. In case of 18 bpp, DSI Panels need
* pack alignment and RGB Panels doesn't need pack
* alignment. Enable pack alignment based on ctl's
* pack_align_msb support.
*/
if (ctl->intf_type == MDSS_INTF_DSI &&
ctl->pack_align_msb)
ctl->dst_format = MDSS_MDP_PANEL_FORMAT_RGB666 |
MDSS_MDP_PANEL_FORMAT_PACK_ALIGN_MSB;
else

@ -683,6 +683,7 @@ enum mdss_mpd_intf_index {
#define MDSS_MDP_REG_INTF_INTR_CLEAR 0x1C8
#define MDSS_MDP_REG_INTF_PROG_LINE_INTR_CONF 0x250
#define MDSS_MDP_REG_INTF_VBLANK_END_CONF 0x264
#define MDSS_MDP_REG_INTF_RGB_INTF_CTRL 0x268
#define MDSS_MDP_REG_INTF_FRAME_LINE_COUNT_EN 0x0A8
#define MDSS_MDP_REG_INTF_FRAME_COUNT 0x0AC

@ -507,6 +507,10 @@ static int mdss_mdp_video_timegen_setup(struct mdss_mdp_ctl *ctl,
mdp_video_write(ctx, MDSS_MDP_REG_INTF_HSYNC_SKEW, p->hsync_skew);
mdp_video_write(ctx, MDSS_MDP_REG_INTF_POLARITY_CTL, polarity_ctl);
mdp_video_write(ctx, MDSS_MDP_REG_INTF_FRAME_LINE_COUNT_EN, 0x3);
if (mdata->pan_cfg.pan_intf == MDSS_PANEL_INTF_RGB)
mdp_video_write(ctx, MDSS_MDP_REG_INTF_RGB_INTF_CTRL, 0x1);
MDSS_XLOG(hsync_period, vsync_period);
/*

@ -61,6 +61,7 @@ enum fps_resolution {
#define LVDS_PANEL 11 /* LVDS */
#define EDP_PANEL 12 /* LVDS */
#define SPI_PANEL 13 /* SPI */
#define RGB_PANEL 14 /* RGB */
#define DSC_PPS_LEN 128
#define INTF_EVENT_STR(x) #x
@ -111,6 +112,7 @@ enum {
MDSS_PANEL_INTF_EDP,
MDSS_PANEL_INTF_HDMI,
MDSS_PANEL_INTF_SPI,
MDSS_PANEL_INTF_RGB,
};
enum {

File diff suppressed because it is too large Load Diff

@ -0,0 +1,104 @@
/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only 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.
*
*/
#include "mdss_panel.h"
#include "mdss_dsi_clk.h"
#include "mdss_dsi.h"
#define NONE_PANEL "none"
#define DSIPHY_CMN_CTRL_0 0x001c
#define DSIPHY_CMN_CTRL_1 0x0020
#define DSIPHY_CMN_LDO_CNTRL 0x004c
#define DSIPHY_CMN_GLBL_TEST_CTRL 0x0018
#define DSIPHY_PLL_CLKBUFLR_EN 0x041c
struct mdss_rgb_data {
int ndx;
bool res_init;
struct platform_device *pdev;
struct spi_device *spi;
unsigned char *ctrl_base;
struct dss_io_data ctrl_io;
struct dss_io_data phy_io;
int reg_size;
u32 *dbg_bus;
int dbg_bus_size;
u32 hw_config; /* RGB setup configuration i.e. single*/
u32 pll_src_config; /* PLL source selection for RGB clocks */
u32 hw_rev; /* DSI h/w revision */
struct mdss_panel_data panel_data;
bool refresh_clk_rate;
struct clk *pixel_clk_rgb;
struct clk *byte_clk_rgb;
u32 pclk_rate;
u32 byte_clk_rate;
/* DSI core regulators */
struct dss_module_power panel_power_data;
struct dss_module_power power_data[DSI_MAX_PM];
/* DSI bus clocks */
struct clk *mdp_core_clk;
struct clk *mnoc_clk;
struct clk *ahb_clk;
struct clk *axi_clk;
struct clk *mmss_misc_ahb_clk;
struct clk *ext_pixel0_clk;
struct clk *ext_byte0_clk;
//struct clk *ext_pixel1_clk;
struct clk *byte_clk_rcg;
struct clk *pixel_clk_rcg;
struct clk *byte0_parent;
struct clk *pixel0_parent;
void *clk_mngr;
void *clk_handle;
void *mdp_clk_handle;
/* Data bus(AXI) scale settings */
struct msm_bus_scale_pdata *bus_scale_table;
u32 bus_handle;
u32 bus_refcount;
int bklt_ctrl; /* backlight ctrl */
int pwm_enabled;
struct pwm_device *pwm_bl;
struct dsi_pinctrl_res pin_res;
u8 ctrl_state;
bool core_power;
/* GPIOs */
int rst_gpio;
int (*on)(struct mdss_panel_data *pdata);
int (*off)(struct mdss_panel_data *pdata);
};
enum mdss_rgb_hw_config {
SINGLE_RGB,
};
int mdss_rgb_panel_init(struct device_node *node,
struct mdss_rgb_data *rgb_data);
int mdss_rgb_clk_refresh(struct mdss_rgb_data *rgb_data);
int mdss_rgb_clk_div_config(struct mdss_rgb_data *rgb_data,
struct mdss_panel_info *panel_info, int frame_rate);
int rgb_panel_device_register(struct platform_device *ctrl_pdev,
struct device_node *pan_node, struct mdss_rgb_data *rgb_data);
int mdss_rgb_write_command(struct mdss_rgb_data *rgb_data, u8 cmd);
int mdss_rgb_write_data(struct mdss_rgb_data *rgb_data, u8 data);
int mdss_rgb_read_command(struct mdss_rgb_data *rgb_data,
u8 cmd, u8 *data, u8 data_len);

@ -0,0 +1,458 @@
/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only 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.
*/
#include <linux/of_device.h>
#include <linux/delay.h>
#include <video/mipi_display.h>
#include <linux/pwm.h>
#include "mdss_rgb.h"
#define RAMCTRL_CMD 0xb0
#define RGBCTRL_CMD 0xb1
#define PORCTRL_CMD 0xb2
#define GCTRL_CMD 0xb7
#define VCOMS_CMD 0xbb
#define LCMCTRL_CMD 0xc0
#define VDVVRHEN_CMD 0xc2
#define VRHS_CMD 0xc3
#define VDVS_CMD 0xc4
#define VCMOFSET_CMD 0xc5
#define FRCTRL2_CMD 0xc6
#define PWCTRL1_CMD 0xd0
#define PVGAMCTRL_CMD 0xe0
#define NVGAMCTRL_CMD 0xe1
#define SPI2EN_CMD 0xe7
#define PWCTRL2_CMD 0xe8
static void mdss_rgb_panel_reset(struct mdss_rgb_data *rgb_data)
{
if (gpio_is_valid(rgb_data->rst_gpio)) {
gpio_set_value(rgb_data->rst_gpio, 1);
usleep_range(10000, 20000);
gpio_set_value(rgb_data->rst_gpio, 0);
usleep_range(10000, 20000);
gpio_set_value(rgb_data->rst_gpio, 1);
usleep_range(10000, 20000);
}
}
static int mdss_rgb_panel_on(struct mdss_panel_data *pdata)
{
struct mdss_rgb_data *rgb_data = NULL;
if (pdata == NULL) {
pr_err("%s: invalid mdss panel data\n", __func__);
return -EINVAL;
}
rgb_data = container_of(pdata, struct mdss_rgb_data,
panel_data);
mdss_rgb_panel_reset(rgb_data);
mdss_rgb_write_command(rgb_data, MIPI_DCS_EXIT_SLEEP_MODE);
msleep(120);
/* display and color format setting */
mdss_rgb_write_command(rgb_data, MIPI_DCS_SET_ADDRESS_MODE);
mdss_rgb_write_data(rgb_data, 0x00);
mdss_rgb_write_command(rgb_data, MIPI_DCS_SET_PIXEL_FORMAT);
mdss_rgb_write_data(rgb_data, 0x06);
/* frame rate setting */
/* RAM Control */
mdss_rgb_write_command(rgb_data, RAMCTRL_CMD);
mdss_rgb_write_data(rgb_data, 0x11);
mdss_rgb_write_data(rgb_data, 0xf0);
/* RGB Interface control */
mdss_rgb_write_command(rgb_data, RGBCTRL_CMD);
mdss_rgb_write_data(rgb_data, 0x4c);
mdss_rgb_write_data(rgb_data, 0x05);
mdss_rgb_write_data(rgb_data, 0x14);
/* Porch setting */
mdss_rgb_write_command(rgb_data, PORCTRL_CMD);
mdss_rgb_write_data(rgb_data, 0x0c);
mdss_rgb_write_data(rgb_data, 0x0c);
mdss_rgb_write_data(rgb_data, 0x00);
mdss_rgb_write_data(rgb_data, 0x33);
mdss_rgb_write_data(rgb_data, 0x33);
/* Gate Control */
mdss_rgb_write_command(rgb_data, GCTRL_CMD);
mdss_rgb_write_data(rgb_data, 0x35);
/* VGH=13.26V, VGL=-10.43V */
/* Power setting */
/* vcom setting */
mdss_rgb_write_command(rgb_data, VCOMS_CMD);
mdss_rgb_write_data(rgb_data, 0x19); /* 1.05 */
/* LCM Control */
mdss_rgb_write_command(rgb_data, LCMCTRL_CMD);
mdss_rgb_write_data(rgb_data, 0x2c);
/* VDV and VRH Command Enable */
mdss_rgb_write_command(rgb_data, VDVVRHEN_CMD);
mdss_rgb_write_data(rgb_data, 0x01);
/* VRH Set, VAP(GVDD) & VAN(GVCL) */
mdss_rgb_write_command(rgb_data, VRHS_CMD);
mdss_rgb_write_data(rgb_data, 0x1d);
/* set VDV */
mdss_rgb_write_command(rgb_data, VDVS_CMD);
mdss_rgb_write_data(rgb_data, 0x20); /* VDV=0V */
/* vcom Offset Set */
mdss_rgb_write_command(rgb_data, VCMOFSET_CMD);
mdss_rgb_write_data(rgb_data, 0x20); /* vcom Offset=0V */
/* Frame rate control in normal mode */
mdss_rgb_write_command(rgb_data, FRCTRL2_CMD);
mdss_rgb_write_data(rgb_data, 0x0f); /* dot inversion & 60Hz */
/* Power control 1 */
mdss_rgb_write_command(rgb_data, PWCTRL1_CMD);
mdss_rgb_write_data(rgb_data, 0xa4);
/* AVDD=6.8V; AVCL=-4.8V; VDDS=2.3V */
mdss_rgb_write_data(rgb_data, 0xa1);
/* Power control 2 */
mdss_rgb_write_command(rgb_data, PWCTRL2_CMD);
mdss_rgb_write_data(rgb_data, 0x83);
/* Set Gamma */
mdss_rgb_write_command(rgb_data, PVGAMCTRL_CMD);
mdss_rgb_write_data(rgb_data, 0xd2);
mdss_rgb_write_data(rgb_data, 0x13);
mdss_rgb_write_data(rgb_data, 0x16);
mdss_rgb_write_data(rgb_data, 0x0d);
mdss_rgb_write_data(rgb_data, 0x0f);
mdss_rgb_write_data(rgb_data, 0x38);
mdss_rgb_write_data(rgb_data, 0x3d);
mdss_rgb_write_data(rgb_data, 0x43);
mdss_rgb_write_data(rgb_data, 0x4d);
mdss_rgb_write_data(rgb_data, 0x1b);
mdss_rgb_write_data(rgb_data, 0x16);
mdss_rgb_write_data(rgb_data, 0x14);
mdss_rgb_write_data(rgb_data, 0x1b);
mdss_rgb_write_data(rgb_data, 0x1f);
/* Set Gamma */
mdss_rgb_write_command(rgb_data, NVGAMCTRL_CMD);
mdss_rgb_write_data(rgb_data, 0xd2);
mdss_rgb_write_data(rgb_data, 0x13);
mdss_rgb_write_data(rgb_data, 0x16);
mdss_rgb_write_data(rgb_data, 0x0d);
mdss_rgb_write_data(rgb_data, 0x0f);
mdss_rgb_write_data(rgb_data, 0x38);
mdss_rgb_write_data(rgb_data, 0x3d);
mdss_rgb_write_data(rgb_data, 0x43);
mdss_rgb_write_data(rgb_data, 0x4d);
mdss_rgb_write_data(rgb_data, 0x1b);
mdss_rgb_write_data(rgb_data, 0x16);
mdss_rgb_write_data(rgb_data, 0x14);
mdss_rgb_write_data(rgb_data, 0x1b);
mdss_rgb_write_data(rgb_data, 0x1f);
/* SPI2 Enable */
mdss_rgb_write_command(rgb_data, SPI2EN_CMD);
mdss_rgb_write_data(rgb_data, 0x10); /* Enable 2 data lane mode */
mdss_rgb_write_command(rgb_data, MIPI_DCS_SET_DISPLAY_ON);
msleep(30);
pr_debug("%s: RGB panel power on done\n", __func__);
return 0;
}
static int mdss_rgb_panel_off(struct mdss_panel_data *pdata)
{
struct mdss_rgb_data *rgb_data = NULL;
if (pdata == NULL) {
pr_err("%s: Invalid mdss panel data\n", __func__);
return -EINVAL;
}
rgb_data = container_of(pdata, struct mdss_rgb_data,
panel_data);
mdss_rgb_write_command(rgb_data, MIPI_DCS_SET_DISPLAY_OFF);
return 0;
}
static int mdss_rgb_panel_timing_from_dt(struct device_node *np,
struct mdss_panel_timing *pt,
struct mdss_panel_data *panel_data)
{
u64 tmp64;
int rc;
struct mdss_panel_info *pinfo;
pinfo = &panel_data->panel_info;
rc = of_property_read_u32(np, "qcom,mdss-rgb-panel-width", &pt->xres);
if (rc) {
pr_err("%s:%d, panel width not specified\n",
__func__, __LINE__);
return -EINVAL;
}
rc = of_property_read_u32(np, "qcom,mdss-rgb-panel-height", &pt->yres);
if (rc) {
pr_err("%s:%d, panel height not specified\n",
__func__, __LINE__);
return -EINVAL;
}
pt->h_front_porch = 6;
rc = of_property_read_u32(np, "qcom,mdss-rgb-h-front-porch",
&pt->h_front_porch);
pt->h_back_porch = 6;
rc = of_property_read_u32(np, "qcom,mdss-rgb-h-back-porch",
&pt->h_back_porch);
pt->h_pulse_width = 2;
rc = of_property_read_u32(np, "qcom,mdss-rgb-h-pulse-width",
&pt->h_pulse_width);
pt->hsync_skew = 0;
rc = of_property_read_u32(np, "qcom,mdss-rgb-h-sync-skew",
&pt->hsync_skew);
pt->v_back_porch = 6;
rc = of_property_read_u32(np, "qcom,mdss-rgb-v-back-porch",
&pt->v_back_porch);
pt->v_front_porch = 6;
rc = of_property_read_u32(np, "qcom,mdss-rgb-v-front-porch",
&pt->v_front_porch);
pt->v_pulse_width = 2;
rc = of_property_read_u32(np, "qcom,mdss-rgb-v-pulse-width",
&pt->v_pulse_width);
pt->border_left = 0;
rc = of_property_read_u32(np, "qcom,mdss-rgb-h-left-border",
&pt->border_left);
pt->border_right = 0;
rc = of_property_read_u32(np, "qcom,mdss-rgb-h-right-border",
&pt->border_right);
pt->border_top = 0;
rc = of_property_read_u32(np, "qcom,mdss-rgb-v-top-border",
&pt->border_top);
pt->border_bottom = 0;
rc = of_property_read_u32(np, "qcom,mdss-rgb-v-bottom-border",
&pt->border_bottom);
pt->frame_rate = DEFAULT_FRAME_RATE;
rc = of_property_read_u32(np, "qcom,mdss-rgb-panel-framerate",
(u32 *)&pt->frame_rate);
rc = of_property_read_u64(np, "qcom,mdss-rgb-panel-clockrate", &tmp64);
if (rc == -EOVERFLOW) {
tmp64 = 0;
rc = of_property_read_u32(np, "qcom,mdss-rgb-panel-clockrate",
(u32 *)&tmp64);
}
pt->clk_rate = !rc ? tmp64 : 0;
pt->name = kstrdup(np->name, GFP_KERNEL);
pr_debug("%s: found new timing \"%s\"\n", __func__, np->name);
return 0;
}
int mdss_rgb_clk_refresh(struct mdss_rgb_data *rgb_data)
{
struct mdss_panel_info *pinfo = NULL;
struct mdss_panel_data *pdata = &rgb_data->panel_data;
int rc = 0;
if (!pdata) {
pr_err("%s: invalid mdss panel data\n", __func__);
return -EINVAL;
}
pinfo = &pdata->panel_info;
mdss_rgb_clk_div_config(rgb_data, &pdata->panel_info,
pdata->panel_info.mipi.frame_rate);
rgb_data->refresh_clk_rate = false;
rgb_data->pclk_rate = pdata->panel_info.mipi.dsi_pclk_rate;
rgb_data->byte_clk_rate = pdata->panel_info.clk_rate / 8;
pr_debug("%s rgb_data->byte_clk_rate=%d rgb_data->pclk_rate=%d\n",
__func__, rgb_data->byte_clk_rate, rgb_data->pclk_rate);
rc = mdss_dsi_clk_set_link_rate(rgb_data->clk_handle,
MDSS_DSI_LINK_BYTE_CLK, rgb_data->byte_clk_rate,
MDSS_DSI_CLK_UPDATE_CLK_RATE_AT_ON);
if (rc) {
pr_err("%s: byte_clk - clk_set_rate failed\n",
__func__);
return rc;
}
rc = mdss_dsi_clk_set_link_rate(rgb_data->clk_handle,
MDSS_DSI_LINK_PIX_CLK, rgb_data->pclk_rate,
MDSS_DSI_CLK_UPDATE_CLK_RATE_AT_ON);
if (rc)
pr_err("%s: pixel_clk - clk_set_rate failed\n",
__func__);
return rc;
}
int mdss_rgb_panel_timing_switch(struct mdss_rgb_data *rgb_data,
struct mdss_panel_timing *timing)
{
struct mdss_panel_info *pinfo = &rgb_data->panel_data.panel_info;
struct mdss_panel_data *panel_data = &rgb_data->panel_data;
if (!timing)
return -EINVAL;
if (timing == panel_data->current_timing) {
pr_warn("%s: panel timing \"%s\" already set\n", __func__,
timing->name);
return 0; /* nothing to do */
}
//Copy Timings from display_timing struct to panel_info struct
mdss_panel_info_from_timing(timing, pinfo);
panel_data->current_timing = timing;
if (!timing->clk_rate)
rgb_data->refresh_clk_rate = true;
mdss_rgb_clk_refresh(rgb_data);
return 0;
}
static int mdss_rgb_panel_parse_display_timings(struct device_node *np,
struct mdss_rgb_data *rgb_data)
{
struct device_node *timings_np;
struct mdss_panel_data *panel_data = &rgb_data->panel_data;
int rc = 0;
INIT_LIST_HEAD(&panel_data->timings_list);
timings_np = of_get_child_by_name(np, "qcom,mdss-rgb-display-timings");
if (!timings_np) {
/*
* display timings node is not available, fallback to reading
* timings directly from root node instead
*/
struct mdss_panel_timing pt;
memset(&pt, 0, sizeof(struct mdss_panel_timing));
pr_debug("reading display-timings from panel node\n");
rc = mdss_rgb_panel_timing_from_dt(np, &pt, panel_data);
if (!rc) {
/*
* Switch to the parsed timings
*/
rc = mdss_rgb_panel_timing_switch(rgb_data, &pt);
}
}
return rc;
}
static int mdss_rgb_panel_parse_dt(struct device_node *np,
struct mdss_rgb_data *rgb_data)
{
int rc = 0;
struct mdss_panel_info *pinfo = &(rgb_data->panel_data.panel_info);
pinfo->physical_width = 0;
rc = of_property_read_u32(np, "qcom,mdss-pan-physical-width-dimension",
&pinfo->physical_width);
pinfo->physical_height = 0;
rc = of_property_read_u32(np, "qcom,mdss-pan-physical-height-dimension",
&pinfo->physical_height);
pinfo->bpp = 24;
rc = of_property_read_u32(np, "qcom,mdss-rgb-bpp", &pinfo->bpp);
if (rc) {
pr_err("%s:%d, bpp not specified\n", __func__, __LINE__);
return -EINVAL;
}
pinfo->mipi.mode = DSI_VIDEO_MODE;
switch (pinfo->bpp) {
case 16:
pinfo->mipi.dst_format = DSI_VIDEO_DST_FORMAT_RGB565;
break;
case 18:
pinfo->mipi.dst_format = DSI_VIDEO_DST_FORMAT_RGB666;
break;
case 24:
default:
pinfo->mipi.dst_format = DSI_VIDEO_DST_FORMAT_RGB888;
break;
}
rc = mdss_rgb_panel_parse_display_timings(np, rgb_data);
return rc;
}
int mdss_rgb_panel_init(struct device_node *node,
struct mdss_rgb_data *rgb_data)
{
int rc = 0;
static const char *panel_name;
struct mdss_panel_info *pinfo;
if (!node) {
pr_err("%s: Invalid device node\n", __func__);
return -ENODEV;
}
pinfo = &rgb_data->panel_data.panel_info;
pinfo->panel_name[0] = '\0';
panel_name = of_get_property(node, "qcom,mdss-rgb-panel-name", NULL);
if (!panel_name) {
pr_info("%s:%d, Panel name not specified\n",
__func__, __LINE__);
} else {
pr_info("%s: Panel Name = %s\n", __func__, panel_name);
strlcpy(&pinfo->panel_name[0], panel_name,
sizeof(pinfo->panel_name));
}
rc = mdss_rgb_panel_parse_dt(node, rgb_data);
if (rc)
return rc;
rgb_data->on = mdss_rgb_panel_on;
rgb_data->off = mdss_rgb_panel_off;
return rc;
}
Loading…
Cancel
Save