Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * MPC8610 HPCD board specific routines
0004  *
0005  * Initial author: Xianghua Xiao <x.xiao@freescale.com>
0006  * Recode: Jason Jin <jason.jin@freescale.com>
0007  *         York Sun <yorksun@freescale.com>
0008  *
0009  * Rewrite the interrupt routing. remove the 8259PIC support,
0010  * All the integrated device in ULI use sideband interrupt.
0011  *
0012  * Copyright 2008 Freescale Semiconductor Inc.
0013  */
0014 
0015 #include <linux/stddef.h>
0016 #include <linux/kernel.h>
0017 #include <linux/pci.h>
0018 #include <linux/interrupt.h>
0019 #include <linux/kdev_t.h>
0020 #include <linux/delay.h>
0021 #include <linux/seq_file.h>
0022 #include <linux/of.h>
0023 #include <linux/of_address.h>
0024 #include <linux/of_irq.h>
0025 #include <linux/fsl/guts.h>
0026 
0027 #include <asm/time.h>
0028 #include <asm/machdep.h>
0029 #include <asm/pci-bridge.h>
0030 #include <mm/mmu_decl.h>
0031 #include <asm/udbg.h>
0032 
0033 #include <asm/mpic.h>
0034 
0035 #include <linux/of_platform.h>
0036 #include <sysdev/fsl_pci.h>
0037 #include <sysdev/fsl_soc.h>
0038 
0039 #include "mpc86xx.h"
0040 
0041 static struct device_node *pixis_node;
0042 static unsigned char *pixis_bdcfg0, *pixis_arch;
0043 
0044 /* DIU Pixel Clock bits of the CLKDVDR Global Utilities register */
0045 #define CLKDVDR_PXCKEN      0x80000000
0046 #define CLKDVDR_PXCKINV     0x10000000
0047 #define CLKDVDR_PXCKDLY     0x06000000
0048 #define CLKDVDR_PXCLK_MASK  0x001F0000
0049 
0050 #ifdef CONFIG_SUSPEND
0051 static irqreturn_t mpc8610_sw9_irq(int irq, void *data)
0052 {
0053     pr_debug("%s: PIXIS' event (sw9/wakeup) IRQ handled\n", __func__);
0054     return IRQ_HANDLED;
0055 }
0056 
0057 static void __init mpc8610_suspend_init(void)
0058 {
0059     int irq;
0060     int ret;
0061 
0062     if (!pixis_node)
0063         return;
0064 
0065     irq = irq_of_parse_and_map(pixis_node, 0);
0066     if (!irq) {
0067         pr_err("%s: can't map pixis event IRQ.\n", __func__);
0068         return;
0069     }
0070 
0071     ret = request_irq(irq, mpc8610_sw9_irq, 0, "sw9:wakeup", NULL);
0072     if (ret) {
0073         pr_err("%s: can't request pixis event IRQ: %d\n",
0074                __func__, ret);
0075         irq_dispose_mapping(irq);
0076     }
0077 
0078     enable_irq_wake(irq);
0079 }
0080 #else
0081 static inline void mpc8610_suspend_init(void) { }
0082 #endif /* CONFIG_SUSPEND */
0083 
0084 static const struct of_device_id mpc8610_ids[] __initconst = {
0085     { .compatible = "fsl,mpc8610-immr", },
0086     { .compatible = "fsl,mpc8610-guts", },
0087     /* So that the DMA channel nodes can be probed individually: */
0088     { .compatible = "fsl,eloplus-dma", },
0089     /* PCI controllers */
0090     { .compatible = "fsl,mpc8610-pci", },
0091     {}
0092 };
0093 
0094 static int __init mpc8610_declare_of_platform_devices(void)
0095 {
0096     /* Enable wakeup on PIXIS' event IRQ. */
0097     mpc8610_suspend_init();
0098 
0099     mpc86xx_common_publish_devices();
0100 
0101     /* Without this call, the SSI device driver won't get probed. */
0102     of_platform_bus_probe(NULL, mpc8610_ids, NULL);
0103 
0104     return 0;
0105 }
0106 machine_arch_initcall(mpc86xx_hpcd, mpc8610_declare_of_platform_devices);
0107 
0108 #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
0109 
0110 /*
0111  * DIU Area Descriptor
0112  *
0113  * The MPC8610 reference manual shows the bits of the AD register in
0114  * little-endian order, which causes the BLUE_C field to be split into two
0115  * parts. To simplify the definition of the MAKE_AD() macro, we define the
0116  * fields in big-endian order and byte-swap the result.
0117  *
0118  * So even though the registers don't look like they're in the
0119  * same bit positions as they are on the P1022, the same value is written to
0120  * the AD register on the MPC8610 and on the P1022.
0121  */
0122 #define AD_BYTE_F       0x10000000
0123 #define AD_ALPHA_C_MASK     0x0E000000
0124 #define AD_ALPHA_C_SHIFT    25
0125 #define AD_BLUE_C_MASK      0x01800000
0126 #define AD_BLUE_C_SHIFT     23
0127 #define AD_GREEN_C_MASK     0x00600000
0128 #define AD_GREEN_C_SHIFT    21
0129 #define AD_RED_C_MASK       0x00180000
0130 #define AD_RED_C_SHIFT      19
0131 #define AD_PALETTE      0x00040000
0132 #define AD_PIXEL_S_MASK     0x00030000
0133 #define AD_PIXEL_S_SHIFT    16
0134 #define AD_COMP_3_MASK      0x0000F000
0135 #define AD_COMP_3_SHIFT     12
0136 #define AD_COMP_2_MASK      0x00000F00
0137 #define AD_COMP_2_SHIFT     8
0138 #define AD_COMP_1_MASK      0x000000F0
0139 #define AD_COMP_1_SHIFT     4
0140 #define AD_COMP_0_MASK      0x0000000F
0141 #define AD_COMP_0_SHIFT     0
0142 
0143 #define MAKE_AD(alpha, red, blue, green, size, c0, c1, c2, c3) \
0144     cpu_to_le32(AD_BYTE_F | (alpha << AD_ALPHA_C_SHIFT) | \
0145     (blue << AD_BLUE_C_SHIFT) | (green << AD_GREEN_C_SHIFT) | \
0146     (red << AD_RED_C_SHIFT) | (c3 << AD_COMP_3_SHIFT) | \
0147     (c2 << AD_COMP_2_SHIFT) | (c1 << AD_COMP_1_SHIFT) | \
0148     (c0 << AD_COMP_0_SHIFT) | (size << AD_PIXEL_S_SHIFT))
0149 
0150 u32 mpc8610hpcd_get_pixel_format(enum fsl_diu_monitor_port port,
0151                  unsigned int bits_per_pixel)
0152 {
0153     static const u32 pixelformat[][3] = {
0154         {
0155             MAKE_AD(3, 0, 2, 1, 3, 8, 8, 8, 8),
0156             MAKE_AD(4, 2, 0, 1, 2, 8, 8, 8, 0),
0157             MAKE_AD(4, 0, 2, 1, 1, 5, 6, 5, 0)
0158         },
0159         {
0160             MAKE_AD(3, 2, 0, 1, 3, 8, 8, 8, 8),
0161             MAKE_AD(4, 0, 2, 1, 2, 8, 8, 8, 0),
0162             MAKE_AD(4, 2, 0, 1, 1, 5, 6, 5, 0)
0163         },
0164     };
0165     unsigned int arch_monitor;
0166 
0167     /* The DVI port is mis-wired on revision 1 of this board. */
0168     arch_monitor =
0169         ((*pixis_arch == 0x01) && (port == FSL_DIU_PORT_DVI)) ? 0 : 1;
0170 
0171     switch (bits_per_pixel) {
0172     case 32:
0173         return pixelformat[arch_monitor][0];
0174     case 24:
0175         return pixelformat[arch_monitor][1];
0176     case 16:
0177         return pixelformat[arch_monitor][2];
0178     default:
0179         pr_err("fsl-diu: unsupported pixel depth %u\n", bits_per_pixel);
0180         return 0;
0181     }
0182 }
0183 
0184 void mpc8610hpcd_set_gamma_table(enum fsl_diu_monitor_port port,
0185                  char *gamma_table_base)
0186 {
0187     int i;
0188     if (port == FSL_DIU_PORT_DLVDS) {
0189         for (i = 0; i < 256*3; i++)
0190             gamma_table_base[i] = (gamma_table_base[i] << 2) |
0191                      ((gamma_table_base[i] >> 6) & 0x03);
0192     }
0193 }
0194 
0195 #define PX_BRDCFG0_DVISEL   (1 << 3)
0196 #define PX_BRDCFG0_DLINK    (1 << 4)
0197 #define PX_BRDCFG0_DIU_MASK (PX_BRDCFG0_DVISEL | PX_BRDCFG0_DLINK)
0198 
0199 void mpc8610hpcd_set_monitor_port(enum fsl_diu_monitor_port port)
0200 {
0201     switch (port) {
0202     case FSL_DIU_PORT_DVI:
0203         clrsetbits_8(pixis_bdcfg0, PX_BRDCFG0_DIU_MASK,
0204                  PX_BRDCFG0_DVISEL | PX_BRDCFG0_DLINK);
0205         break;
0206     case FSL_DIU_PORT_LVDS:
0207         clrsetbits_8(pixis_bdcfg0, PX_BRDCFG0_DIU_MASK,
0208                  PX_BRDCFG0_DLINK);
0209         break;
0210     case FSL_DIU_PORT_DLVDS:
0211         clrbits8(pixis_bdcfg0, PX_BRDCFG0_DIU_MASK);
0212         break;
0213     }
0214 }
0215 
0216 /**
0217  * mpc8610hpcd_set_pixel_clock: program the DIU's clock
0218  *
0219  * @pixclock: the wavelength, in picoseconds, of the clock
0220  */
0221 void mpc8610hpcd_set_pixel_clock(unsigned int pixclock)
0222 {
0223     struct device_node *guts_np = NULL;
0224     struct ccsr_guts __iomem *guts;
0225     unsigned long freq;
0226     u64 temp;
0227     u32 pxclk;
0228 
0229     /* Map the global utilities registers. */
0230     guts_np = of_find_compatible_node(NULL, NULL, "fsl,mpc8610-guts");
0231     if (!guts_np) {
0232         pr_err("mpc8610hpcd: missing global utilities device node\n");
0233         return;
0234     }
0235 
0236     guts = of_iomap(guts_np, 0);
0237     of_node_put(guts_np);
0238     if (!guts) {
0239         pr_err("mpc8610hpcd: could not map global utilities device\n");
0240         return;
0241     }
0242 
0243     /* Convert pixclock from a wavelength to a frequency */
0244     temp = 1000000000000ULL;
0245     do_div(temp, pixclock);
0246     freq = temp;
0247 
0248     /*
0249      * 'pxclk' is the ratio of the platform clock to the pixel clock.
0250      * On the MPC8610, the value programmed into CLKDVDR is the ratio
0251      * minus one.  The valid range of values is 2-31.
0252      */
0253     pxclk = DIV_ROUND_CLOSEST(fsl_get_sys_freq(), freq) - 1;
0254     pxclk = clamp_t(u32, pxclk, 2, 31);
0255 
0256     /* Disable the pixel clock, and set it to non-inverted and no delay */
0257     clrbits32(&guts->clkdvdr,
0258           CLKDVDR_PXCKEN | CLKDVDR_PXCKDLY | CLKDVDR_PXCLK_MASK);
0259 
0260     /* Enable the clock and set the pxclk */
0261     setbits32(&guts->clkdvdr, CLKDVDR_PXCKEN | (pxclk << 16));
0262 
0263     iounmap(guts);
0264 }
0265 
0266 enum fsl_diu_monitor_port
0267 mpc8610hpcd_valid_monitor_port(enum fsl_diu_monitor_port port)
0268 {
0269     return port;
0270 }
0271 
0272 #endif
0273 
0274 static void __init mpc86xx_hpcd_setup_arch(void)
0275 {
0276     struct resource r;
0277     unsigned char *pixis;
0278 
0279     if (ppc_md.progress)
0280         ppc_md.progress("mpc86xx_hpcd_setup_arch()", 0);
0281 
0282     fsl_pci_assign_primary();
0283 
0284 #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
0285     diu_ops.get_pixel_format    = mpc8610hpcd_get_pixel_format;
0286     diu_ops.set_gamma_table     = mpc8610hpcd_set_gamma_table;
0287     diu_ops.set_monitor_port    = mpc8610hpcd_set_monitor_port;
0288     diu_ops.set_pixel_clock     = mpc8610hpcd_set_pixel_clock;
0289     diu_ops.valid_monitor_port  = mpc8610hpcd_valid_monitor_port;
0290 #endif
0291 
0292     pixis_node = of_find_compatible_node(NULL, NULL, "fsl,fpga-pixis");
0293     if (pixis_node) {
0294         of_address_to_resource(pixis_node, 0, &r);
0295         of_node_put(pixis_node);
0296         pixis = ioremap(r.start, 32);
0297         if (!pixis) {
0298             printk(KERN_ERR "Err: can't map FPGA cfg register!\n");
0299             return;
0300         }
0301         pixis_bdcfg0 = pixis + 8;
0302         pixis_arch = pixis + 1;
0303     } else
0304         printk(KERN_ERR "Err: "
0305                 "can't find device node 'fsl,fpga-pixis'\n");
0306 
0307     printk("MPC86xx HPCD board from Freescale Semiconductor\n");
0308 }
0309 
0310 /*
0311  * Called very early, device-tree isn't unflattened
0312  */
0313 static int __init mpc86xx_hpcd_probe(void)
0314 {
0315     if (of_machine_is_compatible("fsl,MPC8610HPCD"))
0316         return 1;   /* Looks good */
0317 
0318     return 0;
0319 }
0320 
0321 define_machine(mpc86xx_hpcd) {
0322     .name           = "MPC86xx HPCD",
0323     .probe          = mpc86xx_hpcd_probe,
0324     .setup_arch     = mpc86xx_hpcd_setup_arch,
0325     .init_IRQ       = mpc86xx_init_irq,
0326     .get_irq        = mpic_get_irq,
0327     .time_init      = mpc86xx_time_init,
0328     .calibrate_decr     = generic_calibrate_decr,
0329     .progress       = udbg_progress,
0330 #ifdef CONFIG_PCI
0331     .pcibios_fixup_bus  = fsl_pcibios_fixup_bus,
0332 #endif
0333 };