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