blob: 16e85a6fc47297aaf67b940f4133c0b5402d8541 [file] [log] [blame]
Julius Werner898a8df2019-06-05 12:40:35 -07001/*
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
Julius Werner3a95cd22020-08-27 16:30:44 -070013#define REG_APID_MAP(apid) (0x0C440900U + 4U * i)
Julius Werner898a8df2019-06-05 12:40:35 -070014#define NUM_APID 0x80
15
Julius Werner3a95cd22020-08-27 16:30:44 -070016#define PPID_MASK (0xfffU << 8)
Julius Werner898a8df2019-06-05 12:40:35 -070017
Julius Werner3a95cd22020-08-27 16:30:44 -070018#define REG_ARB_CMD(apid) (0x0C600000U + 0x10000U * apid)
Julius Werner898a8df2019-06-05 12:40:35 -070019/* These are opcodes specific to this SPMI arbitrator, *not* SPMI commands. */
20#define OPC_EXT_WRITEL 0
21#define OPC_EXT_READL 1
22
Julius Werner3a95cd22020-08-27 16:30:44 -070023#define REG_ARB_STATUS(apid) (0x0C600008U + 0x10000U * apid)
Julius Werner898a8df2019-06-05 12:40:35 -070024#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
Julius Werner3a95cd22020-08-27 16:30:44 -070032#define REG_ARB_RDATA0(apid) (0x0C600018U + 0x10000U * apid)
33#define REG_ARB_WDATA0(apid) (0x0C600010U + 0x10000U * apid)
Julius Werner898a8df2019-06-05 12:40:35 -070034
35static 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
49static 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
69static 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
76int 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
95int 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}