Skip to contentSkip to conversation

dm: imx: Add driver model support for GPIO and serial on cm_fx6

PATCH Superseded Simon Glass 4 participants 26 messages Sep 17, 2014 – Oct 2, 2014

Subsystems (4)

v3 of 4 Superseded Latest is v4 →

lore
Share & tools
lore
#0 lore raw

v3 cover dm: imx: Add driver model support for GPIO and serial on cm_fx6

This series adjusts the IMX serial and GPIO drivers to support driver model. As an example of its use, the recently-added cm_fx6 board is converted over to driver model.

Some minor driver model core changed are required to make this work and these are included with this series.

Changes in v3:
- Add a check for the Ethernet gpio_request() also
- Add a comment for the CONFIG_SPL_BUILD #ifdef
- Just warn when one of the board init stages fails
- Use gpio_is_requested() in one more place

Changes in v2:
- Add an internal function to check if a GPIO is requested
- Add new patch to add error checking to setup_i2c()
- Add patch to display error number when an error occurs in initcall
- Change 'reserved' to 'requested'
- Check return values of gpio_request()
- Tidy up confusing code that creates names for gpio_request()
- Use the correct namespace for the platform data

Simon Glass (11):
dm: linker_lists: Add a way to declare multiple objects
dm: core: Allow a list of devices to be declared in one step
dm: core: Allow device_bind() to used without CONFIG_OF_CONTROL
initcall: Display error number when an error occurs
dm: serial: Don't require device tree to configure a console
dm: serial: Put common code into separate functions
imx: Add error checking to setup_i2c()
dm: imx: Use gpio_request() to request GPIOs
dm: imx: gpio: Support driver model in MXC gpio driver
dm: imx: serial: Support driver model in the MXC serial driver
dm: imx: Move cm_fx6 to use driver model for serial and GPIO

 arch/arm/imx-common/i2c-mxv7.c            |  48 ++++-
 arch/arm/include/asm/imx-common/mxc_i2c.h |   4 +-
 board/compulab/cm_fx6/cm_fx6.c            |  88 +++++++--
 board/compulab/cm_fx6/common.c            |   8 +
 drivers/core/device.c                     |   7 +-
 drivers/gpio/mxc_gpio.c                   | 304 +++++++++++++++++++++++++++++-
 drivers/serial/serial-uclass.c            |  35 ++--
 drivers/serial/serial_mxc.c               | 170 ++++++++++++++---
 include/configs/cm_fx6.h                  |  11 ++
 include/dm/platdata.h                     |   4 +
 include/linker_lists.h                    |  21 +++
 include/serial_mxc.h                      |  14 ++
 lib/initcall.c                            |   8 +-
 13 files changed, 657 insertions(+), 65 deletions(-)
 create mode 100644 include/serial_mxc.h
Signature · 1 line
2.1.0.rc2.206.gedb03e5
#1 lore raw

PATCH v3 1/11 dm: linker_lists: Add a way to declare multiple objects

The existing ll_entry_declare() permits a single element of the list to be added to a linker list. Sometimes we want to add several objects at once. To avoid lots of messy declarations, add a macro to support this.

---

Changes in v3: None
Changes in v2: None

 include/linker_lists.h | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)
include/linker_lists.h +21 -0
index 557e627..32cc9fc 100644
@@ -141,6 +141,27 @@
 			section(".u_boot_list_2_"#_list"_2_"#_name)))
 
 /**
+ * ll_entry_declare_list() - Declare a list of link-generated array entries
+ * @_type:	Data type of each entry
+ * @_name:	Name of the entry
+ * @_list:	name of the list. Should contain only characters allowed
+ *		in a C variable name!
+ *
+ * This is like ll_entry_declare() but creates multiple entries. It should
+ * be assigned to an array.
+ *
+ * ll_entry_declare_list(struct my_sub_cmd, my_sub_cmd, cmd_sub, cmd.sub) = {
+ *	{ .x = 3, .y = 4 },
+ *	{ .x = 8, .y = 2 },
+ *	{ .x = 1, .y = 7 }
+ * };
+ */
+#define ll_entry_declare_list(_type, _name, _list)			\
+	_type _u_boot_list_2_##_list##_2_##_name[] __aligned(4)		\
+			__attribute__((unused,				\
+			section(".u_boot_list_2_"#_list"_2_"#_name)))
+
+/**
  * We need a 0-byte-size type for iterator symbols, and the compiler
  * does not allow defining objects of C type 'void'. Using an empty
  * struct is allowed by the compiler, but causes gcc versions 4.4 and
Signature · 1 line
2.1.0.rc2.206.gedb03e5
#2 lore raw

PATCH v3 2/11 dm: core: Allow a list of devices to be declared in one step

In reply to Simon Glass

The U_BOOT_DEVICE macro allows the declaration of a single U-Boot device. Add an equivalent macro to declare an array of devices, for convenience.

---

Changes in v3: None
Changes in v2: None

 include/dm/platdata.h | 4 ++++
 1 file changed, 4 insertions(+)
include/dm/platdata.h +4 -0
index 2bc8b14..9e47e51 100644
@@ -25,4 +25,8 @@ struct driver_info {
 #define U_BOOT_DEVICE(__name)						\
 	ll_entry_declare(struct driver_info, __name, driver_info)
 
+/* Declare a list of devices. The argument is a driver_info[] array */
+#define U_BOOT_DEVICES(__name)						\
+	ll_entry_declare_list(struct driver_info, __name, driver_info)
+
 #endif
Signature · 1 line
2.1.0.rc2.206.gedb03e5
#3 lore raw

PATCH v3 3/11 dm: core: Allow device_bind() to used without CONFIG_OF_CONTROL

In reply to Simon Glass

The sequence number support in driver model requires device tree control. It should be skipped if CONFIG_OF_CONTROL is not defined, and should not require functions from fdtdec.

---

Changes in v3: None
Changes in v2: None

 drivers/core/device.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/core/device.c +5 -2
index 166b073..ef41a9b 100644
@@ -106,13 +106,16 @@ int device_bind(struct udevice *parent, struct driver *drv, const char *name,
 	 * a 'requested' sequence, and will be resolved (and ->seq updated)
 	 * when the device is probed.
 	 */
-	dev->req_seq = fdtdec_get_int(gd->fdt_blob, of_offset, "reg", -1);
 	dev->seq = -1;
+#ifdef CONFIG_OF_CONTROL
+	dev->req_seq = fdtdec_get_int(gd->fdt_blob, of_offset, "reg", -1);
 	if (uc->uc_drv->name && of_offset != -1) {
 		fdtdec_get_alias_seq(gd->fdt_blob, uc->uc_drv->name, of_offset,
 				     &dev->req_seq);
 	}
-
+#else
+	dev->req_seq = -1;
+#endif
 	if (!dev->platdata && drv->platdata_auto_alloc_size)
 		dev->flags |= DM_FLAG_ALLOC_PDATA;
 
Signature · 1 line
2.1.0.rc2.206.gedb03e5
#4 lore raw

PATCH v3 3/11 dm: core: Allow device_bind() to used without CONFIG_OF_CONTROL

Quoted 5 lines · Simon Glass

The sequence number support in driver model requires device tree control. It should be skipped if CONFIG_OF_CONTROL is not defined, and should not require functions from fdtdec.

Applied to u-boot-dm and now in mainline.

#5 lore raw

PATCH v3 4/11 initcall: Display error number when an error occurs

In reply to Simon Glass

Now that some initcall functions return a useful error number, display it when something goes wrong.

---

Changes in v3: None
Changes in v2:
- Add patch to display error number when an error occurs in initcall

 lib/initcall.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)
lib/initcall.c +5 -3
index 7597bad..39f4b3f 100644
@@ -15,14 +15,16 @@ int initcall_run_list(const init_fnc_t init_sequence[])
 
 	for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
 		unsigned long reloc_ofs = 0;
+		int ret;
 
 		if (gd->flags & GD_FLG_RELOC)
 			reloc_ofs = gd->reloc_off;
 		debug("initcall: %p\n", (char *)*init_fnc_ptr - reloc_ofs);
-		if ((*init_fnc_ptr)()) {
-			printf("initcall sequence %p failed at call %p\n",
+		ret = (*init_fnc_ptr)();
+		if (ret) {
+			printf("initcall sequence %p failed at call %p (err=%d)\n",
 			       init_sequence,
-			       (char *)*init_fnc_ptr - reloc_ofs);
+			       (char *)*init_fnc_ptr - reloc_ofs, ret);
 			return -1;
 		}
 	}
Signature · 1 line
2.1.0.rc2.206.gedb03e5
#6 lore raw

PATCH v3 5/11 dm: serial: Don't require device tree to configure a console

In reply to Simon Glass

Allow serial_find_console_or_panic() to work without a device tree.

---

Changes in v3: None
Changes in v2: None

 drivers/serial/serial-uclass.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/serial/serial-uclass.c +2 -1
index d04104e..1ac943f 100644
@@ -25,6 +25,7 @@ struct udevice *cur_dev __attribute__ ((section(".data")));
 
 static void serial_find_console_or_panic(void)
 {
+#ifdef CONFIG_OF_CONTROL
 	int node;
 
 	/* Check for a chosen console */
@@ -44,7 +45,7 @@ static void serial_find_console_or_panic(void)
 			return;
 		cur_dev = NULL;
 	}
-
+#endif
 	/*
 	 * Failing that, get the device with sequence number 0, or in extremis
 	 * just the first serial device we can find. But we insist on having
Signature · 1 line
2.1.0.rc2.206.gedb03e5
#7 lore raw

PATCH v3 5/11 dm: serial: Don't require device tree to configure a console

Quoted 3 lines · Simon Glass

Allow serial_find_console_or_panic() to work without a device tree.

Applied to u-boot-dm and now in mainline.

#8 lore raw

PATCH v3 6/11 dm: serial: Put common code into separate functions

In reply to Simon Glass

Avoid duplicating the code which deals with getc() and putc(). It is fairly simple, but may expand later.

---

Changes in v3: None
Changes in v2: None

 drivers/serial/serial-uclass.c | 32 +++++++++++++++++---------------
 1 file changed, 17 insertions(+), 15 deletions(-)
drivers/serial/serial-uclass.c +17 -15
index 1ac943f..e93c624 100644
@@ -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)
Signature · 1 line
2.1.0.rc2.206.gedb03e5
#9 lore raw

PATCH v3 7/11 imx: Add error checking to setup_i2c()

In reply to Simon Glass

Since this function can fail, check its return value.

---

Changes in v3:
- Just warn when one of the board init stages fails

Changes in v2:
- Add new patch to add error checking to setup_i2c()

 arch/arm/imx-common/i2c-mxv7.c            | 24 ++++++++++---
 arch/arm/include/asm/imx-common/mxc_i2c.h |  4 +--
 board/compulab/cm_fx6/cm_fx6.c            | 56 ++++++++++++++++++++++++++-----
 3 files changed, 68 insertions(+), 16 deletions(-)
arch/arm/imx-common/i2c-mxv7.c +19 -5
index a580873..70cff5c 100644
@@ -69,15 +69,29 @@ 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)
 {
+	int ret;
+
 	if (i2c_index >= ARRAY_SIZE(i2c_bases))
-		return;
+		return -EINVAL;
 	/* 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:
+	return ret;
 }
arch/arm/include/asm/imx-common/mxc_i2c.h +2 -2
index 182c2f3..af86163 100644
@@ -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,
board/compulab/cm_fx6/cm_fx6.c +47 -9

91 lines not on this page · raw message

Signature · 1 line
2.1.0.rc2.206.gedb03e5
#11 lore raw

PATCH v3 7/11 imx: Add error checking to setup_i2c()

In reply to Simon Glass
Quoted 160 lines · Simon Glass

Since this function can fail, check its return value.

---

Changes in v3:
- Just warn when one of the board init stages fails

Changes in v2:
- Add new patch to add error checking to setup_i2c()

 arch/arm/imx-common/i2c-mxv7.c            | 24 ++++++++++---
 arch/arm/include/asm/imx-common/mxc_i2c.h |  4 +--
 board/compulab/cm_fx6/cm_fx6.c            | 56 ++++++++++++++++++++++++++-----
 3 files changed, 68 insertions(+), 16 deletions(-)
arch/arm/imx-common/i2c-mxv7.c +19 -5
index a580873..70cff5c 100644
@@ -69,15 +69,29 @@ 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)
 {
+	int ret;
+
 	if (i2c_index >= ARRAY_SIZE(i2c_bases))
-		return;
+		return -EINVAL;
 	/* 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:
+	return ret;
 }
arch/arm/include/asm/imx-common/mxc_i2c.h +2 -2
index 182c2f3..af86163 100644
@@ -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,
board/compulab/cm_fx6/cm_fx6.c +42 -8
index fdb8ebf..10a568f 100644
@@ -69,7 +69,7 @@ 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 */
@@ -79,14 +79,24 @@ static void cm_fx6_setup_issd(void)
 	cm_fx6_sata_power(0);
 	mdelay(250);
 	cm_fx6_sata_power(1);
+
+	return 0;
 }
 
 #define CM_FX6_SATA_INIT_RETRIES	10
 int sata_initialize(void)
 {
-	int err, i;
+	int err, i, ret;
 
-	cm_fx6_setup_issd();
+	/*
+	 * 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!\n");
 	for (i = 0; i < CM_FX6_SATA_INIT_RETRIES; i++) {
 		err = setup_sata();
 		if (err) {
@@ -141,14 +151,36 @@ I2C_PADS(i2c2_pads,
 	 IMX_GPIO_NR(1, 6));
 
 
-static void cm_fx6_setup_i2c(void)
+static int cm_fx6_setup_one_i2c(int busnum, struct i2c_pads_info *pads)
+{
+	int ret;
+
+	ret = setup_i2c(busnum, CONFIG_SYS_I2C_SPEED, 0x7f, pads);
+	if (ret)
+		printf("Warning: I2C%d setup failed: %d\n", busnum, ret);
+
+	return ret;
+}
+
+static int cm_fx6_setup_i2c(void)
 {
-	setup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x7f, I2C_PADS_INFO(i2c0_pads));
-	setup_i2c(1, CONFIG_SYS_I2C_SPEED, 0x7f, I2C_PADS_INFO(i2c1_pads));
-	setup_i2c(2, CONFIG_SYS_I2C_SPEED, 0x7f, I2C_PADS_INFO(i2c2_pads));
+	int ret = 0, err;
+
+	/* i2c<x>_pads are wierd macro variables; we can't use an array */
+	err = cm_fx6_setup_one_i2c(0, I2C_PADS_INFO(i2c0_pads));
+	if (err)
+		ret = err;
+	err = cm_fx6_setup_one_i2c(1, I2C_PADS_INFO(i2c1_pads));
+	if (err)
+		ret = err;
+	err = cm_fx6_setup_one_i2c(2, I2C_PADS_INFO(i2c2_pads));
+	if (err)
+		ret = err;
+
+	return ret;
 }
 #else
-static void cm_fx6_setup_i2c(void) { }
+static int cm_fx6_setup_i2c(void) { return 0; }
 #endif
 
 #ifdef CONFIG_USB_EHCI_MX6
@@ -409,9 +441,15 @@ void ft_board_setup(void *blob, bd_t *bd)
 
 int board_init(void)
 {
+	int ret;
+
 	gd->bd->bi_boot_params = PHYS_SDRAM_1 + 0x100;

board/compulab/cm_fx6/cm_fx6.c void ft_board_setup(void *blob, bd_t *bd) · line 455

Quoted 10 lines
board/compulab/cm_fx6/cm_fx6.c +5 -1
 	cm_fx6_setup_gpmi_nand();
-	cm_fx6_setup_i2c();
+
+	/* 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;
 }

Thanks !

Best regards,
Stefano

Signature · 5 lines
=====================================================================
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-53 Fax: +49-8142-66989-80 Email: sbabic at denx.de
=====================================================================
#12 lore raw

PATCH v3 7/11 imx: Add error checking to setup_i2c()

In reply to Simon Glass

Hi Simon,

Quoted 100 lines · Simon Glass

Since this function can fail, check its return value.

---

Changes in v3:
- Just warn when one of the board init stages fails

Changes in v2:
- Add new patch to add error checking to setup_i2c()

  arch/arm/imx-common/i2c-mxv7.c            | 24 ++++++++++---
  arch/arm/include/asm/imx-common/mxc_i2c.h |  4 +--
  board/compulab/cm_fx6/cm_fx6.c            | 56 ++++++++++++++++++++++++++-----
  3 files changed, 68 insertions(+), 16 deletions(-)
arch/arm/imx-common/i2c-mxv7.c +19 -5
index a580873..70cff5c 100644
@@ -69,15 +69,29 @@ 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)
  {
+	int ret;
+
  	if (i2c_index >= ARRAY_SIZE(i2c_bases))
-		return;
+		return -EINVAL;
  	/* 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:
+	return ret;
  }
arch/arm/include/asm/imx-common/mxc_i2c.h +2 -2
index 182c2f3..af86163 100644
@@ -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,
board/compulab/cm_fx6/cm_fx6.c +6 -3
index fdb8ebf..10a568f 100644
@@ -69,7 +69,7 @@ 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 */
@@ -79,14 +79,24 @@ static void cm_fx6_setup_issd(void)
  	cm_fx6_sata_power(0);
  	mdelay(250);
  	cm_fx6_sata_power(1);
+
+	return 0;
  }
 
  #define CM_FX6_SATA_INIT_RETRIES	10
  int sata_initialize(void)
  {
-	int err, i;
+	int err, i, ret;
 
-	cm_fx6_setup_issd();
+	/*
+	 * cm-fx6 may have iSSD not assembled and in this case it has

board/compulab/cm_fx6/cm_fx6.c static void cm_fx6_setup_issd(void) · line 102

Quoted 10 lines
board/compulab/cm_fx6/cm_fx6.c +7 -0
+	 * 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!\n");
  	for (i = 0; i < CM_FX6_SATA_INIT_RETRIES; i++) {
  		err = setup_sata();
  		if (err) {

The issd stuff above is unrelated to the subject of this patch. It should be part of the next patch.

Aside from that,

Signature · 2 lines
Regards,
Nikita Kiryanov
#13 lore raw

PATCH v3 7/11 imx: Add error checking to setup_i2c()

Hi Nikita,

Quoted 127 lines · Nikita Kiryanov

Hi Simon,

Quoted 110 lines · Simon Glass

Since this function can fail, check its return value.

---

Changes in v3:
- Just warn when one of the board init stages fails

Changes in v2:
- Add new patch to add error checking to setup_i2c()

  arch/arm/imx-common/i2c-mxv7.c            | 24 ++++++++++---
  arch/arm/include/asm/imx-common/mxc_i2c.h |  4 +--
  board/compulab/cm_fx6/cm_fx6.c            | 56
++++++++++++++++++++++++++-----
  3 files changed, 68 insertions(+), 16 deletions(-)
arch/arm/imx-common/i2c-mxv7.c +19 -5
index a580873..70cff5c 100644
@@ -69,15 +69,29 @@ 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)
  {
+       int ret;
+
        if (i2c_index >= ARRAY_SIZE(i2c_bases))
-               return;
+               return -EINVAL;
        /* 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:
+       return ret;
  }
arch/arm/include/asm/imx-common/mxc_i2c.h +2 -2
index 182c2f3..af86163 100644
@@ -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,

board/compulab/cm_fx6/cm_fx6.c +1 -1
index fdb8ebf..10a568f 100644
@@ -69,7 +69,7 @@ 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 */
board/compulab/cm_fx6/cm_fx6.c +7 -2
@@ -79,14 +79,24 @@ static void cm_fx6_setup_issd(void)
        cm_fx6_sata_power(0);
        mdelay(250);
        cm_fx6_sata_power(1);
+
+       return 0;
  }
 
  #define CM_FX6_SATA_INIT_RETRIES      10
  int sata_initialize(void)
  {
-       int err, i;
+       int err, i, ret;
 
-       cm_fx6_setup_issd();
+       /*
+        * 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

board/compulab/cm_fx6/cm_fx6.c static void cm_fx6_setup_issd(void) · line 102

Quoted 8 lines
board/compulab/cm_fx6/cm_fx6.c +5 -0
+        * if the setup fails.
+        */
+       ret = cm_fx6_setup_issd();
+       if (ret)
+               printf("Warning: iSSD setup failed!\n");
        for (i = 0; i < CM_FX6_SATA_INIT_RETRIES; i++) {
                err = setup_sata();
                if (err) {

The issd stuff above is unrelated to the subject of this patch. It should be part of the next patch.

Quoted 3 lines

Aside from that,

Thanks - I'll take another look later on today.

Regards,
Simon

#14 lore raw

PATCH v3 8/11 dm: imx: Use gpio_request() to request GPIOs

In reply to Simon Glass

GPIOs should be requested before use. Without this, driver model will not permit the GPIO to be used.

---

Changes in v3:
- Add a check for the Ethernet gpio_request() also
- Add a comment for the CONFIG_SPL_BUILD #ifdef
- Just warn when one of the board init stages fails

Changes in v2:
- Check return values of gpio_request()

 arch/arm/imx-common/i2c-mxv7.c | 24 ++++++++++++++++++++++++
 board/compulab/cm_fx6/cm_fx6.c | 22 ++++++++++++++++++++--
 board/compulab/cm_fx6/common.c |  8 ++++++++
 3 files changed, 52 insertions(+), 2 deletions(-)
arch/arm/imx-common/i2c-mxv7.c +24 -0
index 70cff5c..aaf6936 100644
@@ -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>
@@ -72,10 +73,26 @@ static void * const i2c_bases[] = {
 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 -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 */
 	ret = enable_i2c_clk(1, i2c_index);
 	if (ret)
@@ -93,5 +110,12 @@ int setup_i2c(unsigned i2c_index, int speed, int slave_addr,
 
 err_idle:
 err_clk:
+	gpio_free(p->scl.gp);
+err_req2:
+	gpio_free(p->sda.gp);
+err_req1:
+	free(name1);
+	free(name2);
+
 	return ret;
 }
board/compulab/cm_fx6/cm_fx6.c +20 -2
index 10a568f..a089e82 100644
@@ -71,8 +71,21 @@ static iomux_v3_cfg_t const sata_pads[] = {
 
 static int cm_fx6_setup_issd(void)
 {
+	int ret;
+	int i;
+
 	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;
+	}
+
 	/* Make sure this gpio has logical 0 value */
+	ret = gpio_request(CM_FX6_SATA_PWLOSS_INT, "sata_pwloss_int");
+	if (ret)
+		return ret;
 	gpio_direction_output(CM_FX6_SATA_PWLOSS_INT, 0);
 	udelay(100);
 
@@ -350,12 +363,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);
board/compulab/cm_fx6/common.c +8 -0
index 1f39679..20b758b 100644
@@ -79,6 +79,14 @@ void cm_fx6_set_ecspi_iomux(void)
 
 int board_spi_cs_gpio(unsigned bus, unsigned cs)
 {
+	/* DM does not support SPL yet and this function is not implemented */
+#ifndef CONFIG_SPL_BUILD
+	int ret;
+
+	ret = gpio_request(CM_FX6_ECSPI_BUS0_CS0, "ecspi_bus0_cs0");
+	if (ret)
+		return ret;
+#endif
 	return (bus == 0 && cs == 0) ? (CM_FX6_ECSPI_BUS0_CS0) : -1;
 }
 #endif
Signature · 1 line
2.1.0.rc2.206.gedb03e5
#16 lore raw

PATCH v3 8/11 dm: imx: Use gpio_request() to request GPIOs

In reply to Simon Glass
Quoted 127 lines · Simon Glass

GPIOs should be requested before use. Without this, driver model will not permit the GPIO to be used.

---

Changes in v3:
- Add a check for the Ethernet gpio_request() also
- Add a comment for the CONFIG_SPL_BUILD #ifdef
- Just warn when one of the board init stages fails

Changes in v2:
- Check return values of gpio_request()

 arch/arm/imx-common/i2c-mxv7.c | 24 ++++++++++++++++++++++++
 board/compulab/cm_fx6/cm_fx6.c | 22 ++++++++++++++++++++--
 board/compulab/cm_fx6/common.c |  8 ++++++++
 3 files changed, 52 insertions(+), 2 deletions(-)
arch/arm/imx-common/i2c-mxv7.c +24 -0
index 70cff5c..aaf6936 100644
@@ -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>
@@ -72,10 +73,26 @@ static void * const i2c_bases[] = {
 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 -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 */
 	ret = enable_i2c_clk(1, i2c_index);
 	if (ret)
@@ -93,5 +110,12 @@ int setup_i2c(unsigned i2c_index, int speed, int slave_addr,
 
 err_idle:
 err_clk:
+	gpio_free(p->scl.gp);
+err_req2:
+	gpio_free(p->sda.gp);
+err_req1:
+	free(name1);
+	free(name2);
+
 	return ret;
 }
board/compulab/cm_fx6/cm_fx6.c +20 -2
index 10a568f..a089e82 100644
@@ -71,8 +71,21 @@ static iomux_v3_cfg_t const sata_pads[] = {
 
 static int cm_fx6_setup_issd(void)
 {
+	int ret;
+	int i;
+
 	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;
+	}
+
 	/* Make sure this gpio has logical 0 value */
+	ret = gpio_request(CM_FX6_SATA_PWLOSS_INT, "sata_pwloss_int");
+	if (ret)
+		return ret;
 	gpio_direction_output(CM_FX6_SATA_PWLOSS_INT, 0);
 	udelay(100);
 
@@ -350,12 +363,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);
board/compulab/cm_fx6/common.c +1 -0
index 1f39679..20b758b 100644
@@ -79,6 +79,14 @@ void cm_fx6_set_ecspi_iomux(void)
 
 int board_spi_cs_gpio(unsigned bus, unsigned cs)
 {
+	/* DM does not support SPL yet and this function is not implemented */

board/compulab/cm_fx6/common.c void cm_fx6_set_ecspi_iomux(void) · line 92

Quoted 10 lines
board/compulab/cm_fx6/common.c +7 -0
+#ifndef CONFIG_SPL_BUILD
+	int ret;
+
+	ret = gpio_request(CM_FX6_ECSPI_BUS0_CS0, "ecspi_bus0_cs0");
+	if (ret)
+		return ret;
+#endif
 	return (bus == 0 && cs == 0) ? (CM_FX6_ECSPI_BUS0_CS0) : -1;
 }
 #endif

Best regards,
Stefano Babic

Signature · 5 lines
=====================================================================
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-53 Fax: +49-8142-66989-80 Email: sbabic at denx.de
=====================================================================
#17 lore raw

PATCH v3 8/11 dm: imx: Use gpio_request() to request GPIOs

In reply to Simon Glass

Hi Simon,

Quoted 4 lines · Simon Glass

GPIOs should be requested before use. Without this, driver model will not permit the GPIO to be used.

This patch introduces a bunch of errors (once the driver model stuff is turned on), all related to the gpios never being freed, but requested anew when reinitializing subsystems.

The errors are:

CM-FX6 # sata init
Warning: iSSD setup failed!
AHCI 0001.0300 32 slots 1 ports 3 Gbps 0x1 impl SATA mode
flags: ncq stag pm led clo only pmp pio slum part SATA Device Info:
S/N: 123900127157
Product model number: SanDisk SSD i100 8GB Firmware version: 11.56.00
Capacity: 15649200 sectors

CM-FX6 # usb start
(Re)start USB...
USB0: USB OTG pwr gpio request failed: -16
USB OTG pwr gpio request failed: -16
USB EHCI 1.00
scanning bus 0 for devices... 2 USB Device(s) found
USB1: USB hub rst gpio request failed: -16
USB hub rst gpio request failed: -16
USB EHCI 1.00
scanning bus 1 for devices... 6 USB Device(s) found
scanning usb for storage devices... max USB Storage Device
reached: 5 stopping
5 Storage Device(s) found

CM-FX6 # sf probe
mxc_spi: cannot setup gpio -16
SF: Failed to set up slave
Failed to initialize SPI flash at 0:0

CM-FX6 # saveenv
Saving Environment to SPI Flash...
mxc_spi: cannot setup gpio -16
SF: Failed to set up slave
*** Warning - spi_flash_probe() failed, using default environment

I am going to submit a modified version of the cm_fx6 patches to address these problems.

Signature · 2 lines
Regards,
Nikita Kiryanov
#18 lore raw

PATCH v3 8/11 dm: imx: Use gpio_request() to request GPIOs

Hi Nikita,

Quoted 16 lines · Nikita Kiryanov

Hi Simon,

Quoted 5 lines · Simon Glass

GPIOs should be requested before use. Without this, driver model will not permit the GPIO to be used.

This patch introduces a bunch of errors (once the driver model stuff is turned on), all related to the gpios never being freed, but requested anew when reinitializing subsystems.

The errors are:

Quoted 9 lines

CM-FX6 # sata init
Warning: iSSD setup failed!
AHCI 0001.0300 32 slots 1 ports 3 Gbps 0x1 impl SATA mode
flags: ncq stag pm led clo only pmp pio slum part SATA Device Info:
S/N: 123900127157
Product model number: SanDisk SSD i100 8GB Firmware version: 11.56.00
Capacity: 15649200 sectors

Is it correct to init something twice? It has already been done when U-Boot boots I think. If it is, then are you thinking of changing cm_fx6_setup_issd() to cope with that?

Quoted 15 lines

CM-FX6 # usb start
(Re)start USB...
USB0: USB OTG pwr gpio request failed: -16
USB OTG pwr gpio request failed: -16
USB EHCI 1.00
scanning bus 0 for devices... 2 USB Device(s) found
USB1: USB hub rst gpio request failed: -16
USB hub rst gpio request failed: -16
USB EHCI 1.00
scanning bus 1 for devices... 6 USB Device(s) found
scanning usb for storage devices... max USB Storage Device reached: 5
stopping
5 Storage Device(s) found

Quoted 4 lines

CM-FX6 # sf probe
mxc_spi: cannot setup gpio -16
SF: Failed to set up slave
Failed to initialize SPI flash at 0:0

I took at look at how this works for SPI. The approach of calling a board function to find out the GPIO should go away with driver model - we can use device tree, or platform data if that is not yet available.

Also if you change the board code to 'stash' the GPIO and not request it a second time, you will need to do that in every board. It seems better to me to make this change in the driver, at least for SPI.

board_spi_cs_gpio() was added very recently in commit 155fa9af9. If you change it so that setup_cs_gpio() remembers the GPIO after calling board_spi_cs_gpio() then we can avoid passing the problem on to boards.

Quoted 6 lines

CM-FX6 # saveenv
Saving Environment to SPI Flash...
mxc_spi: cannot setup gpio -16
SF: Failed to set up slave
*** Warning - spi_flash_probe() failed, using default environment

Same issue.

Quoted 3 lines

I am going to submit a modified version of the cm_fx6 patches to address these problems.

I think those are already merged - I based my patches on your cm_fx6 patches and there were already in mainline.

Quoted 4 lines

--
Regards,
Nikita Kiryanov

Regards,
Simon

#19 lore raw

PATCH v3 8/11 dm: imx: Use gpio_request() to request GPIOs

Hi Simon,

Quoted 29 lines · Simon Glass

Hi Nikita,

Quoted 16 lines · Nikita Kiryanov

Hi Simon,

Quoted 5 lines · Simon Glass

GPIOs should be requested before use. Without this, driver model will not permit the GPIO to be used.

This patch introduces a bunch of errors (once the driver model stuff is turned on), all related to the gpios never being freed, but requested anew when reinitializing subsystems.

The errors are:

Quoted 9 lines

CM-FX6 # sata init
Warning: iSSD setup failed!
AHCI 0001.0300 32 slots 1 ports 3 Gbps 0x1 impl SATA mode
flags: ncq stag pm led clo only pmp pio slum part SATA Device Info:
S/N: 123900127157
Product model number: SanDisk SSD i100 8GB Firmware version: 11.56.00
Capacity: 15649200 sectors

Quoted 1 line

Is it correct to init something twice?

Of course. A re-init is a common use case, not just for sata, and anyway the reason for a failed re-init shouldn't be because sata code is preventing itself from utilizing its own GPIOs.

Quoted 3 lines

It has already been done when
U-Boot boots I think. If it is, then are you thinking of changing cm_fx6_setup_issd() to cope with that?

Yes.

Quoted 21 lines
Quoted 16 lines

CM-FX6 # usb start
(Re)start USB...
USB0: USB OTG pwr gpio request failed: -16
USB OTG pwr gpio request failed: -16
USB EHCI 1.00
scanning bus 0 for devices... 2 USB Device(s) found
USB1: USB hub rst gpio request failed: -16
USB hub rst gpio request failed: -16
USB EHCI 1.00
scanning bus 1 for devices... 6 USB Device(s) found
scanning usb for storage devices... max USB Storage Device reached: 5
stopping
5 Storage Device(s) found

Quoted 4 lines

CM-FX6 # sf probe
mxc_spi: cannot setup gpio -16
SF: Failed to set up slave
Failed to initialize SPI flash at 0:0

Quoted 7 lines

I took at look at how this works for SPI. The approach of calling a board function to find out the GPIO should go away with driver model - we can use device tree, or platform data if that is not yet available.

Also if you change the board code to 'stash' the GPIO and not request it a second time, you will need to do that in every board. It seems better to me to make this change in the driver, at least for SPI.

There are benefits to stashing (or a better word would be 'pre-claiming') it in board code. If a gpio is necessary for SPI to work, it is not really meant to be used by other users, even if it's not immediately requested on boot. Pre-claiming it in board code enforces this.

Quoted 1 line

board_spi_cs_gpio() was added very recently in commit 155fa9af9.

Yes, that is one of my patches :)

Quoted 3 lines

If you change it so that setup_cs_gpio() remembers the GPIO after calling board_spi_cs_gpio() then we can avoid passing the problem on to boards.

I would like to revisit this debate after the SPI driver is converted to driver model. For now I favour the pre-claiming in board code approach.

Quoted 8 lines
Quoted 7 lines

CM-FX6 # saveenv
Saving Environment to SPI Flash...
mxc_spi: cannot setup gpio -16
SF: Failed to set up slave
*** Warning - spi_flash_probe() failed, using default environment

Quoted 8 lines

Same issue.

Quoted 3 lines

I am going to submit a modified version of the cm_fx6 patches to address these problems.

I think those are already merged - I based my patches on your cm_fx6 patches and there were already in mainline.

I was actually referring to a modified version of your patches that touches cm_fx6 code. That is, take your changes as follows:
imx: Add error checking to setup_i2c() (sans the issd stuff)
dm: imx: Use gpio_request() to request GPIOs (just the i2c-mxv7.c stuff) and add a new patch that refactors cm_fx6 init stuff.

Quoted 9 lines
Quoted 5 lines

--
Regards,
Nikita Kiryanov

Regards,
Simon

Signature · 2 lines
Regards,
Nikita Kiryanov
#20 lore raw

PATCH v3 8/11 dm: imx: Use gpio_request() to request GPIOs

Hi Nikita,

Quoted 38 lines · Nikita Kiryanov

Hi Simon,

Quoted 35 lines · Simon Glass

Hi Nikita,

Quoted 29 lines · Nikita Kiryanov

Hi Simon,

Quoted 7 lines · Simon Glass

GPIOs should be requested before use. Without this, driver model will not
permit the GPIO to be used.

This patch introduces a bunch of errors (once the driver model stuff is turned on), all related to the gpios never being freed, but requested anew when reinitializing subsystems.

The errors are:

CM-FX6 # sata init
Warning: iSSD setup failed!
AHCI 0001.0300 32 slots 1 ports 3 Gbps 0x1 impl SATA mode
flags: ncq stag pm led clo only pmp pio slum part SATA Device Info:
S/N: 123900127157
Product model number: SanDisk SSD i100 8GB Firmware version: 11.56.00
Capacity: 15649200 sectors

Quoted 6 lines
Quoted 1 line

Is it correct to init something twice?

Of course. A re-init is a common use case, not just for sata, and anyway the reason for a failed re-init shouldn't be because sata code is preventing itself from utilizing its own GPIOs.

Yes, it needs to handle re-init, not just init.

Quoted 40 lines
Quoted 4 lines

It has already been done when
U-Boot boots I think. If it is, then are you thinking of changing cm_fx6_setup_issd() to cope with that?

Yes.

Quoted 23 lines
Quoted 17 lines

CM-FX6 # usb start
(Re)start USB...
USB0: USB OTG pwr gpio request failed: -16
USB OTG pwr gpio request failed: -16
USB EHCI 1.00
scanning bus 0 for devices... 2 USB Device(s) found
USB1: USB hub rst gpio request failed: -16
USB hub rst gpio request failed: -16
USB EHCI 1.00
scanning bus 1 for devices... 6 USB Device(s) found
scanning usb for storage devices... max USB Storage Device
reached: 5
stopping
5 Storage Device(s) found

Quoted 4 lines

CM-FX6 # sf probe
mxc_spi: cannot setup gpio -16
SF: Failed to set up slave
Failed to initialize SPI flash at 0:0

Quoted 7 lines

I took at look at how this works for SPI. The approach of calling a board function to find out the GPIO should go away with driver model - we can use device tree, or platform data if that is not yet available.

Also if you change the board code to 'stash' the GPIO and not request it a second time, you will need to do that in every board. It seems better to me to make this change in the driver, at least for SPI.

Quoted 5 lines

There are benefits to stashing (or a better word would be 'pre-claiming') it in board code. If a gpio is necessary for SPI to work, it is not really meant to be used by other users, even if it's not immediately requested on boot. Pre-claiming it in board code enforces this.

But my stash idea was not a good one as I mentioned in the other thread.

I've thought about that quite a lot as part of the driver model work. Claiming GPIOs in board code doesn't feel right to me:

1. If using device tree, the GPIOs are in there, and it means the board code needs to go looking there as well as the driver. The board code actually needs to sniff around in the driver's device tree nodes. That just seems honky.

2. In the driver model world, we hope that board init will fade away to a large extent. Certainly it should be possible to specify most of what a driver needs in device tree or platform data. Getting rid of the explicit init calls in U-Boot (board_init_f(), board_init(), board_late_init(), board_early_init_f(), ...) is a nice effect of driver model I hope.

3. Even if not using device tree, and using platform data, where the board code may specify the platform data, it still feels honky for the board to be parsing its own data (designed for use by the driver) to claim GPIOs.

4. I don't really see why pre-claiming enforces anything. If two subsystems claim the same GPIO you are going to get an error somewhere in any case.

5. If you look at the calls that drivers make to find out information from the board file, or perform some init (mmc does this, USB, ethernet, etc.) it is mostly because the driver has no idea of the specifics of the board. Device tree and platform data fix exactly this problem. The driver has the best idea of when it needs to start up, when it needs this resource of that. In some cases the driver have the ability to operate in two modes (e.g. 4 bit or 8 bit SDIO, UART with/without flow control) and this means the init depends on the driver's mode.

Quoted 6 lines
Quoted 2 lines

board_spi_cs_gpio() was added very recently in commit 155fa9af9.

Yes, that is one of my patches :)

Quoted 7 lines
Quoted 3 lines

If you change it so that setup_cs_gpio() remembers the GPIO after calling board_spi_cs_gpio() then we can avoid passing the problem on to boards.

I would like to revisit this debate after the SPI driver is converted to driver model. For now I favour the pre-claiming in board code approach.

OK, but see above. I feel this is going in the wrong direction for driver model at least.

Are you interested in converting the SPI driver?

Quoted 21 lines
Quoted 13 lines
Quoted 8 lines

CM-FX6 # saveenv
Saving Environment to SPI Flash...
mxc_spi: cannot setup gpio -16
SF: Failed to set up slave
*** Warning - spi_flash_probe() failed, using default environment

Same issue.

Quoted 1 line
Quoted 6 lines
Quoted 2 lines

I am going to submit a modified version of the cm_fx6 patches to address these problems.

I think those are already merged - I based my patches on your cm_fx6 patches and there were already in mainline.

Quoted 5 lines

I was actually referring to a modified version of your patches that touches cm_fx6 code. That is, take your changes as follows:
imx: Add error checking to setup_i2c() (sans the issd stuff)
dm: imx: Use gpio_request() to request GPIOs (just the i2c-mxv7.c stuff) and add a new patch that refactors cm_fx6 init stuff.

Ah OK, that should have been obvious, sorry (was looking at samsung/master where they didn't exist). Thanks for any assistance you can provide.

Regards,
Simon

#21 lore raw

PATCH v3 9/11 dm: imx: gpio: Support driver model in MXC gpio driver

In reply to Simon Glass

Add driver model support with this driver. In this case the platform data is in the driver. It would be better to put this into an SOC-specific file, but this is best attempted when more boards are moved over to use driver model.

---

Changes in v3:
- Use gpio_is_requested() in one more place

Changes in v2:
- Add an internal function to check if a GPIO is requested
- Change 'reserved' to 'requested'
- Tidy up confusing code that creates names for gpio_request()

 drivers/gpio/mxc_gpio.c | 304 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 303 insertions(+), 1 deletion(-)
drivers/gpio/mxc_gpio.c +303 -1
index 6a572d5..3f7b7d2 100644
@@ -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
Signature · 1 line
2.1.0.rc2.206.gedb03e5
#22 lore raw

PATCH v3 9/11 dm: imx: gpio: Support driver model in MXC gpio driver

Quoted 6 lines · Simon Glass

Add driver model support with this driver. In this case the platform data is in the driver. It would be better to put this into an SOC-specific file, but this is best attempted when more boards are moved over to use driver model.

Signature · 2 lines
Regards,
Igor.
#23 lore raw

PATCH v3 9/11 dm: imx: gpio: Support driver model in MXC gpio driver

Hi Igor,

Quoted 10 lines · Igor Grinberg
Quoted 6 lines · Simon Glass

Add driver model support with this driver. In this case the platform data is in the driver. It would be better to put this into an SOC-specific file, but this is best attempted when more boards are moved over to use driver model.

Thanks for reviewing these.

The latest experimental state of driver model is at u-boot-dm/working. There is also an imx-working branch with this series in it.

Regards,
Simon

#24 lore raw

PATCH v3 10/11 dm: imx: serial: Support driver model in the MXC serial driver

In reply to Simon Glass

Add driver model support with this driver. Boards which use this driver should define platform data in their board files.

---

Changes in v3: None
Changes in v2: None

 drivers/serial/serial_mxc.c | 170 +++++++++++++++++++++++++++++++++++++-------
 include/serial_mxc.h        |  14 ++++
 2 files changed, 159 insertions(+), 25 deletions(-)
 create mode 100644 include/serial_mxc.h
drivers/serial/serial_mxc.c +145 -25
index 313d560..9ce24f9 100644
@@ -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
include/serial_mxc.h new file +14 -0
new file mode 100644
index 0000000..7d3ace2
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __serial_mxc_h
+#define __serial_mxc_h
+
+/* Information about a serial port */
+struct mxc_serial_platdata {
+	struct mxc_uart *reg;  /* address of registers in physical memory */
+};
+
+#endif
Signature · 1 line
2.1.0.rc2.206.gedb03e5
#25 lore raw

PATCH v3 11/11 dm: imx: Move cm_fx6 to use driver model for serial and GPIO

In reply to Simon Glass

Now that serial and GPIO are available for iMX.6, move cm_fx6 over as an example.

---

Changes in v3: None
Changes in v2:
- Use the correct namespace for the platform data

 board/compulab/cm_fx6/cm_fx6.c | 10 ++++++++++
 include/configs/cm_fx6.h       | 11 +++++++++++
 2 files changed, 21 insertions(+)
board/compulab/cm_fx6/cm_fx6.c +10 -0
index a089e82..3a8ebd5 100644
@@ -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>
@@ -537,3 +539,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,
+};
include/configs/cm_fx6.h +11 -0
index 10d02b4..1f55150 100644
@@ -21,6 +21,17 @@
 #define CONFIG_MACH_TYPE		4273
 #define CONFIG_SYS_HZ			1000
 
+#ifndef CONFIG_SPL_BUILD
+#define CONFIG_DM
+#define CONFIG_CMD_DM
+
+#define CONFIG_DM_GPIO
+#define CONFIG_CMD_GPIO
+
+#define CONFIG_DM_SERIAL
+#define CONFIG_SYS_MALLOC_F_LEN		(1 << 10)
+#endif
+
 /* Display information on boot */
 #define CONFIG_DISPLAY_CPUINFO
 #define CONFIG_DISPLAY_BOARDINFO
Signature · 1 line
2.1.0.rc2.206.gedb03e5