linux/arch/arm/mach-versatile/versatile_dt.c
<<
>>
Prefs
   1/*
   2 * Versatile board support using the device tree
   3 *
   4 *  Copyright (C) 2010 Secret Lab Technologies Ltd.
   5 *  Copyright (C) 2009 Jeremy Kerr <jeremy.kerr@canonical.com>
   6 *  Copyright (C) 2004 ARM Limited
   7 *  Copyright (C) 2000 Deep Blue Solutions Ltd
   8 *
   9 * This program is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License as published by
  11 * the Free Software Foundation; either version 2 of the License, or
  12 * (at your option) any later version.
  13 *
  14 * This program is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17 * GNU General Public License for more details.
  18 *
  19 * You should have received a copy of the GNU General Public License
  20 * along with this program; if not, write to the Free Software
  21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  22 */
  23
  24#include <linux/init.h>
  25#include <linux/io.h>
  26#include <linux/of.h>
  27#include <linux/of_address.h>
  28#include <linux/of_irq.h>
  29#include <linux/of_platform.h>
  30#include <linux/slab.h>
  31#include <linux/amba/bus.h>
  32#include <linux/amba/clcd.h>
  33#include <linux/platform_data/video-clcd-versatile.h>
  34#include <linux/amba/mmci.h>
  35#include <linux/mtd/physmap.h>
  36#include <asm/mach-types.h>
  37#include <asm/mach/arch.h>
  38#include <asm/mach/map.h>
  39
  40/* macro to get at MMIO space when running virtually */
  41#define IO_ADDRESS(x)           (((x) & 0x0fffffff) + (((x) >> 4) & 0x0f000000) + 0xf0000000)
  42#define __io_address(n)         ((void __iomem __force *)IO_ADDRESS(n))
  43
  44/*
  45 * Memory definitions
  46 */
  47#define VERSATILE_FLASH_BASE           0x34000000
  48#define VERSATILE_FLASH_SIZE           SZ_64M
  49
  50/*
  51 * ------------------------------------------------------------------------
  52 *  Versatile Registers
  53 * ------------------------------------------------------------------------
  54 */
  55#define VERSATILE_SYS_PCICTL_OFFSET           0x44
  56#define VERSATILE_SYS_MCI_OFFSET              0x48
  57#define VERSATILE_SYS_FLASH_OFFSET            0x4C
  58#define VERSATILE_SYS_CLCD_OFFSET             0x50
  59
  60/*
  61 * VERSATILE_SYS_FLASH
  62 */
  63#define VERSATILE_FLASHPROG_FLVPPEN     (1 << 0)        /* Enable writing to flash */
  64
  65/*
  66 * VERSATILE peripheral addresses
  67 */
  68#define VERSATILE_MMCI0_BASE           0x10005000       /* MMC interface */
  69#define VERSATILE_MMCI1_BASE           0x1000B000       /* MMC Interface */
  70#define VERSATILE_CLCD_BASE            0x10120000       /* CLCD */
  71#define VERSATILE_SCTL_BASE            0x101E0000       /* System controller */
  72#define VERSATILE_IB2_BASE             0x24000000       /* IB2 module */
  73#define VERSATILE_IB2_CTL_BASE          (VERSATILE_IB2_BASE + 0x03000000)
  74
  75/*
  76 * System controller bit assignment
  77 */
  78#define VERSATILE_REFCLK        0
  79#define VERSATILE_TIMCLK        1
  80
  81#define VERSATILE_TIMER1_EnSel  15
  82#define VERSATILE_TIMER2_EnSel  17
  83#define VERSATILE_TIMER3_EnSel  19
  84#define VERSATILE_TIMER4_EnSel  21
  85
  86static void __iomem *versatile_sys_base;
  87static void __iomem *versatile_ib2_ctrl;
  88
  89static void versatile_flash_set_vpp(struct platform_device *pdev, int on)
  90{
  91        u32 val;
  92
  93        val = readl(versatile_sys_base + VERSATILE_SYS_FLASH_OFFSET);
  94        if (on)
  95                val |= VERSATILE_FLASHPROG_FLVPPEN;
  96        else
  97                val &= ~VERSATILE_FLASHPROG_FLVPPEN;
  98        writel(val, versatile_sys_base + VERSATILE_SYS_FLASH_OFFSET);
  99}
 100
 101static struct physmap_flash_data versatile_flash_data = {
 102        .width                  = 4,
 103        .set_vpp                = versatile_flash_set_vpp,
 104};
 105
 106static struct resource versatile_flash_resource = {
 107        .start                  = VERSATILE_FLASH_BASE,
 108        .end                    = VERSATILE_FLASH_BASE + VERSATILE_FLASH_SIZE - 1,
 109        .flags                  = IORESOURCE_MEM,
 110};
 111
 112struct platform_device versatile_flash_device = {
 113        .name                   = "physmap-flash",
 114        .id                     = 0,
 115        .dev                    = {
 116                .platform_data  = &versatile_flash_data,
 117        },
 118        .num_resources          = 1,
 119        .resource               = &versatile_flash_resource,
 120};
 121
 122unsigned int mmc_status(struct device *dev)
 123{
 124        struct amba_device *adev = container_of(dev, struct amba_device, dev);
 125        u32 mask;
 126
 127        if (adev->res.start == VERSATILE_MMCI0_BASE)
 128                mask = 1;
 129        else
 130                mask = 2;
 131
 132        return readl(versatile_sys_base + VERSATILE_SYS_MCI_OFFSET) & mask;
 133}
 134
 135static struct mmci_platform_data mmc0_plat_data = {
 136        .ocr_mask       = MMC_VDD_32_33|MMC_VDD_33_34,
 137        .status         = mmc_status,
 138        .gpio_wp        = -1,
 139        .gpio_cd        = -1,
 140};
 141
 142static struct mmci_platform_data mmc1_plat_data = {
 143        .ocr_mask       = MMC_VDD_32_33|MMC_VDD_33_34,
 144        .status         = mmc_status,
 145        .gpio_wp        = -1,
 146        .gpio_cd        = -1,
 147};
 148
 149/*
 150 * CLCD support.
 151 */
 152#define SYS_CLCD_MODE_MASK      (3 << 0)
 153#define SYS_CLCD_MODE_888       (0 << 0)
 154#define SYS_CLCD_MODE_5551      (1 << 0)
 155#define SYS_CLCD_MODE_565_RLSB  (2 << 0)
 156#define SYS_CLCD_MODE_565_BLSB  (3 << 0)
 157#define SYS_CLCD_NLCDIOON       (1 << 2)
 158#define SYS_CLCD_VDDPOSSWITCH   (1 << 3)
 159#define SYS_CLCD_PWR3V5SWITCH   (1 << 4)
 160#define SYS_CLCD_ID_MASK        (0x1f << 8)
 161#define SYS_CLCD_ID_SANYO_3_8   (0x00 << 8)
 162#define SYS_CLCD_ID_UNKNOWN_8_4 (0x01 << 8)
 163#define SYS_CLCD_ID_EPSON_2_2   (0x02 << 8)
 164#define SYS_CLCD_ID_SANYO_2_5   (0x07 << 8)
 165#define SYS_CLCD_ID_VGA         (0x1f << 8)
 166
 167static bool is_sanyo_2_5_lcd;
 168
 169/*
 170 * Disable all display connectors on the interface module.
 171 */
 172static void versatile_clcd_disable(struct clcd_fb *fb)
 173{
 174        void __iomem *sys_clcd = versatile_sys_base + VERSATILE_SYS_CLCD_OFFSET;
 175        u32 val;
 176
 177        val = readl(sys_clcd);
 178        val &= ~SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH;
 179        writel(val, sys_clcd);
 180
 181        /*
 182         * If the LCD is Sanyo 2x5 in on the IB2 board, turn the back-light off
 183         */
 184        if (of_machine_is_compatible("arm,versatile-ab") && is_sanyo_2_5_lcd) {
 185                unsigned long ctrl;
 186
 187                ctrl = readl(versatile_ib2_ctrl);
 188                ctrl &= ~0x01;
 189                writel(ctrl, versatile_ib2_ctrl);
 190        }
 191}
 192
 193/*
 194 * Enable the relevant connector on the interface module.
 195 */
 196static void versatile_clcd_enable(struct clcd_fb *fb)
 197{
 198        struct fb_var_screeninfo *var = &fb->fb.var;
 199        void __iomem *sys_clcd = versatile_sys_base + VERSATILE_SYS_CLCD_OFFSET;
 200        u32 val;
 201
 202        val = readl(sys_clcd);
 203        val &= ~SYS_CLCD_MODE_MASK;
 204
 205        switch (var->green.length) {
 206        case 5:
 207                val |= SYS_CLCD_MODE_5551;
 208                break;
 209        case 6:
 210                if (var->red.offset == 0)
 211                        val |= SYS_CLCD_MODE_565_RLSB;
 212                else
 213                        val |= SYS_CLCD_MODE_565_BLSB;
 214                break;
 215        case 8:
 216                val |= SYS_CLCD_MODE_888;
 217                break;
 218        }
 219
 220        /*
 221         * Set the MUX
 222         */
 223        writel(val, sys_clcd);
 224
 225        /*
 226         * And now enable the PSUs
 227         */
 228        val |= SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH;
 229        writel(val, sys_clcd);
 230
 231        /*
 232         * If the LCD is Sanyo 2x5 in on the IB2 board, turn the back-light on
 233         */
 234        if (of_machine_is_compatible("arm,versatile-ab") && is_sanyo_2_5_lcd) {
 235                unsigned long ctrl;
 236
 237                ctrl = readl(versatile_ib2_ctrl);
 238                ctrl |= 0x01;
 239                writel(ctrl, versatile_ib2_ctrl);
 240        }
 241}
 242
 243/*
 244 * Detect which LCD panel is connected, and return the appropriate
 245 * clcd_panel structure.  Note: we do not have any information on
 246 * the required timings for the 8.4in panel, so we presently assume
 247 * VGA timings.
 248 */
 249static int versatile_clcd_setup(struct clcd_fb *fb)
 250{
 251        void __iomem *sys_clcd = versatile_sys_base + VERSATILE_SYS_CLCD_OFFSET;
 252        const char *panel_name;
 253        u32 val;
 254
 255        is_sanyo_2_5_lcd = false;
 256
 257        val = readl(sys_clcd) & SYS_CLCD_ID_MASK;
 258        if (val == SYS_CLCD_ID_SANYO_3_8)
 259                panel_name = "Sanyo TM38QV67A02A";
 260        else if (val == SYS_CLCD_ID_SANYO_2_5) {
 261                panel_name = "Sanyo QVGA Portrait";
 262                is_sanyo_2_5_lcd = true;
 263        } else if (val == SYS_CLCD_ID_EPSON_2_2)
 264                panel_name = "Epson L2F50113T00";
 265        else if (val == SYS_CLCD_ID_VGA)
 266                panel_name = "VGA";
 267        else {
 268                printk(KERN_ERR "CLCD: unknown LCD panel ID 0x%08x, using VGA\n",
 269                        val);
 270                panel_name = "VGA";
 271        }
 272
 273        fb->panel = versatile_clcd_get_panel(panel_name);
 274        if (!fb->panel)
 275                return -EINVAL;
 276
 277        return versatile_clcd_setup_dma(fb, SZ_1M);
 278}
 279
 280static void versatile_clcd_decode(struct clcd_fb *fb, struct clcd_regs *regs)
 281{
 282        clcdfb_decode(fb, regs);
 283
 284        /* Always clear BGR for RGB565: we do the routing externally */
 285        if (fb->fb.var.green.length == 6)
 286                regs->cntl &= ~CNTL_BGR;
 287}
 288
 289static struct clcd_board clcd_plat_data = {
 290        .name           = "Versatile",
 291        .caps           = CLCD_CAP_5551 | CLCD_CAP_565 | CLCD_CAP_888,
 292        .check          = clcdfb_check,
 293        .decode         = versatile_clcd_decode,
 294        .disable        = versatile_clcd_disable,
 295        .enable         = versatile_clcd_enable,
 296        .setup          = versatile_clcd_setup,
 297        .mmap           = versatile_clcd_mmap_dma,
 298        .remove         = versatile_clcd_remove_dma,
 299};
 300
 301/*
 302 * Lookup table for attaching a specific name and platform_data pointer to
 303 * devices as they get created by of_platform_populate().  Ideally this table
 304 * would not exist, but the current clock implementation depends on some devices
 305 * having a specific name.
 306 */
 307struct of_dev_auxdata versatile_auxdata_lookup[] __initdata = {
 308        OF_DEV_AUXDATA("arm,primecell", VERSATILE_MMCI0_BASE, "fpga:05", &mmc0_plat_data),
 309        OF_DEV_AUXDATA("arm,primecell", VERSATILE_MMCI1_BASE, "fpga:0b", &mmc1_plat_data),
 310        OF_DEV_AUXDATA("arm,primecell", VERSATILE_CLCD_BASE, "dev:20", &clcd_plat_data),
 311        {}
 312};
 313
 314static struct map_desc versatile_io_desc[] __initdata __maybe_unused = {
 315        {
 316                .virtual        =  IO_ADDRESS(VERSATILE_SCTL_BASE),
 317                .pfn            = __phys_to_pfn(VERSATILE_SCTL_BASE),
 318                .length         = SZ_4K * 9,
 319                .type           = MT_DEVICE
 320        }
 321};
 322
 323static void __init versatile_map_io(void)
 324{
 325        debug_ll_io_init();
 326        iotable_init(versatile_io_desc, ARRAY_SIZE(versatile_io_desc));
 327}
 328
 329static void __init versatile_init_early(void)
 330{
 331        u32 val;
 332
 333        /*
 334         * set clock frequency:
 335         *      VERSATILE_REFCLK is 32KHz
 336         *      VERSATILE_TIMCLK is 1MHz
 337         */
 338        val = readl(__io_address(VERSATILE_SCTL_BASE));
 339        writel((VERSATILE_TIMCLK << VERSATILE_TIMER1_EnSel) |
 340               (VERSATILE_TIMCLK << VERSATILE_TIMER2_EnSel) |
 341               (VERSATILE_TIMCLK << VERSATILE_TIMER3_EnSel) |
 342               (VERSATILE_TIMCLK << VERSATILE_TIMER4_EnSel) | val,
 343               __io_address(VERSATILE_SCTL_BASE));
 344}
 345
 346static void __init versatile_dt_pci_init(void)
 347{
 348        u32 val;
 349        struct device_node *np;
 350        struct property *newprop;
 351
 352        np = of_find_compatible_node(NULL, NULL, "arm,versatile-pci");
 353        if (!np)
 354                return;
 355
 356        /* Check if PCI backplane is detected */
 357        val = readl(versatile_sys_base + VERSATILE_SYS_PCICTL_OFFSET);
 358        if (val & 1) {
 359                /*
 360                 * Enable PCI accesses. Note that the documentaton is
 361                 * inconsistent whether or not this is needed, but the old
 362                 * driver had it so we will keep it.
 363                 */
 364                writel(1, versatile_sys_base + VERSATILE_SYS_PCICTL_OFFSET);
 365                return;
 366        }
 367
 368        newprop = kzalloc(sizeof(*newprop), GFP_KERNEL);
 369        if (!newprop)
 370                return;
 371
 372        newprop->name = kstrdup("status", GFP_KERNEL);
 373        newprop->value = kstrdup("disabled", GFP_KERNEL);
 374        newprop->length = sizeof("disabled");
 375        of_update_property(np, newprop);
 376
 377        pr_info("Not plugged into PCI backplane!\n");
 378}
 379
 380static void __init versatile_dt_init(void)
 381{
 382        struct device_node *np;
 383
 384        np = of_find_compatible_node(NULL, NULL, "arm,core-module-versatile");
 385        if (np)
 386                versatile_sys_base = of_iomap(np, 0);
 387        WARN_ON(!versatile_sys_base);
 388
 389        versatile_ib2_ctrl = ioremap(VERSATILE_IB2_CTL_BASE, SZ_4K);
 390
 391        versatile_dt_pci_init();
 392
 393        platform_device_register(&versatile_flash_device);
 394        of_platform_populate(NULL, of_default_bus_match_table,
 395                             versatile_auxdata_lookup, NULL);
 396}
 397
 398static const char *const versatile_dt_match[] __initconst = {
 399        "arm,versatile-ab",
 400        "arm,versatile-pb",
 401        NULL,
 402};
 403
 404DT_MACHINE_START(VERSATILE_PB, "ARM-Versatile (Device Tree Support)")
 405        .map_io         = versatile_map_io,
 406        .init_early     = versatile_init_early,
 407        .init_machine   = versatile_dt_init,
 408        .dt_compat      = versatile_dt_match,
 409MACHINE_END
 410