[PATCH] i2c: fsi: Create busses for all ports
Eddie James
eajames at linux.ibm.com
Wed Jun 5 08:57:34 AEST 2019
On 6/4/19 1:14 AM, Oliver wrote:
> On Tue, Jun 4, 2019 at 12:15 AM Eddie James <eajames at linux.ibm.com> wrote:
>>
>> On 6/3/19 12:57 AM, Oliver O'Halloran wrote:
>>> Currently we only create an I2C bus for the ports listed in the
>>> device-tree for that master. There's no real reason for this since
>>> we can discover the number of ports the master supports by looking
>>> at the port_max field of the status register.
>>>
>>> This patch re-works the bus add logic so that we always create buses
>>> for each port, unless the bus is marked as unavailable in the DT. This
>>> is useful since it ensures that all the buses provided by the CFAM I2C
>>> master are accessible to debug tools.
>>>
>>> Cc: Eddie James <eajames at linux.vnet.ibm.com>
>>> Signed-off-by: Oliver O'Halloran <oohall at gmail.com>
>>> ---
>>> drivers/i2c/busses/i2c-fsi.c | 30 +++++++++++++++++++++++++-----
>>> 1 file changed, 25 insertions(+), 5 deletions(-)
>>>
>>> diff --git a/drivers/i2c/busses/i2c-fsi.c b/drivers/i2c/busses/i2c-fsi.c
>>> index 1e2be2219a60..59a76c6e31ad 100644
>>> --- a/drivers/i2c/busses/i2c-fsi.c
>>> +++ b/drivers/i2c/busses/i2c-fsi.c
>>> @@ -658,13 +658,27 @@ static const struct i2c_algorithm fsi_i2c_algorithm = {
>>> .functionality = fsi_i2c_functionality,
>>> };
>>>
>>> +static device_node *fsi_i2c_find_port_of_node(struct device_node *master,
>>> + int port)
> Turns out I had a pile of compile fixes staged but not committed so
> this patch is totally broken. Oops.
>
>>> +{
>>> + struct device_node *np;
>>> +
>>> + for_each_child_of_node(fsi, np) {
>>> + rc = of_property_read_u32(np, "reg", &port_no);
>>> + if (!rc && port_no == port)
>>> + return np;
>>> + }
>>> +
>>> + return NULL;
>>> +}
>>> +
>>> static int fsi_i2c_probe(struct device *dev)
>>> {
>>> struct fsi_i2c_master *i2c;
>>> struct fsi_i2c_port *port;
>>> struct device_node *np;
>>> + u32 port_no, ports, stat;
>>> int rc;
>>> - u32 port_no;
>>>
>>> i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL);
>>> if (!i2c)
>>> @@ -678,10 +692,16 @@ static int fsi_i2c_probe(struct device *dev)
>>> if (rc)
>>> return rc;
>>>
>>> - /* Add adapter for each i2c port of the master. */
>>> - for_each_available_child_of_node(dev->of_node, np) {
>>> - rc = of_property_read_u32(np, "reg", &port_no);
>>> - if (rc || port_no > USHRT_MAX)
>>> + rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_STAT, &state);
>>> + if (rc)
>>> + return rc;
>>> +
>>> + ports = FIELD_GET(I2C_STAT_MAX_PORT, stat);
>>> + dev_dbg(dev, "I2C master has %d ports\n", ports);
>>
>> Thanks for the patch Oliver. This looks great except some older CFAM
>> types don't report the max port number, in which case this would not
>> probe up any ports. So we probably need a fallback to dts if the max
>> ports is 0.
> Hmm, The oldest CFAM spec I could find was v1.2 which is from the p6
> era and it includes the MAX_PORT field. When I was checking the spec I
> noticed that I mis-interpreted the meaning of MAX_PORT. It's actually
> the largest value you can write into the port field of the mode
> register rather than the number of ports the master supports. So zero
> is a valid value for MAX_PORT that you would see if the master only
> has one port.
Yep, now that I look at the specs too, that is correct.
>
> Do you know if the old masters only had one port? If not, do you know
> what version (from the ext status reg) of the master doesn't support
> the max_port field?
I used to have some more up-to-date specs but I can't seem to find
them... I think I see what's going on. Some versions of the CFAM have
the max port, or "upper threshold for ports" at bits 16-19, while others
have that information at 9-15 or 12-15... I'm not sure we can reliably
determine where/what that number will be. I'm open to suggestions!
Thanks,
Eddie
>
>
>> Thanks,
>>
>> Eddie
>>
>>
>>> +
>>> + for (port_no = 0; port_no < ports; port_no++) {
>>> + np = fsi_i2c_find_port_of_node(dev.of_node, port_no);
>>> + if (np && !of_device_is_available(np))
>>> continue;
>>>
>>> port = kzalloc(sizeof(*port), GFP_KERNEL);
More information about the openbmc
mailing list