Re: [PATCH 0/4] occ: fsi and hwmon: Fixes for polling un-initialized OCC
On Tue, 2021-02-09 at 11:12 -0600, Eddie James wrote: > In the event that the OCC is not initialized when the driver sends a > poll > command, the driver may receive an invalid response. This isn't an > error > condition unless there is no valid response before the timeout > expires. So > change the starting sequence number and check for the un-initialized > OCC > state before returning the response in order to detect this condition > and > continue waiting if necessary. Hi Joel, Do you have any comments on the FSI side of this series? Thanks, Eddie > > Eddie James (4): > fsi: occ: Don't accept response from un-initialized OCC > fsi: occ: Log error for checksum failure > hwmon: (occ) Start sequence number at one > hwmon: (occ) Print response status in first poll error message > > drivers/fsi/fsi-occ.c | 11 --- > drivers/hwmon/occ/common.c | 7 +-- > 2 files changed, 13 insertions(+), 5 deletions(-) >
[PATCH] net/ncsi: Avoid channel_monitor hrtimer deadlock
From: Milton Miller Calling ncsi_stop_channel_monitor from channel_monitor is a guaranteed deadlock on SMP because stop calls del_timer_sync on the timer that inoked channel_monitor as its timer function. Recognise the inherent race of marking the monitor disabled before deleting the timer by just returning if enable was cleared. After a timeout (the default case -- reset to START when response received) just mark the monitor.enabled false. If the channel has an entrie on the channel_queue list, or if the state is not ACTIVE or INACTIVE, then warn and mark the timer stopped and don't restart, as the locking is broken somehow. Fixes: 0795fb2021f0 ("net/ncsi: Stop monitor if channel times out or is inactive") Signed-off-by: Milton Miller Signed-off-by: Eddie James --- net/ncsi/ncsi-manage.c | 20 +--- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c index a9cb355324d1..8da707b8 100644 --- a/net/ncsi/ncsi-manage.c +++ b/net/ncsi/ncsi-manage.c @@ -105,13 +105,20 @@ static void ncsi_channel_monitor(struct timer_list *t) monitor_state = nc->monitor.state; spin_unlock_irqrestore(>lock, flags); - if (!enabled || chained) { - ncsi_stop_channel_monitor(nc); - return; - } + if (!enabled) + return; /* expected race disabling timer */ + if (WARN_ON_ONCE(chained)) + goto bad_state; + if (state != NCSI_CHANNEL_INACTIVE && state != NCSI_CHANNEL_ACTIVE) { - ncsi_stop_channel_monitor(nc); +bad_state: + netdev_warn(ndp->ndev.dev, + "Bad NCSI monitor state channel %d 0x%x %s queue\n", + nc->id, state, chained ? "on" : "off"); + spin_lock_irqsave(>lock, flags); + nc->monitor.enabled = false; + spin_unlock_irqrestore(>lock, flags); return; } @@ -136,10 +143,9 @@ static void ncsi_channel_monitor(struct timer_list *t) ncsi_report_link(ndp, true); ndp->flags |= NCSI_DEV_RESHUFFLE; - ncsi_stop_channel_monitor(nc); - ncm = >modes[NCSI_MODE_LINK]; spin_lock_irqsave(>lock, flags); + nc->monitor.enabled = false; nc->state = NCSI_CHANNEL_INVISIBLE; ncm->data[2] &= ~0x1; spin_unlock_irqrestore(>lock, flags); -- 2.27.0
[PATCH] fsi: scom: Reset the FSI2PIB engine for any error
The error bits in the FSI2PIB status are only cleared by a reset. So the driver needs to perform a reset after seeing any of the FSI2PIB errors, otherwise subsequent operations will also look like failures. Fixes: 6b293258cded ("fsi: scom: Major overhaul") Signed-off-by: Eddie James --- drivers/fsi/fsi-scom.c | 16 +--- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/fsi/fsi-scom.c b/drivers/fsi/fsi-scom.c index b45bfab7b7f5..75d1389e2626 100644 --- a/drivers/fsi/fsi-scom.c +++ b/drivers/fsi/fsi-scom.c @@ -38,9 +38,10 @@ #define SCOM_STATUS_PIB_RESP_MASK 0x7000 #define SCOM_STATUS_PIB_RESP_SHIFT 12 -#define SCOM_STATUS_ANY_ERR(SCOM_STATUS_PROTECTION | \ -SCOM_STATUS_PARITY | \ -SCOM_STATUS_PIB_ABORT | \ +#define SCOM_STATUS_FSI2PIB_ERROR (SCOM_STATUS_PROTECTION | \ +SCOM_STATUS_PARITY | \ +SCOM_STATUS_PIB_ABORT) +#define SCOM_STATUS_ANY_ERR(SCOM_STATUS_FSI2PIB_ERROR |\ SCOM_STATUS_PIB_RESP_MASK) /* SCOM address encodings */ #define XSCOM_ADDR_IND_FLAGBIT_ULL(63) @@ -240,13 +241,14 @@ static int handle_fsi2pib_status(struct scom_device *scom, uint32_t status) { uint32_t dummy = -1; - if (status & SCOM_STATUS_PROTECTION) - return -EPERM; - if (status & SCOM_STATUS_PARITY) { + if (status & SCOM_STATUS_FSI2PIB_ERROR) fsi_device_write(scom->fsi_dev, SCOM_FSI2PIB_RESET_REG, , sizeof(uint32_t)); + + if (status & SCOM_STATUS_PROTECTION) + return -EPERM; + if (status & SCOM_STATUS_PARITY) return -EIO; - } /* Return -EBUSY on PIB abort to force a retry */ if (status & SCOM_STATUS_PIB_ABORT) return -EBUSY; -- 2.27.0
Re: [PATCH] spi: fsi: Remove multiple sequenced ops for restricted chips
On Thu, 2021-03-25 at 13:50 +, Mark Brown wrote: > On Wed, Mar 24, 2021 at 05:05:16PM -0500, Eddie James wrote: > > > Updated restricted chips have trouble processing multiple sequenced > > operations. So remove the capability to sequence multiple > > operations and > > reduce the maximum transfer size to 8 bytes. > > That's a very small limit, it would be nice to be able to identify > devices that can use the larger limit so they don't suffer > needlessly. Yes, this is only for the "restricted" controllers which are marked by a different compatible string. I guess the commit message isn't perfectly clear. Thanks, Eddie
[PATCH] spi: fsi: Remove multiple sequenced ops for restricted chips
Updated restricted chips have trouble processing multiple sequenced operations. So remove the capability to sequence multiple operations and reduce the maximum transfer size to 8 bytes. Signed-off-by: Eddie James --- drivers/spi/spi-fsi.c | 27 +++ 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/drivers/spi/spi-fsi.c b/drivers/spi/spi-fsi.c index 3920cd3286d8..de359718e816 100644 --- a/drivers/spi/spi-fsi.c +++ b/drivers/spi/spi-fsi.c @@ -26,7 +26,7 @@ #define SPI_FSI_BASE 0x7 #define SPI_FSI_INIT_TIMEOUT_MS1000 #define SPI_FSI_MAX_XFR_SIZE 2048 -#define SPI_FSI_MAX_XFR_SIZE_RESTRICTED32 +#define SPI_FSI_MAX_XFR_SIZE_RESTRICTED8 #define SPI_FSI_ERROR 0x0 #define SPI_FSI_COUNTER_CFG0x1 @@ -265,14 +265,12 @@ static int fsi_spi_sequence_transfer(struct fsi_spi *ctx, struct fsi_spi_sequence *seq, struct spi_transfer *transfer) { - bool docfg = false; int loops; int idx; int rc; u8 val = 0; u8 len = min(transfer->len, 8U); u8 rem = transfer->len % len; - u64 cfg = 0ULL; loops = transfer->len / len; @@ -292,28 +290,17 @@ static int fsi_spi_sequence_transfer(struct fsi_spi *ctx, return -EINVAL; } - if (ctx->restricted) { - const int eidx = rem ? 5 : 6; - - while (loops > 1 && idx <= eidx) { - idx = fsi_spi_sequence_add(seq, val); - loops--; - docfg = true; - } - - if (loops > 1) { - dev_warn(ctx->dev, "No sequencer slots; aborting.\n"); - return -EINVAL; - } + if (ctx->restricted && loops > 1) { + dev_warn(ctx->dev, +"Transfer too large; no branches permitted.\n"); + return -EINVAL; } if (loops > 1) { + u64 cfg = SPI_FSI_COUNTER_CFG_LOOPS(loops - 1); + fsi_spi_sequence_add(seq, SPI_FSI_SEQUENCE_BRANCH(idx)); - docfg = true; - } - if (docfg) { - cfg = SPI_FSI_COUNTER_CFG_LOOPS(loops - 1); if (transfer->rx_buf) cfg |= SPI_FSI_COUNTER_CFG_N2_RX | SPI_FSI_COUNTER_CFG_N2_TX | -- 2.27.0
[PATCH] fsi: Aspeed: Reduce poll timeout
The lengthy timeout previously used sometimes resulted in scheduling problems, detailed below. Therefore reduce the timeout to 500us. This timeout selection is supported by the benchmarks collected below with various clock dividers. This is purely the time spent polling (reported by ktime_get()). div 1: max:150us avg: 2us div 2: max:155us avg: 3us div 4: max:149us avg: 7us div 8: max:153us avg: 13us div 16: max:197us avg: 21us div 32: max:181us avg: 50us div 64: max:262us avg:100us Jan 22 01:27:21 rain27bmc kernel: rcu: INFO: rcu_sched self-detected stall on CPU Jan 22 01:27:21 rain27bmc kernel: rcu: 0-: (2099 ticks this GP) idle=0ca/1/0x4002 softirq=349573/349573 fqs=1048 Jan 22 01:27:21 rain27bmc kernel: (t=2100 jiffies g=841149 q=7163) Jan 22 01:27:21 rain27bmc kernel: NMI backtrace for cpu 0 Jan 22 01:27:21 rain27bmc kernel: CPU: 0 PID: 5959 Comm: ibm-read-vpd Not tainted 5.8.17-a9b4ea8 #1 Jan 22 01:27:21 rain27bmc kernel: Hardware name: Generic DT based system Jan 22 01:27:21 rain27bmc kernel: Backtrace: Jan 22 01:27:25 rain27bmc kernel: [<8010d92c>] (dump_backtrace) from [<8010db80>] (show_stack+0x20/0x24) ... Jan 22 01:27:25 rain27bmc kernel: [<8010130c>] (gic_handle_irq) from [<80100b0c>] (__irq_svc+0x6c/0x90) Jan 22 01:27:25 rain27bmc kernel: Exception stack(0xb79159b0 to 0xb79159f8) Jan 22 01:27:25 rain27bmc kernel: 59a0: 9e88e5d5 0559 0559 0018 Jan 22 01:27:25 rain27bmc kernel: 59c0: 9f217c55 0003 0559 a0201c00 bfa4d048 bfa4d000 b7915a44 Jan 22 01:27:25 rain27bmc kernel: 59e0: 40e88f8a b7915a00 3254e553 80734924 80030113 Jan 22 01:27:25 rain27bmc kernel: r9:b7914000 r8:a0201c00 r7:b79159e4 r6: r5:80030113 r4:80734924 Jan 22 01:27:25 rain27bmc kernel: [<807348b4>] (__opb_read) from [<80734d98>] (aspeed_master_read+0xbc/0xcc) Jan 22 01:27:25 rain27bmc kernel: r10:0004 r9:0002 r8:80734cdc r7:bd33fa40 r6:0004 r5:bd33f840 Jan 22 01:27:25 rain27bmc kernel: r4:00201c00 Jan 22 01:27:25 rain27bmc kernel: [<80734cdc>] (aspeed_master_read) from [<807320f0>] (fsi_master_read+0x6c/0x1bc) ... Signed-off-by: Eddie James --- drivers/fsi/fsi-master-aspeed.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/fsi/fsi-master-aspeed.c b/drivers/fsi/fsi-master-aspeed.c index 90dbe58ca1ed..03c61e50b299 100644 --- a/drivers/fsi/fsi-master-aspeed.c +++ b/drivers/fsi/fsi-master-aspeed.c @@ -92,7 +92,7 @@ static const u32 fsi_base = 0xa000; static u16 aspeed_fsi_divisor = FSI_DIVISOR_DEFAULT; module_param_named(bus_div,aspeed_fsi_divisor, ushort, 0); -#define OPB_POLL_TIMEOUT 1 +#define OPB_POLL_TIMEOUT 500 static int __opb_write(struct fsi_master_aspeed *aspeed, u32 addr, u32 val, u32 transfer_size) -- 2.27.0
[PATCH 4/4] hwmon: (occ) Print response status in first poll error message
In order to better debug problems starting up the driver, print the response status from the OCC in the error logged when the first poll command fails. Signed-off-by: Eddie James --- drivers/hwmon/occ/common.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/occ/common.c b/drivers/hwmon/occ/common.c index ee0c5d12dfdf..f71d62b57468 100644 --- a/drivers/hwmon/occ/common.c +++ b/drivers/hwmon/occ/common.c @@ -1161,8 +1161,9 @@ int occ_setup(struct occ *occ, const char *name) dev_info(occ->bus_dev, "host is not ready\n"); return rc; } else if (rc < 0) { - dev_err(occ->bus_dev, "failed to get OCC poll response: %d\n", - rc); + dev_err(occ->bus_dev, + "failed to get OCC poll response=%02x: %d\n", + occ->resp.return_status, rc); return rc; } -- 2.27.0
[PATCH 3/4] hwmon: (occ) Start sequence number at one
Initialize the sequence number at one, rather than zero, in order to prevent false matches with the zero-initialized OCC SRAM buffer before the OCC is fully initialized. Signed-off-by: Eddie James --- drivers/hwmon/occ/common.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/hwmon/occ/common.c b/drivers/hwmon/occ/common.c index 7a5e539b567b..ee0c5d12dfdf 100644 --- a/drivers/hwmon/occ/common.c +++ b/drivers/hwmon/occ/common.c @@ -1150,6 +1150,8 @@ int occ_setup(struct occ *occ, const char *name) { int rc; + /* start with 1 to avoid false match with zero-initialized SRAM buffer */ + occ->seq_no = 1; mutex_init(>lock); occ->groups[0] = >group; -- 2.27.0
[PATCH 2/4] fsi: occ: Log error for checksum failure
Log an error if the response checksum doesn't match the calculated checksum. Signed-off-by: Eddie James --- drivers/fsi/fsi-occ.c | 10 +++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/fsi/fsi-occ.c b/drivers/fsi/fsi-occ.c index cb05b6dacc9d..524460995465 100644 --- a/drivers/fsi/fsi-occ.c +++ b/drivers/fsi/fsi-occ.c @@ -223,7 +223,8 @@ static const struct file_operations occ_fops = { .release = occ_release, }; -static int occ_verify_checksum(struct occ_response *resp, u16 data_length) +static int occ_verify_checksum(struct occ *occ, struct occ_response *resp, + u16 data_length) { /* Fetch the two bytes after the data for the checksum. */ u16 checksum_resp = get_unaligned_be16(>data[data_length]); @@ -238,8 +239,11 @@ static int occ_verify_checksum(struct occ_response *resp, u16 data_length) for (i = 0; i < data_length; ++i) checksum += resp->data[i]; - if (checksum != checksum_resp) + if (checksum != checksum_resp) { + dev_err(occ->dev, "Bad checksum: %04x!=%04x\n", checksum, + checksum_resp); return -EBADMSG; + } return 0; } @@ -533,7 +537,7 @@ int fsi_occ_submit(struct device *dev, const void *request, size_t req_len, } *resp_len = resp_data_length + 7; - rc = occ_verify_checksum(resp, resp_data_length); + rc = occ_verify_checksum(occ, resp, resp_data_length); done: mutex_unlock(>occ_lock); -- 2.27.0
[PATCH 0/4] occ: fsi and hwmon: Fixes for polling un-initialized OCC
In the event that the OCC is not initialized when the driver sends a poll command, the driver may receive an invalid response. This isn't an error condition unless there is no valid response before the timeout expires. So change the starting sequence number and check for the un-initialized OCC state before returning the response in order to detect this condition and continue waiting if necessary. Eddie James (4): fsi: occ: Don't accept response from un-initialized OCC fsi: occ: Log error for checksum failure hwmon: (occ) Start sequence number at one hwmon: (occ) Print response status in first poll error message drivers/fsi/fsi-occ.c | 11 --- drivers/hwmon/occ/common.c | 7 +-- 2 files changed, 13 insertions(+), 5 deletions(-) -- 2.27.0
[PATCH 1/4] fsi: occ: Don't accept response from un-initialized OCC
If the OCC is not initialized and responds as such, the driver should continue waiting for a valid response until the timeout expires. Signed-off-by: Eddie James --- drivers/fsi/fsi-occ.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/fsi/fsi-occ.c b/drivers/fsi/fsi-occ.c index 10ca2e290655..cb05b6dacc9d 100644 --- a/drivers/fsi/fsi-occ.c +++ b/drivers/fsi/fsi-occ.c @@ -495,6 +495,7 @@ int fsi_occ_submit(struct device *dev, const void *request, size_t req_len, goto done; if (resp->return_status == OCC_RESP_CMD_IN_PRG || + resp->return_status == OCC_RESP_CRIT_INIT || resp->seq_no != seq_no) { rc = -ETIMEDOUT; -- 2.27.0
[PATCH v2 1/2] hwmon: (pmbus) Add a PMBUS_NO_CAPABILITY platform data flag
Some PMBus chips don't respond with valid data when reading the CAPABILITY register. Add a flag that device drivers can set so that the PMBus core driver doesn't use CAPABILITY to determine it's behavior. Signed-off-by: Eddie James --- drivers/hwmon/pmbus/pmbus_core.c | 8 +--- include/linux/pmbus.h| 9 + 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index 192442b3b7a2..906c9fec9cce 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -2204,9 +2204,11 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data, } /* Enable PEC if the controller supports it */ - ret = i2c_smbus_read_byte_data(client, PMBUS_CAPABILITY); - if (ret >= 0 && (ret & PB_CAPABILITY_ERROR_CHECK)) - client->flags |= I2C_CLIENT_PEC; + if (!(data->flags & PMBUS_NO_CAPABILITY)) { + ret = i2c_smbus_read_byte_data(client, PMBUS_CAPABILITY); + if (ret >= 0 && (ret & PB_CAPABILITY_ERROR_CHECK)) + client->flags |= I2C_CLIENT_PEC; + } /* * Check if the chip is write protected. If it is, we can not clear diff --git a/include/linux/pmbus.h b/include/linux/pmbus.h index 1ea5bae708a1..12cbbf305969 100644 --- a/include/linux/pmbus.h +++ b/include/linux/pmbus.h @@ -34,6 +34,15 @@ */ #define PMBUS_WRITE_PROTECTED BIT(1) +/* + * PMBUS_NO_CAPABILITY + * + * Some PMBus chips don't respond with valid data when reading the CAPABILITY + * register. For such chips, this flag should be set so that the PMBus core + * driver doesn't use CAPABILITY to determine it's behavior. + */ +#define PMBUS_NO_CAPABILITYBIT(2) + struct pmbus_platform_data { u32 flags; /* Device specific flags */ -- 2.27.0
[PATCH v2 2/2] hwmon: (pmbus/ibm-cffps) Set the PMBUS_NO_CAPABILITY flag
Several power supplies supported by the IBM CFFPS driver don't report valid data in the CAPABILITY register. This results in PEC being enabled when it's not supported by the device, and since the automatic version detection might fail, disable use of the CAPABILITY register across the board for this driver. Signed-off-by: Eddie James --- drivers/hwmon/pmbus/ibm-cffps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwmon/pmbus/ibm-cffps.c b/drivers/hwmon/pmbus/ibm-cffps.c index d6223871..ffde5aaa5036 100644 --- a/drivers/hwmon/pmbus/ibm-cffps.c +++ b/drivers/hwmon/pmbus/ibm-cffps.c @@ -472,7 +472,7 @@ static struct pmbus_driver_info ibm_cffps_info[] = { }; static struct pmbus_platform_data ibm_cffps_pdata = { - .flags = PMBUS_SKIP_STATUS_CHECK, + .flags = PMBUS_SKIP_STATUS_CHECK | PMBUS_NO_CAPABILITY, }; static int ibm_cffps_probe(struct i2c_client *client) -- 2.27.0
[PATCH v2 0/2] hwmon: (pmbus) Add the PMBUS_NO_CAPABILITY flag
Some PMBus chips, like some power supplies supported by the cffps driver, don't respond with valid data when reading the CAPABILITY register. Add a platform data flag that device drivers can set to tell the PMBus core driver that it shouldn't use the CAPABILITY register. The second patch sets this flag for the cffps driver. Changes since v1: - Rename the flag to PMBUS_NO_CAPABILITY and adjust the associated comment accordingly. Eddie James (2): hwmon: (pmbus) Add a PMBUS_NO_CAPABILITY platform data flag hwmon: (pmbus/ibm-cffps) Set the PMBUS_NO_CAPABILITY flag drivers/hwmon/pmbus/ibm-cffps.c | 2 +- drivers/hwmon/pmbus/pmbus_core.c | 8 +--- include/linux/pmbus.h| 9 + 3 files changed, 15 insertions(+), 4 deletions(-) -- 2.27.0
Re: [PATCH 1/2] hwmon: (pmbus) Add a NO_PEC flag to probe chips with faulty CAPABILITY
On Mon, 2020-12-21 at 08:54 -0800, Guenter Roeck wrote: > On 12/21/20 8:30 AM, Eddie James wrote: > > Some PMBus chips don't respond with valid data when reading the > > CAPABILITY register. For instance the register may report that the > > chip supports PEC when in reality it does not. For such chips, PEC > > must not be enabled while probing the chip, so add a flag so that > > device drivers can force PEC off. > > > > I think the flag should indicate that the capability register > shall not be read/used. That the capability register is currently > only used to check for PEC is secondary. We might,for example, > start using it to check for alert support or to check the numeric > format. OK, that makes sense. I'll rename the flag in v2, how does PMBUS_NO_CAPABILITY sound? Thanks for the quick reply, Eddie > > Thanks, > Guenter > > > Signed-off-by: Eddie James > > --- > > drivers/hwmon/pmbus/pmbus_core.c | 8 +--- > > include/linux/pmbus.h| 10 ++ > > 2 files changed, 15 insertions(+), 3 deletions(-) > > > > diff --git a/drivers/hwmon/pmbus/pmbus_core.c > > b/drivers/hwmon/pmbus/pmbus_core.c > > index 192442b3b7a2..3de1657dde35 100644 > > --- a/drivers/hwmon/pmbus/pmbus_core.c > > +++ b/drivers/hwmon/pmbus/pmbus_core.c > > @@ -2204,9 +2204,11 @@ static int pmbus_init_common(struct > > i2c_client *client, struct pmbus_data *data, > > } > > > > /* Enable PEC if the controller supports it */ > > - ret = i2c_smbus_read_byte_data(client, PMBUS_CAPABILITY); > > - if (ret >= 0 && (ret & PB_CAPABILITY_ERROR_CHECK)) > > - client->flags |= I2C_CLIENT_PEC; > > + if (!(data->flags & PMBUS_NO_PEC)) { > > + ret = i2c_smbus_read_byte_data(client, > > PMBUS_CAPABILITY); > > + if (ret >= 0 && (ret & PB_CAPABILITY_ERROR_CHECK)) > > + client->flags |= I2C_CLIENT_PEC; > > + } > > > > /* > > * Check if the chip is write protected. If it is, we can not > > clear > > diff --git a/include/linux/pmbus.h b/include/linux/pmbus.h > > index 1ea5bae708a1..9bdc8a581b03 100644 > > --- a/include/linux/pmbus.h > > +++ b/include/linux/pmbus.h > > @@ -34,6 +34,16 @@ > > */ > > #define PMBUS_WRITE_PROTECTED BIT(1) > > > > +/* > > + * PMBUS_NO_PEC > > + * > > + * Some PMBus chips don't respond with valid data when reading the > > CAPABILITY > > + * register. In this case, the register may report that the chip > > supports PEC > > + * with bit 7 (PB_CAPABILITY_ERROR_CHECK) when in reality it's not > > supported. > > + * For such chips, PEC must not be enabled before probing the > > chip. > > + */ > > +#define PMBUS_NO_PEC BIT(2) > > + > > struct pmbus_platform_data { > > u32 flags; /* Device specific flags */ > > > >
[PATCH 0/2] hwmon: (pmbus) Add a NO_PEC flag to probe chips with faulty CAPABILITY
Some PMBus chips don't respond with valid data when reading the CAPABILITY register. For instance the register may report that the chip supports PEC when in reality it does not. For such chips, PEC must not be enabled while probing the chip, so this series adds a flag that allows device drivers to force PEC off. The second patch enables this flag for the IBM CFFPS driver, which supports power supplies that report invalid in the CAPABILITY register and must therefore force PEC off. Eddie James (2): hwmon: (pmbus) Add a NO_PEC flag to probe chips with faulty CAPABILITY hwmon: (pmbus/ibm-cffps) Set the PMBUS_NO_PEC flag drivers/hwmon/pmbus/ibm-cffps.c | 2 +- drivers/hwmon/pmbus/pmbus_core.c | 8 +--- include/linux/pmbus.h| 10 ++ 3 files changed, 16 insertions(+), 4 deletions(-) -- 2.27.0
[PATCH 1/2] hwmon: (pmbus) Add a NO_PEC flag to probe chips with faulty CAPABILITY
Some PMBus chips don't respond with valid data when reading the CAPABILITY register. For instance the register may report that the chip supports PEC when in reality it does not. For such chips, PEC must not be enabled while probing the chip, so add a flag so that device drivers can force PEC off. Signed-off-by: Eddie James --- drivers/hwmon/pmbus/pmbus_core.c | 8 +--- include/linux/pmbus.h| 10 ++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index 192442b3b7a2..3de1657dde35 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -2204,9 +2204,11 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data, } /* Enable PEC if the controller supports it */ - ret = i2c_smbus_read_byte_data(client, PMBUS_CAPABILITY); - if (ret >= 0 && (ret & PB_CAPABILITY_ERROR_CHECK)) - client->flags |= I2C_CLIENT_PEC; + if (!(data->flags & PMBUS_NO_PEC)) { + ret = i2c_smbus_read_byte_data(client, PMBUS_CAPABILITY); + if (ret >= 0 && (ret & PB_CAPABILITY_ERROR_CHECK)) + client->flags |= I2C_CLIENT_PEC; + } /* * Check if the chip is write protected. If it is, we can not clear diff --git a/include/linux/pmbus.h b/include/linux/pmbus.h index 1ea5bae708a1..9bdc8a581b03 100644 --- a/include/linux/pmbus.h +++ b/include/linux/pmbus.h @@ -34,6 +34,16 @@ */ #define PMBUS_WRITE_PROTECTED BIT(1) +/* + * PMBUS_NO_PEC + * + * Some PMBus chips don't respond with valid data when reading the CAPABILITY + * register. In this case, the register may report that the chip supports PEC + * with bit 7 (PB_CAPABILITY_ERROR_CHECK) when in reality it's not supported. + * For such chips, PEC must not be enabled before probing the chip. + */ +#define PMBUS_NO_PEC BIT(2) + struct pmbus_platform_data { u32 flags; /* Device specific flags */ -- 2.27.0
[PATCH 2/2] hwmon: (pmbus/ibm-cffps) Set the PMBUS_NO_PEC flag
Several power supplies supported by the IBM CFFPS driver don't report valid data in the CAPABILITY register, or support PEC only for certain PMBus registers. Since the automatic version detection of the driver might fail on some supplies with PEC enabled, just disable PEC entirely for this driver. Signed-off-by: Eddie James --- drivers/hwmon/pmbus/ibm-cffps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwmon/pmbus/ibm-cffps.c b/drivers/hwmon/pmbus/ibm-cffps.c index d6223871..f8e3ae989e99 100644 --- a/drivers/hwmon/pmbus/ibm-cffps.c +++ b/drivers/hwmon/pmbus/ibm-cffps.c @@ -472,7 +472,7 @@ static struct pmbus_driver_info ibm_cffps_info[] = { }; static struct pmbus_platform_data ibm_cffps_pdata = { - .flags = PMBUS_SKIP_STATUS_CHECK, + .flags = PMBUS_SKIP_STATUS_CHECK | PMBUS_NO_PEC, }; static int ibm_cffps_probe(struct i2c_client *client) -- 2.27.0
[PATCH] spi: fsi: Fix transfer returning without finalizing message
In the case that the SPI mux isn't set, the transfer_one_message function returns without finalizing the message. This means that the transfer never completes, resulting in hung tasks and an eventual kernel panic. Fix it by finalizing the transfer in this case. Fixes: 9211a441e606 ("spi: fsi: Check mux status before transfers") Signed-off-by: Eddie James --- drivers/spi/spi-fsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-fsi.c b/drivers/spi/spi-fsi.c index 8a440c7078ef..3920cd3286d8 100644 --- a/drivers/spi/spi-fsi.c +++ b/drivers/spi/spi-fsi.c @@ -477,7 +477,7 @@ static int fsi_spi_transfer_one_message(struct spi_controller *ctlr, rc = fsi_spi_check_mux(ctx->fsi, ctx->dev); if (rc) - return rc; + goto error; list_for_each_entry(transfer, >transfers, transfer_list) { struct fsi_spi_sequence seq; -- 2.26.2
Re: [PATCH v3 3/5] i2c: aspeed: Mask IRQ status to relevant bits
On 9/10/20 4:00 AM, Brendan Higgins wrote: On Wed, Sep 9, 2020 at 1:31 PM Eddie James wrote: Mask the IRQ status to only the bits that the driver checks. This prevents excessive driver warnings when operating in slave mode when additional bits are set that the driver doesn't handle. Signed-off-by: Eddie James Reviewed-by: Tao Ren Sorry, looks like I didn't get my comment in in time. Looks good in principle. One minor comment below: --- drivers/i2c/busses/i2c-aspeed.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c index 31268074c422..724bf30600d6 100644 --- a/drivers/i2c/busses/i2c-aspeed.c +++ b/drivers/i2c/busses/i2c-aspeed.c @@ -69,6 +69,7 @@ * These share bit definitions, so use the same values for the enable & * status bits. */ +#define ASPEED_I2CD_INTR_RECV_MASK 0xf000 Could we define ASPEED_I2CD_INTR_RECV_MASK to be ASPEED_I2CD_INTR_ALL ? That was my original thought... there is another define for that already a few lines down though. Thanks, Eddie #define ASPEED_I2CD_INTR_SDA_DL_TIMEOUTBIT(14) #define ASPEED_I2CD_INTR_BUS_RECOVER_DONE BIT(13) #define ASPEED_I2CD_INTR_SLAVE_MATCH BIT(7) @@ -604,6 +605,7 @@ static irqreturn_t aspeed_i2c_bus_irq(int irq, void *dev_id) writel(irq_received & ~ASPEED_I2CD_INTR_RX_DONE, bus->base + ASPEED_I2C_INTR_STS_REG); readl(bus->base + ASPEED_I2C_INTR_STS_REG); + irq_received &= ASPEED_I2CD_INTR_RECV_MASK; irq_remaining = irq_received; #if IS_ENABLED(CONFIG_I2C_SLAVE) -- 2.26.2
[PATCH 1/4] dt-bindings: clock: Add AST2600 APLLdivN definition
Add a new clock definition for the "APLLdivN" as described in the AST2600 specification. This clock is simply the APLL divided by a factor defined in the SCU registers. It is the input to the FSI bus. Signed-off-by: Eddie James --- include/dt-bindings/clock/ast2600-clock.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/dt-bindings/clock/ast2600-clock.h b/include/dt-bindings/clock/ast2600-clock.h index 62b9520a00fd..5a9ae0a1d574 100644 --- a/include/dt-bindings/clock/ast2600-clock.h +++ b/include/dt-bindings/clock/ast2600-clock.h @@ -87,6 +87,7 @@ #define ASPEED_CLK_MAC2RCLK68 #define ASPEED_CLK_MAC3RCLK69 #define ASPEED_CLK_MAC4RCLK70 +#define ASPEED_CLK_APLLN 71 /* Only list resets here that are not part of a gate */ #define ASPEED_RESET_ADC 55 -- 2.26.2
[PATCH 0/4] clk: AST2600 and FSI: Add APLL to control FSI bus frequency
Add functionality to control the APLL clock on the AST2600. The APLL provides the clock for the FSI master on the AST2600. Then add a devicetree property to set the AST2600 FSI master bus frequency. Eddie James (4): dt-bindings: clock: Add AST2600 APLLdivN definition clk: ast2600: Add functionality to the APLL clock dt-bindings: fsi: Aspeed master: Add bus-frequency property fsi: Aspeed master: Set bus frequency from devicetree .../bindings/fsi/fsi-master-aspeed.txt| 1 + drivers/clk/clk-ast2600.c | 177 -- drivers/fsi/fsi-master-aspeed.c | 5 + include/dt-bindings/clock/ast2600-clock.h | 1 + 4 files changed, 172 insertions(+), 12 deletions(-) -- 2.26.2
[PATCH 2/4] clk: ast2600: Add functionality to the APLL clock
Register a clock with it's own operations to describe the APLL on the AST2600. The clock is controlled by an SCU register containing a multiplier and divider of the 25MHz input clock. The functionality to change the APLL is necessary to finely control the FSI bus frequency. Signed-off-by: Eddie James --- drivers/clk/clk-ast2600.c | 177 +++--- 1 file changed, 165 insertions(+), 12 deletions(-) diff --git a/drivers/clk/clk-ast2600.c b/drivers/clk/clk-ast2600.c index 177368cac6dd..a147dffbaccc 100644 --- a/drivers/clk/clk-ast2600.c +++ b/drivers/clk/clk-ast2600.c @@ -4,6 +4,7 @@ #define pr_fmt(fmt) "clk-ast2600: " fmt +#include #include #include #include @@ -15,7 +16,7 @@ #include "clk-aspeed.h" -#define ASPEED_G6_NUM_CLKS 71 +#define ASPEED_G6_NUM_CLKS 72 #define ASPEED_G6_SILICON_REV 0x004 @@ -31,6 +32,7 @@ #define ASPEED_G6_CLK_SELECTION1 0x300 #define ASPEED_G6_CLK_SELECTION2 0x304 #define ASPEED_G6_CLK_SELECTION4 0x310 +#define ASPEED_G6_CLK_SELECTION5 0x314 #define ASPEED_HPLL_PARAM 0x200 #define ASPEED_APLL_PARAM 0x210 @@ -116,7 +118,7 @@ static const struct aspeed_gate_data aspeed_g6_gates[] = { [ASPEED_CLK_GATE_UART11CLK] = { 59, -1, "uart11clk-gate", "uartx", 0 }, /* UART11 */ [ASPEED_CLK_GATE_UART12CLK] = { 60, -1, "uart12clk-gate", "uartx", 0 }, /* UART12 */ [ASPEED_CLK_GATE_UART13CLK] = { 61, -1, "uart13clk-gate", "uartx", 0 }, /* UART13 */ - [ASPEED_CLK_GATE_FSICLK]= { 62, 59, "fsiclk-gate", NULL, 0 }, /* FSI */ + [ASPEED_CLK_GATE_FSICLK]= { 62, 59, "fsiclk-gate", "aplln", CLK_SET_RATE_PARENT }, /* FSI */ }; static const struct clk_div_table ast2600_eclk_div_table[] = { @@ -187,24 +189,166 @@ static struct clk_hw *ast2600_calc_pll(const char *name, u32 val) mult, div); }; -static struct clk_hw *ast2600_calc_apll(const char *name, u32 val) +/* + * APLL Frequency: F = 25MHz * (2 - od) * [(m + 2) / (n + 1)] + */ +static void ast2600_apll_get_params(unsigned int *div, unsigned int *mul) { - unsigned int mult, div; + u32 val = readl(scu_g6_base + ASPEED_APLL_PARAM); if (val & BIT(20)) { /* Pass through mode */ - mult = div = 1; + *mul = *div = 1; } else { - /* F = 25Mhz * (2-od) * [(m + 2) / (n + 1)] */ u32 m = (val >> 5) & 0x3f; u32 od = (val >> 4) & 0x1; u32 n = val & 0xf; - mult = (2 - od) * (m + 2); - div = n + 1; + *mul = (2 - od) * (m + 2); + *div = n + 1; } - return clk_hw_register_fixed_factor(NULL, name, "clkin", 0, - mult, div); +} + +static long ast2600_apll_best(unsigned long ul_rate, unsigned long ul_prate, + unsigned int *out_div, unsigned int *out_mul, + unsigned int *output_divider) +{ +#define min_mult 2ULL +#define max_mult 65ULL +#define min_div 1ULL +#define max_div 16ULL + int i; + unsigned int bod = 0; + unsigned long long rem = 1ULL; + unsigned long long brem = ~(0ULL); + unsigned long long bdiv = 1ULL; + unsigned long long tdiv; + unsigned long long bmul = 16ULL; + unsigned long long tmul; + long brate = -ERANGE; + unsigned long long trate; + unsigned long long rate = ul_rate; + unsigned long long prate = ul_prate; + + for (i = 0; i < 2; ++i, prate *= 2ULL) { + for (tdiv = min_div; tdiv <= max_div; ++tdiv) { + tmul = DIV_ROUND_CLOSEST_ULL(rate * tdiv, prate); + if (tmul < min_mult || tmul > max_mult) + continue; + + trate = DIV_ROUND_CLOSEST_ULL(prate * tmul, tdiv); + if (trate > rate) + rem = trate - rate; + else + rem = rate - trate; + + if (rem < brem) { + bod = !i; + brem = rem; + bdiv = tdiv; + bmul = tmul; + brate = (long)trate; + } + + if (!rem) + break; + } + + if (!rem) + break; + } + + if (out_div) + *out_div = (unsigned int)bdiv; + + if (out_mul) + *out_mul = (unsigned int)bmul; + + if (output_divider) +
[PATCH 3/4] dt-bindings: fsi: Aspeed master: Add bus-frequency property
Document the bus-frequency property. Signed-off-by: Eddie James --- Documentation/devicetree/bindings/fsi/fsi-master-aspeed.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/fsi/fsi-master-aspeed.txt b/Documentation/devicetree/bindings/fsi/fsi-master-aspeed.txt index a513e65ec0c9..d84bd19526ca 100644 --- a/Documentation/devicetree/bindings/fsi/fsi-master-aspeed.txt +++ b/Documentation/devicetree/bindings/fsi/fsi-master-aspeed.txt @@ -17,6 +17,7 @@ Optional properties: - fsi-routing-gpios: GPIO for setting the FSI mux (internal or cabled) - fsi-mux-gpios: GPIO for detecting the desired FSI mux state + - bus-frequency: the frequency of the FSI bus Examples: -- 2.26.2
[PATCH 4/4] fsi: Aspeed master: Set bus frequency from devicetree
Set the FSI bus frequency based on the value encoded in the devicetree. The default value is 166MHz, which is the highest frequency some FSI slaves can accept. Signed-off-by: Eddie James Reviewed-by: Joel Stanley --- drivers/fsi/fsi-master-aspeed.c | 5 + 1 file changed, 5 insertions(+) diff --git a/drivers/fsi/fsi-master-aspeed.c b/drivers/fsi/fsi-master-aspeed.c index c006ec008a1a..be19fee0bece 100644 --- a/drivers/fsi/fsi-master-aspeed.c +++ b/drivers/fsi/fsi-master-aspeed.c @@ -515,6 +515,7 @@ static int fsi_master_aspeed_probe(struct platform_device *pdev) struct fsi_master_aspeed *aspeed; struct resource *res; int rc, links, reg; + u32 bus_freq = 1; __be32 raw; rc = tacoma_cabled_fsi_fixup(>dev); @@ -539,6 +540,10 @@ static int fsi_master_aspeed_probe(struct platform_device *pdev) dev_err(aspeed->dev, "couldn't get clock\n"); return PTR_ERR(aspeed->clk); } + + of_property_read_u32(pdev->dev.of_node, "bus-frequency", _freq); + clk_set_rate(aspeed->clk, bus_freq); + rc = clk_prepare_enable(aspeed->clk); if (rc) { dev_err(aspeed->dev, "couldn't enable clock\n"); -- 2.26.2
[PATCH v2 1/6] spi: fsi: Handle 9 to 15 byte transfers lengths
From: Brad Bishop The trailing - 8 bytes of transfer data in this size range is no longer ignored. Fixes: bbb6b2f9865b ("spi: Add FSI-attached SPI controller driver") Signed-off-by: Brad Bishop Signed-off-by: Eddie James Reviewed-by: Joel Stanley Signed-off-by: Joel Stanley --- drivers/spi/spi-fsi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-fsi.c b/drivers/spi/spi-fsi.c index 37a3e0f8e752..8f64af0140e0 100644 --- a/drivers/spi/spi-fsi.c +++ b/drivers/spi/spi-fsi.c @@ -258,15 +258,15 @@ static int fsi_spi_sequence_transfer(struct fsi_spi *ctx, if (loops > 1) { fsi_spi_sequence_add(seq, SPI_FSI_SEQUENCE_BRANCH(idx)); - if (rem) - fsi_spi_sequence_add(seq, rem); - rc = fsi_spi_write_reg(ctx, SPI_FSI_COUNTER_CFG, SPI_FSI_COUNTER_CFG_LOOPS(loops - 1)); if (rc) return rc; } + if (rem) + fsi_spi_sequence_add(seq, rem); + return 0; } -- 2.26.2
[PATCH v2 6/6] spi: fsi: Check mux status before transfers
The SPI controllers are not accessible if the mux isn't set. Therefore, check the mux status before starting a transfer and fail out if it isn't set. Signed-off-by: Eddie James Signed-off-by: Joel Stanley --- drivers/spi/spi-fsi.c | 40 +++- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/drivers/spi/spi-fsi.c b/drivers/spi/spi-fsi.c index a702e9d7d68c..8a440c7078ef 100644 --- a/drivers/spi/spi-fsi.c +++ b/drivers/spi/spi-fsi.c @@ -12,6 +12,7 @@ #define FSI_ENGID_SPI 0x23 #define FSI_MBOX_ROOT_CTRL_8 0x2860 +#define FSI_MBOX_ROOT_CTRL_8_SPI_MUX 0xf000 #define FSI2SPI_DATA0 0x00 #define FSI2SPI_DATA1 0x04 @@ -84,6 +85,26 @@ struct fsi_spi_sequence { u64 data; }; +static int fsi_spi_check_mux(struct fsi_device *fsi, struct device *dev) +{ + int rc; + u32 root_ctrl_8; + __be32 root_ctrl_8_be; + + rc = fsi_slave_read(fsi->slave, FSI_MBOX_ROOT_CTRL_8, _ctrl_8_be, + sizeof(root_ctrl_8_be)); + if (rc) + return rc; + + root_ctrl_8 = be32_to_cpu(root_ctrl_8_be); + dev_dbg(dev, "Root control register 8: %08x\n", root_ctrl_8); + if ((root_ctrl_8 & FSI_MBOX_ROOT_CTRL_8_SPI_MUX) == +FSI_MBOX_ROOT_CTRL_8_SPI_MUX) + return 0; + + return -ENOLINK; +} + static int fsi_spi_check_status(struct fsi_spi *ctx) { int rc; @@ -449,11 +470,15 @@ static int fsi_spi_transfer_init(struct fsi_spi *ctx) static int fsi_spi_transfer_one_message(struct spi_controller *ctlr, struct spi_message *mesg) { - int rc = 0; + int rc; u8 seq_slave = SPI_FSI_SEQUENCE_SEL_SLAVE(mesg->spi->chip_select + 1); struct spi_transfer *transfer; struct fsi_spi *ctx = spi_controller_get_devdata(ctlr); + rc = fsi_spi_check_mux(ctx->fsi, ctx->dev); + if (rc) + return rc; + list_for_each_entry(transfer, >transfers, transfer_list) { struct fsi_spi_sequence seq; struct spi_transfer *next = NULL; @@ -537,24 +562,13 @@ static size_t fsi_spi_max_transfer_size(struct spi_device *spi) static int fsi_spi_probe(struct device *dev) { int rc; - u32 root_ctrl_8; struct device_node *np; int num_controllers_registered = 0; struct fsi_device *fsi = to_fsi_dev(dev); - /* -* Check the SPI mux before attempting to probe. If the mux isn't set -* then the SPI controllers can't access their slave devices. -*/ - rc = fsi_slave_read(fsi->slave, FSI_MBOX_ROOT_CTRL_8, _ctrl_8, - sizeof(root_ctrl_8)); + rc = fsi_spi_check_mux(fsi, dev); if (rc) - return rc; - - if (!root_ctrl_8) { - dev_dbg(dev, "SPI mux not set, aborting probe.\n"); return -ENODEV; - } for_each_available_child_of_node(dev->of_node, np) { u32 base; -- 2.26.2
[PATCH v2 2/6] spi: fsi: Fix clock running too fast
From: Brad Bishop Use a clock divider tuned to a 200MHz FSI bus frequency (the maximum). Use of the previous divider at 200MHz results in corrupt data from endpoint devices. Ideally the clock divider would be calculated from the FSI clock, but that would require some significant work on the FSI driver. With FSI frequencies slower than 200MHz, the SPI clock will simply run slower, but safely. Signed-off-by: Brad Bishop Signed-off-by: Eddie James Signed-off-by: Joel Stanley --- drivers/spi/spi-fsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-fsi.c b/drivers/spi/spi-fsi.c index 8f64af0140e0..559d0ff981f3 100644 --- a/drivers/spi/spi-fsi.c +++ b/drivers/spi/spi-fsi.c @@ -350,7 +350,7 @@ static int fsi_spi_transfer_init(struct fsi_spi *ctx) u64 status = 0ULL; u64 wanted_clock_cfg = SPI_FSI_CLOCK_CFG_ECC_DISABLE | SPI_FSI_CLOCK_CFG_SCK_NO_DEL | - FIELD_PREP(SPI_FSI_CLOCK_CFG_SCK_DIV, 4); + FIELD_PREP(SPI_FSI_CLOCK_CFG_SCK_DIV, 19); end = jiffies + msecs_to_jiffies(SPI_FSI_INIT_TIMEOUT_MS); do { -- 2.26.2
[PATCH v2 4/6] dt-bindings: fsi: fsi2spi: Add compatible string for restricted version
Add a compatible string for the restricted version of the SPI controller. The restricted version cannot process sequence loop operations and therefore has a smaller transfer size. Signed-off-by: Eddie James --- Documentation/devicetree/bindings/fsi/ibm,fsi2spi.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/fsi/ibm,fsi2spi.yaml b/Documentation/devicetree/bindings/fsi/ibm,fsi2spi.yaml index b26d4b4be743..fe39ea4904c1 100644 --- a/Documentation/devicetree/bindings/fsi/ibm,fsi2spi.yaml +++ b/Documentation/devicetree/bindings/fsi/ibm,fsi2spi.yaml @@ -19,6 +19,7 @@ properties: compatible: enum: - ibm,fsi2spi + - ibm,fsi2spi-restricted reg: items: -- 2.26.2
[PATCH v2 3/6] spi: fsi: Fix use of the bneq+ sequencer instruction
From: Brad Bishop All of the switches in N2_count_control in the counter configuration are required to make the branch if not equal and increment command work. Set them when using bneq+. A side effect of this mode requires a dummy write to TDR when both transmitting and receiving otherwise the controller won't start shifting receive data. It is likely not possible to avoid TDR underrun errors in this mode and they are harmless, so do not check for them. Fixes: bbb6b2f9865b ("spi: Add FSI-attached SPI controller driver") Signed-off-by: Brad Bishop Signed-off-by: Eddie James Reviewed-by: Joel Stanley Signed-off-by: Joel Stanley --- drivers/spi/spi-fsi.c | 28 +--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-fsi.c b/drivers/spi/spi-fsi.c index 559d0ff981f3..c31a852b6a3e 100644 --- a/drivers/spi/spi-fsi.c +++ b/drivers/spi/spi-fsi.c @@ -29,6 +29,10 @@ #define SPI_FSI_ERROR 0x0 #define SPI_FSI_COUNTER_CFG0x1 #define SPI_FSI_COUNTER_CFG_LOOPS(x) (((u64)(x) & 0xffULL) << 32) +#define SPI_FSI_COUNTER_CFG_N2_RX BIT_ULL(8) +#define SPI_FSI_COUNTER_CFG_N2_TX BIT_ULL(9) +#define SPI_FSI_COUNTER_CFG_N2_IMPLICIT BIT_ULL(10) +#define SPI_FSI_COUNTER_CFG_N2_RELOAD BIT_ULL(11) #define SPI_FSI_CFG1 0x2 #define SPI_FSI_CLOCK_CFG 0x3 #define SPI_FSI_CLOCK_CFG_MM_ENABLEBIT_ULL(32) @@ -61,7 +65,7 @@ #define SPI_FSI_STATUS_RDR_OVERRUN BIT_ULL(62) #define SPI_FSI_STATUS_RDR_FULLBIT_ULL(63) #define SPI_FSI_STATUS_ANY_ERROR \ - (SPI_FSI_STATUS_ERROR | SPI_FSI_STATUS_TDR_UNDERRUN | \ + (SPI_FSI_STATUS_ERROR | \ SPI_FSI_STATUS_TDR_OVERRUN | SPI_FSI_STATUS_RDR_UNDERRUN | \ SPI_FSI_STATUS_RDR_OVERRUN) #define SPI_FSI_PORT_CTRL 0x9 @@ -238,6 +242,7 @@ static int fsi_spi_sequence_transfer(struct fsi_spi *ctx, int rc; u8 len = min(transfer->len, 8U); u8 rem = transfer->len % len; + u64 cfg = 0ULL; loops = transfer->len / len; @@ -258,8 +263,14 @@ static int fsi_spi_sequence_transfer(struct fsi_spi *ctx, if (loops > 1) { fsi_spi_sequence_add(seq, SPI_FSI_SEQUENCE_BRANCH(idx)); - rc = fsi_spi_write_reg(ctx, SPI_FSI_COUNTER_CFG, - SPI_FSI_COUNTER_CFG_LOOPS(loops - 1)); + cfg = SPI_FSI_COUNTER_CFG_LOOPS(loops - 1); + if (transfer->rx_buf) + cfg |= SPI_FSI_COUNTER_CFG_N2_RX | + SPI_FSI_COUNTER_CFG_N2_TX | + SPI_FSI_COUNTER_CFG_N2_IMPLICIT | + SPI_FSI_COUNTER_CFG_N2_RELOAD; + + rc = fsi_spi_write_reg(ctx, SPI_FSI_COUNTER_CFG, cfg); if (rc) return rc; } @@ -275,6 +286,7 @@ static int fsi_spi_transfer_data(struct fsi_spi *ctx, { int rc = 0; u64 status = 0ULL; + u64 cfg = 0ULL; if (transfer->tx_buf) { int nb; @@ -312,6 +324,16 @@ static int fsi_spi_transfer_data(struct fsi_spi *ctx, u64 in = 0ULL; u8 *rx = transfer->rx_buf; + rc = fsi_spi_read_reg(ctx, SPI_FSI_COUNTER_CFG, ); + if (rc) + return rc; + + if (cfg & SPI_FSI_COUNTER_CFG_N2_IMPLICIT) { + rc = fsi_spi_write_reg(ctx, SPI_FSI_DATA_TX, 0); + if (rc) + return rc; + } + while (transfer->len > recv) { do { rc = fsi_spi_read_reg(ctx, SPI_FSI_STATUS, -- 2.26.2
[PATCH v2 5/6] spi: fsi: Implement restricted size for certain controllers
Some of the FSI-attached SPI controllers cannot use the loop command in programming the sequencer due to security requirements. Check the devicetree compatibility that indicates this condition and restrict the size for these controllers. Also, add more transfers directly in the sequence up to the length of the sequence register. Fixes: bbb6b2f9865b ("spi: Add FSI-attached SPI controller driver") Signed-off-by: Eddie James Reviewed-by: Joel Stanley Signed-off-by: Joel Stanley --- drivers/spi/spi-fsi.c | 65 +++ 1 file changed, 53 insertions(+), 12 deletions(-) diff --git a/drivers/spi/spi-fsi.c b/drivers/spi/spi-fsi.c index c31a852b6a3e..a702e9d7d68c 100644 --- a/drivers/spi/spi-fsi.c +++ b/drivers/spi/spi-fsi.c @@ -24,7 +24,8 @@ #define SPI_FSI_BASE 0x7 #define SPI_FSI_INIT_TIMEOUT_MS1000 -#define SPI_FSI_MAX_TRANSFER_SIZE 2048 +#define SPI_FSI_MAX_XFR_SIZE 2048 +#define SPI_FSI_MAX_XFR_SIZE_RESTRICTED32 #define SPI_FSI_ERROR 0x0 #define SPI_FSI_COUNTER_CFG0x1 @@ -74,6 +75,8 @@ struct fsi_spi { struct device *dev; /* SPI controller device */ struct fsi_device *fsi; /* FSI2SPI CFAM engine device */ u32 base; + size_t max_xfr_size; + bool restricted; }; struct fsi_spi_sequence { @@ -209,8 +212,12 @@ static int fsi_spi_reset(struct fsi_spi *ctx) if (rc) return rc; - return fsi_spi_write_reg(ctx, SPI_FSI_CLOCK_CFG, -SPI_FSI_CLOCK_CFG_RESET2); + rc = fsi_spi_write_reg(ctx, SPI_FSI_CLOCK_CFG, + SPI_FSI_CLOCK_CFG_RESET2); + if (rc) + return rc; + + return fsi_spi_write_reg(ctx, SPI_FSI_STATUS, 0ULL); } static int fsi_spi_sequence_add(struct fsi_spi_sequence *seq, u8 val) @@ -218,8 +225,8 @@ static int fsi_spi_sequence_add(struct fsi_spi_sequence *seq, u8 val) /* * Add the next byte of instruction to the 8-byte sequence register. * Then decrement the counter so that the next instruction will go in -* the right place. Return the number of "slots" left in the sequence -* register. +* the right place. Return the index of the slot we just filled in the +* sequence register. */ seq->data |= (u64)val << seq->bit; seq->bit -= 8; @@ -237,9 +244,11 @@ static int fsi_spi_sequence_transfer(struct fsi_spi *ctx, struct fsi_spi_sequence *seq, struct spi_transfer *transfer) { + bool docfg = false; int loops; int idx; int rc; + u8 val = 0; u8 len = min(transfer->len, 8U); u8 rem = transfer->len % len; u64 cfg = 0ULL; @@ -247,22 +256,42 @@ static int fsi_spi_sequence_transfer(struct fsi_spi *ctx, loops = transfer->len / len; if (transfer->tx_buf) { - idx = fsi_spi_sequence_add(seq, - SPI_FSI_SEQUENCE_SHIFT_OUT(len)); + val = SPI_FSI_SEQUENCE_SHIFT_OUT(len); + idx = fsi_spi_sequence_add(seq, val); + if (rem) rem = SPI_FSI_SEQUENCE_SHIFT_OUT(rem); } else if (transfer->rx_buf) { - idx = fsi_spi_sequence_add(seq, - SPI_FSI_SEQUENCE_SHIFT_IN(len)); + val = SPI_FSI_SEQUENCE_SHIFT_IN(len); + idx = fsi_spi_sequence_add(seq, val); + if (rem) rem = SPI_FSI_SEQUENCE_SHIFT_IN(rem); } else { return -EINVAL; } + if (ctx->restricted) { + const int eidx = rem ? 5 : 6; + + while (loops > 1 && idx <= eidx) { + idx = fsi_spi_sequence_add(seq, val); + loops--; + docfg = true; + } + + if (loops > 1) { + dev_warn(ctx->dev, "No sequencer slots; aborting.\n"); + return -EINVAL; + } + } + if (loops > 1) { fsi_spi_sequence_add(seq, SPI_FSI_SEQUENCE_BRANCH(idx)); + docfg = true; + } + if (docfg) { cfg = SPI_FSI_COUNTER_CFG_LOOPS(loops - 1); if (transfer->rx_buf) cfg |= SPI_FSI_COUNTER_CFG_N2_RX | @@ -273,6 +302,8 @@ static int fsi_spi_sequence_transfer(struct fsi_spi *ctx, rc = fsi_spi_write_reg(ctx, SPI_FSI_COUNTER_CFG, cfg); if (rc) return rc; + } else { + fsi_spi_write_reg(ctx, SPI_FSI_COUNTER_CFG, 0ULL); } if (rem) @@ -429,7 +460,7 @@ static int fsi_s
[PATCH v2 0/6] spi: Fixes for FSI-attached controller
This series implements a number of fixes for the FSI-attached SPI controller driver. Changes since v1: - Switch to a new compatible string for the restricted version of the SPI controller, rather than a new boolean parameter. Brad Bishop (3): spi: fsi: Handle 9 to 15 byte transfers lengths spi: fsi: Fix clock running too fast spi: fsi: Fix use of the bneq+ sequencer instruction Eddie James (3): dt-bindings: fsi: fsi2spi: Add compatible string for restricted version spi: fsi: Implement restricted size for certain controllers spi: fsi: Check mux status before transfers .../devicetree/bindings/fsi/ibm,fsi2spi.yaml | 1 + drivers/spi/spi-fsi.c | 139 ++ 2 files changed, 109 insertions(+), 31 deletions(-) -- 2.26.2
[PATCH v3 2/5] input: misc: Add IBM Operation Panel driver
Add a driver to get the button events from the panel and provide them to userspace with the input subsystem. The panel is connected with I2C and controls the bus, so the driver registers as an I2C slave device. Signed-off-by: Eddie James Reviewed-by: Joel Stanley --- MAINTAINERS| 1 + drivers/input/misc/Kconfig | 18 drivers/input/misc/Makefile| 1 + drivers/input/misc/ibm-panel.c | 189 + 4 files changed, 209 insertions(+) create mode 100644 drivers/input/misc/ibm-panel.c diff --git a/MAINTAINERS b/MAINTAINERS index 28408d29d873..5429da957a1a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8351,6 +8351,7 @@ M:Eddie James L: linux-in...@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/input/ibm,op-panel.yaml +F: drivers/input/misc/ibm-panel.c IBM Power 842 compression accelerator M: Haren Myneni diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 362e8a01980c..65ab1ce7b259 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -708,6 +708,24 @@ config INPUT_ADXL34X_SPI To compile this driver as a module, choose M here: the module will be called adxl34x-spi. +config INPUT_IBM_PANEL + tristate "IBM Operation Panel driver" + depends on I2C_SLAVE || COMPILE_TEST + help + Say Y here if you have an IBM Operation Panel connected to your system + over I2C. The panel is typically connected only to a system's service + processor (BMC). + + If unsure, say N. + + The Operation Panel is a controller with some buttons and an LCD + display that allows someone with physical access to the system to + perform various administrative tasks. This driver only supports the part + of the controller that sends commands to the system. + + To compile this driver as a module, choose M here: the module will be + called ibm-panel. + config INPUT_IMS_PCU tristate "IMS Passenger Control Unit driver" depends on USB diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index a48e5f2d859d..7e9edf0a142b 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_INPUT_GPIO_DECODER) += gpio_decoder.o obj-$(CONFIG_INPUT_GPIO_VIBRA) += gpio-vibra.o obj-$(CONFIG_INPUT_HISI_POWERKEY) += hisi_powerkey.o obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o +obj-$(CONFIG_INPUT_IBM_PANEL) += ibm-panel.o obj-$(CONFIG_INPUT_IMS_PCU)+= ims-pcu.o obj-$(CONFIG_INPUT_IQS269A)+= iqs269a.o obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o diff --git a/drivers/input/misc/ibm-panel.c b/drivers/input/misc/ibm-panel.c new file mode 100644 index ..7329f4641636 --- /dev/null +++ b/drivers/input/misc/ibm-panel.c @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) IBM Corporation 2020 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEVICE_NAME"ibm-panel" + +struct ibm_panel { + u8 idx; + u8 command[11]; + spinlock_t lock;/* protects writes to idx and command */ + struct input_dev *input; +}; + +static void ibm_panel_process_command(struct ibm_panel *panel) +{ + u8 i; + u8 chksum; + u16 sum = 0; + int pressed; + int released; + + if (panel->command[0] != 0xff && panel->command[1] != 0xf0) { + dev_dbg(>input->dev, "command invalid\n"); + return; + } + + for (i = 0; i < sizeof(panel->command) - 1; ++i) { + sum += panel->command[i]; + if (sum & 0xff00) { + sum &= 0xff; + sum++; + } + } + + chksum = sum & 0xff; + chksum = ~chksum; + chksum++; + + if (chksum != panel->command[sizeof(panel->command) - 1]) { + dev_dbg(>input->dev, "command failed checksum\n"); + return; + } + + released = panel->command[2] & 0x80; + pressed = released ? 0 : 1; + + switch (panel->command[2] & 0xf) { + case 0: + input_report_key(panel->input, BTN_NORTH, pressed); + break; + case 1: + input_report_key(panel->input, BTN_SOUTH, pressed); + break; + case 2: + input_report_key(panel->input, BTN_SELECT, pressed); + break; + default: + dev_dbg(>input->dev, "unknown command %u\n", + panel->command[2] & 0xf); + return; + } + + input_sync(panel->input); +} + +static int
[PATCH v3 5/5] ARM: dts: Aspeed: Rainier: Add IBM Operation Panel I2C device
Set I2C bus 7 to multi-master mode and add the panel device that will register as a slave. Signed-off-by: Eddie James Reviewed-by: Joel Stanley --- arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts | 7 +++ 1 file changed, 7 insertions(+) diff --git a/arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts b/arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts index b94421f6cbd5..50d528444f5d 100644 --- a/arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts +++ b/arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts @@ -4,6 +4,7 @@ #include "aspeed-g6.dtsi" #include +#include #include / { @@ -698,6 +699,7 @@ eeprom@53 { }; { + multi-master; status = "okay"; si7021-a20@20 { @@ -831,6 +833,11 @@ gpio@15 { }; }; + ibm-panel@62 { + compatible = "ibm,op-panel"; + reg = <(0x62 | I2C_OWN_SLAVE_ADDRESS)>; + }; + dps: dps310@76 { compatible = "infineon,dps310"; reg = <0x76>; -- 2.26.2
[PATCH v3 4/5] ARM: dts: Aspeed: Tacoma: Add IBM Operation Panel I2C device
Set I2C bus 0 to multi-master mode and add the panel device that will register as a slave. Signed-off-by: Eddie James Reviewed-by: Joel Stanley --- arch/arm/boot/dts/aspeed-bmc-opp-tacoma.dts | 7 +++ 1 file changed, 7 insertions(+) diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-tacoma.dts b/arch/arm/boot/dts/aspeed-bmc-opp-tacoma.dts index 5f4ee67ac787..4d070d6ba09f 100644 --- a/arch/arm/boot/dts/aspeed-bmc-opp-tacoma.dts +++ b/arch/arm/boot/dts/aspeed-bmc-opp-tacoma.dts @@ -4,6 +4,7 @@ #include "aspeed-g6.dtsi" #include +#include #include / { @@ -438,7 +439,13 @@ aliases { }; { + multi-master; status = "okay"; + + ibm-panel@62 { + compatible = "ibm,op-panel"; + reg = <(0x62 | I2C_OWN_SLAVE_ADDRESS)>; + }; }; { -- 2.26.2
[PATCH v3 0/5] input: misc: Add IBM Operation Panel driver
This series adds support for input from the IBM Operation Panel, which is a simple controller with three buttons and an LCD display meant for interacting with a server. It's connected over I2C, typically to a service processor. This series only supports the input from the panel, in which the panel masters the I2C bus and sends data to the host system when someone presses a button on the controller. Changes since v2: - Add "additionalProperties: false" to dts doc - Refactor switch statement in the input driver; check command size and call the processing function within the STOP case - Use a different definition name for Aspeed interrupt status mask Changes since v1: - Redo DTS documentation example to use I2C_OWN_SLAVE_ADDRESS - Reject commands received in the input driver that are too long - Add a definition for the interrupt status mask in the Aspeed I2C driver - Use I2C_OWN_SLAVE_ADDRESS for both dts additions Eddie James (5): dt-bindings: input: Add documentation for IBM Operation Panel input: misc: Add IBM Operation Panel driver i2c: aspeed: Mask IRQ status to relevant bits ARM: dts: Aspeed: Tacoma: Add IBM Operation Panel I2C device ARM: dts: Aspeed: Rainier: Add IBM Operation Panel I2C device .../bindings/input/ibm,op-panel.yaml | 41 MAINTAINERS | 7 + arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts | 7 + arch/arm/boot/dts/aspeed-bmc-opp-tacoma.dts | 7 + drivers/i2c/busses/i2c-aspeed.c | 2 + drivers/input/misc/Kconfig| 18 ++ drivers/input/misc/Makefile | 1 + drivers/input/misc/ibm-panel.c| 189 ++ 8 files changed, 272 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/ibm,op-panel.yaml create mode 100644 drivers/input/misc/ibm-panel.c -- 2.26.2
[PATCH v3 1/5] dt-bindings: input: Add documentation for IBM Operation Panel
Document the bindings for the IBM Operation Panel, which provides a simple interface to control a server. It has a display and three buttons. Also update MAINTAINERS for the new file. Signed-off-by: Eddie James Reviewed-by: Rob Herring Acked-by: Joel Stanley --- .../bindings/input/ibm,op-panel.yaml | 41 +++ MAINTAINERS | 6 +++ 2 files changed, 47 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/ibm,op-panel.yaml diff --git a/Documentation/devicetree/bindings/input/ibm,op-panel.yaml b/Documentation/devicetree/bindings/input/ibm,op-panel.yaml new file mode 100644 index ..52c4a6275a77 --- /dev/null +++ b/Documentation/devicetree/bindings/input/ibm,op-panel.yaml @@ -0,0 +1,41 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/ibm,op-panel.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: IBM Operation Panel + +maintainers: + - Eddie James + +description: | + The IBM Operation Panel provides a simple interface to control the connected + server. It has a display and three buttons: two directional arrows and one + 'Enter' button. + +properties: + compatible: +const: ibm,op-panel + + reg: +maxItems: 1 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | +#include +i2c { +#address-cells = <1>; +#size-cells = <0>; + +ibm-op-panel@62 { +compatible = "ibm,op-panel"; +reg = <(0x62 | I2C_OWN_SLAVE_ADDRESS)>; +}; +}; diff --git a/MAINTAINERS b/MAINTAINERS index 3c0692404907..28408d29d873 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8346,6 +8346,12 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux.git F: Documentation/ia64/ F: arch/ia64/ +IBM Operation Panel Input Driver +M: Eddie James +L: linux-in...@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/input/ibm,op-panel.yaml + IBM Power 842 compression accelerator M: Haren Myneni S: Supported -- 2.26.2
[PATCH v3 3/5] i2c: aspeed: Mask IRQ status to relevant bits
Mask the IRQ status to only the bits that the driver checks. This prevents excessive driver warnings when operating in slave mode when additional bits are set that the driver doesn't handle. Signed-off-by: Eddie James Reviewed-by: Tao Ren --- drivers/i2c/busses/i2c-aspeed.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c index 31268074c422..724bf30600d6 100644 --- a/drivers/i2c/busses/i2c-aspeed.c +++ b/drivers/i2c/busses/i2c-aspeed.c @@ -69,6 +69,7 @@ * These share bit definitions, so use the same values for the enable & * status bits. */ +#define ASPEED_I2CD_INTR_RECV_MASK 0xf000 #define ASPEED_I2CD_INTR_SDA_DL_TIMEOUTBIT(14) #define ASPEED_I2CD_INTR_BUS_RECOVER_DONE BIT(13) #define ASPEED_I2CD_INTR_SLAVE_MATCH BIT(7) @@ -604,6 +605,7 @@ static irqreturn_t aspeed_i2c_bus_irq(int irq, void *dev_id) writel(irq_received & ~ASPEED_I2CD_INTR_RX_DONE, bus->base + ASPEED_I2C_INTR_STS_REG); readl(bus->base + ASPEED_I2C_INTR_STS_REG); + irq_received &= ASPEED_I2CD_INTR_RECV_MASK; irq_remaining = irq_received; #if IS_ENABLED(CONFIG_I2C_SLAVE) -- 2.26.2
[PATCH v2 3/5] i2c: aspeed: Mask IRQ status to relevant bits
Mask the IRQ status to only the bits that the driver checks. This prevents excessive driver warnings when operating in slave mode when additional bits are set that the driver doesn't handle. Signed-off-by: Eddie James --- drivers/i2c/busses/i2c-aspeed.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c index 31268074c422..2a388911038a 100644 --- a/drivers/i2c/busses/i2c-aspeed.c +++ b/drivers/i2c/busses/i2c-aspeed.c @@ -69,6 +69,7 @@ * These share bit definitions, so use the same values for the enable & * status bits. */ +#define ASPEED_I2CD_INTR_ALL 0xf000 #define ASPEED_I2CD_INTR_SDA_DL_TIMEOUTBIT(14) #define ASPEED_I2CD_INTR_BUS_RECOVER_DONE BIT(13) #define ASPEED_I2CD_INTR_SLAVE_MATCH BIT(7) @@ -604,6 +605,7 @@ static irqreturn_t aspeed_i2c_bus_irq(int irq, void *dev_id) writel(irq_received & ~ASPEED_I2CD_INTR_RX_DONE, bus->base + ASPEED_I2C_INTR_STS_REG); readl(bus->base + ASPEED_I2C_INTR_STS_REG); + irq_received &= ASPEED_I2CD_INTR_ALL; irq_remaining = irq_received; #if IS_ENABLED(CONFIG_I2C_SLAVE) -- 2.26.2
[PATCH v2 5/5] ARM: dts: Aspeed: Rainier: Add IBM Operation Panel I2C device
Set I2C bus 7 to multi-master mode and add the panel device that will register as a slave. Signed-off-by: Eddie James Reviewed-by: Joel Stanley --- arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts | 7 +++ 1 file changed, 7 insertions(+) diff --git a/arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts b/arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts index b94421f6cbd5..50d528444f5d 100644 --- a/arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts +++ b/arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts @@ -4,6 +4,7 @@ #include "aspeed-g6.dtsi" #include +#include #include / { @@ -698,6 +699,7 @@ eeprom@53 { }; { + multi-master; status = "okay"; si7021-a20@20 { @@ -831,6 +833,11 @@ gpio@15 { }; }; + ibm-panel@62 { + compatible = "ibm,op-panel"; + reg = <(0x62 | I2C_OWN_SLAVE_ADDRESS)>; + }; + dps: dps310@76 { compatible = "infineon,dps310"; reg = <0x76>; -- 2.26.2
[PATCH v2 0/5] input: misc: Add IBM Operation Panel driver
This series adds support for input from the IBM Operation Panel, which is a simple controller with three buttons and an LCD display meant for interacting with a server. It's connected over I2C, typically to a service processor. This series only supports the input from the panel, in which the panel masters the I2C bus and sends data to the host system when someone presses a button on the controller. Changes since v1: - Redo DTS documentation example to use I2C_OWN_SLAVE_ADDRESS - Reject commands received in the input driver that are too long - Add a definition for the interrupt status mask in the Aspeed I2C driver - Use I2C_OWN_SLAVE_ADDRESS for both dts additions Eddie James (5): dt-bindings: input: Add documentation for IBM Operation Panel input: misc: Add IBM Operation Panel driver i2c: aspeed: Mask IRQ status to relevant bits ARM: dts: Aspeed: Tacoma: Add IBM Operation Panel I2C device ARM: dts: Aspeed: Rainier: Add IBM Operation Panel I2C device .../bindings/input/ibm,op-panel.yaml | 39 MAINTAINERS | 7 + arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts | 7 + arch/arm/boot/dts/aspeed-bmc-opp-tacoma.dts | 7 + drivers/i2c/busses/i2c-aspeed.c | 2 + drivers/input/misc/Kconfig| 18 ++ drivers/input/misc/Makefile | 1 + drivers/input/misc/ibm-panel.c| 192 ++ 8 files changed, 273 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/ibm,op-panel.yaml create mode 100644 drivers/input/misc/ibm-panel.c -- 2.26.2
[PATCH v2 4/5] ARM: dts: Aspeed: Tacoma: Add IBM Operation Panel I2C device
Set I2C bus 0 to multi-master mode and add the panel device that will register as a slave. Signed-off-by: Eddie James Reviewed-by: Joel Stanley --- arch/arm/boot/dts/aspeed-bmc-opp-tacoma.dts | 7 +++ 1 file changed, 7 insertions(+) diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-tacoma.dts b/arch/arm/boot/dts/aspeed-bmc-opp-tacoma.dts index 5f4ee67ac787..4d070d6ba09f 100644 --- a/arch/arm/boot/dts/aspeed-bmc-opp-tacoma.dts +++ b/arch/arm/boot/dts/aspeed-bmc-opp-tacoma.dts @@ -4,6 +4,7 @@ #include "aspeed-g6.dtsi" #include +#include #include / { @@ -438,7 +439,13 @@ aliases { }; { + multi-master; status = "okay"; + + ibm-panel@62 { + compatible = "ibm,op-panel"; + reg = <(0x62 | I2C_OWN_SLAVE_ADDRESS)>; + }; }; { -- 2.26.2
[PATCH v2 1/5] dt-bindings: input: Add documentation for IBM Operation Panel
Document the bindings for the IBM Operation Panel, which provides a simple interface to control a server. It has a display and three buttons. Also update MAINTAINERS for the new file. Signed-off-by: Eddie James Acked-by: Joel Stanley --- .../bindings/input/ibm,op-panel.yaml | 39 +++ MAINTAINERS | 6 +++ 2 files changed, 45 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/ibm,op-panel.yaml diff --git a/Documentation/devicetree/bindings/input/ibm,op-panel.yaml b/Documentation/devicetree/bindings/input/ibm,op-panel.yaml new file mode 100644 index ..5f068fce93ad --- /dev/null +++ b/Documentation/devicetree/bindings/input/ibm,op-panel.yaml @@ -0,0 +1,39 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/ibm,op-panel.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: IBM Operation Panel + +maintainers: + - Eddie James + +description: | + The IBM Operation Panel provides a simple interface to control the connected + server. It has a display and three buttons: two directional arrows and one + 'Enter' button. + +properties: + compatible: +const: ibm,op-panel + + reg: +maxItems: 1 + +required: + - compatible + - reg + +examples: + - | +#include +i2c { +#address-cells = <1>; +#size-cells = <0>; + +ibm-op-panel@62 { +compatible = "ibm,op-panel"; +reg = <(0x62 | I2C_OWN_SLAVE_ADDRESS)>; +}; +}; diff --git a/MAINTAINERS b/MAINTAINERS index 4a5d6797a206..0d83eada50e4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8345,6 +8345,12 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux.git F: Documentation/ia64/ F: arch/ia64/ +IBM Operation Panel Input Driver +M: Eddie James +L: linux-in...@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/input/ibm,op-panel.yaml + IBM Power 842 compression accelerator M: Haren Myneni S: Supported -- 2.26.2
[PATCH v2 2/5] input: misc: Add IBM Operation Panel driver
Add a driver to get the button events from the panel and provide them to userspace with the input subsystem. The panel is connected with I2C and controls the bus, so the driver registers as an I2C slave device. Signed-off-by: Eddie James Reviewed-by: Joel Stanley --- MAINTAINERS| 1 + drivers/input/misc/Kconfig | 18 drivers/input/misc/Makefile| 1 + drivers/input/misc/ibm-panel.c | 192 + 4 files changed, 212 insertions(+) create mode 100644 drivers/input/misc/ibm-panel.c diff --git a/MAINTAINERS b/MAINTAINERS index 0d83eada50e4..0f9605c4cfc6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8350,6 +8350,7 @@ M:Eddie James L: linux-in...@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/input/ibm,op-panel.yaml +F: drivers/input/misc/ibm-panel.c IBM Power 842 compression accelerator M: Haren Myneni diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 362e8a01980c..65ab1ce7b259 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -708,6 +708,24 @@ config INPUT_ADXL34X_SPI To compile this driver as a module, choose M here: the module will be called adxl34x-spi. +config INPUT_IBM_PANEL + tristate "IBM Operation Panel driver" + depends on I2C_SLAVE || COMPILE_TEST + help + Say Y here if you have an IBM Operation Panel connected to your system + over I2C. The panel is typically connected only to a system's service + processor (BMC). + + If unsure, say N. + + The Operation Panel is a controller with some buttons and an LCD + display that allows someone with physical access to the system to + perform various administrative tasks. This driver only supports the part + of the controller that sends commands to the system. + + To compile this driver as a module, choose M here: the module will be + called ibm-panel. + config INPUT_IMS_PCU tristate "IMS Passenger Control Unit driver" depends on USB diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index a48e5f2d859d..7e9edf0a142b 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_INPUT_GPIO_DECODER) += gpio_decoder.o obj-$(CONFIG_INPUT_GPIO_VIBRA) += gpio-vibra.o obj-$(CONFIG_INPUT_HISI_POWERKEY) += hisi_powerkey.o obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o +obj-$(CONFIG_INPUT_IBM_PANEL) += ibm-panel.o obj-$(CONFIG_INPUT_IMS_PCU)+= ims-pcu.o obj-$(CONFIG_INPUT_IQS269A)+= iqs269a.o obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o diff --git a/drivers/input/misc/ibm-panel.c b/drivers/input/misc/ibm-panel.c new file mode 100644 index ..7b147b090c2a --- /dev/null +++ b/drivers/input/misc/ibm-panel.c @@ -0,0 +1,192 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) IBM Corporation 2020 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEVICE_NAME"ibm-panel" + +struct ibm_panel { + u8 idx; + u8 command[11]; + spinlock_t lock;/* protects writes to idx and command */ + struct input_dev *input; +}; + +static void ibm_panel_process_command(struct ibm_panel *panel, u8 command_size) +{ + u8 i; + u8 chksum; + u16 sum = 0; + int pressed; + int released; + + if (command_size != sizeof(panel->command)) { + dev_dbg(>input->dev, "command size incorrect\n"); + return; + } + + if (panel->command[0] != 0xff && panel->command[1] != 0xf0) { + dev_dbg(>input->dev, "command invalid\n"); + return; + } + + for (i = 0; i < sizeof(panel->command) - 1; ++i) { + sum += panel->command[i]; + if (sum & 0xff00) { + sum &= 0xff; + sum++; + } + } + + chksum = sum & 0xff; + chksum = ~chksum; + chksum++; + + if (chksum != panel->command[sizeof(panel->command) - 1]) { + dev_dbg(>input->dev, "command failed checksum\n"); + return; + } + + released = panel->command[2] & 0x80; + pressed = released ? 0 : 1; + + switch (panel->command[2] & 0xf) { + case 0: + input_report_key(panel->input, BTN_NORTH, pressed); + break; + case 1: + input_report_key(panel->input, BTN_SOUTH, pressed); + break; + case 2: + input_report_key(panel->input, BTN_SELECT, pressed); + break; + default: + dev_dbg(>input
Re: [PATCH 2/5] input: misc: Add IBM Operation Panel driver
On 9/1/20 1:11 AM, Wolfram Sang wrote: + switch (event) { + case I2C_SLAVE_STOP: + command_size = panel->idx; + fallthrough; + case I2C_SLAVE_WRITE_REQUESTED: + panel->idx = 0; + break; + case I2C_SLAVE_WRITE_RECEIVED: + if (panel->idx < sizeof(panel->command)) + panel->command[panel->idx++] = *val; + else + dev_dbg(>input->dev, "command truncated\n"); Just double checking: Do you really want to process truncated commands? Since you detect the state here, you could also choose to reject such commands? Yes I suppose not. It could still be a valid command with extra bytes, but unlikely, so probably better not to handle it. Thanks, Eddie
Re: [PATCH 3/5] i2c: aspeed: Mask IRQ status to relevant bits
On 8/25/20 1:38 AM, Joel Stanley wrote: On Thu, 20 Aug 2020 at 16:12, Eddie James wrote: Mask the IRQ status to only the bits that the driver checks. This prevents excessive driver warnings when operating in slave mode when additional bits are set that the driver doesn't handle. Signed-off-by: Eddie James --- drivers/i2c/busses/i2c-aspeed.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c index 31268074c422..abf40f2af8b4 100644 --- a/drivers/i2c/busses/i2c-aspeed.c +++ b/drivers/i2c/busses/i2c-aspeed.c @@ -604,6 +604,7 @@ static irqreturn_t aspeed_i2c_bus_irq(int irq, void *dev_id) writel(irq_received & ~ASPEED_I2CD_INTR_RX_DONE, bus->base + ASPEED_I2C_INTR_STS_REG); readl(bus->base + ASPEED_I2C_INTR_STS_REG); + irq_received &= 0xf000; irq_remaining = irq_received; This would defeat the check for irq_remaining. I don't think we want to do this. Can you explain why these bits are being set in slave mode? No, I don't have any documentation for the bits that are masked off here, so I don't know why they would get set. The check for irq_remaining is still useful for detecting that the driver state machine might be out of sync with what the master is doing. Thanks, Eddie
Re: [PATCH 4/7] dt-bindings: fsi: fsi2spi: Document new restricted property
On 8/20/20 12:14 PM, Mark Brown wrote: On Thu, Aug 20, 2020 at 12:02:25PM -0500, Eddie James wrote: Add documentation for the "fsi2spi,restricted" property which indicates a controller shouldn't sequence loops and therefore has a smaller transfer size. In what situation might someone set this? It sounds like a configuration option rather than a description of the hardware. It is a description of the configuration of the hardware. For controllers that are configured to be restricted for security purposes, this property will be set. Thanks, Eddie
Re: [PATCH 2/7] spi: fsi: Fix clock running too fast
On 8/20/20 12:12 PM, Mark Brown wrote: On Thu, Aug 20, 2020 at 12:02:23PM -0500, Eddie James wrote: From: Brad Bishop Use a clock divider tuned to a 200MHz FSI clock. Use of the previous divider at 200MHz results in corrupt data from endpoint devices. Ideally the clock divider would be calculated from the FSI clock, but that would require some significant work on the FSI driver. Presumably this divider was chosen for FSI clocks that aren't 200MHz - how will those be handled? They aren't handled at the moment, but 200MHz FSI represents the worst case, as it's the maximum. Slower FSI clocks will simply result in slower SPI clocks. Thanks, Eddie
[PATCH 5/7] spi: fsi: Implement restricted size for certain controllers
Some of the FSI-attached SPI controllers cannot use the loop command in programming the sequencer due to security requirements. Add a boolean devicetree property that describes this condition and restrict the size for these controllers. Also, add more transfers directly in the sequence up to the length of the sequence register. Fixes: bbb6b2f9865b ("spi: Add FSI-attached SPI controller driver") Signed-off-by: Eddie James Reviewed-by: Joel Stanley Signed-off-by: Joel Stanley --- drivers/spi/spi-fsi.c | 65 +++ 1 file changed, 53 insertions(+), 12 deletions(-) diff --git a/drivers/spi/spi-fsi.c b/drivers/spi/spi-fsi.c index c31a852b6a3e..53cfa201e187 100644 --- a/drivers/spi/spi-fsi.c +++ b/drivers/spi/spi-fsi.c @@ -24,7 +24,8 @@ #define SPI_FSI_BASE 0x7 #define SPI_FSI_INIT_TIMEOUT_MS1000 -#define SPI_FSI_MAX_TRANSFER_SIZE 2048 +#define SPI_FSI_MAX_XFR_SIZE 2048 +#define SPI_FSI_MAX_XFR_SIZE_RESTRICTED32 #define SPI_FSI_ERROR 0x0 #define SPI_FSI_COUNTER_CFG0x1 @@ -74,6 +75,8 @@ struct fsi_spi { struct device *dev; /* SPI controller device */ struct fsi_device *fsi; /* FSI2SPI CFAM engine device */ u32 base; + size_t max_xfr_size; + bool restricted; }; struct fsi_spi_sequence { @@ -209,8 +212,12 @@ static int fsi_spi_reset(struct fsi_spi *ctx) if (rc) return rc; - return fsi_spi_write_reg(ctx, SPI_FSI_CLOCK_CFG, -SPI_FSI_CLOCK_CFG_RESET2); + rc = fsi_spi_write_reg(ctx, SPI_FSI_CLOCK_CFG, + SPI_FSI_CLOCK_CFG_RESET2); + if (rc) + return rc; + + return fsi_spi_write_reg(ctx, SPI_FSI_STATUS, 0ULL); } static int fsi_spi_sequence_add(struct fsi_spi_sequence *seq, u8 val) @@ -218,8 +225,8 @@ static int fsi_spi_sequence_add(struct fsi_spi_sequence *seq, u8 val) /* * Add the next byte of instruction to the 8-byte sequence register. * Then decrement the counter so that the next instruction will go in -* the right place. Return the number of "slots" left in the sequence -* register. +* the right place. Return the index of the slot we just filled in the +* sequence register. */ seq->data |= (u64)val << seq->bit; seq->bit -= 8; @@ -237,9 +244,11 @@ static int fsi_spi_sequence_transfer(struct fsi_spi *ctx, struct fsi_spi_sequence *seq, struct spi_transfer *transfer) { + bool docfg = false; int loops; int idx; int rc; + u8 val = 0; u8 len = min(transfer->len, 8U); u8 rem = transfer->len % len; u64 cfg = 0ULL; @@ -247,22 +256,42 @@ static int fsi_spi_sequence_transfer(struct fsi_spi *ctx, loops = transfer->len / len; if (transfer->tx_buf) { - idx = fsi_spi_sequence_add(seq, - SPI_FSI_SEQUENCE_SHIFT_OUT(len)); + val = SPI_FSI_SEQUENCE_SHIFT_OUT(len); + idx = fsi_spi_sequence_add(seq, val); + if (rem) rem = SPI_FSI_SEQUENCE_SHIFT_OUT(rem); } else if (transfer->rx_buf) { - idx = fsi_spi_sequence_add(seq, - SPI_FSI_SEQUENCE_SHIFT_IN(len)); + val = SPI_FSI_SEQUENCE_SHIFT_IN(len); + idx = fsi_spi_sequence_add(seq, val); + if (rem) rem = SPI_FSI_SEQUENCE_SHIFT_IN(rem); } else { return -EINVAL; } + if (ctx->restricted) { + const int eidx = rem ? 5 : 6; + + while (loops > 1 && idx <= eidx) { + idx = fsi_spi_sequence_add(seq, val); + loops--; + docfg = true; + } + + if (loops > 1) { + dev_warn(ctx->dev, "No sequencer slots; aborting.\n"); + return -EINVAL; + } + } + if (loops > 1) { fsi_spi_sequence_add(seq, SPI_FSI_SEQUENCE_BRANCH(idx)); + docfg = true; + } + if (docfg) { cfg = SPI_FSI_COUNTER_CFG_LOOPS(loops - 1); if (transfer->rx_buf) cfg |= SPI_FSI_COUNTER_CFG_N2_RX | @@ -273,6 +302,8 @@ static int fsi_spi_sequence_transfer(struct fsi_spi *ctx, rc = fsi_spi_write_reg(ctx, SPI_FSI_COUNTER_CFG, cfg); if (rc) return rc; + } else { + fsi_spi_write_reg(ctx, SPI_FSI_COUNTER_CFG, 0ULL); } if (rem) @@ -429,7 +460,7 @@ static int fsi_spi_
[PATCH 2/7] spi: fsi: Fix clock running too fast
From: Brad Bishop Use a clock divider tuned to a 200MHz FSI clock. Use of the previous divider at 200MHz results in corrupt data from endpoint devices. Ideally the clock divider would be calculated from the FSI clock, but that would require some significant work on the FSI driver. Signed-off-by: Brad Bishop Signed-off-by: Eddie James Signed-off-by: Joel Stanley --- drivers/spi/spi-fsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-fsi.c b/drivers/spi/spi-fsi.c index 8f64af0140e0..559d0ff981f3 100644 --- a/drivers/spi/spi-fsi.c +++ b/drivers/spi/spi-fsi.c @@ -350,7 +350,7 @@ static int fsi_spi_transfer_init(struct fsi_spi *ctx) u64 status = 0ULL; u64 wanted_clock_cfg = SPI_FSI_CLOCK_CFG_ECC_DISABLE | SPI_FSI_CLOCK_CFG_SCK_NO_DEL | - FIELD_PREP(SPI_FSI_CLOCK_CFG_SCK_DIV, 4); + FIELD_PREP(SPI_FSI_CLOCK_CFG_SCK_DIV, 19); end = jiffies + msecs_to_jiffies(SPI_FSI_INIT_TIMEOUT_MS); do { -- 2.26.2
[PATCH 0/7] spi: Fix FSI-attached controller and AT25 drivers
This series implements a number of fixes for the FSI-attached SPI controller driver and the AT25 eeprom driver. Brad Bishop (4): spi: fsi: Handle 9 to 15 byte transfers lengths spi: fsi: Fix clock running too fast spi: fsi: Fix use of the bneq+ sequencer instruction eeprom: at25: Split reads into chunks and cap write size Eddie James (3): dt-bindings: fsi: fsi2spi: Document new restricted property spi: fsi: Implement restricted size for certain controllers spi: fsi: Check mux status before transfers .../devicetree/bindings/fsi/ibm,fsi2spi.yaml | 10 ++ drivers/misc/eeprom/at25.c| 94 +++- drivers/spi/spi-fsi.c | 139 ++ 3 files changed, 172 insertions(+), 71 deletions(-) -- 2.26.2
[PATCH 3/7] spi: fsi: Fix use of the bneq+ sequencer instruction
From: Brad Bishop All of the switches in N2_count_control in the counter configuration are required to make the branch if not equal and increment command work. Set them when using bneq+. A side effect of this mode requires a dummy write to TDR when both transmitting and receiving otherwise the controller won't start shifting receive data. It is likely not possible to avoid TDR underrun errors in this mode and they are harmless, so do not check for them. Fixes: bbb6b2f9865b ("spi: Add FSI-attached SPI controller driver") Signed-off-by: Brad Bishop Signed-off-by: Eddie James Reviewed-by: Joel Stanley Signed-off-by: Joel Stanley --- drivers/spi/spi-fsi.c | 28 +--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-fsi.c b/drivers/spi/spi-fsi.c index 559d0ff981f3..c31a852b6a3e 100644 --- a/drivers/spi/spi-fsi.c +++ b/drivers/spi/spi-fsi.c @@ -29,6 +29,10 @@ #define SPI_FSI_ERROR 0x0 #define SPI_FSI_COUNTER_CFG0x1 #define SPI_FSI_COUNTER_CFG_LOOPS(x) (((u64)(x) & 0xffULL) << 32) +#define SPI_FSI_COUNTER_CFG_N2_RX BIT_ULL(8) +#define SPI_FSI_COUNTER_CFG_N2_TX BIT_ULL(9) +#define SPI_FSI_COUNTER_CFG_N2_IMPLICIT BIT_ULL(10) +#define SPI_FSI_COUNTER_CFG_N2_RELOAD BIT_ULL(11) #define SPI_FSI_CFG1 0x2 #define SPI_FSI_CLOCK_CFG 0x3 #define SPI_FSI_CLOCK_CFG_MM_ENABLEBIT_ULL(32) @@ -61,7 +65,7 @@ #define SPI_FSI_STATUS_RDR_OVERRUN BIT_ULL(62) #define SPI_FSI_STATUS_RDR_FULLBIT_ULL(63) #define SPI_FSI_STATUS_ANY_ERROR \ - (SPI_FSI_STATUS_ERROR | SPI_FSI_STATUS_TDR_UNDERRUN | \ + (SPI_FSI_STATUS_ERROR | \ SPI_FSI_STATUS_TDR_OVERRUN | SPI_FSI_STATUS_RDR_UNDERRUN | \ SPI_FSI_STATUS_RDR_OVERRUN) #define SPI_FSI_PORT_CTRL 0x9 @@ -238,6 +242,7 @@ static int fsi_spi_sequence_transfer(struct fsi_spi *ctx, int rc; u8 len = min(transfer->len, 8U); u8 rem = transfer->len % len; + u64 cfg = 0ULL; loops = transfer->len / len; @@ -258,8 +263,14 @@ static int fsi_spi_sequence_transfer(struct fsi_spi *ctx, if (loops > 1) { fsi_spi_sequence_add(seq, SPI_FSI_SEQUENCE_BRANCH(idx)); - rc = fsi_spi_write_reg(ctx, SPI_FSI_COUNTER_CFG, - SPI_FSI_COUNTER_CFG_LOOPS(loops - 1)); + cfg = SPI_FSI_COUNTER_CFG_LOOPS(loops - 1); + if (transfer->rx_buf) + cfg |= SPI_FSI_COUNTER_CFG_N2_RX | + SPI_FSI_COUNTER_CFG_N2_TX | + SPI_FSI_COUNTER_CFG_N2_IMPLICIT | + SPI_FSI_COUNTER_CFG_N2_RELOAD; + + rc = fsi_spi_write_reg(ctx, SPI_FSI_COUNTER_CFG, cfg); if (rc) return rc; } @@ -275,6 +286,7 @@ static int fsi_spi_transfer_data(struct fsi_spi *ctx, { int rc = 0; u64 status = 0ULL; + u64 cfg = 0ULL; if (transfer->tx_buf) { int nb; @@ -312,6 +324,16 @@ static int fsi_spi_transfer_data(struct fsi_spi *ctx, u64 in = 0ULL; u8 *rx = transfer->rx_buf; + rc = fsi_spi_read_reg(ctx, SPI_FSI_COUNTER_CFG, ); + if (rc) + return rc; + + if (cfg & SPI_FSI_COUNTER_CFG_N2_IMPLICIT) { + rc = fsi_spi_write_reg(ctx, SPI_FSI_DATA_TX, 0); + if (rc) + return rc; + } + while (transfer->len > recv) { do { rc = fsi_spi_read_reg(ctx, SPI_FSI_STATUS, -- 2.26.2
[PATCH 7/7] eeprom: at25: Split reads into chunks and cap write size
From: Brad Bishop Make use of spi_max_transfer_size to avoid requesting transfers that are too large for some spi controllers. Signed-off-by: Brad Bishop Signed-off-by: Eddie James Signed-off-by: Joel Stanley --- drivers/misc/eeprom/at25.c | 94 ++ 1 file changed, 54 insertions(+), 40 deletions(-) diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c index ed8d38b09925..30f0704ab2d4 100644 --- a/drivers/misc/eeprom/at25.c +++ b/drivers/misc/eeprom/at25.c @@ -64,12 +64,17 @@ static int at25_ee_read(void *priv, unsigned int offset, { struct at25_data *at25 = priv; char *buf = val; + size_t max_chunk = spi_max_transfer_size(at25->spi); + size_t num_msgs = DIV_ROUND_UP(count, max_chunk); + size_t nr_bytes = 0; u8 command[EE_MAXADDRLEN + 1]; u8 *cp; ssize_t status; struct spi_transfer t[2]; struct spi_message m; u8 instr; + unsigned intmsg_offset; + size_t msg_count; if (unlikely(offset >= at25->chip.byte_len)) return -EINVAL; @@ -78,57 +83,64 @@ static int at25_ee_read(void *priv, unsigned int offset, if (unlikely(!count)) return -EINVAL; - cp = command; - - instr = AT25_READ; - if (at25->chip.flags & EE_INSTR_BIT3_IS_ADDR) - if (offset >= (1U << (at25->addrlen * 8))) - instr |= AT25_INSTR_BIT3; - *cp++ = instr; - - /* 8/16/24-bit address is written MSB first */ - switch (at25->addrlen) { - default:/* case 3 */ - *cp++ = offset >> 16; - fallthrough; - case 2: - *cp++ = offset >> 8; - fallthrough; - case 1: - case 0: /* can't happen: for better codegen */ - *cp++ = offset >> 0; - } + msg_offset = (unsigned int)offset; + msg_count = min(count, max_chunk); + while (num_msgs) { + cp = command; + + instr = AT25_READ; + if (at25->chip.flags & EE_INSTR_BIT3_IS_ADDR) + if (msg_offset >= (1U << (at25->addrlen * 8))) + instr |= AT25_INSTR_BIT3; + *cp++ = instr; + + /* 8/16/24-bit address is written MSB first */ + switch (at25->addrlen) { + default:/* case 3 */ + *cp++ = msg_offset >> 16; + fallthrough; + case 2: + *cp++ = msg_offset >> 8; + fallthrough; + case 1: + case 0: /* can't happen: for better codegen */ + *cp++ = msg_offset >> 0; + } - spi_message_init(); - memset(t, 0, sizeof(t)); + spi_message_init(); + memset(t, 0, sizeof(t)); - t[0].tx_buf = command; - t[0].len = at25->addrlen + 1; - spi_message_add_tail([0], ); + t[0].tx_buf = command; + t[0].len = at25->addrlen + 1; + spi_message_add_tail([0], ); - t[1].rx_buf = buf; - t[1].len = count; - spi_message_add_tail([1], ); + t[1].rx_buf = buf + nr_bytes; + t[1].len = msg_count; + spi_message_add_tail([1], ); - mutex_lock(>lock); + mutex_lock(>lock); - /* Read it all at once. -* -* REVISIT that's potentially a problem with large chips, if -* other devices on the bus need to be accessed regularly or -* this chip is clocked very slowly -*/ - status = spi_sync(at25->spi, ); - dev_dbg(>spi->dev, "read %zu bytes at %d --> %zd\n", - count, offset, status); + status = spi_sync(at25->spi, ); - mutex_unlock(>lock); - return status; + mutex_unlock(>lock); + + if (status) + return status; + + --num_msgs; + msg_offset += msg_count; + nr_bytes += msg_count; + } + + dev_dbg(>spi->dev, "read %zu bytes at %d\n", + count, offset); + return 0; } static int at25_ee_write(void *priv, unsigned int off, void *val, size_t count) { struct at25_data *at25 = priv; + size_t maxsz = spi_max_transfer_size(at25->spi); const char *buf = val; int status = 0; unsignedbuf_size; @@ -191,6 +203,8 @@ static int at25_ee_write(void *priv, unsigned int off, void *val, size_t count) segm
[PATCH 6/7] spi: fsi: Check mux status before transfers
The SPI controllers are not accessible if the mux isn't set. Therefore, check the mux status before starting a transfer and fail out if it isn't set. Signed-off-by: Eddie James Signed-off-by: Joel Stanley --- drivers/spi/spi-fsi.c | 40 +++- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/drivers/spi/spi-fsi.c b/drivers/spi/spi-fsi.c index 53cfa201e187..9c0a4413ec3d 100644 --- a/drivers/spi/spi-fsi.c +++ b/drivers/spi/spi-fsi.c @@ -12,6 +12,7 @@ #define FSI_ENGID_SPI 0x23 #define FSI_MBOX_ROOT_CTRL_8 0x2860 +#define FSI_MBOX_ROOT_CTRL_8_SPI_MUX 0xf000 #define FSI2SPI_DATA0 0x00 #define FSI2SPI_DATA1 0x04 @@ -84,6 +85,26 @@ struct fsi_spi_sequence { u64 data; }; +static int fsi_spi_check_mux(struct fsi_device *fsi, struct device *dev) +{ + int rc; + u32 root_ctrl_8; + __be32 root_ctrl_8_be; + + rc = fsi_slave_read(fsi->slave, FSI_MBOX_ROOT_CTRL_8, _ctrl_8_be, + sizeof(root_ctrl_8_be)); + if (rc) + return rc; + + root_ctrl_8 = be32_to_cpu(root_ctrl_8_be); + dev_dbg(dev, "Root control register 8: %08x\n", root_ctrl_8); + if ((root_ctrl_8 & FSI_MBOX_ROOT_CTRL_8_SPI_MUX) == +FSI_MBOX_ROOT_CTRL_8_SPI_MUX) + return 0; + + return -ENOLINK; +} + static int fsi_spi_check_status(struct fsi_spi *ctx) { int rc; @@ -449,11 +470,15 @@ static int fsi_spi_transfer_init(struct fsi_spi *ctx) static int fsi_spi_transfer_one_message(struct spi_controller *ctlr, struct spi_message *mesg) { - int rc = 0; + int rc; u8 seq_slave = SPI_FSI_SEQUENCE_SEL_SLAVE(mesg->spi->chip_select + 1); struct spi_transfer *transfer; struct fsi_spi *ctx = spi_controller_get_devdata(ctlr); + rc = fsi_spi_check_mux(ctx->fsi, ctx->dev); + if (rc) + return rc; + list_for_each_entry(transfer, >transfers, transfer_list) { struct fsi_spi_sequence seq; struct spi_transfer *next = NULL; @@ -537,24 +562,13 @@ static size_t fsi_spi_max_transfer_size(struct spi_device *spi) static int fsi_spi_probe(struct device *dev) { int rc; - u32 root_ctrl_8; struct device_node *np; int num_controllers_registered = 0; struct fsi_device *fsi = to_fsi_dev(dev); - /* -* Check the SPI mux before attempting to probe. If the mux isn't set -* then the SPI controllers can't access their slave devices. -*/ - rc = fsi_slave_read(fsi->slave, FSI_MBOX_ROOT_CTRL_8, _ctrl_8, - sizeof(root_ctrl_8)); + rc = fsi_spi_check_mux(fsi, dev); if (rc) - return rc; - - if (!root_ctrl_8) { - dev_dbg(dev, "SPI mux not set, aborting probe.\n"); return -ENODEV; - } for_each_available_child_of_node(dev->of_node, np) { u32 base; -- 2.26.2
[PATCH 4/7] dt-bindings: fsi: fsi2spi: Document new restricted property
Add documentation for the "fsi2spi,restricted" property which indicates a controller shouldn't sequence loops and therefore has a smaller transfer size. Signed-off-by: Eddie James Acked-by: Joel Stanley Signed-off-by: Joel Stanley --- Documentation/devicetree/bindings/fsi/ibm,fsi2spi.yaml | 10 ++ 1 file changed, 10 insertions(+) diff --git a/Documentation/devicetree/bindings/fsi/ibm,fsi2spi.yaml b/Documentation/devicetree/bindings/fsi/ibm,fsi2spi.yaml index b26d4b4be743..0d2fb071fd00 100644 --- a/Documentation/devicetree/bindings/fsi/ibm,fsi2spi.yaml +++ b/Documentation/devicetree/bindings/fsi/ibm,fsi2spi.yaml @@ -24,6 +24,16 @@ properties: items: - description: FSI slave address +patternProperties: + "^spi(@.*|-[0-9a-f])*$": +type: object + +properties: + fsi2spi,restricted: +description: indicates the controller should not use looping in the + sequencer and therefore has a smaller maximum transfer size +type: boolean + required: - compatible - reg -- 2.26.2
[PATCH 1/7] spi: fsi: Handle 9 to 15 byte transfers lengths
From: Brad Bishop The trailing - 8 bytes of transfer data in this size range is no longer ignored. Fixes: bbb6b2f9865b ("spi: Add FSI-attached SPI controller driver") Signed-off-by: Brad Bishop Signed-off-by: Eddie James Reviewed-by: Joel Stanley Signed-off-by: Joel Stanley --- drivers/spi/spi-fsi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-fsi.c b/drivers/spi/spi-fsi.c index 37a3e0f8e752..8f64af0140e0 100644 --- a/drivers/spi/spi-fsi.c +++ b/drivers/spi/spi-fsi.c @@ -258,15 +258,15 @@ static int fsi_spi_sequence_transfer(struct fsi_spi *ctx, if (loops > 1) { fsi_spi_sequence_add(seq, SPI_FSI_SEQUENCE_BRANCH(idx)); - if (rem) - fsi_spi_sequence_add(seq, rem); - rc = fsi_spi_write_reg(ctx, SPI_FSI_COUNTER_CFG, SPI_FSI_COUNTER_CFG_LOOPS(loops - 1)); if (rc) return rc; } + if (rem) + fsi_spi_sequence_add(seq, rem); + return 0; } -- 2.26.2
[PATCH 2/5] input: misc: Add IBM Operation Panel driver
Add a driver to get the button events from the panel and provide them to userspace with the input subsystem. The panel is connected with I2C and controls the bus, so the driver registers as an I2C slave device. Signed-off-by: Eddie James --- MAINTAINERS| 1 + drivers/input/misc/Kconfig | 10 ++ drivers/input/misc/Makefile| 1 + drivers/input/misc/ibm-panel.c | 186 + 4 files changed, 198 insertions(+) create mode 100644 drivers/input/misc/ibm-panel.c diff --git a/MAINTAINERS b/MAINTAINERS index a9fd08e9cd54..077cc79ad7fd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8283,6 +8283,7 @@ M:Eddie James L: linux-in...@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/input/ibm,op-panel.yaml +F: drivers/input/misc/ibm-panel.c IBM Power 842 compression accelerator M: Haren Myneni diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 362e8a01980c..88fb465a18b8 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -708,6 +708,16 @@ config INPUT_ADXL34X_SPI To compile this driver as a module, choose M here: the module will be called adxl34x-spi. +config INPUT_IBM_PANEL + tristate "IBM Operation Panel driver" + depends on I2C_SLAVE || COMPILE_TEST + help + Supports the IBM Operation Panel as an input device. The panel is a + controller attached to the system with some buttons and an LCD display + that allows someone with physical access to the system to perform + various administrative tasks. This driver only supports the part of + the controller that sends commands to the system. + config INPUT_IMS_PCU tristate "IMS Passenger Control Unit driver" depends on USB diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index a48e5f2d859d..7e9edf0a142b 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_INPUT_GPIO_DECODER) += gpio_decoder.o obj-$(CONFIG_INPUT_GPIO_VIBRA) += gpio-vibra.o obj-$(CONFIG_INPUT_HISI_POWERKEY) += hisi_powerkey.o obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o +obj-$(CONFIG_INPUT_IBM_PANEL) += ibm-panel.o obj-$(CONFIG_INPUT_IMS_PCU)+= ims-pcu.o obj-$(CONFIG_INPUT_IQS269A)+= iqs269a.o obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o diff --git a/drivers/input/misc/ibm-panel.c b/drivers/input/misc/ibm-panel.c new file mode 100644 index ..607e7dd5a0fb --- /dev/null +++ b/drivers/input/misc/ibm-panel.c @@ -0,0 +1,186 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) IBM Corporation 2020 + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DEVICE_NAME"ibm-panel" + +struct ibm_panel { + u8 idx; + u8 command[11]; + spinlock_t lock;/* protects writes to idx and command */ + struct input_dev *input; +}; + +static void ibm_panel_process_command(struct ibm_panel *panel, u8 command_size) +{ + u8 i; + u8 chksum; + u16 sum = 0; + int pressed; + int released; + + if (command_size != sizeof(panel->command)) { + dev_dbg(>input->dev, "command too short\n"); + return; + } + + if (panel->command[0] != 0xff && panel->command[1] != 0xf0) { + dev_dbg(>input->dev, "command invalid\n"); + return; + } + + for (i = 0; i < sizeof(panel->command) - 1; ++i) { + sum += panel->command[i]; + if (sum & 0xff00) { + sum &= 0xff; + sum++; + } + } + + chksum = sum & 0xff; + chksum = ~chksum; + chksum++; + + if (chksum != panel->command[sizeof(panel->command) - 1]) { + dev_dbg(>input->dev, "command failed checksum\n"); + return; + } + + released = panel->command[2] & 0x80; + pressed = released ? 0 : 1; + + switch (panel->command[2] & 0xf) { + case 0: + input_report_key(panel->input, BTN_NORTH, pressed); + break; + case 1: + input_report_key(panel->input, BTN_SOUTH, pressed); + break; + case 2: + input_report_key(panel->input, BTN_SELECT, pressed); + break; + default: + dev_dbg(>input->dev, "unknown command %u\n", + panel->command[2] & 0xf); + return; + } + + input_sync(panel->input); +} + +static int ibm_panel_i2c_slave_cb(struct i2c_client *client, + enum i2c_slave_event event
[PATCH 0/5] input: misc: Add IBM Operation Panel driver
This series adds support for input from the IBM Operation Panel, which is a simple controller with three buttons and an LCD display meant for interacting with a server. It's connected over I2C. This series only supports the input from the panel, in which the panel masters the I2C bus and sends data to the host system when someone presses a button on the controller. Eddie James (5): dt-bindings: input: Add documentation for IBM Operation Panel input: misc: Add IBM Operation Panel driver i2c: aspeed: Mask IRQ status to relevant bits ARM: dts: Aspeed: Tacoma: Add IBM Operation Panel I2C device ARM: dts: Aspeed: Rainier: Add IBM Operation Panel I2C device .../bindings/input/ibm,op-panel.yaml | 38 MAINTAINERS | 7 + arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts | 6 + arch/arm/boot/dts/aspeed-bmc-opp-tacoma.dts | 6 + drivers/i2c/busses/i2c-aspeed.c | 1 + drivers/input/misc/Kconfig| 10 + drivers/input/misc/Makefile | 1 + drivers/input/misc/ibm-panel.c| 186 ++ 8 files changed, 255 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/ibm,op-panel.yaml create mode 100644 drivers/input/misc/ibm-panel.c -- 2.26.2
[PATCH 1/5] dt-bindings: input: Add documentation for IBM Operation Panel
Document the bindings for the IBM Operation Panel, which provides a simple interface to control a server. It has a display and three buttons. Also update MAINTAINERS for the new file. Signed-off-by: Eddie James --- .../bindings/input/ibm,op-panel.yaml | 38 +++ MAINTAINERS | 6 +++ 2 files changed, 44 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/ibm,op-panel.yaml diff --git a/Documentation/devicetree/bindings/input/ibm,op-panel.yaml b/Documentation/devicetree/bindings/input/ibm,op-panel.yaml new file mode 100644 index ..86a32e8f3ef0 --- /dev/null +++ b/Documentation/devicetree/bindings/input/ibm,op-panel.yaml @@ -0,0 +1,38 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/ibm,op-panel.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: IBM Operation Panel + +maintainers: + - Eddie James + +description: | + The IBM Operation Panel provides a simple interface to control the connected + server. It has a display and three buttons: two directional arrows and one + 'Enter' button. + +properties: + compatible: +const: ibm,op-panel + + reg: +maxItems: 1 + +required: + - compatible + - reg + +examples: + - | +i2c { +#address-cells = <1>; +#size-cells = <0>; + +ibm-op-panel@62 { +compatible = "ibm,op-panel"; +reg = <0x4062>; /* I2C_OWN_SLAVE_ADDRESS */ +}; +}; diff --git a/MAINTAINERS b/MAINTAINERS index ac79fdbdf8d0..a9fd08e9cd54 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8278,6 +8278,12 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux.git F: Documentation/ia64/ F: arch/ia64/ +IBM Operation Panel Input Driver +M: Eddie James +L: linux-in...@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/input/ibm,op-panel.yaml + IBM Power 842 compression accelerator M: Haren Myneni S: Supported -- 2.26.2
[PATCH 5/5] ARM: dts: Aspeed: Rainier: Add IBM Operation Panel I2C device
Set I2C bus 7 to multi-master mode and add the panel device that will register as a slave. Signed-off-by: Eddie James --- arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts | 6 ++ 1 file changed, 6 insertions(+) diff --git a/arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts b/arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts index b94421f6cbd5..f121f3c26a3a 100644 --- a/arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts +++ b/arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts @@ -698,6 +698,7 @@ eeprom@53 { }; { + multi-master; status = "okay"; si7021-a20@20 { @@ -831,6 +832,11 @@ gpio@15 { }; }; + ibm-panel@62 { + compatible = "ibm,op-panel"; + reg = <0x4062>; /* I2C_OWN_SLAVE_ADDRESS */ + }; + dps: dps310@76 { compatible = "infineon,dps310"; reg = <0x76>; -- 2.26.2
[PATCH 4/5] ARM: dts: Aspeed: Tacoma: Add IBM Operation Panel I2C device
Set I2C bus 0 to multi-master mode and add the panel device that will register as a slave. Signed-off-by: Eddie James --- arch/arm/boot/dts/aspeed-bmc-opp-tacoma.dts | 6 ++ 1 file changed, 6 insertions(+) diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-tacoma.dts b/arch/arm/boot/dts/aspeed-bmc-opp-tacoma.dts index 5f4ee67ac787..9cf2e02ae9e2 100644 --- a/arch/arm/boot/dts/aspeed-bmc-opp-tacoma.dts +++ b/arch/arm/boot/dts/aspeed-bmc-opp-tacoma.dts @@ -438,7 +438,13 @@ aliases { }; { + multi-master; status = "okay"; + + ibm-panel@62 { + compatible = "ibm,op-panel"; + reg = <0x4062>; /* I2C_OWN_SLAVE_ADDRESS */ + }; }; { -- 2.26.2
[PATCH 3/5] i2c: aspeed: Mask IRQ status to relevant bits
Mask the IRQ status to only the bits that the driver checks. This prevents excessive driver warnings when operating in slave mode when additional bits are set that the driver doesn't handle. Signed-off-by: Eddie James --- drivers/i2c/busses/i2c-aspeed.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c index 31268074c422..abf40f2af8b4 100644 --- a/drivers/i2c/busses/i2c-aspeed.c +++ b/drivers/i2c/busses/i2c-aspeed.c @@ -604,6 +604,7 @@ static irqreturn_t aspeed_i2c_bus_irq(int irq, void *dev_id) writel(irq_received & ~ASPEED_I2CD_INTR_RX_DONE, bus->base + ASPEED_I2C_INTR_STS_REG); readl(bus->base + ASPEED_I2C_INTR_STS_REG); + irq_received &= 0xf000; irq_remaining = irq_received; #if IS_ENABLED(CONFIG_I2C_SLAVE) -- 2.26.2
[PATCH v2 1/2] dt-bindings: leds: pca955x: Add IBM implementation compatible string
IBM created an implementation of the PCA9552 on a PIC16F microcontroller. Document the new compatible string for this device. Signed-off-by: Eddie James --- Documentation/devicetree/bindings/leds/leds-pca955x.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/leds/leds-pca955x.txt b/Documentation/devicetree/bindings/leds/leds-pca955x.txt index 7a5830f8d5ab..817f460f3a72 100644 --- a/Documentation/devicetree/bindings/leds/leds-pca955x.txt +++ b/Documentation/devicetree/bindings/leds/leds-pca955x.txt @@ -9,6 +9,7 @@ Required properties: "nxp,pca9550" "nxp,pca9551" "nxp,pca9552" + "ibm,pca9552" "nxp,pca9553" - #address-cells: must be 1 - #size-cells: must be 0 -- 2.24.0
[PATCH v2 2/2] leds: pca955x: Add an IBM software implementation of the PCA9552 chip
IBM created an implementation of the PCA9552 on a PIC16F microcontroller. The I2C device addresses are different from the hardware PCA9552, so add a new compatible string and associated platform data to be able to probe this device. Signed-off-by: Eddie James Reviewed-by: Vishwanatha Subbanna --- drivers/leds/leds-pca955x.c | 8 1 file changed, 8 insertions(+) diff --git a/drivers/leds/leds-pca955x.c b/drivers/leds/leds-pca955x.c index 131f8e922ade..7087ca4592fc 100644 --- a/drivers/leds/leds-pca955x.c +++ b/drivers/leds/leds-pca955x.c @@ -65,6 +65,7 @@ enum pca955x_type { pca9550, pca9551, pca9552, + ibm_pca9552, pca9553, }; @@ -90,6 +91,11 @@ static struct pca955x_chipdef pca955x_chipdefs[] = { .slv_addr = /* 1100xxx */ 0x60, .slv_addr_shift = 3, }, + [ibm_pca9552] = { + .bits = 16, + .slv_addr = /* 0110xxx */ 0x30, + .slv_addr_shift = 3, + }, [pca9553] = { .bits = 4, .slv_addr = /* 110001x */ 0x62, @@ -101,6 +107,7 @@ static const struct i2c_device_id pca955x_id[] = { { "pca9550", pca9550 }, { "pca9551", pca9551 }, { "pca9552", pca9552 }, + { "ibm-pca9552", ibm_pca9552 }, { "pca9553", pca9553 }, { } }; @@ -412,6 +419,7 @@ static const struct of_device_id of_pca955x_match[] = { { .compatible = "nxp,pca9550", .data = (void *)pca9550 }, { .compatible = "nxp,pca9551", .data = (void *)pca9551 }, { .compatible = "nxp,pca9552", .data = (void *)pca9552 }, + { .compatible = "ibm,pca9552", .data = (void *)ibm_pca9552 }, { .compatible = "nxp,pca9553", .data = (void *)pca9553 }, {}, }; -- 2.24.0
[PATCH v2 0/2] leds: pca955x: Add IBM software implemenation of the PCA9552 chip
IBM created an implementation of the PCA9552 on a PIC16F microcontroller. The I2C device addresses are different from the hardware PCA9552, so add a new compatible string and associated platform data to be able to probe this device, and document the new string. Changes since v1: - Switch the vendor part of the compatible string to ibm - Change the enum in the driver to be ibm_ Eddie James (2): dt-bindings: leds: pca955x: Add IBM implementation compatible string leds: pca955x: Add an IBM software implementation of the PCA9552 chip Documentation/devicetree/bindings/leds/leds-pca955x.txt | 1 + drivers/leds/leds-pca955x.c | 8 2 files changed, 9 insertions(+) -- 2.24.0
Re: [PATCH 2/2] leds: pca955x: Add an IBM software implementation of the PCA9552 chip
On 7/9/20 3:50 PM, Andy Shevchenko wrote: On Thu, Jul 9, 2020 at 11:16 PM Eddie James wrote: IBM created an implementation of the PCA9552 on a PIC16F microcontroller. The I2C device addresses are different from the hardware PCA9552, so add a new compatible string and associated platform data to be able to probe this device. This is weird. I would rather expect ibm prefix with corresponding part number. Yep I agree now, see my note to Pavel just now. Thanks, Eddie + pca9552_ibm, + [pca9552_ibm] = { + { "pca9552-ibm", pca9552_ibm }, + { .compatible = "nxp,pca9552-ibm", .data = (void *)pca9552_ibm },
Re: [PATCH 1/2] dt-bindings: leds: pca955x: Add IBM implementation compatible string
On 7/11/20 8:48 AM, Pavel Machek wrote: Hi! IBM created an implementation of the PCA9552 on a PIC16F microcontroller. Document the new compatible string for this device. Is the implementation opensource? Hi, no it is not. Signed-off-by: Eddie James +++ b/Documentation/devicetree/bindings/leds/leds-pca955x.txt @@ -9,6 +9,7 @@ Required properties: "nxp,pca9550" "nxp,pca9551" "nxp,pca9552" + "nxp,pca9552-ibm" "nxp,pca9553" Is it good idea to use nxp prefix for something that is software-defined and not built by nxp? Yea I suppose not... Would ibm,pca9552 be better, or maybe even sw,pca9552 to indicate that is not real hardware, but software emulation? How about ibm,pca9552-sw? Someone suggested that just adding "sw" could be a problem if another company does the same thing but it isn't compatible. Thanks for taking a look! Eddie Best regards, Pavel
Re: [PATCH] fsi: fsi-occ: fix return value check in occ_probe()
On 7/12/20 10:33 PM, Xu Wang wrote: In case of error, the function platform_device_register_full() returns ERR_PTR() and never returns NULL. The NULL test in the return value check should be replaced with IS_ERR(). Thanks, Reviewed-by: Eddie James Signed-off-by: Xu Wang --- drivers/fsi/fsi-occ.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/fsi/fsi-occ.c b/drivers/fsi/fsi-occ.c index 7da9c81759ac..9eeb856c8905 100644 --- a/drivers/fsi/fsi-occ.c +++ b/drivers/fsi/fsi-occ.c @@ -555,7 +555,7 @@ static int occ_probe(struct platform_device *pdev) hwmon_dev_info.id = occ->idx; hwmon_dev = platform_device_register_full(_dev_info); - if (!hwmon_dev) + if (IS_ERR(hwmon_dev)) dev_warn(dev, "failed to create hwmon device\n"); return 0;
[PATCH 2/2] mmc: sdhci-of-aspeed: Fix clock divider calculation
When calculating the clock divider, start dividing at 2 instead of 1. The divider is divided by two at the end of the calculation, so starting at 1 may result in a divider of 0, which shouldn't happen. Signed-off-by: Eddie James --- drivers/mmc/host/sdhci-of-aspeed.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-of-aspeed.c b/drivers/mmc/host/sdhci-of-aspeed.c index 56912e30c47e..a1bcc0f4ba9e 100644 --- a/drivers/mmc/host/sdhci-of-aspeed.c +++ b/drivers/mmc/host/sdhci-of-aspeed.c @@ -68,7 +68,7 @@ static void aspeed_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) if (WARN_ON(clock > host->max_clk)) clock = host->max_clk; - for (div = 1; div < 256; div *= 2) { + for (div = 2; div < 256; div *= 2) { if ((parent / div) <= clock) break; } -- 2.24.0
[PATCH 1/2] clk: AST2600: Add mux for EMMC clock
The EMMC clock can be derived from either the HPLL or the MPLL. Register a clock mux so that the rate is calculated correctly based upon the parent. Signed-off-by: Eddie James Reviewed-by: Andrew Jeffery --- drivers/clk/clk-ast2600.c | 49 --- 1 file changed, 41 insertions(+), 8 deletions(-) diff --git a/drivers/clk/clk-ast2600.c b/drivers/clk/clk-ast2600.c index 99afc949925f..177368cac6dd 100644 --- a/drivers/clk/clk-ast2600.c +++ b/drivers/clk/clk-ast2600.c @@ -131,6 +131,18 @@ static const struct clk_div_table ast2600_eclk_div_table[] = { { 0 } }; +static const struct clk_div_table ast2600_emmc_extclk_div_table[] = { + { 0x0, 2 }, + { 0x1, 4 }, + { 0x2, 6 }, + { 0x3, 8 }, + { 0x4, 10 }, + { 0x5, 12 }, + { 0x6, 14 }, + { 0x7, 16 }, + { 0 } +}; + static const struct clk_div_table ast2600_mac_div_table[] = { { 0x0, 4 }, { 0x1, 4 }, @@ -390,6 +402,11 @@ static struct clk_hw *aspeed_g6_clk_hw_register_gate(struct device *dev, return hw; } +static const char *const emmc_extclk_parent_names[] = { + "emmc_extclk_hpll_in", + "mpll", +}; + static const char * const vclk_parent_names[] = { "dpll", "d1pll", @@ -459,16 +476,32 @@ static int aspeed_g6_clk_probe(struct platform_device *pdev) return PTR_ERR(hw); aspeed_g6_clk_data->hws[ASPEED_CLK_UARTX] = hw; - /* EMMC ext clock divider */ - hw = clk_hw_register_gate(dev, "emmc_extclk_gate", "hpll", 0, - scu_g6_base + ASPEED_G6_CLK_SELECTION1, 15, 0, - _g6_clk_lock); + /* EMMC ext clock */ + hw = clk_hw_register_fixed_factor(dev, "emmc_extclk_hpll_in", "hpll", + 0, 1, 2); if (IS_ERR(hw)) return PTR_ERR(hw); - hw = clk_hw_register_divider_table(dev, "emmc_extclk", "emmc_extclk_gate", 0, - scu_g6_base + ASPEED_G6_CLK_SELECTION1, 12, 3, 0, - ast2600_div_table, - _g6_clk_lock); + + hw = clk_hw_register_mux(dev, "emmc_extclk_mux", +emmc_extclk_parent_names, +ARRAY_SIZE(emmc_extclk_parent_names), 0, +scu_g6_base + ASPEED_G6_CLK_SELECTION1, 11, 1, +0, _g6_clk_lock); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + hw = clk_hw_register_gate(dev, "emmc_extclk_gate", "emmc_extclk_mux", + 0, scu_g6_base + ASPEED_G6_CLK_SELECTION1, + 15, 0, _g6_clk_lock); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + hw = clk_hw_register_divider_table(dev, "emmc_extclk", + "emmc_extclk_gate", 0, + scu_g6_base + + ASPEED_G6_CLK_SELECTION1, 12, + 3, 0, ast2600_emmc_extclk_div_table, + _g6_clk_lock); if (IS_ERR(hw)) return PTR_ERR(hw); aspeed_g6_clk_data->hws[ASPEED_CLK_EMMC] = hw; -- 2.24.0
[PATCH 0/2] clk: Aspeed: Fix eMMC clock speeds
There were two problems affecting clock speeds to the eMMC chip. Firstly, the AST2600 clock was not muxed correctly to be derived from the MPLL. Secondly, the SDHCI clock control divider was not calculated correctly. This series addresses these problems. Eddie James (2): clk: AST2600: Add mux for EMMC clock mmc: sdhci-of-aspeed: Fix clock divider calculation drivers/clk/clk-ast2600.c | 49 +- drivers/mmc/host/sdhci-of-aspeed.c | 2 +- 2 files changed, 42 insertions(+), 9 deletions(-) -- 2.24.0
[PATCH 2/2] leds: pca955x: Add an IBM software implementation of the PCA9552 chip
IBM created an implementation of the PCA9552 on a PIC16F microcontroller. The I2C device addresses are different from the hardware PCA9552, so add a new compatible string and associated platform data to be able to probe this device. Signed-off-by: Eddie James Reviewed-by: Vishwanatha Subbanna --- drivers/leds/leds-pca955x.c | 8 1 file changed, 8 insertions(+) diff --git a/drivers/leds/leds-pca955x.c b/drivers/leds/leds-pca955x.c index 4037c504589c..bf7ead45f66b 100644 --- a/drivers/leds/leds-pca955x.c +++ b/drivers/leds/leds-pca955x.c @@ -65,6 +65,7 @@ enum pca955x_type { pca9550, pca9551, pca9552, + pca9552_ibm, pca9553, }; @@ -90,6 +91,11 @@ static struct pca955x_chipdef pca955x_chipdefs[] = { .slv_addr = /* 1100xxx */ 0x60, .slv_addr_shift = 3, }, + [pca9552_ibm] = { + .bits = 16, + .slv_addr = /* 0110xxx */ 0x30, + .slv_addr_shift = 3, + }, [pca9553] = { .bits = 4, .slv_addr = /* 110001x */ 0x62, @@ -101,6 +107,7 @@ static const struct i2c_device_id pca955x_id[] = { { "pca9550", pca9550 }, { "pca9551", pca9551 }, { "pca9552", pca9552 }, + { "pca9552-ibm", pca9552_ibm }, { "pca9553", pca9553 }, { } }; @@ -412,6 +419,7 @@ static const struct of_device_id of_pca955x_match[] = { { .compatible = "nxp,pca9550", .data = (void *)pca9550 }, { .compatible = "nxp,pca9551", .data = (void *)pca9551 }, { .compatible = "nxp,pca9552", .data = (void *)pca9552 }, + { .compatible = "nxp,pca9552-ibm", .data = (void *)pca9552_ibm }, { .compatible = "nxp,pca9553", .data = (void *)pca9553 }, {}, }; -- 2.24.0
[PATCH 1/2] dt-bindings: leds: pca955x: Add IBM implementation compatible string
IBM created an implementation of the PCA9552 on a PIC16F microcontroller. Document the new compatible string for this device. Signed-off-by: Eddie James --- Documentation/devicetree/bindings/leds/leds-pca955x.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/leds/leds-pca955x.txt b/Documentation/devicetree/bindings/leds/leds-pca955x.txt index 7a5830f8d5ab..28edb976ee77 100644 --- a/Documentation/devicetree/bindings/leds/leds-pca955x.txt +++ b/Documentation/devicetree/bindings/leds/leds-pca955x.txt @@ -9,6 +9,7 @@ Required properties: "nxp,pca9550" "nxp,pca9551" "nxp,pca9552" + "nxp,pca9552-ibm" "nxp,pca9553" - #address-cells: must be 1 - #size-cells: must be 0 -- 2.24.0
[PATCH 0/2] leds: pca955x: Add IBM software implemenation of the PCA9552 chip
IBM created an implementation of the PCA9552 on a PIC16F microcontroller. The I2C device addresses are different from the hardware PCA9552, so add a new compatible string and associated platform data to be able to probe this device, and document the new string. Eddie James (2): dt-bindings: leds: pca955x: Add IBM implementation compatible string leds: pca955x: Add an IBM software implementation of the PCA9552 chip Documentation/devicetree/bindings/leds/leds-pca955x.txt | 1 + drivers/leds/leds-pca955x.c | 8 2 files changed, 9 insertions(+) -- 2.24.0
[PATCH] fsi: aspeed: Enable 23-bit addressing
In order to access more than the second hub link, 23-bit addressing is required. The core provides the highest two bits of address as the slave ID to the master. OpenBMC-Staging-Count: 1 Signed-off-by: Eddie James Acked-by: Jeremy Kerr Signed-off-by: Joel Stanley --- drivers/fsi/fsi-master-aspeed.c | 6 -- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/fsi/fsi-master-aspeed.c b/drivers/fsi/fsi-master-aspeed.c index f49742b310c2..b49dccf14315 100644 --- a/drivers/fsi/fsi-master-aspeed.c +++ b/drivers/fsi/fsi-master-aspeed.c @@ -241,9 +241,10 @@ static int aspeed_master_read(struct fsi_master *master, int link, struct fsi_master_aspeed *aspeed = to_fsi_master_aspeed(master); int ret; - if (id != 0) + if (id > 0x3) return -EINVAL; + addr |= id << 21; addr += link * FSI_HUB_LINK_SIZE; switch (size) { @@ -273,9 +274,10 @@ static int aspeed_master_write(struct fsi_master *master, int link, struct fsi_master_aspeed *aspeed = to_fsi_master_aspeed(master); int ret; - if (id != 0) + if (id > 0x3) return -EINVAL; + addr |= id << 21; addr += link * FSI_HUB_LINK_SIZE; switch (size) { -- 2.24.0
Re: [PATCH v2 2/2] i2c: fsi: Prevent adding adapters for ports without dts nodes
On 7/4/20 1:39 AM, Wolfram Sang wrote: On Tue, Jun 09, 2020 at 03:15:55PM -0500, Eddie James wrote: Ports should be defined in the devicetree if they are to be enabled on the system. The patch description does not really fit anymore, does it? There is no change in behaviour, we just remove a redundant check. Hi, it does change the behavior actually. By checking for the device node pointer, it would proceed and create the port for a NULL device node, which is not the desired behavior. Thanks, Eddie Signed-off-by: Eddie James Signed-off-by: Joel Stanley --- Changes since v1: - Remove the check for null device node since that is checked in of_device_is_available drivers/i2c/busses/i2c-fsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-fsi.c b/drivers/i2c/busses/i2c-fsi.c index 977d6f524649..10332693edf0 100644 --- a/drivers/i2c/busses/i2c-fsi.c +++ b/drivers/i2c/busses/i2c-fsi.c @@ -703,7 +703,7 @@ static int fsi_i2c_probe(struct device *dev) 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)) + if (!of_device_is_available(np)) continue; port = kzalloc(sizeof(*port), GFP_KERNEL); -- 2.24.0
[PATCH v2 2/2] i2c: fsi: Prevent adding adapters for ports without dts nodes
Ports should be defined in the devicetree if they are to be enabled on the system. Signed-off-by: Eddie James Signed-off-by: Joel Stanley --- Changes since v1: - Remove the check for null device node since that is checked in of_device_is_available drivers/i2c/busses/i2c-fsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-fsi.c b/drivers/i2c/busses/i2c-fsi.c index 977d6f524649..10332693edf0 100644 --- a/drivers/i2c/busses/i2c-fsi.c +++ b/drivers/i2c/busses/i2c-fsi.c @@ -703,7 +703,7 @@ static int fsi_i2c_probe(struct device *dev) 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)) + if (!of_device_is_available(np)) continue; port = kzalloc(sizeof(*port), GFP_KERNEL); -- 2.24.0
[PATCH v2 0/2] i2c: fsi: Fixes for systems with more ports
This series fixes a register definition for the FSI-attached I2C master to allow all the available ports. In addition, the code to add an adapter for each port is modified to require a device-tree entry for the bus. This is so that systems with lots of busses that have no devices on them don't add lots of unecessary devices. Changes since v1: - Remove the check for null device node since that is checked in of_device_is_available Eddie James (2): i2c: fsi: Fix the port number field in status register i2c: fsi: Prevent adding adapters for ports without dts nodes drivers/i2c/busses/i2c-fsi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) -- 2.24.0
[PATCH v2 1/2] i2c: fsi: Fix the port number field in status register
The port number field in the status register was not correct, so fix it. Fixes: d6ffb6300116 ("i2c: Add FSI-attached I2C master algorithm") Signed-off-by: Eddie James Signed-off-by: Joel Stanley --- drivers/i2c/busses/i2c-fsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-fsi.c b/drivers/i2c/busses/i2c-fsi.c index e0c256922d4f..977d6f524649 100644 --- a/drivers/i2c/busses/i2c-fsi.c +++ b/drivers/i2c/busses/i2c-fsi.c @@ -98,7 +98,7 @@ #define I2C_STAT_DAT_REQ BIT(25) #define I2C_STAT_CMD_COMP BIT(24) #define I2C_STAT_STOP_ERR BIT(23) -#define I2C_STAT_MAX_PORT GENMASK(19, 16) +#define I2C_STAT_MAX_PORT GENMASK(22, 16) #define I2C_STAT_ANY_INT BIT(15) #define I2C_STAT_SCL_INBIT(11) #define I2C_STAT_SDA_INBIT(10) -- 2.24.0
Re: [PATCH 2/2] i2c: fsi: Prevent adding adapters for ports without dts nodes
On 6/8/20 11:31 AM, Andy Shevchenko wrote: On Mon, Jun 8, 2020 at 7:05 PM Eddie James wrote: Ports should be defined in the devicetree if they are to be enabled on the system. ... 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)) + /* Do not add port if it is not described in the device tree */ + if (!np) + continue; I believe this is redundant, since below will do the same second time. Good point, thanks, I'll update that. + /* Do not add port if it is described as disabled */ + if (!of_device_is_available(np)) continue;
[PATCH 2/2] i2c: fsi: Prevent adding adapters for ports without dts nodes
Ports should be defined in the devicetree if they are to be enabled on the system. Signed-off-by: Eddie James Signed-off-by: Joel Stanley --- drivers/i2c/busses/i2c-fsi.c | 7 ++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-fsi.c b/drivers/i2c/busses/i2c-fsi.c index 977d6f524649..95b6b6bc1d78 100644 --- a/drivers/i2c/busses/i2c-fsi.c +++ b/drivers/i2c/busses/i2c-fsi.c @@ -703,7 +703,12 @@ static int fsi_i2c_probe(struct device *dev) 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)) + /* Do not add port if it is not described in the device tree */ + if (!np) + continue; + + /* Do not add port if it is described as disabled */ + if (!of_device_is_available(np)) continue; port = kzalloc(sizeof(*port), GFP_KERNEL); -- 2.24.0
[PATCH 0/2] i2c: fsi: Fixes for systems with more ports
This series fixes a register definition for the FSI-attached I2C master to allow all the available ports. In addition, the code to add an adapter for each port is modified to require a device-tree entry for the bus. This is so that systems with lots of busses that have no devices on them don't add lots of unecessary devices. Eddie James (2): i2c: fsi: Fix the port number field in status register i2c: fsi: Prevent adding adapters for ports without dts nodes drivers/i2c/busses/i2c-fsi.c | 9 +++-- 1 file changed, 7 insertions(+), 2 deletions(-) -- 2.24.0
[PATCH 1/2] i2c: fsi: Fix the port number field in status register
The port number field in the status register was not correct, so fix it. Fixes: d6ffb6300116 ("i2c: Add FSI-attached I2C master algorithm") Signed-off-by: Eddie James Signed-off-by: Joel Stanley --- drivers/i2c/busses/i2c-fsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-fsi.c b/drivers/i2c/busses/i2c-fsi.c index e0c256922d4f..977d6f524649 100644 --- a/drivers/i2c/busses/i2c-fsi.c +++ b/drivers/i2c/busses/i2c-fsi.c @@ -98,7 +98,7 @@ #define I2C_STAT_DAT_REQ BIT(25) #define I2C_STAT_CMD_COMP BIT(24) #define I2C_STAT_STOP_ERR BIT(23) -#define I2C_STAT_MAX_PORT GENMASK(19, 16) +#define I2C_STAT_MAX_PORT GENMASK(22, 16) #define I2C_STAT_ANY_INT BIT(15) #define I2C_STAT_SCL_INBIT(11) #define I2C_STAT_SDA_INBIT(10) -- 2.24.0
Re: [PATCH 3/3] hwmon: (occ) Add new temperature sensor type
On 5/6/20 10:57 AM, Guenter Roeck wrote: On Fri, May 01, 2020 at 10:08:33AM -0500, Eddie James wrote: The latest version of the On-Chip Controller (OCC) has a different format for the temperature sensor data. Add a new temperature sensor version to handle this data. Signed-off-by: Eddie James For my reference: Acked-by: Guenter Roeck I assume this depends on at least patch 2 of the series, so we'll have to wait for that to be accepted. Thanks Guenter. Yes that's correct. Eddie Guenter --- drivers/hwmon/occ/common.c | 75 ++ 1 file changed, 75 insertions(+) diff --git a/drivers/hwmon/occ/common.c b/drivers/hwmon/occ/common.c index 30e18eb60da7..52af0e728232 100644 --- a/drivers/hwmon/occ/common.c +++ b/drivers/hwmon/occ/common.c @@ -41,6 +41,14 @@ struct temp_sensor_2 { u8 value; } __packed; +struct temp_sensor_10 { + u32 sensor_id; + u8 fru_type; + u8 value; + u8 throttle; + u8 reserved; +} __packed; + struct freq_sensor_1 { u16 sensor_id; u16 value; @@ -307,6 +315,60 @@ static ssize_t occ_show_temp_2(struct device *dev, return snprintf(buf, PAGE_SIZE - 1, "%u\n", val); } +static ssize_t occ_show_temp_10(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int rc; + u32 val = 0; + struct temp_sensor_10 *temp; + struct occ *occ = dev_get_drvdata(dev); + struct occ_sensors *sensors = >sensors; + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); + + rc = occ_update_response(occ); + if (rc) + return rc; + + temp = ((struct temp_sensor_10 *)sensors->temp.data) + sattr->index; + + switch (sattr->nr) { + case 0: + val = get_unaligned_be32(>sensor_id); + break; + case 1: + val = temp->value; + if (val == OCC_TEMP_SENSOR_FAULT) + return -EREMOTEIO; + + /* +* VRM doesn't return temperature, only alarm bit. This +* attribute maps to tempX_alarm instead of tempX_input for +* VRM +*/ + if (temp->fru_type != OCC_FRU_TYPE_VRM) { + /* sensor not ready */ + if (val == 0) + return -EAGAIN; + + val *= 1000; + } + break; + case 2: + val = temp->fru_type; + break; + case 3: + val = temp->value == OCC_TEMP_SENSOR_FAULT; + break; + case 4: + val = temp->throttle * 1000; + break; + default: + return -EINVAL; + } + + return snprintf(buf, PAGE_SIZE - 1, "%u\n", val); +} + static ssize_t occ_show_freq_1(struct device *dev, struct device_attribute *attr, char *buf) { @@ -745,6 +807,10 @@ static int occ_setup_sensor_attrs(struct occ *occ) num_attrs += (sensors->temp.num_sensors * 4); show_temp = occ_show_temp_2; break; + case 0x10: + num_attrs += (sensors->temp.num_sensors * 5); + show_temp = occ_show_temp_10; + break; default: sensors->temp.num_sensors = 0; } @@ -844,6 +910,15 @@ static int occ_setup_sensor_attrs(struct occ *occ) attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_temp, NULL, 3, i); attr++; + + if (sensors->temp.version == 0x10) { + snprintf(attr->name, sizeof(attr->name), +"temp%d_max", s); + attr->sensor = OCC_INIT_ATTR(attr->name, 0444, +show_temp, NULL, +4, i); + attr++; + } } }
[PATCH v11 4/8] soc: aspeed: xdma: Add reset ioctl
Users of the XDMA engine need a way to reset it if something goes wrong. Problems on the host side, or user error, such as incorrect host address, may result in the DMA operation never completing and no way to determine what went wrong. Therefore, add an ioctl to reset the engine so that users can recover in this situation. Signed-off-by: Eddie James Acked-by: Andrew Jeffery --- drivers/soc/aspeed/aspeed-xdma.c | 32 include/uapi/linux/aspeed-xdma.h | 4 2 files changed, 36 insertions(+) diff --git a/drivers/soc/aspeed/aspeed-xdma.c b/drivers/soc/aspeed/aspeed-xdma.c index b4d4d34..4d8af9e 100644 --- a/drivers/soc/aspeed/aspeed-xdma.c +++ b/drivers/soc/aspeed/aspeed-xdma.c @@ -638,6 +638,37 @@ static __poll_t aspeed_xdma_poll(struct file *file, return mask; } +static long aspeed_xdma_ioctl(struct file *file, unsigned int cmd, + unsigned long param) +{ + unsigned long flags; + struct aspeed_xdma_client *client = file->private_data; + struct aspeed_xdma *ctx = client->ctx; + + switch (cmd) { + case ASPEED_XDMA_IOCTL_RESET: + spin_lock_irqsave(>engine_lock, flags); + if (ctx->in_reset) { + spin_unlock_irqrestore(>engine_lock, flags); + return 0; + } + + ctx->in_reset = true; + spin_unlock_irqrestore(>engine_lock, flags); + + if (READ_ONCE(ctx->current_client)) + dev_warn(ctx->dev, +"User reset with transfer in progress.\n"); + + aspeed_xdma_reset(ctx); + break; + default: + return -EINVAL; + } + + return 0; +} + static void aspeed_xdma_vma_close(struct vm_area_struct *vma) { int rc; @@ -756,6 +787,7 @@ static int aspeed_xdma_release(struct inode *inode, struct file *file) .owner = THIS_MODULE, .write = aspeed_xdma_write, .poll = aspeed_xdma_poll, + .unlocked_ioctl = aspeed_xdma_ioctl, .mmap = aspeed_xdma_mmap, .open = aspeed_xdma_open, .release= aspeed_xdma_release, diff --git a/include/uapi/linux/aspeed-xdma.h b/include/uapi/linux/aspeed-xdma.h index 2efaa60..3a3646f 100644 --- a/include/uapi/linux/aspeed-xdma.h +++ b/include/uapi/linux/aspeed-xdma.h @@ -4,8 +4,12 @@ #ifndef _UAPI_LINUX_ASPEED_XDMA_H_ #define _UAPI_LINUX_ASPEED_XDMA_H_ +#include #include +#define __ASPEED_XDMA_IOCTL_MAGIC 0xb7 +#define ASPEED_XDMA_IOCTL_RESET_IO(__ASPEED_XDMA_IOCTL_MAGIC, 0) + /* * aspeed_xdma_direction * -- 1.8.3.1
[PATCH v11 0/8] soc: aspeed: Add XDMA engine driver
This series adds a driver to control the Aspeed XDMA engine embedded in the AST2500 and AST2600. The XDMA engine performs automatic DMA operations over PCI-E between the Aspeed SOC (acting as a BMC) and a host processor. Changes since v10: - Fix devicetree binding documentation - Add patches to enable the device on witherspoon and tacoma systems - Fix the driver to actually use the updated bindings - Remove the device managed memory in favor of manually allocating and freeing This adds considerable complexity to the probe function and requires the use of a kobject and associated release method, but it fixes the problem of the device context being deleted during an operation or with memory still mapped if the device is unbound from the driver - Remove the client kref system - Reset the device when a user closes a file handle with an on-going operation Changes since v9: - Remove the kernel command queue - Use memcpy_toio instead to copy commands to the buffer - Free the client's genalloc'd memory in the release method - Switch the bindings documentation to yaml - Add patches to fix SCU interrupt controller include Changes since v8: - Use DMA API to allocate memory from reserved region. - Fix the driver for the AST2500 by keeping the command queue in kernel memory and copying the whole buffer to the reserved memory area before starting the operation. - Add krefs to the client structure to prevent use-after-free. - Switch reset-names binding to "device", "root-complex" Eddie James (8): dt-bindings: soc: Add Aspeed XDMA Engine soc: aspeed: Add XDMA Engine Driver soc: aspeed: xdma: Add user interface soc: aspeed: xdma: Add reset ioctl ARM: dts: Aspeed: AST2600: Update XDMA engine node ARM: dts: Aspeed: AST2500: Update XDMA engine node ARM: dts: Aspeed: Witherspoon: Enable XDMA engine ARM: dts: Aspeed: Tacoma: Enable XDMA engine .../devicetree/bindings/soc/aspeed/xdma.yaml | 103 ++ MAINTAINERS|8 + arch/arm/boot/dts/aspeed-bmc-opp-tacoma.dts| 11 + arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts | 11 + arch/arm/boot/dts/aspeed-g5.dtsi |5 +- arch/arm/boot/dts/aspeed-g6.dtsi |8 +- drivers/soc/aspeed/Kconfig |8 + drivers/soc/aspeed/Makefile|1 + drivers/soc/aspeed/aspeed-xdma.c | 1205 include/uapi/linux/aspeed-xdma.h | 42 + 10 files changed, 1397 insertions(+), 5 deletions(-) create mode 100644 Documentation/devicetree/bindings/soc/aspeed/xdma.yaml create mode 100644 drivers/soc/aspeed/aspeed-xdma.c create mode 100644 include/uapi/linux/aspeed-xdma.h -- 1.8.3.1
[PATCH v11 1/8] dt-bindings: soc: Add Aspeed XDMA Engine
Document the bindings for the Aspeed AST25XX and AST26XX XDMA engine. Signed-off-by: Eddie James Reviewed-by: Andrew Jeffery --- .../devicetree/bindings/soc/aspeed/xdma.yaml | 103 + MAINTAINERS| 6 ++ 2 files changed, 109 insertions(+) create mode 100644 Documentation/devicetree/bindings/soc/aspeed/xdma.yaml diff --git a/Documentation/devicetree/bindings/soc/aspeed/xdma.yaml b/Documentation/devicetree/bindings/soc/aspeed/xdma.yaml new file mode 100644 index 000..4957435 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/aspeed/xdma.yaml @@ -0,0 +1,103 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/soc/aspeed/xdma.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Aspeed AST25XX and AST26XX XDMA Engine + +maintainers: + - Eddie James + +description: | + This binding describes the XDMA Engine embedded in the AST2500 and AST2600 + SOCs. The XDMA engine can perform automatic DMA operations over PCI between + the SOC (acting as a BMC) and a host processor. + +properties: + compatible: +enum: + - aspeed,ast2500-xdma + - aspeed,ast2600-xdma + + reg: +maxItems: 1 + + clocks: +maxItems: 1 + + resets: +minItems: 1 +maxItems: 2 + + reset-names: +maxItems: 2 +items: + - const: device + - const: root-complex + + interrupts: +maxItems: 2 +items: + - description: global interrupt for the XDMA engine + - description: PCI-E reset or PERST interrupt + + aspeed,scu: +description: a reference to the System Control Unit node of the Aspeed SOC. +allOf: + - $ref: /schemas/types.yaml#/definitions/phandle + + aspeed,pcie-device: +description: describes which PCI-E device the XDMA engine should use +allOf: + - $ref: /schemas/types.yaml#/definitions/string + - enum: [ bmc, vga ] + +required: + - compatible + - reg + - clocks + - resets + - interrupts-extended + - aspeed,scu + - memory-region + +if: + properties: +compatible: + contains: +const: aspeed,ast2600-xdma +then: + required: +- reset-names + +examples: + - | +#include +#include +#include +syscon: syscon@1e6e2000 { +reg = <0x1e6e2000 0x1000>; +ranges = <0 0x1e6e2000 0x1000>; +#address-cells = <1>; +#size-cells = <1>; +#clock-cells = <1>; +#reset-cells = <1>; +scu_ic0: interrupt-controller@560 { +reg = <0x560 0x4>; +interrupt-controller; +#interrupt-cells = <1>; +}; +}; +xdma@1e6e7000 { +compatible = "aspeed,ast2600-xdma"; +reg = <0x1e6e7000 0x100>; +clocks = < ASPEED_CLK_GATE_BCLK>; +resets = < ASPEED_RESET_DEV_XDMA>, < ASPEED_RESET_RC_XDMA>; +reset-names = "device", "root-complex"; +interrupts-extended = < GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>, + <_ic0 ASPEED_AST2600_SCU_IC0_PCIE_PERST_LO_TO_HI>; +aspeed,scu = <>; +aspeed,pcie-device = "bmc"; +memory-region = <_memory>; +}; diff --git a/MAINTAINERS b/MAINTAINERS index b103ff0..6a421fd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2780,6 +2780,12 @@ S: Maintained F: Documentation/devicetree/bindings/media/aspeed-video.txt F: drivers/media/platform/aspeed-video.c +ASPEED XDMA ENGINE DRIVER +M: Eddie James +L: linux-asp...@lists.ozlabs.org (moderated for non-subscribers) +S: Maintained +F: Documentation/devicetree/bindings/soc/aspeed/xdma.yaml + ASUS NOTEBOOKS AND EEEPC ACPI/WMI EXTRAS DRIVERS M: Corentin Chary L: acpi4asus-u...@lists.sourceforge.net -- 1.8.3.1
[PATCH v11 6/8] ARM: dts: Aspeed: AST2500: Update XDMA engine node
Correct the pcie-device property, and add the Aspeed SCU interrupt controller include. Signed-off-by: Eddie James --- arch/arm/boot/dts/aspeed-g5.dtsi | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi index 284face..8d9eeef 100644 --- a/arch/arm/boot/dts/aspeed-g5.dtsi +++ b/arch/arm/boot/dts/aspeed-g5.dtsi @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ #include +#include / { model = "Aspeed BMC"; @@ -267,8 +268,8 @@ reg = <0x1e6e7000 0x100>; clocks = < ASPEED_CLK_GATE_BCLK>; resets = < ASPEED_RESET_XDMA>; - interrupts-extended = < 6>, <_ic 2>; - pcie-device = "bmc"; + interrupts-extended = < 6>, <_ic ASPEED_AST2500_SCU_IC_PCIE_RESET_LO_TO_HI>; + aspeed,pcie-device = "bmc"; aspeed,scu = <>; status = "disabled"; }; -- 1.8.3.1
[PATCH v11 3/8] soc: aspeed: xdma: Add user interface
This commits adds a miscdevice to provide a user interface to the XDMA engine. The interface provides the write operation to start DMA operations. The DMA parameters are passed as the data to the write call. The actual data to transfer is NOT passed through write. Note that both directions of DMA operation are accomplished through the write command; BMC to host and host to BMC. The XDMA driver reserves an area of physical memory for DMA operations, as the XDMA engine is restricted to accessing certain physical memory areas on some platforms. This memory forms a pool from which users can allocate pages for their usage with calls to mmap. The space allocated by a client will be the space used in the DMA operation. For an "upstream" (BMC to host) operation, the data in the client's area will be transferred to the host. For a "downstream" (host to BMC) operation, the host data will be placed in the client's memory area. Poll is also provided in order to determine when the DMA operation is complete for non-blocking IO. Signed-off-by: Eddie James Reviewed-by: Andrew Jeffery --- drivers/soc/aspeed/aspeed-xdma.c | 218 +++ 1 file changed, 218 insertions(+) diff --git a/drivers/soc/aspeed/aspeed-xdma.c b/drivers/soc/aspeed/aspeed-xdma.c index da78149..b4d4d34 100644 --- a/drivers/soc/aspeed/aspeed-xdma.c +++ b/drivers/soc/aspeed/aspeed-xdma.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -235,6 +236,8 @@ struct aspeed_xdma { dma_addr_t mem_coherent; dma_addr_t cmdq_phys; struct gen_pool *pool; + + struct miscdevice misc; }; struct aspeed_xdma_client { @@ -553,6 +556,211 @@ static irqreturn_t aspeed_xdma_pcie_irq(int irq, void *arg) return IRQ_HANDLED; } +static ssize_t aspeed_xdma_write(struct file *file, const char __user *buf, +size_t len, loff_t *offset) +{ + int rc; + unsigned int num_cmds; + struct aspeed_xdma_op op; + struct aspeed_xdma_cmd cmds[2]; + struct aspeed_xdma_client *client = file->private_data; + struct aspeed_xdma *ctx = client->ctx; + + if (len != sizeof(op)) + return -EINVAL; + + rc = copy_from_user(, buf, len); + if (rc) + return rc; + + if (!op.len || op.len > client->size || + op.direction > ASPEED_XDMA_DIRECTION_UPSTREAM) + return -EINVAL; + + num_cmds = ctx->chip->set_cmd(ctx, cmds, , client->phys); + do { + rc = aspeed_xdma_start(ctx, num_cmds, cmds, !!op.direction, + client); + if (!rc) + break; + + if ((file->f_flags & O_NONBLOCK) || rc != -EBUSY) + return rc; + + rc = wait_event_interruptible(ctx->wait, + !(ctx->current_client || + ctx->in_reset)); + } while (!rc); + + if (rc) + return -EINTR; + + if (!(file->f_flags & O_NONBLOCK)) { + rc = wait_event_interruptible(ctx->wait, !client->in_progress); + if (rc) + return -EINTR; + + if (client->error) + return -EIO; + } + + return len; +} + +static __poll_t aspeed_xdma_poll(struct file *file, +struct poll_table_struct *wait) +{ + __poll_t mask = 0; + __poll_t req = poll_requested_events(wait); + struct aspeed_xdma_client *client = file->private_data; + struct aspeed_xdma *ctx = client->ctx; + + if (req & (EPOLLIN | EPOLLRDNORM)) { + if (READ_ONCE(client->in_progress)) + poll_wait(file, >wait, wait); + + if (!READ_ONCE(client->in_progress)) { + if (READ_ONCE(client->error)) + mask |= EPOLLERR; + else + mask |= EPOLLIN | EPOLLRDNORM; + } + } + + if (req & (EPOLLOUT | EPOLLWRNORM)) { + if (READ_ONCE(ctx->current_client)) + poll_wait(file, >wait, wait); + + if (!READ_ONCE(ctx->current_client)) + mask |= EPOLLOUT | EPOLLWRNORM; + } + + return mask; +} + +static void aspeed_xdma_vma_close(struct vm_area_struct *vma) +{ + int rc; + struct aspeed_xdma_client *client = vma->vm_private_data; + + rc = wait_event_interruptible(client->ctx->wait, !client->in_progress); + if (rc) + return; + + gen_pool_free(client->ctx->pool, (unsigned long)client->virt, + client->size); + + cli
[PATCH v11 2/8] soc: aspeed: Add XDMA Engine Driver
The XDMA engine embedded in the AST2500 and AST2600 SOCs performs PCI DMA operations between the SOC (acting as a BMC) and a host processor in a server. This commit adds a driver to control the XDMA engine and adds functions to initialize the hardware and memory and start DMA operations. Signed-off-by: Eddie James Reviewed-by: Andrew Jeffery --- MAINTAINERS | 2 + drivers/soc/aspeed/Kconfig | 8 + drivers/soc/aspeed/Makefile | 1 + drivers/soc/aspeed/aspeed-xdma.c | 955 +++ include/uapi/linux/aspeed-xdma.h | 38 ++ 5 files changed, 1004 insertions(+) create mode 100644 drivers/soc/aspeed/aspeed-xdma.c create mode 100644 include/uapi/linux/aspeed-xdma.h diff --git a/MAINTAINERS b/MAINTAINERS index 6a421fd..5d6c8b3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2785,6 +2785,8 @@ M:Eddie James L: linux-asp...@lists.ozlabs.org (moderated for non-subscribers) S: Maintained F: Documentation/devicetree/bindings/soc/aspeed/xdma.yaml +F: drivers/soc/aspeed/aspeed-xdma.c +F: include/uapi/linux/aspeed-xdma.h ASUS NOTEBOOKS AND EEEPC ACPI/WMI EXTRAS DRIVERS M: Corentin Chary diff --git a/drivers/soc/aspeed/Kconfig b/drivers/soc/aspeed/Kconfig index 323e177..2a6c16f 100644 --- a/drivers/soc/aspeed/Kconfig +++ b/drivers/soc/aspeed/Kconfig @@ -29,4 +29,12 @@ config ASPEED_P2A_CTRL ioctl()s, the driver also provides an interface for userspace mappings to a pre-defined region. +config ASPEED_XDMA + tristate "Aspeed XDMA Engine Driver" + depends on SOC_ASPEED && REGMAP && MFD_SYSCON && HAS_DMA + help + Enable support for the Aspeed XDMA Engine found on the Aspeed AST2XXX + SOCs. The XDMA engine can perform automatic PCI DMA operations + between the AST2XXX (acting as a BMC) and a host processor. + endmenu diff --git a/drivers/soc/aspeed/Makefile b/drivers/soc/aspeed/Makefile index b64be47..977b046 100644 --- a/drivers/soc/aspeed/Makefile +++ b/drivers/soc/aspeed/Makefile @@ -2,3 +2,4 @@ obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o obj-$(CONFIG_ASPEED_P2A_CTRL) += aspeed-p2a-ctrl.o +obj-$(CONFIG_ASPEED_XDMA) += aspeed-xdma.o diff --git a/drivers/soc/aspeed/aspeed-xdma.c b/drivers/soc/aspeed/aspeed-xdma.c new file mode 100644 index 000..da78149 --- /dev/null +++ b/drivers/soc/aspeed/aspeed-xdma.c @@ -0,0 +1,955 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright IBM Corp 2019 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEVICE_NAME"aspeed-xdma" + +#define SCU_AST2600_MISC_CTRL 0x0c0 +#define SCU_AST2600_MISC_CTRL_XDMA_BMC BIT(8) + +#define SCU_AST2500_PCIE_CONF 0x180 +#define SCU_AST2600_PCIE_CONF 0xc20 +#define SCU_PCIE_CONF_VGA_EN BIT(0) +#define SCU_PCIE_CONF_VGA_EN_MMIO BIT(1) +#define SCU_PCIE_CONF_VGA_EN_LPC BIT(2) +#define SCU_PCIE_CONF_VGA_EN_MSI BIT(3) +#define SCU_PCIE_CONF_VGA_EN_MCTP BIT(4) +#define SCU_PCIE_CONF_VGA_EN_IRQ BIT(5) +#define SCU_PCIE_CONF_VGA_EN_DMA BIT(6) +#define SCU_PCIE_CONF_BMC_EN BIT(8) +#define SCU_PCIE_CONF_BMC_EN_MMIO BIT(9) +#define SCU_PCIE_CONF_BMC_EN_MSI BIT(11) +#define SCU_PCIE_CONF_BMC_EN_MCTP BIT(12) +#define SCU_PCIE_CONF_BMC_EN_IRQ BIT(13) +#define SCU_PCIE_CONF_BMC_EN_DMA BIT(14) + +#define SCU_AST2500_BMC_CLASS_REV 0x19c +#define SCU_AST2600_BMC_CLASS_REV 0xc68 +#define SCU_BMC_CLASS_REV_XDMA 0xff01 + +#define XDMA_CMDQ_SIZE PAGE_SIZE +#define XDMA_NUM_CMDS \ + (XDMA_CMDQ_SIZE / sizeof(struct aspeed_xdma_cmd)) + +/* Aspeed specification requires 100us after disabling the reset */ +#define XDMA_ENGINE_SETUP_TIME_MAX_US 1000 +#define XDMA_ENGINE_SETUP_TIME_MIN_US 100 + +#define XDMA_CMD_AST2500_PITCH_SHIFT 3 +#define XDMA_CMD_AST2500_PITCH_BMC GENMASK_ULL(62, 51) +#define XDMA_CMD_AST2500_PITCH_HOSTGENMASK_ULL(46, 35) +#define XDMA_CMD_AST2500_PITCH_UPSTREAMBIT_ULL(31) +#define XDMA_CMD_AST2500_PITCH_ADDRGENMASK_ULL(29, 4) +#define XDMA_CMD_AST2500_PITCH_ID BIT_ULL(0) +#define XDMA_CMD_AST2500_CMD_IRQ_ENBIT_ULL(31) +#define XDMA_CMD_AST2500_CMD_LINE_NO GENMASK_ULL(27, 16) +#define XDMA_CMD_AST250
[PATCH v11 5/8] ARM: dts: Aspeed: AST2600: Update XDMA engine node
Add the PCI-E root complex reset, correct the pcie-device property, and add the Aspeed SCU interrupt controller include. Signed-off-by: Eddie James --- arch/arm/boot/dts/aspeed-g6.dtsi | 8 +--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi index 1ffc1517..86a8e94 100644 --- a/arch/arm/boot/dts/aspeed-g6.dtsi +++ b/arch/arm/boot/dts/aspeed-g6.dtsi @@ -2,6 +2,7 @@ // Copyright 2019 IBM Corp. #include +#include #include / { @@ -342,10 +343,11 @@ compatible = "aspeed,ast2600-xdma"; reg = <0x1e6e7000 0x100>; clocks = < ASPEED_CLK_GATE_BCLK>; - resets = < ASPEED_RESET_DEV_XDMA>; + resets = < ASPEED_RESET_DEV_XDMA>, < ASPEED_RESET_RC_XDMA>; + reset-names = "device", "root-complex"; interrupts-extended = < GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>, - <_ic0 2>; - pcie-device = "bmc"; + <_ic0 ASPEED_AST2600_SCU_IC0_PCIE_PERST_LO_TO_HI>; + aspeed,pcie-device = "bmc"; aspeed,scu = <>; status = "disabled"; }; -- 1.8.3.1
[PATCH v11 8/8] ARM: dts: Aspeed: Tacoma: Enable XDMA engine
Add a reserved memory node for the VGA memory. Add the XDMA engine node, enable it, and point it's memory region to the VGA memory. Signed-off-by: Eddie James --- arch/arm/boot/dts/aspeed-bmc-opp-tacoma.dts | 11 +++ 1 file changed, 11 insertions(+) diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-tacoma.dts b/arch/arm/boot/dts/aspeed-bmc-opp-tacoma.dts index 47293a5..d336dd4 100644 --- a/arch/arm/boot/dts/aspeed-bmc-opp-tacoma.dts +++ b/arch/arm/boot/dts/aspeed-bmc-opp-tacoma.dts @@ -29,6 +29,12 @@ no-map; reg = <0xb800 0x400>; /* 64M */ }; + + vga_memory: region@bf00 { + no-map; + compatible = "shared-dma-pool"; + reg = <0xbf00 0x0100>; /* 16M */ + }; }; gpio-keys { @@ -804,3 +810,8 @@ pinctrl-0 = <_lpc_default>, <_lsirq_default>; }; + + { + status = "okay"; + memory-region = <_memory>; +}; -- 1.8.3.1
[PATCH v11 7/8] ARM: dts: Aspeed: Witherspoon: Enable XDMA engine
Add a reserved memory node for the VGA memory. Add the XDMA engine node, enable it, and point it's memory region to the VGA memory. Signed-off-by: Eddie James --- arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts | 11 +++ 1 file changed, 11 insertions(+) diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts b/arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts index a0f99e3..85d58a6 100644 --- a/arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts +++ b/arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts @@ -27,6 +27,12 @@ reg = <0x9800 0x0400>; /* 64M */ }; + vga_memory: region@9f00 { + no-map; + compatible = "shared-dma-pool"; + reg = <0x9f00 0x0100>; /* 16M */ + }; + gfx_memory: framebuffer { size = <0x0100>; alignment = <0x0100>; @@ -690,4 +696,9 @@ memory-region = <_engine_memory>; }; + { + status = "okay"; + memory-region = <_memory>; +}; + #include "ibm-power9-dual.dtsi" -- 1.8.3.1
[PATCH 3/3] hwmon: (occ) Add new temperature sensor type
The latest version of the On-Chip Controller (OCC) has a different format for the temperature sensor data. Add a new temperature sensor version to handle this data. Signed-off-by: Eddie James --- drivers/hwmon/occ/common.c | 75 ++ 1 file changed, 75 insertions(+) diff --git a/drivers/hwmon/occ/common.c b/drivers/hwmon/occ/common.c index 30e18eb60da7..52af0e728232 100644 --- a/drivers/hwmon/occ/common.c +++ b/drivers/hwmon/occ/common.c @@ -41,6 +41,14 @@ struct temp_sensor_2 { u8 value; } __packed; +struct temp_sensor_10 { + u32 sensor_id; + u8 fru_type; + u8 value; + u8 throttle; + u8 reserved; +} __packed; + struct freq_sensor_1 { u16 sensor_id; u16 value; @@ -307,6 +315,60 @@ static ssize_t occ_show_temp_2(struct device *dev, return snprintf(buf, PAGE_SIZE - 1, "%u\n", val); } +static ssize_t occ_show_temp_10(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int rc; + u32 val = 0; + struct temp_sensor_10 *temp; + struct occ *occ = dev_get_drvdata(dev); + struct occ_sensors *sensors = >sensors; + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); + + rc = occ_update_response(occ); + if (rc) + return rc; + + temp = ((struct temp_sensor_10 *)sensors->temp.data) + sattr->index; + + switch (sattr->nr) { + case 0: + val = get_unaligned_be32(>sensor_id); + break; + case 1: + val = temp->value; + if (val == OCC_TEMP_SENSOR_FAULT) + return -EREMOTEIO; + + /* +* VRM doesn't return temperature, only alarm bit. This +* attribute maps to tempX_alarm instead of tempX_input for +* VRM +*/ + if (temp->fru_type != OCC_FRU_TYPE_VRM) { + /* sensor not ready */ + if (val == 0) + return -EAGAIN; + + val *= 1000; + } + break; + case 2: + val = temp->fru_type; + break; + case 3: + val = temp->value == OCC_TEMP_SENSOR_FAULT; + break; + case 4: + val = temp->throttle * 1000; + break; + default: + return -EINVAL; + } + + return snprintf(buf, PAGE_SIZE - 1, "%u\n", val); +} + static ssize_t occ_show_freq_1(struct device *dev, struct device_attribute *attr, char *buf) { @@ -745,6 +807,10 @@ static int occ_setup_sensor_attrs(struct occ *occ) num_attrs += (sensors->temp.num_sensors * 4); show_temp = occ_show_temp_2; break; + case 0x10: + num_attrs += (sensors->temp.num_sensors * 5); + show_temp = occ_show_temp_10; + break; default: sensors->temp.num_sensors = 0; } @@ -844,6 +910,15 @@ static int occ_setup_sensor_attrs(struct occ *occ) attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_temp, NULL, 3, i); attr++; + + if (sensors->temp.version == 0x10) { + snprintf(attr->name, sizeof(attr->name), +"temp%d_max", s); + attr->sensor = OCC_INIT_ATTR(attr->name, 0444, +show_temp, NULL, +4, i); + attr++; + } } } -- 2.24.0
[PATCH 0/3] occ: Add support for P10
The OCC in the P10 has a number of differences from the P9. Add some logic to handle the differences in accessing the OCC from the service processor, and support the new temperature sensor type. Eddie James (3): dt-bindings: fsi: Add P10 OCC device documentation fsi: occ: Add support for P10 hwmon: (occ) Add new temperature sensor type .../devicetree/bindings/fsi/ibm,p9-occ.txt| 12 +- drivers/fsi/fsi-occ.c | 126 +- drivers/hwmon/occ/common.c| 75 +++ 3 files changed, 173 insertions(+), 40 deletions(-) -- 2.24.0
[PATCH 2/3] fsi: occ: Add support for P10
The P10 OCC has a different SRAM address for the command and response buffers. In addition, the SBE commands to access the SRAM have changed format. Add versioning to the driver to handle these differences. Signed-off-by: Eddie James --- drivers/fsi/fsi-occ.c | 126 ++ 1 file changed, 92 insertions(+), 34 deletions(-) diff --git a/drivers/fsi/fsi-occ.c b/drivers/fsi/fsi-occ.c index 7da9c81759ac..942eff4032b0 100644 --- a/drivers/fsi/fsi-occ.c +++ b/drivers/fsi/fsi-occ.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -24,8 +25,13 @@ #define OCC_CMD_DATA_BYTES 4090 #define OCC_RESP_DATA_BYTES4089 -#define OCC_SRAM_CMD_ADDR 0xFFFBE000 -#define OCC_SRAM_RSP_ADDR 0xFFFBF000 +#define OCC_P9_SRAM_CMD_ADDR 0xFFFBE000 +#define OCC_P9_SRAM_RSP_ADDR 0xFFFBF000 + +#define OCC_P10_SRAM_CMD_ADDR 0xD000 +#define OCC_P10_SRAM_RSP_ADDR 0xE000 + +#define OCC_P10_SRAM_MODE 0x58/* Normal mode, OCB channel 2 */ /* * Assume we don't have much FFDC, if we do we'll overflow and @@ -37,11 +43,14 @@ #define OCC_TIMEOUT_MS 1000 #define OCC_CMD_IN_PRG_WAIT_MS 50 +enum versions { occ_p9, occ_p10 }; + struct occ { struct device *dev; struct device *sbefifo; char name[32]; int idx; + enum versions version; struct miscdevice mdev; struct mutex occ_lock; }; @@ -235,29 +244,43 @@ static int occ_verify_checksum(struct occ_response *resp, u16 data_length) return 0; } -static int occ_getsram(struct occ *occ, u32 address, void *data, ssize_t len) +static int occ_getsram(struct occ *occ, u32 offset, void *data, ssize_t len) { u32 data_len = ((len + 7) / 8) * 8; /* must be multiples of 8 B */ - size_t resp_len, resp_data_len; - __be32 *resp, cmd[5]; - int rc; + size_t cmd_len, resp_len, resp_data_len; + __be32 *resp, cmd[6]; + int idx = 0, rc; /* * Magic sequence to do SBE getsram command. SBE will fetch data from * specified SRAM address. */ - cmd[0] = cpu_to_be32(0x5); + switch (occ->version) { + default: + case occ_p9: + cmd_len = 5; + cmd[2] = cpu_to_be32(1);/* Normal mode */ + cmd[3] = cpu_to_be32(OCC_P9_SRAM_RSP_ADDR + offset); + break; + case occ_p10: + idx = 1; + cmd_len = 6; + cmd[2] = cpu_to_be32(OCC_P10_SRAM_MODE); + cmd[3] = 0; + cmd[4] = cpu_to_be32(OCC_P10_SRAM_RSP_ADDR + offset); + break; + } + + cmd[0] = cpu_to_be32(cmd_len); cmd[1] = cpu_to_be32(SBEFIFO_CMD_GET_OCC_SRAM); - cmd[2] = cpu_to_be32(1); - cmd[3] = cpu_to_be32(address); - cmd[4] = cpu_to_be32(data_len); + cmd[4 + idx] = cpu_to_be32(data_len); resp_len = (data_len >> 2) + OCC_SBE_STATUS_WORDS; resp = kzalloc(resp_len << 2, GFP_KERNEL); if (!resp) return -ENOMEM; - rc = sbefifo_submit(occ->sbefifo, cmd, 5, resp, _len); + rc = sbefifo_submit(occ->sbefifo, cmd, cmd_len, resp, _len); if (rc) goto free; @@ -287,20 +310,21 @@ static int occ_getsram(struct occ *occ, u32 address, void *data, ssize_t len) return rc; } -static int occ_putsram(struct occ *occ, u32 address, const void *data, - ssize_t len) +static int occ_putsram(struct occ *occ, const void *data, ssize_t len) { size_t cmd_len, buf_len, resp_len, resp_data_len; u32 data_len = ((len + 7) / 8) * 8; /* must be multiples of 8 B */ __be32 *buf; - int rc; + int idx = 0, rc; + + cmd_len = (occ->version == occ_p10) ? 6 : 5; /* * We use the same buffer for command and response, make * sure it's big enough */ resp_len = OCC_SBE_STATUS_WORDS; - cmd_len = (data_len >> 2) + 5; + cmd_len += data_len >> 2; buf_len = max(cmd_len, resp_len); buf = kzalloc(buf_len << 2, GFP_KERNEL); if (!buf) @@ -312,11 +336,23 @@ static int occ_putsram(struct occ *occ, u32 address, const void *data, */ buf[0] = cpu_to_be32(cmd_len); buf[1] = cpu_to_be32(SBEFIFO_CMD_PUT_OCC_SRAM); - buf[2] = cpu_to_be32(1); - buf[3] = cpu_to_be32(address); - buf[4] = cpu_to_be32(data_len); - memcpy([5], data, len); + switch (occ->version) { + default: + case occ_p9: + buf[2] = cpu_to_be32(1);/* Normal mode */ + buf[3] = cpu_to_be32(OCC_P9_SRAM_CMD_ADDR); + break; + case occ_p10: + idx = 1; + buf[2] = cpu_to_be32(OCC_P10_SRAM_MODE); + buf[3] = 0; + buf[4] = cpu_to_be32(
[PATCH 1/3] dt-bindings: fsi: Add P10 OCC device documentation
Add the P10 compatible string. Signed-off-by: Eddie James --- Documentation/devicetree/bindings/fsi/ibm,p9-occ.txt | 12 ++-- 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/fsi/ibm,p9-occ.txt b/Documentation/devicetree/bindings/fsi/ibm,p9-occ.txt index 99ca9862a586..e73358075a90 100644 --- a/Documentation/devicetree/bindings/fsi/ibm,p9-occ.txt +++ b/Documentation/devicetree/bindings/fsi/ibm,p9-occ.txt @@ -1,13 +1,13 @@ -Device-tree bindings for FSI-attached POWER9 On-Chip Controller (OCC) -- +Device-tree bindings for FSI-attached POWER9/POWER10 On-Chip Controller (OCC) +- -This is the binding for the P9 On-Chip Controller accessed over FSI from a -service processor. See fsi.txt for details on bindings for FSI slave and CFAM +This is the binding for the P9 or P10 On-Chip Controller accessed over FSI from +a service processor. See fsi.txt for details on bindings for FSI slave and CFAM nodes. The OCC is not an FSI slave device itself, rather it is accessed -through the SBE fifo. +through the SBE FIFO. Required properties: - - compatible = "ibm,p9-occ" + - compatible = "ibm,p9-occ" or "ibm,p10-occ" Examples: -- 2.24.0
[PATCH 1/2] dt-bindings: hwmon: Document ibm,cffps compatible string
Document this string that indicates that any version of the power supply may be connected. In this case, the driver must detect the version automatically. Signed-off-by: Eddie James --- Documentation/devicetree/bindings/hwmon/ibm,cffps1.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/hwmon/ibm,cffps1.txt b/Documentation/devicetree/bindings/hwmon/ibm,cffps1.txt index 1036f65..d9a2719 100644 --- a/Documentation/devicetree/bindings/hwmon/ibm,cffps1.txt +++ b/Documentation/devicetree/bindings/hwmon/ibm,cffps1.txt @@ -5,6 +5,9 @@ Required properties: - compatible : Must be one of the following: "ibm,cffps1" "ibm,cffps2" + or "ibm,cffps" if the system + must support any version of the + power supply - reg = < I2C bus address >; : Address of the power supply on the I2C bus. -- 1.8.3.1
[PATCH 0/2] hwmon: (pmbus/ibm-cffps) Add version detection capability
The IBM common form factor power supply driver may need to detect which PSU version is connected, since some systems can use a variety of power supplies. This series adds a new compatible string with no version number, and some code to parse the CCIN of the PSU to determine which version is applicable. Eddie James (2): dt-bindings: hwmon: Document ibm,cffps compatible string hwmon: (pmbus/ibm-cffps) Add version detection capability .../devicetree/bindings/hwmon/ibm,cffps1.txt | 3 ++ drivers/hwmon/pmbus/ibm-cffps.c| 37 +++--- 2 files changed, 36 insertions(+), 4 deletions(-) -- 1.8.3.1
[PATCH v2 4/4] ARM: dts: aspeed: ast2600: Add SCU interrupt controllers
Add nodes for the interrupt controllers provided by the SCU. Signed-off-by: Eddie James --- arch/arm/boot/dts/aspeed-g6.dtsi | 18 ++ 1 file changed, 18 insertions(+) diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi index 3a1422f..d89f1e6 100644 --- a/arch/arm/boot/dts/aspeed-g6.dtsi +++ b/arch/arm/boot/dts/aspeed-g6.dtsi @@ -159,6 +159,24 @@ compatible = "aspeed,ast2600-smpmem"; reg = <0x180 0x40>; }; + + scu_ic0: interrupt-controller@0 { + #interrupt-cells = <1>; + compatible = "aspeed,ast2600-scu-ic0"; + reg = <0x560 0x4>; + interrupt-parent = <>; + interrupts = ; + interrupt-controller; + }; + + scu_ic1: interrupt-controller@1 { + #interrupt-cells = <1>; + compatible = "aspeed,ast2600-scu-ic1"; + reg = <0x570 0x4>; + interrupt-parent = <>; + interrupts = ; + interrupt-controller; + }; }; rng: hwrng@1e6e2524 { -- 1.8.3.1