root/arch/powerpc/platforms/86xx/mpc8610_hpcd.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mpc8610_sw9_irq
  2. mpc8610_suspend_init
  3. mpc8610_suspend_init
  4. mpc8610_declare_of_platform_devices
  5. mpc8610hpcd_get_pixel_format
  6. mpc8610hpcd_set_gamma_table
  7. mpc8610hpcd_set_monitor_port
  8. mpc8610hpcd_set_pixel_clock
  9. mpc8610hpcd_valid_monitor_port
  10. mpc86xx_hpcd_setup_arch
  11. mpc86xx_hpcd_probe
  12. define_machine

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * MPC8610 HPCD board specific routines
   4  *
   5  * Initial author: Xianghua Xiao <x.xiao@freescale.com>
   6  * Recode: Jason Jin <jason.jin@freescale.com>
   7  *         York Sun <yorksun@freescale.com>
   8  *
   9  * Rewrite the interrupt routing. remove the 8259PIC support,
  10  * All the integrated device in ULI use sideband interrupt.
  11  *
  12  * Copyright 2008 Freescale Semiconductor Inc.
  13  */
  14 
  15 #include <linux/stddef.h>
  16 #include <linux/kernel.h>
  17 #include <linux/pci.h>
  18 #include <linux/interrupt.h>
  19 #include <linux/kdev_t.h>
  20 #include <linux/delay.h>
  21 #include <linux/seq_file.h>
  22 #include <linux/of.h>
  23 #include <linux/fsl/guts.h>
  24 
  25 #include <asm/time.h>
  26 #include <asm/machdep.h>
  27 #include <asm/pci-bridge.h>
  28 #include <asm/prom.h>
  29 #include <mm/mmu_decl.h>
  30 #include <asm/udbg.h>
  31 
  32 #include <asm/mpic.h>
  33 
  34 #include <linux/of_platform.h>
  35 #include <sysdev/fsl_pci.h>
  36 #include <sysdev/fsl_soc.h>
  37 #include <sysdev/simple_gpio.h>
  38 
  39 #include "mpc86xx.h"
  40 
  41 static struct device_node *pixis_node;
  42 static unsigned char *pixis_bdcfg0, *pixis_arch;
  43 
  44 /* DIU Pixel Clock bits of the CLKDVDR Global Utilities register */
  45 #define CLKDVDR_PXCKEN          0x80000000
  46 #define CLKDVDR_PXCKINV         0x10000000
  47 #define CLKDVDR_PXCKDLY         0x06000000
  48 #define CLKDVDR_PXCLK_MASK      0x001F0000
  49 
  50 #ifdef CONFIG_SUSPEND
  51 static irqreturn_t mpc8610_sw9_irq(int irq, void *data)
  52 {
  53         pr_debug("%s: PIXIS' event (sw9/wakeup) IRQ handled\n", __func__);
  54         return IRQ_HANDLED;
  55 }
  56 
  57 static void __init mpc8610_suspend_init(void)
  58 {
  59         int irq;
  60         int ret;
  61 
  62         if (!pixis_node)
  63                 return;
  64 
  65         irq = irq_of_parse_and_map(pixis_node, 0);
  66         if (!irq) {
  67                 pr_err("%s: can't map pixis event IRQ.\n", __func__);
  68                 return;
  69         }
  70 
  71         ret = request_irq(irq, mpc8610_sw9_irq, 0, "sw9:wakeup", NULL);
  72         if (ret) {
  73                 pr_err("%s: can't request pixis event IRQ: %d\n",
  74                        __func__, ret);
  75                 irq_dispose_mapping(irq);
  76         }
  77 
  78         enable_irq_wake(irq);
  79 }
  80 #else
  81 static inline void mpc8610_suspend_init(void) { }
  82 #endif /* CONFIG_SUSPEND */
  83 
  84 static const struct of_device_id mpc8610_ids[] __initconst = {
  85         { .compatible = "fsl,mpc8610-immr", },
  86         { .compatible = "fsl,mpc8610-guts", },
  87         /* So that the DMA channel nodes can be probed individually: */
  88         { .compatible = "fsl,eloplus-dma", },
  89         /* PCI controllers */
  90         { .compatible = "fsl,mpc8610-pci", },
  91         {}
  92 };
  93 
  94 static int __init mpc8610_declare_of_platform_devices(void)
  95 {
  96         /* Firstly, register PIXIS GPIOs. */
  97         simple_gpiochip_init("fsl,fpga-pixis-gpio-bank");
  98 
  99         /* Enable wakeup on PIXIS' event IRQ. */
 100         mpc8610_suspend_init();
 101 
 102         mpc86xx_common_publish_devices();
 103 
 104         /* Without this call, the SSI device driver won't get probed. */
 105         of_platform_bus_probe(NULL, mpc8610_ids, NULL);
 106 
 107         return 0;
 108 }
 109 machine_arch_initcall(mpc86xx_hpcd, mpc8610_declare_of_platform_devices);
 110 
 111 #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
 112 
 113 /*
 114  * DIU Area Descriptor
 115  *
 116  * The MPC8610 reference manual shows the bits of the AD register in
 117  * little-endian order, which causes the BLUE_C field to be split into two
 118  * parts. To simplify the definition of the MAKE_AD() macro, we define the
 119  * fields in big-endian order and byte-swap the result.
 120  *
 121  * So even though the registers don't look like they're in the
 122  * same bit positions as they are on the P1022, the same value is written to
 123  * the AD register on the MPC8610 and on the P1022.
 124  */
 125 #define AD_BYTE_F               0x10000000
 126 #define AD_ALPHA_C_MASK         0x0E000000
 127 #define AD_ALPHA_C_SHIFT        25
 128 #define AD_BLUE_C_MASK          0x01800000
 129 #define AD_BLUE_C_SHIFT         23
 130 #define AD_GREEN_C_MASK         0x00600000
 131 #define AD_GREEN_C_SHIFT        21
 132 #define AD_RED_C_MASK           0x00180000
 133 #define AD_RED_C_SHIFT          19
 134 #define AD_PALETTE              0x00040000
 135 #define AD_PIXEL_S_MASK         0x00030000
 136 #define AD_PIXEL_S_SHIFT        16
 137 #define AD_COMP_3_MASK          0x0000F000
 138 #define AD_COMP_3_SHIFT         12
 139 #define AD_COMP_2_MASK          0x00000F00
 140 #define AD_COMP_2_SHIFT         8
 141 #define AD_COMP_1_MASK          0x000000F0
 142 #define AD_COMP_1_SHIFT         4
 143 #define AD_COMP_0_MASK          0x0000000F
 144 #define AD_COMP_0_SHIFT         0
 145 
 146 #define MAKE_AD(alpha, red, blue, green, size, c0, c1, c2, c3) \
 147         cpu_to_le32(AD_BYTE_F | (alpha << AD_ALPHA_C_SHIFT) | \
 148         (blue << AD_BLUE_C_SHIFT) | (green << AD_GREEN_C_SHIFT) | \
 149         (red << AD_RED_C_SHIFT) | (c3 << AD_COMP_3_SHIFT) | \
 150         (c2 << AD_COMP_2_SHIFT) | (c1 << AD_COMP_1_SHIFT) | \
 151         (c0 << AD_COMP_0_SHIFT) | (size << AD_PIXEL_S_SHIFT))
 152 
 153 u32 mpc8610hpcd_get_pixel_format(enum fsl_diu_monitor_port port,
 154                                  unsigned int bits_per_pixel)
 155 {
 156         static const u32 pixelformat[][3] = {
 157                 {
 158                         MAKE_AD(3, 0, 2, 1, 3, 8, 8, 8, 8),
 159                         MAKE_AD(4, 2, 0, 1, 2, 8, 8, 8, 0),
 160                         MAKE_AD(4, 0, 2, 1, 1, 5, 6, 5, 0)
 161                 },
 162                 {
 163                         MAKE_AD(3, 2, 0, 1, 3, 8, 8, 8, 8),
 164                         MAKE_AD(4, 0, 2, 1, 2, 8, 8, 8, 0),
 165                         MAKE_AD(4, 2, 0, 1, 1, 5, 6, 5, 0)
 166                 },
 167         };
 168         unsigned int arch_monitor;
 169 
 170         /* The DVI port is mis-wired on revision 1 of this board. */
 171         arch_monitor =
 172                 ((*pixis_arch == 0x01) && (port == FSL_DIU_PORT_DVI)) ? 0 : 1;
 173 
 174         switch (bits_per_pixel) {
 175         case 32:
 176                 return pixelformat[arch_monitor][0];
 177         case 24:
 178                 return pixelformat[arch_monitor][1];
 179         case 16:
 180                 return pixelformat[arch_monitor][2];
 181         default:
 182                 pr_err("fsl-diu: unsupported pixel depth %u\n", bits_per_pixel);
 183                 return 0;
 184         }
 185 }
 186 
 187 void mpc8610hpcd_set_gamma_table(enum fsl_diu_monitor_port port,
 188                                  char *gamma_table_base)
 189 {
 190         int i;
 191         if (port == FSL_DIU_PORT_DLVDS) {
 192                 for (i = 0; i < 256*3; i++)
 193                         gamma_table_base[i] = (gamma_table_base[i] << 2) |
 194                                          ((gamma_table_base[i] >> 6) & 0x03);
 195         }
 196 }
 197 
 198 #define PX_BRDCFG0_DVISEL       (1 << 3)
 199 #define PX_BRDCFG0_DLINK        (1 << 4)
 200 #define PX_BRDCFG0_DIU_MASK     (PX_BRDCFG0_DVISEL | PX_BRDCFG0_DLINK)
 201 
 202 void mpc8610hpcd_set_monitor_port(enum fsl_diu_monitor_port port)
 203 {
 204         switch (port) {
 205         case FSL_DIU_PORT_DVI:
 206                 clrsetbits_8(pixis_bdcfg0, PX_BRDCFG0_DIU_MASK,
 207                              PX_BRDCFG0_DVISEL | PX_BRDCFG0_DLINK);
 208                 break;
 209         case FSL_DIU_PORT_LVDS:
 210                 clrsetbits_8(pixis_bdcfg0, PX_BRDCFG0_DIU_MASK,
 211                              PX_BRDCFG0_DLINK);
 212                 break;
 213         case FSL_DIU_PORT_DLVDS:
 214                 clrbits8(pixis_bdcfg0, PX_BRDCFG0_DIU_MASK);
 215                 break;
 216         }
 217 }
 218 
 219 /**
 220  * mpc8610hpcd_set_pixel_clock: program the DIU's clock
 221  *
 222  * @pixclock: the wavelength, in picoseconds, of the clock
 223  */
 224 void mpc8610hpcd_set_pixel_clock(unsigned int pixclock)
 225 {
 226         struct device_node *guts_np = NULL;
 227         struct ccsr_guts __iomem *guts;
 228         unsigned long freq;
 229         u64 temp;
 230         u32 pxclk;
 231 
 232         /* Map the global utilities registers. */
 233         guts_np = of_find_compatible_node(NULL, NULL, "fsl,mpc8610-guts");
 234         if (!guts_np) {
 235                 pr_err("mpc8610hpcd: missing global utilities device node\n");
 236                 return;
 237         }
 238 
 239         guts = of_iomap(guts_np, 0);
 240         of_node_put(guts_np);
 241         if (!guts) {
 242                 pr_err("mpc8610hpcd: could not map global utilities device\n");
 243                 return;
 244         }
 245 
 246         /* Convert pixclock from a wavelength to a frequency */
 247         temp = 1000000000000ULL;
 248         do_div(temp, pixclock);
 249         freq = temp;
 250 
 251         /*
 252          * 'pxclk' is the ratio of the platform clock to the pixel clock.
 253          * On the MPC8610, the value programmed into CLKDVDR is the ratio
 254          * minus one.  The valid range of values is 2-31.
 255          */
 256         pxclk = DIV_ROUND_CLOSEST(fsl_get_sys_freq(), freq) - 1;
 257         pxclk = clamp_t(u32, pxclk, 2, 31);
 258 
 259         /* Disable the pixel clock, and set it to non-inverted and no delay */
 260         clrbits32(&guts->clkdvdr,
 261                   CLKDVDR_PXCKEN | CLKDVDR_PXCKDLY | CLKDVDR_PXCLK_MASK);
 262 
 263         /* Enable the clock and set the pxclk */
 264         setbits32(&guts->clkdvdr, CLKDVDR_PXCKEN | (pxclk << 16));
 265 
 266         iounmap(guts);
 267 }
 268 
 269 enum fsl_diu_monitor_port
 270 mpc8610hpcd_valid_monitor_port(enum fsl_diu_monitor_port port)
 271 {
 272         return port;
 273 }
 274 
 275 #endif
 276 
 277 static void __init mpc86xx_hpcd_setup_arch(void)
 278 {
 279         struct resource r;
 280         unsigned char *pixis;
 281 
 282         if (ppc_md.progress)
 283                 ppc_md.progress("mpc86xx_hpcd_setup_arch()", 0);
 284 
 285         fsl_pci_assign_primary();
 286 
 287 #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
 288         diu_ops.get_pixel_format        = mpc8610hpcd_get_pixel_format;
 289         diu_ops.set_gamma_table         = mpc8610hpcd_set_gamma_table;
 290         diu_ops.set_monitor_port        = mpc8610hpcd_set_monitor_port;
 291         diu_ops.set_pixel_clock         = mpc8610hpcd_set_pixel_clock;
 292         diu_ops.valid_monitor_port      = mpc8610hpcd_valid_monitor_port;
 293 #endif
 294 
 295         pixis_node = of_find_compatible_node(NULL, NULL, "fsl,fpga-pixis");
 296         if (pixis_node) {
 297                 of_address_to_resource(pixis_node, 0, &r);
 298                 of_node_put(pixis_node);
 299                 pixis = ioremap(r.start, 32);
 300                 if (!pixis) {
 301                         printk(KERN_ERR "Err: can't map FPGA cfg register!\n");
 302                         return;
 303                 }
 304                 pixis_bdcfg0 = pixis + 8;
 305                 pixis_arch = pixis + 1;
 306         } else
 307                 printk(KERN_ERR "Err: "
 308                                 "can't find device node 'fsl,fpga-pixis'\n");
 309 
 310         printk("MPC86xx HPCD board from Freescale Semiconductor\n");
 311 }
 312 
 313 /*
 314  * Called very early, device-tree isn't unflattened
 315  */
 316 static int __init mpc86xx_hpcd_probe(void)
 317 {
 318         if (of_machine_is_compatible("fsl,MPC8610HPCD"))
 319                 return 1;       /* Looks good */
 320 
 321         return 0;
 322 }
 323 
 324 define_machine(mpc86xx_hpcd) {
 325         .name                   = "MPC86xx HPCD",
 326         .probe                  = mpc86xx_hpcd_probe,
 327         .setup_arch             = mpc86xx_hpcd_setup_arch,
 328         .init_IRQ               = mpc86xx_init_irq,
 329         .get_irq                = mpic_get_irq,
 330         .time_init              = mpc86xx_time_init,
 331         .calibrate_decr         = generic_calibrate_decr,
 332         .progress               = udbg_progress,
 333 #ifdef CONFIG_PCI
 334         .pcibios_fixup_bus      = fsl_pcibios_fixup_bus,
 335 #endif
 336 };

/* [<][>][^][v][top][bottom][index][help] */