Commit 103f19f0 authored by Andre Przywara's avatar Andre Przywara
Browse files

allwinner: Add RSB driver



The "Reduced Serial Bus" is an Allwinner specific bus, bearing many
similarities with I2C. It sports a much higher bus frequency, though,
(typically 3 MHz) and requires much less handholding for the typical
task of manipulating slave registers (fire-and-forget).
On most A64 boards this bus is used to connect the PMIC to the SoC.

This driver provides basic primitives to read and write slave registers,
it will be later used by the PMIC code.
Signed-off-by: default avatarAndre Przywara <andre.przywara@arm.com>
parent 3d22228f
/*
* Copyright (c) 2017-2018 ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <debug.h>
#include <delay_timer.h>
#include <errno.h>
#include <mmio.h>
#include <sunxi_mmap.h>
#define RSB_CTRL 0x00
#define RSB_CCR 0x04
#define RSB_INTE 0x08
#define RSB_STAT 0x0c
#define RSB_DADDR0 0x10
#define RSB_DLEN 0x18
#define RSB_DATA0 0x1c
#define RSB_LCR 0x24
#define RSB_PMCR 0x28
#define RSB_CMD 0x2c
#define RSB_SADDR 0x30
#define RSBCMD_SRTA 0xE8
#define RSBCMD_RD8 0x8B
#define RSBCMD_RD16 0x9C
#define RSBCMD_RD32 0xA6
#define RSBCMD_WR8 0x4E
#define RSBCMD_WR16 0x59
#define RSBCMD_WR32 0x63
#define MAX_TRIES 100000
static int rsb_wait_bit(const char *desc, unsigned int offset, uint32_t mask)
{
uint32_t reg, tries = MAX_TRIES;
do
reg = mmio_read_32(SUNXI_R_RSB_BASE + offset);
while ((reg & mask) && --tries); /* transaction in progress */
if (reg & mask) {
ERROR("%s: timed out\n", desc);
return -ETIMEDOUT;
}
return 0;
}
static int rsb_wait_stat(const char *desc)
{
uint32_t reg;
int ret = rsb_wait_bit(desc, RSB_CTRL, BIT(7));
if (ret)
return ret;
reg = mmio_read_32(SUNXI_R_RSB_BASE + RSB_STAT);
if (reg == 0x01)
return 0;
ERROR("%s: 0x%x\n", desc, reg);
return -reg;
}
/* Initialize the RSB controller. */
int rsb_init_controller(void)
{
mmio_write_32(SUNXI_R_RSB_BASE + RSB_CTRL, 0x01); /* soft reset */
return rsb_wait_bit("RSB: reset controller", RSB_CTRL, BIT(0));
}
int rsb_read(uint8_t rt_addr, uint8_t reg_addr)
{
int ret;
mmio_write_32(SUNXI_R_RSB_BASE + RSB_CMD, RSBCMD_RD8); /* read a byte */
mmio_write_32(SUNXI_R_RSB_BASE + RSB_SADDR, rt_addr << 16);
mmio_write_32(SUNXI_R_RSB_BASE + RSB_DADDR0, reg_addr);
mmio_write_32(SUNXI_R_RSB_BASE + RSB_CTRL, 0x80);/* start transaction */
ret = rsb_wait_stat("RSB: read command");
if (ret)
return ret;
return mmio_read_32(SUNXI_R_RSB_BASE + RSB_DATA0) & 0xff; /* result */
}
int rsb_write(uint8_t rt_addr, uint8_t reg_addr, uint8_t value)
{
mmio_write_32(SUNXI_R_RSB_BASE + RSB_CMD, RSBCMD_WR8); /* byte write */
mmio_write_32(SUNXI_R_RSB_BASE + RSB_SADDR, rt_addr << 16);
mmio_write_32(SUNXI_R_RSB_BASE + RSB_DADDR0, reg_addr);
mmio_write_32(SUNXI_R_RSB_BASE + RSB_DATA0, value);
mmio_write_32(SUNXI_R_RSB_BASE + RSB_CTRL, 0x80);/* start transaction */
return rsb_wait_stat("RSB: write command");
}
int rsb_set_device_mode(uint32_t device_mode)
{
mmio_write_32(SUNXI_R_RSB_BASE + RSB_PMCR,
(device_mode & 0x00ffffff) | BIT(31));
return rsb_wait_bit("RSB: set device to RSB", RSB_PMCR, BIT(31));
}
int rsb_set_bus_speed(uint32_t source_freq, uint32_t bus_freq)
{
uint32_t reg;
if (bus_freq == 0)
return -EINVAL;
reg = source_freq / bus_freq;
if (reg < 2)
return -EINVAL;
reg = reg / 2 - 1;
reg |= (1U << 8); /* one cycle of CD output delay */
mmio_write_32(SUNXI_R_RSB_BASE + RSB_CCR, reg);
return 0;
}
/* Initialize the RSB PMIC connection. */
int rsb_assign_runtime_address(uint16_t hw_addr, uint8_t rt_addr)
{
mmio_write_32(SUNXI_R_RSB_BASE + RSB_SADDR, hw_addr | (rt_addr << 16));
mmio_write_32(SUNXI_R_RSB_BASE + RSB_CMD, RSBCMD_SRTA);
mmio_write_32(SUNXI_R_RSB_BASE + RSB_CTRL, 0x80);
return rsb_wait_stat("RSB: set run-time address");
}
/*
* Copyright (c) 2017-2018 ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef SUNXI_RSB_H
#define SUNXI_RSB_H
#include <stdint.h>
int rsb_init_controller(void);
int rsb_set_bus_speed(uint32_t source_freq, uint32_t bus_freq);
int rsb_set_device_mode(uint32_t device_mode);
int rsb_assign_runtime_address(uint16_t hw_addr, uint8_t rt_addr);
int rsb_read(uint8_t rt_addr, uint8_t reg_addr);
int rsb_write(uint8_t rt_addr, uint8_t reg_addr, uint8_t value);
#endif
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment