/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of ARM nor the names of its contributors may be used * to endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include "sunxi_def.h" #include "sunxi_private.h" #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) #define BIT(n) (1U << (n)) #define AXP803_HW_ADDR 0x3a3 /* * RSB has 15 valid runtime addresses. * Allwinner typically skips the first one for unknown reasons. */ #define RUNTIME_ADDR0 0x17 #define RUNTIME_ADDR1 0x2d #define RUNTIME_ADDR2 0x3a #define RUNTIME_ADDR3 0x4e #define RUNTIME_ADDR4 0x59 #define RUNTIME_ADDR5 0x63 #define RUNTIME_ADDR6 0x74 #define RUNTIME_ADDR7 0x8b #define RUNTIME_ADDR8 0x9c #define RUNTIME_ADDR9 0xa6 #define RUNTIME_ADDR10 0xb1 #define RUNTIME_ADDR11 0xc5 #define RUNTIME_ADDR12 0xd2 #define RUNTIME_ADDR13 0xe8 #define RUNTIME_ADDR14 0xff #define R_PRCM_BASE 0x01f01400ULL #define R_PIO_BASE 0x01f02c00ULL #define R_RSB_BASE 0x01f03400ULL #define RSB_CTRL 0x00 #define RSB_CCR 0x04 #define RSB_INTE 0x08 #define RSB_INTS 0x0c #define RSB_AR 0x10 #define RSB_DATA 0x1c #define RSB_LCR 0x24 #define RSB_DMCR 0x28 #define RSB_CMD 0x2c #define RSB_DAR 0x30 #define RSB_CTRL_START_TRANS BIT(7) #define RSB_CTRL_ABORT_TRANS BIT(6) #define RSB_CTRL_SOFT_RESET BIT(0) #define RSB_INTS_TRAS_OVER BIT(0) #define RSB_CMD_STRA 0xE8 /* SeT Run-time Address */ #define RSB_CMD_RD8 0x8B /* ReaD 8 bit */ #define RSB_CMD_RD16 0x9C #define RSB_CMD_RD32 0xA6 #define RSB_CMD_WR8 0x4E #define RSB_CMD_WR16 0x59 #define RSB_CMD_WR32 0x63 #define RSB_DMCR_DEVICE_START BIT(31) #define RSB_DMCR_MODE_DATA (0x7c << 16) #define RSB_DMCR_MODE_REG (0x3e << 8) #define RSB_DMCR_DEV_ADDR 0x00 struct rsb_slave { uint16_t hw_addr; uint8_t rt_addr; }; static struct rsb_slave rsb_slaves[] = { { AXP803_HW_ADDR, RUNTIME_ADDR1 }, /* PMIC */ }; static struct spinlock lock; static inline void rsb_cmd(uint8_t cmd) { uint32_t reg; /* Start the command */ mmio_write_32(R_RSB_BASE + RSB_CTRL, cmd); /* * The control register clears the set command bit, * when the command has finished. */ do { reg = mmio_read_32(R_RSB_BASE + RSB_CTRL); } while (reg & cmd); } int rsb_read(uint8_t rt_addr, uint8_t addr, uint32_t *val, size_t size) { uint32_t reg, cmd, mask; spin_lock(&lock); switch (size) { case 1: cmd = RSB_CMD_RD8; mask = 0xff; break; case 2: cmd = RSB_CMD_RD16; mask = 0xffff; break; case 3: cmd = RSB_CMD_RD32; mask = 0xffffffff; break; default: spin_unlock(&lock); ERROR("Invalid RSB read size %u", size); return -1; } mmio_write_32(R_RSB_BASE + RSB_CMD, cmd); mmio_write_32(R_RSB_BASE + RSB_DAR, (rt_addr << 16)); mmio_write_32(R_RSB_BASE + RSB_AR, addr); /* Start transaction and wait for completion */ rsb_cmd(RSB_CTRL_START_TRANS); /* Read status */ reg = mmio_read_32(R_RSB_BASE + RSB_INTS); if (reg != RSB_INTS_TRAS_OVER) { spin_unlock(&lock); return -reg; } /* Get data */ reg = mmio_read_32(R_RSB_BASE + RSB_DATA); if (val) *val = reg & mask; spin_unlock(&lock); return 0; } int rsb_write(uint8_t rt_addr, uint8_t addr, uint32_t val, size_t size) { uint32_t reg, cmd; spin_lock(&lock); switch (size) { case 1: cmd = RSB_CMD_WR8; break; case 2: cmd = RSB_CMD_WR16; break; case 3: cmd = RSB_CMD_WR32; break; default: spin_unlock(&lock); ERROR("Invalid RSB read size %u", size); return -1; } mmio_write_32(R_RSB_BASE + RSB_CMD, cmd); mmio_write_32(R_RSB_BASE + RSB_DAR, (rt_addr << 16)); mmio_write_32(R_RSB_BASE + RSB_AR, addr); mmio_write_32(R_RSB_BASE + RSB_DATA, val); /* Start transaction and wait for completion */ rsb_cmd(RSB_CTRL_START_TRANS); /* Read status */ reg = mmio_read_32(R_RSB_BASE + RSB_INTS); if (reg != RSB_INTS_TRAS_OVER) { spin_unlock(&lock); return -1; } spin_unlock(&lock); return 0; } /* Initialize the RSB PMIC connection. */ static int sunxi_rsb_setup_slaves(void) { size_t i; int ret; uint32_t reg; /* Initialize all devices on the bus into RSB mode */ reg = RSB_DMCR_DEVICE_START | RSB_DMCR_MODE_DATA | RSB_DMCR_MODE_REG | RSB_DMCR_DEV_ADDR; mmio_write_32(R_RSB_BASE + RSB_DMCR, reg); do { ret = mmio_read_32(R_RSB_BASE + RSB_DMCR); } while (ret & RSB_DMCR_DEVICE_START); /* Set clock speed to 3 Mhz */ mmio_write_32(R_RSB_BASE + RSB_CCR, 0x103); for (i = 0; i < ARRAY_SIZE(rsb_slaves); i++) { uint16_t hw_addr = rsb_slaves[i].hw_addr; uint8_t rt_addr = rsb_slaves[i].rt_addr; /* Set run-time address for given hardware address */ mmio_write_32(R_RSB_BASE + RSB_DAR, hw_addr | (rt_addr << 16)); /* Command: set the run-time address to the device */ mmio_write_32(R_RSB_BASE + RSB_CMD, RSB_CMD_STRA); /* Start transaction and wait for completion */ rsb_cmd(RSB_CTRL_START_TRANS); /* Read status */ reg = mmio_read_32(R_RSB_BASE + RSB_INTS); if (reg != RSB_INTS_TRAS_OVER) ERROR("Could not set run-time address: 0x%x\n", reg); } return 0; } /* Initialize the RSB controller and its pins. */ int sunxi_rsb_init(void) { uint32_t reg; /* un-gate PIO clock */ reg = mmio_read_32(R_PRCM_BASE + 0x28); mmio_write_32(R_PRCM_BASE + 0x28, reg | 0x01); /* get currently configured function for pins PL0 and PL1 */ reg = mmio_read_32(R_PIO_BASE + 0x00); if ((reg & 0xff) == 0x33) { NOTICE("RSB: already configured for TWI\n"); return -1; } if ((reg & 0xff) == 0x22) { NOTICE("RSB: already configured for RSB\n"); return 0; /* configured for RSB mode already */ } /* switch pins PL0 and PL1 to RSB */ mmio_write_32(R_PIO_BASE + 0, (reg & ~0xff) | 0x22); /* level 2 drive strength */ reg = mmio_read_32(R_PIO_BASE + 0x14); mmio_write_32(R_PIO_BASE + 0x14, (reg & ~0x0f) | 0xa); /* set both ports to pull-up */ reg = mmio_read_32(R_PIO_BASE + 0x1c); mmio_write_32(R_PIO_BASE + 0x1c, (reg & ~0x0f) | 0x5); /* assert & de-assert reset of RSB */ reg = mmio_read_32(R_PRCM_BASE + 0xb0); mmio_write_32(R_PRCM_BASE + 0xb0, reg & ~0x08); reg = mmio_read_32(R_PRCM_BASE + 0xb0); mmio_write_32(R_PRCM_BASE + 0xb0, reg | 0x08); /* un-gate RSB clock */ reg = mmio_read_32(R_PRCM_BASE + 0x28); mmio_write_32(R_PRCM_BASE + 0x28, reg | 0x08); /* Soft reset of RSB block */ rsb_cmd(RSB_CTRL_SOFT_RESET); /* Set clock to 400 kHz */ mmio_write_32(R_RSB_BASE + RSB_CCR, 0x11d); sunxi_rsb_setup_slaves(); return 0; }