linux/arch/powerpc/platforms/512x/mpc512x_shared.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2007,2008 Freescale Semiconductor, Inc. All rights reserved.
   3 *
   4 * Author: John Rigby <jrigby@freescale.com>
   5 *
   6 * Description:
   7 * MPC512x Shared code
   8 *
   9 * This is free software; you can redistribute it and/or modify it
  10 * 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
  15#include <linux/kernel.h>
  16#include <linux/io.h>
  17#include <linux/irq.h>
  18#include <linux/of_platform.h>
  19#include <linux/fsl-diu-fb.h>
  20#include <linux/bootmem.h>
  21#include <sysdev/fsl_soc.h>
  22
  23#include <asm/cacheflush.h>
  24#include <asm/machdep.h>
  25#include <asm/ipic.h>
  26#include <asm/prom.h>
  27#include <asm/time.h>
  28#include <asm/mpc5121.h>
  29#include <asm/mpc52xx_psc.h>
  30
  31#include "mpc512x.h"
  32
  33static struct mpc512x_reset_module __iomem *reset_module_base;
  34
  35static void __init mpc512x_restart_init(void)
  36{
  37        struct device_node *np;
  38        const char *reset_compat;
  39
  40        reset_compat = mpc512x_select_reset_compat();
  41        np = of_find_compatible_node(NULL, NULL, reset_compat);
  42        if (!np)
  43                return;
  44
  45        reset_module_base = of_iomap(np, 0);
  46        of_node_put(np);
  47}
  48
  49void mpc512x_restart(char *cmd)
  50{
  51        if (reset_module_base) {
  52                /* Enable software reset "RSTE" */
  53                out_be32(&reset_module_base->rpr, 0x52535445);
  54                /* Set software hard reset */
  55                out_be32(&reset_module_base->rcr, 0x2);
  56        } else {
  57                pr_err("Restart module not mapped.\n");
  58        }
  59        for (;;)
  60                ;
  61}
  62
  63#if IS_ENABLED(CONFIG_FB_FSL_DIU)
  64
  65struct fsl_diu_shared_fb {
  66        u8              gamma[0x300];   /* 32-bit aligned! */
  67        struct diu_ad   ad0;            /* 32-bit aligned! */
  68        phys_addr_t     fb_phys;
  69        size_t          fb_len;
  70        bool            in_use;
  71};
  72
  73#define DIU_DIV_MASK    0x000000ff
  74void mpc512x_set_pixel_clock(unsigned int pixclock)
  75{
  76        unsigned long bestval, bestfreq, speed, busfreq;
  77        unsigned long minpixclock, maxpixclock, pixval;
  78        struct mpc512x_ccm __iomem *ccm;
  79        struct device_node *np;
  80        u32 temp;
  81        long err;
  82        int i;
  83
  84        np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-clock");
  85        if (!np) {
  86                pr_err("Can't find clock control module.\n");
  87                return;
  88        }
  89
  90        ccm = of_iomap(np, 0);
  91        of_node_put(np);
  92        if (!ccm) {
  93                pr_err("Can't map clock control module reg.\n");
  94                return;
  95        }
  96
  97        np = of_find_node_by_type(NULL, "cpu");
  98        if (np) {
  99                const unsigned int *prop =
 100                        of_get_property(np, "bus-frequency", NULL);
 101
 102                of_node_put(np);
 103                if (prop) {
 104                        busfreq = *prop;
 105                } else {
 106                        pr_err("Can't get bus-frequency property\n");
 107                        return;
 108                }
 109        } else {
 110                pr_err("Can't find 'cpu' node.\n");
 111                return;
 112        }
 113
 114        /* Pixel Clock configuration */
 115        pr_debug("DIU: Bus Frequency = %lu\n", busfreq);
 116        speed = busfreq * 4; /* DIU_DIV ratio is 4 * CSB_CLK / DIU_CLK */
 117
 118        /* Calculate the pixel clock with the smallest error */
 119        /* calculate the following in steps to avoid overflow */
 120        pr_debug("DIU pixclock in ps - %d\n", pixclock);
 121        temp = (1000000000 / pixclock) * 1000;
 122        pixclock = temp;
 123        pr_debug("DIU pixclock freq - %u\n", pixclock);
 124
 125        temp = temp / 20; /* pixclock * 0.05 */
 126        pr_debug("deviation = %d\n", temp);
 127        minpixclock = pixclock - temp;
 128        maxpixclock = pixclock + temp;
 129        pr_debug("DIU minpixclock - %lu\n", minpixclock);
 130        pr_debug("DIU maxpixclock - %lu\n", maxpixclock);
 131        pixval = speed/pixclock;
 132        pr_debug("DIU pixval = %lu\n", pixval);
 133
 134        err = LONG_MAX;
 135        bestval = pixval;
 136        pr_debug("DIU bestval = %lu\n", bestval);
 137
 138        bestfreq = 0;
 139        for (i = -1; i <= 1; i++) {
 140                temp = speed / (pixval+i);
 141                pr_debug("DIU test pixval i=%d, pixval=%lu, temp freq. = %u\n",
 142                        i, pixval, temp);
 143                if ((temp < minpixclock) || (temp > maxpixclock))
 144                        pr_debug("DIU exceeds monitor range (%lu to %lu)\n",
 145                                minpixclock, maxpixclock);
 146                else if (abs(temp - pixclock) < err) {
 147                        pr_debug("Entered the else if block %d\n", i);
 148                        err = abs(temp - pixclock);
 149                        bestval = pixval + i;
 150                        bestfreq = temp;
 151                }
 152        }
 153
 154        pr_debug("DIU chose = %lx\n", bestval);
 155        pr_debug("DIU error = %ld\n NomPixClk ", err);
 156        pr_debug("DIU: Best Freq = %lx\n", bestfreq);
 157        /* Modify DIU_DIV in CCM SCFR1 */
 158        temp = in_be32(&ccm->scfr1);
 159        pr_debug("DIU: Current value of SCFR1: 0x%08x\n", temp);
 160        temp &= ~DIU_DIV_MASK;
 161        temp |= (bestval & DIU_DIV_MASK);
 162        out_be32(&ccm->scfr1, temp);
 163        pr_debug("DIU: Modified value of SCFR1: 0x%08x\n", temp);
 164        iounmap(ccm);
 165}
 166
 167enum fsl_diu_monitor_port
 168mpc512x_valid_monitor_port(enum fsl_diu_monitor_port port)
 169{
 170        return FSL_DIU_PORT_DVI;
 171}
 172
 173static struct fsl_diu_shared_fb __attribute__ ((__aligned__(8))) diu_shared_fb;
 174
 175static inline void mpc512x_free_bootmem(struct page *page)
 176{
 177        BUG_ON(PageTail(page));
 178        BUG_ON(atomic_read(&page->_count) > 1);
 179        free_reserved_page(page);
 180}
 181
 182void mpc512x_release_bootmem(void)
 183{
 184        unsigned long addr = diu_shared_fb.fb_phys & PAGE_MASK;
 185        unsigned long size = diu_shared_fb.fb_len;
 186        unsigned long start, end;
 187
 188        if (diu_shared_fb.in_use) {
 189                start = PFN_UP(addr);
 190                end = PFN_DOWN(addr + size);
 191
 192                for (; start < end; start++)
 193                        mpc512x_free_bootmem(pfn_to_page(start));
 194
 195                diu_shared_fb.in_use = false;
 196        }
 197        diu_ops.release_bootmem = NULL;
 198}
 199
 200/*
 201 * Check if DIU was pre-initialized. If so, perform steps
 202 * needed to continue displaying through the whole boot process.
 203 * Move area descriptor and gamma table elsewhere, they are
 204 * destroyed by bootmem allocator otherwise. The frame buffer
 205 * address range will be reserved in setup_arch() after bootmem
 206 * allocator is up.
 207 */
 208void __init mpc512x_init_diu(void)
 209{
 210        struct device_node *np;
 211        struct diu __iomem *diu_reg;
 212        phys_addr_t desc;
 213        void __iomem *vaddr;
 214        unsigned long mode, pix_fmt, res, bpp;
 215        unsigned long dst;
 216
 217        np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-diu");
 218        if (!np) {
 219                pr_err("No DIU node\n");
 220                return;
 221        }
 222
 223        diu_reg = of_iomap(np, 0);
 224        of_node_put(np);
 225        if (!diu_reg) {
 226                pr_err("Can't map DIU\n");
 227                return;
 228        }
 229
 230        mode = in_be32(&diu_reg->diu_mode);
 231        if (mode == MFB_MODE0) {
 232                pr_info("%s: DIU OFF\n", __func__);
 233                goto out;
 234        }
 235
 236        desc = in_be32(&diu_reg->desc[0]);
 237        vaddr = ioremap(desc, sizeof(struct diu_ad));
 238        if (!vaddr) {
 239                pr_err("Can't map DIU area desc.\n");
 240                goto out;
 241        }
 242        memcpy(&diu_shared_fb.ad0, vaddr, sizeof(struct diu_ad));
 243        /* flush fb area descriptor */
 244        dst = (unsigned long)&diu_shared_fb.ad0;
 245        flush_dcache_range(dst, dst + sizeof(struct diu_ad) - 1);
 246
 247        res = in_be32(&diu_reg->disp_size);
 248        pix_fmt = in_le32(vaddr);
 249        bpp = ((pix_fmt >> 16) & 0x3) + 1;
 250        diu_shared_fb.fb_phys = in_le32(vaddr + 4);
 251        diu_shared_fb.fb_len = ((res & 0xfff0000) >> 16) * (res & 0xfff) * bpp;
 252        diu_shared_fb.in_use = true;
 253        iounmap(vaddr);
 254
 255        desc = in_be32(&diu_reg->gamma);
 256        vaddr = ioremap(desc, sizeof(diu_shared_fb.gamma));
 257        if (!vaddr) {
 258                pr_err("Can't map DIU area desc.\n");
 259                diu_shared_fb.in_use = false;
 260                goto out;
 261        }
 262        memcpy(&diu_shared_fb.gamma, vaddr, sizeof(diu_shared_fb.gamma));
 263        /* flush gamma table */
 264        dst = (unsigned long)&diu_shared_fb.gamma;
 265        flush_dcache_range(dst, dst + sizeof(diu_shared_fb.gamma) - 1);
 266
 267        iounmap(vaddr);
 268        out_be32(&diu_reg->gamma, virt_to_phys(&diu_shared_fb.gamma));
 269        out_be32(&diu_reg->desc[1], 0);
 270        out_be32(&diu_reg->desc[2], 0);
 271        out_be32(&diu_reg->desc[0], virt_to_phys(&diu_shared_fb.ad0));
 272
 273out:
 274        iounmap(diu_reg);
 275}
 276
 277void __init mpc512x_setup_diu(void)
 278{
 279        int ret;
 280
 281        /*
 282         * We do not allocate and configure new area for bitmap buffer
 283         * because it would requere copying bitmap data (splash image)
 284         * and so negatively affect boot time. Instead we reserve the
 285         * already configured frame buffer area so that it won't be
 286         * destroyed. The starting address of the area to reserve and
 287         * also it's length is passed to reserve_bootmem(). It will be
 288         * freed later on first open of fbdev, when splash image is not
 289         * needed any more.
 290         */
 291        if (diu_shared_fb.in_use) {
 292                ret = reserve_bootmem(diu_shared_fb.fb_phys,
 293                                      diu_shared_fb.fb_len,
 294                                      BOOTMEM_EXCLUSIVE);
 295                if (ret) {
 296                        pr_err("%s: reserve bootmem failed\n", __func__);
 297                        diu_shared_fb.in_use = false;
 298                }
 299        }
 300
 301        diu_ops.set_pixel_clock         = mpc512x_set_pixel_clock;
 302        diu_ops.valid_monitor_port      = mpc512x_valid_monitor_port;
 303        diu_ops.release_bootmem         = mpc512x_release_bootmem;
 304}
 305
 306#endif
 307
 308void __init mpc512x_init_IRQ(void)
 309{
 310        struct device_node *np;
 311
 312        np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-ipic");
 313        if (!np)
 314                return;
 315
 316        ipic_init(np, 0);
 317        of_node_put(np);
 318
 319        /*
 320         * Initialize the default interrupt mapping priorities,
 321         * in case the boot rom changed something on us.
 322         */
 323        ipic_set_default_priority();
 324}
 325
 326/*
 327 * Nodes to do bus probe on, soc and localbus
 328 */
 329static struct of_device_id __initdata of_bus_ids[] = {
 330        { .compatible = "fsl,mpc5121-immr", },
 331        { .compatible = "fsl,mpc5121-localbus", },
 332        { .compatible = "fsl,mpc5121-mbx", },
 333        { .compatible = "fsl,mpc5121-nfc", },
 334        { .compatible = "fsl,mpc5121-sram", },
 335        { .compatible = "fsl,mpc5121-pci", },
 336        { .compatible = "gpio-leds", },
 337        {},
 338};
 339
 340void __init mpc512x_declare_of_platform_devices(void)
 341{
 342        if (of_platform_bus_probe(NULL, of_bus_ids, NULL))
 343                printk(KERN_ERR __FILE__ ": "
 344                        "Error while probing of_platform bus\n");
 345}
 346
 347#define DEFAULT_FIFO_SIZE 16
 348
 349const char *mpc512x_select_psc_compat(void)
 350{
 351        if (of_machine_is_compatible("fsl,mpc5121"))
 352                return "fsl,mpc5121-psc";
 353
 354        if (of_machine_is_compatible("fsl,mpc5125"))
 355                return "fsl,mpc5125-psc";
 356
 357        return NULL;
 358}
 359
 360const char *mpc512x_select_reset_compat(void)
 361{
 362        if (of_machine_is_compatible("fsl,mpc5121"))
 363                return "fsl,mpc5121-reset";
 364
 365        if (of_machine_is_compatible("fsl,mpc5125"))
 366                return "fsl,mpc5125-reset";
 367
 368        return NULL;
 369}
 370
 371static unsigned int __init get_fifo_size(struct device_node *np,
 372                                         char *prop_name)
 373{
 374        const unsigned int *fp;
 375
 376        fp = of_get_property(np, prop_name, NULL);
 377        if (fp)
 378                return *fp;
 379
 380        pr_warning("no %s property in %s node, defaulting to %d\n",
 381                   prop_name, np->full_name, DEFAULT_FIFO_SIZE);
 382
 383        return DEFAULT_FIFO_SIZE;
 384}
 385
 386#define FIFOC(_base) ((struct mpc512x_psc_fifo __iomem *) \
 387                    ((u32)(_base) + sizeof(struct mpc52xx_psc)))
 388
 389/* Init PSC FIFO space for TX and RX slices */
 390void __init mpc512x_psc_fifo_init(void)
 391{
 392        struct device_node *np;
 393        void __iomem *psc;
 394        unsigned int tx_fifo_size;
 395        unsigned int rx_fifo_size;
 396        const char *psc_compat;
 397        int fifobase = 0; /* current fifo address in 32 bit words */
 398
 399        psc_compat = mpc512x_select_psc_compat();
 400        if (!psc_compat) {
 401                pr_err("%s: no compatible devices found\n", __func__);
 402                return;
 403        }
 404
 405        for_each_compatible_node(np, NULL, psc_compat) {
 406                tx_fifo_size = get_fifo_size(np, "fsl,tx-fifo-size");
 407                rx_fifo_size = get_fifo_size(np, "fsl,rx-fifo-size");
 408
 409                /* size in register is in 4 byte units */
 410                tx_fifo_size /= 4;
 411                rx_fifo_size /= 4;
 412                if (!tx_fifo_size)
 413                        tx_fifo_size = 1;
 414                if (!rx_fifo_size)
 415                        rx_fifo_size = 1;
 416
 417                psc = of_iomap(np, 0);
 418                if (!psc) {
 419                        pr_err("%s: Can't map %s device\n",
 420                                __func__, np->full_name);
 421                        continue;
 422                }
 423
 424                /* FIFO space is 4KiB, check if requested size is available */
 425                if ((fifobase + tx_fifo_size + rx_fifo_size) > 0x1000) {
 426                        pr_err("%s: no fifo space available for %s\n",
 427                                __func__, np->full_name);
 428                        iounmap(psc);
 429                        /*
 430                         * chances are that another device requests less
 431                         * fifo space, so we continue.
 432                         */
 433                        continue;
 434                }
 435
 436                /* set tx and rx fifo size registers */
 437                out_be32(&FIFOC(psc)->txsz, (fifobase << 16) | tx_fifo_size);
 438                fifobase += tx_fifo_size;
 439                out_be32(&FIFOC(psc)->rxsz, (fifobase << 16) | rx_fifo_size);
 440                fifobase += rx_fifo_size;
 441
 442                /* reset and enable the slices */
 443                out_be32(&FIFOC(psc)->txcmd, 0x80);
 444                out_be32(&FIFOC(psc)->txcmd, 0x01);
 445                out_be32(&FIFOC(psc)->rxcmd, 0x80);
 446                out_be32(&FIFOC(psc)->rxcmd, 0x01);
 447
 448                iounmap(psc);
 449        }
 450}
 451
 452void __init mpc512x_init_early(void)
 453{
 454        mpc512x_restart_init();
 455        if (IS_ENABLED(CONFIG_FB_FSL_DIU))
 456                mpc512x_init_diu();
 457}
 458
 459void __init mpc512x_init(void)
 460{
 461        mpc5121_clk_init();
 462        mpc512x_declare_of_platform_devices();
 463        mpc512x_psc_fifo_init();
 464}
 465
 466void __init mpc512x_setup_arch(void)
 467{
 468        if (IS_ENABLED(CONFIG_FB_FSL_DIU))
 469                mpc512x_setup_diu();
 470}
 471
 472/**
 473 * mpc512x_cs_config - Setup chip select configuration
 474 * @cs: chip select number
 475 * @val: chip select configuration value
 476 *
 477 * Perform chip select configuration for devices on LocalPlus Bus.
 478 * Intended to dynamically reconfigure the chip select parameters
 479 * for configurable devices on the bus.
 480 */
 481int mpc512x_cs_config(unsigned int cs, u32 val)
 482{
 483        static struct mpc512x_lpc __iomem *lpc;
 484        struct device_node *np;
 485
 486        if (cs > 7)
 487                return -EINVAL;
 488
 489        if (!lpc) {
 490                np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-lpc");
 491                lpc = of_iomap(np, 0);
 492                of_node_put(np);
 493                if (!lpc)
 494                        return -ENOMEM;
 495        }
 496
 497        out_be32(&lpc->cs_cfg[cs], val);
 498        return 0;
 499}
 500EXPORT_SYMBOL(mpc512x_cs_config);
 501