From 9f4cd0200cae9821f9ae7994b86ec7a2023bbcd0 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 5 Jan 2015 20:05:23 -0700 Subject: dm: gpio: Bring in GPIO device tree binding Add the binding file that we are about to support. Signed-off-by: Simon Glass --- doc/device-tree-bindings/gpio/gpio.txt | 211 +++++++++++++++++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 doc/device-tree-bindings/gpio/gpio.txt (limited to 'doc') diff --git a/doc/device-tree-bindings/gpio/gpio.txt b/doc/device-tree-bindings/gpio/gpio.txt new file mode 100644 index 00000000000..b9bd1d64cfa --- /dev/null +++ b/doc/device-tree-bindings/gpio/gpio.txt @@ -0,0 +1,211 @@ +Specifying GPIO information for devices +============================================ + +1) gpios property +----------------- + +Nodes that makes use of GPIOs should specify them using one or more +properties, each containing a 'gpio-list': + + gpio-list ::= [gpio-list] + single-gpio ::= + gpio-phandle : phandle to gpio controller node + gpio-specifier : Array of #gpio-cells specifying specific gpio + (controller specific) + +GPIO properties should be named "[-]gpios", with being the purpose +of this GPIO for the device. While a non-existent is considered valid +for compatibility reasons (resolving to the "gpios" property), it is not allowed +for new bindings. + +GPIO properties can contain one or more GPIO phandles, but only in exceptional +cases should they contain more than one. If your device uses several GPIOs with +distinct functions, reference each of them under its own property, giving it a +meaningful name. The only case where an array of GPIOs is accepted is when +several GPIOs serve the same function (e.g. a parallel data line). + +The exact purpose of each gpios property must be documented in the device tree +binding of the device. + +The following example could be used to describe GPIO pins used as device enable +and bit-banged data signals: + + gpio1: gpio1 { + gpio-controller + #gpio-cells = <2>; + }; + gpio2: gpio2 { + gpio-controller + #gpio-cells = <1>; + }; + [...] + + enable-gpios = <&gpio2 2>; + data-gpios = <&gpio1 12 0>, + <&gpio1 13 0>, + <&gpio1 14 0>, + <&gpio1 15 0>; + +Note that gpio-specifier length is controller dependent. In the +above example, &gpio1 uses 2 cells to specify a gpio, while &gpio2 +only uses one. + +gpio-specifier may encode: bank, pin position inside the bank, +whether pin is open-drain and whether pin is logically inverted. +Exact meaning of each specifier cell is controller specific, and must +be documented in the device tree binding for the device. Use the macros +defined in include/dt-bindings/gpio/gpio.h whenever possible: + +Example of a node using GPIOs: + + node { + enable-gpios = <&qe_pio_e 18 GPIO_ACTIVE_HIGH>; + }; + +GPIO_ACTIVE_HIGH is 0, so in this example gpio-specifier is "18 0" and encodes +GPIO pin number, and GPIO flags as accepted by the "qe_pio_e" gpio-controller. + +1.1) GPIO specifier best practices +---------------------------------- + +A gpio-specifier should contain a flag indicating the GPIO polarity; active- +high or active-low. If it does, the follow best practices should be followed: + +The gpio-specifier's polarity flag should represent the physical level at the +GPIO controller that achieves (or represents, for inputs) a logically asserted +value at the device. The exact definition of logically asserted should be +defined by the binding for the device. If the board inverts the signal between +the GPIO controller and the device, then the gpio-specifier will represent the +opposite physical level than the signal at the device's pin. + +When the device's signal polarity is configurable, the binding for the +device must either: + +a) Define a single static polarity for the signal, with the expectation that +any software using that binding would statically program the device to use +that signal polarity. + +The static choice of polarity may be either: + +a1) (Preferred) Dictated by a binding-specific DT property. + +or: + +a2) Defined statically by the DT binding itself. + +In particular, the polarity cannot be derived from the gpio-specifier, since +that would prevent the DT from separately representing the two orthogonal +concepts of configurable signal polarity in the device, and possible board- +level signal inversion. + +or: + +b) Pick a single option for device signal polarity, and document this choice +in the binding. The gpio-specifier should represent the polarity of the signal +(at the GPIO controller) assuming that the device is configured for this +particular signal polarity choice. If software chooses to program the device +to generate or receive a signal of the opposite polarity, software will be +responsible for correctly interpreting (inverting) the GPIO signal at the GPIO +controller. + +2) gpio-controller nodes +------------------------ + +Every GPIO controller node must contain both an empty "gpio-controller" +property, and a #gpio-cells integer property, which indicates the number of +cells in a gpio-specifier. + +Example of two SOC GPIO banks defined as gpio-controller nodes: + + qe_pio_a: gpio-controller@1400 { + compatible = "fsl,qe-pario-bank-a", "fsl,qe-pario-bank"; + reg = <0x1400 0x18>; + gpio-controller; + #gpio-cells = <2>; + }; + + qe_pio_e: gpio-controller@1460 { + compatible = "fsl,qe-pario-bank-e", "fsl,qe-pario-bank"; + reg = <0x1460 0x18>; + gpio-controller; + #gpio-cells = <2>; + }; + +2.1) gpio- and pin-controller interaction +----------------------------------------- + +Some or all of the GPIOs provided by a GPIO controller may be routed to pins +on the package via a pin controller. This allows muxing those pins between +GPIO and other functions. + +It is useful to represent which GPIOs correspond to which pins on which pin +controllers. The gpio-ranges property described below represents this, and +contains information structures as follows: + + gpio-range-list ::= [gpio-range-list] + single-gpio-range ::= | + numeric-gpio-range ::= + + named-gpio-range ::= '<0 0>' + gpio-phandle : phandle to pin controller node. + gpio-base : Base GPIO ID in the GPIO controller + pinctrl-base : Base pinctrl pin ID in the pin controller + count : The number of GPIOs/pins in this range + +The "pin controller node" mentioned above must conform to the bindings +described in ../pinctrl/pinctrl-bindings.txt. + +In case named gpio ranges are used (ranges with both and + set to 0), the property gpio-ranges-group-names contains one string +for every single-gpio-range in gpio-ranges: + gpiorange-names-list ::= [gpiorange-names-list] + gpiorange-name : Name of the pingroup associated to the GPIO range in + the respective pin controller. + +Elements of gpiorange-names-list corresponding to numeric ranges contain +the empty string. Elements of gpiorange-names-list corresponding to named +ranges contain the name of a pin group defined in the respective pin +controller. The number of pins/GPIOs in the range is the number of pins in +that pin group. + +Previous versions of this binding required all pin controller nodes that +were referenced by any gpio-ranges property to contain a property named +#gpio-range-cells with value <3>. This requirement is now deprecated. +However, that property may still exist in older device trees for +compatibility reasons, and would still be required even in new device +trees that need to be compatible with older software. + +Example 1: + + qe_pio_e: gpio-controller@1460 { + #gpio-cells = <2>; + compatible = "fsl,qe-pario-bank-e", "fsl,qe-pario-bank"; + reg = <0x1460 0x18>; + gpio-controller; + gpio-ranges = <&pinctrl1 0 20 10>, <&pinctrl2 10 50 20>; + }; + +Here, a single GPIO controller has GPIOs 0..9 routed to pin controller +pinctrl1's pins 20..29, and GPIOs 10..19 routed to pin controller pinctrl2's +pins 50..59. + +Example 2: + + gpio_pio_i: gpio-controller@14B0 { + #gpio-cells = <2>; + compatible = "fsl,qe-pario-bank-e", "fsl,qe-pario-bank"; + reg = <0x1480 0x18>; + gpio-controller; + gpio-ranges = <&pinctrl1 0 20 10>, + <&pinctrl2 10 0 0>, + <&pinctrl1 15 0 10>, + <&pinctrl2 25 0 0>; + gpio-ranges-group-names = "", + "foo", + "", + "bar"; + }; + +Here, three GPIO ranges are defined wrt. two pin controllers. pinctrl1 GPIO +ranges are defined using pin numbers whereas the GPIO ranges wrt. pinctrl2 +are named "foo" and "bar". -- cgit v1.3.1 From 35ea1bfde30a541188ffd24cdf9b3ba79b0e4684 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 5 Jan 2015 20:05:24 -0700 Subject: dm: exynos: Bring in GPIO device tree binding At present the exynos GPIO driver does not fully support the existing device tree binding, but add the binding file to cover the existing partial support. Signed-off-by: Simon Glass --- doc/device-tree-bindings/gpio/gpio-samsung.txt | 41 ++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 doc/device-tree-bindings/gpio/gpio-samsung.txt (limited to 'doc') diff --git a/doc/device-tree-bindings/gpio/gpio-samsung.txt b/doc/device-tree-bindings/gpio/gpio-samsung.txt new file mode 100644 index 00000000000..5375625e8cd --- /dev/null +++ b/doc/device-tree-bindings/gpio/gpio-samsung.txt @@ -0,0 +1,41 @@ +Samsung Exynos4 GPIO Controller + +Required properties: +- compatible: Compatible property value should be "samsung,exynos4-gpio>". + +- reg: Physical base address of the controller and length of memory mapped + region. + +- #gpio-cells: Should be 4. The syntax of the gpio specifier used by client nodes + should be the following with values derived from the SoC user manual. + <[phandle of the gpio controller node] + [pin number within the gpio controller] + [mux function] + [flags and pull up/down] + [drive strength]> + + Values for gpio specifier: + - Pin number: is a value between 0 to 7. + - Flags and Pull Up/Down: 0 - Pull Up/Down Disabled. + 1 - Pull Down Enabled. + 3 - Pull Up Enabled. + Bit 16 (0x00010000) - Input is active low. + - Drive Strength: 0 - 1x, + 1 - 3x, + 2 - 2x, + 3 - 4x + +- gpio-controller: Specifies that the node is a gpio controller. +- #address-cells: should be 1. +- #size-cells: should be 1. + +Example: + + gpa0: gpio-controller@11400000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "samsung,exynos4-gpio"; + reg = <0x11400000 0x20>; + #gpio-cells = <4>; + gpio-controller; + }; -- cgit v1.3.1 From 5cfc662c496a0e52301a9379f91755b1f8fbf368 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 5 Jan 2015 20:05:25 -0700 Subject: dm: tegra: Bring in GPIO device tree binding At present the tegra GPIO driver does not fully support the existing device tree binding, but add the binding file to cover the existing partial support. Signed-off-by: Simon Glass --- .../gpio/nvidia,tegra20-gpio.txt | 40 ++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 doc/device-tree-bindings/gpio/nvidia,tegra20-gpio.txt (limited to 'doc') diff --git a/doc/device-tree-bindings/gpio/nvidia,tegra20-gpio.txt b/doc/device-tree-bindings/gpio/nvidia,tegra20-gpio.txt new file mode 100644 index 00000000000..023c9526e5f --- /dev/null +++ b/doc/device-tree-bindings/gpio/nvidia,tegra20-gpio.txt @@ -0,0 +1,40 @@ +NVIDIA Tegra GPIO controller + +Required properties: +- compatible : "nvidia,tegra-gpio" +- reg : Physical base address and length of the controller's registers. +- interrupts : The interrupt outputs from the controller. For Tegra20, + there should be 7 interrupts specified, and for Tegra30, there should + be 8 interrupts specified. +- #gpio-cells : Should be two. The first cell is the pin number and the + second cell is used to specify optional parameters: + - bit 0 specifies polarity (0 for normal, 1 for inverted) +- gpio-controller : Marks the device node as a GPIO controller. +- #interrupt-cells : Should be 2. + The first cell is the GPIO number. + The second cell is used to specify flags: + bits[3:0] trigger type and level flags: + 1 = low-to-high edge triggered. + 2 = high-to-low edge triggered. + 4 = active high level-sensitive. + 8 = active low level-sensitive. + Valid combinations are 1, 2, 3, 4, 8. +- interrupt-controller : Marks the device node as an interrupt controller. + +Example: + +gpio: gpio@6000d000 { + compatible = "nvidia,tegra20-gpio"; + reg = < 0x6000d000 0x1000 >; + interrupts = < 0 32 0x04 + 0 33 0x04 + 0 34 0x04 + 0 35 0x04 + 0 55 0x04 + 0 87 0x04 + 0 89 0x04 >; + #gpio-cells = <2>; + gpio-controller; + #interrupt-cells = <2>; + interrupt-controller; +}; -- cgit v1.3.1 From 2f3b95dbc78ce96b0f9f471e688db66223988419 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 25 Jan 2015 08:26:58 -0700 Subject: dm: core: Set device tree node for root device The root device corresponds to the root device tree node, so set this up. Also add a few notes to the documentation. Signed-off-by: Simon Glass --- doc/driver-model/README.txt | 4 ++++ drivers/core/root.c | 3 +++ 2 files changed, 7 insertions(+) (limited to 'doc') diff --git a/doc/driver-model/README.txt b/doc/driver-model/README.txt index eafa825ab44..40415698cf4 100644 --- a/doc/driver-model/README.txt +++ b/doc/driver-model/README.txt @@ -363,6 +363,10 @@ can leave out platdata_auto_alloc_size. In this case you can use malloc in your ofdata_to_platdata (or probe) method to allocate the required memory, and you should free it in the remove method. +The driver model tree is intended to mirror that of the device tree. The +root driver is at device tree offset 0 (the root node, '/'), and its +children are the children of the root node. + Declaring Uclasses ------------------ diff --git a/drivers/core/root.c b/drivers/core/root.c index 47b3acfbe98..a5b0a615016 100644 --- a/drivers/core/root.c +++ b/drivers/core/root.c @@ -49,6 +49,9 @@ int dm_init(void) ret = device_bind_by_name(NULL, false, &root_info, &DM_ROOT_NON_CONST); if (ret) return ret; +#ifdef CONFIG_OF_CONTROL + DM_ROOT_NON_CONST->of_offset = 0; +#endif ret = device_probe(DM_ROOT_NON_CONST); if (ret) return ret; -- cgit v1.3.1 From 9cc36a2b89ebe5148d69d521745c1e1d26365c3a Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 25 Jan 2015 08:27:05 -0700 Subject: dm: core: Add a flag to control sequence numbering At present we try to use the 'reg' property and device tree aliases to give devices a sequence number. The 'reg' property is often actually a memory address, so the sequence numbers thus-obtained are not useful. It would be better if the devices were just sequentially numbered in that case. In fact neither I2C nor SPI use this feature, so drop it. Some devices need us to look up an alias to number them within the uclass. Add a flag to control this, so it is not done unless it is needed. Adjust the tests to test this new behaviour. Signed-off-by: Simon Glass Reviewed-by: Masahiro Yamada --- doc/driver-model/README.txt | 51 +++++++++++------------------------------- drivers/core/device.c | 28 +++++++++++------------ drivers/i2c/i2c-uclass.c | 1 + drivers/serial/serial-uclass.c | 1 + drivers/spi/spi-uclass.c | 1 + include/dm/uclass.h | 5 +++++ test/dm/bus.c | 3 ++- test/dm/test-fdt.c | 9 ++++---- test/dm/test.dts | 16 +++++++++++++ 9 files changed, 57 insertions(+), 58 deletions(-) (limited to 'doc') diff --git a/doc/driver-model/README.txt b/doc/driver-model/README.txt index 40415698cf4..0c1292bf125 100644 --- a/doc/driver-model/README.txt +++ b/doc/driver-model/README.txt @@ -388,12 +388,12 @@ Device Sequence Numbers U-Boot numbers devices from 0 in many situations, such as in the command line for I2C and SPI buses, and the device names for serial ports (serial0, serial1, ...). Driver model supports this numbering and permits devices -to be locating by their 'sequence'. This numbering unique identifies a +to be locating by their 'sequence'. This numbering uniquely identifies a device in its uclass, so no two devices within a particular uclass can have the same sequence number. Sequence numbers start from 0 but gaps are permitted. For example, a board -may have I2C buses 0, 1, 4, 5 but no 2 or 3. The choice of how devices are +may have I2C buses 1, 4, 5 but no 0, 2 or 3. The choice of how devices are numbered is up to a particular board, and may be set by the SoC in some cases. While it might be tempting to automatically renumber the devices where there are gaps in the sequence, this can lead to confusion and is @@ -403,7 +403,7 @@ Each device can request a sequence number. If none is required then the device will be automatically allocated the next available sequence number. To specify the sequence number in the device tree an alias is typically -used. +used. Make sure that the uclass has the DM_UC_FLAG_SEQ_ALIAS flag set. aliases { serial2 = "/serial@22230000"; @@ -413,43 +413,18 @@ This indicates that in the uclass called "serial", the named node ("/serial@22230000") will be given sequence number 2. Any command or driver which requests serial device 2 will obtain this device. -Some devices represent buses where the devices on the bus are numbered or -addressed. For example, SPI typically numbers its slaves from 0, and I2C -uses a 7-bit address. In these cases the 'reg' property of the subnode is -used, for example: +More commonly you can use node references, which expand to the full path: -{ - aliases { - spi2 = "/spi@22300000"; - }; - - spi@22300000 { - #address-cells = <1>; - #size-cells = <1>; - spi-flash@0 { - reg = <0>; - ... - } - eeprom@1 { - reg = <1>; - }; - }; - -In this case we have a SPI bus with two slaves at 0 and 1. The SPI bus -itself is numbered 2. So we might access the SPI flash with: - - sf probe 2:0 - -and the eeprom with - - sspi 2:1 32 ef - -These commands simply need to look up the 2nd device in the SPI uclass to -find the right SPI bus. Then, they look at the children of that bus for the -right sequence number (0 or 1 in this case). +aliases { + serial2 = &serial_2; +}; +... +serial_2: serial@22230000 { +... +}; -Typically the alias method is used for top-level nodes and the 'reg' method -is used only for buses. +The alias resolves to the same string in this case, but this version is +easier to read. Device sequence numbers are resolved when a device is probed. Before then the sequence number is only a request which may or may not be honoured, diff --git a/drivers/core/device.c b/drivers/core/device.c index 2606d187177..f78b78a299e 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -53,24 +53,22 @@ int device_bind(struct udevice *parent, struct driver *drv, const char *name, dev->driver = drv; dev->uclass = uc; - /* - * For some devices, such as a SPI or I2C bus, the 'reg' property - * is a reasonable indicator of the sequence number. But if there is - * an alias, we use that in preference. In any case, this is just - * a 'requested' sequence, and will be resolved (and ->seq updated) - * when the device is probed. - */ dev->seq = -1; + dev->req_seq = -1; #ifdef CONFIG_OF_CONTROL - dev->req_seq = fdtdec_get_int(gd->fdt_blob, of_offset, "reg", -1); - if (!IS_ERR_VALUE(dev->req_seq)) - dev->req_seq &= INT_MAX; - if (uc->uc_drv->name && of_offset != -1) { - fdtdec_get_alias_seq(gd->fdt_blob, uc->uc_drv->name, of_offset, - &dev->req_seq); + /* + * Some devices, such as a SPI bus, I2C bus and serial ports are + * numbered using aliases. + * + * This is just a 'requested' sequence, and will be + * resolved (and ->seq updated) when the device is probed. + */ + if (uc->uc_drv->flags & DM_UC_FLAG_SEQ_ALIAS) { + 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; diff --git a/drivers/i2c/i2c-uclass.c b/drivers/i2c/i2c-uclass.c index 24e5ec68f2b..94b49dfe52b 100644 --- a/drivers/i2c/i2c-uclass.c +++ b/drivers/i2c/i2c-uclass.c @@ -453,6 +453,7 @@ int i2c_post_bind(struct udevice *dev) UCLASS_DRIVER(i2c) = { .id = UCLASS_I2C, .name = "i2c", + .flags = DM_UC_FLAG_SEQ_ALIAS, .per_device_auto_alloc_size = sizeof(struct dm_i2c_bus), .post_bind = i2c_post_bind, .post_probe = i2c_post_probe, diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c index d1b5777cecd..9131a8f93d9 100644 --- a/drivers/serial/serial-uclass.c +++ b/drivers/serial/serial-uclass.c @@ -297,6 +297,7 @@ static int serial_pre_remove(struct udevice *dev) UCLASS_DRIVER(serial) = { .id = UCLASS_SERIAL, .name = "serial", + .flags = DM_UC_FLAG_SEQ_ALIAS, .post_probe = serial_post_probe, .pre_remove = serial_pre_remove, .per_device_auto_alloc_size = sizeof(struct serial_dev_priv), diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c index 7a57bceb260..35756ad784e 100644 --- a/drivers/spi/spi-uclass.c +++ b/drivers/spi/spi-uclass.c @@ -344,6 +344,7 @@ int spi_ofdata_to_platdata(const void *blob, int node, UCLASS_DRIVER(spi) = { .id = UCLASS_SPI, .name = "spi", + .flags = DM_UC_FLAG_SEQ_ALIAS, .post_bind = spi_post_bind, .post_probe = spi_post_probe, .per_device_auto_alloc_size = sizeof(struct dm_spi_bus), diff --git a/include/dm/uclass.h b/include/dm/uclass.h index 7d92d34bec0..9000b22c38d 100644 --- a/include/dm/uclass.h +++ b/include/dm/uclass.h @@ -40,6 +40,9 @@ struct uclass { struct udevice; +/* Members of this uclass sequence themselves with aliases */ +#define DM_UC_FLAG_SEQ_ALIAS (1 << 0) + /** * struct uclass_driver - Driver for the uclass * @@ -66,6 +69,7 @@ struct udevice; * a falback if this member is 0 in the driver. * @ops: Uclass operations, providing the consistent interface to devices * within the uclass. + * @flags: Flags for this uclass (DM_UC_...) */ struct uclass_driver { const char *name; @@ -80,6 +84,7 @@ struct uclass_driver { int per_device_auto_alloc_size; int per_child_platdata_auto_alloc_size; const void *ops; + uint32_t flags; }; /* Declare a new uclass_driver */ diff --git a/test/dm/bus.c b/test/dm/bus.c index e18a6f72499..972c4497908 100644 --- a/test/dm/bus.c +++ b/test/dm/bus.c @@ -88,12 +88,13 @@ U_BOOT_DRIVER(testbus_drv) = { UCLASS_DRIVER(testbus) = { .name = "testbus", .id = UCLASS_TEST_BUS, + .flags = DM_UC_FLAG_SEQ_ALIAS, }; /* Test that we can probe for children */ static int dm_test_bus_children(struct dm_test_state *dms) { - int num_devices = 4; + int num_devices = 6; struct udevice *bus; struct uclass *uc; diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c index dc4ebf9adaf..dfcb3af61bb 100644 --- a/test/dm/test-fdt.c +++ b/test/dm/test-fdt.c @@ -89,6 +89,7 @@ int testfdt_ping(struct udevice *dev, int pingval, int *pingret) UCLASS_DRIVER(testfdt) = { .name = "testfdt", .id = UCLASS_TEST_FDT, + .flags = DM_UC_FLAG_SEQ_ALIAS, }; int dm_check_devices(struct dm_test_state *dms, int num_devices) @@ -128,7 +129,7 @@ int dm_check_devices(struct dm_test_state *dms, int num_devices) /* Test that FDT-based binding works correctly */ static int dm_test_fdt(struct dm_test_state *dms) { - const int num_devices = 4; + const int num_devices = 6; struct udevice *dev; struct uclass *uc; int ret; @@ -184,7 +185,7 @@ static int dm_test_fdt_uclass_seq(struct dm_test_state *dms) ut_assertok(uclass_find_device_by_seq(UCLASS_TEST_FDT, 3, true, &dev)); ut_asserteq_str("b-test", dev->name); - ut_assertok(uclass_find_device_by_seq(UCLASS_TEST_FDT, 0, true, &dev)); + ut_assertok(uclass_find_device_by_seq(UCLASS_TEST_FDT, 8, true, &dev)); ut_asserteq_str("a-test", dev->name); ut_asserteq(-ENODEV, uclass_find_device_by_seq(UCLASS_TEST_FDT, 5, @@ -220,11 +221,11 @@ static int dm_test_fdt_uclass_seq(struct dm_test_state *dms) ut_asserteq(-ENODEV, uclass_get_device_by_seq(UCLASS_TEST_FDT, 1, &dev)); ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev)); - ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 1, &dev)); + ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 4, &dev)); /* But now that it is probed, we can find it */ ut_assertok(uclass_get_device_by_seq(UCLASS_TEST_FDT, 1, &dev)); - ut_asserteq_str("a-test", dev->name); + ut_asserteq_str("f-test", dev->name); return 0; } diff --git a/test/dm/test.dts b/test/dm/test.dts index 33f2c00747d..84024a44a3f 100644 --- a/test/dm/test.dts +++ b/test/dm/test.dts @@ -8,7 +8,15 @@ aliases { console = &uart0; + i2c0 = "/i2c@0"; + spi0 = "/spi@0"; testfdt6 = "/e-test"; + testbus3 = "/some-bus"; + testfdt0 = "/some-bus/c-test@0"; + testfdt1 = "/some-bus/c-test@1"; + testfdt3 = "/b-test"; + testfdt5 = "/some-bus/c-test@5"; + testfdt8 = "/a-test"; }; uart0: serial { @@ -86,6 +94,14 @@ compatible = "google,another-fdt-test"; }; + f-test { + compatible = "denx,u-boot-fdt-test"; + }; + + g-test { + compatible = "denx,u-boot-fdt-test"; + }; + gpio_a: base-gpios { compatible = "sandbox,gpio"; gpio-controller; -- cgit v1.3.1 From 2017aaef8c383c910e791bf0f87fa4d6b78f5945 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 25 Jan 2015 08:27:20 -0700 Subject: dm: Update documentation for new bus features Now that we have new bus features, update README.txt and the SPI docs to explain these. Signed-off-by: Simon Glass --- doc/driver-model/README.txt | 36 ++++++++++++++++++++++++++---------- doc/driver-model/spi-howto.txt | 40 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 63 insertions(+), 13 deletions(-) (limited to 'doc') diff --git a/doc/driver-model/README.txt b/doc/driver-model/README.txt index 0c1292bf125..f83264d615d 100644 --- a/doc/driver-model/README.txt +++ b/doc/driver-model/README.txt @@ -441,11 +441,18 @@ access to other devices. Example of buses include SPI and I2C. Typically the bus provides some sort of transport or translation that makes it possible to talk to the devices on the bus. -Driver model provides a few useful features to help with implementing -buses. Firstly, a bus can request that its children store some 'parent -data' which can be used to keep track of child state. Secondly, the bus can -define methods which are called when a child is probed or removed. This is -similar to the methods the uclass driver provides. +Driver model provides some useful features to help with implementing buses. +Firstly, a bus can request that its children store some 'parent data' which +can be used to keep track of child state. Secondly, the bus can define +methods which are called when a child is probed or removed. This is similar +to the methods the uclass driver provides. Thirdly, per-child platform data +can be provided to specify things like the child's address on the bus. This +persists across child probe()/remove() cycles. + +For consistency and ease of implementation, the bus uclass can specify the +per-child platform data, so that it can be the same for all children of buses +in that uclass. There are also uclass methods which can be called when +children are bound and probed. Here an explanation of how a bus fits with a uclass may be useful. Consider a USB bus with several devices attached to it, each from a different (made @@ -460,15 +467,23 @@ Each of the devices is connected to a different address on the USB bus. The bus device wants to store this address and some other information such as the bus speed for each device. -To achieve this, the bus device can use dev->parent_priv in each of its -three children. This can be auto-allocated if the bus driver has a non-zero -value for per_child_auto_alloc_size. If not, then the bus device can -allocate the space itself before the child device is probed. +To achieve this, the bus device can use dev->parent_platdata in each of its +three children. This can be auto-allocated if the bus driver (or bus uclass) +has a non-zero value for per_child_platdata_auto_alloc_size. If not, then +the bus device or uclass can allocate the space itself before the child +device is probed. Also the bus driver can define the child_pre_probe() and child_post_remove() methods to allow it to do some processing before the child is activated or after it is deactivated. +Similarly the bus uclass can define the child_post_bind() method to obtain +the per-child platform data from the device tree and set it up for the child. +The bus uclass can also provide a child_pre_probe() method. Very often it is +the bus uclass that controls these features, since it avoids each driver +having to do the same processing. Of course the driver can still tweak and +override these activities. + Note that the information that controls this behaviour is in the bus's driver, not the child's. In fact it is possible that child has no knowledge that it is connected to a bus. The same child device may even be used on two @@ -495,7 +510,8 @@ bus device, regardless of its own views on the matter. The uclass for the device can also contain data private to that uclass. But note that each device on the bus may be a memeber of a different uclass, and this data has nothing to do with the child data for each child -on the bus. +on the bus. It is the bus' uclass that controls the child with respect to +the bus. Driver Lifecycle diff --git a/doc/driver-model/spi-howto.txt b/doc/driver-model/spi-howto.txt index 719dbd5cdd2..5bc29ad65ce 100644 --- a/doc/driver-model/spi-howto.txt +++ b/doc/driver-model/spi-howto.txt @@ -3,7 +3,8 @@ How to port a SPI driver to driver model Here is a rough step-by-step guide. It is based around converting the exynos SPI driver to driver model (DM) and the example code is based -around U-Boot v2014.10-rc2 (commit be9f643). +around U-Boot v2014.10-rc2 (commit be9f643). This has been updated for +v2015.04. It is quite long since it includes actual code examples. @@ -262,8 +263,8 @@ U_BOOT_DEVICE(board_spi0) = { .platdata = &platdata_spi0, }; -You will unfortunately need to put the struct into a header file in this -case so that your board file can use it. +You will unfortunately need to put the struct definition into a header file +in this case so that your board file can use it. 9. Add the device private data @@ -592,3 +593,36 @@ board. You can use 'tools/patman/patman' to prepare, check and send patches for your work. See the README for details. + +20. A little note about SPI uclass features: + +The SPI uclass keeps some information about each device 'dev' on the bus: + + struct dm_spi_slave_platdata - this is device_get_parent_platdata(dev) + This is where the chip select number is stored, along with + the default bus speed and mode. It is automatically read + from the device tree in spi_child_post_bind(). It must not + be changed at run-time after being set up because platform + data is supposed to be immutable at run-time. + struct spi_slave - this is device_get_parentdata(dev) + Already mentioned above. It holds run-time information about + the device. + +There are also some SPI uclass methods that get called behind the scenes: + + spi_post_bind() - called when a new bus is bound + This scans the device tree for devices on the bus, and binds + each one. This in turn causes spi_child_post_bind() to be + called for each, which reads the device tree information + into the parent (per-child) platform data. + spi_child_post_bind() - called when a new child is bound + As mentioned above this reads the device tree information + into the per-child platform data + spi_child_pre_probe() - called before a new child is probed + This sets up the mode and speed in struct spi_slave by + copying it from the parent's platform data for this child. + It also sets the 'dev' pointer, needed to permit passing + 'struct spi_slave' around the place without needing a + separate 'struct udevice' pointer. + +The above housekeeping makes it easier to write your SPI driver. -- cgit v1.3.1 From 49cad54788a64a296567abadcd736fdbe47cc3a3 Mon Sep 17 00:00:00 2001 From: Martin Dorwig Date: Mon, 26 Jan 2015 15:22:54 -0700 Subject: Export redesign this is an atempt to make the export of functions typesafe. I replaced the jumptable void ** by a struct (jt_funcs) with function pointers. The EXPORT_FUNC macro now has 3 fixed parameters and one variadic parameter The first is the name of the exported function, the rest of the parameters are used to format a functionpointer in the jumptable, the EXPORT_FUNC macros are expanded three times, 1. to declare the members of the struct 2. to initialize the structmember pointers 3. to call the functions in stubs.c Signed-off-by: Martin Dorwig Acked-by: Simon Glass Signed-off-by: Simon Glass (resending to the list since my tweaks are not quite trivial) --- arch/blackfin/cpu/cpu.c | 3 +- board/BuS/eb_cpux9k2/cpux9k2.c | 2 +- common/cmd_load.c | 2 +- common/console.c | 20 ++++---- common/exports.c | 29 ++---------- doc/README.standalone | 41 +++++++++++----- examples/standalone/stubs.c | 64 +++++++++++++------------ include/_exports.h | 99 +++++++++++++++++++++++++++------------ include/asm-generic/global_data.h | 2 +- include/exports.h | 22 +++++---- 10 files changed, 163 insertions(+), 121 deletions(-) (limited to 'doc') diff --git a/arch/blackfin/cpu/cpu.c b/arch/blackfin/cpu/cpu.c index b7f118801d1..91aa5cc89c3 100644 --- a/arch/blackfin/cpu/cpu.c +++ b/arch/blackfin/cpu/cpu.c @@ -24,6 +24,7 @@ #include "cpu.h" #include "initcode.h" +#include "exports.h" ulong bfin_poweron_retx; DECLARE_GLOBAL_DATA_PTR; @@ -121,7 +122,7 @@ static void display_global_data(void) printf(" |-ram_size: %lx\n", gd->ram_size); printf(" |-env_addr: %lx\n", gd->env_addr); printf(" |-env_valid: %lx\n", gd->env_valid); - printf(" |-jt(%p): %p\n", gd->jt, *(gd->jt)); + printf(" |-jt(%p): %p\n", gd->jt, gd->jt->get_version); printf(" \\-bd: %p\n", gd->bd); printf(" |-bi_boot_params: %lx\n", bd->bi_boot_params); printf(" |-bi_memstart: %lx\n", bd->bi_memstart); diff --git a/board/BuS/eb_cpux9k2/cpux9k2.c b/board/BuS/eb_cpux9k2/cpux9k2.c index 5e4778e9788..76ad7c443bb 100644 --- a/board/BuS/eb_cpux9k2/cpux9k2.c +++ b/board/BuS/eb_cpux9k2/cpux9k2.c @@ -98,7 +98,7 @@ int misc_init_r(void) puts("Error: invalid MAC at EEPROM\n"); } } - gd->jt[XF_do_reset] = (void *) do_reset; + gd->jt->do_reset = do_reset; #ifdef CONFIG_STATUS_LED status_led_set(STATUS_LED_BOOT, STATUS_LED_BLINKING); diff --git a/common/cmd_load.c b/common/cmd_load.c index f6e522cbb34..d043e6d7bcf 100644 --- a/common/cmd_load.c +++ b/common/cmd_load.c @@ -222,7 +222,7 @@ static int read_record(char *buf, ulong len) } /* Check for the console hangup (if any different from serial) */ - if (gd->jt[XF_getc] != getc) { + if (gd->jt->getc != getc) { if (ctrlc()) { return (-1); } diff --git a/common/console.c b/common/console.c index fc1963b2a97..3f25e76fe79 100644 --- a/common/console.c +++ b/common/console.c @@ -125,13 +125,13 @@ static int console_setfile(int file, struct stdio_dev * dev) */ switch (file) { case stdin: - gd->jt[XF_getc] = getc; - gd->jt[XF_tstc] = tstc; + gd->jt->getc = getc; + gd->jt->tstc = tstc; break; case stdout: - gd->jt[XF_putc] = putc; - gd->jt[XF_puts] = puts; - gd->jt[XF_printf] = printf; + gd->jt->putc = putc; + gd->jt->puts = puts; + gd->jt->printf = printf; break; } break; @@ -758,11 +758,11 @@ int console_init_r(void) #endif /* set default handlers at first */ - gd->jt[XF_getc] = serial_getc; - gd->jt[XF_tstc] = serial_tstc; - gd->jt[XF_putc] = serial_putc; - gd->jt[XF_puts] = serial_puts; - gd->jt[XF_printf] = serial_printf; + gd->jt->getc = serial_getc; + gd->jt->tstc = serial_tstc; + gd->jt->putc = serial_putc; + gd->jt->puts = serial_puts; + gd->jt->printf = serial_printf; /* stdin stdout and stderr are in environment */ /* scan for it */ diff --git a/common/exports.c b/common/exports.c index 459e18cb097..333107c74c3 100644 --- a/common/exports.c +++ b/common/exports.c @@ -1,6 +1,7 @@ #include #include #include +#include DECLARE_GLOBAL_DATA_PTR; @@ -13,34 +14,10 @@ unsigned long get_version(void) return XF_VERSION; } -/* Reuse _exports.h with a little trickery to avoid bitrot */ -#define EXPORT_FUNC(sym) gd->jt[XF_##sym] = (void *)sym; - -#if !defined(CONFIG_X86) && !defined(CONFIG_PPC) -# define install_hdlr dummy -# define free_hdlr dummy -#else /* kludge for non-standard function naming */ -# define install_hdlr irq_install_handler -# define free_hdlr irq_free_handler -#endif -#if !defined(CONFIG_CMD_I2C) || \ - (defined(CONFIG_DM_I2C) && !defined(CONFIG_DM_I2C_COMPAT)) -# define i2c_write dummy -# define i2c_read dummy -#endif -#if !defined(CONFIG_CMD_SPI) || defined(CONFIG_DM_SPI) -# define spi_init dummy -# define spi_setup_slave dummy -# define spi_free_slave dummy -#endif -#ifndef CONFIG_CMD_SPI -# define spi_claim_bus dummy -# define spi_release_bus dummy -# define spi_xfer dummy -#endif +#define EXPORT_FUNC(f, a, x, ...) gd->jt->x = f; void jumptable_init(void) { - gd->jt = malloc(XF_MAX * sizeof(void *)); + gd->jt = malloc(sizeof(struct jt_funcs)); #include <_exports.h> } diff --git a/doc/README.standalone b/doc/README.standalone index e3000efcc62..659a12f6cb7 100644 --- a/doc/README.standalone +++ b/doc/README.standalone @@ -5,18 +5,18 @@ Design Notes on Exporting U-Boot Functions to Standalone Applications: table is allocated and initialized in the jumptable_init() routine (common/exports.c). Other routines may also modify the jump table, however. The jump table can be accessed as the 'jt' field of the - 'global_data' structure. The slot numbers for the jump table are + 'global_data' structure. The struct members for the jump table are defined in the header. E.g., to substitute the malloc() and free() functions that will be available to standalone applications, one should do the following: DECLARE_GLOBAL_DATA_PTR; - gd->jt[XF_malloc] = my_malloc; - gd->jt[XF_free] = my_free; + gd->jt->malloc = my_malloc; + gd->jt->free = my_free; - Note that the pointers to the functions all have 'void *' type and - thus the compiler cannot perform type checks on these assignments. + Note that the pointers to the functions are real function pointers + so the compiler can perform type checks on these assignments. 2. The pointer to the jump table is passed to the application in a machine-dependent way. PowerPC, ARM, MIPS, Blackfin and Nios II @@ -65,27 +65,46 @@ Design Notes on Exporting U-Boot Functions to Standalone Applications: => tftp 0x40000 hello_world.bin => go 0x40004 -5. To export some additional function foobar(), the following steps +5. To export some additional function long foobar(int i,char c), the following steps should be undertaken: - Append the following line at the end of the include/_exports.h file: - EXPORT_FUNC(foobar) + EXPORT_FUNC(foobar, long, foobar, int, char) + + Parameters to EXPORT_FUNC: + - the first parameter is the function that is exported (default implementation) + - the second parameter is the return value type + - the third parameter is the name of the member in struct jt_funcs + this is also the name that the standalone application will used. + the rest of the parameters are the function arguments - Add the prototype for this function to the include/exports.h file: - void foobar(void); + long foobar(int i, char c); + + Initialization with the default implementation is done in jumptable_init() + + You can override the default implementation using: - - Add the initialization of the jump table slot wherever - appropriate (most likely, to the jumptable_init() function): + gd->jt->foobar = another_foobar; - gd->jt[XF_foobar] = foobar; + The signature of another_foobar must then match the declaration of foobar. - Increase the XF_VERSION value by one in the include/exports.h file + - If you want to export a function which depends on a CONFIG_XXX + use 2 lines like this: + #ifdef CONFIG_FOOBAR + EXPORT_FUNC(foobar, long, foobar, int, char) + #else + EXPORT_FUNC(dummy, void, foobar, void) + #endif + + 6. The code for exporting the U-Boot functions to applications is mostly machine-independent. The only places written in assembly language are stub functions that perform the jump through the jump diff --git a/examples/standalone/stubs.c b/examples/standalone/stubs.c index 0bf690e73d1..920a0a9cf3b 100644 --- a/examples/standalone/stubs.c +++ b/examples/standalone/stubs.c @@ -2,6 +2,8 @@ #include #include +#define FO(x) offsetof(struct jt_funcs, x) + #if defined(CONFIG_X86) /* * x86 does not have a dedicated register to store the pointer to @@ -10,23 +12,23 @@ * from flash memory. The global_data address is passed as argv[-1] * to the application program. */ -static void **jt; +static struct jt_funcs *jt; gd_t *global_data; -#define EXPORT_FUNC(x) \ +#define EXPORT_FUNC(f, a, x, ...) \ asm volatile ( \ " .globl " #x "\n" \ #x ":\n" \ " movl %0, %%eax\n" \ " movl jt, %%ecx\n" \ " jmp *(%%ecx, %%eax)\n" \ - : : "i"(XF_ ## x * sizeof(void *)) : "eax", "ecx"); + : : "i"(FO(x)) : "eax", "ecx"); #elif defined(CONFIG_PPC) /* * r2 holds the pointer to the global_data, r11 is a call-clobbered * register */ -#define EXPORT_FUNC(x) \ +#define EXPORT_FUNC(f, a, x, ...) \ asm volatile ( \ " .globl " #x "\n" \ #x ":\n" \ @@ -34,33 +36,33 @@ gd_t *global_data; " lwz %%r11, %1(%%r11)\n" \ " mtctr %%r11\n" \ " bctr\n" \ - : : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "r11"); + : : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "r11"); #elif defined(CONFIG_ARM) #ifdef CONFIG_ARM64 /* * x18 holds the pointer to the global_data, x9 is a call-clobbered * register */ -#define EXPORT_FUNC(x) \ +#define EXPORT_FUNC(f, a, x, ...) \ asm volatile ( \ " .globl " #x "\n" \ #x ":\n" \ " ldr x9, [x18, %0]\n" \ " ldr x9, [x9, %1]\n" \ " br x9\n" \ - : : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "x9"); + : : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "x9"); #else /* * r9 holds the pointer to the global_data, ip is a call-clobbered * register */ -#define EXPORT_FUNC(x) \ +#define EXPORT_FUNC(f, a, x, ...) \ asm volatile ( \ " .globl " #x "\n" \ #x ":\n" \ " ldr ip, [r9, %0]\n" \ " ldr pc, [ip, %1]\n" \ - : : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "ip"); + : : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "ip"); #endif #elif defined(CONFIG_MIPS) /* @@ -70,19 +72,19 @@ gd_t *global_data; * it; however, GCC/mips generates an additional `nop' after each asm * statement */ -#define EXPORT_FUNC(x) \ +#define EXPORT_FUNC(f, a, x, ...) \ asm volatile ( \ " .globl " #x "\n" \ #x ":\n" \ " lw $25, %0($26)\n" \ " lw $25, %1($25)\n" \ " jr $25\n" \ - : : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "t9"); + : : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "t9"); #elif defined(CONFIG_NIOS2) /* * gp holds the pointer to the global_data, r8 is call-clobbered */ -#define EXPORT_FUNC(x) \ +#define EXPORT_FUNC(f, a, x, ...) \ asm volatile ( \ " .globl " #x "\n" \ #x ":\n" \ @@ -92,13 +94,13 @@ gd_t *global_data; " ldw r8, 0(r8)\n" \ " ldw r8, %1(r8)\n" \ " jmp r8\n" \ - : : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "gp"); + : : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "gp"); #elif defined(CONFIG_M68K) /* * d7 holds the pointer to the global_data, a0 is a call-clobbered * register */ -#define EXPORT_FUNC(x) \ +#define EXPORT_FUNC(f, a, x, ...) \ asm volatile ( \ " .globl " #x "\n" \ #x ":\n" \ @@ -108,50 +110,50 @@ gd_t *global_data; " adda.l %1, %%a0\n" \ " move.l (%%a0), %%a0\n" \ " jmp (%%a0)\n" \ - : : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "a0"); + : : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "a0"); #elif defined(CONFIG_MICROBLAZE) /* * r31 holds the pointer to the global_data. r5 is a call-clobbered. */ -#define EXPORT_FUNC(x) \ +#define EXPORT_FUNC(f, a, x, ...) \ asm volatile ( \ " .globl " #x "\n" \ #x ":\n" \ " lwi r5, r31, %0\n" \ " lwi r5, r5, %1\n" \ " bra r5\n" \ - : : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "r5"); + : : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "r5"); #elif defined(CONFIG_BLACKFIN) /* * P3 holds the pointer to the global_data, P0 is a call-clobbered * register */ -#define EXPORT_FUNC(x) \ +#define EXPORT_FUNC(f, a, x, ...) \ asm volatile ( \ " .globl _" #x "\n_" \ #x ":\n" \ " P0 = [P3 + %0]\n" \ " P0 = [P0 + %1]\n" \ " JUMP (P0)\n" \ - : : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "P0"); + : : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "P0"); #elif defined(CONFIG_AVR32) /* * r6 holds the pointer to the global_data. r8 is call clobbered. */ -#define EXPORT_FUNC(x) \ +#define EXPORT_FUNC(f, a, x, ...) \ asm volatile( \ " .globl\t" #x "\n" \ #x ":\n" \ " ld.w r8, r6[%0]\n" \ " ld.w pc, r8[%1]\n" \ : \ - : "i"(offsetof(gd_t, jt)), "i"(XF_ ##x) \ + : "i"(offsetof(gd_t, jt)), "i"(FO(x)) \ : "r8"); #elif defined(CONFIG_SH) /* * r13 holds the pointer to the global_data. r1 is a call clobbered. */ -#define EXPORT_FUNC(x) \ +#define EXPORT_FUNC(f, a, x, ...) \ asm volatile ( \ " .align 2\n" \ " .globl " #x "\n" \ @@ -164,12 +166,12 @@ gd_t *global_data; " jmp @r1\n" \ " nop\n" \ " nop\n" \ - : : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "r1", "r2"); + : : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "r1", "r2"); #elif defined(CONFIG_SPARC) /* * g7 holds the pointer to the global_data. g1 is call clobbered. */ -#define EXPORT_FUNC(x) \ +#define EXPORT_FUNC(f, a, x, ...) \ asm volatile( \ " .globl\t" #x "\n" \ #x ":\n" \ @@ -179,26 +181,26 @@ gd_t *global_data; " ld [%%g1 + %1], %%g1\n" \ " jmp %%g1\n" \ " nop\n" \ - : : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "g1" ); + : : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "g1"); #elif defined(CONFIG_NDS32) /* * r16 holds the pointer to the global_data. gp is call clobbered. * not support reduced register (16 GPR). */ -#define EXPORT_FUNC(x) \ +#define EXPORT_FUNC(f, a, x, ...) \ asm volatile ( \ " .globl " #x "\n" \ #x ":\n" \ " lwi $r16, [$gp + (%0)]\n" \ " lwi $r16, [$r16 + (%1)]\n" \ " jr $r16\n" \ - : : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "$r16"); + : : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "$r16"); #elif defined(CONFIG_OPENRISC) /* * r10 holds the pointer to the global_data, r13 is a call-clobbered * register */ -#define EXPORT_FUNC(x) \ +#define EXPORT_FUNC(f, a, x, ...) \ asm volatile ( \ " .globl " #x "\n" \ #x ":\n" \ @@ -206,12 +208,12 @@ gd_t *global_data; " l.lwz r13, %1(r13)\n" \ " l.jr r13\n" \ " l.nop\n" \ - : : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "r13"); + : : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "r13"); #elif defined(CONFIG_ARC) /* * r25 holds the pointer to the global_data. r10 is call clobbered. */ -#define EXPORT_FUNC(x) \ +#define EXPORT_FUNC(f, a, x, ...) \ asm volatile( \ " .align 4\n" \ " .globl " #x "\n" \ @@ -219,7 +221,7 @@ gd_t *global_data; " ld r10, [r25, %0]\n" \ " ld r10, [r10, %1]\n" \ " j [r10]\n" \ - : : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "r10"); + : : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "r10"); #else /*" addi $sp, $sp, -24\n" \ " br $r16\n" \*/ diff --git a/include/_exports.h b/include/_exports.h index 349a3c5522f..594470328ea 100644 --- a/include/_exports.h +++ b/include/_exports.h @@ -1,32 +1,73 @@ /* - * You do not need to use #ifdef around functions that may not exist + * You need to use #ifdef around functions that may not exist * in the final configuration (such as i2c). + * use a dummyfunction as first parameter to EXPORT_FUNC. + * As an example see the CONFIG_CMD_I2C section below */ -EXPORT_FUNC(get_version) -EXPORT_FUNC(getc) -EXPORT_FUNC(tstc) -EXPORT_FUNC(putc) -EXPORT_FUNC(puts) -EXPORT_FUNC(printf) -EXPORT_FUNC(install_hdlr) -EXPORT_FUNC(free_hdlr) -EXPORT_FUNC(malloc) -EXPORT_FUNC(free) -EXPORT_FUNC(udelay) -EXPORT_FUNC(get_timer) -EXPORT_FUNC(vprintf) -EXPORT_FUNC(do_reset) -EXPORT_FUNC(getenv) -EXPORT_FUNC(setenv) -EXPORT_FUNC(simple_strtoul) -EXPORT_FUNC(strict_strtoul) -EXPORT_FUNC(simple_strtol) -EXPORT_FUNC(strcmp) -EXPORT_FUNC(i2c_write) -EXPORT_FUNC(i2c_read) -EXPORT_FUNC(spi_init) -EXPORT_FUNC(spi_setup_slave) -EXPORT_FUNC(spi_free_slave) -EXPORT_FUNC(spi_claim_bus) -EXPORT_FUNC(spi_release_bus) -EXPORT_FUNC(spi_xfer) +#ifndef EXPORT_FUNC +#define EXPORT_FUNC(a, b, c, ...) +#endif + EXPORT_FUNC(get_version, unsigned long, get_version, void) + EXPORT_FUNC(getc, int, getc, void) + EXPORT_FUNC(tstc, int, tstc, void) + EXPORT_FUNC(putc, void, putc, const char) + EXPORT_FUNC(puts, void, puts, const char *) + EXPORT_FUNC(printf, int, printf, const char*, ...) +#if defined(CONFIG_X86) || defined(CONFIG_PPC) + EXPORT_FUNC(irq_install_handler, void, install_hdlr, + int, interrupt_handler_t, void*) + + EXPORT_FUNC(irq_free_handler, void, free_hdlr, int) +#else + EXPORT_FUNC(dummy, void, install_hdlr, void) + EXPORT_FUNC(dummy, void, free_hdlr, void) +#endif + EXPORT_FUNC(malloc, void *, malloc, size_t) + EXPORT_FUNC(free, void, free, void *) + EXPORT_FUNC(udelay, void, udelay, unsigned long) + EXPORT_FUNC(get_timer, unsigned long, get_timer, unsigned long) + EXPORT_FUNC(vprintf, int, vprintf, const char *, va_list) + EXPORT_FUNC(do_reset, int, do_reset, cmd_tbl_t *, + int , int , char * const []) + EXPORT_FUNC(getenv, char *, getenv, const char*) + EXPORT_FUNC(setenv, int, setenv, const char *, const char *) + EXPORT_FUNC(simple_strtoul, unsigned long, simple_strtoul, + const char *, char **, unsigned int) + EXPORT_FUNC(strict_strtoul, int, strict_strtoul, + const char *, unsigned int , unsigned long *) + EXPORT_FUNC(simple_strtol, long, simple_strtol, + const char *, char **, unsigned int) + EXPORT_FUNC(strcmp, int, strcmp, const char *cs, const char *ct) +#if defined(CONFIG_CMD_I2C) && \ + (!defined(CONFIG_DM_I2C) || defined(CONFIG_DM_I2C_COMPAT)) + EXPORT_FUNC(i2c_write, int, i2c_write, uchar, uint, int , uchar * , int) + EXPORT_FUNC(i2c_read, int, i2c_read, uchar, uint, int , uchar * , int) +#else + EXPORT_FUNC(dummy, void, i2c_write, void) + EXPORT_FUNC(dummy, void, i2c_read, void) +#endif + +#if !defined(CONFIG_CMD_SPI) || defined(CONFIG_DM_SPI) + EXPORT_FUNC(dummy, void, spi_init, void) + EXPORT_FUNC(dummy, void, spi_setup_slave, void) + EXPORT_FUNC(dummy, void, spi_free_slave, void) +#else + EXPORT_FUNC(spi_init, void, spi_init, void) + EXPORT_FUNC(spi_setup_slave, struct spi_slave *, spi_setup_slave, + unsigned int, unsigned int, unsigned int, unsigned int) + EXPORT_FUNC(spi_free_slave, void, spi_free_slave, struct spi_slave *) +#endif +#ifndef CONFIG_CMD_SPI + EXPORT_FUNC(dummy, void, spi_claim_bus, void) + EXPORT_FUNC(dummy, void, spi_release_bus, void) + EXPORT_FUNC(dummy, void, spi_xfer, void) +#else + EXPORT_FUNC(spi_claim_bus, int, spi_claim_bus, struct spi_slave *) + EXPORT_FUNC(spi_release_bus, void, spi_release_bus, struct spi_slave *) + EXPORT_FUNC(spi_xfer, int, spi_xfer, struct spi_slave *, + unsigned int, const void *, void *, unsigned long) +#endif + EXPORT_FUNC(ustrtoul, unsigned long, ustrtoul, + const char *, char **, unsigned int) + EXPORT_FUNC(ustrtoull, unsigned long long, ustrtoull, + const char *, char **, unsigned int) diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index 3d14d5f1174..6747619b1c7 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -73,7 +73,7 @@ typedef struct global_data { const void *fdt_blob; /* Our device tree, NULL if none */ void *new_fdt; /* Relocated FDT */ unsigned long fdt_size; /* Space reserved for relocated FDT */ - void **jt; /* jump table */ + struct jt_funcs *jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ #ifdef CONFIG_TRACE void *trace_buff; /* The trace buffer */ diff --git a/include/exports.h b/include/exports.h index 41d5085e16c..205affe72d7 100644 --- a/include/exports.h +++ b/include/exports.h @@ -3,6 +3,8 @@ #ifndef __ASSEMBLY__ +struct spi_slave; + /* These are declarations of exported functions available in C code */ unsigned long get_version(void); int getc(void); @@ -10,22 +12,23 @@ int tstc(void); void putc(const char); void puts(const char*); int printf(const char* fmt, ...); -void install_hdlr(int, void (*interrupt_handler_t)(void *), void*); +void install_hdlr(int, interrupt_handler_t, void*); void free_hdlr(int); void *malloc(size_t); void free(void*); void __udelay(unsigned long); unsigned long get_timer(unsigned long); int vprintf(const char *, va_list); -unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base); +unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base); int strict_strtoul(const char *cp, unsigned int base, unsigned long *res); char *getenv (const char *name); int setenv (const char *varname, const char *varvalue); -long simple_strtol(const char *cp,char **endp,unsigned int base); -int strcmp(const char * cs,const char * ct); +long simple_strtol(const char *cp, char **endp, unsigned int base); +int strcmp(const char *cs, const char *ct); unsigned long ustrtoul(const char *cp, char **endp, unsigned int base); unsigned long long ustrtoull(const char *cp, char **endp, unsigned int base); -#if defined(CONFIG_CMD_I2C) +#if defined(CONFIG_CMD_I2C) && \ + (!defined(CONFIG_DM_I2C) || defined(CONFIG_DM_I2C_COMPAT)) int i2c_write (uchar, uint, int , uchar* , int); int i2c_read (uchar, uint, int , uchar* , int); #endif @@ -34,15 +37,14 @@ void app_startup(char * const *); #endif /* ifndef __ASSEMBLY__ */ -enum { -#define EXPORT_FUNC(x) XF_ ## x , +struct jt_funcs { +#define EXPORT_FUNC(impl, res, func, ...) res(*func)(__VA_ARGS__); #include <_exports.h> #undef EXPORT_FUNC - - XF_MAX }; -#define XF_VERSION 6 + +#define XF_VERSION 7 #if defined(CONFIG_X86) extern gd_t *global_data; -- cgit v1.3.1 From 7132b9fd68a1c76bf557d56dd62756a6607cf761 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 26 Jan 2015 20:29:37 -0700 Subject: dm: i2c: dts: Support an offset-len device tree property Since U-Boot can support different offset lengths (0-4 bytes), add a device tree property to specify this. This avoids hard-coding it in the driver. Signed-off-by: Simon Glass --- doc/device-tree-bindings/i2c/i2c.txt | 28 ++++++++++++++++++++++++++++ drivers/i2c/i2c-uclass.c | 3 ++- 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 doc/device-tree-bindings/i2c/i2c.txt (limited to 'doc') diff --git a/doc/device-tree-bindings/i2c/i2c.txt b/doc/device-tree-bindings/i2c/i2c.txt new file mode 100644 index 00000000000..ea918dd61d5 --- /dev/null +++ b/doc/device-tree-bindings/i2c/i2c.txt @@ -0,0 +1,28 @@ +U-Boot I2C +---------- + +U-Boot's I2C model has the concept of an offset within a chip (I2C target +device). The offset can be up to 4 bytes long, but is normally 1 byte, +meaning that offsets from 0 to 255 are supported by the chip. This often +corresponds to register numbers. + +Apart from the controller-specific I2C bindings, U-Boot supports a special +property which allows the chip offset length to be selected. + +Optional properties: +- u-boot,i2c-offset-len - length of chip offset in bytes. If omitted the + default value of 1 is used. + + +Example +------- + +i2c4: i2c@12ca0000 { + cros-ec@1e { + reg = <0x1e>; + compatible = "google,cros-ec"; + i2c-max-frequency = <100000>; + u-boot,i2c-offset-len = <0>; + ec-interrupt = <&gpx1 6 GPIO_ACTIVE_LOW>; + }; +}; diff --git a/drivers/i2c/i2c-uclass.c b/drivers/i2c/i2c-uclass.c index 393cd6f583a..eafa457845d 100644 --- a/drivers/i2c/i2c-uclass.c +++ b/drivers/i2c/i2c-uclass.c @@ -420,7 +420,8 @@ int i2c_deblock(struct udevice *bus) int i2c_chip_ofdata_to_platdata(const void *blob, int node, struct dm_i2c_chip *chip) { - chip->offset_len = 1; /* default */ + chip->offset_len = fdtdec_get_int(gd->fdt_blob, node, + "u-boot,i2c-offset-len", 1); chip->flags = 0; chip->chip_addr = fdtdec_get_int(gd->fdt_blob, node, "reg", -1); if (chip->chip_addr == -1) { -- cgit v1.3.1