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