diff options
author | Gilad Avidov <gavidov@codeaurora.org> | 2015-03-25 13:37:32 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-03-26 18:51:36 -0400 |
commit | d0c6ae41d12ad7b2ba271f279936327320b6671c (patch) | |
tree | add5d2166f09fa4b00c0e9309810841275a124f9 | |
parent | 0b9641f5722a9c08cacb534d633ff469ab02a288 (diff) |
spmi: pmic_arb: add support for hw version 2
Qualcomm PMIC Arbiter version-2 changes from version-1 are:
- Some different register offsets.
- New channel register space, one per PMIC peripheral (ppid).
All tx traffic uses these channels.
- New observer register space. All rx trafic uses this space.
- Different command format for spmi command registers.
Reviewed-by: Sagar Dharia <sdharia@codeaurora.org>
Signed-off-by: Gilad Avidov <gavidov@codeaurora.org>
Tested-by: Ivan T. Ivanov <iivanov@mm-sol.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt | 6 | ||||
-rw-r--r-- | drivers/spmi/spmi-pmic-arb.c | 319 |
2 files changed, 265 insertions, 60 deletions
diff --git a/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt b/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt index 715d0998af8e..e16b9b5afc70 100644 --- a/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt +++ b/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt | |||
@@ -1,6 +1,6 @@ | |||
1 | Qualcomm SPMI Controller (PMIC Arbiter) | 1 | Qualcomm SPMI Controller (PMIC Arbiter) |
2 | 2 | ||
3 | The SPMI PMIC Arbiter is found on the Snapdragon 800 Series. It is an SPMI | 3 | The SPMI PMIC Arbiter is found on Snapdragon chipsets. It is an SPMI |
4 | controller with wrapping arbitration logic to allow for multiple on-chip | 4 | controller with wrapping arbitration logic to allow for multiple on-chip |
5 | devices to control a single SPMI master. | 5 | devices to control a single SPMI master. |
6 | 6 | ||
@@ -19,6 +19,10 @@ Required properties: | |||
19 | "core" - core registers | 19 | "core" - core registers |
20 | "intr" - interrupt controller registers | 20 | "intr" - interrupt controller registers |
21 | "cnfg" - configuration registers | 21 | "cnfg" - configuration registers |
22 | Registers used only for V2 PMIC Arbiter: | ||
23 | "chnls" - tx-channel per virtual slave registers. | ||
24 | "obsrvr" - rx-channel (called observer) per virtual slave registers. | ||
25 | |||
22 | - reg : address + size pairs describing the PMIC arb register sets; order must | 26 | - reg : address + size pairs describing the PMIC arb register sets; order must |
23 | correspond with the order of entries in reg-names | 27 | correspond with the order of entries in reg-names |
24 | - #address-cells : must be set to 2 | 28 | - #address-cells : must be set to 2 |
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index 20559ab3466d..d7119db49cfe 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c | |||
@@ -1,4 +1,5 @@ | |||
1 | /* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. | 1 | /* |
2 | * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. | ||
2 | * | 3 | * |
3 | * This program is free software; you can redistribute it and/or modify | 4 | * This program is free software; you can redistribute it and/or modify |
4 | * it under the terms of the GNU General Public License version 2 and | 5 | * it under the terms of the GNU General Public License version 2 and |
@@ -25,22 +26,18 @@ | |||
25 | 26 | ||
26 | /* PMIC Arbiter configuration registers */ | 27 | /* PMIC Arbiter configuration registers */ |
27 | #define PMIC_ARB_VERSION 0x0000 | 28 | #define PMIC_ARB_VERSION 0x0000 |
29 | #define PMIC_ARB_VERSION_V2_MIN 0x20010000 | ||
28 | #define PMIC_ARB_INT_EN 0x0004 | 30 | #define PMIC_ARB_INT_EN 0x0004 |
29 | 31 | ||
30 | /* PMIC Arbiter channel registers */ | 32 | /* PMIC Arbiter channel registers offsets */ |
31 | #define PMIC_ARB_CMD(N) (0x0800 + (0x80 * (N))) | 33 | #define PMIC_ARB_CMD 0x00 |
32 | #define PMIC_ARB_CONFIG(N) (0x0804 + (0x80 * (N))) | 34 | #define PMIC_ARB_CONFIG 0x04 |
33 | #define PMIC_ARB_STATUS(N) (0x0808 + (0x80 * (N))) | 35 | #define PMIC_ARB_STATUS 0x08 |
34 | #define PMIC_ARB_WDATA0(N) (0x0810 + (0x80 * (N))) | 36 | #define PMIC_ARB_WDATA0 0x10 |
35 | #define PMIC_ARB_WDATA1(N) (0x0814 + (0x80 * (N))) | 37 | #define PMIC_ARB_WDATA1 0x14 |
36 | #define PMIC_ARB_RDATA0(N) (0x0818 + (0x80 * (N))) | 38 | #define PMIC_ARB_RDATA0 0x18 |
37 | #define PMIC_ARB_RDATA1(N) (0x081C + (0x80 * (N))) | 39 | #define PMIC_ARB_RDATA1 0x1C |
38 | 40 | #define PMIC_ARB_REG_CHNL(N) (0x800 + 0x4 * (N)) | |
39 | /* Interrupt Controller */ | ||
40 | #define SPMI_PIC_OWNER_ACC_STATUS(M, N) (0x0000 + ((32 * (M)) + (4 * (N)))) | ||
41 | #define SPMI_PIC_ACC_ENABLE(N) (0x0200 + (4 * (N))) | ||
42 | #define SPMI_PIC_IRQ_STATUS(N) (0x0600 + (4 * (N))) | ||
43 | #define SPMI_PIC_IRQ_CLEAR(N) (0x0A00 + (4 * (N))) | ||
44 | 41 | ||
45 | /* Mapping Table */ | 42 | /* Mapping Table */ |
46 | #define SPMI_MAPPING_TABLE_REG(N) (0x0B00 + (4 * (N))) | 43 | #define SPMI_MAPPING_TABLE_REG(N) (0x0B00 + (4 * (N))) |
@@ -52,6 +49,7 @@ | |||
52 | 49 | ||
53 | #define SPMI_MAPPING_TABLE_LEN 255 | 50 | #define SPMI_MAPPING_TABLE_LEN 255 |
54 | #define SPMI_MAPPING_TABLE_TREE_DEPTH 16 /* Maximum of 16-bits */ | 51 | #define SPMI_MAPPING_TABLE_TREE_DEPTH 16 /* Maximum of 16-bits */ |
52 | #define PPID_TO_CHAN_TABLE_SZ BIT(12) /* PPID is 12bit chan is 1byte*/ | ||
55 | 53 | ||
56 | /* Ownership Table */ | 54 | /* Ownership Table */ |
57 | #define SPMI_OWNERSHIP_TABLE_REG(N) (0x0700 + (4 * (N))) | 55 | #define SPMI_OWNERSHIP_TABLE_REG(N) (0x0700 + (4 * (N))) |
@@ -88,6 +86,7 @@ enum pmic_arb_cmd_op_code { | |||
88 | 86 | ||
89 | /* Maximum number of support PMIC peripherals */ | 87 | /* Maximum number of support PMIC peripherals */ |
90 | #define PMIC_ARB_MAX_PERIPHS 256 | 88 | #define PMIC_ARB_MAX_PERIPHS 256 |
89 | #define PMIC_ARB_MAX_CHNL 128 | ||
91 | #define PMIC_ARB_PERIPH_ID_VALID (1 << 15) | 90 | #define PMIC_ARB_PERIPH_ID_VALID (1 << 15) |
92 | #define PMIC_ARB_TIMEOUT_US 100 | 91 | #define PMIC_ARB_TIMEOUT_US 100 |
93 | #define PMIC_ARB_MAX_TRANS_BYTES (8) | 92 | #define PMIC_ARB_MAX_TRANS_BYTES (8) |
@@ -98,14 +97,17 @@ enum pmic_arb_cmd_op_code { | |||
98 | /* interrupt enable bit */ | 97 | /* interrupt enable bit */ |
99 | #define SPMI_PIC_ACC_ENABLE_BIT BIT(0) | 98 | #define SPMI_PIC_ACC_ENABLE_BIT BIT(0) |
100 | 99 | ||
100 | struct pmic_arb_ver_ops; | ||
101 | |||
101 | /** | 102 | /** |
102 | * spmi_pmic_arb_dev - SPMI PMIC Arbiter object | 103 | * spmi_pmic_arb_dev - SPMI PMIC Arbiter object |
103 | * | 104 | * |
104 | * @base: address of the PMIC Arbiter core registers. | 105 | * @rd_base: on v1 "core", on v2 "observer" register base off DT. |
106 | * @wr_base: on v1 "core", on v2 "chnls" register base off DT. | ||
105 | * @intr: address of the SPMI interrupt control registers. | 107 | * @intr: address of the SPMI interrupt control registers. |
106 | * @cnfg: address of the PMIC Arbiter configuration registers. | 108 | * @cnfg: address of the PMIC Arbiter configuration registers. |
107 | * @lock: lock to synchronize accesses. | 109 | * @lock: lock to synchronize accesses. |
108 | * @channel: which channel to use for accesses. | 110 | * @channel: execution environment channel to use for accesses. |
109 | * @irq: PMIC ARB interrupt. | 111 | * @irq: PMIC ARB interrupt. |
110 | * @ee: the current Execution Environment | 112 | * @ee: the current Execution Environment |
111 | * @min_apid: minimum APID (used for bounding IRQ search) | 113 | * @min_apid: minimum APID (used for bounding IRQ search) |
@@ -113,10 +115,14 @@ enum pmic_arb_cmd_op_code { | |||
113 | * @mapping_table: in-memory copy of PPID -> APID mapping table. | 115 | * @mapping_table: in-memory copy of PPID -> APID mapping table. |
114 | * @domain: irq domain object for PMIC IRQ domain | 116 | * @domain: irq domain object for PMIC IRQ domain |
115 | * @spmic: SPMI controller object | 117 | * @spmic: SPMI controller object |
116 | * @apid_to_ppid: cached mapping from APID to PPID | 118 | * @apid_to_ppid: in-memory copy of APID -> PPID mapping table. |
119 | * @ver_ops: version dependent operations. | ||
120 | * @ppid_to_chan in-memory copy of PPID -> channel (APID) mapping table. | ||
121 | * v2 only. | ||
117 | */ | 122 | */ |
118 | struct spmi_pmic_arb_dev { | 123 | struct spmi_pmic_arb_dev { |
119 | void __iomem *base; | 124 | void __iomem *rd_base; |
125 | void __iomem *wr_base; | ||
120 | void __iomem *intr; | 126 | void __iomem *intr; |
121 | void __iomem *cnfg; | 127 | void __iomem *cnfg; |
122 | raw_spinlock_t lock; | 128 | raw_spinlock_t lock; |
@@ -129,17 +135,54 @@ struct spmi_pmic_arb_dev { | |||
129 | struct irq_domain *domain; | 135 | struct irq_domain *domain; |
130 | struct spmi_controller *spmic; | 136 | struct spmi_controller *spmic; |
131 | u16 apid_to_ppid[256]; | 137 | u16 apid_to_ppid[256]; |
138 | const struct pmic_arb_ver_ops *ver_ops; | ||
139 | u8 *ppid_to_chan; | ||
140 | }; | ||
141 | |||
142 | /** | ||
143 | * pmic_arb_ver: version dependent functionality. | ||
144 | * | ||
145 | * @non_data_cmd: on v1 issues an spmi non-data command. | ||
146 | * on v2 no HW support, returns -EOPNOTSUPP. | ||
147 | * @offset: on v1 offset of per-ee channel. | ||
148 | * on v2 offset of per-ee and per-ppid channel. | ||
149 | * @fmt_cmd: formats a GENI/SPMI command. | ||
150 | * @owner_acc_status: on v1 offset of PMIC_ARB_SPMI_PIC_OWNERm_ACC_STATUSn | ||
151 | * on v2 offset of SPMI_PIC_OWNERm_ACC_STATUSn. | ||
152 | * @acc_enable: on v1 offset of PMIC_ARB_SPMI_PIC_ACC_ENABLEn | ||
153 | * on v2 offset of SPMI_PIC_ACC_ENABLEn. | ||
154 | * @irq_status: on v1 offset of PMIC_ARB_SPMI_PIC_IRQ_STATUSn | ||
155 | * on v2 offset of SPMI_PIC_IRQ_STATUSn. | ||
156 | * @irq_clear: on v1 offset of PMIC_ARB_SPMI_PIC_IRQ_CLEARn | ||
157 | * on v2 offset of SPMI_PIC_IRQ_CLEARn. | ||
158 | */ | ||
159 | struct pmic_arb_ver_ops { | ||
160 | /* spmi commands (read_cmd, write_cmd, cmd) functionality */ | ||
161 | u32 (*offset)(struct spmi_pmic_arb_dev *dev, u8 sid, u16 addr); | ||
162 | u32 (*fmt_cmd)(u8 opc, u8 sid, u16 addr, u8 bc); | ||
163 | int (*non_data_cmd)(struct spmi_controller *ctrl, u8 opc, u8 sid); | ||
164 | /* Interrupts controller functionality (offset of PIC registers) */ | ||
165 | u32 (*owner_acc_status)(u8 m, u8 n); | ||
166 | u32 (*acc_enable)(u8 n); | ||
167 | u32 (*irq_status)(u8 n); | ||
168 | u32 (*irq_clear)(u8 n); | ||
132 | }; | 169 | }; |
133 | 170 | ||
134 | static inline u32 pmic_arb_base_read(struct spmi_pmic_arb_dev *dev, u32 offset) | 171 | static inline u32 pmic_arb_base_read(struct spmi_pmic_arb_dev *dev, u32 offset) |
135 | { | 172 | { |
136 | return readl_relaxed(dev->base + offset); | 173 | return readl_relaxed(dev->rd_base + offset); |
137 | } | 174 | } |
138 | 175 | ||
139 | static inline void pmic_arb_base_write(struct spmi_pmic_arb_dev *dev, | 176 | static inline void pmic_arb_base_write(struct spmi_pmic_arb_dev *dev, |
140 | u32 offset, u32 val) | 177 | u32 offset, u32 val) |
141 | { | 178 | { |
142 | writel_relaxed(val, dev->base + offset); | 179 | writel_relaxed(val, dev->wr_base + offset); |
180 | } | ||
181 | |||
182 | static inline void pmic_arb_set_rd_cmd(struct spmi_pmic_arb_dev *dev, | ||
183 | u32 offset, u32 val) | ||
184 | { | ||
185 | writel_relaxed(val, dev->rd_base + offset); | ||
143 | } | 186 | } |
144 | 187 | ||
145 | /** | 188 | /** |
@@ -168,15 +211,16 @@ pa_write_data(struct spmi_pmic_arb_dev *dev, const u8 *buf, u32 reg, u8 bc) | |||
168 | pmic_arb_base_write(dev, reg, data); | 211 | pmic_arb_base_write(dev, reg, data); |
169 | } | 212 | } |
170 | 213 | ||
171 | static int pmic_arb_wait_for_done(struct spmi_controller *ctrl) | 214 | static int pmic_arb_wait_for_done(struct spmi_controller *ctrl, |
215 | void __iomem *base, u8 sid, u16 addr) | ||
172 | { | 216 | { |
173 | struct spmi_pmic_arb_dev *dev = spmi_controller_get_drvdata(ctrl); | 217 | struct spmi_pmic_arb_dev *dev = spmi_controller_get_drvdata(ctrl); |
174 | u32 status = 0; | 218 | u32 status = 0; |
175 | u32 timeout = PMIC_ARB_TIMEOUT_US; | 219 | u32 timeout = PMIC_ARB_TIMEOUT_US; |
176 | u32 offset = PMIC_ARB_STATUS(dev->channel); | 220 | u32 offset = dev->ver_ops->offset(dev, sid, addr) + PMIC_ARB_STATUS; |
177 | 221 | ||
178 | while (timeout--) { | 222 | while (timeout--) { |
179 | status = pmic_arb_base_read(dev, offset); | 223 | status = readl_relaxed(base + offset); |
180 | 224 | ||
181 | if (status & PMIC_ARB_STATUS_DONE) { | 225 | if (status & PMIC_ARB_STATUS_DONE) { |
182 | if (status & PMIC_ARB_STATUS_DENIED) { | 226 | if (status & PMIC_ARB_STATUS_DENIED) { |
@@ -211,28 +255,45 @@ static int pmic_arb_wait_for_done(struct spmi_controller *ctrl) | |||
211 | return -ETIMEDOUT; | 255 | return -ETIMEDOUT; |
212 | } | 256 | } |
213 | 257 | ||
214 | /* Non-data command */ | 258 | static int |
215 | static int pmic_arb_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid) | 259 | pmic_arb_non_data_cmd_v1(struct spmi_controller *ctrl, u8 opc, u8 sid) |
216 | { | 260 | { |
217 | struct spmi_pmic_arb_dev *pmic_arb = spmi_controller_get_drvdata(ctrl); | 261 | struct spmi_pmic_arb_dev *pmic_arb = spmi_controller_get_drvdata(ctrl); |
218 | unsigned long flags; | 262 | unsigned long flags; |
219 | u32 cmd; | 263 | u32 cmd; |
220 | int rc; | 264 | int rc; |
221 | 265 | u32 offset = pmic_arb->ver_ops->offset(pmic_arb, sid, 0); | |
222 | /* Check for valid non-data command */ | ||
223 | if (opc < SPMI_CMD_RESET || opc > SPMI_CMD_WAKEUP) | ||
224 | return -EINVAL; | ||
225 | 266 | ||
226 | cmd = ((opc | 0x40) << 27) | ((sid & 0xf) << 20); | 267 | cmd = ((opc | 0x40) << 27) | ((sid & 0xf) << 20); |
227 | 268 | ||
228 | raw_spin_lock_irqsave(&pmic_arb->lock, flags); | 269 | raw_spin_lock_irqsave(&pmic_arb->lock, flags); |
229 | pmic_arb_base_write(pmic_arb, PMIC_ARB_CMD(pmic_arb->channel), cmd); | 270 | pmic_arb_base_write(pmic_arb, offset + PMIC_ARB_CMD, cmd); |
230 | rc = pmic_arb_wait_for_done(ctrl); | 271 | rc = pmic_arb_wait_for_done(ctrl, pmic_arb->wr_base, sid, 0); |
231 | raw_spin_unlock_irqrestore(&pmic_arb->lock, flags); | 272 | raw_spin_unlock_irqrestore(&pmic_arb->lock, flags); |
232 | 273 | ||
233 | return rc; | 274 | return rc; |
234 | } | 275 | } |
235 | 276 | ||
277 | static int | ||
278 | pmic_arb_non_data_cmd_v2(struct spmi_controller *ctrl, u8 opc, u8 sid) | ||
279 | { | ||
280 | return -EOPNOTSUPP; | ||
281 | } | ||
282 | |||
283 | /* Non-data command */ | ||
284 | static int pmic_arb_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid) | ||
285 | { | ||
286 | struct spmi_pmic_arb_dev *pmic_arb = spmi_controller_get_drvdata(ctrl); | ||
287 | |||
288 | dev_dbg(&ctrl->dev, "cmd op:0x%x sid:%d\n", opc, sid); | ||
289 | |||
290 | /* Check for valid non-data command */ | ||
291 | if (opc < SPMI_CMD_RESET || opc > SPMI_CMD_WAKEUP) | ||
292 | return -EINVAL; | ||
293 | |||
294 | return pmic_arb->ver_ops->non_data_cmd(ctrl, opc, sid); | ||
295 | } | ||
296 | |||
236 | static int pmic_arb_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, | 297 | static int pmic_arb_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, |
237 | u16 addr, u8 *buf, size_t len) | 298 | u16 addr, u8 *buf, size_t len) |
238 | { | 299 | { |
@@ -241,10 +302,11 @@ static int pmic_arb_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, | |||
241 | u8 bc = len - 1; | 302 | u8 bc = len - 1; |
242 | u32 cmd; | 303 | u32 cmd; |
243 | int rc; | 304 | int rc; |
305 | u32 offset = pmic_arb->ver_ops->offset(pmic_arb, sid, addr); | ||
244 | 306 | ||
245 | if (bc >= PMIC_ARB_MAX_TRANS_BYTES) { | 307 | if (bc >= PMIC_ARB_MAX_TRANS_BYTES) { |
246 | dev_err(&ctrl->dev, | 308 | dev_err(&ctrl->dev, |
247 | "pmic-arb supports 1..%d bytes per trans, but %d requested", | 309 | "pmic-arb supports 1..%d bytes per trans, but:%zu requested", |
248 | PMIC_ARB_MAX_TRANS_BYTES, len); | 310 | PMIC_ARB_MAX_TRANS_BYTES, len); |
249 | return -EINVAL; | 311 | return -EINVAL; |
250 | } | 312 | } |
@@ -259,20 +321,20 @@ static int pmic_arb_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, | |||
259 | else | 321 | else |
260 | return -EINVAL; | 322 | return -EINVAL; |
261 | 323 | ||
262 | cmd = (opc << 27) | ((sid & 0xf) << 20) | (addr << 4) | (bc & 0x7); | 324 | cmd = pmic_arb->ver_ops->fmt_cmd(opc, sid, addr, bc); |
263 | 325 | ||
264 | raw_spin_lock_irqsave(&pmic_arb->lock, flags); | 326 | raw_spin_lock_irqsave(&pmic_arb->lock, flags); |
265 | pmic_arb_base_write(pmic_arb, PMIC_ARB_CMD(pmic_arb->channel), cmd); | 327 | pmic_arb_set_rd_cmd(pmic_arb, offset + PMIC_ARB_CMD, cmd); |
266 | rc = pmic_arb_wait_for_done(ctrl); | 328 | rc = pmic_arb_wait_for_done(ctrl, pmic_arb->rd_base, sid, addr); |
267 | if (rc) | 329 | if (rc) |
268 | goto done; | 330 | goto done; |
269 | 331 | ||
270 | pa_read_data(pmic_arb, buf, PMIC_ARB_RDATA0(pmic_arb->channel), | 332 | pa_read_data(pmic_arb, buf, offset + PMIC_ARB_RDATA0, |
271 | min_t(u8, bc, 3)); | 333 | min_t(u8, bc, 3)); |
272 | 334 | ||
273 | if (bc > 3) | 335 | if (bc > 3) |
274 | pa_read_data(pmic_arb, buf + 4, | 336 | pa_read_data(pmic_arb, buf + 4, |
275 | PMIC_ARB_RDATA1(pmic_arb->channel), bc - 4); | 337 | offset + PMIC_ARB_RDATA1, bc - 4); |
276 | 338 | ||
277 | done: | 339 | done: |
278 | raw_spin_unlock_irqrestore(&pmic_arb->lock, flags); | 340 | raw_spin_unlock_irqrestore(&pmic_arb->lock, flags); |
@@ -287,10 +349,11 @@ static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, | |||
287 | u8 bc = len - 1; | 349 | u8 bc = len - 1; |
288 | u32 cmd; | 350 | u32 cmd; |
289 | int rc; | 351 | int rc; |
352 | u32 offset = pmic_arb->ver_ops->offset(pmic_arb, sid, addr); | ||
290 | 353 | ||
291 | if (bc >= PMIC_ARB_MAX_TRANS_BYTES) { | 354 | if (bc >= PMIC_ARB_MAX_TRANS_BYTES) { |
292 | dev_err(&ctrl->dev, | 355 | dev_err(&ctrl->dev, |
293 | "pmic-arb supports 1..%d bytes per trans, but:%d requested", | 356 | "pmic-arb supports 1..%d bytes per trans, but:%zu requested", |
294 | PMIC_ARB_MAX_TRANS_BYTES, len); | 357 | PMIC_ARB_MAX_TRANS_BYTES, len); |
295 | return -EINVAL; | 358 | return -EINVAL; |
296 | } | 359 | } |
@@ -307,19 +370,19 @@ static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, | |||
307 | else | 370 | else |
308 | return -EINVAL; | 371 | return -EINVAL; |
309 | 372 | ||
310 | cmd = (opc << 27) | ((sid & 0xf) << 20) | (addr << 4) | (bc & 0x7); | 373 | cmd = pmic_arb->ver_ops->fmt_cmd(opc, sid, addr, bc); |
311 | 374 | ||
312 | /* Write data to FIFOs */ | 375 | /* Write data to FIFOs */ |
313 | raw_spin_lock_irqsave(&pmic_arb->lock, flags); | 376 | raw_spin_lock_irqsave(&pmic_arb->lock, flags); |
314 | pa_write_data(pmic_arb, buf, PMIC_ARB_WDATA0(pmic_arb->channel) | 377 | pa_write_data(pmic_arb, buf, offset + PMIC_ARB_WDATA0, |
315 | , min_t(u8, bc, 3)); | 378 | min_t(u8, bc, 3)); |
316 | if (bc > 3) | 379 | if (bc > 3) |
317 | pa_write_data(pmic_arb, buf + 4, | 380 | pa_write_data(pmic_arb, buf + 4, |
318 | PMIC_ARB_WDATA1(pmic_arb->channel), bc - 4); | 381 | offset + PMIC_ARB_WDATA1, bc - 4); |
319 | 382 | ||
320 | /* Start the transaction */ | 383 | /* Start the transaction */ |
321 | pmic_arb_base_write(pmic_arb, PMIC_ARB_CMD(pmic_arb->channel), cmd); | 384 | pmic_arb_base_write(pmic_arb, offset + PMIC_ARB_CMD, cmd); |
322 | rc = pmic_arb_wait_for_done(ctrl); | 385 | rc = pmic_arb_wait_for_done(ctrl, pmic_arb->wr_base, sid, addr); |
323 | raw_spin_unlock_irqrestore(&pmic_arb->lock, flags); | 386 | raw_spin_unlock_irqrestore(&pmic_arb->lock, flags); |
324 | 387 | ||
325 | return rc; | 388 | return rc; |
@@ -376,7 +439,7 @@ static void periph_interrupt(struct spmi_pmic_arb_dev *pa, u8 apid) | |||
376 | u32 status; | 439 | u32 status; |
377 | int id; | 440 | int id; |
378 | 441 | ||
379 | status = readl_relaxed(pa->intr + SPMI_PIC_IRQ_STATUS(apid)); | 442 | status = readl_relaxed(pa->intr + pa->ver_ops->irq_status(apid)); |
380 | while (status) { | 443 | while (status) { |
381 | id = ffs(status) - 1; | 444 | id = ffs(status) - 1; |
382 | status &= ~(1 << id); | 445 | status &= ~(1 << id); |
@@ -402,7 +465,7 @@ static void pmic_arb_chained_irq(unsigned int irq, struct irq_desc *desc) | |||
402 | 465 | ||
403 | for (i = first; i <= last; ++i) { | 466 | for (i = first; i <= last; ++i) { |
404 | status = readl_relaxed(intr + | 467 | status = readl_relaxed(intr + |
405 | SPMI_PIC_OWNER_ACC_STATUS(pa->ee, i)); | 468 | pa->ver_ops->owner_acc_status(pa->ee, i)); |
406 | while (status) { | 469 | while (status) { |
407 | id = ffs(status) - 1; | 470 | id = ffs(status) - 1; |
408 | status &= ~(1 << id); | 471 | status &= ~(1 << id); |
@@ -422,7 +485,7 @@ static void qpnpint_irq_ack(struct irq_data *d) | |||
422 | u8 data; | 485 | u8 data; |
423 | 486 | ||
424 | raw_spin_lock_irqsave(&pa->lock, flags); | 487 | raw_spin_lock_irqsave(&pa->lock, flags); |
425 | writel_relaxed(1 << irq, pa->intr + SPMI_PIC_IRQ_CLEAR(apid)); | 488 | writel_relaxed(1 << irq, pa->intr + pa->ver_ops->irq_clear(apid)); |
426 | raw_spin_unlock_irqrestore(&pa->lock, flags); | 489 | raw_spin_unlock_irqrestore(&pa->lock, flags); |
427 | 490 | ||
428 | data = 1 << irq; | 491 | data = 1 << irq; |
@@ -439,10 +502,11 @@ static void qpnpint_irq_mask(struct irq_data *d) | |||
439 | u8 data; | 502 | u8 data; |
440 | 503 | ||
441 | raw_spin_lock_irqsave(&pa->lock, flags); | 504 | raw_spin_lock_irqsave(&pa->lock, flags); |
442 | status = readl_relaxed(pa->intr + SPMI_PIC_ACC_ENABLE(apid)); | 505 | status = readl_relaxed(pa->intr + pa->ver_ops->acc_enable(apid)); |
443 | if (status & SPMI_PIC_ACC_ENABLE_BIT) { | 506 | if (status & SPMI_PIC_ACC_ENABLE_BIT) { |
444 | status = status & ~SPMI_PIC_ACC_ENABLE_BIT; | 507 | status = status & ~SPMI_PIC_ACC_ENABLE_BIT; |
445 | writel_relaxed(status, pa->intr + SPMI_PIC_ACC_ENABLE(apid)); | 508 | writel_relaxed(status, pa->intr + |
509 | pa->ver_ops->acc_enable(apid)); | ||
446 | } | 510 | } |
447 | raw_spin_unlock_irqrestore(&pa->lock, flags); | 511 | raw_spin_unlock_irqrestore(&pa->lock, flags); |
448 | 512 | ||
@@ -460,10 +524,10 @@ static void qpnpint_irq_unmask(struct irq_data *d) | |||
460 | u8 data; | 524 | u8 data; |
461 | 525 | ||
462 | raw_spin_lock_irqsave(&pa->lock, flags); | 526 | raw_spin_lock_irqsave(&pa->lock, flags); |
463 | status = readl_relaxed(pa->intr + SPMI_PIC_ACC_ENABLE(apid)); | 527 | status = readl_relaxed(pa->intr + pa->ver_ops->acc_enable(apid)); |
464 | if (!(status & SPMI_PIC_ACC_ENABLE_BIT)) { | 528 | if (!(status & SPMI_PIC_ACC_ENABLE_BIT)) { |
465 | writel_relaxed(status | SPMI_PIC_ACC_ENABLE_BIT, | 529 | writel_relaxed(status | SPMI_PIC_ACC_ENABLE_BIT, |
466 | pa->intr + SPMI_PIC_ACC_ENABLE(apid)); | 530 | pa->intr + pa->ver_ops->acc_enable(apid)); |
467 | } | 531 | } |
468 | raw_spin_unlock_irqrestore(&pa->lock, flags); | 532 | raw_spin_unlock_irqrestore(&pa->lock, flags); |
469 | 533 | ||
@@ -624,6 +688,91 @@ static int qpnpint_irq_domain_map(struct irq_domain *d, | |||
624 | return 0; | 688 | return 0; |
625 | } | 689 | } |
626 | 690 | ||
691 | /* v1 offset per ee */ | ||
692 | static u32 pmic_arb_offset_v1(struct spmi_pmic_arb_dev *pa, u8 sid, u16 addr) | ||
693 | { | ||
694 | return 0x800 + 0x80 * pa->channel; | ||
695 | } | ||
696 | |||
697 | /* v2 offset per ppid (chan) and per ee */ | ||
698 | static u32 pmic_arb_offset_v2(struct spmi_pmic_arb_dev *pa, u8 sid, u16 addr) | ||
699 | { | ||
700 | u16 ppid = (sid << 8) | (addr >> 8); | ||
701 | u8 chan = pa->ppid_to_chan[ppid]; | ||
702 | |||
703 | return 0x1000 * pa->ee + 0x8000 * chan; | ||
704 | } | ||
705 | |||
706 | static u32 pmic_arb_fmt_cmd_v1(u8 opc, u8 sid, u16 addr, u8 bc) | ||
707 | { | ||
708 | return (opc << 27) | ((sid & 0xf) << 20) | (addr << 4) | (bc & 0x7); | ||
709 | } | ||
710 | |||
711 | static u32 pmic_arb_fmt_cmd_v2(u8 opc, u8 sid, u16 addr, u8 bc) | ||
712 | { | ||
713 | return (opc << 27) | ((addr & 0xff) << 4) | (bc & 0x7); | ||
714 | } | ||
715 | |||
716 | static u32 pmic_arb_owner_acc_status_v1(u8 m, u8 n) | ||
717 | { | ||
718 | return 0x20 * m + 0x4 * n; | ||
719 | } | ||
720 | |||
721 | static u32 pmic_arb_owner_acc_status_v2(u8 m, u8 n) | ||
722 | { | ||
723 | return 0x100000 + 0x1000 * m + 0x4 * n; | ||
724 | } | ||
725 | |||
726 | static u32 pmic_arb_acc_enable_v1(u8 n) | ||
727 | { | ||
728 | return 0x200 + 0x4 * n; | ||
729 | } | ||
730 | |||
731 | static u32 pmic_arb_acc_enable_v2(u8 n) | ||
732 | { | ||
733 | return 0x1000 * n; | ||
734 | } | ||
735 | |||
736 | static u32 pmic_arb_irq_status_v1(u8 n) | ||
737 | { | ||
738 | return 0x600 + 0x4 * n; | ||
739 | } | ||
740 | |||
741 | static u32 pmic_arb_irq_status_v2(u8 n) | ||
742 | { | ||
743 | return 0x4 + 0x1000 * n; | ||
744 | } | ||
745 | |||
746 | static u32 pmic_arb_irq_clear_v1(u8 n) | ||
747 | { | ||
748 | return 0xA00 + 0x4 * n; | ||
749 | } | ||
750 | |||
751 | static u32 pmic_arb_irq_clear_v2(u8 n) | ||
752 | { | ||
753 | return 0x8 + 0x1000 * n; | ||
754 | } | ||
755 | |||
756 | static const struct pmic_arb_ver_ops pmic_arb_v1 = { | ||
757 | .non_data_cmd = pmic_arb_non_data_cmd_v1, | ||
758 | .offset = pmic_arb_offset_v1, | ||
759 | .fmt_cmd = pmic_arb_fmt_cmd_v1, | ||
760 | .owner_acc_status = pmic_arb_owner_acc_status_v1, | ||
761 | .acc_enable = pmic_arb_acc_enable_v1, | ||
762 | .irq_status = pmic_arb_irq_status_v1, | ||
763 | .irq_clear = pmic_arb_irq_clear_v1, | ||
764 | }; | ||
765 | |||
766 | static const struct pmic_arb_ver_ops pmic_arb_v2 = { | ||
767 | .non_data_cmd = pmic_arb_non_data_cmd_v2, | ||
768 | .offset = pmic_arb_offset_v2, | ||
769 | .fmt_cmd = pmic_arb_fmt_cmd_v2, | ||
770 | .owner_acc_status = pmic_arb_owner_acc_status_v2, | ||
771 | .acc_enable = pmic_arb_acc_enable_v2, | ||
772 | .irq_status = pmic_arb_irq_status_v2, | ||
773 | .irq_clear = pmic_arb_irq_clear_v2, | ||
774 | }; | ||
775 | |||
627 | static const struct irq_domain_ops pmic_arb_irq_domain_ops = { | 776 | static const struct irq_domain_ops pmic_arb_irq_domain_ops = { |
628 | .map = qpnpint_irq_domain_map, | 777 | .map = qpnpint_irq_domain_map, |
629 | .xlate = qpnpint_irq_domain_dt_translate, | 778 | .xlate = qpnpint_irq_domain_dt_translate, |
@@ -634,8 +783,10 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev) | |||
634 | struct spmi_pmic_arb_dev *pa; | 783 | struct spmi_pmic_arb_dev *pa; |
635 | struct spmi_controller *ctrl; | 784 | struct spmi_controller *ctrl; |
636 | struct resource *res; | 785 | struct resource *res; |
637 | u32 channel, ee; | 786 | void __iomem *core; |
787 | u32 channel, ee, hw_ver; | ||
638 | int err, i; | 788 | int err, i; |
789 | bool is_v1; | ||
639 | 790 | ||
640 | ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*pa)); | 791 | ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*pa)); |
641 | if (!ctrl) | 792 | if (!ctrl) |
@@ -645,12 +796,65 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev) | |||
645 | pa->spmic = ctrl; | 796 | pa->spmic = ctrl; |
646 | 797 | ||
647 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core"); | 798 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core"); |
648 | pa->base = devm_ioremap_resource(&ctrl->dev, res); | 799 | core = devm_ioremap_resource(&ctrl->dev, res); |
649 | if (IS_ERR(pa->base)) { | 800 | if (IS_ERR(core)) { |
650 | err = PTR_ERR(pa->base); | 801 | err = PTR_ERR(core); |
651 | goto err_put_ctrl; | 802 | goto err_put_ctrl; |
652 | } | 803 | } |
653 | 804 | ||
805 | hw_ver = readl_relaxed(core + PMIC_ARB_VERSION); | ||
806 | is_v1 = (hw_ver < PMIC_ARB_VERSION_V2_MIN); | ||
807 | |||
808 | dev_info(&ctrl->dev, "PMIC Arb Version-%d (0x%x)\n", (is_v1 ? 1 : 2), | ||
809 | hw_ver); | ||
810 | |||
811 | if (is_v1) { | ||
812 | pa->ver_ops = &pmic_arb_v1; | ||
813 | pa->wr_base = core; | ||
814 | pa->rd_base = core; | ||
815 | } else { | ||
816 | u8 chan; | ||
817 | u16 ppid; | ||
818 | u32 regval; | ||
819 | |||
820 | pa->ver_ops = &pmic_arb_v2; | ||
821 | |||
822 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, | ||
823 | "obsrvr"); | ||
824 | pa->rd_base = devm_ioremap_resource(&ctrl->dev, res); | ||
825 | if (IS_ERR(pa->rd_base)) { | ||
826 | err = PTR_ERR(pa->rd_base); | ||
827 | goto err_put_ctrl; | ||
828 | } | ||
829 | |||
830 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, | ||
831 | "chnls"); | ||
832 | pa->wr_base = devm_ioremap_resource(&ctrl->dev, res); | ||
833 | if (IS_ERR(pa->wr_base)) { | ||
834 | err = PTR_ERR(pa->wr_base); | ||
835 | goto err_put_ctrl; | ||
836 | } | ||
837 | |||
838 | pa->ppid_to_chan = devm_kzalloc(&ctrl->dev, | ||
839 | PPID_TO_CHAN_TABLE_SZ, GFP_KERNEL); | ||
840 | if (!pa->ppid_to_chan) { | ||
841 | err = -ENOMEM; | ||
842 | goto err_put_ctrl; | ||
843 | } | ||
844 | /* | ||
845 | * PMIC_ARB_REG_CHNL is a table in HW mapping channel to ppid. | ||
846 | * ppid_to_chan is an in-memory invert of that table. | ||
847 | */ | ||
848 | for (chan = 0; chan < PMIC_ARB_MAX_CHNL; ++chan) { | ||
849 | regval = readl_relaxed(core + PMIC_ARB_REG_CHNL(chan)); | ||
850 | if (!regval) | ||
851 | continue; | ||
852 | |||
853 | ppid = (regval >> 8) & 0xFFF; | ||
854 | pa->ppid_to_chan[ppid] = chan; | ||
855 | } | ||
856 | } | ||
857 | |||
654 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intr"); | 858 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intr"); |
655 | pa->intr = devm_ioremap_resource(&ctrl->dev, res); | 859 | pa->intr = devm_ioremap_resource(&ctrl->dev, res); |
656 | if (IS_ERR(pa->intr)) { | 860 | if (IS_ERR(pa->intr)) { |
@@ -731,9 +935,6 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev) | |||
731 | if (err) | 935 | if (err) |
732 | goto err_domain_remove; | 936 | goto err_domain_remove; |
733 | 937 | ||
734 | dev_dbg(&ctrl->dev, "PMIC Arb Version 0x%x\n", | ||
735 | pmic_arb_base_read(pa, PMIC_ARB_VERSION)); | ||
736 | |||
737 | return 0; | 938 | return 0; |
738 | 939 | ||
739 | err_domain_remove: | 940 | err_domain_remove: |