new file mode 100644
@@ -0,0 +1,20 @@
+/dts-v1/;
+
+/memreserve/ 0x1c000000 0x04000000;
+/include/ "tegra250.dtsi"
+
+/ {
+ model = "NVIDIA Seaboard";
+ compatible = "nvidia,seaboard", "nvidia,tegra250";
+
+ /* Enable the ports we want to use, and update the speed if needed */
+ i2c@0x7000c000 {
+ status = "ok";
+ };
+
+ i2c@0x7000c400 {
+ speed = <400000>;
+ status = "ok";
+ };
+
+};
new file mode 100644
@@ -0,0 +1,42 @@
+/* This is not a real fdt! It is just for illustration in this RFC */
+
+/ {
+ model = "NVIDIA Tegra 250";
+ compatible = "nvidia,tegra250";
+
+ i2c@0x7000c000 {
+ compatible = "nvidia,tegra250-i2c";
+ reg = <0x7000c000 0x006c>;
+ pinmux = <1>;
+ speed = <100000>;
+ periph-id = <12>; // PERIPH_ID_I2C1
+ status = "disabled";
+ };
+
+ i2c@0x7000c400 {
+ compatible = "nvidia,tegra250-i2c";
+ reg = <0x7000c400 0x006c>;
+ pinmux = <2>;
+ speed = <100000>;
+ periph-id = <54>; // PERIPH_ID_I2C2
+ status = "disabled";
+ };
+
+ i2c@0x7000c500 {
+ compatible = "nvidia,tegra250-i2c";
+ reg = <0x7000c500 0x006c>;
+ pinmux = <1>;
+ speed = <100000>;
+ periph-id = <67>; // PERIPH_ID_I2C3
+ status = "disabled";
+ };
+
+ i2c@0x7000d000 {
+ compatible = "nvidia,tegra250-i2c";
+ reg = <0x7000d000 0x007c>;
+ pinmux = <1>;
+ speed = <100000>;
+ periph-id = <47>; // PERIPH_ID_DVC_I2C
+ status = "disabled";
+ };
+};
@@ -388,6 +388,97 @@ static int tegra2_i2c_read_data(u32 addr, u8 *data, u32 len)
return error;
}
+#ifndef CONFIG_OF_CONTROL
+/* This is the original code, whic uses CONFIG_..., TEGRA2_...,etc. */
+static const enum periph_id i2c_periph_ids[CONFIG_SYS_MAX_I2C_BUS] = {
+ PERIPH_ID_DVC_I2C,
+ PERIPH_ID_I2C1,
+ PERIPH_ID_I2C2,
+ PERIPH_ID_I2C3
+};
+
+static const u32 *i2c_bus_base[CONFIG_SYS_MAX_I2C_BUS] = {
+ (u32 *)TEGRA2_DVC_BASE,
+ (u32 *)TEGRA2_I2C1_BASE,
+ (u32 *)TEGRA2_I2C2_BASE,
+ (u32 *)TEGRA2_I2C3_BASE
+};
+
+/* pinmux_configs based on the pinmux configuration */
+static const int pinmux_configs[CONFIG_SYS_MAX_I2C_BUS] = {
+ CONFIG_I2CP_PIN_MUX, /* for I2CP (DVC I2C) */
+ CONFIG_I2C1_PIN_MUX, /* for I2C1 */
+ CONFIG_I2C2_PIN_MUX, /* for I2C2 */
+ CONFIG_I2C3_PIN_MUX /* for I2C3 */
+};
+
+static int i2c_get_config(int *index, struct i2c_bus *i2c_bus)
+{
+ int i = *index;
+
+ if (i >= CONFIG_SYS_MAX_I2C_BUS)
+ return -1;
+
+ i2c_bus->periph_id = i2c_periph_ids[i];
+ i2c_bus->pinmux_config = pinmux_configs[i];
+ i2c_bus->regs = (struct i2c_ctlr *)i2c_bus_base[i];
+ i2c_bus->speed = I2CSPEED_KHZ * 1000;
+
+ *index = i + 1;
+
+ return 0;
+}
+#else
+/* This is the fdt code */
+static int i2c_get_config(int *index, struct i2c_bus *i2c_bus)
+{
+ const void *blob = gd->blob;
+ struct fdt_i2c config;
+ int node = fdt_decode_next_alias(blob,
+ "i2c",
+ COMPAT_NVIDIA_TEGRA250_I2C,
+ index);
+ if (node < 0)
+ return -1;
+
+ if (fdt_decode_i2c(blob, node, &config))
+ return -1;
+
+ i2c_bus->periph_id = config.periph_id;
+ i2c_bus->pinmux_config = config.pinmux;
+ i2c_bus->regs = config.reg;
+ i2c_bus->speed = config.speed;
+ i2c_bus->enabled = config.enable;
+
+ return 0;
+}
+#endif
+
+int i2c_init_board(void)
+{
+ struct i2c_bus *i2c_bus;
+ int index = 0;
+ int i;
+
+ /* build the i2c_controllers[] for each controller */
+ for (i = 0; i < CONFIG_SYS_MAX_I2C_BUS; ++i) {
+ i2c_bus = &i2c_controllers[i];
+ i2c_bus->id = i;
+
+ i2c_get_config(&index, i2c_bus);
+
+ if (i2c_bus->periph_id == PERIPH_ID_DVC_I2C)
+ i2c_bus->control =
+ &((struct dvc_ctlr *)i2c_bus->regs)->control;
+ else
+ i2c_bus->control = &i2c_bus->regs->control;
+
+ i2c_init_controller(i2c_bus);
+ }
+
+ return 0;
+}
+
void i2c_init(int speed, int slaveaddr)
{
debug("i2c_init(speed=%u, slaveaddr=0x%x)\n", speed, slaveaddr);
This is only an example for comment. It is not a real driver as yet. It just shows how the config is read from the fdt. You can see that the main difference (as you might expect) is whether configuration comes from the fdt or the CONFIG options. Some drivers will need changing to split their config out in such a clear way, or to add a structure to hold the config rather than using CONFIG_... options throughout their code. This also provides an example fdt fragment to show what the device is actually reading. Signed-off-by: Simon Glass <sjg@chromium.org> --- Changes in v2: - Add example of i2c driver changes required to support fdt control - Add example fdt fragments for Tegra2 I2C, just for illustration board/nvidia/seaboard/tegra2-seaboard.dts | 20 ++++++ board/nvidia/seaboard/tegra250.dtsi | 42 +++++++++++++ drivers/i2c/tegra2_i2c.c | 91 +++++++++++++++++++++++++++++ 3 files changed, 153 insertions(+), 0 deletions(-) create mode 100644 board/nvidia/seaboard/tegra2-seaboard.dts create mode 100644 board/nvidia/seaboard/tegra250.dtsi