blob: 119dc44b0961be6f0c251cdfe2cabda36cc659c9 [file] [log] [blame]
/*
* setup.c
*
* Copyright (C) 2009-2013 Imagination Technologies Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/clk.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/dma-mapping.h>
#include <linux/serial_8250.h>
#include <linux/timeriomem-rng.h>
#include <linux/uccp.h>
#include <linux/syscore_ops.h>
#include <linux/of_platform.h>
#include <asm/global_lock.h>
#include <asm/mach/arch.h>
#include <asm/soc-tz1090/clock.h>
#include <asm/soc-tz1090/defs.h>
#include <asm/soc-tz1090/gpio.h>
#include <asm/soc-tz1090/pdc.h>
#include <asm/soc-tz1090/pm.h>
#include <asm/soc-tz1090/setup.h>
/*---------------------------- RNG Setup -------------------------------------*/
static struct resource rng_resource = {
.flags = IORESOURCE_MEM,
.start = CR_PERIP_RNG_NUM,
.end = CR_PERIP_RNG_NUM + 4 - 1,
};
static struct timeriomem_rng_data rng_data = {
.period = 0,
};
static struct platform_device rng_device = {
.name = "timeriomem_rng",
.id = -1,
.dev = {
.platform_data = &rng_data,
},
.resource = &rng_resource,
.num_resources = 1,
};
static void comet_rng_init(void)
{
/* start rng without programmable seed */
unsigned long rng_ctrl;
rng_ctrl = CR_PERIP_RNG_START_BITS | CR_PERIP_RNG_PSEED_DIS_BITS;
writel(rng_ctrl, CR_PERIP_RNG_CTRL);
}
/*---------------------------- UCCP Setup ------------------------------------*/
/* regions accessible from all uccp device nodes */
static struct uccp_region comet_uccp_global_regions[] = {
{
.type = UCCP_REGION_ALL,
.physical = UCCP_BASE_ADDR,
.size = UCCP_SIZE,
},
{
.type = UCCP_REGION_SYS_INTERNAL,
.physical = UCCP_SYSINT_BASE_ADDR,
.size = UCCP_SYSINT_SIZE,
},
};
static struct uccp_region comet_uccp0_regions[] = {
{
.type = UCCP_REGION_MTX,
.physical = UCCP0_MTX_BASE_ADDR,
.size = UCCP0_MTX_SIZE,
},
{
.type = UCCP_REGION_MCP_16_BIT,
.physical = UCCP0_MCP16BIT_BASE_ADDR,
.size = UCCP0_MCP16BIT_SIZE,
},
{
.type = UCCP_REGION_MCP_24_BIT,
.physical = UCCP0_MCP24BIT_BASE_ADDR,
.size = UCCP0_MCP24BIT_SIZE,
},
};
static struct uccp_region comet_uccp1_regions[] = {
{
.type = UCCP_REGION_MTX,
.physical = UCCP1_MTX_BASE_ADDR,
.size = UCCP1_MTX_SIZE,
},
};
static struct uccp_core comet_uccp_cores[] = {
[0] = {
.regions = comet_uccp0_regions,
.num_regions = ARRAY_SIZE(comet_uccp0_regions),
.num_mc_req = UCC0_MC_REQ_MAX,
},
[1] = {
.regions = comet_uccp1_regions,
.num_regions = ARRAY_SIZE(comet_uccp1_regions),
.num_mc_req = UCC1_MC_REQ_MAX,
},
};
static struct uccp_pdata comet_uccp_pdata = {
.cores = comet_uccp_cores,
.num_cores = ARRAY_SIZE(comet_uccp_cores),
.regions = comet_uccp_global_regions,
.num_regions = ARRAY_SIZE(comet_uccp_global_regions),
};
/* register blocks */
static struct resource comet_uccp_resources[] = {
{
.start = UCC0_HOST_BASE_ADDR,
.end = UCC0_HOST_BASE_ADDR + UCC0_HOST_SIZE,
.flags = IORESOURCE_MEM
| UCCP_RES(0, UCCP_RES_HOSTSYSBUS),
},
{
.start = UCC0_MC_BASE_ADDR,
.end = UCC0_MC_BASE_ADDR + UCC0_MC_SIZE,
.flags = IORESOURCE_MEM
| UCCP_RES(0, UCCP_RES_MCREQ),
},
{
.start = UCC1_HOST_BASE_ADDR,
.end = UCC1_HOST_BASE_ADDR + UCC1_HOST_SIZE,
.flags = IORESOURCE_MEM
| UCCP_RES(1, UCCP_RES_HOSTSYSBUS),
},
{
.start = UCC1_MC_BASE_ADDR,
.end = UCC1_MC_BASE_ADDR + UCC1_MC_SIZE,
.flags = IORESOURCE_MEM
| UCCP_RES(1, UCCP_RES_MCREQ),
},
};
static struct platform_device uccp_device = {
.name = "uccp",
.id = -1,
.dev = {
.platform_data = &comet_uccp_pdata,
},
.resource = comet_uccp_resources,
.num_resources = ARRAY_SIZE(comet_uccp_resources),
};
/*---------------------------- PDC Setup -------------------------------------*/
/* Stores the boot time 32khz clock rate for drivers to access */
unsigned long clk32k_bootfreq;
EXPORT_SYMBOL_GPL(clk32k_bootfreq);
static void comet_pdc_init(void)
{
unsigned int soc_gpio2, div;
int lstat;
/*
* The driver needs to know the boot time 32KHz clock frequency so it
* can compensate for incorrect clock rates during power down.
*/
clk32k_bootfreq = get_32kclock();
/*
* Set up PDC clock input to use XTAL1 with a divider. XTAL1 is
* likely less accurate (due to physical oscillator accuracy)
* than what might be available as XTAL3, but XTAL3 cannot be
* relied upon to reset the system.
*/
div = (2 * get_xtal1() / CLK32K_DESIRED_FREQUENCY + 1) / 2;
set_32kclock_src(1, div);
/* bypass XTAL3 */
__global_lock2(lstat);
soc_gpio2 = readl(PDC_BASE_ADDR + PDC_SOC_GPIO_CONTROL2);
soc_gpio2 |= PDC_SOC_GPIO2_XTAL3_BYPASS;
soc_gpio2 &= ~PDC_SOC_GPIO2_XTAL3_EN;
writel(soc_gpio2, PDC_BASE_ADDR + PDC_SOC_GPIO_CONTROL2);
__global_unlock2(lstat);
}
/*---------------------- Event/Timestamp counter Setup------------------------*/
#ifdef CONFIG_IMG_EVT
static struct resource comet_evt_resource = {
.start = EVENT_TS_BASE_ADDR,
.end = EVENT_TS_BASE_ADDR + EVENT_TS_SIZE,
.flags = IORESOURCE_MEM,
};
static struct platform_device comet_evt_device = {
.name = "img-eventtimer",
.id = -1,
.resource = &comet_evt_resource,
.num_resources = 1,
};
#endif
/*-----------------------Platform Devices Setup-------------------------------*/
static struct platform_device *comet_devices[] __initdata = {
&rng_device,
&uccp_device,
#ifdef CONFIG_IMG_EVT
&comet_evt_device,
#endif
};
static void __init comet_clocks_init(void)
{
unsigned int lstat, temp, clkenab2;
__global_lock2(lstat);
/* initialise HEP clocks to off */
clkenab2 = readl(CR_TOP_CLKENAB2);
temp = readl(CR_HEP_CLK_EN);
temp &= ~CR_2D_CLK_EN;
/* only stop PDP/PDI clock if pixel clock isn't already going */
if (!(clkenab2 & (1 << CR_TOP_PIXEL_CLK_2_EN_BIT)))
temp &= ~CR_PDP_PDI_CLK_EN;
writel(temp, CR_HEP_CLK_EN);
__global_unlock2(lstat);
}
/**
* comet_prepare_reset() - Prepare SoC for reset.
*
* This ensures workarounds can take place for reset/poweroff related quirks.
*/
void comet_prepare_reset(void)
{
/*
* Due to a hardware bug the 32.768KHz clock resets to being derived
* from XTAL1 with a divider of 768 when the power is cut. Setting
* explicitly beforehand triggers the notifier chain so that drivers of
* devices that use it can compensate.
*/
set_32kclock_src(1, 768);
}
/* board reboot callbacks */
void (*board_restart)(char *cmd) = NULL;
void (*board_halt)(void) = NULL;
void (*board_power_off)(void) = NULL;
static void comet_restart(char *cmd)
{
comet_prepare_reset();
if (board_restart)
board_restart(cmd);
comet_pdc_restart();
}
static void comet_halt(void)
{
comet_prepare_reset();
if (board_halt)
board_halt();
}
static void comet_power_off(void)
{
comet_prepare_reset();
if (board_power_off)
board_power_off();
comet_pdc_power_off();
}
#ifdef CONFIG_METAG_SUSPEND_MEM
static int comet_suspend(void)
{
return 0;
}
static void comet_resume(void)
{
comet_pdc_init();
comet_rng_init();
}
#else
#define comet_suspend NULL
#define comet_resume NULL
#endif /* CONFIG_METAG_SUSPEND_MEM */
static struct syscore_ops comet_syscore_ops = {
.suspend = comet_suspend,
.resume = comet_resume,
};
bool comet_is_evaluation_silicon(void)
{
unsigned int core_rev = readl(CR_COMET_CORE_REV);
return unlikely((core_rev & CR_COMET_CORE_REV_MAJOR_BITS)
== CR_COMET_CORE_REV_MAJOR_ES1);
}
void __init comet_init_early(void)
{
/*
* It's an easy mistake to forget SOC_COMET_ES1.
* It is better to panic now rather than mysteriously going wrong later.
*/
#ifndef CONFIG_SOC_COMET_ES1
if (comet_is_evaluation_silicon())
panic("This kernel doesn't support prototype (ES1) silicon. "
"Please enable SOC_COMET_ES1.");
#endif
}
void __init comet_init_machine(void)
{
printk(KERN_INFO"Comet Soc: XTAL1 is %ld HZ\n", get_xtal1());
printk(KERN_INFO"Comet Soc: XTAL2 is %ld HZ\n", get_xtal2());
printk(KERN_INFO"Comet Soc: XTAL3 is %ld HZ\n", get_xtal3());
printk(KERN_INFO"Comet Soc: Clocks:\n");
printk(KERN_INFO"Comet Soc: \tSys Clock (Pre deleter) %ld HZ\n",
get_sysclock_undeleted());
printk(KERN_INFO"Comet Soc: \tDDR Clock %ld HZ\n",
get_ddrclock());
/* Temporary backwards compatibility */
clk_add_alias("pdi", NULL, "pdp", NULL);
comet_clocks_init();
comet_rng_init();
platform_add_devices(comet_devices, ARRAY_SIZE(comet_devices));
register_syscore_ops(&comet_syscore_ops);
soc_restart = comet_restart;
soc_halt = comet_halt;
pm_power_off = comet_power_off;
comet_pdc_init();
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
}
static const char *tz1090_boards_compat[] __initdata = {
"toumaz,tz1090",
NULL,
};
MACHINE_START(TZ1090, "Generic TZ1090")
.dt_compat = tz1090_boards_compat,
TZ1090_MACHINE_DEFAULTS,
MACHINE_END