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