diff options
Diffstat (limited to 'drivers/pinctrl/renesas/core.c')
-rw-r--r-- | drivers/pinctrl/renesas/core.c | 117 |
1 files changed, 69 insertions, 48 deletions
diff --git a/drivers/pinctrl/renesas/core.c b/drivers/pinctrl/renesas/core.c index d0d4714731c1..8c14b2021bf0 100644 --- a/drivers/pinctrl/renesas/core.c +++ b/drivers/pinctrl/renesas/core.c @@ -13,10 +13,11 @@ #include <linux/bitops.h> #include <linux/err.h> #include <linux/errno.h> +#include <linux/init.h> #include <linux/io.h> #include <linux/ioport.h> #include <linux/kernel.h> -#include <linux/init.h> +#include <linux/math.h> #include <linux/of.h> #include <linux/of_device.h> #include <linux/pinctrl/machine.h> @@ -71,12 +72,11 @@ static int sh_pfc_map_resources(struct sh_pfc *pfc, /* Fill them. */ for (i = 0; i < num_windows; i++) { - res = platform_get_resource(pdev, IORESOURCE_MEM, i); - windows->phys = res->start; - windows->size = resource_size(res); - windows->virt = devm_ioremap_resource(pfc->dev, res); + windows->virt = devm_platform_get_and_ioremap_resource(pdev, i, &res); if (IS_ERR(windows->virt)) return -ENOMEM; + windows->phys = res->start; + windows->size = resource_size(res); windows++; } for (i = 0; i < num_irqs; i++) @@ -214,7 +214,7 @@ static void sh_pfc_config_reg_helper(struct sh_pfc *pfc, *maskp = (1 << crp->var_field_width[in_pos]) - 1; *posp = crp->reg_width; for (k = 0; k <= in_pos; k++) - *posp -= crp->var_field_width[k]; + *posp -= abs(crp->var_field_width[k]); } } @@ -262,14 +262,17 @@ static int sh_pfc_get_config_reg(struct sh_pfc *pfc, u16 enum_id, if (!r_width) break; - for (bit_pos = 0; bit_pos < r_width; bit_pos += curr_width) { + for (bit_pos = 0; bit_pos < r_width; bit_pos += curr_width, m++) { u32 ncomb; u32 n; - if (f_width) + if (f_width) { curr_width = f_width; - else - curr_width = config_reg->var_field_width[m]; + } else { + curr_width = abs(config_reg->var_field_width[m]); + if (config_reg->var_field_width[m] < 0) + continue; + } ncomb = 1 << curr_width; for (n = 0; n < ncomb; n++) { @@ -281,7 +284,6 @@ static int sh_pfc_get_config_reg(struct sh_pfc *pfc, u16 enum_id, } } pos += ncomb; - m++; } k++; } @@ -875,7 +877,8 @@ static const struct sh_pfc_pin __init *sh_pfc_find_pin( static void __init sh_pfc_check_cfg_reg(const char *drvname, const struct pinmux_cfg_reg *cfg_reg) { - unsigned int i, n, rw, fw; + unsigned int i, n, rw, r; + int fw; sh_pfc_check_reg(drvname, cfg_reg->reg, GENMASK(cfg_reg->reg_width - 1, 0)); @@ -883,16 +886,29 @@ static void __init sh_pfc_check_cfg_reg(const char *drvname, if (cfg_reg->field_width) { fw = cfg_reg->field_width; n = (cfg_reg->reg_width / fw) << fw; + for (i = 0, r = 0; i < n; i += 1 << fw) { + if (is0s(&cfg_reg->enum_ids[i], 1 << fw)) + r++; + } + + if ((r << fw) * sizeof(u16) > cfg_reg->reg_width / fw) + sh_pfc_warn("reg 0x%x can be described with variable-width reserved fields\n", + cfg_reg->reg); + /* Skip field checks (done at build time) */ goto check_enum_ids; } for (i = 0, n = 0, rw = 0; (fw = cfg_reg->var_field_width[i]); i++) { - if (fw > 3 && is0s(&cfg_reg->enum_ids[n], 1 << fw)) - sh_pfc_warn("reg 0x%x: reserved field [%u:%u] can be split to reduce table size\n", - cfg_reg->reg, rw, rw + fw - 1); - n += 1 << fw; - rw += fw; + if (fw < 0) { + rw += -fw; + } else { + if (is0s(&cfg_reg->enum_ids[n], 1 << fw)) + sh_pfc_warn("reg 0x%x: field [%u:%u] can be described as reserved\n", + cfg_reg->reg, rw, rw + fw - 1); + n += 1 << fw; + rw += fw; + } } if (rw != cfg_reg->reg_width) @@ -1007,7 +1023,18 @@ static void __init sh_pfc_compare_groups(const char *drvname, static void __init sh_pfc_check_info(const struct sh_pfc_soc_info *info) { const struct pinmux_drive_reg *drive_regs = info->drive_regs; +#define drive_nfields ARRAY_SIZE(drive_regs->fields) +#define drive_ofs(i) drive_regs[(i) / drive_nfields] +#define drive_reg(i) drive_ofs(i).reg +#define drive_bit(i) ((i) % drive_nfields) +#define drive_field(i) drive_ofs(i).fields[drive_bit(i)] const struct pinmux_bias_reg *bias_regs = info->bias_regs; +#define bias_npins ARRAY_SIZE(bias_regs->pins) +#define bias_ofs(i) bias_regs[(i) / bias_npins] +#define bias_puen(i) bias_ofs(i).puen +#define bias_pud(i) bias_ofs(i).pud +#define bias_bit(i) ((i) % bias_npins) +#define bias_pin(i) bias_ofs(i).pins[bias_bit(i)] const char *drvname = info->name; unsigned int *refcnts; unsigned int i, j, k; @@ -1076,17 +1103,17 @@ static void __init sh_pfc_check_info(const struct sh_pfc_soc_info *info) if (!drive_regs) { sh_pfc_err_once(drive, "SH_PFC_PIN_CFG_DRIVE_STRENGTH flag set but drive_regs missing\n"); } else { - for (j = 0; drive_regs[j / 8].reg; j++) { - if (!drive_regs[j / 8].fields[j % 8].pin && - !drive_regs[j / 8].fields[j % 8].offset && - !drive_regs[j / 8].fields[j % 8].size) + for (j = 0; drive_reg(j); j++) { + if (!drive_field(j).pin && + !drive_field(j).offset && + !drive_field(j).size) continue; - if (drive_regs[j / 8].fields[j % 8].pin == pin->pin) + if (drive_field(j).pin == pin->pin) break; } - if (!drive_regs[j / 8].reg) + if (!drive_reg(j)) sh_pfc_err("pin %s: SH_PFC_PIN_CFG_DRIVE_STRENGTH flag set but not in drive_regs\n", pin->name); } @@ -1164,20 +1191,17 @@ static void __init sh_pfc_check_info(const struct sh_pfc_soc_info *info) for (i = 0; drive_regs && drive_regs[i].reg; i++) sh_pfc_check_drive_reg(info, &drive_regs[i]); - for (i = 0; drive_regs && drive_regs[i / 8].reg; i++) { - if (!drive_regs[i / 8].fields[i % 8].pin && - !drive_regs[i / 8].fields[i % 8].offset && - !drive_regs[i / 8].fields[i % 8].size) + for (i = 0; drive_regs && drive_reg(i); i++) { + if (!drive_field(i).pin && !drive_field(i).offset && + !drive_field(i).size) continue; for (j = 0; j < i; j++) { - if (drive_regs[i / 8].fields[i % 8].pin == - drive_regs[j / 8].fields[j % 8].pin && - drive_regs[j / 8].fields[j % 8].offset && - drive_regs[j / 8].fields[j % 8].size) { - sh_pfc_err("drive_reg 0x%x:%u/0x%x:%u: pin conflict\n", - drive_regs[i / 8].reg, i % 8, - drive_regs[j / 8].reg, j % 8); + if (drive_field(i).pin == drive_field(j).pin && + drive_field(j).offset && drive_field(j).size) { + sh_pfc_err("drive_reg 0x%x:%zu/0x%x:%zu: pin conflict\n", + drive_reg(i), drive_bit(i), + drive_reg(j), drive_bit(j)); } } } @@ -1186,26 +1210,23 @@ static void __init sh_pfc_check_info(const struct sh_pfc_soc_info *info) for (i = 0; bias_regs && (bias_regs[i].puen || bias_regs[i].pud); i++) sh_pfc_check_bias_reg(info, &bias_regs[i]); - for (i = 0; bias_regs && - (bias_regs[i / 32].puen || bias_regs[i / 32].pud); i++) { - if (bias_regs[i / 32].pins[i % 32] == SH_PFC_PIN_NONE) + for (i = 0; bias_regs && (bias_puen(i) || bias_pud(i)); i++) { + if (bias_pin(i) == SH_PFC_PIN_NONE) continue; for (j = 0; j < i; j++) { - if (bias_regs[i / 32].pins[i % 32] != - bias_regs[j / 32].pins[j % 32]) + if (bias_pin(i) != bias_pin(j)) continue; - if (bias_regs[i / 32].puen && bias_regs[j / 32].puen) - sh_pfc_err("bias_reg 0x%x:%u/0x%x:%u: pin conflict\n", - bias_regs[i / 32].puen, i % 32, - bias_regs[j / 32].puen, j % 32); - if (bias_regs[i / 32].pud && bias_regs[j / 32].pud) - sh_pfc_err("bias_reg 0x%x:%u/0x%x:%u: pin conflict\n", - bias_regs[i / 32].pud, i % 32, - bias_regs[j / 32].pud, j % 32); + if (bias_puen(i) && bias_puen(j)) + sh_pfc_err("bias_reg 0x%x:%zu/0x%x:%zu: pin conflict\n", + bias_puen(i), bias_bit(i), + bias_puen(j), bias_bit(j)); + if (bias_pud(i) && bias_pud(j)) + sh_pfc_err("bias_reg 0x%x:%zu/0x%x:%zu: pin conflict\n", + bias_pud(i), bias_bit(i), + bias_pud(j), bias_bit(j)); } - } /* Check ioctrl registers */ |