diff options
author | Ruilin Hao <rlhao@marvell.com> | 2015-11-10 00:18:59 -0800 |
---|---|---|
committer | Patrick Georgi <pgeorgi@google.com> | 2016-02-04 11:31:45 +0100 |
commit | de4defbaaf76a8bf7a705e3d1b265e1936cd7481 (patch) | |
tree | 8b1184e4496851be3a9a98d8a37527be4891bab9 /src/soc | |
parent | c1b9e7934c0b100b8ce558669df8b57a03b2271f (diff) | |
download | coreboot-de4defbaaf76a8bf7a705e3d1b265e1936cd7481.tar.xz |
soc/marvell/armada38x: Add i2c driver for armada38x
Port i2c driver from uboot to coreboot
BUG=chrome-os-partner:47462
TEST=emerge-cyclone coreboot
BRANCH=tot
Change-Id: I8ce2a965acaed68ad0f0518648490ec471c6810b
Signed-off-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Commit-Id: 4c2e9592662787ebed1d0aa8cafaa00fd12c2e9c
Original-Change-Id: If791228edf29405fa4b2f959a21510bd7da9865b
Original-Signed-off-by: Ruilin Hao <rlhao@marvell.com>
Original-Reviewed-on: https://chromium-review.googlesource.com/313342
Original-Commit-Ready: Kan Yan <kyan@google.com>
Original-Tested-by: Kan Yan <kyan@google.com>
Original-Reviewed-by: Furquan Shaikh <furquan@chromium.org>
Reviewed-on: https://review.coreboot.org/13113
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Diffstat (limited to 'src/soc')
-rw-r--r-- | src/soc/marvell/armada38x/Makefile.inc | 7 | ||||
-rw-r--r-- | src/soc/marvell/armada38x/clock.c | 35 | ||||
-rw-r--r-- | src/soc/marvell/armada38x/i2c.c | 1251 | ||||
-rw-r--r-- | src/soc/marvell/armada38x/include/soc/clock.h | 21 | ||||
-rw-r--r-- | src/soc/marvell/armada38x/include/soc/i2c.h | 120 | ||||
-rw-r--r-- | src/soc/marvell/armada38x/spi.c | 3 | ||||
-rw-r--r-- | src/soc/marvell/armada38x/uart.c | 3 |
7 files changed, 1437 insertions, 3 deletions
diff --git a/src/soc/marvell/armada38x/Makefile.inc b/src/soc/marvell/armada38x/Makefile.inc index bc72d10dc9..c62d95f96e 100644 --- a/src/soc/marvell/armada38x/Makefile.inc +++ b/src/soc/marvell/armada38x/Makefile.inc @@ -5,6 +5,7 @@ bootblock-y += bootblock_asm.S bootblock-y += spi.c bootblock-y += gpio.c bootblock-y += monotonic_timer.c +bootblock-y += clock.c ifeq ($(CONFIG_BOOTBLOCK_CONSOLE),y) bootblock-$(CONFIG_DRIVERS_UART) += uart.c endif @@ -13,12 +14,15 @@ verstage-$(CONFIG_DRIVERS_UART) += uart.c verstage-y += monotonic_timer.c verstage-y += spi.c verstage-y += gpio.c +verstage-y += i2c.c +verstage-y += clock.c romstage-y += spi.c romstage-y += gpio.c romstage-y += cbmem.c romstage-y += monotonic_timer.c romstage-$(CONFIG_DRIVERS_UART) += uart.c +romstage-y += clock.c ramstage-y += spi.c ramstage-y += gpio.c @@ -26,8 +30,9 @@ ramstage-y += cbmem.c ramstage-y += monotonic_timer.c ramstage-y += soc.c ramstage-$(CONFIG_DRIVERS_UART) += uart.c +ramstage-y += clock.c -CPPFLAGS_common += -Isrc/soc/marvell/armada38x/include/ +CPPFLAGS_common += -Isrc/soc/marvell/armada38x/include/ -Isrc/commonlib/include/commonlib/ BIN_HDR = 3rdparty/blobs/cpu/marvell/armada38x/bin_hdr.bin DOIMAGE = 3rdparty/blobs/cpu/marvell/armada38x/doimage diff --git a/src/soc/marvell/armada38x/clock.c b/src/soc/marvell/armada38x/clock.c new file mode 100644 index 0000000000..579e1a3d2b --- /dev/null +++ b/src/soc/marvell/armada38x/clock.c @@ -0,0 +1,35 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2015 Google 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 <soc/common.h> +#include <soc/clock.h> + +uint32_t mv_tclk_get(void) +{ + uint32_t tclk_reg_value; + uint32_t tclk; + + tclk_reg_value = (mrvl_reg_read(MPP_SAMPLE_AT_RESET)); + tclk_reg_value = ((tclk_reg_value & (1 << 15)) >> 15); + switch (tclk_reg_value) { + case 0: + tclk = MV_BOARD_TCLK_250MHZ; + case 1: + tclk = MV_BOARD_TCLK_200MHZ; + default: + tclk = MV_BOARD_TCLK_250MHZ; + } + return tclk; +} diff --git a/src/soc/marvell/armada38x/i2c.c b/src/soc/marvell/armada38x/i2c.c new file mode 100644 index 0000000000..723d3b4b1d --- /dev/null +++ b/src/soc/marvell/armada38x/i2c.c @@ -0,0 +1,1251 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2015 Marvell 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 <arch/cpu.h> +#include <console/console.h> +#include <delay.h> +#include <device/i2c.h> +#include <soc/common.h> +#include <soc/i2c.h> +#include <soc/clock.h> +#include <helpers.h> + +#undef MV_DEBUG +//#define MV_DEBUG +#ifdef MV_DEBUG +#define DB(x) x +#else +#define DB(x) +#endif +#define mv_os_printf(args...) printk(BIOS_INFO, args) + +/* The TWSI interface supports both 7-bit and 10-bit addressing. */ +/* This enumerator describes addressing type. */ +typedef enum _mv_twsi_addr_type { + ADDR7_BIT, /* 7 bit address */ + ADDR10_BIT /* 10 bit address */ +} MV_TWSI_ADDR_TYPE; + +/* This structure describes TWSI address. */ +typedef struct _mv_twsi_addr { + uint32_t address; /* address */ + MV_TWSI_ADDR_TYPE type; /* Address type */ +} MV_TWSI_ADDR; + +/* This structure describes a TWSI slave. */ +typedef struct _mv_twsi_slave { + MV_TWSI_ADDR slave_addr; + int valid_offset; /* whether the slave has offset (i.e. Eeprom etc.) */ + uint32_t offset; /* offset in the slave. */ + int more_than256; /* whether the ofset is bigger then 256 */ +} MV_TWSI_SLAVE; + +/* This enumerator describes TWSI protocol commands. */ +typedef enum _mv_twsi_cmd { + MV_TWSI_WRITE, /* TWSI write command - 0 according to spec */ + MV_TWSI_READ /* TWSI read command - 1 according to spec */ +} MV_TWSI_CMD; + +static void twsi_int_flg_clr(uint8_t chan_num); +static uint8_t twsi_main_int_get(uint8_t chan_num); +static void twsi_ack_bit_set(uint8_t chan_num); +static uint32_t twsi_sts_get(uint8_t chan_num); +static void twsi_reset(uint8_t chan_num); +static int twsi_addr7_bit_set(uint8_t chan_num, + uint32_t device_address, + MV_TWSI_CMD command); +static int twsi_addr10_bit_set(uint8_t chan_num, + uint32_t device_address, + MV_TWSI_CMD command); +static int twsi_data_transmit(uint8_t chan_num, + uint8_t *p_block, + uint32_t block_size); +static int twsi_data_receive(uint8_t chan_num, + uint8_t *p_block, + uint32_t block_size); +static int twsi_target_offs_set(uint8_t chan_num, + uint32_t offset, + uint8_t more_than256); +static int mv_twsi_start_bit_set(uint8_t chan_num); +static int mv_twsi_stop_bit_set(uint8_t chan_num); +static int mv_twsi_addr_set(uint8_t chan_num, + MV_TWSI_ADDR *twsi_addr, + MV_TWSI_CMD command); +static uint32_t mv_twsi_init(uint8_t chan_num, + uint32_t frequency, + uint32_t Tclk, + MV_TWSI_ADDR *twsi_addr, + uint8_t general_call_enable); +static int mv_twsi_read(uint8_t chan_num, + MV_TWSI_SLAVE *twsi_slave, + uint8_t *p_block, + uint32_t block_size); +static int mv_twsi_write(uint8_t chan_num, + MV_TWSI_SLAVE *twsi_slave, + uint8_t *p_block, + uint32_t block_size); +static uint32_t who_am_i(void); +static int i2c_init(unsigned bus); +static void i2c_reset(unsigned bus); + +static int m_initialized[MAX_I2C_NUM] = {0, 0}; + +static uint8_t twsi_timeout_chk(uint32_t timeout, const char *p_string) +{ + if (timeout >= TWSI_TIMEOUT_VALUE) { + DB(mv_os_printf("%s", p_string)); + return MV_TRUE; + } + return MV_FALSE; +} + +/******************************************************************************* +* mv_twsi_start_bit_set - Set start bit on the bus +* +* DESCRIPTION: +* This routine sets the start bit on the TWSI bus. +* The routine first checks for interrupt flag condition, then it sets +* the start bit in the TWSI Control register. +* If the interrupt flag condition check previously was set, the function +* will clear it. +* The function then wait for the start bit to be cleared by the HW. +* Then it waits for the interrupt flag to be set and eventually, the +* TWSI status is checked to be 0x8 or 0x10(repeated start bit). +* +* INPUT: +* chan_num - TWSI channel. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_OK if start bit was set successfuly on the bus. +* MV_FAIL if start_bit not set or status does not indicate start +* condition trasmitted. +* +*******************************************************************************/ +static int mv_twsi_start_bit_set(uint8_t chan_num) +{ + uint8_t is_int_flag = MV_FALSE; + uint32_t timeout, temp; + + DB(mv_os_printf("TWSI: mv_twsi_start_bit_set\n")); + /* check Int flag */ + if (twsi_main_int_get(chan_num)) + is_int_flag = MV_TRUE; + /* set start Bit */ + mrvl_reg_bit_set(TWSI_CONTROL_REG(chan_num), TWSI_CONTROL_START_BIT); + + /* in case that the int flag was set before i.e. repeated start bit */ + if (is_int_flag) { + DB(mv_os_printf( + "TWSI: mv_twsi_start_bit_set repeated start Bit\n")); + twsi_int_flg_clr(chan_num); + } + + /* wait for interrupt */ + timeout = 0; + while (!twsi_main_int_get(chan_num) && (timeout++ < TWSI_TIMEOUT_VALUE)) + ; + + /* check for timeout */ + if (MV_TRUE == + twsi_timeout_chk(timeout, + (const char *)"TWSI: Start Clear bit time_out.\n")) + return MV_TIMEOUT; + + /* check that start bit went down */ + if ((mrvl_reg_read(TWSI_CONTROL_REG(chan_num)) & + TWSI_CONTROL_START_BIT) != 0) { + mv_os_printf("TWSI: start bit didn't go down\n"); + return MV_FAIL; + } + + /* check the status */ + temp = twsi_sts_get(chan_num); + if ((TWSI_M_LOST_ARB_DUR_AD_OR_DATA_TRA == temp) || + (TWSI_M_LOST_ARB_DUR_AD_TRA_GNL_CALL_AD_REC_ACK_TRA == temp)) { + DB(mv_os_printf("TWSI: Lost Arb, status %x\n", temp)); + return MV_RETRY; + } else if ((temp != TWSI_START_CON_TRA) && + (temp != TWSI_REPEATED_START_CON_TRA)) { + mv_os_printf("TWSI: status %x after Set Start Bit.\n", temp); + return MV_FAIL; + } + + return MV_OK; +} + +/******************************************************************************* +* mv_twsi_stop_bit_set - Set stop bit on the bus +* +* DESCRIPTION: +* This routine set the stop bit on the TWSI bus. +* The function then wait for the stop bit to be cleared by the HW. +* Finally the function checks for status of 0xF8. +* +* INPUT: +* chan_num - TWSI channel +* +* OUTPUT: +* None. +* +* RETURN: +* MV_TRUE is stop bit was set successfuly on the bus. +* +*******************************************************************************/ +static int mv_twsi_stop_bit_set(uint8_t chan_num) +{ + uint32_t timeout, temp; + + /* Generate stop bit */ + mrvl_reg_bit_set(TWSI_CONTROL_REG(chan_num), TWSI_CONTROL_STOP_BIT); + + twsi_int_flg_clr(chan_num); + + /* wait for stop bit to come down */ + timeout = 0; + while (((mrvl_reg_read(TWSI_CONTROL_REG(chan_num)) & + TWSI_CONTROL_STOP_BIT) != 0) && + (timeout++ < TWSI_TIMEOUT_VALUE)) + ; + + /* check for timeout */ + if (MV_TRUE == + twsi_timeout_chk(timeout, + (const char *)"TWSI: ERROR - Stop bit timeout\n")) + return MV_TIMEOUT; + + /* check that the stop bit went down */ + if ((mrvl_reg_read(TWSI_CONTROL_REG(chan_num)) & + TWSI_CONTROL_STOP_BIT) != 0) { + mv_os_printf( + "TWSI: ERROR - stop bit not went down\n"); + return MV_FAIL; + } + + /* check the status */ + temp = twsi_sts_get(chan_num); + if ((TWSI_M_LOST_ARB_DUR_AD_OR_DATA_TRA == temp) || + (TWSI_M_LOST_ARB_DUR_AD_TRA_GNL_CALL_AD_REC_ACK_TRA == temp)) { + DB(mv_os_printf("TWSI: Lost Arb, status %x\n", temp)); + return MV_RETRY; + } else if (temp != TWSI_NO_REL_STS_INT_FLAG_IS_KEPT_0) { + mv_os_printf( + "TWSI: ERROR - status %x after Stop Bit\n", + temp); + return MV_FAIL; + } + + return MV_OK; +} + +/******************************************************************************* +* twsi_main_int_get - Get twsi bit from main Interrupt cause. +* +* DESCRIPTION: +* This routine returns the twsi interrupt flag value. +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_TRUE is interrupt flag is set, MV_FALSE otherwise. +* +*******************************************************************************/ +static uint32_t who_am_i(void) +{ + return (read_mpidr() & 0x1); +} + +static uint8_t twsi_main_int_get(uint8_t chan_num) +{ + uint32_t temp; + + /* get the int flag bit */ + temp = mrvl_reg_read(MV_TWSI_CPU_MAIN_INT_CAUSE(chan_num, who_am_i())); + if (temp & (1 << CPU_MAIN_INT_TWSI_OFFS(chan_num))) + return MV_TRUE; + + return MV_FALSE; +} + +/******************************************************************************* +* twsi_int_flg_clr - Clear Interrupt flag. +* +* DESCRIPTION: +* This routine clears the interrupt flag. It does NOT poll the interrupt +* to make sure the clear. After clearing the interrupt, it waits for at +* least 1 miliseconds. +* +* INPUT: +* chan_num - TWSI channel +* +* OUTPUT: +* None. +* +* RETURN: +* None. +* +*******************************************************************************/ +static void twsi_int_flg_clr(uint8_t chan_num) +{ + /* wait for 1ms to prevent TWSI register write after write problems */ + mdelay(1); + /* clear the int flag bit */ + mrvl_reg_bit_reset( + TWSI_CONTROL_REG(chan_num), TWSI_CONTROL_INT_FLAG_SET); + /* wait for 1 mili sec for the clear to take effect */ + mdelay(1); +} + +/******************************************************************************* +* twsi_ack_bit_set - Set acknowledge bit on the bus +* +* DESCRIPTION: +* This routine set the acknowledge bit on the TWSI bus. +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* None. +* +*******************************************************************************/ +static void twsi_ack_bit_set(uint8_t chan_num) +{ + /*Set the Ack bit */ + mrvl_reg_bit_set(TWSI_CONTROL_REG(chan_num), TWSI_CONTROL_ACK); + /* Add delay of 1ms */ + mdelay(1); +} + +/******************************************************************************* +* twsi_init - Initialize TWSI interface +* +* DESCRIPTION: +* This routine: +* -Reset the TWSI. +* -Initialize the TWSI clock baud rate according to given frequency +* parameter based on Tclk frequency and enables TWSI slave. +* -Set the ack bit. +* -Assign the TWSI slave address according to the TWSI address Type. +* +* INPUT: +* chan_num - TWSI channel +* frequency - TWSI frequency in KHz. (up to 100_kHZ) +* +* OUTPUT: +* None. +* +* RETURN: +* Actual frequency. +* +*******************************************************************************/ +static uint32_t mv_twsi_init(uint8_t chan_num, + uint32_t frequency, + uint32_t Tclk, + MV_TWSI_ADDR *p_twsi_addr, + uint8_t general_call_enable) +{ + uint32_t n, m, freq, margin, min_margin = 0xffffffff; + uint32_t power; + uint32_t actual_freq = 0, actual_n = 0, actual_m = 0, val; + + if (frequency > 100000) + die("TWSI frequency is too high!"); + + DB(mv_os_printf("TWSI: mv_twsi_init - Tclk = %d freq = %d\n", Tclk, + frequency)); + /* Calucalte N and M for the TWSI clock baud rate */ + for (n = 0; n < 8; n++) { + for (m = 0; m < 16; m++) { + power = 2 << n; /* power = 2^(n+1) */ + freq = Tclk / (10 * (m + 1) * power); + margin = ABS(frequency - freq); + + if ((freq <= frequency) && (margin < min_margin)) { + min_margin = margin; + actual_freq = freq; + actual_n = n; + actual_m = m; + } + } + } + DB(mv_os_printf("TWSI: mv_twsi_init - act_n %u act_m %u act_freq %u\n", + actual_n, actual_m, actual_freq)); + /* Reset the TWSI logic */ + twsi_reset(chan_num); + + /* Set the baud rate */ + val = ((actual_m << TWSI_BAUD_RATE_M_OFFS) | + actual_n << TWSI_BAUD_RATE_N_OFFS); + mrvl_reg_write(TWSI_STATUS_BAUDE_RATE_REG(chan_num), val); + + /* Enable the TWSI and slave */ + mrvl_reg_write(TWSI_CONTROL_REG(chan_num), + TWSI_CONTROL_ENA | TWSI_CONTROL_ACK); + + /* set the TWSI slave address */ + if (p_twsi_addr->type == ADDR10_BIT) { + /* writing the 2 most significant bits of the 10 bit address */ + val = ((p_twsi_addr->address & TWSI_SLAVE_ADDR_10_BIT_MASK) >> + TWSI_SLAVE_ADDR_10_BIT_OFFS); + /* bits 7:3 must be 0x11110 */ + val |= TWSI_SLAVE_ADDR_10_BIT_CONST; + /* set GCE bit */ + if (general_call_enable) + val |= TWSI_SLAVE_ADDR_GCE_ENA; + /* write slave address */ + mrvl_reg_write(TWSI_SLAVE_ADDR_REG(chan_num), val); + + /* writing the 8 least significant bits of the 10 bit address */ + val = (p_twsi_addr->address << TWSI_EXTENDED_SLAVE_OFFS) & + TWSI_EXTENDED_SLAVE_MASK; + mrvl_reg_write(TWSI_EXTENDED_SLAVE_ADDR_REG(chan_num), val); + } else { + /* set the 7 Bits address */ + mrvl_reg_write(TWSI_EXTENDED_SLAVE_ADDR_REG(chan_num), 0x0); + val = (p_twsi_addr->address << TWSI_SLAVE_ADDR_7_BIT_OFFS) & + TWSI_SLAVE_ADDR_7_BIT_MASK; + mrvl_reg_write(TWSI_SLAVE_ADDR_REG(chan_num), val); + } + + /* unmask twsi int */ + mrvl_reg_bit_set(TWSI_CONTROL_REG(chan_num), TWSI_CONTROL_INT_ENA); + + /* unmask twsi int in Interrupt source control register */ + mrvl_reg_bit_set(CPU_INT_SOURCE_CONTROL_REG( + CPU_MAIN_INT_CAUSE_TWSI(chan_num)), ( + 1 << CPU_INT_SOURCE_CONTROL_IRQ_OFFS)); + + /* Add delay of 1ms */ + mdelay(1); + + return actual_freq; +} + +/******************************************************************************* +* twsi_sts_get - Get the TWSI status value. +* +* DESCRIPTION: +* This routine returns the TWSI status value. +* +* INPUT: +* chan_num - TWSI channel +* +* OUTPUT: +* None. +* +* RETURN: +* uint32_t - the TWSI status. +* +*******************************************************************************/ +static uint32_t twsi_sts_get(uint8_t chan_num) +{ + return mrvl_reg_read(TWSI_STATUS_BAUDE_RATE_REG(chan_num)); +} + +/******************************************************************************* +* twsi_reset - Reset the TWSI. +* +* DESCRIPTION: +* Resets the TWSI logic and sets all TWSI registers to their reset values. +* +* INPUT: +* chan_num - TWSI channel +* +* OUTPUT: +* None. +* +* RETURN: +* None +* +*******************************************************************************/ +static void twsi_reset(uint8_t chan_num) +{ + /* Reset the TWSI logic */ + mrvl_reg_write(TWSI_SOFT_RESET_REG(chan_num), 0); + + /* wait for 2 mili sec */ + mdelay(2); +} + +/******************************************************************************* +* mv_twsi_addr_set - Set address on TWSI bus. +* +* DESCRIPTION: +* This function Set address (7 or 10 Bit address) on the Twsi Bus. +* +* INPUT: +* chan_num - TWSI channel +* p_twsi_addr - twsi address. +* command - read / write . +* +* OUTPUT: +* None. +* +* RETURN: +* MV_OK - if setting the address completed successfully. +* MV_FAIL otherwmise. +* +*******************************************************************************/ +static int mv_twsi_addr_set(uint8_t chan_num, + MV_TWSI_ADDR *p_twsi_addr, + MV_TWSI_CMD command) +{ + DB(mv_os_printf( + "TWSI: mv_twsi_addr7_bit_set addr %x , type %d, cmd is %s\n", + p_twsi_addr->address, p_twsi_addr->type, + ((command == MV_TWSI_WRITE) ? "Write" : "Read"))); + /* 10 Bit address */ + if (p_twsi_addr->type == ADDR10_BIT) + return twsi_addr10_bit_set(chan_num, p_twsi_addr->address, + command); + /* 7 Bit address */ + else + return twsi_addr7_bit_set(chan_num, p_twsi_addr->address, + command); +} + +/******************************************************************************* +* twsi_addr10_bit_set - Set 10 Bit address on TWSI bus. +* +* DESCRIPTION: +* There are two address phases: +* 1) Write '11110' to data register bits [7:3] and 10-bit address MSB +* (bits [9:8]) to data register bits [2:1] plus a write(0) or read(1) +*bit +* to the Data register. Then it clears interrupt flag which drive +* the address on the TWSI bus. The function then waits for interrupt +* flag to be active and status 0x18 (write) or 0x40 (read) to be set. +* 2) write the rest of 10-bit address to data register and clears +* interrupt flag which drive the address on the TWSI bus. The +* function then waits for interrupt flag to be active and status +* 0xD0 (write) or 0xE0 (read) to be set. +* +* INPUT: +* chan_num - TWSI channel +* device_address - twsi address. +* command - read / write . +* +* OUTPUT: +* None. +* +* RETURN: +* MV_OK - if setting the address completed successfully. +* MV_FAIL otherwmise. +* +*******************************************************************************/ +static int twsi_addr10_bit_set(uint8_t chan_num, + uint32_t device_address, + MV_TWSI_CMD command) +{ + uint32_t val, timeout; + + /* writing the 2 most significant bits of the 10 bit address */ + val = ((device_address & TWSI_DATA_ADDR_10_BIT_MASK) >> + TWSI_DATA_ADDR_10_BIT_OFFS); + /* bits 7:3 must be 0x11110 */ + val |= TWSI_DATA_ADDR_10_BIT_CONST; + /* set command */ + val |= command; + mrvl_reg_write(TWSI_DATA_REG(chan_num), val); + /* WA add a delay */ + mdelay(1); + + /* clear Int flag */ + twsi_int_flg_clr(chan_num); + + /* wait for Int to be Set */ + timeout = 0; + while (!twsi_main_int_get(chan_num) && (timeout++ < TWSI_TIMEOUT_VALUE)) + ; + + /* check for timeout */ + if (MV_TRUE == + twsi_timeout_chk( + timeout, (const char *)"TWSI: addr (10_bit) Int time_out.\n")) + return MV_TIMEOUT; + + /* check the status */ + val = twsi_sts_get(chan_num); + if ((TWSI_M_LOST_ARB_DUR_AD_OR_DATA_TRA == val) || + (TWSI_M_LOST_ARB_DUR_AD_TRA_GNL_CALL_AD_REC_ACK_TRA == val)) { + DB(mv_os_printf("TWSI: Lost Arb, status %x\n", val)); + return MV_RETRY; + } else if (((val != TWSI_AD_PLS_RD_BIT_TRA_ACK_REC) && + (command == MV_TWSI_READ)) || + ((val != TWSI_AD_PLS_WR_BIT_TRA_ACK_REC) && + (command == MV_TWSI_WRITE))) { + mv_os_printf("TWSI: status %x 1st addr (10 Bit) in %s mode.\n", + val, + ((command == MV_TWSI_WRITE) ? "Write" : "Read")); + return MV_FAIL; + } + + /* set 8 LSB of the address */ + val = (device_address << TWSI_DATA_ADDR_7_BIT_OFFS) & + TWSI_DATA_ADDR_7_BIT_MASK; + mrvl_reg_write(TWSI_DATA_REG(chan_num), val); + + /* clear Int flag */ + twsi_int_flg_clr(chan_num); + + /* wait for Int to be Set */ + timeout = 0; + while (!twsi_main_int_get(chan_num) && (timeout++ < TWSI_TIMEOUT_VALUE)) + ; + + /* check for timeout */ + if (MV_TRUE == + twsi_timeout_chk(timeout, + (const char *)"TWSI: 2nd (10 Bit) Int tim_out.\n")) + return MV_TIMEOUT; + + /* check the status */ + val = twsi_sts_get(chan_num); + if ((TWSI_M_LOST_ARB_DUR_AD_OR_DATA_TRA == val) || + (TWSI_M_LOST_ARB_DUR_AD_TRA_GNL_CALL_AD_REC_ACK_TRA == val)) { + DB(mv_os_printf("TWSI: Lost Arb, status %x\n", val)); + return MV_RETRY; + } else if (((val != TWSI_SEC_AD_PLS_RD_BIT_TRA_ACK_REC) && + (command == MV_TWSI_READ)) || + ((val != TWSI_SEC_AD_PLS_WR_BIT_TRA_ACK_REC) && + (command == MV_TWSI_WRITE))) { + mv_os_printf("TWSI: status %x 2nd addr(10 Bit) in %s mode.\n", + val, + ((command == MV_TWSI_WRITE) ? "Write" : "Read")); + return MV_FAIL; + } + + return MV_OK; +} + +/******************************************************************************* +* twsi_addr7_bit_set - Set 7 Bit address on TWSI bus. +* +* DESCRIPTION: +* This function writes 7 bit address plus a write or read bit to the +* Data register. Then it clears interrupt flag which drive the address on +* the TWSI bus. The function then waits for interrupt flag to be active +* and status 0x18 (write) or 0x40 (read) to be set. +* +* INPUT: +* chan_num - TWSI channel +* device_address - twsi address. +* command - read / write . +* +* OUTPUT: +* None. +* +* RETURN: +* MV_OK - if setting the address completed successfully. +* MV_FAIL otherwmise. +* +*******************************************************************************/ +static int twsi_addr7_bit_set(uint8_t chan_num, + uint32_t device_address, + MV_TWSI_CMD command) +{ + uint32_t val, timeout; + + /* set the address */ + val = (device_address << TWSI_DATA_ADDR_7_BIT_OFFS) & + TWSI_DATA_ADDR_7_BIT_MASK; + /* set command */ + val |= command; + mrvl_reg_write(TWSI_DATA_REG(chan_num), val); + /* WA add a delay */ + mdelay(1); + + /* clear Int flag */ + twsi_int_flg_clr(chan_num); + + /* wait for Int to be Set */ + timeout = 0; + while (!twsi_main_int_get(chan_num) && (timeout++ < TWSI_TIMEOUT_VALUE)) + ; + + /* check for timeout */ + if (MV_TRUE == + twsi_timeout_chk( + timeout, (const char *)"TWSI: Addr (7 Bit) int time_out.\n")) + return MV_TIMEOUT; + + /* check the status */ + val = twsi_sts_get(chan_num); + if ((TWSI_M_LOST_ARB_DUR_AD_OR_DATA_TRA == val) || + (TWSI_M_LOST_ARB_DUR_AD_TRA_GNL_CALL_AD_REC_ACK_TRA == val)) { + DB(mv_os_printf("TWSI: Lost Arb, status %x\n", val)); + return MV_RETRY; + } else if (((val != TWSI_AD_PLS_RD_BIT_TRA_ACK_REC) && + (command == MV_TWSI_READ)) || + ((val != TWSI_AD_PLS_WR_BIT_TRA_ACK_REC) && + (command == MV_TWSI_WRITE))) { + /* only in debug, since in boot we try to read the SPD of both + DRAM, and we don't + want error messeges in case DIMM doesn't exist. */ + DB(mv_os_printf( + "TWSI: status %x addr (7 Bit) in %s mode.\n", val, + ((command == MV_TWSI_WRITE) ? "Write" : "Read"))); + return MV_FAIL; + } + + return MV_OK; +} + +/******************************************************************************* +* twsi_data_write - Trnasmit a data block over TWSI bus. +* +* DESCRIPTION: +* This function writes a given data block to TWSI bus in 8 bit +* granularity. +* first The function waits for interrupt flag to be active then +* For each 8-bit data: +* The function writes data to data register. It then clears +* interrupt flag which drives the data on the TWSI bus. +* The function then waits for interrupt flag to be active and status +* 0x28 to be set. +* +* +* INPUT: +* chan_num - TWSI channel +* p_block - Data block. +* block_size - number of chars in p_block. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_OK - if transmiting the block completed successfully, +* MV_BAD_PARAM - if p_block is NULL, +* MV_FAIL otherwmise. +* +*******************************************************************************/ +static int twsi_data_transmit(uint8_t chan_num, + uint8_t *p_block, + uint32_t block_size) +{ + uint32_t timeout, temp, block_size_wr = block_size; + + if (NULL == p_block) + return MV_BAD_PARAM; + + /* wait for Int to be Set */ + timeout = 0; + while (!twsi_main_int_get(chan_num) && (timeout++ < TWSI_TIMEOUT_VALUE)) + ; + + /* check for timeout */ + if (MV_TRUE == + twsi_timeout_chk(timeout, + (const char *)"TWSI: Read Data Int time_out.\n")) + return MV_TIMEOUT; + + while (block_size_wr) { + /* write the data */ + mrvl_reg_write(TWSI_DATA_REG(chan_num), (uint32_t)*p_block); + DB(mv_os_printf( + "TWSI: twsi_data_transmit place = %d write %x\n", + block_size - block_size_wr, *p_block)); + p_block++; + block_size_wr--; + + twsi_int_flg_clr(chan_num); + + /* wait for Int to be Set */ + timeout = 0; + while (!twsi_main_int_get(chan_num) && + (timeout++ < TWSI_TIMEOUT_VALUE)) + ; + + /* check for timeout */ + if (MV_TRUE == twsi_timeout_chk( + timeout, (const char *)"TWSI: time_out.\n")) + return MV_TIMEOUT; + + /* check the status */ + temp = twsi_sts_get(chan_num); + if ((TWSI_M_LOST_ARB_DUR_AD_OR_DATA_TRA == temp) || + (TWSI_M_LOST_ARB_DUR_AD_TRA_GNL_CALL_AD_REC_ACK_TRA == + temp)) { + DB(mv_os_printf("TWSI: Lost Arb, status %x\n", temp)); + return MV_RETRY; + } else if (temp != TWSI_M_TRAN_DATA_BYTE_ACK_REC) { + mv_os_printf("TWSI: status %x in write trans\n", temp); + return MV_FAIL; + } + } + + return MV_OK; +} + +/******************************************************************************* +* twsi_data_receive - Receive data block from TWSI bus. +* +* DESCRIPTION: +* This function receive data block from TWSI bus in 8bit granularity +* into p_block buffer. +* first The function waits for interrupt flag to be active then +* For each 8-bit data: +* It clears the interrupt flag which allows the next data to be +* received from TWSI bus. +* The function waits for interrupt flag to be active, +* and status reg is 0x50. +* Then the function reads data from data register, and copies it to +* the given buffer. +* +* INPUT: +* chan_num - TWSI channel +* block_size - number of bytes to read. +* +* OUTPUT: +* p_block - Data block. +* +* RETURN: +* MV_OK - if receive transaction completed successfully, +* MV_BAD_PARAM - if p_block is NULL, +* MV_FAIL otherwmise. +* +*******************************************************************************/ +static int twsi_data_receive(uint8_t chan_num, + uint8_t *p_block, + uint32_t block_size) +{ + uint32_t timeout, temp, block_size_rd = block_size; + + if (NULL == p_block) + return MV_BAD_PARAM; + + /* wait for Int to be Set */ + timeout = 0; + while (!twsi_main_int_get(chan_num) && (timeout++ < TWSI_TIMEOUT_VALUE)) + ; + + /* check for timeout */ + if (MV_TRUE == + twsi_timeout_chk(timeout, + (const char *)"TWSI: Read Data int Time out .\n")) + return MV_TIMEOUT; + + while (block_size_rd) { + if (block_size_rd == 1) + /* clear ack and Int flag */ + mrvl_reg_bit_reset( + TWSI_CONTROL_REG(chan_num), TWSI_CONTROL_ACK); + + twsi_int_flg_clr(chan_num); + /* wait for Int to be Set */ + timeout = 0; + while ((!twsi_main_int_get(chan_num)) && + (timeout++ < TWSI_TIMEOUT_VALUE)) + ; + + /* check for timeout */ + if (MV_TRUE == + twsi_timeout_chk(timeout, (const char *)"TWSI: Timeout.\n")) + return MV_TIMEOUT; + + /* check the status */ + temp = twsi_sts_get(chan_num); + if ((TWSI_M_LOST_ARB_DUR_AD_OR_DATA_TRA == temp) || + (TWSI_M_LOST_ARB_DUR_AD_TRA_GNL_CALL_AD_REC_ACK_TRA == + temp)) { + DB(mv_os_printf("TWSI: Lost Arb, status %x\n", temp)); + return MV_RETRY; + } else if ((temp != TWSI_M_REC_RD_DATA_ACK_TRA) && + (block_size_rd != 1)) { + mv_os_printf("TWSI: status %x in read trans\n", temp); + return MV_FAIL; + } else if ((temp != TWSI_M_REC_RD_DATA_ACK_NOT_TRA) && + (block_size_rd == 1)) { + mv_os_printf("TWSI: status %x in Rd Terminate\n", temp); + return MV_FAIL; + } + + /* read the data */ + *p_block = (uint8_t)mrvl_reg_read(TWSI_DATA_REG(chan_num)); + DB(mv_os_printf("TWSI: twsi_data_receive place %d read %x\n", + block_size - block_size_rd, *p_block)); + p_block++; + block_size_rd--; + } + + return MV_OK; +} + +/******************************************************************************* +* twsi_target_offs_set - Set TWST target offset on TWSI bus. +* +* DESCRIPTION: +* The function support TWSI targets that have inside address space (for +* example EEPROMs). The function: +* 1) Convert the given offset into p_block and size. +* in case the offset should be set to a TWSI slave which support +* more then 256 bytes offset, the offset setting will be done +* in 2 transactions. +* 2) Use twsi_data_transmit to place those on the bus. +* +* INPUT: +* chan_num - TWSI channel +* offset - offset to be set on the EEPROM device. +* more_than256 - whether the EEPROM device support more then 256 byte +*offset. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_OK - if setting the offset completed successfully. +* MV_FAIL otherwmise. +* +*******************************************************************************/ +static int twsi_target_offs_set(uint8_t chan_num, + uint32_t offset, + uint8_t more_than256) +{ + uint8_t off_block[2]; + uint32_t off_size; + + if (more_than256 == MV_TRUE) { + off_block[0] = (offset >> 8) & 0xff; + off_block[1] = offset & 0xff; + off_size = 2; + } else { + off_block[0] = offset & 0xff; + off_size = 1; + } + DB(mv_os_printf( + "TWSI: twsi_target_offs_set off_size = %x addr1 = %x addr2 = %x\n", + off_size, off_block[0], off_block[1])); + return twsi_data_transmit(chan_num, off_block, off_size); +} + +/******************************************************************************* +* mv_twsi_read - Read data block from a TWSI Slave. +* +* DESCRIPTION: +* The function calls the following functions: +* -) mv_twsi_start_bit_set(); +* if (EEPROM device) +* -) mv_twsi_addr_set(w); +* -) twsi_target_offs_set(); +* -) mv_twsi_start_bit_set(); +* -) mv_twsi_addr_set(r); +* -) twsi_data_receive(); +* -) mv_twsi_stop_bit_set(); +* +* INPUT: +* chan_num - TWSI channel +* p_twsi_slave - Twsi Slave structure. +* block_size - number of bytes to read. +* +* OUTPUT: +* p_block - Data block. +* +* RETURN: +* MV_OK - if EEPROM read transaction completed successfully, +* MV_BAD_PARAM - if p_block is NULL, +* MV_FAIL otherwmise. +* +*******************************************************************************/ +static int mv_twsi_read(uint8_t chan_num, + MV_TWSI_SLAVE *p_twsi_slave, + uint8_t *p_block, + uint32_t block_size) +{ + int rc; + int ret = MV_FAIL; + uint32_t counter = 0; + + if ((NULL == p_block) || (NULL == p_twsi_slave)) + return MV_BAD_PARAM; + + do { + /* wait for 1 mili sec for the clear to take effect */ + if (counter > 0) + mdelay(1); + ret = mv_twsi_start_bit_set(chan_num); + + if (MV_RETRY == ret) + continue; + else if (MV_OK != ret) { + mv_twsi_stop_bit_set(chan_num); + DB(mv_os_printf( + "mv_twsi_read:mv_twsi_start_bit_set failed\n")); + return MV_FAIL; + } + + DB(mv_os_printf( + "TWSI: mv_twsi_eeprom_read after mv_twsi_start_bit_set\n")); + + /* in case offset exsist (i.e. eeprom ) */ + if (MV_TRUE == p_twsi_slave->valid_offset) { + rc = mv_twsi_addr_set(chan_num, + &(p_twsi_slave->slave_addr), + MV_TWSI_WRITE); + if (MV_RETRY == rc) + continue; + else if (MV_OK != rc) { + mv_twsi_stop_bit_set(chan_num); + DB(mv_os_printf( + "mv_twsi_addr_set(%d,0x%x,%d) rc=%d\n", + chan_num, + (uint32_t) &(p_twsi_slave->slave_addr), + MV_TWSI_WRITE, rc)); + return MV_FAIL; + } + + ret = + twsi_target_offs_set(chan_num, p_twsi_slave->offset, + p_twsi_slave->more_than256); + if (MV_RETRY == ret) + continue; + else if (MV_OK != ret) { + mv_twsi_stop_bit_set(chan_num); + DB(mv_os_printf( + "TWSI: twsi_target_offs_set Failed\n")); + return MV_FAIL; + } + DB(mv_os_printf("TWSI: after twsi_target_offs_set\n")); + ret = mv_twsi_start_bit_set(chan_num); + if (MV_RETRY == ret) + continue; + else if (MV_OK != ret) { + mv_twsi_stop_bit_set(chan_num); + DB(mv_os_printf( + "TWSI: mv_twsi_start_bit_set failed\n")); + return MV_FAIL; + } + DB(mv_os_printf("TWSI: after mv_twsi_start_bit_set\n")); + } + ret = mv_twsi_addr_set(chan_num, &(p_twsi_slave->slave_addr), + MV_TWSI_READ); + if (MV_RETRY == ret) + continue; + else if (MV_OK != ret) { + mv_twsi_stop_bit_set(chan_num); + DB(mv_os_printf( + "mv_twsi_read: mv_twsi_addr_set 2 Failed\n")); + return MV_FAIL; + } + DB(mv_os_printf( + "TWSI: mv_twsi_eeprom_read after mv_twsi_addr_set\n")); + + ret = twsi_data_receive(chan_num, p_block, block_size); + if (MV_RETRY == ret) + continue; + else if (MV_OK != ret) { + mv_twsi_stop_bit_set(chan_num); + DB(mv_os_printf( + "mv_twsi_read: twsi_data_receive Failed\n")); + return MV_FAIL; + } + DB(mv_os_printf( + "TWSI: mv_twsi_eeprom_read after twsi_data_receive\n")); + + ret = mv_twsi_stop_bit_set(chan_num); + if (MV_RETRY == ret) + continue; + else if (MV_OK != ret) { + DB(mv_os_printf( + "mv_twsi_read: mv_twsi_stop_bit_set 3 Failed\n")); + return MV_FAIL; + } + counter++; + } while ((MV_RETRY == ret) && (counter < MAX_RETRY_CNT)); + + if (counter == MAX_RETRY_CNT) + DB(mv_os_printf("mv_twsi_write: Retry Expire\n")); + + twsi_ack_bit_set(chan_num); + + DB(mv_os_printf( + "TWSI: mv_twsi_eeprom_read after mv_twsi_stop_bit_set\n")); + + return MV_OK; +} + +/******************************************************************************* +* mv_twsi_write - Write data block to a TWSI Slave. +* +* DESCRIPTION: +* The function calls the following functions: +* -) mv_twsi_start_bit_set(); +* -) mv_twsi_addr_set(); +* -)if (EEPROM device) +* -) twsi_target_offs_set(); +* -) twsi_data_transmit(); +* -) mv_twsi_stop_bit_set(); +* +* INPUT: +* chan_num - TWSI channel +* eeprom_address - eeprom address. +* block_size - number of bytes to write. +* p_block - Data block. +* +* OUTPUT: +* None +* +* RETURN: +* MV_OK - if EEPROM read transaction completed successfully. +* MV_BAD_PARAM - if p_block is NULL, +* MV_FAIL otherwmise. +* +* NOTE: Part of the EEPROM, required that the offset will be aligned to the +* max write burst supported. +*******************************************************************************/ +static int mv_twsi_write(uint8_t chan_num, + MV_TWSI_SLAVE *p_twsi_slave, + uint8_t *p_block, + uint32_t block_size) +{ + int ret = MV_FAIL; + uint32_t counter = 0; + + if ((NULL == p_block) || (NULL == p_twsi_slave)) + return MV_BAD_PARAM; + + do { + if (counter > + 0) /* wait for 1 mili sec for the clear to take effect */ + mdelay(1); + ret = mv_twsi_start_bit_set(chan_num); + + if (MV_RETRY == ret) + continue; + + else if (MV_OK != ret) { + mv_twsi_stop_bit_set(chan_num); + DB(mv_os_printf( + "mv_twsi_write: mv_twsi_start_bit_set failed\n")); + return MV_FAIL; + } + + ret = mv_twsi_addr_set(chan_num, &(p_twsi_slave->slave_addr), + MV_TWSI_WRITE); + if (MV_RETRY == ret) + continue; + else if (MV_OK != ret) { + mv_twsi_stop_bit_set(chan_num); + DB(mv_os_printf( + "mv_twsi_write: mv_twsi_addr_set failed\n")); + return MV_FAIL; + } + + /* in case offset exsist (i.e. eeprom ) */ + if (MV_TRUE == p_twsi_slave->valid_offset) { + ret = + twsi_target_offs_set(chan_num, p_twsi_slave->offset, + p_twsi_slave->more_than256); + if (MV_RETRY == ret) + continue; + else if (MV_OK != ret) { + mv_twsi_stop_bit_set(chan_num); + DB(mv_os_printf( + "TWSI: twsi_target_offs_set failed\n")); + return MV_FAIL; + } + } + + ret = twsi_data_transmit(chan_num, p_block, block_size); + if (MV_RETRY == ret) + continue; + else if (MV_OK != ret) { + mv_twsi_stop_bit_set(chan_num); + DB(mv_os_printf( + "mv_twsi_write: twsi_data_transmit failed\n")); + return MV_FAIL; + } + ret = mv_twsi_stop_bit_set(chan_num); + if (MV_RETRY == ret) + continue; + else if (MV_OK != ret) { + DB(mv_os_printf( + "mv_twsi_write: failed to set stopbit\n")); + return MV_FAIL; + } + counter++; + } while ((MV_RETRY == ret) && (counter < MAX_RETRY_CNT)); + + if (counter == MAX_RETRY_CNT) + DB(mv_os_printf("mv_twsi_write: Retry Expire\n")); + + return MV_OK; +} + +static int i2c_init(unsigned bus) +{ + if (bus >= MAX_I2C_NUM) + return 1; + + if (!m_initialized[bus]) { + /* TWSI init */ + MV_TWSI_ADDR slave; + + slave.type = ADDR7_BIT; + slave.address = 0; + mv_twsi_init(bus, TWSI_SPEED, mv_tclk_get(), &slave, 0); + m_initialized[bus] = 1; + } + + return 0; +} + +static void i2c_reset(unsigned bus) +{ + if (bus < MAX_I2C_NUM) + m_initialized[bus] = 0; +} + +int platform_i2c_transfer(unsigned bus, struct i2c_seg *segments, int seg_count) +{ + struct i2c_seg *seg = segments; + int ret = 0; + MV_TWSI_SLAVE twsi_slave; + + if (i2c_init(bus)) + return 1; + + while (!ret && seg_count--) { + twsi_slave.slave_addr.address = seg->chip; + twsi_slave.slave_addr.type = ADDR7_BIT; + twsi_slave.more_than256 = MV_FALSE; + twsi_slave.valid_offset = MV_FALSE; + if (seg->read) + ret = + mv_twsi_read(bus, &twsi_slave, seg->buf, seg->len); + else + ret = + mv_twsi_write(bus, &twsi_slave, seg->buf, seg->len); + seg++; + } + + if (ret) { + i2c_reset(bus); + DB(mv_os_printf("mv_twsi_read/mv_twsi_write failed\n")); + return 1; + } + + return 0; +} diff --git a/src/soc/marvell/armada38x/include/soc/clock.h b/src/soc/marvell/armada38x/include/soc/clock.h new file mode 100644 index 0000000000..82af93724b --- /dev/null +++ b/src/soc/marvell/armada38x/include/soc/clock.h @@ -0,0 +1,21 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2015 Google 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. + */ + +#ifndef __SOC_MARVELL_ARMADA38X_CLOCK_H_ +#define __SOC_MARVELL_ARMADA38X_CLOCK_H_ + +uint32_t mv_tclk_get(void); + +#endif // __SOC_MARVELL_ARMADA38X_CLOCK_H_ diff --git a/src/soc/marvell/armada38x/include/soc/i2c.h b/src/soc/marvell/armada38x/include/soc/i2c.h new file mode 100644 index 0000000000..7de29534b6 --- /dev/null +++ b/src/soc/marvell/armada38x/include/soc/i2c.h @@ -0,0 +1,120 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2015 Marvell 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. + */ + +#ifndef __SOC_MARVELL_ARMADA38X_I2C_H_ +#define __SOC_MARVELL_ARMADA38X_I2C_H_ + +#include <types.h> + +#define TWSI_SPEED 100000 + +#define MAX_I2C_NUM 2 +#define MAX_RETRY_CNT 1000 +#define TWSI_TIMEOUT_VALUE 0x500 + +#define MV_TWSI_SLAVE_REGS_OFFSET(chan_num) (0x11000 + (chan_num * 0x100)) +#define MV_TWSI_SLAVE_REGS_BASE(unit) (MV_TWSI_SLAVE_REGS_OFFSET(unit)) +#define TWSI_SLAVE_ADDR_REG(chan_num) (MV_TWSI_SLAVE_REGS_BASE(chan_num) + 0x00) + +#define MV_CPUIF_REGS_OFFSET(cpu) (0x21800 + (cpu)*0x100) +#define MV_CPUIF_REGS_BASE(cpu) (MV_CPUIF_REGS_OFFSET(cpu)) +#define CPU_MAIN_INT_CAUSE_REG(vec, cpu) \ + (MV_CPUIF_REGS_BASE(cpu) + 0x80 + (vec * 0x4)) +#define CPU_MAIN_INT_TWSI_OFFS(i) (2 + i) +#define CPU_MAIN_INT_CAUSE_TWSI(i) (31 + i) +#define TWSI_CPU_MAIN_INT_CAUSE_REG(cpu) CPU_MAIN_INT_CAUSE_REG(1, (cpu)) +#define MV_TWSI_CPU_MAIN_INT_CAUSE(ch_num, cpu) TWSI_CPU_MAIN_INT_CAUSE_REG(cpu) + +#define MV_MBUS_REGS_OFFSET (0x20000) +#define MV_CPUIF_SHARED_REGS_BASE (MV_MBUS_REGS_OFFSET) +#define CPU_INT_SOURCE_CONTROL_REG(i) \ + (MV_CPUIF_SHARED_REGS_BASE + 0xB00 + (i * 0x4)) + +#define CPU_INT_SOURCE_CONTROL_IRQ_OFFS 28 +#define CPU_INT_SOURCE_CONTROL_IRQ_MASK (1 << CPU_INT_SOURCE_CONTROL_IRQ_OFFS) + +#define TWSI_SLAVE_ADDR_GCE_ENA BIT(0) +#define TWSI_SLAVE_ADDR_7_BIT_OFFS 0x1 +#define TWSI_SLAVE_ADDR_7_BIT_MASK (0xFF << TWSI_SLAVE_ADDR_7_BIT_OFFS) +#define TWSI_SLAVE_ADDR_10_BIT_OFFS 0x7 +#define TWSI_SLAVE_ADDR_10_BIT_MASK 0x300 +#define TWSI_SLAVE_ADDR_10_BIT_CONST 0xF0 + +#define TWSI_DATA_REG(chan_num) (MV_TWSI_SLAVE_REGS_BASE(chan_num) + 0x04) +#define TWSI_DATA_COMMAND_OFFS 0x0 +#define TWSI_DATA_COMMAND_MASK (0x1 << TWSI_DATA_COMMAND_OFFS) +#define TWSI_DATA_COMMAND_WR (0x1 << TWSI_DATA_COMMAND_OFFS) +#define TWSI_DATA_COMMAND_RD (0x0 << TWSI_DATA_COMMAND_OFFS) +#define TWSI_DATA_ADDR_7_BIT_OFFS 0x1 +#define TWSI_DATA_ADDR_7_BIT_MASK (0xFF << TWSI_DATA_ADDR_7_BIT_OFFS) +#define TWSI_DATA_ADDR_10_BIT_OFFS 0x7 +#define TWSI_DATA_ADDR_10_BIT_MASK 0x300 +#define TWSI_DATA_ADDR_10_BIT_CONST 0xF0 + +#define TWSI_CONTROL_REG(chan_num) (MV_TWSI_SLAVE_REGS_BASE(chan_num) + 0x08) +#define TWSI_CONTROL_ACK BIT(2) +#define TWSI_CONTROL_INT_FLAG_SET BIT(3) +#define TWSI_CONTROL_STOP_BIT BIT(4) +#define TWSI_CONTROL_START_BIT BIT(5) +#define TWSI_CONTROL_ENA BIT(6) +#define TWSI_CONTROL_INT_ENA BIT(7) + +#define TWSI_STATUS_BAUDE_RATE_REG(chan_num) \ + (MV_TWSI_SLAVE_REGS_BASE(chan_num) + 0x0c) +#define TWSI_BAUD_RATE_N_OFFS 0 +#define TWSI_BAUD_RATE_N_MASK (0x7 << TWSI_BAUD_RATE_N_OFFS) +#define TWSI_BAUD_RATE_M_OFFS 3 +#define TWSI_BAUD_RATE_M_MASK (0xF << TWSI_BAUD_RATE_M_OFFS) + +#define TWSI_EXTENDED_SLAVE_ADDR_REG(chan_num) \ + (MV_TWSI_SLAVE_REGS_BASE(chan_num) + 0x10) +#define TWSI_EXTENDED_SLAVE_OFFS 0 +#define TWSI_EXTENDED_SLAVE_MASK (0xFF << TWSI_EXTENDED_SLAVE_OFFS) + +#define TWSI_SOFT_RESET_REG(chan_num) (MV_TWSI_SLAVE_REGS_BASE(chan_num) + 0x1c) + +#define TWSI_BUS_ERROR 0x00 +#define TWSI_START_CON_TRA 0x08 +#define TWSI_REPEATED_START_CON_TRA 0x10 +#define TWSI_AD_PLS_WR_BIT_TRA_ACK_REC 0x18 +#define TWSI_AD_PLS_WR_BIT_TRA_ACK_NOT_REC 0x20 +#define TWSI_M_TRAN_DATA_BYTE_ACK_REC 0x28 +#define TWSI_M_TRAN_DATA_BYTE_ACK_NOT_REC 0x30 +#define TWSI_M_LOST_ARB_DUR_AD_OR_DATA_TRA 0x38 +#define TWSI_AD_PLS_RD_BIT_TRA_ACK_REC 0x40 +#define TWSI_AD_PLS_RD_BIT_TRA_ACK_NOT_REC 0x48 +#define TWSI_M_REC_RD_DATA_ACK_TRA 0x50 +#define TWSI_M_REC_RD_DATA_ACK_NOT_TRA 0x58 +#define TWSI_SLA_REC_AD_PLS_WR_BIT_ACK_TRA 0x60 +#define TWSI_M_LOST_ARB_DUR_AD_TRA_AD_IS_TRGT_TO_SLA_ACK_TRA_W 0x68 +#define TWSI_GNL_CALL_REC_ACK_TRA 0x70 +#define TWSI_M_LOST_ARB_DUR_AD_TRA_GNL_CALL_AD_REC_ACK_TRA 0x78 +#define TWSI_SLA_REC_WR_DATA_AF_REC_SLA_AD_ACK_TRAN 0x80 +#define TWSI_SLA_REC_WR_DATA_AF_REC_SLA_AD_ACK_NOT_TRAN 0x88 +#define TWSI_SLA_REC_WR_DATA_AF_REC_GNL_CALL_ACK_TRAN 0x90 +#define TWSI_SLA_REC_WR_DATA_AF_REC_GNL_CALL_ACK_NOT_TRAN 0x98 +#define TWSI_SLA_REC_STOP_OR_REPEATED_STRT_CON 0xA0 +#define TWSI_SLA_REC_AD_PLS_RD_BIT_ACK_TRA 0xA8 +#define TWSI_M_LOST_ARB_DUR_AD_TRA_AD_IS_TRGT_TO_SLA_ACK_TRA_R 0xB0 +#define TWSI_SLA_TRA_RD_DATA_ACK_REC 0xB8 +#define TWSI_SLA_TRA_RD_DATA_ACK_NOT_REC 0xC0 +#define TWSI_SLA_TRA_LAST_RD_DATA_ACK_REC 0xC8 +#define TWSI_SEC_AD_PLS_WR_BIT_TRA_ACK_REC 0xD0 +#define TWSI_SEC_AD_PLS_WR_BIT_TRA_ACK_NOT_REC 0xD8 +#define TWSI_SEC_AD_PLS_RD_BIT_TRA_ACK_REC 0xE0 +#define TWSI_SEC_AD_PLS_RD_BIT_TRA_ACK_NOT_REC 0xE8 +#define TWSI_NO_REL_STS_INT_FLAG_IS_KEPT_0 0xF8 + +#endif // __SOC_MARVELL_ARMADA38X_I2C_H__ diff --git a/src/soc/marvell/armada38x/spi.c b/src/soc/marvell/armada38x/spi.c index ed5d519dd0..6a0e062327 100644 --- a/src/soc/marvell/armada38x/spi.c +++ b/src/soc/marvell/armada38x/spi.c @@ -21,6 +21,7 @@ #include <assert.h> #include <console/console.h> #include <soc/common.h> +#include <soc/clock.h> /****************************************************************************** base type define @@ -352,7 +353,7 @@ int mv_spi_sys_init(unsigned char spi_id, MV_SPI_HAL_DATA hal_data; hal_data.ctrl_model = MV_6810_DEV_ID; - hal_data.tclk = MV_BOARD_TCLK_250MHZ; + hal_data.tclk = mv_tclk_get(); return mv_spi_init(spi_id, cs_id, serial_baud_rate, &hal_data); } diff --git a/src/soc/marvell/armada38x/uart.c b/src/soc/marvell/armada38x/uart.c index e535aebf67..dbd8dca78f 100644 --- a/src/soc/marvell/armada38x/uart.c +++ b/src/soc/marvell/armada38x/uart.c @@ -21,6 +21,7 @@ #include <stdint.h> #include <assert.h> #include <soc/common.h> +#include <soc/clock.h> struct armada38x_uart { union { @@ -94,7 +95,7 @@ static int armada38x_uart_tst_byte(struct armada38x_uart *uart_ptr) unsigned int uart_platform_refclk(void) { - return MV_BOARD_TCLK_250MHZ; + return mv_tclk_get(); } uintptr_t uart_platform_base(int idx) |