From da963e316446eeff0e2932946b98ea50b99f5b78 Mon Sep 17 00:00:00 2001 From: Jorge Ramirez-Ortiz Date: Sun, 23 Sep 2018 09:40:26 +0200 Subject: [PATCH] rcar_gen3: drivers: i2c dvfs Signed-off-by: ldts --- drivers/renesas/rcar/iic_dvfs/iic_dvfs.c | 568 +++++++++++++++++++++++ drivers/renesas/rcar/iic_dvfs/iic_dvfs.h | 23 + 2 files changed, 591 insertions(+) create mode 100644 drivers/renesas/rcar/iic_dvfs/iic_dvfs.c create mode 100644 drivers/renesas/rcar/iic_dvfs/iic_dvfs.h diff --git a/drivers/renesas/rcar/iic_dvfs/iic_dvfs.c b/drivers/renesas/rcar/iic_dvfs/iic_dvfs.c new file mode 100644 index 000000000..11d52bf76 --- /dev/null +++ b/drivers/renesas/rcar/iic_dvfs/iic_dvfs.c @@ -0,0 +1,568 @@ +/* + * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include "rcar_def.h" +#include "cpg_registers.h" +#include "iic_dvfs.h" +#include "rcar_private.h" + +#define DVFS_RETRY_MAX (2U) + +#define IIC_DVFS_SET_ICCL_EXTAL_TYPE_0 (0x07) +#define IIC_DVFS_SET_ICCL_EXTAL_TYPE_1 (0x09) +#define IIC_DVFS_SET_ICCL_EXTAL_TYPE_2 (0x0B) +#define IIC_DVFS_SET_ICCL_EXTAL_TYPE_3 (0x0E) +#define IIC_DVFS_SET_ICCL_EXTAL_TYPE_E (0x15) + +#define IIC_DVFS_SET_ICCH_EXTAL_TYPE_0 (0x01) +#define IIC_DVFS_SET_ICCH_EXTAL_TYPE_1 (0x02) +#define IIC_DVFS_SET_ICCH_EXTAL_TYPE_2 (0x03) +#define IIC_DVFS_SET_ICCH_EXTAL_TYPE_3 (0x05) +#define IIC_DVFS_SET_ICCH_EXTAL_TYPE_E (0x07) + +#define CPG_BIT_SMSTPCR9_DVFS (0x04000000) + +#define IIC_DVFS_REG_BASE (0xE60B0000) +#define IIC_DVFS_REG_ICDR (IIC_DVFS_REG_BASE + 0x0000) +#define IIC_DVFS_REG_ICCR (IIC_DVFS_REG_BASE + 0x0004) +#define IIC_DVFS_REG_ICSR (IIC_DVFS_REG_BASE + 0x0008) +#define IIC_DVFS_REG_ICIC (IIC_DVFS_REG_BASE + 0x000C) +#define IIC_DVFS_REG_ICCL (IIC_DVFS_REG_BASE + 0x0010) +#define IIC_DVFS_REG_ICCH (IIC_DVFS_REG_BASE + 0x0014) + +#define IIC_DVFS_BIT_ICSR_BUSY (0x10) +#define IIC_DVFS_BIT_ICSR_AL (0x08) +#define IIC_DVFS_BIT_ICSR_TACK (0x04) +#define IIC_DVFS_BIT_ICSR_WAIT (0x02) +#define IIC_DVFS_BIT_ICSR_DTE (0x01) + +#define IIC_DVFS_BIT_ICCR_ENABLE (0x80) +#define IIC_DVFS_SET_ICCR_START (0x94) +#define IIC_DVFS_SET_ICCR_STOP (0x90) +#define IIC_DVFS_SET_ICCR_RETRANSMISSION (0x94) +#define IIC_DVFS_SET_ICCR_CHANGE (0x81) +#define IIC_DVFS_SET_ICCR_STOP_READ (0xC0) + +#define IIC_DVFS_BIT_ICIC_TACKE (0x04) +#define IIC_DVFS_BIT_ICIC_WAITE (0x02) +#define IIC_DVFS_BIT_ICIC_DTEE (0x01) + +#define DVFS_READ_MODE (0x01) +#define DVFS_WRITE_MODE (0x00) + +#define IIC_DVFS_SET_DUMMY (0x52) +#define IIC_DVFS_SET_BUSY_LOOP (500000000U) + +typedef enum { + DVFS_START = 0, + DVFS_STOP, + DVFS_RETRANSMIT, + DVFS_READ, + DVFS_STOP_READ, + DVFS_SET_SLAVE_READ, + DVFS_SET_SLAVE, + DVFS_WRITE_ADDR, + DVFS_WRITE_DATA, + DVFS_CHANGE_SEND_TO_RECIEVE, + DVFS_DONE, +} DVFS_STATE_T; + +#define DVFS_PROCESS (1) +#define DVFS_COMPLETE (0) +#define DVFS_ERROR (-1) + +#if IMAGE_BL31 +#define IIC_DVFS_FUNC(__name, ...) \ +static int32_t __attribute__ ((section (".system_ram"))) \ +dvfs_ ##__name(__VA_ARGS__) + +#define RCAR_DVFS_API(__name, ...) \ +int32_t __attribute__ ((section (".system_ram"))) \ +rcar_iic_dvfs_ ##__name(__VA_ARGS__) + +#else +#define IIC_DVFS_FUNC(__name, ...) \ +static int32_t dvfs_ ##__name(__VA_ARGS__) + +#define RCAR_DVFS_API(__name, ...) \ +int32_t rcar_iic_dvfs_ ##__name(__VA_ARGS__) +#endif + +IIC_DVFS_FUNC(check_error, DVFS_STATE_T *state, uint32_t *err, uint8_t mode) +{ + uint8_t icsr_al = 0, icsr_tack = 0; + uint8_t reg, stop; + uint32_t i = 0; + + stop = mode == DVFS_READ_MODE ? IIC_DVFS_SET_ICCR_STOP_READ : + IIC_DVFS_SET_ICCR_STOP; + + reg = mmio_read_8(IIC_DVFS_REG_ICSR); + icsr_al = (reg & IIC_DVFS_BIT_ICSR_AL) == IIC_DVFS_BIT_ICSR_AL; + icsr_tack = (reg & IIC_DVFS_BIT_ICSR_TACK) == IIC_DVFS_BIT_ICSR_TACK; + + if (icsr_al == 0 && icsr_tack == 0) + return DVFS_PROCESS; + + if (icsr_al) { + reg = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_AL; + mmio_write_8(IIC_DVFS_REG_ICSR, reg); + + if (*state == DVFS_SET_SLAVE) + mmio_write_8(IIC_DVFS_REG_ICDR, IIC_DVFS_SET_DUMMY); + + do { + reg = mmio_read_8(IIC_DVFS_REG_ICSR) & + IIC_DVFS_BIT_ICSR_WAIT; + } while (reg == 0); + + mmio_write_8(IIC_DVFS_REG_ICCR, stop); + + reg = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_WAIT; + mmio_write_8(IIC_DVFS_REG_ICSR, reg); + + i = 0; + do { + reg = mmio_read_8(IIC_DVFS_REG_ICSR) & + IIC_DVFS_BIT_ICSR_BUSY; + if (reg == 0) + break; + + if (i++ > IIC_DVFS_SET_BUSY_LOOP) + panic(); + + } while (1); + + mmio_write_8(IIC_DVFS_REG_ICCR, 0x00U); + + (*err)++; + if (*err > DVFS_RETRY_MAX) + return DVFS_ERROR; + + *state = DVFS_START; + + return DVFS_PROCESS; + + } + + /* icsr_tack */ + mmio_write_8(IIC_DVFS_REG_ICCR, stop); + + reg = mmio_read_8(IIC_DVFS_REG_ICIC); + reg &= ~(IIC_DVFS_BIT_ICIC_WAITE | IIC_DVFS_BIT_ICIC_DTEE); + mmio_write_8(IIC_DVFS_REG_ICIC, reg); + + reg = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_TACK; + mmio_write_8(IIC_DVFS_REG_ICSR, reg); + + i = 0; + while ((mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_BUSY) != 0) { + if (i++ > IIC_DVFS_SET_BUSY_LOOP) + panic(); + } + + mmio_write_8(IIC_DVFS_REG_ICCR, 0); + (*err)++; + + if (*err > DVFS_RETRY_MAX) + return DVFS_ERROR; + + *state = DVFS_START; + + return DVFS_PROCESS; +} + +IIC_DVFS_FUNC(start, DVFS_STATE_T * state) +{ + uint8_t iccl = IIC_DVFS_SET_ICCL_EXTAL_TYPE_E; + uint8_t icch = IIC_DVFS_SET_ICCH_EXTAL_TYPE_E; + int32_t result = DVFS_PROCESS; + uint32_t reg, lsi_product; + uint8_t mode; + + mode = mmio_read_8(IIC_DVFS_REG_ICCR) | IIC_DVFS_BIT_ICCR_ENABLE; + mmio_write_8(IIC_DVFS_REG_ICCR, mode); + + lsi_product = mmio_read_32(RCAR_PRR) & RCAR_PRODUCT_MASK; + if (lsi_product == RCAR_PRODUCT_E3) + goto start; + + reg = mmio_read_32(RCAR_MODEMR) & CHECK_MD13_MD14; + switch (reg) { + case MD14_MD13_TYPE_0: + iccl = IIC_DVFS_SET_ICCL_EXTAL_TYPE_0; + icch = IIC_DVFS_SET_ICCH_EXTAL_TYPE_0; + break; + case MD14_MD13_TYPE_1: + iccl = IIC_DVFS_SET_ICCL_EXTAL_TYPE_1; + icch = IIC_DVFS_SET_ICCH_EXTAL_TYPE_1; + break; + case MD14_MD13_TYPE_2: + iccl = IIC_DVFS_SET_ICCL_EXTAL_TYPE_2; + icch = IIC_DVFS_SET_ICCH_EXTAL_TYPE_2; + break; + default: + iccl = IIC_DVFS_SET_ICCL_EXTAL_TYPE_3; + icch = IIC_DVFS_SET_ICCH_EXTAL_TYPE_3; + break; + } +start: + mmio_write_8(IIC_DVFS_REG_ICCL, iccl); + mmio_write_8(IIC_DVFS_REG_ICCH, icch); + + mode = mmio_read_8(IIC_DVFS_REG_ICIC) + | IIC_DVFS_BIT_ICIC_TACKE + | IIC_DVFS_BIT_ICIC_WAITE | IIC_DVFS_BIT_ICIC_DTEE; + + mmio_write_8(IIC_DVFS_REG_ICIC, mode); + mmio_write_8(IIC_DVFS_REG_ICCR, IIC_DVFS_SET_ICCR_START); + + *state = DVFS_SET_SLAVE; + + return result; +} + +IIC_DVFS_FUNC(set_slave, DVFS_STATE_T * state, uint32_t *err, uint8_t slave) +{ + uint8_t mode; + int32_t result; + uint8_t address; + + result = dvfs_check_error(state, err, DVFS_WRITE_MODE); + if (result == DVFS_ERROR) + return result; + + mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_DTE; + if (mode != IIC_DVFS_BIT_ICSR_DTE) + return result; + + mode = mmio_read_8(IIC_DVFS_REG_ICIC) & ~IIC_DVFS_BIT_ICIC_DTEE; + mmio_write_8(IIC_DVFS_REG_ICIC, mode); + + address = slave << 1; + mmio_write_8(IIC_DVFS_REG_ICDR, address); + + *state = DVFS_WRITE_ADDR; + + return result; +} + +IIC_DVFS_FUNC(write_addr, DVFS_STATE_T *state, uint32_t *err, uint8_t reg_addr) +{ + uint8_t mode; + int32_t result; + + result = dvfs_check_error(state, err, DVFS_WRITE_MODE); + if (result == DVFS_ERROR) + return result; + + mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_WAIT; + if (mode != IIC_DVFS_BIT_ICSR_WAIT) + return result; + + mmio_write_8(IIC_DVFS_REG_ICDR, reg_addr); + + mode = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_WAIT; + mmio_write_8(IIC_DVFS_REG_ICSR, mode); + + *state = DVFS_WRITE_DATA; + + return result; +} + +IIC_DVFS_FUNC(write_data, DVFS_STATE_T *state, uint32_t *err, uint8_t reg_data) +{ + int32_t result; + uint8_t mode; + + result = dvfs_check_error(state, err, DVFS_WRITE_MODE); + if (result == DVFS_ERROR) + return result; + + mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_WAIT; + if (mode != IIC_DVFS_BIT_ICSR_WAIT) + return result; + + mmio_write_8(IIC_DVFS_REG_ICDR, reg_data); + + mode = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_WAIT; + mmio_write_8(IIC_DVFS_REG_ICSR, mode); + + *state = DVFS_STOP; + + return result; +} + +IIC_DVFS_FUNC(stop, DVFS_STATE_T *state, uint32_t *err) +{ + int32_t result; + uint8_t mode; + + result = dvfs_check_error(state, err, DVFS_WRITE_MODE); + if (result == DVFS_ERROR) + return result; + + mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_WAIT; + if (mode != IIC_DVFS_BIT_ICSR_WAIT) + return result; + + mmio_write_8(IIC_DVFS_REG_ICCR, IIC_DVFS_SET_ICCR_STOP); + + mode = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_WAIT; + mmio_write_8(IIC_DVFS_REG_ICSR, mode); + + *state = DVFS_DONE; + + return result; +} + +IIC_DVFS_FUNC(done, void) +{ + uint32_t i; + + for (i = 0; i < IIC_DVFS_SET_BUSY_LOOP; i++) { + if (mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_BUSY) + continue; + goto done; + } + + panic(); +done: + mmio_write_8(IIC_DVFS_REG_ICCR, 0); + + return DVFS_COMPLETE; +} + +IIC_DVFS_FUNC(write_reg_addr_read, DVFS_STATE_T *state, uint32_t *err, + uint8_t reg_addr) +{ + int32_t result; + uint8_t mode; + + result = dvfs_check_error(state, err, DVFS_WRITE_MODE); + if (result == DVFS_ERROR) + return result; + + mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_WAIT; + if (mode != IIC_DVFS_BIT_ICSR_WAIT) + return result; + + mmio_write_8(IIC_DVFS_REG_ICDR, reg_addr); + + mode = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_WAIT; + mmio_write_8(IIC_DVFS_REG_ICSR, mode); + + *state = DVFS_RETRANSMIT; + + return result; +} + +IIC_DVFS_FUNC(retransmit, DVFS_STATE_T *state, uint32_t *err) +{ + int32_t result; + uint8_t mode; + + result = dvfs_check_error(state, err, DVFS_WRITE_MODE); + if (result == DVFS_ERROR) + return result; + + mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_WAIT; + if (mode != IIC_DVFS_BIT_ICSR_WAIT) + return result; + + mmio_write_8(IIC_DVFS_REG_ICCR, IIC_DVFS_SET_ICCR_RETRANSMISSION); + + mode = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_WAIT; + mmio_write_8(IIC_DVFS_REG_ICSR, mode); + + mode = mmio_read_8(IIC_DVFS_REG_ICIC) | IIC_DVFS_BIT_ICIC_DTEE; + mmio_write_8(IIC_DVFS_REG_ICIC, mode); + + *state = DVFS_SET_SLAVE_READ; + + return result; +} + +IIC_DVFS_FUNC(set_slave_read, DVFS_STATE_T *state, uint32_t *err, + uint8_t slave) +{ + uint8_t address; + int32_t result; + uint8_t mode; + + result = dvfs_check_error(state, err, DVFS_WRITE_MODE); + if (result == DVFS_ERROR) + return result; + + mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_DTE; + if (mode != IIC_DVFS_BIT_ICSR_DTE) + return result; + + mode = mmio_read_8(IIC_DVFS_REG_ICIC) & ~IIC_DVFS_BIT_ICIC_DTEE; + mmio_write_8(IIC_DVFS_REG_ICIC, mode); + + address = ((uint8_t) (slave << 1) + DVFS_READ_MODE); + mmio_write_8(IIC_DVFS_REG_ICDR, address); + + *state = DVFS_CHANGE_SEND_TO_RECIEVE; + + return result; +} + +IIC_DVFS_FUNC(change_send_to_recieve, DVFS_STATE_T *state, uint32_t *err) +{ + int32_t result; + uint8_t mode; + + result = dvfs_check_error(state, err, DVFS_WRITE_MODE); + if (result == DVFS_ERROR) + return result; + + mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_WAIT; + if (mode != IIC_DVFS_BIT_ICSR_WAIT) + return result; + + mmio_write_8(IIC_DVFS_REG_ICCR, IIC_DVFS_SET_ICCR_CHANGE); + + mode = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_WAIT; + mmio_write_8(IIC_DVFS_REG_ICSR, mode); + + *state = DVFS_STOP_READ; + + return result; +} + +IIC_DVFS_FUNC(stop_read, DVFS_STATE_T *state, uint32_t *err) +{ + int32_t result; + uint8_t mode; + + result = dvfs_check_error(state, err, DVFS_READ_MODE); + if (result == DVFS_ERROR) + return result; + + mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_WAIT; + if (mode != IIC_DVFS_BIT_ICSR_WAIT) + return result; + + mmio_write_8(IIC_DVFS_REG_ICCR, IIC_DVFS_SET_ICCR_STOP_READ); + + mode = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_WAIT; + mmio_write_8(IIC_DVFS_REG_ICSR, mode); + + mode = mmio_read_8(IIC_DVFS_REG_ICIC) | IIC_DVFS_BIT_ICIC_DTEE; + mmio_write_8(IIC_DVFS_REG_ICIC, mode); + + *state = DVFS_READ; + + return result; +} + +IIC_DVFS_FUNC(read, DVFS_STATE_T *state, uint8_t *reg_data) +{ + uint8_t mode; + + mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_DTE; + if (mode != IIC_DVFS_BIT_ICSR_DTE) + return DVFS_PROCESS; + + mode = mmio_read_8(IIC_DVFS_REG_ICIC) & ~IIC_DVFS_BIT_ICIC_DTEE; + mmio_write_8(IIC_DVFS_REG_ICIC, mode); + + *reg_data = mmio_read_8(IIC_DVFS_REG_ICDR); + *state = DVFS_DONE; + + return DVFS_PROCESS; +} + +RCAR_DVFS_API(send, uint8_t slave, uint8_t reg_addr, uint8_t reg_data) +{ + DVFS_STATE_T state = DVFS_START; + int32_t result = DVFS_PROCESS; + uint32_t err = 0; + + mstpcr_write(SCMSTPCR9, CPG_MSTPSR9, CPG_BIT_SMSTPCR9_DVFS); + mmio_write_8(IIC_DVFS_REG_ICCR, 0); +again: + switch (state) { + case DVFS_START: + result = dvfs_start(&state); + break; + case DVFS_SET_SLAVE: + result = dvfs_set_slave(&state, &err, slave); + break; + case DVFS_WRITE_ADDR: + result = dvfs_write_addr(&state, &err, reg_addr); + break; + case DVFS_WRITE_DATA: + result = dvfs_write_data(&state, &err, reg_data); + break; + case DVFS_STOP: + result = dvfs_stop(&state, &err); + break; + case DVFS_DONE: + result = dvfs_done(); + break; + default: + panic(); + break; + } + + if (result == DVFS_PROCESS) + goto again; + + return result; +} + +RCAR_DVFS_API(receive, uint8_t slave, uint8_t reg, uint8_t *data) +{ + DVFS_STATE_T state = DVFS_START; + int32_t result = DVFS_PROCESS; + uint32_t err = 0; + + mstpcr_write(SCMSTPCR9, CPG_MSTPSR9, CPG_BIT_SMSTPCR9_DVFS); + mmio_write_8(IIC_DVFS_REG_ICCR, 0); +again: + switch (state) { + case DVFS_START: + result = dvfs_start(&state); + break; + case DVFS_SET_SLAVE: + result = dvfs_set_slave(&state, &err, slave); + break; + case DVFS_WRITE_ADDR: + result = dvfs_write_reg_addr_read(&state, &err, reg); + break; + case DVFS_RETRANSMIT: + result = dvfs_retransmit(&state, &err); + break; + case DVFS_SET_SLAVE_READ: + result = dvfs_set_slave_read(&state, &err, slave); + break; + case DVFS_CHANGE_SEND_TO_RECIEVE: + result = dvfs_change_send_to_recieve(&state, &err); + break; + case DVFS_STOP_READ: + result = dvfs_stop_read(&state, &err); + break; + case DVFS_READ: + result = dvfs_read(&state, data); + break; + case DVFS_DONE: + result = dvfs_done(); + break; + default: + panic(); + break; + } + + if (result == DVFS_PROCESS) + goto again; + + return result; +} diff --git a/drivers/renesas/rcar/iic_dvfs/iic_dvfs.h b/drivers/renesas/rcar/iic_dvfs/iic_dvfs.h new file mode 100644 index 000000000..3c4a9a552 --- /dev/null +++ b/drivers/renesas/rcar/iic_dvfs/iic_dvfs.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef IIC_DVFS_H__ +#define IIC_DVFS_H__ + +/* PMIC slave */ +#define PMIC (0x30) +#define BKUP_MODE_CNT (0x20) +#define DVFS_SET_VID (0x54) +#define REG_KEEP10 (0x79) + +/* EEPROM slave */ +#define EEPROM (0x50) +#define BOARD_ID (0x70) + +int32_t rcar_iic_dvfs_receive(uint8_t slave, uint8_t reg, uint8_t *data); +int32_t rcar_iic_dvfs_send(uint8_t slave, uint8_t regr, uint8_t data); + +#endif