avr32: Hammerhead board support

The Hammerhead platform is built around a AVR32 32-bit microcontroller
from Atmel.  It offers versatile peripherals, such as ethernet, usb
device, usb host etc.

The board also incooperates a power supply and is a Power over Ethernet
(PoE) Powered Device (PD).

Additonally, a Cyclone III FPGA from Altera is integrated on the board.
The FPGA is mapped into the 32-bit AVR memory bus. The FPGA offers two
DDR2 SDRAM interfaces, which will cover even the most exceptional need
of memory bandwidth. Together with the onboard video decoder the board
is ready for video processing.

This patch does include the basic support for the fpga device driver,
but not the device driver itself.

Signed-off-by: Alex Raimondi <mailinglist@miromico.ch>
Signed-off-by: Haavard Skinnemoen <haavard.skinnemoen@atmel.com>
This commit is contained in:
Alex Raimondi 2008-12-09 16:17:13 +01:00 committed by Haavard Skinnemoen
parent bc08969fe6
commit dd5e1339e5
10 changed files with 2155 additions and 2 deletions

View File

@ -122,6 +122,24 @@ config BOARD_ATNGW100
bool "ATNGW100 Network Gateway"
select CPU_AT32AP7000
config BOARD_HAMMERHEAD
bool "Hammerhead board"
select CPU_AT32AP7000
select USB_ARCH_HAS_HCD
help
The Hammerhead platform is built around a AVR32 32-bit microcontroller from Atmel.
It offers versatile peripherals, such as ethernet, usb device, usb host etc.
The board also incooperates a power supply and is a Power over Ethernet (PoE) Powered
Device (PD).
Additonally, a Cyclone III FPGA from Altera is integrated on the board. The FPGA is
mapped into the 32-bit AVR memory bus. The FPGA offers two DDR2 SDRAM interfaces, which
will cover even the most exceptional need of memory bandwidth. Together with the onboard
video decoder the board is ready for video processing.
For more information see: http://www.miromico.com/hammerhead
config BOARD_FAVR_32
bool "Favr-32 LCD-board"
select CPU_AT32AP7000
@ -133,6 +151,7 @@ endchoice
source "arch/avr32/boards/atstk1000/Kconfig"
source "arch/avr32/boards/atngw100/Kconfig"
source "arch/avr32/boards/hammerhead/Kconfig"
source "arch/avr32/boards/favr-32/Kconfig"
choice

View File

@ -33,6 +33,7 @@ head-y += arch/avr32/kernel/head.o
core-y += $(machdirs)
core-$(CONFIG_BOARD_ATSTK1000) += arch/avr32/boards/atstk1000/
core-$(CONFIG_BOARD_ATNGW100) += arch/avr32/boards/atngw100/
core-$(CONFIG_BOARD_HAMMERHEAD) += arch/avr32/boards/hammerhead/
core-$(CONFIG_BOARD_FAVR_32) += arch/avr32/boards/favr-32/
core-$(CONFIG_BOARD_MIMC200) += arch/avr32/boards/mimc200/
core-$(CONFIG_LOADER_U_BOOT) += arch/avr32/boot/u-boot/

View File

@ -0,0 +1,43 @@
# Hammerhead customization
if BOARD_HAMMERHEAD
config BOARD_HAMMERHEAD_USB
bool "Philips ISP116x-hcd USB support"
help
This enables USB support for Hammerheads internal ISP116x
controller from Philips.
Choose 'Y' here if you want to have your board USB driven.
config BOARD_HAMMERHEAD_LCD
bool "Atmel AT91/AT32 LCD support"
help
This enables LCD support for the Hammerhead board. You may
also add support for framebuffer devices (AT91/AT32 LCD Controller)
and framebuffer console support to get the most out of your LCD.
Choose 'Y' here if you have ordered a Corona daugther board and
want to have support for your Hantronix HDA-351T-LV LCD.
config BOARD_HAMMERHEAD_SND
bool "Atmel AC97 Sound support"
help
This enables Sound support for the Hammerhead board. You may
also go trough the ALSA settings to get it working.
Choose 'Y' here if you have ordered a Corona daugther board and
want to make your board funky.
config BOARD_HAMMERHEAD_FPGA
bool "Hammerhead FPGA Support"
default y
help
This adds support for the Cyclone III FPGA from Altera
found on Miromico's Hammerhead board.
Choose 'Y' here if you want to have FPGA support enabled.
You will have to choose the "Hammerhead FPGA Device Support" in
Device Drivers->Misc to be able to use FPGA functionality.
endif # BOARD_ATNGW100

View File

@ -0,0 +1 @@
obj-y += setup.o flash.o

View File

@ -0,0 +1,377 @@
/*
* Hammerhead board-specific flash initialization
*
* Copyright (C) 2008 Miromico AG
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/physmap.h>
#include <linux/usb/isp116x.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <mach/portmux.h>
#include <mach/at32ap700x.h>
#include <mach/smc.h>
#include "../../mach-at32ap/clock.h"
#include "flash.h"
#define HAMMERHEAD_USB_PERIPH_GCLK0 0x40000000
#define HAMMERHEAD_USB_PERIPH_CS2 0x02000000
#define HAMMERHEAD_USB_PERIPH_EXTINT0 0x02000000
#define HAMMERHEAD_FPGA_PERIPH_MOSI 0x00000002
#define HAMMERHEAD_FPGA_PERIPH_SCK 0x00000020
#define HAMMERHEAD_FPGA_PERIPH_EXTINT3 0x10000000
static struct smc_timing flash_timing __initdata = {
.ncs_read_setup = 0,
.nrd_setup = 40,
.ncs_write_setup = 0,
.nwe_setup = 10,
.ncs_read_pulse = 80,
.nrd_pulse = 40,
.ncs_write_pulse = 65,
.nwe_pulse = 55,
.read_cycle = 120,
.write_cycle = 120,
};
static struct smc_config flash_config __initdata = {
.bus_width = 2,
.nrd_controlled = 1,
.nwe_controlled = 1,
.byte_write = 1,
};
static struct mtd_partition flash_parts[] = {
{
.name = "u-boot",
.offset = 0x00000000,
.size = 0x00020000, /* 128 KiB */
.mask_flags = MTD_WRITEABLE,
},
{
.name = "root",
.offset = 0x00020000,
.size = 0x007d0000,
},
{
.name = "env",
.offset = 0x007f0000,
.size = 0x00010000,
.mask_flags = MTD_WRITEABLE,
},
};
static struct physmap_flash_data flash_data = {
.width = 2,
.nr_parts = ARRAY_SIZE(flash_parts),
.parts = flash_parts,
};
static struct resource flash_resource = {
.start = 0x00000000,
.end = 0x007fffff,
.flags = IORESOURCE_MEM,
};
static struct platform_device flash_device = {
.name = "physmap-flash",
.id = 0,
.resource = &flash_resource,
.num_resources = 1,
.dev = { .platform_data = &flash_data, },
};
#ifdef CONFIG_BOARD_HAMMERHEAD_USB
static struct smc_timing isp1160_timing __initdata = {
.ncs_read_setup = 75,
.nrd_setup = 75,
.ncs_write_setup = 75,
.nwe_setup = 75,
/* We use conservative timing settings, as the minimal settings aren't
stable. There may be room for tweaking. */
.ncs_read_pulse = 75, /* min. 33ns */
.nrd_pulse = 75, /* min. 33ns */
.ncs_write_pulse = 75, /* min. 26ns */
.nwe_pulse = 75, /* min. 26ns */
.read_cycle = 225, /* min. 143ns */
.write_cycle = 225, /* min. 136ns */
};
static struct smc_config isp1160_config __initdata = {
.bus_width = 2,
.nrd_controlled = 1,
.nwe_controlled = 1,
.byte_write = 0,
};
/*
* The platform delay function is only used to enforce the strange
* read to write delay. This can not be configured in the SMC. All other
* timings are controlled by the SMC (see timings obove)
* So in isp116x-hcd.c we should comment out USE_PLATFORM_DELAY
*/
void isp116x_delay(struct device *dev, int delay)
{
if (delay > 150)
ndelay(delay - 150);
}
static struct isp116x_platform_data isp1160_data = {
.sel15Kres = 1, /* use internal downstream resistors */
.oc_enable = 0, /* external overcurrent detection */
.int_edge_triggered = 0, /* interrupt is level triggered */
.int_act_high = 0, /* interrupt is active low */
.delay = isp116x_delay, /* platform delay function */
};
static struct resource isp1160_resource[] = {
{
.start = 0x08000000,
.end = 0x08000001,
.flags = IORESOURCE_MEM,
},
{
.start = 0x08000002,
.end = 0x08000003,
.flags = IORESOURCE_MEM,
},
{
.start = 64,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device isp1160_device = {
.name = "isp116x-hcd",
.id = 0,
.resource = isp1160_resource,
.num_resources = 3,
.dev = {
.platform_data = &isp1160_data,
},
};
#endif
#ifdef CONFIG_BOARD_HAMMERHEAD_USB
static int __init hammerhead_usbh_init(void)
{
struct clk *gclk;
struct clk *osc;
int ret;
/* setup smc for usbh */
smc_set_timing(&isp1160_config, &isp1160_timing);
ret = smc_set_configuration(2, &isp1160_config);
if (ret < 0) {
printk(KERN_ERR
"hammerhead: failed to set ISP1160 USBH timing\n");
return ret;
}
/* setup gclk0 to run from osc1 */
gclk = clk_get(NULL, "gclk0");
if (IS_ERR(gclk))
goto err_gclk;
osc = clk_get(NULL, "osc1");
if (IS_ERR(osc))
goto err_osc;
if (clk_set_parent(gclk, osc)) {
pr_debug("hammerhead: failed to set osc1 for USBH clock\n");
goto err_set_clk;
}
/* set clock to 6MHz */
clk_set_rate(gclk, 6000000);
/* and enable */
clk_enable(gclk);
/* select GCLK0 peripheral function */
at32_select_periph(GPIO_PIOA_BASE, HAMMERHEAD_USB_PERIPH_GCLK0,
GPIO_PERIPH_A, 0);
/* enable CS2 peripheral function */
at32_select_periph(GPIO_PIOE_BASE, HAMMERHEAD_USB_PERIPH_CS2,
GPIO_PERIPH_A, 0);
/* H_WAKEUP must be driven low */
at32_select_gpio(GPIO_PIN_PA(8), AT32_GPIOF_OUTPUT);
/* Select EXTINT0 for PB25 */
at32_select_periph(GPIO_PIOB_BASE, HAMMERHEAD_USB_PERIPH_EXTINT0,
GPIO_PERIPH_A, 0);
/* register usbh device driver */
platform_device_register(&isp1160_device);
err_set_clk:
clk_put(osc);
err_osc:
clk_put(gclk);
err_gclk:
return ret;
}
#endif
#ifdef CONFIG_BOARD_HAMMERHEAD_FPGA
static struct smc_timing fpga_timing __initdata = {
.ncs_read_setup = 16,
.nrd_setup = 32,
.ncs_read_pulse = 48,
.nrd_pulse = 32,
.read_cycle = 64,
.ncs_write_setup = 16,
.nwe_setup = 16,
.ncs_write_pulse = 32,
.nwe_pulse = 32,
.write_cycle = 64,
};
static struct smc_config fpga_config __initdata = {
.bus_width = 4,
.nrd_controlled = 1,
.nwe_controlled = 1,
.byte_write = 0,
};
static struct resource hh_fpga0_resource[] = {
{
.start = 0xffe00400,
.end = 0xffe00400 + 0x3ff,
.flags = IORESOURCE_MEM,
},
{
.start = 4,
.end = 4,
.flags = IORESOURCE_IRQ,
},
{
.start = 0x0c000000,
.end = 0x0c000100,
.flags = IORESOURCE_MEM,
},
{
.start = 67,
.end = 67,
.flags = IORESOURCE_IRQ,
},
};
static u64 hh_fpga0_dma_mask = DMA_32BIT_MASK;
static struct platform_device hh_fpga0_device = {
.name = "hh_fpga",
.id = 0,
.dev = {
.dma_mask = &hh_fpga0_dma_mask,
.coherent_dma_mask = DMA_32BIT_MASK,
},
.resource = hh_fpga0_resource,
.num_resources = ARRAY_SIZE(hh_fpga0_resource),
};
static struct clk hh_fpga0_spi_clk = {
.name = "spi_clk",
.dev = &hh_fpga0_device.dev,
.mode = pba_clk_mode,
.get_rate = pba_clk_get_rate,
.index = 1,
};
struct platform_device *__init at32_add_device_hh_fpga(void)
{
/* Select peripheral functionallity for SPI SCK and MOSI */
at32_select_periph(GPIO_PIOB_BASE, HAMMERHEAD_FPGA_PERIPH_SCK,
GPIO_PERIPH_B, 0);
at32_select_periph(GPIO_PIOB_BASE, HAMMERHEAD_FPGA_PERIPH_MOSI,
GPIO_PERIPH_B, 0);
/* reserve all other needed gpio
* We have on board pull ups, so there is no need
* to enable gpio pull ups */
/* INIT_DONE (input) */
at32_select_gpio(GPIO_PIN_PB(0), 0);
/* nSTATUS (input) */
at32_select_gpio(GPIO_PIN_PB(2), 0);
/* nCONFIG (output, low) */
at32_select_gpio(GPIO_PIN_PB(3), AT32_GPIOF_OUTPUT);
/* CONF_DONE (input) */
at32_select_gpio(GPIO_PIN_PB(4), 0);
/* Select EXTINT3 for PB28 (Interrupt from FPGA) */
at32_select_periph(GPIO_PIOB_BASE, HAMMERHEAD_FPGA_PERIPH_EXTINT3,
GPIO_PERIPH_A, 0);
/* Get our parent clock */
hh_fpga0_spi_clk.parent = clk_get(NULL, "pba");
clk_put(hh_fpga0_spi_clk.parent);
/* Register clock in at32 clock tree */
at32_clk_register(&hh_fpga0_spi_clk);
platform_device_register(&hh_fpga0_device);
return &hh_fpga0_device;
}
#endif
/* This needs to be called after the SMC has been initialized */
static int __init hammerhead_flash_init(void)
{
int ret;
smc_set_timing(&flash_config, &flash_timing);
ret = smc_set_configuration(0, &flash_config);
if (ret < 0) {
printk(KERN_ERR "hammerhead: failed to set NOR flash timing\n");
return ret;
}
platform_device_register(&flash_device);
#ifdef CONFIG_BOARD_HAMMERHEAD_USB
hammerhead_usbh_init();
#endif
#ifdef CONFIG_BOARD_HAMMERHEAD_FPGA
/* Setup SMC for FPGA interface */
smc_set_timing(&fpga_config, &fpga_timing);
ret = smc_set_configuration(3, &fpga_config);
#endif
if (ret < 0) {
printk(KERN_ERR "hammerhead: failed to set FPGA timing\n");
return ret;
}
return 0;
}
device_initcall(hammerhead_flash_init);

View File

@ -0,0 +1,6 @@
#ifndef __BOARDS_HAMMERHEAD_FLASH_H
#define __BOARDS_HAMMERHEAD_FLASH_H
struct platform_device *at32_add_device_hh_fpga(void);
#endif /* __BOARDS_HAMMERHEAD_FLASH_H */

View File

@ -0,0 +1,236 @@
/*
* Board-specific setup code for the Miromico Hammerhead board
*
* Copyright (C) 2008 Miromico AG
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/clk.h>
#include <linux/fb.h>
#include <linux/etherdevice.h>
#include <linux/i2c.h>
#include <linux/i2c-gpio.h>
#include <linux/init.h>
#include <linux/linkage.h>
#include <linux/platform_device.h>
#include <linux/types.h>
#include <linux/spi/spi.h>
#include <video/atmel_lcdc.h>
#include <linux/io.h>
#include <asm/setup.h>
#include <mach/at32ap700x.h>
#include <mach/board.h>
#include <mach/init.h>
#include <mach/portmux.h>
#include "../../mach-at32ap/clock.h"
#include "flash.h"
/* Oscillator frequencies. These are board-specific */
unsigned long at32_board_osc_rates[3] = {
[0] = 32768, /* 32.768 kHz on RTC osc */
[1] = 25000000, /* 25MHz on osc0 */
[2] = 12000000, /* 12 MHz on osc1 */
};
/* Initialized by bootloader-specific startup code. */
struct tag *bootloader_tags __initdata;
#ifdef CONFIG_BOARD_HAMMERHEAD_LCD
static struct fb_videomode __initdata hda350tlv_modes[] = {
{
.name = "320x240 @ 75",
.refresh = 75,
.xres = 320,
.yres = 240,
.pixclock = KHZ2PICOS(6891),
.left_margin = 48,
.right_margin = 18,
.upper_margin = 18,
.lower_margin = 4,
.hsync_len = 20,
.vsync_len = 2,
.sync = 0,
.vmode = FB_VMODE_NONINTERLACED,
},
};
static struct fb_monspecs __initdata hammerhead_hda350t_monspecs = {
.manufacturer = "HAN",
.monitor = "HDA350T-LV",
.modedb = hda350tlv_modes,
.modedb_len = ARRAY_SIZE(hda350tlv_modes),
.hfmin = 14900,
.hfmax = 22350,
.vfmin = 60,
.vfmax = 90,
.dclkmax = 10000000,
};
struct atmel_lcdfb_info __initdata hammerhead_lcdc_data = {
.default_bpp = 24,
.default_dmacon = ATMEL_LCDC_DMAEN | ATMEL_LCDC_DMA2DEN,
.default_lcdcon2 = (ATMEL_LCDC_DISTYPE_TFT
| ATMEL_LCDC_INVCLK
| ATMEL_LCDC_CLKMOD_ALWAYSACTIVE
| ATMEL_LCDC_MEMOR_BIG),
.default_monspecs = &hammerhead_hda350t_monspecs,
.guard_time = 2,
};
#endif
struct eth_addr {
u8 addr[6];
};
static struct eth_addr __initdata hw_addr[1];
static struct eth_platform_data __initdata eth_data[1];
/*
* The next two functions should go away as the boot loader is
* supposed to initialize the macb address registers with a valid
* ethernet address. But we need to keep it around for a while until
* we can be reasonably sure the boot loader does this.
*
* The phy_id is ignored as the driver will probe for it.
*/
static int __init parse_tag_ethernet(struct tag *tag)
{
int i = tag->u.ethernet.mac_index;
if (i < ARRAY_SIZE(hw_addr))
memcpy(hw_addr[i].addr, tag->u.ethernet.hw_address,
sizeof(hw_addr[i].addr));
return 0;
}
__tagtable(ATAG_ETHERNET, parse_tag_ethernet);
static void __init set_hw_addr(struct platform_device *pdev)
{
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
const u8 *addr;
void __iomem *regs;
struct clk *pclk;
if (!res)
return;
if (pdev->id >= ARRAY_SIZE(hw_addr))
return;
addr = hw_addr[pdev->id].addr;
if (!is_valid_ether_addr(addr))
return;
/*
* Since this is board-specific code, we'll cheat and use the
* physical address directly as we happen to know that it's
* the same as the virtual address.
*/
regs = (void __iomem __force *)res->start;
pclk = clk_get(&pdev->dev, "pclk");
if (!pclk)
return;
clk_enable(pclk);
__raw_writel((addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) |
addr[0], regs + 0x98);
__raw_writel((addr[5] << 8) | addr[4], regs + 0x9c);
clk_disable(pclk);
clk_put(pclk);
}
void __init setup_board(void)
{
at32_map_usart(1, 0); /* USART 1: /dev/ttyS0, DB9 */
at32_setup_serial_console(0);
}
static struct i2c_gpio_platform_data i2c_gpio_data = {
.sda_pin = GPIO_PIN_PA(6),
.scl_pin = GPIO_PIN_PA(7),
.sda_is_open_drain = 1,
.scl_is_open_drain = 1,
.udelay = 2, /* close to 100 kHz */
};
static struct platform_device i2c_gpio_device = {
.name = "i2c-gpio",
.id = 0,
.dev = { .platform_data = &i2c_gpio_data, },
};
static struct i2c_board_info __initdata i2c_info[] = {};
#ifdef CONFIG_BOARD_HAMMERHEAD_SND
static struct ac97c_platform_data ac97c_data = {
.reset_pin = GPIO_PIN_PA(16),
};
#endif
static int __init hammerhead_init(void)
{
/*
* Hammerhead uses 32-bit SDRAM interface. Reserve the
* SDRAM-specific pins so that nobody messes with them.
*/
at32_reserve_pin(GPIO_PIOE_BASE, ATMEL_EBI_PE_DATA_ALL);
at32_add_device_usart(0);
/* Reserve PB29 (GCLK3). This pin is used as clock source
* for ETH PHY (25MHz). GCLK3 setup is done by U-Boot.
*/
at32_reserve_pin(GPIO_PIOB_BASE, (1<<29));
/*
* Hammerhead uses only one ethernet port, so we don't set
* address of second port
*/
set_hw_addr(at32_add_device_eth(0, &eth_data[0]));
#ifdef CONFIG_BOARD_HAMMERHEAD_FPGA
at32_add_device_hh_fpga();
#endif
at32_add_device_mci(0, NULL);
#ifdef CONFIG_BOARD_HAMMERHEAD_USB
at32_add_device_usba(0, NULL);
#endif
#ifdef CONFIG_BOARD_HAMMERHEAD_LCD
at32_add_device_lcdc(0, &hammerhead_lcdc_data, fbmem_start,
fbmem_size, ATMEL_LCDC_PRI_24BIT);
#endif
at32_select_gpio(i2c_gpio_data.sda_pin,
AT32_GPIOF_MULTIDRV | AT32_GPIOF_OUTPUT |
AT32_GPIOF_HIGH);
at32_select_gpio(i2c_gpio_data.scl_pin,
AT32_GPIOF_MULTIDRV | AT32_GPIOF_OUTPUT |
AT32_GPIOF_HIGH);
platform_device_register(&i2c_gpio_device);
i2c_register_board_info(0, i2c_info, ARRAY_SIZE(i2c_info));
#ifdef CONFIG_BOARD_HAMMERHEAD_SND
at32_add_device_ac97c(0, &ac97c_data);
#endif
/* Select the Touchscreen interrupt pin mode */
at32_select_periph(GPIO_PIOB_BASE, 0x08000000, GPIO_PERIPH_A, 0);
return 0;
}
postcore_initcall(hammerhead_init);

File diff suppressed because it is too large Load Diff

View File

@ -421,7 +421,7 @@ static unsigned long hsb_clk_get_rate(struct clk *clk)
return bus_clk_get_rate(clk, shift);
}
static void pba_clk_mode(struct clk *clk, int enabled)
void pba_clk_mode(struct clk *clk, int enabled)
{
unsigned long flags;
u32 mask;
@ -436,7 +436,7 @@ static void pba_clk_mode(struct clk *clk, int enabled)
spin_unlock_irqrestore(&pm_lock, flags);
}
static unsigned long pba_clk_get_rate(struct clk *clk)
unsigned long pba_clk_get_rate(struct clk *clk)
{
unsigned long cksel, shift = 0;

View File

@ -30,3 +30,6 @@ struct clk {
u16 users; /* Enabled if non-zero */
u16 index; /* Sibling index */
};
unsigned long pba_clk_get_rate(struct clk *clk);
void pba_clk_mode(struct clk *clk, int enabled);