blob: 7075c674d50510be276b4258ba63043780adfe36 [file] [log] [blame]
Andre Przywara10d69c72017-12-13 01:08:01 +00001/*
2 * Copyright (c) 2017-2018 ARM Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <debug.h>
8#include <delay_timer.h>
9#include <errno.h>
10#include <mmio.h>
11#include <sunxi_mmap.h>
12
13#define RSB_CTRL 0x00
14#define RSB_CCR 0x04
15#define RSB_INTE 0x08
16#define RSB_STAT 0x0c
17#define RSB_DADDR0 0x10
18#define RSB_DLEN 0x18
19#define RSB_DATA0 0x1c
20#define RSB_LCR 0x24
21#define RSB_PMCR 0x28
22#define RSB_CMD 0x2c
23#define RSB_SADDR 0x30
24
25#define RSBCMD_SRTA 0xE8
26#define RSBCMD_RD8 0x8B
27#define RSBCMD_RD16 0x9C
28#define RSBCMD_RD32 0xA6
29#define RSBCMD_WR8 0x4E
30#define RSBCMD_WR16 0x59
31#define RSBCMD_WR32 0x63
32
33#define MAX_TRIES 100000
34
35static int rsb_wait_bit(const char *desc, unsigned int offset, uint32_t mask)
36{
37 uint32_t reg, tries = MAX_TRIES;
38
39 do
40 reg = mmio_read_32(SUNXI_R_RSB_BASE + offset);
41 while ((reg & mask) && --tries); /* transaction in progress */
42 if (reg & mask) {
43 ERROR("%s: timed out\n", desc);
44 return -ETIMEDOUT;
45 }
46
47 return 0;
48}
49
50static int rsb_wait_stat(const char *desc)
51{
52 uint32_t reg;
53 int ret = rsb_wait_bit(desc, RSB_CTRL, BIT(7));
54
55 if (ret)
56 return ret;
57
58 reg = mmio_read_32(SUNXI_R_RSB_BASE + RSB_STAT);
59 if (reg == 0x01)
60 return 0;
61
62 ERROR("%s: 0x%x\n", desc, reg);
63 return -reg;
64}
65
66/* Initialize the RSB controller. */
67int rsb_init_controller(void)
68{
69 mmio_write_32(SUNXI_R_RSB_BASE + RSB_CTRL, 0x01); /* soft reset */
70
71 return rsb_wait_bit("RSB: reset controller", RSB_CTRL, BIT(0));
72}
73
74int rsb_read(uint8_t rt_addr, uint8_t reg_addr)
75{
76 int ret;
77
78 mmio_write_32(SUNXI_R_RSB_BASE + RSB_CMD, RSBCMD_RD8); /* read a byte */
79 mmio_write_32(SUNXI_R_RSB_BASE + RSB_SADDR, rt_addr << 16);
80 mmio_write_32(SUNXI_R_RSB_BASE + RSB_DADDR0, reg_addr);
81 mmio_write_32(SUNXI_R_RSB_BASE + RSB_CTRL, 0x80);/* start transaction */
82
83 ret = rsb_wait_stat("RSB: read command");
84 if (ret)
85 return ret;
86
87 return mmio_read_32(SUNXI_R_RSB_BASE + RSB_DATA0) & 0xff; /* result */
88}
89
90int rsb_write(uint8_t rt_addr, uint8_t reg_addr, uint8_t value)
91{
92 mmio_write_32(SUNXI_R_RSB_BASE + RSB_CMD, RSBCMD_WR8); /* byte write */
93 mmio_write_32(SUNXI_R_RSB_BASE + RSB_SADDR, rt_addr << 16);
94 mmio_write_32(SUNXI_R_RSB_BASE + RSB_DADDR0, reg_addr);
95 mmio_write_32(SUNXI_R_RSB_BASE + RSB_DATA0, value);
96 mmio_write_32(SUNXI_R_RSB_BASE + RSB_CTRL, 0x80);/* start transaction */
97
98 return rsb_wait_stat("RSB: write command");
99}
100
101int rsb_set_device_mode(uint32_t device_mode)
102{
103 mmio_write_32(SUNXI_R_RSB_BASE + RSB_PMCR,
104 (device_mode & 0x00ffffff) | BIT(31));
105
106 return rsb_wait_bit("RSB: set device to RSB", RSB_PMCR, BIT(31));
107}
108
109int rsb_set_bus_speed(uint32_t source_freq, uint32_t bus_freq)
110{
111 uint32_t reg;
112
113 if (bus_freq == 0)
114 return -EINVAL;
115
116 reg = source_freq / bus_freq;
117 if (reg < 2)
118 return -EINVAL;
119
120 reg = reg / 2 - 1;
121 reg |= (1U << 8); /* one cycle of CD output delay */
122
123 mmio_write_32(SUNXI_R_RSB_BASE + RSB_CCR, reg);
124
125 return 0;
126}
127
128/* Initialize the RSB PMIC connection. */
129int rsb_assign_runtime_address(uint16_t hw_addr, uint8_t rt_addr)
130{
131 mmio_write_32(SUNXI_R_RSB_BASE + RSB_SADDR, hw_addr | (rt_addr << 16));
132 mmio_write_32(SUNXI_R_RSB_BASE + RSB_CMD, RSBCMD_SRTA);
133 mmio_write_32(SUNXI_R_RSB_BASE + RSB_CTRL, 0x80);
134
135 return rsb_wait_stat("RSB: set run-time address");
136}