2015-01-18 23:37:11 +01:00
|
|
|
/*
|
|
|
|
* This file is part of the coreboot project.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2014 Imagination Technologies
|
|
|
|
*
|
|
|
|
* 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 <stdint.h>
|
|
|
|
#include <soc/clocks.h>
|
2015-01-30 18:05:15 +01:00
|
|
|
#include <assert.h>
|
2015-03-09 16:31:38 +01:00
|
|
|
#include <boardid.h>
|
2015-01-18 23:37:11 +01:00
|
|
|
|
2015-02-17 19:45:28 +01:00
|
|
|
#define PADS_FUNCTION_SELECT0_ADDR (0xB8101C00 + 0xC0)
|
|
|
|
|
2015-01-18 23:37:11 +01:00
|
|
|
#define GPIO_BIT_EN_ADDR(bank) (0xB8101C00 + 0x200 + (0x24 * (bank)))
|
2015-01-30 18:05:15 +01:00
|
|
|
#define PAD_DRIVE_STRENGTH_ADDR(bank) (0xB8101C00 + 0x120 + (0x4 * (bank)))
|
|
|
|
#define MAX_NO_MFIOS 89
|
|
|
|
#define PAD_DRIVE_STRENGTH_LENGTH 2
|
|
|
|
#define PAD_DRIVE_STRENGTH_MASK 0x3
|
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
DRIVE_STRENGTH_2mA = 0,
|
|
|
|
DRIVE_STRENGTH_4mA = 1,
|
|
|
|
DRIVE_STRENGTH_8mA = 2,
|
|
|
|
DRIVE_STRENGTH_12mA = 3
|
|
|
|
} drive_strength;
|
2015-01-18 23:37:11 +01:00
|
|
|
|
2015-02-17 19:45:28 +01:00
|
|
|
/* MFIO definitions for UART1 */
|
2015-01-18 23:37:11 +01:00
|
|
|
#define UART1_RXD_MFIO 59
|
|
|
|
#define UART1_TXD_MFIO 60
|
|
|
|
|
|
|
|
/* MFIO definitions for SPIM */
|
|
|
|
#define SPIM1_D0_TXD_MFIO 5
|
|
|
|
#define SPIM1_D1_RXD_MFIO 4
|
|
|
|
#define SPIM1_MCLK_MFIO 3
|
|
|
|
#define SPIM1_D2_MFIO 6
|
|
|
|
#define SPIM1_D3_MFIO 7
|
|
|
|
#define SPIM1_CS0_MFIO 0
|
|
|
|
|
2015-03-05 15:13:54 +01:00
|
|
|
/* MFIO definitions for I2C */
|
|
|
|
#define I2C_DATA_MFIO(i) (28 + (2*(i)))
|
|
|
|
#define I2C_CLK_MFIO(i) (29 + (2*(i)))
|
|
|
|
#define I2C_DATA_FUNCTION_OFFSET(i) (20 + (2*(i)))
|
|
|
|
#define I2C_CLK_FUNCTION_OFFSET(i) (21 + (2*(i)))
|
|
|
|
#define I2C_DATA_FUNCTION_MASK 0x1
|
|
|
|
#define I2C_CLK_FUNCTION_MASK 0x1
|
2015-02-17 19:45:28 +01:00
|
|
|
|
2015-01-30 18:05:15 +01:00
|
|
|
static void pad_drive_strength(u32 pad, drive_strength strength)
|
|
|
|
{
|
|
|
|
u32 reg, drive_strength_shift;
|
|
|
|
|
|
|
|
assert(pad <= MAX_NO_MFIOS);
|
|
|
|
assert(!(strength & ~(PAD_DRIVE_STRENGTH_MASK)));
|
|
|
|
|
|
|
|
/* Set drive strength value */
|
|
|
|
drive_strength_shift = (pad % 16) * PAD_DRIVE_STRENGTH_LENGTH;
|
|
|
|
reg = read32(PAD_DRIVE_STRENGTH_ADDR(pad / 16));
|
|
|
|
reg &= ~(PAD_DRIVE_STRENGTH_MASK << drive_strength_shift);
|
|
|
|
reg |= strength << drive_strength_shift;
|
|
|
|
write32(PAD_DRIVE_STRENGTH_ADDR(pad / 16), reg);
|
|
|
|
}
|
|
|
|
|
2015-01-18 23:37:11 +01:00
|
|
|
static void uart1_mfio_setup(void)
|
|
|
|
{
|
|
|
|
u32 reg, mfio_mask;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Disable GPIO for UART1 MFIOs
|
|
|
|
* All UART MFIOs have MFIO/16 = 3, therefore we use GPIO pad 3
|
2015-02-17 19:45:28 +01:00
|
|
|
* This is the only function (0) of these MFIOs and therfore there
|
2015-01-18 23:37:11 +01:00
|
|
|
* is no need to set up a function number in the corresponding
|
|
|
|
* function select register.
|
|
|
|
*/
|
|
|
|
reg = read32(GPIO_BIT_EN_ADDR(3));
|
|
|
|
mfio_mask = 1 << (UART1_RXD_MFIO % 16);
|
|
|
|
mfio_mask |= 1 << (UART1_TXD_MFIO % 16);
|
|
|
|
/* Clear relevant bits */
|
|
|
|
reg &= ~mfio_mask;
|
|
|
|
/*
|
|
|
|
* Set corresponding bits in the upper half word
|
|
|
|
* in order to be able to modify the chosen pins
|
|
|
|
*/
|
|
|
|
reg |= mfio_mask << 16;
|
|
|
|
write32(GPIO_BIT_EN_ADDR(3), reg);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void spim1_mfio_setup(void)
|
|
|
|
{
|
|
|
|
u32 reg, mfio_mask;
|
|
|
|
/*
|
|
|
|
* Disable GPIO for SPIM1 MFIOs
|
|
|
|
* All SPFI1 MFIOs have MFIO/16 = 0, therefore we use GPIO pad 0
|
2015-02-17 19:45:28 +01:00
|
|
|
* This is the only function (0) of these MFIOs and therfore there
|
2015-01-18 23:37:11 +01:00
|
|
|
* is no need to set up a function number in the corresponding
|
|
|
|
* function select register.
|
|
|
|
*/
|
|
|
|
reg = read32(GPIO_BIT_EN_ADDR(0));
|
|
|
|
|
2015-02-17 19:45:28 +01:00
|
|
|
/* Disable GPIO for SPIM1 MFIOs */
|
2015-01-18 23:37:11 +01:00
|
|
|
mfio_mask = 1 << (SPIM1_D0_TXD_MFIO % 16);
|
|
|
|
mfio_mask |= 1 << (SPIM1_D1_RXD_MFIO % 16);
|
|
|
|
mfio_mask |= 1 << (SPIM1_MCLK_MFIO % 16);
|
|
|
|
mfio_mask |= 1 << (SPIM1_D2_MFIO % 16);
|
|
|
|
mfio_mask |= 1 << (SPIM1_D3_MFIO % 16);
|
|
|
|
mfio_mask |= 1 << (SPIM1_CS0_MFIO % 16);
|
|
|
|
|
|
|
|
/* Clear relevant bits */
|
|
|
|
reg &= ~mfio_mask;
|
|
|
|
/*
|
|
|
|
* Set corresponding bits in the upper half word
|
|
|
|
* in order to be able to modify the chosen pins
|
|
|
|
*/
|
|
|
|
reg |= mfio_mask << 16;
|
|
|
|
write32(GPIO_BIT_EN_ADDR(0), reg);
|
2015-01-30 18:05:15 +01:00
|
|
|
|
|
|
|
/* Set drive strength to maximum for these MFIOs */
|
|
|
|
pad_drive_strength(SPIM1_CS0_MFIO, DRIVE_STRENGTH_12mA);
|
|
|
|
pad_drive_strength(SPIM1_D1_RXD_MFIO, DRIVE_STRENGTH_12mA);
|
|
|
|
pad_drive_strength(SPIM1_D0_TXD_MFIO, DRIVE_STRENGTH_12mA);
|
|
|
|
pad_drive_strength(SPIM1_D2_MFIO, DRIVE_STRENGTH_12mA);
|
|
|
|
pad_drive_strength(SPIM1_D3_MFIO, DRIVE_STRENGTH_12mA);
|
|
|
|
pad_drive_strength(SPIM1_MCLK_MFIO, DRIVE_STRENGTH_12mA);
|
2015-01-18 23:37:11 +01:00
|
|
|
}
|
|
|
|
|
2015-03-05 15:13:54 +01:00
|
|
|
static void i2c_mfio_setup(int interface)
|
2015-02-17 19:45:28 +01:00
|
|
|
{
|
|
|
|
u32 reg, mfio_mask;
|
|
|
|
|
2015-03-05 15:13:54 +01:00
|
|
|
assert(interface < 4);
|
2015-02-17 19:45:28 +01:00
|
|
|
/*
|
2015-03-05 15:13:54 +01:00
|
|
|
* Disable GPIO for I2C MFIOs
|
2015-02-17 19:45:28 +01:00
|
|
|
*/
|
2015-03-05 15:13:54 +01:00
|
|
|
reg = read32(GPIO_BIT_EN_ADDR(I2C_DATA_MFIO(interface) / 16));
|
|
|
|
mfio_mask = 1 << (I2C_DATA_MFIO(interface) % 16);
|
|
|
|
mfio_mask |= 1 << (I2C_CLK_MFIO(interface) % 16);
|
2015-02-17 19:45:28 +01:00
|
|
|
/* Clear relevant bits */
|
|
|
|
reg &= ~mfio_mask;
|
|
|
|
/*
|
|
|
|
* Set corresponding bits in the upper half word
|
|
|
|
* in order to be able to modify the chosen pins
|
|
|
|
*/
|
|
|
|
reg |= mfio_mask << 16;
|
2015-03-05 15:13:54 +01:00
|
|
|
write32(GPIO_BIT_EN_ADDR(I2C_DATA_MFIO(interface) / 16), reg);
|
2015-02-17 19:45:28 +01:00
|
|
|
|
2015-03-05 15:13:54 +01:00
|
|
|
/* for I2C0 and I2C1:
|
|
|
|
* Set bits to 0 (clear) which is the primary function
|
2015-02-17 19:45:28 +01:00
|
|
|
* for these MFIOs; those bits will all be set to 1 by
|
2015-03-05 15:13:54 +01:00
|
|
|
* default.
|
|
|
|
* There is no need to do that for I2C2 and I2C3
|
2015-02-17 19:45:28 +01:00
|
|
|
*/
|
2015-03-05 15:13:54 +01:00
|
|
|
if (interface > 1)
|
|
|
|
return;
|
2015-02-17 19:45:28 +01:00
|
|
|
reg = read32(PADS_FUNCTION_SELECT0_ADDR);
|
2015-03-05 15:13:54 +01:00
|
|
|
reg &= ~(I2C_DATA_FUNCTION_MASK <<
|
|
|
|
I2C_DATA_FUNCTION_OFFSET(interface));
|
|
|
|
reg &= ~(I2C_CLK_FUNCTION_MASK <<
|
|
|
|
I2C_CLK_FUNCTION_OFFSET(interface));
|
2015-02-17 19:45:28 +01:00
|
|
|
write32(PADS_FUNCTION_SELECT0_ADDR, reg);
|
|
|
|
}
|
|
|
|
|
2015-03-09 16:31:38 +01:00
|
|
|
static void bootblock_mainboard_init(void)
|
2015-01-18 23:37:11 +01:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2015-07-15 13:10:05 +02:00
|
|
|
/* System PLL divided by 2 -> 350 MHz */
|
2015-01-18 23:37:11 +01:00
|
|
|
/* The same frequency will be the input frequency for the SPFI block */
|
|
|
|
system_clk_setup(1);
|
2015-01-26 14:15:12 +01:00
|
|
|
|
2015-02-03 01:26:08 +01:00
|
|
|
/* MIPS CPU dividers: division by 1 -> 546 MHz
|
2015-01-26 14:15:12 +01:00
|
|
|
* This is set up as we cannot make any assumption about
|
|
|
|
* the values set or not by the boot ROM code */
|
|
|
|
mips_clk_setup(0, 0);
|
|
|
|
|
2015-07-15 13:10:05 +02:00
|
|
|
/* Setup system PLL at 700 MHz */
|
|
|
|
ret = sys_pll_setup(2, 1, 13, 350);
|
2015-01-18 23:37:11 +01:00
|
|
|
if (ret != CLOCKS_OK)
|
2015-03-09 16:31:38 +01:00
|
|
|
return;
|
2015-02-03 01:26:08 +01:00
|
|
|
/* Setup MIPS PLL at 546 MHz */
|
|
|
|
ret = mips_pll_setup(2, 1, 1, 21);
|
2015-01-18 23:37:11 +01:00
|
|
|
if (ret != CLOCKS_OK)
|
2015-03-09 16:31:38 +01:00
|
|
|
return;
|
|
|
|
|
2015-11-01 20:55:48 +01:00
|
|
|
/*
|
|
|
|
* Move peripheral clock control from RPU to MIPS.
|
|
|
|
* The RPU gate register is not managed in Linux so disable its default
|
|
|
|
* values and assign MIPS gate register the default values.
|
|
|
|
* *Note*: All unused clocks will be gated by Linux
|
|
|
|
*/
|
|
|
|
setup_clk_gate_defaults();
|
|
|
|
|
2015-03-09 16:31:38 +01:00
|
|
|
/* Setup SPIM1 MFIOs */
|
|
|
|
spim1_mfio_setup();
|
|
|
|
/* Setup UART1 clock and MFIOs
|
2015-07-15 13:10:05 +02:00
|
|
|
* System PLL divided by 5 divided by 76 -> 1.8421 Mhz
|
2015-03-09 16:31:38 +01:00
|
|
|
*/
|
2015-07-15 13:10:05 +02:00
|
|
|
uart1_clk_setup(4, 75);
|
2015-03-09 16:31:38 +01:00
|
|
|
uart1_mfio_setup();
|
2015-01-18 23:37:11 +01:00
|
|
|
}
|
|
|
|
|
2015-03-09 16:31:38 +01:00
|
|
|
|
|
|
|
static int init_extra_hardware(void)
|
2015-01-18 23:37:11 +01:00
|
|
|
{
|
2015-03-09 16:31:38 +01:00
|
|
|
const struct board_hw *hardware;
|
|
|
|
|
|
|
|
/* Obtain information about current board */
|
|
|
|
hardware = board_get_hw();
|
|
|
|
if (!hardware) {
|
|
|
|
printk(BIOS_ERR, "%s: Invalid hardware information.\n",
|
|
|
|
__func__);
|
|
|
|
return -1;
|
2015-01-18 23:37:11 +01:00
|
|
|
}
|
2015-03-09 16:31:38 +01:00
|
|
|
|
|
|
|
/* Setup USB clock
|
2015-07-15 13:10:05 +02:00
|
|
|
* System clock divided by 7 -> 50 MHz
|
2015-03-09 16:31:38 +01:00
|
|
|
*/
|
2015-07-15 13:10:05 +02:00
|
|
|
if (usb_clk_setup(6, 2, 7) != CLOCKS_OK) {
|
2015-03-09 16:31:38 +01:00
|
|
|
printk(BIOS_ERR, "%s: Failed to set up USB clock.\n",
|
|
|
|
__func__);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Setup I2C clocks and MFIOs
|
2015-07-15 13:10:05 +02:00
|
|
|
* System clock divided by 4 divided by 3 -> 29.1(6) MHz
|
2015-03-09 16:31:38 +01:00
|
|
|
*/
|
|
|
|
i2c_clk_setup(3, 2, hardware->i2c_interface);
|
|
|
|
i2c_mfio_setup(hardware->i2c_interface);
|
|
|
|
|
|
|
|
/* Ethernet clocks setup: ENET as clock source */
|
2015-07-15 13:10:05 +02:00
|
|
|
eth_clk_setup(0, 6);
|
|
|
|
/* ROM clock setup: system clock divided by 2 -> 175 MHz */
|
2015-03-09 16:31:38 +01:00
|
|
|
/* Hash accelerator is driven from the ROM clock */
|
|
|
|
rom_clk_setup(1);
|
|
|
|
|
|
|
|
return 0;
|
2015-01-18 23:37:11 +01:00
|
|
|
}
|