diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpio/dwapb_gpio.c | 33 | ||||
-rw-r--r-- | drivers/led/led_gpio.c | 7 | ||||
-rw-r--r-- | drivers/pinctrl/Kconfig | 7 | ||||
-rw-r--r-- | drivers/pinctrl/Makefile | 1 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-generic.c | 127 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-kendryte.c | 737 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-sandbox.c | 186 | ||||
-rw-r--r-- | drivers/ram/Kconfig | 1 | ||||
-rw-r--r-- | drivers/ram/Makefile | 1 | ||||
-rw-r--r-- | drivers/ram/aspeed/Kconfig | 10 | ||||
-rw-r--r-- | drivers/ram/aspeed/Makefile | 3 | ||||
-rw-r--r-- | drivers/ram/aspeed/sdram_ast2500.c | 439 | ||||
-rw-r--r-- | drivers/watchdog/designware_wdt.c | 2 |
13 files changed, 1460 insertions, 94 deletions
diff --git a/drivers/gpio/dwapb_gpio.c b/drivers/gpio/dwapb_gpio.c index e5e3518194..37916e7771 100644 --- a/drivers/gpio/dwapb_gpio.c +++ b/drivers/gpio/dwapb_gpio.c @@ -40,7 +40,7 @@ struct gpio_dwapb_platdata { const char *name; int bank; int pins; - fdt_addr_t base; + void __iomem *base; }; static int dwapb_gpio_direction_input(struct udevice *dev, unsigned pin) @@ -66,13 +66,6 @@ static int dwapb_gpio_direction_output(struct udevice *dev, unsigned pin, return 0; } -static int dwapb_gpio_get_value(struct udevice *dev, unsigned pin) -{ - struct gpio_dwapb_platdata *plat = dev_get_platdata(dev); - return !!(readl(plat->base + GPIO_EXT_PORT(plat->bank)) & (1 << pin)); -} - - static int dwapb_gpio_set_value(struct udevice *dev, unsigned pin, int val) { struct gpio_dwapb_platdata *plat = dev_get_platdata(dev); @@ -98,6 +91,18 @@ static int dwapb_gpio_get_function(struct udevice *dev, unsigned offset) return GPIOF_INPUT; } +static int dwapb_gpio_get_value(struct udevice *dev, unsigned pin) +{ + struct gpio_dwapb_platdata *plat = dev_get_platdata(dev); + u32 value; + + if (dwapb_gpio_get_function(dev, pin) == GPIOF_OUTPUT) + value = readl(plat->base + GPIO_SWPORT_DR(plat->bank)); + else + value = readl(plat->base + GPIO_EXT_PORT(plat->bank)); + return !!(value & BIT(pin)); +} + static const struct dm_gpio_ops gpio_dwapb_ops = { .direction_input = dwapb_gpio_direction_input, .direction_output = dwapb_gpio_direction_output, @@ -176,7 +181,7 @@ static int gpio_dwapb_bind(struct udevice *dev) if (!plat) return -ENOMEM; - plat->base = base; + plat->base = (void *)base; plat->bank = bank; plat->pins = ofnode_read_u32_default(node, "snps,nr-gpios", 0); @@ -186,7 +191,15 @@ static int gpio_dwapb_bind(struct udevice *dev) * Fall back to node name. This means accessing pins * via bank name won't work. */ - plat->name = ofnode_get_name(node); + char name[32]; + + snprintf(name, sizeof(name), "%s_", + ofnode_get_name(node)); + plat->name = strdup(name); + if (!plat->name) { + kfree(plat); + return -ENOMEM; + } } ret = device_bind_ofnode(dev, dev->driver, plat->name, diff --git a/drivers/led/led_gpio.c b/drivers/led/led_gpio.c index ef9b61ee62..2cdb0269f4 100644 --- a/drivers/led/led_gpio.c +++ b/drivers/led/led_gpio.c @@ -99,11 +99,8 @@ static int led_gpio_bind(struct udevice *parent) const char *label; label = ofnode_read_string(node, "label"); - if (!label) { - debug("%s: node %s has no label\n", __func__, - ofnode_get_name(node)); - return -EINVAL; - } + if (!label) + label = ofnode_get_name(node); ret = device_bind_driver_to_node(parent, "gpio_led", ofnode_get_name(node), node, &dev); diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 048583f39b..77fb851114 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -291,6 +291,13 @@ config ASPEED_AST2500_PINCTRL uses Generic Pinctrl framework and is compatible with the Linux driver, i.e. it uses the same device tree configuration. +config PINCTRL_K210 + bool "Kendryte K210 Fully-Programmable Input/Output Array driver" + depends on DM && PINCTRL_GENERIC + help + Support pin multiplexing on the K210. The "FPIOA" can remap any + supported function to any multifunctional IO pin. It can also perform + basic GPIO functions, such as reading the current value of a pin. endif source "drivers/pinctrl/broadcom/Kconfig" diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 507dd3a926..05b71f2f13 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_PINCTRL_SANDBOX) += pinctrl-sandbox.o obj-$(CONFIG_PINCTRL_UNIPHIER) += uniphier/ obj-$(CONFIG_PINCTRL_PIC32) += pinctrl_pic32.o obj-$(CONFIG_PINCTRL_EXYNOS) += exynos/ +obj-$(CONFIG_PINCTRL_K210) += pinctrl-kendryte.o obj-$(CONFIG_PINCTRL_MESON) += meson/ obj-$(CONFIG_PINCTRL_MTK) += mediatek/ obj-$(CONFIG_PINCTRL_MSCC) += mscc/ diff --git a/drivers/pinctrl/pinctrl-generic.c b/drivers/pinctrl/pinctrl-generic.c index 313aeccb1e..3c8e24088c 100644 --- a/drivers/pinctrl/pinctrl-generic.c +++ b/drivers/pinctrl/pinctrl-generic.c @@ -227,6 +227,13 @@ static int pinconf_enable_setting(struct udevice *dev, bool is_group, } #endif +enum pinmux_subnode_type { + PST_NONE = 0, + PST_PIN, + PST_GROUP, + PST_PINMUX, +}; + /** * pinctrl_generic_set_state_one() - set state for a certain pin/group * Apply all pin multiplexing and pin configurations specified by @config @@ -234,13 +241,15 @@ static int pinconf_enable_setting(struct udevice *dev, bool is_group, * * @dev: pin controller device * @config: pseudo device pointing to config node - * @is_group: target of operation (true: pin group, false: pin) - * @selector: pin selector or group selector, depending on @is_group + * @subnode_type: target of operation (pin, group, or pin specified by a pinmux + * group) + * @selector: pin selector or group selector, depending on @subnode_type * @return: 0 on success, or negative error code on failure */ static int pinctrl_generic_set_state_one(struct udevice *dev, struct udevice *config, - bool is_group, unsigned selector) + enum pinmux_subnode_type subnode_type, + unsigned selector) { const char *propname; const void *value; @@ -248,17 +257,22 @@ static int pinctrl_generic_set_state_one(struct udevice *dev, int len, func_selector, param, ret; u32 arg, default_val; + assert(subnode_type != PST_NONE); + dev_for_each_property(property, config) { value = dev_read_prop_by_prop(&property, &propname, &len); if (!value) return -EINVAL; - if (!strcmp(propname, "function")) { + /* pinmux subnodes already have their muxing set */ + if (subnode_type != PST_PINMUX && + !strcmp(propname, "function")) { func_selector = pinmux_func_name_to_selector(dev, value); if (func_selector < 0) return func_selector; - ret = pinmux_enable_setting(dev, is_group, + ret = pinmux_enable_setting(dev, + subnode_type == PST_GROUP, selector, func_selector); } else { @@ -272,7 +286,8 @@ static int pinctrl_generic_set_state_one(struct udevice *dev, else arg = default_val; - ret = pinconf_enable_setting(dev, is_group, + ret = pinconf_enable_setting(dev, + subnode_type == PST_GROUP, selector, param, arg); } @@ -284,6 +299,41 @@ static int pinctrl_generic_set_state_one(struct udevice *dev, } /** + * pinctrl_generic_get_subnode_type() - determine whether there is a valid + * pins, groups, or pinmux property in the config node + * + * @dev: pin controller device + * @config: pseudo device pointing to config node + * @count: number of specifiers contained within the property + * @return: the type of the subnode, or PST_NONE + */ +static enum pinmux_subnode_type pinctrl_generic_get_subnode_type(struct udevice *dev, + struct udevice *config, + int *count) +{ + const struct pinctrl_ops *ops = pinctrl_get_ops(dev); + + *count = dev_read_string_count(config, "pins"); + if (*count >= 0) + return PST_PIN; + + *count = dev_read_string_count(config, "groups"); + if (*count >= 0) + return PST_GROUP; + + if (ops->pinmux_property_set) { + *count = dev_read_size(config, "pinmux"); + if (*count >= 0 && !(*count % sizeof(u32))) { + *count /= sizeof(u32); + return PST_PINMUX; + } + } + + *count = 0; + return PST_NONE; +} + +/** * pinctrl_generic_set_state_subnode() - apply all settings in config node * * @dev: pin controller device @@ -293,38 +343,55 @@ static int pinctrl_generic_set_state_one(struct udevice *dev, static int pinctrl_generic_set_state_subnode(struct udevice *dev, struct udevice *config) { - const char *subnode_target_type = "pins"; - bool is_group = false; + enum pinmux_subnode_type subnode_type; const char *name; - int strings_count, selector, i, ret; - - strings_count = dev_read_string_count(config, subnode_target_type); - if (strings_count < 0) { - subnode_target_type = "groups"; - is_group = true; - strings_count = dev_read_string_count(config, - subnode_target_type); - if (strings_count < 0) { + int count, selector, i, ret, scratch; + const u32 *pinmux_groups = NULL; /* prevent use-uninitialized warning */ + + subnode_type = pinctrl_generic_get_subnode_type(dev, config, &count); + + debug("%s(%s, %s): count=%d\n", __func__, dev->name, config->name, + count); + + if (subnode_type == PST_PINMUX) { + pinmux_groups = dev_read_prop(config, "pinmux", &scratch); + if (!pinmux_groups) + return -EINVAL; + } + + for (i = 0; i < count; i++) { + switch (subnode_type) { + case PST_PIN: + ret = dev_read_string_index(config, "pins", i, &name); + if (ret) + return ret; + selector = pinctrl_pin_name_to_selector(dev, name); + break; + case PST_GROUP: + ret = dev_read_string_index(config, "groups", i, &name); + if (ret) + return ret; + selector = pinctrl_group_name_to_selector(dev, name); + break; + case PST_PINMUX: { + const struct pinctrl_ops *ops = pinctrl_get_ops(dev); + u32 pinmux_group = fdt32_to_cpu(pinmux_groups[i]); + + /* Checked for in pinctrl_generic_get_subnode_type */ + selector = ops->pinmux_property_set(dev, pinmux_group); + break; + } + case PST_NONE: + default: /* skip this node; may contain config child nodes */ return 0; } - } - - for (i = 0; i < strings_count; i++) { - ret = dev_read_string_index(config, subnode_target_type, i, - &name); - if (ret) - return ret; - if (is_group) - selector = pinctrl_group_name_to_selector(dev, name); - else - selector = pinctrl_pin_name_to_selector(dev, name); if (selector < 0) return selector; - ret = pinctrl_generic_set_state_one(dev, config, - is_group, selector); + ret = pinctrl_generic_set_state_one(dev, config, subnode_type, + selector); if (ret) return ret; } diff --git a/drivers/pinctrl/pinctrl-kendryte.c b/drivers/pinctrl/pinctrl-kendryte.c new file mode 100644 index 0000000000..5ad049d955 --- /dev/null +++ b/drivers/pinctrl/pinctrl-kendryte.c @@ -0,0 +1,737 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2020 Sean Anderson <seanga2@gmail.com> + */ + +#include <common.h> +#include <clk.h> +#include <dm.h> +#include <dm/pinctrl.h> +#include <dt-bindings/pinctrl/k210-pinctrl.h> +#include <mapmem.h> +#include <regmap.h> +#include <syscon.h> +#include <asm/io.h> +#include <linux/err.h> +#include <linux/bitfield.h> +#include <linux/bitops.h> + +/* + * The K210 only implements 8 drive levels, even though there is register space + * for 16 + */ +#define K210_PC_DRIVE_MASK GENMASK(11, 8) +#define K210_PC_DRIVE_SHIFT 8 +#define K210_PC_DRIVE_0 (0 << K210_PC_DRIVE_SHIFT) +#define K210_PC_DRIVE_1 (1 << K210_PC_DRIVE_SHIFT) +#define K210_PC_DRIVE_2 (2 << K210_PC_DRIVE_SHIFT) +#define K210_PC_DRIVE_3 (3 << K210_PC_DRIVE_SHIFT) +#define K210_PC_DRIVE_4 (4 << K210_PC_DRIVE_SHIFT) +#define K210_PC_DRIVE_5 (5 << K210_PC_DRIVE_SHIFT) +#define K210_PC_DRIVE_6 (6 << K210_PC_DRIVE_SHIFT) +#define K210_PC_DRIVE_7 (7 << K210_PC_DRIVE_SHIFT) +#define K210_PC_DRIVE_MAX 7 + +#define K210_PC_MODE_MASK GENMASK(23, 12) +/* + * output enabled == PC_OE & (PC_OE_INV ^ FUNCTION_OE) where FUNCTION_OE is a + * physical signal from the function + */ +#define K210_PC_OE BIT(12) /* Output Enable */ +#define K210_PC_OE_INV BIT(13) /* INVert function-controlled Output Enable */ +#define K210_PC_DO_OE BIT(14) /* set Data Out to the Output Enable signal */ +#define K210_PC_DO_INV BIT(15) /* INVert final Data Output */ +#define K210_PC_PU BIT(16) /* Pull Up */ +#define K210_PC_PD BIT(17) /* Pull Down */ +/* Strong pull up not implemented on K210 */ +#define K210_PC_SL BIT(19) /* reduce SLew rate to prevent overshoot */ +/* Same semantics as OE above */ +#define K210_PC_IE BIT(20) /* Input Enable */ +#define K210_PC_IE_INV BIT(21) /* INVert function-controlled Input Enable */ +#define K210_PC_DI_INV BIT(22) /* INVert Data Input */ +#define K210_PC_ST BIT(23) /* Schmitt Trigger */ +#define K210_PC_DI BIT(31) /* raw Data Input */ +#define K210_PC_BIAS_MASK (K210_PC_PU & K210_PC_PD) + +#define K210_PC_MODE_IN (K210_PC_IE | K210_PC_ST) +#define K210_PC_MODE_OUT (K210_PC_DRIVE_7 | K210_PC_OE) +#define K210_PC_MODE_I2C (K210_PC_MODE_IN | K210_PC_IE_INV | K210_PC_SL | \ + K210_PC_OE | K210_PC_OE_INV | K210_PC_PU) +#define K210_PC_MODE_SPI (K210_PC_MODE_IN | K210_PC_IE_INV | \ + K210_PC_MODE_OUT | K210_PC_OE_INV) +#define K210_PC_MODE_GPIO (K210_PC_MODE_IN | K210_PC_MODE_OUT) + +#define K210_PG_FUNC GENMASK(7, 0) +#define K210_PG_DO BIT(8) +#define K210_PG_PIN GENMASK(22, 16) + +#define PIN_CONFIG_OUTPUT_INVERT (PIN_CONFIG_END + 1) +#define PIN_CONFIG_INPUT_INVERT (PIN_CONFIG_END + 2) + +struct k210_fpioa { + u32 pins[48]; + u32 tie_en[8]; + u32 tie_val[8]; +}; + +struct k210_pc_priv { + struct clk clk; + struct k210_fpioa __iomem *fpioa; /* FPIOA register */ + struct regmap *sysctl; /* Sysctl regmap */ + u32 power_offset; /* Power bank register offset */ +}; + +#ifdef CONFIG_CMD_PINMUX +static const char k210_pc_pin_names[][6] = { +#define PIN(i) \ + [i] = "IO_" #i + PIN(0), + PIN(1), + PIN(2), + PIN(3), + PIN(4), + PIN(5), + PIN(6), + PIN(7), + PIN(8), + PIN(9), + PIN(10), + PIN(11), + PIN(12), + PIN(13), + PIN(14), + PIN(15), + PIN(16), + PIN(17), + PIN(18), + PIN(19), + PIN(20), + PIN(21), + PIN(22), + PIN(23), + PIN(24), + PIN(25), + PIN(26), + PIN(27), + PIN(28), + PIN(29), + PIN(30), + PIN(31), + PIN(32), + PIN(33), + PIN(34), + PIN(35), + PIN(36), + PIN(37), + PIN(38), + PIN(39), + PIN(40), + PIN(41), + PIN(42), + PIN(43), + PIN(44), + PIN(45), + PIN(46), + PIN(47), +#undef PIN +}; + +static int k210_pc_get_pins_count(struct udevice *dev) +{ + return ARRAY_SIZE(k210_pc_pin_names); +}; + +static const char *k210_pc_get_pin_name(struct udevice *dev, unsigned selector) +{ + return k210_pc_pin_names[selector]; +} +#endif /* CONFIG_CMD_PINMUX */ + +/* These are just power domains */ +static const char k210_pc_group_names[][3] = { + [0] = "A0", + [1] = "A1", + [2] = "A2", + [3] = "B0", + [4] = "B1", + [5] = "B2", + [6] = "C0", + [7] = "C1", +}; + +static int k210_pc_get_groups_count(struct udevice *dev) +{ + return ARRAY_SIZE(k210_pc_group_names); +} + +static const char *k210_pc_get_group_name(struct udevice *dev, + unsigned selector) +{ + return k210_pc_group_names[selector]; +} + +enum k210_pc_mode_id { + K210_PC_DEFAULT_DISABLED, + K210_PC_DEFAULT_IN, + K210_PC_DEFAULT_IN_TIE, + K210_PC_DEFAULT_OUT, + K210_PC_DEFAULT_I2C, + K210_PC_DEFAULT_SPI, + K210_PC_DEFAULT_GPIO, + K210_PC_DEFAULT_INT13, +}; + +static const u32 k210_pc_mode_id_to_mode[] = { +#define DEFAULT(mode) \ + [K210_PC_DEFAULT_##mode] = K210_PC_MODE_##mode + [K210_PC_DEFAULT_DISABLED] = 0, + DEFAULT(IN), + [K210_PC_DEFAULT_IN_TIE] = K210_PC_MODE_IN, + DEFAULT(OUT), + DEFAULT(I2C), + DEFAULT(SPI), + DEFAULT(GPIO), + [K210_PC_DEFAULT_INT13] = K210_PC_MODE_IN | K210_PC_PU, +#undef DEFAULT +}; + +/* This saves around 2K vs having a pointer+mode */ +struct k210_pcf_info { +#ifdef CONFIG_CMD_PINMUX + char name[15]; +#endif + u8 mode_id; +}; + +static const struct k210_pcf_info k210_pcf_infos[] = { +#ifdef CONFIG_CMD_PINMUX +#define FUNC(id, mode) \ + [K210_PCF_##id] = { \ + .name = #id, \ + .mode_id = K210_PC_DEFAULT_##mode \ + } +#else +#define FUNC(id, mode) \ + [K210_PCF_##id] = { \ + .mode_id = K210_PC_DEFAULT_##mode \ + } +#endif + FUNC(JTAG_TCLK, IN), + FUNC(JTAG_TDI, IN), + FUNC(JTAG_TMS, IN), + FUNC(JTAG_TDO, OUT), + FUNC(SPI0_D0, SPI), + FUNC(SPI0_D1, SPI), + FUNC(SPI0_D2, SPI), + FUNC(SPI0_D3, SPI), + FUNC(SPI0_D4, SPI), + FUNC(SPI0_D5, SPI), + FUNC(SPI0_D6, SPI), + FUNC(SPI0_D7, SPI), + FUNC(SPI0_SS0, OUT), + FUNC(SPI0_SS1, OUT), + FUNC(SPI0_SS2, OUT), + FUNC(SPI0_SS3, OUT), + FUNC(SPI0_ARB, IN_TIE), + FUNC(SPI0_SCLK, OUT), + FUNC(UARTHS_RX, IN), + FUNC(UARTHS_TX, OUT), + FUNC(RESV6, IN), + FUNC(RESV7, IN), + FUNC(CLK_SPI1, OUT), + FUNC(CLK_I2C1, OUT), + FUNC(GPIOHS0, GPIO), + FUNC(GPIOHS1, GPIO), + FUNC(GPIOHS2, GPIO), + FUNC(GPIOHS3, GPIO), + FUNC(GPIOHS4, GPIO), + FUNC(GPIOHS5, GPIO), + FUNC(GPIOHS6, GPIO), + FUNC(GPIOHS7, GPIO), + FUNC(GPIOHS8, GPIO), + FUNC(GPIOHS9, GPIO), + FUNC(GPIOHS10, GPIO), + FUNC(GPIOHS11, GPIO), + FUNC(GPIOHS12, GPIO), + FUNC(GPIOHS13, GPIO), + FUNC(GPIOHS14, GPIO), + FUNC(GPIOHS15, GPIO), + FUNC(GPIOHS16, GPIO), + FUNC(GPIOHS17, GPIO), + FUNC(GPIOHS18, GPIO), + FUNC(GPIOHS19, GPIO), + FUNC(GPIOHS20, GPIO), + FUNC(GPIOHS21, GPIO), + FUNC(GPIOHS22, GPIO), + FUNC(GPIOHS23, GPIO), + FUNC(GPIOHS24, GPIO), + FUNC(GPIOHS25, GPIO), + FUNC(GPIOHS26, GPIO), + FUNC(GPIOHS27, GPIO), + FUNC(GPIOHS28, GPIO), + FUNC(GPIOHS29, GPIO), + FUNC(GPIOHS30, GPIO), + FUNC(GPIOHS31, GPIO), + FUNC(GPIO0, GPIO), + FUNC(GPIO1, GPIO), + FUNC(GPIO2, GPIO), + FUNC(GPIO3, GPIO), + FUNC(GPIO4, GPIO), + FUNC(GPIO5, GPIO), + FUNC(GPIO6, GPIO), + FUNC(GPIO7, GPIO), + FUNC(UART1_RX, IN), + FUNC(UART1_TX, OUT), + FUNC(UART2_RX, IN), + FUNC(UART2_TX, OUT), + FUNC(UART3_RX, IN), + FUNC(UART3_TX, OUT), + FUNC(SPI1_D0, SPI), + FUNC(SPI1_D1, SPI), + FUNC(SPI1_D2, SPI), + FUNC(SPI1_D3, SPI), + FUNC(SPI1_D4, SPI), + FUNC(SPI1_D5, SPI), + FUNC(SPI1_D6, SPI), + FUNC(SPI1_D7, SPI), + FUNC(SPI1_SS0, OUT), + FUNC(SPI1_SS1, OUT), + FUNC(SPI1_SS2, OUT), + FUNC(SPI1_SS3, OUT), + FUNC(SPI1_ARB, IN_TIE), + FUNC(SPI1_SCLK, OUT), + FUNC(SPI2_D0, SPI), + FUNC(SPI2_SS, IN), + FUNC(SPI2_SCLK, IN), + FUNC(I2S0_MCLK, OUT), + FUNC(I2S0_SCLK, OUT), + FUNC(I2S0_WS, OUT), + FUNC(I2S0_IN_D0, IN), + FUNC(I2S0_IN_D1, IN), + FUNC(I2S0_IN_D2, IN), + FUNC(I2S0_IN_D3, IN), + FUNC(I2S0_OUT_D0, OUT), + FUNC(I2S0_OUT_D1, OUT), + FUNC(I2S0_OUT_D2, OUT), + FUNC(I2S0_OUT_D3, OUT), + FUNC(I2S1_MCLK, OUT), + FUNC(I2S1_SCLK, OUT), + FUNC(I2S1_WS, OUT), + FUNC(I2S1_IN_D0, IN), + FUNC(I2S1_IN_D1, IN), + FUNC(I2S1_IN_D2, IN), + FUNC(I2S1_IN_D3, IN), + FUNC(I2S1_OUT_D0, OUT), + FUNC(I2S1_OUT_D1, OUT), + FUNC(I2S1_OUT_D2, OUT), + FUNC(I2S1_OUT_D3, OUT), + FUNC(I2S2_MCLK, OUT), + FUNC(I2S2_SCLK, OUT), + FUNC(I2S2_WS, OUT), + FUNC(I2S2_IN_D0, IN), + FUNC(I2S2_IN_D1, IN), + FUNC(I2S2_IN_D2, IN), + FUNC(I2S2_IN_D3, IN), + FUNC(I2S2_OUT_D0, OUT), + FUNC(I2S2_OUT_D1, OUT), + FUNC(I2S2_OUT_D2, OUT), + FUNC(I2S2_OUT_D3, OUT), + FUNC(RESV0, DISABLED), + FUNC(RESV1, DISABLED), + FUNC(RESV2, DISABLED), + FUNC(RESV3, DISABLED), + FUNC(RESV4, DISABLED), + FUNC(RESV5, DISABLED), + FUNC(I2C0_SCLK, I2C), + FUNC(I2C0_SDA, I2C), + FUNC(I2C1_SCLK, I2C), + FUNC(I2C1_SDA, I2C), + FUNC(I2C2_SCLK, I2C), + FUNC(I2C2_SDA, I2C), + FUNC(DVP_XCLK, OUT), + FUNC(DVP_RST, OUT), + FUNC(DVP_PWDN, OUT), + FUNC(DVP_VSYNC, IN), + FUNC(DVP_HSYNC, IN), + FUNC(DVP_PCLK, IN), + FUNC(DVP_D0, IN), + FUNC(DVP_D1, IN), + FUNC(DVP_D2, IN), + FUNC(DVP_D3, IN), + FUNC(DVP_D4, IN), + FUNC(DVP_D5, IN), + FUNC(DVP_D6, IN), + FUNC(DVP_D7, IN), + FUNC(SCCB_SCLK, I2C), + FUNC(SCCB_SDA, I2C), + FUNC(UART1_CTS, IN), + FUNC(UART1_DSR, IN), + FUNC(UART1_DCD, IN), + FUNC(UART1_RI, IN), + FUNC(UART1_SIR_IN, IN), + FUNC(UART1_DTR, OUT), + FUNC(UART1_RTS, OUT), + FUNC(UART1_OUT2, OUT), + FUNC(UART1_OUT1, OUT), + FUNC(UART1_SIR_OUT, OUT), + FUNC(UART1_BAUD, OUT), + FUNC(UART1_RE, OUT), + FUNC(UART1_DE, OUT), + FUNC(UART1_RS485_EN, OUT), + FUNC(UART2_CTS, IN), + FUNC(UART2_DSR, IN), + FUNC(UART2_DCD, IN), + FUNC(UART2_RI, IN), + FUNC(UART2_SIR_IN, IN), + FUNC(UART2_DTR, OUT), + FUNC(UART2_RTS, OUT), + FUNC(UART2_OUT2, OUT), + FUNC(UART2_OUT1, OUT), + FUNC(UART2_SIR_OUT, OUT), + FUNC(UART2_BAUD, OUT), + FUNC(UART2_RE, OUT), + FUNC(UART2_DE, OUT), + FUNC(UART2_RS485_EN, OUT), + FUNC(UART3_CTS, IN), + FUNC(UART3_DSR, IN), + FUNC(UART3_DCD, IN), + FUNC(UART3_RI, IN), + FUNC(UART3_SIR_IN, IN), + FUNC(UART3_DTR, OUT), + FUNC(UART3_RTS, OUT), + FUNC(UART3_OUT2, OUT), + FUNC(UART3_OUT1, OUT), + FUNC(UART3_SIR_OUT, OUT), + FUNC(UART3_BAUD, OUT), + FUNC(UART3_RE, OUT), + FUNC(UART3_DE, OUT), + FUNC(UART3_RS485_EN, OUT), + FUNC(TIMER0_TOGGLE1, OUT), + FUNC(TIMER0_TOGGLE2, OUT), + FUNC(TIMER0_TOGGLE3, OUT), + FUNC(TIMER0_TOGGLE4, OUT), + FUNC(TIMER1_TOGGLE1, OUT), + FUNC(TIMER1_TOGGLE2, OUT), + FUNC(TIMER1_TOGGLE3, OUT), + FUNC(TIMER1_TOGGLE4, OUT), + FUNC(TIMER2_TOGGLE1, OUT), + FUNC(TIMER2_TOGGLE2, OUT), + FUNC(TIMER2_TOGGLE3, OUT), + FUNC(TIMER2_TOGGLE4, OUT), + FUNC(CLK_SPI2, OUT), + FUNC(CLK_I2C2, OUT), + FUNC(INTERNAL0, OUT), + FUNC(INTERNAL1, OUT), + FUNC(INTERNAL2, OUT), + FUNC(INTERNAL3, OUT), + FUNC(INTERNAL4, OUT), + FUNC(INTERNAL5, OUT), + FUNC(INTERNAL6, OUT), + FUNC(INTERNAL7, OUT), + FUNC(INTERNAL8, OUT), + FUNC(INTERNAL9, IN), + FUNC(INTERNAL10, IN), + FUNC(INTERNAL11, IN), + FUNC(INTERNAL12, IN), + FUNC(INTERNAL13, INT13), + FUNC(INTERNAL14, I2C), + FUNC(INTERNAL15, IN), + FUNC(INTERNAL16, IN), + FUNC(INTERNAL17, IN), + FUNC(CONSTANT, DISABLED), + FUNC(INTERNAL18, IN), + FUNC(DEBUG0, OUT), + FUNC(DEBUG1, OUT), + FUNC(DEBUG2, OUT), + FUNC(DEBUG3, OUT), + FUNC(DEBUG4, OUT), + FUNC(DEBUG5, OUT), + FUNC(DEBUG6, OUT), + FUNC(DEBUG7, OUT), + FUNC(DEBUG8, OUT), + FUNC(DEBUG9, OUT), + FUNC(DEBUG10, OUT), + FUNC(DEBUG11, OUT), + FUNC(DEBUG12, OUT), + FUNC(DEBUG13, OUT), + FUNC(DEBUG14, OUT), + FUNC(DEBUG15, OUT), + FUNC(DEBUG16, OUT), + FUNC(DEBUG17, OUT), + FUNC(DEBUG18, OUT), + FUNC(DEBUG19, OUT), + FUNC(DEBUG20, OUT), + FUNC(DEBUG21, OUT), + FUNC(DEBUG22, OUT), + FUNC(DEBUG23, OUT), + FUNC(DEBUG24, OUT), + FUNC(DEBUG25, OUT), + FUNC(DEBUG26, OUT), + FUNC(DEBUG27, OUT), + FUNC(DEBUG28, OUT), + FUNC(DEBUG29, OUT), + FUNC(DEBUG30, OUT), + FUNC(DEBUG31, OUT), +#undef FUNC +}; + +static int k210_pc_pinmux_set(struct udevice *dev, u32 pinmux_group) +{ + unsigned pin = FIELD_GET(K210_PG_PIN, pinmux_group); + bool do_oe = FIELD_GET(K210_PG_DO, pinmux_group); + unsigned func = FIELD_GET(K210_PG_FUNC, pinmux_group); + struct k210_pc_priv *priv = dev_get_priv(dev); + const struct k210_pcf_info *info = &k210_pcf_infos[func]; + u32 mode = k210_pc_mode_id_to_mode[info->mode_id]; + u32 val = func | mode | (do_oe ? K210_PC_DO_OE : 0); + + debug("%s(%.8x): IO_%.2u = %3u | %.8x\n", __func__, pinmux_group, pin, + func, mode); + + writel(val, &priv->fpioa->pins[pin]); + return pin; +} + +/* Max drive strength in uA */ +static const int k210_pc_drive_strength[] = { + [0] = 11200, + [1] = 16800, + [2] = 22300, + [3] = 27800, + [4] = 33300, + [5] = 38700, + [6] = 44100, + [7] = 49500, +}; + +static int k210_pc_get_drive(unsigned max_strength_ua) +{ + int i; + + for (i = K210_PC_DRIVE_MAX; i; i--) + if (k210_pc_drive_strength[i] < max_strength_ua) + return i; + + return -EINVAL; +} + +static int k210_pc_pinconf_set(struct udevice *dev, unsigned pin_selector, + unsigned param, unsigned argument) +{ + struct k210_pc_priv *priv = dev_get_priv(dev); + u32 val = readl(&priv->fpioa->pins[pin_selector]); + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + val &= ~K210_PC_BIAS_MASK; + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + if (argument) + val |= K210_PC_PD; + else + return -EINVAL; + break; + case PIN_CONFIG_BIAS_PULL_UP: + if (argument) + val |= K210_PC_PD; + else + return -EINVAL; + break; + case PIN_CONFIG_DRIVE_STRENGTH: + argument *= 1000; + case PIN_CONFIG_DRIVE_STRENGTH_UA: { + int drive = k210_pc_get_drive(argument); + + if (IS_ERR_VALUE(drive)) + return drive; + val &= ~K210_PC_DRIVE_MASK; + val |= FIELD_PREP(K210_PC_DRIVE_MASK, drive); + break; + } + case PIN_CONFIG_INPUT_ENABLE: + if (argument) + val |= K210_PC_IE; + else + val &= ~K210_PC_IE; + break; + case PIN_CONFIG_INPUT_SCHMITT: + argument = 1; + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + if (argument) + val |= K210_PC_ST; + else + val &= ~K210_PC_ST; + break; + case PIN_CONFIG_OUTPUT: + k210_pc_pinmux_set(dev, + K210_FPIOA(pin_selector, K210_PCF_CONSTANT)); + val = readl(&priv->fpioa->pins[pin_selector]); + val |= K210_PC_MODE_OUT; + + if (!argument) + val |= K210_PC_DO_INV; + break; + case PIN_CONFIG_OUTPUT_ENABLE: + if (argument) + val |= K210_PC_OE; + else + val &= ~K210_PC_OE; + break; + case PIN_CONFIG_SLEW_RATE: + if (argument) + val |= K210_PC_SL; + else + val &= ~K210_PC_SL; + break; + case PIN_CONFIG_OUTPUT_INVERT: + if (argument) + val |= K210_PC_DO_INV; + else + val &= ~K210_PC_DO_INV; + break; + case PIN_CONFIG_INPUT_INVERT: + if (argument) + val |= K210_PC_DI_INV; + else + val &= ~K210_PC_DI_INV; + break; + default: + return -EINVAL; + } + + writel(val, &priv->fpioa->pins[pin_selector]); + return 0; +} + +static int k210_pc_pinconf_group_set(struct udevice *dev, + unsigned group_selector, unsigned param, + unsigned argument) +{ + struct k210_pc_priv *priv = dev_get_priv(dev); + + if (param == PIN_CONFIG_POWER_SOURCE) { + u32 bit = BIT(group_selector); + + regmap_update_bits(priv->sysctl, priv->power_offset, bit, + argument ? bit : 0); + } else { + return -EINVAL; + } + + return 0; +} + +#ifdef CONFIG_CMD_PINMUX +static int k210_pc_get_pin_muxing(struct udevice *dev, unsigned int selector, + char *buf, int size) +{ + struct k210_pc_priv *priv = dev_get_priv(dev); + u32 val = readl(&priv->fpioa->pins[selector]); + const struct k210_pcf_info *info = &k210_pcf_infos[val & K210_PCF_MASK]; + + strncpy(buf, info->name, min((size_t)size, sizeof(info->name))); + return 0; +} +#endif + +static const struct pinconf_param k210_pc_pinconf_params[] = { + { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 }, + { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 }, + { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 }, + { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, U32_MAX }, + { "drive-strength-ua", PIN_CONFIG_DRIVE_STRENGTH_UA, U32_MAX }, + { "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 }, + { "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 }, + { "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 }, + { "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 }, + { "power-source", PIN_CONFIG_POWER_SOURCE, K210_PC_POWER_1V8 }, + { "output-low", PIN_CONFIG_OUTPUT, 0 }, + { "output-high", PIN_CONFIG_OUTPUT, 1 }, + { "output-enable", PIN_CONFIG_OUTPUT_ENABLE, 1 }, + { "output-disable", PIN_CONFIG_OUTPUT_ENABLE, 0 }, + { "slew-rate", PIN_CONFIG_SLEW_RATE, 1 }, + { "output-polarity-invert", PIN_CONFIG_OUTPUT_INVERT, 1}, + { "input-polarity-invert", PIN_CONFIG_INPUT_INVERT, 1}, +}; + +static const struct pinctrl_ops k210_pc_pinctrl_ops = { +#ifdef CONFIG_CMD_PINMUX + .get_pins_count = k210_pc_get_pins_count, + .get_pin_name = k210_pc_get_pin_name, +#endif + .get_groups_count = k210_pc_get_groups_count, + .get_group_name = k210_pc_get_group_name, + .pinmux_property_set = k210_pc_pinmux_set, + .pinconf_num_params = ARRAY_SIZE(k210_pc_pinconf_params), + .pinconf_params = k210_pc_pinconf_params, + .pinconf_set = k210_pc_pinconf_set, + .pinconf_group_set = k210_pc_pinconf_group_set, + .set_state = pinctrl_generic_set_state, +#ifdef CONFIG_CMD_PINMUX + .get_pin_muxing = k210_pc_get_pin_muxing, +#endif +}; + +static int k210_pc_probe(struct udevice *dev) +{ + int ret, i, j; + struct k210_pc_priv *priv = dev_get_priv(dev); + + priv->fpioa = dev_read_addr_ptr(dev); + if (!priv->fpioa) + return -EINVAL; + + ret = clk_get_by_index(dev, 0, &priv->clk); + if (ret) + return ret; + + ret = clk_enable(&priv->clk); + if (ret && ret != -ENOSYS && ret != -ENOTSUPP) + goto err; + + priv->sysctl = syscon_regmap_lookup_by_phandle(dev, "kendryte,sysctl"); + if (IS_ERR(priv->sysctl)) { + ret = -ENODEV; + goto err; + } + + ret = dev_read_u32(dev, "kendryte,power-offset", &priv->power_offset); + if (ret) + goto err; + + debug("%s: fpioa = %p sysctl = %p power offset = %x\n", __func__, + priv->fpioa, (void *)priv->sysctl->ranges[0].start, + priv->power_offset); + + /* Init input ties */ + for (i = 0; i < ARRAY_SIZE(priv->fpioa->tie_en); i++) { + u32 val = 0; + + for (j = 0; j < 32; j++) + if (k210_pcf_infos[i * 32 + j].mode_id == + K210_PC_DEFAULT_IN_TIE) + val |= BIT(j); + writel(val, &priv->fpioa->tie_en[i]); + writel(val, &priv->fpioa->tie_val[i]); + } + + return 0; + +err: + clk_free(&priv->clk); + return ret; +} + +static const struct udevice_id k210_pc_ids[] = { + { .compatible = "kendryte,k210-fpioa" }, + { } +}; + +U_BOOT_DRIVER(pinctrl_k210) = { + .name = "pinctrl_k210", + .id = UCLASS_PINCTRL, + .of_match = k210_pc_ids, + .probe = k210_pc_probe, + .priv_auto_alloc_size = sizeof(struct k210_pc_priv), + .ops = &k210_pc_pinctrl_ops, +}; diff --git a/drivers/pinctrl/pinctrl-sandbox.c b/drivers/pinctrl/pinctrl-sandbox.c index ac0119d198..d27f74248d 100644 --- a/drivers/pinctrl/pinctrl-sandbox.c +++ b/drivers/pinctrl/pinctrl-sandbox.c @@ -1,57 +1,70 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com> + * Copyright (C) 2020 Sean Anderson <seanga2@gmail.com> + * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com> */ -/* #define DEBUG */ - #include <common.h> #include <dm.h> -#include <log.h> #include <dm/pinctrl.h> +#include <dt-bindings/pinctrl/sandbox-pinmux.h> +#include <log.h> #include <linux/bitops.h> +/* + * This driver emulates a pin controller with the following rules: + * - The pinctrl config for each pin must be set individually + * - The first three pins (P0-P2) must be muxed as a group + * - The next two pins (P3-P4) must be muxed as a group + * - The last four pins (P5-P8) must be muxed individually + */ + static const char * const sandbox_pins[] = { - "SCL", - "SDA", - "TX", - "RX", - "W1", - "GPIO0", - "GPIO1", - "GPIO2", - "GPIO3", +#define PIN(x) \ + [x] = "P" #x + PIN(0), + PIN(1), + PIN(2), + PIN(3), + PIN(4), + PIN(5), + PIN(6), + PIN(7), + PIN(8), +#undef PIN }; -static const char * const sandbox_pins_muxing[] = { - "I2C SCL", - "I2C SDA", - "Uart TX", - "Uart RX", - "1-wire gpio", - "gpio", - "gpio", - "gpio", - "gpio", +static const char * const sandbox_pins_muxing[][2] = { + { "UART TX", "I2C SCL" }, + { "UART RX", "I2C SDA" }, + { "SPI SCLK", "I2S SCK" }, + { "SPI MOSI", "I2S SD" }, + { "SPI MISO", "I2S WS" }, + { "GPIO0", "SPI CS0" }, + { "GPIO1", "SPI CS1" }, + { "GPIO2", "PWM0" }, + { "GPIO3", "PWM1" }, }; +#define SANDBOX_GROUP_I2C_UART 0 +#define SANDBOX_GROUP_SPI_I2S 1 + static const char * const sandbox_groups[] = { - "i2c", - "serial_a", - "serial_b", - "spi", - "w1", + [SANDBOX_GROUP_I2C_UART] = "I2C_UART", + [SANDBOX_GROUP_SPI_I2S] = "SPI_I2S", }; static const char * const sandbox_functions[] = { - "i2c", - "serial", - "spi", - "w1", - "gpio", - "gpio", - "gpio", - "gpio", +#define FUNC(id) \ + [SANDBOX_PINMUX_##id] = #id + FUNC(UART), + FUNC(I2C), + FUNC(SPI), + FUNC(I2S), + FUNC(GPIO), + FUNC(CS), + FUNC(PWM), +#undef FUNC }; static const struct pinconf_param sandbox_conf_params[] = { @@ -68,9 +81,12 @@ static const struct pinconf_param sandbox_conf_params[] = { { "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 }, }; -/* bitfield used to save param and value of each pin/selector */ -static unsigned int sandbox_pins_param[ARRAY_SIZE(sandbox_pins)]; -static unsigned int sandbox_pins_value[ARRAY_SIZE(sandbox_pins)]; +/* Bitfield used to save param and value of each pin/selector */ +struct sandbox_pinctrl_priv { + unsigned int mux; + unsigned int pins_param[ARRAY_SIZE(sandbox_pins)]; + unsigned int pins_value[ARRAY_SIZE(sandbox_pins)]; +}; static int sandbox_get_pins_count(struct udevice *dev) { @@ -87,16 +103,18 @@ static int sandbox_get_pin_muxing(struct udevice *dev, char *buf, int size) { const struct pinconf_param *p; + struct sandbox_pinctrl_priv *priv = dev_get_priv(dev); int i; - snprintf(buf, size, "%s", sandbox_pins_muxing[selector]); + snprintf(buf, size, "%s", + sandbox_pins_muxing[selector][!!(priv->mux & BIT(selector))]); - if (sandbox_pins_param[selector]) { + if (priv->pins_param[selector]) { for (i = 0, p = sandbox_conf_params; i < ARRAY_SIZE(sandbox_conf_params); i++, p++) { - if ((sandbox_pins_param[selector] & BIT(p->param)) && - (!!(sandbox_pins_value[selector] & BIT(p->param)) == + if ((priv->pins_param[selector] & BIT(p->param)) && + (!!(priv->pins_value[selector] & BIT(p->param)) == p->default_value)) { strncat(buf, " ", size); strncat(buf, p->property, size); @@ -133,12 +151,32 @@ static const char *sandbox_get_function_name(struct udevice *dev, static int sandbox_pinmux_set(struct udevice *dev, unsigned pin_selector, unsigned func_selector) { + int mux; + struct sandbox_pinctrl_priv *priv = dev_get_priv(dev); + debug("sandbox pinmux: pin = %d (%s), function = %d (%s)\n", pin_selector, sandbox_get_pin_name(dev, pin_selector), func_selector, sandbox_get_function_name(dev, func_selector)); - sandbox_pins_param[pin_selector] = 0; - sandbox_pins_value[pin_selector] = 0; + if (pin_selector < 5) + return -EINVAL; + + switch (func_selector) { + case SANDBOX_PINMUX_GPIO: + mux = 0; + break; + case SANDBOX_PINMUX_CS: + case SANDBOX_PINMUX_PWM: + mux = BIT(pin_selector); + break; + default: + return -EINVAL; + } + + priv->mux &= ~BIT(pin_selector); + priv->mux |= mux; + priv->pins_param[pin_selector] = 0; + priv->pins_value[pin_selector] = 0; return 0; } @@ -147,25 +185,75 @@ static int sandbox_pinmux_group_set(struct udevice *dev, unsigned group_selector, unsigned func_selector) { + bool mux; + int i, group_start, group_end; + struct sandbox_pinctrl_priv *priv = dev_get_priv(dev); + unsigned int mask; + debug("sandbox pinmux: group = %d (%s), function = %d (%s)\n", group_selector, sandbox_get_group_name(dev, group_selector), func_selector, sandbox_get_function_name(dev, func_selector)); + if (group_selector == SANDBOX_GROUP_I2C_UART) { + group_start = 0; + group_end = 1; + + if (func_selector == SANDBOX_PINMUX_UART) + mux = false; + else if (func_selector == SANDBOX_PINMUX_I2C) + mux = true; + else + return -EINVAL; + } else if (group_selector == SANDBOX_GROUP_SPI_I2S) { + group_start = 2; + group_end = 4; + + if (func_selector == SANDBOX_PINMUX_SPI) + mux = false; + else if (func_selector == SANDBOX_PINMUX_I2S) + mux = true; + else + return -EINVAL; + } else { + return -EINVAL; + } + + mask = GENMASK(group_end, group_start); + priv->mux &= ~mask; + priv->mux |= mux ? mask : 0; + + for (i = group_start; i < group_end; i++) { + priv->pins_param[i] = 0; + priv->pins_value[i] = 0; + } + return 0; } +static int sandbox_pinmux_property_set(struct udevice *dev, u32 pinmux_group) +{ + int ret; + unsigned pin_selector = pinmux_group & 0xFFFF; + unsigned func_selector = pinmux_group >> 16; + + ret = sandbox_pinmux_set(dev, pin_selector, func_selector); + return ret ? ret : pin_selector; +} + static int sandbox_pinconf_set(struct udevice *dev, unsigned pin_selector, unsigned param, unsigned argument) { + struct sandbox_pinctrl_priv *priv = dev_get_priv(dev); + debug("sandbox pinconf: pin = %d (%s), param = %d, arg = %d\n", pin_selector, sandbox_get_pin_name(dev, pin_selector), param, argument); - sandbox_pins_param[pin_selector] |= BIT(param); + priv->pins_param[pin_selector] |= BIT(param); if (argument) - sandbox_pins_value[pin_selector] |= BIT(param); + priv->pins_value[pin_selector] |= BIT(param); else - sandbox_pins_value[pin_selector] &= ~BIT(param); + priv->pins_value[pin_selector] &= ~BIT(param); return 0; } @@ -191,6 +279,7 @@ const struct pinctrl_ops sandbox_pinctrl_ops = { .get_function_name = sandbox_get_function_name, .pinmux_set = sandbox_pinmux_set, .pinmux_group_set = sandbox_pinmux_group_set, + .pinmux_property_set = sandbox_pinmux_property_set, .pinconf_num_params = ARRAY_SIZE(sandbox_conf_params), .pinconf_params = sandbox_conf_params, .pinconf_set = sandbox_pinconf_set, @@ -207,5 +296,6 @@ U_BOOT_DRIVER(sandbox_pinctrl) = { .name = "sandbox_pinctrl", .id = UCLASS_PINCTRL, .of_match = sandbox_pinctrl_match, + .priv_auto_alloc_size = sizeof(struct sandbox_pinctrl_priv), .ops = &sandbox_pinctrl_ops, }; diff --git a/drivers/ram/Kconfig b/drivers/ram/Kconfig index a0e859afd6..a270e13b26 100644 --- a/drivers/ram/Kconfig +++ b/drivers/ram/Kconfig @@ -73,6 +73,7 @@ config IMXRT_SDRAM to support external memories like sdram, psram & nand. This driver is for the sdram memory interface with the SEMC. +source "drivers/ram/aspeed/Kconfig" source "drivers/ram/rockchip/Kconfig" source "drivers/ram/sifive/Kconfig" source "drivers/ram/stm32mp1/Kconfig" diff --git a/drivers/ram/Makefile b/drivers/ram/Makefile index d685a579a0..209a78c06f 100644 --- a/drivers/ram/Makefile +++ b/drivers/ram/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ obj-$(CONFIG_K3_AM654_DDRSS) += k3-am654-ddrss.o obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/ +obj-$(CONFIG_ARCH_ASPEED) += aspeed/ obj-$(CONFIG_K3_J721E_DDRSS) += k3-j721e/ obj-$(CONFIG_IMXRT_SDRAM) += imxrt_sdram.o diff --git a/drivers/ram/aspeed/Kconfig b/drivers/ram/aspeed/Kconfig new file mode 100644 index 0000000000..020c913188 --- /dev/null +++ b/drivers/ram/aspeed/Kconfig @@ -0,0 +1,10 @@ +if RAM || SPL_RAM +config ASPEED_DDR4_DUALX8 + bool "Enable Dual X8 DDR4 die" + depends on DM && OF_CONTROL && ARCH_ASPEED + default n + help + Say Y if dual X8 DDR4 die is used on the board. The aspeed ddr sdram + controller needs to know if the memory chip mounted on the board is dual + x8 die or not. Or it may get the wrong size of the memory space. +endif diff --git a/drivers/ram/aspeed/Makefile b/drivers/ram/aspeed/Makefile new file mode 100644 index 0000000000..af604f8a4b --- /dev/null +++ b/drivers/ram/aspeed/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +obj-$(CONFIG_ASPEED_AST2500) += sdram_ast2500.o
\ No newline at end of file diff --git a/drivers/ram/aspeed/sdram_ast2500.c b/drivers/ram/aspeed/sdram_ast2500.c new file mode 100644 index 0000000000..9f4304cb66 --- /dev/null +++ b/drivers/ram/aspeed/sdram_ast2500.c @@ -0,0 +1,439 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2012-2020 ASPEED Technology Inc. + * + * Copyright 2016 Google, Inc + */ + +#include <common.h> +#include <clk.h> +#include <dm.h> +#include <errno.h> +#include <log.h> +#include <ram.h> +#include <regmap.h> +#include <reset.h> +#include <asm/io.h> +#include <asm/arch/scu_ast2500.h> +#include <asm/arch/sdram_ast2500.h> +#include <asm/arch/wdt.h> +#include <linux/err.h> +#include <linux/kernel.h> +#include <dt-bindings/clock/aspeed-clock.h> + +/* These configuration parameters are taken from Aspeed SDK */ +#define DDR4_MR46_MODE 0x08000000 +#define DDR4_MR5_MODE 0x400 +#define DDR4_MR13_MODE 0x101 +#define DDR4_MR02_MODE 0x410 +#define DDR4_TRFC 0x45457188 + +#define PHY_CFG_SIZE 15 + +static const u32 ddr4_ac_timing[3] = {0x63604e37, 0xe97afa99, 0x00019000}; +static const struct { + u32 index[PHY_CFG_SIZE]; + u32 value[PHY_CFG_SIZE]; +} ddr4_phy_config = { + .index = {0, 1, 3, 4, 5, 56, 57, 58, 59, 60, 61, 62, 36, 49, 50}, + .value = { + 0x42492aae, 0x09002000, 0x55e00b0b, 0x20000000, 0x24, + 0x03002900, 0x0e0000a0, 0x000e001c, 0x35b8c106, 0x08080607, + 0x9b000900, 0x0e400a00, 0x00100008, 0x3c183c3c, 0x00631e0e, + }, +}; + +#define SDRAM_MAX_SIZE (1024 * 1024 * 1024) +#define SDRAM_MIN_SIZE (128 * 1024 * 1024) + +DECLARE_GLOBAL_DATA_PTR; + +/* + * Bandwidth configuration parameters for different SDRAM requests. + * These are hardcoded settings taken from Aspeed SDK. + */ +static const u32 ddr_max_grant_params[4] = { + 0x88448844, 0x24422288, 0x22222222, 0x22222222 +}; + +/* + * These registers are not documented by Aspeed at all. + * All writes and reads are taken pretty much as is from SDK. + */ +struct ast2500_ddr_phy { + u32 phy[117]; +}; + +struct dram_info { + struct ram_info info; + struct clk ddr_clk; + struct ast2500_sdrammc_regs *regs; + struct ast2500_scu *scu; + struct ast2500_ddr_phy *phy; + ulong clock_rate; +}; + +static int ast2500_sdrammc_init_phy(struct ast2500_ddr_phy *phy) +{ + writel(0, &phy->phy[2]); + writel(0, &phy->phy[6]); + writel(0, &phy->phy[8]); + writel(0, &phy->phy[10]); + writel(0, &phy->phy[12]); + writel(0, &phy->phy[42]); + writel(0, &phy->phy[44]); + + writel(0x86000000, &phy->phy[16]); + writel(0x00008600, &phy->phy[17]); + writel(0x80000000, &phy->phy[18]); + writel(0x80808080, &phy->phy[19]); + + return 0; +} + +static void ast2500_ddr_phy_init_process(struct dram_info *info) +{ + struct ast2500_sdrammc_regs *regs = info->regs; + + writel(0, ®s->phy_ctrl[0]); + writel(0x4040, &info->phy->phy[51]); + + writel(SDRAM_PHYCTRL0_NRST | SDRAM_PHYCTRL0_INIT, ®s->phy_ctrl[0]); + while ((readl(®s->phy_ctrl[0]) & SDRAM_PHYCTRL0_INIT)) + ; + writel(SDRAM_PHYCTRL0_NRST | SDRAM_PHYCTRL0_AUTO_UPDATE, + ®s->phy_ctrl[0]); +} + +static void ast2500_sdrammc_set_vref(struct dram_info *info, u32 vref) +{ + writel(0, &info->regs->phy_ctrl[0]); + writel((vref << 8) | 0x6, &info->phy->phy[48]); + ast2500_ddr_phy_init_process(info); +} + +static int ast2500_ddr_cbr_test(struct dram_info *info) +{ + struct ast2500_sdrammc_regs *regs = info->regs; + int i; + const u32 test_params = SDRAM_TEST_EN + | SDRAM_TEST_ERRSTOP + | SDRAM_TEST_TWO_MODES; + int ret = 0; + + writel((1 << SDRAM_REFRESH_CYCLES_SHIFT) | + (0x5c << SDRAM_REFRESH_PERIOD_SHIFT), ®s->refresh_timing); + writel((0xfff << SDRAM_TEST_LEN_SHIFT), ®s->test_addr); + writel(0xff00ff00, ®s->test_init_val); + writel(SDRAM_TEST_EN | (SDRAM_TEST_MODE_RW << SDRAM_TEST_MODE_SHIFT) | + SDRAM_TEST_ERRSTOP, ®s->ecc_test_ctrl); + + while (!(readl(®s->ecc_test_ctrl) & SDRAM_TEST_DONE)) + ; + + if (readl(®s->ecc_test_ctrl) & SDRAM_TEST_FAIL) { + ret = -EIO; + } else { + for (i = 0; i <= SDRAM_TEST_GEN_MODE_MASK; ++i) { + writel((i << SDRAM_TEST_GEN_MODE_SHIFT) | test_params, + ®s->ecc_test_ctrl); + while (!(readl(®s->ecc_test_ctrl) & SDRAM_TEST_DONE)) + ; + if (readl(®s->ecc_test_ctrl) & SDRAM_TEST_FAIL) { + ret = -EIO; + break; + } + } + } + + writel(0, ®s->refresh_timing); + writel(0, ®s->ecc_test_ctrl); + + return ret; +} + +static int ast2500_sdrammc_ddr4_calibrate_vref(struct dram_info *info) +{ + int i; + int vref_min = 0xff; + int vref_max = 0; + int range_size = 0; + + for (i = 1; i < 0x40; ++i) { + int res; + + ast2500_sdrammc_set_vref(info, i); + res = ast2500_ddr_cbr_test(info); + if (res < 0) { + if (range_size > 0) + break; + } else { + ++range_size; + vref_min = min(vref_min, i); + vref_max = max(vref_max, i); + } + } + + /* Pick average setting */ + ast2500_sdrammc_set_vref(info, (vref_min + vref_max + 1) / 2); + + return 0; +} + +static size_t ast2500_sdrammc_get_vga_mem_size(struct dram_info *info) +{ + size_t vga_mem_size_base = 8 * 1024 * 1024; + u32 vga_hwconf = (readl(&info->scu->hwstrap) & SCU_HWSTRAP_VGAMEM_MASK) + >> SCU_HWSTRAP_VGAMEM_SHIFT; + + return vga_mem_size_base << vga_hwconf; +} + +/* + * Find out RAM size and save it in dram_info + * + * The procedure is taken from Aspeed SDK + */ +static void ast2500_sdrammc_calc_size(struct dram_info *info) +{ + /* The controller supports 128/256/512/1024 MB ram */ + size_t ram_size = SDRAM_MIN_SIZE; + const int write_test_offset = 0x100000; + u32 test_pattern = 0xdeadbeef; + u32 cap_param = SDRAM_CONF_CAP_1024M; + u32 refresh_timing_param = DDR4_TRFC; + const u32 write_addr_base = CONFIG_SYS_SDRAM_BASE + write_test_offset; + + for (ram_size = SDRAM_MAX_SIZE; ram_size > SDRAM_MIN_SIZE; + ram_size >>= 1) { + writel(test_pattern, write_addr_base + (ram_size >> 1)); + test_pattern = (test_pattern >> 4) | (test_pattern << 28); + } + + /* One last write to overwrite all wrapped values */ + writel(test_pattern, write_addr_base); + + /* Reset the pattern and see which value was really written */ + test_pattern = 0xdeadbeef; + for (ram_size = SDRAM_MAX_SIZE; ram_size > SDRAM_MIN_SIZE; + ram_size >>= 1) { + if (readl(write_addr_base + (ram_size >> 1)) == test_pattern) + break; + + --cap_param; + refresh_timing_param >>= 8; + test_pattern = (test_pattern >> 4) | (test_pattern << 28); + } + + clrsetbits_le32(&info->regs->ac_timing[1], + (SDRAM_AC_TRFC_MASK << SDRAM_AC_TRFC_SHIFT), + ((refresh_timing_param & SDRAM_AC_TRFC_MASK) + << SDRAM_AC_TRFC_SHIFT)); + + info->info.base = CONFIG_SYS_SDRAM_BASE; + info->info.size = ram_size - ast2500_sdrammc_get_vga_mem_size(info); + clrsetbits_le32(&info->regs->config, + (SDRAM_CONF_CAP_MASK << SDRAM_CONF_CAP_SHIFT), + ((cap_param & SDRAM_CONF_CAP_MASK) + << SDRAM_CONF_CAP_SHIFT)); +} + +static int ast2500_sdrammc_init_ddr4(struct dram_info *info) +{ + int i; + const u32 power_control = SDRAM_PCR_CKE_EN + | (1 << SDRAM_PCR_CKE_DELAY_SHIFT) + | (2 << SDRAM_PCR_TCKE_PW_SHIFT) + | SDRAM_PCR_RESETN_DIS + | SDRAM_PCR_RGAP_CTRL_EN | SDRAM_PCR_ODT_EN | SDRAM_PCR_ODT_EXT_EN; + const u32 conf = (SDRAM_CONF_CAP_1024M << SDRAM_CONF_CAP_SHIFT) +#ifdef CONFIG_ASPEED_DDR4_DUALX8 + | SDRAM_CONF_DUALX8 +#endif + | SDRAM_CONF_SCRAMBLE | SDRAM_CONF_SCRAMBLE_PAT2 | SDRAM_CONF_DDR4; + int ret; + + writel(conf, &info->regs->config); + for (i = 0; i < ARRAY_SIZE(ddr4_ac_timing); ++i) + writel(ddr4_ac_timing[i], &info->regs->ac_timing[i]); + + writel(DDR4_MR46_MODE, &info->regs->mr46_mode_setting); + writel(DDR4_MR5_MODE, &info->regs->mr5_mode_setting); + writel(DDR4_MR02_MODE, &info->regs->mr02_mode_setting); + writel(DDR4_MR13_MODE, &info->regs->mr13_mode_setting); + + for (i = 0; i < PHY_CFG_SIZE; ++i) { + writel(ddr4_phy_config.value[i], + &info->phy->phy[ddr4_phy_config.index[i]]); + } + + writel(power_control, &info->regs->power_control); + + ast2500_ddr_phy_init_process(info); + + ret = ast2500_sdrammc_ddr4_calibrate_vref(info); + if (ret < 0) { + debug("Vref calibration failed!\n"); + return ret; + } + + writel((1 << SDRAM_REFRESH_CYCLES_SHIFT) + | SDRAM_REFRESH_ZQCS_EN | (0x2f << SDRAM_REFRESH_PERIOD_SHIFT), + &info->regs->refresh_timing); + + setbits_le32(&info->regs->power_control, + SDRAM_PCR_AUTOPWRDN_EN | SDRAM_PCR_ODT_AUTO_ON); + + ast2500_sdrammc_calc_size(info); + + setbits_le32(&info->regs->config, SDRAM_CONF_CACHE_INIT_EN); + while (!(readl(&info->regs->config) & SDRAM_CONF_CACHE_INIT_DONE)) + ; + setbits_le32(&info->regs->config, SDRAM_CONF_CACHE_EN); + + writel(SDRAM_MISC_DDR4_TREFRESH, &info->regs->misc_control); + + /* Enable all requests except video & display */ + writel(SDRAM_REQ_USB20_EHCI1 + | SDRAM_REQ_USB20_EHCI2 + | SDRAM_REQ_CPU + | SDRAM_REQ_AHB2 + | SDRAM_REQ_AHB + | SDRAM_REQ_MAC0 + | SDRAM_REQ_MAC1 + | SDRAM_REQ_PCIE + | SDRAM_REQ_XDMA + | SDRAM_REQ_ENCRYPTION + | SDRAM_REQ_VIDEO_FLAG + | SDRAM_REQ_VIDEO_LOW_PRI_WRITE + | SDRAM_REQ_2D_RW + | SDRAM_REQ_MEMCHECK, &info->regs->req_limit_mask); + + return 0; +} + +static void ast2500_sdrammc_unlock(struct dram_info *info) +{ + writel(SDRAM_UNLOCK_KEY, &info->regs->protection_key); + while (!readl(&info->regs->protection_key)) + ; +} + +static void ast2500_sdrammc_lock(struct dram_info *info) +{ + writel(~SDRAM_UNLOCK_KEY, &info->regs->protection_key); + while (readl(&info->regs->protection_key)) + ; +} + +static int ast2500_sdrammc_probe(struct udevice *dev) +{ + struct reset_ctl reset_ctl; + struct dram_info *priv = (struct dram_info *)dev_get_priv(dev); + struct ast2500_sdrammc_regs *regs = priv->regs; + int i; + int ret = clk_get_by_index(dev, 0, &priv->ddr_clk); + + if (ret) { + debug("DDR:No CLK\n"); + return ret; + } + + priv->scu = ast_get_scu(); + if (IS_ERR(priv->scu)) { + debug("%s(): can't get SCU\n", __func__); + return PTR_ERR(priv->scu); + } + + clk_set_rate(&priv->ddr_clk, priv->clock_rate); + ret = reset_get_by_index(dev, 0, &reset_ctl); + if (ret) { + debug("%s(): Failed to get reset signal\n", __func__); + return ret; + } + + ret = reset_assert(&reset_ctl); + if (ret) { + debug("%s(): SDRAM reset failed: %u\n", __func__, ret); + return ret; + } + + ast2500_sdrammc_unlock(priv); + + writel(SDRAM_PCR_MREQI_DIS | SDRAM_PCR_RESETN_DIS, + ®s->power_control); + writel(SDRAM_VIDEO_UNLOCK_KEY, ®s->gm_protection_key); + + /* Mask all requests except CPU and AHB during PHY init */ + writel(~(SDRAM_REQ_CPU | SDRAM_REQ_AHB), ®s->req_limit_mask); + + for (i = 0; i < ARRAY_SIZE(ddr_max_grant_params); ++i) + writel(ddr_max_grant_params[i], ®s->max_grant_len[i]); + + setbits_le32(®s->intr_ctrl, SDRAM_ICR_RESET_ALL); + + ast2500_sdrammc_init_phy(priv->phy); + if (readl(&priv->scu->hwstrap) & SCU_HWSTRAP_DDR4) { + ast2500_sdrammc_init_ddr4(priv); + } else { + debug("Unsupported DRAM3\n"); + return -EINVAL; + } + + clrbits_le32(®s->intr_ctrl, SDRAM_ICR_RESET_ALL); + ast2500_sdrammc_lock(priv); + + return 0; +} + +static int ast2500_sdrammc_ofdata_to_platdata(struct udevice *dev) +{ + struct dram_info *priv = dev_get_priv(dev); + struct regmap *map; + int ret; + + ret = regmap_init_mem(dev_ofnode(dev), &map); + if (ret) + return ret; + + priv->regs = regmap_get_range(map, 0); + priv->phy = regmap_get_range(map, 1); + + priv->clock_rate = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), + "clock-frequency", 0); + + if (!priv->clock_rate) { + debug("DDR Clock Rate not defined\n"); + return -EINVAL; + } + + return 0; +} + +static int ast2500_sdrammc_get_info(struct udevice *dev, struct ram_info *info) +{ + struct dram_info *priv = dev_get_priv(dev); + + *info = priv->info; + + return 0; +} + +static struct ram_ops ast2500_sdrammc_ops = { + .get_info = ast2500_sdrammc_get_info, +}; + +static const struct udevice_id ast2500_sdrammc_ids[] = { + { .compatible = "aspeed,ast2500-sdrammc" }, + { } +}; + +U_BOOT_DRIVER(sdrammc_ast2500) = { + .name = "aspeed_ast2500_sdrammc", + .id = UCLASS_RAM, + .of_match = ast2500_sdrammc_ids, + .ops = &ast2500_sdrammc_ops, + .ofdata_to_platdata = ast2500_sdrammc_ofdata_to_platdata, + .probe = ast2500_sdrammc_probe, + .priv_auto_alloc_size = sizeof(struct dram_info), +}; diff --git a/drivers/watchdog/designware_wdt.c b/drivers/watchdog/designware_wdt.c index 12f09a7a39..7caa6c550c 100644 --- a/drivers/watchdog/designware_wdt.c +++ b/drivers/watchdog/designware_wdt.c @@ -130,7 +130,7 @@ static int designware_wdt_probe(struct udevice *dev) if (ret) return ret; - priv->clk_khz = clk_get_rate(&clk); + priv->clk_khz = clk_get_rate(&clk) / 1000; if (!priv->clk_khz) return -EINVAL; #else |