[U-Boot] [PATCH 00/50] rockchip: Add support for cros_ec keyboard

This series provides a number of new features and improvements leading to enabling the keyboard (via Chrome OS EC) on jerry. This is conneected via SPI and uses its own message protocol.
Features and fixes are needed in the rockchip code to make this work include: - RK808 PMIC and regulator driver - Fixes and improvements to the i2c and SPI drivers - A full implementation of the GPIO driver - Additional clock support - Additional pinctrl support
The series moves a few rockchip boards to use the full pinctrl driver. I'm not sure this is a great idea, as it slows down start-up noticeably. It is currently needed for the display series (to come), but I intend to change that.
Simon Glass (50): dm: clk: Add support for decoding clocks from the device tree dm: core: Don't set pinctrl for pinctrl devices dm: pinctrl: Add a function to parse PIN_CONFIG flags dm: pmic: Add 'reg status' to show all regulators dts: Bring in pinctrl device tree binding power: Add base support for the RK808 PMIC power: Add support for RK808 regulators dm: Add a power sequencing uclass rockchip: Avoid using MMC code when not booting from MMC rockchip: Convert the PMU IOMUX registers into an array rockchip: mmc: Use a pwrseq device if available rockchip: Correct the defconfig order rockchip: Use pwrseq for MMC start-up on jerry rockchip: jerry: Disable pmic-int-1 setup to avoid a hang rockchip: Use a separate clock ID for clocks rockchip: clock: Rename the general clock variable to gclk_rate rockchip: clk: Add a function to get a peripheral clock rate rockchip: clock: Add a function to find a clock by ID rockchip: i2c: Update the driver to use the new clock ID rockchip: spi: Update the driver to use the new clock ID rockchip: spi: Avoid setting the pinctrl twice rockchip: mmc: Update the driver to use the new clock ID rockchip: pinctrl: Add a full pinctrl driver rockchip: Move firefly and jerry to use the full pinctrl rockchip: jerry: Enable the RK808 PMIC and regulator rockchip: Disable simple-bus in SPL for firefly-rk3288, jerry rockchip: jerry: Drop unused options gpio: Allow 's' as an abbreviation for 'status' cros_ec: Disable the Chrome OS EC in SPL dm: i2c: Allow muxes to be enabled for SPL separately spi: Correct device tree usage in spi_flash_decode_fdt() dm: power: Allow regulators to be omitted from SPL dm: pinctrl: Add a way for a GPIO driver to obtain a pin function dm: core: Export uclass_find_device_by_of_offset() dm: power: Tidy up debugging output and return values dm: power: Allow regulators to not implement all operations dm: clk: Add a simple version of clk_get_by_index() rockchip: sdram: Use the rk_clr/setreg() interface rockchip: reset: Use the rk_clr/setreg() interface rockchip: spi: Remember the last speed to avoid re-setting it rockchip: spi: Correct the bus init code rockchip: clk: Make rkclk_get_clk() SoC-specific rockchip: pinctrl: Reduce the size for SPL rockchip: pinctrl: Implement the get_gpio_mux() method rockchip: gpio: Read the GPIO value correctly rockchip: gpio: Implement the get_function() method rockchip: spi: Implement the delays rockchip: spi: Correct chip-enable code rockchip: spi: Remove the explicit pinctrl setting rockchip: jerry: Enable the Chrome OS EC
arch/arm/dts/rk3288-veyron-chromebook.dtsi | 4 + arch/arm/dts/rk3288-veyron.dtsi | 20 +- arch/arm/include/asm/arch-rockchip/clock.h | 12 + arch/arm/include/asm/arch-rockchip/pmu_rk3288.h | 12 +- arch/arm/mach-rockchip/Makefile | 1 - arch/arm/mach-rockchip/common.c | 28 -- arch/arm/mach-rockchip/rk3288-board-spl.c | 2 + arch/arm/mach-rockchip/rk3288/reset_rk3288.c | 4 +- arch/arm/mach-rockchip/rk3288/sdram_rk3288.c | 7 +- common/cmd_gpio.c | 2 +- common/cmd_regulator.c | 66 ++++- configs/chromebook_jerry_defconfig | 25 +- configs/firefly-rk3288_defconfig | 7 +- .../pinctrl/pinctrl-bindings.txt | 236 ++++++++++++++++ drivers/clk/clk-uclass.c | 46 ++++ drivers/clk/clk_rk3036.c | 33 ++- drivers/clk/clk_rk3288.c | 157 ++++++++--- drivers/core/device.c | 6 +- drivers/core/uclass.c | 4 +- drivers/gpio/rk_gpio.c | 42 ++- drivers/i2c/Makefile | 4 +- drivers/i2c/muxes/Kconfig | 9 + drivers/i2c/muxes/Makefile | 2 +- drivers/i2c/rk_i2c.c | 37 +-- drivers/misc/Kconfig | 18 ++ drivers/misc/Makefile | 3 + drivers/misc/pwrseq-uclass.c | 24 ++ drivers/mmc/rockchip_dw_mmc.c | 57 +++- drivers/mtd/spi/spi_flash.c | 9 +- drivers/pinctrl/pinctrl-uclass.c | 22 ++ drivers/pinctrl/rockchip/pinctrl_rk3288.c | 290 +++++++++++++++++++- drivers/power/pmic/Kconfig | 30 ++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/pmic-uclass.c | 13 +- drivers/power/pmic/rk808.c | 102 +++++++ drivers/power/regulator/Kconfig | 18 ++ drivers/power/regulator/Makefile | 5 +- drivers/power/regulator/regulator-uclass.c | 4 +- drivers/power/regulator/rk808.c | 301 +++++++++++++++++++++ drivers/spi/rk_spi.c | 83 +++--- include/clk.h | 15 + include/configs/chromebook_jerry.h | 9 + include/configs/firefly-rk3288.h | 2 + include/configs/rk3288_common.h | 8 + include/dm/pinctrl.h | 45 +++ include/dm/uclass-id.h | 1 + include/dm/uclass-internal.h | 16 ++ include/power/rk808_pmic.h | 77 ++++++ include/pwrseq.h | 18 ++ 49 files changed, 1731 insertions(+), 206 deletions(-) delete mode 100644 arch/arm/mach-rockchip/common.c create mode 100644 doc/device-tree-bindings/pinctrl/pinctrl-bindings.txt create mode 100644 drivers/misc/pwrseq-uclass.c create mode 100644 drivers/power/pmic/rk808.c create mode 100644 drivers/power/regulator/rk808.c create mode 100644 include/power/rk808_pmic.h create mode 100644 include/pwrseq.h

Add a method which can locate a clock for a device, given its index. This uses the normal device tree bindings to return the clock device and the first argument which is normally used as a peripheral ID in U-Boot.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/clk/clk-uclass.c | 28 ++++++++++++++++++++++++++++ include/clk.h | 15 +++++++++++++++ 2 files changed, 43 insertions(+)
diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c index 8078b0f..a205b26 100644 --- a/drivers/clk/clk-uclass.c +++ b/drivers/clk/clk-uclass.c @@ -12,6 +12,8 @@ #include <dm/lists.h> #include <dm/root.h>
+DECLARE_GLOBAL_DATA_PTR; + ulong clk_get_rate(struct udevice *dev) { struct clk_ops *ops = clk_get_ops(dev); @@ -62,6 +64,32 @@ int clk_get_id(struct udevice *dev, int args_count, uint32_t *args) return ops->get_id(dev, args_count, args); }
+int clk_get_by_index(struct udevice *dev, int index, struct udevice **clk_devp, + int *periphp) +{ + struct fdtdec_phandle_args args; + int ret; + + ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev->of_offset, + "clocks", "#clock-cells", 0, index, + &args); + if (ret) { + debug("%s: fdtdec_parse_phandle_with_args failed: err=%d\n", + __func__, ret); + return ret; + } + + ret = uclass_get_device_by_of_offset(UCLASS_CLK, args.node, clk_devp); + if (ret) { + debug("%s: uclass_get_device_by_of_offset failed: err=%d\n", + __func__, ret); + return ret; + } + *periphp = args.args_count > 0 ? args.args[0] : -1; + + return 0; +} + UCLASS_DRIVER(clk) = { .id = UCLASS_CLK, .name = "clk", diff --git a/include/clk.h b/include/clk.h index ce2db41..b77c788 100644 --- a/include/clk.h +++ b/include/clk.h @@ -150,4 +150,19 @@ static inline int fdt_clk_get(const void *fdt, int nodeoffset, int index, } #endif
+/** + * clk_get_by_index() - look up a clock referenced by a device + * + * Parse a device's 'clocks' list, returning information on the indexed clock, + * ensuring that it is activated. + * + * @dev: Device containing the clock reference + * @index: Clock index to return (0 = first) + * @clk_devp: Returns clock device + * @periphp: Returns peripheral ID for the device to control. This is the + * first argument after the clock node phandle. + * @return 0 if OK, or -ve error code + */ +int clk_get_by_index(struct udevice *dev, int index, struct udevice **clk_devp, + int *periphp); #endif /* _CLK_H_ */

Hi Simon,
@@ -12,6 +12,8 @@ #include <dm/lists.h> #include <dm/root.h>
+DECLARE_GLOBAL_DATA_PTR;
ulong clk_get_rate(struct udevice *dev) { struct clk_ops *ops = clk_get_ops(dev); @@ -62,6 +64,32 @@ int clk_get_id(struct udevice *dev, int args_count, uint32_t *args) return ops->get_id(dev, args_count, args); }
+int clk_get_by_index(struct udevice *dev, int index, struct udevice **clk_devp,
int *periphp)
This function causes NULL pointer access if called with clk_devp == NULL.
You can decrease the number of arguments if this function returns periph ID.
+{
struct fdtdec_phandle_args args;
int ret;
ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev->of_offset,
"clocks", "#clock-cells", 0, index,
&args);
if (ret) {
debug("%s: fdtdec_parse_phandle_with_args failed: err=%d\n",
__func__, ret);
return ret;
}
ret = uclass_get_device_by_of_offset(UCLASS_CLK, args.node, clk_devp);
if (ret) {
debug("%s: uclass_get_device_by_of_offset failed: err=%d\n",
__func__, ret);
return ret;
}
*periphp = args.args_count > 0 ? args.args[0] : -1;
Do you want to let this function fail against #clock-cells == 0?
This code should be compiled only when OF_CONTROL is on.

Hi Masahiro,
On 14 January 2016 at 03:11, Masahiro Yamada yamada.masahiro@socionext.com wrote:
Hi Simon,
@@ -12,6 +12,8 @@ #include <dm/lists.h> #include <dm/root.h>
+DECLARE_GLOBAL_DATA_PTR;
ulong clk_get_rate(struct udevice *dev) { struct clk_ops *ops = clk_get_ops(dev); @@ -62,6 +64,32 @@ int clk_get_id(struct udevice *dev, int args_count, uint32_t *args) return ops->get_id(dev, args_count, args); }
+int clk_get_by_index(struct udevice *dev, int index, struct udevice **clk_devp,
int *periphp)
This function causes NULL pointer access if called with clk_devp == NULL.
Yes, don't do that. Do you think the function comment is unclear?
You can decrease the number of arguments if this function returns periph ID.
Right, but how to handle 0?
+{
struct fdtdec_phandle_args args;
int ret;
ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev->of_offset,
"clocks", "#clock-cells", 0, index,
&args);
if (ret) {
debug("%s: fdtdec_parse_phandle_with_args failed: err=%d\n",
__func__, ret);
return ret;
}
ret = uclass_get_device_by_of_offset(UCLASS_CLK, args.node, clk_devp);
if (ret) {
debug("%s: uclass_get_device_by_of_offset failed: err=%d\n",
__func__, ret);
return ret;
}
*periphp = args.args_count > 0 ? args.args[0] : -1;
Do you want to let this function fail against #clock-cells == 0?
At present it doesn't. That's why I didn't have it return the peripheral ID. What could we return to signify that the function succeeded but there was no peripheral ID?
This code should be compiled only when OF_CONTROL is on.
OK, I'll update it once we sort out the above.
Regards, Simon

Hi Simon,
2016-01-15 22:21 GMT+09:00 Simon Glass sjg@chromium.org:
Hi Masahiro,
On 14 January 2016 at 03:11, Masahiro Yamada yamada.masahiro@socionext.com wrote:
Hi Simon,
@@ -12,6 +12,8 @@ #include <dm/lists.h> #include <dm/root.h>
+DECLARE_GLOBAL_DATA_PTR;
ulong clk_get_rate(struct udevice *dev) { struct clk_ops *ops = clk_get_ops(dev); @@ -62,6 +64,32 @@ int clk_get_id(struct udevice *dev, int args_count, uint32_t *args) return ops->get_id(dev, args_count, args); }
+int clk_get_by_index(struct udevice *dev, int index, struct udevice **clk_devp,
int *periphp)
This function causes NULL pointer access if called with clk_devp == NULL.
Yes, don't do that. Do you think the function comment is unclear?
This would not be a problem in this case, but I thought NULL-pointer checking is a boilterplate when we return a pointer filled into a function argument.
You can decrease the number of arguments if this function returns periph ID.
Right, but how to handle 0?
= 0 means peripheral ID.
< 0 means error code.
+{
struct fdtdec_phandle_args args;
int ret;
ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev->of_offset,
"clocks", "#clock-cells", 0, index,
&args);
if (ret) {
debug("%s: fdtdec_parse_phandle_with_args failed: err=%d\n",
__func__, ret);
return ret;
}
ret = uclass_get_device_by_of_offset(UCLASS_CLK, args.node, clk_devp);
if (ret) {
debug("%s: uclass_get_device_by_of_offset failed: err=%d\n",
__func__, ret);
return ret;
}
*periphp = args.args_count > 0 ? args.args[0] : -1;
Do you want to let this function fail against #clock-cells == 0?
At present it doesn't. That's why I didn't have it return the peripheral ID. What could we return to signify that the function succeeded but there was no peripheral ID?
I think any clock provider should have at least one ID.
If "clock-cells == 0", this clock has ID 0.
Please correct me if I am misunderstanding.

Hi Masahiro,
On 18 January 2016 at 19:01, Masahiro Yamada yamada.masahiro@socionext.com wrote:
Hi Simon,
2016-01-15 22:21 GMT+09:00 Simon Glass sjg@chromium.org:
Hi Masahiro,
On 14 January 2016 at 03:11, Masahiro Yamada yamada.masahiro@socionext.com wrote:
Hi Simon,
@@ -12,6 +12,8 @@ #include <dm/lists.h> #include <dm/root.h>
+DECLARE_GLOBAL_DATA_PTR;
ulong clk_get_rate(struct udevice *dev) { struct clk_ops *ops = clk_get_ops(dev); @@ -62,6 +64,32 @@ int clk_get_id(struct udevice *dev, int args_count, uint32_t *args) return ops->get_id(dev, args_count, args); }
+int clk_get_by_index(struct udevice *dev, int index, struct udevice **clk_devp,
int *periphp)
This function causes NULL pointer access if called with clk_devp == NULL.
Yes, don't do that. Do you think the function comment is unclear?
This would not be a problem in this case, but I thought NULL-pointer checking is a boilterplate when we return a pointer filled into a function argument.
You can decrease the number of arguments if this function returns periph ID.
Right, but how to handle 0?
= 0 means peripheral ID.
< 0 means error code.
+{
struct fdtdec_phandle_args args;
int ret;
ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev->of_offset,
"clocks", "#clock-cells", 0, index,
&args);
if (ret) {
debug("%s: fdtdec_parse_phandle_with_args failed: err=%d\n",
__func__, ret);
return ret;
}
ret = uclass_get_device_by_of_offset(UCLASS_CLK, args.node, clk_devp);
if (ret) {
debug("%s: uclass_get_device_by_of_offset failed: err=%d\n",
__func__, ret);
return ret;
}
*periphp = args.args_count > 0 ? args.args[0] : -1;
Do you want to let this function fail against #clock-cells == 0?
At present it doesn't. That's why I didn't have it return the peripheral ID. What could we return to signify that the function succeeded but there was no peripheral ID?
I think any clock provider should have at least one ID.
If "clock-cells == 0", this clock has ID 0.
Please correct me if I am misunderstanding.
That sounds fine to me. I've sent an update to that one patch.
Regards, Simon

There is sort-of race condition when a pinctrl device is probed. The pinctrl function is called which may end up using the same device as is being probed. This results in operations being used before the device is actually probed.
For now, disallow pinctrl operations on pinctrl devices while probing. An alternative solution would be to move the operation to later in the device_probe() function (for pinctrl devices only) but this needs more thought.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/core/device.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/core/device.c b/drivers/core/device.c index a9fcac9..f7eab17 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -299,9 +299,11 @@ int device_probe_child(struct udevice *dev, void *parent_priv)
/* * Process pinctrl for everything except the root device, and - * continue regardless of the result of pinctrl. + * continue regardless of the result of pinctrl. Don't process pinctrl + * settings for pinctrl devices since the device may not yet be + * probed. */ - if (dev->parent) + if (dev->parent && device_get_uclass_id(dev) != UCLASS_PINCTRL) pinctrl_select_state(dev, "default");
ret = uclass_pre_probe_device(dev);

Add a function which produces a flags word from a few common PIN_CONFIG settings. This is useful for simple pinctrl drivers that don't need to worry about drive strength, etc.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/pinctrl/pinctrl-uclass.c | 12 ++++++++++++ include/dm/pinctrl.h | 13 +++++++++++++ 2 files changed, 25 insertions(+)
diff --git a/drivers/pinctrl/pinctrl-uclass.c b/drivers/pinctrl/pinctrl-uclass.c index c42b312..1acbfaf 100644 --- a/drivers/pinctrl/pinctrl-uclass.c +++ b/drivers/pinctrl/pinctrl-uclass.c @@ -15,6 +15,18 @@
DECLARE_GLOBAL_DATA_PTR;
+int pinctrl_decode_pin_config(const void *blob, int node) +{ + int flags = 0; + + if (fdtdec_get_bool(blob, node, "bias-pull-up")) + flags |= 1 << PIN_CONFIG_BIAS_PULL_UP; + else if (fdtdec_get_bool(blob, node, "bias-pull-down")) + flags |= 1 << PIN_CONFIG_BIAS_PULL_DOWN; + + return flags; +} + #if CONFIG_IS_ENABLED(PINCTRL_FULL) /** * pinctrl_config_one() - apply pinctrl settings for a single node diff --git a/include/dm/pinctrl.h b/include/dm/pinctrl.h index f6025f6..5cd4503 100644 --- a/include/dm/pinctrl.h +++ b/include/dm/pinctrl.h @@ -284,4 +284,17 @@ int pinctrl_request_noflags(struct udevice *dev, int func); */ int pinctrl_get_periph_id(struct udevice *dev, struct udevice *periph);
+/** + * pinctrl_decode_pin_config() - decode pin configuration flags + * + * This decodes some of the PIN_CONFIG values into flags, with each value + * being (1 << pin_cfg). This does not support things with values like the + * slew rate. + * + * @blob: Device tree blob + * @node: Node containing the PIN_CONFIG values + * @return decoded flag value, or -ve on error + */ +int pinctrl_decode_pin_config(const void *blob, int node); + #endif /* __PINCTRL_H */

It is convenient to be able to see the status of all regulators in a list. Add this feature to the 'reg status' command.
Signed-off-by: Simon Glass sjg@chromium.org ---
common/cmd_regulator.c | 66 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 56 insertions(+), 10 deletions(-)
diff --git a/common/cmd_regulator.c b/common/cmd_regulator.c index 793f08e..bfea6e0 100644 --- a/common/cmd_regulator.c +++ b/common/cmd_regulator.c @@ -180,18 +180,13 @@ static int do_info(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) return CMD_RET_SUCCESS; }
-static int do_status(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +static void do_status_detail(struct udevice *dev, + struct dm_regulator_uclass_platdata *uc_pdata) { - struct dm_regulator_uclass_platdata *uc_pdata; - int current, value, mode, ret; - const char *mode_name = NULL; - struct udevice *dev; + int current, value, mode; + const char *mode_name; bool enabled;
- ret = curr_dev_and_platdata(&dev, &uc_pdata, true); - if (ret) - return ret; - printf("Regulator %s status:\n", uc_pdata->name);
enabled = regulator_get_enable(dev); @@ -206,6 +201,57 @@ static int do_status(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) mode = regulator_get_mode(dev); mode_name = get_mode_name(uc_pdata->mode, uc_pdata->mode_count, mode); constraint(" * mode id:", mode, mode_name); +} + +static void do_status_line(struct udevice *dev) +{ + struct dm_regulator_uclass_platdata *pdata; + int current, value, mode; + const char *mode_name; + bool enabled; + + pdata = dev_get_uclass_platdata(dev); + enabled = regulator_get_enable(dev); + value = regulator_get_value(dev); + current = regulator_get_current(dev); + mode = regulator_get_mode(dev); + mode_name = get_mode_name(pdata->mode, pdata->mode_count, mode); + printf("%-20s %-10s ", pdata->name, enabled ? "enabled" : "disabled"); + if (value >= 0) + printf("%10d ", value); + else + printf("%10s ", "-"); + if (current >= 0) + printf("%10d ", current); + else + printf("%10s ", "-"); + if (mode >= 0) + printf("%-10s", mode_name); + else + printf("%-10s", "-"); + printf("\n"); +} + +static int do_status(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + struct dm_regulator_uclass_platdata *uc_pdata; + struct udevice *dev; + int ret; + + if (currdev && (argc < 2 || strcmp(argv[1], "-a"))) { + ret = curr_dev_and_platdata(&dev, &uc_pdata, true); + if (ret) + return CMD_RET_FAILURE; + do_status_detail(dev, uc_pdata); + return 0; + } + + /* Show all of them in a list, probing them as needed */ + printf("%-20s %-10s %10s %10s %-10s\n", "Name", "Enabled", "uV", "mA", + "Mode"); + for (ret = uclass_first_device(UCLASS_REGULATOR, &dev); dev; + ret = uclass_next_device(&dev)) + do_status_line(dev);
return CMD_RET_SUCCESS; } @@ -400,7 +446,7 @@ U_BOOT_CMD(regulator, CONFIG_SYS_MAXARGS, 1, do_regulator, "list - list UCLASS regulator devices\n" "regulator dev [regulator-name] - show/[set] operating regulator device\n" "regulator info - print constraints info\n" - "regulator status - print operating status\n" + "regulator status [-a] - print operating status [for all]\n" "regulator value [val] [-f] - print/[set] voltage value [uV] (force)\n" "regulator current [val] - print/[set] current value [uA]\n" "regulator mode [id] - print/[set] operating mode id\n"

Add this binding file since we now use it in U-Boot.
Signed-off-by: Simon Glass sjg@chromium.org ---
.../pinctrl/pinctrl-bindings.txt | 236 +++++++++++++++++++++ 1 file changed, 236 insertions(+) create mode 100644 doc/device-tree-bindings/pinctrl/pinctrl-bindings.txt
diff --git a/doc/device-tree-bindings/pinctrl/pinctrl-bindings.txt b/doc/device-tree-bindings/pinctrl/pinctrl-bindings.txt new file mode 100644 index 0000000..b73c96d --- /dev/null +++ b/doc/device-tree-bindings/pinctrl/pinctrl-bindings.txt @@ -0,0 +1,236 @@ +== Introduction == + +Hardware modules that control pin multiplexing or configuration parameters +such as pull-up/down, tri-state, drive-strength etc are designated as pin +controllers. Each pin controller must be represented as a node in device tree, +just like any other hardware module. + +Hardware modules whose signals are affected by pin configuration are +designated client devices. Again, each client device must be represented as a +node in device tree, just like any other hardware module. + +For a client device to operate correctly, certain pin controllers must +set up certain specific pin configurations. Some client devices need a +single static pin configuration, e.g. set up during initialization. Others +need to reconfigure pins at run-time, for example to tri-state pins when the +device is inactive. Hence, each client device can define a set of named +states. The number and names of those states is defined by the client device's +own binding. + +The common pinctrl bindings defined in this file provide an infrastructure +for client device device tree nodes to map those state names to the pin +configuration used by those states. + +Note that pin controllers themselves may also be client devices of themselves. +For example, a pin controller may set up its own "active" state when the +driver loads. This would allow representing a board's static pin configuration +in a single place, rather than splitting it across multiple client device +nodes. The decision to do this or not somewhat rests with the author of +individual board device tree files, and any requirements imposed by the +bindings for the individual client devices in use by that board, i.e. whether +they require certain specific named states for dynamic pin configuration. + +== Pinctrl client devices == + +For each client device individually, every pin state is assigned an integer +ID. These numbers start at 0, and are contiguous. For each state ID, a unique +property exists to define the pin configuration. Each state may also be +assigned a name. When names are used, another property exists to map from +those names to the integer IDs. + +Each client device's own binding determines the set of states that must be +defined in its device tree node, and whether to define the set of state +IDs that must be provided, or whether to define the set of state names that +must be provided. + +Required properties: +pinctrl-0: List of phandles, each pointing at a pin configuration + node. These referenced pin configuration nodes must be child + nodes of the pin controller that they configure. Multiple + entries may exist in this list so that multiple pin + controllers may be configured, or so that a state may be built + from multiple nodes for a single pin controller, each + contributing part of the overall configuration. See the next + section of this document for details of the format of these + pin configuration nodes. + + In some cases, it may be useful to define a state, but for it + to be empty. This may be required when a common IP block is + used in an SoC either without a pin controller, or where the + pin controller does not affect the HW module in question. If + the binding for that IP block requires certain pin states to + exist, they must still be defined, but may be left empty. + +Optional properties: +pinctrl-1: List of phandles, each pointing at a pin configuration + node within a pin controller. +... +pinctrl-n: List of phandles, each pointing at a pin configuration + node within a pin controller. +pinctrl-names: The list of names to assign states. List entry 0 defines the + name for integer state ID 0, list entry 1 for state ID 1, and + so on. + +For example: + + /* For a client device requiring named states */ + device { + pinctrl-names = "active", "idle"; + pinctrl-0 = <&state_0_node_a>; + pinctrl-1 = <&state_1_node_a &state_1_node_b>; + }; + + /* For the same device if using state IDs */ + device { + pinctrl-0 = <&state_0_node_a>; + pinctrl-1 = <&state_1_node_a &state_1_node_b>; + }; + + /* + * For an IP block whose binding supports pin configuration, + * but in use on an SoC that doesn't have any pin control hardware + */ + device { + pinctrl-names = "active", "idle"; + pinctrl-0 = <>; + pinctrl-1 = <>; + }; + +== Pin controller devices == + +Pin controller devices should contain the pin configuration nodes that client +devices reference. + +For example: + + pincontroller { + ... /* Standard DT properties for the device itself elided */ + + state_0_node_a { + ... + }; + state_1_node_a { + ... + }; + state_1_node_b { + ... + }; + } + +The contents of each of those pin configuration child nodes is defined +entirely by the binding for the individual pin controller device. There +exists no common standard for this content. + +The pin configuration nodes need not be direct children of the pin controller +device; they may be grandchildren, for example. Whether this is legal, and +whether there is any interaction between the child and intermediate parent +nodes, is again defined entirely by the binding for the individual pin +controller device. + +== Generic pin multiplexing node content == + +pin multiplexing nodes: + +function - the mux function to select +groups - the list of groups to select with this function + (either this or "pins" must be specified) +pins - the list of pins to select with this function (either + this or "groups" must be specified) + +Example: + +state_0_node_a { + uart0 { + function = "uart0"; + groups = "u0rxtx", "u0rtscts"; + }; +}; +state_1_node_a { + spi0 { + function = "spi0"; + groups = "spi0pins"; + }; +}; +state_2_node_a { + function = "i2c0"; + pins = "mfio29", "mfio30"; +}; + +== Generic pin configuration node content == + +Many data items that are represented in a pin configuration node are common +and generic. Pin control bindings should use the properties defined below +where they are applicable; not all of these properties are relevant or useful +for all hardware or binding structures. Each individual binding document +should state which of these generic properties, if any, are used, and the +structure of the DT nodes that contain these properties. + +Supported generic properties are: + +pins - the list of pins that properties in the node + apply to (either this or "group" has to be + specified) +group - the group to apply the properties to, if the driver + supports configuration of whole groups rather than + individual pins (either this or "pins" has to be + specified) +bias-disable - disable any pin bias +bias-high-impedance - high impedance mode ("third-state", "floating") +bias-bus-hold - latch weakly +bias-pull-up - pull up the pin +bias-pull-down - pull down the pin +bias-pull-pin-default - use pin-default pull state +drive-push-pull - drive actively high and low +drive-open-drain - drive with open drain +drive-open-source - drive with open source +drive-strength - sink or source at most X mA +input-enable - enable input on pin (no effect on output) +input-disable - disable input on pin (no effect on output) +input-schmitt-enable - enable schmitt-trigger mode +input-schmitt-disable - disable schmitt-trigger mode +input-debounce - debounce mode with debound time X +power-source - select between different power supplies +low-power-enable - enable low power mode +low-power-disable - disable low power mode +output-low - set the pin to output mode with low level +output-high - set the pin to output mode with high level +slew-rate - set the slew rate + +For example: + +state_0_node_a { + cts_rxd { + pins = "GPIO0_AJ5", "GPIO2_AH4"; /* CTS+RXD */ + bias-pull-up; + }; +}; +state_1_node_a { + rts_txd { + pins = "GPIO1_AJ3", "GPIO3_AH3"; /* RTS+TXD */ + output-high; + }; +}; +state_2_node_a { + foo { + group = "foo-group"; + bias-pull-up; + }; +}; + +Some of the generic properties take arguments. For those that do, the +arguments are described below. + +- pins takes a list of pin names or IDs as a required argument. The specific + binding for the hardware defines: + - Whether the entries are integers or strings, and their meaning. + +- bias-pull-up, -down and -pin-default take as optional argument on hardware + supporting it the pull strength in Ohm. bias-disable will disable the pull. + +- drive-strength takes as argument the target strength in mA. + +- input-debounce takes the debounce time in usec as argument + or 0 to disable debouncing + +More in-depth documentation on these parameters can be found in +<include/linux/pinctrl/pinconf-generic.h>

This Rockchip PMIC provides features suitable for battery-powered applications. It is commonly used with Rockchip SoCs.
Add a driver which provides register access. The regulator driver will use this.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/power/pmic/Kconfig | 9 +++++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/rk808.c | 96 +++++++++++++++++++++++++++++++++++++++++++++ include/power/rk808_pmic.h | 77 ++++++++++++++++++++++++++++++++++++ 4 files changed, 183 insertions(+) create mode 100644 drivers/power/pmic/rk808.c create mode 100644 include/power/rk808_pmic.h
diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig index fb29843..8be3c07 100644 --- a/drivers/power/pmic/Kconfig +++ b/drivers/power/pmic/Kconfig @@ -33,6 +33,15 @@ config DM_PMIC_MAX77686 This config enables implementation of driver-model pmic uclass features for PMIC MAX77686. The driver implements read/write operations.
+config PMIC_RK808 + bool "Enable support for Rockchip PMIC RK808" + depends on DM_PMIC + ---help--- + The Rockchip RK808 PMIC provides four buck DC-DC convertors, 8 LDOs, + an RTC and two low Rds (resistance (drain to source)) switches. It is + accessed via an I2C interface. The device is used with Rockchip SoCs. + This driver implements register read/write operations. + config PMIC_S2MPS11 bool "Enable Driver Model for PMIC Samsung S2MPS11" depends on DM_PMIC diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile index 91e78f8..c6e8d0c 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_DM_PMIC_PFUZE100) += pfuze100.o obj-$(CONFIG_PMIC_S2MPS11) += s2mps11.o obj-$(CONFIG_DM_PMIC_SANDBOX) += sandbox.o i2c_pmic_emul.o obj-$(CONFIG_PMIC_ACT8846) += act8846.o +obj-$(CONFIG_PMIC_RK808) += rk808.o obj-$(CONFIG_PMIC_TPS65090) += tps65090.o obj-$(CONFIG_PMIC_S5M8767) += s5m8767.o
diff --git a/drivers/power/pmic/rk808.c b/drivers/power/pmic/rk808.c new file mode 100644 index 0000000..11d5f07 --- /dev/null +++ b/drivers/power/pmic/rk808.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2015 Google, Inc + * Written by Simon Glass sjg@chromium.org + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <fdtdec.h> +#include <libfdt.h> +#include <power/rk808_pmic.h> +#include <power/pmic.h> + +DECLARE_GLOBAL_DATA_PTR; + +static const struct pmic_child_info pmic_children_info[] = { + { .prefix = "DCDC_REG", .driver = "rk808_buck"}, + { .prefix = "LDO_REG", .driver = "rk808_ldo"}, + { .prefix = "SWITCH_REG", .driver = "rk808_switch"}, + { }, +}; + +static int rk808_reg_count(struct udevice *dev) +{ + return RK808_NUM_OF_REGS; +} + +static int rk808_write(struct udevice *dev, uint reg, const uint8_t *buff, + int len) +{ + if (dm_i2c_write(dev, reg, buff, len)) { + debug("write error to device: %p register: %#x!", dev, reg); + return -EIO; + } + + return 0; +} + +static int rk808_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{ + if (dm_i2c_read(dev, reg, buff, len)) { + debug("read error from device: %p register: %#x!", dev, reg); + return -EIO; + } + + return 0; +} + +#if CONFIG_IS_ENABLED(PMIC_CHILDREN) +static int rk808_bind(struct udevice *dev) +{ + const void *blob = gd->fdt_blob; + int regulators_node; + int children; + + regulators_node = fdt_subnode_offset(blob, dev->of_offset, + "regulators"); + if (regulators_node <= 0) { + debug("%s: %s regulators subnode not found!", __func__, + dev->name); + return -ENXIO; + } + + debug("%s: '%s' - found regulators subnode\n", __func__, dev->name); + + children = pmic_bind_children(dev, regulators_node, pmic_children_info); + if (!children) + debug("%s: %s - no child found\n", __func__, dev->name); + + /* Always return success for this device */ + return 0; +} +#endif + +static struct dm_pmic_ops rk808_ops = { + .reg_count = rk808_reg_count, + .read = rk808_read, + .write = rk808_write, +}; + +static const struct udevice_id rk808_ids[] = { + { .compatible = "rockchip,rk808" }, + { } +}; + +U_BOOT_DRIVER(pmic_rk808) = { + .name = "rk808 pmic", + .id = UCLASS_PMIC, + .of_match = rk808_ids, +#if CONFIG_IS_ENABLED(PMIC_CHILDREN) + .bind = rk808_bind, +#endif + .ops = &rk808_ops, +}; diff --git a/include/power/rk808_pmic.h b/include/power/rk808_pmic.h new file mode 100644 index 0000000..fb0800b --- /dev/null +++ b/include/power/rk808_pmic.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2015 Google, Inc + * Written by Simon Glass sjg@chromium.org + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _PMIC_RK808_H_ +#define _PMIC_RK808_H_ + +enum { + REG_DCDC_EN = 0x23, + REG_LDO_EN, + REG_SLEEP_SET_OFF1, + REG_SLEEP_SET_OFF2, + REG_DCDC_UV_STS, + + REG_DCDC_UV_ACT, + REG_LDO_UV_STS, + REG_LDO_UV_ACT, + REG_DCDC_PG, + REG_LDO_PG, + REG_VOUT_MON_TDB, + REG_BUCK1_CONFIG, + REG_BUCK1_ON_VSEL, + + REG_BUCK1_SLP_VSEL, + REG_BUCK1_DVS_VSEL, + REG_BUCK2_CONFIG, + REG_BUCK2_ON_VSEL, + REG_BUCK2_SLP_VSEL, + REG_BUCK2_DVS_VSEL, + REG_BUCK3_CONFIG, + REG_BUCK4_CONFIG, + + REG_BUCK4_ON_VSEL, + REG_BUCK4_SLP_VSEL, + LDO1_ON_VSEL = 0x3b, + LDO1_SLP_VSEL, + LDO2_ON_VSEL, + LDO2_SLP_VSEL, + LDO3_ON_VSEL, + + LDO3_SLP_VSEL, + LDO4_ON_VSEL, + LDO4_SLP_VSEL, + LDO5_ON_VSEL, + LDO5_SLP_VSEL, + LDO6_ON_VSEL, + LDO6_SLP_VSEL, + LDO7_ON_VSEL, + + LDO7_SLP_VSEL, + LDO8_ON_VSEL, + LDO8_SLP_VSEL, + DEVCTRL, + INT_STS1, + INT_STS_MSK1, + INT_STS2, + INT_STS_MSK2, + IO_POL, + + /* Not sure what this does */ + DCDC_ILMAX = 0x90, + + RK808_NUM_OF_REGS, +}; + +struct rk808_reg_table { + char *name; + u8 reg_ctl; + u8 reg_vol; +}; + +int rk808_spl_configure_buck(struct udevice *pmic, int buck, int uvolt); + +#endif

Add regulator support for the RK808 PMIC. It integrated 4 BUCKs and 8 LDOs all of which are supported by this driver.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/power/regulator/Kconfig | 9 ++ drivers/power/regulator/Makefile | 1 + drivers/power/regulator/rk808.c | 301 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 311 insertions(+) create mode 100644 drivers/power/regulator/rk808.c
diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig index 434dd02..8f638a9 100644 --- a/drivers/power/regulator/Kconfig +++ b/drivers/power/regulator/Kconfig @@ -49,6 +49,15 @@ config DM_REGULATOR_FIXED features for fixed value regulators. The driver implements get/set api for enable and get only for voltage value.
+config REGULATOR_RK808 + bool "Enable driver for RK808 regulators" + depends on DM_REGULATOR && PMIC_RK808 + ---help--- + Enable support for the regulator functions of the RK808 PMIC. The + driver implements get/set api for the various BUCKS and LDOs supported + by the PMIC device. This driver is controlled by a device tree node + which includes voltage limits. + config REGULATOR_S5M8767 bool "Enable support for S5M8767 regulator" depends on DM_REGULATOR && PMIC_S5M8767 diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile index c85978e..0d18c2b 100644 --- a/drivers/power/regulator/Makefile +++ b/drivers/power/regulator/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_REGULATOR_ACT8846) += act8846.o obj-$(CONFIG_DM_REGULATOR_MAX77686) += max77686.o obj-$(CONFIG_DM_REGULATOR_PFUZE100) += pfuze100.o obj-$(CONFIG_DM_REGULATOR_FIXED) += fixed.o +obj-$(CONFIG_REGULATOR_RK808) += rk808.o obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o obj-$(CONFIG_DM_REGULATOR_SANDBOX) += sandbox.o obj-$(CONFIG_REGULATOR_TPS65090) += tps65090_regulator.o diff --git a/drivers/power/regulator/rk808.c b/drivers/power/regulator/rk808.c new file mode 100644 index 0000000..adef8f5 --- /dev/null +++ b/drivers/power/regulator/rk808.c @@ -0,0 +1,301 @@ +/* + * Copyright (C) 2015 Google, Inc + * Written by Simon Glass sjg@chromium.org + * + * Based on Rockchip's drivers/power/pmic/pmic_rk808.c: + * Copyright (C) 2012 rockchips + * zyw zyw@rock-chips.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <power/rk808_pmic.h> +#include <power/pmic.h> +#include <power/regulator.h> + +#ifndef CONFIG_SPL_BUILD +#define ENABLE_DRIVER +#endif + +struct rk808_reg_info { + uint min_uv; + uint step_uv; + s8 vsel_reg; + u8 vsel_bits; +}; + +static const struct rk808_reg_info rk808_buck[] = { + { 712500, 12500, REG_BUCK1_ON_VSEL, 6, }, + { 712500, 12500, REG_BUCK2_ON_VSEL, 6, }, + { 712500, 12500, -1, 6, }, + { 1800000, 100000, REG_BUCK4_ON_VSEL, 4, }, +}; + +static const struct rk808_reg_info rk808_ldo[] = { + { 1800000, 100000, LDO1_ON_VSEL, 5, }, + { 1800000, 100000, LDO2_ON_VSEL, 5, }, + { 800000, 100000, LDO3_ON_VSEL, 4, }, + { 1800000, 100000, LDO4_ON_VSEL, 5, }, + { 1800000, 100000, LDO5_ON_VSEL, 5, }, + { 800000, 100000, LDO6_ON_VSEL, 5, }, + { 800000, 100000, LDO7_ON_VSEL, 5, }, + { 1800000, 100000, LDO8_ON_VSEL, 5, }, +}; + + +static int _buck_set_value(struct udevice *pmic, int buck, int uvolt) +{ + const struct rk808_reg_info *info = &rk808_buck[buck - 1]; + int mask = (1 << info->vsel_bits) - 1; + int val; + + if (info->vsel_reg == -1) + return -ENOSYS; + val = (uvolt - info->min_uv) / info->step_uv; + debug("%s: reg=%x, mask=%x, val=%x\n", __func__, info->vsel_reg, mask, + val); + + return pmic_clrsetbits(pmic, info->vsel_reg, mask, val); +} + +static int _buck_set_enable(struct udevice *pmic, int buck, bool enable) +{ + uint mask; + int ret; + + buck--; + mask = 1 << buck; + if (enable) { + ret = pmic_clrsetbits(pmic, DCDC_ILMAX, 0, 3 << (buck * 2)); + if (ret) + return ret; + ret = pmic_clrsetbits(pmic, REG_DCDC_UV_ACT, 1 << buck, 0); + if (ret) + return ret; + } + + return pmic_clrsetbits(pmic, REG_DCDC_EN, mask, enable ? mask : 0); +} + +#ifdef ENABLE_DRIVER +static int buck_get_value(struct udevice *dev) +{ + int buck = dev->driver_data - 1; + const struct rk808_reg_info *info = &rk808_buck[buck]; + int mask = (1 << info->vsel_bits) - 1; + int ret, val; + + if (info->vsel_reg == -1) + return -ENOSYS; + ret = pmic_reg_read(dev->parent, info->vsel_reg); + if (ret < 0) + return ret; + val = ret & mask; + + return info->min_uv + val * info->step_uv; +} + +static int buck_set_value(struct udevice *dev, int uvolt) +{ + int buck = dev->driver_data; + + return _buck_set_value(dev->parent, buck, uvolt); +} + +static int buck_set_enable(struct udevice *dev, bool enable) +{ + int buck = dev->driver_data; + + return _buck_set_enable(dev->parent, buck, enable); +} + +static bool buck_get_enable(struct udevice *dev) +{ + int buck = dev->driver_data - 1; + int ret; + uint mask; + + mask = 1 << buck; + + ret = pmic_reg_read(dev->parent, REG_DCDC_EN); + if (ret < 0) + return ret; + + return ret & mask ? true : false; +} + +static int ldo_get_value(struct udevice *dev) +{ + int ldo = dev->driver_data - 1; + const struct rk808_reg_info *info = &rk808_ldo[ldo]; + int mask = (1 << info->vsel_bits) - 1; + int ret, val; + + if (info->vsel_reg == -1) + return -ENOSYS; + ret = pmic_reg_read(dev->parent, info->vsel_reg); + if (ret < 0) + return ret; + val = ret & mask; + + return info->min_uv + val * info->step_uv; +} + +static int ldo_set_value(struct udevice *dev, int uvolt) +{ + int ldo = dev->driver_data - 1; + const struct rk808_reg_info *info = &rk808_ldo[ldo]; + int mask = (1 << info->vsel_bits) - 1; + int val; + + if (info->vsel_reg == -1) + return -ENOSYS; + val = (uvolt - info->min_uv) / info->step_uv; + debug("%s: reg=%x, mask=%x, val=%x\n", __func__, info->vsel_reg, mask, + val); + + return pmic_clrsetbits(dev->parent, info->vsel_reg, mask, val); +} + +static int ldo_set_enable(struct udevice *dev, bool enable) +{ + int ldo = dev->driver_data - 1; + uint mask; + + mask = 1 << ldo; + + return pmic_clrsetbits(dev->parent, REG_LDO_EN, mask, + enable ? mask : 0); +} + +static bool ldo_get_enable(struct udevice *dev) +{ + int ldo = dev->driver_data - 1; + int ret; + uint mask; + + mask = 1 << ldo; + + ret = pmic_reg_read(dev->parent, REG_LDO_EN); + if (ret < 0) + return ret; + + return ret & mask ? true : false; +} + +static int switch_set_enable(struct udevice *dev, bool enable) +{ + int sw = dev->driver_data - 1; + uint mask; + + mask = 1 << (sw + 5); + + return pmic_clrsetbits(dev->parent, REG_DCDC_EN, mask, + enable ? mask : 0); +} + +static bool switch_get_enable(struct udevice *dev) +{ + int sw = dev->driver_data - 1; + int ret; + uint mask; + + mask = 1 << (sw + 5); + + ret = pmic_reg_read(dev->parent, REG_DCDC_EN); + if (ret < 0) + return ret; + + return ret & mask ? true : false; +} + +static int rk808_buck_probe(struct udevice *dev) +{ + struct dm_regulator_uclass_platdata *uc_pdata; + + uc_pdata = dev_get_uclass_platdata(dev); + + uc_pdata->type = REGULATOR_TYPE_BUCK; + uc_pdata->mode_count = 0; + + return 0; +} + +static int rk808_ldo_probe(struct udevice *dev) +{ + struct dm_regulator_uclass_platdata *uc_pdata; + + uc_pdata = dev_get_uclass_platdata(dev); + + uc_pdata->type = REGULATOR_TYPE_LDO; + uc_pdata->mode_count = 0; + + return 0; +} + +static int rk808_switch_probe(struct udevice *dev) +{ + struct dm_regulator_uclass_platdata *uc_pdata; + + uc_pdata = dev_get_uclass_platdata(dev); + + uc_pdata->type = REGULATOR_TYPE_FIXED; + uc_pdata->mode_count = 0; + + return 0; +} + +static const struct dm_regulator_ops rk808_buck_ops = { + .get_value = buck_get_value, + .set_value = buck_set_value, + .get_enable = buck_get_enable, + .set_enable = buck_set_enable, +}; + +static const struct dm_regulator_ops rk808_ldo_ops = { + .get_value = ldo_get_value, + .set_value = ldo_set_value, + .get_enable = ldo_get_enable, + .set_enable = ldo_set_enable, +}; + +static const struct dm_regulator_ops rk808_switch_ops = { + .get_enable = switch_get_enable, + .set_enable = switch_set_enable, +}; + +U_BOOT_DRIVER(rk808_buck) = { + .name = "rk808_buck", + .id = UCLASS_REGULATOR, + .ops = &rk808_buck_ops, + .probe = rk808_buck_probe, +}; + +U_BOOT_DRIVER(rk808_ldo) = { + .name = "rk808_ldo", + .id = UCLASS_REGULATOR, + .ops = &rk808_ldo_ops, + .probe = rk808_ldo_probe, +}; + +U_BOOT_DRIVER(rk808_switch) = { + .name = "rk808_switch", + .id = UCLASS_REGULATOR, + .ops = &rk808_switch_ops, + .probe = rk808_switch_probe, +}; +#endif + +int rk808_spl_configure_buck(struct udevice *pmic, int buck, int uvolt) +{ + int ret; + + ret = _buck_set_value(pmic, buck, uvolt); + if (ret) + return ret; + + return _buck_set_enable(pmic, buck, true); +}

Some devices need special sequences to be used when starting up. Add a uclass for this. Drivers can be added to provide specific features as needed.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/misc/Kconfig | 18 ++++++++++++++++++ drivers/misc/Makefile | 1 + drivers/misc/pwrseq-uclass.c | 24 ++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/pwrseq.h | 18 ++++++++++++++++++ 5 files changed, 62 insertions(+) create mode 100644 drivers/misc/pwrseq-uclass.c create mode 100644 include/pwrseq.h
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index b92da4e..cba2363 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -90,6 +90,24 @@ config MXC_OCOTP Programmable memory pages that are stored on the some Freescale i.MX processors.
+config PWRSEQ + bool "Enable power-sequencing drivers" + depends on DM + help + Power-sequencing drivers provide support for controlling power for + devices. They are typically referenced by a phandle from another + device. When the device is started up, its power sequence can be + initiated. + +config SPL_PWRSEQ + bool "Enable power-sequencing drivers for SPL" + depends on PWRSEQ + help + Power-sequencing drivers provide support for controlling power for + devices. They are typically referenced by a phandle from another + device. When the device is started up, its power sequence can be + initiated. + config PCA9551_LED bool "Enable PCA9551 LED driver" help diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index aa137f5..fc8eb6f 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_MXC_OCOTP) += mxc_ocotp.o obj-$(CONFIG_MXS_OCOTP) += mxs_ocotp.o obj-$(CONFIG_NS87308) += ns87308.o obj-$(CONFIG_PDSP188x) += pdsp188x.o +obj-$(CONFIG_$(SPL_)PWRSEQ) += pwrseq-uclass.o obj-$(CONFIG_SANDBOX) += reset_sandbox.o ifdef CONFIG_DM_I2C obj-$(CONFIG_SANDBOX) += i2c_eeprom_emul.o diff --git a/drivers/misc/pwrseq-uclass.c b/drivers/misc/pwrseq-uclass.c new file mode 100644 index 0000000..8ed2ad4 --- /dev/null +++ b/drivers/misc/pwrseq-uclass.c @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2015 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <pwrseq.h> + +int pwrseq_set_power(struct udevice *dev, bool enable) +{ + struct pwrseq_ops *ops = pwrseq_get_ops(dev); + + if (!ops->set_power) + return -ENOSYS; + + return ops->set_power(dev, enable); +} + +UCLASS_DRIVER(pwrseq) = { + .id = UCLASS_PWRSEQ, + .name = "pwrseq", +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index a0a3a79..b5f43ae 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -51,6 +51,7 @@ enum uclass_id { UCLASS_PINCTRL, /* Pinctrl (pin muxing/configuration) device */ UCLASS_PINCONFIG, /* Pin configuration node device */ UCLASS_PMIC, /* PMIC I/O device */ + UCLASS_PWRSEQ, /* Power sequence device */ UCLASS_REGULATOR, /* Regulator device */ UCLASS_RESET, /* Reset device */ UCLASS_REMOTEPROC, /* Remote Processor device */ diff --git a/include/pwrseq.h b/include/pwrseq.h new file mode 100644 index 0000000..b934f29 --- /dev/null +++ b/include/pwrseq.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2013 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __pwrseq_h +#define __pwrseq_h + +struct pwrseq_ops { + int (*set_power)(struct udevice *dev, bool enable); +}; + +#define pwrseq_get_ops(dev) ((struct pwrseq_ops *)(dev)->driver->ops) + +int pwrseq_set_power(struct udevice *dev, bool enable); + +#endif

This saves some code space in SPL which is useful on jerry.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/arm/mach-rockchip/rk3288-board-spl.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/arch/arm/mach-rockchip/rk3288-board-spl.c b/arch/arm/mach-rockchip/rk3288-board-spl.c index 8199cad..b2c5729 100644 --- a/arch/arm/mach-rockchip/rk3288-board-spl.c +++ b/arch/arm/mach-rockchip/rk3288-board-spl.c @@ -113,6 +113,7 @@ static void configure_l2ctlr(void)
static int configure_emmc(struct udevice *pinctrl) { +#ifdef CONFIG_SPL_MMC_SUPPORT struct gpio_desc desc; int ret;
@@ -142,6 +143,7 @@ static int configure_emmc(struct udevice *pinctrl) debug("gpio value ret=%d\n", ret); return ret; } +#endif
return 0; }

This is easier to deal with when using generic code since it allows us to use a register index instead of naming each register.
Adjust it, adding an enum to improve readability.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/arm/include/asm/arch-rockchip/pmu_rk3288.h | 12 ++++++++---- drivers/pinctrl/rockchip/pinctrl_rk3288.c | 4 ++-- 2 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/arch/arm/include/asm/arch-rockchip/pmu_rk3288.h b/arch/arm/include/asm/arch-rockchip/pmu_rk3288.h index 12fa685..081675e 100644 --- a/arch/arm/include/asm/arch-rockchip/pmu_rk3288.h +++ b/arch/arm/include/asm/arch-rockchip/pmu_rk3288.h @@ -46,14 +46,18 @@ struct rk3288_pmu { u32 gpio_op;
u32 gpio0_sel18; /* 0x80 */ - u32 gpio0a_iomux; - u32 gpio0b_iomux; - u32 gpio0c_iomux; - u32 gpio0d_iomux; + u32 gpio0_iomux[4]; /* a, b, c, d */ u32 sys_reg[4]; }; check_member(rk3288_pmu, sys_reg[3], 0x00a0);
+enum { + PMU_GPIO0_A = 0, + PMU_GPIO0_B, + PMU_GPIO0_C, + PMU_GPIO0_D, +}; + /* PMU_GPIO0_B_IOMUX */ enum { GPIO0_B7_SHIFT = 14, diff --git a/drivers/pinctrl/rockchip/pinctrl_rk3288.c b/drivers/pinctrl/rockchip/pinctrl_rk3288.c index c432a00..ec3c4fe 100644 --- a/drivers/pinctrl/rockchip/pinctrl_rk3288.c +++ b/drivers/pinctrl/rockchip/pinctrl_rk3288.c @@ -56,10 +56,10 @@ static void pinctrl_rk3288_i2c_config(struct rk3288_grf *grf, { switch (i2c_id) { case PERIPH_ID_I2C0: - clrsetbits_le32(&pmu->gpio0b_iomux, + clrsetbits_le32(&pmu->gpio0_iomux[PMU_GPIO0_B], GPIO0_B7_MASK << GPIO0_B7_SHIFT, GPIO0_B7_I2C0PMU_SDA << GPIO0_B7_SHIFT); - clrsetbits_le32(&pmu->gpio0b_iomux, + clrsetbits_le32(&pmu->gpio0_iomux[PMU_GPIO0_C], GPIO0_C0_MASK << GPIO0_C0_SHIFT, GPIO0_C0_I2C0PMU_SCL << GPIO0_C0_SHIFT); break;

Use the pwrseq uclass to find a suitable power sequence for the MMC device. If this is enabled in the device tree, we will pick it up automatically.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/mmc/rockchip_dw_mmc.c | 47 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+)
diff --git a/drivers/mmc/rockchip_dw_mmc.c b/drivers/mmc/rockchip_dw_mmc.c index aeaec6c..67b1fce 100644 --- a/drivers/mmc/rockchip_dw_mmc.c +++ b/drivers/mmc/rockchip_dw_mmc.c @@ -9,7 +9,9 @@ #include <dm.h> #include <dwmmc.h> #include <errno.h> +#include <pwrseq.h> #include <syscon.h> +#include <asm/gpio.h> #include <asm/arch/clock.h> #include <asm/arch/periph.h> #include <linux/err.h> @@ -62,6 +64,7 @@ static int rockchip_dwmmc_probe(struct udevice *dev) struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); struct rockchip_dwmmc_priv *priv = dev_get_priv(dev); struct dwmci_host *host = &priv->host; + struct udevice *pwr_dev __maybe_unused; u32 minmax[2]; int ret; int fifo_depth; @@ -88,6 +91,16 @@ static int rockchip_dwmmc_probe(struct udevice *dev) if (fdtdec_get_bool(gd->fdt_blob, dev->of_offset, "fifo-mode")) host->fifo_mode = true;
+#ifdef CONFIG_PWRSEQ + /* Enable power if needed */ + ret = uclass_get_device_by_phandle(UCLASS_PWRSEQ, dev, "mmc-pwrseq", + &pwr_dev); + if (!ret) { + ret = pwrseq_set_power(pwr_dev, true); + if (ret) + return ret; + } +#endif ret = add_dwmci(host, minmax[1], minmax[0]); if (ret) return ret; @@ -110,3 +123,37 @@ U_BOOT_DRIVER(rockchip_dwmmc_drv) = { .probe = rockchip_dwmmc_probe, .priv_auto_alloc_size = sizeof(struct rockchip_dwmmc_priv), }; + +#ifdef CONFIG_PWRSEQ +static int rockchip_dwmmc_pwrseq_set_power(struct udevice *dev, bool enable) +{ + struct gpio_desc reset; + int ret; + + ret = gpio_request_by_name(dev, "reset-gpios", 0, &reset, GPIOD_IS_OUT); + if (ret) + return ret; + dm_gpio_set_value(&reset, 1); + udelay(1); + dm_gpio_set_value(&reset, 0); + udelay(200); + + return 0; +} + +static const struct pwrseq_ops rockchip_dwmmc_pwrseq_ops = { + .set_power = rockchip_dwmmc_pwrseq_set_power, +}; + +static const struct udevice_id rockchip_dwmmc_pwrseq_ids[] = { + { .compatible = "mmc-pwrseq-emmc" }, + { } +}; + +U_BOOT_DRIVER(rockchip_dwmmc_pwrseq_drv) = { + .name = "mmc_pwrseq_emmc", + .id = UCLASS_PWRSEQ, + .of_match = rockchip_dwmmc_pwrseq_ids, + .ops = &rockchip_dwmmc_pwrseq_ops, +}; +#endif

This has got out of sequence somehow. Fix it.
Signed-off-by: Simon Glass sjg@chromium.org ---
configs/chromebook_jerry_defconfig | 6 +++--- configs/firefly-rk3288_defconfig | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/configs/chromebook_jerry_defconfig b/configs/chromebook_jerry_defconfig index a515d8d..39cd9d6 100644 --- a/configs/chromebook_jerry_defconfig +++ b/configs/chromebook_jerry_defconfig @@ -4,9 +4,9 @@ CONFIG_SYS_MALLOC_F_LEN=0x2000 CONFIG_ROCKCHIP_RK3288=y CONFIG_TARGET_CHROMEBOOK_JERRY=y CONFIG_SPL_STACK_R_ADDR=0x80000 -CONFIG_SPL_STACK_R_MALLOC_SIMPLE_LEN=0x2000 CONFIG_DEFAULT_DEVICE_TREE="rk3288-jerry" CONFIG_SPL_STACK_R=y +CONFIG_SPL_STACK_R_MALLOC_SIMPLE_LEN=0x2000 # CONFIG_CMD_IMLS is not set # CONFIG_CMD_SETEXPR is not set CONFIG_CMD_PMIC=y @@ -15,11 +15,11 @@ CONFIG_SPL_OF_CONTROL=y CONFIG_REGMAP=y CONFIG_SPL_REGMAP=y CONFIG_SYSCON=y +CONFIG_SPL_SYSCON=y CONFIG_CLK=y CONFIG_SPL_CLK=y CONFIG_ROCKCHIP_GPIO=y CONFIG_SYS_I2C_ROCKCHIP=y -CONFIG_SPL_SYSCON=y CONFIG_LED=y CONFIG_SPL_LED=y CONFIG_LED_GPIO=y @@ -42,8 +42,8 @@ CONFIG_DEBUG_UART_BASE=0xff690000 CONFIG_DEBUG_UART_CLOCK=24000000 CONFIG_DEBUG_UART_SHIFT=2 CONFIG_SYS_NS16550=y +CONFIG_ROCKCHIP_SPI=y CONFIG_USE_PRIVATE_LIBGCC=y CONFIG_USE_TINY_PRINTF=y CONFIG_CMD_DHRYSTONE=y CONFIG_ERRNO_STR=y -CONFIG_ROCKCHIP_SPI=y diff --git a/configs/firefly-rk3288_defconfig b/configs/firefly-rk3288_defconfig index be4ca88..f41c241 100644 --- a/configs/firefly-rk3288_defconfig +++ b/configs/firefly-rk3288_defconfig @@ -4,9 +4,9 @@ CONFIG_SYS_MALLOC_F_LEN=0x2000 CONFIG_ROCKCHIP_RK3288=y CONFIG_TARGET_FIREFLY_RK3288=y CONFIG_SPL_STACK_R_ADDR=0x80000 -CONFIG_SPL_STACK_R_MALLOC_SIMPLE_LEN=0x2000 CONFIG_DEFAULT_DEVICE_TREE="rk3288-firefly" CONFIG_SPL_STACK_R=y +CONFIG_SPL_STACK_R_MALLOC_SIMPLE_LEN=0x2000 # CONFIG_CMD_IMLS is not set # CONFIG_CMD_SETEXPR is not set CONFIG_CMD_PMIC=y @@ -15,11 +15,11 @@ CONFIG_SPL_OF_CONTROL=y CONFIG_REGMAP=y CONFIG_SPL_REGMAP=y CONFIG_SYSCON=y +CONFIG_SPL_SYSCON=y CONFIG_CLK=y CONFIG_SPL_CLK=y CONFIG_ROCKCHIP_GPIO=y CONFIG_SYS_I2C_ROCKCHIP=y -CONFIG_SPL_SYSCON=y CONFIG_LED=y CONFIG_LED_GPIO=y CONFIG_RESET=y

This is defined in the device tree in Linux. Copy over the settings so that this can be used instead of hard-coding the reset line.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/arm/dts/rk3288-veyron.dtsi | 15 +++++++++++---- configs/chromebook_jerry_defconfig | 1 + include/configs/rk3288_common.h | 1 + 3 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/arch/arm/dts/rk3288-veyron.dtsi b/arch/arm/dts/rk3288-veyron.dtsi index 7e37158..12404ff 100644 --- a/arch/arm/dts/rk3288-veyron.dtsi +++ b/arch/arm/dts/rk3288-veyron.dtsi @@ -106,6 +106,13 @@ priority = /bits/ 8 <200>; };
+ emmc_pwrseq: emmc-pwrseq { + compatible = "mmc-pwrseq-emmc"; + pinctrl-0 = <&emmc_reset>; + pinctrl-names = "default"; + reset-gpios = <&gpio2 9 GPIO_ACTIVE_HIGH>; + }; + sound { compatible = "rockchip,rockchip-audio-max98090"; rockchip,model = "ROCKCHIP-I2S"; @@ -259,11 +266,12 @@ bus-width = <8>; cap-mmc-highspeed; mmc-hs200-1_8v; + mmc-pwrseq = <&emmc_pwrseq>; disable-wp; non-removable; num-slots = <1>; pinctrl-names = "default"; - pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_bus8 &emmc_deassert_reset>; + pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_bus8 &emmc_pwr>; status = "okay"; };
@@ -671,9 +679,8 @@ };
emmc { - /* Make sure eMMC is not in reset */ - emmc_deassert_reset: emmc-deassert-reset { - rockchip,pins = <7 12 RK_FUNC_GPIO &pcfg_pull_up>; + emmc_reset: emmc-reset { + rockchip,pins = <2 9 RK_FUNC_GPIO &pcfg_pull_none>; };
/* diff --git a/configs/chromebook_jerry_defconfig b/configs/chromebook_jerry_defconfig index 39cd9d6..456b6ea 100644 --- a/configs/chromebook_jerry_defconfig +++ b/configs/chromebook_jerry_defconfig @@ -23,6 +23,7 @@ CONFIG_SYS_I2C_ROCKCHIP=y CONFIG_LED=y CONFIG_SPL_LED=y CONFIG_LED_GPIO=y +CONFIG_PWRSEQ=y CONFIG_RESET=y CONFIG_DM_MMC=y CONFIG_ROCKCHIP_DWMMC=y diff --git a/include/configs/rk3288_common.h b/include/configs/rk3288_common.h index 238711a..f47573b 100644 --- a/include/configs/rk3288_common.h +++ b/include/configs/rk3288_common.h @@ -26,6 +26,7 @@ #define CONFIG_SYS_TIMER_COUNTER (CONFIG_SYS_TIMER_BASE + 8)
#define CONFIG_SPL_FRAMEWORK +#define CONFIG_SPL_DRIVERS_MISC_SUPPORT #define CONFIG_SPL_LIBCOMMON_SUPPORT #define CONFIG_SPL_LIBGENERIC_SUPPORT #define CONFIG_SPL_SERIAL_SUPPORT

This hangs when activated (by probing the PMIC). Disable it for now until we understand the root cause.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/arm/dts/rk3288-veyron.dtsi | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/arch/arm/dts/rk3288-veyron.dtsi b/arch/arm/dts/rk3288-veyron.dtsi index 12404ff..a31e00e 100644 --- a/arch/arm/dts/rk3288-veyron.dtsi +++ b/arch/arm/dts/rk3288-veyron.dtsi @@ -715,7 +715,10 @@
pmic { pmic_int_l: pmic-int-l { - rockchip,pins = <RK_GPIO0 4 RK_FUNC_GPIO &pcfg_pull_up>; + /* + * Causes jerry to hang when probing bus 0 + * rockchip,pins = <RK_GPIO0 4 RK_FUNC_GPIO &pcfg_pull_up>; + */ }; };

At present we use the same peripheral ID for clocks and pinctrl. While this works it is probably better to use the device tree clock binding ID for clocks. We can use the clk_get_by_index() function to find this.
Update the clock drivers and the code that uses them.
Signed-off-by: Simon Glass sjg@chromium.org ---
configs/chromebook_jerry_defconfig | 1 + configs/firefly-rk3288_defconfig | 1 + drivers/clk/clk_rk3036.c | 16 +++++----- drivers/clk/clk_rk3288.c | 63 +++++++++++++++++++++----------------- drivers/mmc/rockchip_dw_mmc.c | 10 ++---- 5 files changed, 48 insertions(+), 43 deletions(-)
diff --git a/configs/chromebook_jerry_defconfig b/configs/chromebook_jerry_defconfig index 456b6ea..5535105 100644 --- a/configs/chromebook_jerry_defconfig +++ b/configs/chromebook_jerry_defconfig @@ -12,6 +12,7 @@ CONFIG_SPL_STACK_R_MALLOC_SIMPLE_LEN=0x2000 CONFIG_CMD_PMIC=y CONFIG_CMD_REGULATOR=y CONFIG_SPL_OF_CONTROL=y +CONFIG_OF_SPL_REMOVE_PROPS="pinctrl-0 pinctrl-names clock-names interrupt-parent" CONFIG_REGMAP=y CONFIG_SPL_REGMAP=y CONFIG_SYSCON=y diff --git a/configs/firefly-rk3288_defconfig b/configs/firefly-rk3288_defconfig index f41c241..5b26a3d 100644 --- a/configs/firefly-rk3288_defconfig +++ b/configs/firefly-rk3288_defconfig @@ -12,6 +12,7 @@ CONFIG_SPL_STACK_R_MALLOC_SIMPLE_LEN=0x2000 CONFIG_CMD_PMIC=y CONFIG_CMD_REGULATOR=y CONFIG_SPL_OF_CONTROL=y +CONFIG_OF_SPL_REMOVE_PROPS="pinctrl-0 pinctrl-names clock-names interrupt-parent" CONFIG_REGMAP=y CONFIG_SPL_REGMAP=y CONFIG_SYSCON=y diff --git a/drivers/clk/clk_rk3036.c b/drivers/clk/clk_rk3036.c index 6c802b6..4077bd8 100644 --- a/drivers/clk/clk_rk3036.c +++ b/drivers/clk/clk_rk3036.c @@ -13,8 +13,8 @@ #include <asm/arch/clock.h> #include <asm/arch/cru_rk3036.h> #include <asm/arch/hardware.h> -#include <asm/arch/periph.h> #include <dm/lists.h> +#include <dt-bindings/clock/rk3036-cru.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -233,19 +233,19 @@ static uint32_t rkclk_pll_get_rate(struct rk3036_cru *cru, }
static ulong rockchip_mmc_get_clk(struct rk3036_cru *cru, uint clk_general_rate, - enum periph_id periph) + int periph) { uint src_rate; uint div, mux; u32 con;
switch (periph) { - case PERIPH_ID_EMMC: + case HCLK_EMMC: con = readl(&cru->cru_clksel_con[12]); mux = (con >> EMMC_PLL_SHIFT) & EMMC_PLL_MASK; div = (con >> EMMC_DIV_SHIFT) & EMMC_DIV_MASK; break; - case PERIPH_ID_SDCARD: + case HCLK_SDIO: con = readl(&cru->cru_clksel_con[12]); mux = (con >> MMC0_PLL_SHIFT) & MMC0_PLL_MASK; div = (con >> MMC0_DIV_SHIFT) & MMC0_DIV_MASK; @@ -259,7 +259,7 @@ static ulong rockchip_mmc_get_clk(struct rk3036_cru *cru, uint clk_general_rate, }
static ulong rockchip_mmc_set_clk(struct rk3036_cru *cru, uint clk_general_rate, - enum periph_id periph, uint freq) + int periph, uint freq) { int src_clk_div; int mux; @@ -277,14 +277,14 @@ static ulong rockchip_mmc_set_clk(struct rk3036_cru *cru, uint clk_general_rate, }
switch (periph) { - case PERIPH_ID_EMMC: + case HCLK_EMMC: rk_clrsetreg(&cru->cru_clksel_con[12], EMMC_PLL_MASK << EMMC_PLL_SHIFT | EMMC_DIV_MASK << EMMC_DIV_SHIFT, mux << EMMC_PLL_SHIFT | (src_clk_div - 1) << EMMC_DIV_SHIFT); break; - case PERIPH_ID_SDCARD: + case HCLK_SDIO: rk_clrsetreg(&cru->cru_clksel_con[11], MMC0_PLL_MASK << MMC0_PLL_SHIFT | MMC0_DIV_MASK << MMC0_DIV_SHIFT, @@ -320,7 +320,7 @@ ulong rk3036_set_periph_rate(struct udevice *dev, int periph, ulong rate) ulong new_rate;
switch (periph) { - case PERIPH_ID_EMMC: + case HCLK_EMMC: new_rate = rockchip_mmc_set_clk(priv->cru, clk_get_rate(dev), periph, rate); break; diff --git a/drivers/clk/clk_rk3288.c b/drivers/clk/clk_rk3288.c index 54d4930..7244d52 100644 --- a/drivers/clk/clk_rk3288.c +++ b/drivers/clk/clk_rk3288.c @@ -14,7 +14,7 @@ #include <asm/arch/cru_rk3288.h> #include <asm/arch/grf_rk3288.h> #include <asm/arch/hardware.h> -#include <asm/arch/periph.h> +#include <dt-bindings/clock/rk3288-cru.h> #include <dm/lists.h>
DECLARE_GLOBAL_DATA_PTR; @@ -364,24 +364,24 @@ static ulong rk3288_clk_set_rate(struct udevice *dev, ulong rate) }
static ulong rockchip_mmc_get_clk(struct rk3288_cru *cru, uint clk_general_rate, - enum periph_id periph) + int periph) { uint src_rate; uint div, mux; u32 con;
switch (periph) { - case PERIPH_ID_EMMC: + case HCLK_EMMC: con = readl(&cru->cru_clksel_con[12]); mux = (con >> EMMC_PLL_SHIFT) & EMMC_PLL_MASK; div = (con >> EMMC_DIV_SHIFT) & EMMC_DIV_MASK; break; - case PERIPH_ID_SDCARD: - con = readl(&cru->cru_clksel_con[12]); + case HCLK_SDMMC: + con = readl(&cru->cru_clksel_con[11]); mux = (con >> MMC0_PLL_SHIFT) & MMC0_PLL_MASK; div = (con >> MMC0_DIV_SHIFT) & MMC0_DIV_MASK; break; - case PERIPH_ID_SDMMC2: + case HCLK_SDIO0: con = readl(&cru->cru_clksel_con[12]); mux = (con >> SDIO0_PLL_SHIFT) & SDIO0_PLL_MASK; div = (con >> SDIO0_DIV_SHIFT) & SDIO0_DIV_MASK; @@ -395,7 +395,7 @@ static ulong rockchip_mmc_get_clk(struct rk3288_cru *cru, uint clk_general_rate, }
static ulong rockchip_mmc_set_clk(struct rk3288_cru *cru, uint clk_general_rate, - enum periph_id periph, uint freq) + int periph, uint freq) { int src_clk_div; int mux; @@ -414,21 +414,21 @@ static ulong rockchip_mmc_set_clk(struct rk3288_cru *cru, uint clk_general_rate, (int)MMC0_PLL_SELECT_GENERAL); } switch (periph) { - case PERIPH_ID_EMMC: + case HCLK_EMMC: rk_clrsetreg(&cru->cru_clksel_con[12], EMMC_PLL_MASK << EMMC_PLL_SHIFT | EMMC_DIV_MASK << EMMC_DIV_SHIFT, mux << EMMC_PLL_SHIFT | (src_clk_div - 1) << EMMC_DIV_SHIFT); break; - case PERIPH_ID_SDCARD: + case HCLK_SDMMC: rk_clrsetreg(&cru->cru_clksel_con[11], MMC0_PLL_MASK << MMC0_PLL_SHIFT | MMC0_DIV_MASK << MMC0_DIV_SHIFT, mux << MMC0_PLL_SHIFT | (src_clk_div - 1) << MMC0_DIV_SHIFT); break; - case PERIPH_ID_SDMMC2: + case HCLK_SDIO0: rk_clrsetreg(&cru->cru_clksel_con[12], SDIO0_PLL_MASK << SDIO0_PLL_SHIFT | SDIO0_DIV_MASK << SDIO0_DIV_SHIFT, @@ -443,23 +443,23 @@ static ulong rockchip_mmc_set_clk(struct rk3288_cru *cru, uint clk_general_rate, }
static ulong rockchip_spi_get_clk(struct rk3288_cru *cru, uint clk_general_rate, - enum periph_id periph) + int periph) { uint div, mux; u32 con;
switch (periph) { - case PERIPH_ID_SPI0: + case SCLK_SPI0: con = readl(&cru->cru_clksel_con[25]); mux = (con >> SPI0_PLL_SHIFT) & SPI0_PLL_MASK; div = (con >> SPI0_DIV_SHIFT) & SPI0_DIV_MASK; break; - case PERIPH_ID_SPI1: + case SCLK_SPI1: con = readl(&cru->cru_clksel_con[25]); mux = (con >> SPI1_PLL_SHIFT) & SPI1_PLL_MASK; div = (con >> SPI1_DIV_SHIFT) & SPI1_DIV_MASK; break; - case PERIPH_ID_SPI2: + case SCLK_SPI2: con = readl(&cru->cru_clksel_con[39]); mux = (con >> SPI2_PLL_SHIFT) & SPI2_PLL_MASK; div = (con >> SPI2_DIV_SHIFT) & SPI2_DIV_MASK; @@ -473,28 +473,28 @@ static ulong rockchip_spi_get_clk(struct rk3288_cru *cru, uint clk_general_rate, }
static ulong rockchip_spi_set_clk(struct rk3288_cru *cru, uint clk_general_rate, - enum periph_id periph, uint freq) + int periph, uint freq) { int src_clk_div;
debug("%s: clk_general_rate=%u\n", __func__, clk_general_rate); src_clk_div = RATE_TO_DIV(clk_general_rate, freq); switch (periph) { - case PERIPH_ID_SPI0: + case SCLK_SPI0: rk_clrsetreg(&cru->cru_clksel_con[25], SPI0_PLL_MASK << SPI0_PLL_SHIFT | SPI0_DIV_MASK << SPI0_DIV_SHIFT, SPI0_PLL_SELECT_GENERAL << SPI0_PLL_SHIFT | src_clk_div << SPI0_DIV_SHIFT); break; - case PERIPH_ID_SPI1: + case SCLK_SPI1: rk_clrsetreg(&cru->cru_clksel_con[25], SPI1_PLL_MASK << SPI1_PLL_SHIFT | SPI1_DIV_MASK << SPI1_DIV_SHIFT, SPI1_PLL_SELECT_GENERAL << SPI1_PLL_SHIFT | src_clk_div << SPI1_DIV_SHIFT); break; - case PERIPH_ID_SPI2: + case SCLK_SPI2: rk_clrsetreg(&cru->cru_clksel_con[39], SPI2_PLL_MASK << SPI2_PLL_SHIFT | SPI2_DIV_MASK << SPI2_DIV_SHIFT, @@ -511,19 +511,26 @@ static ulong rockchip_spi_set_clk(struct rk3288_cru *cru, uint clk_general_rate, ulong rk3288_set_periph_rate(struct udevice *dev, int periph, ulong rate) { struct rk3288_clk_priv *priv = dev_get_priv(dev); - ulong new_rate; + struct udevice *gclk; + ulong new_rate, gclk_rate; + int ret;
+ ret = uclass_get_device(UCLASS_CLK, CLK_GENERAL, &gclk); + if (ret) + return ret; + gclk_rate = clk_get_rate(gclk); switch (periph) { - case PERIPH_ID_EMMC: - case PERIPH_ID_SDCARD: - new_rate = rockchip_mmc_set_clk(priv->cru, clk_get_rate(dev), - periph, rate); + case HCLK_EMMC: + case HCLK_SDMMC: + case HCLK_SDIO0: + new_rate = rockchip_mmc_set_clk(priv->cru, gclk_rate, periph, + rate); break; - case PERIPH_ID_SPI0: - case PERIPH_ID_SPI1: - case PERIPH_ID_SPI2: - new_rate = rockchip_spi_set_clk(priv->cru, clk_get_rate(dev), - periph, rate); + case SCLK_SPI0: + case SCLK_SPI1: + case SCLK_SPI2: + new_rate = rockchip_spi_set_clk(priv->cru, gclk_rate, periph, + rate); break; default: return -ENOENT; diff --git a/drivers/mmc/rockchip_dw_mmc.c b/drivers/mmc/rockchip_dw_mmc.c index 67b1fce..f1c468f 100644 --- a/drivers/mmc/rockchip_dw_mmc.c +++ b/drivers/mmc/rockchip_dw_mmc.c @@ -20,7 +20,7 @@ DECLARE_GLOBAL_DATA_PTR;
struct rockchip_dwmmc_priv { struct udevice *clk; - struct rk3288_grf *grf; + int periph; struct dwmci_host host; };
@@ -30,8 +30,7 @@ static uint rockchip_dwmmc_get_mmc_clk(struct dwmci_host *host, uint freq) struct rockchip_dwmmc_priv *priv = dev_get_priv(dev); int ret;
- ret = clk_set_periph_rate(priv->clk, PERIPH_ID_SDMMC0 + host->dev_index, - freq); + ret = clk_set_periph_rate(priv->clk, priv->periph, freq); if (ret < 0) { debug("%s: err=%d\n", __func__, ret); return ret; @@ -69,10 +68,7 @@ static int rockchip_dwmmc_probe(struct udevice *dev) int ret; int fifo_depth;
- priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); - if (IS_ERR(priv->grf)) - return PTR_ERR(priv->grf); - ret = uclass_get_device(UCLASS_CLK, CLK_GENERAL, &priv->clk); + ret = clk_get_by_index(dev, 0, &priv->clk, &priv->periph); if (ret) return ret;

The current name is confusing and a bit verbose. Rename it.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/clk/clk_rk3288.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/drivers/clk/clk_rk3288.c b/drivers/clk/clk_rk3288.c index 7244d52..0bb674d 100644 --- a/drivers/clk/clk_rk3288.c +++ b/drivers/clk/clk_rk3288.c @@ -363,7 +363,7 @@ static ulong rk3288_clk_set_rate(struct udevice *dev, ulong rate) return 0; }
-static ulong rockchip_mmc_get_clk(struct rk3288_cru *cru, uint clk_general_rate, +static ulong rockchip_mmc_get_clk(struct rk3288_cru *cru, uint gclk_rate, int periph) { uint src_rate; @@ -390,18 +390,18 @@ static ulong rockchip_mmc_get_clk(struct rk3288_cru *cru, uint clk_general_rate, return -EINVAL; }
- src_rate = mux == EMMC_PLL_SELECT_24MHZ ? OSC_HZ : clk_general_rate; + src_rate = mux == EMMC_PLL_SELECT_24MHZ ? OSC_HZ : gclk_rate; return DIV_TO_RATE(src_rate, div); }
-static ulong rockchip_mmc_set_clk(struct rk3288_cru *cru, uint clk_general_rate, +static ulong rockchip_mmc_set_clk(struct rk3288_cru *cru, uint gclk_rate, int periph, uint freq) { int src_clk_div; int mux;
- debug("%s: clk_general_rate=%u\n", __func__, clk_general_rate); - src_clk_div = RATE_TO_DIV(clk_general_rate, freq); + debug("%s: gclk_rate=%u\n", __func__, gclk_rate); + src_clk_div = RATE_TO_DIV(gclk_rate, freq);
if (src_clk_div > 0x3f) { src_clk_div = RATE_TO_DIV(OSC_HZ, freq); @@ -439,10 +439,10 @@ static ulong rockchip_mmc_set_clk(struct rk3288_cru *cru, uint clk_general_rate, return -EINVAL; }
- return rockchip_mmc_get_clk(cru, clk_general_rate, periph); + return rockchip_mmc_get_clk(cru, gclk_rate, periph); }
-static ulong rockchip_spi_get_clk(struct rk3288_cru *cru, uint clk_general_rate, +static ulong rockchip_spi_get_clk(struct rk3288_cru *cru, uint gclk_rate, int periph) { uint div, mux; @@ -469,16 +469,16 @@ static ulong rockchip_spi_get_clk(struct rk3288_cru *cru, uint clk_general_rate, } assert(mux == SPI0_PLL_SELECT_GENERAL);
- return DIV_TO_RATE(clk_general_rate, div); + return DIV_TO_RATE(gclk_rate, div); }
-static ulong rockchip_spi_set_clk(struct rk3288_cru *cru, uint clk_general_rate, +static ulong rockchip_spi_set_clk(struct rk3288_cru *cru, uint gclk_rate, int periph, uint freq) { int src_clk_div;
- debug("%s: clk_general_rate=%u\n", __func__, clk_general_rate); - src_clk_div = RATE_TO_DIV(clk_general_rate, freq); + debug("%s: clk_general_rate=%u\n", __func__, gclk_rate); + src_clk_div = RATE_TO_DIV(gclk_rate, freq); switch (periph) { case SCLK_SPI0: rk_clrsetreg(&cru->cru_clksel_con[25], @@ -505,7 +505,7 @@ static ulong rockchip_spi_set_clk(struct rk3288_cru *cru, uint clk_general_rate, return -EINVAL; }
- return rockchip_spi_get_clk(cru, clk_general_rate, periph); + return rockchip_spi_get_clk(cru, gclk_rate, periph); }
ulong rk3288_set_periph_rate(struct udevice *dev, int periph, ulong rate)

It is useful to be able to read the rate of a peripheral clock. Add a handler for that.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/clk/clk_rk3288.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+)
diff --git a/drivers/clk/clk_rk3288.c b/drivers/clk/clk_rk3288.c index 0bb674d..5eceb98 100644 --- a/drivers/clk/clk_rk3288.c +++ b/drivers/clk/clk_rk3288.c @@ -508,6 +508,42 @@ static ulong rockchip_spi_set_clk(struct rk3288_cru *cru, uint gclk_rate, return rockchip_spi_get_clk(cru, gclk_rate, periph); }
+ulong rk3288_get_periph_rate(struct udevice *dev, int periph) +{ + struct rk3288_clk_priv *priv = dev_get_priv(dev); + struct udevice *gclk; + ulong new_rate, gclk_rate; + int ret; + + ret = uclass_get_device(UCLASS_CLK, CLK_GENERAL, &gclk); + if (ret) + return ret; + gclk_rate = clk_get_rate(gclk); + switch (periph) { + case HCLK_EMMC: + case HCLK_SDIO0: + case HCLK_SDIO1: + new_rate = rockchip_mmc_get_clk(priv->cru, gclk_rate, periph); + break; + case SCLK_SPI0: + case SCLK_SPI1: + case SCLK_SPI2: + new_rate = rockchip_spi_get_clk(priv->cru, gclk_rate, periph); + break; + case PCLK_I2C0: + case PCLK_I2C1: + case PCLK_I2C2: + case PCLK_I2C3: + case PCLK_I2C4: + case PCLK_I2C5: + return gclk_rate; + default: + return -ENOENT; + } + + return new_rate; +} + ulong rk3288_set_periph_rate(struct udevice *dev, int periph, ulong rate) { struct rk3288_clk_priv *priv = dev_get_priv(dev); @@ -543,6 +579,7 @@ static struct clk_ops rk3288_clk_ops = { .get_rate = rk3288_clk_get_rate, .set_rate = rk3288_clk_set_rate, .set_periph_rate = rk3288_set_periph_rate, + .get_periph_rate = rk3288_get_periph_rate, };
static int rk3288_clk_probe(struct udevice *dev)

The current approach of using uclass_get_device() is error-prone. Another clock (for example a fixed-clock) may cause it to break. Add a function that does a proper search.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/arm/include/asm/arch-rockchip/clock.h | 12 ++++++++++++ drivers/clk/clk_rk3288.c | 24 ++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 2 deletions(-)
diff --git a/arch/arm/include/asm/arch-rockchip/clock.h b/arch/arm/include/asm/arch-rockchip/clock.h index 8a0376c..a9ea268 100644 --- a/arch/arm/include/asm/arch-rockchip/clock.h +++ b/arch/arm/include/asm/arch-rockchip/clock.h @@ -62,4 +62,16 @@ static inline u32 clk_get_divisor(ulong input_rate, uint output_rate) */ void *rockchip_get_cru(void);
+/** + * rkclk_get_clk() - get a pointer to a given clock + * + * This is an internal function - use outside the clock subsystem indicates + * that work is needed! + * + * @clk_id: Clock requested + * @devp: Returns a pointer to that clock + * @return 0 if OK, -ve on error + */ +int rkclk_get_clk(enum rk_clk_id clk_id, struct udevice **devp); + #endif diff --git a/drivers/clk/clk_rk3288.c b/drivers/clk/clk_rk3288.c index 5eceb98..d507b48 100644 --- a/drivers/clk/clk_rk3288.c +++ b/drivers/clk/clk_rk3288.c @@ -15,7 +15,9 @@ #include <asm/arch/grf_rk3288.h> #include <asm/arch/hardware.h> #include <dt-bindings/clock/rk3288-cru.h> +#include <dm/device-internal.h> #include <dm/lists.h> +#include <dm/uclass-internal.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -139,6 +141,24 @@ static const struct pll_div apll_init_cfg = PLL_DIVISORS(APLL_HZ, 1, 1); static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 2, 2); static const struct pll_div cpll_init_cfg = PLL_DIVISORS(CPLL_HZ, 1, 2);
+int rkclk_get_clk(enum rk_clk_id clk_id, struct udevice **devp) +{ + struct udevice *dev; + + for (uclass_find_first_device(UCLASS_CLK, &dev); + dev; + uclass_find_next_device(&dev)) { + struct rk3288_clk_plat *plat = dev_get_platdata(dev); + + if (plat->clk_id == clk_id) { + *devp = dev; + return device_probe(dev); + } + } + + return -ENODEV; +} + static int rkclk_set_pll(struct rk3288_cru *cru, enum rk_clk_id clk_id, const struct pll_div *div) { @@ -515,7 +535,7 @@ ulong rk3288_get_periph_rate(struct udevice *dev, int periph) ulong new_rate, gclk_rate; int ret;
- ret = uclass_get_device(UCLASS_CLK, CLK_GENERAL, &gclk); + ret = rkclk_get_clk(CLK_GENERAL, &gclk); if (ret) return ret; gclk_rate = clk_get_rate(gclk); @@ -551,7 +571,7 @@ ulong rk3288_set_periph_rate(struct udevice *dev, int periph, ulong rate) ulong new_rate, gclk_rate; int ret;
- ret = uclass_get_device(UCLASS_CLK, CLK_GENERAL, &gclk); + ret = rkclk_get_clk(CLK_GENERAL, &gclk); if (ret) return ret; gclk_rate = clk_get_rate(gclk);

We can use the new clk_get_by_index() function to get the correct clock.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/i2c/rk_i2c.c | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-)
diff --git a/drivers/i2c/rk_i2c.c b/drivers/i2c/rk_i2c.c index ebdba35..4030330 100644 --- a/drivers/i2c/rk_i2c.c +++ b/drivers/i2c/rk_i2c.c @@ -30,10 +30,9 @@ DECLARE_GLOBAL_DATA_PTR;
struct rk_i2c { struct udevice *clk; - struct udevice *pinctrl; struct i2c_regs *regs; unsigned int speed; - enum periph_id id; + int clk_id; };
static inline void rk_i2c_get_div(int div, int *divh, int *divl) @@ -56,7 +55,7 @@ static void rk_i2c_set_clk(struct rk_i2c *i2c, uint32_t scl_rate) int div, divl, divh;
/* First get i2c rate from pclk */ - i2c_rate = clk_get_periph_rate(i2c->clk, i2c->id); + i2c_rate = clk_get_periph_rate(i2c->clk, i2c->clk_id);
div = DIV_ROUND_UP(i2c_rate, scl_rate * 8) - 2; divh = 0; @@ -352,23 +351,28 @@ int rockchip_i2c_set_bus_speed(struct udevice *bus, unsigned int speed) return 0; }
-static int rockchip_i2c_probe(struct udevice *bus) +static int rockchip_i2c_ofdata_to_platdata(struct udevice *bus) { - struct rk_i2c *i2c = dev_get_priv(bus); + struct rk_i2c *priv = dev_get_priv(bus); int ret;
- ret = uclass_get_device(UCLASS_PINCTRL, 0, &i2c->pinctrl); - if (ret) - return ret; - ret = uclass_get_device(UCLASS_CLK, 0, &i2c->clk); - if (ret) - return ret; - ret = pinctrl_get_periph_id(i2c->pinctrl, bus); - if (ret < 0) + ret = clk_get_by_index(bus, 0, &priv->clk, &priv->clk_id); + if (ret < 0) { + debug("%s: Could not get clock for %s: %d\n", __func__, + bus->name, ret); return ret; - i2c->id = ret; - i2c->regs = (void *)dev_get_addr(bus); - return pinctrl_request(i2c->pinctrl, i2c->id, 0); + } + + return 0; +} + +static int rockchip_i2c_probe(struct udevice *bus) +{ + struct rk_i2c *priv = dev_get_priv(bus); + + priv->regs = (void *)dev_get_addr(bus); + + return 0; }
static const struct dm_i2c_ops rockchip_i2c_ops = { @@ -385,6 +389,7 @@ U_BOOT_DRIVER(i2c_rockchip) = { .name = "i2c_rockchip", .id = UCLASS_I2C, .of_match = rockchip_i2c_ids, + .ofdata_to_platdata = rockchip_i2c_ofdata_to_platdata, .probe = rockchip_i2c_probe, .priv_auto_alloc_size = sizeof(struct rk_i2c), .ops = &rockchip_i2c_ops,

Hello Simon,
Am 14.01.2016 um 00:25 schrieb Simon Glass:
We can use the new clk_get_by_index() function to get the correct clock.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/i2c/rk_i2c.c | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-)
Thanks!
Acked-by: Heiko Schocher hs@denx.de
bye, Heiko
diff --git a/drivers/i2c/rk_i2c.c b/drivers/i2c/rk_i2c.c index ebdba35..4030330 100644 --- a/drivers/i2c/rk_i2c.c +++ b/drivers/i2c/rk_i2c.c @@ -30,10 +30,9 @@ DECLARE_GLOBAL_DATA_PTR;
struct rk_i2c { struct udevice *clk;
- struct udevice *pinctrl; struct i2c_regs *regs; unsigned int speed;
- enum periph_id id;
int clk_id; };
static inline void rk_i2c_get_div(int div, int *divh, int *divl)
@@ -56,7 +55,7 @@ static void rk_i2c_set_clk(struct rk_i2c *i2c, uint32_t scl_rate) int div, divl, divh;
/* First get i2c rate from pclk */
- i2c_rate = clk_get_periph_rate(i2c->clk, i2c->id);
i2c_rate = clk_get_periph_rate(i2c->clk, i2c->clk_id);
div = DIV_ROUND_UP(i2c_rate, scl_rate * 8) - 2; divh = 0;
@@ -352,23 +351,28 @@ int rockchip_i2c_set_bus_speed(struct udevice *bus, unsigned int speed) return 0; }
-static int rockchip_i2c_probe(struct udevice *bus) +static int rockchip_i2c_ofdata_to_platdata(struct udevice *bus) {
- struct rk_i2c *i2c = dev_get_priv(bus);
- struct rk_i2c *priv = dev_get_priv(bus); int ret;
- ret = uclass_get_device(UCLASS_PINCTRL, 0, &i2c->pinctrl);
- if (ret)
return ret;
- ret = uclass_get_device(UCLASS_CLK, 0, &i2c->clk);
- if (ret)
return ret;
- ret = pinctrl_get_periph_id(i2c->pinctrl, bus);
- if (ret < 0)
- ret = clk_get_by_index(bus, 0, &priv->clk, &priv->clk_id);
- if (ret < 0) {
debug("%s: Could not get clock for %s: %d\n", __func__,
return ret;bus->name, ret);
- i2c->id = ret;
- i2c->regs = (void *)dev_get_addr(bus);
- return pinctrl_request(i2c->pinctrl, i2c->id, 0);
- }
- return 0;
+}
+static int rockchip_i2c_probe(struct udevice *bus) +{
struct rk_i2c *priv = dev_get_priv(bus);
priv->regs = (void *)dev_get_addr(bus);
return 0; }
static const struct dm_i2c_ops rockchip_i2c_ops = {
@@ -385,6 +389,7 @@ U_BOOT_DRIVER(i2c_rockchip) = { .name = "i2c_rockchip", .id = UCLASS_I2C, .of_match = rockchip_i2c_ids,
- .ofdata_to_platdata = rockchip_i2c_ofdata_to_platdata, .probe = rockchip_i2c_probe, .priv_auto_alloc_size = sizeof(struct rk_i2c), .ops = &rockchip_i2c_ops,

We can use the new clk_get_by_index() function to get the correct clock.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/spi/rk_spi.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-)
diff --git a/drivers/spi/rk_spi.c b/drivers/spi/rk_spi.c index 5e0c6ad..aaf6040 100644 --- a/drivers/spi/rk_spi.c +++ b/drivers/spi/rk_spi.c @@ -27,7 +27,7 @@ DECLARE_GLOBAL_DATA_PTR; #define DEBUG_RK_SPI 0
struct rockchip_spi_platdata { - enum periph_id periph_id; + int periph_id; struct udevice *pinctrl; s32 frequency; /* Default clock frequency, -1 for none */ fdt_addr_t base; @@ -36,10 +36,10 @@ struct rockchip_spi_platdata {
struct rockchip_spi_priv { struct rockchip_spi *regs; - struct udevice *clk_gpll; + struct udevice *clk; + int clk_id; unsigned int max_freq; unsigned int mode; - enum periph_id periph_id; /* Peripheral ID for this device */ ulong last_transaction_us; /* Time of last transaction end */ u8 bits_per_word; /* max 16 bits per word */ u8 n_bytes; @@ -114,6 +114,7 @@ static void spi_cs_deactivate(struct rockchip_spi *regs, uint cs) static int rockchip_spi_ofdata_to_platdata(struct udevice *bus) { struct rockchip_spi_platdata *plat = bus->platdata; + struct rockchip_spi_priv *priv = dev_get_priv(bus); const void *blob = gd->fdt_blob; int node = bus->of_offset; int ret; @@ -127,16 +128,22 @@ static int rockchip_spi_ofdata_to_platdata(struct udevice *bus) if (ret < 0) { debug("%s: Could not get peripheral ID for %s: %d\n", __func__, bus->name, ret); - return -FDT_ERR_NOTFOUND; + return ret; } plat->periph_id = ret; + ret = clk_get_by_index(bus, 0, &priv->clk, &priv->clk_id); + if (ret < 0) { + debug("%s: Could not get clock for %s: %d\n", __func__, + bus->name, ret); + return ret; + }
plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency", - 50000000); + 50000000); plat->deactivate_delay_us = fdtdec_get_int(blob, node, "spi-deactivate-delay", 0); debug("%s: base=%x, periph_id=%d, max-frequency=%d, deactivate_delay=%d\n", - __func__, plat->base, plat->periph_id, plat->frequency, + __func__, (uint)plat->base, plat->periph_id, plat->frequency, plat->deactivate_delay_us);
return 0; @@ -153,18 +160,12 @@ static int rockchip_spi_probe(struct udevice *bus)
priv->last_transaction_us = timer_get_us(); priv->max_freq = plat->frequency; - priv->periph_id = plat->periph_id; - ret = uclass_get_device(UCLASS_CLK, CLK_GENERAL, &priv->clk_gpll); - if (ret) { - debug("%s: Failed to find CLK_GENERAL: %d\n", __func__, ret); - return ret; - }
/* * Use 99 MHz as our clock since it divides nicely into 594 MHz which * is the assumed speed for CLK_GENERAL. */ - ret = clk_set_periph_rate(priv->clk_gpll, plat->periph_id, 99000000); + ret = clk_set_periph_rate(priv->clk, priv->clk_id, 99000000); if (ret < 0) { debug("%s: Failed to set clock: %d\n", __func__, ret); return ret; @@ -248,7 +249,7 @@ static int rockchip_spi_claim_bus(struct udevice *dev)
writel(ctrlr0, ®s->ctrlr0);
- ret = pinctrl_request(plat->pinctrl, priv->periph_id, slave_plat->cs); + ret = pinctrl_request(plat->pinctrl, plat->periph_id, slave_plat->cs); if (ret) { debug("%s: Cannot request pinctrl: %d\n", __func__, ret); return ret;

If full pinctrl is enabled we don't need to manually set the pinctrl in the driver. It will happen automatically. Adjust the code to suit - we will still use manual mode in SPL.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/spi/rk_spi.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/drivers/spi/rk_spi.c b/drivers/spi/rk_spi.c index aaf6040..f98284c 100644 --- a/drivers/spi/rk_spi.c +++ b/drivers/spi/rk_spi.c @@ -181,13 +181,15 @@ static int rockchip_spi_probe(struct udevice *bus) static int rockchip_spi_claim_bus(struct udevice *dev) { struct udevice *bus = dev->parent; - struct rockchip_spi_platdata *plat = dev_get_platdata(bus); struct rockchip_spi_priv *priv = dev_get_priv(bus); struct rockchip_spi *regs = priv->regs; - struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev); u8 spi_dfs, spi_tf; uint ctrlr0; +#if !CONFIG_IS_ENABLED(PINCTRL_FULL) + struct rockchip_spi_platdata *plat = dev_get_platdata(bus); + struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev); int ret; +#endif
/* Disable the SPI hardware */ rkspi_enable_chip(regs, 0); @@ -248,12 +250,13 @@ static int rockchip_spi_claim_bus(struct udevice *dev) ctrlr0 |= (priv->tmode & TMOD_MASK) << TMOD_SHIFT;
writel(ctrlr0, ®s->ctrlr0); - +#if !CONFIG_IS_ENABLED(PINCTRL_FULL) ret = pinctrl_request(plat->pinctrl, plat->periph_id, slave_plat->cs); if (ret) { debug("%s: Cannot request pinctrl: %d\n", __func__, ret); return ret; } +#endif
return 0; }

We can use the new clk_get_by_index() function to get the correct clock.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/clk/clk_rk3288.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/clk/clk_rk3288.c b/drivers/clk/clk_rk3288.c index d507b48..d6d2896 100644 --- a/drivers/clk/clk_rk3288.c +++ b/drivers/clk/clk_rk3288.c @@ -541,8 +541,8 @@ ulong rk3288_get_periph_rate(struct udevice *dev, int periph) gclk_rate = clk_get_rate(gclk); switch (periph) { case HCLK_EMMC: + case HCLK_SDMMC: case HCLK_SDIO0: - case HCLK_SDIO1: new_rate = rockchip_mmc_get_clk(priv->cru, gclk_rate, periph); break; case SCLK_SPI0:

We can make use of the device tree to configure pinctrl settings. Add this support for the driver so we can use it in U-Boot proper.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/pinctrl/rockchip/pinctrl_rk3288.c | 230 +++++++++++++++++++++++++++++- 1 file changed, 229 insertions(+), 1 deletion(-)
diff --git a/drivers/pinctrl/rockchip/pinctrl_rk3288.c b/drivers/pinctrl/rockchip/pinctrl_rk3288.c index ec3c4fe..0e7721e 100644 --- a/drivers/pinctrl/rockchip/pinctrl_rk3288.c +++ b/drivers/pinctrl/rockchip/pinctrl_rk3288.c @@ -24,8 +24,103 @@ DECLARE_GLOBAL_DATA_PTR; struct rk3288_pinctrl_priv { struct rk3288_grf *grf; struct rk3288_pmu *pmu; + int num_banks; };
+/** + * Encode variants of iomux registers into a type variable + */ +#define IOMUX_GPIO_ONLY BIT(0) +#define IOMUX_WIDTH_4BIT BIT(1) +#define IOMUX_SOURCE_PMU BIT(2) +#define IOMUX_UNROUTED BIT(3) + +/** + * @type: iomux variant using IOMUX_* constants + * @offset: if initialized to -1 it will be autocalculated, by specifying + * an initial offset value the relevant source offset can be reset + * to a new value for autocalculating the following iomux registers. + */ +struct rockchip_iomux { + u8 type; + s16 offset; +}; + +/** + * @reg: register offset of the gpio bank + * @nr_pins: number of pins in this bank + * @bank_num: number of the bank, to account for holes + * @name: name of the bank + * @iomux: array describing the 4 iomux sources of the bank + */ +struct rockchip_pin_bank { + u16 reg; + u8 nr_pins; + u8 bank_num; + char *name; + struct rockchip_iomux iomux[4]; +}; + +#define PIN_BANK(id, pins, label) \ + { \ + .bank_num = id, \ + .nr_pins = pins, \ + .name = label, \ + .iomux = { \ + { .offset = -1 }, \ + { .offset = -1 }, \ + { .offset = -1 }, \ + { .offset = -1 }, \ + }, \ + } + +#define PIN_BANK_IOMUX_FLAGS(id, pins, label, iom0, iom1, iom2, iom3) \ + { \ + .bank_num = id, \ + .nr_pins = pins, \ + .name = label, \ + .iomux = { \ + { .type = iom0, .offset = -1 }, \ + { .type = iom1, .offset = -1 }, \ + { .type = iom2, .offset = -1 }, \ + { .type = iom3, .offset = -1 }, \ + }, \ + } + +#ifndef CONFIG_SPL_BUILD +static struct rockchip_pin_bank rk3288_pin_banks[] = { + PIN_BANK_IOMUX_FLAGS(0, 24, "gpio0", IOMUX_SOURCE_PMU, + IOMUX_SOURCE_PMU, + IOMUX_SOURCE_PMU, + IOMUX_UNROUTED + ), + PIN_BANK_IOMUX_FLAGS(1, 32, "gpio1", IOMUX_UNROUTED, + IOMUX_UNROUTED, + IOMUX_UNROUTED, + 0 + ), + PIN_BANK_IOMUX_FLAGS(2, 32, "gpio2", 0, 0, 0, IOMUX_UNROUTED), + PIN_BANK_IOMUX_FLAGS(3, 32, "gpio3", 0, 0, 0, IOMUX_WIDTH_4BIT), + PIN_BANK_IOMUX_FLAGS(4, 32, "gpio4", IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + 0, + 0 + ), + PIN_BANK_IOMUX_FLAGS(5, 32, "gpio5", IOMUX_UNROUTED, + 0, + 0, + IOMUX_UNROUTED + ), + PIN_BANK_IOMUX_FLAGS(6, 32, "gpio6", 0, 0, 0, IOMUX_UNROUTED), + PIN_BANK_IOMUX_FLAGS(7, 32, "gpio7", 0, + 0, + IOMUX_WIDTH_4BIT, + IOMUX_UNROUTED + ), + PIN_BANK(8, 16, "gpio8"), +}; +#endif + static void pinctrl_rk3288_pwm_config(struct rk3288_grf *grf, int pwm_id) { switch (pwm_id) { @@ -410,7 +505,106 @@ static int rk3288_pinctrl_set_state_simple(struct udevice *dev, return rk3288_pinctrl_request(dev, func, 0); }
+#ifndef CONFIG_SPL_BUILD +static int rk3288_pinctrl_set_pins(struct udevice *dev, int banknum, int index, + int muxval, int flags) +{ + struct rk3288_pinctrl_priv *priv = dev_get_priv(dev); + struct rockchip_pin_bank *bank = &rk3288_pin_banks[banknum]; + uint shift, muxnum, ind = index; + u32 *addr; + + debug("%s: %x %x %x %x\n", __func__, banknum, index, muxval, flags); + for (muxnum = 0; muxnum < 4; muxnum++) { + struct rockchip_iomux *mux = &bank->iomux[muxnum]; + uint mask; + + if (ind >= 8) { + ind -= 8; + continue; + } + + if (mux->type & IOMUX_SOURCE_PMU) + addr = priv->pmu->gpio0_iomux; + else + addr = (u32 *)priv->grf - 4; + addr += mux->offset; + shift = ind & 7; + if (mux->type & IOMUX_WIDTH_4BIT) { + mask = 0xf; + shift *= 4; + if (shift >= 16) { + shift -= 16; + addr++; + } + } else { + mask = 3; + shift *= 2; + } + + debug("%s: addr=%p, mask=%x, shift=%x\n", __func__, addr, + mask, shift); + rk_clrsetreg(addr, mask << shift, muxval << shift); + break; + } + if (flags) { + uint val = 0; + + if (flags & (1 << PIN_CONFIG_BIAS_PULL_UP)) + val = 1; + else if (flags & (1 << PIN_CONFIG_BIAS_PULL_DOWN)) + val = 2; + shift = (index & 7) * 2; + ind = index >> 3; + if (banknum == 0) + addr = &priv->pmu->gpio0pull[ind]; + else + addr = &priv->grf->gpio1_p[banknum - 1][ind]; + debug("%s: addr=%p, val=%x, shift=%x\n", __func__, addr, val, + shift); + rk_clrsetreg(addr, 3 << shift, val << shift); + } + + return 0; +} + +static int rk3288_pinctrl_set_state(struct udevice *dev, struct udevice *config) +{ + const void *blob = gd->fdt_blob; + int pcfg_node, ret, flags, count, i; + u32 cell[40], *ptr; + + debug("%s: %s %s\n", __func__, dev->name, config->name); + ret = fdtdec_get_int_array_count(blob, config->of_offset, + "rockchip,pins", cell, + ARRAY_SIZE(cell)); + if (ret < 0) { + debug("%s: bad array %d\n", __func__, ret); + return -EINVAL; + } + count = ret; + for (i = 0, ptr = cell; i < count; i += 4, ptr += 4) { + pcfg_node = fdt_node_offset_by_phandle(blob, ptr[3]); + if (pcfg_node < 0) + return -EINVAL; + flags = pinctrl_decode_pin_config(blob, pcfg_node); + if (flags < 0) + return flags; + + ret = rk3288_pinctrl_set_pins(dev, ptr[0], ptr[1], ptr[2], + flags); + if (ret) + return ret; + } + + return 0; +} +#endif + static struct pinctrl_ops rk3288_pinctrl_ops = { +#ifndef CONFIG_SPL_BUILD + .set_state = rk3288_pinctrl_set_state, +#endif .set_state_simple = rk3288_pinctrl_set_state_simple, .request = rk3288_pinctrl_request, .get_periph_id = rk3288_pinctrl_get_periph_id, @@ -422,15 +616,49 @@ static int rk3288_pinctrl_bind(struct udevice *dev) return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false); }
+#ifndef CONFIG_SPL_BUILD +static int rk3288_pinctrl_parse_tables(struct rk3288_pinctrl_priv *priv, + struct rockchip_pin_bank *banks, + int count) +{ + struct rockchip_pin_bank *bank; + uint reg, muxnum, banknum; + + reg = 0; + for (banknum = 0; banknum < count; banknum++) { + bank = &banks[banknum]; + bank->reg = reg; + debug("%s: bank %d, reg %x\n", __func__, banknum, reg * 4); + for (muxnum = 0; muxnum < 4; muxnum++) { + struct rockchip_iomux *mux = &bank->iomux[muxnum]; + + if (!(mux->type & IOMUX_UNROUTED)) + mux->offset = reg; + if (mux->type & IOMUX_WIDTH_4BIT) + reg += 2; + else + reg += 1; + } + } + + return 0; +} +#endif + static int rk3288_pinctrl_probe(struct udevice *dev) { struct rk3288_pinctrl_priv *priv = dev_get_priv(dev); + int ret = 0;
priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); priv->pmu = syscon_get_first_range(ROCKCHIP_SYSCON_PMU); debug("%s: grf=%p, pmu=%p\n", __func__, priv->grf, priv->pmu); +#ifndef CONFIG_SPL_BUILD + ret = rk3288_pinctrl_parse_tables(priv, rk3288_pin_banks, + ARRAY_SIZE(rk3288_pin_banks)); +#endif
- return 0; + return ret; }
static const struct udevice_id rk3288_pinctrl_ids[] = {

Use the full pinctrl driver in U-Boot proper.
Signed-off-by: Simon Glass sjg@chromium.org ---
configs/chromebook_jerry_defconfig | 1 - configs/firefly-rk3288_defconfig | 1 - 2 files changed, 2 deletions(-)
diff --git a/configs/chromebook_jerry_defconfig b/configs/chromebook_jerry_defconfig index 5535105..1e5edc9 100644 --- a/configs/chromebook_jerry_defconfig +++ b/configs/chromebook_jerry_defconfig @@ -29,7 +29,6 @@ CONFIG_RESET=y CONFIG_DM_MMC=y CONFIG_ROCKCHIP_DWMMC=y CONFIG_PINCTRL=y -# CONFIG_PINCTRL_FULL is not set CONFIG_SPL_PINCTRL=y # CONFIG_SPL_PINCTRL_FULL is not set CONFIG_ROCKCHIP_PINCTRL=y diff --git a/configs/firefly-rk3288_defconfig b/configs/firefly-rk3288_defconfig index 5b26a3d..7d8ca6c 100644 --- a/configs/firefly-rk3288_defconfig +++ b/configs/firefly-rk3288_defconfig @@ -27,7 +27,6 @@ CONFIG_RESET=y CONFIG_DM_MMC=y CONFIG_ROCKCHIP_DWMMC=y CONFIG_PINCTRL=y -# CONFIG_PINCTRL_FULL is not set CONFIG_SPL_PINCTRL=y # CONFIG_SPL_PINCTRL_FULL is not set CONFIG_ROCKCHIP_PINCTRL=y

Enable this PMIC and regulator, which is used on jerry.
Signed-off-by: Simon Glass sjg@chromium.org ---
configs/chromebook_jerry_defconfig | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/configs/chromebook_jerry_defconfig b/configs/chromebook_jerry_defconfig index 1e5edc9..a0af6ec 100644 --- a/configs/chromebook_jerry_defconfig +++ b/configs/chromebook_jerry_defconfig @@ -34,8 +34,10 @@ CONFIG_SPL_PINCTRL=y CONFIG_ROCKCHIP_PINCTRL=y CONFIG_DM_PMIC=y CONFIG_PMIC_ACT8846=y +CONFIG_PMIC_RK808=y CONFIG_DM_REGULATOR=y CONFIG_REGULATOR_ACT8846=y +CONFIG_REGULATOR_RK808=y CONFIG_RAM=y CONFIG_SPL_RAM=y CONFIG_DEBUG_UART=y

This is not needed for booting, so drop it from SPL to save about 300 bytes.
Signed-off-by: Simon Glass sjg@chromium.org ---
configs/chromebook_jerry_defconfig | 1 + configs/firefly-rk3288_defconfig | 1 + 2 files changed, 2 insertions(+)
diff --git a/configs/chromebook_jerry_defconfig b/configs/chromebook_jerry_defconfig index a0af6ec..99f6161 100644 --- a/configs/chromebook_jerry_defconfig +++ b/configs/chromebook_jerry_defconfig @@ -17,6 +17,7 @@ CONFIG_REGMAP=y CONFIG_SPL_REGMAP=y CONFIG_SYSCON=y CONFIG_SPL_SYSCON=y +# CONFIG_SPL_SIMPLE_BUS is not set CONFIG_CLK=y CONFIG_SPL_CLK=y CONFIG_ROCKCHIP_GPIO=y diff --git a/configs/firefly-rk3288_defconfig b/configs/firefly-rk3288_defconfig index 7d8ca6c..d8db532 100644 --- a/configs/firefly-rk3288_defconfig +++ b/configs/firefly-rk3288_defconfig @@ -17,6 +17,7 @@ CONFIG_REGMAP=y CONFIG_SPL_REGMAP=y CONFIG_SYSCON=y CONFIG_SPL_SYSCON=y +# CONFIG_SPL_SIMPLE_BUS is not set CONFIG_CLK=y CONFIG_SPL_CLK=y CONFIG_ROCKCHIP_GPIO=y

To reduce the SPL image size, drop the LED features. Jerry does not have an LED and we can leave out GPIO support also.
Signed-off-by: Simon Glass sjg@chromium.org ---
configs/chromebook_jerry_defconfig | 5 ----- include/configs/chromebook_jerry.h | 2 ++ 2 files changed, 2 insertions(+), 5 deletions(-)
diff --git a/configs/chromebook_jerry_defconfig b/configs/chromebook_jerry_defconfig index 99f6161..ceec6f5 100644 --- a/configs/chromebook_jerry_defconfig +++ b/configs/chromebook_jerry_defconfig @@ -22,9 +22,6 @@ CONFIG_CLK=y CONFIG_SPL_CLK=y CONFIG_ROCKCHIP_GPIO=y CONFIG_SYS_I2C_ROCKCHIP=y -CONFIG_LED=y -CONFIG_SPL_LED=y -CONFIG_LED_GPIO=y CONFIG_PWRSEQ=y CONFIG_RESET=y CONFIG_DM_MMC=y @@ -34,10 +31,8 @@ CONFIG_SPL_PINCTRL=y # CONFIG_SPL_PINCTRL_FULL is not set CONFIG_ROCKCHIP_PINCTRL=y CONFIG_DM_PMIC=y -CONFIG_PMIC_ACT8846=y CONFIG_PMIC_RK808=y CONFIG_DM_REGULATOR=y -CONFIG_REGULATOR_ACT8846=y CONFIG_REGULATOR_RK808=y CONFIG_RAM=y CONFIG_SPL_RAM=y diff --git a/include/configs/chromebook_jerry.h b/include/configs/chromebook_jerry.h index e29d776..78c06af 100644 --- a/include/configs/chromebook_jerry.h +++ b/include/configs/chromebook_jerry.h @@ -15,4 +15,6 @@ #define CONFIG_SPL_SPI_LOAD #define CONFIG_SPI_FLASH_GIGADEVICE
+#undef CONFIG_SPL_GPIO_SUPPORT + #endif

The 'gpio' command allows abbreviations for most subcommands. Allow them for 'status' also.
Signed-off-by: Simon Glass sjg@chromium.org ---
common/cmd_gpio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/common/cmd_gpio.c b/common/cmd_gpio.c index 65d6df4..bb0f63a 100644 --- a/common/cmd_gpio.c +++ b/common/cmd_gpio.c @@ -141,7 +141,7 @@ static int do_gpio(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) #endif if (argc > 0) str_gpio = *argv; - if (!strcmp(str_cmd, "status")) { + if (!strncmp(str_cmd, "status", 1)) { /* Support deprecated gpio_status() */ #ifdef gpio_status gpio_status();

This is not used in SPL so don't allow it to be built there, even if I2C is enabled in SPL.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/misc/Makefile | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index fc8eb6f..cd4846b 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -10,11 +10,13 @@ obj-$(CONFIG_ALI152X) += ali512x.o obj-$(CONFIG_ALTERA_SYSID) += altera_sysid.o obj-$(CONFIG_DS4510) += ds4510.o obj-$(CONFIG_CBMEM_CONSOLE) += cbmem_console.o +ifndef CONFIG_SPL_BUILD obj-$(CONFIG_CROS_EC) += cros_ec.o obj-$(CONFIG_CROS_EC_LPC) += cros_ec_lpc.o obj-$(CONFIG_CROS_EC_I2C) += cros_ec_i2c.o obj-$(CONFIG_CROS_EC_SANDBOX) += cros_ec_sandbox.o obj-$(CONFIG_CROS_EC_SPI) += cros_ec_spi.o +endif obj-$(CONFIG_FSL_DEBUG_SERVER) += fsl_debug_server.o obj-$(CONFIG_FSL_IIM) += fsl_iim.o obj-$(CONFIG_GPIO_LED) += gpio_led.o

Since I2C muxes are seldom needed in SPL, and the code for this increases the size somewhat, add a separate option to enable I2C muxes for SPL.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/i2c/Makefile | 4 ++-- drivers/i2c/muxes/Kconfig | 9 +++++++++ drivers/i2c/muxes/Makefile | 2 +- 3 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 811ad9b..bbbc0dc 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -7,8 +7,8 @@ obj-$(CONFIG_DM_I2C) += i2c-uclass.o obj-$(CONFIG_DM_I2C_COMPAT) += i2c-uclass-compat.o obj-$(CONFIG_DM_I2C_GPIO) += i2c-gpio.o -obj-$(CONFIG_I2C_CROS_EC_TUNNEL) += cros_ec_tunnel.o -obj-$(CONFIG_I2C_CROS_EC_LDO) += cros_ec_ldo.o +obj-$(CONFIG_$(SPL_)I2C_CROS_EC_TUNNEL) += cros_ec_tunnel.o +obj-$(CONFIG_$(SPL_)I2C_CROS_EC_LDO) += cros_ec_ldo.o
obj-$(CONFIG_SYS_I2C_ADI) += adi_i2c.o obj-$(CONFIG_I2C_MV) += mv_i2c.o diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig index 913093d..f959d9d 100644 --- a/drivers/i2c/muxes/Kconfig +++ b/drivers/i2c/muxes/Kconfig @@ -7,6 +7,15 @@ config I2C_MUX bus select is handled automatically when that bus is accessed, using a suitable I2C MUX driver.
+config SPL_I2C_MUX + bool "Support I2C multiplexers on SPL" + depends on I2C_MUX + help + This enables I2C buses to be multiplexed, so that you can select + one of several buses using some sort of control mechanism. The + bus select is handled automatically when that bus is accessed, + using a suitable I2C MUX driver. + config I2C_ARB_GPIO_CHALLENGE bool "GPIO-based I2C arbitration" depends on I2C_MUX diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile index 612cc27..47c1240 100644 --- a/drivers/i2c/muxes/Makefile +++ b/drivers/i2c/muxes/Makefile @@ -4,4 +4,4 @@ # SPDX-License-Identifier: GPL-2.0+ # obj-$(CONFIG_I2C_ARB_GPIO_CHALLENGE) += i2c-arb-gpio-challenge.o -obj-$(CONFIG_I2C_MUX) += i2c-mux-uclass.o +obj-$(CONFIG_$(SPL_)I2C_MUX) += i2c-mux-uclass.o

Hello Simon,
Am 14.01.2016 um 00:25 schrieb Simon Glass:
Since I2C muxes are seldom needed in SPL, and the code for this increases the size somewhat, add a separate option to enable I2C muxes for SPL.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/i2c/Makefile | 4 ++-- drivers/i2c/muxes/Kconfig | 9 +++++++++ drivers/i2c/muxes/Makefile | 2 +- 3 files changed, 12 insertions(+), 3 deletions(-)
Thanks!
Acked-by: Heiko Schocher hs@denx.de
bye, Heiko
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 811ad9b..bbbc0dc 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -7,8 +7,8 @@ obj-$(CONFIG_DM_I2C) += i2c-uclass.o obj-$(CONFIG_DM_I2C_COMPAT) += i2c-uclass-compat.o obj-$(CONFIG_DM_I2C_GPIO) += i2c-gpio.o -obj-$(CONFIG_I2C_CROS_EC_TUNNEL) += cros_ec_tunnel.o -obj-$(CONFIG_I2C_CROS_EC_LDO) += cros_ec_ldo.o +obj-$(CONFIG_$(SPL_)I2C_CROS_EC_TUNNEL) += cros_ec_tunnel.o +obj-$(CONFIG_$(SPL_)I2C_CROS_EC_LDO) += cros_ec_ldo.o
obj-$(CONFIG_SYS_I2C_ADI) += adi_i2c.o obj-$(CONFIG_I2C_MV) += mv_i2c.o diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig index 913093d..f959d9d 100644 --- a/drivers/i2c/muxes/Kconfig +++ b/drivers/i2c/muxes/Kconfig @@ -7,6 +7,15 @@ config I2C_MUX bus select is handled automatically when that bus is accessed, using a suitable I2C MUX driver.
+config SPL_I2C_MUX
- bool "Support I2C multiplexers on SPL"
- depends on I2C_MUX
- help
This enables I2C buses to be multiplexed, so that you can select
one of several buses using some sort of control mechanism. The
bus select is handled automatically when that bus is accessed,
using a suitable I2C MUX driver.
- config I2C_ARB_GPIO_CHALLENGE bool "GPIO-based I2C arbitration" depends on I2C_MUX
diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile index 612cc27..47c1240 100644 --- a/drivers/i2c/muxes/Makefile +++ b/drivers/i2c/muxes/Makefile @@ -4,4 +4,4 @@ # SPDX-License-Identifier: GPL-2.0+ # obj-$(CONFIG_I2C_ARB_GPIO_CHALLENGE) += i2c-arb-gpio-challenge.o -obj-$(CONFIG_I2C_MUX) += i2c-mux-uclass.o +obj-$(CONFIG_$(SPL_)I2C_MUX) += i2c-mux-uclass.o

This function currently searches the entire device tree for a node that it thinks is relevant. But the node is known and is passed in. Correct the code and enable it only with driver model, since only driver-model boards will use it.
This avoids bringing in a large number of strings from fdtdec.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/mtd/spi/spi_flash.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c index 7ffa136..8d0c47e 100644 --- a/drivers/mtd/spi/spi_flash.c +++ b/drivers/mtd/spi/spi_flash.c @@ -872,14 +872,10 @@ static int spi_flash_set_qeb(struct spi_flash *flash, u8 idcode0) #if CONFIG_IS_ENABLED(OF_CONTROL) int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash) { +#ifdef CONFIG_DM_SPI_FLASH fdt_addr_t addr; fdt_size_t size; - int node; - - /* If there is no node, do nothing */ - node = fdtdec_next_compatible(blob, 0, COMPAT_GENERIC_SPI_FLASH); - if (node < 0) - return 0; + int node = flash->dev->of_offset;
addr = fdtdec_get_addr_size(blob, node, "memory-map", &size); if (addr == FDT_ADDR_T_NONE) { @@ -892,6 +888,7 @@ int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash) return -1; } flash->memory_map = map_sysmem(addr, size); +#endif
return 0; }

For some boards the pmic interface is useful but the regulator interface (which comes with it) is too large. Allow them to be separated such that SPL can decide which it needs.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/power/pmic/Kconfig | 21 +++++++++++++++++++++ drivers/power/pmic/pmic-uclass.c | 2 ++ drivers/power/regulator/Kconfig | 9 +++++++++ drivers/power/regulator/Makefile | 4 ++-- 4 files changed, 34 insertions(+), 2 deletions(-)
diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig index 8be3c07..7f69ae1 100644 --- a/drivers/power/pmic/Kconfig +++ b/drivers/power/pmic/Kconfig @@ -10,6 +10,27 @@ config DM_PMIC - 'drivers/power/pmic/pmic-uclass.c' - 'include/power/pmic.h'
+config PMIC_CHILDREN + bool "Allow child devices for PMICs" + depends on DM_PMIC + default y + ---help--- + This allows PMICs to support child devices (such as regulators) in + SPL. This adds quite a bit of code so if you are not using this + feature you can turn it off. Most likely you should turn it on for + U-Boot proper. + +config SPL_PMIC_CHILDREN + bool "Allow child devices for PMICs in SPL" + depends on DM_PMIC + default y + ---help--- + This allows PMICs to support child devices (such as regulators) in + SPL. This adds quite a bit of code so if you are not using this + feature you can turn it off. In this case you may need a 'back door' + to call your regulator code (e.g. see rk808.c for direct functions + for use in SPL). + config PMIC_ACT8846 bool "Enable support for the active-semi 8846 PMIC" depends on DM_PMIC && DM_I2C diff --git a/drivers/power/pmic/pmic-uclass.c b/drivers/power/pmic/pmic-uclass.c index 49709f3..8b19998 100644 --- a/drivers/power/pmic/pmic-uclass.c +++ b/drivers/power/pmic/pmic-uclass.c @@ -18,6 +18,7 @@
DECLARE_GLOBAL_DATA_PTR;
+#if CONFIG_IS_ENABLED(PMIC_CHILDREN) int pmic_bind_children(struct udevice *pmic, int offset, const struct pmic_child_info *child_info) { @@ -84,6 +85,7 @@ int pmic_bind_children(struct udevice *pmic, int offset, debug("Bound: %d childs for PMIC: '%s'\n", bind_count, pmic->name); return bind_count; } +#endif
int pmic_get(const char *name, struct udevice **devp) { diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig index 8f638a9..465ff3f 100644 --- a/drivers/power/regulator/Kconfig +++ b/drivers/power/regulator/Kconfig @@ -16,6 +16,15 @@ config DM_REGULATOR for this purpose if PMIC I/O driver is implemented or dm_scan_fdt_node() otherwise. Detailed information can be found in the header file.
+config SPL_DM_REGULATOR + bool "Enable regulators for SPL" + depends on DM_REGULATOR + ---help--- + Regulators are seldom needed in SPL. Even if they are accessed, some + code space can be saved by accessing the PMIC registers directly. + Enable this option if you need regulators in SPL and can cope with + the extra code size. + config REGULATOR_ACT8846 bool "Enable driver for ACT8846 regulator" depends on DM_REGULATOR && PMIC_ACT8846 diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile index 0d18c2b..1590d85 100644 --- a/drivers/power/regulator/Makefile +++ b/drivers/power/regulator/Makefile @@ -5,11 +5,11 @@ # SPDX-License-Identifier: GPL-2.0+ #
-obj-$(CONFIG_DM_REGULATOR) += regulator-uclass.o +obj-$(CONFIG_$(SPL_)DM_REGULATOR) += regulator-uclass.o obj-$(CONFIG_REGULATOR_ACT8846) += act8846.o obj-$(CONFIG_DM_REGULATOR_MAX77686) += max77686.o obj-$(CONFIG_DM_REGULATOR_PFUZE100) += pfuze100.o -obj-$(CONFIG_DM_REGULATOR_FIXED) += fixed.o +obj-$(CONFIG_$(SPL_)DM_REGULATOR_FIXED) += fixed.o obj-$(CONFIG_REGULATOR_RK808) += rk808.o obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o obj-$(CONFIG_DM_REGULATOR_SANDBOX) += sandbox.o

GPIO drivers want to be able to show if a pin is enabled for input, output, or is being used by another function. Some drivers can easily find this and the code is included in the driver. For some SoCs this is more complex. Conceptually this should be handled by pinctrl rather than GPIO. Most pinctrl drivers will have this feature anyway.
Add a method by which a GPIO driver can obtain the pin mux value given a GPIO reference. This avoids repeating the code in two places.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/pinctrl/pinctrl-uclass.c | 10 ++++++++++ include/dm/pinctrl.h | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+)
diff --git a/drivers/pinctrl/pinctrl-uclass.c b/drivers/pinctrl/pinctrl-uclass.c index 1acbfaf..ccc5d30 100644 --- a/drivers/pinctrl/pinctrl-uclass.c +++ b/drivers/pinctrl/pinctrl-uclass.c @@ -246,6 +246,16 @@ int pinctrl_get_periph_id(struct udevice *dev, struct udevice *periph) return ops->get_periph_id(dev, periph); }
+int pinctrl_get_gpio_mux(struct udevice *dev, int banknum, int index) +{ + struct pinctrl_ops *ops = pinctrl_get_ops(dev); + + if (!ops->get_gpio_mux) + return -ENOSYS; + + return ops->get_gpio_mux(dev, banknum, index); +} + /** * pinconfig_post-bind() - post binding for PINCTRL uclass * Recursively bind child nodes as pinconfig devices in case of full pinctrl. diff --git a/include/dm/pinctrl.h b/include/dm/pinctrl.h index 5cd4503..0eb4b92 100644 --- a/include/dm/pinctrl.h +++ b/include/dm/pinctrl.h @@ -114,6 +114,22 @@ struct pinctrl_ops { * @return peripheral ID of @periph, or -ENOENT on error */ int (*get_periph_id)(struct udevice *dev, struct udevice *periph); + + /** + * get_gpio_mux() - get the mux value for a particular GPIO + * + * This allows the raw mux value for a GPIO to be obtained. It is + * useful for displaying the function being used by that GPIO, such + * as with the 'gpio' command. This function is internal to the GPIO + * subsystem and should not be used by generic code. Typically it is + * used by a GPIO driver with knowledge of the SoC pinctrl setup. + * + * @dev: Pinctrl device to use + * @banknum: GPIO bank number + * @index: GPIO index within the bank + * @return mux value (SoC-specific, e.g. 0 for input, 1 for output) + */ + int (*get_gpio_mux)(struct udevice *dev, int banknum, int index); };
#define pinctrl_get_ops(dev) ((struct pinctrl_ops *)(dev)->driver->ops) @@ -297,4 +313,20 @@ int pinctrl_get_periph_id(struct udevice *dev, struct udevice *periph); */ int pinctrl_decode_pin_config(const void *blob, int node);
+/** + * pinctrl_get_gpio_mux() - get the mux value for a particular GPIO + * + * This allows the raw mux value for a GPIO to be obtained. It is + * useful for displaying the function being used by that GPIO, such + * as with the 'gpio' command. This function is internal to the GPIO + * subsystem and should not be used by generic code. Typically it is + * used by a GPIO driver with knowledge of the SoC pinctrl setup. + * + * @dev: Pinctrl device to use + * @banknum: GPIO bank number + * @index: GPIO index within the bank + * @return mux value (SoC-specific, e.g. 0 for input, 1 for output) +*/ +int pinctrl_get_gpio_mux(struct udevice *dev, int banknum, int index); + #endif /* __PINCTRL_H */

It is sometimes useful to be able to find a device before probing it, perhaps to set up some platform data for it. Allow finding by of_offset also.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/core/uclass.c | 4 ++-- include/dm/uclass-internal.h | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index 7f38dae..020b6bc 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -254,8 +254,8 @@ int uclass_find_device_by_seq(enum uclass_id id, int seq_or_req_seq, return -ENODEV; }
-static int uclass_find_device_by_of_offset(enum uclass_id id, int node, - struct udevice **devp) +int uclass_find_device_by_of_offset(enum uclass_id id, int node, + struct udevice **devp) { struct uclass *uc; struct udevice *dev; diff --git a/include/dm/uclass-internal.h b/include/dm/uclass-internal.h index b51e1da..ad284b8 100644 --- a/include/dm/uclass-internal.h +++ b/include/dm/uclass-internal.h @@ -99,6 +99,22 @@ int uclass_find_device_by_seq(enum uclass_id id, int seq_or_req_seq, bool find_req_seq, struct udevice **devp);
/** + * uclass_find_device_by_of_offset() - Find a uclass device by device tree node + * + * This searches the devices in the uclass for one attached to the given + * device tree node. + * + * The device is NOT probed, it is merely returned. + * + * @id: ID to look up + * @node: Device tree offset to search for (if -ve then -ENODEV is returned) + * @devp: Returns pointer to device (there is only one for each node) + * @return 0 if OK, -ve on error + */ +int uclass_find_device_by_of_offset(enum uclass_id id, int node, + struct udevice **devp); + +/** * uclass_bind_device() - Associate device with a uclass * * Connect the device into uclass's list of devices.

The currect PMIC debugging is a little confusing. Adjust it so that it is clear whether the operation succeeded or failed. Also, avoid creating a new error return value when a perfectly good one is already available.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/power/pmic/pmic-uclass.c | 11 ++++++++--- drivers/power/pmic/rk808.c | 14 ++++++++++---- drivers/power/regulator/regulator-uclass.c | 2 +- 3 files changed, 19 insertions(+), 8 deletions(-)
diff --git a/drivers/power/pmic/pmic-uclass.c b/drivers/power/pmic/pmic-uclass.c index 8b19998..7211026 100644 --- a/drivers/power/pmic/pmic-uclass.c +++ b/drivers/power/pmic/pmic-uclass.c @@ -133,8 +133,9 @@ int pmic_reg_read(struct udevice *dev, uint reg) u8 byte; int ret;
+ debug("%s: reg=%x", __func__, reg); ret = pmic_read(dev, reg, &byte, 1); - debug("%s: reg=%x, value=%x\n", __func__, reg, byte); + debug(", value=%x, ret=%d\n", byte, ret);
return ret ? ret : byte; } @@ -142,9 +143,13 @@ int pmic_reg_read(struct udevice *dev, uint reg) int pmic_reg_write(struct udevice *dev, uint reg, uint value) { u8 byte = value; + int ret; + + debug("%s: reg=%x, value=%x", __func__, reg, value); + ret = pmic_write(dev, reg, &byte, 1); + debug(", ret=%d\n", ret);
- debug("%s: reg=%x, value=%x\n", __func__, reg, value); - return pmic_write(dev, reg, &byte, 1); + return ret; }
int pmic_clrsetbits(struct udevice *dev, uint reg, uint clr, uint set) diff --git a/drivers/power/pmic/rk808.c b/drivers/power/pmic/rk808.c index 11d5f07..770f471 100644 --- a/drivers/power/pmic/rk808.c +++ b/drivers/power/pmic/rk808.c @@ -30,9 +30,12 @@ static int rk808_reg_count(struct udevice *dev) static int rk808_write(struct udevice *dev, uint reg, const uint8_t *buff, int len) { - if (dm_i2c_write(dev, reg, buff, len)) { + int ret; + + ret = dm_i2c_write(dev, reg, buff, len); + if (ret) { debug("write error to device: %p register: %#x!", dev, reg); - return -EIO; + return ret; }
return 0; @@ -40,9 +43,12 @@ static int rk808_write(struct udevice *dev, uint reg, const uint8_t *buff,
static int rk808_read(struct udevice *dev, uint reg, uint8_t *buff, int len) { - if (dm_i2c_read(dev, reg, buff, len)) { + int ret; + + ret = dm_i2c_read(dev, reg, buff, len); + if (ret) { debug("read error from device: %p register: %#x!", dev, reg); - return -EIO; + return ret; }
return 0; diff --git a/drivers/power/regulator/regulator-uclass.c b/drivers/power/regulator/regulator-uclass.c index 4241a4c..fec2886 100644 --- a/drivers/power/regulator/regulator-uclass.c +++ b/drivers/power/regulator/regulator-uclass.c @@ -178,7 +178,7 @@ static void regulator_show(struct udevice *dev, int ret) printf("; set %d uA", uc_pdata->min_uA); printf("; enabling"); if (ret) - printf(" (ret: %d)\n", ret); + printf(" (ret: %d)", ret); printf("\n"); }

Some regulators will not implement any operations (e.g. fixed regulators). This is not an error, so allow the autoset process to continue when one of these regulators is found.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/power/regulator/regulator-uclass.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/drivers/power/regulator/regulator-uclass.c b/drivers/power/regulator/regulator-uclass.c index fec2886..9fe07f2 100644 --- a/drivers/power/regulator/regulator-uclass.c +++ b/drivers/power/regulator/regulator-uclass.c @@ -334,6 +334,8 @@ int regulators_enable_boot_on(bool verbose) } if (verbose) regulator_show(dev, ret); + if (ret == -ENOSYS) + ret = 0; }
return ret;

This function adds quite a bit of code to SPL and we probably don't need all the features in SPL. Add a simple version (for SPL only) to save space.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/clk/clk-uclass.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c index a205b26..8ed41ed 100644 --- a/drivers/clk/clk-uclass.c +++ b/drivers/clk/clk-uclass.c @@ -67,9 +67,26 @@ int clk_get_id(struct udevice *dev, int args_count, uint32_t *args) int clk_get_by_index(struct udevice *dev, int index, struct udevice **clk_devp, int *periphp) { - struct fdtdec_phandle_args args; int ret;
+#ifdef CONFIG_SPL_BUILD + u32 cell[2]; + + if (index != 0) + return -ENOSYS; + ret = uclass_get_device(UCLASS_CLK, 0, clk_devp); + if (ret) + return ret; + ret = fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, "clocks", + cell, 2); + if (ret) + return ret; + *periphp = cell[1]; + + return 0; +#else + struct fdtdec_phandle_args args; + ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev->of_offset, "clocks", "#clock-cells", 0, index, &args); @@ -86,6 +103,7 @@ int clk_get_by_index(struct udevice *dev, int index, struct udevice **clk_devp, return ret; } *periphp = args.args_count > 0 ? args.args[0] : -1; +#endif
return 0; }

Use this function in preference to the macro.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/arm/mach-rockchip/rk3288/sdram_rk3288.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c b/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c index 09017cc..5da04b9 100644 --- a/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c +++ b/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c @@ -400,7 +400,7 @@ static void set_bandwidth_ratio(const struct chan_info *chan, u32 channel,
if (n == 1) { setbits_le32(&pctl->ppcfg, 1); - writel(RK_SETBITS(1 << (8 + channel)), &grf->soc_con0); + rk_setreg(&grf->soc_con0, 1 << (8 + channel)); setbits_le32(&msch->ddrtiming, 1 << 31); /* Data Byte disable*/ clrbits_le32(&publ->datx8[2].dxgcr, 1); @@ -410,7 +410,7 @@ static void set_bandwidth_ratio(const struct chan_info *chan, u32 channel, setbits_le32(&publ->datx8[3].dxdllcr, DXDLLCR_DLLDIS); } else { clrbits_le32(&pctl->ppcfg, 1); - writel(RK_CLRBITS(1 << (8 + channel)), &grf->soc_con0); + rk_clrreg(&grf->soc_con0, 1 << (8 + channel)); clrbits_le32(&msch->ddrtiming, 1 << 31); /* Data Byte enable*/ setbits_le32(&publ->datx8[2].dxgcr, 1); @@ -571,8 +571,7 @@ static void dram_all_config(const struct dram_info *dram, dram_cfg_rbc(&dram->chan[chan], chan, sdram_params); } writel(sys_reg, &dram->pmu->sys_reg[2]); - writel(RK_CLRSETBITS(0x1F, sdram_params->base.stride), - &dram->sgrf->soc_con2); + rk_clrsetreg(&dram->sgrf->soc_con2, 0x1f, sdram_params->base.stride); }
static int sdram_init(const struct dram_info *dram,

Use this function in preference to the macro.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/arm/mach-rockchip/rk3288/reset_rk3288.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/arm/mach-rockchip/rk3288/reset_rk3288.c b/arch/arm/mach-rockchip/rk3288/reset_rk3288.c index 7affd11..bf7540a 100644 --- a/arch/arm/mach-rockchip/rk3288/reset_rk3288.c +++ b/arch/arm/mach-rockchip/rk3288/reset_rk3288.c @@ -22,11 +22,11 @@ int rk3288_reset_request(struct udevice *dev, enum reset_t type) return PTR_ERR(cru); switch (type) { case RESET_WARM: - writel(RK_CLRBITS(0xffff), &cru->cru_mode_con); + rk_clrreg(&cru->cru_mode_con, 0xffff); writel(0xeca8, &cru->cru_glb_srst_snd_value); break; case RESET_COLD: - writel(RK_CLRBITS(0xffff), &cru->cru_mode_con); + rk_clrreg(&cru->cru_mode_con, 0xffff); writel(0xfdb9, &cru->cru_glb_srst_fst_value); break; default:

Rather than changing the clock to the same value on every transaction, remember the last value and don't adjust the clock unless it is necessary.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/spi/rk_spi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/spi/rk_spi.c b/drivers/spi/rk_spi.c index f98284c..7b4a04c 100644 --- a/drivers/spi/rk_spi.c +++ b/drivers/spi/rk_spi.c @@ -44,6 +44,7 @@ struct rockchip_spi_priv { u8 bits_per_word; /* max 16 bits per word */ u8 n_bytes; unsigned int speed_hz; + unsigned int last_speed_hz; unsigned int tmode; uint input_rate; }; @@ -82,6 +83,7 @@ static void rkspi_set_clk(struct rockchip_spi_priv *priv, uint speed) debug("spi speed %u, div %u\n", speed, clk_div);
writel(clk_div, &priv->regs->baudr); + priv->last_speed_hz = speed; }
static int rkspi_wait_till_not_busy(struct rockchip_spi *regs) @@ -211,7 +213,8 @@ static int rockchip_spi_claim_bus(struct udevice *dev) return -EPROTONOSUPPORT; }
- rkspi_set_clk(priv, priv->speed_hz); + if (priv->speed_hz != priv->last_speed_hz) + rkspi_set_clk(priv, priv->speed_hz);
/* Operation Mode */ ctrlr0 = OMOD_MASTER << OMOD_SHIFT;

Two of the init values are created locally so cannot be out of range. The masking is unnecessary and in one case is incorrect. Fix it.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/spi/rk_spi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/spi/rk_spi.c b/drivers/spi/rk_spi.c index 7b4a04c..2570ca3 100644 --- a/drivers/spi/rk_spi.c +++ b/drivers/spi/rk_spi.c @@ -220,7 +220,7 @@ static int rockchip_spi_claim_bus(struct udevice *dev) ctrlr0 = OMOD_MASTER << OMOD_SHIFT;
/* Data Frame Size */ - ctrlr0 |= spi_dfs & DFS_MASK << DFS_SHIFT; + ctrlr0 |= spi_dfs << DFS_SHIFT;
/* set SPI mode 0..3 */ if (priv->mode & SPI_CPOL) @@ -241,7 +241,7 @@ static int rockchip_spi_claim_bus(struct udevice *dev) ctrlr0 |= FBM_MSB << FBM_SHIFT;
/* Byte and Halfword Transform */ - ctrlr0 |= (spi_tf & HALF_WORD_MASK) << HALF_WORD_TX_SHIFT; + ctrlr0 |= spi_tf << HALF_WORD_TX_SHIFT;
/* Rxd Sample Delay */ ctrlr0 |= 0 << RXDSD_SHIFT;

The current method assumes that clocks are numbered from 0 and we can determine a clock by its number. It is safer to use an ID in the clock's platform data to avoid the situation where another clock is bound before the one we expect.
Move the existing code into rk3036 since it still works there. Add a new implementation for rk3288.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/arm/mach-rockchip/Makefile | 1 - arch/arm/mach-rockchip/common.c | 28 ---------------------------- drivers/clk/clk_rk3036.c | 17 +++++++++++++++++ drivers/clk/clk_rk3288.c | 13 +++++++++++++ 4 files changed, 30 insertions(+), 29 deletions(-) delete mode 100644 arch/arm/mach-rockchip/common.c
diff --git a/arch/arm/mach-rockchip/Makefile b/arch/arm/mach-rockchip/Makefile index 1cc4a96..55567cb 100644 --- a/arch/arm/mach-rockchip/Makefile +++ b/arch/arm/mach-rockchip/Makefile @@ -11,6 +11,5 @@ else obj-$(CONFIG_ROCKCHIP_RK3288) += board.o endif obj-y += rk_timer.o -obj-$(CONFIG_$(SPL_)ROCKCHIP_COMMON) += common.o obj-$(CONFIG_ROCKCHIP_RK3288) += rk3288/ obj-$(CONFIG_ROCKCHIP_RK3036) += rk3036/ diff --git a/arch/arm/mach-rockchip/common.c b/arch/arm/mach-rockchip/common.c deleted file mode 100644 index fc7ac72..0000000 --- a/arch/arm/mach-rockchip/common.c +++ /dev/null @@ -1,28 +0,0 @@ -/* - * (C) Copyright 2015 Google, Inc - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <dm.h> -#include <errno.h> -#include <fdtdec.h> -#include <linux/err.h> - -void *rockchip_get_cru(void) -{ - struct udevice *dev; - fdt_addr_t addr; - int ret; - - ret = uclass_get_device(UCLASS_CLK, 0, &dev); - if (ret) - return ERR_PTR(ret); - - addr = dev_get_addr(dev); - if (addr == FDT_ADDR_T_NONE) - return ERR_PTR(-EINVAL); - - return (void *)addr; -} diff --git a/drivers/clk/clk_rk3036.c b/drivers/clk/clk_rk3036.c index 4077bd8..4909c0c 100644 --- a/drivers/clk/clk_rk3036.c +++ b/drivers/clk/clk_rk3036.c @@ -57,6 +57,23 @@ static inline unsigned int log2(unsigned int value) return fls(value) - 1; }
+void *rockchip_get_cru(void) +{ + struct udevice *dev; + fdt_addr_t addr; + int ret; + + ret = uclass_get_device(UCLASS_CLK, 0, &dev); + if (ret) + return ERR_PTR(ret); + + addr = dev_get_addr(dev); + if (addr == FDT_ADDR_T_NONE) + return ERR_PTR(-EINVAL); + + return (void *)addr; +} + static int rkclk_set_pll(struct rk3036_cru *cru, enum rk_clk_id clk_id, const struct pll_div *div) { diff --git a/drivers/clk/clk_rk3288.c b/drivers/clk/clk_rk3288.c index d6d2896..f25a124 100644 --- a/drivers/clk/clk_rk3288.c +++ b/drivers/clk/clk_rk3288.c @@ -159,6 +159,19 @@ int rkclk_get_clk(enum rk_clk_id clk_id, struct udevice **devp) return -ENODEV; }
+void *rockchip_get_cru(void) +{ + struct rk3288_clk_priv *priv; + struct udevice *dev; + int ret; + + ret = rkclk_get_clk(CLK_GENERAL, &dev); + if (ret) + return ERR_PTR(ret); + priv = dev_get_priv(dev); + return priv->cru; +} + static int rkclk_set_pll(struct rk3288_cru *cru, enum rk_clk_id clk_id, const struct pll_div *div) {

This file has many features that are not needed by SPL. Use #ifdef to remove the unused features and reduce the code size.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/pinctrl/rockchip/pinctrl_rk3288.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-)
diff --git a/drivers/pinctrl/rockchip/pinctrl_rk3288.c b/drivers/pinctrl/rockchip/pinctrl_rk3288.c index 0e7721e..53b8cf2 100644 --- a/drivers/pinctrl/rockchip/pinctrl_rk3288.c +++ b/drivers/pinctrl/rockchip/pinctrl_rk3288.c @@ -158,6 +158,7 @@ static void pinctrl_rk3288_i2c_config(struct rk3288_grf *grf, GPIO0_C0_MASK << GPIO0_C0_SHIFT, GPIO0_C0_I2C0PMU_SCL << GPIO0_C0_SHIFT); break; +#ifndef CONFIG_SPL_BUILD case PERIPH_ID_I2C1: rk_clrsetreg(&grf->gpio8a_iomux, GPIO8A4_MASK << GPIO8A4_SHIFT | @@ -194,12 +195,14 @@ static void pinctrl_rk3288_i2c_config(struct rk3288_grf *grf, GPIO7C4_MASK << GPIO7C4_SHIFT, GPIO7C4_I2C5HDMI_SCL << GPIO7C4_SHIFT); break; +#endif default: debug("i2c id = %d iomux error!\n", i2c_id); break; } }
+#ifndef CONFIG_SPL_BUILD static void pinctrl_rk3288_lcdc_config(struct rk3288_grf *grf, int lcd_id) { switch (lcd_id) { @@ -219,11 +222,13 @@ static void pinctrl_rk3288_lcdc_config(struct rk3288_grf *grf, int lcd_id) break; } } +#endif
static int pinctrl_rk3288_spi_config(struct rk3288_grf *grf, enum periph_id spi_id, int cs) { switch (spi_id) { +#ifndef CONFIG_SPL_BUILD case PERIPH_ID_SPI0: switch (cs) { case 0: @@ -260,6 +265,7 @@ static int pinctrl_rk3288_spi_config(struct rk3288_grf *grf, GPIO7B5_SPI1_CSN0 << GPIO7B5_SHIFT | GPIO7B4_SPI1_CLK << GPIO7B4_SHIFT); break; +#endif case PERIPH_ID_SPI2: switch (cs) { case 0: @@ -297,6 +303,7 @@ err: static void pinctrl_rk3288_uart_config(struct rk3288_grf *grf, int uart_id) { switch (uart_id) { +#ifndef CONFIG_SPL_BUILD case PERIPH_ID_UART_BT: rk_clrsetreg(&grf->gpio4c_iomux, GPIO4C3_MASK << GPIO4C3_SHIFT | @@ -319,6 +326,7 @@ static void pinctrl_rk3288_uart_config(struct rk3288_grf *grf, int uart_id) GPIO5B1_UART1BB_SOUT << GPIO5B1_SHIFT | GPIO5B0_UART1BB_SIN << GPIO5B0_SHIFT); break; +#endif case PERIPH_ID_UART_DBG: rk_clrsetreg(&grf->gpio7ch_iomux, GPIO7C7_MASK << GPIO7C7_SHIFT | @@ -326,6 +334,7 @@ static void pinctrl_rk3288_uart_config(struct rk3288_grf *grf, int uart_id) GPIO7C7_UART2DBG_SOUT << GPIO7C7_SHIFT | GPIO7C6_UART2DBG_SIN << GPIO7C6_SHIFT); break; +#ifndef CONFIG_SPL_BUILD case PERIPH_ID_UART_GPS: rk_clrsetreg(&grf->gpio7b_iomux, GPIO7B2_MASK << GPIO7B2_SHIFT | @@ -349,6 +358,7 @@ static void pinctrl_rk3288_uart_config(struct rk3288_grf *grf, int uart_id) GPIO5B6_UART4EXP_SOUT << GPIO5B6_SHIFT | GPIO5B7_UART4EXP_SIN << GPIO5B7_SHIFT); break; +#endif default: debug("uart id = %d iomux error!\n", uart_id); break; @@ -393,6 +403,7 @@ static void pinctrl_rk3288_sdmmc_config(struct rk3288_grf *grf, int mmc_id) } }
+#ifndef CONFIG_SPL_BUILD static void pinctrl_rk3288_hdmi_config(struct rk3288_grf *grf, int hdmi_id) { switch (hdmi_id) { @@ -407,6 +418,7 @@ static void pinctrl_rk3288_hdmi_config(struct rk3288_grf *grf, int hdmi_id) break; } } +#endif
static int rk3288_pinctrl_request(struct udevice *dev, int func, int flags) { @@ -441,17 +453,19 @@ static int rk3288_pinctrl_request(struct udevice *dev, int func, int flags) case PERIPH_ID_UART4: pinctrl_rk3288_uart_config(priv->grf, func); break; +#ifndef CONFIG_SPL_BUILD case PERIPH_ID_LCDC0: case PERIPH_ID_LCDC1: pinctrl_rk3288_lcdc_config(priv->grf, func); break; + case PERIPH_ID_HDMI: + pinctrl_rk3288_hdmi_config(priv->grf, func); + break; +#endif case PERIPH_ID_SDMMC0: case PERIPH_ID_SDMMC1: pinctrl_rk3288_sdmmc_config(priv->grf, func); break; - case PERIPH_ID_HDMI: - pinctrl_rk3288_hdmi_config(priv->grf, func); - break; default: return -EINVAL; }

Hi Simon
I think the best way to reduce SPL size is to jump back to boot rom. Which don't require eMMC, SD card driver in SPL any more. Even clock and pinctrl driver is not required. All we need is DDR initialization. We should do as little thing as possible in SPL and let U-boot take care others.
Thanks
Eddie
2016-01-14 7:25 GMT+08:00 Simon Glass sjg@chromium.org:
This file has many features that are not needed by SPL. Use #ifdef to remove the unused features and reduce the code size.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/pinctrl/rockchip/pinctrl_rk3288.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-)
diff --git a/drivers/pinctrl/rockchip/pinctrl_rk3288.c b/drivers/pinctrl/rockchip/pinctrl_rk3288.c index 0e7721e..53b8cf2 100644 --- a/drivers/pinctrl/rockchip/pinctrl_rk3288.c +++ b/drivers/pinctrl/rockchip/pinctrl_rk3288.c @@ -158,6 +158,7 @@ static void pinctrl_rk3288_i2c_config(struct rk3288_grf *grf, GPIO0_C0_MASK << GPIO0_C0_SHIFT, GPIO0_C0_I2C0PMU_SCL << GPIO0_C0_SHIFT); break; +#ifndef CONFIG_SPL_BUILD case PERIPH_ID_I2C1: rk_clrsetreg(&grf->gpio8a_iomux, GPIO8A4_MASK << GPIO8A4_SHIFT | @@ -194,12 +195,14 @@ static void pinctrl_rk3288_i2c_config(struct rk3288_grf *grf, GPIO7C4_MASK << GPIO7C4_SHIFT, GPIO7C4_I2C5HDMI_SCL << GPIO7C4_SHIFT); break; +#endif default: debug("i2c id = %d iomux error!\n", i2c_id); break; } }
+#ifndef CONFIG_SPL_BUILD static void pinctrl_rk3288_lcdc_config(struct rk3288_grf *grf, int lcd_id) { switch (lcd_id) { @@ -219,11 +222,13 @@ static void pinctrl_rk3288_lcdc_config(struct rk3288_grf *grf, int lcd_id) break; } } +#endif
static int pinctrl_rk3288_spi_config(struct rk3288_grf *grf, enum periph_id spi_id, int cs) { switch (spi_id) { +#ifndef CONFIG_SPL_BUILD case PERIPH_ID_SPI0: switch (cs) { case 0: @@ -260,6 +265,7 @@ static int pinctrl_rk3288_spi_config(struct rk3288_grf *grf, GPIO7B5_SPI1_CSN0 << GPIO7B5_SHIFT | GPIO7B4_SPI1_CLK << GPIO7B4_SHIFT); break; +#endif case PERIPH_ID_SPI2: switch (cs) { case 0: @@ -297,6 +303,7 @@ err: static void pinctrl_rk3288_uart_config(struct rk3288_grf *grf, int uart_id) { switch (uart_id) { +#ifndef CONFIG_SPL_BUILD case PERIPH_ID_UART_BT: rk_clrsetreg(&grf->gpio4c_iomux, GPIO4C3_MASK << GPIO4C3_SHIFT | @@ -319,6 +326,7 @@ static void pinctrl_rk3288_uart_config(struct rk3288_grf *grf, int uart_id) GPIO5B1_UART1BB_SOUT << GPIO5B1_SHIFT | GPIO5B0_UART1BB_SIN << GPIO5B0_SHIFT); break; +#endif case PERIPH_ID_UART_DBG: rk_clrsetreg(&grf->gpio7ch_iomux, GPIO7C7_MASK << GPIO7C7_SHIFT | @@ -326,6 +334,7 @@ static void pinctrl_rk3288_uart_config(struct rk3288_grf *grf, int uart_id) GPIO7C7_UART2DBG_SOUT << GPIO7C7_SHIFT | GPIO7C6_UART2DBG_SIN << GPIO7C6_SHIFT); break; +#ifndef CONFIG_SPL_BUILD case PERIPH_ID_UART_GPS: rk_clrsetreg(&grf->gpio7b_iomux, GPIO7B2_MASK << GPIO7B2_SHIFT | @@ -349,6 +358,7 @@ static void pinctrl_rk3288_uart_config(struct rk3288_grf *grf, int uart_id) GPIO5B6_UART4EXP_SOUT << GPIO5B6_SHIFT | GPIO5B7_UART4EXP_SIN << GPIO5B7_SHIFT); break; +#endif default: debug("uart id = %d iomux error!\n", uart_id); break; @@ -393,6 +403,7 @@ static void pinctrl_rk3288_sdmmc_config(struct rk3288_grf *grf, int mmc_id) } }
+#ifndef CONFIG_SPL_BUILD static void pinctrl_rk3288_hdmi_config(struct rk3288_grf *grf, int hdmi_id) { switch (hdmi_id) { @@ -407,6 +418,7 @@ static void pinctrl_rk3288_hdmi_config(struct rk3288_grf *grf, int hdmi_id) break; } } +#endif
static int rk3288_pinctrl_request(struct udevice *dev, int func, int flags) { @@ -441,17 +453,19 @@ static int rk3288_pinctrl_request(struct udevice *dev, int func, int flags) case PERIPH_ID_UART4: pinctrl_rk3288_uart_config(priv->grf, func); break; +#ifndef CONFIG_SPL_BUILD case PERIPH_ID_LCDC0: case PERIPH_ID_LCDC1: pinctrl_rk3288_lcdc_config(priv->grf, func); break;
case PERIPH_ID_HDMI:
pinctrl_rk3288_hdmi_config(priv->grf, func);
break;
+#endif case PERIPH_ID_SDMMC0: case PERIPH_ID_SDMMC1: pinctrl_rk3288_sdmmc_config(priv->grf, func); break;
case PERIPH_ID_HDMI:
pinctrl_rk3288_hdmi_config(priv->grf, func);
break; default: return -EINVAL; }
-- 2.6.0.rc2.230.g3dd15c0
U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot

Hi Eddie,
On 14 January 2016 at 05:47, Eddie Cai eddie.cai.kernel@gmail.com wrote:
Hi Simon
I think the best way to reduce SPL size is to jump back to boot rom. Which don't require eMMC, SD card driver in SPL any more. Even clock and pinctrl driver is not required. All we need is DDR initialization. We should do as little thing as possible in SPL and let U-boot take care others.
Is it possible to use the ROM to load U-Boot and then get control back before jumping to it? If so, then I agree this would be best.
Ideally we just need a routine we can call which can load from eMMC/SD.
Regards, Simon
Thanks
Eddie
[snip]

On Thu, 2016-01-14 at 08:51 -0700, Simon Glass wrote:
Hi Eddie,
On 14 January 2016 at 05:47, Eddie Cai eddie.cai.kernel@gmail.com wrote:
Hi Simon
I think the best way to reduce SPL size is to jump back to boot rom. Which don't require eMMC, SD card driver in SPL any more. Even clock and pinctrl driver is not required. All we need is DDR initialization. We should do as little thing as possible in SPL and let U-boot take care others.
Is it possible to use the ROM to load U-Boot and then get control back before jumping to it? If so, then I agree this would be best.
Ideally we just need a routine we can call which can load from eMMC/SD.
Incidentally I've been playing with this a bit over the last week. Mostly because I wanted to load u-boot over USB OTG to make it simpler to quickly test things (e.g. to test my networking series more easily).
I've got some work in progress code to jump back to the bootrom after the SPL which allows me to load u-boot via USB OTG as well, which is great start.
Unfortunately it seems that loading a kernel after that will cause the kernel to wedge during early boot. Initial analysis shows it doesn't get interrupts from the architecture timer, but it might well be interrupts don't work at all...
Eddie, any ideas what the maskrom code might do different with the interrupt setup if loading things over OTG vs. from MMC?
Regards, Simon
Thanks
Eddie
[snip] _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot

Hi,
On 18 January 2016 at 02:39, Sjoerd Simons sjoerd.simons@collabora.co.uk wrote:
On Thu, 2016-01-14 at 08:51 -0700, Simon Glass wrote:
Hi Eddie,
On 14 January 2016 at 05:47, Eddie Cai eddie.cai.kernel@gmail.com wrote:
Hi Simon
I think the best way to reduce SPL size is to jump back to boot rom. Which don't require eMMC, SD card driver in SPL any more. Even clock and pinctrl driver is not required. All we need is DDR initialization. We should do as little thing as possible in SPL and let U-boot take care others.
Is it possible to use the ROM to load U-Boot and then get control back before jumping to it? If so, then I agree this would be best.
Ideally we just need a routine we can call which can load from eMMC/SD.
Incidentally I've been playing with this a bit over the last week. Mostly because I wanted to load u-boot over USB OTG to make it simpler to quickly test things (e.g. to test my networking series more easily).
I've got some work in progress code to jump back to the bootrom after the SPL which allows me to load u-boot via USB OTG as well, which is great start.
Unfortunately it seems that loading a kernel after that will cause the kernel to wedge during early boot. Initial analysis shows it doesn't get interrupts from the architecture timer, but it might well be interrupts don't work at all...
Eddie, any ideas what the maskrom code might do different with the interrupt setup if loading things over OTG vs. from MMC?
It would certainly be great if we can use the boot ROM code. This is what we do on exynos and it makes a big difference to the SPL size.
Regards, Simon

Implement this so that the GPIO command will be able to report whether a GPIO is used for input or output.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/pinctrl/rockchip/pinctrl_rk3288.c | 68 +++++++++++++++++++++++-------- 1 file changed, 52 insertions(+), 16 deletions(-)
diff --git a/drivers/pinctrl/rockchip/pinctrl_rk3288.c b/drivers/pinctrl/rockchip/pinctrl_rk3288.c index 53b8cf2..8356786 100644 --- a/drivers/pinctrl/rockchip/pinctrl_rk3288.c +++ b/drivers/pinctrl/rockchip/pinctrl_rk3288.c @@ -520,18 +520,16 @@ static int rk3288_pinctrl_set_state_simple(struct udevice *dev, }
#ifndef CONFIG_SPL_BUILD -static int rk3288_pinctrl_set_pins(struct udevice *dev, int banknum, int index, - int muxval, int flags) +int rk3288_pinctrl_get_pin_info(struct rk3288_pinctrl_priv *priv, + int banknum, int ind, u32 **addrp, uint *shiftp, + uint *maskp) { - struct rk3288_pinctrl_priv *priv = dev_get_priv(dev); struct rockchip_pin_bank *bank = &rk3288_pin_banks[banknum]; - uint shift, muxnum, ind = index; + uint muxnum; u32 *addr;
- debug("%s: %x %x %x %x\n", __func__, banknum, index, muxval, flags); for (muxnum = 0; muxnum < 4; muxnum++) { struct rockchip_iomux *mux = &bank->iomux[muxnum]; - uint mask;
if (ind >= 8) { ind -= 8; @@ -543,24 +541,61 @@ static int rk3288_pinctrl_set_pins(struct udevice *dev, int banknum, int index, else addr = (u32 *)priv->grf - 4; addr += mux->offset; - shift = ind & 7; + *shiftp = ind & 7; if (mux->type & IOMUX_WIDTH_4BIT) { - mask = 0xf; - shift *= 4; - if (shift >= 16) { - shift -= 16; + *maskp = 0xf; + *shiftp *= 4; + if (*shiftp >= 16) { + *shiftp -= 16; addr++; } } else { - mask = 3; - shift *= 2; + *maskp = 3; + *shiftp *= 2; }
debug("%s: addr=%p, mask=%x, shift=%x\n", __func__, addr, - mask, shift); - rk_clrsetreg(addr, mask << shift, muxval << shift); - break; + *maskp, *shiftp); + *addrp = addr; + return 0; } + + return -EINVAL; +} + +static int rk3288_pinctrl_get_gpio_mux(struct udevice *dev, int banknum, + int index) +{ + struct rk3288_pinctrl_priv *priv = dev_get_priv(dev); + uint shift; + uint mask; + u32 *addr; + int ret; + + ret = rk3288_pinctrl_get_pin_info(priv, banknum, index, &addr, &shift, + &mask); + if (ret) + return ret; + return (readl(addr) & mask) >> shift; +} + +static int rk3288_pinctrl_set_pins(struct udevice *dev, int banknum, int index, + int muxval, int flags) +{ + struct rk3288_pinctrl_priv *priv = dev_get_priv(dev); + uint shift, ind = index; + uint mask; + u32 *addr; + int ret; + + debug("%s: %x %x %x %x\n", __func__, banknum, index, muxval, flags); + ret = rk3288_pinctrl_get_pin_info(priv, banknum, index, &addr, &shift, + &mask); + if (ret) + return ret; + rk_clrsetreg(addr, mask << shift, muxval << shift); + + /* Handle pullup/pulldown */ if (flags) { uint val = 0;
@@ -618,6 +653,7 @@ static int rk3288_pinctrl_set_state(struct udevice *dev, struct udevice *config) static struct pinctrl_ops rk3288_pinctrl_ops = { #ifndef CONFIG_SPL_BUILD .set_state = rk3288_pinctrl_set_state, + .get_gpio_mux = rk3288_pinctrl_get_gpio_mux, #endif .set_state_simple = rk3288_pinctrl_set_state_simple, .request = rk3288_pinctrl_request,

This function should return 0 or 1, not a mask. Fix it.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/gpio/rk_gpio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpio/rk_gpio.c b/drivers/gpio/rk_gpio.c index fbdf9f3..a22e219 100644 --- a/drivers/gpio/rk_gpio.c +++ b/drivers/gpio/rk_gpio.c @@ -53,7 +53,7 @@ static int rockchip_gpio_get_value(struct udevice *dev, unsigned offset) struct rockchip_gpio_priv *priv = dev_get_priv(dev); struct rockchip_gpio_regs *regs = priv->regs;
- return readl(®s->ext_port) & OFFSET_TO_BIT(offset); + return readl(®s->ext_port) & OFFSET_TO_BIT(offset) ? 1 : 0; }
static int rockchip_gpio_set_value(struct udevice *dev, unsigned offset,

Provide this method so that 'gpio status' works fully. It now shows whether a pin is used for input, output or some other function.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/gpio/rk_gpio.c | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-)
diff --git a/drivers/gpio/rk_gpio.c b/drivers/gpio/rk_gpio.c index a22e219..c62f025 100644 --- a/drivers/gpio/rk_gpio.c +++ b/drivers/gpio/rk_gpio.c @@ -8,11 +8,16 @@ */
#include <common.h> +#include <clk.h> #include <dm.h> +#include <syscon.h> #include <asm/errno.h> #include <asm/gpio.h> #include <asm/io.h> +#include <asm/arch/clock.h> +#include <dm/pinctrl.h> #include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/clock/rk3288-cru.h>
enum { ROCKCHIP_GPIOS_PER_BANK = 32, @@ -22,6 +27,8 @@ enum {
struct rockchip_gpio_priv { struct rockchip_gpio_regs *regs; + struct udevice *pinctrl; + int bank; char name[2]; };
@@ -70,7 +77,25 @@ static int rockchip_gpio_set_value(struct udevice *dev, unsigned offset,
static int rockchip_gpio_get_function(struct udevice *dev, unsigned offset) { - return -ENOSYS; +#ifdef CONFIG_SPL_BUILD + return -ENODATA; +#else + struct rockchip_gpio_priv *priv = dev_get_priv(dev); + struct rockchip_gpio_regs *regs = priv->regs; + bool is_output; + int ret; + + ret = pinctrl_get_gpio_mux(priv->pinctrl, priv->bank, offset); + if (ret) + return ret; + + /* If it's not 0, then it is not a GPIO */ + if (ret) + return GPIOF_FUNC; + is_output = readl(®s->swport_ddr) & OFFSET_TO_BIT(offset); + + return is_output ? GPIOF_OUTPUT : GPIOF_INPUT; +#endif }
static int rockchip_gpio_xlate(struct udevice *dev, struct gpio_desc *desc, @@ -87,13 +112,20 @@ static int rockchip_gpio_probe(struct udevice *dev) struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); struct rockchip_gpio_priv *priv = dev_get_priv(dev); char *end; - int bank; + int ret;
+ /* This only supports RK3288 at present */ priv->regs = (struct rockchip_gpio_regs *)dev_get_addr(dev); + ret = uclass_first_device(UCLASS_PINCTRL, &priv->pinctrl); + if (ret) + return ret; + if (!priv->pinctrl) + return -ENODEV; + uc_priv->gpio_count = ROCKCHIP_GPIOS_PER_BANK; end = strrchr(dev->name, '@'); - bank = trailing_strtoln(dev->name, end); - priv->name[0] = 'A' + bank; + priv->bank = trailing_strtoln(dev->name, end); + priv->name[0] = 'A' + priv->bank; uc_priv->bank_name = priv->name;
return 0;

Some devices need delays before and after activiation. Implement these features in the SPI driver so that we will be able to enable the Chrome OS EC.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/spi/rk_spi.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-)
diff --git a/drivers/spi/rk_spi.c b/drivers/spi/rk_spi.c index 2570ca3..91538b4 100644 --- a/drivers/spi/rk_spi.c +++ b/drivers/spi/rk_spi.c @@ -32,6 +32,7 @@ struct rockchip_spi_platdata { s32 frequency; /* Default clock frequency, -1 for none */ fdt_addr_t base; uint deactivate_delay_us; /* Delay to wait after deactivate */ + uint activate_delay_us; /* Delay to wait after activate */ };
struct rockchip_spi_priv { @@ -101,16 +102,32 @@ static int rkspi_wait_till_not_busy(struct rockchip_spi *regs) return 0; }
-static void spi_cs_activate(struct rockchip_spi *regs, uint cs) +static void spi_cs_activate(struct udevice *dev, uint cs) { + struct udevice *bus = dev->parent; + struct rockchip_spi_platdata *plat = bus->platdata; + struct rockchip_spi_priv *priv = dev_get_priv(bus); + struct rockchip_spi *regs = priv->regs; + debug("activate cs%u\n", cs); writel(1 << cs, ®s->ser); + if (plat->activate_delay_us) + udelay(plat->activate_delay_us); }
-static void spi_cs_deactivate(struct rockchip_spi *regs, uint cs) +static void spi_cs_deactivate(struct udevice *dev, uint cs) { + struct udevice *bus = dev->parent; + struct rockchip_spi_platdata *plat = bus->platdata; + struct rockchip_spi_priv *priv = dev_get_priv(bus); + struct rockchip_spi *regs = priv->regs; + debug("deactivate cs%u\n", cs); writel(0, ®s->ser); + + /* Remember time of this transaction so we can honour the bus delay */ + if (plat->deactivate_delay_us) + priv->last_transaction_us = timer_get_us(); }
static int rockchip_spi_ofdata_to_platdata(struct udevice *bus) @@ -144,6 +161,8 @@ static int rockchip_spi_ofdata_to_platdata(struct udevice *bus) 50000000); plat->deactivate_delay_us = fdtdec_get_int(blob, node, "spi-deactivate-delay", 0); + plat->activate_delay_us = fdtdec_get_int(blob, node, + "spi-activate-delay", 0); debug("%s: base=%x, periph_id=%d, max-frequency=%d, deactivate_delay=%d\n", __func__, (uint)plat->base, plat->periph_id, plat->frequency, plat->deactivate_delay_us); @@ -289,7 +308,7 @@ static int rockchip_spi_xfer(struct udevice *dev, unsigned int bitlen,
/* Assert CS before transfer */ if (flags & SPI_XFER_BEGIN) - spi_cs_activate(regs, slave_plat->cs); + spi_cs_activate(dev, slave_plat->cs);
while (len > 0) { int todo = min(len, 0xffff); @@ -323,7 +342,7 @@ static int rockchip_spi_xfer(struct udevice *dev, unsigned int bitlen,
/* Deassert CS after transfer */ if (flags & SPI_XFER_END) - spi_cs_deactivate(regs, slave_plat->cs); + spi_cs_deactivate(dev, slave_plat->cs);
rkspi_enable_chip(regs, false);

At present there is an incorrect call to rkspi_enable_chip(). It should be disabling the chip, not enabling it. Correct this and ensure that the chip is disabled when releasing the bus.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/spi/rk_spi.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/spi/rk_spi.c b/drivers/spi/rk_spi.c index 91538b4..ecda833 100644 --- a/drivers/spi/rk_spi.c +++ b/drivers/spi/rk_spi.c @@ -285,6 +285,11 @@ static int rockchip_spi_claim_bus(struct udevice *dev)
static int rockchip_spi_release_bus(struct udevice *dev) { + struct udevice *bus = dev->parent; + struct rockchip_spi_priv *priv = dev_get_priv(bus); + + rkspi_enable_chip(priv->regs, false); + return 0; }
@@ -313,7 +318,7 @@ static int rockchip_spi_xfer(struct udevice *dev, unsigned int bitlen, while (len > 0) { int todo = min(len, 0xffff);
- rkspi_enable_chip(regs, true); + rkspi_enable_chip(regs, false); writel(todo - 1, ®s->ctrlr1); rkspi_enable_chip(regs, true);

The correct pinctrl is handled automatically so we don't need to do it in the driver. The exception is when we want to use a different chip select (other than 0). But this isn't used at present.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/spi/rk_spi.c | 28 ++-------------------------- 1 file changed, 2 insertions(+), 26 deletions(-)
diff --git a/drivers/spi/rk_spi.c b/drivers/spi/rk_spi.c index ecda833..203db09 100644 --- a/drivers/spi/rk_spi.c +++ b/drivers/spi/rk_spi.c @@ -27,8 +27,6 @@ DECLARE_GLOBAL_DATA_PTR; #define DEBUG_RK_SPI 0
struct rockchip_spi_platdata { - int periph_id; - struct udevice *pinctrl; s32 frequency; /* Default clock frequency, -1 for none */ fdt_addr_t base; uint deactivate_delay_us; /* Delay to wait after deactivate */ @@ -139,17 +137,7 @@ static int rockchip_spi_ofdata_to_platdata(struct udevice *bus) int ret;
plat->base = dev_get_addr(bus); - ret = uclass_get_device(UCLASS_PINCTRL, 0, &plat->pinctrl); - if (ret) - return ret; - ret = pinctrl_get_periph_id(plat->pinctrl, bus);
- if (ret < 0) { - debug("%s: Could not get peripheral ID for %s: %d\n", __func__, - bus->name, ret); - return ret; - } - plat->periph_id = ret; ret = clk_get_by_index(bus, 0, &priv->clk, &priv->clk_id); if (ret < 0) { debug("%s: Could not get clock for %s: %d\n", __func__, @@ -163,8 +151,8 @@ static int rockchip_spi_ofdata_to_platdata(struct udevice *bus) "spi-deactivate-delay", 0); plat->activate_delay_us = fdtdec_get_int(blob, node, "spi-activate-delay", 0); - debug("%s: base=%x, periph_id=%d, max-frequency=%d, deactivate_delay=%d\n", - __func__, (uint)plat->base, plat->periph_id, plat->frequency, + debug("%s: base=%x, max-frequency=%d, deactivate_delay=%d\n", + __func__, (uint)plat->base, plat->frequency, plat->deactivate_delay_us);
return 0; @@ -206,11 +194,6 @@ static int rockchip_spi_claim_bus(struct udevice *dev) struct rockchip_spi *regs = priv->regs; u8 spi_dfs, spi_tf; uint ctrlr0; -#if !CONFIG_IS_ENABLED(PINCTRL_FULL) - struct rockchip_spi_platdata *plat = dev_get_platdata(bus); - struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev); - int ret; -#endif
/* Disable the SPI hardware */ rkspi_enable_chip(regs, 0); @@ -272,13 +255,6 @@ static int rockchip_spi_claim_bus(struct udevice *dev) ctrlr0 |= (priv->tmode & TMOD_MASK) << TMOD_SHIFT;
writel(ctrlr0, ®s->ctrlr0); -#if !CONFIG_IS_ENABLED(PINCTRL_FULL) - ret = pinctrl_request(plat->pinctrl, plat->periph_id, slave_plat->cs); - if (ret) { - debug("%s: Cannot request pinctrl: %d\n", __func__, ret); - return ret; - } -#endif
return 0; }

Turn on the EC and enable the keyboard.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/arm/dts/rk3288-veyron-chromebook.dtsi | 4 ++++ configs/chromebook_jerry_defconfig | 8 ++++++++ include/configs/chromebook_jerry.h | 7 +++++++ include/configs/firefly-rk3288.h | 2 ++ include/configs/rk3288_common.h | 7 +++++++ 5 files changed, 28 insertions(+)
diff --git a/arch/arm/dts/rk3288-veyron-chromebook.dtsi b/arch/arm/dts/rk3288-veyron-chromebook.dtsi index 6d619c9..bbbc2f4 100644 --- a/arch/arm/dts/rk3288-veyron-chromebook.dtsi +++ b/arch/arm/dts/rk3288-veyron-chromebook.dtsi @@ -91,12 +91,16 @@
&spi0 { status = "okay"; + spi-activate-delay = <100>; + spi-max-frequency = <3000000>; + spi-deactivate-delay = <200>;
cros_ec: ec@0 { compatible = "google,cros-ec-spi"; spi-max-frequency = <3000000>; interrupt-parent = <&gpio7>; interrupts = <7 IRQ_TYPE_LEVEL_LOW>; + ec-interrupt = <&gpio7 7 GPIO_ACTIVE_LOW>; pinctrl-names = "default"; pinctrl-0 = <&ec_int>; reg = <0>; diff --git a/configs/chromebook_jerry_defconfig b/configs/chromebook_jerry_defconfig index ceec6f5..b2672b8 100644 --- a/configs/chromebook_jerry_defconfig +++ b/configs/chromebook_jerry_defconfig @@ -4,6 +4,7 @@ CONFIG_SYS_MALLOC_F_LEN=0x2000 CONFIG_ROCKCHIP_RK3288=y CONFIG_TARGET_CHROMEBOOK_JERRY=y CONFIG_SPL_STACK_R_ADDR=0x80000 +CONFIG_DM_KEYBOARD=y CONFIG_DEFAULT_DEVICE_TREE="rk3288-jerry" CONFIG_SPL_STACK_R=y CONFIG_SPL_STACK_R_MALLOC_SIMPLE_LEN=0x2000 @@ -21,7 +22,13 @@ CONFIG_SPL_SYSCON=y CONFIG_CLK=y CONFIG_SPL_CLK=y CONFIG_ROCKCHIP_GPIO=y +CONFIG_I2C_CROS_EC_TUNNEL=y CONFIG_SYS_I2C_ROCKCHIP=y +CONFIG_I2C_MUX=y +CONFIG_CROS_EC_KEYB=y +CONFIG_CMD_CROS_EC=y +CONFIG_CROS_EC=y +CONFIG_CROS_EC_SPI=y CONFIG_PWRSEQ=y CONFIG_RESET=y CONFIG_DM_MMC=y @@ -31,6 +38,7 @@ CONFIG_SPL_PINCTRL=y # CONFIG_SPL_PINCTRL_FULL is not set CONFIG_ROCKCHIP_PINCTRL=y CONFIG_DM_PMIC=y +# CONFIG_SPL_PMIC_CHILDREN is not set CONFIG_PMIC_RK808=y CONFIG_DM_REGULATOR=y CONFIG_REGULATOR_RK808=y diff --git a/include/configs/chromebook_jerry.h b/include/configs/chromebook_jerry.h index 78c06af..6e32f2c 100644 --- a/include/configs/chromebook_jerry.h +++ b/include/configs/chromebook_jerry.h @@ -7,6 +7,11 @@ #ifndef __CONFIG_H #define __CONFIG_H
+#define ROCKCHIP_DEVICE_SETTINGS \ + "stdin=serial,cros-ec-keyb\0" \ + "stdout=serial\0" \ + "stderr=serial\0" + #include <configs/rk3288_common.h>
#define CONFIG_ENV_IS_NOWHERE @@ -17,4 +22,6 @@
#undef CONFIG_SPL_GPIO_SUPPORT
+#define CONFIG_KEYBOARD + #endif diff --git a/include/configs/firefly-rk3288.h b/include/configs/firefly-rk3288.h index 4c5c4dd..8ac6521 100644 --- a/include/configs/firefly-rk3288.h +++ b/include/configs/firefly-rk3288.h @@ -7,6 +7,8 @@ #ifndef __CONFIG_H #define __CONFIG_H
+#define ROCKCHIP_DEVICE_SETTINGS + #include <configs/rk3288_common.h>
#define CONFIG_SPL_MMC_SUPPORT diff --git a/include/configs/rk3288_common.h b/include/configs/rk3288_common.h index f47573b..ebddfb0 100644 --- a/include/configs/rk3288_common.h +++ b/include/configs/rk3288_common.h @@ -42,6 +42,12 @@ #define CONFIG_ROCKCHIP_COMMON #define CONFIG_SPL_ROCKCHIP_COMMON
+#define CONFIG_SILENT_CONSOLE +#ifndef CONFIG_SPL_BUILD +# define CONFIG_SYS_CONSOLE_IS_IN_ENV +# define CONFIG_CONSOLE_MUX +#endif + /* MMC/SD IP block */ #define CONFIG_MMC #define CONFIG_GENERIC_MMC @@ -110,6 +116,7 @@ "fdt_high=0x1fffffff\0" \ "initrd_high=0x1fffffff\0" \ ENV_MEM_LAYOUT_SETTINGS \ + ROCKCHIP_DEVICE_SETTINGS \ BOOTENV #endif

Hi,
On 13 January 2016 at 16:24, Simon Glass sjg@chromium.org wrote:
This series provides a number of new features and improvements leading to enabling the keyboard (via Chrome OS EC) on jerry. This is conneected via SPI and uses its own message protocol.
Features and fixes are needed in the rockchip code to make this work include: - RK808 PMIC and regulator driver - Fixes and improvements to the i2c and SPI drivers - A full implementation of the GPIO driver - Additional clock support - Additional pinctrl support
The series moves a few rockchip boards to use the full pinctrl driver. I'm not sure this is a great idea, as it slows down start-up noticeably. It is currently needed for the display series (to come), but I intend to change that.
Simon Glass (50): dm: clk: Add support for decoding clocks from the device tree dm: core: Don't set pinctrl for pinctrl devices dm: pinctrl: Add a function to parse PIN_CONFIG flags dm: pmic: Add 'reg status' to show all regulators dts: Bring in pinctrl device tree binding power: Add base support for the RK808 PMIC power: Add support for RK808 regulators dm: Add a power sequencing uclass rockchip: Avoid using MMC code when not booting from MMC rockchip: Convert the PMU IOMUX registers into an array rockchip: mmc: Use a pwrseq device if available rockchip: Correct the defconfig order rockchip: Use pwrseq for MMC start-up on jerry rockchip: jerry: Disable pmic-int-1 setup to avoid a hang rockchip: Use a separate clock ID for clocks rockchip: clock: Rename the general clock variable to gclk_rate rockchip: clk: Add a function to get a peripheral clock rate rockchip: clock: Add a function to find a clock by ID rockchip: i2c: Update the driver to use the new clock ID rockchip: spi: Update the driver to use the new clock ID rockchip: spi: Avoid setting the pinctrl twice rockchip: mmc: Update the driver to use the new clock ID rockchip: pinctrl: Add a full pinctrl driver rockchip: Move firefly and jerry to use the full pinctrl rockchip: jerry: Enable the RK808 PMIC and regulator rockchip: Disable simple-bus in SPL for firefly-rk3288, jerry rockchip: jerry: Drop unused options gpio: Allow 's' as an abbreviation for 'status' cros_ec: Disable the Chrome OS EC in SPL dm: i2c: Allow muxes to be enabled for SPL separately spi: Correct device tree usage in spi_flash_decode_fdt() dm: power: Allow regulators to be omitted from SPL dm: pinctrl: Add a way for a GPIO driver to obtain a pin function dm: core: Export uclass_find_device_by_of_offset() dm: power: Tidy up debugging output and return values dm: power: Allow regulators to not implement all operations dm: clk: Add a simple version of clk_get_by_index() rockchip: sdram: Use the rk_clr/setreg() interface rockchip: reset: Use the rk_clr/setreg() interface rockchip: spi: Remember the last speed to avoid re-setting it rockchip: spi: Correct the bus init code rockchip: clk: Make rkclk_get_clk() SoC-specific rockchip: pinctrl: Reduce the size for SPL rockchip: pinctrl: Implement the get_gpio_mux() method rockchip: gpio: Read the GPIO value correctly rockchip: gpio: Implement the get_function() method rockchip: spi: Implement the delays rockchip: spi: Correct chip-enable code rockchip: spi: Remove the explicit pinctrl setting rockchip: jerry: Enable the Chrome OS EC
I know this is pretty soon, but I'd like to apply this to u-boot-rockchip in the next day or two. If there are any more comments, please send them through.
Regards, Simon
participants (5)
-
Eddie Cai
-
Heiko Schocher
-
Masahiro Yamada
-
Simon Glass
-
Sjoerd Simons