]> git.sur5r.net Git - u-boot/commitdiff
Merge git://git.denx.de/u-boot-fdt
authorTom Rini <trini@ti.com>
Thu, 23 Oct 2014 10:51:46 +0000 (06:51 -0400)
committerTom Rini <trini@ti.com>
Thu, 23 Oct 2014 10:51:46 +0000 (06:51 -0400)
161 files changed:
arch/arm/cpu/armv7/exynos/pinmux.c
arch/arm/dts/exynos4.dtsi
arch/arm/dts/exynos4210-origen.dts
arch/arm/dts/exynos4210-pinctrl-uboot.dtsi [new file with mode: 0644]
arch/arm/dts/exynos4210-pinctrl.dtsi [new file with mode: 0644]
arch/arm/dts/exynos4210-smdkv310.dts
arch/arm/dts/exynos4210-trats.dts
arch/arm/dts/exynos4210-universal_c210.dts
arch/arm/dts/exynos4210.dtsi [new file with mode: 0644]
arch/arm/dts/exynos4412-odroid.dts
arch/arm/dts/exynos4412-trats2.dts
arch/arm/dts/exynos4412.dtsi [new file with mode: 0644]
arch/arm/dts/exynos4x12-pinctrl-uboot.dtsi [new file with mode: 0644]
arch/arm/dts/exynos4x12-pinctrl.dtsi [new file with mode: 0644]
arch/arm/dts/exynos4x12.dtsi [new file with mode: 0644]
arch/arm/dts/exynos5.dtsi
arch/arm/dts/exynos5250-pinctrl-uboot.dtsi [new file with mode: 0644]
arch/arm/dts/exynos5250-pinctrl.dtsi [new file with mode: 0644]
arch/arm/dts/exynos5250-smdk5250.dts
arch/arm/dts/exynos5250-snow.dts
arch/arm/dts/exynos5250.dtsi
arch/arm/dts/exynos5420-peach-pit.dts
arch/arm/dts/exynos5420-smdk5420.dts
arch/arm/dts/exynos54xx-pinctrl-uboot.dtsi [new file with mode: 0644]
arch/arm/dts/exynos54xx-pinctrl.dtsi [new file with mode: 0644]
arch/arm/dts/exynos54xx.dtsi
arch/arm/dts/s5pc100-pinctrl.dtsi [new file with mode: 0644]
arch/arm/dts/s5pc110-pinctrl.dtsi [new file with mode: 0644]
arch/arm/dts/s5pc1xx-goni.dts
arch/arm/dts/s5pc1xx-smdkc100.dts
arch/arm/dts/tegra20-trimslice.dts
arch/arm/dts/tegra30-beaver.dts
arch/arm/dts/tegra30-cardhu.dts
arch/arm/dts/tegra30-colibri.dts
arch/arm/imx-common/i2c-mxv7.c
arch/arm/include/asm/arch-bcm2835/gpio.h
arch/arm/include/asm/arch-exynos/gpio.h
arch/arm/include/asm/arch-s5pc1xx/gpio.h
arch/arm/include/asm/arch-tegra114/tegra114_spi.h [deleted file]
arch/arm/include/asm/arch-tegra20/tegra20_sflash.h [deleted file]
arch/arm/include/asm/arch-tegra20/tegra20_slink.h [deleted file]
arch/arm/include/asm/imx-common/mxc_i2c.h
arch/sandbox/dts/sandbox.dts
arch/sandbox/include/asm/spi.h
arch/sandbox/include/asm/state.h
arch/x86/cpu/Makefile
arch/x86/cpu/start16.S
arch/x86/include/asm/bootm.h [new file with mode: 0644]
arch/x86/include/asm/config.h
arch/x86/lib/bootm.c
arch/x86/lib/zimage.c
board/buffalo/lsxl/lsxl.c
board/compulab/cm_fx6/cm_fx6.c
board/nvidia/common/board.c
board/raspberrypi/rpi_b/rpi_b.c
board/renesas/sh7752evb/sh7752evb.c
board/renesas/sh7753evb/sh7753evb.c
board/renesas/sh7757lcr/sh7757lcr.c
board/samsung/arndale/arndale.c
board/samsung/common/board.c
board/samsung/common/misc.c
board/samsung/goni/goni.c
board/samsung/origen/origen.c
board/samsung/smdk5250/exynos5-dt.c
board/samsung/smdk5420/smdk5420.c
board/samsung/smdkc100/smdkc100.c
board/samsung/smdkv310/smdkv310.c
board/samsung/trats/trats.c
board/samsung/trats2/trats2.c
board/samsung/universal_c210/universal.c
common/board_r.c
common/bootm.c
common/cmd_bootm.c
common/cmd_sf.c
common/cmd_spi.c
common/cros_ec.c
common/env_sf.c
common/exports.c
common/image-fit.c
common/image.c
doc/device-tree-bindings/mtd/spi/spi-flash.txt [new file with mode: 0644]
doc/device-tree-bindings/spi/soft-spi.txt [new file with mode: 0644]
doc/driver-model/README.txt
doc/driver-model/spi-howto.txt [new file with mode: 0644]
doc/uImage.FIT/kernel.its
doc/uImage.FIT/source_file_format.txt
doc/uImage.FIT/x86-fit-boot.txt [new file with mode: 0644]
drivers/core/Makefile
drivers/core/device.c
drivers/core/lists.c
drivers/core/simple-bus.c [new file with mode: 0644]
drivers/core/uclass.c
drivers/dfu/dfu_sf.c
drivers/gpio/bcm2835_gpio.c
drivers/gpio/mxc_gpio.c
drivers/gpio/s5p_gpio.c
drivers/misc/cros_ec.c
drivers/misc/cros_ec_sandbox.c
drivers/misc/cros_ec_spi.c
drivers/mmc/s5p_sdhci.c
drivers/mtd/spi/Makefile
drivers/mtd/spi/ramtron.c
drivers/mtd/spi/sandbox.c
drivers/mtd/spi/sf-uclass.c [new file with mode: 0644]
drivers/mtd/spi/sf_internal.h
drivers/mtd/spi/sf_params.c
drivers/mtd/spi/sf_probe.c
drivers/mtd/spi/spi_spl_load.c
drivers/serial/Makefile
drivers/serial/serial-uclass.c
drivers/serial/serial_mxc.c
drivers/serial/serial_pl01x.c
drivers/serial/serial_pl01x.h [deleted file]
drivers/serial/serial_pl01x_internal.h [new file with mode: 0644]
drivers/serial/serial_s5p.c
drivers/spi/Makefile
drivers/spi/exynos_spi.c
drivers/spi/fdt_spi.c [deleted file]
drivers/spi/sandbox_spi.c
drivers/spi/soft_spi.c
drivers/spi/soft_spi_legacy.c [new file with mode: 0644]
drivers/spi/spi-emul-uclass.c [new file with mode: 0644]
drivers/spi/spi-uclass.c [new file with mode: 0644]
drivers/spi/tegra114_spi.c
drivers/spi/tegra20_sflash.c
drivers/spi/tegra20_slink.c
drivers/spi/tegra_spi.h [new file with mode: 0644]
include/bootstage.h
include/configs/cm_fx6.h
include/configs/exynos-common.h
include/configs/peach-pit.h
include/configs/rpi_b.h
include/configs/s5p_goni.h
include/configs/s5pc210_universal.h
include/configs/sacsng.h
include/configs/sandbox.h
include/configs/smdkc100.h
include/configs/tegra-common-post.h
include/configs/tegra-common.h
include/configs/zipitz2.h
include/cros_ec.h
include/dm/device-internal.h
include/dm/device.h
include/dm/lists.h
include/dm/platdata.h
include/dm/uclass-id.h
include/dm/uclass.h
include/dm/util.h
include/image.h
include/linker_lists.h
include/serial_mxc.h [new file with mode: 0644]
include/serial_pl01x.h [new file with mode: 0644]
include/spi.h
include/spi_flash.h
lib/initcall.c
test/dm/Makefile
test/dm/bus.c
test/dm/sf.c [new file with mode: 0644]
test/dm/spi.c [new file with mode: 0644]
test/dm/test-dm.sh
test/dm/test.dts

index b929486da9c2c99766084bf5440d19a81016a3a1..3d95dc3339e6ee87859748d529510a7036b6cece 100644 (file)
@@ -7,7 +7,7 @@
 
 #include <common.h>
 #include <fdtdec.h>
-#include <asm/arch/gpio.h>
+#include <asm/gpio.h>
 #include <asm/arch/pinmux.h>
 #include <asm/arch/sromc.h>
 
@@ -172,6 +172,9 @@ static int exynos5420_mmc_config(int peripheral, int flags)
                 * this same assumption.
                 */
                if ((peripheral == PERIPH_ID_SDMMC0) && (i == (start + 2))) {
+#ifndef CONFIG_SPL_BUILD
+                       gpio_request(i, "sdmmc0_vdden");
+#endif
                        gpio_set_value(i, 1);
                        gpio_cfg_pin(i, S5P_GPIO_OUTPUT);
                } else {
index 110eb43a2f8b4aa9af5323e2c22937badd2a79f3..77fad48fb4bd72614d575660af1ae81d2188f9c1 100644 (file)
@@ -7,9 +7,16 @@
  * SPDX-License-Identifier:    GPL-2.0+
  */
 
-/include/ "skeleton.dtsi"
+#include "skeleton.dtsi"
 
 / {
+       combiner: interrupt-controller@10440000 {
+               compatible = "samsung,exynos4210-combiner";
+               #interrupt-cells = <2>;
+               interrupt-controller;
+               reg = <0x10440000 0x1000>;
+       };
+
        serial@13800000 {
                compatible = "samsung,exynos4210-uart";
                reg = <0x13800000 0x3c>;
index 15059d22022738954eea77af7f8e30b07bd8696e..dd2476c1a39e35f74beb2f21d2cde8a44dcdbd04 100644 (file)
@@ -8,8 +8,8 @@
  */
 
 /dts-v1/;
-/include/ "skeleton.dtsi"
-/include/ "exynos4.dtsi"
+#include "skeleton.dtsi"
+#include "exynos4210.dtsi"
 
 / {
        model = "Insignal Origen evaluation board based on Exynos4210";
diff --git a/arch/arm/dts/exynos4210-pinctrl-uboot.dtsi b/arch/arm/dts/exynos4210-pinctrl-uboot.dtsi
new file mode 100644 (file)
index 0000000..ee071c1
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * U-Boot additions to enable a generic Exynos GPIO driver
+ *
+ * Copyright (c) 2014 Google, Inc
+ */
+
+/{
+       pinctrl_0: pinctrl@11400000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "samsung,exynos4210-pinctrl";
+       };
+
+       pinctrl_1: pinctrl@11000000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               gpy0: gpy0 {
+                       reg = <0xc00>;
+               };
+       };
+
+       pinctrl_2: pinctrl@03860000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+       };
+
+};
diff --git a/arch/arm/dts/exynos4210-pinctrl.dtsi b/arch/arm/dts/exynos4210-pinctrl.dtsi
new file mode 100644 (file)
index 0000000..bda17f7
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ * Samsung's Exynos4210 SoC pin-mux and pin-config device tree source
+ *
+ * Copyright (c) 2011-2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ * Copyright (c) 2011-2012 Linaro Ltd.
+ *             www.linaro.org
+ *
+ * Samsung's Exynos4210 SoC pin-mux and pin-config optiosn are listed as device
+ * tree nodes are listed in this file.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+/ {
+       pinctrl@11400000 {
+               gpa0: gpa0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpa1: gpa1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpb: gpb {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpc0: gpc0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpc1: gpc1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpd0: gpd0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpd1: gpd1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpe0: gpe0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpe1: gpe1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpe2: gpe2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpe3: gpe3 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpe4: gpe4 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpf0: gpf0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpf1: gpf1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpf2: gpf2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpf3: gpf3 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+       };
+
+       pinctrl@11000000 {
+               gpj0: gpj0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpj1: gpj1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpk0: gpk0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpk1: gpk1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpk2: gpk2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpk3: gpk3 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpl0: gpl0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpl1: gpl1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpl2: gpl2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpy0: gpy0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpy1: gpy1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpy2: gpy2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpy3: gpy3 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpy4: gpy4 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpy5: gpy5 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpy6: gpy6 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpx0: gpx0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       interrupt-parent = <&gic>;
+                       interrupts = <0 16 0>, <0 17 0>, <0 18 0>, <0 19 0>,
+                                    <0 20 0>, <0 21 0>, <0 22 0>, <0 23 0>;
+                       #interrupt-cells = <2>;
+               };
+
+               gpx1: gpx1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       interrupt-parent = <&gic>;
+                       interrupts = <0 24 0>, <0 25 0>, <0 26 0>, <0 27 0>,
+                                    <0 28 0>, <0 29 0>, <0 30 0>, <0 31 0>;
+                       #interrupt-cells = <2>;
+               };
+
+               gpx2: gpx2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpx3: gpx3 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+       };
+
+       pinctrl@03860000 {
+               gpz: gpz {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+       };
+};
index c390c8f0c8afae80b3f807c95fec89330ad22907..00cad0447d8fbb3b29e6ce393a2f0cdb6269bf66 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 /dts-v1/;
-/include/ "exynos4.dtsi"
+#include "exynos4.dtsi"
 
 / {
        model = "Samsung SMDKV310 on Exynos4210";
index 0ff69393b758621eb5d9d953cce61269ca2d5fba..81188bca13b429a8c761db4020c2d507fbeb1078 100644 (file)
@@ -8,7 +8,7 @@
  */
 
 /dts-v1/;
-/include/ "exynos4.dtsi"
+#include "exynos4210.dtsi"
 
 / {
        model = "Samsung Trats based on Exynos4210";
index 6941906aaa353b3a2ebcd5bb405a824937fc5a72..9139810b1a924e7fab07b306f5c121103ff90c4a 100644 (file)
@@ -8,7 +8,7 @@
  */
 
 /dts-v1/;
-/include/ "exynos4.dtsi"
+#include "exynos4210.dtsi"
 
 / {
        model = "Samsung Universal C210 based on Exynos4210 rev0";
                status = "disabled";
        };
 
+       soft-spi {
+               compatible = "u-boot,soft-spi";
+               cs-gpio = <&gpio 235 0>;        /* Y43 */
+               sclk-gpio = <&gpio 225 0>;      /* Y31 */
+               mosi-gpio = <&gpio 227 0>;      /* Y33 */
+               miso-gpio = <&gpio 224 0>;      /* Y30 */
+               spi-delay-us = <1>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               cs@0 {
+               };
+       };
+
        fimd@11c00000 {
                compatible = "samsung,exynos-fimd";
                reg = <0x11c00000 0xa4>;
diff --git a/arch/arm/dts/exynos4210.dtsi b/arch/arm/dts/exynos4210.dtsi
new file mode 100644 (file)
index 0000000..634a5c1
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * Samsung's Exynos4210 SoC device tree source
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ * Copyright (c) 2010-2011 Linaro Ltd.
+ *             www.linaro.org
+ *
+ * Samsung's Exynos4210 SoC device nodes are listed in this file. Exynos4210
+ * based board files can include this file and provide values for board specfic
+ * bindings.
+ *
+ * Note: This file does not include device nodes for all the controllers in
+ * Exynos4210 SoC. As device tree coverage for Exynos4210 increases, additional
+ * nodes can be added to this file.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include "exynos4.dtsi"
+#include "exynos4210-pinctrl.dtsi"
+#include "exynos4210-pinctrl-uboot.dtsi"
+
+/ {
+       compatible = "samsung,exynos4210";
+
+       aliases {
+               pinctrl0 = &pinctrl_0;
+               pinctrl1 = &pinctrl_1;
+               pinctrl2 = &pinctrl_2;
+       };
+
+       pd_lcd1: lcd1-power-domain@10023CA0 {
+               compatible = "samsung,exynos4210-pd";
+               reg = <0x10023CA0 0x20>;
+       };
+
+       gic: interrupt-controller@10490000 {
+               cpu-offset = <0x8000>;
+       };
+
+       combiner: interrupt-controller@10440000 {
+               samsung,combiner-nr = <16>;
+               interrupts = <0 0 0>, <0 1 0>, <0 2 0>, <0 3 0>,
+                            <0 4 0>, <0 5 0>, <0 6 0>, <0 7 0>,
+                            <0 8 0>, <0 9 0>, <0 10 0>, <0 11 0>,
+                            <0 12 0>, <0 13 0>, <0 14 0>, <0 15 0>;
+       };
+
+       mct@10050000 {
+               compatible = "samsung,exynos4210-mct";
+               reg = <0x10050000 0x800>;
+               interrupt-parent = <&mct_map>;
+               interrupts = <0>, <1>, <2>, <3>, <4>, <5>;
+               clocks = <&clock 3>, <&clock 344>;
+               clock-names = "fin_pll", "mct";
+
+               mct_map: mct-map {
+                       #interrupt-cells = <1>;
+                       #address-cells = <0>;
+                       #size-cells = <0>;
+                       interrupt-map = <0 &gic 0 57 0>,
+                                       <1 &gic 0 69 0>,
+                                       <2 &combiner 12 6>,
+                                       <3 &combiner 12 7>,
+                                       <4 &gic 0 42 0>,
+                                       <5 &gic 0 48 0>;
+               };
+       };
+
+       clock: clock-controller@10030000 {
+               compatible = "samsung,exynos4210-clock";
+               reg = <0x10030000 0x20000>;
+               #clock-cells = <1>;
+       };
+
+       pmu {
+               compatible = "arm,cortex-a9-pmu";
+               interrupt-parent = <&combiner>;
+               interrupts = <2 2>, <3 2>;
+       };
+
+       pinctrl_0: pinctrl@11400000 {
+               compatible = "samsung,exynos4210-pinctrl";
+               reg = <0x11400000 0x1000>;
+               interrupts = <0 47 0>;
+       };
+
+       pinctrl_1: pinctrl@11000000 {
+               compatible = "samsung,exynos4210-pinctrl";
+               reg = <0x11000000 0x1000>;
+               interrupts = <0 46 0>;
+
+               wakup_eint: wakeup-interrupt-controller {
+                       compatible = "samsung,exynos4210-wakeup-eint";
+                       interrupt-parent = <&gic>;
+                       interrupts = <0 32 0>;
+               };
+       };
+
+       pinctrl_2: pinctrl@03860000 {
+               compatible = "samsung,exynos4210-pinctrl";
+               reg = <0x03860000 0x1000>;
+       };
+
+       tmu@100C0000 {
+               compatible = "samsung,exynos4210-tmu";
+               interrupt-parent = <&combiner>;
+               reg = <0x100C0000 0x100>;
+               interrupts = <2 4>;
+               clocks = <&clock 383>;
+               clock-names = "tmu_apbif";
+               status = "disabled";
+       };
+
+       g2d@12800000 {
+               compatible = "samsung,s5pv210-g2d";
+               reg = <0x12800000 0x1000>;
+               interrupts = <0 89 0>;
+               clocks = <&clock 177>, <&clock 277>;
+               clock-names = "sclk_fimg2d", "fimg2d";
+               status = "disabled";
+       };
+
+       camera {
+               clocks = <&clock 132>, <&clock 133>, <&clock 351>, <&clock 352>;
+               clock-names = "sclk_cam0", "sclk_cam1", "pxl_async0", "pxl_async1";
+
+               fimc_0: fimc@11800000 {
+                       samsung,pix-limits = <4224 8192 1920 4224>;
+                       samsung,mainscaler-ext;
+                       samsung,cam-if;
+               };
+
+               fimc_1: fimc@11810000 {
+                       samsung,pix-limits = <4224 8192 1920 4224>;
+                       samsung,mainscaler-ext;
+                       samsung,cam-if;
+               };
+
+               fimc_2: fimc@11820000 {
+                       samsung,pix-limits = <4224 8192 1920 4224>;
+                       samsung,mainscaler-ext;
+                       samsung,lcd-wb;
+               };
+
+               fimc_3: fimc@11830000 {
+                       samsung,pix-limits = <1920 8192 1366 1920>;
+                       samsung,rotators = <0>;
+                       samsung,mainscaler-ext;
+                       samsung,lcd-wb;
+               };
+       };
+};
index 24d0bf18e3e7654c3dac33566edb4cfc14f4174b..4c5e2b39be5cb51181287e6390872b0016df7f5f 100644 (file)
@@ -8,7 +8,7 @@
  */
 
 /dts-v1/;
-/include/ "exynos4.dtsi"
+#include "exynos4.dtsi"
 
 / {
        model = "Odroid based on Exynos4412";
index cc58c878b82ba713f5ca8325642440dafcfd6d1f..3b1e4588b54b3cfb9bd0b5c6bcf3424239eb76c8 100644 (file)
@@ -8,7 +8,7 @@
  */
 
 /dts-v1/;
-/include/ "exynos4.dtsi"
+#include "exynos4412.dtsi"
 
 / {
        model = "Samsung Trats2 based on Exynos4412";
diff --git a/arch/arm/dts/exynos4412.dtsi b/arch/arm/dts/exynos4412.dtsi
new file mode 100644 (file)
index 0000000..87b339c
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Samsung's Exynos4412 SoC device tree source
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Samsung's Exynos4412 SoC device nodes are listed in this file. Exynos4412
+ * based board files can include this file and provide values for board specfic
+ * bindings.
+ *
+ * Note: This file does not include device nodes for all the controllers in
+ * Exynos4412 SoC. As device tree coverage for Exynos4412 increases, additional
+ * nodes can be added to this file.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include "exynos4x12.dtsi"
+
+/ {
+       compatible = "samsung,exynos4412";
+
+       gic: interrupt-controller@10490000 {
+               cpu-offset = <0x4000>;
+       };
+
+       interrupt-controller@10440000 {
+               samsung,combiner-nr = <20>;
+               interrupts = <0 0 0>, <0 1 0>, <0 2 0>, <0 3 0>,
+                            <0 4 0>, <0 5 0>, <0 6 0>, <0 7 0>,
+                            <0 8 0>, <0 9 0>, <0 10 0>, <0 11 0>,
+                            <0 12 0>, <0 13 0>, <0 14 0>, <0 15 0>,
+                            <0 107 0>, <0 108 0>, <0 48 0>, <0 42 0>;
+       };
+
+};
diff --git a/arch/arm/dts/exynos4x12-pinctrl-uboot.dtsi b/arch/arm/dts/exynos4x12-pinctrl-uboot.dtsi
new file mode 100644 (file)
index 0000000..c02796d
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * U-Boot additions to enable a generic Exynos GPIO driver
+ *
+ * Copyright (c) 2014 Google, Inc
+ */
+
+/{
+       pinctrl_0: pinctrl@11400000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               gpf0: gpf0 {
+                       reg = <0xc180>;
+               };
+               gpj0: gpj0 {
+                       reg = <0x240>;
+               };
+       };
+
+       pinctrl_1: pinctrl@11000000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               gpk0: gpk0 {
+                       reg = <0x40>;
+               };
+               gpm0: gpm0 {
+                       reg = <0x260>;
+               };
+               gpy0: gpy0 {
+                       reg = <0x120>;
+               };
+               gpx0: gpx0 {
+                       reg = <0xc00>;
+               };
+       };
+
+       pinctrl_2: pinctrl@03860000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+       };
+
+       pinctrl_3: pinctrl@106E0000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+       };
+
+};
diff --git a/arch/arm/dts/exynos4x12-pinctrl.dtsi b/arch/arm/dts/exynos4x12-pinctrl.dtsi
new file mode 100644 (file)
index 0000000..93f3998
--- /dev/null
@@ -0,0 +1,344 @@
+/*
+ * Samsung's Exynos4x12 SoCs pin-mux and pin-config device tree source
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Samsung's Exynos4x12 SoCs pin-mux and pin-config optiosn are listed as device
+ * tree nodes are listed in this file.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+/ {
+       pinctrl@11400000 {
+               gpa0: gpa0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpa1: gpa1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpb: gpb {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpc0: gpc0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpc1: gpc1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpd0: gpd0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpd1: gpd1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpf0: gpf0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpf1: gpf1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpf2: gpf2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpf3: gpf3 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpj0: gpj0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpj1: gpj1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+       };
+
+       pinctrl@11000000 {
+               gpk0: gpk0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpk1: gpk1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpk2: gpk2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpk3: gpk3 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpl0: gpl0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpl1: gpl1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpl2: gpl2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpm0: gpm0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpm1: gpm1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpm2: gpm2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpm3: gpm3 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpm4: gpm4 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpy0: gpy0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpy1: gpy1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpy2: gpy2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpy3: gpy3 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpy4: gpy4 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpy5: gpy5 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpy6: gpy6 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpx0: gpx0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       interrupt-parent = <&gic>;
+                       interrupts = <0 16 0>, <0 17 0>, <0 18 0>, <0 19 0>,
+                                    <0 20 0>, <0 21 0>, <0 22 0>, <0 23 0>;
+                       #interrupt-cells = <2>;
+               };
+
+               gpx1: gpx1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       interrupt-parent = <&gic>;
+                       interrupts = <0 24 0>, <0 25 0>, <0 26 0>, <0 27 0>,
+                                    <0 28 0>, <0 29 0>, <0 30 0>, <0 31 0>;
+                       #interrupt-cells = <2>;
+               };
+
+               gpx2: gpx2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpx3: gpx3 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+       };
+
+       pinctrl@03860000 {
+               gpz: gpz {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+       };
+
+       pinctrl@106E0000 {
+               gpv0: gpv0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpv1: gpv1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpv2: gpv2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpv3: gpv3 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpv4: gpv4 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+       };
+};
diff --git a/arch/arm/dts/exynos4x12.dtsi b/arch/arm/dts/exynos4x12.dtsi
new file mode 100644 (file)
index 0000000..5d58c6e
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Samsung's Exynos4x12 SoCs device tree source
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Samsung's Exynos4x12 SoCs device nodes are listed in this file. Exynos4x12
+ * based board files can include this file and provide values for board specfic
+ * bindings.
+ *
+ * Note: This file does not include device nodes for all the controllers in
+ * Exynos4x12 SoC. As device tree coverage for Exynos4x12 increases, additional
+ * nodes can be added to this file.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+` * published by the Free Software Foundation.
+*/
+
+#include "exynos4.dtsi"
+#include "exynos4x12-pinctrl.dtsi"
+#include "exynos4x12-pinctrl-uboot.dtsi"
+
+/ {
+       aliases {
+               pinctrl0 = &pinctrl_0;
+               pinctrl1 = &pinctrl_1;
+               pinctrl2 = &pinctrl_2;
+               pinctrl3 = &pinctrl_3;
+               mshc0 = &mshc_0;
+       };
+
+       pd_isp: isp-power-domain@10023CA0 {
+               compatible = "samsung,exynos4210-pd";
+               reg = <0x10023CA0 0x20>;
+       };
+
+       clock: clock-controller@10030000 {
+               compatible = "samsung,exynos4412-clock";
+               reg = <0x10030000 0x20000>;
+               #clock-cells = <1>;
+       };
+
+       mct@10050000 {
+               compatible = "samsung,exynos4412-mct";
+               reg = <0x10050000 0x800>;
+               interrupt-parent = <&mct_map>;
+               interrupts = <0>, <1>, <2>, <3>, <4>;
+               clocks = <&clock 3>, <&clock 344>;
+               clock-names = "fin_pll", "mct";
+
+               mct_map: mct-map {
+                       #interrupt-cells = <1>;
+                       #address-cells = <0>;
+                       #size-cells = <0>;
+                       interrupt-map = <0 &gic 0 57 0>,
+                                       <1 &combiner 12 5>,
+                                       <2 &combiner 12 6>,
+                                       <3 &combiner 12 7>,
+                                       <4 &gic 1 12 0>;
+               };
+       };
+
+       pinctrl_0: pinctrl@11400000 {
+               compatible = "samsung,exynos4x12-pinctrl";
+               reg = <0x11400000 0x1000>;
+               interrupts = <0 47 0>;
+       };
+
+       pinctrl_1: pinctrl@11000000 {
+               compatible = "samsung,exynos4x12-pinctrl";
+               reg = <0x11000000 0x1000>;
+               interrupts = <0 46 0>;
+
+               wakup_eint: wakeup-interrupt-controller {
+                       compatible = "samsung,exynos4210-wakeup-eint";
+                       interrupt-parent = <&gic>;
+                       interrupts = <0 32 0>;
+               };
+       };
+
+       pinctrl_2: pinctrl@03860000 {
+               compatible = "samsung,exynos4x12-pinctrl";
+               reg = <0x03860000 0x1000>;
+               interrupt-parent = <&combiner>;
+               interrupts = <10 0>;
+       };
+
+       pinctrl_3: pinctrl@106E0000 {
+               compatible = "samsung,exynos4x12-pinctrl";
+               reg = <0x106E0000 0x1000>;
+               interrupts = <0 72 0>;
+       };
+
+       g2d@10800000 {
+               compatible = "samsung,exynos4212-g2d";
+               reg = <0x10800000 0x1000>;
+               interrupts = <0 89 0>;
+               clocks = <&clock 177>, <&clock 277>;
+               clock-names = "sclk_fimg2d", "fimg2d";
+               status = "disabled";
+       };
+
+       mshc_0: mmc@12550000 {
+               compatible = "samsung,exynos4412-dw-mshc";
+               reg = <0x12550000 0x1000>;
+               interrupts = <0 77 0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               fifo-depth = <0x80>;
+               clocks = <&clock 301>, <&clock 149>;
+               clock-names = "biu", "ciu";
+               status = "disabled";
+       };
+};
index a2b533a1368ccb503701cb8c77eeaf7f092c37c7..e53906892c82de8b0ba922927fff25c64c859045 100644 (file)
@@ -5,11 +5,38 @@
  * SPDX-License-Identifier:    GPL-2.0+
  */
 
-/include/ "skeleton.dtsi"
+#include "skeleton.dtsi"
 
 / {
        compatible = "samsung,exynos5";
 
+       combiner: interrupt-controller@10440000 {
+               compatible = "samsung,exynos4210-combiner";
+               #interrupt-cells = <2>;
+               interrupt-controller;
+               samsung,combiner-nr = <32>;
+               reg = <0x10440000 0x1000>;
+               interrupts =    <0 0 0>, <0 1 0>, <0 2 0>, <0 3 0>,
+                               <0 4 0>, <0 5 0>, <0 6 0>, <0 7 0>,
+                               <0 8 0>, <0 9 0>, <0 10 0>, <0 11 0>,
+                               <0 12 0>, <0 13 0>, <0 14 0>, <0 15 0>,
+                               <0 16 0>, <0 17 0>, <0 18 0>, <0 19 0>,
+                               <0 20 0>, <0 21 0>, <0 22 0>, <0 23 0>,
+                               <0 24 0>, <0 25 0>, <0 26 0>, <0 27 0>,
+                               <0 28 0>, <0 29 0>, <0 30 0>, <0 31 0>;
+       };
+
+       gic: interrupt-controller@10481000 {
+               compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic";
+               #interrupt-cells = <3>;
+               interrupt-controller;
+               reg =   <0x10481000 0x1000>,
+                       <0x10482000 0x1000>,
+                       <0x10484000 0x2000>,
+                       <0x10486000 0x2000>;
+               interrupts = <1 9 0xf04>;
+       };
+
        sromc@12250000 {
                compatible = "samsung,exynos-sromc";
                reg = <0x12250000 0x20>;
                #size-cells = <0>;
        };
 
+       combiner: interrupt-controller@10440000 {
+               compatible = "samsung,exynos4210-combiner";
+               #interrupt-cells = <2>;
+               interrupt-controller;
+               samsung,combiner-nr = <32>;
+               reg = <0x10440000 0x1000>;
+               interrupts =    <0 0 0>, <0 1 0>, <0 2 0>, <0 3 0>,
+                               <0 4 0>, <0 5 0>, <0 6 0>, <0 7 0>,
+                               <0 8 0>, <0 9 0>, <0 10 0>, <0 11 0>,
+                               <0 12 0>, <0 13 0>, <0 14 0>, <0 15 0>,
+                               <0 16 0>, <0 17 0>, <0 18 0>, <0 19 0>,
+                               <0 20 0>, <0 21 0>, <0 22 0>, <0 23 0>,
+                               <0 24 0>, <0 25 0>, <0 26 0>, <0 27 0>,
+                               <0 28 0>, <0 29 0>, <0 30 0>, <0 31 0>;
+       };
+
+       gic: interrupt-controller@10481000 {
+               compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic";
+               #interrupt-cells = <3>;
+               interrupt-controller;
+               reg =   <0x10481000 0x1000>,
+                       <0x10482000 0x1000>,
+                       <0x10484000 0x2000>,
+                       <0x10486000 0x2000>;
+               interrupts = <1 9 0xf04>;
+       };
+
        i2c@12c60000 {
                #address-cells = <1>;
                #size-cells = <0>;
                compatible = "samsung,exynos4210-uart";
                reg = <0x12C30000 0x100>;
                interrupts = <0 54 0>;
+               u-boot,dm-pre-reloc;
                id = <3>;
        };
 
diff --git a/arch/arm/dts/exynos5250-pinctrl-uboot.dtsi b/arch/arm/dts/exynos5250-pinctrl-uboot.dtsi
new file mode 100644 (file)
index 0000000..7edb0ca
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * U-Boot additions to enable a generic Exynos GPIO driver
+ *
+ * Copyright (c) 2014 Google, Inc
+ */
+
+/{
+       pinctrl_0: pinctrl@11400000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               gpc4: gpc4 {
+                       reg = <0x2e0>;
+               };
+               gpx0: gpx0 {
+                       reg = <0xc00>;
+               };
+       };
+
+       pinctrl_1: pinctrl@13400000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+       };
+
+       pinctrl_2: pinctrl@10d10000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               gpv2: gpv2 {
+                       reg = <0x060>;
+               };
+               gpv4: gpv4 {
+                       reg = <0xc0>;
+               };
+       };
+
+       pinctrl_3: pinctrl@03860000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+       };
+
+};
diff --git a/arch/arm/dts/exynos5250-pinctrl.dtsi b/arch/arm/dts/exynos5250-pinctrl.dtsi
new file mode 100644 (file)
index 0000000..67755a1
--- /dev/null
@@ -0,0 +1,331 @@
+/*
+ * Samsung's Exynos5250 SoC pin-mux and pin-config device tree source
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Samsung's Exynos5250 SoC pin-mux and pin-config optiosn are listed as device
+ * tree nodes are listed in this file.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+/ {
+       pinctrl@11400000 {
+               gpa0: gpa0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpa1: gpa1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpa2: gpa2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpb0: gpb0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpb1: gpb1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpb2: gpb2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpb3: gpb3 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpc0: gpc0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpc1: gpc1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpc2: gpc2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpc3: gpc3 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpd0: gpd0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpd1: gpd1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpy0: gpy0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpy1: gpy1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpy2: gpy2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpy3: gpy3 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpy4: gpy4 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpy5: gpy5 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpy6: gpy6 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpc4: gpc4 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpx0: gpx0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       interrupt-parent = <&combiner>;
+                       #interrupt-cells = <2>;
+                       interrupts = <23 0>, <24 0>, <25 0>, <25 1>,
+                                    <26 0>, <26 1>, <27 0>, <27 1>;
+               };
+
+               gpx1: gpx1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       interrupt-parent = <&combiner>;
+                       #interrupt-cells = <2>;
+                       interrupts = <28 0>, <28 1>, <29 0>, <29 1>,
+                                    <30 0>, <30 1>, <31 0>, <31 1>;
+               };
+
+               gpx2: gpx2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpx3: gpx3 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+       };
+
+       pinctrl@13400000 {
+               gpe0: gpe0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpe1: gpe1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpf0: gpf0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpf1: gpf1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpg0: gpg0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpg1: gpg1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpg2: gpg2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gph0: gph0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gph1: gph1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+       };
+
+       pinctrl@10d10000 {
+               gpv0: gpv0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpv1: gpv1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpv2: gpv2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpv3: gpv3 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpv4: gpv4 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+       };
+
+       pinctrl@03860000 {
+               gpz: gpz {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+       };
+};
index 9020382d97cf4df92f7ba13513248c58a8f5f5f1..885040920c077cad8aa26f8360daed79bc4d0d81 100644 (file)
@@ -10,7 +10,7 @@
 */
 
 /dts-v1/;
-/include/ "exynos5250.dtsi"
+#include "exynos5250.dtsi"
 
 / {
        model = "SAMSUNG SMDK5250 board based on EXYNOS5250";
index ab4f2f858151c7710b2c114bcca9f11820c2cc57..6fd9275c4ef789134344bd4a774de154e18c4c5a 100644 (file)
@@ -10,7 +10,7 @@
 */
 
 /dts-v1/;
-/include/ "exynos5250.dtsi"
+#include "exynos5250.dtsi"
 
 / {
        model = "Google Snow";
                };
        };
 
+       spi@12d30000 {
+               spi-max-frequency = <50000000>;
+               firmware_storage_spi: flash@0 {
+                       compatible = "spi-flash";
+                       reg = <0>;
+               };
+       };
+
        spi@131b0000 {
                spi-max-frequency = <1000000>;
                spi-deactivate-delay = <100>;
index 0c644e7cac8ce563af433f726ece26abaf8922bc..ccbafe9b07d7500569c4be9a82f3cb57bdf5d322 100644 (file)
@@ -5,9 +5,48 @@
  * SPDX-License-Identifier:    GPL-2.0+
  */
 
-/include/ "exynos5.dtsi"
+#include "exynos5.dtsi"
+#include "exynos5250-pinctrl.dtsi"
+#include "exynos5250-pinctrl-uboot.dtsi"
 
 / {
+       aliases {
+               pinctrl0 = &pinctrl_0;
+               pinctrl1 = &pinctrl_1;
+               pinctrl2 = &pinctrl_2;
+               pinctrl3 = &pinctrl_3;
+       };
+
+       pinctrl_0: pinctrl@11400000 {
+               compatible = "samsung,exynos5250-pinctrl";
+               reg = <0x11400000 0x1000>;
+               interrupts = <0 46 0>;
+
+               wakup_eint: wakeup-interrupt-controller {
+                       compatible = "samsung,exynos4210-wakeup-eint";
+                       interrupt-parent = <&gic>;
+                       interrupts = <0 32 0>;
+               };
+       };
+
+       pinctrl_1: pinctrl@13400000 {
+               compatible = "samsung,exynos5250-pinctrl";
+               reg = <0x13400000 0x1000>;
+               interrupts = <0 45 0>;
+       };
+
+       pinctrl_2: pinctrl@10d10000 {
+               compatible = "samsung,exynos5250-pinctrl";
+               reg = <0x10d10000 0x1000>;
+               interrupts = <0 50 0>;
+       };
+
+       pinctrl_3: pinctrl@03860000 {
+               compatible = "samsung,exynos5250-pinctrl";
+               reg = <0x03860000 0x1000>;
+               interrupts = <0 47 0>;
+       };
+
        i2c@12ca0000 {
                #address-cells = <1>;
                #size-cells = <0>;
index 995e62b33721fe345dce5c705a0427382c1c2643..fde863de3cf6b00b9b5fbcc3aa7585f3026044fc 100644 (file)
@@ -8,7 +8,7 @@
  */
 
 /dts-v1/;
-/include/ "exynos54xx.dtsi"
+#include "exynos54xx.dtsi"
 
 / {
        model = "Samsung/Google Peach Pit board based on Exynos5420";
        spi@12d30000 { /* spi1 */
                spi-max-frequency = <50000000>;
                firmware_storage_spi: flash@0 {
+                       compatible = "spi-flash";
                        reg = <0>;
 
                        /*
index 1bc62562835f045b686a9cf3099055d8186fcc97..6855027389d8d84cf7ad59decc7a377d62034e39 100644 (file)
@@ -8,7 +8,7 @@
  */
 
 /dts-v1/;
-/include/ "exynos54xx.dtsi"
+#include "exynos54xx.dtsi"
 
 / {
        model = "SAMSUNG SMDK5420 board based on EXYNOS5420";
diff --git a/arch/arm/dts/exynos54xx-pinctrl-uboot.dtsi b/arch/arm/dts/exynos54xx-pinctrl-uboot.dtsi
new file mode 100644 (file)
index 0000000..5a86211
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * U-Boot additions to enable a generic Exynos GPIO driver
+ *
+ * Copyright (c) 2014 Google, Inc
+ */
+
+/{
+       /*
+        * Replicate the ordering of arch/arm/include/asm/arch-exynos/gpio.h
+        * TODO(sjg@chromium.org): This ordering ceases to matter once GPIO
+        * numbers are not needed in U-Boot for exynos.
+        */
+       pinctrl@14010000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+       };
+       pinctrl@13400000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               gpy7 {
+               };
+
+               gpx0 {
+                       reg = <0xc00>;
+               };
+       };
+       pinctrl@13410000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+       };
+       pinctrl@14000000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+       };
+       pinctrl@03860000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+       };
+
+};
diff --git a/arch/arm/dts/exynos54xx-pinctrl.dtsi b/arch/arm/dts/exynos54xx-pinctrl.dtsi
new file mode 100644 (file)
index 0000000..775d956
--- /dev/null
@@ -0,0 +1,305 @@
+/*
+ * Samsung's Exynos5420 SoC pin-mux and pin-config device tree source
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Samsung's Exynos5420 SoC pin-mux and pin-config options are listed as device
+ * tree nodes are listed in this file.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include "exynos54xx-pinctrl-uboot.dtsi"
+
+/ {
+       pinctrl@13400000 {
+               gpy7: gpy7 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpx0: gpx0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       interrupt-parent = <&combiner>;
+                       #interrupt-cells = <2>;
+                       interrupts = <23 0>, <24 0>, <25 0>, <25 1>,
+                                    <26 0>, <26 1>, <27 0>, <27 1>;
+               };
+
+               gpx1: gpx1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       interrupt-parent = <&combiner>;
+                       #interrupt-cells = <2>;
+                       interrupts = <28 0>, <28 1>, <29 0>, <29 1>,
+                                    <30 0>, <30 1>, <31 0>, <31 1>;
+               };
+
+               gpx2: gpx2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpx3: gpx3 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+       };
+
+       pinctrl@13410000 {
+               gpc0: gpc0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpc1: gpc1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpc2: gpc2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpc3: gpc3 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpc4: gpc4 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpd1: gpd1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpy0: gpy0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpy1: gpy1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpy2: gpy2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpy3: gpy3 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpy4: gpy4 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpy5: gpy5 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpy6: gpy6 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+       };
+
+       pinctrl@14000000 {
+               gpe0: gpe0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpe1: gpe1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpf0: gpf0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpf1: gpf1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpg0: gpg0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpg1: gpg1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpg2: gpg2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpj4: gpj4 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+       };
+
+       pinctrl@14010000 {
+               gpa0: gpa0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpa1: gpa1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpa2: gpa2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpb0: gpb0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpb1: gpb1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpb2: gpb2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpb3: gpb3 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpb4: gpb4 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gph0: gph0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+       };
+
+       pinctrl@03860000 {
+               gpz: gpz {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+       };
+};
index c21d798a23d0b54a295d6f0a90a8f5c578f925dc..916cf3a5b6681dd72d061eb7e48ab88d2ab8c270 100644 (file)
@@ -5,7 +5,8 @@
  * SPDX-License-Identifier:    GPL-2.0+
  */
 
-/include/ "exynos5.dtsi"
+#include "exynos5.dtsi"
+#include "exynos54xx-pinctrl.dtsi"
 
 / {
        config {
                i2c8 = "/i2c@12e00000";
                i2c9 = "/i2c@12e10000";
                i2c10 = "/i2c@12e20000";
+               pinctrl0 = &pinctrl_0;
+               pinctrl1 = &pinctrl_1;
+               pinctrl2 = &pinctrl_2;
+               pinctrl3 = &pinctrl_3;
+               pinctrl4 = &pinctrl_4;
                spi0 = "/spi@12d20000";
                spi1 = "/spi@12d30000";
                spi2 = "/spi@12d40000";
                reg = <0x14680000 0x100>;
        };
 
+       pinctrl_0: pinctrl@13400000 {
+               compatible = "samsung,exynos5420-pinctrl";
+               reg = <0x13400000 0x1000>;
+               interrupts = <0 45 0>;
+
+               wakeup-interrupt-controller {
+                       compatible = "samsung,exynos4210-wakeup-eint";
+                       interrupt-parent = <&gic>;
+                       interrupts = <0 32 0>;
+               };
+       };
+
+       pinctrl_1: pinctrl@13410000 {
+               compatible = "samsung,exynos5420-pinctrl";
+               reg = <0x13410000 0x1000>;
+               interrupts = <0 78 0>;
+       };
+
+       pinctrl_2: pinctrl@14000000 {
+               compatible = "samsung,exynos5420-pinctrl";
+               reg = <0x14000000 0x1000>;
+               interrupts = <0 46 0>;
+       };
+
+       pinctrl_3: pinctrl@14010000 {
+               compatible = "samsung,exynos5420-pinctrl";
+               reg = <0x14010000 0x1000>;
+               interrupts = <0 50 0>;
+       };
+
+       pinctrl_4: pinctrl@03860000 {
+               compatible = "samsung,exynos5420-pinctrl";
+               reg = <0x03860000 0x1000>;
+               interrupts = <0 47 0>;
+       };
+
        fimd@14400000 {
                /* sysmmu is not used in U-Boot */
                samsung,disable-sysmmu;
diff --git a/arch/arm/dts/s5pc100-pinctrl.dtsi b/arch/arm/dts/s5pc100-pinctrl.dtsi
new file mode 100644 (file)
index 0000000..bd9f97c
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * U-Boot additions to enable a generic Exynos GPIO driver
+ *
+ * Copyright (c) 2014 Google, Inc
+ */
+
+/ {
+       pinctrl@e0300000 {
+               gpa0: gpa0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpa1: gpa1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpb: gpb {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpc: gpc {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpd: gpd {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpe0: gpe0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpe1: gpe1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpf0: gpf0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpf1: gpf1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpf2: gpf2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpf3: gpf3 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpg0: gpg0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpg1: gpg1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpg2: gpg2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpg3: gpg3 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpi: gpi {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpj0: gpj0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpj1: gpj1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpj2: gpj2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpj3: gpj3 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpj4: gpj4 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpk0: gpk0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpk1: gpk1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpk2: gpk2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpk3: gpk3 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpl0: gpl0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpl1: gpl1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpl2: gpl2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpl3: gpl3 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpl4: gpl4 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gph0: gph0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gph1: gph1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gph2: gph2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gph3: gph3 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+       };
+};
diff --git a/arch/arm/dts/s5pc110-pinctrl.dtsi b/arch/arm/dts/s5pc110-pinctrl.dtsi
new file mode 100644 (file)
index 0000000..d21b6ab
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * U-Boot additions to enable a generic Exynos GPIO driver
+ *
+ * Copyright (c) 2014 Google, Inc
+ */
+
+/ {
+       pinctrl@e0200000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               gpa0: gpa0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpa1: gpa1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpb: gpb {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpc0: gpc0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpc1: gpc1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpd0: gpd0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpd1: gpd1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpe0: gpe0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpe1: gpe1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpf0: gpf0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpf1: gpf1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpf2: gpf2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpf3: gpf3 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpg0: gpg0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpg1: gpg1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpg2: gpg2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpg3: gpg3 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpi: gpi {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpj0: gpj0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpj1: gpj1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpj2: gpj2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpj3: gpj3 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpj4: gpj4 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpmp01: gpmp01 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpmp02: gpmp02 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpmp03: gpmp03 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpmp04: gpmp04 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpmp05: gpmp05 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpmp06: gpmp06 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpmp07: gpmp07 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpmp10: gpmp10 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpmp11: gpmp11 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpmp12: gpmp12 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpmp13: gpmp13 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpmp14: gpmp14 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpmp15: gpmp15 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpmp16: gpmp16 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpmp17: gpmp17 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpmp18: gpmp18 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpmp20: gpmp20 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpmp21: gpmp21 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpmp22: gpmp22 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpmp23: gpmp23 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpmp24: gpmp24 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpmp25: gpmp25 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpmp26: gpmp26 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpmp27: gpmp27 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpmp28: gpmp28 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gph0: gph0 {
+                       reg = <0xc00>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gph1: gph1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gph2: gph2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gph3: gph3 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+       };
+};
index 2e671bbf7e9a99f54ad5c4b0d0e26c43ff49c5f5..7bbfe591cd88e1ae45bc25e7cbaf5d8a2fe5c67c 100644 (file)
@@ -9,6 +9,7 @@
 /dts-v1/;
 
 #include "skeleton.dtsi"
+#include "s5pc110-pinctrl.dtsi"
 
 / {
        model = "Samsung Goni based on S5PC110";
        aliases {
                serial2 = "/serial@e2900800";
                console = "/serial@e2900800";
+               pinctrl0 = &pinctrl0;
+       };
+
+       pinctrl0: pinctrl@e0200000 {
+               compatible = "samsung,s5pc110-pinctrl";
+               reg = <0xe0200000 0x1000>;
        };
 
        serial@e2900800 {
index 42754ce811c7c5eab93a298e23309181b728d765..95f15ed48d39ccd57e029f7abe3124ddcc1e9319 100644 (file)
@@ -9,6 +9,7 @@
 /dts-v1/;
 
 #include "skeleton.dtsi"
+#include "s5pc100-pinctrl.dtsi"
 
 / {
        model = "Samsung SMDKC100 based on S5PC100";
        aliases {
                serial0 = "/serial@ec000000";
                console = "/serial@ec000000";
+               pinctrl0 = &pinctrl0;
+       };
+
+       pinctrl0: pinctrl@e0300000 {
+               compatible = "samsung,s5pc100-pinctrl";
+               reg = <0xe0200000 0x1000>;
        };
 
        serial@ec000000 {
index cee5cfe0d2dbb8c6024fffba353e22eec57fc2ef..74e8a16280bd85afa150c77ef52861e734272d46 100644 (file)
@@ -15,6 +15,7 @@
                usb1 = "/usb@c5000000";
                sdhci0 = "/sdhci@c8000600";
                sdhci1 = "/sdhci@c8000000";
+               spi0 = "/spi@7000c380";
        };
 
        memory {
index ad140def95f4d630e11519554f16d71fbfb10f25..9acd84d80296fa367f6e1196051cf9f9b200497c 100644 (file)
@@ -18,6 +18,7 @@
                i2c4 = "/i2c@7000c700";
                sdhci0 = "/sdhci@78000600";
                sdhci1 = "/sdhci@78000000";
+               spi0 = "/spi@7000da00";
                usb0 = "/usb@7d000000";
                usb1 = "/usb@7d008000";
        };
index b4fbe71aa534c01d60b541b790bd25b921fc7211..1b8ed737e049707f0cec91f491bdb2e84e3099f0 100644 (file)
@@ -18,6 +18,7 @@
                i2c4 = "/i2c@7000c700";
                sdhci0 = "/sdhci@78000600";
                sdhci1 = "/sdhci@78000000";
+               spi0 = "/spi@7000da00";
                usb0 = "/usb@7d008000";
        };
 
index 43d03ca4fa53a256bfe79cd3abdfe8fa937d2507..df79c26a45898ee5a89b348950db872918e7f405 100644 (file)
@@ -12,6 +12,7 @@
                i2c2 = "/i2c@7000c700";
                sdhci0 = "/sdhci@78000600";
                sdhci1 = "/sdhci@78000200";
+               spi0 = "/spi@7000d400";
                usb0 = "/usb@7d000000";
                usb1 = "/usb@7d004000"; /* on module only, for ASIX */
                usb2 = "/usb@7d008000";
index a58087399cedc8786983d5a41268e97976ee07e9..34f53872e89b3d0674f9cff2227a8d10ea510c45 100644 (file)
@@ -4,6 +4,7 @@
  * SPDX-License-Identifier:    GPL-2.0+
  */
 #include <common.h>
+#include <malloc.h>
 #include <asm/arch/clock.h>
 #include <asm/arch/imx-regs.h>
 #include <asm/errno.h>
@@ -69,15 +70,53 @@ static void * const i2c_bases[] = {
 };
 
 /* i2c_index can be from 0 - 2 */
-void setup_i2c(unsigned i2c_index, int speed, int slave_addr,
-               struct i2c_pads_info *p)
+int setup_i2c(unsigned i2c_index, int speed, int slave_addr,
+             struct i2c_pads_info *p)
 {
+       char *name1, *name2;
+       int ret;
+
        if (i2c_index >= ARRAY_SIZE(i2c_bases))
-               return;
+               return -EINVAL;
+
+       name1 = malloc(9);
+       name2 = malloc(9);
+       if (!name1 || !name2)
+               return -ENOMEM;
+
+       sprintf(name1, "i2c_sda%d", i2c_index);
+       sprintf(name2, "i2c_scl%d", i2c_index);
+       ret = gpio_request(p->sda.gp, name1);
+       if (ret)
+               goto err_req1;
+
+       ret = gpio_request(p->scl.gp, name2);
+       if (ret)
+               goto err_req2;
+
        /* Enable i2c clock */
-       enable_i2c_clk(1, i2c_index);
+       ret = enable_i2c_clk(1, i2c_index);
+       if (ret)
+               goto err_clk;
+
        /* Make sure bus is idle */
-       force_idle_bus(p);
+       ret = force_idle_bus(p);
+       if (ret)
+               goto err_idle;
+
        bus_i2c_init(i2c_bases[i2c_index], speed, slave_addr,
                        force_idle_bus, p);
+
+       return 0;
+
+err_idle:
+err_clk:
+       gpio_free(p->scl.gp);
+err_req2:
+       gpio_free(p->sda.gp);
+err_req1:
+       free(name1);
+       free(name2);
+
+       return ret;
 }
index 9a49b6e05efa5af346953a183f88d415d98fe46d..db42896201b321fb623af79c78a22addddf9de34 100644 (file)
@@ -52,4 +52,13 @@ struct bcm2835_gpio_regs {
        u32 gppudclk[2];
 };
 
+/**
+ * struct bcm2835_gpio_platdata - GPIO platform description
+ *
+ * @base: Base address of GPIO controller
+ */
+struct bcm2835_gpio_platdata {
+       unsigned long base;
+};
+
 #endif /* _BCM2835_GPIO_H_ */
index 8fb5c2321ecdd5c95c43230e7198260cf10ed8a5..ad2ece64f49b3568e7903541360f89bb1d2e5c63 100644 (file)
@@ -284,7 +284,7 @@ enum exynos4_gpio_pin {
        EXYNOS4_GPIO_Y65,
        EXYNOS4_GPIO_Y66,
        EXYNOS4_GPIO_Y67,
-       EXYNOS4_GPIO_X00 = 896,         /* 896 0x380 */
+       EXYNOS4_GPIO_X00,               /* 256 0x100 */
        EXYNOS4_GPIO_X01,
        EXYNOS4_GPIO_X02,
        EXYNOS4_GPIO_X03,
@@ -292,7 +292,7 @@ enum exynos4_gpio_pin {
        EXYNOS4_GPIO_X05,
        EXYNOS4_GPIO_X06,
        EXYNOS4_GPIO_X07,
-       EXYNOS4_GPIO_X10,               /* 904 0x388 */
+       EXYNOS4_GPIO_X10,               /* 264 0x108 */
        EXYNOS4_GPIO_X11,
        EXYNOS4_GPIO_X12,
        EXYNOS4_GPIO_X13,
@@ -300,7 +300,7 @@ enum exynos4_gpio_pin {
        EXYNOS4_GPIO_X15,
        EXYNOS4_GPIO_X16,
        EXYNOS4_GPIO_X17,
-       EXYNOS4_GPIO_X20,               /* 912 0x390 */
+       EXYNOS4_GPIO_X20,               /* 272 0x110 */
        EXYNOS4_GPIO_X21,
        EXYNOS4_GPIO_X22,
        EXYNOS4_GPIO_X23,
@@ -308,7 +308,7 @@ enum exynos4_gpio_pin {
        EXYNOS4_GPIO_X25,
        EXYNOS4_GPIO_X26,
        EXYNOS4_GPIO_X27,
-       EXYNOS4_GPIO_X30,               /* 920 0x398 */
+       EXYNOS4_GPIO_X30,               /* 280 0x118 */
        EXYNOS4_GPIO_X31,
        EXYNOS4_GPIO_X32,
        EXYNOS4_GPIO_X33,
@@ -318,7 +318,7 @@ enum exynos4_gpio_pin {
        EXYNOS4_GPIO_X37,
 
        /* GPIO_PART3_STARTS */
-       EXYNOS4_GPIO_MAX_PORT_PART_2,   /* 928 0x3A0 */
+       EXYNOS4_GPIO_MAX_PORT_PART_2,   /* 288 0x120 */
        EXYNOS4_GPIO_Z0 = EXYNOS4_GPIO_MAX_PORT_PART_2,
        EXYNOS4_GPIO_Z1,
        EXYNOS4_GPIO_Z2,
@@ -389,7 +389,7 @@ enum exynos4X12_gpio_pin {
        EXYNOS4X12_GPIO_D15,
        EXYNOS4X12_GPIO_D16,
        EXYNOS4X12_GPIO_D17,
-       EXYNOS4X12_GPIO_F00 = 96,       /* 96 0x60 */
+       EXYNOS4X12_GPIO_F00,            /* 56 0x38 */
        EXYNOS4X12_GPIO_F01,
        EXYNOS4X12_GPIO_F02,
        EXYNOS4X12_GPIO_F03,
@@ -397,7 +397,7 @@ enum exynos4X12_gpio_pin {
        EXYNOS4X12_GPIO_F05,
        EXYNOS4X12_GPIO_F06,
        EXYNOS4X12_GPIO_F07,
-       EXYNOS4X12_GPIO_F10,            /* 104 0x68 */
+       EXYNOS4X12_GPIO_F10,            /* 64 0x40 */
        EXYNOS4X12_GPIO_F11,
        EXYNOS4X12_GPIO_F12,
        EXYNOS4X12_GPIO_F13,
@@ -405,7 +405,7 @@ enum exynos4X12_gpio_pin {
        EXYNOS4X12_GPIO_F15,
        EXYNOS4X12_GPIO_F16,
        EXYNOS4X12_GPIO_F17,
-       EXYNOS4X12_GPIO_F20,            /* 112 0x70 */
+       EXYNOS4X12_GPIO_F20,            /* 72 0x48 */
        EXYNOS4X12_GPIO_F21,
        EXYNOS4X12_GPIO_F22,
        EXYNOS4X12_GPIO_F23,
@@ -413,7 +413,7 @@ enum exynos4X12_gpio_pin {
        EXYNOS4X12_GPIO_F25,
        EXYNOS4X12_GPIO_F26,
        EXYNOS4X12_GPIO_F27,
-       EXYNOS4X12_GPIO_F30,            /* 120 0x78 */
+       EXYNOS4X12_GPIO_F30,            /* 80 0x50 */
        EXYNOS4X12_GPIO_F31,
        EXYNOS4X12_GPIO_F32,
        EXYNOS4X12_GPIO_F33,
@@ -421,7 +421,7 @@ enum exynos4X12_gpio_pin {
        EXYNOS4X12_GPIO_F35,
        EXYNOS4X12_GPIO_F36,
        EXYNOS4X12_GPIO_F37,
-       EXYNOS4X12_GPIO_J00 = 144,      /* 144 0x90 */
+       EXYNOS4X12_GPIO_J00,            /* 88 0x58 */
        EXYNOS4X12_GPIO_J01,
        EXYNOS4X12_GPIO_J02,
        EXYNOS4X12_GPIO_J03,
@@ -429,7 +429,7 @@ enum exynos4X12_gpio_pin {
        EXYNOS4X12_GPIO_J05,
        EXYNOS4X12_GPIO_J06,
        EXYNOS4X12_GPIO_J07,
-       EXYNOS4X12_GPIO_J10,            /* 152 0x98 */
+       EXYNOS4X12_GPIO_J10,            /* 96 0x60 */
        EXYNOS4X12_GPIO_J11,
        EXYNOS4X12_GPIO_J12,
        EXYNOS4X12_GPIO_J13,
@@ -439,8 +439,8 @@ enum exynos4X12_gpio_pin {
        EXYNOS4X12_GPIO_J17,
 
        /* GPIO_PART2_STARTS */
-       EXYNOS4X12_GPIO_MAX_PORT_PART_1,/* 160 0xA0 */
-       EXYNOS4X12_GPIO_K00 = 176,      /* 176 0xB0 */
+       EXYNOS4X12_GPIO_MAX_PORT_PART_1,/* 104 0x66 */
+       EXYNOS4X12_GPIO_K00 = EXYNOS4X12_GPIO_MAX_PORT_PART_1,
        EXYNOS4X12_GPIO_K01,
        EXYNOS4X12_GPIO_K02,
        EXYNOS4X12_GPIO_K03,
@@ -448,7 +448,7 @@ enum exynos4X12_gpio_pin {
        EXYNOS4X12_GPIO_K05,
        EXYNOS4X12_GPIO_K06,
        EXYNOS4X12_GPIO_K07,
-       EXYNOS4X12_GPIO_K10,            /* 184 0xB8 */
+       EXYNOS4X12_GPIO_K10,            /* 112 0x70 */
        EXYNOS4X12_GPIO_K11,
        EXYNOS4X12_GPIO_K12,
        EXYNOS4X12_GPIO_K13,
@@ -456,7 +456,7 @@ enum exynos4X12_gpio_pin {
        EXYNOS4X12_GPIO_K15,
        EXYNOS4X12_GPIO_K16,
        EXYNOS4X12_GPIO_K17,
-       EXYNOS4X12_GPIO_K20,            /* 192 0xC0 */
+       EXYNOS4X12_GPIO_K20,            /* 120 0x78 */
        EXYNOS4X12_GPIO_K21,
        EXYNOS4X12_GPIO_K22,
        EXYNOS4X12_GPIO_K23,
@@ -464,7 +464,7 @@ enum exynos4X12_gpio_pin {
        EXYNOS4X12_GPIO_K25,
        EXYNOS4X12_GPIO_K26,
        EXYNOS4X12_GPIO_K27,
-       EXYNOS4X12_GPIO_K30,            /* 200 0xC8 */
+       EXYNOS4X12_GPIO_K30,            /* 128 0x80 */
        EXYNOS4X12_GPIO_K31,
        EXYNOS4X12_GPIO_K32,
        EXYNOS4X12_GPIO_K33,
@@ -472,7 +472,7 @@ enum exynos4X12_gpio_pin {
        EXYNOS4X12_GPIO_K35,
        EXYNOS4X12_GPIO_K36,
        EXYNOS4X12_GPIO_K37,
-       EXYNOS4X12_GPIO_L00,            /* 208 0xD0 */
+       EXYNOS4X12_GPIO_L00,            /* 136 0x88 */
        EXYNOS4X12_GPIO_L01,
        EXYNOS4X12_GPIO_L02,
        EXYNOS4X12_GPIO_L03,
@@ -480,7 +480,7 @@ enum exynos4X12_gpio_pin {
        EXYNOS4X12_GPIO_L05,
        EXYNOS4X12_GPIO_L06,
        EXYNOS4X12_GPIO_L07,
-       EXYNOS4X12_GPIO_L10,            /* 216 0xD8 */
+       EXYNOS4X12_GPIO_L10,            /* 144 0x90 */
        EXYNOS4X12_GPIO_L11,
        EXYNOS4X12_GPIO_L12,
        EXYNOS4X12_GPIO_L13,
@@ -488,7 +488,7 @@ enum exynos4X12_gpio_pin {
        EXYNOS4X12_GPIO_L15,
        EXYNOS4X12_GPIO_L16,
        EXYNOS4X12_GPIO_L17,
-       EXYNOS4X12_GPIO_L20,            /* 224 0xE0 */
+       EXYNOS4X12_GPIO_L20,            /* 152 0x98 */
        EXYNOS4X12_GPIO_L21,
        EXYNOS4X12_GPIO_L22,
        EXYNOS4X12_GPIO_L23,
@@ -496,7 +496,7 @@ enum exynos4X12_gpio_pin {
        EXYNOS4X12_GPIO_L25,
        EXYNOS4X12_GPIO_L26,
        EXYNOS4X12_GPIO_L27,
-       EXYNOS4X12_GPIO_Y00,            /* 232 0xE8 */
+       EXYNOS4X12_GPIO_Y00,            /* 160 0xa0 */
        EXYNOS4X12_GPIO_Y01,
        EXYNOS4X12_GPIO_Y02,
        EXYNOS4X12_GPIO_Y03,
@@ -504,7 +504,7 @@ enum exynos4X12_gpio_pin {
        EXYNOS4X12_GPIO_Y05,
        EXYNOS4X12_GPIO_Y06,
        EXYNOS4X12_GPIO_Y07,
-       EXYNOS4X12_GPIO_Y10,            /* 240 0xF0 */
+       EXYNOS4X12_GPIO_Y10,            /* 168 0xa8 */
        EXYNOS4X12_GPIO_Y11,
        EXYNOS4X12_GPIO_Y12,
        EXYNOS4X12_GPIO_Y13,
@@ -512,7 +512,7 @@ enum exynos4X12_gpio_pin {
        EXYNOS4X12_GPIO_Y15,
        EXYNOS4X12_GPIO_Y16,
        EXYNOS4X12_GPIO_Y17,
-       EXYNOS4X12_GPIO_Y20,            /* 248 0xF8 */
+       EXYNOS4X12_GPIO_Y20,            /* 176 0xb0 */
        EXYNOS4X12_GPIO_Y21,
        EXYNOS4X12_GPIO_Y22,
        EXYNOS4X12_GPIO_Y23,
@@ -520,7 +520,7 @@ enum exynos4X12_gpio_pin {
        EXYNOS4X12_GPIO_Y25,
        EXYNOS4X12_GPIO_Y26,
        EXYNOS4X12_GPIO_Y27,
-       EXYNOS4X12_GPIO_Y30,            /* 256 0x100 */
+       EXYNOS4X12_GPIO_Y30,            /* 184 0xb8 */
        EXYNOS4X12_GPIO_Y31,
        EXYNOS4X12_GPIO_Y32,
        EXYNOS4X12_GPIO_Y33,
@@ -528,7 +528,7 @@ enum exynos4X12_gpio_pin {
        EXYNOS4X12_GPIO_Y35,
        EXYNOS4X12_GPIO_Y36,
        EXYNOS4X12_GPIO_Y37,
-       EXYNOS4X12_GPIO_Y40,            /* 264 0x108 */
+       EXYNOS4X12_GPIO_Y40,            /* 192 0xc0 */
        EXYNOS4X12_GPIO_Y41,
        EXYNOS4X12_GPIO_Y42,
        EXYNOS4X12_GPIO_Y43,
@@ -536,7 +536,7 @@ enum exynos4X12_gpio_pin {
        EXYNOS4X12_GPIO_Y45,
        EXYNOS4X12_GPIO_Y46,
        EXYNOS4X12_GPIO_Y47,
-       EXYNOS4X12_GPIO_Y50,            /* 272 0x110 */
+       EXYNOS4X12_GPIO_Y50,            /* 200 0xc8 */
        EXYNOS4X12_GPIO_Y51,
        EXYNOS4X12_GPIO_Y52,
        EXYNOS4X12_GPIO_Y53,
@@ -544,7 +544,7 @@ enum exynos4X12_gpio_pin {
        EXYNOS4X12_GPIO_Y55,
        EXYNOS4X12_GPIO_Y56,
        EXYNOS4X12_GPIO_Y57,
-       EXYNOS4X12_GPIO_Y60,            /* 280 0x118 */
+       EXYNOS4X12_GPIO_Y60,            /* 208 0xd0 */
        EXYNOS4X12_GPIO_Y61,
        EXYNOS4X12_GPIO_Y62,
        EXYNOS4X12_GPIO_Y63,
@@ -552,7 +552,7 @@ enum exynos4X12_gpio_pin {
        EXYNOS4X12_GPIO_Y65,
        EXYNOS4X12_GPIO_Y66,
        EXYNOS4X12_GPIO_Y67,
-       EXYNOS4X12_GPIO_M00 = 312,      /* 312 0xF0 */
+       EXYNOS4X12_GPIO_M00,            /* 216 0xd8 */
        EXYNOS4X12_GPIO_M01,
        EXYNOS4X12_GPIO_M02,
        EXYNOS4X12_GPIO_M03,
@@ -560,7 +560,7 @@ enum exynos4X12_gpio_pin {
        EXYNOS4X12_GPIO_M05,
        EXYNOS4X12_GPIO_M06,
        EXYNOS4X12_GPIO_M07,
-       EXYNOS4X12_GPIO_M10,            /* 320 0xF8 */
+       EXYNOS4X12_GPIO_M10,            /* 224 0xe0 */
        EXYNOS4X12_GPIO_M11,
        EXYNOS4X12_GPIO_M12,
        EXYNOS4X12_GPIO_M13,
@@ -568,7 +568,7 @@ enum exynos4X12_gpio_pin {
        EXYNOS4X12_GPIO_M15,
        EXYNOS4X12_GPIO_M16,
        EXYNOS4X12_GPIO_M17,
-       EXYNOS4X12_GPIO_M20,            /* 328 0x100 */
+       EXYNOS4X12_GPIO_M20,            /* 232 0xe8 */
        EXYNOS4X12_GPIO_M21,
        EXYNOS4X12_GPIO_M22,
        EXYNOS4X12_GPIO_M23,
@@ -576,7 +576,7 @@ enum exynos4X12_gpio_pin {
        EXYNOS4X12_GPIO_M25,
        EXYNOS4X12_GPIO_M26,
        EXYNOS4X12_GPIO_M27,
-       EXYNOS4X12_GPIO_M30,            /* 336 0x108 */
+       EXYNOS4X12_GPIO_M30,            /* 240 0xf0 */
        EXYNOS4X12_GPIO_M31,
        EXYNOS4X12_GPIO_M32,
        EXYNOS4X12_GPIO_M33,
@@ -584,7 +584,7 @@ enum exynos4X12_gpio_pin {
        EXYNOS4X12_GPIO_M35,
        EXYNOS4X12_GPIO_M36,
        EXYNOS4X12_GPIO_M37,
-       EXYNOS4X12_GPIO_M40,            /* 344 0x110 */
+       EXYNOS4X12_GPIO_M40,            /* 248 0xf8 */
        EXYNOS4X12_GPIO_M41,
        EXYNOS4X12_GPIO_M42,
        EXYNOS4X12_GPIO_M43,
@@ -592,7 +592,7 @@ enum exynos4X12_gpio_pin {
        EXYNOS4X12_GPIO_M45,
        EXYNOS4X12_GPIO_M46,
        EXYNOS4X12_GPIO_M47,
-       EXYNOS4X12_GPIO_X00 = 928,      /* 928 0x3A0 */
+       EXYNOS4X12_GPIO_X00,            /* 256 0x100 */
        EXYNOS4X12_GPIO_X01,
        EXYNOS4X12_GPIO_X02,
        EXYNOS4X12_GPIO_X03,
@@ -600,7 +600,7 @@ enum exynos4X12_gpio_pin {
        EXYNOS4X12_GPIO_X05,
        EXYNOS4X12_GPIO_X06,
        EXYNOS4X12_GPIO_X07,
-       EXYNOS4X12_GPIO_X10,            /* 936 0x3A8 */
+       EXYNOS4X12_GPIO_X10,            /* 264 0x108 */
        EXYNOS4X12_GPIO_X11,
        EXYNOS4X12_GPIO_X12,
        EXYNOS4X12_GPIO_X13,
@@ -608,7 +608,7 @@ enum exynos4X12_gpio_pin {
        EXYNOS4X12_GPIO_X15,
        EXYNOS4X12_GPIO_X16,
        EXYNOS4X12_GPIO_X17,
-       EXYNOS4X12_GPIO_X20,            /* 944 0x3B0 */
+       EXYNOS4X12_GPIO_X20,            /* 272 0x110 */
        EXYNOS4X12_GPIO_X21,
        EXYNOS4X12_GPIO_X22,
        EXYNOS4X12_GPIO_X23,
@@ -616,7 +616,7 @@ enum exynos4X12_gpio_pin {
        EXYNOS4X12_GPIO_X25,
        EXYNOS4X12_GPIO_X26,
        EXYNOS4X12_GPIO_X27,
-       EXYNOS4X12_GPIO_X30,            /* 952 0x3B8 */
+       EXYNOS4X12_GPIO_X30,            /* 280 0x118 */
        EXYNOS4X12_GPIO_X31,
        EXYNOS4X12_GPIO_X32,
        EXYNOS4X12_GPIO_X33,
@@ -626,7 +626,7 @@ enum exynos4X12_gpio_pin {
        EXYNOS4X12_GPIO_X37,
 
        /* GPIO_PART3_STARTS */
-       EXYNOS4X12_GPIO_MAX_PORT_PART_2,/* 960 0x3C0 */
+       EXYNOS4X12_GPIO_MAX_PORT_PART_2,/* 288 0x120 */
        EXYNOS4X12_GPIO_Z0 = EXYNOS4X12_GPIO_MAX_PORT_PART_2,
        EXYNOS4X12_GPIO_Z1,
        EXYNOS4X12_GPIO_Z2,
@@ -637,7 +637,7 @@ enum exynos4X12_gpio_pin {
        EXYNOS4X12_GPIO_Z7,
 
        /* GPIO_PART4_STARTS */
-       EXYNOS4X12_GPIO_MAX_PORT_PART_3,/* 968 0x3C8 */
+       EXYNOS4X12_GPIO_MAX_PORT_PART_3,/* 296 0x128 */
        EXYNOS4X12_GPIO_V00 = EXYNOS4X12_GPIO_MAX_PORT_PART_3,
        EXYNOS4X12_GPIO_V01,
        EXYNOS4X12_GPIO_V02,
@@ -646,7 +646,7 @@ enum exynos4X12_gpio_pin {
        EXYNOS4X12_GPIO_V05,
        EXYNOS4X12_GPIO_V06,
        EXYNOS4X12_GPIO_V07,
-       EXYNOS4X12_GPIO_V10,            /* 976 0x3D0 */
+       EXYNOS4X12_GPIO_V10,            /* 304 0x130 */
        EXYNOS4X12_GPIO_V11,
        EXYNOS4X12_GPIO_V12,
        EXYNOS4X12_GPIO_V13,
@@ -654,7 +654,7 @@ enum exynos4X12_gpio_pin {
        EXYNOS4X12_GPIO_V15,
        EXYNOS4X12_GPIO_V16,
        EXYNOS4X12_GPIO_V17,
-       EXYNOS4X12_GPIO_V20 = 992,      /* 992 0x3E0 */
+       EXYNOS4X12_GPIO_V20,            /* 312 0x138 */
        EXYNOS4X12_GPIO_V21,
        EXYNOS4X12_GPIO_V22,
        EXYNOS4X12_GPIO_V23,
@@ -662,7 +662,7 @@ enum exynos4X12_gpio_pin {
        EXYNOS4X12_GPIO_V25,
        EXYNOS4X12_GPIO_V26,
        EXYNOS4X12_GPIO_V27,
-       EXYNOS4X12_GPIO_V30 = 1000,     /* 1000 0x3E8 */
+       EXYNOS4X12_GPIO_V30,            /* 320 0x140 */
        EXYNOS4X12_GPIO_V31,
        EXYNOS4X12_GPIO_V32,
        EXYNOS4X12_GPIO_V33,
@@ -670,7 +670,7 @@ enum exynos4X12_gpio_pin {
        EXYNOS4X12_GPIO_V35,
        EXYNOS4X12_GPIO_V36,
        EXYNOS4X12_GPIO_V37,
-       EXYNOS4X12_GPIO_V40 = 1016,     /* 1016 0x3F8 */
+       EXYNOS4X12_GPIO_V40,            /* 328 0x148 */
        EXYNOS4X12_GPIO_V41,
        EXYNOS4X12_GPIO_V42,
        EXYNOS4X12_GPIO_V43,
@@ -1504,12 +1504,7 @@ static const struct gpio_name_num_table exynos5420_gpio_table[] = {
 void gpio_cfg_pin(int gpio, int cfg);
 void gpio_set_pull(int gpio, int mode);
 void gpio_set_drv(int gpio, int mode);
-int gpio_direction_input(unsigned gpio);
-int gpio_direction_output(unsigned gpio, int value);
-int gpio_set_value(unsigned gpio, int value);
-int gpio_get_value(unsigned gpio);
 void gpio_set_rate(int gpio, int mode);
-struct s5p_gpio_bank *s5p_gpio_get_bank(unsigned gpio);
 int s5p_gpio_get_pin(unsigned gpio);
 #endif
 
index d5dbc22c18d0b1717ecba69fddd1df892fcb0aaf..2de205e74b635ba320b02a2fed8994e814b01d42 100644 (file)
@@ -682,8 +682,7 @@ enum s5pc110_gpio_pin {
        S5PC110_GPIO_MP285,
        S5PC110_GPIO_MP286,
        S5PC110_GPIO_MP287,
-       S5PC110_GPIO_RES,
-       S5PC110_GPIO_H00 = (S5PC110_GPIO_RES + (48 * 8)),
+       S5PC110_GPIO_H00,
        S5PC110_GPIO_H01,
        S5PC110_GPIO_H02,
        S5PC110_GPIO_H03,
@@ -815,11 +814,7 @@ static const struct gpio_name_num_table s5pc110_gpio_table[] = {
 void gpio_cfg_pin(int gpio, int cfg);
 void gpio_set_pull(int gpio, int mode);
 void gpio_set_drv(int gpio, int mode);
-int gpio_direction_output(unsigned gpio, int value);
-int gpio_set_value(unsigned gpio, int value);
-int gpio_get_value(unsigned gpio);
 void gpio_set_rate(int gpio, int mode);
-struct s5p_gpio_bank *s5p_gpio_get_bank(unsigned gpio);
 int s5p_gpio_get_pin(unsigned gpio);
 
 /* GPIO pins per bank  */
diff --git a/arch/arm/include/asm/arch-tegra114/tegra114_spi.h b/arch/arm/include/asm/arch-tegra114/tegra114_spi.h
deleted file mode 100644 (file)
index 48197bc..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * NVIDIA Tegra SPI controller
- *
- * Copyright 2010-2013 NVIDIA Corporation
- *
- * This software may be used and distributed according to the
- * terms of the GNU Public License, Version 2, incorporated
- * herein by reference.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * Version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
-
-#ifndef _TEGRA114_SPI_H_
-#define _TEGRA114_SPI_H_
-
-#include <asm/types.h>
-
-int tegra114_spi_init(int *node_list, int count);
-int tegra114_spi_cs_is_valid(unsigned int bus, unsigned int cs);
-struct spi_slave *tegra114_spi_setup_slave(unsigned int bus, unsigned int cs,
-                                 unsigned int max_hz, unsigned int mode);
-void tegra114_spi_free_slave(struct spi_slave *slave);
-int tegra114_spi_claim_bus(struct spi_slave *slave);
-void tegra114_spi_cs_activate(struct spi_slave *slave);
-void tegra114_spi_cs_deactivate(struct spi_slave *slave);
-int tegra114_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
-                    const void *data_out, void *data_in, unsigned long flags);
-
-#endif /* _TEGRA114_SPI_H_ */
diff --git a/arch/arm/include/asm/arch-tegra20/tegra20_sflash.h b/arch/arm/include/asm/arch-tegra20/tegra20_sflash.h
deleted file mode 100644 (file)
index e8cc68c..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * NVIDIA Tegra20 SPI-FLASH controller
- *
- * Copyright 2010-2012 NVIDIA Corporation
- *
- * This software may be used and distributed according to the
- * terms of the GNU Public License, Version 2, incorporated
- * herein by reference.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * Version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
-
-#ifndef _TEGRA20_SPI_H_
-#define _TEGRA20_SPI_H_
-
-#include <asm/types.h>
-
-int tegra20_spi_cs_is_valid(unsigned int bus, unsigned int cs);
-struct spi_slave *tegra20_spi_setup_slave(unsigned int bus, unsigned int cs,
-                                 unsigned int max_hz, unsigned int mode);
-void tegra20_spi_free_slave(struct spi_slave *slave);
-int tegra20_spi_init(int *node_list, int count);
-int tegra20_spi_claim_bus(struct spi_slave *slave);
-void tegra20_spi_cs_activate(struct spi_slave *slave);
-void tegra20_spi_cs_deactivate(struct spi_slave *slave);
-int tegra20_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
-            const void *data_out, void *data_in, unsigned long flags);
-
-#endif /* _TEGRA20_SPI_H_ */
diff --git a/arch/arm/include/asm/arch-tegra20/tegra20_slink.h b/arch/arm/include/asm/arch-tegra20/tegra20_slink.h
deleted file mode 100644 (file)
index 5aa74dd..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * NVIDIA Tegra SPI-SLINK controller
- *
- * Copyright 2010-2013 NVIDIA Corporation
- *
- * This software may be used and distributed according to the
- * terms of the GNU Public License, Version 2, incorporated
- * herein by reference.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * Version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
-
-#ifndef _TEGRA30_SPI_H_
-#define _TEGRA30_SPI_H_
-
-#include <asm/types.h>
-
-int tegra30_spi_init(int *node_list, int count);
-int tegra30_spi_cs_is_valid(unsigned int bus, unsigned int cs);
-struct spi_slave *tegra30_spi_setup_slave(unsigned int bus, unsigned int cs,
-                                 unsigned int max_hz, unsigned int mode);
-void tegra30_spi_free_slave(struct spi_slave *slave);
-int tegra30_spi_claim_bus(struct spi_slave *slave);
-void tegra30_spi_cs_activate(struct spi_slave *slave);
-void tegra30_spi_cs_deactivate(struct spi_slave *slave);
-int tegra30_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
-                    const void *data_out, void *data_in, unsigned long flags);
-
-#endif /* _TEGRA30_SPI_H_ */
index 182c2f397f1748d0f574a4ffaa9a31335475fba5..af861635350d00209405435084ef767bec5b77e6 100644 (file)
@@ -52,8 +52,8 @@ struct i2c_pads_info {
                                        &mx6q_##name : &mx6s_##name
 #endif
 
-void setup_i2c(unsigned i2c_index, int speed, int slave_addr,
-               struct i2c_pads_info *p);
+int setup_i2c(unsigned i2c_index, int speed, int slave_addr,
+             struct i2c_pads_info *p);
 void bus_i2c_init(void *base, int speed, int slave_addr,
                int (*idle_bus_fn)(void *p), void *p);
 int bus_i2c_read(void *base, uchar chip, uint addr, int alen, uchar *buf,
index 797478a2c7f661294bb462d56d71048459652cd7..76147154c22366b7f70e5a95e83c8ea8ee3dfbe1 100644 (file)
@@ -1,6 +1,9 @@
 /dts-v1/;
 
 / {
+       #address-cells = <1>;
+       #size-cells = <0>;
+
        chosen {
                stdout-path = "/serial";
        };
                num-gpios = <20>;
        };
 
+       spi@0 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               reg = <0>;
+               compatible = "sandbox,spi";
+               cs-gpios = <0>, <&gpio_a 0>;
+               flash@0 {
+                       reg = <0>;
+                       compatible = "spansion,m25p16", "sandbox,spi-flash";
+                       spi-max-frequency = <40000000>;
+                       sandbox,filename = "spi.bin";
+               };
+       };
+
+       cros-ec@0 {
+               compatible = "google,cros-ec";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               firmware_storage_spi: flash@0 {
+                       reg = <0 0x400000>;
+               };
+       };
+
 };
index 49b4a0f103a166ad02a0e5a316704aefb96ce8ca..9985e3c494922985d5f4f9538c9212dcb62e8bbf 100644 (file)
@@ -32,19 +32,6 @@ struct sandbox_spi_emu_ops {
        int (*xfer)(void *priv, const u8 *rx, u8 *tx, uint bytes);
 };
 
-/*
- * There are times when the data lines are allowed to tristate.  What
- * is actually sensed on the line depends on the hardware.  It could
- * always be 0xFF/0x00 (if there are pull ups/downs), or things could
- * float and so we'd get garbage back.  This func encapsulates that
- * scenario so we can worry about the details here.
- */
-static inline void sandbox_spi_tristate(u8 *buf, uint len)
-{
-       /* XXX: make this into a user config option ? */
-       memset(buf, 0xff, len);
-}
-
 /*
  * Extract the bus/cs from the spi spec and return the start of the spi
  * client spec.  If the bus/cs are invalid for the current config, then
index d17a82e90fcaab037057531ffef881e41b85525b..32d55ccc4c241deacdcf394daac81859d234657d 100644 (file)
@@ -42,7 +42,7 @@ enum state_terminal_raw {
 
 struct sandbox_spi_info {
        const char *spec;
-       const struct sandbox_spi_emu_ops *ops;
+       struct udevice *emul;
 };
 
 /* The complete state of the test system */
index 415bc2498935222afea91cbaee0e51011d69346f..e7bb3e33d5bdd999f246e56e02a2a06775553035 100644 (file)
@@ -9,5 +9,5 @@
 #
 
 extra-y        = start.o
-extra-$(CONFIG_X86_RESET_VECTOR) += resetvec.o start16.o
-obj-y  = interrupts.o cpu.o
+obj-$(CONFIG_X86_RESET_VECTOR) += resetvec.o start16.o
+obj-y  += interrupts.o cpu.o
index 8b9b327cd48734fbd50b71dbe3d6a238151d7074..6968fda6494998d1d595c9862e64a10a8082a3e1 100644 (file)
@@ -70,7 +70,7 @@ idt_ptr:
  * GDT is setup in a safe location in RAM
  */
 gdt_ptr:
-       .word   0x20            /* limit (32 bytes = 4 GDT entries) */
+       .word   0x1f            /* limit (31 bytes = 4 GDT entries - 1) */
        .long   BOOT_SEG + gdt  /* base */
 
 /* Some CPUs are picky about GDT alignment... */
diff --git a/arch/x86/include/asm/bootm.h b/arch/x86/include/asm/bootm.h
new file mode 100644 (file)
index 0000000..033ab79
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2013, Google Inc.
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef ARM_BOOTM_H
+#define ARM_BOOTM_H
+
+void bootm_announce_and_cleanup(void);
+
+#endif
index f06a15cdfca06c76f87e2d2209077856286cea7d..ff15828a713de5d1258aada2dc5aa599734ca900 100644 (file)
@@ -8,4 +8,7 @@
 #define _ASM_CONFIG_H_
 
 #define CONFIG_SYS_GENERIC_BOARD
+#define CONFIG_LMB
+#define CONFIG_SYS_BOOT_RAMDISK_HIGH
+
 #endif
index ff158dd6a9d940c823bfc59059ce6151bc60d675..4c5c7f5aa796bc679cf2bb91f6f16f64de128098 100644 (file)
 
 #include <common.h>
 #include <command.h>
+#include <fdt_support.h>
 #include <image.h>
 #include <u-boot/zlib.h>
 #include <asm/bootparam.h>
 #include <asm/byteorder.h>
 #include <asm/zimage.h>
+#ifdef CONFIG_SYS_COREBOOT
+#include <asm/arch/timestamp.h>
+#endif
 
 #define COMMAND_LINE_OFFSET 0x9000
 
-/*cmd_boot.c*/
-int do_bootm_linux(int flag, int argc, char * const argv[],
-               bootm_headers_t *images)
+/*
+ * Implement a weak default function for boards that optionally
+ * need to clean up the system before jumping to the kernel.
+ */
+__weak void board_final_cleanup(void)
 {
-       struct boot_params *base_ptr = NULL;
-       ulong os_data, os_len;
-       image_header_t *hdr;
-       void *load_address;
+}
 
-#if defined(CONFIG_FIT)
-       const void      *data;
-       size_t          len;
+void bootm_announce_and_cleanup(void)
+{
+       printf("\nStarting kernel ...\n\n");
+
+#ifdef CONFIG_SYS_COREBOOT
+       timestamp_add_now(TS_U_BOOT_START_KERNEL);
+#endif
+       bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel");
+#ifdef CONFIG_BOOTSTAGE_REPORT
+       bootstage_report();
 #endif
+       board_final_cleanup();
+}
 
-       if (flag & BOOTM_STATE_OS_PREP)
-               return 0;
-       if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
-               return 1;
+#if defined(CONFIG_OF_LIBFDT) && !defined(CONFIG_OF_NO_KERNEL)
+int arch_fixup_memory_node(void *blob)
+{
+       bd_t    *bd = gd->bd;
+       int bank;
+       u64 start[CONFIG_NR_DRAM_BANKS];
+       u64 size[CONFIG_NR_DRAM_BANKS];
+
+       for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) {
+               start[bank] = bd->bi_dram[bank].start;
+               size[bank] = bd->bi_dram[bank].size;
+       }
+
+       return fdt_fixup_memory_banks(blob, start, size, CONFIG_NR_DRAM_BANKS);
+}
+#endif
 
+/* Subcommand: PREP */
+static int boot_prep_linux(bootm_headers_t *images)
+{
+       char *cmd_line_dest = NULL;
+       image_header_t *hdr;
+       int is_zimage = 0;
+       void *data = NULL;
+       size_t len;
+       int ret;
+
+#ifdef CONFIG_OF_LIBFDT
+       if (images->ft_len) {
+               debug("using: FDT\n");
+               if (image_setup_linux(images)) {
+                       puts("FDT creation failed! hanging...");
+                       hang();
+               }
+       }
+#endif
        if (images->legacy_hdr_valid) {
                hdr = images->legacy_hdr_os;
                if (image_check_type(hdr, IH_TYPE_MULTI)) {
+                       ulong os_data, os_len;
+
                        /* if multi-part image, we need to get first subimage */
                        image_multi_getimg(hdr, 0, &os_data, &os_len);
+                       data = (void *)os_data;
+                       len = os_len;
                } else {
                        /* otherwise get image data */
-                       os_data = image_get_data(hdr);
-                       os_len = image_get_data_size(hdr);
+                       data = (void *)image_get_data(hdr);
+                       len = image_get_data_size(hdr);
                }
+               is_zimage = 1;
 #if defined(CONFIG_FIT)
-       } else if (images->fit_uname_os) {
-               int ret;
-
+       } else if (images->fit_uname_os && is_zimage) {
                ret = fit_image_get_data(images->fit_hdr_os,
-                                       images->fit_noffset_os, &data, &len);
+                               images->fit_noffset_os,
+                               (const void **)&data, &len);
                if (ret) {
                        puts("Can't get image data/size!\n");
                        goto error;
                }
-               os_data = (ulong)data;
-               os_len = (ulong)len;
+               is_zimage = 1;
 #endif
-       } else {
-               puts("Could not find kernel image!\n");
-               goto error;
        }
 
-#ifdef CONFIG_CMD_ZBOOT
-       base_ptr = load_zimage((void *)os_data, os_len, &load_address);
-#endif
+       if (is_zimage) {
+               void *load_address;
+               char *base_ptr;
 
-       if (NULL == base_ptr) {
-               printf("## Kernel loading failed ...\n");
+               base_ptr = (char *)load_zimage(data, len, &load_address);
+               images->os.load = (ulong)load_address;
+               cmd_line_dest = base_ptr + COMMAND_LINE_OFFSET;
+               images->ep = (ulong)base_ptr;
+       } else if (images->ep) {
+               cmd_line_dest = (void *)images->ep + COMMAND_LINE_OFFSET;
+       } else {
+               printf("## Kernel loading failed (no setup) ...\n");
                goto error;
        }
 
-       if (setup_zimage(base_ptr, (char *)base_ptr + COMMAND_LINE_OFFSET,
+       printf("Setup at %#08lx\n", images->ep);
+       ret = setup_zimage((void *)images->ep, cmd_line_dest,
                        0, images->rd_start,
-                       images->rd_end - images->rd_start)) {
+                       images->rd_end - images->rd_start);
+
+       if (ret) {
                printf("## Setting up boot parameters failed ...\n");
-               goto error;
+               return 1;
        }
 
-       boot_zimage(base_ptr, load_address);
-       /* does not return */
+       return 0;
 
 error:
        return 1;
 }
+
+/* Subcommand: GO */
+static int boot_jump_linux(bootm_headers_t *images)
+{
+       debug("## Transferring control to Linux (at address %08lx, kernel %08lx) ...\n",
+             images->ep, images->os.load);
+
+       boot_zimage((struct boot_params *)images->ep, (void *)images->os.load);
+       /* does not return */
+
+       return 1;
+}
+
+int do_bootm_linux(int flag, int argc, char * const argv[],
+               bootm_headers_t *images)
+{
+       /* No need for those on x86 */
+       if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE)
+               return -1;
+
+       if (flag & BOOTM_STATE_OS_PREP)
+               return boot_prep_linux(images);
+
+       if (flag & BOOTM_STATE_OS_GO) {
+               boot_jump_linux(images);
+               return 0;
+       }
+
+       return boot_jump_linux(images);
+}
index 1dab3cc78878dcea322d1685f0df0ed388f7a70c..2f0e92f123a5acaa06a6c2f031cec72766d06099 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/ptrace.h>
 #include <asm/zimage.h>
 #include <asm/byteorder.h>
+#include <asm/bootm.h>
 #include <asm/bootparam.h>
 #ifdef CONFIG_SYS_COREBOOT
 #include <asm/arch/timestamp.h>
@@ -242,41 +243,27 @@ int setup_zimage(struct boot_params *setup_base, char *cmd_line, int auto_boot,
                hdr->loadflags |= HEAP_FLAG;
        }
 
-       if (bootproto >= 0x0202) {
-               hdr->cmd_line_ptr = (uintptr_t)cmd_line;
-       } else if (bootproto >= 0x0200) {
-               setup_base->screen_info.cl_magic = COMMAND_LINE_MAGIC;
-               setup_base->screen_info.cl_offset =
-                       (uintptr_t)cmd_line - (uintptr_t)setup_base;
+       if (cmd_line) {
+               if (bootproto >= 0x0202) {
+                       hdr->cmd_line_ptr = (uintptr_t)cmd_line;
+               } else if (bootproto >= 0x0200) {
+                       setup_base->screen_info.cl_magic = COMMAND_LINE_MAGIC;
+                       setup_base->screen_info.cl_offset =
+                               (uintptr_t)cmd_line - (uintptr_t)setup_base;
+
+                       hdr->setup_move_size = 0x9100;
+               }
 
-               hdr->setup_move_size = 0x9100;
+               /* build command line at COMMAND_LINE_OFFSET */
+               build_command_line(cmd_line, auto_boot);
        }
 
-       /* build command line at COMMAND_LINE_OFFSET */
-       build_command_line(cmd_line, auto_boot);
        return 0;
 }
 
-/*
- * Implement a weak default function for boards that optionally
- * need to clean up the system before jumping to the kernel.
- */
-__weak void board_final_cleanup(void)
-{
-}
-
 void boot_zimage(void *setup_base, void *load_address)
 {
-       debug("## Transferring control to Linux (at address %08x) ...\n",
-             (u32)setup_base);
-
-       bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel");
-#ifdef CONFIG_BOOTSTAGE_REPORT
-       bootstage_report();
-#endif
-       board_final_cleanup();
-
-       printf("\nStarting kernel ...\n\n");
+       bootm_announce_and_cleanup();
 
 #ifdef CONFIG_SYS_COREBOOT
        timestamp_add_now(TS_U_BOOT_START_KERNEL);
index 659a124b22750fda1fb4b02df5d74defaf4012e6..c1cb07b27829a270cfb40a7e64cbcd03de3b3c47 100644 (file)
 #include <malloc.h>
 #include <netdev.h>
 #include <miiphy.h>
+#include <spi.h>
+#include <spi_flash.h>
 #include <asm/arch/kirkwood.h>
 #include <asm/arch/cpu.h>
 #include <asm/arch/mpp.h>
 #include <asm/arch/gpio.h>
-#include <spi_flash.h>
 
 #include "lsxl.h"
 
index fdb8ebf9e75567c41965d4018b306f2266ffc5e8..f77ff48a1c3fb69f7bc04ec22f8cf95ac291122b 100644 (file)
@@ -9,11 +9,13 @@
  */
 
 #include <common.h>
+#include <dm.h>
 #include <fsl_esdhc.h>
 #include <miiphy.h>
 #include <netdev.h>
 #include <fdt_support.h>
 #include <sata.h>
+#include <serial_mxc.h>
 #include <asm/arch/crm_regs.h>
 #include <asm/arch/sys_proto.h>
 #include <asm/arch/iomux.h>
@@ -69,16 +71,23 @@ static iomux_v3_cfg_t const sata_pads[] = {
        IOMUX_PADS(PAD_EIM_BCLK__GPIO6_IO31   | MUX_PAD_CTRL(NO_PAD_CTRL)),
 };
 
-static void cm_fx6_setup_issd(void)
+static int cm_fx6_setup_issd(void)
 {
+       int ret, i;
+
        SETUP_IOMUX_PADS(sata_pads);
-       /* Make sure this gpio has logical 0 value */
-       gpio_direction_output(CM_FX6_SATA_PWLOSS_INT, 0);
-       udelay(100);
 
-       cm_fx6_sata_power(0);
-       mdelay(250);
-       cm_fx6_sata_power(1);
+       for (i = 0; i < ARRAY_SIZE(cm_fx6_issd_gpios); i++) {
+               ret = gpio_request(cm_fx6_issd_gpios[i], "sata");
+               if (ret)
+                       return ret;
+       }
+
+       ret = gpio_request(CM_FX6_SATA_PWLOSS_INT, "sata_pwloss_int");
+       if (ret)
+               return ret;
+
+       return 0;
 }
 
 #define CM_FX6_SATA_INIT_RETRIES       10
@@ -86,7 +95,14 @@ int sata_initialize(void)
 {
        int err, i;
 
-       cm_fx6_setup_issd();
+       /* Make sure this gpio has logical 0 value */
+       gpio_direction_output(CM_FX6_SATA_PWLOSS_INT, 0);
+       udelay(100);
+
+       cm_fx6_sata_power(0);
+       mdelay(250);
+       cm_fx6_sata_power(1);
+
        for (i = 0; i < CM_FX6_SATA_INIT_RETRIES; i++) {
                err = setup_sata();
                if (err) {
@@ -109,6 +125,8 @@ int sata_initialize(void)
 
        return err;
 }
+#else
+static int cm_fx6_setup_issd(void) { return 0; }
 #endif
 
 #ifdef CONFIG_SYS_I2C_MXC
@@ -141,49 +159,68 @@ I2C_PADS(i2c2_pads,
         IMX_GPIO_NR(1, 6));
 
 
-static void cm_fx6_setup_i2c(void)
+static int cm_fx6_setup_one_i2c(int busnum, struct i2c_pads_info *pads)
+{
+       int ret;
+
+       ret = setup_i2c(busnum, CONFIG_SYS_I2C_SPEED, 0x7f, pads);
+       if (ret)
+               printf("Warning: I2C%d setup failed: %d\n", busnum, ret);
+
+       return ret;
+}
+
+static int cm_fx6_setup_i2c(void)
 {
-       setup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x7f, I2C_PADS_INFO(i2c0_pads));
-       setup_i2c(1, CONFIG_SYS_I2C_SPEED, 0x7f, I2C_PADS_INFO(i2c1_pads));
-       setup_i2c(2, CONFIG_SYS_I2C_SPEED, 0x7f, I2C_PADS_INFO(i2c2_pads));
+       int ret = 0, err;
+
+       /* i2c<x>_pads are wierd macro variables; we can't use an array */
+       err = cm_fx6_setup_one_i2c(0, I2C_PADS_INFO(i2c0_pads));
+       if (err)
+               ret = err;
+       err = cm_fx6_setup_one_i2c(1, I2C_PADS_INFO(i2c1_pads));
+       if (err)
+               ret = err;
+       err = cm_fx6_setup_one_i2c(2, I2C_PADS_INFO(i2c2_pads));
+       if (err)
+               ret = err;
+
+       return ret;
 }
 #else
-static void cm_fx6_setup_i2c(void) { }
+static int cm_fx6_setup_i2c(void) { return 0; }
 #endif
 
 #ifdef CONFIG_USB_EHCI_MX6
 #define WEAK_PULLDOWN  (PAD_CTL_PUS_100K_DOWN |                \
                        PAD_CTL_SPEED_MED | PAD_CTL_DSE_40ohm | \
                        PAD_CTL_HYS | PAD_CTL_SRE_SLOW)
+#define MX6_USBNC_BASEADDR     0x2184800
+#define USBNC_USB_H1_PWR_POL   (1 << 9)
 
-static int cm_fx6_usb_hub_reset(void)
+static int cm_fx6_setup_usb_host(void)
 {
        int err;
 
        err = gpio_request(CM_FX6_USB_HUB_RST, "usb hub rst");
-       if (err) {
-               printf("USB hub rst gpio request failed: %d\n", err);
-               return -1;
-       }
+       if (err)
+               return err;
 
+       SETUP_IOMUX_PAD(PAD_GPIO_0__USB_H1_PWR | MUX_PAD_CTRL(NO_PAD_CTRL));
        SETUP_IOMUX_PAD(PAD_SD3_RST__GPIO7_IO08 | MUX_PAD_CTRL(NO_PAD_CTRL));
-       gpio_direction_output(CM_FX6_USB_HUB_RST, 0);
-       udelay(10);
-       gpio_direction_output(CM_FX6_USB_HUB_RST, 1);
-       mdelay(1);
 
        return 0;
 }
 
-static int cm_fx6_init_usb_otg(void)
+static int cm_fx6_setup_usb_otg(void)
 {
-       int ret;
+       int err;
        struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR;
 
-       ret = gpio_request(SB_FX6_USB_OTG_PWR, "usb-pwr");
-       if (ret) {
-               printf("USB OTG pwr gpio request failed: %d\n", ret);
-               return ret;
+       err = gpio_request(SB_FX6_USB_OTG_PWR, "usb-pwr");
+       if (err) {
+               printf("USB OTG pwr gpio request failed: %d\n", err);
+               return err;
        }
 
        SETUP_IOMUX_PAD(PAD_EIM_D22__GPIO3_IO22 | MUX_PAD_CTRL(NO_PAD_CTRL));
@@ -194,25 +231,27 @@ static int cm_fx6_init_usb_otg(void)
        return gpio_direction_output(SB_FX6_USB_OTG_PWR, 0);
 }
 
-#define MX6_USBNC_BASEADDR     0x2184800
-#define USBNC_USB_H1_PWR_POL   (1 << 9)
 int board_ehci_hcd_init(int port)
 {
+       int ret;
        u32 *usbnc_usb_uh1_ctrl = (u32 *)(MX6_USBNC_BASEADDR + 4);
 
-       switch (port) {
-       case 0:
-               return cm_fx6_init_usb_otg();
-       case 1:
-               SETUP_IOMUX_PAD(PAD_GPIO_0__USB_H1_PWR |
-                               MUX_PAD_CTRL(NO_PAD_CTRL));
+       /* Only 1 host controller in use. port 0 is OTG & needs no attention */
+       if (port != 1)
+               return 0;
 
-               /* Set PWR polarity to match power switch's enable polarity */
-               setbits_le32(usbnc_usb_uh1_ctrl, USBNC_USB_H1_PWR_POL);
-               return cm_fx6_usb_hub_reset();
-       default:
-               break;
-       }
+       /* Set PWR polarity to match power switch's enable polarity */
+       setbits_le32(usbnc_usb_uh1_ctrl, USBNC_USB_H1_PWR_POL);
+       ret = gpio_direction_output(CM_FX6_USB_HUB_RST, 0);
+       if (ret)
+               return ret;
+
+       udelay(10);
+       ret = gpio_direction_output(CM_FX6_USB_HUB_RST, 1);
+       if (ret)
+               return ret;
+
+       mdelay(1);
 
        return 0;
 }
@@ -224,6 +263,9 @@ int board_ehci_power(int port, int on)
 
        return 0;
 }
+#else
+static int cm_fx6_setup_usb_otg(void) { return 0; }
+static int cm_fx6_setup_usb_host(void) { return 0; }
 #endif
 
 #ifdef CONFIG_FEC_MXC
@@ -318,12 +360,17 @@ static int handle_mac_address(void)
 
 int board_eth_init(bd_t *bis)
 {
-       int res = handle_mac_address();
-       if (res)
+       int err;
+
+       err = handle_mac_address();
+       if (err)
                puts("No MAC address found\n");
 
        SETUP_IOMUX_PADS(enet_pads);
        /* phy reset */
+       err = gpio_request(CM_FX6_ENET_NRST, "enet_nrst");
+       if (err)
+               printf("Etnernet NRST gpio request failed: %d\n", err);
        gpio_direction_output(CM_FX6_ENET_NRST, 0);
        udelay(500);
        gpio_set_value(CM_FX6_ENET_NRST, 1);
@@ -394,6 +441,16 @@ int board_mmc_init(bd_t *bis)
 }
 #endif
 
+#ifdef CONFIG_MXC_SPI
+int cm_fx6_setup_ecspi(void)
+{
+       cm_fx6_set_ecspi_iomux();
+       return gpio_request(CM_FX6_ECSPI_BUS0_CS0, "ecspi_bus0_cs0");
+}
+#else
+int cm_fx6_setup_ecspi(void) { return 0; }
+#endif
+
 #ifdef CONFIG_OF_BOARD_SETUP
 void ft_board_setup(void *blob, bd_t *bd)
 {
@@ -409,9 +466,37 @@ void ft_board_setup(void *blob, bd_t *bd)
 
 int board_init(void)
 {
+       int ret;
+
        gd->bd->bi_boot_params = PHYS_SDRAM_1 + 0x100;
        cm_fx6_setup_gpmi_nand();
-       cm_fx6_setup_i2c();
+
+       ret = cm_fx6_setup_ecspi();
+       if (ret)
+               printf("Warning: ECSPI setup failed: %d\n", ret);
+
+       ret = cm_fx6_setup_usb_otg();
+       if (ret)
+               printf("Warning: USB OTG setup failed: %d\n", ret);
+
+       ret = cm_fx6_setup_usb_host();
+       if (ret)
+               printf("Warning: USB host setup failed: %d\n", ret);
+
+       /*
+        * cm-fx6 may have iSSD not assembled and in this case it has
+        * bypasses for a (m)SATA socket on the baseboard. The socketed
+        * device is not controlled by those GPIOs. So just print a warning
+        * if the setup fails.
+        */
+       ret = cm_fx6_setup_issd();
+       if (ret)
+               printf("Warning: iSSD setup failed: %d\n", ret);
+
+       /* Warn on failure but do not abort boot */
+       ret = cm_fx6_setup_i2c();
+       if (ret)
+               printf("Warning: I2C setup failed: %d\n", ret);
 
        return 0;
 }
@@ -481,3 +566,11 @@ u32 get_board_rev(void)
        return cl_eeprom_get_board_rev();
 }
 
+static struct mxc_serial_platdata cm_fx6_mxc_serial_plat = {
+       .reg = (struct mxc_uart *)UART4_BASE,
+};
+
+U_BOOT_DEVICE(cm_fx6_serial) = {
+       .name   = "serial_mxc",
+       .platdata = &cm_fx6_mxc_serial_plat,
+};
index d01abcee13c14121dfd8db0eeea8f21440b36363..03f055dad2aa4d2ff72b26f36b5a23e01849d6a6 100644 (file)
@@ -114,9 +114,8 @@ int board_init(void)
        clock_init();
        clock_verify();
 
-#ifdef CONFIG_FDT_SPI
+#ifdef CONFIG_TEGRA_SPI
        pin_mux_spi();
-       spi_init();
 #endif
 
 #ifdef CONFIG_PWM_TEGRA
index 220bb90dc1ae025ddf37e8fe9636201843c00650..447c940f63154aa560881046a1d742b6bc1e7d5e 100644 (file)
 
 #include <common.h>
 #include <config.h>
+#include <dm.h>
 #include <fdt_support.h>
 #include <lcd.h>
 #include <mmc.h>
+#include <asm/gpio.h>
 #include <asm/arch/mbox.h>
 #include <asm/arch/sdhci.h>
 #include <asm/global_data.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
+static const struct bcm2835_gpio_platdata gpio_platdata = {
+       .base = BCM2835_GPIO_BASE,
+};
+
+U_BOOT_DEVICE(bcm2835_gpios) = {
+       .name = "gpio_bcm2835",
+       .platdata = &gpio_platdata,
+};
+
 struct msg_get_arm_mem {
        struct bcm2835_mbox_hdr hdr;
        struct bcm2835_mbox_tag_get_arm_mem get_arm_mem;
index 5eedbf8ce66c5deadd36f268d181f998123fa45e..3aad532367b361cfe0c5bba0ed72f2f0e5c69c90 100644 (file)
@@ -9,6 +9,7 @@
 #include <asm/processor.h>
 #include <asm/io.h>
 #include <asm/mmc.h>
+#include <spi.h>
 #include <spi_flash.h>
 
 int checkboard(void)
index 42b920fb33395013fdda8ec2af0af823a9efa464..9f6494561c6a43378f899fda6d4702344b6cf63a 100644 (file)
@@ -9,6 +9,7 @@
 #include <asm/processor.h>
 #include <asm/io.h>
 #include <asm/mmc.h>
+#include <spi.h>
 #include <spi_flash.h>
 
 int checkboard(void)
index 1464f48b43ae00f2ad290c292433f07fcbe7386d..ddcf275f6e7854ca6d23cc7ab1d24162cf3c626f 100644 (file)
@@ -9,6 +9,7 @@
 #include <asm/processor.h>
 #include <asm/io.h>
 #include <asm/mmc.h>
+#include <spi.h>
 #include <spi_flash.h>
 
 int checkboard(void)
index 83fd3bd754bdf1549a7a9fe65a8929649feb2f2a..881d080522563912da43a96e90a7a66a6fa4866a 100644 (file)
@@ -6,9 +6,9 @@
 
 #include <common.h>
 #include <usb.h>
+#include <asm/gpio.h>
 #include <asm/arch/pinmux.h>
 #include <asm/arch/dwmmc.h>
-#include <asm/arch/gpio.h>
 #include <asm/arch/power.h>
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -19,6 +19,8 @@ int board_usb_init(int index, enum usb_init_type init)
        /* Configure gpios for usb 3503 hub:
         * disconnect, toggle reset and connect
         */
+       gpio_request(EXYNOS5_GPIO_D17, "usb_connect");
+       gpio_request(EXYNOS5_GPIO_X35, "usb_reset");
        gpio_direction_output(EXYNOS5_GPIO_D17, 0);
        gpio_direction_output(EXYNOS5_GPIO_X35, 0);
 
index 5c3c5bb9254b0bc427ab493033844f5fb1083086..e1fc123fcc4ea154cd4e189460a8afb3e1713399 100644 (file)
 #include <tmu.h>
 #include <netdev.h>
 #include <asm/io.h>
+#include <asm/gpio.h>
 #include <asm/arch/board.h>
 #include <asm/arch/cpu.h>
 #include <asm/arch/dwmmc.h>
-#include <asm/arch/gpio.h>
 #include <asm/arch/mmc.h>
 #include <asm/arch/pinmux.h>
 #include <asm/arch/power.h>
@@ -87,9 +87,6 @@ int board_init(void)
        boot_temp_check();
 #endif
 
-#ifdef CONFIG_EXYNOS_SPI
-       spi_init();
-#endif
        return exynos_init();
 }
 
index 8766f0ca0684948877b28bcec64177c6b51530b0..4538ac7f2a2fc2d2a91f840944d13ec542e35e11 100644 (file)
@@ -14,7 +14,6 @@
 #include <malloc.h>
 #include <linux/sizes.h>
 #include <asm/arch/cpu.h>
-#include <asm/arch/gpio.h>
 #include <asm/gpio.h>
 #include <linux/input.h>
 #include <power/pmic.h>
@@ -412,6 +411,8 @@ void check_boot_mode(void)
 void keys_init(void)
 {
        /* Set direction to input */
+       gpio_request(KEY_VOL_UP_GPIO, "volume-up");
+       gpio_request(KEY_VOL_DOWN_GPIO, "volume-down");
        gpio_direction_input(KEY_VOL_UP_GPIO);
        gpio_direction_input(KEY_VOL_DOWN_GPIO);
 }
index eb0f9bffae0e4a3b925b570af2ab4f1337aa2f60..58cf96eaa84f49bcd9ce47a3f2476504deb783be 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 #include <common.h>
-#include <asm/arch/gpio.h>
+#include <asm/gpio.h>
 #include <asm/arch/mmc.h>
 #include <power/pmic.h>
 #include <usb/s3c_udc.h>
@@ -33,6 +33,16 @@ int board_init(void)
        return 0;
 }
 
+#ifdef CONFIG_SYS_I2C_INIT_BOARD
+void i2c_init_board(void)
+{
+       gpio_request(S5PC110_GPIO_J43, "i2c_clk");
+       gpio_request(S5PC110_GPIO_J40, "i2c_data");
+       gpio_direction_output(S5PC110_GPIO_J43, 1);
+       gpio_direction_output(S5PC110_GPIO_J40, 1);
+}
+#endif
+
 int power_init_board(void)
 {
        int ret;
@@ -80,6 +90,7 @@ int board_mmc_init(bd_t *bis)
        int i, ret, ret_sd = 0;
 
        /* MASSMEMORY_EN: XMSMDATA7: GPJ2[7] output high */
+       gpio_request(S5PC110_GPIO_J27, "massmemory_en");
        gpio_direction_output(S5PC110_GPIO_J27, 1);
 
        /*
@@ -108,6 +119,7 @@ int board_mmc_init(bd_t *bis)
         * SD card (T_FLASH) detect and init
         * T_FLASH_DETECT: EINT28: GPH3[4] input mode
         */
+       gpio_request(S5PC110_GPIO_H34, "t_flash_detect");
        gpio_cfg_pin(S5PC110_GPIO_H34, S5P_GPIO_INPUT);
        gpio_set_pull(S5PC110_GPIO_H34, S5P_GPIO_PULL_UP);
 
index a539267a1ca43339ddfe246ecc37aa85b0f73b9f..99a2facd1ee71f00945c01d5774d7d00e955c832 100644 (file)
@@ -6,8 +6,8 @@
 
 #include <common.h>
 #include <asm/io.h>
+#include <asm/gpio.h>
 #include <asm/arch/cpu.h>
-#include <asm/arch/gpio.h>
 #include <asm/arch/mmc.h>
 #include <asm/arch/periph.h>
 #include <asm/arch/pinmux.h>
index d6ce1337b94ba6f06172ea6459c7162396dbc5ea..53ff7061d730c293260acd1f77367ec1d5bb4f16 100644 (file)
@@ -29,6 +29,7 @@ DECLARE_GLOBAL_DATA_PTR;
 static void board_enable_audio_codec(void)
 {
        /* Enable MAX98095 Codec */
+       gpio_request(EXYNOS5_GPIO_X17, "max98095_enable");
        gpio_direction_output(EXYNOS5_GPIO_X17, 1);
        gpio_set_pull(EXYNOS5_GPIO_X17, S5P_GPIO_PULL_NONE);
 }
@@ -199,16 +200,19 @@ static int board_dp_bridge_setup(void)
        /* Setup the GPIOs */
 
        /* PD is ACTIVE_LOW, and initially de-asserted */
+       gpio_request(EXYNOS5_GPIO_Y25, "dp_bridge_pd");
        gpio_set_pull(EXYNOS5_GPIO_Y25, S5P_GPIO_PULL_NONE);
        gpio_direction_output(EXYNOS5_GPIO_Y25, 1);
 
        /* Reset is ACTIVE_LOW */
+       gpio_request(EXYNOS5_GPIO_X15, "dp_bridge_reset");
        gpio_set_pull(EXYNOS5_GPIO_X15, S5P_GPIO_PULL_NONE);
        gpio_direction_output(EXYNOS5_GPIO_X15, 0);
 
        udelay(10);
        gpio_set_value(EXYNOS5_GPIO_X15, 1);
 
+       gpio_request(EXYNOS5_GPIO_X07, "dp_bridge_hpd");
        gpio_direction_input(EXYNOS5_GPIO_X07);
 
        /*
@@ -236,10 +240,12 @@ static int board_dp_bridge_setup(void)
 void exynos_cfg_lcd_gpio(void)
 {
        /* For Backlight */
+       gpio_request(EXYNOS5_GPIO_B20, "lcd_backlight");
        gpio_cfg_pin(EXYNOS5_GPIO_B20, S5P_GPIO_OUTPUT);
        gpio_set_value(EXYNOS5_GPIO_B20, 1);
 
        /* LCD power on */
+       gpio_request(EXYNOS5_GPIO_X15, "lcd_power");
        gpio_cfg_pin(EXYNOS5_GPIO_X15, S5P_GPIO_OUTPUT);
        gpio_set_value(EXYNOS5_GPIO_X15, 1);
 
@@ -276,6 +282,7 @@ void exynos_backlight_on(unsigned int on)
        mdelay(10);
 
        /* board_dp_backlight_en */
+       gpio_request(EXYNOS5_GPIO_X30, "board_dp_backlight_en");
        gpio_direction_output(EXYNOS5_GPIO_X30, 1);
 #endif
 }
index 270ee834e65695210c88668f2beab5e06ac4a304..a691222b8b143dd61e784ae8e3122dc95b8e3953 100644 (file)
@@ -11,9 +11,9 @@
 #include <lcd.h>
 #include <spi.h>
 #include <errno.h>
+#include <asm/gpio.h>
 #include <asm/arch/board.h>
 #include <asm/arch/cpu.h>
-#include <asm/arch/gpio.h>
 #include <asm/arch/pinmux.h>
 #include <asm/arch/system.h>
 #include <asm/arch/dp_info.h>
@@ -74,9 +74,12 @@ void exynos_lcd_power_on(void)
        mdelay(5);
 
        /* TODO(ajaykumar.rs@samsung.com): Use device tree */
+       gpio_request(EXYNOS5420_GPIO_X35, "edp_slp#");
        gpio_direction_output(EXYNOS5420_GPIO_X35, 1);  /* EDP_SLP# */
        mdelay(10);
+       gpio_request(EXYNOS5420_GPIO_Y77, "edp_rst#");
        gpio_direction_output(EXYNOS5420_GPIO_Y77, 1);  /* EDP_RST# */
+       gpio_request(EXYNOS5420_GPIO_X26, "edp_hpd");
        gpio_direction_input(EXYNOS5420_GPIO_X26);      /* EDP_HPD */
        gpio_set_pull(EXYNOS5420_GPIO_X26, S5P_GPIO_PULL_NONE);
 
@@ -88,6 +91,7 @@ void exynos_lcd_power_on(void)
 void exynos_backlight_on(unsigned int onoff)
 {
        /* For PWM */
+       gpio_request(EXYNOS5420_GPIO_B20, "backlight_on");
        gpio_cfg_pin(EXYNOS5420_GPIO_B20, S5P_GPIO_FUNC(0x1));
        gpio_set_value(EXYNOS5420_GPIO_B20, 1);
 
index e009564a5988ce8a79a9bd7e83634ee9e8ca7ac4..66b6a9801f734ec1894b213a822b37ca86139419 100644 (file)
@@ -7,9 +7,9 @@
  */
 
 #include <common.h>
+#include <asm/gpio.h>
 #include <asm/io.h>
 #include <asm/arch/sromc.h>
-#include <asm/arch/gpio.h>
 #include <netdev.h>
 
 DECLARE_GLOBAL_DATA_PTR;
index 8eca358981f10351a639c7775a58e19504072106..cb7f9b0ac88babc95253a5cf43e9e8d2ca580da6 100644 (file)
@@ -5,10 +5,10 @@
  */
 
 #include <common.h>
+#include <asm/gpio.h>
 #include <asm/io.h>
 #include <netdev.h>
 #include <asm/arch/cpu.h>
-#include <asm/arch/gpio.h>
 #include <asm/arch/mmc.h>
 #include <asm/arch/periph.h>
 #include <asm/arch/pinmux.h>
index 3dd340b7d8da7e3b6a80d770e8442d0ba1a477b8..e163e45a587df150324e60ee57114a5735269a76 100644 (file)
@@ -10,8 +10,8 @@
 #include <common.h>
 #include <lcd.h>
 #include <asm/io.h>
+#include <asm/gpio.h>
 #include <asm/arch/cpu.h>
-#include <asm/arch/gpio.h>
 #include <asm/arch/pinmux.h>
 #include <asm/arch/clock.h>
 #include <asm/arch/mipi_dsim.h>
@@ -63,6 +63,8 @@ void i2c_init_board(void)
        }
 
        /* I2C_8 -> FG */
+       gpio_request(EXYNOS4_GPIO_Y40, "i2c_clk");
+       gpio_request(EXYNOS4_GPIO_Y41, "i2c_data");
        gpio_direction_output(EXYNOS4_GPIO_Y40, 1);
        gpio_direction_output(EXYNOS4_GPIO_Y41, 1);
 }
@@ -346,12 +348,17 @@ int exynos_power_init(void)
 static unsigned int get_hw_revision(void)
 {
        int hwrev = 0;
+       char str[10];
        int i;
 
        /* hw_rev[3:0] == GPE1[3:0] */
-       for (i = EXYNOS4_GPIO_E10; i < EXYNOS4_GPIO_E14; i++) {
-               gpio_cfg_pin(i, S5P_GPIO_INPUT);
-               gpio_set_pull(i, S5P_GPIO_PULL_NONE);
+       for (i = 0; i < 4; i++) {
+               int pin = i + EXYNOS4_GPIO_E10;
+
+               sprintf(str, "hw_rev%d", i);
+               gpio_request(pin, str);
+               gpio_cfg_pin(pin, S5P_GPIO_INPUT);
+               gpio_set_pull(pin, S5P_GPIO_PULL_NONE);
        }
 
        udelay(1);
@@ -517,6 +524,7 @@ static void board_power_init(void)
 static void exynos_uart_init(void)
 {
        /* UART_SEL GPY4[7] (part2) at EXYNOS4 */
+       gpio_request(EXYNOS4_GPIO_Y47, "uart_sel");
        gpio_set_pull(EXYNOS4_GPIO_Y47, S5P_GPIO_PULL_UP);
        gpio_direction_output(EXYNOS4_GPIO_Y47, 1);
 }
@@ -534,6 +542,7 @@ int exynos_early_init_f(void)
 
 void exynos_reset_lcd(void)
 {
+       gpio_request(EXYNOS4_GPIO_Y45, "lcd_reset");
        gpio_direction_output(EXYNOS4_GPIO_Y45, 1);
        udelay(10000);
        gpio_direction_output(EXYNOS4_GPIO_Y45, 0);
index fa26e61244fc97e2a16b903dc89b971dadf26010..a7377497e5d2d4002f7b847ae051abfe5e8bb2b9 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <common.h>
 #include <lcd.h>
+#include <asm/gpio.h>
 #include <asm/arch/pinmux.h>
 #include <asm/arch/power.h>
 #include <asm/arch/mipi_dsim.h>
@@ -32,6 +33,7 @@ static inline u32 get_model_rev(void);
 static void check_hw_revision(void)
 {
        int modelrev = 0;
+       char str[12];
        int i;
 
        /*
@@ -40,13 +42,22 @@ static void check_hw_revision(void)
         * TRM say that it may cause unexcepted state and leakage current.
         * and pull-none is only for output function.
         */
-       for (i = EXYNOS4X12_GPIO_M10; i < EXYNOS4X12_GPIO_M12; i++)
-               gpio_cfg_pin(i, S5P_GPIO_INPUT);
+       for (i = 0; i < 2; i++) {
+               int pin = i + EXYNOS4X12_GPIO_M10;
+
+               sprintf(str, "model_rev%d", i);
+               gpio_request(pin, str);
+               gpio_cfg_pin(pin, S5P_GPIO_INPUT);
+       }
 
        /* GPM1[5:2]: HW_REV[3:0] */
-       for (i = EXYNOS4X12_GPIO_M12; i < EXYNOS4X12_GPIO_M16; i++) {
-               gpio_cfg_pin(i, S5P_GPIO_INPUT);
-               gpio_set_pull(i, S5P_GPIO_PULL_NONE);
+       for (i = 0; i < 4; i++) {
+               int pin = i + EXYNOS4X12_GPIO_M12;
+
+               sprintf(str, "hw_rev%d", i);
+               gpio_request(pin, str);
+               gpio_cfg_pin(pin, S5P_GPIO_INPUT);
+               gpio_set_pull(pin, S5P_GPIO_PULL_NONE);
        }
 
        /* GPM1[1:0]: MODEL_REV[1:0] */
@@ -102,10 +113,14 @@ static void board_init_i2c(void)
        }
 
        /* I2C_8 */
+       gpio_request(EXYNOS4X12_GPIO_F14, "i2c8_clk");
+       gpio_request(EXYNOS4X12_GPIO_F15, "i2c8_data");
        gpio_direction_output(EXYNOS4X12_GPIO_F14, 1);
        gpio_direction_output(EXYNOS4X12_GPIO_F15, 1);
 
        /* I2C_9 */
+       gpio_request(EXYNOS4X12_GPIO_M21, "i2c9_clk");
+       gpio_request(EXYNOS4X12_GPIO_M20, "i2c9_data");
        gpio_direction_output(EXYNOS4X12_GPIO_M21, 1);
        gpio_direction_output(EXYNOS4X12_GPIO_M20, 1);
 }
@@ -387,6 +402,7 @@ void exynos_lcd_power_on(void)
        struct pmic *p = pmic_get("MAX77686_PMIC");
 
        /* LCD_2.2V_EN: GPC0[1] */
+       gpio_request(EXYNOS4X12_GPIO_C01, "lcd_2v2_en");
        gpio_set_pull(EXYNOS4X12_GPIO_C01, S5P_GPIO_PULL_UP);
        gpio_direction_output(EXYNOS4X12_GPIO_C01, 1);
 
@@ -399,6 +415,7 @@ void exynos_lcd_power_on(void)
 void exynos_reset_lcd(void)
 {
        /* reset lcd */
+       gpio_request(EXYNOS4X12_GPIO_F21, "lcd_reset");
        gpio_direction_output(EXYNOS4X12_GPIO_F21, 0);
        udelay(10);
        gpio_set_value(EXYNOS4X12_GPIO_F21, 1);
index 47e7f538d65b7cd35943328d91ecb44385096961..22b08497cb57c1091b1eb82aeed7b58b73c18857 100644 (file)
@@ -12,7 +12,6 @@
 #include <asm/io.h>
 #include <asm/gpio.h>
 #include <asm/arch/adc.h>
-#include <asm/arch/gpio.h>
 #include <asm/arch/pinmux.h>
 #include <asm/arch/watchdog.h>
 #include <ld9040.h>
@@ -202,53 +201,6 @@ int exynos_early_init_f(void)
        return 0;
 }
 
-#ifdef CONFIG_SOFT_SPI
-static void soft_spi_init(void)
-{
-       gpio_direction_output(CONFIG_SOFT_SPI_GPIO_SCLK,
-               CONFIG_SOFT_SPI_MODE & SPI_CPOL);
-       gpio_direction_output(CONFIG_SOFT_SPI_GPIO_MOSI, 1);
-       gpio_direction_input(CONFIG_SOFT_SPI_GPIO_MISO);
-       gpio_direction_output(CONFIG_SOFT_SPI_GPIO_CS,
-               !(CONFIG_SOFT_SPI_MODE & SPI_CS_HIGH));
-}
-
-void spi_cs_activate(struct spi_slave *slave)
-{
-       gpio_set_value(CONFIG_SOFT_SPI_GPIO_CS,
-               !(CONFIG_SOFT_SPI_MODE & SPI_CS_HIGH));
-       SPI_SCL(1);
-       gpio_set_value(CONFIG_SOFT_SPI_GPIO_CS,
-               CONFIG_SOFT_SPI_MODE & SPI_CS_HIGH);
-}
-
-void spi_cs_deactivate(struct spi_slave *slave)
-{
-       gpio_set_value(CONFIG_SOFT_SPI_GPIO_CS,
-               !(CONFIG_SOFT_SPI_MODE & SPI_CS_HIGH));
-}
-
-int  spi_cs_is_valid(unsigned int bus, unsigned int cs)
-{
-       return bus == 0 && cs == 0;
-}
-
-void universal_spi_scl(int bit)
-{
-       gpio_set_value(CONFIG_SOFT_SPI_GPIO_SCLK, bit);
-}
-
-void universal_spi_sda(int bit)
-{
-       gpio_set_value(CONFIG_SOFT_SPI_GPIO_MOSI, bit);
-}
-
-int universal_spi_read(void)
-{
-       return gpio_get_value(CONFIG_SOFT_SPI_GPIO_MISO);
-}
-#endif
-
 static void init_pmic_lcd(void)
 {
        unsigned char val;
@@ -331,9 +283,8 @@ void exynos_cfg_lcd_gpio(void)
        }
 
        /* gpio pad configuration for LCD reset. */
+       gpio_request(EXYNOS4_GPIO_Y45, "lcd_reset");
        gpio_cfg_pin(EXYNOS4_GPIO_Y45, S5P_GPIO_OUTPUT);
-
-       spi_init();
 }
 
 int mipi_power(void)
@@ -387,6 +338,7 @@ int exynos_init(void)
                 * you should set it HIGH since it removes the inverter
                 */
                /* MASSMEMORY_EN: XMDMDATA_6: GPE3[6] */
+               gpio_request(EXYNOS4_GPIO_E36, "ldo_en");
                gpio_direction_output(EXYNOS4_GPIO_E36, 0);
                break;
        default:
@@ -395,13 +347,11 @@ int exynos_init(void)
                 * But set it as HIGH to ensure
                 */
                /* MASSMEMORY_EN: XMDMADDR_3: GPE1[3] */
+               gpio_request(EXYNOS4_GPIO_E13, "massmemory_en");
                gpio_direction_output(EXYNOS4_GPIO_E13, 1);
                break;
        }
 
-#ifdef CONFIG_SOFT_SPI
-       soft_spi_init();
-#endif
        check_hw_revision();
        printf("HW Revision:\t0x%x\n", board_rev);
 
index 7e1a76d97f73be5d2eb3d347dffbb82d301b7522..3affb6362f4531ebd3f313248df1fbd7c588e7bf 100644 (file)
@@ -354,7 +354,7 @@ static int initr_flash(void)
 }
 #endif
 
-#ifdef CONFIG_PPC
+#if defined(CONFIG_PPC) && !defined(CONFIG_DM_SPI)
 static int initr_spi(void)
 {
        /* PPC does this here */
index ff81a271a559232c07e3f7c1cbebc4bf327731c3..17ed3897f99391cbc0eb8f962d46ae138a4d1d17 100644 (file)
@@ -9,6 +9,7 @@
 #include <common.h>
 #include <bootstage.h>
 #include <bzlib.h>
+#include <errno.h>
 #include <fdt_support.h>
 #include <lmb.h>
 #include <malloc.h>
@@ -83,6 +84,7 @@ static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc,
 {
        const void *os_hdr;
        bool ep_found = false;
+       int ret;
 
        /* get kernel image header, start address and length */
        os_hdr = boot_get_kernel(cmdtp, flag, argc, argv,
@@ -102,6 +104,7 @@ static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc,
 
                images.os.end = image_get_image_end(os_hdr);
                images.os.load = image_get_load(os_hdr);
+               images.os.arch = image_get_arch(os_hdr);
                break;
 #endif
 #if defined(CONFIG_FIT)
@@ -129,6 +132,13 @@ static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc,
                        return 1;
                }
 
+               if (fit_image_get_arch(images.fit_hdr_os,
+                                      images.fit_noffset_os,
+                                      &images.os.arch)) {
+                       puts("Can't get image ARCH!\n");
+                       return 1;
+               }
+
                images.os.end = fit_get_end(images.fit_hdr_os);
 
                if (fit_image_get_load(images.fit_hdr_os, images.fit_noffset_os,
@@ -156,8 +166,17 @@ static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc,
                return 1;
        }
 
-       /* find kernel entry point */
-       if (images.legacy_hdr_valid) {
+       /* If we have a valid setup.bin, we will use that for entry (x86) */
+       if (images.os.arch == IH_ARCH_I386) {
+               ulong len;
+
+               ret = boot_get_setup(&images, IH_ARCH_I386, &images.ep, &len);
+               if (ret < 0 && ret != -ENOENT) {
+                       puts("Could not find a valid setup.bin for x86\n");
+                       return 1;
+               }
+               /* Kernel entry point is the setup.bin */
+       } else if (images.legacy_hdr_valid) {
                images.ep = image_get_ep(&images.legacy_hdr_os_copy);
 #if defined(CONFIG_FIT)
        } else if (images.fit_uname_os) {
index 843ec6e0c2696380d176740bbb5864b05e46624b..67233600b157244409c2710afa606337d2ebaf80 100644 (file)
@@ -12,6 +12,7 @@
 #include <bootm.h>
 #include <command.h>
 #include <environment.h>
+#include <errno.h>
 #include <image.h>
 #include <lmb.h>
 #include <malloc.h>
index c60e8d10df6e1ad244a154a795bff79a4d51c8df..95a6f89a845da57b5e5430b339dbda12f4d5d354 100644 (file)
@@ -8,10 +8,13 @@
 
 #include <common.h>
 #include <div64.h>
+#include <dm.h>
 #include <malloc.h>
+#include <spi.h>
 #include <spi_flash.h>
 
 #include <asm/io.h>
+#include <dm/device-internal.h>
 
 static struct spi_flash *flash;
 
@@ -80,7 +83,12 @@ static int do_spi_flash_probe(int argc, char * const argv[])
        unsigned int speed = CONFIG_SF_DEFAULT_SPEED;
        unsigned int mode = CONFIG_SF_DEFAULT_MODE;
        char *endp;
+#ifdef CONFIG_DM_SPI_FLASH
+       struct udevice *new, *bus_dev;
+       int ret;
+#else
        struct spi_flash *new;
+#endif
 
        if (argc >= 2) {
                cs = simple_strtoul(argv[1], &endp, 0);
@@ -108,6 +116,23 @@ static int do_spi_flash_probe(int argc, char * const argv[])
                        return -1;
        }
 
+#ifdef CONFIG_DM_SPI_FLASH
+       /* Remove the old device, otherwise probe will just be a nop */
+       ret = spi_find_bus_and_cs(bus, cs, &bus_dev, &new);
+       if (!ret) {
+               device_remove(new);
+               device_unbind(new);
+       }
+       flash = NULL;
+       ret = spi_flash_probe_bus_cs(bus, cs, speed, mode, &new);
+       if (ret) {
+               printf("Failed to initialize SPI flash at %u:%u (error %d)\n",
+                      bus, cs, ret);
+               return 1;
+       }
+
+       flash = new->uclass_priv;
+#else
        new = spi_flash_probe(bus, cs, speed, mode);
        if (!new) {
                printf("Failed to initialize SPI flash at %u:%u\n", bus, cs);
@@ -117,6 +142,7 @@ static int do_spi_flash_probe(int argc, char * const argv[])
        if (flash)
                spi_flash_free(flash);
        flash = new;
+#endif
 
        return 0;
 }
index be5709c6173d09562a3f274fd6c1a0e4756c67af..64c3ffcf423b35fc1b0a65daccb99d490a053c5f 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <common.h>
 #include <command.h>
+#include <dm.h>
 #include <errno.h>
 #include <spi.h>
 
@@ -42,19 +43,38 @@ static uchar                din[MAX_SPI_BYTES];
 static int do_spi_xfer(int bus, int cs)
 {
        struct spi_slave *slave;
-       int rcode = 0;
-
+       int ret = 0;
+
+#ifdef CONFIG_DM_SPI
+       char name[30], *str;
+       struct udevice *dev;
+
+       snprintf(name, sizeof(name), "generic_%d:%d", bus, cs);
+       str = strdup(name);
+       ret = spi_get_bus_and_cs(bus, cs, 1000000, mode, "spi_generic_drv",
+                                str, &dev, &slave);
+       if (ret)
+               return ret;
+#else
        slave = spi_setup_slave(bus, cs, 1000000, mode);
        if (!slave) {
                printf("Invalid device %d:%d\n", bus, cs);
                return -EINVAL;
        }
+#endif
 
-       spi_claim_bus(slave);
-       if (spi_xfer(slave, bitlen, dout, din,
-                    SPI_XFER_BEGIN | SPI_XFER_END) != 0) {
-               printf("Error during SPI transaction\n");
-               rcode = -EIO;
+       ret = spi_claim_bus(slave);
+       if (ret)
+               goto done;
+       ret = spi_xfer(slave, bitlen, dout, din,
+                      SPI_XFER_BEGIN | SPI_XFER_END);
+#ifndef CONFIG_DM_SPI
+       /* We don't get an error code in this case */
+       if (ret)
+               ret = -EIO;
+#endif
+       if (ret) {
+               printf("Error %d during SPI transaction\n", ret);
        } else {
                int j;
 
@@ -62,10 +82,13 @@ static int do_spi_xfer(int bus, int cs)
                        printf("%02X", din[j]);
                printf("\n");
        }
+done:
        spi_release_bus(slave);
+#ifndef CONFIG_DM_SPI
        spi_free_slave(slave);
+#endif
 
-       return rcode;
+       return ret;
 }
 
 /*
index b8ce1b581aab463f65330e4dcc769f3fc00b1f19..bb299bccfff7073791ad9b1cedf5c1d3c171d190 100644 (file)
 
 #include <common.h>
 #include <cros_ec.h>
+#include <dm.h>
+#include <errno.h>
+
 DECLARE_GLOBAL_DATA_PTR;
 
+#ifndef CONFIG_DM_CROS_EC
 struct local_info {
        struct cros_ec_dev *cros_ec_dev;        /* Pointer to cros_ec device */
        int cros_ec_err;                        /* Error for cros_ec, 0 if ok */
 };
 
 static struct local_info local;
+#endif
 
 struct cros_ec_dev *board_get_cros_ec_dev(void)
 {
+#ifdef CONFIG_DM_CROS_EC
+       struct udevice *dev;
+       int ret;
+
+       ret = uclass_get_device(UCLASS_CROS_EC, 0, &dev);
+       if (ret) {
+               debug("%s: Error %d\n", __func__, ret);
+               return NULL;
+       }
+       return dev->uclass_priv;
+#else
        return local.cros_ec_dev;
+#endif
 }
 
 static int board_init_cros_ec_devices(const void *blob)
 {
+#ifndef CONFIG_DM_CROS_EC
        local.cros_ec_err = cros_ec_init(blob, &local.cros_ec_dev);
        if (local.cros_ec_err)
                return -1;  /* Will report in board_late_init() */
+#endif
 
        return 0;
 }
@@ -40,5 +59,16 @@ int cros_ec_board_init(void)
 
 int cros_ec_get_error(void)
 {
+#ifdef CONFIG_DM_CROS_EC
+       struct udevice *dev;
+       int ret;
+
+       ret = uclass_get_device(UCLASS_CROS_EC, 0, &dev);
+       if (ret && ret != -ENODEV)
+               return ret;
+
+       return 0;
+#else
        return local.cros_ec_err;
+#endif
 }
index 37ab13ae17842309339fa9a70a42e49b8669207e..5e3729c2c2d62dfb201e2329081318f1657fa422 100644 (file)
@@ -12,6 +12,7 @@
 #include <common.h>
 #include <environment.h>
 #include <malloc.h>
+#include <spi.h>
 #include <spi_flash.h>
 #include <search.h>
 #include <errno.h>
index b97ca48307dcba1493d9426bde8e6f706d8fa1ed..88fcfc8cb6fc652e8fb5242869ebdb4c0813f5dd 100644 (file)
@@ -27,10 +27,12 @@ unsigned long get_version(void)
 # define i2c_write         dummy
 # define i2c_read          dummy
 #endif
-#ifndef CONFIG_CMD_SPI
+#if !defined(CONFIG_CMD_SPI) || defined(CONFIG_DM_SPI)
 # define spi_init          dummy
 # define spi_setup_slave   dummy
 # define spi_free_slave    dummy
+#endif
+#ifndef CONFIG_CMD_SPI
 # define spi_claim_bus     dummy
 # define spi_release_bus   dummy
 # define spi_xfer          dummy
index 255c4cac9cafa328d33cd382e524207c1728c7cc..2016d1e7dda85a34c5d1c787015bd309ed6061da 100644 (file)
@@ -1497,6 +1497,8 @@ static const char *fit_get_image_type_property(int type)
                return FIT_KERNEL_PROP;
        case IH_TYPE_RAMDISK:
                return FIT_RAMDISK_PROP;
+       case IH_TYPE_X86_SETUP:
+               return FIT_SETUP_PROP;
        }
 
        return "unknown";
@@ -1591,7 +1593,7 @@ int fit_image_load(bootm_headers_t *images, ulong addr,
        }
 
        bootstage_mark(bootstage_id + BOOTSTAGE_SUB_CHECK_ARCH);
-#ifndef USE_HOSTCC
+#if !defined(USE_HOSTCC) && !defined(CONFIG_SANDBOX)
        if (!fit_image_check_target_arch(fit, noffset)) {
                puts("Unsupported Architecture\n");
                bootstage_error(bootstage_id + BOOTSTAGE_SUB_CHECK_ARCH);
@@ -1693,3 +1695,23 @@ int fit_image_load(bootm_headers_t *images, ulong addr,
 
        return noffset;
 }
+
+int boot_get_setup_fit(bootm_headers_t *images, uint8_t arch,
+                       ulong *setup_start, ulong *setup_len)
+{
+       int noffset;
+       ulong addr;
+       ulong len;
+       int ret;
+
+       addr = map_to_sysmem(images->fit_hdr_os);
+       noffset = fit_get_node_from_config(images, FIT_SETUP_PROP, addr);
+       if (noffset < 0)
+               return noffset;
+
+       ret = fit_image_load(images, addr, NULL, NULL, arch,
+                            IH_TYPE_X86_SETUP, BOOTSTAGE_ID_FIT_SETUP_START,
+                            FIT_LOAD_REQUIRED, setup_start, &len);
+
+       return ret;
+}
index 085771c7639b6a4aaed005dcef5f305dc3fe7e4e..640e83b7bdf8013d02416615faf796c483a12d0f 100644 (file)
@@ -143,6 +143,7 @@ static const table_entry_t uimage_type[] = {
        {       IH_TYPE_UBLIMAGE,   "ublimage",   "Davinci UBL image",},
        {       IH_TYPE_MXSIMAGE,   "mxsimage",   "Freescale MXS Boot Image",},
        {       IH_TYPE_ATMELIMAGE, "atmelimage", "ATMEL ROM-Boot Image",},
+       {       IH_TYPE_X86_SETUP,  "x86_setup",  "x86 setup.bin",    },
        {       -1,                 "",           "",                   },
 };
 
@@ -1136,6 +1137,16 @@ error:
 }
 #endif /* CONFIG_SYS_BOOT_RAMDISK_HIGH */
 
+int boot_get_setup(bootm_headers_t *images, uint8_t arch,
+                  ulong *setup_start, ulong *setup_len)
+{
+#if defined(CONFIG_FIT)
+       return boot_get_setup_fit(images, arch, setup_start, setup_len);
+#else
+       return -ENOENT;
+#endif
+}
+
 #ifdef CONFIG_SYS_BOOT_GET_CMDLINE
 /**
  * boot_get_cmdline - allocate and initialize kernel cmdline
diff --git a/doc/device-tree-bindings/mtd/spi/spi-flash.txt b/doc/device-tree-bindings/mtd/spi/spi-flash.txt
new file mode 100644 (file)
index 0000000..85522d8
--- /dev/null
@@ -0,0 +1,25 @@
+* MTD SPI driver for serial flash chips
+
+Required properties:
+- #address-cells, #size-cells : Must be present if the device has sub-nodes
+  representing partitions.
+- compatible : Should be the manufacturer and the name of the chip. Bear in
+               mind that the DT binding is not U-Boot-only, but in case of
+               U-Boot, see spi_flash_params_table table in
+               drivers/mtd/spi/sf_params.c for the list of supported chips.
+- reg : Chip-Select number
+- spi-max-frequency : Maximum frequency of the SPI bus the chip can operate at
+
+Optional properties:
+ - memory-map : Address and size of the flash, if memory mapped. This may
+                apply to Intel chipsets, which tend to memory-map flash.
+
+Example:
+
+       flash: m25p80@0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "spansion,m25p80";
+               reg = <0>;
+               spi-max-frequency = <40000000>;
+       };
diff --git a/doc/device-tree-bindings/spi/soft-spi.txt b/doc/device-tree-bindings/spi/soft-spi.txt
new file mode 100644 (file)
index 0000000..d09c1a5
--- /dev/null
@@ -0,0 +1,34 @@
+Soft SPI
+
+The soft SPI bus implementation allows the use of GPIO pins to simulate a
+SPI bus. No SPI host is required for this to work. The down-side is that the
+performance will typically be much lower than a real SPI bus.
+
+The soft SPI node requires the following properties:
+
+compatible: "u-boot,soft-spi"
+soft_spi_cs: GPIO number to use for SPI chip select (output)
+soft_spi_sclk: GPIO number to use for SPI clock (output)
+soft_spi_mosi: GPIO number to use for SPI MOSI line (output)
+soft_spi_miso GPIO number to use for SPI MISO line (input)
+spi-delay-us: Number of microseconds of delay between each CS transition
+
+The GPIOs should be specified as required by the GPIO controller referenced.
+The first cell holds the phandle of the controller and the second cell
+typically holds the GPIO number.
+
+
+Example:
+
+       soft-spi {
+               compatible = "u-boot,soft-spi";
+               cs-gpio = <&gpio 235 0>;        /* Y43 */
+               sclk-gpio = <&gpio 225 0>;      /* Y31 */
+               mosi-gpio = <&gpio 227 0>;      /* Y33 */
+               miso-gpio = <&gpio 224 0>;      /* Y30 */
+               spi-delay-us = <1>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               cs@0 {
+               };
+       };
index f9b68beb6f6d663bba7d0da97fdea32024b337fa..8dfcf75c3d369219b8cbc15782723013b94b0129 100644 (file)
@@ -95,7 +95,7 @@ are provided in test/dm. To run them, try:
 You should see something like this:
 
     <...U-Boot banner...>
-    Running 21 driver model tests
+    Running 22 driver model tests
     Test: dm_test_autobind
     Test: dm_test_autoprobe
     Test: dm_test_bus_children
@@ -103,6 +103,7 @@ You should see something like this:
     Device 'c-test@0': seq 0 is in use by 'a-test'
     Device 'c-test@1': seq 1 is in use by 'd-test'
     Test: dm_test_bus_children_funcs
+    Test: dm_test_bus_children_iterators
     Test: dm_test_bus_parent_data
     Test: dm_test_bus_parent_ops
     Test: dm_test_children
@@ -358,7 +359,9 @@ Device Sequence Numbers
 U-Boot numbers devices from 0 in many situations, such as in the command
 line for I2C and SPI buses, and the device names for serial ports (serial0,
 serial1, ...). Driver model supports this numbering and permits devices
-to be locating by their 'sequence'.
+to be locating by their 'sequence'. This numbering unique identifies a
+device in its uclass, so no two devices within a particular uclass can have
+the same sequence number.
 
 Sequence numbers start from 0 but gaps are permitted. For example, a board
 may have I2C buses 0, 1, 4, 5 but no 2 or 3. The choice of how devices are
diff --git a/doc/driver-model/spi-howto.txt b/doc/driver-model/spi-howto.txt
new file mode 100644 (file)
index 0000000..719dbd5
--- /dev/null
@@ -0,0 +1,594 @@
+How to port a SPI driver to driver model
+========================================
+
+Here is a rough step-by-step guide. It is based around converting the
+exynos SPI driver to driver model (DM) and the example code is based
+around U-Boot v2014.10-rc2 (commit be9f643).
+
+It is quite long since it includes actual code examples.
+
+Before driver model, SPI drivers have their own private structure which
+contains 'struct spi_slave'. With driver model, 'struct spi_slave' still
+exists, but now it is 'per-child data' for the SPI bus. Each child of the
+SPI bus is a SPI slave. The information that was stored in the
+driver-specific slave structure can now be port in private data for the
+SPI bus.
+
+For example, struct tegra_spi_slave looks like this:
+
+struct tegra_spi_slave {
+       struct spi_slave slave;
+       struct tegra_spi_ctrl *ctrl;
+};
+
+In this case 'slave' will be in per-child data, and 'ctrl' will be in the
+SPI's buses private data.
+
+
+0. How long does this take?
+
+You should be able to complete this within 2 hours, including testing but
+excluding preparing the patches. The API is basically the same as before
+with only minor changes:
+
+- methods to set speed and mode are separated out
+- cs_info is used to get information on a chip select
+
+
+1. Enable driver mode for SPI and SPI flash
+
+Add these to your board config:
+
+#define CONFIG_DM_SPI
+#define CONFIG_DM_SPI_FLASH
+
+
+2. Add the skeleton
+
+Put this code at the bottom of your existing driver file:
+
+struct spi_slave *spi_setup_slave(unsigned int busnum, unsigned int cs,
+                       unsigned int max_hz, unsigned int mode)
+{
+       return NULL;
+}
+
+struct spi_slave *spi_setup_slave_fdt(const void *blob, int slave_node,
+                                     int spi_node)
+{
+       return NULL;
+}
+
+static int exynos_spi_ofdata_to_platdata(struct udevice *dev)
+{
+       return -ENODEV;
+}
+
+static int exynos_spi_probe(struct udevice *dev)
+{
+       return -ENODEV;
+}
+
+static int exynos_spi_remove(struct udevice *dev)
+{
+       return -ENODEV;
+}
+
+static int exynos_spi_claim_bus(struct udevice *dev)
+{
+
+       return -ENODEV;
+}
+
+static int exynos_spi_release_bus(struct udevice *dev)
+{
+
+       return -ENODEV;
+}
+
+static int exynos_spi_xfer(struct udevice *dev, unsigned int bitlen,
+                           const void *dout, void *din, unsigned long flags)
+{
+
+       return -ENODEV;
+}
+
+static int exynos_spi_set_speed(struct udevice *dev, uint speed)
+{
+       return -ENODEV;
+}
+
+static int exynos_spi_set_mode(struct udevice *dev, uint mode)
+{
+       return -ENODEV;
+}
+
+static int exynos_cs_info(struct udevice *bus, uint cs,
+                         struct spi_cs_info *info)
+{
+       return -ENODEV;
+}
+
+static const struct dm_spi_ops exynos_spi_ops = {
+       .claim_bus      = exynos_spi_claim_bus,
+       .release_bus    = exynos_spi_release_bus,
+       .xfer           = exynos_spi_xfer,
+       .set_speed      = exynos_spi_set_speed,
+       .set_mode       = exynos_spi_set_mode,
+       .cs_info        = exynos_cs_info,
+};
+
+static const struct udevice_id exynos_spi_ids[] = {
+       { .compatible = "samsung,exynos-spi" },
+       { }
+};
+
+U_BOOT_DRIVER(exynos_spi) = {
+       .name   = "exynos_spi",
+       .id     = UCLASS_SPI,
+       .of_match = exynos_spi_ids,
+       .ops    = &exynos_spi_ops,
+       .ofdata_to_platdata = exynos_spi_ofdata_to_platdata,
+       .probe  = exynos_spi_probe,
+       .remove = exynos_spi_remove,
+};
+
+
+3. Replace 'exynos' in the above code with your driver name
+
+
+4. #ifdef out all of the code in your driver except for the above
+
+This will allow you to get it building, which means you can work
+incrementally. Since all the methods return an error initially, there is
+less chance that you will accidentally leave something in.
+
+Also, even though your conversion is basically a rewrite, it might help
+reviewers if you leave functions in the same place in the file,
+particularly for large drivers.
+
+
+5. Add some includes
+
+Add these includes to your driver:
+
+#include <dm.h>
+#include <errno.h>
+
+
+6. Build
+
+At this point you should be able to build U-Boot for your board with the
+empty SPI driver. You still have empty methods in your driver, but we will
+write these one by one.
+
+If you have spi_init() functions or the like that are called from your
+board then the build will fail. Remove these calls and make a note of the
+init that needs to be done.
+
+
+7. Set up your platform data structure
+
+This will hold the information your driver to operate, like its hardware
+address or maximum frequency.
+
+You may already have a struct like this, or you may need to create one
+from some of the #defines or global variables in the driver.
+
+Note that this information is not the run-time information. It should not
+include state that changes. It should be fixed throughout the live of
+U-Boot. Run-time information comes later.
+
+Here is what was in the exynos spi driver:
+
+struct spi_bus {
+       enum periph_id periph_id;
+       s32 frequency;          /* Default clock frequency, -1 for none */
+       struct exynos_spi *regs;
+       int inited;             /* 1 if this bus is ready for use */
+       int node;
+       uint deactivate_delay_us;       /* Delay to wait after deactivate */
+};
+
+Of these, inited is handled by DM and node is the device tree node, which
+DM tells you. The name is not quite right. So in this case we would use:
+
+struct exynos_spi_platdata {
+       enum periph_id periph_id;
+       s32 frequency;          /* Default clock frequency, -1 for none */
+       struct exynos_spi *regs;
+       uint deactivate_delay_us;       /* Delay to wait after deactivate */
+};
+
+
+8a. Write ofdata_to_platdata()   [for device tree only]
+
+This method will convert information in the device tree node into a C
+structure in your driver (called platform data). If you are not using
+device tree, go to 8b.
+
+DM will automatically allocate the struct for us when we are using device
+tree, but we need to tell it the size:
+
+U_BOOT_DRIVER(spi_exynos) = {
+...
+       .platdata_auto_alloc_size = sizeof(struct exynos_spi_platdata),
+
+
+Here is a sample function. It gets a pointer to the platform data and
+fills in the fields from device tree.
+
+static int exynos_spi_ofdata_to_platdata(struct udevice *bus)
+{
+       struct exynos_spi_platdata *plat = bus->platdata;
+       const void *blob = gd->fdt_blob;
+       int node = bus->of_offset;
+
+       plat->regs = (struct exynos_spi *)fdtdec_get_addr(blob, node, "reg");
+       plat->periph_id = pinmux_decode_periph_id(blob, node);
+
+       if (plat->periph_id == PERIPH_ID_NONE) {
+               debug("%s: Invalid peripheral ID %d\n", __func__,
+                       plat->periph_id);
+               return -FDT_ERR_NOTFOUND;
+       }
+
+       /* Use 500KHz as a suitable default */
+       plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency",
+                                       500000);
+       plat->deactivate_delay_us = fdtdec_get_int(blob, node,
+                                       "spi-deactivate-delay", 0);
+       debug("%s: regs=%p, periph_id=%d, max-frequency=%d, deactivate_delay=%d\n",
+             __func__, plat->regs, plat->periph_id, plat->frequency,
+              plat->deactivate_delay_us);
+
+       return 0;
+}
+
+
+8b. Add the platform data  [non-device-tree only]
+
+Specify this data in a U_BOOT_DEVICE() declaration in your board file:
+
+struct exynos_spi_platdata platdata_spi0 = {
+       .periph_id = ...
+       .frequency = ...
+       .regs = ...
+       .deactivate_delay_us = ...
+};
+
+U_BOOT_DEVICE(board_spi0) = {
+       .name = "exynos_spi",
+       .platdata = &platdata_spi0,
+};
+
+You will unfortunately need to put the struct into a header file in this
+case so that your board file can use it.
+
+
+9. Add the device private data
+
+Most devices have some private data which they use to keep track of things
+while active. This is the run-time information and needs to be stored in
+a structure. There is probably a structure in the driver that includes a
+'struct spi_slave', so you can use that.
+
+struct exynos_spi_slave {
+       struct spi_slave slave;
+       struct exynos_spi *regs;
+       unsigned int freq;              /* Default frequency */
+       unsigned int mode;
+       enum periph_id periph_id;       /* Peripheral ID for this device */
+       unsigned int fifo_size;
+       int skip_preamble;
+       struct spi_bus *bus;            /* Pointer to our SPI bus info */
+       ulong last_transaction_us;      /* Time of last transaction end */
+};
+
+
+We should rename this to make its purpose more obvious, and get rid of
+the slave structure, so we have:
+
+struct exynos_spi_priv {
+       struct exynos_spi *regs;
+       unsigned int freq;              /* Default frequency */
+       unsigned int mode;
+       enum periph_id periph_id;       /* Peripheral ID for this device */
+       unsigned int fifo_size;
+       int skip_preamble;
+       ulong last_transaction_us;      /* Time of last transaction end */
+};
+
+
+DM can auto-allocate this also:
+
+U_BOOT_DRIVER(spi_exynos) = {
+...
+       .priv_auto_alloc_size = sizeof(struct exynos_spi_priv),
+
+
+Note that this is created before the probe method is called, and destroyed
+after the remove method is called. It will be zeroed when the probe
+method is called.
+
+
+10. Add the probe() and remove() methods
+
+Note: It's a good idea to build repeatedly as you are working, to avoid a
+huge amount of work getting things compiling at the end.
+
+The probe method is supposed to set up the hardware. U-Boot used to use
+spi_setup_slave() to do this. So take a look at this function and see
+what you can copy out to set things up.
+
+
+static int exynos_spi_probe(struct udevice *bus)
+{
+       struct exynos_spi_platdata *plat = dev_get_platdata(bus);
+       struct exynos_spi_priv *priv = dev_get_priv(bus);
+
+       priv->regs = plat->regs;
+       if (plat->periph_id == PERIPH_ID_SPI1 ||
+           plat->periph_id == PERIPH_ID_SPI2)
+               priv->fifo_size = 64;
+       else
+               priv->fifo_size = 256;
+
+       priv->skip_preamble = 0;
+       priv->last_transaction_us = timer_get_us();
+       priv->freq = plat->frequency;
+       priv->periph_id = plat->periph_id;
+
+       return 0;
+}
+
+This implementation doesn't actually touch the hardware, which is somewhat
+unusual for a driver. In this case we will do that when the device is
+claimed by something that wants to use the SPI bus.
+
+For remove we could shut down the clocks, but in this case there is
+nothing to do. DM frees any memory that it allocated, so we can just
+remove exynos_spi_remove() and its reference in U_BOOT_DRIVER.
+
+
+11. Implement set_speed()
+
+This should set up clocks so that the SPI bus is running at the right
+speed. With the old API spi_claim_bus() would normally do this and several
+of the following functions, so let's look at that function:
+
+int spi_claim_bus(struct spi_slave *slave)
+{
+       struct exynos_spi_slave *spi_slave = to_exynos_spi(slave);
+       struct exynos_spi *regs = spi_slave->regs;
+       u32 reg = 0;
+       int ret;
+
+       ret = set_spi_clk(spi_slave->periph_id,
+                                       spi_slave->freq);
+       if (ret < 0) {
+               debug("%s: Failed to setup spi clock\n", __func__);
+               return ret;
+       }
+
+       exynos_pinmux_config(spi_slave->periph_id, PINMUX_FLAG_NONE);
+
+       spi_flush_fifo(slave);
+
+       reg = readl(&regs->ch_cfg);
+       reg &= ~(SPI_CH_CPHA_B | SPI_CH_CPOL_L);
+
+       if (spi_slave->mode & SPI_CPHA)
+               reg |= SPI_CH_CPHA_B;
+
+       if (spi_slave->mode & SPI_CPOL)
+               reg |= SPI_CH_CPOL_L;
+
+       writel(reg, &regs->ch_cfg);
+       writel(SPI_FB_DELAY_180, &regs->fb_clk);
+
+       return 0;
+}
+
+
+It sets up the speed, mode, pinmux, feedback delay and clears the FIFOs.
+With DM these will happen in separate methods.
+
+
+Here is an example for the speed part:
+
+static int exynos_spi_set_speed(struct udevice *bus, uint speed)
+{
+       struct exynos_spi_platdata *plat = bus->platdata;
+       struct exynos_spi_priv *priv = dev_get_priv(bus);
+       int ret;
+
+       if (speed > plat->frequency)
+               speed = plat->frequency;
+       ret = set_spi_clk(priv->periph_id, speed);
+       if (ret)
+               return ret;
+       priv->freq = speed;
+       debug("%s: regs=%p, speed=%d\n", __func__, priv->regs, priv->freq);
+
+       return 0;
+}
+
+
+12. Implement set_mode()
+
+This should adjust the SPI mode (polarity, etc.). Again this code probably
+comes from the old spi_claim_bus(). Here is an example:
+
+
+static int exynos_spi_set_mode(struct udevice *bus, uint mode)
+{
+       struct exynos_spi_priv *priv = dev_get_priv(bus);
+       uint32_t reg;
+
+       reg = readl(&priv->regs->ch_cfg);
+       reg &= ~(SPI_CH_CPHA_B | SPI_CH_CPOL_L);
+
+       if (mode & SPI_CPHA)
+               reg |= SPI_CH_CPHA_B;
+
+       if (mode & SPI_CPOL)
+               reg |= SPI_CH_CPOL_L;
+
+       writel(reg, &priv->regs->ch_cfg);
+       priv->mode = mode;
+       debug("%s: regs=%p, mode=%d\n", __func__, priv->regs, priv->mode);
+
+       return 0;
+}
+
+
+13. Implement claim_bus()
+
+This is where a client wants to make use of the bus, so claims it first.
+At this point we need to make sure everything is set up ready for data
+transfer. Note that this function is wholly internal to the driver - at
+present the SPI uclass never calls it.
+
+Here again we look at the old claim function and see some code that is
+needed. It is anything unrelated to speed and mode:
+
+static int exynos_spi_claim_bus(struct udevice *bus)
+{
+       struct exynos_spi_priv *priv = dev_get_priv(bus);
+
+       exynos_pinmux_config(priv->periph_id, PINMUX_FLAG_NONE);
+       spi_flush_fifo(priv->regs);
+
+       writel(SPI_FB_DELAY_180, &priv->regs->fb_clk);
+
+       return 0;
+}
+
+The spi_flush_fifo() function is in the removed part of the code, so we
+need to expose it again (perhaps with an #endif before it and '#if 0'
+after it). It only needs access to priv->regs which is why we have
+passed that in:
+
+/**
+ * Flush spi tx, rx fifos and reset the SPI controller
+ *
+ * @param regs Pointer to SPI registers
+ */
+static void spi_flush_fifo(struct exynos_spi *regs)
+{
+       clrsetbits_le32(&regs->ch_cfg, SPI_CH_HS_EN, SPI_CH_RST);
+       clrbits_le32(&regs->ch_cfg, SPI_CH_RST);
+       setbits_le32(&regs->ch_cfg, SPI_TX_CH_ON | SPI_RX_CH_ON);
+}
+
+
+14. Implement release_bus()
+
+This releases the bus - in our example the old code in spi_release_bus()
+is a call to spi_flush_fifo, so we add:
+
+static int exynos_spi_release_bus(struct udevice *bus)
+{
+       struct exynos_spi_priv *priv = dev_get_priv(bus);
+
+       spi_flush_fifo(priv->regs);
+
+       return 0;
+}
+
+
+15. Implement xfer()
+
+This is the final method that we need to create, and it is where all the
+work happens. The method parameters are the same as the old spi_xfer() with
+the addition of a 'struct udevice' so conversion is pretty easy. Start
+by copying the contents of spi_xfer() to your new xfer() method and proceed
+from there.
+
+If (flags & SPI_XFER_BEGIN) is non-zero then xfer() normally calls an
+activate function, something like this:
+
+void spi_cs_activate(struct spi_slave *slave)
+{
+       struct exynos_spi_slave *spi_slave = to_exynos_spi(slave);
+
+       /* If it's too soon to do another transaction, wait */
+       if (spi_slave->bus->deactivate_delay_us &&
+           spi_slave->last_transaction_us) {
+               ulong delay_us;         /* The delay completed so far */
+               delay_us = timer_get_us() - spi_slave->last_transaction_us;
+               if (delay_us < spi_slave->bus->deactivate_delay_us)
+                       udelay(spi_slave->bus->deactivate_delay_us - delay_us);
+       }
+
+       clrbits_le32(&spi_slave->regs->cs_reg, SPI_SLAVE_SIG_INACT);
+       debug("Activate CS, bus %d\n", spi_slave->slave.bus);
+       spi_slave->skip_preamble = spi_slave->mode & SPI_PREAMBLE;
+}
+
+The new version looks like this:
+
+static void spi_cs_activate(struct udevice *dev)
+{
+       struct udevice *bus = dev->parent;
+       struct exynos_spi_platdata *pdata = dev_get_platdata(bus);
+       struct exynos_spi_priv *priv = dev_get_priv(bus);
+
+       /* If it's too soon to do another transaction, wait */
+       if (pdata->deactivate_delay_us &&
+           priv->last_transaction_us) {
+               ulong delay_us;         /* The delay completed so far */
+               delay_us = timer_get_us() - priv->last_transaction_us;
+               if (delay_us < pdata->deactivate_delay_us)
+                       udelay(pdata->deactivate_delay_us - delay_us);
+       }
+
+       clrbits_le32(&priv->regs->cs_reg, SPI_SLAVE_SIG_INACT);
+       debug("Activate CS, bus '%s'\n", bus->name);
+       priv->skip_preamble = priv->mode & SPI_PREAMBLE;
+}
+
+All we have really done here is change the pointers and print the device name
+instead of the bus number. Other local static functions can be treated in
+the same way.
+
+
+16. Set up the per-child data and child pre-probe function
+
+To minimise the pain and complexity of the SPI subsystem while the driver
+model change-over is in place, struct spi_slave is used to reference a
+SPI bus slave, even though that slave is actually a struct udevice. In fact
+struct spi_slave is the device's child data. We need to make sure this space
+is available. It is possible to allocate more space that struct spi_slave
+needs, but this is the minimum.
+
+U_BOOT_DRIVER(exynos_spi) = {
+...
+       .per_child_auto_alloc_size      = sizeof(struct spi_slave),
+}
+
+
+17. Optional: Set up cs_info() if you want it
+
+Sometimes it is useful to know whether a SPI chip select is valid, but this
+is not obvious from outside the driver. In this case you can provide a
+method for cs_info() to deal with this. If you don't provide it, then the
+device tree will be used to determine what chip selects are valid.
+
+Return -ENODEV if the supplied chip select is invalid, or 0 if it is valid.
+If you don't provide the cs_info() method, -ENODEV is assumed for all
+chip selects that do not appear in the device tree.
+
+
+18. Test it
+
+Now that you have the code written and it compiles, try testing it using
+the 'sf test' command. You may need to enable CONFIG_CMD_SF_TEST for your
+board.
+
+
+19. Prepare patches and send them to the mailing lists
+
+You can use 'tools/patman/patman' to prepare, check and send patches for
+your work. See the README for details.
index ef3ab8f726a1326e0e878bd75ae3254e08dd6b26..539cdbfafec0d8f63d3cd298323525f2f3e04cb7 100644 (file)
                };
        };
 };
+
+
+
+For x86 a setup node is also required: see x86-fit-boot.txt.
+
+/dts-v1/;
+
+/ {
+       description = "Simple image with single Linux kernel on x86";
+       #address-cells = <1>;
+
+       images {
+               kernel@1 {
+                       description = "Vanilla Linux kernel";
+                       data = /incbin/("./image.bin.lzo");
+                       type = "kernel";
+                       arch = "x86";
+                       os = "linux";
+                       compression = "lzo";
+                       load = <0x01000000>;
+                       entry = <0x00000000>;
+                       hash@2 {
+                               algo = "sha1";
+                       };
+               };
+
+               setup@1 {
+                       description = "Linux setup.bin";
+                       data = /incbin/("./setup.bin");
+                       type = "x86_setup";
+                       arch = "x86";
+                       os = "linux";
+                       compression = "none";
+                       load = <0x00090000>;
+                       entry = <0x00090000>;
+                       hash@2 {
+                               algo = "sha1";
+                       };
+               };
+       };
+
+       configurations {
+               default = "config@1";
+               config@1 {
+                       description = "Boot Linux kernel";
+                       kernel = "kernel@1";
+                       setup = "setup@1";
+               };
+       };
+};
index 9ed6f65e599383f837cc611e43d2c05a659b956c..b47ce73b8323a4034bbd58c77ce50d49f5492b38 100644 (file)
@@ -55,7 +55,7 @@ FIT is formally a flattened device tree (in the libfdt meaning), which
 conforms to bindings defined in this document.
 
 .its   - image tree source
-.itb   - image tree blob
+.fit   - flattened image tree blob
 
 c) Image building procedure
 
@@ -101,15 +101,15 @@ Root node of the uImage Tree should have the following layout:
     |
     o images
     | |
-    | o img@1 {...}
-    | o img@2 {...}
+    | o image@1 {...}
+    | o image@2 {...}
     | ...
     |
     o configurations
-      |- default = "cfg@1"
+      |- default = "conf@1"
       |
-      o cfg@1 {...}
-      o cfg@2 {...}
+      o conf@1 {...}
+      o conf@2 {...}
       ...
 
 
@@ -159,7 +159,7 @@ the '/images' node should have the following layout:
   - description : Textual description of the component sub-image
   - type : Name of component sub-image type, supported types are:
     "standalone", "kernel", "ramdisk", "firmware", "script", "filesystem",
-    "flat_dt".
+    "flat_dt" and others (see uimage_type in common/images.c).
   - data : Path to the external file which contains this node's binary data.
   - compression : Compression used by included data. Supported compressions
     are "gzip" and "bzip2". If no compression is used compression property
@@ -173,7 +173,8 @@ the '/images' node should have the following layout:
   - arch : Architecture name, mandatory for types: "standalone", "kernel",
     "firmware", "ramdisk" and "fdt". Valid architecture names are: "alpha",
     "arm", "i386", "ia64", "mips", "mips64", "ppc", "s390", "sh", "sparc",
-    "sparc64", "m68k", "microblaze", "nios2", "blackfin", "avr32", "st200".
+    "sparc64", "m68k", "microblaze", "nios2", "blackfin", "avr32", "st200",
+    "sandbox".
   - entry : entry point address, address size is determined by
     '#address-cells' property of the root node. Mandatory for for types:
     "standalone" and "kernel".
@@ -246,6 +247,8 @@ o config@1
     node of a "ramdisk" type).
   - fdt : Unit name of the corresponding fdt blob (component image node of a
     "fdt type").
+  - setup : Unit name of the corresponding setup binary (used for booting
+    an x86 kernel). This contains the setup.bin file built by the kernel.
 
 The FDT blob is required to properly boot FDT based kernel, so the minimal
 configuration for 2.6 FDT kernel is (kernel, fdt) pair.
diff --git a/doc/uImage.FIT/x86-fit-boot.txt b/doc/uImage.FIT/x86-fit-boot.txt
new file mode 100644 (file)
index 0000000..61c10ff
--- /dev/null
@@ -0,0 +1,276 @@
+Booting Linux on x86 with FIT
+=============================
+
+Background
+----------
+
+(corrections to the text below are welcome)
+
+Generally Linux x86 uses its own very complex booting method. There is a setup
+binary which contains all sorts of parameters and a compressed self-extracting
+binary for the kernel itself, often with a small built-in serial driver to
+display decompression progress.
+
+The x86 CPU has various processor modes. I am no expert on these, but my
+understanding is that an x86 CPU (even a really new one) starts up in a 16-bit
+'real' mode where only 1MB of memory is visible, moves to 32-bit 'protected'
+mode where 4GB is visible (or more with special memory access techniques) and
+then to 64-bit 'long' mode if 64-bit execution is required.
+
+Partly the self-extracting nature of Linux was introduced to cope with boot
+loaders that were barely capable of loading anything. Even changing to 32-bit
+mode was something of a challenge, so putting this logic in the kernel seemed
+to make sense.
+
+Bit by bit more and more logic has been added to this post-boot pre-Linux
+wrapper:
+
+- Changing to 32-bit mode
+- Decompression
+- Serial output (with drivers for various chips)
+- Load address randomisation
+- Elf loader complete with relocation (for the above)
+- Random number generator via 3 methods (again for the above)
+- Some sort of EFI mini-loader (1000+ glorious lines of code)
+- Locating and tacking on a device tree and ramdisk
+
+To my mind, if you sit back and look at things from first principles, this
+doesn't make a huge amount of sense. Any boot loader worth its salts already
+has most of the above features and more besides. The boot loader already knows
+the layout of memory, has a serial driver, can decompress things, includes an
+ELF loader and supports device tree and ramdisks. The decision to duplicate
+all these features in a Linux wrapper caters for the lowest common
+denominator: a boot loader which consists of a BIOS call to load something off
+disk, followed by a jmp instruction.
+
+(Aside: On ARM systems, we worry that the boot loader won't know where to load
+the kernel. It might be easier to just provide that information in the image,
+or in the boot loader rather than adding a self-relocator to put it in the
+right place. Or just use ELF?
+
+As a result, the x86 kernel boot process is needlessly complex. The file
+format is also complex, and obfuscates the contents to a degree that it is
+quite a challenge to extract anything from it. This bzImage format has become
+so prevalent that is actually isn't possible to produce the 'raw' kernel build
+outputs with the standard Makefile (as it is on ARM for example, at least at
+the time of writing).
+
+This document describes an alternative boot process which uses simple raw
+images which are loaded into the right place by the boot loader and then
+executed.
+
+
+Build the kernel
+----------------
+
+Note: these instructions assume a 32-bit kernel. U-Boot does not currently
+support booting a 64-bit kernel as it has no way of going into 64-bit mode on
+x86.
+
+You can build the kernel as normal with 'make'. This will create a file called
+'vmlinux'. This is a standard ELF file and you can look at it if you like:
+
+$ objdump -h vmlinux
+
+vmlinux:     file format elf32-i386
+
+Sections:
+Idx Name          Size      VMA       LMA       File off  Algn
+  0 .text         00416850  81000000  01000000  00001000  2**5
+                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
+  1 .notes        00000024  81416850  01416850  00417850  2**2
+                  CONTENTS, ALLOC, LOAD, READONLY, CODE
+  2 __ex_table    00000c50  81416880  01416880  00417880  2**3
+                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
+  3 .rodata       00154b9e  81418000  01418000  00419000  2**5
+                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
+  4 __bug_table   0000597c  8156cba0  0156cba0  0056dba0  2**0
+                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
+  5 .pci_fixup    00001b80  8157251c  0157251c  0057351c  2**2
+                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
+  6 .tracedata    00000024  8157409c  0157409c  0057509c  2**0
+                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
+  7 __ksymtab     00007ec0  815740c0  015740c0  005750c0  2**2
+                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
+  8 __ksymtab_gpl 00004a28  8157bf80  0157bf80  0057cf80  2**2
+                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
+  9 __ksymtab_strings 0001d6fc  815809a8  015809a8  005819a8  2**0
+                  CONTENTS, ALLOC, LOAD, READONLY, DATA
+ 10 __init_rodata 00001c3c  8159e0a4  0159e0a4  0059f0a4  2**2
+                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
+ 11 __param       00000ff0  8159fce0  0159fce0  005a0ce0  2**2
+                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
+ 12 __modver      00000330  815a0cd0  015a0cd0  005a1cd0  2**2
+                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
+ 13 .data         00063000  815a1000  015a1000  005a2000  2**12
+                  CONTENTS, ALLOC, LOAD, RELOC, DATA
+ 14 .init.text    0002f104  81604000  01604000  00605000  2**2
+                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
+ 15 .init.data    00040cdc  81634000  01634000  00635000  2**12
+                  CONTENTS, ALLOC, LOAD, RELOC, DATA
+ 16 .x86_cpu_dev.init 0000001c  81674cdc  01674cdc  00675cdc  2**2
+                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
+ 17 .altinstructions 0000267c  81674cf8  01674cf8  00675cf8  2**0
+                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
+ 18 .altinstr_replacement 00000942  81677374  01677374  00678374  2**0
+                  CONTENTS, ALLOC, LOAD, READONLY, CODE
+ 19 .iommu_table  00000014  81677cb8  01677cb8  00678cb8  2**2
+                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
+ 20 .apicdrivers  00000004  81677cd0  01677cd0  00678cd0  2**2
+                  CONTENTS, ALLOC, LOAD, RELOC, DATA
+ 21 .exit.text    00001a80  81677cd8  01677cd8  00678cd8  2**0
+                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
+ 22 .data..percpu 00007880  8167a000  0167a000  0067b000  2**12
+                  CONTENTS, ALLOC, LOAD, RELOC, DATA
+ 23 .smp_locks    00003000  81682000  01682000  00683000  2**2
+                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
+ 24 .bss          000a1000  81685000  01685000  00686000  2**12
+                  ALLOC
+ 25 .brk          00424000  81726000  01726000  00686000  2**0
+                  ALLOC
+ 26 .comment      00000049  00000000  00000000  00686000  2**0
+                  CONTENTS, READONLY
+ 27 .GCC.command.line 0003e055  00000000  00000000  00686049  2**0
+                  CONTENTS, READONLY
+ 28 .debug_aranges 0000f4c8  00000000  00000000  006c40a0  2**3
+                  CONTENTS, RELOC, READONLY, DEBUGGING
+ 29 .debug_info   0440b0df  00000000  00000000  006d3568  2**0
+                  CONTENTS, RELOC, READONLY, DEBUGGING
+ 30 .debug_abbrev 0022a83b  00000000  00000000  04ade647  2**0
+                  CONTENTS, READONLY, DEBUGGING
+ 31 .debug_line   004ead0d  00000000  00000000  04d08e82  2**0
+                  CONTENTS, RELOC, READONLY, DEBUGGING
+ 32 .debug_frame  0010a960  00000000  00000000  051f3b90  2**2
+                  CONTENTS, RELOC, READONLY, DEBUGGING
+ 33 .debug_str    001b442d  00000000  00000000  052fe4f0  2**0
+                  CONTENTS, READONLY, DEBUGGING
+ 34 .debug_loc    007c7fa9  00000000  00000000  054b291d  2**0
+                  CONTENTS, RELOC, READONLY, DEBUGGING
+ 35 .debug_ranges 00098828  00000000  00000000  05c7a8c8  2**3
+                  CONTENTS, RELOC, READONLY, DEBUGGING
+
+There is also the setup binary mentioned earlier. This is at
+arch/x86/boot/setup.bin and is about 12KB in size. It includes the command
+line and various settings need by the kernel. Arguably the boot loader should
+provide all of this also, but setting it up is some complex that the kernel
+helps by providing a head start.
+
+As you can see the code loads to address 0x01000000 and everything else
+follows after that. We could load this image using the 'bootelf' command but
+we would still need to provide the setup binary. This is not supported by
+U-Boot although I suppose you could mostly script it. This would permit the
+use of a relocatable kernel.
+
+All we need to boot is the vmlinux file and the setup.bin file.
+
+
+Create a FIT
+------------
+
+To create a FIT you will need a source file describing what should go in the
+FIT. See kernel.its for an example for x86. Put this into a file called
+image.its.
+
+Note that setup is loaded to the special address of 0x90000 (a special address
+you just have to know) and the kernel is loaded to 0x01000000 (the address you
+saw above). This means that you will need to load your FIT to a different
+address so that U-Boot doesn't overwrite it when decompressing. Something like
+0x02000000 will do so you can set CONFIG_SYS_LOAD_ADDR to that.
+
+In that example the kernel is compressed with lzo. Also we need to provide a
+flat binary, not an ELF. So the steps needed to set things are are:
+
+   # Create a flat binary
+   objcopy -O binary vmlinux vmlinux.bin
+
+   # Compress it into LZO format
+   lzop vmlinux.bin
+
+   # Build a FIT image
+   mkimage -f image.its image.fit
+
+(be careful to run the mkimage from your U-Boot tools directory since it
+will have x86_setup support.)
+
+You can take a look at the resulting fit file if you like:
+
+$ dumpimage -l image.fit
+FIT description: Simple image with single Linux kernel on x86
+Created:         Tue Oct  7 10:57:24 2014
+ Image 0 (kernel@1)
+  Description:  Vanilla Linux kernel
+  Created:      Tue Oct  7 10:57:24 2014
+  Type:         Kernel Image
+  Compression:  lzo compressed
+  Data Size:    4591767 Bytes = 4484.15 kB = 4.38 MB
+  Architecture: Intel x86
+  OS:           Linux
+  Load Address: 0x01000000
+  Entry Point:  0x00000000
+  Hash algo:    sha1
+  Hash value:   446b5163ebfe0fb6ee20cbb7a8501b263cd92392
+ Image 1 (setup@1)
+  Description:  Linux setup.bin
+  Created:      Tue Oct  7 10:57:24 2014
+  Type:         x86 setup.bin
+  Compression:  uncompressed
+  Data Size:    12912 Bytes = 12.61 kB = 0.01 MB
+  Hash algo:    sha1
+  Hash value:   a1f2099cf47ff9816236cd534c77af86e713faad
+ Default Configuration: 'config@1'
+ Configuration 0 (config@1)
+  Description:  Boot Linux kernel
+  Kernel:       kernel@1
+
+
+Booting the FIT
+---------------
+
+To make it boot you need to load it and then use 'bootm' to boot it. A
+suitable script to do this from a network server is:
+
+   bootp
+   tftp image.fit
+   bootm
+
+This will load the image from the network and boot it. The command line (from
+the 'bootargs' environment variable) will be passed to the kernel.
+
+If you want a ramdisk you can add it as normal with FIT. If you want a device
+tree then x86 doesn't normally use those - it has ACPI instead.
+
+
+Why Bother?
+-----------
+
+1. It demystifies the process of booting an x86 kernel
+2. It allows use of the standard U-Boot boot file format
+3. It allows U-Boot to perform decompression - problems will provide an error
+message and you are still in the boot loader. It is possible to investigate.
+4. It avoids all the pre-loader code in the kernel which is quite complex to
+follow
+5. You can use verified/secure boot and other features which haven't yet been
+added to the pre-Linux
+6. It makes x86 more like other architectures in the way it boots a kernel.
+You can potentially use the same file format for the kernel, and the same
+procedure for building and packaging it.
+
+
+References
+----------
+
+In the Linux kernel, Documentation/x86/boot.txt defines the boot protocol for
+the kernel including the setup.bin format. This is handled in U-Boot in
+arch/x86/lib/zimage.c and arch/x86/lib/bootm.c.
+
+The procedure for entering 64-bit mode on x86 seems to be described here:
+
+   http://wiki.osdev.org/64-bit_Higher_Half_Kernel_with_GRUB_2
+
+Various files in the same directory as this file describe the FIT format.
+
+
+--
+Simon Glass
+sjg@chromium.org
+7-Oct-2014
index c7905b14409fcf4fe56653655960de8407c5348b..151c2398a4d47fce304d43a6ae775befd379baa2 100644 (file)
@@ -5,3 +5,4 @@
 #
 
 obj-y := device.o lists.o root.o uclass.o util.o
+obj-$(CONFIG_OF_CONTROL) += simple-bus.o
index 32e80e82b59c99f9ac5734c8f3dadc7c3b0c5f28..49faa29dc1a0eecaa84e76371b8301c2eef14d7b 100644 (file)
@@ -232,7 +232,7 @@ static void device_free(struct udevice *dev)
        }
 }
 
-int device_probe(struct udevice *dev)
+int device_probe_child(struct udevice *dev, void *parent_priv)
 {
        struct driver *drv;
        int size = 0;
@@ -282,6 +282,8 @@ int device_probe(struct udevice *dev)
                                ret = -ENOMEM;
                                goto fail;
                        }
+                       if (parent_priv)
+                               memcpy(dev->parent_priv, parent_priv, size);
                }
 
                ret = device_probe(dev->parent);
@@ -335,6 +337,11 @@ fail:
        return ret;
 }
 
+int device_probe(struct udevice *dev)
+{
+       return device_probe_child(dev, NULL);
+}
+
 int device_remove(struct udevice *dev)
 {
        struct driver *drv;
@@ -514,3 +521,30 @@ int device_get_child_by_of_offset(struct udevice *parent, int seq,
        ret = device_find_child_by_of_offset(parent, seq, &dev);
        return device_get_device_tail(dev, ret, devp);
 }
+
+int device_find_first_child(struct udevice *parent, struct udevice **devp)
+{
+       if (list_empty(&parent->child_head)) {
+               *devp = NULL;
+       } else {
+               *devp = list_first_entry(&parent->child_head, struct udevice,
+                                        sibling_node);
+       }
+
+       return 0;
+}
+
+int device_find_next_child(struct udevice **devp)
+{
+       struct udevice *dev = *devp;
+       struct udevice *parent = dev->parent;
+
+       if (list_is_last(&dev->sibling_node, &parent->child_head)) {
+               *devp = NULL;
+       } else {
+               *devp = list_entry(dev->sibling_node.next, struct udevice,
+                                  sibling_node);
+       }
+
+       return 0;
+}
index 699f94b435f213a0e78e91e4d2e854ae45473e7b..3a1ea8565449699a39ba5684dbecfbf71e30780b 100644 (file)
@@ -24,19 +24,12 @@ struct driver *lists_driver_lookup_name(const char *name)
                ll_entry_start(struct driver, driver);
        const int n_ents = ll_entry_count(struct driver, driver);
        struct driver *entry;
-       int len;
 
        if (!drv || !n_ents)
                return NULL;
 
-       len = strlen(name);
-
        for (entry = drv; entry != drv + n_ents; entry++) {
-               if (strncmp(name, entry->name, len))
-                       continue;
-
-               /* Full match */
-               if (len == strlen(entry->name))
+               if (!strcmp(name, entry->name))
                        return entry;
        }
 
diff --git a/drivers/core/simple-bus.c b/drivers/core/simple-bus.c
new file mode 100644 (file)
index 0000000..3ea4d82
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/root.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int simple_bus_post_bind(struct udevice *dev)
+{
+       return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
+}
+
+UCLASS_DRIVER(simple_bus) = {
+       .id             = UCLASS_SIMPLE_BUS,
+       .name           = "simple_bus",
+       .post_bind      = simple_bus_post_bind,
+};
+
+static const struct udevice_id generic_simple_bus_ids[] = {
+       { .compatible = "simple-bus" },
+       { }
+};
+
+U_BOOT_DRIVER(simple_bus_drv) = {
+       .name   = "generic_simple_bus",
+       .id     = UCLASS_SIMPLE_BUS,
+       .of_match = generic_simple_bus_ids,
+};
index 61ca17e564a25dff143da7c26b8d886dab90de04..901b06ed2baaf5f4b0cbdb71d3ca40170de33991 100644 (file)
@@ -60,10 +60,6 @@ static int uclass_add(enum uclass_id id, struct uclass **ucp)
                        id);
                return -ENOENT;
        }
-       if (uc_drv->ops) {
-               dm_warn("No ops for uclass id %d\n", id);
-               return -EINVAL;
-       }
        uc = calloc(1, sizeof(*uc));
        if (!uc)
                return -ENOMEM;
index 91f6df220b1dd7f11aabdaddb28fa7e3db32b44e..c3d3c3bcd85355b77dc8cb1d4c945a589f550781 100644 (file)
@@ -9,6 +9,7 @@
 #include <errno.h>
 #include <div64.h>
 #include <dfu.h>
+#include <spi.h>
 #include <spi_flash.h>
 
 static long dfu_get_medium_size_sf(struct dfu_entity *dfu)
index 97b51371145e81de9f268a33f001c72d6f63ff98..332cfc2b231835ca7c4ffd9f0ead44b2a8351730 100644 (file)
  */
 
 #include <common.h>
+#include <dm.h>
+#include <errno.h>
 #include <asm/gpio.h>
 #include <asm/io.h>
 
-inline int gpio_is_valid(unsigned gpio)
+#define GPIO_NAME_SIZE         20
+
+struct bcm2835_gpios {
+       char label[BCM2835_GPIO_COUNT][GPIO_NAME_SIZE];
+       struct bcm2835_gpio_regs *reg;
+};
+
+/**
+ * gpio_is_requested() - check if a GPIO has been requested
+ *
+ * @bank:      Bank to check
+ * @offset:    GPIO offset within bank to check
+ * @return true if marked as requested, false if not
+ */
+static inline bool gpio_is_requested(struct bcm2835_gpios *gpios, int offset)
 {
-       return (gpio < BCM2835_GPIO_COUNT);
+       return *gpios->label[offset] != '\0';
 }
 
-int gpio_request(unsigned gpio, const char *label)
+static int check_requested(struct udevice *dev, unsigned offset,
+                          const char *func)
 {
-       return !gpio_is_valid(gpio);
+       struct bcm2835_gpios *gpios = dev_get_priv(dev);
+       struct gpio_dev_priv *uc_priv = dev->uclass_priv;
+
+       if (!gpio_is_requested(gpios, offset)) {
+               printf("omap_gpio: %s: error: gpio %s%d not requested\n",
+                      func, uc_priv->bank_name, offset);
+               return -EPERM;
+       }
+
+       return 0;
 }
 
-int gpio_free(unsigned gpio)
+static int bcm2835_gpio_request(struct udevice *dev, unsigned offset,
+                               const char *label)
 {
+       struct bcm2835_gpios *gpios = dev_get_priv(dev);
+
+       if (gpio_is_requested(gpios, offset))
+               return -EBUSY;
+
+       strncpy(gpios->label[offset], label, GPIO_NAME_SIZE);
+       gpios->label[offset][GPIO_NAME_SIZE - 1] = '\0';
+
        return 0;
 }
 
-int gpio_direction_input(unsigned gpio)
+static int bcm2835_gpio_free(struct udevice *dev, unsigned offset)
 {
-       struct bcm2835_gpio_regs *reg =
-               (struct bcm2835_gpio_regs *)BCM2835_GPIO_BASE;
+       struct bcm2835_gpios *gpios = dev_get_priv(dev);
+       int ret;
+
+       ret = check_requested(dev, offset, __func__);
+       if (ret)
+               return ret;
+       gpios->label[offset][0] = '\0';
+
+       return 0;
+}
+
+static int bcm2835_gpio_direction_input(struct udevice *dev, unsigned gpio)
+{
+       struct bcm2835_gpios *gpios = dev_get_priv(dev);
        unsigned val;
 
-       val = readl(&reg->gpfsel[BCM2835_GPIO_FSEL_BANK(gpio)]);
+       val = readl(&gpios->reg->gpfsel[BCM2835_GPIO_FSEL_BANK(gpio)]);
        val &= ~(BCM2835_GPIO_FSEL_MASK << BCM2835_GPIO_FSEL_SHIFT(gpio));
        val |= (BCM2835_GPIO_INPUT << BCM2835_GPIO_FSEL_SHIFT(gpio));
-       writel(val, &reg->gpfsel[BCM2835_GPIO_FSEL_BANK(gpio)]);
+       writel(val, &gpios->reg->gpfsel[BCM2835_GPIO_FSEL_BANK(gpio)]);
 
        return 0;
 }
 
-int gpio_direction_output(unsigned gpio, int value)
+static int bcm2835_gpio_direction_output(struct udevice *dev, unsigned gpio,
+                                        int value)
 {
-       struct bcm2835_gpio_regs *reg =
-               (struct bcm2835_gpio_regs *)BCM2835_GPIO_BASE;
+       struct bcm2835_gpios *gpios = dev_get_priv(dev);
        unsigned val;
 
        gpio_set_value(gpio, value);
 
-       val = readl(&reg->gpfsel[BCM2835_GPIO_FSEL_BANK(gpio)]);
+       val = readl(&gpios->reg->gpfsel[BCM2835_GPIO_FSEL_BANK(gpio)]);
        val &= ~(BCM2835_GPIO_FSEL_MASK << BCM2835_GPIO_FSEL_SHIFT(gpio));
        val |= (BCM2835_GPIO_OUTPUT << BCM2835_GPIO_FSEL_SHIFT(gpio));
-       writel(val, &reg->gpfsel[BCM2835_GPIO_FSEL_BANK(gpio)]);
+       writel(val, &gpios->reg->gpfsel[BCM2835_GPIO_FSEL_BANK(gpio)]);
 
        return 0;
 }
 
-int gpio_get_value(unsigned gpio)
+static bool bcm2835_gpio_is_output(const struct bcm2835_gpios *gpios, int gpio)
+{
+       u32 val;
+
+       val = readl(&gpios->reg->gpfsel[BCM2835_GPIO_FSEL_BANK(gpio)]);
+       val &= BCM2835_GPIO_FSEL_MASK << BCM2835_GPIO_FSEL_SHIFT(gpio);
+       return val ? true : false;
+}
+
+static int bcm2835_get_value(const struct bcm2835_gpios *gpios, unsigned gpio)
 {
-       struct bcm2835_gpio_regs *reg =
-               (struct bcm2835_gpio_regs *)BCM2835_GPIO_BASE;
        unsigned val;
 
-       val = readl(&reg->gplev[BCM2835_GPIO_COMMON_BANK(gpio)]);
+       val = readl(&gpios->reg->gplev[BCM2835_GPIO_COMMON_BANK(gpio)]);
 
        return (val >> BCM2835_GPIO_COMMON_SHIFT(gpio)) & 0x1;
 }
 
-int gpio_set_value(unsigned gpio, int value)
+static int bcm2835_gpio_get_value(struct udevice *dev, unsigned gpio)
 {
-       struct bcm2835_gpio_regs *reg =
-               (struct bcm2835_gpio_regs *)BCM2835_GPIO_BASE;
-       u32 *output_reg = value ? reg->gpset : reg->gpclr;
+       const struct bcm2835_gpios *gpios = dev_get_priv(dev);
+
+       return bcm2835_get_value(gpios, gpio);
+}
+
+static int bcm2835_gpio_set_value(struct udevice *dev, unsigned gpio,
+                                 int value)
+{
+       struct bcm2835_gpios *gpios = dev_get_priv(dev);
+       u32 *output_reg = value ? gpios->reg->gpset : gpios->reg->gpclr;
 
        writel(1 << BCM2835_GPIO_COMMON_SHIFT(gpio),
                                &output_reg[BCM2835_GPIO_COMMON_BANK(gpio)]);
 
        return 0;
 }
+
+static int bcm2835_gpio_get_function(struct udevice *dev, unsigned offset)
+{
+       struct bcm2835_gpios *gpios = dev_get_priv(dev);
+
+       if (!gpio_is_requested(gpios, offset))
+               return GPIOF_UNUSED;
+
+       /* GPIOF_FUNC is not implemented yet */
+       if (bcm2835_gpio_is_output(gpios, offset))
+               return GPIOF_OUTPUT;
+       else
+               return GPIOF_INPUT;
+}
+
+static int bcm2835_gpio_get_state(struct udevice *dev, unsigned int offset,
+                                 char *buf, int bufsize)
+{
+       struct gpio_dev_priv *uc_priv = dev->uclass_priv;
+       struct bcm2835_gpios *gpios = dev_get_priv(dev);
+       const char *label;
+       bool requested;
+       bool is_output;
+       int size;
+
+       label = gpios->label[offset];
+       is_output = bcm2835_gpio_is_output(gpios, offset);
+       size = snprintf(buf, bufsize, "%s%d: ",
+                       uc_priv->bank_name ? uc_priv->bank_name : "", offset);
+       buf += size;
+       bufsize -= size;
+       requested = gpio_is_requested(gpios, offset);
+       snprintf(buf, bufsize, "%s: %d [%c]%s%s",
+                is_output ? "out" : " in",
+                bcm2835_get_value(gpios, offset),
+                requested ? 'x' : ' ',
+                requested ? " " : "",
+                label);
+
+       return 0;
+}
+
+static const struct dm_gpio_ops gpio_bcm2835_ops = {
+       .request                = bcm2835_gpio_request,
+       .free                   = bcm2835_gpio_free,
+       .direction_input        = bcm2835_gpio_direction_input,
+       .direction_output       = bcm2835_gpio_direction_output,
+       .get_value              = bcm2835_gpio_get_value,
+       .set_value              = bcm2835_gpio_set_value,
+       .get_function           = bcm2835_gpio_get_function,
+       .get_state              = bcm2835_gpio_get_state,
+};
+
+static int bcm2835_gpio_probe(struct udevice *dev)
+{
+       struct bcm2835_gpios *gpios = dev_get_priv(dev);
+       struct bcm2835_gpio_platdata *plat = dev_get_platdata(dev);
+       struct gpio_dev_priv *uc_priv = dev->uclass_priv;
+
+       uc_priv->bank_name = "GPIO";
+       uc_priv->gpio_count = BCM2835_GPIO_COUNT;
+       gpios->reg = (struct bcm2835_gpio_regs *)plat->base;
+
+       return 0;
+}
+
+U_BOOT_DRIVER(gpio_bcm2835) = {
+       .name   = "gpio_bcm2835",
+       .id     = UCLASS_GPIO,
+       .ops    = &gpio_bcm2835_ops,
+       .probe  = bcm2835_gpio_probe,
+       .priv_auto_alloc_size = sizeof(struct bcm2835_gpios),
+};
index 6a572d5454b39e4905da9094edd01f47cf451035..3f7b7d24416b4bb59b31f9d4a02fe3c41039ac20 100644 (file)
@@ -8,16 +8,31 @@
  * SPDX-License-Identifier:    GPL-2.0+
  */
 #include <common.h>
+#include <errno.h>
+#include <dm.h>
+#include <malloc.h>
 #include <asm/arch/imx-regs.h>
 #include <asm/gpio.h>
 #include <asm/io.h>
-#include <errno.h>
 
 enum mxc_gpio_direction {
        MXC_GPIO_DIRECTION_IN,
        MXC_GPIO_DIRECTION_OUT,
 };
 
+#define GPIO_NAME_SIZE                 20
+#define GPIO_PER_BANK                  32
+
+struct mxc_gpio_plat {
+       struct gpio_regs *regs;
+};
+
+struct mxc_bank_info {
+       char label[GPIO_PER_BANK][GPIO_NAME_SIZE];
+       struct gpio_regs *regs;
+};
+
+#ifndef CONFIG_DM_GPIO
 #define GPIO_TO_PORT(n)                (n / 32)
 
 /* GPIO port description */
@@ -134,3 +149,290 @@ int gpio_direction_output(unsigned gpio, int value)
 
        return mxc_gpio_direction(gpio, MXC_GPIO_DIRECTION_OUT);
 }
+#endif
+
+#ifdef CONFIG_DM_GPIO
+/**
+ * gpio_is_requested() - check if a GPIO has been requested
+ *
+ * @bank:      Bank to check
+ * @offset:    GPIO offset within bank to check
+ * @return true if marked as requested, false if not
+ */
+static inline bool gpio_is_requested(struct mxc_bank_info *bank, int offset)
+{
+       return *bank->label[offset] != '\0';
+}
+
+static int mxc_gpio_is_output(struct gpio_regs *regs, int offset)
+{
+       u32 val;
+
+       val = readl(&regs->gpio_dir);
+
+       return val & (1 << offset) ? 1 : 0;
+}
+
+static void mxc_gpio_bank_direction(struct gpio_regs *regs, int offset,
+                                   enum mxc_gpio_direction direction)
+{
+       u32 l;
+
+       l = readl(&regs->gpio_dir);
+
+       switch (direction) {
+       case MXC_GPIO_DIRECTION_OUT:
+               l |= 1 << offset;
+               break;
+       case MXC_GPIO_DIRECTION_IN:
+               l &= ~(1 << offset);
+       }
+       writel(l, &regs->gpio_dir);
+}
+
+static void mxc_gpio_bank_set_value(struct gpio_regs *regs, int offset,
+                                   int value)
+{
+       u32 l;
+
+       l = readl(&regs->gpio_dr);
+       if (value)
+               l |= 1 << offset;
+       else
+               l &= ~(1 << offset);
+       writel(l, &regs->gpio_dr);
+}
+
+static int mxc_gpio_bank_get_value(struct gpio_regs *regs, int offset)
+{
+       return (readl(&regs->gpio_psr) >> offset) & 0x01;
+}
+
+static int mxc_gpio_bank_get_output_value(struct gpio_regs *regs, int offset)
+{
+       return (readl(&regs->gpio_dr) >> offset) & 0x01;
+}
+
+static int check_requested(struct udevice *dev, unsigned offset,
+                          const char *func)
+{
+       struct mxc_bank_info *bank = dev_get_priv(dev);
+       struct gpio_dev_priv *uc_priv = dev->uclass_priv;
+
+       if (!gpio_is_requested(bank, offset)) {
+               printf("mxc_gpio: %s: error: gpio %s%d not requested\n",
+                      func, uc_priv->bank_name, offset);
+               return -EPERM;
+       }
+
+       return 0;
+}
+
+/* set GPIO pin 'gpio' as an input */
+static int mxc_gpio_direction_input(struct udevice *dev, unsigned offset)
+{
+       struct mxc_bank_info *bank = dev_get_priv(dev);
+       int ret;
+
+       ret = check_requested(dev, offset, __func__);
+       if (ret)
+               return ret;
+
+       /* Configure GPIO direction as input. */
+       mxc_gpio_bank_direction(bank->regs, offset, MXC_GPIO_DIRECTION_IN);
+
+       return 0;
+}
+
+/* set GPIO pin 'gpio' as an output, with polarity 'value' */
+static int mxc_gpio_direction_output(struct udevice *dev, unsigned offset,
+                                      int value)
+{
+       struct mxc_bank_info *bank = dev_get_priv(dev);
+       int ret;
+
+       ret = check_requested(dev, offset, __func__);
+       if (ret)
+               return ret;
+
+       /* Configure GPIO output value. */
+       mxc_gpio_bank_set_value(bank->regs, offset, value);
+
+       /* Configure GPIO direction as output. */
+       mxc_gpio_bank_direction(bank->regs, offset, MXC_GPIO_DIRECTION_OUT);
+
+       return 0;
+}
+
+/* read GPIO IN value of pin 'gpio' */
+static int mxc_gpio_get_value(struct udevice *dev, unsigned offset)
+{
+       struct mxc_bank_info *bank = dev_get_priv(dev);
+       int ret;
+
+       ret = check_requested(dev, offset, __func__);
+       if (ret)
+               return ret;
+
+       return mxc_gpio_bank_get_value(bank->regs, offset);
+}
+
+/* write GPIO OUT value to pin 'gpio' */
+static int mxc_gpio_set_value(struct udevice *dev, unsigned offset,
+                                int value)
+{
+       struct mxc_bank_info *bank = dev_get_priv(dev);
+       int ret;
+
+       ret = check_requested(dev, offset, __func__);
+       if (ret)
+               return ret;
+
+       mxc_gpio_bank_set_value(bank->regs, offset, value);
+
+       return 0;
+}
+
+static int mxc_gpio_get_state(struct udevice *dev, unsigned int offset,
+                             char *buf, int bufsize)
+{
+       struct gpio_dev_priv *uc_priv = dev->uclass_priv;
+       struct mxc_bank_info *bank = dev_get_priv(dev);
+       const char *label;
+       bool requested;
+       bool is_output;
+       int size;
+
+       label = bank->label[offset];
+       is_output = mxc_gpio_is_output(bank->regs, offset);
+       size = snprintf(buf, bufsize, "%s%d: ",
+                       uc_priv->bank_name ? uc_priv->bank_name : "", offset);
+       buf += size;
+       bufsize -= size;
+       requested = gpio_is_requested(bank, offset);
+       snprintf(buf, bufsize, "%s: %d [%c]%s%s",
+                is_output ? "out" : " in",
+                is_output ?
+                       mxc_gpio_bank_get_output_value(bank->regs, offset) :
+                       mxc_gpio_bank_get_value(bank->regs, offset),
+                requested ? 'x' : ' ',
+                requested ? " " : "",
+                label);
+
+       return 0;
+}
+
+static int mxc_gpio_request(struct udevice *dev, unsigned offset,
+                             const char *label)
+{
+       struct mxc_bank_info *bank = dev_get_priv(dev);
+
+       if (gpio_is_requested(bank, offset))
+               return -EBUSY;
+
+       strncpy(bank->label[offset], label, GPIO_NAME_SIZE);
+       bank->label[offset][GPIO_NAME_SIZE - 1] = '\0';
+
+       return 0;
+}
+
+static int mxc_gpio_free(struct udevice *dev, unsigned offset)
+{
+       struct mxc_bank_info *bank = dev_get_priv(dev);
+       int ret;
+
+       ret = check_requested(dev, offset, __func__);
+       if (ret)
+               return ret;
+       bank->label[offset][0] = '\0';
+
+       return 0;
+}
+
+static int mxc_gpio_get_function(struct udevice *dev, unsigned offset)
+{
+       struct mxc_bank_info *bank = dev_get_priv(dev);
+
+       if (!gpio_is_requested(bank, offset))
+               return GPIOF_UNUSED;
+
+       /* GPIOF_FUNC is not implemented yet */
+       if (mxc_gpio_is_output(bank->regs, offset))
+               return GPIOF_OUTPUT;
+       else
+               return GPIOF_INPUT;
+}
+
+static const struct dm_gpio_ops gpio_mxc_ops = {
+       .request                = mxc_gpio_request,
+       .free                   = mxc_gpio_free,
+       .direction_input        = mxc_gpio_direction_input,
+       .direction_output       = mxc_gpio_direction_output,
+       .get_value              = mxc_gpio_get_value,
+       .set_value              = mxc_gpio_set_value,
+       .get_function           = mxc_gpio_get_function,
+       .get_state              = mxc_gpio_get_state,
+};
+
+static const struct mxc_gpio_plat mxc_plat[] = {
+       { (struct gpio_regs *)GPIO1_BASE_ADDR },
+       { (struct gpio_regs *)GPIO2_BASE_ADDR },
+       { (struct gpio_regs *)GPIO3_BASE_ADDR },
+#if defined(CONFIG_MX25) || defined(CONFIG_MX27) || defined(CONFIG_MX51) || \
+               defined(CONFIG_MX53) || defined(CONFIG_MX6)
+       { (struct gpio_regs *)GPIO4_BASE_ADDR },
+#endif
+#if defined(CONFIG_MX27) || defined(CONFIG_MX53) || defined(CONFIG_MX6)
+       { (struct gpio_regs *)GPIO5_BASE_ADDR },
+       { (struct gpio_regs *)GPIO6_BASE_ADDR },
+#endif
+#if defined(CONFIG_MX53) || defined(CONFIG_MX6)
+       { (struct gpio_regs *)GPIO7_BASE_ADDR },
+#endif
+};
+
+static int mxc_gpio_probe(struct udevice *dev)
+{
+       struct mxc_bank_info *bank = dev_get_priv(dev);
+       struct mxc_gpio_plat *plat = dev_get_platdata(dev);
+       struct gpio_dev_priv *uc_priv = dev->uclass_priv;
+       int banknum;
+       char name[18], *str;
+
+       banknum = plat - mxc_plat;
+       sprintf(name, "GPIO%d_", banknum + 1);
+       str = strdup(name);
+       if (!str)
+               return -ENOMEM;
+       uc_priv->bank_name = str;
+       uc_priv->gpio_count = GPIO_PER_BANK;
+       bank->regs = plat->regs;
+
+       return 0;
+}
+
+U_BOOT_DRIVER(gpio_mxc) = {
+       .name   = "gpio_mxc",
+       .id     = UCLASS_GPIO,
+       .ops    = &gpio_mxc_ops,
+       .probe  = mxc_gpio_probe,
+       .priv_auto_alloc_size = sizeof(struct mxc_bank_info),
+};
+
+U_BOOT_DEVICES(mxc_gpios) = {
+       { "gpio_mxc", &mxc_plat[0] },
+       { "gpio_mxc", &mxc_plat[1] },
+       { "gpio_mxc", &mxc_plat[2] },
+#if defined(CONFIG_MX25) || defined(CONFIG_MX27) || defined(CONFIG_MX51) || \
+               defined(CONFIG_MX53) || defined(CONFIG_MX6)
+       { "gpio_mxc", &mxc_plat[3] },
+#endif
+#if defined(CONFIG_MX27) || defined(CONFIG_MX53) || defined(CONFIG_MX6)
+       { "gpio_mxc", &mxc_plat[4] },
+       { "gpio_mxc", &mxc_plat[5] },
+#endif
+#if defined(CONFIG_MX53) || defined(CONFIG_MX6)
+       { "gpio_mxc", &mxc_plat[6] },
+#endif
+};
+#endif
index db7b67373101636b61034b3fc90d2b147a33219a..13d74eb951bc406a6c3aea51f2548201c16ac258 100644 (file)
  */
 
 #include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <malloc.h>
 #include <asm/io.h>
 #include <asm/gpio.h>
-#include <asm/arch/gpio.h>
+#include <dm/device-internal.h>
+
+DECLARE_GLOBAL_DATA_PTR;
 
 #define S5P_GPIO_GET_PIN(x)    (x % GPIO_PER_BANK)
 
-#define CON_MASK(x)            (0xf << ((x) << 2))
-#define CON_SFR(x, v)          ((v) << ((x) << 2))
+#define CON_MASK(val)                  (0xf << ((val) << 2))
+#define CON_SFR(gpio, cfg)             ((cfg) << ((gpio) << 2))
+#define CON_SFR_UNSHIFT(val, gpio)     ((val) >> ((gpio) << 2))
+
+#define DAT_MASK(gpio)                 (0x1 << (gpio))
+#define DAT_SET(gpio)                  (0x1 << (gpio))
+
+#define PULL_MASK(gpio)                (0x3 << ((gpio) << 1))
+#define PULL_MODE(gpio, pull)          ((pull) << ((gpio) << 1))
+
+#define DRV_MASK(gpio)                 (0x3 << ((gpio) << 1))
+#define DRV_SET(gpio, mode)            ((mode) << ((gpio) << 1))
+#define RATE_MASK(gpio)                (0x1 << (gpio + 16))
+#define RATE_SET(gpio)                 (0x1 << (gpio + 16))
 
-#define DAT_MASK(x)            (0x1 << (x))
-#define DAT_SET(x)             (0x1 << (x))
+#define GPIO_NAME_SIZE                 20
 
-#define PULL_MASK(x)           (0x3 << ((x) << 1))
-#define PULL_MODE(x, v)                ((v) << ((x) << 1))
+/* Platform data for each bank */
+struct exynos_gpio_platdata {
+       struct s5p_gpio_bank *bank;
+       const char *bank_name;  /* Name of port, e.g. 'gpa0" */
+};
 
-#define DRV_MASK(x)            (0x3 << ((x) << 1))
-#define DRV_SET(x, m)          ((m) << ((x) << 1))
-#define RATE_MASK(x)           (0x1 << (x + 16))
-#define RATE_SET(x)            (0x1 << (x + 16))
+/* Information about each bank at run-time */
+struct exynos_bank_info {
+       char label[GPIO_PER_BANK][GPIO_NAME_SIZE];
+       struct s5p_gpio_bank *bank;
+};
 
-#define name_to_gpio(n) s5p_name_to_gpio(n)
-static inline int s5p_name_to_gpio(const char *name)
+static struct s5p_gpio_bank *s5p_gpio_get_bank(unsigned int gpio)
 {
-       unsigned num, irregular_set_number, irregular_bank_base;
-       const struct gpio_name_num_table *tabp;
-       char this_bank, bank_name, irregular_bank_name;
-       char *endp;
-
-       /*
-        * The gpio name starts with either 'g' or 'gp' followed by the bank
-        * name character. Skip one or two characters depending on the prefix.
-        */
-       if (name[0] == 'g' && name[1] == 'p')
-               name += 2;
-       else if (name[0] == 'g')
-               name++;
-       else
-               return -1; /* Name must start with 'g' */
-
-       bank_name = *name++;
-       if (!*name)
-               return -1; /* At least one digit is required/expected. */
-
-       /*
-        * On both exynos5 and exynos5420 architectures there is a bank of
-        * GPIOs which does not fall into the regular address pattern. Those
-        * banks are c4 on Exynos5 and y7 on Exynos5420. The rest of the below
-        * assignments help to handle these irregularities.
-        */
-#if defined(CONFIG_EXYNOS4) || defined(CONFIG_EXYNOS5)
-       if (cpu_is_exynos5()) {
-               if (proid_is_exynos5420()) {
-                       tabp = exynos5420_gpio_table;
-                       irregular_bank_name = 'y';
-                       irregular_set_number = '7';
-                       irregular_bank_base = EXYNOS5420_GPIO_Y70;
-               } else {
-                       tabp = exynos5_gpio_table;
-                       irregular_bank_name = 'c';
-                       irregular_set_number = '4';
-                       irregular_bank_base = EXYNOS5_GPIO_C40;
-               }
-       } else {
-               if (proid_is_exynos4412())
-                       tabp = exynos4x12_gpio_table;
-               else
-                       tabp = exynos4_gpio_table;
-               irregular_bank_name = 0;
-               irregular_set_number = 0;
-               irregular_bank_base = 0;
-       }
-#else
-       if (cpu_is_s5pc110())
-               tabp = s5pc110_gpio_table;
-       else
-               tabp = s5pc100_gpio_table;
-       irregular_bank_name = 0;
-       irregular_set_number = 0;
-       irregular_bank_base = 0;
-#endif
+       const struct gpio_info *data;
+       unsigned int upto;
+       int i, count;
 
-       this_bank = tabp->bank;
-       do {
-               if (bank_name == this_bank) {
-                       unsigned pin_index; /* pin number within the bank */
-                       if ((bank_name == irregular_bank_name) &&
-                           (name[0] == irregular_set_number)) {
-                               pin_index = name[1] - '0';
-                               /* Irregular sets have 8 pins. */
-                               if (pin_index >= GPIO_PER_BANK)
-                                       return -1;
-                               num = irregular_bank_base + pin_index;
-                       } else {
-                               pin_index = simple_strtoul(name, &endp, 8);
-                               pin_index -= tabp->bank_offset;
-                               /*
-                                * Sanity check: bunk 'z' has no set number,
-                                * for all other banks there must be exactly
-                                * two octal digits, and the resulting number
-                                * should not exceed the number of pins in the
-                                * bank.
-                                */
-                               if (((bank_name != 'z') && !name[1]) ||
-                                   *endp ||
-                                   (pin_index >= tabp->bank_size))
-                                       return -1;
-                               num = tabp->base + pin_index;
-                       }
-                       return num;
+       data = get_gpio_data();
+       count = get_bank_num();
+       upto = 0;
+
+       for (i = 0; i < count; i++) {
+               debug("i=%d, upto=%d\n", i, upto);
+               if (gpio < data->max_gpio) {
+                       struct s5p_gpio_bank *bank;
+                       bank = (struct s5p_gpio_bank *)data->reg_addr;
+                       bank += (gpio - upto) / GPIO_PER_BANK;
+                       debug("gpio=%d, bank=%p\n", gpio, bank);
+                       return bank;
                }
-               this_bank = (++tabp)->bank;
-       } while (this_bank);
 
-       return -1;
+               upto = data->max_gpio;
+               data++;
+       }
+
+       return NULL;
 }
 
 static void s5p_gpio_cfg_pin(struct s5p_gpio_bank *bank, int gpio, int cfg)
@@ -143,16 +95,23 @@ static void s5p_gpio_set_value(struct s5p_gpio_bank *bank, int gpio, int en)
        writel(value, &bank->dat);
 }
 
-static void s5p_gpio_direction_output(struct s5p_gpio_bank *bank,
-                                     int gpio, int en)
+#ifdef CONFIG_SPL_BUILD
+/* Common GPIO API - SPL does not support driver model yet */
+int gpio_set_value(unsigned gpio, int value)
 {
-       s5p_gpio_cfg_pin(bank, gpio, S5P_GPIO_OUTPUT);
-       s5p_gpio_set_value(bank, gpio, en);
-}
+       s5p_gpio_set_value(s5p_gpio_get_bank(gpio),
+                          s5p_gpio_get_pin(gpio), value);
 
-static void s5p_gpio_direction_input(struct s5p_gpio_bank *bank, int gpio)
+       return 0;
+}
+#else
+static int s5p_gpio_get_cfg_pin(struct s5p_gpio_bank *bank, int gpio)
 {
-       s5p_gpio_cfg_pin(bank, gpio, S5P_GPIO_INPUT);
+       unsigned int value;
+
+       value = readl(&bank->con);
+       value &= CON_MASK(gpio);
+       return CON_SFR_UNSHIFT(value, gpio);
 }
 
 static unsigned int s5p_gpio_get_value(struct s5p_gpio_bank *bank, int gpio)
@@ -162,6 +121,7 @@ static unsigned int s5p_gpio_get_value(struct s5p_gpio_bank *bank, int gpio)
        value = readl(&bank->dat);
        return !!(value & DAT_MASK(gpio));
 }
+#endif /* CONFIG_SPL_BUILD */
 
 static void s5p_gpio_set_pull(struct s5p_gpio_bank *bank, int gpio, int mode)
 {
@@ -222,78 +182,156 @@ static void s5p_gpio_set_rate(struct s5p_gpio_bank *bank, int gpio, int mode)
        writel(value, &bank->drv);
 }
 
-struct s5p_gpio_bank *s5p_gpio_get_bank(unsigned int gpio)
+int s5p_gpio_get_pin(unsigned gpio)
 {
-       const struct gpio_info *data;
-       unsigned int upto;
-       int i, count;
+       return S5P_GPIO_GET_PIN(gpio);
+}
 
-       data = get_gpio_data();
-       count = get_bank_num();
-       upto = 0;
+/* Driver model interface */
+#ifndef CONFIG_SPL_BUILD
+static int exynos_gpio_get_state(struct udevice *dev, unsigned int offset,
+                               char *buf, int bufsize)
+{
+       struct gpio_dev_priv *uc_priv = dev->uclass_priv;
+       struct exynos_bank_info *state = dev_get_priv(dev);
+       const char *label;
+       bool is_output;
+       int size;
+       int cfg;
+
+       label = state->label[offset];
+       cfg = s5p_gpio_get_cfg_pin(state->bank, offset);
+       is_output = cfg == S5P_GPIO_OUTPUT;
+       size = snprintf(buf, bufsize, "%s%d: ",
+                       uc_priv->bank_name ? uc_priv->bank_name : "", offset);
+       buf += size;
+       bufsize -= size;
+       if (is_output || cfg == S5P_GPIO_INPUT) {
+               snprintf(buf, bufsize, "%s: %d [%c]%s%s",
+                        is_output ? "out" : " in",
+                        s5p_gpio_get_value(state->bank, offset),
+                        *label ? 'x' : ' ',
+                        *label ? " " : "",
+                        label);
+       } else {
+               snprintf(buf, bufsize, "sfpio");
+       }
 
-       for (i = 0; i < count; i++) {
-               debug("i=%d, upto=%d\n", i, upto);
-               if (gpio < data->max_gpio) {
-                       struct s5p_gpio_bank *bank;
-                       bank = (struct s5p_gpio_bank *)data->reg_addr;
-                       bank += (gpio - upto) / GPIO_PER_BANK;
-                       debug("gpio=%d, bank=%p\n", gpio, bank);
-                       return bank;
-               }
+       return 0;
+}
 
-               upto = data->max_gpio;
-               data++;
+static int check_reserved(struct udevice *dev, unsigned offset,
+                         const char *func)
+{
+       struct exynos_bank_info *state = dev_get_priv(dev);
+       struct gpio_dev_priv *uc_priv = dev->uclass_priv;
+
+       if (!*state->label[offset]) {
+               printf("exynos_gpio: %s: error: gpio %s%d not reserved\n",
+                      func, uc_priv->bank_name, offset);
+               return -EPERM;
        }
 
-       return NULL;
+       return 0;
 }
 
-int s5p_gpio_get_pin(unsigned gpio)
+/* set GPIO pin 'gpio' as an input */
+static int exynos_gpio_direction_input(struct udevice *dev, unsigned offset)
 {
-       return S5P_GPIO_GET_PIN(gpio);
-}
+       struct exynos_bank_info *state = dev_get_priv(dev);
+       int ret;
 
-/* Common GPIO API */
+       ret = check_reserved(dev, offset, __func__);
+       if (ret)
+               return ret;
+
+       /* Configure GPIO direction as input. */
+       s5p_gpio_cfg_pin(state->bank, offset, S5P_GPIO_INPUT);
 
-int gpio_request(unsigned gpio, const char *label)
-{
        return 0;
 }
 
-int gpio_free(unsigned gpio)
+/* set GPIO pin 'gpio' as an output, with polarity 'value' */
+static int exynos_gpio_direction_output(struct udevice *dev, unsigned offset,
+                                      int value)
 {
+       struct exynos_bank_info *state = dev_get_priv(dev);
+       int ret;
+
+       ret = check_reserved(dev, offset, __func__);
+       if (ret)
+               return ret;
+
+       /* Configure GPIO output value. */
+       s5p_gpio_set_value(state->bank, offset, value);
+
+       /* Configure GPIO direction as output. */
+       s5p_gpio_cfg_pin(state->bank, offset, S5P_GPIO_OUTPUT);
+
        return 0;
 }
 
-int gpio_direction_input(unsigned gpio)
+/* read GPIO IN value of pin 'gpio' */
+static int exynos_gpio_get_value(struct udevice *dev, unsigned offset)
 {
-       s5p_gpio_direction_input(s5p_gpio_get_bank(gpio),
-                               s5p_gpio_get_pin(gpio));
-       return 0;
+       struct exynos_bank_info *state = dev_get_priv(dev);
+       int ret;
+
+       ret = check_reserved(dev, offset, __func__);
+       if (ret)
+               return ret;
+
+       return s5p_gpio_get_value(state->bank, offset);
 }
 
-int gpio_direction_output(unsigned gpio, int value)
+/* write GPIO OUT value to pin 'gpio' */
+static int exynos_gpio_set_value(struct udevice *dev, unsigned offset,
+                                int value)
 {
-       s5p_gpio_direction_output(s5p_gpio_get_bank(gpio),
-                                s5p_gpio_get_pin(gpio), value);
+       struct exynos_bank_info *state = dev_get_priv(dev);
+       int ret;
+
+       ret = check_reserved(dev, offset, __func__);
+       if (ret)
+               return ret;
+
+       s5p_gpio_set_value(state->bank, offset, value);
+
        return 0;
 }
 
-int gpio_get_value(unsigned gpio)
+static int exynos_gpio_request(struct udevice *dev, unsigned offset,
+                             const char *label)
 {
-       return (int) s5p_gpio_get_value(s5p_gpio_get_bank(gpio),
-                                      s5p_gpio_get_pin(gpio));
+       struct exynos_bank_info *state = dev_get_priv(dev);
+
+       if (*state->label[offset])
+               return -EBUSY;
+
+       strncpy(state->label[offset], label, GPIO_NAME_SIZE);
+       state->label[offset][GPIO_NAME_SIZE - 1] = '\0';
+
+       return 0;
 }
 
-int gpio_set_value(unsigned gpio, int value)
+static int exynos_gpio_free(struct udevice *dev, unsigned offset)
 {
-       s5p_gpio_set_value(s5p_gpio_get_bank(gpio),
-                         s5p_gpio_get_pin(gpio), value);
+       struct exynos_bank_info *state = dev_get_priv(dev);
+       int ret;
+
+       ret = check_reserved(dev, offset, __func__);
+       if (ret)
+               return ret;
+       state->label[offset][0] = '\0';
 
        return 0;
 }
+#endif /* nCONFIG_SPL_BUILD */
 
+/*
+ * There is no common GPIO API for pull, drv, pin, rate (yet). These
+ * functions are kept here to preserve function ordering for review.
+ */
 void gpio_set_pull(int gpio, int mode)
 {
        s5p_gpio_set_pull(s5p_gpio_get_bank(gpio),
@@ -317,3 +355,117 @@ void gpio_set_rate(int gpio, int mode)
        s5p_gpio_set_rate(s5p_gpio_get_bank(gpio),
                          s5p_gpio_get_pin(gpio), mode);
 }
+
+#ifndef CONFIG_SPL_BUILD
+static int exynos_gpio_get_function(struct udevice *dev, unsigned offset)
+{
+       struct exynos_bank_info *state = dev_get_priv(dev);
+       int cfg;
+
+       if (!*state->label[offset])
+               return GPIOF_UNUSED;
+       cfg = s5p_gpio_get_cfg_pin(state->bank, offset);
+       if (cfg == S5P_GPIO_OUTPUT)
+               return GPIOF_OUTPUT;
+       else if (cfg == S5P_GPIO_INPUT)
+               return GPIOF_INPUT;
+       else
+               return GPIOF_FUNC;
+}
+
+static const struct dm_gpio_ops gpio_exynos_ops = {
+       .request                = exynos_gpio_request,
+       .free                   = exynos_gpio_free,
+       .direction_input        = exynos_gpio_direction_input,
+       .direction_output       = exynos_gpio_direction_output,
+       .get_value              = exynos_gpio_get_value,
+       .set_value              = exynos_gpio_set_value,
+       .get_function           = exynos_gpio_get_function,
+       .get_state              = exynos_gpio_get_state,
+};
+
+static int gpio_exynos_probe(struct udevice *dev)
+{
+       struct gpio_dev_priv *uc_priv = dev->uclass_priv;
+       struct exynos_bank_info *priv = dev->priv;
+       struct exynos_gpio_platdata *plat = dev->platdata;
+
+       /* Only child devices have ports */
+       if (!plat)
+               return 0;
+
+       priv->bank = plat->bank;
+
+       uc_priv->gpio_count = GPIO_PER_BANK;
+       uc_priv->bank_name = plat->bank_name;
+
+       return 0;
+}
+
+/**
+ * We have a top-level GPIO device with no actual GPIOs. It has a child
+ * device for each Exynos GPIO bank.
+ */
+static int gpio_exynos_bind(struct udevice *parent)
+{
+       struct exynos_gpio_platdata *plat = parent->platdata;
+       struct s5p_gpio_bank *bank, *base;
+       const void *blob = gd->fdt_blob;
+       int node;
+
+       /* If this is a child device, there is nothing to do here */
+       if (plat)
+               return 0;
+
+       base = (struct s5p_gpio_bank *)fdtdec_get_addr(gd->fdt_blob,
+                                                  parent->of_offset, "reg");
+       for (node = fdt_first_subnode(blob, parent->of_offset), bank = base;
+            node > 0;
+            node = fdt_next_subnode(blob, node), bank++) {
+               struct exynos_gpio_platdata *plat;
+               struct udevice *dev;
+               fdt_addr_t reg;
+               int ret;
+
+               if (!fdtdec_get_bool(blob, node, "gpio-controller"))
+                       continue;
+               plat = calloc(1, sizeof(*plat));
+               if (!plat)
+                       return -ENOMEM;
+               reg = fdtdec_get_addr(blob, node, "reg");
+               if (reg != FDT_ADDR_T_NONE)
+                       bank = (struct s5p_gpio_bank *)((ulong)base + reg);
+               plat->bank = bank;
+               plat->bank_name = fdt_get_name(blob, node, NULL);
+               debug("dev at %p: %s\n", bank, plat->bank_name);
+
+               ret = device_bind(parent, parent->driver,
+                                       plat->bank_name, plat, -1, &dev);
+               if (ret)
+                       return ret;
+               dev->of_offset = parent->of_offset;
+       }
+
+       return 0;
+}
+
+static const struct udevice_id exynos_gpio_ids[] = {
+       { .compatible = "samsung,s5pc100-pinctrl" },
+       { .compatible = "samsung,s5pc110-pinctrl" },
+       { .compatible = "samsung,exynos4210-pinctrl" },
+       { .compatible = "samsung,exynos4x12-pinctrl" },
+       { .compatible = "samsung,exynos5250-pinctrl" },
+       { .compatible = "samsung,exynos5420-pinctrl" },
+       { }
+};
+
+U_BOOT_DRIVER(gpio_exynos) = {
+       .name   = "gpio_exynos",
+       .id     = UCLASS_GPIO,
+       .of_match = exynos_gpio_ids,
+       .bind   = gpio_exynos_bind,
+       .probe = gpio_exynos_probe,
+       .priv_auto_alloc_size = sizeof(struct exynos_bank_info),
+       .ops    = &gpio_exynos_ops,
+};
+#endif
index 068373b94263a999098d6af4d6d7038b0a4c7995..521edfd5de5cf5698ff98c1627e30703c3649282 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <common.h>
 #include <command.h>
+#include <dm.h>
 #include <i2c.h>
 #include <cros_ec.h>
 #include <fdtdec.h>
@@ -24,6 +25,8 @@
 #include <asm/errno.h>
 #include <asm/io.h>
 #include <asm-generic/gpio.h>
+#include <dm/device-internal.h>
+#include <dm/uclass-internal.h>
 
 #ifdef DEBUG_TRACE
 #define debug_trace(fmt, b...) debug(fmt, #b)
@@ -38,7 +41,9 @@ enum {
        CROS_EC_CMD_HASH_TIMEOUT_MS = 2000,
 };
 
+#ifndef CONFIG_DM_CROS_EC
 static struct cros_ec_dev static_dev, *last_dev;
+#endif
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -204,6 +209,9 @@ static int send_command_proto3(struct cros_ec_dev *dev,
                               const void *dout, int dout_len,
                               uint8_t **dinp, int din_len)
 {
+#ifdef CONFIG_DM_CROS_EC
+       struct dm_cros_ec_ops *ops;
+#endif
        int out_bytes, in_bytes;
        int rv;
 
@@ -218,6 +226,10 @@ static int send_command_proto3(struct cros_ec_dev *dev,
        if (in_bytes < 0)
                return in_bytes;
 
+#ifdef CONFIG_DM_CROS_EC
+       ops = dm_cros_ec_get_ops(dev->dev);
+       rv = ops->packet(dev->dev, out_bytes, in_bytes);
+#else
        switch (dev->interface) {
 #ifdef CONFIG_CROS_EC_SPI
        case CROS_EC_IF_SPI:
@@ -235,6 +247,7 @@ static int send_command_proto3(struct cros_ec_dev *dev,
                debug("%s: Unsupported interface\n", __func__);
                rv = -1;
        }
+#endif
        if (rv < 0)
                return rv;
 
@@ -246,6 +259,9 @@ static int send_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
                        const void *dout, int dout_len,
                        uint8_t **dinp, int din_len)
 {
+#ifdef CONFIG_DM_CROS_EC
+       struct dm_cros_ec_ops *ops;
+#endif
        int ret = -1;
 
        /* Handle protocol version 3 support */
@@ -254,6 +270,11 @@ static int send_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
                                           dout, dout_len, dinp, din_len);
        }
 
+#ifdef CONFIG_DM_CROS_EC
+       ops = dm_cros_ec_get_ops(dev->dev);
+       ret = ops->command(dev->dev, cmd, cmd_version,
+                          (const uint8_t *)dout, dout_len, dinp, din_len);
+#else
        switch (dev->interface) {
 #ifdef CONFIG_CROS_EC_SPI
        case CROS_EC_IF_SPI:
@@ -280,6 +301,7 @@ static int send_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
        default:
                ret = -1;
        }
+#endif
 
        return ret;
 }
@@ -990,6 +1012,7 @@ int cros_ec_get_ldo(struct cros_ec_dev *dev, uint8_t index, uint8_t *state)
        return 0;
 }
 
+#ifndef CONFIG_DM_CROS_EC
 /**
  * Decode EC interface details from the device tree and allocate a suitable
  * device.
@@ -1055,11 +1078,61 @@ static int cros_ec_decode_fdt(const void *blob, int node,
 
        return 0;
 }
+#endif
 
-int cros_ec_init(const void *blob, struct cros_ec_dev **cros_ecp)
+#ifdef CONFIG_DM_CROS_EC
+int cros_ec_register(struct udevice *dev)
 {
+       struct cros_ec_dev *cdev = dev->uclass_priv;
+       const void *blob = gd->fdt_blob;
+       int node = dev->of_offset;
        char id[MSG_BYTES];
+
+       cdev->dev = dev;
+       fdtdec_decode_gpio(blob, node, "ec-interrupt", &cdev->ec_int);
+       cdev->optimise_flash_write = fdtdec_get_bool(blob, node,
+                                                    "optimise-flash-write");
+
+       /* we will poll the EC interrupt line */
+       fdtdec_setup_gpio(&cdev->ec_int);
+       if (fdt_gpio_isvalid(&cdev->ec_int)) {
+               gpio_request(cdev->ec_int.gpio, "cros-ec-irq");
+               gpio_direction_input(cdev->ec_int.gpio);
+       }
+
+       if (cros_ec_check_version(cdev)) {
+               debug("%s: Could not detect CROS-EC version\n", __func__);
+               return -CROS_EC_ERR_CHECK_VERSION;
+       }
+
+       if (cros_ec_read_id(cdev, id, sizeof(id))) {
+               debug("%s: Could not read KBC ID\n", __func__);
+               return -CROS_EC_ERR_READ_ID;
+       }
+
+       /* Remember this device for use by the cros_ec command */
+       debug("Google Chrome EC CROS-EC driver ready, id '%s'\n", id);
+
+       return 0;
+}
+#else
+int cros_ec_init(const void *blob, struct cros_ec_dev **cros_ecp)
+{
        struct cros_ec_dev *dev;
+       char id[MSG_BYTES];
+#ifdef CONFIG_DM_CROS_EC
+       struct udevice *udev;
+       int ret;
+
+       ret = uclass_find_device(UCLASS_CROS_EC, 0, &udev);
+       if (!ret)
+               device_remove(udev);
+       ret = uclass_get_device(UCLASS_CROS_EC, 0, &udev);
+       if (ret)
+               return ret;
+       dev = udev->uclass_priv;
+       return 0;
+#else
        int node = 0;
 
        *cros_ecp = NULL;
@@ -1108,11 +1181,14 @@ int cros_ec_init(const void *blob, struct cros_ec_dev **cros_ecp)
        default:
                return 0;
        }
+#endif
 
        /* we will poll the EC interrupt line */
        fdtdec_setup_gpio(&dev->ec_int);
-       if (fdt_gpio_isvalid(&dev->ec_int))
+       if (fdt_gpio_isvalid(&dev->ec_int)) {
+               gpio_request(dev->ec_int.gpio, "cros-ec-irq");
                gpio_direction_input(dev->ec_int.gpio);
+       }
 
        if (cros_ec_check_version(dev)) {
                debug("%s: Could not detect CROS-EC version\n", __func__);
@@ -1125,11 +1201,15 @@ int cros_ec_init(const void *blob, struct cros_ec_dev **cros_ecp)
        }
 
        /* Remember this device for use by the cros_ec command */
-       last_dev = *cros_ecp = dev;
+       *cros_ecp = dev;
+#ifndef CONFIG_DM_CROS_EC
+       last_dev = dev;
+#endif
        debug("Google Chrome EC CROS-EC driver ready, id '%s'\n", id);
 
        return 0;
 }
+#endif
 
 int cros_ec_decode_region(int argc, char * const argv[])
 {
@@ -1147,15 +1227,10 @@ int cros_ec_decode_region(int argc, char * const argv[])
        return -1;
 }
 
-int cros_ec_decode_ec_flash(const void *blob, struct fdt_cros_ec *config)
+int cros_ec_decode_ec_flash(const void *blob, int node,
+                           struct fdt_cros_ec *config)
 {
-       int flash_node, node;
-
-       node = fdtdec_next_compatible(blob, 0, COMPAT_GOOGLE_CROS_EC);
-       if (node < 0) {
-               debug("Failed to find chrome-ec node'\n");
-               return -1;
-       }
+       int flash_node;
 
        flash_node = fdt_subnode_offset(blob, node, "flash");
        if (flash_node < 0) {
@@ -1516,7 +1591,10 @@ static int cros_ec_i2c_passthrough(struct cros_ec_dev *dev, int flag,
 
 static int do_cros_ec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
-       struct cros_ec_dev *dev = last_dev;
+       struct cros_ec_dev *dev;
+#ifdef CONFIG_DM_CROS_EC
+       struct udevice *udev;
+#endif
        const char *cmd;
        int ret = 0;
 
@@ -1525,19 +1603,31 @@ static int do_cros_ec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 
        cmd = argv[1];
        if (0 == strcmp("init", cmd)) {
+#ifndef CONFIG_DM_CROS_EC
                ret = cros_ec_init(gd->fdt_blob, &dev);
                if (ret) {
                        printf("Could not init cros_ec device (err %d)\n", ret);
                        return 1;
                }
+#endif
                return 0;
        }
 
+#ifdef CONFIG_DM_CROS_EC
+       ret = uclass_get_device(UCLASS_CROS_EC, 0, &udev);
+       if (ret) {
+               printf("Cannot get cros-ec device (err=%d)\n", ret);
+               return 1;
+       }
+       dev = udev->uclass_priv;
+#else
        /* Just use the last allocated device; there should be only one */
        if (!last_dev) {
                printf("No CROS-EC device available\n");
                return 1;
        }
+       dev = last_dev;
+#endif
        if (0 == strcmp("id", cmd)) {
                char id[MSG_BYTES];
 
@@ -1794,3 +1884,11 @@ U_BOOT_CMD(
        "crosec i2c mw chip address[.0, .1, .2] value [count] - write to I2C passthru (fill)"
 );
 #endif
+
+#ifdef CONFIG_DM_CROS_EC
+UCLASS_DRIVER(cros_ec) = {
+       .id             = UCLASS_CROS_EC,
+       .name           = "cros_ec",
+       .per_device_auto_alloc_size = sizeof(struct cros_ec_dev),
+};
+#endif
index 8a04af557d035e6211865e4f2e1662d105d4447d..99cc5297cfb866acddd6495c088b681171d2c8f1 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <common.h>
 #include <cros_ec.h>
+#include <dm.h>
 #include <ec_commands.h>
 #include <errno.h>
 #include <hash.h>
@@ -85,7 +86,7 @@ struct ec_state {
        struct ec_keymatrix_entry *matrix;      /* the key matrix info */
        uint8_t keyscan[KEYBOARD_COLS];
        bool recovery_req;
-} s_state, *state;
+} s_state, *g_state;
 
 /**
  * cros_ec_read_state() - read the sandbox EC state from the state file
@@ -138,7 +139,7 @@ static int cros_ec_read_state(const void *blob, int node)
  */
 static int cros_ec_write_state(void *blob, int node)
 {
-       struct ec_state *ec = &s_state;
+       struct ec_state *ec = g_state;
 
        /* We are guaranteed enough space to write basic properties */
        fdt_setprop_u32(blob, node, "current-image", ec->current_image);
@@ -369,7 +370,7 @@ static int process_cmd(struct ec_state *ec,
                struct fmap_entry *entry;
                int ret, size;
 
-               entry = &state->ec_config.region[EC_FLASH_REGION_RW];
+               entry = &ec->ec_config.region[EC_FLASH_REGION_RW];
 
                switch (req->cmd) {
                case EC_VBOOT_HASH_RECALC:
@@ -426,7 +427,7 @@ static int process_cmd(struct ec_state *ec,
                case EC_FLASH_REGION_RO:
                case EC_FLASH_REGION_RW:
                case EC_FLASH_REGION_WP_RO:
-                       entry = &state->ec_config.region[req->region];
+                       entry = &ec->ec_config.region[req->region];
                        resp->offset = entry->offset;
                        resp->size = entry->length;
                        len = sizeof(*resp);
@@ -466,16 +467,24 @@ static int process_cmd(struct ec_state *ec,
        return len;
 }
 
+#ifdef CONFIG_DM_CROS_EC
+int cros_ec_sandbox_packet(struct udevice *udev, int out_bytes, int in_bytes)
+{
+       struct cros_ec_dev *dev = udev->uclass_priv;
+       struct ec_state *ec = dev_get_priv(dev->dev);
+#else
 int cros_ec_sandbox_packet(struct cros_ec_dev *dev, int out_bytes,
                           int in_bytes)
 {
+       struct ec_state *ec = &s_state;
+#endif
        struct ec_host_request *req_hdr = (struct ec_host_request *)dev->dout;
        const void *req_data = req_hdr + 1;
        struct ec_host_response *resp_hdr = (struct ec_host_response *)dev->din;
        void *resp_data = resp_hdr + 1;
        int len;
 
-       len = process_cmd(&s_state, req_hdr, req_data, resp_hdr, resp_data);
+       len = process_cmd(ec, req_hdr, req_data, resp_hdr, resp_data);
        if (len < 0)
                return len;
 
@@ -498,7 +507,11 @@ int cros_ec_sandbox_decode_fdt(struct cros_ec_dev *dev, const void *blob)
 
 void cros_ec_check_keyboard(struct cros_ec_dev *dev)
 {
+#ifdef CONFIG_DM_CROS_EC
+       struct ec_state *ec = dev_get_priv(dev->dev);
+#else
        struct ec_state *ec = &s_state;
+#endif
        ulong start;
 
        printf("Press keys for EC to detect on reset (ESC=recovery)...");
@@ -512,6 +525,52 @@ void cros_ec_check_keyboard(struct cros_ec_dev *dev)
        }
 }
 
+#ifdef CONFIG_DM_CROS_EC
+int cros_ec_probe(struct udevice *dev)
+{
+       struct ec_state *ec = dev->priv;
+       struct cros_ec_dev *cdev = dev->uclass_priv;
+       const void *blob = gd->fdt_blob;
+       int node;
+       int err;
+
+       memcpy(ec, &s_state, sizeof(*ec));
+       err = cros_ec_decode_ec_flash(blob, dev->of_offset, &ec->ec_config);
+       if (err)
+               return err;
+
+       node = fdtdec_next_compatible(blob, 0, COMPAT_GOOGLE_CROS_EC_KEYB);
+       if (node < 0) {
+               debug("%s: No cros_ec keyboard found\n", __func__);
+       } else if (keyscan_read_fdt_matrix(ec, blob, node)) {
+               debug("%s: Could not read key matrix\n", __func__);
+               return -1;
+       }
+
+       /* If we loaded EC data, check that the length matches */
+       if (ec->flash_data &&
+           ec->flash_data_len != ec->ec_config.flash.length) {
+               printf("EC data length is %x, expected %x, discarding data\n",
+                      ec->flash_data_len, ec->ec_config.flash.length);
+               os_free(ec->flash_data);
+               ec->flash_data = NULL;
+       }
+
+       /* Otherwise allocate the memory */
+       if (!ec->flash_data) {
+               ec->flash_data_len = ec->ec_config.flash.length;
+               ec->flash_data = os_malloc(ec->flash_data_len);
+               if (!ec->flash_data)
+                       return -ENOMEM;
+       }
+
+       cdev->dev = dev;
+       g_state = ec;
+       return cros_ec_register(dev);
+}
+
+#else
+
 /**
  * Initialize sandbox EC emulation.
  *
@@ -525,8 +584,13 @@ int cros_ec_sandbox_init(struct cros_ec_dev *dev, const void *blob)
        int node;
        int err;
 
-       state = &s_state;
-       err = cros_ec_decode_ec_flash(blob, &ec->ec_config);
+       node = fdtdec_next_compatible(blob, 0, COMPAT_GOOGLE_CROS_EC);
+       if (node < 0) {
+               debug("Failed to find chrome-ec node'\n");
+               return -1;
+       }
+
+       err = cros_ec_decode_ec_flash(blob, node, &ec->ec_config);
        if (err)
                return err;
 
@@ -557,3 +621,24 @@ int cros_ec_sandbox_init(struct cros_ec_dev *dev, const void *blob)
 
        return 0;
 }
+#endif
+
+#ifdef CONFIG_DM_CROS_EC
+struct dm_cros_ec_ops cros_ec_ops = {
+       .packet = cros_ec_sandbox_packet,
+};
+
+static const struct udevice_id cros_ec_ids[] = {
+       { .compatible = "google,cros-ec" },
+       { }
+};
+
+U_BOOT_DRIVER(cros_ec_sandbox) = {
+       .name           = "cros_ec",
+       .id             = UCLASS_CROS_EC,
+       .of_match       = cros_ec_ids,
+       .probe          = cros_ec_probe,
+       .priv_auto_alloc_size = sizeof(struct ec_state),
+       .ops            = &cros_ec_ops,
+};
+#endif
index 015333f139a209fd686a4ac173aba02baeeb1b33..e403664bb561755184c60e9020e028b84169d40f 100644 (file)
 
 #include <common.h>
 #include <cros_ec.h>
+#include <dm.h>
+#include <errno.h>
 #include <spi.h>
 
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_DM_CROS_EC
+int cros_ec_spi_packet(struct udevice *udev, int out_bytes, int in_bytes)
+{
+       struct cros_ec_dev *dev = udev->uclass_priv;
+#else
 int cros_ec_spi_packet(struct cros_ec_dev *dev, int out_bytes, int in_bytes)
 {
+#endif
+       struct spi_slave *slave = dev_get_parentdata(dev->dev);
        int rv;
 
        /* Do the transfer */
-       if (spi_claim_bus(dev->spi)) {
+       if (spi_claim_bus(slave)) {
                debug("%s: Cannot claim SPI bus\n", __func__);
                return -1;
        }
 
-       rv = spi_xfer(dev->spi, max(out_bytes, in_bytes) * 8,
+       rv = spi_xfer(slave, max(out_bytes, in_bytes) * 8,
                      dev->dout, dev->din,
                      SPI_XFER_BEGIN | SPI_XFER_END);
 
-       spi_release_bus(dev->spi);
+       spi_release_bus(slave);
 
        if (rv) {
                debug("%s: Cannot complete SPI transfer\n", __func__);
@@ -56,10 +67,19 @@ int cros_ec_spi_packet(struct cros_ec_dev *dev, int out_bytes, int in_bytes)
  * @param din_len      Maximum size of response in bytes
  * @return number of bytes in response, or -1 on error
  */
+#ifdef CONFIG_DM_CROS_EC
+int cros_ec_spi_command(struct udevice *udev, uint8_t cmd, int cmd_version,
+                    const uint8_t *dout, int dout_len,
+                    uint8_t **dinp, int din_len)
+{
+       struct cros_ec_dev *dev = udev->uclass_priv;
+#else
 int cros_ec_spi_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
                     const uint8_t *dout, int dout_len,
                     uint8_t **dinp, int din_len)
 {
+#endif
+       struct spi_slave *slave = dev_get_parentdata(dev->dev);
        int in_bytes = din_len + 4;     /* status, length, checksum, trailer */
        uint8_t *out;
        uint8_t *p;
@@ -92,7 +112,7 @@ int cros_ec_spi_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
         */
        memset(dev->din, '\0', in_bytes);
 
-       if (spi_claim_bus(dev->spi)) {
+       if (spi_claim_bus(slave)) {
                debug("%s: Cannot claim SPI bus\n", __func__);
                return -1;
        }
@@ -113,10 +133,10 @@ int cros_ec_spi_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
        p = dev->din + sizeof(int64_t) - 2;
        len = dout_len + 4;
        cros_ec_dump_data("out", cmd, out, len);
-       rv = spi_xfer(dev->spi, max(len, in_bytes) * 8, out, p,
+       rv = spi_xfer(slave, max(len, in_bytes) * 8, out, p,
                      SPI_XFER_BEGIN | SPI_XFER_END);
 
-       spi_release_bus(dev->spi);
+       spi_release_bus(slave);
 
        if (rv) {
                debug("%s: Cannot complete SPI transfer\n", __func__);
@@ -146,6 +166,7 @@ int cros_ec_spi_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
        return len;
 }
 
+#ifndef CONFIG_DM_CROS_EC
 int cros_ec_spi_decode_fdt(struct cros_ec_dev *dev, const void *blob)
 {
        /* Decode interface-specific FDT params */
@@ -165,11 +186,59 @@ int cros_ec_spi_decode_fdt(struct cros_ec_dev *dev, const void *blob)
  */
 int cros_ec_spi_init(struct cros_ec_dev *dev, const void *blob)
 {
-       dev->spi = spi_setup_slave_fdt(blob, dev->node, dev->parent_node);
-       if (!dev->spi) {
+       int ret;
+
+       ret = spi_setup_slave_fdt(blob, dev->node, dev->parent_node,
+                                 &slave);
+       if (ret) {
                debug("%s: Could not setup SPI slave\n", __func__);
-               return -1;
+               return ret;
        }
 
        return 0;
 }
+#endif
+
+#ifdef CONFIG_DM_CROS_EC
+int cros_ec_probe(struct udevice *dev)
+{
+       struct spi_slave *slave = dev_get_parentdata(dev);
+       int ret;
+
+       /*
+        * TODO(sjg@chromium.org)
+        *
+        * This is really horrible at present. It is an artifact of removing
+        * the child_pre_probe() method for SPI. Everything here could go in
+        * an automatic function, except that spi_get_bus_and_cs() wants to
+        * set it up manually and call device_probe_child().
+        *
+        * The solution may be to re-enable the child_pre_probe() method for
+        * SPI and have it do nothing if the child is already passed in via
+        * device_probe_child().
+        */
+       slave->dev = dev;
+       ret = spi_ofdata_to_platdata(gd->fdt_blob, dev->of_offset, slave);
+       if (ret)
+               return ret;
+       return cros_ec_register(dev);
+}
+
+struct dm_cros_ec_ops cros_ec_ops = {
+       .packet = cros_ec_spi_packet,
+       .command = cros_ec_spi_command,
+};
+
+static const struct udevice_id cros_ec_ids[] = {
+       { .compatible = "google,cros-ec" },
+       { }
+};
+
+U_BOOT_DRIVER(cros_ec_spi) = {
+       .name           = "cros_ec",
+       .id             = UCLASS_CROS_EC,
+       .of_match       = cros_ec_ids,
+       .probe          = cros_ec_probe,
+       .ops            = &cros_ec_ops,
+};
+#endif
index 637dd972a5b3612d74b0ec3b6924f9f8544aa344..0dea45d079f33e9c4f8b3b55288d7f508e4abc2d 100644 (file)
@@ -102,6 +102,7 @@ struct sdhci_host sdhci_host[SDHCI_MAX_HOSTS];
 
 static int do_sdhci_init(struct sdhci_host *host)
 {
+       char str[20];
        int dev_id, flag;
        int err = 0;
 
@@ -109,6 +110,8 @@ static int do_sdhci_init(struct sdhci_host *host)
        dev_id = host->index + PERIPH_ID_SDMMC0;
 
        if (fdt_gpio_isvalid(&host->pwr_gpio)) {
+               sprintf(str, "sdhci%d_power", host->index & 0xf);
+               gpio_request(host->pwr_gpio.gpio, str);
                gpio_direction_output(host->pwr_gpio.gpio, 1);
                err = exynos_pinmux_config(dev_id, flag);
                if (err) {
@@ -118,7 +121,9 @@ static int do_sdhci_init(struct sdhci_host *host)
        }
 
        if (fdt_gpio_isvalid(&host->cd_gpio)) {
-               gpio_direction_output(host->cd_gpio.gpio, 0xf);
+               sprintf(str, "sdhci%d_cd", host->index & 0xf);
+               gpio_request(host->cd_gpio.gpio, str);
+               gpio_direction_output(host->cd_gpio.gpio, 1);
                if (gpio_get_value(host->cd_gpio.gpio))
                        return -ENODEV;
 
index 9e18fb41de624b4684e19e435c5513525c38de5e..15789a07d8f674786e201581784a7ffb9c37bfed 100644 (file)
@@ -5,13 +5,18 @@
 # SPDX-License-Identifier:     GPL-2.0+
 #
 
+obj-$(CONFIG_DM_SPI_FLASH) += sf-uclass.o
+
 ifdef CONFIG_SPL_BUILD
 obj-$(CONFIG_SPL_SPI_LOAD)     += spi_spl_load.o
 obj-$(CONFIG_SPL_SPI_BOOT)     += fsl_espi_spl.o
 endif
 
+#ifndef CONFIG_DM_SPI
+obj-$(CONFIG_SPI_FLASH) += sf_probe.o
+#endif
 obj-$(CONFIG_CMD_SF) += sf.o
-obj-$(CONFIG_SPI_FLASH) += sf_params.o sf_probe.o sf_ops.o
+obj-$(CONFIG_SPI_FLASH) += sf_ops.o sf_params.o
 obj-$(CONFIG_SPI_FRAM_RAMTRON) += ramtron.o
 obj-$(CONFIG_SPI_FLASH_SANDBOX) += sandbox.o
 obj-$(CONFIG_SPI_M95XXX) += eeprom_m95xxx.o
index d50da37c89af4418b5a6ad52c297007f6bb3dfc3..a23032cca58df0fdc2f304ce8aabaef253bd54fd 100644 (file)
@@ -35,6 +35,7 @@
 
 #include <common.h>
 #include <malloc.h>
+#include <spi.h>
 #include <spi_flash.h>
 #include "sf_internal.h"
 
index 98e0a34d4e3b2fa74017fff981b80f47d0736271..1cf2f98310a17493a5a99cce29caa652cb9aabd1 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <common.h>
+#include <dm.h>
 #include <malloc.h>
 #include <spi.h>
 #include <os.h>
 #include <asm/getopt.h>
 #include <asm/spi.h>
 #include <asm/state.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/uclass-internal.h>
+
+DECLARE_GLOBAL_DATA_PTR;
 
 /*
  * The different states that our SPI flash transitions between.
@@ -34,12 +40,14 @@ enum sandbox_sf_state {
        SF_ERASE, /* erase the flash */
        SF_READ_STATUS, /* read the flash's status register */
        SF_READ_STATUS1, /* read the flash's status register upper 8 bits*/
+       SF_WRITE_STATUS, /* write the flash's status register */
 };
 
 static const char *sandbox_sf_state_name(enum sandbox_sf_state state)
 {
        static const char * const states[] = {
                "CMD", "ID", "ADDR", "READ", "WRITE", "ERASE", "READ_STATUS",
+               "READ_STATUS1", "WRITE_STATUS",
        };
        return states[state];
 }
@@ -58,6 +66,7 @@ static u8 sandbox_sf_0xff[0x1000];
 
 /* Internal state data for each SPI flash */
 struct sandbox_spi_flash {
+       unsigned int cs;        /* Chip select we are attached to */
        /*
         * As we receive data over the SPI bus, our flash transitions
         * between states.  For example, we start off in the SF_CMD
@@ -84,71 +93,124 @@ struct sandbox_spi_flash {
        int fd;
 };
 
-static int sandbox_sf_setup(void **priv, const char *spec)
+struct sandbox_spi_flash_plat_data {
+       const char *filename;
+       const char *device_name;
+       int bus;
+       int cs;
+};
+
+/**
+ * This is a very strange probe function. If it has platform data (which may
+ * have come from the device tree) then this function gets the filename and
+ * device type from there. Failing that it looks at the command line
+ * parameter.
+ */
+static int sandbox_sf_probe(struct udevice *dev)
 {
        /* spec = idcode:file */
-       struct sandbox_spi_flash *sbsf;
+       struct sandbox_spi_flash *sbsf = dev_get_priv(dev);
        const char *file;
        size_t len, idname_len;
        const struct spi_flash_params *data;
-
-       file = strchr(spec, ':');
-       if (!file) {
-               printf("sandbox_sf: unable to parse file\n");
-               goto error;
+       struct sandbox_spi_flash_plat_data *pdata = dev_get_platdata(dev);
+       struct sandbox_state *state = state_get_current();
+       struct udevice *bus = dev->parent;
+       const char *spec = NULL;
+       int ret = 0;
+       int cs = -1;
+       int i;
+
+       debug("%s: bus %d, looking for emul=%p: ", __func__, bus->seq, dev);
+       if (bus->seq >= 0 && bus->seq < CONFIG_SANDBOX_SPI_MAX_BUS) {
+               for (i = 0; i < CONFIG_SANDBOX_SPI_MAX_CS; i++) {
+                       if (state->spi[bus->seq][i].emul == dev)
+                               cs = i;
+               }
+       }
+       if (cs == -1) {
+               printf("Error: Unknown chip select for device '%s'",
+                      dev->name);
+               return -EINVAL;
+       }
+       debug("found at cs %d\n", cs);
+
+       if (!pdata->filename) {
+               struct sandbox_state *state = state_get_current();
+
+               assert(bus->seq != -1);
+               if (bus->seq < CONFIG_SANDBOX_SPI_MAX_BUS)
+                       spec = state->spi[bus->seq][cs].spec;
+               if (!spec)
+                       return -ENOENT;
+
+               file = strchr(spec, ':');
+               if (!file) {
+                       printf("sandbox_sf: unable to parse file\n");
+                       ret = -EINVAL;
+                       goto error;
+               }
+               idname_len = file - spec;
+               pdata->filename = file + 1;
+               pdata->device_name = spec;
+               ++file;
+       } else {
+               spec = strchr(pdata->device_name, ',');
+               if (spec)
+                       spec++;
+               else
+                       spec = pdata->device_name;
+               idname_len = strlen(spec);
        }
-       idname_len = file - spec;
-       ++file;
+       debug("%s: device='%s'\n", __func__, spec);
 
        for (data = spi_flash_params_table; data->name; data++) {
                len = strlen(data->name);
                if (idname_len != len)
                        continue;
-               if (!memcmp(spec, data->name, len))
+               if (!strncasecmp(spec, data->name, len))
                        break;
        }
        if (!data->name) {
                printf("sandbox_sf: unknown flash '%*s'\n", (int)idname_len,
                       spec);
+               ret = -EINVAL;
                goto error;
        }
 
        if (sandbox_sf_0xff[0] == 0x00)
                memset(sandbox_sf_0xff, 0xff, sizeof(sandbox_sf_0xff));
 
-       sbsf = calloc(sizeof(*sbsf), 1);
-       if (!sbsf) {
-               printf("sandbox_sf: out of memory\n");
-               goto error;
-       }
-
-       sbsf->fd = os_open(file, 02);
+       sbsf->fd = os_open(pdata->filename, 02);
        if (sbsf->fd == -1) {
                free(sbsf);
-               printf("sandbox_sf: unable to open file '%s'\n", file);
+               printf("sandbox_sf: unable to open file '%s'\n",
+                      pdata->filename);
+               ret = -EIO;
                goto error;
        }
 
        sbsf->data = data;
+       sbsf->cs = cs;
 
-       *priv = sbsf;
        return 0;
 
  error:
-       return 1;
+       return ret;
 }
 
-static void sandbox_sf_free(void *priv)
+static int sandbox_sf_remove(struct udevice *dev)
 {
-       struct sandbox_spi_flash *sbsf = priv;
+       struct sandbox_spi_flash *sbsf = dev_get_priv(dev);
 
        os_close(sbsf->fd);
-       free(sbsf);
+
+       return 0;
 }
 
-static void sandbox_sf_cs_activate(void *priv)
+static void sandbox_sf_cs_activate(struct udevice *dev)
 {
-       struct sandbox_spi_flash *sbsf = priv;
+       struct sandbox_spi_flash *sbsf = dev_get_priv(dev);
 
        debug("sandbox_sf: CS activated; state is fresh!\n");
 
@@ -160,11 +222,24 @@ static void sandbox_sf_cs_activate(void *priv)
        sbsf->cmd = SF_CMD;
 }
 
-static void sandbox_sf_cs_deactivate(void *priv)
+static void sandbox_sf_cs_deactivate(struct udevice *dev)
 {
        debug("sandbox_sf: CS deactivated; cmd done processing!\n");
 }
 
+/*
+ * There are times when the data lines are allowed to tristate.  What
+ * is actually sensed on the line depends on the hardware.  It could
+ * always be 0xFF/0x00 (if there are pull ups/downs), or things could
+ * float and so we'd get garbage back.  This func encapsulates that
+ * scenario so we can worry about the details here.
+ */
+static void sandbox_spi_tristate(u8 *buf, uint len)
+{
+       /* XXX: make this into a user config option ? */
+       memset(buf, 0xff, len);
+}
+
 /* Figure out what command this stream is telling us to do */
 static int sandbox_sf_process_cmd(struct sandbox_spi_flash *sbsf, const u8 *rx,
                                  u8 *tx)
@@ -172,7 +247,8 @@ static int sandbox_sf_process_cmd(struct sandbox_spi_flash *sbsf, const u8 *rx,
        enum sandbox_sf_state oldstate = sbsf->state;
 
        /* We need to output a byte for the cmd byte we just ate */
-       sandbox_spi_tristate(tx, 1);
+       if (tx)
+               sandbox_spi_tristate(tx, 1);
 
        sbsf->cmd = rx[0];
        switch (sbsf->cmd) {
@@ -200,6 +276,9 @@ static int sandbox_sf_process_cmd(struct sandbox_spi_flash *sbsf, const u8 *rx,
                debug(" write enabled\n");
                sbsf->status |= STAT_WEL;
                break;
+       case CMD_WRITE_STATUS:
+               sbsf->state = SF_WRITE_STATUS;
+               break;
        default: {
                int flags = sbsf->data->flags;
 
@@ -216,7 +295,7 @@ static int sandbox_sf_process_cmd(struct sandbox_spi_flash *sbsf, const u8 *rx,
                        sbsf->erase_size = 64 << 10;
                } else {
                        debug(" cmd unknown: %#x\n", sbsf->cmd);
-                       return 1;
+                       return -EIO;
                }
                sbsf->state = SF_ADDR;
                break;
@@ -246,20 +325,27 @@ int sandbox_erase_part(struct sandbox_spi_flash *sbsf, int size)
        return 0;
 }
 
-static int sandbox_sf_xfer(void *priv, const u8 *rx, u8 *tx,
-               uint bytes)
+static int sandbox_sf_xfer(struct udevice *dev, unsigned int bitlen,
+                          const void *rxp, void *txp, unsigned long flags)
 {
-       struct sandbox_spi_flash *sbsf = priv;
+       struct sandbox_spi_flash *sbsf = dev_get_priv(dev);
+       const uint8_t *rx = rxp;
+       uint8_t *tx = txp;
        uint cnt, pos = 0;
+       int bytes = bitlen / 8;
        int ret;
 
        debug("sandbox_sf: state:%x(%s) bytes:%u\n", sbsf->state,
              sandbox_sf_state_name(sbsf->state), bytes);
 
+       if ((flags & SPI_XFER_BEGIN))
+               sandbox_sf_cs_activate(dev);
+
        if (sbsf->state == SF_CMD) {
                /* Figure out the initial state */
-               if (sandbox_sf_process_cmd(sbsf, rx, tx))
-                       return 1;
+               ret = sandbox_sf_process_cmd(sbsf, rx, tx);
+               if (ret)
+                       return ret;
                ++pos;
        }
 
@@ -290,7 +376,9 @@ static int sandbox_sf_xfer(void *priv, const u8 *rx, u8 *tx,
                                sbsf->off = (sbsf->off << 8) | rx[pos];
                        debug("addr:%06x\n", sbsf->off);
 
-                       sandbox_spi_tristate(&tx[pos++], 1);
+                       if (tx)
+                               sandbox_spi_tristate(&tx[pos], 1);
+                       pos++;
 
                        /* See if we're done processing */
                        if (sbsf->addr_bytes <
@@ -300,7 +388,7 @@ static int sandbox_sf_xfer(void *priv, const u8 *rx, u8 *tx,
                        /* Next state! */
                        if (os_lseek(sbsf->fd, sbsf->off, OS_SEEK_SET) < 0) {
                                puts("sandbox_sf: os_lseek() failed");
-                               return 1;
+                               return -EIO;
                        }
                        switch (sbsf->cmd) {
                        case CMD_READ_ARRAY_FAST:
@@ -326,10 +414,11 @@ static int sandbox_sf_xfer(void *priv, const u8 *rx, u8 *tx,
 
                        cnt = bytes - pos;
                        debug(" tx: read(%u)\n", cnt);
+                       assert(tx);
                        ret = os_read(sbsf->fd, tx + pos, cnt);
                        if (ret < 0) {
-                               puts("sandbox_spi: os_read() failed\n");
-                               return 1;
+                               puts("sandbox_sf: os_read() failed\n");
+                               return -EIO;
                        }
                        pos += ret;
                        break;
@@ -345,6 +434,10 @@ static int sandbox_sf_xfer(void *priv, const u8 *rx, u8 *tx,
                        memset(tx + pos, sbsf->status >> 8, cnt);
                        pos += cnt;
                        break;
+               case SF_WRITE_STATUS:
+                       debug(" write status: %#x (ignored)\n", rx[pos]);
+                       pos = bytes;
+                       break;
                case SF_WRITE:
                        /*
                         * XXX: need to handle exotic behavior:
@@ -359,11 +452,12 @@ static int sandbox_sf_xfer(void *priv, const u8 *rx, u8 *tx,
 
                        cnt = bytes - pos;
                        debug(" rx: write(%u)\n", cnt);
-                       sandbox_spi_tristate(&tx[pos], cnt);
+                       if (tx)
+                               sandbox_spi_tristate(&tx[pos], cnt);
                        ret = os_write(sbsf->fd, rx + pos, cnt);
                        if (ret < 0) {
                                puts("sandbox_spi: os_write() failed\n");
-                               return 1;
+                               return -EIO;
                        }
                        pos += ret;
                        sbsf->status &= ~STAT_WEL;
@@ -388,7 +482,8 @@ static int sandbox_sf_xfer(void *priv, const u8 *rx, u8 *tx,
                              sbsf->erase_size);
 
                        cnt = bytes - pos;
-                       sandbox_spi_tristate(&tx[pos], cnt);
+                       if (tx)
+                               sandbox_spi_tristate(&tx[pos], cnt);
                        pos += cnt;
 
                        /*
@@ -410,17 +505,33 @@ static int sandbox_sf_xfer(void *priv, const u8 *rx, u8 *tx,
        }
 
  done:
-       return pos == bytes ? 0 : 1;
+       if (flags & SPI_XFER_END)
+               sandbox_sf_cs_deactivate(dev);
+       return pos == bytes ? 0 : -EIO;
+}
+
+int sandbox_sf_ofdata_to_platdata(struct udevice *dev)
+{
+       struct sandbox_spi_flash_plat_data *pdata = dev_get_platdata(dev);
+       const void *blob = gd->fdt_blob;
+       int node = dev->of_offset;
+
+       pdata->filename = fdt_getprop(blob, node, "sandbox,filename", NULL);
+       pdata->device_name = fdt_getprop(blob, node, "compatible", NULL);
+       if (!pdata->filename || !pdata->device_name) {
+               debug("%s: Missing properties, filename=%s, device_name=%s\n",
+                     __func__, pdata->filename, pdata->device_name);
+               return -EINVAL;
+       }
+
+       return 0;
 }
 
-static const struct sandbox_spi_emu_ops sandbox_sf_ops = {
-       .setup         = sandbox_sf_setup,
-       .free          = sandbox_sf_free,
-       .cs_activate   = sandbox_sf_cs_activate,
-       .cs_deactivate = sandbox_sf_cs_deactivate,
+static const struct dm_spi_emul_ops sandbox_sf_emul_ops = {
        .xfer          = sandbox_sf_xfer,
 };
 
+#ifdef CONFIG_SPI_FLASH
 static int sandbox_cmdline_cb_spi_sf(struct sandbox_state *state,
                                     const char *arg)
 {
@@ -438,8 +549,141 @@ static int sandbox_cmdline_cb_spi_sf(struct sandbox_state *state,
         * spec here, but the problem is that no U-Boot init has been done
         * yet. Perhaps we can figure something out.
         */
-       state->spi[bus][cs].ops = &sandbox_sf_ops;
        state->spi[bus][cs].spec = spec;
        return 0;
 }
 SANDBOX_CMDLINE_OPT(spi_sf, 1, "connect a SPI flash: <bus>:<cs>:<id>:<file>");
+
+int sandbox_sf_bind_emul(struct sandbox_state *state, int busnum, int cs,
+                        struct udevice *bus, int of_offset, const char *spec)
+{
+       struct udevice *emul;
+       char name[20], *str;
+       struct driver *drv;
+       int ret;
+
+       /* now the emulator */
+       strncpy(name, spec, sizeof(name) - 6);
+       name[sizeof(name) - 6] = '\0';
+       strcat(name, "-emul");
+       str = strdup(name);
+       if (!str)
+               return -ENOMEM;
+       drv = lists_driver_lookup_name("sandbox_sf_emul");
+       if (!drv) {
+               puts("Cannot find sandbox_sf_emul driver\n");
+               return -ENOENT;
+       }
+       ret = device_bind(bus, drv, str, NULL, of_offset, &emul);
+       if (ret) {
+               printf("Cannot create emul device for spec '%s' (err=%d)\n",
+                      spec, ret);
+               return ret;
+       }
+       state->spi[busnum][cs].emul = emul;
+
+       return 0;
+}
+
+void sandbox_sf_unbind_emul(struct sandbox_state *state, int busnum, int cs)
+{
+       state->spi[busnum][cs].emul = NULL;
+}
+
+static int sandbox_sf_bind_bus_cs(struct sandbox_state *state, int busnum,
+                                 int cs, const char *spec)
+{
+       struct udevice *bus, *slave;
+       int ret;
+
+       ret = uclass_find_device_by_seq(UCLASS_SPI, busnum, true, &bus);
+       if (ret) {
+               printf("Invalid bus %d for spec '%s' (err=%d)\n", busnum,
+                      spec, ret);
+               return ret;
+       }
+       ret = device_find_child_by_seq(bus, cs, true, &slave);
+       if (!ret) {
+               printf("Chip select %d already exists for spec '%s'\n", cs,
+                      spec);
+               return -EEXIST;
+       }
+
+       ret = spi_bind_device(bus, cs, "spi_flash_std", spec, &slave);
+       if (ret)
+               return ret;
+
+       return sandbox_sf_bind_emul(state, busnum, cs, bus, -1, spec);
+}
+
+int sandbox_spi_get_emul(struct sandbox_state *state,
+                        struct udevice *bus, struct udevice *slave,
+                        struct udevice **emulp)
+{
+       struct sandbox_spi_info *info;
+       int busnum = bus->seq;
+       int cs = spi_chip_select(slave);
+       int ret;
+
+       info = &state->spi[busnum][cs];
+       if (!info->emul) {
+               /* Use the same device tree node as the SPI flash device */
+               debug("%s: busnum=%u, cs=%u: binding SPI flash emulation: ",
+                     __func__, busnum, cs);
+               ret = sandbox_sf_bind_emul(state, busnum, cs, bus,
+                                          slave->of_offset, slave->name);
+               if (ret) {
+                       debug("failed (err=%d)\n", ret);
+                       return ret;
+               }
+               debug("OK\n");
+       }
+       *emulp = info->emul;
+
+       return 0;
+}
+
+int dm_scan_other(bool pre_reloc_only)
+{
+       struct sandbox_state *state = state_get_current();
+       int busnum, cs;
+
+       if (pre_reloc_only)
+               return 0;
+       for (busnum = 0; busnum < CONFIG_SANDBOX_SPI_MAX_BUS; busnum++) {
+               for (cs = 0; cs < CONFIG_SANDBOX_SPI_MAX_CS; cs++) {
+                       const char *spec = state->spi[busnum][cs].spec;
+                       int ret;
+
+                       if (spec) {
+                               ret = sandbox_sf_bind_bus_cs(state, busnum,
+                                                            cs, spec);
+                               if (ret) {
+                                       debug("%s: Bind failed for bus %d, cs %d\n",
+                                             __func__, busnum, cs);
+                                       return ret;
+                               }
+                       }
+               }
+       }
+
+       return 0;
+}
+#endif
+
+static const struct udevice_id sandbox_sf_ids[] = {
+       { .compatible = "sandbox,spi-flash" },
+       { }
+};
+
+U_BOOT_DRIVER(sandbox_sf_emul) = {
+       .name           = "sandbox_sf_emul",
+       .id             = UCLASS_SPI_EMUL,
+       .of_match       = sandbox_sf_ids,
+       .ofdata_to_platdata = sandbox_sf_ofdata_to_platdata,
+       .probe          = sandbox_sf_probe,
+       .remove         = sandbox_sf_remove,
+       .priv_auto_alloc_size = sizeof(struct sandbox_spi_flash),
+       .platdata_auto_alloc_size = sizeof(struct sandbox_spi_flash_plat_data),
+       .ops            = &sandbox_sf_emul_ops,
+};
diff --git a/drivers/mtd/spi/sf-uclass.c b/drivers/mtd/spi/sf-uclass.c
new file mode 100644 (file)
index 0000000..376d815
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <spi.h>
+#include <spi_flash.h>
+#include <dm/device-internal.h>
+#include "sf_internal.h"
+
+/*
+ * TODO(sjg@chromium.org): This is an old-style function. We should remove
+ * it when all SPI flash drivers use dm
+ */
+struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs,
+                                 unsigned int max_hz, unsigned int spi_mode)
+{
+       struct udevice *dev;
+
+       if (spi_flash_probe_bus_cs(bus, cs, max_hz, spi_mode, &dev))
+               return NULL;
+
+       return dev->uclass_priv;
+}
+
+void spi_flash_free(struct spi_flash *flash)
+{
+       spi_flash_remove(flash->spi->dev);
+}
+
+int spi_flash_probe_bus_cs(unsigned int busnum, unsigned int cs,
+                          unsigned int max_hz, unsigned int spi_mode,
+                          struct udevice **devp)
+{
+       struct spi_slave *slave;
+       struct udevice *bus;
+       char name[20], *str;
+       int ret;
+
+       snprintf(name, sizeof(name), "%d:%d", busnum, cs);
+       str = strdup(name);
+       ret = spi_get_bus_and_cs(busnum, cs, max_hz, spi_mode,
+                                 "spi_flash_std", str, &bus, &slave);
+       if (ret)
+               return ret;
+
+       *devp = slave->dev;
+       return 0;
+}
+
+int spi_flash_remove(struct udevice *dev)
+{
+       return device_remove(dev);
+}
+
+UCLASS_DRIVER(spi_flash) = {
+       .id             = UCLASS_SPI_FLASH,
+       .name           = "spi_flash",
+       .per_device_auto_alloc_size = sizeof(struct spi_flash),
+};
index 19d49146ebd1520d9f6a481765acdbd884b384ee..5b7670c9aaf1219e841cd2dfc5096bb62e7e3390 100644 (file)
 #ifndef _SF_INTERNAL_H_
 #define _SF_INTERNAL_H_
 
+#include <linux/types.h>
+#include <linux/compiler.h>
+
+/* Dual SPI flash memories - see SPI_COMM_DUAL_... */
+enum spi_dual_flash {
+       SF_SINGLE_FLASH = 0,
+       SF_DUAL_STACKED_FLASH   = 1 << 0,
+       SF_DUAL_PARALLEL_FLASH  = 1 << 1,
+};
+
+/* Enum list - Full read commands */
+enum spi_read_cmds {
+       ARRAY_SLOW              = 1 << 0,
+       DUAL_OUTPUT_FAST        = 1 << 1,
+       DUAL_IO_FAST            = 1 << 2,
+       QUAD_OUTPUT_FAST        = 1 << 3,
+       QUAD_IO_FAST            = 1 << 4,
+};
+
+#define RD_EXTN        (ARRAY_SLOW | DUAL_OUTPUT_FAST | DUAL_IO_FAST)
+#define RD_FULL        (RD_EXTN | QUAD_OUTPUT_FAST | QUAD_IO_FAST)
+
+/* sf param flags */
+enum {
+       SECT_4K         = 1 << 0,
+       SECT_32K        = 1 << 1,
+       E_FSR           = 1 << 2,
+       WR_QPP          = 1 << 3,
+};
+
 #define SPI_FLASH_3B_ADDR_LEN          3
 #define SPI_FLASH_CMD_LEN              (1 + SPI_FLASH_3B_ADDR_LEN)
 #define SPI_FLASH_16MB_BOUN            0x1000000
 #define CMD_WRITE_STATUS               0x01
 #define CMD_PAGE_PROGRAM               0x02
 #define CMD_WRITE_DISABLE              0x04
-#define CMD_READ_STATUS                        0x05
+#define CMD_READ_STATUS                0x05
 #define CMD_QUAD_PAGE_PROGRAM          0x32
 #define CMD_READ_STATUS1               0x35
 #define CMD_WRITE_ENABLE               0x06
-#define CMD_READ_CONFIG                        0x35
-#define CMD_FLAG_STATUS                        0x70
+#define CMD_READ_CONFIG                0x35
+#define CMD_FLAG_STATUS                0x70
 
 /* Read commands */
 #define CMD_READ_ARRAY_SLOW            0x03
@@ -57,7 +87,7 @@
 /* Common status */
 #define STATUS_WIP                     (1 << 0)
 #define STATUS_QEB_WINSPAN             (1 << 1)
-#define STATUS_QEB_MXIC                        (1 << 6)
+#define STATUS_QEB_MXIC                (1 << 6)
 #define STATUS_PEC                     (1 << 7)
 
 #ifdef CONFIG_SYS_SPI_ST_ENABLE_WP_PIN
 
 /* Flash timeout values */
 #define SPI_FLASH_PROG_TIMEOUT         (2 * CONFIG_SYS_HZ)
-#define SPI_FLASH_PAGE_ERASE_TIMEOUT   (5 * CONFIG_SYS_HZ)
+#define SPI_FLASH_PAGE_ERASE_TIMEOUT           (5 * CONFIG_SYS_HZ)
 #define SPI_FLASH_SECTOR_ERASE_TIMEOUT (10 * CONFIG_SYS_HZ)
 
 /* SST specific */
 #ifdef CONFIG_SPI_FLASH_SST
-# define SST_WP                        0x01    /* Supports AAI word program */
+# define SST_WP                0x01    /* Supports AAI word program */
 # define CMD_SST_BP            0x02    /* Byte Program */
-# define CMD_SST_AAI_WP                0xAD    /* Auto Address Incr Word Program */
+# define CMD_SST_AAI_WP        0xAD    /* Auto Address Incr Word Program */
 
 int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len,
                const void *buf);
 #endif
 
+/**
+ * struct spi_flash_params - SPI/QSPI flash device params structure
+ *
+ * @name:              Device name ([MANUFLETTER][DEVTYPE][DENSITY][EXTRAINFO])
+ * @jedec:             Device jedec ID (0x[1byte_manuf_id][2byte_dev_id])
+ * @ext_jedec:         Device ext_jedec ID
+ * @sector_size:       Sector size of this device
+ * @nr_sectors:        No.of sectors on this device
+ * @e_rd_cmd:          Enum list for read commands
+ * @flags:             Important param, for flash specific behaviour
+ */
+struct spi_flash_params {
+       const char *name;
+       u32 jedec;
+       u16 ext_jedec;
+       u32 sector_size;
+       u32 nr_sectors;
+       u8 e_rd_cmd;
+       u16 flags;
+};
+
+extern const struct spi_flash_params spi_flash_params_table[];
+
 /* Send a single-byte command to the device and read the response */
 int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len);
 
index 453edf0149518cd69c945adcf2b3a270ddaebb62..61545cacaabe8415bf7a1a1fa35d2e7e8294e2b9 100644 (file)
@@ -7,6 +7,7 @@
  */
 
 #include <common.h>
+#include <spi.h>
 #include <spi_flash.h>
 
 #include "sf_internal.h"
index 4d148d1ace3749744cbc1e9ef190f5fdcb84649a..26364269be1a5e823efc99bd498262bd1a9d3393 100644 (file)
@@ -9,6 +9,8 @@
  */
 
 #include <common.h>
+#include <dm.h>
+#include <errno.h>
 #include <fdtdec.h>
 #include <malloc.h>
 #include <spi.h>
@@ -95,15 +97,15 @@ static int spi_flash_set_qeb(struct spi_flash *flash, u8 idcode0)
        }
 }
 
-static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi,
-               u8 *idcode)
+static int spi_flash_validate_params(struct spi_slave *spi, u8 *idcode,
+                                    struct spi_flash *flash)
 {
        const struct spi_flash_params *params;
-       struct spi_flash *flash;
        u8 cmd;
        u16 jedec = idcode[1] << 8 | idcode[2];
        u16 ext_jedec = idcode[3] << 8 | idcode[4];
 
+       /* Validate params from spi_flash_params table */
        params = spi_flash_params_table;
        for (; params->name != NULL; params++) {
                if ((params->jedec >> 16) == idcode[0]) {
@@ -120,13 +122,7 @@ static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi,
                printf("SF: Unsupported flash IDs: ");
                printf("manuf %02x, jedec %04x, ext_jedec %04x\n",
                       idcode[0], jedec, ext_jedec);
-               return NULL;
-       }
-
-       flash = calloc(1, sizeof(*flash));
-       if (!flash) {
-               debug("SF: Failed to allocate spi_flash\n");
-               return NULL;
+               return -EPROTONOSUPPORT;
        }
 
        /* Assign spi data */
@@ -136,13 +132,15 @@ static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi,
        flash->dual_flash = flash->spi->option;
 
        /* Assign spi_flash ops */
+#ifndef CONFIG_DM_SPI_FLASH
        flash->write = spi_flash_cmd_write_ops;
-#ifdef CONFIG_SPI_FLASH_SST
+#if defined(CONFIG_SPI_FLASH_SST)
        if (params->flags & SST_WP)
                flash->write = sst_write_wp;
 #endif
        flash->erase = spi_flash_cmd_erase_ops;
        flash->read = spi_flash_cmd_read_ops;
+#endif
 
        /* Compute the flash size */
        flash->shift = (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) ? 1 : 0;
@@ -227,15 +225,18 @@ static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi,
 #ifdef CONFIG_SPI_FLASH_BAR
        u8 curr_bank = 0;
        if (flash->size > SPI_FLASH_16MB_BOUN) {
+               int ret;
+
                flash->bank_read_cmd = (idcode[0] == 0x01) ?
                                        CMD_BANKADDR_BRRD : CMD_EXTNADDR_RDEAR;
                flash->bank_write_cmd = (idcode[0] == 0x01) ?
                                        CMD_BANKADDR_BRWR : CMD_EXTNADDR_WREAR;
 
-               if (spi_flash_read_common(flash, &flash->bank_read_cmd, 1,
-                                         &curr_bank, 1)) {
+               ret = spi_flash_read_common(flash, &flash->bank_read_cmd, 1,
+                                           &curr_bank, 1);
+               if (ret) {
                        debug("SF: fail to read bank addr register\n");
-                       return NULL;
+                       return ret;
                }
                flash->bank_curr = curr_bank;
        } else {
@@ -250,7 +251,7 @@ static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi,
                spi_flash_cmd_write_status(flash, 0);
 #endif
 
-       return flash;
+       return 0;
 }
 
 #ifdef CONFIG_OF_CONTROL
@@ -309,23 +310,29 @@ static int spi_enable_wp_pin(struct spi_flash *flash)
 }
 #endif
 
-static struct spi_flash *spi_flash_probe_slave(struct spi_slave *spi)
+/**
+ * spi_flash_probe_slave() - Probe for a SPI flash device on a bus
+ *
+ * @spi: Bus to probe
+ * @flashp: Pointer to place to put flash info, which may be NULL if the
+ * space should be allocated
+ */
+int spi_flash_probe_slave(struct spi_slave *spi, struct spi_flash *flash)
 {
-       struct spi_flash *flash = NULL;
        u8 idcode[5];
        int ret;
 
        /* Setup spi_slave */
        if (!spi) {
                printf("SF: Failed to set up slave\n");
-               return NULL;
+               return -ENODEV;
        }
 
        /* Claim spi bus */
        ret = spi_claim_bus(spi);
        if (ret) {
                debug("SF: Failed to claim SPI bus: %d\n", ret);
-               goto err_claim_bus;
+               return ret;
        }
 
        /* Read the ID codes */
@@ -340,10 +347,10 @@ static struct spi_flash *spi_flash_probe_slave(struct spi_slave *spi)
        print_buffer(0, idcode, 1, sizeof(idcode), 0);
 #endif
 
-       /* Validate params from spi_flash_params table */
-       flash = spi_flash_validate_params(spi, idcode);
-       if (!flash)
+       if (spi_flash_validate_params(spi, idcode, flash)) {
+               ret = -EINVAL;
                goto err_read_id;
+       }
 
        /* Set the quad enable bit - only for quad commands */
        if ((flash->read_cmd == CMD_READ_QUAD_OUTPUT_FAST) ||
@@ -351,13 +358,15 @@ static struct spi_flash *spi_flash_probe_slave(struct spi_slave *spi)
            (flash->write_cmd == CMD_QUAD_PAGE_PROGRAM)) {
                if (spi_flash_set_qeb(flash, idcode[0])) {
                        debug("SF: Fail to set QEB for %02x\n", idcode[0]);
-                       return NULL;
+                       ret = -EINVAL;
+                       goto err_read_id;
                }
        }
 
 #ifdef CONFIG_OF_CONTROL
        if (spi_flash_decode_fdt(gd->fdt_blob, flash)) {
                debug("SF: FDT decode error\n");
+               ret = -EINVAL;
                goto err_read_id;
        }
 #endif
@@ -385,32 +394,51 @@ static struct spi_flash *spi_flash_probe_slave(struct spi_slave *spi)
        /* Release spi bus */
        spi_release_bus(spi);
 
-       return flash;
+       return 0;
 
 err_read_id:
        spi_release_bus(spi);
-err_claim_bus:
-       spi_free_slave(spi);
-       return NULL;
+       return ret;
 }
 
-struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs,
+#ifndef CONFIG_DM_SPI_FLASH
+struct spi_flash *spi_flash_probe_tail(struct spi_slave *bus)
+{
+       struct spi_flash *flash;
+
+       /* Allocate space if needed (not used by sf-uclass */
+       flash = calloc(1, sizeof(*flash));
+       if (!flash) {
+               debug("SF: Failed to allocate spi_flash\n");
+               return NULL;
+       }
+
+       if (spi_flash_probe_slave(bus, flash)) {
+               spi_free_slave(bus);
+               free(flash);
+               return NULL;
+       }
+
+       return flash;
+}
+
+struct spi_flash *spi_flash_probe(unsigned int busnum, unsigned int cs,
                unsigned int max_hz, unsigned int spi_mode)
 {
-       struct spi_slave *spi;
+       struct spi_slave *bus;
 
-       spi = spi_setup_slave(bus, cs, max_hz, spi_mode);
-       return spi_flash_probe_slave(spi);
+       bus = spi_setup_slave(busnum, cs, max_hz, spi_mode);
+       return spi_flash_probe_tail(bus);
 }
 
 #ifdef CONFIG_OF_SPI_FLASH
 struct spi_flash *spi_flash_probe_fdt(const void *blob, int slave_node,
                                      int spi_node)
 {
-       struct spi_slave *spi;
+       struct spi_slave *bus;
 
-       spi = spi_setup_slave_fdt(blob, slave_node, spi_node);
-       return spi_flash_probe_slave(spi);
+       bus = spi_setup_slave_fdt(blob, slave_node, spi_node);
+       return spi_flash_probe_tail(bus);
 }
 #endif
 
@@ -419,3 +447,61 @@ void spi_flash_free(struct spi_flash *flash)
        spi_free_slave(flash->spi);
        free(flash);
 }
+
+#else /* defined CONFIG_DM_SPI_FLASH */
+
+static int spi_flash_std_read(struct udevice *dev, u32 offset, size_t len,
+                             void *buf)
+{
+       struct spi_flash *flash = dev->uclass_priv;
+
+       return spi_flash_cmd_read_ops(flash, offset, len, buf);
+}
+
+int spi_flash_std_write(struct udevice *dev, u32 offset, size_t len,
+                       const void *buf)
+{
+       struct spi_flash *flash = dev->uclass_priv;
+
+       return spi_flash_cmd_write_ops(flash, offset, len, buf);
+}
+
+int spi_flash_std_erase(struct udevice *dev, u32 offset, size_t len)
+{
+       struct spi_flash *flash = dev->uclass_priv;
+
+       return spi_flash_cmd_erase_ops(flash, offset, len);
+}
+
+int spi_flash_std_probe(struct udevice *dev)
+{
+       struct spi_slave *slave = dev_get_parentdata(dev);
+       struct spi_flash *flash;
+
+       flash = dev->uclass_priv;
+       flash->dev = dev;
+       debug("%s: slave=%p, cs=%d\n", __func__, slave, slave->cs);
+       return spi_flash_probe_slave(slave, flash);
+}
+
+static const struct dm_spi_flash_ops spi_flash_std_ops = {
+       .read = spi_flash_std_read,
+       .write = spi_flash_std_write,
+       .erase = spi_flash_std_erase,
+};
+
+static const struct udevice_id spi_flash_std_ids[] = {
+       { .compatible = "spi-flash" },
+       { }
+};
+
+U_BOOT_DRIVER(spi_flash_std) = {
+       .name           = "spi_flash_std",
+       .id             = UCLASS_SPI_FLASH,
+       .of_match       = spi_flash_std_ids,
+       .probe          = spi_flash_std_probe,
+       .priv_auto_alloc_size = sizeof(struct spi_flash),
+       .ops            = &spi_flash_std_ops,
+};
+
+#endif /* CONFIG_DM_SPI_FLASH */
index 59cca0f4d998d1d6b87f9b7ca0a16180f8840bcd..2e0c871219bd05ac31c63a80ba793e1dc1255899 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 #include <common.h>
+#include <spi.h>
 #include <spi_flash.h>
 #include <spl.h>
 
index b4f299bb0ede65966624972b900c09142f202e24..17c56ea66e8e65185110bfa91b20069da675fbfa 100644 (file)
@@ -7,8 +7,11 @@
 
 ifdef CONFIG_DM_SERIAL
 obj-y += serial-uclass.o
+obj-$(CONFIG_PL01X_SERIAL) += serial_pl01x.o
 else
 obj-y += serial.o
+obj-$(CONFIG_PL010_SERIAL) += serial_pl01x.o
+obj-$(CONFIG_PL011_SERIAL) += serial_pl01x.o
 obj-$(CONFIG_SYS_NS16550_SERIAL) += serial_ns16550.o
 endif
 
@@ -25,8 +28,6 @@ obj-$(CONFIG_IMX_SERIAL) += serial_imx.o
 obj-$(CONFIG_KS8695_SERIAL) += serial_ks8695.o
 obj-$(CONFIG_MAX3100_SERIAL) += serial_max3100.o
 obj-$(CONFIG_MXC_UART) += serial_mxc.o
-obj-$(CONFIG_PL010_SERIAL) += serial_pl01x.o
-obj-$(CONFIG_PL011_SERIAL) += serial_pl01x.o
 obj-$(CONFIG_PXA_SERIAL) += serial_pxa.o
 obj-$(CONFIG_SA1100_SERIAL) += serial_sa1100.o
 obj-$(CONFIG_S3C24X0_SERIAL) += serial_s3c24x0.o
index 6dde4eaf47286a3a38feb3c84a782c5421c01630..1a75950d19fa4c738f7f5c881da08561d416faf2 100644 (file)
@@ -71,7 +71,7 @@ void serial_initialize(void)
        serial_find_console_or_panic();
 }
 
-void serial_putc(char ch)
+static void serial_putc_dev(struct udevice *dev, char ch)
 {
        struct dm_serial_ops *ops = serial_get_ops(cur_dev);
        int err;
@@ -83,6 +83,11 @@ void serial_putc(char ch)
                serial_putc('\r');
 }
 
+void serial_putc(char ch)
+{
+       serial_putc_dev(cur_dev, ch);
+}
+
 void serial_setbrg(void)
 {
        struct dm_serial_ops *ops = serial_get_ops(cur_dev);
@@ -107,28 +112,32 @@ int serial_tstc(void)
        return 1;
 }
 
-int serial_getc(void)
+static int serial_getc_dev(struct udevice *dev)
 {
-       struct dm_serial_ops *ops = serial_get_ops(cur_dev);
+       struct dm_serial_ops *ops = serial_get_ops(dev);
        int err;
 
        do {
-               err = ops->getc(cur_dev);
+               err = ops->getc(dev);
        } while (err == -EAGAIN);
 
        return err >= 0 ? err : 0;
 }
 
+int serial_getc(void)
+{
+       return serial_getc_dev(cur_dev);
+}
+
 void serial_stdio_init(void)
 {
 }
 
-void serial_stub_putc(struct stdio_dev *sdev, const char ch)
+static void serial_stub_putc(struct stdio_dev *sdev, const char ch)
 {
        struct udevice *dev = sdev->priv;
-       struct dm_serial_ops *ops = serial_get_ops(dev);
 
-       ops->putc(dev, ch);
+       serial_putc_dev(dev, ch);
 }
 
 void serial_stub_puts(struct stdio_dev *sdev, const char *str)
@@ -140,15 +149,8 @@ void serial_stub_puts(struct stdio_dev *sdev, const char *str)
 int serial_stub_getc(struct stdio_dev *sdev)
 {
        struct udevice *dev = sdev->priv;
-       struct dm_serial_ops *ops = serial_get_ops(dev);
-
-       int err;
 
-       do {
-               err = ops->getc(dev);
-       } while (err == -EAGAIN);
-
-       return err >= 0 ? err : 0;
+       return serial_getc_dev(dev);
 }
 
 int serial_stub_tstc(struct stdio_dev *sdev)
index 313d560afce8635f3b1f29c3ea029173b69f8c40..9ce24f9f932d932f6244479241809b8858a696a4 100644 (file)
@@ -5,37 +5,15 @@
  */
 
 #include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <serial_mxc.h>
 #include <watchdog.h>
 #include <asm/arch/imx-regs.h>
 #include <asm/arch/clock.h>
 #include <serial.h>
 #include <linux/compiler.h>
 
-#define __REG(x)     (*((volatile u32 *)(x)))
-
-#ifndef CONFIG_MXC_UART_BASE
-#error "define CONFIG_MXC_UART_BASE to use the MXC UART driver"
-#endif
-
-#define UART_PHYS      CONFIG_MXC_UART_BASE
-
-/* Register definitions */
-#define URXD  0x0  /* Receiver Register */
-#define UTXD  0x40 /* Transmitter Register */
-#define UCR1  0x80 /* Control Register 1 */
-#define UCR2  0x84 /* Control Register 2 */
-#define UCR3  0x88 /* Control Register 3 */
-#define UCR4  0x8c /* Control Register 4 */
-#define UFCR  0x90 /* FIFO Control Register */
-#define USR1  0x94 /* Status Register 1 */
-#define USR2  0x98 /* Status Register 2 */
-#define UESC  0x9c /* Escape Character Register */
-#define UTIM  0xa0 /* Escape Timer Register */
-#define UBIR  0xa4 /* BRM Incremental Register */
-#define UBMR  0xa8 /* BRM Modulator Register */
-#define UBRC  0xac /* Baud Rate Count Register */
-#define UTS   0xb4 /* UART Test Register (mx31) */
-
 /* UART Control Register Bit Fields.*/
 #define  URXD_CHARRDY    (1<<15)
 #define  URXD_ERR        (1<<14)
 #define  UTS_RXFULL     (1<<3)  /* RxFIFO full */
 #define  UTS_SOFTRST    (1<<0)  /* Software reset */
 
+#ifndef CONFIG_DM_SERIAL
+
+#ifndef CONFIG_MXC_UART_BASE
+#error "define CONFIG_MXC_UART_BASE to use the MXC UART driver"
+#endif
+
+#define UART_PHYS      CONFIG_MXC_UART_BASE
+
+#define __REG(x)     (*((volatile u32 *)(x)))
+
+/* Register definitions */
+#define URXD  0x0  /* Receiver Register */
+#define UTXD  0x40 /* Transmitter Register */
+#define UCR1  0x80 /* Control Register 1 */
+#define UCR2  0x84 /* Control Register 2 */
+#define UCR3  0x88 /* Control Register 3 */
+#define UCR4  0x8c /* Control Register 4 */
+#define UFCR  0x90 /* FIFO Control Register */
+#define USR1  0x94 /* Status Register 1 */
+#define USR2  0x98 /* Status Register 2 */
+#define UESC  0x9c /* Escape Character Register */
+#define UTIM  0xa0 /* Escape Timer Register */
+#define UBIR  0xa4 /* BRM Incremental Register */
+#define UBMR  0xa8 /* BRM Modulator Register */
+#define UBRC  0xac /* Baud Rate Count Register */
+#define UTS   0xb4 /* UART Test Register (mx31) */
+
 DECLARE_GLOBAL_DATA_PTR;
 
 static void mxc_serial_setbrg(void)
@@ -222,3 +227,118 @@ __weak struct serial_device *default_serial_console(void)
 {
        return &mxc_serial_drv;
 }
+#endif
+
+#ifdef CONFIG_DM_SERIAL
+
+struct mxc_uart {
+       u32 rxd;
+       u32 spare0[15];
+
+       u32 txd;
+       u32 spare1[15];
+
+       u32 cr1;
+       u32 cr2;
+       u32 cr3;
+       u32 cr4;
+
+       u32 fcr;
+       u32 sr1;
+       u32 sr2;
+       u32 esc;
+
+       u32 tim;
+       u32 bir;
+       u32 bmr;
+       u32 brc;
+
+       u32 onems;
+       u32 ts;
+};
+
+int mxc_serial_setbrg(struct udevice *dev, int baudrate)
+{
+       struct mxc_serial_platdata *plat = dev->platdata;
+       struct mxc_uart *const uart = plat->reg;
+       u32 clk = imx_get_uartclk();
+
+       writel(4 << 7, &uart->fcr); /* divide input clock by 2 */
+       writel(0xf, &uart->bir);
+       writel(clk / (2 * baudrate), &uart->bmr);
+
+       writel(UCR2_WS | UCR2_IRTS | UCR2_RXEN | UCR2_TXEN | UCR2_SRST,
+              &uart->cr2);
+       writel(UCR1_UARTEN, &uart->cr1);
+
+       return 0;
+}
+
+static int mxc_serial_probe(struct udevice *dev)
+{
+       struct mxc_serial_platdata *plat = dev->platdata;
+       struct mxc_uart *const uart = plat->reg;
+
+       writel(0, &uart->cr1);
+       writel(0, &uart->cr2);
+       while (!(readl(&uart->cr2) & UCR2_SRST));
+       writel(0x704 | UCR3_ADNIMP, &uart->cr3);
+       writel(0x8000, &uart->cr4);
+       writel(0x2b, &uart->esc);
+       writel(0, &uart->tim);
+       writel(0, &uart->ts);
+
+       return 0;
+}
+
+static int mxc_serial_getc(struct udevice *dev)
+{
+       struct mxc_serial_platdata *plat = dev->platdata;
+       struct mxc_uart *const uart = plat->reg;
+
+       if (readl(&uart->ts) & UTS_RXEMPTY)
+               return -EAGAIN;
+
+       return readl(&uart->rxd) & URXD_RX_DATA;
+}
+
+static int mxc_serial_putc(struct udevice *dev, const char ch)
+{
+       struct mxc_serial_platdata *plat = dev->platdata;
+       struct mxc_uart *const uart = plat->reg;
+
+       if (!(readl(&uart->ts) & UTS_TXEMPTY))
+               return -EAGAIN;
+
+       writel(ch, &uart->txd);
+
+       return 0;
+}
+
+static int mxc_serial_pending(struct udevice *dev, bool input)
+{
+       struct mxc_serial_platdata *plat = dev->platdata;
+       struct mxc_uart *const uart = plat->reg;
+       uint32_t sr2 = readl(&uart->sr2);
+
+       if (input)
+               return sr2 & USR2_RDR ? 1 : 0;
+       else
+               return sr2 & USR2_TXDC ? 0 : 1;
+}
+
+static const struct dm_serial_ops mxc_serial_ops = {
+       .putc = mxc_serial_putc,
+       .pending = mxc_serial_pending,
+       .getc = mxc_serial_getc,
+       .setbrg = mxc_serial_setbrg,
+};
+
+U_BOOT_DRIVER(serial_mxc) = {
+       .name   = "serial_mxc",
+       .id     = UCLASS_SERIAL,
+       .probe = mxc_serial_probe,
+       .ops    = &mxc_serial_ops,
+       .flags = DM_FLAG_PRE_RELOC,
+};
+#endif
index dfb610e1a9d553429d1462335a6550f6d31afe04..e6313ad3d3a8d238a774543bab6777964b04627f 100644 (file)
 /* Simple U-Boot driver for the PrimeCell PL010/PL011 UARTs */
 
 #include <common.h>
+#include <dm.h>
+#include <errno.h>
 #include <watchdog.h>
 #include <asm/io.h>
 #include <serial.h>
+#include <serial_pl01x.h>
 #include <linux/compiler.h>
-#include "serial_pl01x.h"
+#include "serial_pl01x_internal.h"
+
+#ifndef CONFIG_DM_SERIAL
 
-/*
- * Integrator AP has two UARTs, we use the first one, at 38400-8-N-1
- * Integrator CP has two UARTs, use the first one, at 38400-8-N-1
- * Versatile PB has four UARTs.
- */
-#define CONSOLE_PORT CONFIG_CONS_INDEX
 static volatile unsigned char *const port[] = CONFIG_PL01x_PORTS;
+static enum pl01x_type pl01x_type __attribute__ ((section(".data")));
+static struct pl01x_regs *base_regs __attribute__ ((section(".data")));
 #define NUM_PORTS (sizeof(port)/sizeof(port[0]))
 
-static void pl01x_putc (int portnum, char c);
-static int pl01x_getc (int portnum);
-static int pl01x_tstc (int portnum);
-unsigned int baudrate = CONFIG_BAUDRATE;
 DECLARE_GLOBAL_DATA_PTR;
+#endif
 
-static struct pl01x_regs *pl01x_get_regs(int portnum)
-{
-       return (struct pl01x_regs *) port[portnum];
-}
-
-#ifdef CONFIG_PL010_SERIAL
-
-static int pl01x_serial_init(void)
+static int pl01x_putc(struct pl01x_regs *regs, char c)
 {
-       struct pl01x_regs *regs = pl01x_get_regs(CONSOLE_PORT);
-       unsigned int divisor;
-
-       /* First, disable everything */
-       writel(0, &regs->pl010_cr);
+       /* Wait until there is space in the FIFO */
+       if (readl(&regs->fr) & UART_PL01x_FR_TXFF)
+               return -EAGAIN;
 
-       /* Set baud rate */
-       switch (baudrate) {
-       case 9600:
-               divisor = UART_PL010_BAUD_9600;
-               break;
+       /* Send the character */
+       writel(c, &regs->dr);
 
-       case 19200:
-               divisor = UART_PL010_BAUD_9600;
-               break;
+       return 0;
+}
 
-       case 38400:
-               divisor = UART_PL010_BAUD_38400;
-               break;
+static int pl01x_getc(struct pl01x_regs *regs)
+{
+       unsigned int data;
 
-       case 57600:
-               divisor = UART_PL010_BAUD_57600;
-               break;
+       /* Wait until there is data in the FIFO */
+       if (readl(&regs->fr) & UART_PL01x_FR_RXFE)
+               return -EAGAIN;
 
-       case 115200:
-               divisor = UART_PL010_BAUD_115200;
-               break;
+       data = readl(&regs->dr);
 
-       default:
-               divisor = UART_PL010_BAUD_38400;
+       /* Check for an error flag */
+       if (data & 0xFFFFFF00) {
+               /* Clear the error */
+               writel(0xFFFFFFFF, &regs->ecr);
+               return -1;
        }
 
-       writel((divisor & 0xf00) >> 8, &regs->pl010_lcrm);
-       writel(divisor & 0xff, &regs->pl010_lcrl);
-
-       /* Set the UART to be 8 bits, 1 stop bit, no parity, fifo enabled */
-       writel(UART_PL010_LCRH_WLEN_8 | UART_PL010_LCRH_FEN, &regs->pl010_lcrh);
-
-       /* Finally, enable the UART */
-       writel(UART_PL010_CR_UARTEN, &regs->pl010_cr);
-
-       return 0;
+       return (int) data;
 }
 
-#endif /* CONFIG_PL010_SERIAL */
-
-#ifdef CONFIG_PL011_SERIAL
+static int pl01x_tstc(struct pl01x_regs *regs)
+{
+       WATCHDOG_RESET();
+       return !(readl(&regs->fr) & UART_PL01x_FR_RXFE);
+}
 
-static int pl01x_serial_init(void)
+static int pl01x_generic_serial_init(struct pl01x_regs *regs,
+                                    enum pl01x_type type)
 {
-       struct pl01x_regs *regs = pl01x_get_regs(CONSOLE_PORT);
-       unsigned int temp;
-       unsigned int divider;
-       unsigned int remainder;
-       unsigned int fraction;
        unsigned int lcr;
 
 #ifdef CONFIG_PL011_SERIAL_FLUSH_ON_INIT
-       /* Empty RX fifo if necessary */
-       if (readl(&regs->pl011_cr) & UART_PL011_CR_UARTEN) {
-               while (!(readl(&regs->fr) & UART_PL01x_FR_RXFE))
-                       readl(&regs->dr);
+       if (type == TYPE_PL011) {
+               /* Empty RX fifo if necessary */
+               if (readl(&regs->pl011_cr) & UART_PL011_CR_UARTEN) {
+                       while (!(readl(&regs->fr) & UART_PL01x_FR_RXFE))
+                               readl(&regs->dr);
+               }
        }
 #endif
 
        /* First, disable everything */
-       writel(0, &regs->pl011_cr);
-
-       /*
-        * Set baud rate
-        *
-        * IBRD = UART_CLK / (16 * BAUD_RATE)
-        * FBRD = RND((64 * MOD(UART_CLK,(16 * BAUD_RATE))) / (16 * BAUD_RATE))
-        */
-       temp = 16 * baudrate;
-       divider = CONFIG_PL011_CLOCK / temp;
-       remainder = CONFIG_PL011_CLOCK % temp;
-       temp = (8 * remainder) / baudrate;
-       fraction = (temp >> 1) + (temp & 1);
-
-       writel(divider, &regs->pl011_ibrd);
-       writel(fraction, &regs->pl011_fbrd);
+       writel(0, &regs->pl010_cr);
 
        /* Set the UART to be 8 bits, 1 stop bit, no parity, fifo enabled */
        lcr = UART_PL011_LCRH_WLEN_8 | UART_PL011_LCRH_FEN;
        writel(lcr, &regs->pl011_lcrh);
 
+       switch (type) {
+       case TYPE_PL010:
+               break;
+       case TYPE_PL011: {
 #ifdef CONFIG_PL011_SERIAL_RLCR
-       {
                int i;
 
                /*
@@ -144,90 +109,151 @@ static int pl01x_serial_init(void)
                writel(lcr, &regs->pl011_rlcr);
                /* lcrh needs to be set again for change to be effective */
                writel(lcr, &regs->pl011_lcrh);
-       }
 #endif
-       /* Finally, enable the UART */
-       writel(UART_PL011_CR_UARTEN | UART_PL011_CR_TXE | UART_PL011_CR_RXE |
-              UART_PL011_CR_RTS, &regs->pl011_cr);
+               break;
+       }
+       default:
+               return -EINVAL;
+       }
 
        return 0;
 }
 
-#endif /* CONFIG_PL011_SERIAL */
-
-static void pl01x_serial_putc(const char c)
+static int pl01x_generic_setbrg(struct pl01x_regs *regs, enum pl01x_type type,
+                               int clock, int baudrate)
 {
-       if (c == '\n')
-               pl01x_putc (CONSOLE_PORT, '\r');
+       switch (type) {
+       case TYPE_PL010: {
+               unsigned int divisor;
+
+               switch (baudrate) {
+               case 9600:
+                       divisor = UART_PL010_BAUD_9600;
+                       break;
+               case 19200:
+                       divisor = UART_PL010_BAUD_9600;
+                       break;
+               case 38400:
+                       divisor = UART_PL010_BAUD_38400;
+                       break;
+               case 57600:
+                       divisor = UART_PL010_BAUD_57600;
+                       break;
+               case 115200:
+                       divisor = UART_PL010_BAUD_115200;
+                       break;
+               default:
+                       divisor = UART_PL010_BAUD_38400;
+               }
+
+               writel((divisor & 0xf00) >> 8, &regs->pl010_lcrm);
+               writel(divisor & 0xff, &regs->pl010_lcrl);
+
+               /* Finally, enable the UART */
+               writel(UART_PL010_CR_UARTEN, &regs->pl010_cr);
+               break;
+       }
+       case TYPE_PL011: {
+               unsigned int temp;
+               unsigned int divider;
+               unsigned int remainder;
+               unsigned int fraction;
 
-       pl01x_putc (CONSOLE_PORT, c);
-}
+               /*
+               * Set baud rate
+               *
+               * IBRD = UART_CLK / (16 * BAUD_RATE)
+               * FBRD = RND((64 * MOD(UART_CLK,(16 * BAUD_RATE)))
+               *               / (16 * BAUD_RATE))
+               */
+               temp = 16 * baudrate;
+               divider = clock / temp;
+               remainder = clock % temp;
+               temp = (8 * remainder) / baudrate;
+               fraction = (temp >> 1) + (temp & 1);
+
+               writel(divider, &regs->pl011_ibrd);
+               writel(fraction, &regs->pl011_fbrd);
+
+               /* Finally, enable the UART */
+               writel(UART_PL011_CR_UARTEN | UART_PL011_CR_TXE |
+                      UART_PL011_CR_RXE | UART_PL011_CR_RTS, &regs->pl011_cr);
+               break;
+       }
+       default:
+               return -EINVAL;
+       }
 
-static int pl01x_serial_getc(void)
-{
-       return pl01x_getc (CONSOLE_PORT);
+       return 0;
 }
 
-static int pl01x_serial_tstc(void)
+#ifndef CONFIG_DM_SERIAL
+static void pl01x_serial_init_baud(int baudrate)
 {
-       return pl01x_tstc (CONSOLE_PORT);
+       int clock = 0;
+
+#if defined(CONFIG_PL010_SERIAL)
+       pl01x_type = TYPE_PL010;
+#elif defined(CONFIG_PL011_SERIAL)
+       pl01x_type = TYPE_PL011;
+       clock = CONFIG_PL011_CLOCK;
+#endif
+       base_regs = (struct pl01x_regs *)port[CONFIG_CONS_INDEX];
+
+       pl01x_generic_serial_init(base_regs, pl01x_type);
+       pl01x_generic_setbrg(base_regs, TYPE_PL010, clock, baudrate);
 }
 
-static void pl01x_serial_setbrg(void)
+/*
+ * Integrator AP has two UARTs, we use the first one, at 38400-8-N-1
+ * Integrator CP has two UARTs, use the first one, at 38400-8-N-1
+ * Versatile PB has four UARTs.
+ */
+int pl01x_serial_init(void)
 {
-       struct pl01x_regs *regs = pl01x_get_regs(CONSOLE_PORT);
+       pl01x_serial_init_baud(CONFIG_BAUDRATE);
 
-       baudrate = gd->baudrate;
-       /*
-        * Flush FIFO and wait for non-busy before changing baudrate to avoid
-        * crap in console
-        */
-       while (!(readl(&regs->fr) & UART_PL01x_FR_TXFE))
-               WATCHDOG_RESET();
-       while (readl(&regs->fr) & UART_PL01x_FR_BUSY)
-               WATCHDOG_RESET();
-       serial_init();
+       return 0;
 }
 
-static void pl01x_putc (int portnum, char c)
+static void pl01x_serial_putc(const char c)
 {
-       struct pl01x_regs *regs = pl01x_get_regs(portnum);
-
-       /* Wait until there is space in the FIFO */
-       while (readl(&regs->fr) & UART_PL01x_FR_TXFF)
-               WATCHDOG_RESET();
+       if (c == '\n')
+               while (pl01x_putc(base_regs, '\r') == -EAGAIN);
 
-       /* Send the character */
-       writel(c, &regs->dr);
+       while (pl01x_putc(base_regs, c) == -EAGAIN);
 }
 
-static int pl01x_getc (int portnum)
+static int pl01x_serial_getc(void)
 {
-       struct pl01x_regs *regs = pl01x_get_regs(portnum);
-       unsigned int data;
+       while (1) {
+               int ch = pl01x_getc(base_regs);
 
-       /* Wait until there is data in the FIFO */
-       while (readl(&regs->fr) & UART_PL01x_FR_RXFE)
-               WATCHDOG_RESET();
-
-       data = readl(&regs->dr);
+               if (ch == -EAGAIN) {
+                       WATCHDOG_RESET();
+                       continue;
+               }
 
-       /* Check for an error flag */
-       if (data & 0xFFFFFF00) {
-               /* Clear the error */
-               writel(0xFFFFFFFF, &regs->ecr);
-               return -1;
+               return ch;
        }
-
-       return (int) data;
 }
 
-static int pl01x_tstc (int portnum)
+static int pl01x_serial_tstc(void)
 {
-       struct pl01x_regs *regs = pl01x_get_regs(portnum);
+       return pl01x_tstc(base_regs);
+}
 
-       WATCHDOG_RESET();
-       return !(readl(&regs->fr) & UART_PL01x_FR_RXFE);
+static void pl01x_serial_setbrg(void)
+{
+       /*
+        * Flush FIFO and wait for non-busy before changing baudrate to avoid
+        * crap in console
+        */
+       while (!(readl(&base_regs->fr) & UART_PL01x_FR_TXFE))
+               WATCHDOG_RESET();
+       while (readl(&base_regs->fr) & UART_PL01x_FR_BUSY)
+               WATCHDOG_RESET();
+       pl01x_serial_init_baud(gd->baudrate);
 }
 
 static struct serial_device pl01x_serial_drv = {
@@ -250,3 +276,74 @@ __weak struct serial_device *default_serial_console(void)
 {
        return &pl01x_serial_drv;
 }
+
+#endif /* nCONFIG_DM_SERIAL */
+
+#ifdef CONFIG_DM_SERIAL
+
+struct pl01x_priv {
+       struct pl01x_regs *regs;
+       enum pl01x_type type;
+};
+
+static int pl01x_serial_setbrg(struct udevice *dev, int baudrate)
+{
+       struct pl01x_serial_platdata *plat = dev_get_platdata(dev);
+       struct pl01x_priv *priv = dev_get_priv(dev);
+
+       pl01x_generic_setbrg(priv->regs, priv->type, plat->clock, baudrate);
+
+       return 0;
+}
+
+static int pl01x_serial_probe(struct udevice *dev)
+{
+       struct pl01x_serial_platdata *plat = dev_get_platdata(dev);
+       struct pl01x_priv *priv = dev_get_priv(dev);
+
+       priv->regs = (struct pl01x_regs *)plat->base;
+       priv->type = plat->type;
+       return pl01x_generic_serial_init(priv->regs, priv->type);
+}
+
+static int pl01x_serial_getc(struct udevice *dev)
+{
+       struct pl01x_priv *priv = dev_get_priv(dev);
+
+       return pl01x_getc(priv->regs);
+}
+
+static int pl01x_serial_putc(struct udevice *dev, const char ch)
+{
+       struct pl01x_priv *priv = dev_get_priv(dev);
+
+       return pl01x_putc(priv->regs, ch);
+}
+
+static int pl01x_serial_pending(struct udevice *dev, bool input)
+{
+       struct pl01x_priv *priv = dev_get_priv(dev);
+       unsigned int fr = readl(&priv->regs->fr);
+
+       if (input)
+               return pl01x_tstc(priv->regs);
+       else
+               return fr & UART_PL01x_FR_TXFF ? 0 : 1;
+}
+
+static const struct dm_serial_ops pl01x_serial_ops = {
+       .putc = pl01x_serial_putc,
+       .pending = pl01x_serial_pending,
+       .getc = pl01x_serial_getc,
+       .setbrg = pl01x_serial_setbrg,
+};
+
+U_BOOT_DRIVER(serial_pl01x) = {
+       .name   = "serial_pl01x",
+       .id     = UCLASS_SERIAL,
+       .probe = pl01x_serial_probe,
+       .ops    = &pl01x_serial_ops,
+       .flags = DM_FLAG_PRE_RELOC,
+};
+
+#endif
diff --git a/drivers/serial/serial_pl01x.h b/drivers/serial/serial_pl01x.h
deleted file mode 100644 (file)
index 288a4f1..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * (C) Copyright 2003, 2004
- * ARM Ltd.
- * Philippe Robin, <philippe.robin@arm.com>
- *
- * SPDX-License-Identifier:    GPL-2.0+
- */
-
-/*
- * ARM PrimeCell UART's (PL010 & PL011)
- * ------------------------------------
- *
- *  Definitions common to both PL010 & PL011
- *
- */
-
-#ifndef __ASSEMBLY__
-/*
- * We can use a combined structure for PL010 and PL011, because they overlap
- * only in common registers.
- */
-struct pl01x_regs {
-       u32     dr;             /* 0x00 Data register */
-       u32     ecr;            /* 0x04 Error clear register (Write) */
-       u32     pl010_lcrh;     /* 0x08 Line control register, high byte */
-       u32     pl010_lcrm;     /* 0x0C Line control register, middle byte */
-       u32     pl010_lcrl;     /* 0x10 Line control register, low byte */
-       u32     pl010_cr;       /* 0x14 Control register */
-       u32     fr;             /* 0x18 Flag register (Read only) */
-#ifdef CONFIG_PL011_SERIAL_RLCR
-       u32     pl011_rlcr;     /* 0x1c Receive line control register */
-#else
-       u32     reserved;
-#endif
-       u32     ilpr;           /* 0x20 IrDA low-power counter register */
-       u32     pl011_ibrd;     /* 0x24 Integer baud rate register */
-       u32     pl011_fbrd;     /* 0x28 Fractional baud rate register */
-       u32     pl011_lcrh;     /* 0x2C Line control register */
-       u32     pl011_cr;       /* 0x30 Control register */
-};
-#endif
-
-#define UART_PL01x_RSR_OE               0x08
-#define UART_PL01x_RSR_BE               0x04
-#define UART_PL01x_RSR_PE               0x02
-#define UART_PL01x_RSR_FE               0x01
-
-#define UART_PL01x_FR_TXFE              0x80
-#define UART_PL01x_FR_RXFF              0x40
-#define UART_PL01x_FR_TXFF              0x20
-#define UART_PL01x_FR_RXFE              0x10
-#define UART_PL01x_FR_BUSY              0x08
-#define UART_PL01x_FR_TMSK              (UART_PL01x_FR_TXFF + UART_PL01x_FR_BUSY)
-
-/*
- *  PL010 definitions
- *
- */
-#define UART_PL010_CR_LPE               (1 << 7)
-#define UART_PL010_CR_RTIE              (1 << 6)
-#define UART_PL010_CR_TIE               (1 << 5)
-#define UART_PL010_CR_RIE               (1 << 4)
-#define UART_PL010_CR_MSIE              (1 << 3)
-#define UART_PL010_CR_IIRLP             (1 << 2)
-#define UART_PL010_CR_SIREN             (1 << 1)
-#define UART_PL010_CR_UARTEN            (1 << 0)
-
-#define UART_PL010_LCRH_WLEN_8          (3 << 5)
-#define UART_PL010_LCRH_WLEN_7          (2 << 5)
-#define UART_PL010_LCRH_WLEN_6          (1 << 5)
-#define UART_PL010_LCRH_WLEN_5          (0 << 5)
-#define UART_PL010_LCRH_FEN             (1 << 4)
-#define UART_PL010_LCRH_STP2            (1 << 3)
-#define UART_PL010_LCRH_EPS             (1 << 2)
-#define UART_PL010_LCRH_PEN             (1 << 1)
-#define UART_PL010_LCRH_BRK             (1 << 0)
-
-
-#define UART_PL010_BAUD_460800            1
-#define UART_PL010_BAUD_230400            3
-#define UART_PL010_BAUD_115200            7
-#define UART_PL010_BAUD_57600             15
-#define UART_PL010_BAUD_38400             23
-#define UART_PL010_BAUD_19200             47
-#define UART_PL010_BAUD_14400             63
-#define UART_PL010_BAUD_9600              95
-#define UART_PL010_BAUD_4800              191
-#define UART_PL010_BAUD_2400              383
-#define UART_PL010_BAUD_1200              767
-/*
- *  PL011 definitions
- *
- */
-#define UART_PL011_LCRH_SPS             (1 << 7)
-#define UART_PL011_LCRH_WLEN_8          (3 << 5)
-#define UART_PL011_LCRH_WLEN_7          (2 << 5)
-#define UART_PL011_LCRH_WLEN_6          (1 << 5)
-#define UART_PL011_LCRH_WLEN_5          (0 << 5)
-#define UART_PL011_LCRH_FEN             (1 << 4)
-#define UART_PL011_LCRH_STP2            (1 << 3)
-#define UART_PL011_LCRH_EPS             (1 << 2)
-#define UART_PL011_LCRH_PEN             (1 << 1)
-#define UART_PL011_LCRH_BRK             (1 << 0)
-
-#define UART_PL011_CR_CTSEN             (1 << 15)
-#define UART_PL011_CR_RTSEN             (1 << 14)
-#define UART_PL011_CR_OUT2              (1 << 13)
-#define UART_PL011_CR_OUT1              (1 << 12)
-#define UART_PL011_CR_RTS               (1 << 11)
-#define UART_PL011_CR_DTR               (1 << 10)
-#define UART_PL011_CR_RXE               (1 << 9)
-#define UART_PL011_CR_TXE               (1 << 8)
-#define UART_PL011_CR_LPE               (1 << 7)
-#define UART_PL011_CR_IIRLP             (1 << 2)
-#define UART_PL011_CR_SIREN             (1 << 1)
-#define UART_PL011_CR_UARTEN            (1 << 0)
-
-#define UART_PL011_IMSC_OEIM            (1 << 10)
-#define UART_PL011_IMSC_BEIM            (1 << 9)
-#define UART_PL011_IMSC_PEIM            (1 << 8)
-#define UART_PL011_IMSC_FEIM            (1 << 7)
-#define UART_PL011_IMSC_RTIM            (1 << 6)
-#define UART_PL011_IMSC_TXIM            (1 << 5)
-#define UART_PL011_IMSC_RXIM            (1 << 4)
-#define UART_PL011_IMSC_DSRMIM          (1 << 3)
-#define UART_PL011_IMSC_DCDMIM          (1 << 2)
-#define UART_PL011_IMSC_CTSMIM          (1 << 1)
-#define UART_PL011_IMSC_RIMIM           (1 << 0)
diff --git a/drivers/serial/serial_pl01x_internal.h b/drivers/serial/serial_pl01x_internal.h
new file mode 100644 (file)
index 0000000..288a4f1
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * (C) Copyright 2003, 2004
+ * ARM Ltd.
+ * Philippe Robin, <philippe.robin@arm.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+/*
+ * ARM PrimeCell UART's (PL010 & PL011)
+ * ------------------------------------
+ *
+ *  Definitions common to both PL010 & PL011
+ *
+ */
+
+#ifndef __ASSEMBLY__
+/*
+ * We can use a combined structure for PL010 and PL011, because they overlap
+ * only in common registers.
+ */
+struct pl01x_regs {
+       u32     dr;             /* 0x00 Data register */
+       u32     ecr;            /* 0x04 Error clear register (Write) */
+       u32     pl010_lcrh;     /* 0x08 Line control register, high byte */
+       u32     pl010_lcrm;     /* 0x0C Line control register, middle byte */
+       u32     pl010_lcrl;     /* 0x10 Line control register, low byte */
+       u32     pl010_cr;       /* 0x14 Control register */
+       u32     fr;             /* 0x18 Flag register (Read only) */
+#ifdef CONFIG_PL011_SERIAL_RLCR
+       u32     pl011_rlcr;     /* 0x1c Receive line control register */
+#else
+       u32     reserved;
+#endif
+       u32     ilpr;           /* 0x20 IrDA low-power counter register */
+       u32     pl011_ibrd;     /* 0x24 Integer baud rate register */
+       u32     pl011_fbrd;     /* 0x28 Fractional baud rate register */
+       u32     pl011_lcrh;     /* 0x2C Line control register */
+       u32     pl011_cr;       /* 0x30 Control register */
+};
+#endif
+
+#define UART_PL01x_RSR_OE               0x08
+#define UART_PL01x_RSR_BE               0x04
+#define UART_PL01x_RSR_PE               0x02
+#define UART_PL01x_RSR_FE               0x01
+
+#define UART_PL01x_FR_TXFE              0x80
+#define UART_PL01x_FR_RXFF              0x40
+#define UART_PL01x_FR_TXFF              0x20
+#define UART_PL01x_FR_RXFE              0x10
+#define UART_PL01x_FR_BUSY              0x08
+#define UART_PL01x_FR_TMSK              (UART_PL01x_FR_TXFF + UART_PL01x_FR_BUSY)
+
+/*
+ *  PL010 definitions
+ *
+ */
+#define UART_PL010_CR_LPE               (1 << 7)
+#define UART_PL010_CR_RTIE              (1 << 6)
+#define UART_PL010_CR_TIE               (1 << 5)
+#define UART_PL010_CR_RIE               (1 << 4)
+#define UART_PL010_CR_MSIE              (1 << 3)
+#define UART_PL010_CR_IIRLP             (1 << 2)
+#define UART_PL010_CR_SIREN             (1 << 1)
+#define UART_PL010_CR_UARTEN            (1 << 0)
+
+#define UART_PL010_LCRH_WLEN_8          (3 << 5)
+#define UART_PL010_LCRH_WLEN_7          (2 << 5)
+#define UART_PL010_LCRH_WLEN_6          (1 << 5)
+#define UART_PL010_LCRH_WLEN_5          (0 << 5)
+#define UART_PL010_LCRH_FEN             (1 << 4)
+#define UART_PL010_LCRH_STP2            (1 << 3)
+#define UART_PL010_LCRH_EPS             (1 << 2)
+#define UART_PL010_LCRH_PEN             (1 << 1)
+#define UART_PL010_LCRH_BRK             (1 << 0)
+
+
+#define UART_PL010_BAUD_460800            1
+#define UART_PL010_BAUD_230400            3
+#define UART_PL010_BAUD_115200            7
+#define UART_PL010_BAUD_57600             15
+#define UART_PL010_BAUD_38400             23
+#define UART_PL010_BAUD_19200             47
+#define UART_PL010_BAUD_14400             63
+#define UART_PL010_BAUD_9600              95
+#define UART_PL010_BAUD_4800              191
+#define UART_PL010_BAUD_2400              383
+#define UART_PL010_BAUD_1200              767
+/*
+ *  PL011 definitions
+ *
+ */
+#define UART_PL011_LCRH_SPS             (1 << 7)
+#define UART_PL011_LCRH_WLEN_8          (3 << 5)
+#define UART_PL011_LCRH_WLEN_7          (2 << 5)
+#define UART_PL011_LCRH_WLEN_6          (1 << 5)
+#define UART_PL011_LCRH_WLEN_5          (0 << 5)
+#define UART_PL011_LCRH_FEN             (1 << 4)
+#define UART_PL011_LCRH_STP2            (1 << 3)
+#define UART_PL011_LCRH_EPS             (1 << 2)
+#define UART_PL011_LCRH_PEN             (1 << 1)
+#define UART_PL011_LCRH_BRK             (1 << 0)
+
+#define UART_PL011_CR_CTSEN             (1 << 15)
+#define UART_PL011_CR_RTSEN             (1 << 14)
+#define UART_PL011_CR_OUT2              (1 << 13)
+#define UART_PL011_CR_OUT1              (1 << 12)
+#define UART_PL011_CR_RTS               (1 << 11)
+#define UART_PL011_CR_DTR               (1 << 10)
+#define UART_PL011_CR_RXE               (1 << 9)
+#define UART_PL011_CR_TXE               (1 << 8)
+#define UART_PL011_CR_LPE               (1 << 7)
+#define UART_PL011_CR_IIRLP             (1 << 2)
+#define UART_PL011_CR_SIREN             (1 << 1)
+#define UART_PL011_CR_UARTEN            (1 << 0)
+
+#define UART_PL011_IMSC_OEIM            (1 << 10)
+#define UART_PL011_IMSC_BEIM            (1 << 9)
+#define UART_PL011_IMSC_PEIM            (1 << 8)
+#define UART_PL011_IMSC_FEIM            (1 << 7)
+#define UART_PL011_IMSC_RTIM            (1 << 6)
+#define UART_PL011_IMSC_TXIM            (1 << 5)
+#define UART_PL011_IMSC_RXIM            (1 << 4)
+#define UART_PL011_IMSC_DSRMIM          (1 << 3)
+#define UART_PL011_IMSC_DCDMIM          (1 << 2)
+#define UART_PL011_IMSC_CTSMIM          (1 << 1)
+#define UART_PL011_IMSC_RIMIM           (1 << 0)
index 98c62b4c147ef185d8a9cabb0290be854a38b892..8469afdaae9da8d18e046218a354eb789b87ddd5 100644 (file)
@@ -9,6 +9,8 @@
  */
 
 #include <common.h>
+#include <dm.h>
+#include <errno.h>
 #include <fdtdec.h>
 #include <linux/compiler.h>
 #include <asm/io.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
-#define RX_FIFO_COUNT_MASK     0xff
-#define RX_FIFO_FULL_MASK      (1 << 8)
-#define TX_FIFO_FULL_MASK      (1 << 24)
+#define RX_FIFO_COUNT_SHIFT    0
+#define RX_FIFO_COUNT_MASK     (0xff << RX_FIFO_COUNT_SHIFT)
+#define RX_FIFO_FULL           (1 << 8)
+#define TX_FIFO_COUNT_SHIFT    16
+#define TX_FIFO_COUNT_MASK     (0xff << TX_FIFO_COUNT_SHIFT)
+#define TX_FIFO_FULL           (1 << 24)
 
 /* Information about a serial port */
-struct fdt_serial {
-       u32 base_addr;  /* address of registers in physical memory */
+struct s5p_serial_platdata {
+       struct s5p_uart *reg;  /* address of registers in physical memory */
        u8 port_id;     /* uart port number */
-       u8 enabled;     /* 1 if enabled, 0 if disabled */
-} config __attribute__ ((section(".data")));
-
-static inline struct s5p_uart *s5p_get_base_uart(int dev_index)
-{
-#ifdef CONFIG_OF_CONTROL
-       return (struct s5p_uart *)(config.base_addr);
-#else
-       u32 offset = dev_index * sizeof(struct s5p_uart);
-       return (struct s5p_uart *)(samsung_get_base_uart() + offset);
-#endif
-}
+};
 
 /*
  * The coefficient, used to calculate the baudrate on S5P UARTs is
@@ -65,23 +59,13 @@ static const int udivslot[] = {
        0xffdf,
 };
 
-static void serial_setbrg_dev(const int dev_index)
+int s5p_serial_setbrg(struct udevice *dev, int baudrate)
 {
-       struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
-       u32 uclk = get_uart_clk(dev_index);
-       u32 baudrate = gd->baudrate;
+       struct s5p_serial_platdata *plat = dev->platdata;
+       struct s5p_uart *const uart = plat->reg;
+       u32 uclk = get_uart_clk(plat->port_id);
        u32 val;
 
-#if defined(CONFIG_SILENT_CONSOLE) && \
-               defined(CONFIG_OF_CONTROL) && \
-               !defined(CONFIG_SPL_BUILD)
-       if (fdtdec_get_config_int(gd->fdt_blob, "silent_console", 0))
-               gd->flags |= GD_FLG_SILENT;
-#endif
-
-       if (!config.enabled)
-               return;
-
        val = uclk / baudrate;
 
        writel(val / 16 - 1, &uart->ubrdiv);
@@ -90,15 +74,14 @@ static void serial_setbrg_dev(const int dev_index)
                writew(udivslot[val % 16], &uart->rest.slot);
        else
                writeb(val % 16, &uart->rest.value);
+
+       return 0;
 }
 
-/*
- * Initialise the serial port with the given baudrate. The settings
- * are always 8 data bits, no parity, 1 stop bit, no start bits.
- */
-static int serial_init_dev(const int dev_index)
+static int s5p_serial_probe(struct udevice *dev)
 {
-       struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
+       struct s5p_serial_platdata *plat = dev->platdata;
+       struct s5p_uart *const uart = plat->reg;
 
        /* enable FIFOs, auto clear Rx FIFO */
        writel(0x3, &uart->ufcon);
@@ -108,14 +91,11 @@ static int serial_init_dev(const int dev_index)
        /* No interrupts, no DMA, pure polling */
        writel(0x245, &uart->ucon);
 
-       serial_setbrg_dev(dev_index);
-
        return 0;
 }
 
-static int serial_err_check(const int dev_index, int op)
+static int serial_err_check(const struct s5p_uart *const uart, int op)
 {
-       struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
        unsigned int mask;
 
        /*
@@ -133,169 +113,78 @@ static int serial_err_check(const int dev_index, int op)
        return readl(&uart->uerstat) & mask;
 }
 
-/*
- * Read a single byte from the serial port. Returns 1 on success, 0
- * otherwise. When the function is succesfull, the character read is
- * written into its argument c.
- */
-static int serial_getc_dev(const int dev_index)
+static int s5p_serial_getc(struct udevice *dev)
 {
-       struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
-
-       if (!config.enabled)
-               return 0;
+       struct s5p_serial_platdata *plat = dev->platdata;
+       struct s5p_uart *const uart = plat->reg;
 
-       /* wait for character to arrive */
-       while (!(readl(&uart->ufstat) & (RX_FIFO_COUNT_MASK |
-                                        RX_FIFO_FULL_MASK))) {
-               if (serial_err_check(dev_index, 0))
-                       return 0;
-       }
+       if (!(readl(&uart->ufstat) & RX_FIFO_COUNT_MASK))
+               return -EAGAIN;
 
+       serial_err_check(uart, 0);
        return (int)(readb(&uart->urxh) & 0xff);
 }
 
-/*
- * Output a single byte to the serial port.
- */
-static void serial_putc_dev(const char c, const int dev_index)
+static int s5p_serial_putc(struct udevice *dev, const char ch)
 {
-       struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
-
-       if (!config.enabled)
-               return;
-
-       /* wait for room in the tx FIFO */
-       while ((readl(&uart->ufstat) & TX_FIFO_FULL_MASK)) {
-               if (serial_err_check(dev_index, 1))
-                       return;
-       }
+       struct s5p_serial_platdata *plat = dev->platdata;
+       struct s5p_uart *const uart = plat->reg;
 
-       writeb(c, &uart->utxh);
+       if (readl(&uart->ufstat) & TX_FIFO_FULL)
+               return -EAGAIN;
 
-       /* If \n, also do \r */
-       if (c == '\n')
-               serial_putc('\r');
-}
-
-/*
- * Test whether a character is in the RX buffer
- */
-static int serial_tstc_dev(const int dev_index)
-{
-       struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
+       writeb(ch, &uart->utxh);
+       serial_err_check(uart, 1);
 
-       if (!config.enabled)
-               return 0;
-
-       return (int)(readl(&uart->utrstat) & 0x1);
+       return 0;
 }
 
-static void serial_puts_dev(const char *s, const int dev_index)
+static int s5p_serial_pending(struct udevice *dev, bool input)
 {
-       while (*s)
-               serial_putc_dev(*s++, dev_index);
-}
+       struct s5p_serial_platdata *plat = dev->platdata;
+       struct s5p_uart *const uart = plat->reg;
+       uint32_t ufstat = readl(&uart->ufstat);
 
-/* Multi serial device functions */
-#define DECLARE_S5P_SERIAL_FUNCTIONS(port) \
-static int s5p_serial##port##_init(void) { return serial_init_dev(port); } \
-static void s5p_serial##port##_setbrg(void) { serial_setbrg_dev(port); } \
-static int s5p_serial##port##_getc(void) { return serial_getc_dev(port); } \
-static int s5p_serial##port##_tstc(void) { return serial_tstc_dev(port); } \
-static void s5p_serial##port##_putc(const char c) { serial_putc_dev(c, port); } \
-static void s5p_serial##port##_puts(const char *s) { serial_puts_dev(s, port); }
-
-#define INIT_S5P_SERIAL_STRUCTURE(port, __name) {      \
-       .name   = __name,                               \
-       .start  = s5p_serial##port##_init,              \
-       .stop   = NULL,                                 \
-       .setbrg = s5p_serial##port##_setbrg,            \
-       .getc   = s5p_serial##port##_getc,              \
-       .tstc   = s5p_serial##port##_tstc,              \
-       .putc   = s5p_serial##port##_putc,              \
-       .puts   = s5p_serial##port##_puts,              \
+       if (input)
+               return (ufstat & RX_FIFO_COUNT_MASK) >> RX_FIFO_COUNT_SHIFT;
+       else
+               return (ufstat & TX_FIFO_COUNT_MASK) >> TX_FIFO_COUNT_SHIFT;
 }
 
-DECLARE_S5P_SERIAL_FUNCTIONS(0);
-struct serial_device s5p_serial0_device =
-       INIT_S5P_SERIAL_STRUCTURE(0, "s5pser0");
-DECLARE_S5P_SERIAL_FUNCTIONS(1);
-struct serial_device s5p_serial1_device =
-       INIT_S5P_SERIAL_STRUCTURE(1, "s5pser1");
-DECLARE_S5P_SERIAL_FUNCTIONS(2);
-struct serial_device s5p_serial2_device =
-       INIT_S5P_SERIAL_STRUCTURE(2, "s5pser2");
-DECLARE_S5P_SERIAL_FUNCTIONS(3);
-struct serial_device s5p_serial3_device =
-       INIT_S5P_SERIAL_STRUCTURE(3, "s5pser3");
-
-#ifdef CONFIG_OF_CONTROL
-int fdtdec_decode_console(int *index, struct fdt_serial *uart)
+static int s5p_serial_ofdata_to_platdata(struct udevice *dev)
 {
-       const void *blob = gd->fdt_blob;
-       int node;
+       struct s5p_serial_platdata *plat = dev->platdata;
+       fdt_addr_t addr;
 
-       node = fdt_path_offset(blob, "console");
-       if (node < 0)
-               return node;
+       addr = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg");
+       if (addr == FDT_ADDR_T_NONE)
+               return -EINVAL;
 
-       uart->base_addr = fdtdec_get_addr(blob, node, "reg");
-       if (uart->base_addr == FDT_ADDR_T_NONE)
-               return -FDT_ERR_NOTFOUND;
-
-       uart->port_id = fdtdec_get_int(blob, node, "id", -1);
-       uart->enabled = fdtdec_get_is_enabled(blob, node);
+       plat->reg = (struct s5p_uart *)addr;
+       plat->port_id = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "id", -1);
 
        return 0;
 }
-#endif
 
-__weak struct serial_device *default_serial_console(void)
-{
-#ifdef CONFIG_OF_CONTROL
-       int index = 0;
-
-       if ((!config.base_addr) && (fdtdec_decode_console(&index, &config))) {
-               debug("Cannot decode default console node\n");
-               return NULL;
-       }
-
-       switch (config.port_id) {
-       case 0:
-               return &s5p_serial0_device;
-       case 1:
-               return &s5p_serial1_device;
-       case 2:
-               return &s5p_serial2_device;
-       case 3:
-               return &s5p_serial3_device;
-       default:
-               debug("Unknown config.port_id: %d", config.port_id);
-               break;
-       }
-
-       return NULL;
-#else
-       config.enabled = 1;
-#if defined(CONFIG_SERIAL0)
-       return &s5p_serial0_device;
-#elif defined(CONFIG_SERIAL1)
-       return &s5p_serial1_device;
-#elif defined(CONFIG_SERIAL2)
-       return &s5p_serial2_device;
-#elif defined(CONFIG_SERIAL3)
-       return &s5p_serial3_device;
-#else
-#error "CONFIG_SERIAL? missing."
-#endif
-#endif
-}
+static const struct dm_serial_ops s5p_serial_ops = {
+       .putc = s5p_serial_putc,
+       .pending = s5p_serial_pending,
+       .getc = s5p_serial_getc,
+       .setbrg = s5p_serial_setbrg,
+};
 
-void s5p_serial_initialize(void)
-{
-       serial_register(&s5p_serial0_device);
-       serial_register(&s5p_serial1_device);
-       serial_register(&s5p_serial2_device);
-       serial_register(&s5p_serial3_device);
-}
+static const struct udevice_id s5p_serial_ids[] = {
+       { .compatible = "samsung,exynos4210-uart" },
+       { }
+};
+
+U_BOOT_DRIVER(serial_s5p) = {
+       .name   = "serial_s5p",
+       .id     = UCLASS_SERIAL,
+       .of_match = s5p_serial_ids,
+       .ofdata_to_platdata = s5p_serial_ofdata_to_platdata,
+       .platdata_auto_alloc_size = sizeof(struct s5p_serial_platdata),
+       .probe = s5p_serial_probe,
+       .ops    = &s5p_serial_ops,
+       .flags = DM_FLAG_PRE_RELOC,
+};
index f02c35a52c0cd5100804342ca0e05a915151fd7d..eabbf27d4d0449cf0ed93d3983479cb629fd1108 100644 (file)
@@ -6,7 +6,14 @@
 #
 
 # There are many options which enable SPI, so make this library available
+ifdef CONFIG_DM_SPI
+obj-y += spi-uclass.o
+obj-$(CONFIG_SANDBOX) += spi-emul-uclass.o
+obj-$(CONFIG_SOFT_SPI) += soft_spi.o
+else
 obj-y += spi.o
+obj-$(CONFIG_SOFT_SPI) += soft_spi_legacy.o
+endif
 
 obj-$(CONFIG_EP93XX_SPI) += ep93xx_spi.o
 obj-$(CONFIG_ALTERA_SPI) += altera_spi.o
@@ -30,11 +37,9 @@ obj-$(CONFIG_MXS_SPI) += mxs_spi.o
 obj-$(CONFIG_OC_TINY_SPI) += oc_tiny_spi.o
 obj-$(CONFIG_OMAP3_SPI) += omap3_spi.o
 obj-$(CONFIG_SANDBOX_SPI) += sandbox_spi.o
-obj-$(CONFIG_SOFT_SPI) += soft_spi.o
 obj-$(CONFIG_SH_SPI) += sh_spi.o
 obj-$(CONFIG_SH_QSPI) += sh_qspi.o
 obj-$(CONFIG_FSL_ESPI) += fsl_espi.o
-obj-$(CONFIG_FDT_SPI) += fdt_spi.o
 obj-$(CONFIG_TEGRA20_SFLASH) += tegra20_sflash.o
 obj-$(CONFIG_TEGRA20_SLINK) += tegra20_slink.o
 obj-$(CONFIG_TEGRA114_SPI) += tegra114_spi.o
index 2969184ee877360da2a170b9f2ddb12722ffb08a..f078973531c1d960e5635a485e50c42170b45d80 100644 (file)
@@ -6,6 +6,8 @@
  */
 
 #include <common.h>
+#include <dm.h>
+#include <errno.h>
 #include <malloc.h>
 #include <spi.h>
 #include <fdtdec.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
-/* Information about each SPI controller */
-struct spi_bus {
+struct exynos_spi_platdata {
        enum periph_id periph_id;
        s32 frequency;          /* Default clock frequency, -1 for none */
        struct exynos_spi *regs;
-       int inited;             /* 1 if this bus is ready for use */
-       int node;
        uint deactivate_delay_us;       /* Delay to wait after deactivate */
 };
 
-/* A list of spi buses that we know about */
-static struct spi_bus spi_bus[EXYNOS5_SPI_NUM_CONTROLLERS];
-static unsigned int bus_count;
-
-struct exynos_spi_slave {
-       struct spi_slave slave;
+struct exynos_spi_priv {
        struct exynos_spi *regs;
        unsigned int freq;              /* Default frequency */
        unsigned int mode;
        enum periph_id periph_id;       /* Peripheral ID for this device */
        unsigned int fifo_size;
        int skip_preamble;
-       struct spi_bus *bus;            /* Pointer to our SPI bus info */
        ulong last_transaction_us;      /* Time of last transaction end */
 };
 
-static struct spi_bus *spi_get_bus(unsigned dev_index)
-{
-       if (dev_index < bus_count)
-               return &spi_bus[dev_index];
-       debug("%s: invalid bus %d", __func__, dev_index);
-
-       return NULL;
-}
-
-static inline struct exynos_spi_slave *to_exynos_spi(struct spi_slave *slave)
-{
-       return container_of(slave, struct exynos_spi_slave, slave);
-}
-
-/**
- * Setup the driver private data
- *
- * @param bus          ID of the bus that the slave is attached to
- * @param cs           ID of the chip select connected to the slave
- * @param max_hz       Required spi frequency
- * @param mode         Required spi mode (clk polarity, clk phase and
- *                     master or slave)
- * @return new device or NULL
- */
-struct spi_slave *spi_setup_slave(unsigned int busnum, unsigned int cs,
-                       unsigned int max_hz, unsigned int mode)
-{
-       struct exynos_spi_slave *spi_slave;
-       struct spi_bus *bus;
-
-       if (!spi_cs_is_valid(busnum, cs)) {
-               debug("%s: Invalid bus/chip select %d, %d\n", __func__,
-                     busnum, cs);
-               return NULL;
-       }
-
-       spi_slave = spi_alloc_slave(struct exynos_spi_slave, busnum, cs);
-       if (!spi_slave) {
-               debug("%s: Could not allocate spi_slave\n", __func__);
-               return NULL;
-       }
-
-       bus = &spi_bus[busnum];
-       spi_slave->bus = bus;
-       spi_slave->regs = bus->regs;
-       spi_slave->mode = mode;
-       spi_slave->periph_id = bus->periph_id;
-       if (bus->periph_id == PERIPH_ID_SPI1 ||
-           bus->periph_id == PERIPH_ID_SPI2)
-               spi_slave->fifo_size = 64;
-       else
-               spi_slave->fifo_size = 256;
-
-       spi_slave->skip_preamble = 0;
-       spi_slave->last_transaction_us = timer_get_us();
-
-       spi_slave->freq = bus->frequency;
-       if (max_hz)
-               spi_slave->freq = min(max_hz, spi_slave->freq);
-
-       return &spi_slave->slave;
-}
-
-/**
- * Free spi controller
- *
- * @param slave        Pointer to spi_slave to which controller has to
- *             communicate with
- */
-void spi_free_slave(struct spi_slave *slave)
-{
-       struct exynos_spi_slave *spi_slave = to_exynos_spi(slave);
-
-       free(spi_slave);
-}
-
 /**
  * Flush spi tx, rx fifos and reset the SPI controller
  *
- * @param slave        Pointer to spi_slave to which controller has to
- *             communicate with
+ * @param regs Pointer to SPI registers
  */
-static void spi_flush_fifo(struct spi_slave *slave)
+static void spi_flush_fifo(struct exynos_spi *regs)
 {
-       struct exynos_spi_slave *spi_slave = to_exynos_spi(slave);
-       struct exynos_spi *regs = spi_slave->regs;
-
        clrsetbits_le32(&regs->ch_cfg, SPI_CH_HS_EN, SPI_CH_RST);
        clrbits_le32(&regs->ch_cfg, SPI_CH_RST);
        setbits_le32(&regs->ch_cfg, SPI_TX_CH_ON | SPI_RX_CH_ON);
 }
 
-/**
- * Initialize the spi base registers, set the required clock frequency and
- * initialize the gpios
- *
- * @param slave        Pointer to spi_slave to which controller has to
- *             communicate with
- * @return zero on success else a negative value
- */
-int spi_claim_bus(struct spi_slave *slave)
-{
-       struct exynos_spi_slave *spi_slave = to_exynos_spi(slave);
-       struct exynos_spi *regs = spi_slave->regs;
-       u32 reg = 0;
-       int ret;
-
-       ret = set_spi_clk(spi_slave->periph_id,
-                                       spi_slave->freq);
-       if (ret < 0) {
-               debug("%s: Failed to setup spi clock\n", __func__);
-               return ret;
-       }
-
-       exynos_pinmux_config(spi_slave->periph_id, PINMUX_FLAG_NONE);
-
-       spi_flush_fifo(slave);
-
-       reg = readl(&regs->ch_cfg);
-       reg &= ~(SPI_CH_CPHA_B | SPI_CH_CPOL_L);
-
-       if (spi_slave->mode & SPI_CPHA)
-               reg |= SPI_CH_CPHA_B;
-
-       if (spi_slave->mode & SPI_CPOL)
-               reg |= SPI_CH_CPOL_L;
-
-       writel(reg, &regs->ch_cfg);
-       writel(SPI_FB_DELAY_180, &regs->fb_clk);
-
-       return 0;
-}
-
-/**
- * Reset the spi H/W and flush the tx and rx fifos
- *
- * @param slave        Pointer to spi_slave to which controller has to
- *             communicate with
- */
-void spi_release_bus(struct spi_slave *slave)
-{
-       spi_flush_fifo(slave);
-}
-
 static void spi_get_fifo_levels(struct exynos_spi *regs,
        int *rx_lvl, int *tx_lvl)
 {
@@ -208,6 +69,8 @@ static void spi_get_fifo_levels(struct exynos_spi *regs,
  */
 static void spi_request_bytes(struct exynos_spi *regs, int count, int step)
 {
+       debug("%s: regs=%p, count=%d, step=%d\n", __func__, regs, count, step);
+
        /* For word address we need to swap bytes */
        if (step == 4) {
                setbits_le32(&regs->mode_cfg,
@@ -230,10 +93,10 @@ static void spi_request_bytes(struct exynos_spi *regs, int count, int step)
        writel(count | SPI_PACKET_CNT_EN, &regs->pkt_cnt);
 }
 
-static int spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,
+static int spi_rx_tx(struct exynos_spi_priv *priv, int todo,
                        void **dinp, void const **doutp, unsigned long flags)
 {
-       struct exynos_spi *regs = spi_slave->regs;
+       struct exynos_spi *regs = priv->regs;
        uchar *rxp = *dinp;
        const uchar *txp = *doutp;
        int rx_lvl, tx_lvl;
@@ -245,8 +108,8 @@ static int spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,
 
        out_bytes = in_bytes = todo;
 
-       stopping = spi_slave->skip_preamble && (flags & SPI_XFER_END) &&
-                                       !(spi_slave->mode & SPI_SLAVE);
+       stopping = priv->skip_preamble && (flags & SPI_XFER_END) &&
+                                       !(priv->mode & SPI_SLAVE);
 
        /*
         * Try to transfer words if we can. This helps read performance at
@@ -254,7 +117,7 @@ static int spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,
         */
        step = 1;
        if (!((todo | (uintptr_t)rxp | (uintptr_t)txp) & 3) &&
-           !spi_slave->skip_preamble)
+           !priv->skip_preamble)
                step = 4;
 
        /*
@@ -279,7 +142,7 @@ static int spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,
                 * Don't completely fill the txfifo, since we don't want our
                 * rxfifo to overflow, and it may already contain data.
                 */
-               while (tx_lvl < spi_slave->fifo_size/2 && out_bytes) {
+               while (tx_lvl < priv->fifo_size/2 && out_bytes) {
                        if (!txp)
                                temp = -1;
                        else if (step == 4)
@@ -295,9 +158,9 @@ static int spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,
                if (rx_lvl >= step) {
                        while (rx_lvl >= step) {
                                temp = readl(&regs->rx_data);
-                               if (spi_slave->skip_preamble) {
+                               if (priv->skip_preamble) {
                                        if (temp == SPI_PREAMBLE_END_BYTE) {
-                                               spi_slave->skip_preamble = 0;
+                                               priv->skip_preamble = 0;
                                                stopping = 0;
                                        }
                                } else {
@@ -326,7 +189,7 @@ static int spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,
                        txp = NULL;
                        spi_request_bytes(regs, toread, step);
                }
-               if (spi_slave->skip_preamble && get_timer(start) > 100) {
+               if (priv->skip_preamble && get_timer(start) > 100) {
                        printf("SPI timeout: in_bytes=%d, out_bytes=%d, ",
                               in_bytes, out_bytes);
                        return -1;
@@ -339,95 +202,30 @@ static int spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,
        return 0;
 }
 
-/**
- * Transfer and receive data
- *
- * @param slave                Pointer to spi_slave to which controller has to
- *                     communicate with
- * @param bitlen       No of bits to tranfer or receive
- * @param dout         Pointer to transfer buffer
- * @param din          Pointer to receive buffer
- * @param flags                Flags for transfer begin and end
- * @return zero on success else a negative value
- */
-int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
-            void *din, unsigned long flags)
-{
-       struct exynos_spi_slave *spi_slave = to_exynos_spi(slave);
-       int upto, todo;
-       int bytelen;
-       int ret = 0;
-
-       /* spi core configured to do 8 bit transfers */
-       if (bitlen % 8) {
-               debug("Non byte aligned SPI transfer.\n");
-               return -1;
-       }
-
-       /* Start the transaction, if necessary. */
-       if ((flags & SPI_XFER_BEGIN))
-               spi_cs_activate(slave);
-
-       /*
-        * Exynos SPI limits each transfer to 65535 transfers. To keep
-        * things simple, allow a maximum of 65532 bytes. We could allow
-        * more in word mode, but the performance difference is small.
-        */
-       bytelen =  bitlen / 8;
-       for (upto = 0; !ret && upto < bytelen; upto += todo) {
-               todo = min(bytelen - upto, (1 << 16) - 4);
-               ret = spi_rx_tx(spi_slave, todo, &din, &dout, flags);
-               if (ret)
-                       break;
-       }
-
-       /* Stop the transaction, if necessary. */
-       if ((flags & SPI_XFER_END) && !(spi_slave->mode & SPI_SLAVE)) {
-               spi_cs_deactivate(slave);
-               if (spi_slave->skip_preamble) {
-                       assert(!spi_slave->skip_preamble);
-                       debug("Failed to complete premable transaction\n");
-                       ret = -1;
-               }
-       }
-
-       return ret;
-}
-
-/**
- * Validates the bus and chip select numbers
- *
- * @param bus  ID of the bus that the slave is attached to
- * @param cs   ID of the chip select connected to the slave
- * @return one on success else zero
- */
-int spi_cs_is_valid(unsigned int bus, unsigned int cs)
-{
-       return spi_get_bus(bus) && cs == 0;
-}
-
 /**
  * Activate the CS by driving it LOW
  *
  * @param slave        Pointer to spi_slave to which controller has to
  *             communicate with
  */
-void spi_cs_activate(struct spi_slave *slave)
+static void spi_cs_activate(struct udevice *dev)
 {
-       struct exynos_spi_slave *spi_slave = to_exynos_spi(slave);
+       struct udevice *bus = dev->parent;
+       struct exynos_spi_platdata *pdata = dev_get_platdata(bus);
+       struct exynos_spi_priv *priv = dev_get_priv(bus);
 
        /* If it's too soon to do another transaction, wait */
-       if (spi_slave->bus->deactivate_delay_us &&
-           spi_slave->last_transaction_us) {
+       if (pdata->deactivate_delay_us &&
+           priv->last_transaction_us) {
                ulong delay_us;         /* The delay completed so far */
-               delay_us = timer_get_us() - spi_slave->last_transaction_us;
-               if (delay_us < spi_slave->bus->deactivate_delay_us)
-                       udelay(spi_slave->bus->deactivate_delay_us - delay_us);
+               delay_us = timer_get_us() - priv->last_transaction_us;
+               if (delay_us < pdata->deactivate_delay_us)
+                       udelay(pdata->deactivate_delay_us - delay_us);
        }
 
-       clrbits_le32(&spi_slave->regs->cs_reg, SPI_SLAVE_SIG_INACT);
-       debug("Activate CS, bus %d\n", spi_slave->slave.bus);
-       spi_slave->skip_preamble = spi_slave->mode & SPI_PREAMBLE;
+       clrbits_le32(&priv->regs->cs_reg, SPI_SLAVE_SIG_INACT);
+       debug("Activate CS, bus '%s'\n", bus->name);
+       priv->skip_preamble = priv->mode & SPI_PREAMBLE;
 }
 
 /**
@@ -436,148 +234,197 @@ void spi_cs_activate(struct spi_slave *slave)
  * @param slave        Pointer to spi_slave to which controller has to
  *             communicate with
  */
-void spi_cs_deactivate(struct spi_slave *slave)
+static void spi_cs_deactivate(struct udevice *dev)
 {
-       struct exynos_spi_slave *spi_slave = to_exynos_spi(slave);
+       struct udevice *bus = dev->parent;
+       struct exynos_spi_platdata *pdata = dev_get_platdata(bus);
+       struct exynos_spi_priv *priv = dev_get_priv(bus);
 
-       setbits_le32(&spi_slave->regs->cs_reg, SPI_SLAVE_SIG_INACT);
+       setbits_le32(&priv->regs->cs_reg, SPI_SLAVE_SIG_INACT);
 
        /* Remember time of this transaction so we can honour the bus delay */
-       if (spi_slave->bus->deactivate_delay_us)
-               spi_slave->last_transaction_us = timer_get_us();
+       if (pdata->deactivate_delay_us)
+               priv->last_transaction_us = timer_get_us();
 
-       debug("Deactivate CS, bus %d\n", spi_slave->slave.bus);
+       debug("Deactivate CS, bus '%s'\n", bus->name);
 }
 
-static inline struct exynos_spi *get_spi_base(int dev_index)
+static int exynos_spi_ofdata_to_platdata(struct udevice *bus)
 {
-       if (dev_index < 3)
-               return (struct exynos_spi *)samsung_get_base_spi() + dev_index;
-       else
-               return (struct exynos_spi *)samsung_get_base_spi_isp() +
-                                       (dev_index - 3);
-}
+       struct exynos_spi_platdata *plat = bus->platdata;
+       const void *blob = gd->fdt_blob;
+       int node = bus->of_offset;
 
-/*
- * Read the SPI config from the device tree node.
- *
- * @param blob  FDT blob to read from
- * @param node  Node offset to read from
- * @param bus   SPI bus structure to fill with information
- * @return 0 if ok, or -FDT_ERR_NOTFOUND if something was missing
- */
-#ifdef CONFIG_OF_CONTROL
-static int spi_get_config(const void *blob, int node, struct spi_bus *bus)
-{
-       bus->node = node;
-       bus->regs = (struct exynos_spi *)fdtdec_get_addr(blob, node, "reg");
-       bus->periph_id = pinmux_decode_periph_id(blob, node);
+       plat->regs = (struct exynos_spi *)fdtdec_get_addr(blob, node, "reg");
+       plat->periph_id = pinmux_decode_periph_id(blob, node);
 
-       if (bus->periph_id == PERIPH_ID_NONE) {
+       if (plat->periph_id == PERIPH_ID_NONE) {
                debug("%s: Invalid peripheral ID %d\n", __func__,
-                       bus->periph_id);
+                       plat->periph_id);
                return -FDT_ERR_NOTFOUND;
        }
 
        /* Use 500KHz as a suitable default */
-       bus->frequency = fdtdec_get_int(blob, node, "spi-max-frequency",
+       plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency",
                                        500000);
-       bus->deactivate_delay_us = fdtdec_get_int(blob, node,
+       plat->deactivate_delay_us = fdtdec_get_int(blob, node,
                                        "spi-deactivate-delay", 0);
+       debug("%s: regs=%p, periph_id=%d, max-frequency=%d, deactivate_delay=%d\n",
+             __func__, plat->regs, plat->periph_id, plat->frequency,
+             plat->deactivate_delay_us);
 
        return 0;
 }
 
-/*
- * Process a list of nodes, adding them to our list of SPI ports.
- *
- * @param blob          fdt blob
- * @param node_list     list of nodes to process (any <=0 are ignored)
- * @param count         number of nodes to process
- * @param is_dvc        1 if these are DVC ports, 0 if standard I2C
- * @return 0 if ok, -1 on error
- */
-static int process_nodes(const void *blob, int node_list[], int count)
+static int exynos_spi_probe(struct udevice *bus)
 {
-       int i;
+       struct exynos_spi_platdata *plat = dev_get_platdata(bus);
+       struct exynos_spi_priv *priv = dev_get_priv(bus);
 
-       /* build the i2c_controllers[] for each controller */
-       for (i = 0; i < count; i++) {
-               int node = node_list[i];
-               struct spi_bus *bus;
+       priv->regs = plat->regs;
+       if (plat->periph_id == PERIPH_ID_SPI1 ||
+           plat->periph_id == PERIPH_ID_SPI2)
+               priv->fifo_size = 64;
+       else
+               priv->fifo_size = 256;
 
-               if (node <= 0)
-                       continue;
+       priv->skip_preamble = 0;
+       priv->last_transaction_us = timer_get_us();
+       priv->freq = plat->frequency;
+       priv->periph_id = plat->periph_id;
 
-               bus = &spi_bus[i];
-               if (spi_get_config(blob, node, bus)) {
-                       printf("exynos spi_init: failed to decode bus %d\n",
-                               i);
-                       return -1;
-               }
+       return 0;
+}
 
-               debug("spi: controller bus %d at %p, periph_id %d\n",
-                     i, bus->regs, bus->periph_id);
-               bus->inited = 1;
-               bus_count++;
-       }
+static int exynos_spi_claim_bus(struct udevice *bus)
+{
+       struct exynos_spi_priv *priv = dev_get_priv(bus);
+
+       exynos_pinmux_config(priv->periph_id, PINMUX_FLAG_NONE);
+       spi_flush_fifo(priv->regs);
+
+       writel(SPI_FB_DELAY_180, &priv->regs->fb_clk);
 
        return 0;
 }
-#endif
 
-/**
- * Set up a new SPI slave for an fdt node
- *
- * @param blob         Device tree blob
- * @param node         SPI peripheral node to use
- * @return 0 if ok, -1 on error
- */
-struct spi_slave *spi_setup_slave_fdt(const void *blob, int slave_node,
-                                     int spi_node)
+static int exynos_spi_release_bus(struct udevice *bus)
 {
-       struct spi_bus *bus;
-       unsigned int i;
+       struct exynos_spi_priv *priv = dev_get_priv(bus);
+
+       spi_flush_fifo(priv->regs);
+
+       return 0;
+}
+
+static int exynos_spi_xfer(struct udevice *dev, unsigned int bitlen,
+                          const void *dout, void *din, unsigned long flags)
+{
+       struct udevice *bus = dev->parent;
+       struct exynos_spi_priv *priv = dev_get_priv(bus);
+       int upto, todo;
+       int bytelen;
+       int ret = 0;
+
+       /* spi core configured to do 8 bit transfers */
+       if (bitlen % 8) {
+               debug("Non byte aligned SPI transfer.\n");
+               return -1;
+       }
+
+       /* Start the transaction, if necessary. */
+       if ((flags & SPI_XFER_BEGIN))
+               spi_cs_activate(dev);
+
+       /*
+        * Exynos SPI limits each transfer to 65535 transfers. To keep
+        * things simple, allow a maximum of 65532 bytes. We could allow
+        * more in word mode, but the performance difference is small.
+        */
+       bytelen = bitlen / 8;
+       for (upto = 0; !ret && upto < bytelen; upto += todo) {
+               todo = min(bytelen - upto, (1 << 16) - 4);
+               ret = spi_rx_tx(priv, todo, &din, &dout, flags);
+               if (ret)
+                       break;
+       }
 
-       for (i = 0, bus = spi_bus; i < bus_count; i++, bus++) {
-               if (bus->node == spi_node)
-                       return spi_base_setup_slave_fdt(blob, i, slave_node);
+       /* Stop the transaction, if necessary. */
+       if ((flags & SPI_XFER_END) && !(priv->mode & SPI_SLAVE)) {
+               spi_cs_deactivate(dev);
+               if (priv->skip_preamble) {
+                       assert(!priv->skip_preamble);
+                       debug("Failed to complete premable transaction\n");
+                       ret = -1;
+               }
        }
 
-       debug("%s: Failed to find bus node %d\n", __func__, spi_node);
-       return NULL;
+       return ret;
 }
 
-/* Sadly there is no error return from this function */
-void spi_init(void)
+static int exynos_spi_set_speed(struct udevice *bus, uint speed)
 {
-       int count;
+       struct exynos_spi_platdata *plat = bus->platdata;
+       struct exynos_spi_priv *priv = dev_get_priv(bus);
+       int ret;
 
-#ifdef CONFIG_OF_CONTROL
-       int node_list[EXYNOS5_SPI_NUM_CONTROLLERS];
-       const void *blob = gd->fdt_blob;
+       if (speed > plat->frequency)
+               speed = plat->frequency;
+       ret = set_spi_clk(priv->periph_id, speed);
+       if (ret)
+               return ret;
+       priv->freq = speed;
+       debug("%s: regs=%p, speed=%d\n", __func__, priv->regs, priv->freq);
+
+       return 0;
+}
 
-       count = fdtdec_find_aliases_for_id(blob, "spi",
-                       COMPAT_SAMSUNG_EXYNOS_SPI, node_list,
-                       EXYNOS5_SPI_NUM_CONTROLLERS);
-       if (process_nodes(blob, node_list, count))
-               return;
+static int exynos_spi_set_mode(struct udevice *bus, uint mode)
+{
+       struct exynos_spi_priv *priv = dev_get_priv(bus);
+       uint32_t reg;
 
-#else
-       struct spi_bus *bus;
+       reg = readl(&priv->regs->ch_cfg);
+       reg &= ~(SPI_CH_CPHA_B | SPI_CH_CPOL_L);
 
-       for (count = 0; count < EXYNOS5_SPI_NUM_CONTROLLERS; count++) {
-               bus = &spi_bus[count];
-               bus->regs = get_spi_base(count);
-               bus->periph_id = PERIPH_ID_SPI0 + count;
+       if (mode & SPI_CPHA)
+               reg |= SPI_CH_CPHA_B;
 
-               /* Although Exynos5 supports upto 50Mhz speed,
-                * we are setting it to 10Mhz for safe side
-                */
-               bus->frequency = 10000000;
-               bus->inited = 1;
-               bus->node = 0;
-               bus_count = EXYNOS5_SPI_NUM_CONTROLLERS;
-       }
-#endif
+       if (mode & SPI_CPOL)
+               reg |= SPI_CH_CPOL_L;
+
+       writel(reg, &priv->regs->ch_cfg);
+       priv->mode = mode;
+       debug("%s: regs=%p, mode=%d\n", __func__, priv->regs, priv->mode);
+
+       return 0;
 }
+
+static const struct dm_spi_ops exynos_spi_ops = {
+       .claim_bus      = exynos_spi_claim_bus,
+       .release_bus    = exynos_spi_release_bus,
+       .xfer           = exynos_spi_xfer,
+       .set_speed      = exynos_spi_set_speed,
+       .set_mode       = exynos_spi_set_mode,
+       /*
+        * cs_info is not needed, since we require all chip selects to be
+        * in the device tree explicitly
+        */
+};
+
+static const struct udevice_id exynos_spi_ids[] = {
+       { .compatible = "samsung,exynos-spi" },
+       { }
+};
+
+U_BOOT_DRIVER(exynos_spi) = {
+       .name   = "exynos_spi",
+       .id     = UCLASS_SPI,
+       .of_match = exynos_spi_ids,
+       .ops    = &exynos_spi_ops,
+       .ofdata_to_platdata = exynos_spi_ofdata_to_platdata,
+       .platdata_auto_alloc_size = sizeof(struct exynos_spi_platdata),
+       .priv_auto_alloc_size = sizeof(struct exynos_spi_priv),
+       .per_child_auto_alloc_size      = sizeof(struct spi_slave),
+       .probe  = exynos_spi_probe,
+};
diff --git a/drivers/spi/fdt_spi.c b/drivers/spi/fdt_spi.c
deleted file mode 100644 (file)
index 58f139a..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Common fdt based SPI driver front end
- *
- * Copyright (c) 2013 NVIDIA Corporation
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
-
-#include <common.h>
-#include <malloc.h>
-#include <asm/io.h>
-#include <asm/gpio.h>
-#include <asm/arch/clock.h>
-#include <asm/arch-tegra/clk_rst.h>
-#include <asm/arch-tegra20/tegra20_sflash.h>
-#include <asm/arch-tegra20/tegra20_slink.h>
-#include <asm/arch-tegra114/tegra114_spi.h>
-#include <spi.h>
-#include <fdtdec.h>
-
-DECLARE_GLOBAL_DATA_PTR;
-
-struct fdt_spi_driver {
-       int compat;
-       int max_ctrls;
-       int (*init)(int *node_list, int count);
-       int (*claim_bus)(struct spi_slave *slave);
-       int (*release_bus)(struct spi_slave *slave);
-       int (*cs_is_valid)(unsigned int bus, unsigned int cs);
-       struct spi_slave *(*setup_slave)(unsigned int bus, unsigned int cs,
-                                       unsigned int max_hz, unsigned int mode);
-       void (*free_slave)(struct spi_slave *slave);
-       void (*cs_activate)(struct spi_slave *slave);
-       void (*cs_deactivate)(struct spi_slave *slave);
-       int (*xfer)(struct spi_slave *slave, unsigned int bitlen,
-                   const void *data_out, void *data_in, unsigned long flags);
-};
-
-static struct fdt_spi_driver fdt_spi_drivers[] = {
-#ifdef CONFIG_TEGRA20_SFLASH
-       {
-               .compat         = COMPAT_NVIDIA_TEGRA20_SFLASH,
-               .max_ctrls      = 1,
-               .init           = tegra20_spi_init,
-               .claim_bus      = tegra20_spi_claim_bus,
-               .cs_is_valid    = tegra20_spi_cs_is_valid,
-               .setup_slave    = tegra20_spi_setup_slave,
-               .free_slave     = tegra20_spi_free_slave,
-               .cs_activate    = tegra20_spi_cs_activate,
-               .cs_deactivate  = tegra20_spi_cs_deactivate,
-               .xfer           = tegra20_spi_xfer,
-       },
-#endif
-#ifdef CONFIG_TEGRA20_SLINK
-       {
-               .compat         = COMPAT_NVIDIA_TEGRA20_SLINK,
-               .max_ctrls      = CONFIG_TEGRA_SLINK_CTRLS,
-               .init           = tegra30_spi_init,
-               .claim_bus      = tegra30_spi_claim_bus,
-               .cs_is_valid    = tegra30_spi_cs_is_valid,
-               .setup_slave    = tegra30_spi_setup_slave,
-               .free_slave     = tegra30_spi_free_slave,
-               .cs_activate    = tegra30_spi_cs_activate,
-               .cs_deactivate  = tegra30_spi_cs_deactivate,
-               .xfer           = tegra30_spi_xfer,
-       },
-#endif
-#ifdef CONFIG_TEGRA114_SPI
-       {
-               .compat         = COMPAT_NVIDIA_TEGRA114_SPI,
-               .max_ctrls      = CONFIG_TEGRA114_SPI_CTRLS,
-               .init           = tegra114_spi_init,
-               .claim_bus      = tegra114_spi_claim_bus,
-               .cs_is_valid    = tegra114_spi_cs_is_valid,
-               .setup_slave    = tegra114_spi_setup_slave,
-               .free_slave     = tegra114_spi_free_slave,
-               .cs_activate    = tegra114_spi_cs_activate,
-               .cs_deactivate  = tegra114_spi_cs_deactivate,
-               .xfer           = tegra114_spi_xfer,
-       },
-#endif
-};
-
-static struct fdt_spi_driver *driver;
-
-int spi_cs_is_valid(unsigned int bus, unsigned int cs)
-{
-       if (!driver)
-               return 0;
-       else if (!driver->cs_is_valid)
-               return 1;
-       else
-               return driver->cs_is_valid(bus, cs);
-}
-
-struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
-               unsigned int max_hz, unsigned int mode)
-{
-       if (!driver || !driver->setup_slave)
-               return NULL;
-
-       return driver->setup_slave(bus, cs, max_hz, mode);
-}
-
-void spi_free_slave(struct spi_slave *slave)
-{
-       if (driver && driver->free_slave)
-               return driver->free_slave(slave);
-}
-
-static int spi_init_driver(struct fdt_spi_driver *driver)
-{
-       int count;
-       int node_list[driver->max_ctrls];
-
-       count = fdtdec_find_aliases_for_id(gd->fdt_blob, "spi",
-                                          driver->compat,
-                                          node_list,
-                                          driver->max_ctrls);
-       return driver->init(node_list, count);
-}
-
-void spi_init(void)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(fdt_spi_drivers); i++) {
-               driver = &fdt_spi_drivers[i];
-               if (!spi_init_driver(driver))
-                       break;
-       }
-       if (i == ARRAY_SIZE(fdt_spi_drivers))
-               driver = NULL;
-}
-
-int spi_claim_bus(struct spi_slave *slave)
-{
-       if (!driver)
-               return 1;
-       if (!driver->claim_bus)
-               return 0;
-
-       return driver->claim_bus(slave);
-}
-
-void spi_release_bus(struct spi_slave *slave)
-{
-       if (driver && driver->release_bus)
-               driver->release_bus(slave);
-}
-
-void spi_cs_activate(struct spi_slave *slave)
-{
-       if (driver && driver->cs_activate)
-               driver->cs_activate(slave);
-}
-
-void spi_cs_deactivate(struct spi_slave *slave)
-{
-       if (driver && driver->cs_deactivate)
-               driver->cs_deactivate(slave);
-}
-
-int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
-            const void *data_out, void *data_in, unsigned long flags)
-{
-       if (!driver || !driver->xfer)
-               return -1;
-
-       return driver->xfer(slave, bitlen, data_out, data_in, flags);
-}
index 12e9bdad38db51fdc0fdb127d142189d06c127ae..e717424db83a9ff7dcc15bc57074c5722b66ff11 100644 (file)
@@ -9,26 +9,23 @@
  */
 
 #include <common.h>
+#include <dm.h>
 #include <malloc.h>
 #include <spi.h>
+#include <spi_flash.h>
 #include <os.h>
 
 #include <asm/errno.h>
 #include <asm/spi.h>
 #include <asm/state.h>
+#include <dm/device-internal.h>
+
+DECLARE_GLOBAL_DATA_PTR;
 
 #ifndef CONFIG_SPI_IDLE_VAL
 # define CONFIG_SPI_IDLE_VAL 0xFF
 #endif
 
-struct sandbox_spi_slave {
-       struct spi_slave slave;
-       const struct sandbox_spi_emu_ops *ops;
-       void *priv;
-};
-
-#define to_sandbox_spi_slave(s) container_of(s, struct sandbox_spi_slave, slave)
-
 const char *sandbox_spi_parse_spec(const char *arg, unsigned long *bus,
                                   unsigned long *cs)
 {
@@ -45,120 +42,52 @@ const char *sandbox_spi_parse_spec(const char *arg, unsigned long *bus,
        return endp + 1;
 }
 
-int spi_cs_is_valid(unsigned int bus, unsigned int cs)
-{
-       return bus < CONFIG_SANDBOX_SPI_MAX_BUS &&
-               cs < CONFIG_SANDBOX_SPI_MAX_CS;
-}
-
-void spi_cs_activate(struct spi_slave *slave)
-{
-       struct sandbox_spi_slave *sss = to_sandbox_spi_slave(slave);
-
-       debug("sandbox_spi: activating CS\n");
-       if (sss->ops->cs_activate)
-               sss->ops->cs_activate(sss->priv);
-}
-
-void spi_cs_deactivate(struct spi_slave *slave)
-{
-       struct sandbox_spi_slave *sss = to_sandbox_spi_slave(slave);
-
-       debug("sandbox_spi: deactivating CS\n");
-       if (sss->ops->cs_deactivate)
-               sss->ops->cs_deactivate(sss->priv);
-}
-
-void spi_init(void)
-{
-}
-
-void spi_set_speed(struct spi_slave *slave, uint hz)
+__weak int sandbox_spi_get_emul(struct sandbox_state *state,
+                               struct udevice *bus, struct udevice *slave,
+                               struct udevice **emulp)
 {
+       return -ENOENT;
 }
 
-struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
-               unsigned int max_hz, unsigned int mode)
+static int sandbox_spi_xfer(struct udevice *slave, unsigned int bitlen,
+                           const void *dout, void *din, unsigned long flags)
 {
-       struct sandbox_spi_slave *sss;
+       struct udevice *bus = slave->parent;
        struct sandbox_state *state = state_get_current();
-       const char *spec;
-
-       if (!spi_cs_is_valid(bus, cs)) {
-               debug("sandbox_spi: Invalid SPI bus/cs\n");
-               return NULL;
-       }
-
-       sss = spi_alloc_slave(struct sandbox_spi_slave, bus, cs);
-       if (!sss) {
-               debug("sandbox_spi: Out of memory\n");
-               return NULL;
-       }
-
-       spec = state->spi[bus][cs].spec;
-       sss->ops = state->spi[bus][cs].ops;
-       if (!spec || !sss->ops || sss->ops->setup(&sss->priv, spec)) {
-               free(sss);
-               printf("sandbox_spi: unable to locate a slave client\n");
-               return NULL;
-       }
-
-       return &sss->slave;
-}
-
-void spi_free_slave(struct spi_slave *slave)
-{
-       struct sandbox_spi_slave *sss = to_sandbox_spi_slave(slave);
-
-       debug("sandbox_spi: releasing slave\n");
-
-       if (sss->ops->free)
-               sss->ops->free(sss->priv);
-
-       free(sss);
-}
-
-static int spi_bus_claim_cnt[CONFIG_SANDBOX_SPI_MAX_BUS];
-
-int spi_claim_bus(struct spi_slave *slave)
-{
-       if (spi_bus_claim_cnt[slave->bus]++) {
-               printf("sandbox_spi: error: bus already claimed: %d!\n",
-                      spi_bus_claim_cnt[slave->bus]);
-       }
-
-       return 0;
-}
-
-void spi_release_bus(struct spi_slave *slave)
-{
-       if (--spi_bus_claim_cnt[slave->bus]) {
-               printf("sandbox_spi: error: bus freed too often: %d!\n",
-                      spi_bus_claim_cnt[slave->bus]);
-       }
-}
-
-int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
-               void *din, unsigned long flags)
-{
-       struct sandbox_spi_slave *sss = to_sandbox_spi_slave(slave);
+       struct dm_spi_emul_ops *ops;
+       struct udevice *emul;
        uint bytes = bitlen / 8, i;
-       int ret = 0;
+       int ret;
        u8 *tx = (void *)dout, *rx = din;
+       uint busnum, cs;
 
        if (bitlen == 0)
-               goto done;
+               return 0;
 
        /* we can only do 8 bit transfers */
        if (bitlen % 8) {
                printf("sandbox_spi: xfer: invalid bitlen size %u; needs to be 8bit\n",
                       bitlen);
-               flags |= SPI_XFER_END;
-               goto done;
+               return -EINVAL;
        }
 
-       if (flags & SPI_XFER_BEGIN)
-               spi_cs_activate(slave);
+       busnum = bus->seq;
+       cs = spi_chip_select(slave);
+       if (busnum >= CONFIG_SANDBOX_SPI_MAX_BUS ||
+           cs >= CONFIG_SANDBOX_SPI_MAX_CS) {
+               printf("%s: busnum=%u, cs=%u: out of range\n", __func__,
+                      busnum, cs);
+               return -ENOENT;
+       }
+       ret = sandbox_spi_get_emul(state, bus, slave, &emul);
+       if (ret) {
+               printf("%s: busnum=%u, cs=%u: no emulation available (err=%d)\n",
+                      __func__, busnum, cs, ret);
+               return -ENOENT;
+       }
+       ret = device_probe(emul);
+       if (ret)
+               return ret;
 
        /* make sure rx/tx buffers are full so clients can assume */
        if (!tx) {
@@ -178,12 +107,8 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
                }
        }
 
-       debug("sandbox_spi: xfer: bytes = %u\n tx:", bytes);
-       for (i = 0; i < bytes; ++i)
-               debug(" %u:%02x", i, tx[i]);
-       debug("\n");
-
-       ret = sss->ops->xfer(sss->priv, tx, rx, bytes);
+       ops = spi_emul_get_ops(emul);
+       ret = ops->xfer(emul, bitlen, dout, din, flags);
 
        debug("sandbox_spi: xfer: got back %i (that's %s)\n rx:",
              ret, ret ? "bad" : "good");
@@ -196,22 +121,45 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
        if (rx != din)
                free(rx);
 
- done:
-       if (flags & SPI_XFER_END)
-               spi_cs_deactivate(slave);
-
        return ret;
 }
 
-/**
- * Set up a new SPI slave for an fdt node
- *
- * @param blob         Device tree blob
- * @param node         SPI peripheral node to use
- * @return 0 if ok, -1 on error
- */
-struct spi_slave *spi_setup_slave_fdt(const void *blob, int slave_node,
-                                     int spi_node)
+static int sandbox_spi_set_speed(struct udevice *bus, uint speed)
+{
+       return 0;
+}
+
+static int sandbox_spi_set_mode(struct udevice *bus, uint mode)
+{
+       return 0;
+}
+
+static int sandbox_cs_info(struct udevice *bus, uint cs,
+                          struct spi_cs_info *info)
 {
-       return NULL;
+       /* Always allow activity on CS 0 */
+       if (cs >= 1)
+               return -ENODEV;
+
+       return 0;
 }
+
+static const struct dm_spi_ops sandbox_spi_ops = {
+       .xfer           = sandbox_spi_xfer,
+       .set_speed      = sandbox_spi_set_speed,
+       .set_mode       = sandbox_spi_set_mode,
+       .cs_info        = sandbox_cs_info,
+};
+
+static const struct udevice_id sandbox_spi_ids[] = {
+       { .compatible = "sandbox,spi" },
+       { }
+};
+
+U_BOOT_DRIVER(spi_sandbox) = {
+       .name   = "spi_sandbox",
+       .id     = UCLASS_SPI,
+       .of_match = sandbox_spi_ids,
+       .per_child_auto_alloc_size      = sizeof(struct spi_slave),
+       .ops    = &sandbox_spi_ops,
+};
index c969be31eb31828066e2c044c825529d6412db69..558803618a272cc6e0e8b880ddd89cc8950e6e68 100644 (file)
@@ -1,4 +1,6 @@
 /*
+ * Copyright (c) 2014 Google, Inc
+ *
  * (C) Copyright 2002
  * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com.
  *
  */
 
 #include <common.h>
-#include <spi.h>
-
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
 #include <malloc.h>
+#include <spi.h>
+#include <asm/gpio.h>
 
-/*-----------------------------------------------------------------------
- * Definitions
- */
+DECLARE_GLOBAL_DATA_PTR;
 
-#ifdef DEBUG_SPI
-#define PRINTD(fmt,args...)    printf (fmt ,##args)
-#else
-#define PRINTD(fmt,args...)
-#endif
+struct soft_spi_platdata {
+       struct fdt_gpio_state cs;
+       struct fdt_gpio_state sclk;
+       struct fdt_gpio_state mosi;
+       struct fdt_gpio_state miso;
+       int spi_delay_us;
+};
 
-struct soft_spi_slave {
-       struct spi_slave slave;
+struct soft_spi_priv {
        unsigned int mode;
 };
 
-static inline struct soft_spi_slave *to_soft_spi(struct spi_slave *slave)
+static int soft_spi_scl(struct udevice *dev, int bit)
 {
-       return container_of(slave, struct soft_spi_slave, slave);
-}
+       struct soft_spi_platdata *plat = dev->platdata;
+       struct soft_spi_priv *priv = dev_get_priv(dev);
 
-/*=====================================================================*/
-/*                         Public Functions                            */
-/*=====================================================================*/
+       gpio_set_value(plat->sclk.gpio, priv->mode & SPI_CPOL ? bit : !bit);
 
-/*-----------------------------------------------------------------------
- * Initialization
- */
-void spi_init (void)
-{
-#ifdef SPI_INIT
-       volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
-
-       SPI_INIT;
-#endif
+       return 0;
 }
 
-struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
-               unsigned int max_hz, unsigned int mode)
+static int soft_spi_sda(struct udevice *dev, int bit)
 {
-       struct soft_spi_slave *ss;
+       struct soft_spi_platdata *plat = dev->platdata;
 
-       if (!spi_cs_is_valid(bus, cs))
-               return NULL;
+       gpio_set_value(plat->mosi.gpio, bit);
 
-       ss = spi_alloc_slave(struct soft_spi_slave, bus, cs);
-       if (!ss)
-               return NULL;
+       return 0;
+}
 
-       ss->mode = mode;
+static int soft_spi_cs_activate(struct udevice *dev)
+{
+       struct soft_spi_platdata *plat = dev->platdata;
+       struct soft_spi_priv *priv = dev_get_priv(dev);
 
-       /* TODO: Use max_hz to limit the SCK rate */
+       gpio_set_value(plat->cs.gpio, !(priv->mode & SPI_CS_HIGH));
+       gpio_set_value(plat->sclk.gpio, priv->mode & SPI_CPOL);
+       gpio_set_value(plat->cs.gpio, priv->mode & SPI_CS_HIGH);
 
-       return &ss->slave;
+       return 0;
 }
 
-void spi_free_slave(struct spi_slave *slave)
+static int soft_spi_cs_deactivate(struct udevice *dev)
 {
-       struct soft_spi_slave *ss = to_soft_spi(slave);
+       struct soft_spi_platdata *plat = dev->platdata;
+       struct soft_spi_priv *priv = dev_get_priv(dev);
 
-       free(ss);
+       gpio_set_value(plat->cs.gpio, !(priv->mode & SPI_CS_HIGH));
+
+       return 0;
 }
 
-int spi_claim_bus(struct spi_slave *slave)
+static int soft_spi_claim_bus(struct udevice *dev)
 {
-#ifdef CONFIG_SYS_IMMR
-       volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
-#endif
-       struct soft_spi_slave *ss = to_soft_spi(slave);
-
        /*
         * Make sure the SPI clock is in idle state as defined for
         * this slave.
         */
-       if (ss->mode & SPI_CPOL)
-               SPI_SCL(1);
-       else
-               SPI_SCL(0);
-
-       return 0;
+       return soft_spi_scl(dev, 0);
 }
 
-void spi_release_bus(struct spi_slave *slave)
+static int soft_spi_release_bus(struct udevice *dev)
 {
        /* Nothing to do */
+       return 0;
 }
 
 /*-----------------------------------------------------------------------
@@ -111,28 +100,27 @@ void spi_release_bus(struct spi_slave *slave)
  * input data overwrites the output data (since both are buffered by
  * temporary variables, this is OK).
  */
-int  spi_xfer(struct spi_slave *slave, unsigned int bitlen,
-               const void *dout, void *din, unsigned long flags)
+static int soft_spi_xfer(struct udevice *dev, unsigned int bitlen,
+                        const void *dout, void *din, unsigned long flags)
 {
-#ifdef CONFIG_SYS_IMMR
-       volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
-#endif
-       struct soft_spi_slave *ss = to_soft_spi(slave);
+       struct soft_spi_priv *priv = dev_get_priv(dev);
+       struct soft_spi_platdata *plat = dev->platdata;
        uchar           tmpdin  = 0;
        uchar           tmpdout = 0;
        const u8        *txd = dout;
        u8              *rxd = din;
-       int             cpol = ss->mode & SPI_CPOL;
-       int             cpha = ss->mode & SPI_CPHA;
+       int             cpol = priv->mode & SPI_CPOL;
+       int             cpha = priv->mode & SPI_CPHA;
        unsigned int    j;
 
-       PRINTD("spi_xfer: slave %u:%u dout %08X din %08X bitlen %u\n",
-               slave->bus, slave->cs, *(uint *)txd, *(uint *)rxd, bitlen);
+       debug("spi_xfer: slave %s:%s dout %08X din %08X bitlen %u\n",
+             dev->parent->name, dev->name, *(uint *)txd, *(uint *)rxd,
+             bitlen);
 
        if (flags & SPI_XFER_BEGIN)
-               spi_cs_activate(slave);
+               soft_spi_cs_activate(dev);
 
-       for(j = 0; j < bitlen; j++) {
+       for (j = 0; j < bitlen; j++) {
                /*
                 * Check if it is time to work on a new byte.
                 */
@@ -141,7 +129,7 @@ int  spi_xfer(struct spi_slave *slave, unsigned int bitlen,
                                tmpdout = *txd++;
                        else
                                tmpdout = 0;
-                       if(j != 0) {
+                       if (j != 0) {
                                if (rxd)
                                        *rxd++ = tmpdin;
                        }
@@ -149,19 +137,19 @@ int  spi_xfer(struct spi_slave *slave, unsigned int bitlen,
                }
 
                if (!cpha)
-                       SPI_SCL(!cpol);
-               SPI_SDA(tmpdout & 0x80);
-               SPI_DELAY;
+                       soft_spi_scl(dev, !cpol);
+               soft_spi_sda(dev, tmpdout & 0x80);
+               udelay(plat->spi_delay_us);
                if (cpha)
-                       SPI_SCL(!cpol);
+                       soft_spi_scl(dev, !cpol);
                else
-                       SPI_SCL(cpol);
+                       soft_spi_scl(dev, cpol);
                tmpdin  <<= 1;
-               tmpdin  |= SPI_READ;
+               tmpdin  |= gpio_get_value(plat->miso.gpio);
                tmpdout <<= 1;
-               SPI_DELAY;
+               udelay(plat->spi_delay_us);
                if (cpha)
-                       SPI_SCL(cpol);
+                       soft_spi_scl(dev, cpol);
        }
        /*
         * If the number of bits isn't a multiple of 8, shift the last
@@ -175,7 +163,90 @@ int  spi_xfer(struct spi_slave *slave, unsigned int bitlen,
        }
 
        if (flags & SPI_XFER_END)
-               spi_cs_deactivate(slave);
+               soft_spi_cs_deactivate(dev);
 
-       return(0);
+       return 0;
 }
+
+static int soft_spi_set_speed(struct udevice *dev, unsigned int speed)
+{
+       /* Accept any speed */
+       return 0;
+}
+
+static int soft_spi_set_mode(struct udevice *dev, unsigned int mode)
+{
+       struct soft_spi_priv *priv = dev_get_priv(dev);
+
+       priv->mode = mode;
+
+       return 0;
+}
+
+static int soft_spi_child_pre_probe(struct udevice *dev)
+{
+       struct spi_slave *slave = dev_get_parentdata(dev);
+
+       slave->dev = dev;
+       return spi_ofdata_to_platdata(gd->fdt_blob, dev->of_offset, slave);
+}
+
+static const struct dm_spi_ops soft_spi_ops = {
+       .claim_bus      = soft_spi_claim_bus,
+       .release_bus    = soft_spi_release_bus,
+       .xfer           = soft_spi_xfer,
+       .set_speed      = soft_spi_set_speed,
+       .set_mode       = soft_spi_set_mode,
+};
+
+static int soft_spi_ofdata_to_platdata(struct udevice *dev)
+{
+       struct soft_spi_platdata *plat = dev->platdata;
+       const void *blob = gd->fdt_blob;
+       int node = dev->of_offset;
+
+       if (fdtdec_decode_gpio(blob, node, "cs-gpio", &plat->cs) ||
+           fdtdec_decode_gpio(blob, node, "sclk-gpio", &plat->sclk) ||
+           fdtdec_decode_gpio(blob, node, "mosi-gpio", &plat->mosi) ||
+           fdtdec_decode_gpio(blob, node, "miso-gpio", &plat->miso))
+               return -EINVAL;
+       plat->spi_delay_us = fdtdec_get_int(blob, node, "spi-delay-us", 0);
+
+       return 0;
+}
+
+static int soft_spi_probe(struct udevice *dev)
+{
+       struct spi_slave *slave = dev_get_parentdata(dev);
+       struct soft_spi_platdata *plat = dev->platdata;
+
+       gpio_request(plat->cs.gpio, "soft_spi_cs");
+       gpio_request(plat->sclk.gpio, "soft_spi_sclk");
+       gpio_request(plat->mosi.gpio, "soft_spi_mosi");
+       gpio_request(plat->miso.gpio, "soft_spi_miso");
+
+       gpio_direction_output(plat->sclk.gpio, slave->mode & SPI_CPOL);
+       gpio_direction_output(plat->mosi.gpio, 1);
+       gpio_direction_input(plat->miso.gpio);
+       gpio_direction_output(plat->cs.gpio, !(slave->mode & SPI_CS_HIGH));
+
+       return 0;
+}
+
+static const struct udevice_id soft_spi_ids[] = {
+       { .compatible = "u-boot,soft-spi" },
+       { }
+};
+
+U_BOOT_DRIVER(soft_spi) = {
+       .name   = "soft_spi",
+       .id     = UCLASS_SPI,
+       .of_match = soft_spi_ids,
+       .ops    = &soft_spi_ops,
+       .ofdata_to_platdata = soft_spi_ofdata_to_platdata,
+       .platdata_auto_alloc_size = sizeof(struct soft_spi_platdata),
+       .priv_auto_alloc_size = sizeof(struct soft_spi_priv),
+       .per_child_auto_alloc_size      = sizeof(struct spi_slave),
+       .probe  = soft_spi_probe,
+       .child_pre_probe        = soft_spi_child_pre_probe,
+};
diff --git a/drivers/spi/soft_spi_legacy.c b/drivers/spi/soft_spi_legacy.c
new file mode 100644 (file)
index 0000000..941daa7
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * (C) Copyright 2002
+ * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com.
+ *
+ * Influenced by code from:
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <spi.h>
+
+#include <malloc.h>
+
+/*-----------------------------------------------------------------------
+ * Definitions
+ */
+
+#ifdef DEBUG_SPI
+#define PRINTD(fmt,args...)    printf (fmt ,##args)
+#else
+#define PRINTD(fmt,args...)
+#endif
+
+struct soft_spi_slave {
+       struct spi_slave slave;
+       unsigned int mode;
+};
+
+static inline struct soft_spi_slave *to_soft_spi(struct spi_slave *slave)
+{
+       return container_of(slave, struct soft_spi_slave, slave);
+}
+
+/*=====================================================================*/
+/*                         Public Functions                            */
+/*=====================================================================*/
+
+/*-----------------------------------------------------------------------
+ * Initialization
+ */
+void spi_init (void)
+{
+}
+
+struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
+               unsigned int max_hz, unsigned int mode)
+{
+       struct soft_spi_slave *ss;
+
+       if (!spi_cs_is_valid(bus, cs))
+               return NULL;
+
+       ss = spi_alloc_slave(struct soft_spi_slave, bus, cs);
+       if (!ss)
+               return NULL;
+
+       ss->mode = mode;
+
+       /* TODO: Use max_hz to limit the SCK rate */
+
+       return &ss->slave;
+}
+
+void spi_free_slave(struct spi_slave *slave)
+{
+       struct soft_spi_slave *ss = to_soft_spi(slave);
+
+       free(ss);
+}
+
+int spi_claim_bus(struct spi_slave *slave)
+{
+#ifdef CONFIG_SYS_IMMR
+       volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+#endif
+       struct soft_spi_slave *ss = to_soft_spi(slave);
+
+       /*
+        * Make sure the SPI clock is in idle state as defined for
+        * this slave.
+        */
+       if (ss->mode & SPI_CPOL)
+               SPI_SCL(1);
+       else
+               SPI_SCL(0);
+
+       return 0;
+}
+
+void spi_release_bus(struct spi_slave *slave)
+{
+       /* Nothing to do */
+}
+
+/*-----------------------------------------------------------------------
+ * SPI transfer
+ *
+ * This writes "bitlen" bits out the SPI MOSI port and simultaneously clocks
+ * "bitlen" bits in the SPI MISO port.  That's just the way SPI works.
+ *
+ * The source of the outgoing bits is the "dout" parameter and the
+ * destination of the input bits is the "din" parameter.  Note that "dout"
+ * and "din" can point to the same memory location, in which case the
+ * input data overwrites the output data (since both are buffered by
+ * temporary variables, this is OK).
+ */
+int  spi_xfer(struct spi_slave *slave, unsigned int bitlen,
+               const void *dout, void *din, unsigned long flags)
+{
+#ifdef CONFIG_SYS_IMMR
+       volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+#endif
+       struct soft_spi_slave *ss = to_soft_spi(slave);
+       uchar           tmpdin  = 0;
+       uchar           tmpdout = 0;
+       const u8        *txd = dout;
+       u8              *rxd = din;
+       int             cpol = ss->mode & SPI_CPOL;
+       int             cpha = ss->mode & SPI_CPHA;
+       unsigned int    j;
+
+       PRINTD("spi_xfer: slave %u:%u dout %08X din %08X bitlen %u\n",
+               slave->bus, slave->cs, *(uint *)txd, *(uint *)rxd, bitlen);
+
+       if (flags & SPI_XFER_BEGIN)
+               spi_cs_activate(slave);
+
+       for(j = 0; j < bitlen; j++) {
+               /*
+                * Check if it is time to work on a new byte.
+                */
+               if ((j % 8) == 0) {
+                       if (txd)
+                               tmpdout = *txd++;
+                       else
+                               tmpdout = 0;
+                       if(j != 0) {
+                               if (rxd)
+                                       *rxd++ = tmpdin;
+                       }
+                       tmpdin  = 0;
+               }
+
+               if (!cpha)
+                       SPI_SCL(!cpol);
+               SPI_SDA(tmpdout & 0x80);
+               SPI_DELAY;
+               if (cpha)
+                       SPI_SCL(!cpol);
+               else
+                       SPI_SCL(cpol);
+               tmpdin  <<= 1;
+               tmpdin  |= SPI_READ;
+               tmpdout <<= 1;
+               SPI_DELAY;
+               if (cpha)
+                       SPI_SCL(cpol);
+       }
+       /*
+        * If the number of bits isn't a multiple of 8, shift the last
+        * bits over to left-justify them.  Then store the last byte
+        * read in.
+        */
+       if (rxd) {
+               if ((bitlen % 8) != 0)
+                       tmpdin <<= 8 - (bitlen % 8);
+               *rxd++ = tmpdin;
+       }
+
+       if (flags & SPI_XFER_END)
+               spi_cs_deactivate(slave);
+
+       return(0);
+}
diff --git a/drivers/spi/spi-emul-uclass.c b/drivers/spi/spi-emul-uclass.c
new file mode 100644 (file)
index 0000000..b436a0e
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <spi.h>
+#include <spi_flash.h>
+
+UCLASS_DRIVER(spi_emul) = {
+       .id             = UCLASS_SPI_EMUL,
+       .name           = "spi_emul",
+};
diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c
new file mode 100644 (file)
index 0000000..13c6b77
--- /dev/null
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <malloc.h>
+#include <spi.h>
+#include <dm/device-internal.h>
+#include <dm/uclass-internal.h>
+#include <dm/root.h>
+#include <dm/lists.h>
+#include <dm/util.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int spi_set_speed_mode(struct udevice *bus, int speed, int mode)
+{
+       struct dm_spi_ops *ops;
+       int ret;
+
+       ops = spi_get_ops(bus);
+       if (ops->set_speed)
+               ret = ops->set_speed(bus, speed);
+       else
+               ret = -EINVAL;
+       if (ret) {
+               printf("Cannot set speed (err=%d)\n", ret);
+               return ret;
+       }
+
+       if (ops->set_mode)
+               ret = ops->set_mode(bus, mode);
+       else
+               ret = -EINVAL;
+       if (ret) {
+               printf("Cannot set mode (err=%d)\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+int spi_claim_bus(struct spi_slave *slave)
+{
+       struct udevice *dev = slave->dev;
+       struct udevice *bus = dev->parent;
+       struct dm_spi_ops *ops = spi_get_ops(bus);
+       struct dm_spi_bus *spi = bus->uclass_priv;
+       int speed;
+       int ret;
+
+       speed = slave->max_hz;
+       if (spi->max_hz) {
+               if (speed)
+                       speed = min(speed, spi->max_hz);
+               else
+                       speed = spi->max_hz;
+       }
+       if (!speed)
+               speed = 100000;
+       ret = spi_set_speed_mode(bus, speed, slave->mode);
+       if (ret)
+               return ret;
+
+       return ops->claim_bus ? ops->claim_bus(bus) : 0;
+}
+
+void spi_release_bus(struct spi_slave *slave)
+{
+       struct udevice *dev = slave->dev;
+       struct udevice *bus = dev->parent;
+       struct dm_spi_ops *ops = spi_get_ops(bus);
+
+       if (ops->release_bus)
+               ops->release_bus(bus);
+}
+
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
+            const void *dout, void *din, unsigned long flags)
+{
+       struct udevice *dev = slave->dev;
+       struct udevice *bus = dev->parent;
+
+       if (bus->uclass->uc_drv->id != UCLASS_SPI)
+               return -EOPNOTSUPP;
+
+       return spi_get_ops(bus)->xfer(dev, bitlen, dout, din, flags);
+}
+
+int spi_post_bind(struct udevice *dev)
+{
+       /* Scan the bus for devices */
+       return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
+}
+
+int spi_post_probe(struct udevice *dev)
+{
+       struct dm_spi_bus *spi = dev->uclass_priv;
+
+       spi->max_hz = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
+                                    "spi-max-frequency", 0);
+
+       return 0;
+}
+
+int spi_chip_select(struct udevice *dev)
+{
+       struct spi_slave *slave = dev_get_parentdata(dev);
+
+       return slave ? slave->cs : -ENOENT;
+}
+
+/**
+ * spi_find_chip_select() - Find the slave attached to chip select
+ *
+ * @bus:       SPI bus to search
+ * @cs:                Chip select to look for
+ * @devp:      Returns the slave device if found
+ * @return 0 if found, -ENODEV on error
+ */
+static int spi_find_chip_select(struct udevice *bus, int cs,
+                               struct udevice **devp)
+{
+       struct udevice *dev;
+
+       for (device_find_first_child(bus, &dev); dev;
+            device_find_next_child(&dev)) {
+               struct spi_slave store;
+               struct spi_slave *slave = dev_get_parentdata(dev);
+
+               if (!slave)  {
+                       slave = &store;
+                       spi_ofdata_to_platdata(gd->fdt_blob, dev->of_offset,
+                                              slave);
+               }
+               debug("%s: slave=%p, cs=%d\n", __func__, slave,
+                     slave ? slave->cs : -1);
+               if (slave && slave->cs == cs) {
+                       *devp = dev;
+                       return 0;
+               }
+       }
+
+       return -ENODEV;
+}
+
+int spi_cs_is_valid(unsigned int busnum, unsigned int cs)
+{
+       struct spi_cs_info info;
+       struct udevice *bus;
+       int ret;
+
+       ret = uclass_find_device_by_seq(UCLASS_SPI, busnum, false, &bus);
+       if (ret) {
+               debug("%s: No bus %d\n", __func__, busnum);
+               return ret;
+       }
+
+       return spi_cs_info(bus, cs, &info);
+}
+
+int spi_cs_info(struct udevice *bus, uint cs, struct spi_cs_info *info)
+{
+       struct spi_cs_info local_info;
+       struct dm_spi_ops *ops;
+       int ret;
+
+       if (!info)
+               info = &local_info;
+
+       /* If there is a device attached, return it */
+       info->dev = NULL;
+       ret = spi_find_chip_select(bus, cs, &info->dev);
+       if (!ret)
+               return 0;
+
+       /*
+        * Otherwise ask the driver. For the moment we don't have CS info.
+        * When we do we could provide the driver with a helper function
+        * to figure out what chip selects are valid, or just handle the
+        * request.
+        */
+       ops = spi_get_ops(bus);
+       if (ops->cs_info)
+               return ops->cs_info(bus, cs, info);
+
+       /*
+        * We could assume there is at least one valid chip select, but best
+        * to be sure and return an error in this case. The driver didn't
+        * care enough to tell us.
+        */
+       return -ENODEV;
+}
+
+int spi_bind_device(struct udevice *bus, int cs, const char *drv_name,
+                   const char *dev_name, struct udevice **devp)
+{
+       struct driver *drv;
+       int ret;
+
+       drv = lists_driver_lookup_name(drv_name);
+       if (!drv) {
+               printf("Cannot find driver '%s'\n", drv_name);
+               return -ENOENT;
+       }
+       ret = device_bind(bus, drv, dev_name, NULL, -1, devp);
+       if (ret) {
+               printf("Cannot create device named '%s' (err=%d)\n",
+                      dev_name, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+int spi_find_bus_and_cs(int busnum, int cs, struct udevice **busp,
+                       struct udevice **devp)
+{
+       struct udevice *bus, *dev;
+       int ret;
+
+       ret = uclass_find_device_by_seq(UCLASS_SPI, busnum, false, &bus);
+       if (ret) {
+               debug("%s: No bus %d\n", __func__, busnum);
+               return ret;
+       }
+       ret = spi_find_chip_select(bus, cs, &dev);
+       if (ret) {
+               debug("%s: No cs %d\n", __func__, cs);
+               return ret;
+       }
+       *busp = bus;
+       *devp = dev;
+
+       return ret;
+}
+
+int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode,
+                      const char *drv_name, const char *dev_name,
+                      struct udevice **busp, struct spi_slave **devp)
+{
+       struct udevice *bus, *dev;
+       struct spi_slave *slave;
+       bool created = false;
+       int ret;
+
+       ret = uclass_get_device_by_seq(UCLASS_SPI, busnum, &bus);
+       if (ret) {
+               printf("Invalid bus %d (err=%d)\n", busnum, ret);
+               return ret;
+       }
+       ret = spi_find_chip_select(bus, cs, &dev);
+
+       /*
+        * If there is no such device, create one automatically. This means
+        * that we don't need a device tree node or platform data for the
+        * SPI flash chip - we will bind to the correct driver.
+        */
+       if (ret == -ENODEV && drv_name) {
+               debug("%s: Binding new device '%s', busnum=%d, cs=%d, driver=%s\n",
+                     __func__, dev_name, busnum, cs, drv_name);
+               ret = spi_bind_device(bus, cs, drv_name, dev_name, &dev);
+               if (ret)
+                       return ret;
+               created = true;
+       } else if (ret) {
+               printf("Invalid chip select %d:%d (err=%d)\n", busnum, cs,
+                      ret);
+               return ret;
+       }
+
+       if (!device_active(dev)) {
+               slave = (struct spi_slave *)calloc(1,
+                                                  sizeof(struct spi_slave));
+               if (!slave) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
+
+               ret = spi_ofdata_to_platdata(gd->fdt_blob, dev->of_offset,
+                                            slave);
+               if (ret)
+                       goto err;
+               slave->cs = cs;
+               slave->dev = dev;
+               ret = device_probe_child(dev, slave);
+               free(slave);
+               if (ret)
+                       goto err;
+       }
+
+       ret = spi_set_speed_mode(bus, speed, mode);
+       if (ret)
+               goto err;
+
+       *busp = bus;
+       *devp = dev_get_parentdata(dev);
+       debug("%s: bus=%p, slave=%p\n", __func__, bus, *devp);
+
+       return 0;
+
+err:
+       if (created) {
+               device_remove(dev);
+               device_unbind(dev);
+       }
+
+       return ret;
+}
+
+/* Compatibility function - to be removed */
+struct spi_slave *spi_setup_slave_fdt(const void *blob, int node,
+                                     int bus_node)
+{
+       struct udevice *bus, *dev;
+       int ret;
+
+       ret = uclass_get_device_by_of_offset(UCLASS_SPI, bus_node, &bus);
+       if (ret)
+               return NULL;
+       ret = device_get_child_by_of_offset(bus, node, &dev);
+       if (ret)
+               return NULL;
+       return dev_get_parentdata(dev);
+}
+
+/* Compatibility function - to be removed */
+struct spi_slave *spi_setup_slave(unsigned int busnum, unsigned int cs,
+                                 unsigned int speed, unsigned int mode)
+{
+       struct spi_slave *slave;
+       struct udevice *dev;
+       int ret;
+
+       ret = spi_get_bus_and_cs(busnum, cs, speed, mode, NULL, 0, &dev,
+                                 &slave);
+       if (ret)
+               return NULL;
+
+       return slave;
+}
+
+void spi_free_slave(struct spi_slave *slave)
+{
+       device_remove(slave->dev);
+       slave->dev = NULL;
+}
+
+int spi_ofdata_to_platdata(const void *blob, int node,
+                          struct spi_slave *spi)
+{
+       int mode = 0;
+
+       spi->cs = fdtdec_get_int(blob, node, "reg", -1);
+       spi->max_hz = fdtdec_get_int(blob, node, "spi-max-frequency", 0);
+       if (fdtdec_get_bool(blob, node, "spi-cpol"))
+               mode |= SPI_CPOL;
+       if (fdtdec_get_bool(blob, node, "spi-cpha"))
+               mode |= SPI_CPHA;
+       if (fdtdec_get_bool(blob, node, "spi-cs-high"))
+               mode |= SPI_CS_HIGH;
+       if (fdtdec_get_bool(blob, node, "spi-half-duplex"))
+               mode |= SPI_PREAMBLE;
+       spi->mode = mode;
+
+       return 0;
+}
+
+UCLASS_DRIVER(spi) = {
+       .id             = UCLASS_SPI,
+       .name           = "spi",
+       .post_bind      = spi_post_bind,
+       .post_probe     = spi_post_probe,
+       .per_device_auto_alloc_size = sizeof(struct dm_spi_bus),
+};
+
+UCLASS_DRIVER(spi_generic) = {
+       .id             = UCLASS_SPI_GENERIC,
+       .name           = "spi_generic",
+};
+
+U_BOOT_DRIVER(spi_generic_drv) = {
+       .name           = "spi_generic_drv",
+       .id             = UCLASS_SPI_GENERIC,
+};
index 810fa4718ce17b87c389a522c6cea788c9df3867..2d97625fba73b81dcb8a2ba2d55d5e1d5eef0bcb 100644 (file)
  */
 
 #include <common.h>
-#include <malloc.h>
+#include <dm.h>
 #include <asm/io.h>
-#include <asm/gpio.h>
 #include <asm/arch/clock.h>
 #include <asm/arch-tegra/clk_rst.h>
-#include <asm/arch-tegra114/tegra114_spi.h>
 #include <spi.h>
 #include <fdtdec.h>
+#include "tegra_spi.h"
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -104,130 +103,63 @@ struct spi_regs {
        u32 spare_ctl;  /* 18c:SPI_SPARE_CTRL register */
 };
 
-struct tegra_spi_ctrl {
+struct tegra114_spi_priv {
        struct spi_regs *regs;
        unsigned int freq;
        unsigned int mode;
        int periph_id;
        int valid;
+       int last_transaction_us;
 };
 
-struct tegra_spi_slave {
-       struct spi_slave slave;
-       struct tegra_spi_ctrl *ctrl;
-};
-
-static struct tegra_spi_ctrl spi_ctrls[CONFIG_TEGRA114_SPI_CTRLS];
-
-static inline struct tegra_spi_slave *to_tegra_spi(struct spi_slave *slave)
+static int tegra114_spi_ofdata_to_platdata(struct udevice *bus)
 {
-       return container_of(slave, struct tegra_spi_slave, slave);
-}
+       struct tegra_spi_platdata *plat = bus->platdata;
+       const void *blob = gd->fdt_blob;
+       int node = bus->of_offset;
 
-int tegra114_spi_cs_is_valid(unsigned int bus, unsigned int cs)
-{
-       if (bus >= CONFIG_TEGRA114_SPI_CTRLS || cs > 3 || !spi_ctrls[bus].valid)
-               return 0;
-       else
-               return 1;
-}
+       plat->base = fdtdec_get_addr(blob, node, "reg");
+       plat->periph_id = clock_decode_periph_id(blob, node);
 
-struct spi_slave *tegra114_spi_setup_slave(unsigned int bus, unsigned int cs,
-               unsigned int max_hz, unsigned int mode)
-{
-       struct tegra_spi_slave *spi;
-
-       debug("%s: bus: %u, cs: %u, max_hz: %u, mode: %u\n", __func__,
-               bus, cs, max_hz, mode);
-
-       if (!spi_cs_is_valid(bus, cs)) {
-               printf("SPI error: unsupported bus %d / chip select %d\n",
-                      bus, cs);
-               return NULL;
-       }
-
-       if (max_hz > TEGRA_SPI_MAX_FREQ) {
-               printf("SPI error: unsupported frequency %d Hz. Max frequency"
-                       " is %d Hz\n", max_hz, TEGRA_SPI_MAX_FREQ);
-               return NULL;
+       if (plat->periph_id == PERIPH_ID_NONE) {
+               debug("%s: could not decode periph id %d\n", __func__,
+                     plat->periph_id);
+               return -FDT_ERR_NOTFOUND;
        }
 
-       spi = spi_alloc_slave(struct tegra_spi_slave, bus, cs);
-       if (!spi) {
-               printf("SPI error: malloc of SPI structure failed\n");
-               return NULL;
-       }
-       spi->ctrl = &spi_ctrls[bus];
-       if (!spi->ctrl) {
-               printf("SPI error: could not find controller for bus %d\n",
-                      bus);
-               return NULL;
-       }
+       /* Use 500KHz as a suitable default */
+       plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency",
+                                       500000);
+       plat->deactivate_delay_us = fdtdec_get_int(blob, node,
+                                       "spi-deactivate-delay", 0);
+       debug("%s: base=%#08lx, periph_id=%d, max-frequency=%d, deactivate_delay=%d\n",
+             __func__, plat->base, plat->periph_id, plat->frequency,
+             plat->deactivate_delay_us);
 
-       if (max_hz < spi->ctrl->freq) {
-               debug("%s: limiting frequency from %u to %u\n", __func__,
-                     spi->ctrl->freq, max_hz);
-               spi->ctrl->freq = max_hz;
-       }
-       spi->ctrl->mode = mode;
-
-       return &spi->slave;
-}
-
-void tegra114_spi_free_slave(struct spi_slave *slave)
-{
-       struct tegra_spi_slave *spi = to_tegra_spi(slave);
-
-       free(spi);
+       return 0;
 }
 
-int tegra114_spi_init(int *node_list, int count)
+static int tegra114_spi_probe(struct udevice *bus)
 {
-       struct tegra_spi_ctrl *ctrl;
-       int i;
-       int node = 0;
-       int found = 0;
-
-       for (i = 0; i < count; i++) {
-               ctrl = &spi_ctrls[i];
-               node = node_list[i];
-
-               ctrl->regs = (struct spi_regs *)fdtdec_get_addr(gd->fdt_blob,
-                                                                node, "reg");
-               if ((fdt_addr_t)ctrl->regs == FDT_ADDR_T_NONE) {
-                       debug("%s: no spi register found\n", __func__);
-                       continue;
-               }
-               ctrl->freq = fdtdec_get_int(gd->fdt_blob, node,
-                                           "spi-max-frequency", 0);
-               if (!ctrl->freq) {
-                       debug("%s: no spi max frequency found\n", __func__);
-                       continue;
-               }
+       struct tegra_spi_platdata *plat = dev_get_platdata(bus);
+       struct tegra114_spi_priv *priv = dev_get_priv(bus);
 
-               ctrl->periph_id = clock_decode_periph_id(gd->fdt_blob, node);
-               if (ctrl->periph_id == PERIPH_ID_NONE) {
-                       debug("%s: could not decode periph id\n", __func__);
-                       continue;
-               }
-               ctrl->valid = 1;
-               found = 1;
+       priv->regs = (struct spi_regs *)plat->base;
 
-               debug("%s: found controller at %p, freq = %u, periph_id = %d\n",
-                     __func__, ctrl->regs, ctrl->freq, ctrl->periph_id);
-       }
+       priv->last_transaction_us = timer_get_us();
+       priv->freq = plat->frequency;
+       priv->periph_id = plat->periph_id;
 
-       return !found;
+       return 0;
 }
 
-int tegra114_spi_claim_bus(struct spi_slave *slave)
+static int tegra114_spi_claim_bus(struct udevice *bus)
 {
-       struct tegra_spi_slave *spi = to_tegra_spi(slave);
-       struct spi_regs *regs = spi->ctrl->regs;
+       struct tegra114_spi_priv *priv = dev_get_priv(bus);
+       struct spi_regs *regs = priv->regs;
 
        /* Change SPI clock to correct frequency, PLLP_OUT0 source */
-       clock_start_periph_pll(spi->ctrl->periph_id, CLOCK_ID_PERIPH,
-                              spi->ctrl->freq);
+       clock_start_periph_pll(priv->periph_id, CLOCK_ID_PERIPH, priv->freq);
 
        /* Clear stale status here */
        setbits_le32(&regs->fifo_status,
@@ -244,33 +176,64 @@ int tegra114_spi_claim_bus(struct spi_slave *slave)
 
        /* Set master mode and sw controlled CS */
        setbits_le32(&regs->command1, SPI_CMD1_M_S | SPI_CMD1_CS_SW_HW |
-                    (spi->ctrl->mode << SPI_CMD1_MODE_SHIFT));
+                    (priv->mode << SPI_CMD1_MODE_SHIFT));
        debug("%s: COMMAND1 = %08x\n", __func__, readl(&regs->command1));
 
        return 0;
 }
 
-void tegra114_spi_cs_activate(struct spi_slave *slave)
+/**
+ * Activate the CS by driving it LOW
+ *
+ * @param slave        Pointer to spi_slave to which controller has to
+ *             communicate with
+ */
+static void spi_cs_activate(struct udevice *dev)
 {
-       struct tegra_spi_slave *spi = to_tegra_spi(slave);
-       struct spi_regs *regs = spi->ctrl->regs;
+       struct udevice *bus = dev->parent;
+       struct tegra_spi_platdata *pdata = dev_get_platdata(bus);
+       struct tegra114_spi_priv *priv = dev_get_priv(bus);
+
+       /* If it's too soon to do another transaction, wait */
+       if (pdata->deactivate_delay_us &&
+           priv->last_transaction_us) {
+               ulong delay_us;         /* The delay completed so far */
+               delay_us = timer_get_us() - priv->last_transaction_us;
+               if (delay_us < pdata->deactivate_delay_us)
+                       udelay(pdata->deactivate_delay_us - delay_us);
+       }
 
-       clrbits_le32(&regs->command1, SPI_CMD1_CS_SW_VAL);
+       clrbits_le32(&priv->regs->command1, SPI_CMD1_CS_SW_VAL);
 }
 
-void tegra114_spi_cs_deactivate(struct spi_slave *slave)
+/**
+ * Deactivate the CS by driving it HIGH
+ *
+ * @param slave        Pointer to spi_slave to which controller has to
+ *             communicate with
+ */
+static void spi_cs_deactivate(struct udevice *dev)
 {
-       struct tegra_spi_slave *spi = to_tegra_spi(slave);
-       struct spi_regs *regs = spi->ctrl->regs;
+       struct udevice *bus = dev->parent;
+       struct tegra_spi_platdata *pdata = dev_get_platdata(bus);
+       struct tegra114_spi_priv *priv = dev_get_priv(bus);
+
+       setbits_le32(&priv->regs->command1, SPI_CMD1_CS_SW_VAL);
 
-       setbits_le32(&regs->command1, SPI_CMD1_CS_SW_VAL);
+       /* Remember time of this transaction so we can honour the bus delay */
+       if (pdata->deactivate_delay_us)
+               priv->last_transaction_us = timer_get_us();
+
+       debug("Deactivate CS, bus '%s'\n", bus->name);
 }
 
-int tegra114_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
-               const void *data_out, void *data_in, unsigned long flags)
+static int tegra114_spi_xfer(struct udevice *dev, unsigned int bitlen,
+                            const void *data_out, void *data_in,
+                            unsigned long flags)
 {
-       struct tegra_spi_slave *spi = to_tegra_spi(slave);
-       struct spi_regs *regs = spi->ctrl->regs;
+       struct udevice *bus = dev->parent;
+       struct tegra114_spi_priv *priv = dev_get_priv(bus);
+       struct spi_regs *regs = priv->regs;
        u32 reg, tmpdout, tmpdin = 0;
        const u8 *dout = data_out;
        u8 *din = data_in;
@@ -278,7 +241,7 @@ int tegra114_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
        int ret;
 
        debug("%s: slave %u:%u dout %p din %p bitlen %u\n",
-             __func__, slave->bus, slave->cs, dout, din, bitlen);
+             __func__, bus->seq, spi_chip_select(dev), dout, din, bitlen);
        if (bitlen % 8)
                return -1;
        num_bytes = bitlen / 8;
@@ -291,13 +254,13 @@ int tegra114_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
 
        clrsetbits_le32(&regs->command1, SPI_CMD1_CS_SW_VAL,
                        SPI_CMD1_RX_EN | SPI_CMD1_TX_EN | SPI_CMD1_LSBY_FE |
-                       (slave->cs << SPI_CMD1_CS_SEL_SHIFT));
+                       (spi_chip_select(dev) << SPI_CMD1_CS_SEL_SHIFT));
 
        /* set xfer size to 1 block (32 bits) */
        writel(0, &regs->dma_blk);
 
        if (flags & SPI_XFER_BEGIN)
-               spi_cs_activate(slave);
+               spi_cs_activate(dev);
 
        /* handle data in 32-bit chunks */
        while (num_bytes > 0) {
@@ -383,7 +346,7 @@ int tegra114_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
        }
 
        if (flags & SPI_XFER_END)
-               spi_cs_deactivate(slave);
+               spi_cs_deactivate(dev);
 
        debug("%s: transfer ended. Value=%08x, fifo_status = %08x\n",
              __func__, tmpdin, readl(&regs->fifo_status));
@@ -394,5 +357,56 @@ int tegra114_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
                return -1;
        }
 
+       return ret;
+}
+
+static int tegra114_spi_set_speed(struct udevice *bus, uint speed)
+{
+       struct tegra_spi_platdata *plat = bus->platdata;
+       struct tegra114_spi_priv *priv = dev_get_priv(bus);
+
+       if (speed > plat->frequency)
+               speed = plat->frequency;
+       priv->freq = speed;
+       debug("%s: regs=%p, speed=%d\n", __func__, priv->regs, priv->freq);
+
        return 0;
 }
+
+static int tegra114_spi_set_mode(struct udevice *bus, uint mode)
+{
+       struct tegra114_spi_priv *priv = dev_get_priv(bus);
+
+       priv->mode = mode;
+       debug("%s: regs=%p, mode=%d\n", __func__, priv->regs, priv->mode);
+
+       return 0;
+}
+
+static const struct dm_spi_ops tegra114_spi_ops = {
+       .claim_bus      = tegra114_spi_claim_bus,
+       .xfer           = tegra114_spi_xfer,
+       .set_speed      = tegra114_spi_set_speed,
+       .set_mode       = tegra114_spi_set_mode,
+       /*
+        * cs_info is not needed, since we require all chip selects to be
+        * in the device tree explicitly
+        */
+};
+
+static const struct udevice_id tegra114_spi_ids[] = {
+       { .compatible = "nvidia,tegra114-spi" },
+       { }
+};
+
+U_BOOT_DRIVER(tegra114_spi) = {
+       .name   = "tegra114_spi",
+       .id     = UCLASS_SPI,
+       .of_match = tegra114_spi_ids,
+       .ops    = &tegra114_spi_ops,
+       .ofdata_to_platdata = tegra114_spi_ofdata_to_platdata,
+       .platdata_auto_alloc_size = sizeof(struct tegra_spi_platdata),
+       .priv_auto_alloc_size = sizeof(struct tegra114_spi_priv),
+       .per_child_auto_alloc_size      = sizeof(struct spi_slave),
+       .probe  = tegra114_spi_probe,
+};
index b5d561be34108dade5a7450391ff9824461d03c9..7d0d0f37fc70a7f5f5da821b2af8589bf59ac7a1 100644 (file)
@@ -7,15 +7,16 @@
  */
 
 #include <common.h>
-#include <malloc.h>
+#include <dm.h>
+#include <errno.h>
 #include <asm/io.h>
 #include <asm/gpio.h>
 #include <asm/arch/clock.h>
 #include <asm/arch/pinmux.h>
 #include <asm/arch-tegra/clk_rst.h>
-#include <asm/arch-tegra20/tegra20_sflash.h>
 #include <spi.h>
 #include <fdtdec.h>
+#include "tegra_spi.h"
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -64,129 +65,75 @@ struct spi_regs {
        u32 rx_fifo;    /* SPI_RX_FIFO_0 register */
 };
 
-struct tegra_spi_ctrl {
+struct tegra20_sflash_priv {
        struct spi_regs *regs;
        unsigned int freq;
        unsigned int mode;
        int periph_id;
        int valid;
+       int last_transaction_us;
 };
 
-struct tegra_spi_slave {
-       struct spi_slave slave;
-       struct tegra_spi_ctrl *ctrl;
-};
-
-/* tegra20 only supports one SFLASH controller */
-static struct tegra_spi_ctrl spi_ctrls[1];
-
-static inline struct tegra_spi_slave *to_tegra_spi(struct spi_slave *slave)
-{
-       return container_of(slave, struct tegra_spi_slave, slave);
-}
-
-int tegra20_spi_cs_is_valid(unsigned int bus, unsigned int cs)
+int tegra20_sflash_cs_info(struct udevice *bus, unsigned int cs,
+                          struct spi_cs_info *info)
 {
        /* Tegra20 SPI-Flash - only 1 device ('bus/cs') */
-       if (bus != 0 || cs != 0)
-               return 0;
+       if (cs != 0)
+               return -ENODEV;
        else
-               return 1;
+               return 0;
 }
 
-struct spi_slave *tegra20_spi_setup_slave(unsigned int bus, unsigned int cs,
-                                 unsigned int max_hz, unsigned int mode)
+static int tegra20_sflash_ofdata_to_platdata(struct udevice *bus)
 {
-       struct tegra_spi_slave *spi;
+       struct tegra_spi_platdata *plat = bus->platdata;
+       const void *blob = gd->fdt_blob;
+       int node = bus->of_offset;
 
-       if (!spi_cs_is_valid(bus, cs)) {
-               printf("SPI error: unsupported bus %d / chip select %d\n",
-                      bus, cs);
-               return NULL;
-       }
+       plat->base = fdtdec_get_addr(blob, node, "reg");
+       plat->periph_id = clock_decode_periph_id(blob, node);
 
-       if (max_hz > TEGRA_SPI_MAX_FREQ) {
-               printf("SPI error: unsupported frequency %d Hz. Max frequency"
-                       " is %d Hz\n", max_hz, TEGRA_SPI_MAX_FREQ);
-               return NULL;
+       if (plat->periph_id == PERIPH_ID_NONE) {
+               debug("%s: could not decode periph id %d\n", __func__,
+                     plat->periph_id);
+               return -FDT_ERR_NOTFOUND;
        }
 
-       spi = spi_alloc_slave(struct tegra_spi_slave, bus, cs);
-       if (!spi) {
-               printf("SPI error: malloc of SPI structure failed\n");
-               return NULL;
-       }
-       spi->ctrl = &spi_ctrls[bus];
-       if (!spi->ctrl) {
-               printf("SPI error: could not find controller for bus %d\n",
-                      bus);
-               return NULL;
-       }
+       /* Use 500KHz as a suitable default */
+       plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency",
+                                       500000);
+       plat->deactivate_delay_us = fdtdec_get_int(blob, node,
+                                       "spi-deactivate-delay", 0);
+       debug("%s: base=%#08lx, periph_id=%d, max-frequency=%d, deactivate_delay=%d\n",
+             __func__, plat->base, plat->periph_id, plat->frequency,
+             plat->deactivate_delay_us);
 
-       if (max_hz < spi->ctrl->freq) {
-               debug("%s: limiting frequency from %u to %u\n", __func__,
-                     spi->ctrl->freq, max_hz);
-               spi->ctrl->freq = max_hz;
-       }
-       spi->ctrl->mode = mode;
-
-       return &spi->slave;
+       return 0;
 }
 
-void tegra20_spi_free_slave(struct spi_slave *slave)
+static int tegra20_sflash_probe(struct udevice *bus)
 {
-       struct tegra_spi_slave *spi = to_tegra_spi(slave);
-
-       free(spi);
-}
+       struct tegra_spi_platdata *plat = dev_get_platdata(bus);
+       struct tegra20_sflash_priv *priv = dev_get_priv(bus);
 
-int tegra20_spi_init(int *node_list, int count)
-{
-       struct tegra_spi_ctrl *ctrl;
-       int i;
-       int node = 0;
-       int found = 0;
-
-       for (i = 0; i < count; i++) {
-               ctrl = &spi_ctrls[i];
-               node = node_list[i];
-
-               ctrl->regs = (struct spi_regs *)fdtdec_get_addr(gd->fdt_blob,
-                                                               node, "reg");
-               if ((fdt_addr_t)ctrl->regs == FDT_ADDR_T_NONE) {
-                       debug("%s: no slink register found\n", __func__);
-                       continue;
-               }
-               ctrl->freq = fdtdec_get_int(gd->fdt_blob, node,
-                                           "spi-max-frequency", 0);
-               if (!ctrl->freq) {
-                       debug("%s: no slink max frequency found\n", __func__);
-                       continue;
-               }
+       priv->regs = (struct spi_regs *)plat->base;
 
-               ctrl->periph_id = clock_decode_periph_id(gd->fdt_blob, node);
-               if (ctrl->periph_id == PERIPH_ID_NONE) {
-                       debug("%s: could not decode periph id\n", __func__);
-                       continue;
-               }
-               ctrl->valid = 1;
-               found = 1;
+       priv->last_transaction_us = timer_get_us();
+       priv->freq = plat->frequency;
+       priv->periph_id = plat->periph_id;
 
-               debug("%s: found controller at %p, freq = %u, periph_id = %d\n",
-                     __func__, ctrl->regs, ctrl->freq, ctrl->periph_id);
-       }
-       return !found;
+       return 0;
 }
 
-int tegra20_spi_claim_bus(struct spi_slave *slave)
+static int tegra20_sflash_claim_bus(struct udevice *bus)
 {
-       struct tegra_spi_slave *spi = to_tegra_spi(slave);
-       struct spi_regs *regs = spi->ctrl->regs;
+       struct tegra20_sflash_priv *priv = dev_get_priv(bus);
+       struct spi_regs *regs = priv->regs;
        u32 reg;
 
        /* Change SPI clock to correct frequency, PLLP_OUT0 source */
-       clock_start_periph_pll(spi->ctrl->periph_id, CLOCK_ID_PERIPH,
-                              spi->ctrl->freq);
+       clock_start_periph_pll(priv->periph_id, CLOCK_ID_PERIPH,
+                              priv->freq);
 
        /* Clear stale status here */
        reg = SPI_STAT_RDY | SPI_STAT_RXF_FLUSH | SPI_STAT_TXF_FLUSH | \
@@ -197,8 +144,8 @@ int tegra20_spi_claim_bus(struct spi_slave *slave)
        /*
         * Use sw-controlled CS, so we can clock in data after ReadID, etc.
         */
-       reg = (spi->ctrl->mode & 1) << SPI_CMD_ACTIVE_SDA_SHIFT;
-       if (spi->ctrl->mode & 2)
+       reg = (priv->mode & 1) << SPI_CMD_ACTIVE_SDA_SHIFT;
+       if (priv->mode & 2)
                reg |= 1 << SPI_CMD_ACTIVE_SCLK_SHIFT;
        clrsetbits_le32(&regs->command, SPI_CMD_ACTIVE_SCLK_MASK |
                SPI_CMD_ACTIVE_SDA_MASK, SPI_CMD_CS_SOFT | reg);
@@ -215,37 +162,54 @@ int tegra20_spi_claim_bus(struct spi_slave *slave)
        return 0;
 }
 
-void tegra20_spi_cs_activate(struct spi_slave *slave)
+static void spi_cs_activate(struct udevice *dev)
 {
-       struct tegra_spi_slave *spi = to_tegra_spi(slave);
-       struct spi_regs *regs = spi->ctrl->regs;
+       struct udevice *bus = dev->parent;
+       struct tegra_spi_platdata *pdata = dev_get_platdata(bus);
+       struct tegra20_sflash_priv *priv = dev_get_priv(bus);
+
+       /* If it's too soon to do another transaction, wait */
+       if (pdata->deactivate_delay_us &&
+           priv->last_transaction_us) {
+               ulong delay_us;         /* The delay completed so far */
+               delay_us = timer_get_us() - priv->last_transaction_us;
+               if (delay_us < pdata->deactivate_delay_us)
+                       udelay(pdata->deactivate_delay_us - delay_us);
+       }
 
        /* CS is negated on Tegra, so drive a 1 to get a 0 */
-       setbits_le32(&regs->command, SPI_CMD_CS_VAL);
+       setbits_le32(&priv->regs->command, SPI_CMD_CS_VAL);
 }
 
-void tegra20_spi_cs_deactivate(struct spi_slave *slave)
+static void spi_cs_deactivate(struct udevice *dev)
 {
-       struct tegra_spi_slave *spi = to_tegra_spi(slave);
-       struct spi_regs *regs = spi->ctrl->regs;
+       struct udevice *bus = dev->parent;
+       struct tegra_spi_platdata *pdata = dev_get_platdata(bus);
+       struct tegra20_sflash_priv *priv = dev_get_priv(bus);
 
        /* CS is negated on Tegra, so drive a 0 to get a 1 */
-       clrbits_le32(&regs->command, SPI_CMD_CS_VAL);
+       clrbits_le32(&priv->regs->command, SPI_CMD_CS_VAL);
+
+       /* Remember time of this transaction so we can honour the bus delay */
+       if (pdata->deactivate_delay_us)
+               priv->last_transaction_us = timer_get_us();
 }
 
-int tegra20_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
-               const void *data_out, void *data_in, unsigned long flags)
+static int tegra20_sflash_xfer(struct udevice *dev, unsigned int bitlen,
+                            const void *data_out, void *data_in,
+                            unsigned long flags)
 {
-       struct tegra_spi_slave *spi = to_tegra_spi(slave);
-       struct spi_regs *regs = spi->ctrl->regs;
+       struct udevice *bus = dev->parent;
+       struct tegra20_sflash_priv *priv = dev_get_priv(bus);
+       struct spi_regs *regs = priv->regs;
        u32 reg, tmpdout, tmpdin = 0;
        const u8 *dout = data_out;
        u8 *din = data_in;
        int num_bytes;
        int ret;
 
-       debug("spi_xfer: slave %u:%u dout %08X din %08X bitlen %u\n",
-             slave->bus, slave->cs, *(u8 *)dout, *(u8 *)din, bitlen);
+       debug("%s: slave %u:%u dout %p din %p bitlen %u\n",
+             __func__, bus->seq, spi_chip_select(dev), dout, din, bitlen);
        if (bitlen % 8)
                return -1;
        num_bytes = bitlen / 8;
@@ -262,7 +226,7 @@ int tegra20_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
        debug("spi_xfer: COMMAND = %08x\n", readl(&regs->command));
 
        if (flags & SPI_XFER_BEGIN)
-               spi_cs_activate(slave);
+               spi_cs_activate(dev);
 
        /* handle data in 32-bit chunks */
        while (num_bytes > 0) {
@@ -327,7 +291,7 @@ int tegra20_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
        }
 
        if (flags & SPI_XFER_END)
-               spi_cs_deactivate(slave);
+               spi_cs_deactivate(dev);
 
        debug("spi_xfer: transfer ended. Value=%08x, status = %08x\n",
                tmpdin, readl(&regs->status));
@@ -339,3 +303,51 @@ int tegra20_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
 
        return 0;
 }
+
+static int tegra20_sflash_set_speed(struct udevice *bus, uint speed)
+{
+       struct tegra_spi_platdata *plat = bus->platdata;
+       struct tegra20_sflash_priv *priv = dev_get_priv(bus);
+
+       if (speed > plat->frequency)
+               speed = plat->frequency;
+       priv->freq = speed;
+       debug("%s: regs=%p, speed=%d\n", __func__, priv->regs, priv->freq);
+
+       return 0;
+}
+
+static int tegra20_sflash_set_mode(struct udevice *bus, uint mode)
+{
+       struct tegra20_sflash_priv *priv = dev_get_priv(bus);
+
+       priv->mode = mode;
+       debug("%s: regs=%p, mode=%d\n", __func__, priv->regs, priv->mode);
+
+       return 0;
+}
+
+static const struct dm_spi_ops tegra20_sflash_ops = {
+       .claim_bus      = tegra20_sflash_claim_bus,
+       .xfer           = tegra20_sflash_xfer,
+       .set_speed      = tegra20_sflash_set_speed,
+       .set_mode       = tegra20_sflash_set_mode,
+       .cs_info        = tegra20_sflash_cs_info,
+};
+
+static const struct udevice_id tegra20_sflash_ids[] = {
+       { .compatible = "nvidia,tegra20-sflash" },
+       { }
+};
+
+U_BOOT_DRIVER(tegra20_sflash) = {
+       .name   = "tegra20_sflash",
+       .id     = UCLASS_SPI,
+       .of_match = tegra20_sflash_ids,
+       .ops    = &tegra20_sflash_ops,
+       .ofdata_to_platdata = tegra20_sflash_ofdata_to_platdata,
+       .platdata_auto_alloc_size = sizeof(struct tegra_spi_platdata),
+       .priv_auto_alloc_size = sizeof(struct tegra20_sflash_priv),
+       .per_child_auto_alloc_size      = sizeof(struct spi_slave),
+       .probe  = tegra20_sflash_probe,
+};
index 664de6e916613f4571fadb9fbd46497a32131fce..213fa5f7939a848889e0168d1991040dd9830a61 100644 (file)
  */
 
 #include <common.h>
-#include <malloc.h>
+#include <dm.h>
 #include <asm/io.h>
-#include <asm/gpio.h>
 #include <asm/arch/clock.h>
 #include <asm/arch-tegra/clk_rst.h>
-#include <asm/arch-tegra20/tegra20_slink.h>
 #include <spi.h>
 #include <fdtdec.h>
+#include "tegra_spi.h"
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -87,130 +86,70 @@ struct spi_regs {
        u32 rx_fifo;    /* SLINK_RX_FIFO_0 reg off 180h */
 };
 
-struct tegra_spi_ctrl {
+struct tegra30_spi_priv {
        struct spi_regs *regs;
        unsigned int freq;
        unsigned int mode;
        int periph_id;
        int valid;
+       int last_transaction_us;
 };
 
 struct tegra_spi_slave {
        struct spi_slave slave;
-       struct tegra_spi_ctrl *ctrl;
+       struct tegra30_spi_priv *ctrl;
 };
 
-static struct tegra_spi_ctrl spi_ctrls[CONFIG_TEGRA_SLINK_CTRLS];
-
-static inline struct tegra_spi_slave *to_tegra_spi(struct spi_slave *slave)
-{
-       return container_of(slave, struct tegra_spi_slave, slave);
-}
-
-int tegra30_spi_cs_is_valid(unsigned int bus, unsigned int cs)
+static int tegra30_spi_ofdata_to_platdata(struct udevice *bus)
 {
-       if (bus >= CONFIG_TEGRA_SLINK_CTRLS || cs > 3 || !spi_ctrls[bus].valid)
-               return 0;
-       else
-               return 1;
-}
+       struct tegra_spi_platdata *plat = bus->platdata;
+       const void *blob = gd->fdt_blob;
+       int node = bus->of_offset;
 
-struct spi_slave *tegra30_spi_setup_slave(unsigned int bus, unsigned int cs,
-               unsigned int max_hz, unsigned int mode)
-{
-       struct tegra_spi_slave *spi;
+       plat->base = fdtdec_get_addr(blob, node, "reg");
+       plat->periph_id = clock_decode_periph_id(blob, node);
 
-       debug("%s: bus: %u, cs: %u, max_hz: %u, mode: %u\n", __func__,
-               bus, cs, max_hz, mode);
-
-       if (!spi_cs_is_valid(bus, cs)) {
-               printf("SPI error: unsupported bus %d / chip select %d\n",
-                      bus, cs);
-               return NULL;
-       }
-
-       if (max_hz > TEGRA_SPI_MAX_FREQ) {
-               printf("SPI error: unsupported frequency %d Hz. Max frequency"
-                       " is %d Hz\n", max_hz, TEGRA_SPI_MAX_FREQ);
-               return NULL;
+       if (plat->periph_id == PERIPH_ID_NONE) {
+               debug("%s: could not decode periph id %d\n", __func__,
+                     plat->periph_id);
+               return -FDT_ERR_NOTFOUND;
        }
 
-       spi = spi_alloc_slave(struct tegra_spi_slave, bus, cs);
-       if (!spi) {
-               printf("SPI error: malloc of SPI structure failed\n");
-               return NULL;
-       }
-       spi->ctrl = &spi_ctrls[bus];
-       if (!spi->ctrl) {
-               printf("SPI error: could not find controller for bus %d\n",
-                      bus);
-               return NULL;
-       }
+       /* Use 500KHz as a suitable default */
+       plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency",
+                                       500000);
+       plat->deactivate_delay_us = fdtdec_get_int(blob, node,
+                                       "spi-deactivate-delay", 0);
+       debug("%s: base=%#08lx, periph_id=%d, max-frequency=%d, deactivate_delay=%d\n",
+             __func__, plat->base, plat->periph_id, plat->frequency,
+             plat->deactivate_delay_us);
 
-       if (max_hz < spi->ctrl->freq) {
-               debug("%s: limiting frequency from %u to %u\n", __func__,
-                     spi->ctrl->freq, max_hz);
-               spi->ctrl->freq = max_hz;
-       }
-       spi->ctrl->mode = mode;
-
-       return &spi->slave;
+       return 0;
 }
 
-void tegra30_spi_free_slave(struct spi_slave *slave)
+static int tegra30_spi_probe(struct udevice *bus)
 {
-       struct tegra_spi_slave *spi = to_tegra_spi(slave);
-
-       free(spi);
-}
+       struct tegra_spi_platdata *plat = dev_get_platdata(bus);
+       struct tegra30_spi_priv *priv = dev_get_priv(bus);
 
-int tegra30_spi_init(int *node_list, int count)
-{
-       struct tegra_spi_ctrl *ctrl;
-       int i;
-       int node = 0;
-       int found = 0;
-
-       for (i = 0; i < count; i++) {
-               ctrl = &spi_ctrls[i];
-               node = node_list[i];
-
-               ctrl->regs = (struct spi_regs *)fdtdec_get_addr(gd->fdt_blob,
-                                                               node, "reg");
-               if ((fdt_addr_t)ctrl->regs == FDT_ADDR_T_NONE) {
-                       debug("%s: no slink register found\n", __func__);
-                       continue;
-               }
-               ctrl->freq = fdtdec_get_int(gd->fdt_blob, node,
-                                           "spi-max-frequency", 0);
-               if (!ctrl->freq) {
-                       debug("%s: no slink max frequency found\n", __func__);
-                       continue;
-               }
+       priv->regs = (struct spi_regs *)plat->base;
 
-               ctrl->periph_id = clock_decode_periph_id(gd->fdt_blob, node);
-               if (ctrl->periph_id == PERIPH_ID_NONE) {
-                       debug("%s: could not decode periph id\n", __func__);
-                       continue;
-               }
-               ctrl->valid = 1;
-               found = 1;
+       priv->last_transaction_us = timer_get_us();
+       priv->freq = plat->frequency;
+       priv->periph_id = plat->periph_id;
 
-               debug("%s: found controller at %p, freq = %u, periph_id = %d\n",
-                     __func__, ctrl->regs, ctrl->freq, ctrl->periph_id);
-       }
-       return !found;
+       return 0;
 }
 
-int tegra30_spi_claim_bus(struct spi_slave *slave)
+static int tegra30_spi_claim_bus(struct udevice *bus)
 {
-       struct tegra_spi_slave *spi = to_tegra_spi(slave);
-       struct spi_regs *regs = spi->ctrl->regs;
+       struct tegra30_spi_priv *priv = dev_get_priv(bus);
+       struct spi_regs *regs = priv->regs;
        u32 reg;
 
        /* Change SPI clock to correct frequency, PLLP_OUT0 source */
-       clock_start_periph_pll(spi->ctrl->periph_id, CLOCK_ID_PERIPH,
-                              spi->ctrl->freq);
+       clock_start_periph_pll(priv->periph_id, CLOCK_ID_PERIPH,
+                              priv->freq);
 
        /* Clear stale status here */
        reg = SLINK_STAT_RDY | SLINK_STAT_RXF_FLUSH | SLINK_STAT_TXF_FLUSH | \
@@ -227,29 +166,46 @@ int tegra30_spi_claim_bus(struct spi_slave *slave)
        return 0;
 }
 
-void tegra30_spi_cs_activate(struct spi_slave *slave)
+static void spi_cs_activate(struct udevice *dev)
 {
-       struct tegra_spi_slave *spi = to_tegra_spi(slave);
-       struct spi_regs *regs = spi->ctrl->regs;
+       struct udevice *bus = dev->parent;
+       struct tegra_spi_platdata *pdata = dev_get_platdata(bus);
+       struct tegra30_spi_priv *priv = dev_get_priv(bus);
+
+       /* If it's too soon to do another transaction, wait */
+       if (pdata->deactivate_delay_us &&
+           priv->last_transaction_us) {
+               ulong delay_us;         /* The delay completed so far */
+               delay_us = timer_get_us() - priv->last_transaction_us;
+               if (delay_us < pdata->deactivate_delay_us)
+                       udelay(pdata->deactivate_delay_us - delay_us);
+       }
 
        /* CS is negated on Tegra, so drive a 1 to get a 0 */
-       setbits_le32(&regs->command, SLINK_CMD_CS_VAL);
+       setbits_le32(&priv->regs->command, SLINK_CMD_CS_VAL);
 }
 
-void tegra30_spi_cs_deactivate(struct spi_slave *slave)
+static void spi_cs_deactivate(struct udevice *dev)
 {
-       struct tegra_spi_slave *spi = to_tegra_spi(slave);
-       struct spi_regs *regs = spi->ctrl->regs;
+       struct udevice *bus = dev->parent;
+       struct tegra_spi_platdata *pdata = dev_get_platdata(bus);
+       struct tegra30_spi_priv *priv = dev_get_priv(bus);
 
        /* CS is negated on Tegra, so drive a 0 to get a 1 */
-       clrbits_le32(&regs->command, SLINK_CMD_CS_VAL);
+       clrbits_le32(&priv->regs->command, SLINK_CMD_CS_VAL);
+
+       /* Remember time of this transaction so we can honour the bus delay */
+       if (pdata->deactivate_delay_us)
+               priv->last_transaction_us = timer_get_us();
 }
 
-int tegra30_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
-               const void *data_out, void *data_in, unsigned long flags)
+static int tegra30_spi_xfer(struct udevice *dev, unsigned int bitlen,
+                           const void *data_out, void *data_in,
+                           unsigned long flags)
 {
-       struct tegra_spi_slave *spi = to_tegra_spi(slave);
-       struct spi_regs *regs = spi->ctrl->regs;
+       struct udevice *bus = dev->parent;
+       struct tegra30_spi_priv *priv = dev_get_priv(bus);
+       struct spi_regs *regs = priv->regs;
        u32 reg, tmpdout, tmpdin = 0;
        const u8 *dout = data_out;
        u8 *din = data_in;
@@ -257,7 +213,7 @@ int tegra30_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
        int ret;
 
        debug("%s: slave %u:%u dout %p din %p bitlen %u\n",
-             __func__, slave->bus, slave->cs, dout, din, bitlen);
+             __func__, bus->seq, spi_chip_select(dev), dout, din, bitlen);
        if (bitlen % 8)
                return -1;
        num_bytes = bitlen / 8;
@@ -276,11 +232,11 @@ int tegra30_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
 
        clrsetbits_le32(&regs->command2, SLINK_CMD2_SS_EN_MASK,
                        SLINK_CMD2_TXEN | SLINK_CMD2_RXEN |
-                       (slave->cs << SLINK_CMD2_SS_EN_SHIFT));
+                       (spi_chip_select(dev) << SLINK_CMD2_SS_EN_SHIFT));
        debug("%s entry: COMMAND2 = %08x\n", __func__, readl(&regs->command2));
 
        if (flags & SPI_XFER_BEGIN)
-               spi_cs_activate(slave);
+               spi_cs_activate(dev);
 
        /* handle data in 32-bit chunks */
        while (num_bytes > 0) {
@@ -344,7 +300,7 @@ int tegra30_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
        }
 
        if (flags & SPI_XFER_END)
-               spi_cs_deactivate(slave);
+               spi_cs_deactivate(dev);
 
        debug("%s: transfer ended. Value=%08x, status = %08x\n",
              __func__, tmpdin, readl(&regs->status));
@@ -357,3 +313,54 @@ int tegra30_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
 
        return 0;
 }
+
+static int tegra30_spi_set_speed(struct udevice *bus, uint speed)
+{
+       struct tegra_spi_platdata *plat = bus->platdata;
+       struct tegra30_spi_priv *priv = dev_get_priv(bus);
+
+       if (speed > plat->frequency)
+               speed = plat->frequency;
+       priv->freq = speed;
+       debug("%s: regs=%p, speed=%d\n", __func__, priv->regs, priv->freq);
+
+       return 0;
+}
+
+static int tegra30_spi_set_mode(struct udevice *bus, uint mode)
+{
+       struct tegra30_spi_priv *priv = dev_get_priv(bus);
+
+       priv->mode = mode;
+       debug("%s: regs=%p, mode=%d\n", __func__, priv->regs, priv->mode);
+
+       return 0;
+}
+
+static const struct dm_spi_ops tegra30_spi_ops = {
+       .claim_bus      = tegra30_spi_claim_bus,
+       .xfer           = tegra30_spi_xfer,
+       .set_speed      = tegra30_spi_set_speed,
+       .set_mode       = tegra30_spi_set_mode,
+       /*
+        * cs_info is not needed, since we require all chip selects to be
+        * in the device tree explicitly
+        */
+};
+
+static const struct udevice_id tegra30_spi_ids[] = {
+       { .compatible = "nvidia,tegra20-slink" },
+       { }
+};
+
+U_BOOT_DRIVER(tegra30_spi) = {
+       .name   = "tegra20_slink",
+       .id     = UCLASS_SPI,
+       .of_match = tegra30_spi_ids,
+       .ops    = &tegra30_spi_ops,
+       .ofdata_to_platdata = tegra30_spi_ofdata_to_platdata,
+       .platdata_auto_alloc_size = sizeof(struct tegra_spi_platdata),
+       .priv_auto_alloc_size = sizeof(struct tegra30_spi_priv),
+       .per_child_auto_alloc_size      = sizeof(struct spi_slave),
+       .probe  = tegra30_spi_probe,
+};
diff --git a/drivers/spi/tegra_spi.h b/drivers/spi/tegra_spi.h
new file mode 100644 (file)
index 0000000..fb2b50f
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+ * (C) Copyright 2014 Google, Inc
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+struct tegra_spi_platdata {
+       enum periph_id periph_id;
+       int frequency;          /* Default clock frequency, -1 for none */
+       ulong base;
+       uint deactivate_delay_us;       /* Delay to wait after deactivate */
+};
index 87bf906b263e09a8a25527f7238cbb6352de953d..df13ab2f63eddbb075d5d2cc2bdffacccd88e68b 100644 (file)
@@ -159,6 +159,9 @@ enum bootstage_id {
        /* Next 10 IDs used by BOOTSTAGE_SUB_... */
        BOOTSTAGE_ID_FIT_RD_START = 120,        /* Ramdisk stages */
 
+       /* Next 10 IDs used by BOOTSTAGE_SUB_... */
+       BOOTSTAGE_ID_FIT_SETUP_START = 130,     /* x86 setup stages */
+
        BOOTSTAGE_ID_IDE_FIT_READ = 140,
        BOOTSTAGE_ID_IDE_FIT_READ_OK,
 
index 7cf241e31d7725b826671d8f70c0b4df3ac119ef..a20c3733212ca39d2dc9509a63b703746aad5c0a 100644 (file)
 #define CONFIG_MACH_TYPE               4273
 #define CONFIG_SYS_HZ                  1000
 
+#ifndef CONFIG_SPL_BUILD
+#define CONFIG_DM
+#define CONFIG_CMD_DM
+
+#define CONFIG_DM_GPIO
+#define CONFIG_CMD_GPIO
+
+#define CONFIG_DM_SERIAL
+#define CONFIG_SYS_MALLOC_F_LEN                (1 << 10)
+#endif
+
 /* Display information on boot */
 #define CONFIG_DISPLAY_CPUINFO
 #define CONFIG_DISPLAY_BOARDINFO
index 371f32d84095bb803422a7f22428ed8c373b7b2d..6ba9bb7a1b15252fe56049ee1af3833609dee66e 100644 (file)
 #include <linux/sizes.h>
 
 #define CONFIG_SYS_GENERIC_BOARD
+#define CONFIG_DM
+#define CONFIG_CMD_DM
+#define CONFIG_DM_GPIO
+#define CONFIG_DM_SERIAL
+#define CONFIG_DM_SPI
+#define CONFIG_DM_SPI_FLASH
+
 #define CONFIG_ARCH_CPU_INIT
 #define CONFIG_DISPLAY_CPUINFO
 #define CONFIG_DISPLAY_BOARDINFO
index ab8ac60df23042084726d1bc53bcd0c07fa14fb2..91bd37d6bca60fb9dfa9bc88ff61da2fad4bf8df 100644 (file)
@@ -38,6 +38,7 @@
 
 #define CONFIG_POWER_TPS65090_EC
 #define CONFIG_CROS_EC_SPI             /* Support CROS_EC over SPI */
+#define CONFIG_DM_CROS_EC
 
 #define CONFIG_USB_XHCI
 #define CONFIG_USB_XHCI_EXYNOS
index 2d698094800f2c7bbc50d6f7b8ef63e27b5b7742..d9475e950b798188244e15269348c1a79ec5c687 100644 (file)
  */
 #define CONFIG_MACH_TYPE               MACH_TYPE_BCM2708
 
+/* Enable driver model */
+#define CONFIG_DM
+#define CONFIG_CMD_DM
+#define CONFIG_DM_GPIO
+
 /* Memory layout */
 #define CONFIG_NR_DRAM_BANKS           1
 #define CONFIG_SYS_SDRAM_BASE          0x00000000
index 0c6e9c7878477048b4e4e69bb9f3510f33f72563..3633a355bd7f83b04bb65a30b731029376b5bff9 100644 (file)
 #define CONFIG_SYS_I2C_SOFT_SPEED      50000
 #define CONFIG_SYS_I2C_SOFT_SLAVE      0x7F
 #define CONFIG_I2C_MULTI_BUS
+#define CONFIG_SYS_I2C_INIT_BOARD
+
 #define CONFIG_SYS_MAX_I2C_BUS 7
 #define CONFIG_USB_GADGET
 #define CONFIG_USB_GADGET_S3C_UDC_OTG
 
 #define CONFIG_OF_LIBFDT
 
+#define CONFIG_SYS_GENERIC_BOARD
+#define CONFIG_DM
+#define CONFIG_CMD_DM
+#define CONFIG_DM_GPIO
+#define CONFIG_DM_SERIAL
+
 #endif /* __CONFIG_H */
index 27f3d0af47105668009a9dd78677c4c2b06eb79e..4b30d148c31d4882aee8c544f2d724ca67130245 100644 (file)
  * SPI Settings
  */
 #define CONFIG_SOFT_SPI
-#define CONFIG_SOFT_SPI_MODE SPI_MODE_3
-#define CONFIG_SOFT_SPI_GPIO_SCLK EXYNOS4_GPIO_Y31
-#define CONFIG_SOFT_SPI_GPIO_MOSI EXYNOS4_GPIO_Y33
-#define CONFIG_SOFT_SPI_GPIO_MISO EXYNOS4_GPIO_Y30
-#define CONFIG_SOFT_SPI_GPIO_CS EXYNOS4_GPIO_Y43
-
-#define SPI_DELAY udelay(1)
-#undef SPI_INIT
-#define SPI_SCL(bit) universal_spi_scl(bit)
-#define SPI_SDA(bit) universal_spi_sda(bit)
-#define SPI_READ universal_spi_read()
+
 #ifndef        __ASSEMBLY__
 void universal_spi_scl(int bit);
 void universal_spi_sda(int bit);
index b5064ab37c05f2c807bb9106ec667bb0c3293501..2dee315f91e761449314c6385881a6b6fe09739f 100644 (file)
 #define I2C_MOSI       0x00004000      /* PD 17: Master Out, Slave In */
 #define I2C_MISO       0x00008000      /* PD 16: Master In, Slave Out */
 
-#undef  SPI_INIT                       /* no port initialization needed */
 #define SPI_READ        ((immr->im_ioport.iop_pdatd & I2C_MISO) != 0)
 #define SPI_SDA(bit)    do {                                           \
                        if(bit) immr->im_ioport.iop_pdatd |=  I2C_MOSI; \
index 022629f522e1630df0a1d4fc954bd24ff639e559..ee4b24473cd27b37f803f10a4b3efccd0a000d8c 100644 (file)
@@ -32,6 +32,7 @@
 #define CONFIG_DM_GPIO
 #define CONFIG_DM_TEST
 #define CONFIG_DM_SERIAL
+#define CONFIG_DM_CROS_EC
 
 #define CONFIG_SYS_STDIO_DEREGISTER
 
@@ -97,8 +98,8 @@
 #define CONFIG_CMD_SF_TEST
 #define CONFIG_CMD_SPI
 #define CONFIG_SPI_FLASH
-#define CONFIG_OF_SPI
-#define CONFIG_OF_SPI_FLASH
+#define CONFIG_DM_SPI
+#define CONFIG_DM_SPI_FLASH
 #define CONFIG_SPI_FLASH_ATMEL
 #define CONFIG_SPI_FLASH_EON
 #define CONFIG_SPI_FLASH_GIGADEVICE
index 22835ffd6403a795cb04e1bfa6390bb9c206cf5a..982d0dcea397737fa5aca1dc1b167c213c163858 100644 (file)
 
 #define CONFIG_OF_LIBFDT
 
+#define CONFIG_SYS_GENERIC_BOARD
+#define CONFIG_DM
+#define CONFIG_CMD_DM
+#define CONFIG_DM_GPIO
+#define CONFIG_DM_SERIAL
+
 #endif /* __CONFIG_H */
index 23e3c8af31a8a758b6027d1810f0adce4b8f558a..a258699af7ec5fb089c78daf52496a6c919f983f 100644 (file)
@@ -59,7 +59,7 @@
        BOARD_EXTRA_ENV_SETTINGS
 
 #if defined(CONFIG_TEGRA20_SFLASH) || defined(CONFIG_TEGRA20_SLINK) || defined(CONFIG_TEGRA114_SPI)
-#define CONFIG_FDT_SPI
+#define CONFIG_TEGRA_SPI
 #endif
 
 /* overrides for SPL build here */
index 834b3d5686c159b019b5c4661bfa943e0dc45957..4719ee10aeeca8810c25bad2392e2dff6875f422 100644 (file)
@@ -24,6 +24,8 @@
 #ifndef CONFIG_SPL_BUILD
 #define CONFIG_DM_SERIAL
 #endif
+#define CONFIG_DM_SPI
+#define CONFIG_DM_SPI_FLASH
 
 #define CONFIG_SYS_TIMER_RATE          1000000
 #define CONFIG_SYS_TIMER_COUNTER       NV_PA_TMRUS_BASE
index 41a7c99edcfd64094d871529c7856c3adf32fcd4..fe331bc0825989a7c612a01b2fcbe20b81bdaff5 100644 (file)
@@ -99,7 +99,6 @@
 #define        CONFIG_VIDEO_BMP_GZIP
 #define        CONFIG_VIDEO_BMP_RLE8
 #define        CONFIG_SYS_VIDEO_LOGO_MAX_SIZE  (2 << 20)
-#undef SPI_INIT
 
 #define        SPI_DELAY       udelay(10)
 #define        SPI_SDA(val)    zipitz2_spi_sda(val)
index 1e4d8db96b7889e32586c665e001513523357b48..9e13146ecbb266a5b73dbb9b93b1e90317c79a06 100644 (file)
@@ -14,6 +14,7 @@
 #include <fdtdec.h>
 #include <cros_ec_message.h>
 
+#ifndef CONFIG_DM_CROS_EC
 /* Which interface is the device on? */
 enum cros_ec_interface_t {
        CROS_EC_IF_NONE,
@@ -22,9 +23,13 @@ enum cros_ec_interface_t {
        CROS_EC_IF_LPC, /* Intel Low Pin Count interface */
        CROS_EC_IF_SANDBOX,
 };
+#endif
 
 /* Our configuration information */
 struct cros_ec_dev {
+#ifdef CONFIG_DM_CROS_EC
+       struct udevice *dev;            /* Transport device */
+#else
        enum cros_ec_interface_t interface;
        struct spi_slave *spi;          /* Our SPI slave, if using SPI */
        int node;                       /* Our node */
@@ -33,6 +38,7 @@ struct cros_ec_dev {
        unsigned int addr;              /* Device address (for I2C) */
        unsigned int bus_num;           /* Bus number (for I2C) */
        unsigned int max_frequency;     /* Maximum interface frequency */
+#endif
        struct fdt_gpio_state ec_int;   /* GPIO used as EC interrupt line */
        int protocol_version;           /* Protocol version to use */
        int optimise_flash_write;       /* Don't write erased flash blocks */
@@ -233,6 +239,22 @@ int cros_ec_flash_update_rw(struct cros_ec_dev *dev,
  */
 struct cros_ec_dev *board_get_cros_ec_dev(void);
 
+#ifdef CONFIG_DM_CROS_EC
+
+struct dm_cros_ec_ops {
+       int (*check_version)(struct udevice *dev);
+       int (*command)(struct udevice *dev, uint8_t cmd, int cmd_version,
+                      const uint8_t *dout, int dout_len,
+                      uint8_t **dinp, int din_len);
+       int (*packet)(struct udevice *dev, int out_bytes, int in_bytes);
+};
+
+#define dm_cros_ec_get_ops(dev) \
+               ((struct dm_cros_ec_ops *)(dev)->driver->ops)
+
+int cros_ec_register(struct udevice *dev);
+
+#else /* !CONFIG_DM_CROS_EC */
 
 /* Internal interfaces */
 int cros_ec_i2c_init(struct cros_ec_dev *dev, const void *blob);
@@ -336,6 +358,7 @@ int cros_ec_spi_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
 int cros_ec_spi_packet(struct cros_ec_dev *dev, int out_bytes, int in_bytes);
 int cros_ec_sandbox_packet(struct cros_ec_dev *dev, int out_bytes,
                           int in_bytes);
+#endif
 
 /**
  * Dump a block of data for a command.
@@ -489,9 +512,11 @@ int cros_ec_get_error(void);
  * Returns information from the FDT about the Chrome EC flash
  *
  * @param blob         FDT blob to use
+ * @param node         Node offset to read from
  * @param config       Structure to use to return information
  */
-int cros_ec_decode_ec_flash(const void *blob, struct fdt_cros_ec *config);
+int cros_ec_decode_ec_flash(const void *blob, int node,
+                           struct fdt_cros_ec *config);
 
 /**
  * Check the current keyboard state, in case recovery mode is requested.
index 7005d03d08f5d96adcd3f28c2a11f7f9e318ec44..44cb7ef93bfdeea682ea0602d33bf9615260ad9d 100644 (file)
@@ -65,6 +65,19 @@ int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
  */
 int device_probe(struct udevice *dev);
 
+/**
+ * device_probe() - Probe a child device, activating it
+ *
+ * Activate a device so that it is ready for use. All its parents are probed
+ * first. The child is provided with parent data if parent_priv is not NULL.
+ *
+ * @dev: Pointer to device to probe
+ * @parent_priv: Pointer to parent data. If non-NULL then this is provided to
+ * the child.
+ * @return 0 if OK, -ve on error
+ */
+int device_probe_child(struct udevice *dev, void *parent_priv);
+
 /**
  * device_remove() - Remove a device, de-activating it
  *
index c8a4072bcf7d60d2fb6cdaa24cc7fbb77946a76a..9ce95a834e75ee54d6d7edefb21ee0f848f97e0f 100644 (file)
@@ -57,7 +57,8 @@ struct driver_info;
  * @sibling_node: Next device in list of all devices
  * @flags: Flags for this device DM_FLAG_...
  * @req_seq: Requested sequence number for this device (-1 = any)
- * @seq: Allocated sequence number for this device (-1 = none)
+ * @seq: Allocated sequence number for this device (-1 = none). This is set up
+ * when the device is probed and will be unique within the device's uclass.
  */
 struct udevice {
        struct driver *driver;
@@ -96,6 +97,12 @@ struct udevice_id {
        ulong data;
 };
 
+#ifdef CONFIG_OF_CONTROL
+#define of_match_ptr(_ptr)     (_ptr)
+#else
+#define of_match_ptr(_ptr)     NULL
+#endif /* CONFIG_OF_CONTROL */
+
 /**
  * struct driver - A driver for a feature or peripheral
  *
@@ -133,6 +140,10 @@ struct udevice_id {
  * @per_child_auto_alloc_size: Each device can hold private data owned by
  * its parent. If required this will be automatically allocated if this
  * value is non-zero.
+ * TODO(sjg@chromium.org): I'm considering dropping this, and just having
+ * device_probe_child() pass it in. So far the use case for allocating it
+ * is SPI, but I found that unsatisfactory. Since it is here I will leave it
+ * until things are clearer.
  * @ops: Driver-specific operations. This is typically a list of function
  * pointers defined by the driver, to implement driver functions required by
  * the uclass.
@@ -274,4 +285,22 @@ int device_find_child_by_of_offset(struct udevice *parent, int of_offset,
 int device_get_child_by_of_offset(struct udevice *parent, int seq,
                                  struct udevice **devp);
 
+/**
+ * device_find_first_child() - Find the first child of a device
+ *
+ * @parent: Parent device to search
+ * @devp: Returns first child device, or NULL if none
+ * @return 0
+ */
+int device_find_first_child(struct udevice *parent, struct udevice **devp);
+
+/**
+ * device_find_first_child() - Find the first child of a device
+ *
+ * @devp: Pointer to previous child device on entry. Returns pointer to next
+ *             child device, or NULL if none
+ * @return 0
+ */
+int device_find_next_child(struct udevice **devp);
+
 #endif
index 23568952467e6d5b685d84e2664561f5ca9ea942..704e33e37fb9dadc739f71312e15f79c4f9bb651 100644 (file)
@@ -38,7 +38,7 @@ struct uclass_driver *lists_uclass_lookup(enum uclass_id id);
  * This searches the U_BOOT_DEVICE() structures and creates new devices for
  * each one. The devices will have @parent as their parent.
  *
- * @parent: parent driver (root)
+ * @parent: parent device (root)
  * @early_only: If true, bind only drivers with the DM_INIT_F flag. If false
  * bind all drivers.
  */
@@ -50,7 +50,7 @@ int lists_bind_drivers(struct udevice *parent, bool pre_reloc_only);
  * This creates a new device bound to the given device tree node, with
  * @parent as its parent.
  *
- * @parent: parent driver (root)
+ * @parent: parent device (root)
  * @blob: device tree blob
  * @offset: offset of this device tree node
  * @devp: if non-NULL, returns a pointer to the bound device
index 2bc8b147edfed01f152c1ca5e310ba8248637534..fbc8a6b3adda18424bd485a0ea39df981143f55e 100644 (file)
 #ifndef _DM_PLATDATA_H
 #define _DM_PLATDATA_H
 
+#include <linker_lists.h>
+
 /**
  * struct driver_info - Information required to instantiate a device
  *
- * @name:      Device name
+ * @name:      Driver name
  * @platdata:  Driver-specific platform data
  */
 struct driver_info {
@@ -25,4 +27,8 @@ struct driver_info {
 #define U_BOOT_DEVICE(__name)                                          \
        ll_entry_declare(struct driver_info, __name, driver_info)
 
+/* Declare a list of devices. The argument is a driver_info[] array */
+#define U_BOOT_DEVICES(__name)                                         \
+       ll_entry_declare_list(struct driver_info, __name, driver_info)
+
 #endif
index 7f0e37b7b789cd64b48a124a0726dc4efbbe2fe4..a8944c97d03a9cfc9162a8c6289b21515862386b 100644 (file)
@@ -18,10 +18,16 @@ enum uclass_id {
        UCLASS_TEST,
        UCLASS_TEST_FDT,
        UCLASS_TEST_BUS,
+       UCLASS_SPI_EMUL,        /* sandbox SPI device emulator */
+       UCLASS_SIMPLE_BUS,
 
        /* U-Boot uclasses start here */
        UCLASS_GPIO,            /* Bank of general-purpose I/O pins */
        UCLASS_SERIAL,          /* Serial UART */
+       UCLASS_SPI,             /* SPI bus */
+       UCLASS_SPI_GENERIC,     /* Generic SPI flash target */
+       UCLASS_SPI_FLASH,       /* SPI flash */
+       UCLASS_CROS_EC, /* Chrome OS EC */
 
        UCLASS_COUNT,
        UCLASS_INVALID = -1,
index 8d09ecff7b4e0c0c4590792391303f0eeea7f2f6..f6ec6d7e9f62f7551b869f1eb7b188e8587b44ee 100644 (file)
@@ -11,6 +11,7 @@
 #define _DM_UCLASS_H
 
 #include <dm/uclass-id.h>
+#include <linker_lists.h>
 #include <linux/list.h>
 
 /**
index 8be64a921dd75aaf835de4c1b87296ebcc2bd327..6ac3a38ef008b686221a5e213e67f5e503233846 100644 (file)
@@ -5,6 +5,7 @@
  */
 
 #ifndef __DM_UTIL_H
+#define __DM_UTIL_H
 
 void dm_warn(const char *fmt, ...);
 
index 4347532520b7c700a9e4395dd22b7df7ffbe5e1c..a13a30289f691819c849834a1584c77a438fdc1a 100644 (file)
@@ -233,6 +233,7 @@ struct lmb;
 #define IH_TYPE_GPIMAGE                17      /* TI Keystone GPHeader Image   */
 #define IH_TYPE_ATMELIMAGE     18      /* ATMEL ROM bootable Image     */
 #define IH_TYPE_SOCFPGAIMAGE   19      /* Altera SOCFPGA Preloader     */
+#define IH_TYPE_X86_SETUP      20      /* x86 setup.bin Image          */
 
 /*
  * Compression Types
@@ -273,6 +274,7 @@ typedef struct image_info {
        ulong           image_start, image_len; /* start of image within blob, len of image */
        ulong           load;                   /* load addr for the image */
        uint8_t         comp, type, os;         /* compression, type of image, os type */
+       uint8_t         arch;                   /* CPU architecture */
 } image_info_t;
 
 /*
@@ -303,6 +305,10 @@ typedef struct bootm_headers {
        void            *fit_hdr_fdt;   /* FDT blob FIT image header */
        const char      *fit_uname_fdt; /* FDT blob subimage node unit name */
        int             fit_noffset_fdt;/* FDT blob subimage node offset */
+
+       void            *fit_hdr_setup; /* x86 setup FIT image header */
+       const char      *fit_uname_setup; /* x86 setup subimage node name */
+       int             fit_noffset_setup;/* x86 setup subimage node offset */
 #endif
 
 #ifndef USE_HOSTCC
@@ -417,6 +423,9 @@ enum fit_load_op {
        FIT_LOAD_REQUIRED,      /* Must be provided */
 };
 
+int boot_get_setup(bootm_headers_t *images, uint8_t arch, ulong *setup_start,
+                  ulong *setup_len);
+
 #ifndef USE_HOSTCC
 /* Image format types, returned by _get_format() routine */
 #define IMAGE_FORMAT_INVALID   0x00
@@ -438,6 +447,9 @@ int boot_get_ramdisk(int argc, char * const argv[], bootm_headers_t *images,
                uint8_t arch, ulong *rd_start, ulong *rd_end);
 #endif
 
+int boot_get_setup_fit(bootm_headers_t *images, uint8_t arch,
+                      ulong *setup_start, ulong *setup_len);
+
 /**
  * fit_image_load() - load an image from a FIT
  *
@@ -721,6 +733,7 @@ int bootz_setup(ulong image, ulong *start, ulong *end);
 #define FIT_RAMDISK_PROP       "ramdisk"
 #define FIT_FDT_PROP           "fdt"
 #define FIT_DEFAULT_PROP       "default"
+#define FIT_SETUP_PROP         "setup"
 
 #define FIT_MAX_HASH_LEN       HASH_MAX_DIGEST_SIZE
 
index 507d61ba9a5c0d54d60f54f966391a8a7ef6eae2..d37fba44dcafc6b1ce6813cca4e8f3d6999e95d5 100644 (file)
@@ -11,6 +11,8 @@
 #ifndef __LINKER_LISTS_H__
 #define __LINKER_LISTS_H__
 
+#include <linux/compiler.h>
+
 /*
  * There is no use in including this from ASM files, but that happens
  * anyway, e.g. PPC kgdb.S includes command.h which incluse us.
                        __attribute__((unused,                          \
                        section(".u_boot_list_2_"#_list"_2_"#_name)))
 
+/**
+ * ll_entry_declare_list() - Declare a list of link-generated array entries
+ * @_type:     Data type of each entry
+ * @_name:     Name of the entry
+ * @_list:     name of the list. Should contain only characters allowed
+ *             in a C variable name!
+ *
+ * This is like ll_entry_declare() but creates multiple entries. It should
+ * be assigned to an array.
+ *
+ * ll_entry_declare_list(struct my_sub_cmd, my_sub_cmd, cmd_sub, cmd.sub) = {
+ *     { .x = 3, .y = 4 },
+ *     { .x = 8, .y = 2 },
+ *     { .x = 1, .y = 7 }
+ * };
+ */
+#define ll_entry_declare_list(_type, _name, _list)                     \
+       _type _u_boot_list_2_##_list##_2_##_name[] __aligned(4)         \
+                       __attribute__((unused,                          \
+                       section(".u_boot_list_2_"#_list"_2_"#_name)))
+
 /**
  * We need a 0-byte-size type for iterator symbols, and the compiler
  * does not allow defining objects of C type 'void'. Using an empty
diff --git a/include/serial_mxc.h b/include/serial_mxc.h
new file mode 100644 (file)
index 0000000..7d3ace2
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __serial_mxc_h
+#define __serial_mxc_h
+
+/* Information about a serial port */
+struct mxc_serial_platdata {
+       struct mxc_uart *reg;  /* address of registers in physical memory */
+};
+
+#endif
diff --git a/include/serial_pl01x.h b/include/serial_pl01x.h
new file mode 100644 (file)
index 0000000..5e068f3
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __serial_pl01x_h
+#define __serial_pl01x_h
+
+enum pl01x_type {
+       TYPE_PL010,
+       TYPE_PL011,
+};
+
+/*
+ *Information about a serial port
+ *
+ * @base: Register base address
+ * @type: Port type
+ * @clock: Input clock rate, used for calculating the baud rate divisor
+ */
+struct pl01x_serial_platdata {
+       unsigned long base;
+       enum pl01x_type type;
+       unsigned int clock;
+};
+
+#endif
index b673be270c8077b1d9eb73824b3fe0527d76b921..aa0a48ea62710dd019c77c75cc5350a9f61fb14d 100644 (file)
 
 #define SPI_DEFAULT_WORDLEN 8
 
+#ifdef CONFIG_DM_SPI
+struct dm_spi_bus {
+       uint max_hz;
+};
+
+#endif /* CONFIG_DM_SPI */
+
 /**
  * struct spi_slave - Representation of a SPI slave
  *
- * Drivers are expected to extend this with controller-specific data.
+ * For driver model this is the per-child data used by the SPI bus. It can
+ * be accessed using dev_get_parentdata() on the slave device. Each SPI
+ * driver should define this child data in its U_BOOT_DRIVER() definition:
+ *
+ *     .per_child_auto_alloc_size      = sizeof(struct spi_slave),
  *
- * @bus:               ID of the bus that the slave is attached to.
+ * If not using driver model, drivers are expected to extend this with
+ * controller-specific data.
+ *
+ * @dev:               SPI slave device
+ * @max_hz:            Maximum speed for this slave
+ * @mode:              SPI mode to use for this slave (see SPI mode flags)
+ * @bus:               ID of the bus that the slave is attached to. For
+ *                     driver model this is the sequence number of the SPI
+ *                     bus (bus->seq) so does not need to be stored
  * @cs:                        ID of the chip select connected to the slave.
  * @op_mode_rx:                SPI RX operation mode.
  * @op_mode_tx:                SPI TX operation mode.
  * @flags:             Indication of SPI flags.
  */
 struct spi_slave {
+#ifdef CONFIG_DM_SPI
+       struct udevice *dev;    /* struct spi_slave is dev->parentdata */
+       uint max_hz;
+       uint mode;
+#else
        unsigned int bus;
+#endif
        unsigned int cs;
        u8 op_mode_rx;
        u8 op_mode_tx;
@@ -228,8 +253,9 @@ int  spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
  * Returns: 1 if bus:cs identifies a valid chip on this board, 0
  * otherwise.
  */
-int  spi_cs_is_valid(unsigned int bus, unsigned int cs);
+int spi_cs_is_valid(unsigned int bus, unsigned int cs);
 
+#ifndef CONFIG_DM_SPI
 /**
  * Activate a SPI chipselect.
  * This function is provided by the board code when using a driver
@@ -255,6 +281,7 @@ void spi_cs_deactivate(struct spi_slave *slave);
  * @hz:                The transfer speed
  */
 void spi_set_speed(struct spi_slave *slave, uint hz);
+#endif
 
 /**
  * Write 8 bits, then read 8 bits.
@@ -305,4 +332,270 @@ struct spi_slave *spi_setup_slave_fdt(const void *blob, int slave_node,
 struct spi_slave *spi_base_setup_slave_fdt(const void *blob, int busnum,
                                           int node);
 
+#ifdef CONFIG_DM_SPI
+
+/**
+ * struct spi_cs_info - Information about a bus chip select
+ *
+ * @dev:       Connected device, or NULL if none
+ */
+struct spi_cs_info {
+       struct udevice *dev;
+};
+
+/**
+ * struct struct dm_spi_ops - Driver model SPI operations
+ *
+ * The uclass interface is implemented by all SPI devices which use
+ * driver model.
+ */
+struct dm_spi_ops {
+       /**
+        * Claim the bus and prepare it for communication.
+        *
+        * The device provided is the slave device. It's parent controller
+        * will be used to provide the communication.
+        *
+        * This must be called before doing any transfers with a SPI slave. It
+        * will enable and initialize any SPI hardware as necessary, and make
+        * sure that the SCK line is in the correct idle state. It is not
+        * allowed to claim the same bus for several slaves without releasing
+        * the bus in between.
+        *
+        * @bus:        The SPI slave
+        *
+        * Returns: 0 if the bus was claimed successfully, or a negative value
+        * if it wasn't.
+        */
+       int (*claim_bus)(struct udevice *bus);
+
+       /**
+        * Release the SPI bus
+        *
+        * This must be called once for every call to spi_claim_bus() after
+        * all transfers have finished. It may disable any SPI hardware as
+        * appropriate.
+        *
+        * @bus:        The SPI slave
+        */
+       int (*release_bus)(struct udevice *bus);
+
+       /**
+        * Set the word length for SPI transactions
+        *
+        * Set the word length (number of bits per word) for SPI transactions.
+        *
+        * @bus:        The SPI slave
+        * @wordlen:    The number of bits in a word
+        *
+        * Returns: 0 on success, -ve on failure.
+        */
+       int (*set_wordlen)(struct udevice *bus, unsigned int wordlen);
+
+       /**
+        * SPI transfer
+        *
+        * This writes "bitlen" bits out the SPI MOSI port and simultaneously
+        * clocks "bitlen" bits in the SPI MISO port.  That's just the way SPI
+        * works.
+        *
+        * The source of the outgoing bits is the "dout" parameter and the
+        * destination of the input bits is the "din" parameter.  Note that
+        * "dout" and "din" can point to the same memory location, in which
+        * case the input data overwrites the output data (since both are
+        * buffered by temporary variables, this is OK).
+        *
+        * spi_xfer() interface:
+        * @dev:        The slave device to communicate with
+        * @bitlen:     How many bits to write and read.
+        * @dout:       Pointer to a string of bits to send out.  The bits are
+        *              held in a byte array and are sent MSB first.
+        * @din:        Pointer to a string of bits that will be filled in.
+        * @flags:      A bitwise combination of SPI_XFER_* flags.
+        *
+        * Returns: 0 on success, not -1 on failure
+        */
+       int (*xfer)(struct udevice *dev, unsigned int bitlen, const void *dout,
+                   void *din, unsigned long flags);
+
+       /**
+        * Set transfer speed.
+        * This sets a new speed to be applied for next spi_xfer().
+        * @bus:        The SPI bus
+        * @hz:         The transfer speed
+        * @return 0 if OK, -ve on error
+        */
+       int (*set_speed)(struct udevice *bus, uint hz);
+
+       /**
+        * Set the SPI mode/flags
+        *
+        * It is unclear if we want to set speed and mode together instead
+        * of separately.
+        *
+        * @bus:        The SPI bus
+        * @mode:       Requested SPI mode (SPI_... flags)
+        * @return 0 if OK, -ve on error
+        */
+       int (*set_mode)(struct udevice *bus, uint mode);
+
+       /**
+        * Get information on a chip select
+        *
+        * This is only called when the SPI uclass does not know about a
+        * chip select, i.e. it has no attached device. It gives the driver
+        * a chance to allow activity on that chip select even so.
+        *
+        * @bus:        The SPI bus
+        * @cs:         The chip select (0..n-1)
+        * @info:       Returns information about the chip select, if valid.
+        *              On entry info->dev is NULL
+        * @return 0 if OK (and @info is set up), -ENODEV if the chip select
+        *         is invalid, other -ve value on error
+        */
+       int (*cs_info)(struct udevice *bus, uint cs, struct spi_cs_info *info);
+};
+
+struct dm_spi_emul_ops {
+       /**
+        * SPI transfer
+        *
+        * This writes "bitlen" bits out the SPI MOSI port and simultaneously
+        * clocks "bitlen" bits in the SPI MISO port.  That's just the way SPI
+        * works. Here the device is a slave.
+        *
+        * The source of the outgoing bits is the "dout" parameter and the
+        * destination of the input bits is the "din" parameter.  Note that
+        * "dout" and "din" can point to the same memory location, in which
+        * case the input data overwrites the output data (since both are
+        * buffered by temporary variables, this is OK).
+        *
+        * spi_xfer() interface:
+        * @slave:      The SPI slave which will be sending/receiving the data.
+        * @bitlen:     How many bits to write and read.
+        * @dout:       Pointer to a string of bits sent to the device. The
+        *              bits are held in a byte array and are sent MSB first.
+        * @din:        Pointer to a string of bits that will be sent back to
+        *              the master.
+        * @flags:      A bitwise combination of SPI_XFER_* flags.
+        *
+        * Returns: 0 on success, not -1 on failure
+        */
+       int (*xfer)(struct udevice *slave, unsigned int bitlen,
+                   const void *dout, void *din, unsigned long flags);
+};
+
+/**
+ * spi_find_bus_and_cs() - Find bus and slave devices by number
+ *
+ * Given a bus number and chip select, this finds the corresponding bus
+ * device and slave device. Neither device is activated by this function,
+ * although they may have been activated previously.
+ *
+ * @busnum:    SPI bus number
+ * @cs:                Chip select to look for
+ * @busp:      Returns bus device
+ * @devp:      Return slave device
+ * @return 0 if found, -ENODEV on error
+ */
+int spi_find_bus_and_cs(int busnum, int cs, struct udevice **busp,
+                       struct udevice **devp);
+
+/**
+ * spi_get_bus_and_cs() - Find and activate bus and slave devices by number
+ *
+ * Given a bus number and chip select, this finds the corresponding bus
+ * device and slave device.
+ *
+ * If no such slave exists, and drv_name is not NULL, then a new slave device
+ * is automatically bound on this chip select.
+ *
+ * Ths new slave device is probed ready for use with the given speed and mode.
+ *
+ * @busnum:    SPI bus number
+ * @cs:                Chip select to look for
+ * @speed:     SPI speed to use for this slave
+ * @mode:      SPI mode to use for this slave
+ * @drv_name:  Name of driver to attach to this chip select
+ * @dev_name:  Name of the new device thus created
+ * @busp:      Returns bus device
+ * @devp:      Return slave device
+ * @return 0 if found, -ve on error
+ */
+int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode,
+                       const char *drv_name, const char *dev_name,
+                       struct udevice **busp, struct spi_slave **devp);
+
+/**
+ * spi_chip_select() - Get the chip select for a slave
+ *
+ * @return the chip select this slave is attached to
+ */
+int spi_chip_select(struct udevice *slave);
+
+/**
+ * spi_bind_device() - bind a device to a bus's chip select
+ *
+ * This binds a new device to an given chip select (which must be unused).
+ *
+ * @bus:       SPI bus to search
+ * @cs:                Chip select to attach to
+ * @drv_name:  Name of driver to attach to this chip select
+ * @dev_name:  Name of the new device thus created
+ * @devp:      Returns the newly bound device
+ */
+int spi_bind_device(struct udevice *bus, int cs, const char *drv_name,
+                   const char *dev_name, struct udevice **devp);
+
+/**
+ * spi_ofdata_to_platdata() - decode standard SPI platform data
+ *
+ * This decodes the speed and mode from a device tree node and puts it into
+ * the spi_slave structure.
+ *
+ * @blob:      Device tree blob
+ * @node:      Node offset to read from
+ * @spi:       Place to put the decoded information
+ */
+int spi_ofdata_to_platdata(const void *blob, int node, struct spi_slave *spi);
+
+/**
+ * spi_cs_info() - Check information on a chip select
+ *
+ * This checks a particular chip select on a bus to see if it has a device
+ * attached, or is even valid.
+ *
+ * @bus:       The SPI bus
+ * @cs:                The chip select (0..n-1)
+ * @info:      Returns information about the chip select, if valid
+ * @return 0 if OK (and @info is set up), -ENODEV if the chip select
+ *        is invalid, other -ve value on error
+ */
+int spi_cs_info(struct udevice *bus, uint cs, struct spi_cs_info *info);
+
+struct sandbox_state;
+
+/**
+ * sandbox_spi_get_emul() - get an emulator for a SPI slave
+ *
+ * This provides a way to attach an emulated SPI device to a particular SPI
+ * slave, so that xfer() operations on the slave will be handled by the
+ * emulator. If a emulator already exists on that chip select it is returned.
+ * Otherwise one is created.
+ *
+ * @state:     Sandbox state
+ * @bus:       SPI bus requesting the emulator
+ * @slave:     SPI slave device requesting the emulator
+ * @emuip:     Returns pointer to emulator
+ * @return 0 if OK, -ve on error
+ */
+int sandbox_spi_get_emul(struct sandbox_state *state,
+                        struct udevice *bus, struct udevice *slave,
+                        struct udevice **emulp);
+
+/* Access the serial operations for a device */
+#define spi_get_ops(dev)       ((struct dm_spi_ops *)(dev)->driver->ops)
+#define spi_emul_get_ops(dev)  ((struct dm_spi_emul_ops *)(dev)->driver->ops)
+#endif /* CONFIG_DM_SPI */
+
 #endif /* _SPI_H_ */
index 408a5b401cd91e66e88b84eab5c1dcef97681522..5913b39e268ee30598de449d03447a8205c80dae 100644 (file)
@@ -15,9 +15,8 @@
 #ifndef _SPI_FLASH_H_
 #define _SPI_FLASH_H_
 
-#include <spi.h>
+#include <dm.h>        /* Because we dereference struct udevice here */
 #include <linux/types.h>
-#include <linux/compiler.h>
 
 #ifndef CONFIG_SF_DEFAULT_SPEED
 # define CONFIG_SF_DEFAULT_SPEED       1000000
 # define CONFIG_SF_DEFAULT_BUS         0
 #endif
 
-/* sf param flags */
-#define SECT_4K                1 << 1
-#define SECT_32K       1 << 2
-#define E_FSR          1 << 3
-#define WR_QPP         1 << 4
-
-/* Enum list - Full read commands */
-enum spi_read_cmds {
-       ARRAY_SLOW = 1 << 0,
-       DUAL_OUTPUT_FAST = 1 << 1,
-       DUAL_IO_FAST = 1 << 2,
-       QUAD_OUTPUT_FAST = 1 << 3,
-       QUAD_IO_FAST = 1 << 4,
-};
-#define RD_EXTN                ARRAY_SLOW | DUAL_OUTPUT_FAST | DUAL_IO_FAST
-#define RD_FULL                RD_EXTN | QUAD_OUTPUT_FAST | QUAD_IO_FAST
-
-/* Dual SPI flash memories */
-enum spi_dual_flash {
-       SF_SINGLE_FLASH = 0,
-       SF_DUAL_STACKED_FLASH = 1 << 0,
-       SF_DUAL_PARALLEL_FLASH = 1 << 1,
-};
-
-/**
- * struct spi_flash_params - SPI/QSPI flash device params structure
- *
- * @name:              Device name ([MANUFLETTER][DEVTYPE][DENSITY][EXTRAINFO])
- * @jedec:             Device jedec ID (0x[1byte_manuf_id][2byte_dev_id])
- * @ext_jedec:         Device ext_jedec ID
- * @sector_size:       Sector size of this device
- * @nr_sectors:                No.of sectors on this device
- * @e_rd_cmd:          Enum list for read commands
- * @flags:             Important param, for flash specific behaviour
- */
-struct spi_flash_params {
-       const char *name;
-       u32 jedec;
-       u16 ext_jedec;
-       u32 sector_size;
-       u32 nr_sectors;
-       u8 e_rd_cmd;
-       u16 flags;
-};
-
-extern const struct spi_flash_params spi_flash_params_table[];
+struct spi_slave;
 
 /**
  * struct spi_flash - SPI flash structure
  *
  * @spi:               SPI slave
  * @name:              Name of SPI flash
- * @dual_flash:                Indicates dual flash memories - dual stacked, parallel
+ * @dual_flash:        Indicates dual flash memories - dual stacked, parallel
  * @shift:             Flash shift useful in dual parallel
  * @size:              Total flash size
  * @page_size:         Write (page) size
  * @sector_size:       Sector size
- * @erase_size:                Erase size
+ * @erase_size:        Erase size
  * @bank_read_cmd:     Bank read cmd
  * @bank_write_cmd:    Bank write cmd
  * @bank_curr:         Current flash bank
@@ -97,8 +51,8 @@ extern const struct spi_flash_params spi_flash_params_table[];
  * @erase_cmd:         Erase cmd 4K, 32K, 64K
  * @read_cmd:          Read cmd - Array Fast, Extn read and quad read.
  * @write_cmd:         Write cmd - page and quad program.
- * @dummy_byte:                Dummy cycles for read operation.
- * @memory_map:                Address of read-only SPI flash access
+ * @dummy_byte:        Dummy cycles for read operation.
+ * @memory_map:        Address of read-only SPI flash access
  * @read:              Flash read ops: Read len bytes at offset into buf
  *                     Supported cmds: Fast Array Read
  * @write:             Flash write ops: Write len bytes from buf into offset
@@ -108,7 +62,12 @@ extern const struct spi_flash_params spi_flash_params_table[];
  * return 0 - Success, 1 - Failure
  */
 struct spi_flash {
+#ifdef CONFIG_DM_SPI_FLASH
+       struct spi_slave *spi;
+       struct udevice *dev;
+#else
        struct spi_slave *spi;
+#endif
        const char *name;
        u8 dual_flash;
        u8 shift;
@@ -129,12 +88,75 @@ struct spi_flash {
        u8 dummy_byte;
 
        void *memory_map;
+#ifndef CONFIG_DM_SPI_FLASH
+       /*
+        * These are not strictly needed for driver model, but keep them here
+        * whilt the transition is in progress.
+        *
+        * Normally each driver would provide its own operations, but for
+        * SPI flash most chips use the same algorithms. One approach is
+        * to create a 'common' SPI flash device which knows how to talk
+        * to most devices, and then allow other drivers to be used instead
+        * if requird, perhaps with a way of scanning through the list to
+        * find the driver that matches the device.
+        */
        int (*read)(struct spi_flash *flash, u32 offset, size_t len, void *buf);
        int (*write)(struct spi_flash *flash, u32 offset, size_t len,
                        const void *buf);
        int (*erase)(struct spi_flash *flash, u32 offset, size_t len);
+#endif
 };
 
+struct dm_spi_flash_ops {
+       int (*read)(struct udevice *dev, u32 offset, size_t len, void *buf);
+       int (*write)(struct udevice *dev, u32 offset, size_t len,
+                    const void *buf);
+       int (*erase)(struct udevice *dev, u32 offset, size_t len);
+};
+
+/* Access the serial operations for a device */
+#define sf_get_ops(dev) ((struct dm_spi_flash_ops *)(dev)->driver->ops)
+
+#ifdef CONFIG_DM_SPI_FLASH
+int spi_flash_probe_bus_cs(unsigned int busnum, unsigned int cs,
+                          unsigned int max_hz, unsigned int spi_mode,
+                          struct udevice **devp);
+
+/* Compatibility function - this is the old U-Boot API */
+struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs,
+                                 unsigned int max_hz, unsigned int spi_mode);
+
+/* Compatibility function - this is the old U-Boot API */
+void spi_flash_free(struct spi_flash *flash);
+
+int spi_flash_remove(struct udevice *flash);
+
+static inline int spi_flash_read(struct spi_flash *flash, u32 offset,
+               size_t len, void *buf)
+{
+       return sf_get_ops(flash->dev)->read(flash->dev, offset, len, buf);
+}
+
+static inline int spi_flash_write(struct spi_flash *flash, u32 offset,
+               size_t len, const void *buf)
+{
+       return sf_get_ops(flash->dev)->write(flash->dev, offset, len, buf);
+}
+
+static inline int spi_flash_erase(struct spi_flash *flash, u32 offset,
+               size_t len)
+{
+       return sf_get_ops(flash->dev)->erase(flash->dev, offset, len);
+}
+
+struct sandbox_state;
+
+int sandbox_sf_bind_emul(struct sandbox_state *state, int busnum, int cs,
+                        struct udevice *bus, int of_offset, const char *spec);
+
+void sandbox_sf_unbind_emul(struct sandbox_state *state, int busnum, int cs);
+
+#else
 struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs,
                unsigned int max_hz, unsigned int spi_mode);
 
@@ -169,6 +191,7 @@ static inline int spi_flash_erase(struct spi_flash *flash, u32 offset,
 {
        return flash->erase(flash, offset, len);
 }
+#endif
 
 void spi_boot(void) __noreturn;
 void spi_spl_load_image(uint32_t offs, unsigned int size, void *vdst);
index 7597bad555404a276a72afd4bda981e0f4187ce7..39f4b3f8ad5ffecc59afa59f9e96a93f4e16fe5c 100644 (file)
@@ -15,14 +15,16 @@ int initcall_run_list(const init_fnc_t init_sequence[])
 
        for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
                unsigned long reloc_ofs = 0;
+               int ret;
 
                if (gd->flags & GD_FLG_RELOC)
                        reloc_ofs = gd->reloc_off;
                debug("initcall: %p\n", (char *)*init_fnc_ptr - reloc_ofs);
-               if ((*init_fnc_ptr)()) {
-                       printf("initcall sequence %p failed at call %p\n",
+               ret = (*init_fnc_ptr)();
+               if (ret) {
+                       printf("initcall sequence %p failed at call %p (err=%d)\n",
                               init_sequence,
-                              (char *)*init_fnc_ptr - reloc_ofs);
+                              (char *)*init_fnc_ptr - reloc_ofs, ret);
                        return -1;
                }
        }
index 5c2415e3d2a93b9307e27cbefa48d6dab9eb40c9..75d3d41536bfb47079f37a284beca95bd982b425 100644 (file)
@@ -18,4 +18,6 @@ obj-$(CONFIG_DM_TEST) += core.o
 obj-$(CONFIG_DM_TEST) += ut.o
 ifneq ($(CONFIG_SANDBOX),)
 obj-$(CONFIG_DM_GPIO) += gpio.o
+obj-$(CONFIG_DM_SPI) += spi.o
+obj-$(CONFIG_DM_SPI_FLASH) += sf.o
 endif
index 873d64e42a4eda8cbe2ccaddd15cc6f2701cf5a0..abbaccff509ce09374f30e88983252672d3c4e62 100644 (file)
@@ -140,6 +140,37 @@ static int dm_test_bus_children_funcs(struct dm_test_state *dms)
 }
 DM_TEST(dm_test_bus_children_funcs, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 
+/* Test that we can iterate through children */
+static int dm_test_bus_children_iterators(struct dm_test_state *dms)
+{
+       struct udevice *bus, *dev, *child;
+
+       /* Walk through the children one by one */
+       ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
+       ut_assertok(device_find_first_child(bus, &dev));
+       ut_asserteq_str("c-test@5", dev->name);
+       ut_assertok(device_find_next_child(&dev));
+       ut_asserteq_str("c-test@0", dev->name);
+       ut_assertok(device_find_next_child(&dev));
+       ut_asserteq_str("c-test@1", dev->name);
+       ut_assertok(device_find_next_child(&dev));
+       ut_asserteq_ptr(dev, NULL);
+
+       /* Move to the next child without using device_find_first_child() */
+       ut_assertok(device_find_child_by_seq(bus, 5, true, &dev));
+       ut_asserteq_str("c-test@5", dev->name);
+       ut_assertok(device_find_next_child(&dev));
+       ut_asserteq_str("c-test@0", dev->name);
+
+       /* Try a device with no children */
+       ut_assertok(device_find_first_child(dev, &child));
+       ut_asserteq_ptr(child, NULL);
+
+       return 0;
+}
+DM_TEST(dm_test_bus_children_iterators,
+       DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
 /* Test that the bus can store data about each child */
 static int dm_test_bus_parent_data(struct dm_test_state *dms)
 {
diff --git a/test/dm/sf.c b/test/dm/sf.c
new file mode 100644 (file)
index 0000000..57dd134
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2013 Google, Inc
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <spi.h>
+#include <spi_flash.h>
+#include <asm/state.h>
+#include <dm/ut.h>
+#include <dm/test.h>
+#include <dm/util.h>
+
+/* Test that sandbox SPI flash works correctly */
+static int dm_test_spi_flash(struct dm_test_state *dms)
+{
+       /*
+        * Create an empty test file and run the SPI flash tests. This is a
+        * long way from being a unit test, but it does test SPI device and
+        * emulator binding, probing, the SPI flash emulator including
+        * device tree decoding, plus the file-based backing store of SPI.
+        *
+        * More targeted tests could be created to perform the above steps
+        * one at a time. This might not increase test coverage much, but
+        * it would make bugs easier to find. It's not clear whether the
+        * benefit is worth the extra complexity.
+        */
+       ut_asserteq(0, run_command_list(
+               "sb save hostfs - spi.bin 0 200000;"
+               "sf probe;"
+               "sf test 0 10000", -1,  0));
+       /*
+        * Since we are about to destroy all devices, we must tell sandbox
+        * to forget the emulation device
+        */
+       sandbox_sf_unbind_emul(state_get_current(), 0, 0);
+
+       return 0;
+}
+DM_TEST(dm_test_spi_flash, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/spi.c b/test/dm/spi.c
new file mode 100644 (file)
index 0000000..61b5b25
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2013 Google, Inc
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <spi.h>
+#include <spi_flash.h>
+#include <dm/device-internal.h>
+#include <dm/test.h>
+#include <dm/uclass-internal.h>
+#include <dm/ut.h>
+#include <dm/util.h>
+#include <asm/state.h>
+
+/* Test that we can find buses and chip-selects */
+static int dm_test_spi_find(struct dm_test_state *dms)
+{
+       struct sandbox_state *state = state_get_current();
+       struct spi_slave *slave;
+       struct udevice *bus, *dev;
+       const int busnum = 0, cs = 0, mode = 0, speed = 1000000, cs_b = 1;
+       struct spi_cs_info info;
+       int of_offset;
+
+       ut_asserteq(-ENODEV, uclass_find_device_by_seq(UCLASS_SPI, busnum,
+                                                      false, &bus));
+
+       /*
+        * spi_post_bind() will bind devices to chip selects. Check this then
+        * remove the emulation and the slave device.
+        */
+       ut_asserteq(0, uclass_get_device_by_seq(UCLASS_SPI, busnum, &bus));
+       ut_assertok(spi_cs_info(bus, cs, &info));
+       of_offset = info.dev->of_offset;
+       sandbox_sf_unbind_emul(state_get_current(), busnum, cs);
+       device_remove(info.dev);
+       device_unbind(info.dev);
+
+       /*
+        * Even though the device is gone, the sandbox SPI drivers always
+        * reports that CS 0 is present
+        */
+       ut_assertok(spi_cs_info(bus, cs, &info));
+       ut_asserteq_ptr(info.dev, NULL);
+
+       /* This finds nothing because we removed the device */
+       ut_asserteq(-ENODEV, spi_find_bus_and_cs(busnum, cs, &bus, &dev));
+       ut_asserteq(-ENODEV, spi_get_bus_and_cs(busnum, cs, speed, mode,
+                                               NULL, 0, &bus, &slave));
+
+       /*
+        * This forces the device to be re-added, but there is no emulation
+        * connected so the probe will fail. We require that bus is left
+        * alone on failure, and that the spi_get_bus_and_cs() does not add
+        * a 'partially-inited' device.
+        */
+       ut_asserteq(-ENODEV, spi_find_bus_and_cs(busnum, cs, &bus, &dev));
+       ut_asserteq(-ENOENT, spi_get_bus_and_cs(busnum, cs, speed, mode,
+                                               "spi_flash_std", "name", &bus,
+                                               &slave));
+       ut_assertok(spi_cs_info(bus, cs, &info));
+       ut_asserteq_ptr(info.dev, NULL);
+
+       /* Add the emulation and try again */
+       ut_assertok(sandbox_sf_bind_emul(state, busnum, cs, bus, of_offset,
+                                        "name"));
+       ut_assertok(spi_find_bus_and_cs(busnum, cs, &bus, &dev));
+       ut_assertok(spi_get_bus_and_cs(busnum, cs, speed, mode,
+                                      "spi_flash_std", "name", &bus, &slave));
+
+       ut_assertok(spi_cs_info(bus, cs, &info));
+       ut_asserteq_ptr(info.dev, slave->dev);
+
+       /* We should be able to add something to another chip select */
+       ut_assertok(sandbox_sf_bind_emul(state, busnum, cs_b, bus, of_offset,
+                                        "name"));
+       ut_assertok(spi_get_bus_and_cs(busnum, cs_b, speed, mode,
+                                      "spi_flash_std", "name", &bus, &slave));
+       ut_assertok(spi_cs_info(bus, cs_b, &info));
+       ut_asserteq_ptr(info.dev, slave->dev);
+
+       /*
+        * Since we are about to destroy all devices, we must tell sandbox
+        * to forget the emulation device
+        */
+       sandbox_sf_unbind_emul(state_get_current(), busnum, cs);
+       sandbox_sf_unbind_emul(state_get_current(), busnum, cs_b);
+
+       return 0;
+}
+DM_TEST(dm_test_spi_find, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test that sandbox SPI works correctly */
+static int dm_test_spi_xfer(struct dm_test_state *dms)
+{
+       struct spi_slave *slave;
+       struct udevice *bus;
+       const int busnum = 0, cs = 0, mode = 0;
+       const char dout[5] = {0x9f};
+       unsigned char din[5];
+
+       ut_assertok(spi_get_bus_and_cs(busnum, cs, 1000000, mode, NULL, 0,
+                                      &bus, &slave));
+       ut_assertok(spi_claim_bus(slave));
+       ut_assertok(spi_xfer(slave, 40, dout, din,
+                            SPI_XFER_BEGIN | SPI_XFER_END));
+       ut_asserteq(0xff, din[0]);
+       ut_asserteq(0x20, din[1]);
+       ut_asserteq(0x20, din[2]);
+       ut_asserteq(0x15, din[3]);
+       spi_release_bus(slave);
+
+       /*
+        * Since we are about to destroy all devices, we must tell sandbox
+        * to forget the emulation device
+        */
+#ifdef CONFIG_DM_SPI_FLASH
+       sandbox_sf_unbind_emul(state_get_current(), busnum, cs);
+#endif
+
+       return 0;
+}
+DM_TEST(dm_test_spi_xfer, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
index ef5aca5ac3c43800fe62b9242027cb341f4e9af7..bb99677ece9462604e4362fc514030291e30862d 100755 (executable)
@@ -4,4 +4,6 @@ NUM_CPUS=$(cat /proc/cpuinfo |grep -c processor)
 dtc -I dts -O dtb test/dm/test.dts -o test/dm/test.dtb
 make O=sandbox sandbox_config
 make O=sandbox -s -j${NUM_CPUS}
+dd if=/dev/zero of=spi.bin bs=1M count=2
 ./sandbox/u-boot -d test/dm/test.dtb -c "dm test"
+rm spi.bin
index 84895951550ffec7b1df26c4f2e782398f589ce5..1fba7925642a928fd60f10fd4ed7ee1bcc192890 100644 (file)
@@ -81,7 +81,7 @@
                compatible = "google,another-fdt-test";
        };
 
-       base-gpios {
+       gpio_a: base-gpios {
                compatible = "sandbox,gpio";
                gpio-bank-name = "a";
                num-gpios = <20>;
                gpio-bank-name = "b";
                num-gpios = <10>;
        };
+
+       spi@0 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               reg = <0>;
+               compatible = "sandbox,spi";
+               cs-gpios = <0>, <&gpio_a 0>;
+               spi.bin@0 {
+                       reg = <0>;
+                       compatible = "spansion,m25p16", "spi-flash";
+                       spi-max-frequency = <40000000>;
+                       sandbox,filename = "spi.bin";
+               };
+       };
+
 };