From f9093185ec7e97b73304598df0037ea7b030012c Mon Sep 17 00:00:00 2001 From: Priouzeau Christophe Date: Mon, 3 Feb 2020 14:58:34 +0100 Subject: [PATCH] U-BOOT: bump to v1.2.0 (v2018.11-r4) Change-Id: Id53c130643e9a3c0bf9ba1a3644d45b34524dd35 Signed-off-by: Priouzeau Christophe --- .../u-boot/u-boot-stm32mp-common_2018.11.inc | 6 +- recipes-bsp/u-boot/u-boot-stm32mp-extlinux.bb | 2 +- .../u-boot-stm32mp-extlinux/boot.scr.cmd | 11 +- ...0014-ARM-v2018.11-stm32mp-r4-MACHINE.patch | 494 ++ .../0015-ARM-v2018.11-stm32mp-r4-BOARD.patch | 255 + ...6-ARM-v2018.11-stm32mp-r4-DEVICETREE.patch | 1191 +++++ .../0017-ARM-v2018.11-stm32mp-r4-MISC.patch | 4739 +++++++++++++++++ 7 files changed, 6691 insertions(+), 7 deletions(-) create mode 100644 recipes-bsp/u-boot/u-boot-stm32mp/0014-ARM-v2018.11-stm32mp-r4-MACHINE.patch create mode 100644 recipes-bsp/u-boot/u-boot-stm32mp/0015-ARM-v2018.11-stm32mp-r4-BOARD.patch create mode 100644 recipes-bsp/u-boot/u-boot-stm32mp/0016-ARM-v2018.11-stm32mp-r4-DEVICETREE.patch create mode 100644 recipes-bsp/u-boot/u-boot-stm32mp/0017-ARM-v2018.11-stm32mp-r4-MISC.patch diff --git a/recipes-bsp/u-boot/u-boot-stm32mp-common_2018.11.inc b/recipes-bsp/u-boot/u-boot-stm32mp-common_2018.11.inc index 9923789..620e61b 100644 --- a/recipes-bsp/u-boot/u-boot-stm32mp-common_2018.11.inc +++ b/recipes-bsp/u-boot/u-boot-stm32mp-common_2018.11.inc @@ -29,6 +29,10 @@ SRC_URI += " \ file://0011-ARM-v2018.11-stm32mp-r3-DEVICETREE.patch \ file://0012-ARM-v2018.11-stm32mp-r3-CONFIG.patch \ file://0013-ARM-v2018.11-stm32mp-r3-MISC.patch \ + file://0014-ARM-v2018.11-stm32mp-r4-MACHINE.patch \ + file://0015-ARM-v2018.11-stm32mp-r4-BOARD.patch \ + file://0016-ARM-v2018.11-stm32mp-r4-DEVICETREE.patch \ + file://0017-ARM-v2018.11-stm32mp-r4-MISC.patch \ " U_BOOT_VERSION = "2018.11" @@ -42,7 +46,7 @@ S = "${WORKDIR}/u-boot-${PV}" BBCLASSEXTEND = "devupstream:target" SRC_URI_class-devupstream = "git://github.com/STMicroelectronics/u-boot.git;name=uboot;protocol=https;branch=v2018.11-stm32mp" -SRCREV_class-devupstream = "22eea618b3295cfae777aa80789eb1b46824db12" +SRCREV_class-devupstream = "fd915f073fe23fea3eb509dbc26ac9da1893692a" SRCREV_FORMAT_class-devupstream = "uboot" PV_class-devupstream = "${U_BOOT_VERSION}+github+${SRCPV}" diff --git a/recipes-bsp/u-boot/u-boot-stm32mp-extlinux.bb b/recipes-bsp/u-boot/u-boot-stm32mp-extlinux.bb index 67d2687..2218195 100644 --- a/recipes-bsp/u-boot/u-boot-stm32mp-extlinux.bb +++ b/recipes-bsp/u-boot/u-boot-stm32mp-extlinux.bb @@ -8,7 +8,7 @@ PACKAGE_ARCH = "${MACHINE_ARCH}" SRC_URI = "file://boot.scr.cmd" -PV = "2.0" +PV = "2.6" inherit kernel-arch extlinuxconf-stm32mp diff --git a/recipes-bsp/u-boot/u-boot-stm32mp-extlinux/boot.scr.cmd b/recipes-bsp/u-boot/u-boot-stm32mp-extlinux/boot.scr.cmd index 5ad9a9d..06707e3 100644 --- a/recipes-bsp/u-boot/u-boot-stm32mp-extlinux/boot.scr.cmd +++ b/recipes-bsp/u-boot/u-boot-stm32mp-extlinux/boot.scr.cmd @@ -29,16 +29,17 @@ elif test ${boot_device} = nand; then elif test ${boot_device} = nor; then - #SDCARD boot - run bootcmd_mmc0 + #EMMC boot + env set boot_prefixes "/${boot_device}${boot_instance}-mmc1_${board_name}_" + run bootcmd_mmc1 #NAND boot env set boot_prefixes "/nand0_${board_name}_" run bootcmd_ubifs0 - #EMMC boot - env set boot_prefixes "/${boot_device}${boot_instance}-mmc1_${board_name}_" - run bootcmd_mmc1 + #SDCARD boot + env set boot_prefixes "/${boot_device}${boot_instance}_${board_name}_" + run bootcmd_mmc0 fi echo SCRIPT FAILED... ${boot_prefixes}extlinux/extlinux.conf not found ! diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/0014-ARM-v2018.11-stm32mp-r4-MACHINE.patch b/recipes-bsp/u-boot/u-boot-stm32mp/0014-ARM-v2018.11-stm32mp-r4-MACHINE.patch new file mode 100644 index 0000000..3fe26e6 --- /dev/null +++ b/recipes-bsp/u-boot/u-boot-stm32mp/0014-ARM-v2018.11-stm32mp-r4-MACHINE.patch @@ -0,0 +1,494 @@ +From 19120ee9047a8e592c8a82d12a8482ef944f0dda Mon Sep 17 00:00:00 2001 +From: Romuald JEANNE +Date: Thu, 30 Jan 2020 14:55:56 +0100 +Subject: [PATCH 14/17] ARM v2018.11 stm32mp r4 MACHINE + +--- + arch/arm/mach-stm32mp/Makefile | 3 +- + arch/arm/mach-stm32mp/bsec.c | 4 +- + arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c | 82 ++++++++++++++----------- + arch/arm/mach-stm32mp/cpu.c | 21 +++++++ + arch/arm/mach-stm32mp/include/mach/ddr.h | 6 +- + arch/arm/mach-stm32mp/include/mach/stm32.h | 1 + + arch/arm/mach-stm32mp/include/mach/sys_proto.h | 13 +++- + arch/arm/mach-stm32mp/spl.c | 41 ++++++++----- + arch/arm/mach-stm32mp/stm32mp1_helper_dbg.S | 5 +- + 9 files changed, 116 insertions(+), 60 deletions(-) + +diff --git a/arch/arm/mach-stm32mp/Makefile b/arch/arm/mach-stm32mp/Makefile +index 9158a20..13e7773 100644 +--- a/arch/arm/mach-stm32mp/Makefile ++++ b/arch/arm/mach-stm32mp/Makefile +@@ -6,6 +6,7 @@ + obj-y += cpu.o + obj-y += dram_init.o + obj-y += syscon.o ++obj-y += bsec.o + + ifdef CONFIG_SPL_BUILD + obj-y += spl.o +@@ -13,8 +14,6 @@ obj-$(CONFIG_STM32MP1_RESET_HALT_WORKAROUND) += stm32mp1_helper_dbg.o + else + obj-$(CONFIG_CMD_STM32PROG) += cmd_stm32prog/ + obj-$(CONFIG_CMD_STM32KEY) += cmd_stm32key.o +- +-obj-y += bsec.o + obj-$(CONFIG_SYSRESET) += cmd_poweroff.o + obj-$(CONFIG_ARMV7_PSCI) += psci.o + endif +diff --git a/arch/arm/mach-stm32mp/bsec.c b/arch/arm/mach-stm32mp/bsec.c +index 5256378..fa7f39f 100644 +--- a/arch/arm/mach-stm32mp/bsec.c ++++ b/arch/arm/mach-stm32mp/bsec.c +@@ -436,7 +436,7 @@ static int stm32mp_bsec_ofdata_to_platdata(struct udevice *dev) + return 0; + } + +-#ifndef CONFIG_STM32MP1_TRUSTED ++#if !defined(CONFIG_STM32MP1_TRUSTED) && !defined(CONFIG_SPL_BUILD) + static int stm32mp_bsec_probe(struct udevice *dev) + { + int otp; +@@ -463,7 +463,7 @@ U_BOOT_DRIVER(stm32mp_bsec) = { + .ofdata_to_platdata = stm32mp_bsec_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct stm32mp_bsec_platdata), + .ops = &stm32mp_bsec_ops, +-#ifndef CONFIG_STM32MP1_TRUSTED ++#if !defined(CONFIG_STM32MP1_TRUSTED) && !defined(CONFIG_SPL_BUILD) + .probe = stm32mp_bsec_probe, + #endif + }; +diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c +index 8325b56..c6d8f14 100644 +--- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c ++++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c +@@ -63,7 +63,7 @@ static const efi_guid_t uuid_mmc[3] = { + }; + + DECLARE_GLOBAL_DATA_PTR; +-#define ENV_BUF_LEN SZ_1K ++#define ALT_BUF_LEN SZ_1K + + /* order of column in flash layout file */ + enum stm32prog_col_t { +@@ -842,8 +842,8 @@ static int treat_partition_list(struct stm32prog_data *data) + static int create_partitions(struct stm32prog_data *data) + { + int offset = 0; +- char cmdbuf[32]; +- char buf[ENV_BUF_LEN]; ++ const int buflen = SZ_8K; ++ char *buf; + char uuid[UUID_STR_LEN + 1]; + unsigned char *uuid_bin; + unsigned int mmc_id; +@@ -851,6 +851,10 @@ static int create_partitions(struct stm32prog_data *data) + bool rootfs_found; + struct stm32prog_part_t *part; + ++ buf = malloc(buflen); ++ if (!buf) ++ return -ENOMEM; ++ + puts("partitions : "); + /* initialize the selected device */ + for (i = 0; i < data->dev_nb; i++) { +@@ -860,7 +864,7 @@ static int create_partitions(struct stm32prog_data *data) + + offset = 0; + rootfs_found = false; +- memset(buf, 0, sizeof(buf)); ++ memset(buf, 0, buflen); + + list_for_each_entry(part, &data->dev[i].part_list, list) { + /* skip eMMC boot partitions */ +@@ -871,7 +875,17 @@ static int create_partitions(struct stm32prog_data *data) + if (part->part_type == RAW_IMAGE) + continue; + +- offset += snprintf(buf + offset, ENV_BUF_LEN - offset, ++ if (offset + 100 > buflen) { ++ pr_debug("\n%s: buffer too small, %s skippped", ++ __func__, part->name); ++ continue; ++ } ++ ++ if (!offset) ++ offset += sprintf(buf, "gpt write mmc %d \"", ++ data->dev[i].dev_id); ++ ++ offset += snprintf(buf + offset, buflen - offset, + "name=%s,start=0x%llx,size=0x%llx", + part->name, + part->addr, +@@ -879,17 +893,17 @@ static int create_partitions(struct stm32prog_data *data) + + if (part->part_type == PART_BINARY) + offset += snprintf(buf + offset, +- ENV_BUF_LEN - offset, ++ buflen - offset, + ",type=" + LINUX_RESERVED_UUID); + else + offset += snprintf(buf + offset, +- ENV_BUF_LEN - offset, ++ buflen - offset, + ",type=linux"); + + if (part->part_type == PART_SYSTEM) + offset += snprintf(buf + offset, +- ENV_BUF_LEN - offset, ++ buflen - offset, + ",bootable"); + + if (!rootfs_found && !strcmp(part->name, "rootfs")) { +@@ -901,23 +915,21 @@ static int create_partitions(struct stm32prog_data *data) + uuid_bin_to_str(uuid_bin, uuid, + UUID_STR_FORMAT_GUID); + offset += snprintf(buf + offset, +- ENV_BUF_LEN - offset, ++ buflen - offset, + ",uuid=%s", uuid); + } + } + +- offset += snprintf(buf + offset, +- ENV_BUF_LEN - offset, +- ";"); ++ offset += snprintf(buf + offset, buflen - offset, ";"); + } + + if (offset) { +- sprintf(cmdbuf, "gpt write mmc %d \"%s\"", +- data->dev[i].dev_id, buf); +- pr_debug("cmd: %s\n", cmdbuf); +- if (run_command(cmdbuf, 0)) { +- stm32prog_err("partitionning fail : %s", +- cmdbuf); ++ offset += snprintf(buf + offset, buflen - offset, "\""); ++ pr_debug("\ncmd: %s\n", buf); ++ if (run_command(buf, 0)) { ++ stm32prog_err("partitionning fail : %s", buf); ++ free(buf); ++ + return -1; + } + } +@@ -926,21 +938,21 @@ static int create_partitions(struct stm32prog_data *data) + part_init(data->dev[i].block_dev); + + #ifdef DEBUG +- sprintf(cmdbuf, "gpt verify mmc %d", +- data->dev[i].dev_id); +- pr_debug("cmd: %s ", cmdbuf); +- if (run_command(cmdbuf, 0)) ++ sprintf(buf, "gpt verify mmc %d", data->dev[i].dev_id); ++ pr_debug("\ncmd: %s", buf); ++ if (run_command(buf, 0)) + printf("fail !\n"); + else + printf("OK\n"); + + /* TEMP : for debug, display partition */ +- sprintf(cmdbuf, "part list mmc %d", +- data->dev[i].dev_id); +- run_command(cmdbuf, 0); ++ sprintf(buf, "part list mmc %d", data->dev[i].dev_id); ++ run_command(buf, 0); + #endif + } + puts("done\n"); ++ free(buf); ++ + return 0; + } + +@@ -952,7 +964,7 @@ static int stm32prog_alt_add(struct stm32prog_data *data, + int offset = 0; + char devstr[4]; + char dfustr[10]; +- char buf[ENV_BUF_LEN]; ++ char buf[ALT_BUF_LEN]; + u32 size; + char multiplier, type; + +@@ -973,7 +985,7 @@ static int stm32prog_alt_add(struct stm32prog_data *data, + type = 'a';/*Readable*/ + + memset(buf, 0, sizeof(buf)); +- offset = snprintf(buf, ENV_BUF_LEN - offset, ++ offset = snprintf(buf, ALT_BUF_LEN - offset, + "@%s/0x%02x/1*%d%c%c ", + part->name, part->id, + size, multiplier, type); +@@ -985,29 +997,29 @@ static int stm32prog_alt_add(struct stm32prog_data *data, + dfu_size = part->size / part->dev->lba_blk_size; + else + dfu_size = part->size; +- offset += snprintf(buf + offset, ENV_BUF_LEN - offset, ++ offset += snprintf(buf + offset, ALT_BUF_LEN - offset, + "raw 0x0 0x%llx", dfu_size); + } else if (part->part_id < 0) { + u64 nb_blk = part->size / part->dev->lba_blk_size; + + /* lba_blk_size, mmc->read_bl_len */ +- offset += snprintf(buf + offset, ENV_BUF_LEN - offset, ++ offset += snprintf(buf + offset, ALT_BUF_LEN - offset, + "raw 0x%llx 0x%llx", + part->addr, nb_blk); +- offset += snprintf(buf + offset, ENV_BUF_LEN - offset, ++ offset += snprintf(buf + offset, ALT_BUF_LEN - offset, + " mmcpart %d;", -(part->part_id)); + } else { + if (part->part_type == PART_SYSTEM && + (part->dev_type == DFU_DEV_NAND || + part->dev_type == DFU_DEV_SF)) + offset += snprintf(buf + offset, +- ENV_BUF_LEN - offset, ++ ALT_BUF_LEN - offset, + "partubi"); + else + offset += snprintf(buf + offset, +- ENV_BUF_LEN - offset, ++ ALT_BUF_LEN - offset, + "part"); +- offset += snprintf(buf + offset, ENV_BUF_LEN - offset, ++ offset += snprintf(buf + offset, ALT_BUF_LEN - offset, + " %d %d;", + part->dev_id, + part->part_id); +@@ -1041,7 +1053,7 @@ static int stm32prog_alt_add_virt(struct dfu_entity *dfu, + { + int ret = 0; + char devstr[4]; +- char buf[ENV_BUF_LEN]; ++ char buf[ALT_BUF_LEN]; + + sprintf(devstr, "%d", phase); + sprintf(buf, "@%s/0x%02x/1*%dBe", name, phase, size); +@@ -1100,7 +1112,7 @@ static int dfu_init_entities(struct stm32prog_data *data) + ret = stm32prog_alt_add(data, dfu, part); + } + } else { +- char buf[ENV_BUF_LEN]; ++ char buf[ALT_BUF_LEN]; + + sprintf(buf, "@FlashLayout/0x%02x/1*256Ke ram %x 40000", + PHASE_FLASHLAYOUT, STM32_DDR_BASE); +diff --git a/arch/arm/mach-stm32mp/cpu.c b/arch/arm/mach-stm32mp/cpu.c +index efe8b79..5d43f0b 100644 +--- a/arch/arm/mach-stm32mp/cpu.c ++++ b/arch/arm/mach-stm32mp/cpu.c +@@ -291,18 +291,36 @@ int print_cpuinfo(void) + + /* MPUs Part Numbers */ + switch (get_cpu_type()) { ++ case CPU_STM32MP157Fxx: ++ cpu_s = "157F"; ++ break; ++ case CPU_STM32MP157Dxx: ++ cpu_s = "157D"; ++ break; + case CPU_STM32MP157Cxx: + cpu_s = "157C"; + break; + case CPU_STM32MP157Axx: + cpu_s = "157A"; + break; ++ case CPU_STM32MP153Fxx: ++ cpu_s = "153F"; ++ break; ++ case CPU_STM32MP153Dxx: ++ cpu_s = "153D"; ++ break; + case CPU_STM32MP153Cxx: + cpu_s = "153C"; + break; + case CPU_STM32MP153Axx: + cpu_s = "153A"; + break; ++ case CPU_STM32MP151Fxx: ++ cpu_s = "151F"; ++ break; ++ case CPU_STM32MP151Dxx: ++ cpu_s = "151D"; ++ break; + case CPU_STM32MP151Cxx: + cpu_s = "151C"; + break; +@@ -341,6 +359,9 @@ int print_cpuinfo(void) + case CPU_REVB: + cpu_r = "B"; + break; ++ case CPU_REVZ: ++ cpu_r = "Z"; ++ break; + default: + cpu_r = "?"; + break; +diff --git a/arch/arm/mach-stm32mp/include/mach/ddr.h b/arch/arm/mach-stm32mp/include/mach/ddr.h +index b8a17cf..bfc42a7 100644 +--- a/arch/arm/mach-stm32mp/include/mach/ddr.h ++++ b/arch/arm/mach-stm32mp/include/mach/ddr.h +@@ -9,8 +9,10 @@ + /* DDR power initializations */ + enum ddr_type { + STM32MP_DDR3, +- STM32MP_LPDDR2, +- STM32MP_LPDDR3, ++ STM32MP_LPDDR2_16, ++ STM32MP_LPDDR2_32, ++ STM32MP_LPDDR3_16, ++ STM32MP_LPDDR3_32, + }; + + int board_ddr_power_init(enum ddr_type ddr_type); +diff --git a/arch/arm/mach-stm32mp/include/mach/stm32.h b/arch/arm/mach-stm32mp/include/mach/stm32.h +index 5283e90..70fb235 100644 +--- a/arch/arm/mach-stm32mp/include/mach/stm32.h ++++ b/arch/arm/mach-stm32mp/include/mach/stm32.h +@@ -96,6 +96,7 @@ enum boot_device { + #define TAMP_BACKUP_MAGIC_NUMBER TAMP_BACKUP_REGISTER(4) + #define TAMP_BACKUP_BRANCH_ADDRESS TAMP_BACKUP_REGISTER(5) + /* non secure access */ ++#define TAMP_COPRO_RSC_TBL_ADDRESS TAMP_BACKUP_REGISTER(17) + #define TAMP_BOOT_CONTEXT TAMP_BACKUP_REGISTER(20) + #define TAMP_BOOTCOUNT TAMP_BACKUP_REGISTER(21) + +diff --git a/arch/arm/mach-stm32mp/include/mach/sys_proto.h b/arch/arm/mach-stm32mp/include/mach/sys_proto.h +index 871324b..0ede1e7 100644 +--- a/arch/arm/mach-stm32mp/include/mach/sys_proto.h ++++ b/arch/arm/mach-stm32mp/include/mach/sys_proto.h +@@ -3,19 +3,26 @@ + * Copyright (C) 2015-2017, STMicroelectronics - All Rights Reserved + */ + +-/* ID = Device Version (bit31:16) + Device Part Number (RPN) (bit15:0)*/ ++/* ID = Device Version (bit31:16) + Device Part Number (RPN) (bit7:0) */ + #define CPU_STM32MP157Cxx 0x05000000 + #define CPU_STM32MP157Axx 0x05000001 + #define CPU_STM32MP153Cxx 0x05000024 + #define CPU_STM32MP153Axx 0x05000025 + #define CPU_STM32MP151Cxx 0x0500002E + #define CPU_STM32MP151Axx 0x0500002F ++#define CPU_STM32MP157Fxx 0x05000080 ++#define CPU_STM32MP157Dxx 0x05000081 ++#define CPU_STM32MP153Fxx 0x050000A4 ++#define CPU_STM32MP153Dxx 0x050000A5 ++#define CPU_STM32MP151Fxx 0x050000AE ++#define CPU_STM32MP151Dxx 0x050000AF + + /* return CPU_STMP32MP...Xxx constants */ + u32 get_cpu_type(void); + + #define CPU_REVA 0x1000 + #define CPU_REVB 0x2000 ++#define CPU_REVZ 0x2001 + + /* return CPU_REV constants */ + u32 get_cpu_rev(void); +@@ -32,3 +39,7 @@ u32 get_cpu_package(void); + u32 get_bootmode(void); + /* start IWDG watchdog */ + int watchdog_start(void); ++ ++/* board power management : configure vddcore according OPP */ ++void board_vddcore_init(u32 voltage_mv); ++int board_vddcore_set(void); +diff --git a/arch/arm/mach-stm32mp/spl.c b/arch/arm/mach-stm32mp/spl.c +index 6c8744f..74b56f9 100644 +--- a/arch/arm/mach-stm32mp/spl.c ++++ b/arch/arm/mach-stm32mp/spl.c +@@ -85,42 +85,49 @@ void spl_display_print(void) + } + #endif + ++__weak int board_vddcore_set(void) ++{ ++ return 0; ++} ++ + void board_init_f(ulong dummy) + { + struct udevice *dev; +- int ret; ++ int ret, clk, reset, pinctrl, power; + + arch_cpu_init(); + + ret = spl_early_init(); + if (ret) { +- debug("spl_early_init() failed: %d\n", ret); ++ debug("%s: spl_early_init() failed: %d\n", __func__, ret); + hang(); + } + +- ret = uclass_get_device(UCLASS_CLK, 0, &dev); +- if (ret) { +- debug("Clock init failed: %d\n", ret); +- return; +- } ++ clk = uclass_get_device(UCLASS_CLK, 0, &dev); ++ if (clk) ++ debug("%s: Clock init failed: %d\n", __func__, clk); + +- ret = uclass_get_device(UCLASS_RESET, 0, &dev); +- if (ret) { +- debug("Reset init failed: %d\n", ret); +- return; +- } ++ reset = uclass_get_device(UCLASS_RESET, 0, &dev); ++ if (reset) ++ debug("%s: Reset init failed: %d\n", __func__, reset); + +- ret = uclass_get_device(UCLASS_PINCTRL, 0, &dev); +- if (ret) { +- debug("%s: Cannot find pinctrl device\n", __func__); +- return; +- } ++ pinctrl = uclass_get_device(UCLASS_PINCTRL, 0, &dev); ++ if (pinctrl) ++ debug("%s: Cannot find pinctrl device: %d\n", ++ __func__, pinctrl); + + /* enable console uart printing */ + preloader_console_init(); + + watchdog_start(); + ++ /* change vddcore if needed after clock tree init */ ++ power = board_vddcore_set(); ++ ++ if (clk || reset || pinctrl || power) ++ printf("%s: probe failed clk=%d reset=%d pinctrl=%d power=%d\n", ++ __func__, clk, reset, pinctrl, power); ++ + ret = uclass_get_device(UCLASS_RAM, 0, &dev); + if (ret) { + printf("DRAM init failed: %d\n", ret); +diff --git a/arch/arm/mach-stm32mp/stm32mp1_helper_dbg.S b/arch/arm/mach-stm32mp/stm32mp1_helper_dbg.S +index 37a1b06..d17a37a 100644 +--- a/arch/arm/mach-stm32mp/stm32mp1_helper_dbg.S ++++ b/arch/arm/mach-stm32mp/stm32mp1_helper_dbg.S +@@ -10,6 +10,9 @@ + * fixes the limitation. Anyway, this source code identifies the Soc revision + * and is only executed if it corresponds, so it can be kept on other + * revisions without any consequence. ++ * The revisions that need the workaround have ID values: ++ * - 0x2000X500 ++ * - 0x2001X500 + ****************************************************************************/ + + #include +@@ -30,7 +33,7 @@ + #define PWR_CR1_DBP BIT(8) + + #define DBGMCU_IDC_ADDR 0x50081000 +-#define DBGMCU_IDC_MASK 0xFFFF0FFF ++#define DBGMCU_IDC_MASK 0xFFFE0FFF + #define DBGMCU_IDC_VALUE 0x20000500 + + #define TAMP_BKP_REGISTER_20 (0x5C00A100 + (20 << 2)) +-- +2.7.4 + diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/0015-ARM-v2018.11-stm32mp-r4-BOARD.patch b/recipes-bsp/u-boot/u-boot-stm32mp/0015-ARM-v2018.11-stm32mp-r4-BOARD.patch new file mode 100644 index 0000000..5f8eb7b --- /dev/null +++ b/recipes-bsp/u-boot/u-boot-stm32mp/0015-ARM-v2018.11-stm32mp-r4-BOARD.patch @@ -0,0 +1,255 @@ +From 74c58d9ed7af723b31a4f9d3725afcce9fde1ca4 Mon Sep 17 00:00:00 2001 +From: Romuald JEANNE +Date: Thu, 30 Jan 2020 14:56:24 +0100 +Subject: [PATCH 15/17] ARM v2018.11 stm32mp r4 BOARD + +--- + board/st/stm32mp1/Kconfig | 4 ++++ + board/st/stm32mp1/README | 21 ++++++++++++++-- + board/st/stm32mp1/board.c | 57 ++++++++++++++++++++++++++++++++++++++++---- + board/st/stm32mp1/stm32mp1.c | 36 +++++++++++++--------------- + 4 files changed, 92 insertions(+), 26 deletions(-) + +diff --git a/board/st/stm32mp1/Kconfig b/board/st/stm32mp1/Kconfig +index 92d8f90..6a06e5b 100644 +--- a/board/st/stm32mp1/Kconfig ++++ b/board/st/stm32mp1/Kconfig +@@ -16,4 +16,8 @@ config CMD_STBOARD + This compile the stboard command to + read and write the board in the OTP. + ++config TARGET_STM32MP157C_DK2 ++ bool "support of STMicroelectronics STM32MP157C-DK2 Discovery Board" ++ default y ++ + endif +diff --git a/board/st/stm32mp1/README b/board/st/stm32mp1/README +index b710602..782b9d18 100644 +--- a/board/st/stm32mp1/README ++++ b/board/st/stm32mp1/README +@@ -305,7 +305,20 @@ Mac id storage and retrieval in stm32mp otp : + To program a MAC address on virgin OTP words above, you can use the fuse command + on bank 0 to access to internal OTP: + +- example to set mac address "12:34:56:78:9a:bc" ++ Prerequisite: check if a MAC address isn't yet programmed in OTP ++ ++ 1- check OTP: their value must be equal to 0 ++ ++ STM32MP> fuse sense 0 57 2 ++ Sensing bank 0: ++ Word 0x00000039: 00000000 00000000 ++ ++ 2- check environment variable ++ ++ STM32MP> env print ethaddr ++ ## Error: "ethaddr" not defined ++ ++ Example to set mac address "12:34:56:78:9a:bc" + + 1- Write OTP + STM32MP> fuse prog -y 0 57 0x78563412 0x0000bc9a +@@ -319,9 +332,13 @@ on bank 0 to access to internal OTP: + ### Setting environment from OTP MAC address = "12:34:56:78:9a:bc" + + 4 check env update +- STM32MP> print ethaddr ++ STM32MP> env print ethaddr + ethaddr=12:34:56:78:9a:bc + ++warning:: This MAC address provisioning can't be executed twice on the same ++ board as the OTP are protected. It is already done for the board ++ provided by STMicroelectronics. ++ + 10. Coprocessor firmware + ======================== + +diff --git a/board/st/stm32mp1/board.c b/board/st/stm32mp1/board.c +index c3d832f..3e38aef 100644 +--- a/board/st/stm32mp1/board.c ++++ b/board/st/stm32mp1/board.c +@@ -38,11 +38,46 @@ void board_debug_uart_init(void) + #endif + + #ifdef CONFIG_PMIC_STPMIC1 ++u32 opp_voltage_mv; ++ ++void board_vddcore_init(u32 voltage_mv) ++{ ++ opp_voltage_mv = voltage_mv; ++} ++ ++int board_vddcore_set(void) ++{ ++ struct udevice *dev; ++ int ret; ++ u32 value; ++ ++ if (!opp_voltage_mv) ++ return 0; ++ ++ ret = uclass_get_device_by_driver(UCLASS_PMIC, ++ DM_GET_DRIVER(pmic_stpmic1), &dev); ++ if (ret) ++ return ret; ++ ++ /* VDDCORE= STMPCI1 BUCK1 ramp=+25mV, 5 => 725mV, 36 => 1500mV */ ++ value = ((opp_voltage_mv - 725) / 25) + 5; ++ if (value < 5) ++ value = 5; ++ if (value > 36) ++ value = 36; ++ ++ return pmic_clrsetbits(dev, ++ STPMIC1_BUCKX_MAIN_CR(STPMIC1_BUCK1), ++ STPMIC1_BUCK_VOUT_MASK, ++ STPMIC1_BUCK_VOUT(value)); ++} ++ + int board_ddr_power_init(enum ddr_type ddr_type) + { + struct udevice *dev; + bool buck3_at_1800000v = false; + int ret; ++ u32 buck2; + + ret = uclass_get_device_by_driver(UCLASS_PMIC, + DM_GET_DRIVER(pmic_stpmic1), &dev); +@@ -102,8 +137,10 @@ int board_ddr_power_init(enum ddr_type ddr_type) + + break; + +- case STM32MP_LPDDR2: +- case STM32MP_LPDDR3: ++ case STM32MP_LPDDR2_16: ++ case STM32MP_LPDDR2_32: ++ case STM32MP_LPDDR3_16: ++ case STM32MP_LPDDR3_32: + /* + * configure VDD_DDR1 = LDO3 + * Set LDO3 to 1.8V +@@ -133,11 +170,23 @@ int board_ddr_power_init(enum ddr_type ddr_type) + if (ret < 0) + return ret; + +- /* VDD_DDR2 : Set BUCK2 to 1.2V */ ++ /* VDD_DDR2 : Set BUCK2 to 1.2V (16bits) or 1.25V (32 bits)*/ ++ switch (ddr_type) { ++ case STM32MP_LPDDR2_32: ++ case STM32MP_LPDDR3_32: ++ buck2 = STPMIC1_BUCK2_1250000V; ++ break; ++ default: ++ case STM32MP_LPDDR2_16: ++ case STM32MP_LPDDR3_16: ++ buck2 = STPMIC1_BUCK2_1200000V; ++ break; ++ } ++ + ret = pmic_clrsetbits(dev, + STPMIC1_BUCKX_MAIN_CR(STPMIC1_BUCK2), + STPMIC1_BUCK_VOUT_MASK, +- STPMIC1_BUCK2_1200000V); ++ buck2); + if (ret < 0) + return ret; + +diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c +index f852b1e..822b6d7 100644 +--- a/board/st/stm32mp1/stm32mp1.c ++++ b/board/st/stm32mp1/stm32mp1.c +@@ -388,10 +388,15 @@ int g_dnl_board_usb_cable_connected(void) + } + + #define STM32MP1_G_DNL_DFU_PRODUCT_NUM 0xdf11 ++#define STM32MP1_G_DNL_FASTBOOT_PRODUCT_NUM 0x0afb ++ + int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name) + { + if (!strcmp(name, "usb_dnl_dfu")) + put_unaligned(STM32MP1_G_DNL_DFU_PRODUCT_NUM, &dev->idProduct); ++ else if (!strcmp(name, "usb_dnl_fastboot")) ++ put_unaligned(STM32MP1_G_DNL_FASTBOOT_PRODUCT_NUM, ++ &dev->idProduct); + else + put_unaligned(CONFIG_USB_GADGET_PRODUCT_NUM, &dev->idProduct); + +@@ -517,6 +522,7 @@ static void __maybe_unused led_error_blink(u32 nb_blink) + mdelay(125); + WATCHDOG_RESET(); + } ++ led_set_state(led, LEDST_ON); + } + #endif + +@@ -876,7 +882,8 @@ const char *env_ext4_get_dev_part(void) + + static __maybe_unused bool board_is_dk2(void) + { +- if (of_machine_is_compatible("st,stm32mp157c-dk2")) ++ if (CONFIG_IS_ENABLED(TARGET_STM32MP157C_DK2) && ++ of_machine_is_compatible("st,stm32mp157c-dk2")) + return true; + + return false; +@@ -1079,9 +1086,7 @@ void board_mtdparts_default(const char **mtdids, const char **mtdparts) + #if defined(CONFIG_OF_BOARD_SETUP) + int ft_board_setup(void *blob, bd_t *bd) + { +- ulong copro_rsc_addr, copro_rsc_size; + int off; +- char *s_copro = NULL; + #ifdef CONFIG_FDT_FIXUP_PARTITIONS + struct node_info nodes[] = { + { "st,stm32f469-qspi", MTD_DEV_TYPE_NOR, }, +@@ -1093,20 +1098,11 @@ int ft_board_setup(void *blob, bd_t *bd) + /* Update DT if coprocessor started */ + off = fdt_path_offset(blob, "/m4"); + if (off > 0) { +- s_copro = env_get("copro_state"); +- copro_rsc_addr = env_get_hex("copro_rsc_addr", 0); +- copro_rsc_size = env_get_hex("copro_rsc_size", 0); +- +- if (s_copro) { ++ if (env_get("copro_state")) { + fdt_setprop_empty(blob, off, "early-booted"); +- if (copro_rsc_addr) +- fdt_setprop_u32(blob, off, "rsc-address", +- copro_rsc_addr); +- if (copro_rsc_size) +- fdt_setprop_u32(blob, off, "rsc-size", +- copro_rsc_size); + } else { + fdt_delprop(blob, off, "early-booted"); ++ writel(0, TAMP_COPRO_RSC_TBL_ADDRESS); + } + } + +@@ -1128,18 +1124,18 @@ static void board_stm32copro_image_process(ulong fw_image, size_t fw_size) + } + + ret = rproc_load_rsc_table(id, fw_image, fw_size, &rsc_addr, &rsc_size); +- if (!ret) { +- env_set_hex("copro_rsc_addr", rsc_addr); +- env_set_hex("copro_rsc_size", rsc_size); +- } ++ if (ret && ret != -ENODATA) ++ return; + + ret = rproc_load(id, fw_image, fw_size); + printf("Load Remote Processor %d with data@addr=0x%08lx %u bytes:%s\n", + id, fw_image, fw_size, ret ? " Failed!" : " Success!"); + + if (!ret) { +- rproc_start(id); +- env_set("copro_state", "booted"); ++ ret = rproc_start(id); ++ printf("Start firmware:%s\n", ret ? " Failed!" : " Success!"); ++ if (!ret) ++ env_set("copro_state", "booted"); + } + } + +-- +2.7.4 + diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/0016-ARM-v2018.11-stm32mp-r4-DEVICETREE.patch b/recipes-bsp/u-boot/u-boot-stm32mp/0016-ARM-v2018.11-stm32mp-r4-DEVICETREE.patch new file mode 100644 index 0000000..bc0c041 --- /dev/null +++ b/recipes-bsp/u-boot/u-boot-stm32mp/0016-ARM-v2018.11-stm32mp-r4-DEVICETREE.patch @@ -0,0 +1,1191 @@ +From 6220cbc776b6bfb9d88646eb98dc4f928e05374b Mon Sep 17 00:00:00 2001 +From: Romuald JEANNE +Date: Thu, 30 Jan 2020 14:57:26 +0100 +Subject: [PATCH 16/17] ARM v2018.11 stm32mp r4 DEVICETREE + +--- + arch/arm/dts/stm32mp157-u-boot.dtsi | 12 +- + arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi | 7 - + arch/arm/dts/stm32mp157a-dk1.dts | 33 +- + arch/arm/dts/stm32mp157c-dk2.dts | 4 +- + arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi | 7 - + arch/arm/dts/stm32mp157c-ed1.dts | 25 +- + arch/arm/dts/stm32mp157c-ev1.dts | 8 +- + arch/arm/dts/stm32mp157c-m4-srm.dtsi | 525 +++++++++++++++++++++++++ + arch/arm/dts/stm32mp157c.dtsi | 109 +++-- + doc/device-tree-bindings/clock/st,stm32mp1.txt | 4 + + include/dt-bindings/mfd/st,stpmic1.h | 4 + + include/dt-bindings/pinctrl/stm32-pinfunc.h | 1 + + 12 files changed, 673 insertions(+), 66 deletions(-) + +diff --git a/arch/arm/dts/stm32mp157-u-boot.dtsi b/arch/arm/dts/stm32mp157-u-boot.dtsi +index 98cf1aa..1c1a7cc 100644 +--- a/arch/arm/dts/stm32mp157-u-boot.dtsi ++++ b/arch/arm/dts/stm32mp157-u-boot.dtsi +@@ -47,7 +47,7 @@ + }; + + &bsec { +- u-boot,dm-pre-proper; ++ u-boot,dm-pre-reloc; + }; + + &clk_csi { +@@ -70,6 +70,16 @@ + u-boot,dm-pre-reloc; + }; + ++&cpu0_opp_table { ++ u-boot,dm-spl; ++ opp-650000000 { ++ u-boot,dm-spl; ++ }; ++ opp-800000000 { ++ u-boot,dm-spl; ++ }; ++}; ++ + &gpioa { + u-boot,dm-pre-reloc; + }; +diff --git a/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi b/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi +index 757df24..7bc2b7f 100644 +--- a/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi ++++ b/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi +@@ -121,13 +121,6 @@ + CLK_LPTIM45_LSE + >; + +- /* VCO = 1300.0 MHz => P = 650 (CPU) */ +- pll1: st,pll@0 { +- cfg = < 2 80 0 0 0 PQR(1,0,0) >; +- frac = < 0x800 >; +- u-boot,dm-pre-reloc; +- }; +- + /* VCO = 1066.0 MHz => P = 266 (AXI), Q = 533 (GPU), R = 533 (DDR) */ + pll2: st,pll@1 { + cfg = < 2 65 1 0 0 PQR(1,1,1) >; +diff --git a/arch/arm/dts/stm32mp157a-dk1.dts b/arch/arm/dts/stm32mp157a-dk1.dts +index 2b01a01..9ec45de 100644 +--- a/arch/arm/dts/stm32mp157a-dk1.dts ++++ b/arch/arm/dts/stm32mp157a-dk1.dts +@@ -7,8 +7,8 @@ + /dts-v1/; + + #include "stm32mp157c.dtsi" +-#include "stm32mp157c-m4-srm.dtsi" + #include "stm32mp157cac-pinctrl.dtsi" ++#include "stm32mp157c-m4-srm.dtsi" + #include + #include + +@@ -162,6 +162,14 @@ + status = "okay"; + }; + ++&cpu0{ ++ cpu-supply = <&vddcore>; ++}; ++ ++&cpu1{ ++ cpu-supply = <&vddcore>; ++}; ++ + &dma1 { + sram = <&dma_pool>; + }; +@@ -252,9 +260,6 @@ + reset-gpios = <&gpioa 10 GPIO_ACTIVE_LOW>; + interrupts = <1 IRQ_TYPE_EDGE_FALLING>; + interrupt-parent = <&gpiog>; +- pinctrl-names = "default", "sleep"; +- pinctrl-0 = <<dc_pins_a>; +- pinctrl-1 = <<dc_pins_sleep_a>; + status = "okay"; + + ports { +@@ -284,6 +289,7 @@ + pinctrl-1 = <&i2c4_pins_sleep_a>; + i2c-scl-rising-time-ns = <185>; + i2c-scl-falling-time-ns = <20>; ++ clock-frequency = <400000>; + status = "okay"; + /delete-property/dmas; + /delete-property/dma-names; +@@ -312,10 +318,7 @@ + interrupt-controller; + #interrupt-cells = <2>; + status = "okay"; +- +- st,main-control-register = <0x04>; +- st,vin-control-register = <0xc0>; +- st,usb-control-register = <0x20>; ++ wakeup-source; + + regulators { + compatible = "st,stpmic1-regulators"; +@@ -427,20 +430,20 @@ + vbus_otg: pwr_sw1 { + regulator-name = "vbus_otg"; + interrupts = ; +- regulator-active-discharge; + }; + + vbus_sw: pwr_sw2 { + regulator-name = "vbus_sw"; + interrupts = ; +- regulator-active-discharge; ++ regulator-active-discharge = <1>; + }; + }; + + onkey { + compatible = "st,stpmic1-onkey"; +- interrupts = , ; ++ interrupts = , ; + interrupt-names = "onkey-falling", "onkey-rising"; ++ power-off-time-sec = <10>; + status = "okay"; + }; + +@@ -487,6 +490,9 @@ + }; + + <dc { ++ pinctrl-names = "default", "sleep"; ++ pinctrl-0 = <<dc_pins_a>; ++ pinctrl-1 = <<dc_pins_sleep_a>; + status = "okay"; + + port { +@@ -703,6 +709,8 @@ + pinctrl-1 = <&uart4_sleep_pins_a>; + pinctrl-2 = <&uart4_idle_pins_a>; + pinctrl-3 = <&uart4_pins_a>; ++ /delete-property/dmas; ++ /delete-property/dma-names; + status = "okay"; + }; + +@@ -711,6 +719,8 @@ + pinctrl-0 = <&uart7_pins_a>; + pinctrl-1 = <&uart7_sleep_pins_a>; + pinctrl-2 = <&uart7_idle_pins_a>; ++ /delete-property/dmas; ++ /delete-property/dma-names; + status = "disabled"; + }; + +@@ -719,6 +729,7 @@ + pinctrl-0 = <&usart3_pins_b>; + pinctrl-1 = <&usart3_sleep_pins_b>; + pinctrl-2 = <&usart3_idle_pins_b>; ++ st,hw-flow-ctrl; + status = "disabled"; + }; + +diff --git a/arch/arm/dts/stm32mp157c-dk2.dts b/arch/arm/dts/stm32mp157c-dk2.dts +index d11fbb8..5523dc3 100644 +--- a/arch/arm/dts/stm32mp157c-dk2.dts ++++ b/arch/arm/dts/stm32mp157c-dk2.dts +@@ -47,7 +47,7 @@ + }; + }; + +- panel@0 { ++ panel: panel@0 { + compatible = "orisetech,otm8009a"; + reg = <0>; + reset-gpios = <&gpioe 4 GPIO_ACTIVE_LOW>; +@@ -71,6 +71,7 @@ + interrupt-controller; + touchscreen-size-x = <480>; + touchscreen-size-y = <800>; ++ panel = <&panel>; + status = "okay"; + }; + touchscreen@38 { +@@ -81,6 +82,7 @@ + interrupt-controller; + touchscreen-size-x = <480>; + touchscreen-size-y = <800>; ++ panel = <&panel>; + status = "okay"; + }; + }; +diff --git a/arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi b/arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi +index 5ab4eeb..898155f 100644 +--- a/arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi ++++ b/arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi +@@ -119,13 +119,6 @@ + CLK_LPTIM45_LSE + >; + +- /* VCO = 1300.0 MHz => P = 650 (CPU) */ +- pll1: st,pll@0 { +- cfg = < 2 80 0 0 0 PQR(1,0,0) >; +- frac = < 0x800 >; +- u-boot,dm-pre-reloc; +- }; +- + /* VCO = 1066.0 MHz => P = 266 (AXI), Q = 533 (GPU), R = 533 (DDR) */ + pll2: st,pll@1 { + cfg = < 2 65 1 0 0 PQR(1,1,1) >; +diff --git a/arch/arm/dts/stm32mp157c-ed1.dts b/arch/arm/dts/stm32mp157c-ed1.dts +index c9eabc1..f5e685d 100644 +--- a/arch/arm/dts/stm32mp157c-ed1.dts ++++ b/arch/arm/dts/stm32mp157c-ed1.dts +@@ -6,8 +6,8 @@ + /dts-v1/; + + #include "stm32mp157c.dtsi" +-#include "stm32mp157c-m4-srm.dtsi" + #include "stm32mp157caa-pinctrl.dtsi" ++#include "stm32mp157c-m4-srm.dtsi" + #include + + / { +@@ -137,6 +137,14 @@ + }; + }; + ++&cpu0{ ++ cpu-supply = <&vddcore>; ++}; ++ ++&cpu1{ ++ cpu-supply = <&vddcore>; ++}; ++ + &dac { + pinctrl-names = "default"; + pinctrl-0 = <&dac_ch1_pins_a &dac_ch2_pins_a>; +@@ -173,6 +181,7 @@ + pinctrl-1 = <&i2c4_pins_sleep_a>; + i2c-scl-rising-time-ns = <185>; + i2c-scl-falling-time-ns = <20>; ++ clock-frequency = <400000>; + status = "okay"; + /delete-property/dmas; + /delete-property/dma-names; +@@ -184,14 +193,10 @@ + interrupt-controller; + #interrupt-cells = <2>; + status = "okay"; +- +- st,main-control-register = <0x04>; +- st,vin-control-register = <0xc0>; +- st,usb-control-register = <0x20>; ++ wakeup-source; + + regulators { + compatible = "st,stpmic1-regulators"; +- + ldo1-supply = <&v3v3>; + ldo2-supply = <&v3v3>; + ldo3-supply = <&vdd_ddr>; +@@ -295,20 +300,20 @@ + vbus_otg: pwr_sw1 { + regulator-name = "vbus_otg"; + interrupts = ; +- regulator-active-discharge; + }; + + vbus_sw: pwr_sw2 { + regulator-name = "vbus_sw"; + interrupts = ; +- regulator-active-discharge; ++ regulator-active-discharge = <1>; + }; + }; + + onkey { + compatible = "st,stpmic1-onkey"; +- interrupts = , ; ++ interrupts = , ; + interrupt-names = "onkey-falling", "onkey-rising"; ++ power-off-time-sec = <10>; + status = "okay"; + }; + +@@ -408,6 +413,8 @@ + pinctrl-1 = <&uart4_sleep_pins_a>; + pinctrl-2 = <&uart4_idle_pins_a>; + pinctrl-3 = <&uart4_pins_a>; ++ /delete-property/dmas; ++ /delete-property/dma-names; + status = "okay"; + }; + +diff --git a/arch/arm/dts/stm32mp157c-ev1.dts b/arch/arm/dts/stm32mp157c-ev1.dts +index 559b9b9..7323f40 100644 +--- a/arch/arm/dts/stm32mp157c-ev1.dts ++++ b/arch/arm/dts/stm32mp157c-ev1.dts +@@ -98,7 +98,7 @@ + }; + }; + +- sound { ++ sound: sound { + compatible = "audio-graph-card"; + label = "STM32MP1-EV"; + routing = +@@ -325,7 +325,7 @@ + }; + }; + +- panel-dsi@0 { ++ panel_dsi: panel-dsi@0 { + compatible = "raydium,rm68200"; + reg = <0>; + reset-gpios = <&gpiof 15 GPIO_ACTIVE_LOW>; +@@ -495,6 +495,7 @@ + gt9147: goodix_ts@5d { + compatible = "goodix,gt9147"; + reg = <0x5d>; ++ panel = <&panel_dsi>; + status = "okay"; + + irq-gpios = <&stmfx_pinctrl 14 GPIO_ACTIVE_HIGH>; +@@ -649,7 +650,7 @@ + &spdifrx { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&spdifrx_pins_a>; +- pinctrl-1 = <&spdifrx_sleep_pins_a>; ++ pinctrl-1 = <&spdifrx_pins_a>; + status = "okay"; + + spdifrx_port: port { +@@ -717,6 +718,7 @@ + pinctrl-0 = <&usart3_pins_a>; + pinctrl-1 = <&usart3_sleep_pins_a>; + pinctrl-2 = <&usart3_idle_pins_a>; ++ st,hw-flow-ctrl; + status = "disabled"; + }; + +diff --git a/arch/arm/dts/stm32mp157c-m4-srm.dtsi b/arch/arm/dts/stm32mp157c-m4-srm.dtsi +index 9ea9736..4d641a9 100644 +--- a/arch/arm/dts/stm32mp157c-m4-srm.dtsi ++++ b/arch/arm/dts/stm32mp157c-m4-srm.dtsi +@@ -1,3 +1,528 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved ++ * Author: Fabien Dessenne for STMicroelectronics. ++ */ ++ ++&pinctrl { ++ m4_adc1_in6_pins_a: m4-adc1-in6 { ++ pins { ++ pinmux = ; ++ }; ++ }; ++ ++ m4_adc12_ain_pins_a: m4-adc12-ain-0 { ++ pins { ++ pinmux = , /* ADC1 in13 */ ++ , /* ADC1 in6 */ ++ , /* ADC2 in2 */ ++ ; /* ADC2 in6 */ ++ }; ++ }; ++ ++ m4_adc12_usb_pwr_pins_a: m4-adc12-usb-pwr-pins-0 { ++ pins { ++ pinmux = , /* ADC12 in18 */ ++ ; /* ADC12 in19 */ ++ }; ++ }; ++ ++ m4_cec_pins_a: m4-cec-0 { ++ pins { ++ pinmux = ; ++ }; ++ }; ++ ++ m4_cec_pins_b: m4-cec-1 { ++ pins { ++ pinmux = ; ++ }; ++ }; ++ ++ m4_dac_ch1_pins_a: m4-dac-ch1 { ++ pins { ++ pinmux = ; ++ }; ++ }; ++ ++ m4_dac_ch2_pins_a: m4-dac-ch2 { ++ pins { ++ pinmux = ; ++ }; ++ }; ++ ++ m4_dcmi_pins_a: m4-dcmi-0 { ++ pins { ++ pinmux = ,/* DCMI_HSYNC */ ++ ,/* DCMI_VSYNC */ ++ ,/* DCMI_PIXCLK */ ++ ,/* DCMI_D0 */ ++ ,/* DCMI_D1 */ ++ ,/* DCMI_D2 */ ++ ,/* DCMI_D3 */ ++ ,/* DCMI_D4 */ ++ ,/* DCMI_D5 */ ++ ,/* DCMI_D6 */ ++ ,/* DCMI_D7 */ ++ ,/* DCMI_D8 */ ++ ,/* DCMI_D9 */ ++ ,/* DCMI_D10 */ ++ ;/* DCMI_D11 */ ++ }; ++ }; ++ ++ m4_dfsdm_clkout_pins_a: m4-dfsdm-clkout-pins-0 { ++ pins { ++ pinmux = ; /* DFSDM_CKOUT */ ++ }; ++ }; ++ ++ m4_dfsdm_data1_pins_a: m4-dfsdm-data1-pins-0 { ++ pins { ++ pinmux = ; /* DFSDM_DATA1 */ ++ }; ++ }; ++ ++ m4_dfsdm_data3_pins_a: m4-dfsdm-data3-pins-0 { ++ pins { ++ pinmux = ; /* DFSDM_DATA3 */ ++ }; ++ }; ++ ++ m4_ethernet0_rgmii_pins_a: m4-rgmii-0 { ++ pins { ++ pinmux = , /* ETH_RGMII_CLK125 */ ++ , /* ETH_RGMII_GTX_CLK */ ++ , /* ETH_RGMII_TXD0 */ ++ , /* ETH_RGMII_TXD1 */ ++ , /* ETH_RGMII_TXD2 */ ++ , /* ETH_RGMII_TXD3 */ ++ , /* ETH_RGMII_TX_CTL */ ++ , /* ETH_MDC */ ++ , /* ETH_MDIO */ ++ , /* ETH_RGMII_RXD0 */ ++ , /* ETH_RGMII_RXD1 */ ++ , /* ETH_RGMII_RXD2 */ ++ , /* ETH_RGMII_RXD3 */ ++ , /* ETH_RGMII_RX_CLK */ ++ ; /* ETH_RGMII_RX_CTL */ ++ }; ++ }; ++ ++ m4_fmc_pins_a: m4-fmc-0 { ++ pins { ++ pinmux = , /* FMC_NOE */ ++ , /* FMC_NWE */ ++ , /* FMC_A16_FMC_CLE */ ++ , /* FMC_A17_FMC_ALE */ ++ , /* FMC_D0 */ ++ , /* FMC_D1 */ ++ , /* FMC_D2 */ ++ , /* FMC_D3 */ ++ , /* FMC_D4 */ ++ , /* FMC_D5 */ ++ , /* FMC_D6 */ ++ , /* FMC_D7 */ ++ , /* FMC_NE2_FMC_NCE */ ++ ; /* FMC_NWAIT */ ++ }; ++ }; ++ ++ m4_hdp0_pins_a: m4-hdp0-0 { ++ pins { ++ pinmux = ; /* HDP0 */ ++ }; ++ }; ++ ++ m4_hdp6_pins_a: m4-hdp6-0 { ++ pins { ++ pinmux = ; /* HDP6 */ ++ }; ++ }; ++ ++ m4_hdp7_pins_a: m4-hdp7-0 { ++ pins { ++ pinmux = ; /* HDP7 */ ++ }; ++ }; ++ ++ m4_i2c1_pins_a: m4-i2c1-0 { ++ pins { ++ pinmux = , /* I2C1_SCL */ ++ ; /* I2C1_SDA */ ++ }; ++ }; ++ ++ m4_i2c2_pins_a: m4-i2c2-0 { ++ pins { ++ pinmux = , /* I2C2_SCL */ ++ ; /* I2C2_SDA */ ++ }; ++ }; ++ ++ m4_i2c5_pins_a: m4-i2c5-0 { ++ pins { ++ pinmux = , /* I2C5_SCL */ ++ ; /* I2C5_SDA */ ++ }; ++ }; ++ ++ m4_i2s2_pins_a: m4-i2s2-0 { ++ pins { ++ pinmux = , /* I2S2_SDO */ ++ , /* I2S2_WS */ ++ ; /* I2S2_CK */ ++ }; ++ }; ++ ++ m4_ltdc_pins_a: m4-ltdc-a-0 { ++ pins { ++ pinmux = , /* LCD_CLK */ ++ , /* LCD_HSYNC */ ++ , /* LCD_VSYNC */ ++ , /* LCD_DE */ ++ , /* LCD_R0 */ ++ , /* LCD_R1 */ ++ , /* LCD_R2 */ ++ , /* LCD_R3 */ ++ , /* LCD_R4 */ ++ , /* LCD_R5 */ ++ , /* LCD_R6 */ ++ , /* LCD_R7 */ ++ , /* LCD_G0 */ ++ , /* LCD_G1 */ ++ , /* LCD_G2 */ ++ , /* LCD_G3 */ ++ , /* LCD_G4 */ ++ , /* LCD_G5 */ ++ , /* LCD_G6 */ ++ , /* LCD_G7 */ ++ , /* LCD_B0 */ ++ , /* LCD_B1 */ ++ , /* LCD_B2 */ ++ , /* LCD_B3 */ ++ , /* LCD_B4 */ ++ , /* LCD_B5 */ ++ , /* LCD_B6 */ ++ ; /* LCD_B7 */ ++ }; ++ }; ++ ++ m4_ltdc_pins_b: m4-ltdc-b-0 { ++ pins { ++ pinmux = , /* LCD_CLK */ ++ , /* LCD_HSYNC */ ++ , /* LCD_VSYNC */ ++ , /* LCD_DE */ ++ , /* LCD_R0 */ ++ , /* LCD_R1 */ ++ , /* LCD_R2 */ ++ , /* LCD_R3 */ ++ , /* LCD_R4 */ ++ , /* LCD_R5 */ ++ , /* LCD_R6 */ ++ , /* LCD_R7 */ ++ , /* LCD_G0 */ ++ , /* LCD_G1 */ ++ , /* LCD_G2 */ ++ , /* LCD_G3 */ ++ , /* LCD_G4 */ ++ , /* LCD_G5 */ ++ , /* LCD_G6 */ ++ , /* LCD_G7 */ ++ , /* LCD_B0 */ ++ , /* LCD_B1 */ ++ , /* LCD_B2 */ ++ , /* LCD_B3 */ ++ , /* LCD_B4 */ ++ , /* LCD_B5 */ ++ , /* LCD_B6 */ ++ ; /* LCD_B7 */ ++ }; ++ }; ++ ++ m4_m_can1_pins_a: m4-m-can1-0 { ++ pins { ++ pinmux = , /* CAN1_TX */ ++ ; /* CAN1_RX */ ++ }; ++ }; ++ ++ m4_pwm1_pins_a: m4-pwm1-0 { ++ pins { ++ pinmux = , /* TIM1_CH1 */ ++ , /* TIM1_CH2 */ ++ ; /* TIM1_CH4 */ ++ }; ++ }; ++ ++ m4_pwm2_pins_a: m4-pwm2-0 { ++ pins { ++ pinmux = ; /* TIM2_CH4 */ ++ }; ++ }; ++ ++ m4_pwm3_pins_a: m4-pwm3-0 { ++ pins { ++ pinmux = ; /* TIM3_CH2 */ ++ }; ++ }; ++ ++ m4_pwm4_pins_a: m4-pwm4-0 { ++ pins { ++ pinmux = , /* TIM4_CH3 */ ++ ; /* TIM4_CH4 */ ++ }; ++ }; ++ ++ m4_pwm4_pins_b: m4-pwm4-1 { ++ pins { ++ pinmux = ; /* TIM4_CH2 */ ++ }; ++ }; ++ ++ m4_pwm5_pins_a: m4-pwm5-0 { ++ pins { ++ pinmux = ; /* TIM5_CH2 */ ++ }; ++ }; ++ ++ m4_pwm8_pins_a: m4-pwm8-0 { ++ pins { ++ pinmux = ; /* TIM8_CH4 */ ++ }; ++ }; ++ ++ m4_pwm12_pins_a: m4-pwm12-0 { ++ pins { ++ pinmux = ; /* TIM12_CH1 */ ++ }; ++ }; ++ ++ m4_qspi_bk1_pins_a: m4-qspi-bk1-0 { ++ pins { ++ pinmux = , /* QSPI_BK1_IO0 */ ++ , /* QSPI_BK1_IO1 */ ++ , /* QSPI_BK1_IO2 */ ++ , /* QSPI_BK1_IO3 */ ++ ; /* QSPI_BK1_NCS */ ++ }; ++ }; ++ ++ m4_qspi_bk2_pins_a: m4-qspi-bk2-0 { ++ pins { ++ pinmux = , /* QSPI_BK2_IO0 */ ++ , /* QSPI_BK2_IO1 */ ++ , /* QSPI_BK2_IO2 */ ++ , /* QSPI_BK2_IO3 */ ++ ; /* QSPI_BK2_NCS */ ++ }; ++ }; ++ ++ m4_qspi_clk_pins_a: m4-qspi-clk-0 { ++ pins { ++ pinmux = ; /* QSPI_CLK */ ++ }; ++ }; ++ ++ m4_rtc_out2_rmp_pins_a: m4-rtc-out2-rmp-pins-0 { ++ pins { ++ pinmux = ; /* RTC_OUT2_RMP */ ++ }; ++ }; ++ ++ m4_sai2a_pins_a: m4-sai2a-0 { ++ pins { ++ pinmux = , /* SAI2_SCK_A */ ++ , /* SAI2_SD_A */ ++ , /* SAI2_FS_A */ ++ ; /* SAI2_MCLK_A */ ++ }; ++ }; ++ ++ m4_sai2b_pins_a: m4-sai2b-0 { ++ pins { ++ pinmux = , /* SAI2_SCK_B */ ++ , /* SAI2_FS_B */ ++ , /* SAI2_MCLK_B */ ++ ; /* SAI2_SD_B */ ++ }; ++ }; ++ ++ m4_sai2b_pins_b: m4-sai2b-2 { ++ pins { ++ pinmux = ; /* SAI2_SD_B */ ++ }; ++ }; ++ ++ m4_sai4a_pins_a: m4-sai4a-0 { ++ pins { ++ pinmux = ; /* SAI4_SD_A */ ++ }; ++ }; ++ ++ m4_sdmmc1_b4_pins_a: m4-sdmmc1-b4-0 { ++ pins { ++ pinmux = , /* SDMMC1_D0 */ ++ , /* SDMMC1_D1 */ ++ , /* SDMMC1_D2 */ ++ , /* SDMMC1_D3 */ ++ , /* SDMMC1_CMD */ ++ ; /* SDMMC1_CK */ ++ }; ++ }; ++ ++ m4_sdmmc1_dir_pins_a: m4-sdmmc1-dir-0 { ++ pins { ++ pinmux = , /* SDMMC1_D0DIR */ ++ , /* SDMMC1_D123DIR */ ++ , /* SDMMC1_CDIR */ ++ ; /* SDMMC1_CKIN */ ++ }; ++ }; ++ ++ m4_sdmmc2_b4_pins_a: m4-sdmmc2-b4-0 { ++ pins { ++ pinmux = , /* SDMMC2_D0 */ ++ , /* SDMMC2_D1 */ ++ , /* SDMMC2_D2 */ ++ , /* SDMMC2_D3 */ ++ , /* SDMMC2_CMD */ ++ ; /* SDMMC2_CK */ ++ }; ++ }; ++ ++ m4_sdmmc2_b4_pins_b: m4-sdmmc2-b4-1 { ++ pins { ++ pinmux = , /* SDMMC2_D0 */ ++ , /* SDMMC2_D1 */ ++ , /* SDMMC2_D2 */ ++ , /* SDMMC2_D3 */ ++ , /* SDMMC2_CMD */ ++ ; /* SDMMC2_CK */ ++ }; ++ }; ++ ++ m4_sdmmc2_d47_pins_a: m4-sdmmc2-d47-0 { ++ pins { ++ pinmux = , /* SDMMC2_D4 */ ++ , /* SDMMC2_D5 */ ++ , /* SDMMC2_D6 */ ++ ; /* SDMMC2_D7 */ ++ }; ++ }; ++ ++ m4_sdmmc3_b4_pins_a: m4-sdmmc3-b4-0 { ++ pins { ++ pinmux = , /* SDMMC3_D0 */ ++ , /* SDMMC3_D1 */ ++ , /* SDMMC3_D2 */ ++ , /* SDMMC3_D3 */ ++ , /* SDMMC3_CMD */ ++ ; /* SDMMC3_CK */ ++ }; ++ }; ++ ++ m4_spdifrx_pins_a: m4-spdifrx-0 { ++ pins { ++ pinmux = ; /* SPDIF_IN1 */ ++ }; ++ }; ++ ++ m4_spi4_pins_a: m4-spi4-0 { ++ pins { ++ pinmux = , /* SPI4_SCK */ ++ , /* SPI4_MOSI */ ++ ; /* SPI4_MISO */ ++ }; ++ }; ++ ++ m4_spi5_pins_a: m4-spi5-0 { ++ pins { ++ pinmux = , /* SPI5_SCK */ ++ , /* SPI5_MOSI */ ++ ; /* SPI5_MISO */ ++ }; ++ }; ++ ++ m4_stusb1600_pins_a: m4-stusb1600-0 { ++ pins { ++ pinmux = ; ++ }; ++ }; ++ ++ m4_uart4_pins_a: m4-uart4-0 { ++ pins { ++ pinmux = , /* UART4_TX */ ++ ; /* UART4_RX */ ++ }; ++ }; ++ ++ m4_uart7_pins_a: m4-uart7-0 { ++ pins { ++ pinmux = , /* USART7_TX */ ++ ; /* USART7_RX */ ++ }; ++ }; ++ ++ m4_usart2_pins_a: m4-usart2-0 { ++ pins { ++ pinmux = , /* USART2_TX */ ++ , /* USART2_RTS */ ++ , /* USART2_RX */ ++ ; /* USART2_CTS_NSS */ ++ }; ++ }; ++ ++ m4_usart3_pins_a: m4-usart3-0 { ++ pins { ++ pinmux = , /* USART3_TX */ ++ , /* USART3_RTS */ ++ , /* USART3_RX */ ++ ; /* USART3_CTS_NSS */ ++ }; ++ }; ++ ++ m4_usart3_pins_b: m4-usart3-1 { ++ pins { ++ pinmux = , /* USART3_TX */ ++ , /* USART3_RTS */ ++ , /* USART3_RX */ ++ ; /* USART3_CTS_NSS */ ++ }; ++ }; ++ ++ m4_usbotg_hs_pins_a: m4-usbotg_hs-0 { ++ pins { ++ pinmux = ; /* OTG_ID */ ++ }; ++ }; ++ ++ m4_usbotg_fs_dp_dm_pins_a: m4-usbotg-fs-dp-dm-0 { ++ pins { ++ pinmux = , /* OTG_FS_DM */ ++ ; /* OTG_FS_DP */ ++ }; ++ }; ++}; ++ ++&pinctrl_z { ++ m4_i2c4_pins_a: m4-i2c4-0 { ++ pins { ++ pinmux = , /* I2C4_SCL */ ++ ; /* I2C4_SDA */ ++ }; ++ }; ++ ++ m4_spi1_pins_a: m4-spi1-0 { ++ pins { ++ pinmux = , /* SPI1_SCK */ ++ , /* SPI1_MOSI */ ++ ; /* SPI1_MISO */ ++ }; ++ }; ++}; ++ + &m4_rproc { + m4_system_resources { + #address-cells = <1>; +diff --git a/arch/arm/dts/stm32mp157c.dtsi b/arch/arm/dts/stm32mp157c.dtsi +index c94a1f25..d56e0f9 100644 +--- a/arch/arm/dts/stm32mp157c.dtsi ++++ b/arch/arm/dts/stm32mp157c.dtsi +@@ -20,14 +20,36 @@ + compatible = "arm,cortex-a7"; + device_type = "cpu"; + reg = <0>; +- clock-frequency = <650000000>; ++ clocks = <&rcc CK_MPU>; ++ clock-names = "cpu"; ++ operating-points-v2 = <&cpu0_opp_table>; ++ nvmem-cells = <&part_number_otp>; ++ nvmem-cell-names = "part_number"; + }; + + cpu1: cpu@1 { + compatible = "arm,cortex-a7"; + device_type = "cpu"; + reg = <1>; +- clock-frequency = <650000000>; ++ clocks = <&rcc CK_MPU>; ++ clock-names = "cpu"; ++ operating-points-v2 = <&cpu0_opp_table>; ++ }; ++ }; ++ ++ cpu0_opp_table: cpu0-opp-table { ++ compatible = "operating-points-v2"; ++ opp-shared; ++ ++ opp-650000000 { ++ opp-hz = /bits/ 64 <650000000>; ++ opp-microvolt = <1200000>; ++ opp-supported-hw = <0x1>; ++ }; ++ opp-800000000 { ++ opp-hz = /bits/ 64 <800000000>; ++ opp-microvolt = <1350000>; ++ opp-supported-hw = <0x2>; + }; + }; + +@@ -500,6 +522,9 @@ + resets = <&rcc USART2_R>; + wakeup-source; + power-domains = <&pd_core>; ++ dmas = <&dmamux1 43 0x400 0x21>, ++ <&dmamux1 44 0x400 0x1>; ++ dma-names = "rx", "tx"; + status = "disabled"; + }; + +@@ -513,6 +538,9 @@ + resets = <&rcc USART3_R>; + wakeup-source; + power-domains = <&pd_core>; ++ dmas = <&dmamux1 45 0x400 0x21>, ++ <&dmamux1 46 0x400 0x1>; ++ dma-names = "rx", "tx"; + status = "disabled"; + }; + +@@ -526,6 +554,9 @@ + resets = <&rcc UART4_R>; + wakeup-source; + power-domains = <&pd_core>; ++ dmas = <&dmamux1 63 0x400 0x21>, ++ <&dmamux1 64 0x400 0x1>; ++ dma-names = "rx", "tx"; + status = "disabled"; + }; + +@@ -539,6 +570,9 @@ + resets = <&rcc UART5_R>; + wakeup-source; + power-domains = <&pd_core>; ++ dmas = <&dmamux1 65 0x400 0x21>, ++ <&dmamux1 66 0x400 0x1>; ++ dma-names = "rx", "tx"; + status = "disabled"; + }; + +@@ -666,6 +700,9 @@ + resets = <&rcc UART7_R>; + wakeup-source; + power-domains = <&pd_core>; ++ dmas = <&dmamux1 79 0x400 0x21>, ++ <&dmamux1 80 0x400 0x1>; ++ dma-names = "rx", "tx"; + status = "disabled"; + }; + +@@ -679,6 +716,9 @@ + resets = <&rcc UART8_R>; + wakeup-source; + power-domains = <&pd_core>; ++ dmas = <&dmamux1 81 0x400 0x21>, ++ <&dmamux1 82 0x400 0x1>; ++ dma-names = "rx", "tx"; + status = "disabled"; + }; + +@@ -754,6 +794,9 @@ + resets = <&rcc USART6_R>; + wakeup-source; + power-domains = <&pd_core>; ++ dmas = <&dmamux1 71 0x400 0x21>, ++ <&dmamux1 72 0x400 0x1>; ++ dma-names = "rx", "tx"; + status = "disabled"; + }; + +@@ -1060,7 +1103,7 @@ + interrupts = , + ; + interrupt-names = "int0", "int1"; +- clocks = <&rcc CK_HSE>, <&rcc FDCAN_K>; ++ clocks = <&rcc FDCAN>, <&rcc FDCAN_K>; + clock-names = "hclk", "cclk"; + bosch,mram-cfg = <0x0 0 0 32 0 0 2 2>; + status = "disabled"; +@@ -1073,7 +1116,7 @@ + interrupts = , + ; + interrupt-names = "int0", "int1"; +- clocks = <&rcc CK_HSE>, <&rcc FDCAN_K>; ++ clocks = <&rcc FDCAN>, <&rcc FDCAN_K>; + clock-names = "hclk", "cclk"; + bosch,mram-cfg = <0x1400 0 0 32 0 0 2 2>; + status = "disabled"; +@@ -1095,14 +1138,14 @@ + #dma-cells = <4>; + st,mem2mem; + dma-requests = <8>; +- dmas = <&mdma1 0 0x11 0x1200000a 0x48000008 0x00000020 1>, +- <&mdma1 1 0x11 0x1200000a 0x48000008 0x00000800 1>, +- <&mdma1 2 0x11 0x1200000a 0x48000008 0x00200000 1>, +- <&mdma1 3 0x11 0x1200000a 0x48000008 0x08000000 1>, +- <&mdma1 4 0x11 0x1200000a 0x4800000C 0x00000020 1>, +- <&mdma1 5 0x11 0x1200000a 0x4800000C 0x00000800 1>, +- <&mdma1 6 0x11 0x1200000a 0x4800000C 0x00200000 1>, +- <&mdma1 7 0x11 0x1200000a 0x4800000C 0x08000000 1>; ++ dmas = <&mdma1 0 0x3 0x1200000a 0x48000008 0x00000020 1>, ++ <&mdma1 1 0x3 0x1200000a 0x48000008 0x00000800 1>, ++ <&mdma1 2 0x3 0x1200000a 0x48000008 0x00200000 1>, ++ <&mdma1 3 0x3 0x1200000a 0x48000008 0x08000000 1>, ++ <&mdma1 4 0x3 0x1200000a 0x4800000C 0x00000020 1>, ++ <&mdma1 5 0x3 0x1200000a 0x4800000C 0x00000800 1>, ++ <&mdma1 6 0x3 0x1200000a 0x4800000C 0x00200000 1>, ++ <&mdma1 7 0x3 0x1200000a 0x4800000C 0x08000000 1>; + dma-names = "ch0", "ch1", "ch2", "ch3", "ch4", "ch5", "ch6", "ch7"; + }; + +@@ -1122,14 +1165,14 @@ + #dma-cells = <4>; + st,mem2mem; + dma-requests = <8>; +- dmas = <&mdma1 8 0x11 0x1200000a 0x48001008 0x00000020 1>, +- <&mdma1 9 0x11 0x1200000a 0x48001008 0x00000800 1>, +- <&mdma1 10 0x11 0x1200000a 0x48001008 0x00200000 1>, +- <&mdma1 11 0x11 0x1200000a 0x48001008 0x08000000 1>, +- <&mdma1 12 0x11 0x1200000a 0x4800100C 0x00000020 1>, +- <&mdma1 13 0x11 0x1200000a 0x4800100C 0x00000800 1>, +- <&mdma1 14 0x11 0x1200000a 0x4800100C 0x00200000 1>, +- <&mdma1 15 0x11 0x1200000a 0x4800100C 0x08000000 1>; ++ dmas = <&mdma1 8 0x3 0x1200000a 0x48001008 0x00000020 1>, ++ <&mdma1 9 0x3 0x1200000a 0x48001008 0x00000800 1>, ++ <&mdma1 10 0x3 0x1200000a 0x48001008 0x00200000 1>, ++ <&mdma1 11 0x3 0x1200000a 0x48001008 0x08000000 1>, ++ <&mdma1 12 0x3 0x1200000a 0x4800100C 0x00000020 1>, ++ <&mdma1 13 0x3 0x1200000a 0x4800100C 0x00000800 1>, ++ <&mdma1 14 0x3 0x1200000a 0x4800100C 0x00200000 1>, ++ <&mdma1 15 0x3 0x1200000a 0x4800100C 0x08000000 1>; + dma-names = "ch0", "ch1", "ch2", "ch3", "ch4", "ch5", "ch6", "ch7"; + }; + +@@ -1309,6 +1352,13 @@ + interrupt-controller; + #interrupt-cells = <3>; + ++ wakeup-gpios = <&gpioa 0 GPIO_ACTIVE_HIGH>, ++ <&gpioa 2 GPIO_ACTIVE_HIGH>, ++ <&gpioc 13 GPIO_ACTIVE_HIGH>, ++ <&gpioi 8 GPIO_ACTIVE_HIGH>, ++ <&gpioi 11 GPIO_ACTIVE_HIGH>, ++ <&gpioc 1 GPIO_ACTIVE_HIGH>; ++ + pwr-regulators { + compatible = "st,stm32mp1,pwr-reg"; + st,tzcr = <&rcc 0x0 0x1>; +@@ -1655,7 +1705,7 @@ + interrupts = ; + clocks = <&rcc HASH1>; + resets = <&rcc HASH1_R>; +- dmas = <&mdma1 31 0x10 0x1000A02 0x0 0x0 0x0>; ++ dmas = <&mdma1 31 0x2 0x1000A02 0x0 0x0 0x0>; + dma-names = "in"; + dma-maxburst = <2>; + status = "disabled"; +@@ -1690,22 +1740,22 @@ + <0x89010000 0x1000>, + <0x89020000 0x1000>; + interrupts = ; +- dmas = <&mdma1 20 0x10 0x12000A02 0x0 0x0 0>, +- <&mdma1 20 0x10 0x12000A08 0x0 0x0 0>, +- <&mdma1 21 0x10 0x12000A0A 0x0 0x0 0>; ++ dmas = <&mdma1 20 0x2 0x12000A02 0x0 0x0 0>, ++ <&mdma1 20 0x2 0x12000A08 0x0 0x0 0>, ++ <&mdma1 21 0x2 0x12000A0A 0x0 0x0 0>; + dma-names = "tx", "rx", "ecc"; + clocks = <&rcc FMC_K>; + resets = <&rcc FMC_R>; + status = "disabled"; + }; + +- qspi: qspi@58003000 { ++ qspi: spi@58003000 { + compatible = "st,stm32f469-qspi"; + reg = <0x58003000 0x1000>, <0x70000000 0x10000000>; + reg-names = "qspi", "qspi_mm"; + interrupts = ; +- dmas = <&mdma1 22 0x10 0x100002 0x0 0x0 0x0>, +- <&mdma1 22 0x10 0x100008 0x0 0x0 0x0>; ++ dmas = <&mdma1 22 0x2 0x100002 0x0 0x0 0x0>, ++ <&mdma1 22 0x2 0x100008 0x0 0x0 0x0>; + dma-names = "tx", "rx"; + clocks = <&rcc QSPI_K>; + resets = <&rcc QSPI_R>; +@@ -1941,6 +1991,10 @@ + reg = <0x5c005000 0x400>; + #address-cells = <1>; + #size-cells = <1>; ++ ++ part_number_otp: part_number_otp@4 { ++ reg = <0x4 0x1>; ++ }; + ts_cal1: calib@5c { + reg = <0x5c 0x2>; + }; +@@ -2001,6 +2055,7 @@ + st,syscfg-pdds = <&pwr 0x014 0x1>; + st,syscfg-holdboot = <&rcc 0x10C 0x1>; + st,syscfg-tz = <&rcc 0x000 0x1>; ++ st,syscfg-rsc-tbl = <&tamp 0x144 0xFFFFFFFF>; + status = "disabled"; + + m4_system_resources { +diff --git a/doc/device-tree-bindings/clock/st,stm32mp1.txt b/doc/device-tree-bindings/clock/st,stm32mp1.txt +index ec1d703..a703318 100644 +--- a/doc/device-tree-bindings/clock/st,stm32mp1.txt ++++ b/doc/device-tree-bindings/clock/st,stm32mp1.txt +@@ -84,6 +84,10 @@ Optional Properties: + are listed with associated index 0 to 3 (st,pll@0 to st,pll@3). + PLLx is off when the associated node is absent. + ++ For PLL1, when the node is absent, the frequency of the OPP node is used ++ to compute the PLL setting (see compatible "operating-points-v2" in ++ opp/opp.txt for details). ++ + Here are the available properties for each PLL node: + + - cfg: The parameters for PLL configuration in the following order: +diff --git a/include/dt-bindings/mfd/st,stpmic1.h b/include/dt-bindings/mfd/st,stpmic1.h +index b2d6c83..321cd08 100644 +--- a/include/dt-bindings/mfd/st,stpmic1.h ++++ b/include/dt-bindings/mfd/st,stpmic1.h +@@ -43,4 +43,8 @@ + #define IT_SWIN_F 30 + #define IT_SWIN_R 31 + ++/* BUCK MODES definitions */ ++#define STPMIC1_BUCK_MODE_NORMAL 0 ++#define STPMIC1_BUCK_MODE_LP 2 ++ + #endif /* __DT_BINDINGS_STPMIC1_H__ */ +diff --git a/include/dt-bindings/pinctrl/stm32-pinfunc.h b/include/dt-bindings/pinctrl/stm32-pinfunc.h +index e928aea..e3b45a8 100644 +--- a/include/dt-bindings/pinctrl/stm32-pinfunc.h ++++ b/include/dt-bindings/pinctrl/stm32-pinfunc.h +@@ -26,6 +26,7 @@ + #define AF14 0xf + #define AF15 0x10 + #define ANALOG 0x11 ++#define RSVD 0x12 + + /* define Pins number*/ + #define PIN_NO(port, line) (((port) - 'A') * 0x10 + (line)) +-- +2.7.4 + diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/0017-ARM-v2018.11-stm32mp-r4-MISC.patch b/recipes-bsp/u-boot/u-boot-stm32mp/0017-ARM-v2018.11-stm32mp-r4-MISC.patch new file mode 100644 index 0000000..e360167 --- /dev/null +++ b/recipes-bsp/u-boot/u-boot-stm32mp/0017-ARM-v2018.11-stm32mp-r4-MISC.patch @@ -0,0 +1,4739 @@ +From a962515cc6270639e7ec645409a0dd1b0c848829 Mon Sep 17 00:00:00 2001 +From: Romuald JEANNE +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 + #include + #include ++#include + + #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 for STMicroelectronics. ++ * ++ */ ++ ++#include ++#include ++#include ++ ++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 for STMicroelectronics. + * Yannick Fertre 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 + #include ++#include + #include + #include +-#include + #include + #include + #include + #include + #include +-#include + #include + #include + +@@ -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 "); + MODULE_AUTHOR("Philippe Cornu "); +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 +- * +- * 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 +-#include +-#include +-#include +-#include +- +-/** +- * 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 "); +-MODULE_AUTHOR("Yannick Fertre "); +-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 ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++ ++/** ++ * 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 for STMicroelectronics. + * Philippe Cornu 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 + #include + #include +-#include ++#include + #include + #include + #include +@@ -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 for STMicroelectronics. + * Philippe Cornu 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 + #include + #include +-#include ++#include + #include + #include + #include +@@ -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 for STMicroelectronics. + * Yannick Fertre 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 + #include + #include +-#include +-#include ++#include ++#include + #include + #include + #include +@@ -19,6 +20,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -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 for STMicroelectronics. + * Yannick Fertre for STMicroelectronics. + */ ++ + #include + #include + #include +@@ -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 for STMicroelectronics. ++ * ++ */ ++ ++#ifndef _DSI_HOST_H ++#define _DSI_HOST_H ++ ++#include ++ ++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 + * Copyright (C) 2006 Nokia Corporation +- * Copyright (C) 2018 STMicroelectronics - All Rights Reserved +- * Author(s): Imre Deak +- * Yannick Fertre +- * Philippe Cornu ++ * Author: Imre Deak + * + * 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 ++ * Yannick Fertre ++ * Philippe Cornu ++ * ++ * 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 ++#include ++ ++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 +