Changeset View
Changeset View
Standalone View
Standalone View
head/sys/mips/broadcom/bcm_machdep.c
/*- | /*- | ||||
* Copyright (c) 2007 Bruce M. Simpson. | * Copyright (c) 2007 Bruce M. Simpson. | ||||
* Copyright (c) 2016 Michael Zhilin <mizhka@gmail.com> | * Copyright (c) 2016 Michael Zhilin <mizhka@gmail.com> | ||||
* Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org> | |||||
* | * | ||||
* All rights reserved. | * All rights reserved. | ||||
* | * | ||||
* Redistribution and use in source and binary forms, with or without | * Redistribution and use in source and binary forms, with or without | ||||
* modification, are permitted provided that the following conditions | * modification, are permitted provided that the following conditions | ||||
* are met: | * are met: | ||||
* 1. Redistributions of source code must retain the above copyright | * 1. Redistributions of source code must retain the above copyright | ||||
* notice, this list of conditions and the following disclaimer. | * notice, this list of conditions and the following disclaimer. | ||||
▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | |||||
#include <machine/intr_machdep.h> | #include <machine/intr_machdep.h> | ||||
#include <machine/locore.h> | #include <machine/locore.h> | ||||
#include <machine/md_var.h> | #include <machine/md_var.h> | ||||
#include <machine/pte.h> | #include <machine/pte.h> | ||||
#include <machine/sigframe.h> | #include <machine/sigframe.h> | ||||
#include <machine/trap.h> | #include <machine/trap.h> | ||||
#include <machine/vmparam.h> | #include <machine/vmparam.h> | ||||
#include <dev/bhnd/bhnd.h> | |||||
#include <dev/bhnd/bhndreg.h> | |||||
#include <dev/bhnd/bcma/bcma_eromvar.h> | |||||
#include <dev/bhnd/siba/sibareg.h> | |||||
#include <dev/bhnd/siba/sibavar.h> | |||||
#include <dev/bhnd/cores/chipc/chipcreg.h> | |||||
#include "bcm_machdep.h" | |||||
#include "bcm_mips_exts.h" | |||||
#include "bcm_socinfo.h" | #include "bcm_socinfo.h" | ||||
#ifdef CFE | #ifdef CFE | ||||
#include <dev/cfe/cfe_api.h> | #include <dev/cfe/cfe_api.h> | ||||
#endif | #endif | ||||
#if 0 | #if 0 | ||||
#define BCM_TRACE(_fmt, ...) printf(_fmt, ##__VA_ARGS__) | #define BCM_TRACE(_fmt, ...) printf(_fmt, ##__VA_ARGS__) | ||||
#else | #else | ||||
#define BCM_TRACE(_fmt, ...) | #define BCM_TRACE(_fmt, ...) | ||||
#endif | #endif | ||||
static int bcm_find_core(struct bhnd_chipid *chipid, | |||||
bhnd_devclass_t devclass, int unit, | |||||
struct bhnd_core_info *info, uintptr_t *addr); | |||||
static int bcm_init_platform_data(struct bcm_platform *pdata); | |||||
/* Allow bus-specific implementations to override bcm_find_core_(bcma|siba) | |||||
* symbols, if included in the kernel build */ | |||||
__weak_reference(bcm_find_core_default, bcm_find_core_bcma); | |||||
__weak_reference(bcm_find_core_default, bcm_find_core_siba); | |||||
extern int *edata; | extern int *edata; | ||||
extern int *end; | extern int *end; | ||||
static struct bcm_platform bcm_platform_data; | |||||
static bool bcm_platform_data_avail = false; | |||||
struct bcm_platform * | |||||
bcm_get_platform(void) | |||||
{ | |||||
if (!bcm_platform_data_avail) | |||||
panic("platform data not available"); | |||||
return (&bcm_platform_data); | |||||
} | |||||
/* Default (no-op) bcm_find_core() implementation. */ | |||||
int | |||||
bcm_find_core_default(struct bhnd_chipid *chipid, bhnd_devclass_t devclass, | |||||
int unit, struct bhnd_core_info *info, uintptr_t *addr) | |||||
{ | |||||
return (ENODEV); | |||||
} | |||||
/** | |||||
* Search @p chipid's enumeration table for a core with @p devclass and | |||||
* @p unit. | |||||
* | |||||
* @param chipid Chip identification data, including the address | |||||
* of the enumeration table to be searched. | |||||
* @param devclass Search for a core matching this device class. | |||||
* @param unit The core's required unit number. | |||||
* @param[out] info On success, will be populated with the core | |||||
* info. | |||||
*/ | |||||
static int | |||||
bcm_find_core(struct bhnd_chipid *chipid, bhnd_devclass_t devclass, int unit, | |||||
struct bhnd_core_info *info, uintptr_t *addr) | |||||
{ | |||||
switch (chipid->chip_type) { | |||||
case BHND_CHIPTYPE_SIBA: | |||||
return (bcm_find_core_siba(chipid, devclass, unit, info, addr)); | |||||
break; | |||||
default: | |||||
if (!BHND_CHIPTYPE_HAS_EROM(chipid->chip_type)) { | |||||
printf("%s: unsupported chip type: %d\n", __FUNCTION__, | |||||
chipid->chip_type); | |||||
return (ENXIO); | |||||
} | |||||
return (bcm_find_core_bcma(chipid, devclass, unit, info, addr)); | |||||
} | |||||
} | |||||
/** | |||||
* Populate platform configuration data. | |||||
*/ | |||||
static int | |||||
bcm_init_platform_data(struct bcm_platform *pdata) | |||||
{ | |||||
uint32_t reg; | |||||
bhnd_addr_t enum_addr; | |||||
long maddr; | |||||
uint8_t chip_type; | |||||
bool aob, pmu; | |||||
int error; | |||||
/* Fetch CFE console handle (if any). Must be initialized before | |||||
* any calls to printf/early_putc. */ | |||||
#ifdef CFE | |||||
if ((pdata->cfe_console = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE)) < 0) | |||||
pdata->cfe_console = -1; | |||||
#endif | |||||
/* Fetch bhnd/chipc address */ | |||||
if (resource_long_value("bhnd", 0, "maddr", &maddr) == 0) | |||||
pdata->cc_addr = (u_long)maddr; | |||||
else | |||||
pdata->cc_addr = BHND_DEFAULT_CHIPC_ADDR; | |||||
/* Read chip identifier from ChipCommon */ | |||||
reg = BCM_SOC_READ_4(pdata->cc_addr, CHIPC_ID); | |||||
chip_type = CHIPC_GET_BITS(reg, CHIPC_ID_BUS); | |||||
if (BHND_CHIPTYPE_HAS_EROM(chip_type)) | |||||
enum_addr = BCM_SOC_READ_4(pdata->cc_addr, CHIPC_EROMPTR); | |||||
else | |||||
enum_addr = pdata->cc_addr; | |||||
pdata->id = bhnd_parse_chipid(reg, enum_addr); | |||||
/* Fetch chipc core info and capabilities */ | |||||
pdata->cc_caps = BCM_SOC_READ_4(pdata->cc_addr, CHIPC_CAPABILITIES); | |||||
error = bcm_find_core(&pdata->id, BHND_DEVCLASS_CC, 0, &pdata->cc_id, | |||||
NULL); | |||||
if (error) { | |||||
printf("%s: error locating chipc core: %d", __FUNCTION__, | |||||
error); | |||||
return (error); | |||||
} | |||||
if (CHIPC_HWREV_HAS_CAP_EXT(pdata->cc_id.hwrev)) { | |||||
pdata->cc_caps_ext = BCM_SOC_READ_4(pdata->cc_addr, | |||||
CHIPC_CAPABILITIES_EXT); | |||||
} else { | |||||
pdata->cc_caps_ext = 0x0; | |||||
} | |||||
/* Fetch PMU info */ | |||||
pmu = CHIPC_GET_FLAG(pdata->cc_caps, CHIPC_CAP_PMU); | |||||
aob = CHIPC_GET_FLAG(pdata->cc_caps_ext, CHIPC_CAP2_AOB); | |||||
if (pmu && aob) { | |||||
/* PMU block mapped to a PMU core on the Always-on-Bus (aob) */ | |||||
error = bcm_find_core(&pdata->id, BHND_DEVCLASS_PMU, 0, | |||||
&pdata->pmu_id, &pdata->pmu_addr); | |||||
if (error) { | |||||
printf("%s: error locating pmu core: %d", __FUNCTION__, | |||||
error); | |||||
return (error); | |||||
} | |||||
} else if (pmu) { | |||||
/* PMU block mapped to chipc */ | |||||
pdata->pmu_addr = pdata->cc_addr; | |||||
pdata->pmu_id = pdata->cc_id; | |||||
} else { | |||||
/* No PMU */ | |||||
pdata->pmu_addr = 0x0; | |||||
memset(&pdata->pmu_id, 0, sizeof(pdata->pmu_id)); | |||||
} | |||||
bcm_platform_data_avail = true; | |||||
return (0); | |||||
} | |||||
void | void | ||||
platform_cpu_init() | platform_cpu_init() | ||||
{ | { | ||||
/* Nothing special */ | /* Nothing special */ | ||||
} | } | ||||
static void | static void | ||||
mips_init(void) | mips_init(void) | ||||
▲ Show 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | #ifdef KDB | ||||
if (boothowto & RB_KDB) | if (boothowto & RB_KDB) | ||||
kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); | kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); | ||||
#endif | #endif | ||||
} | } | ||||
void | void | ||||
platform_reset(void) | platform_reset(void) | ||||
{ | { | ||||
bool bcm4785war; | |||||
printf("bcm::platform_reset()\n"); | printf("bcm::platform_reset()\n"); | ||||
intr_disable(); | intr_disable(); | ||||
#if defined(CFE) | #ifdef CFE | ||||
/* Fall back on CFE if reset requested during platform | |||||
* data initialization */ | |||||
if (!bcm_platform_data_avail) { | |||||
cfe_exit(0, 0); | cfe_exit(0, 0); | ||||
#else | while (1); | ||||
/* PMU watchdog reset */ | } | ||||
BCM_WRITE_REG32(BCM_REG_CHIPC_PMUWD_OFFS, 2); /* PMU watchdog */ | |||||
#endif | #endif | ||||
#if 0 | /* Handle BCM4785-specific behavior */ | ||||
/* Non-PMU reset | bcm4785war = false; | ||||
* XXX: Need chipc capability flags */ | if (bcm_get_platform()->id.chip_id == BHND_CHIPID_BCM4785) { | ||||
*((volatile uint8_t *)MIPS_PHYS_TO_KSEG1(SENTRY5_EXTIFADR)) = 0x80; | bcm4785war = true; | ||||
#endif | |||||
for (;;); | /* Switch to async mode */ | ||||
bcm_mips_wr_pllcfg3(MIPS_BCMCFG_PLLCFG3_SM); | |||||
} | } | ||||
/* Set watchdog (PMU or ChipCommon) */ | |||||
if (bcm_get_platform()->pmu_addr != 0x0) { | |||||
BCM_CHIPC_WRITE_4(CHIPC_PMU_WATCHDOG, 1); | |||||
} else | |||||
BCM_CHIPC_WRITE_4(CHIPC_WATCHDOG, 1); | |||||
/* BCM4785 */ | |||||
if (bcm4785war) { | |||||
mips_sync(); | |||||
__asm __volatile("wait"); | |||||
} | |||||
while (1); | |||||
} | |||||
void | void | ||||
platform_start(__register_t a0, __register_t a1, __register_t a2, | platform_start(__register_t a0, __register_t a1, __register_t a2, | ||||
__register_t a3) | __register_t a3) | ||||
{ | { | ||||
vm_offset_t kernend; | vm_offset_t kernend; | ||||
uint64_t platform_counter_freq; | uint64_t platform_counter_freq; | ||||
struct bcm_socinfo *socinfo; | struct bcm_socinfo *socinfo; | ||||
int error; | |||||
/* clear the BSS and SBSS segments */ | /* clear the BSS and SBSS segments */ | ||||
kernend = (vm_offset_t)&end; | kernend = (vm_offset_t)&end; | ||||
memset(&edata, 0, kernend - (vm_offset_t)(&edata)); | memset(&edata, 0, kernend - (vm_offset_t)(&edata)); | ||||
mips_postboot_fixup(); | mips_postboot_fixup(); | ||||
/* Initialize pcpu stuff */ | /* Initialize pcpu stuff */ | ||||
Show All 9 Lines | #ifdef CFE | ||||
* a0: firmware handle | * a0: firmware handle | ||||
* a2: firmware entry point | * a2: firmware entry point | ||||
* a3: entry point seal | * a3: entry point seal | ||||
*/ | */ | ||||
if (a3 == CFE_EPTSEAL) | if (a3 == CFE_EPTSEAL) | ||||
cfe_init(a0, a2); | cfe_init(a0, a2); | ||||
#endif | #endif | ||||
#if 0 | /* Init BCM platform data */ | ||||
/* | if ((error = bcm_init_platform_data(&bcm_platform_data))) | ||||
* Probe the Broadcom on-chip PLL clock registers | panic("bcm_init_platform_data() failed: %d", error); | ||||
* and discover the CPU pipeline clock and bus clock | |||||
* multipliers from this. | |||||
* XXX: Wrong place. You have to ask the ChipCommon | |||||
* or External Interface cores on the SiBa. | |||||
*/ | |||||
uint32_t busmult, cpumult, refclock, clkcfg1; | |||||
#define S5_CLKCFG1_REFCLOCK_MASK 0x0000001F | |||||
#define S5_CLKCFG1_BUSMULT_MASK 0x000003E0 | |||||
#define S5_CLKCFG1_BUSMULT_SHIFT 5 | |||||
#define S5_CLKCFG1_CPUMULT_MASK 0xFFFFFC00 | |||||
#define S5_CLKCFG1_CPUMULT_SHIFT 10 | |||||
counter_freq = 100000000; /* XXX */ | |||||
clkcfg1 = s5_rd_clkcfg1(); | |||||
printf("clkcfg1 = 0x%08x\n", clkcfg1); | |||||
refclock = clkcfg1 & 0x1F; | |||||
busmult = ((clkcfg1 & 0x000003E0) >> 5) + 1; | |||||
cpumult = ((clkcfg1 & 0xFFFFFC00) >> 10) + 1; | |||||
printf("refclock = %u\n", refclock); | |||||
printf("busmult = %u\n", busmult); | |||||
printf("cpumult = %u\n", cpumult); | |||||
counter_freq = cpumult * refclock; | |||||
#endif | |||||
socinfo = bcm_get_socinfo(); | socinfo = bcm_get_socinfo(); | ||||
platform_counter_freq = socinfo->cpurate * 1000 * 1000; /* BCM4718 is 480MHz */ | platform_counter_freq = socinfo->cpurate * 1000 * 1000; /* BCM4718 is 480MHz */ | ||||
mips_timer_early_init(platform_counter_freq); | mips_timer_early_init(platform_counter_freq); | ||||
cninit(); | cninit(); | ||||
mips_init(); | mips_init(); | ||||
mips_timer_init_params(platform_counter_freq, socinfo->double_count); | mips_timer_init_params(platform_counter_freq, socinfo->double_count); | ||||
} | } | ||||
/* | /* | ||||
* CFE-based EARLY_PRINTF support. To use, add the following to the kernel | * CFE-based EARLY_PRINTF support. To use, add the following to the kernel | ||||
* config: | * config: | ||||
* option EARLY_PRINTF | * option EARLY_PRINTF | ||||
* option CFE | * option CFE | ||||
* device cfe | * device cfe | ||||
*/ | */ | ||||
#if defined(EARLY_PRINTF) && defined(CFE) | #if defined(EARLY_PRINTF) && defined(CFE) | ||||
static void | static void | ||||
bcm_cfe_eputc(int c) | bcm_cfe_eputc(int c) | ||||
{ | { | ||||
static int fd = -1; | |||||
unsigned char ch; | unsigned char ch; | ||||
int handle; | |||||
ch = (unsigned char) c; | ch = (unsigned char) c; | ||||
if (fd == -1) { | /* bcm_get_platform() cannot be used here, as we may be called | ||||
if ((fd = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE)) < 0) | * from bcm_init_platform_data(). */ | ||||
if ((handle = bcm_platform_data.cfe_console) < 0) | |||||
return; | return; | ||||
} | |||||
if (ch == '\n') | if (ch == '\n') | ||||
early_putc('\r'); | early_putc('\r'); | ||||
while ((cfe_write(fd, &ch, 1)) == 0) | while ((cfe_write(handle, &ch, 1)) == 0) | ||||
continue; | continue; | ||||
} | } | ||||
early_putc_t *early_putc = bcm_cfe_eputc; | early_putc_t *early_putc = bcm_cfe_eputc; | ||||
#endif /* EARLY_PRINTF */ | #endif /* EARLY_PRINTF */ |