Commit d978780b authored by Wolfgang Denk's avatar Wolfgang Denk
Browse files

Merge branch 'master' of git://git.denx.de/u-boot-microblaze

* 'master' of git://git.denx.de/u-boot-microblaze

:
  microblaze: Wire up SPI driver
  spi: microblaze: Adds driver for Xilinx SPI controller
  microblaze: intc: Clear interrupt code
  microblaze: Call serial multi initialization
  microblaze: Move __udelay implementation
  microblaze: Remove extern from board.c
  microblaze: Wire up dts configuration
  fdt: Add board specific dts inclusion
  microblaze: Move individual board linker scripts to common script in cpu tree.
  microblaze: Add gpio.h
  microblaze: Add missing undefs for UBI and UBIFS
  microblaze: Expand and correct configuration comments
  microblaze: Enable ubi support
  microblaze: Avoid compile error on systems without cfi flash
  microblaze: Remove wrong define CONFIG_SYS_FLASH_PROTECTION

Conflicts:
	drivers/spi/Makefile
Signed-off-by: default avatarWolfgang Denk <wd@denx.de>
parents b54d1f26 bcec8f49
......@@ -29,3 +29,5 @@ CROSS_COMPILE ?= mb-
CONFIG_STANDALONE_LOAD_ADDR ?= 0x80F00000
PLATFORM_CPPFLAGS += -ffixed-r31 -D__microblaze__
LDSCRIPT ?= $(SRCTREE)/$(CPUDIR)/u-boot.lds
......@@ -26,6 +26,7 @@
#include <common.h>
#include <command.h>
#include <malloc.h>
#include <asm/microblaze_intc.h>
#include <asm/asm.h>
......@@ -48,20 +49,19 @@ int disable_interrupts (void)
return (msr & 0x2) != 0;
}
#ifdef CONFIG_SYS_INTC_0
static struct irq_action vecs[CONFIG_SYS_INTC_0_NUM];
static struct irq_action *vecs;
static u32 irq_no;
/* mapping structure to interrupt controller */
microblaze_intc_t *intc = (microblaze_intc_t *) (CONFIG_SYS_INTC_0_ADDR);
microblaze_intc_t *intc;
/* default handler */
void def_hdlr (void)
static void def_hdlr(void)
{
puts ("def_hdlr\n");
}
void enable_one_interrupt (int irq)
static void enable_one_interrupt(int irq)
{
int mask;
int offset = 1;
......@@ -76,7 +76,7 @@ void enable_one_interrupt (int irq)
#endif
}
void disable_one_interrupt (int irq)
static void disable_one_interrupt(int irq)
{
int mask;
int offset = 1;
......@@ -96,7 +96,7 @@ void install_interrupt_handler (int irq, interrupt_handler_t * hdlr, void *arg)
{
struct irq_action *act;
/* irq out of range */
if ((irq < 0) || (irq > CONFIG_SYS_INTC_0_NUM)) {
if ((irq < 0) || (irq > irq_no)) {
puts ("IRQ out of range\n");
return;
}
......@@ -114,7 +114,7 @@ void install_interrupt_handler (int irq, interrupt_handler_t * hdlr, void *arg)
}
/* initialization interrupt controller - hardware */
void intc_init (void)
static void intc_init(void)
{
intc->mer = 0;
intc->ier = 0;
......@@ -127,18 +127,33 @@ void intc_init (void)
#endif
}
int interrupts_init (void)
int interrupts_init(void)
{
int i;
/* initialize irq list */
for (i = 0; i < CONFIG_SYS_INTC_0_NUM; i++) {
vecs[i].handler = (interrupt_handler_t *) def_hdlr;
vecs[i].arg = (void *)i;
vecs[i].count = 0;
#if defined(CONFIG_SYS_INTC_0_ADDR) && defined(CONFIG_SYS_INTC_0_NUM)
intc = (microblaze_intc_t *) (CONFIG_SYS_INTC_0_ADDR);
irq_no = CONFIG_SYS_INTC_0_NUM;
#endif
if (irq_no) {
vecs = calloc(1, sizeof(struct irq_action) * irq_no);
if (vecs == NULL) {
puts("Interrupt vector allocation failed\n");
return -1;
}
/* initialize irq list */
for (i = 0; i < irq_no; i++) {
vecs[i].handler = (interrupt_handler_t *) def_hdlr;
vecs[i].arg = (void *)i;
vecs[i].count = 0;
}
/* initialize intc controller */
intc_init();
enable_interrupts();
} else {
puts("Undefined interrupt controller\n");
}
/* initialize intc controller */
intc_init ();
enable_interrupts ();
return 0;
}
......@@ -172,33 +187,30 @@ void interrupt_handler (void)
printf ("Interrupt handler on %x line, r14 %x\n", irqs, value);
#endif
}
#endif
#if defined(CONFIG_CMD_IRQ)
#ifdef CONFIG_SYS_INTC_0
int do_irqinfo (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, const char *argv[])
{
int i;
struct irq_action *act = vecs;
puts ("\nInterrupt-Information:\n\n"
"Nr Routine Arg Count\n"
"-----------------------------\n");
for (i = 0; i < CONFIG_SYS_INTC_0_NUM; i++) {
if (act->handler != (interrupt_handler_t*) def_hdlr) {
printf ("%02d %08x %08x %d\n", i,
(int)act->handler, (int)act->arg, act->count);
if (irq_no) {
puts("\nInterrupt-Information:\n\n"
"Nr Routine Arg Count\n"
"-----------------------------\n");
for (i = 0; i < irq_no; i++) {
if (act->handler != (interrupt_handler_t *) def_hdlr) {
printf("%02d %08x %08x %d\n", i,
(int)act->handler, (int)act->arg,
act->count);
}
act++;
}
act++;
puts("\n");
} else {
puts("Undefined interrupt controller\n");
}
puts ("\n");
return (0);
}
#else
int do_irqinfo (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
{
puts ("Undefined interrupt controller\n");
return 0;
}
#endif
#endif
......@@ -108,7 +108,6 @@ _start:
sh r6, r0, r8
#endif
#ifdef CONFIG_SYS_INTC_0
/* interrupt_handler */
swi r2, r0, 0x10 /* interrupt - imm opcode */
swi r3, r0, 0x14 /* interrupt - brai opcode */
......@@ -120,7 +119,6 @@ _start:
sh r7, r0, r8
rsubi r8, r10, 0x16
sh r6, r0, r8
#endif
/* hardware exception */
swi r2, r0, 0x20 /* hardware exception - imm opcode */
......
......@@ -40,7 +40,25 @@ ulong get_timer (ulong base)
}
#endif
#ifdef CONFIG_SYS_INTC_0
#ifdef CONFIG_SYS_TIMER_0
void __udelay(unsigned long usec)
{
int i;
i = get_timer(0);
while ((get_timer(0) - i) < (usec / 1000))
;
}
#else
void __udelay(unsigned long usec)
{
unsigned int i;
for (i = 0; i < (usec * CONFIG_XILINX_CLOCK_FREQ / 10000000); i++)
;
}
#endif
#ifdef CONFIG_SYS_TIMER_0
microblaze_timer_t *tmr = (microblaze_timer_t *) (CONFIG_SYS_TIMER_0_ADDR);
......@@ -61,7 +79,6 @@ int timer_init (void)
return 0;
}
#endif
#endif
/*
* This function is derived from PowerPC code (read timebase as long long).
......
#ifndef _ASM_MICROBLAZE_GPIO_H_
#define _ASM_MICROBLAZE_GPIO_H_
#include <asm/io.h>
static inline int gpio_request(unsigned gpio, const char *label)
{
return 0;
}
static inline int gpio_free(unsigned gpio)
{
return 0;
}
static inline int gpio_direction_input(unsigned gpio)
{
return 0;
}
static inline int gpio_direction_output(unsigned gpio, int value)
{
return 0;
}
static inline int gpio_get_value(unsigned gpio)
{
return 0;
}
static inline int gpio_set_value(unsigned gpio, int value)
{
return 0;
}
static inline int gpio_is_valid(int number)
{
return 0;
}
#endif
......@@ -41,3 +41,6 @@ struct irq_action {
void install_interrupt_handler (int irq, interrupt_handler_t * hdlr,
void *arg);
int interrupts_init(void);
......@@ -29,7 +29,6 @@ SOBJS-y +=
COBJS-y += board.o
COBJS-y += bootm.o
COBJS-y += time.o
SRCS := $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c)
OBJS := $(addprefix $(obj),$(SOBJS-y) $(COBJS-y))
......
......@@ -30,21 +30,16 @@
#include <version.h>
#include <watchdog.h>
#include <stdio_dev.h>
#include <serial.h>
#include <net.h>
#include <asm/processor.h>
#include <asm/microblaze_intc.h>
DECLARE_GLOBAL_DATA_PTR;
#ifdef CONFIG_SYS_GPIO_0
extern int gpio_init (void);
#endif
#ifdef CONFIG_SYS_INTC_0
extern int interrupts_init (void);
#endif
#if defined(CONFIG_CMD_NET)
extern int eth_init (bd_t * bis);
#endif
#ifdef CONFIG_SYS_TIMER_0
extern int timer_init (void);
#endif
......@@ -73,9 +68,7 @@ init_fnc_t *init_sequence[] = {
#ifdef CONFIG_SYS_GPIO_0
gpio_init,
#endif
#ifdef CONFIG_SYS_INTC_0
interrupts_init,
#endif
#ifdef CONFIG_SYS_TIMER_0
timer_init,
#endif
......@@ -117,6 +110,10 @@ void board_init (void)
*/
mem_malloc_init (CONFIG_SYS_MALLOC_BASE, CONFIG_SYS_MALLOC_LEN);
#ifdef CONFIG_SERIAL_MULTI
serial_initialize();
#endif
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
WATCHDOG_RESET ();
if ((*init_fnc_ptr) () != 0) {
......
/*
* (C) Copyright 2007 Michal Simek
* (C) Copyright 2004 Atmark Techno, Inc.
*
* Michal SIMEK <monstr@monstr.eu>
* Yasushi SHOJI <yashi@atmark-techno.com>
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <common.h>
#ifdef CONFIG_SYS_TIMER_0
void __udelay (unsigned long usec)
{
int i;
i = get_timer (0);
while ((get_timer (0) - i) < (usec / 1000)) ;
}
#else
void __udelay (unsigned long usec)
{
unsigned int i;
for (i = 0; i < (usec * CONFIG_XILINX_CLOCK_FREQ / 10000000); i++);
}
#endif
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <1>;
aliases {
} ;
} ;
......@@ -44,6 +44,8 @@ COBJS-$(CONFIG_SOFT_SPI) += soft_spi.o
COBJS-$(CONFIG_SH_SPI) += sh_spi.o
COBJS-$(CONFIG_FSL_ESPI) += fsl_espi.o
COBJS-$(CONFIG_TEGRA_SPI) += tegra_spi.o
COBJS-$(CONFIG_TEGRA2_SPI) += tegra2_spi.o
COBJS-$(CONFIG_XILINX_SPI) += xilinx_spi.o
COBJS := $(COBJS-y)
SRCS := $(COBJS:.o=.c)
......
/*
* Xilinx SPI driver
*
* supports 8 bit SPI transfers only, with or w/o FIFO
*
* based on bfin_spi.c, by way of altera_spi.c
* Copyright (c) 2005-2008 Analog Devices Inc.
* Copyright (c) 2010 Thomas Chou <thomas@wytron.com.tw>
* Copyright (c) 2010 Graeme Smecher <graeme.smecher@mail.mcgill.ca>
* Copyright (c) 2012 Stephan Linz <linz@li-pro.net>
*
* Licensed under the GPL-2 or later.
*
* [0]: http://www.xilinx.com/support/documentation
*
* [S]: [0]/ip_documentation/xps_spi.pdf
* [0]/ip_documentation/axi_spi_ds742.pdf
*/
#include <config.h>
#include <common.h>
#include <malloc.h>
#include <spi.h>
#include "xilinx_spi.h"
#ifndef CONFIG_SYS_XILINX_SPI_LIST
#define CONFIG_SYS_XILINX_SPI_LIST { CONFIG_SYS_SPI_BASE }
#endif
#ifndef CONFIG_XILINX_SPI_IDLE_VAL
#define CONFIG_XILINX_SPI_IDLE_VAL 0xff
#endif
#define XILSPI_SPICR_DFLT_ON (SPICR_MANUAL_SS | \
SPICR_MASTER_MODE | \
SPICR_SPE)
#define XILSPI_SPICR_DFLT_OFF (SPICR_MASTER_INHIBIT | \
SPICR_MANUAL_SS)
#define XILSPI_MAX_XFER_BITS 8
static unsigned long xilinx_spi_base_list[] = CONFIG_SYS_XILINX_SPI_LIST;
__attribute__((weak))
int spi_cs_is_valid(unsigned int bus, unsigned int cs)
{
return bus < ARRAY_SIZE(xilinx_spi_base_list) && cs < 32;
}
__attribute__((weak))
void spi_cs_activate(struct spi_slave *slave)
{
struct xilinx_spi_slave *xilspi = to_xilinx_spi_slave(slave);
writel(SPISSR_ACT(slave->cs), &xilspi->regs->spissr);
}
__attribute__((weak))
void spi_cs_deactivate(struct spi_slave *slave)
{
struct xilinx_spi_slave *xilspi = to_xilinx_spi_slave(slave);
writel(SPISSR_OFF, &xilspi->regs->spissr);
}
void spi_init(void)
{
/* do nothing */
}
void spi_set_speed(struct spi_slave *slave, uint hz)
{
/* xilinx spi core does not support programmable speed */
}
struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
unsigned int max_hz, unsigned int mode)
{
struct xilinx_spi_slave *xilspi;
struct xilinx_spi_reg *regs;
if (!spi_cs_is_valid(bus, cs)) {
printf("XILSPI error: %s: unsupported bus %d / cs %d\n",
__func__, bus, cs);
return NULL;
}
xilspi = malloc(sizeof(*xilspi));
if (!xilspi) {
printf("XILSPI error: %s: malloc of SPI structure failed\n",
__func__);
return NULL;
}
xilspi->slave.bus = bus;
xilspi->slave.cs = cs;
xilspi->regs = (struct xilinx_spi_reg *)xilinx_spi_base_list[bus];
xilspi->freq = max_hz;
xilspi->mode = mode;
debug("%s: bus:%i cs:%i base:%p mode:%x max_hz:%d\n", __func__,
bus, cs, xilspi->regs, xilspi->mode, xilspi->freq);
return &xilspi->slave;
}
void spi_free_slave(struct spi_slave *slave)
{
struct xilinx_spi_slave *xilspi = to_xilinx_spi_slave(slave);
free(xilspi);
}
int spi_claim_bus(struct spi_slave *slave)
{
struct xilinx_spi_slave *xilspi = to_xilinx_spi_slave(slave);
u32 spicr;
debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
writel(SPISSR_OFF, &xilspi->regs->spissr);
spicr = XILSPI_SPICR_DFLT_ON;
if (xilspi->mode & SPI_LSB_FIRST)
spicr |= SPICR_LSB_FIRST;
if (xilspi->mode & SPI_CPHA)
spicr |= SPICR_CPHA;
if (xilspi->mode & SPI_CPOL)
spicr |= SPICR_CPOL;
if (xilspi->mode & SPI_LOOP)
spicr |= SPICR_LOOP;
writel(spicr, &xilspi->regs->spicr);
return 0;
}
void spi_release_bus(struct spi_slave *slave)
{
struct xilinx_spi_slave *xilspi = to_xilinx_spi_slave(slave);
debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
writel(SPISSR_OFF, &xilspi->regs->spissr);
writel(XILSPI_SPICR_DFLT_OFF, &xilspi->regs->spicr);
}
int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
void *din, unsigned long flags)
{
struct xilinx_spi_slave *xilspi = to_xilinx_spi_slave(slave);
/* assume spi core configured to do 8 bit transfers */
unsigned int bytes = bitlen / XILSPI_MAX_XFER_BITS;
const unsigned char *txp = dout;
unsigned char *rxp = din;
unsigned rxecount = 17; /* max. 16 elements in FIFO, leftover 1 */
debug("%s: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n", __func__,
slave->bus, slave->cs, bitlen, bytes, flags);
if (bitlen == 0)
goto done;
if (bitlen % XILSPI_MAX_XFER_BITS) {
printf("XILSPI warning: %s: Not a multiple of %d bits\n",
__func__, XILSPI_MAX_XFER_BITS);
flags |= SPI_XFER_END;
goto done;
}
/* empty read buffer */
while (rxecount && !(readl(&xilspi->regs->spisr) & SPISR_RX_EMPTY)) {
readl(&xilspi->regs->spidrr);
rxecount--;
}
if (!rxecount) {
printf("XILSPI error: %s: Rx buffer not empty\n", __func__);
return -1;
}
if (flags & SPI_XFER_BEGIN)
spi_cs_activate(slave);
while (bytes--) {
unsigned timeout = /* at least 1usec or greater, leftover 1 */
xilspi->freq > XILSPI_MAX_XFER_BITS * 1000000 ? 2 :
(XILSPI_MAX_XFER_BITS * 1000000 / xilspi->freq) + 1;
/* get Tx element from data out buffer and count up */
unsigned char d = txp ? *txp++ : CONFIG_XILINX_SPI_IDLE_VAL;
debug("%s: tx:%x ", __func__, d);
/* write out and wait for processing (receive data) */
writel(d & SPIDTR_8BIT_MASK, &xilspi->regs->spidtr);
while (timeout && readl(&xilspi->regs->spisr)
& SPISR_RX_EMPTY) {
timeout--;
udelay(1);
}
if (!timeout) {
printf("XILSPI error: %s: Xfer timeout\n", __func__);
return -1;
}
/* read Rx element and push into data in buffer */
d = readl(&xilspi->regs->spidrr) & SPIDRR_8BIT_MASK;
if (rxp)
*rxp++ = d;
debug("rx:%x\n", d);
}
done:
if (flags & SPI_XFER_END)
spi_cs_deactivate(slave);
return 0;
}
/*
* Xilinx SPI driver
*
* XPS/AXI bus interface
*
* based on bfin_spi.c, by way of altera_spi.c
* Copyright (c) 2005-2008 Analog Devices Inc.
* Copyright (c) 2010 Thomas Chou <thomas@wytron.com.tw>
* Copyright (c) 2010 Graeme Smecher <graeme.smecher@mail.mcgill.ca>
* Copyright (c) 2012 Stephan Linz <linz@li-pro.net>
*
* Licensed under the GPL-2 or later.
*
* [0]: http://www.xilinx.com/support/documentation
*
* [S]: [0]/ip_documentation/xps_spi.pdf
* [0]/ip_documentation/axi_spi_ds742.pdf
*/
#ifndef _XILINX_SPI_
#define _XILINX_SPI_
#include <asm/types.h>
#include <asm/io.h>
/*
* Xilinx SPI Register Definition
*