1 /*
2  * Copyright (c) 2020, Google LLC. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <common/debug.h>
8 #include <drivers/delay_timer.h>
9 #include <lib/mmio.h>
10 
11 #include <spmi_arb.h>
12 
13 #define REG_APID_MAP(apid)	(0x0C440900U + sizeof(uint32_t) * apid)
14 #define NUM_APID		((0x1100U - 0x900U) / sizeof(uint32_t))
15 
16 #define PPID_MASK		(0xfffU << 8)
17 
18 #define REG_ARB_CMD(apid)	(0x0C600000U + 0x10000U * apid)
19 /* These are opcodes specific to this SPMI arbitrator, *not* SPMI commands. */
20 #define OPC_EXT_WRITEL		0
21 #define OPC_EXT_READL		1
22 
23 #define REG_ARB_STATUS(apid)	(0x0C600008U + 0x10000U * apid)
24 #define ARB_STATUS_DONE		BIT(0)
25 #define ARB_STATUS_FAILURE	BIT(1)
26 #define ARB_STATUS_DENIED	BIT(2)
27 #define ARB_STATUS_DROPPED	BIT(3)
28 
29 /* Fake status to report driver errors. */
30 #define ARB_FAKE_STATUS_TIMEOUT	BIT(8)
31 
32 #define REG_ARB_RDATA0(apid)	(0x0C600018U + 0x10000U * apid)
33 #define REG_ARB_WDATA0(apid)	(0x0C600010U + 0x10000U * apid)
34 
addr_to_apid(uint32_t addr)35 static int addr_to_apid(uint32_t addr)
36 {
37 	unsigned int i;
38 
39 	for (i = 0U; i < NUM_APID; i++) {
40 		uint32_t reg = mmio_read_32(REG_APID_MAP(i));
41 		if ((reg != 0U) && ((addr & PPID_MASK) == (reg & PPID_MASK))) {
42 			return i;
43 		}
44 	}
45 
46 	return -1;
47 }
48 
wait_for_done(uint16_t apid)49 static int wait_for_done(uint16_t apid)
50 {
51 	unsigned int timeout = 100;
52 
53 	while (timeout-- != 0U) {
54 		uint32_t status = mmio_read_32(REG_ARB_STATUS(apid));
55 		if ((status & ARB_STATUS_DONE) != 0U) {
56 			if ((status & ARB_STATUS_FAILURE) != 0U ||
57 			    (status & ARB_STATUS_DENIED) != 0U ||
58 			    (status & ARB_STATUS_DROPPED) != 0U) {
59 				return status & 0xff;
60 			}
61 			return 0;
62 		}
63 		mdelay(1);
64 	}
65 	ERROR("SPMI_ARB timeout!\n");
66 	return ARB_FAKE_STATUS_TIMEOUT;
67 }
68 
arb_command(uint16_t apid,uint8_t opcode,uint32_t addr,uint8_t bytes)69 static void arb_command(uint16_t apid, uint8_t opcode, uint32_t addr,
70 			uint8_t bytes)
71 {
72 	mmio_write_32(REG_ARB_CMD(apid), (uint32_t)opcode << 27 |
73 					 (addr & 0xff) << 4 | (bytes - 1));
74 }
75 
spmi_arb_read8(uint32_t addr)76 int spmi_arb_read8(uint32_t addr)
77 {
78 	int apid = addr_to_apid(addr);
79 
80 	if (apid < 0) {
81 		return apid;
82 	}
83 
84 	arb_command(apid, OPC_EXT_READL, addr, 1);
85 
86 	int ret = wait_for_done(apid);
87 	if (ret != 0) {
88 		ERROR("SPMI_ARB read error [0x%x]: 0x%x\n", addr, ret);
89 		return ret;
90 	}
91 
92 	return mmio_read_32(REG_ARB_RDATA0(apid)) & 0xff;
93 }
94 
spmi_arb_write8(uint32_t addr,uint8_t data)95 int spmi_arb_write8(uint32_t addr, uint8_t data)
96 {
97 	int apid = addr_to_apid(addr);
98 
99 	if (apid < 0) {
100 		return apid;
101 	}
102 
103 	mmio_write_32(REG_ARB_WDATA0(apid), data);
104 	arb_command(apid, OPC_EXT_WRITEL, addr, 1);
105 
106 	int ret = wait_for_done(apid);
107 	if (ret != 0) {
108 		ERROR("SPMI_ARB write error [0x%x] = 0x%x: 0x%x\n",
109 		      addr, data, ret);
110 	}
111 
112 	return ret;
113 }
114