Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 //
0003 // Copyright 2010 Darius Augulis <augulis.darius@gmail.com>
0004 // Copyright 2008 Openmoko, Inc.
0005 // Copyright 2008 Simtec Electronics
0006 //  Ben Dooks <ben@simtec.co.uk>
0007 //  http://armlinux.simtec.co.uk/
0008 
0009 #include <linux/init.h>
0010 #include <linux/interrupt.h>
0011 #include <linux/fb.h>
0012 #include <linux/gpio.h>
0013 #include <linux/kernel.h>
0014 #include <linux/list.h>
0015 #include <linux/dm9000.h>
0016 #include <linux/mtd/mtd.h>
0017 #include <linux/mtd/partitions.h>
0018 #include <linux/serial_core.h>
0019 #include <linux/serial_s3c.h>
0020 #include <linux/types.h>
0021 
0022 #include <asm/mach-types.h>
0023 #include <asm/mach/arch.h>
0024 #include <asm/mach/map.h>
0025 
0026 #include "map.h"
0027 #include "regs-gpio.h"
0028 #include "gpio-samsung.h"
0029 
0030 #include <linux/soc/samsung/s3c-adc.h>
0031 #include "cpu.h"
0032 #include "devs.h"
0033 #include "fb.h"
0034 #include <linux/platform_data/mtd-nand-s3c2410.h>
0035 #include <linux/platform_data/mmc-sdhci-s3c.h>
0036 #include "sdhci.h"
0037 #include <linux/platform_data/touchscreen-s3c2410.h>
0038 #include "irqs.h"
0039 
0040 #include <video/platform_lcd.h>
0041 #include <video/samsung_fimd.h>
0042 
0043 #include "s3c64xx.h"
0044 #include "regs-modem-s3c64xx.h"
0045 #include "regs-srom-s3c64xx.h"
0046 
0047 #define UCON S3C2410_UCON_DEFAULT
0048 #define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB)
0049 #define UFCON (S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE)
0050 
0051 static struct s3c2410_uartcfg mini6410_uartcfgs[] __initdata = {
0052     [0] = {
0053         .hwport = 0,
0054         .flags  = 0,
0055         .ucon   = UCON,
0056         .ulcon  = ULCON,
0057         .ufcon  = UFCON,
0058     },
0059     [1] = {
0060         .hwport = 1,
0061         .flags  = 0,
0062         .ucon   = UCON,
0063         .ulcon  = ULCON,
0064         .ufcon  = UFCON,
0065     },
0066     [2] = {
0067         .hwport = 2,
0068         .flags  = 0,
0069         .ucon   = UCON,
0070         .ulcon  = ULCON,
0071         .ufcon  = UFCON,
0072     },
0073     [3] = {
0074         .hwport = 3,
0075         .flags  = 0,
0076         .ucon   = UCON,
0077         .ulcon  = ULCON,
0078         .ufcon  = UFCON,
0079     },
0080 };
0081 
0082 /* DM9000AEP 10/100 ethernet controller */
0083 
0084 static struct resource mini6410_dm9k_resource[] = {
0085     [0] = DEFINE_RES_MEM(S3C64XX_PA_XM0CSN1, 2),
0086     [1] = DEFINE_RES_MEM(S3C64XX_PA_XM0CSN1 + 4, 2),
0087     [2] = DEFINE_RES_NAMED(S3C_EINT(7), 1, NULL, IORESOURCE_IRQ \
0088                     | IORESOURCE_IRQ_HIGHLEVEL),
0089 };
0090 
0091 static struct dm9000_plat_data mini6410_dm9k_pdata = {
0092     .flags      = (DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM),
0093 };
0094 
0095 static struct platform_device mini6410_device_eth = {
0096     .name       = "dm9000",
0097     .id     = -1,
0098     .num_resources  = ARRAY_SIZE(mini6410_dm9k_resource),
0099     .resource   = mini6410_dm9k_resource,
0100     .dev        = {
0101         .platform_data  = &mini6410_dm9k_pdata,
0102     },
0103 };
0104 
0105 static struct mtd_partition mini6410_nand_part[] = {
0106     [0] = {
0107         .name   = "uboot",
0108         .size   = SZ_1M,
0109         .offset = 0,
0110     },
0111     [1] = {
0112         .name   = "kernel",
0113         .size   = SZ_2M,
0114         .offset = SZ_1M,
0115     },
0116     [2] = {
0117         .name   = "rootfs",
0118         .size   = MTDPART_SIZ_FULL,
0119         .offset = SZ_1M + SZ_2M,
0120     },
0121 };
0122 
0123 static struct s3c2410_nand_set mini6410_nand_sets[] = {
0124     [0] = {
0125         .name       = "nand",
0126         .nr_chips   = 1,
0127         .nr_partitions  = ARRAY_SIZE(mini6410_nand_part),
0128         .partitions = mini6410_nand_part,
0129     },
0130 };
0131 
0132 static struct s3c2410_platform_nand mini6410_nand_info = {
0133     .tacls      = 25,
0134     .twrph0     = 55,
0135     .twrph1     = 40,
0136     .nr_sets    = ARRAY_SIZE(mini6410_nand_sets),
0137     .sets       = mini6410_nand_sets,
0138     .engine_type    = NAND_ECC_ENGINE_TYPE_SOFT,
0139 };
0140 
0141 static struct s3c_fb_pd_win mini6410_lcd_type0_fb_win = {
0142     .max_bpp    = 32,
0143     .default_bpp    = 16,
0144     .xres       = 480,
0145     .yres       = 272,
0146 };
0147 
0148 static struct fb_videomode mini6410_lcd_type0_timing = {
0149     /* 4.3" 480x272 */
0150     .left_margin    = 3,
0151     .right_margin   = 2,
0152     .upper_margin   = 1,
0153     .lower_margin   = 1,
0154     .hsync_len  = 40,
0155     .vsync_len  = 1,
0156     .xres       = 480,
0157     .yres       = 272,
0158 };
0159 
0160 static struct s3c_fb_pd_win mini6410_lcd_type1_fb_win = {
0161     .max_bpp    = 32,
0162     .default_bpp    = 16,
0163     .xres       = 800,
0164     .yres       = 480,
0165 };
0166 
0167 static struct fb_videomode mini6410_lcd_type1_timing = {
0168     /* 7.0" 800x480 */
0169     .left_margin    = 8,
0170     .right_margin   = 13,
0171     .upper_margin   = 7,
0172     .lower_margin   = 5,
0173     .hsync_len  = 3,
0174     .vsync_len  = 1,
0175     .xres       = 800,
0176     .yres       = 480,
0177 };
0178 
0179 static struct s3c_fb_platdata mini6410_lcd_pdata[] __initdata = {
0180     {
0181         .setup_gpio = s3c64xx_fb_gpio_setup_24bpp,
0182         .vtiming    = &mini6410_lcd_type0_timing,
0183         .win[0]     = &mini6410_lcd_type0_fb_win,
0184         .vidcon0    = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
0185         .vidcon1    = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
0186     }, {
0187         .setup_gpio = s3c64xx_fb_gpio_setup_24bpp,
0188         .vtiming    = &mini6410_lcd_type1_timing,
0189         .win[0]     = &mini6410_lcd_type1_fb_win,
0190         .vidcon0    = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
0191         .vidcon1    = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
0192     },
0193     { },
0194 };
0195 
0196 static void mini6410_lcd_power_set(struct plat_lcd_data *pd,
0197                    unsigned int power)
0198 {
0199     if (power)
0200         gpio_direction_output(S3C64XX_GPE(0), 1);
0201     else
0202         gpio_direction_output(S3C64XX_GPE(0), 0);
0203 }
0204 
0205 static struct plat_lcd_data mini6410_lcd_power_data = {
0206     .set_power  = mini6410_lcd_power_set,
0207 };
0208 
0209 static struct platform_device mini6410_lcd_powerdev = {
0210     .name           = "platform-lcd",
0211     .dev.parent     = &s3c_device_fb.dev,
0212     .dev.platform_data  = &mini6410_lcd_power_data,
0213 };
0214 
0215 static struct s3c_sdhci_platdata mini6410_hsmmc1_pdata = {
0216     .max_width      = 4,
0217     .cd_type        = S3C_SDHCI_CD_GPIO,
0218     .ext_cd_gpio        = S3C64XX_GPN(10),
0219     .ext_cd_gpio_invert = true,
0220 };
0221 
0222 static struct platform_device *mini6410_devices[] __initdata = {
0223     &mini6410_device_eth,
0224     &s3c_device_hsmmc0,
0225     &s3c_device_hsmmc1,
0226     &s3c_device_ohci,
0227     &s3c_device_nand,
0228     &s3c_device_fb,
0229     &mini6410_lcd_powerdev,
0230     &s3c_device_adc,
0231 };
0232 
0233 static void __init mini6410_map_io(void)
0234 {
0235     u32 tmp;
0236 
0237     s3c64xx_init_io(NULL, 0);
0238     s3c64xx_set_xtal_freq(12000000);
0239     s3c24xx_init_uarts(mini6410_uartcfgs, ARRAY_SIZE(mini6410_uartcfgs));
0240     s3c64xx_set_timer_source(S3C64XX_PWM3, S3C64XX_PWM4);
0241 
0242     /* set the LCD type */
0243     tmp = __raw_readl(S3C64XX_SPCON);
0244     tmp &= ~S3C64XX_SPCON_LCD_SEL_MASK;
0245     tmp |= S3C64XX_SPCON_LCD_SEL_RGB;
0246     __raw_writel(tmp, S3C64XX_SPCON);
0247 
0248     /* remove the LCD bypass */
0249     tmp = __raw_readl(S3C64XX_MODEM_MIFPCON);
0250     tmp &= ~MIFPCON_LCD_BYPASS;
0251     __raw_writel(tmp, S3C64XX_MODEM_MIFPCON);
0252 }
0253 
0254 /*
0255  * mini6410_features string
0256  *
0257  * 0-9 LCD configuration
0258  *
0259  */
0260 static char mini6410_features_str[12] __initdata = "0";
0261 
0262 static int __init mini6410_features_setup(char *str)
0263 {
0264     if (str)
0265         strscpy(mini6410_features_str, str,
0266             sizeof(mini6410_features_str));
0267     return 1;
0268 }
0269 
0270 __setup("mini6410=", mini6410_features_setup);
0271 
0272 #define FEATURE_SCREEN (1 << 0)
0273 
0274 struct mini6410_features_t {
0275     int done;
0276     int lcd_index;
0277 };
0278 
0279 static void mini6410_parse_features(
0280         struct mini6410_features_t *features,
0281         const char *features_str)
0282 {
0283     const char *fp = features_str;
0284 
0285     features->done = 0;
0286     features->lcd_index = 0;
0287 
0288     while (*fp) {
0289         char f = *fp++;
0290 
0291         switch (f) {
0292         case '0'...'9': /* tft screen */
0293             if (features->done & FEATURE_SCREEN) {
0294                 printk(KERN_INFO "MINI6410: '%c' ignored, "
0295                     "screen type already set\n", f);
0296             } else {
0297                 int li = f - '0';
0298                 if (li >= ARRAY_SIZE(mini6410_lcd_pdata))
0299                     printk(KERN_INFO "MINI6410: '%c' out "
0300                         "of range LCD mode\n", f);
0301                 else {
0302                     features->lcd_index = li;
0303                 }
0304             }
0305             features->done |= FEATURE_SCREEN;
0306             break;
0307         }
0308     }
0309 }
0310 
0311 static void __init mini6410_machine_init(void)
0312 {
0313     u32 cs1;
0314     struct mini6410_features_t features = { 0 };
0315 
0316     printk(KERN_INFO "MINI6410: Option string mini6410=%s\n",
0317             mini6410_features_str);
0318 
0319     /* Parse the feature string */
0320     mini6410_parse_features(&features, mini6410_features_str);
0321 
0322     printk(KERN_INFO "MINI6410: selected LCD display is %dx%d\n",
0323         mini6410_lcd_pdata[features.lcd_index].win[0]->xres,
0324         mini6410_lcd_pdata[features.lcd_index].win[0]->yres);
0325 
0326     s3c_nand_set_platdata(&mini6410_nand_info);
0327     s3c_fb_set_platdata(&mini6410_lcd_pdata[features.lcd_index]);
0328     s3c_sdhci1_set_platdata(&mini6410_hsmmc1_pdata);
0329     s3c64xx_ts_set_platdata(NULL);
0330 
0331     /* configure nCS1 width to 16 bits */
0332 
0333     cs1 = __raw_readl(S3C64XX_SROM_BW) &
0334         ~(S3C64XX_SROM_BW__CS_MASK << S3C64XX_SROM_BW__NCS1__SHIFT);
0335     cs1 |= ((1 << S3C64XX_SROM_BW__DATAWIDTH__SHIFT) |
0336         (1 << S3C64XX_SROM_BW__WAITENABLE__SHIFT) |
0337         (1 << S3C64XX_SROM_BW__BYTEENABLE__SHIFT)) <<
0338             S3C64XX_SROM_BW__NCS1__SHIFT;
0339     __raw_writel(cs1, S3C64XX_SROM_BW);
0340 
0341     /* set timing for nCS1 suitable for ethernet chip */
0342 
0343     __raw_writel((0 << S3C64XX_SROM_BCX__PMC__SHIFT) |
0344         (6 << S3C64XX_SROM_BCX__TACP__SHIFT) |
0345         (4 << S3C64XX_SROM_BCX__TCAH__SHIFT) |
0346         (1 << S3C64XX_SROM_BCX__TCOH__SHIFT) |
0347         (13 << S3C64XX_SROM_BCX__TACC__SHIFT) |
0348         (4 << S3C64XX_SROM_BCX__TCOS__SHIFT) |
0349         (0 << S3C64XX_SROM_BCX__TACS__SHIFT), S3C64XX_SROM_BC1);
0350 
0351     gpio_request(S3C64XX_GPF(15), "LCD power");
0352     gpio_request(S3C64XX_GPE(0), "LCD power");
0353 
0354     platform_add_devices(mini6410_devices, ARRAY_SIZE(mini6410_devices));
0355 }
0356 
0357 MACHINE_START(MINI6410, "MINI6410")
0358     /* Maintainer: Darius Augulis <augulis.darius@gmail.com> */
0359     .atag_offset    = 0x100,
0360     .nr_irqs    = S3C64XX_NR_IRQS,
0361     .init_irq   = s3c6410_init_irq,
0362     .map_io     = mini6410_map_io,
0363     .init_machine   = mini6410_machine_init,
0364     .init_time  = s3c64xx_timer_init,
0365 MACHINE_END