Merge git://git.denx.de/u-boot-dm

This commit is contained in:
Tom Rini 2014-10-22 13:51:45 -04:00
commit 68e80fdda1
145 changed files with 7919 additions and 2273 deletions

View 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 {

View 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>;

View 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";

View file

@ -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>;
};
};

View file

@ -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>;
};
};
};

View file

@ -7,7 +7,7 @@
*/
/dts-v1/;
/include/ "exynos4.dtsi"
#include "exynos4.dtsi"
/ {
model = "Samsung SMDKV310 on Exynos4210";

View file

@ -8,7 +8,7 @@
*/
/dts-v1/;
/include/ "exynos4.dtsi"
#include "exynos4210.dtsi"
/ {
model = "Samsung Trats based on Exynos4210";

View file

@ -8,7 +8,7 @@
*/
/dts-v1/;
/include/ "exynos4.dtsi"
#include "exynos4210.dtsi"
/ {
model = "Samsung Universal C210 based on Exynos4210 rev0";
@ -41,6 +41,19 @@
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>;

View file

@ -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;
};
};
};

View file

@ -8,7 +8,7 @@
*/
/dts-v1/;
/include/ "exynos4.dtsi"
#include "exynos4.dtsi"
/ {
model = "Odroid based on Exynos4412";

View file

@ -8,7 +8,7 @@
*/
/dts-v1/;
/include/ "exynos4.dtsi"
#include "exynos4412.dtsi"
/ {
model = "Samsung Trats2 based on Exynos4412";

View file

@ -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>;
};
};

View file

@ -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>;
};
};

View file

@ -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>;
};
};
};

View file

@ -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";
};
};

View 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>;
@ -17,6 +44,33 @@
#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>;
@ -190,6 +244,7 @@
compatible = "samsung,exynos4210-uart";
reg = <0x12C30000 0x100>;
interrupts = <0 54 0>;
u-boot,dm-pre-reloc;
id = <3>;
};

View file

@ -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>;
};
};

View file

@ -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>;
};
};
};

View file

@ -10,7 +10,7 @@
*/
/dts-v1/;
/include/ "exynos5250.dtsi"
#include "exynos5250.dtsi"
/ {
model = "SAMSUNG SMDK5250 board based on EXYNOS5250";

View file

@ -10,7 +10,7 @@
*/
/dts-v1/;
/include/ "exynos5250.dtsi"
#include "exynos5250.dtsi"
/ {
model = "Google Snow";
@ -53,6 +53,14 @@
};
};
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>;

View 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>;

View file

@ -8,7 +8,7 @@
*/
/dts-v1/;
/include/ "exynos54xx.dtsi"
#include "exynos54xx.dtsi"
/ {
model = "Samsung/Google Peach Pit board based on Exynos5420";
@ -140,6 +140,7 @@
spi@12d30000 { /* spi1 */
spi-max-frequency = <50000000>;
firmware_storage_spi: flash@0 {
compatible = "spi-flash";
reg = <0>;
/*

View file

@ -8,7 +8,7 @@
*/
/dts-v1/;
/include/ "exynos54xx.dtsi"
#include "exynos54xx.dtsi"
/ {
model = "SAMSUNG SMDK5420 board based on EXYNOS5420";

View file

@ -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>;
};
};

View file

@ -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>;
};
};
};

View file

@ -5,7 +5,8 @@
* SPDX-License-Identifier: GPL-2.0+
*/
/include/ "exynos5.dtsi"
#include "exynos5.dtsi"
#include "exynos54xx-pinctrl.dtsi"
/ {
config {
@ -24,6 +25,11 @@
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";
@ -123,6 +129,42 @@
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;

View file

@ -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>;
};
};
};

View file

@ -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>;
};
};
};

View file

@ -9,6 +9,7 @@
/dts-v1/;
#include "skeleton.dtsi"
#include "s5pc110-pinctrl.dtsi"
/ {
model = "Samsung Goni based on S5PC110";
@ -17,6 +18,12 @@
aliases {
serial2 = "/serial@e2900800";
console = "/serial@e2900800";
pinctrl0 = &pinctrl0;
};
pinctrl0: pinctrl@e0200000 {
compatible = "samsung,s5pc110-pinctrl";
reg = <0xe0200000 0x1000>;
};
serial@e2900800 {

View file

@ -9,6 +9,7 @@
/dts-v1/;
#include "skeleton.dtsi"
#include "s5pc100-pinctrl.dtsi"
/ {
model = "Samsung SMDKC100 based on S5PC100";
@ -17,6 +18,12 @@
aliases {
serial0 = "/serial@ec000000";
console = "/serial@ec000000";
pinctrl0 = &pinctrl0;
};
pinctrl0: pinctrl@e0300000 {
compatible = "samsung,s5pc100-pinctrl";
reg = <0xe0200000 0x1000>;
};
serial@ec000000 {

View file

@ -15,6 +15,7 @@
usb1 = "/usb@c5000000";
sdhci0 = "/sdhci@c8000600";
sdhci1 = "/sdhci@c8000000";
spi0 = "/spi@7000c380";
};
memory {

View file

@ -18,6 +18,7 @@
i2c4 = "/i2c@7000c700";
sdhci0 = "/sdhci@78000600";
sdhci1 = "/sdhci@78000000";
spi0 = "/spi@7000da00";
usb0 = "/usb@7d000000";
usb1 = "/usb@7d008000";
};

View file

@ -18,6 +18,7 @@
i2c4 = "/i2c@7000c700";
sdhci0 = "/sdhci@78000600";
sdhci1 = "/sdhci@78000000";
spi0 = "/spi@7000da00";
usb0 = "/usb@7d008000";
};

View 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";

View 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;
}

View 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_ */

View 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

View 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 */

View file

@ -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_ */

View file

@ -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_ */

View file

@ -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_ */

View 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,

View file

@ -1,6 +1,9 @@
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <0>;
chosen {
stdout-path = "/serial";
};
@ -131,4 +134,27 @@
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>;
};
};
};

View 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

View 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 */

View file

@ -13,11 +13,12 @@
#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"

View 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)
{
SETUP_IOMUX_PADS(sata_pads);
/* Make sure this gpio has logical 0 value */
gpio_direction_output(CM_FX6_SATA_PWLOSS_INT, 0);
udelay(100);
int ret, i;
cm_fx6_sata_power(0);
mdelay(250);
cm_fx6_sata_power(1);
SETUP_IOMUX_PADS(sata_pads);
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)
{
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;
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)
{
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,
};

View 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

View file

@ -16,15 +16,26 @@
#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;

View 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)

View 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)

View 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)

View 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);

View file

@ -13,10 +13,10 @@
#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();
}

View 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);
}

View 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);

View 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>

View 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
}

View 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);

View 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;

View 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>

View 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);

View 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);

View 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);

View 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 */

View 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;
}

View 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;
}
/*

View file

@ -10,25 +10,44 @@
#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
}

View 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>

View 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

View file

@ -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>;
};

View file

@ -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 {
};
};

View 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

View file

@ -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.

View file

@ -5,3 +5,4 @@
#
obj-y := device.o lists.o root.o uclass.o util.o
obj-$(CONFIG_OF_CONTROL) += simple-bus.o

View 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;
}

View 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;
}

33
drivers/core/simple-bus.c Normal file
View file

@ -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,
};

View 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;

View 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)

View file

@ -6,73 +6,207 @@
*/
#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;
}
int gpio_free(unsigned gpio)
{
return 0;
}
int gpio_direction_input(unsigned gpio)
static int bcm2835_gpio_request(struct udevice *dev, unsigned offset,
const char *label)
{
struct bcm2835_gpio_regs *reg =
(struct bcm2835_gpio_regs *)BCM2835_GPIO_BASE;
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;
}
static int bcm2835_gpio_free(struct udevice *dev, unsigned offset)
{
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),
};

View 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

View file

@ -6,120 +6,72 @@
*/
#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(x) (0x1 << (x))
#define DAT_SET(x) (0x1 << (x))
#define DAT_MASK(gpio) (0x1 << (gpio))
#define DAT_SET(gpio) (0x1 << (gpio))
#define PULL_MASK(x) (0x3 << ((x) << 1))
#define PULL_MODE(x, v) ((v) << ((x) << 1))
#define PULL_MASK(gpio) (0x3 << ((gpio) << 1))
#define PULL_MODE(gpio, pull) ((pull) << ((gpio) << 1))
#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))
#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 name_to_gpio(n) s5p_name_to_gpio(n)
static inline int s5p_name_to_gpio(const char *name)
#define GPIO_NAME_SIZE 20
/* Platform data for each bank */
struct exynos_gpio_platdata {
struct s5p_gpio_bank *bank;
const char *bank_name; /* Name of port, e.g. 'gpa0" */
};
/* Information about each bank at run-time */
struct exynos_bank_info {
char label[GPIO_PER_BANK][GPIO_NAME_SIZE];
struct s5p_gpio_bank *bank;
};
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;
const struct gpio_info *data;
unsigned int upto;
int i, count;
/*
* 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' */
data = get_gpio_data();
count = get_bank_num();
upto = 0;
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;
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;
}
} 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;
upto = data->max_gpio;
data++;
}
#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
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;
}
this_bank = (++tabp)->bank;
} while (this_bank);
return -1;
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)
{
const struct gpio_info *data;
unsigned int upto;
int i, count;
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;
}
upto = data->max_gpio;
data++;
}
return NULL;
}
int s5p_gpio_get_pin(unsigned gpio)
{
return S5P_GPIO_GET_PIN(gpio);
}
/* Common GPIO API */
int gpio_request(unsigned gpio, const char *label)
/* Driver model interface */
#ifndef CONFIG_SPL_BUILD
static int exynos_gpio_get_state(struct udevice *dev, unsigned int offset,
char *buf, int bufsize)
{
return 0;
}
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;
int gpio_free(unsigned gpio)
{
return 0;
}
int gpio_direction_input(unsigned gpio)
{
s5p_gpio_direction_input(s5p_gpio_get_bank(gpio),
s5p_gpio_get_pin(gpio));
return 0;
}
int gpio_direction_output(unsigned gpio, int value)
{
s5p_gpio_direction_output(s5p_gpio_get_bank(gpio),
s5p_gpio_get_pin(gpio), value);
return 0;
}
int gpio_get_value(unsigned gpio)
{
return (int) s5p_gpio_get_value(s5p_gpio_get_bank(gpio),
s5p_gpio_get_pin(gpio));
}
int gpio_set_value(unsigned gpio, int value)
{
s5p_gpio_set_value(s5p_gpio_get_bank(gpio),
s5p_gpio_get_pin(gpio), value);
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");
}
return 0;
}
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 0;
}
/* set GPIO pin 'gpio' as an input */
static int exynos_gpio_direction_input(struct udevice *dev, unsigned offset)
{
struct exynos_bank_info *state = dev_get_priv(dev);
int ret;
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);
return 0;
}
/* 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;
}
/* read GPIO IN value of pin 'gpio' */
static int exynos_gpio_get_value(struct udevice *dev, unsigned offset)
{
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);
}
/* write GPIO OUT value to pin 'gpio' */
static int exynos_gpio_set_value(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;
s5p_gpio_set_value(state->bank, offset, value);
return 0;
}
static int exynos_gpio_request(struct udevice *dev, unsigned offset,
const char *label)
{
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;
}
static int exynos_gpio_free(struct udevice *dev, unsigned offset)
{
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

View 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
#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)
{
char id[MSG_BYTES];
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

View 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

View file

@ -15,23 +15,34 @@
#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

View 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;

View 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

View file

@ -35,6 +35,7 @@
#include <common.h>
#include <malloc.h>
#include <spi.h>
#include <spi_flash.h>
#include "sf_internal.h"

View file

@ -9,6 +9,7 @@
*/
#include <common.h>
#include <dm.h>
#include <malloc.h>
#include <spi.h>
#include <os.h>
@ -19,6 +20,11 @@
#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;
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;
file = strchr(spec, ':');
if (!file) {
printf("sandbox_sf: unable to parse file\n");
goto error;
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;
}
}
idname_len = file - spec;
++file;
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);
}
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;
}
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,
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 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,
};

View file

@ -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),
};

View file

@ -10,6 +10,36 @@
#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
@ -30,12 +60,12 @@
#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
@ -66,19 +96,42 @@
/* 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);

View file

@ -7,6 +7,7 @@
*/
#include <common.h>
#include <spi.h>
#include <spi_flash.h>
#include "sf_internal.h"

View 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 */

View file

@ -10,6 +10,7 @@
*/
#include <common.h>
#include <spi.h>
#include <spi_flash.h>
#include <spl.h>

View 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

View 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)

View 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)
@ -128,6 +106,33 @@
#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

View file

@ -12,203 +12,44 @@
/* 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;
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)
{
struct pl01x_regs *regs = pl01x_get_regs(CONSOLE_PORT);
unsigned int divisor;
/* First, disable everything */
writel(0, &regs->pl010_cr);
/* Set baud rate */
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);
/* 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;
}
#endif /* CONFIG_PL010_SERIAL */
#ifdef CONFIG_PL011_SERIAL
static int pl01x_serial_init(void)
{
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);
}
#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);
/* 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);
#ifdef CONFIG_PL011_SERIAL_RLCR
{
int i;
/*
* Program receive line control register after waiting
* 10 bus cycles. Delay be writing to readonly register
* 10 times
*/
for (i = 0; i < 10; i++)
writel(lcr, &regs->fr);
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);
return 0;
}
#endif /* CONFIG_PL011_SERIAL */
static void pl01x_serial_putc(const char c)
static int pl01x_putc(struct pl01x_regs *regs, char c)
{
if (c == '\n')
pl01x_putc (CONSOLE_PORT, '\r');
pl01x_putc (CONSOLE_PORT, c);
}
static int pl01x_serial_getc(void)
{
return pl01x_getc (CONSOLE_PORT);
}
static int pl01x_serial_tstc(void)
{
return pl01x_tstc (CONSOLE_PORT);
}
static void pl01x_serial_setbrg(void)
{
struct pl01x_regs *regs = pl01x_get_regs(CONSOLE_PORT);
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();
}
static void pl01x_putc (int portnum, 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 (readl(&regs->fr) & UART_PL01x_FR_TXFF)
return -EAGAIN;
/* Send the character */
writel(c, &regs->dr);
return 0;
}
static int pl01x_getc (int portnum)
static int pl01x_getc(struct pl01x_regs *regs)
{
struct pl01x_regs *regs = pl01x_get_regs(portnum);
unsigned int data;
/* Wait until there is data in the FIFO */
while (readl(&regs->fr) & UART_PL01x_FR_RXFE)
WATCHDOG_RESET();
if (readl(&regs->fr) & UART_PL01x_FR_RXFE)
return -EAGAIN;
data = readl(&regs->dr);
@ -222,14 +63,199 @@ static int pl01x_getc (int portnum)
return (int) data;
}
static int pl01x_tstc (int portnum)
static int pl01x_tstc(struct pl01x_regs *regs)
{
struct pl01x_regs *regs = pl01x_get_regs(portnum);
WATCHDOG_RESET();
return !(readl(&regs->fr) & UART_PL01x_FR_RXFE);
}
static int pl01x_generic_serial_init(struct pl01x_regs *regs,
enum pl01x_type type)
{
unsigned int lcr;
#ifdef CONFIG_PL011_SERIAL_FLUSH_ON_INIT
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->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;
/*
* Program receive line control register after waiting
* 10 bus cycles. Delay be writing to readonly register
* 10 times
*/
for (i = 0; i < 10; i++)
writel(lcr, &regs->fr);
writel(lcr, &regs->pl011_rlcr);
/* lcrh needs to be set again for change to be effective */
writel(lcr, &regs->pl011_lcrh);
#endif
break;
}
default:
return -EINVAL;
}
return 0;
}
static int pl01x_generic_setbrg(struct pl01x_regs *regs, enum pl01x_type type,
int clock, int baudrate)
{
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;
/*
* 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;
}
return 0;
}
#ifndef CONFIG_DM_SERIAL
static void pl01x_serial_init_baud(int baudrate)
{
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);
}
/*
* 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)
{
pl01x_serial_init_baud(CONFIG_BAUDRATE);
return 0;
}
static void pl01x_serial_putc(const char c)
{
if (c == '\n')
while (pl01x_putc(base_regs, '\r') == -EAGAIN);
while (pl01x_putc(base_regs, c) == -EAGAIN);
}
static int pl01x_serial_getc(void)
{
while (1) {
int ch = pl01x_getc(base_regs);
if (ch == -EAGAIN) {
WATCHDOG_RESET();
continue;
}
return ch;
}
}
static int pl01x_serial_tstc(void)
{
return pl01x_tstc(base_regs);
}
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 = {
.name = "pl01x_serial",
.start = pl01x_serial_init,
@ -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

Some files were not shown because too many files have changed in this diff Show more