4740 lines
134 KiB
Diff
4740 lines
134 KiB
Diff
From a962515cc6270639e7ec645409a0dd1b0c848829 Mon Sep 17 00:00:00 2001
|
|
From: Romuald JEANNE <romuald.jeanne@st.com>
|
|
Date: Thu, 30 Jan 2020 14:57:55 +0100
|
|
Subject: [PATCH 17/17] ARM v2018.11 stm32mp r4 MISC
|
|
|
|
---
|
|
Makefile | 2 +-
|
|
cmd/remoteproc.c | 4 -
|
|
drivers/clk/clk_stm32mp1.c | 284 +++++++++-
|
|
drivers/i2c/stm32f7_i2c.c | 116 ++--
|
|
drivers/mmc/mmc-uclass.c | 14 +
|
|
drivers/mmc/mmc.c | 15 +
|
|
drivers/mmc/stm32_sdmmc2.c | 13 +-
|
|
drivers/net/dwc_eth_qos.c | 47 +-
|
|
drivers/ram/stm32mp1/stm32mp1_ddr.c | 30 +-
|
|
drivers/ram/stm32mp1/stm32mp1_interactive.c | 4 +-
|
|
drivers/remoteproc/rproc-uclass.c | 35 +-
|
|
drivers/remoteproc/stm32_copro.c | 9 +-
|
|
drivers/video/Kconfig | 13 +-
|
|
drivers/video/Makefile | 5 +-
|
|
drivers/video/dsi-host-uclass.c | 39 ++
|
|
drivers/video/dw_mipi_dsi.c | 140 ++---
|
|
drivers/video/mipi_display.c | 817 ---------------------------
|
|
drivers/video/mipi_dsi.c | 828 ++++++++++++++++++++++++++++
|
|
drivers/video/orisetech_otm8009a.c | 101 ++--
|
|
drivers/video/raydium-rm68200.c | 39 +-
|
|
drivers/video/stm32/stm32_dsi.c | 167 ++++--
|
|
drivers/video/stm32/stm32_ltdc.c | 50 +-
|
|
include/dm/uclass-id.h | 1 +
|
|
include/dsi_host.h | 57 ++
|
|
include/mipi_display.h | 249 +--------
|
|
include/mipi_dsi.h | 473 ++++++++++++++++
|
|
include/mmc.h | 13 +
|
|
include/power/stpmic1.h | 1 +
|
|
include/remoteproc.h | 11 +
|
|
29 files changed, 2188 insertions(+), 1389 deletions(-)
|
|
create mode 100644 drivers/video/dsi-host-uclass.c
|
|
delete mode 100644 drivers/video/mipi_display.c
|
|
create mode 100644 drivers/video/mipi_dsi.c
|
|
create mode 100644 include/dsi_host.h
|
|
create mode 100644 include/mipi_dsi.h
|
|
|
|
diff --git a/Makefile b/Makefile
|
|
index b9579b2..4c72fc1 100644
|
|
--- a/Makefile
|
|
+++ b/Makefile
|
|
@@ -3,7 +3,7 @@
|
|
VERSION = 2018
|
|
PATCHLEVEL = 11
|
|
SUBLEVEL =
|
|
-EXTRAVERSION = -stm32mp-r3
|
|
+EXTRAVERSION = -stm32mp-r4
|
|
NAME =
|
|
|
|
# *DOCUMENTATION*
|
|
diff --git a/cmd/remoteproc.c b/cmd/remoteproc.c
|
|
index 755e933..5665032 100644
|
|
--- a/cmd/remoteproc.c
|
|
+++ b/cmd/remoteproc.c
|
|
@@ -177,10 +177,6 @@ static int do_remoteproc_load_rsc_table(cmd_tbl_t *cmdtp, int flag, int argc,
|
|
}
|
|
|
|
ret = rproc_load_rsc_table(id, addr, size, &rsc_addr, &rsc_size);
|
|
- if (!ret) {
|
|
- env_set_hex("copro_rsc_addr", rsc_addr);
|
|
- env_set_hex("copro_rsc_size", rsc_size);
|
|
- }
|
|
|
|
printf("Remote Processor %d resource table %s : 0x%08lx-0x%x\n",
|
|
id, ret ? "Not found" : "Found", ret ? 0 : rsc_addr,
|
|
diff --git a/drivers/clk/clk_stm32mp1.c b/drivers/clk/clk_stm32mp1.c
|
|
index 2d7b185..a6503e4 100644
|
|
--- a/drivers/clk/clk_stm32mp1.c
|
|
+++ b/drivers/clk/clk_stm32mp1.c
|
|
@@ -650,8 +650,18 @@ static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = {
|
|
};
|
|
|
|
#ifdef STM32MP1_CLOCK_TREE_INIT
|
|
+
|
|
/* define characteristic of PLL according type */
|
|
+#define DIVM_MIN 0
|
|
+#define DIVM_MAX 63
|
|
#define DIVN_MIN 24
|
|
+#define DIVP_MIN 0
|
|
+#define DIVP_MAX 127
|
|
+#define FRAC_MAX 8192
|
|
+
|
|
+#define PLL1600_VCO_MIN 800000000
|
|
+#define PLL1600_VCO_MAX 1600000000
|
|
+
|
|
static const struct stm32mp1_pll stm32mp1_pll[PLL_TYPE_NB] = {
|
|
[PLL_800] = {
|
|
.refclk_min = 4,
|
|
@@ -1206,6 +1216,211 @@ static ulong stm32mp1_clk_get_rate(struct clk *clk)
|
|
}
|
|
|
|
#ifdef STM32MP1_CLOCK_TREE_INIT
|
|
+
|
|
+bool stm32mp1_supports_opp(u32 opp_id, u32 cpu_type)
|
|
+{
|
|
+ unsigned int id;
|
|
+
|
|
+ switch (opp_id) {
|
|
+ case 1:
|
|
+ case 2:
|
|
+ id = opp_id;
|
|
+ break;
|
|
+ default:
|
|
+ id = 1; /* default value */
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ switch (cpu_type) {
|
|
+ case CPU_STM32MP157Fxx:
|
|
+ case CPU_STM32MP157Dxx:
|
|
+ case CPU_STM32MP153Fxx:
|
|
+ case CPU_STM32MP153Dxx:
|
|
+ case CPU_STM32MP151Fxx:
|
|
+ case CPU_STM32MP151Dxx:
|
|
+ return true;
|
|
+ default:
|
|
+ return id == 1;
|
|
+ }
|
|
+}
|
|
+
|
|
+__weak void board_vddcore_init(u32 voltage_mv)
|
|
+{
|
|
+}
|
|
+
|
|
+/*
|
|
+ * gets OPP parameters (frequency in KHz and voltage in mV) from
|
|
+ * an OPP table subnode. Platform HW support capabilities are also checked.
|
|
+ * Returns 0 on success and a negative FDT error code on failure.
|
|
+ */
|
|
+static int stm32mp1_get_opp(u32 cpu_type, ofnode subnode,
|
|
+ u32 *freq_khz, u32 *voltage_mv)
|
|
+{
|
|
+ u32 opp_hw;
|
|
+ u64 read_freq_64;
|
|
+ u32 read_voltage_32;
|
|
+
|
|
+ *freq_khz = 0;
|
|
+ *voltage_mv = 0;
|
|
+
|
|
+ opp_hw = ofnode_read_u32_default(subnode, "opp-supported-hw", 0);
|
|
+ if (opp_hw)
|
|
+ if (!stm32mp1_supports_opp(opp_hw, cpu_type))
|
|
+ return -FDT_ERR_BADVALUE;
|
|
+
|
|
+ read_freq_64 = ofnode_read_u64_default(subnode, "opp-hz", 0) /
|
|
+ 1000ULL;
|
|
+ read_voltage_32 = ofnode_read_u32_default(subnode, "opp-microvolt", 0) /
|
|
+ 1000U;
|
|
+
|
|
+ if (!read_voltage_32 || !read_freq_64)
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+
|
|
+ /* Frequency value expressed in KHz must fit on 32 bits */
|
|
+ if (read_freq_64 > U32_MAX)
|
|
+ return -FDT_ERR_BADVALUE;
|
|
+
|
|
+ /* Millivolt value must fit on 16 bits */
|
|
+ if (read_voltage_32 > U16_MAX)
|
|
+ return -FDT_ERR_BADVALUE;
|
|
+
|
|
+ *freq_khz = (u32)read_freq_64;
|
|
+ *voltage_mv = read_voltage_32;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * parses OPP table in DT and finds the parameters for the
|
|
+ * highest frequency supported by the HW platform.
|
|
+ * Returns 0 on success and a negative FDT error code on failure.
|
|
+ */
|
|
+int stm32mp1_get_max_opp_freq(struct stm32mp1_clk_priv *priv, u64 *freq_hz)
|
|
+{
|
|
+ ofnode node, subnode;
|
|
+ int ret;
|
|
+ u32 freq = 0U, voltage = 0U;
|
|
+ u32 cpu_type = get_cpu_type();
|
|
+
|
|
+ node = ofnode_by_compatible(ofnode_null(), "operating-points-v2");
|
|
+ if (!ofnode_valid(node))
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+
|
|
+ ofnode_for_each_subnode(subnode, node) {
|
|
+ unsigned int read_freq;
|
|
+ unsigned int read_voltage;
|
|
+
|
|
+ ret = stm32mp1_get_opp(cpu_type, subnode,
|
|
+ &read_freq, &read_voltage);
|
|
+ if (ret)
|
|
+ continue;
|
|
+
|
|
+ if (read_freq > freq) {
|
|
+ freq = read_freq;
|
|
+ voltage = read_voltage;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!freq || !voltage)
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+
|
|
+ *freq_hz = (u64)1000U * freq;
|
|
+ board_vddcore_init(voltage);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int stm32mp1_pll1_opp(struct stm32mp1_clk_priv *priv, int clksrc,
|
|
+ u32 *pllcfg, u32 *fracv)
|
|
+{
|
|
+ u32 post_divm;
|
|
+ u32 input_freq;
|
|
+ u64 output_freq;
|
|
+ u64 freq;
|
|
+ u64 vco;
|
|
+ u32 divm, divn, divp, frac;
|
|
+ int i, ret;
|
|
+ u32 diff;
|
|
+ u32 best_diff = U32_MAX;
|
|
+
|
|
+ /* PLL1 is 1600 */
|
|
+ const u32 DIVN_MAX = stm32mp1_pll[PLL_1600].divn_max;
|
|
+ const u32 POST_DIVM_MIN = stm32mp1_pll[PLL_1600].refclk_min * 1000000U;
|
|
+ const u32 POST_DIVM_MAX = stm32mp1_pll[PLL_1600].refclk_max * 1000000U;
|
|
+
|
|
+ ret = stm32mp1_get_max_opp_freq(priv, &output_freq);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ switch (clksrc) {
|
|
+ case CLK_PLL12_HSI:
|
|
+ input_freq = stm32mp1_clk_get_fixed(priv, _HSI);
|
|
+ break;
|
|
+ case CLK_PLL12_HSE:
|
|
+ input_freq = stm32mp1_clk_get_fixed(priv, _HSE);
|
|
+ break;
|
|
+ default:
|
|
+ return -EINTR;
|
|
+ }
|
|
+
|
|
+ /* Following parameters have always the same value */
|
|
+ pllcfg[PLLCFG_Q] = 0;
|
|
+ pllcfg[PLLCFG_R] = 0;
|
|
+ pllcfg[PLLCFG_O] = PQR(1, 0, 0);
|
|
+
|
|
+ for (divm = DIVM_MAX; divm >= DIVM_MIN; divm--) {
|
|
+ post_divm = (u32)(input_freq / (divm + 1));
|
|
+ if (post_divm < POST_DIVM_MIN || post_divm > POST_DIVM_MAX)
|
|
+ continue;
|
|
+
|
|
+ for (divp = DIVP_MIN; divp <= DIVP_MAX; divp++) {
|
|
+ freq = output_freq * (divm + 1) * (divp + 1);
|
|
+ divn = (u32)((freq / input_freq) - 1);
|
|
+ if (divn < DIVN_MIN || divn > DIVN_MAX)
|
|
+ continue;
|
|
+
|
|
+ frac = (u32)(((freq * FRAC_MAX) / input_freq) -
|
|
+ ((divn + 1) * FRAC_MAX));
|
|
+ /* 2 loops to refine the fractional part */
|
|
+ for (i = 2; i != 0; i--) {
|
|
+ if (frac > FRAC_MAX)
|
|
+ break;
|
|
+
|
|
+ vco = (post_divm * (divn + 1)) +
|
|
+ ((post_divm * (u64)frac) /
|
|
+ FRAC_MAX);
|
|
+ if (vco < (PLL1600_VCO_MIN / 2) ||
|
|
+ vco > (PLL1600_VCO_MAX / 2)) {
|
|
+ frac++;
|
|
+ continue;
|
|
+ }
|
|
+ freq = vco / (divp + 1);
|
|
+ if (output_freq < freq)
|
|
+ diff = (u32)(freq - output_freq);
|
|
+ else
|
|
+ diff = (u32)(output_freq - freq);
|
|
+ if (diff < best_diff) {
|
|
+ pllcfg[PLLCFG_M] = divm;
|
|
+ pllcfg[PLLCFG_N] = divn;
|
|
+ pllcfg[PLLCFG_P] = divp;
|
|
+ *fracv = frac;
|
|
+
|
|
+ if (diff == 0)
|
|
+ return 0;
|
|
+
|
|
+ best_diff = diff;
|
|
+ }
|
|
+ frac++;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (best_diff == U32_MAX)
|
|
+ return -1;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static void stm32mp1_ls_osc_set(int enable, fdt_addr_t rcc, u32 offset,
|
|
u32 mask_on)
|
|
{
|
|
@@ -1678,7 +1893,10 @@ static int stm32mp1_clktree(struct udevice *dev)
|
|
unsigned int clksrc[CLKSRC_NB];
|
|
unsigned int clkdiv[CLKDIV_NB];
|
|
unsigned int pllcfg[_PLL_NB][PLLCFG_NB];
|
|
- ofnode plloff[_PLL_NB];
|
|
+ unsigned int pllfracv[_PLL_NB];
|
|
+ unsigned int pllcsg[_PLL_NB][PLLCSG_NB];
|
|
+ bool pllcfg_valid[_PLL_NB];
|
|
+ bool pllcsg_set[_PLL_NB];
|
|
int ret;
|
|
int i, len;
|
|
int lse_css = 0;
|
|
@@ -1700,16 +1918,41 @@ static int stm32mp1_clktree(struct udevice *dev)
|
|
/* check mandatory field in each pll */
|
|
for (i = 0; i < _PLL_NB; i++) {
|
|
char name[12];
|
|
+ ofnode node;
|
|
|
|
sprintf(name, "st,pll@%d", i);
|
|
- plloff[i] = dev_read_subnode(dev, name);
|
|
- if (!ofnode_valid(plloff[i]))
|
|
- continue;
|
|
- ret = ofnode_read_u32_array(plloff[i], "cfg",
|
|
- pllcfg[i], PLLCFG_NB);
|
|
- if (ret < 0) {
|
|
- debug("field cfg invalid: error %d\n", ret);
|
|
- return -FDT_ERR_NOTFOUND;
|
|
+ node = dev_read_subnode(dev, name);
|
|
+ pllcfg_valid[i] = ofnode_valid(node);
|
|
+ pllcsg_set[i] = false;
|
|
+ if (pllcfg_valid[i]) {
|
|
+ debug("DT for PLL %d @ %s\n", i, name);
|
|
+ ret = ofnode_read_u32_array(node, "cfg",
|
|
+ pllcfg[i], PLLCFG_NB);
|
|
+ if (ret < 0) {
|
|
+ debug("field cfg invalid: error %d\n", ret);
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+ pllfracv[i] = ofnode_read_u32_default(node, "frac", 0);
|
|
+
|
|
+ ret = ofnode_read_u32_array(node, "csg", pllcsg[i],
|
|
+ PLLCSG_NB);
|
|
+ if (!ret) {
|
|
+ pllcsg_set[i] = true;
|
|
+ } else if (ret != -FDT_ERR_NOTFOUND) {
|
|
+ debug("invalid csg node for pll@%d res=%d\n",
|
|
+ i, ret);
|
|
+ return ret;
|
|
+ }
|
|
+ } else if (i == _PLL1) {
|
|
+ /* use OPP for PLL1 for A7 CPU */
|
|
+ debug("DT for PLL %d with OPP\n", i);
|
|
+ ret = stm32mp1_pll1_opp(priv,
|
|
+ clksrc[CLKSRC_PLL12],
|
|
+ pllcfg[i],
|
|
+ &pllfracv[i]);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+ pllcfg_valid[i] = true;
|
|
}
|
|
}
|
|
|
|
@@ -1794,29 +2037,18 @@ static int stm32mp1_clktree(struct udevice *dev)
|
|
/* configure and start PLLs */
|
|
debug("configure PLLs\n");
|
|
for (i = 0; i < _PLL_NB; i++) {
|
|
- u32 fracv;
|
|
- u32 csg[PLLCSG_NB];
|
|
-
|
|
- debug("configure PLL %d @ %d\n", i,
|
|
- ofnode_to_offset(plloff[i]));
|
|
- if (!ofnode_valid(plloff[i]))
|
|
+ if (!pllcfg_valid[i])
|
|
continue;
|
|
-
|
|
- fracv = ofnode_read_u32_default(plloff[i], "frac", 0);
|
|
- pll_config(priv, i, pllcfg[i], fracv);
|
|
- ret = ofnode_read_u32_array(plloff[i], "csg", csg, PLLCSG_NB);
|
|
- if (!ret) {
|
|
- pll_csg(priv, i, csg);
|
|
- } else if (ret != -FDT_ERR_NOTFOUND) {
|
|
- debug("invalid csg node for pll@%d res=%d\n", i, ret);
|
|
- return ret;
|
|
- }
|
|
+ debug("configure PLL %d\n", i);
|
|
+ pll_config(priv, i, pllcfg[i], pllfracv[i]);
|
|
+ if (pllcsg_set[i])
|
|
+ pll_csg(priv, i, pllcsg[i]);
|
|
pll_start(priv, i);
|
|
}
|
|
|
|
/* wait and start PLLs ouptut when ready */
|
|
for (i = 0; i < _PLL_NB; i++) {
|
|
- if (!ofnode_valid(plloff[i]))
|
|
+ if (!pllcfg_valid[i])
|
|
continue;
|
|
debug("output PLL %d\n", i);
|
|
pll_output(priv, i, pllcfg[i][PLLCFG_O]);
|
|
diff --git a/drivers/i2c/stm32f7_i2c.c b/drivers/i2c/stm32f7_i2c.c
|
|
index 2b18735..db363a2 100644
|
|
--- a/drivers/i2c/stm32f7_i2c.c
|
|
+++ b/drivers/i2c/stm32f7_i2c.c
|
|
@@ -119,13 +119,6 @@ struct stm32_i2c_regs {
|
|
#define FAST_RATE 400000
|
|
#define FAST_PLUS_RATE 1000000
|
|
|
|
-enum stm32_i2c_speed {
|
|
- STM32_I2C_SPEED_STANDARD, /* 100 kHz */
|
|
- STM32_I2C_SPEED_FAST, /* 400 kHz */
|
|
- STM32_I2C_SPEED_FAST_PLUS, /* 1 MHz */
|
|
- STM32_I2C_SPEED_END,
|
|
-};
|
|
-
|
|
/**
|
|
* struct stm32_i2c_spec - private i2c specification timing
|
|
* @rate: I2C bus speed (Hz)
|
|
@@ -155,7 +148,6 @@ struct stm32_i2c_spec {
|
|
|
|
/**
|
|
* struct stm32_i2c_setup - private I2C timing setup parameters
|
|
- * @speed: I2C speed mode (standard, Fast Plus)
|
|
* @speed_freq: I2C speed frequency (Hz)
|
|
* @clock_src: I2C clock source frequency (Hz)
|
|
* @rise_time: Rise time (ns)
|
|
@@ -164,7 +156,6 @@ struct stm32_i2c_spec {
|
|
* @analog_filter: Analog filter delay (On/Off)
|
|
*/
|
|
struct stm32_i2c_setup {
|
|
- enum stm32_i2c_speed speed;
|
|
u32 speed_freq;
|
|
u32 clock_src;
|
|
u32 rise_time;
|
|
@@ -194,11 +185,12 @@ struct stm32_i2c_priv {
|
|
struct stm32_i2c_regs *regs;
|
|
struct clk clk;
|
|
struct stm32_i2c_setup *setup;
|
|
- int speed;
|
|
+ u32 speed;
|
|
};
|
|
|
|
static const struct stm32_i2c_spec i2c_specs[] = {
|
|
- [STM32_I2C_SPEED_STANDARD] = {
|
|
+ /* Standard speed - 100 KHz */
|
|
+ {
|
|
.rate = STANDARD_RATE,
|
|
.rate_min = 8000,
|
|
.rate_max = 120000,
|
|
@@ -210,7 +202,8 @@ static const struct stm32_i2c_spec i2c_specs[] = {
|
|
.l_min = 4700,
|
|
.h_min = 4000,
|
|
},
|
|
- [STM32_I2C_SPEED_FAST] = {
|
|
+ /* Fast speed - 400 KHz */
|
|
+ {
|
|
.rate = FAST_RATE,
|
|
.rate_min = 320000,
|
|
.rate_max = 480000,
|
|
@@ -222,7 +215,8 @@ static const struct stm32_i2c_spec i2c_specs[] = {
|
|
.l_min = 1300,
|
|
.h_min = 600,
|
|
},
|
|
- [STM32_I2C_SPEED_FAST_PLUS] = {
|
|
+ /* Fast Plus Speed - 1 MHz */
|
|
+ {
|
|
.rate = FAST_PLUS_RATE,
|
|
.rate_min = 800000,
|
|
.rate_max = 1200000,
|
|
@@ -484,6 +478,7 @@ static int stm32_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
|
|
}
|
|
|
|
static int stm32_i2c_compute_solutions(struct stm32_i2c_setup *setup,
|
|
+ const struct stm32_i2c_spec *specs,
|
|
struct list_head *solutions)
|
|
{
|
|
struct stm32_i2c_timings *v;
|
|
@@ -500,13 +495,13 @@ static int stm32_i2c_compute_solutions(struct stm32_i2c_setup *setup,
|
|
af_delay_max = setup->analog_filter ?
|
|
STM32_I2C_ANALOG_FILTER_DELAY_MAX : 0;
|
|
|
|
- sdadel_min = i2c_specs[setup->speed].hddat_min + setup->fall_time -
|
|
+ sdadel_min = specs->hddat_min + setup->fall_time -
|
|
af_delay_min - (setup->dnf + 3) * i2cclk;
|
|
|
|
- sdadel_max = i2c_specs[setup->speed].vddat_max - setup->rise_time -
|
|
+ sdadel_max = specs->vddat_max - setup->rise_time -
|
|
af_delay_max - (setup->dnf + 4) * i2cclk;
|
|
|
|
- scldel_min = setup->rise_time + i2c_specs[setup->speed].sudat_min;
|
|
+ scldel_min = setup->rise_time + specs->sudat_min;
|
|
|
|
if (sdadel_min < 0)
|
|
sdadel_min = 0;
|
|
@@ -558,6 +553,7 @@ static int stm32_i2c_compute_solutions(struct stm32_i2c_setup *setup,
|
|
}
|
|
|
|
static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup,
|
|
+ const struct stm32_i2c_spec *specs,
|
|
struct list_head *solutions,
|
|
struct stm32_i2c_timings *s)
|
|
{
|
|
@@ -580,8 +576,8 @@ static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup,
|
|
dnf_delay = setup->dnf * i2cclk;
|
|
|
|
tsync = af_delay_min + dnf_delay + (2 * i2cclk);
|
|
- clk_max = STM32_NSEC_PER_SEC / i2c_specs[setup->speed].rate_min;
|
|
- clk_min = STM32_NSEC_PER_SEC / i2c_specs[setup->speed].rate_max;
|
|
+ clk_max = STM32_NSEC_PER_SEC / specs->rate_min;
|
|
+ clk_min = STM32_NSEC_PER_SEC / specs->rate_max;
|
|
|
|
/*
|
|
* Among Prescaler possibilities discovered above figures out SCL Low
|
|
@@ -599,7 +595,7 @@ static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup,
|
|
for (l = 0; l < STM32_SCLL_MAX; l++) {
|
|
u32 tscl_l = (l + 1) * prescaler + tsync;
|
|
|
|
- if ((tscl_l < i2c_specs[setup->speed].l_min) ||
|
|
+ if (tscl_l < specs->l_min ||
|
|
(i2cclk >=
|
|
((tscl_l - af_delay_min - dnf_delay) / 4))) {
|
|
continue;
|
|
@@ -611,7 +607,7 @@ static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup,
|
|
setup->rise_time + setup->fall_time;
|
|
|
|
if ((tscl >= clk_min) && (tscl <= clk_max) &&
|
|
- (tscl_h >= i2c_specs[setup->speed].h_min) &&
|
|
+ (tscl_h >= specs->h_min) &&
|
|
(i2cclk < tscl_h)) {
|
|
u32 clk_error;
|
|
|
|
@@ -640,26 +636,40 @@ static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup,
|
|
return ret;
|
|
}
|
|
|
|
+static const struct stm32_i2c_spec *get_specs(u32 rate)
|
|
+{
|
|
+ unsigned int i;
|
|
+
|
|
+ for (i = 0; i < ARRAY_SIZE(i2c_specs); i++)
|
|
+ if (rate <= i2c_specs[i].rate)
|
|
+ return &i2c_specs[i];
|
|
+
|
|
+ /* NOT REACHED */
|
|
+ return ERR_PTR(-EINVAL);
|
|
+}
|
|
+
|
|
static int stm32_i2c_compute_timing(struct stm32_i2c_priv *i2c_priv,
|
|
struct stm32_i2c_setup *setup,
|
|
struct stm32_i2c_timings *output)
|
|
{
|
|
+ const struct stm32_i2c_spec *specs;
|
|
struct stm32_i2c_timings *v, *_v;
|
|
struct list_head solutions;
|
|
int ret;
|
|
|
|
- if (setup->speed >= STM32_I2C_SPEED_END) {
|
|
- pr_err("%s: speed out of bound {%d/%d}\n", __func__,
|
|
- setup->speed, STM32_I2C_SPEED_END - 1);
|
|
+ specs = get_specs(setup->speed_freq);
|
|
+ if (specs == ERR_PTR(-EINVAL)) {
|
|
+ pr_err("%s: speed out of bound {%d}\n", __func__,
|
|
+ setup->speed_freq);
|
|
return -EINVAL;
|
|
}
|
|
|
|
- if ((setup->rise_time > i2c_specs[setup->speed].rise_max) ||
|
|
- (setup->fall_time > i2c_specs[setup->speed].fall_max)) {
|
|
+ if (setup->rise_time > specs->rise_max ||
|
|
+ setup->fall_time > specs->fall_max) {
|
|
pr_err("%s :timings out of bound Rise{%d>%d}/Fall{%d>%d}\n",
|
|
__func__,
|
|
- setup->rise_time, i2c_specs[setup->speed].rise_max,
|
|
- setup->fall_time, i2c_specs[setup->speed].fall_max);
|
|
+ setup->rise_time, specs->rise_max,
|
|
+ setup->fall_time, specs->fall_max);
|
|
return -EINVAL;
|
|
}
|
|
|
|
@@ -669,18 +679,12 @@ static int stm32_i2c_compute_timing(struct stm32_i2c_priv *i2c_priv,
|
|
return -EINVAL;
|
|
}
|
|
|
|
- if (setup->speed_freq > i2c_specs[setup->speed].rate) {
|
|
- pr_err("%s: Freq {%d/%d}\n", __func__,
|
|
- setup->speed_freq, i2c_specs[setup->speed].rate);
|
|
- return -EINVAL;
|
|
- }
|
|
-
|
|
INIT_LIST_HEAD(&solutions);
|
|
- ret = stm32_i2c_compute_solutions(setup, &solutions);
|
|
+ ret = stm32_i2c_compute_solutions(setup, specs, &solutions);
|
|
if (ret)
|
|
goto exit;
|
|
|
|
- ret = stm32_i2c_choose_solution(setup, &solutions, output);
|
|
+ ret = stm32_i2c_choose_solution(setup, specs, &solutions, output);
|
|
if (ret)
|
|
goto exit;
|
|
|
|
@@ -699,14 +703,24 @@ exit:
|
|
return ret;
|
|
}
|
|
|
|
+static u32 get_lower_rate(u32 rate)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ for (i = ARRAY_SIZE(i2c_specs) - 1; i >= 0; i--)
|
|
+ if (rate > i2c_specs[i].rate)
|
|
+ return i2c_specs[i].rate;
|
|
+
|
|
+ return i2c_specs[0].rate;
|
|
+}
|
|
+
|
|
static int stm32_i2c_setup_timing(struct stm32_i2c_priv *i2c_priv,
|
|
struct stm32_i2c_timings *timing)
|
|
{
|
|
struct stm32_i2c_setup *setup = i2c_priv->setup;
|
|
int ret = 0;
|
|
|
|
- setup->speed = i2c_priv->speed;
|
|
- setup->speed_freq = i2c_specs[setup->speed].rate;
|
|
+ setup->speed_freq = i2c_priv->speed;
|
|
setup->clock_src = clk_get_rate(&i2c_priv->clk);
|
|
|
|
if (!setup->clock_src) {
|
|
@@ -719,13 +733,11 @@ static int stm32_i2c_setup_timing(struct stm32_i2c_priv *i2c_priv,
|
|
if (ret) {
|
|
debug("%s: failed to compute I2C timings.\n",
|
|
__func__);
|
|
- if (i2c_priv->speed > STM32_I2C_SPEED_STANDARD) {
|
|
- i2c_priv->speed--;
|
|
- setup->speed = i2c_priv->speed;
|
|
+ if (setup->speed_freq > STANDARD_RATE) {
|
|
setup->speed_freq =
|
|
- i2c_specs[setup->speed].rate;
|
|
+ get_lower_rate(setup->speed_freq);
|
|
debug("%s: downgrade I2C Speed Freq to (%i)\n",
|
|
- __func__, i2c_specs[setup->speed].rate);
|
|
+ __func__, setup->speed_freq);
|
|
} else {
|
|
break;
|
|
}
|
|
@@ -737,13 +749,15 @@ static int stm32_i2c_setup_timing(struct stm32_i2c_priv *i2c_priv,
|
|
return ret;
|
|
}
|
|
|
|
- debug("%s: I2C Speed(%i), Freq(%i), Clk Source(%i)\n", __func__,
|
|
- setup->speed, setup->speed_freq, setup->clock_src);
|
|
+ debug("%s: I2C Freq(%i), Clk Source(%i)\n", __func__,
|
|
+ setup->speed_freq, setup->clock_src);
|
|
debug("%s: I2C Rise(%i) and Fall(%i) Time\n", __func__,
|
|
setup->rise_time, setup->fall_time);
|
|
debug("%s: I2C Analog Filter(%s), DNF(%i)\n", __func__,
|
|
setup->analog_filter ? "On" : "Off", setup->dnf);
|
|
|
|
+ i2c_priv->speed = setup->speed_freq;
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -783,21 +797,13 @@ static int stm32_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
|
|
{
|
|
struct stm32_i2c_priv *i2c_priv = dev_get_priv(bus);
|
|
|
|
- switch (speed) {
|
|
- case STANDARD_RATE:
|
|
- i2c_priv->speed = STM32_I2C_SPEED_STANDARD;
|
|
- break;
|
|
- case FAST_RATE:
|
|
- i2c_priv->speed = STM32_I2C_SPEED_FAST;
|
|
- break;
|
|
- case FAST_PLUS_RATE:
|
|
- i2c_priv->speed = STM32_I2C_SPEED_FAST_PLUS;
|
|
- break;
|
|
- default:
|
|
+ if (speed > FAST_PLUS_RATE) {
|
|
debug("%s: Speed %d not supported\n", __func__, speed);
|
|
return -EINVAL;
|
|
}
|
|
|
|
+ i2c_priv->speed = speed;
|
|
+
|
|
return stm32_i2c_hw_config(i2c_priv);
|
|
}
|
|
|
|
diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c
|
|
index f73f072..79ced50 100644
|
|
--- a/drivers/mmc/mmc-uclass.c
|
|
+++ b/drivers/mmc/mmc-uclass.c
|
|
@@ -120,6 +120,20 @@ int mmc_execute_tuning(struct mmc *mmc, uint opcode)
|
|
}
|
|
#endif
|
|
|
|
+int dm_mmc_host_power_cycle(struct udevice *dev)
|
|
+{
|
|
+ struct dm_mmc_ops *ops = mmc_get_ops(dev);
|
|
+
|
|
+ if (ops->host_power_cycle)
|
|
+ return ops->host_power_cycle(dev);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int mmc_host_power_cycle(struct mmc *mmc)
|
|
+{
|
|
+ return dm_mmc_host_power_cycle(mmc->dev);
|
|
+}
|
|
+
|
|
int mmc_of_parse(struct udevice *dev, struct mmc_config *cfg)
|
|
{
|
|
int val;
|
|
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
|
|
index 585951c..826565f 100644
|
|
--- a/drivers/mmc/mmc.c
|
|
+++ b/drivers/mmc/mmc.c
|
|
@@ -1486,6 +1486,16 @@ static int mmc_set_ios(struct mmc *mmc)
|
|
|
|
return ret;
|
|
}
|
|
+
|
|
+static int mmc_host_power_cycle(struct mmc *mmc)
|
|
+{
|
|
+ int ret = 0;
|
|
+
|
|
+ if (mmc->cfg->ops->host_power_cycle)
|
|
+ ret = mmc->cfg->ops->host_power_cycle(mmc);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
#endif
|
|
|
|
int mmc_set_clock(struct mmc *mmc, uint clock, bool disable)
|
|
@@ -2566,6 +2576,11 @@ static int mmc_power_cycle(struct mmc *mmc)
|
|
ret = mmc_power_off(mmc);
|
|
if (ret)
|
|
return ret;
|
|
+
|
|
+ ret = mmc_host_power_cycle(mmc);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
/*
|
|
* SD spec recommends at least 1ms of delay. Let's wait for 2ms
|
|
* to be on the safer side.
|
|
diff --git a/drivers/mmc/stm32_sdmmc2.c b/drivers/mmc/stm32_sdmmc2.c
|
|
index 32434a4..1726ed7 100644
|
|
--- a/drivers/mmc/stm32_sdmmc2.c
|
|
+++ b/drivers/mmc/stm32_sdmmc2.c
|
|
@@ -524,8 +524,6 @@ static void stm32_sdmmc2_pwrcycle(struct stm32_sdmmc2_priv *priv)
|
|
return;
|
|
|
|
stm32_sdmmc2_reset(priv);
|
|
- writel(SDMMC_POWER_PWRCTRL_CYCLE | priv->pwr_reg_msk,
|
|
- priv->base + SDMMC_POWER);
|
|
}
|
|
|
|
/*
|
|
@@ -619,10 +617,21 @@ static int stm32_sdmmc2_getcd(struct udevice *dev)
|
|
return 1;
|
|
}
|
|
|
|
+static int stm32_sdmmc2_host_power_cycle(struct udevice *dev)
|
|
+{
|
|
+ struct stm32_sdmmc2_priv *priv = dev_get_priv(dev);
|
|
+
|
|
+ writel(SDMMC_POWER_PWRCTRL_CYCLE | priv->pwr_reg_msk,
|
|
+ priv->base + SDMMC_POWER);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static const struct dm_mmc_ops stm32_sdmmc2_ops = {
|
|
.send_cmd = stm32_sdmmc2_send_cmd,
|
|
.set_ios = stm32_sdmmc2_set_ios,
|
|
.get_cd = stm32_sdmmc2_getcd,
|
|
+ .host_power_cycle = stm32_sdmmc2_host_power_cycle,
|
|
};
|
|
|
|
static int stm32_sdmmc2_probe(struct udevice *dev)
|
|
diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c
|
|
index 5b933fb..d8887c1 100644
|
|
--- a/drivers/net/dwc_eth_qos.c
|
|
+++ b/drivers/net/dwc_eth_qos.c
|
|
@@ -692,6 +692,30 @@ static int eqos_start_resets_tegra186(struct udevice *dev)
|
|
|
|
static int eqos_start_resets_stm32(struct udevice *dev)
|
|
{
|
|
+ struct eqos_priv *eqos = dev_get_priv(dev);
|
|
+ int ret;
|
|
+
|
|
+ debug("%s(dev=%p):\n", __func__, dev);
|
|
+
|
|
+ if (dm_gpio_is_valid(&eqos->phy_reset_gpio)) {
|
|
+ ret = dm_gpio_set_value(&eqos->phy_reset_gpio, 1);
|
|
+ if (ret < 0) {
|
|
+ pr_err("dm_gpio_set_value(phy_reset, assert) failed: %d",
|
|
+ ret);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ udelay(2);
|
|
+
|
|
+ ret = dm_gpio_set_value(&eqos->phy_reset_gpio, 0);
|
|
+ if (ret < 0) {
|
|
+ pr_err("dm_gpio_set_value(phy_reset, deassert) failed: %d",
|
|
+ ret);
|
|
+ return ret;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ debug("%s: OK\n", __func__);
|
|
return 0;
|
|
}
|
|
|
|
@@ -707,6 +731,11 @@ static int eqos_stop_resets_tegra186(struct udevice *dev)
|
|
|
|
static int eqos_stop_resets_stm32(struct udevice *dev)
|
|
{
|
|
+ struct eqos_priv *eqos = dev_get_priv(dev);
|
|
+
|
|
+ if (dm_gpio_is_valid(&eqos->phy_reset_gpio))
|
|
+ dm_gpio_set_value(&eqos->phy_reset_gpio, 1);
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -1604,7 +1633,7 @@ static int eqos_probe_resources_stm32(struct udevice *dev)
|
|
int interface;
|
|
bool eth_clk_sel_reg = false;
|
|
bool eth_ref_clk_sel_reg = false;
|
|
-
|
|
+ struct ofnode_phandle_args phandle_args;
|
|
|
|
debug("%s(dev=%p):\n", __func__, dev);
|
|
|
|
@@ -1650,6 +1679,19 @@ static int eqos_probe_resources_stm32(struct udevice *dev)
|
|
if (ret)
|
|
pr_warn("No phy clock provided %d", ret);
|
|
|
|
+ /* search "reset-gpios" in phy node */
|
|
+ ret = dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, 0,
|
|
+ &phandle_args);
|
|
+ if (!ret) {
|
|
+ ret = gpio_request_by_name_nodev(phandle_args.node,
|
|
+ "reset-gpios", 0,
|
|
+ &eqos->phy_reset_gpio,
|
|
+ GPIOD_IS_OUT |
|
|
+ GPIOD_IS_OUT_ACTIVE);
|
|
+ }
|
|
+ if (ret)
|
|
+ pr_warn("gpio_request_by_name(phy reset) not provided %d", ret);
|
|
+
|
|
debug("%s: OK\n", __func__);
|
|
return 0;
|
|
|
|
@@ -1713,6 +1755,9 @@ static int eqos_remove_resources_stm32(struct udevice *dev)
|
|
if (clk_valid(&eqos->clk_ck))
|
|
clk_free(&eqos->clk_ck);
|
|
|
|
+ if (dm_gpio_is_valid(&eqos->phy_reset_gpio))
|
|
+ dm_gpio_free(dev, &eqos->phy_reset_gpio);
|
|
+
|
|
debug("%s: OK\n", __func__);
|
|
return 0;
|
|
}
|
|
diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr.c b/drivers/ram/stm32mp1/stm32mp1_ddr.c
|
|
index f6484da..c87882d 100644
|
|
--- a/drivers/ram/stm32mp1/stm32mp1_ddr.c
|
|
+++ b/drivers/ram/stm32mp1/stm32mp1_ddr.c
|
|
@@ -855,14 +855,34 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
|
|
{
|
|
u32 pir;
|
|
int ret = -EINVAL;
|
|
+ char bus_width;
|
|
+
|
|
+ switch (config->c_reg.mstr & DDRCTRL_MSTR_DATA_BUS_WIDTH_MASK) {
|
|
+ case DDRCTRL_MSTR_DATA_BUS_WIDTH_QUARTER:
|
|
+ bus_width = 8;
|
|
+ break;
|
|
+ case DDRCTRL_MSTR_DATA_BUS_WIDTH_HALF:
|
|
+ bus_width = 16;
|
|
+ break;
|
|
+ default:
|
|
+ bus_width = 32;
|
|
+ break;
|
|
+ }
|
|
+
|
|
|
|
if (config->c_reg.mstr & DDRCTRL_MSTR_DDR3)
|
|
ret = board_ddr_power_init(STM32MP_DDR3);
|
|
- else if (config->c_reg.mstr & DDRCTRL_MSTR_LPDDR2)
|
|
- ret = board_ddr_power_init(STM32MP_LPDDR2);
|
|
- else if (config->c_reg.mstr & DDRCTRL_MSTR_LPDDR3)
|
|
- ret = board_ddr_power_init(STM32MP_LPDDR3);
|
|
-
|
|
+ else if (config->c_reg.mstr & DDRCTRL_MSTR_LPDDR2) {
|
|
+ if (bus_width == 32)
|
|
+ ret = board_ddr_power_init(STM32MP_LPDDR2_32);
|
|
+ else
|
|
+ ret = board_ddr_power_init(STM32MP_LPDDR2_16);
|
|
+ } else if (config->c_reg.mstr & DDRCTRL_MSTR_LPDDR3) {
|
|
+ if (bus_width == 32)
|
|
+ ret = board_ddr_power_init(STM32MP_LPDDR3_32);
|
|
+ else
|
|
+ ret = board_ddr_power_init(STM32MP_LPDDR3_16);
|
|
+ }
|
|
if (ret)
|
|
panic("ddr power init failed\n");
|
|
|
|
diff --git a/drivers/ram/stm32mp1/stm32mp1_interactive.c b/drivers/ram/stm32mp1/stm32mp1_interactive.c
|
|
index 8df6a39..62da596 100644
|
|
--- a/drivers/ram/stm32mp1/stm32mp1_interactive.c
|
|
+++ b/drivers/ram/stm32mp1/stm32mp1_interactive.c
|
|
@@ -367,7 +367,6 @@ bool stm32mp1_ddr_interactive(void *priv,
|
|
enum stm32mp1_ddr_interact_step step,
|
|
const struct stm32mp1_ddr_config *config)
|
|
{
|
|
- const char *prompt = "DDR>";
|
|
char buffer[CONFIG_SYS_CBSIZE];
|
|
char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */
|
|
int argc;
|
|
@@ -403,13 +402,12 @@ bool stm32mp1_ddr_interactive(void *priv,
|
|
}
|
|
|
|
printf("%d:%s\n", step, step_str[step]);
|
|
- printf("%s\n", prompt);
|
|
|
|
if (next_step > step)
|
|
return false;
|
|
|
|
while (next_step == step) {
|
|
- cli_readline_into_buffer(prompt, buffer, 0);
|
|
+ cli_readline_into_buffer("DDR>", buffer, 0);
|
|
argc = cli_simple_parse_line(buffer, argv);
|
|
if (!argc)
|
|
continue;
|
|
diff --git a/drivers/remoteproc/rproc-uclass.c b/drivers/remoteproc/rproc-uclass.c
|
|
index 36f1e97..89eed8c 100644
|
|
--- a/drivers/remoteproc/rproc-uclass.c
|
|
+++ b/drivers/remoteproc/rproc-uclass.c
|
|
@@ -244,6 +244,7 @@ UCLASS_DRIVER(rproc) = {
|
|
.flags = DM_UC_FLAG_SEQ_ALIAS,
|
|
.pre_probe = rproc_pre_probe,
|
|
.post_probe = rproc_post_probe,
|
|
+ .per_device_auto_alloc_size = sizeof(struct rproc_priv),
|
|
.per_device_platdata_auto_alloc_size =
|
|
sizeof(struct dm_rproc_uclass_pdata),
|
|
};
|
|
@@ -432,7 +433,7 @@ static int rproc_load_elf_image(struct udevice *dev, unsigned long addr,
|
|
}
|
|
|
|
/* Load each program header */
|
|
- for (i = 0; i < ehdr->e_phnum; ++i) {
|
|
+ for (i = 0; i < ehdr->e_phnum; ++i, phdr++) {
|
|
void *dst = (void *)(uintptr_t)phdr->p_paddr;
|
|
void *src = (void *)addr + phdr->p_offset;
|
|
|
|
@@ -453,7 +454,6 @@ static int rproc_load_elf_image(struct udevice *dev, unsigned long addr,
|
|
roundup((unsigned long)dst + phdr->p_filesz,
|
|
ARCH_DMA_MINALIGN) -
|
|
rounddown((unsigned long)dst, ARCH_DMA_MINALIGN));
|
|
- ++phdr;
|
|
}
|
|
|
|
*entry = ehdr->e_entry;
|
|
@@ -625,6 +625,7 @@ int rproc_load_rsc_table(int id, ulong addr, ulong size, ulong *rsc_addr,
|
|
{
|
|
struct udevice *dev = NULL;
|
|
const struct dm_rproc_ops *ops;
|
|
+ struct rproc_priv *priv;
|
|
int ret;
|
|
|
|
ret = uclass_get_device_by_seq(UCLASS_REMOTEPROC, id, &dev);
|
|
@@ -640,23 +641,27 @@ int rproc_load_rsc_table(int id, ulong addr, ulong size, ulong *rsc_addr,
|
|
return -EINVAL;
|
|
}
|
|
|
|
- dev_dbg(dev, "Loocking for resource table from address 0x%08lX size of %lu bytes\n",
|
|
+ dev_dbg(dev, "Looking for resource table from address 0x%08lX size of %lu bytes\n",
|
|
addr, size);
|
|
|
|
- if (!rproc_elf_sanity_check(dev, addr, size)) {
|
|
- /* load elf image */
|
|
- ret = rproc_elf_find_load_rsc_table(dev, addr, size, rsc_addr,
|
|
- rsc_size);
|
|
- if (ret) {
|
|
- dev_dbg(dev, "No resource table found\n");
|
|
- return -ENODATA;
|
|
- }
|
|
- dev_dbg(dev, "Resource table at 0x%08lx, size 0x%x!\n",
|
|
- *rsc_addr, *rsc_size);
|
|
- return 0;
|
|
+ ret = rproc_elf_sanity_check(dev, addr, size);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = rproc_elf_find_load_rsc_table(dev, addr, size, rsc_addr,
|
|
+ rsc_size);
|
|
+ if (ret) {
|
|
+ dev_dbg(dev, "No resource table found\n");
|
|
+ return -ENODATA;
|
|
}
|
|
|
|
- return -ENODATA;
|
|
+ priv = dev_get_uclass_priv(dev);
|
|
+ priv->rsc_table_addr = *rsc_addr;
|
|
+ priv->rsc_table_size = *rsc_size;
|
|
+ dev_dbg(dev, "Resource table at 0x%08lx, size 0x%x!\n",
|
|
+ priv->rsc_table_addr, priv->rsc_table_size);
|
|
+
|
|
+ return 0;
|
|
};
|
|
|
|
/*
|
|
diff --git a/drivers/remoteproc/stm32_copro.c b/drivers/remoteproc/stm32_copro.c
|
|
index 0a8b900..9fed8c8 100644
|
|
--- a/drivers/remoteproc/stm32_copro.c
|
|
+++ b/drivers/remoteproc/stm32_copro.c
|
|
@@ -12,6 +12,7 @@
|
|
#include <reset.h>
|
|
#include <syscon.h>
|
|
#include <asm/arch/stm32mp1_smc.h>
|
|
+#include <asm/io.h>
|
|
|
|
#define RCC_GCR_HOLD_BOOT 0
|
|
#define RCC_GCR_RELEASE_BOOT 1
|
|
@@ -202,6 +203,7 @@ static int stm32_copro_load(struct udevice *dev, ulong addr, ulong size)
|
|
*/
|
|
static int stm32_copro_start(struct udevice *dev)
|
|
{
|
|
+ struct rproc_priv *uc_priv = dev_get_uclass_priv(dev);
|
|
int ret;
|
|
|
|
/* move hold boot from true to false start the copro */
|
|
@@ -213,7 +215,12 @@ static int stm32_copro_start(struct udevice *dev)
|
|
* Once copro running, reset hold boot flag to avoid copro
|
|
* rebooting autonomously
|
|
*/
|
|
- return stm32_copro_set_hold_boot(dev, true);
|
|
+ ret = stm32_copro_set_hold_boot(dev, true);
|
|
+ if (!ret)
|
|
+ /* Store rsc_address in bkp register */
|
|
+ writel(uc_priv->rsc_table_addr, TAMP_COPRO_RSC_TBL_ADDRESS);
|
|
+
|
|
+ return ret;
|
|
}
|
|
|
|
/**
|
|
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
|
|
index 8809552..890212de 100644
|
|
--- a/drivers/video/Kconfig
|
|
+++ b/drivers/video/Kconfig
|
|
@@ -74,7 +74,8 @@ config VIDEO_ANSI
|
|
console.
|
|
|
|
config VIDEO_MIPI_DSI
|
|
- bool
|
|
+ bool "Support MIPI DSI interface"
|
|
+ depends on DM_VIDEO
|
|
help
|
|
Support MIPI DSI interface for driving a MIPI compatible device.
|
|
The MIPI Display Serial Interface (MIPI DSI) defines a high-speed
|
|
@@ -332,16 +333,18 @@ config VIDEO_LCD_ORISETECH_OTM8009A
|
|
depends on DM_VIDEO
|
|
select VIDEO_MIPI_DSI
|
|
default n
|
|
- ---help---
|
|
- Support for Orise Tech otm8009a 480p dsi 2dl video mode panel.
|
|
+ help
|
|
+ Say Y here if you want to enable support for Orise Technology
|
|
+ otm8009a 480x800 dsi 2dl panel.
|
|
|
|
config VIDEO_LCD_RAYDIUM_RM68200
|
|
bool "RM68200 DSI LCD panel support"
|
|
depends on DM_VIDEO
|
|
select VIDEO_MIPI_DSI
|
|
default n
|
|
- ---help---
|
|
- Support for Raydium rm68200 720x1280 dsi 2dl video mode panel.
|
|
+ help
|
|
+ Say Y here if you want to enable support for Raydium RM68200
|
|
+ 720x1280 DSI video mode panel.
|
|
|
|
config VIDEO_LCD_SSD2828
|
|
bool "SSD2828 bridge chip"
|
|
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
|
|
index c3d39ed..796eb6c 100644
|
|
--- a/drivers/video/Makefile
|
|
+++ b/drivers/video/Makefile
|
|
@@ -11,6 +11,7 @@ obj-$(CONFIG_CONSOLE_ROTATION) += console_rotate.o
|
|
obj-$(CONFIG_CONSOLE_TRUETYPE) += console_truetype.o fonts/
|
|
obj-$(CONFIG_DISPLAY) += display-uclass.o
|
|
obj-$(CONFIG_DM_VIDEO) += backlight-uclass.o
|
|
+obj-$(CONFIG_DM_VIDEO) += dsi-host-uclass.o
|
|
obj-$(CONFIG_DM_VIDEO) += panel-uclass.o simple_panel.o
|
|
obj-$(CONFIG_DM_VIDEO) += video-uclass.o vidconsole-uclass.o
|
|
obj-$(CONFIG_DM_VIDEO) += video_bmp.o
|
|
@@ -44,6 +45,7 @@ obj-$(CONFIG_VIDEO_BROADWELL_IGD) += broadwell_igd.o
|
|
obj-$(CONFIG_VIDEO_COREBOOT) += coreboot.o
|
|
obj-$(CONFIG_VIDEO_DA8XX) += da8xx-fb.o videomodes.o
|
|
obj-$(CONFIG_VIDEO_DW_HDMI) += dw_hdmi.o
|
|
+obj-$(CONFIG_VIDEO_DW_MIPI_DSI) += dw_mipi_dsi.o
|
|
obj-$(CONFIG_VIDEO_EFI) += efi.o
|
|
obj-$(CONFIG_VIDEO_FSL_DCU_FB) += fsl_dcu_fb.o videomodes.o
|
|
obj-$(CONFIG_VIDEO_IPUV3) += mxc_ipuv3_fb.o ipu_common.o ipu_disp.o
|
|
@@ -54,6 +56,7 @@ obj-$(CONFIG_VIDEO_LCD_ORISETECH_OTM8009A) += orisetech_otm8009a.o
|
|
obj-$(CONFIG_VIDEO_LCD_RAYDIUM_RM68200) += raydium-rm68200.o
|
|
obj-$(CONFIG_VIDEO_LCD_SSD2828) += ssd2828.o
|
|
obj-$(CONFIG_VIDEO_MB862xx) += mb862xx.o videomodes.o
|
|
+obj-${CONFIG_VIDEO_MIPI_DSI} += mipi_dsi.o
|
|
obj-$(CONFIG_VIDEO_MVEBU) += mvebu_lcd.o
|
|
obj-$(CONFIG_VIDEO_MX3) += mx3fb.o videomodes.o
|
|
obj-$(CONFIG_VIDEO_MXS) += mxsfb.o videomodes.o
|
|
@@ -63,8 +66,6 @@ obj-$(CONFIG_VIDEO_SIMPLE) += simplefb.o
|
|
obj-$(CONFIG_VIDEO_TEGRA20) += tegra.o
|
|
obj-$(CONFIG_VIDEO_VCXK) += bus_vcxk.o
|
|
obj-$(CONFIG_VIDEO_VESA) += vesa.o
|
|
-obj-$(CONFIG_VIDEO_DW_MIPI_DSI) += dw_mipi_dsi.o
|
|
-obj-${CONFIG_VIDEO_MIPI_DSI} += mipi_display.o
|
|
|
|
obj-y += bridge/
|
|
obj-y += sunxi/
|
|
diff --git a/drivers/video/dsi-host-uclass.c b/drivers/video/dsi-host-uclass.c
|
|
new file mode 100644
|
|
index 0000000..1db1f88
|
|
--- /dev/null
|
|
+++ b/drivers/video/dsi-host-uclass.c
|
|
@@ -0,0 +1,39 @@
|
|
+// SPDX-License-Identifier: GPL-2.0+
|
|
+/*
|
|
+ * Copyright (C) 2019 STMicroelectronics - All Rights Reserved
|
|
+ * Author(s): Yannick Fertre <yannick.fertre@st.com> for STMicroelectronics.
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include <common.h>
|
|
+#include <dm.h>
|
|
+#include <dsi_host.h>
|
|
+
|
|
+int dsi_host_init(struct udevice *dev,
|
|
+ struct mipi_dsi_device *device,
|
|
+ struct display_timing *timings,
|
|
+ unsigned int max_data_lanes,
|
|
+ const struct mipi_dsi_phy_ops *phy_ops)
|
|
+{
|
|
+ struct dsi_host_ops *ops = dsi_host_get_ops(dev);
|
|
+
|
|
+ if (!ops->init)
|
|
+ return -ENOSYS;
|
|
+
|
|
+ return ops->init(dev, device, timings, max_data_lanes, phy_ops);
|
|
+}
|
|
+
|
|
+int dsi_host_enable(struct udevice *dev)
|
|
+{
|
|
+ struct dsi_host_ops *ops = dsi_host_get_ops(dev);
|
|
+
|
|
+ if (!ops->enable)
|
|
+ return -ENOSYS;
|
|
+
|
|
+ return ops->enable(dev);
|
|
+}
|
|
+
|
|
+UCLASS_DRIVER(dsi_host) = {
|
|
+ .id = UCLASS_DSI_HOST,
|
|
+ .name = "dsi_host",
|
|
+};
|
|
diff --git a/drivers/video/dw_mipi_dsi.c b/drivers/video/dw_mipi_dsi.c
|
|
index fe1e25a..83d7c7b 100644
|
|
--- a/drivers/video/dw_mipi_dsi.c
|
|
+++ b/drivers/video/dw_mipi_dsi.c
|
|
@@ -1,25 +1,24 @@
|
|
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* Copyright (C) 2016, Fuzhou Rockchip Electronics Co., Ltd
|
|
- * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
|
|
+ * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
|
|
* Author(s): Philippe Cornu <philippe.cornu@st.com> for STMicroelectronics.
|
|
* Yannick Fertre <yannick.fertre@st.com> for STMicroelectronics.
|
|
*
|
|
- * This generic Synopsys DesignWare MIPI DSI host driver is based on the
|
|
- * Linux Kernel driver from drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c.
|
|
+ * This generic Synopsys DesignWare MIPI DSI host driver is inspired from
|
|
+ * the Linux Kernel driver drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c.
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <clk.h>
|
|
+#include <dsi_host.h>
|
|
#include <dm.h>
|
|
#include <errno.h>
|
|
-#include <mipi_display.h>
|
|
#include <panel.h>
|
|
#include <video.h>
|
|
#include <asm/io.h>
|
|
#include <asm/arch/gpio.h>
|
|
#include <dm/device-internal.h>
|
|
-#include <dw_mipi_dsi.h>
|
|
#include <linux/iopoll.h>
|
|
#include <video_bridge.h>
|
|
|
|
@@ -221,11 +220,8 @@ struct dw_mipi_dsi {
|
|
void __iomem *base;
|
|
unsigned int lane_mbps; /* per lane */
|
|
u32 channel;
|
|
- u32 lanes;
|
|
- u32 format;
|
|
- unsigned long mode_flags;
|
|
unsigned int max_data_lanes;
|
|
- const struct dw_mipi_dsi_phy_ops *phy_ops;
|
|
+ const struct mipi_dsi_phy_ops *phy_ops;
|
|
};
|
|
|
|
static int dsi_mode_vrefresh(struct display_timing *timings)
|
|
@@ -286,10 +282,7 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
|
|
return -EINVAL;
|
|
}
|
|
|
|
- dsi->lanes = device->lanes;
|
|
dsi->channel = device->channel;
|
|
- dsi->format = device->format;
|
|
- dsi->mode_flags = device->mode_flags;
|
|
|
|
return 0;
|
|
}
|
|
@@ -444,6 +437,7 @@ static const struct mipi_dsi_host_ops dw_mipi_dsi_host_ops = {
|
|
|
|
static void dw_mipi_dsi_video_mode_config(struct dw_mipi_dsi *dsi)
|
|
{
|
|
+ struct mipi_dsi_device *device = dsi->device;
|
|
u32 val;
|
|
|
|
/*
|
|
@@ -453,9 +447,9 @@ static void dw_mipi_dsi_video_mode_config(struct dw_mipi_dsi *dsi)
|
|
*/
|
|
val = ENABLE_LOW_POWER;
|
|
|
|
- if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
|
|
+ if (device->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
|
|
val |= VID_MODE_TYPE_BURST;
|
|
- else if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
|
|
+ else if (device->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
|
|
val |= VID_MODE_TYPE_NON_BURST_SYNC_PULSES;
|
|
else
|
|
val |= VID_MODE_TYPE_NON_BURST_SYNC_EVENTS;
|
|
@@ -466,6 +460,8 @@ static void dw_mipi_dsi_video_mode_config(struct dw_mipi_dsi *dsi)
|
|
static void dw_mipi_dsi_set_mode(struct dw_mipi_dsi *dsi,
|
|
unsigned long mode_flags)
|
|
{
|
|
+ const struct mipi_dsi_phy_ops *phy_ops = dsi->phy_ops;
|
|
+
|
|
dsi_write(dsi, DSI_PWR_UP, RESET);
|
|
|
|
if (mode_flags & MIPI_DSI_MODE_VIDEO) {
|
|
@@ -476,10 +472,13 @@ static void dw_mipi_dsi_set_mode(struct dw_mipi_dsi *dsi,
|
|
dsi_write(dsi, DSI_MODE_CFG, ENABLE_CMD_MODE);
|
|
}
|
|
|
|
+ if (phy_ops->post_set_mode)
|
|
+ phy_ops->post_set_mode(dsi->device, mode_flags);
|
|
+
|
|
dsi_write(dsi, DSI_PWR_UP, POWERUP);
|
|
}
|
|
|
|
-static void dw_mipi_dsi_init(struct dw_mipi_dsi *dsi)
|
|
+static void dw_mipi_dsi_init_pll(struct dw_mipi_dsi *dsi)
|
|
{
|
|
/*
|
|
* The maximum permitted escape clock is 20MHz and it is derived from
|
|
@@ -505,9 +504,10 @@ static void dw_mipi_dsi_init(struct dw_mipi_dsi *dsi)
|
|
static void dw_mipi_dsi_dpi_config(struct dw_mipi_dsi *dsi,
|
|
struct display_timing *timings)
|
|
{
|
|
+ struct mipi_dsi_device *device = dsi->device;
|
|
u32 val = 0, color = 0;
|
|
|
|
- switch (dsi->format) {
|
|
+ switch (device->format) {
|
|
case MIPI_DSI_FMT_RGB888:
|
|
color = DPI_COLOR_CODING_24BIT;
|
|
break;
|
|
@@ -522,9 +522,9 @@ static void dw_mipi_dsi_dpi_config(struct dw_mipi_dsi *dsi,
|
|
break;
|
|
}
|
|
|
|
- if (dsi->mode_flags & DISPLAY_FLAGS_VSYNC_HIGH)
|
|
+ if (device->mode_flags & DISPLAY_FLAGS_VSYNC_HIGH)
|
|
val |= VSYNC_ACTIVE_LOW;
|
|
- if (dsi->mode_flags & DISPLAY_FLAGS_HSYNC_HIGH)
|
|
+ if (device->mode_flags & DISPLAY_FLAGS_HSYNC_HIGH)
|
|
val |= HSYNC_ACTIVE_LOW;
|
|
|
|
dsi_write(dsi, DSI_DPI_VCID, DPI_VCID(dsi->channel));
|
|
@@ -560,6 +560,8 @@ static void dw_mipi_dsi_video_packet_config(struct dw_mipi_dsi *dsi,
|
|
|
|
static void dw_mipi_dsi_command_mode_config(struct dw_mipi_dsi *dsi)
|
|
{
|
|
+ const struct mipi_dsi_phy_ops *phy_ops = dsi->phy_ops;
|
|
+
|
|
/*
|
|
* TODO dw drv improvements
|
|
* compute high speed transmission counter timeout according
|
|
@@ -573,6 +575,9 @@ static void dw_mipi_dsi_command_mode_config(struct dw_mipi_dsi *dsi)
|
|
*/
|
|
dsi_write(dsi, DSI_BTA_TO_CNT, 0xd00);
|
|
dsi_write(dsi, DSI_MODE_CFG, ENABLE_CMD_MODE);
|
|
+
|
|
+ if (phy_ops->post_set_mode)
|
|
+ phy_ops->post_set_mode(dsi->device, 0);
|
|
}
|
|
|
|
/* Get lane byte clock cycles. */
|
|
@@ -662,13 +667,15 @@ static void dw_mipi_dsi_dphy_timing_config(struct dw_mipi_dsi *dsi)
|
|
|
|
static void dw_mipi_dsi_dphy_interface_config(struct dw_mipi_dsi *dsi)
|
|
{
|
|
+ struct mipi_dsi_device *device = dsi->device;
|
|
+
|
|
/*
|
|
* TODO dw drv improvements
|
|
* stop wait time should be the maximum between host dsi
|
|
* and panel stop wait times
|
|
*/
|
|
dsi_write(dsi, DSI_PHY_IF_CFG, PHY_STOP_WAIT_TIME(0x20) |
|
|
- N_LANES(dsi->lanes));
|
|
+ N_LANES(device->lanes));
|
|
}
|
|
|
|
static void dw_mipi_dsi_dphy_init(struct dw_mipi_dsi *dsi)
|
|
@@ -712,15 +719,16 @@ static void dw_mipi_dsi_clear_err(struct dw_mipi_dsi *dsi)
|
|
static void dw_mipi_dsi_bridge_set(struct dw_mipi_dsi *dsi,
|
|
struct display_timing *timings)
|
|
{
|
|
- const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->phy_ops;
|
|
+ const struct mipi_dsi_phy_ops *phy_ops = dsi->phy_ops;
|
|
+ struct mipi_dsi_device *device = dsi->device;
|
|
int ret;
|
|
|
|
- ret = phy_ops->get_lane_mbps(dsi->device, timings, dsi->lanes,
|
|
- dsi->format, &dsi->lane_mbps);
|
|
+ ret = phy_ops->get_lane_mbps(dsi->device, timings, device->lanes,
|
|
+ device->format, &dsi->lane_mbps);
|
|
if (ret)
|
|
dev_warn(dsi->dev, "Phy get_lane_mbps() failed\n");
|
|
|
|
- dw_mipi_dsi_init(dsi);
|
|
+ dw_mipi_dsi_init_pll(dsi);
|
|
dw_mipi_dsi_dpi_config(dsi, timings);
|
|
dw_mipi_dsi_packet_handler_config(dsi);
|
|
dw_mipi_dsi_video_mode_config(dsi);
|
|
@@ -747,62 +755,33 @@ static void dw_mipi_dsi_bridge_set(struct dw_mipi_dsi *dsi,
|
|
dw_mipi_dsi_set_mode(dsi, 0);
|
|
}
|
|
|
|
-void dw_mipi_dsi_bridge_enable(struct mipi_dsi_device *device)
|
|
+static int dw_mipi_dsi_init(struct udevice *dev,
|
|
+ struct mipi_dsi_device *device,
|
|
+ struct display_timing *timings,
|
|
+ unsigned int max_data_lanes,
|
|
+ const struct mipi_dsi_phy_ops *phy_ops)
|
|
{
|
|
- struct mipi_dsi_host *host = device->host;
|
|
- struct dw_mipi_dsi *dsi = host_to_dsi(host);
|
|
-
|
|
- /* Switch to video mode for panel-bridge enable & panel enable */
|
|
- dw_mipi_dsi_set_mode(dsi, MIPI_DSI_MODE_VIDEO);
|
|
-}
|
|
-EXPORT_SYMBOL_GPL(dw_mipi_dsi_bridge_enable);
|
|
-
|
|
-int dw_mipi_dsi_init_bridge(struct mipi_dsi_device *device)
|
|
-{
|
|
- struct dw_mipi_dsi_plat_data *platdata = dev_get_platdata(device->dev);
|
|
- struct udevice *panel = platdata->panel;
|
|
- struct display_timing timings;
|
|
- struct dw_mipi_dsi *dsi;
|
|
+ struct dw_mipi_dsi *dsi = dev_get_priv(dev);
|
|
struct clk clk;
|
|
int ret;
|
|
|
|
- dsi = kzalloc(sizeof(*dsi), GFP_KERNEL);
|
|
+ if (!phy_ops->init || !phy_ops->get_lane_mbps) {
|
|
+ dev_err(device->dev, "Phy not properly configured\n");
|
|
+ return -ENODEV;
|
|
+ }
|
|
|
|
- dsi->phy_ops = platdata->phy_ops;
|
|
- dsi->max_data_lanes = platdata->max_data_lanes;
|
|
+ dsi->phy_ops = phy_ops;
|
|
+ dsi->max_data_lanes = max_data_lanes;
|
|
dsi->device = device;
|
|
dsi->dsi_host.ops = &dw_mipi_dsi_host_ops;
|
|
device->host = &dsi->dsi_host;
|
|
|
|
- /* TODO Get these settings from panel */
|
|
- dsi->lanes = 2;
|
|
- dsi->format = MIPI_DSI_FMT_RGB888;
|
|
- dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
|
|
- MIPI_DSI_MODE_VIDEO_BURST |
|
|
- MIPI_DSI_MODE_LPM;
|
|
-
|
|
dsi->base = (void *)dev_read_addr(device->dev);
|
|
if ((fdt_addr_t)dsi->base == FDT_ADDR_T_NONE) {
|
|
dev_err(device->dev, "dsi dt register address error\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
- ret = panel_get_display_timing(panel, &timings);
|
|
- if (ret) {
|
|
- ret = fdtdec_decode_display_timing(gd->fdt_blob,
|
|
- dev_of_offset(panel),
|
|
- 0, &timings);
|
|
- if (ret) {
|
|
- dev_err(dev, "decode display timing error %d\n", ret);
|
|
- return ret;
|
|
- }
|
|
- }
|
|
-
|
|
- if (!dsi->phy_ops->init || !dsi->phy_ops->get_lane_mbps) {
|
|
- dev_err(device->dev, "Phy not properly configured\n");
|
|
- return -ENODEV;
|
|
- }
|
|
-
|
|
ret = clk_get_by_name(device->dev, "px_clk", &clk);
|
|
if (ret) {
|
|
dev_err(device->dev, "peripheral clock get error %d\n", ret);
|
|
@@ -810,13 +789,40 @@ int dw_mipi_dsi_init_bridge(struct mipi_dsi_device *device)
|
|
}
|
|
|
|
/* get the pixel clock set by the clock framework */
|
|
- timings.pixelclock.typ = clk_get_rate(&clk);
|
|
+ timings->pixelclock.typ = clk_get_rate(&clk);
|
|
|
|
- dw_mipi_dsi_bridge_set(dsi, &timings);
|
|
+ dw_mipi_dsi_bridge_set(dsi, timings);
|
|
|
|
return 0;
|
|
}
|
|
-EXPORT_SYMBOL_GPL(dw_mipi_dsi_init_bridge);
|
|
+
|
|
+static int dw_mipi_dsi_enable(struct udevice *dev)
|
|
+{
|
|
+ struct dw_mipi_dsi *dsi = dev_get_priv(dev);
|
|
+
|
|
+ /* Switch to video mode for panel-bridge enable & panel enable */
|
|
+ dw_mipi_dsi_set_mode(dsi, MIPI_DSI_MODE_VIDEO);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+struct dsi_host_ops dw_mipi_dsi_ops = {
|
|
+ .init = dw_mipi_dsi_init,
|
|
+ .enable = dw_mipi_dsi_enable,
|
|
+};
|
|
+
|
|
+static int dw_mipi_dsi_probe(struct udevice *dev)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+U_BOOT_DRIVER(dw_mipi_dsi) = {
|
|
+ .name = "dw_mipi_dsi",
|
|
+ .id = UCLASS_DSI_HOST,
|
|
+ .probe = dw_mipi_dsi_probe,
|
|
+ .ops = &dw_mipi_dsi_ops,
|
|
+ .priv_auto_alloc_size = sizeof(struct dw_mipi_dsi),
|
|
+};
|
|
|
|
MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>");
|
|
MODULE_AUTHOR("Philippe Cornu <philippe.cornu@st.com>");
|
|
diff --git a/drivers/video/mipi_display.c b/drivers/video/mipi_display.c
|
|
deleted file mode 100644
|
|
index 611ee53..0000000
|
|
--- a/drivers/video/mipi_display.c
|
|
+++ /dev/null
|
|
@@ -1,817 +0,0 @@
|
|
-/*
|
|
- * MIPI DSI Bus
|
|
- *
|
|
- * Copyright (C) 2012-2013, Samsung Electronics, Co., Ltd.
|
|
- * Copyright (C) 2018 STMicroelectronics - All Rights Reserved
|
|
- * 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.
|
|
- *
|
|
- * Mipi_display.c contains a set of dsi helpers.
|
|
- * This file is based on the drm helper file drivers/gpu/drm/drm_mipi_dsi.c
|
|
- * (kernel linux).
|
|
- *
|
|
- */
|
|
-
|
|
-#include <common.h>
|
|
-#include <clk.h>
|
|
-#include <display.h>
|
|
-#include <dm.h>
|
|
-#include <mipi_display.h>
|
|
-
|
|
-/**
|
|
- * 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.
|
|
- */
|
|
-
|
|
-/**
|
|
- * 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);
|
|
-
|
|
-/**
|
|
- * mipi_dsi_device_transfer - transfer message to a DSI device
|
|
- * @dsi: DSI peripheral
|
|
- * @msg: message
|
|
- */
|
|
-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,
|
|
- };
|
|
- int ret = mipi_dsi_device_transfer(dsi, &msg);
|
|
-
|
|
- return (ret < 0) ? ret : 0;
|
|
-}
|
|
-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_pixel_format_to_bpp - obtain the number of bits per pixel for any
|
|
- * given pixel format defined by the MIPI DSI
|
|
- * specification
|
|
- * @fmt: MIPI DSI pixel format
|
|
- *
|
|
- * Returns: The number of bits per pixel of the given pixel format.
|
|
- */
|
|
-int mipi_dsi_pixel_format_to_bpp(enum mipi_dsi_pixel_format fmt)
|
|
-{
|
|
- switch (fmt) {
|
|
- case MIPI_DSI_FMT_RGB888:
|
|
- case MIPI_DSI_FMT_RGB666:
|
|
- return 24;
|
|
-
|
|
- case MIPI_DSI_FMT_RGB666_PACKED:
|
|
- return 18;
|
|
-
|
|
- case MIPI_DSI_FMT_RGB565:
|
|
- return 16;
|
|
- }
|
|
-
|
|
- return -EINVAL;
|
|
-}
|
|
-EXPORT_SYMBOL(mipi_dsi_pixel_format_to_bpp);
|
|
-
|
|
-/**
|
|
- * 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);
|
|
-
|
|
-/**
|
|
- * mipi_dsi_dcs_set_tear_scanline() - set the scanline to use as trigger for
|
|
- * the Tearing Effect output signal of the display module
|
|
- * @dsi: DSI peripheral device
|
|
- * @scanline: scanline to use as trigger
|
|
- *
|
|
- * Return: 0 on success or a negative error code on failure
|
|
- */
|
|
-int mipi_dsi_dcs_set_tear_scanline(struct mipi_dsi_device *dsi, u16 scanline)
|
|
-{
|
|
- u8 payload[3] = { MIPI_DCS_SET_TEAR_SCANLINE, scanline >> 8,
|
|
- scanline & 0xff };
|
|
- ssize_t err;
|
|
-
|
|
- err = mipi_dsi_generic_write(dsi, payload, sizeof(payload));
|
|
- if (err < 0)
|
|
- return err;
|
|
-
|
|
- return 0;
|
|
-}
|
|
-EXPORT_SYMBOL(mipi_dsi_dcs_set_tear_scanline);
|
|
-
|
|
-/**
|
|
- * mipi_dsi_dcs_set_display_brightness() - sets the brightness value of the
|
|
- * display
|
|
- * @dsi: DSI peripheral device
|
|
- * @brightness: brightness value
|
|
- *
|
|
- * Return: 0 on success or a negative error code on failure.
|
|
- */
|
|
-int mipi_dsi_dcs_set_display_brightness(struct mipi_dsi_device *dsi,
|
|
- u16 brightness)
|
|
-{
|
|
- u8 payload[2] = { brightness & 0xff, brightness >> 8 };
|
|
- ssize_t err;
|
|
-
|
|
- err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS,
|
|
- payload, sizeof(payload));
|
|
- if (err < 0)
|
|
- return err;
|
|
-
|
|
- return 0;
|
|
-}
|
|
-EXPORT_SYMBOL(mipi_dsi_dcs_set_display_brightness);
|
|
-
|
|
-/**
|
|
- * mipi_dsi_dcs_get_display_brightness() - gets the current brightness value
|
|
- * of the display
|
|
- * @dsi: DSI peripheral device
|
|
- * @brightness: brightness value
|
|
- *
|
|
- * Return: 0 on success or a negative error code on failure.
|
|
- */
|
|
-int mipi_dsi_dcs_get_display_brightness(struct mipi_dsi_device *dsi,
|
|
- u16 *brightness)
|
|
-{
|
|
- ssize_t err;
|
|
-
|
|
- err = mipi_dsi_dcs_read(dsi, MIPI_DCS_GET_DISPLAY_BRIGHTNESS,
|
|
- brightness, sizeof(*brightness));
|
|
- if (err <= 0) {
|
|
- if (err == 0)
|
|
- err = -ENODATA;
|
|
-
|
|
- return err;
|
|
- }
|
|
-
|
|
- return 0;
|
|
-}
|
|
-EXPORT_SYMBOL(mipi_dsi_dcs_get_display_brightness);
|
|
-
|
|
-MODULE_AUTHOR("Andrzej Hajda <a.hajda@samsung.com>");
|
|
-MODULE_AUTHOR("Yannick Fertre <yannick.fertre@st.com>");
|
|
-MODULE_DESCRIPTION("MIPI DSI Bus");
|
|
-MODULE_LICENSE("GPL and additional rights");
|
|
diff --git a/drivers/video/mipi_dsi.c b/drivers/video/mipi_dsi.c
|
|
new file mode 100644
|
|
index 0000000..cdc3ef5
|
|
--- /dev/null
|
|
+++ b/drivers/video/mipi_dsi.c
|
|
@@ -0,0 +1,828 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/*
|
|
+ * MIPI DSI Bus
|
|
+ *
|
|
+ * Copyright (C) 2012-2013, Samsung Electronics, Co., Ltd.
|
|
+ * Copyright (C) 2019 STMicroelectronics - All Rights Reserved
|
|
+ * 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.
|
|
+ *
|
|
+ * Mipi_dsi.c contains a set of dsi helpers.
|
|
+ * This file is inspired from the drm helper file drivers/gpu/drm/drm_mipi_dsi.c
|
|
+ * (kernel linux).
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include <common.h>
|
|
+#include <clk.h>
|
|
+#include <display.h>
|
|
+#include <dm.h>
|
|
+#include <mipi_display.h>
|
|
+#include <mipi_dsi.h>
|
|
+
|
|
+/**
|
|
+ * 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.
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * 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);
|
|
+
|
|
+/**
|
|
+ * mipi_dsi_device_transfer - transfer message to a DSI device
|
|
+ * @dsi: DSI peripheral
|
|
+ * @msg: message
|
|
+ */
|
|
+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_shutdown_peripheral() - sends a Shutdown Peripheral command
|
|
+ * @dsi: DSI peripheral device
|
|
+ *
|
|
+ * Return: 0 on success or a negative error code on failure.
|
|
+ */
|
|
+int mipi_dsi_shutdown_peripheral(struct mipi_dsi_device *dsi)
|
|
+{
|
|
+ struct mipi_dsi_msg msg = {
|
|
+ .channel = dsi->channel,
|
|
+ .type = MIPI_DSI_SHUTDOWN_PERIPHERAL,
|
|
+ .tx_buf = (u8 [2]) { 0, 0 },
|
|
+ .tx_len = 2,
|
|
+ };
|
|
+ int ret = mipi_dsi_device_transfer(dsi, &msg);
|
|
+
|
|
+ return (ret < 0) ? ret : 0;
|
|
+}
|
|
+EXPORT_SYMBOL(mipi_dsi_shutdown_peripheral);
|
|
+
|
|
+/**
|
|
+ * mipi_dsi_turn_on_peripheral() - sends a Turn On Peripheral command
|
|
+ * @dsi: DSI peripheral device
|
|
+ *
|
|
+ * Return: 0 on success or a negative error code on failure.
|
|
+ */
|
|
+int mipi_dsi_turn_on_peripheral(struct mipi_dsi_device *dsi)
|
|
+{
|
|
+ struct mipi_dsi_msg msg = {
|
|
+ .channel = dsi->channel,
|
|
+ .type = MIPI_DSI_TURN_ON_PERIPHERAL,
|
|
+ .tx_buf = (u8 [2]) { 0, 0 },
|
|
+ .tx_len = 2,
|
|
+ };
|
|
+ int ret = mipi_dsi_device_transfer(dsi, &msg);
|
|
+
|
|
+ return (ret < 0) ? ret : 0;
|
|
+}
|
|
+EXPORT_SYMBOL(mipi_dsi_turn_on_peripheral);
|
|
+
|
|
+/*
|
|
+ * 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,
|
|
+ };
|
|
+ int ret = mipi_dsi_device_transfer(dsi, &msg);
|
|
+
|
|
+ return (ret < 0) ? ret : 0;
|
|
+}
|
|
+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);
|
|
+
|
|
+/**
|
|
+ * mipi_dsi_dcs_set_tear_scanline() - set the scanline to use as trigger for
|
|
+ * the Tearing Effect output signal of the display module
|
|
+ * @dsi: DSI peripheral device
|
|
+ * @scanline: scanline to use as trigger
|
|
+ *
|
|
+ * Return: 0 on success or a negative error code on failure
|
|
+ */
|
|
+int mipi_dsi_dcs_set_tear_scanline(struct mipi_dsi_device *dsi, u16 scanline)
|
|
+{
|
|
+ u8 payload[3] = { MIPI_DCS_SET_TEAR_SCANLINE, scanline >> 8,
|
|
+ scanline & 0xff };
|
|
+ ssize_t err;
|
|
+
|
|
+ err = mipi_dsi_generic_write(dsi, payload, sizeof(payload));
|
|
+ if (err < 0)
|
|
+ return err;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+EXPORT_SYMBOL(mipi_dsi_dcs_set_tear_scanline);
|
|
+
|
|
+/**
|
|
+ * mipi_dsi_dcs_set_display_brightness() - sets the brightness value of the
|
|
+ * display
|
|
+ * @dsi: DSI peripheral device
|
|
+ * @brightness: brightness value
|
|
+ *
|
|
+ * Return: 0 on success or a negative error code on failure.
|
|
+ */
|
|
+int mipi_dsi_dcs_set_display_brightness(struct mipi_dsi_device *dsi,
|
|
+ u16 brightness)
|
|
+{
|
|
+ u8 payload[2] = { brightness & 0xff, brightness >> 8 };
|
|
+ ssize_t err;
|
|
+
|
|
+ err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS,
|
|
+ payload, sizeof(payload));
|
|
+ if (err < 0)
|
|
+ return err;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+EXPORT_SYMBOL(mipi_dsi_dcs_set_display_brightness);
|
|
+
|
|
+/**
|
|
+ * mipi_dsi_dcs_get_display_brightness() - gets the current brightness value
|
|
+ * of the display
|
|
+ * @dsi: DSI peripheral device
|
|
+ * @brightness: brightness value
|
|
+ *
|
|
+ * Return: 0 on success or a negative error code on failure.
|
|
+ */
|
|
+int mipi_dsi_dcs_get_display_brightness(struct mipi_dsi_device *dsi,
|
|
+ u16 *brightness)
|
|
+{
|
|
+ ssize_t err;
|
|
+
|
|
+ err = mipi_dsi_dcs_read(dsi, MIPI_DCS_GET_DISPLAY_BRIGHTNESS,
|
|
+ brightness, sizeof(*brightness));
|
|
+ if (err <= 0) {
|
|
+ if (err == 0)
|
|
+ err = -ENODATA;
|
|
+
|
|
+ return err;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+EXPORT_SYMBOL(mipi_dsi_dcs_get_display_brightness);
|
|
diff --git a/drivers/video/orisetech_otm8009a.c b/drivers/video/orisetech_otm8009a.c
|
|
index 41c4bef..629bf76 100644
|
|
--- a/drivers/video/orisetech_otm8009a.c
|
|
+++ b/drivers/video/orisetech_otm8009a.c
|
|
@@ -1,16 +1,16 @@
|
|
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
- * Copyright (C) 2018 STMicroelectronics - All Rights Reserved
|
|
+ * Copyright (C) 2019 STMicroelectronics - All Rights Reserved
|
|
* Author(s): Yannick Fertre <yannick.fertre@st.com> for STMicroelectronics.
|
|
* Philippe Cornu <philippe.cornu@st.com> for STMicroelectronics.
|
|
*
|
|
- * This otm8009a panel driver is based on the Linux Kernel driver from
|
|
+ * This otm8009a panel driver is inspired from the Linux Kernel driver
|
|
* drivers/gpu/drm/panel/panel-orisetech-otm8009a.c.
|
|
*/
|
|
#include <common.h>
|
|
#include <backlight.h>
|
|
#include <dm.h>
|
|
-#include <mipi_display.h>
|
|
+#include <mipi_dsi.h>
|
|
#include <panel.h>
|
|
#include <asm/gpio.h>
|
|
#include <power/regulator.h>
|
|
@@ -63,15 +63,15 @@ struct otm8009a_panel_priv {
|
|
};
|
|
|
|
static const struct display_timing default_timing = {
|
|
- .pixelclock = {.min = 32729000, .typ = 32729000, .max = 32729000,},
|
|
- .hactive = {.min = 480, .typ = 480, .max = 480,},
|
|
- .hfront_porch = {.min = 120, .typ = 120, .max = 120,},
|
|
- .hback_porch = {.min = 120, .typ = 120, .max = 120,},
|
|
- .hsync_len = {.min = 63, .typ = 63, .max = 63,},
|
|
- .vactive = {.min = 800, .typ = 800, .max = 800,},
|
|
- .vfront_porch = {.min = 12, .typ = 12, .max = 12,},
|
|
- .vback_porch = {.min = 12, .typ = 12, .max = 12,},
|
|
- .vsync_len = {.min = 12, .typ = 12, .max = 12,},
|
|
+ .pixelclock.typ = 29700000,
|
|
+ .hactive.typ = 480,
|
|
+ .hfront_porch.typ = 98,
|
|
+ .hback_porch.typ = 98,
|
|
+ .hsync_len.typ = 32,
|
|
+ .vactive.typ = 800,
|
|
+ .vfront_porch.typ = 15,
|
|
+ .vback_porch.typ = 14,
|
|
+ .vsync_len.typ = 10,
|
|
};
|
|
|
|
static void otm8009a_dcs_write_buf(struct udevice *dev, const void *data,
|
|
@@ -84,12 +84,34 @@ static void otm8009a_dcs_write_buf(struct udevice *dev, const void *data,
|
|
dev_err(dev, "mipi dsi dcs write buffer failed\n");
|
|
}
|
|
|
|
+static void otm8009a_dcs_write_buf_hs(struct udevice *dev, const void *data,
|
|
+ size_t len)
|
|
+{
|
|
+ struct mipi_dsi_panel_plat *plat = dev_get_platdata(dev);
|
|
+ struct mipi_dsi_device *device = plat->device;
|
|
+
|
|
+ /* data will be sent in dsi hs mode (ie. no lpm) */
|
|
+ device->mode_flags &= ~MIPI_DSI_MODE_LPM;
|
|
+
|
|
+ if (mipi_dsi_dcs_write_buffer(device, data, len) < 0)
|
|
+ dev_err(dev, "mipi dsi dcs write buffer failed\n");
|
|
+
|
|
+ /* restore back the dsi lpm mode */
|
|
+ device->mode_flags |= MIPI_DSI_MODE_LPM;
|
|
+}
|
|
+
|
|
#define dcs_write_seq(dev, seq...) \
|
|
({ \
|
|
static const u8 d[] = { seq }; \
|
|
otm8009a_dcs_write_buf(dev, d, ARRAY_SIZE(d)); \
|
|
})
|
|
|
|
+#define dcs_write_seq_hs(dev, seq...) \
|
|
+({ \
|
|
+ static const u8 d[] = { seq }; \
|
|
+ otm8009a_dcs_write_buf_hs(dev, d, ARRAY_SIZE(d)); \
|
|
+})
|
|
+
|
|
#define dcs_write_cmd_at(dev, cmd, seq...) \
|
|
({ \
|
|
static const u16 c = cmd; \
|
|
@@ -196,11 +218,13 @@ static int otm8009a_init_sequence(struct udevice *dev)
|
|
/* Default portrait 480x800 rgb24 */
|
|
dcs_write_seq(dev, MIPI_DCS_SET_ADDRESS_MODE, 0x00);
|
|
|
|
- ret = mipi_dsi_dcs_set_column_address(device, 0, 479);
|
|
+ ret = mipi_dsi_dcs_set_column_address(device, 0,
|
|
+ default_timing.hactive.typ - 1);
|
|
if (ret)
|
|
return ret;
|
|
|
|
- ret = mipi_dsi_dcs_set_page_address(device, 0, 799);
|
|
+ ret = mipi_dsi_dcs_set_page_address(device, 0,
|
|
+ default_timing.vactive.typ - 1);
|
|
if (ret)
|
|
return ret;
|
|
|
|
@@ -213,6 +237,17 @@ static int otm8009a_init_sequence(struct udevice *dev)
|
|
/* Disable CABC feature */
|
|
dcs_write_seq(dev, MIPI_DCS_WRITE_POWER_SAVE, 0x00);
|
|
|
|
+ ret = mipi_dsi_dcs_set_display_on(device);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = mipi_dsi_dcs_nop(device);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ /* Send Command GRAM memory write (no parameters) */
|
|
+ dcs_write_seq(dev, MIPI_DCS_WRITE_MEMORY_START);
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -222,12 +257,6 @@ static int otm8009a_panel_enable_backlight(struct udevice *dev)
|
|
struct mipi_dsi_device *device = plat->device;
|
|
int ret;
|
|
|
|
- device->lanes = 2;
|
|
- device->format = MIPI_DSI_FMT_RGB888;
|
|
- device->mode_flags = MIPI_DSI_MODE_VIDEO |
|
|
- MIPI_DSI_MODE_VIDEO_BURST |
|
|
- MIPI_DSI_MODE_LPM;
|
|
-
|
|
ret = mipi_dsi_attach(device);
|
|
if (ret < 0)
|
|
return ret;
|
|
@@ -247,18 +276,10 @@ static int otm8009a_panel_enable_backlight(struct udevice *dev)
|
|
/* Update Brightness Control & Backlight */
|
|
dcs_write_seq(dev, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24);
|
|
|
|
- ret = mipi_dsi_dcs_set_display_on(device);
|
|
- if (ret)
|
|
- return ret;
|
|
-
|
|
- ret = mipi_dsi_dcs_nop(device);
|
|
- if (ret)
|
|
- return ret;
|
|
-
|
|
- /* Send Command GRAM memory write (no parameters) */
|
|
- dcs_write_seq(dev, MIPI_DCS_WRITE_MEMORY_START);
|
|
+ /* Update Brightness Control & Backlight */
|
|
+ dcs_write_seq_hs(dev, MIPI_DCS_WRITE_CONTROL_DISPLAY);
|
|
|
|
- /* need to wait a few time before set the DSI bridge in video mode */
|
|
+ /* Need to wait a few time before sending the first image */
|
|
mdelay(10);
|
|
|
|
return 0;
|
|
@@ -268,6 +289,7 @@ static int otm8009a_panel_get_display_timing(struct udevice *dev,
|
|
struct display_timing *timings)
|
|
{
|
|
memcpy(timings, &default_timing, sizeof(*timings));
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -299,23 +321,28 @@ static int otm8009a_panel_ofdata_to_platdata(struct udevice *dev)
|
|
static int otm8009a_panel_probe(struct udevice *dev)
|
|
{
|
|
struct otm8009a_panel_priv *priv = dev_get_priv(dev);
|
|
+ struct mipi_dsi_panel_plat *plat = dev_get_platdata(dev);
|
|
int ret;
|
|
|
|
if (IS_ENABLED(CONFIG_DM_REGULATOR) && priv->reg) {
|
|
dev_dbg(dev, "enable regulator '%s'\n", priv->reg->name);
|
|
ret = regulator_set_enable(priv->reg, true);
|
|
- if (ret) {
|
|
- dev_err(dev, "Regulator : '%s' - can't enable\n",
|
|
- priv->reg->name);
|
|
+ if (ret)
|
|
return ret;
|
|
- }
|
|
}
|
|
|
|
/* reset panel */
|
|
dm_gpio_set_value(&priv->reset, true);
|
|
- mdelay(1);
|
|
+ mdelay(1); /* >50us */
|
|
dm_gpio_set_value(&priv->reset, false);
|
|
- mdelay(10);
|
|
+ mdelay(10); /* >5ms */
|
|
+
|
|
+ /* fill characteristics of DSI data link */
|
|
+ plat->lanes = 2;
|
|
+ plat->format = MIPI_DSI_FMT_RGB888;
|
|
+ plat->mode_flags = MIPI_DSI_MODE_VIDEO |
|
|
+ MIPI_DSI_MODE_VIDEO_BURST |
|
|
+ MIPI_DSI_MODE_LPM;
|
|
|
|
return 0;
|
|
}
|
|
diff --git a/drivers/video/raydium-rm68200.c b/drivers/video/raydium-rm68200.c
|
|
index 3347f12..76b0ed2 100644
|
|
--- a/drivers/video/raydium-rm68200.c
|
|
+++ b/drivers/video/raydium-rm68200.c
|
|
@@ -1,16 +1,16 @@
|
|
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
- * Copyright (C) 2018 STMicroelectronics - All Rights Reserved
|
|
+ * Copyright (C) 2019 STMicroelectronics - All Rights Reserved
|
|
* Author(s): Yannick Fertre <yannick.fertre@st.com> for STMicroelectronics.
|
|
* Philippe Cornu <philippe.cornu@st.com> for STMicroelectronics.
|
|
*
|
|
- * This rm68200 panel driver is based on the Linux Kernel driver from
|
|
+ * This rm68200 panel driver is inspired from the Linux Kernel driver
|
|
* drivers/gpu/drm/panel/panel-raydium-rm68200.c.
|
|
*/
|
|
#include <common.h>
|
|
#include <backlight.h>
|
|
#include <dm.h>
|
|
-#include <mipi_display.h>
|
|
+#include <mipi_dsi.h>
|
|
#include <panel.h>
|
|
#include <asm/gpio.h>
|
|
#include <power/regulator.h>
|
|
@@ -76,15 +76,15 @@ struct rm68200_panel_priv {
|
|
};
|
|
|
|
static const struct display_timing default_timing = {
|
|
- .pixelclock = {.min = 52582000, .typ = 52582000, .max = 52582000,},
|
|
- .hactive = {.min = 720, .typ = 720, .max = 720,},
|
|
- .hfront_porch = {.min = 38, .typ = 38, .max = 38,},
|
|
- .hback_porch = {.min = 8, .typ = 8, .max = 8,},
|
|
- .hsync_len = {.min = 38, .typ = 38, .max = 38,},
|
|
- .vactive = {.min = 1280, .typ = 1280, .max = 1280,},
|
|
- .vfront_porch = {.min = 12, .typ = 12, .max = 12,},
|
|
- .vback_porch = {.min = 4, .typ = 4, .max = 4,},
|
|
- .vsync_len = {.min = 12, .typ = 12, .max = 12,},
|
|
+ .pixelclock.typ = 54000000,
|
|
+ .hactive.typ = 720,
|
|
+ .hfront_porch.typ = 48,
|
|
+ .hback_porch.typ = 48,
|
|
+ .hsync_len.typ = 9,
|
|
+ .vactive.typ = 1280,
|
|
+ .vfront_porch.typ = 12,
|
|
+ .vback_porch.typ = 12,
|
|
+ .vsync_len.typ = 5,
|
|
};
|
|
|
|
static void rm68200_dcs_write_buf(struct udevice *dev, const void *data,
|
|
@@ -226,12 +226,6 @@ static int rm68200_panel_enable_backlight(struct udevice *dev)
|
|
struct rm68200_panel_priv *priv = dev_get_priv(dev);
|
|
int ret;
|
|
|
|
- device->lanes = 2;
|
|
- device->format = MIPI_DSI_FMT_RGB888;
|
|
- device->mode_flags = MIPI_DSI_MODE_VIDEO |
|
|
- MIPI_DSI_MODE_VIDEO_BURST |
|
|
- MIPI_DSI_MODE_LPM;
|
|
-
|
|
ret = mipi_dsi_attach(device);
|
|
if (ret < 0)
|
|
return ret;
|
|
@@ -261,6 +255,7 @@ static int rm68200_panel_get_display_timing(struct udevice *dev,
|
|
struct display_timing *timings)
|
|
{
|
|
memcpy(timings, &default_timing, sizeof(*timings));
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -299,6 +294,7 @@ static int rm68200_panel_ofdata_to_platdata(struct udevice *dev)
|
|
static int rm68200_panel_probe(struct udevice *dev)
|
|
{
|
|
struct rm68200_panel_priv *priv = dev_get_priv(dev);
|
|
+ struct mipi_dsi_panel_plat *plat = dev_get_platdata(dev);
|
|
int ret;
|
|
|
|
if (IS_ENABLED(CONFIG_DM_REGULATOR) && priv->reg) {
|
|
@@ -313,6 +309,13 @@ static int rm68200_panel_probe(struct udevice *dev)
|
|
dm_gpio_set_value(&priv->reset, false);
|
|
mdelay(10);
|
|
|
|
+ /* fill characteristics of DSI data link */
|
|
+ plat->lanes = 2;
|
|
+ plat->format = MIPI_DSI_FMT_RGB888;
|
|
+ plat->mode_flags = MIPI_DSI_MODE_VIDEO |
|
|
+ MIPI_DSI_MODE_VIDEO_BURST |
|
|
+ MIPI_DSI_MODE_LPM;
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/drivers/video/stm32/stm32_dsi.c b/drivers/video/stm32/stm32_dsi.c
|
|
index f8f7c83..022ae96 100644
|
|
--- a/drivers/video/stm32/stm32_dsi.c
|
|
+++ b/drivers/video/stm32/stm32_dsi.c
|
|
@@ -1,17 +1,18 @@
|
|
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
- * Copyright (C) 2018 STMicroelectronics - All Rights Reserved
|
|
+ * Copyright (C) 2019 STMicroelectronics - All Rights Reserved
|
|
* Author(s): Philippe Cornu <philippe.cornu@st.com> for STMicroelectronics.
|
|
* Yannick Fertre <yannick.fertre@st.com> for STMicroelectronics.
|
|
*
|
|
* This MIPI DSI controller driver is based on the Linux Kernel driver from
|
|
* drivers/gpu/drm/stm/dw_mipi_dsi-stm.c.
|
|
*/
|
|
+
|
|
#include <common.h>
|
|
#include <clk.h>
|
|
#include <dm.h>
|
|
-#include <dw_mipi_dsi.h>
|
|
-#include <mipi_display.h>
|
|
+#include <dsi_host.h>
|
|
+#include <mipi_dsi.h>
|
|
#include <panel.h>
|
|
#include <reset.h>
|
|
#include <video.h>
|
|
@@ -19,6 +20,7 @@
|
|
#include <asm/io.h>
|
|
#include <asm/arch/gpio.h>
|
|
#include <dm/device-internal.h>
|
|
+#include <dm/lists.h>
|
|
#include <linux/iopoll.h>
|
|
#include <power/regulator.h>
|
|
|
|
@@ -87,6 +89,7 @@ struct stm32_dsi_priv {
|
|
int lane_min_kbps;
|
|
int lane_max_kbps;
|
|
struct udevice *vdd_reg;
|
|
+ struct udevice *dsi_host;
|
|
};
|
|
|
|
static inline void dsi_write(struct stm32_dsi_priv *dsi, u32 reg, u32 val)
|
|
@@ -207,12 +210,14 @@ static int dsi_phy_init(void *priv_data)
|
|
u32 val;
|
|
int ret;
|
|
|
|
+ debug("Initialize DSI physical layer\n");
|
|
+
|
|
/* Enable the regulator */
|
|
dsi_set(dsi, DSI_WRPCR, WRPCR_REGEN | WRPCR_BGREN);
|
|
ret = readl_poll_timeout(dsi->base + DSI_WISR, val, val & WISR_RRS,
|
|
TIMEOUT_US);
|
|
if (ret) {
|
|
- dev_err(dev, "!TIMEOUT! waiting REGU\n");
|
|
+ debug("!TIMEOUT! waiting REGU\n");
|
|
return ret;
|
|
}
|
|
|
|
@@ -221,16 +226,37 @@ static int dsi_phy_init(void *priv_data)
|
|
ret = readl_poll_timeout(dsi->base + DSI_WISR, val, val & WISR_PLLLS,
|
|
TIMEOUT_US);
|
|
if (ret) {
|
|
- dev_err(dev, "!TIMEOUT! waiting PLL\n");
|
|
+ debug("!TIMEOUT! waiting PLL\n");
|
|
return ret;
|
|
}
|
|
|
|
- /* Enable the DSI wrapper */
|
|
- dsi_set(dsi, DSI_WCR, WCR_DSIEN);
|
|
-
|
|
return 0;
|
|
}
|
|
|
|
+static void dsi_phy_post_set_mode(void *priv_data, unsigned long mode_flags)
|
|
+{
|
|
+ struct mipi_dsi_device *device = priv_data;
|
|
+ struct udevice *dev = device->dev;
|
|
+ struct stm32_dsi_priv *dsi = dev_get_priv(dev);
|
|
+
|
|
+ debug("Set mode %p enable %ld\n", dsi,
|
|
+ mode_flags & MIPI_DSI_MODE_VIDEO);
|
|
+
|
|
+ if (!dsi)
|
|
+ return;
|
|
+
|
|
+ /*
|
|
+ * DSI wrapper must be enabled in video mode & disabled in command mode.
|
|
+ * If wrapper is enabled in command mode, the display controller
|
|
+ * register access will hang.
|
|
+ */
|
|
+
|
|
+ if (mode_flags & MIPI_DSI_MODE_VIDEO)
|
|
+ dsi_set(dsi, DSI_WCR, WCR_DSIEN);
|
|
+ else
|
|
+ dsi_clear(dsi, DSI_WCR, WCR_DSIEN);
|
|
+}
|
|
+
|
|
static int dsi_get_lane_mbps(void *priv_data, struct display_timing *timings,
|
|
u32 lanes, u32 format, unsigned int *lane_mbps)
|
|
{
|
|
@@ -302,28 +328,51 @@ static int dsi_get_lane_mbps(void *priv_data, struct display_timing *timings,
|
|
return 0;
|
|
}
|
|
|
|
-static const struct dw_mipi_dsi_phy_ops dw_mipi_dsi_stm_phy_ops = {
|
|
+static const struct mipi_dsi_phy_ops dsi_stm_phy_ops = {
|
|
.init = dsi_phy_init,
|
|
.get_lane_mbps = dsi_get_lane_mbps,
|
|
+ .post_set_mode = dsi_phy_post_set_mode,
|
|
};
|
|
|
|
static int stm32_dsi_attach(struct udevice *dev)
|
|
{
|
|
- struct stm32_dsi_priv *dsi = dev_get_priv(dev);
|
|
- struct dw_mipi_dsi_plat_data *platdata = dev_get_platdata(dev);
|
|
- struct mipi_dsi_device *device = &dsi->device;
|
|
+ struct stm32_dsi_priv *priv = dev_get_priv(dev);
|
|
+ struct mipi_dsi_device *device = &priv->device;
|
|
+ struct mipi_dsi_panel_plat *mplat;
|
|
+ struct display_timing timings;
|
|
int ret;
|
|
|
|
- platdata->max_data_lanes = 2;
|
|
- platdata->phy_ops = &dw_mipi_dsi_stm_phy_ops;
|
|
-
|
|
- ret = uclass_first_device(UCLASS_PANEL, &platdata->panel);
|
|
+ ret = uclass_first_device(UCLASS_PANEL, &priv->panel);
|
|
if (ret) {
|
|
dev_err(dev, "panel device error %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
- ret = dw_mipi_dsi_init_bridge(device);
|
|
+ mplat = dev_get_platdata(priv->panel);
|
|
+ mplat->device = &priv->device;
|
|
+ device->lanes = mplat->lanes;
|
|
+ device->format = mplat->format;
|
|
+ device->mode_flags = mplat->mode_flags;
|
|
+
|
|
+ ret = panel_get_display_timing(priv->panel, &timings);
|
|
+ if (ret) {
|
|
+ ret = fdtdec_decode_display_timing(gd->fdt_blob,
|
|
+ dev_of_offset(priv->panel),
|
|
+ 0, &timings);
|
|
+ if (ret) {
|
|
+ dev_err(dev, "decode display timing error %d\n", ret);
|
|
+ return ret;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ ret = uclass_get_device(UCLASS_DSI_HOST, 0, &priv->dsi_host);
|
|
+ if (ret) {
|
|
+ dev_err(dev, "No video dsi host detected %d\n", ret);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ ret = dsi_host_init(priv->dsi_host, device, &timings, 2,
|
|
+ &dsi_stm_phy_ops);
|
|
if (ret) {
|
|
dev_err(dev, "failed to initialize mipi dsi host\n");
|
|
return ret;
|
|
@@ -334,103 +383,116 @@ static int stm32_dsi_attach(struct udevice *dev)
|
|
|
|
static int stm32_dsi_set_backlight(struct udevice *dev, int percent)
|
|
{
|
|
- struct dw_mipi_dsi_plat_data *dplat = dev_get_platdata(dev);
|
|
- struct stm32_dsi_priv *dsi = dev_get_priv(dev);
|
|
- struct mipi_dsi_device *device = &dsi->device;
|
|
- struct udevice *panel = dplat->panel;
|
|
- struct mipi_dsi_panel_plat *mplat;
|
|
+ struct stm32_dsi_priv *priv = dev_get_priv(dev);
|
|
int ret;
|
|
|
|
- mplat = dev_get_platdata(panel);
|
|
- mplat->device = device;
|
|
-
|
|
- ret = panel_enable_backlight(panel);
|
|
+ ret = panel_enable_backlight(priv->panel);
|
|
if (ret) {
|
|
dev_err(dev, "panel %s enable backlight error %d\n",
|
|
- panel->name, ret);
|
|
+ priv->panel->name, ret);
|
|
return ret;
|
|
}
|
|
|
|
- dw_mipi_dsi_bridge_enable(device);
|
|
+ ret = dsi_host_enable(priv->dsi_host);
|
|
+ if (ret) {
|
|
+ dev_err(dev, "failed to enable mipi dsi host\n");
|
|
+ return ret;
|
|
+ }
|
|
|
|
return 0;
|
|
}
|
|
|
|
+static int stm32_dsi_bind(struct udevice *dev)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ ret = device_bind_driver_to_node(dev, "dw_mipi_dsi", "dsihost",
|
|
+ dev_ofnode(dev), NULL);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ return dm_scan_fdt_dev(dev);
|
|
+}
|
|
+
|
|
static int stm32_dsi_probe(struct udevice *dev)
|
|
{
|
|
- struct stm32_dsi_priv *dsi = dev_get_priv(dev);
|
|
- struct mipi_dsi_device *device = &dsi->device;
|
|
+ struct stm32_dsi_priv *priv = dev_get_priv(dev);
|
|
+ struct mipi_dsi_device *device = &priv->device;
|
|
struct reset_ctl rst;
|
|
struct clk clk;
|
|
int ret;
|
|
|
|
device->dev = dev;
|
|
|
|
- dsi->base = (void *)dev_read_addr(dev);
|
|
- if ((fdt_addr_t)dsi->base == FDT_ADDR_T_NONE) {
|
|
+ priv->base = (void *)dev_read_addr(dev);
|
|
+ if ((fdt_addr_t)priv->base == FDT_ADDR_T_NONE) {
|
|
dev_err(dev, "dsi dt register address error\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (IS_ENABLED(CONFIG_DM_REGULATOR)) {
|
|
ret = device_get_supply_regulator(dev, "phy-dsi-supply",
|
|
- &dsi->vdd_reg);
|
|
+ &priv->vdd_reg);
|
|
if (ret && ret != -ENOENT) {
|
|
dev_err(dev, "Warning: cannot get phy dsi supply\n");
|
|
return -ENODEV;
|
|
}
|
|
|
|
- ret = regulator_set_enable(dsi->vdd_reg, true);
|
|
- if (ret)
|
|
- return -ENODEV;
|
|
+ if (ret != -ENOENT) {
|
|
+ ret = regulator_set_enable(priv->vdd_reg, true);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+ }
|
|
}
|
|
|
|
ret = clk_get_by_name(device->dev, "pclk", &clk);
|
|
if (ret) {
|
|
dev_err(dev, "peripheral clock get error %d\n", ret);
|
|
- regulator_set_enable(dsi->vdd_reg, false);
|
|
- return -ENODEV;
|
|
+ goto err_reg;
|
|
}
|
|
|
|
ret = clk_enable(&clk);
|
|
if (ret) {
|
|
dev_err(dev, "peripheral clock enable error %d\n", ret);
|
|
- regulator_set_enable(dsi->vdd_reg, false);
|
|
- return -ENODEV;
|
|
+ goto err_reg;
|
|
}
|
|
|
|
ret = clk_get_by_name(dev, "ref", &clk);
|
|
if (ret) {
|
|
dev_err(dev, "pll reference clock get error %d\n", ret);
|
|
- clk_disable(&clk);
|
|
- regulator_set_enable(dsi->vdd_reg, false);
|
|
- return ret;
|
|
+ goto err_clk;
|
|
}
|
|
|
|
- dsi->pllref_clk = (unsigned int)clk_get_rate(&clk);
|
|
+ priv->pllref_clk = (unsigned int)clk_get_rate(&clk);
|
|
|
|
ret = reset_get_by_index(device->dev, 0, &rst);
|
|
if (ret) {
|
|
dev_err(dev, "missing dsi hardware reset\n");
|
|
- clk_disable(&clk);
|
|
- regulator_set_enable(dsi->vdd_reg, false);
|
|
- return -ENODEV;
|
|
+ goto err_clk;
|
|
}
|
|
|
|
/* Reset */
|
|
reset_deassert(&rst);
|
|
|
|
/* check hardware version */
|
|
- dsi->hw_version = dsi_read(dsi, DSI_VERSION) & VERSION;
|
|
- if (dsi->hw_version != HWVER_130 &&
|
|
- dsi->hw_version != HWVER_131) {
|
|
+ priv->hw_version = dsi_read(priv, DSI_VERSION) & VERSION;
|
|
+ if (priv->hw_version != HWVER_130 &&
|
|
+ priv->hw_version != HWVER_131) {
|
|
dev_err(dev, "bad dsi hardware version\n");
|
|
clk_disable(&clk);
|
|
- regulator_set_enable(dsi->vdd_reg, false);
|
|
+ if (IS_ENABLED(CONFIG_DM_REGULATOR))
|
|
+ regulator_set_enable(priv->vdd_reg, false);
|
|
return -ENODEV;
|
|
}
|
|
|
|
return 0;
|
|
+err_clk:
|
|
+ clk_disable(&clk);
|
|
+err_reg:
|
|
+ if (IS_ENABLED(CONFIG_DM_REGULATOR))
|
|
+ regulator_set_enable(priv->vdd_reg, false);
|
|
+
|
|
+ return ret;
|
|
}
|
|
|
|
struct video_bridge_ops stm32_dsi_ops = {
|
|
@@ -447,9 +509,8 @@ U_BOOT_DRIVER(stm32_dsi) = {
|
|
.name = "stm32-display-dsi",
|
|
.id = UCLASS_VIDEO_BRIDGE,
|
|
.of_match = stm32_dsi_ids,
|
|
- .bind = dm_scan_fdt_dev,
|
|
+ .bind = stm32_dsi_bind,
|
|
.probe = stm32_dsi_probe,
|
|
.ops = &stm32_dsi_ops,
|
|
.priv_auto_alloc_size = sizeof(struct stm32_dsi_priv),
|
|
- .platdata_auto_alloc_size = sizeof(struct dw_mipi_dsi_plat_data),
|
|
};
|
|
diff --git a/drivers/video/stm32/stm32_ltdc.c b/drivers/video/stm32/stm32_ltdc.c
|
|
index 8c996b8..59ff692 100644
|
|
--- a/drivers/video/stm32/stm32_ltdc.c
|
|
+++ b/drivers/video/stm32/stm32_ltdc.c
|
|
@@ -4,6 +4,7 @@
|
|
* Author(s): Philippe Cornu <philippe.cornu@st.com> for STMicroelectronics.
|
|
* Yannick Fertre <yannick.fertre@st.com> for STMicroelectronics.
|
|
*/
|
|
+
|
|
#include <common.h>
|
|
#include <clk.h>
|
|
#include <display.h>
|
|
@@ -328,9 +329,7 @@ static int stm32_ltdc_probe(struct udevice *dev)
|
|
struct video_uc_platdata *uc_plat = dev_get_uclass_platdata(dev);
|
|
struct video_priv *uc_priv = dev_get_uclass_priv(dev);
|
|
struct stm32_ltdc_priv *priv = dev_get_priv(dev);
|
|
-#ifdef CONFIG_VIDEO_BRIDGE
|
|
struct udevice *bridge = NULL;
|
|
-#endif
|
|
struct udevice *panel = NULL;
|
|
struct display_timing timings;
|
|
struct clk pclk;
|
|
@@ -390,19 +389,20 @@ static int stm32_ltdc_probe(struct udevice *dev)
|
|
/* Reset */
|
|
reset_deassert(&rst);
|
|
|
|
-#ifdef CONFIG_VIDEO_BRIDGE
|
|
- ret = uclass_get_device(UCLASS_VIDEO_BRIDGE, 0, &bridge);
|
|
- if (ret)
|
|
- debug("No video bridge, or no backlight on bridge\n");
|
|
-
|
|
- if (bridge) {
|
|
- ret = video_bridge_attach(bridge);
|
|
- if (ret) {
|
|
- dev_err(dev, "fail to attach bridge\n");
|
|
- return ret;
|
|
+ if (IS_ENABLED(CONFIG_VIDEO_BRIDGE)) {
|
|
+ ret = uclass_get_device(UCLASS_VIDEO_BRIDGE, 0, &bridge);
|
|
+ if (ret)
|
|
+ debug("No video bridge, or no backlight on bridge\n");
|
|
+
|
|
+ if (bridge) {
|
|
+ ret = video_bridge_attach(bridge);
|
|
+ if (ret) {
|
|
+ dev_err(dev, "fail to attach bridge\n");
|
|
+ return ret;
|
|
+ }
|
|
}
|
|
}
|
|
-#endif
|
|
+
|
|
/* TODO Below parameters are hard-coded for the moment... */
|
|
priv->l2bpp = VIDEO_BPP16;
|
|
priv->bg_col_argb = 0xFFFFFFFF; /* white no transparency */
|
|
@@ -428,29 +428,21 @@ static int stm32_ltdc_probe(struct udevice *dev)
|
|
uc_priv->ysize = timings.vactive.typ;
|
|
uc_priv->bpix = priv->l2bpp;
|
|
|
|
-#ifdef CONFIG_VIDEO_BRIDGE
|
|
- if (bridge) {
|
|
- ret = video_bridge_set_backlight(bridge, 80);
|
|
- if (ret) {
|
|
- dev_err(dev, "fail to set backlight\n");
|
|
- return ret;
|
|
- }
|
|
- } else {
|
|
+ if (!bridge) {
|
|
ret = panel_enable_backlight(panel);
|
|
if (ret) {
|
|
dev_err(dev, "panel %s enable backlight error %d\n",
|
|
panel->name, ret);
|
|
return ret;
|
|
}
|
|
+ } else if (IS_ENABLED(CONFIG_VIDEO_BRIDGE)) {
|
|
+ ret = video_bridge_set_backlight(bridge, 80);
|
|
+ if (ret) {
|
|
+ dev_err(dev, "fail to set backlight\n");
|
|
+ return ret;
|
|
+ }
|
|
}
|
|
-#else
|
|
- ret = panel_enable_backlight(panel);
|
|
- if (ret) {
|
|
- dev_err(dev, "panel %s enable backlight error %d\n",
|
|
- panel->name, ret);
|
|
- return ret;
|
|
- }
|
|
-#endif
|
|
+
|
|
video_set_flush_dcache(dev, true);
|
|
|
|
return 0;
|
|
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
|
|
index 6193017..5f62167 100644
|
|
--- a/include/dm/uclass-id.h
|
|
+++ b/include/dm/uclass-id.h
|
|
@@ -35,6 +35,7 @@ enum uclass_id {
|
|
UCLASS_CPU, /* CPU, typically part of an SoC */
|
|
UCLASS_CROS_EC, /* Chrome OS EC */
|
|
UCLASS_DISPLAY, /* Display (e.g. DisplayPort, HDMI) */
|
|
+ UCLASS_DSI_HOST, /* Dsi host device */
|
|
UCLASS_DMA, /* Direct Memory Access */
|
|
UCLASS_EFI, /* EFI managed devices */
|
|
UCLASS_ETH, /* Ethernet device */
|
|
diff --git a/include/dsi_host.h b/include/dsi_host.h
|
|
new file mode 100644
|
|
index 0000000..9ff226f
|
|
--- /dev/null
|
|
+++ b/include/dsi_host.h
|
|
@@ -0,0 +1,57 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0+ */
|
|
+/*
|
|
+ * Copyright (C) 2019 STMicroelectronics - All Rights Reserved
|
|
+ * Author(s): Yannick Fertre <yannick.fertre@st.com> for STMicroelectronics.
|
|
+ *
|
|
+ */
|
|
+
|
|
+#ifndef _DSI_HOST_H
|
|
+#define _DSI_HOST_H
|
|
+
|
|
+#include <mipi_dsi.h>
|
|
+
|
|
+struct dsi_host_ops {
|
|
+ /**
|
|
+ * init() - Enable the dsi_host
|
|
+ *
|
|
+ * @dev: dsi host device
|
|
+ * @return 0 if OK, -ve on error
|
|
+ */
|
|
+ int (*init)(struct udevice *dev,
|
|
+ struct mipi_dsi_device *device,
|
|
+ struct display_timing *timings,
|
|
+ unsigned int max_data_lanes,
|
|
+ const struct mipi_dsi_phy_ops *phy_ops);
|
|
+
|
|
+ /**
|
|
+ * enable() - Enable the dsi_host
|
|
+ *
|
|
+ * @dev: dsi host device
|
|
+ * @return 0 if OK, -ve on error
|
|
+ */
|
|
+ int (*enable)(struct udevice *dev);
|
|
+};
|
|
+
|
|
+#define dsi_host_get_ops(dev) ((struct dsi_host_ops *)(dev)->driver->ops)
|
|
+
|
|
+/**
|
|
+ * dsi_host_init
|
|
+ *
|
|
+ * @dev: dsi host device
|
|
+ * @return 0 if OK, -ve on error
|
|
+ */
|
|
+int dsi_host_init(struct udevice *dev,
|
|
+ struct mipi_dsi_device *device,
|
|
+ struct display_timing *timings,
|
|
+ unsigned int max_data_lanes,
|
|
+ const struct mipi_dsi_phy_ops *phy_ops);
|
|
+
|
|
+/**
|
|
+ * dsi_host_enable
|
|
+ *
|
|
+ * @dev: dsi host device
|
|
+ * @return 0 if OK, -ve on error
|
|
+ */
|
|
+int dsi_host_enable(struct udevice *dev);
|
|
+
|
|
+#endif
|
|
diff --git a/include/mipi_display.h b/include/mipi_display.h
|
|
index 5c3dbbe..19aa65a 100644
|
|
--- a/include/mipi_display.h
|
|
+++ b/include/mipi_display.h
|
|
@@ -4,16 +4,12 @@
|
|
*
|
|
* Copyright (C) 2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
|
|
* Copyright (C) 2006 Nokia Corporation
|
|
- * Copyright (C) 2018 STMicroelectronics - All Rights Reserved
|
|
- * Author(s): Imre Deak <imre.deak@nokia.com>
|
|
- * Yannick Fertre <yannick.fertre@st.com>
|
|
- * Philippe Cornu <philippe.cornu@st.com>
|
|
+ * Author: Imre Deak <imre.deak@nokia.com>
|
|
*
|
|
* 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.
|
|
*/
|
|
-
|
|
#ifndef MIPI_DISPLAY_H
|
|
#define MIPI_DISPLAY_H
|
|
|
|
@@ -139,247 +135,4 @@ enum {
|
|
#define MIPI_DCS_PIXEL_FMT_8BIT 2
|
|
#define MIPI_DCS_PIXEL_FMT_3BIT 1
|
|
|
|
-struct mipi_dsi_host;
|
|
-struct mipi_dsi_device;
|
|
-
|
|
-/* request ACK from peripheral */
|
|
-#define MIPI_DSI_MSG_REQ_ACK BIT(0)
|
|
-/* use Low Power Mode to transmit message */
|
|
-#define MIPI_DSI_MSG_USE_LPM BIT(1)
|
|
-
|
|
-/**
|
|
- * struct mipi_dsi_msg - read/write DSI buffer
|
|
- * @channel: virtual channel id
|
|
- * @type: payload data type
|
|
- * @flags: flags controlling this message transmission
|
|
- * @tx_len: length of @tx_buf
|
|
- * @tx_buf: data to be written
|
|
- * @rx_len: length of @rx_buf
|
|
- * @rx_buf: data to be read, or NULL
|
|
- */
|
|
-struct mipi_dsi_msg {
|
|
- u8 channel;
|
|
- u8 type;
|
|
- u16 flags;
|
|
-
|
|
- size_t tx_len;
|
|
- const void *tx_buf;
|
|
-
|
|
- size_t rx_len;
|
|
- void *rx_buf;
|
|
-};
|
|
-
|
|
-bool mipi_dsi_packet_format_is_short(u8 type);
|
|
-bool mipi_dsi_packet_format_is_long(u8 type);
|
|
-
|
|
-/**
|
|
- * struct mipi_dsi_packet - represents a MIPI DSI packet in protocol format
|
|
- * @size: size (in bytes) of the packet
|
|
- * @header: the four bytes that make up the header (Data ID, Word Count or
|
|
- * Packet Data, and ECC)
|
|
- * @payload_length: number of bytes in the payload
|
|
- * @payload: a pointer to a buffer containing the payload, if any
|
|
- */
|
|
-struct mipi_dsi_packet {
|
|
- size_t size;
|
|
- u8 header[4];
|
|
- size_t payload_length;
|
|
- const u8 *payload;
|
|
-};
|
|
-
|
|
-int mipi_dsi_create_packet(struct mipi_dsi_packet *packet,
|
|
- const struct mipi_dsi_msg *msg);
|
|
-
|
|
-/**
|
|
- * struct mipi_dsi_host_ops - DSI bus operations
|
|
- * @attach: attach DSI device to DSI host
|
|
- * @detach: detach DSI device from DSI host
|
|
- * @transfer: transmit a DSI packet
|
|
- *
|
|
- * DSI packets transmitted by .transfer() are passed in as mipi_dsi_msg
|
|
- * structures. This structure contains information about the type of packet
|
|
- * being transmitted as well as the transmit and receive buffers. When an
|
|
- * error is encountered during transmission, this function will return a
|
|
- * negative error code. On success it shall return the number of bytes
|
|
- * transmitted for write packets or the number of bytes received for read
|
|
- * packets.
|
|
- *
|
|
- * Note that typically DSI packet transmission is atomic, so the .transfer()
|
|
- * function will seldomly return anything other than the number of bytes
|
|
- * contained in the transmit buffer on success.
|
|
- */
|
|
-struct mipi_dsi_host_ops {
|
|
- int (*attach)(struct mipi_dsi_host *host,
|
|
- struct mipi_dsi_device *dsi);
|
|
- int (*detach)(struct mipi_dsi_host *host,
|
|
- struct mipi_dsi_device *dsi);
|
|
- ssize_t (*transfer)(struct mipi_dsi_host *host,
|
|
- const struct mipi_dsi_msg *msg);
|
|
-};
|
|
-
|
|
-/**
|
|
- * struct mipi_dsi_host - DSI host device
|
|
- * @dev: driver model device node for this DSI host
|
|
- * @ops: DSI host operations
|
|
- * @list: list management
|
|
- */
|
|
-struct mipi_dsi_host {
|
|
- struct device *dev;
|
|
- const struct mipi_dsi_host_ops *ops;
|
|
- struct list_head list;
|
|
-};
|
|
-
|
|
-/* DSI mode flags */
|
|
-
|
|
-/* video mode */
|
|
-#define MIPI_DSI_MODE_VIDEO BIT(0)
|
|
-/* video burst mode */
|
|
-#define MIPI_DSI_MODE_VIDEO_BURST BIT(1)
|
|
-/* video pulse mode */
|
|
-#define MIPI_DSI_MODE_VIDEO_SYNC_PULSE BIT(2)
|
|
-/* enable auto vertical count mode */
|
|
-#define MIPI_DSI_MODE_VIDEO_AUTO_VERT BIT(3)
|
|
-/* enable hsync-end packets in vsync-pulse and v-porch area */
|
|
-#define MIPI_DSI_MODE_VIDEO_HSE BIT(4)
|
|
-/* disable hfront-porch area */
|
|
-#define MIPI_DSI_MODE_VIDEO_HFP BIT(5)
|
|
-/* disable hback-porch area */
|
|
-#define MIPI_DSI_MODE_VIDEO_HBP BIT(6)
|
|
-/* disable hsync-active area */
|
|
-#define MIPI_DSI_MODE_VIDEO_HSA BIT(7)
|
|
-/* flush display FIFO on vsync pulse */
|
|
-#define MIPI_DSI_MODE_VSYNC_FLUSH BIT(8)
|
|
-/* disable EoT packets in HS mode */
|
|
-#define MIPI_DSI_MODE_EOT_PACKET BIT(9)
|
|
-/* device supports non-continuous clock behavior (DSI spec 5.6.1) */
|
|
-#define MIPI_DSI_CLOCK_NON_CONTINUOUS BIT(10)
|
|
-/* transmit data in low power */
|
|
-#define MIPI_DSI_MODE_LPM BIT(11)
|
|
-
|
|
-enum mipi_dsi_pixel_format {
|
|
- MIPI_DSI_FMT_RGB888,
|
|
- MIPI_DSI_FMT_RGB666,
|
|
- MIPI_DSI_FMT_RGB666_PACKED,
|
|
- MIPI_DSI_FMT_RGB565,
|
|
-};
|
|
-
|
|
-#define DSI_DEV_NAME_SIZE 20
|
|
-
|
|
-/**
|
|
- * struct mipi_dsi_device_info - template for creating a mipi_dsi_device
|
|
- * @type: DSI peripheral chip type
|
|
- * @channel: DSI virtual channel assigned to peripheral
|
|
- * @node: pointer to OF device node or NULL
|
|
- *
|
|
- * This is populated and passed to mipi_dsi_device_new to create a new
|
|
- * DSI device
|
|
- */
|
|
-struct mipi_dsi_device_info {
|
|
- char type[DSI_DEV_NAME_SIZE];
|
|
- u32 channel;
|
|
- struct device_node *node;
|
|
-};
|
|
-
|
|
-/**
|
|
- * struct mipi_dsi_device - DSI peripheral device
|
|
- * @host: DSI host for this peripheral
|
|
- * @dev: driver model device node for this peripheral
|
|
- * @name: DSI peripheral chip type
|
|
- * @channel: virtual channel assigned to the peripheral
|
|
- * @format: pixel format for video mode
|
|
- * @lanes: number of active data lanes
|
|
- * @mode_flags: DSI operation mode related flags
|
|
- */
|
|
-struct mipi_dsi_device {
|
|
- struct mipi_dsi_host *host;
|
|
- struct udevice *dev;
|
|
-
|
|
- char name[DSI_DEV_NAME_SIZE];
|
|
- unsigned int channel;
|
|
- unsigned int lanes;
|
|
- enum mipi_dsi_pixel_format format;
|
|
- unsigned long mode_flags;
|
|
-};
|
|
-
|
|
-/**
|
|
- * enum mipi_dsi_dcs_tear_mode - Tearing Effect Output Line mode
|
|
- * @MIPI_DSI_DCS_TEAR_MODE_VBLANK: the TE output line consists of V-Blanking
|
|
- * information only
|
|
- * @MIPI_DSI_DCS_TEAR_MODE_VHBLANK : the TE output line consists of both
|
|
- * V-Blanking and H-Blanking information
|
|
- */
|
|
-enum mipi_dsi_dcs_tear_mode {
|
|
- MIPI_DSI_DCS_TEAR_MODE_VBLANK,
|
|
- MIPI_DSI_DCS_TEAR_MODE_VHBLANK,
|
|
-};
|
|
-
|
|
-/**
|
|
- * struct mipi_dsi_panel_plat - DSI panel platform data
|
|
- * @device: DSI peripheral device
|
|
- */
|
|
-struct mipi_dsi_panel_plat {
|
|
- struct mipi_dsi_device *device;
|
|
-};
|
|
-
|
|
-int mipi_dsi_attach(struct mipi_dsi_device *dsi);
|
|
-int mipi_dsi_detach(struct mipi_dsi_device *dsi);
|
|
-int mipi_dsi_pixel_format_to_bpp(enum mipi_dsi_pixel_format fmt);
|
|
-
|
|
-/* bit compatible with the xrandr RR_ definitions (bits 0-13)
|
|
- *
|
|
- * ABI warning: Existing userspace really expects
|
|
- * the mode flags to match the xrandr definitions. Any
|
|
- * changes that don't match the xrandr definitions will
|
|
- * likely need a new client cap or some other mechanism
|
|
- * to avoid breaking existing userspace. This includes
|
|
- * allocating new flags in the previously unused bits!
|
|
- */
|
|
-#define MIPI_DSI_FLAG_PHSYNC BIT(0)
|
|
-#define MIPI_DSI_FLAG_NHSYNC BIT(1)
|
|
-#define MIPI_DSI_FLAG_PVSYNC BIT(2)
|
|
-#define MIPI_DSI_FLAG_NVSYNC BIT(3)
|
|
-#define MIPI_DSI_FLAG_INTERLACE BIT(4)
|
|
-#define MIPI_DSI_FLAG_DBLSCAN BIT(5)
|
|
-#define MIPI_DSI_FLAG_CSYNC BIT(6)
|
|
-#define MIPI_DSI_FLAG_PCSYNC BIT(7)
|
|
-#define MIPI_DSI_FLAG_NCSYNC BIT(8)
|
|
-#define MIPI_DSI_FLAG_HSKEW BIT(9) /* hskew provided */
|
|
-#define MIPI_DSI_FLAG_BCAST BIT(10)
|
|
-#define MIPI_DSI_FLAG_PIXMUX BIT(11)
|
|
-#define MIPI_DSI_FLAG_DBLCLK BIT(12)
|
|
-#define MIPI_DSI_FLAG_CLKDIV2 BIT(13)
|
|
-
|
|
-/* request ACK from peripheral */
|
|
-#define MIPI_DSI_MSG_REQ_ACK BIT(0)
|
|
-/* use Low Power Mode to transmit message */
|
|
-#define MIPI_DSI_MSG_USE_LPM BIT(1)
|
|
-
|
|
-ssize_t mipi_dsi_dcs_write_buffer(struct mipi_dsi_device *dsi,
|
|
- const void *data, size_t len);
|
|
-ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, u8 cmd,
|
|
- const void *data, size_t len);
|
|
-ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, u8 cmd, void *data,
|
|
- size_t len);
|
|
-int mipi_dsi_dcs_nop(struct mipi_dsi_device *dsi);
|
|
-int mipi_dsi_dcs_soft_reset(struct mipi_dsi_device *dsi);
|
|
-int mipi_dsi_dcs_get_power_mode(struct mipi_dsi_device *dsi, u8 *mode);
|
|
-int mipi_dsi_dcs_get_pixel_format(struct mipi_dsi_device *dsi, u8 *format);
|
|
-int mipi_dsi_dcs_enter_sleep_mode(struct mipi_dsi_device *dsi);
|
|
-int mipi_dsi_dcs_exit_sleep_mode(struct mipi_dsi_device *dsi);
|
|
-int mipi_dsi_dcs_set_display_off(struct mipi_dsi_device *dsi);
|
|
-int mipi_dsi_dcs_set_display_on(struct mipi_dsi_device *dsi);
|
|
-int mipi_dsi_dcs_set_column_address(struct mipi_dsi_device *dsi, u16 start,
|
|
- u16 end);
|
|
-int mipi_dsi_dcs_set_page_address(struct mipi_dsi_device *dsi, u16 start,
|
|
- u16 end);
|
|
-int mipi_dsi_dcs_set_tear_off(struct mipi_dsi_device *dsi);
|
|
-int mipi_dsi_dcs_set_tear_on(struct mipi_dsi_device *dsi,
|
|
- enum mipi_dsi_dcs_tear_mode mode);
|
|
-int mipi_dsi_dcs_set_pixel_format(struct mipi_dsi_device *dsi, u8 format);
|
|
-int mipi_dsi_dcs_set_tear_scanline(struct mipi_dsi_device *dsi, u16 scanline);
|
|
-int mipi_dsi_dcs_set_display_brightness(struct mipi_dsi_device *dsi,
|
|
- u16 brightness);
|
|
-int mipi_dsi_dcs_get_display_brightness(struct mipi_dsi_device *dsi,
|
|
- u16 *brightness);
|
|
-
|
|
#endif
|
|
diff --git a/include/mipi_dsi.h b/include/mipi_dsi.h
|
|
new file mode 100644
|
|
index 0000000..f76e8d7
|
|
--- /dev/null
|
|
+++ b/include/mipi_dsi.h
|
|
@@ -0,0 +1,473 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|
+/*
|
|
+ * MIPI DSI Bus
|
|
+ *
|
|
+ * Copyright (C) 2012-2013, Samsung Electronics, Co., Ltd.
|
|
+ * Copyright (C) 2018 STMicroelectronics - All Rights Reserved
|
|
+ * Author(s): Andrzej Hajda <a.hajda@samsung.com>
|
|
+ * Yannick Fertre <yannick.fertre@st.com>
|
|
+ * Philippe Cornu <philippe.cornu@st.com>
|
|
+ *
|
|
+ * 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.
|
|
+ */
|
|
+#ifndef MIPI_DSI_H
|
|
+#define MIPI_DSI_H
|
|
+
|
|
+#include <display.h>
|
|
+#include <mipi_display.h>
|
|
+
|
|
+struct mipi_dsi_host;
|
|
+struct mipi_dsi_device;
|
|
+
|
|
+/* request ACK from peripheral */
|
|
+#define MIPI_DSI_MSG_REQ_ACK BIT(0)
|
|
+/* use Low Power Mode to transmit message */
|
|
+#define MIPI_DSI_MSG_USE_LPM BIT(1)
|
|
+
|
|
+/**
|
|
+ * struct mipi_dsi_msg - read/write DSI buffer
|
|
+ * @channel: virtual channel id
|
|
+ * @type: payload data type
|
|
+ * @flags: flags controlling this message transmission
|
|
+ * @tx_len: length of @tx_buf
|
|
+ * @tx_buf: data to be written
|
|
+ * @rx_len: length of @rx_buf
|
|
+ * @rx_buf: data to be read, or NULL
|
|
+ */
|
|
+struct mipi_dsi_msg {
|
|
+ u8 channel;
|
|
+ u8 type;
|
|
+ u16 flags;
|
|
+
|
|
+ size_t tx_len;
|
|
+ const void *tx_buf;
|
|
+
|
|
+ size_t rx_len;
|
|
+ void *rx_buf;
|
|
+};
|
|
+
|
|
+bool mipi_dsi_packet_format_is_short(u8 type);
|
|
+bool mipi_dsi_packet_format_is_long(u8 type);
|
|
+
|
|
+/**
|
|
+ * struct mipi_dsi_packet - represents a MIPI DSI packet in protocol format
|
|
+ * @size: size (in bytes) of the packet
|
|
+ * @header: the four bytes that make up the header (Data ID, Word Count or
|
|
+ * Packet Data, and ECC)
|
|
+ * @payload_length: number of bytes in the payload
|
|
+ * @payload: a pointer to a buffer containing the payload, if any
|
|
+ */
|
|
+struct mipi_dsi_packet {
|
|
+ size_t size;
|
|
+ u8 header[4];
|
|
+ size_t payload_length;
|
|
+ const u8 *payload;
|
|
+};
|
|
+
|
|
+int mipi_dsi_create_packet(struct mipi_dsi_packet *packet,
|
|
+ const struct mipi_dsi_msg *msg);
|
|
+
|
|
+/**
|
|
+ * struct mipi_dsi_host_ops - DSI bus operations
|
|
+ * @attach: attach DSI device to DSI host
|
|
+ * @detach: detach DSI device from DSI host
|
|
+ * @transfer: transmit a DSI packet
|
|
+ *
|
|
+ * DSI packets transmitted by .transfer() are passed in as mipi_dsi_msg
|
|
+ * structures. This structure contains information about the type of packet
|
|
+ * being transmitted as well as the transmit and receive buffers. When an
|
|
+ * error is encountered during transmission, this function will return a
|
|
+ * negative error code. On success it shall return the number of bytes
|
|
+ * transmitted for write packets or the number of bytes received for read
|
|
+ * packets.
|
|
+ *
|
|
+ * Note that typically DSI packet transmission is atomic, so the .transfer()
|
|
+ * function will seldomly return anything other than the number of bytes
|
|
+ * contained in the transmit buffer on success.
|
|
+ */
|
|
+struct mipi_dsi_host_ops {
|
|
+ int (*attach)(struct mipi_dsi_host *host,
|
|
+ struct mipi_dsi_device *dsi);
|
|
+ int (*detach)(struct mipi_dsi_host *host,
|
|
+ struct mipi_dsi_device *dsi);
|
|
+ ssize_t (*transfer)(struct mipi_dsi_host *host,
|
|
+ const struct mipi_dsi_msg *msg);
|
|
+};
|
|
+
|
|
+/**
|
|
+ * struct mipi_dsi_phy_ops - DSI host physical operations
|
|
+ * @init: initialized host physical part
|
|
+ * @get_lane_mbps: get lane bitrate per lane (mbps)
|
|
+ * @post_set_mode: operation that should after set mode
|
|
+ */
|
|
+struct mipi_dsi_phy_ops {
|
|
+ int (*init)(void *priv_data);
|
|
+ int (*get_lane_mbps)(void *priv_data, struct display_timing *timings,
|
|
+ u32 lanes, u32 format, unsigned int *lane_mbps);
|
|
+ void (*post_set_mode)(void *priv_data, unsigned long mode_flags);
|
|
+};
|
|
+
|
|
+/**
|
|
+ * struct mipi_dsi_host - DSI host device
|
|
+ * @dev: driver model device node for this DSI host
|
|
+ * @ops: DSI host operations
|
|
+ * @list: list management
|
|
+ */
|
|
+struct mipi_dsi_host {
|
|
+ struct device *dev;
|
|
+ const struct mipi_dsi_host_ops *ops;
|
|
+ struct list_head list;
|
|
+};
|
|
+
|
|
+/* DSI mode flags */
|
|
+
|
|
+/* video mode */
|
|
+#define MIPI_DSI_MODE_VIDEO BIT(0)
|
|
+/* video burst mode */
|
|
+#define MIPI_DSI_MODE_VIDEO_BURST BIT(1)
|
|
+/* video pulse mode */
|
|
+#define MIPI_DSI_MODE_VIDEO_SYNC_PULSE BIT(2)
|
|
+/* enable auto vertical count mode */
|
|
+#define MIPI_DSI_MODE_VIDEO_AUTO_VERT BIT(3)
|
|
+/* enable hsync-end packets in vsync-pulse and v-porch area */
|
|
+#define MIPI_DSI_MODE_VIDEO_HSE BIT(4)
|
|
+/* disable hfront-porch area */
|
|
+#define MIPI_DSI_MODE_VIDEO_HFP BIT(5)
|
|
+/* disable hback-porch area */
|
|
+#define MIPI_DSI_MODE_VIDEO_HBP BIT(6)
|
|
+/* disable hsync-active area */
|
|
+#define MIPI_DSI_MODE_VIDEO_HSA BIT(7)
|
|
+/* flush display FIFO on vsync pulse */
|
|
+#define MIPI_DSI_MODE_VSYNC_FLUSH BIT(8)
|
|
+/* disable EoT packets in HS mode */
|
|
+#define MIPI_DSI_MODE_EOT_PACKET BIT(9)
|
|
+/* device supports non-continuous clock behavior (DSI spec 5.6.1) */
|
|
+#define MIPI_DSI_CLOCK_NON_CONTINUOUS BIT(10)
|
|
+/* transmit data in low power */
|
|
+#define MIPI_DSI_MODE_LPM BIT(11)
|
|
+
|
|
+enum mipi_dsi_pixel_format {
|
|
+ MIPI_DSI_FMT_RGB888,
|
|
+ MIPI_DSI_FMT_RGB666,
|
|
+ MIPI_DSI_FMT_RGB666_PACKED,
|
|
+ MIPI_DSI_FMT_RGB565,
|
|
+};
|
|
+
|
|
+#define DSI_DEV_NAME_SIZE 20
|
|
+
|
|
+/**
|
|
+ * struct mipi_dsi_device_info - template for creating a mipi_dsi_device
|
|
+ * @type: DSI peripheral chip type
|
|
+ * @channel: DSI virtual channel assigned to peripheral
|
|
+ * @node: pointer to OF device node or NULL
|
|
+ *
|
|
+ * This is populated and passed to mipi_dsi_device_new to create a new
|
|
+ * DSI device
|
|
+ */
|
|
+struct mipi_dsi_device_info {
|
|
+ char type[DSI_DEV_NAME_SIZE];
|
|
+ u32 channel;
|
|
+ struct device_node *node;
|
|
+};
|
|
+
|
|
+/**
|
|
+ * struct mipi_dsi_device - DSI peripheral device
|
|
+ * @host: DSI host for this peripheral
|
|
+ * @dev: driver model device node for this peripheral
|
|
+ * @name: DSI peripheral chip type
|
|
+ * @channel: virtual channel assigned to the peripheral
|
|
+ * @format: pixel format for video mode
|
|
+ * @lanes: number of active data lanes
|
|
+ * @mode_flags: DSI operation mode related flags
|
|
+ */
|
|
+struct mipi_dsi_device {
|
|
+ struct mipi_dsi_host *host;
|
|
+ struct udevice *dev;
|
|
+
|
|
+ char name[DSI_DEV_NAME_SIZE];
|
|
+ unsigned int channel;
|
|
+ unsigned int lanes;
|
|
+ enum mipi_dsi_pixel_format format;
|
|
+ unsigned long mode_flags;
|
|
+};
|
|
+
|
|
+/**
|
|
+ * mipi_dsi_pixel_format_to_bpp - obtain the number of bits per pixel for any
|
|
+ * given pixel format defined by the MIPI DSI
|
|
+ * specification
|
|
+ * @fmt: MIPI DSI pixel format
|
|
+ *
|
|
+ * Returns: The number of bits per pixel of the given pixel format.
|
|
+ */
|
|
+static inline int mipi_dsi_pixel_format_to_bpp(enum mipi_dsi_pixel_format fmt)
|
|
+{
|
|
+ switch (fmt) {
|
|
+ case MIPI_DSI_FMT_RGB888:
|
|
+ case MIPI_DSI_FMT_RGB666:
|
|
+ return 24;
|
|
+
|
|
+ case MIPI_DSI_FMT_RGB666_PACKED:
|
|
+ return 18;
|
|
+
|
|
+ case MIPI_DSI_FMT_RGB565:
|
|
+ return 16;
|
|
+ }
|
|
+
|
|
+ return -EINVAL;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * struct mipi_dsi_panel_plat - DSI panel platform data
|
|
+ * @device: DSI peripheral device
|
|
+ * @lanes: number of active data lanes
|
|
+ * @format: pixel format for video mode
|
|
+ * @mode_flags: DSI operation mode related flags
|
|
+ */
|
|
+struct mipi_dsi_panel_plat {
|
|
+ struct mipi_dsi_device *device;
|
|
+ unsigned int lanes;
|
|
+ enum mipi_dsi_pixel_format format;
|
|
+ unsigned long mode_flags;
|
|
+};
|
|
+
|
|
+/**
|
|
+ * mipi_dsi_attach - attach a DSI device to its DSI host
|
|
+ * @dsi: DSI peripheral
|
|
+ */
|
|
+int mipi_dsi_attach(struct mipi_dsi_device *dsi);
|
|
+
|
|
+/**
|
|
+ * mipi_dsi_detach - detach a DSI device from its DSI host
|
|
+ * @dsi: DSI peripheral
|
|
+ */
|
|
+int mipi_dsi_detach(struct mipi_dsi_device *dsi);
|
|
+int mipi_dsi_shutdown_peripheral(struct mipi_dsi_device *dsi);
|
|
+int mipi_dsi_turn_on_peripheral(struct mipi_dsi_device *dsi);
|
|
+int mipi_dsi_set_maximum_return_packet_size(struct mipi_dsi_device *dsi,
|
|
+ u16 value);
|
|
+
|
|
+ssize_t mipi_dsi_generic_write(struct mipi_dsi_device *dsi, const void *payload,
|
|
+ size_t size);
|
|
+ssize_t mipi_dsi_generic_read(struct mipi_dsi_device *dsi, const void *params,
|
|
+ size_t num_params, void *data, size_t size);
|
|
+
|
|
+/**
|
|
+ * enum mipi_dsi_dcs_tear_mode - Tearing Effect Output Line mode
|
|
+ * @MIPI_DSI_DCS_TEAR_MODE_VBLANK: the TE output line consists of V-Blanking
|
|
+ * information only
|
|
+ * @MIPI_DSI_DCS_TEAR_MODE_VHBLANK : the TE output line consists of both
|
|
+ * V-Blanking and H-Blanking information
|
|
+ */
|
|
+enum mipi_dsi_dcs_tear_mode {
|
|
+ MIPI_DSI_DCS_TEAR_MODE_VBLANK,
|
|
+ MIPI_DSI_DCS_TEAR_MODE_VHBLANK,
|
|
+};
|
|
+
|
|
+#define MIPI_DSI_DCS_POWER_MODE_DISPLAY BIT(2)
|
|
+#define MIPI_DSI_DCS_POWER_MODE_NORMAL BIT(3)
|
|
+#define MIPI_DSI_DCS_POWER_MODE_SLEEP BIT(4)
|
|
+#define MIPI_DSI_DCS_POWER_MODE_PARTIAL BIT(5)
|
|
+#define MIPI_DSI_DCS_POWER_MODE_IDLE BIT(6)
|
|
+
|
|
+/**
|
|
+ * 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);
|
|
+
|
|
+/**
|
|
+ * 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.
|
|
+
|
|
+ * code on failure.
|
|
+ */
|
|
+ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, u8 cmd,
|
|
+ const void *data, size_t len);
|
|
+
|
|
+/**
|
|
+ * 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);
|
|
+
|
|
+/**
|
|
+ * 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);
|
|
+
|
|
+/**
|
|
+ * 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);
|
|
+
|
|
+/**
|
|
+ * 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);
|
|
+
|
|
+/**
|
|
+ * 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);
|
|
+
|
|
+/**
|
|
+ * 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);
|
|
+
|
|
+/**
|
|
+ * 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);
|
|
+
|
|
+/**
|
|
+ * 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);
|
|
+
|
|
+/**
|
|
+ * 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);
|
|
+
|
|
+/**
|
|
+ * 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);
|
|
+/**
|
|
+ * 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);
|
|
+
|
|
+/**
|
|
+ * 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);
|
|
+
|
|
+/**
|
|
+ * 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);
|
|
+
|
|
+/**
|
|
+ * 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);
|
|
+
|
|
+/**
|
|
+ * mipi_dsi_dcs_set_tear_scanline() - set the scanline to use as trigger for
|
|
+ * the Tearing Effect output signal of the display module
|
|
+ * @dsi: DSI peripheral device
|
|
+ * @scanline: scanline to use as trigger
|
|
+ *
|
|
+ * Return: 0 on success or a negative error code on failure
|
|
+ */
|
|
+int mipi_dsi_dcs_set_tear_scanline(struct mipi_dsi_device *dsi, u16 scanline);
|
|
+
|
|
+/**
|
|
+ * mipi_dsi_dcs_set_display_brightness() - sets the brightness value of the
|
|
+ * display
|
|
+ * @dsi: DSI peripheral device
|
|
+ * @brightness: brightness value
|
|
+ *
|
|
+ * Return: 0 on success or a negative error code on failure.
|
|
+ */
|
|
+int mipi_dsi_dcs_set_display_brightness(struct mipi_dsi_device *dsi,
|
|
+ u16 brightness);
|
|
+
|
|
+/**
|
|
+ * mipi_dsi_dcs_get_display_brightness() - gets the current brightness value
|
|
+ * of the display
|
|
+ * @dsi: DSI peripheral device
|
|
+ * @brightness: brightness value
|
|
+ *
|
|
+ * Return: 0 on success or a negative error code on failure.
|
|
+ */
|
|
+int mipi_dsi_dcs_get_display_brightness(struct mipi_dsi_device *dsi,
|
|
+ u16 *brightness);
|
|
+
|
|
+#endif /* MIPI_DSI_H */
|
|
diff --git a/include/mmc.h b/include/mmc.h
|
|
index 95548e9..a3974a8 100644
|
|
--- a/include/mmc.h
|
|
+++ b/include/mmc.h
|
|
@@ -461,6 +461,16 @@ struct dm_mmc_ops {
|
|
*/
|
|
int (*wait_dat0)(struct udevice *dev, int state, int timeout);
|
|
#endif
|
|
+
|
|
+ /**
|
|
+ * host_power_cycle - host specific tasks in power cycle sequence
|
|
+ * Called between mmc_power_off() and
|
|
+ * mmc_power_on()
|
|
+ *
|
|
+ * @dev: Device to check
|
|
+ * @return 0 if not present, 1 if present, -ve on error
|
|
+ */
|
|
+ int (*host_power_cycle)(struct udevice *dev);
|
|
};
|
|
|
|
#define mmc_get_ops(dev) ((struct dm_mmc_ops *)(dev)->driver->ops)
|
|
@@ -473,6 +483,7 @@ int dm_mmc_get_cd(struct udevice *dev);
|
|
int dm_mmc_get_wp(struct udevice *dev);
|
|
int dm_mmc_execute_tuning(struct udevice *dev, uint opcode);
|
|
int dm_mmc_wait_dat0(struct udevice *dev, int state, int timeout);
|
|
+int dm_mmc_host_power_cycle(struct udevice *dev);
|
|
|
|
/* Transition functions for compatibility */
|
|
int mmc_set_ios(struct mmc *mmc);
|
|
@@ -481,6 +492,7 @@ int mmc_getcd(struct mmc *mmc);
|
|
int mmc_getwp(struct mmc *mmc);
|
|
int mmc_execute_tuning(struct mmc *mmc, uint opcode);
|
|
int mmc_wait_dat0(struct mmc *mmc, int state, int timeout);
|
|
+int mmc_host_power_cycle(struct mmc *mmc);
|
|
|
|
#else
|
|
struct mmc_ops {
|
|
@@ -490,6 +502,7 @@ struct mmc_ops {
|
|
int (*init)(struct mmc *mmc);
|
|
int (*getcd)(struct mmc *mmc);
|
|
int (*getwp)(struct mmc *mmc);
|
|
+ int (*host_power_cycle)(struct mmc *mmc);
|
|
};
|
|
#endif
|
|
|
|
diff --git a/include/power/stpmic1.h b/include/power/stpmic1.h
|
|
index d90a1a9..b5a6d52 100644
|
|
--- a/include/power/stpmic1.h
|
|
+++ b/include/power/stpmic1.h
|
|
@@ -37,6 +37,7 @@
|
|
#define STPMIC1_BUCK_VOUT(sel) (sel << STPMIC1_BUCK_VOUT_SHIFT)
|
|
|
|
#define STPMIC1_BUCK2_1200000V STPMIC1_BUCK_VOUT(24)
|
|
+#define STPMIC1_BUCK2_1250000V STPMIC1_BUCK_VOUT(26)
|
|
#define STPMIC1_BUCK2_1350000V STPMIC1_BUCK_VOUT(30)
|
|
|
|
#define STPMIC1_BUCK3_1800000V STPMIC1_BUCK_VOUT(39)
|
|
diff --git a/include/remoteproc.h b/include/remoteproc.h
|
|
index fa82531..e25702b 100644
|
|
--- a/include/remoteproc.h
|
|
+++ b/include/remoteproc.h
|
|
@@ -45,6 +45,17 @@ struct dm_rproc_uclass_pdata {
|
|
};
|
|
|
|
/**
|
|
+ * struct rproc_priv - Device information used by the rproc uclass
|
|
+ *
|
|
+ * @rsc_table_addr: Resource Table address (if any)
|
|
+ * @rsc_table_size: Resource Table size
|
|
+ */
|
|
+struct rproc_priv {
|
|
+ ulong rsc_table_addr;
|
|
+ unsigned int rsc_table_size;
|
|
+};
|
|
+
|
|
+/**
|
|
* struct dm_rproc_ops - Operations that are provided by remote proc driver
|
|
* @init: Initialize the remoteproc device invoked after probe (optional)
|
|
* Return 0 on success, -ve error on fail
|
|
--
|
|
2.7.4
|
|
|