Linus, (and other people interested in pinmux!)
I've started to look at porting the Tegra pinmux driver to your pinctrl subsystem. In order to replace the existing pinmux driver, I need a way to support configuring options such as tri-state, pull-up/down, drive- strength, etc.
At this point, I have a couple of options:
1) Initialize all those parameters (and indeed the initial system-level mux configuration) using custom code in the Tegra pinmux driver, and just use the pin controller subsystem APIs for dynamic pin-muxing. As you recall, I did post some patches to the Tegra pinmux driver to do this, but I'm hoping to do (2) instead.
2) Enhance the pin controller subsystem to support configuring these properties.
The following is some issues that need to be thought about if we do (2):
Issue 1: Pinctrl core -> driver interface
I propose adding the following to pinctrl_ops:
int (*pin_config)(unsigned pin, u32 param, u32 data); int (*group_config)(unsigned group, u32 param, u32 data);
Where "param" is some driver-specific parameter, such as:
#define TEGRA_PINCTRL_PARAM_TRISTATE_ENABLE 0 #define TEGRA_PINCTRL_PARAM_PULL_TYPE 1 #define TEGRA_PINCTRL_PARAM_SCHMITT_ENABLE 2 #define TEGRA_PINCTRL_PARAM_HIGH_SPEED_ENABLE 3 #define TEGRA_PINCTRL_PARAM_DRIVE_STRENGTH 4 #define TEGRA_PINCTRL_PARAM_PULL_UP_STRENGTH 5 #define TEGRA_PINCTRL_PARAM_PULL_DOWN_STRENGTH 6 #define TEGRA_PINCTRL_PARAM_SLEW_RATE_RISING 7 #define TEGRA_PINCTRL_PARAM_SLEW_RATE_FALLING 8
Rationale:
Param being SoC-specific:
I looked at a bunch of existing pinmux drivers in the mainline kernel. There are certainly some common concepts between SoCs. However, the details are often different enough that I don't think attempting to unify the set of configuration options will be that successful; I doubt we could create a generic enough abstraction of these settings for a cross-SoC driver to be able to usefully name and select values for all the different pin/group options.
Data being a plain u32 rather than a pointer as your v7 patchset had it:
Using a pointer does allow passing arbitrary data into the driver, which seems useful. However, this also makes it much more difficult for the core pin controller API to handle the values, e.g. in the mapping table, in a device-tree representation thereof, etc.
Having both config_pin and config_group functions:
Tegra at least has settings that are applicable to groups. Most (all??) other SoCs apply configurations to individual pins. I think we need separate functions to make this explicit, so the function knows if it's looking up selector as a pin name (ID) or a group name (ID).
Issue 2: Do we need a new "pin settings" table passed from the board to the pin controller core?
Issue 3: Do we need to change "pin settings" on-the-fly, or only at boot?
These issues are closely related.
If we only care about statically configuring pins at boot time, then pinmux_register_mappings() could be enhanced to accept two tables; the existing one for the mux settings, and a second one that's essentially just a list of pin/group_config calls to make at pinmux init time.
However, if we ever want things to change dynamically (say, suspend/ resume), or only be activated when a device initializes (just like the mux settings), we need to enhance struct pinmux_map to contain either mux settings or config settings; perhaps rework it as follows:
enum pinmux_map_type { MUX, PIN_CONFIG, GROUP_CONFIG };
struct pinmux_map { const char *name; struct device *ctrl_dev; const char *ctrl_dev_name; enum pinmux_map_type type; union { struct { const char *function; const char *group; } mux; struct { u32 param; u32 data; } config; } data; struct device *dev; const char *dev_name; const bool hog_on_boot; };
Such that pinmux_enable would both activate all the mux settings, and also call pin/group_config based on the mapping table.
Issue 4: Device-tree
I'd like to enhance the pinmux core to allow the mapping table to be read from device tree. If we end up with a separate "pin configuration" table, the same applies there. Do you have any thoughts here, or should I just go ahead and create/propose something? I'd probably base this partially on my previous patches that do this within the Tegra pinmux driver itself.
Issue 5: Suspend/resume, and other state changes
First, some HW background on Tegra, which I imagine applies to any SoC capable of muxing a single "function" onto different sets of pins:
Lets take Tegra's first I2C controller. It can be mux'd onto pingroups "I2CP" or "RM". Given the register definitions (for each pingroup, there's a "function select" register field), it's possible to tell the HW to mux that I2C function onto *both* pingroups at once. However, we must avoid this, because this will cause incorrect HW operation; for input pins, both pingroups will be trying to drive the internal signal. At best, this will cause the I2C controller to receive garbled signals. At worst, it will cause damage to the chip. (I'm not sure which is true in Tegra's case).
For this reason, any time the pinmux driver is told to disable a function, it must program that pingroup's mux function to a "safe" value, which is guaranteed not to cause conflicts for any other possible mux settings on other pingroups. Possibly, the driver should tristate the pingroup too, to avoid whatever HW function the "safe" function is from actually driving any output pins and confusing the attached device. Our current driver doesn't tristate though.
Now let's suppose that we've enhanced the mapping table to support pin/ group_config values, and that a driver is written to expect a pinmux mapping table with the following mappings:
"active" "suspend"
Where the only difference between those two mappings is some pin/ group_config value. When switching between those two settings, the "active" mux values will be rolled back to some "safe" values, then the "suspend" mux values will be re-programmed. This may cause spurious changes in output signals, depending on what the "safe" function is exactly. It might even temporarily change some pins from inputs to outputs.
The pinmux API currently conflates two different things:
a) A device's ownership of certain pins.
b) The configuration of those pins.
I think we should aim for some mechanism of teasing those two concepts apart, and allowing dynamic transitioning between different configurations for the owned pins without completely releasing them.
There's also the slight issue that if you put() a mapping to change to another one, there's a small window where the driver doesn't own the pins, which might show up in a pinmux debug file, or allow another driver to take ownership of them.
One possibility might be to add another column to the mapping table, so that we end up with the search key being:
Search keys: device, name, configuration (new) Output data: list of mux settings, pin/group_config settings
This would modify the client driver API to something like:
Mapping table:
Driver mapping_name configuration settings ----------------------------------------- i2c - active group i2cp.mux = i2c i2c - active group i2cp.tristate = false i2c - suspend group i2cp.mux = i2c i2c - suspend group i2cp.tristate = true
Driver probe():
reservation = pinmux_reserve(device, NULL /* mapping_name */) pinmux_select(reservation, "active")
Driver suspend():
// Within this call, the pinmux driver doesn't have to program safe values // into HW, because it knows that any future programming on pins relevant // to the driver can only be driven by mapping table entries for the "4-bit" // reservation, and we assume the person creating those mapping table // entries didn't set up some problematic configuration // // The mapping tables may be set up so the only difference is some pin/ // group_config values here pinmux_select(reservation, "suspend")
Driver resume():
pinmux_select(reservation, "active")
Driver remove():
// Within this call, the pinmux driver programs the safe values into HW, // since the ownership of the pins is released; some other driver may // start using the pins or mux'd HW modules now. pinmux_unreserve(reservation)
In this scheme, the mapping table might even be enhanced to be a list of actions to perform on each transition, rather than completely describing the state of the mux in each state. That might optimize the set of actions performed by some state transitions, if the mapping table author desires.
What are your thoughts on this?
For reference, I read through all the pinmux drivers I could find in arch/ arm, and made a rough list of all the pin/group_config settings they support:
msm:
pads?:
drive strength = 2, 4, 6, 8, 10, 12, 14, 16mA pull = n, down, keeper, up
mxs:
pads:
drive strength = 4, 8, 12, 16mA voltage = 1.8, 3.3V pull = n, up
omap2 (2420, 2430, 34xx, 44xx):
pads:
off out enable off out value off pull enable off pull up wakeup enable
tegra20:
mux pingroups:
tri-state = y, n pull = n, up, down
drive pingroups:
high speed mode = y, n schmitt = y, n drive strength = /1, /2, /4, /8 pull down strength = 0..31 pull up strength = 0..31 slew rate rising = fastest, fast, slow, slowest slew rate falling = fastest, fast, slow, slowest
mxc v1:
??
mxc v3:
pads:
dvs? # drive strength? hys? # hysteresis? pke? # pull/keeper enable? pue? # pull enable (rather than keeper)? pull strength = 100k down, 47k up, 22k up ode? # open drain? slew rate = slow, fast
mxc mx1:
??
mxc mx3:
pads:
loopback pke? = none, enable (keeper?) pue? = (look at?) keeper (bit?), pud pull strength = 100k pull down, 100k pull up, 47k pull up, 22k pullup hysteresis = cmos, schmitt driver = cmos, open drain drive strength = normal, high, max slew rate = slow, fast
nomadik (ux500):
pads:
pull = n, up, down sleep mode = make input, no change or: sleep mode wakeup = enable, disable sleep mode pull = n, up, down sleep mode direction = in, out sleep mode value = 0, 1
It might be a good place for me to catch up the pinctrl subsystem discussion, as far as imx migration concerned.
I have not read the backlog of all the previous discussion, so please excuse me if something I put here have been discussed.
On Thu, Oct 13, 2011 at 01:59:55PM -0700, Stephen Warren wrote:
Linus, (and other people interested in pinmux!)
I've started to look at porting the Tegra pinmux driver to your pinctrl subsystem. In order to replace the existing pinmux driver, I need a way to support configuring options such as tri-state, pull-up/down, drive- strength, etc.
I'm also concerned about this. The current pinctrl subsystem only implements pinmux. Before pin/pad configuration (pincfg) support is available, I can not really convert imx iomuxc driver (iomux-v3) over to use the subsystem.
At this point, I have a couple of options:
- Initialize all those parameters (and indeed the initial system-level
mux configuration) using custom code in the Tegra pinmux driver, and just use the pin controller subsystem APIs for dynamic pin-muxing. As you recall, I did post some patches to the Tegra pinmux driver to do this, but I'm hoping to do (2) instead.
- Enhance the pin controller subsystem to support configuring these
properties.
Yeah. I remember Linus.W originally named the subsystem pinmux and changed it to pinctrl later for that he wants to cover not only pinmux but also pin/pad configuration with this subsystem.
The following is some issues that need to be thought about if we do (2):
Issue 1: Pinctrl core -> driver interface
This is something I'm not completely follow right now.
Looking at the two drivers already migrated to the subsystem, pinmux-u300 and pinmux-sirf, from the naming of the driver, it seems they are supposed to be pinmux drivers and only handle pinmux. Is it a indication that we will have another pincfg driver to handle pin configuration? In that case, we need to have a clear separation among pinmux, and pincfg and pinctrl (core), e.g. pinctrl_ops probably should not stay in pinmux driver.
Alternatively, we can have driver pinctrl-u300 rather than pinmux-u300 handling both pinmux and pincfg in one driver. If pinmux and pincfg are not so standalone, e.g. we may want to expand the mapping to be function-pinmux-pincfg, this option might be good.
I propose adding the following to pinctrl_ops:
int (*pin_config)(unsigned pin, u32 param, u32 data); int (*group_config)(unsigned group, u32 param, u32 data);
If we take pinmux and pincfg as two equal but separate pieces of pinctrl, having pinmux_ops for pinmux while plugging pincfg ops into pinctrl_ops is something looks odd to me.
The reasonable way to add pincfg functions into pinctrl_ops would be that we have driver named pincrl-u300 rather than pinmux-u300, both pinmux_ops and pincfg_ops embedded in pinctrl_ops, to handle pinmux and pincfg in the same driver.
Where "param" is some driver-specific parameter, such as:
#define TEGRA_PINCTRL_PARAM_TRISTATE_ENABLE 0 #define TEGRA_PINCTRL_PARAM_PULL_TYPE 1 #define TEGRA_PINCTRL_PARAM_SCHMITT_ENABLE 2 #define TEGRA_PINCTRL_PARAM_HIGH_SPEED_ENABLE 3 #define TEGRA_PINCTRL_PARAM_DRIVE_STRENGTH 4 #define TEGRA_PINCTRL_PARAM_PULL_UP_STRENGTH 5 #define TEGRA_PINCTRL_PARAM_PULL_DOWN_STRENGTH 6 #define TEGRA_PINCTRL_PARAM_SLEW_RATE_RISING 7 #define TEGRA_PINCTRL_PARAM_SLEW_RATE_FALLING 8
Rationale:
Param being SoC-specific:
+1
I looked at a bunch of existing pinmux drivers in the mainline kernel. There are certainly some common concepts between SoCs. However, the details are often different enough that I don't think attempting to unify the set of configuration options will be that successful; I doubt we could create a generic enough abstraction of these settings for a cross-SoC driver to be able to usefully name and select values for all the different pin/group options.
Data being a plain u32 rather than a pointer as your v7 patchset had it:
+1
Using a pointer does allow passing arbitrary data into the driver, which seems useful. However, this also makes it much more difficult for the core pin controller API to handle the values, e.g. in the mapping table, in a device-tree representation thereof, etc.
Having both config_pin and config_group functions:
Tegra at least has settings that are applicable to groups. Most (all??) other SoCs apply configurations to individual pins. I think we need separate functions to make this explicit, so the function knows if it's looking up selector as a pin name (ID) or a group name (ID).
The "group" defined in this subsystem does not necessarily require multiple pins be controlled by single register at hardware level. A group of pins muxed for given function can be controlled by hardware in the way of individual pin. Similar to pinmux, I guess that the interface between pincfg and core can take group only, and leave the mapping between group and pins to the driver. Single-pin function can be a particular case of group-pins.
Issue 2: Do we need a new "pin settings" table passed from the board to the pin controller core?
Issue 3: Do we need to change "pin settings" on-the-fly, or only at boot?
I at least have one case on imx that needs change pincfg on-the-fly. The usdhc on imx6q requires different SD pin/pad configurations for different SD bus frequencies, 50M, 100M and 200M. We can not have one configuration working for all these three frequencies, and have to change configuration per different frequency setting on the fly.
These issues are closely related.
If we only care about statically configuring pins at boot time, then pinmux_register_mappings() could be enhanced to accept two tables; the existing one for the mux settings, and a second one that's essentially just a list of pin/group_config calls to make at pinmux init time.
However, if we ever want things to change dynamically (say, suspend/ resume), or only be activated when a device initializes (just like the mux settings), we need to enhance struct pinmux_map to contain either mux settings or config settings; perhaps rework it as follows:
I would think that we need to enhance pinmux_map to contain both mux *and* config settings. To me, the mapping seems to be a group of pins with specific mux and config settings for a given function.
enum pinmux_map_type { MUX, PIN_CONFIG, GROUP_CONFIG };
struct pinmux_map { const char *name; struct device *ctrl_dev; const char *ctrl_dev_name; enum pinmux_map_type type; union { struct { const char *function; const char *group; } mux; struct { u32 param; u32 data; } config;
If the config has limited number of possible settings for given function, we can probably enumerate it in pinctrl driver just like what we are doing with pinmux option, and add parameter "config" to pinmux_map to select pincfg option for given mapping.
@@ -46,6 +46,7 @@ struct pinmux_map { const char *ctrl_dev_name; const char *function; const char *group; + const char *config; struct device *dev; const char *dev_name; const bool hog_on_boot;
} data; struct device *dev; const char *dev_name; const bool hog_on_boot;
};
Such that pinmux_enable would both activate all the mux settings, and also call pin/group_config based on the mapping table.
Issue 4: Device-tree
Yes, with pincfg added and mapping described by device tree, we will have the subsystem fully ready for existing pinctrl driver under arch/ to migrate to.
I'd like to enhance the pinmux core to allow the mapping table to be read from device tree. If we end up with a separate "pin configuration" table, the same applies there. Do you have any thoughts here, or should I just go ahead and create/propose something? I'd probably base this partially on my previous patches that do this within the Tegra pinmux driver itself.
Issue 5: Suspend/resume, and other state changes
First, some HW background on Tegra, which I imagine applies to any SoC capable of muxing a single "function" onto different sets of pins:
Lets take Tegra's first I2C controller. It can be mux'd onto pingroups "I2CP" or "RM". Given the register definitions (for each pingroup, there's a "function select" register field), it's possible to tell the HW to mux that I2C function onto *both* pingroups at once. However, we must avoid this, because this will cause incorrect HW operation; for input pins, both pingroups will be trying to drive the internal signal. At best, this will cause the I2C controller to receive garbled signals. At worst, it will cause damage to the chip. (I'm not sure which is true in Tegra's case).
For this reason, any time the pinmux driver is told to disable a function, it must program that pingroup's mux function to a "safe" value, which is guaranteed not to cause conflicts for any other possible mux settings on other pingroups. Possibly, the driver should tristate the pingroup too, to avoid whatever HW function the "safe" function is from actually driving any output pins and confusing the attached device. Our current driver doesn't tristate though.
Now let's suppose that we've enhanced the mapping table to support pin/ group_config values, and that a driver is written to expect a pinmux mapping table with the following mappings:
"active" "suspend"
Where the only difference between those two mappings is some pin/ group_config value. When switching between those two settings, the "active" mux values will be rolled back to some "safe" values, then the "suspend" mux values will be re-programmed. This may cause spurious changes in output signals, depending on what the "safe" function is exactly. It might even temporarily change some pins from inputs to outputs.
The pinmux API currently conflates two different things:
a) A device's ownership of certain pins.
b) The configuration of those pins.
I think we should aim for some mechanism of teasing those two concepts apart, and allowing dynamic transitioning between different configurations for the owned pins without completely releasing them.
There's also the slight issue that if you put() a mapping to change to another one, there's a small window where the driver doesn't own the pins, which might show up in a pinmux debug file, or allow another driver to take ownership of them.
I agree with above observations. For my example on imx6q usdhc, when changing from one mapping to another with only pincfg differences, we should manage pinctrl core not release the pins. I'm not sure that the following solution is optimal though, as the changes to the API seems significant.
Regards, Shawn
One possibility might be to add another column to the mapping table, so that we end up with the search key being:
Search keys: device, name, configuration (new) Output data: list of mux settings, pin/group_config settings
This would modify the client driver API to something like:
Mapping table:
Driver mapping_name configuration settings
i2c - active group i2cp.mux = i2c i2c - active group i2cp.tristate = false i2c - suspend group i2cp.mux = i2c i2c - suspend group i2cp.tristate = true
Driver probe():
reservation = pinmux_reserve(device, NULL /* mapping_name */) pinmux_select(reservation, "active")
Driver suspend():
// Within this call, the pinmux driver doesn't have to program safe values // into HW, because it knows that any future programming on pins relevant // to the driver can only be driven by mapping table entries for the "4-bit" // reservation, and we assume the person creating those mapping table // entries didn't set up some problematic configuration // // The mapping tables may be set up so the only difference is some pin/ // group_config values here pinmux_select(reservation, "suspend")
Driver resume():
pinmux_select(reservation, "active")
Driver remove():
// Within this call, the pinmux driver programs the safe values into HW, // since the ownership of the pins is released; some other driver may // start using the pins or mux'd HW modules now. pinmux_unreserve(reservation)
In this scheme, the mapping table might even be enhanced to be a list of actions to perform on each transition, rather than completely describing the state of the mux in each state. That might optimize the set of actions performed by some state transitions, if the mapping table author desires.
What are your thoughts on this?
Shawn Guo wrote at Friday, October 14, 2011 8:59 AM:
It might be a good place for me to catch up the pinctrl subsystem discussion, as far as imx migration concerned.
I have not read the backlog of all the previous discussion, so please excuse me if something I put here have been discussed.
On Thu, Oct 13, 2011 at 01:59:55PM -0700, Stephen Warren wrote:
Linus, (and other people interested in pinmux!)
I've started to look at porting the Tegra pinmux driver to your pinctrl subsystem. In order to replace the existing pinmux driver, I need a way to support configuring options such as tri-state, pull-up/down, drive- strength, etc.
...
- Enhance the pin controller subsystem to support configuring these
properties.
Yeah. I remember Linus.W originally named the subsystem pinmux and changed it to pinctrl later for that he wants to cover not only pinmux but also pin/pad configuration with this subsystem.
AIUI, the pin control subsystem is intended to encompass both pin muxing and pin configuration, it's just that the pin configuration part isn't fleshed out yet, and will be via a separate ops structure that the overall driver can provide.
...
I propose adding the following to pinctrl_ops:
int (*pin_config)(unsigned pin, u32 param, u32 data); int (*group_config)(unsigned group, u32 param, u32 data);
...
Having both config_pin and config_group functions:
Tegra at least has settings that are applicable to groups. Most (all??) other SoCs apply configurations to individual pins. I think we need separate functions to make this explicit, so the function knows if it's looking up selector as a pin name (ID) or a group name (ID).
The "group" defined in this subsystem does not necessarily require multiple pins be controlled by single register at hardware level. A group of pins muxed for given function can be controlled by hardware in the way of individual pin. Similar to pinmux, I guess that the interface between pincfg and core can take group only, and leave the mapping between group and pins to the driver. Single-pin function can be a particular case of group-pins.
That's true; we could define a group for each pin, which no function uses as a legal group/position, but does allow config() to be used.
Issue 2: Do we need a new "pin settings" table passed from the board to the pin controller core?
Issue 3: Do we need to change "pin settings" on-the-fly, or only at boot?
...
However, if we ever want things to change dynamically (say, suspend/ resume), or only be activated when a device initializes (just like the mux settings), we need to enhance struct pinmux_map to contain either mux settings or config settings; perhaps rework it as follows:
I would think that we need to enhance pinmux_map to contain both mux *and* config settings. To me, the mapping seems to be a group of pins with specific mux and config settings for a given function.
enum pinmux_map_type { MUX, PIN_CONFIG, GROUP_CONFIG };
struct pinmux_map { const char *name; struct device *ctrl_dev; const char *ctrl_dev_name; enum pinmux_map_type type; union { struct { const char *function; const char *group; } mux; struct { u32 param; u32 data; } config; } data; struct device *dev; const char *dev_name; const bool hog_on_boot; };
If the config has limited number of possible settings for given function, we can probably enumerate it in pinctrl driver just like what we are doing with pinmux option, and add parameter "config" to pinmux_map to select pincfg option for given mapping.
@@ -46,6 +46,7 @@ struct pinmux_map { const char *ctrl_dev_name; const char *function; const char *group;
const char *config; struct device *dev; const char *dev_name; const bool hog_on_boot;
Such that pinmux_enable would both activate all the mux settings, and also call pin/group_config based on the mapping table.
Having the driver expose a list of all possible combinations of pin configurations seems impractical, for the same reason as I objected to the original proposal for how the driver listed functions; there are simply far too many pin config parameters and legal value to list the entire set of combinations.
Listing legal values for each param individual option might be OK, but at least on Tegra, there are some interactions between them (e.g. for low drive strength, I think some of the faster slew rates aren't available or something like that). I'd tend to avoid the pinmux core defining any format for validation of config values requested in the mapping table, and have the driver or HW do that if required.
However, I like your idea above of simply adding one extra "config" field to the mapping table, rather than adding extra rows each detailing one config value. However, instead, of a "char *" pointing at an enumerated named config, perhaps just point at a board-/dt-defined (rather than driver-defined) list of config values:
struct pinmux_config { u32 param; u32 value; };
Then add the following to each mapping table entry:
struct pinmux_map { ... struct pinmux_config *configs; int nconfigs;
Issue 5: Suspend/resume, and other state changes
...
The pinmux API currently conflates two different things:
a) A device's ownership of certain pins.
b) The configuration of those pins.
I think we should aim for some mechanism of teasing those two concepts apart, and allowing dynamic transitioning between different configurations for the owned pins without completely releasing them.
There's also the slight issue that if you put() a mapping to change to another one, there's a small window where the driver doesn't own the pins, which might show up in a pinmux debug file, or allow another driver to take ownership of them.
I agree with above observations. For my example on imx6q usdhc, when changing from one mapping to another with only pincfg differences, we should manage pinctrl core not release the pins. I'm not sure that the following solution is optimal though, as the changes to the API seems significant.
It true that I proposed quite a change to the API.
That said, I think most of the difference in my example was naming. Re-writing my proposal with existing names, and modifying it to just add parameters to existing functions rather than introducing a new set of functions might end up with:
Driver mapping_name configuration group mux config -------------------------------------------------------------------- i2c - active i2cp i2c tristate = false, ... i2c - suspend i2cp i2c tristate = true, ...
Driver probe():
pmx = pinmux_get(device, NULL /* mapping_name */) pinmux_enable(pmx, "active"); // All we do is add a new parameter here
Driver suspend():
// Within this call, the pinmux driver doesn't have to program safe values // into HW, because it knows that any future programming on pins relevant // to the driver can only be driven by mapping table entries for same // reserved "pmx", and we assume the person creating those mapping table // entries didn't set up some problematic configuration. // // The mapping tables may be set up so the only difference is some pin/ // group_config values here // // Enable acts like enable or switch-to-new-config depending on whether // it was previously called or not. pinmux_enable(pmx, "suspend")
Driver resume():
pinmux_enable(pmx, "active")
Driver remove():
// Within this call, the pinmux driver programs the safe values into HW, // since the ownership of the pins is released; some other driver may // start using the pins or mux'd HW modules now. pinmux_disable(pmx) pinmux_put(pmx)
On Fri, Oct 14, 2011 at 08:53:33AM -0700, Stephen Warren wrote:
Shawn Guo wrote at Friday, October 14, 2011 8:59 AM:
It might be a good place for me to catch up the pinctrl subsystem discussion, as far as imx migration concerned.
I have not read the backlog of all the previous discussion, so please excuse me if something I put here have been discussed.
On Thu, Oct 13, 2011 at 01:59:55PM -0700, Stephen Warren wrote:
Linus, (and other people interested in pinmux!)
I've started to look at porting the Tegra pinmux driver to your pinctrl subsystem. In order to replace the existing pinmux driver, I need a way to support configuring options such as tri-state, pull-up/down, drive- strength, etc.
...
- Enhance the pin controller subsystem to support configuring these
properties.
Yeah. I remember Linus.W originally named the subsystem pinmux and changed it to pinctrl later for that he wants to cover not only pinmux but also pin/pad configuration with this subsystem.
AIUI, the pin control subsystem is intended to encompass both pin muxing and pin configuration, it's just that the pin configuration part isn't fleshed out yet, and will be via a separate ops structure that the overall driver can provide.
...
I propose adding the following to pinctrl_ops:
int (*pin_config)(unsigned pin, u32 param, u32 data); int (*group_config)(unsigned group, u32 param, u32 data);
...
Having both config_pin and config_group functions:
Tegra at least has settings that are applicable to groups. Most (all??) other SoCs apply configurations to individual pins. I think we need separate functions to make this explicit, so the function knows if it's looking up selector as a pin name (ID) or a group name (ID).
The "group" defined in this subsystem does not necessarily require multiple pins be controlled by single register at hardware level. A group of pins muxed for given function can be controlled by hardware in the way of individual pin. Similar to pinmux, I guess that the interface between pincfg and core can take group only, and leave the mapping between group and pins to the driver. Single-pin function can be a particular case of group-pins.
That's true; we could define a group for each pin, which no function uses as a legal group/position, but does allow config() to be used.
Issue 2: Do we need a new "pin settings" table passed from the board to the pin controller core?
Issue 3: Do we need to change "pin settings" on-the-fly, or only at boot?
...
However, if we ever want things to change dynamically (say, suspend/ resume), or only be activated when a device initializes (just like the mux settings), we need to enhance struct pinmux_map to contain either mux settings or config settings; perhaps rework it as follows:
I would think that we need to enhance pinmux_map to contain both mux *and* config settings. To me, the mapping seems to be a group of pins with specific mux and config settings for a given function.
enum pinmux_map_type { MUX, PIN_CONFIG, GROUP_CONFIG };
struct pinmux_map { const char *name; struct device *ctrl_dev; const char *ctrl_dev_name; enum pinmux_map_type type; union { struct { const char *function; const char *group; } mux; struct { u32 param; u32 data; } config; } data; struct device *dev; const char *dev_name; const bool hog_on_boot; };
If the config has limited number of possible settings for given function, we can probably enumerate it in pinctrl driver just like what we are doing with pinmux option, and add parameter "config" to pinmux_map to select pincfg option for given mapping.
@@ -46,6 +46,7 @@ struct pinmux_map { const char *ctrl_dev_name; const char *function; const char *group;
const char *config; struct device *dev; const char *dev_name; const bool hog_on_boot;
Such that pinmux_enable would both activate all the mux settings, and also call pin/group_config based on the mapping table.
Having the driver expose a list of all possible combinations of pin configurations seems impractical, for the same reason as I objected to the original proposal for how the driver listed functions; there are simply far too many pin config parameters and legal value to list the entire set of combinations.
I did not mean to list the entire set of combinations. For given function, the applicable number of config should be very limited. For most cases, it could be just one. For imx6q usdhc example, it's 3, for 50M, 100M and 200M SD bus clock cases.
Regards, Shawn
Shawn Guo wrote at Friday, October 14, 2011 9:12 PM:
On Fri, Oct 14, 2011 at 08:53:33AM -0700, Stephen Warren wrote:
...
Having the driver expose a list of all possible combinations of pin configurations seems impractical, for the same reason as I objected to the original proposal for how the driver listed functions; there are simply far too many pin config parameters and legal value to list the entire set of combinations.
I did not mean to list the entire set of combinations. For given function, the applicable number of config should be very limited. For most cases, it could be just one. For imx6q usdhc example, it's 3, for 50M, 100M and 200M SD bus clock cases.
Shawn,
Are you talking about entries in the (board-specific) mapping table, which I agree would contain the useful subset of combinations of options, or a list of possible settings exposed by the SoC driver, which would have to expose all possibilities, or they wouldn't be available for the mapping table to select from?
In the case of "a list of possible settings exposed by the SoC driver",
* If such a list (of combinations) were to exist, I think it'd need to include all combinations (the cross-product of all individual config params) in general.
* I can certainly imagine that for some SoCs, or for a particular device on a SoC, or for a particular board, only a subset of those would be useful, and hence a limited set would be useful. However, that selection is up to the board mapping table not the SoC driver in general.
* In Tegra's case at least, I think a number of the numeric values (e.g. pull strength with range 0..31) may be for board calibration, and besides that, most combinations of param values would be useful in some case, and hence we'd always have to expose everything, in order to allow the board mapping table to be able to pick anything the designer needed.
* As such, I think the SoC driver should at most list the legal range for each param individually, and let the board-specific mapping table choose the combination(s) required.
On Mon, Oct 17, 2011 at 08:51:11AM -0700, Stephen Warren wrote:
Shawn Guo wrote at Friday, October 14, 2011 9:12 PM:
On Fri, Oct 14, 2011 at 08:53:33AM -0700, Stephen Warren wrote:
...
Having the driver expose a list of all possible combinations of pin configurations seems impractical, for the same reason as I objected to the original proposal for how the driver listed functions; there are simply far too many pin config parameters and legal value to list the entire set of combinations.
I did not mean to list the entire set of combinations. For given function, the applicable number of config should be very limited. For most cases, it could be just one. For imx6q usdhc example, it's 3, for 50M, 100M and 200M SD bus clock cases.
Shawn,
Are you talking about entries in the (board-specific) mapping table, which I agree would contain the useful subset of combinations of options, or a list of possible settings exposed by the SoC driver, which would have to expose all possibilities, or they wouldn't be available for the mapping table to select from?
In the case of "a list of possible settings exposed by the SoC driver",
- If such a list (of combinations) were to exist, I think it'd need to
include all combinations (the cross-product of all individual config params) in general.
- I can certainly imagine that for some SoCs, or for a particular device
on a SoC, or for a particular board, only a subset of those would be useful, and hence a limited set would be useful. However, that selection is up to the board mapping table not the SoC driver in general.
- In Tegra's case at least, I think a number of the numeric values (e.g.
pull strength with range 0..31) may be for board calibration, and besides that, most combinations of param values would be useful in some case, and hence we'd always have to expose everything, in order to allow the board mapping table to be able to pick anything the designer needed.
- As such, I think the SoC driver should at most list the legal range for
each param individually, and let the board-specific mapping table choose the combination(s) required.
Yes, I meant the list of settings exposed by pinctrl driver. But it seems that in your case you need to list all the possible combinations of pin configurations. Then I agree it's impractical to have pinctrl driver to maintain this list.
On Fri, Oct 14, 2011 at 4:59 PM, Shawn Guo shawn.guo@freescale.com wrote:
[Stephen]
I've started to look at porting the Tegra pinmux driver to your pinctrl subsystem. In order to replace the existing pinmux driver, I need a way to support configuring options such as tri-state, pull-up/down, drive- strength, etc.
I'm also concerned about this. The current pinctrl subsystem only implements pinmux. Before pin/pad configuration (pincfg) support is available, I can not really convert imx iomuxc driver (iomux-v3) over to use the subsystem.
I have the same problem for drivers/gpio/gpio-nomadik. which does all weird kind of stuff. So you're not alone.
The reason why this is not in the subsystem as of today is that we cannot push hundreds of kilobytes of upfront design with no drivers using it, the current patch set in for-next is big enough as it is right now. http://en.wikipedia.org/wiki/Big_Design_Up_Front
But we can start thinking about the next step, so lets design the generic pin control stuff we need and merge it to -next early so we can work on it next kernel cycle.
Yours, Linus Walleij
Thanks for a long letter, took som time to read, but as usual it contains good stuff!
I think you're talking about two things here:
1) The need to configure per-pin "stuff" like biasing, driving, load capacitance ... whatever
2) The need to handle state transitions of pinmux settings.
I prefer that we try to keep these two separate and not conflate them too much.
On Thu, Oct 13, 2011 at 10:59 PM, Stephen Warren swarren@nvidia.com wrote:
- Enhance the pin controller subsystem to support configuring these
properties.
This is definately what we want to do. That is why the subsystem was renamed from pinmux to pinctrl in the first place, and also the rationale for introducing the abstract pin groups.
int (*pin_config)(unsigned pin, u32 param, u32 data); int (*group_config)(unsigned group, u32 param, u32 data);
Do you mean int (*group_config)(const char *group, u32 param, u32 data);
On the latter one? We identify groups by name mainly. The selectors is an internal thing between pinctrl core and drivers.
Where "param" is some driver-specific parameter, such as:
#define TEGRA_PINCTRL_PARAM_TRISTATE_ENABLE 0
(...)
I looked at a bunch of existing pinmux drivers in the mainline kernel. There are certainly some common concepts between SoCs. However, the details are often different enough that I don't think attempting to unify the set of configuration options will be that successful; I doubt we could create a generic enough abstraction of these settings for a cross-SoC driver to be able to usefully name and select values for all the different pin/group options.
I don't know, I could easily say the same thing about say input devices: all of them are essentially different, still they opted to create the file <linux/input.h> with this kind of stuff:
... #define KEY_COMMA 51 #define KEY_DOT 52 #define KEY_SLASH 53 #define KEY_RIGHTSHIFT 54 #define KEY_KPASTERISK 55 ...
And it has proven to be very useful. I'd rather opt to just remove the TEGRA_ prefix from all the above, and that we try to create some common sematics to these calls.
Data being a plain u32 rather than a pointer as your v7 patchset had it:
Actually it looked like this:
static inline int pinmux_config(struct pinmux *pmx, u16 param, unsigned long *data)
That was supposed to be an unsigned long (not a *pointer), which is exchangeable to pointer, as per the example known from interrupt handlers. It can also be used to pass a plain argument. It was designed to be "ioctl()-like".
So I prefer we say: int (*pin_config)(unsigned pin, u32 param, unsigned long data); int (*group_config)(const char *group, u32 param, unsigned long data);
Using a pointer does allow passing arbitrary data into the driver, which seems useful. However, this also makes it much more difficult for the core pin controller API to handle the values, e.g. in the mapping table, in a device-tree representation thereof, etc.
Only if it treats "param" as opaque. If we let "param" infer the semantics of "data" it's no problem, and it can easily switch(param) to select the proper semantics for the data.
Having both config_pin and config_group functions:
I buy that straight off, there is obviously a need for that.
Issue 2: Do we need a new "pin settings" table passed from the board to the pin controller core?
Yes I think so, trying to stuff it into the mappings does not look appealing at all. We should try to separate concerns, also it makes for nice separation in the DT metadata I suspect?
Issue 3: Do we need to change "pin settings" on-the-fly, or only at boot?
Both I think, from own experience and from reading the text below...
struct pinmux_map { const char *name; struct device *ctrl_dev; const char *ctrl_dev_name; enum pinmux_map_type type; union { struct { const char *function; const char *group; } mux; struct { u32 param; u32 data; } config; } data; struct device *dev; const char *dev_name; const bool hog_on_boot; };
Such that pinmux_enable would both activate all the mux settings, and also call pin/group_config based on the mapping table.
No thanks :-)
Let's keep these two separate. One mapping, one default pin config or whatever we want to call it.
I'd like to enhance the pinmux core to allow the mapping table to be read from device tree. If we end up with a separate "pin configuration" table, the same applies there. Do you have any thoughts here, or should I just go ahead and create/propose something? I'd probably base this partially on my previous patches that do this within the Tegra pinmux driver itself.
Something is better than nothing, but I cannot claim to be knowledgeable in DT.
Right now I would prefer to create basic stuff first, i.e. create a device tree binding for the stuff we have - the mapping table, get that ready for merge and then move on to the next thing.
Now let's suppose that we've enhanced the mapping table to support pin/ group_config values, and that a driver is written to expect a pinmux mapping table with the following mappings:
"active" "suspend"
I'm not following why this should be different mappings.
I would rather contrast it with the similar concept from the regulator framework, these have modes like these:
enum regulator_status { REGULATOR_STATUS_OFF, REGULATOR_STATUS_ON, REGULATOR_STATUS_ERROR, /* fast/normal/idle/standby are flavors of "on" */ REGULATOR_STATUS_FAST, REGULATOR_STATUS_NORMAL, REGULATOR_STATUS_IDLE, REGULATOR_STATUS_STANDBY, };
So I think we should have pin group states in a similar manner:
enum pinmux_state { PINMUX_STATE_DEFAULT, /* == active */ PINMUX_STATE_LOWPOWER, };
And associated calls:
pinmux_set_state(const char *group, enum pingroup_state state);
Where the only difference between those two mappings is some pin/ group_config value. When switching between those two settings, the "active" mux values will be rolled back to some "safe" values, then the "suspend" mux values will be re-programmed. This may cause spurious changes in output signals, depending on what the "safe" function is exactly. It might even temporarily change some pins from inputs to outputs.
A pinmux_set_state() function all the way down to the driver could handle this I think.
The pinmux API currently conflates two different things:
a) A device's ownership of certain pins.
b) The configuration of those pins.
I think we should aim for some mechanism of teasing those two concepts apart, and allowing dynamic transitioning between different configurations for the owned pins without completely releasing them.
I agree with this. So we only need to decide on a proper mechanism. pinmux_set_state() looks appealing to me...
Driver mapping_name configuration settings
i2c - active group i2cp.mux = i2c i2c - active group i2cp.tristate = false i2c - suspend group i2cp.mux = i2c i2c - suspend group i2cp.tristate = true
I would prefer not to try to shoehorn this into the mapping table. Isn't it possible to introduce this in some orthogonal way, like a per-group state table with associated groups?
Right now the pinmux_map** enumerates the valid groups, and pinmux_get()/put() selects one of them, I don't see any problem with pinmux_set_state() changing from one group to another.
If this has to follow some specific order like first go from group A -> B -> C should probably be handled in the driver since that's definately HW-specific, else we start embedding some scripting engine in the pinctrl core and that would be most unfortunate (IMO).
Driver probe():
reservation = pinmux_reserve(device, NULL /* mapping_name */) pinmux_select(reservation, "active")
Just pmx = pinmux_get()
Driver suspend(): pinmux_select(reservation, "suspend")
pinmux_set_state(pmx, PINMUX_STATE_SUSPEND);
Driver resume():
pinmux_select(reservation, "active")
pinmux_set_state(pmx, PINMUX_STATE_DEFAULT);
Driver remove(): pinmux_unreserve(reservation)
pinmux_put(pmx);
For reference, I read through all the pinmux drivers I could find in arch/ arm, and made a rough list of all the pin/group_config settings they support:
Thanks for this! I need to go over them too, also read some datasheets I guess, else I can not figure out whether my idea of trying to keep parameters generic makes sense or is just plain raving mad.
Yours, Linus Walleij
Linus Walleij wrote at Monday, October 17, 2011 9:03 AM:
Thanks for a long letter, took som time to read, but as usual it contains good stuff!
I think you're talking about two things here:
- The need to configure per-pin "stuff" like biasing, driving,
load capacitance ... whatever
- The need to handle state transitions of pinmux settings.
Yes, that's true.
I prefer that we try to keep these two separate and not conflate them too much.
On Thu, Oct 13, 2011 at 10:59 PM, Stephen Warren swarren@nvidia.com wrote:
- Enhance the pin controller subsystem to support configuring these
properties.
This is definately what we want to do. That is why the subsystem was renamed from pinmux to pinctrl in the first place, and also the rationale for introducing the abstract pin groups.
int (*pin_config)(unsigned pin, u32 param, u32 data); int (*group_config)(unsigned group, u32 param, u32 data);
Do you mean int (*group_config)(const char *group, u32 param, u32 data);
On the latter one? We identify groups by name mainly. The selectors is an internal thing between pinctrl core and drivers.
That was a proposal for the core->driver API, so I think using an int instead of a string makes sense?
Where "param" is some driver-specific parameter, such as:
#define TEGRA_PINCTRL_PARAM_TRISTATE_ENABLE 0
(...)
I looked at a bunch of existing pinmux drivers in the mainline kernel. There are certainly some common concepts between SoCs. However, the details are often different enough that I don't think attempting to unify the set of configuration options will be that successful; I doubt we could create a generic enough abstraction of these settings for a cross-SoC driver to be able to usefully name and select values for all the different pin/group options.
I don't know, I could easily say the same thing about say input devices: all of them are essentially different, still they opted to create the file <linux/input.h> with this kind of stuff:
... #define KEY_COMMA 51 #define KEY_DOT 52 #define KEY_SLASH 53 #define KEY_RIGHTSHIFT 54 #define KEY_KPASTERISK 55 ...
And it has proven to be very useful. I'd rather opt to just remove the TEGRA_ prefix from all the above, and that we try to create some common sematics to these calls.
Hmm. Keys seem to have a bit more uniform behavior than the various pin configuration data. Still, I guess I'm fine defining some unified numbering space for all the parameters, so long as we can add Soc-specific entries to the list when they don't match anything from other SoCs.
Data being a plain u32 rather than a pointer as your v7 patchset had it:
Actually it looked like this:
static inline int pinmux_config(struct pinmux *pmx, u16 param, unsigned long *data)
That was supposed to be an unsigned long (not a *pointer), which is exchangeable to pointer, as per the example known from interrupt handlers. It can also be used to pass a plain argument. It was designed to be "ioctl()-like".
So I prefer we say: int (*pin_config)(unsigned pin, u32 param, unsigned long data); int (*group_config)(const char *group, u32 param, unsigned long data);
For the data function parameter, that's the same as my proposal, except for "unsigned long" rather than "u32".
...
Now let's suppose that we've enhanced the mapping table to support pin/ group_config values, and that a driver is written to expect a pinmux mapping table with the following mappings:
"active" "suspend"
I'm not following why this should be different mappings.
I would rather contrast it with the similar concept from the regulator framework, these have modes like these:
enum regulator_status { REGULATOR_STATUS_OFF, REGULATOR_STATUS_ON, REGULATOR_STATUS_ERROR, /* fast/normal/idle/standby are flavors of "on" */ REGULATOR_STATUS_FAST, REGULATOR_STATUS_NORMAL, REGULATOR_STATUS_IDLE, REGULATOR_STATUS_STANDBY, };
So I think we should have pin group states in a similar manner:
enum pinmux_state { PINMUX_STATE_DEFAULT, /* == active */ PINMUX_STATE_LOWPOWER, };
And associated calls:
pinmux_set_state(const char *group, enum pingroup_state state);
I don't think the pinctrl SoC driver could define what the param values are for such a set of states; the set of parameters to vary, and the values to set them to, is most likely board-specific.
Now, a board probably could define such a set of "states". Perhaps we'd end up with the board supplying both a mapping table, and a "config states" table. I suppose if the APIs to change pin config params between states is separate from the API to acquire ownership of the pins and set pin mux, as you proposed later in your email, then having two tables does make some sense.
Where the only difference between those two mappings is some pin/ group_config value. When switching between those two settings, the "active" mux values will be rolled back to some "safe" values, then the "suspend" mux values will be re-programmed. This may cause spurious changes in output signals, depending on what the "safe" function is exactly. It might even temporarily change some pins from inputs to outputs.
A pinmux_set_state() function all the way down to the driver could handle this I think.
Such a function would handle changing config params just fine.
However, what if you want to change between mux settings without going via any intermediate "safe" mux settings?
That was the main reason I suggested putting both the mux and config values into the same mapping table, so either or both could be switched using the same state-switching API.
If this has to follow some specific order like first go from group A -> B -> C should probably be handled in the driver since that's definately HW-specific, else we start embedding some scripting engine in the pinctrl core and that would be most unfortunate (IMO).
I'm not sure if the driver is the place to make the decision; I think it would be board-specific; any requirements for this are driven by what is connected to the pins in question on a particular board, and hence which functions conflict with the connected HW, and that's something only the board-specific mapping table could know about. Oh, and the issue is more that we'd want to go straight from A -> B and not A -> SAFE -> B, where SAFE would be a requirement if we had to disable(A) enable(B) rather than just having A selected, then calling switch_to(B).
I did wonder while writing my original email if the mapping table should become a sequence of instructions rather than an unordered list of settings. I don't see a need for conditionals, loops, functions, or anything more than just an ordered sequence of mux or config settings though.
On Tue, Oct 18, 2011 at 8:02 PM, Stephen Warren swarren@nvidia.com wrote:
[Me]
- The need to configure per-pin "stuff" like biasing, driving,
load capacitance ... whatever
I sent of a proposal for this so we get somewhere...
- The need to handle state transitions of pinmux settings.
Still uncertain about this.
Do you mean int (*group_config)(const char *group, u32 param, u32 data);
On the latter one? We identify groups by name mainly. The selectors is an internal thing between pinctrl core and drivers.
That was a proposal for the core->driver API, so I think using an int instead of a string makes sense?
Yes, sorry, I was wrong.
I'd rather opt to just remove the TEGRA_ prefix from all the above, and that we try to create some common sematics to these calls.
Hmm. Keys seem to have a bit more uniform behavior than the various pin configuration data. Still, I guess I'm fine defining some unified numbering space for all the parameters, so long as we can add Soc-specific entries to the list when they don't match anything from other SoCs.
There is such an option but after looking it over I think we can actually unify the stuff quite a bit. For example I notice terminology like setting a pin "floating", "tristate", "high-z" etc, basically mean the same thing: high impedance, i.e. disconnect it.
Check the patch I just sent out for reference.
So I prefer we say: int (*pin_config)(unsigned pin, u32 param, unsigned long data); int (*group_config)(const char *group, u32 param, unsigned long data);
For the data function parameter, that's the same as my proposal, except for "unsigned long" rather than "u32".
Yep!
So I think we should have pin group states in a similar manner:
enum pinmux_state { PINMUX_STATE_DEFAULT, /* == active */ PINMUX_STATE_LOWPOWER, };
And associated calls:
pinmux_set_state(const char *group, enum pingroup_state state);
I don't think the pinctrl SoC driver could define what the param values are for such a set of states; the set of parameters to vary, and the values to set them to, is most likely board-specific.
Controller-specific and board specific. I do not intend to enumerate all the possible states of the *system* just of the pins of the pin controller.
Now, a board probably could define such a set of "states". Perhaps we'd end up with the board supplying both a mapping table, and a "config states" table.
Pinmux config states rather than pingroup states I think. For setting individual pins and groups of pins we need something else.
I suppose if the APIs to change pin config params between states is separate from the API to acquire ownership of the pins and set pin mux, as you proposed later in your email, then having two tables does make some sense.
Well yes, now I am worried that we're confusing generic pin or pin group configuration (say biasing and such) with pinmux states.
pinmux settings likely have power states too - like often you want to decouple the pins from some SDIO bus, turn them into regular GPIO and ground them when you go to sleep. (Reverse on the way up to running.) This could be done with pinmux states, possibly implemented by using pin groups etc in the pin controller driver.
One abstraction is to create pin group states, then also have pinmux states that reuse those group states on it's assigned group(s).
However, what if you want to change between mux settings without going via any intermediate "safe" mux settings?
That was the main reason I suggested putting both the mux and config values into the same mapping table, so either or both could be switched using the same state-switching API.
If this has to follow some specific order like first go from group A -> B -> C should probably be handled in the driver since that's definately HW-specific, else we start embedding some scripting engine in the pinctrl core and that would be most unfortunate (IMO).
I'm not sure if the driver is the place to make the decision; I think it would be board-specific; (...)
I am aware of the problem, but for the moment I feel strongly that state transitions is a problem for the individual drivers, albeit in their way of handling a particular board.
(We have a similar problem in Nomadik-gpio actually.)
If the drivers need help with state transition it should be in the form of some pincontrol helper, and platform data passed directly into the pin controller driver, not to the core.
But I have not formulated some final opinion on this or something like that, so let's keep the subject open.
I did wonder while writing my original email if the mapping table should become a sequence of instructions rather than an unordered list of settings. I don't see a need for conditionals, loops, functions, or anything more than just an ordered sequence of mux or config settings though.
I think the term used for this kind of things is "jam table interpreter".
Ref: Hacking the Xbox: an introduction to reverse engineering by Andrew Huang:
"A jam table is industry vernacular for a table of values that contains opcodes for reads, writes and simple decision operations, used in the context of hardware initializations".
Something like that, or close. But it's a complex thing and I'd prefer to keep it as close to the actual hardware as possible, since I currently have not clue on how generic this problem will be.
Yours, Linus Walleij