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 <asm/mach-types.h>
  36#include <asm/mach/arch.h>
  37#include <asm/mach/map.h>
  38
  39/* macro to get at MMIO space when running virtually */
  40#define IO_ADDRESS(x)           (((x) & 0x0fffffff) + (((x) >> 4) & 0x0f000000) + 0xf0000000)
  41#define __io_address(n)         ((void __iomem __force *)IO_ADDRESS(n))
  42
  43/*
  44 * ------------------------------------------------------------------------
  45 *  Versatile Registers
  46 * ------------------------------------------------------------------------
  47 */
  48#define VERSATILE_SYS_PCICTL_OFFSET           0x44
  49#define VERSATILE_SYS_MCI_OFFSET              0x48
  50#define VERSATILE_SYS_CLCD_OFFSET             0x50
  51
  52/*
  53 * VERSATILE peripheral addresses
  54 */
  55#define VERSATILE_MMCI0_BASE           0x10005000       /* MMC interface */
  56#define VERSATILE_MMCI1_BASE           0x1000B000       /* MMC Interface */
  57#define VERSATILE_CLCD_BASE            0x10120000       /* CLCD */
  58#define VERSATILE_SCTL_BASE            0x101E0000       /* System controller */
  59#define VERSATILE_IB2_BASE             0x24000000       /* IB2 module */
  60#define VERSATILE_IB2_CTL_BASE          (VERSATILE_IB2_BASE + 0x03000000)
  61
  62/*
  63 * System controller bit assignment
  64 */
  65#define VERSATILE_REFCLK        0
  66#define VERSATILE_TIMCLK        1
  67
  68#define VERSATILE_TIMER1_EnSel  15
  69#define VERSATILE_TIMER2_EnSel  17
  70#define VERSATILE_TIMER3_EnSel  19
  71#define VERSATILE_TIMER4_EnSel  21
  72
  73static void __iomem *versatile_sys_base;
  74static void __iomem *versatile_ib2_ctrl;
  75
  76unsigned int mmc_status(struct device *dev)
  77{
  78        struct amba_device *adev = container_of(dev, struct amba_device, dev);
  79        u32 mask;
  80
  81        if (adev->res.start == VERSATILE_MMCI0_BASE)
  82                mask = 1;
  83        else
  84                mask = 2;
  85
  86        return readl(versatile_sys_base + VERSATILE_SYS_MCI_OFFSET) & mask;
  87}
  88
  89static struct mmci_platform_data mmc0_plat_data = {
  90        .ocr_mask       = MMC_VDD_32_33|MMC_VDD_33_34,
  91        .status         = mmc_status,
  92        .gpio_wp        = -1,
  93        .gpio_cd        = -1,
  94};
  95
  96static struct mmci_platform_data mmc1_plat_data = {
  97        .ocr_mask       = MMC_VDD_32_33|MMC_VDD_33_34,
  98        .status         = mmc_status,
  99        .gpio_wp        = -1,
 100        .gpio_cd        = -1,
 101};
 102
 103/*
 104 * CLCD support.
 105 */
 106#define SYS_CLCD_MODE_MASK      (3 << 0)
 107#define SYS_CLCD_MODE_888       (0 << 0)
 108#define SYS_CLCD_MODE_5551      (1 << 0)
 109#define SYS_CLCD_MODE_565_RLSB  (2 << 0)
 110#define SYS_CLCD_MODE_565_BLSB  (3 << 0)
 111#define SYS_CLCD_NLCDIOON       (1 << 2)
 112#define SYS_CLCD_VDDPOSSWITCH   (1 << 3)
 113#define SYS_CLCD_PWR3V5SWITCH   (1 << 4)
 114#define SYS_CLCD_ID_MASK        (0x1f << 8)
 115#define SYS_CLCD_ID_SANYO_3_8   (0x00 << 8)
 116#define SYS_CLCD_ID_UNKNOWN_8_4 (0x01 << 8)
 117#define SYS_CLCD_ID_EPSON_2_2   (0x02 << 8)
 118#define SYS_CLCD_ID_SANYO_2_5   (0x07 << 8)
 119#define SYS_CLCD_ID_VGA         (0x1f << 8)
 120
 121static bool is_sanyo_2_5_lcd;
 122
 123/*
 124 * Disable all display connectors on the interface module.
 125 */
 126static void versatile_clcd_disable(struct clcd_fb *fb)
 127{
 128        void __iomem *sys_clcd = versatile_sys_base + VERSATILE_SYS_CLCD_OFFSET;
 129        u32 val;
 130
 131        val = readl(sys_clcd);
 132        val &= ~SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH;
 133        writel(val, sys_clcd);
 134
 135        /*
 136         * If the LCD is Sanyo 2x5 in on the IB2 board, turn the back-light off
 137         */
 138        if (of_machine_is_compatible("arm,versatile-ab") && is_sanyo_2_5_lcd) {
 139                unsigned long ctrl;
 140
 141                ctrl = readl(versatile_ib2_ctrl);
 142                ctrl &= ~0x01;
 143                writel(ctrl, versatile_ib2_ctrl);
 144        }
 145}
 146
 147/*
 148 * Enable the relevant connector on the interface module.
 149 */
 150static void versatile_clcd_enable(struct clcd_fb *fb)
 151{
 152        struct fb_var_screeninfo *var = &fb->fb.var;
 153        void __iomem *sys_clcd = versatile_sys_base + VERSATILE_SYS_CLCD_OFFSET;
 154        u32 val;
 155
 156        val = readl(sys_clcd);
 157        val &= ~SYS_CLCD_MODE_MASK;
 158
 159        switch (var->green.length) {
 160        case 5:
 161                val |= SYS_CLCD_MODE_5551;
 162                break;
 163        case 6:
 164                if (var->red.offset == 0)
 165                        val |= SYS_CLCD_MODE_565_RLSB;
 166                else
 167                        val |= SYS_CLCD_MODE_565_BLSB;
 168                break;
 169        case 8:
 170                val |= SYS_CLCD_MODE_888;
 171                break;
 172        }
 173
 174        /*
 175         * Set the MUX
 176         */
 177        writel(val, sys_clcd);
 178
 179        /*
 180         * And now enable the PSUs
 181         */
 182        val |= SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH;
 183        writel(val, sys_clcd);
 184
 185        /*
 186         * If the LCD is Sanyo 2x5 in on the IB2 board, turn the back-light on
 187         */
 188        if (of_machine_is_compatible("arm,versatile-ab") && is_sanyo_2_5_lcd) {
 189                unsigned long ctrl;
 190
 191                ctrl = readl(versatile_ib2_ctrl);
 192                ctrl |= 0x01;
 193                writel(ctrl, versatile_ib2_ctrl);
 194        }
 195}
 196
 197/*
 198 * Detect which LCD panel is connected, and return the appropriate
 199 * clcd_panel structure.  Note: we do not have any information on
 200 * the required timings for the 8.4in panel, so we presently assume
 201 * VGA timings.
 202 */
 203static int versatile_clcd_setup(struct clcd_fb *fb)
 204{
 205        void __iomem *sys_clcd = versatile_sys_base + VERSATILE_SYS_CLCD_OFFSET;
 206        const char *panel_name;
 207        u32 val;
 208
 209        is_sanyo_2_5_lcd = false;
 210
 211        val = readl(sys_clcd) & SYS_CLCD_ID_MASK;
 212        if (val == SYS_CLCD_ID_SANYO_3_8)
 213                panel_name = "Sanyo TM38QV67A02A";
 214        else if (val == SYS_CLCD_ID_SANYO_2_5) {
 215                panel_name = "Sanyo QVGA Portrait";
 216                is_sanyo_2_5_lcd = true;
 217        } else if (val == SYS_CLCD_ID_EPSON_2_2)
 218                panel_name = "Epson L2F50113T00";
 219        else if (val == SYS_CLCD_ID_VGA)
 220                panel_name = "VGA";
 221        else {
 222                printk(KERN_ERR "CLCD: unknown LCD panel ID 0x%08x, using VGA\n",
 223                        val);
 224                panel_name = "VGA";
 225        }
 226
 227        fb->panel = versatile_clcd_get_panel(panel_name);
 228        if (!fb->panel)
 229                return -EINVAL;
 230
 231        return versatile_clcd_setup_dma(fb, SZ_1M);
 232}
 233
 234static void versatile_clcd_decode(struct clcd_fb *fb, struct clcd_regs *regs)
 235{
 236        clcdfb_decode(fb, regs);
 237
 238        /* Always clear BGR for RGB565: we do the routing externally */
 239        if (fb->fb.var.green.length == 6)
 240                regs->cntl &= ~CNTL_BGR;
 241}
 242
 243static struct clcd_board clcd_plat_data = {
 244        .name           = "Versatile",
 245        .caps           = CLCD_CAP_5551 | CLCD_CAP_565 | CLCD_CAP_888,
 246        .check          = clcdfb_check,
 247        .decode         = versatile_clcd_decode,
 248        .disable        = versatile_clcd_disable,
 249        .enable         = versatile_clcd_enable,
 250        .setup          = versatile_clcd_setup,
 251        .mmap           = versatile_clcd_mmap_dma,
 252        .remove         = versatile_clcd_remove_dma,
 253};
 254
 255/*
 256 * Lookup table for attaching a specific name and platform_data pointer to
 257 * devices as they get created by of_platform_populate().  Ideally this table
 258 * would not exist, but the current clock implementation depends on some devices
 259 * having a specific name.
 260 */
 261struct of_dev_auxdata versatile_auxdata_lookup[] __initdata = {
 262        OF_DEV_AUXDATA("arm,primecell", VERSATILE_MMCI0_BASE, "fpga:05", &mmc0_plat_data),
 263        OF_DEV_AUXDATA("arm,primecell", VERSATILE_MMCI1_BASE, "fpga:0b", &mmc1_plat_data),
 264        OF_DEV_AUXDATA("arm,primecell", VERSATILE_CLCD_BASE, "dev:20", &clcd_plat_data),
 265        {}
 266};
 267
 268static struct map_desc versatile_io_desc[] __initdata __maybe_unused = {
 269        {
 270                .virtual        =  IO_ADDRESS(VERSATILE_SCTL_BASE),
 271                .pfn            = __phys_to_pfn(VERSATILE_SCTL_BASE),
 272                .length         = SZ_4K * 9,
 273                .type           = MT_DEVICE
 274        }
 275};
 276
 277static void __init versatile_map_io(void)
 278{
 279        debug_ll_io_init();
 280        iotable_init(versatile_io_desc, ARRAY_SIZE(versatile_io_desc));
 281}
 282
 283static void __init versatile_init_early(void)
 284{
 285        u32 val;
 286
 287        /*
 288         * set clock frequency:
 289         *      VERSATILE_REFCLK is 32KHz
 290         *      VERSATILE_TIMCLK is 1MHz
 291         */
 292        val = readl(__io_address(VERSATILE_SCTL_BASE));
 293        writel((VERSATILE_TIMCLK << VERSATILE_TIMER1_EnSel) |
 294               (VERSATILE_TIMCLK << VERSATILE_TIMER2_EnSel) |
 295               (VERSATILE_TIMCLK << VERSATILE_TIMER3_EnSel) |
 296               (VERSATILE_TIMCLK << VERSATILE_TIMER4_EnSel) | val,
 297               __io_address(VERSATILE_SCTL_BASE));
 298}
 299
 300static void __init versatile_dt_pci_init(void)
 301{
 302        u32 val;
 303        struct device_node *np;
 304        struct property *newprop;
 305
 306        np = of_find_compatible_node(NULL, NULL, "arm,versatile-pci");
 307        if (!np)
 308                return;
 309
 310        /* Check if PCI backplane is detected */
 311        val = readl(versatile_sys_base + VERSATILE_SYS_PCICTL_OFFSET);
 312        if (val & 1) {
 313                /*
 314                 * Enable PCI accesses. Note that the documentaton is
 315                 * inconsistent whether or not this is needed, but the old
 316                 * driver had it so we will keep it.
 317                 */
 318                writel(1, versatile_sys_base + VERSATILE_SYS_PCICTL_OFFSET);
 319                return;
 320        }
 321
 322        newprop = kzalloc(sizeof(*newprop), GFP_KERNEL);
 323        if (!newprop)
 324                return;
 325
 326        newprop->name = kstrdup("status", GFP_KERNEL);
 327        newprop->value = kstrdup("disabled", GFP_KERNEL);
 328        newprop->length = sizeof("disabled");
 329        of_update_property(np, newprop);
 330
 331        pr_info("Not plugged into PCI backplane!\n");
 332}
 333
 334static void __init versatile_dt_init(void)
 335{
 336        struct device_node *np;
 337
 338        np = of_find_compatible_node(NULL, NULL, "arm,core-module-versatile");
 339        if (np)
 340                versatile_sys_base = of_iomap(np, 0);
 341        WARN_ON(!versatile_sys_base);
 342
 343        versatile_ib2_ctrl = ioremap(VERSATILE_IB2_CTL_BASE, SZ_4K);
 344
 345        versatile_dt_pci_init();
 346
 347        of_platform_default_populate(NULL, versatile_auxdata_lookup, NULL);
 348}
 349
 350static const char *const versatile_dt_match[] __initconst = {
 351        "arm,versatile-ab",
 352        "arm,versatile-pb",
 353        NULL,
 354};
 355
 356DT_MACHINE_START(VERSATILE_PB, "ARM-Versatile (Device Tree Support)")
 357        .map_io         = versatile_map_io,
 358        .init_early     = versatile_init_early,
 359        .init_machine   = versatile_dt_init,
 360        .dt_compat      = versatile_dt_match,
 361MACHINE_END
 362