pinctrl: renesas: Add shorthand for reserved register fields
Currently, reserved register fields must be fully described using dummy enum IDs (zeroes), one for each possible state (2^bits states). Add support for describing reserved fields using negative field width values as shorthands, thus removing the need for dummy values. Apart from the obvious size reduction due to the removal of the dummy values, this will also enable merging adjacent reserved fields into a single field, reducing the number of fields to describe, and thus kernel size. Update the checker accordingly. Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be> Link: https://lore.kernel.org/r/cad7c92ef039d9a4d039807efc15886a7aa862be.1649865241.git.geert+renesas@glider.be
This commit is contained in:
parent
7fefb7c059
commit
6210905586
|
@ -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>
|
||||
|
@ -213,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]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -261,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++) {
|
||||
|
@ -280,7 +284,6 @@ static int sh_pfc_get_config_reg(struct sh_pfc *pfc, u16 enum_id,
|
|||
}
|
||||
}
|
||||
pos += ncomb;
|
||||
m++;
|
||||
}
|
||||
k++;
|
||||
}
|
||||
|
@ -874,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;
|
||||
int fw;
|
||||
|
||||
sh_pfc_check_reg(drvname, cfg_reg->reg,
|
||||
GENMASK(cfg_reg->reg_width - 1, 0));
|
||||
|
@ -887,11 +891,15 @@ static void __init sh_pfc_check_cfg_reg(const char *drvname,
|
|||
}
|
||||
|
||||
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)
|
||||
|
|
|
@ -112,7 +112,7 @@ struct pinmux_cfg_reg {
|
|||
#define SET_NR_ENUM_IDS(n)
|
||||
#endif
|
||||
const u16 *enum_ids;
|
||||
const u8 *var_field_width;
|
||||
const s8 *var_field_width;
|
||||
};
|
||||
|
||||
#define GROUP(...) __VA_ARGS__
|
||||
|
@ -142,14 +142,15 @@ struct pinmux_cfg_reg {
|
|||
* - r_width: Width of the register (in bits)
|
||||
* - f_widths: List of widths of the register fields (in bits), from left
|
||||
* to right (i.e. MSB to LSB), wrapped using the GROUP() macro.
|
||||
* - ids: For each register field (from left to right, i.e. MSB to LSB),
|
||||
* 2^f_widths[i] enum IDs must be specified, one for each possible
|
||||
* combination of the register field bit values, all wrapped using
|
||||
* the GROUP() macro.
|
||||
* Reserved fields are indicated by negating the field width.
|
||||
* - ids: For each non-reserved register field (from left to right, i.e. MSB
|
||||
* to LSB), 2^f_widths[i] enum IDs must be specified, one for each
|
||||
* possible combination of the register field bit values, all wrapped
|
||||
* using the GROUP() macro.
|
||||
*/
|
||||
#define PINMUX_CFG_REG_VAR(name, r, r_width, f_widths, ids) \
|
||||
.reg = r, .reg_width = r_width, \
|
||||
.var_field_width = (const u8 []) { f_widths, 0 }, \
|
||||
.var_field_width = (const s8 []) { f_widths, 0 }, \
|
||||
SET_NR_ENUM_IDS(sizeof((const u16 []) { ids }) / sizeof(u16)) \
|
||||
.enum_ids = (const u16 []) { ids }
|
||||
|
||||
|
|
Loading…
Reference in New Issue