diff mbox series

[U-Boot,RFC] rockchip: tinker: Add automatic board discovery

Message ID 20191117101702.14783-1-michael@amarulasolutions.com
State RFC
Delegated to: Kever Yang
Headers show
Series [U-Boot,RFC] rockchip: tinker: Add automatic board discovery | expand

Commit Message

Michael Nazzareno Trimarchi Nov. 17, 2019, 10:17 a.m. UTC
Add a way to detect board id and pcb id.

Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
---
 arch/arm/dts/rk3288-tinker.dtsi              | 33 ++++++++
 board/rockchip/tinker_rk3288/tinker-rk3288.c | 83 ++++++++++++++++++++
 2 files changed, 116 insertions(+)

Comments

Jagan Teki Nov. 18, 2019, 11:25 a.m. UTC | #1
On Sun, Nov 17, 2019 at 3:47 PM Michael Trimarchi
<michael@amarulasolutions.com> wrote:
>
> Add a way to detect board id and pcb id.
>
> Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
> ---
>  arch/arm/dts/rk3288-tinker.dtsi              | 33 ++++++++
>  board/rockchip/tinker_rk3288/tinker-rk3288.c | 83 ++++++++++++++++++++
>  2 files changed, 116 insertions(+)
>
> diff --git a/arch/arm/dts/rk3288-tinker.dtsi b/arch/arm/dts/rk3288-tinker.dtsi
> index 2f816af47f..67a0374050 100644
> --- a/arch/arm/dts/rk3288-tinker.dtsi
> +++ b/arch/arm/dts/rk3288-tinker.dtsi
> @@ -53,6 +53,21 @@
>                 #clock-cells = <0>;
>         };
>
> +       board_info: board-info {
> +               tinker,pcbid0 = <&gpio2 8 GPIO_ACTIVE_HIGH>;
> +               tinker,pcbid1 = <&gpio2 9 GPIO_ACTIVE_HIGH>;
> +               tinker,pcbid2 = <&gpio2 10 GPIO_ACTIVE_HIGH>;
> +               tinker,pid0 = <&gpio2 1 GPIO_ACTIVE_HIGH>;
> +               tinker,pid1 = <&gpio2 2 GPIO_ACTIVE_HIGH>;
> +               tinker,pid2 = <&gpio2 3 GPIO_ACTIVE_HIGH>;
> +       };
> +
> +       board_control: board-control {
> +               tinker,sdp = <&gpio6 5 GPIO_ACTIVE_HIGH>;
> +               tinker,usblimit = <&gpio6 6 GPIO_ACTIVE_HIGH>;
> +               tinker,maskemmc = <&gpio6 7 GPIO_ACTIVE_HIGH>;
> +       };
> +

Need to move this into -u-boot.dtsi

>         gpio-keys {
>                 compatible = "gpio-keys";
>                 autorepeat;
> @@ -461,6 +476,10 @@
>  };
>
>  &pinctrl {
> +       /* Pins that are not explicitely used by any devices */
> +       pinctrl-names = "default";
> +       pinctrl-0 = <&tinker_pin_hog>;
> +
>         pcfg_pull_none_drv_8ma: pcfg-pull-none-drv-8ma {
>                 drive-strength = <8>;
>         };
> @@ -482,6 +501,20 @@
>                 };
>         };
>
> +       hog {
> +               tinker_pin_hog: tinker-pin-hog {
> +                       rockchip,pins = <2 RK_PA1 RK_FUNC_GPIO &pcfg_pull_up>, /* project id 0 */
> +                                       <2 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>, /* project id 1 */
> +                                       <2 RK_PA3 RK_FUNC_GPIO &pcfg_pull_up>, /* project id 2 */
> +                                       <2 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>, /* pcb id 0 */
> +                                       <2 RK_PB1 RK_FUNC_GPIO &pcfg_pull_none>, /* pcb id 1 */
> +                                       <2 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>, /* pcb id 2 */
> +                                       <6 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>, /* sdp detect */
> +                                       <6 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>, /* current limit */
> +                                       <6 RK_PA7 RK_FUNC_GPIO &pcfg_pull_none>; /* emmc mask */
> +               };
> +       };
> +

hog node is legacy representation, so we need to have a proper node to
define these.

>         eth_phy {
>                 eth_phy_pwr: eth-phy-pwr {
>                         rockchip,pins = <0 6 RK_FUNC_GPIO &pcfg_pull_none>;
> diff --git a/board/rockchip/tinker_rk3288/tinker-rk3288.c b/board/rockchip/tinker_rk3288/tinker-rk3288.c
> index 7a0c3c997d..7c65521f55 100644
> --- a/board/rockchip/tinker_rk3288/tinker-rk3288.c
> +++ b/board/rockchip/tinker_rk3288/tinker-rk3288.c
> @@ -5,12 +5,26 @@
>
>  #include <common.h>
>  #include <dm.h>
> +#include <dm/device-internal.h>
> +#include <asm/gpio.h>
> +#include <dt-bindings/pinctrl/rockchip.h>
>  #include <env.h>
>  #include <i2c_eeprom.h>
>  #include <netdev.h>
>  #include <asm/arch-rockchip/bootrom.h>
>  #include <asm/io.h>
>
> +enum project_id {
> +       tinker_board_s = 0,
> +       tinker_board = 7,
> +};
> +
> +enum pcb_id {
> +       SR,
> +       ER,
> +       PR,
> +};
> +
>  static int get_ethaddr_from_eeprom(u8 *addr)
>  {
>         int ret;
> @@ -23,10 +37,14 @@ static int get_ethaddr_from_eeprom(u8 *addr)
>         return i2c_eeprom_read(dev, 0, addr, 6);
>  }
>
> +int detect_board_init(void);

Mark this function as static.

> +
>  int rk3288_board_late_init(void)
>  {
>         u8 ethaddr[6];
>
> +       detect_board_init();
> +
>         if (get_ethaddr_from_eeprom(ethaddr))
>                 return 0;
>
> @@ -45,3 +63,68 @@ int mmc_get_env_dev(void)
>
>         return 1;
>  }
> +
> +int detect_board_init(void)
> +{
> +       int ret = 0, i;
> +       ofnode node;
> +       struct udevice *gpio_dev2 = NULL;
> +       struct udevice *gpio_dev6 = NULL;
> +       struct gpio_desc pcbid[3];
> +       struct gpio_desc pid[3];
> +       enum project_id prjid;
> +       char gpio_name[64];
> +       enum pcb_id pcbversion;
> +
> +       debug("%s: detect boad\n", __func__);
> +
> +       if (uclass_get_device_by_name(UCLASS_GPIO, "gpio2@ff790000", &gpio_dev2) ||
> +           uclass_get_device_by_name(UCLASS_GPIO, "gpio6@ff7d0000", &gpio_dev6)) {
> +               printf("Could not get GPIO device.\n");
> +               return -EINVAL;
> +       }
> +
> +       ret = device_probe(gpio_dev2);
> +       if (ret)
> +               pr_err("%s - probe failed: %d\n", gpio_dev2->name, ret);
> +
> +       ret = device_probe(gpio_dev6);
> +       if (ret)
> +               pr_err("%s - probe failed: %d\n", gpio_dev6->name, ret);
> +
> +       node = ofnode_path("/board-info");
> +       if (!ofnode_valid(node)) {
> +               pr_err("%s: no /board-info node?\n", __func__);
> +               return -EINVAL;
> +       }
> +
> +       for (i = 0; i < 3; i++) {
> +               snprintf(gpio_name, 64, "tinker,pid%d", i);
> +               if (gpio_request_by_name_nodev(node, gpio_name, 0,
> +                                       &pid[i], GPIOD_IS_IN)) {
> +                       printf("Failed to request %s\n", gpio_name);
> +                       continue;
> +               }
> +        }
> +
> +       for (i = 0; i < 3; i++) {
> +               snprintf(gpio_name, 64, "tinker,pcbid%d", i);
> +               if (gpio_request_by_name_nodev(node, gpio_name, 0,
> +                                               &pcbid[i], GPIOD_IS_IN)) {
> +                       printf("Failed to request %s\n", gpio_name);
> +                       continue;
> +               }
> +        }
> +
> +       prjid = dm_gpio_get_value(&pid[0]) | \
> +               dm_gpio_get_value(&pid[1]) << 1 | \
> +               dm_gpio_get_value(&pid[2]) << 2;
> +       pcbversion = dm_gpio_get_value(&pcbid[0]) | \
> +               dm_gpio_get_value(&pcbid[1]) << 1 | \
> +               dm_gpio_get_value(&pcbid[2]) << 2;
> +
> +       printf("Detect %s rev %d\n",
> +               prjid == tinker_board ? "Tinker" : "Tinker S", pcbversion);

I can see the output on my tinker as
Detect Tinker rev 2

But the back side of PCB show REV 1.2 any clue?
Michael Nazzareno Trimarchi Nov. 18, 2019, 12:02 p.m. UTC | #2
Hi

On Mon, Nov 18, 2019 at 12:25 PM Jagan Teki <jagan@amarulasolutions.com> wrote:
>
> On Sun, Nov 17, 2019 at 3:47 PM Michael Trimarchi
> <michael@amarulasolutions.com> wrote:
> >
> > Add a way to detect board id and pcb id.
> >
> > Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
> > ---
> >  arch/arm/dts/rk3288-tinker.dtsi              | 33 ++++++++
> >  board/rockchip/tinker_rk3288/tinker-rk3288.c | 83 ++++++++++++++++++++
> >  2 files changed, 116 insertions(+)
> >
> > diff --git a/arch/arm/dts/rk3288-tinker.dtsi b/arch/arm/dts/rk3288-tinker.dtsi
> > index 2f816af47f..67a0374050 100644
> > --- a/arch/arm/dts/rk3288-tinker.dtsi
> > +++ b/arch/arm/dts/rk3288-tinker.dtsi
> > @@ -53,6 +53,21 @@
> >                 #clock-cells = <0>;
> >         };
> >
> > +       board_info: board-info {
> > +               tinker,pcbid0 = <&gpio2 8 GPIO_ACTIVE_HIGH>;
> > +               tinker,pcbid1 = <&gpio2 9 GPIO_ACTIVE_HIGH>;
> > +               tinker,pcbid2 = <&gpio2 10 GPIO_ACTIVE_HIGH>;
> > +               tinker,pid0 = <&gpio2 1 GPIO_ACTIVE_HIGH>;
> > +               tinker,pid1 = <&gpio2 2 GPIO_ACTIVE_HIGH>;
> > +               tinker,pid2 = <&gpio2 3 GPIO_ACTIVE_HIGH>;
> > +       };
> > +
> > +       board_control: board-control {
> > +               tinker,sdp = <&gpio6 5 GPIO_ACTIVE_HIGH>;
> > +               tinker,usblimit = <&gpio6 6 GPIO_ACTIVE_HIGH>;
> > +               tinker,maskemmc = <&gpio6 7 GPIO_ACTIVE_HIGH>;
> > +       };
> > +
>
> Need to move this into -u-boot.dtsi
>
> >         gpio-keys {
> >                 compatible = "gpio-keys";
> >                 autorepeat;
> > @@ -461,6 +476,10 @@
> >  };
> >
> >  &pinctrl {
> > +       /* Pins that are not explicitely used by any devices */
> > +       pinctrl-names = "default";
> > +       pinctrl-0 = <&tinker_pin_hog>;
> > +
> >         pcfg_pull_none_drv_8ma: pcfg-pull-none-drv-8ma {
> >                 drive-strength = <8>;
> >         };
> > @@ -482,6 +501,20 @@
> >                 };
> >         };
> >
> > +       hog {
> > +               tinker_pin_hog: tinker-pin-hog {
> > +                       rockchip,pins = <2 RK_PA1 RK_FUNC_GPIO &pcfg_pull_up>, /* project id 0 */
> > +                                       <2 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>, /* project id 1 */
> > +                                       <2 RK_PA3 RK_FUNC_GPIO &pcfg_pull_up>, /* project id 2 */
> > +                                       <2 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>, /* pcb id 0 */
> > +                                       <2 RK_PB1 RK_FUNC_GPIO &pcfg_pull_none>, /* pcb id 1 */
> > +                                       <2 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>, /* pcb id 2 */
> > +                                       <6 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>, /* sdp detect */
> > +                                       <6 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>, /* current limit */
> > +                                       <6 RK_PA7 RK_FUNC_GPIO &pcfg_pull_none>; /* emmc mask */
> > +               };
> > +       };
> > +
>
> hog node is legacy representation, so we need to have a proper node to
> define these.

This is not easy without create a driver. This is a way to make the
pinctrl work and used by other board too
>
> >         eth_phy {
> >                 eth_phy_pwr: eth-phy-pwr {
> >                         rockchip,pins = <0 6 RK_FUNC_GPIO &pcfg_pull_none>;
> > diff --git a/board/rockchip/tinker_rk3288/tinker-rk3288.c b/board/rockchip/tinker_rk3288/tinker-rk3288.c
> > index 7a0c3c997d..7c65521f55 100644
> > --- a/board/rockchip/tinker_rk3288/tinker-rk3288.c
> > +++ b/board/rockchip/tinker_rk3288/tinker-rk3288.c
> > @@ -5,12 +5,26 @@
> >
> >  #include <common.h>
> >  #include <dm.h>
> > +#include <dm/device-internal.h>
> > +#include <asm/gpio.h>
> > +#include <dt-bindings/pinctrl/rockchip.h>
> >  #include <env.h>
> >  #include <i2c_eeprom.h>
> >  #include <netdev.h>
> >  #include <asm/arch-rockchip/bootrom.h>
> >  #include <asm/io.h>
> >
> > +enum project_id {
> > +       tinker_board_s = 0,
> > +       tinker_board = 7,
> > +};
> > +
> > +enum pcb_id {
> > +       SR,
> > +       ER,
> > +       PR,
> > +};
> > +


In the old code pcb version are those
> >  static int get_ethaddr_from_eeprom(u8 *addr)
> >  {
> >         int ret;
> > @@ -23,10 +37,14 @@ static int get_ethaddr_from_eeprom(u8 *addr)
> >         return i2c_eeprom_read(dev, 0, addr, 6);
> >  }
> >
> > +int detect_board_init(void);
>
> Mark this function as static.
>

Ok

> > +
> >  int rk3288_board_late_init(void)
> >  {
> >         u8 ethaddr[6];
> >
> > +       detect_board_init();
> > +
> >         if (get_ethaddr_from_eeprom(ethaddr))
> >                 return 0;
> >
> > @@ -45,3 +63,68 @@ int mmc_get_env_dev(void)
> >
> >         return 1;
> >  }
> > +
> > +int detect_board_init(void)
> > +{
> > +       int ret = 0, i;
> > +       ofnode node;
> > +       struct udevice *gpio_dev2 = NULL;
> > +       struct udevice *gpio_dev6 = NULL;
> > +       struct gpio_desc pcbid[3];
> > +       struct gpio_desc pid[3];
> > +       enum project_id prjid;
> > +       char gpio_name[64];
> > +       enum pcb_id pcbversion;
> > +
> > +       debug("%s: detect boad\n", __func__);
> > +
> > +       if (uclass_get_device_by_name(UCLASS_GPIO, "gpio2@ff790000", &gpio_dev2) ||
> > +           uclass_get_device_by_name(UCLASS_GPIO, "gpio6@ff7d0000", &gpio_dev6)) {
> > +               printf("Could not get GPIO device.\n");
> > +               return -EINVAL;
> > +       }
> > +
> > +       ret = device_probe(gpio_dev2);
> > +       if (ret)
> > +               pr_err("%s - probe failed: %d\n", gpio_dev2->name, ret);
> > +
> > +       ret = device_probe(gpio_dev6);
> > +       if (ret)
> > +               pr_err("%s - probe failed: %d\n", gpio_dev6->name, ret);
> > +
> > +       node = ofnode_path("/board-info");
> > +       if (!ofnode_valid(node)) {
> > +               pr_err("%s: no /board-info node?\n", __func__);
> > +               return -EINVAL;
> > +       }
> > +
> > +       for (i = 0; i < 3; i++) {
> > +               snprintf(gpio_name, 64, "tinker,pid%d", i);
> > +               if (gpio_request_by_name_nodev(node, gpio_name, 0,
> > +                                       &pid[i], GPIOD_IS_IN)) {
> > +                       printf("Failed to request %s\n", gpio_name);
> > +                       continue;
> > +               }
> > +        }
> > +
> > +       for (i = 0; i < 3; i++) {
> > +               snprintf(gpio_name, 64, "tinker,pcbid%d", i);
> > +               if (gpio_request_by_name_nodev(node, gpio_name, 0,
> > +                                               &pcbid[i], GPIOD_IS_IN)) {
> > +                       printf("Failed to request %s\n", gpio_name);
> > +                       continue;
> > +               }
> > +        }
> > +
> > +       prjid = dm_gpio_get_value(&pid[0]) | \
> > +               dm_gpio_get_value(&pid[1]) << 1 | \
> > +               dm_gpio_get_value(&pid[2]) << 2;
> > +       pcbversion = dm_gpio_get_value(&pcbid[0]) | \
> > +               dm_gpio_get_value(&pcbid[1]) << 1 | \
> > +               dm_gpio_get_value(&pcbid[2]) << 2;
> > +
> > +       printf("Detect %s rev %d\n",
> > +               prjid == tinker_board ? "Tinker" : "Tinker S", pcbversion);
>
> I can see the output on my tinker as
> Detect Tinker rev 2
>
> But the back side of PCB show REV 1.2 any clue?

Understand, I should ask to asus

Michael
Michael Nazzareno Trimarchi Nov. 18, 2019, 9:36 p.m. UTC | #3
Hi

On Mon, Nov 18, 2019 at 04:55:02PM +0530, Jagan Teki wrote:
> On Sun, Nov 17, 2019 at 3:47 PM Michael Trimarchi
> <michael@amarulasolutions.com> wrote:
> >
> > Add a way to detect board id and pcb id.
> >
> > Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
> > ---
> >  arch/arm/dts/rk3288-tinker.dtsi              | 33 ++++++++
> >  board/rockchip/tinker_rk3288/tinker-rk3288.c | 83 ++++++++++++++++++++
> >  2 files changed, 116 insertions(+)
> >
> > diff --git a/arch/arm/dts/rk3288-tinker.dtsi b/arch/arm/dts/rk3288-tinker.dtsi

This is a way better

From 86cb476c82b0c5506ddd9fe2b9ec7126f3801e5c Mon Sep 17 00:00:00 2001
From: Michael Trimarchi <michael@amarulasolutions.com>
Date: Sun, 17 Nov 2019 11:11:59 +0100
Subject: [PATCH] rockchip: tinker: Add automatic board discovery

Add a way to detect board id and pcb id.

Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
---
 arch/arm/dts/rk3288-tinker.dtsi       |  32 ++++++
 arch/arm/mach-rockchip/rk3288/Kconfig |   4 +-
 drivers/board/Kconfig                 |   5 +
 drivers/board/Makefile                |   1 +
 drivers/board/tinker.c                | 148 ++++++++++++++++++++++++++
 drivers/board/tinker.h                |  16 +++
 6 files changed, 205 insertions(+), 1 deletion(-)
 create mode 100644 drivers/board/tinker.c
 create mode 100644 drivers/board/tinker.h

diff --git a/arch/arm/dts/rk3288-tinker.dtsi b/arch/arm/dts/rk3288-tinker.dtsi
index 2f816af47f..2704b18243 100644
--- a/arch/arm/dts/rk3288-tinker.dtsi
+++ b/arch/arm/dts/rk3288-tinker.dtsi
@@ -53,6 +53,26 @@
 		#clock-cells = <0>;
 	};
 
+	board_info: board-info {
+		compatible = "asus,board_tinker";
+		pinctrl-names = "default";
+		pinctrl-0 = <&board_pins>;
+
+		ver-gpios = <&gpio2 8 GPIO_ACTIVE_HIGH
+			     &gpio2 9 GPIO_ACTIVE_HIGH
+			     &gpio2 10 GPIO_ACTIVE_HIGH>;
+
+		board-gpios = <&gpio2 1 GPIO_ACTIVE_HIGH
+			       &gpio2 2 GPIO_ACTIVE_HIGH
+			       &gpio2 3 GPIO_ACTIVE_HIGH>;
+	};
+
+	board_control: board-control {
+		tinker,sdp = <&gpio6 5 GPIO_ACTIVE_HIGH>;
+		tinker,usblimit = <&gpio6 6 GPIO_ACTIVE_HIGH>;
+		tinker,maskemmc = <&gpio6 7 GPIO_ACTIVE_HIGH>;
+	};
+
 	gpio-keys {
 		compatible = "gpio-keys";
 		autorepeat;
@@ -461,6 +481,7 @@
 };
 
 &pinctrl {
+
 	pcfg_pull_none_drv_8ma: pcfg-pull-none-drv-8ma {
 		drive-strength = <8>;
 	};
@@ -482,6 +503,17 @@
 		};
 	};
 
+	board {
+		board_pins: board_pins {
+			rockchip,pins = <2 RK_PA1 RK_FUNC_GPIO &pcfg_pull_up>, /* project id 0 */
+					<2 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>, /* project id 1 */
+					<2 RK_PA3 RK_FUNC_GPIO &pcfg_pull_up>, /* project id 2 */
+					<2 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>, /* pcb id 0 */
+					<2 RK_PB1 RK_FUNC_GPIO &pcfg_pull_none>, /* pcb id 1 */
+					<2 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>; /* pcb id 2 */
+		};
+	};
+
 	eth_phy {
 		eth_phy_pwr: eth-phy-pwr {
 			rockchip,pins = <0 6 RK_FUNC_GPIO &pcfg_pull_none>;
diff --git a/arch/arm/mach-rockchip/rk3288/Kconfig b/arch/arm/mach-rockchip/rk3288/Kconfig
index afb62fca78..a08cffd74f 100644
--- a/arch/arm/mach-rockchip/rk3288/Kconfig
+++ b/arch/arm/mach-rockchip/rk3288/Kconfig
@@ -123,7 +123,9 @@ config TARGET_ROCK2
 
 config TARGET_TINKER_RK3288
 	bool "Tinker-RK3288"
-        select BOARD_LATE_INIT
+	select BOARD_LATE_INIT
+	select BOARD
+	select BOARD_TINKER
 	select TPL
 	help
 	  Tinker is a RK3288-based development board with 2 USB ports, HDMI,
diff --git a/drivers/board/Kconfig b/drivers/board/Kconfig
index 2a3fc9c049..5ab60c3f00 100644
--- a/drivers/board/Kconfig
+++ b/drivers/board/Kconfig
@@ -19,4 +19,9 @@ config BOARD_SANDBOX
 	help
 	  Support querying device information for the Sandbox boards.
 
+config BOARD_TINKER
+	bool "Enable board driver for Tinker board"
+	help
+	  Support querying device information for the Tinker boards.
+
 endif
diff --git a/drivers/board/Makefile b/drivers/board/Makefile
index c8dab4fa0b..20378e4186 100644
--- a/drivers/board/Makefile
+++ b/drivers/board/Makefile
@@ -5,3 +5,4 @@
 obj-$(CONFIG_BOARD) += board-uclass.o
 obj-$(CONFIG_BOARD_GAZERBEAM) += gazerbeam.o
 obj-$(CONFIG_BOARD_SANDBOX) += sandbox.o
+obj-$(CONFIG_BOARD_TINKER) += tinker.o
diff --git a/drivers/board/tinker.c b/drivers/board/tinker.c
new file mode 100644
index 0000000000..129835e3ce
--- /dev/null
+++ b/drivers/board/tinker.c
@@ -0,0 +1,148 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2019
+ * Michael Trimarchi, Amarula Solutions Sro , michael@amarulasolutions.com
+ *
+ */
+#include <common.h>
+#include <dm.h>
+#include <board.h>
+#include <asm/gpio.h>
+
+#include "tinker.h"
+
+/**
+ * struct board_tinker_priv - Private data structure for the tinker board
+ *				 driver.
+ * @pcbid_gpios:	GPIOs for the board's hardware variant GPIOs
+ * @projectid_gpios:	GPIOs for the board's hardware version GPIOs
+ * @board_id:		Container for the board's hardware variant
+ * @hwversion:		Container for the board's hardware version
+ */
+struct board_tinker_priv {
+	struct gpio_desc ver_gpios[3];
+	struct gpio_desc board_gpios[3];
+	int board_id;
+	int hwversion;
+};
+
+/**
+ * _read_hwversion() - Read the hardware version from the board.
+ * @dev: The board device for which to read the hardware version.
+ *
+ * The hardware version read from the board (from hard-wired GPIOs) is stored
+ * in the private data structure of the driver to be used by other driver
+ * methods.
+ *
+ * Return: 0 if OK, -ve on error.
+ */
+static int _read_hwversion(struct udevice *dev)
+{
+	struct board_tinker_priv *priv = dev_get_priv(dev);
+	int res;
+
+	res = gpio_request_list_by_name(dev, "ver-gpios", priv->ver_gpios,
+					ARRAY_SIZE(priv->ver_gpios),
+					GPIOD_IS_IN);
+	if (res < 0) {
+		debug("%s: Error getting GPIO list 'ver-gpios' (err = %d)\n",
+		      dev->name, res);
+		return -ENODEV;
+	}
+
+	res = dm_gpio_get_values_as_int(priv->ver_gpios,
+					ARRAY_SIZE(priv->ver_gpios));
+	if (res < 0) {
+		debug("%s: Error reading HW version from expander (err = %d)\n",
+		      dev->name, res);
+		return res;
+	}
+
+	priv->hwversion = res;
+
+	res = gpio_request_list_by_name(dev, "board-gpios", priv->board_gpios,
+					ARRAY_SIZE(priv->board_gpios),
+					GPIOD_IS_IN);
+	if (res < 0) {
+		debug("%s: Error getting GPIO list 'ver-gpios' (err = %d)\n",
+		      dev->name, res);
+		return -ENODEV;
+	}
+
+	res = dm_gpio_get_values_as_int(priv->board_gpios,
+					ARRAY_SIZE(priv->board_gpios));
+	if (res < 0) {
+		debug("%s: Error reading HW version from expander (err = %d)\n",
+		      dev->name, res);
+		return res;
+	}
+
+
+	priv->board_id = res;
+
+	res = gpio_free_list(dev, priv->board_gpios, ARRAY_SIZE(priv->board_gpios));
+	if (res < 0) {
+		debug("%s: Error freeing HW version GPIO list (err = %d)\n",
+		      dev->name, res);
+		return res;
+	}
+
+	return 0;
+}
+
+static int board_tinker_detect(struct udevice *dev)
+{
+	int res;
+
+	res = _read_hwversion(dev);
+	if (res) {
+		debug("%s: Error reading hardware version (err = %d)\n",
+		      dev->name, res);
+		return res;
+	}
+
+	return 0;
+}
+
+static int board_tinker_get_int(struct udevice *dev, int id, int *val)
+{
+	struct board_tinker_priv *priv = dev_get_priv(dev);
+
+	switch (id) {
+	case BOARD_HWVERSION:
+		*val = priv->hwversion;
+		break;
+	case BOARD_VARIANT:
+		*val = priv->board_id;
+		break;
+	default:
+		debug("%s: Integer value %d unknown\n", dev->name, id);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct udevice_id board_tinker_ids[] = {
+	{ .compatible = "asus,board_tinker" },
+	{ /* sentinel */ }
+};
+
+static const struct board_ops board_tinker_ops = {
+	.detect = board_tinker_detect,
+	.get_int = board_tinker_get_int,
+};
+
+static int board_tinker_probe(struct udevice *dev)
+{
+	return 0;
+}
+
+U_BOOT_DRIVER(board_tinker) = {
+	.name           = "board_tinker",
+	.id             = UCLASS_BOARD,
+	.of_match       = board_tinker_ids,
+	.ops		= &board_tinker_ops,
+	.priv_auto_alloc_size = sizeof(struct board_tinker_priv),
+	.probe          = board_tinker_probe,
+};
diff --git a/drivers/board/tinker.h b/drivers/board/tinker.h
new file mode 100644
index 0000000000..817ec5282c
--- /dev/null
+++ b/drivers/board/tinker.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2019
+ * Michael Trimarchi, Amarula Solutions Sro , michael@amarulasolutions.com
+ *
+ */
+
+enum {
+	BOARD_VARIANT,
+	BOARD_HWVERSION,
+};
+
+enum {
+	VAR_TINKER,
+	VAR_TINKERS,
+};
Kever Yang Nov. 19, 2019, 12:39 a.m. UTC | #4
On 2019/11/17 下午6:17, Michael Trimarchi wrote:
> Add a way to detect board id and pcb id.


Is there a document for this from vendor? Are they also use these two ids?

If we can detect tinker vs tinker-s, then we don't need two board 
config/dts, right?

>
> Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
> ---
>   arch/arm/dts/rk3288-tinker.dtsi              | 33 ++++++++
>   board/rockchip/tinker_rk3288/tinker-rk3288.c | 83 ++++++++++++++++++++
>   2 files changed, 116 insertions(+)
>
> diff --git a/arch/arm/dts/rk3288-tinker.dtsi b/arch/arm/dts/rk3288-tinker.dtsi
> index 2f816af47f..67a0374050 100644
> --- a/arch/arm/dts/rk3288-tinker.dtsi
> +++ b/arch/arm/dts/rk3288-tinker.dtsi
> @@ -53,6 +53,21 @@
>   		#clock-cells = <0>;
>   	};
>   
> +	board_info: board-info {
> +		tinker,pcbid0 = <&gpio2 8 GPIO_ACTIVE_HIGH>;
> +		tinker,pcbid1 = <&gpio2 9 GPIO_ACTIVE_HIGH>;
> +		tinker,pcbid2 = <&gpio2 10 GPIO_ACTIVE_HIGH>;
> +		tinker,pid0 = <&gpio2 1 GPIO_ACTIVE_HIGH>;
> +		tinker,pid1 = <&gpio2 2 GPIO_ACTIVE_HIGH>;
> +		tinker,pid2 = <&gpio2 3 GPIO_ACTIVE_HIGH>;
> +	};
> +
> +	board_control: board-control {
> +		tinker,sdp = <&gpio6 5 GPIO_ACTIVE_HIGH>;
> +		tinker,usblimit = <&gpio6 6 GPIO_ACTIVE_HIGH>;
> +		tinker,maskemmc = <&gpio6 7 GPIO_ACTIVE_HIGH>;

These three pin looks like not related to board detect?


Thanks,

- Kever

> +	};
> +
>   	gpio-keys {
>   		compatible = "gpio-keys";
>   		autorepeat;
> @@ -461,6 +476,10 @@
>   };
>   
>   &pinctrl {
> +	/* Pins that are not explicitely used by any devices */
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&tinker_pin_hog>;
> +
>   	pcfg_pull_none_drv_8ma: pcfg-pull-none-drv-8ma {
>   		drive-strength = <8>;
>   	};
> @@ -482,6 +501,20 @@
>   		};
>   	};
>   
> +	hog {
> +		tinker_pin_hog: tinker-pin-hog {
> +			rockchip,pins = <2 RK_PA1 RK_FUNC_GPIO &pcfg_pull_up>, /* project id 0 */
> +					<2 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>, /* project id 1 */
> +					<2 RK_PA3 RK_FUNC_GPIO &pcfg_pull_up>, /* project id 2 */
> +					<2 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>, /* pcb id 0 */
> +					<2 RK_PB1 RK_FUNC_GPIO &pcfg_pull_none>, /* pcb id 1 */
> +					<2 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>, /* pcb id 2 */
> +					<6 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>, /* sdp detect */
> +					<6 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>, /* current limit */
> +					<6 RK_PA7 RK_FUNC_GPIO &pcfg_pull_none>; /* emmc mask */
> +		};
> +	};
> +
>   	eth_phy {
>   		eth_phy_pwr: eth-phy-pwr {
>   			rockchip,pins = <0 6 RK_FUNC_GPIO &pcfg_pull_none>;
> diff --git a/board/rockchip/tinker_rk3288/tinker-rk3288.c b/board/rockchip/tinker_rk3288/tinker-rk3288.c
> index 7a0c3c997d..7c65521f55 100644
> --- a/board/rockchip/tinker_rk3288/tinker-rk3288.c
> +++ b/board/rockchip/tinker_rk3288/tinker-rk3288.c
> @@ -5,12 +5,26 @@
>   
>   #include <common.h>
>   #include <dm.h>
> +#include <dm/device-internal.h>
> +#include <asm/gpio.h>
> +#include <dt-bindings/pinctrl/rockchip.h>
>   #include <env.h>
>   #include <i2c_eeprom.h>
>   #include <netdev.h>
>   #include <asm/arch-rockchip/bootrom.h>
>   #include <asm/io.h>
>   
> +enum project_id {
> +	tinker_board_s = 0,
> +	tinker_board = 7,
> +};
> +
> +enum pcb_id {
> +	SR,
> +	ER,
> +	PR,
> +};
> +
>   static int get_ethaddr_from_eeprom(u8 *addr)
>   {
>   	int ret;
> @@ -23,10 +37,14 @@ static int get_ethaddr_from_eeprom(u8 *addr)
>   	return i2c_eeprom_read(dev, 0, addr, 6);
>   }
>   
> +int detect_board_init(void);
> +
>   int rk3288_board_late_init(void)
>   {
>   	u8 ethaddr[6];
>   
> +	detect_board_init();
> +
>   	if (get_ethaddr_from_eeprom(ethaddr))
>   		return 0;
>   
> @@ -45,3 +63,68 @@ int mmc_get_env_dev(void)
>   
>   	return 1;
>   }
> +
> +int detect_board_init(void)
> +{
> +	int ret = 0, i;
> +	ofnode node;
> +	struct udevice *gpio_dev2 = NULL;
> +	struct udevice *gpio_dev6 = NULL;
> +	struct gpio_desc pcbid[3];
> +	struct gpio_desc pid[3];
> +	enum project_id prjid;
> +	char gpio_name[64];
> +	enum pcb_id pcbversion;
> +
> +	debug("%s: detect boad\n", __func__);
> +
> +	if (uclass_get_device_by_name(UCLASS_GPIO, "gpio2@ff790000", &gpio_dev2) ||
> +	    uclass_get_device_by_name(UCLASS_GPIO, "gpio6@ff7d0000", &gpio_dev6)) {
> +		printf("Could not get GPIO device.\n");
> +		return -EINVAL;
> +	}
> +
> +	ret = device_probe(gpio_dev2);
> +	if (ret)
> +		pr_err("%s - probe failed: %d\n", gpio_dev2->name, ret);
> +
> +	ret = device_probe(gpio_dev6);
> +	if (ret)
> +		pr_err("%s - probe failed: %d\n", gpio_dev6->name, ret);
> +
> +	node = ofnode_path("/board-info");
> +	if (!ofnode_valid(node)) {
> +		pr_err("%s: no /board-info node?\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	for (i = 0; i < 3; i++) {
> +		snprintf(gpio_name, 64, "tinker,pid%d", i);
> +		if (gpio_request_by_name_nodev(node, gpio_name, 0,
> +					&pid[i], GPIOD_IS_IN)) {
> +			printf("Failed to request %s\n", gpio_name);
> +			continue;
> +		}
> +        }
> +
> +	for (i = 0; i < 3; i++) {
> +		snprintf(gpio_name, 64, "tinker,pcbid%d", i);
> +		if (gpio_request_by_name_nodev(node, gpio_name, 0,
> +						&pcbid[i], GPIOD_IS_IN)) {
> +			printf("Failed to request %s\n", gpio_name);
> +			continue;
> +		}
> +        }
> +
> +	prjid = dm_gpio_get_value(&pid[0]) | \
> +		dm_gpio_get_value(&pid[1]) << 1 | \
> +		dm_gpio_get_value(&pid[2]) << 2;
> +	pcbversion = dm_gpio_get_value(&pcbid[0]) | \
> +		dm_gpio_get_value(&pcbid[1]) << 1 | \
> +		dm_gpio_get_value(&pcbid[2]) << 2;
> +
> +	printf("Detect %s rev %d\n",
> +		prjid == tinker_board ? "Tinker" : "Tinker S", pcbversion);
> +
> +	return ret;
> +}
Michael Nazzareno Trimarchi Nov. 19, 2019, 7:01 a.m. UTC | #5
Hi Kever

On Tue, Nov 19, 2019 at 1:40 AM Kever Yang <kever.yang@rock-chips.com> wrote:
>
>
> On 2019/11/17 下午6:17, Michael Trimarchi wrote:
> > Add a way to detect board id and pcb id.
>
>
> Is there a document for this from vendor? Are they also use these two ids?
>
> If we can detect tinker vs tinker-s, then we don't need two board
> config/dts, right?
>

I'm working to test on some tinker board. I was having only tinker-s.
I prefer to have
both board support and then clean-up after I'm sure

> >
> > Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
> > ---
> >   arch/arm/dts/rk3288-tinker.dtsi              | 33 ++++++++
> >   board/rockchip/tinker_rk3288/tinker-rk3288.c | 83 ++++++++++++++++++++
> >   2 files changed, 116 insertions(+)
> >
> > diff --git a/arch/arm/dts/rk3288-tinker.dtsi b/arch/arm/dts/rk3288-tinker.dtsi
> > index 2f816af47f..67a0374050 100644
> > --- a/arch/arm/dts/rk3288-tinker.dtsi
> > +++ b/arch/arm/dts/rk3288-tinker.dtsi
> > @@ -53,6 +53,21 @@
> >               #clock-cells = <0>;
> >       };
> >
> > +     board_info: board-info {
> > +             tinker,pcbid0 = <&gpio2 8 GPIO_ACTIVE_HIGH>;
> > +             tinker,pcbid1 = <&gpio2 9 GPIO_ACTIVE_HIGH>;
> > +             tinker,pcbid2 = <&gpio2 10 GPIO_ACTIVE_HIGH>;
> > +             tinker,pid0 = <&gpio2 1 GPIO_ACTIVE_HIGH>;
> > +             tinker,pid1 = <&gpio2 2 GPIO_ACTIVE_HIGH>;
> > +             tinker,pid2 = <&gpio2 3 GPIO_ACTIVE_HIGH>;
> > +     };
> > +
> > +     board_control: board-control {
> > +             tinker,sdp = <&gpio6 5 GPIO_ACTIVE_HIGH>;
> > +             tinker,usblimit = <&gpio6 6 GPIO_ACTIVE_HIGH>;
> > +             tinker,maskemmc = <&gpio6 7 GPIO_ACTIVE_HIGH>;
>
> These three pin looks like not related to board detect?
>

I take from debian_uboot. I'm going to manage those pins and drop from
this patch

Michael

>
> Thanks,
>
> - Kever
>
> > +     };
> > +
> >       gpio-keys {
> >               compatible = "gpio-keys";
> >               autorepeat;
> > @@ -461,6 +476,10 @@
> >   };
> >
> >   &pinctrl {
> > +     /* Pins that are not explicitely used by any devices */
> > +     pinctrl-names = "default";
> > +     pinctrl-0 = <&tinker_pin_hog>;
> > +
> >       pcfg_pull_none_drv_8ma: pcfg-pull-none-drv-8ma {
> >               drive-strength = <8>;
> >       };
> > @@ -482,6 +501,20 @@
> >               };
> >       };
> >
> > +     hog {
> > +             tinker_pin_hog: tinker-pin-hog {
> > +                     rockchip,pins = <2 RK_PA1 RK_FUNC_GPIO &pcfg_pull_up>, /* project id 0 */
> > +                                     <2 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>, /* project id 1 */
> > +                                     <2 RK_PA3 RK_FUNC_GPIO &pcfg_pull_up>, /* project id 2 */
> > +                                     <2 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>, /* pcb id 0 */
> > +                                     <2 RK_PB1 RK_FUNC_GPIO &pcfg_pull_none>, /* pcb id 1 */
> > +                                     <2 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>, /* pcb id 2 */
> > +                                     <6 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>, /* sdp detect */
> > +                                     <6 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>, /* current limit */
> > +                                     <6 RK_PA7 RK_FUNC_GPIO &pcfg_pull_none>; /* emmc mask */
> > +             };
> > +     };
> > +
> >       eth_phy {
> >               eth_phy_pwr: eth-phy-pwr {
> >                       rockchip,pins = <0 6 RK_FUNC_GPIO &pcfg_pull_none>;
> > diff --git a/board/rockchip/tinker_rk3288/tinker-rk3288.c b/board/rockchip/tinker_rk3288/tinker-rk3288.c
> > index 7a0c3c997d..7c65521f55 100644
> > --- a/board/rockchip/tinker_rk3288/tinker-rk3288.c
> > +++ b/board/rockchip/tinker_rk3288/tinker-rk3288.c
> > @@ -5,12 +5,26 @@
> >
> >   #include <common.h>
> >   #include <dm.h>
> > +#include <dm/device-internal.h>
> > +#include <asm/gpio.h>
> > +#include <dt-bindings/pinctrl/rockchip.h>
> >   #include <env.h>
> >   #include <i2c_eeprom.h>
> >   #include <netdev.h>
> >   #include <asm/arch-rockchip/bootrom.h>
> >   #include <asm/io.h>
> >
> > +enum project_id {
> > +     tinker_board_s = 0,
> > +     tinker_board = 7,
> > +};
> > +
> > +enum pcb_id {
> > +     SR,
> > +     ER,
> > +     PR,
> > +};
> > +
> >   static int get_ethaddr_from_eeprom(u8 *addr)
> >   {
> >       int ret;
> > @@ -23,10 +37,14 @@ static int get_ethaddr_from_eeprom(u8 *addr)
> >       return i2c_eeprom_read(dev, 0, addr, 6);
> >   }
> >
> > +int detect_board_init(void);
> > +
> >   int rk3288_board_late_init(void)
> >   {
> >       u8 ethaddr[6];
> >
> > +     detect_board_init();
> > +
> >       if (get_ethaddr_from_eeprom(ethaddr))
> >               return 0;
> >
> > @@ -45,3 +63,68 @@ int mmc_get_env_dev(void)
> >
> >       return 1;
> >   }
> > +
> > +int detect_board_init(void)
> > +{
> > +     int ret = 0, i;
> > +     ofnode node;
> > +     struct udevice *gpio_dev2 = NULL;
> > +     struct udevice *gpio_dev6 = NULL;
> > +     struct gpio_desc pcbid[3];
> > +     struct gpio_desc pid[3];
> > +     enum project_id prjid;
> > +     char gpio_name[64];
> > +     enum pcb_id pcbversion;
> > +
> > +     debug("%s: detect boad\n", __func__);
> > +
> > +     if (uclass_get_device_by_name(UCLASS_GPIO, "gpio2@ff790000", &gpio_dev2) ||
> > +         uclass_get_device_by_name(UCLASS_GPIO, "gpio6@ff7d0000", &gpio_dev6)) {
> > +             printf("Could not get GPIO device.\n");
> > +             return -EINVAL;
> > +     }
> > +
> > +     ret = device_probe(gpio_dev2);
> > +     if (ret)
> > +             pr_err("%s - probe failed: %d\n", gpio_dev2->name, ret);
> > +
> > +     ret = device_probe(gpio_dev6);
> > +     if (ret)
> > +             pr_err("%s - probe failed: %d\n", gpio_dev6->name, ret);
> > +
> > +     node = ofnode_path("/board-info");
> > +     if (!ofnode_valid(node)) {
> > +             pr_err("%s: no /board-info node?\n", __func__);
> > +             return -EINVAL;
> > +     }
> > +
> > +     for (i = 0; i < 3; i++) {
> > +             snprintf(gpio_name, 64, "tinker,pid%d", i);
> > +             if (gpio_request_by_name_nodev(node, gpio_name, 0,
> > +                                     &pid[i], GPIOD_IS_IN)) {
> > +                     printf("Failed to request %s\n", gpio_name);
> > +                     continue;
> > +             }
> > +        }
> > +
> > +     for (i = 0; i < 3; i++) {
> > +             snprintf(gpio_name, 64, "tinker,pcbid%d", i);
> > +             if (gpio_request_by_name_nodev(node, gpio_name, 0,
> > +                                             &pcbid[i], GPIOD_IS_IN)) {
> > +                     printf("Failed to request %s\n", gpio_name);
> > +                     continue;
> > +             }
> > +        }
> > +
> > +     prjid = dm_gpio_get_value(&pid[0]) | \
> > +             dm_gpio_get_value(&pid[1]) << 1 | \
> > +             dm_gpio_get_value(&pid[2]) << 2;
> > +     pcbversion = dm_gpio_get_value(&pcbid[0]) | \
> > +             dm_gpio_get_value(&pcbid[1]) << 1 | \
> > +             dm_gpio_get_value(&pcbid[2]) << 2;
> > +
> > +     printf("Detect %s rev %d\n",
> > +             prjid == tinker_board ? "Tinker" : "Tinker S", pcbversion);
> > +
> > +     return ret;
> > +}
>
>
diff mbox series

Patch

diff --git a/arch/arm/dts/rk3288-tinker.dtsi b/arch/arm/dts/rk3288-tinker.dtsi
index 2f816af47f..67a0374050 100644
--- a/arch/arm/dts/rk3288-tinker.dtsi
+++ b/arch/arm/dts/rk3288-tinker.dtsi
@@ -53,6 +53,21 @@ 
 		#clock-cells = <0>;
 	};
 
+	board_info: board-info {
+		tinker,pcbid0 = <&gpio2 8 GPIO_ACTIVE_HIGH>;
+		tinker,pcbid1 = <&gpio2 9 GPIO_ACTIVE_HIGH>;
+		tinker,pcbid2 = <&gpio2 10 GPIO_ACTIVE_HIGH>;
+		tinker,pid0 = <&gpio2 1 GPIO_ACTIVE_HIGH>;
+		tinker,pid1 = <&gpio2 2 GPIO_ACTIVE_HIGH>;
+		tinker,pid2 = <&gpio2 3 GPIO_ACTIVE_HIGH>;
+	};
+
+	board_control: board-control {
+		tinker,sdp = <&gpio6 5 GPIO_ACTIVE_HIGH>;
+		tinker,usblimit = <&gpio6 6 GPIO_ACTIVE_HIGH>;
+		tinker,maskemmc = <&gpio6 7 GPIO_ACTIVE_HIGH>;
+	};
+
 	gpio-keys {
 		compatible = "gpio-keys";
 		autorepeat;
@@ -461,6 +476,10 @@ 
 };
 
 &pinctrl {
+	/* Pins that are not explicitely used by any devices */
+	pinctrl-names = "default";
+	pinctrl-0 = <&tinker_pin_hog>;
+
 	pcfg_pull_none_drv_8ma: pcfg-pull-none-drv-8ma {
 		drive-strength = <8>;
 	};
@@ -482,6 +501,20 @@ 
 		};
 	};
 
+	hog {
+		tinker_pin_hog: tinker-pin-hog {
+			rockchip,pins = <2 RK_PA1 RK_FUNC_GPIO &pcfg_pull_up>, /* project id 0 */
+					<2 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>, /* project id 1 */
+					<2 RK_PA3 RK_FUNC_GPIO &pcfg_pull_up>, /* project id 2 */
+					<2 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>, /* pcb id 0 */
+					<2 RK_PB1 RK_FUNC_GPIO &pcfg_pull_none>, /* pcb id 1 */
+					<2 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>, /* pcb id 2 */
+					<6 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>, /* sdp detect */
+					<6 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>, /* current limit */
+					<6 RK_PA7 RK_FUNC_GPIO &pcfg_pull_none>; /* emmc mask */
+		};
+	};
+
 	eth_phy {
 		eth_phy_pwr: eth-phy-pwr {
 			rockchip,pins = <0 6 RK_FUNC_GPIO &pcfg_pull_none>;
diff --git a/board/rockchip/tinker_rk3288/tinker-rk3288.c b/board/rockchip/tinker_rk3288/tinker-rk3288.c
index 7a0c3c997d..7c65521f55 100644
--- a/board/rockchip/tinker_rk3288/tinker-rk3288.c
+++ b/board/rockchip/tinker_rk3288/tinker-rk3288.c
@@ -5,12 +5,26 @@ 
 
 #include <common.h>
 #include <dm.h>
+#include <dm/device-internal.h>
+#include <asm/gpio.h>
+#include <dt-bindings/pinctrl/rockchip.h>
 #include <env.h>
 #include <i2c_eeprom.h>
 #include <netdev.h>
 #include <asm/arch-rockchip/bootrom.h>
 #include <asm/io.h>
 
+enum project_id {
+	tinker_board_s = 0,
+	tinker_board = 7,
+};
+
+enum pcb_id {
+	SR,
+	ER,
+	PR,
+};
+
 static int get_ethaddr_from_eeprom(u8 *addr)
 {
 	int ret;
@@ -23,10 +37,14 @@  static int get_ethaddr_from_eeprom(u8 *addr)
 	return i2c_eeprom_read(dev, 0, addr, 6);
 }
 
+int detect_board_init(void);
+
 int rk3288_board_late_init(void)
 {
 	u8 ethaddr[6];
 
+	detect_board_init();
+
 	if (get_ethaddr_from_eeprom(ethaddr))
 		return 0;
 
@@ -45,3 +63,68 @@  int mmc_get_env_dev(void)
 
 	return 1;
 }
+
+int detect_board_init(void)
+{
+	int ret = 0, i;
+	ofnode node;
+	struct udevice *gpio_dev2 = NULL;
+	struct udevice *gpio_dev6 = NULL;
+	struct gpio_desc pcbid[3];
+	struct gpio_desc pid[3];
+	enum project_id prjid;
+	char gpio_name[64];
+	enum pcb_id pcbversion;
+
+	debug("%s: detect boad\n", __func__);
+
+	if (uclass_get_device_by_name(UCLASS_GPIO, "gpio2@ff790000", &gpio_dev2) ||
+	    uclass_get_device_by_name(UCLASS_GPIO, "gpio6@ff7d0000", &gpio_dev6)) {
+		printf("Could not get GPIO device.\n");
+		return -EINVAL;
+	}
+
+	ret = device_probe(gpio_dev2);
+	if (ret)
+		pr_err("%s - probe failed: %d\n", gpio_dev2->name, ret);
+
+	ret = device_probe(gpio_dev6);
+	if (ret)
+		pr_err("%s - probe failed: %d\n", gpio_dev6->name, ret);
+
+	node = ofnode_path("/board-info");
+	if (!ofnode_valid(node)) {
+		pr_err("%s: no /board-info node?\n", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < 3; i++) {
+		snprintf(gpio_name, 64, "tinker,pid%d", i);
+		if (gpio_request_by_name_nodev(node, gpio_name, 0,
+					&pid[i], GPIOD_IS_IN)) {
+			printf("Failed to request %s\n", gpio_name);
+			continue;
+		}
+        }
+
+	for (i = 0; i < 3; i++) {
+		snprintf(gpio_name, 64, "tinker,pcbid%d", i);
+		if (gpio_request_by_name_nodev(node, gpio_name, 0,
+						&pcbid[i], GPIOD_IS_IN)) {
+			printf("Failed to request %s\n", gpio_name);
+			continue;
+		}
+        }
+
+	prjid = dm_gpio_get_value(&pid[0]) | \
+		dm_gpio_get_value(&pid[1]) << 1 | \
+		dm_gpio_get_value(&pid[2]) << 2;
+	pcbversion = dm_gpio_get_value(&pcbid[0]) | \
+		dm_gpio_get_value(&pcbid[1]) << 1 | \
+		dm_gpio_get_value(&pcbid[2]) << 2;
+
+	printf("Detect %s rev %d\n",
+		prjid == tinker_board ? "Tinker" : "Tinker S", pcbversion);
+
+	return ret;
+}