Home | History | Annotate | Download | only in mach-sunxi
      1 // SPDX-License-Identifier: GPL-2.0+
      2 /*
      3  * (C) Copyright 2014 Hans de Goede <hdegoede (at) redhat.com>
      4  *
      5  * Based on allwinner u-boot sources rsb code which is:
      6  * (C) Copyright 2007-2013
      7  * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
      8  * lixiang <lixiang (at) allwinnertech.com>
      9  */
     10 
     11 #include <common.h>
     12 #include <errno.h>
     13 #include <asm/arch/cpu.h>
     14 #include <asm/arch/gpio.h>
     15 #include <asm/arch/prcm.h>
     16 #include <asm/arch/rsb.h>
     17 
     18 static int rsb_set_device_mode(void);
     19 
     20 static void rsb_cfg_io(void)
     21 {
     22 #ifdef CONFIG_MACH_SUN8I
     23 	sunxi_gpio_set_cfgpin(SUNXI_GPL(0), SUN8I_GPL_R_RSB);
     24 	sunxi_gpio_set_cfgpin(SUNXI_GPL(1), SUN8I_GPL_R_RSB);
     25 	sunxi_gpio_set_pull(SUNXI_GPL(0), 1);
     26 	sunxi_gpio_set_pull(SUNXI_GPL(1), 1);
     27 	sunxi_gpio_set_drv(SUNXI_GPL(0), 2);
     28 	sunxi_gpio_set_drv(SUNXI_GPL(1), 2);
     29 #elif defined CONFIG_MACH_SUN9I
     30 	sunxi_gpio_set_cfgpin(SUNXI_GPN(0), SUN9I_GPN_R_RSB);
     31 	sunxi_gpio_set_cfgpin(SUNXI_GPN(1), SUN9I_GPN_R_RSB);
     32 	sunxi_gpio_set_pull(SUNXI_GPN(0), 1);
     33 	sunxi_gpio_set_pull(SUNXI_GPN(1), 1);
     34 	sunxi_gpio_set_drv(SUNXI_GPN(0), 2);
     35 	sunxi_gpio_set_drv(SUNXI_GPN(1), 2);
     36 #else
     37 #error unsupported MACH_SUNXI
     38 #endif
     39 }
     40 
     41 static void rsb_set_clk(void)
     42 {
     43 	struct sunxi_rsb_reg * const rsb =
     44 		(struct sunxi_rsb_reg *)SUNXI_RSB_BASE;
     45 	u32 div = 0;
     46 	u32 cd_odly = 0;
     47 
     48 	/* Source is Hosc24M, set RSB clk to 3Mhz */
     49 	div = 24000000 / 3000000 / 2 - 1;
     50 	cd_odly = div >> 1;
     51 	if (!cd_odly)
     52 		cd_odly = 1;
     53 
     54 	writel((cd_odly << 8) | div, &rsb->ccr);
     55 }
     56 
     57 int rsb_init(void)
     58 {
     59 	struct sunxi_rsb_reg * const rsb =
     60 		(struct sunxi_rsb_reg *)SUNXI_RSB_BASE;
     61 
     62 	/* Enable RSB and PIO clk, and de-assert their resets */
     63 	prcm_apb0_enable(PRCM_APB0_GATE_PIO | PRCM_APB0_GATE_RSB);
     64 
     65 	/* Setup external pins */
     66 	rsb_cfg_io();
     67 
     68 	writel(RSB_CTRL_SOFT_RST, &rsb->ctrl);
     69 	rsb_set_clk();
     70 
     71 	return rsb_set_device_mode();
     72 }
     73 
     74 static int rsb_await_trans(void)
     75 {
     76 	struct sunxi_rsb_reg * const rsb =
     77 		(struct sunxi_rsb_reg *)SUNXI_RSB_BASE;
     78 	unsigned long tmo = timer_get_us() + 1000000;
     79 	u32 stat;
     80 	int ret;
     81 
     82 	while (1) {
     83 		stat = readl(&rsb->stat);
     84 		if (stat & RSB_STAT_LBSY_INT) {
     85 			ret = -EBUSY;
     86 			break;
     87 		}
     88 		if (stat & RSB_STAT_TERR_INT) {
     89 			ret = -EIO;
     90 			break;
     91 		}
     92 		if (stat & RSB_STAT_TOVER_INT) {
     93 			ret = 0;
     94 			break;
     95 		}
     96 		if (timer_get_us() > tmo) {
     97 			ret = -ETIME;
     98 			break;
     99 		}
    100 	}
    101 	writel(stat, &rsb->stat); /* Clear status bits */
    102 
    103 	return ret;
    104 }
    105 
    106 static int rsb_set_device_mode(void)
    107 {
    108 	struct sunxi_rsb_reg * const rsb =
    109 		(struct sunxi_rsb_reg *)SUNXI_RSB_BASE;
    110 	unsigned long tmo = timer_get_us() + 1000000;
    111 
    112 	writel(RSB_DMCR_DEVICE_MODE_START | RSB_DMCR_DEVICE_MODE_DATA,
    113 	       &rsb->dmcr);
    114 
    115 	while (readl(&rsb->dmcr) & RSB_DMCR_DEVICE_MODE_START) {
    116 		if (timer_get_us() > tmo)
    117 			return -ETIME;
    118 	}
    119 
    120 	return rsb_await_trans();
    121 }
    122 
    123 static int rsb_do_trans(void)
    124 {
    125 	struct sunxi_rsb_reg * const rsb =
    126 		(struct sunxi_rsb_reg *)SUNXI_RSB_BASE;
    127 
    128 	setbits_le32(&rsb->ctrl, RSB_CTRL_START_TRANS);
    129 	return rsb_await_trans();
    130 }
    131 
    132 int rsb_set_device_address(u16 device_addr, u16 runtime_addr)
    133 {
    134 	struct sunxi_rsb_reg * const rsb =
    135 		(struct sunxi_rsb_reg *)SUNXI_RSB_BASE;
    136 
    137 	writel(RSB_DEVADDR_RUNTIME_ADDR(runtime_addr) |
    138 	       RSB_DEVADDR_DEVICE_ADDR(device_addr), &rsb->devaddr);
    139 	writel(RSB_CMD_SET_RTSADDR, &rsb->cmd);
    140 
    141 	return rsb_do_trans();
    142 }
    143 
    144 int rsb_write(const u16 runtime_device_addr, const u8 reg_addr, u8 data)
    145 {
    146 	struct sunxi_rsb_reg * const rsb =
    147 		(struct sunxi_rsb_reg *)SUNXI_RSB_BASE;
    148 
    149 	writel(RSB_DEVADDR_RUNTIME_ADDR(runtime_device_addr), &rsb->devaddr);
    150 	writel(reg_addr, &rsb->addr);
    151 	writel(data, &rsb->data);
    152 	writel(RSB_CMD_BYTE_WRITE, &rsb->cmd);
    153 
    154 	return rsb_do_trans();
    155 }
    156 
    157 int rsb_read(const u16 runtime_device_addr, const u8 reg_addr, u8 *data)
    158 {
    159 	struct sunxi_rsb_reg * const rsb =
    160 		(struct sunxi_rsb_reg *)SUNXI_RSB_BASE;
    161 	int ret;
    162 
    163 	writel(RSB_DEVADDR_RUNTIME_ADDR(runtime_device_addr), &rsb->devaddr);
    164 	writel(reg_addr, &rsb->addr);
    165 	writel(RSB_CMD_BYTE_READ, &rsb->cmd);
    166 
    167 	ret = rsb_do_trans();
    168 	if (ret)
    169 		return ret;
    170 
    171 	*data = readl(&rsb->data) & 0xff;
    172 
    173 	return 0;
    174 }
    175