aboutsummaryrefslogtreecommitdiffstats
path: root/roms/u-boot/drivers/i2c
diff options
context:
space:
mode:
authorAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
committerAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
commitaf1a266670d040d2f4083ff309d732d648afba2a (patch)
tree2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/u-boot/drivers/i2c
parente02cda008591317b1625707ff8e115a4841aa889 (diff)
Add submodule dependency filesHEADmaster
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/u-boot/drivers/i2c')
-rw-r--r--roms/u-boot/drivers/i2c/Kconfig528
-rw-r--r--roms/u-boot/drivers/i2c/Makefile53
-rw-r--r--roms/u-boot/drivers/i2c/acpi_i2c.c226
-rw-r--r--roms/u-boot/drivers/i2c/acpi_i2c.h15
-rw-r--r--roms/u-boot/drivers/i2c/ast_i2c.c357
-rw-r--r--roms/u-boot/drivers/i2c/ast_i2c.h129
-rw-r--r--roms/u-boot/drivers/i2c/at91_i2c.c329
-rw-r--r--roms/u-boot/drivers/i2c/at91_i2c.h78
-rw-r--r--roms/u-boot/drivers/i2c/cros_ec_ldo.c76
-rw-r--r--roms/u-boot/drivers/i2c/cros_ec_tunnel.c62
-rw-r--r--roms/u-boot/drivers/i2c/davinci_i2c.c511
-rw-r--r--roms/u-boot/drivers/i2c/davinci_i2c.h77
-rw-r--r--roms/u-boot/drivers/i2c/designware_i2c.c853
-rw-r--r--roms/u-boot/drivers/i2c/designware_i2c.h231
-rw-r--r--roms/u-boot/drivers/i2c/designware_i2c_pci.c229
-rw-r--r--roms/u-boot/drivers/i2c/exynos_hs_i2c.c564
-rw-r--r--roms/u-boot/drivers/i2c/fsl_i2c.c658
-rw-r--r--roms/u-boot/drivers/i2c/i2c-cdns.c516
-rw-r--r--roms/u-boot/drivers/i2c/i2c-cortina.c347
-rw-r--r--roms/u-boot/drivers/i2c/i2c-cortina.h87
-rw-r--r--roms/u-boot/drivers/i2c/i2c-emul-uclass.c94
-rw-r--r--roms/u-boot/drivers/i2c/i2c-gpio.c379
-rw-r--r--roms/u-boot/drivers/i2c/i2c-uclass.c735
-rw-r--r--roms/u-boot/drivers/i2c/i2c-uniphier-f.c331
-rw-r--r--roms/u-boot/drivers/i2c/i2c-uniphier.c219
-rw-r--r--roms/u-boot/drivers/i2c/i2c-versatile.c277
-rw-r--r--roms/u-boot/drivers/i2c/i2c_core.c350
-rw-r--r--roms/u-boot/drivers/i2c/ihs_i2c.c477
-rw-r--r--roms/u-boot/drivers/i2c/imx_lpi2c.c524
-rw-r--r--roms/u-boot/drivers/i2c/intel_i2c.c312
-rw-r--r--roms/u-boot/drivers/i2c/iproc_i2c.c714
-rw-r--r--roms/u-boot/drivers/i2c/iproc_i2c.h335
-rw-r--r--roms/u-boot/drivers/i2c/kona_i2c.c728
-rw-r--r--roms/u-boot/drivers/i2c/lpc32xx_i2c.c362
-rw-r--r--roms/u-boot/drivers/i2c/meson_i2c.c313
-rw-r--r--roms/u-boot/drivers/i2c/muxes/Kconfig46
-rw-r--r--roms/u-boot/drivers/i2c/muxes/Makefile7
-rw-r--r--roms/u-boot/drivers/i2c/muxes/i2c-arb-gpio-challenge.c150
-rw-r--r--roms/u-boot/drivers/i2c/muxes/i2c-mux-gpio.c141
-rw-r--r--roms/u-boot/drivers/i2c/muxes/i2c-mux-uclass.c226
-rw-r--r--roms/u-boot/drivers/i2c/muxes/pca954x.c177
-rw-r--r--roms/u-boot/drivers/i2c/mv_i2c.c606
-rw-r--r--roms/u-boot/drivers/i2c/mv_i2c.h69
-rw-r--r--roms/u-boot/drivers/i2c/mvtwsi.c896
-rw-r--r--roms/u-boot/drivers/i2c/mxc_i2c.c1080
-rw-r--r--roms/u-boot/drivers/i2c/nx_i2c.c627
-rw-r--r--roms/u-boot/drivers/i2c/ocores_i2c.c638
-rw-r--r--roms/u-boot/drivers/i2c/octeon_i2c.c839
-rw-r--r--roms/u-boot/drivers/i2c/omap24xx_i2c.c1107
-rw-r--r--roms/u-boot/drivers/i2c/omap24xx_i2c.h149
-rw-r--r--roms/u-boot/drivers/i2c/rcar_i2c.c376
-rw-r--r--roms/u-boot/drivers/i2c/rcar_iic.c274
-rw-r--r--roms/u-boot/drivers/i2c/rk_i2c.c498
-rw-r--r--roms/u-boot/drivers/i2c/s3c24x0_i2c.c349
-rw-r--r--roms/u-boot/drivers/i2c/s3c24x0_i2c.h83
-rw-r--r--roms/u-boot/drivers/i2c/sandbox_i2c.c99
-rw-r--r--roms/u-boot/drivers/i2c/sh_i2c.c313
-rw-r--r--roms/u-boot/drivers/i2c/soft_i2c.c517
-rw-r--r--roms/u-boot/drivers/i2c/stm32f7_i2c.c960
-rw-r--r--roms/u-boot/drivers/i2c/tegra186_bpmp_i2c.c128
-rw-r--r--roms/u-boot/drivers/i2c/tegra_i2c.c529
-rw-r--r--roms/u-boot/drivers/i2c/xilinx_xiic.c353
62 files changed, 23313 insertions, 0 deletions
diff --git a/roms/u-boot/drivers/i2c/Kconfig b/roms/u-boot/drivers/i2c/Kconfig
new file mode 100644
index 000000000..57a4efb88
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/Kconfig
@@ -0,0 +1,528 @@
+#
+# I2C subsystem configuration
+#
+
+menu "I2C support"
+
+config DM_I2C
+ bool "Enable Driver Model for I2C drivers"
+ depends on DM
+ help
+ Enable driver model for I2C. The I2C uclass interface: probe, read,
+ write and speed, is implemented with the bus drivers operations,
+ which provide methods for bus setting and data transfer. Each chip
+ device (bus child) info is kept as parent plat. The interface
+ is defined in include/i2c.h.
+
+config SPL_DM_I2C
+ bool "Enable Driver Model for I2C drivers in SPL"
+ depends on SPL_DM && DM_I2C
+ default y
+ help
+ Enable driver model for I2C. The I2C uclass interface: probe, read,
+ write and speed, is implemented with the bus drivers operations,
+ which provide methods for bus setting and data transfer. Each chip
+ device (bus child) info is kept as parent platdata. The interface
+ is defined in include/i2c.h.
+
+config I2C_CROS_EC_TUNNEL
+ tristate "Chrome OS EC tunnel I2C bus"
+ depends on CROS_EC
+ help
+ This provides an I2C bus that will tunnel i2c commands through to
+ the other side of the Chrome OS EC to the I2C bus connected there.
+ This will work whatever the interface used to talk to the EC (SPI,
+ I2C or LPC). Some Chromebooks use this when the hardware design
+ does not allow direct access to the main PMIC from the AP.
+
+config I2C_CROS_EC_LDO
+ bool "Provide access to LDOs on the Chrome OS EC"
+ depends on CROS_EC
+ ---help---
+ On many Chromebooks the main PMIC is inaccessible to the AP. This is
+ often dealt with by using an I2C pass-through interface provided by
+ the EC. On some unfortunate models (e.g. Spring) the pass-through
+ is not available, and an LDO message is available instead. This
+ option enables a driver which provides very basic access to those
+ regulators, via the EC. We implement this as an I2C bus which
+ emulates just the TPS65090 messages we know about. This is done to
+ avoid duplicating the logic in the TPS65090 regulator driver for
+ enabling/disabling an LDO.
+
+config I2C_SET_DEFAULT_BUS_NUM
+ bool "Set default I2C bus number"
+ depends on DM_I2C
+ help
+ Set default number of I2C bus to be accessed. This option provides
+ behaviour similar to old (i.e. pre DM) I2C bus driver.
+
+config I2C_DEFAULT_BUS_NUMBER
+ hex "I2C default bus number"
+ depends on I2C_SET_DEFAULT_BUS_NUM
+ default 0x0
+ help
+ Number of default I2C bus to use
+
+config DM_I2C_GPIO
+ bool "Enable Driver Model for software emulated I2C bus driver"
+ depends on DM_I2C && DM_GPIO
+ help
+ Enable the i2c bus driver emulation by using the GPIOs. The bus GPIO
+ configuration is given by the device tree. Kernel-style device tree
+ bindings are supported.
+ Binding info: doc/device-tree-bindings/i2c/i2c-gpio.txt
+
+config SPL_DM_I2C_GPIO
+ bool "Enable Driver Model for software emulated I2C bus driver in SPL"
+ depends on SPL_DM && DM_I2C_GPIO && SPL_DM_GPIO && SPL_GPIO_SUPPORT
+ default y
+ help
+ Enable the i2c bus driver emulation by using the GPIOs. The bus GPIO
+ configuration is given by the device tree. Kernel-style device tree
+ bindings are supported.
+ Binding info: doc/device-tree-bindings/i2c/i2c-gpio.txt
+
+config SYS_I2C_AT91
+ bool "Atmel I2C driver"
+ depends on DM_I2C && ARCH_AT91
+ help
+ Add support for the Atmel I2C driver. A serious problem is that there
+ is no documented way to issue repeated START conditions for more than
+ two messages, as needed to support combined I2C messages. Use the
+ i2c-gpio driver unless your system can cope with this limitation.
+ Binding info: doc/device-tree-bindings/i2c/i2c-at91.txt
+
+config SYS_I2C_IPROC
+ bool "Broadcom I2C driver"
+ depends on DM_I2C
+ help
+ Broadcom I2C driver.
+ Add support for Broadcom I2C driver.
+ Say yes here to to enable the Broadco I2C driver.
+
+config SYS_I2C_FSL
+ bool "Freescale I2C bus driver"
+ depends on DM_I2C
+ help
+ Add support for Freescale I2C busses as used on MPC8240, MPC8245, and
+ MPC85xx processors.
+
+config SYS_I2C_CADENCE
+ tristate "Cadence I2C Controller"
+ depends on DM_I2C
+ help
+ Say yes here to select Cadence I2C Host Controller. This controller is
+ e.g. used by Xilinx Zynq.
+
+config SYS_I2C_CA
+ tristate "Cortina-Access I2C Controller"
+ depends on DM_I2C && CORTINA_PLATFORM
+ default n
+ help
+ Add support for the Cortina Access I2C host controller.
+ Say yes here to select Cortina-Access I2C Host Controller.
+
+config SYS_I2C_DAVINCI
+ bool "Davinci I2C Controller"
+ depends on (ARCH_KEYSTONE || ARCH_DAVINCI)
+ help
+ Say yes here to add support for Davinci and Keystone I2C controller
+
+config SYS_I2C_DW
+ bool "Designware I2C Controller"
+ default n
+ help
+ Say yes here to select the Designware I2C Host Controller. This
+ controller is used in various SoCs, e.g. the ST SPEAr, Altera
+ SoCFPGA, Synopsys ARC700 and some Intel x86 SoCs.
+
+config SYS_I2C_DW_ENABLE_STATUS_UNSUPPORTED
+ bool "DW I2C Enable Status Register not supported"
+ depends on SYS_I2C_DW && (TARGET_SPEAR300 || TARGET_SPEAR310 || \
+ TARGET_SPEAR320 || TARGET_SPEAR600 || TARGET_X600)
+ default y
+ help
+ Some versions of the Designware I2C controller do not support the
+ enable status register. This config option can be enabled in such
+ cases.
+
+config SYS_I2C_ASPEED
+ bool "Aspeed I2C Controller"
+ depends on DM_I2C && ARCH_ASPEED
+ help
+ Say yes here to select Aspeed I2C Host Controller. The driver
+ supports AST2500 and AST2400 controllers, but is very limited.
+ Only single master mode is supported and only byte-by-byte
+ synchronous reads and writes are supported, no Pool Buffers or DMA.
+
+config SYS_I2C_INTEL
+ bool "Intel I2C/SMBUS driver"
+ depends on DM_I2C
+ help
+ Add support for the Intel SMBUS driver. So far this driver is just
+ a stub which perhaps some basic init. There is no implementation of
+ the I2C API meaning that any I2C operations will immediately fail
+ for now.
+
+config SYS_I2C_IMX_LPI2C
+ bool "NXP i.MX LPI2C driver"
+ help
+ Add support for the NXP i.MX LPI2C driver.
+
+config SYS_I2C_MESON
+ bool "Amlogic Meson I2C driver"
+ depends on DM_I2C && ARCH_MESON
+ help
+ Add support for the I2C controller available in Amlogic Meson
+ SoCs. The controller supports programmable bus speed including
+ standard (100kbits/s) and fast (400kbit/s) speed and allows the
+ software to define a flexible format of the bit streams. It has an
+ internal buffer holding up to 8 bytes for transfers and supports
+ both 7-bit and 10-bit addresses.
+
+config SYS_I2C_MXC
+ bool "NXP MXC I2C driver"
+ help
+ Add support for the NXP I2C driver. This supports up to four bus
+ channels and operating on standard mode up to 100 kbits/s and fast
+ mode up to 400 kbits/s.
+
+# These settings are not used with DM_I2C, however SPL doesn't use
+# DM_I2C even if DM_I2C is enabled, and so might use these settings even
+# when main u-boot does not!
+if SYS_I2C_MXC && (!DM_I2C || SPL)
+config SYS_I2C_MXC_I2C1
+ bool "NXP MXC I2C1"
+ help
+ Add support for NXP MXC I2C Controller 1.
+ Required for SoCs which have I2C MXC controller 1 eg LS1088A, LS2080A
+
+config SYS_I2C_MXC_I2C2
+ bool "NXP MXC I2C2"
+ help
+ Add support for NXP MXC I2C Controller 2.
+ Required for SoCs which have I2C MXC controller 2 eg LS1088A, LS2080A
+
+config SYS_I2C_MXC_I2C3
+ bool "NXP MXC I2C3"
+ help
+ Add support for NXP MXC I2C Controller 3.
+ Required for SoCs which have I2C MXC controller 3 eg LS1088A, LS2080A
+
+config SYS_I2C_MXC_I2C4
+ bool "NXP MXC I2C4"
+ help
+ Add support for NXP MXC I2C Controller 4.
+ Required for SoCs which have I2C MXC controller 4 eg LS1088A, LS2080A
+
+config SYS_I2C_MXC_I2C5
+ bool "NXP MXC I2C5"
+ help
+ Add support for NXP MXC I2C Controller 5.
+ Required for SoCs which have I2C MXC controller 5 eg LX2160A
+
+config SYS_I2C_MXC_I2C6
+ bool "NXP MXC I2C6"
+ help
+ Add support for NXP MXC I2C Controller 6.
+ Required for SoCs which have I2C MXC controller 6 eg LX2160A
+
+config SYS_I2C_MXC_I2C7
+ bool "NXP MXC I2C7"
+ help
+ Add support for NXP MXC I2C Controller 7.
+ Required for SoCs which have I2C MXC controller 7 eg LX2160A
+
+config SYS_I2C_MXC_I2C8
+ bool "NXP MXC I2C8"
+ help
+ Add support for NXP MXC I2C Controller 8.
+ Required for SoCs which have I2C MXC controller 8 eg LX2160A
+endif
+
+if SYS_I2C_MXC_I2C1
+config SYS_MXC_I2C1_SPEED
+ int "I2C Channel 1 speed"
+ default 40000000 if TARGET_LS2080A_EMU
+ default 100000
+ help
+ MXC I2C Channel 1 speed
+
+config SYS_MXC_I2C1_SLAVE
+ int "I2C1 Slave"
+ default 0
+ help
+ MXC I2C1 Slave
+endif
+
+if SYS_I2C_MXC_I2C2
+config SYS_MXC_I2C2_SPEED
+ int "I2C Channel 2 speed"
+ default 40000000 if TARGET_LS2080A_EMU
+ default 100000
+ help
+ MXC I2C Channel 2 speed
+
+config SYS_MXC_I2C2_SLAVE
+ int "I2C2 Slave"
+ default 0
+ help
+ MXC I2C2 Slave
+endif
+
+if SYS_I2C_MXC_I2C3
+config SYS_MXC_I2C3_SPEED
+ int "I2C Channel 3 speed"
+ default 100000
+ help
+ MXC I2C Channel 3 speed
+
+config SYS_MXC_I2C3_SLAVE
+ int "I2C3 Slave"
+ default 0
+ help
+ MXC I2C3 Slave
+endif
+
+if SYS_I2C_MXC_I2C4
+config SYS_MXC_I2C4_SPEED
+ int "I2C Channel 4 speed"
+ default 100000
+ help
+ MXC I2C Channel 4 speed
+
+config SYS_MXC_I2C4_SLAVE
+ int "I2C4 Slave"
+ default 0
+ help
+ MXC I2C4 Slave
+endif
+
+if SYS_I2C_MXC_I2C5
+config SYS_MXC_I2C5_SPEED
+ int "I2C Channel 5 speed"
+ default 100000
+ help
+ MXC I2C Channel 5 speed
+
+config SYS_MXC_I2C5_SLAVE
+ int "I2C5 Slave"
+ default 0
+ help
+ MXC I2C5 Slave
+endif
+
+if SYS_I2C_MXC_I2C6
+config SYS_MXC_I2C6_SPEED
+ int "I2C Channel 6 speed"
+ default 100000
+ help
+ MXC I2C Channel 6 speed
+
+config SYS_MXC_I2C6_SLAVE
+ int "I2C6 Slave"
+ default 0
+ help
+ MXC I2C6 Slave
+endif
+
+if SYS_I2C_MXC_I2C7
+config SYS_MXC_I2C7_SPEED
+ int "I2C Channel 7 speed"
+ default 100000
+ help
+ MXC I2C Channel 7 speed
+
+config SYS_MXC_I2C7_SLAVE
+ int "I2C7 Slave"
+ default 0
+ help
+ MXC I2C7 Slave
+endif
+
+if SYS_I2C_MXC_I2C8
+config SYS_MXC_I2C8_SPEED
+ int "I2C Channel 8 speed"
+ default 100000
+ help
+ MXC I2C Channel 8 speed
+
+config SYS_MXC_I2C8_SLAVE
+ int "I2C8 Slave"
+ default 0
+ help
+ 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_OCORES
+ bool "ocores I2C driver"
+ depends on DM_I2C
+ help
+ Add support for ocores I2C controller. For details see
+ https://opencores.org/projects/i2c
+
+config SYS_I2C_OMAP24XX
+ bool "TI OMAP2+ I2C driver"
+ depends on ARCH_OMAP2PLUS || ARCH_K3
+ help
+ Add support for the OMAP2+ I2C driver.
+
+if SYS_I2C_OMAP24XX
+config SYS_OMAP24_I2C_SLAVE
+ int "I2C Slave addr channel 0"
+ default 1
+ help
+ OMAP24xx I2C Slave address channel 0
+
+config SYS_OMAP24_I2C_SPEED
+ int "I2C Slave channel 0 speed"
+ default 100000
+ help
+ OMAP24xx Slave speed channel 0
+endif
+
+config SYS_I2C_RCAR_I2C
+ bool "Renesas RCar I2C driver"
+ depends on (RCAR_GEN3 || RCAR_GEN2) && DM_I2C
+ help
+ Support for Renesas RCar I2C controller.
+
+config SYS_I2C_RCAR_IIC
+ bool "Renesas RCar Gen3 IIC driver"
+ depends on (RCAR_GEN3 || RCAR_GEN2) && DM_I2C
+ help
+ Support for Renesas RCar Gen3 IIC controller.
+
+config SYS_I2C_ROCKCHIP
+ bool "Rockchip I2C driver"
+ depends on DM_I2C
+ help
+ Add support for the Rockchip I2C driver. This is used with various
+ Rockchip parts such as RK3126, RK3128, RK3036 and RK3288. All chips
+ have several I2C ports and all are provided, controlled by the
+ device tree.
+
+config SYS_I2C_SANDBOX
+ bool "Sandbox I2C driver"
+ depends on SANDBOX && DM_I2C
+ help
+ Enable I2C support for sandbox. This is an emulation of a real I2C
+ bus. Devices can be attached to the bus using the device tree
+ which specifies the driver to use. See sandbox.dts as an example.
+
+config SYS_I2C_OCTEON
+ bool "Octeon II/III/TX/TX2 I2C driver"
+ depends on (ARCH_OCTEON || ARCH_OCTEONTX || ARCH_OCTEONTX2) && DM_I2C
+ default y
+ help
+ Add support for the Marvell Octeon I2C driver. This is used with
+ various Octeon parts such as Octeon II/III and OcteonTX/TX2. All
+ chips have several I2C ports and all are provided, controlled by
+ the device tree.
+
+config SYS_I2C_S3C24X0
+ bool "Samsung I2C driver"
+ depends on ARCH_EXYNOS4 && DM_I2C
+ help
+ Support for Samsung I2C controller as Samsung SoCs.
+
+config SYS_I2C_STM32F7
+ bool "STMicroelectronics STM32F7 I2C support"
+ depends on (STM32F7 || STM32H7 || ARCH_STM32MP) && DM_I2C
+ help
+ Enable this option to add support for STM32 I2C controller
+ introduced with STM32F7/H7 SoCs. This I2C controller supports :
+ _ Slave and master modes
+ _ Multimaster capability
+ _ Standard-mode (up to 100 kHz)
+ _ Fast-mode (up to 400 kHz)
+ _ Fast-mode Plus (up to 1 MHz)
+ _ 7-bit and 10-bit addressing mode
+ _ Multiple 7-bit slave addresses (2 addresses, 1 with configurable mask)
+ _ All 7-bit addresses acknowledge mode
+ _ General call
+ _ Programmable setup and hold times
+ _ Easy to use event management
+ _ Optional clock stretching
+ _ Software reset
+
+config SYS_I2C_TEGRA
+ bool "NVIDIA Tegra internal I2C controller"
+ depends on ARCH_TEGRA
+ help
+ Support for NVIDIA I2C controller available in Tegra SoCs.
+
+config SYS_I2C_UNIPHIER
+ bool "UniPhier I2C driver"
+ depends on ARCH_UNIPHIER && DM_I2C
+ default y
+ help
+ Support for UniPhier I2C controller driver. This I2C controller
+ is used on PH1-LD4, PH1-sLD8 or older UniPhier SoCs.
+
+config SYS_I2C_UNIPHIER_F
+ bool "UniPhier FIFO-builtin I2C driver"
+ depends on ARCH_UNIPHIER && DM_I2C
+ default y
+ help
+ Support for UniPhier FIFO-builtin I2C controller driver.
+ This I2C controller is used on PH1-Pro4 or newer UniPhier SoCs.
+
+config SYS_I2C_VERSATILE
+ bool "Arm Ltd Versatile I2C bus driver"
+ depends on DM_I2C && TARGET_VEXPRESS64_JUNO
+ help
+ Add support for the Arm Ltd Versatile Express I2C driver. The I2C host
+ controller is present in the development boards manufactured by Arm Ltd.
+
+config SYS_I2C_MVTWSI
+ bool "Marvell I2C driver"
+ depends on DM_I2C
+ help
+ Support for Marvell I2C controllers as used on the orion5x and
+ kirkwood SoC families.
+
+config TEGRA186_BPMP_I2C
+ bool "Enable Tegra186 BPMP-based I2C driver"
+ depends on TEGRA186_BPMP
+ help
+ Support for Tegra I2C controllers managed by the BPMP (Boot and
+ Power Management Processor). On Tegra186, some I2C controllers are
+ directly controlled by the main CPU, whereas others are controlled
+ by the BPMP, and can only be accessed by the main CPU via IPC
+ requests to the BPMP. This driver covers the latter case.
+
+config SYS_I2C_BUS_MAX
+ int "Max I2C busses"
+ depends on ARCH_KEYSTONE || ARCH_OMAP2PLUS || ARCH_SOCFPGA
+ default 2 if TI816X
+ default 3 if OMAP34XX || AM33XX || AM43XX || ARCH_KEYSTONE
+ default 4 if ARCH_SOCFPGA || OMAP44XX || TI814X
+ default 5 if OMAP54XX
+ help
+ Define the maximum number of available I2C buses.
+
+config SYS_I2C_XILINX_XIIC
+ bool "Xilinx AXI I2C driver"
+ depends on DM_I2C
+ help
+ Support for Xilinx AXI I2C controller.
+
+config SYS_I2C_IHS
+ bool "gdsys IHS I2C driver"
+ depends on DM_I2C
+ help
+ Support for gdsys IHS I2C driver on FPGA bus.
+
+source "drivers/i2c/muxes/Kconfig"
+
+endmenu
diff --git a/roms/u-boot/drivers/i2c/Makefile b/roms/u-boot/drivers/i2c/Makefile
new file mode 100644
index 000000000..8c9f1fcd8
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/Makefile
@@ -0,0 +1,53 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2000-2007
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+obj-$(CONFIG_$(SPL_)DM_I2C) += i2c-uclass.o
+ifdef CONFIG_ACPIGEN
+obj-$(CONFIG_$(SPL_)DM_I2C) += acpi_i2c.o
+endif
+obj-$(CONFIG_$(SPL_)DM_I2C_GPIO) += i2c-gpio.o
+obj-$(CONFIG_$(SPL_)I2C_CROS_EC_TUNNEL) += cros_ec_tunnel.o
+obj-$(CONFIG_$(SPL_)I2C_CROS_EC_LDO) += cros_ec_ldo.o
+
+obj-$(CONFIG_I2C_MV) += mv_i2c.o
+obj-$(CONFIG_SYS_I2C) += i2c_core.o
+obj-$(CONFIG_SYS_I2C_ASPEED) += ast_i2c.o
+obj-$(CONFIG_SYS_I2C_AT91) += at91_i2c.o
+obj-$(CONFIG_SYS_I2C_CADENCE) += i2c-cdns.o
+obj-$(CONFIG_SYS_I2C_CA) += i2c-cortina.o
+obj-$(CONFIG_SYS_I2C_DAVINCI) += davinci_i2c.o
+obj-$(CONFIG_SYS_I2C_DW) += designware_i2c.o
+ifdef CONFIG_DM_PCI
+obj-$(CONFIG_SYS_I2C_DW) += designware_i2c_pci.o
+endif
+obj-$(CONFIG_SYS_I2C_FSL) += fsl_i2c.o
+obj-$(CONFIG_SYS_I2C_IHS) += ihs_i2c.o
+obj-$(CONFIG_SYS_I2C_INTEL) += intel_i2c.o
+obj-$(CONFIG_SYS_I2C_IMX_LPI2C) += imx_lpi2c.o
+obj-$(CONFIG_SYS_I2C_IPROC) += iproc_i2c.o
+obj-$(CONFIG_SYS_I2C_KONA) += kona_i2c.o
+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_OCORES) += ocores_i2c.o
+obj-$(CONFIG_SYS_I2C_OCTEON) += octeon_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
+obj-$(CONFIG_SYS_I2C_ROCKCHIP) += rk_i2c.o
+obj-$(CONFIG_SYS_I2C_S3C24X0) += s3c24x0_i2c.o exynos_hs_i2c.o
+obj-$(CONFIG_SYS_I2C_SANDBOX) += sandbox_i2c.o i2c-emul-uclass.o
+obj-$(CONFIG_SYS_I2C_SH) += sh_i2c.o
+obj-$(CONFIG_SYS_I2C_SOFT) += soft_i2c.o
+obj-$(CONFIG_SYS_I2C_STM32F7) += stm32f7_i2c.o
+obj-$(CONFIG_SYS_I2C_TEGRA) += tegra_i2c.o
+obj-$(CONFIG_SYS_I2C_UNIPHIER) += i2c-uniphier.o
+obj-$(CONFIG_SYS_I2C_UNIPHIER_F) += i2c-uniphier-f.o
+obj-$(CONFIG_SYS_I2C_VERSATILE) += i2c-versatile.o
+obj-$(CONFIG_SYS_I2C_XILINX_XIIC) += xilinx_xiic.o
+obj-$(CONFIG_TEGRA186_BPMP_I2C) += tegra186_bpmp_i2c.o
+
+obj-$(CONFIG_$(SPL_)I2C_MUX) += muxes/
diff --git a/roms/u-boot/drivers/i2c/acpi_i2c.c b/roms/u-boot/drivers/i2c/acpi_i2c.c
new file mode 100644
index 000000000..142f41178
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/acpi_i2c.c
@@ -0,0 +1,226 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 Google LLC
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+#include <log.h>
+#include <acpi/acpi_device.h>
+#include <acpi/acpigen.h>
+#include <acpi/acpi_dp.h>
+#ifdef CONFIG_X86
+#include <asm/intel_pinctrl_defs.h>
+#endif
+#include <asm-generic/gpio.h>
+#include <dm/acpi.h>
+
+static bool acpi_i2c_add_gpios_to_crs(struct acpi_i2c_priv *priv)
+{
+ /*
+ * Return false if:
+ * 1. Request to explicitly disable export of GPIOs in CRS, or
+ * 2. Both reset and enable GPIOs are not provided.
+ */
+ if (priv->disable_gpio_export_in_crs ||
+ (!dm_gpio_is_valid(&priv->reset_gpio) &&
+ !dm_gpio_is_valid(&priv->enable_gpio)))
+ return false;
+
+ return true;
+}
+
+static int acpi_i2c_write_gpio(struct acpi_ctx *ctx, struct gpio_desc *gpio,
+ int *curindex)
+{
+ int ret;
+
+ if (!dm_gpio_is_valid(gpio))
+ return -ENOENT;
+
+ acpi_device_write_gpio_desc(ctx, gpio);
+ ret = *curindex;
+ (*curindex)++;
+
+ return ret;
+}
+
+int acpi_i2c_fill_ssdt(const struct udevice *dev, struct acpi_ctx *ctx)
+{
+ int reset_gpio_index = -1, enable_gpio_index = -1, irq_gpio_index = -1;
+ enum i2c_device_t type = dev_get_driver_data(dev);
+ struct acpi_i2c_priv *priv = dev_get_priv(dev);
+ struct acpi_dp *dsd = NULL;
+ char scope[ACPI_PATH_MAX];
+ char name[ACPI_NAME_MAX];
+ int tx_state_val;
+ int curindex = 0;
+ int ret;
+
+#ifdef CONFIG_X86
+ tx_state_val = PAD_CFG0_TX_STATE;
+#elif defined(CONFIG_SANDBOX)
+ tx_state_val = BIT(7); /* test value */
+#else
+#error "Not supported on this architecture"
+#endif
+ ret = acpi_get_name(dev, name);
+ if (ret)
+ return log_msg_ret("name", ret);
+ ret = acpi_device_scope(dev, scope, sizeof(scope));
+ if (ret)
+ return log_msg_ret("scope", ret);
+
+ /* Device */
+ acpigen_write_scope(ctx, scope);
+ acpigen_write_device(ctx, name);
+ acpigen_write_name_string(ctx, "_HID", priv->hid);
+ if (type == I2C_DEVICE_HID_OVER_I2C)
+ acpigen_write_name_string(ctx, "_CID", "PNP0C50");
+ acpigen_write_name_integer(ctx, "_UID", priv->uid);
+ acpigen_write_name_string(ctx, "_DDN", priv->desc);
+ acpigen_write_sta(ctx, acpi_device_status(dev));
+
+ /* Resources */
+ acpigen_write_name(ctx, "_CRS");
+ acpigen_write_resourcetemplate_header(ctx);
+ acpi_device_write_i2c_dev(ctx, dev);
+
+ /* Use either Interrupt() or GpioInt() */
+ if (dm_gpio_is_valid(&priv->irq_gpio)) {
+ irq_gpio_index = acpi_i2c_write_gpio(ctx, &priv->irq_gpio,
+ &curindex);
+ } else {
+ ret = acpi_device_write_interrupt_irq(ctx, &priv->irq);
+ if (ret < 0)
+ return log_msg_ret("irq", ret);
+ }
+
+ if (acpi_i2c_add_gpios_to_crs(priv)) {
+ reset_gpio_index = acpi_i2c_write_gpio(ctx, &priv->reset_gpio,
+ &curindex);
+ enable_gpio_index = acpi_i2c_write_gpio(ctx, &priv->enable_gpio,
+ &curindex);
+ }
+ acpigen_write_resourcetemplate_footer(ctx);
+
+ /* Wake capabilities */
+ if (priv->wake) {
+ acpigen_write_name_integer(ctx, "_S0W", 4);
+ acpigen_write_prw(ctx, priv->wake, 3);
+ }
+
+ /* DSD */
+ if (priv->probed || priv->property_count || priv->compat_string ||
+ reset_gpio_index >= 0 || enable_gpio_index >= 0 ||
+ irq_gpio_index >= 0) {
+ char path[ACPI_PATH_MAX];
+
+ ret = acpi_device_path(dev, path, sizeof(path));
+ if (ret)
+ return log_msg_ret("path", ret);
+
+ dsd = acpi_dp_new_table("_DSD");
+ if (priv->compat_string)
+ acpi_dp_add_string(dsd, "compatible",
+ priv->compat_string);
+ if (priv->probed)
+ acpi_dp_add_integer(dsd, "linux,probed", 1);
+ if (irq_gpio_index >= 0)
+ acpi_dp_add_gpio(dsd, "irq-gpios", path,
+ irq_gpio_index, 0,
+ priv->irq_gpio.flags &
+ GPIOD_ACTIVE_LOW ?
+ ACPI_GPIO_ACTIVE_LOW : 0);
+ if (reset_gpio_index >= 0)
+ acpi_dp_add_gpio(dsd, "reset-gpios", path,
+ reset_gpio_index, 0,
+ priv->reset_gpio.flags &
+ GPIOD_ACTIVE_LOW ?
+ ACPI_GPIO_ACTIVE_LOW : 0);
+ if (enable_gpio_index >= 0)
+ acpi_dp_add_gpio(dsd, "enable-gpios", path,
+ enable_gpio_index, 0,
+ priv->enable_gpio.flags &
+ GPIOD_ACTIVE_LOW ?
+ ACPI_GPIO_ACTIVE_LOW : 0);
+ /* Generic property list is not supported */
+ acpi_dp_write(ctx, dsd);
+ }
+
+ /* Power Resource */
+ if (priv->has_power_resource) {
+ ret = acpi_device_add_power_res(ctx, tx_state_val,
+ "\\_SB.GPC0", "\\_SB.SPC0",
+ &priv->reset_gpio, priv->reset_delay_ms,
+ priv->reset_off_delay_ms, &priv->enable_gpio,
+ priv->enable_delay_ms, priv->enable_off_delay_ms,
+ &priv->stop_gpio, priv->stop_delay_ms,
+ priv->stop_off_delay_ms);
+ if (ret)
+ return log_msg_ret("power", ret);
+ }
+ if (priv->hid_desc_reg_offset) {
+ ret = acpi_device_write_dsm_i2c_hid(ctx,
+ priv->hid_desc_reg_offset);
+ if (ret)
+ return log_msg_ret("dsm", ret);
+ }
+
+ acpigen_pop_len(ctx); /* Device */
+ acpigen_pop_len(ctx); /* Scope */
+
+ return 0;
+}
+
+int acpi_i2c_of_to_plat(struct udevice *dev)
+{
+ struct acpi_i2c_priv *priv = dev_get_priv(dev);
+
+ gpio_request_by_name(dev, "reset-gpios", 0, &priv->reset_gpio,
+ GPIOD_IS_OUT);
+ gpio_request_by_name(dev, "enable-gpios", 0, &priv->enable_gpio,
+ GPIOD_IS_OUT);
+ gpio_request_by_name(dev, "irq-gpios", 0, &priv->irq_gpio, GPIOD_IS_IN);
+ gpio_request_by_name(dev, "stop-gpios", 0, &priv->stop_gpio,
+ GPIOD_IS_OUT);
+ irq_get_by_index(dev, 0, &priv->irq);
+ priv->hid = dev_read_string(dev, "acpi,hid");
+ if (!priv->hid)
+ return log_msg_ret("hid", -EINVAL);
+ dev_read_u32(dev, "acpi,uid", &priv->uid);
+ priv->desc = dev_read_string(dev, "acpi,ddn");
+ dev_read_u32(dev, "acpi,wake", &priv->wake);
+ priv->probed = dev_read_bool(dev, "linux,probed");
+ priv->compat_string = dev_read_string(dev, "acpi,compatible");
+ priv->has_power_resource = dev_read_bool(dev,
+ "acpi,has-power-resource");
+ dev_read_u32(dev, "hid-descr-addr", &priv->hid_desc_reg_offset);
+ dev_read_u32(dev, "reset-delay-ms", &priv->reset_delay_ms);
+ dev_read_u32(dev, "reset-off-delay-ms", &priv->reset_off_delay_ms);
+ dev_read_u32(dev, "enable-delay-ms", &priv->enable_delay_ms);
+ dev_read_u32(dev, "enable-off-delay-ms", &priv->enable_off_delay_ms);
+ dev_read_u32(dev, "stop-delay-ms", &priv->stop_delay_ms);
+ dev_read_u32(dev, "stop-off-delay-ms", &priv->stop_off_delay_ms);
+
+ return 0;
+}
+
+/* Use name specified in priv or build one from I2C address */
+static int acpi_i2c_get_name(const struct udevice *dev, char *out_name)
+{
+ struct dm_i2c_chip *chip = dev_get_parent_plat(dev);
+ struct acpi_i2c_priv *priv = dev_get_priv(dev);
+
+ snprintf(out_name, ACPI_NAME_MAX,
+ priv->hid_desc_reg_offset ? "H%03X" : "D%03X",
+ chip->chip_addr);
+
+ return 0;
+}
+
+struct acpi_ops acpi_i2c_ops = {
+ .fill_ssdt = acpi_i2c_fill_ssdt,
+ .get_name = acpi_i2c_get_name,
+};
diff --git a/roms/u-boot/drivers/i2c/acpi_i2c.h b/roms/u-boot/drivers/i2c/acpi_i2c.h
new file mode 100644
index 000000000..fc6616ade
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/acpi_i2c.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2019 Google LLC
+ */
+
+#ifndef __ACPI_I2C_H
+#define __ACPI_I2C_H
+
+#include <dm/acpi.h>
+
+extern struct acpi_ops acpi_i2c_ops;
+
+int acpi_i2c_of_to_plat(struct udevice *dev);
+
+#endif
diff --git a/roms/u-boot/drivers/i2c/ast_i2c.c b/roms/u-boot/drivers/i2c/ast_i2c.c
new file mode 100644
index 000000000..2d3fecaa1
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/ast_i2c.c
@@ -0,0 +1,357 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2012-2020 ASPEED Technology Inc.
+ * Copyright 2016 IBM Corporation
+ * Copyright 2017 Google, Inc.
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <i2c.h>
+#include <log.h>
+#include <asm/io.h>
+#include <asm/arch/scu_ast2500.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+
+#include "ast_i2c.h"
+
+#define I2C_TIMEOUT_US 100000
+#define I2C_SLEEP_STEP_US 20
+
+#define HIGHSPEED_TTIMEOUT 3
+
+/*
+ * Device private data
+ */
+struct ast_i2c_priv {
+ /* This device's clock */
+ struct clk clk;
+ /* Device registers */
+ struct ast_i2c_regs *regs;
+ /* I2C speed in Hz */
+ int speed;
+};
+
+/*
+ * Given desired divider ratio, return the value that needs to be set
+ * in Clock and AC Timing Control register
+ */
+static u32 get_clk_reg_val(ulong divider_ratio)
+{
+ ulong inc = 0, div;
+ ulong scl_low, scl_high, data;
+
+ for (div = 0; divider_ratio >= 16; div++) {
+ inc |= (divider_ratio & 1);
+ divider_ratio >>= 1;
+ }
+ divider_ratio += inc;
+ scl_low = (divider_ratio >> 1) - 1;
+ scl_high = divider_ratio - scl_low - 2;
+ data = I2CD_CACTC_BASE
+ | (scl_high << I2CD_TCKHIGH_SHIFT)
+ | (scl_low << I2CD_TCKLOW_SHIFT)
+ | (div << I2CD_BASE_DIV_SHIFT);
+
+ return data;
+}
+
+static void ast_i2c_clear_interrupts(struct udevice *dev)
+{
+ struct ast_i2c_priv *priv = dev_get_priv(dev);
+
+ writel(~0, &priv->regs->isr);
+}
+
+static void ast_i2c_init_bus(struct udevice *dev)
+{
+ struct ast_i2c_priv *priv = dev_get_priv(dev);
+
+ /* Reset device */
+ writel(0, &priv->regs->fcr);
+ /* Enable Master Mode. Assuming single-master */
+ writel(I2CD_MASTER_EN
+ | I2CD_M_SDA_LOCK_EN
+ | I2CD_MULTI_MASTER_DIS | I2CD_M_SCL_DRIVE_EN,
+ &priv->regs->fcr);
+ /* Enable Interrupts */
+ writel(I2CD_INTR_TX_ACK
+ | I2CD_INTR_TX_NAK
+ | I2CD_INTR_RX_DONE
+ | I2CD_INTR_BUS_RECOVER_DONE
+ | I2CD_INTR_NORMAL_STOP
+ | I2CD_INTR_ABNORMAL, &priv->regs->icr);
+}
+
+static int ast_i2c_of_to_plat(struct udevice *dev)
+{
+ struct ast_i2c_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ priv->regs = dev_read_addr_ptr(dev);
+ if (!priv->regs)
+ return -EINVAL;
+
+ ret = clk_get_by_index(dev, 0, &priv->clk);
+ if (ret < 0) {
+ debug("%s: Can't get clock for %s: %d\n", __func__, dev->name,
+ ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ast_i2c_probe(struct udevice *dev)
+{
+ struct ast2500_scu *scu;
+
+ debug("Enabling I2C%u\n", dev_seq(dev));
+
+ /*
+ * Get all I2C devices out of Reset.
+ * Only needs to be done once, but doing it for every
+ * device does not hurt.
+ */
+ scu = ast_get_scu();
+ ast_scu_unlock(scu);
+ clrbits_le32(&scu->sysreset_ctrl1, SCU_SYSRESET_I2C);
+ ast_scu_lock(scu);
+
+ ast_i2c_init_bus(dev);
+
+ return 0;
+}
+
+static int ast_i2c_wait_isr(struct udevice *dev, u32 flag)
+{
+ struct ast_i2c_priv *priv = dev_get_priv(dev);
+ int timeout = I2C_TIMEOUT_US;
+
+ while (!(readl(&priv->regs->isr) & flag) && timeout > 0) {
+ udelay(I2C_SLEEP_STEP_US);
+ timeout -= I2C_SLEEP_STEP_US;
+ }
+
+ ast_i2c_clear_interrupts(dev);
+ if (timeout <= 0)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int ast_i2c_send_stop(struct udevice *dev)
+{
+ struct ast_i2c_priv *priv = dev_get_priv(dev);
+
+ writel(I2CD_M_STOP_CMD, &priv->regs->csr);
+
+ return ast_i2c_wait_isr(dev, I2CD_INTR_NORMAL_STOP);
+}
+
+static int ast_i2c_wait_tx(struct udevice *dev)
+{
+ struct ast_i2c_priv *priv = dev_get_priv(dev);
+ int timeout = I2C_TIMEOUT_US;
+ u32 flag = I2CD_INTR_TX_ACK | I2CD_INTR_TX_NAK;
+ u32 status = readl(&priv->regs->isr) & flag;
+ int ret = 0;
+
+ while (!status && timeout > 0) {
+ status = readl(&priv->regs->isr) & flag;
+ udelay(I2C_SLEEP_STEP_US);
+ timeout -= I2C_SLEEP_STEP_US;
+ }
+
+ if (status == I2CD_INTR_TX_NAK)
+ ret = -EREMOTEIO;
+
+ if (timeout <= 0)
+ ret = -ETIMEDOUT;
+
+ ast_i2c_clear_interrupts(dev);
+
+ return ret;
+}
+
+static int ast_i2c_start_txn(struct udevice *dev, uint devaddr)
+{
+ struct ast_i2c_priv *priv = dev_get_priv(dev);
+
+ /* Start and Send Device Address */
+ writel(devaddr, &priv->regs->trbbr);
+ writel(I2CD_M_START_CMD | I2CD_M_TX_CMD, &priv->regs->csr);
+
+ return ast_i2c_wait_tx(dev);
+}
+
+static int ast_i2c_read_data(struct udevice *dev, u8 chip_addr, u8 *buffer,
+ size_t len, bool send_stop)
+{
+ struct ast_i2c_priv *priv = dev_get_priv(dev);
+ u32 i2c_cmd = I2CD_M_RX_CMD;
+ int ret;
+
+ ret = ast_i2c_start_txn(dev, (chip_addr << 1) | I2C_M_RD);
+ if (ret < 0)
+ return ret;
+
+ for (; len > 0; len--, buffer++) {
+ if (len == 1)
+ i2c_cmd |= I2CD_M_S_RX_CMD_LAST;
+ writel(i2c_cmd, &priv->regs->csr);
+ ret = ast_i2c_wait_isr(dev, I2CD_INTR_RX_DONE);
+ if (ret < 0)
+ return ret;
+ *buffer = (readl(&priv->regs->trbbr) & I2CD_RX_DATA_MASK)
+ >> I2CD_RX_DATA_SHIFT;
+ }
+ ast_i2c_clear_interrupts(dev);
+
+ if (send_stop)
+ return ast_i2c_send_stop(dev);
+
+ return 0;
+}
+
+static int ast_i2c_write_data(struct udevice *dev, u8 chip_addr, u8
+ *buffer, size_t len, bool send_stop)
+{
+ struct ast_i2c_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = ast_i2c_start_txn(dev, (chip_addr << 1));
+ if (ret < 0)
+ return ret;
+
+ for (; len > 0; len--, buffer++) {
+ writel(*buffer, &priv->regs->trbbr);
+ writel(I2CD_M_TX_CMD, &priv->regs->csr);
+ ret = ast_i2c_wait_tx(dev);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (send_stop)
+ return ast_i2c_send_stop(dev);
+
+ return 0;
+}
+
+static int ast_i2c_deblock(struct udevice *dev)
+{
+ struct ast_i2c_priv *priv = dev_get_priv(dev);
+ struct ast_i2c_regs *regs = priv->regs;
+ u32 csr = readl(&regs->csr);
+ bool sda_high = csr & I2CD_SDA_LINE_STS;
+ bool scl_high = csr & I2CD_SCL_LINE_STS;
+ int ret = 0;
+
+ if (sda_high && scl_high) {
+ /* Bus is idle, no deblocking needed. */
+ return 0;
+ } else if (sda_high) {
+ /* Send stop command */
+ debug("Unterminated TXN in (%x), sending stop\n", csr);
+ ret = ast_i2c_send_stop(dev);
+ } else if (scl_high) {
+ /* Possibly stuck slave */
+ debug("Bus stuck (%x), attempting recovery\n", csr);
+ writel(I2CD_BUS_RECOVER_CMD, &regs->csr);
+ ret = ast_i2c_wait_isr(dev, I2CD_INTR_BUS_RECOVER_DONE);
+ } else {
+ /* Just try to reinit the device. */
+ ast_i2c_init_bus(dev);
+ }
+
+ return ret;
+}
+
+static int ast_i2c_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs)
+{
+ int ret;
+
+ ret = ast_i2c_deblock(dev);
+ if (ret < 0)
+ return ret;
+
+ debug("i2c_xfer: %d messages\n", nmsgs);
+ for (; nmsgs > 0; nmsgs--, msg++) {
+ if (msg->flags & I2C_M_RD) {
+ debug("i2c_read: chip=0x%x, len=0x%x, flags=0x%x\n",
+ msg->addr, msg->len, msg->flags);
+ ret = ast_i2c_read_data(dev, msg->addr, msg->buf,
+ msg->len, (nmsgs == 1));
+ } else {
+ debug("i2c_write: chip=0x%x, len=0x%x, flags=0x%x\n",
+ msg->addr, msg->len, msg->flags);
+ ret = ast_i2c_write_data(dev, msg->addr, msg->buf,
+ msg->len, (nmsgs == 1));
+ }
+ if (ret) {
+ debug("%s: error (%d)\n", __func__, ret);
+ return -EREMOTEIO;
+ }
+ }
+
+ return 0;
+}
+
+static int ast_i2c_set_speed(struct udevice *dev, unsigned int speed)
+{
+ struct ast_i2c_priv *priv = dev_get_priv(dev);
+ struct ast_i2c_regs *regs = priv->regs;
+ ulong i2c_rate, divider;
+
+ debug("Setting speed for I2C%d to <%u>\n", dev_seq(dev), speed);
+ if (!speed) {
+ debug("No valid speed specified\n");
+ return -EINVAL;
+ }
+
+ i2c_rate = clk_get_rate(&priv->clk);
+ divider = i2c_rate / speed;
+
+ priv->speed = speed;
+ if (speed > I2C_SPEED_FAST_RATE) {
+ debug("Enable High Speed\n");
+ setbits_le32(&regs->fcr, I2CD_M_HIGH_SPEED_EN
+ | I2CD_M_SDA_DRIVE_1T_EN
+ | I2CD_SDA_DRIVE_1T_EN);
+ writel(HIGHSPEED_TTIMEOUT, &regs->cactcr2);
+ } else {
+ debug("Enabling Normal Speed\n");
+ writel(I2CD_NO_TIMEOUT_CTRL, &regs->cactcr2);
+ }
+
+ writel(get_clk_reg_val(divider), &regs->cactcr1);
+ ast_i2c_clear_interrupts(dev);
+
+ return 0;
+}
+
+static const struct dm_i2c_ops ast_i2c_ops = {
+ .xfer = ast_i2c_xfer,
+ .set_bus_speed = ast_i2c_set_speed,
+ .deblock = ast_i2c_deblock,
+};
+
+static const struct udevice_id ast_i2c_ids[] = {
+ { .compatible = "aspeed,ast2400-i2c-bus" },
+ { .compatible = "aspeed,ast2500-i2c-bus" },
+ { },
+};
+
+U_BOOT_DRIVER(ast_i2c) = {
+ .name = "ast_i2c",
+ .id = UCLASS_I2C,
+ .of_match = ast_i2c_ids,
+ .probe = ast_i2c_probe,
+ .of_to_plat = ast_i2c_of_to_plat,
+ .priv_auto = sizeof(struct ast_i2c_priv),
+ .ops = &ast_i2c_ops,
+};
diff --git a/roms/u-boot/drivers/i2c/ast_i2c.h b/roms/u-boot/drivers/i2c/ast_i2c.h
new file mode 100644
index 000000000..928785989
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/ast_i2c.h
@@ -0,0 +1,129 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2012-2020 ASPEED Technology Inc.
+ * Copyright 2016 IBM Corporation
+ * Copyright 2017 Google, Inc.
+ */
+#ifndef __AST_I2C_H_
+#define __AST_I2C_H_
+
+struct ast_i2c_regs {
+ u32 fcr;
+ u32 cactcr1;
+ u32 cactcr2;
+ u32 icr;
+ u32 isr;
+ u32 csr;
+ u32 sdar;
+ u32 pbcr;
+ u32 trbbr;
+#ifdef CONFIG_ASPEED_AST2500
+ u32 dma_mbar;
+ u32 dma_tlr;
+#endif
+};
+
+/* Device Register Definition */
+/* 0x00 : I2CD Function Control Register */
+#define I2CD_BUFF_SEL_MASK (0x7 << 20)
+#define I2CD_BUFF_SEL(x) (x << 20)
+#define I2CD_M_SDA_LOCK_EN (0x1 << 16)
+#define I2CD_MULTI_MASTER_DIS (0x1 << 15)
+#define I2CD_M_SCL_DRIVE_EN (0x1 << 14)
+#define I2CD_MSB_STS (0x1 << 9)
+#define I2CD_SDA_DRIVE_1T_EN (0x1 << 8)
+#define I2CD_M_SDA_DRIVE_1T_EN (0x1 << 7)
+#define I2CD_M_HIGH_SPEED_EN (0x1 << 6)
+#define I2CD_DEF_ADDR_EN (0x1 << 5)
+#define I2CD_DEF_ALERT_EN (0x1 << 4)
+#define I2CD_DEF_ARP_EN (0x1 << 3)
+#define I2CD_DEF_GCALL_EN (0x1 << 2)
+#define I2CD_SLAVE_EN (0x1 << 1)
+#define I2CD_MASTER_EN (0x1)
+
+/* 0x04 : I2CD Clock and AC Timing Control Register #1 */
+/* Base register value. These bits are always set by the driver. */
+#define I2CD_CACTC_BASE 0xfff00300
+#define I2CD_TCKHIGH_SHIFT 16
+#define I2CD_TCKLOW_SHIFT 12
+#define I2CD_THDDAT_SHIFT 10
+#define I2CD_TO_DIV_SHIFT 8
+#define I2CD_BASE_DIV_SHIFT 0
+
+/* 0x08 : I2CD Clock and AC Timing Control Register #2 */
+#define I2CD_tTIMEOUT 1
+#define I2CD_NO_TIMEOUT_CTRL 0
+
+/* 0x0c : I2CD Interrupt Control Register &
+ * 0x10 : I2CD Interrupt Status Register
+ *
+ * These share bit definitions, so use the same values for the enable &
+ * status bits.
+ */
+#define I2CD_INTR_SDA_DL_TIMEOUT (0x1 << 14)
+#define I2CD_INTR_BUS_RECOVER_DONE (0x1 << 13)
+#define I2CD_INTR_SMBUS_ALERT (0x1 << 12)
+#define I2CD_INTR_SMBUS_ARP_ADDR (0x1 << 11)
+#define I2CD_INTR_SMBUS_DEV_ALERT_ADDR (0x1 << 10)
+#define I2CD_INTR_SMBUS_DEF_ADDR (0x1 << 9)
+#define I2CD_INTR_GCALL_ADDR (0x1 << 8)
+#define I2CD_INTR_SLAVE_MATCH (0x1 << 7)
+#define I2CD_INTR_SCL_TIMEOUT (0x1 << 6)
+#define I2CD_INTR_ABNORMAL (0x1 << 5)
+#define I2CD_INTR_NORMAL_STOP (0x1 << 4)
+#define I2CD_INTR_ARBIT_LOSS (0x1 << 3)
+#define I2CD_INTR_RX_DONE (0x1 << 2)
+#define I2CD_INTR_TX_NAK (0x1 << 1)
+#define I2CD_INTR_TX_ACK (0x1 << 0)
+
+/* 0x14 : I2CD Command/Status Register */
+#define I2CD_SDA_OE (0x1 << 28)
+#define I2CD_SDA_O (0x1 << 27)
+#define I2CD_SCL_OE (0x1 << 26)
+#define I2CD_SCL_O (0x1 << 25)
+#define I2CD_TX_TIMING (0x1 << 24)
+#define I2CD_TX_STATUS (0x1 << 23)
+
+/* Tx State Machine */
+#define I2CD_IDLE 0x0
+#define I2CD_MACTIVE 0x8
+#define I2CD_MSTART 0x9
+#define I2CD_MSTARTR 0xa
+#define I2CD_MSTOP 0xb
+#define I2CD_MTXD 0xc
+#define I2CD_MRXACK 0xd
+#define I2CD_MRXD 0xe
+#define I2CD_MTXACK 0xf
+#define I2CD_SWAIT 0x1
+#define I2CD_SRXD 0x4
+#define I2CD_STXACK 0x5
+#define I2CD_STXD 0x6
+#define I2CD_SRXACK 0x7
+#define I2CD_RECOVER 0x3
+
+#define I2CD_SCL_LINE_STS (0x1 << 18)
+#define I2CD_SDA_LINE_STS (0x1 << 17)
+#define I2CD_BUS_BUSY_STS (0x1 << 16)
+#define I2CD_SDA_OE_OUT_DIR (0x1 << 15)
+#define I2CD_SDA_O_OUT_DIR (0x1 << 14)
+#define I2CD_SCL_OE_OUT_DIR (0x1 << 13)
+#define I2CD_SCL_O_OUT_DIR (0x1 << 12)
+#define I2CD_BUS_RECOVER_CMD (0x1 << 11)
+#define I2CD_S_ALT_EN (0x1 << 10)
+#define I2CD_RX_DMA_ENABLE (0x1 << 9)
+#define I2CD_TX_DMA_ENABLE (0x1 << 8)
+
+/* Command Bit */
+#define I2CD_RX_BUFF_ENABLE (0x1 << 7)
+#define I2CD_TX_BUFF_ENABLE (0x1 << 6)
+#define I2CD_M_STOP_CMD (0x1 << 5)
+#define I2CD_M_S_RX_CMD_LAST (0x1 << 4)
+#define I2CD_M_RX_CMD (0x1 << 3)
+#define I2CD_S_TX_CMD (0x1 << 2)
+#define I2CD_M_TX_CMD (0x1 << 1)
+#define I2CD_M_START_CMD 0x1
+
+#define I2CD_RX_DATA_SHIFT 8
+#define I2CD_RX_DATA_MASK (0xff << I2CD_RX_DATA_SHIFT)
+
+#endif /* __AST_I2C_H_ */
diff --git a/roms/u-boot/drivers/i2c/at91_i2c.c b/roms/u-boot/drivers/i2c/at91_i2c.c
new file mode 100644
index 000000000..6b4c0e480
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/at91_i2c.c
@@ -0,0 +1,329 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Atmel I2C driver.
+ *
+ * (C) Copyright 2016 Songjun Wu <songjun.wu@atmel.com>
+ */
+
+#include <malloc.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <i2c.h>
+#include <linux/bitops.h>
+#include <mach/clk.h>
+
+#include "at91_i2c.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define I2C_TIMEOUT_MS 100
+
+static int at91_wait_for_xfer(struct at91_i2c_bus *bus, u32 status)
+{
+ struct at91_i2c_regs *reg = bus->regs;
+ ulong start_time = get_timer(0);
+ u32 sr;
+
+ bus->status = 0;
+
+ do {
+ sr = readl(&reg->sr);
+ bus->status |= sr;
+
+ if (sr & TWI_SR_NACK)
+ return -EREMOTEIO;
+ else if (sr & status)
+ return 0;
+ } while (get_timer(start_time) < I2C_TIMEOUT_MS);
+
+ return -ETIMEDOUT;
+}
+
+static int at91_i2c_xfer_msg(struct at91_i2c_bus *bus, struct i2c_msg *msg)
+{
+ struct at91_i2c_regs *reg = bus->regs;
+ bool is_read = msg->flags & I2C_M_RD;
+ u32 i;
+ int ret = 0;
+
+ /* if there is no message to send/receive, just exit quietly */
+ if (msg->len == 0)
+ return ret;
+
+ readl(&reg->sr);
+ if (is_read) {
+ writel(TWI_CR_START, &reg->cr);
+
+ for (i = 0; !ret && i < (msg->len - 1); i++) {
+ ret = at91_wait_for_xfer(bus, TWI_SR_RXRDY);
+ msg->buf[i] = readl(&reg->rhr);
+ }
+
+ if (ret)
+ goto error;
+
+ writel(TWI_CR_STOP, &reg->cr);
+
+ ret = at91_wait_for_xfer(bus, TWI_SR_RXRDY);
+ if (ret)
+ goto error;
+
+ msg->buf[i] = readl(&reg->rhr);
+
+ } else {
+ writel(msg->buf[0], &reg->thr);
+ ret = at91_wait_for_xfer(bus, TWI_SR_TXRDY);
+
+ for (i = 1; !ret && (i < msg->len); i++) {
+ writel(msg->buf[i], &reg->thr);
+ ret = at91_wait_for_xfer(bus, TWI_SR_TXRDY);
+ }
+
+ if (ret)
+ goto error;
+
+ writel(TWI_CR_STOP, &reg->cr);
+ }
+
+ if (!ret)
+ ret = at91_wait_for_xfer(bus, TWI_SR_TXCOMP);
+
+ if (ret)
+ goto error;
+
+ if (bus->status & (TWI_SR_OVRE | TWI_SR_UNRE | TWI_SR_LOCK)) {
+ ret = -EIO;
+ goto error;
+ }
+
+ return 0;
+
+error:
+ if (bus->status & TWI_SR_LOCK)
+ writel(TWI_CR_LOCKCLR, &reg->cr);
+
+ return ret;
+}
+
+static int at91_i2c_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs)
+{
+ struct at91_i2c_bus *bus = dev_get_priv(dev);
+ struct at91_i2c_regs *reg = bus->regs;
+ struct i2c_msg *m_start = msg;
+ bool is_read;
+ u32 int_addr_flag = 0;
+ int ret = 0;
+
+ if (nmsgs == 2) {
+ int internal_address = 0;
+ int i;
+
+ /* 1st msg is put into the internal address, start with 2nd */
+ m_start = &msg[1];
+
+ /* the max length of internal address is 3 bytes */
+ if (msg->len > 3)
+ return -EFAULT;
+
+ for (i = 0; i < msg->len; ++i) {
+ const unsigned addr = msg->buf[msg->len - 1 - i];
+
+ internal_address |= addr << (8 * i);
+ int_addr_flag += TWI_MMR_IADRSZ_1;
+ }
+
+ writel(internal_address, &reg->iadr);
+ }
+
+ is_read = m_start->flags & I2C_M_RD;
+
+ writel((m_start->addr << 16) | int_addr_flag |
+ (is_read ? TWI_MMR_MREAD : 0), &reg->mmr);
+
+ ret = at91_i2c_xfer_msg(bus, m_start);
+
+ return ret;
+}
+
+/*
+ * Calculate symmetric clock as stated in datasheet:
+ * twi_clk = F_MAIN / (2 * (cdiv * (1 << ckdiv) + offset))
+ */
+static void at91_calc_i2c_clock(struct udevice *dev, int i2c_clk)
+{
+ struct at91_i2c_bus *bus = dev_get_priv(dev);
+ const struct at91_i2c_pdata *pdata = bus->pdata;
+ int offset = pdata->clk_offset;
+ int max_ckdiv = pdata->clk_max_div;
+ int ckdiv, cdiv, div;
+ unsigned long src_rate;
+
+ src_rate = bus->bus_clk_rate;
+
+ div = max(0, (int)DIV_ROUND_UP(src_rate, 2 * i2c_clk) - offset);
+ ckdiv = fls(div >> 8);
+ cdiv = div >> ckdiv;
+
+ if (ckdiv > max_ckdiv) {
+ ckdiv = max_ckdiv;
+ cdiv = 255;
+ }
+
+ bus->speed = DIV_ROUND_UP(src_rate,
+ (cdiv * (1 << ckdiv) + offset) * 2);
+
+ bus->cwgr_val = (ckdiv << 16) | (cdiv << 8) | cdiv;
+}
+
+static int at91_i2c_enable_clk(struct udevice *dev)
+{
+ struct at91_i2c_bus *bus = dev_get_priv(dev);
+ struct clk clk;
+ ulong clk_rate;
+ int ret;
+
+ ret = clk_get_by_index(dev, 0, &clk);
+ if (ret)
+ return -EINVAL;
+
+ ret = clk_enable(&clk);
+ if (ret)
+ return ret;
+
+ clk_rate = clk_get_rate(&clk);
+ if (!clk_rate)
+ return -EINVAL;
+
+ bus->bus_clk_rate = clk_rate;
+
+ clk_free(&clk);
+
+ return 0;
+}
+
+static int at91_i2c_set_bus_speed(struct udevice *dev, unsigned int speed)
+{
+ struct at91_i2c_bus *bus = dev_get_priv(dev);
+
+ at91_calc_i2c_clock(dev, speed);
+
+ writel(bus->cwgr_val, &bus->regs->cwgr);
+
+ return 0;
+}
+
+int at91_i2c_get_bus_speed(struct udevice *dev)
+{
+ struct at91_i2c_bus *bus = dev_get_priv(dev);
+
+ return bus->speed;
+}
+
+static int at91_i2c_of_to_plat(struct udevice *dev)
+{
+ const void *blob = gd->fdt_blob;
+ struct at91_i2c_bus *bus = dev_get_priv(dev);
+ int node = dev_of_offset(dev);
+
+ bus->regs = dev_read_addr_ptr(dev);
+ bus->pdata = (struct at91_i2c_pdata *)dev_get_driver_data(dev);
+ bus->clock_frequency = fdtdec_get_int(blob, node,
+ "clock-frequency", 100000);
+
+ return 0;
+}
+
+static const struct dm_i2c_ops at91_i2c_ops = {
+ .xfer = at91_i2c_xfer,
+ .set_bus_speed = at91_i2c_set_bus_speed,
+ .get_bus_speed = at91_i2c_get_bus_speed,
+};
+
+static int at91_i2c_probe(struct udevice *dev)
+{
+ struct at91_i2c_bus *bus = dev_get_priv(dev);
+ struct at91_i2c_regs *reg = bus->regs;
+ int ret;
+
+ ret = at91_i2c_enable_clk(dev);
+ if (ret)
+ return ret;
+
+ writel(TWI_CR_SWRST, &reg->cr);
+
+ at91_calc_i2c_clock(dev, bus->clock_frequency);
+
+ writel(bus->cwgr_val, &reg->cwgr);
+ writel(TWI_CR_MSEN, &reg->cr);
+ writel(TWI_CR_SVDIS, &reg->cr);
+
+ return 0;
+}
+
+static const struct at91_i2c_pdata at91rm9200_config = {
+ .clk_max_div = 5,
+ .clk_offset = 3,
+};
+
+static const struct at91_i2c_pdata at91sam9261_config = {
+ .clk_max_div = 5,
+ .clk_offset = 4,
+};
+
+static const struct at91_i2c_pdata at91sam9260_config = {
+ .clk_max_div = 7,
+ .clk_offset = 4,
+};
+
+static const struct at91_i2c_pdata at91sam9g20_config = {
+ .clk_max_div = 7,
+ .clk_offset = 4,
+};
+
+static const struct at91_i2c_pdata at91sam9g10_config = {
+ .clk_max_div = 7,
+ .clk_offset = 4,
+};
+
+static const struct at91_i2c_pdata at91sam9x5_config = {
+ .clk_max_div = 7,
+ .clk_offset = 4,
+};
+
+static const struct at91_i2c_pdata sama5d4_config = {
+ .clk_max_div = 7,
+ .clk_offset = 4,
+};
+
+static const struct at91_i2c_pdata sama5d2_config = {
+ .clk_max_div = 7,
+ .clk_offset = 3,
+};
+
+static const struct udevice_id at91_i2c_ids[] = {
+{ .compatible = "atmel,at91rm9200-i2c", .data = (long)&at91rm9200_config },
+{ .compatible = "atmel,at91sam9260-i2c", .data = (long)&at91sam9260_config },
+{ .compatible = "atmel,at91sam9261-i2c", .data = (long)&at91sam9261_config },
+{ .compatible = "atmel,at91sam9g20-i2c", .data = (long)&at91sam9g20_config },
+{ .compatible = "atmel,at91sam9g10-i2c", .data = (long)&at91sam9g10_config },
+{ .compatible = "atmel,at91sam9x5-i2c", .data = (long)&at91sam9x5_config },
+{ .compatible = "atmel,sama5d4-i2c", .data = (long)&sama5d4_config },
+{ .compatible = "atmel,sama5d2-i2c", .data = (long)&sama5d2_config },
+{ }
+};
+
+U_BOOT_DRIVER(i2c_at91) = {
+ .name = "i2c_at91",
+ .id = UCLASS_I2C,
+ .of_match = at91_i2c_ids,
+ .probe = at91_i2c_probe,
+ .of_to_plat = at91_i2c_of_to_plat,
+ .per_child_auto = sizeof(struct dm_i2c_chip),
+ .priv_auto = sizeof(struct at91_i2c_bus),
+ .ops = &at91_i2c_ops,
+};
diff --git a/roms/u-boot/drivers/i2c/at91_i2c.h b/roms/u-boot/drivers/i2c/at91_i2c.h
new file mode 100644
index 000000000..3915af837
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/at91_i2c.h
@@ -0,0 +1,78 @@
+#ifndef _AT91_I2C_H
+#define _AT91_I2C_H
+
+#include <linux/bitops.h>
+#define TWI_CR_START BIT(0) /* Send a Start Condition */
+#define TWI_CR_MSEN BIT(2) /* Master Transfer Enable */
+#define TWI_CR_STOP BIT(1) /* Send a Stop Condition */
+#define TWI_CR_SVDIS BIT(5) /* Slave Transfer Disable */
+#define TWI_CR_SWRST BIT(7) /* Software Reset */
+#define TWI_CR_ACMEN BIT(16) /* Alternative Command Mode Enable */
+#define TWI_CR_ACMDIS BIT(17) /* Alternative Command Mode Disable */
+#define TWI_CR_LOCKCLR BIT(26) /* Lock Clear */
+
+#define TWI_MMR_MREAD BIT(12) /* Master Read Direction */
+#define TWI_MMR_IADRSZ_1 BIT(8) /* Internal Device Address Size */
+
+#define TWI_SR_TXCOMP BIT(0) /* Transmission Complete */
+#define TWI_SR_RXRDY BIT(1) /* Receive Holding Register Ready */
+#define TWI_SR_TXRDY BIT(2) /* Transmit Holding Register Ready */
+#define TWI_SR_OVRE BIT(6) /* Overrun Error */
+#define TWI_SR_UNRE BIT(7) /* Underrun Error */
+#define TWI_SR_NACK BIT(8) /* Not Acknowledged */
+#define TWI_SR_LOCK BIT(23) /* TWI Lock due to Frame Errors */
+
+#define TWI_ACR_DATAL(len) ((len) & 0xff)
+#define TWI_ACR_DIR_READ BIT(8)
+
+#define TWI_CWGR_HOLD_MAX 0x1f
+#define TWI_CWGR_HOLD(x) (((x) & TWI_CWGR_HOLD_MAX) << 24)
+
+struct at91_i2c_regs {
+ u32 cr;
+ u32 mmr;
+ u32 smr;
+ u32 iadr;
+ u32 cwgr;
+ u32 rev_0[3];
+ u32 sr;
+ u32 ier;
+ u32 idr;
+ u32 imr;
+ u32 rhr;
+ u32 thr;
+ u32 smbtr;
+ u32 rev_1;
+ u32 acr;
+ u32 filtr;
+ u32 rev_2;
+ u32 swmr;
+ u32 fmr;
+ u32 flr;
+ u32 rev_3;
+ u32 fsr;
+ u32 fier;
+ u32 fidr;
+ u32 fimr;
+ u32 rev_4[29];
+ u32 wpmr;
+ u32 wpsr;
+ u32 rev_5[6];
+};
+
+struct at91_i2c_pdata {
+ unsigned clk_max_div;
+ unsigned clk_offset;
+};
+
+struct at91_i2c_bus {
+ struct at91_i2c_regs *regs;
+ u32 status;
+ ulong bus_clk_rate;
+ u32 clock_frequency;
+ u32 speed;
+ u32 cwgr_val;
+ const struct at91_i2c_pdata *pdata;
+};
+
+#endif
diff --git a/roms/u-boot/drivers/i2c/cros_ec_ldo.c b/roms/u-boot/drivers/i2c/cros_ec_ldo.c
new file mode 100644
index 000000000..c593540ac
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/cros_ec_ldo.c
@@ -0,0 +1,76 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <cros_ec.h>
+#include <errno.h>
+#include <i2c.h>
+#include <log.h>
+#include <power/tps65090.h>
+
+static int cros_ec_ldo_set_bus_speed(struct udevice *dev, unsigned int speed)
+{
+ return 0;
+}
+
+static int cros_ec_ldo_xfer(struct udevice *dev, struct i2c_msg *msg,
+ int nmsgs)
+{
+ bool is_read = nmsgs > 1;
+ int fet_id, ret;
+
+ /*
+ * Look for reads and writes of the LDO registers. In either case the
+ * first message is a write with the register number as the first byte.
+ */
+ if (!nmsgs || !msg->len || (msg->flags & I2C_M_RD)) {
+ debug("%s: Invalid message\n", __func__);
+ goto err;
+ }
+
+ fet_id = msg->buf[0] - REG_FET_BASE;
+ if (fet_id < 1 || fet_id > MAX_FET_NUM) {
+ debug("%s: Invalid FET %d\n", __func__, fet_id);
+ goto err;
+ }
+
+ if (is_read) {
+ uint8_t state;
+
+ ret = cros_ec_get_ldo(dev->parent, fet_id, &state);
+ if (!ret)
+ msg[1].buf[0] = state ?
+ FET_CTRL_ENFET | FET_CTRL_PGFET : 0;
+ } else {
+ bool on = msg->buf[1] & FET_CTRL_ENFET;
+
+ ret = cros_ec_set_ldo(dev->parent, fet_id, on);
+ }
+
+ return ret;
+
+err:
+ /* Indicate that the message is unimplemented */
+ return -ENOSYS;
+}
+
+static const struct dm_i2c_ops cros_ec_i2c_ops = {
+ .xfer = cros_ec_ldo_xfer,
+ .set_bus_speed = cros_ec_ldo_set_bus_speed,
+};
+
+static const struct udevice_id cros_ec_i2c_ids[] = {
+ { .compatible = "google,cros-ec-ldo-tunnel" },
+ { }
+};
+
+U_BOOT_DRIVER(cros_ec_ldo) = {
+ .name = "cros_ec_ldo_tunnel",
+ .id = UCLASS_I2C,
+ .of_match = cros_ec_i2c_ids,
+ .ops = &cros_ec_i2c_ops,
+};
diff --git a/roms/u-boot/drivers/i2c/cros_ec_tunnel.c b/roms/u-boot/drivers/i2c/cros_ec_tunnel.c
new file mode 100644
index 000000000..75828b6e7
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/cros_ec_tunnel.c
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <cros_ec.h>
+#include <errno.h>
+#include <i2c.h>
+#include <asm/global_data.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct cros_ec_i2c_bus {
+ int remote_bus;
+};
+
+static int cros_ec_i2c_set_bus_speed(struct udevice *dev, unsigned int speed)
+{
+ return 0;
+}
+
+static int cros_ec_i2c_xfer(struct udevice *dev, struct i2c_msg *msg,
+ int nmsgs)
+{
+ struct cros_ec_i2c_bus *i2c_bus = dev_get_priv(dev);
+
+ return cros_ec_i2c_tunnel(dev->parent, i2c_bus->remote_bus, msg, nmsgs);
+}
+
+static int cros_ec_i2c_of_to_plat(struct udevice *dev)
+{
+ struct cros_ec_i2c_bus *i2c_bus = dev_get_priv(dev);
+ const void *blob = gd->fdt_blob;
+ int node = dev_of_offset(dev);
+
+ i2c_bus->remote_bus = fdtdec_get_uint(blob, node, "google,remote-bus",
+ 0);
+
+ return 0;
+}
+
+static const struct dm_i2c_ops cros_ec_i2c_ops = {
+ .xfer = cros_ec_i2c_xfer,
+ .set_bus_speed = cros_ec_i2c_set_bus_speed,
+};
+
+static const struct udevice_id cros_ec_i2c_ids[] = {
+ { .compatible = "google,cros-ec-i2c-tunnel" },
+ { }
+};
+
+U_BOOT_DRIVER(cros_ec_tunnel) = {
+ .name = "cros_ec_tunnel",
+ .id = UCLASS_I2C,
+ .of_match = cros_ec_i2c_ids,
+ .of_to_plat = cros_ec_i2c_of_to_plat,
+ .priv_auto = sizeof(struct cros_ec_i2c_bus),
+ .ops = &cros_ec_i2c_ops,
+};
diff --git a/roms/u-boot/drivers/i2c/davinci_i2c.c b/roms/u-boot/drivers/i2c/davinci_i2c.c
new file mode 100644
index 000000000..a4abd25c3
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/davinci_i2c.c
@@ -0,0 +1,511 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * TI DaVinci (TMS320DM644x) I2C driver.
+ *
+ * (C) Copyright 2012-2014
+ * Texas Instruments Incorporated, <www.ti.com>
+ * (C) Copyright 2007 Sergey Kubushyn <ksi@koi8.net>
+ * --------------------------------------------------------
+ *
+ * NOTE: This driver should be converted to driver model before June 2017.
+ * Please see doc/driver-model/i2c-howto.rst for instructions.
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <dm.h>
+#include <log.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/i2c_defs.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include "davinci_i2c.h"
+
+#if CONFIG_IS_ENABLED(DM_I2C)
+/* Information about i2c controller */
+struct i2c_bus {
+ int id;
+ uint speed;
+ struct i2c_regs *regs;
+};
+#endif
+
+#define CHECK_NACK() \
+ do {\
+ if (tmp & (I2C_TIMEOUT | I2C_STAT_NACK)) {\
+ REG(&(i2c_base->i2c_con)) = 0;\
+ return 1;\
+ } \
+ } while (0)
+
+static int _wait_for_bus(struct i2c_regs *i2c_base)
+{
+ int stat, timeout;
+
+ REG(&(i2c_base->i2c_stat)) = 0xffff;
+
+ for (timeout = 0; timeout < 10; timeout++) {
+ stat = REG(&(i2c_base->i2c_stat));
+ if (!((stat) & I2C_STAT_BB)) {
+ REG(&(i2c_base->i2c_stat)) = 0xffff;
+ return 0;
+ }
+
+ REG(&(i2c_base->i2c_stat)) = stat;
+ udelay(50000);
+ }
+
+ REG(&(i2c_base->i2c_stat)) = 0xffff;
+ return 1;
+}
+
+static int _poll_i2c_irq(struct i2c_regs *i2c_base, int mask)
+{
+ int stat, timeout;
+
+ for (timeout = 0; timeout < 10; timeout++) {
+ udelay(1000);
+ stat = REG(&(i2c_base->i2c_stat));
+ if (stat & mask)
+ return stat;
+ }
+
+ REG(&(i2c_base->i2c_stat)) = 0xffff;
+ return stat | I2C_TIMEOUT;
+}
+
+static void _flush_rx(struct i2c_regs *i2c_base)
+{
+ while (1) {
+ if (!(REG(&(i2c_base->i2c_stat)) & I2C_STAT_RRDY))
+ break;
+
+ REG(&(i2c_base->i2c_drr));
+ REG(&(i2c_base->i2c_stat)) = I2C_STAT_RRDY;
+ udelay(1000);
+ }
+}
+
+static uint _davinci_i2c_setspeed(struct i2c_regs *i2c_base,
+ uint speed)
+{
+ uint32_t div, psc;
+
+ psc = 2;
+ /* SCLL + SCLH */
+ div = (CONFIG_SYS_HZ_CLOCK / ((psc + 1) * speed)) - 10;
+ REG(&(i2c_base->i2c_psc)) = psc; /* 27MHz / (2 + 1) = 9MHz */
+ REG(&(i2c_base->i2c_scll)) = (div * 50) / 100; /* 50% Duty */
+ REG(&(i2c_base->i2c_sclh)) = div - REG(&(i2c_base->i2c_scll));
+
+ return 0;
+}
+
+static void _davinci_i2c_init(struct i2c_regs *i2c_base,
+ uint speed, int slaveadd)
+{
+ if (REG(&(i2c_base->i2c_con)) & I2C_CON_EN) {
+ REG(&(i2c_base->i2c_con)) = 0;
+ udelay(50000);
+ }
+
+ _davinci_i2c_setspeed(i2c_base, speed);
+
+ REG(&(i2c_base->i2c_oa)) = slaveadd;
+ REG(&(i2c_base->i2c_cnt)) = 0;
+
+ /* Interrupts must be enabled or I2C module won't work */
+ REG(&(i2c_base->i2c_ie)) = I2C_IE_SCD_IE | I2C_IE_XRDY_IE |
+ I2C_IE_RRDY_IE | I2C_IE_ARDY_IE | I2C_IE_NACK_IE;
+
+ /* Now enable I2C controller (get it out of reset) */
+ REG(&(i2c_base->i2c_con)) = I2C_CON_EN;
+
+ udelay(1000);
+}
+
+static int _davinci_i2c_read(struct i2c_regs *i2c_base, uint8_t chip,
+ uint32_t addr, int alen, uint8_t *buf, int len)
+{
+ uint32_t tmp;
+ int i;
+
+ if ((alen < 0) || (alen > 2)) {
+ printf("%s(): bogus address length %x\n", __func__, alen);
+ return 1;
+ }
+
+ if (_wait_for_bus(i2c_base))
+ return 1;
+
+ if (alen != 0) {
+ /* Start address phase */
+ tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX;
+ REG(&(i2c_base->i2c_cnt)) = alen;
+ REG(&(i2c_base->i2c_sa)) = chip;
+ REG(&(i2c_base->i2c_con)) = tmp;
+
+ tmp = _poll_i2c_irq(i2c_base, I2C_STAT_XRDY | I2C_STAT_NACK);
+
+ CHECK_NACK();
+
+ switch (alen) {
+ case 2:
+ /* Send address MSByte */
+ if (tmp & I2C_STAT_XRDY) {
+ REG(&(i2c_base->i2c_dxr)) = (addr >> 8) & 0xff;
+ } else {
+ REG(&(i2c_base->i2c_con)) = 0;
+ return 1;
+ }
+
+ tmp = _poll_i2c_irq(i2c_base,
+ I2C_STAT_XRDY | I2C_STAT_NACK);
+
+ CHECK_NACK();
+ /* No break, fall through */
+ case 1:
+ /* Send address LSByte */
+ if (tmp & I2C_STAT_XRDY) {
+ REG(&(i2c_base->i2c_dxr)) = addr & 0xff;
+ } else {
+ REG(&(i2c_base->i2c_con)) = 0;
+ return 1;
+ }
+
+ tmp = _poll_i2c_irq(i2c_base, I2C_STAT_XRDY |
+ I2C_STAT_NACK | I2C_STAT_ARDY);
+
+ CHECK_NACK();
+
+ if (!(tmp & I2C_STAT_ARDY)) {
+ REG(&(i2c_base->i2c_con)) = 0;
+ return 1;
+ }
+ }
+ }
+
+ /* Address phase is over, now read 'len' bytes and stop */
+ tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP;
+ REG(&(i2c_base->i2c_cnt)) = len & 0xffff;
+ REG(&(i2c_base->i2c_sa)) = chip;
+ REG(&(i2c_base->i2c_con)) = tmp;
+
+ for (i = 0; i < len; i++) {
+ tmp = _poll_i2c_irq(i2c_base, I2C_STAT_RRDY | I2C_STAT_NACK |
+ I2C_STAT_ROVR);
+
+ CHECK_NACK();
+
+ if (tmp & I2C_STAT_RRDY) {
+ buf[i] = REG(&(i2c_base->i2c_drr));
+ } else {
+ REG(&(i2c_base->i2c_con)) = 0;
+ return 1;
+ }
+ }
+
+ tmp = _poll_i2c_irq(i2c_base, I2C_STAT_SCD | I2C_STAT_NACK);
+
+ CHECK_NACK();
+
+ if (!(tmp & I2C_STAT_SCD)) {
+ REG(&(i2c_base->i2c_con)) = 0;
+ return 1;
+ }
+
+ _flush_rx(i2c_base);
+ REG(&(i2c_base->i2c_stat)) = 0xffff;
+ REG(&(i2c_base->i2c_cnt)) = 0;
+ REG(&(i2c_base->i2c_con)) = 0;
+
+ return 0;
+}
+
+static int _davinci_i2c_write(struct i2c_regs *i2c_base, uint8_t chip,
+ uint32_t addr, int alen, uint8_t *buf, int len)
+{
+ uint32_t tmp;
+ int i;
+
+ if ((alen < 0) || (alen > 2)) {
+ printf("%s(): bogus address length %x\n", __func__, alen);
+ return 1;
+ }
+ if (len < 0) {
+ printf("%s(): bogus length %x\n", __func__, len);
+ return 1;
+ }
+
+ if (_wait_for_bus(i2c_base))
+ return 1;
+
+ /* Start address phase */
+ tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT |
+ I2C_CON_TRX | I2C_CON_STP;
+ REG(&(i2c_base->i2c_cnt)) = (alen == 0) ?
+ len & 0xffff : (len & 0xffff) + alen;
+ REG(&(i2c_base->i2c_sa)) = chip;
+ REG(&(i2c_base->i2c_con)) = tmp;
+
+ switch (alen) {
+ case 2:
+ /* Send address MSByte */
+ tmp = _poll_i2c_irq(i2c_base, I2C_STAT_XRDY | I2C_STAT_NACK);
+
+ CHECK_NACK();
+
+ if (tmp & I2C_STAT_XRDY) {
+ REG(&(i2c_base->i2c_dxr)) = (addr >> 8) & 0xff;
+ } else {
+ REG(&(i2c_base->i2c_con)) = 0;
+ return 1;
+ }
+ /* No break, fall through */
+ case 1:
+ /* Send address LSByte */
+ tmp = _poll_i2c_irq(i2c_base, I2C_STAT_XRDY | I2C_STAT_NACK);
+
+ CHECK_NACK();
+
+ if (tmp & I2C_STAT_XRDY) {
+ REG(&(i2c_base->i2c_dxr)) = addr & 0xff;
+ } else {
+ REG(&(i2c_base->i2c_con)) = 0;
+ return 1;
+ }
+ }
+
+ for (i = 0; i < len; i++) {
+ tmp = _poll_i2c_irq(i2c_base, I2C_STAT_XRDY | I2C_STAT_NACK);
+
+ CHECK_NACK();
+
+ if (tmp & I2C_STAT_XRDY)
+ REG(&(i2c_base->i2c_dxr)) = buf[i];
+ else
+ return 1;
+ }
+
+ tmp = _poll_i2c_irq(i2c_base, I2C_STAT_SCD | I2C_STAT_NACK);
+
+ CHECK_NACK();
+
+ if (!(tmp & I2C_STAT_SCD)) {
+ REG(&(i2c_base->i2c_con)) = 0;
+ return 1;
+ }
+
+ _flush_rx(i2c_base);
+ REG(&(i2c_base->i2c_stat)) = 0xffff;
+ REG(&(i2c_base->i2c_cnt)) = 0;
+ REG(&(i2c_base->i2c_con)) = 0;
+
+ return 0;
+}
+
+static int _davinci_i2c_probe_chip(struct i2c_regs *i2c_base, uint8_t chip)
+{
+ int rc = 1;
+
+ if (chip == REG(&(i2c_base->i2c_oa)))
+ return rc;
+
+ REG(&(i2c_base->i2c_con)) = 0;
+ if (_wait_for_bus(i2c_base))
+ return 1;
+
+ /* try to read one byte from current (or only) address */
+ REG(&(i2c_base->i2c_cnt)) = 1;
+ REG(&(i2c_base->i2c_sa)) = chip;
+ REG(&(i2c_base->i2c_con)) = (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT |
+ I2C_CON_STP);
+ udelay(50000);
+
+ if (!(REG(&(i2c_base->i2c_stat)) & I2C_STAT_NACK)) {
+ rc = 0;
+ _flush_rx(i2c_base);
+ REG(&(i2c_base->i2c_stat)) = 0xffff;
+ } else {
+ REG(&(i2c_base->i2c_stat)) = 0xffff;
+ REG(&(i2c_base->i2c_con)) |= I2C_CON_STP;
+ udelay(20000);
+ if (_wait_for_bus(i2c_base))
+ return 1;
+ }
+
+ _flush_rx(i2c_base);
+ REG(&(i2c_base->i2c_stat)) = 0xffff;
+ REG(&(i2c_base->i2c_cnt)) = 0;
+ return rc;
+}
+
+#if !CONFIG_IS_ENABLED(DM_I2C)
+static struct i2c_regs *davinci_get_base(struct i2c_adapter *adap)
+{
+ switch (adap->hwadapnr) {
+#if CONFIG_SYS_I2C_BUS_MAX >= 3
+ case 2:
+ return (struct i2c_regs *)I2C2_BASE;
+#endif
+#if CONFIG_SYS_I2C_BUS_MAX >= 2
+ case 1:
+ return (struct i2c_regs *)I2C1_BASE;
+#endif
+ case 0:
+ return (struct i2c_regs *)I2C_BASE;
+
+ default:
+ printf("wrong hwadapnr: %d\n", adap->hwadapnr);
+ }
+
+ return NULL;
+}
+
+static uint davinci_i2c_setspeed(struct i2c_adapter *adap, uint speed)
+{
+ struct i2c_regs *i2c_base = davinci_get_base(adap);
+ uint ret;
+
+ adap->speed = speed;
+ ret = _davinci_i2c_setspeed(i2c_base, speed);
+
+ return ret;
+}
+
+static void davinci_i2c_init(struct i2c_adapter *adap, int speed,
+ int slaveadd)
+{
+ struct i2c_regs *i2c_base = davinci_get_base(adap);
+
+ adap->speed = speed;
+ _davinci_i2c_init(i2c_base, speed, slaveadd);
+
+ return;
+}
+
+static int davinci_i2c_read(struct i2c_adapter *adap, uint8_t chip,
+ uint32_t addr, int alen, uint8_t *buf, int len)
+{
+ struct i2c_regs *i2c_base = davinci_get_base(adap);
+ return _davinci_i2c_read(i2c_base, chip, addr, alen, buf, len);
+}
+
+static int davinci_i2c_write(struct i2c_adapter *adap, uint8_t chip,
+ uint32_t addr, int alen, uint8_t *buf, int len)
+{
+ struct i2c_regs *i2c_base = davinci_get_base(adap);
+
+ return _davinci_i2c_write(i2c_base, chip, addr, alen, buf, len);
+}
+
+static int davinci_i2c_probe_chip(struct i2c_adapter *adap, uint8_t chip)
+{
+ struct i2c_regs *i2c_base = davinci_get_base(adap);
+
+ return _davinci_i2c_probe_chip(i2c_base, chip);
+}
+
+U_BOOT_I2C_ADAP_COMPLETE(davinci_0, davinci_i2c_init, davinci_i2c_probe_chip,
+ davinci_i2c_read, davinci_i2c_write,
+ davinci_i2c_setspeed,
+ CONFIG_SYS_DAVINCI_I2C_SPEED,
+ CONFIG_SYS_DAVINCI_I2C_SLAVE,
+ 0)
+
+#if CONFIG_SYS_I2C_BUS_MAX >= 2
+U_BOOT_I2C_ADAP_COMPLETE(davinci_1, davinci_i2c_init, davinci_i2c_probe_chip,
+ davinci_i2c_read, davinci_i2c_write,
+ davinci_i2c_setspeed,
+ CONFIG_SYS_DAVINCI_I2C_SPEED1,
+ CONFIG_SYS_DAVINCI_I2C_SLAVE1,
+ 1)
+#endif
+
+#if CONFIG_SYS_I2C_BUS_MAX >= 3
+U_BOOT_I2C_ADAP_COMPLETE(davinci_2, davinci_i2c_init, davinci_i2c_probe_chip,
+ davinci_i2c_read, davinci_i2c_write,
+ davinci_i2c_setspeed,
+ CONFIG_SYS_DAVINCI_I2C_SPEED2,
+ CONFIG_SYS_DAVINCI_I2C_SLAVE2,
+ 2)
+#endif
+
+#else /* CONFIG_DM_I2C */
+
+static int davinci_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
+ int nmsgs)
+{
+ struct i2c_bus *i2c_bus = dev_get_priv(bus);
+ int ret;
+
+ debug("i2c_xfer: %d messages\n", nmsgs);
+ for (; nmsgs > 0; nmsgs--, msg++) {
+ debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
+ if (msg->flags & I2C_M_RD) {
+ ret = _davinci_i2c_read(i2c_bus->regs, msg->addr,
+ 0, 0, msg->buf, msg->len);
+ } else {
+ ret = _davinci_i2c_write(i2c_bus->regs, msg->addr,
+ 0, 0, msg->buf, msg->len);
+ }
+ if (ret) {
+ debug("i2c_write: error sending\n");
+ return -EREMOTEIO;
+ }
+ }
+
+ return ret;
+}
+
+static int davinci_i2c_set_speed(struct udevice *dev, uint speed)
+{
+ struct i2c_bus *i2c_bus = dev_get_priv(dev);
+
+ i2c_bus->speed = speed;
+ return _davinci_i2c_setspeed(i2c_bus->regs, speed);
+}
+
+static int davinci_i2c_probe(struct udevice *dev)
+{
+ struct i2c_bus *i2c_bus = dev_get_priv(dev);
+
+ i2c_bus->id = dev_seq(dev);
+ i2c_bus->regs = dev_read_addr_ptr(dev);
+
+ i2c_bus->speed = 100000;
+ _davinci_i2c_init(i2c_bus->regs, i2c_bus->speed, 0);
+
+ return 0;
+}
+
+static int davinci_i2c_probe_chip(struct udevice *bus, uint chip_addr,
+ uint chip_flags)
+{
+ struct i2c_bus *i2c_bus = dev_get_priv(bus);
+
+ return _davinci_i2c_probe_chip(i2c_bus->regs, chip_addr);
+}
+
+static const struct dm_i2c_ops davinci_i2c_ops = {
+ .xfer = davinci_i2c_xfer,
+ .probe_chip = davinci_i2c_probe_chip,
+ .set_bus_speed = davinci_i2c_set_speed,
+};
+
+static const struct udevice_id davinci_i2c_ids[] = {
+ { .compatible = "ti,davinci-i2c"},
+ { .compatible = "ti,keystone-i2c"},
+ { }
+};
+
+U_BOOT_DRIVER(i2c_davinci) = {
+ .name = "i2c_davinci",
+ .id = UCLASS_I2C,
+ .of_match = davinci_i2c_ids,
+ .probe = davinci_i2c_probe,
+ .priv_auto = sizeof(struct i2c_bus),
+ .ops = &davinci_i2c_ops,
+};
+
+#endif /* CONFIG_DM_I2C */
diff --git a/roms/u-boot/drivers/i2c/davinci_i2c.h b/roms/u-boot/drivers/i2c/davinci_i2c.h
new file mode 100644
index 000000000..57377ce94
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/davinci_i2c.h
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2004-2014
+ * Texas Instruments, <www.ti.com>
+ *
+ * Some changes copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
+ */
+#ifndef _DAVINCI_I2C_H_
+#define _DAVINCI_I2C_H_
+
+#define I2C_WRITE 0
+#define I2C_READ 1
+
+struct i2c_regs {
+ u32 i2c_oa;
+ u32 i2c_ie;
+ u32 i2c_stat;
+ u32 i2c_scll;
+ u32 i2c_sclh;
+ u32 i2c_cnt;
+ u32 i2c_drr;
+ u32 i2c_sa;
+ u32 i2c_dxr;
+ u32 i2c_con;
+ u32 i2c_iv;
+ u32 res_2c;
+ u32 i2c_psc;
+};
+
+/* I2C masks */
+
+/* I2C Interrupt Enable Register (I2C_IE): */
+#define I2C_IE_SCD_IE (1 << 5) /* Stop condition detect interrupt enable */
+#define I2C_IE_XRDY_IE (1 << 4) /* Transmit data ready interrupt enable */
+#define I2C_IE_RRDY_IE (1 << 3) /* Receive data ready interrupt enable */
+#define I2C_IE_ARDY_IE (1 << 2) /* Register access ready interrupt enable */
+#define I2C_IE_NACK_IE (1 << 1) /* No acknowledgment interrupt enable */
+#define I2C_IE_AL_IE (1 << 0) /* Arbitration lost interrupt enable */
+
+/* I2C Status Register (I2C_STAT): */
+
+#define I2C_STAT_BB (1 << 12) /* Bus busy */
+#define I2C_STAT_ROVR (1 << 11) /* Receive overrun */
+#define I2C_STAT_XUDF (1 << 10) /* Transmit underflow */
+#define I2C_STAT_AAS (1 << 9) /* Address as slave */
+#define I2C_STAT_SCD (1 << 5) /* Stop condition detect */
+#define I2C_STAT_XRDY (1 << 4) /* Transmit data ready */
+#define I2C_STAT_RRDY (1 << 3) /* Receive data ready */
+#define I2C_STAT_ARDY (1 << 2) /* Register access ready */
+#define I2C_STAT_NACK (1 << 1) /* No acknowledgment interrupt enable */
+#define I2C_STAT_AL (1 << 0) /* Arbitration lost interrupt enable */
+
+/* I2C Interrupt Code Register (I2C_INTCODE): */
+
+#define I2C_INTCODE_MASK 7
+#define I2C_INTCODE_NONE 0
+#define I2C_INTCODE_AL 1 /* Arbitration lost */
+#define I2C_INTCODE_NAK 2 /* No acknowledgement/general call */
+#define I2C_INTCODE_ARDY 3 /* Register access ready */
+#define I2C_INTCODE_RRDY 4 /* Rcv data ready */
+#define I2C_INTCODE_XRDY 5 /* Xmit data ready */
+#define I2C_INTCODE_SCD 6 /* Stop condition detect */
+
+/* I2C Configuration Register (I2C_CON): */
+
+#define I2C_CON_EN (1 << 5) /* I2C module enable */
+#define I2C_CON_STB (1 << 4) /* Start byte mode (master mode only) */
+#define I2C_CON_MST (1 << 10) /* Master/slave mode */
+#define I2C_CON_TRX (1 << 9) /* Tx/Rx mode (master mode only) */
+#define I2C_CON_XA (1 << 8) /* Expand address */
+#define I2C_CON_STP (1 << 11) /* Stop condition (master mode only) */
+#define I2C_CON_STT (1 << 13) /* Start condition (master mode only) */
+#define I2C_CON_FREE (1 << 14) /* Free run on emulation */
+
+#define I2C_TIMEOUT 0xffff0000 /* Timeout mask for poll_i2c_irq() */
+
+#endif
diff --git a/roms/u-boot/drivers/i2c/designware_i2c.c b/roms/u-boot/drivers/i2c/designware_i2c.c
new file mode 100644
index 000000000..072803691
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/designware_i2c.c
@@ -0,0 +1,853 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2009
+ * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <i2c.h>
+#include <log.h>
+#include <malloc.h>
+#include <pci.h>
+#include <reset.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include "designware_i2c.h"
+#include <dm/device_compat.h>
+#include <linux/err.h>
+
+/*
+ * This assigned unique hex value is constant and is derived from the two ASCII
+ * letters 'DW' followed by a 16-bit unsigned number
+ */
+#define DW_I2C_COMP_TYPE 0x44570140
+
+#ifdef CONFIG_SYS_I2C_DW_ENABLE_STATUS_UNSUPPORTED
+static int dw_i2c_enable(struct i2c_regs *i2c_base, bool enable)
+{
+ u32 ena = enable ? IC_ENABLE_0B : 0;
+
+ writel(ena, &i2c_base->ic_enable);
+
+ return 0;
+}
+#else
+static int dw_i2c_enable(struct i2c_regs *i2c_base, bool enable)
+{
+ u32 ena = enable ? IC_ENABLE_0B : 0;
+ int timeout = 100;
+
+ do {
+ writel(ena, &i2c_base->ic_enable);
+ if ((readl(&i2c_base->ic_enable_status) & IC_ENABLE_0B) == ena)
+ return 0;
+
+ /*
+ * Wait 10 times the signaling period of the highest I2C
+ * transfer supported by the driver (for 400KHz this is
+ * 25us) as described in the DesignWare I2C databook.
+ */
+ udelay(25);
+ } while (timeout--);
+ printf("timeout in %sabling I2C adapter\n", enable ? "en" : "dis");
+
+ return -ETIMEDOUT;
+}
+#endif
+
+/* High and low times in different speed modes (in ns) */
+enum {
+ /* SDA Hold Time */
+ DEFAULT_SDA_HOLD_TIME = 300,
+};
+
+/**
+ * calc_counts() - Convert a period to a number of IC clk cycles
+ *
+ * @ic_clk: Input clock in Hz
+ * @period_ns: Period to represent, in ns
+ * @return calculated count
+ */
+static uint calc_counts(uint ic_clk, uint period_ns)
+{
+ return DIV_ROUND_UP(ic_clk / 1000 * period_ns, NANO_TO_KILO);
+}
+
+/**
+ * struct i2c_mode_info - Information about an I2C speed mode
+ *
+ * Each speed mode has its own characteristics. This struct holds these to aid
+ * calculations in dw_i2c_calc_timing().
+ *
+ * @speed: Speed in Hz
+ * @min_scl_lowtime_ns: Minimum value for SCL low period in ns
+ * @min_scl_hightime_ns: Minimum value for SCL high period in ns
+ * @def_rise_time_ns: Default rise time in ns
+ * @def_fall_time_ns: Default fall time in ns
+ */
+struct i2c_mode_info {
+ int speed;
+ int min_scl_hightime_ns;
+ int min_scl_lowtime_ns;
+ int def_rise_time_ns;
+ int def_fall_time_ns;
+};
+
+static const struct i2c_mode_info info_for_mode[] = {
+ [IC_SPEED_MODE_STANDARD] = {
+ I2C_SPEED_STANDARD_RATE,
+ MIN_SS_SCL_HIGHTIME,
+ MIN_SS_SCL_LOWTIME,
+ 1000,
+ 300,
+ },
+ [IC_SPEED_MODE_FAST] = {
+ I2C_SPEED_FAST_RATE,
+ MIN_FS_SCL_HIGHTIME,
+ MIN_FS_SCL_LOWTIME,
+ 300,
+ 300,
+ },
+ [IC_SPEED_MODE_FAST_PLUS] = {
+ I2C_SPEED_FAST_PLUS_RATE,
+ MIN_FP_SCL_HIGHTIME,
+ MIN_FP_SCL_LOWTIME,
+ 260,
+ 500,
+ },
+ [IC_SPEED_MODE_HIGH] = {
+ I2C_SPEED_HIGH_RATE,
+ MIN_HS_SCL_HIGHTIME,
+ MIN_HS_SCL_LOWTIME,
+ 120,
+ 120,
+ },
+};
+
+/**
+ * dw_i2c_calc_timing() - Calculate the timings to use for a bus
+ *
+ * @priv: Bus private information (NULL if not using driver model)
+ * @mode: Speed mode to use
+ * @ic_clk: IC clock speed in Hz
+ * @spk_cnt: Spike-suppression count
+ * @config: Returns value to use
+ * @return 0 if OK, -EINVAL if the calculation failed due to invalid data
+ */
+static int dw_i2c_calc_timing(struct dw_i2c *priv, enum i2c_speed_mode mode,
+ int ic_clk, int spk_cnt,
+ struct dw_i2c_speed_config *config)
+{
+ int fall_cnt, rise_cnt, min_tlow_cnt, min_thigh_cnt;
+ int hcnt, lcnt, period_cnt, diff, tot;
+ int sda_hold_time_ns, scl_rise_time_ns, scl_fall_time_ns;
+ const struct i2c_mode_info *info;
+
+ /*
+ * Find the period, rise, fall, min tlow, and min thigh in terms of
+ * counts of the IC clock
+ */
+ info = &info_for_mode[mode];
+ period_cnt = ic_clk / info->speed;
+ scl_rise_time_ns = priv && priv->scl_rise_time_ns ?
+ priv->scl_rise_time_ns : info->def_rise_time_ns;
+ scl_fall_time_ns = priv && priv->scl_fall_time_ns ?
+ priv->scl_fall_time_ns : info->def_fall_time_ns;
+ rise_cnt = calc_counts(ic_clk, scl_rise_time_ns);
+ fall_cnt = calc_counts(ic_clk, scl_fall_time_ns);
+ min_tlow_cnt = calc_counts(ic_clk, info->min_scl_lowtime_ns);
+ min_thigh_cnt = calc_counts(ic_clk, info->min_scl_hightime_ns);
+
+ debug("dw_i2c: mode %d, ic_clk %d, speed %d, period %d rise %d fall %d tlow %d thigh %d spk %d\n",
+ mode, ic_clk, info->speed, period_cnt, rise_cnt, fall_cnt,
+ min_tlow_cnt, min_thigh_cnt, spk_cnt);
+
+ /*
+ * Back-solve for hcnt and lcnt according to the following equations:
+ * SCL_High_time = [(HCNT + IC_*_SPKLEN + 7) * ic_clk] + SCL_Fall_time
+ * SCL_Low_time = [(LCNT + 1) * ic_clk] - SCL_Fall_time + SCL_Rise_time
+ */
+ hcnt = min_thigh_cnt - fall_cnt - 7 - spk_cnt;
+ lcnt = min_tlow_cnt - rise_cnt + fall_cnt - 1;
+
+ if (hcnt < 0 || lcnt < 0) {
+ debug("dw_i2c: bad counts. hcnt = %d lcnt = %d\n", hcnt, lcnt);
+ return log_msg_ret("counts", -EINVAL);
+ }
+
+ /*
+ * Now add things back up to ensure the period is hit. If it is off,
+ * split the difference and bias to lcnt for remainder
+ */
+ tot = hcnt + lcnt + 7 + spk_cnt + rise_cnt + 1;
+
+ if (tot < period_cnt) {
+ diff = (period_cnt - tot) / 2;
+ hcnt += diff;
+ lcnt += diff;
+ tot = hcnt + lcnt + 7 + spk_cnt + rise_cnt + 1;
+ lcnt += period_cnt - tot;
+ }
+
+ config->scl_lcnt = lcnt;
+ config->scl_hcnt = hcnt;
+
+ /* Use internal default unless other value is specified */
+ sda_hold_time_ns = priv && priv->sda_hold_time_ns ?
+ priv->sda_hold_time_ns : DEFAULT_SDA_HOLD_TIME;
+ config->sda_hold = calc_counts(ic_clk, sda_hold_time_ns);
+
+ debug("dw_i2c: hcnt = %d lcnt = %d sda hold = %d\n", hcnt, lcnt,
+ config->sda_hold);
+
+ return 0;
+}
+
+/**
+ * calc_bus_speed() - Calculate the config to use for a particular i2c speed
+ *
+ * @priv: Private information for the driver (NULL if not using driver model)
+ * @i2c_base: Registers for the I2C controller
+ * @speed: Required i2c speed in Hz
+ * @bus_clk: Input clock to the I2C controller in Hz (e.g. IC_CLK)
+ * @config: Returns the config to use for this speed
+ * @return 0 if OK, -ve on error
+ */
+static int calc_bus_speed(struct dw_i2c *priv, struct i2c_regs *regs, int speed,
+ ulong bus_clk, struct dw_i2c_speed_config *config)
+{
+ const struct dw_scl_sda_cfg *scl_sda_cfg = NULL;
+ enum i2c_speed_mode i2c_spd;
+ int spk_cnt;
+ int ret;
+
+ if (priv)
+ scl_sda_cfg = priv->scl_sda_cfg;
+ /* Allow high speed if there is no config, or the config allows it */
+ if (speed >= I2C_SPEED_HIGH_RATE)
+ i2c_spd = IC_SPEED_MODE_HIGH;
+ else if (speed >= I2C_SPEED_FAST_PLUS_RATE)
+ i2c_spd = IC_SPEED_MODE_FAST_PLUS;
+ else if (speed >= I2C_SPEED_FAST_RATE)
+ i2c_spd = IC_SPEED_MODE_FAST;
+ else
+ i2c_spd = IC_SPEED_MODE_STANDARD;
+
+ /* Check is high speed possible and fall back to fast mode if not */
+ if (i2c_spd == IC_SPEED_MODE_HIGH) {
+ u32 comp_param1;
+
+ comp_param1 = readl(&regs->comp_param1);
+ if ((comp_param1 & DW_IC_COMP_PARAM_1_SPEED_MODE_MASK)
+ != DW_IC_COMP_PARAM_1_SPEED_MODE_HIGH)
+ i2c_spd = IC_SPEED_MODE_FAST;
+ }
+
+ /* Get the proper spike-suppression count based on target speed */
+ if (!priv || !priv->has_spk_cnt)
+ spk_cnt = 0;
+ else if (i2c_spd >= IC_SPEED_MODE_HIGH)
+ spk_cnt = readl(&regs->hs_spklen);
+ else
+ spk_cnt = readl(&regs->fs_spklen);
+ if (scl_sda_cfg) {
+ config->sda_hold = scl_sda_cfg->sda_hold;
+ if (i2c_spd == IC_SPEED_MODE_STANDARD) {
+ config->scl_hcnt = scl_sda_cfg->ss_hcnt;
+ config->scl_lcnt = scl_sda_cfg->ss_lcnt;
+ } else if (i2c_spd == IC_SPEED_MODE_HIGH) {
+ config->scl_hcnt = scl_sda_cfg->hs_hcnt;
+ config->scl_lcnt = scl_sda_cfg->hs_lcnt;
+ } else {
+ config->scl_hcnt = scl_sda_cfg->fs_hcnt;
+ config->scl_lcnt = scl_sda_cfg->fs_lcnt;
+ }
+ } else {
+ ret = dw_i2c_calc_timing(priv, i2c_spd, bus_clk, spk_cnt,
+ config);
+ if (ret)
+ return log_msg_ret("gen_confg", ret);
+ }
+ config->speed_mode = i2c_spd;
+
+ return 0;
+}
+
+/**
+ * _dw_i2c_set_bus_speed() - Set the i2c speed
+ *
+ * @priv: Private information for the driver (NULL if not using driver model)
+ * @i2c_base: Registers for the I2C controller
+ * @speed: Required i2c speed in Hz
+ * @bus_clk: Input clock to the I2C controller in Hz (e.g. IC_CLK)
+ * @return 0 if OK, -ve on error
+ */
+static int _dw_i2c_set_bus_speed(struct dw_i2c *priv, struct i2c_regs *i2c_base,
+ unsigned int speed, unsigned int bus_clk)
+{
+ struct dw_i2c_speed_config config;
+ unsigned int cntl;
+ unsigned int ena;
+ int ret;
+
+ ret = calc_bus_speed(priv, i2c_base, speed, bus_clk, &config);
+ if (ret)
+ return ret;
+
+ /* Get enable setting for restore later */
+ ena = readl(&i2c_base->ic_enable) & IC_ENABLE_0B;
+
+ /* to set speed cltr must be disabled */
+ dw_i2c_enable(i2c_base, false);
+
+ cntl = (readl(&i2c_base->ic_con) & (~IC_CON_SPD_MSK));
+
+ switch (config.speed_mode) {
+ case IC_SPEED_MODE_HIGH:
+ cntl |= IC_CON_SPD_HS;
+ writel(config.scl_hcnt, &i2c_base->ic_hs_scl_hcnt);
+ writel(config.scl_lcnt, &i2c_base->ic_hs_scl_lcnt);
+ break;
+ case IC_SPEED_MODE_STANDARD:
+ cntl |= IC_CON_SPD_SS;
+ writel(config.scl_hcnt, &i2c_base->ic_ss_scl_hcnt);
+ writel(config.scl_lcnt, &i2c_base->ic_ss_scl_lcnt);
+ break;
+ case IC_SPEED_MODE_FAST_PLUS:
+ case IC_SPEED_MODE_FAST:
+ default:
+ cntl |= IC_CON_SPD_FS;
+ writel(config.scl_hcnt, &i2c_base->ic_fs_scl_hcnt);
+ writel(config.scl_lcnt, &i2c_base->ic_fs_scl_lcnt);
+ break;
+ }
+
+ writel(cntl, &i2c_base->ic_con);
+
+ /* Configure SDA Hold Time if required */
+ if (config.sda_hold)
+ writel(config.sda_hold, &i2c_base->ic_sda_hold);
+
+ /* Restore back i2c now speed set */
+ if (ena == IC_ENABLE_0B)
+ dw_i2c_enable(i2c_base, true);
+ if (priv)
+ priv->config = config;
+
+ return 0;
+}
+
+int dw_i2c_gen_speed_config(const struct udevice *dev, int speed_hz,
+ struct dw_i2c_speed_config *config)
+{
+ struct dw_i2c *priv = dev_get_priv(dev);
+ ulong rate;
+ int ret;
+
+#if CONFIG_IS_ENABLED(CLK)
+ rate = clk_get_rate(&priv->clk);
+ if (IS_ERR_VALUE(rate))
+ return log_msg_ret("clk", -EINVAL);
+#else
+ rate = IC_CLK;
+#endif
+
+ ret = calc_bus_speed(priv, priv->regs, speed_hz, rate, config);
+ if (ret)
+ printf("%s: ret=%d\n", __func__, ret);
+ if (ret)
+ return log_msg_ret("calc_bus_speed", ret);
+
+ return 0;
+}
+
+/*
+ * i2c_setaddress - Sets the target slave address
+ * @i2c_addr: target i2c address
+ *
+ * Sets the target slave address.
+ */
+static void i2c_setaddress(struct i2c_regs *i2c_base, unsigned int i2c_addr)
+{
+ /* Disable i2c */
+ dw_i2c_enable(i2c_base, false);
+
+ writel(i2c_addr, &i2c_base->ic_tar);
+
+ /* Enable i2c */
+ dw_i2c_enable(i2c_base, true);
+}
+
+/*
+ * i2c_flush_rxfifo - Flushes the i2c RX FIFO
+ *
+ * Flushes the i2c RX FIFO
+ */
+static void i2c_flush_rxfifo(struct i2c_regs *i2c_base)
+{
+ while (readl(&i2c_base->ic_status) & IC_STATUS_RFNE)
+ readl(&i2c_base->ic_cmd_data);
+}
+
+/*
+ * i2c_wait_for_bb - Waits for bus busy
+ *
+ * Waits for bus busy
+ */
+static int i2c_wait_for_bb(struct i2c_regs *i2c_base)
+{
+ unsigned long start_time_bb = get_timer(0);
+
+ while ((readl(&i2c_base->ic_status) & IC_STATUS_MA) ||
+ !(readl(&i2c_base->ic_status) & IC_STATUS_TFE)) {
+
+ /* Evaluate timeout */
+ if (get_timer(start_time_bb) > (unsigned long)(I2C_BYTE_TO_BB))
+ return 1;
+ }
+
+ return 0;
+}
+
+static int i2c_xfer_init(struct i2c_regs *i2c_base, uchar chip, uint addr,
+ int alen)
+{
+ if (i2c_wait_for_bb(i2c_base))
+ return 1;
+
+ i2c_setaddress(i2c_base, chip);
+ while (alen) {
+ alen--;
+ /* high byte address going out first */
+ writel((addr >> (alen * 8)) & 0xff,
+ &i2c_base->ic_cmd_data);
+ }
+ return 0;
+}
+
+static int i2c_xfer_finish(struct i2c_regs *i2c_base)
+{
+ ulong start_stop_det = get_timer(0);
+
+ while (1) {
+ if ((readl(&i2c_base->ic_raw_intr_stat) & IC_STOP_DET)) {
+ readl(&i2c_base->ic_clr_stop_det);
+ break;
+ } else if (get_timer(start_stop_det) > I2C_STOPDET_TO) {
+ break;
+ }
+ }
+
+ if (i2c_wait_for_bb(i2c_base)) {
+ printf("Timed out waiting for bus\n");
+ return 1;
+ }
+
+ i2c_flush_rxfifo(i2c_base);
+
+ return 0;
+}
+
+/*
+ * i2c_read - Read from i2c memory
+ * @chip: target i2c address
+ * @addr: address to read from
+ * @alen:
+ * @buffer: buffer for read data
+ * @len: no of bytes to be read
+ *
+ * Read from i2c memory.
+ */
+static int __dw_i2c_read(struct i2c_regs *i2c_base, u8 dev, uint addr,
+ int alen, u8 *buffer, int len)
+{
+ unsigned long start_time_rx;
+ unsigned int active = 0;
+
+#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW
+ /*
+ * EEPROM chips that implement "address overflow" are ones
+ * like Catalyst 24WC04/08/16 which has 9/10/11 bits of
+ * address and the extra bits end up in the "chip address"
+ * bit slots. This makes a 24WC08 (1Kbyte) chip look like
+ * four 256 byte chips.
+ *
+ * Note that we consider the length of the address field to
+ * still be one byte because the extra address bits are
+ * hidden in the chip address.
+ */
+ dev |= ((addr >> (alen * 8)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
+ addr &= ~(CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW << (alen * 8));
+
+ debug("%s: fix addr_overflow: dev %02x addr %02x\n", __func__, dev,
+ addr);
+#endif
+
+ if (i2c_xfer_init(i2c_base, dev, addr, alen))
+ return 1;
+
+ start_time_rx = get_timer(0);
+ while (len) {
+ if (!active) {
+ /*
+ * Avoid writing to ic_cmd_data multiple times
+ * in case this loop spins too quickly and the
+ * ic_status RFNE bit isn't set after the first
+ * write. Subsequent writes to ic_cmd_data can
+ * trigger spurious i2c transfer.
+ */
+ if (len == 1)
+ writel(IC_CMD | IC_STOP, &i2c_base->ic_cmd_data);
+ else
+ writel(IC_CMD, &i2c_base->ic_cmd_data);
+ active = 1;
+ }
+
+ if (readl(&i2c_base->ic_status) & IC_STATUS_RFNE) {
+ *buffer++ = (uchar)readl(&i2c_base->ic_cmd_data);
+ len--;
+ start_time_rx = get_timer(0);
+ active = 0;
+ } else if (get_timer(start_time_rx) > I2C_BYTE_TO) {
+ return 1;
+ }
+ }
+
+ return i2c_xfer_finish(i2c_base);
+}
+
+/*
+ * i2c_write - Write to i2c memory
+ * @chip: target i2c address
+ * @addr: address to read from
+ * @alen:
+ * @buffer: buffer for read data
+ * @len: no of bytes to be read
+ *
+ * Write to i2c memory.
+ */
+static int __dw_i2c_write(struct i2c_regs *i2c_base, u8 dev, uint addr,
+ int alen, u8 *buffer, int len)
+{
+ int nb = len;
+ unsigned long start_time_tx;
+
+#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW
+ /*
+ * EEPROM chips that implement "address overflow" are ones
+ * like Catalyst 24WC04/08/16 which has 9/10/11 bits of
+ * address and the extra bits end up in the "chip address"
+ * bit slots. This makes a 24WC08 (1Kbyte) chip look like
+ * four 256 byte chips.
+ *
+ * Note that we consider the length of the address field to
+ * still be one byte because the extra address bits are
+ * hidden in the chip address.
+ */
+ dev |= ((addr >> (alen * 8)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
+ addr &= ~(CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW << (alen * 8));
+
+ debug("%s: fix addr_overflow: dev %02x addr %02x\n", __func__, dev,
+ addr);
+#endif
+
+ if (i2c_xfer_init(i2c_base, dev, addr, alen))
+ return 1;
+
+ start_time_tx = get_timer(0);
+ while (len) {
+ if (readl(&i2c_base->ic_status) & IC_STATUS_TFNF) {
+ if (--len == 0) {
+ writel(*buffer | IC_STOP,
+ &i2c_base->ic_cmd_data);
+ } else {
+ writel(*buffer, &i2c_base->ic_cmd_data);
+ }
+ buffer++;
+ start_time_tx = get_timer(0);
+
+ } else if (get_timer(start_time_tx) > (nb * I2C_BYTE_TO)) {
+ printf("Timed out. i2c write Failed\n");
+ return 1;
+ }
+ }
+
+ return i2c_xfer_finish(i2c_base);
+}
+
+/*
+ * __dw_i2c_init - Init function
+ * @speed: required i2c speed
+ * @slaveaddr: slave address for the device
+ *
+ * Initialization function.
+ */
+static int __dw_i2c_init(struct i2c_regs *i2c_base, int speed, int slaveaddr)
+{
+ int ret;
+
+ /* Disable i2c */
+ ret = dw_i2c_enable(i2c_base, false);
+ if (ret)
+ return ret;
+
+ writel(IC_CON_SD | IC_CON_RE | IC_CON_SPD_FS | IC_CON_MM,
+ &i2c_base->ic_con);
+ writel(IC_RX_TL, &i2c_base->ic_rx_tl);
+ writel(IC_TX_TL, &i2c_base->ic_tx_tl);
+ writel(IC_STOP_DET, &i2c_base->ic_intr_mask);
+#if !CONFIG_IS_ENABLED(DM_I2C)
+ _dw_i2c_set_bus_speed(NULL, i2c_base, speed, IC_CLK);
+ writel(slaveaddr, &i2c_base->ic_sar);
+#endif
+
+ /* Enable i2c */
+ ret = dw_i2c_enable(i2c_base, true);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+#if !CONFIG_IS_ENABLED(DM_I2C)
+/*
+ * The legacy I2C functions. These need to get removed once
+ * all users of this driver are converted to DM.
+ */
+static struct i2c_regs *i2c_get_base(struct i2c_adapter *adap)
+{
+ switch (adap->hwadapnr) {
+#if CONFIG_SYS_I2C_BUS_MAX >= 4
+ case 3:
+ return (struct i2c_regs *)CONFIG_SYS_I2C_BASE3;
+#endif
+#if CONFIG_SYS_I2C_BUS_MAX >= 3
+ case 2:
+ return (struct i2c_regs *)CONFIG_SYS_I2C_BASE2;
+#endif
+#if CONFIG_SYS_I2C_BUS_MAX >= 2
+ case 1:
+ return (struct i2c_regs *)CONFIG_SYS_I2C_BASE1;
+#endif
+ case 0:
+ return (struct i2c_regs *)CONFIG_SYS_I2C_BASE;
+ default:
+ printf("Wrong I2C-adapter number %d\n", adap->hwadapnr);
+ }
+
+ return NULL;
+}
+
+static unsigned int dw_i2c_set_bus_speed(struct i2c_adapter *adap,
+ unsigned int speed)
+{
+ adap->speed = speed;
+ return _dw_i2c_set_bus_speed(NULL, i2c_get_base(adap), speed, IC_CLK);
+}
+
+static void dw_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
+{
+ __dw_i2c_init(i2c_get_base(adap), speed, slaveaddr);
+}
+
+static int dw_i2c_read(struct i2c_adapter *adap, u8 dev, uint addr,
+ int alen, u8 *buffer, int len)
+{
+ return __dw_i2c_read(i2c_get_base(adap), dev, addr, alen, buffer, len);
+}
+
+static int dw_i2c_write(struct i2c_adapter *adap, u8 dev, uint addr,
+ int alen, u8 *buffer, int len)
+{
+ return __dw_i2c_write(i2c_get_base(adap), dev, addr, alen, buffer, len);
+}
+
+/* dw_i2c_probe - Probe the i2c chip */
+static int dw_i2c_probe(struct i2c_adapter *adap, u8 dev)
+{
+ struct i2c_regs *i2c_base = i2c_get_base(adap);
+ u32 tmp;
+ int ret;
+
+ /*
+ * Try to read the first location of the chip.
+ */
+ ret = __dw_i2c_read(i2c_base, dev, 0, 1, (uchar *)&tmp, 1);
+ if (ret)
+ dw_i2c_init(adap, adap->speed, adap->slaveaddr);
+
+ return ret;
+}
+
+U_BOOT_I2C_ADAP_COMPLETE(dw_0, dw_i2c_init, dw_i2c_probe, dw_i2c_read,
+ dw_i2c_write, dw_i2c_set_bus_speed,
+ CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 0)
+
+#if CONFIG_SYS_I2C_BUS_MAX >= 2
+U_BOOT_I2C_ADAP_COMPLETE(dw_1, dw_i2c_init, dw_i2c_probe, dw_i2c_read,
+ dw_i2c_write, dw_i2c_set_bus_speed,
+ CONFIG_SYS_I2C_SPEED1, CONFIG_SYS_I2C_SLAVE1, 1)
+#endif
+
+#if CONFIG_SYS_I2C_BUS_MAX >= 3
+U_BOOT_I2C_ADAP_COMPLETE(dw_2, dw_i2c_init, dw_i2c_probe, dw_i2c_read,
+ dw_i2c_write, dw_i2c_set_bus_speed,
+ CONFIG_SYS_I2C_SPEED2, CONFIG_SYS_I2C_SLAVE2, 2)
+#endif
+
+#if CONFIG_SYS_I2C_BUS_MAX >= 4
+U_BOOT_I2C_ADAP_COMPLETE(dw_3, dw_i2c_init, dw_i2c_probe, dw_i2c_read,
+ dw_i2c_write, dw_i2c_set_bus_speed,
+ CONFIG_SYS_I2C_SPEED3, CONFIG_SYS_I2C_SLAVE3, 3)
+#endif
+
+#else /* CONFIG_DM_I2C */
+/* The DM I2C functions */
+
+static int designware_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
+ int nmsgs)
+{
+ struct dw_i2c *i2c = dev_get_priv(bus);
+ int ret;
+
+ debug("i2c_xfer: %d messages\n", nmsgs);
+ for (; nmsgs > 0; nmsgs--, msg++) {
+ debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
+ if (msg->flags & I2C_M_RD) {
+ ret = __dw_i2c_read(i2c->regs, msg->addr, 0, 0,
+ msg->buf, msg->len);
+ } else {
+ ret = __dw_i2c_write(i2c->regs, msg->addr, 0, 0,
+ msg->buf, msg->len);
+ }
+ if (ret) {
+ debug("i2c_write: error sending\n");
+ return -EREMOTEIO;
+ }
+ }
+
+ return 0;
+}
+
+static int designware_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
+{
+ struct dw_i2c *i2c = dev_get_priv(bus);
+ ulong rate;
+
+#if CONFIG_IS_ENABLED(CLK)
+ rate = clk_get_rate(&i2c->clk);
+ if (IS_ERR_VALUE(rate))
+ return log_ret(-EINVAL);
+#else
+ rate = IC_CLK;
+#endif
+ return _dw_i2c_set_bus_speed(i2c, i2c->regs, speed, rate);
+}
+
+static int designware_i2c_probe_chip(struct udevice *bus, uint chip_addr,
+ uint chip_flags)
+{
+ struct dw_i2c *i2c = dev_get_priv(bus);
+ struct i2c_regs *i2c_base = i2c->regs;
+ u32 tmp;
+ int ret;
+
+ /* Try to read the first location of the chip */
+ ret = __dw_i2c_read(i2c_base, chip_addr, 0, 1, (uchar *)&tmp, 1);
+ if (ret)
+ __dw_i2c_init(i2c_base, 0, 0);
+
+ return ret;
+}
+
+int designware_i2c_of_to_plat(struct udevice *bus)
+{
+ struct dw_i2c *priv = dev_get_priv(bus);
+ int ret;
+
+ if (!priv->regs)
+ priv->regs = dev_read_addr_ptr(bus);
+ dev_read_u32(bus, "i2c-scl-rising-time-ns", &priv->scl_rise_time_ns);
+ dev_read_u32(bus, "i2c-scl-falling-time-ns", &priv->scl_fall_time_ns);
+ dev_read_u32(bus, "i2c-sda-hold-time-ns", &priv->sda_hold_time_ns);
+
+ ret = reset_get_bulk(bus, &priv->resets);
+ if (ret) {
+ if (ret != -ENOTSUPP)
+ dev_warn(bus, "Can't get reset: %d\n", ret);
+ } else {
+ reset_deassert_bulk(&priv->resets);
+ }
+
+#if CONFIG_IS_ENABLED(CLK)
+ ret = clk_get_by_index(bus, 0, &priv->clk);
+ if (ret)
+ return ret;
+
+ ret = clk_enable(&priv->clk);
+ if (ret && ret != -ENOSYS && ret != -ENOTSUPP) {
+ clk_free(&priv->clk);
+ dev_err(bus, "failed to enable clock\n");
+ return ret;
+ }
+#endif
+
+ return 0;
+}
+
+int designware_i2c_probe(struct udevice *bus)
+{
+ struct dw_i2c *priv = dev_get_priv(bus);
+ uint comp_type;
+
+ comp_type = readl(&priv->regs->comp_type);
+ if (comp_type != DW_I2C_COMP_TYPE) {
+ log_err("I2C bus %s has unknown type %#x\n", bus->name,
+ comp_type);
+ return -ENXIO;
+ }
+
+ log_debug("I2C bus %s version %#x\n", bus->name,
+ readl(&priv->regs->comp_version));
+
+ return __dw_i2c_init(priv->regs, 0, 0);
+}
+
+int designware_i2c_remove(struct udevice *dev)
+{
+ struct dw_i2c *priv = dev_get_priv(dev);
+
+#if CONFIG_IS_ENABLED(CLK)
+ clk_disable(&priv->clk);
+ clk_free(&priv->clk);
+#endif
+
+ return reset_release_bulk(&priv->resets);
+}
+
+const struct dm_i2c_ops designware_i2c_ops = {
+ .xfer = designware_i2c_xfer,
+ .probe_chip = designware_i2c_probe_chip,
+ .set_bus_speed = designware_i2c_set_bus_speed,
+};
+
+static const struct udevice_id designware_i2c_ids[] = {
+ { .compatible = "snps,designware-i2c" },
+ { }
+};
+
+U_BOOT_DRIVER(i2c_designware) = {
+ .name = "i2c_designware",
+ .id = UCLASS_I2C,
+ .of_match = designware_i2c_ids,
+ .of_to_plat = designware_i2c_of_to_plat,
+ .probe = designware_i2c_probe,
+ .priv_auto = sizeof(struct dw_i2c),
+ .remove = designware_i2c_remove,
+ .flags = DM_FLAG_OS_PREPARE,
+ .ops = &designware_i2c_ops,
+};
+
+#endif /* CONFIG_DM_I2C */
diff --git a/roms/u-boot/drivers/i2c/designware_i2c.h b/roms/u-boot/drivers/i2c/designware_i2c.h
new file mode 100644
index 000000000..9b2349a0a
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/designware_i2c.h
@@ -0,0 +1,231 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2009
+ * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
+ */
+
+#ifndef __DW_I2C_H_
+#define __DW_I2C_H_
+
+#include <clk.h>
+#include <i2c.h>
+#include <reset.h>
+#include <linux/bitops.h>
+
+struct i2c_regs {
+ u32 ic_con; /* 0x00 */
+ u32 ic_tar; /* 0x04 */
+ u32 ic_sar; /* 0x08 */
+ u32 ic_hs_maddr; /* 0x0c */
+ u32 ic_cmd_data; /* 0x10 */
+ u32 ic_ss_scl_hcnt; /* 0x14 */
+ u32 ic_ss_scl_lcnt; /* 0x18 */
+ u32 ic_fs_scl_hcnt; /* 0x1c */
+ u32 ic_fs_scl_lcnt; /* 0x20 */
+ u32 ic_hs_scl_hcnt; /* 0x24 */
+ u32 ic_hs_scl_lcnt; /* 0x28 */
+ u32 ic_intr_stat; /* 0x2c */
+ u32 ic_intr_mask; /* 0x30 */
+ u32 ic_raw_intr_stat; /* 0x34 */
+ u32 ic_rx_tl; /* 0x38 */
+ u32 ic_tx_tl; /* 0x3c */
+ u32 ic_clr_intr; /* 0x40 */
+ u32 ic_clr_rx_under; /* 0x44 */
+ u32 ic_clr_rx_over; /* 0x48 */
+ u32 ic_clr_tx_over; /* 0x4c */
+ u32 ic_clr_rd_req; /* 0x50 */
+ u32 ic_clr_tx_abrt; /* 0x54 */
+ u32 ic_clr_rx_done; /* 0x58 */
+ u32 ic_clr_activity; /* 0x5c */
+ u32 ic_clr_stop_det; /* 0x60 */
+ u32 ic_clr_start_det; /* 0x64 */
+ u32 ic_clr_gen_call; /* 0x68 */
+ u32 ic_enable; /* 0x6c */
+ u32 ic_status; /* 0x70 */
+ u32 ic_txflr; /* 0x74 */
+ u32 ic_rxflr; /* 0x78 */
+ u32 ic_sda_hold; /* 0x7c */
+ u32 ic_tx_abrt_source; /* 0x80 */
+ u32 slv_data_nak_only;
+ u32 dma_cr;
+ u32 dma_tdlr;
+ u32 dma_rdlr;
+ u32 sda_setup;
+ u32 ack_general_call;
+ u32 ic_enable_status; /* 0x9c */
+ u32 fs_spklen;
+ u32 hs_spklen;
+ u32 clr_restart_det;
+ u8 reserved[0xf4 - 0xac];
+ u32 comp_param1; /* 0xf4 */
+ u32 comp_version;
+ u32 comp_type;
+};
+
+#define IC_CLK 166666666
+#define NANO_TO_KILO 1000000
+
+/* High and low times in different speed modes (in ns) */
+#define MIN_SS_SCL_HIGHTIME 4000
+#define MIN_SS_SCL_LOWTIME 4700
+#define MIN_FS_SCL_HIGHTIME 600
+#define MIN_FS_SCL_LOWTIME 1300
+#define MIN_FP_SCL_HIGHTIME 260
+#define MIN_FP_SCL_LOWTIME 500
+#define MIN_HS_SCL_HIGHTIME 60
+#define MIN_HS_SCL_LOWTIME 160
+
+/* Worst case timeout for 1 byte is kept as 2ms */
+#define I2C_BYTE_TO (CONFIG_SYS_HZ/500)
+#define I2C_STOPDET_TO (CONFIG_SYS_HZ/500)
+#define I2C_BYTE_TO_BB (I2C_BYTE_TO * 16)
+
+/* i2c control register definitions */
+#define IC_CON_SD 0x0040
+#define IC_CON_RE 0x0020
+#define IC_CON_10BITADDRMASTER 0x0010
+#define IC_CON_10BITADDR_SLAVE 0x0008
+#define IC_CON_SPD_MSK 0x0006
+#define IC_CON_SPD_SS 0x0002
+#define IC_CON_SPD_FS 0x0004
+#define IC_CON_SPD_HS 0x0006
+#define IC_CON_MM 0x0001
+
+/* i2c target address register definitions */
+#define TAR_ADDR 0x0050
+
+/* i2c slave address register definitions */
+#define IC_SLAVE_ADDR 0x0002
+
+/* i2c data buffer and command register definitions */
+#define IC_CMD 0x0100
+#define IC_STOP 0x0200
+
+/* i2c interrupt status register definitions */
+#define IC_GEN_CALL 0x0800
+#define IC_START_DET 0x0400
+#define IC_STOP_DET 0x0200
+#define IC_ACTIVITY 0x0100
+#define IC_RX_DONE 0x0080
+#define IC_TX_ABRT 0x0040
+#define IC_RD_REQ 0x0020
+#define IC_TX_EMPTY 0x0010
+#define IC_TX_OVER 0x0008
+#define IC_RX_FULL 0x0004
+#define IC_RX_OVER 0x0002
+#define IC_RX_UNDER 0x0001
+
+/* fifo threshold register definitions */
+#define IC_TL0 0x00
+#define IC_TL1 0x01
+#define IC_TL2 0x02
+#define IC_TL3 0x03
+#define IC_TL4 0x04
+#define IC_TL5 0x05
+#define IC_TL6 0x06
+#define IC_TL7 0x07
+#define IC_RX_TL IC_TL0
+#define IC_TX_TL IC_TL0
+
+/* i2c enable register definitions */
+#define IC_ENABLE_0B 0x0001
+
+/* i2c status register definitions */
+#define IC_STATUS_SA 0x0040
+#define IC_STATUS_MA 0x0020
+#define IC_STATUS_RFF 0x0010
+#define IC_STATUS_RFNE 0x0008
+#define IC_STATUS_TFE 0x0004
+#define IC_STATUS_TFNF 0x0002
+#define IC_STATUS_ACT 0x0001
+
+#define DW_IC_COMP_PARAM_1_SPEED_MODE_HIGH (BIT(2) | BIT(3))
+#define DW_IC_COMP_PARAM_1_SPEED_MODE_MASK (BIT(2) | BIT(3))
+
+/**
+ * struct dw_scl_sda_cfg - I2C timing configuration
+ *
+ * @ss_hcnt: Standard speed high time in ns
+ * @fs_hcnt: Fast speed high time in ns
+ * @hs_hcnt: High speed high time in ns
+ * @ss_lcnt: Standard speed low time in ns
+ * @fs_lcnt: Fast speed low time in ns
+ * @hs_lcnt: High speed low time in ns
+ * @sda_hold: SDA hold time
+ */
+struct dw_scl_sda_cfg {
+ u32 ss_hcnt;
+ u32 fs_hcnt;
+ u32 hs_hcnt;
+ u32 ss_lcnt;
+ u32 fs_lcnt;
+ u32 hs_lcnt;
+ u32 sda_hold;
+};
+
+/**
+ * struct dw_i2c_speed_config - timings to use for a particular speed
+ *
+ * This holds calculated values to be written to the I2C controller. Each value
+ * is represented as a number of IC clock cycles.
+ *
+ * @scl_lcnt: Low count value for SCL
+ * @scl_hcnt: High count value for SCL
+ * @sda_hold: Data hold count
+ * @speed_mode: Speed mode being used
+ */
+struct dw_i2c_speed_config {
+ /* SCL high and low period count */
+ u16 scl_lcnt;
+ u16 scl_hcnt;
+ u32 sda_hold;
+ enum i2c_speed_mode speed_mode;
+};
+
+/**
+ * struct dw_i2c - private information for the bus
+ *
+ * @regs: Registers pointer
+ * @scl_sda_cfg: Deprecated information for x86 (should move to device tree)
+ * @resets: Resets for the I2C controller
+ * @scl_rise_time_ns: Configured SCL rise time in nanoseconds
+ * @scl_fall_time_ns: Configured SCL fall time in nanoseconds
+ * @sda_hold_time_ns: Configured SDA hold time in nanoseconds
+ * @has_spk_cnt: true if the spike-count register is present
+ * @clk: Clock input to the I2C controller
+ */
+struct dw_i2c {
+ struct i2c_regs *regs;
+ struct dw_scl_sda_cfg *scl_sda_cfg;
+ struct reset_ctl_bulk resets;
+ u32 scl_rise_time_ns;
+ u32 scl_fall_time_ns;
+ u32 sda_hold_time_ns;
+ bool has_spk_cnt;
+#if CONFIG_IS_ENABLED(CLK)
+ struct clk clk;
+#endif
+ struct dw_i2c_speed_config config;
+};
+
+extern const struct dm_i2c_ops designware_i2c_ops;
+
+int designware_i2c_probe(struct udevice *bus);
+int designware_i2c_remove(struct udevice *dev);
+int designware_i2c_of_to_plat(struct udevice *bus);
+
+/**
+ * dw_i2c_gen_speed_config() - Calculate config info from requested speed
+ *
+ * Calculate the speed config from the given @speed_hz and return it so that
+ * it can be incorporated in ACPI tables
+ *
+ * @dev: I2C bus to check
+ * @speed_hz: Requested speed in Hz
+ * @config: Returns config to use for that speed
+ * @return 0 if OK, -ve on error
+ */
+int dw_i2c_gen_speed_config(const struct udevice *dev, int speed_hz,
+ struct dw_i2c_speed_config *config);
+
+#endif /* __DW_I2C_H_ */
diff --git a/roms/u-boot/drivers/i2c/designware_i2c_pci.c b/roms/u-boot/drivers/i2c/designware_i2c_pci.c
new file mode 100644
index 000000000..9e387737b
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/designware_i2c_pci.c
@@ -0,0 +1,229 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2009
+ * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
+ * Copyright 2019 Google Inc
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <spl.h>
+#include <acpi/acpigen.h>
+#include <acpi/acpi_device.h>
+#include <asm/lpss.h>
+#include <dm/acpi.h>
+#include <dm/device-internal.h>
+#include <dm/uclass-internal.h>
+#include "designware_i2c.h"
+
+enum {
+ VANILLA = 0, /* standard I2C with no tweaks */
+ INTEL_APL, /* Apollo Lake I2C */
+};
+
+/* BayTrail HCNT/LCNT/SDA hold time */
+static struct dw_scl_sda_cfg byt_config = {
+ .ss_hcnt = 0x200,
+ .fs_hcnt = 0x55,
+ .ss_lcnt = 0x200,
+ .fs_lcnt = 0x99,
+ .sda_hold = 0x6,
+};
+
+/* Have a weak function for now - possibly should be a new uclass */
+__weak void lpss_reset_release(void *regs);
+
+static int designware_i2c_pci_of_to_plat(struct udevice *dev)
+{
+ struct dw_i2c *priv = dev_get_priv(dev);
+
+ if (spl_phase() < PHASE_SPL) {
+ u32 base;
+ int ret;
+
+ ret = dev_read_u32(dev, "early-regs", &base);
+ if (ret)
+ return log_msg_ret("early-regs", ret);
+
+ /* Set i2c base address */
+ dm_pci_write_config32(dev, PCI_BASE_ADDRESS_0, base);
+
+ /* Enable memory access and bus master */
+ dm_pci_write_config32(dev, PCI_COMMAND, PCI_COMMAND_MEMORY |
+ PCI_COMMAND_MASTER);
+ }
+
+ if (spl_phase() < PHASE_BOARD_F) {
+ /* Handle early, fixed mapping into a different address space */
+ priv->regs = (struct i2c_regs *)dm_pci_read_bar32(dev, 0);
+ } else {
+ priv->regs = (struct i2c_regs *)
+ dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
+ }
+ if (!priv->regs)
+ return -EINVAL;
+
+ /* Save base address from PCI BAR */
+ if (IS_ENABLED(CONFIG_INTEL_BAYTRAIL))
+ /* Use BayTrail specific timing values */
+ priv->scl_sda_cfg = &byt_config;
+ if (dev_get_driver_data(dev) == INTEL_APL)
+ priv->has_spk_cnt = true;
+
+ return designware_i2c_of_to_plat(dev);
+}
+
+static int designware_i2c_pci_probe(struct udevice *dev)
+{
+ struct dw_i2c *priv = dev_get_priv(dev);
+
+ if (dev_get_driver_data(dev) == INTEL_APL) {
+ /* Ensure controller is in D0 state */
+ lpss_set_power_state(dev, STATE_D0);
+
+ lpss_reset_release(priv->regs);
+ }
+
+ return designware_i2c_probe(dev);
+}
+
+static int designware_i2c_pci_bind(struct udevice *dev)
+{
+ char name[20];
+
+ if (dev_has_ofnode(dev))
+ return 0;
+
+ sprintf(name, "i2c_designware#%u", dev_seq(dev));
+ device_set_name(dev, name);
+
+ return 0;
+}
+
+/*
+ * Write ACPI object to describe speed configuration.
+ *
+ * ACPI Object: Name ("xxxx", Package () { scl_lcnt, scl_hcnt, sda_hold }
+ *
+ * SSCN: I2C_SPEED_STANDARD
+ * FMCN: I2C_SPEED_FAST
+ * FPCN: I2C_SPEED_FAST_PLUS
+ * HSCN: I2C_SPEED_HIGH
+ */
+static void dw_i2c_acpi_write_speed_config(struct acpi_ctx *ctx,
+ struct dw_i2c_speed_config *config)
+{
+ switch (config->speed_mode) {
+ case IC_SPEED_MODE_HIGH:
+ acpigen_write_name(ctx, "HSCN");
+ break;
+ case IC_SPEED_MODE_FAST_PLUS:
+ acpigen_write_name(ctx, "FPCN");
+ break;
+ case IC_SPEED_MODE_FAST:
+ acpigen_write_name(ctx, "FMCN");
+ break;
+ case IC_SPEED_MODE_STANDARD:
+ default:
+ acpigen_write_name(ctx, "SSCN");
+ }
+
+ /* Package () { scl_lcnt, scl_hcnt, sda_hold } */
+ acpigen_write_package(ctx, 3);
+ acpigen_write_word(ctx, config->scl_hcnt);
+ acpigen_write_word(ctx, config->scl_lcnt);
+ acpigen_write_dword(ctx, config->sda_hold);
+ acpigen_pop_len(ctx);
+}
+
+/*
+ * Generate I2C timing information into the SSDT for the OS driver to consume,
+ * optionally applying override values provided by the caller.
+ */
+static int dw_i2c_acpi_fill_ssdt(const struct udevice *dev,
+ struct acpi_ctx *ctx)
+{
+ struct dw_i2c_speed_config config;
+ char path[ACPI_PATH_MAX];
+ u32 speeds[4];
+ uint speed;
+ int size;
+ int ret;
+
+ /* If no device-tree node, ignore this since we assume it isn't used */
+ if (!dev_has_ofnode(dev))
+ return 0;
+
+ ret = acpi_device_path(dev, path, sizeof(path));
+ if (ret)
+ return log_msg_ret("path", ret);
+
+ size = dev_read_size(dev, "i2c,speeds");
+ if (size < 0)
+ return log_msg_ret("i2c,speeds", -EINVAL);
+
+ size /= sizeof(u32);
+ if (size > ARRAY_SIZE(speeds))
+ return log_msg_ret("array", -E2BIG);
+
+ ret = dev_read_u32_array(dev, "i2c,speeds", speeds, size);
+ if (ret)
+ return log_msg_ret("read", -E2BIG);
+
+ speed = dev_read_u32_default(dev, "clock-frequency", 100000);
+ acpigen_write_scope(ctx, path);
+ ret = dw_i2c_gen_speed_config(dev, speed, &config);
+ if (ret)
+ return log_msg_ret("config", ret);
+ dw_i2c_acpi_write_speed_config(ctx, &config);
+ acpigen_pop_len(ctx);
+
+ return 0;
+}
+
+struct acpi_ops dw_i2c_acpi_ops = {
+ .fill_ssdt = dw_i2c_acpi_fill_ssdt,
+};
+
+static const struct udevice_id designware_i2c_pci_ids[] = {
+ { .compatible = "snps,designware-i2c-pci" },
+ { .compatible = "intel,apl-i2c", .data = INTEL_APL },
+ { }
+};
+
+DM_DRIVER_ALIAS(i2c_designware_pci, intel_apl_i2c)
+
+U_BOOT_DRIVER(i2c_designware_pci) = {
+ .name = "i2c_designware_pci",
+ .id = UCLASS_I2C,
+ .of_match = designware_i2c_pci_ids,
+ .bind = designware_i2c_pci_bind,
+ .of_to_plat = designware_i2c_pci_of_to_plat,
+ .probe = designware_i2c_pci_probe,
+ .priv_auto = sizeof(struct dw_i2c),
+ .remove = designware_i2c_remove,
+ .flags = DM_FLAG_OS_PREPARE,
+ .ops = &designware_i2c_ops,
+ ACPI_OPS_PTR(&dw_i2c_acpi_ops)
+};
+
+static struct pci_device_id designware_pci_supported[] = {
+ /* Intel BayTrail has 7 I2C controller located on the PCI bus */
+ { PCI_VDEVICE(INTEL, 0x0f41) },
+ { PCI_VDEVICE(INTEL, 0x0f42) },
+ { PCI_VDEVICE(INTEL, 0x0f43) },
+ { PCI_VDEVICE(INTEL, 0x0f44) },
+ { PCI_VDEVICE(INTEL, 0x0f45) },
+ { PCI_VDEVICE(INTEL, 0x0f46) },
+ { PCI_VDEVICE(INTEL, 0x0f47) },
+ { PCI_VDEVICE(INTEL, 0x5aac), .driver_data = INTEL_APL },
+ { PCI_VDEVICE(INTEL, 0x5aae), .driver_data = INTEL_APL },
+ { PCI_VDEVICE(INTEL, 0x5ab0), .driver_data = INTEL_APL },
+ { PCI_VDEVICE(INTEL, 0x5ab2), .driver_data = INTEL_APL },
+ { PCI_VDEVICE(INTEL, 0x5ab4), .driver_data = INTEL_APL },
+ { PCI_VDEVICE(INTEL, 0x5ab6), .driver_data = INTEL_APL },
+ {},
+};
+
+U_BOOT_PCI_DEVICE(i2c_designware_pci, designware_pci_supported);
diff --git a/roms/u-boot/drivers/i2c/exynos_hs_i2c.c b/roms/u-boot/drivers/i2c/exynos_hs_i2c.c
new file mode 100644
index 000000000..39bcacc17
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/exynos_hs_i2c.c
@@ -0,0 +1,564 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2016, Google Inc
+ *
+ * (C) Copyright 2002
+ * David Mueller, ELSOFT AG, d.mueller@elsoft.ch
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+#include <log.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/pinmux.h>
+#include <asm/global_data.h>
+#include <linux/delay.h>
+#include "s3c24x0_i2c.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* HSI2C-specific register description */
+
+/* I2C_CTL Register bits */
+#define HSI2C_FUNC_MODE_I2C (1u << 0)
+#define HSI2C_MASTER (1u << 3)
+#define HSI2C_RXCHON (1u << 6) /* Write/Send */
+#define HSI2C_TXCHON (1u << 7) /* Read/Receive */
+#define HSI2C_SW_RST (1u << 31)
+
+/* I2C_FIFO_CTL Register bits */
+#define HSI2C_RXFIFO_EN (1u << 0)
+#define HSI2C_TXFIFO_EN (1u << 1)
+#define HSI2C_TXFIFO_TRIGGER_LEVEL (0x20 << 16)
+#define HSI2C_RXFIFO_TRIGGER_LEVEL (0x20 << 4)
+
+/* I2C_TRAILING_CTL Register bits */
+#define HSI2C_TRAILING_COUNT (0xff)
+
+/* I2C_INT_EN Register bits */
+#define HSI2C_TX_UNDERRUN_EN (1u << 2)
+#define HSI2C_TX_OVERRUN_EN (1u << 3)
+#define HSI2C_RX_UNDERRUN_EN (1u << 4)
+#define HSI2C_RX_OVERRUN_EN (1u << 5)
+#define HSI2C_INT_TRAILING_EN (1u << 6)
+#define HSI2C_INT_I2C_EN (1u << 9)
+
+#define HSI2C_INT_ERROR_MASK (HSI2C_TX_UNDERRUN_EN |\
+ HSI2C_TX_OVERRUN_EN |\
+ HSI2C_RX_UNDERRUN_EN |\
+ HSI2C_RX_OVERRUN_EN |\
+ HSI2C_INT_TRAILING_EN)
+
+/* I2C_CONF Register bits */
+#define HSI2C_AUTO_MODE (1u << 31)
+#define HSI2C_10BIT_ADDR_MODE (1u << 30)
+#define HSI2C_HS_MODE (1u << 29)
+
+/* I2C_AUTO_CONF Register bits */
+#define HSI2C_READ_WRITE (1u << 16)
+#define HSI2C_STOP_AFTER_TRANS (1u << 17)
+#define HSI2C_MASTER_RUN (1u << 31)
+
+/* I2C_TIMEOUT Register bits */
+#define HSI2C_TIMEOUT_EN (1u << 31)
+
+/* I2C_TRANS_STATUS register bits */
+#define HSI2C_MASTER_BUSY (1u << 17)
+#define HSI2C_SLAVE_BUSY (1u << 16)
+#define HSI2C_TIMEOUT_AUTO (1u << 4)
+#define HSI2C_NO_DEV (1u << 3)
+#define HSI2C_NO_DEV_ACK (1u << 2)
+#define HSI2C_TRANS_ABORT (1u << 1)
+#define HSI2C_TRANS_SUCCESS (1u << 0)
+#define HSI2C_TRANS_ERROR_MASK (HSI2C_TIMEOUT_AUTO |\
+ HSI2C_NO_DEV | HSI2C_NO_DEV_ACK |\
+ HSI2C_TRANS_ABORT)
+#define HSI2C_TRANS_FINISHED_MASK (HSI2C_TRANS_ERROR_MASK | HSI2C_TRANS_SUCCESS)
+
+
+/* I2C_FIFO_STAT Register bits */
+#define HSI2C_RX_FIFO_EMPTY (1u << 24)
+#define HSI2C_RX_FIFO_FULL (1u << 23)
+#define HSI2C_TX_FIFO_EMPTY (1u << 8)
+#define HSI2C_TX_FIFO_FULL (1u << 7)
+#define HSI2C_RX_FIFO_LEVEL(x) (((x) >> 16) & 0x7f)
+#define HSI2C_TX_FIFO_LEVEL(x) ((x) & 0x7f)
+
+#define HSI2C_SLV_ADDR_MAS(x) ((x & 0x3ff) << 10)
+
+#define HSI2C_TIMEOUT_US 10000 /* 10 ms, finer granularity */
+
+/*
+ * Wait for transfer completion.
+ *
+ * This function reads the interrupt status register waiting for the INT_I2C
+ * bit to be set, which indicates copletion of a transaction.
+ *
+ * @param i2c: pointer to the appropriate register bank
+ *
+ * @return: I2C_OK in case of successful completion, I2C_NOK_TIMEOUT in case
+ * the status bits do not get set in time, or an approrpiate error
+ * value in case of transfer errors.
+ */
+static int hsi2c_wait_for_trx(struct exynos5_hsi2c *i2c)
+{
+ int i = HSI2C_TIMEOUT_US;
+
+ while (i-- > 0) {
+ u32 int_status = readl(&i2c->usi_int_stat);
+
+ if (int_status & HSI2C_INT_I2C_EN) {
+ u32 trans_status = readl(&i2c->usi_trans_status);
+
+ /* Deassert pending interrupt. */
+ writel(int_status, &i2c->usi_int_stat);
+
+ if (trans_status & HSI2C_NO_DEV_ACK) {
+ debug("%s: no ACK from device\n", __func__);
+ return I2C_NACK;
+ }
+ if (trans_status & HSI2C_NO_DEV) {
+ debug("%s: no device\n", __func__);
+ return I2C_NOK;
+ }
+ if (trans_status & HSI2C_TRANS_ABORT) {
+ debug("%s: arbitration lost\n", __func__);
+ return I2C_NOK_LA;
+ }
+ if (trans_status & HSI2C_TIMEOUT_AUTO) {
+ debug("%s: device timed out\n", __func__);
+ return I2C_NOK_TOUT;
+ }
+ return I2C_OK;
+ }
+ udelay(1);
+ }
+ debug("%s: transaction timeout!\n", __func__);
+ return I2C_NOK_TOUT;
+}
+
+static int hsi2c_get_clk_details(struct s3c24x0_i2c_bus *i2c_bus)
+{
+ struct exynos5_hsi2c *hsregs = i2c_bus->hsregs;
+ ulong clkin;
+ unsigned int op_clk = i2c_bus->clock_frequency;
+ unsigned int i = 0, utemp0 = 0, utemp1 = 0;
+ unsigned int t_ftl_cycle;
+
+#if (defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5)
+ clkin = get_i2c_clk();
+#else
+ clkin = get_PCLK();
+#endif
+ /* FPCLK / FI2C =
+ * (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + 8 + 2 * FLT_CYCLE
+ * uTemp0 = (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2)
+ * uTemp1 = (TSCLK_L + TSCLK_H + 2)
+ * uTemp2 = TSCLK_L + TSCLK_H
+ */
+ t_ftl_cycle = (readl(&hsregs->usi_conf) >> 16) & 0x7;
+ utemp0 = (clkin / op_clk) - 8 - 2 * t_ftl_cycle;
+
+ /* CLK_DIV max is 256 */
+ for (i = 0; i < 256; i++) {
+ utemp1 = utemp0 / (i + 1);
+ if ((utemp1 < 512) && (utemp1 > 4)) {
+ i2c_bus->clk_cycle = utemp1 - 2;
+ i2c_bus->clk_div = i;
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+static void hsi2c_ch_init(struct s3c24x0_i2c_bus *i2c_bus)
+{
+ struct exynos5_hsi2c *hsregs = i2c_bus->hsregs;
+ unsigned int t_sr_release;
+ unsigned int n_clkdiv;
+ unsigned int t_start_su, t_start_hd;
+ unsigned int t_stop_su;
+ unsigned int t_data_su, t_data_hd;
+ unsigned int t_scl_l, t_scl_h;
+ u32 i2c_timing_s1;
+ u32 i2c_timing_s2;
+ u32 i2c_timing_s3;
+ u32 i2c_timing_sla;
+
+ n_clkdiv = i2c_bus->clk_div;
+ t_scl_l = i2c_bus->clk_cycle / 2;
+ t_scl_h = i2c_bus->clk_cycle / 2;
+ t_start_su = t_scl_l;
+ t_start_hd = t_scl_l;
+ t_stop_su = t_scl_l;
+ t_data_su = t_scl_l / 2;
+ t_data_hd = t_scl_l / 2;
+ t_sr_release = i2c_bus->clk_cycle;
+
+ i2c_timing_s1 = t_start_su << 24 | t_start_hd << 16 | t_stop_su << 8;
+ i2c_timing_s2 = t_data_su << 24 | t_scl_l << 8 | t_scl_h << 0;
+ i2c_timing_s3 = n_clkdiv << 16 | t_sr_release << 0;
+ i2c_timing_sla = t_data_hd << 0;
+
+ writel(HSI2C_TRAILING_COUNT, &hsregs->usi_trailing_ctl);
+
+ /* Clear to enable Timeout */
+ clrsetbits_le32(&hsregs->usi_timeout, HSI2C_TIMEOUT_EN, 0);
+
+ /* set AUTO mode */
+ writel(readl(&hsregs->usi_conf) | HSI2C_AUTO_MODE, &hsregs->usi_conf);
+
+ /* Enable completion conditions' reporting. */
+ writel(HSI2C_INT_I2C_EN, &hsregs->usi_int_en);
+
+ /* Enable FIFOs */
+ writel(HSI2C_RXFIFO_EN | HSI2C_TXFIFO_EN, &hsregs->usi_fifo_ctl);
+
+ /* Currently operating in Fast speed mode. */
+ writel(i2c_timing_s1, &hsregs->usi_timing_fs1);
+ writel(i2c_timing_s2, &hsregs->usi_timing_fs2);
+ writel(i2c_timing_s3, &hsregs->usi_timing_fs3);
+ writel(i2c_timing_sla, &hsregs->usi_timing_sla);
+}
+
+/* SW reset for the high speed bus */
+static void exynos5_i2c_reset(struct s3c24x0_i2c_bus *i2c_bus)
+{
+ struct exynos5_hsi2c *i2c = i2c_bus->hsregs;
+ u32 i2c_ctl;
+
+ /* Set and clear the bit for reset */
+ i2c_ctl = readl(&i2c->usi_ctl);
+ i2c_ctl |= HSI2C_SW_RST;
+ writel(i2c_ctl, &i2c->usi_ctl);
+
+ i2c_ctl = readl(&i2c->usi_ctl);
+ i2c_ctl &= ~HSI2C_SW_RST;
+ writel(i2c_ctl, &i2c->usi_ctl);
+
+ /* Initialize the configure registers */
+ hsi2c_ch_init(i2c_bus);
+}
+
+/*
+ * Poll the appropriate bit of the fifo status register until the interface is
+ * ready to process the next byte or timeout expires.
+ *
+ * In addition to the FIFO status register this function also polls the
+ * interrupt status register to be able to detect unexpected transaction
+ * completion.
+ *
+ * When FIFO is ready to process the next byte, this function returns I2C_OK.
+ * If in course of polling the INT_I2C assertion is detected, the function
+ * returns I2C_NOK. If timeout happens before any of the above conditions is
+ * met - the function returns I2C_NOK_TOUT;
+
+ * @param i2c: pointer to the appropriate i2c register bank.
+ * @param rx_transfer: set to True if the receive transaction is in progress.
+ * @return: as described above.
+ */
+static unsigned hsi2c_poll_fifo(struct exynos5_hsi2c *i2c, bool rx_transfer)
+{
+ u32 fifo_bit = rx_transfer ? HSI2C_RX_FIFO_EMPTY : HSI2C_TX_FIFO_FULL;
+ int i = HSI2C_TIMEOUT_US;
+
+ while (readl(&i2c->usi_fifo_stat) & fifo_bit) {
+ if (readl(&i2c->usi_int_stat) & HSI2C_INT_I2C_EN) {
+ /*
+ * There is a chance that assertion of
+ * HSI2C_INT_I2C_EN and deassertion of
+ * HSI2C_RX_FIFO_EMPTY happen simultaneously. Let's
+ * give FIFO status priority and check it one more
+ * time before reporting interrupt. The interrupt will
+ * be reported next time this function is called.
+ */
+ if (rx_transfer &&
+ !(readl(&i2c->usi_fifo_stat) & fifo_bit))
+ break;
+ return I2C_NOK;
+ }
+ if (!i--) {
+ debug("%s: FIFO polling timeout!\n", __func__);
+ return I2C_NOK_TOUT;
+ }
+ udelay(1);
+ }
+ return I2C_OK;
+}
+
+/*
+ * Preapre hsi2c transaction, either read or write.
+ *
+ * Set up transfer as described in section 27.5.1.2 'I2C Channel Auto Mode' of
+ * the 5420 UM.
+ *
+ * @param i2c: pointer to the appropriate i2c register bank.
+ * @param chip: slave address on the i2c bus (with read/write bit exlcuded)
+ * @param len: number of bytes expected to be sent or received
+ * @param rx_transfer: set to true for receive transactions
+ * @param: issue_stop: set to true if i2c stop condition should be generated
+ * after this transaction.
+ * @return: I2C_NOK_TOUT in case the bus remained busy for HSI2C_TIMEOUT_US,
+ * I2C_OK otherwise.
+ */
+static int hsi2c_prepare_transaction(struct exynos5_hsi2c *i2c,
+ u8 chip,
+ u16 len,
+ bool rx_transfer,
+ bool issue_stop)
+{
+ u32 conf;
+
+ conf = len | HSI2C_MASTER_RUN;
+
+ if (issue_stop)
+ conf |= HSI2C_STOP_AFTER_TRANS;
+
+ /* Clear to enable Timeout */
+ writel(readl(&i2c->usi_timeout) & ~HSI2C_TIMEOUT_EN, &i2c->usi_timeout);
+
+ /* Set slave address */
+ writel(HSI2C_SLV_ADDR_MAS(chip), &i2c->i2c_addr);
+
+ if (rx_transfer) {
+ /* i2c master, read transaction */
+ writel((HSI2C_RXCHON | HSI2C_FUNC_MODE_I2C | HSI2C_MASTER),
+ &i2c->usi_ctl);
+
+ /* read up to len bytes, stop after transaction is finished */
+ writel(conf | HSI2C_READ_WRITE, &i2c->usi_auto_conf);
+ } else {
+ /* i2c master, write transaction */
+ writel((HSI2C_TXCHON | HSI2C_FUNC_MODE_I2C | HSI2C_MASTER),
+ &i2c->usi_ctl);
+
+ /* write up to len bytes, stop after transaction is finished */
+ writel(conf, &i2c->usi_auto_conf);
+ }
+
+ /* Reset all pending interrupt status bits we care about, if any */
+ writel(HSI2C_INT_I2C_EN, &i2c->usi_int_stat);
+
+ return I2C_OK;
+}
+
+/*
+ * Wait while i2c bus is settling down (mostly stop gets completed).
+ */
+static int hsi2c_wait_while_busy(struct exynos5_hsi2c *i2c)
+{
+ int i = HSI2C_TIMEOUT_US;
+
+ while (readl(&i2c->usi_trans_status) & HSI2C_MASTER_BUSY) {
+ if (!i--) {
+ debug("%s: bus busy\n", __func__);
+ return I2C_NOK_TOUT;
+ }
+ udelay(1);
+ }
+ return I2C_OK;
+}
+
+static int hsi2c_write(struct exynos5_hsi2c *i2c,
+ unsigned char chip,
+ unsigned char addr[],
+ unsigned char alen,
+ unsigned char data[],
+ unsigned short len,
+ bool issue_stop)
+{
+ int i, rv = 0;
+
+ if (!(len + alen)) {
+ /* Writes of zero length not supported in auto mode. */
+ debug("%s: zero length writes not supported\n", __func__);
+ return I2C_NOK;
+ }
+
+ rv = hsi2c_prepare_transaction
+ (i2c, chip, len + alen, false, issue_stop);
+ if (rv != I2C_OK)
+ return rv;
+
+ /* Move address, if any, and the data, if any, into the FIFO. */
+ for (i = 0; i < alen; i++) {
+ rv = hsi2c_poll_fifo(i2c, false);
+ if (rv != I2C_OK) {
+ debug("%s: address write failed\n", __func__);
+ goto write_error;
+ }
+ writel(addr[i], &i2c->usi_txdata);
+ }
+
+ for (i = 0; i < len; i++) {
+ rv = hsi2c_poll_fifo(i2c, false);
+ if (rv != I2C_OK) {
+ debug("%s: data write failed\n", __func__);
+ goto write_error;
+ }
+ writel(data[i], &i2c->usi_txdata);
+ }
+
+ rv = hsi2c_wait_for_trx(i2c);
+
+ write_error:
+ if (issue_stop) {
+ int tmp_ret = hsi2c_wait_while_busy(i2c);
+ if (rv == I2C_OK)
+ rv = tmp_ret;
+ }
+
+ writel(HSI2C_FUNC_MODE_I2C, &i2c->usi_ctl); /* done */
+ return rv;
+}
+
+static int hsi2c_read(struct exynos5_hsi2c *i2c,
+ unsigned char chip,
+ unsigned char addr[],
+ unsigned char alen,
+ unsigned char data[],
+ unsigned short len)
+{
+ int i, rv, tmp_ret;
+ bool drop_data = false;
+
+ if (!len) {
+ /* Reads of zero length not supported in auto mode. */
+ debug("%s: zero length read adjusted\n", __func__);
+ drop_data = true;
+ len = 1;
+ }
+
+ if (alen) {
+ /* Internal register adress needs to be written first. */
+ rv = hsi2c_write(i2c, chip, addr, alen, NULL, 0, false);
+ if (rv != I2C_OK)
+ return rv;
+ }
+
+ rv = hsi2c_prepare_transaction(i2c, chip, len, true, true);
+
+ if (rv != I2C_OK)
+ return rv;
+
+ for (i = 0; i < len; i++) {
+ rv = hsi2c_poll_fifo(i2c, true);
+ if (rv != I2C_OK)
+ goto read_err;
+ if (drop_data)
+ continue;
+ data[i] = readl(&i2c->usi_rxdata);
+ }
+
+ rv = hsi2c_wait_for_trx(i2c);
+
+ read_err:
+ tmp_ret = hsi2c_wait_while_busy(i2c);
+ if (rv == I2C_OK)
+ rv = tmp_ret;
+
+ writel(HSI2C_FUNC_MODE_I2C, &i2c->usi_ctl); /* done */
+ return rv;
+}
+
+static int exynos_hs_i2c_xfer(struct udevice *dev, struct i2c_msg *msg,
+ int nmsgs)
+{
+ struct s3c24x0_i2c_bus *i2c_bus = dev_get_priv(dev);
+ struct exynos5_hsi2c *hsregs = i2c_bus->hsregs;
+ int ret;
+
+ for (; nmsgs > 0; nmsgs--, msg++) {
+ if (msg->flags & I2C_M_RD) {
+ ret = hsi2c_read(hsregs, msg->addr, 0, 0, msg->buf,
+ msg->len);
+ } else {
+ ret = hsi2c_write(hsregs, msg->addr, 0, 0, msg->buf,
+ msg->len, true);
+ }
+ if (ret) {
+ exynos5_i2c_reset(i2c_bus);
+ return -EREMOTEIO;
+ }
+ }
+
+ return 0;
+}
+
+static int s3c24x0_i2c_set_bus_speed(struct udevice *dev, unsigned int speed)
+{
+ struct s3c24x0_i2c_bus *i2c_bus = dev_get_priv(dev);
+
+ i2c_bus->clock_frequency = speed;
+
+ if (hsi2c_get_clk_details(i2c_bus))
+ return -EFAULT;
+ hsi2c_ch_init(i2c_bus);
+
+ return 0;
+}
+
+static int s3c24x0_i2c_probe(struct udevice *dev, uint chip, uint chip_flags)
+{
+ struct s3c24x0_i2c_bus *i2c_bus = dev_get_priv(dev);
+ uchar buf[1];
+ int ret;
+
+ buf[0] = 0;
+
+ /*
+ * What is needed is to send the chip address and verify that the
+ * address was <ACK>ed (i.e. there was a chip at that address which
+ * drove the data line low).
+ */
+ ret = hsi2c_read(i2c_bus->hsregs, chip, 0, 0, buf, 1);
+
+ return ret != I2C_OK;
+}
+
+static int s3c_i2c_of_to_plat(struct udevice *dev)
+{
+ const void *blob = gd->fdt_blob;
+ struct s3c24x0_i2c_bus *i2c_bus = dev_get_priv(dev);
+ int node;
+
+ node = dev_of_offset(dev);
+
+ i2c_bus->hsregs = dev_read_addr_ptr(dev);
+
+ i2c_bus->id = pinmux_decode_periph_id(blob, node);
+
+ i2c_bus->clock_frequency =
+ dev_read_u32_default(dev, "clock-frequency",
+ I2C_SPEED_STANDARD_RATE);
+ i2c_bus->node = node;
+ i2c_bus->bus_num = dev_seq(dev);
+
+ exynos_pinmux_config(i2c_bus->id, PINMUX_FLAG_HS_MODE);
+
+ i2c_bus->active = true;
+
+ return 0;
+}
+
+static const struct dm_i2c_ops exynos_hs_i2c_ops = {
+ .xfer = exynos_hs_i2c_xfer,
+ .probe_chip = s3c24x0_i2c_probe,
+ .set_bus_speed = s3c24x0_i2c_set_bus_speed,
+};
+
+static const struct udevice_id exynos_hs_i2c_ids[] = {
+ { .compatible = "samsung,exynos5-hsi2c" },
+ { }
+};
+
+U_BOOT_DRIVER(hs_i2c) = {
+ .name = "i2c_s3c_hs",
+ .id = UCLASS_I2C,
+ .of_match = exynos_hs_i2c_ids,
+ .of_to_plat = s3c_i2c_of_to_plat,
+ .priv_auto = sizeof(struct s3c24x0_i2c_bus),
+ .ops = &exynos_hs_i2c_ops,
+};
diff --git a/roms/u-boot/drivers/i2c/fsl_i2c.c b/roms/u-boot/drivers/i2c/fsl_i2c.c
new file mode 100644
index 000000000..2200303ea
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/fsl_i2c.c
@@ -0,0 +1,658 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2006,2009 Freescale Semiconductor, Inc.
+ *
+ * 2012, Heiko Schocher, DENX Software Engineering, hs@denx.de.
+ * Changes for multibus/multiadapter I2C support.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <i2c.h> /* Functional interface */
+#include <log.h>
+#include <time.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <asm/fsl_i2c.h> /* HW definitions */
+#include <clk.h>
+#include <dm.h>
+#include <mapmem.h>
+#include <linux/delay.h>
+
+/* The maximum number of microseconds we will wait until another master has
+ * released the bus. If not defined in the board header file, then use a
+ * generic value.
+ */
+#ifndef CONFIG_I2C_MBB_TIMEOUT
+#define CONFIG_I2C_MBB_TIMEOUT 100000
+#endif
+
+/* The maximum number of microseconds we will wait for a read or write
+ * operation to complete. If not defined in the board header file, then use a
+ * generic value.
+ */
+#ifndef CONFIG_I2C_TIMEOUT
+#define CONFIG_I2C_TIMEOUT 100000
+#endif
+
+#define I2C_READ_BIT 1
+#define I2C_WRITE_BIT 0
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if !CONFIG_IS_ENABLED(DM_I2C)
+static const struct fsl_i2c_base *i2c_base[4] = {
+ (struct fsl_i2c_base *)(CONFIG_SYS_IMMR + CONFIG_SYS_FSL_I2C_OFFSET),
+#ifdef CONFIG_SYS_FSL_I2C2_OFFSET
+ (struct fsl_i2c_base *)(CONFIG_SYS_IMMR + CONFIG_SYS_FSL_I2C2_OFFSET),
+#endif
+#ifdef CONFIG_SYS_FSL_I2C3_OFFSET
+ (struct fsl_i2c_base *)(CONFIG_SYS_IMMR + CONFIG_SYS_FSL_I2C3_OFFSET),
+#endif
+#ifdef CONFIG_SYS_FSL_I2C4_OFFSET
+ (struct fsl_i2c_base *)(CONFIG_SYS_IMMR + CONFIG_SYS_FSL_I2C4_OFFSET)
+#endif
+};
+#endif
+
+/* I2C speed map for a DFSR value of 1 */
+
+#ifdef __M68K__
+/*
+ * Map I2C frequency dividers to FDR and DFSR values
+ *
+ * This structure is used to define the elements of a table that maps I2C
+ * frequency divider (I2C clock rate divided by I2C bus speed) to a value to be
+ * programmed into the Frequency Divider Ratio (FDR) and Digital Filter
+ * Sampling Rate (DFSR) registers.
+ *
+ * The actual table should be defined in the board file, and it must be called
+ * fsl_i2c_speed_map[].
+ *
+ * The last entry of the table must have a value of {-1, X}, where X is same
+ * FDR/DFSR values as the second-to-last entry. This guarantees that any
+ * search through the array will always find a match.
+ *
+ * The values of the divider must be in increasing numerical order, i.e.
+ * fsl_i2c_speed_map[x+1].divider > fsl_i2c_speed_map[x].divider.
+ *
+ * For this table, the values are based on a value of 1 for the DFSR
+ * register. See the application note AN2919 "Determining the I2C Frequency
+ * Divider Ratio for SCL"
+ *
+ * ColdFire I2C frequency dividers for FDR values are different from
+ * PowerPC. The protocol to use the I2C module is still the same.
+ * A different table is defined and are based on MCF5xxx user manual.
+ *
+ */
+static const struct {
+ unsigned short divider;
+ u8 fdr;
+} fsl_i2c_speed_map[] = {
+ {20, 32}, {22, 33}, {24, 34}, {26, 35},
+ {28, 0}, {28, 36}, {30, 1}, {32, 37},
+ {34, 2}, {36, 38}, {40, 3}, {40, 39},
+ {44, 4}, {48, 5}, {48, 40}, {56, 6},
+ {56, 41}, {64, 42}, {68, 7}, {72, 43},
+ {80, 8}, {80, 44}, {88, 9}, {96, 41},
+ {104, 10}, {112, 42}, {128, 11}, {128, 43},
+ {144, 12}, {160, 13}, {160, 48}, {192, 14},
+ {192, 49}, {224, 50}, {240, 15}, {256, 51},
+ {288, 16}, {320, 17}, {320, 52}, {384, 18},
+ {384, 53}, {448, 54}, {480, 19}, {512, 55},
+ {576, 20}, {640, 21}, {640, 56}, {768, 22},
+ {768, 57}, {960, 23}, {896, 58}, {1024, 59},
+ {1152, 24}, {1280, 25}, {1280, 60}, {1536, 26},
+ {1536, 61}, {1792, 62}, {1920, 27}, {2048, 63},
+ {2304, 28}, {2560, 29}, {3072, 30}, {3840, 31},
+ {-1, 31}
+};
+#endif
+
+/**
+ * Set the I2C bus speed for a given I2C device
+ *
+ * @param base: the I2C device registers
+ * @i2c_clk: I2C bus clock frequency
+ * @speed: the desired speed of the bus
+ *
+ * The I2C device must be stopped before calling this function.
+ *
+ * The return value is the actual bus speed that is set.
+ */
+static uint set_i2c_bus_speed(const struct fsl_i2c_base *base,
+ uint i2c_clk, uint speed)
+{
+ ushort divider = min(i2c_clk / speed, (uint)USHRT_MAX);
+
+ /*
+ * We want to choose an FDR/DFSR that generates an I2C bus speed that
+ * is equal to or lower than the requested speed. That means that we
+ * want the first divider that is equal to or greater than the
+ * calculated divider.
+ */
+#ifdef __PPC__
+ u8 dfsr, fdr = 0x31; /* Default if no FDR found */
+ /* a, b and dfsr matches identifiers A,B and C respectively in AN2919 */
+ ushort a, b, ga, gb;
+ ulong c_div, est_div;
+
+#ifdef CONFIG_FSL_I2C_CUSTOM_DFSR
+ dfsr = CONFIG_FSL_I2C_CUSTOM_DFSR;
+#else
+ /* Condition 1: dfsr <= 50/T */
+ dfsr = (5 * (i2c_clk / 1000)) / 100000;
+#endif
+#ifdef CONFIG_FSL_I2C_CUSTOM_FDR
+ fdr = CONFIG_FSL_I2C_CUSTOM_FDR;
+ speed = i2c_clk / divider; /* Fake something */
+#else
+ debug("Requested speed:%d, i2c_clk:%d\n", speed, i2c_clk);
+ if (!dfsr)
+ dfsr = 1;
+
+ est_div = ~0;
+ for (ga = 0x4, a = 10; a <= 30; ga++, a += 2) {
+ for (gb = 0; gb < 8; gb++) {
+ b = 16 << gb;
+ c_div = b * (a + ((3 * dfsr) / b) * 2);
+ if (c_div > divider && c_div < est_div) {
+ ushort bin_gb, bin_ga;
+
+ est_div = c_div;
+ bin_gb = gb << 2;
+ bin_ga = (ga & 0x3) | ((ga & 0x4) << 3);
+ fdr = bin_gb | bin_ga;
+ speed = i2c_clk / est_div;
+
+ debug("FDR: 0x%.2x, ", fdr);
+ debug("div: %ld, ", est_div);
+ debug("ga: 0x%x, gb: 0x%x, ", ga, gb);
+ debug("a: %d, b: %d, speed: %d\n", a, b, speed);
+
+ /* Condition 2 not accounted for */
+ debug("Tr <= %d ns\n",
+ (b - 3 * dfsr) * 1000000 /
+ (i2c_clk / 1000));
+ }
+ }
+ if (a == 20)
+ a += 2;
+ if (a == 24)
+ a += 4;
+ }
+ debug("divider: %d, est_div: %ld, DFSR: %d\n", divider, est_div, dfsr);
+ debug("FDR: 0x%.2x, speed: %d\n", fdr, speed);
+#endif
+ writeb(dfsr, &base->dfsrr); /* set default filter */
+ writeb(fdr, &base->fdr); /* set bus speed */
+#else
+ uint i;
+
+ for (i = 0; i < ARRAY_SIZE(fsl_i2c_speed_map); i++)
+ if (fsl_i2c_speed_map[i].divider >= divider) {
+ u8 fdr;
+
+ fdr = fsl_i2c_speed_map[i].fdr;
+ speed = i2c_clk / fsl_i2c_speed_map[i].divider;
+ writeb(fdr, &base->fdr); /* set bus speed */
+
+ break;
+ }
+#endif
+ return speed;
+}
+
+#if !CONFIG_IS_ENABLED(DM_I2C)
+static uint get_i2c_clock(int bus)
+{
+ if (bus)
+ return gd->arch.i2c2_clk; /* I2C2 clock */
+ else
+ return gd->arch.i2c1_clk; /* I2C1 clock */
+}
+#endif
+
+static int fsl_i2c_fixup(const struct fsl_i2c_base *base)
+{
+ const unsigned long long timeout = usec2ticks(CONFIG_I2C_MBB_TIMEOUT);
+ unsigned long long timeval = 0;
+ int ret = -1;
+ uint flags = 0;
+
+#ifdef CONFIG_SYS_FSL_ERRATUM_I2C_A004447
+ uint svr = get_svr();
+
+ if ((SVR_SOC_VER(svr) == SVR_8548 && IS_SVR_REV(svr, 3, 1)) ||
+ (SVR_REV(svr) <= CONFIG_SYS_FSL_A004447_SVR_REV))
+ flags = I2C_CR_BIT6;
+#endif
+
+ writeb(I2C_CR_MEN | I2C_CR_MSTA, &base->cr);
+
+ timeval = get_ticks();
+ while (!(readb(&base->sr) & I2C_SR_MBB)) {
+ if ((get_ticks() - timeval) > timeout)
+ goto err;
+ }
+
+ if (readb(&base->sr) & I2C_SR_MAL) {
+ /* SDA is stuck low */
+ writeb(0, &base->cr);
+ udelay(100);
+ writeb(I2C_CR_MSTA | flags, &base->cr);
+ writeb(I2C_CR_MEN | I2C_CR_MSTA | flags, &base->cr);
+ }
+
+ readb(&base->dr);
+
+ timeval = get_ticks();
+ while (!(readb(&base->sr) & I2C_SR_MIF)) {
+ if ((get_ticks() - timeval) > timeout)
+ goto err;
+ }
+ ret = 0;
+
+err:
+ writeb(I2C_CR_MEN | flags, &base->cr);
+ writeb(0, &base->sr);
+ udelay(100);
+
+ return ret;
+}
+
+static void __i2c_init(const struct fsl_i2c_base *base, int speed, int
+ slaveadd, int i2c_clk, int busnum)
+{
+ const unsigned long long timeout = usec2ticks(CONFIG_I2C_MBB_TIMEOUT);
+ unsigned long long timeval;
+
+#ifdef CONFIG_SYS_I2C_INIT_BOARD
+ /* Call board specific i2c bus reset routine before accessing the
+ * environment, which might be in a chip on that bus. For details
+ * about this problem see doc/I2C_Edge_Conditions.
+ */
+ i2c_init_board();
+#endif
+ writeb(0, &base->cr); /* stop I2C controller */
+ udelay(5); /* let it shutdown in peace */
+ set_i2c_bus_speed(base, i2c_clk, speed);
+ writeb(slaveadd << 1, &base->adr);/* write slave address */
+ writeb(0x0, &base->sr); /* clear status register */
+ writeb(I2C_CR_MEN, &base->cr); /* start I2C controller */
+
+ timeval = get_ticks();
+ while (readb(&base->sr) & I2C_SR_MBB) {
+ if ((get_ticks() - timeval) < timeout)
+ continue;
+
+ if (fsl_i2c_fixup(base))
+ debug("i2c_init: BUS#%d failed to init\n",
+ busnum);
+
+ break;
+ }
+}
+
+static int i2c_wait4bus(const struct fsl_i2c_base *base)
+{
+ unsigned long long timeval = get_ticks();
+ const unsigned long long timeout = usec2ticks(CONFIG_I2C_MBB_TIMEOUT);
+
+ while (readb(&base->sr) & I2C_SR_MBB) {
+ if ((get_ticks() - timeval) > timeout)
+ return -1;
+ }
+
+ return 0;
+}
+
+static int i2c_wait(const struct fsl_i2c_base *base, int write)
+{
+ u32 csr;
+ unsigned long long timeval = get_ticks();
+ const unsigned long long timeout = usec2ticks(CONFIG_I2C_TIMEOUT);
+
+ do {
+ csr = readb(&base->sr);
+ if (!(csr & I2C_SR_MIF))
+ continue;
+ /* Read again to allow register to stabilise */
+ csr = readb(&base->sr);
+
+ writeb(0x0, &base->sr);
+
+ if (csr & I2C_SR_MAL) {
+ debug("%s: MAL\n", __func__);
+ return -1;
+ }
+
+ if (!(csr & I2C_SR_MCF)) {
+ debug("%s: unfinished\n", __func__);
+ return -1;
+ }
+
+ if (write == I2C_WRITE_BIT && (csr & I2C_SR_RXAK)) {
+ debug("%s: No RXACK\n", __func__);
+ return -1;
+ }
+
+ return 0;
+ } while ((get_ticks() - timeval) < timeout);
+
+ debug("%s: timed out\n", __func__);
+ return -1;
+}
+
+static int i2c_write_addr(const struct fsl_i2c_base *base, u8 dev,
+ u8 dir, int rsta)
+{
+ writeb(I2C_CR_MEN | I2C_CR_MSTA | I2C_CR_MTX
+ | (rsta ? I2C_CR_RSTA : 0),
+ &base->cr);
+
+ writeb((dev << 1) | dir, &base->dr);
+
+ if (i2c_wait(base, I2C_WRITE_BIT) < 0)
+ return 0;
+
+ return 1;
+}
+
+static int __i2c_write_data(const struct fsl_i2c_base *base, u8 *data,
+ int length)
+{
+ int i;
+
+ for (i = 0; i < length; i++) {
+ writeb(data[i], &base->dr);
+
+ if (i2c_wait(base, I2C_WRITE_BIT) < 0)
+ break;
+ }
+
+ return i;
+}
+
+static int __i2c_read_data(const struct fsl_i2c_base *base, u8 *data,
+ int length)
+{
+ int i;
+
+ writeb(I2C_CR_MEN | I2C_CR_MSTA | ((length == 1) ? I2C_CR_TXAK : 0),
+ &base->cr);
+
+ /* dummy read */
+ readb(&base->dr);
+
+ for (i = 0; i < length; i++) {
+ if (i2c_wait(base, I2C_READ_BIT) < 0)
+ break;
+
+ /* Generate ack on last next to last byte */
+ if (i == length - 2)
+ writeb(I2C_CR_MEN | I2C_CR_MSTA | I2C_CR_TXAK,
+ &base->cr);
+
+ /* Do not generate stop on last byte */
+ if (i == length - 1)
+ writeb(I2C_CR_MEN | I2C_CR_MSTA | I2C_CR_MTX,
+ &base->cr);
+
+ data[i] = readb(&base->dr);
+ }
+
+ return i;
+}
+
+static int __i2c_read(const struct fsl_i2c_base *base, u8 chip_addr, u8 *offset,
+ int olen, u8 *data, int dlen)
+{
+ int ret = -1; /* signal error */
+
+ if (i2c_wait4bus(base) < 0)
+ return -1;
+
+ /* Some drivers use offset lengths in excess of 4 bytes. These drivers
+ * adhere to the following convention:
+ * - the offset length is passed as negative (that is, the absolute
+ * value of olen is the actual offset length)
+ * - the offset itself is passed in data, which is overwritten by the
+ * subsequent read operation
+ */
+ if (olen < 0) {
+ if (i2c_write_addr(base, chip_addr, I2C_WRITE_BIT, 0) != 0)
+ ret = __i2c_write_data(base, data, -olen);
+
+ if (ret != -olen)
+ return -1;
+
+ if (dlen && i2c_write_addr(base, chip_addr,
+ I2C_READ_BIT, 1) != 0)
+ ret = __i2c_read_data(base, data, dlen);
+ } else {
+ if ((!dlen || olen > 0) &&
+ i2c_write_addr(base, chip_addr, I2C_WRITE_BIT, 0) != 0 &&
+ __i2c_write_data(base, offset, olen) == olen)
+ ret = 0; /* No error so far */
+
+ if (dlen && i2c_write_addr(base, chip_addr, I2C_READ_BIT,
+ olen ? 1 : 0) != 0)
+ ret = __i2c_read_data(base, data, dlen);
+ }
+
+ writeb(I2C_CR_MEN, &base->cr);
+
+ if (i2c_wait4bus(base)) /* Wait until STOP */
+ debug("i2c_read: wait4bus timed out\n");
+
+ if (ret == dlen)
+ return 0;
+
+ return -1;
+}
+
+static int __i2c_write(const struct fsl_i2c_base *base, u8 chip_addr,
+ u8 *offset, int olen, u8 *data, int dlen)
+{
+ int ret = -1; /* signal error */
+
+ if (i2c_wait4bus(base) < 0)
+ return -1;
+
+ if (i2c_write_addr(base, chip_addr, I2C_WRITE_BIT, 0) != 0 &&
+ __i2c_write_data(base, offset, olen) == olen) {
+ ret = __i2c_write_data(base, data, dlen);
+ }
+
+ writeb(I2C_CR_MEN, &base->cr);
+ if (i2c_wait4bus(base)) /* Wait until STOP */
+ debug("i2c_write: wait4bus timed out\n");
+
+ if (ret == dlen)
+ return 0;
+
+ return -1;
+}
+
+static int __i2c_probe_chip(const struct fsl_i2c_base *base, uchar chip)
+{
+ /* For unknown reason the controller will ACK when
+ * probing for a slave with the same address, so skip
+ * it.
+ */
+ if (chip == (readb(&base->adr) >> 1))
+ return -1;
+
+ return __i2c_read(base, chip, 0, 0, NULL, 0);
+}
+
+static uint __i2c_set_bus_speed(const struct fsl_i2c_base *base,
+ uint speed, int i2c_clk)
+{
+ writeb(0, &base->cr); /* stop controller */
+ set_i2c_bus_speed(base, i2c_clk, speed);
+ writeb(I2C_CR_MEN, &base->cr); /* start controller */
+
+ return 0;
+}
+
+#if !CONFIG_IS_ENABLED(DM_I2C)
+static void fsl_i2c_init(struct i2c_adapter *adap, int speed, int slaveadd)
+{
+ __i2c_init(i2c_base[adap->hwadapnr], speed, slaveadd,
+ get_i2c_clock(adap->hwadapnr), adap->hwadapnr);
+}
+
+static int fsl_i2c_probe_chip(struct i2c_adapter *adap, uchar chip)
+{
+ return __i2c_probe_chip(i2c_base[adap->hwadapnr], chip);
+}
+
+static int fsl_i2c_read(struct i2c_adapter *adap, u8 chip_addr, uint offset,
+ int olen, u8 *data, int dlen)
+{
+ u8 *o = (u8 *)&offset;
+
+ return __i2c_read(i2c_base[adap->hwadapnr], chip_addr, &o[4 - olen],
+ olen, data, dlen);
+}
+
+static int fsl_i2c_write(struct i2c_adapter *adap, u8 chip_addr, uint offset,
+ int olen, u8 *data, int dlen)
+{
+ u8 *o = (u8 *)&offset;
+
+ return __i2c_write(i2c_base[adap->hwadapnr], chip_addr, &o[4 - olen],
+ olen, data, dlen);
+}
+
+static uint fsl_i2c_set_bus_speed(struct i2c_adapter *adap, uint speed)
+{
+ return __i2c_set_bus_speed(i2c_base[adap->hwadapnr], speed,
+ get_i2c_clock(adap->hwadapnr));
+}
+
+/*
+ * Register fsl i2c adapters
+ */
+U_BOOT_I2C_ADAP_COMPLETE(fsl_0, fsl_i2c_init, fsl_i2c_probe_chip, fsl_i2c_read,
+ fsl_i2c_write, fsl_i2c_set_bus_speed,
+ CONFIG_SYS_FSL_I2C_SPEED, CONFIG_SYS_FSL_I2C_SLAVE,
+ 0)
+#ifdef CONFIG_SYS_FSL_I2C2_OFFSET
+U_BOOT_I2C_ADAP_COMPLETE(fsl_1, fsl_i2c_init, fsl_i2c_probe_chip, fsl_i2c_read,
+ fsl_i2c_write, fsl_i2c_set_bus_speed,
+ CONFIG_SYS_FSL_I2C2_SPEED, CONFIG_SYS_FSL_I2C2_SLAVE,
+ 1)
+#endif
+#ifdef CONFIG_SYS_FSL_I2C3_OFFSET
+U_BOOT_I2C_ADAP_COMPLETE(fsl_2, fsl_i2c_init, fsl_i2c_probe_chip, fsl_i2c_read,
+ fsl_i2c_write, fsl_i2c_set_bus_speed,
+ CONFIG_SYS_FSL_I2C3_SPEED, CONFIG_SYS_FSL_I2C3_SLAVE,
+ 2)
+#endif
+#ifdef CONFIG_SYS_FSL_I2C4_OFFSET
+U_BOOT_I2C_ADAP_COMPLETE(fsl_3, fsl_i2c_init, fsl_i2c_probe_chip, fsl_i2c_read,
+ fsl_i2c_write, fsl_i2c_set_bus_speed,
+ CONFIG_SYS_FSL_I2C4_SPEED, CONFIG_SYS_FSL_I2C4_SLAVE,
+ 3)
+#endif
+#else /* CONFIG_DM_I2C */
+static int fsl_i2c_probe_chip(struct udevice *bus, u32 chip_addr,
+ u32 chip_flags)
+{
+ struct fsl_i2c_dev *dev = dev_get_priv(bus);
+
+ return __i2c_probe_chip(dev->base, chip_addr);
+}
+
+static int fsl_i2c_set_bus_speed(struct udevice *bus, uint speed)
+{
+ struct fsl_i2c_dev *dev = dev_get_priv(bus);
+
+ return __i2c_set_bus_speed(dev->base, speed, dev->i2c_clk);
+}
+
+static int fsl_i2c_of_to_plat(struct udevice *bus)
+{
+ struct fsl_i2c_dev *dev = dev_get_priv(bus);
+ struct clk clock;
+
+ dev->base = map_sysmem(dev_read_addr(bus), sizeof(struct fsl_i2c_base));
+
+ if (!dev->base)
+ return -ENOMEM;
+
+ dev->index = dev_read_u32_default(bus, "cell-index", -1);
+ dev->slaveadd = dev_read_u32_default(bus, "u-boot,i2c-slave-addr",
+ 0x7f);
+ dev->speed = dev_read_u32_default(bus, "clock-frequency",
+ I2C_SPEED_FAST_RATE);
+
+ if (!clk_get_by_index(bus, 0, &clock))
+ dev->i2c_clk = clk_get_rate(&clock);
+ else
+ dev->i2c_clk = dev->index ? gd->arch.i2c2_clk :
+ gd->arch.i2c1_clk;
+
+ return 0;
+}
+
+static int fsl_i2c_probe(struct udevice *bus)
+{
+ struct fsl_i2c_dev *dev = dev_get_priv(bus);
+
+ __i2c_init(dev->base, dev->speed, dev->slaveadd, dev->i2c_clk,
+ dev->index);
+ return 0;
+}
+
+static int fsl_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
+{
+ struct fsl_i2c_dev *dev = dev_get_priv(bus);
+ struct i2c_msg *dmsg, *omsg, dummy;
+
+ memset(&dummy, 0, sizeof(struct i2c_msg));
+
+ /* We expect either two messages (one with an offset and one with the
+ * actual data) or one message (just data)
+ */
+ if (nmsgs > 2 || nmsgs == 0) {
+ debug("%s: Only one or two messages are supported.", __func__);
+ return -1;
+ }
+
+ omsg = nmsgs == 1 ? &dummy : msg;
+ dmsg = nmsgs == 1 ? msg : msg + 1;
+
+ if (dmsg->flags & I2C_M_RD)
+ return __i2c_read(dev->base, dmsg->addr, omsg->buf, omsg->len,
+ dmsg->buf, dmsg->len);
+ else
+ return __i2c_write(dev->base, dmsg->addr, omsg->buf, omsg->len,
+ dmsg->buf, dmsg->len);
+}
+
+static const struct dm_i2c_ops fsl_i2c_ops = {
+ .xfer = fsl_i2c_xfer,
+ .probe_chip = fsl_i2c_probe_chip,
+ .set_bus_speed = fsl_i2c_set_bus_speed,
+};
+
+static const struct udevice_id fsl_i2c_ids[] = {
+ { .compatible = "fsl-i2c", },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(i2c_fsl) = {
+ .name = "i2c_fsl",
+ .id = UCLASS_I2C,
+ .of_match = fsl_i2c_ids,
+ .probe = fsl_i2c_probe,
+ .of_to_plat = fsl_i2c_of_to_plat,
+ .priv_auto = sizeof(struct fsl_i2c_dev),
+ .ops = &fsl_i2c_ops,
+};
+
+#endif /* CONFIG_DM_I2C */
diff --git a/roms/u-boot/drivers/i2c/i2c-cdns.c b/roms/u-boot/drivers/i2c/i2c-cdns.c
new file mode 100644
index 000000000..a650dd69b
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/i2c-cdns.c
@@ -0,0 +1,516 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2015 Moritz Fischer <moritz.fischer@ettus.com>
+ * IP from Cadence (ID T-CS-PE-0007-100, Version R1p10f2)
+ *
+ * This file is based on: drivers/i2c/zynq_i2c.c,
+ * with added driver-model support and code cleanup.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/io.h>
+#include <linux/errno.h>
+#include <dm/device_compat.h>
+#include <dm/root.h>
+#include <i2c.h>
+#include <fdtdec.h>
+#include <mapmem.h>
+#include <wait_bit.h>
+#include <clk.h>
+
+/* i2c register set */
+struct cdns_i2c_regs {
+ u32 control;
+ u32 status;
+ u32 address;
+ u32 data;
+ u32 interrupt_status;
+ u32 transfer_size;
+ u32 slave_mon_pause;
+ u32 time_out;
+ u32 interrupt_mask;
+ u32 interrupt_enable;
+ u32 interrupt_disable;
+};
+
+/* Control register fields */
+#define CDNS_I2C_CONTROL_RW 0x00000001
+#define CDNS_I2C_CONTROL_MS 0x00000002
+#define CDNS_I2C_CONTROL_NEA 0x00000004
+#define CDNS_I2C_CONTROL_ACKEN 0x00000008
+#define CDNS_I2C_CONTROL_HOLD 0x00000010
+#define CDNS_I2C_CONTROL_SLVMON 0x00000020
+#define CDNS_I2C_CONTROL_CLR_FIFO 0x00000040
+#define CDNS_I2C_CONTROL_DIV_B_SHIFT 8
+#define CDNS_I2C_CONTROL_DIV_B_MASK 0x00003F00
+#define CDNS_I2C_CONTROL_DIV_A_SHIFT 14
+#define CDNS_I2C_CONTROL_DIV_A_MASK 0x0000C000
+
+/* Status register values */
+#define CDNS_I2C_STATUS_RXDV 0x00000020
+#define CDNS_I2C_STATUS_TXDV 0x00000040
+#define CDNS_I2C_STATUS_RXOVF 0x00000080
+#define CDNS_I2C_STATUS_BA 0x00000100
+
+/* Interrupt register fields */
+#define CDNS_I2C_INTERRUPT_COMP 0x00000001
+#define CDNS_I2C_INTERRUPT_DATA 0x00000002
+#define CDNS_I2C_INTERRUPT_NACK 0x00000004
+#define CDNS_I2C_INTERRUPT_TO 0x00000008
+#define CDNS_I2C_INTERRUPT_SLVRDY 0x00000010
+#define CDNS_I2C_INTERRUPT_RXOVF 0x00000020
+#define CDNS_I2C_INTERRUPT_TXOVF 0x00000040
+#define CDNS_I2C_INTERRUPT_RXUNF 0x00000080
+#define CDNS_I2C_INTERRUPT_ARBLOST 0x00000200
+
+#define CDNS_I2C_INTERRUPTS_MASK (CDNS_I2C_INTERRUPT_COMP | \
+ CDNS_I2C_INTERRUPT_DATA | \
+ CDNS_I2C_INTERRUPT_NACK | \
+ CDNS_I2C_INTERRUPT_TO | \
+ CDNS_I2C_INTERRUPT_SLVRDY | \
+ CDNS_I2C_INTERRUPT_RXOVF | \
+ CDNS_I2C_INTERRUPT_TXOVF | \
+ CDNS_I2C_INTERRUPT_RXUNF | \
+ CDNS_I2C_INTERRUPT_ARBLOST)
+
+#define CDNS_I2C_FIFO_DEPTH 16
+#define CDNS_I2C_TRANSFER_SIZE_MAX 255 /* Controller transfer limit */
+#define CDNS_I2C_TRANSFER_SIZE (CDNS_I2C_TRANSFER_SIZE_MAX - 3)
+
+#define CDNS_I2C_BROKEN_HOLD_BIT BIT(0)
+
+#define CDNS_I2C_ARB_LOST_MAX_RETRIES 10
+
+#ifdef DEBUG
+static void cdns_i2c_debug_status(struct cdns_i2c_regs *cdns_i2c)
+{
+ int int_status;
+ int status;
+ int_status = readl(&cdns_i2c->interrupt_status);
+
+ status = readl(&cdns_i2c->status);
+ if (int_status || status) {
+ debug("Status: ");
+ if (int_status & CDNS_I2C_INTERRUPT_COMP)
+ debug("COMP ");
+ if (int_status & CDNS_I2C_INTERRUPT_DATA)
+ debug("DATA ");
+ if (int_status & CDNS_I2C_INTERRUPT_NACK)
+ debug("NACK ");
+ if (int_status & CDNS_I2C_INTERRUPT_TO)
+ debug("TO ");
+ if (int_status & CDNS_I2C_INTERRUPT_SLVRDY)
+ debug("SLVRDY ");
+ if (int_status & CDNS_I2C_INTERRUPT_RXOVF)
+ debug("RXOVF ");
+ if (int_status & CDNS_I2C_INTERRUPT_TXOVF)
+ debug("TXOVF ");
+ if (int_status & CDNS_I2C_INTERRUPT_RXUNF)
+ debug("RXUNF ");
+ if (int_status & CDNS_I2C_INTERRUPT_ARBLOST)
+ debug("ARBLOST ");
+ if (status & CDNS_I2C_STATUS_RXDV)
+ debug("RXDV ");
+ if (status & CDNS_I2C_STATUS_TXDV)
+ debug("TXDV ");
+ if (status & CDNS_I2C_STATUS_RXOVF)
+ debug("RXOVF ");
+ if (status & CDNS_I2C_STATUS_BA)
+ debug("BA ");
+ debug("TS%d ", readl(&cdns_i2c->transfer_size));
+ debug("\n");
+ }
+}
+#endif
+
+struct i2c_cdns_bus {
+ int id;
+ unsigned int input_freq;
+ struct cdns_i2c_regs __iomem *regs; /* register base */
+
+ int hold_flag;
+ u32 quirks;
+};
+
+struct cdns_i2c_platform_data {
+ u32 quirks;
+};
+
+/* Wait for an interrupt */
+static u32 cdns_i2c_wait(struct cdns_i2c_regs *cdns_i2c, u32 mask)
+{
+ int timeout, int_status;
+
+ for (timeout = 0; timeout < 100; timeout++) {
+ int_status = readl(&cdns_i2c->interrupt_status);
+ if (int_status & mask)
+ break;
+ udelay(100);
+ }
+
+ /* Clear interrupt status flags */
+ writel(int_status & mask, &cdns_i2c->interrupt_status);
+
+ return int_status & mask;
+}
+
+#define CDNS_I2C_DIVA_MAX 4
+#define CDNS_I2C_DIVB_MAX 64
+
+static int cdns_i2c_calc_divs(unsigned long *f, unsigned long input_clk,
+ unsigned int *a, unsigned int *b)
+{
+ unsigned long fscl = *f, best_fscl = *f, actual_fscl, temp;
+ unsigned int div_a, div_b, calc_div_a = 0, calc_div_b = 0;
+ unsigned int last_error, current_error;
+
+ /* calculate (divisor_a+1) x (divisor_b+1) */
+ temp = input_clk / (22 * fscl);
+
+ /*
+ * If the calculated value is negative or 0CDNS_I2C_DIVA_MAX,
+ * the fscl input is out of range. Return error.
+ */
+ if (!temp || (temp > (CDNS_I2C_DIVA_MAX * CDNS_I2C_DIVB_MAX)))
+ return -EINVAL;
+
+ last_error = -1;
+ for (div_a = 0; div_a < CDNS_I2C_DIVA_MAX; div_a++) {
+ div_b = DIV_ROUND_UP(input_clk, 22 * fscl * (div_a + 1));
+
+ if ((div_b < 1) || (div_b > CDNS_I2C_DIVB_MAX))
+ continue;
+ div_b--;
+
+ actual_fscl = input_clk / (22 * (div_a + 1) * (div_b + 1));
+
+ if (actual_fscl > fscl)
+ continue;
+
+ current_error = ((actual_fscl > fscl) ? (actual_fscl - fscl) :
+ (fscl - actual_fscl));
+
+ if (last_error > current_error) {
+ calc_div_a = div_a;
+ calc_div_b = div_b;
+ best_fscl = actual_fscl;
+ last_error = current_error;
+ }
+ }
+
+ *a = calc_div_a;
+ *b = calc_div_b;
+ *f = best_fscl;
+
+ return 0;
+}
+
+static int cdns_i2c_set_bus_speed(struct udevice *dev, unsigned int speed)
+{
+ struct i2c_cdns_bus *bus = dev_get_priv(dev);
+ u32 div_a = 0, div_b = 0;
+ unsigned long speed_p = speed;
+ int ret = 0;
+
+ if (speed > I2C_SPEED_FAST_RATE) {
+ debug("%s, failed to set clock speed to %u\n", __func__,
+ speed);
+ return -EINVAL;
+ }
+
+ ret = cdns_i2c_calc_divs(&speed_p, bus->input_freq, &div_a, &div_b);
+ if (ret)
+ return ret;
+
+ debug("%s: div_a: %d, div_b: %d, input freq: %d, speed: %d/%ld\n",
+ __func__, div_a, div_b, bus->input_freq, speed, speed_p);
+
+ writel((div_b << CDNS_I2C_CONTROL_DIV_B_SHIFT) |
+ (div_a << CDNS_I2C_CONTROL_DIV_A_SHIFT), &bus->regs->control);
+
+ /* Enable master mode, ack, and 7-bit addressing */
+ setbits_le32(&bus->regs->control, CDNS_I2C_CONTROL_MS |
+ CDNS_I2C_CONTROL_ACKEN | CDNS_I2C_CONTROL_NEA);
+
+ return 0;
+}
+
+static inline u32 is_arbitration_lost(struct cdns_i2c_regs *regs)
+{
+ return (readl(&regs->interrupt_status) & CDNS_I2C_INTERRUPT_ARBLOST);
+}
+
+static int cdns_i2c_write_data(struct i2c_cdns_bus *i2c_bus, u32 addr, u8 *data,
+ u32 len)
+{
+ u8 *cur_data = data;
+ struct cdns_i2c_regs *regs = i2c_bus->regs;
+ u32 ret;
+
+ /* Set the controller in Master transmit mode and clear FIFO */
+ setbits_le32(&regs->control, CDNS_I2C_CONTROL_CLR_FIFO);
+ clrbits_le32(&regs->control, CDNS_I2C_CONTROL_RW);
+
+ /* Check message size against FIFO depth, and set hold bus bit
+ * if it is greater than FIFO depth
+ */
+ if (len > CDNS_I2C_FIFO_DEPTH)
+ setbits_le32(&regs->control, CDNS_I2C_CONTROL_HOLD);
+
+ /* Clear the interrupts in status register */
+ writel(CDNS_I2C_INTERRUPTS_MASK, &regs->interrupt_status);
+
+ writel(addr, &regs->address);
+
+ while (len-- && !is_arbitration_lost(regs)) {
+ writel(*(cur_data++), &regs->data);
+ if (len && readl(&regs->transfer_size) == CDNS_I2C_FIFO_DEPTH) {
+ ret = cdns_i2c_wait(regs, CDNS_I2C_INTERRUPT_COMP |
+ CDNS_I2C_INTERRUPT_ARBLOST);
+ if (ret & CDNS_I2C_INTERRUPT_ARBLOST)
+ return -EAGAIN;
+ if (ret & CDNS_I2C_INTERRUPT_COMP)
+ continue;
+ /* Release the bus */
+ clrbits_le32(&regs->control,
+ CDNS_I2C_CONTROL_HOLD);
+ return -ETIMEDOUT;
+ }
+ }
+
+ if (len && is_arbitration_lost(regs))
+ return -EAGAIN;
+
+ /* All done... release the bus */
+ if (!i2c_bus->hold_flag)
+ clrbits_le32(&regs->control, CDNS_I2C_CONTROL_HOLD);
+
+ /* Wait for the address and data to be sent */
+ ret = cdns_i2c_wait(regs, CDNS_I2C_INTERRUPT_COMP |
+ CDNS_I2C_INTERRUPT_ARBLOST);
+ if (!(ret & (CDNS_I2C_INTERRUPT_ARBLOST |
+ CDNS_I2C_INTERRUPT_COMP)))
+ return -ETIMEDOUT;
+ if (ret & CDNS_I2C_INTERRUPT_ARBLOST)
+ return -EAGAIN;
+
+ return 0;
+}
+
+static inline bool cdns_is_hold_quirk(int hold_quirk, int curr_recv_count)
+{
+ return hold_quirk && (curr_recv_count == CDNS_I2C_FIFO_DEPTH + 1);
+}
+
+static int cdns_i2c_read_data(struct i2c_cdns_bus *i2c_bus, u32 addr, u8 *data,
+ u32 recv_count)
+{
+ u8 *cur_data = data;
+ struct cdns_i2c_regs *regs = i2c_bus->regs;
+ u32 curr_recv_count;
+ int updatetx, hold_quirk;
+ u32 ret;
+
+ curr_recv_count = recv_count;
+
+ /* Check for the message size against the FIFO depth */
+ if (recv_count > CDNS_I2C_FIFO_DEPTH)
+ setbits_le32(&regs->control, CDNS_I2C_CONTROL_HOLD);
+
+ setbits_le32(&regs->control, CDNS_I2C_CONTROL_CLR_FIFO |
+ CDNS_I2C_CONTROL_RW);
+
+ if (recv_count > CDNS_I2C_TRANSFER_SIZE) {
+ curr_recv_count = CDNS_I2C_TRANSFER_SIZE;
+ writel(curr_recv_count, &regs->transfer_size);
+ } else {
+ writel(recv_count, &regs->transfer_size);
+ }
+
+ /* Start reading data */
+ writel(addr, &regs->address);
+
+ updatetx = recv_count > curr_recv_count;
+
+ hold_quirk = (i2c_bus->quirks & CDNS_I2C_BROKEN_HOLD_BIT) && updatetx;
+
+ while (recv_count && !is_arbitration_lost(regs)) {
+ while (readl(&regs->status) & CDNS_I2C_STATUS_RXDV) {
+ if (recv_count < CDNS_I2C_FIFO_DEPTH &&
+ !i2c_bus->hold_flag) {
+ clrbits_le32(&regs->control,
+ CDNS_I2C_CONTROL_HOLD);
+ }
+ *(cur_data)++ = readl(&regs->data);
+ recv_count--;
+ curr_recv_count--;
+
+ if (cdns_is_hold_quirk(hold_quirk, curr_recv_count))
+ break;
+ }
+
+ if (cdns_is_hold_quirk(hold_quirk, curr_recv_count)) {
+ /* wait while fifo is full */
+ while (readl(&regs->transfer_size) !=
+ (curr_recv_count - CDNS_I2C_FIFO_DEPTH))
+ ;
+ /*
+ * Check number of bytes to be received against maximum
+ * transfer size and update register accordingly.
+ */
+ if ((recv_count - CDNS_I2C_FIFO_DEPTH) >
+ CDNS_I2C_TRANSFER_SIZE) {
+ writel(CDNS_I2C_TRANSFER_SIZE,
+ &regs->transfer_size);
+ curr_recv_count = CDNS_I2C_TRANSFER_SIZE +
+ CDNS_I2C_FIFO_DEPTH;
+ } else {
+ writel(recv_count - CDNS_I2C_FIFO_DEPTH,
+ &regs->transfer_size);
+ curr_recv_count = recv_count;
+ }
+ } else if (recv_count && !hold_quirk && !curr_recv_count) {
+ writel(addr, &regs->address);
+ if (recv_count > CDNS_I2C_TRANSFER_SIZE) {
+ writel(CDNS_I2C_TRANSFER_SIZE,
+ &regs->transfer_size);
+ curr_recv_count = CDNS_I2C_TRANSFER_SIZE;
+ } else {
+ writel(recv_count, &regs->transfer_size);
+ curr_recv_count = recv_count;
+ }
+ }
+ }
+
+ /* Wait for the address and data to be sent */
+ ret = cdns_i2c_wait(regs, CDNS_I2C_INTERRUPT_COMP |
+ CDNS_I2C_INTERRUPT_ARBLOST);
+ if (!(ret & (CDNS_I2C_INTERRUPT_ARBLOST |
+ CDNS_I2C_INTERRUPT_COMP)))
+ return -ETIMEDOUT;
+ if (ret & CDNS_I2C_INTERRUPT_ARBLOST)
+ return -EAGAIN;
+
+ return 0;
+}
+
+static int cdns_i2c_xfer(struct udevice *dev, struct i2c_msg *msg,
+ int nmsgs)
+{
+ struct i2c_cdns_bus *i2c_bus = dev_get_priv(dev);
+ int ret = 0;
+ int count;
+ bool hold_quirk;
+ struct i2c_msg *message = msg;
+ int num_msgs = nmsgs;
+
+ hold_quirk = !!(i2c_bus->quirks & CDNS_I2C_BROKEN_HOLD_BIT);
+
+ if (nmsgs > 1) {
+ /*
+ * This controller does not give completion interrupt after a
+ * master receive message if HOLD bit is set (repeated start),
+ * resulting in SW timeout. Hence, if a receive message is
+ * followed by any other message, an error is returned
+ * indicating that this sequence is not supported.
+ */
+ for (count = 0; (count < nmsgs - 1) && hold_quirk; count++) {
+ if (msg[count].flags & I2C_M_RD) {
+ printf("Can't do repeated start after a receive message\n");
+ return -EOPNOTSUPP;
+ }
+ }
+
+ i2c_bus->hold_flag = 1;
+ setbits_le32(&i2c_bus->regs->control, CDNS_I2C_CONTROL_HOLD);
+ } else {
+ i2c_bus->hold_flag = 0;
+ }
+
+ debug("i2c_xfer: %d messages\n", nmsgs);
+ for (u8 retry = 0; retry < CDNS_I2C_ARB_LOST_MAX_RETRIES &&
+ nmsgs > 0; nmsgs--, msg++) {
+ debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
+ if (msg->flags & I2C_M_RD) {
+ ret = cdns_i2c_read_data(i2c_bus, msg->addr, msg->buf,
+ msg->len);
+ } else {
+ ret = cdns_i2c_write_data(i2c_bus, msg->addr, msg->buf,
+ msg->len);
+ }
+ if (ret == -EAGAIN) {
+ msg = message;
+ nmsgs = num_msgs;
+ retry++;
+ printf("%s,arbitration lost, retrying:%d\n", __func__,
+ retry);
+ continue;
+ }
+
+ if (ret) {
+ debug("i2c_write: error sending\n");
+ return -EREMOTEIO;
+ }
+ }
+
+ return ret;
+}
+
+static int cdns_i2c_of_to_plat(struct udevice *dev)
+{
+ struct i2c_cdns_bus *i2c_bus = dev_get_priv(dev);
+ struct cdns_i2c_platform_data *pdata =
+ (struct cdns_i2c_platform_data *)dev_get_driver_data(dev);
+ struct clk clk;
+ int ret;
+
+ i2c_bus->regs = (struct cdns_i2c_regs *)dev_read_addr(dev);
+ if (!i2c_bus->regs)
+ return -ENOMEM;
+
+ if (pdata)
+ i2c_bus->quirks = pdata->quirks;
+
+ ret = clk_get_by_index(dev, 0, &clk);
+ if (ret)
+ return ret;
+
+ i2c_bus->input_freq = clk_get_rate(&clk);
+
+ ret = clk_enable(&clk);
+ if (ret) {
+ dev_err(dev, "failed to enable clock\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct dm_i2c_ops cdns_i2c_ops = {
+ .xfer = cdns_i2c_xfer,
+ .set_bus_speed = cdns_i2c_set_bus_speed,
+};
+
+static const struct cdns_i2c_platform_data r1p10_i2c_def = {
+ .quirks = CDNS_I2C_BROKEN_HOLD_BIT,
+};
+
+static const struct udevice_id cdns_i2c_of_match[] = {
+ { .compatible = "cdns,i2c-r1p10", .data = (ulong)&r1p10_i2c_def },
+ { .compatible = "cdns,i2c-r1p14" },
+ { /* end of table */ }
+};
+
+U_BOOT_DRIVER(cdns_i2c) = {
+ .name = "i2c_cdns",
+ .id = UCLASS_I2C,
+ .of_match = cdns_i2c_of_match,
+ .of_to_plat = cdns_i2c_of_to_plat,
+ .priv_auto = sizeof(struct i2c_cdns_bus),
+ .ops = &cdns_i2c_ops,
+};
diff --git a/roms/u-boot/drivers/i2c/i2c-cortina.c b/roms/u-boot/drivers/i2c/i2c-cortina.c
new file mode 100644
index 000000000..960ae8c70
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/i2c-cortina.c
@@ -0,0 +1,347 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2020
+ * Arthur Li, Cortina Access, arthur.li@cortina-access.com.
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <log.h>
+#include <asm/io.h>
+#include <dm.h>
+#include <mapmem.h>
+#include "i2c-cortina.h"
+
+static void set_speed(struct i2c_regs *regs, int i2c_spd)
+{
+ union ca_biw_cfg i2c_cfg;
+
+ i2c_cfg.wrd = readl(&regs->i2c_cfg);
+ i2c_cfg.bf.core_en = 0;
+ writel(i2c_cfg.wrd, &regs->i2c_cfg);
+
+ switch (i2c_spd) {
+ case IC_SPEED_MODE_FAST_PLUS:
+ i2c_cfg.bf.prer = CORTINA_PER_IO_FREQ /
+ (5 * I2C_SPEED_FAST_PLUS_RATE) - 1;
+ break;
+
+ case IC_SPEED_MODE_STANDARD:
+ i2c_cfg.bf.prer = CORTINA_PER_IO_FREQ /
+ (5 * I2C_SPEED_STANDARD_RATE) - 1;
+ break;
+
+ case IC_SPEED_MODE_FAST:
+ default:
+ i2c_cfg.bf.prer = CORTINA_PER_IO_FREQ /
+ (5 * I2C_SPEED_FAST_RATE) - 1;
+ break;
+ }
+
+ i2c_cfg.bf.core_en = 1;
+ writel(i2c_cfg.wrd, &regs->i2c_cfg);
+}
+
+static int ca_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
+{
+ struct ca_i2c *priv = dev_get_priv(bus);
+ int i2c_spd;
+
+ if (speed >= I2C_SPEED_FAST_PLUS_RATE) {
+ i2c_spd = IC_SPEED_MODE_FAST_PLUS;
+ priv->speed = I2C_SPEED_FAST_PLUS_RATE;
+ } else if (speed >= I2C_SPEED_FAST_RATE) {
+ i2c_spd = IC_SPEED_MODE_FAST;
+ priv->speed = I2C_SPEED_FAST_RATE;
+ } else {
+ i2c_spd = IC_SPEED_MODE_STANDARD;
+ priv->speed = I2C_SPEED_STANDARD_RATE;
+ }
+
+ set_speed(priv->regs, i2c_spd);
+
+ return 0;
+}
+
+static int ca_i2c_get_bus_speed(struct udevice *bus)
+{
+ struct ca_i2c *priv = dev_get_priv(bus);
+
+ return priv->speed;
+}
+
+static void ca_i2c_init(struct i2c_regs *regs)
+{
+ union ca_biw_cfg i2c_cfg;
+
+ i2c_cfg.wrd = readl(&regs->i2c_cfg);
+ i2c_cfg.bf.core_en = 0;
+ i2c_cfg.bf.biw_soft_reset = 1;
+ writel(i2c_cfg.wrd, &regs->i2c_cfg);
+ mdelay(10);
+ i2c_cfg.bf.biw_soft_reset = 0;
+ writel(i2c_cfg.wrd, &regs->i2c_cfg);
+
+ set_speed(regs, IC_SPEED_MODE_STANDARD);
+
+ i2c_cfg.wrd = readl(&regs->i2c_cfg);
+ i2c_cfg.bf.core_en = 1;
+ writel(i2c_cfg.wrd, &regs->i2c_cfg);
+}
+
+static int i2c_wait_complete(struct i2c_regs *regs)
+{
+ union ca_biw_ctrl i2c_ctrl;
+ unsigned long start_time_bb = get_timer(0);
+
+ i2c_ctrl.wrd = readl(&regs->i2c_ctrl);
+
+ while (i2c_ctrl.bf.biwdone == 0) {
+ i2c_ctrl.wrd = readl(&regs->i2c_ctrl);
+
+ if (get_timer(start_time_bb) >
+ (unsigned long)(I2C_BYTE_TO_BB)) {
+ printf("%s not done!!!\n", __func__);
+ return -ETIMEDOUT;
+ }
+ }
+
+ /* Clear done bit */
+ writel(i2c_ctrl.wrd, &regs->i2c_ctrl);
+
+ return 0;
+}
+
+static void i2c_setaddress(struct i2c_regs *regs, unsigned int i2c_addr,
+ int write_read)
+{
+ writel(i2c_addr | write_read, &regs->i2c_txr);
+
+ writel(BIW_CTRL_START | BIW_CTRL_WRITE,
+ &regs->i2c_ctrl);
+
+ i2c_wait_complete(regs);
+}
+
+static int i2c_wait_for_bus_busy(struct i2c_regs *regs)
+{
+ union ca_biw_ack i2c_ack;
+ unsigned long start_time_bb = get_timer(0);
+
+ i2c_ack.wrd = readl(&regs->i2c_ack);
+
+ while (i2c_ack.bf.biw_busy) {
+ i2c_ack.wrd = readl(&regs->i2c_ack);
+
+ if (get_timer(start_time_bb) >
+ (unsigned long)(I2C_BYTE_TO_BB)) {
+ printf("%s: timeout!\n", __func__);
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
+static int i2c_xfer_init(struct i2c_regs *regs, uint8_t chip, uint addr,
+ int alen, int write_read)
+{
+ int addr_len = alen;
+
+ if (i2c_wait_for_bus_busy(regs))
+ return 1;
+
+ /* First cycle must write addr + offset */
+ chip = ((chip & 0x7F) << 1);
+ if (alen == 0 && write_read == I2C_CMD_RD)
+ i2c_setaddress(regs, chip, I2C_CMD_RD);
+ else
+ i2c_setaddress(regs, chip, I2C_CMD_WT);
+
+ while (alen) {
+ alen--;
+ writel(addr, &regs->i2c_txr);
+ if (write_read == I2C_CMD_RD)
+ writel(BIW_CTRL_WRITE | BIW_CTRL_STOP,
+ &regs->i2c_ctrl);
+ else
+ writel(BIW_CTRL_WRITE, &regs->i2c_ctrl);
+ i2c_wait_complete(regs);
+ }
+
+ /* Send address again with Read flag if it's read command */
+ if (write_read == I2C_CMD_RD && addr_len > 0)
+ i2c_setaddress(regs, chip, I2C_CMD_RD);
+
+ return 0;
+}
+
+static int i2c_xfer_finish(struct i2c_regs *regs)
+{
+ /* Dummy read makes bus free */
+ writel(BIW_CTRL_READ | BIW_CTRL_STOP, &regs->i2c_ctrl);
+ i2c_wait_complete(regs);
+
+ if (i2c_wait_for_bus_busy(regs)) {
+ printf("Timed out waiting for bus\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int ca_i2c_read(struct i2c_regs *regs, uint8_t chip, uint addr,
+ int alen, uint8_t *buffer, int len)
+{
+ unsigned long start_time_rx;
+ int rc = 0;
+
+ rc = i2c_xfer_init(regs, chip, addr, alen, I2C_CMD_RD);
+ if (rc)
+ return rc;
+
+ start_time_rx = get_timer(0);
+ while (len) {
+ /* ACK_IN is ack value to send during read.
+ * ack high only on the very last byte!
+ */
+ if (len == 1)
+ writel(BIW_CTRL_READ | BIW_CTRL_ACK_IN | BIW_CTRL_STOP,
+ &regs->i2c_ctrl);
+ else
+ writel(BIW_CTRL_READ, &regs->i2c_ctrl);
+
+ rc = i2c_wait_complete(regs);
+ udelay(1);
+
+ if (rc == 0) {
+ *buffer++ =
+ (uchar) readl(&regs->i2c_rxr);
+ len--;
+ start_time_rx = get_timer(0);
+
+ } else if (get_timer(start_time_rx) > I2C_BYTE_TO) {
+ return -ETIMEDOUT;
+ }
+ }
+ i2c_xfer_finish(regs);
+ return rc;
+}
+
+static int ca_i2c_write(struct i2c_regs *regs, uint8_t chip, uint addr,
+ int alen, uint8_t *buffer, int len)
+{
+ int rc, nb = len;
+ unsigned long start_time_tx;
+
+ rc = i2c_xfer_init(regs, chip, addr, alen, I2C_CMD_WT);
+ if (rc)
+ return rc;
+
+ start_time_tx = get_timer(0);
+ while (len) {
+ writel(*buffer, &regs->i2c_txr);
+ if (len == 1)
+ writel(BIW_CTRL_WRITE | BIW_CTRL_STOP,
+ &regs->i2c_ctrl);
+ else
+ writel(BIW_CTRL_WRITE, &regs->i2c_ctrl);
+
+ rc = i2c_wait_complete(regs);
+
+ if (rc == 0) {
+ len--;
+ buffer++;
+ start_time_tx = get_timer(0);
+ } else if (get_timer(start_time_tx) > (nb * I2C_BYTE_TO)) {
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
+static int ca_i2c_probe_chip(struct udevice *bus, uint chip_addr,
+ uint chip_flags)
+{
+ struct ca_i2c *priv = dev_get_priv(bus);
+ int ret;
+ u32 tmp;
+
+ /* Try to read the first location of the chip */
+ ret = ca_i2c_read(priv->regs, chip_addr, 0, 1, (uchar *)&tmp, 1);
+ if (ret)
+ ca_i2c_init(priv->regs);
+
+ return ret;
+}
+
+static int ca_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
+{
+ struct ca_i2c *priv = dev_get_priv(bus);
+ int ret;
+
+ debug("i2c_xfer: %d messages\n", nmsgs);
+ for (; nmsgs > 0; nmsgs--, msg++) {
+ debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
+ if (msg->flags & I2C_M_RD)
+ ret = ca_i2c_read(priv->regs, msg->addr, 0, 0,
+ msg->buf, msg->len);
+ else
+ ret = ca_i2c_write(priv->regs, msg->addr, 0, 0,
+ msg->buf, msg->len);
+
+ if (ret) {
+ printf("i2c_xfer: %s error\n",
+ msg->flags & I2C_M_RD ? "read" : "write");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static const struct dm_i2c_ops ca_i2c_ops = {
+ .xfer = ca_i2c_xfer,
+ .probe_chip = ca_i2c_probe_chip,
+ .set_bus_speed = ca_i2c_set_bus_speed,
+ .get_bus_speed = ca_i2c_get_bus_speed,
+};
+
+static const struct udevice_id ca_i2c_ids[] = {
+ { .compatible = "cortina,ca-i2c", },
+ { }
+};
+
+static int ca_i2c_probe(struct udevice *bus)
+{
+ struct ca_i2c *priv = dev_get_priv(bus);
+
+ ca_i2c_init(priv->regs);
+
+ return 0;
+}
+
+static int ca_i2c_of_to_plat(struct udevice *bus)
+{
+ struct ca_i2c *priv = dev_get_priv(bus);
+
+ priv->regs = map_sysmem(dev_read_addr(bus), sizeof(struct i2c_regs));
+ if (!priv->regs) {
+ printf("I2C: base address is invalid\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+U_BOOT_DRIVER(i2c_cortina) = {
+ .name = "i2c_cortina",
+ .id = UCLASS_I2C,
+ .of_match = ca_i2c_ids,
+ .of_to_plat = ca_i2c_of_to_plat,
+ .probe = ca_i2c_probe,
+ .priv_auto = sizeof(struct ca_i2c),
+ .ops = &ca_i2c_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/roms/u-boot/drivers/i2c/i2c-cortina.h b/roms/u-boot/drivers/i2c/i2c-cortina.h
new file mode 100644
index 000000000..7e406b580
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/i2c-cortina.h
@@ -0,0 +1,87 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2019
+ * Cortina Access, <www.cortina-access.com>
+ */
+
+#ifndef __CA_I2C_H_
+#define __CA_I2C_H_
+
+#include <linux/bitops.h>
+#include <linux/delay.h>
+
+#if !defined(__ASSEMBLER__) && !defined(__ASSEMBLY__)
+struct i2c_regs {
+ u32 i2c_cfg;
+ u32 i2c_ctrl;
+ u32 i2c_txr;
+ u32 i2c_rxr;
+ u32 i2c_ack;
+ u32 i2c_ie0;
+ u32 i2c_int0;
+ u32 i2c_ie1;
+ u32 i2c_int1;
+ u32 i2c_stat;
+};
+
+union ca_biw_cfg {
+ struct biw_cfg {
+ u32 core_en : 1;
+ u32 biw_soft_reset : 1;
+ u32 busywait_en : 1;
+ u32 stretch_en : 1;
+ u32 arb_en : 1;
+ u32 clksync_en : 1;
+ u32 rsrvd1 : 2;
+ u32 spike_cnt : 4;
+ u32 rsrvd2 : 4;
+ u32 prer : 16;
+ } bf;
+ unsigned int wrd;
+};
+
+union ca_biw_ctrl {
+ struct biw_ctrl {
+ u32 biwdone : 1;
+ u32 rsrvd1 : 2;
+ u32 ack_in : 1;
+ u32 write : 1;
+ u32 read : 1;
+ u32 stop : 1;
+ u32 start : 1;
+ u32 rsrvd2 : 24;
+ } bf;
+ unsigned int wrd;
+};
+
+union ca_biw_ack {
+ struct biw_ack {
+ u32 al :1;
+ u32 biw_busy :1;
+ u32 ack_out :1;
+ u32 rsrvd1 :29;
+ } bf;
+ unsigned int wrd;
+};
+#endif /* !__ASSEMBLER__*/
+
+struct ca_i2c {
+ struct i2c_regs *regs;
+ unsigned int speed;
+};
+
+#define I2C_CMD_WT 0
+#define I2C_CMD_RD 1
+
+#define BIW_CTRL_DONE BIT(0)
+#define BIW_CTRL_ACK_IN BIT(3)
+#define BIW_CTRL_WRITE BIT(4)
+#define BIW_CTRL_READ BIT(5)
+#define BIW_CTRL_STOP BIT(6)
+#define BIW_CTRL_START BIT(7)
+
+#define I2C_BYTE_TO (CONFIG_SYS_HZ / 500)
+#define I2C_STOPDET_TO (CONFIG_SYS_HZ / 500)
+#define I2C_BYTE_TO_BB (10)
+
+#endif /* __CA_I2C_H_ */
diff --git a/roms/u-boot/drivers/i2c/i2c-emul-uclass.c b/roms/u-boot/drivers/i2c/i2c-emul-uclass.c
new file mode 100644
index 000000000..7917b63c5
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/i2c-emul-uclass.c
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2014 Google, Inc
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+#include <log.h>
+#include <asm/i2c.h>
+#include <dm/device-internal.h>
+#include <dm/uclass-internal.h>
+
+/*
+ * i2c emulation works using an 'emul' node at the bus level. Each device in
+ * that node is in the UCLASS_I2C_EMUL uclass, and emulates one i2c device. A
+ * pointer to the device it emulates is in the 'dev' property of the emul device
+ * uclass plat (struct i2c_emul_plat), put there by i2c_emul_find().
+ * When sandbox wants an emulator for a device, it calls i2c_emul_find() which
+ * searches for the emulator with the correct address. To find the device for an
+ * emulator, call i2c_emul_get_device().
+ *
+ * The 'emul' node is in the UCLASS_I2C_EMUL_PARENT uclass. We use a separate
+ * uclass so avoid having strange devices on the I2C bus.
+ */
+
+struct udevice *i2c_emul_get_device(struct udevice *emul)
+{
+ struct i2c_emul_uc_plat *uc_plat = dev_get_uclass_plat(emul);
+
+ return uc_plat->dev;
+}
+
+void i2c_emul_set_idx(struct udevice *dev, int emul_idx)
+{
+ struct dm_i2c_chip *plat = dev_get_parent_plat(dev);
+
+ plat->emul_idx = emul_idx;
+}
+
+int i2c_emul_find(struct udevice *dev, struct udevice **emulp)
+{
+ struct i2c_emul_uc_plat *uc_plat;
+ struct udevice *emul;
+ int ret;
+
+ if (!CONFIG_IS_ENABLED(OF_PLATDATA)) {
+ ret = uclass_find_device_by_phandle(UCLASS_I2C_EMUL, dev,
+ "sandbox,emul", &emul);
+ } else {
+ struct dm_i2c_chip *plat = dev_get_parent_plat(dev);
+
+ ret = device_get_by_ofplat_idx(plat->emul_idx, &emul);
+ }
+ if (ret) {
+ log_err("No emulators for device '%s'\n", dev->name);
+ return ret;
+ }
+ uc_plat = dev_get_uclass_plat(emul);
+ uc_plat->dev = dev;
+ *emulp = emul;
+
+ return device_probe(emul);
+}
+
+UCLASS_DRIVER(i2c_emul) = {
+ .id = UCLASS_I2C_EMUL,
+ .name = "i2c_emul",
+ .per_device_plat_auto = sizeof(struct i2c_emul_uc_plat),
+};
+
+/*
+ * This uclass is a child of the i2c bus. Its plat is not defined here so
+ * is defined by its parent, UCLASS_I2C, which uses struct dm_i2c_chip. See
+ * per_child_plat_auto in UCLASS_DRIVER(i2c).
+ */
+UCLASS_DRIVER(i2c_emul_parent) = {
+ .id = UCLASS_I2C_EMUL_PARENT,
+ .name = "i2c_emul_parent",
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+ .post_bind = dm_scan_fdt_dev,
+#endif
+};
+
+static const struct udevice_id i2c_emul_parent_ids[] = {
+ { .compatible = "sandbox,i2c-emul-parent" },
+ { }
+};
+
+U_BOOT_DRIVER(sandbox_i2c_emul_parent) = {
+ .name = "sandbox_i2c_emul_parent",
+ .id = UCLASS_I2C_EMUL_PARENT,
+ .of_match = i2c_emul_parent_ids,
+};
diff --git a/roms/u-boot/drivers/i2c/i2c-gpio.c b/roms/u-boot/drivers/i2c/i2c-gpio.c
new file mode 100644
index 000000000..cf8f8f403
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/i2c-gpio.c
@@ -0,0 +1,379 @@
+/*
+ * (C) Copyright 2015, Samsung Electronics
+ * Przemyslaw Marczak <p.marczak@samsung.com>
+ *
+ * This file is based on: drivers/i2c/soft-i2c.c,
+ * with added driver-model support and code cleanup.
+ */
+#include <common.h>
+#include <errno.h>
+#include <dm.h>
+#include <i2c.h>
+#include <log.h>
+#include <asm/gpio.h>
+#include <linux/delay.h>
+
+#define DEFAULT_UDELAY 5
+#define RETRIES 0
+#define I2C_ACK 0
+#define I2C_NOACK 1
+
+enum {
+ PIN_SDA = 0,
+ PIN_SCL,
+ PIN_COUNT,
+};
+
+struct i2c_gpio_bus {
+ /**
+ * udelay - delay [us] between GPIO toggle operations,
+ * which is 1/4 of I2C speed clock period.
+ */
+ int udelay;
+ /* sda, scl */
+ struct gpio_desc gpios[PIN_COUNT];
+
+ int (*get_sda)(struct i2c_gpio_bus *bus);
+ void (*set_sda)(struct i2c_gpio_bus *bus, int bit);
+ void (*set_scl)(struct i2c_gpio_bus *bus, int bit);
+};
+
+static int i2c_gpio_sda_get(struct i2c_gpio_bus *bus)
+{
+ struct gpio_desc *sda = &bus->gpios[PIN_SDA];
+
+ return dm_gpio_get_value(sda);
+}
+
+static void i2c_gpio_sda_set(struct i2c_gpio_bus *bus, int bit)
+{
+ struct gpio_desc *sda = &bus->gpios[PIN_SDA];
+ ulong flags;
+
+ if (bit)
+ flags = GPIOD_IS_IN;
+ else
+ flags = GPIOD_IS_OUT;
+ dm_gpio_clrset_flags(sda, GPIOD_MASK_DIR, flags);
+}
+
+static void i2c_gpio_scl_set(struct i2c_gpio_bus *bus, int bit)
+{
+ struct gpio_desc *scl = &bus->gpios[PIN_SCL];
+ int count = 0;
+
+ if (bit) {
+ dm_gpio_clrset_flags(scl, GPIOD_MASK_DIR, GPIOD_IS_IN);
+ while (!dm_gpio_get_value(scl) && count++ < 100000)
+ udelay(1);
+
+ if (!dm_gpio_get_value(scl))
+ pr_err("timeout waiting on slave to release scl\n");
+ } else {
+ dm_gpio_clrset_flags(scl, GPIOD_MASK_DIR, GPIOD_IS_OUT);
+ }
+}
+
+/* variant for output only gpios which cannot support clock stretching */
+static void i2c_gpio_scl_set_output_only(struct i2c_gpio_bus *bus, int bit)
+{
+ struct gpio_desc *scl = &bus->gpios[PIN_SCL];
+ ulong flags = GPIOD_IS_OUT;
+
+ if (bit)
+ flags |= GPIOD_IS_OUT_ACTIVE;
+ dm_gpio_clrset_flags(scl, GPIOD_MASK_DIR, flags);
+}
+
+static void i2c_gpio_write_bit(struct i2c_gpio_bus *bus, int delay, uchar bit)
+{
+ bus->set_scl(bus, 0);
+ udelay(delay);
+ bus->set_sda(bus, bit);
+ udelay(delay);
+ bus->set_scl(bus, 1);
+ udelay(2 * delay);
+}
+
+static int i2c_gpio_read_bit(struct i2c_gpio_bus *bus, int delay)
+{
+ int value;
+
+ bus->set_scl(bus, 1);
+ udelay(delay);
+ value = bus->get_sda(bus);
+ udelay(delay);
+ bus->set_scl(bus, 0);
+ udelay(2 * delay);
+
+ return value;
+}
+
+/* START: High -> Low on SDA while SCL is High */
+static void i2c_gpio_send_start(struct i2c_gpio_bus *bus, int delay)
+{
+ udelay(delay);
+ bus->set_sda(bus, 1);
+ udelay(delay);
+ bus->set_scl(bus, 1);
+ udelay(delay);
+ bus->set_sda(bus, 0);
+ udelay(delay);
+}
+
+/* STOP: Low -> High on SDA while SCL is High */
+static void i2c_gpio_send_stop(struct i2c_gpio_bus *bus, int delay)
+{
+ bus->set_scl(bus, 0);
+ udelay(delay);
+ bus->set_sda(bus, 0);
+ udelay(delay);
+ bus->set_scl(bus, 1);
+ udelay(delay);
+ bus->set_sda(bus, 1);
+ udelay(delay);
+}
+
+/* ack should be I2C_ACK or I2C_NOACK */
+static void i2c_gpio_send_ack(struct i2c_gpio_bus *bus, int delay, int ack)
+{
+ i2c_gpio_write_bit(bus, delay, ack);
+ bus->set_scl(bus, 0);
+ udelay(delay);
+}
+
+/**
+ * Send a reset sequence consisting of 9 clocks with the data signal high
+ * to clock any confused device back into an idle state. Also send a
+ * <stop> at the end of the sequence for belts & suspenders.
+ */
+static void i2c_gpio_send_reset(struct i2c_gpio_bus *bus, int delay)
+{
+ int j;
+
+ for (j = 0; j < 9; j++)
+ i2c_gpio_write_bit(bus, delay, 1);
+
+ i2c_gpio_send_stop(bus, delay);
+}
+
+/* Set sda high with low clock, before reading slave data */
+static void i2c_gpio_sda_high(struct i2c_gpio_bus *bus, int delay)
+{
+ bus->set_scl(bus, 0);
+ udelay(delay);
+ bus->set_sda(bus, 1);
+ udelay(delay);
+}
+
+/* Send 8 bits and look for an acknowledgement */
+static int i2c_gpio_write_byte(struct i2c_gpio_bus *bus, int delay, uchar data)
+{
+ int j;
+ int nack;
+
+ for (j = 0; j < 8; j++) {
+ i2c_gpio_write_bit(bus, delay, data & 0x80);
+ data <<= 1;
+ }
+
+ udelay(delay);
+
+ /* Look for an <ACK>(negative logic) and return it */
+ i2c_gpio_sda_high(bus, delay);
+ nack = i2c_gpio_read_bit(bus, delay);
+
+ return nack; /* not a nack is an ack */
+}
+
+/**
+ * if ack == I2C_ACK, ACK the byte so can continue reading, else
+ * send I2C_NOACK to end the read.
+ */
+static uchar i2c_gpio_read_byte(struct i2c_gpio_bus *bus, int delay, int ack)
+{
+ int data;
+ int j;
+
+ i2c_gpio_sda_high(bus, delay);
+ data = 0;
+ for (j = 0; j < 8; j++) {
+ data <<= 1;
+ data |= i2c_gpio_read_bit(bus, delay);
+ }
+ i2c_gpio_send_ack(bus, delay, ack);
+
+ return data;
+}
+
+/* send start and the slave chip address */
+int i2c_send_slave_addr(struct i2c_gpio_bus *bus, int delay, uchar chip)
+{
+ i2c_gpio_send_start(bus, delay);
+
+ if (i2c_gpio_write_byte(bus, delay, chip)) {
+ i2c_gpio_send_stop(bus, delay);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int i2c_gpio_write_data(struct i2c_gpio_bus *bus, uchar chip,
+ uchar *buffer, int len,
+ bool end_with_repeated_start)
+{
+ unsigned int delay = bus->udelay;
+ int failures = 0;
+
+ debug("%s: chip %x buffer %p len %d\n", __func__, chip, buffer, len);
+
+ if (i2c_send_slave_addr(bus, delay, chip << 1)) {
+ debug("i2c_write, no chip responded %02X\n", chip);
+ return -EIO;
+ }
+
+ while (len-- > 0) {
+ if (i2c_gpio_write_byte(bus, delay, *buffer++))
+ failures++;
+ }
+
+ if (!end_with_repeated_start) {
+ i2c_gpio_send_stop(bus, delay);
+ return failures;
+ }
+
+ if (i2c_send_slave_addr(bus, delay, (chip << 1) | 0x1)) {
+ debug("i2c_write, no chip responded %02X\n", chip);
+ return -EIO;
+ }
+
+ return failures;
+}
+
+static int i2c_gpio_read_data(struct i2c_gpio_bus *bus, uchar chip,
+ uchar *buffer, int len)
+{
+ unsigned int delay = bus->udelay;
+
+ debug("%s: chip %x buffer: %p len %d\n", __func__, chip, buffer, len);
+
+ while (len-- > 0)
+ *buffer++ = i2c_gpio_read_byte(bus, delay, len == 0);
+
+ i2c_gpio_send_stop(bus, delay);
+
+ return 0;
+}
+
+static int i2c_gpio_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs)
+{
+ struct i2c_gpio_bus *bus = dev_get_priv(dev);
+ int ret;
+
+ for (; nmsgs > 0; nmsgs--, msg++) {
+ bool next_is_read = nmsgs > 1 && (msg[1].flags & I2C_M_RD);
+
+ if (msg->flags & I2C_M_RD) {
+ ret = i2c_gpio_read_data(bus, msg->addr, msg->buf,
+ msg->len);
+ } else {
+ ret = i2c_gpio_write_data(bus, msg->addr, msg->buf,
+ msg->len, next_is_read);
+ }
+
+ if (ret)
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static int i2c_gpio_probe(struct udevice *dev, uint chip, uint chip_flags)
+{
+ struct i2c_gpio_bus *bus = dev_get_priv(dev);
+ unsigned int delay = bus->udelay;
+ int ret;
+
+ i2c_gpio_send_start(bus, delay);
+ ret = i2c_gpio_write_byte(bus, delay, (chip << 1) | 0);
+ i2c_gpio_send_stop(bus, delay);
+
+ debug("%s: bus: %d (%s) chip: %x flags: %x ret: %d\n",
+ __func__, dev_seq(dev), dev->name, chip, chip_flags, ret);
+
+ return ret;
+}
+
+static int i2c_gpio_set_bus_speed(struct udevice *dev, unsigned int speed_hz)
+{
+ struct i2c_gpio_bus *bus = dev_get_priv(dev);
+
+ bus->udelay = 1000000 / (speed_hz << 2);
+
+ i2c_gpio_send_reset(bus, bus->udelay);
+
+ return 0;
+}
+
+static int i2c_gpio_drv_probe(struct udevice *dev)
+{
+ if (dev_read_bool(dev, "i2c-gpio,deblock")) {
+ /* @200kHz 9 clocks = 44us, 62us is ok */
+ const unsigned int DELAY_ABORT_SEQ = 62;
+ struct i2c_gpio_bus *bus = dev_get_priv(dev);
+
+ return i2c_deblock_gpio_loop(&bus->gpios[PIN_SDA],
+ &bus->gpios[PIN_SCL],
+ 16, 5, DELAY_ABORT_SEQ);
+ }
+
+ return 0;
+}
+
+static int i2c_gpio_of_to_plat(struct udevice *dev)
+{
+ struct i2c_gpio_bus *bus = dev_get_priv(dev);
+ int ret;
+
+ ret = gpio_request_list_by_name(dev, "gpios", bus->gpios,
+ ARRAY_SIZE(bus->gpios), 0);
+ if (ret < 0)
+ goto error;
+
+ bus->udelay = dev_read_u32_default(dev, "i2c-gpio,delay-us",
+ DEFAULT_UDELAY);
+
+ bus->get_sda = i2c_gpio_sda_get;
+ bus->set_sda = i2c_gpio_sda_set;
+ if (dev_read_bool(dev, "i2c-gpio,scl-output-only"))
+ bus->set_scl = i2c_gpio_scl_set_output_only;
+ else
+ bus->set_scl = i2c_gpio_scl_set;
+
+ return 0;
+error:
+ pr_err("Can't get %s gpios! Error: %d", dev->name, ret);
+ return ret;
+}
+
+static const struct dm_i2c_ops i2c_gpio_ops = {
+ .xfer = i2c_gpio_xfer,
+ .probe_chip = i2c_gpio_probe,
+ .set_bus_speed = i2c_gpio_set_bus_speed,
+};
+
+static const struct udevice_id i2c_gpio_ids[] = {
+ { .compatible = "i2c-gpio" },
+ { }
+};
+
+U_BOOT_DRIVER(i2c_gpio) = {
+ .name = "i2c-gpio",
+ .id = UCLASS_I2C,
+ .of_match = i2c_gpio_ids,
+ .probe = i2c_gpio_drv_probe,
+ .of_to_plat = i2c_gpio_of_to_plat,
+ .priv_auto = sizeof(struct i2c_gpio_bus),
+ .ops = &i2c_gpio_ops,
+};
diff --git a/roms/u-boot/drivers/i2c/i2c-uclass.c b/roms/u-boot/drivers/i2c/i2c-uclass.c
new file mode 100644
index 000000000..be5678521
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/i2c-uclass.c
@@ -0,0 +1,735 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2014 Google, Inc
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <i2c.h>
+#include <log.h>
+#include <malloc.h>
+#include <acpi/acpi_device.h>
+#include <dm/acpi.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/pinctrl.h>
+#if CONFIG_IS_ENABLED(DM_GPIO)
+#include <asm/gpio.h>
+#endif
+#include <linux/delay.h>
+#include "acpi_i2c.h"
+
+#define I2C_MAX_OFFSET_LEN 4
+
+enum {
+ PIN_SDA = 0,
+ PIN_SCL,
+ PIN_COUNT,
+};
+
+/* Useful debugging function */
+void i2c_dump_msgs(struct i2c_msg *msg, int nmsgs)
+{
+ int i;
+
+ for (i = 0; i < nmsgs; i++) {
+ struct i2c_msg *m = &msg[i];
+
+ printf(" %s %x len=%x", m->flags & I2C_M_RD ? "R" : "W",
+ msg->addr, msg->len);
+ if (!(m->flags & I2C_M_RD))
+ printf(": %x", m->buf[0]);
+ printf("\n");
+ }
+}
+
+/**
+ * i2c_setup_offset() - Set up a new message with a chip offset
+ *
+ * @chip: Chip to use
+ * @offset: Byte offset within chip
+ * @offset_buf: Place to put byte offset
+ * @msg: Message buffer
+ * @return 0 if OK, -EADDRNOTAVAIL if the offset length is 0. In that case the
+ * message is still set up but will not contain an offset.
+ */
+static int i2c_setup_offset(struct dm_i2c_chip *chip, uint offset,
+ uint8_t offset_buf[], struct i2c_msg *msg)
+{
+ int offset_len = chip->offset_len;
+
+ msg->addr = chip->chip_addr;
+ if (chip->chip_addr_offset_mask)
+ msg->addr |= (offset >> (8 * offset_len)) &
+ chip->chip_addr_offset_mask;
+ msg->flags = chip->flags & DM_I2C_CHIP_10BIT ? I2C_M_TEN : 0;
+ msg->len = chip->offset_len;
+ msg->buf = offset_buf;
+ if (!offset_len)
+ return -EADDRNOTAVAIL;
+ assert(offset_len <= I2C_MAX_OFFSET_LEN);
+
+ while (offset_len--)
+ *offset_buf++ = offset >> (8 * offset_len);
+
+ return 0;
+}
+
+static int i2c_read_bytewise(struct udevice *dev, uint offset,
+ uint8_t *buffer, int len)
+{
+ struct dm_i2c_chip *chip = dev_get_parent_plat(dev);
+ struct udevice *bus = dev_get_parent(dev);
+ struct dm_i2c_ops *ops = i2c_get_ops(bus);
+ struct i2c_msg msg[2], *ptr;
+ uint8_t offset_buf[I2C_MAX_OFFSET_LEN];
+ int ret;
+ int i;
+
+ for (i = 0; i < len; i++) {
+ if (i2c_setup_offset(chip, offset + i, offset_buf, msg))
+ return -EINVAL;
+ ptr = msg + 1;
+ ptr->addr = msg->addr;
+ ptr->flags = msg->flags | I2C_M_RD;
+ ptr->len = 1;
+ ptr->buf = &buffer[i];
+ ptr++;
+
+ ret = ops->xfer(bus, msg, ptr - msg);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int i2c_write_bytewise(struct udevice *dev, uint offset,
+ const uint8_t *buffer, int len)
+{
+ struct dm_i2c_chip *chip = dev_get_parent_plat(dev);
+ struct udevice *bus = dev_get_parent(dev);
+ struct dm_i2c_ops *ops = i2c_get_ops(bus);
+ struct i2c_msg msg[1];
+ uint8_t buf[I2C_MAX_OFFSET_LEN + 1];
+ int ret;
+ int i;
+
+ for (i = 0; i < len; i++) {
+ if (i2c_setup_offset(chip, offset + i, buf, msg))
+ return -EINVAL;
+ buf[msg->len++] = buffer[i];
+
+ ret = ops->xfer(bus, msg, 1);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int dm_i2c_read(struct udevice *dev, uint offset, uint8_t *buffer, int len)
+{
+ struct dm_i2c_chip *chip = dev_get_parent_plat(dev);
+ struct udevice *bus = dev_get_parent(dev);
+ struct dm_i2c_ops *ops = i2c_get_ops(bus);
+ struct i2c_msg msg[2], *ptr;
+ uint8_t offset_buf[I2C_MAX_OFFSET_LEN];
+ int msg_count;
+
+ if (!ops->xfer)
+ return -ENOSYS;
+ if (chip->flags & DM_I2C_CHIP_RD_ADDRESS)
+ return i2c_read_bytewise(dev, offset, buffer, len);
+ ptr = msg;
+ if (!i2c_setup_offset(chip, offset, offset_buf, ptr))
+ ptr++;
+
+ if (len) {
+ ptr->addr = msg->addr;
+ ptr->flags = chip->flags & DM_I2C_CHIP_10BIT ? I2C_M_TEN : 0;
+ ptr->flags |= I2C_M_RD;
+ ptr->len = len;
+ ptr->buf = buffer;
+ ptr++;
+ }
+ msg_count = ptr - msg;
+
+ return ops->xfer(bus, msg, msg_count);
+}
+
+int dm_i2c_write(struct udevice *dev, uint offset, const uint8_t *buffer,
+ int len)
+{
+ struct dm_i2c_chip *chip = dev_get_parent_plat(dev);
+ struct udevice *bus = dev_get_parent(dev);
+ struct dm_i2c_ops *ops = i2c_get_ops(bus);
+ struct i2c_msg msg[1];
+
+ if (!ops->xfer)
+ return -ENOSYS;
+
+ if (chip->flags & DM_I2C_CHIP_WR_ADDRESS)
+ return i2c_write_bytewise(dev, offset, buffer, len);
+ /*
+ * The simple approach would be to send two messages here: one to
+ * set the offset and one to write the bytes. However some drivers
+ * will not be expecting this, and some chips won't like how the
+ * driver presents this on the I2C bus.
+ *
+ * The API does not support separate offset and data. We could extend
+ * it with a flag indicating that there is data in the next message
+ * that needs to be processed in the same transaction. We could
+ * instead add an additional buffer to each message. For now, handle
+ * this in the uclass since it isn't clear what the impact on drivers
+ * would be with this extra complication. Unfortunately this means
+ * copying the message.
+ *
+ * Use the stack for small messages, malloc() for larger ones. We
+ * need to allow space for the offset (up to 4 bytes) and the message
+ * itself.
+ */
+ if (len < 64) {
+ uint8_t buf[I2C_MAX_OFFSET_LEN + len];
+
+ i2c_setup_offset(chip, offset, buf, msg);
+ msg->len += len;
+ memcpy(buf + chip->offset_len, buffer, len);
+
+ return ops->xfer(bus, msg, 1);
+ } else {
+ uint8_t *buf;
+ int ret;
+
+ buf = malloc(I2C_MAX_OFFSET_LEN + len);
+ if (!buf)
+ return -ENOMEM;
+ i2c_setup_offset(chip, offset, buf, msg);
+ msg->len += len;
+ memcpy(buf + chip->offset_len, buffer, len);
+
+ ret = ops->xfer(bus, msg, 1);
+ free(buf);
+ return ret;
+ }
+}
+
+int dm_i2c_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs)
+{
+ struct udevice *bus = dev_get_parent(dev);
+ struct dm_i2c_ops *ops = i2c_get_ops(bus);
+
+ if (!ops->xfer)
+ return -ENOSYS;
+
+ return ops->xfer(bus, msg, nmsgs);
+}
+
+int dm_i2c_reg_read(struct udevice *dev, uint offset)
+{
+ uint8_t val;
+ int ret;
+
+ ret = dm_i2c_read(dev, offset, &val, 1);
+ if (ret < 0)
+ return ret;
+
+ return val;
+}
+
+int dm_i2c_reg_write(struct udevice *dev, uint offset, uint value)
+{
+ uint8_t val = value;
+
+ return dm_i2c_write(dev, offset, &val, 1);
+}
+
+/**
+ * i2c_probe_chip() - probe for a chip on a bus
+ *
+ * @bus: Bus to probe
+ * @chip_addr: Chip address to probe
+ * @flags: Flags for the chip
+ * @return 0 if found, -ENOSYS if the driver is invalid, -EREMOTEIO if the chip
+ * does not respond to probe
+ */
+static int i2c_probe_chip(struct udevice *bus, uint chip_addr,
+ enum dm_i2c_chip_flags chip_flags)
+{
+ struct dm_i2c_ops *ops = i2c_get_ops(bus);
+ struct i2c_msg msg[1];
+ int ret;
+
+ if (ops->probe_chip) {
+ ret = ops->probe_chip(bus, chip_addr, chip_flags);
+ if (!ret || ret != -ENOSYS)
+ return ret;
+ }
+
+ if (!ops->xfer)
+ return -ENOSYS;
+
+ /* Probe with a zero-length message */
+ msg->addr = chip_addr;
+ msg->flags = chip_flags & DM_I2C_CHIP_10BIT ? I2C_M_TEN : 0;
+ msg->len = 0;
+ msg->buf = NULL;
+
+ return ops->xfer(bus, msg, 1);
+}
+
+static int i2c_bind_driver(struct udevice *bus, uint chip_addr, uint offset_len,
+ struct udevice **devp)
+{
+ struct dm_i2c_chip *chip;
+ char name[30], *str;
+ struct udevice *dev;
+ int ret;
+
+ snprintf(name, sizeof(name), "generic_%x", chip_addr);
+ str = strdup(name);
+ if (!str)
+ return -ENOMEM;
+ ret = device_bind_driver(bus, "i2c_generic_chip_drv", str, &dev);
+ debug("%s: device_bind_driver: ret=%d\n", __func__, ret);
+ if (ret)
+ goto err_bind;
+
+ /* Tell the device what we know about it */
+ chip = dev_get_parent_plat(dev);
+ chip->chip_addr = chip_addr;
+ chip->offset_len = offset_len;
+ ret = device_probe(dev);
+ debug("%s: device_probe: ret=%d\n", __func__, ret);
+ if (ret)
+ goto err_probe;
+
+ *devp = dev;
+ return 0;
+
+err_probe:
+ /*
+ * If the device failed to probe, unbind it. There is nothing there
+ * on the bus so we don't want to leave it lying around
+ */
+ device_unbind(dev);
+err_bind:
+ free(str);
+ return ret;
+}
+
+int i2c_get_chip(struct udevice *bus, uint chip_addr, uint offset_len,
+ struct udevice **devp)
+{
+ struct udevice *dev;
+
+ debug("%s: Searching bus '%s' for address %02x: ", __func__,
+ bus->name, chip_addr);
+ for (device_find_first_child(bus, &dev); dev;
+ device_find_next_child(&dev)) {
+ struct dm_i2c_chip *chip = dev_get_parent_plat(dev);
+ int ret;
+
+ if (chip->chip_addr == (chip_addr &
+ ~chip->chip_addr_offset_mask)) {
+ ret = device_probe(dev);
+ debug("found, ret=%d\n", ret);
+ if (ret)
+ return ret;
+ *devp = dev;
+ return 0;
+ }
+ }
+ debug("not found\n");
+ return i2c_bind_driver(bus, chip_addr, offset_len, devp);
+}
+
+int i2c_get_chip_for_busnum(int busnum, int chip_addr, uint offset_len,
+ struct udevice **devp)
+{
+ struct udevice *bus;
+ int ret;
+
+ ret = uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus);
+ if (ret) {
+ debug("Cannot find I2C bus %d\n", busnum);
+ return ret;
+ }
+
+ /* detect the presence of the chip on the bus */
+ ret = i2c_probe_chip(bus, chip_addr, 0);
+ debug("%s: bus='%s', address %02x, ret=%d\n", __func__, bus->name,
+ chip_addr, ret);
+ if (ret) {
+ debug("Cannot detect I2C chip %02x on bus %d\n", chip_addr,
+ busnum);
+ return ret;
+ }
+
+ ret = i2c_get_chip(bus, chip_addr, offset_len, devp);
+ if (ret) {
+ debug("Cannot find I2C chip %02x on bus %d\n", chip_addr,
+ busnum);
+ return ret;
+ }
+
+ return 0;
+}
+
+int dm_i2c_probe(struct udevice *bus, uint chip_addr, uint chip_flags,
+ struct udevice **devp)
+{
+ int ret;
+
+ *devp = NULL;
+
+ /* First probe that chip */
+ ret = i2c_probe_chip(bus, chip_addr, chip_flags);
+ debug("%s: bus='%s', address %02x, ret=%d\n", __func__, bus->name,
+ chip_addr, ret);
+ if (ret)
+ return ret;
+
+ /* The chip was found, see if we have a driver, and probe it */
+ ret = i2c_get_chip(bus, chip_addr, 1, devp);
+ debug("%s: i2c_get_chip: ret=%d\n", __func__, ret);
+
+ return ret;
+}
+
+int dm_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
+{
+ struct dm_i2c_ops *ops = i2c_get_ops(bus);
+ struct dm_i2c_bus *i2c = dev_get_uclass_priv(bus);
+ int ret;
+
+ /*
+ * If we have a method, call it. If not then the driver probably wants
+ * to deal with speed changes on the next transfer. It can easily read
+ * the current speed from this uclass
+ */
+ if (ops->set_bus_speed) {
+ ret = ops->set_bus_speed(bus, speed);
+ if (ret)
+ return ret;
+ }
+ i2c->speed_hz = speed;
+
+ return 0;
+}
+
+int dm_i2c_get_bus_speed(struct udevice *bus)
+{
+ struct dm_i2c_ops *ops = i2c_get_ops(bus);
+ struct dm_i2c_bus *i2c = dev_get_uclass_priv(bus);
+
+ if (!ops->get_bus_speed)
+ return i2c->speed_hz;
+
+ return ops->get_bus_speed(bus);
+}
+
+int i2c_set_chip_flags(struct udevice *dev, uint flags)
+{
+ struct udevice *bus = dev->parent;
+ struct dm_i2c_chip *chip = dev_get_parent_plat(dev);
+ struct dm_i2c_ops *ops = i2c_get_ops(bus);
+ int ret;
+
+ if (ops->set_flags) {
+ ret = ops->set_flags(dev, flags);
+ if (ret)
+ return ret;
+ }
+ chip->flags = flags;
+
+ return 0;
+}
+
+int i2c_get_chip_flags(struct udevice *dev, uint *flagsp)
+{
+ struct dm_i2c_chip *chip = dev_get_parent_plat(dev);
+
+ *flagsp = chip->flags;
+
+ return 0;
+}
+
+int i2c_set_chip_offset_len(struct udevice *dev, uint offset_len)
+{
+ struct dm_i2c_chip *chip = dev_get_parent_plat(dev);
+
+ if (offset_len > I2C_MAX_OFFSET_LEN)
+ return log_ret(-EINVAL);
+ chip->offset_len = offset_len;
+
+ return 0;
+}
+
+int i2c_get_chip_offset_len(struct udevice *dev)
+{
+ struct dm_i2c_chip *chip = dev_get_parent_plat(dev);
+
+ return chip->offset_len;
+}
+
+int i2c_set_chip_addr_offset_mask(struct udevice *dev, uint mask)
+{
+ struct dm_i2c_chip *chip = dev_get_parent_plat(dev);
+
+ chip->chip_addr_offset_mask = mask;
+
+ return 0;
+}
+
+uint i2c_get_chip_addr_offset_mask(struct udevice *dev)
+{
+ struct dm_i2c_chip *chip = dev_get_parent_plat(dev);
+
+ return chip->chip_addr_offset_mask;
+}
+
+#if CONFIG_IS_ENABLED(DM_GPIO)
+static void i2c_gpio_set_pin(struct gpio_desc *pin, int bit)
+{
+ if (bit)
+ dm_gpio_set_dir_flags(pin, GPIOD_IS_IN);
+ else
+ dm_gpio_set_dir_flags(pin, GPIOD_IS_OUT |
+ GPIOD_ACTIVE_LOW |
+ GPIOD_IS_OUT_ACTIVE);
+}
+
+static int i2c_gpio_get_pin(struct gpio_desc *pin)
+{
+ return dm_gpio_get_value(pin);
+}
+
+int i2c_deblock_gpio_loop(struct gpio_desc *sda_pin,
+ struct gpio_desc *scl_pin,
+ unsigned int scl_count,
+ unsigned int start_count,
+ unsigned int delay)
+{
+ int i, ret = -EREMOTEIO;
+
+ i2c_gpio_set_pin(sda_pin, 1);
+ i2c_gpio_set_pin(scl_pin, 1);
+ udelay(delay);
+
+ /* Toggle SCL until slave release SDA */
+ for (; scl_count; --scl_count) {
+ i2c_gpio_set_pin(scl_pin, 1);
+ udelay(delay);
+ i2c_gpio_set_pin(scl_pin, 0);
+ udelay(delay);
+ if (i2c_gpio_get_pin(sda_pin)) {
+ ret = 0;
+ break;
+ }
+ }
+
+ if (!ret && start_count) {
+ for (i = 0; i < start_count; i++) {
+ /* Send start condition */
+ udelay(delay);
+ i2c_gpio_set_pin(sda_pin, 1);
+ udelay(delay);
+ i2c_gpio_set_pin(scl_pin, 1);
+ udelay(delay);
+ i2c_gpio_set_pin(sda_pin, 0);
+ udelay(delay);
+ i2c_gpio_set_pin(scl_pin, 0);
+ }
+ }
+
+ /* Then, send I2C stop */
+ i2c_gpio_set_pin(sda_pin, 0);
+ udelay(delay);
+
+ i2c_gpio_set_pin(scl_pin, 1);
+ udelay(delay);
+
+ i2c_gpio_set_pin(sda_pin, 1);
+ udelay(delay);
+
+ if (!i2c_gpio_get_pin(sda_pin) || !i2c_gpio_get_pin(scl_pin))
+ ret = -EREMOTEIO;
+
+ return ret;
+}
+
+static int i2c_deblock_gpio(struct udevice *bus)
+{
+ struct gpio_desc gpios[PIN_COUNT];
+ int ret, ret0;
+
+ ret = gpio_request_list_by_name(bus, "gpios", gpios,
+ ARRAY_SIZE(gpios), GPIOD_IS_IN);
+ if (ret != ARRAY_SIZE(gpios)) {
+ debug("%s: I2C Node '%s' has no 'gpios' property %s\n",
+ __func__, dev_read_name(bus), bus->name);
+ if (ret >= 0) {
+ gpio_free_list(bus, gpios, ret);
+ ret = -ENOENT;
+ }
+ goto out;
+ }
+
+ ret = pinctrl_select_state(bus, "gpio");
+ if (ret) {
+ debug("%s: I2C Node '%s' has no 'gpio' pinctrl state. %s\n",
+ __func__, dev_read_name(bus), bus->name);
+ goto out_no_pinctrl;
+ }
+
+ ret0 = i2c_deblock_gpio_loop(&gpios[PIN_SDA], &gpios[PIN_SCL], 9, 0, 5);
+
+ ret = pinctrl_select_state(bus, "default");
+ if (ret) {
+ debug("%s: I2C Node '%s' has no 'default' pinctrl state. %s\n",
+ __func__, dev_read_name(bus), bus->name);
+ }
+
+ ret = !ret ? ret0 : ret;
+
+out_no_pinctrl:
+ gpio_free_list(bus, gpios, ARRAY_SIZE(gpios));
+out:
+ return ret;
+}
+#else
+static int i2c_deblock_gpio(struct udevice *bus)
+{
+ return -ENOSYS;
+}
+#endif /* DM_GPIO */
+
+int i2c_deblock(struct udevice *bus)
+{
+ struct dm_i2c_ops *ops = i2c_get_ops(bus);
+
+ if (!ops->deblock)
+ return i2c_deblock_gpio(bus);
+
+ return ops->deblock(bus);
+}
+
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
+int i2c_chip_of_to_plat(struct udevice *dev, struct dm_i2c_chip *chip)
+{
+ int addr;
+
+ chip->offset_len = dev_read_u32_default(dev, "u-boot,i2c-offset-len",
+ 1);
+ chip->flags = 0;
+ addr = dev_read_u32_default(dev, "reg", -1);
+ if (addr == -1) {
+ debug("%s: I2C Node '%s' has no 'reg' property %s\n", __func__,
+ dev_read_name(dev), dev->name);
+ return log_ret(-EINVAL);
+ }
+ chip->chip_addr = addr;
+
+ return 0;
+}
+#endif
+
+static int i2c_pre_probe(struct udevice *dev)
+{
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
+ struct dm_i2c_bus *i2c = dev_get_uclass_priv(dev);
+ unsigned int max = 0;
+ ofnode node;
+ int ret;
+
+ i2c->max_transaction_bytes = 0;
+ dev_for_each_subnode(node, dev) {
+ ret = ofnode_read_u32(node,
+ "u-boot,i2c-transaction-bytes",
+ &max);
+ if (!ret && max > i2c->max_transaction_bytes)
+ i2c->max_transaction_bytes = max;
+ }
+
+ debug("%s: I2C bus: %s max transaction bytes: %d\n", __func__,
+ dev->name, i2c->max_transaction_bytes);
+#endif
+ return 0;
+}
+
+static int i2c_post_probe(struct udevice *dev)
+{
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
+ struct dm_i2c_bus *i2c = dev_get_uclass_priv(dev);
+
+ i2c->speed_hz = dev_read_u32_default(dev, "clock-frequency",
+ I2C_SPEED_STANDARD_RATE);
+
+ return dm_i2c_set_bus_speed(dev, i2c->speed_hz);
+#else
+ return 0;
+#endif
+}
+
+static int i2c_child_post_bind(struct udevice *dev)
+{
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
+ struct dm_i2c_chip *plat = dev_get_parent_plat(dev);
+
+ if (!dev_has_ofnode(dev))
+ return 0;
+ return i2c_chip_of_to_plat(dev, plat);
+#else
+ return 0;
+#endif
+}
+
+static int i2c_post_bind(struct udevice *dev)
+{
+ int ret = 0;
+
+ debug("%s: %s, seq=%d\n", __func__, dev->name, dev_seq(dev));
+
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
+ ret = dm_scan_fdt_dev(dev);
+#endif
+ return ret;
+}
+
+UCLASS_DRIVER(i2c) = {
+ .id = UCLASS_I2C,
+ .name = "i2c",
+ .flags = DM_UC_FLAG_SEQ_ALIAS,
+ .post_bind = i2c_post_bind,
+ .pre_probe = i2c_pre_probe,
+ .post_probe = i2c_post_probe,
+ .per_device_auto = sizeof(struct dm_i2c_bus),
+ .per_child_plat_auto = sizeof(struct dm_i2c_chip),
+ .child_post_bind = i2c_child_post_bind,
+};
+
+UCLASS_DRIVER(i2c_generic) = {
+ .id = UCLASS_I2C_GENERIC,
+ .name = "i2c_generic",
+};
+
+static const struct udevice_id generic_chip_i2c_ids[] = {
+ { .compatible = "i2c-chip", .data = I2C_DEVICE_GENERIC },
+#if CONFIG_IS_ENABLED(ACPIGEN)
+ { .compatible = "hid-over-i2c", .data = I2C_DEVICE_HID_OVER_I2C },
+#endif
+ { }
+};
+
+U_BOOT_DRIVER(i2c_generic_chip_drv) = {
+ .name = "i2c_generic_chip_drv",
+ .id = UCLASS_I2C_GENERIC,
+ .of_match = generic_chip_i2c_ids,
+#if CONFIG_IS_ENABLED(ACPIGEN)
+ .of_to_plat = acpi_i2c_of_to_plat,
+ .priv_auto = sizeof(struct acpi_i2c_priv),
+#endif
+ ACPI_OPS_PTR(&acpi_i2c_ops)
+};
diff --git a/roms/u-boot/drivers/i2c/i2c-uniphier-f.c b/roms/u-boot/drivers/i2c/i2c-uniphier-f.c
new file mode 100644
index 000000000..9d6f1688c
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/i2c-uniphier-f.c
@@ -0,0 +1,331 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2014 Panasonic Corporation
+ * Copyright (C) 2015-2016 Socionext Inc.
+ * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
+ */
+
+#include <dm/device_compat.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/sizes.h>
+#include <linux/types.h>
+#include <dm.h>
+#include <i2c.h>
+#include <fdtdec.h>
+
+struct uniphier_fi2c_regs {
+ u32 cr; /* control register */
+#define I2C_CR_MST (1 << 3) /* master mode */
+#define I2C_CR_STA (1 << 2) /* start condition */
+#define I2C_CR_STO (1 << 1) /* stop condition */
+#define I2C_CR_NACK (1 << 0) /* not ACK */
+ u32 dttx; /* send FIFO (write-only) */
+#define dtrx dttx /* receive FIFO (read-only) */
+#define I2C_DTTX_CMD (1 << 8) /* send command (slave addr) */
+#define I2C_DTTX_RD (1 << 0) /* read */
+ u32 __reserved; /* no register at offset 0x08 */
+ u32 slad; /* slave address */
+ u32 cyc; /* clock cycle control */
+ u32 lctl; /* clock low period control */
+ u32 ssut; /* restart/stop setup time control */
+ u32 dsut; /* data setup time control */
+ u32 intr; /* interrupt status */
+ u32 ie; /* interrupt enable */
+ u32 ic; /* interrupt clear */
+#define I2C_INT_TE (1 << 9) /* TX FIFO empty */
+#define I2C_INT_RB (1 << 4) /* received specified bytes */
+#define I2C_INT_NA (1 << 2) /* no answer */
+#define I2C_INT_AL (1 << 1) /* arbitration lost */
+ u32 sr; /* status register */
+#define I2C_SR_DB (1 << 12) /* device busy */
+#define I2C_SR_BB (1 << 8) /* bus busy */
+#define I2C_SR_RFF (1 << 3) /* Rx FIFO full */
+#define I2C_SR_RNE (1 << 2) /* Rx FIFO not empty */
+#define I2C_SR_TNF (1 << 1) /* Tx FIFO not full */
+#define I2C_SR_TFE (1 << 0) /* Tx FIFO empty */
+ u32 __reserved2; /* no register at offset 0x30 */
+ u32 rst; /* reset control */
+#define I2C_RST_TBRST (1 << 2) /* clear Tx FIFO */
+#define I2C_RST_RBRST (1 << 1) /* clear Rx FIFO */
+#define I2C_RST_RST (1 << 0) /* forcible bus reset */
+ u32 bm; /* bus monitor */
+ u32 noise; /* noise filter control */
+ u32 tbc; /* Tx byte count setting */
+ u32 rbc; /* Rx byte count setting */
+ u32 tbcm; /* Tx byte count monitor */
+ u32 rbcm; /* Rx byte count monitor */
+ u32 brst; /* bus reset */
+#define I2C_BRST_FOEN (1 << 1) /* normal operation */
+#define I2C_BRST_RSCLO (1 << 0) /* release SCL low fixing */
+};
+
+#define FIOCLK 50000000
+
+struct uniphier_fi2c_priv {
+ struct udevice *dev;
+ struct uniphier_fi2c_regs __iomem *regs; /* register base */
+ unsigned long fioclk; /* internal operation clock */
+ unsigned long timeout; /* time out (us) */
+};
+
+static void uniphier_fi2c_reset(struct uniphier_fi2c_priv *priv)
+{
+ writel(I2C_RST_RST, &priv->regs->rst);
+}
+
+static int uniphier_fi2c_check_bus_busy(struct uniphier_fi2c_priv *priv)
+{
+ u32 val;
+ int ret;
+
+ ret = readl_poll_timeout(&priv->regs->sr, val, !(val & I2C_SR_DB), 100);
+ if (ret < 0) {
+ dev_dbg(priv->dev, "error: device busy too long. reset...\n");
+ uniphier_fi2c_reset(priv);
+ }
+
+ return ret;
+}
+
+static int uniphier_fi2c_probe(struct udevice *dev)
+{
+ fdt_addr_t addr;
+ struct uniphier_fi2c_priv *priv = dev_get_priv(dev);
+
+ addr = dev_read_addr(dev);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ priv->regs = devm_ioremap(dev, addr, SZ_128);
+ if (!priv->regs)
+ return -ENOMEM;
+
+ priv->fioclk = FIOCLK;
+
+ priv->dev = dev;
+
+ /* bus forcible reset */
+ uniphier_fi2c_reset(priv);
+
+ writel(I2C_BRST_FOEN | I2C_BRST_RSCLO, &priv->regs->brst);
+
+ return 0;
+}
+
+static int wait_for_irq(struct uniphier_fi2c_priv *priv, u32 flags,
+ bool *stop)
+{
+ u32 irq;
+ int ret;
+
+ ret = readl_poll_timeout(&priv->regs->intr, irq, irq & flags,
+ priv->timeout);
+ if (ret < 0) {
+ dev_dbg(priv->dev, "error: time out\n");
+ return ret;
+ }
+
+ if (irq & I2C_INT_AL) {
+ dev_dbg(priv->dev, "error: arbitration lost\n");
+ *stop = false;
+ return ret;
+ }
+
+ if (irq & I2C_INT_NA) {
+ dev_dbg(priv->dev, "error: no answer\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int issue_stop(struct uniphier_fi2c_priv *priv, int old_ret)
+{
+ int ret;
+
+ dev_dbg(priv->dev, "stop condition\n");
+ writel(I2C_CR_MST | I2C_CR_STO, &priv->regs->cr);
+
+ ret = uniphier_fi2c_check_bus_busy(priv);
+ if (ret < 0)
+ dev_dbg(priv->dev, "error: device busy after operation\n");
+
+ return old_ret ? old_ret : ret;
+}
+
+static int uniphier_fi2c_transmit(struct uniphier_fi2c_priv *priv, uint addr,
+ uint len, const u8 *buf, bool *stop)
+{
+ int ret;
+ const u32 irq_flags = I2C_INT_TE | I2C_INT_NA | I2C_INT_AL;
+ struct uniphier_fi2c_regs __iomem *regs = priv->regs;
+
+ dev_dbg(priv->dev, "%s: addr = %x, len = %d\n", __func__, addr, len);
+
+ writel(I2C_DTTX_CMD | addr << 1, &regs->dttx);
+
+ writel(irq_flags, &regs->ie);
+ writel(irq_flags, &regs->ic);
+
+ dev_dbg(priv->dev, "start condition\n");
+ writel(I2C_CR_MST | I2C_CR_STA, &regs->cr);
+
+ ret = wait_for_irq(priv, irq_flags, stop);
+ if (ret < 0)
+ goto error;
+
+ while (len--) {
+ dev_dbg(priv->dev, "sending %x\n", *buf);
+ writel(*buf++, &regs->dttx);
+
+ writel(irq_flags, &regs->ic);
+
+ ret = wait_for_irq(priv, irq_flags, stop);
+ if (ret < 0)
+ goto error;
+ }
+
+error:
+ writel(irq_flags, &regs->ic);
+
+ if (*stop)
+ ret = issue_stop(priv, ret);
+
+ return ret;
+}
+
+static int uniphier_fi2c_receive(struct uniphier_fi2c_priv *priv, uint addr,
+ uint len, u8 *buf, bool *stop)
+{
+ int ret = 0;
+ const u32 irq_flags = I2C_INT_RB | I2C_INT_NA | I2C_INT_AL;
+ struct uniphier_fi2c_regs __iomem *regs = priv->regs;
+
+ dev_dbg(priv->dev, "%s: addr = %x, len = %d\n", __func__, addr, len);
+
+ /*
+ * In case 'len == 0', only the slave address should be sent
+ * for probing, which is covered by the transmit function.
+ */
+ if (len == 0)
+ return uniphier_fi2c_transmit(priv, addr, len, buf, stop);
+
+ writel(I2C_DTTX_CMD | I2C_DTTX_RD | addr << 1, &regs->dttx);
+
+ writel(0, &regs->rbc);
+ writel(irq_flags, &regs->ie);
+ writel(irq_flags, &regs->ic);
+
+ dev_dbg(priv->dev, "start condition\n");
+ writel(I2C_CR_MST | I2C_CR_STA | (len == 1 ? I2C_CR_NACK : 0),
+ &regs->cr);
+
+ while (len--) {
+ ret = wait_for_irq(priv, irq_flags, stop);
+ if (ret < 0)
+ goto error;
+
+ *buf++ = readl(&regs->dtrx);
+ dev_dbg(priv->dev, "received %x\n", *(buf - 1));
+
+ if (len == 1)
+ writel(I2C_CR_MST | I2C_CR_NACK, &regs->cr);
+
+ writel(irq_flags, &regs->ic);
+ }
+
+error:
+ writel(irq_flags, &regs->ic);
+
+ if (*stop)
+ ret = issue_stop(priv, ret);
+
+ return ret;
+}
+
+static int uniphier_fi2c_xfer(struct udevice *bus, struct i2c_msg *msg,
+ int nmsgs)
+{
+ int ret;
+ struct uniphier_fi2c_priv *priv = dev_get_priv(bus);
+ bool stop;
+
+ ret = uniphier_fi2c_check_bus_busy(priv);
+ if (ret < 0)
+ return ret;
+
+ for (; nmsgs > 0; nmsgs--, msg++) {
+ /* If next message is read, skip the stop condition */
+ stop = nmsgs > 1 && msg[1].flags & I2C_M_RD ? false : true;
+
+ if (msg->flags & I2C_M_RD)
+ ret = uniphier_fi2c_receive(priv, msg->addr, msg->len,
+ msg->buf, &stop);
+ else
+ ret = uniphier_fi2c_transmit(priv, msg->addr, msg->len,
+ msg->buf, &stop);
+
+ if (ret < 0)
+ break;
+ }
+
+ return ret;
+}
+
+static int uniphier_fi2c_set_bus_speed(struct udevice *bus, unsigned int speed)
+{
+ int ret;
+ unsigned int clk_count;
+ struct uniphier_fi2c_priv *priv = dev_get_priv(bus);
+ struct uniphier_fi2c_regs __iomem *regs = priv->regs;
+
+ /* max supported frequency is 400 kHz */
+ if (speed > I2C_SPEED_FAST_RATE)
+ return -EINVAL;
+
+ ret = uniphier_fi2c_check_bus_busy(priv);
+ if (ret < 0)
+ return ret;
+
+ /* make sure the bus is idle when changing the frequency */
+ writel(I2C_BRST_RSCLO, &regs->brst);
+
+ clk_count = priv->fioclk / speed;
+
+ writel(clk_count, &regs->cyc);
+ writel(clk_count / 2, &regs->lctl);
+ writel(clk_count / 2, &regs->ssut);
+ writel(clk_count / 16, &regs->dsut);
+
+ writel(I2C_BRST_FOEN | I2C_BRST_RSCLO, &regs->brst);
+
+ /*
+ * Theoretically, each byte can be transferred in
+ * 1000000 * 9 / speed usec.
+ * This time out value is long enough.
+ */
+ priv->timeout = 100000000L / speed;
+
+ return 0;
+}
+
+static const struct dm_i2c_ops uniphier_fi2c_ops = {
+ .xfer = uniphier_fi2c_xfer,
+ .set_bus_speed = uniphier_fi2c_set_bus_speed,
+};
+
+static const struct udevice_id uniphier_fi2c_of_match[] = {
+ { .compatible = "socionext,uniphier-fi2c" },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(uniphier_fi2c) = {
+ .name = "uniphier-fi2c",
+ .id = UCLASS_I2C,
+ .of_match = uniphier_fi2c_of_match,
+ .probe = uniphier_fi2c_probe,
+ .priv_auto = sizeof(struct uniphier_fi2c_priv),
+ .ops = &uniphier_fi2c_ops,
+};
diff --git a/roms/u-boot/drivers/i2c/i2c-uniphier.c b/roms/u-boot/drivers/i2c/i2c-uniphier.c
new file mode 100644
index 000000000..6eafbeeef
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/i2c-uniphier.c
@@ -0,0 +1,219 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2014 Panasonic Corporation
+ * Copyright (C) 2015-2016 Socionext Inc.
+ * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
+ */
+
+#include <dm/device_compat.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/sizes.h>
+#include <linux/types.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <i2c.h>
+
+struct uniphier_i2c_regs {
+ u32 dtrm; /* data transmission */
+#define I2C_DTRM_STA (1 << 10)
+#define I2C_DTRM_STO (1 << 9)
+#define I2C_DTRM_NACK (1 << 8)
+#define I2C_DTRM_RD (1 << 0)
+ u32 drec; /* data reception */
+#define I2C_DREC_STS (1 << 12)
+#define I2C_DREC_LRB (1 << 11)
+#define I2C_DREC_LAB (1 << 9)
+ u32 myad; /* slave address */
+ u32 clk; /* clock frequency control */
+ u32 brst; /* bus reset */
+#define I2C_BRST_FOEN (1 << 1)
+#define I2C_BRST_BRST (1 << 0)
+ u32 hold; /* hold time control */
+ u32 bsts; /* bus status monitor */
+ u32 noise; /* noise filter control */
+ u32 setup; /* setup time control */
+};
+
+#define IOBUS_FREQ 100000000
+
+struct uniphier_i2c_priv {
+ struct udevice *dev;
+ struct uniphier_i2c_regs __iomem *regs; /* register base */
+ unsigned long input_clk; /* master clock (Hz) */
+ unsigned long wait_us; /* wait for every byte transfer (us) */
+};
+
+static int uniphier_i2c_probe(struct udevice *dev)
+{
+ fdt_addr_t addr;
+ struct uniphier_i2c_priv *priv = dev_get_priv(dev);
+
+ addr = dev_read_addr(dev);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ priv->regs = devm_ioremap(dev, addr, SZ_64);
+ if (!priv->regs)
+ return -ENOMEM;
+
+ priv->input_clk = IOBUS_FREQ;
+
+ priv->dev = dev;
+
+ /* deassert reset */
+ writel(0x3, &priv->regs->brst);
+
+ return 0;
+}
+
+static int send_and_recv_byte(struct uniphier_i2c_priv *priv, u32 dtrm)
+{
+ writel(dtrm, &priv->regs->dtrm);
+
+ /*
+ * This controller only provides interruption to inform the completion
+ * of each byte transfer. (No status register to poll it.)
+ * Unfortunately, U-Boot does not have a good support of interrupt.
+ * Wait for a while.
+ */
+ udelay(priv->wait_us);
+
+ return readl(&priv->regs->drec);
+}
+
+static int send_byte(struct uniphier_i2c_priv *priv, u32 dtrm, bool *stop)
+{
+ int ret = 0;
+ u32 drec;
+
+ drec = send_and_recv_byte(priv, dtrm);
+
+ if (drec & I2C_DREC_LAB) {
+ dev_dbg(priv->dev, "uniphier_i2c: bus arbitration failed\n");
+ *stop = false;
+ ret = -EREMOTEIO;
+ }
+ if (drec & I2C_DREC_LRB) {
+ dev_dbg(priv->dev, "uniphier_i2c: slave did not return ACK\n");
+ ret = -EREMOTEIO;
+ }
+ return ret;
+}
+
+static int uniphier_i2c_transmit(struct uniphier_i2c_priv *priv, uint addr,
+ uint len, const u8 *buf, bool *stop)
+{
+ int ret;
+
+ dev_dbg(priv->dev, "%s: addr = %x, len = %d\n", __func__, addr, len);
+
+ ret = send_byte(priv, I2C_DTRM_STA | I2C_DTRM_NACK | addr << 1, stop);
+ if (ret < 0)
+ goto fail;
+
+ while (len--) {
+ ret = send_byte(priv, I2C_DTRM_NACK | *buf++, stop);
+ if (ret < 0)
+ goto fail;
+ }
+
+fail:
+ if (*stop)
+ writel(I2C_DTRM_STO | I2C_DTRM_NACK, &priv->regs->dtrm);
+
+ return ret;
+}
+
+static int uniphier_i2c_receive(struct uniphier_i2c_priv *priv, uint addr,
+ uint len, u8 *buf, bool *stop)
+{
+ int ret;
+
+ dev_dbg(priv->dev, "%s: addr = %x, len = %d\n", __func__, addr, len);
+
+ ret = send_byte(priv, I2C_DTRM_STA | I2C_DTRM_NACK |
+ I2C_DTRM_RD | addr << 1, stop);
+ if (ret < 0)
+ goto fail;
+
+ while (len--)
+ *buf++ = send_and_recv_byte(priv, len ? 0 : I2C_DTRM_NACK);
+
+fail:
+ if (*stop)
+ writel(I2C_DTRM_STO | I2C_DTRM_NACK, &priv->regs->dtrm);
+
+ return ret;
+}
+
+static int uniphier_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
+ int nmsgs)
+{
+ int ret = 0;
+ struct uniphier_i2c_priv *priv = dev_get_priv(bus);
+ bool stop;
+
+ for (; nmsgs > 0; nmsgs--, msg++) {
+ /* If next message is read, skip the stop condition */
+ stop = nmsgs > 1 && msg[1].flags & I2C_M_RD ? false : true;
+
+ if (msg->flags & I2C_M_RD)
+ ret = uniphier_i2c_receive(priv, msg->addr, msg->len,
+ msg->buf, &stop);
+ else
+ ret = uniphier_i2c_transmit(priv, msg->addr, msg->len,
+ msg->buf, &stop);
+
+ if (ret < 0)
+ break;
+ }
+
+ return ret;
+}
+
+static int uniphier_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
+{
+ struct uniphier_i2c_priv *priv = dev_get_priv(bus);
+
+ /* max supported frequency is 400 kHz */
+ if (speed > I2C_SPEED_FAST_RATE)
+ return -EINVAL;
+
+ /* bus reset: make sure the bus is idle when change the frequency */
+ writel(0x1, &priv->regs->brst);
+
+ writel((priv->input_clk / speed / 2 << 16) | (priv->input_clk / speed),
+ &priv->regs->clk);
+
+ writel(0x3, &priv->regs->brst);
+
+ /*
+ * Theoretically, each byte can be transferred in
+ * 1000000 * 9 / speed usec. For safety, wait more than double.
+ */
+ priv->wait_us = 20000000 / speed;
+
+ return 0;
+}
+
+
+static const struct dm_i2c_ops uniphier_i2c_ops = {
+ .xfer = uniphier_i2c_xfer,
+ .set_bus_speed = uniphier_i2c_set_bus_speed,
+};
+
+static const struct udevice_id uniphier_i2c_of_match[] = {
+ { .compatible = "socionext,uniphier-i2c" },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(uniphier_i2c) = {
+ .name = "uniphier-i2c",
+ .id = UCLASS_I2C,
+ .of_match = uniphier_i2c_of_match,
+ .probe = uniphier_i2c_probe,
+ .priv_auto = sizeof(struct uniphier_i2c_priv),
+ .ops = &uniphier_i2c_ops,
+};
diff --git a/roms/u-boot/drivers/i2c/i2c-versatile.c b/roms/u-boot/drivers/i2c/i2c-versatile.c
new file mode 100644
index 000000000..0a1a85dfc
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/i2c-versatile.c
@@ -0,0 +1,277 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2018 Arm Ltd.
+ * Author: Liviu Dudau <liviu.dudau@foss.arm.com>
+ *
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <i2c.h>
+#include <asm/io.h>
+#include <clk.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#define I2C_CONTROL_REG 0x00
+#define I2C_SET_REG 0x00
+#define I2C_CLEAR_REG 0x04
+
+#define SCL BIT(0)
+#define SDA BIT(1)
+
+struct versatile_i2c_priv {
+ phys_addr_t base;
+ u32 delay;
+};
+
+static inline void versatile_sda_set(struct versatile_i2c_priv *priv, u8 state)
+{
+ writel(SDA, priv->base + (state ? I2C_SET_REG : I2C_CLEAR_REG));
+ udelay(priv->delay);
+}
+
+static inline int versatile_sda_get(struct versatile_i2c_priv *priv)
+{
+ int v = !!(readl(priv->base + I2C_CONTROL_REG) & SDA);
+
+ udelay(priv->delay);
+ return v;
+}
+
+static inline void versatile_scl_set(struct versatile_i2c_priv *priv, u8 state)
+{
+ writel(SCL, priv->base + (state ? I2C_SET_REG : I2C_CLEAR_REG));
+ udelay(priv->delay);
+}
+
+static inline int versatile_scl_get(struct versatile_i2c_priv *priv)
+{
+ int v = !!(readl(priv->base + I2C_CONTROL_REG) & SCL);
+
+ udelay(priv->delay);
+ return v;
+}
+
+/* start: SDA goes from high to low while SCL is high */
+static void versatile_i2c_start(struct versatile_i2c_priv *priv)
+{
+ udelay(priv->delay);
+ versatile_sda_set(priv, 1);
+ versatile_scl_set(priv, 1);
+ versatile_sda_set(priv, 0);
+}
+
+/* stop: SDA goes from low to high while SCL is high */
+static void versatile_i2c_stop(struct versatile_i2c_priv *priv)
+{
+ versatile_scl_set(priv, 0);
+ versatile_sda_set(priv, 0);
+ versatile_scl_set(priv, 1);
+ versatile_sda_set(priv, 1);
+}
+
+/* read a bit from the SDA line (data or ACK/NACK) */
+static u8 versatile_i2c_read_bit(struct versatile_i2c_priv *priv)
+{
+ versatile_scl_set(priv, 0);
+ versatile_sda_set(priv, 1);
+ versatile_scl_set(priv, 1);
+ udelay(priv->delay);
+ return (u8)versatile_sda_get(priv);
+}
+
+/* write a bit on the SDA line */
+static void versatile_i2c_write_bit(struct versatile_i2c_priv *priv, u8 bit)
+{
+ versatile_scl_set(priv, 0);
+ versatile_sda_set(priv, bit);
+ versatile_scl_set(priv, 1);
+ udelay(priv->delay);
+}
+
+/* send a reset sequence of 9 clocks with SDA high */
+static void versatile_i2c_reset_bus(struct versatile_i2c_priv *priv)
+{
+ int i;
+
+ for (i = 0; i < 9; i++)
+ versatile_i2c_write_bit(priv, 1);
+
+ versatile_i2c_stop(priv);
+}
+
+/* write byte without start/stop sequence */
+static int versatile_i2c_write_byte(struct versatile_i2c_priv *priv, u8 byte)
+{
+ u8 nak, i;
+
+ for (i = 0; i < 8; i++) {
+ versatile_i2c_write_bit(priv, byte & 0x80);
+ byte <<= 1;
+ }
+
+ /* read ACK */
+ nak = versatile_i2c_read_bit(priv);
+ versatile_scl_set(priv, 0);
+
+ return nak; /* not a nack is an ack */
+}
+
+static int versatile_i2c_read_byte(struct versatile_i2c_priv *priv,
+ u8 *byte, u8 ack)
+{
+ u8 i;
+
+ *byte = 0;
+ for (i = 0; i < 8; i++) {
+ *byte <<= 1;
+ *byte |= versatile_i2c_read_bit(priv);
+ }
+ /* write the nack */
+ versatile_i2c_write_bit(priv, ack);
+
+ return 0;
+}
+
+static int versatile_i2c_send_slave_addr(struct versatile_i2c_priv *priv,
+ struct i2c_msg *msg)
+{
+ u8 addr;
+ int ret;
+
+ if (msg->flags & I2C_M_TEN) {
+ /* 10-bit address, send extended address code first */
+ addr = 0xf0 | ((msg->addr >> 7) & 0x06);
+ ret = versatile_i2c_write_byte(priv, addr);
+ if (ret) {
+ versatile_i2c_stop(priv);
+ return -EIO;
+ }
+
+ /* remaining bits */
+ ret = versatile_i2c_write_byte(priv, msg->addr & 0xff);
+ if (ret) {
+ versatile_i2c_stop(priv);
+ return -EIO;
+ }
+ /* reads need to resend the addr */
+ if (msg->flags & I2C_M_RD) {
+ versatile_i2c_start(priv);
+ addr |= 1;
+ ret = versatile_i2c_write_byte(priv, addr);
+ if (ret) {
+ versatile_i2c_stop(priv);
+ return -EIO;
+ }
+ }
+ } else {
+ /* normal 7-bit address */
+ addr = msg->addr << 1;
+ if (msg->flags & I2C_M_RD)
+ addr |= 1;
+ ret = versatile_i2c_write_byte(priv, addr);
+ if (ret) {
+ versatile_i2c_stop(priv);
+ return -EIO;
+ }
+ }
+
+ return 0;
+}
+
+static int versatile_i2c_message_xfer(struct versatile_i2c_priv *priv,
+ struct i2c_msg *msg)
+{
+ int i, ret;
+ u8 ack;
+
+ versatile_i2c_start(priv);
+ if (versatile_i2c_send_slave_addr(priv, msg))
+ return -EIO;
+
+ for (i = 0; i < msg->len; i++) {
+ if (msg->flags & I2C_M_RD) {
+ ack = (msg->len - i - 1) == 0 ? 1 : 0;
+ ret = versatile_i2c_read_byte(priv, &msg->buf[i], ack);
+ } else {
+ ret = versatile_i2c_write_byte(priv, msg->buf[i]);
+ }
+
+ if (ret)
+ break;
+ }
+
+ versatile_i2c_stop(priv);
+
+ return ret;
+}
+
+static int versatile_i2c_xfer(struct udevice *bus,
+ struct i2c_msg *msg, int nmsgs)
+{
+ struct versatile_i2c_priv *priv = dev_get_priv(bus);
+ int ret;
+
+ for ( ; nmsgs > 0; nmsgs--, msg++) {
+ ret = versatile_i2c_message_xfer(priv, msg);
+ if (ret)
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static int versatile_i2c_chip_probe(struct udevice *bus,
+ uint chip, uint chip_flags)
+{
+ /* probe the presence of a slave by writing a 0-size message */
+ struct i2c_msg msg = { .addr = chip, .flags = chip_flags,
+ .len = 0, .buf = NULL };
+ struct versatile_i2c_priv *priv = dev_get_priv(bus);
+
+ return versatile_i2c_message_xfer(priv, &msg);
+}
+
+static int versatile_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
+{
+ struct versatile_i2c_priv *priv = dev_get_priv(bus);
+
+ priv->delay = 1000000 / (speed << 2);
+
+ versatile_i2c_reset_bus(priv);
+
+ return 0;
+}
+
+static int versatile_i2c_probe(struct udevice *dev)
+{
+ struct versatile_i2c_priv *priv = dev_get_priv(dev);
+
+ priv->base = (phys_addr_t)dev_read_addr(dev);
+ priv->delay = 25; /* 25us * 4 = 100kHz */
+
+ return 0;
+}
+
+static const struct dm_i2c_ops versatile_i2c_ops = {
+ .xfer = versatile_i2c_xfer,
+ .probe_chip = versatile_i2c_chip_probe,
+ .set_bus_speed = versatile_i2c_set_bus_speed,
+};
+
+static const struct udevice_id versatile_i2c_of_match[] = {
+ { .compatible = "arm,versatile-i2c" },
+ { }
+};
+
+U_BOOT_DRIVER(versatile_i2c) = {
+ .name = "i2c-bus-versatile",
+ .id = UCLASS_I2C,
+ .of_match = versatile_i2c_of_match,
+ .probe = versatile_i2c_probe,
+ .priv_auto = sizeof(struct versatile_i2c_priv),
+ .ops = &versatile_i2c_ops,
+};
diff --git a/roms/u-boot/drivers/i2c/i2c_core.c b/roms/u-boot/drivers/i2c/i2c_core.c
new file mode 100644
index 000000000..85cf75ecd
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/i2c_core.c
@@ -0,0 +1,350 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2009 Sergey Kubushyn <ksi@koi8.net>
+ *
+ * (C) Copyright 2012
+ * Heiko Schocher, DENX Software Engineering, hs@denx.de.
+ *
+ * Multibus/multiadapter I2C core functions (wrappers)
+ */
+#include <common.h>
+#include <i2c.h>
+#include <linker_lists.h>
+#include <asm/global_data.h>
+
+struct i2c_adapter *i2c_get_adapter(int index)
+{
+ struct i2c_adapter *i2c_adap_p = ll_entry_start(struct i2c_adapter,
+ i2c);
+ int max = ll_entry_count(struct i2c_adapter, i2c);
+ int i;
+
+ if (index >= max) {
+ printf("Error, wrong i2c adapter %d max %d possible\n",
+ index, max);
+ return i2c_adap_p;
+ }
+ if (index == 0)
+ return i2c_adap_p;
+
+ for (i = 0; i < index; i++)
+ i2c_adap_p++;
+
+ return i2c_adap_p;
+}
+
+#if !defined(CONFIG_SYS_I2C_DIRECT_BUS)
+struct i2c_bus_hose i2c_bus[CONFIG_SYS_NUM_I2C_BUSES] =
+ CONFIG_SYS_I2C_BUSES;
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifndef CONFIG_SYS_I2C_DIRECT_BUS
+/*
+ * i2c_mux_set()
+ * -------------
+ *
+ * This turns on the given channel on I2C multiplexer chip connected to
+ * a given I2C adapter directly or via other multiplexers. In the latter
+ * case the entire multiplexer chain must be initialized first starting
+ * with the one connected directly to the adapter. When disabling a chain
+ * muxes must be programmed in reverse order, starting with the one
+ * farthest from the adapter.
+ *
+ * mux_id is the multiplexer chip type from defined in i2c.h. So far only
+ * NXP (Philips) PCA954x multiplexers are supported. Switches are NOT
+ * supported (anybody uses them?)
+ */
+
+static int i2c_mux_set(struct i2c_adapter *adap, int mux_id, int chip,
+ int channel)
+{
+ uint8_t buf;
+ int ret;
+
+ /* channel < 0 - turn off the mux */
+ if (channel < 0) {
+ buf = 0;
+ ret = adap->write(adap, chip, 0, 0, &buf, 1);
+ if (ret)
+ printf("%s: Could not turn off the mux.\n", __func__);
+ return ret;
+ }
+
+ switch (mux_id) {
+ case I2C_MUX_PCA9540_ID:
+ case I2C_MUX_PCA9542_ID:
+ if (channel > 1)
+ return -1;
+ buf = (uint8_t)((channel & 0x01) | (1 << 2));
+ break;
+ case I2C_MUX_PCA9544_ID:
+ if (channel > 3)
+ return -1;
+ buf = (uint8_t)((channel & 0x03) | (1 << 2));
+ break;
+ case I2C_MUX_PCA9547_ID:
+ if (channel > 7)
+ return -1;
+ buf = (uint8_t)((channel & 0x07) | (1 << 3));
+ break;
+ case I2C_MUX_PCA9548_ID:
+ if (channel > 7)
+ return -1;
+ buf = (uint8_t)(0x01 << channel);
+ break;
+ default:
+ printf("%s: wrong mux id: %d\n", __func__, mux_id);
+ return -1;
+ }
+
+ ret = adap->write(adap, chip, 0, 0, &buf, 1);
+ if (ret)
+ printf("%s: could not set mux: id: %d chip: %x channel: %d\n",
+ __func__, mux_id, chip, channel);
+ return ret;
+}
+
+static int i2c_mux_set_all(void)
+{
+ struct i2c_bus_hose *i2c_bus_tmp = &i2c_bus[I2C_BUS];
+ int i;
+
+ /* Connect requested bus if behind muxes */
+ if (i2c_bus_tmp->next_hop[0].chip != 0) {
+ /* Set all muxes along the path to that bus */
+ for (i = 0; i < CONFIG_SYS_I2C_MAX_HOPS; i++) {
+ int ret;
+
+ if (i2c_bus_tmp->next_hop[i].chip == 0)
+ break;
+
+ ret = i2c_mux_set(I2C_ADAP,
+ i2c_bus_tmp->next_hop[i].mux.id,
+ i2c_bus_tmp->next_hop[i].chip,
+ i2c_bus_tmp->next_hop[i].channel);
+ if (ret != 0)
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static int i2c_mux_disconnect_all(void)
+{
+ struct i2c_bus_hose *i2c_bus_tmp = &i2c_bus[I2C_BUS];
+ int i;
+ uint8_t buf = 0;
+
+ if (I2C_ADAP->init_done == 0)
+ return 0;
+
+ /* Disconnect current bus (turn off muxes if any) */
+ if ((i2c_bus_tmp->next_hop[0].chip != 0) &&
+ (I2C_ADAP->init_done != 0)) {
+ i = CONFIG_SYS_I2C_MAX_HOPS;
+ do {
+ uint8_t chip;
+ int ret;
+
+ chip = i2c_bus_tmp->next_hop[--i].chip;
+ if (chip == 0)
+ continue;
+
+ ret = I2C_ADAP->write(I2C_ADAP, chip, 0, 0, &buf, 1);
+ if (ret != 0) {
+ printf("i2c: mux disconnect error\n");
+ return ret;
+ }
+ } while (i > 0);
+ }
+
+ return 0;
+}
+#endif
+
+/*
+ * i2c_init_bus():
+ * ---------------
+ *
+ * Initializes one bus. Will initialize the parent adapter. No current bus
+ * changes, no mux (if any) setup.
+ */
+static void i2c_init_bus(unsigned int bus_no, int speed, int slaveaddr)
+{
+ if (bus_no >= CONFIG_SYS_NUM_I2C_BUSES)
+ return;
+
+ I2C_ADAP->init(I2C_ADAP, speed, slaveaddr);
+
+ if (gd->flags & GD_FLG_RELOC) {
+ I2C_ADAP->init_done = 1;
+ I2C_ADAP->speed = speed;
+ I2C_ADAP->slaveaddr = slaveaddr;
+ }
+}
+
+/* implement possible board specific board init */
+__weak void i2c_init_board(void)
+{
+}
+
+/* implement possible for i2c specific early i2c init */
+__weak void i2c_early_init_f(void)
+{
+}
+
+/*
+ * i2c_init_all():
+ *
+ * not longer needed, will deleted. Actual init the SPD_BUS
+ * for compatibility.
+ * i2c_adap[] must be initialized beforehead with function pointers and
+ * data, including speed and slaveaddr.
+ */
+void i2c_init_all(void)
+{
+ i2c_init_board();
+ i2c_set_bus_num(CONFIG_SYS_SPD_BUS_NUM);
+ return;
+}
+
+/*
+ * i2c_get_bus_num():
+ * ------------------
+ *
+ * Returns index of currently active I2C bus. Zero-based.
+ */
+unsigned int i2c_get_bus_num(void)
+{
+ return gd->cur_i2c_bus;
+}
+
+/*
+ * i2c_set_bus_num():
+ * ------------------
+ *
+ * Change the active I2C bus. Subsequent read/write calls will
+ * go to this one. Sets all of the muxes in a proper condition
+ * if that bus is behind muxes.
+ * If previously selected bus is behind the muxes turns off all the
+ * muxes along the path to that bus.
+ *
+ * bus - bus index, zero based
+ *
+ * Returns: 0 on success, not 0 on failure
+ */
+int i2c_set_bus_num(unsigned int bus)
+{
+ int max;
+
+ if ((bus == I2C_BUS) && (I2C_ADAP->init_done > 0))
+ return 0;
+
+#ifndef CONFIG_SYS_I2C_DIRECT_BUS
+ if (bus >= CONFIG_SYS_NUM_I2C_BUSES)
+ return -1;
+#endif
+
+ max = ll_entry_count(struct i2c_adapter, i2c);
+ if (I2C_ADAPTER(bus) >= max) {
+ printf("Error, wrong i2c adapter %d max %d possible\n",
+ I2C_ADAPTER(bus), max);
+ return -2;
+ }
+
+#ifndef CONFIG_SYS_I2C_DIRECT_BUS
+ i2c_mux_disconnect_all();
+#endif
+
+ gd->cur_i2c_bus = bus;
+ if (I2C_ADAP->init_done == 0)
+ i2c_init_bus(bus, I2C_ADAP->speed, I2C_ADAP->slaveaddr);
+
+#ifndef CONFIG_SYS_I2C_DIRECT_BUS
+ i2c_mux_set_all();
+#endif
+ return 0;
+}
+
+/*
+ * Probe the given I2C chip address. Returns 0 if a chip responded,
+ * not 0 on failure.
+ */
+int i2c_probe(uint8_t chip)
+{
+ return I2C_ADAP->probe(I2C_ADAP, chip);
+}
+
+/*
+ * Read/Write interface:
+ * chip: I2C chip address, range 0..127
+ * addr: Memory (register) address within the chip
+ * alen: Number of bytes to use for addr (typically 1, 2 for larger
+ * memories, 0 for register type devices with only one
+ * register)
+ * buffer: Where to read/write the data
+ * len: How many bytes to read/write
+ *
+ * Returns: 0 on success, not 0 on failure
+ */
+int i2c_read(uint8_t chip, unsigned int addr, int alen,
+ uint8_t *buffer, int len)
+{
+ return I2C_ADAP->read(I2C_ADAP, chip, addr, alen, buffer, len);
+}
+
+int i2c_write(uint8_t chip, unsigned int addr, int alen,
+ uint8_t *buffer, int len)
+{
+ return I2C_ADAP->write(I2C_ADAP, chip, addr, alen, buffer, len);
+}
+
+unsigned int i2c_set_bus_speed(unsigned int speed)
+{
+ unsigned int ret;
+
+ if (I2C_ADAP->set_bus_speed == NULL)
+ return 0;
+ ret = I2C_ADAP->set_bus_speed(I2C_ADAP, speed);
+ if (gd->flags & GD_FLG_RELOC)
+ I2C_ADAP->speed = (ret == 0) ? speed : 0;
+
+ return ret;
+}
+
+unsigned int i2c_get_bus_speed(void)
+{
+ struct i2c_adapter *cur = I2C_ADAP;
+ return cur->speed;
+}
+
+uint8_t i2c_reg_read(uint8_t addr, uint8_t reg)
+{
+ uint8_t buf;
+
+ i2c_read(addr, reg, 1, &buf, 1);
+
+#ifdef DEBUG
+ printf("%s: bus=%d addr=0x%02x, reg=0x%02x, val=0x%02x\n",
+ __func__, i2c_get_bus_num(), addr, reg, buf);
+#endif
+
+ return buf;
+}
+
+void i2c_reg_write(uint8_t addr, uint8_t reg, uint8_t val)
+{
+#ifdef DEBUG
+ printf("%s: bus=%d addr=0x%02x, reg=0x%02x, val=0x%02x\n",
+ __func__, i2c_get_bus_num(), addr, reg, val);
+#endif
+
+ i2c_write(addr, reg, 1, &val, 1);
+}
+
+__weak void i2c_init(int speed, int slaveaddr)
+{
+ i2c_init_bus(i2c_get_bus_num(), speed, slaveaddr);
+}
diff --git a/roms/u-boot/drivers/i2c/ihs_i2c.c b/roms/u-boot/drivers/i2c/ihs_i2c.c
new file mode 100644
index 000000000..02f014493
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/ihs_i2c.c
@@ -0,0 +1,477 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2013
+ * Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc
+ */
+
+#include <common.h>
+#include <i2c.h>
+#if CONFIG_IS_ENABLED(DM_I2C)
+#include <dm.h>
+#include <regmap.h>
+#else
+#include <gdsys_fpga.h>
+#endif
+#include <log.h>
+#include <asm/global_data.h>
+#include <asm/unaligned.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+
+#if CONFIG_IS_ENABLED(DM_I2C)
+struct ihs_i2c_priv {
+ uint speed;
+ struct regmap *map;
+};
+
+struct ihs_i2c_regs {
+ u16 interrupt_status;
+ u16 interrupt_enable_control;
+ u16 write_mailbox_ext;
+ u16 write_mailbox;
+ u16 read_mailbox_ext;
+ u16 read_mailbox;
+};
+
+#define ihs_i2c_set(map, member, val) \
+ regmap_set(map, struct ihs_i2c_regs, member, val)
+
+#define ihs_i2c_get(map, member, valp) \
+ regmap_get(map, struct ihs_i2c_regs, member, valp)
+
+#else /* !CONFIG_DM_I2C */
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_SYS_I2C_IHS_DUAL
+
+#define I2C_SET_REG(fld, val) \
+ do { \
+ if (I2C_ADAP_HWNR & 0x10) \
+ FPGA_SET_REG(I2C_ADAP_HWNR & 0xf, i2c1.fld, val); \
+ else \
+ FPGA_SET_REG(I2C_ADAP_HWNR, i2c0.fld, val); \
+ } while (0)
+#else
+#define I2C_SET_REG(fld, val) \
+ FPGA_SET_REG(I2C_ADAP_HWNR, i2c0.fld, val)
+#endif
+
+#ifdef CONFIG_SYS_I2C_IHS_DUAL
+#define I2C_GET_REG(fld, val) \
+ do { \
+ if (I2C_ADAP_HWNR & 0x10) \
+ FPGA_GET_REG(I2C_ADAP_HWNR & 0xf, i2c1.fld, val); \
+ else \
+ FPGA_GET_REG(I2C_ADAP_HWNR, i2c0.fld, val); \
+ } while (0)
+#else
+#define I2C_GET_REG(fld, val) \
+ FPGA_GET_REG(I2C_ADAP_HWNR, i2c0.fld, val)
+#endif
+#endif /* CONFIG_DM_I2C */
+
+enum {
+ I2CINT_ERROR_EV = BIT(13),
+ I2CINT_TRANSMIT_EV = BIT(14),
+ I2CINT_RECEIVE_EV = BIT(15),
+};
+
+enum {
+ I2CMB_READ = 0 << 10,
+ I2CMB_WRITE = 1 << 10,
+ I2CMB_1BYTE = 0 << 11,
+ I2CMB_2BYTE = 1 << 11,
+ I2CMB_DONT_HOLD_BUS = 0 << 13,
+ I2CMB_HOLD_BUS = 1 << 13,
+ I2CMB_NATIVE = 2 << 14,
+};
+
+enum {
+ I2COP_WRITE = 0,
+ I2COP_READ = 1,
+};
+
+#if CONFIG_IS_ENABLED(DM_I2C)
+static int wait_for_int(struct udevice *dev, int read)
+#else
+static int wait_for_int(bool read)
+#endif
+{
+ u16 val;
+ uint ctr = 0;
+#if CONFIG_IS_ENABLED(DM_I2C)
+ struct ihs_i2c_priv *priv = dev_get_priv(dev);
+#endif
+
+#if CONFIG_IS_ENABLED(DM_I2C)
+ ihs_i2c_get(priv->map, interrupt_status, &val);
+#else
+ I2C_GET_REG(interrupt_status, &val);
+#endif
+ /* Wait until error or receive/transmit interrupt was raised */
+ while (!(val & (I2CINT_ERROR_EV
+ | (read ? I2CINT_RECEIVE_EV : I2CINT_TRANSMIT_EV)))) {
+ udelay(10);
+ if (ctr++ > 5000) {
+ debug("%s: timed out\n", __func__);
+ return -ETIMEDOUT;
+ }
+#if CONFIG_IS_ENABLED(DM_I2C)
+ ihs_i2c_get(priv->map, interrupt_status, &val);
+#else
+ I2C_GET_REG(interrupt_status, &val);
+#endif
+ }
+
+ return (val & I2CINT_ERROR_EV) ? -EIO : 0;
+}
+
+#if CONFIG_IS_ENABLED(DM_I2C)
+static int ihs_i2c_transfer(struct udevice *dev, uchar chip,
+ uchar *buffer, int len, int read, bool is_last)
+#else
+static int ihs_i2c_transfer(uchar chip, uchar *buffer, int len, bool read,
+ bool is_last)
+#endif
+{
+ u16 val;
+ u16 data;
+ int res;
+#if CONFIG_IS_ENABLED(DM_I2C)
+ struct ihs_i2c_priv *priv = dev_get_priv(dev);
+#endif
+
+ /* Clear interrupt status */
+ data = I2CINT_ERROR_EV | I2CINT_RECEIVE_EV | I2CINT_TRANSMIT_EV;
+#if CONFIG_IS_ENABLED(DM_I2C)
+ ihs_i2c_set(priv->map, interrupt_status, data);
+ ihs_i2c_get(priv->map, interrupt_status, &val);
+#else
+ I2C_SET_REG(interrupt_status, data);
+ I2C_GET_REG(interrupt_status, &val);
+#endif
+
+ /* If we want to write and have data, write the bytes to the mailbox */
+ if (!read && len) {
+ val = buffer[0];
+
+ if (len > 1)
+ val |= buffer[1] << 8;
+#if CONFIG_IS_ENABLED(DM_I2C)
+ ihs_i2c_set(priv->map, write_mailbox_ext, val);
+#else
+ I2C_SET_REG(write_mailbox_ext, val);
+#endif
+ }
+
+ data = I2CMB_NATIVE
+ | (read ? 0 : I2CMB_WRITE)
+ | (chip << 1)
+ | ((len > 1) ? I2CMB_2BYTE : 0)
+ | (is_last ? 0 : I2CMB_HOLD_BUS);
+
+#if CONFIG_IS_ENABLED(DM_I2C)
+ ihs_i2c_set(priv->map, write_mailbox, data);
+#else
+ I2C_SET_REG(write_mailbox, data);
+#endif
+
+#if CONFIG_IS_ENABLED(DM_I2C)
+ res = wait_for_int(dev, read);
+#else
+ res = wait_for_int(read);
+#endif
+ if (res) {
+ if (res == -ETIMEDOUT)
+ debug("%s: time out while waiting for event\n", __func__);
+
+ return res;
+ }
+
+ /* If we want to read, get the bytes from the mailbox */
+ if (read) {
+#if CONFIG_IS_ENABLED(DM_I2C)
+ ihs_i2c_get(priv->map, read_mailbox_ext, &val);
+#else
+ I2C_GET_REG(read_mailbox_ext, &val);
+#endif
+ buffer[0] = val & 0xff;
+ if (len > 1)
+ buffer[1] = val >> 8;
+ }
+
+ return 0;
+}
+
+#if CONFIG_IS_ENABLED(DM_I2C)
+static int ihs_i2c_send_buffer(struct udevice *dev, uchar chip, u8 *data, int len, bool hold_bus, int read)
+#else
+static int ihs_i2c_send_buffer(uchar chip, u8 *data, int len, bool hold_bus,
+ int read)
+#endif
+{
+ int res;
+
+ while (len) {
+ int transfer = min(len, 2);
+ bool is_last = len <= transfer;
+
+#if CONFIG_IS_ENABLED(DM_I2C)
+ res = ihs_i2c_transfer(dev, chip, data, transfer, read,
+ hold_bus ? false : is_last);
+#else
+ res = ihs_i2c_transfer(chip, data, transfer, read,
+ hold_bus ? false : is_last);
+#endif
+ if (res)
+ return res;
+
+ data += transfer;
+ len -= transfer;
+ }
+
+ return 0;
+}
+
+#if CONFIG_IS_ENABLED(DM_I2C)
+static int ihs_i2c_address(struct udevice *dev, uchar chip, u8 *addr, int alen,
+ bool hold_bus)
+#else
+static int ihs_i2c_address(uchar chip, u8 *addr, int alen, bool hold_bus)
+#endif
+{
+#if CONFIG_IS_ENABLED(DM_I2C)
+ return ihs_i2c_send_buffer(dev, chip, addr, alen, hold_bus, I2COP_WRITE);
+#else
+ return ihs_i2c_send_buffer(chip, addr, alen, hold_bus, I2COP_WRITE);
+#endif
+}
+
+#if CONFIG_IS_ENABLED(DM_I2C)
+static int ihs_i2c_access(struct udevice *dev, uchar chip, u8 *addr,
+ int alen, uchar *buffer, int len, int read)
+#else
+static int ihs_i2c_access(struct i2c_adapter *adap, uchar chip, u8 *addr,
+ int alen, uchar *buffer, int len, int read)
+#endif
+{
+ int res;
+
+ /* Don't hold the bus if length of data to send/receive is zero */
+ if (len <= 0)
+ return -EINVAL;
+
+#if CONFIG_IS_ENABLED(DM_I2C)
+ res = ihs_i2c_address(dev, chip, addr, alen, len);
+#else
+ res = ihs_i2c_address(chip, addr, alen, len);
+#endif
+ if (res)
+ return res;
+
+#if CONFIG_IS_ENABLED(DM_I2C)
+ return ihs_i2c_send_buffer(dev, chip, buffer, len, false, read);
+#else
+ return ihs_i2c_send_buffer(chip, buffer, len, false, read);
+#endif
+}
+
+#if CONFIG_IS_ENABLED(DM_I2C)
+
+int ihs_i2c_probe(struct udevice *bus)
+{
+ struct ihs_i2c_priv *priv = dev_get_priv(bus);
+
+ regmap_init_mem(dev_ofnode(bus), &priv->map);
+
+ return 0;
+}
+
+static int ihs_i2c_set_bus_speed(struct udevice *bus, uint speed)
+{
+ struct ihs_i2c_priv *priv = dev_get_priv(bus);
+
+ if (speed != priv->speed && priv->speed != 0)
+ return -EINVAL;
+
+ priv->speed = speed;
+
+ return 0;
+}
+
+static int ihs_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
+{
+ struct i2c_msg *dmsg, *omsg, dummy;
+
+ memset(&dummy, 0, sizeof(struct i2c_msg));
+
+ /* We expect either two messages (one with an offset and one with the
+ * actucal data) or one message (just data)
+ */
+ if (nmsgs > 2 || nmsgs == 0) {
+ debug("%s: Only one or two messages are supported\n", __func__);
+ return -ENOTSUPP;
+ }
+
+ omsg = nmsgs == 1 ? &dummy : msg;
+ dmsg = nmsgs == 1 ? msg : msg + 1;
+
+ if (dmsg->flags & I2C_M_RD)
+ return ihs_i2c_access(bus, dmsg->addr, omsg->buf,
+ omsg->len, dmsg->buf, dmsg->len,
+ I2COP_READ);
+ else
+ return ihs_i2c_access(bus, dmsg->addr, omsg->buf,
+ omsg->len, dmsg->buf, dmsg->len,
+ I2COP_WRITE);
+}
+
+static int ihs_i2c_probe_chip(struct udevice *bus, u32 chip_addr,
+ u32 chip_flags)
+{
+ uchar buffer[2];
+ int res;
+
+ res = ihs_i2c_transfer(bus, chip_addr, buffer, 0, I2COP_READ, true);
+ if (res)
+ return res;
+
+ return 0;
+}
+
+static const struct dm_i2c_ops ihs_i2c_ops = {
+ .xfer = ihs_i2c_xfer,
+ .probe_chip = ihs_i2c_probe_chip,
+ .set_bus_speed = ihs_i2c_set_bus_speed,
+};
+
+static const struct udevice_id ihs_i2c_ids[] = {
+ { .compatible = "gdsys,ihs_i2cmaster", },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(i2c_ihs) = {
+ .name = "i2c_ihs",
+ .id = UCLASS_I2C,
+ .of_match = ihs_i2c_ids,
+ .probe = ihs_i2c_probe,
+ .priv_auto = sizeof(struct ihs_i2c_priv),
+ .ops = &ihs_i2c_ops,
+};
+
+#else /* CONFIG_DM_I2C */
+
+static void ihs_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
+{
+#ifdef CONFIG_SYS_I2C_INIT_BOARD
+ /*
+ * Call board specific i2c bus reset routine before accessing the
+ * environment, which might be in a chip on that bus. For details
+ * about this problem see doc/I2C_Edge_Conditions.
+ */
+ i2c_init_board();
+#endif
+}
+
+static int ihs_i2c_probe(struct i2c_adapter *adap, uchar chip)
+{
+ uchar buffer[2];
+ int res;
+
+ res = ihs_i2c_transfer(chip, buffer, 0, I2COP_READ, true);
+ if (res)
+ return res;
+
+ return 0;
+}
+
+static int ihs_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
+ int alen, uchar *buffer, int len)
+{
+ u8 addr_bytes[4];
+
+ put_unaligned_le32(addr, addr_bytes);
+
+ return ihs_i2c_access(adap, chip, addr_bytes, alen, buffer, len,
+ I2COP_READ);
+}
+
+static int ihs_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
+ int alen, uchar *buffer, int len)
+{
+ u8 addr_bytes[4];
+
+ put_unaligned_le32(addr, addr_bytes);
+
+ return ihs_i2c_access(adap, chip, addr_bytes, alen, buffer, len,
+ I2COP_WRITE);
+}
+
+static unsigned int ihs_i2c_set_bus_speed(struct i2c_adapter *adap,
+ unsigned int speed)
+{
+ if (speed != adap->speed)
+ return -EINVAL;
+ return speed;
+}
+
+/*
+ * Register IHS i2c adapters
+ */
+#ifdef CONFIG_SYS_I2C_IHS_CH0
+U_BOOT_I2C_ADAP_COMPLETE(ihs0, ihs_i2c_init, ihs_i2c_probe,
+ ihs_i2c_read, ihs_i2c_write,
+ ihs_i2c_set_bus_speed,
+ CONFIG_SYS_I2C_IHS_SPEED_0,
+ CONFIG_SYS_I2C_IHS_SLAVE_0, 0)
+#ifdef CONFIG_SYS_I2C_IHS_DUAL
+U_BOOT_I2C_ADAP_COMPLETE(ihs0_1, ihs_i2c_init, ihs_i2c_probe,
+ ihs_i2c_read, ihs_i2c_write,
+ ihs_i2c_set_bus_speed,
+ CONFIG_SYS_I2C_IHS_SPEED_0_1,
+ CONFIG_SYS_I2C_IHS_SLAVE_0_1, 16)
+#endif
+#endif
+#ifdef CONFIG_SYS_I2C_IHS_CH1
+U_BOOT_I2C_ADAP_COMPLETE(ihs1, ihs_i2c_init, ihs_i2c_probe,
+ ihs_i2c_read, ihs_i2c_write,
+ ihs_i2c_set_bus_speed,
+ CONFIG_SYS_I2C_IHS_SPEED_1,
+ CONFIG_SYS_I2C_IHS_SLAVE_1, 1)
+#ifdef CONFIG_SYS_I2C_IHS_DUAL
+U_BOOT_I2C_ADAP_COMPLETE(ihs1_1, ihs_i2c_init, ihs_i2c_probe,
+ ihs_i2c_read, ihs_i2c_write,
+ ihs_i2c_set_bus_speed,
+ CONFIG_SYS_I2C_IHS_SPEED_1_1,
+ CONFIG_SYS_I2C_IHS_SLAVE_1_1, 17)
+#endif
+#endif
+#ifdef CONFIG_SYS_I2C_IHS_CH2
+U_BOOT_I2C_ADAP_COMPLETE(ihs2, ihs_i2c_init, ihs_i2c_probe,
+ ihs_i2c_read, ihs_i2c_write,
+ ihs_i2c_set_bus_speed,
+ CONFIG_SYS_I2C_IHS_SPEED_2,
+ CONFIG_SYS_I2C_IHS_SLAVE_2, 2)
+#ifdef CONFIG_SYS_I2C_IHS_DUAL
+U_BOOT_I2C_ADAP_COMPLETE(ihs2_1, ihs_i2c_init, ihs_i2c_probe,
+ ihs_i2c_read, ihs_i2c_write,
+ ihs_i2c_set_bus_speed,
+ CONFIG_SYS_I2C_IHS_SPEED_2_1,
+ CONFIG_SYS_I2C_IHS_SLAVE_2_1, 18)
+#endif
+#endif
+#ifdef CONFIG_SYS_I2C_IHS_CH3
+U_BOOT_I2C_ADAP_COMPLETE(ihs3, ihs_i2c_init, ihs_i2c_probe,
+ ihs_i2c_read, ihs_i2c_write,
+ ihs_i2c_set_bus_speed,
+ CONFIG_SYS_I2C_IHS_SPEED_3,
+ CONFIG_SYS_I2C_IHS_SLAVE_3, 3)
+#ifdef CONFIG_SYS_I2C_IHS_DUAL
+U_BOOT_I2C_ADAP_COMPLETE(ihs3_1, ihs_i2c_init, ihs_i2c_probe,
+ ihs_i2c_read, ihs_i2c_write,
+ ihs_i2c_set_bus_speed,
+ CONFIG_SYS_I2C_IHS_SPEED_3_1,
+ CONFIG_SYS_I2C_IHS_SLAVE_3_1, 19)
+#endif
+#endif
+#endif /* CONFIG_DM_I2C */
diff --git a/roms/u-boot/drivers/i2c/imx_lpi2c.c b/roms/u-boot/drivers/i2c/imx_lpi2c.c
new file mode 100644
index 000000000..92c500327
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/imx_lpi2c.c
@@ -0,0 +1,524 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2016 Freescale Semiconductors, Inc.
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <log.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/imx-regs.h>
+#include <imx_lpi2c.h>
+#include <asm/arch/sys_proto.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <i2c.h>
+#include <dm/device_compat.h>
+
+#define LPI2C_FIFO_SIZE 4
+#define LPI2C_NACK_TOUT_MS 1
+#define LPI2C_TIMEOUT_MS 100
+
+static int bus_i2c_init(struct udevice *bus, int speed);
+
+/* Weak linked function for overridden by some SoC power function */
+int __weak init_i2c_power(unsigned i2c_num)
+{
+ return 0;
+}
+
+static int imx_lpci2c_check_busy_bus(const struct imx_lpi2c_reg *regs)
+{
+ lpi2c_status_t result = LPI2C_SUCESS;
+ u32 status;
+
+ status = readl(&regs->msr);
+
+ if ((status & LPI2C_MSR_BBF_MASK) && !(status & LPI2C_MSR_MBF_MASK))
+ result = LPI2C_BUSY;
+
+ return result;
+}
+
+static int imx_lpci2c_check_clear_error(struct imx_lpi2c_reg *regs)
+{
+ lpi2c_status_t result = LPI2C_SUCESS;
+ u32 val, status;
+
+ status = readl(&regs->msr);
+ /* errors to check for */
+ status &= LPI2C_MSR_NDF_MASK | LPI2C_MSR_ALF_MASK |
+ LPI2C_MSR_FEF_MASK | LPI2C_MSR_PLTF_MASK;
+
+ if (status) {
+ if (status & LPI2C_MSR_PLTF_MASK)
+ result = LPI2C_PIN_LOW_TIMEOUT_ERR;
+ else if (status & LPI2C_MSR_ALF_MASK)
+ result = LPI2C_ARB_LOST_ERR;
+ else if (status & LPI2C_MSR_NDF_MASK)
+ result = LPI2C_NAK_ERR;
+ else if (status & LPI2C_MSR_FEF_MASK)
+ result = LPI2C_FIFO_ERR;
+
+ /* clear status flags */
+ writel(0x7f00, &regs->msr);
+ /* reset fifos */
+ val = readl(&regs->mcr);
+ val |= LPI2C_MCR_RRF_MASK | LPI2C_MCR_RTF_MASK;
+ writel(val, &regs->mcr);
+ }
+
+ return result;
+}
+
+static int bus_i2c_wait_for_tx_ready(struct imx_lpi2c_reg *regs)
+{
+ lpi2c_status_t result = LPI2C_SUCESS;
+ u32 txcount = 0;
+ ulong start_time = get_timer(0);
+
+ do {
+ txcount = LPI2C_MFSR_TXCOUNT(readl(&regs->mfsr));
+ txcount = LPI2C_FIFO_SIZE - txcount;
+ result = imx_lpci2c_check_clear_error(regs);
+ if (result) {
+ debug("i2c: wait for tx ready: result 0x%x\n", result);
+ return result;
+ }
+ if (get_timer(start_time) > LPI2C_TIMEOUT_MS) {
+ debug("i2c: wait for tx ready: timeout\n");
+ return -1;
+ }
+ } while (!txcount);
+
+ return result;
+}
+
+static int bus_i2c_send(struct udevice *bus, u8 *txbuf, int len)
+{
+ struct imx_lpi2c_bus *i2c_bus = dev_get_priv(bus);
+ struct imx_lpi2c_reg *regs = (struct imx_lpi2c_reg *)(i2c_bus->base);
+ lpi2c_status_t result = LPI2C_SUCESS;
+
+ /* empty tx */
+ if (!len)
+ return result;
+
+ while (len--) {
+ result = bus_i2c_wait_for_tx_ready(regs);
+ if (result) {
+ debug("i2c: send wait for tx ready: %d\n", result);
+ return result;
+ }
+ writel(*txbuf++, &regs->mtdr);
+ }
+
+ return result;
+}
+
+static int bus_i2c_receive(struct udevice *bus, u8 *rxbuf, int len)
+{
+ struct imx_lpi2c_bus *i2c_bus = dev_get_priv(bus);
+ struct imx_lpi2c_reg *regs = (struct imx_lpi2c_reg *)(i2c_bus->base);
+ lpi2c_status_t result = LPI2C_SUCESS;
+ u32 val;
+ ulong start_time = get_timer(0);
+
+ /* empty read */
+ if (!len)
+ return result;
+
+ result = bus_i2c_wait_for_tx_ready(regs);
+ if (result) {
+ debug("i2c: receive wait fot tx ready: %d\n", result);
+ return result;
+ }
+
+ /* clear all status flags */
+ writel(0x7f00, &regs->msr);
+ /* send receive command */
+ val = LPI2C_MTDR_CMD(0x1) | LPI2C_MTDR_DATA(len - 1);
+ writel(val, &regs->mtdr);
+
+ while (len--) {
+ do {
+ result = imx_lpci2c_check_clear_error(regs);
+ if (result) {
+ debug("i2c: receive check clear error: %d\n",
+ result);
+ return result;
+ }
+ if (get_timer(start_time) > LPI2C_TIMEOUT_MS) {
+ debug("i2c: receive mrdr: timeout\n");
+ return -1;
+ }
+ val = readl(&regs->mrdr);
+ } while (val & LPI2C_MRDR_RXEMPTY_MASK);
+ *rxbuf++ = LPI2C_MRDR_DATA(val);
+ }
+
+ return result;
+}
+
+static int bus_i2c_start(struct udevice *bus, u8 addr, u8 dir)
+{
+ lpi2c_status_t result;
+ struct imx_lpi2c_bus *i2c_bus = dev_get_priv(bus);
+ struct imx_lpi2c_reg *regs = (struct imx_lpi2c_reg *)(i2c_bus->base);
+ u32 val;
+
+ result = imx_lpci2c_check_busy_bus(regs);
+ if (result) {
+ debug("i2c: start check busy bus: 0x%x\n", result);
+
+ /* Try to init the lpi2c then check the bus busy again */
+ bus_i2c_init(bus, I2C_SPEED_STANDARD_RATE);
+ result = imx_lpci2c_check_busy_bus(regs);
+ if (result) {
+ printf("i2c: Error check busy bus: 0x%x\n", result);
+ return result;
+ }
+ }
+ /* clear all status flags */
+ writel(0x7f00, &regs->msr);
+ /* turn off auto-stop condition */
+ val = readl(&regs->mcfgr1) & ~LPI2C_MCFGR1_AUTOSTOP_MASK;
+ writel(val, &regs->mcfgr1);
+ /* wait tx fifo ready */
+ result = bus_i2c_wait_for_tx_ready(regs);
+ if (result) {
+ debug("i2c: start wait for tx ready: 0x%x\n", result);
+ return result;
+ }
+ /* issue start command */
+ val = LPI2C_MTDR_CMD(0x4) | (addr << 0x1) | dir;
+ writel(val, &regs->mtdr);
+
+ return result;
+}
+
+static int bus_i2c_stop(struct udevice *bus)
+{
+ lpi2c_status_t result;
+ struct imx_lpi2c_bus *i2c_bus = dev_get_priv(bus);
+ struct imx_lpi2c_reg *regs = (struct imx_lpi2c_reg *)(i2c_bus->base);
+ u32 status;
+ ulong start_time;
+
+ result = bus_i2c_wait_for_tx_ready(regs);
+ if (result) {
+ debug("i2c: stop wait for tx ready: 0x%x\n", result);
+ return result;
+ }
+
+ /* send stop command */
+ writel(LPI2C_MTDR_CMD(0x2), &regs->mtdr);
+
+ start_time = get_timer(0);
+ while (1) {
+ status = readl(&regs->msr);
+ result = imx_lpci2c_check_clear_error(regs);
+ /* stop detect flag */
+ if (status & LPI2C_MSR_SDF_MASK) {
+ /* clear stop flag */
+ status &= LPI2C_MSR_SDF_MASK;
+ writel(status, &regs->msr);
+ break;
+ }
+
+ if (get_timer(start_time) > LPI2C_NACK_TOUT_MS) {
+ debug("stop timeout\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ return result;
+}
+
+static int bus_i2c_read(struct udevice *bus, u32 chip, u8 *buf, int len)
+{
+ lpi2c_status_t result;
+
+ result = bus_i2c_start(bus, chip, 1);
+ if (result)
+ return result;
+ result = bus_i2c_receive(bus, buf, len);
+ if (result)
+ return result;
+
+ return result;
+}
+
+static int bus_i2c_write(struct udevice *bus, u32 chip, u8 *buf, int len)
+{
+ lpi2c_status_t result;
+
+ result = bus_i2c_start(bus, chip, 0);
+ if (result)
+ return result;
+ result = bus_i2c_send(bus, buf, len);
+ if (result)
+ return result;
+
+ return result;
+}
+
+
+u32 __weak imx_get_i2cclk(u32 i2c_num)
+{
+ return 0;
+}
+
+static int bus_i2c_set_bus_speed(struct udevice *bus, int speed)
+{
+ struct imx_lpi2c_bus *i2c_bus = dev_get_priv(bus);
+ struct imx_lpi2c_reg *regs = (struct imx_lpi2c_reg *)(i2c_bus->base);
+ u32 val;
+ u32 preescale = 0, best_pre = 0, clkhi = 0;
+ u32 best_clkhi = 0, abs_error = 0, rate;
+ u32 error = 0xffffffff;
+ u32 clock_rate;
+ bool mode;
+ int i;
+
+ if (IS_ENABLED(CONFIG_CLK)) {
+ clock_rate = clk_get_rate(&i2c_bus->per_clk);
+ if (clock_rate <= 0) {
+ dev_err(bus, "Failed to get i2c clk: %d\n", clock_rate);
+ return clock_rate;
+ }
+ } else {
+ clock_rate = imx_get_i2cclk(dev_seq(bus));
+ if (!clock_rate)
+ return -EPERM;
+ }
+
+ mode = (readl(&regs->mcr) & LPI2C_MCR_MEN_MASK) >> LPI2C_MCR_MEN_SHIFT;
+ /* disable master mode */
+ val = readl(&regs->mcr) & ~LPI2C_MCR_MEN_MASK;
+ writel(val | LPI2C_MCR_MEN(0), &regs->mcr);
+
+ for (preescale = 1; (preescale <= 128) &&
+ (error != 0); preescale = 2 * preescale) {
+ for (clkhi = 1; clkhi < 32; clkhi++) {
+ if (clkhi == 1)
+ rate = (clock_rate / preescale) / (1 + 3 + 2 + 2 / preescale);
+ else
+ rate = (clock_rate / preescale / (3 * clkhi + 2 + 2 / preescale));
+
+ abs_error = speed > rate ? speed - rate : rate - speed;
+
+ if (abs_error < error) {
+ best_pre = preescale;
+ best_clkhi = clkhi;
+ error = abs_error;
+ if (abs_error == 0)
+ break;
+ }
+ }
+ }
+
+ /* Standard, fast, fast mode plus and ultra-fast transfers. */
+ val = LPI2C_MCCR0_CLKHI(best_clkhi);
+ if (best_clkhi < 2)
+ val |= LPI2C_MCCR0_CLKLO(3) | LPI2C_MCCR0_SETHOLD(2) | LPI2C_MCCR0_DATAVD(1);
+ else
+ val |= LPI2C_MCCR0_CLKLO(2 * best_clkhi) | LPI2C_MCCR0_SETHOLD(best_clkhi) |
+ LPI2C_MCCR0_DATAVD(best_clkhi / 2);
+ writel(val, &regs->mccr0);
+
+ for (i = 0; i < 8; i++) {
+ if (best_pre == (1 << i)) {
+ best_pre = i;
+ break;
+ }
+ }
+
+ val = readl(&regs->mcfgr1) & ~LPI2C_MCFGR1_PRESCALE_MASK;
+ writel(val | LPI2C_MCFGR1_PRESCALE(best_pre), &regs->mcfgr1);
+
+ if (mode) {
+ val = readl(&regs->mcr) & ~LPI2C_MCR_MEN_MASK;
+ writel(val | LPI2C_MCR_MEN(1), &regs->mcr);
+ }
+
+ return 0;
+}
+
+static int bus_i2c_init(struct udevice *bus, int speed)
+{
+ u32 val;
+ int ret;
+
+ struct imx_lpi2c_bus *i2c_bus = dev_get_priv(bus);
+ struct imx_lpi2c_reg *regs = (struct imx_lpi2c_reg *)(i2c_bus->base);
+ /* reset peripheral */
+ writel(LPI2C_MCR_RST_MASK, &regs->mcr);
+ writel(0x0, &regs->mcr);
+ /* Disable Dozen mode */
+ writel(LPI2C_MCR_DBGEN(0) | LPI2C_MCR_DOZEN(1), &regs->mcr);
+ /* host request disable, active high, external pin */
+ val = readl(&regs->mcfgr0);
+ val &= (~(LPI2C_MCFGR0_HREN_MASK | LPI2C_MCFGR0_HRPOL_MASK |
+ LPI2C_MCFGR0_HRSEL_MASK));
+ val |= LPI2C_MCFGR0_HRPOL(0x1);
+ writel(val, &regs->mcfgr0);
+ /* pincfg and ignore ack */
+ val = readl(&regs->mcfgr1);
+ val &= ~(LPI2C_MCFGR1_PINCFG_MASK | LPI2C_MCFGR1_IGNACK_MASK);
+ val |= LPI2C_MCFGR1_PINCFG(0x0); /* 2 pin open drain */
+ val |= LPI2C_MCFGR1_IGNACK(0x0); /* ignore nack */
+ writel(val, &regs->mcfgr1);
+
+ ret = bus_i2c_set_bus_speed(bus, speed);
+
+ /* enable lpi2c in master mode */
+ val = readl(&regs->mcr) & ~LPI2C_MCR_MEN_MASK;
+ writel(val | LPI2C_MCR_MEN(1), &regs->mcr);
+
+ debug("i2c : controller bus %d, speed %d:\n", dev_seq(bus), speed);
+
+ return ret;
+}
+
+static int imx_lpi2c_probe_chip(struct udevice *bus, u32 chip,
+ u32 chip_flags)
+{
+ lpi2c_status_t result;
+
+ result = bus_i2c_start(bus, chip, 0);
+ if (result) {
+ bus_i2c_stop(bus);
+ bus_i2c_init(bus, I2C_SPEED_STANDARD_RATE);
+ return result;
+ }
+
+ result = bus_i2c_stop(bus);
+ if (result)
+ bus_i2c_init(bus, I2C_SPEED_STANDARD_RATE);
+
+ return result;
+}
+
+static int imx_lpi2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
+{
+ int ret = 0, ret_stop;
+
+ for (; nmsgs > 0; nmsgs--, msg++) {
+ debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
+ if (msg->flags & I2C_M_RD)
+ ret = bus_i2c_read(bus, msg->addr, msg->buf, msg->len);
+ else {
+ ret = bus_i2c_write(bus, msg->addr, msg->buf,
+ msg->len);
+ if (ret)
+ break;
+ }
+ }
+
+ if (ret)
+ debug("i2c_write: error sending\n");
+
+ ret_stop = bus_i2c_stop(bus);
+ if (ret_stop)
+ debug("i2c_xfer: stop bus error\n");
+
+ ret |= ret_stop;
+
+ return ret;
+}
+
+static int imx_lpi2c_set_bus_speed(struct udevice *bus, unsigned int speed)
+{
+ return bus_i2c_set_bus_speed(bus, speed);
+}
+
+__weak int enable_i2c_clk(unsigned char enable, unsigned int i2c_num)
+{
+ return 0;
+}
+
+static int imx_lpi2c_probe(struct udevice *bus)
+{
+ struct imx_lpi2c_bus *i2c_bus = dev_get_priv(bus);
+ fdt_addr_t addr;
+ int ret;
+
+ i2c_bus->driver_data = dev_get_driver_data(bus);
+
+ addr = dev_read_addr(bus);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ i2c_bus->base = addr;
+ i2c_bus->index = dev_seq(bus);
+ i2c_bus->bus = bus;
+
+ /* power up i2c resource */
+ ret = init_i2c_power(dev_seq(bus));
+ if (ret) {
+ debug("init_i2c_power err = %d\n", ret);
+ return ret;
+ }
+
+ if (IS_ENABLED(CONFIG_CLK)) {
+ ret = clk_get_by_name(bus, "per", &i2c_bus->per_clk);
+ if (ret) {
+ dev_err(bus, "Failed to get per clk\n");
+ return ret;
+ }
+ ret = clk_enable(&i2c_bus->per_clk);
+ if (ret) {
+ dev_err(bus, "Failed to enable per clk\n");
+ return ret;
+ }
+
+ ret = clk_get_by_name(bus, "ipg", &i2c_bus->ipg_clk);
+ if (ret) {
+ dev_err(bus, "Failed to get ipg clk\n");
+ return ret;
+ }
+ ret = clk_enable(&i2c_bus->ipg_clk);
+ if (ret) {
+ dev_err(bus, "Failed to enable ipg clk\n");
+ return ret;
+ }
+ } else {
+ /* To i.MX7ULP, only i2c4-7 can be handled by A7 core */
+ ret = enable_i2c_clk(1, dev_seq(bus));
+ if (ret < 0)
+ return ret;
+ }
+
+ ret = bus_i2c_init(bus, I2C_SPEED_STANDARD_RATE);
+ if (ret < 0)
+ return ret;
+
+ debug("i2c : controller bus %d at 0x%lx , speed %d: ",
+ dev_seq(bus), i2c_bus->base,
+ i2c_bus->speed);
+
+ return 0;
+}
+
+static const struct dm_i2c_ops imx_lpi2c_ops = {
+ .xfer = imx_lpi2c_xfer,
+ .probe_chip = imx_lpi2c_probe_chip,
+ .set_bus_speed = imx_lpi2c_set_bus_speed,
+};
+
+static const struct udevice_id imx_lpi2c_ids[] = {
+ { .compatible = "fsl,imx7ulp-lpi2c", },
+ { .compatible = "fsl,imx8qm-lpi2c", },
+ {}
+};
+
+U_BOOT_DRIVER(imx_lpi2c) = {
+ .name = "imx_lpi2c",
+ .id = UCLASS_I2C,
+ .of_match = imx_lpi2c_ids,
+ .probe = imx_lpi2c_probe,
+ .priv_auto = sizeof(struct imx_lpi2c_bus),
+ .ops = &imx_lpi2c_ops,
+};
diff --git a/roms/u-boot/drivers/i2c/intel_i2c.c b/roms/u-boot/drivers/i2c/intel_i2c.c
new file mode 100644
index 000000000..52f7a528e
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/intel_i2c.c
@@ -0,0 +1,312 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SMBus block read/write support added by Stefan Roese:
+ * Copyright (C) 2016 Stefan Roese <sr@denx.de>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+#include <log.h>
+#include <pci.h>
+#include <asm/io.h>
+
+/* PCI Configuration Space (D31:F3): SMBus */
+#define SMB_BASE 0x20
+#define HOSTC 0x40
+#define HST_EN (1 << 0)
+#define SMB_RCV_SLVA 0x09
+
+/* SMBus I/O bits. */
+#define SMBHSTSTAT 0x0
+#define SMBHSTCTL 0x2
+#define SMBHSTCMD 0x3
+#define SMBXMITADD 0x4
+#define SMBHSTDAT0 0x5
+#define SMBHSTDAT1 0x6
+#define SMBBLKDAT 0x7
+#define SMBTRNSADD 0x9
+#define SMBSLVDATA 0xa
+#define SMBAUXCTL 0xd
+#define SMLINK_PIN_CTL 0xe
+#define SMBUS_PIN_CTL 0xf
+
+/* I801 Hosts Status register bits */
+#define SMBHSTSTS_BYTE_DONE 0x80
+#define SMBHSTSTS_INUSE_STS 0x40
+#define SMBHSTSTS_SMBALERT_STS 0x20
+#define SMBHSTSTS_FAILED 0x10
+#define SMBHSTSTS_BUS_ERR 0x08
+#define SMBHSTSTS_DEV_ERR 0x04
+#define SMBHSTSTS_INTR 0x02
+#define SMBHSTSTS_HOST_BUSY 0x01
+
+/* I801 Host Control register bits */
+#define SMBHSTCNT_INTREN 0x01
+#define SMBHSTCNT_KILL 0x02
+#define SMBHSTCNT_LAST_BYTE 0x20
+#define SMBHSTCNT_START 0x40
+#define SMBHSTCNT_PEC_EN 0x80 /* ICH3 and later */
+
+/* Auxiliary control register bits, ICH4+ only */
+#define SMBAUXCTL_CRC 1
+#define SMBAUXCTL_E32B 2
+
+#define SMBUS_TIMEOUT 100 /* 100 ms */
+
+struct intel_i2c {
+ u32 base;
+ int running;
+};
+
+static int smbus_wait_until_ready(u32 base)
+{
+ unsigned long ts;
+ u8 byte;
+
+ ts = get_timer(0);
+ do {
+ byte = inb(base + SMBHSTSTAT);
+ if (!(byte & 1))
+ return 0;
+ } while (get_timer(ts) < SMBUS_TIMEOUT);
+
+ return -ETIMEDOUT;
+}
+
+static int smbus_wait_until_done(u32 base)
+{
+ unsigned long ts;
+ u8 byte;
+
+ ts = get_timer(0);
+ do {
+ byte = inb(base + SMBHSTSTAT);
+ if (!((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0))
+ return 0;
+ } while (get_timer(ts) < SMBUS_TIMEOUT);
+
+ return -ETIMEDOUT;
+}
+
+static int smbus_block_read(u32 base, u8 dev, u8 *buffer,
+ int offset, int len)
+{
+ u8 buf_temp[32];
+ int count;
+ int i;
+
+ debug("%s (%d): dev=0x%x offs=0x%x len=0x%x\n",
+ __func__, __LINE__, dev, offset, len);
+ if (smbus_wait_until_ready(base) < 0)
+ return -ETIMEDOUT;
+
+ /* Setup transaction */
+
+ /* Reset the data buffer index */
+ inb(base + SMBHSTCTL);
+
+ /* Set the device I'm talking too */
+ outb(((dev & 0x7f) << 1) | 1, base + SMBXMITADD);
+ /* Set the command/address... */
+ outb(offset & 0xff, base + SMBHSTCMD);
+ /* Set up for a block read */
+ outb((inb(base + SMBHSTCTL) & (~(0x7) << 2)) | (0x5 << 2),
+ (base + SMBHSTCTL));
+ /* Clear any lingering errors, so the transaction will run */
+ outb(inb(base + SMBHSTSTAT), base + SMBHSTSTAT);
+
+ /* Start the command */
+ outb((inb(base + SMBHSTCTL) | SMBHSTCNT_START), base + SMBHSTCTL);
+
+ /* Poll for transaction completion */
+ if (smbus_wait_until_done(base) < 0) {
+ printf("SMBUS read transaction timeout (dev=0x%x)\n", dev);
+ return -ETIMEDOUT;
+ }
+
+ count = inb(base + SMBHSTDAT0);
+ debug("%s (%d): count=%d (len=%d)\n", __func__, __LINE__, count, len);
+ if (count == 0) {
+ debug("ERROR: len=0 on read\n");
+ return -EIO;
+ }
+
+ if (count < len) {
+ debug("ERROR: too few bytes read\n");
+ return -EIO;
+ }
+
+ if (count > 32) {
+ debug("ERROR: count=%d too high\n", count);
+ return -EIO;
+ }
+
+ /* Read all available bytes from buffer */
+ for (i = 0; i < count; i++)
+ buf_temp[i] = inb(base + SMBBLKDAT);
+
+ memcpy(buffer, buf_temp, len);
+
+ /* Return results of transaction */
+ if (!(inb(base + SMBHSTSTAT) & SMBHSTSTS_INTR))
+ return -EIO;
+
+ return 0;
+}
+
+static int smbus_block_write(u32 base, u8 dev, u8 *buffer,
+ int offset, int len)
+{
+ int i;
+
+ debug("%s (%d): dev=0x%x offs=0x%x len=0x%x\n",
+ __func__, __LINE__, dev, offset, len);
+ if (smbus_wait_until_ready(base) < 0)
+ return -ETIMEDOUT;
+
+ /* Setup transaction */
+ /* Set the device I'm talking too */
+ outb(((dev & 0x7f) << 1) & ~0x01, base + SMBXMITADD);
+ /* Set the command/address... */
+ outb(offset, base + SMBHSTCMD);
+ /* Set up for a block write */
+ outb((inb(base + SMBHSTCTL) & (~(0x7) << 2)) | (0x5 << 2),
+ (base + SMBHSTCTL));
+ /* Clear any lingering errors, so the transaction will run */
+ outb(inb(base + SMBHSTSTAT), base + SMBHSTSTAT);
+
+ /* Write count in DAT0 register */
+ outb(len, base + SMBHSTDAT0);
+
+ /* Write data bytes... */
+ for (i = 0; i < len; i++)
+ outb(*buffer++, base + SMBBLKDAT);
+
+ /* Start the command */
+ outb((inb(base + SMBHSTCTL) | SMBHSTCNT_START), base + SMBHSTCTL);
+
+ /* Poll for transaction completion */
+ if (smbus_wait_until_done(base) < 0) {
+ printf("SMBUS write transaction timeout (dev=0x%x)\n", dev);
+ return -ETIMEDOUT;
+ }
+
+ /* Return results of transaction */
+ if (!(inb(base + SMBHSTSTAT) & SMBHSTSTS_INTR))
+ return -EIO;
+
+ return 0;
+}
+
+static int intel_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
+{
+ struct intel_i2c *i2c = dev_get_priv(bus);
+ struct i2c_msg *dmsg, *omsg, dummy;
+
+ debug("i2c_xfer: %d messages\n", nmsgs);
+
+ memset(&dummy, 0, sizeof(struct i2c_msg));
+
+ /*
+ * We expect either two messages (one with an offset and one with the
+ * actucal data) or one message (just data)
+ */
+ if (nmsgs > 2 || nmsgs == 0) {
+ debug("%s: Only one or two messages are supported", __func__);
+ return -EIO;
+ }
+
+ omsg = nmsgs == 1 ? &dummy : msg;
+ dmsg = nmsgs == 1 ? msg : msg + 1;
+
+ if (dmsg->flags & I2C_M_RD)
+ return smbus_block_read(i2c->base, dmsg->addr, &dmsg->buf[0],
+ omsg->buf[0], dmsg->len);
+ else
+ return smbus_block_write(i2c->base, dmsg->addr, &dmsg->buf[1],
+ dmsg->buf[0], dmsg->len - 1);
+}
+
+static int intel_i2c_probe_chip(struct udevice *bus, uint chip_addr,
+ uint chip_flags)
+{
+ struct intel_i2c *i2c = dev_get_priv(bus);
+ u8 buf[4];
+
+ return smbus_block_read(i2c->base, chip_addr, buf, 0, 1);
+}
+
+static int intel_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
+{
+ return 0;
+}
+
+static int intel_i2c_probe(struct udevice *dev)
+{
+ struct intel_i2c *priv = dev_get_priv(dev);
+ ulong base;
+
+ /* Save base address from PCI BAR */
+ priv->base = (ulong)dm_pci_map_bar(dev, PCI_BASE_ADDRESS_4,
+ PCI_REGION_IO);
+ base = priv->base;
+
+ /* Set SMBus enable. */
+ dm_pci_write_config8(dev, HOSTC, HST_EN);
+
+ /* Disable interrupts */
+ outb(inb(base + SMBHSTCTL) & ~SMBHSTCNT_INTREN, base + SMBHSTCTL);
+
+ /* Set 32-byte data buffer mode */
+ outb(inb(base + SMBAUXCTL) | SMBAUXCTL_E32B, base + SMBAUXCTL);
+
+ return 0;
+}
+
+static int intel_i2c_bind(struct udevice *dev)
+{
+ char name[20];
+
+ /* Create a unique device name for PCI type devices */
+ if (device_is_on_pci_bus(dev)) {
+ sprintf(name, "intel_i2c#%u", dev_seq(dev));
+ device_set_name(dev, name);
+ }
+
+ return 0;
+}
+
+static const struct dm_i2c_ops intel_i2c_ops = {
+ .xfer = intel_i2c_xfer,
+ .probe_chip = intel_i2c_probe_chip,
+ .set_bus_speed = intel_i2c_set_bus_speed,
+};
+
+static const struct udevice_id intel_i2c_ids[] = {
+ { .compatible = "intel,ich-i2c" },
+ { }
+};
+
+U_BOOT_DRIVER(intel_i2c) = {
+ .name = "i2c_intel",
+ .id = UCLASS_I2C,
+ .of_match = intel_i2c_ids,
+ .ops = &intel_i2c_ops,
+ .priv_auto = sizeof(struct intel_i2c),
+ .bind = intel_i2c_bind,
+ .probe = intel_i2c_probe,
+};
+
+static struct pci_device_id intel_smbus_pci_supported[] = {
+ /* Intel BayTrail SMBus on the PCI bus */
+ { PCI_VDEVICE(INTEL, 0x0f12) },
+ /* Intel IvyBridge (Panther Point PCH) SMBus on the PCI bus */
+ { PCI_VDEVICE(INTEL, 0x1e22) },
+ {},
+};
+
+U_BOOT_PCI_DEVICE(intel_i2c, intel_smbus_pci_supported);
diff --git a/roms/u-boot/drivers/i2c/iproc_i2c.c b/roms/u-boot/drivers/i2c/iproc_i2c.c
new file mode 100644
index 000000000..d975e7826
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/iproc_i2c.c
@@ -0,0 +1,714 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Broadcom
+ *
+ */
+
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <common.h>
+#include <config.h>
+#include <dm.h>
+#include "errno.h"
+#include <i2c.h>
+#include "iproc_i2c.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct iproc_i2c_regs {
+ u32 cfg_reg;
+ u32 timg_cfg;
+ u32 addr_reg;
+ u32 mstr_fifo_ctrl;
+ u32 slv_fifo_ctrl;
+ u32 bitbng_ctrl;
+ u32 blnks[6]; /* Not to be used */
+ u32 mstr_cmd;
+ u32 slv_cmd;
+ u32 evt_en;
+ u32 evt_sts;
+ u32 mstr_datawr;
+ u32 mstr_datard;
+ u32 slv_datawr;
+ u32 slv_datard;
+};
+
+struct iproc_i2c {
+ struct iproc_i2c_regs __iomem *base; /* register base */
+ int bus_speed;
+ int i2c_init_done;
+};
+
+/* Function to read a value from specified register. */
+static unsigned int iproc_i2c_reg_read(u32 *reg_addr)
+{
+ unsigned int val;
+
+ val = readl((void *)(reg_addr));
+ return cpu_to_le32(val);
+}
+
+/* Function to write a value ('val') in to a specified register. */
+static int iproc_i2c_reg_write(u32 *reg_addr, unsigned int val)
+{
+ val = cpu_to_le32(val);
+ writel(val, (void *)(reg_addr));
+ return 0;
+}
+
+#if defined(DEBUG)
+static int iproc_dump_i2c_regs(struct iproc_i2c *bus_prvdata)
+{
+ struct iproc_i2c_regs *base = bus_prvdata->base;
+ unsigned int regval;
+
+ debug("\n----------------------------------------------\n");
+ debug("%s: Dumping SMBus registers...\n", __func__);
+
+ regval = iproc_i2c_reg_read(&base->cfg_reg);
+ debug("CCB_SMB_CFG_REG=0x%08X\n", regval);
+
+ regval = iproc_i2c_reg_read(&base->timg_cfg);
+ debug("CCB_SMB_TIMGCFG_REG=0x%08X\n", regval);
+
+ regval = iproc_i2c_reg_read(&base->addr_reg);
+ debug("CCB_SMB_ADDR_REG=0x%08X\n", regval);
+
+ regval = iproc_i2c_reg_read(&base->mstr_fifo_ctrl);
+ debug("CCB_SMB_MSTRFIFOCTL_REG=0x%08X\n", regval);
+
+ regval = iproc_i2c_reg_read(&base->slv_fifo_ctrl);
+ debug("CCB_SMB_SLVFIFOCTL_REG=0x%08X\n", regval);
+
+ regval = iproc_i2c_reg_read(&base->bitbng_ctrl);
+ debug("CCB_SMB_BITBANGCTL_REG=0x%08X\n", regval);
+
+ regval = iproc_i2c_reg_read(&base->mstr_cmd);
+ debug("CCB_SMB_MSTRCMD_REG=0x%08X\n", regval);
+
+ regval = iproc_i2c_reg_read(&base->slv_cmd);
+ debug("CCB_SMB_SLVCMD_REG=0x%08X\n", regval);
+
+ regval = iproc_i2c_reg_read(&base->evt_en);
+ debug("CCB_SMB_EVTEN_REG=0x%08X\n", regval);
+
+ regval = iproc_i2c_reg_read(&base->evt_sts);
+ debug("CCB_SMB_EVTSTS_REG=0x%08X\n", regval);
+
+ regval = iproc_i2c_reg_read(&base->mstr_datawr);
+ debug("CCB_SMB_MSTRDATAWR_REG=0x%08X\n", regval);
+
+ regval = iproc_i2c_reg_read(&base->mstr_datard);
+ debug("CCB_SMB_MSTRDATARD_REG=0x%08X\n", regval);
+
+ regval = iproc_i2c_reg_read(&base->slv_datawr);
+ debug("CCB_SMB_SLVDATAWR_REG=0x%08X\n", regval);
+
+ regval = iproc_i2c_reg_read(&base->slv_datard);
+ debug("CCB_SMB_SLVDATARD_REG=0x%08X\n", regval);
+
+ debug("----------------------------------------------\n\n");
+ return 0;
+}
+#else
+static int iproc_dump_i2c_regs(struct iproc_i2c *bus_prvdata)
+{
+ return 0;
+}
+#endif
+
+/*
+ * Function to ensure that the previous transaction was completed before
+ * initiating a new transaction. It can also be used in polling mode to
+ * check status of completion of a command
+ */
+static int iproc_i2c_startbusy_wait(struct iproc_i2c *bus_prvdata)
+{
+ struct iproc_i2c_regs *base = bus_prvdata->base;
+ unsigned int regval;
+
+ regval = iproc_i2c_reg_read(&base->mstr_cmd);
+
+ /* Check if an operation is in progress. During probe it won't be.
+ * But when shutdown/remove was called we want to make sure that
+ * the transaction in progress completed
+ */
+ if (regval & CCB_SMB_MSTRSTARTBUSYCMD_MASK) {
+ unsigned int i = 0;
+
+ do {
+ mdelay(10);
+ i++;
+ regval = iproc_i2c_reg_read(&base->mstr_cmd);
+
+ /* If start-busy bit cleared, exit the loop */
+ } while ((regval & CCB_SMB_MSTRSTARTBUSYCMD_MASK) &&
+ (i < IPROC_SMB_MAX_RETRIES));
+
+ if (i >= IPROC_SMB_MAX_RETRIES) {
+ pr_err("%s: START_BUSY bit didn't clear, exiting\n",
+ __func__);
+ return -ETIMEDOUT;
+ }
+ }
+ return 0;
+}
+
+/*
+ * This function set clock frequency for SMBus block. As per hardware
+ * engineering, the clock frequency can be changed dynamically.
+ */
+static int iproc_i2c_set_clk_freq(struct iproc_i2c *bus_prvdata)
+{
+ struct iproc_i2c_regs *base = bus_prvdata->base;
+ unsigned int regval;
+
+ regval = iproc_i2c_reg_read(&base->timg_cfg);
+
+ switch (bus_prvdata->bus_speed) {
+ case I2C_SPEED_STANDARD_RATE:
+ regval &= ~CCB_SMB_TIMGCFG_MODE400_MASK;
+ break;
+
+ case I2C_SPEED_FAST_RATE:
+ regval |= CCB_SMB_TIMGCFG_MODE400_MASK;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ iproc_i2c_reg_write(&base->timg_cfg, regval);
+ return 0;
+}
+
+static int iproc_i2c_init(struct udevice *bus)
+{
+ struct iproc_i2c *bus_prvdata = dev_get_priv(bus);
+ struct iproc_i2c_regs *base = bus_prvdata->base;
+ unsigned int regval;
+
+ debug("\nEntering %s\n", __func__);
+
+ /* Put controller in reset */
+ regval = iproc_i2c_reg_read(&base->cfg_reg);
+ regval |= CCB_SMB_CFG_RST_MASK;
+ regval &= ~CCB_SMB_CFG_SMBEN_MASK;
+ iproc_i2c_reg_write(&base->cfg_reg, regval);
+
+ /* Wait 100 usec as per spec */
+ udelay(100);
+
+ /* bring controller out of reset */
+ regval &= ~CCB_SMB_CFG_RST_MASK;
+ iproc_i2c_reg_write(&base->cfg_reg, regval);
+
+ /* Flush Tx, Rx FIFOs. Note we are setting the Rx FIFO threshold to 0.
+ * May be OK since we are setting RX_EVENT and RX_FIFO_FULL interrupts
+ */
+ regval = CCB_SMB_MSTRRXFIFOFLSH_MASK | CCB_SMB_MSTRTXFIFOFLSH_MASK;
+ iproc_i2c_reg_write(&base->mstr_fifo_ctrl, regval);
+
+ /* Enable SMbus block. Note, we are setting MASTER_RETRY_COUNT to zero
+ * since there will be only one master
+ */
+ regval = iproc_i2c_reg_read(&base->cfg_reg);
+ regval |= CCB_SMB_CFG_SMBEN_MASK;
+ iproc_i2c_reg_write(&base->cfg_reg, regval);
+
+ /* Set default clock frequency */
+ iproc_i2c_set_clk_freq(bus_prvdata);
+
+ /* Disable intrs */
+ iproc_i2c_reg_write(&base->evt_en, 0);
+
+ /* Clear intrs (W1TC) */
+ regval = iproc_i2c_reg_read(&base->evt_sts);
+ iproc_i2c_reg_write(&base->evt_sts, regval);
+
+ bus_prvdata->i2c_init_done = 1;
+
+ iproc_dump_i2c_regs(bus_prvdata);
+ debug("%s: Init successful\n", __func__);
+
+ return 0;
+}
+
+/*
+ * This function copies data to SMBus's Tx FIFO. Valid for write transactions
+ * only
+ *
+ * base_addr: Mapped address of this SMBus instance
+ * dev_addr: SMBus (I2C) device address. We are assuming 7-bit addresses
+ * initially
+ * info: Data to copy in to Tx FIFO. For read commands, the size should be
+ * set to zero by the caller
+ *
+ */
+static void iproc_i2c_write_trans_data(struct iproc_i2c *bus_prvdata,
+ unsigned short dev_addr,
+ struct iproc_xact_info *info)
+{
+ struct iproc_i2c_regs *base = bus_prvdata->base;
+ unsigned int regval;
+ unsigned int i;
+ unsigned int num_data_bytes = 0;
+
+ debug("%s: dev_addr=0x%X cmd_valid=%d cmd=0x%02x size=%u proto=%d buf[] %x\n",
+ __func__, dev_addr, info->cmd_valid,
+ info->command, info->size, info->smb_proto, info->data[0]);
+
+ /* Write SMBus device address first */
+ /* Note, we are assuming 7-bit addresses for now. For 10-bit addresses,
+ * we may have one more write to send the upper 3 bits of 10-bit addr
+ */
+ iproc_i2c_reg_write(&base->mstr_datawr, dev_addr);
+
+ /* If the protocol needs command code, copy it */
+ if (info->cmd_valid)
+ iproc_i2c_reg_write(&base->mstr_datawr, info->command);
+
+ /* Depending on the SMBus protocol, we need to write additional
+ * transaction data in to Tx FIFO. Refer to section 5.5 of SMBus
+ * spec for sequence for a transaction
+ */
+ switch (info->smb_proto) {
+ case SMBUS_PROT_RECV_BYTE:
+ /* No additional data to be written */
+ num_data_bytes = 0;
+ break;
+
+ case SMBUS_PROT_SEND_BYTE:
+ num_data_bytes = info->size;
+ break;
+
+ case SMBUS_PROT_RD_BYTE:
+ case SMBUS_PROT_RD_WORD:
+ case SMBUS_PROT_BLK_RD:
+ /* Write slave address with R/W~ set (bit #0) */
+ iproc_i2c_reg_write(&base->mstr_datawr,
+ dev_addr | 0x1);
+ num_data_bytes = 0;
+ break;
+
+ case SMBUS_PROT_BLK_WR_BLK_RD_PROC_CALL:
+ iproc_i2c_reg_write(&base->mstr_datawr,
+ dev_addr | 0x1 |
+ CCB_SMB_MSTRWRSTS_MASK);
+ num_data_bytes = 0;
+ break;
+
+ case SMBUS_PROT_WR_BYTE:
+ case SMBUS_PROT_WR_WORD:
+ /* No additional bytes to be written.
+ * Data portion is written in the
+ * 'for' loop below
+ */
+ num_data_bytes = info->size;
+ break;
+
+ case SMBUS_PROT_BLK_WR:
+ /* 3rd byte is byte count */
+ iproc_i2c_reg_write(&base->mstr_datawr, info->size);
+ num_data_bytes = info->size;
+ break;
+
+ default:
+ return;
+ }
+
+ /* Copy actual data from caller, next. In general, for reads,
+ * no data is copied
+ */
+ for (i = 0; num_data_bytes; --num_data_bytes, i++) {
+ /* For the last byte, set MASTER_WR_STATUS bit */
+ regval = (num_data_bytes == 1) ?
+ info->data[i] | CCB_SMB_MSTRWRSTS_MASK :
+ info->data[i];
+
+ iproc_i2c_reg_write(&base->mstr_datawr, regval);
+ }
+}
+
+static int iproc_i2c_data_send(struct iproc_i2c *bus_prvdata,
+ unsigned short addr,
+ struct iproc_xact_info *info)
+{
+ struct iproc_i2c_regs *base = bus_prvdata->base;
+ int rc, retry = 3;
+ unsigned int regval;
+
+ /* Make sure the previous transaction completed */
+ rc = iproc_i2c_startbusy_wait(bus_prvdata);
+
+ if (rc < 0) {
+ pr_err("%s: Send: bus is busy, exiting\n", __func__);
+ return rc;
+ }
+
+ /* Write transaction bytes to Tx FIFO */
+ iproc_i2c_write_trans_data(bus_prvdata, addr, info);
+
+ /* Program master command register (0x30) with protocol type and set
+ * start_busy_command bit to initiate the write transaction
+ */
+ regval = (info->smb_proto << CCB_SMB_MSTRSMBUSPROTO_SHIFT) |
+ CCB_SMB_MSTRSTARTBUSYCMD_MASK;
+
+ iproc_i2c_reg_write(&base->mstr_cmd, regval);
+
+ /* Check for Master status */
+ regval = iproc_i2c_reg_read(&base->mstr_cmd);
+ while (regval & CCB_SMB_MSTRSTARTBUSYCMD_MASK) {
+ mdelay(10);
+ if (retry-- <= 0)
+ break;
+ regval = iproc_i2c_reg_read(&base->mstr_cmd);
+ }
+
+ /* If start_busy bit cleared, check if there are any errors */
+ if (!(regval & CCB_SMB_MSTRSTARTBUSYCMD_MASK)) {
+ /* start_busy bit cleared, check master_status field now */
+ regval &= CCB_SMB_MSTRSTS_MASK;
+ regval >>= CCB_SMB_MSTRSTS_SHIFT;
+
+ if (regval != MSTR_STS_XACT_SUCCESS) {
+ /* Error We can flush Tx FIFO here */
+ pr_err("%s: ERROR: Error in transaction %u, exiting\n",
+ __func__, regval);
+ return -EREMOTEIO;
+ }
+ }
+
+ return 0;
+}
+
+static int iproc_i2c_data_recv(struct iproc_i2c *bus_prvdata,
+ unsigned short addr,
+ struct iproc_xact_info *info,
+ unsigned int *num_bytes_read)
+{
+ struct iproc_i2c_regs *base = bus_prvdata->base;
+ int rc, retry = 3;
+ unsigned int regval;
+
+ /* Make sure the previous transaction completed */
+ rc = iproc_i2c_startbusy_wait(bus_prvdata);
+
+ if (rc < 0) {
+ pr_err("%s: Receive: Bus is busy, exiting\n", __func__);
+ return rc;
+ }
+
+ /* Program all transaction bytes into master Tx FIFO */
+ iproc_i2c_write_trans_data(bus_prvdata, addr, info);
+
+ /* Program master command register (0x30) with protocol type and set
+ * start_busy_command bit to initiate the write transaction
+ */
+ regval = (info->smb_proto << CCB_SMB_MSTRSMBUSPROTO_SHIFT) |
+ CCB_SMB_MSTRSTARTBUSYCMD_MASK | info->size;
+
+ iproc_i2c_reg_write(&base->mstr_cmd, regval);
+
+ /* Check for Master status */
+ regval = iproc_i2c_reg_read(&base->mstr_cmd);
+ while (regval & CCB_SMB_MSTRSTARTBUSYCMD_MASK) {
+ udelay(1000);
+ if (retry-- <= 0)
+ break;
+ regval = iproc_i2c_reg_read(&base->mstr_cmd);
+ }
+
+ /* If start_busy bit cleared, check if there are any errors */
+ if (!(regval & CCB_SMB_MSTRSTARTBUSYCMD_MASK)) {
+ /* start_busy bit cleared, check master_status field now */
+ regval &= CCB_SMB_MSTRSTS_MASK;
+ regval >>= CCB_SMB_MSTRSTS_SHIFT;
+
+ if (regval != MSTR_STS_XACT_SUCCESS) {
+ /* We can flush Tx FIFO here */
+ pr_err("%s: Error in transaction %d, exiting\n",
+ __func__, regval);
+ return -EREMOTEIO;
+ }
+ }
+
+ /* Read received byte(s), after TX out address etc */
+ regval = iproc_i2c_reg_read(&base->mstr_datard);
+
+ /* For block read, protocol (hw) returns byte count,
+ * as the first byte
+ */
+ if (info->smb_proto == SMBUS_PROT_BLK_RD) {
+ int i;
+
+ *num_bytes_read = regval & CCB_SMB_MSTRRDDATA_MASK;
+
+ /* Limit to reading a max of 32 bytes only; just a safeguard.
+ * If # bytes read is a number > 32, check transaction set up,
+ * and contact hw engg. Assumption: PEC is disabled
+ */
+ for (i = 0;
+ (i < *num_bytes_read) && (i < I2C_SMBUS_BLOCK_MAX);
+ i++) {
+ /* Read Rx FIFO for data bytes */
+ regval = iproc_i2c_reg_read(&base->mstr_datard);
+ info->data[i] = regval & CCB_SMB_MSTRRDDATA_MASK;
+ }
+ } else {
+ /* 1 Byte data */
+ *info->data = regval & CCB_SMB_MSTRRDDATA_MASK;
+ *num_bytes_read = 1;
+ }
+
+ return 0;
+}
+
+static int i2c_write_byte(struct iproc_i2c *bus_prvdata,
+ u8 devaddr, u8 regoffset, u8 value)
+{
+ int rc;
+ struct iproc_xact_info info;
+
+ devaddr <<= 1;
+
+ info.cmd_valid = 1;
+ info.command = (unsigned char)regoffset;
+ info.data = &value;
+ info.size = 1;
+ info.flags = 0;
+ info.smb_proto = SMBUS_PROT_WR_BYTE;
+ /* Refer to i2c_smbus_write_byte params passed. */
+ rc = iproc_i2c_data_send(bus_prvdata, devaddr, &info);
+
+ if (rc < 0) {
+ pr_err("%s: %s error accessing device 0x%X\n",
+ __func__, "Write", devaddr);
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+int i2c_write(struct udevice *bus,
+ uchar chip, uint regaddr, int alen, uchar *buffer, int len)
+{
+ struct iproc_i2c *bus_prvdata = dev_get_priv(bus);
+ int i, data_len;
+ u8 *data;
+
+ if (len > 256) {
+ pr_err("I2C write: address out of range\n");
+ return 1;
+ }
+
+ if (len < 1) {
+ pr_err("I2C write: Need offset addr and value\n");
+ return 1;
+ }
+
+ /* buffer contains offset addr followed by value to be written */
+ regaddr = buffer[0];
+ data = &buffer[1];
+ data_len = len - 1;
+
+ for (i = 0; i < data_len; i++) {
+ if (i2c_write_byte(bus_prvdata, chip, regaddr + i, data[i])) {
+ pr_err("I2C write (%d): I/O error\n", i);
+ iproc_i2c_init(bus);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int i2c_read_byte(struct iproc_i2c *bus_prvdata,
+ u8 devaddr, u8 regoffset, u8 *value)
+{
+ int rc;
+ struct iproc_xact_info info;
+ unsigned int num_bytes_read = 0;
+
+ devaddr <<= 1;
+
+ info.cmd_valid = 1;
+ info.command = (unsigned char)regoffset;
+ info.data = value;
+ info.size = 1;
+ info.flags = 0;
+ info.smb_proto = SMBUS_PROT_RD_BYTE;
+ /* Refer to i2c_smbus_read_byte for params passed. */
+ rc = iproc_i2c_data_recv(bus_prvdata, devaddr, &info, &num_bytes_read);
+
+ if (rc < 0) {
+ pr_err("%s: %s error accessing device 0x%X\n",
+ __func__, "Read", devaddr);
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+int i2c_read(struct udevice *bus,
+ uchar chip, uint addr, int alen, uchar *buffer, int len)
+{
+ struct iproc_i2c *bus_prvdata = dev_get_priv(bus);
+ int i;
+
+ if (len > 256) {
+ pr_err("I2C read: address out of range\n");
+ return 1;
+ }
+
+ for (i = 0; i < len; i++) {
+ if (i2c_read_byte(bus_prvdata, chip, addr + i, &buffer[i])) {
+ pr_err("I2C read: I/O error\n");
+ iproc_i2c_init(bus);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int iproc_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
+{
+ int ret = 0;
+
+ debug("%s: %d messages\n", __func__, nmsgs);
+
+ for (; nmsgs > 0; nmsgs--, msg++) {
+ if (msg->flags & I2C_M_RD)
+ ret = i2c_read(bus, msg->addr, 0, 0,
+ msg->buf, msg->len);
+ else
+ ret = i2c_write(bus, msg->addr, 0, 0,
+ msg->buf, msg->len);
+ }
+
+ return ret;
+}
+
+static int iproc_i2c_probe_chip(struct udevice *bus, uint chip_addr,
+ uint chip_flags)
+{
+ struct iproc_i2c *bus_prvdata = dev_get_priv(bus);
+ struct iproc_i2c_regs *base = bus_prvdata->base;
+ u32 regval;
+
+ debug("\n%s: Entering chip probe\n", __func__);
+
+ /* Init internal regs, disable intrs (and then clear intrs), set fifo
+ * thresholds, etc.
+ */
+ if (!bus_prvdata->i2c_init_done)
+ iproc_i2c_init(bus);
+
+ regval = (chip_addr << 1);
+ iproc_i2c_reg_write(&base->mstr_datawr, regval);
+ regval = ((SMBUS_PROT_QUICK_CMD << CCB_SMB_MSTRSMBUSPROTO_SHIFT) |
+ (1 << CCB_SMB_MSTRSTARTBUSYCMD_SHIFT));
+ iproc_i2c_reg_write(&base->mstr_cmd, regval);
+
+ do {
+ udelay(100);
+ regval = iproc_i2c_reg_read(&base->mstr_cmd);
+ regval &= CCB_SMB_MSTRSTARTBUSYCMD_MASK;
+ } while (regval);
+
+ regval = iproc_i2c_reg_read(&base->mstr_cmd);
+
+ if ((regval & CCB_SMB_MSTRSTS_MASK) != 0)
+ return -1;
+
+ iproc_dump_i2c_regs(bus_prvdata);
+ debug("%s: chip probe successful\n", __func__);
+
+ return 0;
+}
+
+static int iproc_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
+{
+ struct iproc_i2c *bus_prvdata = dev_get_priv(bus);
+
+ bus_prvdata->bus_speed = speed;
+ return iproc_i2c_set_clk_freq(bus_prvdata);
+}
+
+/**
+ * i2c_get_bus_speed - get i2c bus speed
+ *
+ * This function returns the speed of operation in Hz
+ */
+int iproc_i2c_get_bus_speed(struct udevice *bus)
+{
+ struct iproc_i2c *bus_prvdata = dev_get_priv(bus);
+ struct iproc_i2c_regs *base = bus_prvdata->base;
+ unsigned int regval;
+ int ret = 0;
+
+ regval = iproc_i2c_reg_read(&base->timg_cfg);
+ regval = (regval & CCB_SMB_TIMGCFG_MODE400_MASK) >>
+ CCB_SMB_TIMGCFG_MODE400_SHIFT;
+
+ switch (regval) {
+ case 0:
+ ret = I2C_SPEED_STANDARD_RATE;
+ break;
+ case 1:
+ ret = I2C_SPEED_FAST_RATE;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int iproc_i2c_probe(struct udevice *bus)
+{
+ return iproc_i2c_init(bus);
+}
+
+static int iproc_i2c_of_to_plat(struct udevice *bus)
+{
+ struct iproc_i2c *bus_prvdata = dev_get_priv(bus);
+ int node = dev_of_offset(bus);
+ const void *blob = gd->fdt_blob;
+
+ bus_prvdata->base = map_physmem(dev_read_addr(bus),
+ sizeof(void *),
+ MAP_NOCACHE);
+
+ bus_prvdata->bus_speed =
+ fdtdec_get_int(blob, node, "bus-frequency",
+ I2C_SPEED_STANDARD_RATE);
+
+ return 0;
+}
+
+static const struct dm_i2c_ops iproc_i2c_ops = {
+ .xfer = iproc_i2c_xfer,
+ .probe_chip = iproc_i2c_probe_chip,
+ .set_bus_speed = iproc_i2c_set_bus_speed,
+ .get_bus_speed = iproc_i2c_get_bus_speed,
+};
+
+static const struct udevice_id iproc_i2c_ids[] = {
+ { .compatible = "brcm,iproc-i2c" },
+ { }
+};
+
+U_BOOT_DRIVER(iproc_i2c) = {
+ .name = "iproc_i2c",
+ .id = UCLASS_I2C,
+ .of_match = iproc_i2c_ids,
+ .of_to_plat = iproc_i2c_of_to_plat,
+ .probe = iproc_i2c_probe,
+ .priv_auto = sizeof(struct iproc_i2c),
+ .ops = &iproc_i2c_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/roms/u-boot/drivers/i2c/iproc_i2c.h b/roms/u-boot/drivers/i2c/iproc_i2c.h
new file mode 100644
index 000000000..8c3d84f62
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/iproc_i2c.h
@@ -0,0 +1,335 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2018 Broadcom
+ *
+ */
+
+#ifndef __IPROC_I2C_H__
+#define __IPROC_I2C_H__
+
+/* Registers */
+#define CCB_SMB_CFG_REG 0x0
+
+#define CCB_SMB_CFG_RST_MASK 0x80000000
+#define CCB_SMB_CFG_RST_SHIFT 31
+
+#define CCB_SMB_CFG_SMBEN_MASK 0x40000000
+#define CCB_SMB_CFG_SMBEN_SHIFT 30
+
+#define CCB_SMB_CFG_BITBANGEN_MASK 0x20000000
+#define CCB_SMB_CFG_BITBANGEN_SHIFT 29
+
+#define CCB_SMB_CFG_EN_NIC_SMBADDR0_MASK 0x10000000
+#define CCB_SMB_CFG_EN_NIC_SMBADDR0_SHIFT 28
+
+#define CCB_SMB_CFG_PROMISCMODE_MASK 0x08000000
+#define CCB_SMB_CFG_PROMISCMODE_SHIFT 27
+
+#define CCB_SMB_CFG_TSTMPCNTEN_MASK 0x04000000
+#define CCB_SMB_CFG_TSTMPCNTEN_SHIFT 26
+
+#define CCB_SMB_CFG_MSTRRTRYCNT_MASK 0x000F0000
+#define CCB_SMB_CFG_MSTRRTRYCNT_SHIFT 16
+
+#define CCB_SMB_TIMGCFG_REG 0x4
+
+#define CCB_SMB_TIMGCFG_MODE400_MASK 0x80000000
+#define CCB_SMB_TIMGCFG_MODE400_SHIFT 31
+
+#define CCB_SMB_TIMGCFG_RNDSLVSTR_MASK 0x7F000000
+#define CCB_SMB_TIMGCFG_RNDSLVSTR_SHIFT 24
+
+#define CCB_SMB_TIMGCFG_PERSLVSTR_MASK 0x00FF0000
+#define CCB_SMB_TIMGCFG_PERSLVSTR_SHIFT 16
+
+#define CCB_SMB_TIMGCFG_IDLTIME_MASK 0x0000FF00
+#define CCB_SMB_TIMGCFG_IDLTIME_SHIFT 8
+
+#define CCB_SMB_ADDR_REG 0x8
+
+#define CCB_SMB_EN_NIC_SMBADDR3_MASK 0x80000000
+#define CCB_SMB_EN_NIC_SMBADDR3_SHIFT 31
+
+#define CCB_SMB_NIC_SMBADDR3_MASK 0x7F000000
+#define CCB_SMB_NIC_SMBADDR3_SHIFT 24
+
+#define CCB_SMB_EN_NIC_SMBADDR2_MASK 0x00800000
+#define CCB_SMB_EN_NIC_SMBADDR2_SHIFT 23
+
+#define CCB_SMB_NIC_SMBADDR2_MASK 0x007F0000
+#define CCB_SMB_NIC_SMBADDR2_SHIFT 16
+
+#define CCB_SMB_EN_NIC_SMBADDR1_MASK 0x00008000
+#define CCB_SMB_EN_NIC_SMBADDR1_SHIFT 15
+
+#define CCB_SMB_NIC_SMBADDR1_MASK 0x00007F00
+#define CCB_SMB_NIC_SMBADDR1_SHIFT 8
+
+#define CCB_SMB_EN_NIC_SMBADDR0_MASK 0x00000080
+#define CCB_SMB_EN_NIC_SMBADDR0_SHIFT 7
+
+#define CCB_SMB_NIC_SMBADDR0_MASK 0x0000007F
+#define CCB_SMB_NIC_SMBADDR0_SHIFT 0
+
+#define CCB_SMB_MSTRFIFOCTL_REG 0xC
+
+#define CCB_SMB_MSTRRXFIFOFLSH_MASK 0x80000000
+#define CCB_SMB_MSTRRXFIFOFLSH_SHIFT 31
+
+#define CCB_SMB_MSTRTXFIFOFLSH_MASK 0x40000000
+#define CCB_SMB_MSTRTXFIFOFLSH_SHIFT 30
+
+#define CCB_SMB_MSTRRXPKTCNT_MASK 0x007F0000
+#define CCB_SMB_MSTRRXPKTCNT_SHIFT 16
+
+#define CCB_SMB_MSTRRXFIFOTHR_MASK 0x00003F00
+#define CCB_SMB_MSTRRXFIFOTHR_SHIFT 8
+
+#define CCB_SMB_SLVFIFOCTL_REG 0x10
+
+#define CCB_SMB_SLVRXFIFOFLSH_MASK 0x80000000
+#define CCB_SMB_SLVRXFIFOFLSH_SHIFT 31
+
+#define CCB_SMB_SLVTXFIFOFLSH_MASK 0x40000000
+#define CCB_SMB_SLVTXFIFOFLSH_SHIFT 30
+
+#define CCB_SMB_SLVRXPKTCNT_MASK 0x007F0000
+#define CCB_SMB_SLVRXPKTCNT_SHIFT 16
+
+#define CCB_SMB_SLVRXFIFOTHR_MASK 0x00003F00
+#define CCB_SMB_SLVRXFIFOTHR_SHIFT 8
+
+#define CCB_SMB_BITBANGCTL_REG 0x14
+
+#define CCB_SMB_SMBCLKIN_MASK 0x80000000
+#define CCB_SMB_SMBCLKIN_SHIFT 31
+
+#define CCB_SMB_SMBCLKOUTEN_MASK 0x40000000
+#define CCB_SMB_SMBCLKOUTEN_SHIFT 30
+
+#define CCB_SMB_SMBDATAIN_MASK 0x20000000
+#define CCB_SMB_SMBDATAIN_SHIFT 29
+
+#define CCB_SMB_SMBDATAOUTEN_MASK 0x10000000
+#define CCB_SMB_SMBDATAOUTEN_SHIFT 28
+
+#define CCB_SMB_MSTRCMD_REG 0x30
+
+#define CCB_SMB_MSTRSTARTBUSYCMD_MASK 0x80000000
+#define CCB_SMB_MSTRSTARTBUSYCMD_SHIFT 31
+
+#define CCB_SMB_MSTRABORT_MASK 0x40000000
+#define CCB_SMB_MSTRABORT_SHIFT 30
+
+#define CCB_SMB_MSTRSTS_MASK 0x0E000000
+#define CCB_SMB_MSTRSTS_SHIFT 25
+
+#define CCB_SMB_MSTRSMBUSPROTO_MASK 0x00001E00
+#define CCB_SMB_MSTRSMBUSPROTO_SHIFT 9
+
+#define CCB_SMB_MSTRPEC_MASK 0x00000100
+#define CCB_SMB_MSTRPEC_SHIFT 8
+
+#define CCB_SMB_MSTRRDBYTECNT_MASK 0x000000FF
+#define CCB_SMB_MSTRRDBYTECNT_SHIFT 0
+
+#define CCB_SMB_SLVCMD_REG 0x34
+
+#define CCB_SMB_SLVSTARTBUSYCMD_MASK 0x80000000
+#define CCB_SMB_SLVSTARTBUSYCMD_SHIFT 31
+
+#define CCB_SMB_SLVABORT_MASK 0x40000000
+#define CCB_SMB_SLVABORT_SHIFT 30
+
+#define CCB_SMB_SLVSTS_MASK 0x03800000
+#define CCB_SMB_SLVSTS_SHIFT 23
+
+#define CCB_SMB_SLVPEC_MASK 0x00000100
+#define CCB_SMB_SLVPEC_SHIFT 8
+
+#define CCB_SMB_EVTEN_REG 0x38
+
+#define CCB_SMB_MSTRRXFIFOFULLEN_MASK 0x80000000
+#define CCB_SMB_MSTRRXFIFOFULLEN_SHIFT 31
+
+#define CCB_SMB_MSTRRXFIFOTHRHITEN_MASK 0x40000000
+#define CCB_SMB_MSTRRXFIFOTHRHITEN_SHIFT 30
+
+#define CCB_SMB_MSTRRXEVTEN_MASK 0x20000000
+#define CCB_SMB_MSTRRXEVTEN_SHIFT 29
+
+#define CCB_SMB_MSTRSTARTBUSYEN_MASK 0x10000000
+#define CCB_SMB_MSTRSTARTBUSYEN_SHIFT 28
+
+#define CCB_SMB_MSTRTXUNDEN_MASK 0x08000000
+#define CCB_SMB_MSTRTXUNDEN_SHIFT 27
+
+#define CCB_SMB_SLVRXFIFOFULLEN_MASK 0x04000000
+#define CCB_SMB_SLVRXFIFOFULLEN_SHIFT 26
+
+#define CCB_SMB_SLVRXFIFOTHRHITEN_MASK 0x02000000
+#define CCB_SMB_SLVRXFIFOTHRHITEN_SHIFT 25
+
+#define CCB_SMB_SLVRXEVTEN_MASK 0x01000000
+#define CCB_SMB_SLVRXEVTEN_SHIFT 24
+
+#define CCB_SMB_SLVSTARTBUSYEN_MASK 0x00800000
+#define CCB_SMB_SLVSTARTBUSYEN_SHIFT 23
+
+#define CCB_SMB_SLVTXUNDEN_MASK 0x00400000
+#define CCB_SMB_SLVTXUNDEN_SHIFT 22
+
+#define CCB_SMB_SLVRDEVTEN_MASK 0x00200000
+#define CCB_SMB_SLVRDEVTEN_SHIFT 21
+
+#define CCB_SMB_EVTSTS_REG 0x3C
+
+#define CCB_SMB_MSTRRXFIFOFULLSTS_MASK 0x80000000
+#define CCB_SMB_MSTRRXFIFOFULLSTS_SHIFT 31
+
+#define CCB_SMB_MSTRRXFIFOTHRHITSTS_MASK 0x40000000
+#define CCB_SMB_MSTRRXFIFOTHRHITSTS_SHIFT 30
+
+#define CCB_SMB_MSTRRXEVTSTS_MASK 0x20000000
+#define CCB_SMB_MSTRRXEVTSTS_SHIFT 29
+
+#define CCB_SMB_MSTRSTARTBUSYSTS_MASK 0x10000000
+#define CCB_SMB_MSTRSTARTBUSYSTS_SHIFT 28
+
+#define CCB_SMB_MSTRTXUNDSTS_MASK 0x08000000
+#define CCB_SMB_MSTRTXUNDSTS_SHIFT 27
+
+#define CCB_SMB_SLVRXFIFOFULLSTS_MASK 0x04000000
+#define CCB_SMB_SLVRXFIFOFULLSTS_SHIFT 26
+
+#define CCB_SMB_SLVRXFIFOTHRHITSTS_MASK 0x02000000
+#define CCB_SMB_SLVRXFIFOTHRHITSTS_SHIFT 25
+
+#define CCB_SMB_SLVRXEVTSTS_MASK 0x01000000
+#define CCB_SMB_SLVRXEVTSTS_SHIFT 24
+
+#define CCB_SMB_SLVSTARTBUSYSTS_MASK 0x00800000
+#define CCB_SMB_SLVSTARTBUSYSTS_SHIFT 23
+
+#define CCB_SMB_SLVTXUNDSTS_MASK 0x00400000
+#define CCB_SMB_SLVTXUNDSTS_SHIFT 22
+
+#define CCB_SMB_SLVRDEVTSTS_MASK 0x00200000
+#define CCB_SMB_SLVRDEVTSTS_SHIFT 21
+
+#define CCB_SMB_MSTRDATAWR_REG 0x40
+
+#define CCB_SMB_MSTRWRSTS_MASK 0x80000000
+#define CCB_SMB_MSTRWRSTS_SHIFT 31
+
+#define CCB_SMB_MSTRWRDATA_MASK 0x000000FF
+#define CCB_SMB_MSTRWRDATA_SHIFT 0
+
+#define CCB_SMB_MSTRDATARD_REG 0x44
+
+#define CCB_SMB_MSTRRDSTS_MASK 0xC0000000
+#define CCB_SMB_MSTRRDSTS_SHIFT 30
+
+#define CCB_SMB_MSTRRDPECERR_MASK 0x20000000
+#define CCB_SMB_MSTRRDPECERR_SHIFT 29
+
+#define CCB_SMB_MSTRRDDATA_MASK 0x000000FF
+#define CCB_SMB_MSTRRDDATA_SHIFT 0
+
+#define CCB_SMB_SLVDATAWR_REG 0x48
+
+#define CCB_SMB_SLVWRSTS_MASK 0x80000000
+#define CCB_SMB_SLVWRSTS_SHIFT 31
+
+#define CCB_SMB_SLVWRDATA_MASK 0x000000FF
+#define CCB_SMB_SLVWRDATA_SHIFT 0
+
+#define CCB_SMB_SLVDATARD_REG 0x4C
+
+#define CCB_SMB_SLVRDSTS_MASK 0xC0000000
+#define CCB_SMB_SLVRDSTS_SHIFT 30
+
+#define CCB_SMB_SLVRDERRSTS_MASK 0x30000000
+#define CCB_SMB_SLVRDERRSTS_SHIFT 28
+
+#define CCB_SMB_SLVRDDATA_MASK 0x000000FF
+#define CCB_SMB_SLVRDDATA_SHIFT 0
+
+/* --Registers-- */
+
+/* Transaction error codes defined in Master command register (0x30) */
+#define MSTR_STS_XACT_SUCCESS 0
+#define MSTR_STS_LOST_ARB 1
+#define MSTR_STS_NACK_FIRST_BYTE 2
+
+/* NACK on a byte other than
+ * the first byte
+ */
+#define MSTR_STS_NACK_NON_FIRST_BYTE 3
+
+#define MSTR_STS_TTIMEOUT_EXCEEDED 4
+#define MSTR_STS_TX_TLOW_MEXT_EXCEEDED 5
+#define MSTR_STS_RX_TLOW_MEXT_EXCEEDED 6
+
+/* SMBUS protocol values defined in register 0x30 */
+#define SMBUS_PROT_QUICK_CMD 0
+#define SMBUS_PROT_SEND_BYTE 1
+#define SMBUS_PROT_RECV_BYTE 2
+#define SMBUS_PROT_WR_BYTE 3
+#define SMBUS_PROT_RD_BYTE 4
+#define SMBUS_PROT_WR_WORD 5
+#define SMBUS_PROT_RD_WORD 6
+#define SMBUS_PROT_BLK_WR 7
+#define SMBUS_PROT_BLK_RD 8
+#define SMBUS_PROT_PROC_CALL 9
+#define SMBUS_PROT_BLK_WR_BLK_RD_PROC_CALL 10
+
+/* SMBUS Block speed mode */
+#define SMBUS_BLOCK_MODE_100 0
+#define SMBUS_BLOCK_MODE_400 1
+
+#define BUS_BUSY_COUNT 100000 /* Number can be changed later */
+#define IPROC_I2C_INVALID_ADDR 0xFF
+#define IPROC_SMB_MAX_RETRIES 35
+#define I2C_SMBUS_BLOCK_MAX 32
+#define GETREGFLDVAL(regval, mask, startbit) \
+ (((regval) & (mask)) >> (startbit))
+
+/* This enum will be used to notify the user of status of a data transfer
+ * request
+ */
+enum iproc_smb_error_code {
+ I2C_NO_ERR = 0,
+ I2C_TIMEOUT_ERR = 1,
+
+ /* Invalid parameter(s) passed to the driver */
+ I2C_INVALID_PARAM_ERR = 2,
+
+ /* The driver API was called before the present
+ * transfer was completed
+ */
+ I2C_OPER_IN_PROGRESS = 3,
+
+ /* Transfer aborted unexpectedly, for example a NACK
+ * received, before last byte was read/written
+ */
+ I2C_OPER_ABORT_ERR = 4,
+
+ /* Feature or function not supported
+ * (e.g., 10-bit addresses, or clock speeds
+ * other than 100KHz, 400KHz)
+ */
+ I2C_FUNC_NOT_SUPPORTED = 5,
+};
+
+/* Structure used to pass information to read/write functions. */
+struct iproc_xact_info {
+ unsigned char command;
+ unsigned char *data;
+ unsigned int size;
+ unsigned short flags; /* used for specifying PEC, 10-bit addresses */
+ unsigned char smb_proto; /* SMBus protocol */
+ unsigned int cmd_valid; /* true if command is valid else false */
+};
+
+#endif /* __IPROC_I2C_H__ */
diff --git a/roms/u-boot/drivers/i2c/kona_i2c.c b/roms/u-boot/drivers/i2c/kona_i2c.c
new file mode 100644
index 000000000..4edcba291
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/kona_i2c.c
@@ -0,0 +1,728 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2013 Broadcom Corporation.
+ *
+ * NOTE: This driver should be converted to driver model before June 2017.
+ * Please see doc/driver-model/i2c-howto.rst for instructions.
+ */
+
+#include <common.h>
+#include <log.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <asm/arch/sysmap.h>
+#include <asm/kona-common/clk.h>
+#include <i2c.h>
+
+/* Hardware register offsets and field defintions */
+#define CS_OFFSET 0x00000020
+#define CS_ACK_SHIFT 3
+#define CS_ACK_MASK 0x00000008
+#define CS_ACK_CMD_GEN_START 0x00000000
+#define CS_ACK_CMD_GEN_RESTART 0x00000001
+#define CS_CMD_SHIFT 1
+#define CS_CMD_CMD_NO_ACTION 0x00000000
+#define CS_CMD_CMD_START_RESTART 0x00000001
+#define CS_CMD_CMD_STOP 0x00000002
+#define CS_EN_SHIFT 0
+#define CS_EN_CMD_ENABLE_BSC 0x00000001
+
+#define TIM_OFFSET 0x00000024
+#define TIM_PRESCALE_SHIFT 6
+#define TIM_P_SHIFT 3
+#define TIM_NO_DIV_SHIFT 2
+#define TIM_DIV_SHIFT 0
+
+#define DAT_OFFSET 0x00000028
+
+#define TOUT_OFFSET 0x0000002c
+
+#define TXFCR_OFFSET 0x0000003c
+#define TXFCR_FIFO_FLUSH_MASK 0x00000080
+#define TXFCR_FIFO_EN_MASK 0x00000040
+
+#define IER_OFFSET 0x00000044
+#define IER_READ_COMPLETE_INT_MASK 0x00000010
+#define IER_I2C_INT_EN_MASK 0x00000008
+#define IER_FIFO_INT_EN_MASK 0x00000002
+#define IER_NOACK_EN_MASK 0x00000001
+
+#define ISR_OFFSET 0x00000048
+#define ISR_RESERVED_MASK 0xffffff60
+#define ISR_CMDBUSY_MASK 0x00000080
+#define ISR_READ_COMPLETE_MASK 0x00000010
+#define ISR_SES_DONE_MASK 0x00000008
+#define ISR_ERR_MASK 0x00000004
+#define ISR_TXFIFOEMPTY_MASK 0x00000002
+#define ISR_NOACK_MASK 0x00000001
+
+#define CLKEN_OFFSET 0x0000004c
+#define CLKEN_AUTOSENSE_OFF_MASK 0x00000080
+#define CLKEN_M_SHIFT 4
+#define CLKEN_N_SHIFT 1
+#define CLKEN_CLKEN_MASK 0x00000001
+
+#define FIFO_STATUS_OFFSET 0x00000054
+#define FIFO_STATUS_RXFIFO_EMPTY_MASK 0x00000004
+#define FIFO_STATUS_TXFIFO_EMPTY_MASK 0x00000010
+
+#define HSTIM_OFFSET 0x00000058
+#define HSTIM_HS_MODE_MASK 0x00008000
+#define HSTIM_HS_HOLD_SHIFT 10
+#define HSTIM_HS_HIGH_PHASE_SHIFT 5
+#define HSTIM_HS_SETUP_SHIFT 0
+
+#define PADCTL_OFFSET 0x0000005c
+#define PADCTL_PAD_OUT_EN_MASK 0x00000004
+
+#define RXFCR_OFFSET 0x00000068
+#define RXFCR_NACK_EN_SHIFT 7
+#define RXFCR_READ_COUNT_SHIFT 0
+#define RXFIFORDOUT_OFFSET 0x0000006c
+
+/* Locally used constants */
+#define MAX_RX_FIFO_SIZE 64U /* bytes */
+#define MAX_TX_FIFO_SIZE 64U /* bytes */
+
+#define I2C_TIMEOUT 100000 /* usecs */
+
+#define WAIT_INT_CHK 100 /* usecs */
+#if I2C_TIMEOUT % WAIT_INT_CHK
+#error I2C_TIMEOUT must be a multiple of WAIT_INT_CHK
+#endif
+
+/* Operations that can be commanded to the controller */
+enum bcm_kona_cmd_t {
+ BCM_CMD_NOACTION = 0,
+ BCM_CMD_START,
+ BCM_CMD_RESTART,
+ BCM_CMD_STOP,
+};
+
+/* Internal divider settings for standard mode, fast mode and fast mode plus */
+struct bus_speed_cfg {
+ uint8_t time_m; /* Number of cycles for setup time */
+ uint8_t time_n; /* Number of cycles for hold time */
+ uint8_t prescale; /* Prescale divider */
+ uint8_t time_p; /* Timing coefficient */
+ uint8_t no_div; /* Disable clock divider */
+ uint8_t time_div; /* Post-prescale divider */
+};
+
+static const struct bus_speed_cfg std_cfg_table[] = {
+ [IC_SPEED_MODE_STANDARD] = {0x01, 0x01, 0x03, 0x06, 0x00, 0x02},
+ [IC_SPEED_MODE_FAST] = {0x05, 0x01, 0x03, 0x05, 0x01, 0x02},
+ [IC_SPEED_MODE_FAST_PLUS] = {0x01, 0x01, 0x03, 0x01, 0x01, 0x03},
+};
+
+struct bcm_kona_i2c_dev {
+ void *base;
+ uint speed;
+ const struct bus_speed_cfg *std_cfg;
+};
+
+/* Keep these two defines in sync */
+#define DEF_SPD I2C_SPEED_STANDARD_RATE
+#define DEF_SPD_ENUM IC_SPEED_MODE_STANDARD
+
+#define DEF_DEVICE(num) \
+{(void *)CONFIG_SYS_I2C_BASE##num, DEF_SPD, &std_cfg_table[DEF_SPD_ENUM]}
+
+static struct bcm_kona_i2c_dev g_i2c_devs[CONFIG_SYS_MAX_I2C_BUS] = {
+#ifdef CONFIG_SYS_I2C_BASE0
+ DEF_DEVICE(0),
+#endif
+#ifdef CONFIG_SYS_I2C_BASE1
+ DEF_DEVICE(1),
+#endif
+#ifdef CONFIG_SYS_I2C_BASE2
+ DEF_DEVICE(2),
+#endif
+#ifdef CONFIG_SYS_I2C_BASE3
+ DEF_DEVICE(3),
+#endif
+#ifdef CONFIG_SYS_I2C_BASE4
+ DEF_DEVICE(4),
+#endif
+#ifdef CONFIG_SYS_I2C_BASE5
+ DEF_DEVICE(5),
+#endif
+};
+
+#define I2C_M_TEN 0x0010 /* ten bit address */
+#define I2C_M_RD 0x0001 /* read data */
+#define I2C_M_NOSTART 0x4000 /* no restart between msgs */
+
+struct kona_i2c_msg {
+ uint16_t addr;
+ uint16_t flags;
+ uint16_t len;
+ uint8_t *buf;
+};
+
+static void bcm_kona_i2c_send_cmd_to_ctrl(struct bcm_kona_i2c_dev *dev,
+ enum bcm_kona_cmd_t cmd)
+{
+ debug("%s, %d\n", __func__, cmd);
+
+ switch (cmd) {
+ case BCM_CMD_NOACTION:
+ writel((CS_CMD_CMD_NO_ACTION << CS_CMD_SHIFT) |
+ (CS_EN_CMD_ENABLE_BSC << CS_EN_SHIFT),
+ dev->base + CS_OFFSET);
+ break;
+
+ case BCM_CMD_START:
+ writel((CS_ACK_CMD_GEN_START << CS_ACK_SHIFT) |
+ (CS_CMD_CMD_START_RESTART << CS_CMD_SHIFT) |
+ (CS_EN_CMD_ENABLE_BSC << CS_EN_SHIFT),
+ dev->base + CS_OFFSET);
+ break;
+
+ case BCM_CMD_RESTART:
+ writel((CS_ACK_CMD_GEN_RESTART << CS_ACK_SHIFT) |
+ (CS_CMD_CMD_START_RESTART << CS_CMD_SHIFT) |
+ (CS_EN_CMD_ENABLE_BSC << CS_EN_SHIFT),
+ dev->base + CS_OFFSET);
+ break;
+
+ case BCM_CMD_STOP:
+ writel((CS_CMD_CMD_STOP << CS_CMD_SHIFT) |
+ (CS_EN_CMD_ENABLE_BSC << CS_EN_SHIFT),
+ dev->base + CS_OFFSET);
+ break;
+
+ default:
+ printf("Unknown command %d\n", cmd);
+ }
+}
+
+static void bcm_kona_i2c_enable_clock(struct bcm_kona_i2c_dev *dev)
+{
+ writel(readl(dev->base + CLKEN_OFFSET) | CLKEN_CLKEN_MASK,
+ dev->base + CLKEN_OFFSET);
+}
+
+static void bcm_kona_i2c_disable_clock(struct bcm_kona_i2c_dev *dev)
+{
+ writel(readl(dev->base + CLKEN_OFFSET) & ~CLKEN_CLKEN_MASK,
+ dev->base + CLKEN_OFFSET);
+}
+
+/* Wait until at least one of the mask bit(s) are set */
+static unsigned long wait_for_int_timeout(struct bcm_kona_i2c_dev *dev,
+ unsigned long time_left,
+ uint32_t mask)
+{
+ uint32_t status;
+
+ while (time_left) {
+ status = readl(dev->base + ISR_OFFSET);
+
+ if ((status & ~ISR_RESERVED_MASK) == 0) {
+ debug("Bogus I2C interrupt 0x%x\n", status);
+ continue;
+ }
+
+ /* Must flush the TX FIFO when NAK detected */
+ if (status & ISR_NOACK_MASK)
+ writel(TXFCR_FIFO_FLUSH_MASK | TXFCR_FIFO_EN_MASK,
+ dev->base + TXFCR_OFFSET);
+
+ writel(status & ~ISR_RESERVED_MASK, dev->base + ISR_OFFSET);
+
+ if (status & mask) {
+ /* We are done since one of the mask bits are set */
+ return time_left;
+ }
+ udelay(WAIT_INT_CHK);
+ time_left -= WAIT_INT_CHK;
+ }
+ return 0;
+}
+
+/* Send command to I2C bus */
+static int bcm_kona_send_i2c_cmd(struct bcm_kona_i2c_dev *dev,
+ enum bcm_kona_cmd_t cmd)
+{
+ int rc = 0;
+ unsigned long time_left = I2C_TIMEOUT;
+
+ /* Send the command */
+ bcm_kona_i2c_send_cmd_to_ctrl(dev, cmd);
+
+ /* Wait for transaction to finish or timeout */
+ time_left = wait_for_int_timeout(dev, time_left, IER_I2C_INT_EN_MASK);
+
+ if (!time_left) {
+ printf("controller timed out\n");
+ rc = -ETIMEDOUT;
+ }
+
+ /* Clear command */
+ bcm_kona_i2c_send_cmd_to_ctrl(dev, BCM_CMD_NOACTION);
+
+ return rc;
+}
+
+/* Read a single RX FIFO worth of data from the i2c bus */
+static int bcm_kona_i2c_read_fifo_single(struct bcm_kona_i2c_dev *dev,
+ uint8_t *buf, unsigned int len,
+ unsigned int last_byte_nak)
+{
+ unsigned long time_left = I2C_TIMEOUT;
+
+ /* Start the RX FIFO */
+ writel((last_byte_nak << RXFCR_NACK_EN_SHIFT) |
+ (len << RXFCR_READ_COUNT_SHIFT), dev->base + RXFCR_OFFSET);
+
+ /* Wait for FIFO read to complete */
+ time_left =
+ wait_for_int_timeout(dev, time_left, IER_READ_COMPLETE_INT_MASK);
+
+ if (!time_left) {
+ printf("RX FIFO time out\n");
+ return -EREMOTEIO;
+ }
+
+ /* Read data from FIFO */
+ for (; len > 0; len--, buf++)
+ *buf = readl(dev->base + RXFIFORDOUT_OFFSET);
+
+ return 0;
+}
+
+/* Read any amount of data using the RX FIFO from the i2c bus */
+static int bcm_kona_i2c_read_fifo(struct bcm_kona_i2c_dev *dev,
+ struct kona_i2c_msg *msg)
+{
+ unsigned int bytes_to_read = MAX_RX_FIFO_SIZE;
+ unsigned int last_byte_nak = 0;
+ unsigned int bytes_read = 0;
+ int rc;
+
+ uint8_t *tmp_buf = msg->buf;
+
+ while (bytes_read < msg->len) {
+ if (msg->len - bytes_read <= MAX_RX_FIFO_SIZE) {
+ last_byte_nak = 1; /* NAK last byte of transfer */
+ bytes_to_read = msg->len - bytes_read;
+ }
+
+ rc = bcm_kona_i2c_read_fifo_single(dev, tmp_buf, bytes_to_read,
+ last_byte_nak);
+ if (rc < 0)
+ return -EREMOTEIO;
+
+ bytes_read += bytes_to_read;
+ tmp_buf += bytes_to_read;
+ }
+
+ return 0;
+}
+
+/* Write a single byte of data to the i2c bus */
+static int bcm_kona_i2c_write_byte(struct bcm_kona_i2c_dev *dev, uint8_t data,
+ unsigned int nak_expected)
+{
+ unsigned long time_left = I2C_TIMEOUT;
+ unsigned int nak_received;
+
+ /* Clear pending session done interrupt */
+ writel(ISR_SES_DONE_MASK, dev->base + ISR_OFFSET);
+
+ /* Send one byte of data */
+ writel(data, dev->base + DAT_OFFSET);
+
+ time_left = wait_for_int_timeout(dev, time_left, IER_I2C_INT_EN_MASK);
+
+ if (!time_left) {
+ debug("controller timed out\n");
+ return -ETIMEDOUT;
+ }
+
+ nak_received = readl(dev->base + CS_OFFSET) & CS_ACK_MASK ? 1 : 0;
+
+ if (nak_received ^ nak_expected) {
+ debug("unexpected NAK/ACK\n");
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+/* Write a single TX FIFO worth of data to the i2c bus */
+static int bcm_kona_i2c_write_fifo_single(struct bcm_kona_i2c_dev *dev,
+ uint8_t *buf, unsigned int len)
+{
+ int k;
+ unsigned long time_left = I2C_TIMEOUT;
+ unsigned int fifo_status;
+
+ /* Write data into FIFO */
+ for (k = 0; k < len; k++)
+ writel(buf[k], (dev->base + DAT_OFFSET));
+
+ /* Wait for FIFO to empty */
+ do {
+ time_left =
+ wait_for_int_timeout(dev, time_left,
+ (IER_FIFO_INT_EN_MASK |
+ IER_NOACK_EN_MASK));
+ fifo_status = readl(dev->base + FIFO_STATUS_OFFSET);
+ } while (time_left && !(fifo_status & FIFO_STATUS_TXFIFO_EMPTY_MASK));
+
+ /* Check if there was a NAK */
+ if (readl(dev->base + CS_OFFSET) & CS_ACK_MASK) {
+ printf("unexpected NAK\n");
+ return -EREMOTEIO;
+ }
+
+ /* Check if a timeout occurred */
+ if (!time_left) {
+ printf("completion timed out\n");
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+/* Write any amount of data using TX FIFO to the i2c bus */
+static int bcm_kona_i2c_write_fifo(struct bcm_kona_i2c_dev *dev,
+ struct kona_i2c_msg *msg)
+{
+ unsigned int bytes_to_write = MAX_TX_FIFO_SIZE;
+ unsigned int bytes_written = 0;
+ int rc;
+
+ uint8_t *tmp_buf = msg->buf;
+
+ while (bytes_written < msg->len) {
+ if (msg->len - bytes_written <= MAX_TX_FIFO_SIZE)
+ bytes_to_write = msg->len - bytes_written;
+
+ rc = bcm_kona_i2c_write_fifo_single(dev, tmp_buf,
+ bytes_to_write);
+ if (rc < 0)
+ return -EREMOTEIO;
+
+ bytes_written += bytes_to_write;
+ tmp_buf += bytes_to_write;
+ }
+
+ return 0;
+}
+
+/* Send i2c address */
+static int bcm_kona_i2c_do_addr(struct bcm_kona_i2c_dev *dev,
+ struct kona_i2c_msg *msg)
+{
+ unsigned char addr;
+
+ if (msg->flags & I2C_M_TEN) {
+ /* First byte is 11110XX0 where XX is upper 2 bits */
+ addr = 0xf0 | ((msg->addr & 0x300) >> 7);
+ if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0)
+ return -EREMOTEIO;
+
+ /* Second byte is the remaining 8 bits */
+ addr = msg->addr & 0xff;
+ if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0)
+ return -EREMOTEIO;
+
+ if (msg->flags & I2C_M_RD) {
+ /* For read, send restart command */
+ if (bcm_kona_send_i2c_cmd(dev, BCM_CMD_RESTART) < 0)
+ return -EREMOTEIO;
+
+ /* Then re-send the first byte with the read bit set */
+ addr = 0xf0 | ((msg->addr & 0x300) >> 7) | 0x01;
+ if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0)
+ return -EREMOTEIO;
+ }
+ } else {
+ addr = msg->addr << 1;
+
+ if (msg->flags & I2C_M_RD)
+ addr |= 1;
+
+ if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0)
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static void bcm_kona_i2c_enable_autosense(struct bcm_kona_i2c_dev *dev)
+{
+ writel(readl(dev->base + CLKEN_OFFSET) & ~CLKEN_AUTOSENSE_OFF_MASK,
+ dev->base + CLKEN_OFFSET);
+}
+
+static void bcm_kona_i2c_config_timing(struct bcm_kona_i2c_dev *dev)
+{
+ writel(readl(dev->base + HSTIM_OFFSET) & ~HSTIM_HS_MODE_MASK,
+ dev->base + HSTIM_OFFSET);
+
+ writel((dev->std_cfg->prescale << TIM_PRESCALE_SHIFT) |
+ (dev->std_cfg->time_p << TIM_P_SHIFT) |
+ (dev->std_cfg->no_div << TIM_NO_DIV_SHIFT) |
+ (dev->std_cfg->time_div << TIM_DIV_SHIFT),
+ dev->base + TIM_OFFSET);
+
+ writel((dev->std_cfg->time_m << CLKEN_M_SHIFT) |
+ (dev->std_cfg->time_n << CLKEN_N_SHIFT) |
+ CLKEN_CLKEN_MASK, dev->base + CLKEN_OFFSET);
+}
+
+/* Master transfer function */
+static int bcm_kona_i2c_xfer(struct bcm_kona_i2c_dev *dev,
+ struct kona_i2c_msg msgs[], int num)
+{
+ struct kona_i2c_msg *pmsg;
+ int rc = 0;
+ int i;
+
+ /* Enable pad output */
+ writel(0, dev->base + PADCTL_OFFSET);
+
+ /* Enable internal clocks */
+ bcm_kona_i2c_enable_clock(dev);
+
+ /* Send start command */
+ rc = bcm_kona_send_i2c_cmd(dev, BCM_CMD_START);
+ if (rc < 0) {
+ printf("Start command failed rc = %d\n", rc);
+ goto xfer_disable_pad;
+ }
+
+ /* Loop through all messages */
+ for (i = 0; i < num; i++) {
+ pmsg = &msgs[i];
+
+ /* Send restart for subsequent messages */
+ if ((i != 0) && ((pmsg->flags & I2C_M_NOSTART) == 0)) {
+ rc = bcm_kona_send_i2c_cmd(dev, BCM_CMD_RESTART);
+ if (rc < 0) {
+ printf("restart cmd failed rc = %d\n", rc);
+ goto xfer_send_stop;
+ }
+ }
+
+ /* Send slave address */
+ if (!(pmsg->flags & I2C_M_NOSTART)) {
+ rc = bcm_kona_i2c_do_addr(dev, pmsg);
+ if (rc < 0) {
+ debug("NAK from addr %2.2x msg#%d rc = %d\n",
+ pmsg->addr, i, rc);
+ goto xfer_send_stop;
+ }
+ }
+
+ /* Perform data transfer */
+ if (pmsg->flags & I2C_M_RD) {
+ rc = bcm_kona_i2c_read_fifo(dev, pmsg);
+ if (rc < 0) {
+ printf("read failure\n");
+ goto xfer_send_stop;
+ }
+ } else {
+ rc = bcm_kona_i2c_write_fifo(dev, pmsg);
+ if (rc < 0) {
+ printf("write failure");
+ goto xfer_send_stop;
+ }
+ }
+ }
+
+ rc = num;
+
+xfer_send_stop:
+ /* Send a STOP command */
+ bcm_kona_send_i2c_cmd(dev, BCM_CMD_STOP);
+
+xfer_disable_pad:
+ /* Disable pad output */
+ writel(PADCTL_PAD_OUT_EN_MASK, dev->base + PADCTL_OFFSET);
+
+ /* Stop internal clock */
+ bcm_kona_i2c_disable_clock(dev);
+
+ return rc;
+}
+
+static uint bcm_kona_i2c_assign_bus_speed(struct bcm_kona_i2c_dev *dev,
+ uint speed)
+{
+ switch (speed) {
+ case I2C_SPEED_STANDARD_RATE:
+ dev->std_cfg = &std_cfg_table[IC_SPEED_MODE_STANDARD];
+ break;
+ case I2C_SPEED_FAST_RATE:
+ dev->std_cfg = &std_cfg_table[IC_SPEED_MODE_FAST];
+ break;
+ case I2C_SPEED_FAST_PLUS_RATE:
+ dev->std_cfg = &std_cfg_table[IC_SPEED_MODE_FAST_PLUS];
+ break;
+ default:
+ printf("%d hz bus speed not supported\n", speed);
+ return -EINVAL;
+ }
+ dev->speed = speed;
+ return 0;
+}
+
+static void bcm_kona_i2c_init(struct bcm_kona_i2c_dev *dev)
+{
+ /* Parse bus speed */
+ bcm_kona_i2c_assign_bus_speed(dev, dev->speed);
+
+ /* Enable internal clocks */
+ bcm_kona_i2c_enable_clock(dev);
+
+ /* Configure internal dividers */
+ bcm_kona_i2c_config_timing(dev);
+
+ /* Disable timeout */
+ writel(0, dev->base + TOUT_OFFSET);
+
+ /* Enable autosense */
+ bcm_kona_i2c_enable_autosense(dev);
+
+ /* Enable TX FIFO */
+ writel(TXFCR_FIFO_FLUSH_MASK | TXFCR_FIFO_EN_MASK,
+ dev->base + TXFCR_OFFSET);
+
+ /* Mask all interrupts */
+ writel(0, dev->base + IER_OFFSET);
+
+ /* Clear all pending interrupts */
+ writel(ISR_CMDBUSY_MASK |
+ ISR_READ_COMPLETE_MASK |
+ ISR_SES_DONE_MASK |
+ ISR_ERR_MASK |
+ ISR_TXFIFOEMPTY_MASK | ISR_NOACK_MASK, dev->base + ISR_OFFSET);
+
+ /* Enable the controller but leave it idle */
+ bcm_kona_i2c_send_cmd_to_ctrl(dev, BCM_CMD_NOACTION);
+
+ /* Disable pad output */
+ writel(PADCTL_PAD_OUT_EN_MASK, dev->base + PADCTL_OFFSET);
+}
+
+/*
+ * uboot layer
+ */
+struct bcm_kona_i2c_dev *kona_get_dev(struct i2c_adapter *adap)
+{
+ return &g_i2c_devs[adap->hwadapnr];
+}
+
+static void kona_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
+{
+ struct bcm_kona_i2c_dev *dev = kona_get_dev(adap);
+
+ if (clk_bsc_enable(dev->base))
+ return;
+
+ bcm_kona_i2c_init(dev);
+}
+
+static int kona_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
+ int alen, uchar *buffer, int len)
+{
+ /* msg[0] writes the addr, msg[1] reads the data */
+ struct kona_i2c_msg msg[2];
+ unsigned char msgbuf0[64];
+ struct bcm_kona_i2c_dev *dev = kona_get_dev(adap);
+
+ msg[0].addr = chip;
+ msg[0].flags = 0;
+ msg[0].len = 1;
+ msg[0].buf = msgbuf0; /* msgbuf0 contains incrementing reg addr */
+
+ msg[1].addr = chip;
+ msg[1].flags = I2C_M_RD;
+ /* msg[1].buf dest ptr increments each read */
+
+ msgbuf0[0] = (unsigned char)addr;
+ msg[1].buf = buffer;
+ msg[1].len = len;
+ if (bcm_kona_i2c_xfer(dev, msg, 2) < 0) {
+ /* Sending 2 i2c messages */
+ kona_i2c_init(adap, adap->speed, adap->slaveaddr);
+ debug("I2C read: I/O error\n");
+ return -EIO;
+ }
+ return 0;
+}
+
+static int kona_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
+ int alen, uchar *buffer, int len)
+{
+ struct kona_i2c_msg msg[1];
+ unsigned char msgbuf0[64];
+ unsigned int i;
+ struct bcm_kona_i2c_dev *dev = kona_get_dev(adap);
+
+ msg[0].addr = chip;
+ msg[0].flags = 0;
+ msg[0].len = 2; /* addr byte plus data */
+ msg[0].buf = msgbuf0;
+
+ for (i = 0; i < len; i++) {
+ msgbuf0[0] = addr++;
+ msgbuf0[1] = buffer[i];
+ if (bcm_kona_i2c_xfer(dev, msg, 1) < 0) {
+ kona_i2c_init(adap, adap->speed, adap->slaveaddr);
+ debug("I2C write: I/O error\n");
+ return -EIO;
+ }
+ }
+ return 0;
+}
+
+static int kona_i2c_probe(struct i2c_adapter *adap, uchar chip)
+{
+ uchar tmp;
+
+ /*
+ * read addr 0x0 of the given chip.
+ */
+ return kona_i2c_read(adap, chip, 0x0, 1, &tmp, 1);
+}
+
+static uint kona_i2c_set_bus_speed(struct i2c_adapter *adap, uint speed)
+{
+ struct bcm_kona_i2c_dev *dev = kona_get_dev(adap);
+ return bcm_kona_i2c_assign_bus_speed(dev, speed);
+}
+
+/*
+ * Register kona i2c adapters. Keep the order below so
+ * that the bus number matches the adapter number.
+ */
+#define DEF_ADAPTER(num) \
+U_BOOT_I2C_ADAP_COMPLETE(kona##num, kona_i2c_init, kona_i2c_probe, \
+ kona_i2c_read, kona_i2c_write, \
+ kona_i2c_set_bus_speed, DEF_SPD, 0x00, num)
+
+#ifdef CONFIG_SYS_I2C_BASE0
+ DEF_ADAPTER(0)
+#endif
+#ifdef CONFIG_SYS_I2C_BASE1
+ DEF_ADAPTER(1)
+#endif
+#ifdef CONFIG_SYS_I2C_BASE2
+ DEF_ADAPTER(2)
+#endif
+#ifdef CONFIG_SYS_I2C_BASE3
+ DEF_ADAPTER(3)
+#endif
+#ifdef CONFIG_SYS_I2C_BASE4
+ DEF_ADAPTER(4)
+#endif
+#ifdef CONFIG_SYS_I2C_BASE5
+ DEF_ADAPTER(5)
+#endif
diff --git a/roms/u-boot/drivers/i2c/lpc32xx_i2c.c b/roms/u-boot/drivers/i2c/lpc32xx_i2c.c
new file mode 100644
index 000000000..f89f7955e
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/lpc32xx_i2c.c
@@ -0,0 +1,362 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * LPC32xx I2C interface driver
+ *
+ * (C) Copyright 2014-2015 DENX Software Engineering GmbH
+ * Written-by: Albert ARIBAUD - 3ADEV <albert.aribaud@3adev.fr>
+ */
+
+#include <common.h>
+#include <log.h>
+#include <asm/io.h>
+#include <i2c.h>
+#include <linux/errno.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/i2c.h>
+#include <dm.h>
+#include <mapmem.h>
+
+/*
+ * Provide default speed and slave if target did not
+ */
+
+#if !defined(CONFIG_SYS_I2C_LPC32XX_SPEED)
+#define CONFIG_SYS_I2C_LPC32XX_SPEED 350000
+#endif
+
+#if !defined(CONFIG_SYS_I2C_LPC32XX_SLAVE)
+#define CONFIG_SYS_I2C_LPC32XX_SLAVE 0
+#endif
+
+/* TX register fields */
+#define LPC32XX_I2C_TX_START 0x00000100
+#define LPC32XX_I2C_TX_STOP 0x00000200
+
+/* Control register values */
+#define LPC32XX_I2C_SOFT_RESET 0x00000100
+
+/* Status register values */
+#define LPC32XX_I2C_STAT_TFF 0x00000400
+#define LPC32XX_I2C_STAT_RFE 0x00000200
+#define LPC32XX_I2C_STAT_DRMI 0x00000008
+#define LPC32XX_I2C_STAT_NAI 0x00000004
+#define LPC32XX_I2C_STAT_TDI 0x00000001
+
+#if !CONFIG_IS_ENABLED(DM_I2C)
+static struct lpc32xx_i2c_base *lpc32xx_i2c[] = {
+ (struct lpc32xx_i2c_base *)I2C1_BASE,
+ (struct lpc32xx_i2c_base *)I2C2_BASE,
+ (struct lpc32xx_i2c_base *)(USB_BASE + 0x300)
+};
+#endif
+
+/* Set I2C bus speed */
+static unsigned int __i2c_set_bus_speed(struct lpc32xx_i2c_base *base,
+ unsigned int speed, unsigned int chip)
+{
+ int half_period;
+
+ if (speed == 0)
+ return -EINVAL;
+
+ /* OTG I2C clock source and CLK registers are different */
+ if (chip == 2) {
+ half_period = (get_periph_clk_rate() / speed) / 2;
+ if (half_period > 0xFF)
+ return -EINVAL;
+ } else {
+ half_period = (get_hclk_clk_rate() / speed) / 2;
+ if (half_period > 0x3FF)
+ return -EINVAL;
+ }
+
+ writel(half_period, &base->clk_hi);
+ writel(half_period, &base->clk_lo);
+ return 0;
+}
+
+/* I2C init called by cmd_i2c when doing 'i2c reset'. */
+static void __i2c_init(struct lpc32xx_i2c_base *base,
+ int requested_speed, int slaveadd, unsigned int chip)
+{
+ /* soft reset (auto-clears) */
+ writel(LPC32XX_I2C_SOFT_RESET, &base->ctrl);
+ /* set HI and LO periods for half of the default speed */
+ __i2c_set_bus_speed(base, requested_speed, chip);
+}
+
+/* I2C probe called by cmd_i2c when doing 'i2c probe'. */
+static int __i2c_probe_chip(struct lpc32xx_i2c_base *base, u8 dev)
+{
+ int stat;
+
+ /* Soft-reset the controller */
+ writel(LPC32XX_I2C_SOFT_RESET, &base->ctrl);
+ while (readl(&base->ctrl) & LPC32XX_I2C_SOFT_RESET)
+ ;
+ /* Addre slave for write with start before and stop after */
+ writel((dev<<1) | LPC32XX_I2C_TX_START | LPC32XX_I2C_TX_STOP,
+ &base->tx);
+ /* wait for end of transation */
+ while (!((stat = readl(&base->stat)) & LPC32XX_I2C_STAT_TDI))
+ ;
+ /* was there no acknowledge? */
+ return (stat & LPC32XX_I2C_STAT_NAI) ? -1 : 0;
+}
+
+/*
+ * I2C read called by cmd_i2c when doing 'i2c read' and by cmd_eeprom.c
+ * Begin write, send address byte(s), begin read, receive data bytes, end.
+ */
+static int __i2c_read(struct lpc32xx_i2c_base *base, u8 dev, uint addr,
+ int alen, u8 *data, int length)
+{
+ int stat, wlen;
+
+ /* Soft-reset the controller */
+ writel(LPC32XX_I2C_SOFT_RESET, &base->ctrl);
+ while (readl(&base->ctrl) & LPC32XX_I2C_SOFT_RESET)
+ ;
+ /* do we need to write an address at all? */
+ if (alen) {
+ /* Address slave in write mode */
+ writel((dev<<1) | LPC32XX_I2C_TX_START, &base->tx);
+ /* write address bytes */
+ while (alen--) {
+ /* compute address byte + stop for the last one */
+ int a = (addr >> (8 * alen)) & 0xff;
+ if (!alen)
+ a |= LPC32XX_I2C_TX_STOP;
+ /* Send address byte */
+ writel(a, &base->tx);
+ }
+ /* wait for end of transation */
+ while (!((stat = readl(&base->stat)) & LPC32XX_I2C_STAT_TDI))
+ ;
+ /* clear end-of-transaction flag */
+ writel(1, &base->stat);
+ }
+ /* do we have to read data at all? */
+ if (length) {
+ /* Address slave in read mode */
+ writel(1 | (dev<<1) | LPC32XX_I2C_TX_START, &base->tx);
+ wlen = length;
+ /* get data */
+ while (length | wlen) {
+ /* read status for TFF and RFE */
+ stat = readl(&base->stat);
+ /* must we, can we write a trigger byte? */
+ if ((wlen > 0)
+ & (!(stat & LPC32XX_I2C_STAT_TFF))) {
+ wlen--;
+ /* write trigger byte + stop if last */
+ writel(wlen ? 0 :
+ LPC32XX_I2C_TX_STOP, &base->tx);
+ }
+ /* must we, can we read a data byte? */
+ if ((length > 0)
+ & (!(stat & LPC32XX_I2C_STAT_RFE))) {
+ length--;
+ /* read byte */
+ *(data++) = readl(&base->rx);
+ }
+ }
+ /* wait for end of transation */
+ while (!((stat = readl(&base->stat)) & LPC32XX_I2C_STAT_TDI))
+ ;
+ /* clear end-of-transaction flag */
+ writel(1, &base->stat);
+ }
+ /* success */
+ return 0;
+}
+
+/*
+ * I2C write called by cmd_i2c when doing 'i2c write' and by cmd_eeprom.c
+ * Begin write, send address byte(s), send data bytes, end.
+ */
+static int __i2c_write(struct lpc32xx_i2c_base *base, u8 dev, uint addr,
+ int alen, u8 *data, int length)
+{
+ int stat;
+
+ /* Soft-reset the controller */
+ writel(LPC32XX_I2C_SOFT_RESET, &base->ctrl);
+ while (readl(&base->ctrl) & LPC32XX_I2C_SOFT_RESET)
+ ;
+ /* do we need to write anything at all? */
+ if (alen | length)
+ /* Address slave in write mode */
+ writel((dev<<1) | LPC32XX_I2C_TX_START, &base->tx);
+ else
+ return 0;
+ /* write address bytes */
+ while (alen) {
+ /* wait for transmit fifo not full */
+ stat = readl(&base->stat);
+ if (!(stat & LPC32XX_I2C_STAT_TFF)) {
+ alen--;
+ int a = (addr >> (8 * alen)) & 0xff;
+ if (!(alen | length))
+ a |= LPC32XX_I2C_TX_STOP;
+ /* Send address byte */
+ writel(a, &base->tx);
+ }
+ }
+ while (length) {
+ /* wait for transmit fifo not full */
+ stat = readl(&base->stat);
+ if (!(stat & LPC32XX_I2C_STAT_TFF)) {
+ /* compute data byte, add stop if length==0 */
+ length--;
+ int d = *(data++);
+ if (!length)
+ d |= LPC32XX_I2C_TX_STOP;
+ /* Send data byte */
+ writel(d, &base->tx);
+ }
+ }
+ /* wait for end of transation */
+ while (!((stat = readl(&base->stat)) & LPC32XX_I2C_STAT_TDI))
+ ;
+ /* clear end-of-transaction flag */
+ writel(1, &base->stat);
+ return 0;
+}
+
+#if !CONFIG_IS_ENABLED(DM_I2C)
+static void lpc32xx_i2c_init(struct i2c_adapter *adap,
+ int requested_speed, int slaveadd)
+{
+ __i2c_init(lpc32xx_i2c[adap->hwadapnr], requested_speed, slaveadd,
+ adap->hwadapnr);
+}
+
+static int lpc32xx_i2c_probe_chip(struct i2c_adapter *adap, u8 dev)
+{
+ return __i2c_probe_chip(lpc32xx_i2c[adap->hwadapnr], dev);
+}
+
+static int lpc32xx_i2c_read(struct i2c_adapter *adap, u8 dev, uint addr,
+ int alen, u8 *data, int length)
+{
+ return __i2c_read(lpc32xx_i2c[adap->hwadapnr], dev, addr,
+ alen, data, length);
+}
+
+static int lpc32xx_i2c_write(struct i2c_adapter *adap, u8 dev, uint addr,
+ int alen, u8 *data, int length)
+{
+ return __i2c_write(lpc32xx_i2c[adap->hwadapnr], dev, addr,
+ alen, data, length);
+}
+
+static unsigned int lpc32xx_i2c_set_bus_speed(struct i2c_adapter *adap,
+ unsigned int speed)
+{
+ return __i2c_set_bus_speed(lpc32xx_i2c[adap->hwadapnr], speed,
+ adap->hwadapnr);
+}
+
+U_BOOT_I2C_ADAP_COMPLETE(lpc32xx_0, lpc32xx_i2c_init, lpc32xx_i2c_probe_chip,
+ lpc32xx_i2c_read, lpc32xx_i2c_write,
+ lpc32xx_i2c_set_bus_speed,
+ CONFIG_SYS_I2C_LPC32XX_SPEED,
+ CONFIG_SYS_I2C_LPC32XX_SLAVE,
+ 0)
+
+U_BOOT_I2C_ADAP_COMPLETE(lpc32xx_1, lpc32xx_i2c_init, lpc32xx_i2c_probe_chip,
+ lpc32xx_i2c_read, lpc32xx_i2c_write,
+ lpc32xx_i2c_set_bus_speed,
+ CONFIG_SYS_I2C_LPC32XX_SPEED,
+ CONFIG_SYS_I2C_LPC32XX_SLAVE,
+ 1)
+
+U_BOOT_I2C_ADAP_COMPLETE(lpc32xx_2, lpc32xx_i2c_init, NULL,
+ lpc32xx_i2c_read, lpc32xx_i2c_write,
+ lpc32xx_i2c_set_bus_speed,
+ 100000,
+ 0,
+ 2)
+#else /* CONFIG_DM_I2C */
+static int lpc32xx_i2c_probe(struct udevice *bus)
+{
+ struct lpc32xx_i2c_dev *dev = dev_get_plat(bus);
+
+ /*
+ * FIXME: This is not permitted
+ * dev_seq(bus) = dev->index;
+ */
+
+ __i2c_init(dev->base, dev->speed, 0, dev->index);
+ return 0;
+}
+
+static int lpc32xx_i2c_probe_chip(struct udevice *bus, u32 chip_addr,
+ u32 chip_flags)
+{
+ struct lpc32xx_i2c_dev *dev = dev_get_plat(bus);
+ return __i2c_probe_chip(dev->base, chip_addr);
+}
+
+static int lpc32xx_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
+ int nmsgs)
+{
+ struct lpc32xx_i2c_dev *dev = dev_get_plat(bus);
+ struct i2c_msg *dmsg, *omsg, dummy;
+ uint i = 0, address = 0;
+
+ memset(&dummy, 0, sizeof(struct i2c_msg));
+
+ /* We expect either two messages (one with an offset and one with the
+ * actual data) or one message (just data)
+ */
+ if (nmsgs > 2 || nmsgs == 0) {
+ debug("%s: Only one or two messages are supported.", __func__);
+ return -1;
+ }
+
+ omsg = nmsgs == 1 ? &dummy : msg;
+ dmsg = nmsgs == 1 ? msg : msg + 1;
+
+ /* the address is expected to be a uint, not a array. */
+ address = omsg->buf[0];
+ for (i = 1; i < omsg->len; i++)
+ address = (address << 8) + omsg->buf[i];
+
+ if (dmsg->flags & I2C_M_RD)
+ return __i2c_read(dev->base, dmsg->addr, address,
+ omsg->len, dmsg->buf, dmsg->len);
+ else
+ return __i2c_write(dev->base, dmsg->addr, address,
+ omsg->len, dmsg->buf, dmsg->len);
+}
+
+static int lpc32xx_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
+{
+ struct lpc32xx_i2c_dev *dev = dev_get_plat(bus);
+ return __i2c_set_bus_speed(dev->base, speed, dev->index);
+}
+
+static int lpc32xx_i2c_reset(struct udevice *bus)
+{
+ struct lpc32xx_i2c_dev *dev = dev_get_plat(bus);
+
+ __i2c_init(dev->base, dev->speed, 0, dev->index);
+ return 0;
+}
+
+static const struct dm_i2c_ops lpc32xx_i2c_ops = {
+ .xfer = lpc32xx_i2c_xfer,
+ .probe_chip = lpc32xx_i2c_probe_chip,
+ .deblock = lpc32xx_i2c_reset,
+ .set_bus_speed = lpc32xx_i2c_set_bus_speed,
+};
+
+U_BOOT_DRIVER(i2c_lpc32xx) = {
+ .id = UCLASS_I2C,
+ .name = "i2c_lpc32xx",
+ .probe = lpc32xx_i2c_probe,
+ .ops = &lpc32xx_i2c_ops,
+};
+#endif /* CONFIG_DM_I2C */
diff --git a/roms/u-boot/drivers/i2c/meson_i2c.c b/roms/u-boot/drivers/i2c/meson_i2c.c
new file mode 100644
index 000000000..434e3461b
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/meson_i2c.c
@@ -0,0 +1,313 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2017 - Beniamino Galvani <b.galvani@gmail.com>
+ */
+#include <common.h>
+#include <log.h>
+#include <asm/io.h>
+#include <clk.h>
+#include <dm.h>
+#include <i2c.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+
+#define I2C_TIMEOUT_MS 100
+
+/* Control register fields */
+#define REG_CTRL_START BIT(0)
+#define REG_CTRL_ACK_IGNORE BIT(1)
+#define REG_CTRL_STATUS BIT(2)
+#define REG_CTRL_ERROR BIT(3)
+#define REG_CTRL_CLKDIV_SHIFT 12
+#define REG_CTRL_CLKDIV_MASK GENMASK(21, 12)
+#define REG_CTRL_CLKDIVEXT_SHIFT 28
+#define REG_CTRL_CLKDIVEXT_MASK GENMASK(29, 28)
+
+enum {
+ TOKEN_END = 0,
+ TOKEN_START,
+ TOKEN_SLAVE_ADDR_WRITE,
+ TOKEN_SLAVE_ADDR_READ,
+ TOKEN_DATA,
+ TOKEN_DATA_LAST,
+ TOKEN_STOP,
+};
+
+struct i2c_regs {
+ u32 ctrl;
+ u32 slave_addr;
+ u32 tok_list0;
+ u32 tok_list1;
+ u32 tok_wdata0;
+ u32 tok_wdata1;
+ u32 tok_rdata0;
+ u32 tok_rdata1;
+};
+
+struct meson_i2c_data {
+ unsigned char div_factor;
+};
+
+struct meson_i2c {
+ const struct meson_i2c_data *data;
+ struct clk clk;
+ struct i2c_regs *regs;
+ struct i2c_msg *msg; /* Current I2C message */
+ bool last; /* Whether the message is the last */
+ uint count; /* Number of bytes in the current transfer */
+ uint pos; /* Position of current transfer in message */
+ u32 tokens[2]; /* Sequence of tokens to be written */
+ uint num_tokens; /* Number of tokens to be written */
+};
+
+static void meson_i2c_reset_tokens(struct meson_i2c *i2c)
+{
+ i2c->tokens[0] = 0;
+ i2c->tokens[1] = 0;
+ i2c->num_tokens = 0;
+}
+
+static void meson_i2c_add_token(struct meson_i2c *i2c, int token)
+{
+ if (i2c->num_tokens < 8)
+ i2c->tokens[0] |= (token & 0xf) << (i2c->num_tokens * 4);
+ else
+ i2c->tokens[1] |= (token & 0xf) << ((i2c->num_tokens % 8) * 4);
+
+ i2c->num_tokens++;
+}
+
+/*
+ * Retrieve data for the current transfer (which can be at most 8
+ * bytes) from the device internal buffer.
+ */
+static void meson_i2c_get_data(struct meson_i2c *i2c, u8 *buf, int len)
+{
+ u32 rdata0, rdata1;
+ int i;
+
+ rdata0 = readl(&i2c->regs->tok_rdata0);
+ rdata1 = readl(&i2c->regs->tok_rdata1);
+
+ debug("meson i2c: read data %08x %08x len %d\n", rdata0, rdata1, len);
+
+ for (i = 0; i < min(4, len); i++)
+ *buf++ = (rdata0 >> i * 8) & 0xff;
+
+ for (i = 4; i < min(8, len); i++)
+ *buf++ = (rdata1 >> (i - 4) * 8) & 0xff;
+}
+
+/*
+ * Write data for the current transfer (which can be at most 8 bytes)
+ * to the device internal buffer.
+ */
+static void meson_i2c_put_data(struct meson_i2c *i2c, u8 *buf, int len)
+{
+ u32 wdata0 = 0, wdata1 = 0;
+ int i;
+
+ for (i = 0; i < min(4, len); i++)
+ wdata0 |= *buf++ << (i * 8);
+
+ for (i = 4; i < min(8, len); i++)
+ wdata1 |= *buf++ << ((i - 4) * 8);
+
+ writel(wdata0, &i2c->regs->tok_wdata0);
+ writel(wdata1, &i2c->regs->tok_wdata1);
+
+ debug("meson i2c: write data %08x %08x len %d\n", wdata0, wdata1, len);
+}
+
+/*
+ * Prepare the next transfer: pick the next 8 bytes in the remaining
+ * part of message and write tokens and data (if needed) to the
+ * device.
+ */
+static void meson_i2c_prepare_xfer(struct meson_i2c *i2c)
+{
+ bool write = !(i2c->msg->flags & I2C_M_RD);
+ int i;
+
+ i2c->count = min(i2c->msg->len - i2c->pos, 8u);
+
+ for (i = 0; i + 1 < i2c->count; i++)
+ meson_i2c_add_token(i2c, TOKEN_DATA);
+
+ if (i2c->count) {
+ if (write || i2c->pos + i2c->count < i2c->msg->len)
+ meson_i2c_add_token(i2c, TOKEN_DATA);
+ else
+ meson_i2c_add_token(i2c, TOKEN_DATA_LAST);
+ }
+
+ if (write)
+ meson_i2c_put_data(i2c, i2c->msg->buf + i2c->pos, i2c->count);
+
+ if (i2c->last && i2c->pos + i2c->count >= i2c->msg->len)
+ meson_i2c_add_token(i2c, TOKEN_STOP);
+
+ writel(i2c->tokens[0], &i2c->regs->tok_list0);
+ writel(i2c->tokens[1], &i2c->regs->tok_list1);
+}
+
+static void meson_i2c_do_start(struct meson_i2c *i2c, struct i2c_msg *msg)
+{
+ int token;
+
+ token = (msg->flags & I2C_M_RD) ? TOKEN_SLAVE_ADDR_READ :
+ TOKEN_SLAVE_ADDR_WRITE;
+
+ writel(msg->addr << 1, &i2c->regs->slave_addr);
+ meson_i2c_add_token(i2c, TOKEN_START);
+ meson_i2c_add_token(i2c, token);
+}
+
+static int meson_i2c_xfer_msg(struct meson_i2c *i2c, struct i2c_msg *msg,
+ int last)
+{
+ ulong start;
+
+ debug("meson i2c: %s addr %u len %u\n",
+ (msg->flags & I2C_M_RD) ? "read" : "write",
+ msg->addr, msg->len);
+
+ i2c->msg = msg;
+ i2c->last = last;
+ i2c->pos = 0;
+ i2c->count = 0;
+
+ meson_i2c_reset_tokens(i2c);
+ meson_i2c_do_start(i2c, msg);
+
+ do {
+ meson_i2c_prepare_xfer(i2c);
+
+ /* start the transfer */
+ setbits_le32(&i2c->regs->ctrl, REG_CTRL_START);
+ start = get_timer(0);
+ while (readl(&i2c->regs->ctrl) & REG_CTRL_STATUS) {
+ if (get_timer(start) > I2C_TIMEOUT_MS) {
+ clrbits_le32(&i2c->regs->ctrl, REG_CTRL_START);
+ debug("meson i2c: timeout\n");
+ return -ETIMEDOUT;
+ }
+ udelay(1);
+ }
+ meson_i2c_reset_tokens(i2c);
+ clrbits_le32(&i2c->regs->ctrl, REG_CTRL_START);
+
+ if (readl(&i2c->regs->ctrl) & REG_CTRL_ERROR) {
+ debug("meson i2c: error\n");
+ return -EREMOTEIO;
+ }
+
+ if ((msg->flags & I2C_M_RD) && i2c->count) {
+ meson_i2c_get_data(i2c, i2c->msg->buf + i2c->pos,
+ i2c->count);
+ }
+ i2c->pos += i2c->count;
+ } while (i2c->pos < msg->len);
+
+ return 0;
+}
+
+static int meson_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
+ int nmsgs)
+{
+ struct meson_i2c *i2c = dev_get_priv(bus);
+ int i, ret = 0;
+
+ for (i = 0; i < nmsgs; i++) {
+ ret = meson_i2c_xfer_msg(i2c, msg + i, i == nmsgs - 1);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int meson_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
+{
+ struct meson_i2c *i2c = dev_get_priv(bus);
+ ulong clk_rate;
+ unsigned int div;
+
+ clk_rate = clk_get_rate(&i2c->clk);
+ if (IS_ERR_VALUE(clk_rate))
+ return -EINVAL;
+
+ div = DIV_ROUND_UP(clk_rate, speed * i2c->data->div_factor);
+
+ /* clock divider has 12 bits */
+ if (div >= (1 << 12)) {
+ debug("meson i2c: requested bus frequency too low\n");
+ div = (1 << 12) - 1;
+ }
+
+ clrsetbits_le32(&i2c->regs->ctrl, REG_CTRL_CLKDIV_MASK,
+ (div & GENMASK(9, 0)) << REG_CTRL_CLKDIV_SHIFT);
+
+ clrsetbits_le32(&i2c->regs->ctrl, REG_CTRL_CLKDIVEXT_MASK,
+ (div >> 10) << REG_CTRL_CLKDIVEXT_SHIFT);
+
+ debug("meson i2c: set clk %u, src %lu, div %u\n", speed, clk_rate, div);
+
+ return 0;
+}
+
+static int meson_i2c_probe(struct udevice *bus)
+{
+ struct meson_i2c *i2c = dev_get_priv(bus);
+ int ret;
+
+ i2c->data = (const struct meson_i2c_data *)dev_get_driver_data(bus);
+
+ ret = clk_get_by_index(bus, 0, &i2c->clk);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_enable(&i2c->clk);
+ if (ret)
+ return ret;
+
+ i2c->regs = dev_read_addr_ptr(bus);
+ clrbits_le32(&i2c->regs->ctrl, REG_CTRL_START);
+
+ return 0;
+}
+
+static const struct dm_i2c_ops meson_i2c_ops = {
+ .xfer = meson_i2c_xfer,
+ .set_bus_speed = meson_i2c_set_bus_speed,
+};
+
+static const struct meson_i2c_data i2c_meson6_data = {
+ .div_factor = 4,
+};
+
+static const struct meson_i2c_data i2c_gxbb_data = {
+ .div_factor = 4,
+};
+
+static const struct meson_i2c_data i2c_axg_data = {
+ .div_factor = 3,
+};
+
+static const struct udevice_id meson_i2c_ids[] = {
+ {.compatible = "amlogic,meson6-i2c", .data = (ulong)&i2c_meson6_data},
+ {.compatible = "amlogic,meson-gx-i2c", .data = (ulong)&i2c_gxbb_data},
+ {.compatible = "amlogic,meson-gxbb-i2c", .data = (ulong)&i2c_gxbb_data},
+ {.compatible = "amlogic,meson-axg-i2c", .data = (ulong)&i2c_axg_data},
+ {}
+};
+
+U_BOOT_DRIVER(i2c_meson) = {
+ .name = "i2c_meson",
+ .id = UCLASS_I2C,
+ .of_match = meson_i2c_ids,
+ .probe = meson_i2c_probe,
+ .priv_auto = sizeof(struct meson_i2c),
+ .ops = &meson_i2c_ops,
+};
diff --git a/roms/u-boot/drivers/i2c/muxes/Kconfig b/roms/u-boot/drivers/i2c/muxes/Kconfig
new file mode 100644
index 000000000..39683fc43
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/muxes/Kconfig
@@ -0,0 +1,46 @@
+config I2C_MUX
+ bool "Support I2C multiplexers"
+ depends on DM_I2C
+ help
+ This enables I2C buses to be multiplexed, so that you can select
+ one of several buses using some sort of control mechanism. The
+ bus select is handled automatically when that bus is accessed,
+ using a suitable I2C MUX driver.
+
+config SPL_I2C_MUX
+ bool "Support I2C multiplexers on SPL"
+ depends on I2C_MUX
+ help
+ This enables I2C buses to be multiplexed, so that you can select
+ one of several buses using some sort of control mechanism. The
+ bus select is handled automatically when that bus is accessed,
+ using a suitable I2C MUX driver.
+
+config I2C_ARB_GPIO_CHALLENGE
+ bool "GPIO-based I2C arbitration"
+ depends on I2C_MUX
+ help
+ If you say yes to this option, support will be included for an
+ I2C multimaster arbitration scheme using GPIOs and a challenge &
+ response mechanism where masters have to claim the bus by asserting
+ a GPIO.
+
+config I2C_MUX_PCA954x
+ tristate "TI PCA954x I2C Mux/switches"
+ depends on I2C_MUX
+ help
+ If you say yes here you get support for the TI PCA954x I2C mux/switch
+ devices. It is x width I2C multiplexer which enables to partitioning
+ I2C bus and connect multiple devices with the same address to the same
+ I2C controller where driver handles proper routing to target i2c
+ device. Supported chips are PCA9543, PCA9544, PCA9546, PCA9547,
+ PCA9548 and PCA9646.
+
+config I2C_MUX_GPIO
+ tristate "GPIO-based I2C multiplexer"
+ depends on I2C_MUX && DM_GPIO
+ help
+ If you say yes to this option, support will be included for
+ a GPIO based I2C multiplexer. This driver provides access to
+ I2C busses connected through a MUX, which is controlled
+ through GPIO pins.
diff --git a/roms/u-boot/drivers/i2c/muxes/Makefile b/roms/u-boot/drivers/i2c/muxes/Makefile
new file mode 100644
index 000000000..b69082119
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/muxes/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (c) 2015 Google, Inc
+obj-$(CONFIG_I2C_ARB_GPIO_CHALLENGE) += i2c-arb-gpio-challenge.o
+obj-$(CONFIG_I2C_MUX) += i2c-mux-uclass.o
+obj-$(CONFIG_I2C_MUX_PCA954x) += pca954x.o
+obj-$(CONFIG_I2C_MUX_GPIO) += i2c-mux-gpio.o
diff --git a/roms/u-boot/drivers/i2c/muxes/i2c-arb-gpio-challenge.c b/roms/u-boot/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
new file mode 100644
index 000000000..ad730e0e7
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
@@ -0,0 +1,150 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <i2c.h>
+#include <log.h>
+#include <malloc.h>
+#include <asm/global_data.h>
+#include <asm/gpio.h>
+#include <linux/delay.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct i2c_arbitrator_priv {
+ struct gpio_desc ap_claim;
+ struct gpio_desc ec_claim;
+ uint slew_delay_us;
+ uint wait_retry_ms;
+ uint wait_free_ms;
+};
+
+int i2c_arbitrator_deselect(struct udevice *mux, struct udevice *bus,
+ uint channel)
+{
+ struct i2c_arbitrator_priv *priv = dev_get_priv(mux);
+ int ret;
+
+ debug("%s: %s\n", __func__, mux->name);
+ ret = dm_gpio_set_value(&priv->ap_claim, 0);
+ udelay(priv->slew_delay_us);
+
+ return ret;
+}
+
+int i2c_arbitrator_select(struct udevice *mux, struct udevice *bus,
+ uint channel)
+{
+ struct i2c_arbitrator_priv *priv = dev_get_priv(mux);
+ unsigned start;
+ int ret;
+
+ debug("%s: %s\n", __func__, mux->name);
+ /* Start a round of trying to claim the bus */
+ start = get_timer(0);
+ do {
+ unsigned start_retry;
+ int waiting = 0;
+
+ /* Indicate that we want to claim the bus */
+ ret = dm_gpio_set_value(&priv->ap_claim, 1);
+ if (ret)
+ goto err;
+ udelay(priv->slew_delay_us);
+
+ /* Wait for the EC to release it */
+ start_retry = get_timer(0);
+ while (get_timer(start_retry) < priv->wait_retry_ms) {
+ ret = dm_gpio_get_value(&priv->ec_claim);
+ if (ret < 0) {
+ goto err;
+ } else if (!ret) {
+ /* We got it, so return */
+ return 0;
+ }
+
+ if (!waiting)
+ waiting = 1;
+ }
+
+ /* It didn't release, so give up, wait, and try again */
+ ret = dm_gpio_set_value(&priv->ap_claim, 0);
+ if (ret)
+ goto err;
+
+ mdelay(priv->wait_retry_ms);
+ } while (get_timer(start) < priv->wait_free_ms);
+
+ /* Give up, release our claim */
+ printf("I2C: Could not claim bus, timeout %lu\n", get_timer(start));
+ ret = -ETIMEDOUT;
+ ret = 0;
+err:
+ return ret;
+}
+
+static int i2c_arbitrator_probe(struct udevice *dev)
+{
+ struct i2c_arbitrator_priv *priv = dev_get_priv(dev);
+ const void *blob = gd->fdt_blob;
+ int node = dev_of_offset(dev);
+ int ret;
+
+ debug("%s: %s\n", __func__, dev->name);
+ priv->slew_delay_us = fdtdec_get_int(blob, node, "slew-delay-us", 0);
+ priv->wait_retry_ms = fdtdec_get_int(blob, node, "wait-retry-us", 0) /
+ 1000;
+ priv->wait_free_ms = fdtdec_get_int(blob, node, "wait-free-us", 0) /
+ 1000;
+ ret = gpio_request_by_name(dev, "our-claim-gpio", 0, &priv->ap_claim,
+ GPIOD_IS_OUT);
+ if (ret)
+ goto err;
+ ret = gpio_request_by_name(dev, "their-claim-gpios", 0, &priv->ec_claim,
+ GPIOD_IS_IN);
+ if (ret)
+ goto err_ec_gpio;
+
+ return 0;
+
+err_ec_gpio:
+ dm_gpio_free(dev, &priv->ap_claim);
+err:
+ debug("%s: ret=%d\n", __func__, ret);
+ return ret;
+}
+
+static int i2c_arbitrator_remove(struct udevice *dev)
+{
+ struct i2c_arbitrator_priv *priv = dev_get_priv(dev);
+
+ dm_gpio_free(dev, &priv->ap_claim);
+ dm_gpio_free(dev, &priv->ec_claim);
+
+ return 0;
+}
+
+static const struct i2c_mux_ops i2c_arbitrator_ops = {
+ .select = i2c_arbitrator_select,
+ .deselect = i2c_arbitrator_deselect,
+};
+
+static const struct udevice_id i2c_arbitrator_ids[] = {
+ { .compatible = "i2c-arb-gpio-challenge" },
+ { }
+};
+
+U_BOOT_DRIVER(i2c_arbitrator) = {
+ .name = "i2c_arbitrator",
+ .id = UCLASS_I2C_MUX,
+ .of_match = i2c_arbitrator_ids,
+ .probe = i2c_arbitrator_probe,
+ .remove = i2c_arbitrator_remove,
+ .ops = &i2c_arbitrator_ops,
+ .priv_auto = sizeof(struct i2c_arbitrator_priv),
+};
diff --git a/roms/u-boot/drivers/i2c/muxes/i2c-mux-gpio.c b/roms/u-boot/drivers/i2c/muxes/i2c-mux-gpio.c
new file mode 100644
index 000000000..4ca206115
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/muxes/i2c-mux-gpio.c
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * I2C multiplexer using GPIO API
+ *
+ * Copyright 2017 NXP
+ *
+ * Peng Fan <peng.fan@nxp.com>
+ */
+
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <asm-generic/gpio.h>
+#include <common.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+#include <dm/pinctrl.h>
+#include <fdtdec.h>
+#include <i2c.h>
+#include <linux/errno.h>
+#include <linux/libfdt.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/**
+ * struct i2c_mux_gpio_priv - private data for i2c mux gpio
+ *
+ * @values: the reg value of each child node
+ * @n_values: num of regs
+ * @gpios: the mux-gpios array
+ * @n_gpios: num of gpios in mux-gpios
+ * @idle: the value of idle-state
+ */
+struct i2c_mux_gpio_priv {
+ u32 *values;
+ int n_values;
+ struct gpio_desc *gpios;
+ int n_gpios;
+ u32 idle;
+};
+
+
+static int i2c_mux_gpio_select(struct udevice *dev, struct udevice *bus,
+ uint channel)
+{
+ struct i2c_mux_gpio_priv *priv = dev_get_priv(dev);
+ int i, ret;
+
+ for (i = 0; i < priv->n_gpios; i++) {
+ ret = dm_gpio_set_value(&priv->gpios[i], (channel >> i) & 1);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int i2c_mux_gpio_deselect(struct udevice *dev, struct udevice *bus,
+ uint channel)
+{
+ struct i2c_mux_gpio_priv *priv = dev_get_priv(dev);
+ int i, ret;
+
+ for (i = 0; i < priv->n_gpios; i++) {
+ ret = dm_gpio_set_value(&priv->gpios[i], (priv->idle >> i) & 1);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int i2c_mux_gpio_probe(struct udevice *dev)
+{
+ const void *fdt = gd->fdt_blob;
+ int node = dev_of_offset(dev);
+ struct i2c_mux_gpio_priv *mux = dev_get_priv(dev);
+ struct gpio_desc *gpios;
+ u32 *values;
+ int i = 0, subnode, ret;
+
+ mux->n_values = fdtdec_get_child_count(fdt, node);
+ values = devm_kzalloc(dev, sizeof(*mux->values) * mux->n_values,
+ GFP_KERNEL);
+ if (!values) {
+ dev_err(dev, "Cannot alloc values array");
+ return -ENOMEM;
+ }
+
+ fdt_for_each_subnode(subnode, fdt, node) {
+ *(values + i) = fdtdec_get_uint(fdt, subnode, "reg", -1);
+ i++;
+ }
+
+ mux->values = values;
+
+ mux->idle = fdtdec_get_uint(fdt, node, "idle-state", -1);
+
+ mux->n_gpios = gpio_get_list_count(dev, "mux-gpios");
+ if (mux->n_gpios < 0) {
+ dev_err(dev, "Missing mux-gpios property\n");
+ return -EINVAL;
+ }
+
+ gpios = devm_kzalloc(dev, sizeof(struct gpio_desc) * mux->n_gpios,
+ GFP_KERNEL);
+ if (!gpios) {
+ dev_err(dev, "Cannot allocate gpios array\n");
+ return -ENOMEM;
+ }
+
+ ret = gpio_request_list_by_name(dev, "mux-gpios", gpios, mux->n_gpios,
+ GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+ if (ret <= 0) {
+ dev_err(dev, "Failed to request mux-gpios\n");
+ return ret;
+ }
+
+ mux->gpios = gpios;
+
+ return 0;
+}
+
+static const struct i2c_mux_ops i2c_mux_gpio_ops = {
+ .select = i2c_mux_gpio_select,
+ .deselect = i2c_mux_gpio_deselect,
+};
+
+static const struct udevice_id i2c_mux_gpio_ids[] = {
+ { .compatible = "i2c-mux-gpio", },
+ {}
+};
+
+U_BOOT_DRIVER(i2c_mux_gpio) = {
+ .name = "i2c_mux_gpio",
+ .id = UCLASS_I2C_MUX,
+ .of_match = i2c_mux_gpio_ids,
+ .ops = &i2c_mux_gpio_ops,
+ .probe = i2c_mux_gpio_probe,
+ .priv_auto = sizeof(struct i2c_mux_gpio_priv),
+};
diff --git a/roms/u-boot/drivers/i2c/muxes/i2c-mux-uclass.c b/roms/u-boot/drivers/i2c/muxes/i2c-mux-uclass.c
new file mode 100644
index 000000000..dbca409ee
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/muxes/i2c-mux-uclass.c
@@ -0,0 +1,226 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <i2c.h>
+#include <log.h>
+#include <malloc.h>
+#include <dm/lists.h>
+#include <dm/root.h>
+
+/**
+ * struct i2c_mux: Information the uclass stores about an I2C mux
+ *
+ * @selected: Currently selected mux, or -1 for none
+ * @i2c_bus: I2C bus to use for communcation
+ */
+struct i2c_mux {
+ int selected;
+ struct udevice *i2c_bus;
+};
+
+/**
+ * struct i2c_mux_bus: Information about each bus the mux controls
+ *
+ * @channel: Channel number used to select this bus
+ */
+struct i2c_mux_bus {
+ uint channel;
+};
+
+/* Find out the mux channel number */
+static int i2c_mux_child_post_bind(struct udevice *dev)
+{
+ struct i2c_mux_bus *plat = dev_get_parent_plat(dev);
+ int channel;
+
+ channel = dev_read_u32_default(dev, "reg", -1);
+ if (channel < 0)
+ return -EINVAL;
+ plat->channel = channel;
+
+ return 0;
+}
+
+/* Find the I2C buses selected by this mux */
+static int i2c_mux_post_bind(struct udevice *mux)
+{
+ ofnode node;
+ int ret;
+
+ debug("%s: %s\n", __func__, mux->name);
+ /*
+ * There is no compatible string in the sub-nodes, so we must manually
+ * bind these
+ */
+ dev_for_each_subnode(node, mux) {
+ struct udevice *dev;
+ const char *name;
+ const char *arrow = "->";
+ char *full_name;
+ int parent_name_len, arrow_len, mux_name_len, name_len;
+
+ name = ofnode_get_name(node);
+
+ /* Calculate lenghts of strings */
+ parent_name_len = strlen(mux->parent->name);
+ arrow_len = strlen(arrow);
+ mux_name_len = strlen(mux->name);
+ name_len = strlen(name);
+
+ full_name = calloc(1, parent_name_len + arrow_len +
+ mux_name_len + arrow_len + name_len + 1);
+ if (!full_name)
+ return -ENOMEM;
+
+ /* Compose bus name */
+ strcat(full_name, mux->parent->name);
+ strcat(full_name, arrow);
+ strcat(full_name, mux->name);
+ strcat(full_name, arrow);
+ strcat(full_name, name);
+
+ ret = device_bind_driver_to_node(mux, "i2c_mux_bus_drv",
+ full_name, node, &dev);
+ debug(" - bind ret=%d, %s, seq %d\n", ret,
+ dev ? dev->name : NULL, dev_seq(dev));
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/* Set up the mux ready for use */
+static int i2c_mux_post_probe(struct udevice *mux)
+{
+ struct i2c_mux *priv = dev_get_uclass_priv(mux);
+ int ret;
+
+ debug("%s: %s\n", __func__, mux->name);
+ priv->selected = -1;
+
+ /* if parent is of i2c uclass already, we'll take that, otherwise
+ * look if we find an i2c-parent phandle
+ */
+ if (UCLASS_I2C == device_get_uclass_id(mux->parent)) {
+ priv->i2c_bus = dev_get_parent(mux);
+ debug("%s: bus=%p/%s\n", __func__, priv->i2c_bus,
+ priv->i2c_bus->name);
+ return 0;
+ }
+
+ ret = uclass_get_device_by_phandle(UCLASS_I2C, mux, "i2c-parent",
+ &priv->i2c_bus);
+ if (ret)
+ return ret;
+ debug("%s: bus=%p/%s\n", __func__, priv->i2c_bus, priv->i2c_bus->name);
+
+ return 0;
+}
+
+int i2c_mux_select(struct udevice *dev)
+{
+ struct i2c_mux_bus *plat = dev_get_parent_plat(dev);
+ struct udevice *mux = dev->parent;
+ struct i2c_mux_ops *ops = i2c_mux_get_ops(mux);
+
+ if (!ops->select)
+ return -ENOSYS;
+
+ return ops->select(mux, dev, plat->channel);
+}
+
+int i2c_mux_deselect(struct udevice *dev)
+{
+ struct i2c_mux_bus *plat = dev_get_parent_plat(dev);
+ struct udevice *mux = dev->parent;
+ struct i2c_mux_ops *ops = i2c_mux_get_ops(mux);
+
+ if (!ops->deselect)
+ return -ENOSYS;
+
+ return ops->deselect(mux, dev, plat->channel);
+}
+
+static int i2c_mux_bus_set_bus_speed(struct udevice *dev, unsigned int speed)
+{
+ struct udevice *mux = dev->parent;
+ struct i2c_mux *priv = dev_get_uclass_priv(mux);
+ int ret, ret2;
+
+ ret = i2c_mux_select(dev);
+ if (ret)
+ return ret;
+ ret = dm_i2c_set_bus_speed(priv->i2c_bus, speed);
+ ret2 = i2c_mux_deselect(dev);
+
+ return ret ? ret : ret2;
+}
+
+static int i2c_mux_bus_probe(struct udevice *dev, uint chip_addr,
+ uint chip_flags)
+{
+ struct udevice *mux = dev->parent;
+ struct i2c_mux *priv = dev_get_uclass_priv(mux);
+ struct dm_i2c_ops *ops = i2c_get_ops(priv->i2c_bus);
+ int ret, ret2;
+
+ debug("%s: %s, bus %s\n", __func__, dev->name, priv->i2c_bus->name);
+ if (!ops->probe_chip)
+ return -ENOSYS;
+ ret = i2c_mux_select(dev);
+ if (ret)
+ return ret;
+ ret = ops->probe_chip(priv->i2c_bus, chip_addr, chip_flags);
+ ret2 = i2c_mux_deselect(dev);
+
+ return ret ? ret : ret2;
+}
+
+static int i2c_mux_bus_xfer(struct udevice *dev, struct i2c_msg *msg,
+ int nmsgs)
+{
+ struct udevice *mux = dev->parent;
+ struct i2c_mux *priv = dev_get_uclass_priv(mux);
+ struct dm_i2c_ops *ops = i2c_get_ops(priv->i2c_bus);
+ int ret, ret2;
+
+ debug("%s: %s, bus %s\n", __func__, dev->name, priv->i2c_bus->name);
+ if (!ops->xfer)
+ return -ENOSYS;
+ ret = i2c_mux_select(dev);
+ if (ret)
+ return ret;
+ ret = ops->xfer(priv->i2c_bus, msg, nmsgs);
+ ret2 = i2c_mux_deselect(dev);
+
+ return ret ? ret : ret2;
+}
+
+static const struct dm_i2c_ops i2c_mux_bus_ops = {
+ .xfer = i2c_mux_bus_xfer,
+ .probe_chip = i2c_mux_bus_probe,
+ .set_bus_speed = i2c_mux_bus_set_bus_speed,
+};
+
+U_BOOT_DRIVER(i2c_mux_bus) = {
+ .name = "i2c_mux_bus_drv",
+ .id = UCLASS_I2C,
+ .ops = &i2c_mux_bus_ops,
+};
+
+UCLASS_DRIVER(i2c_mux) = {
+ .id = UCLASS_I2C_MUX,
+ .name = "i2c_mux",
+ .post_bind = i2c_mux_post_bind,
+ .post_probe = i2c_mux_post_probe,
+ .per_device_auto = sizeof(struct i2c_mux),
+ .per_child_plat_auto = sizeof(struct i2c_mux_bus),
+ .child_post_bind = i2c_mux_child_post_bind,
+};
diff --git a/roms/u-boot/drivers/i2c/muxes/pca954x.c b/roms/u-boot/drivers/i2c/muxes/pca954x.c
new file mode 100644
index 000000000..55858cf65
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/muxes/pca954x.c
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2015 - 2016 Xilinx, Inc.
+ * Copyright (C) 2017 National Instruments Corp
+ * Written by Michal Simek
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <i2c.h>
+#include <log.h>
+#include <malloc.h>
+#include <asm/global_data.h>
+
+#include <asm-generic/gpio.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+enum pca_type {
+ PCA9543,
+ PCA9544,
+ PCA9546,
+ PCA9547,
+ PCA9548,
+ PCA9646
+};
+
+struct chip_desc {
+ u8 enable; /* Enable mask in ctl register (used for muxes only) */
+ enum muxtype {
+ pca954x_ismux = 0,
+ pca954x_isswi,
+ } muxtype;
+ u32 width;
+};
+
+struct pca954x_priv {
+ u32 addr; /* I2C mux address */
+ u32 width; /* I2C mux width - number of busses */
+ struct gpio_desc gpio_mux_reset;
+};
+
+static const struct chip_desc chips[] = {
+ [PCA9543] = {
+ .muxtype = pca954x_isswi,
+ .width = 2,
+ },
+ [PCA9544] = {
+ .enable = 0x4,
+ .muxtype = pca954x_ismux,
+ .width = 4,
+ },
+ [PCA9546] = {
+ .muxtype = pca954x_isswi,
+ .width = 4,
+ },
+ [PCA9547] = {
+ .enable = 0x8,
+ .muxtype = pca954x_ismux,
+ .width = 8,
+ },
+ [PCA9548] = {
+ .muxtype = pca954x_isswi,
+ .width = 8,
+ },
+ [PCA9646] = {
+ .muxtype = pca954x_isswi,
+ .width = 4,
+ },
+};
+
+static int pca954x_deselect(struct udevice *mux, struct udevice *bus,
+ uint channel)
+{
+ struct pca954x_priv *priv = dev_get_priv(mux);
+ uchar byte = 0;
+
+ return dm_i2c_write(mux, priv->addr, &byte, 1);
+}
+
+static int pca954x_select(struct udevice *mux, struct udevice *bus,
+ uint channel)
+{
+ struct pca954x_priv *priv = dev_get_priv(mux);
+ const struct chip_desc *chip = &chips[dev_get_driver_data(mux)];
+ uchar byte;
+
+ if (chip->muxtype == pca954x_ismux)
+ byte = channel | chip->enable;
+ else
+ byte = 1 << channel;
+
+ return dm_i2c_write(mux, priv->addr, &byte, 1);
+}
+
+static const struct i2c_mux_ops pca954x_ops = {
+ .select = pca954x_select,
+ .deselect = pca954x_deselect,
+};
+
+static const struct udevice_id pca954x_ids[] = {
+ { .compatible = "nxp,pca9543", .data = PCA9543 },
+ { .compatible = "nxp,pca9544", .data = PCA9544 },
+ { .compatible = "nxp,pca9546", .data = PCA9546 },
+ { .compatible = "nxp,pca9547", .data = PCA9547 },
+ { .compatible = "nxp,pca9548", .data = PCA9548 },
+ { .compatible = "nxp,pca9646", .data = PCA9646 },
+ { }
+};
+
+static int pca954x_of_to_plat(struct udevice *dev)
+{
+ struct pca954x_priv *priv = dev_get_priv(dev);
+ const struct chip_desc *chip = &chips[dev_get_driver_data(dev)];
+
+ priv->addr = dev_read_u32_default(dev, "reg", 0);
+ if (!priv->addr) {
+ debug("MUX not found\n");
+ return -ENODEV;
+ }
+ priv->width = chip->width;
+
+ if (!priv->width) {
+ debug("No I2C MUX width specified\n");
+ return -EINVAL;
+ }
+
+ debug("Device %s at 0x%x with width %d\n",
+ dev->name, priv->addr, priv->width);
+
+ return 0;
+}
+
+static int pca954x_probe(struct udevice *dev)
+{
+ if (CONFIG_IS_ENABLED(DM_GPIO)) {
+ struct pca954x_priv *priv = dev_get_priv(dev);
+ int err;
+
+ err = gpio_request_by_name(dev, "reset-gpios", 0,
+ &priv->gpio_mux_reset, GPIOD_IS_OUT);
+
+ /* it's optional so only bail if we get a real error */
+ if (err && (err != -ENOENT))
+ return err;
+
+ /* dm will take care of polarity */
+ if (dm_gpio_is_valid(&priv->gpio_mux_reset))
+ dm_gpio_set_value(&priv->gpio_mux_reset, 0);
+ }
+
+ return 0;
+}
+
+static int pca954x_remove(struct udevice *dev)
+{
+ if (CONFIG_IS_ENABLED(DM_GPIO)) {
+ struct pca954x_priv *priv = dev_get_priv(dev);
+
+ if (dm_gpio_is_valid(&priv->gpio_mux_reset))
+ dm_gpio_free(dev, &priv->gpio_mux_reset);
+ }
+
+ return 0;
+}
+
+U_BOOT_DRIVER(pca954x) = {
+ .name = "pca954x",
+ .id = UCLASS_I2C_MUX,
+ .of_match = pca954x_ids,
+ .probe = pca954x_probe,
+ .remove = pca954x_remove,
+ .ops = &pca954x_ops,
+ .of_to_plat = pca954x_of_to_plat,
+ .priv_auto = sizeof(struct pca954x_priv),
+};
diff --git a/roms/u-boot/drivers/i2c/mv_i2c.c b/roms/u-boot/drivers/i2c/mv_i2c.c
new file mode 100644
index 000000000..20c5de000
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/mv_i2c.c
@@ -0,0 +1,606 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2000
+ * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it
+ *
+ * (C) Copyright 2000 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * (C) Copyright 2003 Pengutronix e.K.
+ * Robert Schwebel <r.schwebel@pengutronix.de>
+ *
+ * (C) Copyright 2011 Marvell Inc.
+ * Lei Wen <leiwen@marvell.com>
+ *
+ * Back ported to the 8xx platform (from the 8260 platform) by
+ * Murray.Jensen@cmst.csiro.au, 27-Jan-01.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+#include <log.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include "mv_i2c.h"
+
+/* All transfers are described by this data structure */
+struct mv_i2c_msg {
+ u8 condition;
+ u8 acknack;
+ u8 direction;
+ u8 data;
+};
+
+#ifdef CONFIG_ARMADA_3700
+/* Armada 3700 has no padding between the registers */
+struct mv_i2c {
+ u32 ibmr;
+ u32 idbr;
+ u32 icr;
+ u32 isr;
+ u32 isar;
+};
+#else
+struct mv_i2c {
+ u32 ibmr;
+ u32 pad0;
+ u32 idbr;
+ u32 pad1;
+ u32 icr;
+ u32 pad2;
+ u32 isr;
+ u32 pad3;
+ u32 isar;
+};
+#endif
+
+/*
+ * Dummy implementation that can be overwritten by a board
+ * specific function
+ */
+__weak void i2c_clk_enable(void)
+{
+}
+
+/*
+ * i2c_reset: - reset the host controller
+ *
+ */
+static void i2c_reset(struct mv_i2c *base)
+{
+ u32 icr_mode;
+
+ /* Save bus mode (standard or fast speed) for later use */
+ icr_mode = readl(&base->icr) & ICR_MODE_MASK;
+ writel(readl(&base->icr) & ~ICR_IUE, &base->icr); /* disable unit */
+ writel(readl(&base->icr) | ICR_UR, &base->icr); /* reset the unit */
+ udelay(100);
+ writel(readl(&base->icr) & ~ICR_IUE, &base->icr); /* disable unit */
+
+ i2c_clk_enable();
+
+ writel(CONFIG_SYS_I2C_SLAVE, &base->isar); /* set our slave address */
+ /* set control reg values */
+ writel(I2C_ICR_INIT | icr_mode, &base->icr);
+ writel(I2C_ISR_INIT, &base->isr); /* set clear interrupt bits */
+ writel(readl(&base->icr) | ICR_IUE, &base->icr); /* enable unit */
+ udelay(100);
+}
+
+/*
+ * i2c_isr_set_cleared: - wait until certain bits of the I2C status register
+ * are set and cleared
+ *
+ * @return: 1 in case of success, 0 means timeout (no match within 10 ms).
+ */
+static int i2c_isr_set_cleared(struct mv_i2c *base, unsigned long set_mask,
+ unsigned long cleared_mask)
+{
+ int timeout = 1000, isr;
+
+ do {
+ isr = readl(&base->isr);
+ udelay(10);
+ if (timeout-- < 0)
+ return 0;
+ } while (((isr & set_mask) != set_mask)
+ || ((isr & cleared_mask) != 0));
+
+ return 1;
+}
+
+/*
+ * i2c_transfer: - Transfer one byte over the i2c bus
+ *
+ * This function can tranfer a byte over the i2c bus in both directions.
+ * It is used by the public API functions.
+ *
+ * @return: 0: transfer successful
+ * -1: message is empty
+ * -2: transmit timeout
+ * -3: ACK missing
+ * -4: receive timeout
+ * -5: illegal parameters
+ * -6: bus is busy and couldn't be aquired
+ */
+static int i2c_transfer(struct mv_i2c *base, struct mv_i2c_msg *msg)
+{
+ int ret;
+
+ if (!msg)
+ goto transfer_error_msg_empty;
+
+ switch (msg->direction) {
+ case I2C_WRITE:
+ /* check if bus is not busy */
+ if (!i2c_isr_set_cleared(base, 0, ISR_IBB))
+ goto transfer_error_bus_busy;
+
+ /* start transmission */
+ writel(readl(&base->icr) & ~ICR_START, &base->icr);
+ writel(readl(&base->icr) & ~ICR_STOP, &base->icr);
+ writel(msg->data, &base->idbr);
+ if (msg->condition == I2C_COND_START)
+ writel(readl(&base->icr) | ICR_START, &base->icr);
+ if (msg->condition == I2C_COND_STOP)
+ writel(readl(&base->icr) | ICR_STOP, &base->icr);
+ if (msg->acknack == I2C_ACKNAK_SENDNAK)
+ writel(readl(&base->icr) | ICR_ACKNAK, &base->icr);
+ if (msg->acknack == I2C_ACKNAK_SENDACK)
+ writel(readl(&base->icr) & ~ICR_ACKNAK, &base->icr);
+ writel(readl(&base->icr) & ~ICR_ALDIE, &base->icr);
+ writel(readl(&base->icr) | ICR_TB, &base->icr);
+
+ /* transmit register empty? */
+ if (!i2c_isr_set_cleared(base, ISR_ITE, 0))
+ goto transfer_error_transmit_timeout;
+
+ /* clear 'transmit empty' state */
+ writel(readl(&base->isr) | ISR_ITE, &base->isr);
+
+ /* wait for ACK from slave */
+ if (msg->acknack == I2C_ACKNAK_WAITACK)
+ if (!i2c_isr_set_cleared(base, 0, ISR_ACKNAK))
+ goto transfer_error_ack_missing;
+ break;
+
+ case I2C_READ:
+
+ /* check if bus is not busy */
+ if (!i2c_isr_set_cleared(base, 0, ISR_IBB))
+ goto transfer_error_bus_busy;
+
+ /* start receive */
+ writel(readl(&base->icr) & ~ICR_START, &base->icr);
+ writel(readl(&base->icr) & ~ICR_STOP, &base->icr);
+ if (msg->condition == I2C_COND_START)
+ writel(readl(&base->icr) | ICR_START, &base->icr);
+ if (msg->condition == I2C_COND_STOP)
+ writel(readl(&base->icr) | ICR_STOP, &base->icr);
+ if (msg->acknack == I2C_ACKNAK_SENDNAK)
+ writel(readl(&base->icr) | ICR_ACKNAK, &base->icr);
+ if (msg->acknack == I2C_ACKNAK_SENDACK)
+ writel(readl(&base->icr) & ~ICR_ACKNAK, &base->icr);
+ writel(readl(&base->icr) & ~ICR_ALDIE, &base->icr);
+ writel(readl(&base->icr) | ICR_TB, &base->icr);
+
+ /* receive register full? */
+ if (!i2c_isr_set_cleared(base, ISR_IRF, 0))
+ goto transfer_error_receive_timeout;
+
+ msg->data = readl(&base->idbr);
+
+ /* clear 'receive empty' state */
+ writel(readl(&base->isr) | ISR_IRF, &base->isr);
+ break;
+ default:
+ goto transfer_error_illegal_param;
+ }
+
+ return 0;
+
+transfer_error_msg_empty:
+ debug("i2c_transfer: error: 'msg' is empty\n");
+ ret = -1;
+ goto i2c_transfer_finish;
+
+transfer_error_transmit_timeout:
+ debug("i2c_transfer: error: transmit timeout\n");
+ ret = -2;
+ goto i2c_transfer_finish;
+
+transfer_error_ack_missing:
+ debug("i2c_transfer: error: ACK missing\n");
+ ret = -3;
+ goto i2c_transfer_finish;
+
+transfer_error_receive_timeout:
+ debug("i2c_transfer: error: receive timeout\n");
+ ret = -4;
+ goto i2c_transfer_finish;
+
+transfer_error_illegal_param:
+ debug("i2c_transfer: error: illegal parameters\n");
+ ret = -5;
+ goto i2c_transfer_finish;
+
+transfer_error_bus_busy:
+ debug("i2c_transfer: error: bus is busy\n");
+ ret = -6;
+ goto i2c_transfer_finish;
+
+i2c_transfer_finish:
+ debug("i2c_transfer: ISR: 0x%04x\n", readl(&base->isr));
+ i2c_reset(base);
+ return ret;
+}
+
+static int __i2c_read(struct mv_i2c *base, uchar chip, u8 *addr, int alen,
+ uchar *buffer, int len)
+{
+ struct mv_i2c_msg msg;
+
+ debug("i2c_read(chip=0x%02x, addr=0x%02x, alen=0x%02x, "
+ "len=0x%02x)\n", chip, *addr, alen, len);
+
+ if (len == 0) {
+ printf("reading zero byte is invalid\n");
+ return -EINVAL;
+ }
+
+ i2c_reset(base);
+
+ /* dummy chip address write */
+ debug("i2c_read: dummy chip address write\n");
+ msg.condition = I2C_COND_START;
+ msg.acknack = I2C_ACKNAK_WAITACK;
+ msg.direction = I2C_WRITE;
+ msg.data = (chip << 1);
+ msg.data &= 0xFE;
+ if (i2c_transfer(base, &msg))
+ return -1;
+
+ /*
+ * send memory address bytes;
+ * alen defines how much bytes we have to send.
+ */
+ while (--alen >= 0) {
+ debug("i2c_read: send address byte %02x (alen=%d)\n",
+ *addr, alen);
+ msg.condition = I2C_COND_NORMAL;
+ msg.acknack = I2C_ACKNAK_WAITACK;
+ msg.direction = I2C_WRITE;
+ msg.data = addr[alen];
+ if (i2c_transfer(base, &msg))
+ return -1;
+ }
+
+ /* start read sequence */
+ debug("i2c_read: start read sequence\n");
+ msg.condition = I2C_COND_START;
+ msg.acknack = I2C_ACKNAK_WAITACK;
+ msg.direction = I2C_WRITE;
+ msg.data = (chip << 1);
+ msg.data |= 0x01;
+ if (i2c_transfer(base, &msg))
+ return -1;
+
+ /* read bytes; send NACK at last byte */
+ while (len--) {
+ if (len == 0) {
+ msg.condition = I2C_COND_STOP;
+ msg.acknack = I2C_ACKNAK_SENDNAK;
+ } else {
+ msg.condition = I2C_COND_NORMAL;
+ msg.acknack = I2C_ACKNAK_SENDACK;
+ }
+
+ msg.direction = I2C_READ;
+ msg.data = 0x00;
+ if (i2c_transfer(base, &msg))
+ return -1;
+
+ *buffer = msg.data;
+ debug("i2c_read: reading byte (%p)=0x%02x\n",
+ buffer, *buffer);
+ buffer++;
+ }
+
+ i2c_reset(base);
+
+ return 0;
+}
+
+static int __i2c_write(struct mv_i2c *base, uchar chip, u8 *addr, int alen,
+ uchar *buffer, int len)
+{
+ struct mv_i2c_msg msg;
+
+ debug("i2c_write(chip=0x%02x, addr=0x%02x, alen=0x%02x, "
+ "len=0x%02x)\n", chip, *addr, alen, len);
+
+ i2c_reset(base);
+
+ /* chip address write */
+ debug("i2c_write: chip address write\n");
+ msg.condition = I2C_COND_START;
+ msg.acknack = I2C_ACKNAK_WAITACK;
+ msg.direction = I2C_WRITE;
+ msg.data = (chip << 1);
+ msg.data &= 0xFE;
+ if (i2c_transfer(base, &msg))
+ return -1;
+
+ /*
+ * send memory address bytes;
+ * alen defines how much bytes we have to send.
+ */
+ while (--alen >= 0) {
+ debug("i2c_read: send address byte %02x (alen=%d)\n",
+ *addr, alen);
+ msg.condition = I2C_COND_NORMAL;
+ msg.acknack = I2C_ACKNAK_WAITACK;
+ msg.direction = I2C_WRITE;
+ msg.data = addr[alen];
+ if (i2c_transfer(base, &msg))
+ return -1;
+ }
+
+ /* write bytes; send NACK at last byte */
+ while (len--) {
+ debug("i2c_write: writing byte (%p)=0x%02x\n",
+ buffer, *buffer);
+
+ if (len == 0)
+ msg.condition = I2C_COND_STOP;
+ else
+ msg.condition = I2C_COND_NORMAL;
+
+ msg.acknack = I2C_ACKNAK_WAITACK;
+ msg.direction = I2C_WRITE;
+ msg.data = *(buffer++);
+
+ if (i2c_transfer(base, &msg))
+ return -1;
+ }
+
+ i2c_reset(base);
+
+ return 0;
+}
+
+#if !CONFIG_IS_ENABLED(DM_I2C)
+
+static struct mv_i2c *base_glob;
+
+static void i2c_board_init(struct mv_i2c *base)
+{
+#ifdef CONFIG_SYS_I2C_INIT_BOARD
+ u32 icr;
+ /*
+ * call board specific i2c bus reset routine before accessing the
+ * environment, which might be in a chip on that bus. For details
+ * about this problem see doc/I2C_Edge_Conditions.
+ *
+ * disable I2C controller first, otherwhise it thinks we want to
+ * talk to the slave port...
+ */
+ icr = readl(&base->icr);
+ writel(readl(&base->icr) & ~(ICR_SCLE | ICR_IUE), &base->icr);
+
+ i2c_init_board();
+
+ writel(icr, &base->icr);
+#endif
+}
+
+#ifdef CONFIG_I2C_MULTI_BUS
+static unsigned long i2c_regs[CONFIG_MV_I2C_NUM] = CONFIG_MV_I2C_REG;
+static unsigned int bus_initialized[CONFIG_MV_I2C_NUM];
+static unsigned int current_bus;
+
+int i2c_set_bus_num(unsigned int bus)
+{
+ if ((bus < 0) || (bus >= CONFIG_MV_I2C_NUM)) {
+ printf("Bad bus: %d\n", bus);
+ return -1;
+ }
+
+ base_glob = (struct mv_i2c *)i2c_regs[bus];
+ current_bus = bus;
+
+ if (!bus_initialized[current_bus]) {
+ i2c_board_init(base_glob);
+ bus_initialized[current_bus] = 1;
+ }
+
+ return 0;
+}
+
+unsigned int i2c_get_bus_num(void)
+{
+ return current_bus;
+}
+#endif
+
+/* API Functions */
+void i2c_init(int speed, int slaveaddr)
+{
+ u32 val;
+
+#ifdef CONFIG_I2C_MULTI_BUS
+ current_bus = 0;
+ base_glob = (struct mv_i2c *)i2c_regs[current_bus];
+#else
+ base_glob = (struct mv_i2c *)CONFIG_MV_I2C_REG;
+#endif
+
+ if (speed > I2C_SPEED_STANDARD_RATE)
+ val = ICR_FM;
+ else
+ val = ICR_SM;
+ clrsetbits_le32(&base_glob->icr, ICR_MODE_MASK, val);
+
+ i2c_board_init(base_glob);
+}
+
+static int __i2c_probe_chip(struct mv_i2c *base, uchar chip)
+{
+ struct mv_i2c_msg msg;
+
+ i2c_reset(base);
+
+ msg.condition = I2C_COND_START;
+ msg.acknack = I2C_ACKNAK_WAITACK;
+ msg.direction = I2C_WRITE;
+ msg.data = (chip << 1) + 1;
+ if (i2c_transfer(base, &msg))
+ return -1;
+
+ msg.condition = I2C_COND_STOP;
+ msg.acknack = I2C_ACKNAK_SENDNAK;
+ msg.direction = I2C_READ;
+ msg.data = 0x00;
+ if (i2c_transfer(base, &msg))
+ return -1;
+
+ return 0;
+}
+
+/*
+ * i2c_probe: - Test if a chip answers for a given i2c address
+ *
+ * @chip: address of the chip which is searched for
+ * @return: 0 if a chip was found, -1 otherwhise
+ */
+int i2c_probe(uchar chip)
+{
+ return __i2c_probe_chip(base_glob, chip);
+}
+
+/*
+ * i2c_read: - Read multiple bytes from an i2c device
+ *
+ * The higher level routines take into account that this function is only
+ * called with len < page length of the device (see configuration file)
+ *
+ * @chip: address of the chip which is to be read
+ * @addr: i2c data address within the chip
+ * @alen: length of the i2c data address (1..2 bytes)
+ * @buffer: where to write the data
+ * @len: how much byte do we want to read
+ * @return: 0 in case of success
+ */
+int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
+{
+ u8 addr_bytes[4];
+
+ addr_bytes[0] = (addr >> 0) & 0xFF;
+ addr_bytes[1] = (addr >> 8) & 0xFF;
+ addr_bytes[2] = (addr >> 16) & 0xFF;
+ addr_bytes[3] = (addr >> 24) & 0xFF;
+
+ return __i2c_read(base_glob, chip, addr_bytes, alen, buffer, len);
+}
+
+/*
+ * i2c_write: - Write multiple bytes to an i2c device
+ *
+ * The higher level routines take into account that this function is only
+ * called with len < page length of the device (see configuration file)
+ *
+ * @chip: address of the chip which is to be written
+ * @addr: i2c data address within the chip
+ * @alen: length of the i2c data address (1..2 bytes)
+ * @buffer: where to find the data to be written
+ * @len: how much byte do we want to read
+ * @return: 0 in case of success
+ */
+int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
+{
+ u8 addr_bytes[4];
+
+ addr_bytes[0] = (addr >> 0) & 0xFF;
+ addr_bytes[1] = (addr >> 8) & 0xFF;
+ addr_bytes[2] = (addr >> 16) & 0xFF;
+ addr_bytes[3] = (addr >> 24) & 0xFF;
+
+ return __i2c_write(base_glob, chip, addr_bytes, alen, buffer, len);
+}
+
+#else /* CONFIG_DM_I2C */
+
+struct mv_i2c_priv {
+ struct mv_i2c *base;
+};
+
+static int mv_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
+{
+ struct mv_i2c_priv *i2c = dev_get_priv(bus);
+ struct i2c_msg *dmsg, *omsg, dummy;
+
+ memset(&dummy, 0, sizeof(struct i2c_msg));
+
+ /*
+ * We expect either two messages (one with an offset and one with the
+ * actual data) or one message (just data or offset/data combined)
+ */
+ if (nmsgs > 2 || nmsgs == 0) {
+ debug("%s: Only one or two messages are supported.", __func__);
+ return -1;
+ }
+
+ omsg = nmsgs == 1 ? &dummy : msg;
+ dmsg = nmsgs == 1 ? msg : msg + 1;
+
+ if (dmsg->flags & I2C_M_RD)
+ return __i2c_read(i2c->base, dmsg->addr, omsg->buf,
+ omsg->len, dmsg->buf, dmsg->len);
+ else
+ return __i2c_write(i2c->base, dmsg->addr, omsg->buf,
+ omsg->len, dmsg->buf, dmsg->len);
+}
+
+static int mv_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
+{
+ struct mv_i2c_priv *priv = dev_get_priv(bus);
+ u32 val;
+
+ if (speed > I2C_SPEED_STANDARD_RATE)
+ val = ICR_FM;
+ else
+ val = ICR_SM;
+ clrsetbits_le32(&priv->base->icr, ICR_MODE_MASK, val);
+
+ return 0;
+}
+
+static int mv_i2c_probe(struct udevice *bus)
+{
+ struct mv_i2c_priv *priv = dev_get_priv(bus);
+
+ priv->base = dev_read_addr_ptr(bus);
+
+ return 0;
+}
+
+static const struct dm_i2c_ops mv_i2c_ops = {
+ .xfer = mv_i2c_xfer,
+ .set_bus_speed = mv_i2c_set_bus_speed,
+};
+
+static const struct udevice_id mv_i2c_ids[] = {
+ { .compatible = "marvell,armada-3700-i2c" },
+ { }
+};
+
+U_BOOT_DRIVER(i2c_mv) = {
+ .name = "i2c_mv",
+ .id = UCLASS_I2C,
+ .of_match = mv_i2c_ids,
+ .probe = mv_i2c_probe,
+ .priv_auto = sizeof(struct mv_i2c_priv),
+ .ops = &mv_i2c_ops,
+};
+#endif /* CONFIG_DM_I2C */
diff --git a/roms/u-boot/drivers/i2c/mv_i2c.h b/roms/u-boot/drivers/i2c/mv_i2c.h
new file mode 100644
index 000000000..ec2d439e3
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/mv_i2c.h
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2011
+ * Marvell Inc, <www.marvell.com>
+ */
+
+#ifndef _MV_I2C_H_
+#define _MV_I2C_H_
+extern void i2c_clk_enable(void);
+
+/* Shall the current transfer have a start/stop condition? */
+#define I2C_COND_NORMAL 0
+#define I2C_COND_START 1
+#define I2C_COND_STOP 2
+
+/* Shall the current transfer be ack/nacked or being waited for it? */
+#define I2C_ACKNAK_WAITACK 1
+#define I2C_ACKNAK_SENDACK 2
+#define I2C_ACKNAK_SENDNAK 4
+
+/* Specify who shall transfer the data (master or slave) */
+#define I2C_READ 0
+#define I2C_WRITE 1
+
+#define I2C_ICR_INIT (ICR_BEIE | ICR_IRFIE | ICR_ITEIE | ICR_GCD | ICR_SCLE)
+
+#define I2C_ISR_INIT 0x7FF
+/* ----- Control register bits ---------------------------------------- */
+
+#define ICR_START 0x1 /* start bit */
+#define ICR_STOP 0x2 /* stop bit */
+#define ICR_ACKNAK 0x4 /* send ACK(0) or NAK(1) */
+#define ICR_TB 0x8 /* transfer byte bit */
+#define ICR_MA 0x10 /* master abort */
+#define ICR_SCLE 0x20 /* master clock enable, mona SCLEA */
+#define ICR_IUE 0x40 /* unit enable */
+#define ICR_GCD 0x80 /* general call disable */
+#define ICR_ITEIE 0x100 /* enable tx interrupts */
+#define ICR_IRFIE 0x200 /* enable rx interrupts, mona: DRFIE */
+#define ICR_BEIE 0x400 /* enable bus error ints */
+#define ICR_SSDIE 0x800 /* slave STOP detected int enable */
+#define ICR_ALDIE 0x1000 /* enable arbitration interrupt */
+#define ICR_SADIE 0x2000 /* slave address detected int enable */
+#define ICR_UR 0x4000 /* unit reset */
+#ifdef CONFIG_ARMADA_3700
+#define ICR_SM 0x00000 /* Standard Mode */
+#define ICR_FM 0x10000 /* Fast Mode */
+#define ICR_MODE_MASK 0x30000 /* Mode mask */
+#else
+#define ICR_SM 0x00000 /* Standard Mode */
+#define ICR_FM 0x08000 /* Fast Mode */
+#define ICR_MODE_MASK 0x18000 /* Mode mask */
+#endif
+
+/* ----- Status register bits ----------------------------------------- */
+
+#define ISR_RWM 0x1 /* read/write mode */
+#define ISR_ACKNAK 0x2 /* ack/nak status */
+#define ISR_UB 0x4 /* unit busy */
+#define ISR_IBB 0x8 /* bus busy */
+#define ISR_SSD 0x10 /* slave stop detected */
+#define ISR_ALD 0x20 /* arbitration loss detected */
+#define ISR_ITE 0x40 /* tx buffer empty */
+#define ISR_IRF 0x80 /* rx buffer full */
+#define ISR_GCAD 0x100 /* general call address detected */
+#define ISR_SAD 0x200 /* slave address detected */
+#define ISR_BED 0x400 /* bus error no ACK/NAK */
+
+#endif
diff --git a/roms/u-boot/drivers/i2c/mvtwsi.c b/roms/u-boot/drivers/i2c/mvtwsi.c
new file mode 100644
index 000000000..d33e2c7c9
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/mvtwsi.c
@@ -0,0 +1,896 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for the TWSI (i2c) controller found on the Marvell
+ * orion5x and kirkwood SoC families.
+ *
+ * Author: Albert Aribaud <albert.u.boot@aribaud.net>
+ * Copyright (c) 2010 Albert Aribaud.
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <log.h>
+#include <asm/global_data.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+#include <linux/compat.h>
+#if CONFIG_IS_ENABLED(DM_I2C)
+#include <dm.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Include a file that will provide CONFIG_I2C_MVTWSI_BASE*, and possibly other
+ * settings
+ */
+
+#if !CONFIG_IS_ENABLED(DM_I2C)
+#if defined(CONFIG_ARCH_ORION5X)
+#include <asm/arch/orion5x.h>
+#elif (defined(CONFIG_ARCH_KIRKWOOD) || defined(CONFIG_ARCH_MVEBU))
+#include <asm/arch/soc.h>
+#elif defined(CONFIG_ARCH_SUNXI)
+#include <asm/arch/i2c.h>
+#else
+#error Driver mvtwsi not supported by SoC or board
+#endif
+#endif /* CONFIG_DM_I2C */
+
+/*
+ * On SUNXI, we get CONFIG_SYS_TCLK from this include, so we want to
+ * always have it.
+ */
+#if CONFIG_IS_ENABLED(DM_I2C) && defined(CONFIG_ARCH_SUNXI)
+#include <asm/arch/i2c.h>
+#endif
+
+/*
+ * TWSI register structure
+ */
+
+#ifdef CONFIG_ARCH_SUNXI
+
+struct mvtwsi_registers {
+ u32 slave_address;
+ u32 xtnd_slave_addr;
+ u32 data;
+ u32 control;
+ u32 status;
+ u32 baudrate;
+ u32 soft_reset;
+ u32 debug; /* Dummy field for build compatibility with mvebu */
+};
+
+#else
+
+struct mvtwsi_registers {
+ u32 slave_address;
+ u32 data;
+ u32 control;
+ union {
+ u32 status; /* When reading */
+ u32 baudrate; /* When writing */
+ };
+ u32 xtnd_slave_addr;
+ u32 reserved0[2];
+ u32 soft_reset;
+ u32 reserved1[27];
+ u32 debug;
+};
+
+#endif
+
+#if CONFIG_IS_ENABLED(DM_I2C)
+struct mvtwsi_i2c_dev {
+ /* TWSI Register base for the device */
+ struct mvtwsi_registers *base;
+ /* Number of the device (determined from cell-index property) */
+ int index;
+ /* The I2C slave address for the device */
+ u8 slaveadd;
+ /* The configured I2C speed in Hz */
+ uint speed;
+ /* The current length of a clock period (depending on speed) */
+ uint tick;
+};
+#endif /* CONFIG_DM_I2C */
+
+/*
+ * enum mvtwsi_ctrl_register_fields - Bit masks for flags in the control
+ * register
+ */
+enum mvtwsi_ctrl_register_fields {
+ /* Acknowledge bit */
+ MVTWSI_CONTROL_ACK = 0x00000004,
+ /* Interrupt flag */
+ MVTWSI_CONTROL_IFLG = 0x00000008,
+ /* Stop bit */
+ MVTWSI_CONTROL_STOP = 0x00000010,
+ /* Start bit */
+ MVTWSI_CONTROL_START = 0x00000020,
+ /* I2C enable */
+ MVTWSI_CONTROL_TWSIEN = 0x00000040,
+ /* Interrupt enable */
+ MVTWSI_CONTROL_INTEN = 0x00000080,
+};
+
+/*
+ * On sun6i and newer, IFLG is a write-clear bit, which is cleared by writing 1;
+ * on other platforms, it is a normal r/w bit, which is cleared by writing 0.
+ */
+
+#if defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_SUN50I_GEN_H6)
+#define MVTWSI_CONTROL_CLEAR_IFLG 0x00000008
+#else
+#define MVTWSI_CONTROL_CLEAR_IFLG 0x00000000
+#endif
+
+/*
+ * enum mvstwsi_status_values - Possible values of I2C controller's status
+ * register
+ *
+ * Only those statuses expected in normal master operation on
+ * non-10-bit-address devices are specified.
+ *
+ * Every status that's unexpected during normal operation (bus errors,
+ * arbitration losses, missing ACKs...) is passed back to the caller as an error
+ * code.
+ */
+enum mvstwsi_status_values {
+ /* START condition transmitted */
+ MVTWSI_STATUS_START = 0x08,
+ /* Repeated START condition transmitted */
+ MVTWSI_STATUS_REPEATED_START = 0x10,
+ /* Address + write bit transmitted, ACK received */
+ MVTWSI_STATUS_ADDR_W_ACK = 0x18,
+ /* Data transmitted, ACK received */
+ MVTWSI_STATUS_DATA_W_ACK = 0x28,
+ /* Address + read bit transmitted, ACK received */
+ MVTWSI_STATUS_ADDR_R_ACK = 0x40,
+ /* Address + read bit transmitted, ACK not received */
+ MVTWSI_STATUS_ADDR_R_NAK = 0x48,
+ /* Data received, ACK transmitted */
+ MVTWSI_STATUS_DATA_R_ACK = 0x50,
+ /* Data received, ACK not transmitted */
+ MVTWSI_STATUS_DATA_R_NAK = 0x58,
+ /* No relevant status */
+ MVTWSI_STATUS_IDLE = 0xF8,
+};
+
+/*
+ * enum mvstwsi_ack_flags - Determine whether a read byte should be
+ * acknowledged or not.
+ */
+enum mvtwsi_ack_flags {
+ /* Send NAK after received byte */
+ MVTWSI_READ_NAK = 0,
+ /* Send ACK after received byte */
+ MVTWSI_READ_ACK = 1,
+};
+
+/*
+ * calc_tick() - Calculate the duration of a clock cycle from the I2C speed
+ *
+ * @speed: The speed in Hz to calculate the clock cycle duration for.
+ * @return The duration of a clock cycle in ns.
+ */
+inline uint calc_tick(uint speed)
+{
+ /* One tick = the duration of a period at the specified speed in ns (we
+ * add 100 ns to be on the safe side) */
+ return (1000000000u / speed) + 100;
+}
+
+#if !CONFIG_IS_ENABLED(DM_I2C)
+
+/*
+ * twsi_get_base() - Get controller register base for specified adapter
+ *
+ * @adap: Adapter to get the register base for.
+ * @return Register base for the specified adapter.
+ */
+static struct mvtwsi_registers *twsi_get_base(struct i2c_adapter *adap)
+{
+ switch (adap->hwadapnr) {
+#ifdef CONFIG_I2C_MVTWSI_BASE0
+ case 0:
+ return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE0;
+#endif
+#ifdef CONFIG_I2C_MVTWSI_BASE1
+ case 1:
+ return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE1;
+#endif
+#ifdef CONFIG_I2C_MVTWSI_BASE2
+ case 2:
+ return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE2;
+#endif
+#ifdef CONFIG_I2C_MVTWSI_BASE3
+ case 3:
+ return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE3;
+#endif
+#ifdef CONFIG_I2C_MVTWSI_BASE4
+ case 4:
+ return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE4;
+#endif
+#ifdef CONFIG_I2C_MVTWSI_BASE5
+ case 5:
+ return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE5;
+#endif
+ default:
+ printf("Missing mvtwsi controller %d base\n", adap->hwadapnr);
+ break;
+ }
+
+ return NULL;
+}
+#endif
+
+/*
+ * enum mvtwsi_error_class - types of I2C errors
+ */
+enum mvtwsi_error_class {
+ /* The controller returned a different status than expected */
+ MVTWSI_ERROR_WRONG_STATUS = 0x01,
+ /* The controller timed out */
+ MVTWSI_ERROR_TIMEOUT = 0x02,
+};
+
+/*
+ * mvtwsi_error() - Build I2C return code from error information
+ *
+ * For debugging purposes, this function packs some information of an occurred
+ * error into a return code. These error codes are returned from I2C API
+ * functions (i2c_{read,write}, dm_i2c_{read,write}, etc.).
+ *
+ * @ec: The error class of the error (enum mvtwsi_error_class).
+ * @lc: The last value of the control register.
+ * @ls: The last value of the status register.
+ * @es: The expected value of the status register.
+ * @return The generated error code.
+ */
+inline uint mvtwsi_error(uint ec, uint lc, uint ls, uint es)
+{
+ return ((ec << 24) & 0xFF000000)
+ | ((lc << 16) & 0x00FF0000)
+ | ((ls << 8) & 0x0000FF00)
+ | (es & 0xFF);
+}
+
+/*
+ * twsi_wait() - Wait for I2C bus interrupt flag and check status, or time out.
+ *
+ * @return Zero if status is as expected, or a non-zero code if either a time
+ * out occurred, or the status was not the expected one.
+ */
+static int twsi_wait(struct mvtwsi_registers *twsi, int expected_status,
+ uint tick)
+{
+ int control, status;
+ int timeout = 1000;
+
+ do {
+ control = readl(&twsi->control);
+ if (control & MVTWSI_CONTROL_IFLG) {
+ /*
+ * On Armada 38x it seems that the controller works as
+ * if it first set the MVTWSI_CONTROL_IFLAG in the
+ * control register and only after that it changed the
+ * status register.
+ * This sometimes caused weird bugs which only appeared
+ * on selected I2C speeds and even then only sometimes.
+ * We therefore add here a simple ndealy(100), which
+ * seems to fix this weird bug.
+ */
+ ndelay(100);
+ status = readl(&twsi->status);
+ if (status == expected_status)
+ return 0;
+ else
+ return mvtwsi_error(
+ MVTWSI_ERROR_WRONG_STATUS,
+ control, status, expected_status);
+ }
+ ndelay(tick); /* One clock cycle */
+ } while (timeout--);
+ status = readl(&twsi->status);
+ return mvtwsi_error(MVTWSI_ERROR_TIMEOUT, control, status,
+ expected_status);
+}
+
+/*
+ * twsi_start() - Assert a START condition on the bus.
+ *
+ * This function is used in both single I2C transactions and inside
+ * back-to-back transactions (repeated starts).
+ *
+ * @twsi: The MVTWSI register structure to use.
+ * @expected_status: The I2C bus status expected to be asserted after the
+ * operation completion.
+ * @tick: The duration of a clock cycle at the current I2C speed.
+ * @return Zero if status is as expected, or a non-zero code if either a time
+ * out occurred or the status was not the expected one.
+ */
+static int twsi_start(struct mvtwsi_registers *twsi, int expected_status,
+ uint tick)
+{
+ /* Assert START */
+ writel(MVTWSI_CONTROL_TWSIEN | MVTWSI_CONTROL_START |
+ MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
+ /* Wait for controller to process START */
+ return twsi_wait(twsi, expected_status, tick);
+}
+
+/*
+ * twsi_send() - Send a byte on the I2C bus.
+ *
+ * The byte may be part of an address byte or data.
+ *
+ * @twsi: The MVTWSI register structure to use.
+ * @byte: The byte to send.
+ * @expected_status: The I2C bus status expected to be asserted after the
+ * operation completion.
+ * @tick: The duration of a clock cycle at the current I2C speed.
+ * @return Zero if status is as expected, or a non-zero code if either a time
+ * out occurred or the status was not the expected one.
+ */
+static int twsi_send(struct mvtwsi_registers *twsi, u8 byte,
+ int expected_status, uint tick)
+{
+ /* Write byte to data register for sending */
+ writel(byte, &twsi->data);
+ /* Clear any pending interrupt -- that will cause sending */
+ writel(MVTWSI_CONTROL_TWSIEN | MVTWSI_CONTROL_CLEAR_IFLG,
+ &twsi->control);
+ /* Wait for controller to receive byte, and check ACK */
+ return twsi_wait(twsi, expected_status, tick);
+}
+
+/*
+ * twsi_recv() - Receive a byte on the I2C bus.
+ *
+ * The static variable mvtwsi_control_flags controls whether we ack or nak.
+ *
+ * @twsi: The MVTWSI register structure to use.
+ * @byte: The byte to send.
+ * @ack_flag: Flag that determines whether the received byte should
+ * be acknowledged by the controller or not (sent ACK/NAK).
+ * @tick: The duration of a clock cycle at the current I2C speed.
+ * @return Zero if status is as expected, or a non-zero code if either a time
+ * out occurred or the status was not the expected one.
+ */
+static int twsi_recv(struct mvtwsi_registers *twsi, u8 *byte, int ack_flag,
+ uint tick)
+{
+ int expected_status, status, control;
+
+ /* Compute expected status based on passed ACK flag */
+ expected_status = ack_flag ? MVTWSI_STATUS_DATA_R_ACK :
+ MVTWSI_STATUS_DATA_R_NAK;
+ /* Acknowledge *previous state*, and launch receive */
+ control = MVTWSI_CONTROL_TWSIEN;
+ control |= ack_flag == MVTWSI_READ_ACK ? MVTWSI_CONTROL_ACK : 0;
+ writel(control | MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
+ /* Wait for controller to receive byte, and assert ACK or NAK */
+ status = twsi_wait(twsi, expected_status, tick);
+ /* If we did receive the expected byte, store it */
+ if (status == 0)
+ *byte = readl(&twsi->data);
+ return status;
+}
+
+/*
+ * twsi_stop() - Assert a STOP condition on the bus.
+ *
+ * This function is also used to force the bus back to idle state (SDA =
+ * SCL = 1).
+ *
+ * @twsi: The MVTWSI register structure to use.
+ * @tick: The duration of a clock cycle at the current I2C speed.
+ * @return Zero if the operation succeeded, or a non-zero code if a time out
+ * occurred.
+ */
+static int twsi_stop(struct mvtwsi_registers *twsi, uint tick)
+{
+ int control, stop_status;
+ int status = 0;
+ int timeout = 1000;
+
+ /* Assert STOP */
+ control = MVTWSI_CONTROL_TWSIEN | MVTWSI_CONTROL_STOP;
+ writel(control | MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
+ /* Wait for IDLE; IFLG won't rise, so we can't use twsi_wait() */
+ do {
+ stop_status = readl(&twsi->status);
+ if (stop_status == MVTWSI_STATUS_IDLE)
+ break;
+ ndelay(tick); /* One clock cycle */
+ } while (timeout--);
+ control = readl(&twsi->control);
+ if (stop_status != MVTWSI_STATUS_IDLE)
+ status = mvtwsi_error(MVTWSI_ERROR_TIMEOUT,
+ control, status, MVTWSI_STATUS_IDLE);
+ return status;
+}
+
+/*
+ * twsi_calc_freq() - Compute I2C frequency depending on m and n parameters.
+ *
+ * @n: Parameter 'n' for the frequency calculation algorithm.
+ * @m: Parameter 'm' for the frequency calculation algorithm.
+ * @return The I2C frequency corresponding to the passed m and n parameters.
+ */
+static uint twsi_calc_freq(const int n, const int m)
+{
+#ifdef CONFIG_ARCH_SUNXI
+ return CONFIG_SYS_TCLK / (10 * (m + 1) * (1 << n));
+#else
+ return CONFIG_SYS_TCLK / (10 * (m + 1) * (2 << n));
+#endif
+}
+
+/*
+ * twsi_reset() - Reset the I2C controller.
+ *
+ * Resetting the controller also resets the baud rate and slave address, hence
+ * they must be re-established after the reset.
+ *
+ * @twsi: The MVTWSI register structure to use.
+ */
+static void twsi_reset(struct mvtwsi_registers *twsi)
+{
+ /* Reset controller */
+ writel(0, &twsi->soft_reset);
+ /* Wait 2 ms -- this is what the Marvell LSP does */
+ udelay(20000);
+}
+
+/*
+ * __twsi_i2c_set_bus_speed() - Set the speed of the I2C controller.
+ *
+ * This function sets baud rate to the highest possible value that does not
+ * exceed the requested rate.
+ *
+ * @twsi: The MVTWSI register structure to use.
+ * @requested_speed: The desired frequency the controller should run at
+ * in Hz.
+ * @return The actual frequency the controller was configured to.
+ */
+static uint __twsi_i2c_set_bus_speed(struct mvtwsi_registers *twsi,
+ uint requested_speed)
+{
+ uint tmp_speed, highest_speed, n, m;
+ uint baud = 0x44; /* Baud rate after controller reset */
+
+ highest_speed = 0;
+ /* Successively try m, n combinations, and use the combination
+ * resulting in the largest speed that's not above the requested
+ * speed */
+ for (n = 0; n < 8; n++) {
+ for (m = 0; m < 16; m++) {
+ tmp_speed = twsi_calc_freq(n, m);
+ if ((tmp_speed <= requested_speed) &&
+ (tmp_speed > highest_speed)) {
+ highest_speed = tmp_speed;
+ baud = (m << 3) | n;
+ }
+ }
+ }
+ writel(baud, &twsi->baudrate);
+
+ /* Wait for controller for one tick */
+#if CONFIG_IS_ENABLED(DM_I2C)
+ ndelay(calc_tick(highest_speed));
+#else
+ ndelay(10000);
+#endif
+ return highest_speed;
+}
+
+/*
+ * __twsi_i2c_init() - Initialize the I2C controller.
+ *
+ * @twsi: The MVTWSI register structure to use.
+ * @speed: The initial frequency the controller should run at
+ * in Hz.
+ * @slaveadd: The I2C address to be set for the I2C master.
+ * @actual_speed: A output parameter that receives the actual frequency
+ * in Hz the controller was set to by the function.
+ * @return Zero if the operation succeeded, or a non-zero code if a time out
+ * occurred.
+ */
+static void __twsi_i2c_init(struct mvtwsi_registers *twsi, int speed,
+ int slaveadd, uint *actual_speed)
+{
+ uint tmp_speed;
+
+ /* Reset controller */
+ twsi_reset(twsi);
+ /* Set speed */
+ tmp_speed = __twsi_i2c_set_bus_speed(twsi, speed);
+ if (actual_speed)
+ *actual_speed = tmp_speed;
+ /* Set slave address; even though we don't use it */
+ writel(slaveadd, &twsi->slave_address);
+ writel(0, &twsi->xtnd_slave_addr);
+ /* Assert STOP, but don't care for the result */
+#if CONFIG_IS_ENABLED(DM_I2C)
+ (void) twsi_stop(twsi, calc_tick(*actual_speed));
+#else
+ (void) twsi_stop(twsi, 10000);
+#endif
+}
+
+/*
+ * i2c_begin() - Start a I2C transaction.
+ *
+ * Begin a I2C transaction with a given expected start status and chip address.
+ * A START is asserted, and the address byte is sent to the I2C controller. The
+ * expected address status will be derived from the direction bit (bit 0) of
+ * the address byte.
+ *
+ * @twsi: The MVTWSI register structure to use.
+ * @expected_start_status: The I2C status the controller is expected to
+ * assert after the address byte was sent.
+ * @addr: The address byte to be sent.
+ * @tick: The duration of a clock cycle at the current
+ * I2C speed.
+ * @return Zero if the operation succeeded, or a non-zero code if a time out or
+ * unexpected I2C status occurred.
+ */
+static int i2c_begin(struct mvtwsi_registers *twsi, int expected_start_status,
+ u8 addr, uint tick)
+{
+ int status, expected_addr_status;
+
+ /* Compute the expected address status from the direction bit in
+ * the address byte */
+ if (addr & 1) /* Reading */
+ expected_addr_status = MVTWSI_STATUS_ADDR_R_ACK;
+ else /* Writing */
+ expected_addr_status = MVTWSI_STATUS_ADDR_W_ACK;
+ /* Assert START */
+ status = twsi_start(twsi, expected_start_status, tick);
+ /* Send out the address if the start went well */
+ if (status == 0)
+ status = twsi_send(twsi, addr, expected_addr_status, tick);
+ /* Return 0, or the status of the first failure */
+ return status;
+}
+
+/*
+ * __twsi_i2c_probe_chip() - Probe the given I2C chip address.
+ *
+ * This function begins a I2C read transaction, does a dummy read and NAKs; if
+ * the procedure succeeds, the chip is considered to be present.
+ *
+ * @twsi: The MVTWSI register structure to use.
+ * @chip: The chip address to probe.
+ * @tick: The duration of a clock cycle at the current I2C speed.
+ * @return Zero if the operation succeeded, or a non-zero code if a time out or
+ * unexpected I2C status occurred.
+ */
+static int __twsi_i2c_probe_chip(struct mvtwsi_registers *twsi, uchar chip,
+ uint tick)
+{
+ u8 dummy_byte;
+ int status;
+
+ /* Begin i2c read */
+ status = i2c_begin(twsi, MVTWSI_STATUS_START, (chip << 1) | 1, tick);
+ /* Dummy read was accepted: receive byte, but NAK it. */
+ if (status == 0)
+ status = twsi_recv(twsi, &dummy_byte, MVTWSI_READ_NAK, tick);
+ /* Stop transaction */
+ twsi_stop(twsi, tick);
+ /* Return 0, or the status of the first failure */
+ return status;
+}
+
+/*
+ * __twsi_i2c_read() - Read data from a I2C chip.
+ *
+ * This function begins a I2C write transaction, and transmits the address
+ * bytes; then begins a I2C read transaction, and receives the data bytes.
+ *
+ * NOTE: Some devices want a stop right before the second start, while some
+ * will choke if it is there. Since deciding this is not yet supported in
+ * higher level APIs, we need to make a decision here, and for the moment that
+ * will be a repeated start without a preceding stop.
+ *
+ * @twsi: The MVTWSI register structure to use.
+ * @chip: The chip address to read from.
+ * @addr: The address bytes to send.
+ * @alen: The length of the address bytes in bytes.
+ * @data: The buffer to receive the data read from the chip (has to have
+ * a size of at least 'length' bytes).
+ * @length: The amount of data to be read from the chip in bytes.
+ * @tick: The duration of a clock cycle at the current I2C speed.
+ * @return Zero if the operation succeeded, or a non-zero code if a time out or
+ * unexpected I2C status occurred.
+ */
+static int __twsi_i2c_read(struct mvtwsi_registers *twsi, uchar chip,
+ u8 *addr, int alen, uchar *data, int length,
+ uint tick)
+{
+ int status = 0;
+ int stop_status;
+ int expected_start = MVTWSI_STATUS_START;
+
+ if (alen > 0) {
+ /* Begin i2c write to send the address bytes */
+ status = i2c_begin(twsi, expected_start, (chip << 1), tick);
+ /* Send address bytes */
+ while ((status == 0) && alen--)
+ status = twsi_send(twsi, addr[alen],
+ MVTWSI_STATUS_DATA_W_ACK, tick);
+ /* Send repeated STARTs after the initial START */
+ expected_start = MVTWSI_STATUS_REPEATED_START;
+ }
+ /* Begin i2c read to receive data bytes */
+ if (status == 0)
+ status = i2c_begin(twsi, expected_start, (chip << 1) | 1, tick);
+ /* Receive actual data bytes; set NAK if we if we have nothing more to
+ * read */
+ while ((status == 0) && length--)
+ status = twsi_recv(twsi, data++,
+ length > 0 ?
+ MVTWSI_READ_ACK : MVTWSI_READ_NAK, tick);
+ /* Stop transaction */
+ stop_status = twsi_stop(twsi, tick);
+ /* Return 0, or the status of the first failure */
+ return status != 0 ? status : stop_status;
+}
+
+/*
+ * __twsi_i2c_write() - Send data to a I2C chip.
+ *
+ * This function begins a I2C write transaction, and transmits the address
+ * bytes; then begins a new I2C write transaction, and sends the data bytes.
+ *
+ * @twsi: The MVTWSI register structure to use.
+ * @chip: The chip address to read from.
+ * @addr: The address bytes to send.
+ * @alen: The length of the address bytes in bytes.
+ * @data: The buffer containing the data to be sent to the chip.
+ * @length: The length of data to be sent to the chip in bytes.
+ * @tick: The duration of a clock cycle at the current I2C speed.
+ * @return Zero if the operation succeeded, or a non-zero code if a time out or
+ * unexpected I2C status occurred.
+ */
+static int __twsi_i2c_write(struct mvtwsi_registers *twsi, uchar chip,
+ u8 *addr, int alen, uchar *data, int length,
+ uint tick)
+{
+ int status, stop_status;
+
+ /* Begin i2c write to send first the address bytes, then the
+ * data bytes */
+ status = i2c_begin(twsi, MVTWSI_STATUS_START, (chip << 1), tick);
+ /* Send address bytes */
+ while ((status == 0) && (alen-- > 0))
+ status = twsi_send(twsi, addr[alen], MVTWSI_STATUS_DATA_W_ACK,
+ tick);
+ /* Send data bytes */
+ while ((status == 0) && (length-- > 0))
+ status = twsi_send(twsi, *(data++), MVTWSI_STATUS_DATA_W_ACK,
+ tick);
+ /* Stop transaction */
+ stop_status = twsi_stop(twsi, tick);
+ /* Return 0, or the status of the first failure */
+ return status != 0 ? status : stop_status;
+}
+
+#if !CONFIG_IS_ENABLED(DM_I2C)
+static void twsi_i2c_init(struct i2c_adapter *adap, int speed,
+ int slaveadd)
+{
+ struct mvtwsi_registers *twsi = twsi_get_base(adap);
+ __twsi_i2c_init(twsi, speed, slaveadd, NULL);
+}
+
+static uint twsi_i2c_set_bus_speed(struct i2c_adapter *adap,
+ uint requested_speed)
+{
+ struct mvtwsi_registers *twsi = twsi_get_base(adap);
+ __twsi_i2c_set_bus_speed(twsi, requested_speed);
+ return 0;
+}
+
+static int twsi_i2c_probe(struct i2c_adapter *adap, uchar chip)
+{
+ struct mvtwsi_registers *twsi = twsi_get_base(adap);
+ return __twsi_i2c_probe_chip(twsi, chip, 10000);
+}
+
+static int twsi_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
+ int alen, uchar *data, int length)
+{
+ struct mvtwsi_registers *twsi = twsi_get_base(adap);
+ u8 addr_bytes[4];
+
+ addr_bytes[0] = (addr >> 0) & 0xFF;
+ addr_bytes[1] = (addr >> 8) & 0xFF;
+ addr_bytes[2] = (addr >> 16) & 0xFF;
+ addr_bytes[3] = (addr >> 24) & 0xFF;
+
+ return __twsi_i2c_read(twsi, chip, addr_bytes, alen, data, length,
+ 10000);
+}
+
+static int twsi_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
+ int alen, uchar *data, int length)
+{
+ struct mvtwsi_registers *twsi = twsi_get_base(adap);
+ u8 addr_bytes[4];
+
+ addr_bytes[0] = (addr >> 0) & 0xFF;
+ addr_bytes[1] = (addr >> 8) & 0xFF;
+ addr_bytes[2] = (addr >> 16) & 0xFF;
+ addr_bytes[3] = (addr >> 24) & 0xFF;
+
+ return __twsi_i2c_write(twsi, chip, addr_bytes, alen, data, length,
+ 10000);
+}
+
+#ifdef CONFIG_I2C_MVTWSI_BASE0
+U_BOOT_I2C_ADAP_COMPLETE(twsi0, twsi_i2c_init, twsi_i2c_probe,
+ twsi_i2c_read, twsi_i2c_write,
+ twsi_i2c_set_bus_speed,
+ CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 0)
+#endif
+#ifdef CONFIG_I2C_MVTWSI_BASE1
+U_BOOT_I2C_ADAP_COMPLETE(twsi1, twsi_i2c_init, twsi_i2c_probe,
+ twsi_i2c_read, twsi_i2c_write,
+ twsi_i2c_set_bus_speed,
+ CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 1)
+
+#endif
+#ifdef CONFIG_I2C_MVTWSI_BASE2
+U_BOOT_I2C_ADAP_COMPLETE(twsi2, twsi_i2c_init, twsi_i2c_probe,
+ twsi_i2c_read, twsi_i2c_write,
+ twsi_i2c_set_bus_speed,
+ CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 2)
+
+#endif
+#ifdef CONFIG_I2C_MVTWSI_BASE3
+U_BOOT_I2C_ADAP_COMPLETE(twsi3, twsi_i2c_init, twsi_i2c_probe,
+ twsi_i2c_read, twsi_i2c_write,
+ twsi_i2c_set_bus_speed,
+ CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 3)
+
+#endif
+#ifdef CONFIG_I2C_MVTWSI_BASE4
+U_BOOT_I2C_ADAP_COMPLETE(twsi4, twsi_i2c_init, twsi_i2c_probe,
+ twsi_i2c_read, twsi_i2c_write,
+ twsi_i2c_set_bus_speed,
+ CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 4)
+
+#endif
+#ifdef CONFIG_I2C_MVTWSI_BASE5
+U_BOOT_I2C_ADAP_COMPLETE(twsi5, twsi_i2c_init, twsi_i2c_probe,
+ twsi_i2c_read, twsi_i2c_write,
+ twsi_i2c_set_bus_speed,
+ CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 5)
+
+#endif
+#else /* CONFIG_DM_I2C */
+
+static int mvtwsi_i2c_probe_chip(struct udevice *bus, u32 chip_addr,
+ u32 chip_flags)
+{
+ struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
+ return __twsi_i2c_probe_chip(dev->base, chip_addr, dev->tick);
+}
+
+static int mvtwsi_i2c_set_bus_speed(struct udevice *bus, uint speed)
+{
+ struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
+
+ dev->speed = __twsi_i2c_set_bus_speed(dev->base, speed);
+ dev->tick = calc_tick(dev->speed);
+
+ return 0;
+}
+
+static int mvtwsi_i2c_of_to_plat(struct udevice *bus)
+{
+ struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
+
+ dev->base = dev_read_addr_ptr(bus);
+
+ if (!dev->base)
+ return -ENOMEM;
+
+ dev->index = fdtdec_get_int(gd->fdt_blob, dev_of_offset(bus),
+ "cell-index", -1);
+ dev->slaveadd = fdtdec_get_int(gd->fdt_blob, dev_of_offset(bus),
+ "u-boot,i2c-slave-addr", 0x0);
+ dev->speed = dev_read_u32_default(bus, "clock-frequency",
+ I2C_SPEED_STANDARD_RATE);
+
+ return 0;
+}
+
+static void twsi_disable_i2c_slave(struct mvtwsi_registers *twsi)
+{
+ clrbits_le32(&twsi->debug, BIT(18));
+}
+
+static int mvtwsi_i2c_bind(struct udevice *bus)
+{
+ struct mvtwsi_registers *twsi = dev_read_addr_ptr(bus);
+
+ /* Disable the hidden slave in i2c0 of these platforms */
+ if ((IS_ENABLED(CONFIG_ARMADA_38X) ||
+ IS_ENABLED(CONFIG_ARCH_KIRKWOOD) ||
+ IS_ENABLED(CONFIG_ARMADA_8K)) && !dev_seq(bus))
+ twsi_disable_i2c_slave(twsi);
+
+ return 0;
+}
+
+static int mvtwsi_i2c_probe(struct udevice *bus)
+{
+ struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
+ uint actual_speed;
+
+ __twsi_i2c_init(dev->base, dev->speed, dev->slaveadd, &actual_speed);
+ dev->speed = actual_speed;
+ dev->tick = calc_tick(dev->speed);
+ return 0;
+}
+
+static int mvtwsi_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
+{
+ struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
+ struct i2c_msg *dmsg, *omsg, dummy;
+
+ memset(&dummy, 0, sizeof(struct i2c_msg));
+
+ /* We expect either two messages (one with an offset and one with the
+ * actual data) or one message (just data or offset/data combined) */
+ if (nmsgs > 2 || nmsgs == 0) {
+ debug("%s: Only one or two messages are supported.", __func__);
+ return -1;
+ }
+
+ omsg = nmsgs == 1 ? &dummy : msg;
+ dmsg = nmsgs == 1 ? msg : msg + 1;
+
+ if (dmsg->flags & I2C_M_RD)
+ return __twsi_i2c_read(dev->base, dmsg->addr, omsg->buf,
+ omsg->len, dmsg->buf, dmsg->len,
+ dev->tick);
+ else
+ return __twsi_i2c_write(dev->base, dmsg->addr, omsg->buf,
+ omsg->len, dmsg->buf, dmsg->len,
+ dev->tick);
+}
+
+static const struct dm_i2c_ops mvtwsi_i2c_ops = {
+ .xfer = mvtwsi_i2c_xfer,
+ .probe_chip = mvtwsi_i2c_probe_chip,
+ .set_bus_speed = mvtwsi_i2c_set_bus_speed,
+};
+
+static const struct udevice_id mvtwsi_i2c_ids[] = {
+ { .compatible = "marvell,mv64xxx-i2c", },
+ { .compatible = "marvell,mv78230-i2c", },
+ { .compatible = "allwinner,sun6i-a31-i2c", },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(i2c_mvtwsi) = {
+ .name = "i2c_mvtwsi",
+ .id = UCLASS_I2C,
+ .of_match = mvtwsi_i2c_ids,
+ .bind = mvtwsi_i2c_bind,
+ .probe = mvtwsi_i2c_probe,
+ .of_to_plat = mvtwsi_i2c_of_to_plat,
+ .priv_auto = sizeof(struct mvtwsi_i2c_dev),
+ .ops = &mvtwsi_i2c_ops,
+};
+#endif /* CONFIG_DM_I2C */
diff --git a/roms/u-boot/drivers/i2c/mxc_i2c.c b/roms/u-boot/drivers/i2c/mxc_i2c.c
new file mode 100644
index 000000000..003aa33f6
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/mxc_i2c.c
@@ -0,0 +1,1080 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * i2c driver for Freescale i.MX series
+ *
+ * (c) 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
+ * (c) 2011 Marek Vasut <marek.vasut@gmail.com>
+ * Copyright 2020 NXP
+ *
+ * Based on i2c-imx.c from linux kernel:
+ * Copyright (C) 2005 Torsten Koschorrek <koschorrek at synertronixx.de>
+ * Copyright (C) 2005 Matthias Blaschke <blaschke at synertronixx.de>
+ * Copyright (C) 2007 RightHand Technologies, Inc.
+ * Copyright (C) 2008 Darius Augulis <darius.augulis at teltonika.lt>
+ *
+ */
+
+#include <common.h>
+#include <log.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/imx-regs.h>
+#include <asm/global_data.h>
+#include <dm/device_compat.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <asm/mach-imx/mxc_i2c.h>
+#include <asm/mach-imx/sys_proto.h>
+#include <asm/io.h>
+#include <i2c.h>
+#include <watchdog.h>
+#include <dm.h>
+#include <dm/pinctrl.h>
+#include <fdtdec.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define I2C_QUIRK_FLAG (1 << 0)
+
+#define IMX_I2C_REGSHIFT 2
+#define VF610_I2C_REGSHIFT 0
+
+#define I2C_EARLY_INIT_INDEX 0
+#ifdef CONFIG_SYS_I2C_IFDR_DIV
+#define I2C_IFDR_DIV_CONSERVATIVE CONFIG_SYS_I2C_IFDR_DIV
+#else
+#define I2C_IFDR_DIV_CONSERVATIVE 0x7e
+#endif
+
+/* Register index */
+#define IADR 0
+#define IFDR 1
+#define I2CR 2
+#define I2SR 3
+#define I2DR 4
+
+#define I2CR_IIEN (1 << 6)
+#define I2CR_MSTA (1 << 5)
+#define I2CR_MTX (1 << 4)
+#define I2CR_TX_NO_AK (1 << 3)
+#define I2CR_RSTA (1 << 2)
+
+#define I2SR_ICF (1 << 7)
+#define I2SR_IBB (1 << 5)
+#define I2SR_IAL (1 << 4)
+#define I2SR_IIF (1 << 1)
+#define I2SR_RX_NO_AK (1 << 0)
+
+#ifdef I2C_QUIRK_REG
+#define I2CR_IEN (0 << 7)
+#define I2CR_IDIS (1 << 7)
+#define I2SR_IIF_CLEAR (1 << 1)
+#else
+#define I2CR_IEN (1 << 7)
+#define I2CR_IDIS (0 << 7)
+#define I2SR_IIF_CLEAR (0 << 1)
+#endif
+
+#ifdef I2C_QUIRK_REG
+static u16 i2c_clk_div[60][2] = {
+ { 20, 0x00 }, { 22, 0x01 }, { 24, 0x02 }, { 26, 0x03 },
+ { 28, 0x04 }, { 30, 0x05 }, { 32, 0x09 }, { 34, 0x06 },
+ { 36, 0x0A }, { 40, 0x07 }, { 44, 0x0C }, { 48, 0x0D },
+ { 52, 0x43 }, { 56, 0x0E }, { 60, 0x45 }, { 64, 0x12 },
+ { 68, 0x0F }, { 72, 0x13 }, { 80, 0x14 }, { 88, 0x15 },
+ { 96, 0x19 }, { 104, 0x16 }, { 112, 0x1A }, { 128, 0x17 },
+ { 136, 0x4F }, { 144, 0x1C }, { 160, 0x1D }, { 176, 0x55 },
+ { 192, 0x1E }, { 208, 0x56 }, { 224, 0x22 }, { 228, 0x24 },
+ { 240, 0x1F }, { 256, 0x23 }, { 288, 0x5C }, { 320, 0x25 },
+ { 384, 0x26 }, { 448, 0x2A }, { 480, 0x27 }, { 512, 0x2B },
+ { 576, 0x2C }, { 640, 0x2D }, { 768, 0x31 }, { 896, 0x32 },
+ { 960, 0x2F }, { 1024, 0x33 }, { 1152, 0x34 }, { 1280, 0x35 },
+ { 1536, 0x36 }, { 1792, 0x3A }, { 1920, 0x37 }, { 2048, 0x3B },
+ { 2304, 0x3C }, { 2560, 0x3D }, { 3072, 0x3E }, { 3584, 0x7A },
+ { 3840, 0x3F }, { 4096, 0x7B }, { 5120, 0x7D }, { 6144, 0x7E },
+};
+#else
+static u16 i2c_clk_div[50][2] = {
+ { 22, 0x20 }, { 24, 0x21 }, { 26, 0x22 }, { 28, 0x23 },
+ { 30, 0x00 }, { 32, 0x24 }, { 36, 0x25 }, { 40, 0x26 },
+ { 42, 0x03 }, { 44, 0x27 }, { 48, 0x28 }, { 52, 0x05 },
+ { 56, 0x29 }, { 60, 0x06 }, { 64, 0x2A }, { 72, 0x2B },
+ { 80, 0x2C }, { 88, 0x09 }, { 96, 0x2D }, { 104, 0x0A },
+ { 112, 0x2E }, { 128, 0x2F }, { 144, 0x0C }, { 160, 0x30 },
+ { 192, 0x31 }, { 224, 0x32 }, { 240, 0x0F }, { 256, 0x33 },
+ { 288, 0x10 }, { 320, 0x34 }, { 384, 0x35 }, { 448, 0x36 },
+ { 480, 0x13 }, { 512, 0x37 }, { 576, 0x14 }, { 640, 0x38 },
+ { 768, 0x39 }, { 896, 0x3A }, { 960, 0x17 }, { 1024, 0x3B },
+ { 1152, 0x18 }, { 1280, 0x3C }, { 1536, 0x3D }, { 1792, 0x3E },
+ { 1920, 0x1B }, { 2048, 0x3F }, { 2304, 0x1C }, { 2560, 0x1D },
+ { 3072, 0x1E }, { 3840, 0x1F }
+};
+#endif
+
+#ifndef CONFIG_SYS_MXC_I2C1_SPEED
+#define CONFIG_SYS_MXC_I2C1_SPEED 100000
+#endif
+#ifndef CONFIG_SYS_MXC_I2C2_SPEED
+#define CONFIG_SYS_MXC_I2C2_SPEED 100000
+#endif
+#ifndef CONFIG_SYS_MXC_I2C3_SPEED
+#define CONFIG_SYS_MXC_I2C3_SPEED 100000
+#endif
+#ifndef CONFIG_SYS_MXC_I2C4_SPEED
+#define CONFIG_SYS_MXC_I2C4_SPEED 100000
+#endif
+
+#ifndef CONFIG_SYS_MXC_I2C1_SLAVE
+#define CONFIG_SYS_MXC_I2C1_SLAVE 0
+#endif
+#ifndef CONFIG_SYS_MXC_I2C2_SLAVE
+#define CONFIG_SYS_MXC_I2C2_SLAVE 0
+#endif
+#ifndef CONFIG_SYS_MXC_I2C3_SLAVE
+#define CONFIG_SYS_MXC_I2C3_SLAVE 0
+#endif
+#ifndef CONFIG_SYS_MXC_I2C4_SLAVE
+#define CONFIG_SYS_MXC_I2C4_SLAVE 0
+#endif
+
+/*
+ * Calculate and set proper clock divider
+ */
+static uint8_t i2c_imx_get_clk(struct mxc_i2c_bus *i2c_bus, unsigned int rate)
+{
+ unsigned int i2c_clk_rate;
+ unsigned int div;
+ u8 clk_div;
+
+#if defined(CONFIG_MX31)
+ struct clock_control_regs *sc_regs =
+ (struct clock_control_regs *)CCM_BASE;
+
+ /* start the required I2C clock */
+ writel(readl(&sc_regs->cgr0) | (3 << CONFIG_SYS_I2C_CLK_OFFSET),
+ &sc_regs->cgr0);
+#endif
+
+ /* Divider value calculation */
+#if CONFIG_IS_ENABLED(CLK)
+ i2c_clk_rate = clk_get_rate(&i2c_bus->per_clk);
+#else
+ i2c_clk_rate = mxc_get_clock(MXC_I2C_CLK);
+#endif
+
+ div = (i2c_clk_rate + rate - 1) / rate;
+ if (div < i2c_clk_div[0][0])
+ clk_div = 0;
+ else if (div > i2c_clk_div[ARRAY_SIZE(i2c_clk_div) - 1][0])
+ clk_div = ARRAY_SIZE(i2c_clk_div) - 1;
+ else
+ for (clk_div = 0; i2c_clk_div[clk_div][0] < div; clk_div++)
+ ;
+
+ /* Store divider value */
+ return clk_div;
+}
+
+/*
+ * Set I2C Bus speed
+ */
+static int bus_i2c_set_bus_speed(struct mxc_i2c_bus *i2c_bus, int speed)
+{
+ ulong base = i2c_bus->base;
+ bool quirk = i2c_bus->driver_data & I2C_QUIRK_FLAG ? true : false;
+ u8 clk_idx = i2c_imx_get_clk(i2c_bus, speed);
+ u8 idx = i2c_clk_div[clk_idx][1];
+ int reg_shift = quirk ? VF610_I2C_REGSHIFT : IMX_I2C_REGSHIFT;
+
+ if (!base)
+ return -EINVAL;
+
+ /* Store divider value */
+ writeb(idx, base + (IFDR << reg_shift));
+
+ /* Reset module */
+ writeb(I2CR_IDIS, base + (I2CR << reg_shift));
+ writeb(0, base + (I2SR << reg_shift));
+ return 0;
+}
+
+#define ST_BUS_IDLE (0 | (I2SR_IBB << 8))
+#define ST_BUS_BUSY (I2SR_IBB | (I2SR_IBB << 8))
+#define ST_IIF (I2SR_IIF | (I2SR_IIF << 8))
+
+static int wait_for_sr_state(struct mxc_i2c_bus *i2c_bus, unsigned state)
+{
+ unsigned sr;
+ ulong elapsed;
+ bool quirk = i2c_bus->driver_data & I2C_QUIRK_FLAG ? true : false;
+ int reg_shift = quirk ? VF610_I2C_REGSHIFT : IMX_I2C_REGSHIFT;
+ ulong base = i2c_bus->base;
+ ulong start_time = get_timer(0);
+ for (;;) {
+ sr = readb(base + (I2SR << reg_shift));
+ if (sr & I2SR_IAL) {
+ if (quirk)
+ writeb(sr | I2SR_IAL, base +
+ (I2SR << reg_shift));
+ else
+ writeb(sr & ~I2SR_IAL, base +
+ (I2SR << reg_shift));
+ printf("%s: Arbitration lost sr=%x cr=%x state=%x\n",
+ __func__, sr, readb(base + (I2CR << reg_shift)),
+ state);
+ return -ERESTART;
+ }
+ if ((sr & (state >> 8)) == (unsigned char)state)
+ return sr;
+ WATCHDOG_RESET();
+ elapsed = get_timer(start_time);
+ if (elapsed > (CONFIG_SYS_HZ / 10)) /* .1 seconds */
+ break;
+ }
+ printf("%s: failed sr=%x cr=%x state=%x\n", __func__,
+ sr, readb(base + (I2CR << reg_shift)), state);
+ return -ETIMEDOUT;
+}
+
+static int tx_byte(struct mxc_i2c_bus *i2c_bus, u8 byte)
+{
+ int ret;
+ int reg_shift = i2c_bus->driver_data & I2C_QUIRK_FLAG ?
+ VF610_I2C_REGSHIFT : IMX_I2C_REGSHIFT;
+ ulong base = i2c_bus->base;
+
+ writeb(I2SR_IIF_CLEAR, base + (I2SR << reg_shift));
+ writeb(byte, base + (I2DR << reg_shift));
+
+ ret = wait_for_sr_state(i2c_bus, ST_IIF);
+ if (ret < 0)
+ return ret;
+ if (ret & I2SR_RX_NO_AK)
+ return -EREMOTEIO;
+ return 0;
+}
+
+/*
+ * Stub implementations for outer i2c slave operations.
+ */
+void __i2c_force_reset_slave(void)
+{
+}
+void i2c_force_reset_slave(void)
+ __attribute__((weak, alias("__i2c_force_reset_slave")));
+
+/*
+ * Stop I2C transaction
+ */
+static void i2c_imx_stop(struct mxc_i2c_bus *i2c_bus)
+{
+ int ret;
+ int reg_shift = i2c_bus->driver_data & I2C_QUIRK_FLAG ?
+ VF610_I2C_REGSHIFT : IMX_I2C_REGSHIFT;
+ ulong base = i2c_bus->base;
+ unsigned int temp = readb(base + (I2CR << reg_shift));
+
+ temp &= ~(I2CR_MSTA | I2CR_MTX);
+ writeb(temp, base + (I2CR << reg_shift));
+ ret = wait_for_sr_state(i2c_bus, ST_BUS_IDLE);
+ if (ret < 0)
+ printf("%s:trigger stop failed\n", __func__);
+}
+
+/*
+ * Send start signal, chip address and
+ * write register address
+ */
+static int i2c_init_transfer_(struct mxc_i2c_bus *i2c_bus, u8 chip,
+ u32 addr, int alen)
+{
+ unsigned int temp;
+ int ret;
+ bool quirk = i2c_bus->driver_data & I2C_QUIRK_FLAG ? true : false;
+ ulong base = i2c_bus->base;
+ int reg_shift = quirk ? VF610_I2C_REGSHIFT : IMX_I2C_REGSHIFT;
+
+ /* Reset i2c slave */
+ i2c_force_reset_slave();
+
+ /* Enable I2C controller */
+ if (quirk)
+ ret = readb(base + (I2CR << reg_shift)) & I2CR_IDIS;
+ else
+ ret = !(readb(base + (I2CR << reg_shift)) & I2CR_IEN);
+
+ if (ret) {
+ writeb(I2CR_IEN, base + (I2CR << reg_shift));
+ /* Wait for controller to be stable */
+ udelay(50);
+ }
+
+ if (readb(base + (IADR << reg_shift)) == (chip << 1))
+ writeb((chip << 1) ^ 2, base + (IADR << reg_shift));
+ writeb(I2SR_IIF_CLEAR, base + (I2SR << reg_shift));
+ ret = wait_for_sr_state(i2c_bus, ST_BUS_IDLE);
+ if (ret < 0)
+ return ret;
+
+ /* Start I2C transaction */
+ temp = readb(base + (I2CR << reg_shift));
+ temp |= I2CR_MSTA;
+ writeb(temp, base + (I2CR << reg_shift));
+
+ ret = wait_for_sr_state(i2c_bus, ST_BUS_BUSY);
+ if (ret < 0)
+ return ret;
+
+ temp |= I2CR_MTX | I2CR_TX_NO_AK;
+ writeb(temp, base + (I2CR << reg_shift));
+
+ if (alen >= 0) {
+ /* write slave address */
+ ret = tx_byte(i2c_bus, chip << 1);
+ if (ret < 0)
+ return ret;
+
+ while (alen--) {
+ ret = tx_byte(i2c_bus, (addr >> (alen * 8)) & 0xff);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+#if !defined(I2C2_BASE_ADDR)
+#define I2C2_BASE_ADDR 0
+#endif
+
+#if !defined(I2C3_BASE_ADDR)
+#define I2C3_BASE_ADDR 0
+#endif
+
+#if !defined(I2C4_BASE_ADDR)
+#define I2C4_BASE_ADDR 0
+#endif
+
+#if !defined(I2C5_BASE_ADDR)
+#define I2C5_BASE_ADDR 0
+#endif
+
+#if !defined(I2C6_BASE_ADDR)
+#define I2C6_BASE_ADDR 0
+#endif
+
+#if !defined(I2C7_BASE_ADDR)
+#define I2C7_BASE_ADDR 0
+#endif
+
+#if !defined(I2C8_BASE_ADDR)
+#define I2C8_BASE_ADDR 0
+#endif
+
+static struct mxc_i2c_bus mxc_i2c_buses[] = {
+#if defined(CONFIG_ARCH_LS1021A) || defined(CONFIG_VF610) || \
+ defined(CONFIG_FSL_LAYERSCAPE)
+ { 0, I2C1_BASE_ADDR, I2C_QUIRK_FLAG },
+ { 1, I2C2_BASE_ADDR, I2C_QUIRK_FLAG },
+ { 2, I2C3_BASE_ADDR, I2C_QUIRK_FLAG },
+ { 3, I2C4_BASE_ADDR, I2C_QUIRK_FLAG },
+ { 4, I2C5_BASE_ADDR, I2C_QUIRK_FLAG },
+ { 5, I2C6_BASE_ADDR, I2C_QUIRK_FLAG },
+ { 6, I2C7_BASE_ADDR, I2C_QUIRK_FLAG },
+ { 7, I2C8_BASE_ADDR, I2C_QUIRK_FLAG },
+#else
+ { 0, I2C1_BASE_ADDR, 0 },
+ { 1, I2C2_BASE_ADDR, 0 },
+ { 2, I2C3_BASE_ADDR, 0 },
+ { 3, I2C4_BASE_ADDR, 0 },
+ { 4, I2C5_BASE_ADDR, 0 },
+ { 5, I2C6_BASE_ADDR, 0 },
+ { 6, I2C7_BASE_ADDR, 0 },
+ { 7, I2C8_BASE_ADDR, 0 },
+#endif
+};
+
+#if !CONFIG_IS_ENABLED(DM_I2C)
+int i2c_idle_bus(struct mxc_i2c_bus *i2c_bus)
+{
+ if (i2c_bus && i2c_bus->idle_bus_fn)
+ return i2c_bus->idle_bus_fn(i2c_bus->idle_bus_data);
+ return 0;
+}
+#else
+/*
+ * See Linux Documentation/devicetree/bindings/i2c/i2c-imx.txt
+ * "
+ * scl-gpios: specify the gpio related to SCL pin
+ * sda-gpios: specify the gpio related to SDA pin
+ * add pinctrl to configure i2c pins to gpio function for i2c
+ * bus recovery, call it "gpio" state
+ * "
+ *
+ * The i2c_idle_bus is an implementation following Linux Kernel.
+ */
+int i2c_idle_bus(struct mxc_i2c_bus *i2c_bus)
+{
+ struct udevice *bus = i2c_bus->bus;
+ struct dm_i2c_bus *i2c = dev_get_uclass_priv(bus);
+ struct gpio_desc *scl_gpio = &i2c_bus->scl_gpio;
+ struct gpio_desc *sda_gpio = &i2c_bus->sda_gpio;
+ int sda, scl, idle_sclks;
+ int i, ret = 0;
+ ulong elapsed, start_time;
+
+ if (pinctrl_select_state(bus, "gpio")) {
+ dev_dbg(bus, "Can not to switch to use gpio pinmux\n");
+ /*
+ * GPIO pinctrl for i2c force idle is not a must,
+ * but it is strongly recommended to be used.
+ * Because it can help you to recover from bad
+ * i2c bus state. Do not return failure, because
+ * it is not a must.
+ */
+ return 0;
+ }
+
+ dm_gpio_set_dir_flags(scl_gpio, GPIOD_IS_IN);
+ dm_gpio_set_dir_flags(sda_gpio, GPIOD_IS_IN);
+ scl = dm_gpio_get_value(scl_gpio);
+ sda = dm_gpio_get_value(sda_gpio);
+
+ if ((sda & scl) == 1)
+ goto exit; /* Bus is idle already */
+
+ /*
+ * In most cases it is just enough to generate 8 + 1 SCLK
+ * clocks to recover I2C slave device from 'stuck' state
+ * (when for example SW reset was performed, in the middle of
+ * I2C transmission).
+ *
+ * However, there are devices which send data in packets of
+ * N bytes (N > 1). In such case we do need N * 8 + 1 SCLK
+ * clocks.
+ */
+ idle_sclks = 8 + 1;
+
+ if (i2c->max_transaction_bytes > 0)
+ idle_sclks = i2c->max_transaction_bytes * 8 + 1;
+ /* Send high and low on the SCL line */
+ for (i = 0; i < idle_sclks; i++) {
+ dm_gpio_set_dir_flags(scl_gpio, GPIOD_IS_OUT);
+ dm_gpio_set_value(scl_gpio, 0);
+ udelay(50);
+ dm_gpio_set_dir_flags(scl_gpio, GPIOD_IS_IN);
+ udelay(50);
+ }
+ start_time = get_timer(0);
+ for (;;) {
+ dm_gpio_set_dir_flags(scl_gpio, GPIOD_IS_IN);
+ dm_gpio_set_dir_flags(sda_gpio, GPIOD_IS_IN);
+ scl = dm_gpio_get_value(scl_gpio);
+ sda = dm_gpio_get_value(sda_gpio);
+ if ((sda & scl) == 1)
+ break;
+ WATCHDOG_RESET();
+ elapsed = get_timer(start_time);
+ if (elapsed > (CONFIG_SYS_HZ / 5)) { /* .2 seconds */
+ ret = -EBUSY;
+ printf("%s: failed to clear bus, sda=%d scl=%d\n", __func__, sda, scl);
+ break;
+ }
+ }
+
+exit:
+ pinctrl_select_state(bus, "default");
+ return ret;
+}
+#endif
+/*
+ * Early init I2C for prepare read the clk through I2C.
+ */
+void i2c_early_init_f(void)
+{
+ ulong base = mxc_i2c_buses[I2C_EARLY_INIT_INDEX].base;
+ bool quirk = mxc_i2c_buses[I2C_EARLY_INIT_INDEX].driver_data
+ & I2C_QUIRK_FLAG ? true : false;
+ int reg_shift = quirk ? VF610_I2C_REGSHIFT : IMX_I2C_REGSHIFT;
+
+ /* Set I2C divider value */
+ writeb(I2C_IFDR_DIV_CONSERVATIVE, base + (IFDR << reg_shift));
+ /* Reset module */
+ writeb(I2CR_IDIS, base + (I2CR << reg_shift));
+ writeb(0, base + (I2SR << reg_shift));
+ /* Enable I2C */
+ writeb(I2CR_IEN, base + (I2CR << reg_shift));
+}
+
+static int i2c_init_transfer(struct mxc_i2c_bus *i2c_bus, u8 chip,
+ u32 addr, int alen)
+{
+ int retry;
+ int ret;
+ int reg_shift = i2c_bus->driver_data & I2C_QUIRK_FLAG ?
+ VF610_I2C_REGSHIFT : IMX_I2C_REGSHIFT;
+
+ if (!i2c_bus->base)
+ return -EINVAL;
+
+ for (retry = 0; retry < 3; retry++) {
+ ret = i2c_init_transfer_(i2c_bus, chip, addr, alen);
+ if (ret >= 0)
+ return 0;
+ i2c_imx_stop(i2c_bus);
+ if (ret == -EREMOTEIO)
+ return ret;
+
+ printf("%s: failed for chip 0x%x retry=%d\n", __func__, chip,
+ retry);
+ if (ret != -ERESTART)
+ /* Disable controller */
+ writeb(I2CR_IDIS, i2c_bus->base + (I2CR << reg_shift));
+ udelay(100);
+ if (i2c_idle_bus(i2c_bus) < 0)
+ break;
+ }
+ printf("%s: give up i2c_regs=0x%lx\n", __func__, i2c_bus->base);
+ return ret;
+}
+
+
+static int i2c_write_data(struct mxc_i2c_bus *i2c_bus, u8 chip, const u8 *buf,
+ int len)
+{
+ int i, ret = 0;
+
+ debug("i2c_write_data: chip=0x%x, len=0x%x\n", chip, len);
+ debug("write_data: ");
+ /* use rc for counter */
+ for (i = 0; i < len; ++i)
+ debug(" 0x%02x", buf[i]);
+ debug("\n");
+
+ for (i = 0; i < len; i++) {
+ ret = tx_byte(i2c_bus, buf[i]);
+ if (ret < 0) {
+ debug("i2c_write_data(): rc=%d\n", ret);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+/* Will generate a STOP after the last byte if "last" is true, i.e. this is the
+ * final message of a transaction. If not, it switches the bus back to TX mode
+ * and does not send a STOP, leaving the bus in a state where a repeated start
+ * and address can be sent for another message.
+ */
+static int i2c_read_data(struct mxc_i2c_bus *i2c_bus, uchar chip, uchar *buf,
+ int len, bool last)
+{
+ int ret;
+ unsigned int temp;
+ int i;
+ int reg_shift = i2c_bus->driver_data & I2C_QUIRK_FLAG ?
+ VF610_I2C_REGSHIFT : IMX_I2C_REGSHIFT;
+ ulong base = i2c_bus->base;
+
+ debug("i2c_read_data: chip=0x%x, len=0x%x\n", chip, len);
+
+ /* setup bus to read data */
+ temp = readb(base + (I2CR << reg_shift));
+ temp &= ~(I2CR_MTX | I2CR_TX_NO_AK);
+ if (len == 1)
+ temp |= I2CR_TX_NO_AK;
+ writeb(temp, base + (I2CR << reg_shift));
+ writeb(I2SR_IIF_CLEAR, base + (I2SR << reg_shift));
+ /* dummy read to clear ICF */
+ readb(base + (I2DR << reg_shift));
+
+ /* read data */
+ for (i = 0; i < len; i++) {
+ ret = wait_for_sr_state(i2c_bus, ST_IIF);
+ if (ret < 0) {
+ debug("i2c_read_data(): ret=%d\n", ret);
+ i2c_imx_stop(i2c_bus);
+ return ret;
+ }
+
+ if (i == (len - 1)) {
+ /* Final byte has already been received by master! When
+ * we read it from I2DR, the master will start another
+ * cycle. We must program it first to send a STOP or
+ * switch to TX to avoid this.
+ */
+ if (last) {
+ i2c_imx_stop(i2c_bus);
+ } else {
+ /* Final read, no stop, switch back to tx */
+ temp = readb(base + (I2CR << reg_shift));
+ temp |= I2CR_MTX | I2CR_TX_NO_AK;
+ writeb(temp, base + (I2CR << reg_shift));
+ }
+ } else if (i == (len - 2)) {
+ /* Master has already recevied penultimate byte. When
+ * we read it from I2DR, master will start RX of final
+ * byte. We must set TX_NO_AK now so it does not ACK
+ * that final byte.
+ */
+ temp = readb(base + (I2CR << reg_shift));
+ temp |= I2CR_TX_NO_AK;
+ writeb(temp, base + (I2CR << reg_shift));
+ }
+
+ writeb(I2SR_IIF_CLEAR, base + (I2SR << reg_shift));
+ buf[i] = readb(base + (I2DR << reg_shift));
+ }
+
+ /* reuse ret for counter*/
+ for (ret = 0; ret < len; ++ret)
+ debug(" 0x%02x", buf[ret]);
+ debug("\n");
+
+ /* It is not clear to me that this is necessary */
+ if (last)
+ i2c_imx_stop(i2c_bus);
+ return 0;
+}
+
+int __enable_i2c_clk(unsigned char enable, unsigned int i2c_num)
+{
+ return 1;
+}
+
+int enable_i2c_clk(unsigned char enable, unsigned int i2c_num)
+ __attribute__((weak, alias("__enable_i2c_clk")));
+
+#if !CONFIG_IS_ENABLED(DM_I2C)
+/*
+ * Read data from I2C device
+ *
+ * The transactions use the syntax defined in the Linux kernel I2C docs.
+ *
+ * If alen is > 0, then this function will send a transaction of the form:
+ * S Chip Wr [A] Addr [A] S Chip Rd [A] [data] A ... NA P
+ * This is a normal I2C register read: writing the register address, then doing
+ * a repeated start and reading the data.
+ *
+ * If alen == 0, then we get this transaction:
+ * S Chip Wr [A] S Chip Rd [A] [data] A ... NA P
+ * This is somewhat unusual, though valid, transaction. It addresses the chip
+ * in write mode, but doesn't actually write any register address or data, then
+ * does a repeated start and reads data.
+ *
+ * If alen < 0, then we get this transaction:
+ * S Chip Rd [A] [data] A ... NA P
+ * The chip is addressed in read mode and then data is read. No register
+ * address is written first. This is perfectly valid on most devices and
+ * required on some (usually those that don't act like an array of registers).
+ */
+static int bus_i2c_read(struct mxc_i2c_bus *i2c_bus, u8 chip, u32 addr,
+ int alen, u8 *buf, int len)
+{
+ int ret = 0;
+ u32 temp;
+ int reg_shift = i2c_bus->driver_data & I2C_QUIRK_FLAG ?
+ VF610_I2C_REGSHIFT : IMX_I2C_REGSHIFT;
+ ulong base = i2c_bus->base;
+
+ ret = i2c_init_transfer(i2c_bus, chip, addr, alen);
+ if (ret < 0)
+ return ret;
+
+ if (alen >= 0) {
+ temp = readb(base + (I2CR << reg_shift));
+ temp |= I2CR_RSTA;
+ writeb(temp, base + (I2CR << reg_shift));
+ }
+
+ ret = tx_byte(i2c_bus, (chip << 1) | 1);
+ if (ret < 0) {
+ i2c_imx_stop(i2c_bus);
+ return ret;
+ }
+
+ ret = i2c_read_data(i2c_bus, chip, buf, len, true);
+
+ i2c_imx_stop(i2c_bus);
+ return ret;
+}
+
+/*
+ * Write data to I2C device
+ *
+ * If alen > 0, we get this transaction:
+ * S Chip Wr [A] addr [A] data [A] ... [A] P
+ * An ordinary write register command.
+ *
+ * If alen == 0, then we get this:
+ * S Chip Wr [A] data [A] ... [A] P
+ * This is a simple I2C write.
+ *
+ * If alen < 0, then we get this:
+ * S data [A] ... [A] P
+ * This is most likely NOT something that should be used. It doesn't send the
+ * chip address first, so in effect, the first byte of data will be used as the
+ * address.
+ */
+static int bus_i2c_write(struct mxc_i2c_bus *i2c_bus, u8 chip, u32 addr,
+ int alen, const u8 *buf, int len)
+{
+ int ret = 0;
+
+ ret = i2c_init_transfer(i2c_bus, chip, addr, alen);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_write_data(i2c_bus, chip, buf, len);
+
+ i2c_imx_stop(i2c_bus);
+
+ return ret;
+}
+
+struct mxc_i2c_bus *i2c_get_base(struct i2c_adapter *adap)
+{
+ return &mxc_i2c_buses[adap->hwadapnr];
+}
+
+static int mxc_i2c_read(struct i2c_adapter *adap, uint8_t chip,
+ uint addr, int alen, uint8_t *buffer,
+ int len)
+{
+ return bus_i2c_read(i2c_get_base(adap), chip, addr, alen, buffer, len);
+}
+
+static int mxc_i2c_write(struct i2c_adapter *adap, uint8_t chip,
+ uint addr, int alen, uint8_t *buffer,
+ int len)
+{
+ return bus_i2c_write(i2c_get_base(adap), chip, addr, alen, buffer, len);
+}
+
+/*
+ * Test if a chip at a given address responds (probe the chip)
+ */
+static int mxc_i2c_probe(struct i2c_adapter *adap, uint8_t chip)
+{
+ return bus_i2c_write(i2c_get_base(adap), chip, 0, 0, NULL, 0);
+}
+
+void bus_i2c_init(int index, int speed, int unused,
+ int (*idle_bus_fn)(void *p), void *idle_bus_data)
+{
+ int ret;
+
+ if (index >= ARRAY_SIZE(mxc_i2c_buses)) {
+ debug("Error i2c index\n");
+ return;
+ }
+
+ if (CONFIG_IS_ENABLED(IMX_MODULE_FUSE)) {
+ if (i2c_fused((ulong)mxc_i2c_buses[index].base)) {
+ printf("SoC fuse indicates I2C@0x%lx is unavailable.\n",
+ (ulong)mxc_i2c_buses[index].base);
+ return;
+ }
+ }
+
+ /*
+ * Warning: Be careful to allow the assignment to a static
+ * variable here. This function could be called while U-Boot is
+ * still running in flash memory. So such assignment is equal
+ * to write data to flash without erasing.
+ */
+ if (idle_bus_fn)
+ mxc_i2c_buses[index].idle_bus_fn = idle_bus_fn;
+ if (idle_bus_data)
+ mxc_i2c_buses[index].idle_bus_data = idle_bus_data;
+
+ ret = enable_i2c_clk(1, index);
+ if (ret < 0) {
+ debug("I2C-%d clk fail to enable.\n", index);
+ return;
+ }
+
+ bus_i2c_set_bus_speed(&mxc_i2c_buses[index], speed);
+}
+
+
+
+/*
+ * Init I2C Bus
+ */
+static void mxc_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
+{
+ bus_i2c_init(adap->hwadapnr, speed, slaveaddr, NULL, NULL);
+}
+
+/*
+ * Set I2C Speed
+ */
+static u32 mxc_i2c_set_bus_speed(struct i2c_adapter *adap, uint speed)
+{
+ return bus_i2c_set_bus_speed(i2c_get_base(adap), speed);
+}
+
+/*
+ * Register mxc i2c adapters
+ */
+#ifdef CONFIG_SYS_I2C_MXC_I2C1
+U_BOOT_I2C_ADAP_COMPLETE(mxc0, mxc_i2c_init, mxc_i2c_probe,
+ mxc_i2c_read, mxc_i2c_write,
+ mxc_i2c_set_bus_speed,
+ CONFIG_SYS_MXC_I2C1_SPEED,
+ CONFIG_SYS_MXC_I2C1_SLAVE, 0)
+#endif
+
+#ifdef CONFIG_SYS_I2C_MXC_I2C2
+U_BOOT_I2C_ADAP_COMPLETE(mxc1, mxc_i2c_init, mxc_i2c_probe,
+ mxc_i2c_read, mxc_i2c_write,
+ mxc_i2c_set_bus_speed,
+ CONFIG_SYS_MXC_I2C2_SPEED,
+ CONFIG_SYS_MXC_I2C2_SLAVE, 1)
+#endif
+
+#ifdef CONFIG_SYS_I2C_MXC_I2C3
+U_BOOT_I2C_ADAP_COMPLETE(mxc2, mxc_i2c_init, mxc_i2c_probe,
+ mxc_i2c_read, mxc_i2c_write,
+ mxc_i2c_set_bus_speed,
+ CONFIG_SYS_MXC_I2C3_SPEED,
+ CONFIG_SYS_MXC_I2C3_SLAVE, 2)
+#endif
+
+#ifdef CONFIG_SYS_I2C_MXC_I2C4
+U_BOOT_I2C_ADAP_COMPLETE(mxc3, mxc_i2c_init, mxc_i2c_probe,
+ mxc_i2c_read, mxc_i2c_write,
+ mxc_i2c_set_bus_speed,
+ CONFIG_SYS_MXC_I2C4_SPEED,
+ CONFIG_SYS_MXC_I2C4_SLAVE, 3)
+#endif
+
+#ifdef CONFIG_SYS_I2C_MXC_I2C5
+U_BOOT_I2C_ADAP_COMPLETE(mxc4, mxc_i2c_init, mxc_i2c_probe,
+ mxc_i2c_read, mxc_i2c_write,
+ mxc_i2c_set_bus_speed,
+ CONFIG_SYS_MXC_I2C5_SPEED,
+ CONFIG_SYS_MXC_I2C5_SLAVE, 4)
+#endif
+
+#ifdef CONFIG_SYS_I2C_MXC_I2C6
+U_BOOT_I2C_ADAP_COMPLETE(mxc5, mxc_i2c_init, mxc_i2c_probe,
+ mxc_i2c_read, mxc_i2c_write,
+ mxc_i2c_set_bus_speed,
+ CONFIG_SYS_MXC_I2C6_SPEED,
+ CONFIG_SYS_MXC_I2C6_SLAVE, 5)
+#endif
+
+#ifdef CONFIG_SYS_I2C_MXC_I2C7
+U_BOOT_I2C_ADAP_COMPLETE(mxc6, mxc_i2c_init, mxc_i2c_probe,
+ mxc_i2c_read, mxc_i2c_write,
+ mxc_i2c_set_bus_speed,
+ CONFIG_SYS_MXC_I2C7_SPEED,
+ CONFIG_SYS_MXC_I2C7_SLAVE, 6)
+#endif
+
+#ifdef CONFIG_SYS_I2C_MXC_I2C8
+U_BOOT_I2C_ADAP_COMPLETE(mxc7, mxc_i2c_init, mxc_i2c_probe,
+ mxc_i2c_read, mxc_i2c_write,
+ mxc_i2c_set_bus_speed,
+ CONFIG_SYS_MXC_I2C8_SPEED,
+ CONFIG_SYS_MXC_I2C8_SLAVE, 7)
+#endif
+
+#else
+
+static int mxc_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
+{
+ struct mxc_i2c_bus *i2c_bus = dev_get_priv(bus);
+
+ return bus_i2c_set_bus_speed(i2c_bus, speed);
+}
+
+static int mxc_i2c_probe(struct udevice *bus)
+{
+ struct mxc_i2c_bus *i2c_bus = dev_get_priv(bus);
+ const void *fdt = gd->fdt_blob;
+ int node = dev_of_offset(bus);
+ fdt_addr_t addr;
+ int ret, ret2;
+
+ i2c_bus->driver_data = dev_get_driver_data(bus);
+
+ addr = dev_read_addr(bus);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ if (CONFIG_IS_ENABLED(IMX_MODULE_FUSE)) {
+ if (i2c_fused((ulong)addr)) {
+ printf("SoC fuse indicates I2C@0x%lx is unavailable.\n",
+ (ulong)addr);
+ return -ENODEV;
+ }
+ }
+
+ i2c_bus->base = addr;
+ i2c_bus->index = dev_seq(bus);
+ i2c_bus->bus = bus;
+
+ /* Enable clk */
+#if CONFIG_IS_ENABLED(CLK)
+ ret = clk_get_by_index(bus, 0, &i2c_bus->per_clk);
+ if (ret) {
+ printf("Failed to get i2c clk\n");
+ return ret;
+ }
+ ret = clk_enable(&i2c_bus->per_clk);
+ if (ret) {
+ printf("Failed to enable i2c clk\n");
+ return ret;
+ }
+#else
+ ret = enable_i2c_clk(1, dev_seq(bus));
+ if (ret < 0)
+ return ret;
+#endif
+
+ /*
+ * See Documentation/devicetree/bindings/i2c/i2c-imx.txt
+ * Use gpio to force bus idle when necessary.
+ */
+ ret = fdt_stringlist_search(fdt, node, "pinctrl-names", "gpio");
+ if (ret < 0) {
+ debug("i2c bus %d at 0x%2lx, no gpio pinctrl state.\n",
+ dev_seq(bus), i2c_bus->base);
+ } else {
+ ret = gpio_request_by_name_nodev(offset_to_ofnode(node),
+ "scl-gpios", 0, &i2c_bus->scl_gpio,
+ GPIOD_IS_OUT);
+ ret2 = gpio_request_by_name_nodev(offset_to_ofnode(node),
+ "sda-gpios", 0, &i2c_bus->sda_gpio,
+ GPIOD_IS_OUT);
+ if (!dm_gpio_is_valid(&i2c_bus->sda_gpio) ||
+ !dm_gpio_is_valid(&i2c_bus->scl_gpio) ||
+ ret || ret2) {
+ dev_err(bus,
+ "i2c bus %d at 0x%2lx, fail to request scl/sda gpio\n",
+ dev_seq(bus), i2c_bus->base);
+ return -EINVAL;
+ }
+ }
+
+ /*
+ * Pinmux settings are in board file now, until pinmux is supported,
+ * we can set pinmux here in probe function.
+ */
+
+ debug("i2c : controller bus %d at %lu , speed %d: ",
+ dev_seq(bus), i2c_bus->base,
+ i2c_bus->speed);
+
+ return 0;
+}
+
+/* Sends: S Addr Wr [A|NA] P */
+static int mxc_i2c_probe_chip(struct udevice *bus, u32 chip_addr,
+ u32 chip_flags)
+{
+ int ret;
+ struct mxc_i2c_bus *i2c_bus = dev_get_priv(bus);
+
+ ret = i2c_init_transfer(i2c_bus, chip_addr, 0, 0);
+ if (ret < 0) {
+ debug("%s failed, ret = %d\n", __func__, ret);
+ return ret;
+ }
+
+ i2c_imx_stop(i2c_bus);
+
+ return 0;
+}
+
+static int mxc_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
+{
+ struct mxc_i2c_bus *i2c_bus = dev_get_priv(bus);
+ int ret = 0;
+ ulong base = i2c_bus->base;
+ int reg_shift = i2c_bus->driver_data & I2C_QUIRK_FLAG ?
+ VF610_I2C_REGSHIFT : IMX_I2C_REGSHIFT;
+ int read_mode;
+
+ /* Here address len is set to -1 to not send any address at first.
+ * Otherwise i2c_init_transfer will send the chip address with write
+ * mode set. This is wrong if the 1st message is read.
+ */
+ ret = i2c_init_transfer(i2c_bus, msg->addr, 0, -1);
+ if (ret < 0) {
+ debug("i2c_init_transfer error: %d\n", ret);
+ return ret;
+ }
+
+ read_mode = -1; /* So it's always different on the first message */
+ for (; nmsgs > 0; nmsgs--, msg++) {
+ const int msg_is_read = !!(msg->flags & I2C_M_RD);
+
+ debug("i2c_xfer: chip=0x%x, len=0x%x, dir=%c\n", msg->addr,
+ msg->len, msg_is_read ? 'R' : 'W');
+
+ if (msg_is_read != read_mode) {
+ /* Send repeated start if not 1st message */
+ if (read_mode != -1) {
+ debug("i2c_xfer: [RSTART]\n");
+ ret = readb(base + (I2CR << reg_shift));
+ ret |= I2CR_RSTA;
+ writeb(ret, base + (I2CR << reg_shift));
+ }
+ debug("i2c_xfer: [ADDR %02x | %c]\n", msg->addr,
+ msg_is_read ? 'R' : 'W');
+ ret = tx_byte(i2c_bus, (msg->addr << 1) | msg_is_read);
+ if (ret < 0) {
+ debug("i2c_xfer: [STOP]\n");
+ i2c_imx_stop(i2c_bus);
+ break;
+ }
+ read_mode = msg_is_read;
+ }
+
+ if (msg->flags & I2C_M_RD)
+ ret = i2c_read_data(i2c_bus, msg->addr, msg->buf,
+ msg->len, nmsgs == 1 ||
+ (msg->flags & I2C_M_STOP));
+ else
+ ret = i2c_write_data(i2c_bus, msg->addr, msg->buf,
+ msg->len);
+
+ if (ret < 0)
+ break;
+ }
+
+ if (ret)
+ debug("i2c_write: error sending\n");
+
+ i2c_imx_stop(i2c_bus);
+
+ return ret;
+}
+
+static const struct dm_i2c_ops mxc_i2c_ops = {
+ .xfer = mxc_i2c_xfer,
+ .probe_chip = mxc_i2c_probe_chip,
+ .set_bus_speed = mxc_i2c_set_bus_speed,
+};
+
+static const struct udevice_id mxc_i2c_ids[] = {
+ { .compatible = "fsl,imx21-i2c", },
+ { .compatible = "fsl,vf610-i2c", .data = I2C_QUIRK_FLAG, },
+ {}
+};
+
+U_BOOT_DRIVER(i2c_mxc) = {
+ .name = "i2c_mxc",
+ .id = UCLASS_I2C,
+ .of_match = mxc_i2c_ids,
+ .probe = mxc_i2c_probe,
+ .priv_auto = sizeof(struct mxc_i2c_bus),
+ .ops = &mxc_i2c_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
+#endif
diff --git a/roms/u-boot/drivers/i2c/nx_i2c.c b/roms/u-boot/drivers/i2c/nx_i2c.c
new file mode 100644
index 000000000..07cda0fa6
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/nx_i2c.c
@@ -0,0 +1,627 @@
+#include <common.h>
+#include <errno.h>
+#include <dm.h>
+#include <i2c.h>
+#include <log.h>
+#include <asm/arch/nexell.h>
+#include <asm/arch/reset.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/nx_gpio.h>
+#include <asm/global_data.h>
+#include <linux/delay.h>
+
+#define I2C_WRITE 0
+#define I2C_READ 1
+
+#define I2CSTAT_MTM 0xC0 /* Master Transmit Mode */
+#define I2CSTAT_MRM 0x80 /* Master Receive Mode */
+#define I2CSTAT_BSY 0x20 /* Read: Bus Busy */
+#define I2CSTAT_SS 0x20 /* Write: START (1) / STOP (0) */
+#define I2CSTAT_RXTXEN 0x10 /* Rx/Tx enable */
+#define I2CSTAT_ABT 0x08 /* Arbitration bit */
+#define I2CSTAT_NACK 0x01 /* Nack bit */
+#define I2CCON_IRCLR 0x100 /* Interrupt Clear bit */
+#define I2CCON_ACKGEN 0x80 /* Acknowledge generation */
+#define I2CCON_TCP256 0x40 /* Tx-clock prescaler: 16 (0) / 256 (1) */
+#define I2CCON_IRENB 0x20 /* Interrupt Enable bit */
+#define I2CCON_IRPND 0x10 /* Interrupt pending bit */
+#define I2CCON_TCDMSK 0x0F /* I2C-bus transmit clock divider bit mask */
+
+#ifdef CONFIG_ARCH_S5P6818
+#define SDADLY_CLKSTEP 5 /* SDA delay: Reg. val. is multiple of 5 clks */
+#define SDADLY_MAX 3 /* SDA delay: Max. reg. value is 3 */
+#define I2CLC_FILTER 0x04 /* SDA filter on */
+#else
+#define STOPCON_CLR 0x01 /* Clock Line Release */
+#define STOPCON_DLR 0x02 /* Data Line Release */
+#define STOPCON_NAG 0x04 /* not-ackn. generation and data shift cont. */
+#endif
+
+#define I2C_TIMEOUT_MS 10 /* 10 ms */
+
+#define I2C_M_NOSTOP 0x100
+
+#define MAX_I2C_NUM 3
+
+#define DEFAULT_SPEED 100000 /* default I2C speed [Hz] */
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct nx_i2c_regs {
+ uint iiccon;
+ uint iicstat;
+ uint iicadd;
+ uint iicds;
+#ifdef CONFIG_ARCH_S5P6818
+ /* S5P6818: Offset 0x10 is Line Control Register (SDA-delay, Filter) */
+ uint iiclc;
+#else
+ /* S5P4418: Offset 0x10 is Stop Control Register */
+ uint iicstopcon;
+#endif
+};
+
+struct nx_i2c_bus {
+ uint bus_num;
+ struct nx_i2c_regs *regs;
+ uint speed;
+ uint target_speed;
+#ifdef CONFIG_ARCH_S5P6818
+ uint sda_delay;
+#else
+ /* setup time for Stop condition [us] */
+ uint tsu_stop;
+#endif
+};
+
+/* 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);
+}
+
+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) {
+ debug("%s(): clk_get(%s) error!\n",
+ __func__, (const char *)name);
+ return -EINVAL;
+ }
+
+ clk_disable(clk);
+ if (enb)
+ clk_enable(clk);
+
+ return 0;
+}
+
+#ifdef CONFIG_ARCH_S5P6818
+/* Set SDA line delay, not available at S5P4418 */
+static int nx_i2c_set_sda_delay(struct nx_i2c_bus *bus)
+{
+ struct nx_i2c_regs *i2c = bus->regs;
+ uint pclk = 0;
+ uint t_pclk = 0;
+ uint delay = 0;
+
+ /* get input clock of the I2C-controller */
+ pclk = i2c_get_clkrate(bus);
+
+ if (bus->sda_delay) {
+ /* t_pclk = period time of one pclk [ns] */
+ t_pclk = DIV_ROUND_UP(1000, pclk / 1000000);
+ /* delay = number of pclks required for sda_delay [ns] */
+ delay = DIV_ROUND_UP(bus->sda_delay, t_pclk);
+ /* delay = register value (step of 5 clocks) */
+ delay = DIV_ROUND_UP(delay, SDADLY_CLKSTEP);
+ /* max. possible register value = 3 */
+ if (delay > SDADLY_MAX) {
+ delay = SDADLY_MAX;
+ debug("%s(): sda-delay des.: %dns, sat. to max.: %dns (granularity: %dns)\n",
+ __func__, bus->sda_delay, t_pclk * delay * SDADLY_CLKSTEP,
+ t_pclk * SDADLY_CLKSTEP);
+ } else {
+ debug("%s(): sda-delay des.: %dns, act.: %dns (granularity: %dns)\n",
+ __func__, bus->sda_delay, t_pclk * delay * SDADLY_CLKSTEP,
+ t_pclk * SDADLY_CLKSTEP);
+ }
+
+ delay |= I2CLC_FILTER;
+ } else {
+ delay = 0;
+ debug("%s(): sda-delay = 0\n", __func__);
+ }
+
+ delay &= 0x7;
+ writel(delay, &i2c->iiclc);
+
+ return 0;
+}
+#endif
+
+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 pclk, pres = 16, div;
+
+ if (i2c_set_clk(bus, 1))
+ return -EINVAL;
+
+ /* get input clock of the I2C-controller */
+ pclk = i2c_get_clkrate(bus);
+
+ /* calculate prescaler and divisor values */
+ if ((pclk / pres / (16 + 1)) > speed)
+ /* prescaler value 16 is too less --> set to 256 */
+ pres = 256;
+
+ div = 0;
+ /* actual divider = div + 1 */
+ while ((pclk / pres / (div + 1)) > speed)
+ div++;
+
+ if (div > 0xF) {
+ debug("%s(): pres==%ld, div==0x%lx is saturated to 0xF !)\n",
+ __func__, pres, div);
+ div = 0xF;
+ } else {
+ debug("%s(): pres==%ld, div==0x%lx)\n", __func__, pres, div);
+ }
+
+ /* set Tx-clock divisor and prescaler values */
+ writel((div & I2CCON_TCDMSK) | ((pres == 256) ? I2CCON_TCP256 : 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(I2CSTAT_MTM | I2CSTAT_RXTXEN, &i2c->iicstat);
+
+ /* calculate actual I2C speed [Hz] */
+ bus->speed = pclk / ((div + 1) * pres);
+ debug("%s(): speed des.: %dHz, act.: %dHz\n",
+ __func__, speed, bus->speed);
+
+#ifdef CONFIG_ARCH_S5P6818
+ nx_i2c_set_sda_delay(bus);
+#else
+ /* setup time for Stop condition [us], min. 4us @ 100kHz I2C-clock */
+ bus->tsu_stop = DIV_ROUND_UP(400, bus->speed / 1000);
+#endif
+
+ if (i2c_set_clk(bus, 0))
+ return -EINVAL;
+ return 0;
+}
+
+static void i2c_process_node(struct udevice *dev)
+{
+ struct nx_i2c_bus *bus = dev_get_priv(dev);
+
+ bus->target_speed = dev_read_s32_default(dev, "clock-frequency",
+ DEFAULT_SPEED);
+#ifdef CONFIG_ARCH_S5P6818
+ bus->sda_delay = dev_read_s32_default(dev, "i2c-sda-delay-ns", 0);
+#endif
+}
+
+static int nx_i2c_probe(struct udevice *dev)
+{
+ struct nx_i2c_bus *bus = dev_get_priv(dev);
+ fdt_addr_t addr;
+
+ /* get regs = i2c base address */
+ addr = devfdt_get_addr(dev);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+ bus->regs = (struct nx_i2c_regs *)addr;
+
+ bus->bus_num = dev_seq(dev);
+
+ /* i2c node parsing */
+ i2c_process_node(dev);
+ if (!bus->target_speed)
+ return -ENODEV;
+
+ /* reset */
+ i2c_reset(bus->bus_num);
+
+ 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 -EBUSY;
+ }
+ }
+ 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)
+{
+ unsigned int reg;
+
+ reg = readl(&i2c->iiccon);
+ /* reset interrupt pending flag */
+ reg &= ~(I2CCON_IRPND);
+ /*
+ * Interrupt must also be cleared!
+ * Otherwise linux boot may hang after:
+ * [ 0.436000] NetLabel: unlabeled traffic allowed by default
+ * Next would be:
+ * [ 0.442000] clocksource: Switched to clocksource source timer
+ */
+ reg |= I2CCON_IRCLR;
+ writel(reg, &i2c->iiccon);
+}
+
+/* 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_bus *bus)
+{
+ struct nx_i2c_regs *i2c = bus->regs;
+
+ if (IS_ENABLED(CONFIG_ARCH_S5P6818)) {
+ unsigned int reg;
+
+ reg = readl(&i2c->iicstat);
+ reg |= I2CSTAT_MRM | I2CSTAT_RXTXEN;
+ reg &= (~I2CSTAT_SS);
+
+ writel(reg, &i2c->iicstat);
+ i2c_clear_irq(i2c);
+ } else { /* S5P4418 */
+ writel(STOPCON_NAG, &i2c->iicstopcon);
+
+ i2c_clear_irq(i2c);
+
+ /*
+ * Clock Line Release --> SDC changes from Low to High and
+ * SDA from High to Low
+ */
+ writel(STOPCON_CLR, &i2c->iicstopcon);
+
+ /* Hold SDA Low (Setup Time for Stop condition) */
+ udelay(bus->tsu_stop);
+
+ i2c_clear_irq(i2c);
+
+ /* Master Receive Mode Stop --> SDA becomes High */
+ writel(I2CSTAT_MRM, &i2c->iicstat);
+ }
+}
+
+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 -EREMOTEIO if not Acknowledged, otherwise 0 */
+ return (readl(&i2c->iicstat) & I2CSTAT_NACK) ?
+ -EREMOTEIO : 0;
+ } while (get_timer(start_time) < I2C_TIMEOUT_MS);
+
+ return -ETIMEDOUT;
+}
+
+static int i2c_transfer(struct nx_i2c_regs *i2c,
+ uchar cmd_type,
+ uchar chip_addr,
+ uchar addr[],
+ uchar addr_len,
+ uchar data[],
+ unsigned short data_len,
+ uint seq)
+{
+ uint status;
+ int i = 0, result;
+
+ /* Note: data_len = 0 is supported for "probe_chip" */
+
+ i2c_enable_irq(i2c);
+ i2c_enable_ack(i2c);
+
+ /* Get the slave chip address going */
+ /* Enable Rx/Tx */
+ writel(I2CSTAT_RXTXEN, &i2c->iicstat);
+
+ writel(chip_addr, &i2c->iicds);
+ status = I2CSTAT_RXTXEN | I2CSTAT_SS;
+ if (cmd_type == I2C_WRITE || (addr && addr_len))
+ status |= I2CSTAT_MTM;
+ else
+ status |= I2CSTAT_MRM;
+
+ writel(status, &i2c->iicstat);
+ if (seq)
+ i2c_clear_irq(i2c);
+
+ /* Wait for chip address to transmit. */
+ result = wait_for_xfer(i2c);
+ if (result) {
+ debug("%s: transmitting chip address failed\n", __func__);
+ goto bailout;
+ }
+
+ /* If register address needs to be transmitted - do it now. */
+ if (addr && addr_len) { /* register addr */
+ while ((i < addr_len) && !result) {
+ writel(addr[i++], &i2c->iicds);
+ i2c_clear_irq(i2c);
+ result = wait_for_xfer(i2c);
+ }
+
+ i = 0;
+ if (result) {
+ debug("%s: transmitting register address failed\n",
+ __func__);
+ goto bailout;
+ }
+ }
+
+ switch (cmd_type) {
+ case I2C_WRITE:
+ while ((i < data_len) && !result) {
+ 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_addr, &i2c->iicds);
+
+ /* Generate a re-START. */
+ writel(I2CSTAT_MRM | I2CSTAT_RXTXEN |
+ I2CSTAT_SS, &i2c->iicstat);
+ i2c_clear_irq(i2c);
+ result = wait_for_xfer(i2c);
+ if (result) {
+ debug("%s: I2C_READ: sending chip addr. failed\n",
+ __func__);
+ goto bailout;
+ }
+ }
+
+ while ((i < data_len) && !result) {
+ /* 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 == -EREMOTEIO)
+ /* Not Acknowledged --> normal terminated read. */
+ result = 0;
+ else if (result == -ETIMEDOUT)
+ debug("%s: I2C_READ: time out\n", __func__);
+ else
+ debug("%s: I2C_READ: read not terminated with NACK\n",
+ __func__);
+ break;
+
+ default:
+ debug("%s: bad call\n", __func__);
+ result = -EINVAL;
+ break;
+ }
+
+bailout:
+ return result;
+}
+
+static int nx_i2c_read(struct udevice *dev, uchar chip_addr, 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_addr << 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_addr, 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_addr << 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. */
+ ret = i2c_set_clk(bus, 1);
+
+ if (!ret)
+ /* Bus State(Busy) check */
+ ret = i2c_is_busy(i2c);
+ if (!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");
+ ret = -EREMOTEIO;
+ }
+ }
+
+ i2c_send_stop(bus);
+ if (i2c_set_clk(bus, 0))
+ ret = -EINVAL;
+ }
+
+ return ret;
+};
+
+static int nx_i2c_probe_chip(struct udevice *dev, u32 chip_addr,
+ u32 chip_flags)
+{
+ int ret;
+ struct nx_i2c_bus *bus = dev_get_priv(dev);
+
+ ret = i2c_set_clk(bus, 1);
+
+ if (!ret) {
+ /*
+ * Send Chip Address only
+ * --> I2C transfer with data length and address length = 0.
+ * If there is a Slave, i2c_transfer() returns 0 (acknowledge
+ * transfer).
+ * I2C_WRITE must be used in order Master Transmit Mode is
+ * selected. Otherwise (in Master Receive Mode, I2C_READ)
+ * sending the stop condition below is not working (SDA does
+ * not transit to High).
+ */
+ ret = i2c_transfer(bus->regs, I2C_WRITE, (uchar)chip_addr << 1,
+ NULL, 0, NULL, 0, 0);
+
+ i2c_send_stop(bus);
+ if (i2c_set_clk(bus, 0))
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static const struct dm_i2c_ops nx_i2c_ops = {
+ .xfer = nx_i2c_xfer,
+ .probe_chip = nx_i2c_probe_chip,
+ .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 = sizeof(struct nx_i2c_bus),
+ .ops = &nx_i2c_ops,
+};
diff --git a/roms/u-boot/drivers/i2c/ocores_i2c.c b/roms/u-boot/drivers/i2c/ocores_i2c.c
new file mode 100644
index 000000000..088ba9a6a
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/ocores_i2c.c
@@ -0,0 +1,638 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * ocores-i2c.c: I2C bus driver for OpenCores I2C controller
+ * (https://opencores.org/projects/i2c)
+ *
+ * (C) Copyright Peter Korsgaard <peter@korsgaard.com>
+ *
+ * Copyright (C) 2020 SiFive, Inc.
+ * Pragnesh Patel <pragnesh.patel@sifive.com>
+ *
+ * Support for the GRLIB port of the controller by
+ * Andreas Larsson <andreas@gaisler.com>
+ */
+
+#include <common.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <clk.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <i2c.h>
+#include <linux/io.h>
+#include <linux/compat.h>
+#include <linux/log2.h>
+#include <linux/delay.h>
+
+/* registers */
+#define OCI2C_PRELOW 0
+#define OCI2C_PREHIGH 1
+#define OCI2C_CONTROL 2
+#define OCI2C_DATA 3
+#define OCI2C_CMD 4 /* write only */
+#define OCI2C_STATUS 4 /* read only, same address as OCI2C_CMD */
+
+#define OCI2C_CTRL_IEN 0x40
+#define OCI2C_CTRL_EN 0x80
+
+#define OCI2C_CMD_START 0x91
+#define OCI2C_CMD_STOP 0x41
+#define OCI2C_CMD_READ 0x21
+#define OCI2C_CMD_WRITE 0x11
+#define OCI2C_CMD_READ_ACK 0x21
+#define OCI2C_CMD_READ_NACK 0x29
+#define OCI2C_CMD_IACK 0x01
+
+#define OCI2C_STAT_IF 0x01
+#define OCI2C_STAT_TIP 0x02
+#define OCI2C_STAT_ARBLOST 0x20
+#define OCI2C_STAT_BUSY 0x40
+#define OCI2C_STAT_NACK 0x80
+
+#define STATE_DONE 0
+#define STATE_START 1
+#define STATE_WRITE 2
+#define STATE_READ 3
+#define STATE_ERROR 4
+
+#define TYPE_OCORES 0
+#define TYPE_GRLIB 1
+
+#define OCORES_FLAG_BROKEN_IRQ BIT(1) /* Broken IRQ for FU540-C000 SoC */
+
+struct ocores_i2c_bus {
+ void __iomem *base;
+ u32 reg_shift;
+ u32 reg_io_width;
+ unsigned long flags;
+ struct i2c_msg *msg;
+ int pos;
+ int nmsgs;
+ int state; /* see STATE_ */
+ struct clk clk;
+ int ip_clk_khz;
+ int bus_clk_khz;
+ void (*setreg)(struct ocores_i2c_bus *i2c, int reg, u8 value);
+ u8 (*getreg)(struct ocores_i2c_bus *i2c, int reg);
+};
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Boolean attribute values */
+enum {
+ FALSE = 0,
+ TRUE,
+};
+
+static void oc_setreg_8(struct ocores_i2c_bus *i2c, int reg, u8 value)
+{
+ writeb(value, i2c->base + (reg << i2c->reg_shift));
+}
+
+static void oc_setreg_16(struct ocores_i2c_bus *i2c, int reg, u8 value)
+{
+ writew(value, i2c->base + (reg << i2c->reg_shift));
+}
+
+static void oc_setreg_32(struct ocores_i2c_bus *i2c, int reg, u8 value)
+{
+ writel(value, i2c->base + (reg << i2c->reg_shift));
+}
+
+static void oc_setreg_16be(struct ocores_i2c_bus *i2c, int reg, u8 value)
+{
+ out_be16(i2c->base + (reg << i2c->reg_shift), value);
+}
+
+static void oc_setreg_32be(struct ocores_i2c_bus *i2c, int reg, u8 value)
+{
+ out_be32(i2c->base + (reg << i2c->reg_shift), value);
+}
+
+static inline u8 oc_getreg_8(struct ocores_i2c_bus *i2c, int reg)
+{
+ return readb(i2c->base + (reg << i2c->reg_shift));
+}
+
+static inline u8 oc_getreg_16(struct ocores_i2c_bus *i2c, int reg)
+{
+ return readw(i2c->base + (reg << i2c->reg_shift));
+}
+
+static inline u8 oc_getreg_32(struct ocores_i2c_bus *i2c, int reg)
+{
+ return readl(i2c->base + (reg << i2c->reg_shift));
+}
+
+static inline u8 oc_getreg_16be(struct ocores_i2c_bus *i2c, int reg)
+{
+ return in_be16(i2c->base + (reg << i2c->reg_shift));
+}
+
+static inline u8 oc_getreg_32be(struct ocores_i2c_bus *i2c, int reg)
+{
+ return in_be32(i2c->base + (reg << i2c->reg_shift));
+}
+
+static inline void oc_setreg(struct ocores_i2c_bus *i2c, int reg, u8 value)
+{
+ i2c->setreg(i2c, reg, value);
+}
+
+static inline u8 oc_getreg(struct ocores_i2c_bus *i2c, int reg)
+{
+ return i2c->getreg(i2c, reg);
+}
+
+static inline u8 i2c_8bit_addr_from_msg(const struct i2c_msg *msg)
+{
+ return (msg->addr << 1) | (msg->flags & I2C_M_RD ? 1 : 0);
+}
+
+static void ocores_process(struct ocores_i2c_bus *i2c, u8 stat)
+{
+ struct i2c_msg *msg = i2c->msg;
+
+ if (i2c->state == STATE_DONE || i2c->state == STATE_ERROR) {
+ /* stop has been sent */
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK);
+ return;
+ }
+
+ /* error? */
+ if (stat & OCI2C_STAT_ARBLOST) {
+ i2c->state = STATE_ERROR;
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
+ return;
+ }
+
+ if (i2c->state == STATE_START || i2c->state == STATE_WRITE) {
+ i2c->state =
+ (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE;
+
+ if (stat & OCI2C_STAT_NACK) {
+ i2c->state = STATE_ERROR;
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
+ return;
+ }
+ } else {
+ msg->buf[i2c->pos++] = oc_getreg(i2c, OCI2C_DATA);
+ }
+
+ /* end of msg? */
+ if (i2c->pos == msg->len) {
+ i2c->nmsgs--;
+ i2c->msg++;
+ i2c->pos = 0;
+ msg = i2c->msg;
+
+ if (i2c->nmsgs) { /* end? */
+ /* send start? */
+ if (!(msg->flags & I2C_M_NOSTART)) {
+ u8 addr = i2c_8bit_addr_from_msg(msg);
+
+ i2c->state = STATE_START;
+
+ oc_setreg(i2c, OCI2C_DATA, addr);
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START);
+ return;
+ }
+ i2c->state = (msg->flags & I2C_M_RD)
+ ? STATE_READ : STATE_WRITE;
+ } else {
+ i2c->state = STATE_DONE;
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
+ return;
+ }
+ }
+
+ if (i2c->state == STATE_READ) {
+ oc_setreg(i2c, OCI2C_CMD, i2c->pos == (msg->len - 1) ?
+ OCI2C_CMD_READ_NACK : OCI2C_CMD_READ_ACK);
+ } else {
+ oc_setreg(i2c, OCI2C_DATA, msg->buf[i2c->pos++]);
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_WRITE);
+ }
+}
+
+static irqreturn_t ocores_isr(int irq, void *dev_id)
+{
+ struct ocores_i2c_bus *i2c = dev_id;
+ u8 stat = oc_getreg(i2c, OCI2C_STATUS);
+
+ if (i2c->flags & OCORES_FLAG_BROKEN_IRQ) {
+ if ((stat & OCI2C_STAT_IF) && !(stat & OCI2C_STAT_BUSY))
+ return IRQ_NONE;
+ } else if (!(stat & OCI2C_STAT_IF)) {
+ return IRQ_NONE;
+ }
+ ocores_process(i2c, stat);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * Wait until something change in a given register
+ * @i2c: ocores I2C device instance
+ * @reg: register to query
+ * @mask: bitmask to apply on register value
+ * @val: expected result
+ * @msec: timeout in msec
+ *
+ * Timeout is necessary to avoid to stay here forever when the chip
+ * does not answer correctly.
+ *
+ * Return: 0 on success, -ETIMEDOUT on timeout
+ */
+static int ocores_wait(struct ocores_i2c_bus *i2c,
+ int reg, u8 mask, u8 val,
+ const unsigned long msec)
+{
+ u32 count = 0;
+
+ while (1) {
+ u8 status = oc_getreg(i2c, reg);
+
+ if ((status & mask) == val)
+ break;
+
+ udelay(1);
+ count += 1;
+
+ if (count == (1000 * msec))
+ return -ETIMEDOUT;
+ }
+ return 0;
+}
+
+/**
+ * Wait until is possible to process some data
+ * @i2c: ocores I2C device instance
+ *
+ * Used when the device is in polling mode (interrupts disabled).
+ *
+ * Return: 0 on success, -ETIMEDOUT on timeout
+ */
+static int ocores_poll_wait(struct ocores_i2c_bus *i2c)
+{
+ u8 mask;
+ int err;
+
+ if (i2c->state == STATE_DONE || i2c->state == STATE_ERROR) {
+ /* transfer is over */
+ mask = OCI2C_STAT_BUSY;
+ } else {
+ /* on going transfer */
+ mask = OCI2C_STAT_TIP;
+ /*
+ * We wait for the data to be transferred (8bit),
+ * then we start polling on the ACK/NACK bit
+ */
+ udelay((8 * 1000) / i2c->bus_clk_khz);
+ }
+
+ /*
+ * once we are here we expect to get the expected result immediately
+ * so if after 1ms we timeout then something is broken.
+ */
+ err = ocores_wait(i2c, OCI2C_STATUS, mask, 0, 1);
+ if (err)
+ debug("%s: STATUS timeout, bit 0x%x did not clear in 1ms\n",
+ __func__, mask);
+ return err;
+}
+
+/**
+ * It handles an IRQ-less transfer
+ * @i2c: ocores I2C device instance
+ *
+ * Even if IRQ are disabled, the I2C OpenCore IP behavior is exactly the same
+ * (only that IRQ are not produced). This means that we can re-use entirely
+ * ocores_isr(), we just add our polling code around it.
+ *
+ * It can run in atomic context
+ */
+static void ocores_process_polling(struct ocores_i2c_bus *i2c)
+{
+ while (1) {
+ irqreturn_t ret;
+ int err;
+
+ err = ocores_poll_wait(i2c);
+ if (err) {
+ i2c->state = STATE_ERROR;
+ break; /* timeout */
+ }
+
+ ret = ocores_isr(-1, i2c);
+ if (ret == IRQ_NONE) {
+ break; /* all messages have been transferred */
+ } else {
+ if (i2c->flags & OCORES_FLAG_BROKEN_IRQ)
+ if (i2c->state == STATE_DONE)
+ break;
+ }
+ }
+}
+
+static int ocores_xfer_core(struct ocores_i2c_bus *i2c,
+ struct i2c_msg *msgs, int num, bool polling)
+{
+ u8 ctrl;
+
+ ctrl = oc_getreg(i2c, OCI2C_CONTROL);
+
+ if (polling)
+ oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~OCI2C_CTRL_IEN);
+
+ i2c->msg = msgs;
+ i2c->pos = 0;
+ i2c->nmsgs = num;
+ i2c->state = STATE_START;
+
+ oc_setreg(i2c, OCI2C_DATA, i2c_8bit_addr_from_msg(i2c->msg));
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START);
+
+ if (polling)
+ ocores_process_polling(i2c);
+
+ return (i2c->state == STATE_DONE) ? num : -EIO;
+}
+
+static int ocores_i2c_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs)
+{
+ struct ocores_i2c_bus *bus = dev_get_priv(dev);
+ int ret;
+
+ debug("i2c_xfer: %d messages\n", nmsgs);
+
+ ret = ocores_xfer_core(bus, msg, nmsgs, 1);
+
+ if (ret != nmsgs) {
+ debug("i2c_write: error sending\n");
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static int ocores_i2c_enable_clk(struct udevice *dev)
+{
+ struct ocores_i2c_bus *bus = dev_get_priv(dev);
+ ulong clk_rate;
+ int ret;
+
+ ret = clk_get_by_index(dev, 0, &bus->clk);
+ if (ret)
+ return -EINVAL;
+
+ ret = clk_enable(&bus->clk);
+ if (ret)
+ return ret;
+
+ clk_rate = clk_get_rate(&bus->clk);
+ if (!clk_rate)
+ return -EINVAL;
+
+ bus->ip_clk_khz = clk_rate / 1000;
+
+ clk_free(&bus->clk);
+
+ return 0;
+}
+
+static int ocores_init(struct udevice *dev, struct ocores_i2c_bus *bus)
+{
+ int prescale;
+ int diff;
+ u8 ctrl = oc_getreg(bus, OCI2C_CONTROL);
+
+ /* make sure the device is disabled */
+ ctrl &= ~(OCI2C_CTRL_EN | OCI2C_CTRL_IEN);
+ oc_setreg(bus, OCI2C_CONTROL, ctrl);
+
+ prescale = (bus->ip_clk_khz / (5 * bus->bus_clk_khz)) - 1;
+ prescale = clamp(prescale, 0, 0xffff);
+
+ diff = bus->ip_clk_khz / (5 * (prescale + 1)) - bus->bus_clk_khz;
+ if (abs(diff) > bus->bus_clk_khz / 10) {
+ debug("Unsupported clock settings: core: %d KHz, bus: %d KHz\n",
+ bus->ip_clk_khz, bus->bus_clk_khz);
+ return -EINVAL;
+ }
+
+ oc_setreg(bus, OCI2C_PRELOW, prescale & 0xff);
+ oc_setreg(bus, OCI2C_PREHIGH, prescale >> 8);
+
+ /* Init the device */
+ oc_setreg(bus, OCI2C_CMD, OCI2C_CMD_IACK);
+ oc_setreg(bus, OCI2C_CONTROL, ctrl | OCI2C_CTRL_EN);
+
+ return 0;
+}
+
+/*
+ * Read and write functions for the GRLIB port of the controller. Registers are
+ * 32-bit big endian and the PRELOW and PREHIGH registers are merged into one
+ * register. The subsequent registers have their offsets decreased accordingly.
+ */
+static u8 oc_getreg_grlib(struct ocores_i2c_bus *i2c, int reg)
+{
+ u32 rd;
+ int rreg = reg;
+
+ if (reg != OCI2C_PRELOW)
+ rreg--;
+ rd = in_be32(i2c->base + (rreg << i2c->reg_shift));
+ if (reg == OCI2C_PREHIGH)
+ return (u8)(rd >> 8);
+ else
+ return (u8)rd;
+}
+
+static void oc_setreg_grlib(struct ocores_i2c_bus *i2c, int reg, u8 value)
+{
+ u32 curr, wr;
+ int rreg = reg;
+
+ if (reg != OCI2C_PRELOW)
+ rreg--;
+ if (reg == OCI2C_PRELOW || reg == OCI2C_PREHIGH) {
+ curr = in_be32(i2c->base + (rreg << i2c->reg_shift));
+ if (reg == OCI2C_PRELOW)
+ wr = (curr & 0xff00) | value;
+ else
+ wr = (((u32)value) << 8) | (curr & 0xff);
+ } else {
+ wr = value;
+ }
+ out_be32(i2c->base + (rreg << i2c->reg_shift), wr);
+}
+
+static int ocores_i2c_set_bus_speed(struct udevice *dev, unsigned int speed)
+{
+ int prescale;
+ int diff;
+ struct ocores_i2c_bus *bus = dev_get_priv(dev);
+
+ /* speed in Khz */
+ speed = speed / 1000;
+
+ prescale = (bus->ip_clk_khz / (5 * speed)) - 1;
+ prescale = clamp(prescale, 0, 0xffff);
+
+ diff = bus->ip_clk_khz / (5 * (prescale + 1)) - speed;
+ if (abs(diff) > speed / 10) {
+ debug("Unsupported clock settings: core: %d KHz, bus: %d KHz\n",
+ bus->ip_clk_khz, speed);
+ return -EINVAL;
+ }
+
+ oc_setreg(bus, OCI2C_PRELOW, prescale & 0xff);
+ oc_setreg(bus, OCI2C_PREHIGH, prescale >> 8);
+
+ bus->bus_clk_khz = speed;
+ return 0;
+}
+
+int ocores_i2c_get_bus_speed(struct udevice *dev)
+{
+ struct ocores_i2c_bus *bus = dev_get_priv(dev);
+
+ return (bus->bus_clk_khz * 1000);
+}
+
+static const struct dm_i2c_ops ocores_i2c_ops = {
+ .xfer = ocores_i2c_xfer,
+ .set_bus_speed = ocores_i2c_set_bus_speed,
+ .get_bus_speed = ocores_i2c_get_bus_speed,
+};
+
+static int ocores_i2c_probe(struct udevice *dev)
+{
+ struct ocores_i2c_bus *bus = dev_get_priv(dev);
+ bool clock_frequency_present;
+ u32 val;
+ u32 clock_frequency_khz;
+ int ret;
+
+ bus->base = (void __iomem *)devfdt_get_addr(dev);
+
+ if (dev_read_u32(dev, "reg-shift", &bus->reg_shift)) {
+ /* no 'reg-shift', check for deprecated 'regstep' */
+ ret = dev_read_u32(dev, "regstep", &val);
+ if (ret) {
+ dev_err(dev,
+ "missing both reg-shift and regstep property: %d\n", ret);
+ return -EINVAL;
+ } else {
+ bus->reg_shift = ilog2(val);
+ dev_warn(dev,
+ "regstep property deprecated, use reg-shift\n");
+ }
+ }
+
+ if (dev_read_u32(dev, "clock-frequency", &val)) {
+ bus->bus_clk_khz = 100;
+ clock_frequency_present = FALSE;
+ } else {
+ bus->bus_clk_khz = val / 1000;
+ clock_frequency_khz = val / 1000;
+ clock_frequency_present = TRUE;
+ }
+
+ ret = ocores_i2c_enable_clk(dev);
+ if (ret)
+ return ret;
+
+ if (bus->ip_clk_khz == 0) {
+ if (dev_read_u32(dev, "opencores,ip-clock-frequency", &val)) {
+ if (!clock_frequency_present) {
+ dev_err(dev,
+ "Missing required parameter 'opencores,ip-clock-frequency'\n");
+ clk_disable(&bus->clk);
+ return -ENODEV;
+ }
+
+ bus->ip_clk_khz = clock_frequency_khz;
+ dev_warn(dev,
+ "Deprecated usage of the 'clock-frequency' property, please update to 'opencores,ip-clock-frequency'\n");
+ } else {
+ bus->ip_clk_khz = val / 1000;
+ if (clock_frequency_present)
+ bus->bus_clk_khz = clock_frequency_khz;
+ }
+ }
+
+ bus->reg_io_width = dev_read_u32_default(dev, "reg-io-width", 1);
+
+ if (dev_get_driver_data(dev) == TYPE_GRLIB) {
+ debug("GRLIB variant of i2c-ocores\n");
+ bus->setreg = oc_setreg_grlib;
+ bus->getreg = oc_getreg_grlib;
+ }
+
+ if (!bus->setreg || !bus->getreg) {
+ bool be = (cpu_to_be32(0x12345678) == 0x12345678);
+
+ switch (bus->reg_io_width) {
+ case 1:
+ bus->setreg = oc_setreg_8;
+ bus->getreg = oc_getreg_8;
+ break;
+
+ case 2:
+ bus->setreg = be ? oc_setreg_16be : oc_setreg_16;
+ bus->getreg = be ? oc_getreg_16be : oc_getreg_16;
+ break;
+
+ case 4:
+ bus->setreg = be ? oc_setreg_32be : oc_setreg_32;
+ bus->getreg = be ? oc_getreg_32be : oc_getreg_32;
+ break;
+
+ default:
+ debug("Unsupported I/O width (%d)\n",
+ bus->reg_io_width);
+ ret = -EINVAL;
+ goto err_clk;
+ }
+ }
+
+ /*
+ * Set OCORES_FLAG_BROKEN_IRQ to enable workaround for
+ * FU540-C000 SoC in polling mode.
+ * Since the SoC does have an interrupt, its DT has an interrupt
+ * property - But this should be bypassed as the IRQ logic in this
+ * SoC is broken.
+ */
+
+ if (device_is_compatible(dev, "sifive,fu540-c000-i2c"))
+ bus->flags |= OCORES_FLAG_BROKEN_IRQ;
+
+ ret = ocores_init(dev, bus);
+ if (ret)
+ goto err_clk;
+
+ return 0;
+
+err_clk:
+ clk_disable(&bus->clk);
+ return ret;
+}
+
+static const struct udevice_id ocores_i2c_ids[] = {
+{ .compatible = "opencores,i2c-ocores", .data = TYPE_OCORES },
+{ .compatible = "aeroflexgaisler,i2cmst", .data = TYPE_GRLIB },
+{ .compatible = "sifive,fu540-c000-i2c" },
+{ .compatible = "sifive,i2c0" },
+};
+
+U_BOOT_DRIVER(i2c_ocores) = {
+ .name = "i2c_ocores",
+ .id = UCLASS_I2C,
+ .of_match = ocores_i2c_ids,
+ .probe = ocores_i2c_probe,
+ .priv_auto = sizeof(struct ocores_i2c_bus),
+ .ops = &ocores_i2c_ops,
+};
diff --git a/roms/u-boot/drivers/i2c/octeon_i2c.c b/roms/u-boot/drivers/i2c/octeon_i2c.c
new file mode 100644
index 000000000..ea2cc33f9
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/octeon_i2c.c
@@ -0,0 +1,839 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ */
+
+#include <clk.h>
+#include <dm.h>
+#include <i2c.h>
+#include <time.h>
+#include <asm/io.h>
+#include <linux/bitfield.h>
+#include <linux/compat.h>
+#include <linux/delay.h>
+
+#define TWSI_SW_TWSI 0x00
+#define TWSI_TWSI_SW 0x08
+#define TWSI_INT 0x10
+#define TWSI_SW_TWSI_EXT 0x18
+
+#define TWSI_SW_DATA_MASK GENMASK_ULL(31, 0)
+#define TWSI_SW_EOP_IA_MASK GENMASK_ULL(34, 32)
+#define TWSI_SW_IA_MASK GENMASK_ULL(39, 35)
+#define TWSI_SW_ADDR_MASK GENMASK_ULL(49, 40)
+#define TWSI_SW_SCR_MASK GENMASK_ULL(51, 50)
+#define TWSI_SW_SIZE_MASK GENMASK_ULL(54, 52)
+#define TWSI_SW_SOVR BIT_ULL(55)
+#define TWSI_SW_R BIT_ULL(56)
+#define TWSI_SW_OP_MASK GENMASK_ULL(60, 57)
+#define TWSI_SW_EIA GENMASK_ULL(61)
+#define TWSI_SW_SLONLY BIT_ULL(62)
+#define TWSI_SW_V BIT_ULL(63)
+
+#define TWSI_INT_SDA_OVR BIT_ULL(8)
+#define TWSI_INT_SCL_OVR BIT_ULL(9)
+#define TWSI_INT_SDA BIT_ULL(10)
+#define TWSI_INT_SCL BIT_ULL(11)
+
+enum {
+ TWSI_OP_WRITE = 0,
+ TWSI_OP_READ = 1,
+};
+
+enum {
+ TWSI_EOP_SLAVE_ADDR = 0,
+ TWSI_EOP_CLK_CTL = 3,
+ TWSI_SW_EOP_IA = 6,
+};
+
+enum {
+ TWSI_SLAVEADD = 0,
+ TWSI_DATA = 1,
+ TWSI_CTL = 2,
+ TWSI_CLKCTL = 3,
+ TWSI_STAT = 3,
+ TWSI_SLAVEADD_EXT = 4,
+ TWSI_RST = 7,
+};
+
+enum {
+ TWSI_CTL_AAK = BIT(2),
+ TWSI_CTL_IFLG = BIT(3),
+ TWSI_CTL_STP = BIT(4),
+ TWSI_CTL_STA = BIT(5),
+ TWSI_CTL_ENAB = BIT(6),
+ TWSI_CTL_CE = BIT(7),
+};
+
+/*
+ * Internal errors. When debugging is enabled, the driver will report the
+ * error number and the user / developer can check the table below for the
+ * detailed error description.
+ */
+enum {
+ /** Bus error */
+ TWSI_STAT_BUS_ERROR = 0x00,
+ /** Start condition transmitted */
+ TWSI_STAT_START = 0x08,
+ /** Repeat start condition transmitted */
+ TWSI_STAT_RSTART = 0x10,
+ /** Address + write bit transmitted, ACK received */
+ TWSI_STAT_TXADDR_ACK = 0x18,
+ /** Address + write bit transmitted, /ACK received */
+ TWSI_STAT_TXADDR_NAK = 0x20,
+ /** Data byte transmitted in master mode, ACK received */
+ TWSI_STAT_TXDATA_ACK = 0x28,
+ /** Data byte transmitted in master mode, ACK received */
+ TWSI_STAT_TXDATA_NAK = 0x30,
+ /** Arbitration lost in address or data byte */
+ TWSI_STAT_TX_ARB_LOST = 0x38,
+ /** Address + read bit transmitted, ACK received */
+ TWSI_STAT_RXADDR_ACK = 0x40,
+ /** Address + read bit transmitted, /ACK received */
+ TWSI_STAT_RXADDR_NAK = 0x48,
+ /** Data byte received in master mode, ACK transmitted */
+ TWSI_STAT_RXDATA_ACK_SENT = 0x50,
+ /** Data byte received, NACK transmitted */
+ TWSI_STAT_RXDATA_NAK_SENT = 0x58,
+ /** Slave address received, sent ACK */
+ TWSI_STAT_SLAVE_RXADDR_ACK = 0x60,
+ /**
+ * Arbitration lost in address as master, slave address + write bit
+ * received, ACK transmitted
+ */
+ TWSI_STAT_TX_ACK_ARB_LOST = 0x68,
+ /** General call address received, ACK transmitted */
+ TWSI_STAT_RX_GEN_ADDR_ACK = 0x70,
+ /**
+ * Arbitration lost in address as master, general call address
+ * received, ACK transmitted
+ */
+ TWSI_STAT_RX_GEN_ADDR_ARB_LOST = 0x78,
+ /** Data byte received after slave address received, ACK transmitted */
+ TWSI_STAT_SLAVE_RXDATA_ACK = 0x80,
+ /** Data byte received after slave address received, /ACK transmitted */
+ TWSI_STAT_SLAVE_RXDATA_NAK = 0x88,
+ /**
+ * Data byte received after general call address received, ACK
+ * transmitted
+ */
+ TWSI_STAT_GEN_RXADDR_ACK = 0x90,
+ /**
+ * Data byte received after general call address received, /ACK
+ * transmitted
+ */
+ TWSI_STAT_GEN_RXADDR_NAK = 0x98,
+ /** STOP or repeated START condition received in slave mode */
+ TWSI_STAT_STOP_MULTI_START = 0xa0,
+ /** Slave address + read bit received, ACK transmitted */
+ TWSI_STAT_SLAVE_RXADDR2_ACK = 0xa8,
+ /**
+ * Arbitration lost in address as master, slave address + read bit
+ * received, ACK transmitted
+ */
+ TWSI_STAT_RXDATA_ACK_ARB_LOST = 0xb0,
+ /** Data byte transmitted in slave mode, ACK received */
+ TWSI_STAT_SLAVE_TXDATA_ACK = 0xb8,
+ /** Data byte transmitted in slave mode, /ACK received */
+ TWSI_STAT_SLAVE_TXDATA_NAK = 0xc0,
+ /** Last byte transmitted in slave mode, ACK received */
+ TWSI_STAT_SLAVE_TXDATA_END_ACK = 0xc8,
+ /** Second address byte + write bit transmitted, ACK received */
+ TWSI_STAT_TXADDR2DATA_ACK = 0xd0,
+ /** Second address byte + write bit transmitted, /ACK received */
+ TWSI_STAT_TXADDR2DATA_NAK = 0xd8,
+ /** No relevant status information */
+ TWSI_STAT_IDLE = 0xf8
+};
+
+#define CONFIG_SYS_I2C_OCTEON_SLAVE_ADDR 0x77
+
+enum {
+ PROBE_PCI = 0, /* PCI based probing */
+ PROBE_DT, /* DT based probing */
+};
+
+enum {
+ CLK_METHOD_OCTEON = 0,
+ CLK_METHOD_OCTEONTX2,
+};
+
+/**
+ * struct octeon_i2c_data - SoC specific data of this driver
+ *
+ * @probe: Probing of this SoC (DT vs PCI)
+ * @reg_offs: Register offset
+ * @thp: THP define for divider calculation
+ * @clk_method: Clock calculation method
+ */
+struct octeon_i2c_data {
+ int probe;
+ u32 reg_offs;
+ int thp;
+ int clk_method;
+};
+
+/**
+ * struct octeon_twsi - Private data of this driver
+ *
+ * @base: Base address of i2c registers
+ * @data: Pointer to SoC specific data struct
+ */
+struct octeon_twsi {
+ void __iomem *base;
+ const struct octeon_i2c_data *data;
+ struct clk clk;
+};
+
+static void twsi_unblock(void *base);
+static int twsi_stop(void *base);
+
+/**
+ * Returns true if we lost arbitration
+ *
+ * @code status code
+ * @final_read true if this is the final read operation
+ * @return true if arbitration has been lost, false if it hasn't been lost.
+ */
+static int twsi_i2c_lost_arb(u8 code, int final_read)
+{
+ switch (code) {
+ case TWSI_STAT_TX_ARB_LOST:
+ case TWSI_STAT_TX_ACK_ARB_LOST:
+ case TWSI_STAT_RX_GEN_ADDR_ARB_LOST:
+ case TWSI_STAT_RXDATA_ACK_ARB_LOST:
+ /* Arbitration lost */
+ return -EAGAIN;
+
+ case TWSI_STAT_SLAVE_RXADDR_ACK:
+ case TWSI_STAT_RX_GEN_ADDR_ACK:
+ case TWSI_STAT_GEN_RXADDR_ACK:
+ case TWSI_STAT_GEN_RXADDR_NAK:
+ /* Being addressed as slave, should back off and listen */
+ return -EIO;
+
+ case TWSI_STAT_SLAVE_RXDATA_ACK:
+ case TWSI_STAT_SLAVE_RXDATA_NAK:
+ case TWSI_STAT_STOP_MULTI_START:
+ case TWSI_STAT_SLAVE_RXADDR2_ACK:
+ case TWSI_STAT_SLAVE_TXDATA_ACK:
+ case TWSI_STAT_SLAVE_TXDATA_NAK:
+ case TWSI_STAT_SLAVE_TXDATA_END_ACK:
+ /* Core busy as slave */
+ return -EIO;
+
+ case TWSI_STAT_RXDATA_ACK_SENT:
+ /* Ack allowed on pre-terminal bytes only */
+ if (!final_read)
+ return 0;
+ return -EAGAIN;
+
+ case TWSI_STAT_RXDATA_NAK_SENT:
+ /* NAK allowed on terminal byte only */
+ if (!final_read)
+ return 0;
+ return -EAGAIN;
+
+ case TWSI_STAT_TXDATA_NAK:
+ case TWSI_STAT_TXADDR_NAK:
+ case TWSI_STAT_RXADDR_NAK:
+ case TWSI_STAT_TXADDR2DATA_NAK:
+ return -EAGAIN;
+ }
+
+ return 0;
+}
+
+/**
+ * Writes to the MIO_TWS(0..5)_SW_TWSI register
+ *
+ * @base Base address of i2c registers
+ * @val value to write
+ * @return 0 for success, otherwise error
+ */
+static u64 twsi_write_sw(void __iomem *base, u64 val)
+{
+ unsigned long start = get_timer(0);
+
+ val &= ~TWSI_SW_R;
+ val |= TWSI_SW_V;
+
+ debug("%s(%p, 0x%llx)\n", __func__, base, val);
+ writeq(val, base + TWSI_SW_TWSI);
+ do {
+ val = readq(base + TWSI_SW_TWSI);
+ } while ((val & TWSI_SW_V) && (get_timer(start) < 50));
+
+ if (val & TWSI_SW_V)
+ debug("%s: timed out\n", __func__);
+ return val;
+}
+
+/**
+ * Reads the MIO_TWS(0..5)_SW_TWSI register
+ *
+ * @base Base address of i2c registers
+ * @val value for eia and op, etc. to read
+ * @return value of the register
+ */
+static u64 twsi_read_sw(void __iomem *base, u64 val)
+{
+ unsigned long start = get_timer(0);
+
+ val |= TWSI_SW_R | TWSI_SW_V;
+
+ debug("%s(%p, 0x%llx)\n", __func__, base, val);
+ writeq(val, base + TWSI_SW_TWSI);
+
+ do {
+ val = readq(base + TWSI_SW_TWSI);
+ } while ((val & TWSI_SW_V) && (get_timer(start) < 50));
+
+ if (val & TWSI_SW_V)
+ debug("%s: Error writing 0x%llx\n", __func__, val);
+
+ debug("%s: Returning 0x%llx\n", __func__, val);
+ return val;
+}
+
+/**
+ * Write control register
+ *
+ * @base Base address for i2c registers
+ * @data data to write
+ */
+static void twsi_write_ctl(void __iomem *base, u8 data)
+{
+ u64 val;
+
+ debug("%s(%p, 0x%x)\n", __func__, base, data);
+ val = data | FIELD_PREP(TWSI_SW_EOP_IA_MASK, TWSI_CTL) |
+ FIELD_PREP(TWSI_SW_OP_MASK, TWSI_SW_EOP_IA);
+ twsi_write_sw(base, val);
+}
+
+/**
+ * Reads the TWSI Control Register
+ *
+ * @base Base address for i2c
+ * @return 8-bit TWSI control register
+ */
+static u8 twsi_read_ctl(void __iomem *base)
+{
+ u64 val;
+
+ val = FIELD_PREP(TWSI_SW_EOP_IA_MASK, TWSI_CTL) |
+ FIELD_PREP(TWSI_SW_OP_MASK, TWSI_SW_EOP_IA);
+ val = twsi_read_sw(base, val);
+
+ debug("%s(%p): 0x%x\n", __func__, base, (u8)val);
+ return (u8)val;
+}
+
+/**
+ * Read i2c status register
+ *
+ * @base Base address of i2c registers
+ * @return value of status register
+ */
+static u8 twsi_read_status(void __iomem *base)
+{
+ u64 val;
+
+ val = FIELD_PREP(TWSI_SW_EOP_IA_MASK, TWSI_STAT) |
+ FIELD_PREP(TWSI_SW_OP_MASK, TWSI_SW_EOP_IA);
+
+ return twsi_read_sw(base, val);
+}
+
+/**
+ * Waits for an i2c operation to complete
+ *
+ * @param base Base address of registers
+ * @return 0 for success, 1 if timeout
+ */
+static int twsi_wait(void __iomem *base)
+{
+ unsigned long start = get_timer(0);
+ u8 twsi_ctl;
+
+ debug("%s(%p)\n", __func__, base);
+ do {
+ twsi_ctl = twsi_read_ctl(base);
+ twsi_ctl &= TWSI_CTL_IFLG;
+ } while (!twsi_ctl && get_timer(start) < 50);
+
+ debug(" return: %u\n", !twsi_ctl);
+ return !twsi_ctl;
+}
+
+/**
+ * Unsticks the i2c bus
+ *
+ * @base base address of registers
+ */
+static int twsi_start_unstick(void __iomem *base)
+{
+ twsi_stop(base);
+ twsi_unblock(base);
+
+ return 0;
+}
+
+/**
+ * Sends an i2c start condition
+ *
+ * @base base address of registers
+ * @return 0 for success, otherwise error
+ */
+static int twsi_start(void __iomem *base)
+{
+ int ret;
+ u8 stat;
+
+ debug("%s(%p)\n", __func__, base);
+ twsi_write_ctl(base, TWSI_CTL_STA | TWSI_CTL_ENAB);
+ ret = twsi_wait(base);
+ if (ret) {
+ stat = twsi_read_status(base);
+ debug("%s: ret: 0x%x, status: 0x%x\n", __func__, ret, stat);
+ switch (stat) {
+ case TWSI_STAT_START:
+ case TWSI_STAT_RSTART:
+ return 0;
+ case TWSI_STAT_RXADDR_ACK:
+ default:
+ return twsi_start_unstick(base);
+ }
+ }
+
+ debug("%s: success\n", __func__);
+ return 0;
+}
+
+/**
+ * Sends an i2c stop condition
+ *
+ * @base register base address
+ * @return 0 for success, -1 if error
+ */
+static int twsi_stop(void __iomem *base)
+{
+ u8 stat;
+
+ twsi_write_ctl(base, TWSI_CTL_STP | TWSI_CTL_ENAB);
+
+ stat = twsi_read_status(base);
+ if (stat != TWSI_STAT_IDLE) {
+ debug("%s: Bad status on bus@%p\n", __func__, base);
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * Writes data to the i2c bus
+ *
+ * @base register base address
+ * @slave_addr address of slave to write to
+ * @buffer Pointer to buffer to write
+ * @length Number of bytes in buffer to write
+ * @return 0 for success, otherwise error
+ */
+static int twsi_write_data(void __iomem *base, u8 slave_addr,
+ u8 *buffer, unsigned int length)
+{
+ unsigned int curr = 0;
+ u64 val;
+ int ret;
+
+ debug("%s(%p, 0x%x, %p, 0x%x)\n", __func__, base, slave_addr,
+ buffer, length);
+ ret = twsi_start(base);
+ if (ret) {
+ debug("%s: Could not start BUS transaction\n", __func__);
+ return -1;
+ }
+
+ ret = twsi_wait(base);
+ if (ret) {
+ debug("%s: wait failed\n", __func__);
+ return ret;
+ }
+
+ val = (u32)(slave_addr << 1) | TWSI_OP_WRITE |
+ FIELD_PREP(TWSI_SW_EOP_IA_MASK, TWSI_DATA) |
+ FIELD_PREP(TWSI_SW_OP_MASK, TWSI_SW_EOP_IA);
+ twsi_write_sw(base, val);
+ twsi_write_ctl(base, TWSI_CTL_ENAB);
+
+ debug("%s: Waiting\n", __func__);
+ ret = twsi_wait(base);
+ if (ret) {
+ debug("%s: Timed out writing slave address 0x%x to target\n",
+ __func__, slave_addr);
+ return ret;
+ }
+
+ ret = twsi_read_status(base);
+ debug("%s: status: 0x%x\n", __func__, ret);
+ if (ret != TWSI_STAT_TXADDR_ACK) {
+ debug("%s: status: 0x%x\n", __func__, ret);
+ twsi_stop(base);
+ return twsi_i2c_lost_arb(ret, 0);
+ }
+
+ while (curr < length) {
+ val = buffer[curr++] |
+ FIELD_PREP(TWSI_SW_EOP_IA_MASK, TWSI_DATA) |
+ FIELD_PREP(TWSI_SW_OP_MASK, TWSI_SW_EOP_IA);
+ twsi_write_sw(base, val);
+ twsi_write_ctl(base, TWSI_CTL_ENAB);
+
+ debug("%s: Writing 0x%llx\n", __func__, val);
+
+ ret = twsi_wait(base);
+ if (ret) {
+ debug("%s: Timed out writing data to 0x%x\n",
+ __func__, slave_addr);
+ return ret;
+ }
+ ret = twsi_read_status(base);
+ debug("%s: status: 0x%x\n", __func__, ret);
+ }
+
+ debug("%s: Stopping\n", __func__);
+ return twsi_stop(base);
+}
+
+/**
+ * Manually clear the I2C bus and send a stop
+ *
+ * @base register base address
+ */
+static void twsi_unblock(void __iomem *base)
+{
+ int i;
+
+ for (i = 0; i < 9; i++) {
+ writeq(0, base + TWSI_INT);
+ udelay(5);
+ writeq(TWSI_INT_SCL_OVR, base + TWSI_INT);
+ udelay(5);
+ }
+ writeq(TWSI_INT_SCL_OVR | TWSI_INT_SDA_OVR, base + TWSI_INT);
+ udelay(5);
+ writeq(TWSI_INT_SDA_OVR, base + TWSI_INT);
+ udelay(5);
+ writeq(0, base + TWSI_INT);
+ udelay(5);
+}
+
+/**
+ * Performs a read transaction on the i2c bus
+ *
+ * @base Base address of twsi registers
+ * @slave_addr i2c bus address to read from
+ * @buffer buffer to read into
+ * @length number of bytes to read
+ * @return 0 for success, otherwise error
+ */
+static int twsi_read_data(void __iomem *base, u8 slave_addr,
+ u8 *buffer, unsigned int length)
+{
+ unsigned int curr = 0;
+ u64 val;
+ int ret;
+
+ debug("%s(%p, 0x%x, %p, %u)\n", __func__, base, slave_addr,
+ buffer, length);
+ ret = twsi_start(base);
+ if (ret) {
+ debug("%s: start failed\n", __func__);
+ return ret;
+ }
+
+ ret = twsi_wait(base);
+ if (ret) {
+ debug("%s: wait failed\n", __func__);
+ return ret;
+ }
+
+ val = (u32)(slave_addr << 1) | TWSI_OP_READ |
+ FIELD_PREP(TWSI_SW_EOP_IA_MASK, TWSI_DATA) |
+ FIELD_PREP(TWSI_SW_OP_MASK, TWSI_SW_EOP_IA);
+ twsi_write_sw(base, val);
+ twsi_write_ctl(base, TWSI_CTL_ENAB);
+
+ ret = twsi_wait(base);
+ if (ret) {
+ debug("%s: waiting for sending addr failed\n", __func__);
+ return ret;
+ }
+
+ ret = twsi_read_status(base);
+ debug("%s: status: 0x%x\n", __func__, ret);
+ if (ret != TWSI_STAT_RXADDR_ACK) {
+ debug("%s: status: 0x%x\n", __func__, ret);
+ twsi_stop(base);
+ return twsi_i2c_lost_arb(ret, 0);
+ }
+
+ while (curr < length) {
+ twsi_write_ctl(base, TWSI_CTL_ENAB |
+ ((curr < length - 1) ? TWSI_CTL_AAK : 0));
+
+ ret = twsi_wait(base);
+ if (ret) {
+ debug("%s: waiting for data failed\n", __func__);
+ return ret;
+ }
+
+ val = twsi_read_sw(base, val);
+ buffer[curr++] = (u8)val;
+ }
+
+ twsi_stop(base);
+
+ return 0;
+}
+
+/**
+ * Calculate the divisor values
+ *
+ * @speed Speed to set
+ * @m_div Pointer to M divisor
+ * @n_div Pointer to N divisor
+ * @return 0 for success, otherwise error
+ */
+static void twsi_calc_div(struct udevice *bus, ulong sclk, unsigned int speed,
+ int *m_div, int *n_div)
+{
+ struct octeon_twsi *twsi = dev_get_priv(bus);
+ int thp = twsi->data->thp;
+ int tclk, fsamp;
+ int ndiv, mdiv;
+
+ if (twsi->data->clk_method == CLK_METHOD_OCTEON) {
+ tclk = sclk / (2 * (thp + 1));
+ } else {
+ /* Refclk src in mode register defaults to 100MHz clock */
+ sclk = 100000000; /* 100 Mhz */
+ tclk = sclk / (thp + 2);
+ }
+ debug("%s( io_clock %lu tclk %u)\n", __func__, sclk, tclk);
+
+ /*
+ * Compute the clocks M divider:
+ *
+ * TWSI freq = (core freq) / (10 x (M+1) x 2 * (thp+1) x 2^N)
+ * M = ((core freq) / (10 x (TWSI freq) x 2 * (thp+1) x 2^N)) - 1
+ *
+ * For OcteonTX2 -
+ * TWSI freq = (core freq) / (10 x (M+1) x (thp+2) x 2^N)
+ * M = ((core freq) / (10 x (TWSI freq) x (thp+2) x 2^N)) - 1
+ */
+ for (ndiv = 0; ndiv < 8; ndiv++) {
+ fsamp = tclk / (1 << ndiv);
+ mdiv = fsamp / speed / 10;
+ mdiv -= 1;
+ if (mdiv < 16)
+ break;
+ }
+
+ *m_div = mdiv;
+ *n_div = ndiv;
+}
+
+/**
+ * Init I2C controller
+ *
+ * @base Base address of twsi registers
+ * @slave_addr I2C slave address to configure this controller to
+ * @return 0 for success, otherwise error
+ */
+static int twsi_init(void __iomem *base, int slaveaddr)
+{
+ u64 val;
+
+ debug("%s (%p, 0x%x)\n", __func__, base, slaveaddr);
+
+ val = slaveaddr << 1 |
+ FIELD_PREP(TWSI_SW_EOP_IA_MASK, 0) |
+ FIELD_PREP(TWSI_SW_OP_MASK, TWSI_SW_EOP_IA) |
+ TWSI_SW_V;
+ twsi_write_sw(base, val);
+
+ /* Set slave address */
+ val = slaveaddr |
+ FIELD_PREP(TWSI_SW_EOP_IA_MASK, TWSI_EOP_SLAVE_ADDR) |
+ FIELD_PREP(TWSI_SW_OP_MASK, TWSI_SW_EOP_IA) |
+ TWSI_SW_V;
+ twsi_write_sw(base, val);
+
+ return 0;
+}
+
+/**
+ * Transfers data over the i2c bus
+ *
+ * @bus i2c bus to transfer data over
+ * @msg Array of i2c messages
+ * @nmsgs Number of messages to send/receive
+ * @return 0 for success, otherwise error
+ */
+static int octeon_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
+ int nmsgs)
+{
+ struct octeon_twsi *twsi = dev_get_priv(bus);
+ int ret;
+ int i;
+
+ debug("%s: %d messages\n", __func__, nmsgs);
+ for (i = 0; i < nmsgs; i++, msg++) {
+ debug("%s: chip=0x%x, len=0x%x\n", __func__, msg->addr,
+ msg->len);
+
+ if (msg->flags & I2C_M_RD) {
+ debug("%s: Reading data\n", __func__);
+ ret = twsi_read_data(twsi->base, msg->addr,
+ msg->buf, msg->len);
+ } else {
+ debug("%s: Writing data\n", __func__);
+ ret = twsi_write_data(twsi->base, msg->addr,
+ msg->buf, msg->len);
+ }
+ if (ret) {
+ debug("%s: error sending\n", __func__);
+ return -EREMOTEIO;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Set I2C bus speed
+ *
+ * @bus i2c bus to transfer data over
+ * @speed Speed in Hz to set
+ * @return 0 for success, otherwise error
+ */
+static int octeon_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
+{
+ struct octeon_twsi *twsi = dev_get_priv(bus);
+ int m_div, n_div;
+ ulong clk_rate;
+ u64 val;
+
+ debug("%s(%p, %u)\n", __func__, bus, speed);
+
+ clk_rate = clk_get_rate(&twsi->clk);
+ if (IS_ERR_VALUE(clk_rate))
+ return -EINVAL;
+
+ twsi_calc_div(bus, clk_rate, speed, &m_div, &n_div);
+ if (m_div >= 16)
+ return -1;
+
+ val = (u32)(((m_div & 0xf) << 3) | ((n_div & 0x7) << 0)) |
+ FIELD_PREP(TWSI_SW_EOP_IA_MASK, TWSI_CLKCTL) |
+ FIELD_PREP(TWSI_SW_OP_MASK, TWSI_SW_EOP_IA) |
+ TWSI_SW_V;
+ /* Only init non-slave ports */
+ writeq(val, twsi->base + TWSI_SW_TWSI);
+
+ debug("%s: Wrote 0x%llx to sw_twsi\n", __func__, val);
+ return 0;
+}
+
+static const struct octeon_i2c_data i2c_octeon_data = {
+ .probe = PROBE_DT,
+ .reg_offs = 0x0000,
+ .thp = 3,
+ .clk_method = CLK_METHOD_OCTEON,
+};
+
+static const struct octeon_i2c_data i2c_octeontx_data = {
+ .probe = PROBE_PCI,
+ .reg_offs = 0x1000,
+ .thp = 24,
+ .clk_method = CLK_METHOD_OCTEON,
+};
+
+static const struct octeon_i2c_data i2c_octeontx2_data = {
+ .probe = PROBE_PCI,
+ .reg_offs = 0x1000,
+ .thp = 3,
+ .clk_method = CLK_METHOD_OCTEONTX2,
+};
+
+/**
+ * Driver probe function
+ *
+ * @dev I2C device to probe
+ * @return 0 for success, otherwise error
+ */
+static int octeon_i2c_probe(struct udevice *dev)
+{
+ struct octeon_twsi *twsi = dev_get_priv(dev);
+ u32 i2c_slave_addr;
+ int ret;
+
+ /* Octeon TX2 needs a different data struct */
+ if (device_is_compatible(dev, "cavium,thunderx-i2c"))
+ dev->driver_data = (long)&i2c_octeontx2_data;
+
+ twsi->data = (const struct octeon_i2c_data *)dev_get_driver_data(dev);
+
+ if (twsi->data->probe == PROBE_PCI) {
+ pci_dev_t bdf = dm_pci_get_bdf(dev);
+
+ debug("TWSI PCI device: %x\n", bdf);
+
+ twsi->base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0,
+ PCI_REGION_MEM);
+ } else {
+ twsi->base = dev_remap_addr(dev);
+ }
+ twsi->base += twsi->data->reg_offs;
+
+ i2c_slave_addr = dev_read_u32_default(dev, "i2c-sda-hold-time-ns",
+ CONFIG_SYS_I2C_OCTEON_SLAVE_ADDR);
+
+ ret = clk_get_by_index(dev, 0, &twsi->clk);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_enable(&twsi->clk);
+ if (ret)
+ return ret;
+
+ debug("TWSI bus %d at %p\n", dev_seq(dev), twsi->base);
+
+ /* Start with standard speed, real speed set via DT or cmd */
+ return twsi_init(twsi->base, i2c_slave_addr);
+}
+
+static const struct dm_i2c_ops octeon_i2c_ops = {
+ .xfer = octeon_i2c_xfer,
+ .set_bus_speed = octeon_i2c_set_bus_speed,
+};
+
+static const struct udevice_id octeon_i2c_ids[] = {
+ { .compatible = "cavium,octeon-7890-twsi",
+ .data = (ulong)&i2c_octeon_data },
+ { .compatible = "cavium,thunder-8890-twsi",
+ .data = (ulong)&i2c_octeontx_data },
+ { }
+};
+
+U_BOOT_DRIVER(octeon_pci_twsi) = {
+ .name = "i2c_octeon",
+ .id = UCLASS_I2C,
+ .of_match = octeon_i2c_ids,
+ .probe = octeon_i2c_probe,
+ .priv_auto = sizeof(struct octeon_twsi),
+ .ops = &octeon_i2c_ops,
+};
diff --git a/roms/u-boot/drivers/i2c/omap24xx_i2c.c b/roms/u-boot/drivers/i2c/omap24xx_i2c.c
new file mode 100644
index 000000000..71f6f5f7a
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/omap24xx_i2c.c
@@ -0,0 +1,1107 @@
+/*
+ * Basic I2C functions
+ *
+ * Copyright (c) 2004 Texas Instruments
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the license found in the file
+ * named COPYING that should have accompanied this file.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Author: Jian Zhang jzhang@ti.com, Texas Instruments
+ *
+ * Copyright (c) 2003 Wolfgang Denk, wd@denx.de
+ * Rewritten to fit into the current U-Boot framework
+ *
+ * Adapted for OMAP2420 I2C, r-woodruff2@ti.com
+ *
+ * Copyright (c) 2013 Lubomir Popov <lpopov@mm-sol.com>, MM Solutions
+ * New i2c_read, i2c_write and i2c_probe functions, tested on OMAP4
+ * (4430/60/70), OMAP5 (5430) and AM335X (3359); should work on older
+ * OMAPs and derivatives as well. The only anticipated exception would
+ * be the OMAP2420, which shall require driver modification.
+ * - Rewritten i2c_read to operate correctly with all types of chips
+ * (old function could not read consistent data from some I2C slaves).
+ * - Optimized i2c_write.
+ * - New i2c_probe, performs write access vs read. The old probe could
+ * hang the system under certain conditions (e.g. unconfigured pads).
+ * - The read/write/probe functions try to identify unconfigured bus.
+ * - Status functions now read irqstatus_raw as per TRM guidelines
+ * (except for OMAP243X and OMAP34XX).
+ * - Driver now supports up to I2C5 (OMAP5).
+ *
+ * Copyright (c) 2014 Hannes Schmelzer <oe5hpm@oevsv.at>, B&R
+ * - Added support for set_speed
+ *
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+#include <log.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+#include <asm/omap_i2c.h>
+
+/*
+ * Provide access to architecture-specific I2C header files for platforms
+ * that are NOT yet solely relying on CONFIG_DM_I2C, CONFIG_OF_CONTROL, and
+ * the defaults provided in 'omap24xx_i2c.h' for all U-Boot stages where I2C
+ * access is desired.
+ */
+#ifndef CONFIG_ARCH_K3
+#include <asm/arch/i2c.h>
+#endif
+
+#include "omap24xx_i2c.h"
+
+#define I2C_TIMEOUT 1000
+
+/* Absolutely safe for status update at 100 kHz I2C: */
+#define I2C_WAIT 200
+
+enum {
+ OMAP_I2C_REV_REG = 0, /* Only on IP V1 (OMAP34XX) */
+ OMAP_I2C_IE_REG, /* Only on IP V1 (OMAP34XX) */
+ OMAP_I2C_STAT_REG,
+ OMAP_I2C_WE_REG,
+ OMAP_I2C_SYSS_REG,
+ OMAP_I2C_BUF_REG,
+ OMAP_I2C_CNT_REG,
+ OMAP_I2C_DATA_REG,
+ OMAP_I2C_SYSC_REG,
+ OMAP_I2C_CON_REG,
+ OMAP_I2C_OA_REG,
+ OMAP_I2C_SA_REG,
+ OMAP_I2C_PSC_REG,
+ OMAP_I2C_SCLL_REG,
+ OMAP_I2C_SCLH_REG,
+ OMAP_I2C_SYSTEST_REG,
+ OMAP_I2C_BUFSTAT_REG,
+ /* Only on IP V2 (OMAP4430, etc.) */
+ OMAP_I2C_IP_V2_REVNB_LO,
+ OMAP_I2C_IP_V2_REVNB_HI,
+ OMAP_I2C_IP_V2_IRQSTATUS_RAW,
+ OMAP_I2C_IP_V2_IRQENABLE_SET,
+ OMAP_I2C_IP_V2_IRQENABLE_CLR,
+};
+
+static const u8 __maybe_unused reg_map_ip_v1[] = {
+ [OMAP_I2C_REV_REG] = 0x00,
+ [OMAP_I2C_IE_REG] = 0x04,
+ [OMAP_I2C_STAT_REG] = 0x08,
+ [OMAP_I2C_WE_REG] = 0x0c,
+ [OMAP_I2C_SYSS_REG] = 0x10,
+ [OMAP_I2C_BUF_REG] = 0x14,
+ [OMAP_I2C_CNT_REG] = 0x18,
+ [OMAP_I2C_DATA_REG] = 0x1c,
+ [OMAP_I2C_SYSC_REG] = 0x20,
+ [OMAP_I2C_CON_REG] = 0x24,
+ [OMAP_I2C_OA_REG] = 0x28,
+ [OMAP_I2C_SA_REG] = 0x2c,
+ [OMAP_I2C_PSC_REG] = 0x30,
+ [OMAP_I2C_SCLL_REG] = 0x34,
+ [OMAP_I2C_SCLH_REG] = 0x38,
+ [OMAP_I2C_SYSTEST_REG] = 0x3c,
+ [OMAP_I2C_BUFSTAT_REG] = 0x40,
+};
+
+static const u8 __maybe_unused reg_map_ip_v2[] = {
+ [OMAP_I2C_STAT_REG] = 0x28,
+ [OMAP_I2C_WE_REG] = 0x34,
+ [OMAP_I2C_SYSS_REG] = 0x90,
+ [OMAP_I2C_BUF_REG] = 0x94,
+ [OMAP_I2C_CNT_REG] = 0x98,
+ [OMAP_I2C_DATA_REG] = 0x9c,
+ [OMAP_I2C_SYSC_REG] = 0x10,
+ [OMAP_I2C_CON_REG] = 0xa4,
+ [OMAP_I2C_OA_REG] = 0xa8,
+ [OMAP_I2C_SA_REG] = 0xac,
+ [OMAP_I2C_PSC_REG] = 0xb0,
+ [OMAP_I2C_SCLL_REG] = 0xb4,
+ [OMAP_I2C_SCLH_REG] = 0xb8,
+ [OMAP_I2C_SYSTEST_REG] = 0xbc,
+ [OMAP_I2C_BUFSTAT_REG] = 0xc0,
+ [OMAP_I2C_IP_V2_REVNB_LO] = 0x00,
+ [OMAP_I2C_IP_V2_REVNB_HI] = 0x04,
+ [OMAP_I2C_IP_V2_IRQSTATUS_RAW] = 0x24,
+ [OMAP_I2C_IP_V2_IRQENABLE_SET] = 0x2c,
+ [OMAP_I2C_IP_V2_IRQENABLE_CLR] = 0x30,
+};
+
+struct omap_i2c {
+ struct udevice *clk;
+ int ip_rev;
+ struct i2c *regs;
+ unsigned int speed;
+ int waitdelay;
+ int clk_id;
+};
+
+static inline const u8 *omap_i2c_get_ip_reg_map(int ip_rev)
+{
+ switch (ip_rev) {
+ case OMAP_I2C_REV_V1:
+ return reg_map_ip_v1;
+ case OMAP_I2C_REV_V2:
+ /* Fall through... */
+ default:
+ return reg_map_ip_v2;
+ }
+}
+
+static inline void omap_i2c_write_reg(void __iomem *base, int ip_rev,
+ u16 val, int reg)
+{
+ writew(val, base + omap_i2c_get_ip_reg_map(ip_rev)[reg]);
+}
+
+static inline u16 omap_i2c_read_reg(void __iomem *base, int ip_rev, int reg)
+{
+ return readw(base + omap_i2c_get_ip_reg_map(ip_rev)[reg]);
+}
+
+static int omap24_i2c_findpsc(u32 *pscl, u32 *psch, uint speed)
+{
+ unsigned long internal_clk = 0, fclk;
+ unsigned int prescaler;
+
+ /*
+ * This method is only called for Standard and Fast Mode speeds
+ *
+ * For some TI SoCs it is explicitly written in TRM (e,g, SPRUHZ6G,
+ * page 5685, Table 24-7)
+ * that the internal I2C clock (after prescaler) should be between
+ * 7-12 MHz (at least for Fast Mode (FS)).
+ *
+ * Such approach is used in v4.9 Linux kernel in:
+ * ./drivers/i2c/busses/i2c-omap.c (omap_i2c_init function).
+ */
+
+ speed /= 1000; /* convert speed to kHz */
+
+ if (speed > 100)
+ internal_clk = 9600;
+ else
+ internal_clk = 4000;
+
+ fclk = I2C_IP_CLK / 1000;
+ prescaler = fclk / internal_clk;
+ prescaler = prescaler - 1;
+
+ if (speed > 100) {
+ unsigned long scl;
+
+ /* Fast mode */
+ scl = internal_clk / speed;
+ *pscl = scl - (scl / 3) - I2C_FASTSPEED_SCLL_TRIM;
+ *psch = (scl / 3) - I2C_FASTSPEED_SCLH_TRIM;
+ } else {
+ /* Standard mode */
+ *pscl = internal_clk / (speed * 2) - I2C_FASTSPEED_SCLL_TRIM;
+ *psch = internal_clk / (speed * 2) - I2C_FASTSPEED_SCLH_TRIM;
+ }
+
+ debug("%s: speed [kHz]: %d psc: 0x%x sscl: 0x%x ssch: 0x%x\n",
+ __func__, speed, prescaler, *pscl, *psch);
+
+ if (*pscl <= 0 || *psch <= 0 || prescaler <= 0)
+ return -EINVAL;
+
+ return prescaler;
+}
+
+/*
+ * Wait for the bus to be free by checking the Bus Busy (BB)
+ * bit to become clear
+ */
+static int wait_for_bb(void __iomem *i2c_base, int ip_rev, int waitdelay)
+{
+ int timeout = I2C_TIMEOUT;
+ int irq_stat_reg;
+ u16 stat;
+
+ irq_stat_reg = (ip_rev == OMAP_I2C_REV_V1) ?
+ OMAP_I2C_STAT_REG : OMAP_I2C_IP_V2_IRQSTATUS_RAW;
+
+ /* clear current interrupts */
+ omap_i2c_write_reg(i2c_base, ip_rev, 0xFFFF, OMAP_I2C_STAT_REG);
+
+ while ((stat = omap_i2c_read_reg(i2c_base, ip_rev, irq_stat_reg) &
+ I2C_STAT_BB) && timeout--) {
+ omap_i2c_write_reg(i2c_base, ip_rev, stat, OMAP_I2C_STAT_REG);
+ udelay(waitdelay);
+ }
+
+ if (timeout <= 0) {
+ printf("Timed out in %s: status=%04x\n", __func__, stat);
+ return 1;
+ }
+
+ /* clear delayed stuff */
+ omap_i2c_write_reg(i2c_base, ip_rev, 0xFFFF, OMAP_I2C_STAT_REG);
+ return 0;
+}
+
+/*
+ * Wait for the I2C controller to complete current action
+ * and update status
+ */
+static u16 wait_for_event(void __iomem *i2c_base, int ip_rev, int waitdelay)
+{
+ u16 status;
+ int timeout = I2C_TIMEOUT;
+ int irq_stat_reg;
+
+ irq_stat_reg = (ip_rev == OMAP_I2C_REV_V1) ?
+ OMAP_I2C_STAT_REG : OMAP_I2C_IP_V2_IRQSTATUS_RAW;
+ do {
+ udelay(waitdelay);
+ status = omap_i2c_read_reg(i2c_base, ip_rev, irq_stat_reg);
+ } while (!(status &
+ (I2C_STAT_ROVR | I2C_STAT_XUDF | I2C_STAT_XRDY |
+ I2C_STAT_RRDY | I2C_STAT_ARDY | I2C_STAT_NACK |
+ I2C_STAT_AL)) && timeout--);
+
+ if (timeout <= 0) {
+ printf("Timed out in %s: status=%04x\n", __func__, status);
+ /*
+ * If status is still 0 here, probably the bus pads have
+ * not been configured for I2C, and/or pull-ups are missing.
+ */
+ printf("Check if pads/pull-ups of bus are properly configured\n");
+ omap_i2c_write_reg(i2c_base, ip_rev, 0xFFFF, OMAP_I2C_STAT_REG);
+ status = 0;
+ }
+
+ return status;
+}
+
+static void flush_fifo(void __iomem *i2c_base, int ip_rev)
+{
+ u16 stat;
+
+ /*
+ * note: if you try and read data when its not there or ready
+ * you get a bus error
+ */
+ while (1) {
+ stat = omap_i2c_read_reg(i2c_base, ip_rev, OMAP_I2C_STAT_REG);
+ if (stat == I2C_STAT_RRDY) {
+ omap_i2c_read_reg(i2c_base, ip_rev, OMAP_I2C_DATA_REG);
+ omap_i2c_write_reg(i2c_base, ip_rev,
+ I2C_STAT_RRDY, OMAP_I2C_STAT_REG);
+ udelay(1000);
+ } else
+ break;
+ }
+}
+
+static int __omap24_i2c_setspeed(void __iomem *i2c_base, int ip_rev, uint speed,
+ int *waitdelay)
+{
+ int psc, fsscll = 0, fssclh = 0;
+ int hsscll = 0, hssclh = 0;
+ u32 scll = 0, sclh = 0;
+
+ if (speed >= I2C_SPEED_HIGH_RATE) {
+ /* High speed */
+ psc = I2C_IP_CLK / I2C_INTERNAL_SAMPLING_CLK;
+ psc -= 1;
+ if (psc < I2C_PSC_MIN) {
+ printf("Error : I2C unsupported prescaler %d\n", psc);
+ return -1;
+ }
+
+ /* For first phase of HS mode */
+ fsscll = I2C_INTERNAL_SAMPLING_CLK / (2 * speed);
+
+ fssclh = fsscll;
+
+ fsscll -= I2C_HIGHSPEED_PHASE_ONE_SCLL_TRIM;
+ fssclh -= I2C_HIGHSPEED_PHASE_ONE_SCLH_TRIM;
+ if (((fsscll < 0) || (fssclh < 0)) ||
+ ((fsscll > 255) || (fssclh > 255))) {
+ puts("Error : I2C initializing first phase clock\n");
+ return -1;
+ }
+
+ /* For second phase of HS mode */
+ hsscll = hssclh = I2C_INTERNAL_SAMPLING_CLK / (2 * speed);
+
+ hsscll -= I2C_HIGHSPEED_PHASE_TWO_SCLL_TRIM;
+ hssclh -= I2C_HIGHSPEED_PHASE_TWO_SCLH_TRIM;
+ if (((fsscll < 0) || (fssclh < 0)) ||
+ ((fsscll > 255) || (fssclh > 255))) {
+ puts("Error : I2C initializing second phase clock\n");
+ return -1;
+ }
+
+ scll = (unsigned int)hsscll << 8 | (unsigned int)fsscll;
+ sclh = (unsigned int)hssclh << 8 | (unsigned int)fssclh;
+
+ } else {
+ /* Standard and fast speed */
+ psc = omap24_i2c_findpsc(&scll, &sclh, speed);
+ if (0 > psc) {
+ puts("Error : I2C initializing clock\n");
+ return -1;
+ }
+ }
+
+ /* wait for 20 clkperiods */
+ *waitdelay = (10000000 / speed) * 2;
+
+ omap_i2c_write_reg(i2c_base, ip_rev, 0, OMAP_I2C_CON_REG);
+ omap_i2c_write_reg(i2c_base, ip_rev, psc, OMAP_I2C_PSC_REG);
+ omap_i2c_write_reg(i2c_base, ip_rev, scll, OMAP_I2C_SCLL_REG);
+ omap_i2c_write_reg(i2c_base, ip_rev, sclh, OMAP_I2C_SCLH_REG);
+ omap_i2c_write_reg(i2c_base, ip_rev, I2C_CON_EN, OMAP_I2C_CON_REG);
+
+ /* clear all pending status */
+ omap_i2c_write_reg(i2c_base, ip_rev, 0xFFFF, OMAP_I2C_STAT_REG);
+
+ return 0;
+}
+
+static void omap24_i2c_deblock(void __iomem *i2c_base, int ip_rev)
+{
+ int i;
+ u16 systest;
+ u16 orgsystest;
+
+ /* set test mode ST_EN = 1 */
+ orgsystest = omap_i2c_read_reg(i2c_base, ip_rev, OMAP_I2C_SYSTEST_REG);
+ systest = orgsystest;
+
+ /* enable testmode */
+ systest |= I2C_SYSTEST_ST_EN;
+ omap_i2c_write_reg(i2c_base, ip_rev, systest, OMAP_I2C_SYSTEST_REG);
+ systest &= ~I2C_SYSTEST_TMODE_MASK;
+ systest |= 3 << I2C_SYSTEST_TMODE_SHIFT;
+ omap_i2c_write_reg(i2c_base, ip_rev, systest, OMAP_I2C_SYSTEST_REG);
+
+ /* set SCL, SDA = 1 */
+ systest |= I2C_SYSTEST_SCL_O | I2C_SYSTEST_SDA_O;
+ omap_i2c_write_reg(i2c_base, ip_rev, systest, OMAP_I2C_SYSTEST_REG);
+ udelay(10);
+
+ /* toggle scl 9 clocks */
+ for (i = 0; i < 9; i++) {
+ /* SCL = 0 */
+ systest &= ~I2C_SYSTEST_SCL_O;
+ omap_i2c_write_reg(i2c_base, ip_rev,
+ systest, OMAP_I2C_SYSTEST_REG);
+ udelay(10);
+ /* SCL = 1 */
+ systest |= I2C_SYSTEST_SCL_O;
+ omap_i2c_write_reg(i2c_base, ip_rev,
+ systest, OMAP_I2C_SYSTEST_REG);
+ udelay(10);
+ }
+
+ /* send stop */
+ systest &= ~I2C_SYSTEST_SDA_O;
+ omap_i2c_write_reg(i2c_base, ip_rev, systest, OMAP_I2C_SYSTEST_REG);
+ udelay(10);
+ systest |= I2C_SYSTEST_SCL_O | I2C_SYSTEST_SDA_O;
+ omap_i2c_write_reg(i2c_base, ip_rev, systest, OMAP_I2C_SYSTEST_REG);
+ udelay(10);
+
+ /* restore original mode */
+ omap_i2c_write_reg(i2c_base, ip_rev, orgsystest, OMAP_I2C_SYSTEST_REG);
+}
+
+static void __omap24_i2c_init(void __iomem *i2c_base, int ip_rev, int speed,
+ int slaveadd, int *waitdelay)
+{
+ int timeout = I2C_TIMEOUT;
+ int deblock = 1;
+
+retry:
+ if (omap_i2c_read_reg(i2c_base, ip_rev, OMAP_I2C_CON_REG) &
+ I2C_CON_EN) {
+ omap_i2c_write_reg(i2c_base, ip_rev, 0, OMAP_I2C_CON_REG);
+ udelay(50000);
+ }
+
+ /* for ES2 after soft reset */
+ omap_i2c_write_reg(i2c_base, ip_rev, 0x2, OMAP_I2C_SYSC_REG);
+ udelay(1000);
+
+ omap_i2c_write_reg(i2c_base, ip_rev, I2C_CON_EN, OMAP_I2C_CON_REG);
+ while (!(omap_i2c_read_reg(i2c_base, ip_rev, OMAP_I2C_SYSS_REG) &
+ I2C_SYSS_RDONE) && timeout--) {
+ if (timeout <= 0) {
+ puts("ERROR: Timeout in soft-reset\n");
+ return;
+ }
+ udelay(1000);
+ }
+
+ if (__omap24_i2c_setspeed(i2c_base, ip_rev, speed, waitdelay)) {
+ printf("ERROR: failed to setup I2C bus-speed!\n");
+ return;
+ }
+
+ /* own address */
+ omap_i2c_write_reg(i2c_base, ip_rev, slaveadd, OMAP_I2C_OA_REG);
+
+ if (ip_rev == OMAP_I2C_REV_V1) {
+ /*
+ * Have to enable interrupts for OMAP2/3, these IPs don't have
+ * an 'irqstatus_raw' register and we shall have to poll 'stat'
+ */
+ omap_i2c_write_reg(i2c_base, ip_rev, I2C_IE_XRDY_IE |
+ I2C_IE_RRDY_IE | I2C_IE_ARDY_IE |
+ I2C_IE_NACK_IE | I2C_IE_AL_IE,
+ OMAP_I2C_IE_REG);
+ }
+
+ udelay(1000);
+ flush_fifo(i2c_base, ip_rev);
+ omap_i2c_write_reg(i2c_base, ip_rev, 0xFFFF, OMAP_I2C_STAT_REG);
+
+ /* Handle possible failed I2C state */
+ if (wait_for_bb(i2c_base, ip_rev, *waitdelay))
+ if (deblock == 1) {
+ omap24_i2c_deblock(i2c_base, ip_rev);
+ deblock = 0;
+ goto retry;
+ }
+}
+
+/*
+ * i2c_probe: Use write access. Allows to identify addresses that are
+ * write-only (like the config register of dual-port EEPROMs)
+ */
+static int __omap24_i2c_probe(void __iomem *i2c_base, int ip_rev, int waitdelay,
+ uchar chip)
+{
+ u16 status;
+ int res = 1; /* default = fail */
+
+ if (chip == omap_i2c_read_reg(i2c_base, ip_rev, OMAP_I2C_OA_REG))
+ return res;
+
+ /* Wait until bus is free */
+ if (wait_for_bb(i2c_base, ip_rev, waitdelay))
+ return res;
+
+ /* No data transfer, slave addr only */
+ omap_i2c_write_reg(i2c_base, ip_rev, chip, OMAP_I2C_SA_REG);
+
+ /* Stop bit needed here */
+ omap_i2c_write_reg(i2c_base, ip_rev, I2C_CON_EN | I2C_CON_MST |
+ I2C_CON_STT | I2C_CON_TRX | I2C_CON_STP,
+ OMAP_I2C_CON_REG);
+
+ status = wait_for_event(i2c_base, ip_rev, waitdelay);
+
+ if ((status & ~I2C_STAT_XRDY) == 0 || (status & I2C_STAT_AL)) {
+ /*
+ * With current high-level command implementation, notifying
+ * the user shall flood the console with 127 messages. If
+ * silent exit is desired upon unconfigured bus, remove the
+ * following 'if' section:
+ */
+ if (status == I2C_STAT_XRDY)
+ printf("i2c_probe: pads on bus probably not configured (status=0x%x)\n",
+ status);
+
+ goto pr_exit;
+ }
+
+ /* Check for ACK (!NAK) */
+ if (!(status & I2C_STAT_NACK)) {
+ res = 0; /* Device found */
+ udelay(waitdelay);/* Required by AM335X in SPL */
+ /* Abort transfer (force idle state) */
+ omap_i2c_write_reg(i2c_base, ip_rev, I2C_CON_MST | I2C_CON_TRX,
+ OMAP_I2C_CON_REG); /* Reset */
+ udelay(1000);
+ omap_i2c_write_reg(i2c_base, ip_rev, I2C_CON_EN | I2C_CON_MST |
+ I2C_CON_TRX | I2C_CON_STP,
+ OMAP_I2C_CON_REG); /* STP */
+ }
+
+pr_exit:
+ flush_fifo(i2c_base, ip_rev);
+ omap_i2c_write_reg(i2c_base, ip_rev, 0xFFFF, OMAP_I2C_STAT_REG);
+ return res;
+}
+
+/*
+ * i2c_read: Function now uses a single I2C read transaction with bulk transfer
+ * of the requested number of bytes (note that the 'i2c md' command
+ * limits this to 16 bytes anyway). If CONFIG_I2C_REPEATED_START is
+ * defined in the board config header, this transaction shall be with
+ * Repeated Start (Sr) between the address and data phases; otherwise
+ * Stop-Start (P-S) shall be used (some I2C chips do require a P-S).
+ * The address (reg offset) may be 0, 1 or 2 bytes long.
+ * Function now reads correctly from chips that return more than one
+ * byte of data per addressed register (like TI temperature sensors),
+ * or that do not need a register address at all (such as some clock
+ * distributors).
+ */
+static int __omap24_i2c_read(void __iomem *i2c_base, int ip_rev, int waitdelay,
+ uchar chip, uint addr, int alen, uchar *buffer,
+ int len)
+{
+ int i2c_error = 0;
+ u16 status;
+
+ if (alen < 0) {
+ puts("I2C read: addr len < 0\n");
+ return 1;
+ }
+
+ if (len < 0) {
+ puts("I2C read: data len < 0\n");
+ return 1;
+ }
+
+ if (buffer == NULL) {
+ puts("I2C read: NULL pointer passed\n");
+ return 1;
+ }
+
+ if (alen > 2) {
+ printf("I2C read: addr len %d not supported\n", alen);
+ return 1;
+ }
+
+ if (addr + len > (1 << 16)) {
+ puts("I2C read: address out of range\n");
+ return 1;
+ }
+
+#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW
+ /*
+ * EEPROM chips that implement "address overflow" are ones
+ * like Catalyst 24WC04/08/16 which has 9/10/11 bits of
+ * address and the extra bits end up in the "chip address"
+ * bit slots. This makes a 24WC08 (1Kbyte) chip look like
+ * four 256 byte chips.
+ *
+ * Note that we consider the length of the address field to
+ * still be one byte because the extra address bits are
+ * hidden in the chip address.
+ */
+ if (alen > 0)
+ chip |= ((addr >> (alen * 8)) &
+ CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
+#endif
+
+ /* Wait until bus not busy */
+ if (wait_for_bb(i2c_base, ip_rev, waitdelay))
+ return 1;
+
+ /* Zero, one or two bytes reg address (offset) */
+ omap_i2c_write_reg(i2c_base, ip_rev, alen, OMAP_I2C_CNT_REG);
+ /* Set slave address */
+ omap_i2c_write_reg(i2c_base, ip_rev, chip, OMAP_I2C_SA_REG);
+
+ if (alen) {
+ /* Must write reg offset first */
+#ifdef CONFIG_I2C_REPEATED_START
+ /* No stop bit, use Repeated Start (Sr) */
+ omap_i2c_write_reg(i2c_base, ip_rev, I2C_CON_EN | I2C_CON_MST |
+ I2C_CON_STT | I2C_CON_TRX, OMAP_I2C_CON_REG);
+#else
+ /* Stop - Start (P-S) */
+ omap_i2c_write_reg(i2c_base, ip_rev, I2C_CON_EN | I2C_CON_MST |
+ I2C_CON_STT | I2C_CON_STP | I2C_CON_TRX,
+ OMAP_I2C_CON_REG);
+#endif
+ /* Send register offset */
+ while (1) {
+ status = wait_for_event(i2c_base, ip_rev, waitdelay);
+ /* Try to identify bus that is not padconf'd for I2C */
+ if (status == I2C_STAT_XRDY) {
+ i2c_error = 2;
+ printf("i2c_read (addr phase): pads on bus probably not configured (status=0x%x)\n",
+ status);
+ goto rd_exit;
+ }
+ if (status == 0 || (status & I2C_STAT_NACK)) {
+ i2c_error = 1;
+ printf("i2c_read: error waiting for addr ACK (status=0x%x)\n",
+ status);
+ goto rd_exit;
+ }
+ if (alen) {
+ if (status & I2C_STAT_XRDY) {
+ u8 addr_byte;
+ alen--;
+ addr_byte = (addr >> (8 * alen)) & 0xff;
+ omap_i2c_write_reg(i2c_base, ip_rev,
+ addr_byte,
+ OMAP_I2C_DATA_REG);
+ omap_i2c_write_reg(i2c_base, ip_rev,
+ I2C_STAT_XRDY,
+ OMAP_I2C_STAT_REG);
+ }
+ }
+ if (status & I2C_STAT_ARDY) {
+ omap_i2c_write_reg(i2c_base, ip_rev,
+ I2C_STAT_ARDY,
+ OMAP_I2C_STAT_REG);
+ break;
+ }
+ }
+ }
+
+ /* Set slave address */
+ omap_i2c_write_reg(i2c_base, ip_rev, chip, OMAP_I2C_SA_REG);
+ /* Read len bytes from slave */
+ omap_i2c_write_reg(i2c_base, ip_rev, len, OMAP_I2C_CNT_REG);
+ /* Need stop bit here */
+ omap_i2c_write_reg(i2c_base, ip_rev, I2C_CON_EN | I2C_CON_MST |
+ I2C_CON_STT | I2C_CON_STP, OMAP_I2C_CON_REG);
+
+ /* Receive data */
+ while (1) {
+ status = wait_for_event(i2c_base, ip_rev, waitdelay);
+ /*
+ * Try to identify bus that is not padconf'd for I2C. This
+ * state could be left over from previous transactions if
+ * the address phase is skipped due to alen=0.
+ */
+ if (status == I2C_STAT_XRDY) {
+ i2c_error = 2;
+ printf("i2c_read (data phase): pads on bus probably not configured (status=0x%x)\n",
+ status);
+ goto rd_exit;
+ }
+ if (status == 0 || (status & I2C_STAT_NACK)) {
+ i2c_error = 1;
+ goto rd_exit;
+ }
+ if (status & I2C_STAT_RRDY) {
+ *buffer++ = omap_i2c_read_reg(i2c_base, ip_rev,
+ OMAP_I2C_DATA_REG);
+ omap_i2c_write_reg(i2c_base, ip_rev,
+ I2C_STAT_RRDY, OMAP_I2C_STAT_REG);
+ }
+ if (status & I2C_STAT_ARDY) {
+ omap_i2c_write_reg(i2c_base, ip_rev,
+ I2C_STAT_ARDY, OMAP_I2C_STAT_REG);
+ break;
+ }
+ }
+
+rd_exit:
+ flush_fifo(i2c_base, ip_rev);
+ omap_i2c_write_reg(i2c_base, ip_rev, 0xFFFF, OMAP_I2C_STAT_REG);
+ return i2c_error;
+}
+
+/* i2c_write: Address (reg offset) may be 0, 1 or 2 bytes long. */
+static int __omap24_i2c_write(void __iomem *i2c_base, int ip_rev, int waitdelay,
+ uchar chip, uint addr, int alen, uchar *buffer,
+ int len)
+{
+ int i;
+ u16 status;
+ int i2c_error = 0;
+ int timeout = I2C_TIMEOUT;
+
+ if (alen < 0) {
+ puts("I2C write: addr len < 0\n");
+ return 1;
+ }
+
+ if (len < 0) {
+ puts("I2C write: data len < 0\n");
+ return 1;
+ }
+
+ if (buffer == NULL) {
+ puts("I2C write: NULL pointer passed\n");
+ return 1;
+ }
+
+ if (alen > 2) {
+ printf("I2C write: addr len %d not supported\n", alen);
+ return 1;
+ }
+
+ if (addr + len > (1 << 16)) {
+ printf("I2C write: address 0x%x + 0x%x out of range\n",
+ addr, len);
+ return 1;
+ }
+
+#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW
+ /*
+ * EEPROM chips that implement "address overflow" are ones
+ * like Catalyst 24WC04/08/16 which has 9/10/11 bits of
+ * address and the extra bits end up in the "chip address"
+ * bit slots. This makes a 24WC08 (1Kbyte) chip look like
+ * four 256 byte chips.
+ *
+ * Note that we consider the length of the address field to
+ * still be one byte because the extra address bits are
+ * hidden in the chip address.
+ */
+ if (alen > 0)
+ chip |= ((addr >> (alen * 8)) &
+ CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
+#endif
+
+ /* Wait until bus not busy */
+ if (wait_for_bb(i2c_base, ip_rev, waitdelay))
+ return 1;
+
+ /* Start address phase - will write regoffset + len bytes data */
+ omap_i2c_write_reg(i2c_base, ip_rev, alen + len, OMAP_I2C_CNT_REG);
+ /* Set slave address */
+ omap_i2c_write_reg(i2c_base, ip_rev, chip, OMAP_I2C_SA_REG);
+ /* Stop bit needed here */
+ omap_i2c_write_reg(i2c_base, ip_rev, I2C_CON_EN | I2C_CON_MST |
+ I2C_CON_STT | I2C_CON_TRX | I2C_CON_STP,
+ OMAP_I2C_CON_REG);
+
+ while (alen) {
+ /* Must write reg offset (one or two bytes) */
+ status = wait_for_event(i2c_base, ip_rev, waitdelay);
+ /* Try to identify bus that is not padconf'd for I2C */
+ if (status == I2C_STAT_XRDY) {
+ i2c_error = 2;
+ printf("i2c_write: pads on bus probably not configured (status=0x%x)\n",
+ status);
+ goto wr_exit;
+ }
+ if (status == 0 || (status & I2C_STAT_NACK)) {
+ i2c_error = 1;
+ printf("i2c_write: error waiting for addr ACK (status=0x%x)\n",
+ status);
+ goto wr_exit;
+ }
+ if (status & I2C_STAT_XRDY) {
+ alen--;
+ omap_i2c_write_reg(i2c_base, ip_rev,
+ (addr >> (8 * alen)) & 0xff,
+ OMAP_I2C_DATA_REG);
+ omap_i2c_write_reg(i2c_base, ip_rev,
+ I2C_STAT_XRDY, OMAP_I2C_STAT_REG);
+ } else {
+ i2c_error = 1;
+ printf("i2c_write: bus not ready for addr Tx (status=0x%x)\n",
+ status);
+ goto wr_exit;
+ }
+ }
+
+ /* Address phase is over, now write data */
+ for (i = 0; i < len; i++) {
+ status = wait_for_event(i2c_base, ip_rev, waitdelay);
+ if (status == 0 || (status & I2C_STAT_NACK)) {
+ i2c_error = 1;
+ printf("i2c_write: error waiting for data ACK (status=0x%x)\n",
+ status);
+ goto wr_exit;
+ }
+ if (status & I2C_STAT_XRDY) {
+ omap_i2c_write_reg(i2c_base, ip_rev,
+ buffer[i], OMAP_I2C_DATA_REG);
+ omap_i2c_write_reg(i2c_base, ip_rev,
+ I2C_STAT_XRDY, OMAP_I2C_STAT_REG);
+ } else {
+ i2c_error = 1;
+ printf("i2c_write: bus not ready for data Tx (i=%d)\n",
+ i);
+ goto wr_exit;
+ }
+ }
+
+ /*
+ * poll ARDY bit for making sure that last byte really has been
+ * transferred on the bus.
+ */
+ do {
+ status = wait_for_event(i2c_base, ip_rev, waitdelay);
+ } while (!(status & I2C_STAT_ARDY) && timeout--);
+ if (timeout <= 0)
+ printf("i2c_write: timed out writig last byte!\n");
+
+wr_exit:
+ flush_fifo(i2c_base, ip_rev);
+ omap_i2c_write_reg(i2c_base, ip_rev, 0xFFFF, OMAP_I2C_STAT_REG);
+ return i2c_error;
+}
+
+#if !CONFIG_IS_ENABLED(DM_I2C)
+/*
+ * The legacy I2C functions. These need to get removed once
+ * all users of this driver are converted to DM.
+ */
+static void __iomem *omap24_get_base(struct i2c_adapter *adap)
+{
+ switch (adap->hwadapnr) {
+ case 0:
+ return (void __iomem *)I2C_BASE1;
+ break;
+ case 1:
+ return (void __iomem *)I2C_BASE2;
+ break;
+#if (CONFIG_SYS_I2C_BUS_MAX > 2)
+ case 2:
+ return (void __iomem *)I2C_BASE3;
+ break;
+#if (CONFIG_SYS_I2C_BUS_MAX > 3)
+ case 3:
+ return (void __iomem *)I2C_BASE4;
+ break;
+#if (CONFIG_SYS_I2C_BUS_MAX > 4)
+ case 4:
+ return (void __iomem *)I2C_BASE5;
+ break;
+#endif
+#endif
+#endif
+ default:
+ printf("wrong hwadapnr: %d\n", adap->hwadapnr);
+ break;
+ }
+
+ return NULL;
+}
+
+static int omap24_get_ip_rev(void)
+{
+#ifdef CONFIG_OMAP34XX
+ return OMAP_I2C_REV_V1;
+#else
+ return OMAP_I2C_REV_V2;
+#endif
+}
+
+static int omap24_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
+ int alen, uchar *buffer, int len)
+{
+ void __iomem *i2c_base = omap24_get_base(adap);
+ int ip_rev = omap24_get_ip_rev();
+
+ return __omap24_i2c_read(i2c_base, ip_rev, adap->waitdelay, chip, addr,
+ alen, buffer, len);
+}
+
+static int omap24_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
+ int alen, uchar *buffer, int len)
+{
+ void __iomem *i2c_base = omap24_get_base(adap);
+ int ip_rev = omap24_get_ip_rev();
+
+ return __omap24_i2c_write(i2c_base, ip_rev, adap->waitdelay, chip, addr,
+ alen, buffer, len);
+}
+
+static uint omap24_i2c_setspeed(struct i2c_adapter *adap, uint speed)
+{
+ void __iomem *i2c_base = omap24_get_base(adap);
+ int ip_rev = omap24_get_ip_rev();
+ int ret;
+
+ ret = __omap24_i2c_setspeed(i2c_base, ip_rev, speed, &adap->waitdelay);
+ if (ret) {
+ pr_err("%s: set i2c speed failed\n", __func__);
+ return ret;
+ }
+
+ adap->speed = speed;
+
+ return 0;
+}
+
+static void omap24_i2c_init(struct i2c_adapter *adap, int speed, int slaveadd)
+{
+ void __iomem *i2c_base = omap24_get_base(adap);
+ int ip_rev = omap24_get_ip_rev();
+
+ return __omap24_i2c_init(i2c_base, ip_rev, speed, slaveadd,
+ &adap->waitdelay);
+}
+
+static int omap24_i2c_probe(struct i2c_adapter *adap, uchar chip)
+{
+ void __iomem *i2c_base = omap24_get_base(adap);
+ int ip_rev = omap24_get_ip_rev();
+
+ return __omap24_i2c_probe(i2c_base, ip_rev, adap->waitdelay, chip);
+}
+
+#if !defined(CONFIG_SYS_OMAP24_I2C_SPEED1)
+#define CONFIG_SYS_OMAP24_I2C_SPEED1 CONFIG_SYS_OMAP24_I2C_SPEED
+#endif
+#if !defined(CONFIG_SYS_OMAP24_I2C_SLAVE1)
+#define CONFIG_SYS_OMAP24_I2C_SLAVE1 CONFIG_SYS_OMAP24_I2C_SLAVE
+#endif
+
+U_BOOT_I2C_ADAP_COMPLETE(omap24_0, omap24_i2c_init, omap24_i2c_probe,
+ omap24_i2c_read, omap24_i2c_write, omap24_i2c_setspeed,
+ CONFIG_SYS_OMAP24_I2C_SPEED,
+ CONFIG_SYS_OMAP24_I2C_SLAVE,
+ 0)
+U_BOOT_I2C_ADAP_COMPLETE(omap24_1, omap24_i2c_init, omap24_i2c_probe,
+ omap24_i2c_read, omap24_i2c_write, omap24_i2c_setspeed,
+ CONFIG_SYS_OMAP24_I2C_SPEED1,
+ CONFIG_SYS_OMAP24_I2C_SLAVE1,
+ 1)
+
+#if (CONFIG_SYS_I2C_BUS_MAX > 2)
+#if !defined(CONFIG_SYS_OMAP24_I2C_SPEED2)
+#define CONFIG_SYS_OMAP24_I2C_SPEED2 CONFIG_SYS_OMAP24_I2C_SPEED
+#endif
+#if !defined(CONFIG_SYS_OMAP24_I2C_SLAVE2)
+#define CONFIG_SYS_OMAP24_I2C_SLAVE2 CONFIG_SYS_OMAP24_I2C_SLAVE
+#endif
+
+U_BOOT_I2C_ADAP_COMPLETE(omap24_2, omap24_i2c_init, omap24_i2c_probe,
+ omap24_i2c_read, omap24_i2c_write, NULL,
+ CONFIG_SYS_OMAP24_I2C_SPEED2,
+ CONFIG_SYS_OMAP24_I2C_SLAVE2,
+ 2)
+#if (CONFIG_SYS_I2C_BUS_MAX > 3)
+#if !defined(CONFIG_SYS_OMAP24_I2C_SPEED3)
+#define CONFIG_SYS_OMAP24_I2C_SPEED3 CONFIG_SYS_OMAP24_I2C_SPEED
+#endif
+#if !defined(CONFIG_SYS_OMAP24_I2C_SLAVE3)
+#define CONFIG_SYS_OMAP24_I2C_SLAVE3 CONFIG_SYS_OMAP24_I2C_SLAVE
+#endif
+
+U_BOOT_I2C_ADAP_COMPLETE(omap24_3, omap24_i2c_init, omap24_i2c_probe,
+ omap24_i2c_read, omap24_i2c_write, NULL,
+ CONFIG_SYS_OMAP24_I2C_SPEED3,
+ CONFIG_SYS_OMAP24_I2C_SLAVE3,
+ 3)
+#if (CONFIG_SYS_I2C_BUS_MAX > 4)
+#if !defined(CONFIG_SYS_OMAP24_I2C_SPEED4)
+#define CONFIG_SYS_OMAP24_I2C_SPEED4 CONFIG_SYS_OMAP24_I2C_SPEED
+#endif
+#if !defined(CONFIG_SYS_OMAP24_I2C_SLAVE4)
+#define CONFIG_SYS_OMAP24_I2C_SLAVE4 CONFIG_SYS_OMAP24_I2C_SLAVE
+#endif
+
+U_BOOT_I2C_ADAP_COMPLETE(omap24_4, omap24_i2c_init, omap24_i2c_probe,
+ omap24_i2c_read, omap24_i2c_write, NULL,
+ CONFIG_SYS_OMAP24_I2C_SPEED4,
+ CONFIG_SYS_OMAP24_I2C_SLAVE4,
+ 4)
+#endif
+#endif
+#endif
+
+#else /* CONFIG_DM_I2C */
+
+static int omap_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
+{
+ struct omap_i2c *priv = dev_get_priv(bus);
+ int ret;
+
+ debug("i2c_xfer: %d messages\n", nmsgs);
+ for (; nmsgs > 0; nmsgs--, msg++) {
+ debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
+ if (msg->flags & I2C_M_RD) {
+ ret = __omap24_i2c_read(priv->regs, priv->ip_rev,
+ priv->waitdelay,
+ msg->addr, 0, 0, msg->buf,
+ msg->len);
+ } else {
+ ret = __omap24_i2c_write(priv->regs, priv->ip_rev,
+ priv->waitdelay,
+ msg->addr, 0, 0, msg->buf,
+ msg->len);
+ }
+ if (ret) {
+ debug("i2c_write: error sending\n");
+ return -EREMOTEIO;
+ }
+ }
+
+ return 0;
+}
+
+static int omap_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
+{
+ struct omap_i2c *priv = dev_get_priv(bus);
+
+ priv->speed = speed;
+
+ return __omap24_i2c_setspeed(priv->regs, priv->ip_rev, speed,
+ &priv->waitdelay);
+}
+
+static int omap_i2c_probe_chip(struct udevice *bus, uint chip_addr,
+ uint chip_flags)
+{
+ struct omap_i2c *priv = dev_get_priv(bus);
+
+ return __omap24_i2c_probe(priv->regs, priv->ip_rev, priv->waitdelay,
+ chip_addr);
+}
+
+static int omap_i2c_probe(struct udevice *bus)
+{
+ struct omap_i2c *priv = dev_get_priv(bus);
+ struct omap_i2c_plat *plat = dev_get_plat(bus);
+
+ priv->speed = plat->speed;
+ priv->regs = map_physmem(plat->base, sizeof(void *),
+ MAP_NOCACHE);
+ priv->ip_rev = plat->ip_rev;
+
+ __omap24_i2c_init(priv->regs, priv->ip_rev, priv->speed, 0,
+ &priv->waitdelay);
+
+ return 0;
+}
+
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
+static int omap_i2c_of_to_plat(struct udevice *bus)
+{
+ struct omap_i2c_plat *plat = dev_get_plat(bus);
+
+ plat->base = dev_read_addr(bus);
+ plat->speed = dev_read_u32_default(bus, "clock-frequency",
+ I2C_SPEED_STANDARD_RATE);
+ plat->ip_rev = dev_get_driver_data(bus);
+
+ return 0;
+}
+
+static const struct udevice_id omap_i2c_ids[] = {
+ { .compatible = "ti,omap3-i2c", .data = OMAP_I2C_REV_V1 },
+ { .compatible = "ti,omap4-i2c", .data = OMAP_I2C_REV_V2 },
+ { }
+};
+#endif
+
+static const struct dm_i2c_ops omap_i2c_ops = {
+ .xfer = omap_i2c_xfer,
+ .probe_chip = omap_i2c_probe_chip,
+ .set_bus_speed = omap_i2c_set_bus_speed,
+};
+
+U_BOOT_DRIVER(i2c_omap) = {
+ .name = "i2c_omap",
+ .id = UCLASS_I2C,
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
+ .of_match = omap_i2c_ids,
+ .of_to_plat = omap_i2c_of_to_plat,
+ .plat_auto = sizeof(struct omap_i2c_plat),
+#endif
+ .probe = omap_i2c_probe,
+ .priv_auto = sizeof(struct omap_i2c),
+ .ops = &omap_i2c_ops,
+#if !CONFIG_IS_ENABLED(OF_CONTROL)
+ .flags = DM_FLAG_PRE_RELOC,
+#endif
+};
+
+#endif /* CONFIG_DM_I2C */
diff --git a/roms/u-boot/drivers/i2c/omap24xx_i2c.h b/roms/u-boot/drivers/i2c/omap24xx_i2c.h
new file mode 100644
index 000000000..6904f2d9a
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/omap24xx_i2c.h
@@ -0,0 +1,149 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2004-2010
+ * Texas Instruments, <www.ti.com>
+ */
+#ifndef _OMAP2PLUS_I2C_H_
+#define _OMAP2PLUS_I2C_H_
+
+/* I2C masks */
+
+/* I2C Interrupt Enable Register (I2C_IE): */
+#define I2C_IE_GC_IE (1 << 5)
+#define I2C_IE_XRDY_IE (1 << 4) /* Transmit data ready interrupt enable */
+#define I2C_IE_RRDY_IE (1 << 3) /* Receive data ready interrupt enable */
+#define I2C_IE_ARDY_IE (1 << 2) /* Register access ready interrupt enable */
+#define I2C_IE_NACK_IE (1 << 1) /* No acknowledgment interrupt enable */
+#define I2C_IE_AL_IE (1 << 0) /* Arbitration lost interrupt enable */
+
+/* I2C Status Register (I2C_STAT): */
+
+#define I2C_STAT_SBD (1 << 15) /* Single byte data */
+#define I2C_STAT_BB (1 << 12) /* Bus busy */
+#define I2C_STAT_ROVR (1 << 11) /* Receive overrun */
+#define I2C_STAT_XUDF (1 << 10) /* Transmit underflow */
+#define I2C_STAT_AAS (1 << 9) /* Address as slave */
+#define I2C_STAT_GC (1 << 5)
+#define I2C_STAT_XRDY (1 << 4) /* Transmit data ready */
+#define I2C_STAT_RRDY (1 << 3) /* Receive data ready */
+#define I2C_STAT_ARDY (1 << 2) /* Register access ready */
+#define I2C_STAT_NACK (1 << 1) /* No acknowledgment interrupt enable */
+#define I2C_STAT_AL (1 << 0) /* Arbitration lost interrupt enable */
+
+/* I2C Interrupt Code Register (I2C_INTCODE): */
+
+#define I2C_INTCODE_MASK 7
+#define I2C_INTCODE_NONE 0
+#define I2C_INTCODE_AL 1 /* Arbitration lost */
+#define I2C_INTCODE_NAK 2 /* No acknowledgement/general call */
+#define I2C_INTCODE_ARDY 3 /* Register access ready */
+#define I2C_INTCODE_RRDY 4 /* Rcv data ready */
+#define I2C_INTCODE_XRDY 5 /* Xmit data ready */
+
+/* I2C Buffer Configuration Register (I2C_BUF): */
+
+#define I2C_BUF_RDMA_EN (1 << 15) /* Receive DMA channel enable */
+#define I2C_BUF_XDMA_EN (1 << 7) /* Transmit DMA channel enable */
+
+/* I2C Configuration Register (I2C_CON): */
+
+#define I2C_CON_EN (1 << 15) /* I2C module enable */
+#define I2C_CON_BE (1 << 14) /* Big endian mode */
+#define I2C_CON_STB (1 << 11) /* Start byte mode (master mode only) */
+#define I2C_CON_MST (1 << 10) /* Master/slave mode */
+#define I2C_CON_TRX (1 << 9) /* Transmitter/receiver mode */
+ /* (master mode only) */
+#define I2C_CON_XA (1 << 8) /* Expand address */
+#define I2C_CON_STP (1 << 1) /* Stop condition (master mode only) */
+#define I2C_CON_STT (1 << 0) /* Start condition (master mode only) */
+
+/* I2C System Test Register (I2C_SYSTEST): */
+
+#define I2C_SYSTEST_ST_EN (1 << 15) /* System test enable */
+#define I2C_SYSTEST_FREE (1 << 14) /* Free running mode, on brkpoint) */
+#define I2C_SYSTEST_TMODE_MASK (3 << 12) /* Test mode select */
+#define I2C_SYSTEST_TMODE_SHIFT (12) /* Test mode select */
+#define I2C_SYSTEST_SCL_I (1 << 3) /* SCL line sense input value */
+#define I2C_SYSTEST_SCL_O (1 << 2) /* SCL line drive output value */
+#define I2C_SYSTEST_SDA_I (1 << 1) /* SDA line sense input value */
+#define I2C_SYSTEST_SDA_O (1 << 0) /* SDA line drive output value */
+
+/* I2C System Status Register (I2C_SYSS): */
+
+#define I2C_SYSS_RDONE (1 << 0) /* Internel reset monitoring */
+
+#define I2C_SCLL_SCLL 0
+#define I2C_SCLL_SCLL_M 0xFF
+#define I2C_SCLL_HSSCLL 8
+#define I2C_SCLH_HSSCLL_M 0xFF
+#define I2C_SCLH_SCLH 0
+#define I2C_SCLH_SCLH_M 0xFF
+#define I2C_SCLH_HSSCLH 8
+#define I2C_SCLH_HSSCLH_M 0xFF
+
+#define SYSTEM_CLOCK_12 12000000
+#define SYSTEM_CLOCK_13 13000000
+#define SYSTEM_CLOCK_192 19200000
+#define SYSTEM_CLOCK_96 96000000
+
+/* Use the reference value of 96MHz if not explicitly set by the board */
+#ifndef I2C_IP_CLK
+#define I2C_IP_CLK SYSTEM_CLOCK_96
+#endif
+
+/*
+ * The reference minimum clock for high speed is 19.2MHz.
+ * The linux 2.6.30 kernel uses this value.
+ * The reference minimum clock for fast mode is 9.6MHz
+ * The reference minimum clock for standard mode is 4MHz
+ * In TRM, the value of 12MHz is used.
+ */
+#ifndef I2C_INTERNAL_SAMPLING_CLK
+#define I2C_INTERNAL_SAMPLING_CLK 19200000
+#endif
+
+/*
+ * The equation for the low and high time is
+ * tlow = scll + scll_trim = (sampling clock * tlow_duty) / speed
+ * thigh = sclh + sclh_trim = (sampling clock * (1 - tlow_duty)) / speed
+ *
+ * If the duty cycle is 50%
+ *
+ * tlow = scll + scll_trim = sampling clock / (2 * speed)
+ * thigh = sclh + sclh_trim = sampling clock / (2 * speed)
+ *
+ * In TRM
+ * scll_trim = 7
+ * sclh_trim = 5
+ *
+ * The linux 4.9 kernel uses
+ * scll_trim = 7
+ * sclh_trim = 5
+ *
+ * These are the trim values for standard and fast speed
+ */
+#ifndef I2C_FASTSPEED_SCLL_TRIM
+#define I2C_FASTSPEED_SCLL_TRIM 7
+#endif
+#ifndef I2C_FASTSPEED_SCLH_TRIM
+#define I2C_FASTSPEED_SCLH_TRIM 5
+#endif
+
+/* These are the trim values for high speed */
+#ifndef I2C_HIGHSPEED_PHASE_ONE_SCLL_TRIM
+#define I2C_HIGHSPEED_PHASE_ONE_SCLL_TRIM I2C_FASTSPEED_SCLL_TRIM
+#endif
+#ifndef I2C_HIGHSPEED_PHASE_ONE_SCLH_TRIM
+#define I2C_HIGHSPEED_PHASE_ONE_SCLH_TRIM I2C_FASTSPEED_SCLH_TRIM
+#endif
+#ifndef I2C_HIGHSPEED_PHASE_TWO_SCLL_TRIM
+#define I2C_HIGHSPEED_PHASE_TWO_SCLL_TRIM I2C_FASTSPEED_SCLL_TRIM
+#endif
+#ifndef I2C_HIGHSPEED_PHASE_TWO_SCLH_TRIM
+#define I2C_HIGHSPEED_PHASE_TWO_SCLH_TRIM I2C_FASTSPEED_SCLH_TRIM
+#endif
+
+#define I2C_PSC_MAX 0x0f
+#define I2C_PSC_MIN 0x00
+
+#endif /* _OMAP24XX_I2C_H_ */
diff --git a/roms/u-boot/drivers/i2c/rcar_i2c.c b/roms/u-boot/drivers/i2c/rcar_i2c.c
new file mode 100644
index 000000000..14bb6603d
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/rcar_i2c.c
@@ -0,0 +1,376 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * drivers/i2c/rcar_i2c.c
+ *
+ * Copyright (C) 2018 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * Clock configuration based on Linux i2c-rcar.c:
+ * Copyright (C) 2014-15 Wolfram Sang <wsa@sang-engineering.com>
+ * Copyright (C) 2011-2015 Renesas Electronics Corporation
+ * Copyright (C) 2012-14 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <i2c.h>
+#include <asm/io.h>
+#include <wait_bit.h>
+#include <dm/device_compat.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+
+#define RCAR_I2C_ICSCR 0x00 /* slave ctrl */
+#define RCAR_I2C_ICMCR 0x04 /* master ctrl */
+#define RCAR_I2C_ICMCR_MDBS BIT(7) /* non-fifo mode switch */
+#define RCAR_I2C_ICMCR_FSCL BIT(6) /* override SCL pin */
+#define RCAR_I2C_ICMCR_FSDA BIT(5) /* override SDA pin */
+#define RCAR_I2C_ICMCR_OBPC BIT(4) /* override pins */
+#define RCAR_I2C_ICMCR_MIE BIT(3) /* master if enable */
+#define RCAR_I2C_ICMCR_TSBE BIT(2)
+#define RCAR_I2C_ICMCR_FSB BIT(1) /* force stop bit */
+#define RCAR_I2C_ICMCR_ESG BIT(0) /* enable start bit gen */
+#define RCAR_I2C_ICSSR 0x08 /* slave status */
+#define RCAR_I2C_ICMSR 0x0c /* master status */
+#define RCAR_I2C_ICMSR_MASK 0x7f
+#define RCAR_I2C_ICMSR_MNR BIT(6) /* Nack */
+#define RCAR_I2C_ICMSR_MAL BIT(5) /* Arbitration lost */
+#define RCAR_I2C_ICMSR_MST BIT(4) /* Stop */
+#define RCAR_I2C_ICMSR_MDE BIT(3)
+#define RCAR_I2C_ICMSR_MDT BIT(2)
+#define RCAR_I2C_ICMSR_MDR BIT(1)
+#define RCAR_I2C_ICMSR_MAT BIT(0)
+#define RCAR_I2C_ICSIER 0x10 /* slave irq enable */
+#define RCAR_I2C_ICMIER 0x14 /* master irq enable */
+#define RCAR_I2C_ICCCR 0x18 /* clock dividers */
+#define RCAR_I2C_ICCCR_SCGD_OFF 3
+#define RCAR_I2C_ICSAR 0x1c /* slave address */
+#define RCAR_I2C_ICMAR 0x20 /* master address */
+#define RCAR_I2C_ICRXD_ICTXD 0x24 /* data port */
+/*
+ * First Bit Setup Cycle (Gen3).
+ * Defines 1st bit delay between SDA and SCL.
+ */
+#define RCAR_I2C_ICFBSCR 0x38
+#define RCAR_I2C_ICFBSCR_TCYC17 0x0f /* 17*Tcyc */
+
+
+enum rcar_i2c_type {
+ RCAR_I2C_TYPE_GEN2,
+ RCAR_I2C_TYPE_GEN3,
+};
+
+struct rcar_i2c_priv {
+ void __iomem *base;
+ struct clk clk;
+ u32 intdelay;
+ u32 icccr;
+ enum rcar_i2c_type type;
+};
+
+static int rcar_i2c_finish(struct udevice *dev)
+{
+ struct rcar_i2c_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = wait_for_bit_le32(priv->base + RCAR_I2C_ICMSR, RCAR_I2C_ICMSR_MST,
+ true, 10, true);
+
+ writel(0, priv->base + RCAR_I2C_ICSSR);
+ writel(0, priv->base + RCAR_I2C_ICMSR);
+ writel(0, priv->base + RCAR_I2C_ICMCR);
+
+ return ret;
+}
+
+static int rcar_i2c_recover(struct udevice *dev)
+{
+ struct rcar_i2c_priv *priv = dev_get_priv(dev);
+ u32 mcr = RCAR_I2C_ICMCR_MDBS | RCAR_I2C_ICMCR_OBPC;
+ u32 mcra = mcr | RCAR_I2C_ICMCR_FSDA;
+ int i;
+ u32 mstat;
+
+ /* Send 9 SCL pulses */
+ for (i = 0; i < 9; i++) {
+ writel(mcra | RCAR_I2C_ICMCR_FSCL, priv->base + RCAR_I2C_ICMCR);
+ udelay(5);
+ writel(mcra, priv->base + RCAR_I2C_ICMCR);
+ udelay(5);
+ }
+
+ /* Send stop condition */
+ udelay(5);
+ writel(mcra, priv->base + RCAR_I2C_ICMCR);
+ udelay(5);
+ writel(mcr, priv->base + RCAR_I2C_ICMCR);
+ udelay(5);
+ writel(mcr | RCAR_I2C_ICMCR_FSCL, priv->base + RCAR_I2C_ICMCR);
+ udelay(5);
+ writel(mcra | RCAR_I2C_ICMCR_FSCL, priv->base + RCAR_I2C_ICMCR);
+ udelay(5);
+
+ mstat = readl(priv->base + RCAR_I2C_ICMSR);
+ return mstat & RCAR_I2C_ICMCR_FSDA ? -EBUSY : 0;
+}
+
+static int rcar_i2c_set_addr(struct udevice *dev, u8 chip, u8 read)
+{
+ struct rcar_i2c_priv *priv = dev_get_priv(dev);
+ u32 mask = RCAR_I2C_ICMSR_MAT |
+ (read ? RCAR_I2C_ICMSR_MDR : RCAR_I2C_ICMSR_MDE);
+ int ret;
+
+ writel(0, priv->base + RCAR_I2C_ICMIER);
+ writel(RCAR_I2C_ICMCR_MDBS, priv->base + RCAR_I2C_ICMCR);
+ writel(0, priv->base + RCAR_I2C_ICMSR);
+ writel(priv->icccr, priv->base + RCAR_I2C_ICCCR);
+
+ /* Wait for the bus */
+ ret = wait_for_bit_le32(priv->base + RCAR_I2C_ICMCR,
+ RCAR_I2C_ICMCR_FSDA, false, 2, true);
+ if (ret) {
+ if (rcar_i2c_recover(dev)) {
+ dev_err(dev, "Bus busy, aborting\n");
+ return ret;
+ }
+ }
+
+ writel((chip << 1) | read, priv->base + RCAR_I2C_ICMAR);
+ /* Reset */
+ writel(RCAR_I2C_ICMCR_MDBS | RCAR_I2C_ICMCR_MIE | RCAR_I2C_ICMCR_ESG,
+ priv->base + RCAR_I2C_ICMCR);
+ /* Clear Status */
+ writel(0, priv->base + RCAR_I2C_ICMSR);
+
+ ret = wait_for_bit_le32(priv->base + RCAR_I2C_ICMSR, mask,
+ true, 100, true);
+ if (ret)
+ return ret;
+
+ /* Check NAK */
+ if (readl(priv->base + RCAR_I2C_ICMSR) & RCAR_I2C_ICMSR_MNR)
+ return -EREMOTEIO;
+
+ return 0;
+}
+
+static int rcar_i2c_read_common(struct udevice *dev, struct i2c_msg *msg)
+{
+ struct rcar_i2c_priv *priv = dev_get_priv(dev);
+ u32 icmcr = RCAR_I2C_ICMCR_MDBS | RCAR_I2C_ICMCR_MIE;
+ int i, ret = -EREMOTEIO;
+
+ for (i = 0; i < msg->len; i++) {
+ if (msg->len - 1 == i)
+ icmcr |= RCAR_I2C_ICMCR_FSB;
+
+ writel(icmcr, priv->base + RCAR_I2C_ICMCR);
+ writel((u32)~RCAR_I2C_ICMSR_MDR, priv->base + RCAR_I2C_ICMSR);
+
+ ret = wait_for_bit_le32(priv->base + RCAR_I2C_ICMSR,
+ RCAR_I2C_ICMSR_MDR, true, 100, true);
+ if (ret)
+ return ret;
+
+ msg->buf[i] = readl(priv->base + RCAR_I2C_ICRXD_ICTXD) & 0xff;
+ }
+
+ writel((u32)~RCAR_I2C_ICMSR_MDR, priv->base + RCAR_I2C_ICMSR);
+
+ return rcar_i2c_finish(dev);
+}
+
+static int rcar_i2c_write_common(struct udevice *dev, struct i2c_msg *msg)
+{
+ struct rcar_i2c_priv *priv = dev_get_priv(dev);
+ u32 icmcr = RCAR_I2C_ICMCR_MDBS | RCAR_I2C_ICMCR_MIE;
+ int i, ret = -EREMOTEIO;
+
+ for (i = 0; i < msg->len; i++) {
+ writel(msg->buf[i], priv->base + RCAR_I2C_ICRXD_ICTXD);
+ writel(icmcr, priv->base + RCAR_I2C_ICMCR);
+ writel((u32)~RCAR_I2C_ICMSR_MDE, priv->base + RCAR_I2C_ICMSR);
+
+ ret = wait_for_bit_le32(priv->base + RCAR_I2C_ICMSR,
+ RCAR_I2C_ICMSR_MDE, true, 100, true);
+ if (ret)
+ return ret;
+ }
+
+ writel((u32)~RCAR_I2C_ICMSR_MDE, priv->base + RCAR_I2C_ICMSR);
+ icmcr |= RCAR_I2C_ICMCR_FSB;
+ writel(icmcr, priv->base + RCAR_I2C_ICMCR);
+
+ return rcar_i2c_finish(dev);
+}
+
+static int rcar_i2c_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs)
+{
+ int ret;
+
+ for (; nmsgs > 0; nmsgs--, msg++) {
+ ret = rcar_i2c_set_addr(dev, msg->addr, !!(msg->flags & I2C_M_RD));
+ if (ret)
+ return ret;
+
+ if (msg->flags & I2C_M_RD)
+ ret = rcar_i2c_read_common(dev, msg);
+ else
+ ret = rcar_i2c_write_common(dev, msg);
+
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int rcar_i2c_probe_chip(struct udevice *dev, uint addr, uint flags)
+{
+ struct rcar_i2c_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ /* Ignore address 0, slave address */
+ if (addr == 0)
+ return -EINVAL;
+
+ ret = rcar_i2c_set_addr(dev, addr, 1);
+ writel(0, priv->base + RCAR_I2C_ICMSR);
+ return ret;
+}
+
+static int rcar_i2c_set_speed(struct udevice *dev, uint bus_freq_hz)
+{
+ struct rcar_i2c_priv *priv = dev_get_priv(dev);
+ u32 scgd, cdf, round, ick, sum, scl;
+ unsigned long rate;
+
+ /*
+ * calculate SCL clock
+ * see
+ * ICCCR
+ *
+ * ick = clkp / (1 + CDF)
+ * SCL = ick / (20 + SCGD * 8 + F[(ticf + tr + intd) * ick])
+ *
+ * ick : I2C internal clock < 20 MHz
+ * ticf : I2C SCL falling time
+ * tr : I2C SCL rising time
+ * intd : LSI internal delay
+ * clkp : peripheral_clk
+ * F[] : integer up-valuation
+ */
+ rate = clk_get_rate(&priv->clk);
+ cdf = rate / 20000000;
+ if (cdf >= 8) {
+ dev_err(dev, "Input clock %lu too high\n", rate);
+ return -EIO;
+ }
+ ick = rate / (cdf + 1);
+
+ /*
+ * it is impossible to calculate large scale
+ * number on u32. separate it
+ *
+ * F[(ticf + tr + intd) * ick] with sum = (ticf + tr + intd)
+ * = F[sum * ick / 1000000000]
+ * = F[(ick / 1000000) * sum / 1000]
+ */
+ sum = 35 + 200 + priv->intdelay;
+ round = (ick + 500000) / 1000000 * sum;
+ round = (round + 500) / 1000;
+
+ /*
+ * SCL = ick / (20 + SCGD * 8 + F[(ticf + tr + intd) * ick])
+ *
+ * Calculation result (= SCL) should be less than
+ * bus_speed for hardware safety
+ *
+ * We could use something along the lines of
+ * div = ick / (bus_speed + 1) + 1;
+ * scgd = (div - 20 - round + 7) / 8;
+ * scl = ick / (20 + (scgd * 8) + round);
+ * (not fully verified) but that would get pretty involved
+ */
+ for (scgd = 0; scgd < 0x40; scgd++) {
+ scl = ick / (20 + (scgd * 8) + round);
+ if (scl <= bus_freq_hz)
+ goto scgd_find;
+ }
+ dev_err(dev, "it is impossible to calculate best SCL\n");
+ return -EIO;
+
+scgd_find:
+ dev_dbg(dev, "clk %d/%d(%lu), round %u, CDF:0x%x, SCGD: 0x%x\n",
+ scl, bus_freq_hz, clk_get_rate(&priv->clk), round, cdf, scgd);
+
+ priv->icccr = (scgd << RCAR_I2C_ICCCR_SCGD_OFF) | cdf;
+ writel(priv->icccr, priv->base + RCAR_I2C_ICCCR);
+
+ if (priv->type == RCAR_I2C_TYPE_GEN3) {
+ /* Set SCL/SDA delay */
+ writel(RCAR_I2C_ICFBSCR_TCYC17, priv->base + RCAR_I2C_ICFBSCR);
+ }
+
+ return 0;
+}
+
+static int rcar_i2c_probe(struct udevice *dev)
+{
+ struct rcar_i2c_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ priv->base = dev_read_addr_ptr(dev);
+ priv->intdelay = dev_read_u32_default(dev,
+ "i2c-scl-internal-delay-ns", 5);
+ priv->type = dev_get_driver_data(dev);
+
+ ret = clk_get_by_index(dev, 0, &priv->clk);
+ if (ret)
+ return ret;
+
+ ret = clk_enable(&priv->clk);
+ if (ret)
+ return ret;
+
+ /* reset slave mode */
+ writel(0, priv->base + RCAR_I2C_ICSIER);
+ writel(0, priv->base + RCAR_I2C_ICSAR);
+ writel(0, priv->base + RCAR_I2C_ICSCR);
+ writel(0, priv->base + RCAR_I2C_ICSSR);
+
+ /* reset master mode */
+ writel(0, priv->base + RCAR_I2C_ICMIER);
+ writel(0, priv->base + RCAR_I2C_ICMCR);
+ writel(0, priv->base + RCAR_I2C_ICMSR);
+ writel(0, priv->base + RCAR_I2C_ICMAR);
+
+ ret = rcar_i2c_set_speed(dev, I2C_SPEED_STANDARD_RATE);
+ if (ret)
+ clk_disable(&priv->clk);
+
+ return ret;
+}
+
+static const struct dm_i2c_ops rcar_i2c_ops = {
+ .xfer = rcar_i2c_xfer,
+ .probe_chip = rcar_i2c_probe_chip,
+ .set_bus_speed = rcar_i2c_set_speed,
+};
+
+static const struct udevice_id rcar_i2c_ids[] = {
+ { .compatible = "renesas,rcar-gen2-i2c", .data = RCAR_I2C_TYPE_GEN2 },
+ { .compatible = "renesas,rcar-gen3-i2c", .data = RCAR_I2C_TYPE_GEN3 },
+ { }
+};
+
+U_BOOT_DRIVER(i2c_rcar) = {
+ .name = "i2c_rcar",
+ .id = UCLASS_I2C,
+ .of_match = rcar_i2c_ids,
+ .probe = rcar_i2c_probe,
+ .priv_auto = sizeof(struct rcar_i2c_priv),
+ .ops = &rcar_i2c_ops,
+};
diff --git a/roms/u-boot/drivers/i2c/rcar_iic.c b/roms/u-boot/drivers/i2c/rcar_iic.c
new file mode 100644
index 000000000..f0e50914c
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/rcar_iic.c
@@ -0,0 +1,274 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Renesas RCar IIC driver
+ *
+ * Copyright (C) 2017 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * Based on
+ * Copyright (C) 2011, 2013 Renesas Solutions Corp.
+ * Copyright (C) 2011, 2013 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <i2c.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+
+struct rcar_iic_priv {
+ void __iomem *base;
+ struct clk clk;
+ u8 iccl;
+ u8 icch;
+};
+
+#define RCAR_IIC_ICDR 0x00
+#define RCAR_IIC_ICCR 0x04
+#define RCAR_IIC_ICSR 0x08
+#define RCAR_IIC_ICIC 0x0c
+#define RCAR_IIC_ICCL 0x10
+#define RCAR_IIC_ICCH 0x14
+
+/* ICCR */
+#define RCAR_IIC_ICCR_ICE BIT(7)
+#define RCAR_IIC_ICCR_RACK BIT(6)
+#define RCAR_IIC_ICCR_RTS BIT(4)
+#define RCAR_IIC_ICCR_BUSY BIT(2)
+#define RCAR_IIC_ICCR_SCP BIT(0)
+
+/* ICSR / ICIC */
+#define RCAR_IC_BUSY BIT(4)
+#define RCAR_IC_TACK BIT(2)
+#define RCAR_IC_DTE BIT(0)
+
+#define IRQ_WAIT 1000
+
+static void sh_irq_dte(struct udevice *dev)
+{
+ struct rcar_iic_priv *priv = dev_get_priv(dev);
+ int i;
+
+ for (i = 0; i < IRQ_WAIT; i++) {
+ if (RCAR_IC_DTE & readb(priv->base + RCAR_IIC_ICSR))
+ break;
+ udelay(10);
+ }
+}
+
+static int sh_irq_dte_with_tack(struct udevice *dev)
+{
+ struct rcar_iic_priv *priv = dev_get_priv(dev);
+ u8 icsr;
+ int i;
+
+ for (i = 0; i < IRQ_WAIT; i++) {
+ icsr = readb(priv->base + RCAR_IIC_ICSR);
+ if (RCAR_IC_DTE & icsr)
+ break;
+ if (RCAR_IC_TACK & icsr)
+ return -ETIMEDOUT;
+ udelay(10);
+ }
+ return 0;
+}
+
+static void sh_irq_busy(struct udevice *dev)
+{
+ struct rcar_iic_priv *priv = dev_get_priv(dev);
+ int i;
+
+ for (i = 0; i < IRQ_WAIT; i++) {
+ if (!(RCAR_IC_BUSY & readb(priv->base + RCAR_IIC_ICSR)))
+ break;
+ udelay(10);
+ }
+}
+
+static int rcar_iic_set_addr(struct udevice *dev, u8 chip, u8 read)
+{
+ struct rcar_iic_priv *priv = dev_get_priv(dev);
+
+ clrbits_8(priv->base + RCAR_IIC_ICCR, RCAR_IIC_ICCR_ICE);
+ setbits_8(priv->base + RCAR_IIC_ICCR, RCAR_IIC_ICCR_ICE);
+
+ writeb(priv->iccl, priv->base + RCAR_IIC_ICCL);
+ writeb(priv->icch, priv->base + RCAR_IIC_ICCH);
+ writeb(RCAR_IC_TACK, priv->base + RCAR_IIC_ICIC);
+
+ writeb(RCAR_IIC_ICCR_ICE | RCAR_IIC_ICCR_RTS | RCAR_IIC_ICCR_BUSY,
+ priv->base + RCAR_IIC_ICCR);
+ sh_irq_dte(dev);
+
+ clrbits_8(priv->base + RCAR_IIC_ICSR, RCAR_IC_TACK);
+ writeb(chip << 1 | read, priv->base + RCAR_IIC_ICDR);
+ return sh_irq_dte_with_tack(dev);
+}
+
+static void rcar_iic_finish(struct udevice *dev)
+{
+ struct rcar_iic_priv *priv = dev_get_priv(dev);
+
+ writeb(0, priv->base + RCAR_IIC_ICSR);
+ clrbits_8(priv->base + RCAR_IIC_ICCR, RCAR_IIC_ICCR_ICE);
+}
+
+static int rcar_iic_read_common(struct udevice *dev, struct i2c_msg *msg)
+{
+ struct rcar_iic_priv *priv = dev_get_priv(dev);
+ int i, ret = -EREMOTEIO;
+
+ if (rcar_iic_set_addr(dev, msg->addr, 1) != 0)
+ goto err;
+
+ udelay(10);
+
+ writeb(RCAR_IIC_ICCR_ICE | RCAR_IIC_ICCR_SCP,
+ priv->base + RCAR_IIC_ICCR);
+
+ for (i = 0; i < msg->len; i++) {
+ if (sh_irq_dte_with_tack(dev) != 0)
+ goto err;
+
+ msg->buf[i] = readb(priv->base + RCAR_IIC_ICDR) & 0xff;
+
+ if (msg->len - 1 == i) {
+ writeb(RCAR_IIC_ICCR_ICE | RCAR_IIC_ICCR_RACK,
+ priv->base + RCAR_IIC_ICCR);
+ }
+ }
+
+ sh_irq_busy(dev);
+ ret = 0;
+
+err:
+ rcar_iic_finish(dev);
+ return ret;
+}
+
+static int rcar_iic_write_common(struct udevice *dev, struct i2c_msg *msg)
+{
+ struct rcar_iic_priv *priv = dev_get_priv(dev);
+ int i, ret = -EREMOTEIO;
+
+ if (rcar_iic_set_addr(dev, msg->addr, 0) != 0)
+ goto err;
+
+ udelay(10);
+
+ for (i = 0; i < msg->len; i++) {
+ writeb(msg->buf[i], priv->base + RCAR_IIC_ICDR);
+ if (sh_irq_dte_with_tack(dev) != 0)
+ goto err;
+ }
+
+ if (msg->flags & I2C_M_STOP) {
+ writeb(RCAR_IIC_ICCR_ICE | RCAR_IIC_ICCR_RTS,
+ priv->base + RCAR_IIC_ICCR);
+ if (sh_irq_dte_with_tack(dev) != 0)
+ goto err;
+ }
+
+ sh_irq_busy(dev);
+ ret = 0;
+
+err:
+ rcar_iic_finish(dev);
+ return ret;
+}
+
+static int rcar_iic_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs)
+{
+ int ret;
+
+ for (; nmsgs > 0; nmsgs--, msg++) {
+ if (msg->flags & I2C_M_RD)
+ ret = rcar_iic_read_common(dev, msg);
+ else
+ ret = rcar_iic_write_common(dev, msg);
+
+ if (ret)
+ return -EREMOTEIO;
+ }
+
+ return ret;
+}
+
+static int rcar_iic_set_speed(struct udevice *dev, uint speed)
+{
+ struct rcar_iic_priv *priv = dev_get_priv(dev);
+ const unsigned int ratio_high = 4;
+ const unsigned int ratio_low = 5;
+ int clkrate, denom;
+
+ clkrate = clk_get_rate(&priv->clk);
+ if (clkrate < 0)
+ return clkrate;
+
+ /*
+ * Calculate the value for ICCL and ICCH. From the data sheet:
+ * iccl = (p-clock / transfer-rate) * (L / (L + H))
+ * icch = (p clock / transfer rate) * (H / (L + H))
+ * where L and H are the SCL low and high ratio.
+ */
+ denom = speed * (ratio_high + ratio_low);
+ priv->iccl = DIV_ROUND_CLOSEST(clkrate * ratio_low, denom);
+ priv->icch = DIV_ROUND_CLOSEST(clkrate * ratio_high, denom);
+
+ return 0;
+}
+
+static int rcar_iic_probe_chip(struct udevice *dev, uint addr, uint flags)
+{
+ struct rcar_iic_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ rcar_iic_set_addr(dev, addr, 1);
+ writeb(RCAR_IIC_ICCR_ICE | RCAR_IIC_ICCR_SCP,
+ priv->base + RCAR_IIC_ICCR);
+ ret = sh_irq_dte_with_tack(dev);
+ rcar_iic_finish(dev);
+
+ return ret;
+}
+
+static int rcar_iic_probe(struct udevice *dev)
+{
+ struct rcar_iic_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ priv->base = dev_read_addr_ptr(dev);
+
+ ret = clk_get_by_index(dev, 0, &priv->clk);
+ if (ret)
+ return ret;
+
+ ret = clk_enable(&priv->clk);
+ if (ret)
+ return ret;
+
+ rcar_iic_finish(dev);
+
+ return rcar_iic_set_speed(dev, I2C_SPEED_STANDARD_RATE);
+}
+
+static const struct dm_i2c_ops rcar_iic_ops = {
+ .xfer = rcar_iic_xfer,
+ .probe_chip = rcar_iic_probe_chip,
+ .set_bus_speed = rcar_iic_set_speed,
+};
+
+static const struct udevice_id rcar_iic_ids[] = {
+ { .compatible = "renesas,rmobile-iic" },
+ { }
+};
+
+U_BOOT_DRIVER(iic_rcar) = {
+ .name = "iic_rcar",
+ .id = UCLASS_I2C,
+ .of_match = rcar_iic_ids,
+ .probe = rcar_iic_probe,
+ .priv_auto = sizeof(struct rcar_iic_priv),
+ .ops = &rcar_iic_ops,
+};
diff --git a/roms/u-boot/drivers/i2c/rk_i2c.c b/roms/u-boot/drivers/i2c/rk_i2c.c
new file mode 100644
index 000000000..f8fac45b6
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/rk_i2c.c
@@ -0,0 +1,498 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2015 Google, Inc
+ *
+ * (C) Copyright 2008-2014 Rockchip Electronics
+ * Peter, Software Engineering, <superpeter.cai@gmail.com>.
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <errno.h>
+#include <i2c.h>
+#include <log.h>
+#include <asm/io.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/i2c.h>
+#include <asm/arch-rockchip/periph.h>
+#include <dm/pinctrl.h>
+#include <linux/delay.h>
+#include <linux/sizes.h>
+
+/* i2c timerout */
+#define I2C_TIMEOUT_MS 100
+#define I2C_RETRY_COUNT 3
+
+/* rk i2c fifo max transfer bytes */
+#define RK_I2C_FIFO_SIZE 32
+
+struct rk_i2c {
+ struct clk clk;
+ struct i2c_regs *regs;
+ unsigned int speed;
+};
+
+enum {
+ RK_I2C_LEGACY,
+ RK_I2C_NEW,
+};
+
+/**
+ * @controller_type: i2c controller type
+ */
+struct rk_i2c_soc_data {
+ int controller_type;
+};
+
+static inline void rk_i2c_get_div(int div, int *divh, int *divl)
+{
+ *divl = div / 2;
+ if (div % 2 == 0)
+ *divh = div / 2;
+ else
+ *divh = DIV_ROUND_UP(div, 2);
+}
+
+/*
+ * SCL Divisor = 8 * (CLKDIVL+1 + CLKDIVH+1)
+ * SCL = PCLK / SCLK Divisor
+ * i2c_rate = PCLK
+ */
+static void rk_i2c_set_clk(struct rk_i2c *i2c, uint32_t scl_rate)
+{
+ uint32_t i2c_rate;
+ int div, divl, divh;
+
+ /* First get i2c rate from pclk */
+ i2c_rate = clk_get_rate(&i2c->clk);
+
+ div = DIV_ROUND_UP(i2c_rate, scl_rate * 8) - 2;
+ divh = 0;
+ divl = 0;
+ if (div >= 0)
+ rk_i2c_get_div(div, &divh, &divl);
+ writel(I2C_CLKDIV_VAL(divl, divh), &i2c->regs->clkdiv);
+
+ debug("rk_i2c_set_clk: i2c rate = %d, scl rate = %d\n", i2c_rate,
+ scl_rate);
+ debug("set i2c clk div = %d, divh = %d, divl = %d\n", div, divh, divl);
+ debug("set clk(I2C_CLKDIV: 0x%08x)\n", readl(&i2c->regs->clkdiv));
+}
+
+static void rk_i2c_show_regs(struct i2c_regs *regs)
+{
+#ifdef DEBUG
+ uint i;
+
+ debug("i2c_con: 0x%08x\n", readl(&regs->con));
+ debug("i2c_clkdiv: 0x%08x\n", readl(&regs->clkdiv));
+ debug("i2c_mrxaddr: 0x%08x\n", readl(&regs->mrxaddr));
+ debug("i2c_mrxraddR: 0x%08x\n", readl(&regs->mrxraddr));
+ debug("i2c_mtxcnt: 0x%08x\n", readl(&regs->mtxcnt));
+ debug("i2c_mrxcnt: 0x%08x\n", readl(&regs->mrxcnt));
+ debug("i2c_ien: 0x%08x\n", readl(&regs->ien));
+ debug("i2c_ipd: 0x%08x\n", readl(&regs->ipd));
+ debug("i2c_fcnt: 0x%08x\n", readl(&regs->fcnt));
+ for (i = 0; i < 8; i++)
+ debug("i2c_txdata%d: 0x%08x\n", i, readl(&regs->txdata[i]));
+ for (i = 0; i < 8; i++)
+ debug("i2c_rxdata%d: 0x%08x\n", i, readl(&regs->rxdata[i]));
+#endif
+}
+
+static int rk_i2c_send_start_bit(struct rk_i2c *i2c)
+{
+ struct i2c_regs *regs = i2c->regs;
+ ulong start;
+
+ debug("I2c Send Start bit.\n");
+ writel(I2C_IPD_ALL_CLEAN, &regs->ipd);
+
+ writel(I2C_CON_EN | I2C_CON_START, &regs->con);
+ writel(I2C_STARTIEN, &regs->ien);
+
+ start = get_timer(0);
+ while (1) {
+ if (readl(&regs->ipd) & I2C_STARTIPD) {
+ writel(I2C_STARTIPD, &regs->ipd);
+ break;
+ }
+ if (get_timer(start) > I2C_TIMEOUT_MS) {
+ debug("I2C Send Start Bit Timeout\n");
+ rk_i2c_show_regs(regs);
+ return -ETIMEDOUT;
+ }
+ udelay(1);
+ }
+
+ return 0;
+}
+
+static int rk_i2c_send_stop_bit(struct rk_i2c *i2c)
+{
+ struct i2c_regs *regs = i2c->regs;
+ ulong start;
+
+ debug("I2c Send Stop bit.\n");
+ writel(I2C_IPD_ALL_CLEAN, &regs->ipd);
+
+ writel(I2C_CON_EN | I2C_CON_STOP, &regs->con);
+ writel(I2C_CON_STOP, &regs->ien);
+
+ start = get_timer(0);
+ while (1) {
+ if (readl(&regs->ipd) & I2C_STOPIPD) {
+ writel(I2C_STOPIPD, &regs->ipd);
+ break;
+ }
+ if (get_timer(start) > I2C_TIMEOUT_MS) {
+ debug("I2C Send Start Bit Timeout\n");
+ rk_i2c_show_regs(regs);
+ return -ETIMEDOUT;
+ }
+ udelay(1);
+ }
+
+ return 0;
+}
+
+static inline void rk_i2c_disable(struct rk_i2c *i2c)
+{
+ writel(0, &i2c->regs->con);
+}
+
+static int rk_i2c_read(struct rk_i2c *i2c, uchar chip, uint reg, uint r_len,
+ uchar *buf, uint b_len)
+{
+ struct i2c_regs *regs = i2c->regs;
+ uchar *pbuf = buf;
+ uint bytes_remain_len = b_len;
+ uint bytes_xferred = 0;
+ uint words_xferred = 0;
+ ulong start;
+ uint con = 0;
+ uint rxdata;
+ uint i, j;
+ int err;
+ bool snd_chunk = false;
+
+ debug("rk_i2c_read: chip = %d, reg = %d, r_len = %d, b_len = %d\n",
+ chip, reg, r_len, b_len);
+
+ err = rk_i2c_send_start_bit(i2c);
+ if (err)
+ return err;
+
+ writel(I2C_MRXADDR_SET(1, chip << 1 | 1), &regs->mrxaddr);
+ if (r_len == 0) {
+ writel(0, &regs->mrxraddr);
+ } else if (r_len < 4) {
+ writel(I2C_MRXRADDR_SET(r_len, reg), &regs->mrxraddr);
+ } else {
+ debug("I2C Read: addr len %d not supported\n", r_len);
+ return -EIO;
+ }
+
+ while (bytes_remain_len) {
+ if (bytes_remain_len > RK_I2C_FIFO_SIZE) {
+ con = I2C_CON_EN;
+ bytes_xferred = 32;
+ } else {
+ /*
+ * The hw can read up to 32 bytes at a time. If we need
+ * more than one chunk, send an ACK after the last byte.
+ */
+ con = I2C_CON_EN | I2C_CON_LASTACK;
+ bytes_xferred = bytes_remain_len;
+ }
+ words_xferred = DIV_ROUND_UP(bytes_xferred, 4);
+
+ /*
+ * make sure we are in plain RX mode if we read a second chunk
+ */
+ if (snd_chunk)
+ con |= I2C_CON_MOD(I2C_MODE_RX);
+ else
+ con |= I2C_CON_MOD(I2C_MODE_TRX);
+
+ writel(con, &regs->con);
+ writel(bytes_xferred, &regs->mrxcnt);
+ writel(I2C_MBRFIEN | I2C_NAKRCVIEN, &regs->ien);
+
+ start = get_timer(0);
+ while (1) {
+ if (readl(&regs->ipd) & I2C_NAKRCVIPD) {
+ writel(I2C_NAKRCVIPD, &regs->ipd);
+ err = -EREMOTEIO;
+ }
+ if (readl(&regs->ipd) & I2C_MBRFIPD) {
+ writel(I2C_MBRFIPD, &regs->ipd);
+ break;
+ }
+ if (get_timer(start) > I2C_TIMEOUT_MS) {
+ debug("I2C Read Data Timeout\n");
+ err = -ETIMEDOUT;
+ rk_i2c_show_regs(regs);
+ goto i2c_exit;
+ }
+ udelay(1);
+ }
+
+ for (i = 0; i < words_xferred; i++) {
+ rxdata = readl(&regs->rxdata[i]);
+ debug("I2c Read RXDATA[%d] = 0x%x\n", i, rxdata);
+ for (j = 0; j < 4; j++) {
+ if ((i * 4 + j) == bytes_xferred)
+ break;
+ *pbuf++ = (rxdata >> (j * 8)) & 0xff;
+ }
+ }
+
+ bytes_remain_len -= bytes_xferred;
+ snd_chunk = true;
+ debug("I2C Read bytes_remain_len %d\n", bytes_remain_len);
+ }
+
+i2c_exit:
+ rk_i2c_disable(i2c);
+
+ return err;
+}
+
+static int rk_i2c_write(struct rk_i2c *i2c, uchar chip, uint reg, uint r_len,
+ uchar *buf, uint b_len)
+{
+ struct i2c_regs *regs = i2c->regs;
+ int err;
+ uchar *pbuf = buf;
+ uint bytes_remain_len = b_len + r_len + 1;
+ uint bytes_xferred = 0;
+ uint words_xferred = 0;
+ ulong start;
+ uint txdata;
+ uint i, j;
+
+ debug("rk_i2c_write: chip = %d, reg = %d, r_len = %d, b_len = %d\n",
+ chip, reg, r_len, b_len);
+ err = rk_i2c_send_start_bit(i2c);
+ if (err)
+ return err;
+
+ while (bytes_remain_len) {
+ if (bytes_remain_len > RK_I2C_FIFO_SIZE)
+ bytes_xferred = RK_I2C_FIFO_SIZE;
+ else
+ bytes_xferred = bytes_remain_len;
+ words_xferred = DIV_ROUND_UP(bytes_xferred, 4);
+
+ for (i = 0; i < words_xferred; i++) {
+ txdata = 0;
+ for (j = 0; j < 4; j++) {
+ if ((i * 4 + j) == bytes_xferred)
+ break;
+
+ if (i == 0 && j == 0 && pbuf == buf) {
+ txdata |= (chip << 1);
+ } else if (i == 0 && j <= r_len && pbuf == buf) {
+ txdata |= (reg &
+ (0xff << ((j - 1) * 8))) << 8;
+ } else {
+ txdata |= (*pbuf++)<<(j * 8);
+ }
+ }
+ writel(txdata, &regs->txdata[i]);
+ debug("I2c Write TXDATA[%d] = 0x%08x\n", i, txdata);
+ }
+
+ writel(I2C_CON_EN | I2C_CON_MOD(I2C_MODE_TX), &regs->con);
+ writel(bytes_xferred, &regs->mtxcnt);
+ writel(I2C_MBTFIEN | I2C_NAKRCVIEN, &regs->ien);
+
+ start = get_timer(0);
+ while (1) {
+ if (readl(&regs->ipd) & I2C_NAKRCVIPD) {
+ writel(I2C_NAKRCVIPD, &regs->ipd);
+ err = -EREMOTEIO;
+ }
+ if (readl(&regs->ipd) & I2C_MBTFIPD) {
+ writel(I2C_MBTFIPD, &regs->ipd);
+ break;
+ }
+ if (get_timer(start) > I2C_TIMEOUT_MS) {
+ debug("I2C Write Data Timeout\n");
+ err = -ETIMEDOUT;
+ rk_i2c_show_regs(regs);
+ goto i2c_exit;
+ }
+ udelay(1);
+ }
+
+ bytes_remain_len -= bytes_xferred;
+ debug("I2C Write bytes_remain_len %d\n", bytes_remain_len);
+ }
+
+i2c_exit:
+ rk_i2c_disable(i2c);
+
+ return err;
+}
+
+static int rockchip_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
+ int nmsgs)
+{
+ struct rk_i2c *i2c = dev_get_priv(bus);
+ int ret;
+
+ debug("i2c_xfer: %d messages\n", nmsgs);
+ for (; nmsgs > 0; nmsgs--, msg++) {
+ debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
+ if (msg->flags & I2C_M_RD) {
+ ret = rk_i2c_read(i2c, msg->addr, 0, 0, msg->buf,
+ msg->len);
+ } else {
+ ret = rk_i2c_write(i2c, msg->addr, 0, 0, msg->buf,
+ msg->len);
+ }
+ if (ret) {
+ debug("i2c_write: error sending\n");
+ return -EREMOTEIO;
+ }
+ }
+
+ rk_i2c_send_stop_bit(i2c);
+ rk_i2c_disable(i2c);
+
+ return 0;
+}
+
+int rockchip_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
+{
+ struct rk_i2c *i2c = dev_get_priv(bus);
+
+ rk_i2c_set_clk(i2c, speed);
+
+ return 0;
+}
+
+static int rockchip_i2c_of_to_plat(struct udevice *bus)
+{
+ struct rk_i2c *priv = dev_get_priv(bus);
+ int ret;
+
+ ret = clk_get_by_index(bus, 0, &priv->clk);
+ if (ret < 0) {
+ debug("%s: Could not get clock for %s: %d\n", __func__,
+ bus->name, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int rockchip_i2c_probe(struct udevice *bus)
+{
+ struct rk_i2c *priv = dev_get_priv(bus);
+ struct rk_i2c_soc_data *soc_data;
+ struct udevice *pinctrl;
+ int bus_nr;
+ int ret;
+
+ priv->regs = dev_read_addr_ptr(bus);
+
+ soc_data = (struct rk_i2c_soc_data*)dev_get_driver_data(bus);
+
+ if (soc_data->controller_type == RK_I2C_LEGACY) {
+ ret = dev_read_alias_seq(bus, &bus_nr);
+ if (ret < 0) {
+ debug("%s: Could not get alias for %s: %d\n",
+ __func__, bus->name, ret);
+ return ret;
+ }
+
+ ret = uclass_get_device(UCLASS_PINCTRL, 0, &pinctrl);
+ if (ret) {
+ debug("%s: Cannot find pinctrl device\n", __func__);
+ return ret;
+ }
+
+ /* pinctrl will switch I2C to new type */
+ ret = pinctrl_request_noflags(pinctrl, PERIPH_ID_I2C0 + bus_nr);
+ if (ret) {
+ debug("%s: Failed to switch I2C to new type %s: %d\n",
+ __func__, bus->name, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static const struct dm_i2c_ops rockchip_i2c_ops = {
+ .xfer = rockchip_i2c_xfer,
+ .set_bus_speed = rockchip_i2c_set_bus_speed,
+};
+
+static const struct rk_i2c_soc_data rk3066_soc_data = {
+ .controller_type = RK_I2C_LEGACY,
+};
+
+static const struct rk_i2c_soc_data rk3188_soc_data = {
+ .controller_type = RK_I2C_LEGACY,
+};
+
+static const struct rk_i2c_soc_data rk3228_soc_data = {
+ .controller_type = RK_I2C_NEW,
+};
+
+static const struct rk_i2c_soc_data rk3288_soc_data = {
+ .controller_type = RK_I2C_NEW,
+};
+
+static const struct rk_i2c_soc_data rk3328_soc_data = {
+ .controller_type = RK_I2C_NEW,
+};
+
+static const struct rk_i2c_soc_data rk3399_soc_data = {
+ .controller_type = RK_I2C_NEW,
+};
+
+static const struct udevice_id rockchip_i2c_ids[] = {
+ {
+ .compatible = "rockchip,rk3066-i2c",
+ .data = (ulong)&rk3066_soc_data,
+ },
+ {
+ .compatible = "rockchip,rk3188-i2c",
+ .data = (ulong)&rk3188_soc_data,
+ },
+ {
+ .compatible = "rockchip,rk3228-i2c",
+ .data = (ulong)&rk3228_soc_data,
+ },
+ {
+ .compatible = "rockchip,rk3288-i2c",
+ .data = (ulong)&rk3288_soc_data,
+ },
+ {
+ .compatible = "rockchip,rk3328-i2c",
+ .data = (ulong)&rk3328_soc_data,
+ },
+ {
+ .compatible = "rockchip,rk3399-i2c",
+ .data = (ulong)&rk3399_soc_data,
+ },
+ { }
+};
+
+U_BOOT_DRIVER(rockchip_rk3066_i2c) = {
+ .name = "rockchip_rk3066_i2c",
+ .id = UCLASS_I2C,
+ .of_match = rockchip_i2c_ids,
+ .of_to_plat = rockchip_i2c_of_to_plat,
+ .probe = rockchip_i2c_probe,
+ .priv_auto = sizeof(struct rk_i2c),
+ .ops = &rockchip_i2c_ops,
+};
+
+DM_DRIVER_ALIAS(rockchip_rk3066_i2c, rockchip_rk3288_i2c)
diff --git a/roms/u-boot/drivers/i2c/s3c24x0_i2c.c b/roms/u-boot/drivers/i2c/s3c24x0_i2c.c
new file mode 100644
index 000000000..56f0f6988
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/s3c24x0_i2c.c
@@ -0,0 +1,349 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2002
+ * David Mueller, ELSOFT AG, d.mueller@elsoft.ch
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <dm.h>
+#include <fdtdec.h>
+#if (defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5)
+#include <log.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/pinmux.h>
+#else
+#include <asm/arch/s3c24x0_cpu.h>
+#endif
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <i2c.h>
+#include "s3c24x0_i2c.h"
+
+#ifndef CONFIG_SYS_I2C_S3C24X0_SLAVE
+#define SYS_I2C_S3C24X0_SLAVE_ADDR 0
+#else
+#define SYS_I2C_S3C24X0_SLAVE_ADDR CONFIG_SYS_I2C_S3C24X0_SLAVE
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Wait til the byte transfer is completed.
+ *
+ * @param i2c- pointer to the appropriate i2c register bank.
+ * @return I2C_OK, if transmission was ACKED
+ * I2C_NACK, if transmission was NACKED
+ * I2C_NOK_TIMEOUT, if transaction did not complete in I2C_TIMEOUT_MS
+ */
+
+static int WaitForXfer(struct s3c24x0_i2c *i2c)
+{
+ ulong 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 void read_write_byte(struct s3c24x0_i2c *i2c)
+{
+ clrbits_le32(&i2c->iiccon, I2CCON_IRPND);
+}
+
+static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd)
+{
+ ulong freq, pres = 16, div;
+#if (defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5)
+ freq = get_i2c_clk();
+#else
+ freq = get_PCLK();
+#endif
+ /* 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) | 0xA0 | ((pres == 512) ? 0x40 : 0), &i2c->iiccon);
+
+ /* init to SLAVE REVEIVE and set slaveaddr */
+ writel(0, &i2c->iicstat);
+ writel(slaveadd, &i2c->iicadd);
+ /* program Master Transmit (and implicit STOP) */
+ writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat);
+}
+
+static int s3c24x0_i2c_set_bus_speed(struct udevice *dev, unsigned int speed)
+{
+ struct s3c24x0_i2c_bus *i2c_bus = dev_get_priv(dev);
+
+ i2c_bus->clock_frequency = speed;
+
+ i2c_ch_init(i2c_bus->regs, i2c_bus->clock_frequency,
+ SYS_I2C_S3C24X0_SLAVE_ADDR);
+
+ return 0;
+}
+
+/*
+ * cmd_type is 0 for write, 1 for read.
+ *
+ * addr_len can take any value from 0-255, it is only limited
+ * by the char, we could make it larger if needed. If it is
+ * 0 we skip the address write cycle.
+ */
+static int i2c_transfer(struct s3c24x0_i2c *i2c,
+ unsigned char cmd_type,
+ unsigned char chip,
+ unsigned char addr[],
+ unsigned char addr_len,
+ unsigned char data[],
+ unsigned short data_len)
+{
+ int i = 0, result;
+ ulong start_time = get_timer(0);
+
+ if (data == 0 || data_len == 0) {
+ /*Don't support data transfer of no length or to address 0 */
+ debug("i2c_transfer: bad call\n");
+ return I2C_NOK;
+ }
+
+ while (readl(&i2c->iicstat) & I2CSTAT_BSY) {
+ if (get_timer(start_time) > I2C_TIMEOUT_MS)
+ return I2C_NOK_TOUT;
+ }
+
+ writel(readl(&i2c->iiccon) | I2CCON_ACKGEN, &i2c->iiccon);
+
+ /* Get the slave chip address going */
+ writel(chip, &i2c->iicds);
+ if ((cmd_type == I2C_WRITE) || (addr && addr_len))
+ writel(I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP,
+ &i2c->iicstat);
+ else
+ writel(I2C_MODE_MR | I2C_TXRX_ENA | I2C_START_STOP,
+ &i2c->iicstat);
+
+ /* Wait for chip address to transmit. */
+ result = WaitForXfer(i2c);
+ if (result != I2C_OK)
+ goto bailout;
+
+ /* If register address needs to be transmitted - do it now. */
+ if (addr && addr_len) {
+ while ((i < addr_len) && (result == I2C_OK)) {
+ writel(addr[i++], &i2c->iicds);
+ read_write_byte(i2c);
+ result = WaitForXfer(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);
+ read_write_byte(i2c);
+ result = WaitForXfer(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);
+ read_write_byte(i2c);
+ result = WaitForXfer(i2c);
+
+ if (result != I2C_OK)
+ goto bailout;
+ }
+
+ while ((i < data_len) && (result == I2C_OK)) {
+ /* disable ACK for final READ */
+ if (i == data_len - 1)
+ writel(readl(&i2c->iiccon)
+ & ~I2CCON_ACKGEN,
+ &i2c->iiccon);
+ read_write_byte(i2c);
+ result = WaitForXfer(i2c);
+ data[i++] = readl(&i2c->iicds);
+ }
+ if (result == I2C_NACK)
+ result = I2C_OK; /* Normal terminated read. */
+ break;
+
+ default:
+ debug("i2c_transfer: bad call\n");
+ result = I2C_NOK;
+ break;
+ }
+
+bailout:
+ /* Send STOP. */
+ writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat);
+ read_write_byte(i2c);
+
+ return result;
+}
+
+static int s3c24x0_i2c_probe(struct udevice *dev, uint chip, uint chip_flags)
+{
+ struct s3c24x0_i2c_bus *i2c_bus = dev_get_priv(dev);
+ uchar buf[1];
+ int ret;
+
+ buf[0] = 0;
+
+ /*
+ * What is needed is to send the chip address and verify that the
+ * address was <ACK>ed (i.e. there was a chip at that address which
+ * drove the data line low).
+ */
+ ret = i2c_transfer(i2c_bus->regs, I2C_READ, chip << 1, 0, 0, buf, 1);
+
+ return ret != I2C_OK;
+}
+
+static int s3c24x0_do_msg(struct s3c24x0_i2c_bus *i2c_bus, struct i2c_msg *msg,
+ int seq)
+{
+ struct s3c24x0_i2c *i2c = i2c_bus->regs;
+ bool is_read = msg->flags & I2C_M_RD;
+ uint status;
+ uint addr;
+ int ret, i;
+
+ if (!seq)
+ setbits_le32(&i2c->iiccon, I2CCON_ACKGEN);
+
+ /* Get the slave chip address going */
+ addr = msg->addr << 1;
+ writel(addr, &i2c->iicds);
+ status = I2C_TXRX_ENA | I2C_START_STOP;
+ if (is_read)
+ status |= I2C_MODE_MR;
+ else
+ status |= I2C_MODE_MT;
+ writel(status, &i2c->iicstat);
+ if (seq)
+ read_write_byte(i2c);
+
+ /* Wait for chip address to transmit */
+ ret = WaitForXfer(i2c);
+ if (ret)
+ goto err;
+
+ if (is_read) {
+ for (i = 0; !ret && i < msg->len; i++) {
+ /* disable ACK for final READ */
+ if (i == msg->len - 1)
+ clrbits_le32(&i2c->iiccon, I2CCON_ACKGEN);
+ read_write_byte(i2c);
+ ret = WaitForXfer(i2c);
+ msg->buf[i] = readl(&i2c->iicds);
+ }
+ if (ret == I2C_NACK)
+ ret = I2C_OK; /* Normal terminated read */
+ } else {
+ for (i = 0; !ret && i < msg->len; i++) {
+ writel(msg->buf[i], &i2c->iicds);
+ read_write_byte(i2c);
+ ret = WaitForXfer(i2c);
+ }
+ }
+
+err:
+ return ret;
+}
+
+static int s3c24x0_i2c_xfer(struct udevice *dev, struct i2c_msg *msg,
+ int nmsgs)
+{
+ struct s3c24x0_i2c_bus *i2c_bus = dev_get_priv(dev);
+ struct s3c24x0_i2c *i2c = i2c_bus->regs;
+ ulong start_time;
+ int ret, i;
+
+ start_time = get_timer(0);
+ while (readl(&i2c->iicstat) & I2CSTAT_BSY) {
+ if (get_timer(start_time) > I2C_TIMEOUT_MS) {
+ debug("Timeout\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ for (ret = 0, i = 0; !ret && i < nmsgs; i++)
+ ret = s3c24x0_do_msg(i2c_bus, &msg[i], i);
+
+ /* Send STOP */
+ writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat);
+ read_write_byte(i2c);
+
+ return ret ? -EREMOTEIO : 0;
+}
+
+static int s3c_i2c_of_to_plat(struct udevice *dev)
+{
+ const void *blob = gd->fdt_blob;
+ struct s3c24x0_i2c_bus *i2c_bus = dev_get_priv(dev);
+ int node;
+
+ node = dev_of_offset(dev);
+
+ i2c_bus->regs = dev_read_addr_ptr(dev);
+
+ i2c_bus->id = pinmux_decode_periph_id(blob, node);
+
+ i2c_bus->clock_frequency =
+ dev_read_u32_default(dev, "clock-frequency",
+ I2C_SPEED_STANDARD_RATE);
+ i2c_bus->node = node;
+ i2c_bus->bus_num = dev_seq(dev);
+
+ exynos_pinmux_config(i2c_bus->id, 0);
+
+ i2c_bus->active = true;
+
+ return 0;
+}
+
+static const struct dm_i2c_ops s3c_i2c_ops = {
+ .xfer = s3c24x0_i2c_xfer,
+ .probe_chip = s3c24x0_i2c_probe,
+ .set_bus_speed = s3c24x0_i2c_set_bus_speed,
+};
+
+static const struct udevice_id s3c_i2c_ids[] = {
+ { .compatible = "samsung,s3c2440-i2c" },
+ { }
+};
+
+U_BOOT_DRIVER(i2c_s3c) = {
+ .name = "i2c_s3c",
+ .id = UCLASS_I2C,
+ .of_match = s3c_i2c_ids,
+ .of_to_plat = s3c_i2c_of_to_plat,
+ .priv_auto = sizeof(struct s3c24x0_i2c_bus),
+ .ops = &s3c_i2c_ops,
+};
diff --git a/roms/u-boot/drivers/i2c/s3c24x0_i2c.h b/roms/u-boot/drivers/i2c/s3c24x0_i2c.h
new file mode 100644
index 000000000..ec8f1acae
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/s3c24x0_i2c.h
@@ -0,0 +1,83 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2012 Samsung Electronics
+ */
+
+#ifndef _S3C24X0_I2C_H
+#define _S3C24X0_I2C_H
+
+struct s3c24x0_i2c {
+ u32 iiccon;
+ u32 iicstat;
+ u32 iicadd;
+ u32 iicds;
+ u32 iiclc;
+};
+
+struct exynos5_hsi2c {
+ u32 usi_ctl;
+ u32 usi_fifo_ctl;
+ u32 usi_trailing_ctl;
+ u32 usi_clk_ctl;
+ u32 usi_clk_slot;
+ u32 spi_ctl;
+ u32 uart_ctl;
+ u32 res1;
+ u32 usi_int_en;
+ u32 usi_int_stat;
+ u32 usi_modem_stat;
+ u32 usi_error_stat;
+ u32 usi_fifo_stat;
+ u32 usi_txdata;
+ u32 usi_rxdata;
+ u32 res2;
+ u32 usi_conf;
+ u32 usi_auto_conf;
+ u32 usi_timeout;
+ u32 usi_manual_cmd;
+ u32 usi_trans_status;
+ u32 usi_timing_hs1;
+ u32 usi_timing_hs2;
+ u32 usi_timing_hs3;
+ u32 usi_timing_fs1;
+ u32 usi_timing_fs2;
+ u32 usi_timing_fs3;
+ u32 usi_timing_sla;
+ u32 i2c_addr;
+};
+
+struct s3c24x0_i2c_bus {
+ bool active; /* port is active and available */
+ int node; /* device tree node */
+ int bus_num; /* i2c bus number */
+ struct s3c24x0_i2c *regs;
+ struct exynos5_hsi2c *hsregs;
+ int is_highspeed; /* High speed type, rather than I2C */
+ unsigned clock_frequency;
+ int id;
+ unsigned clk_cycle;
+ unsigned clk_div;
+};
+
+#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 */
+
+/* S3C I2C Controller bits */
+#define I2CSTAT_BSY 0x20 /* Busy bit */
+#define I2CSTAT_NACK 0x01 /* Nack bit */
+#define I2CCON_ACKGEN 0x80 /* Acknowledge generation */
+#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 */
+
+#endif /* _S3C24X0_I2C_H */
diff --git a/roms/u-boot/drivers/i2c/sandbox_i2c.c b/roms/u-boot/drivers/i2c/sandbox_i2c.c
new file mode 100644
index 000000000..c99e6de93
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/sandbox_i2c.c
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Simulate an I2C port
+ *
+ * Copyright (c) 2014 Google, Inc
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <i2c.h>
+#include <log.h>
+#include <asm/i2c.h>
+#include <asm/test.h>
+#include <dm/acpi.h>
+#include <dm/lists.h>
+#include <dm/device-internal.h>
+
+static int get_emul(struct udevice *dev, struct udevice **devp,
+ struct dm_i2c_ops **opsp)
+{
+ struct dm_i2c_chip *plat;
+ int ret;
+
+ *devp = NULL;
+ *opsp = NULL;
+ plat = dev_get_parent_plat(dev);
+ if (!plat->emul) {
+ ret = i2c_emul_find(dev, &plat->emul);
+ if (ret)
+ return ret;
+ }
+ *devp = plat->emul;
+ *opsp = i2c_get_ops(plat->emul);
+
+ return 0;
+}
+
+void sandbox_i2c_set_test_mode(struct udevice *bus, bool test_mode)
+{
+ struct sandbox_i2c_priv *priv = dev_get_priv(bus);
+
+ priv->test_mode = test_mode;
+}
+
+static int sandbox_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
+ int nmsgs)
+{
+ struct dm_i2c_bus *i2c = dev_get_uclass_priv(bus);
+ struct sandbox_i2c_priv *priv = dev_get_priv(bus);
+ struct dm_i2c_ops *ops;
+ struct udevice *emul, *dev;
+ bool is_read;
+ int ret;
+
+ /* Special test code to return success but with no emulation */
+ if (priv->test_mode && msg->addr == SANDBOX_I2C_TEST_ADDR)
+ return 0;
+
+ ret = i2c_get_chip(bus, msg->addr, 1, &dev);
+ if (ret)
+ return ret;
+
+ ret = get_emul(dev, &emul, &ops);
+ if (ret)
+ return ret;
+
+ if (priv->test_mode) {
+ /*
+ * For testing, don't allow writing above 100KHz for writes and
+ * 400KHz for reads.
+ */
+ is_read = nmsgs > 1;
+ if (i2c->speed_hz > (is_read ? I2C_SPEED_FAST_RATE :
+ I2C_SPEED_STANDARD_RATE)) {
+ debug("%s: Max speed exceeded\n", __func__);
+ return -EINVAL;
+ }
+ }
+
+ return ops->xfer(emul, msg, nmsgs);
+}
+
+static const struct dm_i2c_ops sandbox_i2c_ops = {
+ .xfer = sandbox_i2c_xfer,
+};
+
+static const struct udevice_id sandbox_i2c_ids[] = {
+ { .compatible = "sandbox,i2c" },
+ { }
+};
+
+U_BOOT_DRIVER(sandbox_i2c) = {
+ .name = "sandbox_i2c",
+ .id = UCLASS_I2C,
+ .of_match = sandbox_i2c_ids,
+ .ops = &sandbox_i2c_ops,
+ .priv_auto = sizeof(struct sandbox_i2c_priv),
+};
diff --git a/roms/u-boot/drivers/i2c/sh_i2c.c b/roms/u-boot/drivers/i2c/sh_i2c.c
new file mode 100644
index 000000000..26a870066
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/sh_i2c.c
@@ -0,0 +1,313 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2011, 2013 Renesas Solutions Corp.
+ * Copyright (C) 2011, 2013 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
+ *
+ * NOTE: This driver should be converted to driver model before June 2017.
+ * Please see doc/driver-model/i2c-howto.rst for instructions.
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <log.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Every register is 32bit aligned, but only 8bits in size */
+#define ureg(name) u8 name; u8 __pad_##name##0; u16 __pad_##name##1;
+struct sh_i2c {
+ ureg(icdr);
+ ureg(iccr);
+ ureg(icsr);
+ ureg(icic);
+ ureg(iccl);
+ ureg(icch);
+};
+#undef ureg
+
+/* ICCR */
+#define SH_I2C_ICCR_ICE (1 << 7)
+#define SH_I2C_ICCR_RACK (1 << 6)
+#define SH_I2C_ICCR_RTS (1 << 4)
+#define SH_I2C_ICCR_BUSY (1 << 2)
+#define SH_I2C_ICCR_SCP (1 << 0)
+
+/* ICSR / ICIC */
+#define SH_IC_BUSY (1 << 4)
+#define SH_IC_TACK (1 << 2)
+#define SH_IC_WAIT (1 << 1)
+#define SH_IC_DTE (1 << 0)
+
+#ifdef CONFIG_SH_I2C_8BIT
+/* store 8th bit of iccl and icch in ICIC register */
+#define SH_I2C_ICIC_ICCLB8 (1 << 7)
+#define SH_I2C_ICIC_ICCHB8 (1 << 6)
+#endif
+
+static const struct sh_i2c *i2c_dev[CONFIG_SYS_I2C_SH_NUM_CONTROLLERS] = {
+ (struct sh_i2c *)CONFIG_SYS_I2C_SH_BASE0,
+#ifdef CONFIG_SYS_I2C_SH_BASE1
+ (struct sh_i2c *)CONFIG_SYS_I2C_SH_BASE1,
+#endif
+#ifdef CONFIG_SYS_I2C_SH_BASE2
+ (struct sh_i2c *)CONFIG_SYS_I2C_SH_BASE2,
+#endif
+#ifdef CONFIG_SYS_I2C_SH_BASE3
+ (struct sh_i2c *)CONFIG_SYS_I2C_SH_BASE3,
+#endif
+#ifdef CONFIG_SYS_I2C_SH_BASE4
+ (struct sh_i2c *)CONFIG_SYS_I2C_SH_BASE4,
+#endif
+};
+
+static u16 iccl, icch;
+
+#define IRQ_WAIT 1000
+
+static void sh_irq_dte(struct sh_i2c *dev)
+{
+ int i;
+
+ for (i = 0; i < IRQ_WAIT; i++) {
+ if (SH_IC_DTE & readb(&dev->icsr))
+ break;
+ udelay(10);
+ }
+}
+
+static int sh_irq_dte_with_tack(struct sh_i2c *dev)
+{
+ int i;
+
+ for (i = 0; i < IRQ_WAIT; i++) {
+ if (SH_IC_DTE & readb(&dev->icsr))
+ break;
+ if (SH_IC_TACK & readb(&dev->icsr))
+ return -1;
+ udelay(10);
+ }
+ return 0;
+}
+
+static void sh_irq_busy(struct sh_i2c *dev)
+{
+ int i;
+
+ for (i = 0; i < IRQ_WAIT; i++) {
+ if (!(SH_IC_BUSY & readb(&dev->icsr)))
+ break;
+ udelay(10);
+ }
+}
+
+static int sh_i2c_set_addr(struct sh_i2c *dev, u8 chip, u8 addr, int stop)
+{
+ u8 icic = SH_IC_TACK;
+
+ debug("%s: chip: %x, addr: %x iccl: %x, icch %x\n",
+ __func__, chip, addr, iccl, icch);
+ clrbits_8(&dev->iccr, SH_I2C_ICCR_ICE);
+ setbits_8(&dev->iccr, SH_I2C_ICCR_ICE);
+
+ writeb(iccl & 0xff, &dev->iccl);
+ writeb(icch & 0xff, &dev->icch);
+#ifdef CONFIG_SH_I2C_8BIT
+ if (iccl > 0xff)
+ icic |= SH_I2C_ICIC_ICCLB8;
+ if (icch > 0xff)
+ icic |= SH_I2C_ICIC_ICCHB8;
+#endif
+ writeb(icic, &dev->icic);
+
+ writeb((SH_I2C_ICCR_ICE|SH_I2C_ICCR_RTS|SH_I2C_ICCR_BUSY), &dev->iccr);
+ sh_irq_dte(dev);
+
+ clrbits_8(&dev->icsr, SH_IC_TACK);
+ writeb(chip << 1, &dev->icdr);
+ if (sh_irq_dte_with_tack(dev) != 0)
+ return -1;
+
+ writeb(addr, &dev->icdr);
+ if (stop)
+ writeb((SH_I2C_ICCR_ICE|SH_I2C_ICCR_RTS), &dev->iccr);
+
+ if (sh_irq_dte_with_tack(dev) != 0)
+ return -1;
+ return 0;
+}
+
+static void sh_i2c_finish(struct sh_i2c *dev)
+{
+ writeb(0, &dev->icsr);
+ clrbits_8(&dev->iccr, SH_I2C_ICCR_ICE);
+}
+
+static int
+sh_i2c_raw_write(struct sh_i2c *dev, u8 chip, uint addr, u8 val)
+{
+ int ret = -1;
+ if (sh_i2c_set_addr(dev, chip, addr, 0) != 0)
+ goto exit0;
+ udelay(10);
+
+ writeb(val, &dev->icdr);
+ if (sh_irq_dte_with_tack(dev) != 0)
+ goto exit0;
+
+ writeb((SH_I2C_ICCR_ICE | SH_I2C_ICCR_RTS), &dev->iccr);
+ if (sh_irq_dte_with_tack(dev) != 0)
+ goto exit0;
+ sh_irq_busy(dev);
+ ret = 0;
+
+exit0:
+ sh_i2c_finish(dev);
+ return ret;
+}
+
+static int sh_i2c_raw_read(struct sh_i2c *dev, u8 chip, u8 addr)
+{
+ int ret = -1;
+
+#if defined(CONFIG_SH73A0)
+ if (sh_i2c_set_addr(dev, chip, addr, 0) != 0)
+ goto exit0;
+#else
+ if (sh_i2c_set_addr(dev, chip, addr, 1) != 0)
+ goto exit0;
+ udelay(100);
+#endif
+
+ writeb((SH_I2C_ICCR_ICE|SH_I2C_ICCR_RTS|SH_I2C_ICCR_BUSY), &dev->iccr);
+ sh_irq_dte(dev);
+
+ writeb(chip << 1 | 0x01, &dev->icdr);
+ if (sh_irq_dte_with_tack(dev) != 0)
+ goto exit0;
+
+ writeb((SH_I2C_ICCR_ICE|SH_I2C_ICCR_SCP), &dev->iccr);
+ if (sh_irq_dte_with_tack(dev) != 0)
+ goto exit0;
+
+ ret = readb(&dev->icdr) & 0xff;
+
+ writeb((SH_I2C_ICCR_ICE|SH_I2C_ICCR_RACK), &dev->iccr);
+ readb(&dev->icdr); /* Dummy read */
+ sh_irq_busy(dev);
+
+exit0:
+ sh_i2c_finish(dev);
+
+ return ret;
+}
+
+static void
+sh_i2c_init(struct i2c_adapter *adap, int speed, int slaveadd)
+{
+ int num, denom, tmp;
+
+ /* No i2c support prior to relocation */
+ if (!(gd->flags & GD_FLG_RELOC))
+ return;
+
+ /*
+ * Calculate the value for iccl. From the data sheet:
+ * iccl = (p-clock / transfer-rate) * (L / (L + H))
+ * where L and H are the SCL low and high ratio.
+ */
+ num = CONFIG_SH_I2C_CLOCK * CONFIG_SH_I2C_DATA_LOW;
+ denom = speed * (CONFIG_SH_I2C_DATA_HIGH + CONFIG_SH_I2C_DATA_LOW);
+ tmp = num * 10 / denom;
+ if (tmp % 10 >= 5)
+ iccl = (u16)((num/denom) + 1);
+ else
+ iccl = (u16)(num/denom);
+
+ /* Calculate the value for icch. From the data sheet:
+ icch = (p clock / transfer rate) * (H / (L + H)) */
+ num = CONFIG_SH_I2C_CLOCK * CONFIG_SH_I2C_DATA_HIGH;
+ tmp = num * 10 / denom;
+ if (tmp % 10 >= 5)
+ icch = (u16)((num/denom) + 1);
+ else
+ icch = (u16)(num/denom);
+
+ debug("clock: %d, speed %d, iccl: %x, icch: %x\n",
+ CONFIG_SH_I2C_CLOCK, speed, iccl, icch);
+}
+
+static int sh_i2c_read(struct i2c_adapter *adap, uint8_t chip,
+ uint addr, int alen, u8 *data, int len)
+{
+ int ret, i;
+ struct sh_i2c *dev = (struct sh_i2c *)i2c_dev[adap->hwadapnr];
+
+ for (i = 0; i < len; i++) {
+ ret = sh_i2c_raw_read(dev, chip, addr + i);
+ if (ret < 0)
+ return -1;
+
+ data[i] = ret & 0xff;
+ debug("%s: data[%d]: %02x\n", __func__, i, data[i]);
+ }
+
+ return 0;
+}
+
+static int sh_i2c_write(struct i2c_adapter *adap, uint8_t chip, uint addr,
+ int alen, u8 *data, int len)
+{
+ struct sh_i2c *dev = (struct sh_i2c *)i2c_dev[adap->hwadapnr];
+ int i;
+
+ for (i = 0; i < len; i++) {
+ debug("%s: data[%d]: %02x\n", __func__, i, data[i]);
+ if (sh_i2c_raw_write(dev, chip, addr + i, data[i]) != 0)
+ return -1;
+ }
+ return 0;
+}
+
+static int
+sh_i2c_probe(struct i2c_adapter *adap, u8 dev)
+{
+ u8 dummy[1];
+
+ return sh_i2c_read(adap, dev, 0, 0, dummy, sizeof dummy);
+}
+
+static unsigned int sh_i2c_set_bus_speed(struct i2c_adapter *adap,
+ unsigned int speed)
+{
+ struct sh_i2c *dev = (struct sh_i2c *)i2c_dev[adap->hwadapnr];
+
+ sh_i2c_finish(dev);
+ sh_i2c_init(adap, speed, 0);
+
+ return 0;
+}
+
+/*
+ * Register RCAR i2c adapters
+ */
+U_BOOT_I2C_ADAP_COMPLETE(sh_0, sh_i2c_init, sh_i2c_probe, sh_i2c_read,
+ sh_i2c_write, sh_i2c_set_bus_speed, CONFIG_SYS_I2C_SH_SPEED0, 0, 0)
+#ifdef CONFIG_SYS_I2C_SH_BASE1
+U_BOOT_I2C_ADAP_COMPLETE(sh_1, sh_i2c_init, sh_i2c_probe, sh_i2c_read,
+ sh_i2c_write, sh_i2c_set_bus_speed, CONFIG_SYS_I2C_SH_SPEED1, 0, 1)
+#endif
+#ifdef CONFIG_SYS_I2C_SH_BASE2
+U_BOOT_I2C_ADAP_COMPLETE(sh_2, sh_i2c_init, sh_i2c_probe, sh_i2c_read,
+ sh_i2c_write, sh_i2c_set_bus_speed, CONFIG_SYS_I2C_SH_SPEED2, 0, 2)
+#endif
+#ifdef CONFIG_SYS_I2C_SH_BASE3
+U_BOOT_I2C_ADAP_COMPLETE(sh_3, sh_i2c_init, sh_i2c_probe, sh_i2c_read,
+ sh_i2c_write, sh_i2c_set_bus_speed, CONFIG_SYS_I2C_SH_SPEED3, 0, 3)
+#endif
+#ifdef CONFIG_SYS_I2C_SH_BASE4
+U_BOOT_I2C_ADAP_COMPLETE(sh_4, sh_i2c_init, sh_i2c_probe, sh_i2c_read,
+ sh_i2c_write, sh_i2c_set_bus_speed, CONFIG_SYS_I2C_SH_SPEED4, 0, 4)
+#endif
diff --git a/roms/u-boot/drivers/i2c/soft_i2c.c b/roms/u-boot/drivers/i2c/soft_i2c.c
new file mode 100644
index 000000000..db69c18cb
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/soft_i2c.c
@@ -0,0 +1,517 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2009
+ * Heiko Schocher, DENX Software Engineering, hs@denx.de.
+ * Changes for multibus/multiadapter I2C support.
+ *
+ * (C) Copyright 2001, 2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * This has been changed substantially by Gerald Van Baren, Custom IDEAS,
+ * vanbaren@cideas.com. It was heavily influenced by LiMon, written by
+ * Neil Russell.
+ *
+ * NOTE: This driver should be converted to driver model before June 2017.
+ * Please see doc/driver-model/i2c-howto.rst for instructions.
+ */
+
+#include <common.h>
+#if defined(CONFIG_AT91FAMILY)
+#include <asm/io.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/at91_pio.h>
+#ifdef CONFIG_ATMEL_LEGACY
+#include <asm/arch/gpio.h>
+#endif
+#endif
+#include <i2c.h>
+#include <asm/global_data.h>
+#include <linux/delay.h>
+
+#if defined(CONFIG_SOFT_I2C_GPIO_SCL)
+# include <asm/gpio.h>
+
+# ifndef I2C_GPIO_SYNC
+# define I2C_GPIO_SYNC
+# endif
+
+# ifndef I2C_INIT
+# define I2C_INIT \
+ do { \
+ gpio_request(CONFIG_SOFT_I2C_GPIO_SCL, "soft_i2c"); \
+ gpio_request(CONFIG_SOFT_I2C_GPIO_SDA, "soft_i2c"); \
+ } while (0)
+# endif
+
+# ifndef I2C_ACTIVE
+# define I2C_ACTIVE do { } while (0)
+# endif
+
+# ifndef I2C_TRISTATE
+# define I2C_TRISTATE do { } while (0)
+# endif
+
+# ifndef I2C_READ
+# define I2C_READ gpio_get_value(CONFIG_SOFT_I2C_GPIO_SDA)
+# endif
+
+# ifndef I2C_SDA
+# define I2C_SDA(bit) \
+ do { \
+ if (bit) \
+ gpio_direction_input(CONFIG_SOFT_I2C_GPIO_SDA); \
+ else \
+ gpio_direction_output(CONFIG_SOFT_I2C_GPIO_SDA, 0); \
+ I2C_GPIO_SYNC; \
+ } while (0)
+# endif
+
+# ifndef I2C_SCL
+# define I2C_SCL(bit) \
+ do { \
+ gpio_direction_output(CONFIG_SOFT_I2C_GPIO_SCL, bit); \
+ I2C_GPIO_SYNC; \
+ } while (0)
+# endif
+
+# ifndef I2C_DELAY
+# define I2C_DELAY udelay(5) /* 1/4 I2C clock duration */
+# endif
+
+#endif
+
+/* #define DEBUG_I2C */
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifndef I2C_SOFT_DECLARATIONS
+# define I2C_SOFT_DECLARATIONS
+#endif
+
+#if !defined(CONFIG_SYS_I2C_SOFT_SPEED)
+#define CONFIG_SYS_I2C_SOFT_SPEED CONFIG_SYS_I2C_SPEED
+#endif
+#if !defined(CONFIG_SYS_I2C_SOFT_SLAVE)
+#define CONFIG_SYS_I2C_SOFT_SLAVE CONFIG_SYS_I2C_SLAVE
+#endif
+
+/*-----------------------------------------------------------------------
+ * Definitions
+ */
+#define RETRIES 0
+
+#define I2C_ACK 0 /* PD_SDA level to ack a byte */
+#define I2C_NOACK 1 /* PD_SDA level to noack a byte */
+
+
+#ifdef DEBUG_I2C
+#define PRINTD(fmt,args...) do { \
+ printf (fmt ,##args); \
+ } while (0)
+#else
+#define PRINTD(fmt,args...)
+#endif
+
+/*-----------------------------------------------------------------------
+ * Local functions
+ */
+#if !defined(CONFIG_SYS_I2C_INIT_BOARD)
+static void send_reset (void);
+#endif
+static void send_start (void);
+static void send_stop (void);
+static void send_ack (int);
+static int write_byte (uchar byte);
+static uchar read_byte (int);
+
+#if !defined(CONFIG_SYS_I2C_INIT_BOARD)
+/*-----------------------------------------------------------------------
+ * Send a reset sequence consisting of 9 clocks with the data signal high
+ * to clock any confused device back into an idle state. Also send a
+ * <stop> at the end of the sequence for belts & suspenders.
+ */
+static void send_reset(void)
+{
+ I2C_SOFT_DECLARATIONS /* intentional without ';' */
+ int j;
+
+ I2C_SCL(1);
+ I2C_SDA(1);
+#ifdef I2C_INIT
+ I2C_INIT;
+#endif
+ I2C_TRISTATE;
+ for(j = 0; j < 9; j++) {
+ I2C_SCL(0);
+ I2C_DELAY;
+ I2C_DELAY;
+ I2C_SCL(1);
+ I2C_DELAY;
+ I2C_DELAY;
+ }
+ send_stop();
+ I2C_TRISTATE;
+}
+#endif
+
+/*-----------------------------------------------------------------------
+ * START: High -> Low on SDA while SCL is High
+ */
+static void send_start(void)
+{
+ I2C_SOFT_DECLARATIONS /* intentional without ';' */
+
+ I2C_DELAY;
+ I2C_SDA(1);
+ I2C_ACTIVE;
+ I2C_DELAY;
+ I2C_SCL(1);
+ I2C_DELAY;
+ I2C_SDA(0);
+ I2C_DELAY;
+}
+
+/*-----------------------------------------------------------------------
+ * STOP: Low -> High on SDA while SCL is High
+ */
+static void send_stop(void)
+{
+ I2C_SOFT_DECLARATIONS /* intentional without ';' */
+
+ I2C_SCL(0);
+ I2C_DELAY;
+ I2C_SDA(0);
+ I2C_ACTIVE;
+ I2C_DELAY;
+ I2C_SCL(1);
+ I2C_DELAY;
+ I2C_SDA(1);
+ I2C_DELAY;
+ I2C_TRISTATE;
+}
+
+/*-----------------------------------------------------------------------
+ * ack should be I2C_ACK or I2C_NOACK
+ */
+static void send_ack(int ack)
+{
+ I2C_SOFT_DECLARATIONS /* intentional without ';' */
+
+ I2C_SCL(0);
+ I2C_DELAY;
+ I2C_ACTIVE;
+ I2C_SDA(ack);
+ I2C_DELAY;
+ I2C_SCL(1);
+ I2C_DELAY;
+ I2C_DELAY;
+ I2C_SCL(0);
+ I2C_DELAY;
+}
+
+/*-----------------------------------------------------------------------
+ * Send 8 bits and look for an acknowledgement.
+ */
+static int write_byte(uchar data)
+{
+ I2C_SOFT_DECLARATIONS /* intentional without ';' */
+ int j;
+ int nack;
+
+ I2C_ACTIVE;
+ for(j = 0; j < 8; j++) {
+ I2C_SCL(0);
+ I2C_DELAY;
+ I2C_SDA(data & 0x80);
+ I2C_DELAY;
+ I2C_SCL(1);
+ I2C_DELAY;
+ I2C_DELAY;
+
+ data <<= 1;
+ }
+
+ /*
+ * Look for an <ACK>(negative logic) and return it.
+ */
+ I2C_SCL(0);
+ I2C_DELAY;
+ I2C_SDA(1);
+ I2C_TRISTATE;
+ I2C_DELAY;
+ I2C_SCL(1);
+ I2C_DELAY;
+ I2C_DELAY;
+ nack = I2C_READ;
+ I2C_SCL(0);
+ I2C_DELAY;
+ I2C_ACTIVE;
+
+ return(nack); /* not a nack is an ack */
+}
+
+/*-----------------------------------------------------------------------
+ * if ack == I2C_ACK, ACK the byte so can continue reading, else
+ * send I2C_NOACK to end the read.
+ */
+static uchar read_byte(int ack)
+{
+ I2C_SOFT_DECLARATIONS /* intentional without ';' */
+ int data;
+ int j;
+
+ /*
+ * Read 8 bits, MSB first.
+ */
+ I2C_TRISTATE;
+ I2C_SDA(1);
+ data = 0;
+ for(j = 0; j < 8; j++) {
+ I2C_SCL(0);
+ I2C_DELAY;
+ I2C_SCL(1);
+ I2C_DELAY;
+ data <<= 1;
+ data |= I2C_READ;
+ I2C_DELAY;
+ }
+ send_ack(ack);
+
+ return(data);
+}
+
+/*-----------------------------------------------------------------------
+ * Initialization
+ */
+static void soft_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
+{
+#if defined(CONFIG_SYS_I2C_INIT_BOARD)
+ /* call board specific i2c bus reset routine before accessing the */
+ /* environment, which might be in a chip on that bus. For details */
+ /* about this problem see doc/I2C_Edge_Conditions. */
+ i2c_init_board();
+#else
+ /*
+ * WARNING: Do NOT save speed in a static variable: if the
+ * I2C routines are called before RAM is initialized (to read
+ * the DIMM SPD, for instance), RAM won't be usable and your
+ * system will crash.
+ */
+ send_reset ();
+#endif
+}
+
+/*-----------------------------------------------------------------------
+ * Probe to see if a chip is present. Also good for checking for the
+ * completion of EEPROM writes since the chip stops responding until
+ * the write completes (typically 10mSec).
+ */
+static int soft_i2c_probe(struct i2c_adapter *adap, uint8_t addr)
+{
+ int rc;
+
+ /*
+ * perform 1 byte write transaction with just address byte
+ * (fake write)
+ */
+ send_start();
+ rc = write_byte ((addr << 1) | 0);
+ send_stop();
+
+ return (rc ? 1 : 0);
+}
+
+/*-----------------------------------------------------------------------
+ * Read bytes
+ */
+static int soft_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
+ int alen, uchar *buffer, int len)
+{
+ int shift;
+ PRINTD("i2c_read: chip %02X addr %02X alen %d buffer %p len %d\n",
+ chip, addr, alen, buffer, len);
+
+#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW
+ /*
+ * EEPROM chips that implement "address overflow" are ones
+ * like Catalyst 24WC04/08/16 which has 9/10/11 bits of
+ * address and the extra bits end up in the "chip address"
+ * bit slots. This makes a 24WC08 (1Kbyte) chip look like
+ * four 256 byte chips.
+ *
+ * Note that we consider the length of the address field to
+ * still be one byte because the extra address bits are
+ * hidden in the chip address.
+ */
+ chip |= ((addr >> (alen * 8)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
+
+ PRINTD("i2c_read: fix addr_overflow: chip %02X addr %02X\n",
+ chip, addr);
+#endif
+
+ /*
+ * Do the addressing portion of a write cycle to set the
+ * chip's address pointer. If the address length is zero,
+ * don't do the normal write cycle to set the address pointer,
+ * there is no address pointer in this chip.
+ */
+ send_start();
+ if(alen > 0) {
+ if(write_byte(chip << 1)) { /* write cycle */
+ send_stop();
+ PRINTD("i2c_read, no chip responded %02X\n", chip);
+ return(1);
+ }
+ shift = (alen-1) * 8;
+ while(alen-- > 0) {
+ if(write_byte(addr >> shift)) {
+ PRINTD("i2c_read, address not <ACK>ed\n");
+ return(1);
+ }
+ shift -= 8;
+ }
+
+ /* Some I2C chips need a stop/start sequence here,
+ * other chips don't work with a full stop and need
+ * only a start. Default behaviour is to send the
+ * stop/start sequence.
+ */
+#ifdef CONFIG_SOFT_I2C_READ_REPEATED_START
+ send_start();
+#else
+ send_stop();
+ send_start();
+#endif
+ }
+ /*
+ * Send the chip address again, this time for a read cycle.
+ * Then read the data. On the last byte, we do a NACK instead
+ * of an ACK(len == 0) to terminate the read.
+ */
+ write_byte((chip << 1) | 1); /* read cycle */
+ while(len-- > 0) {
+ *buffer++ = read_byte(len == 0);
+ }
+ send_stop();
+ return(0);
+}
+
+/*-----------------------------------------------------------------------
+ * Write bytes
+ */
+static int soft_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
+ int alen, uchar *buffer, int len)
+{
+ int shift, failures = 0;
+
+ PRINTD("i2c_write: chip %02X addr %02X alen %d buffer %p len %d\n",
+ chip, addr, alen, buffer, len);
+
+ send_start();
+ if(write_byte(chip << 1)) { /* write cycle */
+ send_stop();
+ PRINTD("i2c_write, no chip responded %02X\n", chip);
+ return(1);
+ }
+ shift = (alen-1) * 8;
+ while(alen-- > 0) {
+ if(write_byte(addr >> shift)) {
+ PRINTD("i2c_write, address not <ACK>ed\n");
+ return(1);
+ }
+ shift -= 8;
+ }
+
+ while(len-- > 0) {
+ if(write_byte(*buffer++)) {
+ failures++;
+ }
+ }
+ send_stop();
+ return(failures);
+}
+
+/*
+ * Register soft i2c adapters
+ */
+U_BOOT_I2C_ADAP_COMPLETE(soft00, soft_i2c_init, soft_i2c_probe,
+ soft_i2c_read, soft_i2c_write, NULL,
+ CONFIG_SYS_I2C_SOFT_SPEED, CONFIG_SYS_I2C_SOFT_SLAVE,
+ 0)
+#if defined(I2C_SOFT_DECLARATIONS2)
+U_BOOT_I2C_ADAP_COMPLETE(soft01, soft_i2c_init, soft_i2c_probe,
+ soft_i2c_read, soft_i2c_write, NULL,
+ CONFIG_SYS_I2C_SOFT_SPEED_2,
+ CONFIG_SYS_I2C_SOFT_SLAVE_2,
+ 1)
+#endif
+#if defined(I2C_SOFT_DECLARATIONS3)
+U_BOOT_I2C_ADAP_COMPLETE(soft02, soft_i2c_init, soft_i2c_probe,
+ soft_i2c_read, soft_i2c_write, NULL,
+ CONFIG_SYS_I2C_SOFT_SPEED_3,
+ CONFIG_SYS_I2C_SOFT_SLAVE_3,
+ 2)
+#endif
+#if defined(I2C_SOFT_DECLARATIONS4)
+U_BOOT_I2C_ADAP_COMPLETE(soft03, soft_i2c_init, soft_i2c_probe,
+ soft_i2c_read, soft_i2c_write, NULL,
+ CONFIG_SYS_I2C_SOFT_SPEED_4,
+ CONFIG_SYS_I2C_SOFT_SLAVE_4,
+ 3)
+#endif
+#if defined(I2C_SOFT_DECLARATIONS5)
+U_BOOT_I2C_ADAP_COMPLETE(soft04, soft_i2c_init, soft_i2c_probe,
+ soft_i2c_read, soft_i2c_write, NULL,
+ CONFIG_SYS_I2C_SOFT_SPEED_5,
+ CONFIG_SYS_I2C_SOFT_SLAVE_5,
+ 4)
+#endif
+#if defined(I2C_SOFT_DECLARATIONS6)
+U_BOOT_I2C_ADAP_COMPLETE(soft05, soft_i2c_init, soft_i2c_probe,
+ soft_i2c_read, soft_i2c_write, NULL,
+ CONFIG_SYS_I2C_SOFT_SPEED_6,
+ CONFIG_SYS_I2C_SOFT_SLAVE_6,
+ 5)
+#endif
+#if defined(I2C_SOFT_DECLARATIONS7)
+U_BOOT_I2C_ADAP_COMPLETE(soft06, soft_i2c_init, soft_i2c_probe,
+ soft_i2c_read, soft_i2c_write, NULL,
+ CONFIG_SYS_I2C_SOFT_SPEED_7,
+ CONFIG_SYS_I2C_SOFT_SLAVE_7,
+ 6)
+#endif
+#if defined(I2C_SOFT_DECLARATIONS8)
+U_BOOT_I2C_ADAP_COMPLETE(soft07, soft_i2c_init, soft_i2c_probe,
+ soft_i2c_read, soft_i2c_write, NULL,
+ CONFIG_SYS_I2C_SOFT_SPEED_8,
+ CONFIG_SYS_I2C_SOFT_SLAVE_8,
+ 7)
+#endif
+#if defined(I2C_SOFT_DECLARATIONS9)
+U_BOOT_I2C_ADAP_COMPLETE(soft08, soft_i2c_init, soft_i2c_probe,
+ soft_i2c_read, soft_i2c_write, NULL,
+ CONFIG_SYS_I2C_SOFT_SPEED_9,
+ CONFIG_SYS_I2C_SOFT_SLAVE_9,
+ 8)
+#endif
+#if defined(I2C_SOFT_DECLARATIONS10)
+U_BOOT_I2C_ADAP_COMPLETE(soft09, soft_i2c_init, soft_i2c_probe,
+ soft_i2c_read, soft_i2c_write, NULL,
+ CONFIG_SYS_I2C_SOFT_SPEED_10,
+ CONFIG_SYS_I2C_SOFT_SLAVE_10,
+ 9)
+#endif
+#if defined(I2C_SOFT_DECLARATIONS11)
+U_BOOT_I2C_ADAP_COMPLETE(soft10, soft_i2c_init, soft_i2c_probe,
+ soft_i2c_read, soft_i2c_write, NULL,
+ CONFIG_SYS_I2C_SOFT_SPEED_11,
+ CONFIG_SYS_I2C_SOFT_SLAVE_11,
+ 10)
+#endif
+#if defined(I2C_SOFT_DECLARATIONS12)
+U_BOOT_I2C_ADAP_COMPLETE(soft11, soft_i2c_init, soft_i2c_probe,
+ soft_i2c_read, soft_i2c_write, NULL,
+ CONFIG_SYS_I2C_SOFT_SPEED_12,
+ CONFIG_SYS_I2C_SOFT_SLAVE_12,
+ 11)
+#endif
diff --git a/roms/u-boot/drivers/i2c/stm32f7_i2c.c b/roms/u-boot/drivers/i2c/stm32f7_i2c.c
new file mode 100644
index 000000000..7b04a09de
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/stm32f7_i2c.c
@@ -0,0 +1,960 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2017 STMicroelectronics
+ */
+
+#define LOG_CATEGORY UCLASS_I2C
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <i2c.h>
+#include <log.h>
+#include <regmap.h>
+#include <reset.h>
+#include <syscon.h>
+#include <dm/device.h>
+#include <dm/device_compat.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+/* STM32 I2C registers */
+struct stm32_i2c_regs {
+ u32 cr1; /* I2C control register 1 */
+ u32 cr2; /* I2C control register 2 */
+ u32 oar1; /* I2C own address 1 register */
+ u32 oar2; /* I2C own address 2 register */
+ u32 timingr; /* I2C timing register */
+ u32 timeoutr; /* I2C timeout register */
+ u32 isr; /* I2C interrupt and status register */
+ u32 icr; /* I2C interrupt clear register */
+ u32 pecr; /* I2C packet error checking register */
+ u32 rxdr; /* I2C receive data register */
+ u32 txdr; /* I2C transmit data register */
+};
+
+#define STM32_I2C_CR1 0x00
+#define STM32_I2C_CR2 0x04
+#define STM32_I2C_TIMINGR 0x10
+#define STM32_I2C_ISR 0x18
+#define STM32_I2C_ICR 0x1C
+#define STM32_I2C_RXDR 0x24
+#define STM32_I2C_TXDR 0x28
+
+/* STM32 I2C control 1 */
+#define STM32_I2C_CR1_ANFOFF BIT(12)
+#define STM32_I2C_CR1_ERRIE BIT(7)
+#define STM32_I2C_CR1_TCIE BIT(6)
+#define STM32_I2C_CR1_STOPIE BIT(5)
+#define STM32_I2C_CR1_NACKIE BIT(4)
+#define STM32_I2C_CR1_ADDRIE BIT(3)
+#define STM32_I2C_CR1_RXIE BIT(2)
+#define STM32_I2C_CR1_TXIE BIT(1)
+#define STM32_I2C_CR1_PE BIT(0)
+
+/* STM32 I2C control 2 */
+#define STM32_I2C_CR2_AUTOEND BIT(25)
+#define STM32_I2C_CR2_RELOAD BIT(24)
+#define STM32_I2C_CR2_NBYTES_MASK GENMASK(23, 16)
+#define STM32_I2C_CR2_NBYTES(n) ((n & 0xff) << 16)
+#define STM32_I2C_CR2_NACK BIT(15)
+#define STM32_I2C_CR2_STOP BIT(14)
+#define STM32_I2C_CR2_START BIT(13)
+#define STM32_I2C_CR2_HEAD10R BIT(12)
+#define STM32_I2C_CR2_ADD10 BIT(11)
+#define STM32_I2C_CR2_RD_WRN BIT(10)
+#define STM32_I2C_CR2_SADD10_MASK GENMASK(9, 0)
+#define STM32_I2C_CR2_SADD10(n) (n & STM32_I2C_CR2_SADD10_MASK)
+#define STM32_I2C_CR2_SADD7_MASK GENMASK(7, 1)
+#define STM32_I2C_CR2_SADD7(n) ((n & 0x7f) << 1)
+#define STM32_I2C_CR2_RESET_MASK (STM32_I2C_CR2_HEAD10R \
+ | STM32_I2C_CR2_NBYTES_MASK \
+ | STM32_I2C_CR2_SADD7_MASK \
+ | STM32_I2C_CR2_RELOAD \
+ | STM32_I2C_CR2_RD_WRN)
+
+/* STM32 I2C Interrupt Status */
+#define STM32_I2C_ISR_BUSY BIT(15)
+#define STM32_I2C_ISR_ARLO BIT(9)
+#define STM32_I2C_ISR_BERR BIT(8)
+#define STM32_I2C_ISR_TCR BIT(7)
+#define STM32_I2C_ISR_TC BIT(6)
+#define STM32_I2C_ISR_STOPF BIT(5)
+#define STM32_I2C_ISR_NACKF BIT(4)
+#define STM32_I2C_ISR_ADDR BIT(3)
+#define STM32_I2C_ISR_RXNE BIT(2)
+#define STM32_I2C_ISR_TXIS BIT(1)
+#define STM32_I2C_ISR_TXE BIT(0)
+#define STM32_I2C_ISR_ERRORS (STM32_I2C_ISR_BERR \
+ | STM32_I2C_ISR_ARLO)
+
+/* STM32 I2C Interrupt Clear */
+#define STM32_I2C_ICR_ARLOCF BIT(9)
+#define STM32_I2C_ICR_BERRCF BIT(8)
+#define STM32_I2C_ICR_STOPCF BIT(5)
+#define STM32_I2C_ICR_NACKCF BIT(4)
+
+/* STM32 I2C Timing */
+#define STM32_I2C_TIMINGR_PRESC(n) ((n & 0xf) << 28)
+#define STM32_I2C_TIMINGR_SCLDEL(n) ((n & 0xf) << 20)
+#define STM32_I2C_TIMINGR_SDADEL(n) ((n & 0xf) << 16)
+#define STM32_I2C_TIMINGR_SCLH(n) ((n & 0xff) << 8)
+#define STM32_I2C_TIMINGR_SCLL(n) (n & 0xff)
+
+#define STM32_I2C_MAX_LEN 0xff
+
+#define STM32_I2C_DNF_DEFAULT 0
+#define STM32_I2C_DNF_MAX 16
+
+#define STM32_I2C_ANALOG_FILTER_ENABLE 1
+#define STM32_I2C_ANALOG_FILTER_DELAY_MIN 50 /* ns */
+#define STM32_I2C_ANALOG_FILTER_DELAY_MAX 260 /* ns */
+
+#define STM32_I2C_RISE_TIME_DEFAULT 25 /* ns */
+#define STM32_I2C_FALL_TIME_DEFAULT 10 /* ns */
+
+#define STM32_PRESC_MAX BIT(4)
+#define STM32_SCLDEL_MAX BIT(4)
+#define STM32_SDADEL_MAX BIT(4)
+#define STM32_SCLH_MAX BIT(8)
+#define STM32_SCLL_MAX BIT(8)
+
+#define STM32_NSEC_PER_SEC 1000000000L
+
+/**
+ * struct stm32_i2c_spec - private i2c specification timing
+ * @rate: I2C bus speed (Hz)
+ * @rate_min: 80% of I2C bus speed (Hz)
+ * @rate_max: 120% of I2C bus speed (Hz)
+ * @fall_max: Max fall time of both SDA and SCL signals (ns)
+ * @rise_max: Max rise time of both SDA and SCL signals (ns)
+ * @hddat_min: Min data hold time (ns)
+ * @vddat_max: Max data valid time (ns)
+ * @sudat_min: Min data setup time (ns)
+ * @l_min: Min low period of the SCL clock (ns)
+ * @h_min: Min high period of the SCL clock (ns)
+ */
+
+struct stm32_i2c_spec {
+ u32 rate;
+ u32 rate_min;
+ u32 rate_max;
+ u32 fall_max;
+ u32 rise_max;
+ u32 hddat_min;
+ u32 vddat_max;
+ u32 sudat_min;
+ u32 l_min;
+ u32 h_min;
+};
+
+/**
+ * struct stm32_i2c_setup - private I2C timing setup parameters
+ * @speed_freq: I2C speed frequency (Hz)
+ * @clock_src: I2C clock source frequency (Hz)
+ * @rise_time: Rise time (ns)
+ * @fall_time: Fall time (ns)
+ * @dnf: Digital filter coefficient (0-16)
+ * @analog_filter: Analog filter delay (On/Off)
+ * @fmp_clr_offset: Fast Mode Plus clear register offset from set register
+ */
+struct stm32_i2c_setup {
+ u32 speed_freq;
+ u32 clock_src;
+ u32 rise_time;
+ u32 fall_time;
+ u8 dnf;
+ bool analog_filter;
+ u32 fmp_clr_offset;
+};
+
+/**
+ * struct stm32_i2c_timings - private I2C output parameters
+ * @prec: Prescaler value
+ * @scldel: Data setup time
+ * @sdadel: Data hold time
+ * @sclh: SCL high period (master mode)
+ * @sclh: SCL low period (master mode)
+ */
+struct stm32_i2c_timings {
+ struct list_head node;
+ u8 presc;
+ u8 scldel;
+ u8 sdadel;
+ u8 sclh;
+ u8 scll;
+};
+
+/**
+ * struct stm32_i2c_priv - private data of the controller
+ * @regs: I2C registers address
+ * @clk: hw i2c clock
+ * @setup: I2C timing setup parameters
+ * @speed: I2C clock frequency of the controller. Standard, Fast or Fast+
+ * @regmap: holds SYSCFG phandle for Fast Mode Plus bit
+ * @regmap_sreg: register address for setting Fast Mode Plus bits
+ * @regmap_creg: register address for clearing Fast Mode Plus bits
+ * @regmap_mask: mask for Fast Mode Plus bits
+ */
+struct stm32_i2c_priv {
+ struct stm32_i2c_regs *regs;
+ struct clk clk;
+ struct stm32_i2c_setup *setup;
+ u32 speed;
+ struct regmap *regmap;
+ u32 regmap_sreg;
+ u32 regmap_creg;
+ u32 regmap_mask;
+};
+
+static const struct stm32_i2c_spec i2c_specs[] = {
+ /* Standard speed - 100 KHz */
+ [IC_SPEED_MODE_STANDARD] = {
+ .rate = I2C_SPEED_STANDARD_RATE,
+ .rate_min = 8000,
+ .rate_max = 120000,
+ .fall_max = 300,
+ .rise_max = 1000,
+ .hddat_min = 0,
+ .vddat_max = 3450,
+ .sudat_min = 250,
+ .l_min = 4700,
+ .h_min = 4000,
+ },
+ /* Fast speed - 400 KHz */
+ [IC_SPEED_MODE_FAST] = {
+ .rate = I2C_SPEED_FAST_RATE,
+ .rate_min = 320000,
+ .rate_max = 480000,
+ .fall_max = 300,
+ .rise_max = 300,
+ .hddat_min = 0,
+ .vddat_max = 900,
+ .sudat_min = 100,
+ .l_min = 1300,
+ .h_min = 600,
+ },
+ /* Fast Plus Speed - 1 MHz */
+ [IC_SPEED_MODE_FAST_PLUS] = {
+ .rate = I2C_SPEED_FAST_PLUS_RATE,
+ .rate_min = 800000,
+ .rate_max = 1200000,
+ .fall_max = 100,
+ .rise_max = 120,
+ .hddat_min = 0,
+ .vddat_max = 450,
+ .sudat_min = 50,
+ .l_min = 500,
+ .h_min = 260,
+ },
+};
+
+static const struct stm32_i2c_setup stm32f7_setup = {
+ .rise_time = STM32_I2C_RISE_TIME_DEFAULT,
+ .fall_time = STM32_I2C_FALL_TIME_DEFAULT,
+ .dnf = STM32_I2C_DNF_DEFAULT,
+ .analog_filter = STM32_I2C_ANALOG_FILTER_ENABLE,
+};
+
+static const struct stm32_i2c_setup stm32mp15_setup = {
+ .rise_time = STM32_I2C_RISE_TIME_DEFAULT,
+ .fall_time = STM32_I2C_FALL_TIME_DEFAULT,
+ .dnf = STM32_I2C_DNF_DEFAULT,
+ .analog_filter = STM32_I2C_ANALOG_FILTER_ENABLE,
+ .fmp_clr_offset = 0x40,
+};
+
+static int stm32_i2c_check_device_busy(struct stm32_i2c_priv *i2c_priv)
+{
+ struct stm32_i2c_regs *regs = i2c_priv->regs;
+ u32 status = readl(&regs->isr);
+
+ if (status & STM32_I2C_ISR_BUSY)
+ return -EBUSY;
+
+ return 0;
+}
+
+static void stm32_i2c_message_start(struct stm32_i2c_priv *i2c_priv,
+ struct i2c_msg *msg, bool stop)
+{
+ struct stm32_i2c_regs *regs = i2c_priv->regs;
+ u32 cr2 = readl(&regs->cr2);
+
+ /* Set transfer direction */
+ cr2 &= ~STM32_I2C_CR2_RD_WRN;
+ if (msg->flags & I2C_M_RD)
+ cr2 |= STM32_I2C_CR2_RD_WRN;
+
+ /* Set slave address */
+ cr2 &= ~(STM32_I2C_CR2_HEAD10R | STM32_I2C_CR2_ADD10);
+ if (msg->flags & I2C_M_TEN) {
+ cr2 &= ~STM32_I2C_CR2_SADD10_MASK;
+ cr2 |= STM32_I2C_CR2_SADD10(msg->addr);
+ cr2 |= STM32_I2C_CR2_ADD10;
+ } else {
+ cr2 &= ~STM32_I2C_CR2_SADD7_MASK;
+ cr2 |= STM32_I2C_CR2_SADD7(msg->addr);
+ }
+
+ /* Set nb bytes to transfer and reload or autoend bits */
+ cr2 &= ~(STM32_I2C_CR2_NBYTES_MASK | STM32_I2C_CR2_RELOAD |
+ STM32_I2C_CR2_AUTOEND);
+ if (msg->len > STM32_I2C_MAX_LEN) {
+ cr2 |= STM32_I2C_CR2_NBYTES(STM32_I2C_MAX_LEN);
+ cr2 |= STM32_I2C_CR2_RELOAD;
+ } else {
+ cr2 |= STM32_I2C_CR2_NBYTES(msg->len);
+ }
+
+ /* Write configurations register */
+ writel(cr2, &regs->cr2);
+
+ /* START/ReSTART generation */
+ setbits_le32(&regs->cr2, STM32_I2C_CR2_START);
+}
+
+/*
+ * RELOAD mode must be selected if total number of data bytes to be
+ * sent is greater than MAX_LEN
+ */
+
+static void stm32_i2c_handle_reload(struct stm32_i2c_priv *i2c_priv,
+ struct i2c_msg *msg, bool stop)
+{
+ struct stm32_i2c_regs *regs = i2c_priv->regs;
+ u32 cr2 = readl(&regs->cr2);
+
+ cr2 &= ~STM32_I2C_CR2_NBYTES_MASK;
+
+ if (msg->len > STM32_I2C_MAX_LEN) {
+ cr2 |= STM32_I2C_CR2_NBYTES(STM32_I2C_MAX_LEN);
+ } else {
+ cr2 &= ~STM32_I2C_CR2_RELOAD;
+ cr2 |= STM32_I2C_CR2_NBYTES(msg->len);
+ }
+
+ writel(cr2, &regs->cr2);
+}
+
+static int stm32_i2c_wait_flags(struct stm32_i2c_priv *i2c_priv,
+ u32 flags, u32 *status)
+{
+ struct stm32_i2c_regs *regs = i2c_priv->regs;
+ u32 time_start = get_timer(0);
+
+ *status = readl(&regs->isr);
+ while (!(*status & flags)) {
+ if (get_timer(time_start) > CONFIG_SYS_HZ) {
+ log_debug("i2c timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ *status = readl(&regs->isr);
+ }
+
+ return 0;
+}
+
+static int stm32_i2c_check_end_of_message(struct stm32_i2c_priv *i2c_priv)
+{
+ struct stm32_i2c_regs *regs = i2c_priv->regs;
+ u32 mask = STM32_I2C_ISR_ERRORS | STM32_I2C_ISR_NACKF |
+ STM32_I2C_ISR_STOPF;
+ u32 status;
+ int ret;
+
+ ret = stm32_i2c_wait_flags(i2c_priv, mask, &status);
+ if (ret)
+ return ret;
+
+ if (status & STM32_I2C_ISR_BERR) {
+ log_debug("Bus error\n");
+
+ /* Clear BERR flag */
+ setbits_le32(&regs->icr, STM32_I2C_ICR_BERRCF);
+
+ return -EIO;
+ }
+
+ if (status & STM32_I2C_ISR_ARLO) {
+ log_debug("Arbitration lost\n");
+
+ /* Clear ARLO flag */
+ setbits_le32(&regs->icr, STM32_I2C_ICR_ARLOCF);
+
+ return -EAGAIN;
+ }
+
+ if (status & STM32_I2C_ISR_NACKF) {
+ log_debug("Receive NACK\n");
+
+ /* Clear NACK flag */
+ setbits_le32(&regs->icr, STM32_I2C_ICR_NACKCF);
+
+ /* Wait until STOPF flag is set */
+ mask = STM32_I2C_ISR_STOPF;
+ ret = stm32_i2c_wait_flags(i2c_priv, mask, &status);
+ if (ret)
+ return ret;
+
+ ret = -EIO;
+ }
+
+ if (status & STM32_I2C_ISR_STOPF) {
+ /* Clear STOP flag */
+ setbits_le32(&regs->icr, STM32_I2C_ICR_STOPCF);
+
+ /* Clear control register 2 */
+ setbits_le32(&regs->cr2, STM32_I2C_CR2_RESET_MASK);
+ }
+
+ return ret;
+}
+
+static int stm32_i2c_message_xfer(struct stm32_i2c_priv *i2c_priv,
+ struct i2c_msg *msg, bool stop)
+{
+ struct stm32_i2c_regs *regs = i2c_priv->regs;
+ u32 status;
+ u32 mask = msg->flags & I2C_M_RD ? STM32_I2C_ISR_RXNE :
+ STM32_I2C_ISR_TXIS | STM32_I2C_ISR_NACKF;
+ int bytes_to_rw = msg->len > STM32_I2C_MAX_LEN ?
+ STM32_I2C_MAX_LEN : msg->len;
+ int ret = 0;
+
+ /* Add errors */
+ mask |= STM32_I2C_ISR_ERRORS;
+
+ stm32_i2c_message_start(i2c_priv, msg, stop);
+
+ while (msg->len) {
+ /*
+ * Wait until TXIS/NACKF/BERR/ARLO flags or
+ * RXNE/BERR/ARLO flags are set
+ */
+ ret = stm32_i2c_wait_flags(i2c_priv, mask, &status);
+ if (ret)
+ break;
+
+ if (status & (STM32_I2C_ISR_NACKF | STM32_I2C_ISR_ERRORS))
+ break;
+
+ if (status & STM32_I2C_ISR_RXNE) {
+ *msg->buf++ = readb(&regs->rxdr);
+ msg->len--;
+ bytes_to_rw--;
+ }
+
+ if (status & STM32_I2C_ISR_TXIS) {
+ writeb(*msg->buf++, &regs->txdr);
+ msg->len--;
+ bytes_to_rw--;
+ }
+
+ if (!bytes_to_rw && msg->len) {
+ /* Wait until TCR flag is set */
+ mask = STM32_I2C_ISR_TCR;
+ ret = stm32_i2c_wait_flags(i2c_priv, mask, &status);
+ if (ret)
+ break;
+
+ bytes_to_rw = msg->len > STM32_I2C_MAX_LEN ?
+ STM32_I2C_MAX_LEN : msg->len;
+ mask = msg->flags & I2C_M_RD ? STM32_I2C_ISR_RXNE :
+ STM32_I2C_ISR_TXIS | STM32_I2C_ISR_NACKF;
+
+ stm32_i2c_handle_reload(i2c_priv, msg, stop);
+ } else if (!bytes_to_rw) {
+ /* Wait until TC flag is set */
+ mask = STM32_I2C_ISR_TC;
+ ret = stm32_i2c_wait_flags(i2c_priv, mask, &status);
+ if (ret)
+ break;
+
+ if (!stop)
+ /* Message sent, new message has to be sent */
+ return 0;
+ }
+ }
+
+ /* End of transfer, send stop condition */
+ mask = STM32_I2C_CR2_STOP;
+ setbits_le32(&regs->cr2, mask);
+
+ return stm32_i2c_check_end_of_message(i2c_priv);
+}
+
+static int stm32_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
+ int nmsgs)
+{
+ struct stm32_i2c_priv *i2c_priv = dev_get_priv(bus);
+ int ret;
+
+ ret = stm32_i2c_check_device_busy(i2c_priv);
+ if (ret)
+ return ret;
+
+ for (; nmsgs > 0; nmsgs--, msg++) {
+ ret = stm32_i2c_message_xfer(i2c_priv, msg, nmsgs == 1);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int stm32_i2c_compute_solutions(struct stm32_i2c_setup *setup,
+ const struct stm32_i2c_spec *specs,
+ struct list_head *solutions)
+{
+ struct stm32_i2c_timings *v;
+ u32 p_prev = STM32_PRESC_MAX;
+ u32 i2cclk = DIV_ROUND_CLOSEST(STM32_NSEC_PER_SEC,
+ setup->clock_src);
+ u32 af_delay_min, af_delay_max;
+ u16 p, l, a;
+ int sdadel_min, sdadel_max, scldel_min;
+ int ret = 0;
+
+ af_delay_min = setup->analog_filter ?
+ STM32_I2C_ANALOG_FILTER_DELAY_MIN : 0;
+ af_delay_max = setup->analog_filter ?
+ STM32_I2C_ANALOG_FILTER_DELAY_MAX : 0;
+
+ sdadel_min = specs->hddat_min + setup->fall_time -
+ af_delay_min - (setup->dnf + 3) * i2cclk;
+
+ sdadel_max = specs->vddat_max - setup->rise_time -
+ af_delay_max - (setup->dnf + 4) * i2cclk;
+
+ scldel_min = setup->rise_time + specs->sudat_min;
+
+ if (sdadel_min < 0)
+ sdadel_min = 0;
+ if (sdadel_max < 0)
+ sdadel_max = 0;
+
+ log_debug("SDADEL(min/max): %i/%i, SCLDEL(Min): %i\n",
+ sdadel_min, sdadel_max, scldel_min);
+
+ /* Compute possible values for PRESC, SCLDEL and SDADEL */
+ for (p = 0; p < STM32_PRESC_MAX; p++) {
+ for (l = 0; l < STM32_SCLDEL_MAX; l++) {
+ int scldel = (l + 1) * (p + 1) * i2cclk;
+
+ if (scldel < scldel_min)
+ continue;
+
+ for (a = 0; a < STM32_SDADEL_MAX; a++) {
+ int sdadel = (a * (p + 1) + 1) * i2cclk;
+
+ if (((sdadel >= sdadel_min) &&
+ (sdadel <= sdadel_max)) &&
+ (p != p_prev)) {
+ v = calloc(1, sizeof(*v));
+ if (!v)
+ return -ENOMEM;
+
+ v->presc = p;
+ v->scldel = l;
+ v->sdadel = a;
+ p_prev = p;
+
+ list_add_tail(&v->node, solutions);
+ break;
+ }
+ }
+
+ if (p_prev == p)
+ break;
+ }
+ }
+
+ if (list_empty(solutions)) {
+ log_err("no Prescaler solution\n");
+ ret = -EPERM;
+ }
+
+ return ret;
+}
+
+static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup,
+ const struct stm32_i2c_spec *specs,
+ struct list_head *solutions,
+ struct stm32_i2c_timings *s)
+{
+ struct stm32_i2c_timings *v;
+ u32 i2cbus = DIV_ROUND_CLOSEST(STM32_NSEC_PER_SEC,
+ setup->speed_freq);
+ u32 clk_error_prev = i2cbus;
+ u32 i2cclk = DIV_ROUND_CLOSEST(STM32_NSEC_PER_SEC,
+ setup->clock_src);
+ u32 clk_min, clk_max;
+ u32 af_delay_min;
+ u32 dnf_delay;
+ u32 tsync;
+ u16 l, h;
+ bool sol_found = false;
+ int ret = 0;
+
+ af_delay_min = setup->analog_filter ?
+ STM32_I2C_ANALOG_FILTER_DELAY_MIN : 0;
+ dnf_delay = setup->dnf * i2cclk;
+
+ tsync = af_delay_min + dnf_delay + (2 * i2cclk);
+ clk_max = STM32_NSEC_PER_SEC / specs->rate_min;
+ clk_min = STM32_NSEC_PER_SEC / specs->rate_max;
+
+ /*
+ * Among Prescaler possibilities discovered above figures out SCL Low
+ * and High Period. Provided:
+ * - SCL Low Period has to be higher than Low Period of the SCL Clock
+ * defined by I2C Specification. I2C Clock has to be lower than
+ * (SCL Low Period - Analog/Digital filters) / 4.
+ * - SCL High Period has to be lower than High Period of the SCL Clock
+ * defined by I2C Specification
+ * - I2C Clock has to be lower than SCL High Period
+ */
+ list_for_each_entry(v, solutions, node) {
+ u32 prescaler = (v->presc + 1) * i2cclk;
+
+ for (l = 0; l < STM32_SCLL_MAX; l++) {
+ u32 tscl_l = (l + 1) * prescaler + tsync;
+
+ if (tscl_l < specs->l_min ||
+ (i2cclk >=
+ ((tscl_l - af_delay_min - dnf_delay) / 4))) {
+ continue;
+ }
+
+ for (h = 0; h < STM32_SCLH_MAX; h++) {
+ u32 tscl_h = (h + 1) * prescaler + tsync;
+ u32 tscl = tscl_l + tscl_h +
+ setup->rise_time + setup->fall_time;
+
+ if ((tscl >= clk_min) && (tscl <= clk_max) &&
+ (tscl_h >= specs->h_min) &&
+ (i2cclk < tscl_h)) {
+ u32 clk_error;
+
+ if (tscl > i2cbus)
+ clk_error = tscl - i2cbus;
+ else
+ clk_error = i2cbus - tscl;
+
+ if (clk_error < clk_error_prev) {
+ clk_error_prev = clk_error;
+ v->scll = l;
+ v->sclh = h;
+ sol_found = true;
+ memcpy(s, v, sizeof(*s));
+ }
+ }
+ }
+ }
+ }
+
+ if (!sol_found) {
+ log_err("no solution at all\n");
+ ret = -EPERM;
+ }
+
+ return ret;
+}
+
+static const struct stm32_i2c_spec *get_specs(u32 rate)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(i2c_specs); i++)
+ if (rate <= i2c_specs[i].rate)
+ return &i2c_specs[i];
+
+ /* NOT REACHED */
+ return ERR_PTR(-EINVAL);
+}
+
+static int stm32_i2c_compute_timing(struct stm32_i2c_priv *i2c_priv,
+ struct stm32_i2c_setup *setup,
+ struct stm32_i2c_timings *output)
+{
+ const struct stm32_i2c_spec *specs;
+ struct stm32_i2c_timings *v, *_v;
+ struct list_head solutions;
+ int ret;
+
+ specs = get_specs(setup->speed_freq);
+ if (specs == ERR_PTR(-EINVAL)) {
+ log_err("speed out of bound {%d}\n",
+ setup->speed_freq);
+ return -EINVAL;
+ }
+
+ if (setup->rise_time > specs->rise_max ||
+ setup->fall_time > specs->fall_max) {
+ log_err("timings out of bound Rise{%d>%d}/Fall{%d>%d}\n",
+ setup->rise_time, specs->rise_max,
+ setup->fall_time, specs->fall_max);
+ return -EINVAL;
+ }
+
+ if (setup->dnf > STM32_I2C_DNF_MAX) {
+ log_err("DNF out of bound %d/%d\n",
+ setup->dnf, STM32_I2C_DNF_MAX);
+ return -EINVAL;
+ }
+
+ INIT_LIST_HEAD(&solutions);
+ ret = stm32_i2c_compute_solutions(setup, specs, &solutions);
+ if (ret)
+ goto exit;
+
+ ret = stm32_i2c_choose_solution(setup, specs, &solutions, output);
+ if (ret)
+ goto exit;
+
+ log_debug("Presc: %i, scldel: %i, sdadel: %i, scll: %i, sclh: %i\n",
+ output->presc,
+ output->scldel, output->sdadel,
+ output->scll, output->sclh);
+
+exit:
+ /* Release list and memory */
+ list_for_each_entry_safe(v, _v, &solutions, node) {
+ list_del(&v->node);
+ free(v);
+ }
+
+ return ret;
+}
+
+static u32 get_lower_rate(u32 rate)
+{
+ int i;
+
+ for (i = ARRAY_SIZE(i2c_specs) - 1; i >= 0; i--)
+ if (rate > i2c_specs[i].rate)
+ return i2c_specs[i].rate;
+
+ return i2c_specs[0].rate;
+}
+
+static int stm32_i2c_setup_timing(struct stm32_i2c_priv *i2c_priv,
+ struct stm32_i2c_timings *timing)
+{
+ struct stm32_i2c_setup *setup = i2c_priv->setup;
+ int ret = 0;
+
+ setup->speed_freq = i2c_priv->speed;
+ setup->clock_src = clk_get_rate(&i2c_priv->clk);
+
+ if (!setup->clock_src) {
+ log_err("clock rate is 0\n");
+ return -EINVAL;
+ }
+
+ do {
+ ret = stm32_i2c_compute_timing(i2c_priv, setup, timing);
+ if (ret) {
+ log_debug("failed to compute I2C timings.\n");
+ if (setup->speed_freq > I2C_SPEED_STANDARD_RATE) {
+ setup->speed_freq =
+ get_lower_rate(setup->speed_freq);
+ log_debug("downgrade I2C Speed Freq to (%i)\n",
+ setup->speed_freq);
+ } else {
+ break;
+ }
+ }
+ } while (ret);
+
+ if (ret) {
+ log_err("impossible to compute I2C timings.\n");
+ return ret;
+ }
+
+ log_debug("I2C Freq(%i), Clk Source(%i)\n",
+ setup->speed_freq, setup->clock_src);
+ log_debug("I2C Rise(%i) and Fall(%i) Time\n",
+ setup->rise_time, setup->fall_time);
+ log_debug("I2C Analog Filter(%s), DNF(%i)\n",
+ setup->analog_filter ? "On" : "Off", setup->dnf);
+
+ i2c_priv->speed = setup->speed_freq;
+
+ return 0;
+}
+
+static int stm32_i2c_write_fm_plus_bits(struct stm32_i2c_priv *i2c_priv)
+{
+ int ret;
+ bool enable = i2c_priv->speed > I2C_SPEED_FAST_RATE;
+
+ /* Optional */
+ if (IS_ERR_OR_NULL(i2c_priv->regmap))
+ return 0;
+
+ if (i2c_priv->regmap_sreg == i2c_priv->regmap_creg)
+ ret = regmap_update_bits(i2c_priv->regmap,
+ i2c_priv->regmap_sreg,
+ i2c_priv->regmap_mask,
+ enable ? i2c_priv->regmap_mask : 0);
+ else
+ ret = regmap_write(i2c_priv->regmap,
+ enable ? i2c_priv->regmap_sreg :
+ i2c_priv->regmap_creg,
+ i2c_priv->regmap_mask);
+
+ return ret;
+}
+
+static int stm32_i2c_hw_config(struct stm32_i2c_priv *i2c_priv)
+{
+ struct stm32_i2c_regs *regs = i2c_priv->regs;
+ struct stm32_i2c_timings t;
+ int ret;
+ u32 timing = 0;
+
+ ret = stm32_i2c_setup_timing(i2c_priv, &t);
+ if (ret)
+ return ret;
+
+ /* Disable I2C */
+ clrbits_le32(&regs->cr1, STM32_I2C_CR1_PE);
+
+ /* Setup Fast mode plus if necessary */
+ ret = stm32_i2c_write_fm_plus_bits(i2c_priv);
+ if (ret)
+ return ret;
+
+ /* Timing settings */
+ timing |= STM32_I2C_TIMINGR_PRESC(t.presc);
+ timing |= STM32_I2C_TIMINGR_SCLDEL(t.scldel);
+ timing |= STM32_I2C_TIMINGR_SDADEL(t.sdadel);
+ timing |= STM32_I2C_TIMINGR_SCLH(t.sclh);
+ timing |= STM32_I2C_TIMINGR_SCLL(t.scll);
+ writel(timing, &regs->timingr);
+
+ /* Enable I2C */
+ if (i2c_priv->setup->analog_filter)
+ clrbits_le32(&regs->cr1, STM32_I2C_CR1_ANFOFF);
+ else
+ setbits_le32(&regs->cr1, STM32_I2C_CR1_ANFOFF);
+ setbits_le32(&regs->cr1, STM32_I2C_CR1_PE);
+
+ return 0;
+}
+
+static int stm32_i2c_set_bus_speed(struct udevice *dev, unsigned int speed)
+{
+ struct stm32_i2c_priv *i2c_priv = dev_get_priv(dev);
+
+ if (speed > I2C_SPEED_FAST_PLUS_RATE) {
+ dev_dbg(dev, "Speed %d not supported\n", speed);
+ return -EINVAL;
+ }
+
+ i2c_priv->speed = speed;
+
+ return stm32_i2c_hw_config(i2c_priv);
+}
+
+static int stm32_i2c_probe(struct udevice *dev)
+{
+ struct stm32_i2c_priv *i2c_priv = dev_get_priv(dev);
+ struct reset_ctl reset_ctl;
+ fdt_addr_t addr;
+ int ret;
+
+ addr = dev_read_addr(dev);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ i2c_priv->regs = (struct stm32_i2c_regs *)addr;
+
+ ret = clk_get_by_index(dev, 0, &i2c_priv->clk);
+ if (ret)
+ return ret;
+
+ ret = clk_enable(&i2c_priv->clk);
+ if (ret)
+ goto clk_free;
+
+ ret = reset_get_by_index(dev, 0, &reset_ctl);
+ if (ret)
+ goto clk_disable;
+
+ reset_assert(&reset_ctl);
+ udelay(2);
+ reset_deassert(&reset_ctl);
+
+ return 0;
+
+clk_disable:
+ clk_disable(&i2c_priv->clk);
+clk_free:
+ clk_free(&i2c_priv->clk);
+
+ return ret;
+}
+
+static int stm32_of_to_plat(struct udevice *dev)
+{
+ struct stm32_i2c_priv *i2c_priv = dev_get_priv(dev);
+ u32 rise_time, fall_time;
+ int ret;
+
+ i2c_priv->setup = (struct stm32_i2c_setup *)dev_get_driver_data(dev);
+ if (!i2c_priv->setup)
+ return -EINVAL;
+
+ rise_time = dev_read_u32_default(dev, "i2c-scl-rising-time-ns", 0);
+ if (rise_time)
+ i2c_priv->setup->rise_time = rise_time;
+
+ fall_time = dev_read_u32_default(dev, "i2c-scl-falling-time-ns", 0);
+ if (fall_time)
+ i2c_priv->setup->fall_time = fall_time;
+
+ /* Optional */
+ i2c_priv->regmap = syscon_regmap_lookup_by_phandle(dev,
+ "st,syscfg-fmp");
+ if (!IS_ERR(i2c_priv->regmap)) {
+ u32 fmp[3];
+
+ ret = dev_read_u32_array(dev, "st,syscfg-fmp", fmp, 3);
+ if (ret)
+ return ret;
+
+ i2c_priv->regmap_sreg = fmp[1];
+ i2c_priv->regmap_creg = fmp[1] +
+ i2c_priv->setup->fmp_clr_offset;
+ i2c_priv->regmap_mask = fmp[2];
+ }
+
+ return 0;
+}
+
+static const struct dm_i2c_ops stm32_i2c_ops = {
+ .xfer = stm32_i2c_xfer,
+ .set_bus_speed = stm32_i2c_set_bus_speed,
+};
+
+static const struct udevice_id stm32_i2c_of_match[] = {
+ { .compatible = "st,stm32f7-i2c", .data = (ulong)&stm32f7_setup },
+ { .compatible = "st,stm32mp15-i2c", .data = (ulong)&stm32mp15_setup },
+ {}
+};
+
+U_BOOT_DRIVER(stm32f7_i2c) = {
+ .name = "stm32f7-i2c",
+ .id = UCLASS_I2C,
+ .of_match = stm32_i2c_of_match,
+ .of_to_plat = stm32_of_to_plat,
+ .probe = stm32_i2c_probe,
+ .priv_auto = sizeof(struct stm32_i2c_priv),
+ .ops = &stm32_i2c_ops,
+};
diff --git a/roms/u-boot/drivers/i2c/tegra186_bpmp_i2c.c b/roms/u-boot/drivers/i2c/tegra186_bpmp_i2c.c
new file mode 100644
index 000000000..588f6bdcc
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/tegra186_bpmp_i2c.c
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2016, NVIDIA CORPORATION.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+#include <log.h>
+#include <misc.h>
+#include <asm/arch-tegra/bpmp_abi.h>
+#include <asm/global_data.h>
+#include <linux/bitops.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct tegra186_bpmp_i2c {
+ uint32_t bpmp_bus_id;
+};
+
+static inline void serialize_u16(uint8_t **p, uint16_t val)
+{
+ (*p)[0] = val & 0xff;
+ (*p)[1] = val >> 8;
+ (*p) += 2;
+}
+
+/* These just happen to have the same values as I2C_M_* and SERIALI2C_* */
+#define SUPPORTED_FLAGS \
+ (I2C_M_TEN | \
+ I2C_M_RD | \
+ I2C_M_STOP | \
+ I2C_M_NOSTART | \
+ I2C_M_REV_DIR_ADDR | \
+ I2C_M_IGNORE_NAK | \
+ I2C_M_NO_RD_ACK | \
+ I2C_M_RECV_LEN)
+
+static int tegra186_bpmp_i2c_xfer(struct udevice *dev, struct i2c_msg *msg,
+ int nmsgs)
+{
+ struct tegra186_bpmp_i2c *priv = dev_get_priv(dev);
+ struct mrq_i2c_request req;
+ struct mrq_i2c_response resp;
+ uint8_t *p;
+ int left, i, ret;
+
+ req.cmd = CMD_I2C_XFER;
+ req.xfer.bus_id = priv->bpmp_bus_id;
+ p = &req.xfer.data_buf[0];
+ left = ARRAY_SIZE(req.xfer.data_buf);
+ for (i = 0; i < nmsgs; i++) {
+ int len = 6;
+ if (!(msg[i].flags & I2C_M_RD))
+ len += msg[i].len;
+ if ((len >= BIT(16)) || (len > left))
+ return -ENOSPC;
+
+ if (msg[i].flags & ~SUPPORTED_FLAGS)
+ return -EINVAL;
+
+ serialize_u16(&p, msg[i].addr);
+ serialize_u16(&p, msg[i].flags);
+ serialize_u16(&p, msg[i].len);
+ if (!(msg[i].flags & I2C_M_RD)) {
+ memcpy(p, msg[i].buf, msg[i].len);
+ p += msg[i].len;
+ }
+ }
+ req.xfer.data_size = p - &req.xfer.data_buf[0];
+
+ ret = misc_call(dev->parent, MRQ_I2C, &req, sizeof(req), &resp,
+ sizeof(resp));
+ if (ret < 0)
+ return ret;
+
+ p = &resp.xfer.data_buf[0];
+ left = resp.xfer.data_size;
+ if (left > ARRAY_SIZE(resp.xfer.data_buf))
+ return -EINVAL;
+ for (i = 0; i < nmsgs; i++) {
+ if (msg[i].flags & I2C_M_RD) {
+ memcpy(msg[i].buf, p, msg[i].len);
+ p += msg[i].len;
+ }
+ }
+
+ return 0;
+}
+
+static int tegra186_bpmp_probe_chip(struct udevice *bus, uint chip_addr,
+ uint chip_flags)
+{
+ return 0;
+}
+
+static int tegra186_bpmp_i2c_probe(struct udevice *dev)
+{
+ struct tegra186_bpmp_i2c *priv = dev_get_priv(dev);
+
+ priv->bpmp_bus_id = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev),
+ "nvidia,bpmp-bus-id", U32_MAX);
+ if (priv->bpmp_bus_id == U32_MAX) {
+ debug("%s: could not parse nvidia,bpmp-bus-id\n", __func__);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct dm_i2c_ops tegra186_bpmp_i2c_ops = {
+ .xfer = tegra186_bpmp_i2c_xfer,
+ .probe_chip = tegra186_bpmp_probe_chip,
+};
+
+static const struct udevice_id tegra186_bpmp_i2c_ids[] = {
+ { .compatible = "nvidia,tegra186-bpmp-i2c" },
+ { }
+};
+
+U_BOOT_DRIVER(i2c_gpio) = {
+ .name = "tegra186_bpmp_i2c",
+ .id = UCLASS_I2C,
+ .of_match = tegra186_bpmp_i2c_ids,
+ .probe = tegra186_bpmp_i2c_probe,
+ .priv_auto = sizeof(struct tegra186_bpmp_i2c),
+ .ops = &tegra186_bpmp_i2c_ops,
+};
diff --git a/roms/u-boot/drivers/i2c/tegra_i2c.c b/roms/u-boot/drivers/i2c/tegra_i2c.c
new file mode 100644
index 000000000..1e7448454
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/tegra_i2c.c
@@ -0,0 +1,529 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+ * Copyright (c) 2010-2011 NVIDIA Corporation
+ * NVIDIA Corporation <www.nvidia.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <i2c.h>
+#include <log.h>
+#include <asm/io.h>
+#include <clk.h>
+#include <reset.h>
+#ifndef CONFIG_TEGRA186
+#include <asm/arch/clock.h>
+#include <asm/arch/funcmux.h>
+#endif
+#include <asm/arch/gpio.h>
+#include <asm/arch-tegra/tegra_i2c.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+
+enum i2c_type {
+ TYPE_114,
+ TYPE_STD,
+ TYPE_DVC,
+};
+
+/* Information about i2c controller */
+struct i2c_bus {
+ int id;
+ struct reset_ctl reset_ctl;
+ struct clk clk;
+ int speed;
+ int pinmux_config;
+ struct i2c_control *control;
+ struct i2c_ctlr *regs;
+ enum i2c_type type;
+ int inited; /* bus is inited */
+};
+
+static void set_packet_mode(struct i2c_bus *i2c_bus)
+{
+ u32 config;
+
+ config = I2C_CNFG_NEW_MASTER_FSM_MASK | I2C_CNFG_PACKET_MODE_MASK;
+
+ if (i2c_bus->type == TYPE_DVC) {
+ struct dvc_ctlr *dvc = (struct dvc_ctlr *)i2c_bus->regs;
+
+ writel(config, &dvc->cnfg);
+ } else {
+ writel(config, &i2c_bus->regs->cnfg);
+ /*
+ * program I2C_SL_CNFG.NEWSL to ENABLE. This fixes probe
+ * issues, i.e., some slaves may be wrongly detected.
+ */
+ setbits_le32(&i2c_bus->regs->sl_cnfg, I2C_SL_CNFG_NEWSL_MASK);
+ }
+}
+
+static void i2c_reset_controller(struct i2c_bus *i2c_bus)
+{
+ /* Reset I2C controller. */
+ reset_assert(&i2c_bus->reset_ctl);
+ udelay(1);
+ reset_deassert(&i2c_bus->reset_ctl);
+ udelay(1);
+
+ /* re-program config register to packet mode */
+ set_packet_mode(i2c_bus);
+}
+
+static int i2c_init_clock(struct i2c_bus *i2c_bus, unsigned rate)
+{
+ int ret;
+
+ ret = reset_assert(&i2c_bus->reset_ctl);
+ if (ret)
+ return ret;
+ ret = clk_enable(&i2c_bus->clk);
+ if (ret)
+ return ret;
+ ret = clk_set_rate(&i2c_bus->clk, rate);
+ if (IS_ERR_VALUE(ret))
+ return ret;
+ ret = reset_deassert(&i2c_bus->reset_ctl);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static void i2c_init_controller(struct i2c_bus *i2c_bus)
+{
+ if (!i2c_bus->speed)
+ return;
+ debug("%s: speed=%d\n", __func__, i2c_bus->speed);
+ /*
+ * Use PLLP - DP-04508-001_v06 datasheet indicates a divisor of 8
+ * here, in section 23.3.1, but in fact we seem to need a factor of
+ * 16 to get the right frequency.
+ */
+ i2c_init_clock(i2c_bus, i2c_bus->speed * 2 * 8);
+
+ if (i2c_bus->type == TYPE_114) {
+ /*
+ * T114 I2C went to a single clock source for standard/fast and
+ * HS clock speeds. The new clock rate setting calculation is:
+ * SCL = CLK_SOURCE.I2C /
+ * (CLK_MULT_STD_FAST_MODE * (I2C_CLK_DIV_STD_FAST_MODE+1) *
+ * I2C FREQUENCY DIVISOR) as per the T114 TRM (sec 30.3.1).
+ *
+ * NOTE: We do this here, after the initial clock/pll start,
+ * because if we read the clk_div reg before the controller
+ * is running, we hang, and we need it for the new calc.
+ */
+ int clk_div_stdfst_mode = readl(&i2c_bus->regs->clk_div) >> 16;
+ unsigned rate = CLK_MULT_STD_FAST_MODE *
+ (clk_div_stdfst_mode + 1) * i2c_bus->speed * 2;
+ debug("%s: CLK_DIV_STD_FAST_MODE setting = %d\n", __func__,
+ clk_div_stdfst_mode);
+
+ i2c_init_clock(i2c_bus, rate);
+ }
+
+ /* Reset I2C controller. */
+ i2c_reset_controller(i2c_bus);
+
+ /* Configure I2C controller. */
+ if (i2c_bus->type == TYPE_DVC) { /* only for DVC I2C */
+ struct dvc_ctlr *dvc = (struct dvc_ctlr *)i2c_bus->regs;
+
+ setbits_le32(&dvc->ctrl3, DVC_CTRL_REG3_I2C_HW_SW_PROG_MASK);
+ }
+
+#ifndef CONFIG_TEGRA186
+ funcmux_select(i2c_bus->clk.id, i2c_bus->pinmux_config);
+#endif
+}
+
+static void send_packet_headers(
+ struct i2c_bus *i2c_bus,
+ struct i2c_trans_info *trans,
+ u32 packet_id,
+ bool end_with_repeated_start)
+{
+ u32 data;
+
+ /* prepare header1: Header size = 0 Protocol = I2C, pktType = 0 */
+ data = PROTOCOL_TYPE_I2C << PKT_HDR1_PROTOCOL_SHIFT;
+ data |= packet_id << PKT_HDR1_PKT_ID_SHIFT;
+ data |= i2c_bus->id << PKT_HDR1_CTLR_ID_SHIFT;
+ writel(data, &i2c_bus->control->tx_fifo);
+ debug("pkt header 1 sent (0x%x)\n", data);
+
+ /* prepare header2 */
+ data = (trans->num_bytes - 1) << PKT_HDR2_PAYLOAD_SIZE_SHIFT;
+ writel(data, &i2c_bus->control->tx_fifo);
+ debug("pkt header 2 sent (0x%x)\n", data);
+
+ /* prepare IO specific header: configure the slave address */
+ data = trans->address << PKT_HDR3_SLAVE_ADDR_SHIFT;
+
+ /* Enable Read if it is not a write transaction */
+ if (!(trans->flags & I2C_IS_WRITE))
+ data |= PKT_HDR3_READ_MODE_MASK;
+ if (end_with_repeated_start)
+ data |= PKT_HDR3_REPEAT_START_MASK;
+
+ /* Write I2C specific header */
+ writel(data, &i2c_bus->control->tx_fifo);
+ debug("pkt header 3 sent (0x%x)\n", data);
+}
+
+static int wait_for_tx_fifo_empty(struct i2c_control *control)
+{
+ u32 count;
+ int timeout_us = I2C_TIMEOUT_USEC;
+
+ while (timeout_us >= 0) {
+ count = (readl(&control->fifo_status) & TX_FIFO_EMPTY_CNT_MASK)
+ >> TX_FIFO_EMPTY_CNT_SHIFT;
+ if (count == I2C_FIFO_DEPTH)
+ return 1;
+ udelay(10);
+ timeout_us -= 10;
+ }
+
+ return 0;
+}
+
+static int wait_for_rx_fifo_notempty(struct i2c_control *control)
+{
+ u32 count;
+ int timeout_us = I2C_TIMEOUT_USEC;
+
+ while (timeout_us >= 0) {
+ count = (readl(&control->fifo_status) & TX_FIFO_FULL_CNT_MASK)
+ >> TX_FIFO_FULL_CNT_SHIFT;
+ if (count)
+ return 1;
+ udelay(10);
+ timeout_us -= 10;
+ }
+
+ return 0;
+}
+
+static int wait_for_transfer_complete(struct i2c_control *control)
+{
+ int int_status;
+ int timeout_us = I2C_TIMEOUT_USEC;
+
+ while (timeout_us >= 0) {
+ int_status = readl(&control->int_status);
+ if (int_status & I2C_INT_NO_ACK_MASK)
+ return -int_status;
+ if (int_status & I2C_INT_ARBITRATION_LOST_MASK)
+ return -int_status;
+ if (int_status & I2C_INT_XFER_COMPLETE_MASK)
+ return 0;
+
+ udelay(10);
+ timeout_us -= 10;
+ }
+
+ return -1;
+}
+
+static int send_recv_packets(struct i2c_bus *i2c_bus,
+ struct i2c_trans_info *trans)
+{
+ struct i2c_control *control = i2c_bus->control;
+ u32 int_status;
+ u32 words;
+ u8 *dptr;
+ u32 local;
+ uchar last_bytes;
+ int error = 0;
+ int is_write = trans->flags & I2C_IS_WRITE;
+
+ /* clear status from previous transaction, XFER_COMPLETE, NOACK, etc. */
+ int_status = readl(&control->int_status);
+ writel(int_status, &control->int_status);
+
+ send_packet_headers(i2c_bus, trans, 1,
+ trans->flags & I2C_USE_REPEATED_START);
+
+ words = DIV_ROUND_UP(trans->num_bytes, 4);
+ last_bytes = trans->num_bytes & 3;
+ dptr = trans->buf;
+
+ while (words) {
+ u32 *wptr = (u32 *)dptr;
+
+ if (is_write) {
+ /* deal with word alignment */
+ if ((words == 1) && last_bytes) {
+ local = 0;
+ memcpy(&local, dptr, last_bytes);
+ } else if ((unsigned long)dptr & 3) {
+ memcpy(&local, dptr, sizeof(u32));
+ } else {
+ local = *wptr;
+ }
+ writel(local, &control->tx_fifo);
+ debug("pkt data sent (0x%x)\n", local);
+ if (!wait_for_tx_fifo_empty(control)) {
+ error = -1;
+ goto exit;
+ }
+ } else {
+ if (!wait_for_rx_fifo_notempty(control)) {
+ error = -1;
+ goto exit;
+ }
+ /*
+ * for the last word, we read into our local buffer,
+ * in case that caller did not provide enough buffer.
+ */
+ local = readl(&control->rx_fifo);
+ if ((words == 1) && last_bytes)
+ memcpy(dptr, (char *)&local, last_bytes);
+ else if ((unsigned long)dptr & 3)
+ memcpy(dptr, &local, sizeof(u32));
+ else
+ *wptr = local;
+ debug("pkt data received (0x%x)\n", local);
+ }
+ words--;
+ dptr += sizeof(u32);
+ }
+
+ if (wait_for_transfer_complete(control)) {
+ error = -1;
+ goto exit;
+ }
+ return 0;
+exit:
+ /* error, reset the controller. */
+ i2c_reset_controller(i2c_bus);
+
+ return error;
+}
+
+static int tegra_i2c_write_data(struct i2c_bus *i2c_bus, u32 addr, u8 *data,
+ u32 len, bool end_with_repeated_start)
+{
+ int error;
+ struct i2c_trans_info trans_info;
+
+ trans_info.address = addr;
+ trans_info.buf = data;
+ trans_info.flags = I2C_IS_WRITE;
+ if (end_with_repeated_start)
+ trans_info.flags |= I2C_USE_REPEATED_START;
+ trans_info.num_bytes = len;
+ trans_info.is_10bit_address = 0;
+
+ error = send_recv_packets(i2c_bus, &trans_info);
+ if (error)
+ debug("tegra_i2c_write_data: Error (%d) !!!\n", error);
+
+ return error;
+}
+
+static int tegra_i2c_read_data(struct i2c_bus *i2c_bus, u32 addr, u8 *data,
+ u32 len)
+{
+ int error;
+ struct i2c_trans_info trans_info;
+
+ trans_info.address = addr | 1;
+ trans_info.buf = data;
+ trans_info.flags = 0;
+ trans_info.num_bytes = len;
+ trans_info.is_10bit_address = 0;
+
+ error = send_recv_packets(i2c_bus, &trans_info);
+ if (error)
+ debug("tegra_i2c_read_data: Error (%d) !!!\n", error);
+
+ return error;
+}
+
+static int tegra_i2c_set_bus_speed(struct udevice *dev, unsigned int speed)
+{
+ struct i2c_bus *i2c_bus = dev_get_priv(dev);
+
+ i2c_bus->speed = speed;
+ i2c_init_controller(i2c_bus);
+
+ return 0;
+}
+
+static int tegra_i2c_probe(struct udevice *dev)
+{
+ struct i2c_bus *i2c_bus = dev_get_priv(dev);
+ int ret;
+ bool is_dvc;
+
+ i2c_bus->id = dev_seq(dev);
+ i2c_bus->type = dev_get_driver_data(dev);
+ i2c_bus->regs = (struct i2c_ctlr *)dev_read_addr(dev);
+ if ((ulong)i2c_bus->regs == FDT_ADDR_T_NONE) {
+ debug("%s: Cannot get regs address\n", __func__);
+ return -EINVAL;
+ }
+
+ ret = reset_get_by_name(dev, "i2c", &i2c_bus->reset_ctl);
+ if (ret) {
+ pr_err("reset_get_by_name() failed: %d\n", ret);
+ return ret;
+ }
+ ret = clk_get_by_name(dev, "div-clk", &i2c_bus->clk);
+ if (ret) {
+ pr_err("clk_get_by_name() failed: %d\n", ret);
+ return ret;
+ }
+
+#ifndef CONFIG_TEGRA186
+ /*
+ * We don't have a binding for pinmux yet. Leave it out for now. So
+ * far no one needs anything other than the default.
+ */
+ i2c_bus->pinmux_config = FUNCMUX_DEFAULT;
+
+ /*
+ * We can't specify the pinmux config in the fdt, so I2C2 will not
+ * work on Seaboard. It normally has no devices on it anyway.
+ * You could add in this little hack if you need to use it.
+ * The correct solution is a pinmux binding in the fdt.
+ *
+ * if (i2c_bus->clk.id == PERIPH_ID_I2C2)
+ * i2c_bus->pinmux_config = FUNCMUX_I2C2_PTA;
+ */
+#endif
+
+ is_dvc = dev_get_driver_data(dev) == TYPE_DVC;
+ if (is_dvc) {
+ i2c_bus->control =
+ &((struct dvc_ctlr *)i2c_bus->regs)->control;
+ } else {
+ i2c_bus->control = &i2c_bus->regs->control;
+ }
+ i2c_init_controller(i2c_bus);
+ debug("%s: controller bus %d at %p, speed %d: ",
+ is_dvc ? "dvc" : "i2c", dev_seq(dev), i2c_bus->regs,
+ i2c_bus->speed);
+
+ return 0;
+}
+
+/* i2c write version without the register address */
+static int i2c_write_data(struct i2c_bus *i2c_bus, uchar chip, uchar *buffer,
+ int len, bool end_with_repeated_start)
+{
+ int rc;
+
+ debug("i2c_write_data: chip=0x%x, len=0x%x\n", chip, len);
+ debug("write_data: ");
+ /* use rc for counter */
+ for (rc = 0; rc < len; ++rc)
+ debug(" 0x%02x", buffer[rc]);
+ debug("\n");
+
+ /* Shift 7-bit address over for lower-level i2c functions */
+ rc = tegra_i2c_write_data(i2c_bus, chip << 1, buffer, len,
+ end_with_repeated_start);
+ if (rc)
+ debug("i2c_write_data(): rc=%d\n", rc);
+
+ return rc;
+}
+
+/* i2c read version without the register address */
+static int i2c_read_data(struct i2c_bus *i2c_bus, uchar chip, uchar *buffer,
+ int len)
+{
+ int rc;
+
+ debug("inside i2c_read_data():\n");
+ /* Shift 7-bit address over for lower-level i2c functions */
+ rc = tegra_i2c_read_data(i2c_bus, chip << 1, buffer, len);
+ if (rc) {
+ debug("i2c_read_data(): rc=%d\n", rc);
+ return rc;
+ }
+
+ debug("i2c_read_data: ");
+ /* reuse rc for counter*/
+ for (rc = 0; rc < len; ++rc)
+ debug(" 0x%02x", buffer[rc]);
+ debug("\n");
+
+ return 0;
+}
+
+/* Probe to see if a chip is present. */
+static int tegra_i2c_probe_chip(struct udevice *bus, uint chip_addr,
+ uint chip_flags)
+{
+ struct i2c_bus *i2c_bus = dev_get_priv(bus);
+ int rc;
+ u8 reg;
+
+ /* Shift 7-bit address over for lower-level i2c functions */
+ rc = tegra_i2c_write_data(i2c_bus, chip_addr << 1, &reg, sizeof(reg),
+ false);
+
+ return rc;
+}
+
+static int tegra_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
+ int nmsgs)
+{
+ struct i2c_bus *i2c_bus = dev_get_priv(bus);
+ int ret;
+
+ debug("i2c_xfer: %d messages\n", nmsgs);
+ for (; nmsgs > 0; nmsgs--, msg++) {
+ bool next_is_read = nmsgs > 1 && (msg[1].flags & I2C_M_RD);
+
+ debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
+ if (msg->flags & I2C_M_RD) {
+ ret = i2c_read_data(i2c_bus, msg->addr, msg->buf,
+ msg->len);
+ } else {
+ ret = i2c_write_data(i2c_bus, msg->addr, msg->buf,
+ msg->len, next_is_read);
+ }
+ if (ret) {
+ debug("i2c_write: error sending\n");
+ return -EREMOTEIO;
+ }
+ }
+
+ return 0;
+}
+
+int tegra_i2c_get_dvc_bus(struct udevice **busp)
+{
+ return uclass_first_device_drvdata(UCLASS_I2C, TYPE_DVC, busp);
+}
+
+static const struct dm_i2c_ops tegra_i2c_ops = {
+ .xfer = tegra_i2c_xfer,
+ .probe_chip = tegra_i2c_probe_chip,
+ .set_bus_speed = tegra_i2c_set_bus_speed,
+};
+
+static const struct udevice_id tegra_i2c_ids[] = {
+ { .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
+ { .compatible = "nvidia,tegra20-i2c", .data = TYPE_STD },
+ { .compatible = "nvidia,tegra20-i2c-dvc", .data = TYPE_DVC },
+ { }
+};
+
+U_BOOT_DRIVER(i2c_tegra) = {
+ .name = "i2c_tegra",
+ .id = UCLASS_I2C,
+ .of_match = tegra_i2c_ids,
+ .probe = tegra_i2c_probe,
+ .priv_auto = sizeof(struct i2c_bus),
+ .ops = &tegra_i2c_ops,
+};
diff --git a/roms/u-boot/drivers/i2c/xilinx_xiic.c b/roms/u-boot/drivers/i2c/xilinx_xiic.c
new file mode 100644
index 000000000..72199a62b
--- /dev/null
+++ b/roms/u-boot/drivers/i2c/xilinx_xiic.c
@@ -0,0 +1,353 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Xilinx AXI I2C driver
+ *
+ * Copyright (C) 2018 Marek Vasut <marex@denx.de>
+ *
+ * Based on Linux 4.14.y i2c-xiic.c
+ * Copyright (c) 2002-2007 Xilinx Inc.
+ * Copyright (c) 2009-2010 Intel Corporation
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <i2c.h>
+#include <wait_bit.h>
+#include <asm/io.h>
+#include <dm/device_compat.h>
+
+struct xilinx_xiic_priv {
+ void __iomem *base;
+ struct clk clk;
+};
+
+#define XIIC_MSB_OFFSET 0
+#define XIIC_REG_OFFSET (0x100+XIIC_MSB_OFFSET)
+
+/*
+ * Register offsets in bytes from RegisterBase. Three is added to the
+ * base offset to access LSB (IBM style) of the word
+ */
+#define XIIC_CR_REG_OFFSET (0x00+XIIC_REG_OFFSET) /* Control Register */
+#define XIIC_SR_REG_OFFSET (0x04+XIIC_REG_OFFSET) /* Status Register */
+#define XIIC_DTR_REG_OFFSET (0x08+XIIC_REG_OFFSET) /* Data Tx Register */
+#define XIIC_DRR_REG_OFFSET (0x0C+XIIC_REG_OFFSET) /* Data Rx Register */
+#define XIIC_ADR_REG_OFFSET (0x10+XIIC_REG_OFFSET) /* Address Register */
+#define XIIC_TFO_REG_OFFSET (0x14+XIIC_REG_OFFSET) /* Tx FIFO Occupancy */
+#define XIIC_RFO_REG_OFFSET (0x18+XIIC_REG_OFFSET) /* Rx FIFO Occupancy */
+#define XIIC_TBA_REG_OFFSET (0x1C+XIIC_REG_OFFSET) /* 10 Bit Address reg */
+#define XIIC_RFD_REG_OFFSET (0x20+XIIC_REG_OFFSET) /* Rx FIFO Depth reg */
+#define XIIC_GPO_REG_OFFSET (0x24+XIIC_REG_OFFSET) /* Output Register */
+
+/* Control Register masks */
+#define XIIC_CR_ENABLE_DEVICE_MASK 0x01 /* Device enable = 1 */
+#define XIIC_CR_TX_FIFO_RESET_MASK 0x02 /* Transmit FIFO reset=1 */
+#define XIIC_CR_MSMS_MASK 0x04 /* Master starts Txing=1 */
+#define XIIC_CR_DIR_IS_TX_MASK 0x08 /* Dir of tx. Txing=1 */
+#define XIIC_CR_NO_ACK_MASK 0x10 /* Tx Ack. NO ack = 1 */
+#define XIIC_CR_REPEATED_START_MASK 0x20 /* Repeated start = 1 */
+#define XIIC_CR_GENERAL_CALL_MASK 0x40 /* Gen Call enabled = 1 */
+
+/* Status Register masks */
+#define XIIC_SR_GEN_CALL_MASK 0x01 /* 1=a mstr issued a GC */
+#define XIIC_SR_ADDR_AS_SLAVE_MASK 0x02 /* 1=when addr as slave */
+#define XIIC_SR_BUS_BUSY_MASK 0x04 /* 1 = bus is busy */
+#define XIIC_SR_MSTR_RDING_SLAVE_MASK 0x08 /* 1=Dir: mstr <-- slave */
+#define XIIC_SR_TX_FIFO_FULL_MASK 0x10 /* 1 = Tx FIFO full */
+#define XIIC_SR_RX_FIFO_FULL_MASK 0x20 /* 1 = Rx FIFO full */
+#define XIIC_SR_RX_FIFO_EMPTY_MASK 0x40 /* 1 = Rx FIFO empty */
+#define XIIC_SR_TX_FIFO_EMPTY_MASK 0x80 /* 1 = Tx FIFO empty */
+
+/* Interrupt Status Register masks Interrupt occurs when... */
+#define XIIC_INTR_ARB_LOST_MASK 0x01 /* 1 = arbitration lost */
+#define XIIC_INTR_TX_ERROR_MASK 0x02 /* 1=Tx error/msg complete */
+#define XIIC_INTR_TX_EMPTY_MASK 0x04 /* 1 = Tx FIFO/reg empty */
+#define XIIC_INTR_RX_FULL_MASK 0x08 /* 1=Rx FIFO/reg=OCY level */
+#define XIIC_INTR_BNB_MASK 0x10 /* 1 = Bus not busy */
+#define XIIC_INTR_AAS_MASK 0x20 /* 1 = when addr as slave */
+#define XIIC_INTR_NAAS_MASK 0x40 /* 1 = not addr as slave */
+#define XIIC_INTR_TX_HALF_MASK 0x80 /* 1 = TX FIFO half empty */
+
+/* The following constants specify the depth of the FIFOs */
+#define IIC_RX_FIFO_DEPTH 16 /* Rx fifo capacity */
+#define IIC_TX_FIFO_DEPTH 16 /* Tx fifo capacity */
+
+/*
+ * Tx Fifo upper bit masks.
+ */
+#define XIIC_TX_DYN_START_MASK 0x0100 /* 1 = Set dynamic start */
+#define XIIC_TX_DYN_STOP_MASK 0x0200 /* 1 = Set dynamic stop */
+
+/*
+ * The following constants define the register offsets for the Interrupt
+ * registers. There are some holes in the memory map for reserved addresses
+ * to allow other registers to be added and still match the memory map of the
+ * interrupt controller registers
+ */
+#define XIIC_DGIER_OFFSET 0x1C /* Device Global Interrupt Enable Register */
+#define XIIC_IISR_OFFSET 0x20 /* Interrupt Status Register */
+#define XIIC_IIER_OFFSET 0x28 /* Interrupt Enable Register */
+#define XIIC_RESETR_OFFSET 0x40 /* Reset Register */
+
+#define XIIC_RESET_MASK 0xAUL
+
+static u8 i2c_8bit_addr_from_flags(uint addr, u16 flags)
+{
+ return (addr << 1) | (flags & I2C_M_RD ? 1 : 0);
+}
+
+static void xiic_irq_clr(struct xilinx_xiic_priv *priv, u32 mask)
+{
+ u32 isr = readl(priv->base + XIIC_IISR_OFFSET);
+
+ writel(isr & mask, priv->base + XIIC_IISR_OFFSET);
+}
+
+static int xiic_read_rx(struct xilinx_xiic_priv *priv,
+ struct i2c_msg *msg, int nmsgs)
+{
+ u8 bytes_in_fifo;
+ u32 pos = 0;
+ int i, ret;
+
+ while (pos < msg->len) {
+ ret = wait_for_bit_8(priv->base + XIIC_SR_REG_OFFSET,
+ XIIC_SR_RX_FIFO_EMPTY_MASK, false,
+ 1000, true);
+ if (ret)
+ return ret;
+
+ bytes_in_fifo = readb(priv->base + XIIC_RFO_REG_OFFSET) + 1;
+
+ if (bytes_in_fifo > msg->len)
+ bytes_in_fifo = msg->len;
+
+ for (i = 0; i < bytes_in_fifo; i++) {
+ msg->buf[pos++] = readb(priv->base +
+ XIIC_DRR_REG_OFFSET);
+ }
+ }
+
+ return 0;
+}
+
+static int xiic_tx_fifo_space(struct xilinx_xiic_priv *priv)
+{
+ /* return the actual space left in the FIFO */
+ return IIC_TX_FIFO_DEPTH - readb(priv->base + XIIC_TFO_REG_OFFSET) - 1;
+}
+
+static void xiic_fill_tx_fifo(struct xilinx_xiic_priv *priv,
+ struct i2c_msg *msg, int nmsgs)
+{
+ u8 fifo_space = xiic_tx_fifo_space(priv);
+ int len = msg->len;
+ u32 pos = 0;
+
+ len = (len > fifo_space) ? fifo_space : len;
+
+ while (len--) {
+ u16 data = msg->buf[pos++];
+
+ if ((msg->len - pos == 0) && nmsgs == 1) {
+ /* last message in transfer -> STOP */
+ data |= XIIC_TX_DYN_STOP_MASK;
+ }
+ writew(data, priv->base + XIIC_DTR_REG_OFFSET);
+ }
+}
+
+static void xilinx_xiic_set_addr(struct udevice *dev, u8 addr,
+ u16 flags, u32 len, u32 nmsgs)
+{
+ struct xilinx_xiic_priv *priv = dev_get_priv(dev);
+
+ xiic_irq_clr(priv, XIIC_INTR_TX_ERROR_MASK);
+
+ if (!(flags & I2C_M_NOSTART)) {
+ /* write the address */
+ u16 data = i2c_8bit_addr_from_flags(addr, flags) |
+ XIIC_TX_DYN_START_MASK;
+ if (nmsgs == 1 && len == 0)
+ /* no data and last message -> add STOP */
+ data |= XIIC_TX_DYN_STOP_MASK;
+
+ writew(data, priv->base + XIIC_DTR_REG_OFFSET);
+ }
+}
+
+static int xilinx_xiic_read_common(struct udevice *dev, struct i2c_msg *msg,
+ u32 nmsgs)
+{
+ struct xilinx_xiic_priv *priv = dev_get_priv(dev);
+ u8 rx_watermark;
+
+ /* Clear and enable Rx full interrupt. */
+ xiic_irq_clr(priv, XIIC_INTR_RX_FULL_MASK | XIIC_INTR_TX_ERROR_MASK);
+
+ /* we want to get all but last byte, because the TX_ERROR IRQ is used
+ * to inidicate error ACK on the address, and negative ack on the last
+ * received byte, so to not mix them receive all but last.
+ * In the case where there is only one byte to receive
+ * we can check if ERROR and RX full is set at the same time
+ */
+ rx_watermark = msg->len;
+ if (rx_watermark > IIC_RX_FIFO_DEPTH)
+ rx_watermark = IIC_RX_FIFO_DEPTH;
+
+ writeb(rx_watermark - 1, priv->base + XIIC_RFD_REG_OFFSET);
+
+ xilinx_xiic_set_addr(dev, msg->addr, msg->flags, msg->len, nmsgs);
+
+ xiic_irq_clr(priv, XIIC_INTR_BNB_MASK);
+
+ writew((msg->len & 0xff) | ((nmsgs == 1) ? XIIC_TX_DYN_STOP_MASK : 0),
+ priv->base + XIIC_DTR_REG_OFFSET);
+
+ if (nmsgs == 1)
+ /* very last, enable bus not busy as well */
+ xiic_irq_clr(priv, XIIC_INTR_BNB_MASK);
+
+ return xiic_read_rx(priv, msg, nmsgs);
+}
+
+static int xilinx_xiic_write_common(struct udevice *dev, struct i2c_msg *msg,
+ int nmsgs)
+{
+ struct xilinx_xiic_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ xilinx_xiic_set_addr(dev, msg->addr, msg->flags, msg->len, nmsgs);
+ xiic_fill_tx_fifo(priv, msg, nmsgs);
+
+ ret = wait_for_bit_8(priv->base + XIIC_SR_REG_OFFSET,
+ XIIC_SR_TX_FIFO_EMPTY_MASK, false, 1000, true);
+ if (ret)
+ return ret;
+
+ /* Clear any pending Tx empty, Tx Error and then enable them. */
+ xiic_irq_clr(priv, XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_ERROR_MASK |
+ XIIC_INTR_BNB_MASK);
+
+ return 0;
+}
+
+static void xiic_clear_rx_fifo(struct xilinx_xiic_priv *priv)
+{
+ u8 sr;
+
+ for (sr = readb(priv->base + XIIC_SR_REG_OFFSET);
+ !(sr & XIIC_SR_RX_FIFO_EMPTY_MASK);
+ sr = readb(priv->base + XIIC_SR_REG_OFFSET))
+ readb(priv->base + XIIC_DRR_REG_OFFSET);
+}
+
+static void xiic_reinit(struct xilinx_xiic_priv *priv)
+{
+ writel(XIIC_RESET_MASK, priv->base + XIIC_RESETR_OFFSET);
+
+ /* Set receive Fifo depth to maximum (zero based). */
+ writeb(IIC_RX_FIFO_DEPTH - 1, priv->base + XIIC_RFD_REG_OFFSET);
+
+ /* Reset Tx Fifo. */
+ writeb(XIIC_CR_TX_FIFO_RESET_MASK, priv->base + XIIC_CR_REG_OFFSET);
+
+ /* Enable IIC Device, remove Tx Fifo reset & disable general call. */
+ writeb(XIIC_CR_ENABLE_DEVICE_MASK, priv->base + XIIC_CR_REG_OFFSET);
+
+ /* make sure RX fifo is empty */
+ xiic_clear_rx_fifo(priv);
+
+ /* Disable interrupts */
+ writel(0, priv->base + XIIC_DGIER_OFFSET);
+
+ xiic_irq_clr(priv, XIIC_INTR_ARB_LOST_MASK);
+}
+
+static int xilinx_xiic_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs)
+{
+ struct xilinx_xiic_priv *priv = dev_get_priv(dev);
+ int ret = 0;
+
+ ret = wait_for_bit_8(priv->base + XIIC_SR_REG_OFFSET,
+ XIIC_SR_BUS_BUSY_MASK, false, 1000, true);
+
+ if (ret == -ETIMEDOUT)
+ dev_err(dev, "timeout waiting for bus not busy condition\n");
+
+ if (ret)
+ return ret;
+
+ xiic_reinit(priv);
+
+ for (; nmsgs > 0; nmsgs--, msg++) {
+ if (msg->flags & I2C_M_RD)
+ ret = xilinx_xiic_read_common(dev, msg, nmsgs);
+ else
+ ret = xilinx_xiic_write_common(dev, msg, nmsgs);
+
+ if (ret)
+ return -EREMOTEIO;
+ }
+
+ return ret;
+}
+
+static int xilinx_xiic_probe_chip(struct udevice *dev, uint addr, uint flags)
+{
+ struct xilinx_xiic_priv *priv = dev_get_priv(dev);
+ u32 reg;
+ int ret;
+
+ xiic_reinit(priv);
+
+ xilinx_xiic_set_addr(dev, addr, 0, 0, 1);
+ ret = wait_for_bit_8(priv->base + XIIC_SR_REG_OFFSET,
+ XIIC_SR_BUS_BUSY_MASK, false, 1000, true);
+ if (ret)
+ return ret;
+
+ reg = readl(priv->base + XIIC_IISR_OFFSET);
+ if (reg & XIIC_INTR_TX_ERROR_MASK)
+ return -ENODEV;
+
+ return 0;
+}
+
+static int xilinx_xiic_set_speed(struct udevice *dev, uint speed)
+{
+ return 0;
+}
+
+static int xilinx_xiic_probe(struct udevice *dev)
+{
+ struct xilinx_xiic_priv *priv = dev_get_priv(dev);
+
+ priv->base = dev_read_addr_ptr(dev);
+
+ writel(XIIC_CR_TX_FIFO_RESET_MASK, priv->base + XIIC_CR_REG_OFFSET);
+ xiic_reinit(priv);
+
+ return 0;
+}
+
+static const struct dm_i2c_ops xilinx_xiic_ops = {
+ .xfer = xilinx_xiic_xfer,
+ .probe_chip = xilinx_xiic_probe_chip,
+ .set_bus_speed = xilinx_xiic_set_speed,
+};
+
+static const struct udevice_id xilinx_xiic_ids[] = {
+ { .compatible = "xlnx,xps-iic-2.00.a" },
+ { }
+};
+
+U_BOOT_DRIVER(xilinx_xiic) = {
+ .name = "xilinx_axi_i2c",
+ .id = UCLASS_I2C,
+ .of_match = xilinx_xiic_ids,
+ .probe = xilinx_xiic_probe,
+ .priv_auto = sizeof(struct xilinx_xiic_priv),
+ .ops = &xilinx_xiic_ops,
+};