* [RFC PATCH 00/10] arm: add support for SoC S5P4418
@ 2020-02-03 19:39 Stefan Bosch
2020-02-03 20:32 ` [RFC PATCH 01/10] arm: add mach-nexell (header files) Stefan Bosch
` (11 more replies)
0 siblings, 12 replies; 19+ messages in thread
From: Stefan Bosch @ 2020-02-03 19:39 UTC (permalink / raw)
To: u-boot
This patch adds support for SAMSUNG's/NEXELL's ARM Cortex-A9 based
S5P4418 SoC, especially FriendlyARM's NanoPi2 and NanoPC-T2 boards.
It is based on the following FriendlyARM's U-Boot version:
https://github.com/friendlyarm/u-boot/tree/nanopi2-v2016.01.
The added mach-nexell also supports the S5P6818 SoC which is a
follow-up of the S5P4418.
Main changes in relation to nanopi2-v2016.01:
- Cosmetic changes due to patman warnings/errors.
- MMC and Video drivers changed to DM.
- Configs reworked (e.g. "CONFIG_..." moved from s5p4418_nanopi2.h
to s5p4418_nanopi2_defconfig)
- SPL related files are not included.
- MACH_TYPE_S5P4418 is not defined/used anymore.
- arch/arm/mach-nexell/include/mach/boot0.h added to generate the NSIH
(Nexell System Information Header), substitudes tools/nexell.
- board/s5p4418/ renamed to board/friendlyarm/
- Only the NanoPi2 and NanoPC-T2 boards are supported yet because I
do only have the NanoPC-T2 board to test the code (this board uses
the NanoPi2 code).
Stefan Bosch (10):
arm: add mach-nexell (header files)
arm: add mach-nexell (all files except header files)
i2c: mmc: add nexell driver (gpio, i2c, mmc, pwm)
video: add nexell video driver (soc: displaytop)
video: add nexell video driver (soc: mlc, mipi)
video: add nexell video driver (soc: lvds, hdmi)
video: add nexell video driver (soc: dpc, makefile)
video: add nexell video driver (display/video driver)
arm: add support for SoC s5p4418 (cpu) / nanopi2 board
arm: add (default) config for nanopi2 board
MAINTAINERS | 19 +
arch/arm/Kconfig | 7 +
arch/arm/Makefile | 1 +
arch/arm/cpu/armv7/Makefile | 1 +
arch/arm/cpu/armv7/s5p4418/Makefile | 6 +
arch/arm/cpu/armv7/s5p4418/cpu.c | 120 ++
arch/arm/dts/Makefile | 3 +
arch/arm/dts/s5p4418-nanopi2.dts | 109 ++
arch/arm/dts/s5p4418-pinctrl.dtsi | 66 +
arch/arm/dts/s5p4418.dtsi | 157 ++
arch/arm/mach-nexell/Kconfig | 67 +
arch/arm/mach-nexell/Makefile | 15 +
arch/arm/mach-nexell/clock.c | 869 +++++++++
arch/arm/mach-nexell/cmd_boot_linux.c | 145 ++
arch/arm/mach-nexell/config.mk | 11 +
arch/arm/mach-nexell/include/mach/boot0.h | 40 +
arch/arm/mach-nexell/include/mach/clk.h | 24 +
arch/arm/mach-nexell/include/mach/display.h | 273 +++
arch/arm/mach-nexell/include/mach/display_dev.h | 37 +
arch/arm/mach-nexell/include/mach/ehci.h | 106 ++
arch/arm/mach-nexell/include/mach/gpio.h | 17 +
arch/arm/mach-nexell/include/mach/mipi_display.h | 219 +++
arch/arm/mach-nexell/include/mach/nexell.h | 352 ++++
arch/arm/mach-nexell/include/mach/nx_gpio.h | 103 ++
arch/arm/mach-nexell/include/mach/reset.h | 19 +
arch/arm/mach-nexell/include/mach/sec_reg.h | 15 +
arch/arm/mach-nexell/include/mach/tieoff.h | 423 +++++
arch/arm/mach-nexell/nx_gpio.c | 352 ++++
arch/arm/mach-nexell/nx_sec_reg.c | 82 +
arch/arm/mach-nexell/reg-call.S | 23 +
arch/arm/mach-nexell/reset.c | 33 +
arch/arm/mach-nexell/serial.c | 262 +++
arch/arm/mach-nexell/tieoff.c | 109 ++
arch/arm/mach-nexell/timer.c | 297 ++++
board/friendlyarm/Kconfig | 39 +
board/friendlyarm/nanopi2/Kconfig | 12 +
board/friendlyarm/nanopi2/MAINTAINERS | 7 +
board/friendlyarm/nanopi2/Makefile | 6 +
board/friendlyarm/nanopi2/board.c | 581 ++++++
board/friendlyarm/nanopi2/hwrev.c | 122 ++
board/friendlyarm/nanopi2/hwrev.h | 29 +
board/friendlyarm/nanopi2/lcds.c | 703 ++++++++
board/friendlyarm/nanopi2/nxp-fb.h | 99 ++
board/friendlyarm/nanopi2/onewire.c | 323 ++++
board/friendlyarm/nanopi2/onewire.h | 29 +
configs/s5p4418_nanopi2_defconfig | 177 ++
doc/README.s5p4418 | 63 +
drivers/gpio/Kconfig | 9 +
drivers/gpio/Makefile | 1 +
drivers/gpio/nx_gpio.c | 252 +++
drivers/i2c/Kconfig | 9 +
drivers/i2c/Makefile | 1 +
drivers/i2c/nx_i2c.c | 537 ++++++
drivers/mmc/Kconfig | 6 +
drivers/mmc/Makefile | 1 +
drivers/mmc/nexell_dw_mmc_dm.c | 350 ++++
drivers/pwm/Makefile | 1 +
drivers/pwm/pwm-nexell.c | 252 +++
drivers/pwm/pwm-nexell.h | 54 +
drivers/video/Kconfig | 10 +
drivers/video/Makefile | 1 +
drivers/video/nexell/Kconfig | 27 +
drivers/video/nexell/Makefile | 12 +
drivers/video/nexell/s5pxx18_dp.c | 338 ++++
drivers/video/nexell/s5pxx18_dp_hdmi.c | 543 ++++++
drivers/video/nexell/s5pxx18_dp_lvds.c | 274 +++
drivers/video/nexell/s5pxx18_dp_mipi.c | 677 +++++++
drivers/video/nexell/s5pxx18_dp_rgb.c | 69 +
drivers/video/nexell/soc/Makefile | 11 +
drivers/video/nexell/soc/s5pxx18_soc_disptop.c | 185 ++
drivers/video/nexell/soc/s5pxx18_soc_disptop.h | 385 ++++
drivers/video/nexell/soc/s5pxx18_soc_disptop_clk.c | 309 ++++
drivers/video/nexell/soc/s5pxx18_soc_disptop_clk.h | 59 +
drivers/video/nexell/soc/s5pxx18_soc_disptype.h | 23 +
drivers/video/nexell/soc/s5pxx18_soc_dpc.c | 1569 +++++++++++++++++
drivers/video/nexell/soc/s5pxx18_soc_dpc.h | 444 +++++
drivers/video/nexell/soc/s5pxx18_soc_hdmi.c | 50 +
drivers/video/nexell/soc/s5pxx18_soc_hdmi.h | 488 +++++
drivers/video/nexell/soc/s5pxx18_soc_lvds.c | 278 +++
drivers/video/nexell/soc/s5pxx18_soc_lvds.h | 83 +
drivers/video/nexell/soc/s5pxx18_soc_mipi.c | 580 ++++++
drivers/video/nexell/soc/s5pxx18_soc_mipi.h | 291 +++
drivers/video/nexell/soc/s5pxx18_soc_mlc.c | 1861 ++++++++++++++++++++
drivers/video/nexell/soc/s5pxx18_soc_mlc.h | 429 +++++
drivers/video/nexell_display.c | 658 +++++++
include/configs/s5p4418_nanopi2.h | 270 +++
86 files changed, 17969 insertions(+)
create mode 100644 arch/arm/cpu/armv7/s5p4418/Makefile
create mode 100644 arch/arm/cpu/armv7/s5p4418/cpu.c
create mode 100644 arch/arm/dts/s5p4418-nanopi2.dts
create mode 100644 arch/arm/dts/s5p4418-pinctrl.dtsi
create mode 100644 arch/arm/dts/s5p4418.dtsi
create mode 100644 arch/arm/mach-nexell/Kconfig
create mode 100644 arch/arm/mach-nexell/Makefile
create mode 100644 arch/arm/mach-nexell/clock.c
create mode 100644 arch/arm/mach-nexell/cmd_boot_linux.c
create mode 100644 arch/arm/mach-nexell/config.mk
create mode 100644 arch/arm/mach-nexell/include/mach/boot0.h
create mode 100644 arch/arm/mach-nexell/include/mach/clk.h
create mode 100644 arch/arm/mach-nexell/include/mach/display.h
create mode 100644 arch/arm/mach-nexell/include/mach/display_dev.h
create mode 100644 arch/arm/mach-nexell/include/mach/ehci.h
create mode 100644 arch/arm/mach-nexell/include/mach/gpio.h
create mode 100644 arch/arm/mach-nexell/include/mach/mipi_display.h
create mode 100644 arch/arm/mach-nexell/include/mach/nexell.h
create mode 100644 arch/arm/mach-nexell/include/mach/nx_gpio.h
create mode 100644 arch/arm/mach-nexell/include/mach/reset.h
create mode 100644 arch/arm/mach-nexell/include/mach/sec_reg.h
create mode 100644 arch/arm/mach-nexell/include/mach/tieoff.h
create mode 100644 arch/arm/mach-nexell/nx_gpio.c
create mode 100644 arch/arm/mach-nexell/nx_sec_reg.c
create mode 100644 arch/arm/mach-nexell/reg-call.S
create mode 100644 arch/arm/mach-nexell/reset.c
create mode 100644 arch/arm/mach-nexell/serial.c
create mode 100644 arch/arm/mach-nexell/tieoff.c
create mode 100644 arch/arm/mach-nexell/timer.c
create mode 100644 board/friendlyarm/Kconfig
create mode 100644 board/friendlyarm/nanopi2/Kconfig
create mode 100644 board/friendlyarm/nanopi2/MAINTAINERS
create mode 100644 board/friendlyarm/nanopi2/Makefile
create mode 100644 board/friendlyarm/nanopi2/board.c
create mode 100644 board/friendlyarm/nanopi2/hwrev.c
create mode 100644 board/friendlyarm/nanopi2/hwrev.h
create mode 100644 board/friendlyarm/nanopi2/lcds.c
create mode 100644 board/friendlyarm/nanopi2/nxp-fb.h
create mode 100644 board/friendlyarm/nanopi2/onewire.c
create mode 100644 board/friendlyarm/nanopi2/onewire.h
create mode 100644 configs/s5p4418_nanopi2_defconfig
create mode 100644 doc/README.s5p4418
create mode 100644 drivers/gpio/nx_gpio.c
create mode 100644 drivers/i2c/nx_i2c.c
create mode 100644 drivers/mmc/nexell_dw_mmc_dm.c
create mode 100644 drivers/pwm/pwm-nexell.c
create mode 100644 drivers/pwm/pwm-nexell.h
create mode 100644 drivers/video/nexell/Kconfig
create mode 100644 drivers/video/nexell/Makefile
create mode 100644 drivers/video/nexell/s5pxx18_dp.c
create mode 100644 drivers/video/nexell/s5pxx18_dp_hdmi.c
create mode 100644 drivers/video/nexell/s5pxx18_dp_lvds.c
create mode 100644 drivers/video/nexell/s5pxx18_dp_mipi.c
create mode 100644 drivers/video/nexell/s5pxx18_dp_rgb.c
create mode 100644 drivers/video/nexell/soc/Makefile
create mode 100644 drivers/video/nexell/soc/s5pxx18_soc_disptop.c
create mode 100644 drivers/video/nexell/soc/s5pxx18_soc_disptop.h
create mode 100644 drivers/video/nexell/soc/s5pxx18_soc_disptop_clk.c
create mode 100644 drivers/video/nexell/soc/s5pxx18_soc_disptop_clk.h
create mode 100644 drivers/video/nexell/soc/s5pxx18_soc_disptype.h
create mode 100644 drivers/video/nexell/soc/s5pxx18_soc_dpc.c
create mode 100644 drivers/video/nexell/soc/s5pxx18_soc_dpc.h
create mode 100644 drivers/video/nexell/soc/s5pxx18_soc_hdmi.c
create mode 100644 drivers/video/nexell/soc/s5pxx18_soc_hdmi.h
create mode 100644 drivers/video/nexell/soc/s5pxx18_soc_lvds.c
create mode 100644 drivers/video/nexell/soc/s5pxx18_soc_lvds.h
create mode 100644 drivers/video/nexell/soc/s5pxx18_soc_mipi.c
create mode 100644 drivers/video/nexell/soc/s5pxx18_soc_mipi.h
create mode 100644 drivers/video/nexell/soc/s5pxx18_soc_mlc.c
create mode 100644 drivers/video/nexell/soc/s5pxx18_soc_mlc.h
create mode 100644 drivers/video/nexell_display.c
create mode 100644 include/configs/s5p4418_nanopi2.h
--
1.9.1
^ permalink raw reply [flat|nested] 19+ messages in thread
* [RFC PATCH 01/10] arm: add mach-nexell (header files)
2020-02-03 19:39 [RFC PATCH 00/10] arm: add support for SoC S5P4418 Stefan Bosch
@ 2020-02-03 20:32 ` Stefan Bosch
2020-02-03 20:38 ` [RFC PATCH 02/10] arm: add mach-nexell (all files except header files) Stefan Bosch
` (10 subsequent siblings)
11 siblings, 0 replies; 19+ messages in thread
From: Stefan Bosch @ 2020-02-03 20:32 UTC (permalink / raw)
To: u-boot
Changes in relation to FriendlyARM's U-Boot nanopi2-v2016.01:
- DM_VIDEO support (display_dev.h).
- boot0.h added, handles NSIH --> tools/nexell obsolete.
- gpio.h: Include-path to errno.h changed.
Signed-off-by: Stefan Bosch <stefan_b@posteo.net>
---
arch/arm/mach-nexell/include/mach/boot0.h | 40 +++
arch/arm/mach-nexell/include/mach/clk.h | 24 ++
arch/arm/mach-nexell/include/mach/display.h | 273 +++++++++++++++
arch/arm/mach-nexell/include/mach/display_dev.h | 37 ++
arch/arm/mach-nexell/include/mach/ehci.h | 106 ++++++
arch/arm/mach-nexell/include/mach/gpio.h | 17 +
arch/arm/mach-nexell/include/mach/mipi_display.h | 219 ++++++++++++
arch/arm/mach-nexell/include/mach/nexell.h | 352 +++++++++++++++++++
arch/arm/mach-nexell/include/mach/nx_gpio.h | 103 ++++++
arch/arm/mach-nexell/include/mach/reset.h | 19 +
arch/arm/mach-nexell/include/mach/sec_reg.h | 15 +
arch/arm/mach-nexell/include/mach/tieoff.h | 423 +++++++++++++++++++++++
12 files changed, 1628 insertions(+)
create mode 100644 arch/arm/mach-nexell/include/mach/boot0.h
create mode 100644 arch/arm/mach-nexell/include/mach/clk.h
create mode 100644 arch/arm/mach-nexell/include/mach/display.h
create mode 100644 arch/arm/mach-nexell/include/mach/display_dev.h
create mode 100644 arch/arm/mach-nexell/include/mach/ehci.h
create mode 100644 arch/arm/mach-nexell/include/mach/gpio.h
create mode 100644 arch/arm/mach-nexell/include/mach/mipi_display.h
create mode 100644 arch/arm/mach-nexell/include/mach/nexell.h
create mode 100644 arch/arm/mach-nexell/include/mach/nx_gpio.h
create mode 100644 arch/arm/mach-nexell/include/mach/reset.h
create mode 100644 arch/arm/mach-nexell/include/mach/sec_reg.h
create mode 100644 arch/arm/mach-nexell/include/mach/tieoff.h
diff --git a/arch/arm/mach-nexell/include/mach/boot0.h b/arch/arm/mach-nexell/include/mach/boot0.h
new file mode 100644
index 0000000..e05c07e
--- /dev/null
+++ b/arch/arm/mach-nexell/include/mach/boot0.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0+
+ *
+ * NSIH (Nexell System Information Header) for FriendlyArm nanopi2 board
+ *
+ * The NSIH (first 512 Bytes of u-boot.bin) is necessary for the
+ * 2nd-Bootloader to get information like load address of U-Boot.
+ *
+ * 0x400 must be added to CONFIG_SYS_TEXT_BASE to have the actual load and
+ * start address because 2nd-Bootloader loads with an offset of 0x400
+ * (NSIH + 0x200 bytes are not loaded into RAM).
+ *
+ * It has been tested / is working with the following 2nd-Bootloader:
+ * "BL1 by Nexell V1.0.0-gd551e13 [Built on 2018-01-25 16:58:29]"
+ *
+ * (C) Copyright 2020 Stefan Bosch <stefan_b@posteo.net>
+ */
+
+#ifndef __BOOT0_H
+#define __BOOT0_H
+
+ ARM_VECTORS
+ .space 0x30
+ .word (_end - _start) + 20 * 1024 /* 0x50: load size
+ * (bin + 20k for DTB) */
+ .space 0x4
+ .word CONFIG_SYS_TEXT_BASE + 0x400 /* 0x58: load address */
+ .word 0x00000000
+ .word CONFIG_SYS_TEXT_BASE + 0x400 /* 0x60: start address */
+ .space 0x198
+ .byte 'N' /* 0x1FC: "NSIH" signature */
+ .byte 'S'
+ .byte 'I'
+ .byte 'H'
+
+ /* The NSIH + 0x200 bytes are omitted by the 2nd-Bootloader */
+ .space 0x200
+_start:
+ ARM_VECTORS
+
+#endif /* __BOOT0_H */
diff --git a/arch/arm/mach-nexell/include/mach/clk.h b/arch/arm/mach-nexell/include/mach/clk.h
new file mode 100644
index 0000000..cc5589a
--- /dev/null
+++ b/arch/arm/mach-nexell/include/mach/clk.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0+
+ *
+ * (C) Copyright 2016 Nexell
+ * Hyunseok, Jung <hsjung@nexell.co.kr>
+ */
+
+#ifndef __ASM_ARM_ARCH_CLK_H_
+#define __ASM_ARM_ARCH_CLK_H_
+
+struct clk {
+ unsigned long rate;
+};
+
+void clk_init(void);
+
+struct clk *clk_get(const char *id);
+void clk_put(struct clk *clk);
+unsigned long clk_get_rate(struct clk *clk);
+long clk_round_rate(struct clk *clk, unsigned long rate);
+int clk_set_rate(struct clk *clk, unsigned long rate);
+int clk_enable(struct clk *clk);
+void clk_disable(struct clk *clk);
+
+#endif
diff --git a/arch/arm/mach-nexell/include/mach/display.h b/arch/arm/mach-nexell/include/mach/display.h
new file mode 100644
index 0000000..b167e63
--- /dev/null
+++ b/arch/arm/mach-nexell/include/mach/display.h
@@ -0,0 +1,273 @@
+/* SPDX-License-Identifier: GPL-2.0+
+ *
+ * Copyright (C) 2016 Nexell Co., Ltd.
+ *
+ * Author: junghyun, kim <jhkim@nexell.co.kr>
+ */
+
+#ifndef _NX__DISPLAY_H_
+#define _NX__DISPLAY_H_
+
+#define DP_PLANS_NUM 3
+
+/* the display output format. */
+#define DPC_FORMAT_RGB555 0 /* RGB555 Format */
+#define DPC_FORMAT_RGB565 1 /* RGB565 Format */
+#define DPC_FORMAT_RGB666 2 /* RGB666 Format */
+#define DPC_FORMAT_RGB888 3 /* RGB888 Format */
+#define DPC_FORMAT_MRGB555A 4 /* MRGB555A Format */
+#define DPC_FORMAT_MRGB555B 5 /* MRGB555B Format */
+#define DPC_FORMAT_MRGB565 6 /* MRGB565 Format */
+#define DPC_FORMAT_MRGB666 7 /* MRGB666 Format */
+#define DPC_FORMAT_MRGB888A 8 /* MRGB888A Format */
+#define DPC_FORMAT_MRGB888B 9 /* MRGB888B Format */
+#define DPC_FORMAT_CCIR656 10 /* ITU-R BT.656 / 601(8-bit) */
+#define DPC_FORMAT_CCIR601A 12 /* ITU-R BT.601A */
+#define DPC_FORMAT_CCIR601B 13 /* ITU-R BT.601B */
+#define DPC_FORMAT_4096COLOR 1 /* 4096 Color Format */
+#define DPC_FORMAT_16GRAY 3 /* 16 Level Gray Format */
+
+/* layer pixel format. */
+#define MLC_RGBFMT_R5G6B5 0x44320000 /* {R5,G6,B5 }. */
+#define MLC_RGBFMT_B5G6R5 0xC4320000 /* {B5,G6,R5 }. */
+#define MLC_RGBFMT_X1R5G5B5 0x43420000 /* {X1,R5,G5,B5}. */
+#define MLC_RGBFMT_X1B5G5R5 0xC3420000 /* {X1,B5,G5,R5}. */
+#define MLC_RGBFMT_X4R4G4B4 0x42110000 /* {X4,R4,G4,B4}. */
+#define MLC_RGBFMT_X4B4G4R4 0xC2110000 /* {X4,B4,G4,R4}. */
+#define MLC_RGBFMT_X8R3G3B2 0x41200000 /* {X8,R3,G3,B2}. */
+#define MLC_RGBFMT_X8B3G3R2 0xC1200000 /* {X8,B3,G3,R2}. */
+#define MLC_RGBFMT_A1R5G5B5 0x33420000 /* {A1,R5,G5,B5}. */
+#define MLC_RGBFMT_A1B5G5R5 0xB3420000 /* {A1,B5,G5,R5}. */
+#define MLC_RGBFMT_A4R4G4B4 0x22110000 /* {A4,R4,G4,B4}. */
+#define MLC_RGBFMT_A4B4G4R4 0xA2110000 /* {A4,B4,G4,R4}. */
+#define MLC_RGBFMT_A8R3G3B2 0x11200000 /* {A8,R3,G3,B2}. */
+#define MLC_RGBFMT_A8B3G3R2 0x91200000 /* {A8,B3,G3,R2}. */
+#define MLC_RGBFMT_R8G8B8 0x46530000 /* {R8,G8,B8 }. */
+#define MLC_RGBFMT_B8G8R8 0xC6530000 /* {B8,G8,R8 }. */
+#define MLC_RGBFMT_X8R8G8B8 0x46530000 /* {X8,R8,G8,B8}. */
+#define MLC_RGBFMT_X8B8G8R8 0xC6530000 /* {X8,B8,G8,R8}. */
+#define MLC_RGBFMT_A8R8G8B8 0x06530000 /* {A8,R8,G8,B8}. */
+#define MLC_RGBFMT_A8B8G8R8 0x86530000 /* {A8,B8,G8,R8}. */
+
+/* the data output order in case of ITU-R BT.656 / 601. */
+#define DPC_YCORDER_CBYCRY 0
+#define DPC_YCORDER_CRYCBY 1
+#define DPC_YCORDER_YCBYCR 2
+#define DPC_YCORDER_YCRYCB 3
+
+/* the PAD output clock. */
+#define DPC_PADCLKSEL_VCLK 0 /* VCLK */
+#define DPC_PADCLKSEL_VCLK2 1 /* VCLK2 */
+
+/* display sync info for DPC */
+struct dp_sync_info {
+ int interlace;
+ int h_active_len;
+ int h_sync_width;
+ int h_back_porch;
+ int h_front_porch;
+ int h_sync_invert; /* default active low */
+ int v_active_len;
+ int v_sync_width;
+ int v_back_porch;
+ int v_front_porch;
+ int v_sync_invert; /* default active low */
+ int pixel_clock_hz; /* HZ */
+};
+
+/* syncgen control (DPC) */
+#define DP_SYNC_DELAY_RGB_PVD (1 << 0)
+#define DP_SYNC_DELAY_HSYNC_CP1 (1 << 1)
+#define DP_SYNC_DELAY_VSYNC_FRAM (1 << 2)
+#define DP_SYNC_DELAY_DE_CP (1 << 3)
+
+struct dp_ctrl_info {
+ /* clock gen */
+ int clk_src_lv0;
+ int clk_div_lv0;
+ int clk_src_lv1;
+ int clk_div_lv1;
+ /* scan format */
+ int interlace;
+ /* syncgen format */
+ unsigned int out_format;
+ int invert_field; /* 0:normal(Low odd), 1:invert (low even) */
+ int swap_RB;
+ unsigned int yc_order; /* for CCIR output */
+ /* extern sync delay */
+ int delay_mask; /* if 0, set defalut delays */
+ int d_rgb_pvd; /* delay for RGB/PVD, 0~16, default 0 */
+ int d_hsync_cp1; /* delay for HSYNC/CP1, 0~63, default 12 */
+ int d_vsync_fram; /* delay for VSYNC/FRAM, 0~63, default 12 */
+ int d_de_cp2; /* delay for DE/CP2, 0~63, default 12 */
+ /* sync offset */
+ int vs_start_offset; /* start vsync offset, defatult 0 */
+ int vs_end_offset; /* end vsync offset, default 0 */
+ int ev_start_offset; /* start even vsync offset, default 0 */
+ int ev_end_offset; /* end even vsync offset , default 0 */
+ /* pad clock seletor */
+ int vck_select; /* 0=vclk0, 1=vclk2 */
+ int clk_inv_lv0; /* OUTCLKINVn */
+ int clk_delay_lv0; /* OUTCLKDELAYn */
+ int clk_inv_lv1; /* OUTCLKINVn */
+ int clk_delay_lv1; /* OUTCLKDELAYn */
+ int clk_sel_div1; /* 0=clk1_inv, 1=clk1_div_2_ns */
+};
+
+/* multi layer control (MLC) */
+struct dp_plane_top {
+ int screen_width;
+ int screen_height;
+ int video_prior; /* 0: video>RGBn, 1: RGB0>video>RGB1,
+ * 2: RGB0 > RGB1 > video .. */
+ int interlace;
+ int plane_num;
+ unsigned int back_color;
+};
+
+struct dp_plane_info {
+ int layer;
+ unsigned int fb_base;
+ int left;
+ int top;
+ int width;
+ int height;
+ int pixel_byte;
+ unsigned int format;
+ int alpha_on;
+ int alpha_depth;
+ int tp_on; /* transparency color enable */
+ unsigned int tp_color;
+ unsigned int mem_lock_size; /* memory burst access (4,8,16) */
+ int video_layer;
+ int enable;
+};
+
+/*
+ * LCD device dependency struct
+ * RGB, LVDS, MiPi, HDMI
+ */
+enum {
+ DP_DEVICE_RESCONV = 0,
+ DP_DEVICE_RGBLCD = 1,
+ DP_DEVICE_HDMI = 2,
+ DP_DEVICE_MIPI = 3,
+ DP_DEVICE_LVDS = 4,
+ DP_DEVICE_CVBS = 5,
+ DP_DEVICE_DP0 = 6,
+ DP_DEVICE_DP1 = 7,
+ DP_DEVICE_END,
+};
+
+enum {
+ DP_CLOCK_RESCONV = 0,
+ DP_CLOCK_LCDIF = 1,
+ DP_CLOCK_MIPI = 2,
+ DP_CLOCK_LVDS = 3,
+ DP_CLOCK_HDMI = 4,
+ DP_CLOCK_END,
+};
+
+enum dp_lvds_format {
+ DP_LVDS_FORMAT_VESA = 0,
+ DP_LVDS_FORMAT_JEIDA = 1,
+ DP_LVDS_FORMAT_LOC = 2,
+};
+
+#define DEF_VOLTAGE_LEVEL (0x20)
+
+struct dp_lvds_dev {
+ enum dp_lvds_format lvds_format; /* 0:VESA, 1:JEIDA, 2: Location */
+ int pol_inv_hs; /* hsync polarity invert for VESA, JEIDA */
+ int pol_inv_vs; /* bsync polarity invert for VESA, JEIDA */
+ int pol_inv_de; /* de polarity invert for VESA, JEIDA */
+ int pol_inv_ck; /* input clock(pixel clock) polarity invert */
+ int voltage_level;
+ /* Location setting */
+ unsigned int loc_map[9]; /* Location Setting */
+ unsigned int loc_mask[2]; /* Location Setting, 0 ~ 34 */
+ unsigned int loc_pol[2]; /* Location Setting, 0 ~ 34 */
+};
+
+#include "mipi_display.h"
+
+struct dp_mipi_dev {
+ int lp_bitrate; /* to lcd setup, low power bitrate (150, 100, 80 Mhz) */
+ int hs_bitrate; /* to lcd data, high speed bitrate (1000, ... Mhz) */
+ int lpm_trans;
+ int command_mode;
+ unsigned int hs_pllpms;
+ unsigned int hs_bandctl;
+ unsigned int lp_pllpms;
+ unsigned int lp_bandctl;
+ struct mipi_dsi_device dsi;
+};
+
+struct dp_rgb_dev {
+ int lcd_mpu_type;
+};
+
+struct dp_hdmi_dev {
+ int preset;
+};
+
+/* platform data for the driver model */
+struct nx_display_platdata {
+ int module;
+ struct dp_sync_info sync;
+ struct dp_ctrl_info ctrl;
+ struct dp_plane_top top;
+ struct dp_plane_info plane[DP_PLANS_NUM];
+ int dev_type;
+ void *device;
+};
+
+/* Lcd api */
+void nx_lvds_display(int module,
+ struct dp_sync_info *sync, struct dp_ctrl_info *ctrl,
+ struct dp_plane_top *top,
+ struct dp_plane_info *planes,
+ struct dp_lvds_dev *dev);
+
+void nx_rgb_display(int module,
+ struct dp_sync_info *sync, struct dp_ctrl_info *ctrl,
+ struct dp_plane_top *top, struct dp_plane_info *planes,
+ struct dp_rgb_dev *dev);
+
+void nx_hdmi_display(int module,
+ struct dp_sync_info *sync, struct dp_ctrl_info *ctrl,
+ struct dp_plane_top *top,
+ struct dp_plane_info *planes,
+ struct dp_hdmi_dev *dev);
+
+void nx_mipi_display(int module,
+ struct dp_sync_info *sync, struct dp_ctrl_info *ctrl,
+ struct dp_plane_top *top,
+ struct dp_plane_info *planes,
+ struct dp_mipi_dev *dev);
+
+int nx_mipi_dsi_lcd_bind(struct mipi_dsi_device *dsi);
+
+/* disaply api */
+void dp_control_init(int module);
+int dp_control_setup(int module, struct dp_sync_info *sync,
+ struct dp_ctrl_info *ctrl);
+void dp_control_enable(int module, int on);
+
+void dp_plane_init(int module);
+int dp_plane_screen_setup(int module, struct dp_plane_top *top);
+void dp_plane_screen_enable(int module, int on);
+
+int dp_plane_layer_setup(int module, struct dp_plane_info *plane);
+void dp_plane_layer_enable(int module, struct dp_plane_info *plane, int on);
+
+int dp_plane_set_enable(int module, int layer, int on);
+int dp_plane_set_address(int module, int layer, unsigned int address);
+int dp_plane_wait_vsync(int module, int layer, int fps);
+
+#if defined CONFIG_SPL_BUILD || \
+ (!defined(CONFIG_DM) && !defined(CONFIG_OF_CONTROL))
+int nx_display_probe(struct nx_display_platdata *plat);
+#endif
+
+#endif
diff --git a/arch/arm/mach-nexell/include/mach/display_dev.h b/arch/arm/mach-nexell/include/mach/display_dev.h
new file mode 100644
index 0000000..77eb614
--- /dev/null
+++ b/arch/arm/mach-nexell/include/mach/display_dev.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0+
+ *
+ * Copyright (C) 2016 Nexell Co., Ltd.
+ *
+ * Author: junghyun, kim <jhkim@nexell.co.kr>
+ */
+
+#ifndef _NX__DISPLAY_DEV_H_
+#define _NX__DISPLAY_DEV_H_
+
+#if defined CONFIG_VIDEO || defined CONFIG_DM_VIDEO
+#include <video_fb.h>
+#elif defined CONFIG_LCD
+#include <lcd.h>
+#endif
+
+struct nx_display_dev {
+#if defined CONFIG_VIDEO || defined CONFIG_DM_VIDEO
+ GraphicDevice graphic_device;
+#elif defined CONFIG_LCD
+ vidinfo_t *panel_info;
+#endif
+ unsigned long base;
+ int module;
+ struct dp_sync_info sync;
+ struct dp_ctrl_info ctrl;
+ struct dp_plane_top top;
+ struct dp_plane_info planes[DP_PLANS_NUM];
+ int dev_type;
+ void *device;
+ struct dp_plane_info *fb_plane;
+ unsigned int depth; /* byte per pixel */
+ unsigned int fb_addr;
+ unsigned int fb_size;
+};
+
+#endif
diff --git a/arch/arm/mach-nexell/include/mach/ehci.h b/arch/arm/mach-nexell/include/mach/ehci.h
new file mode 100644
index 0000000..545153b
--- /dev/null
+++ b/arch/arm/mach-nexell/include/mach/ehci.h
@@ -0,0 +1,106 @@
+/* SPDX-License-Identifier: GPL-2.0+
+ *
+ * NEXELL USB HOST EHCI Controller
+ *
+ * (C) Copyright 2016 Nexell
+ * Hyunseok, Jung <hsjung@nexell.co.kr>
+ */
+
+#ifndef __ASM_ARM_ARCH_EHCI_H__
+#define __ASM_ARM_ARCH_EHCI_H__
+
+/* Nexell USBHOST PHY registers */
+
+/* USBHOST Configuration 0 Register */
+#define NX_HOST_CON0 0x14
+#define NX_HOST_CON0_SS_WORD_IF BIT(26)
+#define NX_HOST_CON0_SS_WORD_IF_ENB BIT(25)
+#define NX_HOST_CON0_SS_WORD_IF_16 ( \
+ NX_HOST_CON0_SS_WORD_IF | \
+ NX_HOST_CON0_SS_WORD_IF_ENB)
+
+#define NX_HOST_CON0_HSIC_480M_FROM_OTG_PHY BIT(24)
+#define NX_HOST_CON0_HSIC_FREE_CLOCK_ENB BIT(23)
+#define NX_HOST_CON0_HSIC_CLK_MASK (0x3 << 23)
+
+#define NX_HOST_CON0_N_HOST_HSIC_RESET_SYNC BIT(22)
+#define NX_HOST_CON0_N_HOST_UTMI_RESET_SYNC BIT(21)
+#define NX_HOST_CON0_N_HOST_PHY_RESET_SYNC BIT(20)
+#define NX_HOST_CON0_UTMI_RESET_SYNC ( \
+ NX_HOST_CON0_N_HOST_HSIC_RESET_SYNC | \
+ NX_HOST_CON0_N_HOST_UTMI_RESET_SYNC | \
+ NX_HOST_CON0_N_HOST_PHY_RESET_SYNC)
+
+#define NX_HOST_CON0_N_AUXWELL_RESET_SYNC BIT(19)
+#define NX_HOST_CON0_N_OHCI_RESET_SYNC BIT(18)
+#define NX_HOST_CON0_N_RESET_SYNC BIT(17)
+#define NX_HOST_CON0_AHB_RESET_SYNC ( \
+ NX_HOST_CON0_N_AUXWELL_RESET_SYNC | \
+ NX_HOST_CON0_N_OHCI_RESET_SYNC | \
+ NX_HOST_CON0_N_RESET_SYNC)
+
+#define NX_HOST_CON0_HSIC_EN_PORT1 (0x2 << 14)
+#define NX_HOST_CON0_HSIC_EN_MASK (0x7 << 14)
+
+/* USBHOST Configuration 1 Register */
+#define NX_HOST_CON1 0x18
+
+/* USBHOST Configuration 2 Register */
+#define NX_HOST_CON2 0x1C
+#define NX_HOST_CON2_SS_ENA_INCRX_ALIGN (0x1 << 28)
+#define NX_HOST_CON2_SS_ENA_INCR4 (0x1 << 27)
+#define NX_HOST_CON2_SS_ENA_INCR8 (0x1 << 26)
+#define NX_HOST_CON2_SS_ENA_INCR16 (0x1 << 25)
+#define NX_HOST_CON2_SS_DMA_BURST_MASK \
+ (NX_HOST_CON2_SS_ENA_INCR16 | NX_HOST_CON2_SS_ENA_INCR8 | \
+ NX_HOST_CON2_SS_ENA_INCR4 | NX_HOST_CON2_SS_ENA_INCRX_ALIGN)
+
+#define NX_HOST_CON2_EHCI_SS_ENABLE_DMA_BURST \
+ (NX_HOST_CON2_SS_ENA_INCR16 | NX_HOST_CON2_SS_ENA_INCR8 | \
+ NX_HOST_CON2_SS_ENA_INCR4 | NX_HOST_CON2_SS_ENA_INCRX_ALIGN)
+
+#define NX_HOST_CON2_OHCI_SS_ENABLE_DMA_BURST \
+ (NX_HOST_CON2_SS_ENA_INCR4 | NX_HOST_CON2_SS_ENA_INCRX_ALIGN)
+
+#define NX_HOST_CON2_SS_FLADJ_VAL_0_OFFSET (21)
+#define NX_HOST_CON2_SS_FLADJ_VAL_OFFSET (3)
+#define NX_HOST_CON2_SS_FLADJ_VAL_NUM (6)
+#define NX_HOST_CON2_SS_FLADJ_VAL_0_SEL BIT(5)
+#define NX_HOST_CON2_SS_FLADJ_VAL_MAX 0x7
+
+/* USBHOST Configuration 3 Register */
+#define NX_HOST_CON3 0x20
+#define NX_HOST_CON3_POR BIT(8)
+#define NX_HOST_CON3_POR_ENB BIT(7)
+#define NX_HOST_CON3_POR_MASK (0x3 << 7)
+
+/* USBHOST Configuration 4 Register */
+#define NX_HOST_CON4 0x24
+#define NX_HOST_CON4_WORDINTERFACE BIT(9)
+#define NX_HOST_CON4_WORDINTERFACE_ENB BIT(8)
+#define NX_HOST_CON4_WORDINTERFACE_16 ( \
+ NX_HOST_CON4_WORDINTERFACE | \
+ NX_HOST_CON4_WORDINTERFACE_ENB)
+
+/* USBHOST Configuration 5 Register */
+#define NX_HOST_CON5 0x28
+#define NX_HOST_CON5_HSIC_POR BIT(19)
+#define NX_HOST_CON5_HSIC_POR_ENB BIT(18)
+#define NX_HOST_CON5_HSIC_POR_MASK (0x3 << 18)
+
+/* USBHOST Configuration 6 Register */
+#define NX_HOST_CON6 0x2C
+#define NX_HOST_CON6_HSIC_WORDINTERFACE BIT(13)
+#define NX_HOST_CON6_HSIC_WORDINTERFACE_ENB BIT(12)
+#define NX_HOST_CON6_HSIC_WORDINTERFACE_16 ( \
+ NX_HOST_CON6_HSIC_WORDINTERFACE | \
+ NX_HOST_CON6_HSIC_WORDINTERFACE_ENB)
+
+/* Register map for PHY control */
+struct nx_usb_phy {
+ unsigned int reserved;
+ unsigned int others[4];
+ unsigned int usbhost_con[7];
+};
+
+#endif /* __ASM_ARM_ARCH_EHCI_H__ */
diff --git a/arch/arm/mach-nexell/include/mach/gpio.h b/arch/arm/mach-nexell/include/mach/gpio.h
new file mode 100644
index 0000000..7167d3c
--- /dev/null
+++ b/arch/arm/mach-nexell/include/mach/gpio.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0+
+ *
+ * (C) Copyright 2016 Nexell
+ * DeokJin, Lee <truevirtue@nexell.co.kr>
+ */
+
+#ifndef __ASM_ARCH_NEXELL_GPIO_H
+#define __ASM_ARCH_NEXELL_GPIO_H
+
+#include <asm/io.h>
+#include <linux/errno.h>
+
+#define PIN_BASE 0
+
+#define MAX_GPIO_BANKS 5
+
+#endif /* __ASM_ARCH_NEXELL_GPIO_H */
diff --git a/arch/arm/mach-nexell/include/mach/mipi_display.h b/arch/arm/mach-nexell/include/mach/mipi_display.h
new file mode 100644
index 0000000..f10f4ae
--- /dev/null
+++ b/arch/arm/mach-nexell/include/mach/mipi_display.h
@@ -0,0 +1,219 @@
+/* SPDX-License-Identifier: GPL-2.0+
+ *
+ * Defines for Mobile Industry Processor Interface (MIPI(R))
+ * Display Working Group standards: DSI, DCS, DBI, DPI
+ *
+ * Copyright (C) 2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ * Copyright (C) 2006 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef MIPI_DISPLAY_H
+#define MIPI_DISPLAY_H
+
+/* MIPI DSI Processor-to-Peripheral transaction types */
+enum {
+ MIPI_DSI_V_SYNC_START = 0x01,
+ MIPI_DSI_V_SYNC_END = 0x11,
+ MIPI_DSI_H_SYNC_START = 0x21,
+ MIPI_DSI_H_SYNC_END = 0x31,
+
+ MIPI_DSI_COLOR_MODE_OFF = 0x02,
+ MIPI_DSI_COLOR_MODE_ON = 0x12,
+ MIPI_DSI_SHUTDOWN_PERIPHERAL = 0x22,
+ MIPI_DSI_TURN_ON_PERIPHERAL = 0x32,
+
+ MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM = 0x03,
+ MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM = 0x13,
+ MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM = 0x23,
+
+ MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM = 0x04,
+ MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM = 0x14,
+ MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM = 0x24,
+
+ MIPI_DSI_DCS_SHORT_WRITE = 0x05,
+ MIPI_DSI_DCS_SHORT_WRITE_PARAM = 0x15,
+
+ MIPI_DSI_DCS_READ = 0x06,
+
+ MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE = 0x37,
+
+ MIPI_DSI_END_OF_TRANSMISSION = 0x08,
+
+ MIPI_DSI_NULL_PACKET = 0x09,
+ MIPI_DSI_BLANKING_PACKET = 0x19,
+ MIPI_DSI_GENERIC_LONG_WRITE = 0x29,
+ MIPI_DSI_DCS_LONG_WRITE = 0x39,
+
+ MIPI_DSI_LOOSELY_PACKED_PIXEL_STREAM_YCBCR20 = 0x0c,
+ MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR24 = 0x1c,
+ MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16 = 0x2c,
+
+ MIPI_DSI_PACKED_PIXEL_STREAM_30 = 0x0d,
+ MIPI_DSI_PACKED_PIXEL_STREAM_36 = 0x1d,
+ MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12 = 0x3d,
+
+ MIPI_DSI_PACKED_PIXEL_STREAM_16 = 0x0e,
+ MIPI_DSI_PACKED_PIXEL_STREAM_18 = 0x1e,
+ MIPI_DSI_PIXEL_STREAM_3BYTE_18 = 0x2e,
+ MIPI_DSI_PACKED_PIXEL_STREAM_24 = 0x3e,
+};
+
+/* MIPI DSI Peripheral-to-Processor transaction types */
+enum {
+ MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT = 0x02,
+ MIPI_DSI_RX_END_OF_TRANSMISSION = 0x08,
+ MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE = 0x11,
+ MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE = 0x12,
+ MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE = 0x1a,
+ MIPI_DSI_RX_DCS_LONG_READ_RESPONSE = 0x1c,
+ MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE = 0x21,
+ MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE = 0x22,
+};
+
+/* MIPI DCS commands */
+enum {
+ MIPI_DCS_NOP = 0x00,
+ MIPI_DCS_SOFT_RESET = 0x01,
+ MIPI_DCS_GET_DISPLAY_ID = 0x04,
+ MIPI_DCS_GET_RED_CHANNEL = 0x06,
+ MIPI_DCS_GET_GREEN_CHANNEL = 0x07,
+ MIPI_DCS_GET_BLUE_CHANNEL = 0x08,
+ MIPI_DCS_GET_DISPLAY_STATUS = 0x09,
+ MIPI_DCS_GET_POWER_MODE = 0x0A,
+ MIPI_DCS_GET_ADDRESS_MODE = 0x0B,
+ MIPI_DCS_GET_PIXEL_FORMAT = 0x0C,
+ MIPI_DCS_GET_DISPLAY_MODE = 0x0D,
+ MIPI_DCS_GET_SIGNAL_MODE = 0x0E,
+ MIPI_DCS_GET_DIAGNOSTIC_RESULT = 0x0F,
+ MIPI_DCS_ENTER_SLEEP_MODE = 0x10,
+ MIPI_DCS_EXIT_SLEEP_MODE = 0x11,
+ MIPI_DCS_ENTER_PARTIAL_MODE = 0x12,
+ MIPI_DCS_ENTER_NORMAL_MODE = 0x13,
+ MIPI_DCS_EXIT_INVERT_MODE = 0x20,
+ MIPI_DCS_ENTER_INVERT_MODE = 0x21,
+ MIPI_DCS_SET_GAMMA_CURVE = 0x26,
+ MIPI_DCS_SET_DISPLAY_OFF = 0x28,
+ MIPI_DCS_SET_DISPLAY_ON = 0x29,
+ MIPI_DCS_SET_COLUMN_ADDRESS = 0x2A,
+ MIPI_DCS_SET_PAGE_ADDRESS = 0x2B,
+ MIPI_DCS_WRITE_MEMORY_START = 0x2C,
+ MIPI_DCS_WRITE_LUT = 0x2D,
+ MIPI_DCS_READ_MEMORY_START = 0x2E,
+ MIPI_DCS_SET_PARTIAL_AREA = 0x30,
+ MIPI_DCS_SET_SCROLL_AREA = 0x33,
+ MIPI_DCS_SET_TEAR_OFF = 0x34,
+ MIPI_DCS_SET_TEAR_ON = 0x35,
+ MIPI_DCS_SET_ADDRESS_MODE = 0x36,
+ MIPI_DCS_SET_SCROLL_START = 0x37,
+ MIPI_DCS_EXIT_IDLE_MODE = 0x38,
+ MIPI_DCS_ENTER_IDLE_MODE = 0x39,
+ MIPI_DCS_SET_PIXEL_FORMAT = 0x3A,
+ MIPI_DCS_WRITE_MEMORY_CONTINUE = 0x3C,
+ MIPI_DCS_READ_MEMORY_CONTINUE = 0x3E,
+ MIPI_DCS_SET_TEAR_SCANLINE = 0x44,
+ MIPI_DCS_GET_SCANLINE = 0x45,
+ MIPI_DCS_READ_DDB_START = 0xA1,
+ MIPI_DCS_READ_DDB_CONTINUE = 0xA8,
+};
+
+/* MIPI DCS pixel formats */
+#define MIPI_DCS_PIXEL_FMT_24BIT 7
+#define MIPI_DCS_PIXEL_FMT_18BIT 6
+#define MIPI_DCS_PIXEL_FMT_16BIT 5
+#define MIPI_DCS_PIXEL_FMT_12BIT 3
+#define MIPI_DCS_PIXEL_FMT_8BIT 2
+#define MIPI_DCS_PIXEL_FMT_3BIT 1
+
+/* 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; /* virtual channel id */
+ u8 type; /* payload data type */
+ u16 flags; /* flags controlling this message transmission */
+ size_t tx_len;
+ const void *tx_buf;
+ size_t rx_len;
+ void *rx_buf;
+};
+
+/* 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) /* DSI mode flags */
+
+enum mipi_dsi_pixel_format {
+ MIPI_DSI_FMT_RGB888,
+ MIPI_DSI_FMT_RGB666,
+ MIPI_DSI_FMT_RGB666_PACKED,
+ MIPI_DSI_FMT_RGB565,
+};
+
+/**
+ * struct mipi_dsi_device - DSI peripheral device
+ * @host: DSI host for this peripheral
+ * @dev: driver model device node for this peripheral
+ * @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 {
+ unsigned int channel;
+ unsigned int lanes;
+ enum mipi_dsi_pixel_format format;
+ unsigned long mode_flags;
+ struct mipi_panel_ops *ops;
+ ssize_t (*write_buffer)(struct mipi_dsi_device *dsi,
+ const void *data, size_t len);
+};
+
+struct mipi_panel_ops {
+ int (*init)(struct mipi_dsi_device *dsi, int width, int height);
+ int (*prepare)(struct mipi_dsi_device *dsi);
+ int (*unprepare)(struct mipi_dsi_device *dsi);
+ int (*enable)(struct mipi_dsi_device *dsi);
+ int (*disable)(struct mipi_dsi_device *dsi);
+ void *private_data;
+};
+
+#endif
diff --git a/arch/arm/mach-nexell/include/mach/nexell.h b/arch/arm/mach-nexell/include/mach/nexell.h
new file mode 100644
index 0000000..e42805f
--- /dev/null
+++ b/arch/arm/mach-nexell/include/mach/nexell.h
@@ -0,0 +1,352 @@
+/* SPDX-License-Identifier: GPL-2.0+
+ *
+ * (C) Copyright 2016 Nexell
+ * Hyunseok, Jung <hsjung@nexell.co.kr>
+ */
+
+#ifndef __NEXELL_H__
+#define __NEXELL_H__
+
+#define PHY_BASEADDR_DMA0 (0xC0000000)
+#define PHY_BASEADDR_DMA1 (0xC0001000)
+#if defined(CONFIG_ARCH_S5P4418)
+#define PHY_BASEADDR_INTC0 (0xC0002000)
+#define PHY_BASEADDR_INTC1 (0xC0003000)
+#elif defined(CONFIG_ARCH_S5P6818)
+#define PHY_BASEADDR_INTC (0xC0008000)
+#endif
+#define PHY_BASEADDR_CLKPWR (0xC0010000)
+#define PHY_BASEADDR_RTC (0xC0010C00)
+#define PHY_BASEADDR_ALIVE (0xC0010800)
+#define PHY_BASEADDR_RSTCON (0xC0012000)
+#define PHY_BASEADDR_TIEOFF (0xC0011000)
+#define PHY_BASEADDR_PDM (0xC0014000)
+#define PHY_BASEADDR_CRYPTO (0xC0015000)
+#define PHY_BASEADDR_TIMER (0xC0017000)
+#define PHY_BASEADDR_PWM (0xC0018000)
+#define PHY_BASEADDR_WDT (0xC0019000)
+#define PHY_BASEADDR_GPIOA (0xC001A000)
+#define PHY_BASEADDR_GPIOB (0xC001B000)
+#define PHY_BASEADDR_GPIOC (0xC001C000)
+#define PHY_BASEADDR_GPIOD (0xC001D000)
+#define PHY_BASEADDR_GPIOE (0xC001E000)
+#define PHY_BASEADDR_OHCI (0xC0020000)
+#define PHY_BASEADDR_EHCI (0xC0030000)
+#define PHY_BASEADDR_HSOTG (0xC0040000)
+#define PHY_BASEADDR_ADC (0xC0053000)
+#define PHY_BASEADDR_PPM (0xC0054000)
+#define PHY_BASEADDR_I2S0 (0xC0055000)
+#define PHY_BASEADDR_I2S1 (0xC0056000)
+#define PHY_BASEADDR_I2S2 (0xC0057000)
+#define PHY_BASEADDR_AC97 (0xC0058000)
+#define PHY_BASEADDR_SPDIF_TX (0xC0059000)
+#define PHY_BASEADDR_SPDIF_RX (0xC005A000)
+#define PHY_BASEADDR_SSP0 (0xC005B000)
+#define PHY_BASEADDR_SSP1 (0xC005C000)
+#define PHY_BASEADDR_SSP2 (0xC005F000)
+#define PHY_BASEADDR_MPEGTSI (0xC005D000)
+#define PHY_BASEADDR_GMAC (0xC0060000)
+#define PHY_BASEADDR_VIP0 (0xC0063000)
+#define PHY_BASEADDR_VIP1 (0xC0064000)
+#if defined(CONFIG_ARCH_S5P6818)
+#define PHY_BASEADDR_VIP2 (0xC0099000)
+#endif
+#define PHY_BASEADDR_DEINTERLACE (0xC0065000)
+#define PHY_BASEADDR_SCALER (0xC0066000)
+#define PHY_BASEADDR_ECID (0xC0067000)
+#define PHY_BASEADDR_SDMMC0 (0xC0062000)
+#define PHY_BASEADDR_SDMMC1 (0xC0068000)
+#define PHY_BASEADDR_SDMMC2 (0xC0069000)
+#define PHY_BASEADDR_MALI400 (0xC0070000)
+#define PHY_BASEADDR_CODA_APB0 (0xC0080000)
+#define PHY_BASEADDR_CODA_APB1 (0xC0081000)
+#define PHY_BASEADDR_CODA_APB2 (0xC0082000)
+#define PHY_BASEADDR_CODA_APB3 (0xC0083000)
+/* dma (O), modem(X), UART0_MODULE */
+#define PHY_BASEADDR_UART0 (0xC00A1000)
+/* dma (O), modem(O), pl01115_Uart_modem_MODULE */
+#define PHY_BASEADDR_UART1 (0xC00A0000)
+/* dma (O), modem(X), UART1_MODULE */
+#define PHY_BASEADDR_UART2 (0xC00A2000)
+/* dma (X), modem(X), pl01115_Uart_nodma0_MODULE */
+#define PHY_BASEADDR_UART3 (0xC00A3000)
+/* dma (X), modem(X), pl01115_Uart_nodma1_MODULE */
+#define PHY_BASEADDR_UART4 (0xC006D000)
+/* dma (X), modem(X), pl01115_Uart_nodma2_MODULE */
+#define PHY_BASEADDR_UART5 (0xC006F000)
+#define PHY_BASEADDR_I2C0 (0xC00A4000)
+#define PHY_BASEADDR_I2C1 (0xC00A5000)
+#define PHY_BASEADDR_I2C2 (0xC00A6000)
+#define PHY_BASEADDR_CAN0 (0xC00CE000)
+#define PHY_BASEADDR_CAN1 (0xC00CF000)
+#define PHY_BASEADDR_MIPI (0xC00D0000)
+#define PHY_BASEADDR_DISPLAYTOP (0xC0100000)
+
+#define PHY_BASEADDR_CLKGEN0 (0xC00BB000) /* TIMER_1 */
+#define PHY_BASEADDR_CLKGEN1 (0xC00BC000) /* TIMER_2 */
+#define PHY_BASEADDR_CLKGEN2 (0xC00BD000) /* TIMER_3 */
+#define PHY_BASEADDR_CLKGEN3 (0xC00BE000) /* PWM_1 */
+#define PHY_BASEADDR_CLKGEN4 (0xC00BF000) /* PWM_2 */
+#define PHY_BASEADDR_CLKGEN5 (0xC00C0000) /* PWM_3 */
+#define PHY_BASEADDR_CLKGEN6 (0xC00AE000) /* I2C_0 */
+#define PHY_BASEADDR_CLKGEN7 (0xC00AF000) /* I2C_1 */
+#define PHY_BASEADDR_CLKGEN8 (0xC00B0000) /* I2C_2 */
+#define PHY_BASEADDR_CLKGEN9 (0xC00CA000) /* MIPI */
+#define PHY_BASEADDR_CLKGEN10 (0xC00C8000) /* GMAC */
+#define PHY_BASEADDR_CLKGEN11 (0xC00B8000) /* SPDIF_TX */
+#define PHY_BASEADDR_CLKGEN12 (0xC00B7000) /* MPEGTSI */
+#define PHY_BASEADDR_CLKGEN13 (0xC00BA000) /* PWM_0 */
+#define PHY_BASEADDR_CLKGEN14 (0xC00B9000) /* TIMER_0 */
+#define PHY_BASEADDR_CLKGEN15 (0xC00B2000) /* I2S_0 */
+#define PHY_BASEADDR_CLKGEN16 (0xC00B3000) /* I2S_1 */
+#define PHY_BASEADDR_CLKGEN17 (0xC00B4000) /* I2S_2 */
+#define PHY_BASEADDR_CLKGEN18 (0xC00C5000) /* SDHC_0 */
+#define PHY_BASEADDR_CLKGEN19 (0xC00CC000) /* SDHC_1 */
+#define PHY_BASEADDR_CLKGEN20 (0xC00CD000) /* SDHC_2 */
+#define PHY_BASEADDR_CLKGEN21 (0xC00C3000) /* MALI */
+#define PHY_BASEADDR_CLKGEN22 (0xC00A9000) /* UART_0 */
+#define PHY_BASEADDR_CLKGEN23 (0xC00AA000) /* UART_2 */
+#define PHY_BASEADDR_CLKGEN24 (0xC00A8000) /* UART_1 */
+#define PHY_BASEADDR_CLKGEN25 (0xC00AB000) /* UART_3 */
+#define PHY_BASEADDR_CLKGEN26 (0xC006E000) /* UART_4 */
+#define PHY_BASEADDR_CLKGEN27 (0xC00B1000) /* UART_5 */
+#define PHY_BASEADDR_CLKGEN28 (0xC00B5000) /* DEINTERLACE */
+#define PHY_BASEADDR_CLKGEN29 (0xC00C4000) /* PPM */
+#define PHY_BASEADDR_CLKGEN30 (0xC00C1000) /* VIP_0 */
+#define PHY_BASEADDR_CLKGEN31 (0xC00C2000) /* VIP_1 */
+#define PHY_BASEADDR_CLKGEN32 (0xC006B000) /* USB2HOST */
+#define PHY_BASEADDR_CLKGEN33 (0xC00C7000) /* CODA */
+#define PHY_BASEADDR_CLKGEN34 (0xC00C6000) /* CRYPTO */
+#define PHY_BASEADDR_CLKGEN35 (0xC00B6000) /* SCALER */
+#define PHY_BASEADDR_CLKGEN36 (0xC00CB000) /* PDM */
+#define PHY_BASEADDR_CLKGEN37 (0xC00AC000) /* SPI0 */
+#define PHY_BASEADDR_CLKGEN38 (0xC00AD000) /* SPI1 */
+#define PHY_BASEADDR_CLKGEN39 (0xC00A7000) /* SPI2 */
+#if defined(CONFIG_ARCH_S5P6818)
+#define PHY_BASEADDR_CLKGEN40 (0xC009A000)
+#endif
+#define PHY_BASEADDR_DREX (0xC00E0000)
+
+#define PHY_BASEADDR_CS_NAND (0x2C000000)
+
+#define PHY_BASEADDR_SRAM (0xFFFF0000)
+
+/*
+ * Nexell clock generator
+ */
+#define CLK_ID_TIMER_1 0
+#define CLK_ID_TIMER_2 1
+#define CLK_ID_TIMER_3 2
+#define CLK_ID_PWM_1 3
+#define CLK_ID_PWM_2 4
+#define CLK_ID_PWM_3 5
+#define CLK_ID_I2C_0 6
+#define CLK_ID_I2C_1 7
+#define CLK_ID_I2C_2 8
+#define CLK_ID_MIPI 9
+#define CLK_ID_GMAC 10 /* External Clock 1 */
+#define CLK_ID_SPDIF_TX 11
+#define CLK_ID_MPEGTSI 12
+#define CLK_ID_PWM_0 13
+#define CLK_ID_TIMER_0 14
+#define CLK_ID_I2S_0 15 /* External Clock 1 */
+#define CLK_ID_I2S_1 16 /* External Clock 1 */
+#define CLK_ID_I2S_2 17 /* External Clock 1 */
+#define CLK_ID_SDHC_0 18
+#define CLK_ID_SDHC_1 19
+#define CLK_ID_SDHC_2 20
+#define CLK_ID_MALI 21
+#define CLK_ID_UART_0 22 /* UART0_MODULE */
+#define CLK_ID_UART_2 23 /* UART1_MODULE */
+#define CLK_ID_UART_1 24 /* pl01115_Uart_modem_MODULE */
+#define CLK_ID_UART_3 25 /* pl01115_Uart_nodma0_MODULE */
+#define CLK_ID_UART_4 26 /* pl01115_Uart_nodma1_MODULE */
+#define CLK_ID_UART_5 27 /* pl01115_Uart_nodma2_MODULE */
+#define CLK_ID_DIT 28
+#define CLK_ID_PPM 29
+#define CLK_ID_VIP_0 30 /* External Clock 1 */
+#define CLK_ID_VIP_1 31 /* External Clock 1, 2 */
+#define CLK_ID_USB2HOST 32 /* External Clock 2 */
+#define CLK_ID_CODA 33
+#define CLK_ID_CRYPTO 34
+#define CLK_ID_SCALER 35
+#define CLK_ID_PDM 36
+#define CLK_ID_SPI_0 37
+#define CLK_ID_SPI_1 38
+#define CLK_ID_SPI_2 39
+#define CLK_ID_MAX 39
+
+/*
+ * Nexell Reset control
+ */
+#define RESET_ID_AC97 0
+#define RESET_ID_CPU1 1
+#define RESET_ID_CPU2 2
+#define RESET_ID_CPU3 3
+#define RESET_ID_WD1 4
+#define RESET_ID_WD2 5
+#define RESET_ID_WD3 6
+#define RESET_ID_CRYPTO 7
+#define RESET_ID_DEINTERLACE 8
+#define RESET_ID_DISP_TOP 9
+#define RESET_ID_DISPLAY 10
+#define RESET_ID_RESCONV 11
+#define RESET_ID_LCDIF 12
+#define RESET_ID_HDMI 13
+#define RESET_ID_HDMI_VIDEO 14
+#define RESET_ID_HDMI_SPDIF 15
+#define RESET_ID_HDMI_TMDS 16
+#define RESET_ID_HDMI_PHY 17
+#define RESET_ID_LVDS 18
+#define RESET_ID_ECID 19
+#define RESET_ID_I2C0 20
+#define RESET_ID_I2C1 21
+#define RESET_ID_I2C2 22
+#define RESET_ID_I2S0 23
+#define RESET_ID_I2S1 24
+#define RESET_ID_I2S2 25
+#define RESET_ID_DREX_C 26
+#define RESET_ID_DREX_A 27
+#define RESET_ID_DREX 28
+#define RESET_ID_MIPI 29
+#define RESET_ID_MIPI_DSI 30
+#define RESET_ID_MIPI_CSI 31
+#define RESET_ID_MIPI_PHY_S 32
+#define RESET_ID_MIPI_PHY_M 33
+#define RESET_ID_MPEGTSI 34
+#define RESET_ID_PDM 35
+#define RESET_ID_TIMER 36
+#define RESET_ID_PWM 37
+#define RESET_ID_SCALER 38
+#define RESET_ID_SDMMC0 39
+#define RESET_ID_SDMMC1 40
+#define RESET_ID_SDMMC2 41
+#define RESET_ID_SPDIFRX 42
+#define RESET_ID_SPDIFTX 43
+#define RESET_ID_SSP0_P 44
+#define RESET_ID_SSP0 45
+#define RESET_ID_SSP1_P 46
+#define RESET_ID_SSP1 47
+#define RESET_ID_SSP2_P 48
+#define RESET_ID_SSP2 49
+#define RESET_ID_UART0 50 /* UART1 */
+#define RESET_ID_UART1 51 /* pl01115_Uart_modem */
+#define RESET_ID_UART2 52 /* UART1 */
+#define RESET_ID_UART3 53 /* pl01115_Uart_nodma0 */
+#define RESET_ID_UART4 54 /* pl01115_Uart_nodma1 */
+#define RESET_ID_UART5 55 /* pl01115_Uart_nodma2 */
+#define RESET_ID_USB20HOST 56
+#define RESET_ID_USB20OTG 57
+#define RESET_ID_WDT 58
+#define RESET_ID_WDT_POR 59
+#define RESET_ID_ADC 60
+#define RESET_ID_CODA_A 61
+#define RESET_ID_CODA_P 62
+#define RESET_ID_CODA_C 63
+#define RESET_ID_DWC_GMAC 64
+#define RESET_ID_MALI400 65
+#define RESET_ID_PPM 66
+#define RESET_ID_VIP1 67
+#define RESET_ID_VIP0 68
+#if defined(CONFIG_ARCH_S5P6818)
+#define RESET_ID_VIP2 69
+#endif
+
+/*
+ * device name
+ */
+#define DEV_NAME_UART "nx-uart" /* pl0115 (amba-pl011.c) */
+#define DEV_NAME_FB "nx-fb"
+#define DEV_NAME_DISP "nx-disp"
+#define DEV_NAME_LCD "nx-lcd"
+#define DEV_NAME_LVDS "nx-lvds"
+#define DEV_NAME_HDMI "nx-hdmi"
+#define DEV_NAME_RESCONV "nx-resconv"
+#define DEV_NAME_MIPI "nx-mipi"
+#define DEV_NAME_PCM "nx-pcm"
+#define DEV_NAME_I2S "nx-i2s"
+#define DEV_NAME_SPDIF_TX "nx-spdif-tx"
+#define DEV_NAME_SPDIF_RX "nx-spdif-rx"
+#define DEV_NAME_I2C "nx-i2c"
+#define DEV_NAME_NAND "nx-nand"
+#define DEV_NAME_KEYPAD "nx-keypad"
+#define DEV_NAME_SDHC "nx-sdhc"
+#define DEV_NAME_PWM "nx-pwm"
+#define DEV_NAME_TIMER "nx-timer"
+#define DEV_NAME_SOC_PWM "nx-soc-pwm"
+#define DEV_NAME_GPIO "nx-gpio"
+#define DEV_NAME_RTC "nx-rtc"
+#define DEV_NAME_GMAC "nx-gmac"
+#define DEV_NAME_MPEGTSI "nx-mpegtsi"
+#define DEV_NAME_MALI "nx-mali"
+#define DEV_NAME_DIT "nx-deinterlace"
+#define DEV_NAME_PPM "nx-ppm"
+#define DEV_NAME_VIP "nx-vip"
+#define DEV_NAME_CODA "nx-coda"
+#define DEV_NAME_USB2HOST "nx-usb2h"
+#define DEV_NAME_CRYPTO "nx-crypto"
+#define DEV_NAME_SCALER "nx-scaler"
+#define DEV_NAME_PDM "nx-pdm"
+#define DEV_NAME_SPI "nx-spi"
+#define DEV_NAME_CPUFREQ "nx-cpufreq"
+
+/*
+ * clock generator
+ */
+#define CORECLK_NAME_PLL0 "pll0" /* cpu clock */
+#define CORECLK_NAME_PLL1 "pll1"
+#define CORECLK_NAME_PLL2 "pll2"
+#define CORECLK_NAME_PLL3 "pll3"
+#define CORECLK_NAME_FCLK "fclk"
+#define CORECLK_NAME_MCLK "mclk"
+#define CORECLK_NAME_BCLK "bclk"
+#define CORECLK_NAME_PCLK "pclk"
+#define CORECLK_NAME_HCLK "hclk"
+
+#define CORECLK_ID_PLL0 0
+#define CORECLK_ID_PLL1 1
+#define CORECLK_ID_PLL2 2
+#define CORECLK_ID_PLL3 3
+#define CORECLK_ID_FCLK 4
+#define CORECLK_ID_MCLK 5
+#define CORECLK_ID_BCLK 6
+#define CORECLK_ID_PCLK 7
+#define CORECLK_ID_HCLK 8
+
+#define ALIVEPWRGATEREG (PHY_BASEADDR_ALIVE + 0x0)
+
+#if defined(CONFIG_ARCH_S5P4418)
+#define SCR_ARM_SECOND_BOOT (0xC0010C1C) /* PWR scratch */
+#define SCR_ARM_SECOND_BOOT_REG1 (0xc0010234) /* ToDo : Check Address */
+#elif defined(CONFIG_ARCH_S5P6818)
+#define SCR_ARM_SECOND_BOOT (0xc0010230) /* PWR scratch */
+#define SCR_ARM_SECOND_BOOT_REG1 (0xc0010234) /* PWR scratch */
+#define SCR_ARM_SECOND_BOOT_REG2 (0xc0010238) /* PWR scratch */
+#endif
+
+#define SCR_ALIVE_BASE (PHY_BASEADDR_ALIVE)
+#define SCR_SIGNAGURE_RESET (SCR_ALIVE_BASE + 0x068)
+#define SCR_SIGNAGURE_SET (SCR_ALIVE_BASE + 0x06C)
+#define SCR_SIGNAGURE_READ (SCR_ALIVE_BASE + 0x070)
+
+#define SYSRSTCONFIG (0x23C)
+#define DEVICEBOOTINFO (0x50)
+#define BOOTMODE_MASK (0x7)
+#define BOOTMODE_SDMMC 5
+#define BOOTMODE_USB 6
+#define BOOTMODE_SDMMC_PORT_VAL(x) ((((x) >> 3) & 1) | \
+ (((x) >> 19 & 1) << 1))
+#define EMMC_PORT_NUM 2
+#define SD_PORT_NUM 0
+#define ID_REG_EC0 (0x54)
+#define WIRE0_MASK (0x1)
+
+#ifndef __ASSEMBLY__
+
+#define NS_IN_HZ (1000000000UL)
+#define TO_PERIOD_NS(freq) (NS_IN_HZ / (freq))
+#define TO_DUTY_NS(duty, freq) (duty ? TO_PERIOD_NS(freq) / (100 / duty) : 0)
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __NEXELL_H__ */
diff --git a/arch/arm/mach-nexell/include/mach/nx_gpio.h b/arch/arm/mach-nexell/include/mach/nx_gpio.h
new file mode 100644
index 0000000..91803d2
--- /dev/null
+++ b/arch/arm/mach-nexell/include/mach/nx_gpio.h
@@ -0,0 +1,103 @@
+/* SPDX-License-Identifier: GPL-2.0+
+ *
+ * (C) Copyright 2016 Nexell
+ * Youngbok, Park <ybpark@nexell.co.kr>
+ */
+
+#include <linux/types.h>
+#include <asm/io.h>
+
+#ifndef __nx_gpio_h__
+#define __nx_gpio_h__
+
+struct nx_gpio_register_set {
+ u32 gpioxout;
+ u32 gpioxoutenb;
+ u32 gpioxdetmode[2];
+ u32 gpioxintenb;
+ u32 gpioxdet;
+ u32 gpioxpad;
+ u32 gpioxpuenb;
+ u32 gpioxaltfn[2];
+ u32 gpioxdetmodeex;
+ u32 __reserved[4];
+ u32 gpioxdetenb;
+ u32 gpiox_slew;
+ u32 gpiox_slew_disable_default;
+ u32 gpiox_drv1;
+ u32 gpiox_drv1_disable_default;
+ u32 gpiox_drv0;
+ u32 gpiox_drv0_disable_default;
+ u32 gpiox_pullsel;
+ u32 gpiox_pullsel_disable_default;
+ u32 gpiox_pullenb;
+ u32 gpiox_pullenb_disable_default;
+ u32 gpiox_input_mux_select0;
+ u32 gpiox_input_mux_select1;
+ u8 __reserved1[0x1000 - 0x70];
+};
+
+enum {
+ nx_gpio_padfunc_0 = 0ul,
+ nx_gpio_padfunc_1 = 1ul,
+ nx_gpio_padfunc_2 = 2ul,
+ nx_gpio_padfunc_3 = 3ul
+};
+
+enum {
+ nx_gpio_drvstrength_0 = 0ul,
+ nx_gpio_drvstrength_1 = 1ul,
+ nx_gpio_drvstrength_2 = 2ul,
+ nx_gpio_drvstrength_3 = 3ul
+};
+
+enum {
+ nx_gpio_pull_down = 0ul,
+ nx_gpio_pull_up = 1ul,
+ nx_gpio_pull_off = 2ul
+};
+
+int nx_gpio_initialize(void);
+u32 nx_gpio_get_number_of_module(void);
+u32 nx_gpio_get_size_of_register_set(void);
+void nx_gpio_set_base_address(u32 module_index, void *base_address);
+void *nx_gpio_get_base_address(u32 module_index);
+int nx_gpio_open_module(u32 module_index);
+int nx_gpio_close_module(u32 module_index);
+int nx_gpio_check_busy(u32 module_index);
+void nx_gpio_set_detect_enable(u32 module_index, u32 bit_number,
+ int detect_enb);
+void nx_gpio_set_pad_function(u32 module_index, u32 bit_number, u32 padfunc);
+void nx_gpio_set_pad_function32(u32 module_index, u32 msbvalue, u32 lsbvalue);
+int nx_gpio_get_pad_function(u32 module_index, u32 bit_number);
+void nx_gpio_set_output_enable(u32 module_index, u32 bit_number,
+ int output_enb);
+int nx_gpio_get_detect_enable(u32 module_index, u32 bit_number);
+u32 nx_gpio_get_detect_enable32(u32 module_index);
+void nx_gpio_set_detect_enable(u32 module_index, u32 bit_number,
+ int detect_enb);
+void nx_gpio_set_detect_enable32(u32 module_index, u32 enable_flag);
+int nx_gpio_get_output_enable(u32 module_index, u32 bit_number);
+void nx_gpio_set_output_enable32(u32 module_index, int output_enb);
+u32 nx_gpio_get_output_enable32(u32 module_index);
+void nx_gpio_set_output_value(u32 module_index, u32 bit_number, int value);
+int nx_gpio_get_output_value(u32 module_index, u32 bit_number);
+void nx_gpio_set_output_value32(u32 module_index, u32 value);
+u32 nx_gpio_get_output_value32(u32 module_index);
+int nx_gpio_get_input_value(u32 module_index, u32 bit_number);
+void nx_gpio_set_pull_select(u32 module_index, u32 bit_number, int enable);
+void nx_gpio_set_pull_select32(u32 module_index, u32 value);
+int nx_gpio_get_pull_select(u32 module_index, u32 bit_number);
+u32 nx_gpio_get_pull_select32(u32 module_index);
+void nx_gpio_set_pull_mode(u32 module_index, u32 bit_number, u32 mode);
+void nx_gpio_set_fast_slew(u32 module_index, u32 bit_number, int enable);
+void nx_gpio_set_drive_strength_disable_default(u32 module_index,
+ u32 bit_number, int enable);
+void nx_gpio_set_drive_strength_disable_default(u32 module_index,
+ u32 bit_number, int enable);
+void nx_gpio_set_drive_strength(u32 module_index, u32 bit_number,
+ u32 drvstrength);
+void nx_gpio_set_drive_strength_disable_default(u32 module_index,
+ u32 bit_number, int enable);
+u32 nx_gpio_get_drive_strength(u32 module_index, u32 bit_number);
+#endif
diff --git a/arch/arm/mach-nexell/include/mach/reset.h b/arch/arm/mach-nexell/include/mach/reset.h
new file mode 100644
index 0000000..e1301d4
--- /dev/null
+++ b/arch/arm/mach-nexell/include/mach/reset.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0+
+ *
+ * (C) Copyright 2016 Nexell
+ * Youngbok, Park <ybpark@nexell.co.kr>
+ */
+
+#ifndef __NEXELL_RESET__
+#define __NEXELL_RESET__
+
+#define NUMBER_OF_RESET_MODULE_PIN 69
+
+enum rstcon {
+ RSTCON_ASSERT = 0UL,
+ RSTCON_NEGATE = 1UL
+};
+
+void nx_rstcon_setrst(u32 rstindex, enum rstcon status);
+
+#endif /* __NEXELL_RESET__ */
diff --git a/arch/arm/mach-nexell/include/mach/sec_reg.h b/arch/arm/mach-nexell/include/mach/sec_reg.h
new file mode 100644
index 0000000..e3ae5ac
--- /dev/null
+++ b/arch/arm/mach-nexell/include/mach/sec_reg.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0+
+ *
+ * (C) Copyright 2016 Nexell
+ * Youngbok, Park <park@nexell.co.kr>
+ */
+
+#define NEXELL_L2C_SEC_ID 0
+#define NEXELL_MALI_SEC_ID 2
+#define NEXELL_MIPI_SEC_ID 4
+#define NEXELL_TOFF_SEC_ID 6
+
+int write_sec_reg_by_id(void __iomem *reg, int val, int id);
+int read_sec_reg_by_id(void __iomem *reg, int id);
+int read_sec_reg(void __iomem *reg);
+int write_sec_reg(void __iomem *reg, int val);
diff --git a/arch/arm/mach-nexell/include/mach/tieoff.h b/arch/arm/mach-nexell/include/mach/tieoff.h
new file mode 100644
index 0000000..70e9652
--- /dev/null
+++ b/arch/arm/mach-nexell/include/mach/tieoff.h
@@ -0,0 +1,423 @@
+/* SPDX-License-Identifier: GPL-2.0+
+ *
+ * (C) Copyright 2016 Nexell
+ * Youngbok, Park <park@nexell.co.kr>
+ */
+
+#ifndef _NEXELL_TIEOFF_H
+#define _NEXELL_TIEOFF_H
+
+void nx_tieoff_set(u32 tieoff_index, u32 tieoff_value);
+u32 nx_tieoff_get(u32 tieoff_index);
+
+#if defined(CONFIG_ARCH_S5P4418)
+#define NX_TIEOFF_CORTEXA9MP_TOP_QUADL2C_CLAMPCOREOUT ((1 << 16) | 0)
+#define NX_TIEOFF_CORTEXA9MP_TOP_QUADL2C_CLAMPCPU0 ((1 << 16) | 1)
+#define NX_TIEOFF_CORTEXA9MP_TOP_QUADL2C_CLAMPCPU1 ((1 << 16) | 2)
+#define NX_TIEOFF_CORTEXA9MP_TOP_QUADL2C_CLAMPCPU2 ((1 << 16) | 3)
+#define NX_TIEOFF_CORTEXA9MP_TOP_QUADL2C_CLAMPCPU3 ((1 << 16) | 4)
+#define NX_TIEOFF_CORTEXA9MP_TOP_QUADL2C_COREPWRDOWN ((1 << 16) | 5)
+#define NX_TIEOFF_CORTEXA9MP_TOP_QUADL2C_CPU0PWRDOWN ((1 << 16) | 6)
+#define NX_TIEOFF_CORTEXA9MP_TOP_QUADL2C_CPU1PWRDOWN ((1 << 16) | 7)
+#define NX_TIEOFF_CORTEXA9MP_TOP_QUADL2C_CPU2PWRDOWN ((1 << 16) | 8)
+#define NX_TIEOFF_CORTEXA9MP_TOP_QUADL2C_CPU3PWRDOWN ((1 << 16) | 9)
+#define NX_TIEOFF_CORTEXA9MP_TOP_QUADL2C_L2_CFGENDIAN ((1 << 16) | 10)
+#define NX_TIEOFF_CORTEXA9MP_TOP_QUADL2C_L1EMAS ((1 << 16) | 11)
+#define NX_TIEOFF_CORTEXA9MP_TOP_QUADL2C_L2RET1N_0 ((1 << 16) | 12)
+#define NX_TIEOFF_CORTEXA9MP_TOP_QUADL2C_L2RET1N_1 ((1 << 16) | 13)
+#define NX_TIEOFF_CORTEXA9MP_TOP_QUADL2C_L2PGEN_0 ((1 << 16) | 14)
+#define NX_TIEOFF_CORTEXA9MP_TOP_QUADL2C_L2PGEN_1 ((1 << 16) | 15)
+#define NX_TIEOFF_CORTEXA9MP_TOP_QUADL2C_CLAMPL2_0 ((1 << 16) | 16)
+#define NX_TIEOFF_CORTEXA9MP_TOP_QUADL2C_CLAMPL2_1 ((1 << 16) | 17)
+#define NX_TIEOFF_CORTEXA9MP_TOP_QUADL2C_VINITHI ((4 << 16) | 18)
+#define NX_TIEOFF_CORTEXA9MP_TOP_QUADL2C_L2EMA ((3 << 16) | 22)
+#define NX_TIEOFF_CORTEXA9MP_TOP_QUADL2C_TEINIT ((4 << 16) | 25)
+#define NX_TIEOFF_CORTEXA9MP_TOP_QUADL2C_L1EMAW ((2 << 16) | 29)
+#define NX_TIEOFF_CORTEXA9MP_TOP_QUADL2C_L2EMAW ((2 << 16) | 32)
+#define NX_TIEOFF_CORTEXA9MP_TOP_QUADL2C_L1EMA ((3 << 16) | 34)
+#define NX_TIEOFF_CORTEXA9MP_TOP_QUADL2C_CPUCLKOFF ((4 << 16) | 37)
+#define NX_TIEOFF_CORTEXA9MP_TOP_QUADL2C_PWRCTLI0 ((2 << 16) | 41)
+#define NX_TIEOFF_CORTEXA9MP_TOP_QUADL2C_PWRCTLI1 ((2 << 16) | 43)
+#define NX_TIEOFF_CORTEXA9MP_TOP_QUADL2C_PWRCTLI2 ((2 << 16) | 45)
+#elif defined(CONFIG_ARCH_S5P6818)
+#define NX_TIEOFF_MMC_8BIT ((1 << 16) | 5)
+#endif
+#define NX_TIEOFF_AXISRAM0_i_TIE_ra2w_EMAA ((3 << 16) | 47)
+#define NX_TIEOFF_AXISRAM0_i_TIE_ra2w_EMAB ((3 << 16) | 50)
+#define NX_TIEOFF_AXISRAM0_i_TIE_ra2w_EMAWA ((2 << 16) | 53)
+#define NX_TIEOFF_AXISRAM0_i_TIE_ra2w_EMAWB ((2 << 16) | 55)
+#define NX_TIEOFF_AXISRAM0_i_nPowerDown ((1 << 16) | 57)
+#define NX_TIEOFF_AXISRAM0_i_nSleep ((1 << 16) | 58)
+#define NX_TIEOFF_CAN0_i_TIE_rf1_EMA ((3 << 16) | 59)
+#define NX_TIEOFF_CAN0_i_TIE_rf1_EMAW ((2 << 16) | 62)
+#define NX_TIEOFF_CAN0_i_nPowerDown ((1 << 16) | 64)
+#define NX_TIEOFF_CAN0_i_nSleep ((1 << 16) | 65)
+#define NX_TIEOFF_CAN1_i_TIE_rf1_EMA ((3 << 16) | 66)
+#define NX_TIEOFF_CAN1_i_TIE_rf1_EMAW ((2 << 16) | 69)
+#define NX_TIEOFF_CAN1_i_nPowerDown ((1 << 16) | 71)
+#define NX_TIEOFF_CAN1_i_nSleep ((1 << 16) | 72)
+#define NX_TIEOFF_DEINTERLACE0_i_NX_RF1_EMA ((3 << 16) | 73)
+#define NX_TIEOFF_DEINTERLACE0_i_NX_RF1_EMAW ((2 << 16) | 76)
+#define NX_TIEOFF_DEINTERLACE0_i_NX_RF2_EMAA ((3 << 16) | 78)
+#define NX_TIEOFF_DEINTERLACE0_i_NX_RF2_EMAB ((3 << 16) | 81)
+#define NX_TIEOFF_DEINTERLACE0_i_NX_RF2W_EMAA ((3 << 16) | 84)
+#define NX_TIEOFF_DEINTERLACE0_i_NX_RF2W_EMAB ((3 << 16) | 87)
+#define NX_TIEOFF_DISPLAYTOP0_i_ResConv_nPowerDown ((1 << 16) | 90)
+#define NX_TIEOFF_DISPLAYTOP0_i_ResConv_nSleep ((1 << 16) | 91)
+#define NX_TIEOFF_DISPLAYTOP0_i_HDMI_nPowerDown ((2 << 16) | 92)
+#define NX_TIEOFF_DISPLAYTOP0_i_HDMI_nSleep ((2 << 16) | 94)
+#define NX_TIEOFF_DISPLAYTOP0_i_HDMI_PHY_REFCLK_SEL ((1 << 16) | 96)
+#define NX_TIEOFF_DISPLAYTOP0_i_TIEOFF_SPSRAM_EMA ((3 << 16) | 97)
+#define NX_TIEOFF_DISPLAYTOP0_i_TIEOFF_SPSRAM_EMAW ((2 << 16) | 100)
+#define NX_TIEOFF_DISPLAYTOP0_i_TIEOFF_DPSRAM_1R1W_EMAA ((3 << 16) | 102)
+#define NX_TIEOFF_DISPLAYTOP0_i_TIEOFF_DPSRAM_1R1W_EMAB ((3 << 16) | 105)
+#define NX_TIEOFF_DISPLAYTOP0_i_TIEOFF_DPSRAM_EMAA ((3 << 16) | 108)
+#define NX_TIEOFF_DISPLAYTOP0_i_TIEOFF_DPSRAM_EMAB ((3 << 16) | 111)
+#define NX_TIEOFF_DISPLAYTOP0_i_TIEOFF_DPSRAM_EMAWA ((2 << 16) | 114)
+#define NX_TIEOFF_DISPLAYTOP0_i_TIEOFF_DPSRAM_EMAWB ((2 << 16) | 116)
+#define NX_TIEOFF_MCUSTOP0_i_vrom_EMA ((3 << 16) | 118)
+#define NX_TIEOFF_DREX0_CKE_INIT ((1 << 16) | 121)
+#define NX_TIEOFF_DREX0_CA_SWAP ((1 << 16) | 122)
+#define NX_TIEOFF_DREX0_CSYSREQ ((1 << 16) | 123)
+#define NX_TIEOFF_DREX0_PAUSE_REQ ((1 << 16) | 124)
+#define NX_TIEOFF_DREX0_PEREV_TRIGGER ((1 << 16) | 125)
+#define NX_TIEOFF_DREX0_CTRL_HCKE ((1 << 16) | 126)
+#define NX_TIEOFF_DREX0_DFI_RESET_N_P0 ((1 << 16) | 127)
+#define NX_TIEOFF_DREX0_DFI_RESET_N_P1 ((1 << 16) | 128)
+#define NX_TIEOFF_MIPI0_NX_DPSRAM_1R1W_EMAA ((3 << 16) | 129)
+#define NX_TIEOFF_MIPI0_NX_DPSRAM_1R1W_EMAB ((3 << 16) | 132)
+#define NX_TIEOFF_MIPI0_i_NX_NPOWERDOWN ((4 << 16) | 135)
+#define NX_TIEOFF_MIPI0_i_NX_NSLEEP ((4 << 16) | 139)
+#define NX_TIEOFF_SCALER0_i_NX_EMA ((3 << 16) | 143)
+#define NX_TIEOFF_SCALER0_i_NX_EMAW ((2 << 16) | 146)
+#define NX_TIEOFF_UART0_USESMC ((1 << 16) | 148)
+#define NX_TIEOFF_UART0_SMCTXENB ((1 << 16) | 149)
+#define NX_TIEOFF_UART0_SMCRXENB ((1 << 16) | 150)
+#define NX_TIEOFF_UART1_USESMC ((1 << 16) | 151)
+#define NX_TIEOFF_UART1_SMCTXENB ((1 << 16) | 152)
+#define NX_TIEOFF_UART1_SMCRXENB ((1 << 16) | 153)
+#define NX_TIEOFF_UART2_USESMC ((1 << 16) | 154)
+#define NX_TIEOFF_UART2_SMCTXENB ((1 << 16) | 155)
+#define NX_TIEOFF_UART2_SMCRXENB ((1 << 16) | 156)
+#define NX_TIEOFF_UART3_USESMC ((1 << 16) | 157)
+#define NX_TIEOFF_UART3_SMCTXENB ((1 << 16) | 158)
+#define NX_TIEOFF_UART3_SMCRXENB ((1 << 16) | 159)
+#define NX_TIEOFF_UART4_USESMC ((1 << 16) | 160)
+#define NX_TIEOFF_UART4_SMCTXENB ((1 << 16) | 161)
+#define NX_TIEOFF_UART4_SMCRXENB ((1 << 16) | 162)
+#define NX_TIEOFF_UART5_USESMC ((1 << 16) | 163)
+#define NX_TIEOFF_UART5_SMCTXENB ((1 << 16) | 164)
+#define NX_TIEOFF_UART5_SMCRXENB ((1 << 16) | 165)
+#define NX_TIEOFF_USB20HOST0_i_nPowerDown ((1 << 16) | 166)
+#define NX_TIEOFF_USB20HOST0_i_nSleep ((1 << 16) | 167)
+#define NX_TIEOFF_USB20HOST0_i_NX_RF1_EMA ((3 << 16) | 168)
+#define NX_TIEOFF_USB20HOST0_i_NX_RF1_EMAW ((2 << 16) | 171)
+#define NX_TIEOFF_USB20HOST0_sys_interrupt_i ((1 << 16) | 173)
+#define NX_TIEOFF_USB20HOST0_i_hsic_en ((3 << 16) | 174)
+#define NX_TIEOFF_USB20HOST0_i_nResetSync ((1 << 16) | 177)
+#define NX_TIEOFF_USB20HOST0_i_nResetSync_ohci ((1 << 16) | 178)
+#define NX_TIEOFF_USB20HOST0_i_nAuxWellResetSync ((1 << 16) | 179)
+#define NX_TIEOFF_USB20HOST0_i_nHostPhyResetSync ((1 << 16) | 180)
+#define NX_TIEOFF_USB20HOST0_i_nHostUtmiResetSync ((1 << 16) | 181)
+#define NX_TIEOFF_USB20HOST0_i_nHostHsicResetSync ((1 << 16) | 182)
+#define NX_TIEOFF_USB20HOST0_i_HSIC_FREE_CLOCK_ENB ((1 << 16) | 183)
+#define NX_TIEOFF_USB20HOST0_i_HSIC_480M_FROM_OTG_PHY ((1 << 16) | 184)
+#define NX_TIEOFF_USB20HOST0_ss_word_if_enb_i ((1 << 16) | 185)
+#define NX_TIEOFF_USB20HOST0_ss_word_if_i ((1 << 16) | 186)
+#define NX_TIEOFF_USB20HOST0_ss_utmi_backward_enb_i ((1 << 16) | 187)
+#define NX_TIEOFF_USB20HOST0_ss_resume_utmi_pls_dis_i ((1 << 16) | 188)
+#define NX_TIEOFF_USB20HOST0_phy_vstatus_0_i ((3 << 16) | 189)
+#define NX_TIEOFF_USB20HOST0_phy_vstatus_1_i ((3 << 16) | 192)
+#define NX_TIEOFF_USB20HOST0_phy_vstatus_2_i ((3 << 16) | 195)
+#define NX_TIEOFF_USB20HOST0_phy_vstatus_3_i ((3 << 16) | 198)
+#define NX_TIEOFF_USB20HOST0_phy_vstatus_4_i ((3 << 16) | 201)
+#define NX_TIEOFF_USB20HOST0_phy_vstatus_5_i ((3 << 16) | 204)
+#define NX_TIEOFF_USB20HOST0_phy_vstatus_6_i ((3 << 16) | 207)
+#define NX_TIEOFF_USB20HOST0_phy_vstatus_7_i ((3 << 16) | 210)
+#define NX_TIEOFF_USB20HOST0_ss_power_state_valid_i ((1 << 16) | 213)
+#define NX_TIEOFF_USB20HOST0_ss_nxt_power_state_valid_i ((1 << 16) | 214)
+#define NX_TIEOFF_USB20HOST0_ss_power_state_i ((2 << 16) | 215)
+#define NX_TIEOFF_USB20HOST0_ss_next_power_state_i ((2 << 16) | 217)
+#define NX_TIEOFF_USB20HOST0_app_prt_ovrcur_i ((3 << 16) | 219)
+#define NX_TIEOFF_USB20HOST0_ss_simulation_mode_i ((1 << 16) | 222)
+#define NX_TIEOFF_USB20HOST0_ss_fladj_val_host_i ((6 << 16) | 224)
+#define NX_TIEOFF_USB20HOST0_ss_fladj_val_5_i ((3 << 16) | 230)
+#define NX_TIEOFF_USB20HOST0_ss_fladj_val_4_i ((3 << 16) | 233)
+#define NX_TIEOFF_USB20HOST0_ss_fladj_val_3_i ((3 << 16) | 236)
+#define NX_TIEOFF_USB20HOST0_ss_fladj_val_2_i ((3 << 16) | 239)
+#define NX_TIEOFF_USB20HOST0_ss_fladj_val_1_i ((3 << 16) | 242)
+#define NX_TIEOFF_USB20HOST0_ss_fladj_val_0_i ((3 << 16) | 245)
+#define NX_TIEOFF_USB20HOST0_ss_autoppd_on_overcur_en_i ((1 << 16) | 248)
+#define NX_TIEOFF_USB20HOST0_ss_ena_incr16_i ((1 << 16) | 249)
+#define NX_TIEOFF_USB20HOST0_ss_ena_incr8_i ((1 << 16) | 250)
+#define NX_TIEOFF_USB20HOST0_ss_ena_incr4_i ((1 << 16) | 251)
+#define NX_TIEOFF_USB20HOST0_ss_ena_incrx_align_i ((1 << 16) | 252)
+#define NX_TIEOFF_USB20HOST0_i_ohci_0_cntsel_n ((1 << 16) | 253)
+#define NX_TIEOFF_USB20HOST0_ohci_0_app_irq1_i ((1 << 16) | 254)
+#define NX_TIEOFF_USB20HOST0_ohci_0_app_irq12_i ((1 << 16) | 255)
+#define NX_TIEOFF_USB20HOST0_ohci_0_app_io_hit_i ((1 << 16) | 256)
+#define NX_TIEOFF_USB20HOST0_ss_hubsetup_min_i ((1 << 16) | 257)
+#define NX_TIEOFF_USB20HOST0_app_start_clk_i ((1 << 16) | 258)
+#define NX_TIEOFF_USB20HOST0_ohci_susp_lgcy_i ((1 << 16) | 259)
+#define NX_TIEOFF_USB20HOST0_i_SIDDQ ((1 << 16) | 260)
+#define NX_TIEOFF_USB20HOST0_i_VATESTENB ((2 << 16) | 261)
+#define NX_TIEOFF_USB20HOST0_i_POR_ENB ((1 << 16) | 263)
+#define NX_TIEOFF_USB20HOST0_i_POR ((1 << 16) | 264)
+#define NX_TIEOFF_USB20HOST0_i_REFCLKSEL ((2 << 16) | 265)
+#define NX_TIEOFF_USB20HOST0_i_FSEL ((3 << 16) | 267)
+#define NX_TIEOFF_USB20HOST0_i_COMMONONN ((1 << 16) | 270)
+#define NX_TIEOFF_USB20HOST0_i_RESREQIN ((1 << 16) | 271)
+#define NX_TIEOFF_USB20HOST0_i_PORTRESET ((1 << 16) | 272)
+#define NX_TIEOFF_USB20HOST0_i_OTGDISABLE ((1 << 16) | 273)
+#define NX_TIEOFF_USB20HOST0_i_LOOPBACKENB ((1 << 16) | 274)
+#define NX_TIEOFF_USB20HOST0_i_IDPULLUPi ((1 << 16) | 275)
+#define NX_TIEOFF_USB20HOST0_i_DRVVBUS ((1 << 16) | 276)
+#define NX_TIEOFF_USB20HOST0_i_ADPCHRG ((1 << 16) | 277)
+#define NX_TIEOFF_USB20HOST0_i_ADPDISCHRG ((1 << 16) | 278)
+#define NX_TIEOFF_USB20HOST0_i_ADPPRBENB ((1 << 16) | 279)
+#define NX_TIEOFF_USB20HOST0_i_VBUSVLDEXT ((1 << 16) | 280)
+#define NX_TIEOFF_USB20HOST0_i_VBUSVLDEXTSEL ((1 << 16) | 281)
+#define NX_TIEOFF_USB20HOST0_i_DPPULLDOWN ((1 << 16) | 282)
+#define NX_TIEOFF_USB20HOST0_i_DMPULLDOWN ((1 << 16) | 283)
+#define NX_TIEOFF_USB20HOST0_i_SUSPENDM_ENB ((1 << 16) | 284)
+#define NX_TIEOFF_USB20HOST0_i_SUSPENDM ((1 << 16) | 285)
+#define NX_TIEOFF_USB20HOST0_i_SLEEPM_ENB ((1 << 16) | 286)
+#define NX_TIEOFF_USB20HOST0_i_SLEEPM ((1 << 16) | 287)
+#define NX_TIEOFF_USB20HOST0_i_OPMODE_ENB ((1 << 16) | 288)
+#define NX_TIEOFF_USB20HOST0_i_OPMODE ((2 << 16) | 289)
+#define NX_TIEOFF_USB20HOST0_i_TERMSEL_ENB ((1 << 16) | 291)
+#define NX_TIEOFF_USB20HOST0_i_TERMSEL ((1 << 16) | 292)
+#define NX_TIEOFF_USB20HOST0_i_XCVRSEL_ENB ((1 << 16) | 293)
+#define NX_TIEOFF_USB20HOST0_i_XCVRSEL ((2 << 16) | 294)
+#define NX_TIEOFF_USB20HOST0_i_WORDINTERFACE_ENB ((1 << 16) | 296)
+#define NX_TIEOFF_USB20HOST0_i_WORDINTERFACE ((1 << 16) | 297)
+#define NX_TIEOFF_USB20HOST0_i_TXBITSTUFFEN ((1 << 16) | 298)
+#define NX_TIEOFF_USB20HOST0_i_TXBITSTUFFENH ((1 << 16) | 299)
+#define NX_TIEOFF_USB20HOST0_i_BYPASSDPDATA ((1 << 16) | 300)
+#define NX_TIEOFF_USB20HOST0_i_BYPASSDMDATA ((1 << 16) | 301)
+#define NX_TIEOFF_USB20HOST0_i_BYPASSDPEN ((1 << 16) | 302)
+#define NX_TIEOFF_USB20HOST0_i_BYPASSDMEN ((1 << 16) | 303)
+#define NX_TIEOFF_USB20HOST0_i_BYPASSSEL ((1 << 16) | 304)
+#define NX_TIEOFF_USB20HOST0_i_COMPDISTUNE ((3 << 16) | 305)
+#define NX_TIEOFF_USB20HOST0_i_SQRXTUNE ((3 << 16) | 308)
+#define NX_TIEOFF_USB20HOST0_i_OTGTUNE ((3 << 16) | 311)
+#define NX_TIEOFF_USB20HOST0_i_TXHSXVTUNE ((2 << 16) | 314)
+#define NX_TIEOFF_USB20HOST0_i_TXFSLSTUNE ((4 << 16) | 316)
+#define NX_TIEOFF_USB20HOST0_i_TXVREFTUNE ((4 << 16) | 320)
+#define NX_TIEOFF_USB20HOST0_i_TXRISETUNE ((2 << 16) | 324)
+#define NX_TIEOFF_USB20HOST0_i_TXRESTUNE ((2 << 16) | 326)
+#define NX_TIEOFF_USB20HOST0_i_TXPREEMPAMPTUNE ((2 << 16) | 328)
+#define NX_TIEOFF_USB20HOST0_i_TXPREEMPPULSETUNE ((1 << 16) | 330)
+#define NX_TIEOFF_USB20HOST0_i_CHRGSEL ((1 << 16) | 331)
+#define NX_TIEOFF_USB20HOST0_i_VDATDETENB ((1 << 16) | 332)
+#define NX_TIEOFF_USB20HOST0_i_VDATSRCENB ((1 << 16) | 333)
+#define NX_TIEOFF_USB20HOST0_i_DCDENB ((1 << 16) | 334)
+#define NX_TIEOFF_USB20HOST0_i_ACAENB ((1 << 16) | 335)
+#define NX_TIEOFF_USB20HOST0_i_HSIC_MSTRXCVR ((1 << 16) | 336)
+#define NX_TIEOFF_USB20HOST0_i_HSIC_SIDDQ ((1 << 16) | 337)
+#define NX_TIEOFF_USB20HOST0_i_HSIC_POR_ENB ((1 << 16) | 338)
+#define NX_TIEOFF_USB20HOST0_i_HSIC_POR ((1 << 16) | 339)
+#define NX_TIEOFF_USB20HOST0_i_HSIC_REFCLKDIV ((7 << 16) | 340)
+#define NX_TIEOFF_USB20HOST0_i_HSIC_REFCLKSEL ((2 << 16) | 347)
+#define NX_TIEOFF_USB20HOST0_i_HSIC_COMMONONN ((1 << 16) | 349)
+#define NX_TIEOFF_USB20HOST0_i_HSIC_PORTRESET ((1 << 16) | 350)
+#define NX_TIEOFF_USB20HOST0_i_HSIC_LOOPBACKENB ((1 << 16) | 351)
+#define NX_TIEOFF_USB20HOST0_i_HSIC_DPPULLDOWN ((1 << 16) | 352)
+#define NX_TIEOFF_USB20HOST0_i_HSIC_DMPULLDOWN ((1 << 16) | 353)
+#define NX_TIEOFF_USB20HOST0_i_HSIC_SUSPENDM_ENB ((1 << 16) | 354)
+#define NX_TIEOFF_USB20HOST0_i_HSIC_SUSPENDM ((1 << 16) | 355)
+#define NX_TIEOFF_USB20HOST0_i_HSIC_SLEEPM_ENB ((1 << 16) | 356)
+#define NX_TIEOFF_USB20HOST0_i_HSIC_SLEEPM ((1 << 16) | 357)
+#define NX_TIEOFF_USB20HOST0_i_HSIC_MSTRXOPU ((1 << 16) | 358)
+#define NX_TIEOFF_USB20HOST0_i_HSIC_OPMODE_ENB ((1 << 16) | 359)
+#define NX_TIEOFF_USB20HOST0_i_HSIC_OPMODE ((2 << 16) | 360)
+#define NX_TIEOFF_USB20HOST0_i_HSIC_XCVRSELECT_ENB ((1 << 16) | 362)
+#define NX_TIEOFF_USB20HOST0_i_HSIC_XCVRSELECT ((1 << 16) | 363)
+#define NX_TIEOFF_USB20HOST0_i_HSIC_WORDINTERFACE_ENB ((1 << 16) | 364)
+#define NX_TIEOFF_USB20HOST0_i_HSIC_WORDINTERFACE ((1 << 16) | 365)
+#define NX_TIEOFF_USB20HOST0_i_HSIC_TXBITSTUFFEN ((1 << 16) | 366)
+#define NX_TIEOFF_USB20HOST0_i_HSIC_TXBITSTUFFENH ((1 << 16) | 367)
+#define NX_TIEOFF_USB20HOST0_i_HSIC_TXRPUTUNE ((2 << 16) | 368)
+#define NX_TIEOFF_USB20HOST0_i_HSIC_TXRPDTUNE ((2 << 16) | 370)
+#define NX_TIEOFF_USB20HOST0_i_HSIC_TXSRTUNE ((4 << 16) | 372)
+#define NX_TIEOFF_USB20OTG0_i_nPowerDown ((1 << 16) | 376)
+#define NX_TIEOFF_USB20OTG0_i_nSleep ((1 << 16) | 377)
+#define NX_TIEOFF_USB20OTG0_i_NX_RF1_EMA ((3 << 16) | 378)
+#define NX_TIEOFF_USB20OTG0_i_NX_RF1_EMAW ((2 << 16) | 381)
+#define NX_TIEOFF_USB20OTG0_i_ss_scaledown_mode ((2 << 16) | 384)
+#define NX_TIEOFF_USB20OTG0_i_gp_in ((16 << 16) | 386)
+#define NX_TIEOFF_USB20OTG0_i_sof_count ((14 << 16) | 402)
+#define NX_TIEOFF_USB20OTG0_i_sys_dma_done ((1 << 16) | 416)
+#define NX_TIEOFF_USB20OTG0_i_if_select_hsic ((1 << 16) | 417)
+#define NX_TIEOFF_USB20OTG0_i_nResetSync ((1 << 16) | 418)
+#define NX_TIEOFF_USB20OTG0_i_nUtmiResetSync ((1 << 16) | 419)
+#define NX_TIEOFF_USB20OTG0_i_SIDDQ ((1 << 16) | 420)
+#define NX_TIEOFF_USB20OTG0_i_VATESTENB ((2 << 16) | 421)
+#define NX_TIEOFF_USB20OTG0_i_POR_ENB ((1 << 16) | 423)
+#define NX_TIEOFF_USB20OTG0_i_POR ((1 << 16) | 424)
+#define NX_TIEOFF_USB20OTG0_i_REFCLKSEL ((2 << 16) | 425)
+#define NX_TIEOFF_USB20OTG0_i_FSEL ((3 << 16) | 427)
+#define NX_TIEOFF_USB20OTG0_i_COMMONONN ((1 << 16) | 430)
+#define NX_TIEOFF_USB20OTG0_i_RESREQIN ((1 << 16) | 431)
+#define NX_TIEOFF_USB20OTG0_i_PORTRESET ((1 << 16) | 432)
+#define NX_TIEOFF_USB20OTG0_i_OTGDISABLE ((1 << 16) | 433)
+#define NX_TIEOFF_USB20OTG0_i_LOOPBACKENB ((1 << 16) | 434)
+#define NX_TIEOFF_USB20OTG0_i_IDPULLUP ((1 << 16) | 435)
+#define NX_TIEOFF_USB20OTG0_i_DRVVBUS ((1 << 16) | 436)
+#define NX_TIEOFF_USB20OTG0_i_ADPCHRG ((1 << 16) | 437)
+#define NX_TIEOFF_USB20OTG0_i_ADPDISCHRG ((1 << 16) | 438)
+#define NX_TIEOFF_USB20OTG0_i_ADPPRBENB ((1 << 16) | 439)
+#define NX_TIEOFF_USB20OTG0_i_VBUSVLDEXT ((1 << 16) | 440)
+#define NX_TIEOFF_USB20OTG0_i_VBUSVLDEXTSEL ((1 << 16) | 441)
+#define NX_TIEOFF_USB20OTG0_i_DPPULLDOWN ((1 << 16) | 442)
+#define NX_TIEOFF_USB20OTG0_i_DMPULLDOWN ((1 << 16) | 443)
+#define NX_TIEOFF_USB20OTG0_i_SUSPENDM_ENB ((1 << 16) | 444)
+#define NX_TIEOFF_USB20OTG0_i_SUSPENDM ((1 << 16) | 445)
+#define NX_TIEOFF_USB20OTG0_i_SLEEPM_ENB ((1 << 16) | 446)
+#define NX_TIEOFF_USB20OTG0_i_SLEEPM ((1 << 16) | 447)
+#define NX_TIEOFF_USB20OTG0_i_OPMODE_ENB ((1 << 16) | 448)
+#define NX_TIEOFF_USB20OTG0_i_OPMODE ((2 << 16) | 449)
+#define NX_TIEOFF_USB20OTG0_i_TERMSEL_ENB ((1 << 16) | 451)
+#define NX_TIEOFF_USB20OTG0_i_TERMSEL ((1 << 16) | 452)
+#define NX_TIEOFF_USB20OTG0_i_XCVRSEL_ENB ((1 << 16) | 453)
+#define NX_TIEOFF_USB20OTG0_i_XCVRSEL ((2 << 16) | 454)
+#define NX_TIEOFF_USB20OTG0_i_WORDINTERFACE_ENB ((1 << 16) | 456)
+#define NX_TIEOFF_USB20OTG0_i_WORDINTERFACE ((1 << 16) | 457)
+#define NX_TIEOFF_USB20OTG0_i_TXBITSTUFFEN ((1 << 16) | 458)
+#define NX_TIEOFF_USB20OTG0_i_TXBITSTUFFENH ((1 << 16) | 459)
+#define NX_TIEOFF_USB20OTG0_i_BYPASSDPDATA ((1 << 16) | 460)
+#define NX_TIEOFF_USB20OTG0_i_BYPASSDMDATA ((1 << 16) | 461)
+#define NX_TIEOFF_USB20OTG0_i_BYPASSDPEN ((1 << 16) | 462)
+#define NX_TIEOFF_USB20OTG0_i_BYPASSDMEN ((1 << 16) | 463)
+#define NX_TIEOFF_USB20OTG0_i_BYPASSSEL ((1 << 16) | 464)
+#define NX_TIEOFF_USB20OTG0_i_COMPDISTUNE ((3 << 16) | 465)
+#define NX_TIEOFF_USB20OTG0_i_SQRXTUNE ((3 << 16) | 468)
+#define NX_TIEOFF_USB20OTG0_i_OTGTUNE ((3 << 16) | 471)
+#define NX_TIEOFF_USB20OTG0_i_TXHSXVTUNE ((2 << 16) | 474)
+#define NX_TIEOFF_USB20OTG0_i_TXFSLSTUNE ((4 << 16) | 476)
+#define NX_TIEOFF_USB20OTG0_i_TXVREFTUNE ((4 << 16) | 480)
+#define NX_TIEOFF_USB20OTG0_i_TXRISETUNE ((2 << 16) | 484)
+#define NX_TIEOFF_USB20OTG0_i_TXRESTUNE ((2 << 16) | 486)
+#define NX_TIEOFF_USB20OTG0_i_TXPREEMPAMPTUNE ((2 << 16) | 488)
+#define NX_TIEOFF_USB20OTG0_i_TXPREEMPPULSETUNE ((1 << 16) | 490)
+#define NX_TIEOFF_USB20OTG0_i_CHRGSEL ((1 << 16) | 491)
+#define NX_TIEOFF_USB20OTG0_i_VDATDETENB ((1 << 16) | 492)
+#define NX_TIEOFF_USB20OTG0_i_VDATSRCENB ((1 << 16) | 493)
+#define NX_TIEOFF_USB20OTG0_i_DCDENB ((1 << 16) | 494)
+#define NX_TIEOFF_USB20OTG0_i_ACAENB ((1 << 16) | 495)
+#define NX_TIEOFF_USB20OTG0_i_IDPULLUP_ENB ((1 << 16) | 496)
+#define NX_TIEOFF_USB20OTG0_i_DPPULLDOWN_ENB ((1 << 16) | 497)
+#define NX_TIEOFF_USB20OTG0_i_DMPULLDOWN_ENB ((1 << 16) | 498)
+#define NX_TIEOFF_USB20OTG0_i_DRVVBUS_ENB ((1 << 16) | 499)
+#define NX_TIEOFF_USB20OTG0_i_LPMClkMuxCntrl ((1 << 16) | 500)
+#define NX_TIEOFF_USB20OTG0_i_GLITCHLESSMUXCntrl ((1 << 16) | 501)
+#define NX_TIEOFF_CODA9600_i_nPWRDN00 ((4 << 16) | 502)
+#define NX_TIEOFF_CODA9600_i_nSLEEP00 ((4 << 16) | 506)
+#define NX_TIEOFF_CODA9600_i_nPWRDN01 ((8 << 16) | 512)
+#define NX_TIEOFF_CODA9600_i_nSLEEP01 ((8 << 16) | 520)
+#define NX_TIEOFF_CODA9600_i_nPWRDN02 ((10 << 16) | 528)
+#define NX_TIEOFF_CODA9600_i_nSLEEP02 ((10 << 16) | 544)
+#define NX_TIEOFF_CODA9600_i_nPWRDN03 ((2 << 16) | 554)
+#define NX_TIEOFF_CODA9600_i_nSLEEP03 ((2 << 16) | 556)
+#define NX_TIEOFF_CODA9600_i_nPWRDN04 ((8 << 16) | 558)
+#define NX_TIEOFF_CODA9600_i_nSLEEP04 ((8 << 16) | 566)
+#define NX_TIEOFF_CODA9600_i_nPWRDN05 ((3 << 16) | 576)
+#define NX_TIEOFF_CODA9600_i_nSLEEP05 ((3 << 16) | 579)
+#define NX_TIEOFF_CODA9600_i_nPWRDN06 ((7 << 16) | 582)
+#define NX_TIEOFF_CODA9600_i_nSLEEP06 ((7 << 16) | 589)
+#define NX_TIEOFF_CODA9600_i_nPWRDN07 ((12 << 16) | 596)
+#define NX_TIEOFF_CODA9600_i_nSLEEP07 ((12 << 16) | 608)
+#define NX_TIEOFF_CODA9600_i_nPWRDN08 ((1 << 16) | 620)
+#define NX_TIEOFF_CODA9600_i_nSLEEP08 ((1 << 16) | 621)
+#define NX_TIEOFF_CODA9600_i_nPWRDN09 ((2 << 16) | 622)
+#define NX_TIEOFF_CODA9600_i_nSLEEP09 ((2 << 16) | 624)
+#define NX_TIEOFF_CODA9600_i_nPWRDN10 ((10 << 16) | 626)
+#define NX_TIEOFF_CODA9600_i_nSLEEP10 ((10 << 16) | 640)
+#define NX_TIEOFF_CODA9600_i_nPWRDN11 ((1 << 16) | 650)
+#define NX_TIEOFF_CODA9600_i_nSLEEP11 ((1 << 16) | 651)
+#define NX_TIEOFF_CODA9600_i_TIE_rf2_EMAA ((3 << 16) | 652)
+#define NX_TIEOFF_CODA9600_i_TIE_rf2_EMAB ((3 << 16) | 655)
+#define NX_TIEOFF_CODA9600_i_TIE_rf2w_EMAA ((3 << 16) | 658)
+#define NX_TIEOFF_CODA9600_i_TIE_rf2w_EMAB ((3 << 16) | 661)
+#define NX_TIEOFF_CODA9600_i_TIE_ra2_EMAA ((3 << 16) | 664)
+#define NX_TIEOFF_CODA9600_i_TIE_ra2_EMAB ((3 << 16) | 667)
+#define NX_TIEOFF_CODA9600_i_TIE_ra2_EMAWA ((2 << 16) | 670)
+#define NX_TIEOFF_CODA9600_i_TIE_ra2_EMAWB ((2 << 16) | 672)
+#define NX_TIEOFF_CODA9600_i_TIE_ra2w_EMAA ((3 << 16) | 674)
+#define NX_TIEOFF_CODA9600_i_TIE_ra2w_EMAB ((3 << 16) | 677)
+#define NX_TIEOFF_CODA9600_i_TIE_ra2w_EMAWA ((2 << 16) | 680)
+#define NX_TIEOFF_CODA9600_i_TIE_ra2w_EMAWB ((2 << 16) | 682)
+#define NX_TIEOFF_CODA9600_i_TIE_rf1_EMA ((3 << 16) | 684)
+#define NX_TIEOFF_CODA9600_i_TIE_rf1_EMAW ((2 << 16) | 687)
+#define NX_TIEOFF_CODA9600_i_TIE_rf1w_EMA ((3 << 16) | 689)
+#define NX_TIEOFF_CODA9600_i_TIE_rf1w_EMAW ((2 << 16) | 692)
+#define NX_TIEOFF_DWC_GMAC0_sbd_flowctrl_i ((1 << 16) | 694)
+#define NX_TIEOFF_DWC_GMAC0_phy_intf_sel_i ((3 << 16) | 695)
+#define NX_TIEOFF_DWC_GMAC0_i_NX_RF2_EMAA ((3 << 16) | 698)
+#define NX_TIEOFF_DWC_GMAC0_i_NX_RF2_EMAB ((3 << 16) | 701)
+#define NX_TIEOFF_MALI4000_NX_DPSRAM_1R1W_EMAA ((3 << 16) | 704)
+#define NX_TIEOFF_MALI4000_NX_DPSRAM_1R1W_EMAB ((3 << 16) | 707)
+#define NX_TIEOFF_MALI4000_NX_SPSRAM_EMA ((3 << 16) | 710)
+#define NX_TIEOFF_MALI4000_NX_SPSRAM_EMAW ((2 << 16) | 713)
+#define NX_TIEOFF_MALI4000_NX_SPSRAM_BW_EMA ((3 << 16) | 715)
+#define NX_TIEOFF_MALI4000_NX_SPSRAM_BW_EMAW ((2 << 16) | 718)
+#define NX_TIEOFF_MALI4000_PWRDNBYPASS ((1 << 16) | 720)
+#define NX_TIEOFF_MALI4000_GP_NX_NPOWERDOWN ((15 << 16) | 721)
+#define NX_TIEOFF_MALI4000_GP_NX_NSLEEP ((15 << 16) | 736)
+#define NX_TIEOFF_MALI4000_L2_NX_NPOWERDOWN ((3 << 16) | 751)
+#define NX_TIEOFF_MALI4000_L2_NX_NSLEEP ((3 << 16) | 754)
+#define NX_TIEOFF_MALI4000_PP0_NX_NPOWERDOWN ((32 << 16) | 768)
+#define NX_TIEOFF_MALI4000_PP0_NX_NSLEEP ((32 << 16) | 800)
+#define NX_TIEOFF_MALI4000_PP1_NX_NPOWERDOWN ((32 << 16) | 832)
+#define NX_TIEOFF_MALI4000_PP1_NX_NSLEEP ((32 << 16) | 864)
+#define NX_TIEOFF_MALI4000_PP2_NX_NPOWERDOWN ((32 << 16) | 896)
+#define NX_TIEOFF_MALI4000_PP2_NX_NSLEEP ((32 << 16) | 928)
+#define NX_TIEOFF_MALI4000_PP3_NX_NPOWERDOWN ((32 << 16) | 960)
+#define NX_TIEOFF_MALI4000_PP3_NX_NSLEEP ((32 << 16) | 992)
+#define NX_TIEOFF_A3BM_AXI_PERI_BUS0_SYNCMODEREQm9 ((1 << 16) | 1024)
+#define NX_TIEOFF_A3BM_AXI_PERI_BUS0_SYNCMODEREQm10 ((1 << 16) | 1025)
+#define NX_TIEOFF_A3BM_AXI_PERI_BUS0_SYNCMODEREQm16 ((1 << 16) | 1026)
+#define NX_TIEOFF_A3BM_AXI_TOP_MASTER_BUS0_REMAP ((2 << 16) | 1027)
+#if defined(CONFIG_ARCH_S5P6818)
+#define NX_TIEOFF_Inst_ARMTOP_SMPEN ((4 << 16) | 2816)
+#define NX_TIEOFF_Inst_ARMTOP_STANBYWFI ((4 << 16) | 2880)
+#define NX_TIEOFF_Inst_ARMTOP_STANBYWFIL2 ((1 << 16) | 2884)
+#define NX_TIEOFF_Inst_ARMTOP_DBGNOPWRDWN ((4 << 16) | 2889)
+#define NX_TIEOFF_Inst_ARMTOP_DBGPWRUPREQ ((4 << 16) | 2893)
+#define NX_TIEOFF_Inst_ARMTOP_COREPWRDOWNPRE ((1 << 16) | 2901)
+#define NX_TIEOFF_Inst_ARMTOP_CPU0PWRDOWNPRE ((1 << 16) | 2902)
+#define NX_TIEOFF_Inst_ARMTOP_CPU1PWRDOWNPRE ((1 << 16) | 2903)
+#define NX_TIEOFF_Inst_ARMTOP_CPU2PWRDOWNPRE ((1 << 16) | 2904)
+#define NX_TIEOFF_Inst_ARMTOP_CPU3PWRDOWNPRE ((1 << 16) | 2905)
+#define NX_TIEOFF_Inst_ARMTOP_COREPWRDOWNALL ((1 << 16) | 2906)
+#define NX_TIEOFF_Inst_ARMTOP_CPU0PWRDOWNALL ((1 << 16) | 2907)
+#define NX_TIEOFF_Inst_ARMTOP_CPU1PWRDOWNALL ((1 << 16) | 2908)
+#define NX_TIEOFF_Inst_ARMTOP_CPU2PWRDOWNALL ((1 << 16) | 2909)
+#define NX_TIEOFF_Inst_ARMTOP_CPU3PWRDOWNALL ((1 << 16) | 2910)
+#define NX_TIEOFF_Inst_ARMTOP_CLAMPL2 ((1 << 16) | 2920)
+#define NX_TIEOFF_Inst_ARMTOP_L2FLUSHREQ ((1 << 16) | 3018)
+#define NX_TIEOFF_Inst_ARMTOP_L2FLUSHDONE ((1 << 16) | 3019)
+#define NX_TIEOFF_Inst_ARMTOP_ACINACTM ((1 << 16) | 3023)
+#define NX_TIEOFF_Inst_ARMTOP_P1_SMPEN ((4 << 16) | 3360)
+#define NX_TIEOFF_Inst_ARMTOP_P1_STANBYWFI ((4 << 16) | 3424)
+#define NX_TIEOFF_Inst_ARMTOP_P1_STANBYWFIL2 ((1 << 16) | 3428)
+#define NX_TIEOFF_Inst_ARMTOP_P1_DBGNOPWRDWN ((4 << 16) | 3442)
+#define NX_TIEOFF_Inst_ARMTOP_P1_DBGPWRUPREQ ((4 << 16) | 3443)
+#define NX_TIEOFF_Inst_ARMTOP_P1_DBGPWRDUP ((4 << 16) | 3444)
+#define NX_TIEOFF_Inst_ARMTOP_P1_COREPWRDOWNPRE ((1 << 16) | 3445)
+#define NX_TIEOFF_Inst_ARMTOP_P1_CPU0PWRDOWNPRE ((1 << 16) | 3446)
+#define NX_TIEOFF_Inst_ARMTOP_P1_CPU1PWRDOWNPRE ((1 << 16) | 3447)
+#define NX_TIEOFF_Inst_ARMTOP_P1_CPU2PWRDOWNPRE ((1 << 16) | 3448)
+#define NX_TIEOFF_Inst_ARMTOP_P1_CPU3PWRDOWNPRE ((1 << 16) | 3449)
+#define NX_TIEOFF_Inst_ARMTOP_P1_COREPWRDOWNALL ((1 << 16) | 3450)
+#define NX_TIEOFF_Inst_ARMTOP_P1_CPU0PWRDOWNALL ((1 << 16) | 3451)
+#define NX_TIEOFF_Inst_ARMTOP_P1_CPU1PWRDOWNALL ((1 << 16) | 3452)
+#define NX_TIEOFF_Inst_ARMTOP_P1_CPU2PWRDOWNALL ((1 << 16) | 3453)
+#define NX_TIEOFF_Inst_ARMTOP_P1_CPU3PWRDOWNALL ((1 << 16) | 3454)
+#define NX_TIEOFF_Inst_ARMTOP_P1_CLAMPL2 ((1 << 16) | 3464)
+#define NX_TIEOFF_Inst_ARMTOP_P1_L2FLUSHREQ ((1 << 16) | 3562)
+#define NX_TIEOFF_Inst_ARMTOP_P1_L2FLUSHDONE ((1 << 16) | 3563)
+#define NX_TIEOFF_Inst_ARMTOP_P1_ACINACTM ((1 << 16) | 3567)
+#endif
+
+#endif /* _NEXELL_TIEOFF_H */
--
1.9.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH 02/10] arm: add mach-nexell (all files except header files)
2020-02-03 19:39 [RFC PATCH 00/10] arm: add support for SoC S5P4418 Stefan Bosch
2020-02-03 20:32 ` [RFC PATCH 01/10] arm: add mach-nexell (header files) Stefan Bosch
@ 2020-02-03 20:38 ` Stefan Bosch
2020-02-03 20:40 ` [RFC PATCH 03/10] i2c: mmc: add nexell driver (gpio, i2c, mmc, pwm) Stefan Bosch
` (9 subsequent siblings)
11 siblings, 0 replies; 19+ messages in thread
From: Stefan Bosch @ 2020-02-03 20:38 UTC (permalink / raw)
To: u-boot
Changes in relation to FriendlyARM's U-Boot nanopi2-v2016.01:
- SPL not supported yet --> no spl-directory in arch/arm/mach-nexell.
Appropriate line in Makefile removed.
- clock.c: 'section(".data")' added to declaration of clk_periphs[] and
core_hz.
- Kconfig: Changes to have a structure like in mach-bcm283x/Kconfig,
e.g. "config ..." entries moved from other Kconfig.
- timer.c: 'section(".data")' added to declaration of timestamp and
lastdec.
Signed-off-by: Stefan Bosch <stefan_b@posteo.net>
---
arch/arm/Kconfig | 7 +
arch/arm/Makefile | 1 +
arch/arm/mach-nexell/Kconfig | 67 +++
arch/arm/mach-nexell/Makefile | 15 +
arch/arm/mach-nexell/clock.c | 869 ++++++++++++++++++++++++++++++++++
arch/arm/mach-nexell/cmd_boot_linux.c | 145 ++++++
arch/arm/mach-nexell/config.mk | 11 +
arch/arm/mach-nexell/nx_gpio.c | 352 ++++++++++++++
arch/arm/mach-nexell/nx_sec_reg.c | 82 ++++
arch/arm/mach-nexell/reg-call.S | 23 +
arch/arm/mach-nexell/reset.c | 33 ++
arch/arm/mach-nexell/serial.c | 262 ++++++++++
arch/arm/mach-nexell/tieoff.c | 109 +++++
arch/arm/mach-nexell/timer.c | 297 ++++++++++++
14 files changed, 2273 insertions(+)
create mode 100644 arch/arm/mach-nexell/Kconfig
create mode 100644 arch/arm/mach-nexell/Makefile
create mode 100644 arch/arm/mach-nexell/clock.c
create mode 100644 arch/arm/mach-nexell/cmd_boot_linux.c
create mode 100644 arch/arm/mach-nexell/config.mk
create mode 100644 arch/arm/mach-nexell/nx_gpio.c
create mode 100644 arch/arm/mach-nexell/nx_sec_reg.c
create mode 100644 arch/arm/mach-nexell/reg-call.S
create mode 100644 arch/arm/mach-nexell/reset.c
create mode 100644 arch/arm/mach-nexell/serial.c
create mode 100644 arch/arm/mach-nexell/tieoff.c
create mode 100644 arch/arm/mach-nexell/timer.c
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index a623ef5..469aa65 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -875,6 +875,11 @@ config ARCH_MX5
select CPU_V7A
imply MXC_GPIO
+config ARCH_NEXELL
+ bool "Nexell S5P4418/S5P6818 SoC"
+ select ENABLE_ARM_SOC_BOOT0_HOOK
+ select DM
+
config ARCH_OWL
bool "Actions Semi OWL SoCs"
select ARM64
@@ -1797,6 +1802,8 @@ source "arch/arm/cpu/armv8/Kconfig"
source "arch/arm/mach-imx/Kconfig"
+source "arch/arm/mach-nexell/Kconfig"
+
source "board/bosch/shc/Kconfig"
source "board/bosch/guardian/Kconfig"
source "board/CarMediaLab/flea3/Kconfig"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 1e60a9f..5a390b8 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -67,6 +67,7 @@ machine-$(CONFIG_ARCH_MESON) += meson
machine-$(CONFIG_ARCH_MVEBU) += mvebu
# TODO: rename CONFIG_TEGRA -> CONFIG_ARCH_TEGRA
# TODO: rename CONFIG_ORION5X -> CONFIG_ARCH_ORION5X
+machine-$(CONFIG_ARCH_NEXELL) += nexell
machine-$(CONFIG_ORION5X) += orion5x
machine-$(CONFIG_ARCH_OMAP2PLUS) += omap2
machine-$(CONFIG_ARCH_OWL) += owl
diff --git a/arch/arm/mach-nexell/Kconfig b/arch/arm/mach-nexell/Kconfig
new file mode 100644
index 0000000..5368909
--- /dev/null
+++ b/arch/arm/mach-nexell/Kconfig
@@ -0,0 +1,67 @@
+if ARCH_NEXELL
+
+config NEXELL_COMMON
+ bool "Nexell common options"
+
+config NEXELL_ARMV7_COMMON
+ bool "Nexell 32-bit common options"
+ select CPU_V7A
+ select NEXELL_COMMON
+ #select SUPPORT_SPL
+
+config NEXELL_ARMV8_COMMON
+ bool "Nexell 64-bit common options"
+ select ARM64
+ select ARMV8_MULTIENTRY
+ select NEXELL_COMMON
+
+config ARCH_S5P4418
+ bool "Nexell S5P4418 SoC"
+ select NEXELL_ARMV7_COMMON
+ select OF_CONTROL
+ select OF_SEPARATE
+ select NX_GPIO
+ select PL011_SERIAL
+ select PL011_SERIAL_FLUSH_ON_INIT
+
+config ARCH_S5P6818
+ bool "Nexell S5P6818 SoC"
+ select NEXELL_ARMV8_COMMON
+
+menu "Nexell S5P4418/S5P6818"
+ #depends on ARCH_S5P4418
+ depends on ARCH_NEXELL
+
+choice
+ prompt "Nexell S5P4418/S5P6818 board select"
+ optional
+
+config TARGET_NANOPI2
+ bool "FriendlyARM NanoPi2 Board"
+ select ARCH_S5P4418
+
+endchoice
+
+config SYS_BOARD
+ default "nanopi2"
+
+config SYS_VENDOR
+ default "friendlyarm"
+
+config SYS_SOC
+ default "nexell"
+
+config SYS_CONFIG_NAME
+ default "s5p4418_nanopi2"
+
+endmenu
+
+config SYS_PLLFIN
+ int
+
+config TIMER_SYS_TICK_CH
+ int
+
+source "board/friendlyarm/Kconfig"
+
+endif
diff --git a/arch/arm/mach-nexell/Makefile b/arch/arm/mach-nexell/Makefile
new file mode 100644
index 0000000..e144196
--- /dev/null
+++ b/arch/arm/mach-nexell/Makefile
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2016 Nexell
+# Hyunseok, Jung <hsjung@nexell.co.kr>
+
+obj-y += clock.o
+obj-y += timer.o
+obj-y += reset.o
+obj-y += nx_gpio.o
+obj-y += tieoff.o
+obj-$(CONFIG_ARCH_S5P4418) += reg-call.o
+obj-$(CONFIG_ARCH_S5P4418) += nx_sec_reg.o
+obj-$(CONFIG_CMD_BOOTL) += cmd_boot_linux.o
+obj-$(CONFIG_S5P_SERIAL) += serial.o
+obj-$(CONFIG_SPL_BUILD) += spl/
diff --git a/arch/arm/mach-nexell/clock.c b/arch/arm/mach-nexell/clock.c
new file mode 100644
index 0000000..a0ba2d8
--- /dev/null
+++ b/arch/arm/mach-nexell/clock.c
@@ -0,0 +1,869 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2016 Nexell
+ * Hyunseok, Jung <hsjung@nexell.co.kr>
+ */
+
+#include <common.h>
+#include <command.h>
+#include <linux/err.h>
+#include <asm/io.h>
+#include <asm/arch/nexell.h>
+#include <asm/arch/clk.h>
+
+/*
+ * clock generator macros
+ */
+#define I_PLL0_BIT (0)
+#define I_PLL1_BIT (1)
+#define I_PLL2_BIT (2)
+#define I_PLL3_BIT (3)
+#define I_EXT1_BIT (4)
+#define I_EXT2_BIT (5)
+#define I_CLKn_BIT (7)
+#define I_EXT1_BIT_FORCE (8)
+#define I_EXT2_BIT_FORCE (9)
+
+#define I_CLOCK_NUM 6 /* PLL0, PLL1, PLL2, PLL3, EXT1, EXT2 */
+
+#define I_EXECEPT_CLK (0)
+#define I_CLOCK_MASK (((1 << I_CLOCK_NUM) - 1) & ~I_EXECEPT_CLK)
+
+#define I_PLL0 (1 << I_PLL0_BIT)
+#define I_PLL1 (1 << I_PLL1_BIT)
+#define I_PLL2 (1 << I_PLL2_BIT)
+#define I_PLL3 (1 << I_PLL3_BIT)
+#define I_EXTCLK1 (1 << I_EXT1_BIT)
+#define I_EXTCLK2 (1 << I_EXT2_BIT)
+#define I_EXTCLK1_FORCE (1 << I_EXT1_BIT_FORCE)
+#define I_EXTCLK2_FORCE (1 << I_EXT2_BIT_FORCE)
+
+#define I_PLL_0_1 (I_PLL0 | I_PLL1)
+#define I_PLL_0_2 (I_PLL_0_1 | I_PLL2)
+#define I_PLL_0_3 (I_PLL_0_2 | I_PLL3)
+#define I_CLKnOUT (0)
+
+#define I_PCLK (1 << 16)
+#define I_BCLK (1 << 17)
+#define I_GATE_PCLK (1 << 20)
+#define I_GATE_BCLK (1 << 21)
+#define I_PCLK_MASK (I_GATE_PCLK | I_PCLK)
+#define I_BCLK_MASK (I_GATE_BCLK | I_BCLK)
+
+struct clk_dev_peri {
+ const char *dev_name;
+ void __iomem *base;
+ int dev_id;
+ int periph_id;
+ int clk_step;
+ u32 in_mask;
+ u32 in_mask1;
+ int div_src_0;
+ int div_val_0;
+ int invert_0;
+ int div_src_1;
+ int div_val_1;
+ int invert_1;
+ int in_extclk_1;
+ int in_extclk_2;
+};
+
+struct clk_dev {
+ struct clk clk;
+ struct clk *link;
+ const char *name;
+ struct clk_dev_peri *peri;
+};
+
+struct clk_dev_map {
+ unsigned int con_enb;
+ unsigned int con_gen[4];
+};
+
+#define CLK_PERI_1S(name, devid, id, addr, mk)[id] = \
+ { .dev_name = name, .dev_id = devid, .periph_id = id, .clk_step = 1, \
+ .base = (void *)addr, .in_mask = mk, }
+
+#define CLK_PERI_2S(name, devid, id, addr, mk, mk2)[id] = \
+ { .dev_name = name, .dev_id = devid, .periph_id = id, .clk_step = 2, \
+ .base = (void *)addr, .in_mask = mk, .in_mask1 = mk2, }
+
+static const char * const clk_core[] = {
+ CORECLK_NAME_PLL0, CORECLK_NAME_PLL1, CORECLK_NAME_PLL2,
+ CORECLK_NAME_PLL3, CORECLK_NAME_FCLK, CORECLK_NAME_MCLK,
+ CORECLK_NAME_BCLK, CORECLK_NAME_PCLK, CORECLK_NAME_HCLK,
+};
+
+/*
+ * Section ".data" must be used because BSS is not available before relocation,
+ * in board_init_f(), respectively! I.e. global variables can not be used!
+ */
+static struct clk_dev_peri clk_periphs[]
+ __attribute__((section(".data"))) = {
+ CLK_PERI_1S(DEV_NAME_TIMER, 0, CLK_ID_TIMER_0,
+ PHY_BASEADDR_CLKGEN14, (I_PLL_0_2)),
+ CLK_PERI_1S(DEV_NAME_TIMER, 1, CLK_ID_TIMER_1,
+ PHY_BASEADDR_CLKGEN0, (I_PLL_0_2)),
+ CLK_PERI_1S(DEV_NAME_TIMER, 2, CLK_ID_TIMER_2,
+ PHY_BASEADDR_CLKGEN1, (I_PLL_0_2)),
+ CLK_PERI_1S(DEV_NAME_TIMER, 3, CLK_ID_TIMER_3,
+ PHY_BASEADDR_CLKGEN2, (I_PLL_0_2)),
+ CLK_PERI_1S(DEV_NAME_UART, 0, CLK_ID_UART_0,
+ PHY_BASEADDR_CLKGEN22, (I_PLL_0_2)),
+ CLK_PERI_1S(DEV_NAME_UART, 1, CLK_ID_UART_1,
+ PHY_BASEADDR_CLKGEN24, (I_PLL_0_2)),
+ CLK_PERI_1S(DEV_NAME_UART, 2, CLK_ID_UART_2,
+ PHY_BASEADDR_CLKGEN23, (I_PLL_0_2)),
+ CLK_PERI_1S(DEV_NAME_UART, 3, CLK_ID_UART_3,
+ PHY_BASEADDR_CLKGEN25, (I_PLL_0_2)),
+ CLK_PERI_1S(DEV_NAME_UART, 4, CLK_ID_UART_4,
+ PHY_BASEADDR_CLKGEN26, (I_PLL_0_2)),
+ CLK_PERI_1S(DEV_NAME_UART, 5, CLK_ID_UART_5,
+ PHY_BASEADDR_CLKGEN27, (I_PLL_0_2)),
+ CLK_PERI_1S(DEV_NAME_PWM, 0, CLK_ID_PWM_0,
+ PHY_BASEADDR_CLKGEN13, (I_PLL_0_2)),
+ CLK_PERI_1S(DEV_NAME_PWM, 1, CLK_ID_PWM_1,
+ PHY_BASEADDR_CLKGEN3, (I_PLL_0_2)),
+ CLK_PERI_1S(DEV_NAME_PWM, 2, CLK_ID_PWM_2,
+ PHY_BASEADDR_CLKGEN4, (I_PLL_0_2)),
+ CLK_PERI_1S(DEV_NAME_PWM, 3, CLK_ID_PWM_3,
+ PHY_BASEADDR_CLKGEN5, (I_PLL_0_2)),
+ CLK_PERI_1S(DEV_NAME_I2C, 0, CLK_ID_I2C_0,
+ PHY_BASEADDR_CLKGEN6, (I_GATE_PCLK)),
+ CLK_PERI_1S(DEV_NAME_I2C, 1, CLK_ID_I2C_1,
+ PHY_BASEADDR_CLKGEN7, (I_GATE_PCLK)),
+ CLK_PERI_1S(DEV_NAME_I2C, 2, CLK_ID_I2C_2,
+ PHY_BASEADDR_CLKGEN8, (I_GATE_PCLK)),
+ CLK_PERI_2S(DEV_NAME_GMAC, 0, CLK_ID_GMAC,
+ PHY_BASEADDR_CLKGEN10,
+ (I_PLL_0_3 | I_EXTCLK1 | I_EXTCLK1_FORCE),
+ (I_CLKnOUT)),
+ CLK_PERI_2S(DEV_NAME_I2S, 0, CLK_ID_I2S_0,
+ PHY_BASEADDR_CLKGEN15, (I_PLL_0_3 | I_EXTCLK1),
+ (I_CLKnOUT)),
+ CLK_PERI_2S(DEV_NAME_I2S, 1, CLK_ID_I2S_1,
+ PHY_BASEADDR_CLKGEN16, (I_PLL_0_3 | I_EXTCLK1),
+ (I_CLKnOUT)),
+ CLK_PERI_2S(DEV_NAME_I2S, 2, CLK_ID_I2S_2,
+ PHY_BASEADDR_CLKGEN17, (I_PLL_0_3 | I_EXTCLK1),
+ (I_CLKnOUT)),
+ CLK_PERI_1S(DEV_NAME_SDHC, 0, CLK_ID_SDHC_0,
+ PHY_BASEADDR_CLKGEN18, (I_PLL_0_2 | I_GATE_PCLK)),
+ CLK_PERI_1S(DEV_NAME_SDHC, 1, CLK_ID_SDHC_1,
+ PHY_BASEADDR_CLKGEN19, (I_PLL_0_2 | I_GATE_PCLK)),
+ CLK_PERI_1S(DEV_NAME_SDHC, 2, CLK_ID_SDHC_2,
+ PHY_BASEADDR_CLKGEN20, (I_PLL_0_2 | I_GATE_PCLK)),
+ CLK_PERI_1S(DEV_NAME_SPI, 0, CLK_ID_SPI_0,
+ PHY_BASEADDR_CLKGEN37, (I_PLL_0_2)),
+ CLK_PERI_1S(DEV_NAME_SPI, 1, CLK_ID_SPI_1,
+ PHY_BASEADDR_CLKGEN38, (I_PLL_0_2)),
+ CLK_PERI_1S(DEV_NAME_SPI, 2, CLK_ID_SPI_2,
+ PHY_BASEADDR_CLKGEN39, (I_PLL_0_2)),
+};
+
+#define CLK_PERI_NUM ((int)ARRAY_SIZE(clk_periphs))
+#define CLK_CORE_NUM ((int)ARRAY_SIZE(clk_core))
+#define CLK_DEVS_NUM (CLK_CORE_NUM + CLK_PERI_NUM)
+#define MAX_DIVIDER ((1 << 8) - 1) /* 256, align 2 */
+
+static struct clk_dev st_clk_devs[CLK_DEVS_NUM]
+ __attribute__((section(".data")));
+#define clk_dev_get(n) ((struct clk_dev *)&st_clk_devs[n])
+#define clk_container(p) (container_of(p, struct clk_dev, clk))
+
+/*
+ * Core frequencys
+ */
+struct _core_hz_ {
+ unsigned long pll[4]; /* PLL */
+ unsigned long cpu_fclk, cpu_bclk; /* cpu */
+ unsigned long mem_fclk, mem_dclk, mem_bclk, mem_pclk; /* ddr */
+ unsigned long bus_bclk, bus_pclk; /* bus */
+#if defined(CONFIG_ARCH_S5P6818)
+ unsigned long cci4_bclk, cci4_pclk; /* cci */
+#endif
+ /* ip */
+ unsigned long g3d_bclk;
+ unsigned long coda_bclk, coda_pclk;
+#if defined(CONFIG_ARCH_S5P6818)
+ unsigned long disp_bclk, disp_pclk;
+ unsigned long hdmi_pclk;
+#endif
+};
+
+/*
+ * Section ".data" must be used because BSS is not available before relocation,
+ * in board_init_f(), respectively! I.e. global variables can not be used!
+ */
+/* core clock */
+static struct _core_hz_ core_hz __attribute__((section(".data")));
+
+#define CORE_HZ_SIZE (sizeof(core_hz) / 4)
+
+/*
+ * CLKGEN HW
+ */
+static inline void clk_dev_bclk(void *base, int on)
+{
+ struct clk_dev_map *reg = base;
+ unsigned int val = readl(®->con_enb) & ~(0x3);
+
+ val |= (on ? 3 : 0) & 0x3; /* always BCLK */
+ writel(val, ®->con_enb);
+}
+
+static inline void clk_dev_pclk(void *base, int on)
+{
+ struct clk_dev_map *reg = base;
+ unsigned int val = 0;
+
+ if (!on)
+ return;
+
+ val = readl(®->con_enb) & ~(1 << 3);
+ val |= (1 << 3);
+ writel(val, ®->con_enb);
+}
+
+static inline void clk_dev_rate(void *base, int step, int src, int div)
+{
+ struct clk_dev_map *reg = base;
+ unsigned int val = 0;
+
+ val = readl(®->con_gen[step << 1]);
+ val &= ~(0x07 << 2);
+ val |= (src << 2); /* source */
+ val &= ~(0xFF << 5);
+ val |= (div - 1) << 5; /* divider */
+ writel(val, ®->con_gen[step << 1]);
+}
+
+static inline void clk_dev_inv(void *base, int step, int inv)
+{
+ struct clk_dev_map *reg = base;
+ unsigned int val = readl(®->con_gen[step << 1]) & ~(1 << 1);
+
+ val |= (inv << 1);
+ writel(val, ®->con_gen[step << 1]);
+}
+
+static inline void clk_dev_enb(void *base, int on)
+{
+ struct clk_dev_map *reg = base;
+ unsigned int val = readl(®->con_enb) & ~(1 << 2);
+
+ val |= ((on ? 1 : 0) << 2);
+ writel(val, ®->con_enb);
+}
+
+/*
+ * CORE FREQUENCY
+ *
+ * PLL0 [P,M,S] ------- | | ----- [DIV0] --- CPU-G0
+ * |M| ----- [DIV1] --- BCLK/PCLK
+ * PLL1 [P,M,S] ------- | | ----- [DIV2] --- DDR
+ * |U| ----- [DIV3] --- 3D
+ * PLL2 [P,M,S,K]-------| | ----- [DIV4] --- CODA
+ * |X| ----- [DIV5] --- DISPLAY
+ * PLL3 [P,M,S,K]-------| | ----- [DIV6] --- HDMI
+ * | | ----- [DIV7] --- CPU-G1
+ * | | ----- [DIV8] --- CCI-400(FASTBUS)
+ *
+ */
+
+struct nx_clkpwr_registerset {
+ u32 clkmodereg0; /* 0x000 : Clock Mode Register0 */
+ u32 __reserved0; /* 0x004 */
+ u32 pllsetreg[4]; /* 0x008 ~ 0x014 : PLL Setting Register */
+ u32 __reserved1[2]; /* 0x018 ~ 0x01C */
+ u32 dvoreg[9]; /* 0x020 ~ 0x040 : Divider Setting Register */
+ u32 __Reserved2; /* 0x044 */
+ u32 pllsetreg_sscg[6]; /* 0x048 ~ 0x05C */
+ u32 __reserved3[8]; /* 0x060 ~ 0x07C */
+ u8 __reserved4[0x200 - 0x80]; /* padding (0x80 ~ 0x1FF) */
+ u32 gpiowakeupriseenb; /* 0x200 : GPIO Rising Edge Detect En. Reg. */
+ u32 gpiowakeupfallenb; /* 0x204 : GPIO Falling Edge Detect En. Reg. */
+ u32 gpiorstenb; /* 0x208 : GPIO Reset Enable Register */
+ u32 gpiowakeupenb; /* 0x20C : GPIO Wakeup Source Enable */
+ u32 gpiointenb; /* 0x210 : Interrupt Enable Register */
+ u32 gpiointpend; /* 0x214 : Interrupt Pend Register */
+ u32 resetstatus; /* 0x218 : Reset Status Register */
+ u32 intenable; /* 0x21C : Interrupt Enable Register */
+ u32 intpend; /* 0x220 : Interrupt Pend Register */
+ u32 pwrcont; /* 0x224 : Power Control Register */
+ u32 pwrmode; /* 0x228 : Power Mode Register */
+ u32 __reserved5; /* 0x22C : Reserved Region */
+ u32 scratch[3]; /* 0x230 ~ 0x238 : Scratch Register */
+ u32 sysrstconfig; /* 0x23C : System Reset Configuration Reg. */
+ u8 __reserved6[0x2A0 - 0x240]; /* padding (0x240 ~ 0x29F) */
+ u32 cpupowerdownreq; /* 0x2A0 : CPU Power Down Request Register */
+ u32 cpupoweronreq; /* 0x2A4 : CPU Power On Request Register */
+ u32 cpuresetmode; /* 0x2A8 : CPU Reset Mode Register */
+ u32 cpuwarmresetreq; /* 0x2AC : CPU Warm Reset Request Register */
+ u32 __reserved7; /* 0x2B0 */
+ u32 cpustatus; /* 0x2B4 : CPU Status Register */
+ u8 __reserved8[0x400 - 0x2B8]; /* padding (0x2B8 ~ 0x33F) */
+};
+
+static struct nx_clkpwr_registerset * const clkpwr =
+ (struct nx_clkpwr_registerset *)PHY_BASEADDR_CLKPWR;
+
+#define getquotient(v, d) ((v) / (d))
+
+#define DIV_CPUG0 0
+#define DIV_BUS 1
+#define DIV_MEM 2
+#define DIV_G3D 3
+#define DIV_CODA 4
+#if defined(CONFIG_ARCH_S5P6818)
+#define DIV_DISP 5
+#define DIV_HDMI 6
+#define DIV_CPUG1 7
+#define DIV_CCI4 8
+#endif
+
+#define DVO0 3
+#define DVO1 9
+#define DVO2 15
+#define DVO3 21
+
+static unsigned int pll_rate(unsigned int plln, unsigned int xtal)
+{
+ unsigned int val, val1, nP, nM, nS, nK;
+ unsigned int temp = 0;
+
+ val = clkpwr->pllsetreg[plln];
+ val1 = clkpwr->pllsetreg_sscg[plln];
+ xtal /= 1000; /* Unit Khz */
+
+ nP = (val >> 18) & 0x03F;
+ nM = (val >> 8) & 0x3FF;
+ nS = (val >> 0) & 0x0FF;
+ nK = (val1 >> 16) & 0xFFFF;
+
+ if (plln > 1 && nK) {
+ temp = (unsigned int)(getquotient((getquotient((nK * 1000),
+ 65536) * xtal), nP) >> nS);
+ }
+
+ temp = (unsigned int)((getquotient((nM * xtal), nP) >> nS) * 1000)
+ + temp;
+ return temp;
+}
+
+static unsigned int pll_dvo(int dvo)
+{
+ unsigned int val;
+
+ val = (clkpwr->dvoreg[dvo] & 0x7);
+ return val;
+}
+
+static unsigned int pll_div(int dvo)
+{
+ unsigned int val = clkpwr->dvoreg[dvo];
+
+ return ((((val >> DVO3) & 0x3F) + 1) << 24) |
+ ((((val >> DVO2) & 0x3F) + 1) << 16) |
+ ((((val >> DVO1) & 0x3F) + 1) << 8) |
+ ((((val >> DVO0) & 0x3F) + 1) << 0);
+}
+
+#define PLLN_RATE(n) (pll_rate(n, CONFIG_SYS_PLLFIN)) /* 0~ 3 */
+#define CPU_FCLK_RATE(n) (pll_rate(pll_dvo(n), CONFIG_SYS_PLLFIN) / \
+ ((pll_div(n) >> 0) & 0x3F))
+#define CPU_BCLK_RATE(n) (pll_rate(pll_dvo(n), CONFIG_SYS_PLLFIN) / \
+ ((pll_div(n) >> 0) & 0x3F) / \
+ ((pll_div(n) >> 8) & 0x3F))
+
+#define MEM_FCLK_RATE() (pll_rate(pll_dvo(DIV_MEM), CONFIG_SYS_PLLFIN) / \
+ ((pll_div(DIV_MEM) >> 0) & 0x3F) / \
+ ((pll_div(DIV_MEM) >> 8) & 0x3F))
+
+#define MEM_DCLK_RATE() (pll_rate(pll_dvo(DIV_MEM), CONFIG_SYS_PLLFIN) / \
+ ((pll_div(DIV_MEM) >> 0) & 0x3F))
+
+#define MEM_BCLK_RATE() (pll_rate(pll_dvo(DIV_MEM), CONFIG_SYS_PLLFIN) / \
+ ((pll_div(DIV_MEM) >> 0) & 0x3F) / \
+ ((pll_div(DIV_MEM) >> 8) & 0x3F) / \
+ ((pll_div(DIV_MEM) >> 16) & 0x3F))
+#define MEM_PCLK_RATE() (pll_rate(pll_dvo(DIV_MEM), CONFIG_SYS_PLLFIN) / \
+ ((pll_div(DIV_MEM) >> 0) & 0x3F) / \
+ ((pll_div(DIV_MEM) >> 8) & 0x3F) / \
+ ((pll_div(DIV_MEM) >> 16) & 0x3F) / \
+ ((pll_div(DIV_MEM) >> 24) & 0x3F))
+
+#define BUS_BCLK_RATE() (pll_rate(pll_dvo(DIV_BUS), CONFIG_SYS_PLLFIN) / \
+ ((pll_div(DIV_BUS) >> 0) & 0x3F))
+#define BUS_PCLK_RATE() (pll_rate(pll_dvo(DIV_BUS), CONFIG_SYS_PLLFIN) / \
+ ((pll_div(DIV_BUS) >> 0) & 0x3F) / \
+ ((pll_div(DIV_BUS) >> 8) & 0x3F))
+
+#define G3D_BCLK_RATE() (pll_rate(pll_dvo(DIV_G3D), CONFIG_SYS_PLLFIN) / \
+ ((pll_div(DIV_G3D) >> 0) & 0x3F))
+
+#define MPG_BCLK_RATE() (pll_rate(pll_dvo(DIV_CODA), CONFIG_SYS_PLLFIN) / \
+ ((pll_div(DIV_CODA) >> 0) & 0x3F))
+#define MPG_PCLK_RATE() (pll_rate(pll_dvo(DIV_CODA), CONFIG_SYS_PLLFIN) / \
+ ((pll_div(DIV_CODA) >> 0) & 0x3F) / \
+ ((pll_div(DIV_CODA) >> 8) & 0x3F))
+
+#if defined(CONFIG_ARCH_S5P6818)
+#define DISP_BCLK_RATE() (pll_rate(pll_dvo(DIV_DISP), CONFIG_SYS_PLLFIN) / \
+ ((pll_div(DIV_DISP) >> 0) & 0x3F))
+#define DISP_PCLK_RATE() (pll_rate(pll_dvo(DIV_DISP), CONFIG_SYS_PLLFIN) / \
+ ((pll_div(DIV_DISP) >> 0) & 0x3F) / \
+ ((pll_div(DIV_DISP) >> 8) & 0x3F))
+
+#define HDMI_PCLK_RATE() (pll_rate(pll_dvo(DIV_HDMI), CONFIG_SYS_PLLFIN) / \
+ ((pll_div(DIV_HDMI) >> 0) & 0x3F))
+
+#define CCI4_BCLK_RATE() (pll_rate(pll_dvo(DIV_CCI4), CONFIG_SYS_PLLFIN) / \
+ ((pll_div(DIV_CCI4) >> 0) & 0x3F))
+#define CCI4_PCLK_RATE() (pll_rate(pll_dvo(DIV_CCI4), CONFIG_SYS_PLLFIN) / \
+ ((pll_div(DIV_CCI4) >> 0) & 0x3F) / \
+ ((pll_div(DIV_CCI4) >> 8) & 0x3F))
+#endif
+
+static void core_update_rate(int type)
+{
+ switch (type) {
+ case 0:
+ core_hz.pll[0] = PLLN_RATE(0); break;
+ case 1:
+ core_hz.pll[1] = PLLN_RATE(1); break;
+ case 2:
+ core_hz.pll[2] = PLLN_RATE(2); break;
+ case 3:
+ core_hz.pll[3] = PLLN_RATE(3); break;
+ case 4:
+ core_hz.cpu_fclk = CPU_FCLK_RATE(DIV_CPUG0); break;
+ case 5:
+ core_hz.mem_fclk = MEM_FCLK_RATE(); break;
+ case 6:
+ core_hz.bus_bclk = BUS_BCLK_RATE(); break;
+ case 7:
+ core_hz.bus_pclk = BUS_PCLK_RATE(); break;
+ case 8:
+ core_hz.cpu_bclk = CPU_BCLK_RATE(DIV_CPUG0); break;
+ case 9:
+ core_hz.mem_dclk = MEM_DCLK_RATE(); break;
+ case 10:
+ core_hz.mem_bclk = MEM_BCLK_RATE(); break;
+ case 11:
+ core_hz.mem_pclk = MEM_PCLK_RATE(); break;
+ case 12:
+ core_hz.g3d_bclk = G3D_BCLK_RATE(); break;
+ case 13:
+ core_hz.coda_bclk = MPG_BCLK_RATE(); break;
+ case 14:
+ core_hz.coda_pclk = MPG_PCLK_RATE(); break;
+#if defined(CONFIG_ARCH_S5P6818)
+ case 15:
+ core_hz.disp_bclk = DISP_BCLK_RATE(); break;
+ case 16:
+ core_hz.disp_pclk = DISP_PCLK_RATE(); break;
+ case 17:
+ core_hz.hdmi_pclk = HDMI_PCLK_RATE(); break;
+ case 18:
+ core_hz.cci4_bclk = CCI4_BCLK_RATE(); break;
+ case 19:
+ core_hz.cci4_pclk = CCI4_PCLK_RATE(); break;
+#endif
+ };
+}
+
+static unsigned long core_get_rate(int type)
+{
+ unsigned long rate = 0;
+
+ switch (type) {
+ case 0:
+ rate = core_hz.pll[0]; break;
+ case 1:
+ rate = core_hz.pll[1]; break;
+ case 2:
+ rate = core_hz.pll[2]; break;
+ case 3:
+ rate = core_hz.pll[3]; break;
+ case 4:
+ rate = core_hz.cpu_fclk; break;
+ case 5:
+ rate = core_hz.mem_fclk; break;
+ case 6:
+ rate = core_hz.bus_bclk; break;
+ case 7:
+ rate = core_hz.bus_pclk; break;
+ case 8:
+ rate = core_hz.cpu_bclk; break;
+ case 9:
+ rate = core_hz.mem_dclk; break;
+ case 10:
+ rate = core_hz.mem_bclk; break;
+ case 11:
+ rate = core_hz.mem_pclk; break;
+ case 12:
+ rate = core_hz.g3d_bclk; break;
+ case 13:
+ rate = core_hz.coda_bclk; break;
+ case 14:
+ rate = core_hz.coda_pclk; break;
+#if defined(CONFIG_ARCH_S5P6818)
+ case 15:
+ rate = core_hz.disp_bclk; break;
+ case 16:
+ rate = core_hz.disp_pclk; break;
+ case 17:
+ rate = core_hz.hdmi_pclk; break;
+ case 18:
+ rate = core_hz.cci4_bclk; break;
+ case 19:
+ rate = core_hz.cci4_pclk; break;
+#endif
+ default:
+ printf("unknown core clock type %d ...\n", type);
+ break;
+ };
+ return rate;
+}
+
+static long core_set_rate(struct clk *clk, long rate)
+{
+ return clk->rate;
+}
+
+static void core_rate_init(void)
+{
+ int i;
+
+ for (i = 0; i < CORE_HZ_SIZE; i++)
+ core_update_rate(i);
+}
+
+/*
+ * Clock Interfaces
+ */
+static inline long clk_divide(long rate, long request,
+ int align, int *divide)
+{
+ int div = (rate / request);
+ int max = MAX_DIVIDER & ~(align - 1);
+ int adv = (div & ~(align - 1)) + align;
+ long ret;
+
+ if (!div) {
+ if (divide)
+ *divide = 1;
+ return rate;
+ }
+
+ if (div != 1)
+ div &= ~(align - 1);
+
+ if (div != adv && abs(request - rate / div) > abs(request - rate / adv))
+ div = adv;
+
+ div = (div > max ? max : div);
+ if (divide)
+ *divide = div;
+
+ ret = rate / div;
+ return ret;
+}
+
+void clk_put(struct clk *clk)
+{
+}
+
+struct clk *clk_get(const char *id)
+{
+ struct clk_dev *cdev = clk_dev_get(0);
+ struct clk *clk = NULL;
+ const char *str = NULL, *c = NULL;
+ int i, devid;
+
+ if (id)
+ str = id;
+
+ for (i = 0; i < CLK_DEVS_NUM; i++, cdev++) {
+ if (!cdev->name)
+ continue;
+ if (!strncmp(cdev->name, str, strlen(cdev->name))) {
+ c = strrchr((const char *)str, (int)'.');
+ if (!c || !cdev->peri)
+ break;
+ devid = simple_strtoul(++c, NULL, 10);
+ if (cdev->peri->dev_id == devid)
+ break;
+ }
+ }
+ if (i < CLK_DEVS_NUM)
+ clk = &cdev->clk;
+ else
+ clk = &(clk_dev_get(7))->clk; /* pclk */
+
+ return clk ? clk : ERR_PTR(-ENOENT);
+}
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+ struct clk_dev *pll = NULL, *cdev = clk_container(clk);
+ struct clk_dev_peri *peri = cdev->peri;
+ unsigned long request = rate, rate_hz = 0;
+ unsigned int mask;
+ int step, div[2] = { 0, };
+ int i, n, clk2 = 0;
+ int start_src = 0, max_src = I_CLOCK_NUM;
+ short s1 = 0, s2 = 0, d1 = 0, d2 = 0;
+
+ if (!peri)
+ return core_set_rate(clk, rate);
+
+ step = peri->clk_step;
+ mask = peri->in_mask;
+ debug("clk: %s.%d request = %ld [input=0x%x]\n", peri->dev_name,
+ peri->dev_id, rate, mask);
+
+ if (!(I_CLOCK_MASK & mask)) {
+ if (I_PCLK_MASK & mask)
+ return core_get_rate(CORECLK_ID_PCLK);
+ else if (I_BCLK_MASK & mask)
+ return core_get_rate(CORECLK_ID_BCLK);
+ else
+ return clk->rate;
+ }
+
+next:
+ if (peri->in_mask & I_EXTCLK1_FORCE) {
+ start_src = 4; max_src = 5;
+ }
+ for (n = start_src ; max_src > n; n++) {
+ if (!(((mask & I_CLOCK_MASK) >> n) & 0x1))
+ continue;
+
+ if (n == I_EXT1_BIT) {
+ rate = peri->in_extclk_1;
+ } else if (n == I_EXT2_BIT) {
+ rate = peri->in_extclk_2;
+ } else {
+ pll = clk_dev_get(n);
+ rate = pll->clk.rate;
+ }
+
+ if (!rate)
+ continue;
+
+ for (i = 0; step > i ; i++)
+ rate = clk_divide(rate, request, 2, &div[i]);
+
+ if (rate_hz && (abs(rate - request) > abs(rate_hz - request)))
+ continue;
+
+ debug("clk: %s.%d, pll.%d[%lu] request[%ld] calc[%ld]\n",
+ peri->dev_name, peri->dev_id, n, pll->clk.rate,
+ request, rate);
+
+ if (clk2) {
+ s1 = -1, d1 = -1; /* not use */
+ s2 = n, d2 = div[0];
+ } else {
+ s1 = n, d1 = div[0];
+ s2 = I_CLKn_BIT, d2 = div[1];
+ }
+ rate_hz = rate;
+ }
+
+ /* search 2th clock from input */
+ if (!clk2 && abs(rate_hz - request) &&
+ peri->in_mask1 & ((1 << I_CLOCK_NUM) - 1)) {
+ clk2 = 1;
+ mask = peri->in_mask1;
+ step = 1;
+ goto next;
+ }
+ if (peri->in_mask & I_EXTCLK1_FORCE) {
+ if (s1 == 0) {
+ s1 = 4; s2 = 7;
+ d1 = 1; d2 = 1;
+ }
+ }
+
+ peri->div_src_0 = s1, peri->div_val_0 = d1;
+ peri->div_src_1 = s2, peri->div_val_1 = d2;
+ clk->rate = rate_hz;
+
+ debug("clk: %s.%d, step[%d] src[%d,%d] %ld", peri->dev_name,
+ peri->dev_id, peri->clk_step, peri->div_src_0, peri->div_src_1,
+ rate);
+ debug("/(div0: %d * div1: %d) = %ld, %ld diff (%ld)\n",
+ peri->div_val_0, peri->div_val_1, rate_hz, request,
+ abs(rate_hz - request));
+
+ return clk->rate;
+}
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+ struct clk_dev *cdev = clk_container(clk);
+
+ if (cdev->link)
+ clk = cdev->link;
+ return clk->rate;
+}
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+ struct clk_dev *cdev = clk_container(clk);
+ struct clk_dev_peri *peri = cdev->peri;
+ int i;
+
+ if (!peri)
+ return core_set_rate(clk, rate);
+
+ clk_round_rate(clk, rate);
+
+ for (i = 0; peri->clk_step > i ; i++) {
+ int s = (i == 0 ? peri->div_src_0 : peri->div_src_1);
+ int d = (i == 0 ? peri->div_val_0 : peri->div_val_1);
+
+ if (-1 == s)
+ continue;
+
+ clk_dev_rate(peri->base, i, s, d);
+
+ debug("clk: %s.%d (%p) set_rate [%d] src[%d] div[%d]\n",
+ peri->dev_name, peri->dev_id, peri->base, i, s, d);
+ }
+
+ return clk->rate;
+}
+
+int clk_enable(struct clk *clk)
+{
+ struct clk_dev *cdev = clk_container(clk);
+ struct clk_dev_peri *peri = cdev->peri;
+ int i = 0, inv = 0;
+
+ if (!peri)
+ return 0;
+
+ debug("clk: %s.%d enable (BCLK=%s, PCLK=%s)\n", peri->dev_name,
+ peri->dev_id, I_GATE_BCLK & peri->in_mask ? "ON" : "PASS",
+ I_GATE_PCLK & peri->in_mask ? "ON" : "PASS");
+
+ if (!(I_CLOCK_MASK & peri->in_mask)) {
+ /* Gated BCLK/PCLK enable */
+ if (I_GATE_BCLK & peri->in_mask)
+ clk_dev_bclk(peri->base, 1);
+
+ if (I_GATE_PCLK & peri->in_mask)
+ clk_dev_pclk(peri->base, 1);
+
+ return 0;
+ }
+
+ /* invert */
+ inv = peri->invert_0;
+ for (; peri->clk_step > i; i++, inv = peri->invert_1)
+ clk_dev_inv(peri->base, i, inv);
+
+ /* Gated BCLK/PCLK enable */
+ if (I_GATE_BCLK & peri->in_mask)
+ clk_dev_bclk(peri->base, 1);
+
+ if (I_GATE_PCLK & peri->in_mask)
+ clk_dev_pclk(peri->base, 1);
+
+ /* restore clock rate */
+ for (i = 0; peri->clk_step > i ; i++) {
+ int s = (i == 0 ? peri->div_src_0 : peri->div_src_1);
+ int d = (i == 0 ? peri->div_val_0 : peri->div_val_1);
+
+ if (s == -1)
+ continue;
+ clk_dev_rate(peri->base, i, s, d);
+ }
+
+ clk_dev_enb(peri->base, 1);
+
+ return 0;
+}
+
+void clk_disable(struct clk *clk)
+{
+ struct clk_dev *cdev = clk_container(clk);
+ struct clk_dev_peri *peri = cdev->peri;
+
+ if (!peri)
+ return;
+
+ debug("clk: %s.%d disable\n", peri->dev_name, peri->dev_id);
+
+ if (!(I_CLOCK_MASK & peri->in_mask)) {
+ /* Gated BCLK/PCLK disable */
+ if (I_GATE_BCLK & peri->in_mask)
+ clk_dev_bclk(peri->base, 0);
+
+ if (I_GATE_PCLK & peri->in_mask)
+ clk_dev_pclk(peri->base, 0);
+
+ return;
+ }
+
+ clk_dev_rate(peri->base, 0, 7, 256); /* for power save */
+ clk_dev_enb(peri->base, 0);
+
+ /* Gated BCLK/PCLK disable */
+ if (I_GATE_BCLK & peri->in_mask)
+ clk_dev_bclk(peri->base, 0);
+
+ if (I_GATE_PCLK & peri->in_mask)
+ clk_dev_pclk(peri->base, 0);
+}
+
+/*
+ * Core clocks APIs
+ */
+void __init clk_init(void)
+{
+ struct clk_dev *cdev = st_clk_devs;
+ struct clk_dev_peri *peri = clk_periphs;
+ struct clk *clk = NULL;
+ int i = 0;
+
+ memset(cdev, 0, sizeof(st_clk_devs));
+ core_rate_init();
+
+ for (i = 0; (CLK_CORE_NUM + CLK_PERI_NUM) > i; i++, cdev++) {
+ if (i < CLK_CORE_NUM) {
+ cdev->name = clk_core[i];
+ clk = &cdev->clk;
+ clk->rate = core_get_rate(i);
+ continue;
+ }
+
+ peri = &clk_periphs[i - CLK_CORE_NUM];
+ peri->base = (void *)peri->base;
+
+ cdev->peri = peri;
+ cdev->name = peri->dev_name;
+
+ if (!(I_CLOCK_MASK & peri->in_mask)) {
+ if (I_BCLK_MASK & peri->in_mask)
+ cdev->clk.rate = core_get_rate(CORECLK_ID_BCLK);
+ if (I_PCLK_MASK & peri->in_mask)
+ cdev->clk.rate = core_get_rate(CORECLK_ID_PCLK);
+ }
+
+ /* prevent uart clock disable for low step debug message */
+ #ifndef CONFIG_DEBUG_NX_UART
+ if (peri->dev_name) {
+ #ifdef CONFIG_BACKLIGHT_PWM
+ if (!strcmp(peri->dev_name, DEV_NAME_PWM))
+ continue;
+ #endif
+ }
+ #endif
+ }
+ debug("CPU : Clock Generator= %d EA, ", CLK_DEVS_NUM);
+}
diff --git a/arch/arm/mach-nexell/cmd_boot_linux.c b/arch/arm/mach-nexell/cmd_boot_linux.c
new file mode 100644
index 0000000..f9d2a5c
--- /dev/null
+++ b/arch/arm/mach-nexell/cmd_boot_linux.c
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2016 nexell
+ * jhkim <jhkim@nexell.co.kr>
+ */
+
+#include <common.h>
+#include <bootm.h>
+#include <command.h>
+#include <environment.h>
+#include <errno.h>
+#include <image.h>
+#include <fdt_support.h>
+
+#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_CLI_FRAMEWORK)
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static bootm_headers_t linux_images;
+
+static void boot_go_set_os(cmd_tbl_t *cmdtp, int flag, int argc,
+ char * const argv[],
+ bootm_headers_t *images)
+{
+ char * const img_addr = argv[0];
+
+ images->os.type = IH_TYPE_KERNEL;
+ images->os.comp = IH_COMP_NONE;
+ images->os.os = IH_OS_LINUX;
+ images->os.load = simple_strtoul(img_addr, NULL, 16);
+ images->ep = images->os.load;
+#if defined(CONFIG_ARM)
+ images->os.arch = IH_ARCH_ARM;
+#elif defined(CONFIG_ARM64)
+ images->os.arch = IH_ARCH_ARM64;
+#else
+ #error "Not support architecture ..."
+#endif
+
+#if !defined(CONFIG_OF_LIBFDT) && !defined(CONFIG_SPL_BUILD)
+ /* set DTB address for linux kernel */
+ if (argc > 2) {
+ unsigned long ft_addr;
+
+ ft_addr = simple_strtol(argv[2], NULL, 16);
+ images->ft_addr = (char *)ft_addr;
+
+ /*
+ * if not defined IMAGE_ENABLE_OF_LIBFDT,
+ * must be set to fdt address
+ */
+ if (!IMAGE_ENABLE_OF_LIBFDT)
+ gd->bd->bi_boot_params = ft_addr;
+
+ debug("## set ft:%08lx and boot params:%08lx [control of:%s]"
+ "...\n", ft_addr, gd->bd->bi_boot_params,
+ IMAGE_ENABLE_OF_LIBFDT ? "on" : "off");
+ }
+#endif
+}
+
+#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_LMB)
+static void boot_start_lmb(bootm_headers_t *images)
+{
+ ulong mem_start;
+ phys_size_t mem_size;
+
+ lmb_init(&images->lmb);
+
+ mem_start = getenv_bootm_low();
+ mem_size = getenv_bootm_size();
+
+ lmb_add(&images->lmb, (phys_addr_t)mem_start, mem_size);
+
+ arch_lmb_reserve(&images->lmb);
+ board_lmb_reserve(&images->lmb);
+}
+#else
+#define lmb_reserve(lmb, base, size)
+static inline void boot_start_lmb(bootm_headers_t *images) { }
+#endif
+
+int do_boot_linux(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ boot_os_fn *boot_fn;
+ bootm_headers_t *images = &linux_images;
+ int flags;
+ int ret;
+
+ boot_start_lmb(images);
+
+ flags = BOOTM_STATE_START;
+
+ argc--; argv++;
+ boot_go_set_os(cmdtp, flag, argc, argv, images);
+
+#if defined(CONFIG_OF_LIBFDT)
+ /* find flattened device tree */
+ ret = boot_get_fdt(flag, argc, argv, IH_ARCH_DEFAULT, images,
+ &images->ft_addr, &images->ft_len);
+ if (ret) {
+ puts("Could not find a valid device tree\n");
+ return 1;
+ }
+ set_working_fdt_addr((ulong)images->ft_addr);
+#endif
+#if !defined(CONFIG_OF_LIBFDT)
+ flags |= BOOTM_STATE_OS_GO;
+#endif
+
+ boot_fn = do_bootm_linux;
+ ret = boot_fn(flags, argc, argv, images);
+
+ if (ret == BOOTM_ERR_UNIMPLEMENTED)
+ show_boot_progress(BOOTSTAGE_ID_DECOMP_UNIMPL);
+ else if (ret == BOOTM_ERR_RESET)
+ do_reset(cmdtp, flag, argc, argv);
+
+ return ret;
+}
+
+U_BOOT_CMD(bootl, CONFIG_SYS_MAXARGS, 1, do_boot_linux,
+ "boot linux image from memory",
+ "[addr [arg ...]]\n - boot linux image stored in memory\n"
+ "\tuse a '-' for the DTB address\n"
+);
+#endif
+
+#if defined(CONFIG_CMD_BOOTD) && !defined(CONFIG_CMD_BOOTM)
+int do_bootd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ return run_command(env_get("bootcmd"), flag);
+}
+
+U_BOOT_CMD(boot, 1, 1, do_bootd,
+ "boot default, i.e., run 'bootcmd'",
+ ""
+);
+
+/* keep old command name "bootd" for backward compatibility */
+U_BOOT_CMD(bootd, 1, 1, do_bootd,
+ "boot default, i.e., run 'bootcmd'",
+ ""
+);
+#endif
diff --git a/arch/arm/mach-nexell/config.mk b/arch/arm/mach-nexell/config.mk
new file mode 100644
index 0000000..7b06626
--- /dev/null
+++ b/arch/arm/mach-nexell/config.mk
@@ -0,0 +1,11 @@
+#
+# (C) Copyright 2016 Nexell
+# junghyun kim<jhkim@nexell.co.kr>
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+SOCDIR=CPUDIR/$(VENDOR)
+MACHDIR=$(patsubst %,arch/arm/mach-%,$(machine-y))
+
+LDPPFLAGS += -DMACHDIR=$(MACHDIR) -DSOCDIR=$(SOCDIR)
diff --git a/arch/arm/mach-nexell/nx_gpio.c b/arch/arm/mach-nexell/nx_gpio.c
new file mode 100644
index 0000000..dfba3a2
--- /dev/null
+++ b/arch/arm/mach-nexell/nx_gpio.c
@@ -0,0 +1,352 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2016 Nexell
+ * Youngbok, Park <ybpark@nexell.co.kr>
+ */
+
+/*
+ * FIXME : will be remove after support pinctrl
+ */
+#include <linux/types.h>
+#include <asm/io.h>
+#include <asm/arch/nexell.h>
+#include "asm/arch/nx_gpio.h"
+#define NUMBER_OF_GPIO_MODULE 5
+u32 __g_nx_gpio_valid_bit[NUMBER_OF_GPIO_MODULE] = {
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF};
+
+static struct {
+ struct nx_gpio_register_set *pregister;
+} __g_module_variables[NUMBER_OF_GPIO_MODULE] = {
+ { (struct nx_gpio_register_set *)PHY_BASEADDR_GPIOA },
+ { (struct nx_gpio_register_set *)PHY_BASEADDR_GPIOB },
+ { (struct nx_gpio_register_set *)PHY_BASEADDR_GPIOC },
+ { (struct nx_gpio_register_set *)PHY_BASEADDR_GPIOD },
+ { (struct nx_gpio_register_set *)PHY_BASEADDR_GPIOE },
+};
+
+enum { nx_gpio_max_bit = 32 };
+
+void nx_gpio_set_bit(u32 *value, u32 bit, int enable)
+{
+ register u32 newvalue;
+
+ newvalue = *value;
+ newvalue &= ~(1ul << bit);
+ newvalue |= (u32)enable << bit;
+ writel(newvalue, value);
+}
+
+int nx_gpio_get_bit(u32 value, u32 bit)
+{
+ return (int)((value >> bit) & (1ul));
+}
+
+void nx_gpio_set_bit2(u32 *value, u32 bit, u32 bit_value)
+{
+ register u32 newvalue = *value;
+
+ newvalue = (u32)(newvalue & ~(3ul << (bit * 2)));
+ newvalue = (u32)(newvalue | (bit_value << (bit * 2)));
+
+ writel(newvalue, value);
+}
+
+u32 nx_gpio_get_bit2(u32 value, u32 bit)
+{
+ return (u32)((u32)(value >> (bit * 2)) & 3ul);
+}
+
+int nx_gpio_initialize(void)
+{
+ static int binit;
+ u32 i;
+
+ binit = 0;
+
+ if (binit == 0) {
+ for (i = 0; i < NUMBER_OF_GPIO_MODULE; i++)
+ __g_module_variables[i].pregister = NULL;
+ binit = true;
+ }
+ for (i = 0; i < NUMBER_OF_GPIO_MODULE; i++) {
+ __g_nx_gpio_valid_bit[i] = 0xFFFFFFFF;
+ };
+ return true;
+}
+
+u32 nx_gpio_get_number_of_module(void)
+{
+ return NUMBER_OF_GPIO_MODULE;
+}
+
+u32 nx_gpio_get_size_of_register_set(void)
+{
+ return sizeof(struct nx_gpio_register_set);
+}
+
+void nx_gpio_set_base_address(u32 module_index, void *base_address)
+{
+ __g_module_variables[module_index].pregister =
+ (struct nx_gpio_register_set *)base_address;
+}
+
+void *nx_gpio_get_base_address(u32 module_index)
+{
+ return (void *)__g_module_variables[module_index].pregister;
+}
+
+int nx_gpio_open_module(u32 module_index)
+{
+ register struct nx_gpio_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ writel(0xFFFFFFFF, &pregister->gpiox_slew_disable_default);
+ writel(0xFFFFFFFF, &pregister->gpiox_drv1_disable_default);
+ writel(0xFFFFFFFF, &pregister->gpiox_drv0_disable_default);
+ writel(0xFFFFFFFF, &pregister->gpiox_pullsel_disable_default);
+ writel(0xFFFFFFFF, &pregister->gpiox_pullenb_disable_default);
+ return true;
+}
+
+int nx_gpio_close_module(u32 module_index) { return true; }
+
+int nx_gpio_check_busy(u32 module_index) { return false; }
+
+void nx_gpio_set_pad_function(u32 module_index, u32 bit_number,
+ u32 padfunc)
+{
+ register struct nx_gpio_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ nx_gpio_set_bit2(&pregister->gpioxaltfn[bit_number / 16],
+ bit_number % 16, padfunc);
+}
+
+void nx_gpio_set_pad_function32(u32 module_index, u32 msbvalue, u32 lsbvalue)
+{
+ register struct nx_gpio_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ writel(lsbvalue, &pregister->gpioxaltfn[0]);
+ writel(msbvalue, &pregister->gpioxaltfn[1]);
+}
+
+int nx_gpio_get_pad_function(u32 module_index, u32 bit_number)
+{
+ register struct nx_gpio_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ return (int)nx_gpio_get_bit2
+ (readl(&pregister->gpioxaltfn[bit_number / 16]),
+ bit_number % 16);
+}
+
+void nx_gpio_set_output_enable(u32 module_index, u32 bit_number,
+ int output_enb)
+{
+ register struct nx_gpio_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ nx_gpio_set_bit(&pregister->gpioxoutenb, bit_number, output_enb);
+}
+
+int nx_gpio_get_detect_enable(u32 module_index, u32 bit_number)
+{
+ register struct nx_gpio_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ return nx_gpio_get_bit(readl(&pregister->gpioxdetenb), bit_number);
+}
+
+u32 nx_gpio_get_detect_enable32(u32 module_index)
+{
+ register struct nx_gpio_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ return readl(&pregister->gpioxdetenb);
+}
+
+void nx_gpio_set_detect_enable(u32 module_index, u32 bit_number,
+ int detect_enb)
+{
+ register struct nx_gpio_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ nx_gpio_set_bit(&pregister->gpioxdetenb, bit_number, detect_enb);
+}
+
+void nx_gpio_set_detect_enable32(u32 module_index, u32 enable_flag)
+{
+ register struct nx_gpio_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ writel(enable_flag, &pregister->gpioxdetenb);
+}
+
+int nx_gpio_get_output_enable(u32 module_index, u32 bit_number)
+{
+ register struct nx_gpio_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ return nx_gpio_get_bit(readl(&pregister->gpioxoutenb), bit_number);
+}
+
+void nx_gpio_set_output_enable32(u32 module_index, int output_enb)
+{
+ register struct nx_gpio_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ if (output_enb)
+ writel(0xFFFFFFFF, &pregister->gpioxoutenb);
+ else
+ writel(0x0, &pregister->gpioxoutenb);
+}
+
+u32 nx_gpio_get_output_enable32(u32 module_index)
+{
+ register struct nx_gpio_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ return readl(&pregister->gpioxoutenb);
+}
+
+void nx_gpio_set_output_value(u32 module_index, u32 bit_number, int value)
+{
+ register struct nx_gpio_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ nx_gpio_set_bit(&pregister->gpioxout, bit_number, value);
+}
+
+int nx_gpio_get_output_value(u32 module_index, u32 bit_number)
+{
+ register struct nx_gpio_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ return nx_gpio_get_bit(readl(&pregister->gpioxout), bit_number);
+}
+
+void nx_gpio_set_output_value32(u32 module_index, u32 value)
+{
+ register struct nx_gpio_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ writel(value, &pregister->gpioxout);
+}
+
+u32 nx_gpio_get_output_value32(u32 module_index)
+{
+ register struct nx_gpio_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ return readl(&pregister->gpioxout);
+}
+
+int nx_gpio_get_input_value(u32 module_index, u32 bit_number)
+{
+ register struct nx_gpio_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ return nx_gpio_get_bit(readl(&pregister->gpioxpad), bit_number);
+}
+
+void nx_gpio_set_pull_select(u32 module_index, u32 bit_number, int enable)
+{
+ nx_gpio_set_bit(&__g_module_variables[module_index]
+ .pregister->gpiox_pullsel_disable_default,
+ bit_number, true);
+ nx_gpio_set_bit
+ (&__g_module_variables[module_index].pregister->gpiox_pullsel,
+ bit_number, enable);
+}
+
+void nx_gpio_set_pull_select32(u32 module_index, u32 value)
+{
+ writel(value,
+ &__g_module_variables[module_index].pregister->gpiox_pullsel);
+}
+
+int nx_gpio_get_pull_select(u32 module_index, u32 bit_number)
+{
+ return nx_gpio_get_bit
+ (__g_module_variables[module_index].pregister->gpiox_pullsel,
+ bit_number);
+}
+
+u32 nx_gpio_get_pull_select32(u32 module_index)
+{
+ return __g_module_variables[module_index].pregister->gpiox_pullsel;
+}
+
+void nx_gpio_set_pull_mode(u32 module_index, u32 bit_number, u32 mode)
+{
+ nx_gpio_set_bit(&__g_module_variables[module_index]
+ .pregister->gpiox_pullsel_disable_default,
+ bit_number, true);
+ nx_gpio_set_bit(&__g_module_variables[module_index]
+ .pregister->gpiox_pullenb_disable_default,
+ bit_number, true);
+ if (mode == nx_gpio_pull_off) {
+ nx_gpio_set_bit
+ (&__g_module_variables[module_index].pregister->gpiox_pullenb,
+ bit_number, false);
+ nx_gpio_set_bit
+ (&__g_module_variables[module_index].pregister->gpiox_pullsel,
+ bit_number, false);
+ } else {
+ nx_gpio_set_bit
+ (&__g_module_variables[module_index].pregister->gpiox_pullsel,
+ bit_number, (mode & 1 ? true : false));
+ nx_gpio_set_bit
+ (&__g_module_variables[module_index].pregister->gpiox_pullenb,
+ bit_number, true);
+ }
+}
+
+void nx_gpio_set_fast_slew(u32 module_index, u32 bit_number,
+ int enable)
+{
+ register struct nx_gpio_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ nx_gpio_set_bit(&pregister->gpiox_slew, bit_number,
+ (int)(!enable));
+}
+
+void nx_gpio_set_drive_strength(u32 module_index, u32 bit_number,
+ u32 drvstrength)
+{
+ register struct nx_gpio_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ nx_gpio_set_bit(&pregister->gpiox_drv1, bit_number,
+ (int)(((u32)drvstrength >> 0) & 0x1));
+ nx_gpio_set_bit(&pregister->gpiox_drv0, bit_number,
+ (int)(((u32)drvstrength >> 1) & 0x1));
+}
+
+void nx_gpio_set_drive_strength_disable_default(u32 module_index,
+ u32 bit_number, int enable)
+{
+ register struct nx_gpio_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ nx_gpio_set_bit(&pregister->gpiox_drv1_disable_default, bit_number,
+ (int)(enable));
+ nx_gpio_set_bit(&pregister->gpiox_drv0_disable_default, bit_number,
+ (int)(enable));
+}
+
+u32 nx_gpio_get_drive_strength(u32 module_index, u32 bit_number)
+{
+ register struct nx_gpio_register_set *pregister;
+ register u32 retvalue;
+
+ pregister = __g_module_variables[module_index].pregister;
+ retvalue =
+ nx_gpio_get_bit(readl(&pregister->gpiox_drv0), bit_number) << 1;
+ retvalue |=
+ nx_gpio_get_bit(readl(&pregister->gpiox_drv1), bit_number) << 0;
+ return retvalue;
+}
diff --git a/arch/arm/mach-nexell/nx_sec_reg.c b/arch/arm/mach-nexell/nx_sec_reg.c
new file mode 100644
index 0000000..3d3dd9f
--- /dev/null
+++ b/arch/arm/mach-nexell/nx_sec_reg.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2016 Nexell
+ * Youngbok, Park <park@nexell.co.kr>
+ */
+
+#include <linux/types.h>
+#include <asm/io.h>
+#include <asm/arch/nexell.h>
+#include <asm/arch/sec_reg.h>
+#include <linux/linkage.h>
+
+#define NEXELL_SMC_BASE 0x82000000
+
+#define NEXELL_SMC_FN(n) (NEXELL_SMC_BASE + (n))
+
+#define NEXELL_SMC_SEC_REG_WRITE NEXELL_SMC_FN(0x0)
+#define NEXELL_SMC_SEC_REG_READ NEXELL_SMC_FN(0x1)
+
+#define SECURE_ID_SHIFT 8
+
+#define SEC_4K_OFFSET ((4 * 1024) - 1)
+#define SEC_64K_OFFSET ((64 * 1024) - 1)
+
+asmlinkage int __invoke_nexell_fn_smc(u32, u32, u32, u32);
+
+int write_sec_reg_by_id(void __iomem *reg, int val, int id)
+{
+ int ret = 0;
+ u32 off = 0;
+
+ switch (id) {
+ case NEXELL_L2C_SEC_ID:
+ case NEXELL_MIPI_SEC_ID:
+ case NEXELL_TOFF_SEC_ID:
+ off = (u32)reg & SEC_4K_OFFSET;
+ break;
+ case NEXELL_MALI_SEC_ID:
+ off = (u32)reg & SEC_64K_OFFSET;
+ break;
+ }
+ ret = __invoke_nexell_fn_smc(NEXELL_SMC_SEC_REG_WRITE |
+ ((1 << SECURE_ID_SHIFT) + id), off, val, 0);
+ return ret;
+}
+
+int read_sec_reg_by_id(void __iomem *reg, int id)
+{
+ int ret = 0;
+ u32 off = 0;
+
+ switch (id) {
+ case NEXELL_L2C_SEC_ID:
+ case NEXELL_MIPI_SEC_ID:
+ case NEXELL_TOFF_SEC_ID:
+ off = (u32)reg & SEC_4K_OFFSET;
+ break;
+ case NEXELL_MALI_SEC_ID:
+ off = (u32)reg & SEC_64K_OFFSET;
+ break;
+ }
+ ret = __invoke_nexell_fn_smc(NEXELL_SMC_SEC_REG_READ |
+ ((1 << SECURE_ID_SHIFT) + id), off, 0, 0);
+ return ret;
+}
+
+int write_sec_reg(void __iomem *reg, int val)
+{
+ int ret = 0;
+
+ ret = __invoke_nexell_fn_smc(NEXELL_SMC_SEC_REG_WRITE,
+ (u32)reg, val, 0);
+ return ret;
+}
+
+int read_sec_reg(void __iomem *reg)
+{
+ int ret = 0;
+
+ ret = __invoke_nexell_fn_smc(NEXELL_SMC_SEC_REG_READ, (u32)reg, 0, 0);
+ return ret;
+}
diff --git a/arch/arm/mach-nexell/reg-call.S b/arch/arm/mach-nexell/reg-call.S
new file mode 100644
index 0000000..5fdf515
--- /dev/null
+++ b/arch/arm/mach-nexell/reg-call.S
@@ -0,0 +1,23 @@
+#include <asm-offsets.h>
+#include <config.h>
+#include <linux/linkage.h>
+
+#define ___asm_opcode_identity32(x) ((x) & 0xFFFFFFFF)
+#define __opcode_to_mem_arm(x) ___opcode_identity32(x)
+#define ___asm_opcode_to_mem_arm(x) ___asm_opcode_identity32(x)
+
+#define ___opcode_identity32(x) ((u32)(x))
+#define ___inst_arm(x) .long x
+#define __inst_arm(x) ___inst_arm(___asm_opcode_to_mem_arm(x))
+
+#define __inst_arm_thumb32(arm_opcode, thumb_opcode) __inst_arm(arm_opcode)
+
+#define __SMC(imm4) __inst_arm_thumb32( \
+ 0xE1600070 | (((imm4) & 0xF) << 0), \
+ 0xF7F08000 | (((imm4) & 0xF) << 16) \
+)
+
+ENTRY(__invoke_nexell_fn_smc)
+ __SMC(0)
+ bx lr
+ENDPROC(__invoke_nexell_fn_smc)
diff --git a/arch/arm/mach-nexell/reset.c b/arch/arm/mach-nexell/reset.c
new file mode 100644
index 0000000..1f732a3
--- /dev/null
+++ b/arch/arm/mach-nexell/reset.c
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2016 Nexell
+ * Youngbok, Park <park@nexell.co.kr>
+ */
+
+/*
+ *FIXME : Not support device tree & reset control driver.
+ * will remove after support device tree & reset control driver.
+ */
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/nexell.h>
+#include <asm/arch/reset.h>
+
+struct nx_rstcon_registerset {
+ u32 regrst[(NUMBER_OF_RESET_MODULE_PIN + 31) >> 5];
+};
+
+static struct nx_rstcon_registerset *nx_rstcon =
+ (struct nx_rstcon_registerset *)PHY_BASEADDR_RSTCON;
+
+void nx_rstcon_setrst(u32 rstindex, enum rstcon status)
+{
+ u32 regnum, bitpos, curstat;
+
+ regnum = rstindex >> 5;
+ curstat = (u32)readl(&nx_rstcon->regrst[regnum]);
+ bitpos = rstindex & 0x1f;
+ curstat &= ~(1UL << bitpos);
+ curstat |= (status & 0x01) << bitpos;
+ writel(curstat, &nx_rstcon->regrst[regnum]);
+}
diff --git a/arch/arm/mach-nexell/serial.c b/arch/arm/mach-nexell/serial.c
new file mode 100644
index 0000000..c137922
--- /dev/null
+++ b/arch/arm/mach-nexell/serial.c
@@ -0,0 +1,262 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2016 Nexell
+ * Hyunseok, Jung <hsjung@nexell.co.kr>
+ */
+
+#include <common.h>
+#include <linux/compiler.h>
+#include <asm/io.h>
+#include <asm/arch/clk.h>
+#include <serial.h>
+#include <asm/arch/nexell.h>
+#include <asm/arch/clk.h>
+
+/* baudrate rest value */
+union br_rest {
+ unsigned short slot; /* udivslot */
+ unsigned char value; /* ufracval */
+};
+
+struct s5p_uart {
+ unsigned int ulcon;
+ unsigned int ucon;
+ unsigned int ufcon;
+ unsigned int umcon;
+ unsigned int utrstat;
+ unsigned int uerstat;
+ unsigned int ufstat;
+ unsigned int umstat;
+ unsigned char utxh;
+ unsigned char res1[3];
+ unsigned char urxh;
+ unsigned char res2[3];
+ unsigned int ubrdiv;
+ union br_rest rest;
+ unsigned char res3[0x3d0];
+};
+
+static inline int s5p_uart_divslot(void)
+{
+ return 1;
+}
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define CONSOLE_PORT CONFIG_S5P_SERIAL_INDEX
+#if (0 == CONSOLE_PORT)
+#define CONFIG_S5P_SERIAL_PORT (void *)PHY_BASEADDR_UART0
+#elif (1 == CONSOLE_PORT)
+#define CONFIG_S5P_SERIAL_PORT (void *)PHY_BASEADDR_UART1
+#elif (2 == CONSOLE_PORT)
+#define CONFIG_S5P_SERIAL_PORT (void *)PHY_BASEADDR_UART2
+#elif (3 == CONSOLE_PORT)
+#define CONFIG_S5P_SERIAL_PORT (void *)PHY_BASEADDR_UART3
+#elif (4 == CONSOLE_PORT)
+#define CONFIG_S5P_SERIAL_PORT (void *)PHY_BASEADDR_UART4
+#elif (5 == CONSOLE_PORT)
+#define CONFIG_S5P_SERIAL_PORT (void *)PHY_BASEADDR_UART5
+#endif
+static unsigned char *const port = CONFIG_S5P_SERIAL_PORT;
+static unsigned int const clock_in = CONFIG_S5P_SERIAL_CLOCK;
+
+#define RX_FIFO_COUNT_MASK 0xff
+#define RX_FIFO_FULL_MASK (1 << 8)
+#define TX_FIFO_FULL_MASK (1 << 24)
+
+static void __serial_device_init(void)
+{
+ char dev[10];
+
+ sprintf(dev, "nx-uart.%d", CONFIG_S5P_SERIAL_INDEX);
+
+ struct clk *clk = clk_get((const char *)dev);
+
+ /* set clock */
+ clk_disable(clk);
+ clk_set_rate(clk, CONFIG_UART_CLKGEN_CLOCK_HZ);
+ clk_enable(clk);
+}
+
+void serial_device_init(void)
+ __attribute__((weak, alias("__serial_device_init")));
+
+static inline struct s5p_uart *s5p_get_base_uart(int dev_index)
+{
+ return (struct s5p_uart *)port;
+}
+
+/*
+ * The coefficient, used to calculate the baudrate on S5P UARTs is
+ * calculated as
+ * C = UBRDIV * 16 + number_of_set_bits_in_UDIVSLOT
+ * however, section 31.6.11 of the datasheet doesn't recomment using 1 for 1,
+ * 3 for 2, ... (2^n - 1) for n, instead, they suggest using these constants:
+ */
+static const int udivslot[] = {
+ 0,
+ 0x0080,
+ 0x0808,
+ 0x0888,
+ 0x2222,
+ 0x4924,
+ 0x4a52,
+ 0x54aa,
+ 0x5555,
+ 0xd555,
+ 0xd5d5,
+ 0xddd5,
+ 0xdddd,
+ 0xdfdd,
+ 0xdfdf,
+ 0xffdf,
+};
+
+static void serial_setbrg_dev(const int dev_index)
+{
+ struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
+ u32 uclk = clock_in;
+ u32 baudrate = gd->baudrate;
+ u32 val;
+
+ val = uclk / baudrate;
+
+ writel(val / 16 - 1, &uart->ubrdiv);
+
+ if (s5p_uart_divslot())
+ writew(udivslot[val % 16], &uart->rest.slot);
+ else
+ writeb(val % 16, &uart->rest.value);
+}
+
+/*
+ * Initialise the serial port with the given baudrate. The settings
+ * are always 8 data bits, no parity, 1 stop bit, no start bits.
+ */
+static int serial_init_dev(const int dev_index)
+{
+ struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
+
+ serial_device_init();
+
+ /* enable FIFOs, auto clear Rx FIFO */
+ writel(0x3, &uart->ufcon);
+ writel(0, &uart->umcon);
+ /* 8N1 */
+ writel(0x3, &uart->ulcon);
+ /* No interrupts, no DMA, pure polling */
+ writel(0x245, &uart->ucon);
+
+ serial_setbrg_dev(dev_index);
+
+ return 0;
+}
+
+static int serial_err_check(const int dev_index, int op)
+{
+ struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
+ unsigned int mask;
+
+ /*
+ * UERSTAT
+ * Break Detect [3]
+ * Frame Err [2] : receive operation
+ * Parity Err [1] : receive operation
+ * Overrun Err [0] : receive operation
+ */
+ if (op)
+ mask = 0x8;
+ else
+ mask = 0xf;
+
+ return readl(&uart->uerstat) & mask;
+}
+
+/*
+ * Read a single byte from the serial port. Returns 1 on success, 0
+ * otherwise. When the function is succesfull, the character read is
+ * written into its argument c.
+ */
+static int serial_getc_dev(const int dev_index)
+{
+ struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
+
+ /* wait for character to arrive */
+ while (!(readl(&uart->ufstat) & (RX_FIFO_COUNT_MASK |
+ RX_FIFO_FULL_MASK))) {
+ if (serial_err_check(dev_index, 0))
+ return 0;
+ }
+
+ return (int)(readb(&uart->urxh) & 0xff);
+}
+
+/*
+ * Output a single byte to the serial port.
+ */
+static void serial_putc_dev(const char c, const int dev_index)
+{
+ struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
+
+ /* wait for room in the tx FIFO */
+ while ((readl(&uart->ufstat) & TX_FIFO_FULL_MASK)) {
+ if (serial_err_check(dev_index, 1))
+ return;
+ }
+
+ writeb(c, &uart->utxh);
+
+ /* If \n, also do \r */
+ if (c == '\n')
+ serial_putc('\r');
+}
+
+/*
+ * Test whether a character is in the RX buffer
+ */
+static int serial_tstc_dev(const int dev_index)
+{
+ struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
+
+ return (int)(readl(&uart->utrstat) & 0x1);
+}
+
+static void serial_puts_dev(const char *s, const int dev_index)
+{
+ while (*s)
+ serial_putc_dev(*s++, dev_index);
+}
+
+static int s5p_serial_init(void)
+{ return serial_init_dev(CONSOLE_PORT); }
+static void s5p_serial_setbrg(void)
+{ serial_setbrg_dev(CONSOLE_PORT); }
+static int s5p_serial_getc(void)
+{ return serial_getc_dev(CONSOLE_PORT); }
+static int s5p_serial_tstc(void)
+{ return serial_tstc_dev(CONSOLE_PORT); }
+static void s5p_serial_putc(const char c)
+{ serial_putc_dev(c, CONSOLE_PORT); }
+static void s5p_serial_puts(const char *s)
+{ serial_puts_dev(s, CONSOLE_PORT); }
+
+static struct serial_device s5p_serial_device = {
+ .name = "serial_s5p",
+ .start = s5p_serial_init,
+ .stop = NULL,
+ .setbrg = s5p_serial_setbrg,
+ .getc = s5p_serial_getc,
+ .tstc = s5p_serial_tstc,
+ .putc = s5p_serial_putc,
+ .puts = s5p_serial_puts,
+};
+
+__weak struct serial_device *default_serial_console(void)
+{
+ return &s5p_serial_device;
+}
+
+void s5p_serial_initialize(void)
+{
+ serial_register(&s5p_serial_device);
+}
diff --git a/arch/arm/mach-nexell/tieoff.c b/arch/arm/mach-nexell/tieoff.c
new file mode 100644
index 0000000..9a89517
--- /dev/null
+++ b/arch/arm/mach-nexell/tieoff.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2016 Nexell
+ * Youngbok, Park <park@nexell.co.kr>
+ */
+
+#include <common.h>
+#include <asm/arch/nexell.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/reset.h>
+#include <asm/arch/nx_gpio.h>
+#include <asm/arch/tieoff.h>
+#include <asm/arch/sec_reg.h>
+
+#define NX_PIN_FN_SIZE 4
+#define TIEOFF_REG_NUM 33
+
+struct nx_tieoff_registerset {
+ u32 tieoffreg[TIEOFF_REG_NUM];
+};
+
+static struct nx_tieoff_registerset *nx_tieoff = (void *)PHY_BASEADDR_TIEOFF;
+
+static int tieoff_readl(void __iomem *reg)
+{
+#ifdef CONFIG_ARCH_S5P4418
+ return read_sec_reg_by_id(reg, NEXELL_TOFF_SEC_ID);
+#else
+ return readl(reg);
+#endif
+}
+
+static int tieoff_writetl(void __iomem *reg, int val)
+{
+#ifdef CONFIG_ARCH_S5P4418
+ return write_sec_reg_by_id(reg, val, NEXELL_TOFF_SEC_ID);
+#else
+ return writel(val, reg);
+#endif
+}
+
+void nx_tieoff_set(u32 tieoff_index, u32 tieoff_value)
+{
+ u32 regindex, mask;
+ u32 lsb, msb;
+ u32 regval;
+
+ u32 position;
+ u32 bitwidth;
+
+ position = tieoff_index & 0xffff;
+ bitwidth = (tieoff_index >> 16) & 0xffff;
+
+ regindex = position >> 5;
+
+ lsb = position & 0x1F;
+ msb = lsb + bitwidth;
+
+ if (msb > 32) {
+ msb &= 0x1F;
+ mask = ~(0xffffffff << lsb);
+ regval = tieoff_readl(&nx_tieoff->tieoffreg[regindex]) & mask;
+ regval |= ((tieoff_value & ((1UL << bitwidth) - 1)) << lsb);
+ tieoff_writetl(&nx_tieoff->tieoffreg[regindex], regval);
+
+ mask = (0xffffffff << msb);
+ regval = tieoff_readl(&nx_tieoff->tieoffreg[regindex]) & mask;
+ regval |= ((tieoff_value & ((1UL << bitwidth) - 1)) >> msb);
+ tieoff_writetl(&nx_tieoff->tieoffreg[regindex + 1], regval);
+ } else {
+ mask = (0xffffffff << msb) | (~(0xffffffff << lsb));
+ regval = tieoff_readl(&nx_tieoff->tieoffreg[regindex]) & mask;
+ regval |= ((tieoff_value & ((1UL << bitwidth) - 1)) << lsb);
+ tieoff_writetl(&nx_tieoff->tieoffreg[regindex], regval);
+ }
+}
+
+u32 nx_tieoff_get(u32 tieoff_index)
+{
+ u32 regindex, mask;
+ u32 lsb, msb;
+ u32 regval;
+
+ u32 position;
+ u32 bitwidth;
+
+ position = tieoff_index & 0xffff;
+ bitwidth = (tieoff_index >> 16) & 0xffff;
+
+ regindex = position / 32;
+ lsb = position % 32;
+ msb = lsb + bitwidth;
+
+ if (msb > 32) {
+ msb &= 0x1F;
+ mask = 0xffffffff << lsb;
+ regval = tieoff_readl(&nx_tieoff->tieoffreg[regindex]) & mask;
+ regval >>= lsb;
+
+ mask = ~(0xffffffff << msb);
+ regval |= ((tieoff_readl(&nx_tieoff->tieoffreg[regindex + 1])
+ & mask) << (32 - lsb));
+ } else {
+ mask = ~(0xffffffff << msb) & (0xffffffff << lsb);
+ regval = tieoff_readl(&nx_tieoff->tieoffreg[regindex]) & mask;
+ regval >>= lsb;
+ }
+ return regval;
+}
diff --git a/arch/arm/mach-nexell/timer.c b/arch/arm/mach-nexell/timer.c
new file mode 100644
index 0000000..f915684
--- /dev/null
+++ b/arch/arm/mach-nexell/timer.c
@@ -0,0 +1,297 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2016 Nexell
+ * Hyunseok, Jung <hsjung@nexell.co.kr>
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/nexell.h>
+#include <asm/arch/clk.h>
+#if defined(CONFIG_ARCH_S5P4418)
+#include <asm/arch/reset.h>
+#endif
+
+#if (CONFIG_TIMER_SYS_TICK_CH > 3)
+#error Not support timer channel. Please use "0~3" channels.
+#endif
+
+/* global variables to save timer count
+ *
+ * Section ".data" must be used because BSS is not available before relocation,
+ * in board_init_f(), respectively! I.e. global variables can not be used!
+ */
+static unsigned long timestamp __attribute__ ((section(".data")));
+static unsigned long lastdec __attribute__ ((section(".data")));
+static int timerinit __attribute__ ((section(".data")));
+
+/* macro to hw timer tick config */
+static long TIMER_FREQ = 1000000;
+static long TIMER_HZ = 1000000 / CONFIG_SYS_HZ;
+static long TIMER_COUNT = 0xFFFFFFFF;
+
+#define REG_TCFG0 (0x00)
+#define REG_TCFG1 (0x04)
+#define REG_TCON (0x08)
+#define REG_TCNTB0 (0x0C)
+#define REG_TCMPB0 (0x10)
+#define REG_TCNT0 (0x14)
+#define REG_CSTAT (0x44)
+
+#define TCON_BIT_AUTO (1 << 3)
+#define TCON_BIT_INVT (1 << 2)
+#define TCON_BIT_UP (1 << 1)
+#define TCON_BIT_RUN (1 << 0)
+#define TCFG0_BIT_CH(ch) ((ch) == 0 || (ch) == 1 ? 0 : 8)
+#define TCFG1_BIT_CH(ch) ((ch) * 4)
+#define TCON_BIT_CH(ch) ((ch) ? (ch) * 4 + 4 : 0)
+#define TINT_CH(ch) (ch)
+#define TINT_CSTAT_BIT_CH(ch) ((ch) + 5)
+#define TINT_CSTAT_MASK (0x1F)
+#define TIMER_TCNT_OFFS (0xC)
+
+void reset_timer_masked(void);
+unsigned long get_timer_masked(void);
+
+/*
+ * Timer HW
+ */
+static inline void timer_clock(void __iomem *base, int ch, int mux, int scl)
+{
+ u32 val = readl(base + REG_TCFG0) & ~(0xFF << TCFG0_BIT_CH(ch));
+
+ writel(val | ((scl - 1) << TCFG0_BIT_CH(ch)), base + REG_TCFG0);
+ val = readl(base + REG_TCFG1) & ~(0xF << TCFG1_BIT_CH(ch));
+ writel(val | (mux << TCFG1_BIT_CH(ch)), base + REG_TCFG1);
+}
+
+static inline void timer_count(void __iomem *base, int ch, unsigned int cnt)
+{
+ writel((cnt - 1), base + REG_TCNTB0 + (TIMER_TCNT_OFFS * ch));
+ writel((cnt - 1), base + REG_TCMPB0 + (TIMER_TCNT_OFFS * ch));
+}
+
+static inline void timer_start(void __iomem *base, int ch)
+{
+ int on = 0;
+ u32 val = readl(base + REG_CSTAT) & ~(TINT_CSTAT_MASK << 5 | 0x1 << ch);
+
+ writel(val | (0x1 << TINT_CSTAT_BIT_CH(ch) | on << ch),
+ base + REG_CSTAT);
+ val = readl(base + REG_TCON) & ~(0xE << TCON_BIT_CH(ch));
+ writel(val | (TCON_BIT_UP << TCON_BIT_CH(ch)), base + REG_TCON);
+
+ val &= ~(TCON_BIT_UP << TCON_BIT_CH(ch));
+ val |= ((TCON_BIT_AUTO | TCON_BIT_RUN) << TCON_BIT_CH(ch));
+ writel(val, base + REG_TCON);
+ dmb();
+}
+
+static inline void timer_stop(void __iomem *base, int ch)
+{
+ int on = 0;
+ u32 val = readl(base + REG_CSTAT) & ~(TINT_CSTAT_MASK << 5 | 0x1 << ch);
+
+ writel(val | (0x1 << TINT_CSTAT_BIT_CH(ch) | on << ch),
+ base + REG_CSTAT);
+ val = readl(base + REG_TCON) & ~(TCON_BIT_RUN << TCON_BIT_CH(ch));
+ writel(val, base + REG_TCON);
+}
+
+static inline unsigned long timer_read(void __iomem *base, int ch)
+{
+ unsigned long ret;
+
+ ret = TIMER_COUNT - readl(base + REG_TCNT0 + (TIMER_TCNT_OFFS * ch));
+ return ret;
+}
+
+int timer_init(void)
+{
+ struct clk *clk = NULL;
+ char name[16] = "pclk";
+ int ch = CONFIG_TIMER_SYS_TICK_CH;
+ unsigned long rate, tclk = 0;
+ unsigned long mout, thz, cmp = -1UL;
+ int tcnt, tscl = 0, tmux = 0;
+ int mux = 0, scl = 0;
+ void __iomem *base = (void __iomem *)PHY_BASEADDR_TIMER;
+
+ if (timerinit)
+ return 0;
+
+ /* get with PCLK */
+ clk = clk_get(name);
+ rate = clk_get_rate(clk);
+ for (mux = 0; mux < 5; mux++) {
+ mout = rate / (1 << mux), scl = mout / TIMER_FREQ,
+ thz = mout / scl;
+ if (!(mout % TIMER_FREQ) && 256 > scl) {
+ tclk = thz, tmux = mux, tscl = scl;
+ break;
+ }
+ if (scl > 256)
+ continue;
+ if (abs(thz - TIMER_FREQ) >= cmp)
+ continue;
+ tclk = thz, tmux = mux, tscl = scl;
+ cmp = abs(thz - TIMER_FREQ);
+ }
+ tcnt = tclk; /* Timer Count := 1 Mhz counting */
+
+ TIMER_FREQ = tcnt; /* Timer Count := 1 Mhz counting */
+ TIMER_HZ = TIMER_FREQ / CONFIG_SYS_HZ;
+ tcnt = TIMER_COUNT == 0xFFFFFFFF ? TIMER_COUNT + 1 : tcnt;
+
+ timer_stop(base, ch);
+ timer_clock(base, ch, tmux, tscl);
+ timer_count(base, ch, tcnt);
+ timer_start(base, ch);
+
+ reset_timer_masked();
+ timerinit = 1;
+
+ return 0;
+}
+
+void reset_timer(void)
+{
+ reset_timer_masked();
+}
+
+unsigned long get_timer(unsigned long base)
+{
+ long ret;
+ unsigned long time = get_timer_masked();
+ unsigned long hz = TIMER_HZ;
+
+ ret = time / hz - base;
+ return ret;
+}
+
+void set_timer(unsigned long t)
+{
+ timestamp = (unsigned long)t;
+}
+
+void reset_timer_masked(void)
+{
+ void __iomem *base = (void __iomem *)PHY_BASEADDR_TIMER;
+ int ch = CONFIG_TIMER_SYS_TICK_CH;
+
+ /* reset time */
+ /* capure current decrementer value time */
+ lastdec = timer_read(base, ch);
+ /* start "advancing" time stamp from 0 */
+ timestamp = 0;
+}
+
+unsigned long get_timer_masked(void)
+{
+ void __iomem *base = (void __iomem *)PHY_BASEADDR_TIMER;
+ int ch = CONFIG_TIMER_SYS_TICK_CH;
+
+ unsigned long now = timer_read(base, ch); /* current tick value */
+
+ if (now >= lastdec) { /* normal mode (non roll) */
+ /* move stamp fordward with absolute diff ticks */
+ timestamp += now - lastdec;
+ } else {
+ /* we have overflow of the count down timer */
+ /* nts = ts + ld + (TLV - now)
+ * ts=old stamp, ld=time that passed before passing through -1
+ * (TLV-now) amount of time after passing though -1
+ * nts = new "advancing time stamp"...
+ * it could also roll and cause problems.
+ */
+ timestamp += now + TIMER_COUNT - lastdec;
+ }
+ /* save last */
+ lastdec = now;
+
+ debug("now=%lu, last=%lu, timestamp=%lu\n", now, lastdec, timestamp);
+ return (unsigned long)timestamp;
+}
+
+void __udelay(unsigned long usec)
+{
+ unsigned long tmo, tmp;
+
+ debug("+udelay=%ld\n", usec);
+
+ if (!timerinit)
+ timer_init();
+
+ /* if "big" number, spread normalization to seconds */
+ if (usec >= 1000) {
+ /* start to normalize for usec to ticks per sec */
+ tmo = usec / 1000;
+ /* find number of "ticks" to wait to achieve target */
+ tmo *= TIMER_FREQ;
+ /* finish normalize. */
+ tmo /= 1000;
+ /* else small number, don't kill it prior to HZ multiply */
+ } else {
+ tmo = usec * TIMER_FREQ;
+ tmo /= (1000 * 1000);
+ }
+
+ tmp = get_timer_masked(); /* get current timestamp */
+ debug("A. tmo=%ld, tmp=%ld\n", tmo, tmp);
+
+ /* if setting this fordward will roll time stamp */
+ if (tmp > (tmo + tmp + 1))
+ /* reset "advancing" timestamp to 0, set lastdec value */
+ reset_timer_masked();
+ else
+ /* set advancing stamp wake up time */
+ tmo += tmp;
+
+ debug("B. tmo=%ld, tmp=%ld\n", tmo, tmp);
+
+ /* loop till event */
+ do {
+ tmp = get_timer_masked();
+ } while (tmo > tmp);
+ debug("-udelay=%ld\n", usec);
+}
+
+void udelay_masked(unsigned long usec)
+{
+ unsigned long tmo, endtime;
+ signed long diff;
+
+ /* if "big" number, spread normalization to seconds */
+ if (usec >= 1000) {
+ /* start to normalize for usec to ticks per sec */
+ tmo = usec / 1000;
+ /* find number of "ticks" to wait to achieve target */
+ tmo *= TIMER_FREQ;
+ /* finish normalize. */
+ tmo /= 1000;
+ } else { /* else small number, don't kill it prior to HZ multiply */
+ tmo = usec * TIMER_FREQ;
+ tmo /= (1000 * 1000);
+ }
+
+ endtime = get_timer_masked() + tmo;
+
+ do {
+ unsigned long now = get_timer_masked();
+
+ diff = endtime - now;
+ } while (diff >= 0);
+}
+
+unsigned long long get_ticks(void)
+{
+ return get_timer_masked();
+}
+
+#if defined(CONFIG_ARCH_S5P4418)
+ulong get_tbclk(void)
+{
+ ulong tbclk = TIMER_FREQ;
+ return tbclk;
+}
+#endif
--
1.9.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH 03/10] i2c: mmc: add nexell driver (gpio, i2c, mmc, pwm)
2020-02-03 19:39 [RFC PATCH 00/10] arm: add support for SoC S5P4418 Stefan Bosch
2020-02-03 20:32 ` [RFC PATCH 01/10] arm: add mach-nexell (header files) Stefan Bosch
2020-02-03 20:38 ` [RFC PATCH 02/10] arm: add mach-nexell (all files except header files) Stefan Bosch
@ 2020-02-03 20:40 ` Stefan Bosch
2020-02-04 6:58 ` Heiko Schocher
2020-02-03 20:41 ` [RFC PATCH 04/10] video: add nexell video driver (soc: displaytop) Stefan Bosch
` (8 subsequent siblings)
11 siblings, 1 reply; 19+ messages in thread
From: Stefan Bosch @ 2020-02-03 20:40 UTC (permalink / raw)
To: u-boot
Changes in relation to FriendlyARM's U-Boot nanopi2-v2016.01:
- i2c/nx_i2c.c: Some adaptions mainly because of changes in
"struct udevice".
- mmc: nexell_dw_mmc.c changed to nexell_dw_mmc_dm.c (switched to DM).
Signed-off-by: Stefan Bosch <stefan_b@posteo.net>
---
drivers/gpio/Kconfig | 9 +
drivers/gpio/Makefile | 1 +
drivers/gpio/nx_gpio.c | 252 +++++++++++++++++++
drivers/i2c/Kconfig | 9 +
drivers/i2c/Makefile | 1 +
drivers/i2c/nx_i2c.c | 537 +++++++++++++++++++++++++++++++++++++++++
drivers/mmc/Kconfig | 6 +
drivers/mmc/Makefile | 1 +
drivers/mmc/nexell_dw_mmc_dm.c | 350 +++++++++++++++++++++++++++
drivers/pwm/Makefile | 1 +
drivers/pwm/pwm-nexell.c | 252 +++++++++++++++++++
drivers/pwm/pwm-nexell.h | 54 +++++
12 files changed, 1473 insertions(+)
create mode 100644 drivers/gpio/nx_gpio.c
create mode 100644 drivers/i2c/nx_i2c.c
create mode 100644 drivers/mmc/nexell_dw_mmc_dm.c
create mode 100644 drivers/pwm/pwm-nexell.c
create mode 100644 drivers/pwm/pwm-nexell.h
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 1de6f52..febda89 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -421,4 +421,13 @@ config MT7621_GPIO
help
Say yes here to support MediaTek MT7621 compatible GPIOs.
+config NX_GPIO
+ bool "Nexell GPIO driver"
+ depends on DM_GPIO
+ help
+ Support GPIO access on Nexell SoCs. The GPIOs are arranged into
+ a number of banks (different for each SoC type) each with 32 GPIOs.
+ The GPIOs for a device are defined in the device tree with one node
+ for each bank.
+
endmenu
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 449046b..e3340de 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -65,3 +65,4 @@ obj-$(CONFIG_PM8916_GPIO) += pm8916_gpio.o
obj-$(CONFIG_MT7621_GPIO) += mt7621_gpio.o
obj-$(CONFIG_MSCC_SGPIO) += mscc_sgpio.o
obj-$(CONFIG_SIFIVE_GPIO) += sifive-gpio.o
+obj-$(CONFIG_NX_GPIO) += nx_gpio.o
diff --git a/drivers/gpio/nx_gpio.c b/drivers/gpio/nx_gpio.c
new file mode 100644
index 0000000..86472f6
--- /dev/null
+++ b/drivers/gpio/nx_gpio.c
@@ -0,0 +1,252 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2016 Nexell
+ * DeokJin, Lee <truevirtue@nexell.co.kr>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <malloc.h>
+#include <fdtdec.h>
+#include <asm/io.h>
+#include <asm/gpio.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct nx_gpio_regs {
+ u32 data; /* Data register */
+ u32 outputenb; /* Output Enable register */
+ u32 detmode[2]; /* Detect Mode Register */
+ u32 intenb; /* Interrupt Enable Register */
+ u32 det; /* Event Detect Register */
+ u32 pad; /* Pad Status Register */
+};
+
+struct nx_alive_gpio_regs {
+ u32 pwrgate; /* Power Gating Register */
+ u32 reserved0[28]; /* Reserved0 */
+ u32 outputenb_reset;/* Alive GPIO Output Enable Reset Register */
+ u32 outputenb; /* Alive GPIO Output Enable Register */
+ u32 outputenb_read; /* Alive GPIO Output Read Register */
+ u32 reserved1[3]; /* Reserved1 */
+ u32 pad_reset; /* Alive GPIO Output Reset Register */
+ u32 data; /* Alive GPIO Output Register */
+ u32 pad_read; /* Alive GPIO Pad Read Register */
+ u32 reserved2[33]; /* Reserved2 */
+ u32 pad; /* Alive GPIO Input Value Register */
+};
+
+struct nx_gpio_platdata {
+ void *regs;
+ int gpio_count;
+ const char *bank_name;
+};
+
+static int nx_alive_gpio_is_check(struct udevice *dev)
+{
+ struct nx_gpio_platdata *plat = dev_get_platdata(dev);
+ const char *bank_name = plat->bank_name;
+
+ if (!strcmp(bank_name, "gpio_alv"))
+ return 1;
+
+ return 0;
+}
+
+static int nx_alive_gpio_direction_input(struct udevice *dev, unsigned int pin)
+{
+ struct nx_gpio_platdata *plat = dev_get_platdata(dev);
+ struct nx_alive_gpio_regs *const regs = plat->regs;
+
+ setbits_le32(®s->outputenb_reset, 1 << pin);
+
+ return 0;
+}
+
+static int nx_alive_gpio_direction_output(struct udevice *dev, unsigned int pin,
+ int val)
+{
+ struct nx_gpio_platdata *plat = dev_get_platdata(dev);
+ struct nx_alive_gpio_regs *const regs = plat->regs;
+
+ if (val)
+ setbits_le32(®s->data, 1 << pin);
+ else
+ setbits_le32(®s->pad_reset, 1 << pin);
+
+ setbits_le32(®s->outputenb, 1 << pin);
+
+ return 0;
+}
+
+static int nx_alive_gpio_get_value(struct udevice *dev, unsigned int pin)
+{
+ struct nx_gpio_platdata *plat = dev_get_platdata(dev);
+ struct nx_alive_gpio_regs *const regs = plat->regs;
+ unsigned int mask = 1UL << pin;
+ unsigned int value;
+
+ value = (readl(®s->pad_read) & mask) >> pin;
+
+ return value;
+}
+
+static int nx_alive_gpio_set_value(struct udevice *dev, unsigned int pin,
+ int val)
+{
+ struct nx_gpio_platdata *plat = dev_get_platdata(dev);
+ struct nx_alive_gpio_regs *const regs = plat->regs;
+
+ if (val)
+ setbits_le32(®s->data, 1 << pin);
+ else
+ clrbits_le32(®s->pad_reset, 1 << pin);
+
+ return 0;
+}
+
+static int nx_alive_gpio_get_function(struct udevice *dev, unsigned int pin)
+{
+ struct nx_gpio_platdata *plat = dev_get_platdata(dev);
+ struct nx_alive_gpio_regs *const regs = plat->regs;
+ unsigned int mask = (1UL << pin);
+ unsigned int output;
+
+ output = readl(®s->outputenb_read) & mask;
+
+ if (output)
+ return GPIOF_OUTPUT;
+ else
+ return GPIOF_INPUT;
+}
+
+static int nx_gpio_direction_input(struct udevice *dev, unsigned int pin)
+{
+ struct nx_gpio_platdata *plat = dev_get_platdata(dev);
+ struct nx_gpio_regs *const regs = plat->regs;
+
+ if (nx_alive_gpio_is_check(dev))
+ return nx_alive_gpio_direction_input(dev, pin);
+
+ clrbits_le32(®s->outputenb, 1 << pin);
+
+ return 0;
+}
+
+static int nx_gpio_direction_output(struct udevice *dev, unsigned int pin,
+ int val)
+{
+ struct nx_gpio_platdata *plat = dev_get_platdata(dev);
+ struct nx_gpio_regs *const regs = plat->regs;
+
+ if (nx_alive_gpio_is_check(dev))
+ return nx_alive_gpio_direction_output(dev, pin, val);
+
+ if (val)
+ setbits_le32(®s->data, 1 << pin);
+ else
+ clrbits_le32(®s->data, 1 << pin);
+
+ setbits_le32(®s->outputenb, 1 << pin);
+
+ return 0;
+}
+
+static int nx_gpio_get_value(struct udevice *dev, unsigned int pin)
+{
+ struct nx_gpio_platdata *plat = dev_get_platdata(dev);
+ struct nx_gpio_regs *const regs = plat->regs;
+ unsigned int mask = 1UL << pin;
+ unsigned int value;
+
+ if (nx_alive_gpio_is_check(dev))
+ return nx_alive_gpio_get_value(dev, pin);
+
+ value = (readl(®s->pad) & mask) >> pin;
+
+ return value;
+}
+
+static int nx_gpio_set_value(struct udevice *dev, unsigned int pin, int val)
+{
+ struct nx_gpio_platdata *plat = dev_get_platdata(dev);
+ struct nx_gpio_regs *const regs = plat->regs;
+
+ if (nx_alive_gpio_is_check(dev))
+ return nx_alive_gpio_set_value(dev, pin, val);
+
+ if (val)
+ setbits_le32(®s->data, 1 << pin);
+ else
+ clrbits_le32(®s->data, 1 << pin);
+
+ return 0;
+}
+
+static int nx_gpio_get_function(struct udevice *dev, unsigned int pin)
+{
+ struct nx_gpio_platdata *plat = dev_get_platdata(dev);
+ struct nx_gpio_regs *const regs = plat->regs;
+ unsigned int mask = (1UL << pin);
+ unsigned int output;
+
+ if (nx_alive_gpio_is_check(dev))
+ return nx_alive_gpio_get_function(dev, pin);
+
+ output = readl(®s->outputenb) & mask;
+
+ if (output)
+ return GPIOF_OUTPUT;
+ else
+ return GPIOF_INPUT;
+}
+
+static int nx_gpio_probe(struct udevice *dev)
+{
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct nx_gpio_platdata *plat = dev_get_platdata(dev);
+
+ uc_priv->gpio_count = plat->gpio_count;
+ uc_priv->bank_name = plat->bank_name;
+
+ return 0;
+}
+
+static int nx_gpio_ofdata_to_platdata(struct udevice *dev)
+{
+ struct nx_gpio_platdata *plat = dev_get_platdata(dev);
+
+ plat->regs = map_physmem(devfdt_get_addr(dev),
+ sizeof(struct nx_gpio_regs),
+ MAP_NOCACHE);
+ plat->gpio_count = fdtdec_get_int(gd->fdt_blob, dev->node.of_offset,
+ "nexell,gpio-bank-width", 32);
+ plat->bank_name = fdt_getprop(gd->fdt_blob, dev->node.of_offset,
+ "gpio-bank-name", NULL);
+
+ return 0;
+}
+
+static const struct dm_gpio_ops nx_gpio_ops = {
+ .direction_input = nx_gpio_direction_input,
+ .direction_output = nx_gpio_direction_output,
+ .get_value = nx_gpio_get_value,
+ .set_value = nx_gpio_set_value,
+ .get_function = nx_gpio_get_function,
+};
+
+static const struct udevice_id nx_gpio_ids[] = {
+ { .compatible = "nexell,nexell-gpio" },
+ { }
+};
+
+U_BOOT_DRIVER(nx_gpio) = {
+ .name = "nx_gpio",
+ .id = UCLASS_GPIO,
+ .of_match = nx_gpio_ids,
+ .ops = &nx_gpio_ops,
+ .ofdata_to_platdata = nx_gpio_ofdata_to_platdata,
+ .platdata_auto_alloc_size = sizeof(struct nx_gpio_platdata),
+ .probe = nx_gpio_probe,
+};
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index 03d2fed..2cd0ed3 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -317,6 +317,15 @@ config SYS_MXC_I2C8_SLAVE
MXC I2C8 Slave
endif
+config SYS_I2C_NEXELL
+ bool "Nexell I2C driver"
+ depends on DM_I2C
+ help
+ Add support for the Nexell I2C driver. This is used with various
+ Nexell parts such as S5Pxx18 series SoCs. All chips
+ have several I2C ports and all are provided, controlled by the
+ device tree.
+
config SYS_I2C_OMAP24XX
bool "TI OMAP2+ I2C driver"
depends on ARCH_OMAP2PLUS || ARCH_K3
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index f5a471f..64b8ead 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -26,6 +26,7 @@ obj-$(CONFIG_SYS_I2C_LPC32XX) += lpc32xx_i2c.o
obj-$(CONFIG_SYS_I2C_MESON) += meson_i2c.o
obj-$(CONFIG_SYS_I2C_MVTWSI) += mvtwsi.o
obj-$(CONFIG_SYS_I2C_MXC) += mxc_i2c.o
+obj-$(CONFIG_SYS_I2C_NEXELL) += nx_i2c.o
obj-$(CONFIG_SYS_I2C_OMAP24XX) += omap24xx_i2c.o
obj-$(CONFIG_SYS_I2C_RCAR_I2C) += rcar_i2c.o
obj-$(CONFIG_SYS_I2C_RCAR_IIC) += rcar_iic.o
diff --git a/drivers/i2c/nx_i2c.c b/drivers/i2c/nx_i2c.c
new file mode 100644
index 0000000..a3eec6c
--- /dev/null
+++ b/drivers/i2c/nx_i2c.c
@@ -0,0 +1,537 @@
+#include <common.h>
+#include <errno.h>
+#include <dm.h>
+#include <i2c.h>
+#include <asm/arch/nexell.h>
+#include <asm/arch/reset.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/nx_gpio.h>
+
+#define I2C_WRITE 0
+#define I2C_READ 1
+
+#define I2C_OK 0
+#define I2C_NOK 1
+#define I2C_NACK 2
+#define I2C_NOK_LA 3 /* Lost arbitration */
+#define I2C_NOK_TOUT 4 /* time out */
+
+#define I2CLC_FILTER 0x04 /* SDA filter on*/
+#define I2CSTAT_BSY 0x20 /* Busy bit */
+#define I2CSTAT_NACK 0x01 /* Nack bit */
+#define I2CSTAT_ABT 0x08 /* Arbitration bit */
+#define I2CCON_ACKGEN 0x80 /* Acknowledge generation */
+#define I2CCON_IRENB 0x20 /* Interrupt Enable bit */
+#define I2CCON_IRPND 0x10 /* Interrupt pending bit */
+#define I2C_MODE_MT 0xC0 /* Master Transmit Mode */
+#define I2C_MODE_MR 0x80 /* Master Receive Mode */
+#define I2C_START_STOP 0x20 /* START / STOP */
+#define I2C_TXRX_ENA 0x10 /* I2C Tx/Rx enable */
+
+#define I2C_TIMEOUT_MS 10 /* 10 ms */
+
+#define I2C_M_NOSTOP 0x100
+
+#ifndef CONFIG_MAX_I2C_NUM
+#define CONFIG_MAX_I2C_NUM 3
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct nx_i2c_regs {
+ uint iiccon;
+ uint iicstat;
+ uint iicadd;
+ uint iicds;
+ uint iiclc;
+};
+
+struct nx_i2c_bus {
+ uint bus_num;
+ struct nx_i2c_regs *regs;
+ uint speed;
+ uint target_speed;
+ uint sda_delay;
+};
+
+/* s5pxx18 i2c must be reset before enabled */
+static void i2c_reset(int ch)
+{
+ int rst_id = RESET_ID_I2C0 + ch;
+
+ nx_rstcon_setrst(rst_id, 0);
+ nx_rstcon_setrst(rst_id, 1);
+}
+
+/* FIXME : this func will be removed after reset dm driver ported.
+ * set mmc pad alternative func.
+ */
+static void set_i2c_pad_func(struct nx_i2c_bus *i2c)
+{
+ switch (i2c->bus_num) {
+ case 0:
+ nx_gpio_set_pad_function(3, 2, 1);
+ nx_gpio_set_pad_function(3, 3, 1);
+ break;
+ case 1:
+ nx_gpio_set_pad_function(3, 4, 1);
+ nx_gpio_set_pad_function(3, 5, 1);
+ break;
+ case 2:
+ nx_gpio_set_pad_function(3, 6, 1);
+ nx_gpio_set_pad_function(3, 7, 1);
+ break;
+ }
+}
+
+static uint i2c_get_clkrate(struct nx_i2c_bus *bus)
+{
+ struct clk *clk;
+ int index = bus->bus_num;
+ char name[50] = {0, };
+
+ sprintf(name, "%s.%d", DEV_NAME_I2C, index);
+ clk = clk_get((const char *)name);
+ if (!clk)
+ return -1;
+
+ return clk_get_rate(clk);
+}
+
+static uint i2c_set_clk(struct nx_i2c_bus *bus, uint enb)
+{
+ struct clk *clk;
+ char name[50];
+
+ sprintf(name, "%s.%d", DEV_NAME_I2C, bus->bus_num);
+ clk = clk_get((const char *)name);
+ if (!clk)
+ return -1;
+
+ if (enb) {
+ clk_disable(clk);
+ clk_enable(clk);
+ } else {
+ clk_disable(clk);
+ }
+
+ return 0;
+}
+
+/* get i2c module number from base address */
+static uint i2c_get_busnum(struct nx_i2c_bus *bus)
+{
+ void *base_addr = (void *)PHY_BASEADDR_I2C0;
+ int i;
+
+ for (i = 0; i < CONFIG_MAX_I2C_NUM; i++) {
+ if (base_addr == ((void *)bus->regs)) {
+ bus->bus_num = i;
+ return i;
+ }
+ base_addr += 0x1000;
+ }
+
+ return -1;
+}
+
+/* Set SDA line delay */
+static int nx_i2c_set_sda_delay(struct nx_i2c_bus *bus, ulong clkin)
+{
+ struct nx_i2c_regs *i2c = bus->regs;
+ uint sda_delay = 0;
+
+ if (bus->sda_delay) {
+ sda_delay = clkin * bus->sda_delay;
+ sda_delay = DIV_ROUND_UP(sda_delay, 1000000);
+ sda_delay = DIV_ROUND_UP(sda_delay, 5);
+ if (sda_delay > 3)
+ sda_delay = 3;
+ sda_delay |= I2CLC_FILTER;
+ } else {
+ sda_delay = 0;
+ }
+
+ sda_delay &= 0x7;
+ writel(sda_delay, &i2c->iiclc);
+
+ return 0;
+}
+
+/* Calculate the value of the divider and prescaler, set the bus speed. */
+static int nx_i2c_set_bus_speed(struct udevice *dev, uint speed)
+{
+ struct nx_i2c_bus *bus = dev_get_priv(dev);
+ struct nx_i2c_regs *i2c = bus->regs;
+ unsigned long freq, pres = 16, div;
+
+ freq = i2c_get_clkrate(bus);
+ /* calculate prescaler and divisor values */
+ if ((freq / pres / (16 + 1)) > speed)
+ /* set prescaler to 512 */
+ pres = 512;
+
+ div = 0;
+ while ((freq / pres / (div + 1)) > speed)
+ div++;
+
+ /* set prescaler, divisor according to freq, also set ACKGEN, IRQ */
+ writel((div & 0x0F) | ((pres == 512) ? 0x40 : 0), &i2c->iiccon);
+
+ /* init to SLAVE REVEIVE and set slaveaddr */
+ writel(0, &i2c->iicstat);
+ writel(0x00, &i2c->iicadd);
+ /* program Master Transmit (and implicit STOP) */
+ writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat);
+
+ bus->speed = bus->target_speed / (div * pres);
+
+ return 0;
+}
+
+static void nx_i2c_set_clockrate(struct udevice *dev, uint speed)
+{
+ struct nx_i2c_bus *bus = dev_get_priv(dev);
+ ulong clkin;
+
+ nx_i2c_set_bus_speed(dev, speed);
+ clkin = bus->speed; /* the actual i2c speed */
+ clkin /= 1000; /* clkin now in Khz */
+ nx_i2c_set_sda_delay(bus, clkin);
+}
+
+static void i2c_process_node(struct udevice *dev)
+{
+ struct nx_i2c_bus *bus = dev_get_priv(dev);
+ const void *blob = gd->fdt_blob;
+
+ int node;
+
+ node = dev->node.of_offset;
+
+ bus->target_speed = fdtdec_get_int(blob, node,
+ "nexell,i2c-max-bus-freq", 0);
+ bus->sda_delay = fdtdec_get_int(blob, node,
+ "nexell,i2c-sda-delay", 0);
+}
+
+static int nx_i2c_probe(struct udevice *dev)
+{
+ struct nx_i2c_bus *bus = dev_get_priv(dev);
+
+ /* get regs */
+ bus->regs = (struct nx_i2c_regs *)devfdt_get_addr(dev);
+ /* calc index */
+ if (!i2c_get_busnum(bus)) {
+ debug("not found i2c number!\n");
+ return -1;
+ }
+
+ /* i2c optional node parsing */
+ i2c_process_node(dev);
+ if (!bus->target_speed)
+ return -1;
+
+ /* reset */
+ i2c_reset(bus->bus_num);
+ /* gpio pad */
+ set_i2c_pad_func(bus);
+
+ /* clock rate */
+ i2c_set_clk(bus, 1);
+ nx_i2c_set_clockrate(dev, bus->target_speed);
+ i2c_set_clk(bus, 0);
+
+ return 0;
+}
+
+/* i2c bus busy check */
+static int i2c_is_busy(struct nx_i2c_regs *i2c)
+{
+ ulong start_time;
+
+ start_time = get_timer(0);
+ while (readl(&i2c->iicstat) & I2CSTAT_BSY) {
+ if (get_timer(start_time) > I2C_TIMEOUT_MS) {
+ debug("Timeout\n");
+ return -I2C_NOK_TOUT;
+ }
+ }
+ return 0;
+}
+
+/* irq enable/disable functions */
+static void i2c_enable_irq(struct nx_i2c_regs *i2c)
+{
+ unsigned int reg;
+
+ reg = readl(&i2c->iiccon);
+ reg |= I2CCON_IRENB;
+ writel(reg, &i2c->iiccon);
+}
+
+/* irq clear function */
+static void i2c_clear_irq(struct nx_i2c_regs *i2c)
+{
+ clrbits_le32(&i2c->iiccon, I2CCON_IRPND);
+}
+
+/* ack enable functions */
+static void i2c_enable_ack(struct nx_i2c_regs *i2c)
+{
+ unsigned int reg;
+
+ reg = readl(&i2c->iiccon);
+ reg |= I2CCON_ACKGEN;
+ writel(reg, &i2c->iiccon);
+}
+
+static void i2c_send_stop(struct nx_i2c_regs *i2c)
+{
+ unsigned int reg;
+
+ /* Send STOP. */
+ reg = readl(&i2c->iicstat);
+ reg |= I2C_MODE_MR | I2C_TXRX_ENA;
+ reg &= (~I2C_START_STOP);
+ writel(reg, &i2c->iicstat);
+ i2c_clear_irq(i2c);
+}
+
+static int wait_for_xfer(struct nx_i2c_regs *i2c)
+{
+ unsigned long start_time = get_timer(0);
+
+ do {
+ if (readl(&i2c->iiccon) & I2CCON_IRPND)
+ return (readl(&i2c->iicstat) & I2CSTAT_NACK) ?
+ I2C_NACK : I2C_OK;
+ } while (get_timer(start_time) < I2C_TIMEOUT_MS);
+
+ return I2C_NOK_TOUT;
+}
+
+static int i2c_transfer(struct nx_i2c_regs *i2c,
+ uchar cmd_type,
+ uchar chip,
+ uchar addr[],
+ uchar addr_len,
+ uchar data[],
+ unsigned short data_len,
+ uint seq)
+{
+ uint status;
+ int i = 0, result;
+
+ if (data == 0 || data_len == 0) {
+ /*Don't support data transfer of no length or to address 0 */
+ debug("%s: bad call\n", __func__);
+ return I2C_NOK;
+ }
+
+ i2c_enable_irq(i2c);
+ i2c_enable_ack(i2c);
+
+ /* Get the slave chip address going */
+ writel(chip, &i2c->iicds);
+ status = I2C_TXRX_ENA | I2C_START_STOP;
+ if (cmd_type == I2C_WRITE || (addr && addr_len))
+ status |= I2C_MODE_MT;
+ else
+ status |= I2C_MODE_MR;
+ writel(status, &i2c->iicstat);
+ if (seq)
+ i2c_clear_irq(i2c);
+
+ /* Wait for chip address to transmit. */
+ result = wait_for_xfer(i2c);
+ if (result != I2C_OK)
+ goto bailout;
+
+ /* If register address needs to be transmitted - do it now. */
+ if (addr && addr_len) { /* register addr */
+ while ((i < addr_len) && (result == I2C_OK)) {
+ writel(addr[i++], &i2c->iicds);
+ i2c_clear_irq(i2c);
+ result = wait_for_xfer(i2c);
+ }
+
+ i = 0;
+ if (result != I2C_OK)
+ goto bailout;
+ }
+
+ switch (cmd_type) {
+ case I2C_WRITE:
+ while ((i < data_len) && (result == I2C_OK)) {
+ writel(data[i++], &i2c->iicds);
+ i2c_clear_irq(i2c);
+ result = wait_for_xfer(i2c);
+ }
+ break;
+ case I2C_READ:
+ if (addr && addr_len) {
+ /*
+ * Register address has been sent, now send slave chip
+ * address again to start the actual read transaction.
+ */
+ writel(chip, &i2c->iicds);
+
+ /* Generate a re-START. */
+ writel(I2C_MODE_MR | I2C_TXRX_ENA
+ | I2C_START_STOP, &i2c->iicstat);
+ i2c_clear_irq(i2c);
+ result = wait_for_xfer(i2c);
+ if (result != I2C_OK)
+ goto bailout;
+ }
+
+ while ((i < data_len) && (result == I2C_OK)) {
+ /* disable ACK for final READ */
+ if (i == data_len - 1)
+ clrbits_le32(&i2c->iiccon
+ , I2CCON_ACKGEN);
+
+ i2c_clear_irq(i2c);
+ result = wait_for_xfer(i2c);
+ data[i++] = readb(&i2c->iicds);
+ }
+
+ if (result == I2C_NACK)
+ result = I2C_OK; /* Normal terminated read. */
+ break;
+
+ default:
+ debug("%s: bad call\n", __func__);
+ result = I2C_NOK;
+ break;
+ }
+
+bailout:
+ return result;
+}
+
+static int nx_i2c_read(struct udevice *dev, uchar chip, uint addr,
+ uint alen, uchar *buffer, uint len, uint seq)
+{
+ struct nx_i2c_bus *i2c;
+ uchar xaddr[4];
+ int ret;
+
+ i2c = dev_get_priv(dev);
+ if (!i2c)
+ return -EFAULT;
+
+ if (alen > 4) {
+ debug("I2C read: addr len %d not supported\n", alen);
+ return -EADDRNOTAVAIL;
+ }
+
+ if (alen > 0)
+ xaddr[0] = (addr >> 24) & 0xFF;
+
+ if (alen > 0) {
+ xaddr[0] = (addr >> 24) & 0xFF;
+ xaddr[1] = (addr >> 16) & 0xFF;
+ xaddr[2] = (addr >> 8) & 0xFF;
+ xaddr[3] = addr & 0xFF;
+ }
+
+ ret = i2c_transfer(i2c->regs, I2C_READ, chip << 1,
+ &xaddr[4 - alen], alen, buffer, len, seq);
+
+ if (ret) {
+ debug("I2C read failed %d\n", ret);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int nx_i2c_write(struct udevice *dev, uchar chip, uint addr,
+ uint alen, uchar *buffer, uint len, uint seq)
+{
+ struct nx_i2c_bus *i2c;
+ uchar xaddr[4];
+ int ret;
+
+ i2c = dev_get_priv(dev);
+ if (!i2c)
+ return -EFAULT;
+
+ if (alen > 4) {
+ debug("I2C write: addr len %d not supported\n", alen);
+ return -EINVAL;
+ }
+
+ if (alen > 0) {
+ xaddr[0] = (addr >> 24) & 0xFF;
+ xaddr[1] = (addr >> 16) & 0xFF;
+ xaddr[2] = (addr >> 8) & 0xFF;
+ xaddr[3] = addr & 0xFF;
+ }
+
+ ret = i2c_transfer(i2c->regs, I2C_WRITE, chip << 1,
+ &xaddr[4 - alen], alen, buffer, len, seq);
+ if (ret) {
+ debug("I2C write failed %d\n", ret);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int nx_i2c_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs)
+{
+ struct nx_i2c_bus *bus = dev_get_priv(dev);
+ struct nx_i2c_regs *i2c = bus->regs;
+ int ret;
+ int i;
+
+ /* The power loss by the clock, only during on/off. */
+ i2c_set_clk(bus, 1);
+
+ /* Bus State(Busy) check */
+ ret = i2c_is_busy(i2c);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < nmsgs; msg++, i++) {
+ if (msg->flags & I2C_M_RD) {
+ ret = nx_i2c_read(dev, msg->addr, 0, 0, msg->buf,
+ msg->len, i);
+ } else {
+ ret = nx_i2c_write(dev, msg->addr, 0, 0, msg->buf,
+ msg->len, i);
+ }
+
+ if (ret) {
+ debug("i2c_xfer: error sending\n");
+ return -EREMOTEIO;
+ }
+ }
+ /* Send Stop */
+ i2c_send_stop(i2c);
+ i2c_set_clk(bus, 0);
+
+ return ret ? -EREMOTEIO : 0;
+};
+
+static const struct dm_i2c_ops nx_i2c_ops = {
+ .xfer = nx_i2c_xfer,
+ .set_bus_speed = nx_i2c_set_bus_speed,
+};
+
+static const struct udevice_id nx_i2c_ids[] = {
+ { .compatible = "nexell,s5pxx18-i2c" },
+ { }
+};
+
+U_BOOT_DRIVER(i2c_nexell) = {
+ .name = "i2c_nexell",
+ .id = UCLASS_I2C,
+ .of_match = nx_i2c_ids,
+ .probe = nx_i2c_probe,
+ .priv_auto_alloc_size = sizeof(struct nx_i2c_bus),
+ .ops = &nx_i2c_ops,
+};
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index 2f0eedc..bb8e7c0 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -253,6 +253,12 @@ config MMC_DW_SNPS
This selects support for Synopsys DesignWare Memory Card Interface driver
extensions used in various Synopsys ARC devboards.
+config NEXELL_DWMMC
+ bool "Nexell SD/MMC controller support"
+ depends on ARCH_NEXELL
+ depends on MMC_DW
+ default y
+
config MMC_MESON_GX
bool "Meson GX EMMC controller support"
depends on DM_MMC && BLK && ARCH_MESON
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 9c1f8e5..a7b5a7b 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -43,6 +43,7 @@ obj-$(CONFIG_SH_MMCIF) += sh_mmcif.o
obj-$(CONFIG_SH_SDHI) += sh_sdhi.o
obj-$(CONFIG_STM32_SDMMC2) += stm32_sdmmc2.o
obj-$(CONFIG_JZ47XX_MMC) += jz_mmc.o
+obj-$(CONFIG_NEXELL_DWMMC) += nexell_dw_mmc_dm.o
# SDHCI
obj-$(CONFIG_MMC_SDHCI) += sdhci.o
diff --git a/drivers/mmc/nexell_dw_mmc_dm.c b/drivers/mmc/nexell_dw_mmc_dm.c
new file mode 100644
index 0000000..b06b60d
--- /dev/null
+++ b/drivers/mmc/nexell_dw_mmc_dm.c
@@ -0,0 +1,350 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2016 Nexell
+ * Youngbok, Park <park@nexell.co.kr>
+ *
+ * (C) Copyright 2019 Stefan Bosch <stefan_b@posteo.net>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <dt-structs.h>
+#include <dwmmc.h>
+#include <syscon.h>
+#include <asm/gpio.h>
+#include <asm/arch/nx_gpio.h>
+#include <asm/arch/reset.h>
+
+#define DWMCI_CLKSEL 0x09C
+#define DWMCI_SHIFT_0 0x0
+#define DWMCI_SHIFT_1 0x1
+#define DWMCI_SHIFT_2 0x2
+#define DWMCI_SHIFT_3 0x3
+#define DWMCI_SET_SAMPLE_CLK(x) (x)
+#define DWMCI_SET_DRV_CLK(x) ((x) << 16)
+#define DWMCI_SET_DIV_RATIO(x) ((x) << 24)
+#define DWMCI_CLKCTRL 0x114
+#define NX_MMC_CLK_DELAY(x, y, a, b) ((((x) & 0xFF) << 0) |\
+ (((y) & 0x03) << 16) |\
+ (((a) & 0xFF) << 8) |\
+ (((b) & 0x03) << 24))
+
+struct nexell_mmc_plat {
+ struct mmc_config cfg;
+ struct mmc mmc;
+};
+
+struct nexell_dwmmc_priv {
+ struct clk *clk;
+ struct dwmci_host host;
+ int fifo_size;
+ bool fifo_mode;
+ int frequency;
+ u32 min_freq;
+ u32 max_freq;
+ int d_delay;
+ int d_shift;
+ int s_delay;
+ int s_shift;
+
+};
+
+struct clk *clk_get(const char *id);
+
+static void set_pin_stat(int index, int bit, int value)
+{
+#if !defined(CONFIG_SPL_BUILD)
+ nx_gpio_set_pad_function(index, bit, value);
+#else
+#if defined(CONFIG_ARCH_S5P4418) || \
+ defined(CONFIG_ARCH_S5P6818)
+
+ unsigned long base[5] = {
+ PHY_BASEADDR_GPIOA, PHY_BASEADDR_GPIOB,
+ PHY_BASEADDR_GPIOC, PHY_BASEADDR_GPIOD,
+ PHY_BASEADDR_GPIOE,
+ };
+
+ dw_mmc_set_pin(base[index], bit, value);
+#endif
+#endif
+}
+
+static void nx_dw_mmc_set_pin(struct dwmci_host *host)
+{
+ debug(" %s(): dev_index == %d", __func__, host->dev_index);
+
+ switch (host->dev_index) {
+ case 0:
+ set_pin_stat(0, 29, 1);
+ set_pin_stat(0, 31, 1);
+ set_pin_stat(1, 1, 1);
+ set_pin_stat(1, 3, 1);
+ set_pin_stat(1, 5, 1);
+ set_pin_stat(1, 7, 1);
+ break;
+ case 1:
+ set_pin_stat(3, 22, 1);
+ set_pin_stat(3, 23, 1);
+ set_pin_stat(3, 24, 1);
+ set_pin_stat(3, 25, 1);
+ set_pin_stat(3, 26, 1);
+ set_pin_stat(3, 27, 1);
+ break;
+ case 2:
+ set_pin_stat(2, 18, 2);
+ set_pin_stat(2, 19, 2);
+ set_pin_stat(2, 20, 2);
+ set_pin_stat(2, 21, 2);
+ set_pin_stat(2, 22, 2);
+ set_pin_stat(2, 23, 2);
+ if (host->buswidth == 8) {
+ set_pin_stat(4, 21, 2);
+ set_pin_stat(4, 22, 2);
+ set_pin_stat(4, 23, 2);
+ set_pin_stat(4, 24, 2);
+ }
+ break;
+ default:
+ debug(" is invalid!");
+ }
+ debug("\n");
+}
+
+static void nx_dw_mmc_clksel(struct dwmci_host *host)
+{
+ u32 val;
+
+#ifdef CONFIG_BOOST_MMC
+ val = DWMCI_SET_SAMPLE_CLK(DWMCI_SHIFT_0) |
+ DWMCI_SET_DRV_CLK(DWMCI_SHIFT_0) | DWMCI_SET_DIV_RATIO(1);
+#else
+ val = DWMCI_SET_SAMPLE_CLK(DWMCI_SHIFT_0) |
+ DWMCI_SET_DRV_CLK(DWMCI_SHIFT_0) | DWMCI_SET_DIV_RATIO(3);
+#endif
+
+ dwmci_writel(host, DWMCI_CLKSEL, val);
+}
+
+static void nx_dw_mmc_reset(int ch)
+{
+ int rst_id = RESET_ID_SDMMC0 + ch;
+
+ nx_rstcon_setrst(rst_id, 0);
+ nx_rstcon_setrst(rst_id, 1);
+}
+
+static void nx_dw_mmc_clk_delay(struct udevice *dev)
+{
+ unsigned int delay;
+ struct nexell_dwmmc_priv *priv = dev_get_priv(dev);
+ struct dwmci_host *host = &priv->host;
+
+ delay = NX_MMC_CLK_DELAY(priv->d_delay,
+ priv->d_shift, priv->s_delay, priv->s_shift);
+
+ writel(delay, (host->ioaddr + DWMCI_CLKCTRL));
+ debug("%s(): Values set: d_delay==%d, d_shift==%d, s_delay==%d, "
+ "s_shift==%d\n", __func__, priv->d_delay, priv->d_shift,
+ priv->s_delay, priv->s_shift);
+}
+
+static unsigned int nx_dw_mmc_get_clk(struct dwmci_host *host, uint freq)
+{
+ struct clk *clk;
+ struct udevice *dev = host->priv;
+ struct nexell_dwmmc_priv *priv = dev_get_priv(dev);
+
+ int index = host->dev_index;
+ char name[50] = { 0, };
+
+ clk = priv->clk;
+ if (!clk) {
+ sprintf(name, "%s.%d", DEV_NAME_SDHC, index);
+ clk = clk_get((const char *)name);
+ if (!clk)
+ return 0;
+ priv->clk = clk;
+ }
+
+ return clk_get_rate(clk) / 2;
+}
+
+static unsigned long nx_dw_mmc_set_clk(struct dwmci_host *host,
+ unsigned int rate)
+{
+ struct clk *clk;
+ char name[50] = { 0, };
+ struct udevice *dev = host->priv;
+ struct nexell_dwmmc_priv *priv = dev_get_priv(dev);
+
+ int index = host->dev_index;
+
+ clk = priv->clk;
+ if (!clk) {
+ sprintf(name, "%s.%d", DEV_NAME_SDHC, index);
+ clk = clk_get((const char *)name);
+ if (!clk)
+ return 0;
+ priv->clk = clk;
+ }
+
+ clk_disable(clk);
+ rate = clk_set_rate(clk, rate);
+ clk_enable(clk);
+
+ return rate;
+}
+
+static int nexell_dwmmc_ofdata_to_platdata(struct udevice *dev)
+{
+ /* if (dev): *priv = dev->priv, else: *priv = NULL */
+ struct nexell_dwmmc_priv *priv = dev_get_priv(dev);
+ struct dwmci_host *host = &priv->host;
+ int val = -1;
+
+ debug("%s()\n", __func__);
+
+ host->name = dev->name;
+ host->ioaddr = dev_read_addr_ptr(dev);
+
+ val = dev_read_u32_default(dev, "nexell,bus-width", -1);
+ if (val < 0) {
+ debug(" 'nexell,bus-width' missing/invalid!\n");
+ return -EINVAL;
+ }
+ host->buswidth = val;
+ host->get_mmc_clk = nx_dw_mmc_get_clk;
+ host->clksel = nx_dw_mmc_clksel;
+ host->priv = dev;
+
+ val = dev_read_u32_default(dev, "index", -1);
+ if (val < 0) {
+ debug(" 'index' missing/invalid!\n");
+ return -EINVAL;
+ }
+ host->dev_index = val;
+
+ val = dev_read_u32_default(dev, "fifo-size", 0x20);
+ if (val <= 0) {
+ debug(" 'fifo-size' missing/invalid!\n");
+ return -EINVAL;
+ }
+ priv->fifo_size = val;
+
+ priv->fifo_mode = dev_read_bool(dev, "fifo-mode");
+
+ val = dev_read_u32_default(dev, "frequency", -1);
+ if (val < 0) {
+ debug(" 'frequency' missing/invalid!\n");
+ return -EINVAL;
+ }
+ priv->frequency = val;
+
+ val = dev_read_u32_default(dev, "max-frequency", -1);
+ if (val < 0) {
+ debug(" 'max-frequency' missing/invalid!\n");
+ return -EINVAL;
+ }
+ priv->max_freq = val;
+ priv->min_freq = 400000; /* 400 kHz */
+
+ val = dev_read_u32_default(dev, "nexell,drive_dly", -1);
+ if (val < 0) {
+ debug(" 'nexell,drive_dly' missing/invalid!\n");
+ return -EINVAL;
+ }
+ priv->d_delay = val;
+
+ val = dev_read_u32_default(dev, "nexell,drive_shift", -1);
+ if (val < 0) {
+ debug(" 'nexell,drive_shift' missing/invalid!\n");
+ return -EINVAL;
+ }
+ priv->d_shift = val;
+
+ val = dev_read_u32_default(dev, "nexell,sample_dly", -1);
+ if (val < 0) {
+ debug(" 'nexell,sample_dly' missing/invalid!\n");
+ return -EINVAL;
+ }
+ priv->s_delay = val;
+
+ val = dev_read_u32_default(dev, "nexell,sample_shift", -1);
+ if (val < 0) {
+ debug(" 'nexell,sample_shift' missing/invalid!\n");
+ return -EINVAL;
+ }
+ priv->s_shift = val;
+
+ debug(" index==%d, name==%s, ioaddr==0x%08x, buswidth==%d, "
+ "fifo_size==%d, fifo_mode==%d, frequency==%d\n",
+ host->dev_index, host->name, (u32)host->ioaddr,
+ host->buswidth, priv->fifo_size, priv->fifo_mode,
+ priv->frequency);
+ debug(" min_freq==%d, max_freq==%d, delay: "
+ "0x%02x:0x%02x:0x%02x:0x%02x\n",
+ priv->min_freq, priv->max_freq, priv->d_delay,
+ priv->d_shift, priv->s_delay, priv->s_shift);
+
+ return 0;
+}
+
+static int nexell_dwmmc_probe(struct udevice *dev)
+{
+ struct nexell_mmc_plat *plat = dev_get_platdata(dev);
+ struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
+ struct nexell_dwmmc_priv *priv = dev_get_priv(dev);
+ struct dwmci_host *host = &priv->host;
+ struct udevice *pwr_dev __maybe_unused;
+
+ debug("%s():\n", __func__);
+
+ host->fifoth_val = MSIZE(0x2) |
+ RX_WMARK(priv->fifo_size / 2 - 1) |
+ TX_WMARK(priv->fifo_size / 2);
+
+ host->fifo_mode = priv->fifo_mode;
+
+ dwmci_setup_cfg(&plat->cfg, host, priv->max_freq, priv->min_freq);
+ host->mmc = &plat->mmc;
+ host->mmc->priv = &priv->host;
+ host->mmc->dev = dev;
+ upriv->mmc = host->mmc;
+
+ nx_dw_mmc_set_pin(host);
+
+ debug(" nx_dw_mmc_set_clk(host, frequency * 4 == %d)\n",
+ priv->frequency * 4);
+ nx_dw_mmc_set_clk(host, priv->frequency * 4);
+
+ nx_dw_mmc_reset(host->dev_index);
+ nx_dw_mmc_clk_delay(dev);
+
+ return dwmci_probe(dev);
+}
+
+static int nexell_dwmmc_bind(struct udevice *dev)
+{
+ struct nexell_mmc_plat *plat = dev_get_platdata(dev);
+
+ return dwmci_bind(dev, &plat->mmc, &plat->cfg);
+}
+
+static const struct udevice_id nexell_dwmmc_ids[] = {
+ { .compatible = "nexell,nexell-dwmmc" },
+ { }
+};
+
+U_BOOT_DRIVER(nexell_dwmmc_drv) = {
+ .name = "nexell_dwmmc",
+ .id = UCLASS_MMC,
+ .of_match = nexell_dwmmc_ids,
+ .ofdata_to_platdata = nexell_dwmmc_ofdata_to_platdata,
+ .ops = &dm_dwmci_ops,
+ .bind = nexell_dwmmc_bind,
+ .probe = nexell_dwmmc_probe,
+ .priv_auto_alloc_size = sizeof(struct nexell_dwmmc_priv),
+ .platdata_auto_alloc_size = sizeof(struct nexell_mmc_plat),
+};
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index a837c35..b45aada 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -16,3 +16,4 @@ obj-$(CONFIG_PWM_ROCKCHIP) += rk_pwm.o
obj-$(CONFIG_PWM_SANDBOX) += sandbox_pwm.o
obj-$(CONFIG_PWM_TEGRA) += tegra_pwm.o
obj-$(CONFIG_PWM_SUNXI) += sunxi_pwm.o
+obj-$(CONFIG_PWM_NX) += pwm-nexell.o
diff --git a/drivers/pwm/pwm-nexell.c b/drivers/pwm/pwm-nexell.c
new file mode 100644
index 0000000..6c0f8f4
--- /dev/null
+++ b/drivers/pwm/pwm-nexell.c
@@ -0,0 +1,252 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2011 Samsung Electronics
+ *
+ * Donghwa Lee <dh09.lee@samsung.com>
+ */
+
+/* This codes are copied from arch/arm/cpu/armv7/s5p-common/pwm.c */
+
+#include <common.h>
+#include <errno.h>
+#include <pwm.h>
+#include <asm/io.h>
+#include <asm/arch/clk.h>
+#include "pwm-nexell.h"
+
+#if defined(CONFIG_ARCH_NEXELL)
+#include <asm/arch/nexell.h>
+#include <asm/arch/reset.h>
+#include <asm/arch/nx_gpio.h>
+#include <asm/arch/tieoff.h>
+
+struct pwm_device {
+ int ch;
+ int grp;
+ int bit;
+ int pwm_fn;
+};
+
+static struct pwm_device pwm_dev[] = {
+ [0] = { .ch = 0, .grp = 3, .bit = 1, .pwm_fn = 1 },
+ [1] = { .ch = 1, .grp = 2, .bit = 13, .pwm_fn = 2 },
+ [2] = { .ch = 2, .grp = 2, .bit = 14, .pwm_fn = 2 },
+ [3] = { .ch = 3, .grp = 3, .bit = 0, .pwm_fn = 2 },
+};
+#endif
+
+int pwm_enable(int pwm_id)
+{
+ const struct s5p_timer *pwm =
+#if defined(CONFIG_ARCH_NEXELL)
+ (struct s5p_timer *)PHY_BASEADDR_PWM;
+#else
+ (struct s5p_timer *)samsung_get_base_timer();
+#endif
+ unsigned long tcon;
+
+ tcon = readl(&pwm->tcon);
+ tcon |= TCON_START(pwm_id);
+
+ writel(tcon, &pwm->tcon);
+
+ return 0;
+}
+
+void pwm_disable(int pwm_id)
+{
+ const struct s5p_timer *pwm =
+#if defined(CONFIG_ARCH_NEXELL)
+ (struct s5p_timer *)PHY_BASEADDR_PWM;
+#else
+ (struct s5p_timer *)samsung_get_base_timer();
+#endif
+ unsigned long tcon;
+
+ tcon = readl(&pwm->tcon);
+ tcon &= ~TCON_START(pwm_id);
+
+ writel(tcon, &pwm->tcon);
+}
+
+static unsigned long pwm_calc_tin(int pwm_id, unsigned long freq)
+{
+ unsigned long tin_parent_rate;
+ unsigned int div;
+#if defined(CONFIG_ARCH_NEXELL)
+ unsigned int pre_div;
+ const struct s5p_timer *pwm =
+ (struct s5p_timer *)PHY_BASEADDR_PWM;
+ unsigned int val;
+#endif
+
+#if defined(CONFIG_ARCH_NEXELL)
+ struct clk *clk = clk_get(CORECLK_NAME_PCLK);
+
+ tin_parent_rate = clk_get_rate(clk);
+#else
+ tin_parent_rate = get_pwm_clk();
+#endif
+
+#if defined(CONFIG_ARCH_NEXELL)
+ writel(0, &pwm->tcfg0);
+ val = readl(&pwm->tcfg0);
+
+ if (pwm_id < 2)
+ div = ((val >> 0) & 0xff) + 1;
+ else
+ div = ((val >> 8) & 0xff) + 1;
+
+ writel(0, &pwm->tcfg1);
+ val = readl(&pwm->tcfg1);
+ val = (val >> MUX_DIV_SHIFT(pwm_id)) & 0xF;
+ pre_div = (1UL << val);
+
+ freq = tin_parent_rate / div / pre_div;
+
+ return freq;
+#else
+ for (div = 2; div <= 16; div *= 2) {
+ if ((tin_parent_rate / (div << 16)) < freq)
+ return tin_parent_rate / div;
+ }
+
+ return tin_parent_rate / 16;
+#endif
+}
+
+#define NS_IN_SEC 1000000000UL
+
+int pwm_config(int pwm_id, int duty_ns, int period_ns)
+{
+ const struct s5p_timer *pwm =
+#if defined(CONFIG_ARCH_NEXELL)
+ (struct s5p_timer *)PHY_BASEADDR_PWM;
+#else
+ (struct s5p_timer *)samsung_get_base_timer();
+#endif
+ unsigned int offset;
+ unsigned long tin_rate;
+ unsigned long tin_ns;
+ unsigned long frequency;
+ unsigned long tcon;
+ unsigned long tcnt;
+ unsigned long tcmp;
+
+ /*
+ * We currently avoid using 64bit arithmetic by using the
+ * fact that anything faster than 1GHz is easily representable
+ * by 32bits.
+ */
+ if (period_ns > NS_IN_SEC || duty_ns > NS_IN_SEC || period_ns == 0)
+ return -ERANGE;
+
+ if (duty_ns > period_ns)
+ return -EINVAL;
+
+ frequency = NS_IN_SEC / period_ns;
+
+ /* Check to see if we are changing the clock rate of the PWM */
+ tin_rate = pwm_calc_tin(pwm_id, frequency);
+
+ tin_ns = NS_IN_SEC / tin_rate;
+#if defined(CONFIG_ARCH_NEXELL)
+ /* The counter starts at zero. */
+ tcnt = (period_ns / tin_ns) - 1;
+#else
+ tcnt = period_ns / tin_ns;
+#endif
+
+ /* Note, counters count down */
+ tcmp = duty_ns / tin_ns;
+ tcmp = tcnt - tcmp;
+
+ /* Update the PWM register block. */
+ offset = pwm_id * 3;
+ if (pwm_id < 4) {
+ writel(tcnt, &pwm->tcntb0 + offset);
+ writel(tcmp, &pwm->tcmpb0 + offset);
+ }
+
+ tcon = readl(&pwm->tcon);
+ tcon |= TCON_UPDATE(pwm_id);
+ if (pwm_id < 4)
+ tcon |= TCON_AUTO_RELOAD(pwm_id);
+ else
+ tcon |= TCON4_AUTO_RELOAD;
+ writel(tcon, &pwm->tcon);
+
+ tcon &= ~TCON_UPDATE(pwm_id);
+ writel(tcon, &pwm->tcon);
+
+ return 0;
+}
+
+int pwm_init(int pwm_id, int div, int invert)
+{
+ u32 val;
+ const struct s5p_timer *pwm =
+#if defined(CONFIG_ARCH_NEXELL)
+ (struct s5p_timer *)PHY_BASEADDR_PWM;
+#else
+ (struct s5p_timer *)samsung_get_base_timer();
+#endif
+ unsigned long ticks_per_period;
+ unsigned int offset, prescaler;
+
+ /*
+ * Timer Freq(HZ) =
+ * PWM_CLK / { (prescaler_value + 1) * (divider_value) }
+ */
+
+ val = readl(&pwm->tcfg0);
+ if (pwm_id < 2) {
+ prescaler = PRESCALER_0;
+ val &= ~0xff;
+ val |= (prescaler & 0xff);
+ } else {
+ prescaler = PRESCALER_1;
+ val &= ~(0xff << 8);
+ val |= (prescaler & 0xff) << 8;
+ }
+ writel(val, &pwm->tcfg0);
+ val = readl(&pwm->tcfg1);
+ val &= ~(0xf << MUX_DIV_SHIFT(pwm_id));
+ val |= (div & 0xf) << MUX_DIV_SHIFT(pwm_id);
+ writel(val, &pwm->tcfg1);
+
+ if (pwm_id == 4) {
+ /*
+ * TODO(sjg): Use this as a countdown timer for now. We count
+ * down from the maximum value to 0, then reset.
+ */
+ ticks_per_period = -1UL;
+ } else {
+ const unsigned long pwm_hz = 1000;
+#if defined(CONFIG_ARCH_NEXELL)
+ struct clk *clk = clk_get(CORECLK_NAME_PCLK);
+ unsigned long timer_rate_hz = clk_get_rate(clk) /
+#else
+ unsigned long timer_rate_hz = get_pwm_clk() /
+#endif
+ ((prescaler + 1) * (1 << div));
+
+ ticks_per_period = timer_rate_hz / pwm_hz;
+ }
+
+ /* set count value */
+ offset = pwm_id * 3;
+
+ writel(ticks_per_period, &pwm->tcntb0 + offset);
+
+ val = readl(&pwm->tcon) & ~(0xf << TCON_OFFSET(pwm_id));
+ if (invert && pwm_id < 4)
+ val |= TCON_INVERTER(pwm_id);
+ writel(val, &pwm->tcon);
+
+ nx_gpio_set_pad_function(pwm_dev[pwm_id].grp, pwm_dev[pwm_id].bit,
+ pwm_dev[pwm_id].pwm_fn);
+ pwm_enable(pwm_id);
+
+ return 0;
+}
diff --git a/drivers/pwm/pwm-nexell.h b/drivers/pwm/pwm-nexell.h
new file mode 100644
index 0000000..92dc707
--- /dev/null
+++ b/drivers/pwm/pwm-nexell.h
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: GPL-2.0+
+ *
+ * Copyright (C) 2009 Samsung Electronics
+ * Kyungmin Park <kyungmin.park@samsung.com>
+ * Minkyu Kang <mk7.kang@samsung.com>
+ */
+
+#ifndef __ASM_ARM_ARCH_PWM_H_
+#define __ASM_ARM_ARCH_PWM_H_
+
+#define PRESCALER_0 (8 - 1) /* prescaler of timer 0, 1 */
+#define PRESCALER_1 (16 - 1) /* prescaler of timer 2, 3, 4 */
+
+/* Divider MUX */
+#define MUX_DIV_1 0 /* 1/1 period */
+#define MUX_DIV_2 1 /* 1/2 period */
+#define MUX_DIV_4 2 /* 1/4 period */
+#define MUX_DIV_8 3 /* 1/8 period */
+#define MUX_DIV_16 4 /* 1/16 period */
+
+#define MUX_DIV_SHIFT(x) ((x) * 4)
+
+#define TCON_OFFSET(x) (((x) + 1) * (!!x) << 2)
+
+#define TCON_START(x) (1 << TCON_OFFSET(x))
+#define TCON_UPDATE(x) (1 << (TCON_OFFSET(x) + 1))
+#define TCON_INVERTER(x) (1 << (TCON_OFFSET(x) + 2))
+#define TCON_AUTO_RELOAD(x) (1 << (TCON_OFFSET(x) + 3))
+#define TCON4_AUTO_RELOAD (1 << 22)
+
+#ifndef __ASSEMBLY__
+struct s5p_timer {
+ unsigned int tcfg0;
+ unsigned int tcfg1;
+ unsigned int tcon;
+ unsigned int tcntb0;
+ unsigned int tcmpb0;
+ unsigned int tcnto0;
+ unsigned int tcntb1;
+ unsigned int tcmpb1;
+ unsigned int tcnto1;
+ unsigned int tcntb2;
+ unsigned int tcmpb2;
+ unsigned int tcnto2;
+ unsigned int tcntb3;
+ unsigned int res1;
+ unsigned int tcnto3;
+ unsigned int tcntb4;
+ unsigned int tcnto4;
+ unsigned int tintcstat;
+};
+#endif /* __ASSEMBLY__ */
+
+#endif
--
1.9.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH 04/10] video: add nexell video driver (soc: displaytop)
2020-02-03 19:39 [RFC PATCH 00/10] arm: add support for SoC S5P4418 Stefan Bosch
` (2 preceding siblings ...)
2020-02-03 20:40 ` [RFC PATCH 03/10] i2c: mmc: add nexell driver (gpio, i2c, mmc, pwm) Stefan Bosch
@ 2020-02-03 20:41 ` Stefan Bosch
2020-02-03 20:43 ` [RFC PATCH 05/10] video: add nexell video driver (soc: mlc, mipi) Stefan Bosch
` (7 subsequent siblings)
11 siblings, 0 replies; 19+ messages in thread
From: Stefan Bosch @ 2020-02-03 20:41 UTC (permalink / raw)
To: u-boot
Low level functions for DisplayTop (Display Topology).
Signed-off-by: Stefan Bosch <stefan_b@posteo.net>
---
drivers/video/nexell/soc/s5pxx18_soc_disptop.c | 185 ++++++++++
drivers/video/nexell/soc/s5pxx18_soc_disptop.h | 385 +++++++++++++++++++++
drivers/video/nexell/soc/s5pxx18_soc_disptop_clk.c | 309 +++++++++++++++++
drivers/video/nexell/soc/s5pxx18_soc_disptop_clk.h | 59 ++++
drivers/video/nexell/soc/s5pxx18_soc_disptype.h | 23 ++
5 files changed, 961 insertions(+)
create mode 100644 drivers/video/nexell/soc/s5pxx18_soc_disptop.c
create mode 100644 drivers/video/nexell/soc/s5pxx18_soc_disptop.h
create mode 100644 drivers/video/nexell/soc/s5pxx18_soc_disptop_clk.c
create mode 100644 drivers/video/nexell/soc/s5pxx18_soc_disptop_clk.h
create mode 100644 drivers/video/nexell/soc/s5pxx18_soc_disptype.h
diff --git a/drivers/video/nexell/soc/s5pxx18_soc_disptop.c b/drivers/video/nexell/soc/s5pxx18_soc_disptop.c
new file mode 100644
index 0000000..626e53a
--- /dev/null
+++ b/drivers/video/nexell/soc/s5pxx18_soc_disptop.c
@@ -0,0 +1,185 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Nexell Co., Ltd.
+ *
+ * Author: junghyun, kim <jhkim@nexell.co.kr>
+ */
+
+#include <linux/types.h>
+#include <linux/io.h>
+
+#include "s5pxx18_soc_disptop.h"
+
+static struct {
+ struct nx_disp_top_register_set *pregister;
+} __g_module_variables = { NULL, };
+
+int nx_disp_top_initialize(void)
+{
+ static int binit;
+ u32 i;
+
+ if (binit == 0) {
+ for (i = 0; i < NUMBER_OF_DISPTOP_MODULE; i++)
+ __g_module_variables.pregister = NULL;
+ binit = 1;
+ }
+ return 1;
+}
+
+u32 nx_disp_top_get_number_of_module(void)
+{
+ return NUMBER_OF_DISPTOP_MODULE;
+}
+
+u32 nx_disp_top_get_physical_address(void)
+{
+ static const u32 physical_addr[] = PHY_BASEADDR_DISPTOP_LIST;
+
+ return (u32)(physical_addr[0] + PHY_BASEADDR_DISPLAYTOP_MODULE_OFFSET);
+}
+
+u32 nx_disp_top_get_size_of_register_set(void)
+{
+ return sizeof(struct nx_disp_top_register_set);
+}
+
+void nx_disp_top_set_base_address(void *base_address)
+{
+ __g_module_variables.pregister =
+ (struct nx_disp_top_register_set *)base_address;
+}
+
+void *nx_disp_top_get_base_address(void)
+{
+ return (void *)__g_module_variables.pregister;
+}
+
+void nx_disp_top_set_resconvmux(int benb, u32 sel)
+{
+ register struct nx_disp_top_register_set *pregister;
+ u32 regvalue;
+
+ pregister = __g_module_variables.pregister;
+ regvalue = (benb << 31) | (sel << 0);
+ writel((u32)regvalue, &pregister->resconv_mux_ctrl);
+}
+
+void nx_disp_top_set_hdmimux(int benb, u32 sel)
+{
+ register struct nx_disp_top_register_set *pregister;
+ u32 regvalue;
+
+ pregister = __g_module_variables.pregister;
+ regvalue = (benb << 31) | (sel << 0);
+ writel((u32)regvalue, &pregister->interconv_mux_ctrl);
+}
+
+void nx_disp_top_set_mipimux(int benb, u32 sel)
+{
+ register struct nx_disp_top_register_set *pregister;
+ u32 regvalue;
+
+ pregister = __g_module_variables.pregister;
+ regvalue = (benb << 31) | (sel << 0);
+ writel((u32)regvalue, &pregister->mipi_mux_ctrl);
+}
+
+void nx_disp_top_set_lvdsmux(int benb, u32 sel)
+{
+ register struct nx_disp_top_register_set *pregister;
+ u32 regvalue;
+
+ pregister = __g_module_variables.pregister;
+ regvalue = (benb << 31) | (sel << 0);
+ writel((u32)regvalue, &pregister->lvds_mux_ctrl);
+}
+
+void nx_disp_top_set_primary_mux(u32 sel)
+{
+ register struct nx_disp_top_register_set *pregister;
+
+ pregister = __g_module_variables.pregister;
+ writel((u32)sel, &pregister->tftmpu_mux);
+}
+
+void nx_disp_top_hdmi_set_vsync_start(u32 sel)
+{
+ register struct nx_disp_top_register_set *pregister;
+
+ pregister = __g_module_variables.pregister;
+ writel((u32)sel, &pregister->hdmisyncctrl0);
+}
+
+void nx_disp_top_hdmi_set_vsync_hsstart_end(u32 start, u32 end)
+{
+ register struct nx_disp_top_register_set *pregister;
+
+ pregister = __g_module_variables.pregister;
+ writel((u32)(end << 16) | (start << 0), &pregister->hdmisyncctrl3);
+}
+
+void nx_disp_top_hdmi_set_hactive_start(u32 sel)
+{
+ register struct nx_disp_top_register_set *pregister;
+
+ pregister = __g_module_variables.pregister;
+ writel((u32)sel, &pregister->hdmisyncctrl1);
+}
+
+void nx_disp_top_hdmi_set_hactive_end(u32 sel)
+{
+ register struct nx_disp_top_register_set *pregister;
+
+ pregister = __g_module_variables.pregister;
+ writel((u32)sel, &pregister->hdmisyncctrl2);
+}
+
+void nx_disp_top_set_hdmifield(u32 enable, u32 init_val, u32 vsynctoggle,
+ u32 hsynctoggle, u32 vsyncclr, u32 hsyncclr,
+ u32 field_use, u32 muxsel)
+{
+ register struct nx_disp_top_register_set *pregister;
+ u32 regvalue;
+
+ pregister = __g_module_variables.pregister;
+ regvalue = ((enable & 0x01) << 0) | ((init_val & 0x01) << 1) |
+ ((vsynctoggle & 0x3fff) << 2) |
+ ((hsynctoggle & 0x3fff) << 17);
+ writel(regvalue, &pregister->hdmifieldctrl);
+ regvalue = ((field_use & 0x01) << 31) | ((muxsel & 0x01) << 30) |
+ ((hsyncclr) << 15) | ((vsyncclr) << 0);
+ writel(regvalue, &pregister->greg0);
+}
+
+void nx_disp_top_set_padclock(u32 mux_index, u32 padclk_cfg)
+{
+ register struct nx_disp_top_register_set *pregister;
+ u32 regvalue;
+
+ pregister = __g_module_variables.pregister;
+ regvalue = readl(&pregister->greg1);
+ if (padmux_secondary_mlc == mux_index) {
+ regvalue = regvalue & (~(0x7 << 3));
+ regvalue = regvalue | (padclk_cfg << 3);
+ } else if (padmux_resolution_conv == mux_index) {
+ regvalue = regvalue & (~(0x7 << 6));
+ regvalue = regvalue | (padclk_cfg << 6);
+ } else {
+ regvalue = regvalue & (~(0x7 << 0));
+ regvalue = regvalue | (padclk_cfg << 0);
+ }
+ writel(regvalue, &pregister->greg1);
+}
+
+void nx_disp_top_set_lcdif_enb(int enb)
+{
+ register struct nx_disp_top_register_set *pregister;
+ u32 regvalue;
+
+ pregister = __g_module_variables.pregister;
+ regvalue = readl(&pregister->greg1);
+ regvalue = regvalue & (~(0x1 << 9));
+ regvalue = regvalue | ((enb & 0x1) << 9);
+ writel(regvalue, &pregister->greg1);
+}
diff --git a/drivers/video/nexell/soc/s5pxx18_soc_disptop.h b/drivers/video/nexell/soc/s5pxx18_soc_disptop.h
new file mode 100644
index 0000000..c7bf504
--- /dev/null
+++ b/drivers/video/nexell/soc/s5pxx18_soc_disptop.h
@@ -0,0 +1,385 @@
+/* SPDX-License-Identifier: GPL-2.0+
+ *
+ * Copyright (C) 2016 Nexell Co., Ltd.
+ *
+ * Author: junghyun, kim <jhkim@nexell.co.kr>
+ */
+
+#ifndef _S5PXX18_SOC_DISPTOP_H_
+#define _S5PXX18_SOC_DISPTOP_H_
+
+#include "s5pxx18_soc_disptype.h"
+
+#define NUMBER_OF_DISPTOP_MODULE 1
+#define PHY_BASEADDR_DISPLAYTOP_MODULE 0xC0100000
+#define PHY_BASEADDR_DISPTOP_LIST \
+ { PHY_BASEADDR_DISPLAYTOP_MODULE }
+
+#define HDMI_ADDR_OFFSET \
+ (((PHY_BASEADDR_DISPLAYTOP_MODULE / 0x00100000) % 2) ? 0x100000 \
+ : 0x000000)
+#define OTHER_ADDR_OFFSET \
+ (((PHY_BASEADDR_DISPLAYTOP_MODULE / 0x00100000) % 2) ? 0x000000 \
+ : 0x100000)
+#define PHY_BASEADDR_DISPLAYTOP_MODULE_OFFSET (OTHER_ADDR_OFFSET + 0x001000)
+#define PHY_BASEADDR_DUALDISPLAY_MODULE \
+ (PHY_BASEADDR_DISPLAYTOP_MODULE + OTHER_ADDR_OFFSET + 0x002000)
+#define PHY_BASEADDR_RESCONV_MODULE \
+ (PHY_BASEADDR_DISPLAYTOP_MODULE + OTHER_ADDR_OFFSET + 0x003000)
+#define PHY_BASEADDR_LCDINTERFACE_MODULE \
+ (PHY_BASEADDR_DISPLAYTOP_MODULE + OTHER_ADDR_OFFSET + 0x004000)
+#define PHY_BASEADDR_HDMI_MODULE (PHY_BASEADDR_DISPLAYTOP_MODULE + 0x000000)
+#define PHY_BASEADDR_LVDS_MODULE \
+ (PHY_BASEADDR_DISPLAYTOP_MODULE + OTHER_ADDR_OFFSET + 0x00a000)
+
+#define NUMBER_OF_DUALDISPLAY_MODULE 1
+#define INTNUM_OF_DUALDISPLAY_MODULE_PRIMIRQ \
+ INTNUM_OF_DISPLAYTOP_MODULE_DUALDISPLAY_PRIMIRQ
+#define INTNUM_OF_DUALDISPLAY_MODULE_SECONDIRQ \
+ INTNUM_OF_DISPLAYTOP_MODULE_DUALDISPLAY_SECONDIRQ
+#define RESETINDEX_OF_DUALDISPLAY_MODULE_I_NRST \
+ RESETINDEX_OF_DISPLAYTOP_MODULE_I_DUALDISPLAY_NRST
+#define PADINDEX_OF_DUALDISPLAY_O_NCS \
+ PADINDEX_OF_DISPLAYTOP_O_DUAL_DISPLAY_PADPRIMVCLK
+#define PADINDEX_OF_DUALDISPLAY_O_NRD \
+ PADINDEX_OF_DISPLAYTOP_O_DUAL_DISPLAY_PRIM_PADN_HSYNC
+#define PADINDEX_OF_DUALDISPLAY_O_RS \
+ PADINDEX_OF_DISPLAYTOP_O_DUAL_DISPLAY_PRIM_PADN_VSYNC
+#define PADINDEX_OF_DUALDISPLAY_O_NWR \
+ PADINDEX_OF_DISPLAYTOP_O_DUAL_DISPLAY_PRIM_PADDE
+#define PADINDEX_OF_DUALDISPLAY_PADPRIMVCLK \
+ PADINDEX_OF_DISPLAYTOP_O_DUAL_DISPLAY_PADPRIMVCLK
+#define PADINDEX_OF_DUALDISPLAY_O_PRIM_PADN_HSYNC \
+ PADINDEX_OF_DISPLAYTOP_O_DUAL_DISPLAY_PRIM_PADN_HSYNC
+#define PADINDEX_OF_DUALDISPLAY_O_PRIM_PADN_VSYNC \
+ PADINDEX_OF_DISPLAYTOP_O_DUAL_DISPLAY_PRIM_PADN_VSYNC
+#define PADINDEX_OF_DUALDISPLAY_O_PRIM_PADDE \
+ PADINDEX_OF_DISPLAYTOP_O_DUAL_DISPLAY_PRIM_PADDE
+#define PADINDEX_OF_DUALDISPLAY_PRIM_0_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_0_
+#define PADINDEX_OF_DUALDISPLAY_PRIM_1_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_1_
+#define PADINDEX_OF_DUALDISPLAY_PRIM_2_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_2_
+#define PADINDEX_OF_DUALDISPLAY_PRIM_3_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_3_
+#define PADINDEX_OF_DUALDISPLAY_PRIM_4_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_4_
+#define PADINDEX_OF_DUALDISPLAY_PRIM_5_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_5_
+#define PADINDEX_OF_DUALDISPLAY_PRIM_6_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_6_
+#define PADINDEX_OF_DUALDISPLAY_PRIM_7_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_7_
+#define PADINDEX_OF_DUALDISPLAY_PRIM_8_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_8_
+#define PADINDEX_OF_DUALDISPLAY_PRIM_9_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_9_
+#define PADINDEX_OF_DUALDISPLAY_PRIM_10_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_10_
+#define PADINDEX_OF_DUALDISPLAY_PRIM_11_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_11_
+#define PADINDEX_OF_DUALDISPLAY_PRIM_12_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_12_
+#define PADINDEX_OF_DUALDISPLAY_PRIM_13_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_13_
+#define PADINDEX_OF_DUALDISPLAY_PRIM_14_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_14_
+#define PADINDEX_OF_DUALDISPLAY_PRIM_15_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_15_
+#define PADINDEX_OF_DUALDISPLAY_PRIM_16_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_16_
+#define PADINDEX_OF_DUALDISPLAY_PRIM_17_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_17_
+#define PADINDEX_OF_DUALDISPLAY_PRIM_18_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_18_
+#define PADINDEX_OF_DUALDISPLAY_PRIM_19_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_19_
+#define PADINDEX_OF_DUALDISPLAY_PRIM_20_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_20_
+#define PADINDEX_OF_DUALDISPLAY_PRIM_21_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_21_
+#define PADINDEX_OF_DUALDISPLAY_PRIM_22_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_22_
+#define PADINDEX_OF_DUALDISPLAY_PRIM_23_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_23_
+#define PADINDEX_OF_DUALDISPLAY_PADSECONDVCLK \
+ PADINDEX_OF_DISPLAYTOP_O_DUAL_DISPLAY_PADPRIMVCLK
+#define PADINDEX_OF_DUALDISPLAY_O_SECOND_PADN_HSYNC \
+ PADINDEX_OF_DISPLAYTOP_O_DUAL_DISPLAY_PRIM_PADN_HSYNC
+#define PADINDEX_OF_DUALDISPLAY_O_SECOND_PADN_VSYNC \
+ PADINDEX_OF_DISPLAYTOP_O_DUAL_DISPLAY_PRIM_PADN_VSYNC
+#define PADINDEX_OF_DUALDISPLAY_O_SECOND_PADDE \
+ PADINDEX_OF_DISPLAYTOP_O_DUAL_DISPLAY_PRIM_PADDE
+#define PADINDEX_OF_DUALDISPLAY_SECOND_0_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_0_
+#define PADINDEX_OF_DUALDISPLAY_SECOND_1_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_1_
+#define PADINDEX_OF_DUALDISPLAY_SECOND_2_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_2_
+#define PADINDEX_OF_DUALDISPLAY_SECOND_3_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_3_
+#define PADINDEX_OF_DUALDISPLAY_SECOND_4_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_4_
+#define PADINDEX_OF_DUALDISPLAY_SECOND_5_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_5_
+#define PADINDEX_OF_DUALDISPLAY_SECOND_6_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_6_
+#define PADINDEX_OF_DUALDISPLAY_SECOND_7_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_7_
+#define PADINDEX_OF_DUALDISPLAY_SECOND_8_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_8_
+#define PADINDEX_OF_DUALDISPLAY_SECOND_9_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_9_
+#define PADINDEX_OF_DUALDISPLAY_SECOND_10_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_10_
+#define PADINDEX_OF_DUALDISPLAY_SECOND_11_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_11_
+#define PADINDEX_OF_DUALDISPLAY_SECOND_12_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_12_
+#define PADINDEX_OF_DUALDISPLAY_SECOND_13_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_13_
+#define PADINDEX_OF_DUALDISPLAY_SECOND_14_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_14_
+#define PADINDEX_OF_DUALDISPLAY_SECOND_15_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_15_
+#define PADINDEX_OF_DUALDISPLAY_SECOND_16_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_16_
+#define PADINDEX_OF_DUALDISPLAY_SECOND_17_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_17_
+#define PADINDEX_OF_DUALDISPLAY_SECOND_18_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_18_
+#define PADINDEX_OF_DUALDISPLAY_SECOND_19_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_19_
+#define PADINDEX_OF_DUALDISPLAY_SECOND_20_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_20_
+#define PADINDEX_OF_DUALDISPLAY_SECOND_21_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_21_
+#define PADINDEX_OF_DUALDISPLAY_SECOND_22_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_22_
+#define PADINDEX_OF_DUALDISPLAY_SECOND_23_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_23_
+
+#define NUMBER_OF_RESCONV_MODULE 1
+#define INTNUM_OF_RESCONV_MODULE INTNUM_OF_DISPLAYTOP_MODULE_RESCONV_IRQ
+#define RESETINDEX_OF_RESCONV_MODULE_I_NRST \
+ RESETINDEX_OF_DISPLAYTOP_MODULE_I_RESCONV_NRST
+#define RESETINDEX_OF_RESCONV_MODULE RESETINDEX_OF_RESCONV_MODULE_I_NRST
+#define NUMBER_OF_LCDINTERFACE_MODULE 1
+#define RESETINDEX_OF_LCDINTERFACE_MODULE_I_NRST \
+ RESETINDEX_OF_DISPLAYTOP_MODULE_I_LCDIF_NRST
+#define PADINDEX_OF_LCDINTERFACE_O_VCLK \
+ PADINDEX_OF_DISPLAYTOP_O_DUAL_DISPLAY_PADPRIMVCLK
+#define PADINDEX_OF_LCDINTERFACE_O_NHSYNC \
+ PADINDEX_OF_DISPLAYTOP_O_DUAL_DISPLAY_PRIM_PADN_HSYNC
+#define PADINDEX_OF_LCDINTERFACE_O_NVSYNC \
+ PADINDEX_OF_DISPLAYTOP_O_DUAL_DISPLAY_PRIM_PADN_VSYNC
+#define PADINDEX_OF_LCDINTERFACE_O_DE \
+ PADINDEX_OF_DISPLAYTOP_O_DUAL_DISPLAY_PRIM_PADDE
+#define PADINDEX_OF_LCDINTERFACE_RGB24_0_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_0_
+#define PADINDEX_OF_LCDINTERFACE_RGB24_1_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_1_
+#define PADINDEX_OF_LCDINTERFACE_RGB24_2_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_2_
+#define PADINDEX_OF_LCDINTERFACE_RGB24_3_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_3_
+#define PADINDEX_OF_LCDINTERFACE_RGB24_4_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_4_
+#define PADINDEX_OF_LCDINTERFACE_RGB24_5_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_5_
+#define PADINDEX_OF_LCDINTERFACE_RGB24_6_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_6_
+#define PADINDEX_OF_LCDINTERFACE_RGB24_7_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_7_
+#define PADINDEX_OF_LCDINTERFACE_RGB24_8_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_8_
+#define PADINDEX_OF_LCDINTERFACE_RGB24_9_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_9_
+#define PADINDEX_OF_LCDINTERFACE_RGB24_10_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_10_
+#define PADINDEX_OF_LCDINTERFACE_RGB24_11_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_11_
+#define PADINDEX_OF_LCDINTERFACE_RGB24_12_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_12_
+#define PADINDEX_OF_LCDINTERFACE_RGB24_13_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_13_
+#define PADINDEX_OF_LCDINTERFACE_RGB24_14_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_14_
+#define PADINDEX_OF_LCDINTERFACE_RGB24_15_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_15_
+#define PADINDEX_OF_LCDINTERFACE_RGB24_16_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_16_
+#define PADINDEX_OF_LCDINTERFACE_RGB24_17_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_17_
+#define PADINDEX_OF_LCDINTERFACE_RGB24_18_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_18_
+#define PADINDEX_OF_LCDINTERFACE_RGB24_19_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_19_
+#define PADINDEX_OF_LCDINTERFACE_RGB24_20_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_20_
+#define PADINDEX_OF_LCDINTERFACE_RGB24_21_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_21_
+#define PADINDEX_OF_LCDINTERFACE_RGB24_22_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_22_
+#define PADINDEX_OF_LCDINTERFACE_RGB24_23_ \
+ PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_23_
+
+#define NUMBER_OF_HDMI_MODULE 1
+#define INTNUM_OF_HDMI_MODULE INTNUM_OF_DISPLAYTOP_MODULE_HDMI_IRQ
+#define RESETINDEX_OF_HDMI_MODULE_I_NRST \
+ RESETINDEX_OF_DISPLAYTOP_MODULE_I_HDMI_NRST
+#define RESETINDEX_OF_HDMI_MODULE_I_NRST_VIDEO \
+ RESETINDEX_OF_DISPLAYTOP_MODULE_I_HDMI_VIDEO_NRST
+#define RESETINDEX_OF_HDMI_MODULE_I_NRST_SPDIF \
+ RESETINDEX_OF_DISPLAYTOP_MODULE_I_HDMI_SPDIF_NRST
+#define RESETINDEX_OF_HDMI_MODULE_I_NRST_TMDS \
+ RESETINDEX_OF_DISPLAYTOP_MODULE_I_HDMI_TMDS_NRST
+#define RESETINDEX_OF_HDMI_MODULE_I_NRST_PHY \
+ RESETINDEX_OF_DISPLAYTOP_MODULE_I_HDMI_PHY_NRST
+#define PADINDEX_OF_HDMI_I_PHY_CLKI PADINDEX_OF_DISPLAYTOP_I_HDMI_CLKI
+#define PADINDEX_OF_HDMI_O_PHY_CLKO PADINDEX_OF_DISPLAYTOP_O_HDMI_CLKO
+#define PADINDEX_OF_HDMI_IO_PHY_REXT PADINDEX_OF_DISPLAYTOP_IO_HDMI_REXT
+#define PADINDEX_OF_HDMI_O_PHY_TX0P PADINDEX_OF_DISPLAYTOP_O_HDMI_TX0P
+#define PADINDEX_OF_HDMI_O_PHY_TX0N PADINDEX_OF_DISPLAYTOP_O_HDMI_TX0N
+#define PADINDEX_OF_HDMI_O_PHY_TX1P PADINDEX_OF_DISPLAYTOP_O_HDMI_TX1P
+#define PADINDEX_OF_HDMI_O_PHY_TX1N PADINDEX_OF_DISPLAYTOP_O_HDMI_TX1N
+#define PADINDEX_OF_HDMI_O_PHY_TX2P PADINDEX_OF_DISPLAYTOP_O_HDMI_TX2P
+#define PADINDEX_OF_HDMI_O_PHY_TX2N PADINDEX_OF_DISPLAYTOP_O_HDMI_TX2N
+#define PADINDEX_OF_HDMI_O_PHY_TXCP PADINDEX_OF_DISPLAYTOP_O_HDMI_TXCP
+#define PADINDEX_OF_HDMI_O_PHY_TXCN PADINDEX_OF_DISPLAYTOP_O_HDMI_TXCN
+#define PADINDEX_OF_HDMI_I_HOTPLUG PADINDEX_OF_DISPLAYTOP_I_HDMI_HOTPLUG_5V
+#define PADINDEX_OF_HDMI_IO_PAD_CEC PADINDEX_OF_DISPLAYTOP_IO_HDMI_CEC
+#define NUMBER_OF_LVDS_MODULE 1
+
+#define RESETINDEX_OF_LVDS_MODULE_I_RESETN \
+ RESETINDEX_OF_DISPLAYTOP_MODULE_I_LVDS_NRST
+#define RESETINDEX_OF_LVDS_MODULE RESETINDEX_OF_LVDS_MODULE_I_RESETN
+
+#define PADINDEX_OF_LVDS_TAP PADINDEX_OF_DISPLAYTOP_LVDS_TXP_A
+#define PADINDEX_OF_LVDS_TAN PADINDEX_OF_DISPLAYTOP_LVDS_TXN_A
+#define PADINDEX_OF_LVDS_TBP PADINDEX_OF_DISPLAYTOP_LVDS_TXP_B
+#define PADINDEX_OF_LVDS_TBN PADINDEX_OF_DISPLAYTOP_LVDS_TXN_B
+#define PADINDEX_OF_LVDS_TCP PADINDEX_OF_DISPLAYTOP_LVDS_TXP_C
+#define PADINDEX_OF_LVDS_TCN PADINDEX_OF_DISPLAYTOP_LVDS_TXN_C
+#define PADINDEX_OF_LVDS_TDP PADINDEX_OF_DISPLAYTOP_LVDS_TXP_D
+#define PADINDEX_OF_LVDS_TDN PADINDEX_OF_DISPLAYTOP_LVDS_TXN_D
+#define PADINDEX_OF_LVDS_TCLKP PADINDEX_OF_DISPLAYTOP_LVDS_TXP_CLK
+#define PADINDEX_OF_LVDS_TCLKN PADINDEX_OF_DISPLAYTOP_LVDS_TXN_CLK
+#define PADINDEX_OF_LVDS_ROUT PADINDEX_OF_DISPLAYTOP_LVDS_ROUT
+#define PADINDEX_OF_LVDS_TEP PADINDEX_OF_DISPLAYTOP_LVDS_TXN_E
+#define PADINDEX_OF_LVDS_TEN PADINDEX_OF_DISPLAYTOP_LVDS_TXN_E
+#define NUMBER_OF_DISPTOP_CLKGEN_MODULE 5
+
+enum disptop_clkgen_module_index {
+ res_conv_clkgen = 0,
+ lcdif_clkgen = 1,
+ to_mipi_clkgen = 2,
+ to_lvds_clkgen = 3,
+ hdmi_clkgen = 4,
+};
+
+enum disptop_res_conv_iclk_cclk {
+ res_conv_iclk = 0,
+ res_conv_cclk = 1,
+};
+
+enum disptop_res_conv_oclk {
+ res_conv_oclk = 1,
+};
+
+enum disptop_lcdif_clk {
+ lcdif_pixel_clkx_n = 0,
+ lcdif_pixel_clk = 1,
+};
+
+#define HDMI_SPDIF_CLKGEN 2
+#define HDMI_SPDIF_CLKOUT 0
+#define HDMI_I_VCLK_CLKOUT 0
+#define PHY_BASEADDR_DISPTOP_CLKGEN0_MODULE \
+ (PHY_BASEADDR_DISPLAYTOP_MODULE + OTHER_ADDR_OFFSET + 0x006000)
+#define PHY_BASEADDR_DISPTOP_CLKGEN1_MODULE \
+ (PHY_BASEADDR_DISPLAYTOP_MODULE + OTHER_ADDR_OFFSET + 0x007000)
+#define PHY_BASEADDR_DISPTOP_CLKGEN2_MODULE \
+ (PHY_BASEADDR_DISPLAYTOP_MODULE + OTHER_ADDR_OFFSET + 0x005000)
+#define PHY_BASEADDR_DISPTOP_CLKGEN3_MODULE \
+ (PHY_BASEADDR_DISPLAYTOP_MODULE + OTHER_ADDR_OFFSET + 0x008000)
+#define PHY_BASEADDR_DISPTOP_CLKGEN4_MODULE \
+ (PHY_BASEADDR_DISPLAYTOP_MODULE + OTHER_ADDR_OFFSET + 0x009000)
+
+struct nx_disp_top_register_set {
+ u32 resconv_mux_ctrl;
+ u32 interconv_mux_ctrl;
+ u32 mipi_mux_ctrl;
+ u32 lvds_mux_ctrl;
+ u32 hdmifixctrl0;
+ u32 hdmisyncctrl0;
+ u32 hdmisyncctrl1;
+ u32 hdmisyncctrl2;
+ u32 hdmisyncctrl3;
+ u32 tftmpu_mux;
+ u32 hdmifieldctrl;
+ u32 greg0;
+ u32 greg1;
+ u32 greg2;
+ u32 greg3;
+ u32 greg4;
+ u32 greg5;
+};
+
+int nx_disp_top_initialize(void);
+u32 nx_disp_top_get_number_of_module(void);
+
+u32 nx_disp_top_get_physical_address(void);
+u32 nx_disp_top_get_size_of_register_set(void);
+void nx_disp_top_set_base_address(void *base_address);
+void *nx_disp_top_get_base_address(void);
+int nx_disp_top_open_module(void);
+int nx_disp_top_close_module(void);
+int nx_disp_top_check_busy(void);
+
+enum mux_index {
+ primary_mlc = 0,
+ secondary_mlc = 1,
+ resolution_conv = 2,
+};
+
+enum prim_pad_mux_index {
+ padmux_primary_mlc = 0,
+ padmux_primary_mpu = 1,
+ padmux_secondary_mlc = 2,
+ padmux_resolution_conv = 3,
+};
+
+void nx_disp_top_set_resconvmux(int benb, u32 sel);
+void nx_disp_top_set_hdmimux(int benb, u32 sel);
+void nx_disp_top_set_mipimux(int benb, u32 sel);
+void nx_disp_top_set_lvdsmux(int benb, u32 sel);
+void nx_disp_top_set_primary_mux(u32 sel);
+void nx_disp_top_hdmi_set_vsync_start(u32 sel);
+void nx_disp_top_hdmi_set_vsync_hsstart_end(u32 start, u32 end);
+void nx_disp_top_hdmi_set_hactive_start(u32 sel);
+void nx_disp_top_hdmi_set_hactive_end(u32 sel);
+
+void nx_disp_top_set_hdmifield(u32 enable, u32 init_val, u32 vsynctoggle,
+ u32 hsynctoggle, u32 vsyncclr, u32 hsyncclr,
+ u32 field_use, u32 muxsel);
+
+enum padclk_config {
+ padclk_clk = 0,
+ padclk_inv_clk = 1,
+ padclk_reserved_clk = 2,
+ padclk_reserved_inv_clk = 3,
+ padclk_clk_div2_0 = 4,
+ padclk_clk_div2_90 = 5,
+ padclk_clk_div2_180 = 6,
+ padclk_clk_div2_270 = 7,
+};
+
+void nx_disp_top_set_padclock(u32 mux_index, u32 padclk_cfg);
+void nx_disp_top_set_lcdif_enb(int enb);
+void nx_disp_top_set_hdmifield(u32 enable, u32 init_val, u32 vsynctoggle,
+ u32 hsynctoggle, u32 vsyncclr, u32 hsyncclr,
+ u32 field_use, u32 muxsel);
+
+#endif
diff --git a/drivers/video/nexell/soc/s5pxx18_soc_disptop_clk.c b/drivers/video/nexell/soc/s5pxx18_soc_disptop_clk.c
new file mode 100644
index 0000000..02361ba
--- /dev/null
+++ b/drivers/video/nexell/soc/s5pxx18_soc_disptop_clk.c
@@ -0,0 +1,309 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Nexell Co., Ltd.
+ *
+ * Author: junghyun, kim <jhkim@nexell.co.kr>
+ */
+
+#include <linux/types.h>
+#include <linux/io.h>
+
+#include "s5pxx18_soc_disptop_clk.h"
+#include "s5pxx18_soc_disptop.h"
+
+static struct {
+ struct nx_disptop_clkgen_register_set *__g_pregister;
+} __g_module_variables[NUMBER_OF_DISPTOP_CLKGEN_MODULE] = {
+ { NULL,},
+};
+
+int nx_disp_top_clkgen_initialize(void)
+{
+ static int binit;
+ u32 i;
+
+ if (binit == 0) {
+ for (i = 0; i < NUMBER_OF_DISPTOP_CLKGEN_MODULE; i++)
+ __g_module_variables[i].__g_pregister = NULL;
+ binit = 1;
+ }
+ return 1;
+}
+
+u32 nx_disp_top_clkgen_get_number_of_module(void)
+{
+ return NUMBER_OF_DISPTOP_CLKGEN_MODULE;
+}
+
+u32 nx_disp_top_clkgen_get_physical_address(u32 module_index)
+{
+ static const u32 physical_addr[] =
+ PHY_BASEADDR_DISPTOP_CLKGEN_LIST;
+
+ return (u32)physical_addr[module_index];
+}
+
+u32 nx_disp_top_clkgen_get_size_of_register_set(void)
+{
+ return sizeof(struct nx_disptop_clkgen_register_set);
+}
+
+void nx_disp_top_clkgen_set_base_address(u32 module_index, void *base_address)
+{
+ __g_module_variables[module_index].__g_pregister =
+ (struct nx_disptop_clkgen_register_set *)base_address;
+}
+
+void *nx_disp_top_clkgen_get_base_address(u32 module_index)
+{
+ return (void *)__g_module_variables[module_index].__g_pregister;
+}
+
+void nx_disp_top_clkgen_set_clock_bclk_mode(u32 module_index,
+ enum nx_bclkmode mode)
+{
+ register struct nx_disptop_clkgen_register_set *pregister;
+ register u32 regvalue;
+ u32 clkmode = 0;
+
+ pregister = __g_module_variables[module_index].__g_pregister;
+ switch (mode) {
+ case nx_bclkmode_disable:
+ clkmode = 0;
+ case nx_bclkmode_dynamic:
+ clkmode = 2;
+ break;
+ case nx_bclkmode_always:
+ clkmode = 3;
+ break;
+ default:
+ break;
+ }
+
+ regvalue = pregister->clkenb;
+ regvalue &= ~3ul;
+ regvalue |= (clkmode & 0x03);
+
+ writel(regvalue, &pregister->clkenb);
+}
+
+enum nx_bclkmode nx_disp_top_clkgen_get_clock_bclk_mode(u32 module_index)
+{
+ register struct nx_disptop_clkgen_register_set *pregister;
+ u32 mode = 0;
+
+ pregister = __g_module_variables[module_index].__g_pregister;
+ mode = (pregister->clkenb & 3ul);
+
+ switch (mode) {
+ case 0:
+ return nx_bclkmode_disable;
+ case 2:
+ return nx_bclkmode_dynamic;
+ case 3:
+ return nx_bclkmode_always;
+ default:
+ break;
+ }
+ return nx_bclkmode_disable;
+}
+
+void nx_disp_top_clkgen_set_clock_pclk_mode(u32 module_index,
+ enum nx_pclkmode mode)
+{
+ register struct nx_disptop_clkgen_register_set *pregister;
+ register u32 regvalue;
+ const u32 pclkmode_pos = 3;
+ u32 clkmode = 0;
+
+ pregister = __g_module_variables[module_index].__g_pregister;
+ switch (mode) {
+ case nx_pclkmode_dynamic:
+ clkmode = 0;
+ break;
+ case nx_pclkmode_always:
+ clkmode = 1;
+ break;
+ default:
+ break;
+ }
+
+ regvalue = pregister->clkenb;
+ regvalue &= ~(1ul << pclkmode_pos);
+ regvalue |= (clkmode & 0x01) << pclkmode_pos;
+
+ writel(regvalue, &pregister->clkenb);
+}
+
+enum nx_pclkmode nx_disp_top_clkgen_get_clock_pclk_mode(u32 module_index)
+{
+ register struct nx_disptop_clkgen_register_set *pregister;
+ const u32 pclkmode_pos = 3;
+
+ pregister = __g_module_variables[module_index].__g_pregister;
+
+ if (pregister->clkenb & (1ul << pclkmode_pos))
+ return nx_pclkmode_always;
+
+ return nx_pclkmode_dynamic;
+}
+
+void nx_disp_top_clkgen_set_clock_source(u32 module_index, u32 index,
+ u32 clk_src)
+{
+ register struct nx_disptop_clkgen_register_set *pregister;
+ register u32 read_value;
+
+ const u32 clksrcsel_pos = 2;
+ const u32 clksrcsel_mask = 0x07 << clksrcsel_pos;
+
+ pregister = __g_module_variables[module_index].__g_pregister;
+
+ read_value = pregister->CLKGEN[index << 1];
+ read_value &= ~clksrcsel_mask;
+ read_value |= clk_src << clksrcsel_pos;
+
+ writel(read_value, &pregister->CLKGEN[index << 1]);
+}
+
+u32 nx_disp_top_clkgen_get_clock_source(u32 module_index, u32 index)
+{
+ register struct nx_disptop_clkgen_register_set *pregister;
+ const u32 clksrcsel_pos = 2;
+ const u32 clksrcsel_mask = 0x07 << clksrcsel_pos;
+
+ pregister = __g_module_variables[module_index].__g_pregister;
+
+ return (pregister->CLKGEN[index << 1] &
+ clksrcsel_mask) >> clksrcsel_pos;
+}
+
+void nx_disp_top_clkgen_set_clock_divisor(u32 module_index, u32 index,
+ u32 divisor)
+{
+ register struct nx_disptop_clkgen_register_set *pregister;
+ const u32 clkdiv_pos = 5;
+ const u32 clkdiv_mask = 0xff << clkdiv_pos;
+ register u32 read_value;
+
+ pregister = __g_module_variables[module_index].__g_pregister;
+
+ read_value = pregister->CLKGEN[index << 1];
+ read_value &= ~clkdiv_mask;
+ read_value |= (divisor - 1) << clkdiv_pos;
+ writel(read_value, &pregister->CLKGEN[index << 1]);
+}
+
+u32 nx_disp_top_clkgen_get_clock_divisor(u32 module_index, u32 index)
+{
+ register struct nx_disptop_clkgen_register_set *pregister;
+ const u32 clkdiv_pos = 5;
+ const u32 clkdiv_mask = 0xff << clkdiv_pos;
+
+ pregister = __g_module_variables[module_index].__g_pregister;
+
+ return ((pregister->CLKGEN[index << 1] &
+ clkdiv_mask) >> clkdiv_pos) + 1;
+}
+
+void nx_disp_top_clkgen_set_clock_divisor_enable(u32 module_index, int enable)
+{
+ register struct nx_disptop_clkgen_register_set *pregister;
+ register u32 read_value;
+ const u32 clkgenenb_pos = 2;
+ const u32 clkgenenb_mask = 1ul << clkgenenb_pos;
+
+ pregister = __g_module_variables[module_index].__g_pregister;
+
+ read_value = pregister->clkenb;
+ read_value &= ~clkgenenb_mask;
+ read_value |= (u32)enable << clkgenenb_pos;
+
+ writel(read_value, &pregister->clkenb);
+}
+
+int nx_disp_top_clkgen_get_clock_divisor_enable(u32 module_index)
+{
+ register struct nx_disptop_clkgen_register_set *pregister;
+ const u32 clkgenenb_pos = 2;
+ const u32 clkgenenb_mask = 1ul << clkgenenb_pos;
+
+ pregister = __g_module_variables[module_index].__g_pregister;
+
+ return (int)((pregister->clkenb &
+ clkgenenb_mask) >> clkgenenb_pos);
+}
+
+void nx_disp_top_clkgen_set_clock_out_inv(u32 module_index, u32 index,
+ int out_clk_inv)
+{
+ register struct nx_disptop_clkgen_register_set *pregister;
+ register u32 read_value;
+ const u32 outclkinv_pos = 1;
+ const u32 outclkinv_mask = 1ul << outclkinv_pos;
+
+ pregister = __g_module_variables[module_index].__g_pregister;
+
+ read_value = pregister->CLKGEN[index << 1];
+ read_value &= ~outclkinv_mask;
+ read_value |= out_clk_inv << outclkinv_pos;
+
+ writel(read_value, &pregister->CLKGEN[index << 1]);
+}
+
+int nx_disp_top_clkgen_get_clock_out_inv(u32 module_index, u32 index)
+{
+ register struct nx_disptop_clkgen_register_set *pregister;
+ const u32 outclkinv_pos = 1;
+ const u32 outclkinv_mask = 1ul << outclkinv_pos;
+
+ pregister = __g_module_variables[module_index].__g_pregister;
+
+ return (int)((pregister->CLKGEN[index << 1] &
+ outclkinv_mask) >> outclkinv_pos);
+}
+
+int nx_disp_top_clkgen_set_input_inv(u32 module_index,
+ u32 index, int in_clk_inv)
+{
+ register struct nx_disptop_clkgen_register_set *pregister;
+ register u32 read_value;
+ const u32 inclkinv_pos = 4 + index;
+ const u32 inclkinv_mask = 1ul << inclkinv_pos;
+
+ pregister = __g_module_variables[module_index].__g_pregister;
+
+ read_value = pregister->clkenb;
+ read_value &= ~inclkinv_mask;
+ read_value |= in_clk_inv << inclkinv_pos;
+
+ writel(read_value, &pregister->clkenb);
+ return true;
+}
+
+int nx_disp_top_clkgen_get_input_inv(u32 module_index, u32 index)
+{
+ register struct nx_disptop_clkgen_register_set *pregister;
+ const u32 inclkinv_pos = 4 + index;
+ const u32 inclkinv_mask = 1ul << inclkinv_pos;
+
+ pregister = __g_module_variables[module_index].__g_pregister;
+
+ return (int)((pregister->clkenb &
+ inclkinv_mask) >> inclkinv_pos);
+}
+
+void nx_disp_top_clkgen_set_clock_out_select(u32 module_index, u32 index,
+ int bbypass)
+{
+ register struct nx_disptop_clkgen_register_set *pregister;
+ register u32 read_value;
+
+ pregister = __g_module_variables[module_index].__g_pregister;
+
+ read_value = pregister->CLKGEN[index << 1];
+ read_value = read_value & (~0x01);
+ read_value = read_value | bbypass;
+
+ writel(read_value, &pregister->CLKGEN[index << 1]);
+}
diff --git a/drivers/video/nexell/soc/s5pxx18_soc_disptop_clk.h b/drivers/video/nexell/soc/s5pxx18_soc_disptop_clk.h
new file mode 100644
index 0000000..d55fef7
--- /dev/null
+++ b/drivers/video/nexell/soc/s5pxx18_soc_disptop_clk.h
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: GPL-2.0+
+ *
+ * Copyright (C) 2016 Nexell Co., Ltd.
+ *
+ * Author: junghyun, kim <jhkim@nexell.co.kr>
+ */
+
+#ifndef _S5PXX18_SOC_DISPTOP_CLK_H_
+#define _S5PXX18_SOC_DISPTOP_CLK_H_
+
+#include "s5pxx18_soc_disptype.h"
+
+#define PHY_BASEADDR_DISPTOP_CLKGEN_LIST \
+ { PHY_BASEADDR_DISPTOP_CLKGEN0_MODULE, \
+ PHY_BASEADDR_DISPTOP_CLKGEN1_MODULE, \
+ PHY_BASEADDR_DISPTOP_CLKGEN2_MODULE, \
+ PHY_BASEADDR_DISPTOP_CLKGEN3_MODULE, \
+ PHY_BASEADDR_DISPTOP_CLKGEN4_MODULE, \
+ }
+
+struct nx_disptop_clkgen_register_set {
+ u32 clkenb;
+ u32 CLKGEN[4];
+};
+
+int nx_disp_top_clkgen_initialize(void);
+u32 nx_disp_top_clkgen_get_number_of_module(void);
+u32 nx_disp_top_clkgen_get_physical_address(u32 module_index);
+u32 nx_disp_top_clkgen_get_size_of_register_set(void);
+void nx_disp_top_clkgen_set_base_address(u32 module_index,
+ void *base_address);
+void *nx_disp_top_clkgen_get_base_address(u32 module_index);
+void nx_disp_top_clkgen_set_clock_pclk_mode(u32 module_index,
+ enum nx_pclkmode mode);
+enum nx_pclkmode nx_disp_top_clkgen_get_clock_pclk_mode(u32 module_index);
+void nx_disp_top_clkgen_set_clock_source(u32 module_index, u32 index,
+ u32 clk_src);
+u32 nx_disp_top_clkgen_get_clock_source(u32 module_index, u32 index);
+void nx_disp_top_clkgen_set_clock_divisor(u32 module_index, u32 index,
+ u32 divisor);
+u32 nx_disp_top_clkgen_get_clock_divisor(u32 module_index, u32 index);
+void nx_disp_top_clkgen_set_clock_divisor_enable(u32 module_index,
+ int enable);
+int nx_disp_top_clkgen_get_clock_divisor_enable(u32 module_index);
+void nx_disp_top_clkgen_set_clock_bclk_mode(u32 module_index,
+ enum nx_bclkmode mode);
+enum nx_bclkmode nx_disp_top_clkgen_get_clock_bclk_mode(u32 module_index);
+
+void nx_disp_top_clkgen_set_clock_out_inv(u32 module_index, u32 index,
+ int out_clk_inv);
+int nx_disp_top_clkgen_get_clock_out_inv(u32 module_index, u32 index);
+int nx_disp_top_clkgen_set_input_inv(u32 module_index, u32 index,
+ int out_clk_inv);
+int nx_disp_top_clkgen_get_input_inv(u32 module_index, u32 index);
+
+void nx_disp_top_clkgen_set_clock_out_select(u32 module_index, u32 index,
+ int bbypass);
+
+#endif
diff --git a/drivers/video/nexell/soc/s5pxx18_soc_disptype.h b/drivers/video/nexell/soc/s5pxx18_soc_disptype.h
new file mode 100644
index 0000000..b5df7a7
--- /dev/null
+++ b/drivers/video/nexell/soc/s5pxx18_soc_disptype.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0+
+ *
+ * Copyright (C) 2016 Nexell Co., Ltd.
+ *
+ * Author: junghyun, kim <jhkim@nexell.co.kr>
+ */
+
+#ifndef _S5PXX18_SOC_DISP_TYPE_H_
+#define _S5PXX18_SOC_DISP_TYPE_H_
+
+/* clock control types */
+enum nx_pclkmode {
+ nx_pclkmode_dynamic = 0UL,
+ nx_pclkmode_always = 1UL
+};
+
+enum nx_bclkmode {
+ nx_bclkmode_disable = 0UL,
+ nx_bclkmode_dynamic = 2UL,
+ nx_bclkmode_always = 3UL
+};
+
+#endif
--
1.9.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH 05/10] video: add nexell video driver (soc: mlc, mipi)
2020-02-03 19:39 [RFC PATCH 00/10] arm: add support for SoC S5P4418 Stefan Bosch
` (3 preceding siblings ...)
2020-02-03 20:41 ` [RFC PATCH 04/10] video: add nexell video driver (soc: displaytop) Stefan Bosch
@ 2020-02-03 20:43 ` Stefan Bosch
2020-02-03 20:44 ` [RFC PATCH 06/10] video: add nexell video driver (soc: lvds, hdmi) Stefan Bosch
` (6 subsequent siblings)
11 siblings, 0 replies; 19+ messages in thread
From: Stefan Bosch @ 2020-02-03 20:43 UTC (permalink / raw)
To: u-boot
Low level functions for MLC (Multi Layer Control) and MIPI (Mobile
Industry Processor Interface).
Signed-off-by: Stefan Bosch <stefan_b@posteo.net>
---
drivers/video/nexell/soc/s5pxx18_soc_mipi.c | 580 +++++++++
drivers/video/nexell/soc/s5pxx18_soc_mipi.h | 291 +++++
drivers/video/nexell/soc/s5pxx18_soc_mlc.c | 1861 +++++++++++++++++++++++++++
drivers/video/nexell/soc/s5pxx18_soc_mlc.h | 429 ++++++
4 files changed, 3161 insertions(+)
create mode 100644 drivers/video/nexell/soc/s5pxx18_soc_mipi.c
create mode 100644 drivers/video/nexell/soc/s5pxx18_soc_mipi.h
create mode 100644 drivers/video/nexell/soc/s5pxx18_soc_mlc.c
create mode 100644 drivers/video/nexell/soc/s5pxx18_soc_mlc.h
diff --git a/drivers/video/nexell/soc/s5pxx18_soc_mipi.c b/drivers/video/nexell/soc/s5pxx18_soc_mipi.c
new file mode 100644
index 0000000..1000ddb
--- /dev/null
+++ b/drivers/video/nexell/soc/s5pxx18_soc_mipi.c
@@ -0,0 +1,580 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Nexell Co., Ltd.
+ *
+ * Author: junghyun, kim <jhkim@nexell.co.kr>
+ */
+
+#include <linux/types.h>
+#include <linux/io.h>
+
+#include "s5pxx18_soc_disptop.h"
+#include "s5pxx18_soc_mipi.h"
+
+static struct nx_mipi_register_set *__g_pregister[NUMBER_OF_MIPI_MODULE];
+
+int nx_mipi_smoke_test(u32 module_index)
+{
+ register struct nx_mipi_register_set *pregister;
+
+ pregister = __g_pregister[module_index];
+
+ if (pregister->csis_config_ch0 != 0x000000FC)
+ return false;
+
+ if (pregister->dsim_intmsk != 0xB337FFFF)
+ return false;
+
+ writel(0xDEADC0DE, &pregister->csis_dphyctrl);
+ writel(0xFFFFFFFF, &pregister->csis_ctrl2);
+ writel(0xDEADC0DE, &pregister->dsim_msync);
+
+ if (pregister->csis_dphyctrl != 0xDE80001E)
+ return false;
+
+ if ((pregister->csis_ctrl2 & (~1)) != 0xEEE00010)
+ return false;
+
+ if (pregister->dsim_msync != 0xDE80C0DE)
+ return false;
+
+ return true;
+}
+
+void nx_mipi_set_base_address(u32 module_index, void *base_address)
+{
+ __g_pregister[module_index] =
+ (struct nx_mipi_register_set *)base_address;
+}
+
+void *nx_mipi_get_base_address(u32 module_index)
+{
+ return (void *)__g_pregister[module_index];
+}
+
+u32 nx_mipi_get_physical_address(u32 module_index)
+{
+ const u32 physical_addr[] = PHY_BASEADDR_MIPI_LIST;
+
+ return physical_addr[module_index];
+}
+
+#define __nx_mipi_valid_dsi_intmask__ \
+ (~((1 << 26) | (1 << 23) | (1 << 22) | (1 << 19)))
+
+void nx_mipi_set_interrupt_enable(u32 module_index, u32 int_num, int enable)
+{
+ register struct nx_mipi_register_set *pregister;
+ register u32 regvalue;
+
+ pregister = __g_pregister[module_index];
+ if (int_num < 32) {
+ regvalue = pregister->csis_intmsk;
+ regvalue &= ~(1ul << int_num);
+ regvalue |= (u32)enable << int_num;
+ writel(regvalue, &pregister->csis_intmsk);
+ } else {
+ regvalue = pregister->dsim_intmsk;
+ regvalue &= ~(1ul << (int_num - 32));
+ regvalue |= (u32)enable << (int_num - 32);
+ writel(regvalue, &pregister->dsim_intmsk);
+ }
+}
+
+int nx_mipi_get_interrupt_enable(u32 module_index, u32 int_num)
+{
+ if (int_num < 32)
+ return (int)((__g_pregister[module_index]->csis_intmsk >>
+ int_num) & 0x01);
+ else
+ return (int)((__g_pregister[module_index]->dsim_intmsk >>
+ (int_num - 32)) & 0x01);
+}
+
+int nx_mipi_get_interrupt_pending(u32 module_index, u32 int_num)
+{
+ register struct nx_mipi_register_set *pregister;
+ register u32 regvalue;
+ int ret;
+
+ pregister = __g_pregister[module_index];
+ if (int_num < 32) {
+ regvalue = pregister->csis_intmsk;
+ regvalue &= pregister->csis_intsrc;
+ ret = (int)((regvalue >> int_num) & 0x01);
+ } else {
+ regvalue = pregister->dsim_intmsk;
+ regvalue &= pregister->dsim_intsrc;
+ ret = (int)((regvalue >> (int_num - 32)) & 0x01);
+ }
+
+ return ret;
+}
+
+void nx_mipi_clear_interrupt_pending(u32 module_index, u32 int_num)
+{
+ register struct nx_mipi_register_set *pregister;
+
+ pregister = __g_pregister[module_index];
+ if (int_num < 32)
+ writel(1ul << int_num, &pregister->csis_intsrc);
+ else
+ writel(1ul << (int_num - 32), &pregister->dsim_intsrc);
+}
+
+void nx_mipi_set_interrupt_enable_all(u32 module_index, int enable)
+{
+ register struct nx_mipi_register_set *pregister;
+
+ pregister = __g_pregister[module_index];
+ if (enable)
+ writel(__nx_mipi_valid_dsi_intmask__, &pregister->dsim_intmsk);
+ else
+ writel(0, &pregister->dsim_intmsk);
+}
+
+int nx_mipi_get_interrupt_enable_all(u32 module_index)
+{
+ if (__g_pregister[module_index]->csis_intmsk)
+ return true;
+
+ if (__g_pregister[module_index]->dsim_intmsk)
+ return true;
+
+ return false;
+}
+
+int nx_mipi_get_interrupt_pending_all(u32 module_index)
+{
+ register struct nx_mipi_register_set *pregister;
+ register u32 regvalue;
+
+ pregister = __g_pregister[module_index];
+ regvalue = pregister->csis_intmsk;
+ regvalue &= pregister->csis_intsrc;
+
+ if (regvalue)
+ return true;
+
+ regvalue = pregister->dsim_intmsk;
+ regvalue &= pregister->dsim_intsrc;
+
+ if (regvalue)
+ return true;
+
+ return false;
+}
+
+void nx_mipi_clear_interrupt_pending_all(u32 module_index)
+{
+ register struct nx_mipi_register_set *pregister;
+
+ pregister = __g_pregister[module_index];
+ writel(__nx_mipi_valid_dsi_intmask__, &pregister->dsim_intsrc);
+}
+
+int32_t nx_mipi_get_interrupt_pending_number(u32 module_index)
+{
+ register struct nx_mipi_register_set *pregister;
+ register u32 regvalue;
+ int i;
+
+ pregister = __g_pregister[module_index];
+ regvalue = pregister->csis_intmsk;
+ regvalue &= pregister->csis_intsrc;
+ if (regvalue != 0) {
+ for (i = 0; i < 32; i++) {
+ if (regvalue & 1ul)
+ return i;
+ regvalue >>= 1;
+ }
+ }
+
+ regvalue = pregister->dsim_intmsk;
+ regvalue &= pregister->dsim_intsrc;
+ if (regvalue != 0) {
+ for (i = 0; i < 32; i++) {
+ if (regvalue & 1ul)
+ return i + 32;
+ regvalue >>= 1;
+ }
+ }
+ return -1;
+}
+
+#define writereg(regname, mask, value) \
+ regvalue = pregister->(regname); \
+ regvalue = (regvalue & (~(mask))) | (value); \
+ writel(regvalue, &pregister->(regname))
+
+void nx_mipi_dsi_get_status(u32 module_index, u32 *pulps, u32 *pstop,
+ u32 *pispllstable, u32 *pisinreset,
+ u32 *pisbackward, u32 *pishsclockready)
+{
+ register struct nx_mipi_register_set *pregister;
+ register u32 regvalue;
+
+ pregister = __g_pregister[module_index];
+ regvalue = pregister->dsim_status;
+ if (pulps) {
+ *pulps = 0;
+ if (regvalue & (1 << 4))
+ *pulps |= (1 << 0);
+ if (regvalue & (1 << 5))
+ *pulps |= (1 << 1);
+ if (regvalue & (1 << 6))
+ *pulps |= (1 << 2);
+ if (regvalue & (1 << 7))
+ *pulps |= (1 << 3);
+ if (regvalue & (1 << 9))
+ *pulps |= (1 << 4);
+ }
+
+ if (pstop) {
+ *pstop = 0;
+ if (regvalue & (1 << 0))
+ *pstop |= (1 << 0);
+ if (regvalue & (1 << 1))
+ *pstop |= (1 << 1);
+ if (regvalue & (1 << 2))
+ *pstop |= (1 << 2);
+ if (regvalue & (1 << 3))
+ *pstop |= (1 << 3);
+ if (regvalue & (1 << 8))
+ *pstop |= (1 << 4);
+ }
+
+ if (pispllstable)
+ *pispllstable = (regvalue >> 31) & 1;
+
+ if (pisinreset)
+ *pisinreset = ((regvalue >> 20) & 1) ? 0 : 1;
+
+ if (pisbackward)
+ *pisbackward = (regvalue >> 16) & 1;
+
+ if (pishsclockready)
+ *pishsclockready = (regvalue >> 10) & 1;
+}
+
+void nx_mipi_dsi_software_reset(u32 module_index)
+{
+ register struct nx_mipi_register_set *pregister;
+
+ pregister = __g_pregister[module_index];
+
+ writel(0x00010001, &pregister->dsim_swrst);
+
+ while (0 != (readl(&pregister->dsim_status) & (1 << 20)))
+ ;
+
+ writel(0x00000000, &pregister->dsim_swrst);
+}
+
+void nx_mipi_dsi_set_clock(u32 module_index, int enable_txhsclock,
+ int use_external_clock, int enable_byte_clock,
+ int enable_escclock_clock_lane,
+ int enable_escclock_data_lane0,
+ int enable_escclock_data_lane1,
+ int enable_escclock_data_lane2,
+ int enable_escclock_data_lane3,
+ int enable_escprescaler, u32 escprescalervalue)
+{
+ register struct nx_mipi_register_set *pregister;
+ register u32 regvalue;
+
+ pregister = __g_pregister[module_index];
+ regvalue = 0;
+ regvalue |= (enable_txhsclock << 31);
+ regvalue |= (use_external_clock << 27);
+ regvalue |= (enable_byte_clock << 24);
+ regvalue |= (enable_escclock_clock_lane << 19);
+ regvalue |= (enable_escclock_data_lane0 << 20);
+ regvalue |= (enable_escclock_data_lane1 << 21);
+ regvalue |= (enable_escclock_data_lane2 << 22);
+ regvalue |= (enable_escclock_data_lane3 << 23);
+ regvalue |= (enable_escprescaler << 28);
+ regvalue |= escprescalervalue;
+
+ writel(regvalue, &pregister->dsim_clkctrl);
+}
+
+void nx_mipi_dsi_set_timeout(u32 module_index, u32 bta_tout, u32 lpdrtout)
+{
+ register struct nx_mipi_register_set *pregister;
+ register u32 regvalue;
+
+ pregister = __g_pregister[module_index];
+ regvalue = 0;
+ regvalue |= (bta_tout << 16);
+ regvalue |= (lpdrtout << 0);
+
+ writel(regvalue, &pregister->dsim_timeout);
+}
+
+void nx_mipi_dsi_set_config_video_mode(u32 module_index,
+ int enable_auto_flush_main_display_fifo,
+ int enable_auto_vertical_count,
+ int enable_burst,
+ enum nx_mipi_dsi_syncmode sync_mode,
+ int enable_eo_tpacket,
+ int enable_hsync_end_packet,
+ int enable_hfp, int enable_hbp,
+ int enable_hsa,
+ u32 number_of_virtual_channel,
+ enum nx_mipi_dsi_format format,
+ u32 number_of_words_in_hfp,
+ u32 number_of_words_in_hbp,
+ u32 number_of_words_in_hsync,
+ u32 number_of_lines_in_vfp,
+ u32 number_of_lines_in_vbp,
+ u32 number_of_lines_in_vsync,
+ u32 number_of_lines_in_command_allow)
+{
+ register struct nx_mipi_register_set *pregister;
+ register u32 regvalue;
+ u32 newvalue;
+
+ pregister = __g_pregister[module_index];
+ newvalue = (1 << 25);
+ newvalue |= ((1 - enable_auto_flush_main_display_fifo) << 29);
+ newvalue |= (enable_auto_vertical_count << 24);
+ newvalue |= (enable_burst << 26);
+ newvalue |= (sync_mode << 27);
+ newvalue |= ((1 - enable_eo_tpacket) << 28);
+ newvalue |= (enable_hsync_end_packet << 23);
+ newvalue |= ((1 - enable_hfp) << 22);
+ newvalue |= ((1 - enable_hbp) << 21);
+ newvalue |= ((1 - enable_hsa) << 20);
+ newvalue |= (number_of_virtual_channel << 18);
+ newvalue |= (format << 12);
+
+ writereg(dsim_config, 0xFFFFFF00, newvalue);
+
+ newvalue = (number_of_lines_in_command_allow << 28);
+ newvalue |= (number_of_lines_in_vfp << 16);
+ newvalue |= (number_of_lines_in_vbp << 0);
+
+ writel(newvalue, &pregister->dsim_mvporch);
+
+ newvalue = (number_of_words_in_hfp << 16);
+ newvalue |= (number_of_words_in_hbp << 0);
+
+ writel(newvalue, &pregister->dsim_mhporch);
+
+ newvalue = (number_of_words_in_hsync << 0);
+ newvalue |= (number_of_lines_in_vsync << 22);
+
+ writel(newvalue, &pregister->dsim_msync);
+}
+
+void nx_mipi_dsi_set_config_command_mode(u32 module_index,
+ int
+ enable_auto_flush_main_display_fifo,
+ int enable_eo_tpacket,
+ u32 number_of_virtual_channel,
+ enum nx_mipi_dsi_format format)
+{
+ register struct nx_mipi_register_set *pregister;
+ register u32 regvalue;
+ u32 newvalue;
+
+ pregister = __g_pregister[module_index];
+ newvalue = (0 << 25);
+ newvalue |= (enable_auto_flush_main_display_fifo << 29);
+ newvalue |= (enable_eo_tpacket << 28);
+ newvalue |= (number_of_virtual_channel << 18);
+ newvalue |= (format << 12);
+ writereg(dsim_config, 0xFFFFFF00, newvalue);
+}
+
+void nx_mipi_dsi_set_escape_mode(u32 module_index, u32 stop_state_count,
+ int force_stop_state, int force_bta,
+ enum nx_mipi_dsi_lpmode cmdin_lp,
+ enum nx_mipi_dsi_lpmode txinlp)
+{
+ register struct nx_mipi_register_set *pregister;
+ register u32 regvalue;
+ u32 newvalue;
+
+ pregister = __g_pregister[module_index];
+ newvalue = (stop_state_count << 21);
+ newvalue |= (force_stop_state << 20);
+ newvalue |= (force_bta << 16);
+ newvalue |= (cmdin_lp << 7);
+ newvalue |= (txinlp << 6);
+ writereg(dsim_escmode, 0xFFFFFFC0, newvalue);
+}
+
+void nx_mipi_dsi_set_escape_lp(u32 module_index,
+ enum nx_mipi_dsi_lpmode cmdin_lp,
+ enum nx_mipi_dsi_lpmode txinlp)
+{
+ register struct nx_mipi_register_set *pregister;
+ register u32 regvalue;
+ u32 newvalue = 0;
+
+ pregister = __g_pregister[module_index];
+ newvalue |= (cmdin_lp << 7);
+ newvalue |= (txinlp << 6);
+ writereg(dsim_escmode, 0xC0, newvalue);
+}
+
+void nx_mipi_dsi_remote_reset_trigger(u32 module_index)
+{
+ register struct nx_mipi_register_set *pregister;
+ register u32 regvalue;
+ u32 newvalue;
+
+ pregister = __g_pregister[module_index];
+ newvalue = (1 << 4);
+ writereg(dsim_escmode, (1 << 4), newvalue);
+
+ while (readl(&pregister->dsim_escmode) & (1 << 4))
+ ;
+}
+
+void nx_mipi_dsi_set_ulps(u32 module_index, int ulpsclocklane, int ulpsdatalane)
+{
+ register struct nx_mipi_register_set *pregister;
+ register u32 regvalue;
+
+ pregister = __g_pregister[module_index];
+ regvalue = pregister->dsim_escmode;
+
+ if (ulpsclocklane) {
+ regvalue &= ~(1 << 0);
+ regvalue |= (1 << 1);
+ } else {
+ regvalue |= (1 << 0);
+ }
+
+ if (ulpsdatalane) {
+ regvalue &= ~(1 << 2);
+ regvalue |= (1 << 3);
+ } else {
+ regvalue |= (1 << 2);
+ }
+
+ writel(regvalue, &pregister->dsim_escmode);
+
+ if (ulpsclocklane)
+ while ((1 << 9) ==
+ (readl(&pregister->dsim_status) & (1 << 9)))
+ ;
+ else
+ while (0 != (readl(&pregister->dsim_status) & (1 << 9)))
+ ;
+
+ if (ulpsdatalane)
+ while ((15 << 4) ==
+ (readl(&pregister->dsim_status) & (15 << 4)))
+ ;
+ else
+ while (0 != (readl(&pregister->dsim_status) & (15 << 4)))
+ ;
+
+ if (!ulpsclocklane)
+ regvalue &= (3 << 0);
+
+ if (!ulpsdatalane)
+ regvalue |= (3 << 2);
+
+ writel(regvalue, &pregister->dsim_escmode);
+}
+
+void nx_mipi_dsi_set_size(u32 module_index, u32 width, u32 height)
+{
+ register struct nx_mipi_register_set *pregister;
+ register u32 regvalue;
+ u32 newvalue;
+
+ pregister = __g_pregister[module_index];
+ newvalue = (height << 16);
+ newvalue |= (width << 0);
+ writereg(dsim_mdresol, 0x0FFFFFFF, newvalue);
+}
+
+void nx_mipi_dsi_set_enable(u32 module_index, int enable)
+{
+ register struct nx_mipi_register_set *pregister;
+ register u32 regvalue;
+
+ pregister = __g_pregister[module_index];
+ writereg(dsim_mdresol, (1 << 31), (enable << 31));
+}
+
+void nx_mipi_dsi_set_phy(u32 module_index, u32 number_of_data_lanes,
+ int enable_clock_lane, int enable_data_lane0,
+ int enable_data_lane1, int enable_data_lane2,
+ int enable_data_lane3, int swap_clock_lane,
+ int swap_data_lane)
+{
+ register struct nx_mipi_register_set *pregister;
+ register u32 regvalue;
+ u32 newvalue;
+
+ pregister = __g_pregister[module_index];
+ newvalue = (number_of_data_lanes << 5);
+ newvalue |= (enable_clock_lane << 0);
+ newvalue |= (enable_data_lane0 << 1);
+ newvalue |= (enable_data_lane1 << 2);
+ newvalue |= (enable_data_lane2 << 3);
+ newvalue |= (enable_data_lane3 << 4);
+ writereg(dsim_config, 0xFF, newvalue);
+ newvalue = (swap_clock_lane << 1);
+ newvalue |= (swap_data_lane << 0);
+ writereg(dsim_phyacchr1, 0x3, newvalue);
+}
+
+void nx_mipi_dsi_set_pll(u32 module_index, int enable, u32 pllstabletimer,
+ u32 m_pllpms, u32 m_bandctl, u32 m_dphyctl,
+ u32 b_dphyctl)
+{
+ register struct nx_mipi_register_set *pregister;
+ register u32 regvalue;
+ u32 newvalue;
+
+ pregister = __g_pregister[module_index];
+ if (!enable) {
+ newvalue = (enable << 23);
+ newvalue |= (m_pllpms << 1);
+ newvalue |= (m_bandctl << 24);
+ writereg(dsim_pllctrl, 0x0FFFFFFF, newvalue);
+ }
+
+ writel(m_dphyctl, &pregister->dsim_phyacchr);
+ writel(pllstabletimer, &pregister->dsim_plltmr);
+ writel((b_dphyctl << 9), &pregister->dsim_phyacchr1);
+
+ if (enable) {
+ newvalue = (enable << 23);
+ newvalue |= (m_pllpms << 1);
+ newvalue |= (m_bandctl << 24);
+ writereg(dsim_pllctrl, 0x0FFFFFFF, newvalue);
+ }
+}
+
+void nx_mipi_dsi_write_pkheader(u32 module_index, u32 data)
+{
+ register struct nx_mipi_register_set *pregister;
+
+ pregister = __g_pregister[module_index];
+ writel(data, &pregister->dsim_pkthdr);
+}
+
+void nx_mipi_dsi_write_payload(u32 module_index, u32 data)
+{
+ register struct nx_mipi_register_set *pregister;
+
+ pregister = __g_pregister[module_index];
+ writel(data, &pregister->dsim_payload);
+}
+
+u32 nx_mipi_dsi_read_fifo_status(u32 module_index)
+{
+ register struct nx_mipi_register_set *pregister;
+
+ pregister = __g_pregister[module_index];
+ return readl(&pregister->dsim_fifoctrl);
+}
diff --git a/drivers/video/nexell/soc/s5pxx18_soc_mipi.h b/drivers/video/nexell/soc/s5pxx18_soc_mipi.h
new file mode 100644
index 0000000..63751ca
--- /dev/null
+++ b/drivers/video/nexell/soc/s5pxx18_soc_mipi.h
@@ -0,0 +1,291 @@
+/* SPDX-License-Identifier: GPL-2.0+
+ *
+ * Copyright (C) 2016 Nexell Co., Ltd.
+ *
+ * Author: junghyun, kim <jhkim@nexell.co.kr>
+ */
+
+#ifndef _S5PXX18_SOC_MIPI_H_
+#define _S5PXX18_SOC_MIPI_H_
+
+#define NUMBER_OF_MIPI_MODULE 1
+#define PHY_BASEADDR_MIPI_MODULE 0xC00D0000
+#define PHY_BASEADDR_MIPI_LIST \
+ { PHY_BASEADDR_MIPI_MODULE }
+
+#define nx_mipi_numberof_csi_channels 2
+
+struct nx_mipi_register_set {
+ u32 csis_control;
+ u32 csis_dphyctrl;
+ u32 csis_config_ch0;
+ u32 csis_dphysts;
+ u32 csis_intmsk;
+ u32 csis_intsrc;
+ u32 csis_ctrl2;
+ u32 csis_version;
+ u32 csis_dphyctrl_0;
+ u32 csis_dphyctrl_1;
+ u32 __reserved0;
+ u32 csis_resol_ch0;
+ u32 __reserved1;
+ u32 __reserved2;
+ u32 sdw_config_ch0;
+ u32 sdw_resol_ch0;
+ u32 csis_config_ch1;
+ u32 csis_resol_ch1;
+ u32 sdw_config_ch1;
+ u32 sdw_resol_ch1;
+ u32 csis_config_ch2;
+ u32 csis_resol_ch2;
+ u32 sdw_config_ch2;
+ u32 sdw_resol_ch2;
+ u32 csis_config_ch3;
+ u32 csis_resol_ch3;
+ u32 sdw_config_ch3;
+ u32 sdw_resol_3;
+ u32 __reserved3[(16 + 128) / 4];
+
+ u32 dsim_status;
+ u32 dsim_swrst;
+ u32 dsim_clkctrl;
+ u32 dsim_timeout;
+ u32 dsim_config;
+ u32 dsim_escmode;
+ u32 dsim_mdresol;
+ u32 dsim_mvporch;
+ u32 dsim_mhporch;
+ u32 dsim_msync;
+ u32 dsim_sdresol;
+ u32 dsim_intsrc;
+ u32 dsim_intmsk;
+ u32 dsim_pkthdr;
+ u32 dsim_payload;
+ u32 dsim_rxfifo;
+ u32 dsim_fifothld;
+ u32 dsim_fifoctrl;
+ u32 dsim_memacchr;
+ u32 dsim_pllctrl;
+ u32 dsim_plltmr;
+ u32 dsim_phyacchr;
+ u32 dsim_phyacchr1;
+
+ u32 __reserved4[(0x2000 - 0x015C) / 4];
+ u32 mipi_csis_pktdata[0x2000 / 4];
+};
+
+enum nx_mipi_dsi_syncmode {
+ nx_mipi_dsi_syncmode_event = 0,
+ nx_mipi_dsi_syncmode_pulse = 1,
+};
+
+enum nx_mipi_dsi_format {
+ nx_mipi_dsi_format_command3 = 0,
+ nx_mipi_dsi_format_command8 = 1,
+ nx_mipi_dsi_format_command12 = 2,
+ nx_mipi_dsi_format_command16 = 3,
+ nx_mipi_dsi_format_rgb565 = 4,
+ nx_mipi_dsi_format_rgb666_packed = 5,
+ nx_mipi_dsi_format_rgb666 = 6,
+ nx_mipi_dsi_format_rgb888 = 7
+};
+
+enum nx_mipi_dsi_lpmode {
+ nx_mipi_dsi_lpmode_hs = 0,
+ nx_mipi_dsi_lpmode_lp = 1
+};
+
+enum nx_mipi_phy_b_dphyctl {
+ nx_mipi_phy_b_dphyctl_m_txclkesc_20_mhz = 0x1F4,
+ nx_mipi_phy_b_dphyctl_m_txclkesc_19_mhz = 0x1DB,
+ nx_mipi_phy_b_dphyctl_m_txclkesc_18_mhz = 0x1C2,
+ nx_mipi_phy_b_dphyctl_m_txclkesc_17_mhz = 0x1A9,
+ nx_mipi_phy_b_dphyctl_m_txclkesc_16_mhz = 0x190,
+ nx_mipi_phy_b_dphyctl_m_txclkesc_15_mhz = 0x177,
+ nx_mipi_phy_b_dphyctl_m_txclkesc_14_mhz = 0x15E,
+ nx_mipi_phy_b_dphyctl_m_txclkesc_13_mhz = 0x145,
+ nx_mipi_phy_b_dphyctl_m_txclkesc_12_mhz = 0x12C,
+ nx_mipi_phy_b_dphyctl_m_txclkesc_11_mhz = 0x113,
+ nx_mipi_phy_b_dphyctl_m_txclkesc_10_mhz = 0x0FA,
+ nx_mipi_phy_b_dphyctl_m_txclkesc_9_mhz = 0x0E1,
+ nx_mipi_phy_b_dphyctl_m_txclkesc_8_mhz = 0x0C8,
+ nx_mipi_phy_b_dphyctl_m_txclkesc_7_mhz = 0x0AF,
+ nx_mipi_phy_b_dphyctl_m_txclkesc_6_mhz = 0x096,
+ nx_mipi_phy_b_dphyctl_m_txclkesc_5_mhz = 0x07D,
+ nx_mipi_phy_b_dphyctl_m_txclkesc_4_mhz = 0x064,
+ nx_mipi_phy_b_dphyctl_m_txclkesc_3_mhz = 0x04B,
+ nx_mipi_phy_b_dphyctl_m_txclkesc_2_mhz = 0x032,
+ nx_mipi_phy_b_dphyctl_m_txclkesc_1_mhz = 0x019,
+ nx_mipi_phy_b_dphyctl_m_txclkesc_0_10_mhz = 0x003,
+ nx_mipi_phy_b_dphyctl_m_txclkesc_0_01_mhz = 0x000
+};
+
+enum {
+ nx_mipi_rst = 0,
+ nx_mipi_rst_dsi_i,
+ nx_mipi_rst_csi_i,
+ nx_mipi_rst_phy_s,
+ nx_mipi_rst_phy_m
+};
+
+enum nx_mipi_int {
+ nx_mipi_int_csi_even_before = 31,
+ nx_mipi_int_csi_even_after = 30,
+ nx_mipi_int_csi_odd_before = 29,
+ nx_mipi_int_csi_odd_after = 28,
+ nx_mipi_int_csi_frame_start_ch3 = 27,
+ nx_mipi_int_csi_frame_start_ch2 = 26,
+ nx_mipi_int_csi_frame_start_ch1 = 25,
+ nx_mipi_int_csi_frame_start_ch0 = 24,
+ nx_mipi_int_csi_frame_end_ch3 = 23,
+ nx_mipi_int_csi_frame_end_ch2 = 22,
+ nx_mipi_int_csi_frame_end_ch1 = 21,
+ nx_mipi_int_csi_frame_end_ch0 = 20,
+ nx_mipi_int_csi_err_sot_hs_ch3 = 19,
+ nx_mipi_int_csi_err_sot_hs_ch2 = 18,
+ nx_mipi_int_csi_err_sot_hs_ch1 = 17,
+ nx_mipi_int_csi_err_sot_hs_ch0 = 16,
+ nx_mipi_int_csi_err_lost_fs_ch3 = 15,
+ nx_mipi_int_csi_err_lost_fs_ch2 = 14,
+ nx_mipi_int_csi_err_lost_fs_ch1 = 13,
+ nx_mipi_int_csi_err_lost_fs_ch0 = 12,
+ nx_mipi_int_csi_err_lost_fe_ch3 = 11,
+ nx_mipi_int_csi_err_lost_fe_ch2 = 10,
+ nx_mipi_int_csi_err_lost_fe_ch1 = 9,
+ nx_mipi_int_csi_err_lost_fe_ch0 = 8,
+ nx_mipi_int_csi_err_over_ch3 = 7,
+ nx_mipi_int_csi_err_over_ch2 = 6,
+ nx_mipi_int_csi_err_over_ch1 = 5,
+ nx_mipi_int_csi_err_over_ch0 = 4,
+
+ nx_mipi_int_csi_err_ecc = 2,
+ nx_mipi_int_csi_err_crc = 1,
+ nx_mipi_int_csi_err_id = 0,
+ nx_mipi_int_dsi_pll_stable = 32 + 31,
+ nx_mipi_int_dsi_sw_rst_release = 32 + 30,
+ nx_mipi_int_dsi_sfrplfifoempty = 32 + 29,
+ nx_mipi_int_dsi_sfrphfifoempty = 32 + 28,
+ nx_mipi_int_dsi_sync_override = 32 + 27,
+
+ nx_mipi_int_dsi_bus_turn_over = 32 + 25,
+ nx_mipi_int_dsi_frame_done = 32 + 24,
+
+ nx_mipi_int_dsi_lpdr_tout = 32 + 21,
+ nx_mipi_int_dsi_ta_tout = 32 + 20,
+
+ nx_mipi_int_dsi_rx_dat_done = 32 + 18,
+ nx_mipi_int_dsi_rx_te = 32 + 17,
+ nx_mipi_int_dsi_rx_ack = 32 + 16,
+ nx_mipi_int_dsi_err_rx_ecc = 32 + 15,
+ nx_mipi_int_dsi_err_rx_crc = 32 + 14,
+ nx_mipi_int_dsi_err_esc3 = 32 + 13,
+ nx_mipi_int_dsi_err_esc2 = 32 + 12,
+ nx_mipi_int_dsi_err_esc1 = 32 + 11,
+ nx_mipi_int_dsi_err_esc0 = 32 + 10,
+ nx_mipi_int_dsi_err_sync3 = 32 + 9,
+ nx_mipi_int_dsi_err_sync2 = 32 + 8,
+ nx_mipi_int_dsi_err_sync1 = 32 + 7,
+ nx_mipi_int_dsi_err_sync0 = 32 + 6,
+ nx_mipi_int_dsi_err_control3 = 32 + 5,
+ nx_mipi_int_dsi_err_control2 = 32 + 4,
+ nx_mipi_int_dsi_err_control1 = 32 + 3,
+ nx_mipi_int_dsi_err_control0 = 32 + 2,
+ nx_mipi_int_dsi_err_content_lp0 = 32 + 1,
+ nx_mipi_int_dsi_err_content_lp1 = 32 + 0,
+};
+
+#define DSI_TX_FIFO_SIZE 2048
+#define DSI_RX_FIFO_SIZE 256
+#define DSI_RX_FIFO_EMPTY 0x30800002
+
+void nx_mipi_dsi_get_status(u32 module_index, u32 *pulps, u32 *pstop,
+ u32 *pispllstable, u32 *pisinreset,
+ u32 *pisbackward, u32 *pishsclockready);
+
+void nx_mipi_dsi_software_reset(u32 module_index);
+
+void nx_mipi_dsi_set_clock(u32 module_index, int enable_txhsclock,
+ int use_external_clock, int enable_byte_clock,
+ int enable_escclock_clock_lane,
+ int enable_escclock_data_lane0,
+ int enable_escclock_data_lane1,
+ int enable_escclock_data_lane2,
+ int enable_escclock_data_lane3,
+ int enable_escprescaler,
+ u32 escprescalervalue);
+
+void nx_mipi_dsi_set_timeout(u32 module_index, u32 bta_tout,
+ u32 lpdrtout);
+
+void nx_mipi_dsi_set_config_video_mode(u32 module_index,
+ int enable_auto_flush_main_display_fifo,
+ int enable_auto_vertical_count,
+ int enable_burst,
+ enum nx_mipi_dsi_syncmode
+ sync_mode, int enable_eo_tpacket,
+ int enable_hsync_end_packet,
+ int enable_hfp, int enable_hbp,
+ int enable_hsa,
+ u32 number_of_virtual_channel,
+ enum nx_mipi_dsi_format format,
+ u32 number_of_words_in_hfp,
+ u32 number_of_words_in_hbp,
+ u32 number_of_words_in_hsync,
+ u32 number_of_lines_in_vfp,
+ u32 number_of_lines_in_vbp,
+ u32 number_of_lines_in_vsync,
+ u32 number_of_lines_in_command_allow);
+
+void nx_mipi_dsi_set_config_command_mode(u32 module_index,
+ int enable_auto_flush_main_display_fifo,
+ int enable_eo_tpacket,
+ u32 number_of_virtual_channel,
+ enum nx_mipi_dsi_format format);
+
+void nx_mipi_dsi_set_escape_mode(u32 module_index, u32 stop_state_count,
+ int force_stop_state, int force_bta,
+ enum nx_mipi_dsi_lpmode cmdin_lp,
+ enum nx_mipi_dsi_lpmode txinlp);
+void nx_mipi_dsi_set_escape_lp(u32 module_index,
+ enum nx_mipi_dsi_lpmode cmdin_lp,
+ enum nx_mipi_dsi_lpmode txinlp);
+
+void nx_mipi_dsi_remote_reset_trigger(u32 module_index);
+void nx_mipi_dsi_set_ulps(u32 module_index, int ulpsclocklane,
+ int ulpsdatalane);
+void nx_mipi_dsi_set_size(u32 module_index, u32 width, u32 height);
+void nx_mipi_dsi_set_enable(u32 module_index, int enable);
+void nx_mipi_dsi_set_phy(u32 module_index, u32 number_of_data_lanes,
+ int enable_clock_lane, int enable_data_lane0,
+ int enable_data_lane1, int enable_data_lane2,
+ int enable_data_lane3, int swap_clock_lane,
+ int swap_data_lane);
+
+void nx_mipi_dsi_set_pll(u32 module_index, int enable,
+ u32 pllstabletimer, u32 m_pllpms, u32 m_bandctl,
+ u32 m_dphyctl, u32 b_dphyctl);
+
+void nx_mipi_dsi_write_pkheader(u32 module_index, u32 data);
+void nx_mipi_dsi_write_payload(u32 module_index, u32 data);
+u32 nx_mipi_dsi_read_fifo(u32 module_index);
+u32 nx_mipi_dsi_read_fifo_status(u32 module_index);
+
+int nx_mipi_smoke_test(u32 module_index);
+void nx_mipi_set_base_address(u32 module_index, void *base_address);
+void *nx_mipi_get_base_address(u32 module_index);
+u32 nx_mipi_get_physical_address(u32 module_index);
+
+void nx_mipi_dsi_set_interrupt_enable_all(u32 module_index, int enable);
+void nx_mipi_dsi_set_interrupt_enable(u32 module_index,
+ u32 int_num, int enable);
+int nx_mipi_dsi_get_interrupt_enable(u32 module_index, u32 int_num);
+int nx_mipi_dsi_get_interrupt_enable_all(u32 module_index);
+
+int nx_mipi_dsi_get_interrupt_pending(u32 module_index, u32 int_num);
+int nx_mipi_dsi_get_interrupt_pending_all(u32 module_index);
+int32_t nx_mipi_dsi_get_interrupt_pending_number(u32 module_index);
+
+void nx_mipi_dsi_clear_interrupt_pending(u32 module_index, u32 int_num);
+void nx_mipi_dsi_clear_interrupt_pending_all(u32 module_index);
+
+#endif
diff --git a/drivers/video/nexell/soc/s5pxx18_soc_mlc.c b/drivers/video/nexell/soc/s5pxx18_soc_mlc.c
new file mode 100644
index 0000000..c8cf833
--- /dev/null
+++ b/drivers/video/nexell/soc/s5pxx18_soc_mlc.c
@@ -0,0 +1,1861 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Nexell Co., Ltd.
+ *
+ * Author: junghyun, kim <jhkim@nexell.co.kr>
+ */
+
+#include <linux/types.h>
+#include <linux/io.h>
+
+#include "s5pxx18_soc_mlc.h"
+
+static struct {
+ struct nx_mlc_register_set *pregister;
+} __g_module_variables[NUMBER_OF_MLC_MODULE] = { { NULL, },};
+
+int nx_mlc_initialize(void)
+{
+ static int binit;
+ u32 i;
+
+ if (binit == 0) {
+ for (i = 0; i < NUMBER_OF_MLC_MODULE; i++)
+ __g_module_variables[i].pregister = NULL;
+ binit = 1;
+ }
+ return 1;
+}
+
+u32 nx_mlc_get_physical_address(u32 module_index)
+{
+ const u32 physical_addr[] = PHY_BASEADDR_MLC_LIST;
+
+ return physical_addr[module_index];
+}
+
+void nx_mlc_set_base_address(u32 module_index, void *base_address)
+{
+ __g_module_variables[module_index].pregister =
+ (struct nx_mlc_register_set *)base_address;
+}
+
+void *nx_mlc_get_base_address(u32 module_index)
+{
+ return (void *)__g_module_variables[module_index].pregister;
+}
+
+void nx_mlc_set_clock_pclk_mode(u32 module_index, enum nx_pclkmode mode)
+{
+ const u32 pclkmode_pos = 3;
+ u32 clkmode = 0;
+
+ register u32 regvalue;
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ switch (mode) {
+ case nx_pclkmode_dynamic:
+ clkmode = 0;
+ break;
+ case nx_pclkmode_always:
+ clkmode = 1;
+ break;
+ default:
+ break;
+ }
+ regvalue = pregister->mlcclkenb;
+ regvalue &= ~(1ul << pclkmode_pos);
+ regvalue |= (clkmode & 0x01) << pclkmode_pos;
+
+ writel(regvalue, &pregister->mlcclkenb);
+}
+
+enum nx_pclkmode nx_mlc_get_clock_pclk_mode(u32 module_index)
+{
+ const u32 pclkmode_pos = 3;
+
+ if (__g_module_variables[module_index].pregister->mlcclkenb &
+ (1ul << pclkmode_pos)) {
+ return nx_pclkmode_always;
+ }
+ return nx_pclkmode_dynamic;
+}
+
+void nx_mlc_set_clock_bclk_mode(u32 module_index, enum nx_bclkmode mode)
+{
+ register u32 regvalue;
+ register struct nx_mlc_register_set *pregister;
+ u32 clkmode = 0;
+
+ pregister = __g_module_variables[module_index].pregister;
+ switch (mode) {
+ case nx_bclkmode_disable:
+ clkmode = 0;
+ break;
+ case nx_bclkmode_dynamic:
+ clkmode = 2;
+ break;
+ case nx_bclkmode_always:
+ clkmode = 3;
+ break;
+ default:
+ break;
+ }
+ regvalue = pregister->mlcclkenb;
+ regvalue &= ~(0x3);
+ regvalue |= clkmode & 0x3;
+
+ writel(regvalue, &pregister->mlcclkenb);
+}
+
+enum nx_bclkmode nx_mlc_get_clock_bclk_mode(u32 module_index)
+{
+ const u32 bclkmode = 3ul << 0;
+
+ switch (__g_module_variables[module_index].pregister->mlcclkenb &
+ bclkmode) {
+ case 0:
+ return nx_bclkmode_disable;
+ case 2:
+ return nx_bclkmode_dynamic;
+ case 3:
+ return nx_bclkmode_always;
+ }
+ return nx_bclkmode_disable;
+}
+
+void nx_mlc_set_top_power_mode(u32 module_index, int bpower)
+{
+ const u32 pixelbuffer_pwd_pos = 11;
+ const u32 pixelbuffer_pwd_mask = 1ul << pixelbuffer_pwd_pos;
+ const u32 dittyflag_mask = 1ul << 3;
+ register struct nx_mlc_register_set *pregister;
+ register u32 regvalue;
+
+ pregister = __g_module_variables[module_index].pregister;
+ regvalue = pregister->mlccontrolt;
+ regvalue &= ~(pixelbuffer_pwd_mask | dittyflag_mask);
+ regvalue |= (bpower << pixelbuffer_pwd_pos);
+
+ writel(regvalue, &pregister->mlccontrolt);
+}
+
+int nx_mlc_get_top_power_mode(u32 module_index)
+{
+ const u32 pixelbuffer_pwd_pos = 11;
+ const u32 pixelbuffer_pwd_mask = 1ul << pixelbuffer_pwd_pos;
+
+ return (int)((__g_module_variables[module_index].pregister->mlccontrolt
+ & pixelbuffer_pwd_mask) >>
+ pixelbuffer_pwd_pos);
+}
+
+void nx_mlc_set_top_sleep_mode(u32 module_index, int bsleep)
+{
+ const u32 pixelbuffer_sld_pos = 10;
+ const u32 pixelbuffer_sld_mask = 1ul << pixelbuffer_sld_pos;
+ const u32 dittyflag_mask = 1ul << 3;
+ register struct nx_mlc_register_set *pregister;
+ register u32 regvalue;
+
+ bsleep = (int)((u32)bsleep ^ 1);
+ pregister = __g_module_variables[module_index].pregister;
+ regvalue = pregister->mlccontrolt;
+ regvalue &= ~(pixelbuffer_sld_mask | dittyflag_mask);
+ regvalue |= (bsleep << pixelbuffer_sld_pos);
+
+ writel(regvalue, &pregister->mlccontrolt);
+}
+
+int nx_mlc_get_top_sleep_mode(u32 module_index)
+{
+ const u32 pixelbuffer_sld_pos = 11;
+ const u32 pixelbuffer_sld_mask = 1ul << pixelbuffer_sld_pos;
+
+ return (int)(((__g_module_variables[module_index].pregister->mlccontrolt
+ & pixelbuffer_sld_mask) >>
+ pixelbuffer_sld_pos) ^ 0x01);
+}
+
+void nx_mlc_set_top_dirty_flag(u32 module_index)
+{
+ const u32 dirtyflag = 1ul << 3;
+ register struct nx_mlc_register_set *pregister;
+ register u32 regvalue;
+
+ pregister = __g_module_variables[module_index].pregister;
+ regvalue = pregister->mlccontrolt;
+ regvalue |= dirtyflag;
+
+ writel(regvalue, &pregister->mlccontrolt);
+}
+
+int nx_mlc_get_top_dirty_flag(u32 module_index)
+{
+ const u32 dirtyflag_pos = 3;
+ const u32 dirtyflag_mask = 1ul << dirtyflag_pos;
+
+ return (int)((readl(&__g_module_variables[module_index]
+ .pregister->mlccontrolt) &
+ dirtyflag_mask) >> dirtyflag_pos);
+}
+
+void nx_mlc_set_mlc_enable(u32 module_index, int benb)
+{
+ const u32 mlcenb_pos = 1;
+ const u32 mlcenb_mask = 1ul << mlcenb_pos;
+ const u32 dirtyflag_pos = 3;
+ const u32 dirtyflag_mask = 1ul << dirtyflag_pos;
+ register u32 regvalue;
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ regvalue = pregister->mlccontrolt;
+ regvalue &= ~(mlcenb_mask | dirtyflag_mask);
+ regvalue |= (benb << mlcenb_pos);
+
+ writel(regvalue, &pregister->mlccontrolt);
+}
+
+int nx_mlc_get_mlc_enable(u32 module_index)
+{
+ const u32 mlcenb_pos = 1;
+ const u32 mlcenb_mask = 1ul << mlcenb_pos;
+
+ return (int)((__g_module_variables[module_index].pregister->mlccontrolt
+ & mlcenb_mask) >> mlcenb_pos);
+}
+
+void nx_mlc_set_field_enable(u32 module_index, int benb)
+{
+ const u32 fieldenb_pos = 0;
+ const u32 fieldenb_mask = 1ul << fieldenb_pos;
+ const u32 dirtyflag_pos = 3;
+ const u32 dirtyflag_mask = 1ul << dirtyflag_pos;
+ register u32 regvalue;
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ regvalue = pregister->mlccontrolt;
+ regvalue &= ~(fieldenb_mask | dirtyflag_mask);
+ regvalue |= (benb << fieldenb_pos);
+
+ writel(regvalue, &pregister->mlccontrolt);
+}
+
+int nx_mlc_get_field_enable(u32 module_index)
+{
+ const u32 fieldenb_pos = 0;
+ const u32 fieldenb_mask = 1ul << fieldenb_pos;
+
+ return (int)(__g_module_variables[module_index].pregister->mlccontrolt &
+ fieldenb_mask);
+}
+
+void nx_mlc_set_layer_priority(u32 module_index, enum nx_mlc_priority priority)
+{
+ const u32 priority_pos = 8;
+ const u32 priority_mask = 0x03 << priority_pos;
+ const u32 dirtyflag_pos = 3;
+ const u32 dirtyflag_mask = 1ul << dirtyflag_pos;
+ register struct nx_mlc_register_set *pregister;
+ register u32 regvalue;
+
+ pregister = __g_module_variables[module_index].pregister;
+ regvalue = pregister->mlccontrolt;
+ regvalue &= ~(priority_mask | dirtyflag_mask);
+ regvalue |= (priority << priority_pos);
+
+ writel(regvalue, &pregister->mlccontrolt);
+}
+
+void nx_mlc_set_screen_size(u32 module_index, u32 width, u32 height)
+{
+ register struct nx_mlc_register_set *pregister;
+ register u32 regvalue;
+
+ pregister = __g_module_variables[module_index].pregister;
+ regvalue = ((height - 1) << 16) | (width - 1);
+
+ writel(regvalue, &pregister->mlcscreensize);
+}
+
+void nx_mlc_get_screen_size(u32 module_index, u32 *pwidth, u32 *pheight)
+{
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+
+ if (pwidth)
+ *pwidth = (pregister->mlcscreensize & 0x0fff) + 1;
+
+ if (pheight)
+ *pheight = ((pregister->mlcscreensize >> 16) & 0x0fff) + 1;
+}
+
+void nx_mlc_set_background(u32 module_index, u32 color)
+{
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ writel(color, &pregister->mlcbgcolor);
+}
+
+void nx_mlc_set_dirty_flag(u32 module_index, u32 layer)
+{
+ register struct nx_mlc_register_set *pregister;
+ register u32 regvalue;
+ const u32 dirtyflg_mask = 1ul << 4;
+
+ pregister = __g_module_variables[module_index].pregister;
+ if (layer == 0 || layer == 1) {
+ regvalue = pregister->mlcrgblayer[layer].mlccontrol;
+ regvalue |= dirtyflg_mask;
+
+ writel(regvalue, &pregister->mlcrgblayer[layer].mlccontrol);
+ } else if (layer == 3) {
+ regvalue = pregister->mlcvideolayer.mlccontrol;
+ regvalue |= dirtyflg_mask;
+
+ writel(regvalue, &pregister->mlcvideolayer.mlccontrol);
+ }
+}
+
+int nx_mlc_get_dirty_flag(u32 module_index, u32 layer)
+{
+ const u32 dirtyflg_pos = 4;
+ const u32 dirtyflg_mask = 1ul << dirtyflg_pos;
+
+ if (layer == 0 || layer == 1) {
+ return (int)((__g_module_variables[module_index]
+ .pregister->mlcrgblayer[layer]
+ .mlccontrol & dirtyflg_mask) >> dirtyflg_pos);
+ } else if (layer == 2) {
+ return (int)((__g_module_variables[module_index]
+ .pregister->mlcrgblayer2.mlccontrol &
+ dirtyflg_mask) >> dirtyflg_pos);
+ } else if (layer == 3) {
+ return (int)((__g_module_variables[module_index]
+ .pregister->mlcvideolayer.mlccontrol &
+ dirtyflg_mask) >> dirtyflg_pos);
+ }
+ return 0;
+}
+
+void nx_mlc_set_layer_enable(u32 module_index, u32 layer, int benb)
+{
+ const u32 layerenb_pos = 5;
+ const u32 layerenb_mask = 0x01 << layerenb_pos;
+ const u32 dirtyflag_pos = 4;
+ const u32 dirtyflag_mask = 1ul << dirtyflag_pos;
+ register u32 regvalue;
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ if (layer == 0 || layer == 1) {
+ regvalue = pregister->mlcrgblayer[layer].mlccontrol;
+ regvalue &= ~(layerenb_mask | dirtyflag_mask);
+ regvalue |= (benb << layerenb_pos);
+
+ writel(regvalue, &pregister->mlcrgblayer[layer].mlccontrol);
+ } else if (layer == 3) {
+ regvalue = pregister->mlcvideolayer.mlccontrol;
+ regvalue &= ~(layerenb_mask | dirtyflag_mask);
+ regvalue |= (benb << layerenb_pos);
+
+ writel(regvalue, &pregister->mlcvideolayer.mlccontrol);
+ }
+}
+
+int nx_mlc_get_layer_enable(u32 module_index, u32 layer)
+{
+ const u32 layerenb_pos = 5;
+ const u32 layerenb_mask = 0x01 << layerenb_pos;
+
+ if (layer == 0 || layer == 1) {
+ return (int)((__g_module_variables[module_index]
+ .pregister->mlcrgblayer[layer]
+ .mlccontrol & layerenb_mask) >> layerenb_pos);
+ } else if (layer == 3) {
+ return (int)((__g_module_variables[module_index]
+ .pregister->mlcvideolayer.mlccontrol &
+ layerenb_mask) >> layerenb_pos);
+ }
+ return 0;
+}
+
+void nx_mlc_set_lock_size(u32 module_index, u32 layer, u32 locksize)
+{
+ const u32 locksize_mask = 3ul << 12;
+ const u32 dirtyflag_pos = 4;
+ const u32 dirtyflag_mask = 1ul << dirtyflag_pos;
+ register struct nx_mlc_register_set *pregister;
+ register u32 regvalue;
+
+ pregister = __g_module_variables[module_index].pregister;
+ locksize >>= 3;
+ if (layer == 0 || layer == 1) {
+ regvalue = pregister->mlcrgblayer[layer].mlccontrol;
+ regvalue &= ~(locksize_mask | dirtyflag_mask);
+ regvalue |= (locksize << 12);
+
+ writel(regvalue, &pregister->mlcrgblayer[layer].mlccontrol);
+ }
+}
+
+void nx_mlc_set_alpha_blending(u32 module_index, u32 layer, int benb, u32 alpha)
+{
+ const u32 blendenb_pos = 2;
+ const u32 blendenb_mask = 0x01 << blendenb_pos;
+ const u32 dirtyflag_pos = 4;
+ const u32 dirtyflag_mask = 1ul << dirtyflag_pos;
+ const u32 alpha_pos = 28;
+ const u32 alpha_mask = 0xf << alpha_pos;
+ register u32 regvalue;
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ if (layer == 0 || layer == 1) {
+ regvalue = pregister->mlcrgblayer[layer].mlccontrol;
+ regvalue &= ~(blendenb_mask | dirtyflag_mask);
+ regvalue |= (benb << blendenb_pos);
+
+ writel(regvalue, &pregister->mlcrgblayer[layer].mlccontrol);
+ regvalue = pregister->mlcrgblayer[layer].mlctpcolor;
+ regvalue &= ~alpha_mask;
+ regvalue |= alpha << alpha_pos;
+
+ writel(regvalue, &pregister->mlcrgblayer[layer].mlctpcolor);
+ } else if (layer == 3) {
+ regvalue = pregister->mlcvideolayer.mlccontrol;
+ regvalue &= ~(blendenb_mask | dirtyflag_mask);
+ regvalue |= (benb << blendenb_pos);
+
+ writel(regvalue, &pregister->mlcvideolayer.mlccontrol);
+
+ writel(alpha << alpha_pos,
+ &pregister->mlcvideolayer.mlctpcolor);
+ }
+}
+
+void nx_mlc_set_transparency(u32 module_index, u32 layer, int benb, u32 color)
+{
+ const u32 tpenb_pos = 0;
+ const u32 tpenb_mask = 0x01 << tpenb_pos;
+ const u32 dirtyflag_pos = 4;
+ const u32 dirtyflag_mask = 1ul << dirtyflag_pos;
+ const u32 tpcolor_pos = 0;
+ const u32 tpcolor_mask = ((1 << 24) - 1) << tpcolor_pos;
+ register u32 regvalue;
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ if (layer == 0 || layer == 1) {
+ regvalue = pregister->mlcrgblayer[layer].mlccontrol;
+ regvalue &= ~(tpenb_mask | dirtyflag_mask);
+ regvalue |= (benb << tpenb_pos);
+
+ writel(regvalue, &pregister->mlcrgblayer[layer].mlccontrol);
+ regvalue = pregister->mlcrgblayer[layer].mlctpcolor;
+ regvalue &= ~tpcolor_mask;
+ regvalue |= (color & tpcolor_mask);
+
+ writel(regvalue, &pregister->mlcrgblayer[layer].mlctpcolor);
+ }
+}
+
+void nx_mlc_set_color_inversion(u32 module_index, u32 layer, int benb,
+ u32 color)
+{
+ const u32 invenb_pos = 1;
+ const u32 invenb_mask = 0x01 << invenb_pos;
+ const u32 dirtyflag_pos = 4;
+ const u32 dirtyflag_mask = 1ul << dirtyflag_pos;
+ const u32 invcolor_pos = 0;
+ const u32 invcolor_mask = ((1 << 24) - 1) << invcolor_pos;
+ register u32 regvalue;
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ if (layer == 0 || layer == 1) {
+ regvalue = pregister->mlcrgblayer[layer].mlccontrol;
+ regvalue &= ~(invenb_mask | dirtyflag_mask);
+ regvalue |= (benb << invenb_pos);
+
+ writel(regvalue, &pregister->mlcrgblayer[layer].mlccontrol);
+ regvalue = pregister->mlcrgblayer[layer].mlcinvcolor;
+ regvalue &= ~invcolor_mask;
+ regvalue |= (color & invcolor_mask);
+
+ writel(regvalue, &pregister->mlcrgblayer[layer].mlcinvcolor);
+ }
+}
+
+u32 nx_mlc_get_extended_color(u32 module_index, u32 color,
+ enum nx_mlc_rgbfmt format)
+{
+ u32 rgb[3] = {
+ 0,
+ };
+ u32 bw[3] = {
+ 0,
+ };
+ u32 bp[3] = {
+ 0,
+ };
+ u32 blank = 0;
+ u32 fill = 0;
+ u32 i = 0;
+
+ switch (format) {
+ case nx_mlc_rgbfmt_r5g6b5:
+ bw[0] = 5;
+ bw[1] = 6;
+ bw[2] = 5;
+ bp[0] = 11;
+ bp[1] = 5;
+ bp[2] = 0;
+ break;
+ case nx_mlc_rgbfmt_b5g6r5:
+ bw[0] = 5;
+ bw[1] = 6;
+ bw[2] = 5;
+ bp[0] = 0;
+ bp[1] = 5;
+ bp[2] = 11;
+ break;
+ case nx_mlc_rgbfmt_x1r5g5b5:
+ case nx_mlc_rgbfmt_a1r5g5b5:
+ bw[0] = 5;
+ bw[1] = 5;
+ bw[2] = 5;
+ bp[0] = 10;
+ bp[1] = 5;
+ bp[2] = 0;
+ break;
+ case nx_mlc_rgbfmt_x1b5g5r5:
+ case nx_mlc_rgbfmt_a1b5g5r5:
+ bw[0] = 5;
+ bw[1] = 5;
+ bw[2] = 5;
+ bp[0] = 0;
+ bp[1] = 5;
+ bp[2] = 10;
+ break;
+ case nx_mlc_rgbfmt_x4r4g4b4:
+ case nx_mlc_rgbfmt_a4r4g4b4:
+ bw[0] = 4;
+ bw[1] = 4;
+ bw[2] = 4;
+ bp[0] = 8;
+ bp[1] = 4;
+ bp[2] = 0;
+ break;
+ case nx_mlc_rgbfmt_x4b4g4r4:
+ case nx_mlc_rgbfmt_a4b4g4r4:
+ bw[0] = 4;
+ bw[1] = 4;
+ bw[2] = 4;
+ bp[0] = 0;
+ bp[1] = 4;
+ bp[2] = 8;
+ break;
+ case nx_mlc_rgbfmt_x8r3g3b2:
+ case nx_mlc_rgbfmt_a8r3g3b2:
+ bw[0] = 3;
+ bw[1] = 3;
+ bw[2] = 2;
+ bp[0] = 5;
+ bp[1] = 2;
+ bp[2] = 0;
+ break;
+ case nx_mlc_rgbfmt_x8b3g3r2:
+ case nx_mlc_rgbfmt_a8b3g3r2:
+ bw[0] = 2;
+ bw[1] = 3;
+ bw[2] = 3;
+ bp[0] = 0;
+ bp[1] = 2;
+ bp[2] = 5;
+ break;
+ case nx_mlc_rgbfmt_r8g8b8:
+ case nx_mlc_rgbfmt_a8r8g8b8:
+ bw[0] = 8;
+ bw[1] = 8;
+ bw[2] = 8;
+ bp[0] = 16;
+ bp[1] = 8;
+ bp[2] = 0;
+ break;
+ case nx_mlc_rgbfmt_b8g8r8:
+ case nx_mlc_rgbfmt_a8b8g8r8:
+ bw[0] = 8;
+ bw[1] = 8;
+ bw[2] = 8;
+ bp[0] = 0;
+ bp[1] = 8;
+ bp[2] = 16;
+ break;
+ default:
+ break;
+ }
+ for (i = 0; i < 3; i++) {
+ rgb[i] = (color >> bp[i]) & ((u32)(1 << bw[i]) - 1);
+ fill = bw[i];
+ blank = 8 - fill;
+ rgb[i] <<= blank;
+ while (blank > 0) {
+ rgb[i] |= (rgb[i] >> fill);
+ blank -= fill;
+ fill += fill;
+ }
+ }
+
+ return (rgb[0] << 16) | (rgb[1] << 8) | (rgb[2] << 0);
+}
+
+void nx_mlc_set_format_rgb(u32 module_index, u32 layer,
+ enum nx_mlc_rgbfmt format)
+{
+ const u32 dirtyflag_pos = 4;
+ const u32 dirtyflag_mask = 1ul << dirtyflag_pos;
+ const u32 format_mask = 0xffff0000ul;
+ register u32 regvalue;
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ if (layer == 0 || layer == 1) {
+ regvalue = pregister->mlcrgblayer[layer].mlccontrol;
+ regvalue &= ~(format_mask | dirtyflag_mask);
+ regvalue |= (u32)format;
+
+ writel(regvalue, &pregister->mlcrgblayer[layer].mlccontrol);
+ }
+}
+
+void nx_mlc_set_format_yuv(u32 module_index, enum nx_mlc_yuvfmt format)
+{
+ const u32 format_mask = 0xffff0000ul;
+ register u32 temp;
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ temp = pregister->mlcvideolayer.mlccontrol;
+ temp &= ~format_mask;
+ temp |= (u32)format;
+
+ writel(temp, &pregister->mlcvideolayer.mlccontrol);
+}
+
+void nx_mlc_set_position(u32 module_index, u32 layer, s32 sx, s32 sy,
+ s32 ex, s32 ey)
+{
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ if (layer == 0 || layer == 1) {
+ writel((((u32)sx & 0xffful) << 16) | ((u32)ex & 0xffful),
+ &pregister->mlcrgblayer[layer].mlcleftright);
+
+ writel((((u32)sy & 0xffful) << 16) | ((u32)ey & 0xffful),
+ &pregister->mlcrgblayer[layer].mlctopbottom);
+ } else if (layer == 2) {
+ writel((((u32)sx & 0xffful) << 16) | ((u32)ex & 0xffful),
+ &pregister->mlcrgblayer2.mlcleftright);
+
+ writel((((u32)sy & 0xffful) << 16) | ((u32)ey & 0xffful),
+ &pregister->mlcrgblayer2.mlctopbottom);
+ } else if (layer == 3) {
+ writel((((u32)sx & 0xffful) << 16) | ((u32)ex & 0xffful),
+ &pregister->mlcvideolayer.mlcleftright);
+
+ writel((((u32)sy & 0xffful) << 16) | ((u32)ey & 0xffful),
+ &pregister->mlcvideolayer.mlctopbottom);
+ }
+}
+
+void nx_mlc_set_dither_enable_when_using_gamma(u32 module_index, int benable)
+{
+ const u32 ditherenb_bitpos = 0;
+ const u32 ditherenb_mask = 1 << ditherenb_bitpos;
+ register struct nx_mlc_register_set *pregister;
+ register u32 read_value;
+
+ pregister = __g_module_variables[module_index].pregister;
+ read_value = pregister->mlcgammacont;
+ read_value &= ~ditherenb_mask;
+ read_value |= ((u32)benable << ditherenb_bitpos);
+
+ writel(read_value, &pregister->mlcgammacont);
+}
+
+int nx_mlc_get_dither_enable_when_using_gamma(u32 module_index)
+{
+ const u32 ditherenb_bitpos = 0;
+ const u32 ditherenb_mask = 1 << ditherenb_bitpos;
+
+ return (int)(__g_module_variables[module_index].pregister->mlcgammacont
+ & ditherenb_mask);
+}
+
+void nx_mlc_set_gamma_priority(u32 module_index, int bvideolayer)
+{
+ const u32 alphaselect_bitpos = 5;
+ const u32 alphaselect_mask = 1 << alphaselect_bitpos;
+ register struct nx_mlc_register_set *pregister;
+ register u32 read_value;
+
+ pregister = __g_module_variables[module_index].pregister;
+ read_value = pregister->mlcgammacont;
+ read_value &= ~alphaselect_mask;
+ read_value |= ((u32)bvideolayer << alphaselect_bitpos);
+
+ writel(read_value, &pregister->mlcgammacont);
+}
+
+int nx_mlc_get_gamma_priority(u32 module_index)
+{
+ const u32 alphaselect_bitpos = 5;
+ const u32 alphaselect_mask = 1 << alphaselect_bitpos;
+
+ return (int)((__g_module_variables[module_index].pregister->mlcgammacont
+ & alphaselect_mask) >> alphaselect_bitpos);
+}
+
+void nx_mlc_set_rgblayer_invalid_position(u32 module_index, u32 layer,
+ u32 region, s32 sx, s32 sy,
+ s32 ex, s32 ey, int benb)
+{
+ const u32 invalidenb_pos = 28;
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ if (layer == 0 || layer == 1) {
+ if (region == 0) {
+ writel(((benb << invalidenb_pos) |
+ ((sx & 0x7ff) << 16) | (ex & 0x7ff)),
+ &pregister->mlcrgblayer[layer]
+ .mlcinvalidleftright0);
+
+ writel((((sy & 0x7ff) << 16) | (ey & 0x7ff)),
+ &pregister->mlcrgblayer[layer]
+ .mlcinvalidtopbottom0);
+ } else {
+ writel(((benb << invalidenb_pos) |
+ ((sx & 0x7ff) << 16) | (ex & 0x7ff)),
+ &pregister->mlcrgblayer[layer]
+ .mlcinvalidleftright1);
+
+ writel((((sy & 0x7ff) << 16) | (ey & 0x7ff)),
+ &pregister->mlcrgblayer[layer]
+ .mlcinvalidtopbottom1);
+ }
+ }
+}
+
+void nx_mlc_set_rgblayer_stride(u32 module_index, u32 layer, s32 hstride,
+ s32 vstride)
+{
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ if (layer == 0 || layer == 1) {
+ writel(hstride, &pregister->mlcrgblayer[layer].mlchstride);
+ writel(vstride, &pregister->mlcrgblayer[layer].mlcvstride);
+ } else if (layer == 2) {
+ writel(hstride, &pregister->mlcrgblayer2.mlchstride);
+ writel(vstride, &pregister->mlcrgblayer2.mlcvstride);
+ }
+}
+
+void nx_mlc_set_rgblayer_address(u32 module_index, u32 layer, u32 addr)
+{
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ if (layer == 0 || layer == 1)
+ writel(addr, &pregister->mlcrgblayer[layer].mlcaddress);
+ else if (layer == 2)
+ writel(addr, &pregister->mlcrgblayer2.mlcaddress);
+}
+
+void nx_mlc_set_rgblayer_gama_table_power_mode(u32 module_index, int bred,
+ int bgreen, int bblue)
+{
+ const u32 bgammatable_pwd_bitpos = 11;
+ const u32 ggammatable_pwd_bitpos = 9;
+ const u32 rgammatable_pwd_bitpos = 3;
+ const u32 bgammatable_pwd_mask = (1 << bgammatable_pwd_bitpos);
+ const u32 ggammatable_pwd_mask = (1 << ggammatable_pwd_bitpos);
+ const u32 rgammatable_pwd_mask = (1 << rgammatable_pwd_bitpos);
+ register u32 read_value;
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ read_value = pregister->mlcgammacont;
+ read_value &= ~(bgammatable_pwd_mask | ggammatable_pwd_mask |
+ rgammatable_pwd_mask);
+ read_value |= (((u32)bred << rgammatable_pwd_bitpos) |
+ ((u32)bgreen << ggammatable_pwd_bitpos) |
+ ((u32)bblue << bgammatable_pwd_bitpos));
+
+ writel(read_value, &pregister->mlcgammacont);
+}
+
+void nx_mlc_get_rgblayer_gama_table_power_mode(u32 module_index, int *pbred,
+ int *pbgreen, int *pbblue)
+{
+ const u32 bgammatable_pwd_bitpos = 11;
+ const u32 ggammatable_pwd_bitpos = 9;
+ const u32 rgammatable_pwd_bitpos = 3;
+ const u32 bgammatable_pwd_mask = (1 << bgammatable_pwd_bitpos);
+ const u32 ggammatable_pwd_mask = (1 << ggammatable_pwd_bitpos);
+ const u32 rgammatable_pwd_mask = (1 << rgammatable_pwd_bitpos);
+ register u32 read_value;
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ read_value = pregister->mlcgammacont;
+ if (pbred)
+ *pbred = (read_value & rgammatable_pwd_mask) ? 1 : 0;
+
+ if (pbgreen)
+ *pbgreen = (read_value & ggammatable_pwd_mask) ? 1 : 0;
+
+ if (pbblue)
+ *pbblue = (read_value & bgammatable_pwd_mask) ? 1 : 0;
+}
+
+void nx_mlc_set_rgblayer_gama_table_sleep_mode(u32 module_index, int bred,
+ int bgreen, int bblue)
+{
+ const u32 bgammatable_sld_bitpos = 10;
+ const u32 ggammatable_sld_bitpos = 8;
+ const u32 rgammatable_sld_bitpos = 2;
+ const u32 bgammatable_sld_mask = (1 << bgammatable_sld_bitpos);
+ const u32 ggammatable_sld_mask = (1 << ggammatable_sld_bitpos);
+ const u32 rgammatable_sld_mask = (1 << rgammatable_sld_bitpos);
+ register u32 read_value;
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ read_value = pregister->mlcgammacont;
+ if (bred)
+ read_value &= ~rgammatable_sld_mask;
+ else
+ read_value |= rgammatable_sld_mask;
+
+ if (bgreen)
+ read_value &= ~ggammatable_sld_mask;
+ else
+ read_value |= ggammatable_sld_mask;
+
+ if (bblue)
+ read_value &= ~bgammatable_sld_mask;
+ else
+ read_value |= bgammatable_sld_mask;
+
+ writel(read_value, &pregister->mlcgammacont);
+}
+
+void nx_mlc_get_rgblayer_gama_table_sleep_mode(u32 module_index, int *pbred,
+ int *pbgreen, int *pbblue)
+{
+ const u32 bgammatable_sld_bitpos = 10;
+ const u32 ggammatable_sld_bitpos = 8;
+ const u32 rgammatable_sld_bitpos = 2;
+ const u32 bgammatable_sld_mask = (1 << bgammatable_sld_bitpos);
+ const u32 ggammatable_sld_mask = (1 << ggammatable_sld_bitpos);
+ const u32 rgammatable_sld_mask = (1 << rgammatable_sld_bitpos);
+ register u32 read_value;
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ read_value = pregister->mlcgammacont;
+
+ if (pbred)
+ *pbred = (read_value & rgammatable_sld_mask) ? 0 : 1;
+
+ if (pbgreen)
+ *pbgreen = (read_value & ggammatable_sld_mask) ? 0 : 1;
+
+ if (pbblue)
+ *pbblue = (read_value & bgammatable_sld_mask) ? 0 : 1;
+}
+
+void nx_mlc_set_rgblayer_rgamma_table(u32 module_index, u32 dwaddress,
+ u32 dwdata)
+{
+ register struct nx_mlc_register_set *pregister;
+ const u32 tableaddr_bitpos = 24;
+
+ pregister = __g_module_variables[module_index].pregister;
+ writel(((dwaddress << tableaddr_bitpos) | dwdata),
+ &pregister->mlcrgammatablewrite);
+}
+
+void nx_mlc_set_rgblayer_ggamma_table(u32 module_index, u32 dwaddress,
+ u32 dwdata)
+{
+ register struct nx_mlc_register_set *pregister;
+ const u32 tableaddr_bitpos = 24;
+
+ pregister = __g_module_variables[module_index].pregister;
+ writel(((dwaddress << tableaddr_bitpos) | dwdata),
+ &pregister->mlcggammatablewrite);
+}
+
+void nx_mlc_set_rgblayer_bgamma_table(u32 module_index, u32 dwaddress,
+ u32 dwdata)
+{
+ register struct nx_mlc_register_set *pregister;
+ const u32 tableaddr_bitpos = 24;
+
+ pregister = __g_module_variables[module_index].pregister;
+ writel(((dwaddress << tableaddr_bitpos) | dwdata),
+ &pregister->mlcbgammatablewrite);
+}
+
+void nx_mlc_set_rgblayer_gamma_enable(u32 module_index, int benable)
+{
+ const u32 rgbgammaemb_bitpos = 1;
+ const u32 rgbgammaemb_mask = 1 << rgbgammaemb_bitpos;
+ register u32 read_value;
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ read_value = pregister->mlcgammacont;
+ read_value &= ~rgbgammaemb_mask;
+ read_value |= (u32)benable << rgbgammaemb_bitpos;
+
+ writel(read_value, &pregister->mlcgammacont);
+}
+
+int nx_mlc_get_rgblayer_gamma_enable(u32 module_index)
+{
+ const u32 rgbgammaemb_bitpos = 1;
+ const u32 rgbgammaemb_mask = 1 << rgbgammaemb_bitpos;
+
+ return (int)((__g_module_variables[module_index].pregister->mlcgammacont
+ & rgbgammaemb_mask) >> rgbgammaemb_bitpos);
+}
+
+void nx_mlc_set_video_layer_stride(u32 module_index, s32 lu_stride,
+ s32 cb_stride, s32 cr_stride)
+{
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+
+ writel(lu_stride, &pregister->mlcvideolayer.mlcvstride);
+ writel(cb_stride, &pregister->mlcvideolayer.mlcvstridecb);
+ writel(cr_stride, &pregister->mlcvideolayer.mlcvstridecr);
+}
+
+void nx_mlc_set_video_layer_address(u32 module_index, u32 lu_addr, u32 cb_addr,
+ u32 cr_addr)
+{
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ writel(lu_addr, &pregister->mlcvideolayer.mlcaddress);
+ writel(cb_addr, &pregister->mlcvideolayer.mlcaddresscb);
+ writel(cr_addr, &pregister->mlcvideolayer.mlcaddresscr);
+}
+
+void nx_mlc_set_video_layer_address_yuyv(u32 module_index, u32 addr,
+ s32 stride)
+{
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ writel(addr, &pregister->mlcvideolayer.mlcaddress);
+ writel(stride, &pregister->mlcvideolayer.mlcvstride);
+}
+
+void nx_mlc_set_video_layer_scale_factor(u32 module_index, u32 hscale,
+ u32 vscale, int bhlumaenb,
+ int bhchromaenb, int bvlumaenb,
+ int bvchromaenb)
+{
+ const u32 filter_luma_pos = 28;
+ const u32 filter_choma_pos = 29;
+ const u32 scale_mask = ((1 << 23) - 1);
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+
+ writel(((bhlumaenb << filter_luma_pos) |
+ (bhchromaenb << filter_choma_pos) | (hscale & scale_mask)),
+ &pregister->mlcvideolayer.mlchscale);
+
+ writel(((bvlumaenb << filter_luma_pos) |
+ (bvchromaenb << filter_choma_pos) | (vscale & scale_mask)),
+ &pregister->mlcvideolayer.mlcvscale);
+}
+
+void nx_mlc_set_video_layer_scale_filter(u32 module_index, int bhlumaenb,
+ int bhchromaenb, int bvlumaenb,
+ int bvchromaenb)
+{
+ const u32 filter_luma_pos = 28;
+ const u32 filter_choma_pos = 29;
+ const u32 scale_mask = ((1 << 23) - 1);
+ register struct nx_mlc_register_set *pregister;
+ register u32 read_value;
+
+ pregister = __g_module_variables[module_index].pregister;
+ read_value = pregister->mlcvideolayer.mlchscale;
+ read_value &= scale_mask;
+ read_value |=
+ (bhlumaenb << filter_luma_pos) | (bhchromaenb << filter_choma_pos);
+
+ writel(read_value, &pregister->mlcvideolayer.mlchscale);
+ read_value = pregister->mlcvideolayer.mlcvscale;
+ read_value &= scale_mask;
+ read_value |=
+ (bvlumaenb << filter_luma_pos) | (bvchromaenb << filter_choma_pos);
+
+ writel(read_value, &pregister->mlcvideolayer.mlcvscale);
+}
+
+void nx_mlc_get_video_layer_scale_filter(u32 module_index, int *bhlumaenb,
+ int *bhchromaenb, int *bvlumaenb,
+ int *bvchromaenb)
+{
+ const u32 filter_luma_pos = 28;
+ const u32 filter_choma_pos = 29;
+ const u32 filter_mask = 1ul;
+ register struct nx_mlc_register_set *pregister;
+ register u32 read_value;
+
+ pregister = __g_module_variables[module_index].pregister;
+ read_value = pregister->mlcvideolayer.mlchscale;
+ *bhlumaenb = (read_value >> filter_luma_pos) & filter_mask;
+ *bhchromaenb = (read_value >> filter_choma_pos) & filter_mask;
+ read_value = pregister->mlcvideolayer.mlcvscale;
+ *bvlumaenb = (read_value >> filter_luma_pos) & filter_mask;
+ *bvchromaenb = (read_value >> filter_choma_pos) & filter_mask;
+}
+
+void nx_mlc_set_video_layer_scale(u32 module_index, u32 sw, u32 sh, u32 dw,
+ u32 dh, int bhlumaenb, int bhchromaenb,
+ int bvlumaenb, int bvchromaenb)
+{
+ const u32 filter_luma_pos = 28;
+ const u32 filter_choma_pos = 29;
+ const u32 scale_mask = ((1 << 23) - 1);
+ register u32 hscale, vscale, cal_sh;
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+
+ if ((bhlumaenb || bhchromaenb) && dw > sw) {
+ sw--;
+ dw--;
+ }
+ hscale = (sw << 11) / dw;
+
+ if ((bvlumaenb || bvchromaenb) && dh > sh) {
+ sh--;
+ dh--;
+ vscale = (sh << 11) / dh;
+
+ cal_sh = ((vscale * dh) >> 11);
+ if (sh <= cal_sh)
+ vscale--;
+
+ } else {
+ vscale = (sh << 11) / dh;
+ }
+
+ writel(((bhlumaenb << filter_luma_pos) |
+ (bhchromaenb << filter_choma_pos) | (hscale & scale_mask)),
+ &pregister->mlcvideolayer.mlchscale);
+
+ writel(((bvlumaenb << filter_luma_pos) |
+ (bvchromaenb << filter_choma_pos) | (vscale & scale_mask)),
+ &pregister->mlcvideolayer.mlcvscale);
+}
+
+void nx_mlc_set_video_layer_luma_enhance(u32 module_index, u32 contrast,
+ s32 brightness)
+{
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+
+ writel((((u32)brightness & 0xfful) << 8) | contrast,
+ &pregister->mlcvideolayer.mlcluenh);
+}
+
+void nx_mlc_set_video_layer_chroma_enhance(u32 module_index, u32 quadrant,
+ s32 cb_a, s32 cb_b,
+ s32 cr_a, s32 cr_b)
+{
+ register struct nx_mlc_register_set *pregister;
+ register u32 temp;
+
+ pregister = __g_module_variables[module_index].pregister;
+ temp = (((u32)cr_b & 0xfful) << 24) | (((u32)cr_a & 0xfful) << 16) |
+ (((u32)cb_b & 0xfful) << 8) | (((u32)cb_a & 0xfful) << 0);
+ if (quadrant > 0) {
+ writel(temp, &pregister->mlcvideolayer.mlcchenh[quadrant - 1]);
+ } else {
+ writel(temp, &pregister->mlcvideolayer.mlcchenh[0]);
+ writel(temp, &pregister->mlcvideolayer.mlcchenh[1]);
+ writel(temp, &pregister->mlcvideolayer.mlcchenh[2]);
+ writel(temp, &pregister->mlcvideolayer.mlcchenh[3]);
+ }
+}
+
+void nx_mlc_set_video_layer_line_buffer_power_mode(u32 module_index,
+ int benable)
+{
+ const u32 linebuff_pwd_pos = 15;
+ const u32 linebuff_pwd_mask = 1ul << linebuff_pwd_pos;
+ const u32 dirtyflag_mask = 1ul << 4;
+ register u32 regvalue;
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ regvalue = pregister->mlcvideolayer.mlccontrol;
+ regvalue &= ~(linebuff_pwd_mask | dirtyflag_mask);
+ regvalue |= ((u32)benable << linebuff_pwd_pos);
+
+ writel(regvalue, &pregister->mlcvideolayer.mlccontrol);
+}
+
+int nx_mlc_get_video_layer_line_buffer_power_mode(u32 module_index)
+{
+ const u32 linebuff_pwd_pos = 15;
+ const u32 linebuff_pwd_mask = 1ul << linebuff_pwd_pos;
+
+ return (int)((__g_module_variables[module_index]
+ .pregister->mlcvideolayer.mlccontrol &
+ linebuff_pwd_mask) >> linebuff_pwd_pos);
+}
+
+void nx_mlc_set_video_layer_line_buffer_sleep_mode(u32 module_index,
+ int benable)
+{
+ const u32 linebuff_slmd_pos = 14;
+ const u32 linebuff_slmd_mask = 1ul << linebuff_slmd_pos;
+ const u32 dirtyflag_mask = 1ul << 4;
+ register u32 regvalue;
+ register struct nx_mlc_register_set *pregister;
+
+ benable = (int)((u32)benable ^ 1);
+ pregister = __g_module_variables[module_index].pregister;
+ regvalue = pregister->mlcvideolayer.mlccontrol;
+ regvalue &= ~(linebuff_slmd_mask | dirtyflag_mask);
+ regvalue |= (benable << linebuff_slmd_pos);
+
+ writel(regvalue, &pregister->mlcvideolayer.mlccontrol);
+}
+
+int nx_mlc_get_video_layer_line_buffer_sleep_mode(u32 module_index)
+{
+ const u32 linebuff_slmd_pos = 14;
+ const u32 linebuff_slmd_mask = 1ul << linebuff_slmd_pos;
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ if (linebuff_slmd_mask & pregister->mlcvideolayer.mlccontrol)
+ return 0;
+ else
+ return 1;
+}
+
+void nx_mlc_set_video_layer_gama_table_power_mode(u32 module_index, int by,
+ int bu, int bv)
+{
+ const u32 vgammatable_pwd_bitpos = 17;
+ const u32 ugammatable_pwd_bitpos = 15;
+ const u32 ygammatable_pwd_bitpos = 13;
+ const u32 vgammatable_pwd_mask = (1 << vgammatable_pwd_bitpos);
+ const u32 ugammatable_pwd_mask = (1 << ugammatable_pwd_bitpos);
+ const u32 ygammatable_pwd_mask = (1 << ygammatable_pwd_bitpos);
+ register u32 read_value;
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ read_value = pregister->mlcgammacont;
+ read_value &= ~(ygammatable_pwd_mask | ugammatable_pwd_mask |
+ vgammatable_pwd_mask);
+ read_value |= (((u32)by << ygammatable_pwd_bitpos) |
+ ((u32)bu << ugammatable_pwd_bitpos) |
+ ((u32)bv << vgammatable_pwd_bitpos));
+
+ writel(read_value, &pregister->mlcgammacont);
+}
+
+void nx_mlc_get_video_layer_gama_table_power_mode(u32 module_index, int *pby,
+ int *pbu, int *pbv)
+{
+ const u32 vgammatable_pwd_bitpos = 17;
+ const u32 ugammatable_pwd_bitpos = 15;
+ const u32 ygammatable_pwd_bitpos = 13;
+ const u32 vgammatable_pwd_mask = (1 << vgammatable_pwd_bitpos);
+ const u32 ugammatable_pwd_mask = (1 << ugammatable_pwd_bitpos);
+ const u32 ygammatable_pwd_mask = (1 << ygammatable_pwd_bitpos);
+ register u32 read_value;
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ read_value = pregister->mlcgammacont;
+ if (pby)
+ *pby = (read_value & ygammatable_pwd_mask) ? 1 : 0;
+
+ if (pbu)
+ *pbu = (read_value & ugammatable_pwd_mask) ? 1 : 0;
+
+ if (pbv)
+ *pbv = (read_value & vgammatable_pwd_mask) ? 1 : 0;
+}
+
+void nx_mlc_set_video_layer_gama_table_sleep_mode(u32 module_index, int by,
+ int bu, int bv)
+{
+ const u32 vgammatable_sld_bitpos = 16;
+ const u32 ugammatable_sld_bitpos = 14;
+ const u32 ygammatable_sld_bitpos = 12;
+ const u32 vgammatable_sld_mask = (1 << vgammatable_sld_bitpos);
+ const u32 ugammatable_sld_mask = (1 << ugammatable_sld_bitpos);
+ const u32 ygammatable_sld_mask = (1 << ygammatable_sld_bitpos);
+ register u32 read_value;
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ read_value = pregister->mlcgammacont;
+ if (by)
+ read_value &= ~ygammatable_sld_mask;
+ else
+ read_value |= ygammatable_sld_mask;
+
+ if (bu)
+ read_value &= ~ugammatable_sld_mask;
+ else
+ read_value |= ugammatable_sld_mask;
+
+ if (bv)
+ read_value &= ~vgammatable_sld_mask;
+ else
+ read_value |= vgammatable_sld_mask;
+
+ writel(read_value, &pregister->mlcgammacont);
+}
+
+void nx_mlc_get_video_layer_gama_table_sleep_mode(u32 module_index, int *pby,
+ int *pbu, int *pbv)
+{
+ const u32 vgammatable_sld_bitpos = 16;
+ const u32 ugammatable_sld_bitpos = 14;
+ const u32 ygammatable_sld_bitpos = 12;
+ const u32 vgammatable_sld_mask = (1 << vgammatable_sld_bitpos);
+ const u32 ugammatable_sld_mask = (1 << ugammatable_sld_bitpos);
+ const u32 ygammatable_sld_mask = (1 << ygammatable_sld_bitpos);
+ register u32 read_value;
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ read_value = pregister->mlcgammacont;
+
+ if (pby)
+ *pby = (read_value & vgammatable_sld_mask) ? 0 : 1;
+
+ if (pbu)
+ *pbu = (read_value & ugammatable_sld_mask) ? 0 : 1;
+
+ if (pbv)
+ *pbv = (read_value & ygammatable_sld_mask) ? 0 : 1;
+}
+
+void nx_mlc_set_video_layer_gamma_enable(u32 module_index, int benable)
+{
+ const u32 yuvgammaemb_bitpos = 4;
+ const u32 yuvgammaemb_mask = 1 << yuvgammaemb_bitpos;
+ register u32 read_value;
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ read_value = pregister->mlcgammacont;
+ read_value &= ~yuvgammaemb_mask;
+ read_value |= (u32)benable << yuvgammaemb_bitpos;
+
+ writel(read_value, &pregister->mlcgammacont);
+}
+
+int nx_mlc_get_video_layer_gamma_enable(u32 module_index)
+{
+ const u32 yuvgammaemb_bitpos = 4;
+ const u32 yuvgammaemb_mask = 1 << yuvgammaemb_bitpos;
+
+ return (int)((__g_module_variables[module_index].pregister->mlcgammacont
+ & yuvgammaemb_mask) >> yuvgammaemb_bitpos);
+}
+
+void nx_mlc_set_gamma_table_poweroff(u32 module_index, int enb)
+{
+ register struct nx_mlc_register_set *pregister;
+ u32 regvalue;
+
+ pregister = __g_module_variables[module_index].pregister;
+ if (enb == 1) {
+ regvalue = pregister->mlcgammacont;
+ regvalue = regvalue & 0xf3;
+ writel(regvalue, &pregister->mlcgammacont);
+ }
+}
+
+void nx_mlc_set_mlctop_control_parameter(u32 module_index, int field_enable,
+ int mlcenable, u8 priority,
+ enum g3daddrchangeallowed
+ g3daddr_change_allowed)
+{
+ register u32 mlctopcontrolreg;
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ mlctopcontrolreg = (readl(&pregister->mlccontrolt)) & 0xfffffcfc;
+ mlctopcontrolreg = (u32)(mlctopcontrolreg |
+ ((priority << 8) | ((mlcenable == 1) << 1) |
+ (1 ==
+ field_enable)) | (g3daddr_change_allowed <<
+ 12));
+ writel(mlctopcontrolreg, &pregister->mlccontrolt);
+}
+
+void nx_mlc_set_rgb0layer_control_parameter(u32 module_index, int layer_enable,
+ int grp3denable, int tp_enable,
+ u32 transparency_color,
+ int inv_enable, u32 inverse_color,
+ int blend_enable, u8 alpha_value,
+ enum mlc_rgbfmt rbgformat,
+ enum locksizesel lock_size_select)
+{
+ u32 layer_format;
+ u32 control_enb;
+ u32 alpha_argument;
+ u32 lock_size = (u32)(lock_size_select & 0x3);
+ u32 rgb0controlreg;
+ u32 regvalue;
+ register struct nx_mlc_register_set *pregister;
+
+ layer_format = nx_mlc_get_rgbformat(rbgformat);
+ pregister = __g_module_variables[module_index].pregister;
+ control_enb =
+ (u32)((grp3denable << 8) | (layer_enable << 5) |
+ (blend_enable << 2) | (inv_enable << 1) | tp_enable) & 0x127;
+ alpha_argument = (u32)(alpha_value & 0xf);
+
+ rgb0controlreg = readl(&pregister->mlcrgblayer[0].mlccontrol) & 0x10;
+ regvalue =
+ (u32)(((layer_format << 16) | control_enb | (lock_size << 12)) |
+ rgb0controlreg);
+ writel(regvalue, &pregister->mlcrgblayer[0].mlccontrol);
+
+ regvalue = (u32)((alpha_argument << 28) | transparency_color);
+ writel(regvalue, &pregister->mlcrgblayer[0].mlctpcolor);
+ regvalue = inverse_color;
+ writel(regvalue, &pregister->mlcrgblayer[0].mlcinvcolor);
+}
+
+u32 nx_mlc_get_rgbformat(enum mlc_rgbfmt rbgformat)
+{
+ u32 rgbformatvalue;
+ const u32 format_table[] = {
+ 0x4432ul, 0x4342ul, 0x4211ul, 0x4120ul, 0x4003ul, 0x4554ul,
+ 0x3342ul, 0x2211ul, 0x1120ul, 0x1003ul, 0x4653ul, 0x4653ul,
+ 0x0653ul, 0x4ed3ul, 0x4f84ul, 0xc432ul, 0xc342ul, 0xc211ul,
+ 0xc120ul, 0xb342ul, 0xa211ul, 0x9120ul, 0xc653ul, 0xc653ul,
+ 0x8653ul, 0xced3ul, 0xcf84ul, 0x443aul
+ };
+
+ return rgbformatvalue = format_table[rbgformat];
+}
+
+void nx_mlc_set_rgb1layer_control_parameter(u32 module_index, int layer_enable,
+ int grp3denable, int tp_enable,
+ u32 transparency_color,
+ int inv_enable, u32 inverse_color,
+ int blend_enable, u8 alpha_value,
+ enum mlc_rgbfmt rbgformat,
+ enum locksizesel lock_size_select)
+{
+ u32 layer_format;
+ u32 control_enb;
+ u32 alpha_argument;
+ u32 lock_size = (u32)(lock_size_select & 0x3);
+ u32 rgb0controlreg;
+ u32 regvalue;
+ register struct nx_mlc_register_set *pregister;
+
+ layer_format = nx_mlc_get_rgbformat(rbgformat);
+ pregister = __g_module_variables[module_index].pregister;
+
+ rgb0controlreg = readl(&pregister->mlcrgblayer[1].mlccontrol) & 0x10;
+ control_enb =
+ (u32)((grp3denable << 8) | (layer_enable << 5) |
+ (blend_enable << 2) | (inv_enable << 1) | tp_enable) & 0x127;
+ alpha_argument = (u32)(alpha_value & 0xf);
+ regvalue =
+ (u32)(((layer_format << 16) | control_enb | (lock_size << 12)) |
+ rgb0controlreg);
+ writel(regvalue, &pregister->mlcrgblayer[1].mlccontrol);
+ regvalue = (u32)((alpha_argument << 28) | transparency_color);
+ writel(regvalue, &pregister->mlcrgblayer[1].mlctpcolor);
+ regvalue = inverse_color;
+ writel(regvalue, &pregister->mlcrgblayer[1].mlcinvcolor);
+}
+
+void nx_mlc_set_rgb2layer_control_parameter(u32 module_index, int layer_enable,
+ int grp3denable, int tp_enable,
+ u32 transparency_color,
+ int inv_enable, u32 inverse_color,
+ int blend_enable, u8 alpha_value,
+ enum mlc_rgbfmt rbgformat,
+ enum locksizesel lock_size_select)
+{
+ u32 layer_format;
+ u32 control_enb;
+ u32 alpha_argument;
+ u32 lock_size = (u32)(lock_size_select & 0x3);
+ u32 rgb0controlreg;
+ u32 regvalue;
+ register struct nx_mlc_register_set *pregister;
+
+ layer_format = nx_mlc_get_rgbformat(rbgformat);
+ pregister = __g_module_variables[module_index].pregister;
+
+ rgb0controlreg = readl(&pregister->mlcrgblayer2.mlccontrol) & 0x10;
+ control_enb =
+ (u32)((grp3denable << 8) | (layer_enable << 5) |
+ (blend_enable << 2) | (inv_enable << 1) | tp_enable) & 0x127;
+ alpha_argument = (u32)(alpha_value & 0xf);
+ regvalue =
+ (u32)(((layer_format << 16) | control_enb | (lock_size << 12)) |
+ rgb0controlreg);
+ writel(regvalue, &pregister->mlcrgblayer2.mlccontrol);
+ regvalue = (u32)((alpha_argument << 28) | transparency_color);
+ writel(regvalue, &pregister->mlcrgblayer2.mlctpcolor);
+ regvalue = inverse_color;
+ writel(regvalue, &pregister->mlcrgblayer2.mlcinvcolor);
+}
+
+void nx_mlc_set_video_layer_control_parameter(u32 module_index,
+ int layer_enable, int tp_enable,
+ u32 transparency_color,
+ int inv_enable, u32 inverse_color,
+ int blend_enable, u8 alpha_value,
+ enum nx_mlc_yuvfmt yuvformat)
+{
+ u32 control_enb;
+ u32 alpha_argument;
+ u32 regvalue;
+ register struct nx_mlc_register_set *pregister;
+ u32 video_control_reg;
+
+ pregister = __g_module_variables[module_index].pregister;
+
+ video_control_reg = readl(&pregister->mlcvideolayer.mlccontrol);
+ control_enb =
+ (u32)((yuvformat) | (layer_enable << 5) | (blend_enable << 2) |
+ (inv_enable << 1) | tp_enable) & 0x30027;
+ alpha_argument = (u32)(alpha_value & 0xf);
+ regvalue = (u32)(control_enb | video_control_reg);
+ writel(regvalue, &pregister->mlcvideolayer.mlccontrol);
+ regvalue = (u32)((alpha_argument << 28) | transparency_color);
+ writel(regvalue, &pregister->mlcvideolayer.mlctpcolor);
+ regvalue = (u32)((alpha_argument << 28) | transparency_color);
+ writel(regvalue, &pregister->mlcvideolayer.mlcinvcolor);
+}
+
+void nx_mlc_set_srammode(u32 module_index, enum latyername layer_name,
+ enum srammode sram_mode)
+{
+ u32 control_reg_value;
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ switch (layer_name) {
+ case topmlc:
+ control_reg_value = readl(&pregister->mlccontrolt);
+ writel((u32)(control_reg_value | (sram_mode << 10)),
+ &pregister->mlccontrolt);
+ control_reg_value = 0;
+ break;
+ case rgb0:
+ control_reg_value =
+ readl(&pregister->mlcrgblayer[0].mlccontrol);
+ writel((u32)(control_reg_value | (sram_mode << 14)),
+ &pregister->mlcrgblayer[0].mlccontrol);
+ control_reg_value = 0;
+ break;
+ case rgb1:
+ control_reg_value =
+ readl(&pregister->mlcrgblayer[1].mlccontrol);
+ writel((u32)(control_reg_value | (sram_mode << 14)),
+ &pregister->mlcrgblayer[1].mlccontrol);
+ control_reg_value = 0;
+ break;
+ case rgb2:
+ control_reg_value = readl(&pregister->mlcrgblayer2.mlccontrol);
+ writel((u32)(control_reg_value | (sram_mode << 14)),
+ &pregister->mlcrgblayer2.mlccontrol);
+ control_reg_value = 0;
+ break;
+ case video:
+ control_reg_value = readl(&pregister->mlcvideolayer.mlccontrol);
+ writel((u32)(control_reg_value | (sram_mode << 14)),
+ &pregister->mlcvideolayer.mlccontrol);
+ control_reg_value = 0;
+ break;
+ default:
+ break;
+ }
+}
+
+void nx_mlc_set_layer_reg_finish(u32 module_index, enum latyername layer_name)
+{
+ u32 control_reg_value;
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+
+ switch (layer_name) {
+ case topmlc:
+ control_reg_value = readl(&pregister->mlccontrolt);
+ writel((u32)(control_reg_value | (1ul << 3)),
+ &pregister->mlccontrolt);
+ control_reg_value = 0;
+ break;
+ case rgb0:
+ control_reg_value =
+ readl(&pregister->mlcrgblayer[0].mlccontrol);
+ writel((u32)(control_reg_value | (1ul << 4)),
+ &pregister->mlcrgblayer[0].mlccontrol);
+ control_reg_value = 0;
+ break;
+ case rgb1:
+ control_reg_value =
+ readl(&pregister->mlcrgblayer[1].mlccontrol);
+ writel((u32)(control_reg_value | (1ul << 4)),
+ &pregister->mlcrgblayer[1].mlccontrol);
+ control_reg_value = 0;
+ break;
+ case rgb2:
+ control_reg_value = readl(&pregister->mlcrgblayer2.mlccontrol);
+ writel((u32)(control_reg_value | (1ul << 4)),
+ &pregister->mlcrgblayer2.mlccontrol);
+ control_reg_value = 0;
+ break;
+ case video:
+ control_reg_value = readl(&pregister->mlcvideolayer.mlccontrol);
+ writel((u32)(control_reg_value | (1ul << 4)),
+ &pregister->mlcvideolayer.mlccontrol);
+ control_reg_value = 0;
+ break;
+ default:
+ break;
+ }
+}
+
+void nx_mlc_set_video_layer_coordinate(u32 module_index, int vfilterenable,
+ int hfilterenable, int vfilterenable_c,
+ int hfilterenable_c,
+ u16 video_layer_with,
+ u16 video_layer_height, s16 left,
+ s16 right, s16 top,
+ s16 bottom)
+{
+ s32 source_width, source_height;
+ s32 destination_width;
+ s32 destination_height;
+ s32 hscale, vscale;
+ s32 hfilterenb, vfilterenb;
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ writel((s32)(((left & 0x0fff) << 16) | (right & 0x0fff)),
+ &pregister->mlcvideolayer.mlcleftright);
+ writel((s32)(((top & 0x0fff) << 16) | (bottom & 0x0fff)),
+ &pregister->mlcvideolayer.mlctopbottom);
+ source_width = (s32)(video_layer_with - 1);
+ source_height = (s32)(video_layer_height - 1);
+ destination_width = (s32)(right - left);
+ destination_height = (s32)(bottom - top);
+
+ hscale =
+ (s32)((source_width * (1ul << 11) + (destination_width / 2)) /
+ destination_width);
+ vscale =
+ (s32)((source_height * (1ul << 11) +
+ (destination_height / 2)) / destination_height);
+
+ hfilterenb = (u32)(((hfilterenable_c << 29) | (hfilterenable) << 28)) &
+ 0x30000000;
+ vfilterenb = (u32)(((vfilterenable_c << 29) | (vfilterenable) << 28)) &
+ 0x30000000;
+ writel((u32)(hfilterenb | (hscale & 0x00ffffff)),
+ &pregister->mlcvideolayer.mlchscale);
+ writel((u32)(vfilterenb | (vscale & 0x00ffffff)),
+ &pregister->mlcvideolayer.mlcvscale);
+}
+
+void nx_mlc_set_video_layer_filter_scale(u32 module_index, u32 hscale,
+ u32 vscale)
+{
+ register struct nx_mlc_register_set *pregister;
+ u32 mlchscale = 0;
+ u32 mlcvscale = 0;
+
+ pregister = __g_module_variables[module_index].pregister;
+ mlchscale = readl(&pregister->mlcvideolayer.mlchscale) & (~0x00ffffff);
+ mlcvscale = readl(&pregister->mlcvideolayer.mlcvscale) & (~0x00ffffff);
+
+ writel((u32)(mlchscale | (hscale & 0x00ffffff)),
+ &pregister->mlcvideolayer.mlchscale);
+ writel((u32)(mlcvscale | (vscale & 0x00ffffff)),
+ &pregister->mlcvideolayer.mlcvscale);
+}
+
+void nx_mlc_set_gamma_control_parameter(u32 module_index, int rgbgammaenb,
+ int yuvgammaenb, int yuvalphaarray,
+ int dither_enb)
+{
+ u32 register_data;
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ register_data = readl(&pregister->mlcgammacont);
+ register_data = (register_data & 0xf0c) |
+ ((yuvalphaarray << 5) | (yuvgammaenb << 4) |
+ (rgbgammaenb << 1) | (dither_enb << 0));
+ writel(register_data, &pregister->mlcgammacont);
+}
+
+void nx_mlc_set_layer_alpha256(u32 module_index, u32 layer, u32 alpha)
+{
+ u32 register_data;
+ register struct nx_mlc_register_set *pregister;
+
+ if (alpha < 0)
+ alpha = 0;
+ if (alpha > 255)
+ alpha = 255;
+
+ pregister = __g_module_variables[module_index].pregister;
+ if (layer == 0) {
+ register_data =
+ readl(&pregister->mlcrgblayer[0].mlctpcolor) & 0x00ffffff;
+ register_data = register_data | (alpha << 24);
+ writel(register_data, &pregister->mlcrgblayer[0].mlctpcolor);
+ } else if (layer == 1) {
+ register_data =
+ readl(&pregister->mlcrgblayer[1].mlctpcolor) & 0x00ffffff;
+ register_data = register_data | (alpha << 24);
+ writel(register_data, &pregister->mlcrgblayer[1].mlctpcolor);
+ } else if (layer == 2) {
+ register_data =
+ readl(&pregister->mlcrgblayer[1].mlctpcolor) & 0x00ffffff;
+ register_data = register_data | (alpha << 24);
+ writel(register_data, &pregister->mlcrgblayer2.mlctpcolor);
+ } else {
+ register_data =
+ readl(&pregister->mlcvideolayer.mlctpcolor) & 0x00ffffff;
+ register_data = register_data | (alpha << 24);
+ writel(register_data, &pregister->mlcvideolayer.mlctpcolor);
+ }
+}
+
+int nx_mlc_is_under_flow(u32 module_index)
+{
+ const u32 underflow_pend_pos = 31;
+ const u32 underflow_pend_mask = 1ul << underflow_pend_pos;
+
+ return (int)((__g_module_variables[module_index].pregister->mlccontrolt
+ & underflow_pend_mask) >> underflow_pend_pos);
+}
+
+void nx_mlc_set_gamma_table(u32 module_index, int enb,
+ struct nx_mlc_gamma_table_parameter *p_gammatable)
+{
+ register struct nx_mlc_register_set *pregister;
+ u32 i, regval = 0;
+
+ pregister = __g_module_variables[module_index].pregister;
+ if (enb == 1) {
+ regval = readl(&pregister->mlcgammacont);
+
+ regval = (1 << 11) | (1 << 9) | (1 << 3);
+ writel(regval, &pregister->mlcgammacont);
+
+ regval = regval | (1 << 10) | (1 << 8) | (1 << 2);
+ writel(regval, &pregister->mlcgammacont);
+
+ for (i = 0; i < 256; i++) {
+ nx_mlc_set_rgblayer_rgamma_table(module_index, i,
+ p_gammatable->r_table[i]);
+ nx_mlc_set_rgblayer_ggamma_table(module_index, i,
+ p_gammatable->g_table[i]);
+ nx_mlc_set_rgblayer_bgamma_table(module_index, i,
+ p_gammatable->b_table[i]);
+ }
+
+ regval = regval | (p_gammatable->alphaselect << 5) |
+ (p_gammatable->yuvgammaenb << 4 |
+ p_gammatable->allgammaenb << 4) |
+ (p_gammatable->rgbgammaenb << 1 |
+ p_gammatable->allgammaenb << 1) |
+ (p_gammatable->ditherenb << 1);
+ writel(regval, &pregister->mlcgammacont);
+ } else {
+ regval = regval & ~(1 << 10) & ~(1 << 8) & ~(1 << 2);
+ writel(regval, &pregister->mlcgammacont);
+
+ regval = regval & ~(1 << 11) & ~(1 << 9) & ~(1 << 3);
+ writel(regval, &pregister->mlcgammacont);
+ }
+}
+
+void nx_mlc_get_rgblayer_stride(u32 module_index, u32 layer, s32 *hstride,
+ s32 *vstride)
+{
+ unsigned int hs, vs;
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+
+ hs = readl(&pregister->mlcrgblayer[layer].mlchstride);
+ vs = readl(&pregister->mlcrgblayer[layer].mlcvstride);
+
+ if (hstride)
+ *(s32 *)hstride = hs;
+
+ if (vstride)
+ *(s32 *)vstride = vs;
+}
+
+void nx_mlc_get_rgblayer_address(u32 module_index, u32 layer,
+ u32 *phys_address)
+{
+ u32 pa;
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ pa = readl(&pregister->mlcrgblayer[layer].mlcaddress);
+
+ if (phys_address)
+ *(u32 *)phys_address = pa;
+}
+
+void nx_mlc_get_position(u32 module_index, u32 layer, int *left, int *top,
+ int *right, int *bottom)
+{
+ int lr, tb;
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+
+ lr = readl(&pregister->mlcrgblayer[layer].mlcleftright);
+ tb = readl(&pregister->mlcrgblayer[layer].mlctopbottom);
+
+ if (left)
+ *(int *)left = ((lr >> 16) & 0xFFUL);
+
+ if (top)
+ *(int *)top = ((tb >> 16) & 0xFFUL);
+
+ if (right)
+ *(int *)right = ((lr >> 0) & 0xFFUL);
+
+ if (bottom)
+ *(int *)bottom = ((tb >> 0) & 0xFFUL);
+}
+
+void nx_mlc_get_video_layer_address_yuyv(u32 module_index, u32 *address,
+ u32 *stride)
+{
+ u32 a, s;
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ a = readl(&pregister->mlcvideolayer.mlcaddress);
+ s = readl(&pregister->mlcvideolayer.mlcvstride);
+
+ if (address)
+ *(u32 *)address = a;
+
+ if (stride)
+ *(u32 *)stride = s;
+}
+
+void nx_mlc_get_video_layer_address(u32 module_index, u32 *lu_address,
+ u32 *cb_address, u32 *cr_address)
+{
+ u32 lua, cba, cra;
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+
+ lua = readl(&pregister->mlcvideolayer.mlcaddress);
+ cba = readl(&pregister->mlcvideolayer.mlcaddresscb);
+ cra = readl(&pregister->mlcvideolayer.mlcaddresscr);
+
+ if (lu_address)
+ *(u32 *)lu_address = lua;
+
+ if (cb_address)
+ *(u32 *)cb_address = cba;
+
+ if (cr_address)
+ *(u32 *)cr_address = cra;
+}
+
+void nx_mlc_get_video_layer_stride(u32 module_index, u32 *lu_stride,
+ u32 *cb_stride, u32 *cr_stride)
+{
+ u32 lus, cbs, crs;
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+
+ lus = readl(&pregister->mlcvideolayer.mlcvstride);
+ cbs = readl(&pregister->mlcvideolayer.mlcvstridecb);
+ crs = readl(&pregister->mlcvideolayer.mlcvstridecr);
+
+ if (lu_stride)
+ *(u32 *)lu_stride = lus;
+
+ if (cb_stride)
+ *(u32 *)cb_stride = cbs;
+
+ if (cr_stride)
+ *(u32 *)cr_stride = crs;
+}
+
+void nx_mlc_get_video_position(u32 module_index, int *left, int *top,
+ int *right, int *bottom)
+{
+ int lr, tb;
+ register struct nx_mlc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+
+ lr = readl(&pregister->mlcvideolayer.mlcleftright);
+ tb = readl(&pregister->mlcvideolayer.mlctopbottom);
+
+ if (left)
+ *(int *)left = ((lr >> 16) & 0xFFUL);
+
+ if (top)
+ *(int *)top = ((tb >> 16) & 0xFFUL);
+
+ if (right)
+ *(int *)right = ((lr >> 0) & 0xFFUL);
+
+ if (bottom)
+ *(int *)bottom = ((tb >> 0) & 0xFFUL);
+}
diff --git a/drivers/video/nexell/soc/s5pxx18_soc_mlc.h b/drivers/video/nexell/soc/s5pxx18_soc_mlc.h
new file mode 100644
index 0000000..77ceca6
--- /dev/null
+++ b/drivers/video/nexell/soc/s5pxx18_soc_mlc.h
@@ -0,0 +1,429 @@
+/* SPDX-License-Identifier: GPL-2.0+
+ *
+ * Copyright (C) 2016 Nexell Co., Ltd.
+ *
+ * Author: junghyun, kim <jhkim@nexell.co.kr>
+ */
+
+#ifndef _S5PXX18_SOC_MLC_H_
+#define _S5PXX18_SOC_MLC_H_
+
+#include "s5pxx18_soc_disptype.h"
+
+#define NUMBER_OF_MLC_MODULE 2
+#define PHY_BASEADDR_MLC0 0xC0102000
+#define PHY_BASEADDR_MLC1 0xC0102400
+
+#define PHY_BASEADDR_MLC_LIST \
+ { PHY_BASEADDR_MLC0, PHY_BASEADDR_MLC1 }
+
+struct nx_mlc_register_set {
+ u32 mlccontrolt;
+ u32 mlcscreensize;
+ u32 mlcbgcolor;
+ struct {
+ u32 mlcleftright;
+ u32 mlctopbottom;
+ u32 mlcinvalidleftright0;
+ u32 mlcinvalidtopbottom0;
+ u32 mlcinvalidleftright1;
+ u32 mlcinvalidtopbottom1;
+ u32 mlccontrol;
+ s32 mlchstride;
+ s32 mlcvstride;
+ u32 mlctpcolor;
+ u32 mlcinvcolor;
+ u32 mlcaddress;
+ u32 __reserved0;
+ } mlcrgblayer[2];
+ struct {
+ u32 mlcleftright;
+ u32 mlctopbottom;
+ u32 mlccontrol;
+ u32 mlcvstride;
+ u32 mlctpcolor;
+
+ u32 mlcinvcolor;
+ u32 mlcaddress;
+ u32 mlcaddresscb;
+ u32 mlcaddresscr;
+ s32 mlcvstridecb;
+ s32 mlcvstridecr;
+ u32 mlchscale;
+ u32 mlcvscale;
+ u32 mlcluenh;
+ u32 mlcchenh[4];
+ } mlcvideolayer;
+ struct {
+ u32 mlcleftright;
+ u32 mlctopbottom;
+ u32 mlcinvalidleftright0;
+ u32 mlcinvalidtopbottom0;
+ u32 mlcinvalidleftright1;
+ u32 mlcinvalidtopbottom1;
+ u32 mlccontrol;
+ s32 mlchstride;
+ s32 mlcvstride;
+ u32 mlctpcolor;
+ u32 mlcinvcolor;
+ u32 mlcaddress;
+ } mlcrgblayer2;
+ u32 mlcpaletetable2;
+ u32 mlcgammacont;
+ u32 mlcrgammatablewrite;
+ u32 mlcggammatablewrite;
+ u32 mlcbgammatablewrite;
+ u32 yuvlayergammatable_red;
+ u32 yuvlayergammatable_green;
+ u32 yuvlayergammatable_blue;
+
+ u32 dimctrl;
+ u32 dimlut0;
+ u32 dimlut1;
+ u32 dimbusyflag;
+ u32 dimprdarrr0;
+ u32 dimprdarrr1;
+ u32 dimram0rddata;
+ u32 dimram1rddata;
+ u32 __reserved2[(0x3c0 - 0x12c) / 4];
+ u32 mlcclkenb;
+};
+
+enum nx_mlc_priority {
+ nx_mlc_priority_videofirst = 0ul,
+ nx_mlc_priority_videosecond = 1ul,
+ nx_mlc_priority_videothird = 2ul,
+ nx_mlc_priority_videofourth = 3ul
+};
+
+enum nx_mlc_rgbfmt {
+ nx_mlc_rgbfmt_r5g6b5 = 0x44320000ul,
+ nx_mlc_rgbfmt_b5g6r5 = 0xc4320000ul,
+ nx_mlc_rgbfmt_x1r5g5b5 = 0x43420000ul,
+ nx_mlc_rgbfmt_x1b5g5r5 = 0xc3420000ul,
+ nx_mlc_rgbfmt_x4r4g4b4 = 0x42110000ul,
+ nx_mlc_rgbfmt_x4b4g4r4 = 0xc2110000ul,
+ nx_mlc_rgbfmt_x8r3g3b2 = 0x41200000ul,
+ nx_mlc_rgbfmt_x8b3g3r2 = 0xc1200000ul,
+ nx_mlc_rgbfmt_a1r5g5b5 = 0x33420000ul,
+ nx_mlc_rgbfmt_a1b5g5r5 = 0xb3420000ul,
+ nx_mlc_rgbfmt_a4r4g4b4 = 0x22110000ul,
+ nx_mlc_rgbfmt_a4b4g4r4 = 0xa2110000ul,
+ nx_mlc_rgbfmt_a8r3g3b2 = 0x11200000ul,
+ nx_mlc_rgbfmt_a8b3g3r2 = 0x91200000ul,
+ nx_mlc_rgbfmt_r8g8b8 = 0x46530000ul,
+ nx_mlc_rgbfmt_b8g8r8 = 0xc6530000ul,
+ nx_mlc_rgbfmt_x8r8g8b8 = 0x46530000ul,
+ nx_mlc_rgbfmt_x8b8g8r8 = 0xc6530000ul,
+ nx_mlc_rgbfmt_a8r8g8b8 = 0x06530000ul,
+ nx_mlc_rgbfmt_a8b8g8r8 = 0x86530000ul
+};
+
+enum nx_mlc_yuvfmt {
+ nx_mlc_yuvfmt_420 = 0ul << 16,
+ nx_mlc_yuvfmt_422 = 1ul << 16,
+ nx_mlc_yuvfmt_444 = 3ul << 16,
+ nx_mlc_yuvfmt_yuyv = 2ul << 16,
+ nx_mlc_yuvfmt_422_cbcr = 4ul << 16,
+ nx_mlc_yuvfmt_420_cbcr = 5ul << 16,
+};
+
+#ifdef __arm
+#pragma diag_default 66
+#endif
+
+int nx_mlc_initialize(void);
+u32 nx_mlc_get_number_of_module(void);
+u32 nx_mlc_get_physical_address(u32 module_index);
+u32 nx_mlc_get_size_of_register_set(void);
+void nx_mlc_set_base_address(u32 module_index, void *base_address);
+void *nx_mlc_get_base_address(u32 module_index);
+int nx_mlc_open_module(u32 module_index);
+int nx_mlc_close_module(u32 module_index);
+int nx_mlc_check_busy(u32 module_index);
+int nx_mlc_can_power_down(u32 module_index);
+void nx_mlc_set_clock_pclk_mode(u32 module_index, enum nx_pclkmode mode);
+enum nx_pclkmode nx_mlc_get_clock_pclk_mode(u32 module_index);
+void nx_mlc_set_clock_bclk_mode(u32 module_index, enum nx_bclkmode mode);
+enum nx_bclkmode nx_mlc_get_clock_bclk_mode(u32 module_index);
+
+void nx_mlc_set_top_power_mode(u32 module_index, int bpower);
+int nx_mlc_get_top_power_mode(u32 module_index);
+void nx_mlc_set_top_sleep_mode(u32 module_index, int bsleep);
+int nx_mlc_get_top_sleep_mode(u32 module_index);
+void nx_mlc_set_top_dirty_flag(u32 module_index);
+int nx_mlc_get_top_dirty_flag(u32 module_index);
+void nx_mlc_set_mlc_enable(u32 module_index, int benb);
+int nx_mlc_get_mlc_enable(u32 module_index);
+void nx_mlc_set_field_enable(u32 module_index, int benb);
+int nx_mlc_get_field_enable(u32 module_index);
+void nx_mlc_set_layer_priority(u32 module_index,
+ enum nx_mlc_priority priority);
+void nx_mlc_set_screen_size(u32 module_index, u32 width, u32 height);
+void nx_mlc_get_screen_size(u32 module_index, u32 *pwidth,
+ u32 *pheight);
+void nx_mlc_set_background(u32 module_index, u32 color);
+
+void nx_mlc_set_dirty_flag(u32 module_index, u32 layer);
+int nx_mlc_get_dirty_flag(u32 module_index, u32 layer);
+void nx_mlc_set_layer_enable(u32 module_index, u32 layer, int benb);
+int nx_mlc_get_layer_enable(u32 module_index, u32 layer);
+void nx_mlc_set_lock_size(u32 module_index, u32 layer, u32 locksize);
+void nx_mlc_set_alpha_blending(u32 module_index, u32 layer, int benb,
+ u32 alpha);
+void nx_mlc_set_transparency(u32 module_index, u32 layer, int benb,
+ u32 color);
+void nx_mlc_set_color_inversion(u32 module_index, u32 layer, int benb,
+ u32 color);
+u32 nx_mlc_get_extended_color(u32 module_index, u32 color,
+ enum nx_mlc_rgbfmt format);
+void nx_mlc_set_format_rgb(u32 module_index, u32 layer,
+ enum nx_mlc_rgbfmt format);
+void nx_mlc_set_format_yuv(u32 module_index, enum nx_mlc_yuvfmt format);
+void nx_mlc_set_position(u32 module_index, u32 layer, s32 sx,
+ s32 sy, s32 ex, s32 ey);
+void nx_mlc_set_dither_enable_when_using_gamma(u32 module_index,
+ int benable);
+int nx_mlc_get_dither_enable_when_using_gamma(u32 module_index);
+void nx_mlc_set_gamma_priority(u32 module_index, int bvideolayer);
+int nx_mlc_get_gamma_priority(u32 module_index);
+
+void nx_mlc_set_rgblayer_invalid_position(u32 module_index, u32 layer,
+ u32 region, s32 sx,
+ s32 sy, s32 ex,
+ s32 ey, int benb);
+void nx_mlc_set_rgblayer_stride(u32 module_index, u32 layer,
+ s32 hstride, s32 vstride);
+void nx_mlc_set_rgblayer_address(u32 module_index, u32 layer, u32 addr);
+void nx_mlc_set_rgblayer_gama_table_power_mode(u32 module_index,
+ int bred, int bgreen,
+ int bblue);
+void nx_mlc_get_rgblayer_gama_table_power_mode(u32 module_index,
+ int *pbred, int *pbgreen,
+ int *pbblue);
+void nx_mlc_set_rgblayer_gama_table_sleep_mode(u32 module_index,
+ int bred, int bgreen,
+ int bblue);
+void nx_mlc_get_rgblayer_gama_table_sleep_mode(u32 module_index,
+ int *pbred, int *pbgreen,
+ int *pbblue);
+void nx_mlc_set_rgblayer_rgamma_table(u32 module_index, u32 dwaddress,
+ u32 dwdata);
+void nx_mlc_set_rgblayer_ggamma_table(u32 module_index, u32 dwaddress,
+ u32 dwdata);
+void nx_mlc_set_rgblayer_bgamma_table(u32 module_index, u32 dwaddress,
+ u32 dwdata);
+void nx_mlc_set_rgblayer_gamma_enable(u32 module_index, int benable);
+int nx_mlc_get_rgblayer_gamma_enable(u32 module_index);
+
+void nx_mlc_set_video_layer_stride(u32 module_index, s32 lu_stride,
+ s32 cb_stride, s32 cr_stride);
+void nx_mlc_set_video_layer_address(u32 module_index, u32 lu_addr,
+ u32 cb_addr, u32 cr_addr);
+void nx_mlc_set_video_layer_address_yuyv(u32 module_index, u32 addr,
+ s32 stride);
+void nx_mlc_set_video_layer_scale_factor(u32 module_index, u32 hscale,
+ u32 vscale, int bhlumaenb,
+ int bhchromaenb, int bvlumaenb,
+ int bvchromaenb);
+void nx_mlc_set_video_layer_scale_filter(u32 module_index, int bhlumaenb,
+ int bhchromaenb, int bvlumaenb,
+ int bvchromaenb);
+void nx_mlc_get_video_layer_scale_filter(u32 module_index,
+ int *bhlumaenb,
+ int *bhchromaenb,
+ int *bvlumaenb,
+ int *bvchromaenb);
+void nx_mlc_set_video_layer_scale(u32 module_index, u32 sw, u32 sh,
+ u32 dw, u32 dh, int bhlumaenb,
+ int bhchromaenb, int bvlumaenb,
+ int bvchromaenb);
+void nx_mlc_set_video_layer_luma_enhance(u32 module_index, u32 contrast,
+ s32 brightness);
+void nx_mlc_set_video_layer_chroma_enhance(u32 module_index,
+ u32 quadrant, s32 cb_a,
+ s32 cb_b, s32 cr_a,
+ s32 cr_b);
+void nx_mlc_set_video_layer_line_buffer_power_mode(u32 module_index,
+ int benable);
+int nx_mlc_get_video_layer_line_buffer_power_mode(u32 module_index);
+void nx_mlc_set_video_layer_line_buffer_sleep_mode(u32 module_index,
+ int benable);
+int nx_mlc_get_video_layer_line_buffer_sleep_mode(u32 module_index);
+void nx_mlc_set_video_layer_gamma_enable(u32 module_index, int benable);
+int nx_mlc_get_video_layer_gamma_enable(u32 module_index);
+
+void nx_mlc_set_gamma_table_poweroff(u32 module_index, int enb);
+
+enum mlc_rgbfmt {
+ rgbfmt_r5g6b5 = 0,
+ rgbfmt_x1r5g5b5 = 1,
+ rgbfmt_x4r4g4b4 = 2,
+ rgbfmt_x8r3g3b2 = 3,
+ rgbfmt_x8l8 = 4,
+ rgbfmt_l16 = 5,
+ rgbfmt_a1r5g5b5 = 6,
+ rgbfmt_a4r4g4b4 = 7,
+ rgbfmt_a8r3g3b2 = 8,
+ rgbfmt_a8l8 = 9,
+ rgbfmt_r8g8b8 = 10,
+ rgbfmt_x8r8g8b8 = 11,
+ rgbfmt_a8r8g8b8 = 12,
+ rgbfmt_g8r8_g8b8 = 13,
+ rgbfmt_r8g8_b8g8 = 14,
+ rgbfmt_b5g6r5 = 15,
+ rgbfmt_x1b5g5r5 = 16,
+ rgbfmt_x4b4g4r4 = 17,
+ rgbfmt_x8b3g3r2 = 18,
+ rgbfmt_a1b5g5r5 = 19,
+ rgbfmt_a4b4g4r4 = 20,
+ rgbfmt_a8b3g3r2 = 21,
+ rgbfmt_b8g8r8 = 22,
+ rgbfmt_x8b8g8r8 = 23,
+ rgbfmt_a8b8g8r8 = 24,
+ rgbfmt_g8b8_g8r8 = 25,
+ rgbfmt_b8g8_r8g8 = 26,
+ rgbfmt_pataletb = 27
+};
+
+enum latyername {
+ topmlc = 0,
+ rgb0 = 1,
+ rgb1 = 2,
+ rgb2 = 3,
+ video = 4
+};
+
+enum srammode {
+ poweroff = 0,
+ sleepmode = 2,
+ run = 3
+};
+
+enum locksizesel {
+ locksize_4 = 0,
+ locksize_8 = 1,
+ locksize_16 = 2
+};
+
+enum g3daddrchangeallowed {
+ prim = 0,
+ secon = 1,
+ primorsecon = 2,
+ primandsecon = 3
+};
+
+void nx_mlc_set_mlctop_control_parameter(u32 module_index,
+ int field_enable, int mlcenable,
+ u8 priority,
+ enum g3daddrchangeallowed
+ g3daddr_change_allowed);
+void nx_mlc_set_rgb0layer_control_parameter(u32 module_index,
+ int layer_enable,
+ int grp3denable,
+ int tp_enable,
+ u32 transparency_color,
+ int inv_enable,
+ u32 inverse_color,
+ int blend_enable,
+ u8 alpha_value,
+ enum mlc_rgbfmt rbgformat,
+ enum locksizesel
+ lock_size_select);
+
+u32 nx_mlc_get_rgbformat(enum mlc_rgbfmt rbgformat);
+void nx_mlc_set_rgb1layer_control_parameter(u32 module_index,
+ int layer_enable,
+ int grp3denable,
+ int tp_enable,
+ u32 transparency_color,
+ int inv_enable,
+ u32 inverse_color,
+ int blend_enable,
+ u8 alpha_value,
+ enum mlc_rgbfmt rbgformat,
+ enum locksizesel
+ lock_size_select);
+
+void nx_mlc_set_rgb2layer_control_parameter(u32 module_index,
+ int layer_enable,
+ int grp3denable,
+ int tp_enable,
+ u32 transparency_color,
+ int inv_enable,
+ u32 inverse_color,
+ int blend_enable,
+ u8 alpha_value,
+ enum mlc_rgbfmt rbgformat,
+ enum locksizesel
+ lock_size_select);
+
+void nx_mlc_set_video_layer_control_parameter(u32 module_index,
+ int layer_enable,
+ int tp_enable,
+ u32 transparency_color,
+ int inv_enable,
+ u32 inverse_color,
+ int blend_enable,
+ u8 alpha_value,
+ enum nx_mlc_yuvfmt
+ yuvformat);
+
+void nx_mlc_set_srammode(u32 module_index, enum latyername layer_name,
+ enum srammode sram_mode);
+
+void nx_mlc_set_layer_reg_finish(u32 module_index,
+ enum latyername layer_name);
+
+void nx_mlc_set_video_layer_coordinate(u32 module_index,
+ int vfilterenable,
+ int hfilterenable,
+ int vfilterenable_c,
+ int hfilterenable_c,
+ u16 video_layer_with,
+ u16 video_layer_height,
+ s16 left, s16 right,
+ s16 top, s16 bottom);
+
+void nx_mlc_set_video_layer_filter_scale(u32 module_index, u32 hscale,
+ u32 vscale);
+void nx_mlcsetgammasrammode(u32 module_index, enum srammode sram_mode);
+void nx_mlc_set_gamma_control_parameter(u32 module_index,
+ int rgbgammaenb, int yuvgammaenb,
+ int yuvalphaarray,
+ int dither_enb);
+
+void nx_mlc_set_layer_alpha256(u32 module_index, u32 layer, u32 alpha);
+int nx_mlc_is_under_flow(u32 module_index);
+
+struct nx_mlc_gamma_table_parameter {
+ u32 r_table[256];
+ u32 g_table[256];
+ u32 b_table[256];
+ u32 ditherenb;
+ u32 alphaselect;
+ u32 yuvgammaenb;
+ u32 rgbgammaenb;
+ u32 allgammaenb;
+};
+
+void nx_mlc_set_gamma_table(u32 module_index, int enb,
+ struct nx_mlc_gamma_table_parameter *p_gammatable);
+void nx_mlc_get_rgblayer_stride(u32 module_index, u32 layer,
+ s32 *hstride, s32 *vstride);
+void nx_mlc_get_rgblayer_address(u32 module_index, u32 layer,
+ u32 *phys_address);
+void nx_mlc_get_position(u32 module_index, u32 layer, int *left,
+ int *top, int *right, int *bottom);
+void nx_mlc_get_video_layer_address_yuyv(u32 module_index, u32 *address,
+ u32 *stride);
+void nx_mlc_get_video_layer_address(u32 module_index, u32 *lu_address,
+ u32 *cb_address, u32 *cr_address);
+void nx_mlc_get_video_layer_stride(u32 module_index, u32 *lu_stride,
+ u32 *cb_stride, u32 *cr_stride);
+void nx_mlc_get_video_layer_stride(u32 module_index, u32 *lu_stride,
+ u32 *cb_stride, u32 *cr_stride);
+void nx_mlc_get_video_position(u32 module_index, int *left, int *top,
+ int *right, int *bottom);
+
+#endif
--
1.9.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH 06/10] video: add nexell video driver (soc: lvds, hdmi)
2020-02-03 19:39 [RFC PATCH 00/10] arm: add support for SoC S5P4418 Stefan Bosch
` (4 preceding siblings ...)
2020-02-03 20:43 ` [RFC PATCH 05/10] video: add nexell video driver (soc: mlc, mipi) Stefan Bosch
@ 2020-02-03 20:44 ` Stefan Bosch
2020-02-03 20:45 ` [RFC PATCH 07/10] video: add nexell video driver (soc: dpc, makefile) Stefan Bosch
` (5 subsequent siblings)
11 siblings, 0 replies; 19+ messages in thread
From: Stefan Bosch @ 2020-02-03 20:44 UTC (permalink / raw)
To: u-boot
Low level functions for LVDS and HDMI display interfaces.
Signed-off-by: Stefan Bosch <stefan_b@posteo.net>
---
drivers/video/nexell/soc/s5pxx18_soc_hdmi.c | 50 +++
drivers/video/nexell/soc/s5pxx18_soc_hdmi.h | 488 ++++++++++++++++++++++++++++
drivers/video/nexell/soc/s5pxx18_soc_lvds.c | 278 ++++++++++++++++
drivers/video/nexell/soc/s5pxx18_soc_lvds.h | 83 +++++
4 files changed, 899 insertions(+)
create mode 100644 drivers/video/nexell/soc/s5pxx18_soc_hdmi.c
create mode 100644 drivers/video/nexell/soc/s5pxx18_soc_hdmi.h
create mode 100644 drivers/video/nexell/soc/s5pxx18_soc_lvds.c
create mode 100644 drivers/video/nexell/soc/s5pxx18_soc_lvds.h
diff --git a/drivers/video/nexell/soc/s5pxx18_soc_hdmi.c b/drivers/video/nexell/soc/s5pxx18_soc_hdmi.c
new file mode 100644
index 0000000..7b8be7e
--- /dev/null
+++ b/drivers/video/nexell/soc/s5pxx18_soc_hdmi.c
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Nexell Co., Ltd.
+ *
+ * Author: junghyun, kim <jhkim@nexell.co.kr>
+ */
+
+#include <linux/types.h>
+#include <linux/io.h>
+
+#include "s5pxx18_soc_hdmi.h"
+
+static u32 *hdmi_base_addr;
+
+u32 nx_hdmi_get_reg(u32 module_index, u32 offset)
+{
+ u32 *reg_addr;
+ u32 regvalue;
+
+ reg_addr = hdmi_base_addr + (offset / sizeof(u32));
+ regvalue = readl((u32 *)reg_addr);
+
+ return regvalue;
+}
+
+void nx_hdmi_set_reg(u32 module_index, u32 offset, u32 regvalue)
+{
+ s64 offset_new = (s64)((int32_t)offset);
+ u32 *reg_addr;
+
+ reg_addr = hdmi_base_addr + (offset_new / sizeof(u32));
+ writel(regvalue, (u32 *)reg_addr);
+}
+
+void nx_hdmi_set_base_address(u32 module_index, void *base_address)
+{
+ hdmi_base_addr = (u32 *)base_address;
+}
+
+void *nx_hdmi_get_base_address(u32 module_index)
+{
+ return (u32 *)hdmi_base_addr;
+}
+
+u32 nx_hdmi_get_physical_address(u32 module_index)
+{
+ const u32 physical_addr[] = PHY_BASEADDR_HDMI_LIST;
+
+ return physical_addr[module_index];
+}
diff --git a/drivers/video/nexell/soc/s5pxx18_soc_hdmi.h b/drivers/video/nexell/soc/s5pxx18_soc_hdmi.h
new file mode 100644
index 0000000..a4c5ab5
--- /dev/null
+++ b/drivers/video/nexell/soc/s5pxx18_soc_hdmi.h
@@ -0,0 +1,488 @@
+/* SPDX-License-Identifier: GPL-2.0+
+ *
+ * Copyright (C) 2016 Nexell Co., Ltd.
+ *
+ * Author: junghyun, kim <jhkim@nexell.co.kr>
+ */
+
+#ifndef _S5PXX18_SOC_HDMI_H_
+#define _S5PXX18_SOC_HDMI_H_
+
+#include "s5pxx18_soc_disptop.h"
+
+#define PHY_BASEADDR_HDMI_PHY_MODULE 0xc00f0000
+#define PHY_BASEADDR_HDMI_LIST \
+ { PHY_BASEADDR_HDMI_MODULE }
+
+#define HDMI_LINK_INTC_CON_0 (HDMI_ADDR_OFFSET + 0x00000000)
+#define HDMI_LINK_INTC_FLAG_0 (HDMI_ADDR_OFFSET + 0x00000004)
+#define HDMI_LINK_AESKEY_VALID (HDMI_ADDR_OFFSET + 0x00000008)
+#define HDMI_LINK_HPD (HDMI_ADDR_OFFSET + 0x0000000C)
+#define HDMI_LINK_INTC_CON_1 (HDMI_ADDR_OFFSET + 0x00000010)
+#define HDMI_LINK_INTC_FLAG_1 (HDMI_ADDR_OFFSET + 0x00000014)
+#define HDMI_LINK_PHY_STATUS_0 (HDMI_ADDR_OFFSET + 0x00000020)
+#define HDMI_LINK_PHY_STATUS_CMU (HDMI_ADDR_OFFSET + 0x00000024)
+#define HDMI_LINK_PHY_STATUS_PLL (HDMI_ADDR_OFFSET + 0x00000028)
+#define HDMI_LINK_PHY_CON_0 (HDMI_ADDR_OFFSET + 0x00000030)
+#define HDMI_LINK_HPD_CTRL (HDMI_ADDR_OFFSET + 0x00000040)
+#define HDMI_LINK_HPD_STATUS (HDMI_ADDR_OFFSET + 0x00000044)
+#define HDMI_LINK_HPD_TH_x (HDMI_ADDR_OFFSET + 0x00000050)
+
+#define HDMI_LINK_HDMI_CON_0 (HDMI_ADDR_OFFSET + 0x00010000)
+#define HDMI_LINK_HDMI_CON_1 (HDMI_ADDR_OFFSET + 0x00010004)
+#define HDMI_LINK_HDMI_CON_2 (HDMI_ADDR_OFFSET + 0x00010008)
+#define HDMI_LINK_STATUS (HDMI_ADDR_OFFSET + 0x00010010)
+#define HDMI_LINK_STATUS_EN (HDMI_ADDR_OFFSET + 0x00010020)
+
+#define HDMI_LINK_HDCP_SHA1_REN0 (HDMI_ADDR_OFFSET + 0x00010024)
+#define HDMI_LINK_HDCP_SHA1_REN1 (HDMI_ADDR_OFFSET + 0x00010028)
+
+#define HDMI_LINK_MODE_SEL (HDMI_ADDR_OFFSET + 0x00010040)
+#define HDMI_LINK_ENC_EN (HDMI_ADDR_OFFSET + 0x00010044)
+#define HDMI_LINK_HDMI_YMAX (HDMI_ADDR_OFFSET + 0x00010060)
+#define HDMI_LINK_HDMI_YMIN (HDMI_ADDR_OFFSET + 0x00010064)
+#define HDMI_LINK_HDMI_CMAX (HDMI_ADDR_OFFSET + 0x00010068)
+#define HDMI_LINK_HDMI_CMIN (HDMI_ADDR_OFFSET + 0x0001006C)
+#define HDMI_LINK_H_BLANK_0 (HDMI_ADDR_OFFSET + 0x000100A0)
+#define HDMI_LINK_H_BLANK_1 (HDMI_ADDR_OFFSET + 0x000100A4)
+#define HDMI_LINK_V2_BLANK_0 (HDMI_ADDR_OFFSET + 0x000100B0)
+#define HDMI_LINK_V2_BLANK_1 (HDMI_ADDR_OFFSET + 0x000100B4)
+#define HDMI_LINK_V1_BLANK_0 (HDMI_ADDR_OFFSET + 0x000100B8)
+#define HDMI_LINK_V1_BLANK_1 (HDMI_ADDR_OFFSET + 0x000100BC)
+#define HDMI_LINK_V_LINE_0 (HDMI_ADDR_OFFSET + 0x000100C0)
+#define HDMI_LINK_V_LINE_1 (HDMI_ADDR_OFFSET + 0x000100C4)
+#define HDMI_LINK_H_LINE_0 (HDMI_ADDR_OFFSET + 0x000100C8)
+#define HDMI_LINK_H_LINE_1 (HDMI_ADDR_OFFSET + 0x000100CC)
+#define HDMI_LINK_HSYNC_POL (HDMI_ADDR_OFFSET + 0x000100E0)
+#define HDMI_LINK_VSYNC_POL (HDMI_ADDR_OFFSET + 0x000100E4)
+#define HDMI_LINK_INT_PRO_MODE (HDMI_ADDR_OFFSET + 0x000100E8)
+#define HDMI_LINK_SEND_START_0 (HDMI_ADDR_OFFSET + 0x000100F0)
+#define HDMI_LINK_SEND_START_1 (HDMI_ADDR_OFFSET + 0x000100F4)
+#define HDMI_LINK_SEND_END_0 (HDMI_ADDR_OFFSET + 0x00010100)
+#define HDMI_LINK_SEND_END_1 (HDMI_ADDR_OFFSET + 0x00010104)
+#define HDMI_LINK_SEND_END_2 (HDMI_ADDR_OFFSET + 0x00010108)
+#define HDMI_LINK_V_BLANK_F0_0 (HDMI_ADDR_OFFSET + 0x00010110)
+#define HDMI_LINK_V_BLANK_F0_1 (HDMI_ADDR_OFFSET + 0x00010114)
+#define HDMI_LINK_V_BLANK_F1_0 (HDMI_ADDR_OFFSET + 0x00010118)
+#define HDMI_LINK_V_BLANK_F1_1 (HDMI_ADDR_OFFSET + 0x0001011C)
+#define HDMI_LINK_H_SYNC_START_0 (HDMI_ADDR_OFFSET + 0x00010120)
+#define HDMI_LINK_H_SYNC_START_1 (HDMI_ADDR_OFFSET + 0x00010124)
+#define HDMI_LINK_H_SYNC_END_0 (HDMI_ADDR_OFFSET + 0x00010128)
+#define HDMI_LINK_H_SYNC_END_1 (HDMI_ADDR_OFFSET + 0x0001012C)
+#define HDMI_LINK_V_SYNC_LINE_BEF_2_0 (HDMI_ADDR_OFFSET + 0x00010130)
+#define HDMI_LINK_V_SYNC_LINE_BEF_2_1 (HDMI_ADDR_OFFSET + 0x00010134)
+#define HDMI_LINK_V_SYNC_LINE_BEF_1_0 (HDMI_ADDR_OFFSET + 0x00010138)
+#define HDMI_LINK_V_SYNC_LINE_BEF_1_1 (HDMI_ADDR_OFFSET + 0x0001013C)
+#define HDMI_LINK_V_SYNC_LINE_AFT_2_0 (HDMI_ADDR_OFFSET + 0x00010140)
+#define HDMI_LINK_V_SYNC_LINE_AFT_2_1 (HDMI_ADDR_OFFSET + 0x00010144)
+#define HDMI_LINK_V_SYNC_LINE_AFT_1_0 (HDMI_ADDR_OFFSET + 0x00010148)
+#define HDMI_LINK_V_SYNC_LINE_AFT_1_1 (HDMI_ADDR_OFFSET + 0x0001014C)
+#define HDMI_LINK_V_SYNC_LINE_AFT_PXL_2_0 (HDMI_ADDR_OFFSET + 0x00010150)
+#define HDMI_LINK_V_SYNC_LINE_AFT_PXL_2_1 (HDMI_ADDR_OFFSET + 0x00010154)
+#define HDMI_LINK_V_SYNC_LINE_AFT_PXL_1_0 (HDMI_ADDR_OFFSET + 0x00010158)
+#define HDMI_LINK_V_SYNC_LINE_AFT_PXL_1_1 (HDMI_ADDR_OFFSET + 0x0001015C)
+#define HDMI_LINK_V_BLANK_F2_0 (HDMI_ADDR_OFFSET + 0x00010160)
+#define HDMI_LINK_V_BLANK_F2_1 (HDMI_ADDR_OFFSET + 0x00010164)
+#define HDMI_LINK_V_BLANK_F3_0 (HDMI_ADDR_OFFSET + 0x00010168)
+#define HDMI_LINK_V_BLANK_F3_1 (HDMI_ADDR_OFFSET + 0x0001016C)
+#define HDMI_LINK_V_BLANK_F4_0 (HDMI_ADDR_OFFSET + 0x00010170)
+#define HDMI_LINK_V_BLANK_F4_1 (HDMI_ADDR_OFFSET + 0x00010174)
+#define HDMI_LINK_V_BLANK_F5_0 (HDMI_ADDR_OFFSET + 0x00010178)
+#define HDMI_LINK_V_BLANK_F5_1 (HDMI_ADDR_OFFSET + 0x0001017C)
+#define HDMI_LINK_V_SYNC_LINE_AFT_3_0 (HDMI_ADDR_OFFSET + 0x00010180)
+#define HDMI_LINK_V_SYNC_LINE_AFT_3_1 (HDMI_ADDR_OFFSET + 0x00010184)
+#define HDMI_LINK_V_SYNC_LINE_AFT_4_0 (HDMI_ADDR_OFFSET + 0x00010188)
+#define HDMI_LINK_V_SYNC_LINE_AFT_4_1 (HDMI_ADDR_OFFSET + 0x0001018C)
+#define HDMI_LINK_V_SYNC_LINE_AFT_5_0 (HDMI_ADDR_OFFSET + 0x00010190)
+#define HDMI_LINK_V_SYNC_LINE_AFT_5_1 (HDMI_ADDR_OFFSET + 0x00010194)
+#define HDMI_LINK_V_SYNC_LINE_AFT_6_0 (HDMI_ADDR_OFFSET + 0x00010198)
+#define HDMI_LINK_V_SYNC_LINE_AFT_6_1 (HDMI_ADDR_OFFSET + 0x0001019C)
+#define HDMI_LINK_V_SYNC_LINE_AFT_PXL_3_0 (HDMI_ADDR_OFFSET + 0x000101A0)
+#define HDMI_LINK_V_SYNC_LINE_AFT_PXL_3_1 (HDMI_ADDR_OFFSET + 0x000101A4)
+#define HDMI_LINK_V_SYNC_LINE_AFT_PXL_4_0 (HDMI_ADDR_OFFSET + 0x000101A8)
+#define HDMI_LINK_V_SYNC_LINE_AFT_PXL_4_1 (HDMI_ADDR_OFFSET + 0x000101AC)
+#define HDMI_LINK_V_SYNC_LINE_AFT_PXL_5_0 (HDMI_ADDR_OFFSET + 0x000101B0)
+#define HDMI_LINK_V_SYNC_LINE_AFT_PXL_5_1 (HDMI_ADDR_OFFSET + 0x000101B4)
+#define HDMI_LINK_V_SYNC_LINE_AFT_PXL_6_0 (HDMI_ADDR_OFFSET + 0x000101B8)
+#define HDMI_LINK_V_SYNC_LINE_AFT_PXL_6_1 (HDMI_ADDR_OFFSET + 0x000101BC)
+#define HDMI_LINK_VACT_SPACE1_0 (HDMI_ADDR_OFFSET + 0x000101C0)
+#define HDMI_LINK_VACT_SPACE1_1 (HDMI_ADDR_OFFSET + 0x000101C4)
+#define HDMI_LINK_VACT_SPACE2_0 (HDMI_ADDR_OFFSET + 0x000101C8)
+#define HDMI_LINK_VACT_SPACE2_1 (HDMI_ADDR_OFFSET + 0x000101CC)
+#define HDMI_LINK_VACT_SPACE3_0 (HDMI_ADDR_OFFSET + 0x000101D0)
+#define HDMI_LINK_VACT_SPACE3_1 (HDMI_ADDR_OFFSET + 0x000101D4)
+#define HDMI_LINK_VACT_SPACE4_0 (HDMI_ADDR_OFFSET + 0x000101D8)
+#define HDMI_LINK_VACT_SPACE4_1 (HDMI_ADDR_OFFSET + 0x000101DC)
+#define HDMI_LINK_VACT_SPACE5_0 (HDMI_ADDR_OFFSET + 0x000101E0)
+#define HDMI_LINK_VACT_SPACE5_1 (HDMI_ADDR_OFFSET + 0x000101E4)
+#define HDMI_LINK_VACT_SPACE6_0 (HDMI_ADDR_OFFSET + 0x000101E8)
+#define HDMI_LINK_VACT_SPACE6_1 (HDMI_ADDR_OFFSET + 0x000101EC)
+
+#define HDMI_LINK_CSC_MUX (HDMI_ADDR_OFFSET + 0x000101F0)
+#define HDMI_LINK_SYNC_GEN_MUX (HDMI_ADDR_OFFSET + 0x000101F4)
+
+#define HDMI_LINK_GCP_CON (HDMI_ADDR_OFFSET + 0x00010200)
+#define HDMI_LINK_GCP_BYTE1 (HDMI_ADDR_OFFSET + 0x00010210)
+#define HDMI_LINK_GCP_BYTE2 (HDMI_ADDR_OFFSET + 0x00010214)
+#define HDMI_LINK_GCP_BYTE3 (HDMI_ADDR_OFFSET + 0x00010218)
+#define HDMI_LINK_ASP_CON (HDMI_ADDR_OFFSET + 0x00010300)
+#define HDMI_LINK_ASP_SP_FLAT (HDMI_ADDR_OFFSET + 0x00010304)
+#define HDMI_LINK_ASP_CHCFG0 (HDMI_ADDR_OFFSET + 0x00010310)
+#define HDMI_LINK_ASP_CHCFG1 (HDMI_ADDR_OFFSET + 0x00010314)
+#define HDMI_LINK_ASP_CHCFG2 (HDMI_ADDR_OFFSET + 0x00010318)
+#define HDMI_LINK_ASP_CHCFG3 (HDMI_ADDR_OFFSET + 0x0001031C)
+#define HDMI_LINK_ACR_CON (HDMI_ADDR_OFFSET + 0x00010400)
+#define HDMI_LINK_ACR_MCTS0 (HDMI_ADDR_OFFSET + 0x00010410)
+#define HDMI_LINK_ACR_MCTS1 (HDMI_ADDR_OFFSET + 0x00010414)
+#define HDMI_LINK_ACR_MCTS2 (HDMI_ADDR_OFFSET + 0x00010418)
+#define HDMI_LINK_ACR_N0 (HDMI_ADDR_OFFSET + 0x00010430)
+#define HDMI_LINK_ACR_N1 (HDMI_ADDR_OFFSET + 0x00010434)
+#define HDMI_LINK_ACR_N2 (HDMI_ADDR_OFFSET + 0x00010438)
+#define HDMI_LINK_ACP_CON (HDMI_ADDR_OFFSET + 0x00010500)
+#define HDMI_LINK_ACP_TYPE (HDMI_ADDR_OFFSET + 0x00010514)
+#define HDMI_LINK_ACP_DATAX (HDMI_ADDR_OFFSET + 0x00010520)
+#define HDMI_LINK_ISRC_CON (HDMI_ADDR_OFFSET + 0x00010600)
+#define HDMI_LINK_ISRC1_HEADER1 (HDMI_ADDR_OFFSET + 0x00010614)
+#define HDMI_LINK_ISRC1_DATAX (HDMI_ADDR_OFFSET + 0x00010620)
+#define HDMI_LINK_ISRC2_DATAX (HDMI_ADDR_OFFSET + 0x000106A0)
+#define HDMI_LINK_AVI_CON (HDMI_ADDR_OFFSET + 0x00010700)
+#define HDMI_LINK_AVI_HEADER0 (HDMI_ADDR_OFFSET + 0x00010710)
+#define HDMI_LINK_AVI_HEADER1 (HDMI_ADDR_OFFSET + 0x00010714)
+#define HDMI_LINK_AVI_HEADER2 (HDMI_ADDR_OFFSET + 0x00010718)
+#define HDMI_LINK_AVI_CHECK_SUM (HDMI_ADDR_OFFSET + 0x0001071C)
+#define HDMI_LINK_AVI_BYTEX (HDMI_ADDR_OFFSET + 0x00010720)
+#define HDMI_LINK_AVI_BYTE00 (HDMI_ADDR_OFFSET + 0x00010720)
+#define HDMI_LINK_AVI_BYTE01 (HDMI_ADDR_OFFSET + 0x00010724)
+#define HDMI_LINK_AVI_BYTE02 (HDMI_ADDR_OFFSET + 0x00010728)
+#define HDMI_LINK_AVI_BYTE03 (HDMI_ADDR_OFFSET + 0x0001073C)
+#define HDMI_LINK_AVI_BYTE04 (HDMI_ADDR_OFFSET + 0x00010730)
+#define HDMI_LINK_AVI_BYTE05 (HDMI_ADDR_OFFSET + 0x00010734)
+#define HDMI_LINK_AVI_BYTE06 (HDMI_ADDR_OFFSET + 0x00010738)
+#define HDMI_LINK_AVI_BYTE07 (HDMI_ADDR_OFFSET + 0x0001074C)
+#define HDMI_LINK_AVI_BYTE08 (HDMI_ADDR_OFFSET + 0x00010740)
+#define HDMI_LINK_AVI_BYTE09 (HDMI_ADDR_OFFSET + 0x00010744)
+#define HDMI_LINK_AVI_BYTE10 (HDMI_ADDR_OFFSET + 0x00010748)
+#define HDMI_LINK_AVI_BYTE11 (HDMI_ADDR_OFFSET + 0x0001074C)
+#define HDMI_LINK_AVI_BYTE12 (HDMI_ADDR_OFFSET + 0x00010750)
+#define HDMI_LINK_AUI_CON (HDMI_ADDR_OFFSET + 0x00010800)
+#define HDMI_LINK_AUI_HEADER0 (HDMI_ADDR_OFFSET + 0x00010810)
+#define HDMI_LINK_AUI_HEADER1 (HDMI_ADDR_OFFSET + 0x00010814)
+#define HDMI_LINK_AUI_HEADER2 (HDMI_ADDR_OFFSET + 0x00010818)
+#define HDMI_LINK_AUI_CHECK_SUM (HDMI_ADDR_OFFSET + 0x0001081C)
+#define HDMI_LINK_AUI_BYTEX (HDMI_ADDR_OFFSET + 0x00010820)
+#define HDMI_LINK_MPG_CON (HDMI_ADDR_OFFSET + 0x00010900)
+#define HDMI_LINK_MPG_CHECK_SUM (HDMI_ADDR_OFFSET + 0x0001091C)
+#define HDMI_LINK_MPG_DATAX (HDMI_ADDR_OFFSET + 0x00010920)
+#define HDMI_LINK_SPD_CON (HDMI_ADDR_OFFSET + 0x00010A00)
+#define HDMI_LINK_SPD_HEADER0 (HDMI_ADDR_OFFSET + 0x00010A10)
+#define HDMI_LINK_SPD_HEADER1 (HDMI_ADDR_OFFSET + 0x00010A14)
+#define HDMI_LINK_SPD_HEADER2 (HDMI_ADDR_OFFSET + 0x00010A18)
+#define HDMI_LINK_SPD_DATAX (HDMI_ADDR_OFFSET + 0x00010A20)
+#define HDMI_LINK_GAMUT_CON (HDMI_ADDR_OFFSET + 0x00010B00)
+#define HDMI_LINK_GAMUT_HEADER0 (HDMI_ADDR_OFFSET + 0x00010B10)
+#define HDMI_LINK_GAMUT_HEADER1 (HDMI_ADDR_OFFSET + 0x00010B14)
+#define HDMI_LINK_GAMUT_HEADER2 (HDMI_ADDR_OFFSET + 0x00010B18)
+#define HDMI_LINK_GAMUT_METADATAX (HDMI_ADDR_OFFSET + 0x00010B20)
+#define HDMI_LINK_VSI_CON (HDMI_ADDR_OFFSET + 0x00010C00)
+#define HDMI_LINK_VSI_HEADER0 (HDMI_ADDR_OFFSET + 0x00010C10)
+#define HDMI_LINK_VSI_HEADER1 (HDMI_ADDR_OFFSET + 0x00010C14)
+#define HDMI_LINK_VSI_HEADER2 (HDMI_ADDR_OFFSET + 0x00010C18)
+#define HDMI_LINK_VSI_DATAX (HDMI_ADDR_OFFSET + 0x00010C20)
+#define HDMI_LINK_VSI_DATA00 (HDMI_ADDR_OFFSET + 0x00010C20)
+#define HDMI_LINK_VSI_DATA01 (HDMI_ADDR_OFFSET + 0x00010C24)
+#define HDMI_LINK_VSI_DATA02 (HDMI_ADDR_OFFSET + 0x00010C28)
+#define HDMI_LINK_VSI_DATA03 (HDMI_ADDR_OFFSET + 0x00010C2C)
+#define HDMI_LINK_VSI_DATA04 (HDMI_ADDR_OFFSET + 0x00010C30)
+#define HDMI_LINK_VSI_DATA05 (HDMI_ADDR_OFFSET + 0x00010C34)
+#define HDMI_LINK_VSI_DATA06 (HDMI_ADDR_OFFSET + 0x00010C38)
+#define HDMI_LINK_VSI_DATA07 (HDMI_ADDR_OFFSET + 0x00010C3C)
+#define HDMI_LINK_VSI_DATA08 (HDMI_ADDR_OFFSET + 0x00010C40)
+#define HDMI_LINK_VSI_DATA09 (HDMI_ADDR_OFFSET + 0x00010C44)
+#define HDMI_LINK_VSI_DATA10 (HDMI_ADDR_OFFSET + 0x00010C48)
+#define HDMI_LINK_VSI_DATA11 (HDMI_ADDR_OFFSET + 0x00010c4c)
+#define HDMI_LINK_VSI_DATA12 (HDMI_ADDR_OFFSET + 0x00010C50)
+#define HDMI_LINK_VSI_DATA13 (HDMI_ADDR_OFFSET + 0x00010C54)
+#define HDMI_LINK_VSI_DATA14 (HDMI_ADDR_OFFSET + 0x00010C58)
+#define HDMI_LINK_VSI_DATA15 (HDMI_ADDR_OFFSET + 0x00010C5c)
+#define HDMI_LINK_VSI_DATA16 (HDMI_ADDR_OFFSET + 0x00010C60)
+#define HDMI_LINK_VSI_DATA17 (HDMI_ADDR_OFFSET + 0x00010C64)
+#define HDMI_LINK_VSI_DATA18 (HDMI_ADDR_OFFSET + 0x00010C68)
+#define HDMI_LINK_VSI_DATA19 (HDMI_ADDR_OFFSET + 0x00010C6c)
+#define HDMI_LINK_VSI_DATA20 (HDMI_ADDR_OFFSET + 0x00010C70)
+#define HDMI_LINK_VSI_DATA21 (HDMI_ADDR_OFFSET + 0x00010c74)
+#define HDMI_LINK_VSI_DATA22 (HDMI_ADDR_OFFSET + 0x00010C78)
+#define HDMI_LINK_VSI_DATA23 (HDMI_ADDR_OFFSET + 0x00010C7c)
+#define HDMI_LINK_VSI_DATA24 (HDMI_ADDR_OFFSET + 0x00010C80)
+#define HDMI_LINK_VSI_DATA25 (HDMI_ADDR_OFFSET + 0x00010C84)
+#define HDMI_LINK_VSI_DATA26 (HDMI_ADDR_OFFSET + 0x00010C88)
+#define HDMI_LINK_VSI_DATA27 (HDMI_ADDR_OFFSET + 0x00010C8C)
+#define HDMI_LINK_DC_CONTROL (HDMI_ADDR_OFFSET + 0x00010D00)
+#define HDMI_LINK_VIDEO_PATTERN_GEN (HDMI_ADDR_OFFSET + 0x00010D04)
+#define HDMI_LINK_AN_SEED_SEL (HDMI_ADDR_OFFSET + 0x00010E48)
+#define HDMI_LINK_AN_SEED_0 (HDMI_ADDR_OFFSET + 0x00010E58)
+#define HDMI_LINK_AN_SEED_1 (HDMI_ADDR_OFFSET + 0x00010E5C)
+#define HDMI_LINK_AN_SEED_2 (HDMI_ADDR_OFFSET + 0x00010E60)
+#define HDMI_LINK_AN_SEED_3 (HDMI_ADDR_OFFSET + 0x00010E64)
+#define HDMI_LINK_HDCP_SHA1_X (HDMI_ADDR_OFFSET + 0x00017000)
+
+#define HDMI_LINK_HDCP_SHA1_0_0 (HDMI_LINK_HDCP_SHA1_x + 0x00)
+#define HDMI_LINK_HDCP_SHA1_0_1 (HDMI_LINK_HDCP_SHA1_0_0 + 0x04)
+#define HDMI_LINK_HDCP_SHA1_0_2 (HDMI_LINK_HDCP_SHA1_0_0 + 0x08)
+#define HDMI_LINK_HDCP_SHA1_0_3 (HDMI_LINK_HDCP_SHA1_0_0 + 0x0C)
+#define HDMI_LINK_HDCP_SHA1_1_0 (HDMI_LINK_HDCP_SHA1_x + 0x10)
+#define HDMI_LINK_HDCP_SHA1_1_1 (HDMI_LINK_HDCP_SHA1_1_0 + 0x04)
+#define HDMI_LINK_HDCP_SHA1_1_2 (HDMI_LINK_HDCP_SHA1_1_0 + 0x08)
+#define HDMI_LINK_HDCP_SHA1_1_3 (HDMI_LINK_HDCP_SHA1_1_0 + 0x0C)
+#define HDMI_LINK_HDCP_SHA1_2_0 (HDMI_LINK_HDCP_SHA1_x + 0x20)
+#define HDMI_LINK_HDCP_SHA1_2_1 (HDMI_LINK_HDCP_SHA1_2_0 + 0x04)
+#define HDMI_LINK_HDCP_SHA1_2_2 (HDMI_LINK_HDCP_SHA1_2_0 + 0x08)
+#define HDMI_LINK_HDCP_SHA1_2_3 (HDMI_LINK_HDCP_SHA1_2_0 + 0x0C)
+#define HDMI_LINK_HDCP_SHA1_3_0 (HDMI_LINK_HDCP_SHA1_x + 0x30)
+#define HDMI_LINK_HDCP_SHA1_3_1 (HDMI_LINK_HDCP_SHA1_3_0 + 0x04)
+#define HDMI_LINK_HDCP_SHA1_3_2 (HDMI_LINK_HDCP_SHA1_3_0 + 0x08)
+#define HDMI_LINK_HDCP_SHA1_3_3 (HDMI_LINK_HDCP_SHA1_3_0 + 0x0C)
+#define HDMI_LINK_HDCP_SHA1_4_0 (HDMI_LINK_HDCP_SHA1_x + 0x40)
+#define HDMI_LINK_HDCP_SHA1_4_1 (HDMI_LINK_HDCP_SHA1_4_0 + 0x04)
+#define HDMI_LINK_HDCP_SHA1_4_2 (HDMI_LINK_HDCP_SHA1_4_0 + 0x08)
+#define HDMI_LINK_HDCP_SHA1_4_3 (HDMI_LINK_HDCP_SHA1_4_0 + 0x0C)
+
+#define HDMI_LINK_HDCP_KSV_LIST_X (HDMI_ADDR_OFFSET + 0x00017050)
+
+#define HDMI_LINK_HDCP_KSV_0_0 (HDMI_LINK_HDCP_KSV_LIST_X + 0x00)
+#define HDMI_LINK_HDCP_KSV_0_1 (HDMI_LINK_HDCP_KSV_LIST_X + 0x04)
+#define HDMI_LINK_HDCP_KSV_0_2 (HDMI_LINK_HDCP_KSV_LIST_X + 0x08)
+#define HDMI_LINK_HDCP_KSV_0_3 (HDMI_LINK_HDCP_KSV_LIST_X + 0x0C)
+#define HDMI_LINK_HDCP_KSV_1_0 (HDMI_LINK_HDCP_KSV_LIST_X + 0x10)
+#define HDMI_LINK_HDCP_KSV_1_1 (HDMI_LINK_HDCP_KSV_LIST_X + 0x14)
+
+#define HDMI_LINK_HDCP_KSV_LIST_0_0 (HDMI_LINK_HDCP_KSV_LIST_X + 0x00)
+#define HDMI_LINK_HDCP_KSV_LIST_0_1 (HDMI_LINK_HDCP_KSV_LIST_X + 0x04)
+#define HDMI_LINK_HDCP_KSV_LIST_0_2 (HDMI_LINK_HDCP_KSV_LIST_X + 0x08)
+#define HDMI_LINK_HDCP_KSV_LIST_0_3 (HDMI_LINK_HDCP_KSV_LIST_X + 0x0C)
+#define HDMI_LINK_HDCP_KSV_LIST_1_0 (HDMI_LINK_HDCP_KSV_LIST_X + 0x10)
+#define HDMI_LINK_HDCP_KSV_LIST_1_1 (HDMI_LINK_HDCP_KSV_LIST_X + 0x14)
+
+#define HDMI_LINK_HDCP_KSV_LIST_CON (HDMI_ADDR_OFFSET + 0x00017064)
+#define HDMI_LINK_HDCP_SHA_RESULT (HDMI_ADDR_OFFSET + 0x00017070)
+#define HDMI_LINK_HDCP_CTRL1 (HDMI_ADDR_OFFSET + 0x00017080)
+#define HDMI_LINK_HDCP_CTRL2 (HDMI_ADDR_OFFSET + 0x00017084)
+#define HDMI_LINK_HDCP_CHECK_RESULT (HDMI_ADDR_OFFSET + 0x00017090)
+#define HDMI_LINK_HDCP_BKSV_X (HDMI_ADDR_OFFSET + 0x000170A0)
+
+#define HDMI_LINK_HDCP_BKSV0_0 (HDMI_ADDR_OFFSET + 0x000170A0)
+#define HDMI_LINK_HDCP_BKSV0_1 (HDMI_ADDR_OFFSET + 0x000170A4)
+#define HDMI_LINK_HDCP_BKSV0_2 (HDMI_ADDR_OFFSET + 0x000170A8)
+#define HDMI_LINK_HDCP_BKSV0_3 (HDMI_ADDR_OFFSET + 0x000170AC)
+#define HDMI_LINK_HDCP_BKSV1 (HDMI_ADDR_OFFSET + 0x000170B0)
+
+#define HDMI_LINK_HDCP_AKSV_X (HDMI_ADDR_OFFSET + 0x000170C0)
+#define HDMI_LINK_HDCP_AN_X (HDMI_ADDR_OFFSET + 0x000170E0)
+#define HDMI_LINK_HDCP_BCAPS (HDMI_ADDR_OFFSET + 0x00017100)
+#define HDMI_LINK_HDCP_BSTATUS_0 (HDMI_ADDR_OFFSET + 0x00017110)
+#define HDMI_LINK_HDCP_BSTATUS_1 (HDMI_ADDR_OFFSET + 0x00017114)
+#define HDMI_LINK_HDCP_RI_0 (HDMI_ADDR_OFFSET + 0x00017140)
+#define HDMI_LINK_HDCP_RI_1 (HDMI_ADDR_OFFSET + 0x00017144)
+
+#define HDMI_LINK_HDCP_OFFSET_TX_0 (HDMI_ADDR_OFFSET + 0x00017160)
+#define HDMI_LINK_HDCP_OFFSET_TX_1 (HDMI_ADDR_OFFSET + 0x00017164)
+#define HDMI_LINK_HDCP_OFFSET_TX_2 (HDMI_ADDR_OFFSET + 0x00017168)
+#define HDMI_LINK_HDCP_OFFSET_TX_3 (HDMI_ADDR_OFFSET + 0x0001716C)
+#define HDMI_LINK_HDCP_CYCLE_AA (HDMI_ADDR_OFFSET + 0x00017170)
+
+#define HDMI_LINK_HDCP_I2C_INT (HDMI_ADDR_OFFSET + 0x00017180)
+#define HDMI_LINK_HDCP_AN_INT (HDMI_ADDR_OFFSET + 0x00017190)
+#define HDMI_LINK_HDCP_WATCHDOG_INT (HDMI_ADDR_OFFSET + 0x000171A0)
+#define HDMI_LINK_HDCP_RI_INT (HDMI_ADDR_OFFSET + 0x000171B0)
+#define HDMI_LINK_HDCP_RI_COMPARE_0 (HDMI_ADDR_OFFSET + 0x000171D0)
+#define HDMI_LINK_HDCP_RI_COMPARE_1 (HDMI_ADDR_OFFSET + 0x000171D4)
+
+#define HDMI_LINK_HDCP_RI_INT (HDMI_ADDR_OFFSET + 0x000171B0)
+#define HDMI_LINK_HDCP_RI_COMPARE_0 (HDMI_ADDR_OFFSET + 0x000171D0)
+#define HDMI_LINK_HDCP_RI_COMPARE_1 (HDMI_ADDR_OFFSET + 0x000171D4)
+
+#define HDMI_LINK_HDCP_FRAME_COUNT (HDMI_ADDR_OFFSET + 0x000171E0)
+#define HDMI_LINK_RGB_ROUND_EN (HDMI_ADDR_OFFSET + 0x0001D500)
+#define HDMI_LINK_VACT_SPACE_R_0 (HDMI_ADDR_OFFSET + 0x0001D504)
+#define HDMI_LINK_VACT_SPACE_R_1 (HDMI_ADDR_OFFSET + 0x0001D508)
+#define HDMI_LINK_VACT_SPACE_G_0 (HDMI_ADDR_OFFSET + 0x0001D50C)
+#define HDMI_LINK_VACT_SPACE_G_1 (HDMI_ADDR_OFFSET + 0x0001D510)
+#define HDMI_LINK_VACT_SPACE_B_0 (HDMI_ADDR_OFFSET + 0x0001D514)
+#define HDMI_LINK_VACT_SPACE_B_1 (HDMI_ADDR_OFFSET + 0x0001D518)
+#define HDMI_LINK_BLUE_SCREEN_R_0 (HDMI_ADDR_OFFSET + 0x0001D520)
+#define HDMI_LINK_BLUE_SCREEN_R_1 (HDMI_ADDR_OFFSET + 0x0001D524)
+#define HDMI_LINK_BLUE_SCREEN_G_0 (HDMI_ADDR_OFFSET + 0x0001D528)
+#define HDMI_LINK_BLUE_SCREEN_G_1 (HDMI_ADDR_OFFSET + 0x0001D52C)
+#define HDMI_LINK_BLUE_SCREEN_B_0 (HDMI_ADDR_OFFSET + 0x0001D530)
+#define HDMI_LINK_BLUE_SCREEN_B_1 (HDMI_ADDR_OFFSET + 0x0001D534)
+#define HDMI_LINK_AES_START (HDMI_ADDR_OFFSET + 0x00020000)
+#define HDMI_LINK_AES_DATA_SIZE_L (HDMI_ADDR_OFFSET + 0x00020020)
+#define HDMI_LINK_AES_DATA_SIZE_H (HDMI_ADDR_OFFSET + 0x00020024)
+#define HDMI_LINK_AES_DATA (HDMI_ADDR_OFFSET + 0x00020040)
+#define HDMI_LINK_SPDIFIN_CLK_CTRL (HDMI_ADDR_OFFSET + 0x00030000)
+#define HDMI_LINK_SPDIFIN_OP_CTRL (HDMI_ADDR_OFFSET + 0x00030004)
+#define HDMI_LINK_SPDIFIN_IRQ_MASK (HDMI_ADDR_OFFSET + 0x00030008)
+#define HDMI_LINK_SPDIFIN_IRQ_STATUS (HDMI_ADDR_OFFSET + 0x0003000C)
+#define HDMI_LINK_SPDIFIN_CONFIG_1 (HDMI_ADDR_OFFSET + 0x00030010)
+#define HDMI_LINK_SPDIFIN_CONFIG_2 (HDMI_ADDR_OFFSET + 0x00030014)
+#define HDMI_LINK_SPDIFIN_USER_VALUE_1 (HDMI_ADDR_OFFSET + 0x00030020)
+#define HDMI_LINK_SPDIFIN_USER_VALUE_2 (HDMI_ADDR_OFFSET + 0x00030024)
+#define HDMI_LINK_SPDIFIN_USER_VALUE_3 (HDMI_ADDR_OFFSET + 0x00030028)
+#define HDMI_LINK_SPDIFIN_USER_VALUE_4 (HDMI_ADDR_OFFSET + 0x0003002C)
+#define HDMI_LINK_SPDIFIN_CH_STATUS_0_1 (HDMI_ADDR_OFFSET + 0x00030030)
+#define HDMI_LINK_SPDIFIN_CH_STATUS_0_2 (HDMI_ADDR_OFFSET + 0x00030034)
+#define HDMI_LINK_SPDIFIN_CH_STATUS_0_3 (HDMI_ADDR_OFFSET + 0x00030038)
+#define HDMI_LINK_SPDIFIN_CH_STATUS_0_4 (HDMI_ADDR_OFFSET + 0x0003003C)
+#define HDMI_LINK_SPDIFIN_CH_STATUS_1 (HDMI_ADDR_OFFSET + 0x00030040)
+#define HDMI_LINK_SPDIFIN_FRAME_PERIOD_1 (HDMI_ADDR_OFFSET + 0x00030048)
+#define HDMI_LINK_SPDIFIN_FRAME_PERIOD_2 (HDMI_ADDR_OFFSET + 0x0003004C)
+#define HDMI_LINK_SPDIFIN_PC_INFO_1 (HDMI_ADDR_OFFSET + 0x00030050)
+#define HDMI_LINK_SPDIFIN_PC_INFO_2 (HDMI_ADDR_OFFSET + 0x00030054)
+#define HDMI_LINK_SPDIFIN_PD_INFO_1 (HDMI_ADDR_OFFSET + 0x00030058)
+#define HDMI_LINK_SPDIFIN_PD_INFO_2 (HDMI_ADDR_OFFSET + 0x0003005C)
+#define HDMI_LINK_SPDIFIN_DATA_BUF_0_1 (HDMI_ADDR_OFFSET + 0x00030060)
+#define HDMI_LINK_SPDIFIN_DATA_BUF_0_2 (HDMI_ADDR_OFFSET + 0x00030064)
+#define HDMI_LINK_SPDIFIN_DATA_BUF_0_3 (HDMI_ADDR_OFFSET + 0x00030068)
+#define HDMI_LINK_SPDIFIN_USER_BUF_0 (HDMI_ADDR_OFFSET + 0x0003006C)
+#define HDMI_LINK_SPDIFIN_DATA_BUF_1_1 (HDMI_ADDR_OFFSET + 0x00030070)
+#define HDMI_LINK_SPDIFIN_DATA_BUF_1_2 (HDMI_ADDR_OFFSET + 0x00030074)
+#define HDMI_LINK_SPDIFIN_DATA_BUF_1_3 (HDMI_ADDR_OFFSET + 0x00030078)
+#define HDMI_LINK_SPDIFIN_USER_BUF_1 (HDMI_ADDR_OFFSET + 0x0003007C)
+#define HDMI_LINK_I2S_CLK_CON (HDMI_ADDR_OFFSET + 0x00040000)
+#define HDMI_LINK_I2S_CON_1 (HDMI_ADDR_OFFSET + 0x00040004)
+#define HDMI_LINK_I2S_CON_2 (HDMI_ADDR_OFFSET + 0x00040008)
+#define HDMI_LINK_I2S_PIN_SEL_0 (HDMI_ADDR_OFFSET + 0x0004000C)
+#define HDMI_LINK_I2S_PIN_SEL_1 (HDMI_ADDR_OFFSET + 0x00040010)
+#define HDMI_LINK_I2S_PIN_SEL_2 (HDMI_ADDR_OFFSET + 0x00040014)
+#define HDMI_LINK_I2S_PIN_SEL_3 (HDMI_ADDR_OFFSET + 0x00040018)
+#define HDMI_LINK_I2S_DSD_CON (HDMI_ADDR_OFFSET + 0x0004001C)
+#define HDMI_LINK_I2S_MUX_CON (HDMI_ADDR_OFFSET + 0x00040020)
+#define HDMI_LINK_I2S_CH_ST_CON (HDMI_ADDR_OFFSET + 0x00040024)
+#define HDMI_LINK_I2S_CH_ST_0 (HDMI_ADDR_OFFSET + 0x00040028)
+#define HDMI_LINK_I2S_CH_ST_1 (HDMI_ADDR_OFFSET + 0x0004002C)
+#define HDMI_LINK_I2S_CH_ST_2 (HDMI_ADDR_OFFSET + 0x00040030)
+#define HDMI_LINK_I2S_CH_ST_3 (HDMI_ADDR_OFFSET + 0x00040034)
+#define HDMI_LINK_I2S_CH_ST_4 (HDMI_ADDR_OFFSET + 0x00040038)
+#define HDMI_LINK_I2S_CH_ST_SH_0 (HDMI_ADDR_OFFSET + 0x0004003C)
+#define HDMI_LINK_I2S_CH_ST_SH_1 (HDMI_ADDR_OFFSET + 0x00040040)
+#define HDMI_LINK_I2S_CH_ST_SH_2 (HDMI_ADDR_OFFSET + 0x00040044)
+#define HDMI_LINK_I2S_CH_ST_SH_3 (HDMI_ADDR_OFFSET + 0x00040048)
+#define HDMI_LINK_I2S_CH_ST_SH_4 (HDMI_ADDR_OFFSET + 0x0004004C)
+#define HDMI_LINK_I2S_VD_DATA (HDMI_ADDR_OFFSET + 0x00040050)
+#define HDMI_LINK_I2S_MUX_CH (HDMI_ADDR_OFFSET + 0x00040054)
+#define HDMI_LINK_I2S_MUX_CUV (HDMI_ADDR_OFFSET + 0x00040058)
+#define HDMI_LINK_I2S_CH0_L_0 (HDMI_ADDR_OFFSET + 0x00040064)
+#define HDMI_LINK_I2S_CH0_L_1 (HDMI_ADDR_OFFSET + 0x00040068)
+#define HDMI_LINK_I2S_CH0_L_2 (HDMI_ADDR_OFFSET + 0x0004006C)
+#define HDMI_LINK_I2S_CH0_R_0 (HDMI_ADDR_OFFSET + 0x00040074)
+#define HDMI_LINK_I2S_CH0_R_1 (HDMI_ADDR_OFFSET + 0x00040078)
+#define HDMI_LINK_I2S_CH0_R_2 (HDMI_ADDR_OFFSET + 0x0004007C)
+#define HDMI_LINK_I2S_CH0_R_3 (HDMI_ADDR_OFFSET + 0x00040080)
+#define HDMI_LINK_I2S_CH1_L_0 (HDMI_ADDR_OFFSET + 0x00040084)
+#define HDMI_LINK_I2S_CH1_L_1 (HDMI_ADDR_OFFSET + 0x00040088)
+#define HDMI_LINK_I2S_CH1_L_2 (HDMI_ADDR_OFFSET + 0x0004008C)
+#define HDMI_LINK_I2S_CH1_L_3 (HDMI_ADDR_OFFSET + 0x00040090)
+#define HDMI_LINK_I2S_CH1_R_0 (HDMI_ADDR_OFFSET + 0x00040094)
+#define HDMI_LINK_I2S_CH1_R_1 (HDMI_ADDR_OFFSET + 0x00040098)
+#define HDMI_LINK_I2S_CH1_R_2 (HDMI_ADDR_OFFSET + 0x0004009C)
+#define HDMI_LINK_I2S_CH1_R_3 (HDMI_ADDR_OFFSET + 0x000400A0)
+#define HDMI_LINK_I2S_CH2_L_0 (HDMI_ADDR_OFFSET + 0x000400A4)
+#define HDMI_LINK_I2S_CH2_L_1 (HDMI_ADDR_OFFSET + 0x000400A8)
+#define HDMI_LINK_I2S_CH2_L_2 (HDMI_ADDR_OFFSET + 0x000400AC)
+#define HDMI_LINK_I2S_CH2_L_3 (HDMI_ADDR_OFFSET + 0x000400B0)
+#define HDMI_LINK_I2S_CH2_R_0 (HDMI_ADDR_OFFSET + 0x000400B4)
+#define HDMI_LINK_I2S_CH2_R_1 (HDMI_ADDR_OFFSET + 0x000400B8)
+#define HDMI_LINK_I2S_CH2_R_2 (HDMI_ADDR_OFFSET + 0x000400BC)
+#define HDMI_LINK_I2S_CH2_R_3 (HDMI_ADDR_OFFSET + 0x000400C0)
+#define HDMI_LINK_I2S_CH3_L_0 (HDMI_ADDR_OFFSET + 0x000400C4)
+#define HDMI_LINK_I2S_CH3_L_1 (HDMI_ADDR_OFFSET + 0x000400C8)
+#define HDMI_LINK_I2S_CH3_L_2 (HDMI_ADDR_OFFSET + 0x000400CC)
+#define HDMI_LINK_I2S_CH3_R_0 (HDMI_ADDR_OFFSET + 0x000400D0)
+#define HDMI_LINK_I2S_CH3_R_1 (HDMI_ADDR_OFFSET + 0x000400D4)
+#define HDMI_LINK_I2S_CH3_R_2 (HDMI_ADDR_OFFSET + 0x000400D8)
+#define HDMI_LINK_I2S_CUV_L_R (HDMI_ADDR_OFFSET + 0x000400DC)
+
+#define HDMI_CEC_TX_STATUS_0 (OTHER_ADDR_OFFSET + 0x00000000)
+#define HDMI_CEC_TX_STATUS_1 (OTHER_ADDR_OFFSET + 0x00000004)
+#define HDMI_CEC_RX_STATUS_0 (OTHER_ADDR_OFFSET + 0x00000008)
+#define HDMI_CEC_RX_STATUS_1 (OTHER_ADDR_OFFSET + 0x0000000C)
+#define HDMI_CEC_INTR_MASK (OTHER_ADDR_OFFSET + 0x00000010)
+#define HDMI_CEC_INTR_CLEAR (OTHER_ADDR_OFFSET + 0x00000014)
+#define HDMI_CEC_LOGIC_ADDR (OTHER_ADDR_OFFSET + 0x00000020)
+#define HDMI_CEC_DIVISOR_0 (OTHER_ADDR_OFFSET + 0x00000030)
+#define HDMI_CEC_DIVISOR_1 (OTHER_ADDR_OFFSET + 0x00000034)
+#define HDMI_CEC_DIVISOR_2 (OTHER_ADDR_OFFSET + 0x00000038)
+#define HDMI_CEC_DIVISOR_3 (OTHER_ADDR_OFFSET + 0x0000003C)
+#define HDMI_CEC_TX_CTRL (OTHER_ADDR_OFFSET + 0x00000040)
+#define HDMI_CEC_TX_BYTE_NUM (OTHER_ADDR_OFFSET + 0x00000044)
+#define HDMI_CEC_TX_STATUS_2 (OTHER_ADDR_OFFSET + 0x00000060)
+#define HDMI_CEC_TX_STATUS_3 (OTHER_ADDR_OFFSET + 0x00000064)
+#define HDMI_CEC_TX_BUFFER_x (OTHER_ADDR_OFFSET + 0x00000080)
+#define HDMI_CEC_TX_BUFFER00 (OTHER_ADDR_OFFSET + 0x00000080)
+#define HDMI_CEC_RX_CTRL (OTHER_ADDR_OFFSET + 0x000000C0)
+#define HDMI_CEC_RX_STATUS_2 (OTHER_ADDR_OFFSET + 0x000000E0)
+#define HDMI_CEC_RX_STATUS_3 (OTHER_ADDR_OFFSET + 0x000000E4)
+#define HDMI_CEC_RX_BUFFER_x (OTHER_ADDR_OFFSET + 0x00000100)
+#define HDMI_CEC_FILTER_CTRL (OTHER_ADDR_OFFSET + 0x00000180)
+#define HDMI_CEC_FILTER_TH (OTHER_ADDR_OFFSET + 0x00000184)
+
+#ifdef CONFIG_MACH_S5P6818
+#define HDMI_PHY_OFFSET \
+ (PHY_BASEADDR_HDMI_PHY_MODULE - PHY_BASEADDR_HDMI_MODULE)
+#else
+#define HDMI_PHY_OFFSET 0x400
+#endif
+
+#define HDMI_PHY_REG00 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000000)
+#define HDMI_PHY_REG04 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000004)
+#define HDMI_PHY_REG08 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000008)
+#define HDMI_PHY_REG0C (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x0000000C)
+#define HDMI_PHY_REG10 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000010)
+#define HDMI_PHY_REG14 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000014)
+#define HDMI_PHY_REG18 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000018)
+#define HDMI_PHY_REG1C (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x0000001C)
+#define HDMI_PHY_REG20 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000020)
+#define HDMI_PHY_REG24 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000024)
+#define HDMI_PHY_REG28 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000028)
+#define HDMI_PHY_REG2C (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x0000002C)
+#define HDMI_PHY_REG30 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000030)
+#define HDMI_PHY_REG34 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000034)
+#define HDMI_PHY_REG38 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000038)
+#define HDMI_PHY_REG3C (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x0000003C)
+#define HDMI_PHY_REG40 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000040)
+#define HDMI_PHY_REG44 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000044)
+#define HDMI_PHY_REG48 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000048)
+#define HDMI_PHY_REG4C (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x0000004C)
+#define HDMI_PHY_REG50 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000050)
+#define HDMI_PHY_REG54 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000054)
+#define HDMI_PHY_REG58 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000058)
+#define HDMI_PHY_REG5C (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x0000005C)
+#define HDMI_PHY_REG60 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000060)
+#define HDMI_PHY_REG64 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000064)
+#define HDMI_PHY_REG68 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000068)
+#define HDMI_PHY_REG6C (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x0000006C)
+#define HDMI_PHY_REG70 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000070)
+#define HDMI_PHY_REG74 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000074)
+#define HDMI_PHY_REG78 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000078)
+#define HDMI_PHY_REG7C (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x0000007C)
+#define HDMI_PHY_REG80 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000080)
+#define HDMI_PHY_REG84 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000084)
+#define HDMI_PHY_REG88 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000088)
+#define HDMI_PHY_REG8C (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x0000008C)
+#define HDMI_PHY_REG90 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000090)
+
+enum hdmi_reset {
+ i_nRST = 0,
+ i_nRST_VIDEO = 1,
+ i_nRST_SPDIF = 2,
+ i_nRST_TMDS = 3,
+ i_nRST_PHY = 4,
+};
+
+u32 nx_hdmi_get_reg(u32 module_index, u32 offset);
+void nx_hdmi_set_reg(u32 module_index, u32 offset, u32 regvalue);
+
+void nx_hdmi_set_base_address(u32 module_index, void *base_address);
+void *nx_hdmi_get_base_address(u32 module_index);
+u32 nx_hdmi_get_physical_address(u32 module_index);
+
+#endif
diff --git a/drivers/video/nexell/soc/s5pxx18_soc_lvds.c b/drivers/video/nexell/soc/s5pxx18_soc_lvds.c
new file mode 100644
index 0000000..18c101b
--- /dev/null
+++ b/drivers/video/nexell/soc/s5pxx18_soc_lvds.c
@@ -0,0 +1,278 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Nexell Co., Ltd.
+ *
+ * Author: junghyun, kim <jhkim@nexell.co.kr>
+ */
+
+#include <linux/types.h>
+#include <linux/io.h>
+
+#include "s5pxx18_soc_disptop.h"
+#include "s5pxx18_soc_lvds.h"
+
+#ifndef pow
+static inline unsigned int pow(int a, int b)
+{
+ if (b == 0)
+ return 1;
+ else
+ return a * pow(a, b - 1);
+}
+#endif
+
+static struct nx_lvds_register_set *__g_pregister[NUMBER_OF_LVDS_MODULE];
+
+int nx_lvds_initialize(void)
+{
+ static int binit;
+ u32 i;
+
+ if (binit == 0) {
+ for (i = 0; i < NUMBER_OF_LVDS_MODULE; i++)
+ __g_pregister[i] = NULL;
+ binit = 1;
+ }
+
+ return 1;
+}
+
+u32 nx_lvds_get_number_of_module(void)
+{
+ return NUMBER_OF_LVDS_MODULE;
+}
+
+u32 nx_lvds_get_size_of_register_set(void)
+{
+ return sizeof(struct nx_lvds_register_set);
+}
+
+void nx_lvds_set_base_address(u32 module_index, void *base_address)
+{
+ __g_pregister[module_index] =
+ (struct nx_lvds_register_set *)base_address;
+}
+
+void *nx_lvds_get_base_address(u32 module_index)
+{
+ return (void *)__g_pregister[module_index];
+}
+
+u32 nx_lvds_get_physical_address(u32 module_index)
+{
+ const u32 physical_addr[] = PHY_BASEADDR_LVDS_LIST;
+
+ return physical_addr[module_index];
+}
+
+int nx_lvds_open_module(u32 module_index)
+{
+ return true;
+}
+
+int nx_lvds_close_module(u32 module_index)
+{
+ return true;
+}
+
+int nx_lvds_check_busy(u32 module_index)
+{
+ return false;
+}
+
+void nx_lvds_set_lvdsctrl0(u32 module_index, u32 regvalue)
+{
+ register struct nx_lvds_register_set *pregister;
+
+ pregister = __g_pregister[module_index];
+ writel(regvalue, &pregister->lvdsctrl0);
+}
+
+void nx_lvds_set_lvdsctrl1(u32 module_index, u32 regvalue)
+{
+ register struct nx_lvds_register_set *pregister;
+
+ pregister = __g_pregister[module_index];
+ writel(regvalue, &pregister->lvdsctrl1);
+}
+
+void nx_lvds_set_lvdsctrl2(u32 module_index, u32 regvalue)
+{
+ register struct nx_lvds_register_set *pregister;
+
+ pregister = __g_pregister[module_index];
+ writel(regvalue, &pregister->lvdsctrl2);
+}
+
+void nx_lvds_set_lvdsctrl3(u32 module_index, u32 regvalue)
+{
+ register struct nx_lvds_register_set *pregister;
+
+ pregister = __g_pregister[module_index];
+ writel(regvalue, &pregister->lvdsctrl3);
+}
+
+void nx_lvds_set_lvdsctrl4(u32 module_index, u32 regvalue)
+{
+ register struct nx_lvds_register_set *pregister;
+
+ pregister = __g_pregister[module_index];
+ writel(regvalue, &pregister->lvdsctrl4);
+}
+
+void nx_lvds_set_lvdstmode0(u32 module_index, u32 regvalue)
+{
+ register struct nx_lvds_register_set *pregister;
+
+ pregister = __g_pregister[module_index];
+ writel(regvalue, &pregister->lvdstmode0);
+}
+
+void nx_lvds_set_lvdsloc0(u32 module_index, u32 regvalue)
+{
+ register struct nx_lvds_register_set *pregister;
+
+ pregister = __g_pregister[module_index];
+ writel(regvalue, &pregister->lvdsloc0);
+}
+
+void nx_lvds_set_lvdsloc1(u32 module_index, u32 regvalue)
+{
+ register struct nx_lvds_register_set *pregister;
+
+ pregister = __g_pregister[module_index];
+ writel(regvalue, &pregister->lvdsloc1);
+}
+
+void nx_lvds_set_lvdsloc2(u32 module_index, u32 regvalue)
+{
+ register struct nx_lvds_register_set *pregister;
+
+ pregister = __g_pregister[module_index];
+ writel(regvalue, &pregister->lvdsloc2);
+}
+
+void nx_lvds_set_lvdsloc3(u32 module_index, u32 regvalue)
+{
+ register struct nx_lvds_register_set *pregister;
+
+ pregister = __g_pregister[module_index];
+ writel(regvalue, &pregister->lvdsloc3);
+}
+
+void nx_lvds_set_lvdsloc4(u32 module_index, u32 regvalue)
+{
+ register struct nx_lvds_register_set *pregister;
+
+ pregister = __g_pregister[module_index];
+ writel(regvalue, &pregister->lvdsloc4);
+}
+
+void nx_lvds_set_lvdsloc5(u32 module_index, u32 regvalue)
+{
+ register struct nx_lvds_register_set *pregister;
+
+ pregister = __g_pregister[module_index];
+ writel(regvalue, &pregister->lvdsloc5);
+}
+
+void nx_lvds_set_lvdsloc6(u32 module_index, u32 regvalue)
+{
+ register struct nx_lvds_register_set *pregister;
+
+ pregister = __g_pregister[module_index];
+ writel(regvalue, &pregister->lvdsloc6);
+}
+
+void nx_lvds_set_lvdslocmask0(u32 module_index, u32 regvalue)
+{
+ register struct nx_lvds_register_set *pregister;
+
+ pregister = __g_pregister[module_index];
+ writel(regvalue, &pregister->lvdslocmask0);
+}
+
+void nx_lvds_set_lvdslocmask1(u32 module_index, u32 regvalue)
+{
+ register struct nx_lvds_register_set *pregister;
+
+ pregister = __g_pregister[module_index];
+ writel(regvalue, &pregister->lvdslocmask1);
+}
+
+void nx_lvds_set_lvdslocpol0(u32 module_index, u32 regvalue)
+{
+ register struct nx_lvds_register_set *pregister;
+
+ pregister = __g_pregister[module_index];
+ writel(regvalue, &pregister->lvdslocpol0);
+}
+
+void nx_lvds_set_lvdslocpol1(u32 module_index, u32 regvalue)
+{
+ register struct nx_lvds_register_set *pregister;
+
+ pregister = __g_pregister[module_index];
+ writel(regvalue, &pregister->lvdslocpol1);
+}
+
+void nx_lvds_set_lvdsdummy(u32 module_index, u32 regvalue)
+{
+ register struct nx_lvds_register_set *pregister;
+ u32 oldvalue;
+
+ pregister = __g_pregister[module_index];
+ oldvalue = readl(&pregister->lvdsctrl1) & 0x00ffffff;
+ writel(oldvalue | ((regvalue & 0xff) << 24), &pregister->lvdsctrl1);
+}
+
+u32 nx_lvds_get_lvdsdummy(u32 module_index)
+{
+ register struct nx_lvds_register_set *pregister;
+ u32 oldvalue;
+
+ pregister = __g_pregister[module_index];
+ oldvalue = readl(&pregister->lvdsctrl1);
+ oldvalue = oldvalue >> 24;
+ return oldvalue;
+}
+
+u32 nx_lvds_get_lvdsctrl0(u32 module_index)
+{
+ register struct nx_lvds_register_set *pregister;
+
+ pregister = __g_pregister[module_index];
+ return (u32)readl(&pregister->lvdsctrl0);
+}
+
+u32 nx_lvds_get_lvdsctrl1(u32 module_index)
+{
+ register struct nx_lvds_register_set *pregister;
+
+ pregister = __g_pregister[module_index];
+ return (u32)readl(&pregister->lvdsctrl1);
+}
+
+u32 nx_lvds_get_lvdsctrl2(u32 module_index)
+{
+ register struct nx_lvds_register_set *pregister;
+
+ pregister = __g_pregister[module_index];
+ return (u32)readl(&pregister->lvdsctrl2);
+}
+
+u32 nx_lvds_get_lvdsctrl3(u32 module_index)
+{
+ register struct nx_lvds_register_set *pregister;
+
+ pregister = __g_pregister[module_index];
+ return (u32)readl(&pregister->lvdsctrl3);
+}
+
+u32 nx_lvds_get_lvdsctrl4(u32 module_index)
+{
+ register struct nx_lvds_register_set *pregister;
+
+ pregister = __g_pregister[module_index];
+ return (u32)readl(&pregister->lvdsctrl4);
+}
diff --git a/drivers/video/nexell/soc/s5pxx18_soc_lvds.h b/drivers/video/nexell/soc/s5pxx18_soc_lvds.h
new file mode 100644
index 0000000..08f8e5c
--- /dev/null
+++ b/drivers/video/nexell/soc/s5pxx18_soc_lvds.h
@@ -0,0 +1,83 @@
+/* SPDX-License-Identifier: GPL-2.0+
+ *
+ * Copyright (C) 2016 Nexell Co., Ltd.
+ *
+ * Author: junghyun, kim <jhkim@nexell.co.kr>
+ */
+
+#ifndef _S5PXX18_SOC_LVDS_H_
+#define _S5PXX18_SOC_LVDS_H_
+
+/*
+ * refter to s5pxx18_soc_disptop.h
+ *
+ * #define NUMBER_OF_LVDS_MODULE 1
+ * #define PHY_BASEADDR_LVDS_MODULE 0xC010A000
+ */
+#define PHY_BASEADDR_LVDS_LIST \
+ { PHY_BASEADDR_LVDS_MODULE }
+
+struct nx_lvds_register_set {
+ u32 lvdsctrl0;
+ u32 lvdsctrl1;
+ u32 lvdsctrl2;
+ u32 lvdsctrl3;
+ u32 lvdsctrl4;
+ u32 _reserved0[3];
+ u32 lvdsloc0;
+ u32 lvdsloc1;
+ u32 lvdsloc2;
+ u32 lvdsloc3;
+ u32 lvdsloc4;
+ u32 lvdsloc5;
+ u32 lvdsloc6;
+ u32 _reserved1;
+ u32 lvdslocmask0;
+ u32 lvdslocmask1;
+ u32 lvdslocpol0;
+ u32 lvdslocpol1;
+ u32 lvdstmode0;
+ u32 lvdstmode1;
+ u32 _reserved2[2];
+};
+
+int nx_lvds_initialize(void);
+u32 nx_lvds_get_number_of_module(void);
+u32 nx_lvds_get_size_of_register_set(void);
+void nx_lvds_set_base_address(u32 module_index, void *base_address);
+void *nx_lvds_get_base_address(u32 module_index);
+u32 nx_lvds_get_physical_address(u32 module_index);
+int nx_lvds_open_module(u32 module_index);
+int nx_lvds_close_module(u32 module_index);
+int nx_lvds_check_busy(u32 module_index);
+
+void nx_lvds_set_lvdsctrl0(u32 module_index, u32 regvalue);
+void nx_lvds_set_lvdsctrl1(u32 module_index, u32 regvalue);
+void nx_lvds_set_lvdsctrl2(u32 module_index, u32 regvalue);
+void nx_lvds_set_lvdsctrl3(u32 module_index, u32 regvalue);
+void nx_lvds_set_lvdsctrl4(u32 module_index, u32 regvalue);
+u32 nx_lvds_get_lvdsctrl0(u32 module_index);
+u32 nx_lvds_get_lvdsctrl1(u32 module_index);
+u32 nx_lvds_get_lvdsctrl2(u32 module_index);
+u32 nx_lvds_get_lvdsctrl3(u32 module_index);
+u32 nx_lvds_get_lvdsctrl4(u32 module_index);
+
+void nx_lvds_set_lvdstmode0(u32 module_index, u32 regvalue);
+void nx_lvds_set_lvdsloc0(u32 module_index, u32 regvalue);
+void nx_lvds_set_lvdsloc1(u32 module_index, u32 regvalue);
+void nx_lvds_set_lvdsloc2(u32 module_index, u32 regvalue);
+void nx_lvds_set_lvdsloc3(u32 module_index, u32 regvalue);
+void nx_lvds_set_lvdsloc4(u32 module_index, u32 regvalue);
+void nx_lvds_set_lvdsloc5(u32 module_index, u32 regvalue);
+void nx_lvds_set_lvdsloc6(u32 module_index, u32 regvalue);
+void nx_lvds_set_lvdslocmask0(u32 module_index, u32 regvalue);
+void nx_lvds_set_lvdslocmask1(u32 module_index, u32 regvalue);
+void nx_lvds_set_lvdslocpol0(u32 module_index, u32 regvalue);
+void nx_lvds_set_lvdslocpol1(u32 module_index, u32 regvalue);
+
+void nx_lvds_set_lvdslocpol1(u32 module_index, u32 regvalue);
+
+void nx_lvds_set_lvdsdummy(u32 module_index, u32 regvalue);
+u32 nx_lvds_get_lvdsdummy(u32 module_index);
+
+#endif
--
1.9.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH 07/10] video: add nexell video driver (soc: dpc, makefile)
2020-02-03 19:39 [RFC PATCH 00/10] arm: add support for SoC S5P4418 Stefan Bosch
` (5 preceding siblings ...)
2020-02-03 20:44 ` [RFC PATCH 06/10] video: add nexell video driver (soc: lvds, hdmi) Stefan Bosch
@ 2020-02-03 20:45 ` Stefan Bosch
2020-02-03 20:45 ` [RFC PATCH 08/10] video: add nexell video driver (display/video driver) Stefan Bosch
` (4 subsequent siblings)
11 siblings, 0 replies; 19+ messages in thread
From: Stefan Bosch @ 2020-02-03 20:45 UTC (permalink / raw)
To: u-boot
Low level functions for DPC (Display Controller) and Makefile for all
nexell video low level functions.
Signed-off-by: Stefan Bosch <stefan_b@posteo.net>
---
drivers/video/nexell/soc/Makefile | 11 +
drivers/video/nexell/soc/s5pxx18_soc_dpc.c | 1569 ++++++++++++++++++++++++++++
drivers/video/nexell/soc/s5pxx18_soc_dpc.h | 444 ++++++++
3 files changed, 2024 insertions(+)
create mode 100644 drivers/video/nexell/soc/Makefile
create mode 100644 drivers/video/nexell/soc/s5pxx18_soc_dpc.c
create mode 100644 drivers/video/nexell/soc/s5pxx18_soc_dpc.h
diff --git a/drivers/video/nexell/soc/Makefile b/drivers/video/nexell/soc/Makefile
new file mode 100644
index 0000000..a3036e5
--- /dev/null
+++ b/drivers/video/nexell/soc/Makefile
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2016 Nexell
+# Junghyun, kim<jhkim@nexell.co.kr>
+
+obj-$(CONFIG_VIDEO_NX) += s5pxx18_soc_dpc.o s5pxx18_soc_mlc.o \
+ s5pxx18_soc_disptop.o s5pxx18_soc_disptop_clk.o
+
+obj-$(CONFIG_VIDEO_NX_LVDS) += s5pxx18_soc_lvds.o
+obj-$(CONFIG_VIDEO_NX_MIPI) += s5pxx18_soc_mipi.o
+obj-$(CONFIG_VIDEO_NX_HDMI) += s5pxx18_soc_hdmi.o
diff --git a/drivers/video/nexell/soc/s5pxx18_soc_dpc.c b/drivers/video/nexell/soc/s5pxx18_soc_dpc.c
new file mode 100644
index 0000000..fc15d6b
--- /dev/null
+++ b/drivers/video/nexell/soc/s5pxx18_soc_dpc.c
@@ -0,0 +1,1569 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Nexell Co., Ltd.
+ *
+ * Author: junghyun, kim <jhkim@nexell.co.kr>
+ */
+
+#include <linux/types.h>
+#include <linux/io.h>
+
+#include "s5pxx18_soc_dpc.h"
+
+static struct {
+ struct nx_dpc_register_set *pregister;
+} __g_module_variables[NUMBER_OF_DPC_MODULE] = { { NULL,},};
+
+int nx_dpc_initialize(void)
+{
+ static int binit;
+ u32 i;
+
+ if (binit == 0) {
+ for (i = 0; i < NUMBER_OF_DPC_MODULE; i++)
+ __g_module_variables[i].pregister = NULL;
+ binit = 1;
+ }
+ return 1;
+}
+
+u32 nx_dpc_get_number_of_module(void)
+{
+ return NUMBER_OF_DPC_MODULE;
+}
+
+u32 nx_dpc_get_physical_address(u32 module_index)
+{
+ const u32 physical_addr[] = PHY_BASEADDR_DPC_LIST;
+
+ return physical_addr[module_index];
+}
+
+void nx_dpc_set_base_address(u32 module_index, void *base_address)
+{
+ __g_module_variables[module_index].pregister =
+ (struct nx_dpc_register_set *)base_address;
+}
+
+void *nx_dpc_get_base_address(u32 module_index)
+{
+ return (void *)__g_module_variables[module_index].pregister;
+}
+
+void nx_dpc_set_interrupt_enable(u32 module_index, int32_t int_num, int enable)
+{
+ const u32 intenb_pos = 11;
+ const u32 intenb_mask = 1ul << intenb_pos;
+ const u32 intpend_pos = 10;
+ const u32 intpend_mask = 1ul << intpend_pos;
+
+ register u32 regvalue;
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ regvalue = pregister->dpcctrl0;
+ regvalue &= ~(intenb_mask | intpend_mask);
+ regvalue |= (u32)enable << intenb_pos;
+
+ writel(regvalue, &pregister->dpcctrl0);
+}
+
+int nx_dpc_get_interrupt_enable(u32 module_index, int32_t int_num)
+{
+ const u32 intenb_pos = 11;
+ const u32 intenb_mask = 1ul << intenb_pos;
+
+ return (int)((__g_module_variables[module_index].pregister->dpcctrl0 &
+ intenb_mask) >> intenb_pos);
+}
+
+void nx_dpc_set_interrupt_enable32(u32 module_index, u32 enable_flag)
+{
+ const u32 intenb_pos = 11;
+ const u32 intenb_mask = 1 << intenb_pos;
+ const u32 intpend_pos = 10;
+ const u32 intpend_mask = 1 << intpend_pos;
+
+ register struct nx_dpc_register_set *pregister;
+ register u32 read_value;
+
+ pregister = __g_module_variables[module_index].pregister;
+ read_value = pregister->dpcctrl0 & ~(intpend_mask | intenb_mask);
+
+ writel((u32)(read_value | (enable_flag & 0x01) << intenb_pos),
+ &pregister->dpcctrl0);
+}
+
+u32 nx_dpc_get_interrupt_enable32(u32 module_index)
+{
+ const u32 intenb_pos = 11;
+ const u32 intenb_mask = 1 << intenb_pos;
+
+ return (u32)((__g_module_variables[module_index].pregister->dpcctrl0 &
+ intenb_mask) >> intenb_pos);
+}
+
+int nx_dpc_get_interrupt_pending(u32 module_index, int32_t int_num)
+{
+ const u32 intpend_pos = 10;
+ const u32 intpend_mask = 1ul << intpend_pos;
+
+ return (int)((__g_module_variables[module_index].pregister->dpcctrl0 &
+ intpend_mask) >> intpend_pos);
+}
+
+u32 nx_dpc_get_interrupt_pending32(u32 module_index)
+{
+ const u32 intpend_pos = 10;
+ const u32 intpend_mask = 1 << intpend_pos;
+
+ return (u32)((__g_module_variables[module_index].pregister->dpcctrl0 &
+ intpend_mask) >> intpend_pos);
+}
+
+void nx_dpc_clear_interrupt_pending(u32 module_index, int32_t int_num)
+{
+ const u32 intpend_pos = 10;
+ register struct nx_dpc_register_set *pregister;
+ register u32 regvalue;
+
+ pregister = __g_module_variables[module_index].pregister;
+ regvalue = pregister->dpcctrl0;
+ regvalue |= 1ul << intpend_pos;
+
+ writel(regvalue, &pregister->dpcctrl0);
+}
+
+void nx_dpc_clear_interrupt_pending32(u32 module_index, u32 pending_flag)
+{
+ const u32 intpend_pos = 10;
+ const u32 intpend_mask = 1 << intpend_pos;
+ register struct nx_dpc_register_set *pregister;
+ register u32 read_value;
+
+ pregister = __g_module_variables[module_index].pregister;
+ read_value = pregister->dpcctrl0 & ~intpend_mask;
+
+ writel((u32)(read_value | ((pending_flag & 0x01) << intpend_pos)),
+ &pregister->dpcctrl0);
+}
+
+void nx_dpc_set_interrupt_enable_all(u32 module_index, int enable)
+{
+ const u32 intenb_pos = 11;
+ const u32 intenb_mask = 1ul << intenb_pos;
+ const u32 intpend_pos = 10;
+ const u32 intpend_mask = 1ul << intpend_pos;
+ register u32 regvalue;
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ regvalue = pregister->dpcctrl0;
+ regvalue &= ~(intenb_mask | intpend_mask);
+ regvalue |= (u32)enable << intenb_pos;
+
+ writel(regvalue, &pregister->dpcctrl0);
+}
+
+int nx_dpc_get_interrupt_enable_all(u32 module_index)
+{
+ const u32 intenb_pos = 11;
+ const u32 intenb_mask = 1ul << intenb_pos;
+
+ return (int)((__g_module_variables[module_index].pregister->dpcctrl0 &
+ intenb_mask) >> intenb_pos);
+}
+
+int nx_dpc_get_interrupt_pending_all(u32 module_index)
+{
+ const u32 intpend_pos = 10;
+ const u32 intpend_mask = 1ul << intpend_pos;
+
+ return (int)((__g_module_variables[module_index].pregister->dpcctrl0 &
+ intpend_mask) >> intpend_pos);
+}
+
+void nx_dpc_clear_interrupt_pending_all(u32 module_index)
+{
+ const u32 intpend_pos = 10;
+ register struct nx_dpc_register_set *pregister;
+ register u32 regvalue;
+
+ pregister = __g_module_variables[module_index].pregister;
+ regvalue = pregister->dpcctrl0;
+ regvalue |= 1ul << intpend_pos;
+
+ writel(regvalue, &pregister->dpcctrl0);
+}
+
+int32_t nx_dpc_get_interrupt_pending_number(u32 module_index)
+{
+ const u32 intenb_pos = 11;
+ const u32 intpend_pos = 10;
+ register struct nx_dpc_register_set *pregister;
+ register u32 pend;
+
+ pregister = __g_module_variables[module_index].pregister;
+ pend = ((pregister->dpcctrl0 >> intenb_pos) &&
+ (pregister->dpcctrl0 >> intpend_pos));
+
+ if (pend & 0x01)
+ return 0;
+
+ return -1;
+}
+
+void nx_dpc_set_clock_pclk_mode(u32 module_index, enum nx_pclkmode mode)
+{
+ const u32 pclkmode_pos = 3;
+ register u32 regvalue;
+ register struct nx_dpc_register_set *pregister;
+ u32 clkmode = 0;
+
+ pregister = __g_module_variables[module_index].pregister;
+ switch (mode) {
+ case nx_pclkmode_dynamic:
+ clkmode = 0;
+ break;
+ case nx_pclkmode_always:
+ clkmode = 1;
+ break;
+ default:
+ break;
+ }
+ regvalue = pregister->dpcclkenb;
+ regvalue &= ~(1ul << pclkmode_pos);
+ regvalue |= (clkmode & 0x01) << pclkmode_pos;
+
+ writel(regvalue, &pregister->dpcclkenb);
+}
+
+enum nx_pclkmode nx_dpc_get_clock_pclk_mode(u32 module_index)
+{
+ const u32 pclkmode_pos = 3;
+
+ if (__g_module_variables[module_index].pregister->dpcclkenb &
+ (1ul << pclkmode_pos)) {
+ return nx_pclkmode_always;
+ }
+ return nx_pclkmode_dynamic;
+}
+
+void nx_dpc_set_clock_source(u32 module_index, u32 index, u32 clk_src)
+{
+ const u32 clksrcsel_pos = 2;
+ const u32 clksrcsel_mask = 0x07 << clksrcsel_pos;
+ register struct nx_dpc_register_set *pregister;
+ register u32 read_value;
+
+ pregister = __g_module_variables[module_index].pregister;
+ read_value = pregister->dpcclkgen[index][0];
+ read_value &= ~clksrcsel_mask;
+ read_value |= clk_src << clksrcsel_pos;
+
+ writel(read_value, &pregister->dpcclkgen[index][0]);
+}
+
+u32 nx_dpc_get_clock_source(u32 module_index, u32 index)
+{
+ const u32 clksrcsel_pos = 2;
+ const u32 clksrcsel_mask = 0x07 << clksrcsel_pos;
+
+ return (__g_module_variables[module_index]
+ .pregister->dpcclkgen[index][0] &
+ clksrcsel_mask) >> clksrcsel_pos;
+}
+
+void nx_dpc_set_clock_divisor(u32 module_index, u32 index, u32 divisor)
+{
+ const u32 clkdiv_pos = 5;
+ const u32 clkdiv_mask = ((1 << 8) - 1) << clkdiv_pos;
+ register struct nx_dpc_register_set *pregister;
+ register u32 read_value;
+
+ pregister = __g_module_variables[module_index].pregister;
+ read_value = pregister->dpcclkgen[index][0];
+ read_value &= ~clkdiv_mask;
+ read_value |= (divisor - 1) << clkdiv_pos;
+
+ writel(read_value, &pregister->dpcclkgen[index][0]);
+}
+
+u32 nx_dpc_get_clock_divisor(u32 module_index, u32 index)
+{
+ const u32 clkdiv_pos = 5;
+ const u32 clkdiv_mask = ((1 << 8) - 1) << clkdiv_pos;
+
+ return ((__g_module_variables[module_index]
+ .pregister->dpcclkgen[index][0] &
+ clkdiv_mask) >> clkdiv_pos) + 1;
+}
+
+void nx_dpc_set_clock_out_inv(u32 module_index, u32 index, int out_clk_inv)
+{
+ const u32 outclkinv_pos = 1;
+ const u32 outclkinv_mask = 1ul << outclkinv_pos;
+ register struct nx_dpc_register_set *pregister;
+ register u32 read_value;
+
+ pregister = __g_module_variables[module_index].pregister;
+ read_value = pregister->dpcclkgen[index][0];
+ read_value &= ~outclkinv_mask;
+ read_value |= out_clk_inv << outclkinv_pos;
+
+ writel(read_value, &pregister->dpcclkgen[index][0]);
+}
+
+int nx_dpc_get_clock_out_inv(u32 module_index, u32 index)
+{
+ const u32 outclkinv_pos = 1;
+ const u32 outclkinv_mask = 1ul << outclkinv_pos;
+
+ return (int)((__g_module_variables[module_index]
+ .pregister->dpcclkgen[index][0] &
+ outclkinv_mask) >> outclkinv_pos);
+}
+
+void nx_dpc_set_clock_out_select(u32 module_index, u32 index, int bbypass)
+{
+ const u32 outclksel_pos = 0;
+ const u32 outclksel_mask = 1ul << outclksel_pos;
+ register struct nx_dpc_register_set *pregister;
+ register u32 read_value;
+
+ pregister = __g_module_variables[module_index].pregister;
+ read_value = pregister->dpcclkgen[index][0];
+ read_value &= ~outclksel_mask;
+ if (bbypass == 0)
+ read_value |= outclksel_mask;
+
+ writel(read_value, &pregister->dpcclkgen[index][0]);
+}
+
+int nx_dpc_get_clock_out_select(u32 module_index, u32 index)
+{
+ const u32 outclksel_pos = 0;
+ const u32 outclksel_mask = 1ul << outclksel_pos;
+
+ if (__g_module_variables[module_index].pregister->dpcclkgen[index][0] &
+ outclksel_mask) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+void nx_dpc_set_clock_polarity(u32 module_index, int bpolarity)
+{
+ const u32 clkpol_pos = 2;
+ const u32 clkpol_mask = 1ul << clkpol_pos;
+ register struct nx_dpc_register_set *pregister;
+ register u32 read_value;
+
+ pregister = __g_module_variables[module_index].pregister;
+ read_value = pregister->dpcctrl1;
+ read_value &= ~clkpol_mask;
+ if (bpolarity == 1)
+ read_value |= clkpol_mask;
+
+ writel(read_value, &pregister->dpcctrl1);
+}
+
+int nx_dpc_get_clock_polarity(u32 module_index)
+{
+ const u32 clkpol_pos = 2;
+ const u32 clkpol_mask = 1ul << clkpol_pos;
+
+ if (__g_module_variables[module_index].pregister->dpcctrl1 &
+ clkpol_mask) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+void nx_dpc_set_clock_out_enb(u32 module_index, u32 index, int out_clk_enb)
+{
+ const u32 outclkenb_pos = 15;
+ const u32 outclkenb_mask = 1ul << outclkenb_pos;
+ register struct nx_dpc_register_set *pregister;
+ register u32 read_value;
+
+ pregister = __g_module_variables[module_index].pregister;
+ read_value = pregister->dpcclkgen[index][0];
+ read_value &= ~outclkenb_mask;
+
+ if (out_clk_enb == 1)
+ read_value |= outclkenb_mask;
+
+ writel(read_value, &pregister->dpcclkgen[index][0]);
+}
+
+int nx_dpc_get_clock_out_enb(u32 module_index, u32 index)
+{
+ const u32 outclkenb_pos = 15;
+ const u32 outclkenb_mask = 1ul << outclkenb_pos;
+
+ if (__g_module_variables[module_index].pregister->dpcclkgen[index][0] &
+ outclkenb_mask) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+void nx_dpc_set_clock_out_delay(u32 module_index, u32 index, u32 delay)
+{
+ const u32 outclkdelay_pos = 0;
+ const u32 outclkdelay_mask = 0x1f << outclkdelay_pos;
+ register struct nx_dpc_register_set *pregister;
+ register u32 read_value;
+
+ pregister = __g_module_variables[module_index].pregister;
+ read_value = pregister->dpcclkgen[index][1];
+ read_value &= ~outclkdelay_mask;
+ read_value |= (u32)delay << outclkdelay_pos;
+
+ writel(read_value, &pregister->dpcclkgen[index][1]);
+}
+
+u32 nx_dpc_get_clock_out_delay(u32 module_index, u32 index)
+{
+ register struct nx_dpc_register_set *pregister;
+ const u32 outclkdelay_pos = 0;
+ const u32 outclkdelay_mask = 0x1f << outclkdelay_pos;
+
+ pregister = __g_module_variables[module_index].pregister;
+
+ return (u32)((pregister->dpcclkgen[index][1] & outclkdelay_mask) >>
+ outclkdelay_pos);
+}
+
+void nx_dpc_set_clock_divisor_enable(u32 module_index, int enable)
+{
+ const u32 clkgenenb_pos = 2;
+ const u32 clkgenenb_mask = 1ul << clkgenenb_pos;
+ register struct nx_dpc_register_set *pregister;
+ register u32 read_value;
+
+ pregister = __g_module_variables[module_index].pregister;
+ read_value = pregister->dpcclkenb;
+ read_value &= ~clkgenenb_mask;
+ read_value |= (u32)enable << clkgenenb_pos;
+
+ writel(read_value, &pregister->dpcclkenb);
+}
+
+int nx_dpc_get_clock_divisor_enable(u32 module_index)
+{
+ const u32 clkgenenb_pos = 2;
+ const u32 clkgenenb_mask = 1ul << clkgenenb_pos;
+
+ return (int)((__g_module_variables[module_index].pregister->dpcclkenb &
+ clkgenenb_mask) >> clkgenenb_pos);
+}
+
+void nx_dpc_set_dpc_enable(u32 module_index, int benb)
+{
+ const u32 intpend_pos = 10;
+ const u32 intpend_mask = 1ul << intpend_pos;
+ const u32 dpcenb_pos = 15;
+ const u32 dpcenb_mask = 1ul << dpcenb_pos;
+ register struct nx_dpc_register_set *pregister;
+ register u32 read_value;
+
+ pregister = __g_module_variables[module_index].pregister;
+ read_value = pregister->dpcctrl0;
+ read_value &= ~(intpend_mask | dpcenb_mask);
+ read_value |= (u32)benb << dpcenb_pos;
+
+ writel(read_value, &pregister->dpcctrl0);
+}
+
+int nx_dpc_get_dpc_enable(u32 module_index)
+{
+ const u32 dpcenb_pos = 15;
+ const u32 dpcenb_mask = 1ul << dpcenb_pos;
+
+ return (int)((__g_module_variables[module_index].pregister->dpcctrl0 &
+ dpcenb_mask) >> dpcenb_pos);
+}
+
+void nx_dpc_set_delay(u32 module_index, u32 delay_rgb_pvd, u32 delay_hs_cp1,
+ u32 delay_vs_fram, u32 delay_de_cp2)
+{
+ const u32 intpend_mask = 1u << 10;
+ const u32 delayrgb_pos = 4;
+ const u32 delayrgb_mask = 0xfu << delayrgb_pos;
+ register u32 temp;
+ const u32 delayde_pos = 0;
+ const u32 delayvs_pos = 8;
+ const u32 delayhs_pos = 0;
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ temp = pregister->dpcctrl0;
+ temp &= (u32)~(intpend_mask | delayrgb_mask);
+ temp = (u32)(temp | (delay_rgb_pvd << delayrgb_pos));
+
+ writel(temp, &pregister->dpcctrl0);
+
+ writel((u32)((delay_vs_fram << delayvs_pos) |
+ (delay_hs_cp1 << delayhs_pos)), &pregister->dpcdelay0);
+
+ writel((u32)(delay_de_cp2 << delayde_pos), &pregister->dpcdelay1);
+}
+
+void nx_dpc_get_delay(u32 module_index, u32 *pdelayrgb_pvd, u32 *pdelayhs_cp1,
+ u32 *pdelayvs_fram, u32 *pdelayde_cp2)
+{
+ const u32 delayrgb_pos = 4;
+ const u32 delayrgb_mask = 0xfu << delayrgb_pos;
+ const u32 delayde_pos = 0;
+ const u32 delayde_mask = 0x3fu << delayde_pos;
+ const u32 delayvs_pos = 8;
+ const u32 delayvs_mask = 0x3fu << delayvs_pos;
+ const u32 delayhs_pos = 0;
+ const u32 delayhs_mask = 0x3fu << delayhs_pos;
+ register u32 temp;
+
+ temp = __g_module_variables[module_index].pregister->dpcctrl0;
+ if (pdelayrgb_pvd)
+ *pdelayrgb_pvd = (u32)((temp & delayrgb_mask) >> delayrgb_pos);
+ temp = __g_module_variables[module_index].pregister->dpcdelay0;
+ if (pdelayhs_cp1)
+ *pdelayhs_cp1 = (u32)((temp & delayhs_mask) >> delayhs_pos);
+ if (pdelayvs_fram)
+ *pdelayvs_fram = (u32)((temp & delayvs_mask) >> delayvs_pos);
+ temp = __g_module_variables[module_index].pregister->dpcdelay1;
+ if (pdelayde_cp2)
+ *pdelayde_cp2 = (u32)((temp & delayde_mask) >> delayde_pos);
+}
+
+void nx_dpc_set_dither(u32 module_index, enum nx_dpc_dither dither_r,
+ enum nx_dpc_dither dither_g, enum nx_dpc_dither dither_b)
+{
+ const u32 dither_mask = 0x3fu;
+ const u32 rdither_pos = 0;
+ const u32 gdither_pos = 2;
+ const u32 bdither_pos = 4;
+ register u32 temp;
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ temp = pregister->dpcctrl1;
+ temp &= (u32)~dither_mask;
+ temp = (u32)(temp |
+ ((dither_b << bdither_pos) | (dither_g << gdither_pos) |
+ (dither_r << rdither_pos)));
+
+ writel(temp, &pregister->dpcctrl1);
+}
+
+void nx_dpc_get_dither(u32 module_index, enum nx_dpc_dither *pditherr,
+ enum nx_dpc_dither *pditherg,
+ enum nx_dpc_dither *pditherb)
+{
+ const u32 rdither_pos = 0;
+ const u32 rdither_mask = 0x3u << rdither_pos;
+ const u32 gdither_pos = 2;
+ const u32 gdither_mask = 0x3u << gdither_pos;
+ const u32 bdither_pos = 4;
+ const u32 bdither_mask = 0x3u << bdither_pos;
+ register u32 temp;
+
+ temp = __g_module_variables[module_index].pregister->dpcctrl1;
+ if (pditherr)
+ *pditherr =
+ (enum nx_dpc_dither)((temp & rdither_mask) >> rdither_pos);
+ if (pditherg)
+ *pditherg =
+ (enum nx_dpc_dither)((temp & gdither_mask) >> gdither_pos);
+ if (pditherb)
+ *pditherb =
+ (enum nx_dpc_dither)((temp & bdither_mask) >> bdither_pos);
+}
+
+void nx_dpc_set_mode(u32 module_index, enum nx_dpc_format format,
+ int binterlace, int binvertfield, int brgbmode,
+ int bswaprb, enum nx_dpc_ycorder ycorder, int bclipyc,
+ int bembeddedsync, enum nx_dpc_padclk clock,
+ int binvertclock, int bdualview)
+{
+ const u32 polfield_pos = 2;
+ const u32 seavenb_pos = 8;
+ const u32 scanmode_pos = 9;
+ const u32 intpend_pos = 10;
+ const u32 rgbmode_pos = 12;
+
+ const u32 dither_mask = 0x3f;
+ const u32 ycorder_pos = 6;
+ const u32 format_pos = 8;
+ const u32 ycrange_pos = 13;
+ const u32 swaprb_pos = 15;
+
+ const u32 padclksel_pos = 0;
+ const u32 padclksel_mask = 3u << padclksel_pos;
+ const u32 lcdtype_pos = 7;
+ const u32 lcdtype_mask = 3u << lcdtype_pos;
+ register struct nx_dpc_register_set *pregister;
+ register u32 temp;
+
+ pregister = __g_module_variables[module_index].pregister;
+ temp = pregister->dpcctrl0;
+ temp &= (u32)~(1u << intpend_pos);
+ if (binterlace)
+ temp |= (u32)(1u << scanmode_pos);
+ else
+ temp &= (u32)~(1u << scanmode_pos);
+ if (binvertfield)
+ temp |= (u32)(1u << polfield_pos);
+ else
+ temp &= (u32)~(1u << polfield_pos);
+ if (brgbmode)
+ temp |= (u32)(1u << rgbmode_pos);
+ else
+ temp &= (u32)~(1u << rgbmode_pos);
+ if (bembeddedsync)
+ temp |= (u32)(1u << seavenb_pos);
+ else
+ temp &= (u32)~(1u << seavenb_pos);
+
+ writel(temp, &pregister->dpcctrl0);
+ temp = pregister->dpcctrl1;
+ temp &= (u32)dither_mask;
+ temp = (u32)(temp | (ycorder << ycorder_pos));
+ if (format >= 16) {
+ register u32 temp1;
+
+ temp1 = pregister->dpcctrl2;
+ temp1 = temp1 | (1 << 4);
+ writel(temp1, &pregister->dpcctrl2);
+ } else {
+ register u32 temp1;
+
+ temp1 = pregister->dpcctrl2;
+ temp1 = temp1 & ~(1 << 4);
+ writel(temp1, &pregister->dpcctrl2);
+ }
+ temp = (u32)(temp | ((format & 0xf) << format_pos));
+ if (!bclipyc)
+ temp |= (u32)(1u << ycrange_pos);
+ if (bswaprb)
+ temp |= (u32)(1u << swaprb_pos);
+
+ writel(temp, &pregister->dpcctrl1);
+ temp = pregister->dpcctrl2;
+ temp &= (u32)~(padclksel_mask | lcdtype_mask);
+ temp = (u32)(temp | (clock << padclksel_pos));
+
+ writel(temp, &pregister->dpcctrl2);
+
+ nx_dpc_set_clock_out_inv(module_index, 0, binvertclock);
+ nx_dpc_set_clock_out_inv(module_index, 1, binvertclock);
+}
+
+void nx_dpc_get_mode(u32 module_index, enum nx_dpc_format *pformat,
+ int *pbinterlace, int *pbinvertfield, int *pbrgbmode,
+ int *pbswaprb, enum nx_dpc_ycorder *pycorder,
+ int *pbclipyc, int *pbembeddedsync,
+ enum nx_dpc_padclk *pclock, int *pbinvertclock,
+ int *pbdualview)
+{
+ const u32 polfield = 1u << 2;
+ const u32 seavenb = 1u << 8;
+ const u32 scanmode = 1u << 9;
+ const u32 rgbmode = 1u << 12;
+
+ const u32 ycorder_pos = 6;
+ const u32 ycorder_mask = 0x3u << ycorder_pos;
+ const u32 format_pos = 8;
+ const u32 format_mask = 0xfu << format_pos;
+ const u32 ycrange = 1u << 13;
+ const u32 swaprb = 1u << 15;
+
+ const u32 padclksel_pos = 0;
+ const u32 padclksel_mask = 3u << padclksel_pos;
+ const u32 lcdtype_pos = 7;
+ const u32 lcdtype_mask = 3u << lcdtype_pos;
+ register u32 temp;
+
+ temp = __g_module_variables[module_index].pregister->dpcctrl0;
+ if (pbinterlace)
+ *pbinterlace = (temp & scanmode) ? 1 : 0;
+
+ if (pbinvertfield)
+ *pbinvertfield = (temp & polfield) ? 1 : 0;
+
+ if (pbrgbmode)
+ *pbrgbmode = (temp & rgbmode) ? 1 : 0;
+
+ if (pbembeddedsync)
+ *pbembeddedsync = (temp & seavenb) ? 1 : 0;
+
+ temp = __g_module_variables[module_index].pregister->dpcctrl1;
+
+ if (pycorder)
+ *pycorder =
+ (enum nx_dpc_ycorder)((temp & ycorder_mask) >> ycorder_pos);
+
+ if (pformat)
+ *pformat =
+ (enum nx_dpc_format)((temp & format_mask) >> format_pos);
+ if (pbclipyc)
+ *pbclipyc = (temp & ycrange) ? 0 : 1;
+ if (pbswaprb)
+ *pbswaprb = (temp & swaprb) ? 1 : 0;
+
+ temp = __g_module_variables[module_index].pregister->dpcctrl2;
+
+ if (pclock)
+ *pclock =
+ (enum nx_dpc_padclk)((temp & padclksel_mask) >>
+ padclksel_pos);
+
+ if (pbdualview)
+ *pbdualview = (2 == ((temp & lcdtype_mask) >> lcdtype_pos))
+ ? 1 : 0;
+
+ if (pbinvertclock)
+ *pbinvertclock = nx_dpc_get_clock_out_inv(module_index, 1);
+}
+
+void nx_dpc_set_hsync(u32 module_index, u32 avwidth, u32 hsw, u32 hfp, u32 hbp,
+ int binvhsync)
+{
+ const u32 intpend = 1u << 10;
+ const u32 polhsync = 1u << 0;
+ register u32 temp;
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+
+ writel((u32)(hsw + hbp + avwidth + hfp - 1), &pregister->dpchtotal);
+
+ writel((u32)(hsw - 1), &pregister->dpchswidth);
+
+ writel((u32)(hsw + hbp - 1), &pregister->dpchastart);
+
+ writel((u32)(hsw + hbp + avwidth - 1), &pregister->dpchaend);
+ temp = pregister->dpcctrl0;
+ temp &= ~intpend;
+ if (binvhsync)
+ temp |= (u32)polhsync;
+ else
+ temp &= (u32)~polhsync;
+
+ writel(temp, &pregister->dpcctrl0);
+}
+
+void nx_dpc_get_hsync(u32 module_index, u32 *pavwidth, u32 *phsw, u32 *phfp,
+ u32 *phbp, int *pbinvhsync)
+{
+ const u32 polhsync = 1u << 0;
+ u32 htotal, hsw, hab, hae;
+ u32 avw, hfp, hbp;
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ htotal = (u32)pregister->dpchtotal + 1;
+ hsw = (u32)pregister->dpchswidth + 1;
+ hab = (u32)pregister->dpchastart + 1;
+ hae = (u32)pregister->dpchaend + 1;
+ hbp = hab - hsw;
+ avw = hae - hab;
+ hfp = htotal - hae;
+ if (pavwidth)
+ *pavwidth = avw;
+ if (phsw)
+ *phsw = hsw;
+ if (phfp)
+ *phfp = hfp;
+ if (phbp)
+ *phbp = hbp;
+ if (pbinvhsync)
+ *pbinvhsync = (pregister->dpcctrl0 & polhsync) ? 1 : 0;
+}
+
+void nx_dpc_set_vsync(u32 module_index, u32 avheight, u32 vsw, u32 vfp, u32 vbp,
+ int binvvsync, u32 eavheight, u32 evsw, u32 evfp,
+ u32 evbp)
+{
+ const u32 intpend = 1u << 10;
+ const u32 polvsync = 1u << 1;
+ register u32 temp;
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+
+ writel((u32)(vsw + vbp + avheight + vfp - 1), &pregister->dpcvtotal);
+
+ writel((u32)(vsw - 1), &pregister->dpcvswidth);
+
+ writel((u32)(vsw + vbp - 1), &pregister->dpcvastart);
+
+ writel((u32)(vsw + vbp + avheight - 1), &pregister->dpcvaend);
+
+ writel((u32)(evsw + evbp + eavheight + evfp - 1),
+ &pregister->dpcevtotal);
+
+ writel((u32)(evsw - 1), &pregister->dpcevswidth);
+
+ writel((u32)(evsw + evbp - 1), &pregister->dpcevastart);
+
+ writel((u32)(evsw + evbp + eavheight - 1), &pregister->dpcevaend);
+ temp = pregister->dpcctrl0;
+ temp &= ~intpend;
+ if (binvvsync)
+ temp |= (u32)polvsync;
+ else
+ temp &= (u32)~polvsync;
+
+ writel(temp, &pregister->dpcctrl0);
+}
+
+void nx_dpc_get_vsync(u32 module_index, u32 *pavheight, u32 *pvsw, u32 *pvfp,
+ u32 *pvbp, int *pbinvvsync, u32 *peavheight,
+ u32 *pevsw, u32 *pevfp, u32 *pevbp)
+{
+ const u32 polvsync = 1u << 1;
+ u32 vtotal, vsw, vab, vae;
+ u32 avh, vfp, vbp;
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ vtotal = (u32)pregister->dpcvtotal + 1;
+ vsw = (u32)pregister->dpcvswidth + 1;
+ vab = (u32)pregister->dpcvastart + 1;
+ vae = (u32)pregister->dpcvaend + 1;
+ vbp = vab - vsw;
+ avh = vae - vab;
+ vfp = vtotal - vae;
+ if (pavheight)
+ *pavheight = avh;
+ if (pvsw)
+ *pvsw = vsw;
+ if (pvfp)
+ *pvfp = vfp;
+ if (pvbp)
+ *pvbp = vbp;
+ vtotal = (u32)pregister->dpcevtotal + 1;
+ vsw = (u32)pregister->dpcevswidth + 1;
+ vab = (u32)pregister->dpcevastart + 1;
+ vae = (u32)pregister->dpcevaend + 1;
+ vbp = vab - vsw;
+ avh = vae - vab;
+ vfp = vtotal - vae;
+ if (peavheight)
+ *peavheight = avh;
+ if (pevsw)
+ *pevsw = vsw;
+ if (pevfp)
+ *pevfp = vfp;
+ if (pevbp)
+ *pevbp = vbp;
+ if (pbinvvsync)
+ *pbinvvsync = (pregister->dpcctrl0 & polvsync) ? 1 : 0;
+}
+
+void nx_dpc_set_vsync_offset(u32 module_index, u32 vssoffset, u32 vseoffset,
+ u32 evssoffset, u32 evseoffset)
+{
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+
+ writel((u32)vseoffset, &pregister->dpcvseoffset);
+
+ writel((u32)vssoffset, &pregister->dpcvssoffset);
+
+ writel((u32)evseoffset, &pregister->dpcevseoffset);
+
+ writel((u32)evssoffset, &pregister->dpcevssoffset);
+}
+
+void nx_dpc_get_vsync_offset(u32 module_index, u32 *pvssoffset,
+ u32 *pvseoffset, u32 *pevssoffset,
+ u32 *pevseoffset)
+{
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+
+ if (pvseoffset)
+ *pvseoffset = (u32)pregister->dpcvseoffset;
+
+ if (pvssoffset)
+ *pvssoffset = (u32)pregister->dpcvssoffset;
+
+ if (pevseoffset)
+ *pevseoffset = (u32)pregister->dpcevseoffset;
+
+ if (pevssoffset)
+ *pevssoffset = (u32)pregister->dpcevssoffset;
+}
+
+void nx_dpc_set_horizontal_up_scaler(u32 module_index, int benb,
+ u32 sourcewidth, u32 destwidth)
+{
+ const u32 upscalel_pos = 8;
+ const u32 upscaleh_pos = 0;
+ const u32 upscaleh_mask = ((1 << 15) - 1) << upscaleh_pos;
+ const u32 upscalerenb_pos = 0;
+ register struct nx_dpc_register_set *pregister;
+ register u32 regvalue;
+ register u32 up_scale;
+
+ pregister = __g_module_variables[module_index].pregister;
+ up_scale = ((sourcewidth - 1) * (1 << 11)) / (destwidth - 1);
+ regvalue = 0;
+ regvalue |= (((u32)benb << upscalerenb_pos) |
+ (up_scale & 0xff) << upscalel_pos);
+
+ writel(regvalue, &pregister->dpcupscalecon0);
+
+ writel((up_scale >> 0x08) & upscaleh_mask, &pregister->dpcupscalecon1);
+
+ writel(sourcewidth - 1, &pregister->dpcupscalecon2);
+}
+
+void nx_dpc_get_horizontal_up_scaler(u32 module_index, int *pbenb,
+ u32 *psourcewidth, u32 *pdestwidth)
+{
+ const u32 upscalerenb_pos = 0;
+ const u32 upscalerenb_mask = 1u << upscalerenb_pos;
+ register struct nx_dpc_register_set *pregister;
+
+ u32 up_scale;
+ u32 destwidth, srcwidth;
+
+ pregister = __g_module_variables[module_index].pregister;
+ up_scale = ((u32)(pregister->dpcupscalecon1 & 0x7fff) << 8) |
+ ((u32)(pregister->dpcupscalecon0 >> 8) & 0xff);
+ srcwidth = pregister->dpcupscalecon2;
+ destwidth = (srcwidth * (1 << 11)) / up_scale;
+ if (pbenb)
+ *pbenb = (pregister->dpcupscalecon0 & upscalerenb_mask);
+ if (psourcewidth)
+ *psourcewidth = srcwidth + 1;
+ if (pdestwidth)
+ *pdestwidth = destwidth + 1;
+}
+
+void nx_dpc_set_sync(u32 module_index, enum syncgenmode sync_gen_mode,
+ u32 avwidth, u32 avheight, u32 hsw, u32 hfp, u32 hbp,
+ u32 vsw, u32 vfp, u32 vbp, enum polarity field_polarity,
+ enum polarity hsyncpolarity, enum polarity vsyncpolarity,
+ u32 even_vsw, u32 even_vfp, u32 even_vbp, u32 vsetpixel,
+ u32 vsclrpixel, u32 evenvsetpixel, u32 evenvsclrpixel)
+{
+ register struct nx_dpc_register_set *pregister;
+ u32 regvalue = 0;
+
+ pregister = __g_module_variables[module_index].pregister;
+
+ writel((u32)(hfp + hsw + hbp + avwidth - 1), &pregister->dpchtotal);
+ writel((u32)(hsw - 1), &pregister->dpchswidth);
+ writel((u32)(hsw + hbp - 1), &pregister->dpchastart);
+ writel((u32)(hsw + hbp + avwidth - 1), &pregister->dpchaend);
+ writel((u32)(vfp + vsw + vbp + avheight - 1), &pregister->dpcvtotal);
+ writel((u32)(vsw - 1), &pregister->dpcvswidth);
+ writel((u32)(vsw + vbp - 1), &pregister->dpcvastart);
+ writel((u32)(vsw + vbp + avheight - 1), &pregister->dpcvaend);
+ writel((u32)vsetpixel, &pregister->dpcvseoffset);
+ writel((u32)(hfp + hsw + hbp + avwidth - vsclrpixel - 1),
+ &pregister->dpcvssoffset);
+ writel((u32)evenvsetpixel, &pregister->dpcevseoffset);
+ writel((u32)(hfp + hsw + hbp + avwidth - evenvsclrpixel - 1),
+ &pregister->dpcevssoffset);
+ if (sync_gen_mode == 1) {
+ writel((u32)(even_vfp + even_vsw + even_vbp + avheight - 1),
+ &pregister->dpcevtotal);
+ writel((u32)(even_vsw - 1), &pregister->dpcevswidth);
+ writel((u32)(even_vsw + even_vbp - 1),
+ &pregister->dpcevastart);
+ writel((u32)(even_vsw + even_vbp + avheight - 1),
+ &pregister->dpcevaend);
+ }
+ regvalue = readl(&pregister->dpcctrl0) & 0xfff0ul;
+ regvalue |= (((u32)field_polarity << 2) | ((u32)vsyncpolarity << 1) |
+ ((u32)hsyncpolarity << 0));
+ writel((u32)regvalue, &pregister->dpcctrl0);
+}
+
+void nx_dpc_set_output_format(u32 module_index, enum outputformat output_format,
+ u8 output_video_config)
+{
+ const u32 format_table[] = {
+ (0 << 0), (1 << 0), (2 << 0), (3 << 0), (4 << 0), (5 << 0),
+ (6 << 0), (7 << 0), (8 << 0), (9 << 0), (0 << 0) | (1 << 7),
+ (1 << 0) | (1 << 7), (2 << 0) | (1 << 7), (3 << 0) | (1 << 7),
+ (4 << 0) | (1 << 7), (5 << 0) | (1 << 7), (6 << 0) | (1 << 7),
+ (7 << 0) | (1 << 7), (8 << 0) | (1 << 7), (9 << 0) | (1 << 7),
+ (10 << 0), (11 << 0), (12 << 0), (13 << 0), (14 << 0), (15 << 0)
+ };
+ u32 regvalue;
+ u32 regvalue0;
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ regvalue = readl(&pregister->dpcctrl1) & 0x30fful;
+
+ regvalue |= (format_table[output_format] << 8);
+ writel((u32)regvalue, &pregister->dpcctrl1);
+ regvalue0 = (u32)(readl(&pregister->dpcctrl1) & 0xff3f);
+ regvalue0 = (u32)((output_video_config << 6) | regvalue0);
+ writel((u32)regvalue0, &pregister->dpcctrl1);
+}
+
+void nx_dpc_set_quantization_mode(u32 module_index, enum qmode rgb2yc,
+ enum qmode yc2rgb)
+{
+ register struct nx_dpc_register_set *pregister;
+ u32 regvalue;
+
+ pregister = __g_module_variables[module_index].pregister;
+ regvalue = readl(&pregister->dpcctrl1) & 0x8ffful;
+ regvalue |= ((u32)rgb2yc << 13) | ((u32)yc2rgb << 12);
+ writel((u32)regvalue, &pregister->dpcctrl1);
+}
+
+void nx_dpc_set_enable(u32 module_index, int enable, int rgbmode,
+ int use_ntscsync, int use_analog_output, int seavenable)
+{
+ u32 regvalue;
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ regvalue = readl(&pregister->dpcctrl0) & 0x0efful;
+ regvalue |= ((u32)enable << 15) | ((u32)use_ntscsync << 14) |
+ ((u32)seavenable << 8) | ((u32)use_analog_output << 13) |
+ ((u32)rgbmode << 12);
+ writel((u32)regvalue, &pregister->dpcctrl0);
+}
+
+void nx_dpc_set_out_video_clk_select(u32 module_index,
+ enum outpadclksel out_pad_vclk_sel)
+{
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+
+ writel((u32)((readl(&pregister->dpcctrl2)) | (out_pad_vclk_sel & 0x3)),
+ &pregister->dpcctrl2);
+}
+
+void nx_dpc_set_reg_flush(u32 module_index)
+{
+ u32 reg;
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ reg = readl(&pregister->dpcdataflush);
+ writel((u32)(reg | (1ul << 4)), &pregister->dpcdataflush);
+}
+
+void nx_dpc_set_sramon(u32 module_index)
+{
+ u32 reg;
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ reg = (u32)(readl(&pregister->dpcctrl2) & 0xf3ff);
+ writel((u32)(reg | (1ul << 10)), &pregister->dpcctrl2);
+ reg = (u32)(readl(&pregister->dpcctrl2) & 0xf7ff);
+ writel((u32)(reg | (1ul << 11)), &pregister->dpcctrl2);
+}
+
+void nx_dpc_set_sync_lcdtype(u32 module_index, int stnlcd, int dual_view_enb,
+ int bit_widh, u8 cpcycle)
+{
+ u32 reg;
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+
+ reg = (u32)(readl(&pregister->dpcctrl2) & 0xc0f);
+ writel((u32)(reg | (cpcycle << 12) | (bit_widh << 9) |
+ (dual_view_enb << 8) | (stnlcd << 7)),
+ &pregister->dpcctrl2);
+}
+
+void nx_dpc_set_up_scale_control(u32 module_index, int up_scale_enb,
+ int filter_enb, u32 hscale, u16 source_width)
+{
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ writel((u32)((hscale << 8) | ((u32)filter_enb << 1) | (up_scale_enb)),
+ &pregister->dpcupscalecon0);
+ writel((u32)(hscale >> 8), &pregister->dpcupscalecon1);
+ writel(source_width, &pregister->dpcupscalecon2);
+}
+
+void nx_dpc_set_mputime(u32 module_index, u8 setup, u8 hold, u8 acc)
+{
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ writel((u32)((setup << 8) | (hold & 0xff)), &pregister->dpcmputime0);
+ writel((u32)(acc), &pregister->dpcmputime1);
+}
+
+void nx_dpc_set_index(u32 module_index, u32 index)
+{
+ u32 regvalue;
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ writel((u32)(index & 0xffff), &pregister->dpcmpuwrdatal);
+ writel((u32)((index >> 16) & 0xff), &pregister->dpcmpuindex);
+ if (index == 0x22) {
+ regvalue = readl(&pregister->dpcctrl2);
+ writel((regvalue | 0x10), &pregister->dpcctrl2);
+ }
+}
+
+void nx_dpc_set_data(u32 module_index, u32 data)
+{
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ writel((u32)(data & 0xffff), &pregister->dpcmpuwrdatal);
+ writel((u32)((data >> 16) & 0xff), &pregister->dpcmpudatah);
+}
+
+void nx_dpc_set_cmd_buffer_flush(u32 module_index)
+{
+ u32 reg;
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ reg = readl(&pregister->dpcdataflush);
+ writel((u32)(reg | (1 << 1)), &pregister->dpcdataflush);
+}
+
+void nx_dpc_set_cmd_buffer_clear(u32 module_index)
+{
+ u32 reg;
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ reg = readl(&pregister->dpcdataflush);
+ writel((u32)(reg | (1 << 0)), &pregister->dpcdataflush);
+}
+
+void nx_dpc_set_cmd_buffer_write(u32 module_index, u32 cmd_data)
+{
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ writel((u32)(cmd_data & 0xffff), &pregister->dpccmdbufferdatal);
+ writel((u32)(cmd_data >> 16), &pregister->dpccmdbufferdatah);
+}
+
+void nx_dpc_set(u32 module_index)
+{
+ u32 reg;
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ reg = readl(&pregister->dpcpolctrl);
+ writel((u32)(reg | 0x1), &pregister->dpcpolctrl);
+}
+
+u32 nx_dpc_get_data(u32 module_index)
+{
+ u32 reg = 0;
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ reg = readl(&pregister->dpcmpudatah);
+ reg = (reg << 16) | readl(&pregister->dpcmpurdatal);
+ return reg;
+}
+
+u32 nx_dpc_get_status(u32 module_index)
+{
+ u32 reg = 0;
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ reg = readl(&pregister->dpcmpustatus);
+ reg = (reg << 16) | readl(&pregister->dpcmpurdatal);
+ return reg;
+}
+
+void nx_dpc_rgbmask(u32 module_index, u32 rgbmask)
+{
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ writel((rgbmask >> 0) & 0xffff, &pregister->dpcrgbmask[0]);
+ writel((rgbmask >> 16) & 0x00ff, &pregister->dpcrgbmask[1]);
+}
+
+void nx_dpc_set_pad_location(u32 module_index, u32 index, u32 regvalue)
+{
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ writel(regvalue, &pregister->dpcpadposition[index]);
+}
+
+u32 nx_dpc_get_field_flag(u32 module_index)
+{
+ register struct nx_dpc_register_set *pregister;
+ u32 regvalue;
+
+ pregister = __g_module_variables[module_index].pregister;
+ regvalue = readl(&pregister->dpcrgbshift);
+
+ return (u32)((regvalue >> 5) & 0x01);
+}
+
+void nx_dpc_set_enable_with_interlace(u32 module_index, int enable, int rgbmode,
+ int use_ntscsync, int use_analog_output,
+ int seavenable)
+{
+ u32 regvalue;
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ regvalue = readl(&pregister->dpcctrl0) & 0x0eff;
+ regvalue = readl(&pregister->dpcctrl0) & 0x0eff;
+ regvalue |= ((u32)enable << 15) | ((u32)use_ntscsync << 14) |
+ ((u32)seavenable << 8) | ((u32)use_analog_output << 13) |
+ ((u32)rgbmode << 12);
+
+ regvalue |= (1 << 9);
+ writel((u16)regvalue, &pregister->dpcctrl0);
+}
+
+void nx_dpc_set_encoder_control_reg(u32 module_index, u32 param_a, u32 param_b,
+ u32 param_c)
+{
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ writel(param_a, &pregister->ntsc_ecmda);
+ writel(param_b, &pregister->ntsc_ecmdb);
+ writel(param_c, &pregister->ntsc_ecmdc);
+}
+
+void nx_dpc_set_encoder_shcphase_control(u32 module_index, u32 chroma_param)
+{
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ writel(chroma_param, &pregister->ntsc_sch);
+}
+
+void nx_dpc_set_encoder_timing_config_reg(u32 module_index, u32 icntl)
+{
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ writel(icntl, &pregister->ntsc_icntl);
+}
+
+void nx_dpc_set_encoder_dacoutput_select(u32 module_index, u8 dacsel0,
+ u8 dacsel1, u8 dacsel2, u8 dacsel3,
+ u8 dacsel4, u8 dacsel5)
+{
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ writel(((dacsel1 & 0xf) << 4) | (dacsel0 & 0xf),
+ &pregister->ntsc_dacsel10);
+ writel(((dacsel3 & 0xf) << 4) | (dacsel2 & 0xf),
+ &pregister->ntsc_dacsel32);
+ writel(((dacsel5 & 0xf) << 4) | (dacsel4 & 0xf),
+ &pregister->ntsc_dacsel54);
+}
+
+void nx_dpc_set_encoder_sync_location(u32 module_index, u16 hsoe, u16 hsob,
+ u16 vsob, u16 vsoe, u8 vsost, int novrst)
+{
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ writel((u16)((((vsob & 0x100) >> 2) | ((hsob & 0x700) >> 5) |
+ (hsoe & 0x700) >> 8)), &pregister->ntsc_hsvso);
+ writel((u16)(hsoe & 0xff), &pregister->ntsc_hsoe);
+ writel((u16)(hsob & 0xff), &pregister->ntsc_hsob);
+ writel((u16)(vsob & 0xff), &pregister->ntsc_vsob);
+ writel((u16)(((vsost & 0x3) << 6) | (novrst << 5) | (vsoe & 0x1f)),
+ &pregister->ntsc_vsoe);
+}
+
+void nx_dpc_set_encoder_dacpower_enable(u32 module_index, u8 dacpd)
+{
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ writel(dacpd, &pregister->ntsc_dacpd);
+}
+
+void nx_dpc_set_ycorder(u32 module_index, enum nx_dpc_ycorder ycorder)
+{
+ const u16 ycorder_pos = 6;
+ register struct nx_dpc_register_set *pregister;
+ u32 temp;
+
+ pregister = __g_module_variables[module_index].pregister;
+ temp = pregister->dpcctrl1 & (~(0xf << ycorder_pos));
+ temp = (u16)(temp | (ycorder << ycorder_pos));
+ writel(temp, &pregister->dpcctrl1);
+}
+
+void nx_dpc_set_luma_gain(u32 module_index, u32 luma_gain)
+{
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ writel(luma_gain, &pregister->ntsc_cont);
+}
+
+void nx_dpc_set_encenable(u32 module_index, int benb)
+{
+ const u16 encmode = 1u << 14;
+ const u16 encrst = 1u << 13;
+ const u16 intpend = 1u << 10;
+ register struct nx_dpc_register_set *pregister;
+ register u16 temp;
+
+ pregister = __g_module_variables[module_index].pregister;
+ temp = readl(&pregister->dpcctrl0);
+ temp &= (u16)~intpend;
+ if (benb)
+ temp |= (u16)encrst;
+ else
+ temp &= (u16)~encrst;
+ writel((temp | encmode), &pregister->dpcctrl0);
+ writel(7, &pregister->ntsc_icntl);
+}
+
+int nx_dpc_get_encenable(u32 module_index)
+{
+ const u16 encrst = 1u << 13;
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ return (readl(&pregister->dpcctrl0) & encrst) ? 1 : 0;
+}
+
+void nx_dpc_set_video_encoder_power_down(u32 module_index, int benb)
+{
+ const u16 pwdenc = 1u << 7;
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ if (benb) {
+ writel(readl(&pregister->ntsc_ecmda) | (u16)pwdenc,
+ &pregister->ntsc_ecmda);
+ writel(0, &pregister->ntsc_dacsel10);
+ } else {
+ writel(1, &pregister->ntsc_dacsel10);
+ writel(readl(&pregister->ntsc_ecmda) & (u16)~pwdenc,
+ &pregister->ntsc_ecmda);
+ }
+}
+
+int nx_dpc_get_video_encoder_power_down(u32 module_index)
+{
+ const u16 pwdenc = 1u << 7;
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ return (readl(&pregister->ntsc_ecmda) & pwdenc) ? 1 : 0;
+}
+
+void nx_dpc_set_video_encoder_mode(u32 module_index, enum nx_dpc_vbs vbs,
+ int bpedestal)
+{
+ register struct nx_dpc_register_set *pregister;
+
+#define phalt (1u << 0)
+#define ifmt (1u << 1)
+#define ped (1u << 3)
+#define fscsel_ntsc (0u << 4)
+#define fscsel_pal (1u << 4)
+#define fscsel_palm (2u << 4)
+#define fscsel_paln (3u << 4)
+#define fdrst (1u << 6)
+#define pwdenc (1u << 7)
+ register u16 temp;
+ static const u8 ntsc_ecmda_table[] = {
+ (u8)(fscsel_ntsc | fdrst), (u8)(ifmt | fscsel_ntsc),
+ (u8)(fscsel_pal), (u8)(fscsel_palm | phalt),
+ (u8)(ifmt | fscsel_paln | phalt),
+ (u8)(ifmt | fscsel_pal | phalt | fdrst),
+ (u8)(fscsel_pal | phalt),
+ (u8)(ifmt | fscsel_ntsc)
+ };
+ pregister = __g_module_variables[module_index].pregister;
+ temp = readl(&pregister->ntsc_ecmda);
+ temp &= (u16)pwdenc;
+ temp = (u16)(temp | (u16)ntsc_ecmda_table[vbs]);
+ if (bpedestal)
+ temp |= (u16)ped;
+ writel(temp, &pregister->ntsc_ecmda);
+#undef phalt
+#undef ifmt
+#undef ped
+#undef fscsel_ntsc
+#undef fscsel_pal
+#undef fscsel_palm
+#undef fscsel_paln
+#undef fdrst
+#undef pwdenc
+}
+
+void nx_dpc_set_video_encoder_schlock_control(u32 module_index, int bfreerun)
+{
+ const u16 fdrst = 1u << 6;
+ register struct nx_dpc_register_set *pregister;
+ register u16 temp;
+
+ pregister = __g_module_variables[module_index].pregister;
+ temp = readl(&pregister->ntsc_ecmda);
+ if (bfreerun)
+ temp |= (u16)fdrst;
+ else
+ temp &= (u16)~fdrst;
+ writel(temp, &pregister->ntsc_ecmda);
+}
+
+int nx_dpc_get_video_encoder_schlock_control(u32 module_index)
+{
+ const u16 fdrst = 1u << 6;
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ return (readl(&pregister->ntsc_ecmda) & fdrst) ? 1 : 0;
+}
+
+void nx_dpc_set_video_encoder_bandwidth(u32 module_index,
+ enum nx_dpc_bandwidth luma,
+ enum nx_dpc_bandwidth chroma)
+{
+ const u16 ybw_pos = 0;
+ const u16 cbw_pos = 2;
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ writel((u16)((chroma << cbw_pos) | (luma << ybw_pos)),
+ &pregister->ntsc_ecmdb);
+}
+
+void nx_dpc_get_video_encoder_bandwidth(u32 module_index,
+ enum nx_dpc_bandwidth *pluma,
+ enum nx_dpc_bandwidth *pchroma)
+{
+ const u16 ybw_pos = 0;
+ const u16 ybw_mask = 3u << ybw_pos;
+ const u16 cbw_pos = 2;
+ const u16 cbw_mask = 3u << cbw_pos;
+ register struct nx_dpc_register_set *pregister;
+ register u16 temp;
+
+ pregister = __g_module_variables[module_index].pregister;
+ temp = readl(&pregister->ntsc_ecmdb);
+ if (pluma)
+ *pluma = (enum nx_dpc_bandwidth)((temp & ybw_mask) >> ybw_pos);
+ if (pchroma)
+ *pchroma =
+ (enum nx_dpc_bandwidth)((temp & cbw_mask) >> cbw_pos);
+}
+
+void nx_dpc_set_video_encoder_color_control(u32 module_index, s8 sch,
+ s8 hue, s8 sat, s8 crt,
+ s8 brt)
+{
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ writel((u16)sch, &pregister->ntsc_sch);
+ writel((u16)hue, &pregister->ntsc_hue);
+ writel((u16)sat, &pregister->ntsc_sat);
+ writel((u16)crt, &pregister->ntsc_cont);
+ writel((u16)brt, &pregister->ntsc_bright);
+}
+
+void nx_dpc_get_video_encoder_color_control(u32 module_index, s8 *psch,
+ s8 *phue, s8 *psat,
+ s8 *pcrt, s8 *pbrt)
+{
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ if (psch)
+ *psch = (s8)readl(&pregister->ntsc_sch);
+ if (phue)
+ *phue = (s8)readl(&pregister->ntsc_hue);
+ if (psat)
+ *psat = (s8)readl(&pregister->ntsc_sat);
+ if (pcrt)
+ *pcrt = (s8)readl(&pregister->ntsc_cont);
+ if (pbrt)
+ *pbrt = (s8)readl(&pregister->ntsc_bright);
+}
+
+void nx_dpc_set_video_encoder_fscadjust(u32 module_index, int16_t adjust)
+{
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ writel((u16)(adjust >> 8), &pregister->ntsc_fsc_adjh);
+ writel((u16)(adjust & 0xff), &pregister->ntsc_fsc_adjl);
+}
+
+u16 nx_dpc_get_video_encoder_fscadjust(u32 module_index)
+{
+ register u32 temp;
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ temp = (u32)readl(&pregister->ntsc_fsc_adjh);
+ temp <<= 8;
+ temp |= (((u32)readl(&pregister->ntsc_fsc_adjl)) & 0xff);
+ return (u16)temp;
+}
+
+void nx_dpc_set_video_encoder_timing(u32 module_index, u32 hsos, u32 hsoe,
+ u32 vsos, u32 vsoe)
+{
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ hsos -= 1;
+ hsoe -= 1;
+ writel((u16)((((vsos >> 8) & 1u) << 6) | (((hsos >> 8) & 7u) << 3) |
+ (((hsoe >> 8) & 7u) << 0)), &pregister->ntsc_hsvso);
+ writel((u16)(hsos & 0xffu), &pregister->ntsc_hsob);
+ writel((u16)(hsoe & 0xffu), &pregister->ntsc_hsoe);
+ writel((u16)(vsos & 0xffu), &pregister->ntsc_vsob);
+ writel((u16)(vsoe & 0x1fu), &pregister->ntsc_vsoe);
+}
+
+void nx_dpc_get_video_encoder_timing(u32 module_index, u32 *phsos, u32 *phsoe,
+ u32 *pvsos, u32 *pvsoe)
+{
+ register u16 hsvso;
+ register struct nx_dpc_register_set *pregister;
+
+ pregister = __g_module_variables[module_index].pregister;
+ hsvso = readl(&pregister->ntsc_hsvso);
+ if (phsos)
+ *phsos = (u32)((((hsvso >> 3) & 7u) << 8) |
+ (readl(&pregister->ntsc_hsob) & 0xffu)) + 1;
+ if (phsoe)
+ *phsoe = (u32)((((hsvso >> 0) & 7u) << 8) |
+ (readl(&pregister->ntsc_hsoe) & 0xffu)) + 1;
+ if (pvsos)
+ *pvsos = (u32)((((hsvso >> 6) & 1u) << 8) |
+ (readl(&pregister->ntsc_vsob) & 0xffu));
+ if (pvsoe)
+ *pvsoe = (u32)(readl(&pregister->ntsc_vsoe) & 0x1fu);
+}
diff --git a/drivers/video/nexell/soc/s5pxx18_soc_dpc.h b/drivers/video/nexell/soc/s5pxx18_soc_dpc.h
new file mode 100644
index 0000000..cfa53c3
--- /dev/null
+++ b/drivers/video/nexell/soc/s5pxx18_soc_dpc.h
@@ -0,0 +1,444 @@
+/* SPDX-License-Identifier: GPL-2.0+
+ *
+ * Copyright (C) 2016 Nexell Co., Ltd.
+ *
+ * Author: junghyun, kim <jhkim@nexell.co.kr>
+ */
+
+#ifndef _S5PXX18_SOC_DPC_H_
+#define _S5PXX18_SOC_DPC_H_
+
+#include "s5pxx18_soc_disptype.h"
+
+#define IRQ_OFFSET 32
+#define IRQ_DPC_P (IRQ_OFFSET + 33)
+#define IRQ_DPC_S (IRQ_OFFSET + 34)
+
+#define NUMBER_OF_DPC_MODULE 2
+#define PHY_BASEADDR_DPC0 0xC0102800
+#define PHY_BASEADDR_DPC1 0xC0102C00
+
+#define PHY_BASEADDR_DPC_LIST \
+ { PHY_BASEADDR_DPC0, PHY_BASEADDR_DPC1 }
+
+struct nx_dpc_register_set {
+ u32 ntsc_stata;
+ u32 ntsc_ecmda;
+ u32 ntsc_ecmdb;
+ u32 ntsc_glk;
+ u32 ntsc_sch;
+ u32 ntsc_hue;
+ u32 ntsc_sat;
+ u32 ntsc_cont;
+ u32 ntsc_bright;
+ u32 ntsc_fsc_adjh;
+ u32 ntsc_fsc_adjl;
+ u32 ntsc_ecmdc;
+ u32 ntsc_csdly;
+ u32 __ntsc_reserved_0_[3];
+ u32 ntsc_dacsel10;
+ u32 ntsc_dacsel32;
+ u32 ntsc_dacsel54;
+ u32 ntsc_daclp;
+ u32 ntsc_dacpd;
+ u32 __ntsc_reserved_1_[(0x20 - 0x15)];
+ u32 ntsc_icntl;
+ u32 ntsc_hvoffst;
+ u32 ntsc_hoffst;
+ u32 ntsc_voffset;
+ u32 ntsc_hsvso;
+ u32 ntsc_hsob;
+ u32 ntsc_hsoe;
+ u32 ntsc_vsob;
+ u32 ntsc_vsoe;
+ u32 __reserved[(0xf8 / 4) - 0x29];
+ u32 dpchtotal;
+ u32 dpchswidth;
+ u32 dpchastart;
+ u32 dpchaend;
+ u32 dpcvtotal;
+ u32 dpcvswidth;
+ u32 dpcvastart;
+ u32 dpcvaend;
+ u32 dpcctrl0;
+ u32 dpcctrl1;
+ u32 dpcevtotal;
+ u32 dpcevswidth;
+ u32 dpcevastart;
+ u32 dpcevaend;
+ u32 dpcctrl2;
+ u32 dpcvseoffset;
+ u32 dpcvssoffset;
+ u32 dpcevseoffset;
+ u32 dpcevssoffset;
+ u32 dpcdelay0;
+ u32 dpcupscalecon0;
+ u32 dpcupscalecon1;
+ u32 dpcupscalecon2;
+
+ u32 dpcrnumgencon0;
+ u32 dpcrnumgencon1;
+ u32 dpcrnumgencon2;
+ u32 dpcrndconformula_l;
+ u32 dpcrndconformula_h;
+ u32 dpcfdtaddr;
+ u32 dpcfrdithervalue;
+ u32 dpcfgdithervalue;
+ u32 dpcfbdithervalue;
+ u32 dpcdelay1;
+ u32 dpcmputime0;
+ u32 dpcmputime1;
+ u32 dpcmpuwrdatal;
+ u32 dpcmpuindex;
+ u32 dpcmpustatus;
+ u32 dpcmpudatah;
+ u32 dpcmpurdatal;
+ u32 dpcdummy12;
+ u32 dpccmdbufferdatal;
+ u32 dpccmdbufferdatah;
+ u32 dpcpolctrl;
+ u32 dpcpadposition[8];
+ u32 dpcrgbmask[2];
+ u32 dpcrgbshift;
+ u32 dpcdataflush;
+ u32 __reserved06[((0x3c0) - (2 * 0x0ec)) / 4];
+
+ u32 dpcclkenb;
+ u32 dpcclkgen[2][2];
+};
+
+enum {
+ nx_dpc_int_vsync = 0
+};
+
+enum nx_dpc_format {
+ nx_dpc_format_rgb555 = 0ul,
+ nx_dpc_format_rgb565 = 1ul,
+ nx_dpc_format_rgb666 = 2ul,
+ nx_dpc_format_rgb666b = 18ul,
+ nx_dpc_format_rgb888 = 3ul,
+ nx_dpc_format_mrgb555a = 4ul,
+ nx_dpc_format_mrgb555b = 5ul,
+ nx_dpc_format_mrgb565 = 6ul,
+ nx_dpc_format_mrgb666 = 7ul,
+ nx_dpc_format_mrgb888a = 8ul,
+ nx_dpc_format_mrgb888b = 9ul,
+ nx_dpc_format_ccir656 = 10ul,
+ nx_dpc_format_ccir601a = 12ul,
+ nx_dpc_format_ccir601b = 13ul,
+ nx_dpc_format_srgb888 = 14ul,
+ nx_dpc_format_srgbd8888 = 15ul,
+ nx_dpc_format_4096color = 1ul,
+ nx_dpc_format_16gray = 3ul
+};
+
+enum nx_dpc_ycorder {
+ nx_dpc_ycorder_cb_ycr_y = 0ul,
+ nx_dpc_ycorder_cr_ycb_y = 1ul,
+ nx_dpc_ycorder_ycbycr = 2ul,
+ nx_dpc_ycorder_ycrycb = 3ul
+};
+
+enum nx_dpc_padclk {
+ nx_dpc_padclk_vclk = 0ul,
+ nx_dpc_padclk_vclk2 = 1ul,
+ nx_dpc_padclk_vclk3 = 2ul
+};
+
+enum nx_dpc_dither {
+ nx_dpc_dither_bypass = 0ul,
+ nx_dpc_dither_4bit = 1ul,
+ nx_dpc_dither_5bit = 2ul,
+ nx_dpc_dither_6bit = 3ul
+};
+
+enum nx_dpc_vbs {
+ nx_dpc_vbs_ntsc_m = 0ul,
+ nx_dpc_vbs_ntsc_n = 1ul,
+ nx_dpc_vbs_ntsc_443 = 2ul,
+ nx_dpc_vbs_pal_m = 3ul,
+ nx_dpc_vbs_pal_n = 4ul,
+ nx_dpc_vbs_pal_bghi = 5ul,
+ nx_dpc_vbs_pseudo_pal = 6ul,
+ nx_dpc_vbs_pseudo_ntsc = 7ul
+};
+
+enum nx_dpc_bandwidth {
+ nx_dpc_bandwidth_low = 0ul,
+ nx_dpc_bandwidth_medium = 1ul,
+ nx_dpc_bandwidth_high = 2ul
+};
+
+int nx_dpc_initialize(void);
+u32 nx_dpc_get_number_of_module(void);
+u32 nx_dpc_get_physical_address(u32 module_index);
+u32 nx_dpc_get_size_of_register_set(void);
+void nx_dpc_set_base_address(u32 module_index, void *base_address);
+void *nx_dpc_get_base_address(u32 module_index);
+int nx_dpc_open_module(u32 module_index);
+int nx_dpc_close_module(u32 module_index);
+int nx_dpc_check_busy(u32 module_index);
+int nx_dpc_can_power_down(u32 module_index);
+int32_t nx_dpc_get_interrupt_number(u32 module_index);
+void nx_dpc_set_interrupt_enable(u32 module_index, int32_t int_num,
+ int enable);
+int nx_dpc_get_interrupt_enable(u32 module_index, int32_t int_num);
+int nx_dpc_get_interrupt_pending(u32 module_index, int32_t int_num);
+void nx_dpc_clear_interrupt_pending(u32 module_index, int32_t int_num);
+void nx_dpc_set_interrupt_enable_all(u32 module_index, int enable);
+int nx_dpc_get_interrupt_enable_all(u32 module_index);
+int nx_dpc_get_interrupt_pending_all(u32 module_index);
+void nx_dpc_clear_interrupt_pending_all(u32 module_index);
+void nx_dpc_set_interrupt_enable32(u32 module_index, u32 enable_flag);
+u32 nx_dpc_get_interrupt_enable32(u32 module_index);
+u32 nx_dpc_get_interrupt_pending32(u32 module_index);
+void nx_dpc_clear_interrupt_pending32(u32 module_index,
+ u32 pending_flag);
+int32_t nx_dpc_get_interrupt_pending_number(u32 module_index);
+void nx_dpc_set_clock_pclk_mode(u32 module_index, enum nx_pclkmode mode);
+enum nx_pclkmode nx_dpc_get_clock_pclk_mode(u32 module_index);
+void nx_dpc_set_clock_source(u32 module_index, u32 index, u32 clk_src);
+u32 nx_dpc_get_clock_source(u32 module_index, u32 index);
+void nx_dpc_set_clock_divisor(u32 module_index, u32 index, u32 divisor);
+u32 nx_dpc_get_clock_divisor(u32 module_index, u32 index);
+void nx_dpc_set_clock_out_inv(u32 module_index, u32 index,
+ int out_clk_inv);
+int nx_dpc_get_clock_out_inv(u32 module_index, u32 index);
+void nx_dpc_set_clock_out_select(u32 module_index, u32 index,
+ int bbypass);
+int nx_dpc_get_clock_out_select(u32 module_index, u32 index);
+void nx_dpc_set_clock_polarity(u32 module_index, int bpolarity);
+int nx_dpc_get_clock_polarity(u32 module_index);
+void nx_dpc_set_clock_out_enb(u32 module_index, u32 index,
+ int out_clk_enb);
+int nx_dpc_get_clock_out_enb(u32 module_index, u32 index);
+void nx_dpc_set_clock_out_delay(u32 module_index, u32 index, u32 delay);
+u32 nx_dpc_get_clock_out_delay(u32 module_index, u32 index);
+void nx_dpc_set_clock_divisor_enable(u32 module_index, int enable);
+int nx_dpc_get_clock_divisor_enable(u32 module_index);
+
+void nx_dpc_set_dpc_enable(u32 module_index, int benb);
+int nx_dpc_get_dpc_enable(u32 module_index);
+void nx_dpc_set_delay(u32 module_index, u32 delay_rgb_pvd,
+ u32 delay_hs_cp1, u32 delay_vs_fram,
+ u32 delay_de_cp2);
+void nx_dpc_get_delay(u32 module_index, u32 *pdelayrgb_pvd,
+ u32 *pdelayhs_cp1, u32 *pdelayvs_fram,
+ u32 *pdelayde_cp2);
+void nx_dpc_set_dither(u32 module_index, enum nx_dpc_dither dither_r,
+ enum nx_dpc_dither dither_g,
+ enum nx_dpc_dither dither_b);
+void nx_dpc_get_dither(u32 module_index, enum nx_dpc_dither *pditherr,
+ enum nx_dpc_dither *pditherg,
+ enum nx_dpc_dither *pditherb);
+void nx_dpc_set_horizontal_up_scaler(u32 module_index, int benb,
+ u32 sourcewidth, u32 destwidth);
+void nx_dpc_get_horizontal_up_scaler(u32 module_index, int *pbenb,
+ u32 *psourcewidth,
+ u32 *pdestwidth);
+
+void nx_dpc_set_mode(u32 module_index, enum nx_dpc_format format,
+ int binterlace, int binvertfield, int brgbmode,
+ int bswaprb, enum nx_dpc_ycorder ycorder,
+ int bclipyc, int bembeddedsync,
+ enum nx_dpc_padclk clock, int binvertclock,
+ int bdualview);
+void nx_dpc_get_mode(u32 module_index, enum nx_dpc_format *pformat,
+ int *pbinterlace, int *pbinvertfield,
+ int *pbrgbmode, int *pbswaprb,
+ enum nx_dpc_ycorder *pycorder, int *pbclipyc,
+ int *pbembeddedsync, enum nx_dpc_padclk *pclock,
+ int *pbinvertclock, int *pbdualview);
+void nx_dpc_set_hsync(u32 module_index, u32 avwidth, u32 hsw, u32 hfp,
+ u32 hbp, int binvhsync);
+void nx_dpc_get_hsync(u32 module_index, u32 *pavwidth, u32 *phsw,
+ u32 *phfp, u32 *phbp, int *pbinvhsync);
+void nx_dpc_set_vsync(u32 module_index, u32 avheight, u32 vsw, u32 vfp,
+ u32 vbp, int binvvsync, u32 eavheight, u32 evsw,
+ u32 evfp, u32 evbp);
+void nx_dpc_get_vsync(u32 module_index, u32 *pavheight, u32 *pvsw,
+ u32 *pvfp, u32 *pvbp, int *pbinvvsync,
+ u32 *peavheight, u32 *pevsw, u32 *pevfp,
+ u32 *pevbp);
+void nx_dpc_set_vsync_offset(u32 module_index, u32 vssoffset,
+ u32 vseoffset, u32 evssoffset,
+ u32 evseoffset);
+void nx_dpc_get_vsync_offset(u32 module_index, u32 *pvssoffset,
+ u32 *pvseoffset, u32 *pevssoffset,
+ u32 *pevseoffset);
+
+u32 nx_dpc_enable_pad_tft(u32 module_index, u32 mode_index);
+u32 nx_dpc_enable_pad_i80(u32 module_index, u32 mode_index);
+
+enum syncgenmode {
+ progressive = 0,
+ interlace = 1
+};
+
+enum polarity {
+ polarity_activehigh = 0,
+ polarity_activelow = 1
+};
+
+enum outputformat {
+ outputformat_rgb555 = 0,
+ outputformat_rgb565 = 1,
+ outputformat_rgb666 = 2,
+ outputformat_rgb888 = 3,
+ outputformat_mrgb555a = 4,
+ outputformat_mrgb555b = 5,
+ outputformat_mrgb565 = 6,
+ outputformat_mrgb666 = 7,
+ outputformat_mrgb888a = 8,
+ outputformat_mrgb888b = 9,
+ outputformat_bgr555 = 10,
+ outputformat_bgr565 = 11,
+ outputformat_bgr666 = 12,
+ outputformat_bgr888 = 13,
+ outputformat_mbgr555a = 14,
+ outputformat_mbgr555b = 15,
+ outputformat_mbgr565 = 16,
+ outputformat_mbgr666 = 17,
+ outputformat_mbgr888a = 18,
+ outputformat_mbgr888b = 19,
+ outputformat_ccir656 = 20,
+ outputformat_ccir601_8 = 21,
+ outputformat_ccir601_16a = 22,
+ outputformat_ccir601_16b = 23,
+ outputformat_srgb888 = 24,
+ outputformat_srgbd8888 = 25
+};
+
+enum outpadclksel {
+ padvclk = 0,
+ padvclk2 = 1,
+ padvclk3 = 2
+};
+
+enum qmode {
+ qmode_220 = 0,
+ qmode_256 = 1
+};
+
+void nx_dpc_set_sync(u32 module_index, enum syncgenmode sync_gen_mode,
+ u32 avwidth, u32 avheight, u32 hsw, u32 hfp,
+ u32 hbp, u32 vsw, u32 vfp, u32 vbp,
+ enum polarity field_polarity,
+ enum polarity hsyncpolarity,
+ enum polarity vsyncpolarity, u32 even_vsw,
+ u32 even_vfp, u32 even_vbp, u32 vsetpixel,
+ u32 vsclrpixel, u32 evenvsetpixel,
+ u32 evenvsclrpixel);
+void nx_dpc_set_output_format(u32 module_index,
+ enum outputformat output_format,
+ u8 output_video_config);
+void nx_dpc_set_quantization_mode(u32 module_index, enum qmode rgb2yc,
+ enum qmode yc2rgb);
+void nx_dpc_set_enable(u32 module_index, int enable, int rgbmode,
+ int use_ntscsync, int use_analog_output,
+ int seavenable);
+void nx_dpc_set_enable_with_interlace(u32 module_index, int enable,
+ int rgbmode, int use_ntscsync,
+ int use_analog_output,
+ int seavenable);
+void nx_dpc_set_enable_with_interlace(u32 module_index, int enable,
+ int rgbmode, int use_ntscsync,
+ int use_analog_output,
+ int seavenable);
+void nx_dpc_set_out_video_clk_select(u32 module_index,
+ enum outpadclksel out_pad_vclk_sel);
+void nx_dpc_set_reg_flush(u32 module_index);
+void nx_dpc_set_sramon(u32 module_index);
+void nx_dpc_set_sync_lcdtype(u32 module_index, int stnlcd,
+ int dual_view_enb, int bit_widh,
+ u8 cpcycle);
+void nx_dpc_set_up_scale_control(u32 module_index, int up_scale_enb,
+ int filter_enb, u32 hscale,
+ u16 source_width);
+
+void nx_dpc_set_mputime(u32 module_index, u8 setup, u8 hold, u8 acc);
+void nx_dpc_set_index(u32 module_index, u32 index);
+void nx_dpc_set_data(u32 module_index, u32 data);
+void nx_dpc_set_cmd_buffer_flush(u32 module_index);
+void nx_dpc_set_cmd_buffer_clear(u32 module_index);
+void nx_dpc_set_cmd_buffer_write(u32 module_index, u32 cmd_data);
+void nx_dpc_set(u32 module_index);
+u32 nx_dpc_get_data(u32 module_index);
+u32 nx_dpc_get_status(u32 module_index);
+void nx_dpc_rgbmask(u32 module_index, u32 rgbmask);
+void nx_dpc_set_pad_location(u32 module_index, u32 index, u32 regvalue);
+u32 nx_dpc_get_field_flag(u32 module_index);
+
+void nx_dpc_set_sync_v(u32 module_index, u32 avheight, u32 vsw, u32 vfp,
+ u32 vbp);
+
+int nx_dpc_init_reg_test(u32 module_index);
+void nx_dpc_set_encoder_control_reg(u32 module_index, u32 param_a,
+ u32 param_b, u32 param_c);
+void nx_dpc_set_encoder_shcphase_control(u32 module_index,
+ u32 chroma_param);
+void nx_dpc_set_encoder_timing_config_reg(u32 module_index, u32 inctl);
+void nx_dpc_set_encoder_dacoutput_select(u32 module_index, u8 dacsel0,
+ u8 dacsel1, u8 dacsel2,
+ u8 dacsel3, u8 dacsel4,
+ u8 dacsel5);
+void nx_dpc_set_encoder_sync_location(u32 module_index, u16 hsoe,
+ u16 hsob, u16 vsob, u16 vsoe,
+ u8 vsost, int novrst);
+void nx_dpc_set_encoder_dacpower_enable(u32 module_index, u8 dacpd);
+void nx_dpc_set_ycorder(u32 module_index, enum nx_dpc_ycorder ycorder);
+void nx_dpc_set_luma_gain(u32 module_index, u32 luma_gain);
+
+void nx_dpc_set_secondary_dpcsync(u32 module_index, int benb);
+int nx_dpc_get_secondary_dpcsync(u32 module_index);
+void nx_dpc_set_encenable(u32 module_index, int benb);
+int nx_dpc_get_encenable(u32 module_index);
+void nx_dpc_set_video_encoder_power_down(u32 module_index, int benb);
+int nx_dpc_get_video_encoder_power_down(u32 module_index);
+void nx_dpc_set_video_encoder_mode(u32 module_index, enum nx_dpc_vbs vbs,
+ int bpedestal);
+void nx_dpc_set_video_encoder_schlock_control(u32 module_index,
+ int bfreerun);
+int nx_dpc_get_video_encoder_schlock_control(u32 module_index);
+void nx_dpc_set_video_encoder_bandwidth(u32 module_index,
+ enum nx_dpc_bandwidth luma,
+ enum nx_dpc_bandwidth chroma);
+void nx_dpc_get_video_encoder_bandwidth(u32 module_index,
+ enum nx_dpc_bandwidth *pluma,
+ enum nx_dpc_bandwidth *pchroma);
+void nx_dpc_set_video_encoder_color_control(u32 module_index, s8 sch,
+ s8 hue, s8 sat,
+ s8 crt, s8 brt);
+void nx_dpc_get_video_encoder_color_control(u32 module_index,
+ s8 *psch, s8 *phue,
+ s8 *psat, s8 *pcrt,
+ s8 *pbrt);
+void nx_dpc_set_video_encoder_fscadjust(u32 module_index,
+ int16_t adjust);
+u16 nx_dpc_get_video_encoder_fscadjust(u32 module_index);
+void nx_dpc_set_video_encoder_timing(u32 module_index, u32 hsos,
+ u32 hsoe, u32 vsos, u32 vsoe);
+void nx_dpc_get_video_encoder_timing(u32 module_index, u32 *phsos,
+ u32 *phsoe, u32 *pvsos,
+ u32 *pvsoe);
+void nx_dpc_set_sync_v(u32 module_index, u32 avheight, u32 vsw, u32 vfp,
+ u32 vbp);
+
+int nx_dpc_init_reg_test(u32 module_index);
+void nx_dpc_set_encoder_control_reg(u32 module_index, u32 param_a,
+ u32 param_b, u32 param_c);
+void nx_dpc_set_encoder_shcphase_control(u32 module_index,
+ u32 chroma_param);
+void nx_dpc_set_encoder_timing_config_reg(u32 module_index, u32 inctl);
+void nx_dpc_set_encoder_dacoutput_select(u32 module_index, u8 dacsel0,
+ u8 dacsel1, u8 dacsel2,
+ u8 dacsel3, u8 dacsel4,
+ u8 dacsel5);
+void nx_dpc_set_encoder_sync_location(u32 module_index, u16 hsoe,
+ u16 hsob, u16 vsob, u16 vsoe,
+ u8 vsost, int novrst);
+void nx_dpc_set_encoder_dacpower_enable(u32 module_index, u8 dacpd);
+void nx_dpc_set_ycorder(u32 module_index, enum nx_dpc_ycorder ycorder);
+void nx_dpc_set_luma_gain(u32 module_index, u32 luma_gain);
+
+#endif
--
1.9.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH 08/10] video: add nexell video driver (display/video driver)
2020-02-03 19:39 [RFC PATCH 00/10] arm: add support for SoC S5P4418 Stefan Bosch
` (6 preceding siblings ...)
2020-02-03 20:45 ` [RFC PATCH 07/10] video: add nexell video driver (soc: dpc, makefile) Stefan Bosch
@ 2020-02-03 20:45 ` Stefan Bosch
2020-02-03 20:46 ` [RFC PATCH 09/10] arm: add support for SoC s5p4418 (cpu) / nanopi2 board Stefan Bosch
` (3 subsequent siblings)
11 siblings, 0 replies; 19+ messages in thread
From: Stefan Bosch @ 2020-02-03 20:45 UTC (permalink / raw)
To: u-boot
Changes in relation to FriendlyARM's U-Boot nanopi2-v2016.01:
- nexell_display.c: Changed to DM, CONFIG_FB_ADDR can not be used
anymore because framebuffer is allocated by video_reserve() in
video-uclass.c. Therefore code changed appropriately.
Signed-off-by: Stefan Bosch <stefan_b@posteo.net>
---
drivers/video/Kconfig | 10 +
drivers/video/Makefile | 1 +
drivers/video/nexell/Kconfig | 27 ++
drivers/video/nexell/Makefile | 12 +
drivers/video/nexell/s5pxx18_dp.c | 338 ++++++++++++++++
drivers/video/nexell/s5pxx18_dp_hdmi.c | 543 ++++++++++++++++++++++++++
drivers/video/nexell/s5pxx18_dp_lvds.c | 274 +++++++++++++
drivers/video/nexell/s5pxx18_dp_mipi.c | 677 +++++++++++++++++++++++++++++++++
drivers/video/nexell/s5pxx18_dp_rgb.c | 69 ++++
drivers/video/nexell_display.c | 658 ++++++++++++++++++++++++++++++++
10 files changed, 2609 insertions(+)
create mode 100644 drivers/video/nexell/Kconfig
create mode 100644 drivers/video/nexell/Makefile
create mode 100644 drivers/video/nexell/s5pxx18_dp.c
create mode 100644 drivers/video/nexell/s5pxx18_dp_hdmi.c
create mode 100644 drivers/video/nexell/s5pxx18_dp_lvds.c
create mode 100644 drivers/video/nexell/s5pxx18_dp_mipi.c
create mode 100644 drivers/video/nexell/s5pxx18_dp_rgb.c
create mode 100644 drivers/video/nexell_display.c
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 50ab365..dd224ab 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -563,6 +563,16 @@ source "drivers/video/bridge/Kconfig"
source "drivers/video/imx/Kconfig"
+config VIDEO_NX
+ bool "Enable video support on Nexell SoC"
+ depends on ARCH_S5P6818 || ARCH_S5P4418
+ help
+ Nexell SoC supports many video output options including eDP and
+ HDMI. This option enables this support which can be used on devices
+ which have an eDP display connected.
+
+source "drivers/video/nexell/Kconfig"
+
config VIDEO
bool "Enable legacy video support"
depends on !DM_VIDEO
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index df7119d..3bacc64 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -61,6 +61,7 @@ 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
+obj-$(CONFIG_VIDEO_NX) += nexell_display.o videomodes.o nexell/
obj-$(CONFIG_VIDEO_OMAP3) += omap3_dss.o
obj-$(CONFIG_VIDEO_DSI_HOST_SANDBOX) += sandbox_dsi_host.o
obj-$(CONFIG_VIDEO_SANDBOX_SDL) += sandbox_sdl.o
diff --git a/drivers/video/nexell/Kconfig b/drivers/video/nexell/Kconfig
new file mode 100644
index 0000000..54b8ccb
--- /dev/null
+++ b/drivers/video/nexell/Kconfig
@@ -0,0 +1,27 @@
+if VIDEO_NX
+
+menu "LCD select"
+
+config VIDEO_NX_RGB
+ bool "RGB LCD"
+ help
+ Support for RGB lcd output.
+
+config VIDEO_NX_LVDS
+ bool "LVDS LCD"
+ help
+ Support for LVDS lcd output.
+
+config VIDEO_NX_MIPI
+ bool "MiPi"
+ help
+ Support for MiPi lcd output.
+
+config VIDEO_NX_HDMI
+ bool "HDMI"
+ help
+ Support for hdmi output.
+
+endmenu
+
+endif
diff --git a/drivers/video/nexell/Makefile b/drivers/video/nexell/Makefile
new file mode 100644
index 0000000..111ab45
--- /dev/null
+++ b/drivers/video/nexell/Makefile
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2016 Nexell
+# Junghyun, kim<jhkim@nexell.co.kr>
+
+obj-$(CONFIG_VIDEO_NX) += s5pxx18_dp.o
+obj-$(CONFIG_VIDEO_NX) += soc/
+
+obj-$(CONFIG_VIDEO_NX_RGB) += s5pxx18_dp_rgb.o
+obj-$(CONFIG_VIDEO_NX_LVDS) += s5pxx18_dp_lvds.o
+obj-$(CONFIG_VIDEO_NX_MIPI) += s5pxx18_dp_mipi.o
+obj-$(CONFIG_VIDEO_NX_HDMI) += s5pxx18_dp_hdmi.o
diff --git a/drivers/video/nexell/s5pxx18_dp.c b/drivers/video/nexell/s5pxx18_dp.c
new file mode 100644
index 0000000..c69b69c
--- /dev/null
+++ b/drivers/video/nexell/s5pxx18_dp.c
@@ -0,0 +1,338 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Nexell Co., Ltd.
+ *
+ * Author: junghyun, kim <jhkim@nexell.co.kr>
+ */
+
+#include <config.h>
+#include <common.h>
+#include <errno.h>
+#include <asm/arch/reset.h>
+#include <asm/arch/nexell.h>
+#include <asm/arch/display.h>
+
+#include "soc/s5pxx18_soc_disptop.h"
+#include "soc/s5pxx18_soc_dpc.h"
+#include "soc/s5pxx18_soc_mlc.h"
+
+#define MLC_LAYER_RGB_0 0 /* number of RGB layer 0 */
+#define MLC_LAYER_RGB_1 1 /* number of RGB layer 1 */
+#define MLC_LAYER_VIDEO 3 /* number of Video layer: 3 = VIDEO */
+
+#define __io_address(a) (void *)(uintptr_t)(a)
+
+void dp_control_init(int module)
+{
+ void *base;
+
+ /* top */
+ base = __io_address(nx_disp_top_get_physical_address());
+ nx_disp_top_set_base_address(base);
+
+ /* control */
+ base = __io_address(nx_dpc_get_physical_address(module));
+ nx_dpc_set_base_address(module, base);
+
+ /* top controller */
+ nx_rstcon_setrst(RESET_ID_DISP_TOP, RSTCON_ASSERT);
+ nx_rstcon_setrst(RESET_ID_DISP_TOP, RSTCON_NEGATE);
+
+ /* display controller */
+ nx_rstcon_setrst(RESET_ID_DISPLAY, RSTCON_ASSERT);
+ nx_rstcon_setrst(RESET_ID_DISPLAY, RSTCON_NEGATE);
+
+ nx_dpc_set_clock_pclk_mode(module, nx_pclkmode_always);
+}
+
+int dp_control_setup(int module,
+ struct dp_sync_info *sync, struct dp_ctrl_info *ctrl)
+{
+ unsigned int out_format;
+ unsigned int delay_mask;
+ int rgb_pvd = 0, hsync_cp1 = 7, vsync_fram = 7, de_cp2 = 7;
+ int v_vso = 1, v_veo = 1, e_vso = 1, e_veo = 1;
+
+ int interlace = 0;
+ int invert_field;
+ int swap_rb;
+ unsigned int yc_order;
+ int vck_select;
+ int vclk_invert;
+ int emb_sync;
+
+ enum nx_dpc_dither r_dither, g_dither, b_dither;
+ int rgb_mode = 0;
+
+ if (NULL == sync || NULL == ctrl) {
+ debug("error, dp.%d not set sync or pad clock info !!!\n",
+ module);
+ return -EINVAL;
+ }
+
+ out_format = ctrl->out_format;
+ delay_mask = ctrl->delay_mask;
+ interlace = sync->interlace;
+ invert_field = ctrl->invert_field;
+ swap_rb = ctrl->swap_RB;
+ yc_order = ctrl->yc_order;
+ vck_select = ctrl->vck_select;
+ vclk_invert = ctrl->clk_inv_lv0 | ctrl->clk_inv_lv1;
+ emb_sync = (out_format == DPC_FORMAT_CCIR656 ? 1 : 0);
+
+ /* set delay mask */
+ if (delay_mask & DP_SYNC_DELAY_RGB_PVD)
+ rgb_pvd = ctrl->d_rgb_pvd;
+ if (delay_mask & DP_SYNC_DELAY_HSYNC_CP1)
+ hsync_cp1 = ctrl->d_hsync_cp1;
+ if (delay_mask & DP_SYNC_DELAY_VSYNC_FRAM)
+ vsync_fram = ctrl->d_vsync_fram;
+ if (delay_mask & DP_SYNC_DELAY_DE_CP)
+ de_cp2 = ctrl->d_de_cp2;
+
+ if (ctrl->vs_start_offset != 0 ||
+ ctrl->vs_end_offset != 0 ||
+ ctrl->ev_start_offset != 0 || ctrl->ev_end_offset != 0) {
+ v_vso = ctrl->vs_start_offset;
+ v_veo = ctrl->vs_end_offset;
+ e_vso = ctrl->ev_start_offset;
+ e_veo = ctrl->ev_end_offset;
+ }
+
+ if (nx_dpc_format_rgb555 == out_format ||
+ nx_dpc_format_mrgb555a == out_format ||
+ nx_dpc_format_mrgb555b == out_format) {
+ r_dither = nx_dpc_dither_5bit;
+ g_dither = nx_dpc_dither_5bit;
+ b_dither = nx_dpc_dither_5bit;
+ rgb_mode = 1;
+ } else if (nx_dpc_format_rgb565 == out_format ||
+ nx_dpc_format_mrgb565 == out_format) {
+ r_dither = nx_dpc_dither_5bit;
+ b_dither = nx_dpc_dither_5bit;
+ g_dither = nx_dpc_dither_6bit, rgb_mode = 1;
+ } else if ((nx_dpc_format_rgb666 == out_format) ||
+ (nx_dpc_format_mrgb666 == out_format)) {
+ r_dither = nx_dpc_dither_6bit;
+ g_dither = nx_dpc_dither_6bit;
+ b_dither = nx_dpc_dither_6bit;
+ rgb_mode = 1;
+ } else {
+ r_dither = nx_dpc_dither_bypass;
+ g_dither = nx_dpc_dither_bypass;
+ b_dither = nx_dpc_dither_bypass;
+ rgb_mode = 1;
+ }
+
+ /* CLKGEN0/1 */
+ nx_dpc_set_clock_source(module, 0, ctrl->clk_src_lv0 == 3 ?
+ 6 : ctrl->clk_src_lv0);
+ nx_dpc_set_clock_divisor(module, 0, ctrl->clk_div_lv0);
+ nx_dpc_set_clock_source(module, 1, ctrl->clk_src_lv1);
+ nx_dpc_set_clock_divisor(module, 1, ctrl->clk_div_lv1);
+ nx_dpc_set_clock_out_delay(module, 0, ctrl->clk_delay_lv0);
+ nx_dpc_set_clock_out_delay(module, 1, ctrl->clk_delay_lv1);
+
+ /* LCD out */
+ nx_dpc_set_mode(module, out_format, interlace, invert_field,
+ rgb_mode, swap_rb, yc_order, emb_sync, emb_sync,
+ vck_select, vclk_invert, 0);
+ nx_dpc_set_hsync(module, sync->h_active_len, sync->h_sync_width,
+ sync->h_front_porch, sync->h_back_porch,
+ sync->h_sync_invert);
+ nx_dpc_set_vsync(module, sync->v_active_len, sync->v_sync_width,
+ sync->v_front_porch, sync->v_back_porch,
+ sync->v_sync_invert, sync->v_active_len,
+ sync->v_sync_width, sync->v_front_porch,
+ sync->v_back_porch);
+ nx_dpc_set_vsync_offset(module, v_vso, v_veo, e_vso, e_veo);
+ nx_dpc_set_delay(module, rgb_pvd, hsync_cp1, vsync_fram, de_cp2);
+ nx_dpc_set_dither(module, r_dither, g_dither, b_dither);
+
+#ifdef CONFIG_MACH_S5P6818
+ /* Set TFT_CLKCTRL (offset : 1030h)
+ * Field name : DPC0_CLKCTRL, DPC1_CLKCRL
+ * Default value : clk_inv_lv0/1 = 0 : PADCLK_InvCLK
+ * Invert case : clk_inv_lv0/1 = 1 : PADCLK_CLK
+ */
+ if (module == 0 && ctrl->clk_inv_lv0)
+ nx_disp_top_set_padclock(padmux_primary_mlc, padclk_clk);
+ if (module == 1 && ctrl->clk_inv_lv1)
+ nx_disp_top_set_padclock(padmux_secondary_mlc, padclk_clk);
+#endif
+
+ debug("%s: dp.%d x:%4d, hf:%3d, hb:%3d, hs:%3d, hi=%d\n",
+ __func__, module, sync->h_active_len, sync->h_front_porch,
+ sync->h_back_porch, sync->h_sync_width, sync->h_sync_invert);
+ debug("%s: dp.%d y:%4d, vf:%3d, vb:%3d, vs:%3d, vi=%d\n",
+ __func__, module, sync->v_active_len, sync->v_front_porch,
+ sync->v_back_porch, sync->v_sync_width, sync->h_sync_invert);
+ debug("%s: dp.%d ck.0:%d:%d:%d, ck.1:%d:%d:%d\n",
+ __func__, module,
+ ctrl->clk_src_lv0, ctrl->clk_div_lv0, ctrl->clk_inv_lv0,
+ ctrl->clk_src_lv1, ctrl->clk_div_lv1, ctrl->clk_inv_lv1);
+ debug("%s: dp.%d vs:%d, ve:%d, es:%d, ee:%d\n",
+ __func__, module, v_vso, v_veo, e_vso, e_veo);
+ debug("%s: dp.%d delay RGB:%d, hs:%d, vs:%d, de:%d, fmt:0x%x\n",
+ __func__, module, rgb_pvd, hsync_cp1, vsync_fram, de_cp2,
+ out_format);
+
+ return 0;
+}
+
+void dp_control_enable(int module, int on)
+{
+ debug("%s: dp.%d top %s\n", __func__, module, on ? "ON" : "OFF");
+
+ nx_dpc_set_dpc_enable(module, on);
+ nx_dpc_set_clock_divisor_enable(module, on);
+}
+
+void dp_plane_init(int module)
+{
+ void *base = __io_address(nx_mlc_get_physical_address(module));
+
+ nx_mlc_set_base_address(module, base);
+ nx_mlc_set_clock_pclk_mode(module, nx_pclkmode_always);
+ nx_mlc_set_clock_bclk_mode(module, nx_bclkmode_always);
+}
+
+int dp_plane_screen_setup(int module, struct dp_plane_top *top)
+{
+ int width = top->screen_width;
+ int height = top->screen_height;
+ int interlace = top->interlace;
+ int video_prior = top->video_prior;
+ unsigned int bg_color = top->back_color;
+
+ /* MLC TOP layer */
+ nx_mlc_set_screen_size(module, width, height);
+ nx_mlc_set_layer_priority(module, video_prior);
+ nx_mlc_set_background(module, bg_color);
+ nx_mlc_set_field_enable(module, interlace);
+ nx_mlc_set_rgblayer_gama_table_power_mode(module, 0, 0, 0);
+ nx_mlc_set_rgblayer_gama_table_sleep_mode(module, 1, 1, 1);
+ nx_mlc_set_rgblayer_gamma_enable(module, 0);
+ nx_mlc_set_dither_enable_when_using_gamma(module, 0);
+ nx_mlc_set_gamma_priority(module, 0);
+ nx_mlc_set_top_power_mode(module, 1);
+ nx_mlc_set_top_sleep_mode(module, 0);
+
+ debug("%s: dp.%d screen %dx%d, %s, priority:%d, bg:0x%x\n",
+ __func__, module, width, height,
+ interlace ? "Interlace" : "Progressive",
+ video_prior, bg_color);
+
+ return 0;
+}
+
+void dp_plane_screen_enable(int module, int on)
+{
+ /* enable top screen */
+ nx_mlc_set_mlc_enable(module, on);
+ nx_mlc_set_top_dirty_flag(module);
+ debug("%s: dp.%d top %s\n", __func__, module, on ? "ON" : "OFF");
+}
+
+int dp_plane_layer_setup(int module, struct dp_plane_info *plane)
+{
+ int sx = plane->left;
+ int sy = plane->top;
+ int ex = sx + plane->width - 1;
+ int ey = sy + plane->height - 1;
+ int pixel_byte = plane->pixel_byte;
+ int mem_lock_size = 16; /* fix mem lock size */
+ int layer = plane->layer;
+ unsigned int format = plane->format;
+
+ if (!plane->enable)
+ return -EINVAL;
+
+ /* MLC layer */
+ nx_mlc_set_lock_size(module, layer, mem_lock_size);
+ nx_mlc_set_alpha_blending(module, layer, 0, 15);
+ nx_mlc_set_transparency(module, layer, 0, 0);
+ nx_mlc_set_color_inversion(module, layer, 0, 0);
+ nx_mlc_set_rgblayer_invalid_position(module, layer, 0, 0, 0, 0, 0, 0);
+ nx_mlc_set_rgblayer_invalid_position(module, layer, 1, 0, 0, 0, 0, 0);
+ nx_mlc_set_format_rgb(module, layer, format);
+ nx_mlc_set_position(module, layer, sx, sy, ex, ey);
+ nx_mlc_set_rgblayer_stride(module, layer, pixel_byte,
+ plane->width * pixel_byte);
+ nx_mlc_set_rgblayer_address(module, layer, plane->fb_base);
+
+ debug("%s: dp.%d.%d %d * %d, %dbpp, fmt:0x%x\n",
+ __func__, module, layer, plane->width, plane->height,
+ pixel_byte * 8, format);
+ debug("%s: b:0x%x, l:%d, t:%d, r:%d, b:%d, hs:%d, vs:%d\n",
+ __func__, plane->fb_base, sx, sy, ex, ey,
+ plane->width * pixel_byte, pixel_byte);
+
+ return 0;
+}
+
+int dp_plane_set_enable(int module, int layer, int on)
+{
+ int hl, hc;
+ int vl, vc;
+
+ debug("%s: dp.%d.%d %s:%s\n",
+ __func__, module, layer,
+ layer == MLC_LAYER_VIDEO ? "Video" : "RGB",
+ on ? "ON" : "OFF");
+
+ if (layer != MLC_LAYER_VIDEO) {
+ nx_mlc_set_layer_enable(module, layer, on);
+ nx_mlc_set_dirty_flag(module, layer);
+ return 0;
+ }
+
+ /* video layer */
+ if (on) {
+ nx_mlc_set_video_layer_line_buffer_power_mode(module, 1);
+ nx_mlc_set_video_layer_line_buffer_sleep_mode(module, 0);
+ nx_mlc_set_layer_enable(module, layer, 1);
+ nx_mlc_set_dirty_flag(module, layer);
+ } else {
+ nx_mlc_set_layer_enable(module, layer, 0);
+ nx_mlc_set_dirty_flag(module, layer);
+ nx_mlc_get_video_layer_scale_filter(module,
+ &hl, &hc, &vl, &vc);
+ if (hl || hc || vl || vc)
+ nx_mlc_set_video_layer_scale_filter(module, 0, 0, 0, 0);
+ nx_mlc_set_video_layer_line_buffer_power_mode(module, 0);
+ nx_mlc_set_video_layer_line_buffer_sleep_mode(module, 1);
+ nx_mlc_set_dirty_flag(module, layer);
+ }
+
+ return 0;
+}
+
+void dp_plane_layer_enable(int module,
+ struct dp_plane_info *plane, int on)
+{
+ dp_plane_set_enable(module, plane->layer, on);
+}
+
+int dp_plane_set_address(int module, int layer, unsigned int address)
+{
+ nx_mlc_set_rgblayer_address(module, layer, address);
+ nx_mlc_set_dirty_flag(module, layer);
+
+ return 0;
+}
+
+int dp_plane_wait_vsync(int module, int layer, int fps)
+{
+ int cnt = 0;
+
+ if (fps == 0)
+ return (int)nx_mlc_get_dirty_flag(module, layer);
+
+ while (fps > cnt++) {
+ while (nx_mlc_get_dirty_flag(module, layer))
+ ;
+ nx_mlc_set_dirty_flag(module, layer);
+ }
+ return 0;
+}
diff --git a/drivers/video/nexell/s5pxx18_dp_hdmi.c b/drivers/video/nexell/s5pxx18_dp_hdmi.c
new file mode 100644
index 0000000..5d72d1e
--- /dev/null
+++ b/drivers/video/nexell/s5pxx18_dp_hdmi.c
@@ -0,0 +1,543 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Nexell Co., Ltd.
+ *
+ * Author: junghyun, kim <jhkim@nexell.co.kr>
+ */
+
+#include <config.h>
+#include <common.h>
+#include <errno.h>
+
+#include <asm/arch/nexell.h>
+#include <asm/arch/tieoff.h>
+#include <asm/arch/reset.h>
+#include <asm/arch/display.h>
+
+#include "soc/s5pxx18_soc_dpc.h"
+#include "soc/s5pxx18_soc_hdmi.h"
+#include "soc/s5pxx18_soc_disptop.h"
+#include "soc/s5pxx18_soc_disptop_clk.h"
+
+#define __io_address(a) (void *)(uintptr_t)(a)
+
+static const u8 hdmiphy_preset74_25[32] = {
+ 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0xc8, 0x81,
+ 0xe8, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80, 0x0a,
+ 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x86, 0x54,
+ 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x10, 0x80,
+};
+
+static const u8 hdmiphy_preset148_5[32] = {
+ 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0xc8, 0x81,
+ 0xe8, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80, 0x0a,
+ 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x86, 0x54,
+ 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
+};
+
+#define HDMIPHY_PRESET_TABLE_SIZE (32)
+
+enum NXP_HDMI_PRESET {
+ NXP_HDMI_PRESET_720P = 0, /* 1280 x 720 */
+ NXP_HDMI_PRESET_1080P, /* 1920 x 1080 */
+ NXP_HDMI_PRESET_MAX
+};
+
+static void hdmi_reset(void)
+{
+ nx_rstcon_setrst(RESET_ID_HDMI_VIDEO, RSTCON_ASSERT);
+ nx_rstcon_setrst(RESET_ID_HDMI_SPDIF, RSTCON_ASSERT);
+ nx_rstcon_setrst(RESET_ID_HDMI_TMDS, RSTCON_ASSERT);
+ nx_rstcon_setrst(RESET_ID_HDMI_VIDEO, RSTCON_NEGATE);
+ nx_rstcon_setrst(RESET_ID_HDMI_SPDIF, RSTCON_NEGATE);
+ nx_rstcon_setrst(RESET_ID_HDMI_TMDS, RSTCON_NEGATE);
+}
+
+static int hdmi_phy_enable(int preset, int enable)
+{
+ const u8 *table = NULL;
+ int size = 0;
+ u32 addr, i = 0;
+
+ if (!enable)
+ return 0;
+
+ switch (preset) {
+ case NXP_HDMI_PRESET_720P:
+ table = hdmiphy_preset74_25;
+ size = 32;
+ break;
+ case NXP_HDMI_PRESET_1080P:
+ table = hdmiphy_preset148_5;
+ size = 31;
+ break;
+ default:
+ printf("hdmi: phy not support preset %d\n", preset);
+ return -EINVAL;
+ }
+
+ nx_hdmi_set_reg(0, HDMI_PHY_REG7C, (0 << 7));
+ nx_hdmi_set_reg(0, HDMI_PHY_REG7C, (0 << 7));
+ nx_hdmi_set_reg(0, HDMI_PHY_REG04, (0 << 4));
+ nx_hdmi_set_reg(0, HDMI_PHY_REG04, (0 << 4));
+ nx_hdmi_set_reg(0, HDMI_PHY_REG24, (1 << 7));
+ nx_hdmi_set_reg(0, HDMI_PHY_REG24, (1 << 7));
+
+ for (i = 0, addr = HDMI_PHY_REG04; size > i; i++, addr += 4) {
+ nx_hdmi_set_reg(0, addr, table[i]);
+ nx_hdmi_set_reg(0, addr, table[i]);
+ }
+
+ nx_hdmi_set_reg(0, HDMI_PHY_REG7C, 0x80);
+ nx_hdmi_set_reg(0, HDMI_PHY_REG7C, 0x80);
+ nx_hdmi_set_reg(0, HDMI_PHY_REG7C, (1 << 7));
+ nx_hdmi_set_reg(0, HDMI_PHY_REG7C, (1 << 7));
+ debug("%s: preset = %d\n", __func__, preset);
+
+ return 0;
+}
+
+static inline int hdmi_wait_phy_ready(void)
+{
+ int count = 500;
+
+ do {
+ u32 val = nx_hdmi_get_reg(0, HDMI_LINK_PHY_STATUS_0);
+
+ if (val & 0x01) {
+ printf("HDMI: phy ready...\n");
+ return 1;
+ }
+ mdelay(10);
+ } while (count--);
+
+ return 0;
+}
+
+static inline int hdmi_get_vsync(int preset,
+ struct dp_sync_info *sync,
+ struct dp_ctrl_info *ctrl)
+{
+ switch (preset) {
+ case NXP_HDMI_PRESET_720P: /* 720p: 1280x720 */
+ sync->h_active_len = 1280;
+ sync->h_sync_width = 40;
+ sync->h_back_porch = 220;
+ sync->h_front_porch = 110;
+ sync->h_sync_invert = 0;
+ sync->v_active_len = 720;
+ sync->v_sync_width = 5;
+ sync->v_back_porch = 20;
+ sync->v_front_porch = 5;
+ sync->v_sync_invert = 0;
+ break;
+
+ case NXP_HDMI_PRESET_1080P: /* 1080p: 1920x1080 */
+ sync->h_active_len = 1920;
+ sync->h_sync_width = 44;
+ sync->h_back_porch = 148;
+ sync->h_front_porch = 88;
+ sync->h_sync_invert = 0;
+ sync->v_active_len = 1080;
+ sync->v_sync_width = 5;
+ sync->v_back_porch = 36;
+ sync->v_front_porch = 4;
+ sync->v_sync_invert = 0;
+ break;
+ default:
+ printf("HDMI: not support preset sync %d\n", preset);
+ return -EINVAL;
+ }
+
+ ctrl->clk_src_lv0 = 4;
+ ctrl->clk_div_lv0 = 1;
+ ctrl->clk_src_lv1 = 7;
+ ctrl->clk_div_lv1 = 1;
+
+ ctrl->out_format = outputformat_rgb888;
+ ctrl->delay_mask = (DP_SYNC_DELAY_RGB_PVD | DP_SYNC_DELAY_HSYNC_CP1 |
+ DP_SYNC_DELAY_VSYNC_FRAM | DP_SYNC_DELAY_DE_CP);
+ ctrl->d_rgb_pvd = 0;
+ ctrl->d_hsync_cp1 = 0;
+ ctrl->d_vsync_fram = 0;
+ ctrl->d_de_cp2 = 7;
+
+ /* HFP + HSW + HBP + AVWidth-VSCLRPIXEL- 1; */
+ ctrl->vs_start_offset = (sync->h_front_porch + sync->h_sync_width +
+ sync->h_back_porch + sync->h_active_len - 1);
+ ctrl->vs_end_offset = 0;
+
+ /* HFP + HSW + HBP + AVWidth-EVENVSCLRPIXEL- 1 */
+ ctrl->ev_start_offset = (sync->h_front_porch + sync->h_sync_width +
+ sync->h_back_porch + sync->h_active_len - 1);
+ ctrl->ev_end_offset = 0;
+ debug("%s: preset: %d\n", __func__, preset);
+
+ return 0;
+}
+
+static void hdmi_clock(void)
+{
+ void *base =
+ __io_address(nx_disp_top_clkgen_get_physical_address
+ (to_mipi_clkgen));
+
+ nx_disp_top_clkgen_set_base_address(to_mipi_clkgen, base);
+ nx_disp_top_clkgen_set_clock_divisor_enable(to_mipi_clkgen, 0);
+ nx_disp_top_clkgen_set_clock_pclk_mode(to_mipi_clkgen,
+ nx_pclkmode_always);
+ nx_disp_top_clkgen_set_clock_source(to_mipi_clkgen, HDMI_SPDIF_CLKOUT,
+ 2);
+ nx_disp_top_clkgen_set_clock_divisor(to_mipi_clkgen, HDMI_SPDIF_CLKOUT,
+ 2);
+ nx_disp_top_clkgen_set_clock_source(to_mipi_clkgen, 1, 7);
+ nx_disp_top_clkgen_set_clock_divisor_enable(to_mipi_clkgen, 1);
+
+ /* must initialize this !!! */
+ nx_disp_top_hdmi_set_vsync_hsstart_end(0, 0);
+ nx_disp_top_hdmi_set_vsync_start(0);
+ nx_disp_top_hdmi_set_hactive_start(0);
+ nx_disp_top_hdmi_set_hactive_end(0);
+}
+
+static void hdmi_vsync(struct dp_sync_info *sync)
+{
+ int width = sync->h_active_len;
+ int hsw = sync->h_sync_width;
+ int hbp = sync->h_back_porch;
+ int height = sync->v_active_len;
+ int vsw = sync->v_sync_width;
+ int vbp = sync->v_back_porch;
+
+ int v_sync_s = vsw + vbp + height - 1;
+ int h_active_s = hsw + hbp;
+ int h_active_e = width + hsw + hbp;
+ int v_sync_hs_se0 = hsw + hbp + 1;
+ int v_sync_hs_se1 = hsw + hbp + 2;
+
+ nx_disp_top_hdmi_set_vsync_start(v_sync_s);
+ nx_disp_top_hdmi_set_hactive_start(h_active_s);
+ nx_disp_top_hdmi_set_hactive_end(h_active_e);
+ nx_disp_top_hdmi_set_vsync_hsstart_end(v_sync_hs_se0, v_sync_hs_se1);
+}
+
+static int hdmi_prepare(struct dp_sync_info *sync)
+{
+ int width = sync->h_active_len;
+ int hsw = sync->h_sync_width;
+ int hfp = sync->h_front_porch;
+ int hbp = sync->h_back_porch;
+ int height = sync->v_active_len;
+ int vsw = sync->v_sync_width;
+ int vfp = sync->v_front_porch;
+ int vbp = sync->v_back_porch;
+
+ u32 h_blank, h_line, h_sync_start, h_sync_end;
+ u32 v_blank, v2_blank, v_line;
+ u32 v_sync_line_bef_1, v_sync_line_bef_2;
+
+ u32 fixed_ffff = 0xffff;
+
+ /* calculate sync variables */
+ h_blank = hfp + hsw + hbp;
+ v_blank = vfp + vsw + vbp;
+ v2_blank = height + vfp + vsw + vbp;
+ v_line = height + vfp + vsw + vbp; /* total v */
+ h_line = width + hfp + hsw + hbp; /* total h */
+ h_sync_start = hfp;
+ h_sync_end = hfp + hsw;
+ v_sync_line_bef_1 = vfp;
+ v_sync_line_bef_2 = vfp + vsw;
+
+ /* no blue screen mode, encoding order as it is */
+ nx_hdmi_set_reg(0, HDMI_LINK_HDMI_CON_0, (0 << 5) | (1 << 4));
+
+ /* set HDMI_LINK_BLUE_SCREEN_* to 0x0 */
+ nx_hdmi_set_reg(0, HDMI_LINK_BLUE_SCREEN_R_0, 0x5555);
+ nx_hdmi_set_reg(0, HDMI_LINK_BLUE_SCREEN_R_1, 0x5555);
+ nx_hdmi_set_reg(0, HDMI_LINK_BLUE_SCREEN_G_0, 0x5555);
+ nx_hdmi_set_reg(0, HDMI_LINK_BLUE_SCREEN_G_1, 0x5555);
+ nx_hdmi_set_reg(0, HDMI_LINK_BLUE_SCREEN_B_0, 0x5555);
+ nx_hdmi_set_reg(0, HDMI_LINK_BLUE_SCREEN_B_1, 0x5555);
+
+ /* set HDMI_CON_1 to 0x0 */
+ nx_hdmi_set_reg(0, HDMI_LINK_HDMI_CON_1, 0x0);
+ nx_hdmi_set_reg(0, HDMI_LINK_HDMI_CON_2, 0x0);
+
+ /* set interrupt : enable hpd_plug, hpd_unplug */
+ nx_hdmi_set_reg(0, HDMI_LINK_INTC_CON_0,
+ (1 << 6) | (1 << 3) | (1 << 2));
+
+ /* set STATUS_EN to 0x17 */
+ nx_hdmi_set_reg(0, HDMI_LINK_STATUS_EN, 0x17);
+
+ /* TODO set HDP to 0x0 : later check hpd */
+ nx_hdmi_set_reg(0, HDMI_LINK_HPD, 0x0);
+
+ /* set MODE_SEL to 0x02 */
+ nx_hdmi_set_reg(0, HDMI_LINK_MODE_SEL, 0x2);
+
+ /* set H_BLANK_*, V1_BLANK_*, V2_BLANK_*, V_LINE_*,
+ * H_LINE_*, H_SYNC_START_*, H_SYNC_END_ *
+ * V_SYNC_LINE_BEF_1_*, V_SYNC_LINE_BEF_2_*
+ */
+ nx_hdmi_set_reg(0, HDMI_LINK_H_BLANK_0, h_blank % 256);
+ nx_hdmi_set_reg(0, HDMI_LINK_H_BLANK_1, h_blank >> 8);
+ nx_hdmi_set_reg(0, HDMI_LINK_V1_BLANK_0, v_blank % 256);
+ nx_hdmi_set_reg(0, HDMI_LINK_V1_BLANK_1, v_blank >> 8);
+ nx_hdmi_set_reg(0, HDMI_LINK_V2_BLANK_0, v2_blank % 256);
+ nx_hdmi_set_reg(0, HDMI_LINK_V2_BLANK_1, v2_blank >> 8);
+ nx_hdmi_set_reg(0, HDMI_LINK_V_LINE_0, v_line % 256);
+ nx_hdmi_set_reg(0, HDMI_LINK_V_LINE_1, v_line >> 8);
+ nx_hdmi_set_reg(0, HDMI_LINK_H_LINE_0, h_line % 256);
+ nx_hdmi_set_reg(0, HDMI_LINK_H_LINE_1, h_line >> 8);
+
+ if (width == 1280) {
+ nx_hdmi_set_reg(0, HDMI_LINK_HSYNC_POL, 0x1);
+ nx_hdmi_set_reg(0, HDMI_LINK_VSYNC_POL, 0x1);
+ } else {
+ nx_hdmi_set_reg(0, HDMI_LINK_HSYNC_POL, 0x0);
+ nx_hdmi_set_reg(0, HDMI_LINK_VSYNC_POL, 0x0);
+ }
+
+ nx_hdmi_set_reg(0, HDMI_LINK_INT_PRO_MODE, 0x0);
+
+ nx_hdmi_set_reg(0, HDMI_LINK_H_SYNC_START_0, (h_sync_start % 256) - 2);
+ nx_hdmi_set_reg(0, HDMI_LINK_H_SYNC_START_1, h_sync_start >> 8);
+ nx_hdmi_set_reg(0, HDMI_LINK_H_SYNC_END_0, (h_sync_end % 256) - 2);
+ nx_hdmi_set_reg(0, HDMI_LINK_H_SYNC_END_1, h_sync_end >> 8);
+ nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_BEF_1_0,
+ v_sync_line_bef_1 % 256);
+ nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_BEF_1_1,
+ v_sync_line_bef_1 >> 8);
+ nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_BEF_2_0,
+ v_sync_line_bef_2 % 256);
+ nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_BEF_2_1,
+ v_sync_line_bef_2 >> 8);
+
+ /* Set V_SYNC_LINE_AFT*, V_SYNC_LINE_AFT_PXL*, VACT_SPACE* */
+ nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_1_0, fixed_ffff % 256);
+ nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_1_1, fixed_ffff >> 8);
+ nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_2_0, fixed_ffff % 256);
+ nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_2_1, fixed_ffff >> 8);
+ nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_3_0, fixed_ffff % 256);
+ nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_3_1, fixed_ffff >> 8);
+ nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_4_0, fixed_ffff % 256);
+ nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_4_1, fixed_ffff >> 8);
+ nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_5_0, fixed_ffff % 256);
+ nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_5_1, fixed_ffff >> 8);
+ nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_6_0, fixed_ffff % 256);
+ nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_6_1, fixed_ffff >> 8);
+
+ nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_PXL_1_0, fixed_ffff % 256);
+ nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_PXL_1_1, fixed_ffff >> 8);
+ nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_PXL_2_0, fixed_ffff % 256);
+ nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_PXL_2_1, fixed_ffff >> 8);
+ nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_PXL_3_0, fixed_ffff % 256);
+ nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_PXL_3_1, fixed_ffff >> 8);
+ nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_PXL_4_0, fixed_ffff % 256);
+ nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_PXL_4_1, fixed_ffff >> 8);
+ nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_PXL_5_0, fixed_ffff % 256);
+ nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_PXL_5_1, fixed_ffff >> 8);
+ nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_PXL_6_0, fixed_ffff % 256);
+ nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_PXL_6_1, fixed_ffff >> 8);
+
+ nx_hdmi_set_reg(0, HDMI_LINK_VACT_SPACE1_0, fixed_ffff % 256);
+ nx_hdmi_set_reg(0, HDMI_LINK_VACT_SPACE1_1, fixed_ffff >> 8);
+ nx_hdmi_set_reg(0, HDMI_LINK_VACT_SPACE2_0, fixed_ffff % 256);
+ nx_hdmi_set_reg(0, HDMI_LINK_VACT_SPACE2_1, fixed_ffff >> 8);
+ nx_hdmi_set_reg(0, HDMI_LINK_VACT_SPACE3_0, fixed_ffff % 256);
+ nx_hdmi_set_reg(0, HDMI_LINK_VACT_SPACE3_1, fixed_ffff >> 8);
+ nx_hdmi_set_reg(0, HDMI_LINK_VACT_SPACE4_0, fixed_ffff % 256);
+ nx_hdmi_set_reg(0, HDMI_LINK_VACT_SPACE4_1, fixed_ffff >> 8);
+ nx_hdmi_set_reg(0, HDMI_LINK_VACT_SPACE5_0, fixed_ffff % 256);
+ nx_hdmi_set_reg(0, HDMI_LINK_VACT_SPACE5_1, fixed_ffff >> 8);
+ nx_hdmi_set_reg(0, HDMI_LINK_VACT_SPACE6_0, fixed_ffff % 256);
+ nx_hdmi_set_reg(0, HDMI_LINK_VACT_SPACE6_1, fixed_ffff >> 8);
+
+ nx_hdmi_set_reg(0, HDMI_LINK_CSC_MUX, 0x0);
+ nx_hdmi_set_reg(0, HDMI_LINK_SYNC_GEN_MUX, 0x0);
+
+ nx_hdmi_set_reg(0, HDMI_LINK_SEND_START_0, 0xfd);
+ nx_hdmi_set_reg(0, HDMI_LINK_SEND_START_1, 0x01);
+ nx_hdmi_set_reg(0, HDMI_LINK_SEND_END_0, 0x0d);
+ nx_hdmi_set_reg(0, HDMI_LINK_SEND_END_1, 0x3a);
+ nx_hdmi_set_reg(0, HDMI_LINK_SEND_END_2, 0x08);
+
+ /* Set DC_CONTROL to 0x00 */
+ nx_hdmi_set_reg(0, HDMI_LINK_DC_CONTROL, 0x0);
+
+#if CONFIG_HDMI_PATTERN
+ nx_hdmi_set_reg(0, HDMI_LINK_VIDEO_PATTERN_GEN, 0x1);
+#else
+ nx_hdmi_set_reg(0, HDMI_LINK_VIDEO_PATTERN_GEN, 0x0);
+#endif
+
+ nx_hdmi_set_reg(0, HDMI_LINK_GCP_CON, 0x0a);
+ return 0;
+}
+
+static void hdmi_init(void)
+{
+ void *base;
+ /**
+ * [SEQ 2] set the HDMI CLKGEN's PCLKMODE to always enabled
+ */
+ base =
+ __io_address(nx_disp_top_clkgen_get_physical_address(hdmi_clkgen));
+ nx_disp_top_clkgen_set_base_address(hdmi_clkgen, base);
+ nx_disp_top_clkgen_set_clock_pclk_mode(hdmi_clkgen, nx_pclkmode_always);
+
+ base = __io_address(nx_hdmi_get_physical_address(0));
+ nx_hdmi_set_base_address(0, base);
+
+ /**
+ * [SEQ 3] set the 0xC001100C[0] to 1
+ */
+ nx_tieoff_set(NX_TIEOFF_DISPLAYTOP0_i_HDMI_PHY_REFCLK_SEL, 1);
+
+ /**
+ * [SEQ 4] release the resets of HDMI.i_PHY_nRST and HDMI.i_nRST
+ */
+ nx_rstcon_setrst(RESET_ID_HDMI_PHY, RSTCON_ASSERT);
+ nx_rstcon_setrst(RESET_ID_HDMI, RSTCON_ASSERT);
+ nx_rstcon_setrst(RESET_ID_HDMI_PHY, RSTCON_NEGATE);
+ nx_rstcon_setrst(RESET_ID_HDMI, RSTCON_NEGATE);
+}
+
+void hdmi_enable(int input, int preset, struct dp_sync_info *sync, int enable)
+{
+ if (enable) {
+ nx_hdmi_set_reg(0, HDMI_LINK_HDMI_CON_0,
+ (nx_hdmi_get_reg(0, HDMI_LINK_HDMI_CON_0) |
+ 0x1));
+ hdmi_vsync(sync);
+ } else {
+ hdmi_phy_enable(preset, 0);
+ }
+}
+
+static int hdmi_setup(int input, int preset,
+ struct dp_sync_info *sync, struct dp_ctrl_info *ctrl)
+{
+ u32 HDMI_SEL = 0;
+ int ret;
+
+ switch (input) {
+ case DP_DEVICE_DP0:
+ HDMI_SEL = primary_mlc;
+ break;
+ case DP_DEVICE_DP1:
+ HDMI_SEL = secondary_mlc;
+ break;
+ case DP_DEVICE_RESCONV:
+ HDMI_SEL = resolution_conv;
+ break;
+ default:
+ printf("HDMI: not support source device %d\n", input);
+ return -EINVAL;
+ }
+
+ /**
+ * [SEQ 5] set up the HDMI PHY to specific video clock.
+ */
+ ret = hdmi_phy_enable(preset, 1);
+ if (ret < 0)
+ return ret;
+
+ /**
+ * [SEQ 6] I2S (or SPDIFTX) configuration for the source audio data
+ * this is done in another user app - ex> Android Audio HAL
+ */
+
+ /**
+ * [SEQ 7] Wait for ECID ready
+ */
+
+ /**
+ * [SEQ 8] release the resets of HDMI.i_VIDEO_nRST and HDMI.i_SPDIF_nRST
+ * and HDMI.i_TMDS_nRST
+ */
+ hdmi_reset();
+
+ /**
+ * [SEQ 9] Wait for HDMI PHY ready (wait until 0xC0200020.[0], 1)
+ */
+ if (hdmi_wait_phy_ready() == 0) {
+ printf("%s: failed to wait for hdmiphy ready\n", __func__);
+ hdmi_phy_enable(preset, 0);
+ return -EIO;
+ }
+ /* set mux */
+ nx_disp_top_set_hdmimux(1, HDMI_SEL);
+
+ /**
+ * [SEC 10] Set the DPC CLKGEN's Source Clock to HDMI_CLK &
+ * Set Sync Parameter
+ */
+ hdmi_clock();
+ /* set hdmi link clk to clkgen vs default is hdmi phy clk */
+
+ /**
+ * [SEQ 11] Set up the HDMI Converter parameters
+ */
+ hdmi_get_vsync(preset, sync, ctrl);
+ hdmi_prepare(sync);
+
+ return 0;
+}
+
+void nx_hdmi_display(int module,
+ struct dp_sync_info *sync, struct dp_ctrl_info *ctrl,
+ struct dp_plane_top *top, struct dp_plane_info *planes,
+ struct dp_hdmi_dev *dev)
+{
+ struct dp_plane_info *plane = planes;
+ int input = module == 0 ? DP_DEVICE_DP0 : DP_DEVICE_DP1;
+ int count = top->plane_num;
+ int preset = dev->preset;
+ int i = 0;
+
+ debug("HDMI: display.%d\n", module);
+
+ switch (preset) {
+ case 0:
+ top->screen_width = 1280;
+ top->screen_height = 720;
+ sync->h_active_len = 1280;
+ sync->v_active_len = 720;
+ break;
+ case 1:
+ top->screen_width = 1920;
+ top->screen_height = 1080;
+ sync->h_active_len = 1920;
+ sync->v_active_len = 1080;
+ break;
+ default:
+ printf("hdmi not support preset %d\n", preset);
+ return;
+ }
+
+ printf("HDMI: display.%d, preset %d (%4d * %4d)\n",
+ module, preset, top->screen_width, top->screen_height);
+
+ dp_control_init(module);
+ dp_plane_init(module);
+
+ hdmi_init();
+ hdmi_setup(input, preset, sync, ctrl);
+
+ dp_plane_screen_setup(module, top);
+ for (i = 0; count > i; i++, plane++) {
+ if (!plane->enable)
+ continue;
+ dp_plane_layer_setup(module, plane);
+ dp_plane_layer_enable(module, plane, 1);
+ }
+ dp_plane_screen_enable(module, 1);
+
+ dp_control_setup(module, sync, ctrl);
+ dp_control_enable(module, 1);
+
+ hdmi_enable(input, preset, sync, 1);
+}
diff --git a/drivers/video/nexell/s5pxx18_dp_lvds.c b/drivers/video/nexell/s5pxx18_dp_lvds.c
new file mode 100644
index 0000000..f8ea63f
--- /dev/null
+++ b/drivers/video/nexell/s5pxx18_dp_lvds.c
@@ -0,0 +1,274 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Nexell Co., Ltd.
+ *
+ * Author: junghyun, kim <jhkim@nexell.co.kr>
+ */
+
+#include <config.h>
+#include <common.h>
+#include <errno.h>
+
+#include <asm/arch/nexell.h>
+#include <asm/arch/reset.h>
+#include <asm/arch/display.h>
+
+#include "soc/s5pxx18_soc_lvds.h"
+#include "soc/s5pxx18_soc_disptop.h"
+#include "soc/s5pxx18_soc_disptop_clk.h"
+
+#define __io_address(a) (void *)(uintptr_t)(a)
+
+static void lvds_phy_reset(void)
+{
+ nx_rstcon_setrst(RESET_ID_LVDS, RSTCON_ASSERT);
+ nx_rstcon_setrst(RESET_ID_LVDS, RSTCON_NEGATE);
+}
+
+static void lvds_init(void)
+{
+ int clkid = DP_CLOCK_LVDS;
+ int index = 0;
+ void *base;
+
+ base = __io_address(nx_disp_top_clkgen_get_physical_address(clkid));
+ nx_disp_top_clkgen_set_base_address(clkid, base);
+
+ nx_lvds_initialize();
+
+ for (index = 0; nx_lvds_get_number_of_module() > index; index++)
+ nx_lvds_set_base_address(index,
+ (void *)__io_address(nx_lvds_get_physical_address(index)));
+
+ nx_disp_top_clkgen_set_clock_pclk_mode(clkid, nx_pclkmode_always);
+}
+
+static void lvds_enable(int enable)
+{
+ int clkid = DP_CLOCK_LVDS;
+ int on = (enable ? 1 : 0);
+
+ nx_disp_top_clkgen_set_clock_divisor_enable(clkid, on);
+}
+
+static int lvds_setup(int module, int input,
+ struct dp_sync_info *sync, struct dp_ctrl_info *ctrl,
+ struct dp_lvds_dev *dev)
+{
+ unsigned int val;
+ int clkid = DP_CLOCK_LVDS;
+ enum dp_lvds_format format = DP_LVDS_FORMAT_JEIDA;
+ u32 voltage = DEF_VOLTAGE_LEVEL;
+
+ if (dev) {
+ format = dev->lvds_format;
+ voltage = dev->voltage_level;
+ }
+
+ printf("LVDS: ");
+ printf("%s, ", format == DP_LVDS_FORMAT_VESA ? "VESA" :
+ format == DP_LVDS_FORMAT_JEIDA ? "JEIDA" : "LOC");
+ printf("voltage LV:0x%x\n", voltage);
+
+ /*
+ *-------- predefined type.
+ * only change iTA to iTE in VESA mode
+ * wire [34:0] loc_VideoIn =
+ * {4'hf, 4'h0, i_VDEN, i_VSYNC, i_HSYNC, i_VD[23:0] };
+ */
+ u32 VSYNC = 25;
+ u32 HSYNC = 24;
+ u32 VDEN = 26; /* bit position */
+ u32 ONE = 34;
+ u32 ZERO = 27;
+
+ /*====================================================
+ * current not use location mode
+ *====================================================
+ */
+ u32 LOC_A[7] = {ONE, ONE, ONE, ONE, ONE, ONE, ONE};
+ u32 LOC_B[7] = {ONE, ONE, ONE, ONE, ONE, ONE, ONE};
+ u32 LOC_C[7] = {VDEN, VSYNC, HSYNC, ONE, HSYNC, VSYNC, VDEN};
+ u32 LOC_D[7] = {ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO};
+ u32 LOC_E[7] = {ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO};
+
+ switch (input) {
+ case DP_DEVICE_DP0:
+ input = 0;
+ break;
+ case DP_DEVICE_DP1:
+ input = 1;
+ break;
+ case DP_DEVICE_RESCONV:
+ input = 2;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /*
+ * select TOP MUX
+ */
+ nx_disp_top_clkgen_set_clock_divisor_enable(clkid, 0);
+ nx_disp_top_clkgen_set_clock_source(clkid, 0, ctrl->clk_src_lv0);
+ nx_disp_top_clkgen_set_clock_divisor(clkid, 0, ctrl->clk_div_lv0);
+ nx_disp_top_clkgen_set_clock_source(clkid, 1, ctrl->clk_src_lv1);
+ nx_disp_top_clkgen_set_clock_divisor(clkid, 1, ctrl->clk_div_lv1);
+
+ /*
+ * LVDS Control Pin Setting
+ */
+ val = (0 << 30) | /* CPU_I_VBLK_FLAG_SEL */
+ (0 << 29) | /* CPU_I_BVLK_FLAG */
+ (1 << 28) | /* SKINI_BST */
+ (1 << 27) | /* DLYS_BST */
+ (0 << 26) | /* I_AUTO_SEL */
+ (format << 19) | /* JEiDA data packing */
+ (0x1B << 13) | /* I_LOCK_PPM_SET, PPM setting for PLL lock */
+ (0x638 << 1); /* I_DESKEW_CNT_SEL, period of de-skew region */
+ nx_lvds_set_lvdsctrl0(0, val);
+
+ val = (0 << 28) | /* I_ATE_MODE, function mode */
+ (0 << 27) | /* I_TEST_CON_MODE, DA (test ctrl mode) */
+ (0 << 24) | /* I_TX4010X_DUMMY */
+ (0 << 15) | /* SKCCK 0 */
+ (0 << 12) | /* SKC4 (TX output skew control pin at ODD ch4) */
+ (0 << 9) | /* SKC3 (TX output skew control pin at ODD ch3) */
+ (0 << 6) | /* SKC2 (TX output skew control pin at ODD ch2) */
+ (0 << 3) | /* SKC1 (TX output skew control pin at ODD ch1) */
+ (0 << 0); /* SKC0 (TX output skew control pin@ODD ch0) */
+ nx_lvds_set_lvdsctrl1(0, val);
+
+ val = (0 << 15) | /* CK_POL_SEL, Input clock, bypass */
+ (0 << 14) | /* VSEL, VCO Freq. range. 0: Low(40MHz~90MHz),
+ * 1: High(90MHz~160MHz) */
+ (0x1 << 12) | /* S (Post-scaler) */
+ (0xA << 6) | /* M (Main divider) */
+ (0xA << 0); /* P (Pre-divider) */
+
+ nx_lvds_set_lvdsctrl2(0, val);
+ val = (0x03 << 6) | /* SK_BIAS, Bias current ctrl pin */
+ (0 << 5) | /* SKEWINI, skew selection pin, 0: bypass,
+ * 1: skew enable */
+ (0 << 4) | /* SKEW_EN_H, skew block power down, 0: power down,
+ * 1: operating */
+ (1 << 3) | /* CNTB_TDLY, delay control pin */
+ (0 << 2) | /* SEL_DATABF, input clock 1/2 division cont. pin */
+ (0x3 << 0); /* SKEW_REG_CUR, regulator bias current selection
+ * in SKEW block */
+
+ nx_lvds_set_lvdsctrl3(0, val);
+ val = (0 << 28) | /* FLT_CNT, filter control pin for PLL */
+ (0 << 27) | /* VOD_ONLY_CNT, the pre-emphasis's pre-diriver
+ * control pin (VOD only) */
+ (0 << 26) | /* CNNCT_MODE_SEL, connectivity mode selection,
+ * 0:TX operating, 1:con check */
+ (0 << 24) | /* CNNCT_CNT, connectivity ctrl pin,
+ * 0: tx operating, 1: con check */
+ (0 << 23) | /* VOD_HIGH_S, VOD control pin, 1: Vod only */
+ (0 << 22) | /* SRC_TRH, source termination resistor sel. pin */
+ (voltage << 14) |
+ (0x01 << 6) | /* CNT_PEN_H, TX driver pre-emphasis level cont. */
+ (0x4 << 3) | /* FC_CODE, vos control pin */
+ (0 << 2) | /* OUTCON, TX Driver state selectioin pin, 0:Hi-z,
+ * 1:Low */
+ (0 << 1) | /* LOCK_CNT, Lock signal selection pin, enable */
+ (0 << 0); /* AUTO_DSK_SEL, auto deskew sel. pin, normal */
+ nx_lvds_set_lvdsctrl4(0, val);
+
+ val = (0 << 24) | /* I_BIST_RESETB */
+ (0 << 23) | /* I_BIST_EN */
+ (0 << 21) | /* I_BIST_PAT_SEL */
+ (0 << 14) | /* I_BIST_USER_PATTERN */
+ (0 << 13) | /* I_BIST_FORCE_ERROR */
+ (0 << 7) | /* I_BIST_SKEW_CTRL */
+ (0 << 5) | /* I_BIST_CLK_INV */
+ (0 << 3) | /* I_BIST_DATA_INV */
+ (0 << 0); /* I_BIST_CH_SEL */
+ nx_lvds_set_lvdstmode0(0, val);
+
+ /* user do not need to modify this codes. */
+ val = (LOC_A[4] << 24) | (LOC_A[3] << 18) | (LOC_A[2] << 12) |
+ (LOC_A[1] << 6) | (LOC_A[0] << 0);
+ nx_lvds_set_lvdsloc0(0, val);
+
+ val = (LOC_B[2] << 24) | (LOC_B[1] << 18) | (LOC_B[0] << 12) |
+ (LOC_A[6] << 6) | (LOC_A[5] << 0);
+ nx_lvds_set_lvdsloc1(0, val);
+
+ val = (LOC_C[0] << 24) | (LOC_B[6] << 18) | (LOC_B[5] << 12) |
+ (LOC_B[4] << 6) | (LOC_B[3] << 0);
+ nx_lvds_set_lvdsloc2(0, val);
+
+ val = (LOC_C[5] << 24) | (LOC_C[4] << 18) | (LOC_C[3] << 12) |
+ (LOC_C[2] << 6) | (LOC_C[1] << 0);
+ nx_lvds_set_lvdsloc3(0, val);
+
+ val = (LOC_D[3] << 24) | (LOC_D[2] << 18) | (LOC_D[1] << 12) |
+ (LOC_D[0] << 6) | (LOC_C[6] << 0);
+ nx_lvds_set_lvdsloc4(0, val);
+
+ val = (LOC_E[1] << 24) | (LOC_E[0] << 18) | (LOC_D[6] << 12) |
+ (LOC_D[5] << 6) | (LOC_D[4] << 0);
+ nx_lvds_set_lvdsloc5(0, val);
+
+ val = (LOC_E[6] << 24) | (LOC_E[5] << 18) | (LOC_E[4] << 12) |
+ (LOC_E[3] << 6) | (LOC_E[2] << 0);
+ nx_lvds_set_lvdsloc6(0, val);
+
+ nx_lvds_set_lvdslocmask0(0, 0xffffffff);
+ nx_lvds_set_lvdslocmask1(0, 0xffffffff);
+
+ nx_lvds_set_lvdslocpol0(0, (0 << 19) | (0 << 18));
+
+ /*
+ * select TOP MUX
+ */
+ nx_disp_top_set_lvdsmux(1, input);
+
+ /*
+ * LVDS PHY Reset, make sure last.
+ */
+ lvds_phy_reset();
+
+ return 0;
+}
+
+void nx_lvds_display(int module,
+ struct dp_sync_info *sync, struct dp_ctrl_info *ctrl,
+ struct dp_plane_top *top, struct dp_plane_info *planes,
+ struct dp_lvds_dev *dev)
+{
+ struct dp_plane_info *plane = planes;
+ int input = module == 0 ? DP_DEVICE_DP0 : DP_DEVICE_DP1;
+ int count = top->plane_num;
+ int i = 0;
+
+ printf("LVDS: dp.%d\n", module);
+
+ dp_control_init(module);
+ dp_plane_init(module);
+
+ lvds_init();
+
+ /* set plane */
+ dp_plane_screen_setup(module, top);
+
+ for (i = 0; count > i; i++, plane++) {
+ if (!plane->enable)
+ continue;
+ dp_plane_layer_setup(module, plane);
+ dp_plane_layer_enable(module, plane, 1);
+ }
+
+ dp_plane_screen_enable(module, 1);
+
+ /* set lvds */
+ lvds_setup(module, input, sync, ctrl, dev);
+
+ lvds_enable(1);
+
+ /* set dp control */
+ dp_control_setup(module, sync, ctrl);
+ dp_control_enable(module, 1);
+}
diff --git a/drivers/video/nexell/s5pxx18_dp_mipi.c b/drivers/video/nexell/s5pxx18_dp_mipi.c
new file mode 100644
index 0000000..670272b
--- /dev/null
+++ b/drivers/video/nexell/s5pxx18_dp_mipi.c
@@ -0,0 +1,677 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Nexell Co., Ltd.
+ *
+ * Author: junghyun, kim <jhkim@nexell.co.kr>
+ */
+
+#include <config.h>
+#include <common.h>
+#include <errno.h>
+
+#include <asm/arch/nexell.h>
+#include <asm/arch/tieoff.h>
+#include <asm/arch/reset.h>
+#include <asm/arch/display.h>
+
+#include "soc/s5pxx18_soc_mipi.h"
+#include "soc/s5pxx18_soc_disptop.h"
+#include "soc/s5pxx18_soc_disptop_clk.h"
+
+#define PLLPMS_1000MHZ 0x33E8
+#define BANDCTL_1000MHZ 0xF
+#define PLLPMS_960MHZ 0x2280
+#define BANDCTL_960MHZ 0xF
+#define PLLPMS_900MHZ 0x2258
+#define BANDCTL_900MHZ 0xE
+#define PLLPMS_840MHZ 0x2230
+#define BANDCTL_840MHZ 0xD
+#define PLLPMS_750MHZ 0x43E8
+#define BANDCTL_750MHZ 0xC
+#define PLLPMS_660MHZ 0x21B8
+#define BANDCTL_660MHZ 0xB
+#define PLLPMS_600MHZ 0x2190
+#define BANDCTL_600MHZ 0xA
+#define PLLPMS_540MHZ 0x2168
+#define BANDCTL_540MHZ 0x9
+#define PLLPMS_512MHZ 0x03200
+#define BANDCTL_512MHZ 0x9
+#define PLLPMS_480MHZ 0x2281
+#define BANDCTL_480MHZ 0x8
+#define PLLPMS_420MHZ 0x2231
+#define BANDCTL_420MHZ 0x7
+#define PLLPMS_402MHZ 0x2219
+#define BANDCTL_402MHZ 0x7
+#define PLLPMS_330MHZ 0x21B9
+#define BANDCTL_330MHZ 0x6
+#define PLLPMS_300MHZ 0x2191
+#define BANDCTL_300MHZ 0x5
+#define PLLPMS_210MHZ 0x2232
+#define BANDCTL_210MHZ 0x4
+#define PLLPMS_180MHZ 0x21E2
+#define BANDCTL_180MHZ 0x3
+#define PLLPMS_150MHZ 0x2192
+#define BANDCTL_150MHZ 0x2
+#define PLLPMS_100MHZ 0x3323
+#define BANDCTL_100MHZ 0x1
+#define PLLPMS_80MHZ 0x3283
+#define BANDCTL_80MHZ 0x0
+
+#define MIPI_INDEX 0
+#define MIPI_EXC_PRE_VALUE 1
+#define MIPI_DSI_IRQ_MASK 29
+
+#define __io_address(a) (void *)(uintptr_t)(a)
+
+struct mipi_xfer_msg {
+ u8 id, data[2];
+ u16 flags;
+ const u8 *tx_buf;
+ u16 tx_len;
+ u8 *rx_buf;
+ u16 rx_len;
+};
+
+static void mipi_reset(void)
+{
+ /* tieoff */
+ nx_tieoff_set(NX_TIEOFF_MIPI0_NX_DPSRAM_1R1W_EMAA, 3);
+ nx_tieoff_set(NX_TIEOFF_MIPI0_NX_DPSRAM_1R1W_EMAB, 3);
+
+ /* reset */
+ nx_rstcon_setrst(RESET_ID_MIPI, RSTCON_ASSERT);
+ nx_rstcon_setrst(RESET_ID_MIPI_DSI, RSTCON_ASSERT);
+ nx_rstcon_setrst(RESET_ID_MIPI_CSI, RSTCON_ASSERT);
+ nx_rstcon_setrst(RESET_ID_MIPI_PHY_S, RSTCON_ASSERT);
+ nx_rstcon_setrst(RESET_ID_MIPI_PHY_M, RSTCON_ASSERT);
+
+ nx_rstcon_setrst(RESET_ID_MIPI, RSTCON_NEGATE);
+ nx_rstcon_setrst(RESET_ID_MIPI_DSI, RSTCON_NEGATE);
+ nx_rstcon_setrst(RESET_ID_MIPI_PHY_S, RSTCON_NEGATE);
+ nx_rstcon_setrst(RESET_ID_MIPI_PHY_M, RSTCON_NEGATE);
+}
+
+static void mipi_init(void)
+{
+ int clkid = DP_CLOCK_MIPI;
+ void *base;
+
+ /*
+ * neet to reset before open
+ */
+ mipi_reset();
+
+ base = __io_address(nx_disp_top_clkgen_get_physical_address(clkid));
+ nx_disp_top_clkgen_set_base_address(clkid, base);
+ nx_disp_top_clkgen_set_clock_pclk_mode(clkid, nx_pclkmode_always);
+
+ base = __io_address(nx_mipi_get_physical_address(0));
+ nx_mipi_set_base_address(0, base);
+}
+
+static int mipi_get_phy_pll(int bitrate, unsigned int *pllpms,
+ unsigned int *bandctl)
+{
+ unsigned int pms, ctl;
+
+ switch (bitrate) {
+ case 1000:
+ pms = PLLPMS_1000MHZ;
+ ctl = BANDCTL_1000MHZ;
+ break;
+ case 960:
+ pms = PLLPMS_960MHZ;
+ ctl = BANDCTL_960MHZ;
+ break;
+ case 900:
+ pms = PLLPMS_900MHZ;
+ ctl = BANDCTL_900MHZ;
+ break;
+ case 840:
+ pms = PLLPMS_840MHZ;
+ ctl = BANDCTL_840MHZ;
+ break;
+ case 750:
+ pms = PLLPMS_750MHZ;
+ ctl = BANDCTL_750MHZ;
+ break;
+ case 660:
+ pms = PLLPMS_660MHZ;
+ ctl = BANDCTL_660MHZ;
+ break;
+ case 600:
+ pms = PLLPMS_600MHZ;
+ ctl = BANDCTL_600MHZ;
+ break;
+ case 540:
+ pms = PLLPMS_540MHZ;
+ ctl = BANDCTL_540MHZ;
+ break;
+ case 512:
+ pms = PLLPMS_512MHZ;
+ ctl = BANDCTL_512MHZ;
+ break;
+ case 480:
+ pms = PLLPMS_480MHZ;
+ ctl = BANDCTL_480MHZ;
+ break;
+ case 420:
+ pms = PLLPMS_420MHZ;
+ ctl = BANDCTL_420MHZ;
+ break;
+ case 402:
+ pms = PLLPMS_402MHZ;
+ ctl = BANDCTL_402MHZ;
+ break;
+ case 330:
+ pms = PLLPMS_330MHZ;
+ ctl = BANDCTL_330MHZ;
+ break;
+ case 300:
+ pms = PLLPMS_300MHZ;
+ ctl = BANDCTL_300MHZ;
+ break;
+ case 210:
+ pms = PLLPMS_210MHZ;
+ ctl = BANDCTL_210MHZ;
+ break;
+ case 180:
+ pms = PLLPMS_180MHZ;
+ ctl = BANDCTL_180MHZ;
+ break;
+ case 150:
+ pms = PLLPMS_150MHZ;
+ ctl = BANDCTL_150MHZ;
+ break;
+ case 100:
+ pms = PLLPMS_100MHZ;
+ ctl = BANDCTL_100MHZ;
+ break;
+ case 80:
+ pms = PLLPMS_80MHZ;
+ ctl = BANDCTL_80MHZ;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ *pllpms = pms;
+ *bandctl = ctl;
+
+ return 0;
+}
+
+static int mipi_prepare(int module, int input,
+ struct dp_sync_info *sync, struct dp_ctrl_info *ctrl,
+ struct dp_mipi_dev *mipi)
+{
+ int index = MIPI_INDEX;
+ u32 esc_pre_value = MIPI_EXC_PRE_VALUE;
+ int lpm = mipi->lpm_trans;
+ int ret = 0;
+
+ ret = mipi_get_phy_pll(mipi->hs_bitrate,
+ &mipi->hs_pllpms, &mipi->hs_bandctl);
+ if (ret < 0)
+ return ret;
+
+ ret = mipi_get_phy_pll(mipi->lp_bitrate,
+ &mipi->lp_pllpms, &mipi->lp_bandctl);
+ if (ret < 0)
+ return ret;
+
+ debug("%s: mipi lp:%dmhz:0x%x:0x%x, hs:%dmhz:0x%x:0x%x, %s trans\n",
+ __func__, mipi->lp_bitrate, mipi->lp_pllpms, mipi->lp_bandctl,
+ mipi->hs_bitrate, mipi->hs_pllpms, mipi->hs_bandctl,
+ lpm ? "low" : "high");
+
+ if (lpm)
+ nx_mipi_dsi_set_pll(index, 1, 0xFFFFFFFF,
+ mipi->lp_pllpms, mipi->lp_bandctl, 0, 0);
+ else
+ nx_mipi_dsi_set_pll(index, 1, 0xFFFFFFFF,
+ mipi->hs_pllpms, mipi->hs_bandctl, 0, 0);
+
+#ifdef CONFIG_ARCH_S5P4418
+ /*
+ * disable the escape clock generating prescaler
+ * before soft reset.
+ */
+ nx_mipi_dsi_set_clock(index, 0, 0, 1, 1, 1, 0, 0, 0, 0, 10);
+ mdelay(1);
+#endif
+
+ nx_mipi_dsi_software_reset(index);
+ nx_mipi_dsi_set_clock(index, 0, 0, 1, 1, 1, 0, 0, 0, 1, esc_pre_value);
+ nx_mipi_dsi_set_phy(index, 0, 1, 1, 0, 0, 0, 0, 0);
+
+ if (lpm)
+ nx_mipi_dsi_set_escape_lp(index, nx_mipi_dsi_lpmode_lp,
+ nx_mipi_dsi_lpmode_lp);
+ else
+ nx_mipi_dsi_set_escape_lp(index, nx_mipi_dsi_lpmode_hs,
+ nx_mipi_dsi_lpmode_hs);
+ mdelay(20);
+
+ return 0;
+}
+
+static int mipi_enable(int module, int input,
+ struct dp_sync_info *sync, struct dp_ctrl_info *ctrl,
+ struct dp_mipi_dev *mipi)
+{
+ struct mipi_dsi_device *dsi = &mipi->dsi;
+ int clkid = DP_CLOCK_MIPI;
+ int index = MIPI_INDEX;
+ int width = sync->h_active_len;
+ int height = sync->v_active_len;
+ int HFP = sync->h_front_porch;
+ int HBP = sync->h_back_porch;
+ int HS = sync->h_sync_width;
+ int VFP = sync->v_front_porch;
+ int VBP = sync->v_back_porch;
+ int VS = sync->v_sync_width;
+ int en_prescaler = 1;
+ u32 esc_pre_value = MIPI_EXC_PRE_VALUE;
+
+ int txhsclock = 1;
+ int lpm = mipi->lpm_trans;
+ bool command_mode = mipi->command_mode;
+
+ enum nx_mipi_dsi_format dsi_format;
+ int data_len = dsi->lanes - 1;
+ bool burst = dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST ? true : false;
+ bool eot_enable = dsi->mode_flags & MIPI_DSI_MODE_EOT_PACKET ?
+ false : true;
+
+ /*
+ * disable the escape clock generating prescaler
+ * before soft reset.
+ */
+#ifdef CONFIG_ARCH_S5P4418
+ en_prescaler = 0;
+#endif
+
+ debug("%s: mode:%s, lanes.%d\n", __func__,
+ command_mode ? "command" : "video", data_len + 1);
+
+ if (lpm)
+ nx_mipi_dsi_set_escape_lp(index,
+ nx_mipi_dsi_lpmode_hs,
+ nx_mipi_dsi_lpmode_hs);
+
+ nx_mipi_dsi_set_pll(index, 1, 0xFFFFFFFF,
+ mipi->hs_pllpms, mipi->hs_bandctl, 0, 0);
+ mdelay(1);
+
+ nx_mipi_dsi_set_clock(index, 0, 0, 1, 1, 1, 0, 0, 0, en_prescaler, 10);
+ mdelay(1);
+
+ nx_mipi_dsi_software_reset(index);
+ nx_mipi_dsi_set_clock(index, txhsclock, 0, 1,
+ 1, 1, 0, 0, 0, 1, esc_pre_value);
+
+ switch (data_len) {
+ case 0: /* 1 lane */
+ nx_mipi_dsi_set_phy(index, data_len, 1, 1, 0, 0, 0, 0, 0);
+ break;
+ case 1: /* 2 lane */
+ nx_mipi_dsi_set_phy(index, data_len, 1, 1, 1, 0, 0, 0, 0);
+ break;
+ case 2: /* 3 lane */
+ nx_mipi_dsi_set_phy(index, data_len, 1, 1, 1, 1, 0, 0, 0);
+ break;
+ case 3: /* 3 lane */
+ nx_mipi_dsi_set_phy(index, data_len, 1, 1, 1, 1, 1, 0, 0);
+ break;
+ default:
+ printf("%s: not support data lanes %d\n",
+ __func__, data_len + 1);
+ return -EINVAL;
+ }
+
+ switch (dsi->format) {
+ case MIPI_DSI_FMT_RGB565:
+ dsi_format = nx_mipi_dsi_format_rgb565;
+ break;
+ case MIPI_DSI_FMT_RGB666:
+ dsi_format = nx_mipi_dsi_format_rgb666;
+ break;
+ case MIPI_DSI_FMT_RGB666_PACKED:
+ dsi_format = nx_mipi_dsi_format_rgb666_packed;
+ break;
+ case MIPI_DSI_FMT_RGB888:
+ dsi_format = nx_mipi_dsi_format_rgb888;
+ break;
+ default:
+ printf("%s: not support format %d\n", __func__, dsi->format);
+ return -EINVAL;
+ }
+
+ nx_mipi_dsi_set_config_video_mode(index, 1, 0, burst,
+ nx_mipi_dsi_syncmode_event,
+ eot_enable, 1, 1, 1, 1, 0, dsi_format,
+ HFP, HBP, HS, VFP, VBP, VS, 0);
+
+ nx_mipi_dsi_set_size(index, width, height);
+
+ /* set mux */
+ nx_disp_top_set_mipimux(1, module);
+
+ /* 0 is spdif, 1 is mipi vclk */
+ nx_disp_top_clkgen_set_clock_source(clkid, 1, ctrl->clk_src_lv0);
+ nx_disp_top_clkgen_set_clock_divisor(clkid, 1,
+ ctrl->clk_div_lv1 *
+ ctrl->clk_div_lv0);
+
+ /* SPDIF and MIPI */
+ nx_disp_top_clkgen_set_clock_divisor_enable(clkid, 1);
+
+ /* START: CLKGEN, MIPI is started in setup function */
+ nx_disp_top_clkgen_set_clock_divisor_enable(clkid, true);
+ nx_mipi_dsi_set_enable(index, true);
+
+ return 0;
+}
+
+static int nx_mipi_transfer_tx(struct mipi_dsi_device *dsi,
+ struct mipi_xfer_msg *xfer)
+{
+ const u8 *txb;
+ int size, index = 0;
+ u32 data;
+
+ if (xfer->tx_len > DSI_TX_FIFO_SIZE)
+ printf("warn: tx %d size over fifo %d\n",
+ (int)xfer->tx_len, DSI_TX_FIFO_SIZE);
+
+ /* write payload */
+ size = xfer->tx_len;
+ txb = xfer->tx_buf;
+
+ while (size >= 4) {
+ data = (txb[3] << 24) | (txb[2] << 16) |
+ (txb[1] << 8) | (txb[0]);
+ nx_mipi_dsi_write_payload(index, data);
+ txb += 4, size -= 4;
+ data = 0;
+ }
+
+ switch (size) {
+ case 3:
+ data |= txb[2] << 16;
+ case 2:
+ data |= txb[1] << 8;
+ case 1:
+ data |= txb[0];
+ nx_mipi_dsi_write_payload(index, data);
+ break;
+ case 0:
+ break; /* no payload */
+ }
+
+ /* write packet hdr */
+ data = (xfer->data[1] << 16) | (xfer->data[0] << 8) | xfer->id;
+
+ nx_mipi_dsi_write_pkheader(index, data);
+
+ return 0;
+}
+
+static int nx_mipi_transfer_done(struct mipi_dsi_device *dsi)
+{
+ int index = 0, count = 100;
+ u32 value;
+
+ do {
+ mdelay(1);
+ value = nx_mipi_dsi_read_fifo_status(index);
+ if (((1 << 22) & value))
+ break;
+ } while (count-- > 0);
+
+ if (count < 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int nx_mipi_transfer_rx(struct mipi_dsi_device *dsi,
+ struct mipi_xfer_msg *xfer)
+{
+ u8 *rxb = xfer->rx_buf;
+ int index = 0, rx_len = 0;
+ u32 data, count = 0;
+ u16 size;
+ int err = -EINVAL;
+
+ nx_mipi_dsi_clear_interrupt_pending(index, 18);
+
+ while (1) {
+ /* Completes receiving data. */
+ if (nx_mipi_dsi_get_interrupt_pending(index, 18))
+ break;
+
+ mdelay(1);
+
+ if (count > 500) {
+ printf("%s: error recevice data\n", __func__);
+ err = -EINVAL;
+ goto clear_fifo;
+ } else {
+ count++;
+ }
+ }
+
+ data = nx_mipi_dsi_read_fifo(index);
+
+ switch (data & 0x3f) {
+ case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE:
+ case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE:
+ if (xfer->rx_len >= 2) {
+ rxb[1] = data >> 16;
+ rx_len++;
+ }
+
+ /* Fall through */
+ case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE:
+ case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE:
+ rxb[0] = data >> 8;
+ rx_len++;
+ xfer->rx_len = rx_len;
+ err = rx_len;
+ goto clear_fifo;
+
+ case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT:
+ printf("DSI Error Report: 0x%04x\n", (data >> 8) & 0xffff);
+ err = rx_len;
+ goto clear_fifo;
+ }
+
+ size = (data >> 8) & 0xffff;
+
+ if (size > xfer->rx_len)
+ size = xfer->rx_len;
+ else if (size < xfer->rx_len)
+ xfer->rx_len = size;
+
+ size = xfer->rx_len - rx_len;
+ rx_len += size;
+
+ /* Receive payload */
+ while (size >= 4) {
+ data = nx_mipi_dsi_read_fifo(index);
+ rxb[0] = (data >> 0) & 0xff;
+ rxb[1] = (data >> 8) & 0xff;
+ rxb[2] = (data >> 16) & 0xff;
+ rxb[3] = (data >> 24) & 0xff;
+ rxb += 4, size -= 4;
+ }
+
+ if (size) {
+ data = nx_mipi_dsi_read_fifo(index);
+ switch (size) {
+ case 3:
+ rxb[2] = (data >> 16) & 0xff;
+ case 2:
+ rxb[1] = (data >> 8) & 0xff;
+ case 1:
+ rxb[0] = data & 0xff;
+ }
+ }
+
+ if (rx_len == xfer->rx_len)
+ err = rx_len;
+
+clear_fifo:
+ size = DSI_RX_FIFO_SIZE / 4;
+ do {
+ data = nx_mipi_dsi_read_fifo(index);
+ if (data == DSI_RX_FIFO_EMPTY)
+ break;
+ } while (--size);
+
+ return err;
+}
+
+#define IS_SHORT(t) (9 > ((t) & 0x0f))
+
+static int nx_mipi_transfer(struct mipi_dsi_device *dsi,
+ const struct mipi_dsi_msg *msg)
+{
+ struct mipi_xfer_msg xfer;
+ int err;
+
+ if (!msg->tx_len)
+ return -EINVAL;
+
+ /* set id */
+ xfer.id = msg->type | (msg->channel << 6);
+
+ /* short type msg */
+ if (IS_SHORT(msg->type)) {
+ const char *txb = msg->tx_buf;
+
+ if (msg->tx_len > 2)
+ return -EINVAL;
+
+ xfer.tx_len = 0; /* no payload */
+ xfer.data[0] = txb[0];
+ xfer.data[1] = (msg->tx_len == 2) ? txb[1] : 0;
+ xfer.tx_buf = NULL;
+ } else {
+ xfer.tx_len = msg->tx_len;
+ xfer.data[0] = msg->tx_len & 0xff;
+ xfer.data[1] = msg->tx_len >> 8;
+ xfer.tx_buf = msg->tx_buf;
+ }
+
+ xfer.rx_len = msg->rx_len;
+ xfer.rx_buf = msg->rx_buf;
+ xfer.flags = msg->flags;
+
+ err = nx_mipi_transfer_tx(dsi, &xfer);
+
+ if (xfer.rx_len)
+ err = nx_mipi_transfer_rx(dsi, &xfer);
+
+ nx_mipi_transfer_done(dsi);
+
+ return err;
+}
+
+static ssize_t nx_mipi_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;
+ }
+
+ if (dsi->mode_flags & MIPI_DSI_MODE_LPM)
+ msg.flags |= MIPI_DSI_MSG_USE_LPM;
+
+ return nx_mipi_transfer(dsi, &msg);
+}
+
+__weak int nx_mipi_dsi_lcd_bind(struct mipi_dsi_device *dsi)
+{
+ return 0;
+}
+
+/*
+ * disply
+ * MIPI DSI Setting
+ * (1) Initiallize MIPI(DSIM,DPHY,PLL)
+ * (2) Initiallize LCD
+ * (3) ReInitiallize MIPI(DSIM only)
+ * (4) Turn on display(MLC,DPC,...)
+ */
+void nx_mipi_display(int module,
+ struct dp_sync_info *sync, struct dp_ctrl_info *ctrl,
+ struct dp_plane_top *top, struct dp_plane_info *planes,
+ struct dp_mipi_dev *dev)
+{
+ struct dp_plane_info *plane = planes;
+ struct mipi_dsi_device *dsi = &dev->dsi;
+ int input = module == 0 ? DP_DEVICE_DP0 : DP_DEVICE_DP1;
+ int count = top->plane_num;
+ int i = 0, ret;
+
+ printf("MIPI: dp.%d\n", module);
+
+ /* map mipi-dsi write callback func */
+ dsi->write_buffer = nx_mipi_write_buffer;
+
+ ret = nx_mipi_dsi_lcd_bind(dsi);
+ if (ret) {
+ printf("Error: bind mipi-dsi lcd driver !\n");
+ return;
+ }
+
+ dp_control_init(module);
+ dp_plane_init(module);
+
+ mipi_init();
+
+ /* set plane */
+ dp_plane_screen_setup(module, top);
+
+ for (i = 0; count > i; i++, plane++) {
+ if (!plane->enable)
+ continue;
+ dp_plane_layer_setup(module, plane);
+ dp_plane_layer_enable(module, plane, 1);
+ }
+ dp_plane_screen_enable(module, 1);
+
+ /* set mipi */
+ mipi_prepare(module, input, sync, ctrl, dev);
+
+ if (dsi->ops && dsi->ops->prepare)
+ dsi->ops->prepare(dsi);
+
+ if (dsi->ops && dsi->ops->enable)
+ dsi->ops->enable(dsi);
+
+ mipi_enable(module, input, sync, ctrl, dev);
+
+ /* set dp control */
+ dp_control_setup(module, sync, ctrl);
+ dp_control_enable(module, 1);
+}
diff --git a/drivers/video/nexell/s5pxx18_dp_rgb.c b/drivers/video/nexell/s5pxx18_dp_rgb.c
new file mode 100644
index 0000000..44e8edb
--- /dev/null
+++ b/drivers/video/nexell/s5pxx18_dp_rgb.c
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Nexell Co., Ltd.
+ *
+ * Author: junghyun, kim <jhkim@nexell.co.kr>
+ */
+
+#include <config.h>
+#include <common.h>
+#include <errno.h>
+
+#include <asm/arch/display.h>
+
+#include "soc/s5pxx18_soc_disptop.h"
+
+static int rgb_switch(int module, int input, struct dp_sync_info *sync,
+ struct dp_rgb_dev *dev)
+{
+ int mpu = dev->lcd_mpu_type;
+ int rsc = 0, sel = 0;
+
+ switch (module) {
+ case 0:
+ sel = mpu ? 1 : 0;
+ break;
+ case 1:
+ sel = rsc ? 3 : 2;
+ break;
+ default:
+ printf("Fail, %s nuknown module %d\n", __func__, module);
+ return -1;
+ }
+
+ nx_disp_top_set_primary_mux(sel);
+ return 0;
+}
+
+void nx_rgb_display(int module,
+ struct dp_sync_info *sync, struct dp_ctrl_info *ctrl,
+ struct dp_plane_top *top, struct dp_plane_info *planes,
+ struct dp_rgb_dev *dev)
+{
+ struct dp_plane_info *plane = planes;
+ int input = module == 0 ? DP_DEVICE_DP0 : DP_DEVICE_DP1;
+ int count = top->plane_num;
+ int i = 0;
+
+ printf("RGB: dp.%d\n", module);
+
+ dp_control_init(module);
+ dp_plane_init(module);
+
+ /* set plane */
+ dp_plane_screen_setup(module, top);
+
+ for (i = 0; count > i; i++, plane++) {
+ if (!plane->enable)
+ continue;
+ dp_plane_layer_setup(module, plane);
+ dp_plane_layer_enable(module, plane, 1);
+ }
+
+ dp_plane_screen_enable(module, 1);
+
+ rgb_switch(module, input, sync, dev);
+
+ dp_control_setup(module, sync, ctrl);
+ dp_control_enable(module, 1);
+}
diff --git a/drivers/video/nexell_display.c b/drivers/video/nexell_display.c
new file mode 100644
index 0000000..7ff4651
--- /dev/null
+++ b/drivers/video/nexell_display.c
@@ -0,0 +1,658 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Nexell Co., Ltd.
+ *
+ * Author: junghyun, kim <jhkim@nexell.co.kr>
+ *
+ * Copyright (C) 2019 Stefan Bosch <stefan_b@posteo.net>
+ */
+
+#include <config.h>
+#include <common.h>
+#include <dm.h>
+#include <mapmem.h>
+#include <malloc.h>
+#include <linux/compat.h>
+#include <linux/err.h>
+#include <video.h> /* For struct video_uc_platdata */
+#include <fdtdec.h>
+#include <fdt_support.h>
+#include <video_fb.h>
+#include <lcd.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <asm/arch/display.h>
+#include <asm/arch/display_dev.h>
+#include "videomodes.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if !defined(CONFIG_DM) && !defined(CONFIG_OF_CONTROL)
+static struct nx_display_dev *dp_dev;
+#endif
+
+static char *const dp_dev_str[] = {
+ [DP_DEVICE_RESCONV] = "RESCONV",
+ [DP_DEVICE_RGBLCD] = "LCD",
+ [DP_DEVICE_HDMI] = "HDMI",
+ [DP_DEVICE_MIPI] = "MiPi",
+ [DP_DEVICE_LVDS] = "LVDS",
+ [DP_DEVICE_CVBS] = "TVOUT",
+ [DP_DEVICE_DP0] = "DP0",
+ [DP_DEVICE_DP1] = "DP1",
+};
+
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+static void nx_display_parse_dp_sync(const void *blob, int node,
+ struct dp_sync_info *sync)
+{
+ sync->h_active_len = fdtdec_get_int(blob, node, "h_active_len", 0);
+ sync->h_sync_width = fdtdec_get_int(blob, node, "h_sync_width", 0);
+ sync->h_back_porch = fdtdec_get_int(blob, node, "h_back_porch", 0);
+ sync->h_front_porch = fdtdec_get_int(blob, node, "h_front_porch", 0);
+ sync->h_sync_invert = fdtdec_get_int(blob, node, "h_sync_invert", 0);
+ sync->v_active_len = fdtdec_get_int(blob, node, "v_active_len", 0);
+ sync->v_sync_width = fdtdec_get_int(blob, node, "v_sync_width", 0);
+ sync->v_back_porch = fdtdec_get_int(blob, node, "v_back_porch", 0);
+ sync->v_front_porch = fdtdec_get_int(blob, node, "v_front_porch", 0);
+ sync->v_sync_invert = fdtdec_get_int(blob, node, "v_sync_invert", 0);
+ sync->pixel_clock_hz = fdtdec_get_int(blob, node, "pixel_clock_hz", 0);
+
+ debug("DP: sync ->\n");
+ debug("ha:%d, hs:%d, hb:%d, hf:%d, hi:%d\n",
+ sync->h_active_len, sync->h_sync_width,
+ sync->h_back_porch, sync->h_front_porch, sync->h_sync_invert);
+ debug("va:%d, vs:%d, vb:%d, vf:%d, vi:%d\n",
+ sync->v_active_len, sync->v_sync_width,
+ sync->v_back_porch, sync->v_front_porch, sync->v_sync_invert);
+}
+
+static void nx_display_parse_dp_ctrl(const void *blob, int node,
+ struct dp_ctrl_info *ctrl)
+{
+ /* clock gen */
+ ctrl->clk_src_lv0 = fdtdec_get_int(blob, node, "clk_src_lv0", 0);
+ ctrl->clk_div_lv0 = fdtdec_get_int(blob, node, "clk_div_lv0", 0);
+ ctrl->clk_src_lv1 = fdtdec_get_int(blob, node, "clk_src_lv1", 0);
+ ctrl->clk_div_lv1 = fdtdec_get_int(blob, node, "clk_div_lv1", 0);
+
+ /* scan format */
+ ctrl->interlace = fdtdec_get_int(blob, node, "interlace", 0);
+
+ /* syncgen format */
+ ctrl->out_format = fdtdec_get_int(blob, node, "out_format", 0);
+ ctrl->invert_field = fdtdec_get_int(blob, node, "invert_field", 0);
+ ctrl->swap_RB = fdtdec_get_int(blob, node, "swap_RB", 0);
+ ctrl->yc_order = fdtdec_get_int(blob, node, "yc_order", 0);
+
+ /* extern sync delay */
+ ctrl->delay_mask = fdtdec_get_int(blob, node, "delay_mask", 0);
+ ctrl->d_rgb_pvd = fdtdec_get_int(blob, node, "d_rgb_pvd", 0);
+ ctrl->d_hsync_cp1 = fdtdec_get_int(blob, node, "d_hsync_cp1", 0);
+ ctrl->d_vsync_fram = fdtdec_get_int(blob, node, "d_vsync_fram", 0);
+ ctrl->d_de_cp2 = fdtdec_get_int(blob, node, "d_de_cp2", 0);
+
+ /* extern sync delay */
+ ctrl->vs_start_offset =
+ fdtdec_get_int(blob, node, "vs_start_offset", 0);
+ ctrl->vs_end_offset = fdtdec_get_int(blob, node, "vs_end_offset", 0);
+ ctrl->ev_start_offset =
+ fdtdec_get_int(blob, node, "ev_start_offset", 0);
+ ctrl->ev_end_offset = fdtdec_get_int(blob, node, "ev_end_offset", 0);
+
+ /* pad clock seletor */
+ ctrl->vck_select = fdtdec_get_int(blob, node, "vck_select", 0);
+ ctrl->clk_inv_lv0 = fdtdec_get_int(blob, node, "clk_inv_lv0", 0);
+ ctrl->clk_delay_lv0 = fdtdec_get_int(blob, node, "clk_delay_lv0", 0);
+ ctrl->clk_inv_lv1 = fdtdec_get_int(blob, node, "clk_inv_lv1", 0);
+ ctrl->clk_delay_lv1 = fdtdec_get_int(blob, node, "clk_delay_lv1", 0);
+ ctrl->clk_sel_div1 = fdtdec_get_int(blob, node, "clk_sel_div1", 0);
+
+ debug("DP: ctrl [%s] ->\n",
+ ctrl->interlace ? "Interlace" : " Progressive");
+ debug("cs0:%d, cd0:%d, cs1:%d, cd1:%d\n",
+ ctrl->clk_src_lv0, ctrl->clk_div_lv0,
+ ctrl->clk_src_lv1, ctrl->clk_div_lv1);
+ debug("fmt:0x%x, inv:%d, swap:%d, yb:0x%x\n",
+ ctrl->out_format, ctrl->invert_field,
+ ctrl->swap_RB, ctrl->yc_order);
+ debug("dm:0x%x, drp:%d, dhs:%d, dvs:%d, dde:0x%x\n",
+ ctrl->delay_mask, ctrl->d_rgb_pvd,
+ ctrl->d_hsync_cp1, ctrl->d_vsync_fram, ctrl->d_de_cp2);
+ debug("vss:%d, vse:%d, evs:%d, eve:%d\n",
+ ctrl->vs_start_offset, ctrl->vs_end_offset,
+ ctrl->ev_start_offset, ctrl->ev_end_offset);
+ debug("sel:%d, i0:%d, d0:%d, i1:%d, d1:%d, s1:%d\n",
+ ctrl->vck_select, ctrl->clk_inv_lv0, ctrl->clk_delay_lv0,
+ ctrl->clk_inv_lv1, ctrl->clk_delay_lv1, ctrl->clk_sel_div1);
+}
+
+static void nx_display_parse_dp_top_layer(const void *blob, int node,
+ struct dp_plane_top *top)
+{
+ top->screen_width = fdtdec_get_int(blob, node, "screen_width", 0);
+ top->screen_height = fdtdec_get_int(blob, node, "screen_height", 0);
+ top->video_prior = fdtdec_get_int(blob, node, "video_prior", 0);
+ top->interlace = fdtdec_get_int(blob, node, "interlace", 0);
+ top->back_color = fdtdec_get_int(blob, node, "back_color", 0);
+ top->plane_num = DP_PLANS_NUM;
+
+ debug("DP: top [%s] ->\n",
+ top->interlace ? "Interlace" : " Progressive");
+ debug("w:%d, h:%d, prior:%d, bg:0x%x\n",
+ top->screen_width, top->screen_height,
+ top->video_prior, top->back_color);
+}
+
+static void nx_display_parse_dp_layer(const void *blob, int node,
+ struct dp_plane_info *plane)
+{
+ plane->left = fdtdec_get_int(blob, node, "left", 0);
+ plane->width = fdtdec_get_int(blob, node, "width", 0);
+ plane->top = fdtdec_get_int(blob, node, "top", 0);
+ plane->height = fdtdec_get_int(blob, node, "height", 0);
+ plane->pixel_byte = fdtdec_get_int(blob, node, "pixel_byte", 0);
+ plane->format = fdtdec_get_int(blob, node, "format", 0);
+ plane->alpha_on = fdtdec_get_int(blob, node, "alpha_on", 0);
+ plane->alpha_depth = fdtdec_get_int(blob, node, "alpha", 0);
+ plane->tp_on = fdtdec_get_int(blob, node, "tp_on", 0);
+ plane->tp_color = fdtdec_get_int(blob, node, "tp_color", 0);
+
+ /* enable layer */
+ if (plane->fb_base)
+ plane->enable = 1;
+ else
+ plane->enable = 0;
+
+ if (plane->fb_base == 0) {
+ printf("fail : dp plane.%d invalid fb base [0x%x] ->\n",
+ plane->layer, plane->fb_base);
+ return;
+ }
+
+ debug("DP: plane.%d [0x%x] ->\n", plane->layer, plane->fb_base);
+ debug("f:0x%x, l:%d, t:%d, %d * %d, bpp:%d, a:%d(%d), t:%d(0x%x)\n",
+ plane->format, plane->left, plane->top, plane->width,
+ plane->height, plane->pixel_byte, plane->alpha_on,
+ plane->alpha_depth, plane->tp_on, plane->tp_color);
+}
+
+static void nx_display_parse_dp_planes(const void *blob, int node,
+ struct nx_display_dev *dp,
+ struct video_uc_platdata *plat)
+{
+ const char *name;
+
+ for (node = fdt_first_subnode(blob, node);
+ node > 0; node = fdt_next_subnode(blob, node)) {
+ name = fdt_get_name(blob, node, NULL);
+
+ if (strcmp(name, "layer_top") == 0)
+ nx_display_parse_dp_top_layer(blob, node, &dp->top);
+
+ /*
+ * TODO: Is it sure that only one layer is used? Otherwise
+ * fb_base must be different?
+ */
+ if (strcmp(name, "layer_0") == 0) {
+ dp->planes[0].fb_base =
+ (uint)map_sysmem(plat->base, plat->size);
+ debug("%s(): dp->planes[0].fb_base == 0x%x\n", __func__,
+ (uint)dp->planes[0].fb_base);
+ nx_display_parse_dp_layer(blob, node, &dp->planes[0]);
+ }
+
+ if (strcmp(name, "layer_1") == 0) {
+ dp->planes[1].fb_base =
+ (uint)map_sysmem(plat->base, plat->size);
+ debug("%s(): dp->planes[1].fb_base == 0x%x\n", __func__,
+ (uint)dp->planes[1].fb_base);
+ nx_display_parse_dp_layer(blob, node, &dp->planes[1]);
+ }
+
+ if (strcmp(name, "layer_2") == 0) {
+ dp->planes[2].fb_base =
+ (uint)map_sysmem(plat->base, plat->size);
+ debug("%s(): dp->planes[2].fb_base == 0x%x\n", __func__,
+ (uint)dp->planes[2].fb_base);
+ nx_display_parse_dp_layer(blob, node, &dp->planes[2]);
+ }
+ }
+}
+
+static int nx_display_parse_dp_lvds(const void *blob, int node,
+ struct nx_display_dev *dp)
+{
+ struct dp_lvds_dev *dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+
+ if (!dev) {
+ printf("failed to allocate display LVDS object.\n");
+ return -ENOMEM;
+ }
+
+ dp->device = dev;
+
+ dev->lvds_format = fdtdec_get_int(blob, node, "format", 0);
+ dev->pol_inv_hs = fdtdec_get_int(blob, node, "pol_inv_hs", 0);
+ dev->pol_inv_vs = fdtdec_get_int(blob, node, "pol_inv_vs", 0);
+ dev->pol_inv_de = fdtdec_get_int(blob, node, "pol_inv_de", 0);
+ dev->pol_inv_ck = fdtdec_get_int(blob, node, "pol_inv_ck", 0);
+ dev->voltage_level = fdtdec_get_int(blob, node, "voltage_level", 0);
+
+ if (!dev->voltage_level)
+ dev->voltage_level = DEF_VOLTAGE_LEVEL;
+
+ debug("DP: LVDS -> %s, voltage LV:0x%x\n",
+ dev->lvds_format == DP_LVDS_FORMAT_VESA ? "VESA" :
+ dev->lvds_format == DP_LVDS_FORMAT_JEIDA ? "JEIDA" : "LOC",
+ dev->voltage_level);
+ debug("pol inv hs:%d, vs:%d, de:%d, ck:%d\n",
+ dev->pol_inv_hs, dev->pol_inv_vs,
+ dev->pol_inv_de, dev->pol_inv_ck);
+
+ return 0;
+}
+
+static int nx_display_parse_dp_rgb(const void *blob, int node,
+ struct nx_display_dev *dp)
+{
+ struct dp_rgb_dev *dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+
+ if (!dev) {
+ printf("failed to allocate display RGB LCD object.\n");
+ return -ENOMEM;
+ }
+ dp->device = dev;
+
+ dev->lcd_mpu_type = fdtdec_get_int(blob, node, "lcd_mpu_type", 0);
+
+ debug("DP: RGB -> MPU[%s]\n", dev->lcd_mpu_type ? "O" : "X");
+ return 0;
+}
+
+static int nx_display_parse_dp_mipi(const void *blob, int node,
+ struct nx_display_dev *dp)
+{
+ struct dp_mipi_dev *dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+
+ if (!dev) {
+ printf("failed to allocate display MiPi object.\n");
+ return -ENOMEM;
+ }
+ dp->device = dev;
+
+ dev->lp_bitrate = fdtdec_get_int(blob, node, "lp_bitrate", 0);
+ dev->hs_bitrate = fdtdec_get_int(blob, node, "hs_bitrate", 0);
+ dev->lpm_trans = 1;
+ dev->command_mode = 0;
+
+ debug("DP: MIPI ->\n");
+ debug("lp:%dmhz, hs:%dmhz\n", dev->lp_bitrate, dev->hs_bitrate);
+
+ return 0;
+}
+
+static int nx_display_parse_dp_hdmi(const void *blob, int node,
+ struct nx_display_dev *dp)
+{
+ struct dp_hdmi_dev *dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+
+ if (!dev) {
+ printf("failed to allocate display HDMI object.\n");
+ return -ENOMEM;
+ }
+ dp->device = dev;
+
+ dev->preset = fdtdec_get_int(blob, node, "preset", 0);
+
+ debug("DP: HDMI -> %d\n", dev->preset);
+
+ return 0;
+}
+
+static int nx_display_parse_dp_lcds(const void *blob, int node,
+ const char *type, struct nx_display_dev *dp)
+{
+ if (strcmp(type, "lvds") == 0) {
+ dp->dev_type = DP_DEVICE_LVDS;
+ return nx_display_parse_dp_lvds(blob, node, dp);
+ } else if (strcmp(type, "rgb") == 0) {
+ dp->dev_type = DP_DEVICE_RGBLCD;
+ return nx_display_parse_dp_rgb(blob, node, dp);
+ } else if (strcmp(type, "mipi") == 0) {
+ dp->dev_type = DP_DEVICE_MIPI;
+ return nx_display_parse_dp_mipi(blob, node, dp);
+ } else if (strcmp(type, "hdmi") == 0) {
+ dp->dev_type = DP_DEVICE_HDMI;
+ return nx_display_parse_dp_hdmi(blob, node, dp);
+ }
+
+ printf("%s: node %s unknown display type\n", __func__,
+ fdt_get_name(blob, node, NULL));
+ return -EINVAL;
+
+ return 0;
+}
+
+#define DT_SYNC (1 << 0)
+#define DT_CTRL (1 << 1)
+#define DT_PLANES (1 << 2)
+#define DT_DEVICE (1 << 3)
+
+static int nx_display_parse_dt(const void *blob,
+ struct nx_display_dev *dp, int node,
+ struct video_uc_platdata *plat)
+{
+ const char *name, *dtype;
+ int ret = 0;
+ unsigned int dt_status = 0;
+
+ if (!node)
+ return -ENODEV;
+
+ dp->module = fdtdec_get_int(blob, node, "module", -1);
+ if (dp->module == -1)
+ dp->module = fdtdec_get_int(blob, node, "index", 0);
+
+ dtype = fdt_getprop(blob, node, "lcd-type", NULL);
+
+ for (node = fdt_first_subnode(blob, node);
+ node > 0; node = fdt_next_subnode(blob, node)) {
+ name = fdt_get_name(blob, node, NULL);
+
+ if (strcmp("dp-sync", name) == 0) {
+ dt_status |= DT_SYNC;
+ nx_display_parse_dp_sync(blob, node, &dp->sync);
+ }
+
+ if (strcmp("dp-ctrl", name) == 0) {
+ dt_status |= DT_CTRL;
+ nx_display_parse_dp_ctrl(blob, node, &dp->ctrl);
+ }
+
+ if (strcmp("dp-planes", name) == 0) {
+ dt_status |= DT_PLANES;
+ nx_display_parse_dp_planes(blob, node, dp, plat);
+ }
+
+ if (strcmp("dp-device", name) == 0) {
+ dt_status |= DT_DEVICE;
+ ret = nx_display_parse_dp_lcds(blob, node, dtype, dp);
+ }
+ }
+
+ if (dt_status != (DT_SYNC | DT_CTRL | DT_PLANES | DT_DEVICE)) {
+ printf("Not enough DT config for display [0x%x]\n", dt_status);
+ return -ENODEV;
+ }
+
+ return ret;
+}
+#endif
+
+__weak int nx_display_fixup_dp(struct nx_display_dev *dp)
+{
+ return 0;
+}
+
+static struct nx_display_dev *nx_display_setup(void)
+{
+ struct nx_display_dev *dp;
+ int i, ret;
+ int node = 0;
+ struct video_uc_platdata *plat = NULL;
+
+ struct udevice *dev;
+
+ /* call driver probe */
+ debug("DT: uclass device call...\n");
+
+ ret = uclass_get_device(UCLASS_VIDEO, 0, &dev);
+ if (ret) {
+ debug("%s(): uclass_get_device(UCLASS_VIDEO, 0, &dev) != 0 --> return NULL\n", __func__);
+ return NULL;
+ }
+ plat = dev_get_uclass_platdata(dev);
+ if (!dev) {
+ debug("%s(): dev_get_uclass_platdata(dev) == NULL --> return NULL\n", __func__);
+ return NULL;
+ }
+ dp = dev_get_priv(dev);
+ if (!dp) {
+ debug("%s(): dev_get_priv(dev) == NULL --> return NULL\n", __func__);
+ return NULL;
+ }
+ node = dev->node.of_offset;
+
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+ ret = nx_display_parse_dt(gd->fdt_blob, dp, node, plat);
+ if (ret)
+ goto err_setup;
+#endif
+
+ nx_display_fixup_dp(dp);
+
+ for (i = 0; dp->top.plane_num > i; i++) {
+ dp->planes[i].layer = i;
+ if (dp->planes[i].enable && !dp->fb_plane) {
+ dp->fb_plane = &dp->planes[i];
+ dp->fb_addr = dp->fb_plane->fb_base;
+ dp->depth = dp->fb_plane->pixel_byte;
+ }
+ }
+
+ switch (dp->dev_type) {
+#ifdef CONFIG_VIDEO_NX_RGB
+ case DP_DEVICE_RGBLCD:
+ nx_rgb_display(dp->module,
+ &dp->sync, &dp->ctrl, &dp->top,
+ dp->planes, (struct dp_rgb_dev *)dp->device);
+ break;
+#endif
+#ifdef CONFIG_VIDEO_NX_LVDS
+ case DP_DEVICE_LVDS:
+ nx_lvds_display(dp->module,
+ &dp->sync, &dp->ctrl, &dp->top,
+ dp->planes, (struct dp_lvds_dev *)dp->device);
+ break;
+#endif
+#ifdef CONFIG_VIDEO_NX_MIPI
+ case DP_DEVICE_MIPI:
+ nx_mipi_display(dp->module,
+ &dp->sync, &dp->ctrl, &dp->top,
+ dp->planes, (struct dp_mipi_dev *)dp->device);
+ break;
+#endif
+#ifdef CONFIG_VIDEO_NX_HDMI
+ case DP_DEVICE_HDMI:
+ nx_hdmi_display(dp->module,
+ &dp->sync, &dp->ctrl, &dp->top,
+ dp->planes, (struct dp_hdmi_dev *)dp->device);
+ break;
+#endif
+ default:
+ printf("fail : not support lcd type %d !!!\n", dp->dev_type);
+ goto err_setup;
+ };
+
+ printf("LCD: [%s] dp.%d.%d %dx%d %dbpp FB:0x%08x\n",
+ dp_dev_str[dp->dev_type], dp->module, dp->fb_plane->layer,
+ dp->fb_plane->width, dp->fb_plane->height, dp->depth * 8,
+ dp->fb_addr);
+
+ return dp;
+
+err_setup:
+ kfree(dp);
+
+ return NULL;
+}
+
+#if defined CONFIG_LCD
+
+/* default lcd */
+struct vidinfo panel_info = {
+ .vl_col = 320, .vl_row = 240, .vl_bpix = 32,
+};
+
+void lcd_ctrl_init(void *lcdbase)
+{
+ vidinfo_t *pi = &panel_info;
+ struct nx_display_dev *dp;
+ int bpix;
+
+ dp = nx_display_setup();
+ if (!dp)
+ return NULL;
+
+ switch (dp->depth) {
+ case 2:
+ bpix = LCD_COLOR16;
+ break;
+ case 3:
+ case 4:
+ bpix = LCD_COLOR32;
+ break;
+ default:
+ printf("fail : not support LCD bit per pixel %d\n",
+ dp->depth * 8);
+ return NULL;
+ }
+
+ dp->panel_info = pi;
+
+ /* set resolution with config */
+ pi->vl_bpix = bpix;
+ pi->vl_col = dp->fb_plane->width;
+ pi->vl_row = dp->fb_plane->height;
+ pi->priv = dp;
+ gd->fb_base = dp->fb_addr;
+}
+
+void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue)
+{
+}
+
+__weak void lcd_enable(void)
+{
+}
+#endif
+
+static int nx_display_dev_probe_uclass(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 nx_display_platdata *plat = dev_get_platdata(dev);
+ static GraphicDevice *graphic_device;
+ char addr[64];
+
+ debug("%s()\n", __func__);
+
+ if (!dev)
+ return -EINVAL;
+
+ if (!uc_plat) {
+ debug("%s(): video_uc_platdata *plat == NULL --> return -EINVAL\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!uc_priv) {
+ debug("%s(): video_priv *uc_priv == NULL --> return -EINVAL\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!plat) {
+ debug("%s(): nx_display_platdata *plat == NULL --> return -EINVAL\n", __func__);
+ return -EINVAL;
+ }
+
+ struct nx_display_dev *dp;
+ unsigned int pp_index = 0;
+
+ dp = nx_display_setup();
+ if (!dp) {
+ debug("%s(): nx_display_setup() == 0 --> return -EINVAL\n", __func__);
+ return -EINVAL;
+ }
+
+ switch (dp->depth) {
+ case 2:
+ pp_index = GDF_16BIT_565RGB;
+ uc_priv->bpix = VIDEO_BPP16;
+ break;
+ case 3:
+ /* There is no VIDEO_BPP24 because these values are of
+ * type video_log2_bpp
+ */
+ case 4:
+ pp_index = GDF_32BIT_X888RGB;
+ uc_priv->bpix = VIDEO_BPP32;
+ break;
+ default:
+ printf("fail : not support LCD bit per pixel %d\n",
+ dp->depth * 8);
+ return -EINVAL;
+ }
+
+ uc_priv->xsize = dp->fb_plane->width;
+ uc_priv->ysize = dp->fb_plane->height;
+ uc_priv->rot = 0;
+
+ graphic_device = &dp->graphic_device;
+ graphic_device->frameAdrs = dp->fb_addr;
+ graphic_device->gdfIndex = pp_index;
+ graphic_device->gdfBytesPP = dp->depth;
+ graphic_device->winSizeX = dp->fb_plane->width;
+ graphic_device->winSizeY = dp->fb_plane->height;
+ graphic_device->plnSizeX =
+ graphic_device->winSizeX * graphic_device->gdfBytesPP;
+
+ /*
+ * set environment variable "fb_addr" (frame buffer address), required
+ * for splash image. Because drv_video_init() in common/stdio.c is only
+ * called when CONFIG_VIDEO is set (and not when CONFIG_DM_VIDEO is set).
+ */
+ sprintf(addr, "0x%x", dp->fb_addr);
+ debug("%s(): env_set(\"fb_addr\", %s) ...\n", __func__, addr);
+ env_set("fb_addr", addr);
+
+ return 0;
+}
+
+static int nx_display_bind(struct udevice *dev)
+{
+ struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
+
+ debug("%s()\n", __func__);
+
+ /* Datasheet S5p4418:
+ * Resolution up to 2048 x 1280, up to 12 Bit per color (HDMI)
+ * Actual (max.) size is 0x1000000 because in U-Boot nanopi2-2016.01
+ * "#define CONFIG_FB_ADDR 0x77000000" and next address is
+ * "#define BMP_LOAD_ADDR 0x78000000"
+ */
+ plat->size = 0x1000000;
+
+ return 0;
+}
+
+static int nx_display_probe(struct udevice *dev)
+{
+ return nx_display_dev_probe_uclass(dev);
+}
+
+static const struct udevice_id nx_display_ids[] = {
+ {.compatible = "nexell,nexell-display", },
+ {}
+};
+
+U_BOOT_DRIVER(nexell_display) = {
+ .name = "nexell-display",
+ .id = UCLASS_VIDEO,
+ .of_match = nx_display_ids,
+ .platdata_auto_alloc_size =
+ sizeof(struct nx_display_platdata),
+ .bind = nx_display_bind,
+ .probe = nx_display_probe,
+ .priv_auto_alloc_size = sizeof(struct nx_display_dev),
+};
--
1.9.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH 09/10] arm: add support for SoC s5p4418 (cpu) / nanopi2 board
2020-02-03 19:39 [RFC PATCH 00/10] arm: add support for SoC S5P4418 Stefan Bosch
` (7 preceding siblings ...)
2020-02-03 20:45 ` [RFC PATCH 08/10] video: add nexell video driver (display/video driver) Stefan Bosch
@ 2020-02-03 20:46 ` Stefan Bosch
2020-02-07 16:10 ` Tom Rini
2020-02-03 20:47 ` [RFC PATCH 10/10] arm: add (default) config for " Stefan Bosch
` (2 subsequent siblings)
11 siblings, 1 reply; 19+ messages in thread
From: Stefan Bosch @ 2020-02-03 20:46 UTC (permalink / raw)
To: u-boot
Changes in relation to FriendlyARM's U-Boot nanopi2-v2016.01:
- SPL not supported yet --> no spl-dir in arch/arm/cpu/armv7/s5p4418/.
Appropriate line in Makefile removed.
- cpu.c: '#include <cpu_func.h>' added.
- arch/arm/cpu/armv7/s5p4418/u-boot.lds removed, is not required
anylonger.
- s5p4418.dtsi: '#include "../../../include/generated/autoconf.h"'
removed, is not necessary, error at out-of-tree building.
'#ifdef CONFIG_CPU_NXP4330'-blocks (2x) removed. Some minor changes
regarding mmc. 'u-boot,dm-pre-reloc' added to dp0 because of added
DM_VIDEO support.
- board/s5p4418/ renamed to board/friendlyarm/
- All s5p4418-boards except nanopi2 removed because there is no
possibility to test the other boards.
- Kconfig: Changes to have a structure like mach-bcm283x (RaspberryPi),
e.g. "config ..." entries moved from/to other Kconfig.
- "CONFIG_" removed from several s5p4418/nanopi2 specific defines
because the appropriate values do not need to be configurable.
- nanopi2/board.c: All getenv(), getenv_ulong(), setenv() and saveenv()
renamed to env_get(), env_get_ulong(), env_set() and env_save(),
respectively. MACH_TYPE_S5P4418 is not defined anymore, therefore
appropriate code removed (not necessary for DT-kernels).
- nanopi2/onewire.c: All crc8() renamed to crc8_ow() because crc8() is
already defined in lib/crc8.c (with different parameters).
Signed-off-by: Stefan Bosch <stefan_b@posteo.net>
---
arch/arm/cpu/armv7/Makefile | 1 +
arch/arm/cpu/armv7/s5p4418/Makefile | 6 +
arch/arm/cpu/armv7/s5p4418/cpu.c | 120 ++++++
arch/arm/dts/Makefile | 3 +
arch/arm/dts/s5p4418-nanopi2.dts | 109 ++++++
arch/arm/dts/s5p4418-pinctrl.dtsi | 66 ++++
arch/arm/dts/s5p4418.dtsi | 157 ++++++++
board/friendlyarm/Kconfig | 39 ++
board/friendlyarm/nanopi2/Kconfig | 12 +
board/friendlyarm/nanopi2/MAINTAINERS | 7 +
board/friendlyarm/nanopi2/Makefile | 6 +
board/friendlyarm/nanopi2/board.c | 581 ++++++++++++++++++++++++++++
board/friendlyarm/nanopi2/hwrev.c | 122 ++++++
board/friendlyarm/nanopi2/hwrev.h | 29 ++
board/friendlyarm/nanopi2/lcds.c | 703 ++++++++++++++++++++++++++++++++++
board/friendlyarm/nanopi2/nxp-fb.h | 99 +++++
board/friendlyarm/nanopi2/onewire.c | 323 ++++++++++++++++
board/friendlyarm/nanopi2/onewire.h | 29 ++
18 files changed, 2412 insertions(+)
create mode 100644 arch/arm/cpu/armv7/s5p4418/Makefile
create mode 100644 arch/arm/cpu/armv7/s5p4418/cpu.c
create mode 100644 arch/arm/dts/s5p4418-nanopi2.dts
create mode 100644 arch/arm/dts/s5p4418-pinctrl.dtsi
create mode 100644 arch/arm/dts/s5p4418.dtsi
create mode 100644 board/friendlyarm/Kconfig
create mode 100644 board/friendlyarm/nanopi2/Kconfig
create mode 100644 board/friendlyarm/nanopi2/MAINTAINERS
create mode 100644 board/friendlyarm/nanopi2/Makefile
create mode 100644 board/friendlyarm/nanopi2/board.c
create mode 100644 board/friendlyarm/nanopi2/hwrev.c
create mode 100644 board/friendlyarm/nanopi2/hwrev.h
create mode 100644 board/friendlyarm/nanopi2/lcds.c
create mode 100644 board/friendlyarm/nanopi2/nxp-fb.h
create mode 100644 board/friendlyarm/nanopi2/onewire.c
create mode 100644 board/friendlyarm/nanopi2/onewire.h
diff --git a/arch/arm/cpu/armv7/Makefile b/arch/arm/cpu/armv7/Makefile
index 8c955d0..ee87417 100644
--- a/arch/arm/cpu/armv7/Makefile
+++ b/arch/arm/cpu/armv7/Makefile
@@ -42,3 +42,4 @@ obj-$(CONFIG_RMOBILE) += rmobile/
obj-$(if $(filter stv0991,$(SOC)),y) += stv0991/
obj-$(CONFIG_ARCH_SUNXI) += sunxi/
obj-$(CONFIG_VF610) += vf610/
+obj-$(CONFIG_ARCH_S5P4418) += s5p4418/
diff --git a/arch/arm/cpu/armv7/s5p4418/Makefile b/arch/arm/cpu/armv7/s5p4418/Makefile
new file mode 100644
index 0000000..321b257
--- /dev/null
+++ b/arch/arm/cpu/armv7/s5p4418/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2016 Nexell
+# Hyunseok, Jung <hsjung@nexell.co.kr>
+
+obj-y += cpu.o
diff --git a/arch/arm/cpu/armv7/s5p4418/cpu.c b/arch/arm/cpu/armv7/s5p4418/cpu.c
new file mode 100644
index 0000000..79c284f
--- /dev/null
+++ b/arch/arm/cpu/armv7/s5p4418/cpu.c
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2016 Nexell
+ * Hyunseok, Jung <hsjung@nexell.co.kr>
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/system.h>
+#include <asm/cache.h>
+#include <asm/sections.h>
+#include <asm/io.h>
+#include <asm/arch/nexell.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/reset.h>
+#include <asm/arch/tieoff.h>
+#include <cpu_func.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifndef CONFIG_ARCH_CPU_INIT
+#error must be define the macro "CONFIG_ARCH_CPU_INIT"
+#endif
+
+void s_init(void)
+{
+}
+
+static void cpu_soc_init(void)
+{
+ /*
+ * NOTE> ALIVE Power Gate must enable for Alive register access.
+ * must be clear wfi jump address
+ */
+ writel(1, ALIVEPWRGATEREG);
+ writel(0xFFFFFFFF, SCR_ARM_SECOND_BOOT);
+
+ /* write 0xf0 on alive scratchpad reg for boot success check */
+ writel(readl(SCR_SIGNAGURE_READ) | 0xF0, (SCR_SIGNAGURE_SET));
+
+ /* set l2 cache tieoff */
+ nx_tieoff_set(NX_TIEOFF_CORTEXA9MP_TOP_QUADL2C_L2RET1N_0, 1);
+ nx_tieoff_set(NX_TIEOFF_CORTEXA9MP_TOP_QUADL2C_L2RET1N_1, 1);
+}
+
+#ifdef CONFIG_PL011_SERIAL
+static void serial_device_init(void)
+{
+ char dev[10];
+ int id;
+
+ sprintf(dev, "nx-uart.%d", CONFIG_CONS_INDEX);
+ id = RESET_ID_UART0 + CONFIG_CONS_INDEX;
+
+ struct clk *clk = clk_get((const char *)dev);
+
+ /* reset control: Low active ___|--- */
+ nx_rstcon_setrst(id, RSTCON_ASSERT);
+ udelay(10);
+ nx_rstcon_setrst(id, RSTCON_NEGATE);
+ udelay(10);
+
+ /* set clock */
+ clk_disable(clk);
+ clk_set_rate(clk, CONFIG_PL011_CLOCK);
+ clk_enable(clk);
+}
+#endif
+
+int arch_cpu_init(void)
+{
+ flush_dcache_all();
+ cpu_soc_init();
+ clk_init();
+
+#ifdef CONFIG_PL011_SERIAL
+ serial_device_init();
+#endif
+ return 0;
+}
+
+#if defined(CONFIG_DISPLAY_CPUINFO)
+int print_cpuinfo(void)
+{
+ return 0;
+}
+#endif
+
+void reset_cpu(ulong ignored)
+{
+ void *clkpwr_reg = (void *)PHY_BASEADDR_CLKPWR;
+ const u32 sw_rst_enb_bitpos = 3;
+ const u32 sw_rst_enb_mask = 1 << sw_rst_enb_bitpos;
+ const u32 sw_rst_bitpos = 12;
+ const u32 sw_rst_mask = 1 << sw_rst_bitpos;
+ int pwrcont = 0x224;
+ int pwrmode = 0x228;
+ u32 read_value;
+
+ read_value = readl((void *)(clkpwr_reg + pwrcont));
+
+ read_value &= ~sw_rst_enb_mask;
+ read_value |= 1 << sw_rst_enb_bitpos;
+
+ writel(read_value, (void *)(clkpwr_reg + pwrcont));
+ writel(sw_rst_mask, (void *)(clkpwr_reg + pwrmode));
+}
+
+void enable_caches(void)
+{
+ /* Enable D-cache. I-cache is already enabled in start.S */
+ dcache_enable();
+}
+
+#if defined(CONFIG_ARCH_MISC_INIT)
+int arch_misc_init(void)
+{
+ return 0;
+}
+#endif /* CONFIG_ARCH_MISC_INIT */
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index 04a8ccc..065b2d2 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -137,6 +137,9 @@ dtb-$(CONFIG_ROCKCHIP_RV1108) += \
rv1108-elgin-r1.dtb \
rv1108-evb.dtb
+dtb-$(CONFIG_ARCH_S5P4418) += \
+ s5p4418-nanopi2.dtb
+
dtb-$(CONFIG_ARCH_MESON) += \
meson-gxbb-nanopi-k2.dtb \
meson-gxbb-odroidc2.dtb \
diff --git a/arch/arm/dts/s5p4418-nanopi2.dts b/arch/arm/dts/s5p4418-nanopi2.dts
new file mode 100644
index 0000000..4fb3097
--- /dev/null
+++ b/arch/arm/dts/s5p4418-nanopi2.dts
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2017 FriendlyElec Computer Tech. Co., Ltd.
+ * (http://www.friendlyarm.com)
+ *
+ * (C) Copyright 2016 Nexell
+ * Youngbok, Park <park@nexell.co.kr>
+ */
+
+/dts-v1/;
+#include "s5p4418.dtsi"
+
+/ {
+ model = "FriendlyElec boards based on Nexell s5p4418";
+ cpu-model = "S5p4418";
+
+ compatible = "friendlyelec,nanopi2",
+ "nexell,s5p4418";
+
+ aliases {
+ mmc0 = "/mmc at c0069000";
+ mmc1 = "/mmc at c0062000";
+ i2c2 = "/i2c at 2";
+ };
+
+ mmc0:mmc at c0062000 {
+ frequency = <50000000>;
+ nexell,drive_dly = <0x0>;
+ nexell,drive_shift = <0x03>;
+ nexell,sample_dly = <0x00>;
+ nexell,sample_shift = <0x02>;
+ status = "okay";
+ };
+
+ mmc2:mmc at c0069000 {
+ frequency = <50000000>;
+ nexell,drive_dly = <0x0>;
+ nexell,drive_shift = <0x03>;
+ nexell,sample_dly = <0x00>;
+ nexell,sample_shift = <0x02>;
+ nexell,bus-width = <4>;
+ index = <2>;
+ status = "okay";
+ };
+
+ ehci:usbhost at c0030000 {
+ status = "okay";
+ };
+
+ dwc2otg at c0040000 {
+ status = "okay";
+ };
+
+ i2c2:i2c at 2 {
+ compatible = "i2c-gpio";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ gpios = <&gpio_d 7 0>, /* SDA */
+ <&gpio_d 6 0>; /* SCL */
+ i2c-gpio,delay-us = <3>;
+ status ="okay";
+ };
+
+ dp0:dp at c0102800 {
+ status = "okay";
+ module = <0>;
+ lcd-type = "lvds";
+
+ dp-device {
+ format = <0>; /* 0:VESA, 1:JEIDA */
+ };
+
+ dp-sync {
+ h_active_len = <1024>;
+ h_front_porch = <84>;
+ h_back_porch = <84>;
+ h_sync_width = <88>;
+ h_sync_invert = <0>;
+ v_active_len = <600>;
+ v_front_porch = <10>;
+ v_back_porch = <10>;
+ v_sync_width = <20>;
+ v_sync_invert = <0>;
+ };
+
+ dp-ctrl {
+ clk_src_lv0 = <3>;
+ clk_div_lv0 = <16>;
+ clk_src_lv1 = <7>;
+ clk_div_lv1 = <1>;
+ out_format = <2>;
+ };
+
+ dp-planes {
+ layer_top {
+ screen_width = <1024>;
+ screen_height = <600>;
+ back_color = <0x0>;
+ };
+
+ layer_1 { /* RGB 1 */
+ width = <1024>;
+ height = <600>;
+ format = <0x06530000>;
+ pixel_byte = <4>;
+ };
+ };
+ };
+};
diff --git a/arch/arm/dts/s5p4418-pinctrl.dtsi b/arch/arm/dts/s5p4418-pinctrl.dtsi
new file mode 100644
index 0000000..dcf745a
--- /dev/null
+++ b/arch/arm/dts/s5p4418-pinctrl.dtsi
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Nexell's s5p6818 SoC pin-mux and pin-config device tree source
+ *
+ * Copyright (C) 2016 Nexell Co., Ltd.
+ * http://www.nexell.co.kr
+ *
+ * Nexell's s5p6818 SoC pin-mux and pin-config options are listed as
+ * device tree nodes in this file.
+ *
+ * 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.
+ */
+
+pinctrl at C0010000 {
+ /* GMAC */
+ gmac_txd: gmac-txd {
+ nexell,pins = "gpioe-7", "gpioe-8", "gpioe-9", "gpioe-10";
+ nexell,pin-function = <1>;
+ nexell,pin-pull = <2>;
+ nexell,pin-strength = <3>;
+ };
+
+ gmac_rxd: gmac-rxd {
+ nexell,pins = "gpioe-14", "gpioe-15", "gpioe-16", "gpioe-17";
+ nexell,pin-function = <1>;
+ nexell,pin-pull = <2>;
+ nexell,pin-strength = <3>;
+ };
+
+ gmac_txen: gmac-txen {
+ nexell,pins = "gpioe-11";
+ nexell,pin-function = <1>;
+ nexell,pin-pull = <2>;
+ nexell,pin-strength = <3>;
+ };
+
+ gmac_mdc: gmac-mdc {
+ nexell,pins = "gpioe-20";
+ nexell,pin-function = <1>;
+ nexell,pin-pull = <2>;
+ nexell,pin-strength = <3>;
+ };
+
+ gmac_mdio: gmac-mdio {
+ nexell,pins = "gpioe-21";
+ nexell,pin-function = <1>;
+ nexell,pin-pull = <2>;
+ nexell,pin-strength = <3>;
+ };
+
+ gmac_rxclk: gmac-rxclk {
+ nexell,pins = "gpioe-18";
+ nexell,pin-function = <1>;
+ nexell,pin-pull = <2>;
+ nexell,pin-strength = <3>;
+ };
+
+ gmac_txclk: gmac-txclk {
+ nexell,pins = "gpioe-24";
+ nexell,pin-function = <1>;
+ nexell,pin-pull = <2>;
+ nexell,pin-strength = <2>;
+ };
+};
diff --git a/arch/arm/dts/s5p4418.dtsi b/arch/arm/dts/s5p4418.dtsi
new file mode 100644
index 0000000..d090d9b
--- /dev/null
+++ b/arch/arm/dts/s5p4418.dtsi
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2016 Nexell
+ * Youngbok, Park <park@nexell.co.kr>
+ */
+
+#include "skeleton.dtsi"
+
+/ {
+ #include "s5p4418-pinctrl.dtsi"
+ aliases {
+ mmc0 = &mmc0;
+ mmc1 = &mmc1;
+ mmc2 = &mmc2;
+ gmac = "/ethernet at c0060000";
+ };
+
+ mmc2:mmc at c0069000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "nexell,nexell-dwmmc";
+ reg = <0xc0069000 0x1000>;
+ nexell,bus-width = <4>;
+ index = <2>;
+ max-frequency = <50000000>;
+ status = "disabled";
+ };
+
+ mmc1:mmc at c0068000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "nexell,nexell-dwmmc";
+ reg = <0xc0068000 0x1000>;
+ nexell,bus-width = <4>;
+ index = <1>;
+ max-frequency = <50000000>;
+ status = "disabled";
+ };
+
+ mmc0:mmc at c0062000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "nexell,nexell-dwmmc";
+ reg = <0xc0062000 0x1000>;
+ nexell,bus-width = <4>;
+ index = <0>;
+ max-frequency = <50000000>;
+ status = "disabled";
+ };
+
+ gmac:ethernet at c0060000 {
+ compatible = "nexell,nexell-gmac";
+ reg = <0xc0060000 0x8000>;
+ phy-mode = "rgmii";
+ pinctrl-names = "default";
+ pinctrl-0 = <&gmac_txd>, <&gmac_rxd>, <&gmac_txen>,
+ <&gmac_mdc>, <&gmac_mdio>, <&gmac_rxclk>, <&gmac_txclk>;
+ status = "disabled";
+ };
+
+ ehci:usbhost at c0030000 {
+ compatible = "nexell,nexell-ehci";
+ reg = <0xC0030000 0x10000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ status = "disabled";
+ phy {
+ compatible = "samsung,exynos-usb-phy";
+ reg = <0xC0011000 0x100>;
+ };
+ };
+
+ dwc2otg at c0040000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "nexell,dwc2";
+ reg = <0xC0011000 0x100>, <0xC0040000 0x11000>;
+ status = "disabled";
+ };
+
+ dp0:dp at c0102800 {
+ compatible = "nexell,nexell-display";
+ reg = <0xc0102800 0x100>;
+ index = <0>;
+ u-boot,dm-pre-reloc;
+ status = "disabled";
+ };
+
+ dp1:dp at c0102c00 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "nexell,nexell-display";
+ reg = <0xc0102c00 0x100>;
+ index = <1>;
+ status = "disabled";
+ };
+
+ gpio_a:gpio at c001a000 {
+ compatible = "nexell,nexell-gpio";
+ reg = <0xc001a000 0x00000010>;
+ altr,gpio-bank-width = <32>;
+ gpio-bank-name = "gpio_a";
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ gpio_b:gpio at c001b000 {
+ compatible = "nexell,nexell-gpio";
+ reg = <0xc001b000 0x00000010>;
+ altr,gpio-bank-width = <32>;
+ gpio-bank-name = "gpio_b";
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ gpio_c:gpio at c001c000 {
+ compatible = "nexell,nexell-gpio";
+ reg = <0xc001c000 0x00000010>;
+ nexell,gpio-bank-width = <32>;
+ gpio-bank-name = "gpio_c";
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ gpio_d:gpio at c001d000 {
+ compatible = "nexell,nexell-gpio";
+ reg = <0xc001d000 0x00000010>;
+ nexell,gpio-bank-width = <32>;
+ gpio-bank-name = "gpio_d";
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ gpio_e:gpio at c001e000 {
+ compatible = "nexell,nexell-gpio";
+ reg = <0xc001e000 0x00000010>;
+ nexell,gpio-bank-width = <32>;
+ gpio-bank-name = "gpio_e";
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ gpio_alv:gpio at c0010800 {
+ compatible = "nexell,nexell-gpio";
+ reg = <0xc0010800 0x00000010>;
+ nexell,gpio-bank-width = <32>;
+ gpio-bank-name = "gpio_alv";
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ pinctrl at C0010000 {
+ compatible = "nexell,s5pxx18-pinctrl";
+ reg = <0xc0010000 0xf000>;
+ u-boot,dm-pre-reloc;
+ };
+};
diff --git a/board/friendlyarm/Kconfig b/board/friendlyarm/Kconfig
new file mode 100644
index 0000000..8f79640
--- /dev/null
+++ b/board/friendlyarm/Kconfig
@@ -0,0 +1,39 @@
+
+#config SYS_CONFIG_NAME
+# string "Board header file"
+# help
+# This option should contain the base name of board header file.
+# The header file include/configs/<CONFIG_SYS_CONFIG_NAME>.h
+# should be included from include/config.h.
+
+config S5P4418_ONEWIRE
+ bool "S5P4418_ONEWIRE"
+ #default y
+
+config PWM_NX
+ bool "PWM_NX"
+ #default y
+
+config SYS_RESERVE_MEM_SIZE
+ hex "SYS_RESERVE_MEM_SIZE"
+
+config ROOT_DEV
+ int "ROOT_DEV"
+ help
+ Environment variable rootdev is set to this value if env. var. firstboot
+ does not exist. Otherwise rootdev is set to the MMC boot device. rootdev
+ determines (together with env. var. bootpart) where the OS (linux) is
+ booted from.
+
+config BOOT_PART
+ int "BOOT_PART"
+ help
+ Environment variable bootpart is set to this value. bootpart determines
+ (together with env. var. rootdev) where the OS (linux) is booted from.
+
+config ROOT_PART
+ int "ROOT_PART"
+ help
+ Environment variable rootpart is set to this value.
+
+source "board/friendlyarm/nanopi2/Kconfig"
diff --git a/board/friendlyarm/nanopi2/Kconfig b/board/friendlyarm/nanopi2/Kconfig
new file mode 100644
index 0000000..0f68422
--- /dev/null
+++ b/board/friendlyarm/nanopi2/Kconfig
@@ -0,0 +1,12 @@
+if TARGET_NANOPI2
+
+config SYS_BOARD
+ default "nanopi2"
+
+config SYS_VENDOR
+ default "friendlyarm"
+
+config SYS_CONFIG_NAME
+ default "s5p4418_nanopi2"
+
+endif
diff --git a/board/friendlyarm/nanopi2/MAINTAINERS b/board/friendlyarm/nanopi2/MAINTAINERS
new file mode 100644
index 0000000..c8e2ce7
--- /dev/null
+++ b/board/friendlyarm/nanopi2/MAINTAINERS
@@ -0,0 +1,7 @@
+NANOPI2 BOARD
+NANOPC-T2 BOARD
+M: Stefan Bosch <stefan_b@posteo.net>
+S: Maintained
+F: board/s5p4418/nanopi2/
+F: include/configs/s5p4418_nanopi2.h
+F: configs/s5p4418_nanopi2_defconfig
diff --git a/board/friendlyarm/nanopi2/Makefile b/board/friendlyarm/nanopi2/Makefile
new file mode 100644
index 0000000..cd459f2
--- /dev/null
+++ b/board/friendlyarm/nanopi2/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2016 Nexell
+# Hyunseok, Jung <hsjung@nexell.co.kr>
+
+obj-y := board.o hwrev.o onewire.o lcds.o
diff --git a/board/friendlyarm/nanopi2/board.c b/board/friendlyarm/nanopi2/board.c
new file mode 100644
index 0000000..91fd206
--- /dev/null
+++ b/board/friendlyarm/nanopi2/board.c
@@ -0,0 +1,581 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) Guangzhou FriendlyARM Computer Tech. Co., Ltd.
+ * (http://www.friendlyarm.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
+ */
+
+#include <config.h>
+#include <common.h>
+#ifdef CONFIG_PWM_NX
+#include <pwm.h>
+#endif
+#include <asm/io.h>
+
+#include <asm/arch/nexell.h>
+#include <asm/arch/nx_gpio.h>
+#include <asm/arch/display.h>
+#include <asm/arch/display_dev.h>
+
+#include <u-boot/md5.h>
+
+#include "hwrev.h"
+#include "onewire.h"
+#include "nxp-fb.h"
+
+#include <env_internal.h> /* for env_save() */
+#include <asm/mach-types.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+enum gpio_group {
+ gpio_a, gpio_b, gpio_c, gpio_d, gpio_e,
+};
+
+#ifdef CONFIG_PWM_NX
+struct pwm_device {
+ int grp;
+ int bit;
+ int io_fn;
+};
+
+static inline void bd_pwm_config_gpio(int ch)
+{
+ struct pwm_device pwm_dev[] = {
+ [0] = { .grp = gpio_d, .bit = 1, .io_fn = 0 },
+ [1] = { .grp = gpio_c, .bit = 13, .io_fn = 1 },
+ [2] = { .grp = gpio_c, .bit = 14, .io_fn = 1 },
+ [3] = { .grp = gpio_d, .bit = 0, .io_fn = 0 },
+ };
+
+ int gp = pwm_dev[ch].grp;
+ int io = pwm_dev[ch].bit;
+
+ /* pwm backlight OFF: HIGH, ON: LOW */
+ nx_gpio_set_pad_function(gp, io, pwm_dev[ch].io_fn);
+ nx_gpio_set_output_value(gp, io, 1);
+ nx_gpio_set_output_enable(gp, io, 1);
+}
+#endif
+
+static void bd_backlight_off(void)
+{
+#ifdef CONFIG_S5P4418_ONEWIRE
+ onewire_set_backlight(0);
+
+#elif defined(BACKLIGHT_CH)
+ bd_pwm_config_gpio(BACKLIGHT_CH);
+#endif
+}
+
+static void bd_backlight_on(void)
+{
+#ifdef CONFIG_S5P4418_ONEWIRE
+ onewire_set_backlight(127);
+
+#elif defined(BACKLIGHT_CH)
+ /* pwm backlight ON: HIGH, ON: LOW */
+ pwm_init(BACKLIGHT_CH,
+ BACKLIGHT_DIV, BACKLIGHT_INV);
+ pwm_config(BACKLIGHT_CH,
+ TO_DUTY_NS(BACKLIGHT_DUTY, BACKLIGHT_HZ),
+ TO_PERIOD_NS(BACKLIGHT_HZ));
+#endif
+}
+
+static void bd_lcd_config_gpio(void)
+{
+ int i;
+
+ for (i = 0; i < 28; i++) {
+ nx_gpio_set_pad_function(gpio_a, i, 1);
+ nx_gpio_set_drive_strength(gpio_a, i, 0);
+ nx_gpio_set_pull_mode(gpio_a, i, 2);
+ }
+
+ nx_gpio_set_drive_strength(gpio_a, 0, 1);
+}
+
+/* DEFAULT mmc dev for eMMC boot (dwmmc.2) */
+static int mmc_boot_dev = 0;
+
+int board_mmc_bootdev(void)
+{
+ return mmc_boot_dev;
+}
+
+/* call from common/env_mmc.c */
+int mmc_get_env_dev(void)
+{
+ return mmc_boot_dev;
+}
+
+#ifdef CONFIG_DISPLAY_BOARDINFO
+int checkboard(void)
+{
+ printf("Board: %s\n", get_board_name());
+
+ return 0;
+}
+#endif
+
+int nx_display_fixup_dp(struct nx_display_dev *dp)
+{
+ struct nxp_lcd *lcd = bd_get_lcd();
+ enum lcd_format fmt = bd_get_lcd_format();
+ struct nxp_lcd_timing *timing = &lcd->timing;
+ struct dp_sync_info *sync = &dp->sync;
+ struct dp_plane_info *plane = &dp->planes[0];
+ int i;
+ u32 clk = 800000000;
+ u32 div;
+
+ sync->h_active_len = lcd->width;
+ sync->h_sync_width = timing->h_sw;
+ sync->h_back_porch = timing->h_bp;
+ sync->h_front_porch = timing->h_fp;
+ sync->h_sync_invert = !lcd->polarity.inv_hsync;
+
+ sync->v_active_len = lcd->height;
+ sync->v_sync_width = timing->v_sw;
+ sync->v_back_porch = timing->v_bp;
+ sync->v_front_porch = timing->v_fp;
+ sync->v_sync_invert = !lcd->polarity.inv_vsync;
+
+ /* calculates pixel clock */
+ div = timing->h_sw + timing->h_bp + timing->h_fp + lcd->width;
+ div *= timing->v_sw + timing->v_bp + timing->v_fp + lcd->height;
+ div *= lcd->freq ? : 60;
+ clk /= div;
+
+ dp->ctrl.clk_div_lv0 = clk;
+ dp->ctrl.clk_inv_lv0 = lcd->polarity.rise_vclk;
+
+ dp->top.screen_width = lcd->width;
+ dp->top.screen_height = lcd->height;
+
+ for (i = 0; i < dp->top.plane_num; i++, plane++) {
+ if (plane->enable) {
+ plane->width = lcd->width;
+ plane->height = lcd->height;
+ }
+ }
+
+ /* initialize display device type */
+ if (fmt == LCD_RGB) {
+ dp->dev_type = DP_DEVICE_RGBLCD;
+
+ } else if (fmt == LCD_HDMI) {
+ struct dp_hdmi_dev *dev = (struct dp_hdmi_dev *)dp->device;
+
+ dp->dev_type = DP_DEVICE_HDMI;
+ if (lcd->width == 1920 && lcd->height == 1080)
+ dev->preset = 1;
+ else
+ dev->preset = 0;
+
+ } else {
+ struct dp_lvds_dev *dev = (struct dp_lvds_dev *)dp->device;
+
+ dp->dev_type = DP_DEVICE_LVDS;
+ dev->lvds_format = (fmt & 0x3);
+ }
+
+ return 0;
+}
+
+/* --------------------------------------------------------------------------
+ * initialize board status.
+ */
+
+#define MMC_BOOT_CH0 (0)
+#define MMC_BOOT_CH1 (1 << 3)
+#define MMC_BOOT_CH2 (1 << 19)
+
+static void bd_bootdev_init(void)
+{
+ unsigned int rst = readl(PHY_BASEADDR_CLKPWR + SYSRSTCONFIG);
+
+ rst &= (1 << 19) | (1 << 3);
+ if (rst == MMC_BOOT_CH0) {
+ /* mmc dev 1 for SD boot */
+ mmc_boot_dev = 1;
+ }
+}
+
+static void bd_onewire_init(void)
+{
+ unsigned char lcd;
+ unsigned short fw_ver;
+
+ onewire_init();
+ onewire_get_info(&lcd, &fw_ver);
+}
+
+static void bd_lcd_init(void)
+{
+ struct nxp_lcd *cfg;
+ int id;
+ int ret;
+
+ id = onewire_get_lcd_id();
+ /* -1: onwire probe failed
+ * 0: bad
+ * >0: identified
+ */
+
+ ret = bd_setup_lcd_by_id(id);
+ if (id <= 0 || ret != id) {
+ printf("Panel: N/A (%d)\n", id);
+ bd_setup_lcd_by_name("HDMI720P60");
+
+ } else {
+ printf("Panel: %s\n", bd_get_lcd_name());
+
+ cfg = bd_get_lcd();
+ if (cfg->gpio_init)
+ cfg->gpio_init();
+ }
+}
+
+static int mac_read_from_generic_eeprom(u8 *addr)
+{
+ return -1;
+}
+
+static void make_ether_addr(u8 *addr)
+{
+ u32 hash[20];
+
+#define ETHER_MAC_TAG "ethmac"
+ memset(hash, 0, sizeof(hash));
+ memcpy(hash + 12, ETHER_MAC_TAG, sizeof(ETHER_MAC_TAG));
+
+ hash[4] = readl(PHY_BASEADDR_ECID + 0x00);
+ hash[5] = readl(PHY_BASEADDR_ECID + 0x04);
+ hash[6] = readl(PHY_BASEADDR_ECID + 0x08);
+ hash[7] = readl(PHY_BASEADDR_ECID + 0x0c);
+
+ md5((unsigned char *)&hash[4], 64, (unsigned char *)hash);
+
+ hash[0] ^= hash[2];
+ hash[1] ^= hash[3];
+
+ memcpy(addr, (char *)hash, 6);
+ addr[0] &= 0xfe; /* clear multicast bit */
+ addr[0] |= 0x02;
+}
+
+static void set_ether_addr(void)
+{
+ unsigned char mac[6];
+ char ethaddr[20];
+ int ret;
+
+ if (env_get("ethaddr"))
+ return;
+
+ ret = mac_read_from_generic_eeprom(mac);
+ if (ret < 0)
+ make_ether_addr(mac);
+
+ sprintf(ethaddr, "%02x:%02x:%02x:%02x:%02x:%02x",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+ if (!ret)
+ printf("MAC: [%s]\n", ethaddr);
+
+ env_set("ethaddr", ethaddr);
+}
+
+#ifdef CONFIG_REVISION_TAG
+static void set_board_rev(void)
+{
+ char info[64] = {0, };
+
+ snprintf(info, ARRAY_SIZE(info), "%02x", get_board_rev());
+ env_set("board_rev", info);
+}
+#endif
+
+static void set_dtb_name(void)
+{
+ char info[64] = {0, };
+
+ snprintf(info, ARRAY_SIZE(info),
+ "s5p4418-nanopi2-rev%02x.dtb", get_board_rev());
+ env_set("dtb_name", info);
+}
+
+static void bd_update_env(void)
+{
+ char *lcdtype = env_get("lcdtype");
+ char *lcddpi = env_get("lcddpi");
+ char *bootargs = env_get("bootargs");
+ const char *name;
+ char *p = NULL;
+ int rootdev = board_mmc_bootdev();
+ int need_save = 0;
+
+#define CMDLINE_LCD " lcd="
+ char cmdline[CONFIG_SYS_CBSIZE];
+ int n = 1;
+
+ if (rootdev != CONFIG_ROOT_DEV && !env_get("firstboot")) {
+ env_set_ulong("rootdev", rootdev);
+ env_set("firstboot", "0");
+ need_save = 1;
+ }
+
+ if (lcdtype) {
+ /* Setup again as user specified LCD in env */
+ bd_setup_lcd_by_name(lcdtype);
+ }
+
+ name = bd_get_lcd_name();
+
+ if (bootargs)
+ n = strlen(bootargs); /* isn't 0 for NULL */
+ else
+ cmdline[0] = '\0';
+
+ if ((n + strlen(name) + sizeof(CMDLINE_LCD)) > sizeof(cmdline)) {
+ printf("Error: `bootargs' is too large (%d)\n", n);
+ goto __exit;
+ }
+
+ if (bootargs) {
+ p = strstr(bootargs, CMDLINE_LCD);
+ if (p) {
+ n = (p - bootargs);
+ p += strlen(CMDLINE_LCD);
+ }
+ strncpy(cmdline, bootargs, n);
+ }
+
+ /* add `lcd=NAME,NUMdpi' */
+ strncpy(cmdline + n, CMDLINE_LCD, strlen(CMDLINE_LCD));
+ n += strlen(CMDLINE_LCD);
+
+ strcpy(cmdline + n, name);
+ n += strlen(name);
+
+ if (lcddpi) {
+ n += sprintf(cmdline + n, ",%sdpi", lcddpi);
+ } else {
+ int dpi = bd_get_lcd_density();
+
+ if (dpi > 0 && dpi < 600)
+ n += sprintf(cmdline + n, ",%ddpi", dpi);
+ }
+
+ /* copy remaining of bootargs */
+ if (p) {
+ p = strstr(p, " ");
+ if (p) {
+ strcpy(cmdline + n, p);
+ n += strlen(p);
+ }
+ }
+
+ /* append `bootdev=2' */
+#define CMDLINE_BDEV " bootdev="
+ if (rootdev > 0 && !strstr(cmdline, CMDLINE_BDEV))
+ n += sprintf(cmdline + n, "%s2", CMDLINE_BDEV);
+
+ /* finally, let's update uboot env & save it */
+ if (bootargs && strncmp(cmdline, bootargs, sizeof(cmdline))) {
+ env_set("bootargs", cmdline);
+ need_save = 1;
+ }
+
+__exit:
+ if (need_save)
+ env_save();
+}
+
+/* --------------------------------------------------------------------------
+ * call from u-boot
+ */
+
+int board_early_init_f(void)
+{
+ return 0;
+}
+
+int board_init(void)
+{
+ bd_hwrev_init();
+ bd_base_rev_init();
+
+ bd_bootdev_init();
+ bd_onewire_init();
+
+ bd_backlight_off();
+
+ bd_lcd_config_gpio();
+ bd_lcd_init();
+
+#ifdef CONFIG_SILENT_CONSOLE
+ gd->flags |= GD_FLG_SILENT;
+#endif
+
+ return 0;
+}
+
+#ifdef CONFIG_BOARD_LATE_INIT
+int board_late_init(void)
+{
+ bd_update_env();
+
+#ifdef CONFIG_REVISION_TAG
+ set_board_rev();
+#endif
+ set_dtb_name();
+
+ set_ether_addr();
+
+#ifdef CONFIG_SILENT_CONSOLE
+ gd->flags &= ~GD_FLG_SILENT;
+#endif
+
+ bd_backlight_on();
+ printf("\n");
+
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_SPLASH_SOURCE
+#include <splash.h>
+static struct splash_location splash_locations[] = {
+ {
+ .name = "mmc_fs",
+ .storage = SPLASH_STORAGE_MMC,
+ .flags = SPLASH_STORAGE_FS,
+ .devpart = __stringify(CONFIG_ROOT_DEV) ":"
+ __stringify(CONFIG_BOOT_PART),
+ },
+};
+
+int splash_screen_prepare(void)
+{
+ int err;
+ char *env_cmd = env_get("load_splash");
+
+ debug("%s()\n", __func__);
+
+ if (env_cmd) {
+ err = run_command(env_cmd, 0);
+
+ } else {
+ char devpart[64] = { 0, };
+ int bootpart = env_get_ulong("bootpart", 0, CONFIG_BOOT_PART);
+ int rootdev;
+
+ if (env_get("firstboot"))
+ rootdev = env_get_ulong("rootdev", 0, CONFIG_ROOT_DEV);
+ else
+ rootdev = board_mmc_bootdev();
+
+ snprintf(devpart, ARRAY_SIZE(devpart), "%d:%d", rootdev,
+ bootpart);
+ splash_locations[0].devpart = devpart;
+
+ err = splash_source_load(splash_locations,
+ ARRAY_SIZE(splash_locations));
+ }
+
+ if (!err) {
+ char addr[64];
+
+ sprintf(addr, "0x%lx", gd->fb_base);
+ env_set("fb_addr", addr);
+ }
+
+ return err;
+}
+#endif
+
+/* u-boot dram initialize */
+int dram_init(void)
+{
+ gd->ram_size = CONFIG_SYS_SDRAM_SIZE;
+ return 0;
+}
+
+/* u-boot dram board specific */
+int dram_init_banksize(void)
+{
+#define SCR_USER_SIG6_READ (SCR_ALIVE_BASE + 0x0F0)
+ unsigned int reg_val = readl(SCR_USER_SIG6_READ);
+
+ /* set global data memory */
+ gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x00000100;
+
+ gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
+ gd->bd->bi_dram[0].size = CONFIG_SYS_SDRAM_SIZE;
+
+ /* Number of Row: 14 bits */
+ if ((reg_val >> 28) == 14)
+ gd->bd->bi_dram[0].size -= 0x20000000;
+
+ /* Number of Memory Chips */
+ if ((reg_val & 0x3) > 1) {
+ gd->bd->bi_dram[1].start = 0x80000000;
+ gd->bd->bi_dram[1].size = 0x40000000;
+ }
+ return 0;
+}
+
+#if defined(CONFIG_OF_BOARD_SETUP)
+int ft_board_setup(void *blob, bd_t *bd)
+{
+ int nodeoff;
+ unsigned int rootdev;
+ unsigned int fb_addr;
+
+ if (board_mmc_bootdev() > 0) {
+ rootdev = fdt_getprop_u32_default(blob, "/board", "sdidx", 2);
+ if (rootdev) {
+ /* find or create "/chosen" node. */
+ nodeoff = fdt_find_or_add_subnode(blob, 0, "chosen");
+ if (nodeoff >= 0)
+ fdt_setprop_u32(blob, nodeoff, "linux,rootdev",
+ rootdev);
+ }
+ }
+
+ fb_addr = env_get_ulong("fb_addr", 0, 0);
+ if (fb_addr) {
+ nodeoff = fdt_path_offset(blob, "/reserved-memory");
+ if (nodeoff < 0)
+ return nodeoff;
+
+ nodeoff = fdt_add_subnode(blob, nodeoff, "display_reserved");
+ if (nodeoff >= 0) {
+ fdt32_t cells[2];
+
+ cells[0] = cpu_to_fdt32(fb_addr);
+ cells[1] = cpu_to_fdt32(0x800000);
+
+ fdt_setprop(blob, nodeoff, "reg", cells,
+ sizeof(cells[0]) * 2);
+ }
+ }
+
+ return 0;
+}
+#endif
diff --git a/board/friendlyarm/nanopi2/hwrev.c b/board/friendlyarm/nanopi2/hwrev.c
new file mode 100644
index 0000000..10a41cd
--- /dev/null
+++ b/board/friendlyarm/nanopi2/hwrev.c
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) Guangzhou FriendlyARM Computer Tech. Co., Ltd.
+ * (http://www.friendlyarm.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
+ */
+
+#include <config.h>
+#include <common.h>
+#include <i2c.h>
+#include <asm/io.h>
+
+#include <asm/arch/nexell.h>
+#include <asm/arch/nx_gpio.h>
+
+/* Board revision list: <PCB3 | PCB2 | PCB1>
+ * 0b000 - NanoPi 2
+ * 0b001 - NanoPC-T2
+ * 0b010 - NanoPi S2
+ * 0b011 - Smart4418
+ * 0b100 - NanoPi Fire 2A
+ * 0b111 - NanoPi M2A
+ *
+ * Extented revision:
+ * 0b001 - Smart4418-SDK
+ */
+#define __IO_GRP 2 /* GPIO_C */
+#define __IO_PCB1 26
+#define __IO_PCB2 27
+#define __IO_PCB3 25
+
+static int pcb_rev = -1;
+static int base_rev = 0;
+
+static void bd_hwrev_config_gpio(void)
+{
+ int gpios[3][2] = {
+ { __IO_PCB1, 1 },
+ { __IO_PCB2, 1 },
+ { __IO_PCB3, 1 },
+ };
+ int i;
+
+ /* gpio input mode, pull-down */
+ for (i = 0; i < 3; i++) {
+ nx_gpio_set_pad_function(__IO_GRP, gpios[i][0], gpios[i][1]);
+ nx_gpio_set_output_enable(__IO_GRP, gpios[i][0], 0);
+ nx_gpio_set_pull_mode(__IO_GRP, gpios[i][0], 0);
+ }
+}
+
+void bd_hwrev_init(void)
+{
+ if (pcb_rev >= 0)
+ return;
+
+ bd_hwrev_config_gpio();
+
+ pcb_rev = nx_gpio_get_input_value(__IO_GRP, __IO_PCB1);
+ pcb_rev |= nx_gpio_get_input_value(__IO_GRP, __IO_PCB2) << 1;
+ pcb_rev |= nx_gpio_get_input_value(__IO_GRP, __IO_PCB3) << 2;
+}
+
+/* Get extended revision for SmartXX18 */
+void bd_base_rev_init(void)
+{
+ struct udevice *dev;
+ u8 val = 0;
+
+ if (pcb_rev != 0x3)
+ return;
+
+#define PCA9536_I2C_BUS 2
+#define PCA9636_I2C_ADDR 0x41
+ if (i2c_get_chip_for_busnum
+ (PCA9536_I2C_BUS, PCA9636_I2C_ADDR, 1, &dev))
+ return;
+
+ if (!dm_i2c_read(dev, 0, &val, 1))
+ base_rev = (val & 0xf);
+}
+
+/* To override __weak symbols */
+u32 get_board_rev(void)
+{
+ return (base_rev << 8) | pcb_rev;
+}
+
+const char *get_board_name(void)
+{
+ bd_hwrev_init();
+
+ switch (pcb_rev) {
+ case 0:
+ return "NanoPi 2";
+ case 1:
+ return "NanoPC-T2";
+ case 2:
+ return "NanoPi S2";
+ case 3:
+ return "Smart4418";
+ case 4:
+ return "NanoPi Fire 2A";
+ case 7:
+ return "NanoPi M2A";
+ default:
+ return "s5p4418-X";
+ }
+}
diff --git a/board/friendlyarm/nanopi2/hwrev.h b/board/friendlyarm/nanopi2/hwrev.h
new file mode 100644
index 0000000..7bd1b67
--- /dev/null
+++ b/board/friendlyarm/nanopi2/hwrev.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0+
+ *
+ * Copyright (C) Guangzhou FriendlyARM Computer Tech. Co., Ltd.
+ * (http://www.friendlyarm.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
+ */
+
+#ifndef __BD_HW_REV_H__
+#define __BD_HW_REV_H__
+
+extern void bd_hwrev_init(void);
+extern void bd_base_rev_init(void);
+extern u32 get_board_rev(void);
+extern const char *get_board_name(void);
+
+#endif /* __BD_HW_REV_H__ */
diff --git a/board/friendlyarm/nanopi2/lcds.c b/board/friendlyarm/nanopi2/lcds.c
new file mode 100644
index 0000000..3d2d66f
--- /dev/null
+++ b/board/friendlyarm/nanopi2/lcds.c
@@ -0,0 +1,703 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * board/s5p4418/nanopi2/lcds.c
+ *
+ * Copyright (c) 2017 FriendlyARM (www.arm9.net)
+ *
+ * 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.
+ */
+
+#include <config.h>
+#include <common.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <fdt_support.h>
+#include <asm/io.h>
+
+#include <asm/arch/nexell.h>
+#include <asm/arch/display.h>
+#include <asm/arch/nx_gpio.h>
+
+#include "nxp-fb.h"
+
+/*
+ * param @module_index for nx_gpio APIs and will be removed
+ * after support pinctrl
+ */
+#ifndef PAD_GPIO_A
+#define PAD_GPIO_A 0
+#endif
+
+static inline void common_gpio_init(void)
+{
+ /* PVCLK */
+ nx_gpio_set_fast_slew(PAD_GPIO_A, 0, 1);
+}
+
+static void s70_gpio_init(void)
+{
+ int i;
+
+ /* PVCLK */
+ nx_gpio_set_drive_strength(PAD_GPIO_A, 0, 1);
+
+ /* RGB24 */
+ for (i = 1; i < 25; i++)
+ nx_gpio_set_drive_strength(PAD_GPIO_A, i, 2);
+
+ /* HS/VS/DE */
+ for (; i < 28; i++)
+ nx_gpio_set_drive_strength(PAD_GPIO_A, i, 1);
+}
+
+static void s702_gpio_init(void)
+{
+ int i;
+
+ common_gpio_init();
+
+ nx_gpio_set_drive_strength(PAD_GPIO_A, 0, 2);
+
+ for (i = 1; i < 25; i++)
+ nx_gpio_set_drive_strength(PAD_GPIO_A, i, 0);
+
+ for (; i < 28; i++)
+ nx_gpio_set_drive_strength(PAD_GPIO_A, i, 1);
+}
+
+static void s430_gpio_init(void)
+{
+ int i;
+
+ for (i = 0; i < 28; i++)
+ nx_gpio_set_drive_strength(PAD_GPIO_A, i, 1);
+}
+
+static void hd101_gpio_init(void)
+{
+ int i;
+
+ common_gpio_init();
+
+ nx_gpio_set_drive_strength(PAD_GPIO_A, 0, 2);
+
+ for (i = 1; i < 25; i++)
+ nx_gpio_set_drive_strength(PAD_GPIO_A, i, 1);
+
+ nx_gpio_set_drive_strength(PAD_GPIO_A, 27, 1);
+}
+
+static void hd700_gpio_init(void)
+{
+ hd101_gpio_init();
+}
+
+/* NXP display configs for supported LCD */
+
+static struct nxp_lcd wxga_hd700 = {
+ .width = 800,
+ .height = 1280,
+ .p_width = 94,
+ .p_height = 151,
+ .bpp = 24,
+ .freq = 60,
+
+ .timing = {
+ .h_fp = 20,
+ .h_bp = 20,
+ .h_sw = 24,
+ .v_fp = 4,
+ .v_fpe = 1,
+ .v_bp = 4,
+ .v_bpe = 1,
+ .v_sw = 8,
+ },
+ .polarity = {
+ .rise_vclk = 0,
+ .inv_hsync = 0,
+ .inv_vsync = 0,
+ .inv_vden = 0,
+ },
+ .gpio_init = hd700_gpio_init,
+};
+
+static struct nxp_lcd wvga_s70 = {
+ .width = 800,
+ .height = 480,
+ .p_width = 155,
+ .p_height = 93,
+ .bpp = 24,
+ .freq = 61,
+
+ .timing = {
+ .h_fp = 48,
+ .h_bp = 36,
+ .h_sw = 10,
+ .v_fp = 22,
+ .v_fpe = 1,
+ .v_bp = 15,
+ .v_bpe = 1,
+ .v_sw = 8,
+ },
+ .polarity = {
+ .rise_vclk = 0,
+ .inv_hsync = 1,
+ .inv_vsync = 1,
+ .inv_vden = 0,
+ },
+ .gpio_init = s70_gpio_init,
+};
+
+static struct nxp_lcd wvga_s702 = {
+ .width = 800,
+ .height = 480,
+ .p_width = 155,
+ .p_height = 93,
+ .bpp = 24,
+ .freq = 61,
+
+ .timing = {
+ .h_fp = 44,
+ .h_bp = 26,
+ .h_sw = 20,
+ .v_fp = 22,
+ .v_fpe = 1,
+ .v_bp = 15,
+ .v_bpe = 1,
+ .v_sw = 8,
+ },
+ .polarity = {
+ .rise_vclk = 1,
+ .inv_hsync = 1,
+ .inv_vsync = 1,
+ .inv_vden = 0,
+ },
+ .gpio_init = s702_gpio_init,
+};
+
+static struct nxp_lcd wvga_s70d = {
+ .width = 800,
+ .height = 480,
+ .p_width = 155,
+ .p_height = 93,
+ .bpp = 24,
+ .freq = 61,
+
+ .timing = {
+ .h_fp = 80,
+ .h_bp = 78,
+ .h_sw = 10,
+ .v_fp = 22,
+ .v_fpe = 1,
+ .v_bp = 24,
+ .v_bpe = 1,
+ .v_sw = 8,
+ },
+ .polarity = {
+ .rise_vclk = 0,
+ .inv_hsync = 1,
+ .inv_vsync = 1,
+ .inv_vden = 0,
+ },
+ .gpio_init = s702_gpio_init,
+};
+
+static struct nxp_lcd wvga_w50 = {
+ .width = 800,
+ .height = 480,
+ .p_width = 108,
+ .p_height = 64,
+ .bpp = 24,
+ .freq = 61,
+
+ .timing = {
+ .h_fp = 40,
+ .h_bp = 40,
+ .h_sw = 48,
+ .v_fp = 20,
+ .v_fpe = 1,
+ .v_bp = 20,
+ .v_bpe = 1,
+ .v_sw = 12,
+ },
+ .polarity = {
+ .rise_vclk = 0,
+ .inv_hsync = 1,
+ .inv_vsync = 1,
+ .inv_vden = 0,
+ },
+ .gpio_init = s70_gpio_init,
+};
+
+static struct nxp_lcd wvga_s430 = {
+ .width = 480,
+ .height = 800,
+ .p_width = 108,
+ .p_height = 64,
+ .bpp = 24,
+ .freq = 60,
+
+ .timing = {
+ .h_fp = 64,
+ .h_bp = 0,
+ .h_sw = 16,
+ .v_fp = 32,
+ .v_fpe = 1,
+ .v_bp = 0,
+ .v_bpe = 1,
+ .v_sw = 16,
+ },
+ .polarity = {
+ .rise_vclk = 1,
+ .inv_hsync = 1,
+ .inv_vsync = 1,
+ .inv_vden = 0,
+ },
+ .gpio_init = s430_gpio_init,
+};
+
+static struct nxp_lcd wsvga_w101 = {
+ .width = 1024,
+ .height = 600,
+ .p_width = 204,
+ .p_height = 120,
+ .bpp = 24,
+ .freq = 60,
+
+ .timing = {
+ .h_fp = 40,
+ .h_bp = 40,
+ .h_sw = 200,
+ .v_fp = 8,
+ .v_fpe = 1,
+ .v_bp = 8,
+ .v_bpe = 1,
+ .v_sw = 16,
+ },
+ .polarity = {
+ .rise_vclk = 1,
+ .inv_hsync = 1,
+ .inv_vsync = 1,
+ .inv_vden = 0,
+ },
+};
+
+static struct nxp_lcd wsvga_x710 = {
+ .width = 1024,
+ .height = 600,
+ .p_width = 154,
+ .p_height = 90,
+ .bpp = 24,
+ .freq = 61,
+
+ .timing = {
+ .h_fp = 84,
+ .h_bp = 84,
+ .h_sw = 88,
+ .v_fp = 10,
+ .v_fpe = 1,
+ .v_bp = 10,
+ .v_bpe = 1,
+ .v_sw = 20,
+ },
+ .polarity = {
+ .rise_vclk = 0,
+ .inv_hsync = 1,
+ .inv_vsync = 1,
+ .inv_vden = 0,
+ },
+ .gpio_init = hd101_gpio_init,
+};
+
+static struct nxp_lcd xga_a97 = {
+ .width = 1024,
+ .height = 768,
+ .p_width = 200,
+ .p_height = 150,
+ .bpp = 24,
+ .freq = 61,
+
+ .timing = {
+ .h_fp = 12,
+ .h_bp = 12,
+ .h_sw = 4,
+ .v_fp = 8,
+ .v_fpe = 1,
+ .v_bp = 8,
+ .v_bpe = 1,
+ .v_sw = 4,
+ },
+ .polarity = {
+ .rise_vclk = 0,
+ .inv_hsync = 1,
+ .inv_vsync = 1,
+ .inv_vden = 0,
+ },
+};
+
+static struct nxp_lcd xga_lq150 = {
+ .width = 1024,
+ .height = 768,
+ .p_width = 304,
+ .p_height = 228,
+ .bpp = 24,
+ .freq = 60,
+
+ .timing = {
+ .h_fp = 12,
+ .h_bp = 12,
+ .h_sw = 40,
+ .v_fp = 8,
+ .v_fpe = 1,
+ .v_bp = 8,
+ .v_bpe = 1,
+ .v_sw = 40,
+ },
+ .polarity = {
+ .rise_vclk = 0,
+ .inv_hsync = 1,
+ .inv_vsync = 1,
+ .inv_vden = 0,
+ },
+};
+
+static struct nxp_lcd vga_l80 = {
+ .width = 640,
+ .height = 480,
+ .p_width = 160,
+ .p_height = 120,
+ .bpp = 32,
+ .freq = 60,
+
+ .timing = {
+ .h_fp = 35,
+ .h_bp = 53,
+ .h_sw = 73,
+ .v_fp = 3,
+ .v_fpe = 1,
+ .v_bp = 29,
+ .v_bpe = 1,
+ .v_sw = 6,
+ },
+ .polarity = {
+ .rise_vclk = 0,
+ .inv_hsync = 1,
+ .inv_vsync = 1,
+ .inv_vden = 0,
+ },
+};
+
+static struct nxp_lcd wxga_bp101 = {
+ .width = 1280,
+ .height = 800,
+ .p_width = 218,
+ .p_height = 136,
+ .bpp = 24,
+ .freq = 60,
+
+ .timing = {
+ .h_fp = 20,
+ .h_bp = 20,
+ .h_sw = 24,
+ .v_fp = 4,
+ .v_fpe = 1,
+ .v_bp = 4,
+ .v_bpe = 1,
+ .v_sw = 8,
+ },
+ .polarity = {
+ .rise_vclk = 1,
+ .inv_hsync = 1,
+ .inv_vsync = 1,
+ .inv_vden = 0,
+ },
+};
+
+static struct nxp_lcd wxga_hd101 = {
+ .width = 1280,
+ .height = 800,
+ .p_width = 218,
+ .p_height = 136,
+ .bpp = 24,
+ .freq = 60,
+
+ .timing = {
+ .h_fp = 16,
+ .h_bp = 16,
+ .h_sw = 30,
+ .v_fp = 8,
+ .v_fpe = 1,
+ .v_bp = 8,
+ .v_bpe = 1,
+ .v_sw = 12,
+ },
+ .polarity = {
+ .rise_vclk = 1,
+ .inv_hsync = 0,
+ .inv_vsync = 0,
+ .inv_vden = 0,
+ },
+ .gpio_init = hd101_gpio_init,
+};
+
+static struct nxp_lcd hvga_h43 = {
+ .width = 480,
+ .height = 272,
+ .p_width = 96,
+ .p_height = 54,
+ .bpp = 32,
+ .freq = 65,
+
+ .timing = {
+ .h_fp = 5,
+ .h_bp = 40,
+ .h_sw = 2,
+ .v_fp = 8,
+ .v_fpe = 1,
+ .v_bp = 8,
+ .v_bpe = 1,
+ .v_sw = 2,
+ },
+ .polarity = {
+ .rise_vclk = 0,
+ .inv_hsync = 1,
+ .inv_vsync = 1,
+ .inv_vden = 0,
+ },
+};
+
+static struct nxp_lcd hvga_p43 = {
+ .width = 480,
+ .height = 272,
+ .p_width = 96,
+ .p_height = 54,
+ .bpp = 32,
+ .freq = 65,
+
+ .timing = {
+ .h_fp = 5,
+ .h_bp = 40,
+ .h_sw = 2,
+ .v_fp = 8,
+ .v_fpe = 1,
+ .v_bp = 9,
+ .v_bpe = 1,
+ .v_sw = 2,
+ },
+ .polarity = {
+ .rise_vclk = 1,
+ .inv_hsync = 1,
+ .inv_vsync = 1,
+ .inv_vden = 0,
+ },
+};
+
+static struct nxp_lcd qvga_w35 = {
+ .width = 320,
+ .height = 240,
+ .p_width = 70,
+ .p_height = 52,
+ .bpp = 16,
+ .freq = 65,
+
+ .timing = {
+ .h_fp = 4,
+ .h_bp = 70,
+ .h_sw = 4,
+ .v_fp = 4,
+ .v_fpe = 1,
+ .v_bp = 12,
+ .v_bpe = 1,
+ .v_sw = 4,
+ },
+ .polarity = {
+ .rise_vclk = 1,
+ .inv_hsync = 0,
+ .inv_vsync = 0,
+ .inv_vden = 0,
+ },
+};
+
+/* HDMI */
+static struct nxp_lcd hdmi_def = {
+ .width = 1920,
+ .height = 1080,
+ .p_width = 480,
+ .p_height = 320,
+ .bpp = 24,
+ .freq = 60,
+
+ .timing = {
+ .h_fp = 12,
+ .h_bp = 12,
+ .h_sw = 4,
+ .v_fp = 8,
+ .v_fpe = 1,
+ .v_bp = 8,
+ .v_bpe = 1,
+ .v_sw = 4,
+ },
+ .polarity = {
+ .rise_vclk = 0,
+ .inv_hsync = 1,
+ .inv_vsync = 1,
+ .inv_vden = 0,
+ },
+};
+
+static struct hdmi_config {
+ char *name;
+ int width;
+ int height;
+} bd_hdmi_config[] = {
+ { "HDMI1080P60", 1920, 1080 },
+ { "HDMI1080I60", 1920, 1080 },
+ { "HDMI1080P30", 1920, 1080 },
+ { "HDMI1080P50", 1920, 1080 },
+ { "HDMI1080I50", 1920, 1080 },
+
+ { "HDMI1080P60D", 960, 536 },
+ { "HDMI1080I60D", 960, 536 },
+ { "HDMI1080P30D", 960, 536 },
+ { "HDMI1080P50D", 960, 536 },
+ { "HDMI1080I50D", 960, 536 },
+
+ { "HDMI720P60", 1280, 720 },
+ { "HDMI720P60D", 640, 360 },
+ { "HDMI720P50", 1280, 720 },
+ { "HDMI720P50D", 640, 360 },
+
+ { "HDMI576P16X9", 720, 576 },
+ { "HDMI576P16X9D", 720, 576 },
+ { "HDMI576P4X3", 720, 576 },
+ { "HDMI576P4X3D", 720, 576 },
+
+ { "HDMI480P16X9", 720, 480 },
+ { "HDMI480P16X9D", 720, 480 },
+ { "HDMI480P4X3", 720, 480 },
+ { "HDMI480P4X3D", 720, 480 },
+};
+
+/* Try to guess LCD panel by kernel command line, or
+ * using *HD101* as default
+ */
+static struct {
+ int id;
+ char *name;
+ struct nxp_lcd *lcd;
+ int dpi;
+ int ctp;
+ enum lcd_format fmt;
+} bd_lcd_config[] = {
+ { 25, "HD101", &wxga_hd101, 0, 1, LCD_RGB },
+ { 32, "HD101B", &wxga_hd101, 0, 1, LCD_RGB },
+ { 18, "HD700", &wxga_hd700, 213, 1, LCD_RGB },
+ { 30, "HD702", &wxga_hd700, 213, 1, LCD_RGB },
+ { 33, "H70", &wxga_hd700, 213, 0, LCD_VESA },
+ { 3, "S70", &wvga_s70, 128, 1, LCD_RGB },
+ { 36, "S701", &wvga_s70, 128, 1, LCD_RGB },
+ { 24, "S702", &wvga_s702, 128, 3, LCD_RGB },
+ { 26, "S70D", &wvga_s70d, 128, 0, LCD_RGB },
+ { 14, "H43", &hvga_h43, 0, 0, LCD_RGB },
+ { 19, "P43", &hvga_p43, 0, 0, LCD_RGB },
+ { 8, "W35", &qvga_w35, 0, 0, LCD_RGB },
+ { 28, "X710", &wsvga_x710, 0, 1, LCD_RGB },
+ { 31, "S430", &wvga_s430, 180, 1, LCD_RGB },
+ { 4, "W50", &wvga_w50, 0, 0, LCD_RGB },
+
+ /* TODO: Testing */
+ { 15, "W101", &wsvga_w101, 0, 1, LCD_RGB },
+ { 5, "L80", &vga_l80, 0, 1, LCD_RGB },
+ { -1, "A97", &xga_a97, 0, 0, LCD_RGB },
+ { -1, "LQ150", &xga_lq150, 0, 1, LCD_RGB },
+ { -1, "BP101", &wxga_bp101, 0, 1, LCD_RGB },
+ /* Pls keep it@last */
+ { 128, "HDMI", &hdmi_def, 0, 0, LCD_HDMI },
+};
+
+static int lcd_idx = 0;
+
+int bd_setup_lcd_by_id(int id)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(bd_lcd_config); i++) {
+ if (bd_lcd_config[i].id == id) {
+ lcd_idx = i;
+ break;
+ }
+ }
+
+ if (i >= ARRAY_SIZE(bd_lcd_config)) {
+ /* NOT found */
+ return -19;
+ }
+
+ return bd_lcd_config[i].id;
+}
+
+int bd_setup_lcd_by_name(char *str)
+{
+ char *delim;
+ int i;
+
+ delim = strchr(str, ',');
+ if (delim)
+ *delim++ = '\0';
+
+ if (!strncasecmp("HDMI", str, 4)) {
+ struct hdmi_config *cfg = &bd_hdmi_config[0];
+ struct nxp_lcd *lcd;
+
+ lcd_idx = ARRAY_SIZE(bd_lcd_config) - 1;
+ lcd = bd_lcd_config[lcd_idx].lcd;
+
+ for (i = 0; i < ARRAY_SIZE(bd_hdmi_config); i++, cfg++) {
+ if (!strcasecmp(cfg->name, str)) {
+ lcd->width = cfg->width;
+ lcd->height = cfg->height;
+ bd_lcd_config[lcd_idx].name = cfg->name;
+ goto __ret;
+ }
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(bd_lcd_config); i++) {
+ if (!strcasecmp(bd_lcd_config[i].name, str)) {
+ lcd_idx = i;
+ break;
+ }
+ }
+
+__ret:
+ return 0;
+}
+
+struct nxp_lcd *bd_get_lcd(void)
+{
+ return bd_lcd_config[lcd_idx].lcd;
+}
+
+const char *bd_get_lcd_name(void)
+{
+ return bd_lcd_config[lcd_idx].name;
+}
+
+enum lcd_format bd_get_lcd_format(void)
+{
+ return bd_lcd_config[lcd_idx].fmt;
+}
+
+int bd_get_lcd_density(void)
+{
+ return bd_lcd_config[lcd_idx].dpi;
+}
+
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+int bd_fixup_lcd_fdt(void *blob, struct nxp_lcd *lcd)
+{
+ return 0;
+}
+#endif
diff --git a/board/friendlyarm/nanopi2/nxp-fb.h b/board/friendlyarm/nanopi2/nxp-fb.h
new file mode 100644
index 0000000..9470fa8
--- /dev/null
+++ b/board/friendlyarm/nanopi2/nxp-fb.h
@@ -0,0 +1,99 @@
+/* SPDX-License-Identifier: GPL-2.0+
+ * board/s5p4418/nanopi2/nxp-fb.h
+ *
+ * Copyright (c) 2017 FriendlyARM (www.arm9.net)
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Header file for NXP Display Driver driver
+ *
+ * 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 __MACH_NXP_FB_H__
+#define __MACH_NXP_FB_H__
+
+/*
+ * struct nxp_lcd_polarity
+ * @rise_vclk: if 1, video data is fetched@rising edge
+ * @inv_hsync: if HSYNC polarity is inversed
+ * @inv_vsync: if VSYNC polarity is inversed
+ * @inv_vden: if VDEN polarity is inversed
+ */
+struct nxp_lcd_polarity {
+ int rise_vclk;
+ int inv_hsync;
+ int inv_vsync;
+ int inv_vden;
+};
+
+/*
+ * struct nxp_lcd_timing
+ * @h_fp: horizontal front porch
+ * @h_bp: horizontal back porch
+ * @h_sw: horizontal sync width
+ * @v_fp: vertical front porch
+ * @v_fpe: vertical front porch for even field
+ * @v_bp: vertical back porch
+ * @v_bpe: vertical back porch for even field
+ */
+struct nxp_lcd_timing {
+ int h_fp;
+ int h_bp;
+ int h_sw;
+ int v_fp;
+ int v_fpe;
+ int v_bp;
+ int v_bpe;
+ int v_sw;
+};
+
+/*
+ * struct nxp_lcd
+ * @width: horizontal resolution
+ * @height: vertical resolution
+ * @p_width: width of lcd in mm
+ * @p_height: height of lcd in mm
+ * @bpp: bits per pixel
+ * @freq: vframe frequency
+ * @timing: timing values
+ * @polarity: polarity settings
+ * @gpio_init: pointer to GPIO init function
+ *
+ */
+struct nxp_lcd {
+ int width;
+ int height;
+ int p_width;
+ int p_height;
+ int bpp;
+ int freq;
+ struct nxp_lcd_timing timing;
+ struct nxp_lcd_polarity polarity;
+ void (*gpio_init)(void);
+};
+
+/**
+ * Public interfaces
+ */
+enum lcd_format {
+ LCD_VESA = 0,
+ LCD_JEIDA = 1,
+ LCD_LOC = 2,
+
+ LCD_RGB = 4,
+ LCD_HDMI = 5,
+};
+
+extern int bd_setup_lcd_by_id(int id);
+extern int bd_setup_lcd_by_name(char *name);
+extern struct nxp_lcd *bd_get_lcd(void);
+extern const char *bd_get_lcd_name(void);
+extern int bd_get_lcd_density(void);
+extern enum lcd_format bd_get_lcd_format(void);
+extern int bd_fixup_lcd_fdt(void *blob, struct nxp_lcd *cfg);
+
+#endif /* __MACH_NXP_FB_H__ */
diff --git a/board/friendlyarm/nanopi2/onewire.c b/board/friendlyarm/nanopi2/onewire.c
new file mode 100644
index 0000000..85314f4
--- /dev/null
+++ b/board/friendlyarm/nanopi2/onewire.c
@@ -0,0 +1,323 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) Guangzhou FriendlyARM Computer Tech. Co., Ltd.
+ * (http://www.friendlyarm.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
+ */
+
+#include <config.h>
+#include <common.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <asm/arch/clk.h>
+#include <i2c.h>
+#ifdef CONFIG_PWM_NX
+#include <pwm.h>
+#endif
+
+#include <irq_func.h>
+
+#include <asm/arch/nexell.h>
+#include <asm/arch/nx_gpio.h>
+
+#ifndef NSEC_PER_SEC
+#define NSEC_PER_SEC 1000000000L
+#endif
+
+#define SAMPLE_BPS 9600
+#define SAMPLE_IN_US 101 /* (1000000 / BPS) */
+
+#define REQ_INFO 0x60U
+#define REQ_BL 0x80U
+
+#define BUS_I2C 0x18
+#define ONEWIRE_I2C_BUS 2
+#define ONEWIRE_I2C_ADDR 0x2f
+
+static int bus_type = -1;
+static int lcd_id = -1;
+static unsigned short lcd_fwrev = 0;
+static int current_brightness = -1;
+#ifdef CONFIG_DM_I2C
+static struct udevice *i2c_dev;
+#endif
+
+/* debug */
+#if (0)
+#define DBGOUT(msg...) do { printf("onewire: " msg); } while (0)
+#else
+#define DBGOUT(msg...) do {} while (0)
+#endif
+
+/* based on web page from http://lfh1986.blogspot.com */
+static unsigned char crc8_ow(unsigned int v, unsigned int len)
+{
+ unsigned char crc = 0xACU;
+
+ while (len--) {
+ if ((crc & 0x80U) != 0) {
+ crc <<= 1;
+ crc ^= 0x7U;
+ } else {
+ crc <<= 1;
+ }
+ if ((v & (1U << 31)) != 0)
+ crc ^= 0x7U;
+ v <<= 1;
+ }
+ return crc;
+}
+
+/* GPIO helpers */
+#define __IO_GRP 2 /* GPIOC15 */
+#define __IO_IDX 15
+
+static inline void set_pin_as_input(void)
+{
+ nx_gpio_set_output_enable(__IO_GRP, __IO_IDX, 0);
+}
+
+static inline void set_pin_as_output(void)
+{
+ nx_gpio_set_output_enable(__IO_GRP, __IO_IDX, 1);
+}
+
+static inline void set_pin_value(int v)
+{
+ nx_gpio_set_output_value(__IO_GRP, __IO_IDX, !!v);
+}
+
+static inline int get_pin_value(void)
+{
+ return nx_gpio_get_input_value(__IO_GRP, __IO_IDX);
+}
+
+/* Timer helpers */
+#define PWM_CH 3
+#define PWM_TCON (PHY_BASEADDR_PWM + 0x08)
+#define PWM_TCON_START (1 << 16)
+#define PWM_TINT_CSTAT (PHY_BASEADDR_PWM + 0x44)
+
+static int onewire_init_timer(void)
+{
+ int period_ns = NSEC_PER_SEC / SAMPLE_BPS;
+
+ /* range: 1080~1970 */
+ period_ns -= 1525;
+
+ return pwm_config(PWM_CH, period_ns >> 1, period_ns);
+}
+
+static void wait_one_tick(void)
+{
+ unsigned int tcon;
+
+ tcon = readl(PWM_TCON);
+ tcon |= PWM_TCON_START;
+ writel(tcon, PWM_TCON);
+
+ while (1) {
+ if (readl(PWM_TINT_CSTAT) & (1 << (5 + PWM_CH)))
+ break;
+ }
+
+ writel((1 << (5 + PWM_CH)), PWM_TINT_CSTAT);
+
+ tcon &= ~PWM_TCON_START;
+ writel(tcon, PWM_TCON);
+}
+
+/* Session handler */
+static int onewire_session(unsigned char req, unsigned char res[])
+{
+ unsigned int Req;
+ unsigned int *Res;
+ int ints = disable_interrupts();
+ int i;
+ int ret;
+
+ Req = (req << 24) | (crc8_ow(req << 24, 8) << 16);
+ Res = (unsigned int *)res;
+
+ set_pin_value(1);
+ set_pin_as_output();
+ for (i = 0; i < 60; i++)
+ wait_one_tick();
+
+ set_pin_value(0);
+ for (i = 0; i < 2; i++)
+ wait_one_tick();
+
+ for (i = 0; i < 16; i++) {
+ int v = !!(Req & (1U << 31));
+
+ Req <<= 1;
+ set_pin_value(v);
+ wait_one_tick();
+ }
+
+ wait_one_tick();
+ set_pin_as_input();
+ wait_one_tick();
+ for (i = 0; i < 32; i++) {
+ (*Res) <<= 1;
+ (*Res) |= get_pin_value();
+ wait_one_tick();
+ }
+ set_pin_value(1);
+ set_pin_as_output();
+
+ if (ints)
+ enable_interrupts();
+
+ ret = crc8_ow(*Res, 24) == res[0];
+ DBGOUT("req = %02X, res = %02X%02X%02X%02X, ret = %d\n",
+ req, res[3], res[2], res[1], res[0], ret);
+
+ return ret;
+}
+
+static int onewire_i2c_do_request(unsigned char req, unsigned char *buf)
+{
+ unsigned char tx[4];
+ int ret;
+
+ tx[0] = req;
+ tx[1] = crc8_ow(req << 24, 8);
+
+#ifdef CONFIG_DM_I2C
+ if (dm_i2c_write(i2c_dev, 0, tx, 2))
+ return -EIO;
+
+ if (!buf)
+ return 0;
+
+ if (dm_i2c_read(i2c_dev, 0, buf, 4))
+ return -EIO;
+#else
+ if (i2c_write(ONEWIRE_I2C_ADDR, 0, 0, tx, 2))
+ return -EIO;
+
+ if (!buf) /* NO READ */
+ return 0;
+
+ if (i2c_read(ONEWIRE_I2C_ADDR, 0, 0, buf, 4))
+ return -EIO;
+#endif
+
+ ret = crc8_ow((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8), 24);
+ DBGOUT("req = %02X, res = %02X%02X%02X%02X, ret = %02x\n",
+ req, buf[0], buf[1], buf[2], buf[3], ret);
+
+ return (ret == buf[3]) ? 0 : -EIO;
+}
+
+static void onewire_i2c_init(void)
+{
+ unsigned char buf[4];
+ int ret;
+
+#ifdef CONFIG_DM_I2C
+ ret = i2c_get_chip_for_busnum(ONEWIRE_I2C_BUS,
+ ONEWIRE_I2C_ADDR, 0, &i2c_dev);
+#else
+ i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+ i2c_set_bus_num(ONEWIRE_I2C_BUS);
+
+ ret = i2c_probe(ONEWIRE_I2C_ADDR);
+#endif
+ if (ret)
+ return;
+
+ ret = onewire_i2c_do_request(REQ_INFO, buf);
+ if (!ret) {
+ lcd_id = buf[0];
+ lcd_fwrev = buf[1] * 0x100 + buf[2];
+ bus_type = BUS_I2C;
+ }
+}
+
+void onewire_init(void)
+{
+ /* GPIO, Pull-off */
+ nx_gpio_set_pad_function(__IO_GRP, __IO_IDX, 1);
+ nx_gpio_set_pull_mode(__IO_GRP, __IO_IDX, 2);
+
+ onewire_init_timer();
+ onewire_i2c_init();
+}
+
+int onewire_get_info(unsigned char *lcd, unsigned short *fw_ver)
+{
+ unsigned char res[4];
+ int i;
+
+ if (bus_type == BUS_I2C && lcd_id > 0) {
+ *lcd = lcd_id;
+ *fw_ver = lcd_fwrev;
+ return 0;
+ }
+
+ for (i = 0; i < 3; i++) {
+ if (onewire_session(REQ_INFO, res)) {
+ *lcd = res[3];
+ *fw_ver = res[2] * 0x100 + res[1];
+ lcd_id = *lcd;
+ DBGOUT("lcd = %d, fw_ver = %x\n", *lcd, *fw_ver);
+ return 0;
+ }
+ }
+
+ /* LCD unknown or not connected */
+ *lcd = 0;
+ *fw_ver = -1;
+
+ return -1;
+}
+
+int onewire_get_lcd_id(void)
+{
+ return lcd_id;
+}
+
+int onewire_set_backlight(int brightness)
+{
+ unsigned char res[4];
+ int i;
+
+ if (brightness == current_brightness)
+ return 0;
+
+ if (brightness > 127)
+ brightness = 127;
+ else if (brightness < 0)
+ brightness = 0;
+
+ if (bus_type == BUS_I2C) {
+ onewire_i2c_do_request((REQ_BL | brightness), NULL);
+ current_brightness = brightness;
+ return 0;
+ }
+
+ for (i = 0; i < 3; i++) {
+ if (onewire_session((REQ_BL | brightness), res)) {
+ current_brightness = brightness;
+ return 0;
+ }
+ }
+
+ return -1;
+}
diff --git a/board/friendlyarm/nanopi2/onewire.h b/board/friendlyarm/nanopi2/onewire.h
new file mode 100644
index 0000000..23a93c0
--- /dev/null
+++ b/board/friendlyarm/nanopi2/onewire.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0+
+ *
+ * Copyright (C) Guangzhou FriendlyARM Computer Tech. Co., Ltd.
+ * (http://www.friendlyarm.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
+ */
+
+#ifndef __ONE_WIRE_H__
+#define __ONE_WIRE_H__
+
+extern void onewire_init(void);
+extern int onewire_get_info(unsigned char *lcd, unsigned short *fw_ver);
+extern int onewire_get_lcd_id(void);
+extern int onewire_set_backlight(int brightness);
+
+#endif /* __ONE_WIRE_H__ */
--
1.9.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH 10/10] arm: add (default) config for nanopi2 board
2020-02-03 19:39 [RFC PATCH 00/10] arm: add support for SoC S5P4418 Stefan Bosch
` (8 preceding siblings ...)
2020-02-03 20:46 ` [RFC PATCH 09/10] arm: add support for SoC s5p4418 (cpu) / nanopi2 board Stefan Bosch
@ 2020-02-03 20:47 ` Stefan Bosch
2020-02-07 16:11 ` [RFC PATCH 00/10] arm: add support for SoC S5P4418 Tom Rini
2020-02-22 13:06 ` Amit Tomer
11 siblings, 0 replies; 19+ messages in thread
From: Stefan Bosch @ 2020-02-03 20:47 UTC (permalink / raw)
To: u-boot
Changes in relation to FriendlyARM's U-Boot nanopi2-v2016.01:
- Configuration changed, mainly several "CONFIG_..." moved from
s5p4418_nanopi2.h to s5p4418_nanopi2_defconfig.
- s5p4418_nanopi2.h: "CONFIG_" removed from several s5p4418/nanopi2
specific defines because the appropriate values do not need to be
configurable.
Signed-off-by: Stefan Bosch <stefan_b@posteo.net>
---
MAINTAINERS | 19 +++
configs/s5p4418_nanopi2_defconfig | 177 +++++++++++++++++++++++++
doc/README.s5p4418 | 63 +++++++++
include/configs/s5p4418_nanopi2.h | 270 ++++++++++++++++++++++++++++++++++++++
4 files changed, 529 insertions(+)
create mode 100644 configs/s5p4418_nanopi2_defconfig
create mode 100644 doc/README.s5p4418
create mode 100644 include/configs/s5p4418_nanopi2.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 7d2729d..9e5de66 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -258,6 +258,25 @@ F: arch/arm/mach-at91/
F: board/atmel/
F: drivers/misc/microchip_flexcom.c
+ARM NEXELL S5P4418
+M: Stefan Bosch <stefan_b@posteo.net>
+S: Maintained
+F: arch/arm/cpu/armv7/s5p4418/
+F: arch/arm/dts/s5p4418*
+F: arch/arm/mach-nexell/
+F: board/friendlyarm/
+F: configs/s5p4418_nanopi2_defconfig
+F: doc/README.s5p4418
+F: drivers/gpio/nx_gpio.c
+F: drivers/i2c/nx_i2c.c
+F: drivers/mmc/nexell_dw_mmc_dm.c
+F: drivers/pwm/pwm-nexell*
+F: drivers/video/nexell/
+F: drivers/pwm/pwm-nexell*
+F: drivers/video/nexell/
+F: drivers/video/nexell_display.c
+F: include/configs/s5p4418_nanopi2.h
+
ARM OWL
M: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
S: Maintained
diff --git a/configs/s5p4418_nanopi2_defconfig b/configs/s5p4418_nanopi2_defconfig
new file mode 100644
index 0000000..921470a
--- /dev/null
+++ b/configs/s5p4418_nanopi2_defconfig
@@ -0,0 +1,177 @@
+CONFIG_ARM=y
+CONFIG_ARCH_NEXELL=y
+CONFIG_ARCH_S5P4418=y
+CONFIG_TARGET_NANOPI2=y
+CONFIG_DM_I2C=y
+CONFIG_DM_GPIO=y
+CONFIG_DEFAULT_DEVICE_TREE="s5p4418-nanopi2"
+CONFIG_FIT=y
+
+# Must be set to 'n' (apparently "CONFIG_EFI_LOADER=y" per default)
+# otherwise boot errors "efi_runtime_relocate: Unknown relocation type 0"
+CONFIG_EFI_LOADER=n
+
+# CONFIG_CMD_IMLS is not set
+# CONFIG_CMD_FLASH is not set
+CONFIG_CMD_I2C=y
+CONFIG_CMD_USB=y
+# CONFIG_CMD_FPGA is not set
+CONFIG_CMD_GPIO=y
+# CONFIG_CMD_SETEXPR is not set
+
+# CONFIG_CMD_NET is not set
+
+# Default is CONFIG_NET=y, in this case:
+# Loading Environment from MMC... ## Warning: Unknown environment variable type 'm'
+# OK
+# CONFIG_CMD_NET=y must be set to avoid this Warning. But then:
+# Net: Net Initialization Skipped
+# No ethernet found.
+# If CONFIG_NET=n is set additionally warning at "make s5p4418_nanopi2_defconfig":
+# arch/../configs/s5p4418_nanopi2_defconfig:24:warning: override: reassigning to symbol CMD_NET
+#
+# --> CONFIG_NET=n set only
+CONFIG_NET=n
+
+# CONFIG_CMD_NFS is not set
+CONFIG_CMD_FDISK=y
+CONFIG_CMD_EXT4_IMG_WRITE=y
+CONFIG_CMD_SD_RECOVERY=y
+CONFIG_CMD_PMIC=y
+CONFIG_CMD_REGULATOR=y
+
+CONFIG_DM_I2C_GPIO=y
+CONFIG_SYS_I2C_NEXELL=y
+CONFIG_DM_PMIC=y
+CONFIG_DM_PMIC_AXP228=y
+CONFIG_DM_REGULATOR=y
+CONFIG_DM_REGULATOR_AXP228=y
+CONFIG_DM_PWM=n
+
+CONFIG_USB=y
+CONFIG_DM_USB=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_STORAGE=y
+
+CONFIG_DISPLAY=y
+CONFIG_DM_VIDEO=y
+CONFIG_SYS_CONSOLE_BG_COL=0xff
+CONFIG_SYS_CONSOLE_FG_COL=0x00
+CONFIG_VIDEO_NX=y
+CONFIG_VIDEO_NX_RGB=y
+CONFIG_VIDEO_NX_LVDS=y
+
+CONFIG_VIDEO_NX_HDMI=y
+
+CONFIG_REGEX=y
+CONFIG_ERRNO_STR=y
+
+CONFIG_SYS_TEXT_BASE=0x74C00000
+CONFIG_SYS_RESERVE_MEM_SIZE=0x00400000
+CONFIG_NR_DRAM_BANKS=1
+
+## System initialize options (board_init_f)
+# board_init_f->init_sequence, call board_early_init_f
+CONFIG_BOARD_LATE_INIT=y
+# board_init_f->init_sequence, call print_cpuinfo
+CONFIG_DISPLAY_CPUINFO=y
+# board_init_f->init_sequence, call show_board_info
+CONFIG_DISPLAY_BOARDINFO=y
+# board_init_f, CONFIG_SYS_ICACHE_OFF
+CONFIG_SYS_DCACHE_OFF=y
+# board_init_r, call arch_misc_init
+CONFIG_ARCH_MISC_INIT=y
+
+CONFIG_BOOTDELAY=1
+CONFIG_ZERO_BOOTDELAY_CHECK=y
+
+## U-Boot Environments
+## refer to common/env_common.c
+
+# CONFIG_ENV_IS_IN_MMC must be set here and not in s5p4418_nanopi2.h
+# otherwise CONFIG_ENV_IS_NOWHERE is set by env/Kconfig and environment
+# (bootargs) are not loaded
+CONFIG_ENV_IS_IN_MMC=y
+CONFIG_ENV_OFFSET=0x2E0200
+CONFIG_ENV_SIZE=0x4000
+CONFIG_CMD_SAVEENV=y
+
+## Etc Command definition
+# image info
+CONFIG_CMD_IMI=y
+# add command line history
+CONFIG_CMDLINE_EDITING=y
+CONFIG_INITRD_TAG=y
+CONFIG_SUPPORT_RAW_INITRD=y
+CONFIG_REVISION_TAG=y
+CONFIG_CMD_BOOTZ=y
+
+## serial console configuration
+CONFIG_CONS_INDEX=0
+CONFIG_BAUDRATE=115200
+
+## SD/MMC
+CONFIG_BOUNCE_BUFFER=y
+CONFIG_GENERIC_MMC=y
+CONFIG_MMC=y
+CONFIG_MMC_DW=y
+CONFIG_NEXELL_DWMMC=y
+CONFIG_CMD_MMC=y
+CONFIG_DM_MMC=y
+
+CONFIG_DOS_PARTITION=y
+CONFIG_CMD_FAT=y
+CONFIG_FS_FAT=y
+CONFIG_FAT_WRITE=y
+
+CONFIG_CMD_EXT4=y
+CONFIG_CMD_EXT4_WRITE=y
+CONFIG_FS_EXT4=y
+CONFIG_EXT4_WRITE=y
+
+## Fastboot and USB OTG
+CONFIG_USB_FUNCTION_FASTBOOT=y
+CONFIG_CMD_FASTBOOT=y
+CONFIG_FASTBOOT_FLASH=y
+# Has been "=CONFIG_SYS_MMC_DEV" in s5p4418_nanopi2.h of U-Boot 2016
+CONFIG_FASTBOOT_FLASH_MMC_DEV=2
+CONFIG_FASTBOOT_BUF_ADDR=0x7B000000
+# Has been "=(CONFIG_SYS_MEM_SIZE - 0x2E000000)" in s5p4418_nanopi2.h of
+# U-Boot 2016
+CONFIG_FASTBOOT_BUF_SIZE=0x12000000
+
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DUALSPEED=y
+CONFIG_USB_GADGET_VBUS_DRAW=0
+CONFIG_USB_GADGET_DWC2_OTG=y
+CONFIG_USB_GADGET_NX_UDC_OTG_PHY=y
+CONFIG_USB_GADGET_DOWNLOAD=y
+CONFIG_SYS_CACHELINE_SIZE=64
+# google
+CONFIG_G_DNL_VENDOR_NUM=0x18d1
+# nexus one
+CONFIG_G_DNL_PRODUCT_NUM=0x0002
+CONFIG_G_DNL_MANUFACTURER="Nexell Corporation"
+
+## OF_CONTROL
+CONFIG_FIT_BEST_MATCH=y
+CONFIG_OF_LIBFDT=y
+CONFIG_OF_BOARD_SETUP=y
+
+## BOOTCOMMAND
+CONFIG_ROOT_DEV=1
+CONFIG_BOOT_PART=1
+CONFIG_ROOT_PART=2
+
+## Misc.
+CONFIG_S5P4418_ONEWIRE=y
+CONFIG_PWM_NX=y
+
+# necessary for if-cmd
+CONFIG_HUSH_PARSER=y
+
+# set to 'n' to save memory
+CONFIG_SYS_LONGHELP=y
+
+# uncomment for debugging (trace) of MMC-CMDs
+#CONFIG_MMC_TRACE=y
diff --git a/doc/README.s5p4418 b/doc/README.s5p4418
new file mode 100644
index 0000000..ac724d0
--- /dev/null
+++ b/doc/README.s5p4418
@@ -0,0 +1,63 @@
+
+Summary
+=======
+
+This README is about U-Boot support for SAMSUNG's/NEXELL's ARM Cortex-A9 based
+S5P4418 SoC. It is based on FriendlyARM's U-Boot v2016.01 for the NanoPi2
+(and other) boards [1].
+
+Currently the following boards are supported:
+
+* FriendlyArm NanoPi2 [2]
+* FriendlyArm NanoPC-T2 [3]
+
+
+Build
+=====
+
+* NanoPi2 and NanoPC-T2
+
+make s5p4418_nanopi2_defconfig
+make
+
+
+Installation
+============
+
+- Download Official-ROMs-SDCard-20190718.7z from [4] (images files for android,
+ friendlyCore and LUbuntu)
+- Use s5p4418-sd-lubuntu-desktop-xenial-4.4-armhf-20190718.img to make a SD-card
+- Use dd in the directory where U-Boot has been built to update U-Boot:
+ (replace <SD-card> with the device used for the SD-card, e.g. sdc)
+ sudo dd seek=3841 if=u-boot.bin of=/dev/<SD-card>
+- Boot the board from this SD-card
+
+The source code for (the used?) LUbuntu 16.04 can be found at [5].
+
+
+Links
+=====
+
+[1] FriendlyArm U-boot v2016.01:
+
+https://github.com/friendlyarm/u-boot/tree/nanopi2-v2016.01
+
+
+[2] NanoPi2:
+
+http://wiki.friendlyarm.com/wiki/index.php/NanoPi_2
+
+
+[3] NanoPC-T2:
+
+http://wiki.friendlyarm.com/wiki/index.php/NanoPC-T2
+
+
+[4] FriendlyArm image files for NanoPi2:
+
+http://download.friendlyarm.com//NanoPi2
+
+
+[5] FriendlyArm LUbuntu 16.04 Source Code for NanoPi2:
+
+https://github.com/friendlyarm/linux/tree/nanopi2-v4.4.y
diff --git a/include/configs/s5p4418_nanopi2.h b/include/configs/s5p4418_nanopi2.h
new file mode 100644
index 0000000..64a3f99
--- /dev/null
+++ b/include/configs/s5p4418_nanopi2.h
@@ -0,0 +1,270 @@
+/* SPDX-License-Identifier: GPL-2.0+
+ *
+ * Copyright (C) Guangzhou FriendlyARM Computer Tech. Co., Ltd.
+ * (http://www.friendlyarm.com)
+ *
+ * (C) Copyright 2016 Nexell
+ * Hyejung Kwon <cjscld15@nexell.co.kr>
+ *
+ * Copyright (C) 2019 Stefan Bosch <stefan_b@posteo.net>
+ */
+
+#ifndef __CONFIG_H__
+#define __CONFIG_H__
+
+#include <linux/sizes.h>
+#include <asm/arch/nexell.h>
+
+/*-----------------------------------------------------------------------
+ * System memory Configuration
+ */
+#define CONFIG_SYS_INIT_SP_ADDR CONFIG_SYS_TEXT_BASE
+#define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_TEXT_BASE
+#define CONFIG_SYS_MEM_SIZE 0x40000000
+#define CONFIG_SYS_SDRAM_BASE 0x71000000
+
+/*
+ * "(CONFIG_SYS_MEM_SIZE - CONFIG_SYS_RESERVE_MEM_SIZE)" has been used in
+ * u-boot nanopi2-v2016.01.
+ * This is not working anymore because boot_fdt_add_mem_rsv_regions() in
+ * common/image-fdt.c has been extended:
+ * Also reserved-memory sections are marked as unusable.
+ *
+ * In friendlyArm Ubuntu 16.04 source arch/arm/boot/dts/s5p4418.dtsi:
+ * reserved-memory {
+ * #address-cells = <1>;
+ * #size-cells = <1>;
+ * ranges;
+ *
+ * secure_memory at b0000000 {
+ * reg = <0xB0000000 0x1000000>;
+ * nop-map;
+ * };
+ * };
+ *
+ * arch_lmb_reserve() of arch/arm/lib/bootm.c:
+ * "Allocate space for command line and board info - ... below the current
+ * stack pointer."
+ * --> Memory allocated would overlap with "secure_memory at b0000000"
+ * --> lmb_add_region(rgn, base==0xb0000000, size==0x1000000) fails,
+ * boot output:
+ * ...
+ * Kernel image @ 0x71080000 [ 0x000000 - 0x60e628 ]
+ * ## Flattened Device Tree blob at 7a000000
+ * Booting using the fdt blob at 0x7a000000
+ * ERROR: reserving fdt memory region failed (addr=b0000000 size=1000000)
+ * Using Device Tree in place at 7a000000, end 7a00fbf0
+ *
+ * Starting kernel ...
+ * ...
+ */
+#define CONFIG_SYS_SDRAM_SIZE (0xb0000000 - CONFIG_SYS_SDRAM_BASE)
+
+#define CONFIG_SYS_MALLOC_LEN (32 * 1024 * 1024)
+
+#define BMP_LOAD_ADDR 0x78000000
+
+/* kernel load address */
+#define CONFIG_SYS_LOAD_ADDR 0x71080000
+#define INITRD_START 0x79000000
+#define KERNEL_DTB_ADDR 0x7A000000
+
+/* memtest works on */
+#define CONFIG_SYS_MEMTEST_START CONFIG_SYS_SDRAM_BASE
+#define CONFIG_SYS_MEMTEST_END ((ulong)CONFIG_SYS_SDRAM_BASE + \
+ (ulong)CONFIG_SYS_SDRAM_SIZE)
+
+/*-----------------------------------------------------------------------
+ * High Level System Configuration
+ */
+/* Not used: not need IRQ/FIQ stuff */
+#undef CONFIG_USE_IRQ
+/* decrementer freq: 1ms ticks */
+#define CONFIG_SYS_HZ 1000
+
+/*-----------------------------------------------------------------------
+ * System initialize options (board_init_f)
+ */
+/* board_init_f->init_sequence, call arch_cpu_init */
+#define CONFIG_ARCH_CPU_INIT
+
+/*-----------------------------------------------------------------------
+ * U-Boot default cmd
+ */
+#define CONFIG_CMD_MEMTEST
+
+/*-----------------------------------------------------------------------
+ * Miscellaneous configurable options
+ */
+#ifdef CONFIG_SYS_PROMPT
+#undef CONFIG_SYS_PROMPT
+/* Monitor Command Prompt */
+#define CONFIG_SYS_PROMPT "nanopi2# "
+#endif
+
+/* Console I/O Buffer Size */
+#define CONFIG_SYS_CBSIZE 1024
+/* Print Buffer Size */
+#define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE + \
+ sizeof(CONFIG_SYS_PROMPT) + 16)
+/* max number of command args */
+#define CONFIG_SYS_MAXARGS 16
+/* Boot Argument Buffer Size */
+#define CONFIG_SYS_BARGSIZE CONFIG_SYS_CBSIZE
+
+/*-----------------------------------------------------------------------
+ * allow to overwrite serial and ethaddr
+ */
+#define CONFIG_ENV_OVERWRITE
+
+#ifdef CONFIG_HUSH_PARSER
+#define CONFIG_SYS_PROMPT_HUSH_PS2 "> "
+#endif
+
+/*-----------------------------------------------------------------------
+ * Etc Command definition
+ */
+#define CONFIG_CMDLINE_TAG /* use bootargs commandline */
+
+#undef CONFIG_BOOTM_NETBSD
+#undef CONFIG_BOOTM_RTEMS
+
+/*-----------------------------------------------------------------------
+ * serial console configuration
+ */
+#define CONFIG_PL011_CLOCK 50000000
+#define CONFIG_PL01x_PORTS {(void *)PHY_BASEADDR_UART0, \
+ (void *)PHY_BASEADDR_UART1, \
+ (void *)PHY_BASEADDR_UART2, \
+ (void *)PHY_BASEADDR_UART3}
+#define CONFIG_SYS_BAUDRATE_TABLE { 9600, 19200, 38400, 57600, 115200 }
+
+/*-----------------------------------------------------------------------
+ * PLL
+ */
+#define CONFIG_SYS_PLLFIN 24000000UL
+
+/*-----------------------------------------------------------------------
+ * Timer
+ */
+#define CONFIG_TIMER_SYS_TICK_CH 0
+
+/*-----------------------------------------------------------------------
+ * BACKLIGHT
+ */
+#ifndef CONFIG_S5P4418_ONEWIRE
+/* fallback to pwm */
+#define BACKLIGHT_CH 0
+#define BACKLIGHT_DIV 0
+#define BACKLIGHT_INV 0
+#define BACKLIGHT_DUTY 50
+#define BACKLIGHT_HZ 1000
+#endif
+
+/*-----------------------------------------------------------------------
+ * SD/MMC
+ */
+#if defined(CONFIG_MMC)
+/* eMMC = 0, SD-card = 2 */
+#define CONFIG_SYS_MMC_DEV 2
+#define CONFIG_SYS_MMC_ENV_DEV CONFIG_SYS_MMC_DEV
+
+#endif
+
+/*-----------------------------------------------------------------------
+ * Default environment organization
+ */
+#if !defined(CONFIG_ENV_IS_IN_MMC) && !defined(CONFIG_ENV_IS_IN_NAND) && \
+ !defined(CONFIG_ENV_IS_IN_FLASH) && !defined(CONFIG_ENV_IS_IN_EEPROM)
+ /* default: CONFIG_ENV_IS_NOWHERE */
+ #define CONFIG_ENV_IS_NOWHERE
+ #define CONFIG_ENV_OFFSET 1024
+ #define CONFIG_ENV_SIZE (4 * 1024) /* env size */
+ /* imls - list all images found in flash, default enable so disable */
+ #undef CONFIG_CMD_IMLS
+#endif
+
+/*-----------------------------------------------------------------------
+ * VIDEO
+ */
+
+#define CONFIG_VIDEO_LOGO
+
+#define CONFIG_SPLASH_SCREEN
+
+#ifdef CONFIG_VIDEO_LOGO
+#define CONFIG_CMD_BMP
+
+#ifdef CONFIG_DM_VIDEO
+#define CONFIG_BMP_24BPP
+#endif
+
+#ifdef CONFIG_SPLASH_SCREEN
+#define CONFIG_SPLASH_SOURCE 1
+#define CONFIG_SPLASH_SCREEN_ALIGN 1
+#define SPLASH_FILE logo.bmp
+#endif
+#endif
+
+/*-----------------------------------------------------------------------
+ * ENV
+ */
+#define BLOADER_MMC \
+ "ext4load mmc ${rootdev}:${bootpart} "
+
+#ifdef CONFIG_OF_BOARD_SETUP
+#define EXTRA_ENV_DTB_RESERVE \
+ "dtb_reserve=" \
+ "if test -n \"$dtb_addr\"; then fdt addr $dtb_addr; fi\0"
+#else
+#define EXTRA_ENV_DTB_RESERVE \
+ "dtb_reserve=" \
+ "if test -n \"$fb_addr\"; then " \
+ "fdt addr $dtb_addr;" \
+ "fdt resize;" \
+ "fdt mk /reserved-memory display_reserved;" \
+ "fdt set /reserved-memory/display_reserved " \
+ "reg <$fb_addr 0x800000>;" \
+ "fi;\0"
+#endif
+
+#ifdef CONFIG_SPLASH_SCREEN
+#define EXTRA_ENV_BOOT_LOGO \
+ "splashimage=" __stringify(BMP_LOAD_ADDR)"\0" \
+ "splashfile=" __stringify(SPLASH_FILE)"\0" \
+ "splashpos=m,m\0" \
+ "fb_addr=\0" \
+ EXTRA_ENV_DTB_RESERVE
+#else
+ #define EXTRA_ENV_BOOT_LOGO EXTRA_ENV_DTB_RESERVE
+#endif
+
+#define CONFIG_EXTRA_ENV_SETTINGS \
+ "fdt_high=0xffffffff\0" \
+ "initrd_high=0xffffffff\0" \
+ "rootdev=" __stringify(CONFIG_ROOT_DEV) "\0" \
+ "rootpart=" __stringify(CONFIG_ROOT_PART) "\0" \
+ "bootpart=" __stringify(CONFIG_BOOT_PART) "\0" \
+ "kernel=zImage\0" \
+ "loadaddr=" __stringify(CONFIG_SYS_LOAD_ADDR) "\0" \
+ "dtb_name=s5p4418-nanopi2-rev01.dtb\0" \
+ "dtb_addr=" __stringify(KERNEL_DTB_ADDR) "\0" \
+ "initrd_name=ramdisk.img\0" \
+ "initrd_addr=" __stringify(INITRD_START) "\0" \
+ "initrd_size=0x600000\0" \
+ "load_dtb=" \
+ BLOADER_MMC "${dtb_addr} ${dtb_name}; " \
+ "run dtb_reserve\0" \
+ "load_kernel=" \
+ BLOADER_MMC "${loadaddr} ${kernel}\0" \
+ "load_initrd=" \
+ BLOADER_MMC "${initrd_addr} ${initrd_name}; " \
+ "setenv initrd_size 0x${filesize}\0" \
+ "mmcboot=" \
+ "run load_kernel; run load_initrd; run load_dtb; " \
+ "bootz ${loadaddr} ${initrd_addr}:${initrd_size} " \
+ "${dtb_addr}\0" \
+ "bootcmd=run mmcboot\0" \
+ EXTRA_ENV_BOOT_LOGO
+
+#endif /* __CONFIG_H__ */
--
1.9.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH 03/10] i2c: mmc: add nexell driver (gpio, i2c, mmc, pwm)
2020-02-03 20:40 ` [RFC PATCH 03/10] i2c: mmc: add nexell driver (gpio, i2c, mmc, pwm) Stefan Bosch
@ 2020-02-04 6:58 ` Heiko Schocher
2020-02-04 18:29 ` Stefan B.
2020-02-20 17:49 ` Stefan B.
0 siblings, 2 replies; 19+ messages in thread
From: Heiko Schocher @ 2020-02-04 6:58 UTC (permalink / raw)
To: u-boot
Hello Stefan,
Am 03.02.2020 um 21:40 schrieb Stefan Bosch:
> Changes in relation to FriendlyARM's U-Boot nanopi2-v2016.01:
> - i2c/nx_i2c.c: Some adaptions mainly because of changes in
> "struct udevice".
> - mmc: nexell_dw_mmc.c changed to nexell_dw_mmc_dm.c (switched to DM).
>
> Signed-off-by: Stefan Bosch <stefan_b@posteo.net>
> ---
>
> drivers/gpio/Kconfig | 9 +
> drivers/gpio/Makefile | 1 +
> drivers/gpio/nx_gpio.c | 252 +++++++++++++++++++
> drivers/i2c/Kconfig | 9 +
> drivers/i2c/Makefile | 1 +
> drivers/i2c/nx_i2c.c | 537 +++++++++++++++++++++++++++++++++++++++++
> drivers/mmc/Kconfig | 6 +
> drivers/mmc/Makefile | 1 +
> drivers/mmc/nexell_dw_mmc_dm.c | 350 +++++++++++++++++++++++++++
> drivers/pwm/Makefile | 1 +
> drivers/pwm/pwm-nexell.c | 252 +++++++++++++++++++
> drivers/pwm/pwm-nexell.h | 54 +++++
Could you please split this patch into 4 parts (i2c, gpio, mmc and
pwm) ?
Thanks!
> 12 files changed, 1473 insertions(+)
> create mode 100644 drivers/gpio/nx_gpio.c
> create mode 100644 drivers/i2c/nx_i2c.c
> create mode 100644 drivers/mmc/nexell_dw_mmc_dm.c
> create mode 100644 drivers/pwm/pwm-nexell.c
> create mode 100644 drivers/pwm/pwm-nexell.h
>
[...]
> diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
> index 449046b..e3340de 100644
> --- a/drivers/gpio/Makefile
> +++ b/drivers/gpio/Makefile
> @@ -65,3 +65,4 @@ obj-$(CONFIG_PM8916_GPIO) += pm8916_gpio.o
> obj-$(CONFIG_MT7621_GPIO) += mt7621_gpio.o
> obj-$(CONFIG_MSCC_SGPIO) += mscc_sgpio.o
> obj-$(CONFIG_SIFIVE_GPIO) += sifive-gpio.o
> +obj-$(CONFIG_NX_GPIO) += nx_gpio.o
Please keep lists sorted.
> diff --git a/drivers/gpio/nx_gpio.c b/drivers/gpio/nx_gpio.c
> new file mode 100644
> index 0000000..86472f6
> --- /dev/null
> +++ b/drivers/gpio/nx_gpio.c
> @@ -0,0 +1,252 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * (C) Copyright 2016 Nexell
> + * DeokJin, Lee <truevirtue@nexell.co.kr>
> + */
> +
> +#include <common.h>
> +#include <dm.h>
> +#include <errno.h>
> +#include <malloc.h>
> +#include <fdtdec.h>
> +#include <asm/io.h>
> +#include <asm/gpio.h>
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +struct nx_gpio_regs {
> + u32 data; /* Data register */
> + u32 outputenb; /* Output Enable register */
> + u32 detmode[2]; /* Detect Mode Register */
> + u32 intenb; /* Interrupt Enable Register */
> + u32 det; /* Event Detect Register */
> + u32 pad; /* Pad Status Register */
> +};
> +
> +struct nx_alive_gpio_regs {
> + u32 pwrgate; /* Power Gating Register */
> + u32 reserved0[28]; /* Reserved0 */
> + u32 outputenb_reset;/* Alive GPIO Output Enable Reset Register */
> + u32 outputenb; /* Alive GPIO Output Enable Register */
> + u32 outputenb_read; /* Alive GPIO Output Read Register */
> + u32 reserved1[3]; /* Reserved1 */
> + u32 pad_reset; /* Alive GPIO Output Reset Register */
> + u32 data; /* Alive GPIO Output Register */
> + u32 pad_read; /* Alive GPIO Pad Read Register */
> + u32 reserved2[33]; /* Reserved2 */
> + u32 pad; /* Alive GPIO Input Value Register */
> +};
> +
> +struct nx_gpio_platdata {
> + void *regs;
> + int gpio_count;
> + const char *bank_name;
> +};
> +
> +static int nx_alive_gpio_is_check(struct udevice *dev)
> +{
> + struct nx_gpio_platdata *plat = dev_get_platdata(dev);
> + const char *bank_name = plat->bank_name;
> +
> + if (!strcmp(bank_name, "gpio_alv"))
> + return 1;
> +
> + return 0;
> +}
> +
> +static int nx_alive_gpio_direction_input(struct udevice *dev, unsigned int pin)
> +{
> + struct nx_gpio_platdata *plat = dev_get_platdata(dev);
> + struct nx_alive_gpio_regs *const regs = plat->regs;
> +
> + setbits_le32(®s->outputenb_reset, 1 << pin);
> +
> + return 0;
> +}
> +
> +static int nx_alive_gpio_direction_output(struct udevice *dev, unsigned int pin,
> + int val)
> +{
> + struct nx_gpio_platdata *plat = dev_get_platdata(dev);
> + struct nx_alive_gpio_regs *const regs = plat->regs;
> +
> + if (val)
> + setbits_le32(®s->data, 1 << pin);
> + else
> + setbits_le32(®s->pad_reset, 1 << pin);
> +
> + setbits_le32(®s->outputenb, 1 << pin);
> +
> + return 0;
> +}
> +
> +static int nx_alive_gpio_get_value(struct udevice *dev, unsigned int pin)
> +{
> + struct nx_gpio_platdata *plat = dev_get_platdata(dev);
> + struct nx_alive_gpio_regs *const regs = plat->regs;
> + unsigned int mask = 1UL << pin;
> + unsigned int value;
> +
> + value = (readl(®s->pad_read) & mask) >> pin;
> +
> + return value;
> +}
> +
> +static int nx_alive_gpio_set_value(struct udevice *dev, unsigned int pin,
> + int val)
> +{
> + struct nx_gpio_platdata *plat = dev_get_platdata(dev);
> + struct nx_alive_gpio_regs *const regs = plat->regs;
> +
> + if (val)
> + setbits_le32(®s->data, 1 << pin);
> + else
> + clrbits_le32(®s->pad_reset, 1 << pin);
> +
> + return 0;
> +}
> +
> +static int nx_alive_gpio_get_function(struct udevice *dev, unsigned int pin)
> +{
> + struct nx_gpio_platdata *plat = dev_get_platdata(dev);
> + struct nx_alive_gpio_regs *const regs = plat->regs;
> + unsigned int mask = (1UL << pin);
> + unsigned int output;
> +
> + output = readl(®s->outputenb_read) & mask;
> +
> + if (output)
> + return GPIOF_OUTPUT;
> + else
> + return GPIOF_INPUT;
> +}
> +
> +static int nx_gpio_direction_input(struct udevice *dev, unsigned int pin)
> +{
> + struct nx_gpio_platdata *plat = dev_get_platdata(dev);
> + struct nx_gpio_regs *const regs = plat->regs;
> +
> + if (nx_alive_gpio_is_check(dev))
> + return nx_alive_gpio_direction_input(dev, pin);
> +
> + clrbits_le32(®s->outputenb, 1 << pin);
> +
> + return 0;
> +}
> +
> +static int nx_gpio_direction_output(struct udevice *dev, unsigned int pin,
> + int val)
> +{
> + struct nx_gpio_platdata *plat = dev_get_platdata(dev);
> + struct nx_gpio_regs *const regs = plat->regs;
> +
> + if (nx_alive_gpio_is_check(dev))
> + return nx_alive_gpio_direction_output(dev, pin, val);
> +
> + if (val)
> + setbits_le32(®s->data, 1 << pin);
> + else
> + clrbits_le32(®s->data, 1 << pin);
> +
> + setbits_le32(®s->outputenb, 1 << pin);
> +
> + return 0;
> +}
> +
> +static int nx_gpio_get_value(struct udevice *dev, unsigned int pin)
> +{
> + struct nx_gpio_platdata *plat = dev_get_platdata(dev);
> + struct nx_gpio_regs *const regs = plat->regs;
> + unsigned int mask = 1UL << pin;
> + unsigned int value;
> +
> + if (nx_alive_gpio_is_check(dev))
> + return nx_alive_gpio_get_value(dev, pin);
> +
> + value = (readl(®s->pad) & mask) >> pin;
> +
> + return value;
> +}
> +
> +static int nx_gpio_set_value(struct udevice *dev, unsigned int pin, int val)
> +{
> + struct nx_gpio_platdata *plat = dev_get_platdata(dev);
> + struct nx_gpio_regs *const regs = plat->regs;
> +
> + if (nx_alive_gpio_is_check(dev))
> + return nx_alive_gpio_set_value(dev, pin, val);
> +
> + if (val)
> + setbits_le32(®s->data, 1 << pin);
> + else
> + clrbits_le32(®s->data, 1 << pin);
> +
> + return 0;
> +}
> +
> +static int nx_gpio_get_function(struct udevice *dev, unsigned int pin)
> +{
> + struct nx_gpio_platdata *plat = dev_get_platdata(dev);
> + struct nx_gpio_regs *const regs = plat->regs;
> + unsigned int mask = (1UL << pin);
> + unsigned int output;
> +
> + if (nx_alive_gpio_is_check(dev))
> + return nx_alive_gpio_get_function(dev, pin);
> +
> + output = readl(®s->outputenb) & mask;
> +
> + if (output)
> + return GPIOF_OUTPUT;
> + else
> + return GPIOF_INPUT;
> +}
> +
> +static int nx_gpio_probe(struct udevice *dev)
> +{
> + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
> + struct nx_gpio_platdata *plat = dev_get_platdata(dev);
> +
> + uc_priv->gpio_count = plat->gpio_count;
> + uc_priv->bank_name = plat->bank_name;
> +
> + return 0;
> +}
> +
> +static int nx_gpio_ofdata_to_platdata(struct udevice *dev)
> +{
> + struct nx_gpio_platdata *plat = dev_get_platdata(dev);
> +
> + plat->regs = map_physmem(devfdt_get_addr(dev),
> + sizeof(struct nx_gpio_regs),
> + MAP_NOCACHE);
> + plat->gpio_count = fdtdec_get_int(gd->fdt_blob, dev->node.of_offset,
> + "nexell,gpio-bank-width", 32);
> + plat->bank_name = fdt_getprop(gd->fdt_blob, dev->node.of_offset,
> + "gpio-bank-name", NULL);
> +
> + return 0;
> +}
> +
> +static const struct dm_gpio_ops nx_gpio_ops = {
> + .direction_input = nx_gpio_direction_input,
> + .direction_output = nx_gpio_direction_output,
> + .get_value = nx_gpio_get_value,
> + .set_value = nx_gpio_set_value,
> + .get_function = nx_gpio_get_function,
> +};
> +
> +static const struct udevice_id nx_gpio_ids[] = {
> + { .compatible = "nexell,nexell-gpio" },
> + { }
> +};
> +
> +U_BOOT_DRIVER(nx_gpio) = {
> + .name = "nx_gpio",
> + .id = UCLASS_GPIO,
> + .of_match = nx_gpio_ids,
> + .ops = &nx_gpio_ops,
> + .ofdata_to_platdata = nx_gpio_ofdata_to_platdata,
> + .platdata_auto_alloc_size = sizeof(struct nx_gpio_platdata),
> + .probe = nx_gpio_probe,
> +};
> diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
> index 03d2fed..2cd0ed3 100644
> --- a/drivers/i2c/Kconfig
> +++ b/drivers/i2c/Kconfig
> @@ -317,6 +317,15 @@ config SYS_MXC_I2C8_SLAVE
> MXC I2C8 Slave
> endif
>
> +config SYS_I2C_NEXELL
> + bool "Nexell I2C driver"
> + depends on DM_I2C
> + help
> + Add support for the Nexell I2C driver. This is used with various
> + Nexell parts such as S5Pxx18 series SoCs. All chips
> + have several I2C ports and all are provided, controlled by the
> + device tree.
> +
> config SYS_I2C_OMAP24XX
> bool "TI OMAP2+ I2C driver"
> depends on ARCH_OMAP2PLUS || ARCH_K3
> diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
> index f5a471f..64b8ead 100644
> --- a/drivers/i2c/Makefile
> +++ b/drivers/i2c/Makefile
> @@ -26,6 +26,7 @@ obj-$(CONFIG_SYS_I2C_LPC32XX) += lpc32xx_i2c.o
> obj-$(CONFIG_SYS_I2C_MESON) += meson_i2c.o
> obj-$(CONFIG_SYS_I2C_MVTWSI) += mvtwsi.o
> obj-$(CONFIG_SYS_I2C_MXC) += mxc_i2c.o
> +obj-$(CONFIG_SYS_I2C_NEXELL) += nx_i2c.o
> obj-$(CONFIG_SYS_I2C_OMAP24XX) += omap24xx_i2c.o
> obj-$(CONFIG_SYS_I2C_RCAR_I2C) += rcar_i2c.o
> obj-$(CONFIG_SYS_I2C_RCAR_IIC) += rcar_iic.o
> diff --git a/drivers/i2c/nx_i2c.c b/drivers/i2c/nx_i2c.c
> new file mode 100644
> index 0000000..a3eec6c
> --- /dev/null
> +++ b/drivers/i2c/nx_i2c.c
> @@ -0,0 +1,537 @@
> +#include <common.h>
> +#include <errno.h>
> +#include <dm.h>
> +#include <i2c.h>
> +#include <asm/arch/nexell.h>
> +#include <asm/arch/reset.h>
> +#include <asm/arch/clk.h>
> +#include <asm/arch/nx_gpio.h>
> +
> +#define I2C_WRITE 0
> +#define I2C_READ 1
> +
> +#define I2C_OK 0
> +#define I2C_NOK 1
> +#define I2C_NACK 2
> +#define I2C_NOK_LA 3 /* Lost arbitration */
> +#define I2C_NOK_TOUT 4 /* time out */
> +
> +#define I2CLC_FILTER 0x04 /* SDA filter on*/
> +#define I2CSTAT_BSY 0x20 /* Busy bit */
> +#define I2CSTAT_NACK 0x01 /* Nack bit */
> +#define I2CSTAT_ABT 0x08 /* Arbitration bit */
> +#define I2CCON_ACKGEN 0x80 /* Acknowledge generation */
> +#define I2CCON_IRENB 0x20 /* Interrupt Enable bit */
> +#define I2CCON_IRPND 0x10 /* Interrupt pending bit */
> +#define I2C_MODE_MT 0xC0 /* Master Transmit Mode */
> +#define I2C_MODE_MR 0x80 /* Master Receive Mode */
> +#define I2C_START_STOP 0x20 /* START / STOP */
> +#define I2C_TXRX_ENA 0x10 /* I2C Tx/Rx enable */
> +
> +#define I2C_TIMEOUT_MS 10 /* 10 ms */
> +
> +#define I2C_M_NOSTOP 0x100
> +
> +#ifndef CONFIG_MAX_I2C_NUM
> +#define CONFIG_MAX_I2C_NUM 3
> +#endif
Is this really configurable? If so, I do not find the Kconfig
description.
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +struct nx_i2c_regs {
> + uint iiccon;
> + uint iicstat;
> + uint iicadd;
> + uint iicds;
> + uint iiclc;
> +};
> +
> +struct nx_i2c_bus {
> + uint bus_num;
> + struct nx_i2c_regs *regs;
> + uint speed;
> + uint target_speed;
> + uint sda_delay;
> +};
> +
> +/* s5pxx18 i2c must be reset before enabled */
> +static void i2c_reset(int ch)
> +{
> + int rst_id = RESET_ID_I2C0 + ch;
> +
> + nx_rstcon_setrst(rst_id, 0);
> + nx_rstcon_setrst(rst_id, 1);
> +}
> +
> +/* FIXME : this func will be removed after reset dm driver ported.
> + * set mmc pad alternative func.
> + */
> +static void set_i2c_pad_func(struct nx_i2c_bus *i2c)
> +{
> + switch (i2c->bus_num) {
> + case 0:
> + nx_gpio_set_pad_function(3, 2, 1);
> + nx_gpio_set_pad_function(3, 3, 1);
> + break;
> + case 1:
> + nx_gpio_set_pad_function(3, 4, 1);
> + nx_gpio_set_pad_function(3, 5, 1);
> + break;
> + case 2:
> + nx_gpio_set_pad_function(3, 6, 1);
> + nx_gpio_set_pad_function(3, 7, 1);
> + break;
> + }
> +}
Hmm... may this should be moved into a seperate pincontrol driver?
> +
> +static uint i2c_get_clkrate(struct nx_i2c_bus *bus)
> +{
> + struct clk *clk;
> + int index = bus->bus_num;
> + char name[50] = {0, };
?
> +
> + sprintf(name, "%s.%d", DEV_NAME_I2C, index);
Where is DEV_NAME_I2C defined ?
> + clk = clk_get((const char *)name);
> + if (!clk)
> + return -1;
> +
> + return clk_get_rate(clk);
> +}
> +
> +static uint i2c_set_clk(struct nx_i2c_bus *bus, uint enb)
> +{
> + struct clk *clk;
> + char name[50];
> +
> + sprintf(name, "%s.%d", DEV_NAME_I2C, bus->bus_num);
> + clk = clk_get((const char *)name);
> + if (!clk)
> + return -1;
> +
> + if (enb) {
> + clk_disable(clk);
> + clk_enable(clk);
> + } else {
> + clk_disable(clk);
> + }
> +
> + return 0;
> +}
> +
> +/* get i2c module number from base address */
> +static uint i2c_get_busnum(struct nx_i2c_bus *bus)
> +{
> + void *base_addr = (void *)PHY_BASEADDR_I2C0;
> + int i;
> +
> + for (i = 0; i < CONFIG_MAX_I2C_NUM; i++) {
> + if (base_addr == ((void *)bus->regs)) {
> + bus->bus_num = i;
> + return i;
> + }
> + base_addr += 0x1000;
> + }
> +
> + return -1;
return -ENODEV;
Hmm... is there no chance to use seq from struct udevice
https://gitlab.denx.de/u-boot/u-boot/blob/master/include/dm/device.h#L152
?
For example like:
https://gitlab.denx.de/u-boot/u-boot/blob/master/drivers/i2c/mxc_i2c.c#L895
> +}
> +
> +/* Set SDA line delay */
> +static int nx_i2c_set_sda_delay(struct nx_i2c_bus *bus, ulong clkin)
> +{
> + struct nx_i2c_regs *i2c = bus->regs;
> + uint sda_delay = 0;
> +
> + if (bus->sda_delay) {
> + sda_delay = clkin * bus->sda_delay;
> + sda_delay = DIV_ROUND_UP(sda_delay, 1000000);
> + sda_delay = DIV_ROUND_UP(sda_delay, 5);
> + if (sda_delay > 3)
> + sda_delay = 3;
> + sda_delay |= I2CLC_FILTER;
> + } else {
> + sda_delay = 0;
> + }
> +
> + sda_delay &= 0x7;
> + writel(sda_delay, &i2c->iiclc);
> +
> + return 0;
> +}
> +
> +/* Calculate the value of the divider and prescaler, set the bus speed. */
> +static int nx_i2c_set_bus_speed(struct udevice *dev, uint speed)
> +{
> + struct nx_i2c_bus *bus = dev_get_priv(dev);
> + struct nx_i2c_regs *i2c = bus->regs;
> + unsigned long freq, pres = 16, div;
> +
> + freq = i2c_get_clkrate(bus);
> + /* calculate prescaler and divisor values */
> + if ((freq / pres / (16 + 1)) > speed)
> + /* set prescaler to 512 */
> + pres = 512;
> +
> + div = 0;
> + while ((freq / pres / (div + 1)) > speed)
> + div++;
> +
> + /* set prescaler, divisor according to freq, also set ACKGEN, IRQ */
> + writel((div & 0x0F) | ((pres == 512) ? 0x40 : 0), &i2c->iiccon);
> +
> + /* init to SLAVE REVEIVE and set slaveaddr */
> + writel(0, &i2c->iicstat);
> + writel(0x00, &i2c->iicadd);
> + /* program Master Transmit (and implicit STOP) */
> + writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat);
> +
> + bus->speed = bus->target_speed / (div * pres);
Do you want to allow all values of speeds or may you want to use
standard speeds, see:
https://gitlab.denx.de/u-boot/u-boot/blob/master/include/i2c.h#L33
> +
> + return 0;
> +}
> +
> +static void nx_i2c_set_clockrate(struct udevice *dev, uint speed)
> +{
> + struct nx_i2c_bus *bus = dev_get_priv(dev);
> + ulong clkin;
> +
> + nx_i2c_set_bus_speed(dev, speed);
> + clkin = bus->speed; /* the actual i2c speed */
> + clkin /= 1000; /* clkin now in Khz */
> + nx_i2c_set_sda_delay(bus, clkin);
> +}
> +
> +static void i2c_process_node(struct udevice *dev)
> +{
> + struct nx_i2c_bus *bus = dev_get_priv(dev);
> + const void *blob = gd->fdt_blob;
> +
> + int node;
> +
> + node = dev->node.of_offset;
> +
> + bus->target_speed = fdtdec_get_int(blob, node,
> + "nexell,i2c-max-bus-freq", 0);
> + bus->sda_delay = fdtdec_get_int(blob, node,
> + "nexell,i2c-sda-delay", 0);
You introdue here new properties, please document them in
u-boot:/doc/device-tree-bindings/i2c
Please without "nexell,"
Do you plan to post also a linux i2c driver?
If so, the devicetree bindings should be discussed there to avoid
different properties between U-Boot and linux!
> +}
> +
> +static int nx_i2c_probe(struct udevice *dev)
> +{
> + struct nx_i2c_bus *bus = dev_get_priv(dev);
> +
> + /* get regs */
> + bus->regs = (struct nx_i2c_regs *)devfdt_get_addr(dev);
> + /* calc index */
> + if (!i2c_get_busnum(bus)) {
> + debug("not found i2c number!\n");
> + return -1;
please return -ENODEV
> + }
> +
> + /* i2c optional node parsing */
> + i2c_process_node(dev);
> + if (!bus->target_speed)
> + return -1;
please return here also an errorcode from include/linux/errno.h
Hmm.. if you return here if target_speed is not set, it is not optional!
> +
> + /* reset */
> + i2c_reset(bus->bus_num);
> + /* gpio pad */
> + set_i2c_pad_func(bus);
> +
> + /* clock rate */
> + i2c_set_clk(bus, 1);
> + nx_i2c_set_clockrate(dev, bus->target_speed);
> + i2c_set_clk(bus, 0);
> +
> + return 0;
> +}
> +
> +/* i2c bus busy check */
> +static int i2c_is_busy(struct nx_i2c_regs *i2c)
> +{
> + ulong start_time;
> +
> + start_time = get_timer(0);
> + while (readl(&i2c->iicstat) & I2CSTAT_BSY) {
> + if (get_timer(start_time) > I2C_TIMEOUT_MS) {
> + debug("Timeout\n");
> + return -I2C_NOK_TOUT;
> + }
> + }
> + return 0;
> +}
> +
> +/* irq enable/disable functions */
> +static void i2c_enable_irq(struct nx_i2c_regs *i2c)
> +{
> + unsigned int reg;
> +
> + reg = readl(&i2c->iiccon);
> + reg |= I2CCON_IRENB;
> + writel(reg, &i2c->iiccon);
> +}
> +
> +/* irq clear function */
> +static void i2c_clear_irq(struct nx_i2c_regs *i2c)
> +{
> + clrbits_le32(&i2c->iiccon, I2CCON_IRPND);
> +}
> +
> +/* ack enable functions */
> +static void i2c_enable_ack(struct nx_i2c_regs *i2c)
> +{
> + unsigned int reg;
> +
> + reg = readl(&i2c->iiccon);
> + reg |= I2CCON_ACKGEN;
> + writel(reg, &i2c->iiccon);
> +}
> +
> +static void i2c_send_stop(struct nx_i2c_regs *i2c)
> +{
> + unsigned int reg;
> +
> + /* Send STOP. */
> + reg = readl(&i2c->iicstat);
> + reg |= I2C_MODE_MR | I2C_TXRX_ENA;
> + reg &= (~I2C_START_STOP);
> + writel(reg, &i2c->iicstat);
> + i2c_clear_irq(i2c);
> +}
> +
> +static int wait_for_xfer(struct nx_i2c_regs *i2c)
> +{
> + unsigned long start_time = get_timer(0);
> +
> + do {
> + if (readl(&i2c->iiccon) & I2CCON_IRPND)
> + return (readl(&i2c->iicstat) & I2CSTAT_NACK) ?
> + I2C_NACK : I2C_OK;
> + } while (get_timer(start_time) < I2C_TIMEOUT_MS);
> +
> + return I2C_NOK_TOUT;
> +}
> +
> +static int i2c_transfer(struct nx_i2c_regs *i2c,
> + uchar cmd_type,
> + uchar chip,
> + uchar addr[],
> + uchar addr_len,
> + uchar data[],
> + unsigned short data_len,
> + uint seq)
> +{
> + uint status;
> + int i = 0, result;
> +
> + if (data == 0 || data_len == 0) {
> + /*Don't support data transfer of no length or to address 0 */
> + debug("%s: bad call\n", __func__);
> + return I2C_NOK;
> + }
> +
> + i2c_enable_irq(i2c);
> + i2c_enable_ack(i2c);
> +
> + /* Get the slave chip address going */
> + writel(chip, &i2c->iicds);
> + status = I2C_TXRX_ENA | I2C_START_STOP;
> + if (cmd_type == I2C_WRITE || (addr && addr_len))
> + status |= I2C_MODE_MT;
> + else
> + status |= I2C_MODE_MR;
> + writel(status, &i2c->iicstat);
> + if (seq)
> + i2c_clear_irq(i2c);
> +
> + /* Wait for chip address to transmit. */
> + result = wait_for_xfer(i2c);
> + if (result != I2C_OK)
> + goto bailout;
> +
> + /* If register address needs to be transmitted - do it now. */
> + if (addr && addr_len) { /* register addr */
> + while ((i < addr_len) && (result == I2C_OK)) {
> + writel(addr[i++], &i2c->iicds);
> + i2c_clear_irq(i2c);
> + result = wait_for_xfer(i2c);
> + }
> +
> + i = 0;
> + if (result != I2C_OK)
> + goto bailout;
> + }
> +
> + switch (cmd_type) {
> + case I2C_WRITE:
> + while ((i < data_len) && (result == I2C_OK)) {
> + writel(data[i++], &i2c->iicds);
> + i2c_clear_irq(i2c);
> + result = wait_for_xfer(i2c);
> + }
> + break;
> + case I2C_READ:
> + if (addr && addr_len) {
> + /*
> + * Register address has been sent, now send slave chip
> + * address again to start the actual read transaction.
> + */
> + writel(chip, &i2c->iicds);
> +
> + /* Generate a re-START. */
> + writel(I2C_MODE_MR | I2C_TXRX_ENA
> + | I2C_START_STOP, &i2c->iicstat);
> + i2c_clear_irq(i2c);
> + result = wait_for_xfer(i2c);
> + if (result != I2C_OK)
> + goto bailout;
> + }
> +
> + while ((i < data_len) && (result == I2C_OK)) {
> + /* disable ACK for final READ */
> + if (i == data_len - 1)
> + clrbits_le32(&i2c->iiccon
> + , I2CCON_ACKGEN);
> +
> + i2c_clear_irq(i2c);
> + result = wait_for_xfer(i2c);
> + data[i++] = readb(&i2c->iicds);
> + }
> +
> + if (result == I2C_NACK)
> + result = I2C_OK; /* Normal terminated read. */
> + break;
> +
> + default:
> + debug("%s: bad call\n", __func__);
> + result = I2C_NOK;
> + break;
> + }
> +
> +bailout:
> + return result;
> +}
> +
> +static int nx_i2c_read(struct udevice *dev, uchar chip, uint addr,
> + uint alen, uchar *buffer, uint len, uint seq)
> +{
> + struct nx_i2c_bus *i2c;
> + uchar xaddr[4];
> + int ret;
> +
> + i2c = dev_get_priv(dev);
> + if (!i2c)
> + return -EFAULT;
> +
> + if (alen > 4) {
> + debug("I2C read: addr len %d not supported\n", alen);
> + return -EADDRNOTAVAIL;
> + }
> +
> + if (alen > 0)
> + xaddr[0] = (addr >> 24) & 0xFF;
> +
> + if (alen > 0) {
> + xaddr[0] = (addr >> 24) & 0xFF;
> + xaddr[1] = (addr >> 16) & 0xFF;
> + xaddr[2] = (addr >> 8) & 0xFF;
> + xaddr[3] = addr & 0xFF;
> + }
> +
> + ret = i2c_transfer(i2c->regs, I2C_READ, chip << 1,
> + &xaddr[4 - alen], alen, buffer, len, seq);
> +
> + if (ret) {
> + debug("I2C read failed %d\n", ret);
> + return -EIO;
> + }
> +
> + return 0;
> +}
> +
> +static int nx_i2c_write(struct udevice *dev, uchar chip, uint addr,
> + uint alen, uchar *buffer, uint len, uint seq)
> +{
> + struct nx_i2c_bus *i2c;
> + uchar xaddr[4];
> + int ret;
> +
> + i2c = dev_get_priv(dev);
> + if (!i2c)
> + return -EFAULT;
> +
> + if (alen > 4) {
> + debug("I2C write: addr len %d not supported\n", alen);
> + return -EINVAL;
> + }
> +
> + if (alen > 0) {
> + xaddr[0] = (addr >> 24) & 0xFF;
> + xaddr[1] = (addr >> 16) & 0xFF;
> + xaddr[2] = (addr >> 8) & 0xFF;
> + xaddr[3] = addr & 0xFF;
> + }
> +
> + ret = i2c_transfer(i2c->regs, I2C_WRITE, chip << 1,
> + &xaddr[4 - alen], alen, buffer, len, seq);
> + if (ret) {
> + debug("I2C write failed %d\n", ret);
> + return -EIO;
> + }
> +
> + return 0;
> +}
> +
> +static int nx_i2c_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs)
> +{
> + struct nx_i2c_bus *bus = dev_get_priv(dev);
> + struct nx_i2c_regs *i2c = bus->regs;
> + int ret;
> + int i;
> +
> + /* The power loss by the clock, only during on/off. */
> + i2c_set_clk(bus, 1);
> +
> + /* Bus State(Busy) check */
> + ret = i2c_is_busy(i2c);
> + if (ret < 0)
> + return ret;
> +
> + for (i = 0; i < nmsgs; msg++, i++) {
> + if (msg->flags & I2C_M_RD) {
> + ret = nx_i2c_read(dev, msg->addr, 0, 0, msg->buf,
> + msg->len, i);
> + } else {
> + ret = nx_i2c_write(dev, msg->addr, 0, 0, msg->buf,
> + msg->len, i);
> + }
> +
> + if (ret) {
> + debug("i2c_xfer: error sending\n");
> + return -EREMOTEIO;
> + }
> + }
> + /* Send Stop */
> + i2c_send_stop(i2c);
> + i2c_set_clk(bus, 0);
> +
> + return ret ? -EREMOTEIO : 0;
> +};
> +
> +static const struct dm_i2c_ops nx_i2c_ops = {
> + .xfer = nx_i2c_xfer,
> + .set_bus_speed = nx_i2c_set_bus_speed,
> +};
> +
> +static const struct udevice_id nx_i2c_ids[] = {
> + { .compatible = "nexell,s5pxx18-i2c" },
Same here as for the new properties. Please discuss the names on
devicetree at vger.kernel.org <devicetree@vger.kernel.org>
first!
> + { }
> +};
> +
> +U_BOOT_DRIVER(i2c_nexell) = {
> + .name = "i2c_nexell",
> + .id = UCLASS_I2C,
> + .of_match = nx_i2c_ids,
> + .probe = nx_i2c_probe,
> + .priv_auto_alloc_size = sizeof(struct nx_i2c_bus),
> + .ops = &nx_i2c_ops,
> +};
bye,
Heiko
> diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
> index 2f0eedc..bb8e7c0 100644
> --- a/drivers/mmc/Kconfig
> +++ b/drivers/mmc/Kconfig
> @@ -253,6 +253,12 @@ config MMC_DW_SNPS
> This selects support for Synopsys DesignWare Memory Card Interface driver
> extensions used in various Synopsys ARC devboards.
>
> +config NEXELL_DWMMC
> + bool "Nexell SD/MMC controller support"
> + depends on ARCH_NEXELL
> + depends on MMC_DW
> + default y
> +
> config MMC_MESON_GX
> bool "Meson GX EMMC controller support"
> depends on DM_MMC && BLK && ARCH_MESON
> diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
> index 9c1f8e5..a7b5a7b 100644
> --- a/drivers/mmc/Makefile
> +++ b/drivers/mmc/Makefile
> @@ -43,6 +43,7 @@ obj-$(CONFIG_SH_MMCIF) += sh_mmcif.o
> obj-$(CONFIG_SH_SDHI) += sh_sdhi.o
> obj-$(CONFIG_STM32_SDMMC2) += stm32_sdmmc2.o
> obj-$(CONFIG_JZ47XX_MMC) += jz_mmc.o
> +obj-$(CONFIG_NEXELL_DWMMC) += nexell_dw_mmc_dm.o
>
> # SDHCI
> obj-$(CONFIG_MMC_SDHCI) += sdhci.o
> diff --git a/drivers/mmc/nexell_dw_mmc_dm.c b/drivers/mmc/nexell_dw_mmc_dm.c
> new file mode 100644
> index 0000000..b06b60d
> --- /dev/null
> +++ b/drivers/mmc/nexell_dw_mmc_dm.c
> @@ -0,0 +1,350 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * (C) Copyright 2016 Nexell
> + * Youngbok, Park <park@nexell.co.kr>
> + *
> + * (C) Copyright 2019 Stefan Bosch <stefan_b@posteo.net>
> + */
> +
> +#include <common.h>
> +#include <clk.h>
> +#include <dm.h>
> +#include <dt-structs.h>
> +#include <dwmmc.h>
> +#include <syscon.h>
> +#include <asm/gpio.h>
> +#include <asm/arch/nx_gpio.h>
> +#include <asm/arch/reset.h>
> +
> +#define DWMCI_CLKSEL 0x09C
> +#define DWMCI_SHIFT_0 0x0
> +#define DWMCI_SHIFT_1 0x1
> +#define DWMCI_SHIFT_2 0x2
> +#define DWMCI_SHIFT_3 0x3
> +#define DWMCI_SET_SAMPLE_CLK(x) (x)
> +#define DWMCI_SET_DRV_CLK(x) ((x) << 16)
> +#define DWMCI_SET_DIV_RATIO(x) ((x) << 24)
> +#define DWMCI_CLKCTRL 0x114
> +#define NX_MMC_CLK_DELAY(x, y, a, b) ((((x) & 0xFF) << 0) |\
> + (((y) & 0x03) << 16) |\
> + (((a) & 0xFF) << 8) |\
> + (((b) & 0x03) << 24))
> +
> +struct nexell_mmc_plat {
> + struct mmc_config cfg;
> + struct mmc mmc;
> +};
> +
> +struct nexell_dwmmc_priv {
> + struct clk *clk;
> + struct dwmci_host host;
> + int fifo_size;
> + bool fifo_mode;
> + int frequency;
> + u32 min_freq;
> + u32 max_freq;
> + int d_delay;
> + int d_shift;
> + int s_delay;
> + int s_shift;
> +
> +};
> +
> +struct clk *clk_get(const char *id);
> +
> +static void set_pin_stat(int index, int bit, int value)
> +{
> +#if !defined(CONFIG_SPL_BUILD)
> + nx_gpio_set_pad_function(index, bit, value);
> +#else
> +#if defined(CONFIG_ARCH_S5P4418) || \
> + defined(CONFIG_ARCH_S5P6818)
> +
> + unsigned long base[5] = {
> + PHY_BASEADDR_GPIOA, PHY_BASEADDR_GPIOB,
> + PHY_BASEADDR_GPIOC, PHY_BASEADDR_GPIOD,
> + PHY_BASEADDR_GPIOE,
> + };
> +
> + dw_mmc_set_pin(base[index], bit, value);
> +#endif
> +#endif
> +}
> +
> +static void nx_dw_mmc_set_pin(struct dwmci_host *host)
> +{
> + debug(" %s(): dev_index == %d", __func__, host->dev_index);
> +
> + switch (host->dev_index) {
> + case 0:
> + set_pin_stat(0, 29, 1);
> + set_pin_stat(0, 31, 1);
> + set_pin_stat(1, 1, 1);
> + set_pin_stat(1, 3, 1);
> + set_pin_stat(1, 5, 1);
> + set_pin_stat(1, 7, 1);
> + break;
> + case 1:
> + set_pin_stat(3, 22, 1);
> + set_pin_stat(3, 23, 1);
> + set_pin_stat(3, 24, 1);
> + set_pin_stat(3, 25, 1);
> + set_pin_stat(3, 26, 1);
> + set_pin_stat(3, 27, 1);
> + break;
> + case 2:
> + set_pin_stat(2, 18, 2);
> + set_pin_stat(2, 19, 2);
> + set_pin_stat(2, 20, 2);
> + set_pin_stat(2, 21, 2);
> + set_pin_stat(2, 22, 2);
> + set_pin_stat(2, 23, 2);
> + if (host->buswidth == 8) {
> + set_pin_stat(4, 21, 2);
> + set_pin_stat(4, 22, 2);
> + set_pin_stat(4, 23, 2);
> + set_pin_stat(4, 24, 2);
> + }
> + break;
> + default:
> + debug(" is invalid!");
> + }
> + debug("\n");
> +}
> +
> +static void nx_dw_mmc_clksel(struct dwmci_host *host)
> +{
> + u32 val;
> +
> +#ifdef CONFIG_BOOST_MMC
> + val = DWMCI_SET_SAMPLE_CLK(DWMCI_SHIFT_0) |
> + DWMCI_SET_DRV_CLK(DWMCI_SHIFT_0) | DWMCI_SET_DIV_RATIO(1);
> +#else
> + val = DWMCI_SET_SAMPLE_CLK(DWMCI_SHIFT_0) |
> + DWMCI_SET_DRV_CLK(DWMCI_SHIFT_0) | DWMCI_SET_DIV_RATIO(3);
> +#endif
> +
> + dwmci_writel(host, DWMCI_CLKSEL, val);
> +}
> +
> +static void nx_dw_mmc_reset(int ch)
> +{
> + int rst_id = RESET_ID_SDMMC0 + ch;
> +
> + nx_rstcon_setrst(rst_id, 0);
> + nx_rstcon_setrst(rst_id, 1);
> +}
> +
> +static void nx_dw_mmc_clk_delay(struct udevice *dev)
> +{
> + unsigned int delay;
> + struct nexell_dwmmc_priv *priv = dev_get_priv(dev);
> + struct dwmci_host *host = &priv->host;
> +
> + delay = NX_MMC_CLK_DELAY(priv->d_delay,
> + priv->d_shift, priv->s_delay, priv->s_shift);
> +
> + writel(delay, (host->ioaddr + DWMCI_CLKCTRL));
> + debug("%s(): Values set: d_delay==%d, d_shift==%d, s_delay==%d, "
> + "s_shift==%d\n", __func__, priv->d_delay, priv->d_shift,
> + priv->s_delay, priv->s_shift);
> +}
> +
> +static unsigned int nx_dw_mmc_get_clk(struct dwmci_host *host, uint freq)
> +{
> + struct clk *clk;
> + struct udevice *dev = host->priv;
> + struct nexell_dwmmc_priv *priv = dev_get_priv(dev);
> +
> + int index = host->dev_index;
> + char name[50] = { 0, };
> +
> + clk = priv->clk;
> + if (!clk) {
> + sprintf(name, "%s.%d", DEV_NAME_SDHC, index);
> + clk = clk_get((const char *)name);
> + if (!clk)
> + return 0;
> + priv->clk = clk;
> + }
> +
> + return clk_get_rate(clk) / 2;
> +}
> +
> +static unsigned long nx_dw_mmc_set_clk(struct dwmci_host *host,
> + unsigned int rate)
> +{
> + struct clk *clk;
> + char name[50] = { 0, };
> + struct udevice *dev = host->priv;
> + struct nexell_dwmmc_priv *priv = dev_get_priv(dev);
> +
> + int index = host->dev_index;
> +
> + clk = priv->clk;
> + if (!clk) {
> + sprintf(name, "%s.%d", DEV_NAME_SDHC, index);
> + clk = clk_get((const char *)name);
> + if (!clk)
> + return 0;
> + priv->clk = clk;
> + }
> +
> + clk_disable(clk);
> + rate = clk_set_rate(clk, rate);
> + clk_enable(clk);
> +
> + return rate;
> +}
> +
> +static int nexell_dwmmc_ofdata_to_platdata(struct udevice *dev)
> +{
> + /* if (dev): *priv = dev->priv, else: *priv = NULL */
> + struct nexell_dwmmc_priv *priv = dev_get_priv(dev);
> + struct dwmci_host *host = &priv->host;
> + int val = -1;
> +
> + debug("%s()\n", __func__);
> +
> + host->name = dev->name;
> + host->ioaddr = dev_read_addr_ptr(dev);
> +
> + val = dev_read_u32_default(dev, "nexell,bus-width", -1);
> + if (val < 0) {
> + debug(" 'nexell,bus-width' missing/invalid!\n");
> + return -EINVAL;
> + }
> + host->buswidth = val;
> + host->get_mmc_clk = nx_dw_mmc_get_clk;
> + host->clksel = nx_dw_mmc_clksel;
> + host->priv = dev;
> +
> + val = dev_read_u32_default(dev, "index", -1);
> + if (val < 0) {
> + debug(" 'index' missing/invalid!\n");
> + return -EINVAL;
> + }
> + host->dev_index = val;
> +
> + val = dev_read_u32_default(dev, "fifo-size", 0x20);
> + if (val <= 0) {
> + debug(" 'fifo-size' missing/invalid!\n");
> + return -EINVAL;
> + }
> + priv->fifo_size = val;
> +
> + priv->fifo_mode = dev_read_bool(dev, "fifo-mode");
> +
> + val = dev_read_u32_default(dev, "frequency", -1);
> + if (val < 0) {
> + debug(" 'frequency' missing/invalid!\n");
> + return -EINVAL;
> + }
> + priv->frequency = val;
> +
> + val = dev_read_u32_default(dev, "max-frequency", -1);
> + if (val < 0) {
> + debug(" 'max-frequency' missing/invalid!\n");
> + return -EINVAL;
> + }
> + priv->max_freq = val;
> + priv->min_freq = 400000; /* 400 kHz */
> +
> + val = dev_read_u32_default(dev, "nexell,drive_dly", -1);
> + if (val < 0) {
> + debug(" 'nexell,drive_dly' missing/invalid!\n");
> + return -EINVAL;
> + }
> + priv->d_delay = val;
> +
> + val = dev_read_u32_default(dev, "nexell,drive_shift", -1);
> + if (val < 0) {
> + debug(" 'nexell,drive_shift' missing/invalid!\n");
> + return -EINVAL;
> + }
> + priv->d_shift = val;
> +
> + val = dev_read_u32_default(dev, "nexell,sample_dly", -1);
> + if (val < 0) {
> + debug(" 'nexell,sample_dly' missing/invalid!\n");
> + return -EINVAL;
> + }
> + priv->s_delay = val;
> +
> + val = dev_read_u32_default(dev, "nexell,sample_shift", -1);
> + if (val < 0) {
> + debug(" 'nexell,sample_shift' missing/invalid!\n");
> + return -EINVAL;
> + }
> + priv->s_shift = val;
> +
> + debug(" index==%d, name==%s, ioaddr==0x%08x, buswidth==%d, "
> + "fifo_size==%d, fifo_mode==%d, frequency==%d\n",
> + host->dev_index, host->name, (u32)host->ioaddr,
> + host->buswidth, priv->fifo_size, priv->fifo_mode,
> + priv->frequency);
> + debug(" min_freq==%d, max_freq==%d, delay: "
> + "0x%02x:0x%02x:0x%02x:0x%02x\n",
> + priv->min_freq, priv->max_freq, priv->d_delay,
> + priv->d_shift, priv->s_delay, priv->s_shift);
> +
> + return 0;
> +}
> +
> +static int nexell_dwmmc_probe(struct udevice *dev)
> +{
> + struct nexell_mmc_plat *plat = dev_get_platdata(dev);
> + struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
> + struct nexell_dwmmc_priv *priv = dev_get_priv(dev);
> + struct dwmci_host *host = &priv->host;
> + struct udevice *pwr_dev __maybe_unused;
> +
> + debug("%s():\n", __func__);
> +
> + host->fifoth_val = MSIZE(0x2) |
> + RX_WMARK(priv->fifo_size / 2 - 1) |
> + TX_WMARK(priv->fifo_size / 2);
> +
> + host->fifo_mode = priv->fifo_mode;
> +
> + dwmci_setup_cfg(&plat->cfg, host, priv->max_freq, priv->min_freq);
> + host->mmc = &plat->mmc;
> + host->mmc->priv = &priv->host;
> + host->mmc->dev = dev;
> + upriv->mmc = host->mmc;
> +
> + nx_dw_mmc_set_pin(host);
> +
> + debug(" nx_dw_mmc_set_clk(host, frequency * 4 == %d)\n",
> + priv->frequency * 4);
> + nx_dw_mmc_set_clk(host, priv->frequency * 4);
> +
> + nx_dw_mmc_reset(host->dev_index);
> + nx_dw_mmc_clk_delay(dev);
> +
> + return dwmci_probe(dev);
> +}
> +
> +static int nexell_dwmmc_bind(struct udevice *dev)
> +{
> + struct nexell_mmc_plat *plat = dev_get_platdata(dev);
> +
> + return dwmci_bind(dev, &plat->mmc, &plat->cfg);
> +}
> +
> +static const struct udevice_id nexell_dwmmc_ids[] = {
> + { .compatible = "nexell,nexell-dwmmc" },
> + { }
> +};
> +
> +U_BOOT_DRIVER(nexell_dwmmc_drv) = {
> + .name = "nexell_dwmmc",
> + .id = UCLASS_MMC,
> + .of_match = nexell_dwmmc_ids,
> + .ofdata_to_platdata = nexell_dwmmc_ofdata_to_platdata,
> + .ops = &dm_dwmci_ops,
> + .bind = nexell_dwmmc_bind,
> + .probe = nexell_dwmmc_probe,
> + .priv_auto_alloc_size = sizeof(struct nexell_dwmmc_priv),
> + .platdata_auto_alloc_size = sizeof(struct nexell_mmc_plat),
> +};
> diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
> index a837c35..b45aada 100644
> --- a/drivers/pwm/Makefile
> +++ b/drivers/pwm/Makefile
> @@ -16,3 +16,4 @@ obj-$(CONFIG_PWM_ROCKCHIP) += rk_pwm.o
> obj-$(CONFIG_PWM_SANDBOX) += sandbox_pwm.o
> obj-$(CONFIG_PWM_TEGRA) += tegra_pwm.o
> obj-$(CONFIG_PWM_SUNXI) += sunxi_pwm.o
> +obj-$(CONFIG_PWM_NX) += pwm-nexell.o
> diff --git a/drivers/pwm/pwm-nexell.c b/drivers/pwm/pwm-nexell.c
> new file mode 100644
> index 0000000..6c0f8f4
> --- /dev/null
> +++ b/drivers/pwm/pwm-nexell.c
> @@ -0,0 +1,252 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (C) 2011 Samsung Electronics
> + *
> + * Donghwa Lee <dh09.lee@samsung.com>
> + */
> +
> +/* This codes are copied from arch/arm/cpu/armv7/s5p-common/pwm.c */
> +
> +#include <common.h>
> +#include <errno.h>
> +#include <pwm.h>
> +#include <asm/io.h>
> +#include <asm/arch/clk.h>
> +#include "pwm-nexell.h"
> +
> +#if defined(CONFIG_ARCH_NEXELL)
> +#include <asm/arch/nexell.h>
> +#include <asm/arch/reset.h>
> +#include <asm/arch/nx_gpio.h>
> +#include <asm/arch/tieoff.h>
> +
> +struct pwm_device {
> + int ch;
> + int grp;
> + int bit;
> + int pwm_fn;
> +};
> +
> +static struct pwm_device pwm_dev[] = {
> + [0] = { .ch = 0, .grp = 3, .bit = 1, .pwm_fn = 1 },
> + [1] = { .ch = 1, .grp = 2, .bit = 13, .pwm_fn = 2 },
> + [2] = { .ch = 2, .grp = 2, .bit = 14, .pwm_fn = 2 },
> + [3] = { .ch = 3, .grp = 3, .bit = 0, .pwm_fn = 2 },
> +};
> +#endif
> +
> +int pwm_enable(int pwm_id)
> +{
> + const struct s5p_timer *pwm =
> +#if defined(CONFIG_ARCH_NEXELL)
> + (struct s5p_timer *)PHY_BASEADDR_PWM;
> +#else
> + (struct s5p_timer *)samsung_get_base_timer();
> +#endif
> + unsigned long tcon;
> +
> + tcon = readl(&pwm->tcon);
> + tcon |= TCON_START(pwm_id);
> +
> + writel(tcon, &pwm->tcon);
> +
> + return 0;
> +}
> +
> +void pwm_disable(int pwm_id)
> +{
> + const struct s5p_timer *pwm =
> +#if defined(CONFIG_ARCH_NEXELL)
> + (struct s5p_timer *)PHY_BASEADDR_PWM;
> +#else
> + (struct s5p_timer *)samsung_get_base_timer();
> +#endif
> + unsigned long tcon;
> +
> + tcon = readl(&pwm->tcon);
> + tcon &= ~TCON_START(pwm_id);
> +
> + writel(tcon, &pwm->tcon);
> +}
> +
> +static unsigned long pwm_calc_tin(int pwm_id, unsigned long freq)
> +{
> + unsigned long tin_parent_rate;
> + unsigned int div;
> +#if defined(CONFIG_ARCH_NEXELL)
> + unsigned int pre_div;
> + const struct s5p_timer *pwm =
> + (struct s5p_timer *)PHY_BASEADDR_PWM;
> + unsigned int val;
> +#endif
> +
> +#if defined(CONFIG_ARCH_NEXELL)
> + struct clk *clk = clk_get(CORECLK_NAME_PCLK);
> +
> + tin_parent_rate = clk_get_rate(clk);
> +#else
> + tin_parent_rate = get_pwm_clk();
> +#endif
> +
> +#if defined(CONFIG_ARCH_NEXELL)
> + writel(0, &pwm->tcfg0);
> + val = readl(&pwm->tcfg0);
> +
> + if (pwm_id < 2)
> + div = ((val >> 0) & 0xff) + 1;
> + else
> + div = ((val >> 8) & 0xff) + 1;
> +
> + writel(0, &pwm->tcfg1);
> + val = readl(&pwm->tcfg1);
> + val = (val >> MUX_DIV_SHIFT(pwm_id)) & 0xF;
> + pre_div = (1UL << val);
> +
> + freq = tin_parent_rate / div / pre_div;
> +
> + return freq;
> +#else
> + for (div = 2; div <= 16; div *= 2) {
> + if ((tin_parent_rate / (div << 16)) < freq)
> + return tin_parent_rate / div;
> + }
> +
> + return tin_parent_rate / 16;
> +#endif
> +}
> +
> +#define NS_IN_SEC 1000000000UL
> +
> +int pwm_config(int pwm_id, int duty_ns, int period_ns)
> +{
> + const struct s5p_timer *pwm =
> +#if defined(CONFIG_ARCH_NEXELL)
> + (struct s5p_timer *)PHY_BASEADDR_PWM;
> +#else
> + (struct s5p_timer *)samsung_get_base_timer();
> +#endif
> + unsigned int offset;
> + unsigned long tin_rate;
> + unsigned long tin_ns;
> + unsigned long frequency;
> + unsigned long tcon;
> + unsigned long tcnt;
> + unsigned long tcmp;
> +
> + /*
> + * We currently avoid using 64bit arithmetic by using the
> + * fact that anything faster than 1GHz is easily representable
> + * by 32bits.
> + */
> + if (period_ns > NS_IN_SEC || duty_ns > NS_IN_SEC || period_ns == 0)
> + return -ERANGE;
> +
> + if (duty_ns > period_ns)
> + return -EINVAL;
> +
> + frequency = NS_IN_SEC / period_ns;
> +
> + /* Check to see if we are changing the clock rate of the PWM */
> + tin_rate = pwm_calc_tin(pwm_id, frequency);
> +
> + tin_ns = NS_IN_SEC / tin_rate;
> +#if defined(CONFIG_ARCH_NEXELL)
> + /* The counter starts at zero. */
> + tcnt = (period_ns / tin_ns) - 1;
> +#else
> + tcnt = period_ns / tin_ns;
> +#endif
> +
> + /* Note, counters count down */
> + tcmp = duty_ns / tin_ns;
> + tcmp = tcnt - tcmp;
> +
> + /* Update the PWM register block. */
> + offset = pwm_id * 3;
> + if (pwm_id < 4) {
> + writel(tcnt, &pwm->tcntb0 + offset);
> + writel(tcmp, &pwm->tcmpb0 + offset);
> + }
> +
> + tcon = readl(&pwm->tcon);
> + tcon |= TCON_UPDATE(pwm_id);
> + if (pwm_id < 4)
> + tcon |= TCON_AUTO_RELOAD(pwm_id);
> + else
> + tcon |= TCON4_AUTO_RELOAD;
> + writel(tcon, &pwm->tcon);
> +
> + tcon &= ~TCON_UPDATE(pwm_id);
> + writel(tcon, &pwm->tcon);
> +
> + return 0;
> +}
> +
> +int pwm_init(int pwm_id, int div, int invert)
> +{
> + u32 val;
> + const struct s5p_timer *pwm =
> +#if defined(CONFIG_ARCH_NEXELL)
> + (struct s5p_timer *)PHY_BASEADDR_PWM;
> +#else
> + (struct s5p_timer *)samsung_get_base_timer();
> +#endif
> + unsigned long ticks_per_period;
> + unsigned int offset, prescaler;
> +
> + /*
> + * Timer Freq(HZ) =
> + * PWM_CLK / { (prescaler_value + 1) * (divider_value) }
> + */
> +
> + val = readl(&pwm->tcfg0);
> + if (pwm_id < 2) {
> + prescaler = PRESCALER_0;
> + val &= ~0xff;
> + val |= (prescaler & 0xff);
> + } else {
> + prescaler = PRESCALER_1;
> + val &= ~(0xff << 8);
> + val |= (prescaler & 0xff) << 8;
> + }
> + writel(val, &pwm->tcfg0);
> + val = readl(&pwm->tcfg1);
> + val &= ~(0xf << MUX_DIV_SHIFT(pwm_id));
> + val |= (div & 0xf) << MUX_DIV_SHIFT(pwm_id);
> + writel(val, &pwm->tcfg1);
> +
> + if (pwm_id == 4) {
> + /*
> + * TODO(sjg): Use this as a countdown timer for now. We count
> + * down from the maximum value to 0, then reset.
> + */
> + ticks_per_period = -1UL;
> + } else {
> + const unsigned long pwm_hz = 1000;
> +#if defined(CONFIG_ARCH_NEXELL)
> + struct clk *clk = clk_get(CORECLK_NAME_PCLK);
> + unsigned long timer_rate_hz = clk_get_rate(clk) /
> +#else
> + unsigned long timer_rate_hz = get_pwm_clk() /
> +#endif
> + ((prescaler + 1) * (1 << div));
> +
> + ticks_per_period = timer_rate_hz / pwm_hz;
> + }
> +
> + /* set count value */
> + offset = pwm_id * 3;
> +
> + writel(ticks_per_period, &pwm->tcntb0 + offset);
> +
> + val = readl(&pwm->tcon) & ~(0xf << TCON_OFFSET(pwm_id));
> + if (invert && pwm_id < 4)
> + val |= TCON_INVERTER(pwm_id);
> + writel(val, &pwm->tcon);
> +
> + nx_gpio_set_pad_function(pwm_dev[pwm_id].grp, pwm_dev[pwm_id].bit,
> + pwm_dev[pwm_id].pwm_fn);
> + pwm_enable(pwm_id);
> +
> + return 0;
> +}
> diff --git a/drivers/pwm/pwm-nexell.h b/drivers/pwm/pwm-nexell.h
> new file mode 100644
> index 0000000..92dc707
> --- /dev/null
> +++ b/drivers/pwm/pwm-nexell.h
> @@ -0,0 +1,54 @@
> +/* SPDX-License-Identifier: GPL-2.0+
> + *
> + * Copyright (C) 2009 Samsung Electronics
> + * Kyungmin Park <kyungmin.park@samsung.com>
> + * Minkyu Kang <mk7.kang@samsung.com>
> + */
> +
> +#ifndef __ASM_ARM_ARCH_PWM_H_
> +#define __ASM_ARM_ARCH_PWM_H_
> +
> +#define PRESCALER_0 (8 - 1) /* prescaler of timer 0, 1 */
> +#define PRESCALER_1 (16 - 1) /* prescaler of timer 2, 3, 4 */
> +
> +/* Divider MUX */
> +#define MUX_DIV_1 0 /* 1/1 period */
> +#define MUX_DIV_2 1 /* 1/2 period */
> +#define MUX_DIV_4 2 /* 1/4 period */
> +#define MUX_DIV_8 3 /* 1/8 period */
> +#define MUX_DIV_16 4 /* 1/16 period */
> +
> +#define MUX_DIV_SHIFT(x) ((x) * 4)
> +
> +#define TCON_OFFSET(x) (((x) + 1) * (!!x) << 2)
> +
> +#define TCON_START(x) (1 << TCON_OFFSET(x))
> +#define TCON_UPDATE(x) (1 << (TCON_OFFSET(x) + 1))
> +#define TCON_INVERTER(x) (1 << (TCON_OFFSET(x) + 2))
> +#define TCON_AUTO_RELOAD(x) (1 << (TCON_OFFSET(x) + 3))
> +#define TCON4_AUTO_RELOAD (1 << 22)
> +
> +#ifndef __ASSEMBLY__
> +struct s5p_timer {
> + unsigned int tcfg0;
> + unsigned int tcfg1;
> + unsigned int tcon;
> + unsigned int tcntb0;
> + unsigned int tcmpb0;
> + unsigned int tcnto0;
> + unsigned int tcntb1;
> + unsigned int tcmpb1;
> + unsigned int tcnto1;
> + unsigned int tcntb2;
> + unsigned int tcmpb2;
> + unsigned int tcnto2;
> + unsigned int tcntb3;
> + unsigned int res1;
> + unsigned int tcnto3;
> + unsigned int tcntb4;
> + unsigned int tcnto4;
> + unsigned int tintcstat;
> +};
> +#endif /* __ASSEMBLY__ */
> +
> +#endif
>
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-52 Fax: +49-8142-66989-80 Email: hs at denx.de
^ permalink raw reply [flat|nested] 19+ messages in thread
* [RFC PATCH 03/10] i2c: mmc: add nexell driver (gpio, i2c, mmc, pwm)
2020-02-04 6:58 ` Heiko Schocher
@ 2020-02-04 18:29 ` Stefan B.
2020-02-20 17:49 ` Stefan B.
1 sibling, 0 replies; 19+ messages in thread
From: Stefan B. @ 2020-02-04 18:29 UTC (permalink / raw)
To: u-boot
Hello Heiko,
thanks a lot for your annotations and suggestions. I will have a look at
them and give you feedback ASAP.
Regards
Stefan
Am 04.02.20 um 07:58 schrieb Heiko Schocher:
> Hello Stefan,
>
> Am 03.02.2020 um 21:40 schrieb Stefan Bosch:
>> Changes in relation to FriendlyARM's U-Boot nanopi2-v2016.01:
>> - i2c/nx_i2c.c: Some adaptions mainly because of changes in
>> "struct udevice".
>> - mmc: nexell_dw_mmc.c changed to nexell_dw_mmc_dm.c (switched to DM).
>>
>> Signed-off-by: Stefan Bosch <stefan_b@posteo.net>
>> ---
>>
>> drivers/gpio/Kconfig | 9 +
>> drivers/gpio/Makefile | 1 +
>> drivers/gpio/nx_gpio.c | 252 +++++++++++++++++++
>> drivers/i2c/Kconfig | 9 +
>> drivers/i2c/Makefile | 1 +
>> drivers/i2c/nx_i2c.c | 537
>> +++++++++++++++++++++++++++++++++++++++++
>> drivers/mmc/Kconfig | 6 +
>> drivers/mmc/Makefile | 1 +
>> drivers/mmc/nexell_dw_mmc_dm.c | 350 +++++++++++++++++++++++++++
>> drivers/pwm/Makefile | 1 +
>> drivers/pwm/pwm-nexell.c | 252 +++++++++++++++++++
>> drivers/pwm/pwm-nexell.h | 54 +++++
>
> Could you please split this patch into 4 parts (i2c, gpio, mmc and
> pwm) ?
>
> Thanks!
>
>> 12 files changed, 1473 insertions(+)
>> create mode 100644 drivers/gpio/nx_gpio.c
>> create mode 100644 drivers/i2c/nx_i2c.c
>> create mode 100644 drivers/mmc/nexell_dw_mmc_dm.c
>> create mode 100644 drivers/pwm/pwm-nexell.c
>> create mode 100644 drivers/pwm/pwm-nexell.h
>>
> [...]
>> diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
>> index 449046b..e3340de 100644
>> --- a/drivers/gpio/Makefile
>> +++ b/drivers/gpio/Makefile
>> @@ -65,3 +65,4 @@ obj-$(CONFIG_PM8916_GPIO) += pm8916_gpio.o
>> obj-$(CONFIG_MT7621_GPIO) += mt7621_gpio.o
>> obj-$(CONFIG_MSCC_SGPIO) += mscc_sgpio.o
>> obj-$(CONFIG_SIFIVE_GPIO) += sifive-gpio.o
>> +obj-$(CONFIG_NX_GPIO) += nx_gpio.o
>
> Please keep lists sorted.
>
>> diff --git a/drivers/gpio/nx_gpio.c b/drivers/gpio/nx_gpio.c
>> new file mode 100644
>> index 0000000..86472f6
>> --- /dev/null
>> +++ b/drivers/gpio/nx_gpio.c
>> @@ -0,0 +1,252 @@
>> +// SPDX-License-Identifier: GPL-2.0+
>> +/*
>> + * (C) Copyright 2016 Nexell
>> + * DeokJin, Lee <truevirtue@nexell.co.kr>
>> + */
>> +
>> +#include <common.h>
>> +#include <dm.h>
>> +#include <errno.h>
>> +#include <malloc.h>
>> +#include <fdtdec.h>
>> +#include <asm/io.h>
>> +#include <asm/gpio.h>
>> +
>> +DECLARE_GLOBAL_DATA_PTR;
>> +
>> +struct nx_gpio_regs {
>> + u32 data; /* Data register */
>> + u32 outputenb; /* Output Enable register */
>> + u32 detmode[2]; /* Detect Mode Register */
>> + u32 intenb; /* Interrupt Enable Register */
>> + u32 det; /* Event Detect Register */
>> + u32 pad; /* Pad Status Register */
>> +};
>> +
>> +struct nx_alive_gpio_regs {
>> + u32 pwrgate; /* Power Gating Register */
>> + u32 reserved0[28]; /* Reserved0 */
>> + u32 outputenb_reset;/* Alive GPIO Output Enable Reset Register */
>> + u32 outputenb; /* Alive GPIO Output Enable Register */
>> + u32 outputenb_read; /* Alive GPIO Output Read Register */
>> + u32 reserved1[3]; /* Reserved1 */
>> + u32 pad_reset; /* Alive GPIO Output Reset Register */
>> + u32 data; /* Alive GPIO Output Register */
>> + u32 pad_read; /* Alive GPIO Pad Read Register */
>> + u32 reserved2[33]; /* Reserved2 */
>> + u32 pad; /* Alive GPIO Input Value Register */
>> +};
>> +
>> +struct nx_gpio_platdata {
>> + void *regs;
>> + int gpio_count;
>> + const char *bank_name;
>> +};
>> +
>> +static int nx_alive_gpio_is_check(struct udevice *dev)
>> +{
>> + struct nx_gpio_platdata *plat = dev_get_platdata(dev);
>> + const char *bank_name = plat->bank_name;
>> +
>> + if (!strcmp(bank_name, "gpio_alv"))
>> + return 1;
>> +
>> + return 0;
>> +}
>> +
>> +static int nx_alive_gpio_direction_input(struct udevice *dev,
>> unsigned int pin)
>> +{
>> + struct nx_gpio_platdata *plat = dev_get_platdata(dev);
>> + struct nx_alive_gpio_regs *const regs = plat->regs;
>> +
>> + setbits_le32(®s->outputenb_reset, 1 << pin);
>> +
>> + return 0;
>> +}
>> +
>> +static int nx_alive_gpio_direction_output(struct udevice *dev,
>> unsigned int pin,
>> + int val)
>> +{
>> + struct nx_gpio_platdata *plat = dev_get_platdata(dev);
>> + struct nx_alive_gpio_regs *const regs = plat->regs;
>> +
>> + if (val)
>> + setbits_le32(®s->data, 1 << pin);
>> + else
>> + setbits_le32(®s->pad_reset, 1 << pin);
>> +
>> + setbits_le32(®s->outputenb, 1 << pin);
>> +
>> + return 0;
>> +}
>> +
>> +static int nx_alive_gpio_get_value(struct udevice *dev, unsigned int
>> pin)
>> +{
>> + struct nx_gpio_platdata *plat = dev_get_platdata(dev);
>> + struct nx_alive_gpio_regs *const regs = plat->regs;
>> + unsigned int mask = 1UL << pin;
>> + unsigned int value;
>> +
>> + value = (readl(®s->pad_read) & mask) >> pin;
>> +
>> + return value;
>> +}
>> +
>> +static int nx_alive_gpio_set_value(struct udevice *dev, unsigned int
>> pin,
>> + int val)
>> +{
>> + struct nx_gpio_platdata *plat = dev_get_platdata(dev);
>> + struct nx_alive_gpio_regs *const regs = plat->regs;
>> +
>> + if (val)
>> + setbits_le32(®s->data, 1 << pin);
>> + else
>> + clrbits_le32(®s->pad_reset, 1 << pin);
>> +
>> + return 0;
>> +}
>> +
>> +static int nx_alive_gpio_get_function(struct udevice *dev, unsigned
>> int pin)
>> +{
>> + struct nx_gpio_platdata *plat = dev_get_platdata(dev);
>> + struct nx_alive_gpio_regs *const regs = plat->regs;
>> + unsigned int mask = (1UL << pin);
>> + unsigned int output;
>> +
>> + output = readl(®s->outputenb_read) & mask;
>> +
>> + if (output)
>> + return GPIOF_OUTPUT;
>> + else
>> + return GPIOF_INPUT;
>> +}
>> +
>> +static int nx_gpio_direction_input(struct udevice *dev, unsigned int
>> pin)
>> +{
>> + struct nx_gpio_platdata *plat = dev_get_platdata(dev);
>> + struct nx_gpio_regs *const regs = plat->regs;
>> +
>> + if (nx_alive_gpio_is_check(dev))
>> + return nx_alive_gpio_direction_input(dev, pin);
>> +
>> + clrbits_le32(®s->outputenb, 1 << pin);
>> +
>> + return 0;
>> +}
>> +
>> +static int nx_gpio_direction_output(struct udevice *dev, unsigned
>> int pin,
>> + int val)
>> +{
>> + struct nx_gpio_platdata *plat = dev_get_platdata(dev);
>> + struct nx_gpio_regs *const regs = plat->regs;
>> +
>> + if (nx_alive_gpio_is_check(dev))
>> + return nx_alive_gpio_direction_output(dev, pin, val);
>> +
>> + if (val)
>> + setbits_le32(®s->data, 1 << pin);
>> + else
>> + clrbits_le32(®s->data, 1 << pin);
>> +
>> + setbits_le32(®s->outputenb, 1 << pin);
>> +
>> + return 0;
>> +}
>> +
>> +static int nx_gpio_get_value(struct udevice *dev, unsigned int pin)
>> +{
>> + struct nx_gpio_platdata *plat = dev_get_platdata(dev);
>> + struct nx_gpio_regs *const regs = plat->regs;
>> + unsigned int mask = 1UL << pin;
>> + unsigned int value;
>> +
>> + if (nx_alive_gpio_is_check(dev))
>> + return nx_alive_gpio_get_value(dev, pin);
>> +
>> + value = (readl(®s->pad) & mask) >> pin;
>> +
>> + return value;
>> +}
>> +
>> +static int nx_gpio_set_value(struct udevice *dev, unsigned int pin,
>> int val)
>> +{
>> + struct nx_gpio_platdata *plat = dev_get_platdata(dev);
>> + struct nx_gpio_regs *const regs = plat->regs;
>> +
>> + if (nx_alive_gpio_is_check(dev))
>> + return nx_alive_gpio_set_value(dev, pin, val);
>> +
>> + if (val)
>> + setbits_le32(®s->data, 1 << pin);
>> + else
>> + clrbits_le32(®s->data, 1 << pin);
>> +
>> + return 0;
>> +}
>> +
>> +static int nx_gpio_get_function(struct udevice *dev, unsigned int pin)
>> +{
>> + struct nx_gpio_platdata *plat = dev_get_platdata(dev);
>> + struct nx_gpio_regs *const regs = plat->regs;
>> + unsigned int mask = (1UL << pin);
>> + unsigned int output;
>> +
>> + if (nx_alive_gpio_is_check(dev))
>> + return nx_alive_gpio_get_function(dev, pin);
>> +
>> + output = readl(®s->outputenb) & mask;
>> +
>> + if (output)
>> + return GPIOF_OUTPUT;
>> + else
>> + return GPIOF_INPUT;
>> +}
>> +
>> +static int nx_gpio_probe(struct udevice *dev)
>> +{
>> + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
>> + struct nx_gpio_platdata *plat = dev_get_platdata(dev);
>> +
>> + uc_priv->gpio_count = plat->gpio_count;
>> + uc_priv->bank_name = plat->bank_name;
>> +
>> + return 0;
>> +}
>> +
>> +static int nx_gpio_ofdata_to_platdata(struct udevice *dev)
>> +{
>> + struct nx_gpio_platdata *plat = dev_get_platdata(dev);
>> +
>> + plat->regs = map_physmem(devfdt_get_addr(dev),
>> + sizeof(struct nx_gpio_regs),
>> + MAP_NOCACHE);
>> + plat->gpio_count = fdtdec_get_int(gd->fdt_blob, dev->node.of_offset,
>> + "nexell,gpio-bank-width", 32);
>> + plat->bank_name = fdt_getprop(gd->fdt_blob, dev->node.of_offset,
>> + "gpio-bank-name", NULL);
>> +
>> + return 0;
>> +}
>> +
>> +static const struct dm_gpio_ops nx_gpio_ops = {
>> + .direction_input = nx_gpio_direction_input,
>> + .direction_output = nx_gpio_direction_output,
>> + .get_value = nx_gpio_get_value,
>> + .set_value = nx_gpio_set_value,
>> + .get_function = nx_gpio_get_function,
>> +};
>> +
>> +static const struct udevice_id nx_gpio_ids[] = {
>> + { .compatible = "nexell,nexell-gpio" },
>> + { }
>> +};
>> +
>> +U_BOOT_DRIVER(nx_gpio) = {
>> + .name = "nx_gpio",
>> + .id = UCLASS_GPIO,
>> + .of_match = nx_gpio_ids,
>> + .ops = &nx_gpio_ops,
>> + .ofdata_to_platdata = nx_gpio_ofdata_to_platdata,
>> + .platdata_auto_alloc_size = sizeof(struct nx_gpio_platdata),
>> + .probe = nx_gpio_probe,
>> +};
>> diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
>> index 03d2fed..2cd0ed3 100644
>> --- a/drivers/i2c/Kconfig
>> +++ b/drivers/i2c/Kconfig
>> @@ -317,6 +317,15 @@ config SYS_MXC_I2C8_SLAVE
>> MXC I2C8 Slave
>> endif
>> +config SYS_I2C_NEXELL
>> + bool "Nexell I2C driver"
>> + depends on DM_I2C
>> + help
>> + Add support for the Nexell I2C driver. This is used with various
>> + Nexell parts such as S5Pxx18 series SoCs. All chips
>> + have several I2C ports and all are provided, controlled by the
>> + device tree.
>> +
>> config SYS_I2C_OMAP24XX
>> bool "TI OMAP2+ I2C driver"
>> depends on ARCH_OMAP2PLUS || ARCH_K3
>> diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
>> index f5a471f..64b8ead 100644
>> --- a/drivers/i2c/Makefile
>> +++ b/drivers/i2c/Makefile
>> @@ -26,6 +26,7 @@ obj-$(CONFIG_SYS_I2C_LPC32XX) += lpc32xx_i2c.o
>> obj-$(CONFIG_SYS_I2C_MESON) += meson_i2c.o
>> obj-$(CONFIG_SYS_I2C_MVTWSI) += mvtwsi.o
>> obj-$(CONFIG_SYS_I2C_MXC) += mxc_i2c.o
>> +obj-$(CONFIG_SYS_I2C_NEXELL) += nx_i2c.o
>> obj-$(CONFIG_SYS_I2C_OMAP24XX) += omap24xx_i2c.o
>> obj-$(CONFIG_SYS_I2C_RCAR_I2C) += rcar_i2c.o
>> obj-$(CONFIG_SYS_I2C_RCAR_IIC) += rcar_iic.o
>> diff --git a/drivers/i2c/nx_i2c.c b/drivers/i2c/nx_i2c.c
>> new file mode 100644
>> index 0000000..a3eec6c
>> --- /dev/null
>> +++ b/drivers/i2c/nx_i2c.c
>> @@ -0,0 +1,537 @@
>> +#include <common.h>
>> +#include <errno.h>
>> +#include <dm.h>
>> +#include <i2c.h>
>> +#include <asm/arch/nexell.h>
>> +#include <asm/arch/reset.h>
>> +#include <asm/arch/clk.h>
>> +#include <asm/arch/nx_gpio.h>
>> +
>> +#define I2C_WRITE 0
>> +#define I2C_READ 1
>> +
>> +#define I2C_OK 0
>> +#define I2C_NOK 1
>> +#define I2C_NACK 2
>> +#define I2C_NOK_LA 3 /* Lost arbitration */
>> +#define I2C_NOK_TOUT 4 /* time out */
>> +
>> +#define I2CLC_FILTER 0x04 /* SDA filter on*/
>> +#define I2CSTAT_BSY 0x20 /* Busy bit */
>> +#define I2CSTAT_NACK 0x01 /* Nack bit */
>> +#define I2CSTAT_ABT 0x08 /* Arbitration bit */
>> +#define I2CCON_ACKGEN 0x80 /* Acknowledge generation */
>> +#define I2CCON_IRENB 0x20 /* Interrupt Enable bit */
>> +#define I2CCON_IRPND 0x10 /* Interrupt pending bit */
>> +#define I2C_MODE_MT 0xC0 /* Master Transmit Mode */
>> +#define I2C_MODE_MR 0x80 /* Master Receive Mode */
>> +#define I2C_START_STOP 0x20 /* START / STOP */
>> +#define I2C_TXRX_ENA 0x10 /* I2C Tx/Rx enable */
>> +
>> +#define I2C_TIMEOUT_MS 10 /* 10 ms */
>> +
>> +#define I2C_M_NOSTOP 0x100
>> +
>> +#ifndef CONFIG_MAX_I2C_NUM
>> +#define CONFIG_MAX_I2C_NUM 3
>> +#endif
>
> Is this really configurable? If so, I do not find the Kconfig
> description.
>
>> +
>> +DECLARE_GLOBAL_DATA_PTR;
>> +
>> +struct nx_i2c_regs {
>> + uint iiccon;
>> + uint iicstat;
>> + uint iicadd;
>> + uint iicds;
>> + uint iiclc;
>> +};
>> +
>> +struct nx_i2c_bus {
>> + uint bus_num;
>> + struct nx_i2c_regs *regs;
>> + uint speed;
>> + uint target_speed;
>> + uint sda_delay;
>> +};
>> +
>> +/* s5pxx18 i2c must be reset before enabled */
>> +static void i2c_reset(int ch)
>> +{
>> + int rst_id = RESET_ID_I2C0 + ch;
>> +
>> + nx_rstcon_setrst(rst_id, 0);
>> + nx_rstcon_setrst(rst_id, 1);
>> +}
>> +
>> +/* FIXME : this func will be removed after reset dm driver ported.
>> + * set mmc pad alternative func.
>> + */
>> +static void set_i2c_pad_func(struct nx_i2c_bus *i2c)
>> +{
>> + switch (i2c->bus_num) {
>> + case 0:
>> + nx_gpio_set_pad_function(3, 2, 1);
>> + nx_gpio_set_pad_function(3, 3, 1);
>> + break;
>> + case 1:
>> + nx_gpio_set_pad_function(3, 4, 1);
>> + nx_gpio_set_pad_function(3, 5, 1);
>> + break;
>> + case 2:
>> + nx_gpio_set_pad_function(3, 6, 1);
>> + nx_gpio_set_pad_function(3, 7, 1);
>> + break;
>> + }
>> +}
>
> Hmm... may this should be moved into a seperate pincontrol driver?
>
>> +
>> +static uint i2c_get_clkrate(struct nx_i2c_bus *bus)
>> +{
>> + struct clk *clk;
>> + int index = bus->bus_num;
>> + char name[50] = {0, };
>
> ?
>
>> +
>> + sprintf(name, "%s.%d", DEV_NAME_I2C, index);
>
> Where is DEV_NAME_I2C defined ?
>
>> + clk = clk_get((const char *)name);
>> + if (!clk)
>> + return -1;
>> +
>> + return clk_get_rate(clk);
>> +}
>> +
>> +static uint i2c_set_clk(struct nx_i2c_bus *bus, uint enb)
>> +{
>> + struct clk *clk;
>> + char name[50];
>> +
>> + sprintf(name, "%s.%d", DEV_NAME_I2C, bus->bus_num);
>> + clk = clk_get((const char *)name);
>> + if (!clk)
>> + return -1;
>> +
>> + if (enb) {
>> + clk_disable(clk);
>> + clk_enable(clk);
>> + } else {
>> + clk_disable(clk);
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +/* get i2c module number from base address */
>> +static uint i2c_get_busnum(struct nx_i2c_bus *bus)
>> +{
>> + void *base_addr = (void *)PHY_BASEADDR_I2C0;
>> + int i;
>> +
>> + for (i = 0; i < CONFIG_MAX_I2C_NUM; i++) {
>> + if (base_addr == ((void *)bus->regs)) {
>> + bus->bus_num = i;
>> + return i;
>> + }
>> + base_addr += 0x1000;
>> + }
>> +
>> + return -1;
>
> return -ENODEV;
>
> Hmm... is there no chance to use seq from struct udevice
>
> https://gitlab.denx.de/u-boot/u-boot/blob/master/include/dm/device.h#L152
>
> ?
>
> For example like:
> https://gitlab.denx.de/u-boot/u-boot/blob/master/drivers/i2c/mxc_i2c.c#L895
>
>
>> +}
>> +
>> +/* Set SDA line delay */
>> +static int nx_i2c_set_sda_delay(struct nx_i2c_bus *bus, ulong clkin)
>> +{
>> + struct nx_i2c_regs *i2c = bus->regs;
>> + uint sda_delay = 0;
>> +
>> + if (bus->sda_delay) {
>> + sda_delay = clkin * bus->sda_delay;
>> + sda_delay = DIV_ROUND_UP(sda_delay, 1000000);
>> + sda_delay = DIV_ROUND_UP(sda_delay, 5);
>> + if (sda_delay > 3)
>> + sda_delay = 3;
>> + sda_delay |= I2CLC_FILTER;
>> + } else {
>> + sda_delay = 0;
>> + }
>> +
>> + sda_delay &= 0x7;
>> + writel(sda_delay, &i2c->iiclc);
>> +
>> + return 0;
>> +}
>> +
>> +/* Calculate the value of the divider and prescaler, set the bus
>> speed. */
>> +static int nx_i2c_set_bus_speed(struct udevice *dev, uint speed)
>> +{
>> + struct nx_i2c_bus *bus = dev_get_priv(dev);
>> + struct nx_i2c_regs *i2c = bus->regs;
>> + unsigned long freq, pres = 16, div;
>> +
>> + freq = i2c_get_clkrate(bus);
>> + /* calculate prescaler and divisor values */
>> + if ((freq / pres / (16 + 1)) > speed)
>> + /* set prescaler to 512 */
>> + pres = 512;
>> +
>> + div = 0;
>> + while ((freq / pres / (div + 1)) > speed)
>> + div++;
>> +
>> + /* set prescaler, divisor according to freq, also set ACKGEN, IRQ */
>> + writel((div & 0x0F) | ((pres == 512) ? 0x40 : 0), &i2c->iiccon);
>> +
>> + /* init to SLAVE REVEIVE and set slaveaddr */
>> + writel(0, &i2c->iicstat);
>> + writel(0x00, &i2c->iicadd);
>> + /* program Master Transmit (and implicit STOP) */
>> + writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat);
>> +
>> + bus->speed = bus->target_speed / (div * pres);
>
> Do you want to allow all values of speeds or may you want to use
> standard speeds, see:
>
> https://gitlab.denx.de/u-boot/u-boot/blob/master/include/i2c.h#L33
>
>> +
>> + return 0;
>> +}
>> +
>> +static void nx_i2c_set_clockrate(struct udevice *dev, uint speed)
>> +{
>> + struct nx_i2c_bus *bus = dev_get_priv(dev);
>> + ulong clkin;
>> +
>> + nx_i2c_set_bus_speed(dev, speed);
>> + clkin = bus->speed; /* the actual i2c speed */
>> + clkin /= 1000; /* clkin now in Khz */
>> + nx_i2c_set_sda_delay(bus, clkin);
>> +}
>> +
>> +static void i2c_process_node(struct udevice *dev)
>> +{
>> + struct nx_i2c_bus *bus = dev_get_priv(dev);
>> + const void *blob = gd->fdt_blob;
>> +
>> + int node;
>> +
>> + node = dev->node.of_offset;
>> +
>> + bus->target_speed = fdtdec_get_int(blob, node,
>> + "nexell,i2c-max-bus-freq", 0);
>> + bus->sda_delay = fdtdec_get_int(blob, node,
>> + "nexell,i2c-sda-delay", 0);
>
> You introdue here new properties, please document them in
> u-boot:/doc/device-tree-bindings/i2c
>
> Please without "nexell,"
>
> Do you plan to post also a linux i2c driver?
>
> If so, the devicetree bindings should be discussed there to avoid
> different properties between U-Boot and linux!
>
>> +}
>> +
>> +static int nx_i2c_probe(struct udevice *dev)
>> +{
>> + struct nx_i2c_bus *bus = dev_get_priv(dev);
>> +
>> + /* get regs */
>> + bus->regs = (struct nx_i2c_regs *)devfdt_get_addr(dev);
>> + /* calc index */
>> + if (!i2c_get_busnum(bus)) {
>> + debug("not found i2c number!\n");
>> + return -1;
>
> please return -ENODEV
>
>> + }
>> +
>> + /* i2c optional node parsing */
>> + i2c_process_node(dev);
>> + if (!bus->target_speed)
>> + return -1;
>
> please return here also an errorcode from include/linux/errno.h
>
> Hmm.. if you return here if target_speed is not set, it is not optional!
>
>> +
>> + /* reset */
>> + i2c_reset(bus->bus_num);
>> + /* gpio pad */
>> + set_i2c_pad_func(bus);
>> +
>> + /* clock rate */
>> + i2c_set_clk(bus, 1);
>> + nx_i2c_set_clockrate(dev, bus->target_speed);
>> + i2c_set_clk(bus, 0);
>> +
>> + return 0;
>> +}
>> +
>> +/* i2c bus busy check */
>> +static int i2c_is_busy(struct nx_i2c_regs *i2c)
>> +{
>> + ulong start_time;
>> +
>> + start_time = get_timer(0);
>> + while (readl(&i2c->iicstat) & I2CSTAT_BSY) {
>> + if (get_timer(start_time) > I2C_TIMEOUT_MS) {
>> + debug("Timeout\n");
>> + return -I2C_NOK_TOUT;
>> + }
>> + }
>> + return 0;
>> +}
>> +
>> +/* irq enable/disable functions */
>> +static void i2c_enable_irq(struct nx_i2c_regs *i2c)
>> +{
>> + unsigned int reg;
>> +
>> + reg = readl(&i2c->iiccon);
>> + reg |= I2CCON_IRENB;
>> + writel(reg, &i2c->iiccon);
>> +}
>> +
>> +/* irq clear function */
>> +static void i2c_clear_irq(struct nx_i2c_regs *i2c)
>> +{
>> + clrbits_le32(&i2c->iiccon, I2CCON_IRPND);
>> +}
>> +
>> +/* ack enable functions */
>> +static void i2c_enable_ack(struct nx_i2c_regs *i2c)
>> +{
>> + unsigned int reg;
>> +
>> + reg = readl(&i2c->iiccon);
>> + reg |= I2CCON_ACKGEN;
>> + writel(reg, &i2c->iiccon);
>> +}
>> +
>> +static void i2c_send_stop(struct nx_i2c_regs *i2c)
>> +{
>> + unsigned int reg;
>> +
>> + /* Send STOP. */
>> + reg = readl(&i2c->iicstat);
>> + reg |= I2C_MODE_MR | I2C_TXRX_ENA;
>> + reg &= (~I2C_START_STOP);
>> + writel(reg, &i2c->iicstat);
>> + i2c_clear_irq(i2c);
>> +}
>> +
>> +static int wait_for_xfer(struct nx_i2c_regs *i2c)
>> +{
>> + unsigned long start_time = get_timer(0);
>> +
>> + do {
>> + if (readl(&i2c->iiccon) & I2CCON_IRPND)
>> + return (readl(&i2c->iicstat) & I2CSTAT_NACK) ?
>> + I2C_NACK : I2C_OK;
>> + } while (get_timer(start_time) < I2C_TIMEOUT_MS);
>> +
>> + return I2C_NOK_TOUT;
>> +}
>> +
>> +static int i2c_transfer(struct nx_i2c_regs *i2c,
>> + uchar cmd_type,
>> + uchar chip,
>> + uchar addr[],
>> + uchar addr_len,
>> + uchar data[],
>> + unsigned short data_len,
>> + uint seq)
>> +{
>> + uint status;
>> + int i = 0, result;
>> +
>> + if (data == 0 || data_len == 0) {
>> + /*Don't support data transfer of no length or to address 0 */
>> + debug("%s: bad call\n", __func__);
>> + return I2C_NOK;
>> + }
>> +
>> + i2c_enable_irq(i2c);
>> + i2c_enable_ack(i2c);
>> +
>> + /* Get the slave chip address going */
>> + writel(chip, &i2c->iicds);
>> + status = I2C_TXRX_ENA | I2C_START_STOP;
>> + if (cmd_type == I2C_WRITE || (addr && addr_len))
>> + status |= I2C_MODE_MT;
>> + else
>> + status |= I2C_MODE_MR;
>> + writel(status, &i2c->iicstat);
>> + if (seq)
>> + i2c_clear_irq(i2c);
>> +
>> + /* Wait for chip address to transmit. */
>> + result = wait_for_xfer(i2c);
>> + if (result != I2C_OK)
>> + goto bailout;
>> +
>> + /* If register address needs to be transmitted - do it now. */
>> + if (addr && addr_len) { /* register addr */
>> + while ((i < addr_len) && (result == I2C_OK)) {
>> + writel(addr[i++], &i2c->iicds);
>> + i2c_clear_irq(i2c);
>> + result = wait_for_xfer(i2c);
>> + }
>> +
>> + i = 0;
>> + if (result != I2C_OK)
>> + goto bailout;
>> + }
>> +
>> + switch (cmd_type) {
>> + case I2C_WRITE:
>> + while ((i < data_len) && (result == I2C_OK)) {
>> + writel(data[i++], &i2c->iicds);
>> + i2c_clear_irq(i2c);
>> + result = wait_for_xfer(i2c);
>> + }
>> + break;
>> + case I2C_READ:
>> + if (addr && addr_len) {
>> + /*
>> + * Register address has been sent, now send slave chip
>> + * address again to start the actual read transaction.
>> + */
>> + writel(chip, &i2c->iicds);
>> +
>> + /* Generate a re-START. */
>> + writel(I2C_MODE_MR | I2C_TXRX_ENA
>> + | I2C_START_STOP, &i2c->iicstat);
>> + i2c_clear_irq(i2c);
>> + result = wait_for_xfer(i2c);
>> + if (result != I2C_OK)
>> + goto bailout;
>> + }
>> +
>> + while ((i < data_len) && (result == I2C_OK)) {
>> + /* disable ACK for final READ */
>> + if (i == data_len - 1)
>> + clrbits_le32(&i2c->iiccon
>> + , I2CCON_ACKGEN);
>> +
>> + i2c_clear_irq(i2c);
>> + result = wait_for_xfer(i2c);
>> + data[i++] = readb(&i2c->iicds);
>> + }
>> +
>> + if (result == I2C_NACK)
>> + result = I2C_OK; /* Normal terminated read. */
>> + break;
>> +
>> + default:
>> + debug("%s: bad call\n", __func__);
>> + result = I2C_NOK;
>> + break;
>> + }
>> +
>> +bailout:
>> + return result;
>> +}
>> +
>> +static int nx_i2c_read(struct udevice *dev, uchar chip, uint addr,
>> + uint alen, uchar *buffer, uint len, uint seq)
>> +{
>> + struct nx_i2c_bus *i2c;
>> + uchar xaddr[4];
>> + int ret;
>> +
>> + i2c = dev_get_priv(dev);
>> + if (!i2c)
>> + return -EFAULT;
>> +
>> + if (alen > 4) {
>> + debug("I2C read: addr len %d not supported\n", alen);
>> + return -EADDRNOTAVAIL;
>> + }
>> +
>> + if (alen > 0)
>> + xaddr[0] = (addr >> 24) & 0xFF;
>> +
>> + if (alen > 0) {
>> + xaddr[0] = (addr >> 24) & 0xFF;
>> + xaddr[1] = (addr >> 16) & 0xFF;
>> + xaddr[2] = (addr >> 8) & 0xFF;
>> + xaddr[3] = addr & 0xFF;
>> + }
>> +
>> + ret = i2c_transfer(i2c->regs, I2C_READ, chip << 1,
>> + &xaddr[4 - alen], alen, buffer, len, seq);
>> +
>> + if (ret) {
>> + debug("I2C read failed %d\n", ret);
>> + return -EIO;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int nx_i2c_write(struct udevice *dev, uchar chip, uint addr,
>> + uint alen, uchar *buffer, uint len, uint seq)
>> +{
>> + struct nx_i2c_bus *i2c;
>> + uchar xaddr[4];
>> + int ret;
>> +
>> + i2c = dev_get_priv(dev);
>> + if (!i2c)
>> + return -EFAULT;
>> +
>> + if (alen > 4) {
>> + debug("I2C write: addr len %d not supported\n", alen);
>> + return -EINVAL;
>> + }
>> +
>> + if (alen > 0) {
>> + xaddr[0] = (addr >> 24) & 0xFF;
>> + xaddr[1] = (addr >> 16) & 0xFF;
>> + xaddr[2] = (addr >> 8) & 0xFF;
>> + xaddr[3] = addr & 0xFF;
>> + }
>> +
>> + ret = i2c_transfer(i2c->regs, I2C_WRITE, chip << 1,
>> + &xaddr[4 - alen], alen, buffer, len, seq);
>> + if (ret) {
>> + debug("I2C write failed %d\n", ret);
>> + return -EIO;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int nx_i2c_xfer(struct udevice *dev, struct i2c_msg *msg, int
>> nmsgs)
>> +{
>> + struct nx_i2c_bus *bus = dev_get_priv(dev);
>> + struct nx_i2c_regs *i2c = bus->regs;
>> + int ret;
>> + int i;
>> +
>> + /* The power loss by the clock, only during on/off. */
>> + i2c_set_clk(bus, 1);
>> +
>> + /* Bus State(Busy) check */
>> + ret = i2c_is_busy(i2c);
>> + if (ret < 0)
>> + return ret;
>> +
>> + for (i = 0; i < nmsgs; msg++, i++) {
>> + if (msg->flags & I2C_M_RD) {
>> + ret = nx_i2c_read(dev, msg->addr, 0, 0, msg->buf,
>> + msg->len, i);
>> + } else {
>> + ret = nx_i2c_write(dev, msg->addr, 0, 0, msg->buf,
>> + msg->len, i);
>> + }
>> +
>> + if (ret) {
>> + debug("i2c_xfer: error sending\n");
>> + return -EREMOTEIO;
>> + }
>> + }
>> + /* Send Stop */
>> + i2c_send_stop(i2c);
>> + i2c_set_clk(bus, 0);
>> +
>> + return ret ? -EREMOTEIO : 0;
>> +};
>> +
>> +static const struct dm_i2c_ops nx_i2c_ops = {
>> + .xfer = nx_i2c_xfer,
>> + .set_bus_speed = nx_i2c_set_bus_speed,
>> +};
>> +
>> +static const struct udevice_id nx_i2c_ids[] = {
>> + { .compatible = "nexell,s5pxx18-i2c" },
>
> Same here as for the new properties. Please discuss the names on
>
> devicetree at vger.kernel.org <devicetree@vger.kernel.org>
>
> first!
>
>> + { }
>> +};
>> +
>> +U_BOOT_DRIVER(i2c_nexell) = {
>> + .name = "i2c_nexell",
>> + .id = UCLASS_I2C,
>> + .of_match = nx_i2c_ids,
>> + .probe = nx_i2c_probe,
>> + .priv_auto_alloc_size = sizeof(struct nx_i2c_bus),
>> + .ops = &nx_i2c_ops,
>> +};
>
> bye,
> Heiko
>> diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
>> index 2f0eedc..bb8e7c0 100644
>> --- a/drivers/mmc/Kconfig
>> +++ b/drivers/mmc/Kconfig
>> @@ -253,6 +253,12 @@ config MMC_DW_SNPS
>> This selects support for Synopsys DesignWare Memory Card
>> Interface driver
>> extensions used in various Synopsys ARC devboards.
>> +config NEXELL_DWMMC
>> + bool "Nexell SD/MMC controller support"
>> + depends on ARCH_NEXELL
>> + depends on MMC_DW
>> + default y
>> +
>> config MMC_MESON_GX
>> bool "Meson GX EMMC controller support"
>> depends on DM_MMC && BLK && ARCH_MESON
>> diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
>> index 9c1f8e5..a7b5a7b 100644
>> --- a/drivers/mmc/Makefile
>> +++ b/drivers/mmc/Makefile
>> @@ -43,6 +43,7 @@ obj-$(CONFIG_SH_MMCIF) += sh_mmcif.o
>> obj-$(CONFIG_SH_SDHI) += sh_sdhi.o
>> obj-$(CONFIG_STM32_SDMMC2) += stm32_sdmmc2.o
>> obj-$(CONFIG_JZ47XX_MMC) += jz_mmc.o
>> +obj-$(CONFIG_NEXELL_DWMMC) += nexell_dw_mmc_dm.o
>> # SDHCI
>> obj-$(CONFIG_MMC_SDHCI) += sdhci.o
>> diff --git a/drivers/mmc/nexell_dw_mmc_dm.c
>> b/drivers/mmc/nexell_dw_mmc_dm.c
>> new file mode 100644
>> index 0000000..b06b60d
>> --- /dev/null
>> +++ b/drivers/mmc/nexell_dw_mmc_dm.c
>> @@ -0,0 +1,350 @@
>> +// SPDX-License-Identifier: GPL-2.0+
>> +/*
>> + * (C) Copyright 2016 Nexell
>> + * Youngbok, Park <park@nexell.co.kr>
>> + *
>> + * (C) Copyright 2019 Stefan Bosch <stefan_b@posteo.net>
>> + */
>> +
>> +#include <common.h>
>> +#include <clk.h>
>> +#include <dm.h>
>> +#include <dt-structs.h>
>> +#include <dwmmc.h>
>> +#include <syscon.h>
>> +#include <asm/gpio.h>
>> +#include <asm/arch/nx_gpio.h>
>> +#include <asm/arch/reset.h>
>> +
>> +#define DWMCI_CLKSEL 0x09C
>> +#define DWMCI_SHIFT_0 0x0
>> +#define DWMCI_SHIFT_1 0x1
>> +#define DWMCI_SHIFT_2 0x2
>> +#define DWMCI_SHIFT_3 0x3
>> +#define DWMCI_SET_SAMPLE_CLK(x) (x)
>> +#define DWMCI_SET_DRV_CLK(x) ((x) << 16)
>> +#define DWMCI_SET_DIV_RATIO(x) ((x) << 24)
>> +#define DWMCI_CLKCTRL 0x114
>> +#define NX_MMC_CLK_DELAY(x, y, a, b) ((((x) & 0xFF) << 0) |\
>> + (((y) & 0x03) << 16) |\
>> + (((a) & 0xFF) << 8) |\
>> + (((b) & 0x03) << 24))
>> +
>> +struct nexell_mmc_plat {
>> + struct mmc_config cfg;
>> + struct mmc mmc;
>> +};
>> +
>> +struct nexell_dwmmc_priv {
>> + struct clk *clk;
>> + struct dwmci_host host;
>> + int fifo_size;
>> + bool fifo_mode;
>> + int frequency;
>> + u32 min_freq;
>> + u32 max_freq;
>> + int d_delay;
>> + int d_shift;
>> + int s_delay;
>> + int s_shift;
>> +
>> +};
>> +
>> +struct clk *clk_get(const char *id);
>> +
>> +static void set_pin_stat(int index, int bit, int value)
>> +{
>> +#if !defined(CONFIG_SPL_BUILD)
>> + nx_gpio_set_pad_function(index, bit, value);
>> +#else
>> +#if defined(CONFIG_ARCH_S5P4418) || \
>> + defined(CONFIG_ARCH_S5P6818)
>> +
>> + unsigned long base[5] = {
>> + PHY_BASEADDR_GPIOA, PHY_BASEADDR_GPIOB,
>> + PHY_BASEADDR_GPIOC, PHY_BASEADDR_GPIOD,
>> + PHY_BASEADDR_GPIOE,
>> + };
>> +
>> + dw_mmc_set_pin(base[index], bit, value);
>> +#endif
>> +#endif
>> +}
>> +
>> +static void nx_dw_mmc_set_pin(struct dwmci_host *host)
>> +{
>> + debug(" %s(): dev_index == %d", __func__, host->dev_index);
>> +
>> + switch (host->dev_index) {
>> + case 0:
>> + set_pin_stat(0, 29, 1);
>> + set_pin_stat(0, 31, 1);
>> + set_pin_stat(1, 1, 1);
>> + set_pin_stat(1, 3, 1);
>> + set_pin_stat(1, 5, 1);
>> + set_pin_stat(1, 7, 1);
>> + break;
>> + case 1:
>> + set_pin_stat(3, 22, 1);
>> + set_pin_stat(3, 23, 1);
>> + set_pin_stat(3, 24, 1);
>> + set_pin_stat(3, 25, 1);
>> + set_pin_stat(3, 26, 1);
>> + set_pin_stat(3, 27, 1);
>> + break;
>> + case 2:
>> + set_pin_stat(2, 18, 2);
>> + set_pin_stat(2, 19, 2);
>> + set_pin_stat(2, 20, 2);
>> + set_pin_stat(2, 21, 2);
>> + set_pin_stat(2, 22, 2);
>> + set_pin_stat(2, 23, 2);
>> + if (host->buswidth == 8) {
>> + set_pin_stat(4, 21, 2);
>> + set_pin_stat(4, 22, 2);
>> + set_pin_stat(4, 23, 2);
>> + set_pin_stat(4, 24, 2);
>> + }
>> + break;
>> + default:
>> + debug(" is invalid!");
>> + }
>> + debug("\n");
>> +}
>> +
>> +static void nx_dw_mmc_clksel(struct dwmci_host *host)
>> +{
>> + u32 val;
>> +
>> +#ifdef CONFIG_BOOST_MMC
>> + val = DWMCI_SET_SAMPLE_CLK(DWMCI_SHIFT_0) |
>> + DWMCI_SET_DRV_CLK(DWMCI_SHIFT_0) | DWMCI_SET_DIV_RATIO(1);
>> +#else
>> + val = DWMCI_SET_SAMPLE_CLK(DWMCI_SHIFT_0) |
>> + DWMCI_SET_DRV_CLK(DWMCI_SHIFT_0) | DWMCI_SET_DIV_RATIO(3);
>> +#endif
>> +
>> + dwmci_writel(host, DWMCI_CLKSEL, val);
>> +}
>> +
>> +static void nx_dw_mmc_reset(int ch)
>> +{
>> + int rst_id = RESET_ID_SDMMC0 + ch;
>> +
>> + nx_rstcon_setrst(rst_id, 0);
>> + nx_rstcon_setrst(rst_id, 1);
>> +}
>> +
>> +static void nx_dw_mmc_clk_delay(struct udevice *dev)
>> +{
>> + unsigned int delay;
>> + struct nexell_dwmmc_priv *priv = dev_get_priv(dev);
>> + struct dwmci_host *host = &priv->host;
>> +
>> + delay = NX_MMC_CLK_DELAY(priv->d_delay,
>> + priv->d_shift, priv->s_delay, priv->s_shift);
>> +
>> + writel(delay, (host->ioaddr + DWMCI_CLKCTRL));
>> + debug("%s(): Values set: d_delay==%d, d_shift==%d, s_delay==%d, "
>> + "s_shift==%d\n", __func__, priv->d_delay, priv->d_shift,
>> + priv->s_delay, priv->s_shift);
>> +}
>> +
>> +static unsigned int nx_dw_mmc_get_clk(struct dwmci_host *host, uint
>> freq)
>> +{
>> + struct clk *clk;
>> + struct udevice *dev = host->priv;
>> + struct nexell_dwmmc_priv *priv = dev_get_priv(dev);
>> +
>> + int index = host->dev_index;
>> + char name[50] = { 0, };
>> +
>> + clk = priv->clk;
>> + if (!clk) {
>> + sprintf(name, "%s.%d", DEV_NAME_SDHC, index);
>> + clk = clk_get((const char *)name);
>> + if (!clk)
>> + return 0;
>> + priv->clk = clk;
>> + }
>> +
>> + return clk_get_rate(clk) / 2;
>> +}
>> +
>> +static unsigned long nx_dw_mmc_set_clk(struct dwmci_host *host,
>> + unsigned int rate)
>> +{
>> + struct clk *clk;
>> + char name[50] = { 0, };
>> + struct udevice *dev = host->priv;
>> + struct nexell_dwmmc_priv *priv = dev_get_priv(dev);
>> +
>> + int index = host->dev_index;
>> +
>> + clk = priv->clk;
>> + if (!clk) {
>> + sprintf(name, "%s.%d", DEV_NAME_SDHC, index);
>> + clk = clk_get((const char *)name);
>> + if (!clk)
>> + return 0;
>> + priv->clk = clk;
>> + }
>> +
>> + clk_disable(clk);
>> + rate = clk_set_rate(clk, rate);
>> + clk_enable(clk);
>> +
>> + return rate;
>> +}
>> +
>> +static int nexell_dwmmc_ofdata_to_platdata(struct udevice *dev)
>> +{
>> + /* if (dev): *priv = dev->priv, else: *priv = NULL */
>> + struct nexell_dwmmc_priv *priv = dev_get_priv(dev);
>> + struct dwmci_host *host = &priv->host;
>> + int val = -1;
>> +
>> + debug("%s()\n", __func__);
>> +
>> + host->name = dev->name;
>> + host->ioaddr = dev_read_addr_ptr(dev);
>> +
>> + val = dev_read_u32_default(dev, "nexell,bus-width", -1);
>> + if (val < 0) {
>> + debug(" 'nexell,bus-width' missing/invalid!\n");
>> + return -EINVAL;
>> + }
>> + host->buswidth = val;
>> + host->get_mmc_clk = nx_dw_mmc_get_clk;
>> + host->clksel = nx_dw_mmc_clksel;
>> + host->priv = dev;
>> +
>> + val = dev_read_u32_default(dev, "index", -1);
>> + if (val < 0) {
>> + debug(" 'index' missing/invalid!\n");
>> + return -EINVAL;
>> + }
>> + host->dev_index = val;
>> +
>> + val = dev_read_u32_default(dev, "fifo-size", 0x20);
>> + if (val <= 0) {
>> + debug(" 'fifo-size' missing/invalid!\n");
>> + return -EINVAL;
>> + }
>> + priv->fifo_size = val;
>> +
>> + priv->fifo_mode = dev_read_bool(dev, "fifo-mode");
>> +
>> + val = dev_read_u32_default(dev, "frequency", -1);
>> + if (val < 0) {
>> + debug(" 'frequency' missing/invalid!\n");
>> + return -EINVAL;
>> + }
>> + priv->frequency = val;
>> +
>> + val = dev_read_u32_default(dev, "max-frequency", -1);
>> + if (val < 0) {
>> + debug(" 'max-frequency' missing/invalid!\n");
>> + return -EINVAL;
>> + }
>> + priv->max_freq = val;
>> + priv->min_freq = 400000; /* 400 kHz */
>> +
>> + val = dev_read_u32_default(dev, "nexell,drive_dly", -1);
>> + if (val < 0) {
>> + debug(" 'nexell,drive_dly' missing/invalid!\n");
>> + return -EINVAL;
>> + }
>> + priv->d_delay = val;
>> +
>> + val = dev_read_u32_default(dev, "nexell,drive_shift", -1);
>> + if (val < 0) {
>> + debug(" 'nexell,drive_shift' missing/invalid!\n");
>> + return -EINVAL;
>> + }
>> + priv->d_shift = val;
>> +
>> + val = dev_read_u32_default(dev, "nexell,sample_dly", -1);
>> + if (val < 0) {
>> + debug(" 'nexell,sample_dly' missing/invalid!\n");
>> + return -EINVAL;
>> + }
>> + priv->s_delay = val;
>> +
>> + val = dev_read_u32_default(dev, "nexell,sample_shift", -1);
>> + if (val < 0) {
>> + debug(" 'nexell,sample_shift' missing/invalid!\n");
>> + return -EINVAL;
>> + }
>> + priv->s_shift = val;
>> +
>> + debug(" index==%d, name==%s, ioaddr==0x%08x, buswidth==%d, "
>> + "fifo_size==%d, fifo_mode==%d, frequency==%d\n",
>> + host->dev_index, host->name, (u32)host->ioaddr,
>> + host->buswidth, priv->fifo_size, priv->fifo_mode,
>> + priv->frequency);
>> + debug(" min_freq==%d, max_freq==%d, delay: "
>> + "0x%02x:0x%02x:0x%02x:0x%02x\n",
>> + priv->min_freq, priv->max_freq, priv->d_delay,
>> + priv->d_shift, priv->s_delay, priv->s_shift);
>> +
>> + return 0;
>> +}
>> +
>> +static int nexell_dwmmc_probe(struct udevice *dev)
>> +{
>> + struct nexell_mmc_plat *plat = dev_get_platdata(dev);
>> + struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
>> + struct nexell_dwmmc_priv *priv = dev_get_priv(dev);
>> + struct dwmci_host *host = &priv->host;
>> + struct udevice *pwr_dev __maybe_unused;
>> +
>> + debug("%s():\n", __func__);
>> +
>> + host->fifoth_val = MSIZE(0x2) |
>> + RX_WMARK(priv->fifo_size / 2 - 1) |
>> + TX_WMARK(priv->fifo_size / 2);
>> +
>> + host->fifo_mode = priv->fifo_mode;
>> +
>> + dwmci_setup_cfg(&plat->cfg, host, priv->max_freq, priv->min_freq);
>> + host->mmc = &plat->mmc;
>> + host->mmc->priv = &priv->host;
>> + host->mmc->dev = dev;
>> + upriv->mmc = host->mmc;
>> +
>> + nx_dw_mmc_set_pin(host);
>> +
>> + debug(" nx_dw_mmc_set_clk(host, frequency * 4 == %d)\n",
>> + priv->frequency * 4);
>> + nx_dw_mmc_set_clk(host, priv->frequency * 4);
>> +
>> + nx_dw_mmc_reset(host->dev_index);
>> + nx_dw_mmc_clk_delay(dev);
>> +
>> + return dwmci_probe(dev);
>> +}
>> +
>> +static int nexell_dwmmc_bind(struct udevice *dev)
>> +{
>> + struct nexell_mmc_plat *plat = dev_get_platdata(dev);
>> +
>> + return dwmci_bind(dev, &plat->mmc, &plat->cfg);
>> +}
>> +
>> +static const struct udevice_id nexell_dwmmc_ids[] = {
>> + { .compatible = "nexell,nexell-dwmmc" },
>> + { }
>> +};
>> +
>> +U_BOOT_DRIVER(nexell_dwmmc_drv) = {
>> + .name = "nexell_dwmmc",
>> + .id = UCLASS_MMC,
>> + .of_match = nexell_dwmmc_ids,
>> + .ofdata_to_platdata = nexell_dwmmc_ofdata_to_platdata,
>> + .ops = &dm_dwmci_ops,
>> + .bind = nexell_dwmmc_bind,
>> + .probe = nexell_dwmmc_probe,
>> + .priv_auto_alloc_size = sizeof(struct nexell_dwmmc_priv),
>> + .platdata_auto_alloc_size = sizeof(struct nexell_mmc_plat),
>> +};
>> diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
>> index a837c35..b45aada 100644
>> --- a/drivers/pwm/Makefile
>> +++ b/drivers/pwm/Makefile
>> @@ -16,3 +16,4 @@ obj-$(CONFIG_PWM_ROCKCHIP) += rk_pwm.o
>> obj-$(CONFIG_PWM_SANDBOX) += sandbox_pwm.o
>> obj-$(CONFIG_PWM_TEGRA) += tegra_pwm.o
>> obj-$(CONFIG_PWM_SUNXI) += sunxi_pwm.o
>> +obj-$(CONFIG_PWM_NX) += pwm-nexell.o
>> diff --git a/drivers/pwm/pwm-nexell.c b/drivers/pwm/pwm-nexell.c
>> new file mode 100644
>> index 0000000..6c0f8f4
>> --- /dev/null
>> +++ b/drivers/pwm/pwm-nexell.c
>> @@ -0,0 +1,252 @@
>> +// SPDX-License-Identifier: GPL-2.0+
>> +/*
>> + * Copyright (C) 2011 Samsung Electronics
>> + *
>> + * Donghwa Lee <dh09.lee@samsung.com>
>> + */
>> +
>> +/* This codes are copied from arch/arm/cpu/armv7/s5p-common/pwm.c */
>> +
>> +#include <common.h>
>> +#include <errno.h>
>> +#include <pwm.h>
>> +#include <asm/io.h>
>> +#include <asm/arch/clk.h>
>> +#include "pwm-nexell.h"
>> +
>> +#if defined(CONFIG_ARCH_NEXELL)
>> +#include <asm/arch/nexell.h>
>> +#include <asm/arch/reset.h>
>> +#include <asm/arch/nx_gpio.h>
>> +#include <asm/arch/tieoff.h>
>> +
>> +struct pwm_device {
>> + int ch;
>> + int grp;
>> + int bit;
>> + int pwm_fn;
>> +};
>> +
>> +static struct pwm_device pwm_dev[] = {
>> + [0] = { .ch = 0, .grp = 3, .bit = 1, .pwm_fn = 1 },
>> + [1] = { .ch = 1, .grp = 2, .bit = 13, .pwm_fn = 2 },
>> + [2] = { .ch = 2, .grp = 2, .bit = 14, .pwm_fn = 2 },
>> + [3] = { .ch = 3, .grp = 3, .bit = 0, .pwm_fn = 2 },
>> +};
>> +#endif
>> +
>> +int pwm_enable(int pwm_id)
>> +{
>> + const struct s5p_timer *pwm =
>> +#if defined(CONFIG_ARCH_NEXELL)
>> + (struct s5p_timer *)PHY_BASEADDR_PWM;
>> +#else
>> + (struct s5p_timer *)samsung_get_base_timer();
>> +#endif
>> + unsigned long tcon;
>> +
>> + tcon = readl(&pwm->tcon);
>> + tcon |= TCON_START(pwm_id);
>> +
>> + writel(tcon, &pwm->tcon);
>> +
>> + return 0;
>> +}
>> +
>> +void pwm_disable(int pwm_id)
>> +{
>> + const struct s5p_timer *pwm =
>> +#if defined(CONFIG_ARCH_NEXELL)
>> + (struct s5p_timer *)PHY_BASEADDR_PWM;
>> +#else
>> + (struct s5p_timer *)samsung_get_base_timer();
>> +#endif
>> + unsigned long tcon;
>> +
>> + tcon = readl(&pwm->tcon);
>> + tcon &= ~TCON_START(pwm_id);
>> +
>> + writel(tcon, &pwm->tcon);
>> +}
>> +
>> +static unsigned long pwm_calc_tin(int pwm_id, unsigned long freq)
>> +{
>> + unsigned long tin_parent_rate;
>> + unsigned int div;
>> +#if defined(CONFIG_ARCH_NEXELL)
>> + unsigned int pre_div;
>> + const struct s5p_timer *pwm =
>> + (struct s5p_timer *)PHY_BASEADDR_PWM;
>> + unsigned int val;
>> +#endif
>> +
>> +#if defined(CONFIG_ARCH_NEXELL)
>> + struct clk *clk = clk_get(CORECLK_NAME_PCLK);
>> +
>> + tin_parent_rate = clk_get_rate(clk);
>> +#else
>> + tin_parent_rate = get_pwm_clk();
>> +#endif
>> +
>> +#if defined(CONFIG_ARCH_NEXELL)
>> + writel(0, &pwm->tcfg0);
>> + val = readl(&pwm->tcfg0);
>> +
>> + if (pwm_id < 2)
>> + div = ((val >> 0) & 0xff) + 1;
>> + else
>> + div = ((val >> 8) & 0xff) + 1;
>> +
>> + writel(0, &pwm->tcfg1);
>> + val = readl(&pwm->tcfg1);
>> + val = (val >> MUX_DIV_SHIFT(pwm_id)) & 0xF;
>> + pre_div = (1UL << val);
>> +
>> + freq = tin_parent_rate / div / pre_div;
>> +
>> + return freq;
>> +#else
>> + for (div = 2; div <= 16; div *= 2) {
>> + if ((tin_parent_rate / (div << 16)) < freq)
>> + return tin_parent_rate / div;
>> + }
>> +
>> + return tin_parent_rate / 16;
>> +#endif
>> +}
>> +
>> +#define NS_IN_SEC 1000000000UL
>> +
>> +int pwm_config(int pwm_id, int duty_ns, int period_ns)
>> +{
>> + const struct s5p_timer *pwm =
>> +#if defined(CONFIG_ARCH_NEXELL)
>> + (struct s5p_timer *)PHY_BASEADDR_PWM;
>> +#else
>> + (struct s5p_timer *)samsung_get_base_timer();
>> +#endif
>> + unsigned int offset;
>> + unsigned long tin_rate;
>> + unsigned long tin_ns;
>> + unsigned long frequency;
>> + unsigned long tcon;
>> + unsigned long tcnt;
>> + unsigned long tcmp;
>> +
>> + /*
>> + * We currently avoid using 64bit arithmetic by using the
>> + * fact that anything faster than 1GHz is easily representable
>> + * by 32bits.
>> + */
>> + if (period_ns > NS_IN_SEC || duty_ns > NS_IN_SEC || period_ns == 0)
>> + return -ERANGE;
>> +
>> + if (duty_ns > period_ns)
>> + return -EINVAL;
>> +
>> + frequency = NS_IN_SEC / period_ns;
>> +
>> + /* Check to see if we are changing the clock rate of the PWM */
>> + tin_rate = pwm_calc_tin(pwm_id, frequency);
>> +
>> + tin_ns = NS_IN_SEC / tin_rate;
>> +#if defined(CONFIG_ARCH_NEXELL)
>> + /* The counter starts at zero. */
>> + tcnt = (period_ns / tin_ns) - 1;
>> +#else
>> + tcnt = period_ns / tin_ns;
>> +#endif
>> +
>> + /* Note, counters count down */
>> + tcmp = duty_ns / tin_ns;
>> + tcmp = tcnt - tcmp;
>> +
>> + /* Update the PWM register block. */
>> + offset = pwm_id * 3;
>> + if (pwm_id < 4) {
>> + writel(tcnt, &pwm->tcntb0 + offset);
>> + writel(tcmp, &pwm->tcmpb0 + offset);
>> + }
>> +
>> + tcon = readl(&pwm->tcon);
>> + tcon |= TCON_UPDATE(pwm_id);
>> + if (pwm_id < 4)
>> + tcon |= TCON_AUTO_RELOAD(pwm_id);
>> + else
>> + tcon |= TCON4_AUTO_RELOAD;
>> + writel(tcon, &pwm->tcon);
>> +
>> + tcon &= ~TCON_UPDATE(pwm_id);
>> + writel(tcon, &pwm->tcon);
>> +
>> + return 0;
>> +}
>> +
>> +int pwm_init(int pwm_id, int div, int invert)
>> +{
>> + u32 val;
>> + const struct s5p_timer *pwm =
>> +#if defined(CONFIG_ARCH_NEXELL)
>> + (struct s5p_timer *)PHY_BASEADDR_PWM;
>> +#else
>> + (struct s5p_timer *)samsung_get_base_timer();
>> +#endif
>> + unsigned long ticks_per_period;
>> + unsigned int offset, prescaler;
>> +
>> + /*
>> + * Timer Freq(HZ) =
>> + * PWM_CLK / { (prescaler_value + 1) * (divider_value) }
>> + */
>> +
>> + val = readl(&pwm->tcfg0);
>> + if (pwm_id < 2) {
>> + prescaler = PRESCALER_0;
>> + val &= ~0xff;
>> + val |= (prescaler & 0xff);
>> + } else {
>> + prescaler = PRESCALER_1;
>> + val &= ~(0xff << 8);
>> + val |= (prescaler & 0xff) << 8;
>> + }
>> + writel(val, &pwm->tcfg0);
>> + val = readl(&pwm->tcfg1);
>> + val &= ~(0xf << MUX_DIV_SHIFT(pwm_id));
>> + val |= (div & 0xf) << MUX_DIV_SHIFT(pwm_id);
>> + writel(val, &pwm->tcfg1);
>> +
>> + if (pwm_id == 4) {
>> + /*
>> + * TODO(sjg): Use this as a countdown timer for now. We count
>> + * down from the maximum value to 0, then reset.
>> + */
>> + ticks_per_period = -1UL;
>> + } else {
>> + const unsigned long pwm_hz = 1000;
>> +#if defined(CONFIG_ARCH_NEXELL)
>> + struct clk *clk = clk_get(CORECLK_NAME_PCLK);
>> + unsigned long timer_rate_hz = clk_get_rate(clk) /
>> +#else
>> + unsigned long timer_rate_hz = get_pwm_clk() /
>> +#endif
>> + ((prescaler + 1) * (1 << div));
>> +
>> + ticks_per_period = timer_rate_hz / pwm_hz;
>> + }
>> +
>> + /* set count value */
>> + offset = pwm_id * 3;
>> +
>> + writel(ticks_per_period, &pwm->tcntb0 + offset);
>> +
>> + val = readl(&pwm->tcon) & ~(0xf << TCON_OFFSET(pwm_id));
>> + if (invert && pwm_id < 4)
>> + val |= TCON_INVERTER(pwm_id);
>> + writel(val, &pwm->tcon);
>> +
>> + nx_gpio_set_pad_function(pwm_dev[pwm_id].grp, pwm_dev[pwm_id].bit,
>> + pwm_dev[pwm_id].pwm_fn);
>> + pwm_enable(pwm_id);
>> +
>> + return 0;
>> +}
>> diff --git a/drivers/pwm/pwm-nexell.h b/drivers/pwm/pwm-nexell.h
>> new file mode 100644
>> index 0000000..92dc707
>> --- /dev/null
>> +++ b/drivers/pwm/pwm-nexell.h
>> @@ -0,0 +1,54 @@
>> +/* SPDX-License-Identifier: GPL-2.0+
>> + *
>> + * Copyright (C) 2009 Samsung Electronics
>> + * Kyungmin Park <kyungmin.park@samsung.com>
>> + * Minkyu Kang <mk7.kang@samsung.com>
>> + */
>> +
>> +#ifndef __ASM_ARM_ARCH_PWM_H_
>> +#define __ASM_ARM_ARCH_PWM_H_
>> +
>> +#define PRESCALER_0 (8 - 1) /* prescaler of timer 0, 1 */
>> +#define PRESCALER_1 (16 - 1) /* prescaler of timer 2, 3, 4 */
>> +
>> +/* Divider MUX */
>> +#define MUX_DIV_1 0 /* 1/1 period */
>> +#define MUX_DIV_2 1 /* 1/2 period */
>> +#define MUX_DIV_4 2 /* 1/4 period */
>> +#define MUX_DIV_8 3 /* 1/8 period */
>> +#define MUX_DIV_16 4 /* 1/16 period */
>> +
>> +#define MUX_DIV_SHIFT(x) ((x) * 4)
>> +
>> +#define TCON_OFFSET(x) (((x) + 1) * (!!x) << 2)
>> +
>> +#define TCON_START(x) (1 << TCON_OFFSET(x))
>> +#define TCON_UPDATE(x) (1 << (TCON_OFFSET(x) + 1))
>> +#define TCON_INVERTER(x) (1 << (TCON_OFFSET(x) + 2))
>> +#define TCON_AUTO_RELOAD(x) (1 << (TCON_OFFSET(x) + 3))
>> +#define TCON4_AUTO_RELOAD (1 << 22)
>> +
>> +#ifndef __ASSEMBLY__
>> +struct s5p_timer {
>> + unsigned int tcfg0;
>> + unsigned int tcfg1;
>> + unsigned int tcon;
>> + unsigned int tcntb0;
>> + unsigned int tcmpb0;
>> + unsigned int tcnto0;
>> + unsigned int tcntb1;
>> + unsigned int tcmpb1;
>> + unsigned int tcnto1;
>> + unsigned int tcntb2;
>> + unsigned int tcmpb2;
>> + unsigned int tcnto2;
>> + unsigned int tcntb3;
>> + unsigned int res1;
>> + unsigned int tcnto3;
>> + unsigned int tcntb4;
>> + unsigned int tcnto4;
>> + unsigned int tintcstat;
>> +};
>> +#endif /* __ASSEMBLY__ */
>> +
>> +#endif
>>
>
^ permalink raw reply [flat|nested] 19+ messages in thread
* [RFC PATCH 09/10] arm: add support for SoC s5p4418 (cpu) / nanopi2 board
2020-02-03 20:46 ` [RFC PATCH 09/10] arm: add support for SoC s5p4418 (cpu) / nanopi2 board Stefan Bosch
@ 2020-02-07 16:10 ` Tom Rini
0 siblings, 0 replies; 19+ messages in thread
From: Tom Rini @ 2020-02-07 16:10 UTC (permalink / raw)
To: u-boot
On Mon, Feb 03, 2020 at 09:46:39PM +0100, Stefan Bosch wrote:
> Changes in relation to FriendlyARM's U-Boot nanopi2-v2016.01:
> - SPL not supported yet --> no spl-dir in arch/arm/cpu/armv7/s5p4418/.
> Appropriate line in Makefile removed.
> - cpu.c: '#include <cpu_func.h>' added.
> - arch/arm/cpu/armv7/s5p4418/u-boot.lds removed, is not required
> anylonger.
> - s5p4418.dtsi: '#include "../../../include/generated/autoconf.h"'
> removed, is not necessary, error at out-of-tree building.
> '#ifdef CONFIG_CPU_NXP4330'-blocks (2x) removed. Some minor changes
> regarding mmc. 'u-boot,dm-pre-reloc' added to dp0 because of added
> DM_VIDEO support.
> - board/s5p4418/ renamed to board/friendlyarm/
> - All s5p4418-boards except nanopi2 removed because there is no
> possibility to test the other boards.
> - Kconfig: Changes to have a structure like mach-bcm283x (RaspberryPi),
> e.g. "config ..." entries moved from/to other Kconfig.
> - "CONFIG_" removed from several s5p4418/nanopi2 specific defines
> because the appropriate values do not need to be configurable.
> - nanopi2/board.c: All getenv(), getenv_ulong(), setenv() and saveenv()
> renamed to env_get(), env_get_ulong(), env_set() and env_save(),
> respectively. MACH_TYPE_S5P4418 is not defined anymore, therefore
> appropriate code removed (not necessary for DT-kernels).
> - nanopi2/onewire.c: All crc8() renamed to crc8_ow() because crc8() is
> already defined in lib/crc8.c (with different parameters).
>
> Signed-off-by: Stefan Bosch <stefan_b@posteo.net>
> ---
>
> arch/arm/cpu/armv7/Makefile | 1 +
> arch/arm/cpu/armv7/s5p4418/Makefile | 6 +
> arch/arm/cpu/armv7/s5p4418/cpu.c | 120 ++++++
> arch/arm/dts/Makefile | 3 +
> arch/arm/dts/s5p4418-nanopi2.dts | 109 ++++++
> arch/arm/dts/s5p4418-pinctrl.dtsi | 66 ++++
> arch/arm/dts/s5p4418.dtsi | 157 ++++++++
Please do the DTS files in their own commit and note what kernel release
they're from. Thanks!
--
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <https://lists.denx.de/pipermail/u-boot/attachments/20200207/d4574cc9/attachment.sig>
^ permalink raw reply [flat|nested] 19+ messages in thread
* [RFC PATCH 00/10] arm: add support for SoC S5P4418
2020-02-03 19:39 [RFC PATCH 00/10] arm: add support for SoC S5P4418 Stefan Bosch
` (9 preceding siblings ...)
2020-02-03 20:47 ` [RFC PATCH 10/10] arm: add (default) config for " Stefan Bosch
@ 2020-02-07 16:11 ` Tom Rini
2020-02-22 13:06 ` Amit Tomer
11 siblings, 0 replies; 19+ messages in thread
From: Tom Rini @ 2020-02-07 16:11 UTC (permalink / raw)
To: u-boot
On Mon, Feb 03, 2020 at 08:39:22PM +0100, Stefan Bosch wrote:
> This patch adds support for SAMSUNG's/NEXELL's ARM Cortex-A9 based
> S5P4418 SoC, especially FriendlyARM's NanoPi2 and NanoPC-T2 boards.
> It is based on the following FriendlyARM's U-Boot version:
> https://github.com/friendlyarm/u-boot/tree/nanopi2-v2016.01.
>
> The added mach-nexell also supports the S5P6818 SoC which is a
> follow-up of the S5P4418.
>
> Main changes in relation to nanopi2-v2016.01:
> - Cosmetic changes due to patman warnings/errors.
> - MMC and Video drivers changed to DM.
> - Configs reworked (e.g. "CONFIG_..." moved from s5p4418_nanopi2.h
> to s5p4418_nanopi2_defconfig)
> - SPL related files are not included.
> - MACH_TYPE_S5P4418 is not defined/used anymore.
> - arch/arm/mach-nexell/include/mach/boot0.h added to generate the NSIH
> (Nexell System Information Header), substitudes tools/nexell.
> - board/s5p4418/ renamed to board/friendlyarm/
> - Only the NanoPi2 and NanoPC-T2 boards are supported yet because I
> do only have the NanoPC-T2 board to test the code (this board uses
> the NanoPi2 code).
>
>
> Stefan Bosch (10):
> arm: add mach-nexell (header files)
> arm: add mach-nexell (all files except header files)
> i2c: mmc: add nexell driver (gpio, i2c, mmc, pwm)
> video: add nexell video driver (soc: displaytop)
> video: add nexell video driver (soc: mlc, mipi)
> video: add nexell video driver (soc: lvds, hdmi)
> video: add nexell video driver (soc: dpc, makefile)
> video: add nexell video driver (display/video driver)
> arm: add support for SoC s5p4418 (cpu) / nanopi2 board
> arm: add (default) config for nanopi2 board
In general:
- Make sure everything is checkpatch clean (or when not, explainable).
- Don't include unused (by the end of the series at least) code.
- Don't include both SPDX tags and then the whole license boilerplate.
- Do make sure that there's nothing in the config.h file that should be
in a _defconfig file at this point.
Thanks!
--
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <https://lists.denx.de/pipermail/u-boot/attachments/20200207/1da83665/attachment.sig>
^ permalink raw reply [flat|nested] 19+ messages in thread
* [RFC PATCH 03/10] i2c: mmc: add nexell driver (gpio, i2c, mmc, pwm)
2020-02-04 6:58 ` Heiko Schocher
2020-02-04 18:29 ` Stefan B.
@ 2020-02-20 17:49 ` Stefan B.
2020-02-22 12:34 ` Heiko Schocher
1 sibling, 1 reply; 19+ messages in thread
From: Stefan B. @ 2020-02-20 17:49 UTC (permalink / raw)
To: u-boot
Hello Heiko,
see below my feedback, please give me further advise where indicated.
Unfortunately there have been some Bugs in the i2c-driver and I learned
that this driver has not been used at all ("i2c-gpio" has been used
instead). So I have done several Bugfixes and improvements appart from
your proposals.
Regards
Stefan
Am 04.02.20 um 07:58 schrieb Heiko Schocher:
> Hello Stefan,
>
> Am 03.02.2020 um 21:40 schrieb Stefan Bosch:
>> Changes in relation to FriendlyARM's U-Boot nanopi2-v2016.01:
>> - i2c/nx_i2c.c: Some adaptions mainly because of changes in
>> ?? "struct udevice".
>> - mmc: nexell_dw_mmc.c changed to nexell_dw_mmc_dm.c (switched to DM).
>>
>> Signed-off-by: Stefan Bosch <stefan_b@posteo.net>
>> ---
>>
>> ? drivers/gpio/Kconfig?????????? |?? 9 +
>> ? drivers/gpio/Makefile????????? |?? 1 +
>> ? drivers/gpio/nx_gpio.c???????? | 252 +++++++++++++++++++
>> ? drivers/i2c/Kconfig??????????? |?? 9 +
>> ? drivers/i2c/Makefile?????????? |?? 1 +
>> ? drivers/i2c/nx_i2c.c?????????? | 537
>> +++++++++++++++++++++++++++++++++++++++++
>> ? drivers/mmc/Kconfig??????????? |?? 6 +
>> ? drivers/mmc/Makefile?????????? |?? 1 +
>> ? drivers/mmc/nexell_dw_mmc_dm.c | 350 +++++++++++++++++++++++++++
>> ? drivers/pwm/Makefile?????????? |?? 1 +
>> ? drivers/pwm/pwm-nexell.c?????? | 252 +++++++++++++++++++
>> ? drivers/pwm/pwm-nexell.h?????? |? 54 +++++
>
> Could you please split this patch into 4 parts (i2c, gpio, mmc and
> pwm) ?
>
> Thanks!
>
Ok, I will split this patch.
>> ? 12 files changed, 1473 insertions(+)
>> ? create mode 100644 drivers/gpio/nx_gpio.c
>> ? create mode 100644 drivers/i2c/nx_i2c.c
>> ? create mode 100644 drivers/mmc/nexell_dw_mmc_dm.c
>> ? create mode 100644 drivers/pwm/pwm-nexell.c
>> ? create mode 100644 drivers/pwm/pwm-nexell.h
>>
> [...]
>> diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
>> index 449046b..e3340de 100644
>> --- a/drivers/gpio/Makefile
>> +++ b/drivers/gpio/Makefile
>> @@ -65,3 +65,4 @@ obj-$(CONFIG_PM8916_GPIO)??? += pm8916_gpio.o
>> ? obj-$(CONFIG_MT7621_GPIO)??? += mt7621_gpio.o
>> ? obj-$(CONFIG_MSCC_SGPIO)??? += mscc_sgpio.o
>> ? obj-$(CONFIG_SIFIVE_GPIO)??? += sifive-gpio.o
>> +obj-$(CONFIG_NX_GPIO)??????? += nx_gpio.o
>
> Please keep lists sorted.
The list is not sorted (at least in no alphabetical order), but I can
e.g. move "... += nx_gpio.o" one line up?
>
>> diff --git a/drivers/gpio/nx_gpio.c b/drivers/gpio/nx_gpio.c
>> new file mode 100644
>> index 0000000..86472f6
>> --- /dev/null
>> +++ b/drivers/gpio/nx_gpio.c
>> @@ -0,0 +1,252 @@
>> +// SPDX-License-Identifier: GPL-2.0+
>> +/*
>> + * (C) Copyright 2016 Nexell
>> + * DeokJin, Lee <truevirtue@nexell.co.kr>
>> + */
>> +
>> +#include <common.h>
>> +#include <dm.h>
>> +#include <errno.h>
>> +#include <malloc.h>
>> +#include <fdtdec.h>
>> +#include <asm/io.h>
>> +#include <asm/gpio.h>
>> +
>> +DECLARE_GLOBAL_DATA_PTR;
>> +
>> +struct nx_gpio_regs {
>> +??? u32??? data;??????? /* Data register */
>> +??? u32??? outputenb;??? /* Output Enable register */
>> +??? u32??? detmode[2];??? /* Detect Mode Register */
>> +??? u32??? intenb;??????? /* Interrupt Enable Register */
>> +??? u32??? det;??????? /* Event Detect Register */
>> +??? u32??? pad;??????? /* Pad Status Register */
>> +};
>> +
>> +struct nx_alive_gpio_regs {
>> +??? u32??? pwrgate;??? /* Power Gating Register */
>> +??? u32??? reserved0[28];??? /* Reserved0 */
>> +??? u32??? outputenb_reset;/* Alive GPIO Output Enable Reset Register */
>> +??? u32??? outputenb;??? /* Alive GPIO Output Enable Register */
>> +??? u32??? outputenb_read; /* Alive GPIO Output Read Register */
>> +??? u32??? reserved1[3];??? /* Reserved1 */
>> +??? u32??? pad_reset;??? /* Alive GPIO Output Reset Register */
>> +??? u32??? data;??????? /* Alive GPIO Output Register */
>> +??? u32??? pad_read;??? /* Alive GPIO Pad Read Register */
>> +??? u32??? reserved2[33];??? /* Reserved2 */
>> +??? u32??? pad;??????? /* Alive GPIO Input Value Register */
>> +};
>> +
>> +struct nx_gpio_platdata {
>> +??? void *regs;
>> +??? int gpio_count;
>> +??? const char *bank_name;
>> +};
>> +
>> +static int nx_alive_gpio_is_check(struct udevice *dev)
>> +{
>> +??? struct nx_gpio_platdata *plat = dev_get_platdata(dev);
>> +??? const char *bank_name = plat->bank_name;
>> +
>> +??? if (!strcmp(bank_name, "gpio_alv"))
>> +??????? return 1;
>> +
>> +??? return 0;
>> +}
>> +
>> +static int nx_alive_gpio_direction_input(struct udevice *dev,
>> unsigned int pin)
>> +{
>> +??? struct nx_gpio_platdata *plat = dev_get_platdata(dev);
>> +??? struct nx_alive_gpio_regs *const regs = plat->regs;
>> +
>> +??? setbits_le32(®s->outputenb_reset, 1 << pin);
>> +
>> +??? return 0;
>> +}
>> +
>> +static int nx_alive_gpio_direction_output(struct udevice *dev,
>> unsigned int pin,
>> +????????????????????? int val)
>> +{
>> +??? struct nx_gpio_platdata *plat = dev_get_platdata(dev);
>> +??? struct nx_alive_gpio_regs *const regs = plat->regs;
>> +
>> +??? if (val)
>> +??????? setbits_le32(®s->data, 1 << pin);
>> +??? else
>> +??????? setbits_le32(®s->pad_reset, 1 << pin);
>> +
>> +??? setbits_le32(®s->outputenb, 1 << pin);
>> +
>> +??? return 0;
>> +}
>> +
>> +static int nx_alive_gpio_get_value(struct udevice *dev, unsigned int
>> pin)
>> +{
>> +??? struct nx_gpio_platdata *plat = dev_get_platdata(dev);
>> +??? struct nx_alive_gpio_regs *const regs = plat->regs;
>> +??? unsigned int mask = 1UL << pin;
>> +??? unsigned int value;
>> +
>> +??? value = (readl(®s->pad_read) & mask) >> pin;
>> +
>> +??? return value;
>> +}
>> +
>> +static int nx_alive_gpio_set_value(struct udevice *dev, unsigned int
>> pin,
>> +?????????????????? int val)
>> +{
>> +??? struct nx_gpio_platdata *plat = dev_get_platdata(dev);
>> +??? struct nx_alive_gpio_regs *const regs = plat->regs;
>> +
>> +??? if (val)
>> +??????? setbits_le32(®s->data, 1 << pin);
>> +??? else
>> +??????? clrbits_le32(®s->pad_reset, 1 << pin);
>> +
>> +??? return 0;
>> +}
>> +
>> +static int nx_alive_gpio_get_function(struct udevice *dev, unsigned
>> int pin)
>> +{
>> +??? struct nx_gpio_platdata *plat = dev_get_platdata(dev);
>> +??? struct nx_alive_gpio_regs *const regs = plat->regs;
>> +??? unsigned int mask = (1UL << pin);
>> +??? unsigned int output;
>> +
>> +??? output = readl(®s->outputenb_read) & mask;
>> +
>> +??? if (output)
>> +??????? return GPIOF_OUTPUT;
>> +??? else
>> +??????? return GPIOF_INPUT;
>> +}
>> +
>> +static int nx_gpio_direction_input(struct udevice *dev, unsigned int
>> pin)
>> +{
>> +??? struct nx_gpio_platdata *plat = dev_get_platdata(dev);
>> +??? struct nx_gpio_regs *const regs = plat->regs;
>> +
>> +??? if (nx_alive_gpio_is_check(dev))
>> +??????? return nx_alive_gpio_direction_input(dev, pin);
>> +
>> +??? clrbits_le32(®s->outputenb, 1 << pin);
>> +
>> +??? return 0;
>> +}
>> +
>> +static int nx_gpio_direction_output(struct udevice *dev, unsigned int
>> pin,
>> +??????????????????? int val)
>> +{
>> +??? struct nx_gpio_platdata *plat = dev_get_platdata(dev);
>> +??? struct nx_gpio_regs *const regs = plat->regs;
>> +
>> +??? if (nx_alive_gpio_is_check(dev))
>> +??????? return nx_alive_gpio_direction_output(dev, pin, val);
>> +
>> +??? if (val)
>> +??????? setbits_le32(®s->data, 1 << pin);
>> +??? else
>> +??????? clrbits_le32(®s->data, 1 << pin);
>> +
>> +??? setbits_le32(®s->outputenb, 1 << pin);
>> +
>> +??? return 0;
>> +}
>> +
>> +static int nx_gpio_get_value(struct udevice *dev, unsigned int pin)
>> +{
>> +??? struct nx_gpio_platdata *plat = dev_get_platdata(dev);
>> +??? struct nx_gpio_regs *const regs = plat->regs;
>> +??? unsigned int mask = 1UL << pin;
>> +??? unsigned int value;
>> +
>> +??? if (nx_alive_gpio_is_check(dev))
>> +??????? return nx_alive_gpio_get_value(dev, pin);
>> +
>> +??? value = (readl(®s->pad) & mask) >> pin;
>> +
>> +??? return value;
>> +}
>> +
>> +static int nx_gpio_set_value(struct udevice *dev, unsigned int pin,
>> int val)
>> +{
>> +??? struct nx_gpio_platdata *plat = dev_get_platdata(dev);
>> +??? struct nx_gpio_regs *const regs = plat->regs;
>> +
>> +??? if (nx_alive_gpio_is_check(dev))
>> +??????? return nx_alive_gpio_set_value(dev, pin, val);
>> +
>> +??? if (val)
>> +??????? setbits_le32(®s->data, 1 << pin);
>> +??? else
>> +??????? clrbits_le32(®s->data, 1 << pin);
>> +
>> +??? return 0;
>> +}
>> +
>> +static int nx_gpio_get_function(struct udevice *dev, unsigned int pin)
>> +{
>> +??? struct nx_gpio_platdata *plat = dev_get_platdata(dev);
>> +??? struct nx_gpio_regs *const regs = plat->regs;
>> +??? unsigned int mask = (1UL << pin);
>> +??? unsigned int output;
>> +
>> +??? if (nx_alive_gpio_is_check(dev))
>> +??????? return nx_alive_gpio_get_function(dev, pin);
>> +
>> +??? output = readl(®s->outputenb) & mask;
>> +
>> +??? if (output)
>> +??????? return GPIOF_OUTPUT;
>> +??? else
>> +??????? return GPIOF_INPUT;
>> +}
>> +
>> +static int nx_gpio_probe(struct udevice *dev)
>> +{
>> +??? struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
>> +??? struct nx_gpio_platdata *plat = dev_get_platdata(dev);
>> +
>> +??? uc_priv->gpio_count = plat->gpio_count;
>> +??? uc_priv->bank_name = plat->bank_name;
>> +
>> +??? return 0;
>> +}
>> +
>> +static int nx_gpio_ofdata_to_platdata(struct udevice *dev)
>> +{
>> +??? struct nx_gpio_platdata *plat = dev_get_platdata(dev);
>> +
>> +??? plat->regs = map_physmem(devfdt_get_addr(dev),
>> +???????????????? sizeof(struct nx_gpio_regs),
>> +???????????????? MAP_NOCACHE);
>> +??? plat->gpio_count = fdtdec_get_int(gd->fdt_blob, dev->node.of_offset,
>> +????????????????????? "nexell,gpio-bank-width", 32);
>> +??? plat->bank_name = fdt_getprop(gd->fdt_blob, dev->node.of_offset,
>> +????????????????????? "gpio-bank-name", NULL);
>> +
>> +??? return 0;
>> +}
>> +
>> +static const struct dm_gpio_ops nx_gpio_ops = {
>> +??? .direction_input??? = nx_gpio_direction_input,
>> +??? .direction_output??? = nx_gpio_direction_output,
>> +??? .get_value??????? = nx_gpio_get_value,
>> +??? .set_value??????? = nx_gpio_set_value,
>> +??? .get_function??????? = nx_gpio_get_function,
>> +};
>> +
>> +static const struct udevice_id nx_gpio_ids[] = {
>> +??? { .compatible = "nexell,nexell-gpio" },
>> +??? { }
>> +};
>> +
>> +U_BOOT_DRIVER(nx_gpio) = {
>> +??? .name??????? = "nx_gpio",
>> +??? .id??????? = UCLASS_GPIO,
>> +??? .of_match??? = nx_gpio_ids,
>> +??? .ops??????? = &nx_gpio_ops,
>> +??? .ofdata_to_platdata = nx_gpio_ofdata_to_platdata,
>> +??? .platdata_auto_alloc_size = sizeof(struct nx_gpio_platdata),
>> +??? .probe??????? = nx_gpio_probe,
>> +};
>> diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
>> index 03d2fed..2cd0ed3 100644
>> --- a/drivers/i2c/Kconfig
>> +++ b/drivers/i2c/Kconfig
>> @@ -317,6 +317,15 @@ config SYS_MXC_I2C8_SLAVE
>> ?????? MXC I2C8 Slave
>> ? endif
>> +config SYS_I2C_NEXELL
>> +??? bool "Nexell I2C driver"
>> +??? depends on DM_I2C
>> +??? help
>> +????? Add support for the Nexell I2C driver. This is used with various
>> +????? Nexell parts such as S5Pxx18 series SoCs. All chips
>> +????? have several I2C ports and all are provided, controlled by the
>> +????? device tree.
>> +
>> ? config SYS_I2C_OMAP24XX
>> ????? bool "TI OMAP2+ I2C driver"
>> ????? depends on ARCH_OMAP2PLUS || ARCH_K3
>> diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
>> index f5a471f..64b8ead 100644
>> --- a/drivers/i2c/Makefile
>> +++ b/drivers/i2c/Makefile
>> @@ -26,6 +26,7 @@ obj-$(CONFIG_SYS_I2C_LPC32XX) += lpc32xx_i2c.o
>> ? obj-$(CONFIG_SYS_I2C_MESON) += meson_i2c.o
>> ? obj-$(CONFIG_SYS_I2C_MVTWSI) += mvtwsi.o
>> ? obj-$(CONFIG_SYS_I2C_MXC) += mxc_i2c.o
>> +obj-$(CONFIG_SYS_I2C_NEXELL) += nx_i2c.o
>> ? obj-$(CONFIG_SYS_I2C_OMAP24XX) += omap24xx_i2c.o
>> ? obj-$(CONFIG_SYS_I2C_RCAR_I2C) += rcar_i2c.o
>> ? obj-$(CONFIG_SYS_I2C_RCAR_IIC) += rcar_iic.o
>> diff --git a/drivers/i2c/nx_i2c.c b/drivers/i2c/nx_i2c.c
>> new file mode 100644
>> index 0000000..a3eec6c
>> --- /dev/null
>> +++ b/drivers/i2c/nx_i2c.c
>> @@ -0,0 +1,537 @@
>> +#include <common.h>
>> +#include <errno.h>
>> +#include <dm.h>
>> +#include <i2c.h>
>> +#include <asm/arch/nexell.h>
>> +#include <asm/arch/reset.h>
>> +#include <asm/arch/clk.h>
>> +#include <asm/arch/nx_gpio.h>
>> +
>> +#define I2C_WRITE?????? 0
>> +#define I2C_READ??????? 1
>> +
>> +#define I2C_OK????????? 0
>> +#define I2C_NOK???????? 1
>> +#define I2C_NACK??????? 2
>> +#define I2C_NOK_LA????? 3?????? /* Lost arbitration */
>> +#define I2C_NOK_TOUT??? 4?????? /* time out */
>> +
>> +#define I2CLC_FILTER??? 0x04??? /* SDA filter on*/
>> +#define I2CSTAT_BSY???? 0x20??? /* Busy bit */
>> +#define I2CSTAT_NACK??? 0x01??? /* Nack bit */
>> +#define I2CSTAT_ABT??? 0x08??? /* Arbitration bit */
>> +#define I2CCON_ACKGEN?? 0x80??? /* Acknowledge generation */
>> +#define I2CCON_IRENB??? 0x20??? /* Interrupt Enable bit? */
>> +#define I2CCON_IRPND??? 0x10??? /* Interrupt pending bit */
>> +#define I2C_MODE_MT???? 0xC0??? /* Master Transmit Mode */
>> +#define I2C_MODE_MR???? 0x80??? /* Master Receive Mode */
>> +#define I2C_START_STOP? 0x20??? /* START / STOP */
>> +#define I2C_TXRX_ENA??? 0x10??? /* I2C Tx/Rx enable */
>> +
>> +#define I2C_TIMEOUT_MS??? 10????? /* 10 ms */
>> +
>> +#define I2C_M_NOSTOP??? 0x100
>> +
>> +#ifndef CONFIG_MAX_I2C_NUM
>> +#define CONFIG_MAX_I2C_NUM 3
>> +#endif
>
> Is this really configurable? If so, I do not find the Kconfig
> description.
No, it is not configurable. I have changed it to MAX_I2C_NUM.
>
>> +
>> +DECLARE_GLOBAL_DATA_PTR;
>> +
>> +struct nx_i2c_regs {
>> +??? uint???? iiccon;
>> +??? uint???? iicstat;
>> +??? uint???? iicadd;
>> +??? uint???? iicds;
>> +??? uint???? iiclc;
>> +};
>> +
>> +struct nx_i2c_bus {
>> +??? uint bus_num;
>> +??? struct nx_i2c_regs *regs;
>> +??? uint speed;
>> +??? uint target_speed;
>> +??? uint sda_delay;
>> +};
>> +
>> +/* s5pxx18 i2c must be reset before enabled */
>> +static void i2c_reset(int ch)
>> +{
>> +??? int rst_id = RESET_ID_I2C0 + ch;
>> +
>> +??? nx_rstcon_setrst(rst_id, 0);
>> +??? nx_rstcon_setrst(rst_id, 1);
>> +}
>> +
>> +/* FIXME : this func will be removed after reset dm driver ported.
>> + * set mmc pad alternative func.
>> + */
>> +static void set_i2c_pad_func(struct nx_i2c_bus *i2c)
>> +{
>> +??? switch (i2c->bus_num) {
>> +??? case 0:
>> +??????? nx_gpio_set_pad_function(3, 2, 1);
>> +??????? nx_gpio_set_pad_function(3, 3, 1);
>> +??????? break;
>> +??? case 1:
>> +??????? nx_gpio_set_pad_function(3, 4, 1);
>> +??????? nx_gpio_set_pad_function(3, 5, 1);
>> +??????? break;
>> +??? case 2:
>> +??????? nx_gpio_set_pad_function(3, 6, 1);
>> +??????? nx_gpio_set_pad_function(3, 7, 1);
>> +??????? break;
>> +??? }
>> +}
>
> Hmm... may this should be moved into a seperate pincontrol driver?
According to the above FIXME comment from Nexell it probably should. But
there is no pincontrol driver implemented. But is the change to a driver
necessary for now?
>
>> +
>> +static uint i2c_get_clkrate(struct nx_i2c_bus *bus)
>> +{
>> +??? struct clk *clk;
>> +??? int index = bus->bus_num;
>> +??? char name[50] = {0, };
>
> ?
>
>> +
>> +??? sprintf(name, "%s.%d", DEV_NAME_I2C, index);
>
> Where is DEV_NAME_I2C defined ?
DEV_NAME_I2C is defined in arch/arm/mach-nexell/include/mach/nexell.h
>
>> +??? clk = clk_get((const char *)name);
>> +??? if (!clk)
>> +??????? return -1;
>> +
>> +??? return clk_get_rate(clk);
>> +}
>> +
>> +static uint i2c_set_clk(struct nx_i2c_bus *bus, uint enb)
>> +{
>> +??? struct clk *clk;
>> +??? char name[50];
>> +
>> +??? sprintf(name, "%s.%d", DEV_NAME_I2C, bus->bus_num);
>> +??? clk = clk_get((const char *)name);
>> +??? if (!clk)
>> +??????? return -1;
>> +
>> +??? if (enb) {
>> +??????? clk_disable(clk);
>> +??????? clk_enable(clk);
>> +??? } else {
>> +??????? clk_disable(clk);
>> +??? }
>> +
>> +??? return 0;
>> +}
>> +
>> +/* get i2c module number from base address */
>> +static uint i2c_get_busnum(struct nx_i2c_bus *bus)
>> +{
>> +??? void *base_addr = (void *)PHY_BASEADDR_I2C0;
>> +??? int i;
>> +
>> +??? for (i = 0; i < CONFIG_MAX_I2C_NUM; i++) {
>> +??????? if (base_addr == ((void *)bus->regs)) {
>> +??????????? bus->bus_num = i;
>> +??????????? return i;
>> +??????? }
>> +??????? base_addr += 0x1000;
>> +??? }
>> +
>> +??? return -1;
>
> return -ENODEV;
>
> Hmm... is there no chance to use seq from struct udevice
>
> https://gitlab.denx.de/u-boot/u-boot/blob/master/include/dm/device.h#L152
>
> ?
>
> For example like:
> https://gitlab.denx.de/u-boot/u-boot/blob/master/drivers/i2c/mxc_i2c.c#L895
>
Ok, I have changed this as proposed.
>> +}
>> +
>> +/* Set SDA line delay */
>> +static int nx_i2c_set_sda_delay(struct nx_i2c_bus *bus, ulong clkin)
>> +{
>> +??? struct nx_i2c_regs *i2c = bus->regs;
>> +??? uint sda_delay = 0;
>> +
>> +??? if (bus->sda_delay) {
>> +??????? sda_delay = clkin * bus->sda_delay;
>> +??????? sda_delay = DIV_ROUND_UP(sda_delay, 1000000);
>> +??????? sda_delay = DIV_ROUND_UP(sda_delay, 5);
>> +??????? if (sda_delay > 3)
>> +??????????? sda_delay = 3;
>> +??????? sda_delay |= I2CLC_FILTER;
>> +??? } else {
>> +??????? sda_delay = 0;
>> +??? }
>> +
>> +??? sda_delay &= 0x7;
>> +??? writel(sda_delay, &i2c->iiclc);
>> +
>> +??? return 0;
>> +}
>> +
>> +/* Calculate the value of the divider and prescaler, set the bus
>> speed. */
>> +static int nx_i2c_set_bus_speed(struct udevice *dev, uint speed)
>> +{
>> +??? struct nx_i2c_bus *bus = dev_get_priv(dev);
>> +??? struct nx_i2c_regs *i2c = bus->regs;
>> +??? unsigned long freq, pres = 16, div;
>> +
>> +??? freq = i2c_get_clkrate(bus);
>> +??? /* calculate prescaler and divisor values */
>> +??? if ((freq / pres / (16 + 1)) > speed)
>> +??????? /* set prescaler to 512 */
>> +??????? pres = 512;
>> +
>> +??? div = 0;
>> +??? while ((freq / pres / (div + 1)) > speed)
>> +??????? div++;
>> +
>> +??? /* set prescaler, divisor according to freq, also set ACKGEN, IRQ */
>> +??? writel((div & 0x0F) | ((pres == 512) ? 0x40 : 0), &i2c->iiccon);
>> +
>> +??? /* init to SLAVE REVEIVE and set slaveaddr */
>> +??? writel(0, &i2c->iicstat);
>> +??? writel(0x00, &i2c->iicadd);
>> +??? /* program Master Transmit (and implicit STOP) */
>> +??? writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat);
>> +
>> +??? bus->speed = bus->target_speed / (div * pres);
>
> Do you want to allow all values of speeds or may you want to use
> standard speeds, see:
>
> https://gitlab.denx.de/u-boot/u-boot/blob/master/include/i2c.h#L33
>
I'd like to allow all values of speed. In my opinion allowing only
standard speeds does complicate things (e.g. how to do error handling?).
Furthermore I think sometimes it could be handy to be able to set speed
to an arbitrary value (e.g. to a lower value than 100000) when trying a
new i2c-device on the bus.
>> +
>> +??? return 0;
>> +}
>> +
>> +static void nx_i2c_set_clockrate(struct udevice *dev, uint speed)
>> +{
>> +??? struct nx_i2c_bus *bus = dev_get_priv(dev);
>> +??? ulong clkin;
>> +
>> +??? nx_i2c_set_bus_speed(dev, speed);
>> +??? clkin = bus->speed;??????????? /* the actual i2c speed */
>> +??? clkin /= 1000;??????????????? /* clkin now in Khz */
>> +??? nx_i2c_set_sda_delay(bus, clkin);
>> +}
>> +
>> +static void i2c_process_node(struct udevice *dev)
>> +{
>> +??? struct nx_i2c_bus *bus = dev_get_priv(dev);
>> +??? const void *blob = gd->fdt_blob;
>> +
>> +??? int node;
>> +
>> +??? node = dev->node.of_offset;
>> +
>> +??? bus->target_speed = fdtdec_get_int(blob, node,
>> +?????????????????????? "nexell,i2c-max-bus-freq", 0);
>> +??? bus->sda_delay = fdtdec_get_int(blob, node,
>> +??????????????????? "nexell,i2c-sda-delay", 0);
>
> You introdue here new properties, please document them in
> u-boot:/doc/device-tree-bindings/i2c
>
> Please without "nexell,"
>
I have changed "nexell,i2c-max-bus-freq" to the already defined
"clock-frequency". Furthermore I have changed "nexell,i2c-sda-delay" to
"i2c-sda-delay-ns".
Furthermore, I have added "nx_i2c.txt" in doc/device-tree-bindings/i2c.
> Do you plan to post also a linux i2c driver?
>
> If so, the devicetree bindings should be discussed there to avoid
> different properties between U-Boot and linux!
>
No, I do not plan to post a linux driver.
>> +}
>> +
>> +static int nx_i2c_probe(struct udevice *dev)
>> +{
>> +??? struct nx_i2c_bus *bus = dev_get_priv(dev);
>> +
>> +??? /* get regs */
>> +??? bus->regs = (struct nx_i2c_regs *)devfdt_get_addr(dev);
>> +??? /* calc index */
>> +??? if (!i2c_get_busnum(bus)) {
>> +??????? debug("not found i2c number!\n");
>> +??????? return -1;
>
> please return -ENODEV
>
Ok
>> +??? }
>> +
>> +??? /* i2c optional node parsing */
>> +??? i2c_process_node(dev);
>> +??? if (!bus->target_speed)
>> +??????? return -1;
>
> please return here also an errorcode from include/linux/errno.h
>
Ok
> Hmm.. if you return here if target_speed is not set, it is not optional!
>
You are right, I have removed 'optional' in the comment.
>> +
>> +??? /* reset */
>> +??? i2c_reset(bus->bus_num);
>> +??? /* gpio pad */
>> +??? set_i2c_pad_func(bus);
>> +
>> +??? /* clock rate */
>> +??? i2c_set_clk(bus, 1);
>> +??? nx_i2c_set_clockrate(dev, bus->target_speed);
>> +??? i2c_set_clk(bus, 0);
>> +
>> +??? return 0;
>> +}
>> +
>> +/* i2c bus busy check */
>> +static int i2c_is_busy(struct nx_i2c_regs *i2c)
>> +{
>> +??? ulong start_time;
>> +
>> +??? start_time = get_timer(0);
>> +??? while (readl(&i2c->iicstat) & I2CSTAT_BSY) {
>> +??????? if (get_timer(start_time) > I2C_TIMEOUT_MS) {
>> +??????????? debug("Timeout\n");
>> +??????????? return -I2C_NOK_TOUT;
>> +??????? }
>> +??? }
>> +??? return 0;
>> +}
>> +
>> +/* irq enable/disable functions */
>> +static void i2c_enable_irq(struct nx_i2c_regs *i2c)
>> +{
>> +??? unsigned int reg;
>> +
>> +??? reg = readl(&i2c->iiccon);
>> +??? reg |= I2CCON_IRENB;
>> +??? writel(reg, &i2c->iiccon);
>> +}
>> +
>> +/* irq clear function */
>> +static void i2c_clear_irq(struct nx_i2c_regs *i2c)
>> +{
>> +??? clrbits_le32(&i2c->iiccon, I2CCON_IRPND);
>> +}
>> +
>> +/* ack enable functions */
>> +static void i2c_enable_ack(struct nx_i2c_regs *i2c)
>> +{
>> +??? unsigned int reg;
>> +
>> +??? reg = readl(&i2c->iiccon);
>> +??? reg |= I2CCON_ACKGEN;
>> +??? writel(reg, &i2c->iiccon);
>> +}
>> +
>> +static void i2c_send_stop(struct nx_i2c_regs *i2c)
>> +{
>> +??? unsigned int reg;
>> +
>> +??? /* Send STOP. */
>> +??? reg = readl(&i2c->iicstat);
>> +??? reg |= I2C_MODE_MR | I2C_TXRX_ENA;
>> +??? reg &= (~I2C_START_STOP);
>> +??? writel(reg, &i2c->iicstat);
>> +??? i2c_clear_irq(i2c);
>> +}
>> +
>> +static int wait_for_xfer(struct nx_i2c_regs *i2c)
>> +{
>> +??? unsigned long start_time = get_timer(0);
>> +
>> +??? do {
>> +??????? if (readl(&i2c->iiccon) & I2CCON_IRPND)
>> +??????????? return (readl(&i2c->iicstat) & I2CSTAT_NACK) ?
>> +??????????????? I2C_NACK : I2C_OK;
>> +??? } while (get_timer(start_time) < I2C_TIMEOUT_MS);
>> +
>> +??? return I2C_NOK_TOUT;
>> +}
>> +
>> +static int i2c_transfer(struct nx_i2c_regs *i2c,
>> +??????????? uchar cmd_type,
>> +??????????? uchar chip,
>> +??????????? uchar addr[],
>> +??????????? uchar addr_len,
>> +??????????? uchar data[],
>> +??????????? unsigned short data_len,
>> +??????????? uint seq)
>> +{
>> +??? uint status;
>> +??? int i = 0, result;
>> +
>> +??? if (data == 0 || data_len == 0) {
>> +??????? /*Don't support data transfer of no length or to address 0 */
>> +??????? debug("%s: bad call\n", __func__);
>> +??????? return I2C_NOK;
>> +??? }
>> +
>> +??? i2c_enable_irq(i2c);
>> +??? i2c_enable_ack(i2c);
>> +
>> +??? /* Get the slave chip address going */
>> +??? writel(chip, &i2c->iicds);
>> +??? status = I2C_TXRX_ENA | I2C_START_STOP;
>> +??? if (cmd_type == I2C_WRITE || (addr && addr_len))
>> +??????? status |= I2C_MODE_MT;
>> +??? else
>> +??????? status |= I2C_MODE_MR;
>> +??? writel(status, &i2c->iicstat);
>> +??? if (seq)
>> +??????? i2c_clear_irq(i2c);
>> +
>> +??? /* Wait for chip address to transmit. */
>> +??? result = wait_for_xfer(i2c);
>> +??? if (result != I2C_OK)
>> +??????? goto bailout;
>> +
>> +??? /* If register address needs to be transmitted - do it now. */
>> +??? if (addr && addr_len) {? /* register addr */
>> +??????? while ((i < addr_len) && (result == I2C_OK)) {
>> +??????????? writel(addr[i++], &i2c->iicds);
>> +??????????? i2c_clear_irq(i2c);
>> +??????????? result = wait_for_xfer(i2c);
>> +??????? }
>> +
>> +??????? i = 0;
>> +??????? if (result != I2C_OK)
>> +??????????? goto bailout;
>> +??? }
>> +
>> +??? switch (cmd_type) {
>> +??? case I2C_WRITE:
>> +??????? while ((i < data_len) && (result == I2C_OK)) {
>> +??????????? writel(data[i++], &i2c->iicds);
>> +??????????? i2c_clear_irq(i2c);
>> +??????????? result = wait_for_xfer(i2c);
>> +??????? }
>> +??????? break;
>> +??? case I2C_READ:
>> +??????? if (addr && addr_len) {
>> +??????????? /*
>> +???????????? * Register address has been sent, now send slave chip
>> +???????????? * address again to start the actual read transaction.
>> +???????????? */
>> +??????????? writel(chip, &i2c->iicds);
>> +
>> +??????????? /* Generate a re-START. */
>> +??????????? writel(I2C_MODE_MR | I2C_TXRX_ENA
>> +??????????????????? | I2C_START_STOP, &i2c->iicstat);
>> +??????????? i2c_clear_irq(i2c);
>> +??????????? result = wait_for_xfer(i2c);
>> +??????????? if (result != I2C_OK)
>> +??????????????? goto bailout;
>> +??????? }
>> +
>> +??????? while ((i < data_len) && (result == I2C_OK)) {
>> +??????????? /* disable ACK for final READ */
>> +??????????? if (i == data_len - 1)
>> +??????????????? clrbits_le32(&i2c->iiccon
>> +??????????????????????? , I2CCON_ACKGEN);
>> +
>> +??????????? i2c_clear_irq(i2c);
>> +??????????? result = wait_for_xfer(i2c);
>> +??????????? data[i++] = readb(&i2c->iicds);
>> +??????? }
>> +
>> +??????? if (result == I2C_NACK)
>> +??????????? result = I2C_OK; /* Normal terminated read. */
>> +??????? break;
>> +
>> +??? default:
>> +??????? debug("%s: bad call\n", __func__);
>> +??????? result = I2C_NOK;
>> +??????? break;
>> +??? }
>> +
>> +bailout:
>> +??? return result;
>> +}
>> +
>> +static int nx_i2c_read(struct udevice *dev, uchar chip, uint addr,
>> +?????????????? uint alen, uchar *buffer, uint len, uint seq)
>> +{
>> +??? struct nx_i2c_bus *i2c;
>> +??? uchar xaddr[4];
>> +??? int ret;
>> +
>> +??? i2c = dev_get_priv(dev);
>> +??? if (!i2c)
>> +??????? return -EFAULT;
>> +
>> +??? if (alen > 4) {
>> +??????? debug("I2C read: addr len %d not supported\n", alen);
>> +??????? return -EADDRNOTAVAIL;
>> +??? }
>> +
>> +??? if (alen > 0)
>> +??????? xaddr[0] = (addr >> 24) & 0xFF;
>> +
>> +??? if (alen > 0) {
>> +??????? xaddr[0] = (addr >> 24) & 0xFF;
>> +??????? xaddr[1] = (addr >> 16) & 0xFF;
>> +??????? xaddr[2] = (addr >> 8) & 0xFF;
>> +??????? xaddr[3] = addr & 0xFF;
>> +??? }
>> +
>> +??? ret = i2c_transfer(i2c->regs, I2C_READ, chip << 1,
>> +?????????????? &xaddr[4 - alen], alen, buffer, len, seq);
>> +
>> +??? if (ret) {
>> +??????? debug("I2C read failed %d\n", ret);
>> +??????? return -EIO;
>> +??? }
>> +
>> +??? return 0;
>> +}
>> +
>> +static int nx_i2c_write(struct udevice *dev, uchar chip, uint addr,
>> +??????????? uint alen, uchar *buffer, uint len, uint seq)
>> +{
>> +??? struct nx_i2c_bus *i2c;
>> +??? uchar xaddr[4];
>> +??? int ret;
>> +
>> +??? i2c = dev_get_priv(dev);
>> +??? if (!i2c)
>> +??????? return -EFAULT;
>> +
>> +??? if (alen > 4) {
>> +??????? debug("I2C write: addr len %d not supported\n", alen);
>> +??????? return -EINVAL;
>> +??? }
>> +
>> +??? if (alen > 0) {
>> +??????? xaddr[0] = (addr >> 24) & 0xFF;
>> +??????? xaddr[1] = (addr >> 16) & 0xFF;
>> +??????? xaddr[2] = (addr >> 8) & 0xFF;
>> +??????? xaddr[3] = addr & 0xFF;
>> +??? }
>> +
>> +??? ret = i2c_transfer(i2c->regs, I2C_WRITE, chip << 1,
>> +?????????????? &xaddr[4 - alen], alen, buffer, len, seq);
>> +??? if (ret) {
>> +??????? debug("I2C write failed %d\n", ret);
>> +??????? return -EIO;
>> +??? }
>> +
>> +??? return 0;
>> +}
>> +
>> +static int nx_i2c_xfer(struct udevice *dev, struct i2c_msg *msg, int
>> nmsgs)
>> +{
>> +??? struct nx_i2c_bus *bus = dev_get_priv(dev);
>> +??? struct nx_i2c_regs *i2c = bus->regs;
>> +??? int ret;
>> +??? int i;
>> +
>> +??? /* The power loss by the clock, only during on/off. */
>> +??? i2c_set_clk(bus, 1);
>> +
>> +??? /* Bus State(Busy) check? */
>> +??? ret = i2c_is_busy(i2c);
>> +??? if (ret < 0)
>> +??????? return ret;
>> +
>> +??? for (i = 0; i < nmsgs; msg++, i++) {
>> +??????? if (msg->flags & I2C_M_RD) {
>> +??????????? ret = nx_i2c_read(dev, msg->addr, 0, 0, msg->buf,
>> +????????????????????? msg->len, i);
>> +??????? } else {
>> +??????????? ret = nx_i2c_write(dev, msg->addr, 0, 0, msg->buf,
>> +?????????????????????? msg->len, i);
>> +??????? }
>> +
>> +??????? if (ret) {
>> +??????????? debug("i2c_xfer: error sending\n");
>> +??????????? return -EREMOTEIO;
>> +??????? }
>> +??? }
>> +??? /* Send Stop */
>> +??? i2c_send_stop(i2c);
>> +??? i2c_set_clk(bus, 0);
>> +
>> +??? return ret ? -EREMOTEIO : 0;
>> +};
>> +
>> +static const struct dm_i2c_ops nx_i2c_ops = {
>> +??? .xfer??????? = nx_i2c_xfer,
>> +??? .set_bus_speed??? = nx_i2c_set_bus_speed,
>> +};
>> +
>> +static const struct udevice_id nx_i2c_ids[] = {
>> +??? { .compatible = "nexell,s5pxx18-i2c" },
>
> Same here as for the new properties. Please discuss the names on
>
> devicetree at vger.kernel.org <devicetree@vger.kernel.org>
>
> first!
>
>> +??? { }
>> +};
>> +
>> +U_BOOT_DRIVER(i2c_nexell) = {
>> +??? .name??????? = "i2c_nexell",
>> +??? .id??????? = UCLASS_I2C,
>> +??? .of_match??? = nx_i2c_ids,
>> +??? .probe??????? = nx_i2c_probe,
>> +??? .priv_auto_alloc_size??? = sizeof(struct nx_i2c_bus),
>> +??? .ops??????? = &nx_i2c_ops,
>> +};
>
> bye,
> Heiko
>> diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
>> index 2f0eedc..bb8e7c0 100644
>> --- a/drivers/mmc/Kconfig
>> +++ b/drivers/mmc/Kconfig
>> @@ -253,6 +253,12 @@ config MMC_DW_SNPS
>> ??????? This selects support for Synopsys DesignWare Memory Card
>> Interface driver
>> ??????? extensions used in various Synopsys ARC devboards.
>> +config NEXELL_DWMMC
>> +??? bool "Nexell SD/MMC controller support"
>> +??? depends on ARCH_NEXELL
>> +??? depends on MMC_DW
>> +??? default y
>> +
>> ? config MMC_MESON_GX
>> ????? bool "Meson GX EMMC controller support"
>> ????? depends on DM_MMC && BLK && ARCH_MESON
>> diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
>> index 9c1f8e5..a7b5a7b 100644
>> --- a/drivers/mmc/Makefile
>> +++ b/drivers/mmc/Makefile
>> @@ -43,6 +43,7 @@ obj-$(CONFIG_SH_MMCIF) += sh_mmcif.o
>> ? obj-$(CONFIG_SH_SDHI) += sh_sdhi.o
>> ? obj-$(CONFIG_STM32_SDMMC2) += stm32_sdmmc2.o
>> ? obj-$(CONFIG_JZ47XX_MMC) += jz_mmc.o
>> +obj-$(CONFIG_NEXELL_DWMMC) += nexell_dw_mmc_dm.o
>> ? # SDHCI
>> ? obj-$(CONFIG_MMC_SDHCI)??????????? += sdhci.o
>> diff --git a/drivers/mmc/nexell_dw_mmc_dm.c
>> b/drivers/mmc/nexell_dw_mmc_dm.c
>> new file mode 100644
>> index 0000000..b06b60d
>> --- /dev/null
>> +++ b/drivers/mmc/nexell_dw_mmc_dm.c
>> @@ -0,0 +1,350 @@
>> +// SPDX-License-Identifier: GPL-2.0+
>> +/*
>> + * (C) Copyright 2016 Nexell
>> + * Youngbok, Park <park@nexell.co.kr>
>> + *
>> + * (C) Copyright 2019 Stefan Bosch <stefan_b@posteo.net>
>> + */
>> +
>> +#include <common.h>
>> +#include <clk.h>
>> +#include <dm.h>
>> +#include <dt-structs.h>
>> +#include <dwmmc.h>
>> +#include <syscon.h>
>> +#include <asm/gpio.h>
>> +#include <asm/arch/nx_gpio.h>
>> +#include <asm/arch/reset.h>
>> +
>> +#define DWMCI_CLKSEL??????????? 0x09C
>> +#define DWMCI_SHIFT_0??????????? 0x0
>> +#define DWMCI_SHIFT_1??????????? 0x1
>> +#define DWMCI_SHIFT_2??????????? 0x2
>> +#define DWMCI_SHIFT_3??????????? 0x3
>> +#define DWMCI_SET_SAMPLE_CLK(x)??? (x)
>> +#define DWMCI_SET_DRV_CLK(x)??? ((x) << 16)
>> +#define DWMCI_SET_DIV_RATIO(x)??? ((x) << 24)
>> +#define DWMCI_CLKCTRL??????????? 0x114
>> +#define NX_MMC_CLK_DELAY(x, y, a, b)??? ((((x) & 0xFF) << 0) |\
>> +??????????????????? (((y) & 0x03) << 16) |\
>> +??????????????????? (((a) & 0xFF) << 8)? |\
>> +??????????????????? (((b) & 0x03) << 24))
>> +
>> +struct nexell_mmc_plat {
>> +??? struct mmc_config cfg;
>> +??? struct mmc mmc;
>> +};
>> +
>> +struct nexell_dwmmc_priv {
>> +??? struct clk *clk;
>> +??? struct dwmci_host host;
>> +??? int fifo_size;
>> +??? bool fifo_mode;
>> +??? int frequency;
>> +??? u32 min_freq;
>> +??? u32 max_freq;
>> +??? int d_delay;
>> +??? int d_shift;
>> +??? int s_delay;
>> +??? int s_shift;
>> +
>> +};
>> +
>> +struct clk *clk_get(const char *id);
>> +
>> +static void set_pin_stat(int index, int bit, int value)
>> +{
>> +#if !defined(CONFIG_SPL_BUILD)
>> +??? nx_gpio_set_pad_function(index, bit, value);
>> +#else
>> +#if defined(CONFIG_ARCH_S5P4418) ||??? \
>> +??? defined(CONFIG_ARCH_S5P6818)
>> +
>> +??? unsigned long base[5] = {
>> +??????? PHY_BASEADDR_GPIOA, PHY_BASEADDR_GPIOB,
>> +??????? PHY_BASEADDR_GPIOC, PHY_BASEADDR_GPIOD,
>> +??????? PHY_BASEADDR_GPIOE,
>> +??? };
>> +
>> +??? dw_mmc_set_pin(base[index], bit, value);
>> +#endif
>> +#endif
>> +}
>> +
>> +static void nx_dw_mmc_set_pin(struct dwmci_host *host)
>> +{
>> +??? debug("? %s(): dev_index == %d", __func__, host->dev_index);
>> +
>> +??? switch (host->dev_index) {
>> +??? case 0:
>> +??????? set_pin_stat(0, 29, 1);
>> +??????? set_pin_stat(0, 31, 1);
>> +??????? set_pin_stat(1, 1, 1);
>> +??????? set_pin_stat(1, 3, 1);
>> +??????? set_pin_stat(1, 5, 1);
>> +??????? set_pin_stat(1, 7, 1);
>> +??????? break;
>> +??? case 1:
>> +??????? set_pin_stat(3, 22, 1);
>> +??????? set_pin_stat(3, 23, 1);
>> +??????? set_pin_stat(3, 24, 1);
>> +??????? set_pin_stat(3, 25, 1);
>> +??????? set_pin_stat(3, 26, 1);
>> +??????? set_pin_stat(3, 27, 1);
>> +??????? break;
>> +??? case 2:
>> +??????? set_pin_stat(2, 18, 2);
>> +??????? set_pin_stat(2, 19, 2);
>> +??????? set_pin_stat(2, 20, 2);
>> +??????? set_pin_stat(2, 21, 2);
>> +??????? set_pin_stat(2, 22, 2);
>> +??????? set_pin_stat(2, 23, 2);
>> +??????? if (host->buswidth == 8) {
>> +??????????? set_pin_stat(4, 21, 2);
>> +??????????? set_pin_stat(4, 22, 2);
>> +??????????? set_pin_stat(4, 23, 2);
>> +??????????? set_pin_stat(4, 24, 2);
>> +??????? }
>> +??????? break;
>> +??? default:
>> +??????? debug(" is invalid!");
>> +??? }
>> +??? debug("\n");
>> +}
>> +
>> +static void nx_dw_mmc_clksel(struct dwmci_host *host)
>> +{
>> +??? u32 val;
>> +
>> +#ifdef CONFIG_BOOST_MMC
>> +??? val = DWMCI_SET_SAMPLE_CLK(DWMCI_SHIFT_0) |
>> +??????? DWMCI_SET_DRV_CLK(DWMCI_SHIFT_0) | DWMCI_SET_DIV_RATIO(1);
>> +#else
>> +??? val = DWMCI_SET_SAMPLE_CLK(DWMCI_SHIFT_0) |
>> +??????? DWMCI_SET_DRV_CLK(DWMCI_SHIFT_0) | DWMCI_SET_DIV_RATIO(3);
>> +#endif
>> +
>> +??? dwmci_writel(host, DWMCI_CLKSEL, val);
>> +}
>> +
>> +static void nx_dw_mmc_reset(int ch)
>> +{
>> +??? int rst_id = RESET_ID_SDMMC0 + ch;
>> +
>> +??? nx_rstcon_setrst(rst_id, 0);
>> +??? nx_rstcon_setrst(rst_id, 1);
>> +}
>> +
>> +static void nx_dw_mmc_clk_delay(struct udevice *dev)
>> +{
>> +??? unsigned int delay;
>> +??? struct nexell_dwmmc_priv *priv = dev_get_priv(dev);
>> +??? struct dwmci_host *host = &priv->host;
>> +
>> +??? delay = NX_MMC_CLK_DELAY(priv->d_delay,
>> +???????????????? priv->d_shift, priv->s_delay, priv->s_shift);
>> +
>> +??? writel(delay, (host->ioaddr + DWMCI_CLKCTRL));
>> +??? debug("%s(): Values set: d_delay==%d, d_shift==%d, s_delay==%d, "
>> +????????? "s_shift==%d\n", __func__, priv->d_delay, priv->d_shift,
>> +????????? priv->s_delay, priv->s_shift);
>> +}
>> +
>> +static unsigned int nx_dw_mmc_get_clk(struct dwmci_host *host, uint
>> freq)
>> +{
>> +??? struct clk *clk;
>> +??? struct udevice *dev = host->priv;
>> +??? struct nexell_dwmmc_priv *priv = dev_get_priv(dev);
>> +
>> +??? int index = host->dev_index;
>> +??? char name[50] = { 0, };
>> +
>> +??? clk = priv->clk;
>> +??? if (!clk) {
>> +??????? sprintf(name, "%s.%d", DEV_NAME_SDHC, index);
>> +??????? clk = clk_get((const char *)name);
>> +??????? if (!clk)
>> +??????????? return 0;
>> +??????? priv->clk = clk;
>> +??? }
>> +
>> +??? return clk_get_rate(clk) / 2;
>> +}
>> +
>> +static unsigned long nx_dw_mmc_set_clk(struct dwmci_host *host,
>> +?????????????????????? unsigned int rate)
>> +{
>> +??? struct clk *clk;
>> +??? char name[50] = { 0, };
>> +??? struct udevice *dev = host->priv;
>> +??? struct nexell_dwmmc_priv *priv = dev_get_priv(dev);
>> +
>> +??? int index = host->dev_index;
>> +
>> +??? clk = priv->clk;
>> +??? if (!clk) {
>> +??????? sprintf(name, "%s.%d", DEV_NAME_SDHC, index);
>> +??????? clk = clk_get((const char *)name);
>> +??????? if (!clk)
>> +??????????? return 0;
>> +??????? priv->clk = clk;
>> +??? }
>> +
>> +??? clk_disable(clk);
>> +??? rate = clk_set_rate(clk, rate);
>> +??? clk_enable(clk);
>> +
>> +??? return rate;
>> +}
>> +
>> +static int nexell_dwmmc_ofdata_to_platdata(struct udevice *dev)
>> +{
>> +??? /* if (dev): *priv = dev->priv, else: *priv = NULL */
>> +??? struct nexell_dwmmc_priv *priv = dev_get_priv(dev);
>> +??? struct dwmci_host *host = &priv->host;
>> +??? int val = -1;
>> +
>> +??? debug("%s()\n", __func__);
>> +
>> +??? host->name = dev->name;
>> +??? host->ioaddr = dev_read_addr_ptr(dev);
>> +
>> +??? val = dev_read_u32_default(dev, "nexell,bus-width", -1);
>> +??? if (val < 0) {
>> +??????? debug("? 'nexell,bus-width' missing/invalid!\n");
>> +??????? return -EINVAL;
>> +??? }
>> +??? host->buswidth = val;
>> +??? host->get_mmc_clk = nx_dw_mmc_get_clk;
>> +??? host->clksel = nx_dw_mmc_clksel;
>> +??? host->priv = dev;
>> +
>> +??? val = dev_read_u32_default(dev, "index", -1);
>> +??? if (val < 0) {
>> +??????? debug("? 'index' missing/invalid!\n");
>> +??????? return -EINVAL;
>> +??? }
>> +??? host->dev_index = val;
>> +
>> +??? val = dev_read_u32_default(dev, "fifo-size", 0x20);
>> +??? if (val <= 0) {
>> +??????? debug("? 'fifo-size' missing/invalid!\n");
>> +??????? return -EINVAL;
>> +??? }
>> +??? priv->fifo_size = val;
>> +
>> +??? priv->fifo_mode = dev_read_bool(dev, "fifo-mode");
>> +
>> +??? val = dev_read_u32_default(dev, "frequency", -1);
>> +??? if (val < 0) {
>> +??????? debug("? 'frequency' missing/invalid!\n");
>> +??????? return -EINVAL;
>> +??? }
>> +??? priv->frequency = val;
>> +
>> +??? val = dev_read_u32_default(dev, "max-frequency", -1);
>> +??? if (val < 0) {
>> +??????? debug("? 'max-frequency' missing/invalid!\n");
>> +??????? return -EINVAL;
>> +??? }
>> +??? priv->max_freq = val;
>> +??? priv->min_freq = 400000;? /* 400 kHz */
>> +
>> +??? val = dev_read_u32_default(dev, "nexell,drive_dly", -1);
>> +??? if (val < 0) {
>> +??????? debug("? 'nexell,drive_dly' missing/invalid!\n");
>> +??????? return -EINVAL;
>> +??? }
>> +??? priv->d_delay = val;
>> +
>> +??? val = dev_read_u32_default(dev, "nexell,drive_shift", -1);
>> +??? if (val < 0) {
>> +??????? debug("? 'nexell,drive_shift' missing/invalid!\n");
>> +??????? return -EINVAL;
>> +??? }
>> +??? priv->d_shift = val;
>> +
>> +??? val = dev_read_u32_default(dev, "nexell,sample_dly", -1);
>> +??? if (val < 0) {
>> +??????? debug("? 'nexell,sample_dly' missing/invalid!\n");
>> +??????? return -EINVAL;
>> +??? }
>> +??? priv->s_delay = val;
>> +
>> +??? val = dev_read_u32_default(dev, "nexell,sample_shift", -1);
>> +??? if (val < 0) {
>> +??????? debug("? 'nexell,sample_shift' missing/invalid!\n");
>> +??????? return -EINVAL;
>> +??? }
>> +??? priv->s_shift = val;
>> +
>> +??? debug("? index==%d, name==%s, ioaddr==0x%08x, buswidth==%d, "
>> +????????? "fifo_size==%d, fifo_mode==%d, frequency==%d\n",
>> +????????? host->dev_index, host->name, (u32)host->ioaddr,
>> +????????? host->buswidth, priv->fifo_size, priv->fifo_mode,
>> +????????? priv->frequency);
>> +??? debug("? min_freq==%d, max_freq==%d, delay: "
>> +????????? "0x%02x:0x%02x:0x%02x:0x%02x\n",
>> +????????? priv->min_freq, priv->max_freq, priv->d_delay,
>> +????????? priv->d_shift, priv->s_delay, priv->s_shift);
>> +
>> +??? return 0;
>> +}
>> +
>> +static int nexell_dwmmc_probe(struct udevice *dev)
>> +{
>> +??? struct nexell_mmc_plat *plat = dev_get_platdata(dev);
>> +??? struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
>> +??? struct nexell_dwmmc_priv *priv = dev_get_priv(dev);
>> +??? struct dwmci_host *host = &priv->host;
>> +??? struct udevice *pwr_dev __maybe_unused;
>> +
>> +??? debug("%s():\n", __func__);
>> +
>> +??? host->fifoth_val = MSIZE(0x2) |
>> +??????? RX_WMARK(priv->fifo_size / 2 - 1) |
>> +??????? TX_WMARK(priv->fifo_size / 2);
>> +
>> +??? host->fifo_mode = priv->fifo_mode;
>> +
>> +??? dwmci_setup_cfg(&plat->cfg, host, priv->max_freq, priv->min_freq);
>> +??? host->mmc = &plat->mmc;
>> +??? host->mmc->priv = &priv->host;
>> +??? host->mmc->dev = dev;
>> +??? upriv->mmc = host->mmc;
>> +
>> +??? nx_dw_mmc_set_pin(host);
>> +
>> +??? debug("? nx_dw_mmc_set_clk(host, frequency * 4 == %d)\n",
>> +????????? priv->frequency * 4);
>> +??? nx_dw_mmc_set_clk(host, priv->frequency * 4);
>> +
>> +??? nx_dw_mmc_reset(host->dev_index);
>> +??? nx_dw_mmc_clk_delay(dev);
>> +
>> +??? return dwmci_probe(dev);
>> +}
>> +
>> +static int nexell_dwmmc_bind(struct udevice *dev)
>> +{
>> +??? struct nexell_mmc_plat *plat = dev_get_platdata(dev);
>> +
>> +??? return dwmci_bind(dev, &plat->mmc, &plat->cfg);
>> +}
>> +
>> +static const struct udevice_id nexell_dwmmc_ids[] = {
>> +??? { .compatible = "nexell,nexell-dwmmc" },
>> +??? { }
>> +};
>> +
>> +U_BOOT_DRIVER(nexell_dwmmc_drv) = {
>> +??? .name??????? = "nexell_dwmmc",
>> +??? .id??????? = UCLASS_MMC,
>> +??? .of_match??? = nexell_dwmmc_ids,
>> +??? .ofdata_to_platdata = nexell_dwmmc_ofdata_to_platdata,
>> +??? .ops??????? = &dm_dwmci_ops,
>> +??? .bind??????? = nexell_dwmmc_bind,
>> +??? .probe??????? = nexell_dwmmc_probe,
>> +??? .priv_auto_alloc_size = sizeof(struct nexell_dwmmc_priv),
>> +??? .platdata_auto_alloc_size = sizeof(struct nexell_mmc_plat),
>> +};
>> diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
>> index a837c35..b45aada 100644
>> --- a/drivers/pwm/Makefile
>> +++ b/drivers/pwm/Makefile
>> @@ -16,3 +16,4 @@ obj-$(CONFIG_PWM_ROCKCHIP)??? += rk_pwm.o
>> ? obj-$(CONFIG_PWM_SANDBOX)??? += sandbox_pwm.o
>> ? obj-$(CONFIG_PWM_TEGRA)??????? += tegra_pwm.o
>> ? obj-$(CONFIG_PWM_SUNXI)??????? += sunxi_pwm.o
>> +obj-$(CONFIG_PWM_NX)??????? += pwm-nexell.o
>> diff --git a/drivers/pwm/pwm-nexell.c b/drivers/pwm/pwm-nexell.c
>> new file mode 100644
>> index 0000000..6c0f8f4
>> --- /dev/null
>> +++ b/drivers/pwm/pwm-nexell.c
>> @@ -0,0 +1,252 @@
>> +// SPDX-License-Identifier: GPL-2.0+
>> +/*
>> + * Copyright (C) 2011 Samsung Electronics
>> + *
>> + * Donghwa Lee <dh09.lee@samsung.com>
>> + */
>> +
>> +/* This codes are copied from arch/arm/cpu/armv7/s5p-common/pwm.c */
>> +
>> +#include <common.h>
>> +#include <errno.h>
>> +#include <pwm.h>
>> +#include <asm/io.h>
>> +#include <asm/arch/clk.h>
>> +#include "pwm-nexell.h"
>> +
>> +#if defined(CONFIG_ARCH_NEXELL)
>> +#include <asm/arch/nexell.h>
>> +#include <asm/arch/reset.h>
>> +#include <asm/arch/nx_gpio.h>
>> +#include <asm/arch/tieoff.h>
>> +
>> +struct pwm_device {
>> +??? int ch;
>> +??? int grp;
>> +??? int bit;
>> +??? int pwm_fn;
>> +};
>> +
>> +static struct pwm_device pwm_dev[] = {
>> +??? [0] = { .ch = 0, .grp = 3, .bit = 1,? .pwm_fn = 1 },
>> +??? [1] = { .ch = 1, .grp = 2, .bit = 13, .pwm_fn = 2 },
>> +??? [2] = { .ch = 2, .grp = 2, .bit = 14, .pwm_fn =??? 2 },
>> +??? [3] = { .ch = 3, .grp = 3, .bit = 0,? .pwm_fn = 2 },
>> +};
>> +#endif
>> +
>> +int pwm_enable(int pwm_id)
>> +{
>> +??? const struct s5p_timer *pwm =
>> +#if defined(CONFIG_ARCH_NEXELL)
>> +??????????? (struct s5p_timer *)PHY_BASEADDR_PWM;
>> +#else
>> +??????????? (struct s5p_timer *)samsung_get_base_timer();
>> +#endif
>> +??? unsigned long tcon;
>> +
>> +??? tcon = readl(&pwm->tcon);
>> +??? tcon |= TCON_START(pwm_id);
>> +
>> +??? writel(tcon, &pwm->tcon);
>> +
>> +??? return 0;
>> +}
>> +
>> +void pwm_disable(int pwm_id)
>> +{
>> +??? const struct s5p_timer *pwm =
>> +#if defined(CONFIG_ARCH_NEXELL)
>> +??????????? (struct s5p_timer *)PHY_BASEADDR_PWM;
>> +#else
>> +??????????? (struct s5p_timer *)samsung_get_base_timer();
>> +#endif
>> +??? unsigned long tcon;
>> +
>> +??? tcon = readl(&pwm->tcon);
>> +??? tcon &= ~TCON_START(pwm_id);
>> +
>> +??? writel(tcon, &pwm->tcon);
>> +}
>> +
>> +static unsigned long pwm_calc_tin(int pwm_id, unsigned long freq)
>> +{
>> +??? unsigned long tin_parent_rate;
>> +??? unsigned int div;
>> +#if defined(CONFIG_ARCH_NEXELL)
>> +??? unsigned int pre_div;
>> +??? const struct s5p_timer *pwm =
>> +??????? (struct s5p_timer *)PHY_BASEADDR_PWM;
>> +??? unsigned int val;
>> +#endif
>> +
>> +#if defined(CONFIG_ARCH_NEXELL)
>> +??? struct clk *clk = clk_get(CORECLK_NAME_PCLK);
>> +
>> +??? tin_parent_rate = clk_get_rate(clk);
>> +#else
>> +??? tin_parent_rate = get_pwm_clk();
>> +#endif
>> +
>> +#if defined(CONFIG_ARCH_NEXELL)
>> +??? writel(0, &pwm->tcfg0);
>> +??? val = readl(&pwm->tcfg0);
>> +
>> +??? if (pwm_id < 2)
>> +??????? div = ((val >> 0) & 0xff) + 1;
>> +??? else
>> +??????? div = ((val >> 8) & 0xff) + 1;
>> +
>> +??? writel(0, &pwm->tcfg1);
>> +??? val = readl(&pwm->tcfg1);
>> +??? val = (val >> MUX_DIV_SHIFT(pwm_id)) & 0xF;
>> +??? pre_div = (1UL << val);
>> +
>> +??? freq = tin_parent_rate / div / pre_div;
>> +
>> +??? return freq;
>> +#else
>> +??? for (div = 2; div <= 16; div *= 2) {
>> +??????? if ((tin_parent_rate / (div << 16)) < freq)
>> +??????????? return tin_parent_rate / div;
>> +??? }
>> +
>> +??? return tin_parent_rate / 16;
>> +#endif
>> +}
>> +
>> +#define NS_IN_SEC 1000000000UL
>> +
>> +int pwm_config(int pwm_id, int duty_ns, int period_ns)
>> +{
>> +??? const struct s5p_timer *pwm =
>> +#if defined(CONFIG_ARCH_NEXELL)
>> +??????? (struct s5p_timer *)PHY_BASEADDR_PWM;
>> +#else
>> +??????? (struct s5p_timer *)samsung_get_base_timer();
>> +#endif
>> +??? unsigned int offset;
>> +??? unsigned long tin_rate;
>> +??? unsigned long tin_ns;
>> +??? unsigned long frequency;
>> +??? unsigned long tcon;
>> +??? unsigned long tcnt;
>> +??? unsigned long tcmp;
>> +
>> +??? /*
>> +???? * We currently avoid using 64bit arithmetic by using the
>> +???? * fact that anything faster than 1GHz is easily representable
>> +???? * by 32bits.
>> +???? */
>> +??? if (period_ns > NS_IN_SEC || duty_ns > NS_IN_SEC || period_ns == 0)
>> +??????? return -ERANGE;
>> +
>> +??? if (duty_ns > period_ns)
>> +??????? return -EINVAL;
>> +
>> +??? frequency = NS_IN_SEC / period_ns;
>> +
>> +??? /* Check to see if we are changing the clock rate of the PWM */
>> +??? tin_rate = pwm_calc_tin(pwm_id, frequency);
>> +
>> +??? tin_ns = NS_IN_SEC / tin_rate;
>> +#if defined(CONFIG_ARCH_NEXELL)
>> +??? /* The counter starts at zero. */
>> +??? tcnt = (period_ns / tin_ns) - 1;
>> +#else
>> +??? tcnt = period_ns / tin_ns;
>> +#endif
>> +
>> +??? /* Note, counters count down */
>> +??? tcmp = duty_ns / tin_ns;
>> +??? tcmp = tcnt - tcmp;
>> +
>> +??? /* Update the PWM register block. */
>> +??? offset = pwm_id * 3;
>> +??? if (pwm_id < 4) {
>> +??????? writel(tcnt, &pwm->tcntb0 + offset);
>> +??????? writel(tcmp, &pwm->tcmpb0 + offset);
>> +??? }
>> +
>> +??? tcon = readl(&pwm->tcon);
>> +??? tcon |= TCON_UPDATE(pwm_id);
>> +??? if (pwm_id < 4)
>> +??????? tcon |= TCON_AUTO_RELOAD(pwm_id);
>> +??? else
>> +??????? tcon |= TCON4_AUTO_RELOAD;
>> +??? writel(tcon, &pwm->tcon);
>> +
>> +??? tcon &= ~TCON_UPDATE(pwm_id);
>> +??? writel(tcon, &pwm->tcon);
>> +
>> +??? return 0;
>> +}
>> +
>> +int pwm_init(int pwm_id, int div, int invert)
>> +{
>> +??? u32 val;
>> +??? const struct s5p_timer *pwm =
>> +#if defined(CONFIG_ARCH_NEXELL)
>> +??????????? (struct s5p_timer *)PHY_BASEADDR_PWM;
>> +#else
>> +??????????? (struct s5p_timer *)samsung_get_base_timer();
>> +#endif
>> +??? unsigned long ticks_per_period;
>> +??? unsigned int offset, prescaler;
>> +
>> +??? /*
>> +???? * Timer Freq(HZ) =
>> +???? *??? PWM_CLK / { (prescaler_value + 1) * (divider_value) }
>> +???? */
>> +
>> +??? val = readl(&pwm->tcfg0);
>> +??? if (pwm_id < 2) {
>> +??????? prescaler = PRESCALER_0;
>> +??????? val &= ~0xff;
>> +??????? val |= (prescaler & 0xff);
>> +??? } else {
>> +??????? prescaler = PRESCALER_1;
>> +??????? val &= ~(0xff << 8);
>> +??????? val |= (prescaler & 0xff) << 8;
>> +??? }
>> +??? writel(val, &pwm->tcfg0);
>> +??? val = readl(&pwm->tcfg1);
>> +??? val &= ~(0xf << MUX_DIV_SHIFT(pwm_id));
>> +??? val |= (div & 0xf) << MUX_DIV_SHIFT(pwm_id);
>> +??? writel(val, &pwm->tcfg1);
>> +
>> +??? if (pwm_id == 4) {
>> +??????? /*
>> +???????? * TODO(sjg): Use this as a countdown timer for now. We count
>> +???????? * down from the maximum value to 0, then reset.
>> +???????? */
>> +??????? ticks_per_period = -1UL;
>> +??? } else {
>> +??????? const unsigned long pwm_hz = 1000;
>> +#if defined(CONFIG_ARCH_NEXELL)
>> +??????? struct clk *clk = clk_get(CORECLK_NAME_PCLK);
>> +??????? unsigned long timer_rate_hz = clk_get_rate(clk) /
>> +#else
>> +??????? unsigned long timer_rate_hz = get_pwm_clk() /
>> +#endif
>> +??????????? ((prescaler + 1) * (1 << div));
>> +
>> +??????? ticks_per_period = timer_rate_hz / pwm_hz;
>> +??? }
>> +
>> +??? /* set count value */
>> +??? offset = pwm_id * 3;
>> +
>> +??? writel(ticks_per_period, &pwm->tcntb0 + offset);
>> +
>> +??? val = readl(&pwm->tcon) & ~(0xf << TCON_OFFSET(pwm_id));
>> +??? if (invert && pwm_id < 4)
>> +??????? val |= TCON_INVERTER(pwm_id);
>> +??? writel(val, &pwm->tcon);
>> +
>> +??? nx_gpio_set_pad_function(pwm_dev[pwm_id].grp, pwm_dev[pwm_id].bit,
>> +???????????????? pwm_dev[pwm_id].pwm_fn);
>> +??? pwm_enable(pwm_id);
>> +
>> +??? return 0;
>> +}
>> diff --git a/drivers/pwm/pwm-nexell.h b/drivers/pwm/pwm-nexell.h
>> new file mode 100644
>> index 0000000..92dc707
>> --- /dev/null
>> +++ b/drivers/pwm/pwm-nexell.h
>> @@ -0,0 +1,54 @@
>> +/* SPDX-License-Identifier: GPL-2.0+
>> + *
>> + * Copyright (C) 2009 Samsung Electronics
>> + * Kyungmin Park <kyungmin.park@samsung.com>
>> + * Minkyu Kang <mk7.kang@samsung.com>
>> + */
>> +
>> +#ifndef __ASM_ARM_ARCH_PWM_H_
>> +#define __ASM_ARM_ARCH_PWM_H_
>> +
>> +#define PRESCALER_0??????? (8 - 1)??????? /* prescaler of timer 0, 1 */
>> +#define PRESCALER_1??????? (16 - 1)??? /* prescaler of timer 2, 3, 4 */
>> +
>> +/* Divider MUX */
>> +#define MUX_DIV_1??????? 0??????? /* 1/1 period */
>> +#define MUX_DIV_2??????? 1??????? /* 1/2 period */
>> +#define MUX_DIV_4??????? 2??????? /* 1/4 period */
>> +#define MUX_DIV_8??????? 3??????? /* 1/8 period */
>> +#define MUX_DIV_16??????? 4??????? /* 1/16 period */
>> +
>> +#define MUX_DIV_SHIFT(x)??? ((x) * 4)
>> +
>> +#define TCON_OFFSET(x)??????? (((x) + 1) * (!!x) << 2)
>> +
>> +#define TCON_START(x)??????? (1 << TCON_OFFSET(x))
>> +#define TCON_UPDATE(x)??????? (1 << (TCON_OFFSET(x) + 1))
>> +#define TCON_INVERTER(x)??? (1 << (TCON_OFFSET(x) + 2))
>> +#define TCON_AUTO_RELOAD(x)??? (1 << (TCON_OFFSET(x) + 3))
>> +#define TCON4_AUTO_RELOAD??? (1 << 22)
>> +
>> +#ifndef __ASSEMBLY__
>> +struct s5p_timer {
>> +??? unsigned int??? tcfg0;
>> +??? unsigned int??? tcfg1;
>> +??? unsigned int??? tcon;
>> +??? unsigned int??? tcntb0;
>> +??? unsigned int??? tcmpb0;
>> +??? unsigned int??? tcnto0;
>> +??? unsigned int??? tcntb1;
>> +??? unsigned int??? tcmpb1;
>> +??? unsigned int??? tcnto1;
>> +??? unsigned int??? tcntb2;
>> +??? unsigned int??? tcmpb2;
>> +??? unsigned int??? tcnto2;
>> +??? unsigned int??? tcntb3;
>> +??? unsigned int??? res1;
>> +??? unsigned int??? tcnto3;
>> +??? unsigned int??? tcntb4;
>> +??? unsigned int??? tcnto4;
>> +??? unsigned int??? tintcstat;
>> +};
>> +#endif??? /* __ASSEMBLY__ */
>> +
>> +#endif
>>
>
^ permalink raw reply [flat|nested] 19+ messages in thread
* [RFC PATCH 03/10] i2c: mmc: add nexell driver (gpio, i2c, mmc, pwm)
2020-02-20 17:49 ` Stefan B.
@ 2020-02-22 12:34 ` Heiko Schocher
0 siblings, 0 replies; 19+ messages in thread
From: Heiko Schocher @ 2020-02-22 12:34 UTC (permalink / raw)
To: u-boot
Hello Stefan,
Am 20.02.2020 um 18:49 schrieb Stefan B.:
> Hello Heiko,
>
> see below my feedback, please give me further advise where indicated.
>
> Unfortunately there have been some Bugs in the i2c-driver and I learned that this driver has not
> been used at all ("i2c-gpio" has been used instead). So I have done several Bugfixes and
> improvements appart from your proposals.
>
>
> Regards
> Stefan
>
>
> Am 04.02.20 um 07:58 schrieb Heiko Schocher:
>> Hello Stefan,
>>
>> Am 03.02.2020 um 21:40 schrieb Stefan Bosch:
>>> Changes in relation to FriendlyARM's U-Boot nanopi2-v2016.01:
>>> - i2c/nx_i2c.c: Some adaptions mainly because of changes in
>>> ?? "struct udevice".
>>> - mmc: nexell_dw_mmc.c changed to nexell_dw_mmc_dm.c (switched to DM).
>>>
>>> Signed-off-by: Stefan Bosch <stefan_b@posteo.net>
>>> ---
>>>
>>> ? drivers/gpio/Kconfig?????????? |?? 9 +
>>> ? drivers/gpio/Makefile????????? |?? 1 +
>>> ? drivers/gpio/nx_gpio.c???????? | 252 +++++++++++++++++++
>>> ? drivers/i2c/Kconfig??????????? |?? 9 +
>>> ? drivers/i2c/Makefile?????????? |?? 1 +
>>> ? drivers/i2c/nx_i2c.c?????????? | 537 +++++++++++++++++++++++++++++++++++++++++
>>> ? drivers/mmc/Kconfig??????????? |?? 6 +
>>> ? drivers/mmc/Makefile?????????? |?? 1 +
>>> ? drivers/mmc/nexell_dw_mmc_dm.c | 350 +++++++++++++++++++++++++++
>>> ? drivers/pwm/Makefile?????????? |?? 1 +
>>> ? drivers/pwm/pwm-nexell.c?????? | 252 +++++++++++++++++++
>>> ? drivers/pwm/pwm-nexell.h?????? |? 54 +++++
>>
>> Could you please split this patch into 4 parts (i2c, gpio, mmc and
>> pwm) ?
>>
>> Thanks!
>>
> Ok, I will split this patch.
Thanks!
>>> ? 12 files changed, 1473 insertions(+)
>>> ? create mode 100644 drivers/gpio/nx_gpio.c
>>> ? create mode 100644 drivers/i2c/nx_i2c.c
>>> ? create mode 100644 drivers/mmc/nexell_dw_mmc_dm.c
>>> ? create mode 100644 drivers/pwm/pwm-nexell.c
>>> ? create mode 100644 drivers/pwm/pwm-nexell.h
>>>
>> [...]
>>> diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
>>> index 449046b..e3340de 100644
>>> --- a/drivers/gpio/Makefile
>>> +++ b/drivers/gpio/Makefile
>>> @@ -65,3 +65,4 @@ obj-$(CONFIG_PM8916_GPIO)??? += pm8916_gpio.o
>>> ? obj-$(CONFIG_MT7621_GPIO)??? += mt7621_gpio.o
>>> ? obj-$(CONFIG_MSCC_SGPIO)??? += mscc_sgpio.o
>>> ? obj-$(CONFIG_SIFIVE_GPIO)??? += sifive-gpio.o
>>> +obj-$(CONFIG_NX_GPIO)??????? += nx_gpio.o
>>
>> Please keep lists sorted.
>
> The list is not sorted (at least in no alphabetical order), but I can e.g. move "... += nx_gpio.o"
> one line up?
Find for me.
>>> diff --git a/drivers/gpio/nx_gpio.c b/drivers/gpio/nx_gpio.c
>>> new file mode 100644
>>> index 0000000..86472f6
>>> --- /dev/null
>>> +++ b/drivers/gpio/nx_gpio.c
>>> @@ -0,0 +1,252 @@
>>> +// SPDX-License-Identifier: GPL-2.0+
>>> +/*
>>> + * (C) Copyright 2016 Nexell
>>> + * DeokJin, Lee <truevirtue@nexell.co.kr>
>>> + */
>>> +
>>> +#include <common.h>
>>> +#include <dm.h>
>>> +#include <errno.h>
>>> +#include <malloc.h>
>>> +#include <fdtdec.h>
>>> +#include <asm/io.h>
>>> +#include <asm/gpio.h>
>>> +
>>> +DECLARE_GLOBAL_DATA_PTR;
>>> +
>>> +struct nx_gpio_regs {
>>> +??? u32??? data;??????? /* Data register */
>>> +??? u32??? outputenb;??? /* Output Enable register */
>>> +??? u32??? detmode[2];??? /* Detect Mode Register */
>>> +??? u32??? intenb;??????? /* Interrupt Enable Register */
>>> +??? u32??? det;??????? /* Event Detect Register */
>>> +??? u32??? pad;??????? /* Pad Status Register */
>>> +};
>>> +
>>> +struct nx_alive_gpio_regs {
>>> +??? u32??? pwrgate;??? /* Power Gating Register */
>>> +??? u32??? reserved0[28];??? /* Reserved0 */
>>> +??? u32??? outputenb_reset;/* Alive GPIO Output Enable Reset Register */
>>> +??? u32??? outputenb;??? /* Alive GPIO Output Enable Register */
>>> +??? u32??? outputenb_read; /* Alive GPIO Output Read Register */
>>> +??? u32??? reserved1[3];??? /* Reserved1 */
>>> +??? u32??? pad_reset;??? /* Alive GPIO Output Reset Register */
>>> +??? u32??? data;??????? /* Alive GPIO Output Register */
>>> +??? u32??? pad_read;??? /* Alive GPIO Pad Read Register */
>>> +??? u32??? reserved2[33];??? /* Reserved2 */
>>> +??? u32??? pad;??????? /* Alive GPIO Input Value Register */
>>> +};
>>> +
>>> +struct nx_gpio_platdata {
>>> +??? void *regs;
>>> +??? int gpio_count;
>>> +??? const char *bank_name;
>>> +};
>>> +
>>> +static int nx_alive_gpio_is_check(struct udevice *dev)
>>> +{
>>> +??? struct nx_gpio_platdata *plat = dev_get_platdata(dev);
>>> +??? const char *bank_name = plat->bank_name;
>>> +
>>> +??? if (!strcmp(bank_name, "gpio_alv"))
>>> +??????? return 1;
>>> +
>>> +??? return 0;
>>> +}
>>> +
>>> +static int nx_alive_gpio_direction_input(struct udevice *dev, unsigned int pin)
>>> +{
>>> +??? struct nx_gpio_platdata *plat = dev_get_platdata(dev);
>>> +??? struct nx_alive_gpio_regs *const regs = plat->regs;
>>> +
>>> +??? setbits_le32(®s->outputenb_reset, 1 << pin);
>>> +
>>> +??? return 0;
>>> +}
>>> +
>>> +static int nx_alive_gpio_direction_output(struct udevice *dev, unsigned int pin,
>>> +????????????????????? int val)
>>> +{
>>> +??? struct nx_gpio_platdata *plat = dev_get_platdata(dev);
>>> +??? struct nx_alive_gpio_regs *const regs = plat->regs;
>>> +
>>> +??? if (val)
>>> +??????? setbits_le32(®s->data, 1 << pin);
>>> +??? else
>>> +??????? setbits_le32(®s->pad_reset, 1 << pin);
>>> +
>>> +??? setbits_le32(®s->outputenb, 1 << pin);
>>> +
>>> +??? return 0;
>>> +}
>>> +
>>> +static int nx_alive_gpio_get_value(struct udevice *dev, unsigned int pin)
>>> +{
>>> +??? struct nx_gpio_platdata *plat = dev_get_platdata(dev);
>>> +??? struct nx_alive_gpio_regs *const regs = plat->regs;
>>> +??? unsigned int mask = 1UL << pin;
>>> +??? unsigned int value;
>>> +
>>> +??? value = (readl(®s->pad_read) & mask) >> pin;
>>> +
>>> +??? return value;
>>> +}
>>> +
>>> +static int nx_alive_gpio_set_value(struct udevice *dev, unsigned int pin,
>>> +?????????????????? int val)
>>> +{
>>> +??? struct nx_gpio_platdata *plat = dev_get_platdata(dev);
>>> +??? struct nx_alive_gpio_regs *const regs = plat->regs;
>>> +
>>> +??? if (val)
>>> +??????? setbits_le32(®s->data, 1 << pin);
>>> +??? else
>>> +??????? clrbits_le32(®s->pad_reset, 1 << pin);
>>> +
>>> +??? return 0;
>>> +}
>>> +
>>> +static int nx_alive_gpio_get_function(struct udevice *dev, unsigned int pin)
>>> +{
>>> +??? struct nx_gpio_platdata *plat = dev_get_platdata(dev);
>>> +??? struct nx_alive_gpio_regs *const regs = plat->regs;
>>> +??? unsigned int mask = (1UL << pin);
>>> +??? unsigned int output;
>>> +
>>> +??? output = readl(®s->outputenb_read) & mask;
>>> +
>>> +??? if (output)
>>> +??????? return GPIOF_OUTPUT;
>>> +??? else
>>> +??????? return GPIOF_INPUT;
>>> +}
>>> +
>>> +static int nx_gpio_direction_input(struct udevice *dev, unsigned int pin)
>>> +{
>>> +??? struct nx_gpio_platdata *plat = dev_get_platdata(dev);
>>> +??? struct nx_gpio_regs *const regs = plat->regs;
>>> +
>>> +??? if (nx_alive_gpio_is_check(dev))
>>> +??????? return nx_alive_gpio_direction_input(dev, pin);
>>> +
>>> +??? clrbits_le32(®s->outputenb, 1 << pin);
>>> +
>>> +??? return 0;
>>> +}
>>> +
>>> +static int nx_gpio_direction_output(struct udevice *dev, unsigned int pin,
>>> +??????????????????? int val)
>>> +{
>>> +??? struct nx_gpio_platdata *plat = dev_get_platdata(dev);
>>> +??? struct nx_gpio_regs *const regs = plat->regs;
>>> +
>>> +??? if (nx_alive_gpio_is_check(dev))
>>> +??????? return nx_alive_gpio_direction_output(dev, pin, val);
>>> +
>>> +??? if (val)
>>> +??????? setbits_le32(®s->data, 1 << pin);
>>> +??? else
>>> +??????? clrbits_le32(®s->data, 1 << pin);
>>> +
>>> +??? setbits_le32(®s->outputenb, 1 << pin);
>>> +
>>> +??? return 0;
>>> +}
>>> +
>>> +static int nx_gpio_get_value(struct udevice *dev, unsigned int pin)
>>> +{
>>> +??? struct nx_gpio_platdata *plat = dev_get_platdata(dev);
>>> +??? struct nx_gpio_regs *const regs = plat->regs;
>>> +??? unsigned int mask = 1UL << pin;
>>> +??? unsigned int value;
>>> +
>>> +??? if (nx_alive_gpio_is_check(dev))
>>> +??????? return nx_alive_gpio_get_value(dev, pin);
>>> +
>>> +??? value = (readl(®s->pad) & mask) >> pin;
>>> +
>>> +??? return value;
>>> +}
>>> +
>>> +static int nx_gpio_set_value(struct udevice *dev, unsigned int pin, int val)
>>> +{
>>> +??? struct nx_gpio_platdata *plat = dev_get_platdata(dev);
>>> +??? struct nx_gpio_regs *const regs = plat->regs;
>>> +
>>> +??? if (nx_alive_gpio_is_check(dev))
>>> +??????? return nx_alive_gpio_set_value(dev, pin, val);
>>> +
>>> +??? if (val)
>>> +??????? setbits_le32(®s->data, 1 << pin);
>>> +??? else
>>> +??????? clrbits_le32(®s->data, 1 << pin);
>>> +
>>> +??? return 0;
>>> +}
>>> +
>>> +static int nx_gpio_get_function(struct udevice *dev, unsigned int pin)
>>> +{
>>> +??? struct nx_gpio_platdata *plat = dev_get_platdata(dev);
>>> +??? struct nx_gpio_regs *const regs = plat->regs;
>>> +??? unsigned int mask = (1UL << pin);
>>> +??? unsigned int output;
>>> +
>>> +??? if (nx_alive_gpio_is_check(dev))
>>> +??????? return nx_alive_gpio_get_function(dev, pin);
>>> +
>>> +??? output = readl(®s->outputenb) & mask;
>>> +
>>> +??? if (output)
>>> +??????? return GPIOF_OUTPUT;
>>> +??? else
>>> +??????? return GPIOF_INPUT;
>>> +}
>>> +
>>> +static int nx_gpio_probe(struct udevice *dev)
>>> +{
>>> +??? struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
>>> +??? struct nx_gpio_platdata *plat = dev_get_platdata(dev);
>>> +
>>> +??? uc_priv->gpio_count = plat->gpio_count;
>>> +??? uc_priv->bank_name = plat->bank_name;
>>> +
>>> +??? return 0;
>>> +}
>>> +
>>> +static int nx_gpio_ofdata_to_platdata(struct udevice *dev)
>>> +{
>>> +??? struct nx_gpio_platdata *plat = dev_get_platdata(dev);
>>> +
>>> +??? plat->regs = map_physmem(devfdt_get_addr(dev),
>>> +???????????????? sizeof(struct nx_gpio_regs),
>>> +???????????????? MAP_NOCACHE);
>>> +??? plat->gpio_count = fdtdec_get_int(gd->fdt_blob, dev->node.of_offset,
>>> +????????????????????? "nexell,gpio-bank-width", 32);
>>> +??? plat->bank_name = fdt_getprop(gd->fdt_blob, dev->node.of_offset,
>>> +????????????????????? "gpio-bank-name", NULL);
>>> +
>>> +??? return 0;
>>> +}
>>> +
>>> +static const struct dm_gpio_ops nx_gpio_ops = {
>>> +??? .direction_input??? = nx_gpio_direction_input,
>>> +??? .direction_output??? = nx_gpio_direction_output,
>>> +??? .get_value??????? = nx_gpio_get_value,
>>> +??? .set_value??????? = nx_gpio_set_value,
>>> +??? .get_function??????? = nx_gpio_get_function,
>>> +};
>>> +
>>> +static const struct udevice_id nx_gpio_ids[] = {
>>> +??? { .compatible = "nexell,nexell-gpio" },
>>> +??? { }
>>> +};
>>> +
>>> +U_BOOT_DRIVER(nx_gpio) = {
>>> +??? .name??????? = "nx_gpio",
>>> +??? .id??????? = UCLASS_GPIO,
>>> +??? .of_match??? = nx_gpio_ids,
>>> +??? .ops??????? = &nx_gpio_ops,
>>> +??? .ofdata_to_platdata = nx_gpio_ofdata_to_platdata,
>>> +??? .platdata_auto_alloc_size = sizeof(struct nx_gpio_platdata),
>>> +??? .probe??????? = nx_gpio_probe,
>>> +};
>>> diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
>>> index 03d2fed..2cd0ed3 100644
>>> --- a/drivers/i2c/Kconfig
>>> +++ b/drivers/i2c/Kconfig
>>> @@ -317,6 +317,15 @@ config SYS_MXC_I2C8_SLAVE
>>> ?????? MXC I2C8 Slave
>>> ? endif
>>> +config SYS_I2C_NEXELL
>>> +??? bool "Nexell I2C driver"
>>> +??? depends on DM_I2C
>>> +??? help
>>> +????? Add support for the Nexell I2C driver. This is used with various
>>> +????? Nexell parts such as S5Pxx18 series SoCs. All chips
>>> +????? have several I2C ports and all are provided, controlled by the
>>> +????? device tree.
>>> +
>>> ? config SYS_I2C_OMAP24XX
>>> ????? bool "TI OMAP2+ I2C driver"
>>> ????? depends on ARCH_OMAP2PLUS || ARCH_K3
>>> diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
>>> index f5a471f..64b8ead 100644
>>> --- a/drivers/i2c/Makefile
>>> +++ b/drivers/i2c/Makefile
>>> @@ -26,6 +26,7 @@ obj-$(CONFIG_SYS_I2C_LPC32XX) += lpc32xx_i2c.o
>>> ? obj-$(CONFIG_SYS_I2C_MESON) += meson_i2c.o
>>> ? obj-$(CONFIG_SYS_I2C_MVTWSI) += mvtwsi.o
>>> ? obj-$(CONFIG_SYS_I2C_MXC) += mxc_i2c.o
>>> +obj-$(CONFIG_SYS_I2C_NEXELL) += nx_i2c.o
>>> ? obj-$(CONFIG_SYS_I2C_OMAP24XX) += omap24xx_i2c.o
>>> ? obj-$(CONFIG_SYS_I2C_RCAR_I2C) += rcar_i2c.o
>>> ? obj-$(CONFIG_SYS_I2C_RCAR_IIC) += rcar_iic.o
>>> diff --git a/drivers/i2c/nx_i2c.c b/drivers/i2c/nx_i2c.c
>>> new file mode 100644
>>> index 0000000..a3eec6c
>>> --- /dev/null
>>> +++ b/drivers/i2c/nx_i2c.c
>>> @@ -0,0 +1,537 @@
>>> +#include <common.h>
>>> +#include <errno.h>
>>> +#include <dm.h>
>>> +#include <i2c.h>
>>> +#include <asm/arch/nexell.h>
>>> +#include <asm/arch/reset.h>
>>> +#include <asm/arch/clk.h>
>>> +#include <asm/arch/nx_gpio.h>
>>> +
>>> +#define I2C_WRITE?????? 0
>>> +#define I2C_READ??????? 1
>>> +
>>> +#define I2C_OK????????? 0
>>> +#define I2C_NOK???????? 1
>>> +#define I2C_NACK??????? 2
>>> +#define I2C_NOK_LA????? 3?????? /* Lost arbitration */
>>> +#define I2C_NOK_TOUT??? 4?????? /* time out */
>>> +
>>> +#define I2CLC_FILTER??? 0x04??? /* SDA filter on*/
>>> +#define I2CSTAT_BSY???? 0x20??? /* Busy bit */
>>> +#define I2CSTAT_NACK??? 0x01??? /* Nack bit */
>>> +#define I2CSTAT_ABT??? 0x08??? /* Arbitration bit */
>>> +#define I2CCON_ACKGEN?? 0x80??? /* Acknowledge generation */
>>> +#define I2CCON_IRENB??? 0x20??? /* Interrupt Enable bit? */
>>> +#define I2CCON_IRPND??? 0x10??? /* Interrupt pending bit */
>>> +#define I2C_MODE_MT???? 0xC0??? /* Master Transmit Mode */
>>> +#define I2C_MODE_MR???? 0x80??? /* Master Receive Mode */
>>> +#define I2C_START_STOP? 0x20??? /* START / STOP */
>>> +#define I2C_TXRX_ENA??? 0x10??? /* I2C Tx/Rx enable */
>>> +
>>> +#define I2C_TIMEOUT_MS??? 10????? /* 10 ms */
>>> +
>>> +#define I2C_M_NOSTOP??? 0x100
>>> +
>>> +#ifndef CONFIG_MAX_I2C_NUM
>>> +#define CONFIG_MAX_I2C_NUM 3
>>> +#endif
>>
>> Is this really configurable? If so, I do not find the Kconfig
>> description.
>
> No, it is not configurable. I have changed it to MAX_I2C_NUM.
Ok.
>>> +
>>> +DECLARE_GLOBAL_DATA_PTR;
>>> +
>>> +struct nx_i2c_regs {
>>> +??? uint???? iiccon;
>>> +??? uint???? iicstat;
>>> +??? uint???? iicadd;
>>> +??? uint???? iicds;
>>> +??? uint???? iiclc;
>>> +};
>>> +
>>> +struct nx_i2c_bus {
>>> +??? uint bus_num;
>>> +??? struct nx_i2c_regs *regs;
>>> +??? uint speed;
>>> +??? uint target_speed;
>>> +??? uint sda_delay;
>>> +};
>>> +
>>> +/* s5pxx18 i2c must be reset before enabled */
>>> +static void i2c_reset(int ch)
>>> +{
>>> +??? int rst_id = RESET_ID_I2C0 + ch;
>>> +
>>> +??? nx_rstcon_setrst(rst_id, 0);
>>> +??? nx_rstcon_setrst(rst_id, 1);
>>> +}
>>> +
>>> +/* FIXME : this func will be removed after reset dm driver ported.
>>> + * set mmc pad alternative func.
>>> + */
>>> +static void set_i2c_pad_func(struct nx_i2c_bus *i2c)
>>> +{
>>> +??? switch (i2c->bus_num) {
>>> +??? case 0:
>>> +??????? nx_gpio_set_pad_function(3, 2, 1);
>>> +??????? nx_gpio_set_pad_function(3, 3, 1);
>>> +??????? break;
>>> +??? case 1:
>>> +??????? nx_gpio_set_pad_function(3, 4, 1);
>>> +??????? nx_gpio_set_pad_function(3, 5, 1);
>>> +??????? break;
>>> +??? case 2:
>>> +??????? nx_gpio_set_pad_function(3, 6, 1);
>>> +??????? nx_gpio_set_pad_function(3, 7, 1);
>>> +??????? break;
>>> +??? }
>>> +}
>>
>> Hmm... may this should be moved into a seperate pincontrol driver?
>
> According to the above FIXME comment from Nexell it probably should. But there is no pincontrol
> driver implemented. But is the change to a driver necessary for now?
Hmm.. it would be better to have a pinctrl driver, but I can accept it
for now.
>>> +
>>> +static uint i2c_get_clkrate(struct nx_i2c_bus *bus)
>>> +{
>>> +??? struct clk *clk;
>>> +??? int index = bus->bus_num;
>>> +??? char name[50] = {0, };
>>
>> ?
>>
>>> +
>>> +??? sprintf(name, "%s.%d", DEV_NAME_I2C, index);
>>
>> Where is DEV_NAME_I2C defined ?
>
> DEV_NAME_I2C is defined in arch/arm/mach-nexell/include/mach/nexell.h
Ah, ok.
>
>>
>>> +??? clk = clk_get((const char *)name);
>>> +??? if (!clk)
>>> +??????? return -1;
>>> +
>>> +??? return clk_get_rate(clk);
>>> +}
>>> +
>>> +static uint i2c_set_clk(struct nx_i2c_bus *bus, uint enb)
>>> +{
>>> +??? struct clk *clk;
>>> +??? char name[50];
>>> +
>>> +??? sprintf(name, "%s.%d", DEV_NAME_I2C, bus->bus_num);
>>> +??? clk = clk_get((const char *)name);
>>> +??? if (!clk)
>>> +??????? return -1;
>>> +
>>> +??? if (enb) {
>>> +??????? clk_disable(clk);
>>> +??????? clk_enable(clk);
>>> +??? } else {
>>> +??????? clk_disable(clk);
>>> +??? }
>>> +
>>> +??? return 0;
>>> +}
>>> +
>>> +/* get i2c module number from base address */
>>> +static uint i2c_get_busnum(struct nx_i2c_bus *bus)
>>> +{
>>> +??? void *base_addr = (void *)PHY_BASEADDR_I2C0;
>>> +??? int i;
>>> +
>>> +??? for (i = 0; i < CONFIG_MAX_I2C_NUM; i++) {
>>> +??????? if (base_addr == ((void *)bus->regs)) {
>>> +??????????? bus->bus_num = i;
>>> +??????????? return i;
>>> +??????? }
>>> +??????? base_addr += 0x1000;
>>> +??? }
>>> +
>>> +??? return -1;
>>
>> return -ENODEV;
>>
>> Hmm... is there no chance to use seq from struct udevice
>>
>> https://gitlab.denx.de/u-boot/u-boot/blob/master/include/dm/device.h#L152
>>
>> ?
>>
>> For example like:
>> https://gitlab.denx.de/u-boot/u-boot/blob/master/drivers/i2c/mxc_i2c.c#L895
>>
>
> Ok, I have changed this as proposed.
Thanks!
>>> +}
>>> +
>>> +/* Set SDA line delay */
>>> +static int nx_i2c_set_sda_delay(struct nx_i2c_bus *bus, ulong clkin)
>>> +{
>>> +??? struct nx_i2c_regs *i2c = bus->regs;
>>> +??? uint sda_delay = 0;
>>> +
>>> +??? if (bus->sda_delay) {
>>> +??????? sda_delay = clkin * bus->sda_delay;
>>> +??????? sda_delay = DIV_ROUND_UP(sda_delay, 1000000);
>>> +??????? sda_delay = DIV_ROUND_UP(sda_delay, 5);
>>> +??????? if (sda_delay > 3)
>>> +??????????? sda_delay = 3;
>>> +??????? sda_delay |= I2CLC_FILTER;
>>> +??? } else {
>>> +??????? sda_delay = 0;
>>> +??? }
>>> +
>>> +??? sda_delay &= 0x7;
>>> +??? writel(sda_delay, &i2c->iiclc);
>>> +
>>> +??? return 0;
>>> +}
>>> +
>>> +/* Calculate the value of the divider and prescaler, set the bus speed. */
>>> +static int nx_i2c_set_bus_speed(struct udevice *dev, uint speed)
>>> +{
>>> +??? struct nx_i2c_bus *bus = dev_get_priv(dev);
>>> +??? struct nx_i2c_regs *i2c = bus->regs;
>>> +??? unsigned long freq, pres = 16, div;
>>> +
>>> +??? freq = i2c_get_clkrate(bus);
>>> +??? /* calculate prescaler and divisor values */
>>> +??? if ((freq / pres / (16 + 1)) > speed)
>>> +??????? /* set prescaler to 512 */
>>> +??????? pres = 512;
>>> +
>>> +??? div = 0;
>>> +??? while ((freq / pres / (div + 1)) > speed)
>>> +??????? div++;
>>> +
>>> +??? /* set prescaler, divisor according to freq, also set ACKGEN, IRQ */
>>> +??? writel((div & 0x0F) | ((pres == 512) ? 0x40 : 0), &i2c->iiccon);
>>> +
>>> +??? /* init to SLAVE REVEIVE and set slaveaddr */
>>> +??? writel(0, &i2c->iicstat);
>>> +??? writel(0x00, &i2c->iicadd);
>>> +??? /* program Master Transmit (and implicit STOP) */
>>> +??? writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat);
>>> +
>>> +??? bus->speed = bus->target_speed / (div * pres);
>>
>> Do you want to allow all values of speeds or may you want to use
>> standard speeds, see:
>>
>> https://gitlab.denx.de/u-boot/u-boot/blob/master/include/i2c.h#L33
>>
>
> I'd like to allow all values of speed. In my opinion allowing only standard speeds does complicate
> things (e.g. how to do error handling?). Furthermore I think sometimes it could be handy to be able
> to set speed to an arbitrary value (e.g. to a lower value than 100000) when trying a new i2c-device
> on the bus.
ok.
>
>>> +
>>> +??? return 0;
>>> +}
>>> +
>>> +static void nx_i2c_set_clockrate(struct udevice *dev, uint speed)
>>> +{
>>> +??? struct nx_i2c_bus *bus = dev_get_priv(dev);
>>> +??? ulong clkin;
>>> +
>>> +??? nx_i2c_set_bus_speed(dev, speed);
>>> +??? clkin = bus->speed;??????????? /* the actual i2c speed */
>>> +??? clkin /= 1000;??????????????? /* clkin now in Khz */
>>> +??? nx_i2c_set_sda_delay(bus, clkin);
>>> +}
>>> +
>>> +static void i2c_process_node(struct udevice *dev)
>>> +{
>>> +??? struct nx_i2c_bus *bus = dev_get_priv(dev);
>>> +??? const void *blob = gd->fdt_blob;
>>> +
>>> +??? int node;
>>> +
>>> +??? node = dev->node.of_offset;
>>> +
>>> +??? bus->target_speed = fdtdec_get_int(blob, node,
>>> +?????????????????????? "nexell,i2c-max-bus-freq", 0);
>>> +??? bus->sda_delay = fdtdec_get_int(blob, node,
>>> +??????????????????? "nexell,i2c-sda-delay", 0);
>>
>> You introdue here new properties, please document them in
>> u-boot:/doc/device-tree-bindings/i2c
>>
>> Please without "nexell,"
>>
>
> I have changed "nexell,i2c-max-bus-freq" to the already defined "clock-frequency". Furthermore I
> have changed "nexell,i2c-sda-delay" to "i2c-sda-delay-ns".
> Furthermore, I have added "nx_i2c.txt" in doc/device-tree-bindings/i2c.
Thanks!
>
>> Do you plan to post also a linux i2c driver?
>>
>> If so, the devicetree bindings should be discussed there to avoid
>> different properties between U-Boot and linux!
>>
>
> No, I do not plan to post a linux driver.
Ok.
>
>>> +}
>>> +
>>> +static int nx_i2c_probe(struct udevice *dev)
>>> +{
>>> +??? struct nx_i2c_bus *bus = dev_get_priv(dev);
>>> +
>>> +??? /* get regs */
>>> +??? bus->regs = (struct nx_i2c_regs *)devfdt_get_addr(dev);
>>> +??? /* calc index */
>>> +??? if (!i2c_get_busnum(bus)) {
>>> +??????? debug("not found i2c number!\n");
>>> +??????? return -1;
>>
>> please return -ENODEV
>>
>
> Ok
>
>>> +??? }
>>> +
>>> +??? /* i2c optional node parsing */
>>> +??? i2c_process_node(dev);
>>> +??? if (!bus->target_speed)
>>> +??????? return -1;
>>
>> please return here also an errorcode from include/linux/errno.h
>>
>
> Ok
>
>> Hmm.. if you return here if target_speed is not set, it is not optional!
>>
>
> You are right, I have removed 'optional' in the comment.
Thanks.
>
>>> +
>>> +??? /* reset */
>>> +??? i2c_reset(bus->bus_num);
>>> +??? /* gpio pad */
>>> +??? set_i2c_pad_func(bus);
>>> +
>>> +??? /* clock rate */
>>> +??? i2c_set_clk(bus, 1);
>>> +??? nx_i2c_set_clockrate(dev, bus->target_speed);
>>> +??? i2c_set_clk(bus, 0);
>>> +
>>> +??? return 0;
>>> +}
>>> +
>>> +/* i2c bus busy check */
>>> +static int i2c_is_busy(struct nx_i2c_regs *i2c)
>>> +{
>>> +??? ulong start_time;
>>> +
>>> +??? start_time = get_timer(0);
>>> +??? while (readl(&i2c->iicstat) & I2CSTAT_BSY) {
>>> +??????? if (get_timer(start_time) > I2C_TIMEOUT_MS) {
>>> +??????????? debug("Timeout\n");
>>> +??????????? return -I2C_NOK_TOUT;
>>> +??????? }
>>> +??? }
>>> +??? return 0;
>>> +}
>>> +
>>> +/* irq enable/disable functions */
>>> +static void i2c_enable_irq(struct nx_i2c_regs *i2c)
>>> +{
>>> +??? unsigned int reg;
>>> +
>>> +??? reg = readl(&i2c->iiccon);
>>> +??? reg |= I2CCON_IRENB;
>>> +??? writel(reg, &i2c->iiccon);
>>> +}
>>> +
>>> +/* irq clear function */
>>> +static void i2c_clear_irq(struct nx_i2c_regs *i2c)
>>> +{
>>> +??? clrbits_le32(&i2c->iiccon, I2CCON_IRPND);
>>> +}
>>> +
>>> +/* ack enable functions */
>>> +static void i2c_enable_ack(struct nx_i2c_regs *i2c)
>>> +{
>>> +??? unsigned int reg;
>>> +
>>> +??? reg = readl(&i2c->iiccon);
>>> +??? reg |= I2CCON_ACKGEN;
>>> +??? writel(reg, &i2c->iiccon);
>>> +}
>>> +
>>> +static void i2c_send_stop(struct nx_i2c_regs *i2c)
>>> +{
>>> +??? unsigned int reg;
>>> +
>>> +??? /* Send STOP. */
>>> +??? reg = readl(&i2c->iicstat);
>>> +??? reg |= I2C_MODE_MR | I2C_TXRX_ENA;
>>> +??? reg &= (~I2C_START_STOP);
>>> +??? writel(reg, &i2c->iicstat);
>>> +??? i2c_clear_irq(i2c);
>>> +}
>>> +
>>> +static int wait_for_xfer(struct nx_i2c_regs *i2c)
>>> +{
>>> +??? unsigned long start_time = get_timer(0);
>>> +
>>> +??? do {
>>> +??????? if (readl(&i2c->iiccon) & I2CCON_IRPND)
>>> +??????????? return (readl(&i2c->iicstat) & I2CSTAT_NACK) ?
>>> +??????????????? I2C_NACK : I2C_OK;
>>> +??? } while (get_timer(start_time) < I2C_TIMEOUT_MS);
>>> +
>>> +??? return I2C_NOK_TOUT;
>>> +}
>>> +
>>> +static int i2c_transfer(struct nx_i2c_regs *i2c,
>>> +??????????? uchar cmd_type,
>>> +??????????? uchar chip,
>>> +??????????? uchar addr[],
>>> +??????????? uchar addr_len,
>>> +??????????? uchar data[],
>>> +??????????? unsigned short data_len,
>>> +??????????? uint seq)
>>> +{
>>> +??? uint status;
>>> +??? int i = 0, result;
>>> +
>>> +??? if (data == 0 || data_len == 0) {
>>> +??????? /*Don't support data transfer of no length or to address 0 */
>>> +??????? debug("%s: bad call\n", __func__);
>>> +??????? return I2C_NOK;
>>> +??? }
>>> +
>>> +??? i2c_enable_irq(i2c);
>>> +??? i2c_enable_ack(i2c);
>>> +
>>> +??? /* Get the slave chip address going */
>>> +??? writel(chip, &i2c->iicds);
>>> +??? status = I2C_TXRX_ENA | I2C_START_STOP;
>>> +??? if (cmd_type == I2C_WRITE || (addr && addr_len))
>>> +??????? status |= I2C_MODE_MT;
>>> +??? else
>>> +??????? status |= I2C_MODE_MR;
>>> +??? writel(status, &i2c->iicstat);
>>> +??? if (seq)
>>> +??????? i2c_clear_irq(i2c);
>>> +
>>> +??? /* Wait for chip address to transmit. */
>>> +??? result = wait_for_xfer(i2c);
>>> +??? if (result != I2C_OK)
>>> +??????? goto bailout;
>>> +
>>> +??? /* If register address needs to be transmitted - do it now. */
>>> +??? if (addr && addr_len) {? /* register addr */
>>> +??????? while ((i < addr_len) && (result == I2C_OK)) {
>>> +??????????? writel(addr[i++], &i2c->iicds);
>>> +??????????? i2c_clear_irq(i2c);
>>> +??????????? result = wait_for_xfer(i2c);
>>> +??????? }
>>> +
>>> +??????? i = 0;
>>> +??????? if (result != I2C_OK)
>>> +??????????? goto bailout;
>>> +??? }
>>> +
>>> +??? switch (cmd_type) {
>>> +??? case I2C_WRITE:
>>> +??????? while ((i < data_len) && (result == I2C_OK)) {
>>> +??????????? writel(data[i++], &i2c->iicds);
>>> +??????????? i2c_clear_irq(i2c);
>>> +??????????? result = wait_for_xfer(i2c);
>>> +??????? }
>>> +??????? break;
>>> +??? case I2C_READ:
>>> +??????? if (addr && addr_len) {
>>> +??????????? /*
>>> +???????????? * Register address has been sent, now send slave chip
>>> +???????????? * address again to start the actual read transaction.
>>> +???????????? */
>>> +??????????? writel(chip, &i2c->iicds);
>>> +
>>> +??????????? /* Generate a re-START. */
>>> +??????????? writel(I2C_MODE_MR | I2C_TXRX_ENA
>>> +??????????????????? | I2C_START_STOP, &i2c->iicstat);
>>> +??????????? i2c_clear_irq(i2c);
>>> +??????????? result = wait_for_xfer(i2c);
>>> +??????????? if (result != I2C_OK)
>>> +??????????????? goto bailout;
>>> +??????? }
>>> +
>>> +??????? while ((i < data_len) && (result == I2C_OK)) {
>>> +??????????? /* disable ACK for final READ */
>>> +??????????? if (i == data_len - 1)
>>> +??????????????? clrbits_le32(&i2c->iiccon
>>> +??????????????????????? , I2CCON_ACKGEN);
>>> +
>>> +??????????? i2c_clear_irq(i2c);
>>> +??????????? result = wait_for_xfer(i2c);
>>> +??????????? data[i++] = readb(&i2c->iicds);
>>> +??????? }
>>> +
>>> +??????? if (result == I2C_NACK)
>>> +??????????? result = I2C_OK; /* Normal terminated read. */
>>> +??????? break;
>>> +
>>> +??? default:
>>> +??????? debug("%s: bad call\n", __func__);
>>> +??????? result = I2C_NOK;
>>> +??????? break;
>>> +??? }
>>> +
>>> +bailout:
>>> +??? return result;
>>> +}
>>> +
>>> +static int nx_i2c_read(struct udevice *dev, uchar chip, uint addr,
>>> +?????????????? uint alen, uchar *buffer, uint len, uint seq)
>>> +{
>>> +??? struct nx_i2c_bus *i2c;
>>> +??? uchar xaddr[4];
>>> +??? int ret;
>>> +
>>> +??? i2c = dev_get_priv(dev);
>>> +??? if (!i2c)
>>> +??????? return -EFAULT;
>>> +
>>> +??? if (alen > 4) {
>>> +??????? debug("I2C read: addr len %d not supported\n", alen);
>>> +??????? return -EADDRNOTAVAIL;
>>> +??? }
>>> +
>>> +??? if (alen > 0)
>>> +??????? xaddr[0] = (addr >> 24) & 0xFF;
>>> +
>>> +??? if (alen > 0) {
>>> +??????? xaddr[0] = (addr >> 24) & 0xFF;
>>> +??????? xaddr[1] = (addr >> 16) & 0xFF;
>>> +??????? xaddr[2] = (addr >> 8) & 0xFF;
>>> +??????? xaddr[3] = addr & 0xFF;
>>> +??? }
>>> +
>>> +??? ret = i2c_transfer(i2c->regs, I2C_READ, chip << 1,
>>> +?????????????? &xaddr[4 - alen], alen, buffer, len, seq);
>>> +
>>> +??? if (ret) {
>>> +??????? debug("I2C read failed %d\n", ret);
>>> +??????? return -EIO;
>>> +??? }
>>> +
>>> +??? return 0;
>>> +}
>>> +
>>> +static int nx_i2c_write(struct udevice *dev, uchar chip, uint addr,
>>> +??????????? uint alen, uchar *buffer, uint len, uint seq)
>>> +{
>>> +??? struct nx_i2c_bus *i2c;
>>> +??? uchar xaddr[4];
>>> +??? int ret;
>>> +
>>> +??? i2c = dev_get_priv(dev);
>>> +??? if (!i2c)
>>> +??????? return -EFAULT;
>>> +
>>> +??? if (alen > 4) {
>>> +??????? debug("I2C write: addr len %d not supported\n", alen);
>>> +??????? return -EINVAL;
>>> +??? }
>>> +
>>> +??? if (alen > 0) {
>>> +??????? xaddr[0] = (addr >> 24) & 0xFF;
>>> +??????? xaddr[1] = (addr >> 16) & 0xFF;
>>> +??????? xaddr[2] = (addr >> 8) & 0xFF;
>>> +??????? xaddr[3] = addr & 0xFF;
>>> +??? }
>>> +
>>> +??? ret = i2c_transfer(i2c->regs, I2C_WRITE, chip << 1,
>>> +?????????????? &xaddr[4 - alen], alen, buffer, len, seq);
>>> +??? if (ret) {
>>> +??????? debug("I2C write failed %d\n", ret);
>>> +??????? return -EIO;
>>> +??? }
>>> +
>>> +??? return 0;
>>> +}
>>> +
>>> +static int nx_i2c_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs)
>>> +{
>>> +??? struct nx_i2c_bus *bus = dev_get_priv(dev);
>>> +??? struct nx_i2c_regs *i2c = bus->regs;
>>> +??? int ret;
>>> +??? int i;
>>> +
>>> +??? /* The power loss by the clock, only during on/off. */
>>> +??? i2c_set_clk(bus, 1);
>>> +
>>> +??? /* Bus State(Busy) check? */
>>> +??? ret = i2c_is_busy(i2c);
>>> +??? if (ret < 0)
>>> +??????? return ret;
>>> +
>>> +??? for (i = 0; i < nmsgs; msg++, i++) {
>>> +??????? if (msg->flags & I2C_M_RD) {
>>> +??????????? ret = nx_i2c_read(dev, msg->addr, 0, 0, msg->buf,
>>> +????????????????????? msg->len, i);
>>> +??????? } else {
>>> +??????????? ret = nx_i2c_write(dev, msg->addr, 0, 0, msg->buf,
>>> +?????????????????????? msg->len, i);
>>> +??????? }
>>> +
>>> +??????? if (ret) {
>>> +??????????? debug("i2c_xfer: error sending\n");
>>> +??????????? return -EREMOTEIO;
>>> +??????? }
>>> +??? }
>>> +??? /* Send Stop */
>>> +??? i2c_send_stop(i2c);
>>> +??? i2c_set_clk(bus, 0);
>>> +
>>> +??? return ret ? -EREMOTEIO : 0;
>>> +};
>>> +
>>> +static const struct dm_i2c_ops nx_i2c_ops = {
>>> +??? .xfer??????? = nx_i2c_xfer,
>>> +??? .set_bus_speed??? = nx_i2c_set_bus_speed,
>>> +};
>>> +
>>> +static const struct udevice_id nx_i2c_ids[] = {
>>> +??? { .compatible = "nexell,s5pxx18-i2c" },
>>
>> Same here as for the new properties. Please discuss the names on
>>
>> devicetree at vger.kernel.org <devicetree@vger.kernel.org>
>>
>> first!
>>
>>> +??? { }
>>> +};
>>> +
>>> +U_BOOT_DRIVER(i2c_nexell) = {
>>> +??? .name??????? = "i2c_nexell",
>>> +??? .id??????? = UCLASS_I2C,
>>> +??? .of_match??? = nx_i2c_ids,
>>> +??? .probe??????? = nx_i2c_probe,
>>> +??? .priv_auto_alloc_size??? = sizeof(struct nx_i2c_bus),
>>> +??? .ops??????? = &nx_i2c_ops,
>>> +};
>>
>> bye,
>> Heiko
>>> diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
>>> index 2f0eedc..bb8e7c0 100644
>>> --- a/drivers/mmc/Kconfig
>>> +++ b/drivers/mmc/Kconfig
>>> @@ -253,6 +253,12 @@ config MMC_DW_SNPS
>>> ??????? This selects support for Synopsys DesignWare Memory Card Interface driver
>>> ??????? extensions used in various Synopsys ARC devboards.
>>> +config NEXELL_DWMMC
>>> +??? bool "Nexell SD/MMC controller support"
>>> +??? depends on ARCH_NEXELL
>>> +??? depends on MMC_DW
>>> +??? default y
>>> +
>>> ? config MMC_MESON_GX
>>> ????? bool "Meson GX EMMC controller support"
>>> ????? depends on DM_MMC && BLK && ARCH_MESON
>>> diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
>>> index 9c1f8e5..a7b5a7b 100644
>>> --- a/drivers/mmc/Makefile
>>> +++ b/drivers/mmc/Makefile
>>> @@ -43,6 +43,7 @@ obj-$(CONFIG_SH_MMCIF) += sh_mmcif.o
>>> ? obj-$(CONFIG_SH_SDHI) += sh_sdhi.o
>>> ? obj-$(CONFIG_STM32_SDMMC2) += stm32_sdmmc2.o
>>> ? obj-$(CONFIG_JZ47XX_MMC) += jz_mmc.o
>>> +obj-$(CONFIG_NEXELL_DWMMC) += nexell_dw_mmc_dm.o
>>> ? # SDHCI
>>> ? obj-$(CONFIG_MMC_SDHCI)??????????? += sdhci.o
>>> diff --git a/drivers/mmc/nexell_dw_mmc_dm.c b/drivers/mmc/nexell_dw_mmc_dm.c
>>> new file mode 100644
>>> index 0000000..b06b60d
>>> --- /dev/null
>>> +++ b/drivers/mmc/nexell_dw_mmc_dm.c
>>> @@ -0,0 +1,350 @@
>>> +// SPDX-License-Identifier: GPL-2.0+
>>> +/*
>>> + * (C) Copyright 2016 Nexell
>>> + * Youngbok, Park <park@nexell.co.kr>
>>> + *
>>> + * (C) Copyright 2019 Stefan Bosch <stefan_b@posteo.net>
>>> + */
>>> +
>>> +#include <common.h>
>>> +#include <clk.h>
>>> +#include <dm.h>
>>> +#include <dt-structs.h>
>>> +#include <dwmmc.h>
>>> +#include <syscon.h>
>>> +#include <asm/gpio.h>
>>> +#include <asm/arch/nx_gpio.h>
>>> +#include <asm/arch/reset.h>
>>> +
>>> +#define DWMCI_CLKSEL??????????? 0x09C
>>> +#define DWMCI_SHIFT_0??????????? 0x0
>>> +#define DWMCI_SHIFT_1??????????? 0x1
>>> +#define DWMCI_SHIFT_2??????????? 0x2
>>> +#define DWMCI_SHIFT_3??????????? 0x3
>>> +#define DWMCI_SET_SAMPLE_CLK(x)??? (x)
>>> +#define DWMCI_SET_DRV_CLK(x)??? ((x) << 16)
>>> +#define DWMCI_SET_DIV_RATIO(x)??? ((x) << 24)
>>> +#define DWMCI_CLKCTRL??????????? 0x114
>>> +#define NX_MMC_CLK_DELAY(x, y, a, b)??? ((((x) & 0xFF) << 0) |\
>>> +??????????????????? (((y) & 0x03) << 16) |\
>>> +??????????????????? (((a) & 0xFF) << 8)? |\
>>> +??????????????????? (((b) & 0x03) << 24))
>>> +
>>> +struct nexell_mmc_plat {
>>> +??? struct mmc_config cfg;
>>> +??? struct mmc mmc;
>>> +};
>>> +
>>> +struct nexell_dwmmc_priv {
>>> +??? struct clk *clk;
>>> +??? struct dwmci_host host;
>>> +??? int fifo_size;
>>> +??? bool fifo_mode;
>>> +??? int frequency;
>>> +??? u32 min_freq;
>>> +??? u32 max_freq;
>>> +??? int d_delay;
>>> +??? int d_shift;
>>> +??? int s_delay;
>>> +??? int s_shift;
>>> +
>>> +};
>>> +
>>> +struct clk *clk_get(const char *id);
>>> +
>>> +static void set_pin_stat(int index, int bit, int value)
>>> +{
>>> +#if !defined(CONFIG_SPL_BUILD)
>>> +??? nx_gpio_set_pad_function(index, bit, value);
>>> +#else
>>> +#if defined(CONFIG_ARCH_S5P4418) ||??? \
>>> +??? defined(CONFIG_ARCH_S5P6818)
>>> +
>>> +??? unsigned long base[5] = {
>>> +??????? PHY_BASEADDR_GPIOA, PHY_BASEADDR_GPIOB,
>>> +??????? PHY_BASEADDR_GPIOC, PHY_BASEADDR_GPIOD,
>>> +??????? PHY_BASEADDR_GPIOE,
>>> +??? };
>>> +
>>> +??? dw_mmc_set_pin(base[index], bit, value);
>>> +#endif
>>> +#endif
>>> +}
>>> +
>>> +static void nx_dw_mmc_set_pin(struct dwmci_host *host)
>>> +{
>>> +??? debug("? %s(): dev_index == %d", __func__, host->dev_index);
>>> +
>>> +??? switch (host->dev_index) {
>>> +??? case 0:
>>> +??????? set_pin_stat(0, 29, 1);
>>> +??????? set_pin_stat(0, 31, 1);
>>> +??????? set_pin_stat(1, 1, 1);
>>> +??????? set_pin_stat(1, 3, 1);
>>> +??????? set_pin_stat(1, 5, 1);
>>> +??????? set_pin_stat(1, 7, 1);
>>> +??????? break;
>>> +??? case 1:
>>> +??????? set_pin_stat(3, 22, 1);
>>> +??????? set_pin_stat(3, 23, 1);
>>> +??????? set_pin_stat(3, 24, 1);
>>> +??????? set_pin_stat(3, 25, 1);
>>> +??????? set_pin_stat(3, 26, 1);
>>> +??????? set_pin_stat(3, 27, 1);
>>> +??????? break;
>>> +??? case 2:
>>> +??????? set_pin_stat(2, 18, 2);
>>> +??????? set_pin_stat(2, 19, 2);
>>> +??????? set_pin_stat(2, 20, 2);
>>> +??????? set_pin_stat(2, 21, 2);
>>> +??????? set_pin_stat(2, 22, 2);
>>> +??????? set_pin_stat(2, 23, 2);
>>> +??????? if (host->buswidth == 8) {
>>> +??????????? set_pin_stat(4, 21, 2);
>>> +??????????? set_pin_stat(4, 22, 2);
>>> +??????????? set_pin_stat(4, 23, 2);
>>> +??????????? set_pin_stat(4, 24, 2);
>>> +??????? }
>>> +??????? break;
>>> +??? default:
>>> +??????? debug(" is invalid!");
>>> +??? }
>>> +??? debug("\n");
>>> +}
>>> +
>>> +static void nx_dw_mmc_clksel(struct dwmci_host *host)
>>> +{
>>> +??? u32 val;
>>> +
>>> +#ifdef CONFIG_BOOST_MMC
>>> +??? val = DWMCI_SET_SAMPLE_CLK(DWMCI_SHIFT_0) |
>>> +??????? DWMCI_SET_DRV_CLK(DWMCI_SHIFT_0) | DWMCI_SET_DIV_RATIO(1);
>>> +#else
>>> +??? val = DWMCI_SET_SAMPLE_CLK(DWMCI_SHIFT_0) |
>>> +??????? DWMCI_SET_DRV_CLK(DWMCI_SHIFT_0) | DWMCI_SET_DIV_RATIO(3);
>>> +#endif
>>> +
>>> +??? dwmci_writel(host, DWMCI_CLKSEL, val);
>>> +}
>>> +
>>> +static void nx_dw_mmc_reset(int ch)
>>> +{
>>> +??? int rst_id = RESET_ID_SDMMC0 + ch;
>>> +
>>> +??? nx_rstcon_setrst(rst_id, 0);
>>> +??? nx_rstcon_setrst(rst_id, 1);
>>> +}
>>> +
>>> +static void nx_dw_mmc_clk_delay(struct udevice *dev)
>>> +{
>>> +??? unsigned int delay;
>>> +??? struct nexell_dwmmc_priv *priv = dev_get_priv(dev);
>>> +??? struct dwmci_host *host = &priv->host;
>>> +
>>> +??? delay = NX_MMC_CLK_DELAY(priv->d_delay,
>>> +???????????????? priv->d_shift, priv->s_delay, priv->s_shift);
>>> +
>>> +??? writel(delay, (host->ioaddr + DWMCI_CLKCTRL));
>>> +??? debug("%s(): Values set: d_delay==%d, d_shift==%d, s_delay==%d, "
>>> +????????? "s_shift==%d\n", __func__, priv->d_delay, priv->d_shift,
>>> +????????? priv->s_delay, priv->s_shift);
>>> +}
>>> +
>>> +static unsigned int nx_dw_mmc_get_clk(struct dwmci_host *host, uint freq)
>>> +{
>>> +??? struct clk *clk;
>>> +??? struct udevice *dev = host->priv;
>>> +??? struct nexell_dwmmc_priv *priv = dev_get_priv(dev);
>>> +
>>> +??? int index = host->dev_index;
>>> +??? char name[50] = { 0, };
>>> +
>>> +??? clk = priv->clk;
>>> +??? if (!clk) {
>>> +??????? sprintf(name, "%s.%d", DEV_NAME_SDHC, index);
>>> +??????? clk = clk_get((const char *)name);
>>> +??????? if (!clk)
>>> +??????????? return 0;
>>> +??????? priv->clk = clk;
>>> +??? }
>>> +
>>> +??? return clk_get_rate(clk) / 2;
>>> +}
>>> +
>>> +static unsigned long nx_dw_mmc_set_clk(struct dwmci_host *host,
>>> +?????????????????????? unsigned int rate)
>>> +{
>>> +??? struct clk *clk;
>>> +??? char name[50] = { 0, };
>>> +??? struct udevice *dev = host->priv;
>>> +??? struct nexell_dwmmc_priv *priv = dev_get_priv(dev);
>>> +
>>> +??? int index = host->dev_index;
>>> +
>>> +??? clk = priv->clk;
>>> +??? if (!clk) {
>>> +??????? sprintf(name, "%s.%d", DEV_NAME_SDHC, index);
>>> +??????? clk = clk_get((const char *)name);
>>> +??????? if (!clk)
>>> +??????????? return 0;
>>> +??????? priv->clk = clk;
>>> +??? }
>>> +
>>> +??? clk_disable(clk);
>>> +??? rate = clk_set_rate(clk, rate);
>>> +??? clk_enable(clk);
>>> +
>>> +??? return rate;
>>> +}
>>> +
>>> +static int nexell_dwmmc_ofdata_to_platdata(struct udevice *dev)
>>> +{
>>> +??? /* if (dev): *priv = dev->priv, else: *priv = NULL */
>>> +??? struct nexell_dwmmc_priv *priv = dev_get_priv(dev);
>>> +??? struct dwmci_host *host = &priv->host;
>>> +??? int val = -1;
>>> +
>>> +??? debug("%s()\n", __func__);
>>> +
>>> +??? host->name = dev->name;
>>> +??? host->ioaddr = dev_read_addr_ptr(dev);
>>> +
>>> +??? val = dev_read_u32_default(dev, "nexell,bus-width", -1);
>>> +??? if (val < 0) {
>>> +??????? debug("? 'nexell,bus-width' missing/invalid!\n");
>>> +??????? return -EINVAL;
>>> +??? }
>>> +??? host->buswidth = val;
>>> +??? host->get_mmc_clk = nx_dw_mmc_get_clk;
>>> +??? host->clksel = nx_dw_mmc_clksel;
>>> +??? host->priv = dev;
>>> +
>>> +??? val = dev_read_u32_default(dev, "index", -1);
>>> +??? if (val < 0) {
>>> +??????? debug("? 'index' missing/invalid!\n");
>>> +??????? return -EINVAL;
>>> +??? }
>>> +??? host->dev_index = val;
>>> +
>>> +??? val = dev_read_u32_default(dev, "fifo-size", 0x20);
>>> +??? if (val <= 0) {
>>> +??????? debug("? 'fifo-size' missing/invalid!\n");
>>> +??????? return -EINVAL;
>>> +??? }
>>> +??? priv->fifo_size = val;
>>> +
>>> +??? priv->fifo_mode = dev_read_bool(dev, "fifo-mode");
>>> +
>>> +??? val = dev_read_u32_default(dev, "frequency", -1);
>>> +??? if (val < 0) {
>>> +??????? debug("? 'frequency' missing/invalid!\n");
>>> +??????? return -EINVAL;
>>> +??? }
>>> +??? priv->frequency = val;
>>> +
>>> +??? val = dev_read_u32_default(dev, "max-frequency", -1);
>>> +??? if (val < 0) {
>>> +??????? debug("? 'max-frequency' missing/invalid!\n");
>>> +??????? return -EINVAL;
>>> +??? }
>>> +??? priv->max_freq = val;
>>> +??? priv->min_freq = 400000;? /* 400 kHz */
>>> +
>>> +??? val = dev_read_u32_default(dev, "nexell,drive_dly", -1);
>>> +??? if (val < 0) {
>>> +??????? debug("? 'nexell,drive_dly' missing/invalid!\n");
>>> +??????? return -EINVAL;
>>> +??? }
>>> +??? priv->d_delay = val;
>>> +
>>> +??? val = dev_read_u32_default(dev, "nexell,drive_shift", -1);
>>> +??? if (val < 0) {
>>> +??????? debug("? 'nexell,drive_shift' missing/invalid!\n");
>>> +??????? return -EINVAL;
>>> +??? }
>>> +??? priv->d_shift = val;
>>> +
>>> +??? val = dev_read_u32_default(dev, "nexell,sample_dly", -1);
>>> +??? if (val < 0) {
>>> +??????? debug("? 'nexell,sample_dly' missing/invalid!\n");
>>> +??????? return -EINVAL;
>>> +??? }
>>> +??? priv->s_delay = val;
>>> +
>>> +??? val = dev_read_u32_default(dev, "nexell,sample_shift", -1);
>>> +??? if (val < 0) {
>>> +??????? debug("? 'nexell,sample_shift' missing/invalid!\n");
>>> +??????? return -EINVAL;
>>> +??? }
>>> +??? priv->s_shift = val;
>>> +
>>> +??? debug("? index==%d, name==%s, ioaddr==0x%08x, buswidth==%d, "
>>> +????????? "fifo_size==%d, fifo_mode==%d, frequency==%d\n",
>>> +????????? host->dev_index, host->name, (u32)host->ioaddr,
>>> +????????? host->buswidth, priv->fifo_size, priv->fifo_mode,
>>> +????????? priv->frequency);
>>> +??? debug("? min_freq==%d, max_freq==%d, delay: "
>>> +????????? "0x%02x:0x%02x:0x%02x:0x%02x\n",
>>> +????????? priv->min_freq, priv->max_freq, priv->d_delay,
>>> +????????? priv->d_shift, priv->s_delay, priv->s_shift);
>>> +
>>> +??? return 0;
>>> +}
>>> +
>>> +static int nexell_dwmmc_probe(struct udevice *dev)
>>> +{
>>> +??? struct nexell_mmc_plat *plat = dev_get_platdata(dev);
>>> +??? struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
>>> +??? struct nexell_dwmmc_priv *priv = dev_get_priv(dev);
>>> +??? struct dwmci_host *host = &priv->host;
>>> +??? struct udevice *pwr_dev __maybe_unused;
>>> +
>>> +??? debug("%s():\n", __func__);
>>> +
>>> +??? host->fifoth_val = MSIZE(0x2) |
>>> +??????? RX_WMARK(priv->fifo_size / 2 - 1) |
>>> +??????? TX_WMARK(priv->fifo_size / 2);
>>> +
>>> +??? host->fifo_mode = priv->fifo_mode;
>>> +
>>> +??? dwmci_setup_cfg(&plat->cfg, host, priv->max_freq, priv->min_freq);
>>> +??? host->mmc = &plat->mmc;
>>> +??? host->mmc->priv = &priv->host;
>>> +??? host->mmc->dev = dev;
>>> +??? upriv->mmc = host->mmc;
>>> +
>>> +??? nx_dw_mmc_set_pin(host);
>>> +
>>> +??? debug("? nx_dw_mmc_set_clk(host, frequency * 4 == %d)\n",
>>> +????????? priv->frequency * 4);
>>> +??? nx_dw_mmc_set_clk(host, priv->frequency * 4);
>>> +
>>> +??? nx_dw_mmc_reset(host->dev_index);
>>> +??? nx_dw_mmc_clk_delay(dev);
>>> +
>>> +??? return dwmci_probe(dev);
>>> +}
>>> +
>>> +static int nexell_dwmmc_bind(struct udevice *dev)
>>> +{
>>> +??? struct nexell_mmc_plat *plat = dev_get_platdata(dev);
>>> +
>>> +??? return dwmci_bind(dev, &plat->mmc, &plat->cfg);
>>> +}
>>> +
>>> +static const struct udevice_id nexell_dwmmc_ids[] = {
>>> +??? { .compatible = "nexell,nexell-dwmmc" },
>>> +??? { }
>>> +};
>>> +
>>> +U_BOOT_DRIVER(nexell_dwmmc_drv) = {
>>> +??? .name??????? = "nexell_dwmmc",
>>> +??? .id??????? = UCLASS_MMC,
>>> +??? .of_match??? = nexell_dwmmc_ids,
>>> +??? .ofdata_to_platdata = nexell_dwmmc_ofdata_to_platdata,
>>> +??? .ops??????? = &dm_dwmci_ops,
>>> +??? .bind??????? = nexell_dwmmc_bind,
>>> +??? .probe??????? = nexell_dwmmc_probe,
>>> +??? .priv_auto_alloc_size = sizeof(struct nexell_dwmmc_priv),
>>> +??? .platdata_auto_alloc_size = sizeof(struct nexell_mmc_plat),
>>> +};
>>> diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
>>> index a837c35..b45aada 100644
>>> --- a/drivers/pwm/Makefile
>>> +++ b/drivers/pwm/Makefile
>>> @@ -16,3 +16,4 @@ obj-$(CONFIG_PWM_ROCKCHIP)??? += rk_pwm.o
>>> ? obj-$(CONFIG_PWM_SANDBOX)??? += sandbox_pwm.o
>>> ? obj-$(CONFIG_PWM_TEGRA)??????? += tegra_pwm.o
>>> ? obj-$(CONFIG_PWM_SUNXI)??????? += sunxi_pwm.o
>>> +obj-$(CONFIG_PWM_NX)??????? += pwm-nexell.o
>>> diff --git a/drivers/pwm/pwm-nexell.c b/drivers/pwm/pwm-nexell.c
>>> new file mode 100644
>>> index 0000000..6c0f8f4
>>> --- /dev/null
>>> +++ b/drivers/pwm/pwm-nexell.c
>>> @@ -0,0 +1,252 @@
>>> +// SPDX-License-Identifier: GPL-2.0+
>>> +/*
>>> + * Copyright (C) 2011 Samsung Electronics
>>> + *
>>> + * Donghwa Lee <dh09.lee@samsung.com>
>>> + */
>>> +
>>> +/* This codes are copied from arch/arm/cpu/armv7/s5p-common/pwm.c */
>>> +
>>> +#include <common.h>
>>> +#include <errno.h>
>>> +#include <pwm.h>
>>> +#include <asm/io.h>
>>> +#include <asm/arch/clk.h>
>>> +#include "pwm-nexell.h"
>>> +
>>> +#if defined(CONFIG_ARCH_NEXELL)
>>> +#include <asm/arch/nexell.h>
>>> +#include <asm/arch/reset.h>
>>> +#include <asm/arch/nx_gpio.h>
>>> +#include <asm/arch/tieoff.h>
>>> +
>>> +struct pwm_device {
>>> +??? int ch;
>>> +??? int grp;
>>> +??? int bit;
>>> +??? int pwm_fn;
>>> +};
>>> +
>>> +static struct pwm_device pwm_dev[] = {
>>> +??? [0] = { .ch = 0, .grp = 3, .bit = 1,? .pwm_fn = 1 },
>>> +??? [1] = { .ch = 1, .grp = 2, .bit = 13, .pwm_fn = 2 },
>>> +??? [2] = { .ch = 2, .grp = 2, .bit = 14, .pwm_fn =??? 2 },
>>> +??? [3] = { .ch = 3, .grp = 3, .bit = 0,? .pwm_fn = 2 },
>>> +};
>>> +#endif
>>> +
>>> +int pwm_enable(int pwm_id)
>>> +{
>>> +??? const struct s5p_timer *pwm =
>>> +#if defined(CONFIG_ARCH_NEXELL)
>>> +??????????? (struct s5p_timer *)PHY_BASEADDR_PWM;
>>> +#else
>>> +??????????? (struct s5p_timer *)samsung_get_base_timer();
>>> +#endif
>>> +??? unsigned long tcon;
>>> +
>>> +??? tcon = readl(&pwm->tcon);
>>> +??? tcon |= TCON_START(pwm_id);
>>> +
>>> +??? writel(tcon, &pwm->tcon);
>>> +
>>> +??? return 0;
>>> +}
>>> +
>>> +void pwm_disable(int pwm_id)
>>> +{
>>> +??? const struct s5p_timer *pwm =
>>> +#if defined(CONFIG_ARCH_NEXELL)
>>> +??????????? (struct s5p_timer *)PHY_BASEADDR_PWM;
>>> +#else
>>> +??????????? (struct s5p_timer *)samsung_get_base_timer();
>>> +#endif
>>> +??? unsigned long tcon;
>>> +
>>> +??? tcon = readl(&pwm->tcon);
>>> +??? tcon &= ~TCON_START(pwm_id);
>>> +
>>> +??? writel(tcon, &pwm->tcon);
>>> +}
>>> +
>>> +static unsigned long pwm_calc_tin(int pwm_id, unsigned long freq)
>>> +{
>>> +??? unsigned long tin_parent_rate;
>>> +??? unsigned int div;
>>> +#if defined(CONFIG_ARCH_NEXELL)
>>> +??? unsigned int pre_div;
>>> +??? const struct s5p_timer *pwm =
>>> +??????? (struct s5p_timer *)PHY_BASEADDR_PWM;
>>> +??? unsigned int val;
>>> +#endif
>>> +
>>> +#if defined(CONFIG_ARCH_NEXELL)
>>> +??? struct clk *clk = clk_get(CORECLK_NAME_PCLK);
>>> +
>>> +??? tin_parent_rate = clk_get_rate(clk);
>>> +#else
>>> +??? tin_parent_rate = get_pwm_clk();
>>> +#endif
>>> +
>>> +#if defined(CONFIG_ARCH_NEXELL)
>>> +??? writel(0, &pwm->tcfg0);
>>> +??? val = readl(&pwm->tcfg0);
>>> +
>>> +??? if (pwm_id < 2)
>>> +??????? div = ((val >> 0) & 0xff) + 1;
>>> +??? else
>>> +??????? div = ((val >> 8) & 0xff) + 1;
>>> +
>>> +??? writel(0, &pwm->tcfg1);
>>> +??? val = readl(&pwm->tcfg1);
>>> +??? val = (val >> MUX_DIV_SHIFT(pwm_id)) & 0xF;
>>> +??? pre_div = (1UL << val);
>>> +
>>> +??? freq = tin_parent_rate / div / pre_div;
>>> +
>>> +??? return freq;
>>> +#else
>>> +??? for (div = 2; div <= 16; div *= 2) {
>>> +??????? if ((tin_parent_rate / (div << 16)) < freq)
>>> +??????????? return tin_parent_rate / div;
>>> +??? }
>>> +
>>> +??? return tin_parent_rate / 16;
>>> +#endif
>>> +}
>>> +
>>> +#define NS_IN_SEC 1000000000UL
>>> +
>>> +int pwm_config(int pwm_id, int duty_ns, int period_ns)
>>> +{
>>> +??? const struct s5p_timer *pwm =
>>> +#if defined(CONFIG_ARCH_NEXELL)
>>> +??????? (struct s5p_timer *)PHY_BASEADDR_PWM;
>>> +#else
>>> +??????? (struct s5p_timer *)samsung_get_base_timer();
>>> +#endif
>>> +??? unsigned int offset;
>>> +??? unsigned long tin_rate;
>>> +??? unsigned long tin_ns;
>>> +??? unsigned long frequency;
>>> +??? unsigned long tcon;
>>> +??? unsigned long tcnt;
>>> +??? unsigned long tcmp;
>>> +
>>> +??? /*
>>> +???? * We currently avoid using 64bit arithmetic by using the
>>> +???? * fact that anything faster than 1GHz is easily representable
>>> +???? * by 32bits.
>>> +???? */
>>> +??? if (period_ns > NS_IN_SEC || duty_ns > NS_IN_SEC || period_ns == 0)
>>> +??????? return -ERANGE;
>>> +
>>> +??? if (duty_ns > period_ns)
>>> +??????? return -EINVAL;
>>> +
>>> +??? frequency = NS_IN_SEC / period_ns;
>>> +
>>> +??? /* Check to see if we are changing the clock rate of the PWM */
>>> +??? tin_rate = pwm_calc_tin(pwm_id, frequency);
>>> +
>>> +??? tin_ns = NS_IN_SEC / tin_rate;
>>> +#if defined(CONFIG_ARCH_NEXELL)
>>> +??? /* The counter starts at zero. */
>>> +??? tcnt = (period_ns / tin_ns) - 1;
>>> +#else
>>> +??? tcnt = period_ns / tin_ns;
>>> +#endif
>>> +
>>> +??? /* Note, counters count down */
>>> +??? tcmp = duty_ns / tin_ns;
>>> +??? tcmp = tcnt - tcmp;
>>> +
>>> +??? /* Update the PWM register block. */
>>> +??? offset = pwm_id * 3;
>>> +??? if (pwm_id < 4) {
>>> +??????? writel(tcnt, &pwm->tcntb0 + offset);
>>> +??????? writel(tcmp, &pwm->tcmpb0 + offset);
>>> +??? }
>>> +
>>> +??? tcon = readl(&pwm->tcon);
>>> +??? tcon |= TCON_UPDATE(pwm_id);
>>> +??? if (pwm_id < 4)
>>> +??????? tcon |= TCON_AUTO_RELOAD(pwm_id);
>>> +??? else
>>> +??????? tcon |= TCON4_AUTO_RELOAD;
>>> +??? writel(tcon, &pwm->tcon);
>>> +
>>> +??? tcon &= ~TCON_UPDATE(pwm_id);
>>> +??? writel(tcon, &pwm->tcon);
>>> +
>>> +??? return 0;
>>> +}
>>> +
>>> +int pwm_init(int pwm_id, int div, int invert)
>>> +{
>>> +??? u32 val;
>>> +??? const struct s5p_timer *pwm =
>>> +#if defined(CONFIG_ARCH_NEXELL)
>>> +??????????? (struct s5p_timer *)PHY_BASEADDR_PWM;
>>> +#else
>>> +??????????? (struct s5p_timer *)samsung_get_base_timer();
>>> +#endif
>>> +??? unsigned long ticks_per_period;
>>> +??? unsigned int offset, prescaler;
>>> +
>>> +??? /*
>>> +???? * Timer Freq(HZ) =
>>> +???? *??? PWM_CLK / { (prescaler_value + 1) * (divider_value) }
>>> +???? */
>>> +
>>> +??? val = readl(&pwm->tcfg0);
>>> +??? if (pwm_id < 2) {
>>> +??????? prescaler = PRESCALER_0;
>>> +??????? val &= ~0xff;
>>> +??????? val |= (prescaler & 0xff);
>>> +??? } else {
>>> +??????? prescaler = PRESCALER_1;
>>> +??????? val &= ~(0xff << 8);
>>> +??????? val |= (prescaler & 0xff) << 8;
>>> +??? }
>>> +??? writel(val, &pwm->tcfg0);
>>> +??? val = readl(&pwm->tcfg1);
>>> +??? val &= ~(0xf << MUX_DIV_SHIFT(pwm_id));
>>> +??? val |= (div & 0xf) << MUX_DIV_SHIFT(pwm_id);
>>> +??? writel(val, &pwm->tcfg1);
>>> +
>>> +??? if (pwm_id == 4) {
>>> +??????? /*
>>> +???????? * TODO(sjg): Use this as a countdown timer for now. We count
>>> +???????? * down from the maximum value to 0, then reset.
>>> +???????? */
>>> +??????? ticks_per_period = -1UL;
>>> +??? } else {
>>> +??????? const unsigned long pwm_hz = 1000;
>>> +#if defined(CONFIG_ARCH_NEXELL)
>>> +??????? struct clk *clk = clk_get(CORECLK_NAME_PCLK);
>>> +??????? unsigned long timer_rate_hz = clk_get_rate(clk) /
>>> +#else
>>> +??????? unsigned long timer_rate_hz = get_pwm_clk() /
>>> +#endif
>>> +??????????? ((prescaler + 1) * (1 << div));
>>> +
>>> +??????? ticks_per_period = timer_rate_hz / pwm_hz;
>>> +??? }
>>> +
>>> +??? /* set count value */
>>> +??? offset = pwm_id * 3;
>>> +
>>> +??? writel(ticks_per_period, &pwm->tcntb0 + offset);
>>> +
>>> +??? val = readl(&pwm->tcon) & ~(0xf << TCON_OFFSET(pwm_id));
>>> +??? if (invert && pwm_id < 4)
>>> +??????? val |= TCON_INVERTER(pwm_id);
>>> +??? writel(val, &pwm->tcon);
>>> +
>>> +??? nx_gpio_set_pad_function(pwm_dev[pwm_id].grp, pwm_dev[pwm_id].bit,
>>> +???????????????? pwm_dev[pwm_id].pwm_fn);
>>> +??? pwm_enable(pwm_id);
>>> +
>>> +??? return 0;
>>> +}
>>> diff --git a/drivers/pwm/pwm-nexell.h b/drivers/pwm/pwm-nexell.h
>>> new file mode 100644
>>> index 0000000..92dc707
>>> --- /dev/null
>>> +++ b/drivers/pwm/pwm-nexell.h
>>> @@ -0,0 +1,54 @@
>>> +/* SPDX-License-Identifier: GPL-2.0+
>>> + *
>>> + * Copyright (C) 2009 Samsung Electronics
>>> + * Kyungmin Park <kyungmin.park@samsung.com>
>>> + * Minkyu Kang <mk7.kang@samsung.com>
>>> + */
>>> +
>>> +#ifndef __ASM_ARM_ARCH_PWM_H_
>>> +#define __ASM_ARM_ARCH_PWM_H_
>>> +
>>> +#define PRESCALER_0??????? (8 - 1)??????? /* prescaler of timer 0, 1 */
>>> +#define PRESCALER_1??????? (16 - 1)??? /* prescaler of timer 2, 3, 4 */
>>> +
>>> +/* Divider MUX */
>>> +#define MUX_DIV_1??????? 0??????? /* 1/1 period */
>>> +#define MUX_DIV_2??????? 1??????? /* 1/2 period */
>>> +#define MUX_DIV_4??????? 2??????? /* 1/4 period */
>>> +#define MUX_DIV_8??????? 3??????? /* 1/8 period */
>>> +#define MUX_DIV_16??????? 4??????? /* 1/16 period */
>>> +
>>> +#define MUX_DIV_SHIFT(x)??? ((x) * 4)
>>> +
>>> +#define TCON_OFFSET(x)??????? (((x) + 1) * (!!x) << 2)
>>> +
>>> +#define TCON_START(x)??????? (1 << TCON_OFFSET(x))
>>> +#define TCON_UPDATE(x)??????? (1 << (TCON_OFFSET(x) + 1))
>>> +#define TCON_INVERTER(x)??? (1 << (TCON_OFFSET(x) + 2))
>>> +#define TCON_AUTO_RELOAD(x)??? (1 << (TCON_OFFSET(x) + 3))
>>> +#define TCON4_AUTO_RELOAD??? (1 << 22)
>>> +
>>> +#ifndef __ASSEMBLY__
>>> +struct s5p_timer {
>>> +??? unsigned int??? tcfg0;
>>> +??? unsigned int??? tcfg1;
>>> +??? unsigned int??? tcon;
>>> +??? unsigned int??? tcntb0;
>>> +??? unsigned int??? tcmpb0;
>>> +??? unsigned int??? tcnto0;
>>> +??? unsigned int??? tcntb1;
>>> +??? unsigned int??? tcmpb1;
>>> +??? unsigned int??? tcnto1;
>>> +??? unsigned int??? tcntb2;
>>> +??? unsigned int??? tcmpb2;
>>> +??? unsigned int??? tcnto2;
>>> +??? unsigned int??? tcntb3;
>>> +??? unsigned int??? res1;
>>> +??? unsigned int??? tcnto3;
>>> +??? unsigned int??? tcntb4;
>>> +??? unsigned int??? tcnto4;
>>> +??? unsigned int??? tintcstat;
>>> +};
>>> +#endif??? /* __ASSEMBLY__ */
>>> +
>>> +#endif
>>>
>>
>
bye,
Heiko
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-52 Fax: +49-8142-66989-80 Email: hs at denx.de
^ permalink raw reply [flat|nested] 19+ messages in thread
* [RFC PATCH 00/10] arm: add support for SoC S5P4418
2020-02-03 19:39 [RFC PATCH 00/10] arm: add support for SoC S5P4418 Stefan Bosch
` (10 preceding siblings ...)
2020-02-07 16:11 ` [RFC PATCH 00/10] arm: add support for SoC S5P4418 Tom Rini
@ 2020-02-22 13:06 ` Amit Tomer
2020-02-25 19:13 ` Stefan B.
11 siblings, 1 reply; 19+ messages in thread
From: Amit Tomer @ 2020-02-22 13:06 UTC (permalink / raw)
To: u-boot
Hi,
On Tue, Feb 4, 2020 at 1:12 AM Stefan Bosch <stefan_b@posteo.net> wrote:
>
>
> This patch adds support for SAMSUNG's/NEXELL's ARM Cortex-A9 based
> S5P4418 SoC, especially FriendlyARM's NanoPi2 and NanoPC-T2 boards.
> It is based on the following FriendlyARM's U-Boot version:
> https://github.com/friendlyarm/u-boot/tree/nanopi2-v2016.01.
>
I don't think this is the right approach, i.e. to take everything from
BSP source as it is and put
it into mainline U-BOOT. AFAIR, Some of the peripherals present on
these NEXELL SoC's are
compatible with SAMSUNG IP (for instance the UART).
So, are we sure that some of the already existing code in U-BOOT can't
be re-used to drive those
compatible peripherals at-least ?
Thanks
-Amit
^ permalink raw reply [flat|nested] 19+ messages in thread
* [RFC PATCH 00/10] arm: add support for SoC S5P4418
2020-02-22 13:06 ` Amit Tomer
@ 2020-02-25 19:13 ` Stefan B.
0 siblings, 0 replies; 19+ messages in thread
From: Stefan B. @ 2020-02-25 19:13 UTC (permalink / raw)
To: u-boot
Hi Amit,
Am 22.02.20 um 14:06 schrieb Amit Tomer:
> Hi,
>
> On Tue, Feb 4, 2020 at 1:12 AM Stefan Bosch <stefan_b@posteo.net> wrote:
>>
>>
>> This patch adds support for SAMSUNG's/NEXELL's ARM Cortex-A9 based
>> S5P4418 SoC, especially FriendlyARM's NanoPi2 and NanoPC-T2 boards.
>> It is based on the following FriendlyARM's U-Boot version:
>> https://github.com/friendlyarm/u-boot/tree/nanopi2-v2016.01.
>>
> I don't think this is the right approach, i.e. to take everything from
> BSP source as it is and put
> it into mainline U-BOOT. AFAIR, Some of the peripherals present on
> these NEXELL SoC's are
> compatible with SAMSUNG IP (for instance the UART).
> So, are we sure that some of the already existing code in U-BOOT can't
> be re-used to drive those
> compatible peripherals at-least ?
>
> Thanks
> -Amit
>
You are right, already existing code in U-BOOT should be used where
possible. So I have reviewed the code (and will review it further). Up
to now, I have the following proposals for the peripherials indicated:
UART:
Actually the UARTs of the S5P4418 are Amba PrimeCell PL011 compatible,
therefore the appropriate code is used. S5P6818 does have different
UARTs which apparently arch/arm/mach-nexell/serial.c is for. Since
S5P6818 is not supported (yet) I will remove this file.
TIMER:
Currently arch/arm/mach-nexell/timer.c is used. I will try to use
arch/arm/cpu/armv7/s5p-common/timer.c instead. The timer-registers used
seem to be the same, but the functions in timer.c are not which is a
possible pitfall.
PWM:
Currently drivers/pwm/pwm-nexell.c is used. This is a extended version
of arch/arm/cpu/armv7/s5p-common/pwm.c. I.e. pwm.c is adapted with
"#if defined(CONFIG_ARCH_NEXELL) ... #else" at some places. So my
proposal is to change s5p-common/pwm.c appropriately to get rid of
pwm-nexell.c.
Regards
Stefan
^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2020-02-25 19:13 UTC | newest]
Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-02-03 19:39 [RFC PATCH 00/10] arm: add support for SoC S5P4418 Stefan Bosch
2020-02-03 20:32 ` [RFC PATCH 01/10] arm: add mach-nexell (header files) Stefan Bosch
2020-02-03 20:38 ` [RFC PATCH 02/10] arm: add mach-nexell (all files except header files) Stefan Bosch
2020-02-03 20:40 ` [RFC PATCH 03/10] i2c: mmc: add nexell driver (gpio, i2c, mmc, pwm) Stefan Bosch
2020-02-04 6:58 ` Heiko Schocher
2020-02-04 18:29 ` Stefan B.
2020-02-20 17:49 ` Stefan B.
2020-02-22 12:34 ` Heiko Schocher
2020-02-03 20:41 ` [RFC PATCH 04/10] video: add nexell video driver (soc: displaytop) Stefan Bosch
2020-02-03 20:43 ` [RFC PATCH 05/10] video: add nexell video driver (soc: mlc, mipi) Stefan Bosch
2020-02-03 20:44 ` [RFC PATCH 06/10] video: add nexell video driver (soc: lvds, hdmi) Stefan Bosch
2020-02-03 20:45 ` [RFC PATCH 07/10] video: add nexell video driver (soc: dpc, makefile) Stefan Bosch
2020-02-03 20:45 ` [RFC PATCH 08/10] video: add nexell video driver (display/video driver) Stefan Bosch
2020-02-03 20:46 ` [RFC PATCH 09/10] arm: add support for SoC s5p4418 (cpu) / nanopi2 board Stefan Bosch
2020-02-07 16:10 ` Tom Rini
2020-02-03 20:47 ` [RFC PATCH 10/10] arm: add (default) config for " Stefan Bosch
2020-02-07 16:11 ` [RFC PATCH 00/10] arm: add support for SoC S5P4418 Tom Rini
2020-02-22 13:06 ` Amit Tomer
2020-02-25 19:13 ` Stefan B.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.