diff options
Diffstat (limited to 'src/soc/rockchip/rk3288')
-rw-r--r-- | src/soc/rockchip/rk3288/Makefile.inc | 8 | ||||
-rw-r--r-- | src/soc/rockchip/rk3288/clock.c | 23 | ||||
-rw-r--r-- | src/soc/rockchip/rk3288/i2c.c | 311 | ||||
-rw-r--r-- | src/soc/rockchip/rk3288/include/soc/addressmap.h | 2 | ||||
-rw-r--r-- | src/soc/rockchip/rk3288/include/soc/clock.h | 2 |
5 files changed, 31 insertions, 315 deletions
diff --git a/src/soc/rockchip/rk3288/Makefile.inc b/src/soc/rockchip/rk3288/Makefile.inc index a76328742d..a57ead3da7 100644 --- a/src/soc/rockchip/rk3288/Makefile.inc +++ b/src/soc/rockchip/rk3288/Makefile.inc @@ -26,7 +26,7 @@ bootblock-y += timer.c bootblock-y += clock.c bootblock-y += ../common/spi.c bootblock-y += gpio.c -bootblock-y += i2c.c +bootblock-y += ../common/i2c.c bootblock-$(CONFIG_SOFTWARE_I2C) += software_i2c.c bootblock-y += ../common/rk808.c @@ -36,13 +36,13 @@ verstage-$(CONFIG_DRIVERS_UART) += ../common/uart.c verstage-y += gpio.c verstage-y += clock.c libverstage-y += crypto.c -verstage-y += i2c.c +verstage-y += ../common/i2c.c verstage-$(CONFIG_SOFTWARE_I2C) += software_i2c.c romstage-y += ../common/cbmem.c romstage-y += timer.c romstage-$(CONFIG_DRIVERS_UART) += ../common/uart.c -romstage-y += i2c.c +romstage-y += ../common/i2c.c romstage-$(CONFIG_SOFTWARE_I2C) += software_i2c.c romstage-y += clock.c romstage-y += gpio.c @@ -55,7 +55,7 @@ romstage-y += tsadc.c ramstage-y += soc.c ramstage-y += ../common/cbmem.c ramstage-y += timer.c -ramstage-y += i2c.c +ramstage-y += ../common/i2c.c ramstage-$(CONFIG_SOFTWARE_I2C) += software_i2c.c ramstage-y += clock.c ramstage-y += ../common/spi.c diff --git a/src/soc/rockchip/rk3288/clock.c b/src/soc/rockchip/rk3288/clock.c index 01f1e9ff23..bb5b846c04 100644 --- a/src/soc/rockchip/rk3288/clock.c +++ b/src/soc/rockchip/rk3288/clock.c @@ -21,6 +21,7 @@ #include <soc/addressmap.h> #include <soc/clock.h> #include <soc/grf.h> +#include <soc/i2c.h> #include <soc/soc.h> #include <stdint.h> #include <stdlib.h> @@ -667,3 +668,25 @@ int rkclk_was_watchdog_reset(void) /* Bits 5 and 4 are "second" and "first" global watchdog reset. */ return read32(&cru_ptr->cru_glb_rst_st) & 0x30; } + +unsigned rkclk_i2c_clock_for_bus(unsigned bus) +{ + /*i2c0,i2c2 src clk from pd_bus_pclk + other i2c src clk from peri_pclk + */ + switch (bus) { + case 0: + case 2: + return PD_BUS_PCLK_HZ; + + case 1: + case 3: + case 4: + case 5: + return PERI_PCLK_HZ; + + default: + return -1; /* Should never happen. */ + } + +} diff --git a/src/soc/rockchip/rk3288/i2c.c b/src/soc/rockchip/rk3288/i2c.c deleted file mode 100644 index 98e4458def..0000000000 --- a/src/soc/rockchip/rk3288/i2c.c +++ /dev/null @@ -1,311 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright 2014 Rockchip Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <arch/io.h> -#include <assert.h> -#include <cbfs.h> -#include <console/console.h> -#include <delay.h> -#include <device/i2c.h> -#include <soc/addressmap.h> -#include <soc/grf.h> -#include <soc/soc.h> -#include <soc/i2c.h> -#include <soc/clock.h> -#include <stdlib.h> -#include <string.h> - -#define RETRY_COUNT 3 -/* 100000us = 100ms */ -#define I2C_TIMEOUT_US 100000 -#define I2C_BUS_MAX 6 -#define I2C_NOACK 2 -#define I2C_TIMEOUT 3 - -#define i2c_info(x...) do {if (0) printk(BIOS_DEBUG, x); } while (0) - -struct rk3288_i2c_regs { - u32 i2c_con; - u32 i2c_clkdiv; - u32 i2c_mrxaddr; - u32 i2c_mrxraddr; - u32 i2c_mtxcnt; - u32 i2c_mrxcnt; - u32 i2c_ien; - u32 i2c_ipd; - u32 i2c_fcnt; - u32 reserved0[(0x100 - 0x24) / 4]; - u32 txdata[8]; - u32 reserved1[(0x200 - 0x120) / 4]; - u32 rxdata[8]; -}; - -struct rk3288_i2c_regs *i2c_bus[] = { - (struct rk3288_i2c_regs *)0xff650000, - (struct rk3288_i2c_regs *)0xff140000, - (struct rk3288_i2c_regs *)0xff660000, - (struct rk3288_i2c_regs *)0xff150000, - (struct rk3288_i2c_regs *)0xff160000, - (struct rk3288_i2c_regs *)0xff170000, -}; - -/* Con register bits. */ -#define I2C_ACT2NAK (1<<6) -#define I2C_NAK (1<<5) -#define I2C_STOP (1<<4) -#define I2C_START (1<<3) -#define I2C_MODE_TX (0<<1) -#define I2C_MODE_TRX (1<<1) -#define I2C_MODE_RX (2<<1) -#define I2C_EN (1<<0) - -#define I2C_8BIT (1<<24) -#define I2C_16BIT (3<<24) -#define I2C_24BIT (7<<24) - -/* Mtxcnt register bits. */ -#define I2C_CNT(cnt) ((cnt) & 0x3F) - -#define I2C_NAKRCVI (1<<6) -#define I2C_STOPI (1<<5) -#define I2C_STARTI (1<<4) -#define I2C_MBRFI (1<<3) -#define I2C_MBTFI (1<<2) -#define I2C_BRFI (1<<1) -#define I2C_BTFI (1<<0) -#define I2C_CLEANI 0x7F - -static int i2c_send_start(struct rk3288_i2c_regs *reg_addr) -{ - int res = 0; - int timeout = I2C_TIMEOUT_US; - - i2c_info("I2c Start::Send Start bit\n"); - write32(®_addr->i2c_ipd, I2C_CLEANI); - write32(®_addr->i2c_con, I2C_EN | I2C_START); - while (timeout--) { - if (read32(®_addr->i2c_ipd) & I2C_STARTI) - break; - udelay(1); - } - - if (timeout <= 0) { - printk(BIOS_ERR, "I2C Start::Send Start Bit Timeout\n"); - res = I2C_TIMEOUT; - } - - return res; -} - -static int i2c_send_stop(struct rk3288_i2c_regs *reg_addr) -{ - int res = 0; - int timeout = I2C_TIMEOUT_US; - - i2c_info("I2c Stop::Send Stop bit\n"); - write32(®_addr->i2c_ipd, I2C_CLEANI); - write32(®_addr->i2c_con, I2C_EN | I2C_STOP); - while (timeout--) { - if (read32(®_addr->i2c_ipd) & I2C_STOPI) - break; - udelay(1); - } - write32(®_addr->i2c_con, 0); - if (timeout <= 0) { - printk(BIOS_ERR, "I2C Stop::Send Stop Bit Timeout\n"); - res = I2C_TIMEOUT; - } - - return res; -} - -static int i2c_read(struct rk3288_i2c_regs *reg_addr, struct i2c_seg segment) -{ - int res = 0; - uint8_t *data = segment.buf; - int timeout = I2C_TIMEOUT_US; - unsigned int bytes_remaining = segment.len; - unsigned int bytes_transfered = 0; - unsigned int words_transfered = 0; - unsigned int rxdata = 0; - unsigned int con = 0; - unsigned int i, j; - - write32(®_addr->i2c_mrxaddr, I2C_8BIT | segment.chip << 1 | 1); - write32(®_addr->i2c_mrxraddr, 0); - con = I2C_MODE_TRX | I2C_EN | I2C_ACT2NAK; - while (bytes_remaining) { - bytes_transfered = MIN(bytes_remaining, 32); - bytes_remaining -= bytes_transfered; - if (!bytes_remaining) - con |= I2C_EN | I2C_NAK; - words_transfered = ALIGN_UP(bytes_transfered, 4) / 4; - - write32(®_addr->i2c_ipd, I2C_CLEANI); - write32(®_addr->i2c_con, con); - write32(®_addr->i2c_mrxcnt, bytes_transfered); - - timeout = I2C_TIMEOUT_US; - while (timeout--) { - if (read32(®_addr->i2c_ipd) & I2C_NAKRCVI) { - write32(®_addr->i2c_mrxcnt, 0); - write32(®_addr->i2c_con, 0); - return I2C_NOACK; - } - if (read32(®_addr->i2c_ipd) & I2C_MBRFI) - break; - udelay(1); - } - if (timeout <= 0) { - printk(BIOS_ERR, "I2C Read::Recv Data Timeout\n"); - write32(®_addr->i2c_mrxcnt, 0); - write32(®_addr->i2c_con, 0); - return I2C_TIMEOUT; - } - - for (i = 0; i < words_transfered; i++) { - rxdata = read32(®_addr->rxdata[i]); - i2c_info("I2c Read::RXDATA[%d] = 0x%x\n", i, rxdata); - for (j = 0; j < 4; j++) { - if ((i * 4 + j) == bytes_transfered) - break; - *data++ = (rxdata >> (j * 8)) & 0xff; - } - } - con = I2C_MODE_RX | I2C_EN | I2C_ACT2NAK; - } - return res; -} - -static int i2c_write(struct rk3288_i2c_regs *reg_addr, struct i2c_seg segment) -{ - int res = 0; - uint8_t *data = segment.buf; - int timeout = I2C_TIMEOUT_US; - int bytes_remaining = segment.len + 1; - int bytes_transfered = 0; - int words_transfered = 0; - unsigned int i; - unsigned int j = 1; - u32 txdata = 0; - - txdata |= (segment.chip << 1); - while (bytes_remaining) { - bytes_transfered = MIN(bytes_remaining, 32); - words_transfered = ALIGN_UP(bytes_transfered, 4) / 4; - for (i = 0; i < words_transfered; i++) { - do { - if ((i * 4 + j) == bytes_transfered) - break; - txdata |= (*data++) << (j * 8); - } while (++j < 4); - write32(®_addr->txdata[i], txdata); - j = 0; - i2c_info("I2c Write::TXDATA[%d] = 0x%x\n", i, txdata); - txdata = 0; - } - - write32(®_addr->i2c_ipd, I2C_CLEANI); - write32(®_addr->i2c_con, - I2C_EN | I2C_MODE_TX | I2C_ACT2NAK); - write32(®_addr->i2c_mtxcnt, bytes_transfered); - - timeout = I2C_TIMEOUT_US; - while (timeout--) { - if (read32(®_addr->i2c_ipd) & I2C_NAKRCVI) { - write32(®_addr->i2c_mtxcnt, 0); - write32(®_addr->i2c_con, 0); - return I2C_NOACK; - } - if (read32(®_addr->i2c_ipd) & I2C_MBTFI) - break; - udelay(1); - } - - if (timeout <= 0) { - printk(BIOS_ERR, "I2C Write::Send Data Timeout\n"); - write32(®_addr->i2c_mtxcnt, 0); - write32(®_addr->i2c_con, 0); - return I2C_TIMEOUT; - } - - bytes_remaining -= bytes_transfered; - } - return res; -} - -static int i2c_do_xfer(void *reg_addr, struct i2c_seg segment) -{ - int res = 0; - - if (i2c_send_start(reg_addr)) - return I2C_TIMEOUT; - if (segment.read) - res = i2c_read(reg_addr, segment); - else - res = i2c_write(reg_addr, segment); - return i2c_send_stop(reg_addr) || res; -} - -int platform_i2c_transfer(unsigned bus, struct i2c_seg *segments, int seg_count) -{ - int i; - int res = 0; - struct rk3288_i2c_regs *regs = i2c_bus[bus]; - struct i2c_seg *seg = segments; - - for (i = 0; i < seg_count; i++, seg++) { - res = i2c_do_xfer(regs, *seg); - if (res) - break; - } - return res; -} - -void i2c_init(unsigned int bus, unsigned int hz) -{ - unsigned int clk_div; - unsigned int divl; - unsigned int divh; - unsigned int i2c_src_clk = 0; - struct rk3288_i2c_regs *regs = i2c_bus[bus]; - - /*i2c0,i2c2 src clk from pd_bus_pclk - other i2c src clk from peri_pclk - */ - switch (bus) { - case 0: - case 2: - i2c_src_clk = PD_BUS_PCLK_HZ; - break; - case 1: - case 3: - case 4: - case 5: - i2c_src_clk = PERI_PCLK_HZ; - break; - default: - break; - } - - /*SCL Divisor = 8*(CLKDIVL + 1 + CLKDIVH + 1) - SCL = PCLK/ SCLK Divisor - */ - clk_div = div_round_up(i2c_src_clk, hz * 8); - divh = clk_div * 3 / 7 - 1; - divl = clk_div - divh - 2; - assert((divh < 65536) && (divl < 65536)); - write32(®s->i2c_clkdiv, (divh << 16) | (divl << 0)); -} diff --git a/src/soc/rockchip/rk3288/include/soc/addressmap.h b/src/soc/rockchip/rk3288/include/soc/addressmap.h index 8a87673d09..fb07cafaed 100644 --- a/src/soc/rockchip/rk3288/include/soc/addressmap.h +++ b/src/soc/rockchip/rk3288/include/soc/addressmap.h @@ -99,5 +99,7 @@ #define BOOT_ROM_BASE 0xFFFF0000 #define BOOT_ROM_CHIP_VER (BOOT_ROM+0x27F0) +#define IC_BASES { I2C0_BASE, I2C1_BASE, I2C2_BASE, \ + I2C3_BASE, I2C4_BASE, I2C5_BASE } #endif /* __SOC_ROCKCHIP_RK3288_ADDRESSMAP_H__ */ diff --git a/src/soc/rockchip/rk3288/include/soc/clock.h b/src/soc/rockchip/rk3288/include/soc/clock.h index fd36d87914..9592c985df 100644 --- a/src/soc/rockchip/rk3288/include/soc/clock.h +++ b/src/soc/rockchip/rk3288/include/soc/clock.h @@ -53,4 +53,6 @@ int rkclk_configure_vop_dclk(u32 vop_id, u32 dclk_hz); void rkclk_configure_edp(void); void rkclk_configure_hdmi(void); int rkclk_was_watchdog_reset(void); +unsigned rkclk_i2c_clock_for_bus(unsigned bus); + #endif /* __SOC_ROCKCHIP_RK3288_CLOCK_H__ */ |