Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 370a4fae authored by David Collins's avatar David Collins
Browse files

spmi: pmic-arb: correct support for up to 512 APIDs



Version 3 of the SPMI PMIC arbiter supports up to 512 APIDs.
However, the APID value is currently stored in u8 variables
throughout the spmi-pmic-arb driver.  Change the type of these
variables to be u16 so that APIDs 256-511 are not truncated.
Also update the out_hwirq value packing in order to support
more than 8 bits for APIDs.

Change-Id: If2408bc4678b2e0f7e2366329be005cd652661cf
CRs-Fixed: 1045396
Signed-off-by: default avatarDavid Collins <collinsd@codeaurora.org>
parent 7888886e
Loading
Loading
Loading
Loading
+47 −40
Original line number Diff line number Diff line
@@ -97,6 +97,17 @@ enum pmic_arb_cmd_op_code {
/* interrupt enable bit */
#define SPMI_PIC_ACC_ENABLE_BIT		BIT(0)

#define HWIRQ(slave_id, periph_id, irq_id, apid) \
	((((slave_id) & 0xF)   << 28) | \
	(((periph_id) & 0xFF)  << 20) | \
	(((irq_id)    & 0x7)   << 16) | \
	(((apid)      & 0x1FF) << 0))

#define HWIRQ_SID(hwirq)  (((hwirq) >> 28) & 0xF)
#define HWIRQ_PER(hwirq)  (((hwirq) >> 20) & 0xFF)
#define HWIRQ_IRQ(hwirq)  (((hwirq) >> 16) & 0x7)
#define HWIRQ_APID(hwirq) (((hwirq) >> 0)  & 0x1FF)

struct pmic_arb_ver_ops;

struct apid_data {
@@ -172,7 +183,7 @@ struct spmi_pmic_arb {
struct pmic_arb_ver_ops {
	const char *ver_str;
	int (*ppid_to_apid)(struct spmi_pmic_arb *pa, u8 sid, u16 addr,
			u8 *apid);
			u16 *apid);
	int (*mode)(struct spmi_pmic_arb *dev, u8 sid, u16 addr,
			mode_t *mode);
	/* spmi commands (read_cmd, write_cmd, cmd) functionality */
@@ -181,10 +192,10 @@ struct pmic_arb_ver_ops {
	u32 (*fmt_cmd)(u8 opc, u8 sid, u16 addr, u8 bc);
	int (*non_data_cmd)(struct spmi_controller *ctrl, u8 opc, u8 sid);
	/* Interrupts controller functionality (offset of PIC registers) */
	u32 (*owner_acc_status)(u8 m, u8 n);
	u32 (*acc_enable)(u8 n);
	u32 (*irq_status)(u8 n);
	u32 (*irq_clear)(u8 n);
	u32 (*owner_acc_status)(u8 m, u16 n);
	u32 (*acc_enable)(u16 n);
	u32 (*irq_status)(u16 n);
	u32 (*irq_clear)(u16 n);
};

static inline void pmic_arb_base_write(struct spmi_pmic_arb *pa,
@@ -466,8 +477,8 @@ static void qpnpint_spmi_write(struct irq_data *d, u8 reg, void *buf,
			       size_t len)
{
	struct spmi_pmic_arb *pa = irq_data_get_irq_chip_data(d);
	u8 sid = d->hwirq >> 24;
	u8 per = d->hwirq >> 16;
	u8 sid = HWIRQ_SID(d->hwirq);
	u8 per = HWIRQ_PER(d->hwirq);

	if (pmic_arb_write_cmd(pa->spmic, SPMI_CMD_EXT_WRITEL, sid,
			       (per << 8) + reg, buf, len))
@@ -479,8 +490,8 @@ static void qpnpint_spmi_write(struct irq_data *d, u8 reg, void *buf,
static void qpnpint_spmi_read(struct irq_data *d, u8 reg, void *buf, size_t len)
{
	struct spmi_pmic_arb *pa = irq_data_get_irq_chip_data(d);
	u8 sid = d->hwirq >> 24;
	u8 per = d->hwirq >> 16;
	u8 sid = HWIRQ_SID(d->hwirq);
	u8 per = HWIRQ_PER(d->hwirq);

	if (pmic_arb_read_cmd(pa->spmic, SPMI_CMD_EXT_READL, sid,
			      (per << 8) + reg, buf, len))
@@ -489,7 +500,7 @@ static void qpnpint_spmi_read(struct irq_data *d, u8 reg, void *buf, size_t len)
				    d->irq);
}

static void cleanup_irq(struct spmi_pmic_arb *pa, u8 apid, int id)
static void cleanup_irq(struct spmi_pmic_arb *pa, u16 apid, int id)
{
	u16 ppid = pa->apid_data[apid].ppid;
	u8 sid = ppid >> 8;
@@ -514,20 +525,19 @@ static void cleanup_irq(struct spmi_pmic_arb *pa, u8 apid, int id)
				irq_mask, ppid);
}

static void periph_interrupt(struct spmi_pmic_arb *pa, u8 apid)
static void periph_interrupt(struct spmi_pmic_arb *pa, u16 apid)
{
	unsigned int irq;
	u32 status;
	int id;
	u8 sid = (pa->apid_data[apid].ppid >> 8) & 0xF;
	u8 per = pa->apid_data[apid].ppid & 0xFF;

	status = readl_relaxed(pa->intr + pa->ver_ops->irq_status(apid));
	while (status) {
		id = ffs(status) - 1;
		status &= ~BIT(id);
		irq = irq_find_mapping(pa->domain,
				       pa->apid_data[apid].ppid << 16
				     | id << 8
				     | apid);
		irq = irq_find_mapping(pa->domain, HWIRQ(sid, per, id, apid));
		if (irq == 0) {
			cleanup_irq(pa, apid, id);
			continue;
@@ -568,8 +578,8 @@ static void pmic_arb_chained_irq(struct irq_desc *desc)
static void qpnpint_irq_ack(struct irq_data *d)
{
	struct spmi_pmic_arb *pa = irq_data_get_irq_chip_data(d);
	u8 irq  = d->hwirq >> 8;
	u8 apid = d->hwirq;
	u8 irq = HWIRQ_IRQ(d->hwirq);
	u16 apid = HWIRQ_APID(d->hwirq);
	u8 data;

	writel_relaxed(BIT(irq), pa->intr + pa->ver_ops->irq_clear(apid));
@@ -580,7 +590,7 @@ static void qpnpint_irq_ack(struct irq_data *d)

static void qpnpint_irq_mask(struct irq_data *d)
{
	u8 irq  = d->hwirq >> 8;
	u8 irq = HWIRQ_IRQ(d->hwirq);
	u8 data = BIT(irq);

	qpnpint_spmi_write(d, QPNPINT_REG_EN_CLR, &data, 1);
@@ -589,8 +599,8 @@ static void qpnpint_irq_mask(struct irq_data *d)
static void qpnpint_irq_unmask(struct irq_data *d)
{
	struct spmi_pmic_arb *pa = irq_data_get_irq_chip_data(d);
	u8 irq  = d->hwirq >> 8;
	u8 apid = d->hwirq;
	u8 irq = HWIRQ_IRQ(d->hwirq);
	u16 apid = HWIRQ_APID(d->hwirq);
	u8 buf[2];

	writel_relaxed(SPMI_PIC_ACC_ENABLE_BIT,
@@ -612,7 +622,7 @@ static void qpnpint_irq_unmask(struct irq_data *d)
static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type)
{
	struct spmi_pmic_arb_qpnpint_type type;
	u8 irq = d->hwirq >> 8;
	u8 irq = HWIRQ_IRQ(d->hwirq);
	u8 bit_mask_irq = BIT(irq);

	qpnpint_spmi_read(d, QPNPINT_REG_SET_TYPE, &type, sizeof(type));
@@ -649,7 +659,7 @@ static int qpnpint_get_irqchip_state(struct irq_data *d,
				     enum irqchip_irq_state which,
				     bool *state)
{
	u8 irq = d->hwirq >> 8;
	u8 irq = HWIRQ_IRQ(d->hwirq);
	u8 status = 0;

	if (which != IRQCHIP_STATE_LINE_LEVEL)
@@ -681,7 +691,7 @@ static int qpnpint_irq_domain_dt_translate(struct irq_domain *d,
{
	struct spmi_pmic_arb *pa = d->host_data;
	int rc;
	u8 apid;
	u16 apid;

	dev_dbg(&pa->spmic->dev,
		"intspec[0] 0x%1x intspec[1] 0x%02x intspec[2] 0x%02x\n",
@@ -709,10 +719,7 @@ static int qpnpint_irq_domain_dt_translate(struct irq_domain *d,
	if (apid < pa->min_apid)
		pa->min_apid = apid;

	*out_hwirq = (intspec[0] & 0xF) << 24
		   | (intspec[1] & 0xFF) << 16
		   | (intspec[2] & 0x7) << 8
		   | apid;
	*out_hwirq = HWIRQ(intspec[0], intspec[1], intspec[2], apid);
	*out_type  = intspec[3] & IRQ_TYPE_SENSE_MASK;

	dev_dbg(&pa->spmic->dev, "out_hwirq = %lu\n", *out_hwirq);
@@ -735,7 +742,7 @@ static int qpnpint_irq_domain_map(struct irq_domain *d,
}

static int
pmic_arb_ppid_to_apid_v1(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u8 *apid)
pmic_arb_ppid_to_apid_v1(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u16 *apid)
{
	u16 ppid = sid << 8 | ((addr >> 8) & 0xFF);
	u32 *mapping_table = pa->mapping_table;
@@ -834,7 +841,7 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid)
}

static int
pmic_arb_ppid_to_apid_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u8 *apid)
pmic_arb_ppid_to_apid_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u16 *apid)
{
	u16 ppid = (sid << 8) | (addr >> 8);
	u16 apid_valid;
@@ -852,7 +859,7 @@ pmic_arb_ppid_to_apid_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u8 *apid)
static int
pmic_arb_mode_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr, mode_t *mode)
{
	u8 apid;
	u16 apid;
	int rc;

	rc = pmic_arb_ppid_to_apid_v2(pa, sid, addr, &apid);
@@ -871,7 +878,7 @@ pmic_arb_mode_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr, mode_t *mode)
static int
pmic_arb_offset_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u32 *offset)
{
	u8 apid;
	u16 apid;
	int rc;

	rc = pmic_arb_ppid_to_apid_v2(pa, sid, addr, &apid);
@@ -892,47 +899,47 @@ static u32 pmic_arb_fmt_cmd_v2(u8 opc, u8 sid, u16 addr, u8 bc)
	return (opc << 27) | ((addr & 0xff) << 4) | (bc & 0x7);
}

static u32 pmic_arb_owner_acc_status_v1(u8 m, u8 n)
static u32 pmic_arb_owner_acc_status_v1(u8 m, u16 n)
{
	return 0x20 * m + 0x4 * n;
}

static u32 pmic_arb_owner_acc_status_v2(u8 m, u8 n)
static u32 pmic_arb_owner_acc_status_v2(u8 m, u16 n)
{
	return 0x100000 + 0x1000 * m + 0x4 * n;
}

static u32 pmic_arb_owner_acc_status_v3(u8 m, u8 n)
static u32 pmic_arb_owner_acc_status_v3(u8 m, u16 n)
{
	return 0x200000 + 0x1000 * m + 0x4 * n;
}

static u32 pmic_arb_acc_enable_v1(u8 n)
static u32 pmic_arb_acc_enable_v1(u16 n)
{
	return 0x200 + 0x4 * n;
}

static u32 pmic_arb_acc_enable_v2(u8 n)
static u32 pmic_arb_acc_enable_v2(u16 n)
{
	return 0x1000 * n;
}

static u32 pmic_arb_irq_status_v1(u8 n)
static u32 pmic_arb_irq_status_v1(u16 n)
{
	return 0x600 + 0x4 * n;
}

static u32 pmic_arb_irq_status_v2(u8 n)
static u32 pmic_arb_irq_status_v2(u16 n)
{
	return 0x4 + 0x1000 * n;
}

static u32 pmic_arb_irq_clear_v1(u8 n)
static u32 pmic_arb_irq_clear_v1(u16 n)
{
	return 0xA00 + 0x4 * n;
}

static u32 pmic_arb_irq_clear_v2(u8 n)
static u32 pmic_arb_irq_clear_v2(u16 n)
{
	return 0x8 + 0x1000 * n;
}