urara: Configure clocks and MFIOs

Set elements:
	- UART1 clock dividers and MFIOs
	- SPIM1 clock dividers and MFIOs
	- USB clock dividers
	- System clock divider
	- System PLL
	- MIPS CPU PLL

BUG=chrome-os-partner:31438
TEST=tested on Pisachio bring up board; UART, SPI NOR, SPI NAND, and USB
have proper functionality.
BRANCH=none

Change-Id: Ib01186a652fd59295a4cafc3ca99b94aa9564f74
Signed-off-by: Stefan Reinauer <reinauer@chromium.org>
Original-Commit-Id: 65e68d82f34bb40ef3cfb397ecf5df0c83201151
Original-Change-Id: Ia2c31bbbfc020dc4fd71c72b877414adfdfc42a8
Original-Signed-off-by: Ionela Voinescu <ionela.voinescu@imgtec.com>
Original-Reviewed-on: https://chromium-review.googlesource.com/241423
Original-Reviewed-by: David Hendricks <dhendrix@chromium.org>
Reviewed-on: http://review.coreboot.org/9662
Tested-by: build bot (Jenkins)
Reviewed-by: Patrick Georgi <pgeorgi@google.com>
This commit is contained in:
Ionela Voinescu 2015-01-18 22:37:11 +00:00 committed by Patrick Georgi
parent 95c902261f
commit b3f666b252
5 changed files with 530 additions and 0 deletions

View File

@ -40,6 +40,10 @@ config MAINBOARD_PART_NUMBER
string
default "ImgTec Pistachio Virtual Platform"
config BOOTBLOCK_MAINBOARD_INIT
string
default "mainboard/google/urara/bootblock.c"
config DRAM_SIZE_MB
int
default 256

View File

@ -0,0 +1,142 @@
/*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include <arch/io.h>
#include <stdint.h>
#include <soc/clocks.h>
#include <console/console.h>
#define GPIO_BIT_EN_ADDR(bank) (0xB8101C00 + 0x200 + (0x24 * (bank)))
/* MFIO definitions for UART0/1 */
#define UART1_RXD_MFIO 59
#define UART1_TXD_MFIO 60
#define UART0_RXD_MFIO 55
#define UART0_TXD_MFIO 56
#define UART0_RTS_MFIO 57
#define UART0_CTS_MFIO 58
/* 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
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
* This is the primary function (0) of these MFIOs and therfore there
* 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
* This is the primary function (0) of these MFIOs and therfore there
* is no need to set up a function number in the corresponding
* function select register.
*/
reg = read32(GPIO_BIT_EN_ADDR(0));
/* Disable GPIO for UART0 MFIOs */
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);
/* TODO: for the moment it only sets up CS0 (NOR) */
/* There is no need for other CS lines in Coreboot */
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);
}
static int init_clocks(void)
{
int ret;
/*
* Set up dividers for peripherals before setting up PLLs
* in order to not over-clock them when enabling PLLs
*/
/* System PLL divided by 2 -> 400 MHz */
/* The same frequency will be the input frequency for the SPFI block */
system_clk_setup(1);
/* System clock divided by 8 -> 50 MHz */
ret = usb_clk_setup(7, 2, 7);
if (ret != CLOCKS_OK)
return ret;
/* System PLL divided by 7 divided by 62 -> 1.8433 Mhz */
uart1_clk_setup(6, 61);
/* Setup system PLL at 800 MHz */
ret = sys_pll_setup(2, 1);
if (ret != CLOCKS_OK)
return ret;
/* Setup MIPS PLL at 550 MHz */
ret = mips_pll_setup(2, 1, 13, 275);
if (ret != CLOCKS_OK)
return ret;
return CLOCKS_OK;
}
static void bootblock_mainboard_init(void)
{
if (!init_clocks()) {
/* Disable GPIO on the peripheral lines */
uart1_mfio_setup();
printk(BIOS_INFO, "Urara board: UART initialized!\n");
spim1_mfio_setup();
}
}

View File

@ -20,6 +20,7 @@
#
# We enable CBFS_SPI_WRAPPER for Pistachio targets.
bootblock-y += clocks.c
bootblock-y += spi.c
romstage-y += spi.c
ramstage-y += spi.c

View File

@ -0,0 +1,344 @@
/*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include <arch/io.h>
#include <soc/clocks.h>
#include <timer.h>
#include <delay.h>
#include <assert.h>
/* Definitions for PLL enable */
#define PISTACHIO_CLOCK_SWITCH 0xB8144200
#define SYS_EXTERN_PLL_BYPASS_MASK 0x00002000
#define SYS_PLL_CTRL4_ADDR 0xB8144048
#define SYS_INTERNAL_PLL_BYPASS_MASK 0x10000000
#define SYS_PLL_PD_CTRL_ADDR 0xB8144044
#define SYS_PLL_PD_CTRL_PD_MASK 0x0000003F
#define MIPS_EXTERN_PLL_BYPASS_MASK 0x00000002
#define MIPS_PLL_CTRL2_ADDR 0xB8144008
#define MIPS_INTERNAL_PLL_BYPASS_MASK 0x10000000
#define MIPS_PLL_PD_CTRL_ADDR 0xB8144004
#define MIPS_PLL_PD_CTRL_PD_MASK 0x0F000000
/* Definitions for PLL dividers */
#define SYS_PLL_POSTDIV_ADDR 0xB8144040
#define SYS_PLL_POSTDIV1_MASK 0x07000000
#define SYS_PLL_POSTDIV1_SHIFT 24
#define SYS_PLL_POSTDIV2_MASK 0x38000000
#define SYS_PLL_POSTDIV2_SHIFT 27
#define SYS_PLL_STATUS_ADDR 0xB8144038
#define SYS_PLL_STATUS_LOCK_MASK 0x00000001
#define MIPS_PLL_POSTDIV_ADDR 0xB8144004
#define MIPS_PLL_POSTDIV1_MASK 0x001C0000
#define MIPS_PLL_POSTDIV1_SHIFT 18
#define MIPS_PLL_POSTDIV2_MASK 0x00E00000
#define MIPS_PLL_POSTDIV2_SHIFT 21
#define MIPS_PLL_STATUS_ADDR 0xB8144000
#define MIPS_PLL_STATUS_LOCK_MASK 0x00000001
#define MIPS_REFDIV_ADDR 0xB8144004
#define MIPS_REFDIV_MASK 0x0000003F
#define MIPS_REFDIV_SHIFT 0
#define MIPS_FEEDBACK_ADDR 0xB8144004
#define MIPS_FEEDBACK_MASK 0x0003FFC0
#define MIPS_FEEDBACK_SHIFT 6
/* Definitions for system clock setup */
#define SYSCLKINTERNAL_CTRL_ADDR 0xB8144244
#define SYSCLKINTERNAL_MASK 0X00000007
/* Definitions for USB clock setup */
#define USBPHYCLKOUT_CTRL_ADDR 0xB814422C
#define USBPHYCLKOUT_MASK 0X0000003F
#define USBPHYCONTROL1_ADDR 0xB8149004
#define USBPHYCONTROL1_FSEL_SHIFT 2
#define USBPHYCONTROL1_FSEL_MASK 0x1C
#define USBPHYSTRAPCTRL_ADDR 0xB8149010
#define USBPHYSTRAPCTRL_REFCLKSEL_SHIFT 4
#define USBPHYSTRAPCTRL_REFCLKSEL_MASK 0x30
#define USBPHYSTATUS_ADDR 0xB8149014
#define USBPHYSTATUS_RX_PHY_CLK_MASK 0x200
#define USBPHYSTATUS_RX_UTMI_CLK_MASK 0x100
#define USBPHYSTATUS_VBUS_FAULT_MASK 0x80
/* Definitions for UART0/1 setup */
#define UART0CLKINTERNAL_CTRL_ADDR 0xB8144234
#define UART0CLKINTERNAL_MASK 0x00000007
#define UART0CLKOUT_CTRL_ADDR 0xB8144238
#define UART0CLKOUT_MASK 0x000003FF
#define UART1CLKINTERNAL_CTRL_ADDR 0xB814423C
#define UART1CLKINTERNAL_MASK 0x00000007
#define UART1CLKOUT_CTRL_ADDR 0xB8144240
#define UART1CLKOUT_MASK 0x000003FF
/* Definitions for timeout values */
#define PLL_TIMEOUT_VALUE_US 20000
#define USB_TIMEOUT_VALUE_US 200000
#define SYS_CLK_LOCK_DELAY 3
struct pll_parameters {
u32 external_bypass_mask;
u32 ctrl_addr;
u32 internal_bypass_mask;
u32 power_down_ctrl_addr;
u32 power_down_ctrl_mask;
u32 postdiv_addr;
u32 postdiv1_shift;
u32 postdiv1_mask;
u32 postdiv2_shift;
u32 postdiv2_mask;
u32 status_addr;
u32 status_lock_mask;
u32 refdivider;
u32 refdiv_addr;
u32 refdiv_shift;
u32 refdiv_mask;
u32 feedback;
u32 feedback_addr;
u32 feedback_shift;
u32 feedback_mask;
};
enum plls {
SYS_PLL = 0,
MIPS_PLL = 1
};
static struct pll_parameters pll_params[] = {
[SYS_PLL] = {
.external_bypass_mask = SYS_EXTERN_PLL_BYPASS_MASK,
.ctrl_addr = SYS_PLL_CTRL4_ADDR,
.internal_bypass_mask = SYS_INTERNAL_PLL_BYPASS_MASK,
.power_down_ctrl_addr = SYS_PLL_PD_CTRL_ADDR,
.power_down_ctrl_mask = SYS_PLL_PD_CTRL_PD_MASK,
.postdiv_addr = SYS_PLL_POSTDIV_ADDR,
.postdiv1_shift = SYS_PLL_POSTDIV1_SHIFT,
.postdiv1_mask = SYS_PLL_POSTDIV1_MASK,
.postdiv2_shift = SYS_PLL_POSTDIV2_SHIFT,
.postdiv2_mask = SYS_PLL_POSTDIV2_MASK,
.status_addr = SYS_PLL_STATUS_ADDR,
.status_lock_mask = SYS_PLL_STATUS_LOCK_MASK,
.refdivider = 0, /* Not defined yet */
.refdiv_addr = 0, /* Not necessary */
.refdiv_shift = 0, /* Not necessary */
.refdiv_mask = 0, /* Not necessary */
.feedback = 0, /* Not necessary */
.feedback_addr = 0, /* Not necessary */
.feedback_shift = 0, /* Not necessary */
.feedback_mask = 0, /* Not necessary */
},
[MIPS_PLL] = {
.external_bypass_mask = MIPS_EXTERN_PLL_BYPASS_MASK,
.ctrl_addr = MIPS_PLL_CTRL2_ADDR,
.internal_bypass_mask = MIPS_INTERNAL_PLL_BYPASS_MASK,
.power_down_ctrl_addr = MIPS_PLL_PD_CTRL_ADDR,
.power_down_ctrl_mask = MIPS_PLL_PD_CTRL_PD_MASK,
.postdiv_addr = MIPS_PLL_POSTDIV_ADDR,
.postdiv1_shift = MIPS_PLL_POSTDIV1_SHIFT,
.postdiv1_mask = MIPS_PLL_POSTDIV1_MASK,
.postdiv2_shift = MIPS_PLL_POSTDIV2_SHIFT,
.postdiv2_mask = MIPS_PLL_POSTDIV2_MASK,
.status_addr = MIPS_PLL_STATUS_ADDR,
.status_lock_mask = MIPS_PLL_STATUS_LOCK_MASK,
.refdivider = 0, /* Not defined yet */
.refdiv_addr = MIPS_REFDIV_ADDR,
.refdiv_shift = MIPS_REFDIV_SHIFT,
.refdiv_mask = MIPS_REFDIV_MASK,
.feedback = 0, /* Not defined yet */
.feedback_addr = MIPS_FEEDBACK_ADDR,
.feedback_shift = MIPS_FEEDBACK_SHIFT,
.feedback_mask = MIPS_FEEDBACK_MASK
}
};
static int pll_setup(struct pll_parameters *param, u8 divider1, u8 divider2)
{
u32 reg;
struct stopwatch sw;
/* Check input parameters */
assert(!(divider1 & ~(param->postdiv1_mask)));
assert(!(divider2 & ~(param->postdiv2_mask)));
/* Temporary bypass PLL (select XTAL as clock input) */
reg = read32(PISTACHIO_CLOCK_SWITCH);
reg &= ~(param->external_bypass_mask);
write32(PISTACHIO_CLOCK_SWITCH, reg);
/* Un-bypass PLL's internal bypass */
reg = read32(param->ctrl_addr);
reg &= ~(param->internal_bypass_mask);
write32(param->ctrl_addr, reg);
/* Disable power down */
reg = read32(param->power_down_ctrl_addr);
reg &= ~(param->power_down_ctrl_mask);
write32(param->power_down_ctrl_addr, reg);
if (param->feedback_addr) {
assert(!(param->feedback & ~(param->feedback_mask)));
reg = read32(param->feedback_addr);
reg &= ~(param->feedback_mask);
reg |= (param->feedback << param->feedback_shift) &
param->feedback_mask;
write32(param->feedback_addr, reg);
}
if (param->refdiv_addr) {
assert(!(param->refdivider & ~(param->refdiv_mask)));
reg = read32(param->refdiv_addr);
reg &= ~(param->refdiv_mask);
reg |= (param->refdivider << param->refdiv_shift) &
param->refdiv_mask;
write32(param->refdiv_addr, reg);
}
/* Read postdivider register value */
reg = read32(param->postdiv_addr);
/* Set divider 1 */
reg &= ~(param->postdiv1_mask);
reg |= (divider1 << param->postdiv1_shift) &
param->postdiv1_mask;
/* Set divider 2 */
reg &= ~(param->postdiv2_mask);
reg |= (divider2 << param->postdiv2_shift) &
param->postdiv2_mask;
/* Write back to register */
write32(param->postdiv_addr, reg);
/* Waiting for PLL to lock*/
stopwatch_init_usecs_expire(&sw, PLL_TIMEOUT_VALUE_US);
while (!(read32(param->status_addr) & param->status_lock_mask)) {
if (stopwatch_expired(&sw))
return PLL_TIMEOUT;
}
/* Start using PLL */
reg = read32(PISTACHIO_CLOCK_SWITCH);
reg |= param->external_bypass_mask;
write32(PISTACHIO_CLOCK_SWITCH, reg);
return CLOCKS_OK;
}
int sys_pll_setup(u8 divider1, u8 divider2)
{
return pll_setup(&(pll_params[SYS_PLL]), divider1, divider2);
}
int mips_pll_setup(u8 divider1, u8 divider2, u8 refdivider, u32 feedback)
{
pll_params[MIPS_PLL].refdivider = refdivider;
pll_params[MIPS_PLL].feedback = feedback;
return pll_setup(&(pll_params[MIPS_PLL]), divider1, divider2);
}
/*
* uart1_clk_setup: sets up clocks for UART1
* divider1: 3-bit divider value
* divider2: 10-bit divider value
*/
void uart1_clk_setup(u8 divider1, u16 divider2)
{
u32 reg;
/* Check input parameters */
assert(!(divider1 & ~(UART1CLKINTERNAL_MASK)));
assert(!(divider2 & ~(UART1CLKOUT_MASK)));
/* Set divider 1 */
reg = read32(UART1CLKINTERNAL_CTRL_ADDR);
reg &= ~UART1CLKINTERNAL_MASK;
reg |= divider1 & UART1CLKINTERNAL_MASK;
write32(UART1CLKINTERNAL_CTRL_ADDR, reg);
/* Set divider 2 */
reg = read32(UART1CLKOUT_CTRL_ADDR);
reg &= ~UART1CLKOUT_MASK;
reg |= divider2 & UART1CLKOUT_MASK;
write32(UART1CLKOUT_CTRL_ADDR, reg);
}
/* system_clk_setup: sets up the system (peripheral) clock */
void system_clk_setup(u8 divider)
{
u32 reg;
/* Check input parameters */
assert(!(divider & ~(SYSCLKINTERNAL_MASK)));
/* Set system clock divider */
reg = read32(SYSCLKINTERNAL_CTRL_ADDR);
reg &= ~SYSCLKINTERNAL_MASK;
reg |= divider & SYSCLKINTERNAL_MASK;
write32(SYSCLKINTERNAL_CTRL_ADDR, reg);
/* Small delay to cover a maximum lock time of 1500 cycles */
udelay(SYS_CLK_LOCK_DELAY);
}
/* usb_clk_setup: sets up USB clock */
int usb_clk_setup(u8 divider, u8 refclksel, u8 fsel)
{
u32 reg;
struct stopwatch sw;
/* Check input parameters */
assert(!(divider & ~(USBPHYCLKOUT_MASK)));
assert(!(refclksel & ~(USBPHYSTRAPCTRL_REFCLKSEL_MASK)));
assert(!(fsel & ~(USBPHYCONTROL1_FSEL_MASK)));
/* Set USB divider */
reg = read32(USBPHYCLKOUT_CTRL_ADDR);
reg &= ~USBPHYCLKOUT_MASK;
reg |= divider & USBPHYCLKOUT_MASK;
write32(USBPHYCLKOUT_CTRL_ADDR, reg);
/* Set REFCLKSEL */
reg = read32(USBPHYSTRAPCTRL_ADDR);
reg &= ~USBPHYSTRAPCTRL_REFCLKSEL_MASK;
reg |= (refclksel << USBPHYSTRAPCTRL_REFCLKSEL_SHIFT) &
USBPHYSTRAPCTRL_REFCLKSEL_MASK;
write32(USBPHYSTRAPCTRL_ADDR, reg);
/* Set FSEL */
reg = read32(USBPHYCONTROL1_ADDR);
reg &= ~USBPHYCONTROL1_FSEL_MASK;
reg |= (fsel << USBPHYCONTROL1_FSEL_SHIFT) &
USBPHYCONTROL1_FSEL_MASK;
write32(USBPHYCONTROL1_ADDR, reg);
/* Waiting for USB clock status */
stopwatch_init_usecs_expire(&sw, USB_TIMEOUT_VALUE_US);
while (1) {
reg = read32(USBPHYSTATUS_ADDR);
if (reg & USBPHYSTATUS_VBUS_FAULT_MASK)
return USB_VBUS_FAULT;
if (stopwatch_expired(&sw))
return USB_TIMEOUT;
}
return CLOCKS_OK;
}

View File

@ -0,0 +1,39 @@
/*
* 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.
*
*/
#ifndef __SOC_IMGTEC_PISTACHIO_CLOCKS_H__
#define __SOC_IMGTEC_PISTACHIO_CLOCKS_H__
#include <stdint.h>
/* Functions for PLL setting */
int sys_pll_setup(u8 divider1, u8 divider2);
int mips_pll_setup(u8 divider1, u8 divider2i, u8 predivider, u32 feedback);
/* Peripheral divider setting */
void uart1_clk_setup(u8 divider1, u16 divider2);
void system_clk_setup(u8 divider);
int usb_clk_setup(u8 divider, u8 refclksel, u8 fsel);
enum {
CLOCKS_OK = 0,
PLL_TIMEOUT = -1,
USB_TIMEOUT = -2,
USB_VBUS_FAULT = -3
};
#endif