[PATCH v2] ARM: CSR: Adding CSR SiRFprimaII board support
Barry Song
21cnbao at gmail.com
Thu Jun 30 13:39:54 EST 2011
Hi Arnd,
Thanks!
2011/6/30 Arnd Bergmann <arnd at arndb.de>:
> On Tuesday 28 June 2011, Barry Song wrote:
>> This patch adds the basic support for this SoC and EVB board based on device
>> tree. It is following the ZYNQ of Grant Likely in some degree.
>
> Hi Barry,
>
> There are a few more things I noticed this time around, and some comments
> about code that changed since v1.
>
>> the device hierarchy in SiRFprimaII is as below
>>
>> AXI(0-0x3FFFFFFF)
>> memory
>> AXI(0x40000000-0xC0000000)
>> CPUIF(sirf-iobus)
>> INTC
>> MEMC
>> LCD
>> VPP
>> GRAPHIC
>> MULTIMEDIA
>> GPS
>> UART
>> ...
>> hard-coded PCI bridge
>> SD/MMC
>> rtc-iobrg
>> RTC
>>
>
> Is this really just one bus with a huge address space, or rather some
> nested buses? I'd prefer to have the device tree representation as
> close as possible to the actual layout.
>
> This also includes using bus-local addresses for the 'reg' properties,
> rather than global addresses.
>
>> 1. clock: use dev_id instead of con_id
>> 2. Kconfig: delete ISA_DMA
>> 3. irq: implement int controller based on DT
>> move to GENERIC_IRQ_CHIP framework
>> 4. timer: implement timer based on DT
>> 5. entry-macro.S: use get_irqnr_preamble to load the base address only once
>> per IRQ exception.
>> 6. others:
>> use readl_relaxed instead of __raw_readl
>> adjust Kconfig order for PRIMA2
>> use clk_get_sys instead of clk_get for system level clock
>> use BUG_ON(IS_ERR(clk)) instead of BUG_ON(IS_ERR_OR_NULL(clk));
>> fix typo for CLOCK_TICK_RATE
>> ("sirf,xxx", "sirf,prima2-xxx") instead of ("sirf,xxx") in dts
>>
>
> Good progress!
>
>> new file mode 100644
>> index 0000000..1777e98
>> --- /dev/null
>> +++ b/arch/arm/boot/dts/prima2-cb.dts
>> @@ -0,0 +1,50 @@
>> +/dts-v1/;
>> +/ {
>> + model = "SIRF Prima2 EVB";
>> + compatible = "sirf,prima2-cb", "sirf,prima2";
>> + #address-cells = <1>;
>> + #size-cells = <1>;
>> + interrupt-parent = <&intc>;
>> +
>> + memory {
>> + reg = <0x00000000 0x20000000>;
>> + };
>> +
>> + chosen {
>> + bootargs = "mem=512M real_root=/dev/mmcblk0p2 console=ttyS1 earlyprintk";
>> + linux,stdout-path = &uart1;
>> + };
>> +
>> + amba {
>> + compatible = "simple-bus";
>> + #address-cells = <1>;
>> + #size-cells = <1>;
>> + ranges;
>> +
>> + intc: interrupt-controller at 0x80020000 {
>> + interrupt-controller;
>> + compatible = "sirf,intc", "sirf,prima2-intc";
>> + reg = <0x80020000 0x1000>;
>> + #interrupt-cells = <1>;
>> + };
>
> Some more commends on the device tree properties:
>
> I think the namespace for the compatible values is supposed to start with
> the stock ticker name of the company making the device as a unique
> identifier. This means you'd have to use
> "csrxf,sirf-intc", "csrxf,sirf-prima2-intc" as the value, instead
> of starting with the product name. I don't know exactly how strictly
> we apply that rule, but I've taken the devicetree-discuss at lists.ozlabs.org
> mailing list on Cc, maybe someone can clarify.
>
>> + timer0: timer at 0xb0020000 {
>> + compatible = "sirf,tick", "sirf,prima2-tick";
>> + reg = <0xb0020000 0x1000>;
>> + interrupts = <0>;
>> + };
>> +
>> + uart0: uart at 0xb0050000 {
>> + compatible = "sirf,uart", "sirf,prima2-uart";
>> + reg = <0xb0050000 0x1000>;
>> + interrupts = <17>;
>> + };
>> +
>> + uart1: uart at 0xb0060000 {
>> + compatible = "sirf,uart", "sirf,prima2-uart";
>> + reg = <0xb0060000 0x1000>;
>> + interrupts = <18>;
>> + };
>> + };
>> +};
>
> When you use local addresses, this would become something like
>
> axi1 {
> compatible = "simple-bus";
> #address-cells = <1>;
> #size-cells = <1>;
> ranges <0 0x80000000 0x10000000>;
>
> intc: interrupt-controller at 20000 {
> interrupt-controller;
> compatible = "sirf,intc", "sirf,prima2-intc";
> reg = <0x20000 0x1000>;
> #interrupt-cells = <1>;
> };
> }
> axi2 {
> compatible = "simple-bus";
> #address-cells = <1>;
> #size-cells = <1>;
> ranges <0 0xb0000000 0x10000000>;
>
> timer0: timer at 20000 {
> reg = <0x20000 0x1000>;
> };
>
> uart0: uart at 50000 {
> reg = <0x50000 0x1000>;
> };
>
> uart1: uart at 60000 {
> reg = <0x60000 0x1000>;
> };
> };
>
>
>
>> +
>> diff --git a/arch/arm/mach-prima2/Makefile b/arch/arm/mach-prima2/Makefile
>> new file mode 100644
>> index 0000000..c51d60d
>> --- /dev/null
>> +++ b/arch/arm/mach-prima2/Makefile
>> @@ -0,0 +1 @@
>> +obj-y := timer.o irq.o clock.o common.o board_dt.o
>
> Minor detail:
>
> better put these in a list with one file per line, like
>
> obj-y += timer.o
> obj-y += irq.o
>
> That makes the list more consistent when you add conditional files.
>
>> +++ b/arch/arm/mach-prima2/board_dt.c
>> @@ -0,0 +1,28 @@
>> +/*
>> + * This file contains code for boards with device tree support.
>> + *
>> + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
>> + *
>> + * Licensed under GPLv2 or later.
>> + */
>> +
>> +#include <linux/of.h>
>> +#include <asm/mach/arch.h>
>> +#include <asm/mach-types.h>
>> +#include <mach/hardware.h>
>> +#include "common.h"
>> +
>> +static const char *prima2cb_dt_match[] __initdata = {
>> + "sirf,prima2-cb",
>> + NULL
>> +};
>> +
>> +MACHINE_START(PRIMA2_EVB, "prima2cb")
>> + .boot_params = SIRFSOC_SDRAM_PA + 0x100,
>> + .init_early = sirfsoc_init_clk,
>> + .map_io = sirfsoc_map_io,
>> + .init_irq = sirfsoc_of_init_irq,
>> + .timer = &sirfsoc_timer,
>> + .init_machine = sirfsoc_mach_init,
>> + .dt_compat = prima2cb_dt_match,
>> +MACHINE_END
>
> How about removing the remaining board file entirely and merging the contents into
> common.c? We don't want to have board specific files any more, so the naming
> and the split is rather obsolete.
that could be. but i am not sure whether grant built this single file
to contain multi-board defines?
>
> It probably makes sense to pick a new name for the combined file, too, but I
> can't think of a good one. Maybe one of platform.c, prima2.c or core.c.
>
>> +#define IOTABLE_ENTRY(region) {\
>> + .virtual = SIRFSOC_##region##_VA_BASE, \
>> + .pfn = __phys_to_pfn(SIRFSOC_##region##_PA_BASE),\
>> + .length = SIRFSOC_##region##_SIZE, \
>> + .type = MT_DEVICE, \
>> +}
>> +
>> +static struct map_desc sirfsoc_iodesc[] __initdata = {
>> + IOTABLE_ENTRY(UART1),
>> + IOTABLE_ENTRY(CLOCK),
>> + IOTABLE_ENTRY(RSTC),
>> +#ifdef CONFIG_CACHE_L2X0
>> + IOTABLE_ENTRY(L2CC),
>> +#endif
>> +};
>
> I've thought about this some more, and I think you can get rid of most
> entries in the global table after all:
>
> * sirfsoc_init_clk() can get the physical address from the device tree
> and call iotable_init for just one entry.
>
> * RSTC does not seem to be needed early at all, you can simply ioremap it.
>
> * L2CC is only accessed from an arch_initcall, which is late enough
> for ioremap.
>
> * UART1 is only needed for early printk, so I would put the function
> that does this remaining iotable_init() call into a separate file
> that only gets compiled when that is enabled.
>
>> +void __init sirfsoc_map_io(void)
>> +{
>> + iotable_init(sirfsoc_iodesc, ARRAY_SIZE(sirfsoc_iodesc));
>> +}
>> +
>> +#define L2X0_ADDR_FILTERING_START 0xC00
>> +#define L2X0_ADDR_FILTERING_END 0xC04
>> +
>> +static int __init sirfsoc_init(void)
>> +{
>> +#ifdef CONFIG_CACHE_L2X0
>> + if (!(readl_relaxed(SIRFSOC_L2CC_VA_BASE + L2X0_CTRL) & 1)) {
>> + /*
>> + * set the physical memory windows L2 cache will cover
>> + */
>> + writel_relaxed(PHYS_OFFSET + 1024 * 1024 * 1024,
>> + SIRFSOC_L2CC_VA_BASE + L2X0_ADDR_FILTERING_END);
>> + writel_relaxed(PHYS_OFFSET | 0x1,
>> + SIRFSOC_L2CC_VA_BASE + L2X0_ADDR_FILTERING_START);
>> +
>> + writel_relaxed(0,
>> + SIRFSOC_L2CC_VA_BASE + L2X0_TAG_LATENCY_CTRL);
>> + writel_relaxed(0,
>> + SIRFSOC_L2CC_VA_BASE + L2X0_DATA_LATENCY_CTRL);
>> + }
>> + l2x0_init((void __iomem *)SIRFSOC_L2CC_VA_BASE, 0x00040000,
>> + 0x00000000);
>> +#endif
>> +
>> + return 0;
>> +}
>> +arch_initcall(sirfsoc_init);
>
> I would also suggest moving the l2x0 code into a new l2x0.c file that
> is conditionally compiled. In the header file, you then do
>
> #ifdef CONFIG_CACHE_L2X0
> extern void sirfsoc_l2x0_init(void);
> #else
> static inline void sirfsoc_l2x0_init(void) {}
> #endif
>
>> +#ifndef __ASM_ARCH_IRQS_H
>> +#define __ASM_ARCH_IRQS_H
>> +
>> +#define SIRFSOC_INTENAL_IRQ_START 0
>> +#define SIRFSOC_INTENAL_IRQ_END 59
>
> Typo, I assume: INTERNAL, not INTENAL
>
>
>> +
>> +static struct of_device_id intc_ids[] = {
>> + { .compatible = "sirf,intc" },
>> + { .compatible = "sirf,prima2-intc" },
>> +};
>
> You should only list one of these in the driver: The idea is that as
> long as all variants of the hardware are identical, you can just list
> the most general name (sirf,intc), and if you need to tell the difference
> you list the more specific names and add a .data=... member that you
> use to differentiate between them. Note that it's usually easier to
> change the code than to change the device tree, so we want to have
> the full list in the device tree, but the code just needs to pick
> one that fits the purpose.
>
> It's the same for the other drivers.
>
>> +static void __init sirfsoc_of_timer_map(void);
>
> You can remove this forward declaration if you move the sched_clock()
> function down.
>
> Arnd
> _______________________________________________
> devicetree-discuss mailing list
> devicetree-discuss at lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/devicetree-discuss
>
--
Barry Song, Linux Kernel Developer
http://21cnbao.blog.51cto.com
More information about the devicetree-discuss
mailing list