[PATCH linux v3 16/18] drivers/fsi: Set up CFAMs for communication

Jeremy Kerr jk at ozlabs.org
Wed Oct 12 11:34:39 AEDT 2016


Hi Chris,

> Issue break command to reset CFAM logic and set ID as appropriate
> for a particular master type.  Begin definition of the slave
> engine register set and accessors.
> 
> V3 - Remove definition of BREAK command from fsi-master.h
> 
>    - Remove definitions of fsi_master_fake for set_smode and
>      break
> 
>    - Remove master->set_smode master dependent function and
>      moved to a generic base master set_smode.
> 
>    - Add fsi_master_link_enable with master type dependencies
> 
> Signed-off-by: Chris Bostic <cbostic at us.ibm.com>

Looking better, I still have a few comments though:

The most significant part of this patch is to add the send_break and
link_enable callbacks, but we're also adding the smode setup. Because of
that, I'd suggest splitting this into two:

 - one patch to update the fsi_master API to add the new callbacks, and
   their implementations; and

 - another patch to do the cfam setup

> +/*
> + * Issue a break commad on this link

 *command

> + */
> +static int fsi_master_break(struct fsi_master *master, int link)
> +{
> +	int rc = 0;
> +
> +	if (master->send_break)
> +		rc = master->send_break(master, link);
> +
> +	return rc;
> +}
> +
> +static void set_smode_defaults(struct fsi_master *master, uint32_t *smode)
> +{
> +	*smode = FSI_SMODE_WSC | FSI_SMODE_ECRC
> +		| fsi_smode_echodly(0xf) | fsi_smode_senddly(0xf)
> +		| fsi_smode_lbcrr(1) | fsi_smode_sid(0);
> +}

I assume that the smode value will depend on the master later, hence the
need for a function for this (otherwise we'd just want a const
uint32_t). However, can you just return the smode rather than setting a
pointer and returning void?

> +static int fsi_master_set_smode(struct fsi_master *master, int link)
> +{
> +	uint32_t smode;
> +	int rc;
> +
> +	set_smode_defaults(master, &smode);
> +	rc = master->write(master, link, 0, FSI_SLAVE_BASE + FSI_SMODE,
> +			&smode, sizeof(smode));
> +
> +	return rc;
> +}
> +

On reading this a little further, I'm a little confused about whether
the smode register is part of the master or part of a slave. I've
assumed the latter (as there are no registers on a GPIO master), but
wouldn't that need to know the slave ID or base address?

[Or is the absence of that a factor of only supporting one slave per
link at the moment? If that's the case, can you rename this to
fsi_slave_set_smode, and add the slave ID parameter that we'll need
later?  That will clarify things a bit]

>  static int fsi_slave_init(struct fsi_master *master,
>  		int link, uint8_t slave_id)
>  {
> -	struct fsi_slave *slave;
> +	struct fsi_slave *slave = NULL;
>  	uint32_t chip_id;
>  	int rc;
>  
> +	/*
> +	 * todo: Due to CFAM hardware issues related to BREAK commands we're
> +	 * limited to only one CFAM per link. Once hardware fixes are available
> +	 * this restriction can be removed.
> +	 */
> +	if (slave_id > 0)
> +		return 0;
> +
> +	rc = fsi_master_break(master, link);
> +	if (rc) {
> +		dev_warn(master->dev, "no slave detected at %02x:%02x\n",
> +				link, slave_id);
> +		return -ENODEV;
> +	}

Shoudln't we do the break as part of a master init (and then build
slave IDs)? Seeing as it will reset the slave IDs, this operation can't
be confined to only a single slave (as the name slave_init would imply.

> +
> +	rc = fsi_master_set_smode(master, link);
> +	if (rc) {
> +		dev_warn(master->dev, "failed to set smode id, rc:%d\n", rc);
> +		return -ENODEV;
> +	}
> +

You'll probably be better returning rc for both of these cases, no need
to squash it to ENODEV (and if you do, EIO might be more appropriate).

>  /* FSI master support */
>  
> +static int fsi_master_link_enable(struct fsi_master *master, int link)
> +{
> +	int rc;
> +
> +	if (master->link_enable)
> +		rc = master->link_enable(master, link);
> +
> +	return rc;
> +}
> +

OK, looks good for a link_enable function of the masters. However, can
you add the new callbacks (link_enable & send_break) and their wrappers
in a separate earlier patch?

>  static int fsi_master_scan(struct fsi_master *master)
>  {
> -	int link, slave_id;
> +	int link, slave_id, rc;
> +
> +	for (link = 0; link < master->n_links; link++) {
> +		rc = fsi_master_link_enable(master, link);
> +		if (rc)
> +			continue;

Shouldn't we fail on that?

>  
> -	for (link = 0; link < master->n_links; link++)
>  		for (slave_id = 0; slave_id < FSI_N_SLAVES; slave_id++)
>  			fsi_slave_init(master, link, slave_id);
> +	}
>  
>  	return 0;
>  
> diff --git a/drivers/fsi/fsi-master-fake.c b/drivers/fsi/fsi-master-fake.c
> index ec1ed5e..c7ad631 100644
> --- a/drivers/fsi/fsi-master-fake.c
> +++ b/drivers/fsi/fsi-master-fake.c
> @@ -63,6 +63,8 @@ static int fsi_master_fake_probe(struct platform_device *pdev)
>  	master->n_links = 1;
>  	master->read = fsi_master_fake_read;
>  	master->write = fsi_master_fake_write;
> +	master->send_break = NULL;
> +	master->link_enable = NULL;

master is kzalloc()ed, no need to set to NULL.

> +/*
> + * Issue a break command on link
> + */
> +static int fsi_master_gpio_break(struct fsi_master *_master, int link)
> +{
> +	struct fsi_master_gpio *master = to_fsi_master_gpio(_master);
> +
> +	if (link != 0)
> +		return -ENODEV;
> +
> +	/* todo: send the break pattern over gpio */
> +	(void)master;
> +
> +	return 0;
> +}
> +
> +static int fsi_master_gpio_link_enable(struct fsi_master *_master, int link)
> +{
> +	struct fsi_master_gpio *master = to_fsi_master_gpio(_master);
> +
> +	if (link != 0)
> +		return -ENODEV;
> +
> +	/* todo: set the enable pin */
> +	(void)master;
> +
> +	return 0;
> +}
> +

Looks good.

> diff --git a/drivers/fsi/fsi-slave.h b/drivers/fsi/fsi-slave.h
> new file mode 100644
> index 0000000..ea7a760
> --- /dev/null
> +++ b/drivers/fsi/fsi-slave.h
> @@ -0,0 +1,62 @@
> +/*
> + * FSI slave engine definitions.
> + *

Why does this need to be in a header file? Isn't it only used by the FSI
core?

Cheers,


Jeremy


More information about the openbmc mailing list