Introduce basic support for Marvell families of system-on-chip ARM devices:

*  Orion
     - 88F5181
     - 88F5182
     - 88F5281

  * Kirkwood
     - 88F6281

  * Discovery
     - MV78100

The above families of SOCs are built around CPU cores compliant with ARMv5TE
instruction set architecture definition. They share a number of integrated
peripherals. This commit brings support for the following basic elements:

  * GPIO
  * Interrupt controller
  * L1, L2 cache
  * Timers, watchdog, RTC
  * TWSI (I2C)
  * UART

Other peripherals drivers will be introduced separately.

Reviewed by:	imp, marcel, stass (Thanks guys!)
Obtained from:	Marvell, Semihalf
This commit is contained in:
Rafal Jaworowski 2008-10-13 20:07:13 +00:00
parent dd891816df
commit 373bbe25ff
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=183840
32 changed files with 5875 additions and 2 deletions

View file

@ -73,6 +73,8 @@ void __startC(void);
#endif
#ifdef CPU_XSCALE_81342
#define cpu_l2cache_wbinv_all xscalec3_l2cache_purge
#elif defined(SOC_MV_KIRKWOOD) || defined(SOC_MV_DISCOVERY)
#define cpu_l2cache_wbinv_all feroceon_l2cache_wbinv_all
#else
#define cpu_l2cache_wbinv_all()
#endif

View file

@ -44,7 +44,9 @@
#elif defined(CPU_XSCALE_PXA2X0)
#include <arm/xscale/pxa/pxareg.h>
#define NIRQ IRQ_GPIO_MAX
#elif defined(CPU_ARM9)
#elif defined(SOC_MV_DISCOVERY)
#define NIRQ 96
#elif defined(CPU_ARM9) || defined(SOC_MV_KIRKWOOD)
#define NIRQ 64
#else
#define NIRQ 32

View file

@ -41,5 +41,6 @@
#define SYS_RES_DRQ 2 /* isa dma lines */
#define SYS_RES_MEMORY 3 /* i/o memory */
#define SYS_RES_IOPORT 4 /* i/o ports */
#define SYS_RES_GPIO 5 /* general purpose i/o */
#endif /* !_MACHINE_RESOURCE_H_ */

162
sys/arm/mv/bus_space.c Normal file
View file

@ -0,0 +1,162 @@
/*-
* Copyright (C) 2008 MARVELL INTERNATIONAL LTD.
* All rights reserved.
*
* Developed by Semihalf.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of MARVELL nor the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <machine/bus.h>
/*
* Bus space functions for Marvell SoC family
*/
/* Prototypes for all the bus_space structure functions */
bs_protos(generic);
bs_protos(generic_armv4);
/*
* The obio bus space tag. This is constant for all instances, so
* we never have to explicitly "create" it.
*/
static struct bus_space _base_tag = {
/* cookie */
(void *) 0,
/* mapping/unmapping */
generic_bs_map,
generic_bs_unmap,
generic_bs_subregion,
/* allocation/deallocation */
generic_bs_alloc,
generic_bs_free,
/* barrier */
generic_bs_barrier,
/* read (single) */
generic_bs_r_1,
generic_armv4_bs_r_2,
generic_bs_r_4,
NULL,
/* read multiple */
generic_bs_rm_1,
generic_armv4_bs_rm_2,
generic_bs_rm_4,
NULL,
/* read region */
generic_bs_rr_1,
generic_armv4_bs_rr_2,
generic_bs_rr_4,
NULL,
/* write (single) */
generic_bs_w_1,
generic_armv4_bs_w_2,
generic_bs_w_4,
NULL,
/* write multiple */
generic_bs_wm_1,
generic_armv4_bs_wm_2,
generic_bs_wm_4,
NULL,
/* write region */
NULL,
NULL,
NULL,
NULL,
/* set multiple */
NULL,
NULL,
NULL,
NULL,
/* set region */
NULL,
NULL,
NULL,
NULL,
/* copy */
NULL,
NULL,
NULL,
NULL,
/* read stream (single) */
NULL,
NULL,
NULL,
NULL,
/* read multiple stream */
NULL,
generic_armv4_bs_rm_2, /* bus_space_read_multi_stream_2 */
NULL,
NULL,
/* read region stream */
NULL,
NULL,
NULL,
NULL,
/* write stream (single) */
NULL,
NULL,
NULL,
NULL,
/* write multiple stream */
NULL,
generic_armv4_bs_wm_2, /* bus_space_write_multi_stream_2 */
NULL,
NULL,
/* write region stream */
NULL,
NULL,
NULL,
NULL
};
bus_space_tag_t obio_tag = &_base_tag;

965
sys/arm/mv/common.c Normal file
View file

@ -0,0 +1,965 @@
/*-
* Copyright (C) 2008 MARVELL INTERNATIONAL LTD.
* All rights reserved.
*
* Developed by Semihalf.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of MARVELL nor the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/systm.h>
#include <sys/bus.h>
#include <machine/bus.h>
#include <arm/mv/mvreg.h>
#include <arm/mv/mvvar.h>
static int win_eth_can_remap(int i);
static int decode_win_cpu_valid(void);
static int decode_win_usb_valid(void);
static int decode_win_eth_valid(void);
static int decode_win_pcie_valid(void);
static void decode_win_cpu_setup(void);
static void decode_win_usb_setup(uint32_t ctrl);
static void decode_win_eth_setup(uint32_t base);
static void decode_win_pcie_setup(uint32_t base);
static uint32_t dev, rev;
uint32_t
read_cpu_ctrl(uint32_t reg)
{
return (bus_space_read_4(obio_tag, MV_CPU_CONTROL_BASE, reg));
}
void
write_cpu_ctrl(uint32_t reg, uint32_t val)
{
bus_space_write_4(obio_tag, MV_CPU_CONTROL_BASE, reg, val);
}
void
cpu_reset(void)
{
write_cpu_ctrl(RSTOUTn_MASK, SOFT_RST_OUT_EN);
write_cpu_ctrl(SYSTEM_SOFT_RESET, SYS_SOFT_RST);
while (1);
}
uint32_t
cpu_extra_feat(void)
{
uint32_t ef = 0;
soc_id(&dev, &rev);
if (dev == MV_DEV_88F6281 || dev == MV_DEV_MV78100)
__asm __volatile("mrc p15, 1, %0, c15, c1, 0" : "=r" (ef));
else if (dev == MV_DEV_88F5182 || dev == MV_DEV_88F5281)
__asm __volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (ef));
else if (bootverbose)
printf("This ARM Core does not support any extra features\n");
return (ef);
}
uint32_t
soc_power_ctrl_get(uint32_t mask)
{
if (mask != CPU_PM_CTRL_NONE)
mask &= read_cpu_ctrl(CPU_PM_CTRL);
return (mask);
}
uint32_t
get_tclk(void)
{
#if defined(SOC_MV_DISCOVERY)
return (TCLK_200MHZ);
#else
return (TCLK_166MHZ);
#endif
}
void
soc_id(uint32_t *dev, uint32_t *rev)
{
/*
* Notice: system identifiers are available in the registers range of
* PCIE controller, so using this function is only allowed (and
* possible) after the internal registers range has been mapped in via
* pmap_devmap_bootstrap().
*/
*dev = bus_space_read_4(obio_tag, MV_PCIE_BASE, 0) >> 16;
*rev = bus_space_read_4(obio_tag, MV_PCIE_BASE, 8) & 0xff;
}
void
soc_identify(void)
{
uint32_t d, r;
const char *dev;
const char *rev;
soc_id(&d, &r);
printf("SOC: ");
if (bootverbose)
printf("(0x%4x:0x%02x) ", d, r);
rev = "";
switch (d) {
case MV_DEV_88F5181:
dev = "Marvell 88F5181";
if (r == 3)
rev = "B1";
break;
case MV_DEV_88F5182:
dev = "Marvell 88F5182";
if (r == 2)
rev = "A2";
break;
case MV_DEV_88F5281:
dev = "Marvell 88F5281";
if (r == 4)
rev = "D0";
else if (r == 5)
rev = "D1";
else if (r == 6)
rev = "D2";
break;
case MV_DEV_88F6281:
dev = "Marvell 88F6281";
break;
case MV_DEV_MV78100:
dev = "Marvell MV78100";
break;
default:
dev = "UNKNOWN";
break;
}
printf("%s", dev);
if (*rev != '\0')
printf(" rev %s", rev);
printf(", TClock %dMHz\n", get_tclk() / 1000 / 1000);
/* TODO add info on currently set endianess */
}
int
soc_decode_win(void)
{
/* Retrieve our ID: some windows facilities vary between SoC models */
soc_id(&dev, &rev);
if (decode_win_cpu_valid() != 1 || decode_win_usb_valid() != 1 ||
decode_win_eth_valid() != 1 || decode_win_idma_valid() != 1 ||
decode_win_pcie_valid() != 1)
return(-1);
decode_win_cpu_setup();
decode_win_usb_setup(MV_USB0_BASE);
decode_win_eth_setup(MV_ETH0_BASE);
if (dev == MV_DEV_MV78100)
decode_win_eth_setup(MV_ETH1_BASE);
decode_win_idma_setup();
decode_win_pcie_setup(MV_PCIE_BASE);
/* TODO set up decode wins for SATA */
return (0);
}
/**************************************************************************
* Decode windows registers accessors
**************************************************************************/
WIN_REG_IDX_RD(win_cpu, cr, MV_WIN_CPU_CTRL, MV_MBUS_BRIDGE_BASE)
WIN_REG_IDX_RD(win_cpu, br, MV_WIN_CPU_BASE, MV_MBUS_BRIDGE_BASE)
WIN_REG_IDX_RD(win_cpu, remap_l, MV_WIN_CPU_REMAP_LO, MV_MBUS_BRIDGE_BASE)
WIN_REG_IDX_RD(win_cpu, remap_h, MV_WIN_CPU_REMAP_HI, MV_MBUS_BRIDGE_BASE)
WIN_REG_IDX_WR(win_cpu, cr, MV_WIN_CPU_CTRL, MV_MBUS_BRIDGE_BASE)
WIN_REG_IDX_WR(win_cpu, br, MV_WIN_CPU_BASE, MV_MBUS_BRIDGE_BASE)
WIN_REG_IDX_WR(win_cpu, remap_l, MV_WIN_CPU_REMAP_LO, MV_MBUS_BRIDGE_BASE)
WIN_REG_IDX_WR(win_cpu, remap_h, MV_WIN_CPU_REMAP_HI, MV_MBUS_BRIDGE_BASE)
WIN_REG_IDX_RD(ddr, br, MV_WIN_DDR_BASE, MV_DDR_CADR_BASE)
WIN_REG_IDX_RD(ddr, sz, MV_WIN_DDR_SIZE, MV_DDR_CADR_BASE)
WIN_REG_IDX_RD(win_usb, cr, MV_WIN_USB_CTRL, MV_USB_AWR_BASE)
WIN_REG_IDX_RD(win_usb, br, MV_WIN_USB_BASE, MV_USB_AWR_BASE)
WIN_REG_IDX_WR(win_usb, cr, MV_WIN_USB_CTRL, MV_USB_AWR_BASE)
WIN_REG_IDX_WR(win_usb, br, MV_WIN_USB_BASE, MV_USB_AWR_BASE)
WIN_REG_BASE_IDX_RD(win_eth, br, MV_WIN_ETH_BASE)
WIN_REG_BASE_IDX_RD(win_eth, sz, MV_WIN_ETH_SIZE)
WIN_REG_BASE_IDX_RD(win_eth, har, MV_WIN_ETH_REMAP)
WIN_REG_BASE_IDX_WR(win_eth, br, MV_WIN_ETH_BASE)
WIN_REG_BASE_IDX_WR(win_eth, sz, MV_WIN_ETH_SIZE)
WIN_REG_BASE_IDX_WR(win_eth, har, MV_WIN_ETH_REMAP)
WIN_REG_BASE_RD(win_eth, bare, 0x290)
WIN_REG_BASE_RD(win_eth, epap, 0x294)
WIN_REG_BASE_WR(win_eth, bare, 0x290)
WIN_REG_BASE_WR(win_eth, epap, 0x294)
WIN_REG_BASE_IDX_RD(win_pcie, cr, MV_WIN_PCIE_CTRL);
WIN_REG_BASE_IDX_RD(win_pcie, br, MV_WIN_PCIE_BASE);
WIN_REG_BASE_IDX_RD(win_pcie, remap, MV_WIN_PCIE_REMAP);
WIN_REG_BASE_IDX_WR(win_pcie, cr, MV_WIN_PCIE_CTRL);
WIN_REG_BASE_IDX_WR(win_pcie, br, MV_WIN_PCIE_BASE);
WIN_REG_BASE_IDX_WR(win_pcie, remap, MV_WIN_PCIE_REMAP);
WIN_REG_BASE_IDX_WR(pcie, bar, MV_PCIE_BAR);
WIN_REG_IDX_RD(win_idma, br, MV_WIN_IDMA_BASE, MV_IDMA_BASE)
WIN_REG_IDX_RD(win_idma, sz, MV_WIN_IDMA_SIZE, MV_IDMA_BASE)
WIN_REG_IDX_RD(win_idma, har, MV_WIN_IDMA_REMAP, MV_IDMA_BASE)
WIN_REG_IDX_RD(win_idma, cap, MV_WIN_IDMA_CAP, MV_IDMA_BASE)
WIN_REG_IDX_WR(win_idma, br, MV_WIN_IDMA_BASE, MV_IDMA_BASE)
WIN_REG_IDX_WR(win_idma, sz, MV_WIN_IDMA_SIZE, MV_IDMA_BASE)
WIN_REG_IDX_WR(win_idma, har, MV_WIN_IDMA_REMAP, MV_IDMA_BASE)
WIN_REG_IDX_WR(win_idma, cap, MV_WIN_IDMA_CAP, MV_IDMA_BASE)
WIN_REG_RD(win_idma, bare, 0xa80, MV_IDMA_BASE)
WIN_REG_WR(win_idma, bare, 0xa80, MV_IDMA_BASE)
/**************************************************************************
* Decode windows helper routines
**************************************************************************/
void
soc_dump_decode_win(void)
{
int i;
soc_id(&dev, &rev);
for (i = 0; i < MV_WIN_CPU_MAX; i++) {
printf("CPU window#%d: c 0x%08x, b 0x%08x", i,
win_cpu_cr_read(i),
win_cpu_br_read(i));
if (win_cpu_can_remap(i))
printf(", rl 0x%08x, rh 0x%08x",
win_cpu_remap_l_read(i),
win_cpu_remap_h_read(i));
printf("\n");
}
printf("Internal regs base: 0x%08x\n",
bus_space_read_4(obio_tag, MV_INTREGS_BASE, 0));
for (i = 0; i < MV_WIN_DDR_MAX; i++)
printf("DDR CS#%d: b 0x%08x, s 0x%08x\n", i,
ddr_br_read(i), ddr_sz_read(i));
for (i = 0; i < MV_WIN_USB_MAX; i++)
printf("USB window#%d: c 0x%08x, b 0x%08x\n", i,
win_usb_cr_read(i), win_usb_br_read(i));
for (i = 0; i < MV_WIN_ETH_MAX; i++) {
printf("ETH window#%d: b 0x%08x, s 0x%08x", i,
win_eth_br_read(MV_ETH0_BASE, i),
win_eth_sz_read(MV_ETH0_BASE, i));
if (win_eth_can_remap(i))
printf(", ha 0x%08x",
win_eth_har_read(MV_ETH0_BASE, i));
printf("\n");
}
printf("ETH windows: bare 0x%08x, epap 0x%08x\n",
win_eth_bare_read(MV_ETH0_BASE),
win_eth_epap_read(MV_ETH0_BASE));
decode_win_idma_dump();
printf("\n");
}
/**************************************************************************
* CPU windows routines
**************************************************************************/
int
win_cpu_can_remap(int i)
{
/* Depending on the SoC certain windows have remap capability */
if ((dev == MV_DEV_88F5182 && i < 2) ||
(dev == MV_DEV_88F5281 && i < 4) ||
(dev == MV_DEV_88F6281 && i < 4) ||
(dev == MV_DEV_MV78100 && i < 8))
return (1);
return (0);
}
/* XXX This should check for overlapping remap fields too.. */
int
decode_win_overlap(int win, int win_no, const struct decode_win *wintab)
{
const struct decode_win *tab;
int i;
tab = wintab;
for (i = 0; i < win_no; i++, tab++) {
if (i == win)
/* Skip self */
continue;
if ((tab->base + tab->size - 1) < (wintab + win)->base)
continue;
else if (((wintab + win)->base + (wintab + win)->size - 1) <
tab->base)
continue;
else
return (i);
}
return (-1);
}
static int
decode_win_cpu_valid(void)
{
int i, j, rv;
uint32_t b, e, s;
if (cpu_wins_no > MV_WIN_CPU_MAX) {
printf("CPU windows: too many entries: %d\n", cpu_wins_no);
return (-1);
}
rv = 1;
for (i = 0; i < cpu_wins_no; i++) {
if (cpu_wins[i].target == 0) {
printf("CPU window#%d: DDR target window is not "
"supposed to be reprogrammed!\n", i);
rv = 0;
}
if (cpu_wins[i].remap >= 0 && win_cpu_can_remap(i) != 1) {
printf("CPU window#%d: not capable of remapping, but "
"val 0x%08x defined\n", i, cpu_wins[i].remap);
rv = 0;
}
s = cpu_wins[i].size;
b = cpu_wins[i].base;
e = b + s - 1;
if (s > (0xFFFFFFFF - b + 1)) {
/*
* XXX this boundary check should account for 64bit
* and remapping..
*/
printf("CPU window#%d: no space for size 0x%08x at "
"0x%08x\n", i, s, b);
rv = 0;
continue;
}
j = decode_win_overlap(i, cpu_wins_no, &cpu_wins[0]);
if (j >= 0) {
printf("CPU window#%d: (0x%08x - 0x%08x) overlaps "
"with #%d (0x%08x - 0x%08x)\n", i, b, e, j,
cpu_wins[j].base,
cpu_wins[j].base + cpu_wins[j].size - 1);
rv = 0;
}
}
return (rv);
}
static void
decode_win_cpu_setup(void)
{
uint32_t br, cr;
int i;
/* Disable all CPU windows */
for (i = 0; i < MV_WIN_CPU_MAX; i++) {
win_cpu_cr_write(i, 0);
win_cpu_br_write(i, 0);
if (win_cpu_can_remap(i)) {
win_cpu_remap_l_write(i, 0);
win_cpu_remap_h_write(i, 0);
}
}
for (i = 0; i < cpu_wins_no; i++)
if (cpu_wins[i].target > 0) {
br = cpu_wins[i].base & 0xffff0000;
win_cpu_br_write(i, br);
if (win_cpu_can_remap(i)) {
if (cpu_wins[i].remap >= 0) {
win_cpu_remap_l_write(i,
cpu_wins[i].remap & 0xffff0000);
win_cpu_remap_h_write(i, 0);
} else {
/*
* Remap function is not used for
* a given window (capable of
* remapping) - set remap field with the
* same value as base.
*/
win_cpu_remap_l_write(i,
cpu_wins[i].base & 0xffff0000);
win_cpu_remap_h_write(i, 0);
}
}
cr = ((cpu_wins[i].size - 1) & 0xffff0000) |
(cpu_wins[i].attr << 8) |
(cpu_wins[i].target << 4) | 1;
win_cpu_cr_write(i, cr);
}
}
/*
* Check if we're able to cover all active DDR banks.
*/
static int
decode_win_can_cover_ddr(int max)
{
int i, c;
c = 0;
for (i = 0; i < MV_WIN_DDR_MAX; i++)
if (ddr_is_active(i))
c++;
if (c > max) {
printf("Unable to cover all active DDR banks: "
"%d, available windows: %d\n", c, max);
return (0);
}
return (1);
}
/**************************************************************************
* DDR windows routines
**************************************************************************/
int
ddr_is_active(int i)
{
if (ddr_sz_read(i) & 0x1)
return (1);
return (0);
}
uint32_t
ddr_base(int i)
{
return (ddr_br_read(i) & 0xff000000);
}
uint32_t
ddr_size(int i)
{
return ((ddr_sz_read(i) | 0x00ffffff) + 1);
}
uint32_t
ddr_attr(int i)
{
return (i == 0 ? 0xe :
(i == 1 ? 0xd :
(i == 2 ? 0xb :
(i == 3 ? 0x7 : 0xff))));
}
uint32_t
ddr_target(int i)
{
/* Mbus unit ID is 0x0 for DDR SDRAM controller */
return (0);
}
/**************************************************************************
* USB windows routines
**************************************************************************/
static int
decode_win_usb_valid(void)
{
return (decode_win_can_cover_ddr(MV_WIN_USB_MAX));
}
/*
* Set USB decode windows.
*/
static void
decode_win_usb_setup(uint32_t ctrl)
{
uint32_t br, cr;
int i, j;
/* Disable and clear all USB windows */
for (i = 0; i < MV_WIN_USB_MAX; i++) {
win_usb_cr_write(i, 0);
win_usb_br_write(i, 0);
}
/* Only access to active DRAM banks is required */
for (i = 0; i < MV_WIN_DDR_MAX; i++)
if (ddr_is_active(i)) {
br = ddr_base(i);
/*
* XXX for 6281 we should handle Mbus write burst limit
* field in the ctrl reg
*/
cr = (((ddr_size(i) - 1) & 0xffff0000) |
(ddr_attr(i) << 8) | (ddr_target(i) << 4) | 1);
/* Set the first free USB window */
for (j = 0; j < MV_WIN_USB_MAX; j++) {
if (win_usb_cr_read(j) & 0x1)
continue;
win_usb_br_write(j, br);
win_usb_cr_write(j, cr);
break;
}
}
}
/**************************************************************************
* ETH windows routines
**************************************************************************/
static int
win_eth_can_remap(int i)
{
/* ETH encode windows 0-3 have remap capability */
if (i < 4)
return (1);
return (0);
}
static int
eth_bare_read(uint32_t base, int i)
{
uint32_t v;
v = win_eth_bare_read(base);
v &= (1 << i);
return (v >> i);
}
static void
eth_bare_write(uint32_t base, int i, int val)
{
uint32_t v;
v = win_eth_bare_read(base);
v &= ~(1 << i);
v |= (val << i);
win_eth_bare_write(base, v);
}
static void
eth_epap_write(uint32_t base, int i, int val)
{
uint32_t v;
v = win_eth_epap_read(base);
v &= ~(0x3 << (i * 2));
v |= (val << (i * 2));
win_eth_epap_write(base, v);
}
static void
decode_win_eth_setup(uint32_t base)
{
uint32_t br, sz;
int i, j;
/* Disable, clear and revoke protection for all ETH windows */
for (i = 0; i < MV_WIN_ETH_MAX; i++) {
eth_bare_write(base, i, 1);
eth_epap_write(base, i, 0);
win_eth_br_write(base, i, 0);
win_eth_sz_write(base, i, 0);
if (win_eth_can_remap(i))
win_eth_har_write(base, i, 0);
}
/* Only access to active DRAM banks is required */
for (i = 0; i < MV_WIN_DDR_MAX; i++)
if (ddr_is_active(i)) {
br = ddr_base(i) | (ddr_attr(i) << 8) | ddr_target(i);
sz = ((ddr_size(i) - 1) & 0xffff0000);
/* Set the first free ETH window */
for (j = 0; j < MV_WIN_ETH_MAX; j++) {
if (eth_bare_read(base, j) == 0)
continue;
win_eth_br_write(base, j, br);
win_eth_sz_write(base, j, sz);
/* XXX remapping ETH windows not supported */
/* Set protection RW */
eth_epap_write(base, j, 0x3);
/* Enable window */
eth_bare_write(base, j, 0);
break;
}
}
}
static int
decode_win_eth_valid(void)
{
return (decode_win_can_cover_ddr(MV_WIN_ETH_MAX));
}
/**************************************************************************
* PCIE windows routines
**************************************************************************/
static void
decode_win_pcie_setup(uint32_t base)
{
uint32_t size = 0;
uint32_t cr, br;
int i, j;
for (i = 0; i < MV_PCIE_BAR_MAX; i++)
pcie_bar_write(base, i, 0);
for (i = 0; i < MV_WIN_PCIE_MAX; i++) {
win_pcie_cr_write(base, i, 0);
win_pcie_br_write(base, i, 0);
win_pcie_remap_write(base, i, 0);
}
for (i = 0; i < MV_WIN_DDR_MAX; i++) {
if (ddr_is_active(i)) {
/* Map DDR to BAR 1 */
cr = (ddr_size(i) - 1) & 0xffff0000;
size += ddr_size(i) & 0xffff0000;
cr |= (ddr_attr(i) << 8) | (ddr_target(i) << 4) | 1;
br = ddr_base(i);
/* Use the first available PCIE window */
for (j = 0; j < MV_WIN_PCIE_MAX; j++) {
if (win_pcie_cr_read(base, j) != 0)
continue;
win_pcie_br_write(base, j, br);
win_pcie_cr_write(base, j, cr);
break;
}
}
}
/*
* Upper 16 bits in BAR register is interpreted as BAR size
* (in 64 kB units) plus 64kB, so substract 0x10000
* form value passed to register to get correct value.
*/
size -= 0x10000;
pcie_bar_write(base, 0, size | 1);
}
static int
decode_win_pcie_valid(void)
{
return (decode_win_can_cover_ddr(MV_WIN_PCIE_MAX));
}
/**************************************************************************
* IDMA windows routines
**************************************************************************/
#if defined(SOC_MV_ORION) || defined(SOC_MV_DISCOVERY)
static int
idma_bare_read(int i)
{
uint32_t v;
v = win_idma_bare_read();
v &= (1 << i);
return (v >> i);
}
static void
idma_bare_write(int i, int val)
{
uint32_t v;
v = win_idma_bare_read();
v &= ~(1 << i);
v |= (val << i);
win_idma_bare_write(v);
}
/*
* Sets channel protection 'val' for window 'w' on channel 'c'
*/
static void
idma_cap_write(int c, int w, int val)
{
uint32_t v;
v = win_idma_cap_read(c);
v &= ~(0x3 << (w * 2));
v |= (val << (w * 2));
win_idma_cap_write(c, v);
}
/*
* Set protection 'val' on all channels for window 'w'
*/
static void
idma_set_prot(int w, int val)
{
int c;
for (c = 0; c < MV_IDMA_CHAN_MAX; c++)
idma_cap_write(c, w, val);
}
static int
win_idma_can_remap(int i)
{
/* IDMA decode windows 0-3 have remap capability */
if (i < 4)
return (1);
return (0);
}
void
decode_win_idma_setup(void)
{
uint32_t br, sz;
int i, j;
/*
* Disable and clear all IDMA windows, revoke protection for all channels
*/
for (i = 0; i < MV_WIN_IDMA_MAX; i++) {
idma_bare_write(i, 1);
win_idma_br_write(i, 0);
win_idma_sz_write(i, 0);
if (win_idma_can_remap(i) == 1)
win_idma_har_write(i, 0);
}
for (i = 0; i < MV_IDMA_CHAN_MAX; i++)
win_idma_cap_write(i, 0);
/*
* Set up access to all active DRAM banks
*/
for (i = 0; i < MV_WIN_DDR_MAX; i++)
if (ddr_is_active(i)) {
br = ddr_base(i) | (ddr_attr(i) << 8) | ddr_target(i);
sz = ((ddr_size(i) - 1) & 0xffff0000);
/* Place DDR entries in non-remapped windows */
for (j = 0; j < MV_WIN_IDMA_MAX; j++)
if (win_idma_can_remap(j) != 1 &&
idma_bare_read(j) == 1) {
/* Configure window */
win_idma_br_write(j, br);
win_idma_sz_write(j, sz);
/* Set protection RW on all channels */
idma_set_prot(j, 0x3);
/* Enable window */
idma_bare_write(j, 0);
break;
}
}
/*
* Remaining targets -- from statically defined table
*/
for (i = 0; i < idma_wins_no; i++)
if (idma_wins[i].target > 0) {
br = (idma_wins[i].base & 0xffff0000) |
(idma_wins[i].attr << 8) | idma_wins[i].target;
sz = ((idma_wins[i].size - 1) & 0xffff0000);
/* Set the first free IDMA window */
for (j = 0; j < MV_WIN_IDMA_MAX; j++) {
if (idma_bare_read(j) == 0)
continue;
/* Configure window */
win_idma_br_write(j, br);
win_idma_sz_write(j, sz);
if (win_idma_can_remap(j) && idma_wins[j].remap >= 0)
win_idma_har_write(j, idma_wins[j].remap);
/* Set protection RW on all channels */
idma_set_prot(j, 0x3);
/* Enable window */
idma_bare_write(j, 0);
break;
}
}
}
int
decode_win_idma_valid(void)
{
const struct decode_win *wintab;
int c, i, j, rv;
uint32_t b, e, s;
if (idma_wins_no > MV_WIN_IDMA_MAX) {
printf("IDMA windows: too many entries: %d\n", idma_wins_no);
return (-1);
}
for (i = 0, c = 0; i < MV_WIN_DDR_MAX; i++)
if (ddr_is_active(i))
c++;
if (idma_wins_no > (MV_WIN_IDMA_MAX - c)) {
printf("IDMA windows: too many entries: %d, available: %d\n",
idma_wins_no, MV_WIN_IDMA_MAX - c);
return (-1);
}
wintab = idma_wins;
rv = 1;
for (i = 0; i < idma_wins_no; i++, wintab++) {
if (wintab->target == 0) {
printf("IDMA window#%d: DDR target window is not supposed "
"to be reprogrammed!\n", i);
rv = 0;
}
if (wintab->remap >= 0 && win_cpu_can_remap(i) != 1) {
printf("IDMA window#%d: not capable of remapping, but "
"val 0x%08x defined\n", i, wintab->remap);
rv = 0;
}
s = wintab->size;
b = wintab->base;
e = b + s - 1;
if (s > (0xFFFFFFFF - b + 1)) {
/* XXX this boundary check should accont for 64bit and
* remapping.. */
printf("IDMA window#%d: no space for size 0x%08x at "
"0x%08x\n", i, s, b);
rv = 0;
continue;
}
j = decode_win_overlap(i, idma_wins_no, &idma_wins[0]);
if (j >= 0) {
printf("IDMA window#%d: (0x%08x - 0x%08x) overlaps with "
"#%d (0x%08x - 0x%08x)\n", i, b, e, j,
idma_wins[j].base,
idma_wins[j].base + idma_wins[j].size - 1);
rv = 0;
}
}
return (rv);
}
void
decode_win_idma_dump(void)
{
int i;
for (i = 0; i < MV_WIN_IDMA_MAX; i++) {
printf("IDMA window#%d: b 0x%08x, s 0x%08x", i,
win_idma_br_read(i), win_idma_sz_read(i));
if (win_idma_can_remap(i))
printf(", ha 0x%08x", win_idma_har_read(i));
printf("\n");
}
for (i = 0; i < MV_IDMA_CHAN_MAX; i++)
printf("IDMA channel#%d: ap 0x%08x\n", i,
win_idma_cap_read(i));
printf("IDMA windows: bare 0x%08x\n", win_idma_bare_read());
}
#else
/* Provide dummy functions to satisfy the build for SoCs not equipped with IDMA */
int
decode_win_idma_valid(void)
{
return (1);
}
void
decode_win_idma_setup(void)
{
}
void
decode_win_idma_dump(void)
{
}
#endif

View file

@ -0,0 +1,110 @@
/*-
* Copyright (C) 2008 MARVELL INTERNATIONAL LTD.
* All rights reserved.
*
* Developed by Semihalf.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of MARVELL nor the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <vm/vm.h>
#include <vm/pmap.h>
#include <machine/pte.h>
#include <machine/pmap.h>
#include <machine/vmparam.h>
#include <arm/mv/mvreg.h>
#include <arm/mv/mvvar.h>
/*
* Virtual address space layout:
* -----------------------------
* 0x0000_0000 - 0xbfff_ffff : user process
*
* 0xc040_0000 - virtual_avail : kernel reserved (text, data, page tables
* : structures, ARM stacks etc.)
* virtual_avail - 0xefff_ffff : KVA (virtual_avail is typically < 0xc0a0_0000)
* 0xf000_0000 - 0xf0ff_ffff : no-cache allocation area (16MB)
* 0xf100_0000 - 0xf10f_ffff : SoC integrated devices registers range (1MB)
* 0xf110_0000 - 0xfffe_ffff : PCIE (MEM+IO) outbound windows (~238MB)
* 0xffff_0000 - 0xffff_0fff : 'high' vectors page (4KB)
* 0xffff_1000 - 0xffff_1fff : ARM_TP_ADDRESS/RAS page (4KB)
* 0xffff_2000 - 0xffff_ffff : unused (~55KB)
*/
const struct pmap_devmap *pmap_devmap_bootstrap_table;
vm_offset_t pmap_bootstrap_lastaddr;
/* Static device mappings. */
static const struct pmap_devmap pmap_devmap[] = {
/*
* Map the on-board devices VA == PA so that we can access them
* with the MMU on or off.
*/
{ /* SoC integrated peripherals registers range */
MV_BASE,
MV_PHYS_BASE,
MV_SIZE,
VM_PROT_READ | VM_PROT_WRITE,
PTE_NOCACHE,
},
{ 0, 0, 0, 0, 0, }
};
int
platform_pmap_init(void)
{
pmap_bootstrap_lastaddr = MV_BASE - ARM_NOCACHE_KVA_SIZE;
pmap_devmap_bootstrap_table = &pmap_devmap[0];
return (0);
}
static void
platform_identify(void *dummy)
{
soc_identify();
/*
* XXX Board identification e.g. read out from FPGA or similar should
* go here
*/
}
SYSINIT(platform_identify, SI_SUB_CPU, SI_ORDER_SECOND, platform_identify, NULL);
/*
* TODO routine setting GPIO/MPP pins
*/

View file

@ -0,0 +1,160 @@
/*-
* Copyright (C) 2008 MARVELL INTERNATIONAL LTD.
* All rights reserved.
*
* Developed by Semihalf.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of MARVELL nor the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <machine/bus.h>
#include <arm/mv/mvreg.h>
#include <arm/mv/mvvar.h>
struct obio_device obio_devices[] = {
{ "ic", MV_IC_BASE, MV_IC_SIZE,
{ -1 },
{ -1 },
CPU_PM_CTRL_NONE
},
{ "timer", MV_TIMERS_BASE, MV_TIMERS_SIZE,
{ MV_INT_TIMER0, -1 },
{ -1 },
CPU_PM_CTRL_NONE
},
{ "gpio", MV_GPIO_BASE, MV_GPIO_SIZE,
{ MV_INT_GPIO7_0, MV_INT_GPIO15_8,
MV_INT_GPIO23_16, MV_INT_GPIO31_24, -1 },
{ -1 },
CPU_PM_CTRL_NONE
},
{ "uart", MV_UART0_BASE, MV_UART_SIZE,
{ MV_INT_UART0, -1 },
{ -1 },
CPU_PM_CTRL_NONE
},
{ "uart", MV_UART1_BASE, MV_UART_SIZE,
{ MV_INT_UART1, -1 },
{ -1 },
CPU_PM_CTRL_NONE
},
{ "idma", MV_IDMA_BASE, MV_IDMA_SIZE,
{ MV_INT_IDMA_ERR, MV_INT_IDMA0, MV_INT_IDMA1,
MV_INT_IDMA2, MV_INT_IDMA3, -1 },
{ -1 },
CPU_PM_CTRL_IDMA
},
{ "xor", MV_XOR_BASE, MV_XOR_SIZE,
{ MV_INT_XOR0, MV_INT_XOR1,
MV_INT_XOR_ERR, -1 },
{ -1 },
CPU_PM_CTRL_XOR
},
{ "ehci", MV_USB0_BASE, MV_USB_SIZE,
{ MV_INT_USB_ERR, MV_INT_USB0, -1 },
{ -1 },
CPU_PM_CTRL_USB0 | CPU_PM_CTRL_USB1 | CPU_PM_CTRL_USB2
},
{ "mge", MV_ETH0_BASE, MV_ETH_SIZE,
{ MV_INT_GBERX, MV_INT_GBETX, MV_INT_GBEMISC,
MV_INT_GBESUM, MV_INT_GBE_ERR, -1 },
{ -1 },
CPU_PM_CTRL_GE0
},
{ "mge", MV_ETH1_BASE, MV_ETH_SIZE,
{ MV_INT_GBE1RX, MV_INT_GBE1TX, MV_INT_GBE1MISC,
MV_INT_GBE1SUM, MV_INT_GBE_ERR, -1 },
{ -1 },
CPU_PM_CTRL_GE1
},
{ "twsi", MV_TWSI_BASE, MV_TWSI_SIZE,
{ -1 }, { -1 },
CPU_PM_CTRL_NONE
},
{ NULL, 0, 0, { 0 }, { 0 }, 0 }
};
struct resource_spec mv_gpio_spec[] = {
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
{ SYS_RES_IRQ, 0, RF_ACTIVE },
{ SYS_RES_IRQ, 1, RF_ACTIVE },
{ SYS_RES_IRQ, 2, RF_ACTIVE },
{ SYS_RES_IRQ, 3, RF_ACTIVE },
{ -1, 0 }
};
struct resource_spec mv_xor_spec[] = {
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
{ SYS_RES_IRQ, 0, RF_ACTIVE },
{ SYS_RES_IRQ, 1, RF_ACTIVE },
{ SYS_RES_IRQ, 2, RF_ACTIVE },
{ -1, 0 }
};
const struct decode_win cpu_win_tbl[] = {
/* PCIE IO */
{ 4, 0x51, MV_PCIE_IO_PHYS_BASE, MV_PCIE_IO_SIZE, -1 },
/* PCIE MEM */
{ 4, 0x59, MV_PCIE_MEM_PHYS_BASE, MV_PCIE_MEM_SIZE, -1 },
/* Device bus BOOT */
{ 1, 0x2f, MV_DEV_BOOT_PHYS_BASE, MV_DEV_BOOT_SIZE, -1 },
/* Device bus CS0 */
{ 1, 0x3e, MV_DEV_CS0_PHYS_BASE, MV_DEV_CS0_SIZE, -1 },
/* Device bus CS1 */
{ 1, 0x3d, MV_DEV_CS1_PHYS_BASE, MV_DEV_CS1_SIZE, -1 },
/* Device bus CS2 */
{ 1, 0x3b, MV_DEV_CS2_PHYS_BASE, MV_DEV_CS2_SIZE, -1 },
};
const struct decode_win *cpu_wins = cpu_win_tbl;
int cpu_wins_no = sizeof(cpu_win_tbl) / sizeof(struct decode_win);
/*
* Note: the decode windows table for IDMA does not explicitly have DRAM
* entries, which are not statically defined: active DDR banks (== windows)
* are established in run time from actual DDR windows settings. All active
* DDR banks are mapped into IDMA decode windows, so at least one IDMA decode
* window is occupied by the DDR bank; in case when all (MV_WIN_DDR_MAX)
* DDR banks are active, the remaining available IDMA decode windows for other
* targets is only MV_WIN_IDMA_MAX - MV_WIN_DDR_MAX.
*/
const struct decode_win idma_win_tbl[] = {
/* PCIE MEM */
{ 4, 0x59, MV_PCIE_MEM_PHYS_BASE, MV_PCIE_MEM_SIZE, -1 },
};
const struct decode_win *idma_wins = idma_win_tbl;
int idma_wins_no = sizeof(idma_win_tbl) / sizeof(struct decode_win);

View file

@ -0,0 +1,4 @@
# $FreeBSD$
arm/mv/discovery/discovery.c standard
arm/mv/discovery/db78xxx.c standard

View file

@ -0,0 +1,13 @@
# $FreeBSD$
include "../mv/std.mv"
files "../mv/discovery/files.db78xxx"
makeoptions KERNPHYSADDR=0x00900000
makeoptions KERNVIRTADDR=0xc0900000
options KERNPHYSADDR=0x00900000
options KERNVIRTADDR=0xc0900000
options PHYSADDR=0x00000000
options PHYSMEM_SIZE=0x20000000
options STARTUP_PAGETABLE_ADDR=0x00100000

34
sys/arm/mv/files.mv Normal file
View file

@ -0,0 +1,34 @@
# $FreeBSD$
#
# The Marvell CPU cores
# - Compliant with V5TE architecture
# - Super scalar dual issue CPU
# - Big/Little Endian
# - MMU/MPU
# - L1 Cache: Supports streaming and write allocate
# - Variable pipeline stages
# - Out-of-order execution
# - Branch Prediction
# - JTAG/ICE
# - Vector Floating Point (VFP) unit
#
arm/arm/bus_space_generic.c standard
arm/arm/cpufunc_asm_arm10.S standard
arm/arm/cpufunc_asm_armv5_ec.S standard
arm/arm/cpufunc_asm_feroceon.S standard
arm/arm/irq_dispatch.S standard
arm/mv/bus_space.c standard
arm/mv/common.c standard
arm/mv/gpio.c standard
arm/mv/ic.c standard
arm/mv/mv_machdep.c standard
arm/mv/obio.c standard
arm/mv/timer.c standard
arm/mv/twsi.c optional iicbus
dev/mge/if_mge.c optional mge
dev/uart/uart_bus_mbus.c optional uart
dev/uart/uart_cpu_mv.c optional uart
dev/uart/uart_dev_ns8250.c optional uart
dev/usb/ehci_mbus.c optional ehci

516
sys/arm/mv/gpio.c Normal file
View file

@ -0,0 +1,516 @@
/*-
* Copyright (c) 2006 Benno Rice.
* Copyright (C) 2008 MARVELL INTERNATIONAL LTD.
* All rights reserved.
*
* Adapted and extended for Marvell SoCs by Semihalf.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* from: FreeBSD: //depot/projects/arm/src/sys/arm/xscale/pxa2x0/pxa2x0_gpio.c, rev 1
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/interrupt.h>
#include <sys/module.h>
#include <sys/malloc.h>
#include <sys/mutex.h>
#include <sys/rman.h>
#include <sys/queue.h>
#include <sys/timetc.h>
#include <machine/bus.h>
#include <machine/intr.h>
#include <arm/mv/mvvar.h>
#include <arm/mv/mvreg.h>
#define GPIO_MAX_INTR_COUNT 8
#define GPIO_PINS_PER_REG 32
struct mv_gpio_softc {
struct resource * res[GPIO_MAX_INTR_COUNT + 1];
void *ih_cookie[GPIO_MAX_INTR_COUNT];
bus_space_tag_t bst;
bus_space_handle_t bsh;
uint8_t pin_num; /* number of GPIO pins */
uint8_t irq_num; /* number of real IRQs occupied by GPIO controller */
uint8_t use_high;
};
extern struct resource_spec mv_gpio_spec[];
static struct mv_gpio_softc *mv_gpio_softc = NULL;
static uint32_t gpio_setup[MV_GPIO_MAX_NPINS];
static int mv_gpio_probe(device_t);
static int mv_gpio_attach(device_t);
static void mv_gpio_intr(void *);
static void mv_gpio_intr_handler(int pin);
static uint32_t mv_gpio_reg_read(uint32_t reg);
static void mv_gpio_reg_write(uint32_t reg, uint32_t val);
static void mv_gpio_reg_set(uint32_t reg, uint32_t val);
static void mv_gpio_reg_clear(uint32_t reg, uint32_t val);
static void mv_gpio_blink(uint32_t pin, uint8_t enable);
static void mv_gpio_polarity(uint32_t pin, uint8_t enable);
static void mv_gpio_level(uint32_t pin, uint8_t enable);
static void mv_gpio_edge(uint32_t pin, uint8_t enable);
static void mv_gpio_out_en(uint32_t pin, uint8_t enable);
static void mv_gpio_int_ack(uint32_t pin);
static void mv_gpio_value_set(uint32_t pin, uint8_t val);
static uint32_t mv_gpio_value_get(uint32_t pin);
static device_method_t mv_gpio_methods[] = {
DEVMETHOD(device_probe, mv_gpio_probe),
DEVMETHOD(device_attach, mv_gpio_attach),
{ 0, 0 }
};
static driver_t mv_gpio_driver = {
"gpio",
mv_gpio_methods,
sizeof(struct mv_gpio_softc),
};
static devclass_t mv_gpio_devclass;
DRIVER_MODULE(gpio, mbus, mv_gpio_driver, mv_gpio_devclass, 0, 0);
static int
mv_gpio_probe(device_t dev)
{
device_set_desc(dev, "Marvell Integrated GPIO Controller");
return (0);
}
static int
mv_gpio_attach(device_t dev)
{
int error, i;
struct mv_gpio_softc *sc;
uint32_t dev_id, rev_id;
sc = (struct mv_gpio_softc *)device_get_softc(dev);
if (mv_gpio_softc != NULL)
return (ENXIO);
mv_gpio_softc = sc;
/* Get board id and revision */
soc_id(&dev_id, &rev_id);
if (dev_id == MV_DEV_88F5182 ||
dev_id == MV_DEV_88F5281 ||
dev_id == MV_DEV_MV78100) {
sc->pin_num = 32;
sc->irq_num = 4;
sc->use_high = 0;
} else if (dev_id == MV_DEV_88F6281) {
sc->pin_num = 50;
sc->irq_num = 7;
sc->use_high = 1;
} else {
device_printf(dev, "unknown board id=0x%x\n", dev_id);
return (ENXIO);
}
error = bus_alloc_resources(dev, mv_gpio_spec, sc->res);
if (error) {
device_printf(dev, "could not allocate resources\n");
return (ENXIO);
}
sc->bst = rman_get_bustag(sc->res[0]);
sc->bsh = rman_get_bushandle(sc->res[0]);
/* Disable and clear all interrupts */
bus_space_write_4(sc->bst, sc->bsh, GPIO_INT_EDGE_MASK, 0);
bus_space_write_4(sc->bst, sc->bsh, GPIO_INT_LEV_MASK, 0);
bus_space_write_4(sc->bst, sc->bsh, GPIO_INT_CAUSE, 0);
if (sc->use_high) {
bus_space_write_4(sc->bst, sc->bsh,
GPIO_HI_INT_EDGE_MASK, 0);
bus_space_write_4(sc->bst, sc->bsh,
GPIO_HI_INT_LEV_MASK, 0);
bus_space_write_4(sc->bst, sc->bsh,
GPIO_HI_INT_CAUSE, 0);
}
for (i = 0; i < sc->irq_num; i++) {
if (bus_setup_intr(dev, sc->res[1 + i],
INTR_TYPE_MISC | INTR_FAST,
(driver_filter_t *)mv_gpio_intr, NULL,
sc, &sc->ih_cookie[i]) != 0) {
bus_release_resources(dev, mv_gpio_spec, sc->res);
device_printf(dev, "could not set up intr %d\n", i);
return (ENXIO);
}
}
return (0);
}
static void
mv_gpio_intr(void *arg)
{
uint32_t int_cause, gpio_val;
uint32_t int_cause_hi, gpio_val_hi = 0;
int i;
int_cause = mv_gpio_reg_read(GPIO_INT_CAUSE);
gpio_val = mv_gpio_reg_read(GPIO_DATA_IN);
gpio_val &= int_cause;
if (mv_gpio_softc->use_high) {
int_cause_hi = mv_gpio_reg_read(GPIO_HI_INT_CAUSE);
gpio_val_hi = mv_gpio_reg_read(GPIO_HI_DATA_IN);
gpio_val_hi &= int_cause_hi;
}
i = 0;
while (gpio_val != 0) {
if (gpio_val & 1)
mv_gpio_intr_handler(i);
gpio_val >>= 1;
i++;
}
if (mv_gpio_softc->use_high) {
i = 0;
while (gpio_val_hi != 0) {
if (gpio_val_hi & 1)
mv_gpio_intr_handler(i + GPIO_PINS_PER_REG);
gpio_val_hi >>= 1;
i++;
}
}
}
/*
* GPIO interrupt handling
*/
static struct intr_event *gpio_events[MV_GPIO_MAX_NPINS];
int
mv_gpio_setup_intrhandler(const char *name, driver_filter_t *filt,
void (*hand)(void *), void *arg, int pin, int flags, void **cookiep)
{
struct intr_event *event;
int error;
if (pin < 0 || pin >= mv_gpio_softc->pin_num)
return (ENXIO);
event = gpio_events[pin];
if (event == NULL) {
error = intr_event_create(&event, (void *)pin, 0, pin,
(void (*)(void *))mv_gpio_intr_mask,
(void (*)(void *))mv_gpio_intr_unmask,
(void (*)(void *))mv_gpio_int_ack,
NULL,
"gpio%d:", pin);
if (error != 0)
return (error);
gpio_events[pin] = event;
}
intr_event_add_handler(event, name, filt, hand, arg, intr_priority(flags),
flags, cookiep);
return (0);
}
void
mv_gpio_intr_mask(int pin)
{
if (pin >= mv_gpio_softc->pin_num)
return;
if (gpio_setup[pin] & MV_GPIO_EDGE)
mv_gpio_edge(pin, 0);
else
mv_gpio_level(pin, 0);
}
void
mv_gpio_intr_unmask(int pin)
{
if (pin >= mv_gpio_softc->pin_num)
return;
if (gpio_setup[pin] & MV_GPIO_EDGE)
mv_gpio_edge(pin, 1);
else
mv_gpio_level(pin, 1);
}
static void
mv_gpio_intr_handler(int pin)
{
struct intr_event *event;
event = gpio_events[pin];
if (event == NULL || TAILQ_EMPTY(&event->ie_handlers))
return;
intr_event_handle(event, NULL);
}
int
mv_gpio_configure(uint32_t pin, uint32_t flags, uint32_t mask)
{
if (pin >= mv_gpio_softc->pin_num)
return (EINVAL);
if (mask & MV_GPIO_BLINK)
mv_gpio_blink(pin, flags & MV_GPIO_BLINK);
if (mask & MV_GPIO_POLARITY)
mv_gpio_polarity(pin, flags & MV_GPIO_POLARITY);
if (mask & MV_GPIO_EDGE)
mv_gpio_edge(pin, flags & MV_GPIO_EDGE);
if (mask & MV_GPIO_LEVEL)
mv_gpio_level(pin, flags & MV_GPIO_LEVEL);
gpio_setup[pin] &= ~(mask);
gpio_setup[pin] |= (flags & mask);
return (0);
}
void
mv_gpio_out(uint32_t pin, uint8_t val, uint8_t enable)
{
mv_gpio_value_set(pin, val);
mv_gpio_out_en(pin, enable);
}
uint8_t
mv_gpio_in(uint32_t pin)
{
return (mv_gpio_value_get(pin));
}
static uint32_t
mv_gpio_reg_read(uint32_t reg)
{
return (bus_space_read_4(mv_gpio_softc->bst,
mv_gpio_softc->bsh, reg));
}
static void
mv_gpio_reg_write(uint32_t reg, uint32_t val)
{
bus_space_write_4(mv_gpio_softc->bst,
mv_gpio_softc->bsh, reg, val);
}
static void
mv_gpio_reg_set(uint32_t reg, uint32_t pin)
{
uint32_t reg_val;
reg_val = mv_gpio_reg_read(reg);
reg_val |= GPIO(pin);
mv_gpio_reg_write(reg, reg_val);
}
static void
mv_gpio_reg_clear(uint32_t reg, uint32_t pin)
{
uint32_t reg_val;
reg_val = mv_gpio_reg_read(reg);
reg_val &= ~(GPIO(pin));
mv_gpio_reg_write(reg, reg_val);
}
static void
mv_gpio_out_en(uint32_t pin, uint8_t enable)
{
uint32_t reg;
if (pin >= mv_gpio_softc->pin_num)
return;
if (pin >= GPIO_PINS_PER_REG) {
reg = GPIO_HI_DATA_OUT_EN_CTRL;
pin -= GPIO_PINS_PER_REG;
} else
reg = GPIO_DATA_OUT_EN_CTRL;
if (enable)
mv_gpio_reg_clear(reg, pin);
else
mv_gpio_reg_set(reg, pin);
}
static void
mv_gpio_blink(uint32_t pin, uint8_t enable)
{
uint32_t reg;
if (pin >= mv_gpio_softc->pin_num)
return;
if (pin >= GPIO_PINS_PER_REG) {
reg = GPIO_HI_BLINK_EN;
pin -= GPIO_PINS_PER_REG;
} else
reg = GPIO_BLINK_EN;
if (enable)
mv_gpio_reg_set(reg, pin);
else
mv_gpio_reg_clear(reg, pin);
}
static void
mv_gpio_polarity(uint32_t pin, uint8_t enable)
{
uint32_t reg;
if (pin >= mv_gpio_softc->pin_num)
return;
if (pin >= GPIO_PINS_PER_REG) {
reg = GPIO_HI_DATA_IN_POLAR;
pin -= GPIO_PINS_PER_REG;
} else
reg = GPIO_DATA_IN_POLAR;
if (enable)
mv_gpio_reg_set(reg, pin);
else
mv_gpio_reg_clear(reg, pin);
}
static void
mv_gpio_level(uint32_t pin, uint8_t enable)
{
uint32_t reg;
if (pin >= mv_gpio_softc->pin_num)
return;
if (pin >= GPIO_PINS_PER_REG) {
reg = GPIO_HI_INT_LEV_MASK;
pin -= GPIO_PINS_PER_REG;
} else
reg = GPIO_INT_LEV_MASK;
if (enable)
mv_gpio_reg_set(reg, pin);
else
mv_gpio_reg_clear(reg, pin);
}
static void
mv_gpio_edge(uint32_t pin, uint8_t enable)
{
uint32_t reg;
if (pin >= mv_gpio_softc->pin_num)
return;
if (pin >= GPIO_PINS_PER_REG) {
reg = GPIO_HI_INT_EDGE_MASK;
pin -= GPIO_PINS_PER_REG;
} else
reg = GPIO_INT_EDGE_MASK;
if (enable)
mv_gpio_reg_set(reg, pin);
else
mv_gpio_reg_clear(reg, pin);
}
static void
mv_gpio_int_ack(uint32_t pin)
{
uint32_t reg;
if (pin >= mv_gpio_softc->pin_num)
return;
if (pin >= GPIO_PINS_PER_REG) {
reg = GPIO_HI_INT_CAUSE;
pin -= GPIO_PINS_PER_REG;
} else
reg = GPIO_INT_CAUSE;
mv_gpio_reg_clear(reg, pin);
}
static uint32_t
mv_gpio_value_get(uint32_t pin)
{
uint32_t reg, reg_val;
if (pin >= mv_gpio_softc->pin_num)
return (0);
if (pin >= GPIO_PINS_PER_REG) {
reg = GPIO_HI_DATA_IN;
pin -= GPIO_PINS_PER_REG;
} else
reg = GPIO_DATA_IN;
reg_val = mv_gpio_reg_read(reg);
return (reg_val & GPIO(pin));
}
static void
mv_gpio_value_set(uint32_t pin, uint8_t val)
{
uint32_t reg;
if (pin >= mv_gpio_softc->pin_num)
return;
if (pin >= GPIO_PINS_PER_REG) {
reg = GPIO_HI_DATA_OUT;
pin -= GPIO_PINS_PER_REG;
} else
reg = GPIO_DATA_OUT;
if (val)
mv_gpio_reg_set(reg, pin);
else
mv_gpio_reg_clear(reg, pin);
}

289
sys/arm/mv/ic.c Normal file
View file

@ -0,0 +1,289 @@
/*-
* Copyright (c) 2006 Benno Rice.
* Copyright (C) 2007-2008 MARVELL INTERNATIONAL LTD.
* All rights reserved.
*
* Adapted and extended to Marvell SoCs by Semihalf.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* from: FreeBSD: //depot/projects/arm/src/sys/arm/xscale/pxa2x0/pxa2x0_icu.c, rev 1
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/rman.h>
#include <machine/bus.h>
#include <machine/intr.h>
#include <arm/mv/mvreg.h>
#include <arm/mv/mvvar.h>
struct mv_ic_softc {
struct resource * ic_res[1];
bus_space_tag_t ic_bst;
bus_space_handle_t ic_bsh;
int ic_high_regs;
int ic_error_regs;
};
static struct resource_spec mv_ic_spec[] = {
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
{ -1, 0 }
};
static struct mv_ic_softc *mv_ic_sc = NULL;
static int mv_ic_probe(device_t);
static int mv_ic_attach(device_t);
uint32_t mv_ic_get_cause(void);
uint32_t mv_ic_get_mask(void);
void mv_ic_set_mask(uint32_t);
uint32_t mv_ic_get_cause_hi(void);
uint32_t mv_ic_get_mask_hi(void);
void mv_ic_set_mask_hi(uint32_t);
uint32_t mv_ic_get_cause_error(void);
uint32_t mv_ic_get_mask_error(void);
void mv_ic_set_mask_error(uint32_t);
static void arm_mask_irq_all(void);
static int
mv_ic_probe(device_t dev)
{
device_set_desc(dev, "Marvell Integrated Interrupt Controller");
return (0);
}
static int
mv_ic_attach(device_t dev)
{
struct mv_ic_softc *sc;
uint32_t dev_id, rev_id;
int error;
sc = (struct mv_ic_softc *)device_get_softc(dev);
if (mv_ic_sc != NULL)
return (ENXIO);
mv_ic_sc = sc;
soc_id(&dev_id, &rev_id);
sc->ic_high_regs = 0;
sc->ic_error_regs = 0;
if (dev_id == MV_DEV_88F6281 || dev_id == MV_DEV_MV78100)
sc->ic_high_regs = 1;
if (dev_id == MV_DEV_MV78100)
sc->ic_error_regs = 1;
error = bus_alloc_resources(dev, mv_ic_spec, sc->ic_res);
if (error) {
device_printf(dev, "could not allocate resources\n");
return (ENXIO);
}
sc->ic_bst = rman_get_bustag(sc->ic_res[0]);
sc->ic_bsh = rman_get_bushandle(sc->ic_res[0]);
/* Mask all interrupts */
arm_mask_irq_all();
return (0);
}
static device_method_t mv_ic_methods[] = {
DEVMETHOD(device_probe, mv_ic_probe),
DEVMETHOD(device_attach, mv_ic_attach),
{ 0, 0 }
};
static driver_t mv_ic_driver = {
"ic",
mv_ic_methods,
sizeof(struct mv_ic_softc),
};
static devclass_t mv_ic_devclass;
DRIVER_MODULE(ic, mbus, mv_ic_driver, mv_ic_devclass, 0, 0);
int
arm_get_next_irq(void)
{
int irq;
irq = mv_ic_get_cause() & mv_ic_get_mask();
if (irq)
return (ffs(irq) - 1);
if (mv_ic_sc->ic_high_regs) {
irq = mv_ic_get_cause_hi() & mv_ic_get_mask_hi();
if (irq)
return (ffs(irq) + 31);
}
if (mv_ic_sc->ic_error_regs) {
irq = mv_ic_get_cause_error() & mv_ic_get_mask_error();
if (irq)
return (ffs(irq) + 63);
}
return (-1);
}
static void
arm_mask_irq_all(void)
{
mv_ic_set_mask(0);
if (mv_ic_sc->ic_high_regs)
mv_ic_set_mask_hi(0);
if (mv_ic_sc->ic_error_regs)
mv_ic_set_mask_error(0);
}
void
arm_mask_irq(uintptr_t nb)
{
uint32_t mr;
if (nb < 32) {
mr = mv_ic_get_mask();
mr &= ~(1 << nb);
mv_ic_set_mask(mr);
} else if ((nb < 64) && mv_ic_sc->ic_high_regs) {
mr = mv_ic_get_mask_hi();
mr &= ~(1 << (nb - 32));
mv_ic_set_mask_hi(mr);
} else if ((nb < 96) && mv_ic_sc->ic_error_regs) {
mr = mv_ic_get_mask_error();
mr &= ~(1 << (nb - 64));
mv_ic_set_mask_error(mr);
}
}
void
arm_unmask_irq(uintptr_t nb)
{
uint32_t mr;
if (nb < 32) {
mr = mv_ic_get_mask();
mr |= (1 << nb);
mv_ic_set_mask(mr);
} else if ((nb < 64) && mv_ic_sc->ic_high_regs) {
mr = mv_ic_get_mask_hi();
mr |= (1 << (nb - 32));
mv_ic_set_mask_hi(mr);
} else if ((nb < 96) && mv_ic_sc->ic_error_regs) {
mr = mv_ic_get_mask_error();
mr |= (1 << (nb - 64));
mv_ic_set_mask_error(mr);
}
}
void
mv_ic_set_mask(uint32_t val)
{
bus_space_write_4(mv_ic_sc->ic_bst, mv_ic_sc->ic_bsh,
IRQ_MASK, val);
}
uint32_t
mv_ic_get_mask(void)
{
return (bus_space_read_4(mv_ic_sc->ic_bst,
mv_ic_sc->ic_bsh, IRQ_MASK));
}
uint32_t
mv_ic_get_cause(void)
{
return (bus_space_read_4(mv_ic_sc->ic_bst,
mv_ic_sc->ic_bsh, IRQ_CAUSE));
}
void
mv_ic_set_mask_hi(uint32_t val)
{
bus_space_write_4(mv_ic_sc->ic_bst, mv_ic_sc->ic_bsh,
IRQ_MASK_HI, val);
}
uint32_t
mv_ic_get_mask_hi(void)
{
return (bus_space_read_4(mv_ic_sc->ic_bst,
mv_ic_sc->ic_bsh, IRQ_MASK_HI));
}
uint32_t
mv_ic_get_cause_hi(void)
{
return (bus_space_read_4(mv_ic_sc->ic_bst,
mv_ic_sc->ic_bsh, IRQ_CAUSE_HI));
}
void
mv_ic_set_mask_error(uint32_t val)
{
bus_space_write_4(mv_ic_sc->ic_bst, mv_ic_sc->ic_bsh,
IRQ_MASK_ERROR, val);
}
uint32_t
mv_ic_get_mask_error(void)
{
return (bus_space_read_4(mv_ic_sc->ic_bst,
mv_ic_sc->ic_bsh, IRQ_MASK_ERROR));
}
uint32_t
mv_ic_get_cause_error(void)
{
return (bus_space_read_4(mv_ic_sc->ic_bst,
mv_ic_sc->ic_bsh, IRQ_CAUSE_ERROR));
}

View file

@ -0,0 +1,124 @@
/*-
* Copyright (C) 2008 MARVELL INTERNATIONAL LTD.
* All rights reserved.
*
* Developed by Semihalf.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of MARVELL nor the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <vm/vm.h>
#include <vm/pmap.h>
#include <machine/pte.h>
#include <machine/pmap.h>
#include <machine/vmparam.h>
#include <arm/mv/mvreg.h>
#include <arm/mv/mvvar.h>
/*
* Virtual address space layout:
* -----------------------------
* 0x0000_0000 - 0xbfff_ffff : user process
*
* 0xc040_0000 - virtual_avail : kernel reserved (text, data, page tables
* : structures, ARM stacks etc.)
* virtual_avail - 0xefff_ffff : KVA (virtual_avail is typically < 0xc0a0_0000)
* 0xf000_0000 - 0xf0ff_ffff : no-cache allocation area (16MB)
* 0xf100_0000 - 0xf10f_ffff : SoC integrated devices registers range (1MB)
* 0xf110_0000 - 0xfffe_ffff : PCIE (MEM+IO) outbound windows (~238MB)
* 0xffff_0000 - 0xffff_0fff : 'high' vectors page (4KB)
* 0xffff_1000 - 0xffff_1fff : ARM_TP_ADDRESS/RAS page (4KB)
* 0xffff_2000 - 0xffff_ffff : unused (~55KB)
*/
const struct pmap_devmap *pmap_devmap_bootstrap_table;
vm_offset_t pmap_bootstrap_lastaddr;
/* Static device mappings. */
static const struct pmap_devmap pmap_devmap[] = {
/*
* Map the on-board devices VA == PA so that we can access them
* with the MMU on or off.
*/
{ /* SoC integrated peripherals registers range */
MV_BASE,
MV_PHYS_BASE,
MV_SIZE,
VM_PROT_READ | VM_PROT_WRITE,
PTE_NOCACHE,
},
{ /* PCIE I/O */
MV_PCIE_IO_BASE,
MV_PCIE_IO_PHYS_BASE,
MV_PCIE_IO_SIZE,
VM_PROT_READ | VM_PROT_WRITE,
PTE_NOCACHE,
},
{ /* PCIE Memory */
MV_PCIE_MEM_BASE,
MV_PCIE_MEM_PHYS_BASE,
MV_PCIE_MEM_SIZE,
VM_PROT_READ | VM_PROT_WRITE,
PTE_NOCACHE,
},
{ 0, 0, 0, 0, 0, }
};
int
platform_pmap_init(void)
{
pmap_bootstrap_lastaddr = MV_BASE - ARM_NOCACHE_KVA_SIZE;
pmap_devmap_bootstrap_table = &pmap_devmap[0];
return (0);
}
static void
platform_identify(void *dummy)
{
soc_identify();
/*
* XXX Board identification e.g. read out from FPGA or similar should
* go here
*/
}
SYSINIT(platform_identify, SI_SUB_CPU, SI_ORDER_SECOND, platform_identify, NULL);
/*
* TODO routine setting GPIO/MPP pins
*/

View file

@ -0,0 +1,5 @@
# $FreeBSD$
arm/mv/rtc.c standard
arm/mv/kirkwood/kirkwood.c standard
arm/mv/kirkwood/db88f6xxx.c standard

View file

@ -0,0 +1,161 @@
/*-
* Copyright (C) 2008 MARVELL INTERNATIONAL LTD.
* All rights reserved.
*
* Developed by Semihalf.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of MARVELL nor the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <machine/bus.h>
#include <arm/mv/mvreg.h>
#include <arm/mv/mvvar.h>
struct obio_device obio_devices[] = {
{ "ic", MV_IC_BASE, MV_IC_SIZE,
{ -1 },
{ -1 },
CPU_PM_CTRL_NONE
},
{ "timer", MV_TIMERS_BASE, MV_TIMERS_SIZE,
{ MV_INT_BRIDGE, -1 },
{ -1 },
CPU_PM_CTRL_NONE
},
{ "rtc", MV_RTC_BASE, MV_RTC_SIZE,
{ -1 },
{ -1 },
CPU_PM_CTRL_NONE
},
{ "gpio", MV_GPIO_BASE, MV_GPIO_SIZE,
{ MV_INT_GPIO7_0, MV_INT_GPIO15_8,
MV_INT_GPIO23_16, MV_INT_GPIO31_24,
MV_INT_GPIOHI7_0, MV_INT_GPIOHI15_8,
MV_INT_GPIOHI23_16, -1 },
{ -1 },
CPU_PM_CTRL_NONE
},
{ "uart", MV_UART0_BASE, MV_UART_SIZE,
{ MV_INT_UART0, -1 },
{ -1 },
CPU_PM_CTRL_NONE
},
{ "uart", MV_UART1_BASE, MV_UART_SIZE,
{ MV_INT_UART1, -1 },
{ -1 },
CPU_PM_CTRL_NONE
},
{ "xor", MV_XOR_BASE, MV_XOR_SIZE,
{ MV_INT_XOR0_CHAN0, MV_INT_XOR0_CHAN1,
MV_INT_XOR1_CHAN0, MV_INT_XOR1_CHAN1,
MV_INT_XOR0_ERR, MV_INT_XOR1_ERR,
-1 },
{ -1 },
CPU_PM_CTRL_XOR0 | CPU_PM_CTRL_XOR1
},
{ "ehci", MV_USB0_BASE, MV_USB_SIZE,
{ MV_INT_USB_BERR, MV_INT_USB_CI, -1 },
{ -1 },
CPU_PM_CTRL_USB0
},
{ "mge", MV_ETH0_BASE, MV_ETH_SIZE,
{ MV_INT_GBERX, MV_INT_GBETX, MV_INT_GBEMISC,
MV_INT_GBESUM, MV_INT_GBEERR, -1 },
{ -1 },
CPU_PM_CTRL_GE0
},
{ "twsi", MV_TWSI_BASE, MV_TWSI_SIZE,
{ -1 }, { -1 },
CPU_PM_CTRL_NONE
},
{ "pcib", MV_PCIE_BASE, MV_PCIE_SIZE,
{ MV_INT_PEX0_ERR, -1 },
{ -1 },
CPU_PM_CTRL_PEX0
},
{ NULL, 0, 0, { 0 }, { 0 }, 0 }
};
#if 0
const struct mv_pci_info pci_info[] = {
{ 1, MV_PCIE_IO_BASE, MV_PCIE_IO_SIZE,
MV_PCIE_MEM_BASE, MV_PCIE_MEM_SIZE,
NULL, MV_INT_PEX0
}
};
#endif
struct resource_spec mv_gpio_spec[] = {
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
{ SYS_RES_IRQ, 0, RF_ACTIVE },
{ SYS_RES_IRQ, 1, RF_ACTIVE },
{ SYS_RES_IRQ, 2, RF_ACTIVE },
{ SYS_RES_IRQ, 3, RF_ACTIVE },
{ SYS_RES_IRQ, 4, RF_ACTIVE },
{ SYS_RES_IRQ, 5, RF_ACTIVE },
{ SYS_RES_IRQ, 6, RF_ACTIVE },
{ -1, 0 }
};
struct resource_spec mv_xor_spec[] = {
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
{ SYS_RES_IRQ, 0, RF_ACTIVE },
{ SYS_RES_IRQ, 1, RF_ACTIVE },
{ SYS_RES_IRQ, 2, RF_ACTIVE },
{ SYS_RES_IRQ, 3, RF_ACTIVE },
{ SYS_RES_IRQ, 4, RF_ACTIVE },
{ SYS_RES_IRQ, 5, RF_ACTIVE },
{ -1, 0 }
};
const struct decode_win cpu_win_tbl[] = {
/* PCIE IO */
{ 4, 0xE0, MV_PCIE_IO_PHYS_BASE, MV_PCIE_IO_SIZE, -1 },
/* PCIE MEM */
{ 4, 0xE8, MV_PCIE_MEM_PHYS_BASE, MV_PCIE_MEM_SIZE, -1 },
/* Device bus BOOT */
{ 1, 0x0f, MV_DEV_BOOT_PHYS_BASE, MV_DEV_BOOT_SIZE, -1 },
/* Device bus CS0 */
{ 1, 0x1e, MV_DEV_CS0_PHYS_BASE, MV_DEV_CS0_SIZE, -1 },
/* Device bus CS1 */
{ 1, 0x1d, MV_DEV_CS1_PHYS_BASE, MV_DEV_CS1_SIZE, -1 },
/* Device bus CS2 */
{ 1, 0x1b, MV_DEV_CS2_PHYS_BASE, MV_DEV_CS2_SIZE, -1 },
};
const struct decode_win *cpu_wins = cpu_win_tbl;
int cpu_wins_no = sizeof(cpu_win_tbl) / sizeof(struct decode_win);

View file

@ -0,0 +1,13 @@
# $FreeBSD$
include "../mv/std.mv"
files "../mv/kirkwood/files.db88f6xxx"
makeoptions KERNPHYSADDR=0x00900000
makeoptions KERNVIRTADDR=0xc0900000
options KERNPHYSADDR=0x00900000
options KERNVIRTADDR=0xc0900000
options PHYSADDR=0x00000000
options PHYSMEM_SIZE=0x20000000
options STARTUP_PAGETABLE_ADDR=0x00100000

643
sys/arm/mv/mv_machdep.c Normal file
View file

@ -0,0 +1,643 @@
/*-
* Copyright (c) 1994-1998 Mark Brinicombe.
* Copyright (c) 1994 Brini.
* All rights reserved.
*
* This code is derived from software written for Brini by Mark Brinicombe
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Brini.
* 4. The name of the company nor the name of the author may be used to
* endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* from: FreeBSD: //depot/projects/arm/src/sys/arm/at91/kb920x_machdep.c, rev 45
*/
#include "opt_msgbuf.h"
#include "opt_ddb.h"
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#define _ARM32_BUS_DMA_PRIVATE
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/sysproto.h>
#include <sys/signalvar.h>
#include <sys/imgact.h>
#include <sys/kernel.h>
#include <sys/ktr.h>
#include <sys/linker.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mutex.h>
#include <sys/pcpu.h>
#include <sys/proc.h>
#include <sys/ptrace.h>
#include <sys/cons.h>
#include <sys/bio.h>
#include <sys/bus.h>
#include <sys/buf.h>
#include <sys/exec.h>
#include <sys/kdb.h>
#include <sys/msgbuf.h>
#include <machine/reg.h>
#include <machine/cpu.h>
#include <vm/vm.h>
#include <vm/pmap.h>
#include <vm/vm_object.h>
#include <vm/vm_page.h>
#include <vm/vm_pager.h>
#include <vm/vm_map.h>
#include <vm/vnode_pager.h>
#include <machine/pte.h>
#include <machine/pmap.h>
#include <machine/vmparam.h>
#include <machine/pcb.h>
#include <machine/undefined.h>
#include <machine/machdep.h>
#include <machine/metadata.h>
#include <machine/armreg.h>
#include <machine/bus.h>
#include <sys/reboot.h>
#include <machine/bootinfo.h>
#include <arm/mv/mvvar.h> /* XXX eventually this should be eliminated */
#ifdef DEBUG
#define debugf(fmt, args...) printf(fmt, ##args)
#else
#define debugf(fmt, args...)
#endif
#define KERNEL_PT_SYS 0 /* Page table for mapping proc0 zero page */
#define KERNEL_PT_KERN 1
/*
* This is the number of L2 page tables required for covering max
* (hypothetical) memsize of 4GB and all kernel mappings (vectors, msgbuf,
* stacks etc.), uprounded to be divisible by 4.
*/
#define KERNEL_PT_MAX 78
/* Define various stack sizes in pages */
#define IRQ_STACK_SIZE 1
#define ABT_STACK_SIZE 1
#define UND_STACK_SIZE 1
/* Maximum number of memory regions */
#define MEM_REGIONS 8
extern unsigned char kernbase[];
extern unsigned char _etext[];
extern unsigned char _edata[];
extern unsigned char __bss_start[];
extern unsigned char _end[];
extern u_int data_abort_handler_address;
extern u_int prefetch_abort_handler_address;
extern u_int undefined_handler_address;
extern const struct pmap_devmap *pmap_devmap_bootstrap_table;
extern vm_offset_t pmap_bootstrap_lastaddr;
struct pv_addr kernel_pt_table[KERNEL_PT_MAX];
extern int *end;
struct pcpu __pcpu;
struct pcpu *pcpup = &__pcpu;
/* Physical and virtual addresses for some global pages */
vm_paddr_t phys_avail[10];
vm_paddr_t dump_avail[4];
vm_offset_t physical_pages;
struct pv_addr systempage;
struct pv_addr msgbufpv;
struct pv_addr irqstack;
struct pv_addr undstack;
struct pv_addr abtstack;
struct pv_addr kernelstack;
static struct trapframe proc0_tf;
struct mem_region {
vm_offset_t mr_start;
vm_size_t mr_size;
};
static struct mem_region availmem_regions[MEM_REGIONS];
static int availmem_regions_sz;
struct bootinfo *bootinfo;
static void print_kenv(void);
static void print_kernel_section_addr(void);
static void print_bootinfo(void);
static void physmap_init(int);
static char *
kenv_next(char *cp)
{
if (cp != NULL) {
while (*cp != 0)
cp++;
cp++;
if (*cp == 0)
cp = NULL;
}
return (cp);
}
static void
print_kenv(void)
{
int len;
char *cp;
debugf("loader passed (static) kenv:\n");
if (kern_envp == NULL) {
debugf(" no env, null ptr\n");
return;
}
debugf(" kern_envp = 0x%08x\n", (uint32_t)kern_envp);
len = 0;
for (cp = kern_envp; cp != NULL; cp = kenv_next(cp))
debugf(" %x %s\n", (uint32_t)cp, cp);
}
static void
print_bootinfo(void)
{
struct bi_mem_region *mr;
struct bi_eth_addr *eth;
int i, j;
debugf("bootinfo:\n");
if (bootinfo == NULL) {
debugf(" no bootinfo, null ptr\n");
return;
}
debugf(" version = 0x%08x\n", bootinfo->bi_version);
debugf(" ccsrbar = 0x%08x\n", bootinfo->bi_bar_base);
debugf(" cpu_clk = 0x%08x\n", bootinfo->bi_cpu_clk);
debugf(" bus_clk = 0x%08x\n", bootinfo->bi_bus_clk);
debugf(" mem regions:\n");
mr = (struct bi_mem_region *)bootinfo->bi_data;
for (i = 0; i < bootinfo->bi_mem_reg_no; i++, mr++)
debugf(" #%d, base = 0x%08x, size = 0x%08x\n", i,
mr->mem_base, mr->mem_size);
debugf(" eth addresses:\n");
eth = (struct bi_eth_addr *)mr;
for (i = 0; i < bootinfo->bi_eth_addr_no; i++, eth++) {
debugf(" #%d, addr = ", i);
for (j = 0; j < 6; j++)
debugf("%02x ", eth->mac_addr[j]);
debugf("\n");
}
}
static void
print_kernel_section_addr(void)
{
debugf("kernel image addresses:\n");
debugf(" kernbase = 0x%08x\n", (uint32_t)kernbase);
debugf(" _etext (sdata) = 0x%08x\n", (uint32_t)_etext);
debugf(" _edata = 0x%08x\n", (uint32_t)_edata);
debugf(" __bss_start = 0x%08x\n", (uint32_t)__bss_start);
debugf(" _end = 0x%08x\n", (uint32_t)_end);
}
struct bi_mem_region *
bootinfo_mr(void)
{
return ((struct bi_mem_region *)bootinfo->bi_data);
}
static void
physmap_init(int hardcoded)
{
int i, j, cnt;
vm_offset_t phys_kernelend, kernload;
uint32_t s, e, sz;
struct mem_region *mp, *mp1;
phys_kernelend = KERNPHYSADDR + (virtual_avail - KERNVIRTADDR);
kernload = KERNPHYSADDR;
/*
* Use hardcoded physical addresses if we don't use memory regions
* from metadata.
*/
if (hardcoded) {
phys_avail[0] = 0;
phys_avail[1] = kernload;
phys_avail[2] = phys_kernelend;
phys_avail[3] = PHYSMEM_SIZE;
phys_avail[4] = 0;
phys_avail[5] = 0;
return;
}
/*
* Remove kernel physical address range from avail
* regions list. Page align all regions.
* Non-page aligned memory isn't very interesting to us.
* Also, sort the entries for ascending addresses.
*/
sz = 0;
cnt = availmem_regions_sz;
debugf("processing avail regions:\n");
for (mp = availmem_regions; mp->mr_size; mp++) {
s = mp->mr_start;
e = mp->mr_start + mp->mr_size;
debugf(" %08x-%08x -> ", s, e);
/* Check whether this region holds all of the kernel. */
if (s < kernload && e > phys_kernelend) {
availmem_regions[cnt].mr_start = phys_kernelend;
availmem_regions[cnt++].mr_size = e - phys_kernelend;
e = kernload;
}
/* Look whether this regions starts within the kernel. */
if (s >= kernload && s < phys_kernelend) {
if (e <= phys_kernelend)
goto empty;
s = phys_kernelend;
}
/* Now look whether this region ends within the kernel. */
if (e > kernload && e <= phys_kernelend) {
if (s >= kernload) {
goto empty;
}
e = kernload;
}
/* Now page align the start and size of the region. */
s = round_page(s);
e = trunc_page(e);
if (e < s)
e = s;
sz = e - s;
debugf("%08x-%08x = %x\n", s, e, sz);
/* Check whether some memory is left here. */
if (sz == 0) {
empty:
printf("skipping\n");
bcopy(mp + 1, mp,
(cnt - (mp - availmem_regions)) * sizeof(*mp));
cnt--;
mp--;
continue;
}
/* Do an insertion sort. */
for (mp1 = availmem_regions; mp1 < mp; mp1++)
if (s < mp1->mr_start)
break;
if (mp1 < mp) {
bcopy(mp1, mp1 + 1, (char *)mp - (char *)mp1);
mp1->mr_start = s;
mp1->mr_size = sz;
} else {
mp->mr_start = s;
mp->mr_size = sz;
}
}
availmem_regions_sz = cnt;
/* Fill in phys_avail table, based on availmem_regions */
debugf("fill in phys_avail:\n");
for (i = 0, j = 0; i < availmem_regions_sz; i++, j += 2) {
debugf(" region: 0x%08x - 0x%08x (0x%08x)\n",
availmem_regions[i].mr_start,
availmem_regions[i].mr_start + availmem_regions[i].mr_size,
availmem_regions[i].mr_size);
phys_avail[j] = availmem_regions[i].mr_start;
phys_avail[j + 1] = availmem_regions[i].mr_start +
availmem_regions[i].mr_size;
}
phys_avail[j] = 0;
phys_avail[j + 1] = 0;
}
void *
initarm(void *mdp, void *unused __unused)
{
struct pv_addr kernel_l1pt;
vm_offset_t freemempos, l2_start, lastaddr;
uint32_t memsize, l2size;
struct bi_mem_region *mr;
void *kmdp;
u_int l1pagetable;
int i = 0;
kmdp = NULL;
lastaddr = 0;
memsize = 0;
set_cpufuncs();
/*
* Mask metadata pointer: it is supposed to be on page boundary. If
* the first argument (mdp) doesn't point to a valid address the
* bootloader must have passed us something else than the metadata
* ptr... In this case we want to fall back to some built-in settings.
*/
mdp = (void *)((uint32_t)mdp & ~PAGE_MASK);
/* Parse metadata and fetch parameters */
if (mdp != NULL) {
preload_metadata = mdp;
kmdp = preload_search_by_type("elf kernel");
if (kmdp != NULL) {
bootinfo = (struct bootinfo *)preload_search_info(kmdp,
MODINFO_METADATA|MODINFOMD_BOOTINFO);
boothowto = MD_FETCH(kmdp, MODINFOMD_HOWTO, int);
kern_envp = MD_FETCH(kmdp, MODINFOMD_ENVP, char *);
lastaddr = MD_FETCH(kmdp, MODINFOMD_KERNEND, vm_offset_t);
}
/* Initialize memory regions table */
mr = bootinfo_mr();
for (i = 0; i < bootinfo->bi_mem_reg_no; i++, mr++) {
if (i == MEM_REGIONS)
break;
availmem_regions[i].mr_start = mr->mem_base;
availmem_regions[i].mr_size = mr->mem_size;
memsize += mr->mem_size;
}
availmem_regions_sz = i;
} else {
/* Fall back to hardcoded boothowto flags and metadata. */
boothowto = RB_VERBOSE | RB_SINGLE;
lastaddr = fake_preload_metadata();
/*
* Assume a single memory region of size specified in board
* configuration file.
*/
memsize = PHYSMEM_SIZE;
}
/*
* If memsize is invalid, we can neither proceed nor panic (too
* early for console output).
*/
if (memsize == 0)
while (1);
/* Platform-specific initialisation */
if (platform_pmap_init() != 0)
return (NULL);
pcpu_init(pcpup, 0, sizeof(struct pcpu));
PCPU_SET(curthread, &thread0);
/* Calculate number of L2 tables needed for mapping vm_page_array */
l2size = (memsize / PAGE_SIZE) * sizeof(struct vm_page);
l2size = (l2size >> L1_S_SHIFT) + 1;
/*
* Add one table for end of kernel map, one for stacks, msgbuf and
* L1 and L2 tables map and one for vectors map.
*/
l2size += 3;
/* Make it divisible by 4 */
l2size = (l2size + 3) & ~3;
#define KERNEL_TEXT_BASE (KERNBASE)
freemempos = (lastaddr + PAGE_MASK) & ~PAGE_MASK;
/* Define a macro to simplify memory allocation */
#define valloc_pages(var, np) \
alloc_pages((var).pv_va, (np)); \
(var).pv_pa = (var).pv_va + (KERNPHYSADDR - KERNVIRTADDR);
#define alloc_pages(var, np) \
(var) = freemempos; \
freemempos += (np * PAGE_SIZE); \
memset((char *)(var), 0, ((np) * PAGE_SIZE));
while (((freemempos - L1_TABLE_SIZE) & (L1_TABLE_SIZE - 1)) != 0)
freemempos += PAGE_SIZE;
valloc_pages(kernel_l1pt, L1_TABLE_SIZE / PAGE_SIZE);
for (i = 0; i < l2size; ++i) {
if (!(i % (PAGE_SIZE / L2_TABLE_SIZE_REAL))) {
valloc_pages(kernel_pt_table[i],
L2_TABLE_SIZE / PAGE_SIZE);
} else {
kernel_pt_table[i].pv_va = freemempos -
(i % (PAGE_SIZE / L2_TABLE_SIZE_REAL)) *
L2_TABLE_SIZE_REAL;
kernel_pt_table[i].pv_pa =
kernel_pt_table[i].pv_va - KERNVIRTADDR +
KERNPHYSADDR;
}
}
/*
* Allocate a page for the system page mapped to 0x00000000
* or 0xffff0000. This page will just contain the system vectors
* and can be shared by all processes.
*/
valloc_pages(systempage, 1);
/* Allocate stacks for all modes */
valloc_pages(irqstack, IRQ_STACK_SIZE);
valloc_pages(abtstack, ABT_STACK_SIZE);
valloc_pages(undstack, UND_STACK_SIZE);
valloc_pages(kernelstack, KSTACK_PAGES);
valloc_pages(msgbufpv, round_page(MSGBUF_SIZE) / PAGE_SIZE);
/*
* Now we start construction of the L1 page table
* We start by mapping the L2 page tables into the L1.
* This means that we can replace L1 mappings later on if necessary
*/
l1pagetable = kernel_l1pt.pv_va;
/*
* Try to map as much as possible of kernel text and data using
* 1MB section mapping and for the rest of initial kernel address
* space use L2 coarse tables.
*
* Link L2 tables for mapping remainder of kernel (modulo 1MB)
* and kernel structures
*/
l2_start = lastaddr & ~(L1_S_OFFSET);
for (i = 0 ; i < l2size - 1; i++)
pmap_link_l2pt(l1pagetable, l2_start + i * L1_S_SIZE,
&kernel_pt_table[KERNEL_PT_KERN + i]);
pmap_curmaxkvaddr = l2_start + (l2size - 1) * L1_S_SIZE;
/* Map kernel code and data */
pmap_map_chunk(l1pagetable, KERNVIRTADDR, KERNPHYSADDR,
(((uint32_t)(lastaddr) - KERNVIRTADDR) + PAGE_MASK) & ~PAGE_MASK,
VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
/* Map L1 directory and allocated L2 page tables */
pmap_map_chunk(l1pagetable, kernel_l1pt.pv_va, kernel_l1pt.pv_pa,
L1_TABLE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE);
pmap_map_chunk(l1pagetable, kernel_pt_table[0].pv_va,
kernel_pt_table[0].pv_pa,
L2_TABLE_SIZE_REAL * l2size,
VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE);
/* Map allocated stacks and msgbuf */
pmap_map_chunk(l1pagetable, irqstack.pv_va, irqstack.pv_pa,
freemempos - irqstack.pv_va,
VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
/* Link and map the vector page */
pmap_link_l2pt(l1pagetable, ARM_VECTORS_HIGH,
&kernel_pt_table[KERNEL_PT_SYS]);
pmap_map_entry(l1pagetable, ARM_VECTORS_HIGH, systempage.pv_pa,
VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
pmap_devmap_bootstrap(l1pagetable, pmap_devmap_bootstrap_table);
cpu_domains((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL * 2)) |
DOMAIN_CLIENT);
setttb(kernel_l1pt.pv_pa);
cpu_tlb_flushID();
cpu_domains(DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL * 2));
cninit();
physmem = memsize / PAGE_SIZE;
debugf("initarm: console initialized\n");
debugf(" arg1 mdp = 0x%08x\n", (uint32_t)mdp);
debugf(" boothowto = 0x%08x\n", boothowto);
print_bootinfo();
print_kernel_section_addr();
print_kenv();
/*
* Re-initialise decode windows
*/
if (soc_decode_win() != 0)
printf("WARNING: could not re-initialise decode windows! "
"Running with existing settings...\n");
/*
* Pages were allocated during the secondary bootstrap for the
* stacks for different CPU modes.
* We must now set the r13 registers in the different CPU modes to
* point to these stacks.
* Since the ARM stacks use STMFD etc. we must set r13 to the top end
* of the stack memory.
*/
cpu_control(CPU_CONTROL_MMU_ENABLE, CPU_CONTROL_MMU_ENABLE);
set_stackptr(PSR_IRQ32_MODE,
irqstack.pv_va + IRQ_STACK_SIZE * PAGE_SIZE);
set_stackptr(PSR_ABT32_MODE,
abtstack.pv_va + ABT_STACK_SIZE * PAGE_SIZE);
set_stackptr(PSR_UND32_MODE,
undstack.pv_va + UND_STACK_SIZE * PAGE_SIZE);
/*
* We must now clean the cache again....
* Cleaning may be done by reading new data to displace any
* dirty data in the cache. This will have happened in setttb()
* but since we are boot strapping the addresses used for the read
* may have just been remapped and thus the cache could be out
* of sync. A re-clean after the switch will cure this.
* After booting there are no gross reloations of the kernel thus
* this problem will not occur after initarm().
*/
cpu_idcache_wbinv_all();
/* Set stack for exception handlers */
data_abort_handler_address = (u_int)data_abort_handler;
prefetch_abort_handler_address = (u_int)prefetch_abort_handler;
undefined_handler_address = (u_int)undefinedinstruction_bounce;
undefined_init();
proc_linkup0(&proc0, &thread0);
thread0.td_kstack = kernelstack.pv_va;
thread0.td_kstack_pages = KSTACK_PAGES;
thread0.td_pcb = (struct pcb *)
(thread0.td_kstack + KSTACK_PAGES * PAGE_SIZE) - 1;
thread0.td_pcb->pcb_flags = 0;
thread0.td_frame = &proc0_tf;
pcpup->pc_curpcb = thread0.td_pcb;
arm_vector_init(ARM_VECTORS_HIGH, ARM_VEC_ALL);
dump_avail[0] = KERNPHYSADDR;
dump_avail[1] = KERNPHYSADDR + memsize;
dump_avail[2] = 0;
dump_avail[3] = 0;
pmap_bootstrap(freemempos, pmap_bootstrap_lastaddr, &kernel_l1pt);
msgbufp = (void *)msgbufpv.pv_va;
msgbufinit(msgbufp, MSGBUF_SIZE);
mutex_init();
/*
* Prepare map of physical memory regions available to vm subsystem.
* If metadata pointer doesn't point to a valid address, use hardcoded
* values.
*/
physmap_init((mdp != NULL) ? 0 : 1);
/* Do basic tuning, hz etc */
init_param1();
init_param2(physmem);
kdb_init();
return ((void *)(kernelstack.pv_va + USPACE_SVC_STACK_TOP -
sizeof(struct pcb)));
}
struct arm32_dma_range *
bus_dma_get_range(void)
{
return (NULL);
}
int
bus_dma_get_range_nb(void)
{
return (0);
}

540
sys/arm/mv/mvreg.h Normal file
View file

@ -0,0 +1,540 @@
/*-
* Copyright (C) 2007-2008 MARVELL INTERNATIONAL LTD.
* All rights reserved.
*
* Developed by Semihalf.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of MARVELL nor the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef _MVREG_H_
#define _MVREG_H_
#include <machine/intr.h>
/*
* Physical addresses of integrated SoC peripherals
*/
#define MV_PHYS_BASE 0xF1000000
#define MV_SIZE 0x100000
/*
* Decode windows addresses (physical)
*/
#define MV_PCIE_IO_PHYS_BASE (MV_PHYS_BASE + MV_SIZE)
#define MV_PCIE_IO_BASE MV_PCIE_IO_PHYS_BASE
#define MV_PCIE_IO_SIZE (1024 * 1024)
#define MV_PCI_IO_PHYS_BASE (MV_PCIE_IO_PHYS_BASE + MV_PCIE_IO_SIZE)
#define MV_PCI_IO_BASE MV_PCI_IO_PHYS_BASE
#define MV_PCI_IO_SIZE (1024 * 1024)
#define MV_PCIE_MEM_PHYS_BASE (MV_PCI_IO_PHYS_BASE + MV_PCI_IO_SIZE)
#define MV_PCIE_MEM_BASE MV_PCIE_MEM_PHYS_BASE
#define MV_PCIE_MEM_SIZE (64 * 1024 * 1024)
#define MV_PCI_MEM_PHYS_BASE (MV_PCIE_MEM_PHYS_BASE + MV_PCIE_MEM_SIZE)
#define MV_PCI_MEM_BASE MV_PCI_MEM_PHYS_BASE
#define MV_PCI_MEM_SIZE (64 * 1024 * 1024)
/* XXX DEV_BOOT, CSx are board specific, should be defined per platform */
/* 512KB NOR FLASH */
#define MV_DEV_BOOT_PHYS_BASE (MV_PCI_MEM_PHYS_BASE + MV_PCI_MEM_SIZE)
#define MV_DEV_BOOT_SIZE (512 * 1024)
/* CS0: 7-seg LED */
#define MV_DEV_CS0_PHYS_BASE 0xFA000000
#define MV_DEV_CS0_SIZE (1024 * 1024) /* XXX u-boot has 2MB */
/* CS1: 32MB NOR FLASH */
#define MV_DEV_CS1_PHYS_BASE (MV_DEV_CS0_PHYS_BASE + MV_DEV_CS0_SIZE)
#define MV_DEV_CS1_SIZE (32 * 1024 * 1024)
/* CS2: 32MB NAND FLASH */
#define MV_DEV_CS2_PHYS_BASE (MV_DEV_CS1_PHYS_BASE + MV_DEV_CS1_SIZE)
#define MV_DEV_CS2_SIZE 1024 /* XXX u-boot has 1MB */
/* XXX this is probably not robust against wraparounds... */
#if ((MV_DEV_CS2_PHYS_BASE + MV_DEV_CS2_SIZE) > 0xFFFEFFFF)
#error Devices memory layout overlaps reset vectors range!
#endif
/*
* Integrated SoC peripherals addresses
*/
#define MV_BASE MV_PHYS_BASE /* VA == PA mapping */
#define MV_DDR_CADR_BASE (MV_BASE + 0x1500)
#define MV_MPP_BASE (MV_BASE + 0x10000)
#define MV_GPIO_BASE (MV_BASE + 0x10100)
#define MV_GPIO_SIZE 0x20
#define MV_RTC_BASE (MV_BASE + 0x10300)
#define MV_RTC_SIZE 0x08
#define MV_TWSI_BASE (MV_BASE + 0x11000)
#define MV_TWSI_SIZE 0x20
#define MV_UART0_BASE (MV_BASE + 0x12000)
#define MV_UART1_BASE (MV_BASE + 0x12100)
#define MV_UART_SIZE 0x20
#define MV_MBUS_BRIDGE_BASE (MV_BASE + 0x20000)
#define MV_INTREGS_BASE (MV_MBUS_BRIDGE_BASE + 0x80)
#define MV_CPU_CONTROL_BASE (MV_MBUS_BRIDGE_BASE + 0x100)
#define MV_IC_BASE (MV_MBUS_BRIDGE_BASE + 0x200)
#define MV_IC_SIZE 0x3C
#define MV_TIMERS_BASE (MV_MBUS_BRIDGE_BASE + 0x300)
#define MV_TIMERS_SIZE 0x30
#define MV_PCI_BASE (MV_BASE + 0x30000)
#define MV_PCI_SIZE 0x2000
#define MV_PCIE_BASE (MV_BASE + 0x40000)
#define MV_PCIE_SIZE 0x2000
#define MV_USB0_BASE (MV_BASE + 0x50000)
#define MV_USB1_BASE (MV_USB0_BASE + 0x1000)
#define MV_USB2_BASE (MV_USB0_BASE + 0x2000)
#define MV_USB_SIZE 0x1000
#define MV_USB_HOST_OFST 0x0100 /* EHCI HC regs start at this offset within USB range */
#define MV_USB_AWR_BASE (MV_USB0_BASE + 0x320)
#define MV_IDMA_BASE (MV_BASE + 0x60000)
#define MV_IDMA_SIZE 0x1000
#define MV_XOR_BASE (MV_BASE + 0x60000)
#define MV_XOR_SIZE 0x1000
#define MV_ETH0_BASE (MV_BASE + 0x72000)
#define MV_ETH1_BASE (MV_BASE + 0x76000)
#define MV_ETH_SIZE 0x2000
#define MV_DEV_CS0_BASE MV_DEV_CS0_PHYS_BASE
/*
* Interrupt sources
*/
#if defined(SOC_MV_ORION)
#define MV_INT_BRIDGE 0 /* AHB-MBus Bridge Interrupt */
#define MV_INT_UART0 3 /* UART0 Interrupt */
#define MV_INT_UART1 4
#define MV_INT_GPIO7_0 6 /* GPIO[7:0] Interrupt */
#define MV_INT_GPIO15_8 7 /* GPIO[15:8] Interrupt */
#define MV_INT_GPIO23_16 8 /* GPIO[23:16] Interrupt */
#define MV_INT_GPIO31_24 9 /* GPIO[31:24] Interrupt */
#define MV_INT_PEX0_ERR 10 /* PCI Express Error */
#define MV_INT_PEX0 11 /* PCI Express INTA,B,C,D Message */
#define MV_INT_PCI_ERR 15 /* PCI Error */
#define MV_INT_USB_BERR 16 /* USB Bridge Error */
#define MV_INT_USB_CI 17 /* USB Controller interrupt */
#define MV_INT_GBERX 18 /* GbE receive interrupt */
#define MV_INT_GBETX 19 /* GbE transmit interrupt */
#define MV_INT_GBEMISC 20 /* GbE misc. interrupt */
#define MV_INT_GBESUM 21 /* GbE summary interrupt */
#define MV_INT_GBEERR 22 /* GbE error interrupt */
#define MV_INT_IDMA_ERR 23 /* DMA error interrupt */
#define MV_INT_IDMA0 24 /* IDMA chan. 0 completion interrupt */
#define MV_INT_IDMA1 25 /* IDMA chan. 1 completion interrupt */
#define MV_INT_IDMA2 26 /* IDMA chan. 2 completion interrupt */
#define MV_INT_IDMA3 27 /* IDMA chan. 3 completion interrupt */
#define MV_INT_SATA 29 /* Serial-ATA Interrupt */
#elif defined(SOC_MV_KIRKWOOD)
#define MV_INT_BRIDGE 1 /* AHB-MBus Bridge Interrupt */
#define MV_INT_XOR0_CHAN0 5 /* XOR engine 0 channel 0 Interrupt */
#define MV_INT_XOR0_CHAN1 6 /* XOR engine 0 channel 1 Interrupt */
#define MV_INT_XOR1_CHAN0 7 /* XOR engine 1 channel 0 Interrupt */
#define MV_INT_XOR1_CHAN1 8 /* XOR engine 1 channel 1 Interrupt */
#define MV_INT_PEX0 9 /* PCI Express INTA,B,C,D Message */
#define MV_INT_GBESUM 11 /* GbE0 summary interrupt */
#define MV_INT_GBERX 12 /* GbE0 receive interrupt */
#define MV_INT_GBETX 13 /* GbE0 transmit interrupt */
#define MV_INT_GBEMISC 14 /* GbE0 misc. interrupt */
#define MV_INT_GBE1SUM 15 /* GbE1 summary interrupt */
#define MV_INT_GBE1RX 16 /* GbE1 receive interrupt */
#define MV_INT_GBE1TX 17 /* GbE1 transmit interrupt */
#define MV_INT_GBE1MISC 18 /* GbE1 misc. interrupt */
#define MV_INT_USB_CI 19 /* USB Controller interrupt */
#define MV_INT_SATA 21 /* Serial-ATA Interrupt */
#define MV_INT_IDMA_ERR 23 /* DMA error interrupt */
#define MV_INT_UART0 33 /* UART0 Interrupt */
#define MV_INT_UART1 34
#define MV_INT_GPIO7_0 35 /* GPIO[7:0] Interrupt */
#define MV_INT_GPIO15_8 36 /* GPIO[15:8] Interrupt */
#define MV_INT_GPIO23_16 37 /* GPIO[23:16] Interrupt */
#define MV_INT_GPIO31_24 38 /* GPIO[31:24] Interrupt */
#define MV_INT_GPIOHI7_0 39 /* GPIOHI[7:0] Interrupt */
#define MV_INT_GPIOHI15_8 40 /* GPIOHI[15:8] Interrupt */
#define MV_INT_GPIOHI23_16 41 /* GPIOHI[23:16] Interrupt */
#define MV_INT_XOR0_ERR 42 /* XOR engine 0 error Interrupt */
#define MV_INT_XOR1_ERR 43 /* XOR engine 1 error Interrupt */
#define MV_INT_PEX0_ERR 44 /* PCI Express Error */
#define MV_INT_GBEERR 46 /* GbE0 error interrupt */
#define MV_INT_GBE1ERR 47 /* GbE1 error interrupt */
#define MV_INT_USB_BERR 48 /* USB Bridge Error */
#elif defined(SOC_MV_DISCOVERY)
#define MV_INT_ERRSUM 0 /* Summary of error interrupts */
#define MV_INT_SPI 1 /* SPI interrupt */
#define MV_INT_TWSI0 2 /* TWSI0 interrupt */
#define MV_INT_TWSI1 3 /* TWSI1 interrupt */
#define MV_INT_IDMA0 4 /* IDMA Channel0 completion */
#define MV_INT_IDMA1 5 /* IDMA Channel0 completion */
#define MV_INT_IDMA2 6 /* IDMA Channel0 completion */
#define MV_INT_IDMA3 7 /* IDMA Channel0 completion */
#define MV_INT_TIMER0 8 /* Timer0 interrupt */
#define MV_INT_TIMER1 9 /* Timer1 interrupt */
#define MV_INT_TIMER2 10 /* Timer2 interrupt */
#define MV_INT_TIMER3 11 /* Timer3 interrupt */
#define MV_INT_UART0 12 /* UART0 interrupt */
#define MV_INT_UART1 13 /* UART1 interrupt */
#define MV_INT_UART2 14 /* UART2 interrupt */
#define MV_INT_UART3 15 /* UART3 interrupt */
#define MV_INT_USB0 16 /* USB0 interrupt */
#define MV_INT_USB1 17 /* USB1 interrupt */
#define MV_INT_USB2 18 /* USB2 interrupt */
#define MV_INT_CRYPTO 19 /* Crypto engine completion interrupt */
#define MV_INT_XOR0 22 /* XOR engine 0 completion interrupt */
#define MV_INT_XOR1 23 /* XOR engine 1 completion interrupt */
#define MV_INT_SATA 26 /* SATA interrupt */
#define MV_INT_PEX00 32 /* PCI Express port 0.0 INTA/B/C/D */
#define MV_INT_PEX01 33 /* PCI Express port 0.1 INTA/B/C/D */
#define MV_INT_PEX02 34 /* PCI Express port 0.2 INTA/B/C/D */
#define MV_INT_PEX03 35 /* PCI Express port 0.3 INTA/B/C/D */
#define MV_INT_PEX10 36 /* PCI Express port 1.0 INTA/B/C/D */
#define MV_INT_PEX11 37 /* PCI Express port 1.1 INTA/B/C/D */
#define MV_INT_PEX12 38 /* PCI Express port 1.2 INTA/B/C/D */
#define MV_INT_PEX13 39 /* PCI Express port 1.3 INTA/B/C/D */
#define MV_INT_GBESUM 40 /* Gigabit Ethernet Port 0 summary */
#define MV_INT_GBERX 41 /* Gigabit Ethernet Port 0 Rx summary */
#define MV_INT_GBETX 42 /* Gigabit Ethernet Port 0 Tx summary */
#define MV_INT_GBEMISC 43 /* Gigabit Ethernet Port 0 Misc summ. */
#define MV_INT_GBE1SUM 44 /* Gigabit Ethernet Port 1 summary */
#define MV_INT_GBE1RX 45 /* Gigabit Ethernet Port 1 Rx summary */
#define MV_INT_GBE1TX 46 /* Gigabit Ethernet Port 1 Tx summary */
#define MV_INT_GBE1MISC 47 /* Gigabit Ethernet Port 1 Misc summ. */
#define MV_INT_GPIO7_0 56 /* GPIO[7:0] Interrupt */
#define MV_INT_GPIO15_8 57 /* GPIO[15:8] Interrupt */
#define MV_INT_GPIO23_16 58 /* GPIO[23:16] Interrupt */
#define MV_INT_GPIO31_24 59 /* GPIO[31:24] Interrupt */
#define MV_INT_DB_IN 60 /* Inbound Doorbell Cause reg Summary */
#define MV_INT_DB_OUT 61 /* Outbound Doorbell Cause reg Summ. */
#define MV_INT_CRYPT_ERR 64 /* Crypto engine error */
#define MV_INT_DEV_ERR 65 /* Device bus error */
#define MV_INT_IDMA_ERR 66 /* DMA error */
#define MV_INT_CPU_ERR 67 /* CPU error */
#define MV_INT_PEX0_ERR 68 /* PCI-Express port0 error */
#define MV_INT_PEX1_ERR 69 /* PCI-Express port1 error */
#define MV_INT_GBE_ERR 70 /* Gigabit Ethernet error */
#define MV_INT_USB_ERR 72 /* USB error */
#define MV_INT_DRAM_ERR 73 /* DRAM ECC error */
#define MV_INT_XOR_ERR 74 /* XOR engine error */
#define MV_INT_WD 79 /* WD Timer interrupt */
#endif /* SOC_MV_ORION */
#define BRIDGE_IRQ_CAUSE 0x10
#define BRIGDE_IRQ_MASK 0x14
#if defined(SOC_MV_DISCOVERY)
#define IRQ_CAUSE_ERROR 0x0
#define IRQ_CAUSE 0x4
#define IRQ_CAUSE_HI 0x8
#define IRQ_MASK_ERROR 0xC
#define IRQ_MASK 0x10
#define IRQ_MASK_HI 0x14
#define IRQ_CAUSE_SELECT 0x18
#define FIQ_MASK_ERROR 0x1C
#define FIQ_MASK 0x20
#define FIQ_MASK_HI 0x24
#define FIQ_CAUSE_SELECT 0x28
#define ENDPOINT_IRQ_MASK_ERROR 0x2C
#define ENDPOINT_IRQ_MASK 0x30
#define ENDPOINT_IRQ_MASK_HI 0x34
#define ENDPOINT_IRQ_CAUSE_SELECT 0x38
#else /* !SOC_MV_DISCOVERY */
#define IRQ_CAUSE 0x0
#define IRQ_MASK 0x4
#define FIQ_MASK 0x8
#define ENDPOINT_IRQ_MASK 0xC
#define IRQ_CAUSE_HI 0x10
#define IRQ_MASK_HI 0x14
#define FIQ_MASK_HI 0x18
#define ENDPOINT_IRQ_MASK_HI 0x1C
#define IRQ_CAUSE_ERROR (-1) /* Fake defines for unified */
#define IRQ_MASK_ERROR (-1) /* interrupt controller code */
#endif
#define BRIDGE_IRQ_CAUSE 0x10
#define IRQ_CPU_SELF 0x00000001
#define IRQ_TIMER0 0x00000002
#define IRQ_TIMER1 0x00000004
#define IRQ_TIMER_WD 0x00000008
#define BRIDGE_IRQ_MASK 0x14
#define IRQ_CPU_MASK 0x00000001
#define IRQ_TIMER0_MASK 0x00000002
#define IRQ_TIMER1_MASK 0x00000004
#define IRQ_TIMER_WD_MASK 0x00000008
/*
* System reset
*/
#define RSTOUTn_MASK 0x8
#define WD_RST_OUT_EN 0x00000002
#define SOFT_RST_OUT_EN 0x00000004
#define SYSTEM_SOFT_RESET 0xc
#define SYS_SOFT_RST 0x00000001
/*
* Power Control
*/
#define CPU_PM_CTRL 0x1C
#define CPU_PM_CTRL_NONE 0
#if defined(SOC_MV_KIRKWOOD)
#define CPU_PM_CTRL_GE0 (1 << 0)
#define CPU_PM_CTRL_PEX0_PHY (1 << 1)
#define CPU_PM_CTRL_PEX0 (1 << 2)
#define CPU_PM_CTRL_USB0 (1 << 3)
#define CPU_PM_CTRL_SDIO (1 << 4)
#define CPU_PM_CTRL_TSU (1 << 5)
#define CPU_PM_CTRL_DUNIT (1 << 6)
#define CPU_PM_CTRL_RUNIT (1 << 7)
#define CPU_PM_CTRL_XOR0 (1 << 8)
#define CPU_PM_CTRL_AUDIO (1 << 9)
#define CPU_PM_CTRL_SATA0 (1 << 14)
#define CPU_PM_CTRL_SATA1 (1 << 15)
#define CPU_PM_CTRL_XOR1 (1 << 16)
#define CPU_PM_CTRL_CRYPTO (1 << 17)
#define CPU_PM_CTRL_GE1 (1 << 18)
#define CPU_PM_CTRL_TDM (1 << 19)
#elif defined(SOC_MV_DISCOVERY)
#define CPU_PM_CTRL_GE0 (1 << 1)
#define CPU_PM_CTRL_GE1 (1 << 2)
#define CPU_PM_CTRL_PEX00 (1 << 5)
#define CPU_PM_CTRL_PEX01 (1 << 6)
#define CPU_PM_CTRL_PEX02 (1 << 7)
#define CPU_PM_CTRL_PEX03 (1 << 8)
#define CPU_PM_CTRL_PEX10 (1 << 9)
#define CPU_PM_CTRL_PEX11 (1 << 10)
#define CPU_PM_CTRL_PEX12 (1 << 11)
#define CPU_PM_CTRL_PEX13 (1 << 12)
#define CPU_PM_CTRL_SATA0_PHY (1 << 13)
#define CPU_PM_CTRL_SATA0 (1 << 14)
#define CPU_PM_CTRL_SATA1_PHY (1 << 15)
#define CPU_PM_CTRL_SATA1 (1 << 16)
#define CPU_PM_CTRL_USB0 (1 << 17)
#define CPU_PM_CTRL_USB1 (1 << 18)
#define CPU_PM_CTRL_USB2 (1 << 19)
#define CPU_PM_CTRL_IDMA (1 << 20)
#define CPU_PM_CTRL_XOR (1 << 21)
#define CPU_PM_CTRL_CRYPTO (1 << 22)
#define CPU_PM_CTRL_DEVICE (1 << 23)
#endif
/*
* Timers
*/
#define CPU_TIMER_CONTROL 0x0
#define CPU_TIMER0_EN 0x00000001
#define CPU_TIMER0_AUTO 0x00000002
#define CPU_TIMER1_EN 0x00000004
#define CPU_TIMER1_AUTO 0x00000008
#define CPU_TIMER_WD_EN 0x00000010
#define CPU_TIMER_WD_AUTO 0x00000020
#define CPU_TIMER0_REL 0x10
#define CPU_TIMER0 0x14
/*
* GPIO
*/
#define GPIO_DATA_OUT 0x00
#define GPIO_DATA_OUT_EN_CTRL 0x04
#define GPIO_BLINK_EN 0x08
#define GPIO_DATA_IN_POLAR 0x0c
#define GPIO_DATA_IN 0x10
#define GPIO_INT_CAUSE 0x14
#define GPIO_INT_EDGE_MASK 0x18
#define GPIO_INT_LEV_MASK 0x1c
#define GPIO_HI_DATA_OUT 0x40
#define GPIO_HI_DATA_OUT_EN_CTRL 0x44
#define GPIO_HI_BLINK_EN 0x48
#define GPIO_HI_DATA_IN_POLAR 0x4c
#define GPIO_HI_DATA_IN 0x50
#define GPIO_HI_INT_CAUSE 0x54
#define GPIO_HI_INT_EDGE_MASK 0x58
#define GPIO_HI_INT_LEV_MASK 0x5c
#define GPIO(n) (1 << (n))
#define MV_GPIO_MAX_NPINS 64
#define MV_GPIO_BLINK 0x1
#define MV_GPIO_POLARITY 0x2
#define MV_GPIO_EDGE 0x4
#define MV_GPIO_LEVEL 0x8
#define IS_GPIO_IRQ(irq) ((irq) >= NIRQ && (irq) < NIRQ + MV_GPIO_MAX_NPINS)
#define GPIO2IRQ(gpio) ((gpio) + NIRQ)
#define IRQ2GPIO(irq) ((irq) - NIRQ)
/*
* MPP
*/
#define MPP_CONTROL0 0x00
#define MPP_CONTROL1 0x04
#define MPP_CONTROL2 0x50
#define DEVICE_MULTIPLEX 0x08
#if defined(SOC_MV_ORION)
#define SAMPLE_AT_RESET 0x10
#elif defined(SOC_MV_KIRKWOOD) || defined(SOC_MV_DISCOVERY)
#define SAMPLE_AT_RESET 0x30
#else
#error SOC_MV_XX not defined
#endif
/*
* Clocks
*/
#ifdef SOC_MV_ORION
#define TCLK_MASK 0x300
#define TCLK_SHIFT 0x8
#elif defined(SOC_MV_KIRKWOOD) || defined(SOC_MV_DISCOVERY)
#define TCLK_MASK 0x30000
#define TCLK_SHIFT 0x10
#else
#error SOC_MV_XX not defined
#endif
#define TCLK_100MHZ 100000000
#define TCLK_125MHZ 125000000
#define TCLK_133MHZ 133333333
#define TCLK_150MHZ 150000000
#define TCLK_166MHZ 166666667
#define TCLK_200MHZ 200000000
/*
* Chip ID
*/
#define MV_DEV_88F5181 0x5181
#define MV_DEV_88F5182 0x5182
#define MV_DEV_88F5281 0x5281
#define MV_DEV_88F6281 0x6281
#define MV_DEV_MV78100 0x6381
/*
* Decode windows definitions and macros
*/
#define MV_WIN_CPU_CTRL(n) (0x10 * (n) + (((n) < 8) ? 0x000 : 0x880))
#define MV_WIN_CPU_BASE(n) (0x10 * (n) + (((n) < 8) ? 0x004 : 0x884))
#define MV_WIN_CPU_REMAP_LO(n) (0x10 * (n) + (((n) < 8) ? 0x008 : 0x888))
#define MV_WIN_CPU_REMAP_HI(n) (0x10 * (n) + (((n) < 8) ? 0x00C : 0x88C))
#if defined(SOC_MV_DISCOVERY)
#define MV_WIN_CPU_MAX 14
#else
#define MV_WIN_CPU_MAX 8
#endif
#define MV_WIN_DDR_BASE(n) (0x8 * (n) + 0x0)
#define MV_WIN_DDR_SIZE(n) (0x8 * (n) + 0x4)
#define MV_WIN_DDR_MAX 4
#define MV_WIN_USB_CTRL(n) (0x10 * (n) + 0x0)
#define MV_WIN_USB_BASE(n) (0x10 * (n) + 0x4)
#define MV_WIN_USB_MAX 4
#define MV_WIN_ETH_BASE(n) (0x8 * (n) + 0x200)
#define MV_WIN_ETH_SIZE(n) (0x8 * (n) + 0x204)
#define MV_WIN_ETH_REMAP(n) (0x4 * (n) + 0x280)
#define MV_WIN_ETH_MAX 6
#define MV_WIN_IDMA_BASE(n) (0x8 * (n) + 0xa00)
#define MV_WIN_IDMA_SIZE(n) (0x8 * (n) + 0xa04)
#define MV_WIN_IDMA_REMAP(n) (0x4 * (n) + 0xa60)
#define MV_WIN_IDMA_CAP(n) (0x4 * (n) + 0xa70)
#define MV_WIN_IDMA_MAX 8
#define MV_IDMA_CHAN_MAX 4
#define MV_WIN_PCIE_CTRL(n) (0x10 * (((n) < 5) ? (n) : \
(n) + 1) + 0x1820)
#define MV_WIN_PCIE_BASE(n) (0x10 * (((n) < 5) ? (n) : \
(n) + 1) + 0x1824)
#define MV_WIN_PCIE_REMAP(n) (0x10 * (((n) < 5) ? (n) : \
(n) + 1) + 0x182C)
#define MV_WIN_PCIE_MAX 6
#define MV_PCIE_BAR(n) (0x04 * (n) + 0x1804)
#define MV_PCIE_BAR_MAX 3
#define WIN_REG_IDX_RD(pre,reg,off,base) \
static __inline uint32_t \
pre ## _ ## reg ## _read(int i) \
{ \
return (bus_space_read_4(obio_tag, base, off(i))); \
}
#define WIN_REG_BASE_IDX_RD(pre,reg,off) \
static __inline uint32_t \
pre ## _ ## reg ## _read(uint32_t base, int i) \
{ \
return (bus_space_read_4(obio_tag, base, off(i))); \
}
#define WIN_REG_IDX_WR(pre,reg,off,base) \
static __inline void \
pre ## _ ## reg ## _write(int i, uint32_t val) \
{ \
bus_space_write_4(obio_tag, base, off(i), val); \
}
#define WIN_REG_BASE_IDX_WR(pre,reg,off) \
static __inline void \
pre ## _ ## reg ## _write(uint32_t base, int i, uint32_t val) \
{ \
bus_space_write_4(obio_tag, base, off(i), val); \
}
#define WIN_REG_RD(pre,reg,off,base) \
static __inline uint32_t \
pre ## _ ## reg ## _read(void) \
{ \
return (bus_space_read_4(obio_tag, base, off)); \
}
#define WIN_REG_BASE_RD(pre,reg,off) \
static __inline uint32_t \
pre ## _ ## reg ## _read(uint32_t base) \
{ \
return (bus_space_read_4(obio_tag, base, off)); \
}
#define WIN_REG_WR(pre,reg,off,base) \
static __inline void \
pre ## _ ## reg ## _write(uint32_t val) \
{ \
bus_space_write_4(obio_tag, base, off, val); \
}
#define WIN_REG_BASE_WR(pre,reg,off) \
static __inline void \
pre ## _ ## reg ## _write(uint32_t base, uint32_t val) \
{ \
bus_space_write_4(obio_tag, base, off, val); \
}
#endif /* _MVREG_H_ */

122
sys/arm/mv/mvvar.h Normal file
View file

@ -0,0 +1,122 @@
/*-
* Copyright (c) 2002, 2003 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Jason R. Thorpe for Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the NetBSD Project by
* Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* from: FreeBSD: //depot/projects/arm/src/sys/arm/xscale/pxa2x0/pxa2x0var.h, rev 1
*
* $FreeBSD$
*/
#ifndef _MVVAR_H_
#define _MVVAR_H_
#include <sys/rman.h>
struct obio_softc {
bus_space_tag_t obio_bst; /* bus space tag */
struct rman obio_mem;
struct rman obio_irq;
struct rman obio_gpio;
};
struct obio_device {
const char *od_name;
u_long od_base;
u_long od_size;
u_int od_irqs[7 + 1]; /* keep additional entry for -1 sentinel */
u_int od_gpio[2 + 1]; /* as above for IRQ */
u_int od_pwr_mask;
struct resource_list od_resources;
};
struct decode_win {
int target; /* Mbus unit ID */
int attr; /* Attributes of the target interface */
vm_paddr_t base; /* Physical base addr */
uint32_t size;
int remap;
};
extern bus_space_tag_t obio_tag;
extern struct obio_device obio_devices[];
extern const struct decode_win *cpu_wins;
extern const struct decode_win *idma_wins;
extern int cpu_wins_no;
extern int idma_wins_no;
/* Function prototypes */
int mv_gpio_setup_intrhandler(const char *name, driver_filter_t *filt,
void (*hand)(void *), void *arg, int pin, int flags, void **cookiep);
void mv_gpio_intr_mask(int pin);
void mv_gpio_intr_unmask(int pin);
int mv_gpio_configure(uint32_t pin, uint32_t flags, uint32_t mask);
void mv_gpio_out(uint32_t pin, uint8_t val, uint8_t enable);
uint8_t mv_gpio_in(uint32_t pin);
int platform_pmap_init(void);
int soc_decode_win(void);
void soc_id(uint32_t *dev, uint32_t *rev);
void soc_identify(void);
void soc_dump_decode_win(void);
uint32_t soc_power_ctrl_get(uint32_t mask);
int decode_win_overlap(int, int, const struct decode_win *);
int win_cpu_can_remap(int);
void decode_win_idma_dump(void);
void decode_win_idma_setup(void);
int decode_win_idma_valid(void);
int ddr_is_active(int i);
uint32_t ddr_base(int i);
uint32_t ddr_size(int i);
uint32_t ddr_attr(int i);
uint32_t ddr_target(int i);
uint32_t cpu_extra_feat(void);
uint32_t get_tclk(void);
uint32_t read_cpu_ctrl(uint32_t);
void write_cpu_ctrl(uint32_t, uint32_t);
enum mbus_device_ivars {
MBUS_IVAR_BASE,
};
#define MBUS_ACCESSOR(var, ivar, type) \
__BUS_ACCESSOR(mbus, var, MBUS, ivar, type)
MBUS_ACCESSOR(base, BASE, u_long)
#undef MBUS_ACCESSOR
#endif /* _MVVAR_H_ */

355
sys/arm/mv/obio.c Normal file
View file

@ -0,0 +1,355 @@
/*-
* Copyright (c) 2006 Benno Rice. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* from: FreeBSD: //depot/projects/arm/src/sys/arm/xscale/pxa2x0/pxa2x0_obio.c, rev 1
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/malloc.h>
#include <sys/rman.h>
#include <machine/bus.h>
#include <machine/intr.h>
#include <arm/mv/mvvar.h>
#include <arm/mv/mvreg.h>
static void mbus_identify(driver_t *, device_t);
static int mbus_probe(device_t);
static int mbus_attach(device_t);
static void
mbus_identify(driver_t *driver, device_t parent)
{
BUS_ADD_CHILD(parent, 0, "mbus", 0);
}
static int
mbus_probe(device_t dev)
{
device_set_desc(dev, "Marvell Internal Bus (Mbus)");
return (0);
}
static int
mbus_attach(device_t dev)
{
struct obio_softc *sc;
struct obio_device *od;
int i;
device_t child;
sc = device_get_softc(dev);
sc->obio_bst = obio_tag;
sc->obio_mem.rm_type = RMAN_ARRAY;
sc->obio_mem.rm_descr = "Marvell OBIO Memory";
if (rman_init(&sc->obio_mem) != 0)
panic("mbus_attach: failed to init obio mem rman");
if (rman_manage_region(&sc->obio_mem, 0, ~0) != 0)
panic("mbus_attach: failed to set up obio mem rman");
sc->obio_irq.rm_type = RMAN_ARRAY;
sc->obio_irq.rm_descr = "Marvell OBIO IRQ";
if (rman_init(&sc->obio_irq) != 0)
panic("mbus_attach: failed to init obio irq rman");
if (rman_manage_region(&sc->obio_irq, 0, NIRQ - 1) != 0)
panic("mbus_attach: failed to set up obio irq rman");
sc->obio_gpio.rm_type = RMAN_ARRAY;
sc->obio_gpio.rm_descr = "Marvell GPIO";
if (rman_init(&sc->obio_gpio) != 0)
panic("mbus_attach: failed to init gpio rman");
if (rman_manage_region(&sc->obio_gpio, 0, MV_GPIO_MAX_NPINS - 1) != 0)
panic("mbus_attach: failed to set up gpio rman");
for (od = obio_devices; od->od_name != NULL; od++) {
if (soc_power_ctrl_get(od->od_pwr_mask) != od->od_pwr_mask)
continue;
resource_list_init(&od->od_resources);
resource_list_add(&od->od_resources, SYS_RES_MEMORY, 0,
od->od_base, od->od_base + od->od_size, od->od_size);
for (i = 0; od->od_irqs[i] != -1; i++) {
resource_list_add(&od->od_resources, SYS_RES_IRQ, i,
od->od_irqs[i], od->od_irqs[i], 1);
}
for (i = 0; od->od_gpio[i] != -1; i++) {
resource_list_add(&od->od_resources, SYS_RES_GPIO, i,
od->od_gpio[i], od->od_gpio[i], 1);
}
child = device_add_child(dev, od->od_name, -1);
device_set_ivars(child, od);
}
bus_generic_probe(dev);
bus_generic_attach(dev);
return (0);
}
static int
mbus_print_child(device_t dev, device_t child)
{
struct obio_device *od;
int rv;
od = (struct obio_device *)device_get_ivars(child);
if (od == NULL)
panic("Unknown device on %s", device_get_nameunit(dev));
rv = 0;
rv += bus_print_child_header(dev, child);
rv += resource_list_print_type(&od->od_resources, "at mem",
SYS_RES_MEMORY, "0x%08lx");
rv += resource_list_print_type(&od->od_resources, "irq",
SYS_RES_IRQ, "%ld");
rv += resource_list_print_type(&od->od_resources, "gpio",
SYS_RES_GPIO, "%ld");
if (device_get_flags(child))
rv += printf(" flags %#x", device_get_flags(child));
rv += bus_print_child_footer(dev, child);
return (rv);
}
static int
mbus_setup_intr(device_t dev, device_t child, struct resource *ires, int flags,
driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep)
{
struct obio_softc *sc;
int error;
sc = (struct obio_softc *)device_get_softc(dev);
if (rman_is_region_manager(ires, &sc->obio_gpio)) {
error = mv_gpio_setup_intrhandler(
device_get_nameunit(child), filt, intr, arg,
rman_get_start(ires), flags, cookiep);
if (error != 0)
return (error);
mv_gpio_intr_unmask(rman_get_start(ires));
return (0);
}
BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags, filt, intr, arg,
cookiep);
arm_unmask_irq(rman_get_start(ires));
return (0);
}
static int
mbus_teardown_intr(device_t dev, device_t child, struct resource *ires, void *cookie)
{
return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, ires, cookie));
}
static int
mbus_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
{
struct obio_device *od;
od = (struct obio_device *)device_get_ivars(child);
switch (which) {
case MBUS_IVAR_BASE:
*((u_long *)result) = od->od_base;
break;
default:
return (ENOENT);
}
return (0);
}
static struct resource_list *
mbus_get_resource_list(device_t dev, device_t child)
{
struct obio_device *od;
od = (struct obio_device *)device_get_ivars(child);
if (od == NULL)
return (NULL);
return (&od->od_resources);
}
static struct resource *
mbus_alloc_resource(device_t dev, device_t child, int type, int *rid,
u_long start, u_long end, u_long count, u_int flags)
{
struct obio_softc *sc;
struct obio_device *od;
struct resource *rv;
struct resource_list *rl;
struct resource_list_entry *rle = NULL;
struct rman *rm;
int needactivate;
sc = (struct obio_softc *)device_get_softc(dev);
if (type == SYS_RES_IRQ && IS_GPIO_IRQ(start)) {
type = SYS_RES_GPIO;
start = IRQ2GPIO(start);
}
switch (type) {
case SYS_RES_IRQ:
rm = &sc->obio_irq;
break;
case SYS_RES_MEMORY:
rm = &sc->obio_mem;
break;
case SYS_RES_GPIO:
rm = &sc->obio_gpio;
break;
default:
return (NULL);
}
if (device_get_parent(child) == dev) {
od = (struct obio_device *)device_get_ivars(child);
rl = &od->od_resources;
rle = resource_list_find(rl, type, *rid);
if (rle->res != NULL)
panic("mbus_alloc_resource: resource is busy");
}
if (rle) {
start = rle->start;
end = rle->end;
count = rle->count;
}
needactivate = flags & RF_ACTIVE;
flags &= ~RF_ACTIVE;
rv = rman_reserve_resource(rm, start, end, count, flags, child);
if (rv == NULL)
return (NULL);
if (rle)
rle->res = rv;
rman_set_rid(rv, *rid);
if (type == SYS_RES_MEMORY) {
rman_set_bustag(rv, sc->obio_bst);
rman_set_bushandle(rv, start);
}
if (needactivate)
if (bus_activate_resource(child, type, *rid, rv)) {
rman_release_resource(rv);
return (NULL);
}
return (rv);
}
static int
mbus_release_resource(device_t dev, device_t child, int type, int rid,
struct resource *r)
{
struct obio_device *od;
struct resource_list *rl;
struct resource_list_entry *rle;
if (device_get_parent(child) == dev) {
od = (struct obio_device *)device_get_ivars(child);
rl = &od->od_resources;
rle = resource_list_find(rl, type, rid);
if (!rle)
panic("mbus_release_resource: can't find resource");
if (!rle->res)
panic("mbus_release_resource: resource entry is not busy");
r = rle->res;
rle->res = NULL;
}
rman_release_resource(r);
return (0);
}
static int
mbus_activate_resource(device_t dev, device_t child, int type, int rid,
struct resource *r)
{
return (rman_activate_resource(r));
}
static device_method_t mbus_methods[] = {
DEVMETHOD(device_identify, mbus_identify),
DEVMETHOD(device_probe, mbus_probe),
DEVMETHOD(device_attach, mbus_attach),
DEVMETHOD(bus_print_child, mbus_print_child),
DEVMETHOD(bus_read_ivar, mbus_read_ivar),
DEVMETHOD(bus_setup_intr, mbus_setup_intr),
DEVMETHOD(bus_teardown_intr, mbus_teardown_intr),
DEVMETHOD(bus_get_resource_list, mbus_get_resource_list),
DEVMETHOD(bus_alloc_resource, mbus_alloc_resource),
DEVMETHOD(bus_release_resource, mbus_release_resource),
DEVMETHOD(bus_activate_resource, mbus_activate_resource),
{0, 0}
};
static driver_t mbus_driver = {
"mbus",
mbus_methods,
sizeof(struct obio_softc),
};
static devclass_t mbus_devclass;
DRIVER_MODULE(mbus, nexus, mbus_driver, mbus_devclass, 0, 0);

View file

@ -0,0 +1,177 @@
/*-
* Copyright (C) 2008 MARVELL INTERNATIONAL LTD.
* All rights reserved.
*
* Developed by Semihalf.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of MARVELL nor the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <vm/vm.h>
#include <vm/pmap.h>
#include <machine/pte.h>
#include <machine/pmap.h>
#include <machine/vmparam.h>
#include <arm/mv/mvreg.h>
#include <arm/mv/mvvar.h>
/*
* Virtual address space layout:
* -----------------------------
* 0x0000_0000 - 0xbfff_ffff : user process
*
* 0xc040_0000 - virtual_avail : kernel reserved (text, data, page tables
* : structures, ARM stacks etc.)
* virtual_avail - 0xefff_ffff : KVA (virtual_avail is typically < 0xc0a0_0000)
* 0xf000_0000 - 0xf0ff_ffff : no-cache allocation area (16MB)
* 0xf100_0000 - 0xf10f_ffff : SoC integrated devices registers range (1MB)
* 0xf110_0000 - 0xfffe_ffff : PCI, PCIE (MEM+IO) outbound windows (~238MB)
* 0xffff_0000 - 0xffff_0fff : 'high' vectors page (4KB)
* 0xffff_1000 - 0xffff_1fff : ARM_TP_ADDRESS/RAS page (4KB)
* 0xffff_2000 - 0xffff_ffff : unused (~55KB)
*/
const struct pmap_devmap *pmap_devmap_bootstrap_table;
vm_offset_t pmap_bootstrap_lastaddr;
/* Static device mappings. */
static const struct pmap_devmap pmap_devmap[] = {
/*
* Map the on-board devices VA == PA so that we can access them
* with the MMU on or off.
*/
{ /* SoC integrated peripherals registers range */
MV_BASE,
MV_PHYS_BASE,
MV_SIZE,
VM_PROT_READ | VM_PROT_WRITE,
PTE_NOCACHE,
},
{ /* PCIE I/O */
MV_PCIE_IO_BASE,
MV_PCIE_IO_PHYS_BASE,
MV_PCIE_IO_SIZE,
VM_PROT_READ | VM_PROT_WRITE,
PTE_NOCACHE,
},
{ /* PCIE Memory */
MV_PCIE_MEM_BASE,
MV_PCIE_MEM_PHYS_BASE,
MV_PCIE_MEM_SIZE,
VM_PROT_READ | VM_PROT_WRITE,
PTE_NOCACHE,
},
{ /* PCI I/O */
MV_PCI_IO_BASE,
MV_PCI_IO_PHYS_BASE,
MV_PCI_IO_SIZE,
VM_PROT_READ | VM_PROT_WRITE,
PTE_NOCACHE,
},
{ /* PCI Memory */
MV_PCI_MEM_BASE,
MV_PCI_MEM_PHYS_BASE,
MV_PCI_MEM_SIZE,
VM_PROT_READ | VM_PROT_WRITE,
PTE_NOCACHE,
},
{ /* 7-seg LED */
MV_DEV_CS0_BASE,
MV_DEV_CS0_PHYS_BASE,
MV_DEV_CS0_SIZE,
VM_PROT_READ | VM_PROT_WRITE,
PTE_NOCACHE,
},
{ 0, 0, 0, 0, 0, }
};
#if 0
int platform_pci_get_irq(u_int bus, u_int slot, u_int func, u_int pin)
{
int irq;
switch (slot) {
case 7:
irq = GPIO2IRQ(12); /* GPIO 0 for DB-88F5182 */
break; /* GPIO 12 for DB-88F5281 */
case 8:
case 9:
irq = GPIO2IRQ(13); /* GPIO 1 for DB-88F5182 */
break; /* GPIO 13 for DB-88F5281 */
default:
irq = -1;
break;
};
/*
* XXX This isn't the right place to setup GPIO, but it makes sure
* that PCI works on 5XXX targets where U-Boot doesn't set up the GPIO
* correctly to handle PCI IRQs (e.g., on 5182). This code will go
* away once we set up GPIO in a generic way in a proper place (TBD).
*/
if (irq >= 0)
mv_gpio_configure(IRQ2GPIO(irq), MV_GPIO_POLARITY |
MV_GPIO_LEVEL, ~0u);
return(irq);
}
#endif
int
platform_pmap_init(void)
{
pmap_bootstrap_lastaddr = MV_BASE - ARM_NOCACHE_KVA_SIZE;
pmap_devmap_bootstrap_table = &pmap_devmap[0];
return (0);
}
static void
platform_identify(void *dummy)
{
soc_identify();
/*
* XXX Board identification e.g. read out from FPGA or similar should
* go here
*/
}
SYSINIT(platform_identify, SI_SUB_CPU, SI_ORDER_SECOND, platform_identify, NULL);
/*
* TODO routine setting GPIO/MPP pins
*/

View file

@ -0,0 +1,4 @@
# $FreeBSD$
arm/mv/orion/orion.c standard
arm/mv/orion/db88f5xxx.c standard

189
sys/arm/mv/orion/orion.c Normal file
View file

@ -0,0 +1,189 @@
/*-
* Copyright (C) 2008 MARVELL INTERNATIONAL LTD.
* All rights reserved.
*
* Developed by Semihalf.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of MARVELL nor the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <machine/bus.h>
#include <arm/mv/mvreg.h>
#include <arm/mv/mvvar.h>
#if 0
#include <arm/mv/mv_pci.h>
extern int platform_pci_get_irq(u_int bus, u_int slot, u_int func, u_int pin);
#endif
struct obio_device obio_devices[] = {
{ "ic", MV_IC_BASE, MV_IC_SIZE,
{ -1 },
{ -1 },
CPU_PM_CTRL_NONE
},
{ "timer", MV_TIMERS_BASE, MV_TIMERS_SIZE,
{ MV_INT_BRIDGE, -1 },
{ -1 },
CPU_PM_CTRL_NONE
},
{ "gpio", MV_GPIO_BASE, MV_GPIO_SIZE,
{ MV_INT_GPIO7_0, MV_INT_GPIO15_8,
MV_INT_GPIO23_16, MV_INT_GPIO31_24, -1 },
{ -1 },
CPU_PM_CTRL_NONE
},
{ "uart", MV_UART0_BASE, MV_UART_SIZE,
{ MV_INT_UART0, -1 },
{ -1 },
CPU_PM_CTRL_NONE
},
{ "uart", MV_UART1_BASE, MV_UART_SIZE,
{ MV_INT_UART1, -1 },
{ -1 },
CPU_PM_CTRL_NONE
},
{ "idma", MV_IDMA_BASE, MV_IDMA_SIZE,
{ MV_INT_IDMA_ERR, MV_INT_IDMA0, MV_INT_IDMA1,
MV_INT_IDMA2, MV_INT_IDMA3, -1 },
{ -1 },
CPU_PM_CTRL_NONE
},
{ "ehci", MV_USB0_BASE, MV_USB_SIZE,
{ MV_INT_USB_BERR, MV_INT_USB_CI, -1 },
{ -1 },
CPU_PM_CTRL_NONE
},
{ "mge", MV_ETH0_BASE, MV_ETH_SIZE,
{ MV_INT_GBERX, MV_INT_GBETX, MV_INT_GBEMISC,
MV_INT_GBESUM, MV_INT_GBEERR, -1 },
{ -1 },
CPU_PM_CTRL_NONE
},
{ "twsi", MV_TWSI_BASE, MV_TWSI_SIZE,
{ -1 }, { -1 },
CPU_PM_CTRL_NONE
},
{ "pcib", MV_PCIE_BASE, MV_PCIE_SIZE,
{ MV_INT_PEX0_ERR, -1 },
{ -1 },
CPU_PM_CTRL_NONE
},
{ "pcib", MV_PCI_BASE, MV_PCI_SIZE,
{ MV_INT_PCI_ERR, -1 },
{-1 },
CPU_PM_CTRL_NONE
},
{ NULL, 0, 0, { 0 } }
};
#if 0
const struct mv_pci_info pci_info[] = {
{ 1, MV_PCIE_IO_BASE, MV_PCIE_IO_SIZE,
MV_PCIE_MEM_BASE, MV_PCIE_MEM_SIZE,
NULL, MV_INT_PEX0
},
{ 0, MV_PCI_IO_BASE, MV_PCI_IO_SIZE,
MV_PCI_MEM_BASE, MV_PCI_MEM_SIZE,
platform_pci_get_irq, -1
},
};
#endif
struct resource_spec mv_gpio_spec[] = {
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
{ SYS_RES_IRQ, 0, RF_ACTIVE },
{ SYS_RES_IRQ, 1, RF_ACTIVE },
{ SYS_RES_IRQ, 2, RF_ACTIVE },
{ SYS_RES_IRQ, 3, RF_ACTIVE },
{ -1, 0 }
};
const struct decode_win cpu_win_tbl[] = {
/* PCIE IO */
{ 4, 0x51, MV_PCIE_IO_PHYS_BASE, MV_PCIE_IO_SIZE, -1 },
/* PCI IO */
{ 3, 0x51, MV_PCI_IO_PHYS_BASE, MV_PCI_IO_SIZE, -1 },
/* PCIE MEM */
{ 4, 0x59, MV_PCIE_MEM_PHYS_BASE, MV_PCIE_MEM_SIZE, -1 },
/* PCI MEM */
{ 3, 0x59, MV_PCI_MEM_PHYS_BASE, MV_PCI_MEM_SIZE, -1 },
/* Device bus BOOT */
{ 1, 0x0f, MV_DEV_BOOT_PHYS_BASE, MV_DEV_BOOT_SIZE, -1 },
/* Device bus CS0 */
{ 1, 0x1e, MV_DEV_CS0_PHYS_BASE, MV_DEV_CS0_SIZE, -1 },
/* Device bus CS1 */
{ 1, 0x1d, MV_DEV_CS1_PHYS_BASE, MV_DEV_CS1_SIZE, -1 },
/* Device bus CS2 */
{ 1, 0x1b, MV_DEV_CS2_PHYS_BASE, MV_DEV_CS2_SIZE, -1 },
};
const struct decode_win *cpu_wins = cpu_win_tbl;
int cpu_wins_no = sizeof(cpu_win_tbl) / sizeof(struct decode_win);
/*
* Note: the decode windows table for IDMA does not explicitly have DRAM
* entries, which are not statically defined: active DDR banks (== windows)
* are established in run time from actual DDR windows settings. All active
* DDR banks are mapped into IDMA decode windows, so at least one IDMA decode
* window is occupied by the DDR bank; in case when all (MV_WIN_DDR_MAX)
* DDR banks are active, the remaining available IDMA decode windows for other
* targets is only MV_WIN_IDMA_MAX - MV_WIN_DDR_MAX.
*/
const struct decode_win idma_win_tbl[] = {
/* PCIE MEM */
{ 4, 0x59, MV_PCIE_MEM_PHYS_BASE, MV_PCIE_MEM_SIZE, -1 },
/* PCI MEM */
{ 3, 0x59, MV_PCI_MEM_PHYS_BASE, MV_PCI_MEM_SIZE, -1 },
/* Device bus BOOT */
{ 1, 0x0f, MV_DEV_BOOT_PHYS_BASE, MV_DEV_BOOT_SIZE, -1 },
/* Device bus CS0 */
{ 1, 0x1e, MV_DEV_CS0_PHYS_BASE, MV_DEV_CS0_SIZE, -1 },
/* Device bus CS1 */
{ 1, 0x1d, MV_DEV_CS1_PHYS_BASE, MV_DEV_CS1_SIZE, -1 },
/* Device bus CS2 */
{ 1, 0x1b, MV_DEV_CS2_PHYS_BASE, MV_DEV_CS2_SIZE, -1 },
};
const struct decode_win *idma_wins = idma_win_tbl;
int idma_wins_no = sizeof(idma_win_tbl) / sizeof(struct decode_win);

View file

@ -0,0 +1,13 @@
# $FreeBSD$
include "../mv/std.mv"
files "../mv/orion/files.db88f5xxx"
makeoptions KERNPHYSADDR=0x00400000
makeoptions KERNVIRTADDR=0xc0400000
options KERNPHYSADDR=0x00400000
options KERNVIRTADDR=0xc0400000
options PHYSADDR=0x00000000
options PHYSMEM_SIZE=0x08000000
options STARTUP_PAGETABLE_ADDR=0x00100000

184
sys/arm/mv/rtc.c Normal file
View file

@ -0,0 +1,184 @@
/*-
* Copyright (C) 2008 MARVELL INTERNATIONAL LTD.
* All rights reserved.
*
* Developed by Semihalf.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of MARVELL nor the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/lock.h>
#include <sys/time.h>
#include <sys/clock.h>
#include <sys/resource.h>
#include <sys/systm.h>
#include <sys/rman.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include "clock_if.h"
#define MV_RTC_TIME_REG 0x00
#define MV_RTC_DATE_REG 0x04
#define YEAR_BASE 2000
struct mv_rtc_softc {
device_t dev;
struct resource *res[1];
};
static struct resource_spec res_spec[] = {
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
{ -1, 0 }
};
static int mv_rtc_probe(device_t dev);
static int mv_rtc_attach(device_t dev);
static int mv_rtc_gettime(device_t dev, struct timespec *ts);
static int mv_rtc_settime(device_t dev, struct timespec *ts);
static uint32_t mv_rtc_reg_read(struct mv_rtc_softc *sc, bus_size_t off);
static int mv_rtc_reg_write(struct mv_rtc_softc *sc, bus_size_t off,
uint32_t val);
static device_method_t mv_rtc_methods[] = {
DEVMETHOD(device_probe, mv_rtc_probe),
DEVMETHOD(device_attach, mv_rtc_attach),
DEVMETHOD(clock_gettime, mv_rtc_gettime),
DEVMETHOD(clock_settime, mv_rtc_settime),
{ 0, 0 },
};
static driver_t mv_rtc_driver = {
"rtc",
mv_rtc_methods,
sizeof(struct mv_rtc_softc),
};
static devclass_t mv_rtc_devclass;
DRIVER_MODULE(mv_rtc, mbus, mv_rtc_driver, mv_rtc_devclass, 0, 0);
static int
mv_rtc_probe(device_t dev)
{
device_set_desc(dev, "Marvell Integrated RTC");
return (0);
}
static int
mv_rtc_attach(device_t dev)
{
struct mv_rtc_softc *sc;
sc = device_get_softc(dev);
sc->dev = dev;
clock_register(dev, 1000000);
if (bus_alloc_resources(dev, res_spec, sc->res)) {
device_printf(dev, "could not allocate resources\n");
return (ENXIO);
}
return (0);
}
static int
mv_rtc_gettime(device_t dev, struct timespec *ts)
{
struct clocktime ct;
struct mv_rtc_softc *sc;
uint32_t val;
sc = device_get_softc(dev);
val = mv_rtc_reg_read(sc, MV_RTC_TIME_REG);
ct.nsec = 0;
ct.sec = FROMBCD(val & 0x7f);
ct.min = FROMBCD((val & 0x7f00) >> 8);
ct.hour = FROMBCD((val & 0x3f0000) >> 16);
ct.dow = FROMBCD((val & 0x7000000) >> 24) - 1;
val = mv_rtc_reg_read(sc, MV_RTC_DATE_REG);
ct.day = FROMBCD(val & 0x7f);
ct.mon = FROMBCD((val & 0x1f00) >> 8);
ct.year = YEAR_BASE + FROMBCD((val & 0xff0000) >> 16);
return (clock_ct_to_ts(&ct, ts));
}
static int
mv_rtc_settime(device_t dev, struct timespec *ts)
{
struct clocktime ct;
struct mv_rtc_softc *sc;
uint32_t val;
sc = device_get_softc(dev);
/* Resolution: 1 sec */
if (ts->tv_nsec >= 500000000)
ts->tv_sec++;
ts->tv_nsec = 0;
clock_ts_to_ct(ts, &ct);
val = TOBCD(ct.sec) | (TOBCD(ct.min) << 8) |
(TOBCD(ct.hour) << 16) | (TOBCD( ct.dow + 1) << 24);
mv_rtc_reg_write(sc, MV_RTC_TIME_REG, val);
val = TOBCD(ct.day) | (TOBCD(ct.mon) << 8) |
(TOBCD(ct.year - YEAR_BASE) << 16);
mv_rtc_reg_write(sc, MV_RTC_DATE_REG, val);
return (0);
}
static uint32_t
mv_rtc_reg_read(struct mv_rtc_softc *sc, bus_size_t off)
{
return (bus_read_4(sc->res[0], off));
}
static int
mv_rtc_reg_write(struct mv_rtc_softc *sc, bus_size_t off, uint32_t val)
{
bus_write_4(sc->res[0], off, val);
return (0);
}

5
sys/arm/mv/std.mv Normal file
View file

@ -0,0 +1,5 @@
# $FreeBSD$
files "../mv/files.mv"
cpu CPU_ARM9E
makeoptions CONF_CFLAGS="-march=armv5te"

381
sys/arm/mv/timer.c Normal file
View file

@ -0,0 +1,381 @@
/*-
* Copyright (c) 2006 Benno Rice.
* Copyright (C) 2007-2008 MARVELL INTERNATIONAL LTD.
* All rights reserved.
*
* Adapted to Marvell SoC by Semihalf.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* from: FreeBSD: //depot/projects/arm/src/sys/arm/xscale/pxa2x0/pxa2x0_timer.c, rev 1
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/malloc.h>
#include <sys/rman.h>
#include <sys/timetc.h>
#include <sys/watchdog.h>
#include <machine/bus.h>
#include <machine/cpu.h>
#include <machine/frame.h>
#include <machine/intr.h>
#include <arm/mv/mvreg.h>
#include <arm/mv/mvvar.h>
#define MV_TIMER_TICK (get_tclk() / hz)
#define INITIAL_TIMECOUNTER (0xffffffff)
#define MAX_WATCHDOG_TICKS (0xffffffff)
struct mv_timer_softc {
struct resource * timer_res[2];
bus_space_tag_t timer_bst;
bus_space_handle_t timer_bsh;
struct mtx timer_mtx;
};
static struct resource_spec mv_timer_spec[] = {
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
{ SYS_RES_IRQ, 0, RF_ACTIVE },
{ -1, 0 }
};
static struct mv_timer_softc *timer_softc = NULL;
static int timers_initialized = 0;
static int mv_timer_probe(device_t);
static int mv_timer_attach(device_t);
static int mv_hardclock(void *);
static unsigned mv_timer_get_timecount(struct timecounter *);
static uint32_t mv_get_timer_control(void);
static void mv_set_timer_control(uint32_t);
static uint32_t mv_get_timer(uint32_t);
static void mv_set_timer(uint32_t, uint32_t);
static void mv_set_timer_rel(uint32_t, uint32_t);
static void mv_watchdog_enable(void);
static void mv_watchdog_disable(void);
static void mv_watchdog_event(void *, unsigned int, int *);
static void mv_setup_timer(void);
static void mv_setup_timercount(void);
static struct timecounter mv_timer_timecounter = {
.tc_get_timecount = mv_timer_get_timecount,
.tc_name = "CPU Timer",
.tc_frequency = 0, /* This is assigned on the fly in the init sequence */
.tc_counter_mask = ~0u,
.tc_quality = 1000,
};
static int
mv_timer_probe(device_t dev)
{
device_set_desc(dev, "Marvell CPU Timer");
return (0);
}
static int
mv_timer_attach(device_t dev)
{
int error;
void *ihl;
struct mv_timer_softc *sc;
if (timer_softc != NULL)
return (ENXIO);
sc = (struct mv_timer_softc *)device_get_softc(dev);
timer_softc = sc;
error = bus_alloc_resources(dev, mv_timer_spec, sc->timer_res);
if (error) {
device_printf(dev, "could not allocate resources\n");
return (ENXIO);
}
sc->timer_bst = rman_get_bustag(sc->timer_res[0]);
sc->timer_bsh = rman_get_bushandle(sc->timer_res[0]);
mtx_init(&timer_softc->timer_mtx, "watchdog", NULL, MTX_DEF);
mv_watchdog_disable();
EVENTHANDLER_REGISTER(watchdog_list, mv_watchdog_event, sc, 0);
if (bus_setup_intr(dev, sc->timer_res[1], INTR_TYPE_CLK,
mv_hardclock, NULL, NULL, &ihl) != 0) {
bus_release_resources(dev, mv_timer_spec, sc->timer_res);
device_printf(dev, "could not setup hardclock interrupt\n");
return (ENXIO);
}
mv_setup_timercount();
timers_initialized = 1;
return (0);
}
static int
mv_hardclock(void *arg)
{
uint32_t irq_cause;
struct trapframe *frame;
frame = (struct trapframe *)arg;
hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame));
irq_cause = read_cpu_ctrl(BRIDGE_IRQ_CAUSE);
irq_cause &= ~(IRQ_TIMER0);
write_cpu_ctrl(BRIDGE_IRQ_CAUSE, irq_cause);
return (FILTER_HANDLED);
}
static device_method_t mv_timer_methods[] = {
DEVMETHOD(device_probe, mv_timer_probe),
DEVMETHOD(device_attach, mv_timer_attach),
{ 0, 0 }
};
static driver_t mv_timer_driver = {
"timer",
mv_timer_methods,
sizeof(struct mv_timer_softc),
};
static devclass_t mv_timer_devclass;
DRIVER_MODULE(timer, mbus, mv_timer_driver, mv_timer_devclass, 0, 0);
static unsigned
mv_timer_get_timecount(struct timecounter *tc)
{
return (INITIAL_TIMECOUNTER - mv_get_timer(1));
}
void
cpu_initclocks(void)
{
uint32_t irq_cause, irq_mask;
mv_setup_timer();
irq_cause = read_cpu_ctrl(BRIDGE_IRQ_CAUSE);
irq_cause &= ~(IRQ_TIMER0);
write_cpu_ctrl(BRIDGE_IRQ_CAUSE, irq_cause);
irq_mask = read_cpu_ctrl(BRIDGE_IRQ_MASK);
irq_mask |= IRQ_TIMER0_MASK;
write_cpu_ctrl(BRIDGE_IRQ_MASK, irq_mask);
mv_timer_timecounter.tc_frequency = get_tclk();
tc_init(&mv_timer_timecounter);
}
void
cpu_startprofclock(void)
{
}
void
cpu_stopprofclock(void)
{
}
void
DELAY(int usec)
{
uint32_t val, val_temp;
int32_t nticks;
if (!timers_initialized) {
for (; usec > 0; usec--)
for (val = 100; val > 0; val--)
;
return;
}
val = mv_get_timer(1);
nticks = ((get_tclk() / 1000000 + 1) * usec);
while (nticks > 0) {
val_temp = mv_get_timer(1);
if (val > val_temp)
nticks -= (val - val_temp);
else
nticks -= (val + (INITIAL_TIMECOUNTER - val_temp));
val = val_temp;
}
}
static uint32_t
mv_get_timer_control(void)
{
return (bus_space_read_4(timer_softc->timer_bst,
timer_softc->timer_bsh, CPU_TIMER_CONTROL));
}
static void
mv_set_timer_control(uint32_t val)
{
bus_space_write_4(timer_softc->timer_bst,
timer_softc->timer_bsh, CPU_TIMER_CONTROL, val);
}
static uint32_t
mv_get_timer(uint32_t timer)
{
return (bus_space_read_4(timer_softc->timer_bst,
timer_softc->timer_bsh, CPU_TIMER0 + timer * 0x8));
}
static void
mv_set_timer(uint32_t timer, uint32_t val)
{
bus_space_write_4(timer_softc->timer_bst,
timer_softc->timer_bsh, CPU_TIMER0 + timer * 0x8, val);
}
static void
mv_set_timer_rel(uint32_t timer, uint32_t val)
{
bus_space_write_4(timer_softc->timer_bst,
timer_softc->timer_bsh, CPU_TIMER0_REL + timer * 0x8, val);
}
static void
mv_watchdog_enable(void)
{
uint32_t val;
uint32_t irq_cause, irq_mask;
irq_cause = read_cpu_ctrl(BRIDGE_IRQ_CAUSE);
irq_cause &= ~(IRQ_TIMER_WD);
write_cpu_ctrl(BRIDGE_IRQ_CAUSE, irq_cause);
irq_mask = read_cpu_ctrl(BRIDGE_IRQ_MASK);
irq_mask |= IRQ_TIMER_WD_MASK;
write_cpu_ctrl(BRIDGE_IRQ_MASK, irq_mask);
val = read_cpu_ctrl(RSTOUTn_MASK);
val |= WD_RST_OUT_EN;
write_cpu_ctrl(RSTOUTn_MASK, val);
val = mv_get_timer_control();
val |= CPU_TIMER_WD_EN | CPU_TIMER_WD_AUTO;
mv_set_timer_control(val);
}
static void
mv_watchdog_disable(void)
{
uint32_t val;
uint32_t irq_cause, irq_mask;
val = mv_get_timer_control();
val &= ~(CPU_TIMER_WD_EN | CPU_TIMER_WD_AUTO);
mv_set_timer_control(val);
val = read_cpu_ctrl(RSTOUTn_MASK);
val &= ~WD_RST_OUT_EN;
write_cpu_ctrl(RSTOUTn_MASK, val);
irq_mask = read_cpu_ctrl(BRIDGE_IRQ_MASK);
irq_mask &= ~(IRQ_TIMER_WD_MASK);
write_cpu_ctrl(BRIDGE_IRQ_MASK, irq_mask);
irq_cause = read_cpu_ctrl(BRIDGE_IRQ_CAUSE);
irq_cause &= ~(IRQ_TIMER_WD);
write_cpu_ctrl(BRIDGE_IRQ_CAUSE, irq_cause);
}
/*
* Watchdog event handler.
*/
static void
mv_watchdog_event(void *arg, unsigned int cmd, int *error)
{
uint64_t ns;
uint64_t ticks;
mtx_lock(&timer_softc->timer_mtx);
if (cmd == 0)
mv_watchdog_disable();
else {
/*
* Watchdog timeout is in nanosecs, calculation according to
* watchdog(9)
*/
ns = (uint64_t)1 << (cmd & WD_INTERVAL);
ticks = (uint64_t)(ns * get_tclk()) / 1000000000;
if (ticks > MAX_WATCHDOG_TICKS)
mv_watchdog_disable();
else {
/* Timer 2 is the watchdog */
mv_set_timer(2, ticks);
mv_watchdog_enable();
*error = 0;
}
}
mtx_unlock(&timer_softc->timer_mtx);
}
static void
mv_setup_timer(void)
{
uint32_t val;
mv_set_timer_rel(0, MV_TIMER_TICK);
mv_set_timer(0, MV_TIMER_TICK);
val = mv_get_timer_control();
val |= CPU_TIMER0_EN | CPU_TIMER0_AUTO;
mv_set_timer_control(val);
}
static void
mv_setup_timercount(void)
{
uint32_t val;
mv_set_timer_rel(1, INITIAL_TIMECOUNTER);
mv_set_timer(1, INITIAL_TIMECOUNTER);
val = mv_get_timer_control();
val |= CPU_TIMER1_EN | CPU_TIMER1_AUTO;
mv_set_timer_control(val);
}

523
sys/arm/mv/twsi.c Normal file
View file

@ -0,0 +1,523 @@
/*-
* Copyright (C) 2008 MARVELL INTERNATIONAL LTD.
* All rights reserved.
*
* Developed by Semihalf.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of MARVELL nor the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Driver for the TWSI (aka I2C, aka IIC) bus controller found on Marvell
* SoCs. Supports master operation only, and works in polling mode.
*
* Calls to DELAY() are needed per Application Note AN-179 "TWSI Software
* Guidelines for Discovery(TM), Horizon (TM) and Feroceon(TM) Devices".
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/resource.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <sys/rman.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <dev/iicbus/iiconf.h>
#include <dev/iicbus/iicbus.h>
#include "iicbus_if.h"
#define MV_TWSI_NAME "twsi"
#define TWSI_SLAVE_ADDR 0x00
#define TWSI_EXT_SLAVE_ADDR 0x10
#define TWSI_DATA 0x04
#define TWSI_CONTROL 0x08
#define TWSI_CONTROL_ACK (1 << 2)
#define TWSI_CONTROL_IFLG (1 << 3)
#define TWSI_CONTROL_STOP (1 << 4)
#define TWSI_CONTROL_START (1 << 5)
#define TWSI_CONTROL_TWSIEN (1 << 6)
#define TWSI_CONTROL_INTEN (1 << 7)
#define TWSI_STATUS 0x0c
#define TWSI_STATUS_START 0x08
#define TWSI_STATUS_RPTD_START 0x10
#define TWSI_STATUS_ADDR_W_ACK 0x18
#define TWSI_STATUS_DATA_WR_ACK 0x28
#define TWSI_STATUS_ADDR_R_ACK 0x40
#define TWSI_STATUS_DATA_RD_ACK 0x50
#define TWSI_STATUS_DATA_RD_NOACK 0x58
#define TWSI_BAUD_RATE 0x0c
#define TWSI_BAUD_RATE_94DOT3 0x53 /* N=3, M=10 */
#define TWSI_BAUD_RATE_74DOT1 0x6b /* N=3, M=13 */
#define TWSI_BAUD_RATE_51DOT8 0x4c /* N=4, M=9 */
#define TWSI_BAUD_RATE_99DOT7 0x66 /* N=6, M=12 */
#define TWSI_SOFT_RESET 0x1c
#define TWSI_DEBUG
#undef TWSI_DEBUG
#ifdef TWSI_DEBUG
#define debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt,##args); } while (0)
#else
#define debugf(fmt, args...)
#endif
struct mv_twsi_softc {
device_t dev;
struct resource *res[1]; /* SYS_RES_MEMORY */
struct mtx mutex;
device_t iicbus;
};
static int mv_twsi_probe(device_t);
static int mv_twsi_attach(device_t);
static int mv_twsi_detach(device_t);
static int mv_twsi_reset(device_t dev, u_char speed, u_char addr,
u_char *oldaddr);
static int mv_twsi_repeated_start(device_t dev, u_char slave, int timeout);
static int mv_twsi_start(device_t dev, u_char slave, int timeout);
static int mv_twsi_stop(device_t dev);
static int mv_twsi_read(device_t dev, char *buf, int len, int *read, int last,
int delay);
static int mv_twsi_write(device_t dev, char *buf, int len, int *sent,
int timeout);
static struct resource_spec res_spec[] = {
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
{ -1, 0 }
};
static device_method_t mv_twsi_methods[] = {
/* device interface */
DEVMETHOD(device_probe, mv_twsi_probe),
DEVMETHOD(device_attach, mv_twsi_attach),
DEVMETHOD(device_detach, mv_twsi_detach),
/* iicbus interface */
DEVMETHOD(iicbus_callback, iicbus_null_callback),
DEVMETHOD(iicbus_repeated_start, mv_twsi_repeated_start),
DEVMETHOD(iicbus_start, mv_twsi_start),
DEVMETHOD(iicbus_stop, mv_twsi_stop),
DEVMETHOD(iicbus_write, mv_twsi_write),
DEVMETHOD(iicbus_read, mv_twsi_read),
DEVMETHOD(iicbus_reset, mv_twsi_reset),
DEVMETHOD(iicbus_transfer, iicbus_transfer_gen),
{ 0, 0 }
};
static devclass_t mv_twsi_devclass;
static driver_t mv_twsi_driver = {
MV_TWSI_NAME,
mv_twsi_methods,
sizeof(struct mv_twsi_softc),
};
DRIVER_MODULE(twsi, mbus, mv_twsi_driver, mv_twsi_devclass, 0, 0);
DRIVER_MODULE(iicbus, twsi, iicbus_driver, iicbus_devclass, 0, 0);
MODULE_DEPEND(twsi, iicbus, 1, 1, 1);
static __inline uint32_t
TWSI_READ(struct mv_twsi_softc *sc, bus_size_t off)
{
return (bus_read_4(sc->res[0], off));
}
static __inline void
TWSI_WRITE(struct mv_twsi_softc *sc, bus_size_t off, uint32_t val)
{
bus_write_4(sc->res[0], off, val);
}
static __inline void
twsi_control_clear(struct mv_twsi_softc *sc, uint32_t mask)
{
uint32_t val;
val = TWSI_READ(sc, TWSI_CONTROL);
val &= ~mask;
TWSI_WRITE(sc, TWSI_CONTROL, val);
}
static __inline void
twsi_control_set(struct mv_twsi_softc *sc, uint32_t mask)
{
uint32_t val;
val = TWSI_READ(sc, TWSI_CONTROL);
val |= mask;
TWSI_WRITE(sc, TWSI_CONTROL, val);
}
static __inline void
twsi_clear_iflg(struct mv_twsi_softc *sc)
{
DELAY(1000);
twsi_control_clear(sc, TWSI_CONTROL_IFLG);
DELAY(1000);
}
/*
* timeout given in us
* returns
* 0 on sucessfull mask change
* non-zero on timeout
*/
static int
twsi_poll_ctrl(struct mv_twsi_softc *sc, int timeout, uint32_t mask)
{
timeout /= 10;
while (!(TWSI_READ(sc, TWSI_CONTROL) & mask)) {
DELAY(10);
if (--timeout < 0)
return (timeout);
}
return (0);
}
/*
* 'timeout' is given in us. Note also that timeout handling is not exact --
* twsi_locked_start() total wait can be more than 2 x timeout
* (twsi_poll_ctrl() is called twice). 'mask' can be either TWSI_STATUS_START
* or TWSI_STATUS_RPTD_START
*/
static int
twsi_locked_start(device_t dev, struct mv_twsi_softc *sc, int32_t mask,
u_char slave, int timeout)
{
int read_access, iflg_set = 0;
uint32_t status;
mtx_assert(&sc->mutex, MA_OWNED);
if (mask == TWSI_STATUS_RPTD_START)
/* read IFLG to know if it should be cleared later; from NBSD */
iflg_set = TWSI_READ(sc, TWSI_CONTROL) & TWSI_CONTROL_IFLG;
twsi_control_set(sc, TWSI_CONTROL_START);
if (mask == TWSI_STATUS_RPTD_START && iflg_set) {
debugf("IFLG set, clearing\n");
twsi_clear_iflg(sc);
}
/*
* Without this delay we timeout checking IFLG if the timeout is 0.
* NBSD driver always waits here too.
*/
DELAY(1000);
if (twsi_poll_ctrl(sc, timeout, TWSI_CONTROL_IFLG)) {
debugf("timeout sending %sSTART condition\n",
mask == TWSI_STATUS_START ? "" : "repeated ");
return (IIC_ETIMEOUT);
}
status = TWSI_READ(sc, TWSI_STATUS);
if (status != mask) {
debugf("wrong status (%02x) after sending %sSTART condition\n",
status, mask == TWSI_STATUS_START ? "" : "repeated ");
return (IIC_ESTATUS);
}
TWSI_WRITE(sc, TWSI_DATA, slave);
DELAY(1000);
twsi_clear_iflg(sc);
if (twsi_poll_ctrl(sc, timeout, TWSI_CONTROL_IFLG)) {
debugf("timeout sending slave address\n");
return (IIC_ETIMEOUT);
}
read_access = (slave & 0x1) ? 1 : 0;
status = TWSI_READ(sc, TWSI_STATUS);
if (status != (read_access ?
TWSI_STATUS_ADDR_R_ACK : TWSI_STATUS_ADDR_W_ACK)) {
debugf("no ACK (status: %02x) after sending slave address\n",
status);
return (IIC_ENOACK);
}
return (IIC_NOERR);
}
static int
mv_twsi_probe(device_t dev)
{
device_set_desc(dev, "Marvell Integrated I2C Bus Controller");
return (BUS_PROBE_DEFAULT);
}
static int
mv_twsi_attach(device_t dev)
{
struct mv_twsi_softc *sc;
sc = device_get_softc(dev);
sc->dev = dev;
mtx_init(&sc->mutex, device_get_nameunit(dev), MV_TWSI_NAME, MTX_DEF);
/* Allocate IO resources */
if (bus_alloc_resources(dev, res_spec, sc->res)) {
device_printf(dev, "could not allocate resources\n");
mv_twsi_detach(dev);
return (ENXIO);
}
sc->iicbus = device_add_child(dev, "iicbus", -1);
if (sc->iicbus == NULL) {
device_printf(dev, "could not add iicbus child\n");
mv_twsi_detach(dev);
return (ENXIO);
}
bus_generic_attach(dev);
return (0);
}
static int
mv_twsi_detach(device_t dev)
{
struct mv_twsi_softc *sc;
int rv;
sc = device_get_softc(dev);
if ((rv = bus_generic_detach(dev)) != 0)
return (rv);
if (sc->iicbus != NULL)
if ((rv = device_delete_child(dev, sc->iicbus)) != 0)
return (rv);
bus_release_resources(dev, res_spec, sc->res);
mtx_destroy(&sc->mutex);
return (0);
}
/*
* Only slave mode supported, disregard [old]addr
*/
static int
mv_twsi_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
{
struct mv_twsi_softc *sc;
uint32_t baud_rate;
sc = device_get_softc(dev);
switch (speed) {
case IIC_SLOW:
baud_rate = TWSI_BAUD_RATE_51DOT8;
break;
case IIC_FAST:
baud_rate = TWSI_BAUD_RATE_51DOT8;
break;
case IIC_UNKNOWN:
case IIC_FASTEST:
default:
baud_rate = TWSI_BAUD_RATE_99DOT7;
break;
}
mtx_lock(&sc->mutex);
TWSI_WRITE(sc, TWSI_SOFT_RESET, 0x0);
DELAY(2000);
TWSI_WRITE(sc, TWSI_BAUD_RATE, baud_rate);
TWSI_WRITE(sc, TWSI_CONTROL, TWSI_CONTROL_TWSIEN | TWSI_CONTROL_ACK);
DELAY(1000);
mtx_unlock(&sc->mutex);
return (0);
}
/*
* timeout is given in us
*/
static int
mv_twsi_repeated_start(device_t dev, u_char slave, int timeout)
{
struct mv_twsi_softc *sc;
int rv;
sc = device_get_softc(dev);
mtx_lock(&sc->mutex);
rv = twsi_locked_start(dev, sc, TWSI_STATUS_RPTD_START, slave,
timeout);
mtx_unlock(&sc->mutex);
if (rv) {
mv_twsi_stop(dev);
return (rv);
} else
return (IIC_NOERR);
}
/*
* timeout is given in us
*/
static int
mv_twsi_start(device_t dev, u_char slave, int timeout)
{
struct mv_twsi_softc *sc;
int rv;
sc = device_get_softc(dev);
mtx_lock(&sc->mutex);
rv = twsi_locked_start(dev, sc, TWSI_STATUS_START, slave, timeout);
mtx_unlock(&sc->mutex);
if (rv) {
mv_twsi_stop(dev);
return (rv);
} else
return (IIC_NOERR);
}
static int
mv_twsi_stop(device_t dev)
{
struct mv_twsi_softc *sc;
sc = device_get_softc(dev);
mtx_lock(&sc->mutex);
twsi_control_set(sc, TWSI_CONTROL_STOP);
DELAY(1000);
twsi_clear_iflg(sc);
mtx_unlock(&sc->mutex);
return (IIC_NOERR);
}
static int
mv_twsi_read(device_t dev, char *buf, int len, int *read, int last, int delay)
{
struct mv_twsi_softc *sc;
uint32_t status;
int last_byte, rv;
sc = device_get_softc(dev);
mtx_lock(&sc->mutex);
*read = 0;
while (*read < len) {
/*
* Check if we are reading last byte of the last buffer,
* do not send ACK then, per I2C specs
*/
last_byte = ((*read == len - 1) && last) ? 1 : 0;
if (last_byte)
twsi_control_clear(sc, TWSI_CONTROL_ACK);
else
twsi_control_set(sc, TWSI_CONTROL_ACK);
DELAY (1000);
twsi_clear_iflg(sc);
if (twsi_poll_ctrl(sc, delay, TWSI_CONTROL_IFLG)) {
debugf("timeout reading data\n");
rv = IIC_ETIMEOUT;
goto out;
}
status = TWSI_READ(sc, TWSI_STATUS);
if (status != (last_byte ?
TWSI_STATUS_DATA_RD_NOACK : TWSI_STATUS_DATA_RD_ACK)) {
debugf("wrong status (%02x) while reading\n", status);
rv = IIC_ESTATUS;
goto out;
}
*buf++ = TWSI_READ(sc, TWSI_DATA);
(*read)++;
}
rv = IIC_NOERR;
out:
mtx_unlock(&sc->mutex);
return (rv);
}
static int
mv_twsi_write(device_t dev, char *buf, int len, int *sent, int timeout)
{
struct mv_twsi_softc *sc;
uint32_t status;
int rv;
sc = device_get_softc(dev);
mtx_lock(&sc->mutex);
*sent = 0;
while (*sent < len) {
TWSI_WRITE(sc, TWSI_DATA, *buf++);
twsi_clear_iflg(sc);
if (twsi_poll_ctrl(sc, timeout, TWSI_CONTROL_IFLG)) {
debugf("timeout writing data\n");
rv = IIC_ETIMEOUT;
goto out;
}
status = TWSI_READ(sc, TWSI_STATUS);
if (status != TWSI_STATUS_DATA_WR_ACK) {
debugf("wrong status (%02x) while writing\n", status);
rv = IIC_ESTATUS;
goto out;
}
(*sent)++;
}
rv = IIC_NOERR;
out:
mtx_unlock(&sc->mutex);
return (rv);
}

View file

@ -75,7 +75,8 @@ FILES_CPU_FUNC = $S/$M/$M/cpufunc_asm_arm7tdmi.S \
$S/$M/$M/cpufunc_asm_arm8.S $S/$M/$M/cpufunc_asm_arm9.S \
$S/$M/$M/cpufunc_asm_sa1.S $S/$M/$M/cpufunc_asm_arm10.S \
$S/$M/$M/cpufunc_asm_xscale.S $S/$M/$M/cpufunc_asm.S \
$S/$M/$M/cpufunc_asm_xscale_c3.S $S/$M/$M/cpufunc_asm_armv5_ec.S
$S/$M/$M/cpufunc_asm_xscale_c3.S $S/$M/$M/cpufunc_asm_armv5_ec.S \
$S/$M/$M/cpufunc_asm_feroceon.S
KERNEL_EXTRA=trampoline
KERNEL_EXTRA_INSTALL=kernel.gz.tramp
trampoline: ${KERNEL_KO}.tramp

View file

@ -20,7 +20,11 @@ KERNPHYSADDR opt_global.h
KERNVIRTADDR opt_global.h
LOADERRAMADDR opt_global.h
PHYSADDR opt_global.h
PHYSMEM_SIZE opt_global.h
SKYEYE_WORKAROUNDS opt_global.h
SOC_MV_DISCOVERY opt_global.h
SOC_MV_KIRKWOOD opt_global.h
SOC_MV_ORION opt_global.h
STARTUP_PAGETABLE_ADDR opt_global.h
XSCALE_CACHE_READ_WRITE_ALLOCATE opt_global.h
XSACLE_DISABLE_CCNT opt_timer.h

View file

@ -0,0 +1,81 @@
/*-
* Copyright (C) 2007 MARVELL INTERNATIONAL LTD.
* All rights reserved.
*
* Developed by Semihalf.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of MARVELL nor the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <machine/bus.h>
#include <sys/rman.h>
#include <machine/resource.h>
#include <dev/uart/uart.h>
#include <dev/uart/uart_bus.h>
#include <dev/uart/uart_cpu.h>
#include <arm/mv/mvvar.h>
static int uart_mbus_probe(device_t dev);
static device_method_t uart_mbus_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, uart_mbus_probe),
DEVMETHOD(device_attach, uart_bus_attach),
DEVMETHOD(device_detach, uart_bus_detach),
{ 0, 0 }
};
static driver_t uart_mbus_driver = {
uart_driver_name,
uart_mbus_methods,
sizeof(struct uart_softc),
};
static int
uart_mbus_probe(device_t dev)
{
struct uart_softc *sc;
int status;
sc = device_get_softc(dev);
sc->sc_class = &uart_ns8250_class;
status = uart_bus_probe(dev, 2, get_tclk(), 0, 0);
return(status);
}
DRIVER_MODULE(uart, mbus, uart_mbus_driver, uart_devclass, 0, 0);

View file

@ -0,0 +1,90 @@
/*-
* Copyright (C) 2007 MARVELL INTERNATIONAL LTD.
* All rights reserved.
*
* Developed by Semihalf.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of MARVELL nor the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "opt_uart.h"
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/cons.h>
#include <machine/bus.h>
#include <dev/uart/uart.h>
#include <dev/uart/uart_cpu.h>
#include <arm/mv/mvreg.h>
#include <arm/mv/mvvar.h>
bus_space_tag_t uart_bus_space_io;
bus_space_tag_t uart_bus_space_mem;
int
uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2)
{
return ((b1->bsh == b2->bsh && b1->bst == b2->bst) ? 1 : 0);
}
int
uart_cpu_getdev(int devtype, struct uart_devinfo *di)
{
struct uart_class *class = &uart_ns8250_class;
/*
* If env specification for UART exists it takes precedence:
* hw.uart.console="mm:0xf1012000" or similar
*/
if (uart_getenv(devtype, di, class) == 0)
return (0);
/*
* Fall back to default UART0 console settings
*/
di->ops = uart_getops(class);
di->bas.chan = 0;
di->bas.bst = obio_tag;
if (bus_space_map(di->bas.bst, MV_UART0_BASE, MV_UART_SIZE,
0, &di->bas.bsh) != 0)
return (ENXIO);
di->baudrate = 115200;
di->bas.regshft = 2;
di->bas.rclk = get_tclk();
di->databits = 8;
di->stopbits = 1;
di->parity = UART_PARITY_NONE;
uart_bus_space_mem = obio_tag;
uart_bus_space_io = NULL;
return (0);
}