diff --git a/Makefile b/Makefile index f6145ea..0717692 100644 --- a/Makefile +++ b/Makefile @@ -599,7 +599,7 @@ # Generate .S file with all kernel symbols quiet_cmd_kallsyms = KSYM $@ - cmd_kallsyms = $(NM) -g -n $< | $(KALLSYMS) > $@ + cmd_kallsyms = $(NM) -n $< | $(KALLSYMS) --all-symbols > $@ .tmp_kallsyms1.o .tmp_kallsyms2.o .tmp_kallsyms3.o: %.o: %.S scripts FORCE $(call if_changed_dep,as_o_S) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index bc54e58..aae0e99 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -115,6 +115,16 @@ These functions work much faster than the normal versions but increase your binary size. +config ARM_UNWIND + bool "enable stack unwinding support" + depends on AEABI + help + This option enables stack unwinding support in barebox + using the information automatically generated by the + compiler. The resulting kernel image is slightly bigger but + the performance is not affected. Currently, this feature + only works with EABI compilers. If unsure say Y. + endmenu source common/Kconfig diff --git a/arch/arm/Makefile b/arch/arm/Makefile index d075efd..697c783 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -34,6 +34,10 @@ CFLAGS_ABI :=$(call cc-option,-mapcs-32,-mabi=apcs-gnu) $(call cc-option,-mno-thumb-interwork,) endif +ifeq ($(CONFIG_ARM_UNWIND),y) +CFLAGS_ABI +=-funwind-tables +endif + CPPFLAGS += $(CFLAGS_ABI) $(arch-y) $(tune-y) AFLAGS += -include asm/unified.h diff --git a/arch/arm/boards/a9m2410/a9m2410.c b/arch/arm/boards/a9m2410/a9m2410.c index 57d8fa3..8cbaec5 100644 --- a/arch/arm/boards/a9m2410/a9m2410.c +++ b/arch/arm/boards/a9m2410/a9m2410.c @@ -176,7 +176,7 @@ #ifdef CONFIG_S3C24XX_NAND_BOOT void __bare_init nand_boot(void) { - s3c24x0_nand_load_image((void *)TEXT_BASE, 256 * 1024, 0, 512); + s3c24x0_nand_load_image((void *)TEXT_BASE, 256 * 1024, 0); } #endif diff --git a/arch/arm/boards/a9m2440/a9m2440.c b/arch/arm/boards/a9m2440/a9m2440.c index 764cd65..39b5276 100644 --- a/arch/arm/boards/a9m2440/a9m2440.c +++ b/arch/arm/boards/a9m2440/a9m2440.c @@ -182,7 +182,7 @@ #ifdef CONFIG_S3C24XX_NAND_BOOT void __bare_init nand_boot(void) { - s3c24x0_nand_load_image((void *)TEXT_BASE, 256 * 1024, 0, 512); + s3c24x0_nand_load_image((void *)TEXT_BASE, 256 * 1024, 0); } #endif diff --git a/arch/arm/boards/at91sam9261ek/env/config b/arch/arm/boards/at91sam9261ek/env/config index 51bfbaa..733326d 100644 --- a/arch/arm/boards/at91sam9261ek/env/config +++ b/arch/arm/boards/at91sam9261ek/env/config @@ -10,8 +10,8 @@ #eth0.gateway=a.b.c.d #eth0.serverip=a.b.c.d -# can be either 'net' or 'nand' -kernel_loc=net +# can be either 'nfs', 'tftp' or 'nand' +kernel_loc=tftp # can be either 'net', 'nand' or 'initrd' rootfs_loc=net diff --git a/arch/arm/boards/at91sam9263ek/env/config b/arch/arm/boards/at91sam9263ek/env/config index 84f163d..f1cb751 100644 --- a/arch/arm/boards/at91sam9263ek/env/config +++ b/arch/arm/boards/at91sam9263ek/env/config @@ -10,8 +10,8 @@ #eth0.gateway=a.b.c.d #eth0.serverip=a.b.c.d -# can be either 'net' , 'nor' or 'nand' -kernel_loc=net +# can be either 'nfs', 'tftp', 'nor' or 'nand' +kernel_loc=tftp # can be either 'net', 'nor', 'nand' or 'initrd' rootfs_loc=net diff --git a/arch/arm/boards/at91sam9m10g45ek/env/config b/arch/arm/boards/at91sam9m10g45ek/env/config index 9fcf465..b8ca18d 100644 --- a/arch/arm/boards/at91sam9m10g45ek/env/config +++ b/arch/arm/boards/at91sam9m10g45ek/env/config @@ -10,8 +10,8 @@ #eth0.gateway=a.b.c.d #eth0.serverip=a.b.c.d -# can be either 'net' or 'nand' -kernel_loc=net +# can be either 'nfs', 'tftp' or 'nand' +kernel_loc=tftp # can be either 'net', 'nand' or 'initrd' rootfs_loc=net diff --git a/arch/arm/boards/chumby_falconwing/falconwing.c b/arch/arm/boards/chumby_falconwing/falconwing.c index d46431c..15ca11b 100644 --- a/arch/arm/boards/chumby_falconwing/falconwing.c +++ b/arch/arm/boards/chumby_falconwing/falconwing.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -46,13 +47,13 @@ .platform_data = &ram_pdata, }; -static struct stm_mci_platform_data mci_pdata = { +static struct mxs_mci_platform_data mci_pdata = { .caps = MMC_MODE_4BIT | MMC_MODE_HS | MMC_MODE_HS_52MHz, .voltages = MMC_VDD_32_33 | MMC_VDD_33_34, /* fixed to 3.3 V */ }; static struct device_d mci_dev = { - .name = "stm_mci", + .name = "mxs_mci", .map_base = IMX_SSP1_BASE, .platform_data = &mci_pdata, }; @@ -98,12 +99,16 @@ .flag = 0, }; +#define MAX_FB_SIZE SZ_1M + static struct imx_fb_platformdata fb_mode = { .mode_list = &falconwing_vmode, .mode_cnt = 1, /* the NMA35 is a 24 bit display, but only 18 bits are connected */ .ld_intf_width = STMLCDIF_18BIT, .enable = chumby_fb_enable, + .fixed_screen = (void *)(0x40000000 + SZ_64M - MAX_FB_SIZE), + .fixed_screen_size = MAX_FB_SIZE, }; static struct device_d ldcif_dev = { @@ -292,11 +297,6 @@ setup_dma_coherent(0x10000000); -#if TEXT_BASE & (0x100000 - 1) -#warning cannot create vector section. Adjust TEXT_BASE to a 1M boundary -#else - arm_create_section(0x0, TEXT_BASE, 1, PMD_SECT_DEF_UNCACHED); -#endif mmu_enable(); return 0; diff --git a/arch/arm/boards/eukrea_cpuimx25/env/config b/arch/arm/boards/eukrea_cpuimx25/env/config index 927010c..5cedbf8 100644 --- a/arch/arm/boards/eukrea_cpuimx25/env/config +++ b/arch/arm/boards/eukrea_cpuimx25/env/config @@ -15,7 +15,7 @@ #eth0.gateway=a.b.c.d #eth0.serverip=a.b.c.d -# can be either 'net' or 'nand' +# can be either 'nfs', 'tftp' or 'nand' kernel_loc=nand # can be either 'net', 'nand' or 'initrd' rootfs_loc=nand diff --git a/arch/arm/boards/eukrea_cpuimx27/eukrea_cpuimx27.c b/arch/arm/boards/eukrea_cpuimx27/eukrea_cpuimx27.c index 4567cba..a7e9951 100644 --- a/arch/arm/boards/eukrea_cpuimx27/eukrea_cpuimx27.c +++ b/arch/arm/boards/eukrea_cpuimx27/eukrea_cpuimx27.c @@ -153,11 +153,6 @@ setup_dma_coherent(0x10000000); -#if TEXT_BASE & (0x100000 - 1) -#warning cannot create vector section. Adjust TEXT_BASE to a 1M boundary -#else - arm_create_section(0x0, TEXT_BASE, 1, PMD_SECT_DEF_UNCACHED); -#endif mmu_enable(); } #else diff --git a/arch/arm/boards/eukrea_cpuimx35/env/config b/arch/arm/boards/eukrea_cpuimx35/env/config index 6ed6b24..776d19a 100644 --- a/arch/arm/boards/eukrea_cpuimx35/env/config +++ b/arch/arm/boards/eukrea_cpuimx35/env/config @@ -15,7 +15,7 @@ #eth0.gateway=a.b.c.d #eth0.serverip=a.b.c.d -# can be either 'net' or 'nand' +# can be either 'nfs', 'tftp' or 'nand' kernel_loc=nand # can be either 'net', 'nand' or 'initrd' rootfs_loc=nand diff --git a/arch/arm/boards/eukrea_cpuimx35/eukrea_cpuimx35.c b/arch/arm/boards/eukrea_cpuimx35/eukrea_cpuimx35.c index f377793..73bb2e1 100644 --- a/arch/arm/boards/eukrea_cpuimx35/eukrea_cpuimx35.c +++ b/arch/arm/boards/eukrea_cpuimx35/eukrea_cpuimx35.c @@ -161,11 +161,6 @@ setup_dma_coherent(0x10000000); -#if TEXT_BASE & (0x100000 - 1) -#warning cannot create vector section. Adjust TEXT_BASE to a 1M boundary -#else - arm_create_section(0x0, TEXT_BASE, 1, PMD_SECT_DEF_UNCACHED); -#endif mmu_enable(); #ifdef CONFIG_CACHE_L2X0 diff --git a/arch/arm/boards/eukrea_cpuimx51/env/config b/arch/arm/boards/eukrea_cpuimx51/env/config index 51fcdde..737f8e3 100644 --- a/arch/arm/boards/eukrea_cpuimx51/env/config +++ b/arch/arm/boards/eukrea_cpuimx51/env/config @@ -18,7 +18,7 @@ #eth0.gateway=a.b.c.d #eth0.serverip=a.b.c.d -# can be either 'net' or 'nand' +# can be either 'nfs', 'tftp' or 'nand' kernel_loc=nand # can be either 'net', 'nand' or 'initrd' rootfs_loc=nand diff --git a/arch/arm/boards/freescale-mx35-3-stack/env/config b/arch/arm/boards/freescale-mx35-3-stack/env/config index df01d42..ee9bd07 100644 --- a/arch/arm/boards/freescale-mx35-3-stack/env/config +++ b/arch/arm/boards/freescale-mx35-3-stack/env/config @@ -14,8 +14,8 @@ #eth0.gateway=a.b.c.d #eth0.serverip=a.b.c.d -# can be either 'net', 'nor' or 'nand' -kernel_loc=net +# can be either 'nfs', 'tftp', 'nor' or 'nand' +kernel_loc=tftp # can be either 'net', 'nor', 'nand' or 'initrd' rootfs_loc=net diff --git a/arch/arm/boards/freescale-mx51-pdk/board.c b/arch/arm/boards/freescale-mx51-pdk/board.c index ff779ca..35d6153 100644 --- a/arch/arm/boards/freescale-mx51-pdk/board.c +++ b/arch/arm/boards/freescale-mx51-pdk/board.c @@ -96,12 +96,6 @@ setup_dma_coherent(0x20000000); -#if TEXT_BASE & (0x100000 - 1) -#warning cannot create vector section. Adjust TEXT_BASE to a 1M boundary -#else - arm_create_section(0x0, TEXT_BASE, 1, PMD_SECT_DEF_UNCACHED); -#endif - mmu_enable(); } #else diff --git a/arch/arm/boards/freescale-mx51-pdk/env/config b/arch/arm/boards/freescale-mx51-pdk/env/config index d9b8407..8e6b34e 100644 --- a/arch/arm/boards/freescale-mx51-pdk/env/config +++ b/arch/arm/boards/freescale-mx51-pdk/env/config @@ -14,8 +14,8 @@ #eth0.gateway=a.b.c.d #eth0.serverip=a.b.c.d -# can be either 'net', 'nor' or 'nand' -kernel_loc=net +# can be either 'nfs', 'tftp', 'nor' or 'nand' +kernel_loc=tftp # can be either 'net', 'nor', 'nand' or 'initrd' rootfs_loc=net diff --git a/arch/arm/boards/guf-cupid/board.c b/arch/arm/boards/guf-cupid/board.c index e30f8e5..d04af78 100644 --- a/arch/arm/boards/guf-cupid/board.c +++ b/arch/arm/boards/guf-cupid/board.c @@ -145,12 +145,6 @@ setup_dma_coherent(0x10000000); -#if TEXT_BASE & (0x100000 - 1) -#warning cannot create vector section. Adjust TEXT_BASE to a 1M boundary -#else - arm_create_section(0x0, TEXT_BASE, 1, PMD_SECT_DEF_UNCACHED); -#endif - mmu_enable(); #ifdef CONFIG_CACHE_L2X0 diff --git a/arch/arm/boards/guf-cupid/env/config b/arch/arm/boards/guf-cupid/env/config index 4db05b6..cd11eb1 100644 --- a/arch/arm/boards/guf-cupid/env/config +++ b/arch/arm/boards/guf-cupid/env/config @@ -14,8 +14,8 @@ #eth0.gateway=a.b.c.d #eth0.serverip=a.b.c.d -# can be either 'net', 'nor' or 'nand' -kernel_loc=net +# can be either 'nfs', 'tftp', 'nor' or 'nand' +kernel_loc=tftp # can be either 'net', 'nor', 'nand' or 'initrd' rootfs_loc=net diff --git a/arch/arm/boards/guf-neso/board.c b/arch/arm/boards/guf-neso/board.c index d371dd6..c4b2fa1 100644 --- a/arch/arm/boards/guf-neso/board.c +++ b/arch/arm/boards/guf-neso/board.c @@ -167,11 +167,6 @@ setup_dma_coherent(0x10000000); -#if TEXT_BASE & (0x100000 - 1) -#warning cannot create vector section. Adjust TEXT_BASE to a 1M boundary -#else - arm_create_section(0x0, TEXT_BASE, 1, PMD_SECT_DEF_UNCACHED); -#endif mmu_enable(); } #else diff --git a/arch/arm/boards/guf-neso/env/config b/arch/arm/boards/guf-neso/env/config index 6327e69..162488f 100644 --- a/arch/arm/boards/guf-neso/env/config +++ b/arch/arm/boards/guf-neso/env/config @@ -14,8 +14,8 @@ #eth0.gateway=a.b.c.d #eth0.serverip=a.b.c.d -# can be either 'net', 'nor' or 'nand' -kernel_loc=net +# can be either 'nfs', 'tftp', 'nor' or 'nand' +kernel_loc=tftp # can be either 'net', 'nor', 'nand' or 'initrd' rootfs_loc=net diff --git a/arch/arm/boards/karo-tx25/env/config b/arch/arm/boards/karo-tx25/env/config index e4ff756..9113a87 100644 --- a/arch/arm/boards/karo-tx25/env/config +++ b/arch/arm/boards/karo-tx25/env/config @@ -14,8 +14,8 @@ #eth0.serverip=a.b.c.d #eth0.gateway=a.b.c.d -# can be either 'net' -kernel_loc=net +# can be either 'nfs' or 'tftp' +kernel_loc=tftp # can be either 'net' or 'initrd' rootfs_loc=net diff --git a/arch/arm/boards/karo-tx28/env/config b/arch/arm/boards/karo-tx28/env/config index 9b302b8..fdf57ea 100644 --- a/arch/arm/boards/karo-tx28/env/config +++ b/arch/arm/boards/karo-tx28/env/config @@ -15,8 +15,8 @@ #eth0.serverip=a.b.c.d #eth0.gateway=a.b.c.d -# can be either 'net' -kernel_loc=net +# can be either 'nfs' or 'tftp' +kernel_loc=tftp # can be either 'net' or 'initrd' rootfs_loc=net diff --git a/arch/arm/boards/karo-tx28/tx28-stk5.c b/arch/arm/boards/karo-tx28/tx28-stk5.c index 9258442..81cb80c 100644 --- a/arch/arm/boards/karo-tx28/tx28-stk5.c +++ b/arch/arm/boards/karo-tx28/tx28-stk5.c @@ -28,14 +28,15 @@ #include #include -static struct stm_mci_platform_data mci_pdata = { - .caps = MMC_MODE_4BIT | MMC_MODE_HS | MMC_MODE_HS_52MHz, +static struct mxs_mci_platform_data mci_pdata = { + .caps = MMC_MODE_4BIT, .voltages = MMC_VDD_32_33 | MMC_VDD_33_34, /* fixed to 3.3 V */ .f_min = 400 * 1000, + .f_max = 25000000, }; static struct device_d mci_socket = { - .name = "stm_mci", + .name = "mxs_mci", .map_base = IMX_SSP0_BASE, .platform_data = &mci_pdata, }; diff --git a/arch/arm/boards/karo-tx28/tx28.c b/arch/arm/boards/karo-tx28/tx28.c index 5692171..1f47a8d 100644 --- a/arch/arm/boards/karo-tx28/tx28.c +++ b/arch/arm/boards/karo-tx28/tx28.c @@ -93,11 +93,6 @@ setup_dma_coherent(0x10000000); -#if TEXT_BASE & (0x100000 - 1) -#warning cannot create vector section. Adjust TEXT_BASE to a 1M boundary -#else - arm_create_section(0x0, TEXT_BASE, 1, PMD_SECT_DEF_UNCACHED); -#endif mmu_enable(); return 0; diff --git a/arch/arm/boards/mini2440/env/config b/arch/arm/boards/mini2440/env/config index b24877e..ff6f1ea 100644 --- a/arch/arm/boards/mini2440/env/config +++ b/arch/arm/boards/mini2440/env/config @@ -14,8 +14,8 @@ #eth0.gateway=a.b.c.d #eth0.serverip=a.b.c.d -# can be either 'net', or 'nand' -kernel_loc=net +# can be either 'nfs', 'tftp' or 'nand' +kernel_loc=tftp # can be either 'net', 'nand' or 'initrd' rootfs_loc=net diff --git a/arch/arm/boards/mini2440/mini2440.c b/arch/arm/boards/mini2440/mini2440.c index ab309a0..448aa40 100644 --- a/arch/arm/boards/mini2440/mini2440.c +++ b/arch/arm/boards/mini2440/mini2440.c @@ -281,7 +281,7 @@ #ifdef CONFIG_S3C24XX_NAND_BOOT void __bare_init nand_boot(void) { - s3c24x0_nand_load_image((void *)TEXT_BASE, 256 * 1024, 0, 512); + s3c24x0_nand_load_image((void *)TEXT_BASE, 256 * 1024, 0); } #endif diff --git a/arch/arm/boards/nhk8815/env/config b/arch/arm/boards/nhk8815/env/config index e657a76..7428c43 100644 --- a/arch/arm/boards/nhk8815/env/config +++ b/arch/arm/boards/nhk8815/env/config @@ -10,8 +10,8 @@ #eth0.gateway=a.b.c.d #eth0.serverip=a.b.c.d -# can be either 'net' or 'nand' -kernel_loc=net +# can be either 'nfs', 'tftp' or 'nand' +kernel_loc=tftp # can be either 'net', 'nand' or 'initrd' rootfs_loc=net diff --git a/arch/arm/boards/pcm037/env/config b/arch/arm/boards/pcm037/env/config index df2f694..3748cc4 100644 --- a/arch/arm/boards/pcm037/env/config +++ b/arch/arm/boards/pcm037/env/config @@ -14,8 +14,8 @@ #eth0.gateway=a.b.c.d #eth0.serverip=a.b.c.d -# can be either 'net', 'nor' or 'nand' -kernel_loc=net +# can be either 'nfs', 'tftp', nor' or 'nand' +kernel_loc=tftp # can be either 'net', 'nor', 'nand' or 'initrd' rootfs_loc=net diff --git a/arch/arm/boards/pcm037/pcm037.c b/arch/arm/boards/pcm037/pcm037.c index ffecec2..cb4ffe6 100644 --- a/arch/arm/boards/pcm037/pcm037.c +++ b/arch/arm/boards/pcm037/pcm037.c @@ -239,11 +239,6 @@ setup_dma_coherent(0x10000000); -#if TEXT_BASE & (0x100000 - 1) -#warning cannot create vector section. Adjust TEXT_BASE to a 1M boundary -#else - arm_create_section(0x0, TEXT_BASE, 1, PMD_SECT_DEF_UNCACHED); -#endif mmu_enable(); #ifdef CONFIG_CACHE_L2X0 diff --git a/arch/arm/boards/pcm038/env/config b/arch/arm/boards/pcm038/env/config index a8be5c9..9e28f5d 100644 --- a/arch/arm/boards/pcm038/env/config +++ b/arch/arm/boards/pcm038/env/config @@ -14,8 +14,8 @@ #eth0.gateway=a.b.c.d #eth0.serverip=a.b.c.d -# can be either 'net', 'nor' or 'nand' -kernel_loc=net +# can be either 'nfs', 'tftp', 'nor' or 'nand' +kernel_loc=tftp # can be either 'net', 'nor', 'nand' or 'initrd' rootfs_loc=net diff --git a/arch/arm/boards/pcm038/pcm038.c b/arch/arm/boards/pcm038/pcm038.c index 1dbc6b6..3ca6650 100644 --- a/arch/arm/boards/pcm038/pcm038.c +++ b/arch/arm/boards/pcm038/pcm038.c @@ -179,11 +179,6 @@ setup_dma_coherent(0x10000000); -#if TEXT_BASE & (0x100000 - 1) -#warning cannot create vector section. Adjust TEXT_BASE to a 1M boundary -#else - arm_create_section(0x0, TEXT_BASE, 1, PMD_SECT_DEF_UNCACHED); -#endif mmu_enable(); } #else diff --git a/arch/arm/boards/pcm043/env/config b/arch/arm/boards/pcm043/env/config index 212b6a9..e7f94f8 100644 --- a/arch/arm/boards/pcm043/env/config +++ b/arch/arm/boards/pcm043/env/config @@ -14,8 +14,8 @@ #eth0.gateway=a.b.c.d #eth0.serverip=a.b.c.d -# can be either 'net', 'nor' or 'nand' -kernel_loc=net +# can be either 'nfs', 'tftp', 'nor' or 'nand' +kernel_loc=tftp # can be either 'net', 'nor', 'nand' or 'initrd' rootfs_loc=net diff --git a/arch/arm/boards/pcm043/pcm043.c b/arch/arm/boards/pcm043/pcm043.c index 36bde45..7db3c83 100644 --- a/arch/arm/boards/pcm043/pcm043.c +++ b/arch/arm/boards/pcm043/pcm043.c @@ -133,12 +133,6 @@ setup_dma_coherent(0x10000000); -#if TEXT_BASE & (0x100000 - 1) -#warning cannot create vector section. Adjust TEXT_BASE to a 1M boundary -#else - arm_create_section(0x0, TEXT_BASE, 1, PMD_SECT_DEF_UNCACHED); -#endif - mmu_enable(); #ifdef CONFIG_CACHE_L2X0 diff --git a/arch/arm/boards/phycard-i.MX27/env/config b/arch/arm/boards/phycard-i.MX27/env/config index d0670de..0e20b48 100644 --- a/arch/arm/boards/phycard-i.MX27/env/config +++ b/arch/arm/boards/phycard-i.MX27/env/config @@ -14,8 +14,8 @@ #eth0.gateway=a.b.c.d #eth0.serverip=a.b.c.d -# can be either 'net', 'nor' or 'nand' -kernel_loc=net +# can be either 'nfs', 'tftp', 'nor' or 'nand' +kernel_loc=tftp # can be either 'net', 'nor', 'nand' or 'initrd' rootfs_loc=net diff --git a/arch/arm/boards/phycard-i.MX27/pca100.c b/arch/arm/boards/phycard-i.MX27/pca100.c index c539ea1..89c0a14 100644 --- a/arch/arm/boards/phycard-i.MX27/pca100.c +++ b/arch/arm/boards/phycard-i.MX27/pca100.c @@ -106,11 +106,6 @@ setup_dma_coherent(0x10000000); -#if TEXT_BASE & (0x100000 - 1) -#warning cannot create vector section. Adjust TEXT_BASE to a 1M boundary -#else - arm_create_section(0x0, TEXT_BASE, 1, PMD_SECT_DEF_UNCACHED); -#endif mmu_enable(); } #else diff --git a/arch/arm/boards/pm9261/env/config b/arch/arm/boards/pm9261/env/config index f7e133e..7933379 100644 --- a/arch/arm/boards/pm9261/env/config +++ b/arch/arm/boards/pm9261/env/config @@ -10,8 +10,8 @@ #eth0.gateway=a.b.c.d #eth0.serverip=a.b.c.d -# can be either 'net' or 'nand' -kernel_loc=net +# can be either 'nfs', 'tftp' or 'nand' +kernel_loc=tftp # can be either 'net', 'nand' or 'initrd' rootfs_loc=net diff --git a/arch/arm/boards/pm9g45/env/config b/arch/arm/boards/pm9g45/env/config index 9fcf465..b8ca18d 100644 --- a/arch/arm/boards/pm9g45/env/config +++ b/arch/arm/boards/pm9g45/env/config @@ -10,8 +10,8 @@ #eth0.gateway=a.b.c.d #eth0.serverip=a.b.c.d -# can be either 'net' or 'nand' -kernel_loc=net +# can be either 'nfs', 'tftp' or 'nand' +kernel_loc=tftp # can be either 'net', 'nand' or 'initrd' rootfs_loc=net diff --git a/arch/arm/boards/scb9328/scb9328.c b/arch/arm/boards/scb9328/scb9328.c index 35c7fdf..a98d9fe 100644 --- a/arch/arm/boards/scb9328/scb9328.c +++ b/arch/arm/boards/scb9328/scb9328.c @@ -31,6 +31,7 @@ #include #include #include +#include static struct device_d cfi_dev = { .id = -1, @@ -68,9 +69,30 @@ .platform_data = &dm9000_data, }; -static int scb9328_devices_init(void) { +struct gpio_led leds[] = { + { + .gpio = 32 + 21, + }, { + .gpio = 32 + 22, + }, { + .gpio = 32 + 23, + }, { + .gpio = 32 + 24, + }, +}; + +static int scb9328_devices_init(void) +{ + int i; imx_gpio_mode(PA23_PF_CS5); + imx_gpio_mode(GPIO_PORTB | GPIO_GPIO | GPIO_OUT | 21); + imx_gpio_mode(GPIO_PORTB | GPIO_GPIO | GPIO_OUT | 22); + imx_gpio_mode(GPIO_PORTB | GPIO_GPIO | GPIO_OUT | 23); + imx_gpio_mode(GPIO_PORTB | GPIO_GPIO | GPIO_OUT | 24); + + for (i = 0; i < ARRAY_SIZE(leds); i++) + led_gpio_register(&leds[i]); /* CS3 becomes CS3 by clearing reset default bit 1 in FMCR */ FMCR = 0x1; diff --git a/arch/arm/boards/versatile/env/config b/arch/arm/boards/versatile/env/config index 9dec3f2..9c5ce61 100644 --- a/arch/arm/boards/versatile/env/config +++ b/arch/arm/boards/versatile/env/config @@ -10,8 +10,8 @@ #eth0.gateway=a.b.c.d #eth0.serverip=a.b.c.d -# can be either 'net' or 'nor' -kernel_loc=net +# can be either 'nfs', 'tftp' or 'nor' +kernel_loc=tftp # can be either 'net', 'nor' or 'initrd' rootfs_loc=initrd diff --git a/arch/arm/cpu/interrupts.c b/arch/arm/cpu/interrupts.c index 4a0b3f8..5168921 100644 --- a/arch/arm/cpu/interrupts.c +++ b/arch/arm/cpu/interrupts.c @@ -27,6 +27,7 @@ #include #include +#include void do_undefined_instruction (struct pt_regs *pt_regs); void do_software_interrupt (struct pt_regs *pt_regs); @@ -115,6 +116,9 @@ fast_interrupts_enabled (regs) ? "on" : "off", processor_modes[processor_mode (regs)], thumb_mode (regs) ? " (T)" : ""); +#ifdef CONFIG_ARM_UNWIND + unwind_backtrace(regs); +#endif } /** diff --git a/arch/arm/cpu/mmu.c b/arch/arm/cpu/mmu.c index 7b5686b..8465d1a 100644 --- a/arch/arm/cpu/mmu.c +++ b/arch/arm/cpu/mmu.c @@ -24,6 +24,52 @@ } /* + * Create a second level translation table for the given virtual address. + * We initially create a flat uncached mapping on it. + * Not yet exported, but may be later if someone finds use for it. + */ +static u32 *arm_create_pte(unsigned long virt) +{ + u32 *table; + int i; + + table = memalign(0x400, 0x400); + + ttb[virt] = (unsigned long)table | PMD_TYPE_TABLE; + + for (i = 0; i < 256; i++) + table[i] = virt | PTE_TYPE_SMALL | PTE_SMALL_AP_UNO_SRW; + + return table; +} + +/* + * We have 8 exception vectors and the table consists of absolute + * jumps, so we need 8 * 4 bytes for the instructions and another + * 8 * 4 bytes for the addresses. + */ +#define ARM_VECTORS_SIZE (sizeof(u32) * 8 * 2) + +/* + * Allocate a page, map it to the zero page and copy our exception + * vectors there. + */ +static void vectors_init(void) +{ + u32 *exc; + void *vectors; + extern unsigned long exception_vectors; + + exc = arm_create_pte(0x0); + + vectors = xmemalign(PAGE_SIZE, PAGE_SIZE); + memset(vectors, 0, PAGE_SIZE); + memcpy(vectors, &exception_vectors, ARM_VECTORS_SIZE); + + exc[0] = (u32)vectors | PTE_TYPE_SMALL | PTE_SMALL_AP_UNO_SRW; +} + +/* * Prepare MMU for usage and create a flat mapping. Board * code is responsible to remap the SDRAM cached */ @@ -42,6 +88,8 @@ /* create a flat mapping */ arm_create_section(0, 0, 4096, PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | PMD_TYPE_SECT); + + vectors_init(); } /* diff --git a/arch/arm/include/asm/stacktrace.h b/arch/arm/include/asm/stacktrace.h new file mode 100644 index 0000000..10f70e1 --- /dev/null +++ b/arch/arm/include/asm/stacktrace.h @@ -0,0 +1,16 @@ +#ifndef __ASM_STACKTRACE_H +#define __ASM_STACKTRACE_H + +struct stackframe { + unsigned long fp; + unsigned long sp; + unsigned long lr; + unsigned long pc; +}; + +extern int unwind_frame(struct stackframe *frame); +extern void walk_stackframe(struct stackframe *frame, + int (*fn)(struct stackframe *, void *), void *data); + +#endif /* __ASM_STACKTRACE_H */ + diff --git a/arch/arm/include/asm/unwind.h b/arch/arm/include/asm/unwind.h new file mode 100644 index 0000000..1bc2a7c --- /dev/null +++ b/arch/arm/include/asm/unwind.h @@ -0,0 +1,54 @@ +/* + * arch/arm/include/asm/unwind.h + * + * Copyright (C) 2008 ARM Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ASM_UNWIND_H +#define __ASM_UNWIND_H + +#ifndef __ASSEMBLY__ + +/* Unwind reason code according the the ARM EABI documents */ +enum unwind_reason_code { + URC_OK = 0, /* operation completed successfully */ + URC_CONTINUE_UNWIND = 8, + URC_FAILURE = 9 /* unspecified failure of some kind */ +}; + +struct unwind_idx { + unsigned long addr; + unsigned long insn; +}; + +struct unwind_table { + struct list_head list; + struct unwind_idx *start; + struct unwind_idx *stop; + unsigned long begin_addr; + unsigned long end_addr; +}; + +extern struct unwind_table *unwind_table_add(unsigned long start, + unsigned long size, + unsigned long text_addr, + unsigned long text_size); +extern void unwind_table_del(struct unwind_table *tab); +extern void unwind_backtrace(struct pt_regs *regs); + +#endif /* !__ASSEMBLY__ */ + +#endif /* __ASM_UNWIND_H */ diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile index 89cb72b..3a01083 100644 --- a/arch/arm/lib/Makefile +++ b/arch/arm/lib/Makefile @@ -14,7 +14,7 @@ obj-y += lshrdi3.o obj-$(CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS) += memcpy.o obj-$(CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS) += memset.o - +obj-$(CONFIG_ARM_UNWIND) += unwind.o obj-$(CONFIG_MODULES) += module.o extra-$(CONFIG_GENERIC_LINKER_SCRIPT) += barebox.lds diff --git a/arch/arm/lib/barebox.lds.S b/arch/arm/lib/barebox.lds.S index cc74b2f..7683f73 100644 --- a/arch/arm/lib/barebox.lds.S +++ b/arch/arm/lib/barebox.lds.S @@ -51,6 +51,22 @@ . = ALIGN(4); .rodata : { *(.rodata*) } +#ifdef CONFIG_ARM_UNWIND + /* + * Stack unwinding tables + */ + . = ALIGN(8); + .ARM.unwind_idx : { + __start_unwind_idx = .; + *(.ARM.exidx*) + __stop_unwind_idx = .; + } + .ARM.unwind_tab : { + __start_unwind_tab = .; + *(.ARM.extab*) + __stop_unwind_tab = .; + } +#endif _etext = .; /* End of text and rodata section */ . = ALIGN(4); diff --git a/arch/arm/lib/unwind.c b/arch/arm/lib/unwind.c new file mode 100644 index 0000000..62d26af --- /dev/null +++ b/arch/arm/lib/unwind.c @@ -0,0 +1,344 @@ +#include +#include +#include +#include +#include + +/* Dummy functions to avoid linker complaints */ +void __aeabi_unwind_cpp_pr0(void) +{ +}; +EXPORT_SYMBOL(__aeabi_unwind_cpp_pr0); + +void __aeabi_unwind_cpp_pr1(void) +{ +}; +EXPORT_SYMBOL(__aeabi_unwind_cpp_pr1); + +void __aeabi_unwind_cpp_pr2(void) +{ +}; +EXPORT_SYMBOL(__aeabi_unwind_cpp_pr2); + +struct unwind_ctrl_block { + unsigned long vrs[16]; /* virtual register set */ + unsigned long *insn; /* pointer to the current instructions word */ + int entries; /* number of entries left to interpret */ + int byte; /* current byte number in the instructions word */ +}; + +enum regs { + FP = 11, + SP = 13, + LR = 14, + PC = 15 +}; + +#define THREAD_SIZE 8192 + +extern struct unwind_idx __start_unwind_idx[]; +extern struct unwind_idx __stop_unwind_idx[]; + +/* Convert a prel31 symbol to an absolute address */ +#define prel31_to_addr(ptr) \ +({ \ + /* sign-extend to 32 bits */ \ + long offset = (((long)*(ptr)) << 1) >> 1; \ + (unsigned long)(ptr) + offset; \ +}) + +static inline int is_kernel_text(unsigned long addr) +{ + if ((addr >= (unsigned long)_stext && addr <= (unsigned long)_etext)) + return 1; + return 0; +} + +void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame) +{ +#ifdef CONFIG_KALLSYMS + printk("[<%08lx>] (%pS) from [<%08lx>] (%pS)\n", where, (void *)where, from, (void *)from); +#else + printk("Function entered at [<%08lx>] from [<%08lx>]\n", where, from); +#endif +} + +/* + * Binary search in the unwind index. The entries entries are + * guaranteed to be sorted in ascending order by the linker. + */ +static struct unwind_idx *search_index(unsigned long addr, + struct unwind_idx *first, + struct unwind_idx *last) +{ + pr_debug("%s(%08lx, %p, %p)\n", __func__, addr, first, last); + + if (addr < first->addr) { + pr_warning("unwind: Unknown symbol address %08lx\n", addr); + return NULL; + } else if (addr >= last->addr) + return last; + + while (first < last - 1) { + struct unwind_idx *mid = first + ((last - first + 1) >> 1); + + if (addr < mid->addr) + last = mid; + else + first = mid; + } + + return first; +} + +static struct unwind_idx *unwind_find_idx(unsigned long addr) +{ + struct unwind_idx *idx = NULL; + + pr_debug("%s(%08lx)\n", __func__, addr); + + if (is_kernel_text(addr)) + /* main unwind table */ + idx = search_index(addr, __start_unwind_idx, + __stop_unwind_idx - 1); + else { + /* module unwinding not supported */ + } + + pr_debug("%s: idx = %p\n", __func__, idx); + return idx; +} + +static unsigned long unwind_get_byte(struct unwind_ctrl_block *ctrl) +{ + unsigned long ret; + + if (ctrl->entries <= 0) { + pr_warning("unwind: Corrupt unwind table\n"); + return 0; + } + + ret = (*ctrl->insn >> (ctrl->byte * 8)) & 0xff; + + if (ctrl->byte == 0) { + ctrl->insn++; + ctrl->entries--; + ctrl->byte = 3; + } else + ctrl->byte--; + + return ret; +} + +/* + * Execute the current unwind instruction. + */ +static int unwind_exec_insn(struct unwind_ctrl_block *ctrl) +{ + unsigned long insn = unwind_get_byte(ctrl); + + pr_debug("%s: insn = %08lx\n", __func__, insn); + + if ((insn & 0xc0) == 0x00) + ctrl->vrs[SP] += ((insn & 0x3f) << 2) + 4; + else if ((insn & 0xc0) == 0x40) + ctrl->vrs[SP] -= ((insn & 0x3f) << 2) + 4; + else if ((insn & 0xf0) == 0x80) { + unsigned long mask; + unsigned long *vsp = (unsigned long *)ctrl->vrs[SP]; + int load_sp, reg = 4; + + insn = (insn << 8) | unwind_get_byte(ctrl); + mask = insn & 0x0fff; + if (mask == 0) { + pr_warning("unwind: 'Refuse to unwind' instruction %04lx\n", + insn); + return -URC_FAILURE; + } + + /* pop R4-R15 according to mask */ + load_sp = mask & (1 << (13 - 4)); + while (mask) { + if (mask & 1) + ctrl->vrs[reg] = *vsp++; + mask >>= 1; + reg++; + } + if (!load_sp) + ctrl->vrs[SP] = (unsigned long)vsp; + } else if ((insn & 0xf0) == 0x90 && + (insn & 0x0d) != 0x0d) + ctrl->vrs[SP] = ctrl->vrs[insn & 0x0f]; + else if ((insn & 0xf0) == 0xa0) { + unsigned long *vsp = (unsigned long *)ctrl->vrs[SP]; + int reg; + + /* pop R4-R[4+bbb] */ + for (reg = 4; reg <= 4 + (insn & 7); reg++) + ctrl->vrs[reg] = *vsp++; + if (insn & 0x80) + ctrl->vrs[14] = *vsp++; + ctrl->vrs[SP] = (unsigned long)vsp; + } else if (insn == 0xb0) { + if (ctrl->vrs[PC] == 0) + ctrl->vrs[PC] = ctrl->vrs[LR]; + /* no further processing */ + ctrl->entries = 0; + } else if (insn == 0xb1) { + unsigned long mask = unwind_get_byte(ctrl); + unsigned long *vsp = (unsigned long *)ctrl->vrs[SP]; + int reg = 0; + + if (mask == 0 || mask & 0xf0) { + pr_warning("unwind: Spare encoding %04lx\n", + (insn << 8) | mask); + return -URC_FAILURE; + } + + /* pop R0-R3 according to mask */ + while (mask) { + if (mask & 1) + ctrl->vrs[reg] = *vsp++; + mask >>= 1; + reg++; + } + ctrl->vrs[SP] = (unsigned long)vsp; + } else if (insn == 0xb2) { + unsigned long uleb128 = unwind_get_byte(ctrl); + + ctrl->vrs[SP] += 0x204 + (uleb128 << 2); + } else { + pr_warning("unwind: Unhandled instruction %02lx\n", insn); + return -URC_FAILURE; + } + + pr_debug("%s: fp = %08lx sp = %08lx lr = %08lx pc = %08lx\n", __func__, + ctrl->vrs[FP], ctrl->vrs[SP], ctrl->vrs[LR], ctrl->vrs[PC]); + + return URC_OK; +} + +/* + * Unwind a single frame starting with *sp for the symbol at *pc. It + * updates the *pc and *sp with the new values. + */ +int unwind_frame(struct stackframe *frame) +{ + unsigned long high, low; + struct unwind_idx *idx; + struct unwind_ctrl_block ctrl; + + /* only go to a higher address on the stack */ + low = frame->sp; + high = ALIGN(low, THREAD_SIZE); + + pr_debug("%s(pc = %08lx lr = %08lx sp = %08lx)\n", __func__, + frame->pc, frame->lr, frame->sp); + + if (!is_kernel_text(frame->pc)) + return -URC_FAILURE; + + idx = unwind_find_idx(frame->pc); + if (!idx) { + pr_warning("unwind: Index not found %08lx\n", frame->pc); + return -URC_FAILURE; + } + + ctrl.vrs[FP] = frame->fp; + ctrl.vrs[SP] = frame->sp; + ctrl.vrs[LR] = frame->lr; + ctrl.vrs[PC] = 0; + + if (idx->insn == 1) + /* can't unwind */ + return -URC_FAILURE; + else if ((idx->insn & 0x80000000) == 0) + /* prel31 to the unwind table */ + ctrl.insn = (unsigned long *)prel31_to_addr(&idx->insn); + else if ((idx->insn & 0xff000000) == 0x80000000) + /* only personality routine 0 supported in the index */ + ctrl.insn = &idx->insn; + else { + pr_warning("unwind: Unsupported personality routine %08lx in the index at %p\n", + idx->insn, idx); + return -URC_FAILURE; + } + + /* check the personality routine */ + if ((*ctrl.insn & 0xff000000) == 0x80000000) { + ctrl.byte = 2; + ctrl.entries = 1; + } else if ((*ctrl.insn & 0xff000000) == 0x81000000) { + ctrl.byte = 1; + ctrl.entries = 1 + ((*ctrl.insn & 0x00ff0000) >> 16); + } else { + pr_warning("unwind: Unsupported personality routine %08lx at %p\n", + *ctrl.insn, ctrl.insn); + return -URC_FAILURE; + } + + while (ctrl.entries > 0) { + int urc = unwind_exec_insn(&ctrl); + if (urc < 0) + return urc; + if (ctrl.vrs[SP] < low || ctrl.vrs[SP] >= high) + return -URC_FAILURE; + } + + if (ctrl.vrs[PC] == 0) + ctrl.vrs[PC] = ctrl.vrs[LR]; + + /* check for infinite loop */ + if (frame->pc == ctrl.vrs[PC]) + return -URC_FAILURE; + + frame->fp = ctrl.vrs[FP]; + frame->sp = ctrl.vrs[SP]; + frame->lr = ctrl.vrs[LR]; + frame->pc = ctrl.vrs[PC]; + + return URC_OK; +} + +void unwind_backtrace(struct pt_regs *regs) +{ + struct stackframe frame; + register unsigned long current_sp asm ("sp"); + + pr_debug("%s\n", __func__); + + if (regs) { + frame.fp = regs->ARM_fp; + frame.sp = regs->ARM_sp; + frame.lr = regs->ARM_lr; + /* PC might be corrupted, use LR in that case. */ + frame.pc = is_kernel_text(regs->ARM_pc) + ? regs->ARM_pc : regs->ARM_lr; + } else { + frame.sp = current_sp; + frame.lr = (unsigned long)__builtin_return_address(0); + frame.pc = (unsigned long)unwind_backtrace; + } + + while (1) { + int urc; + unsigned long where = frame.pc; + + urc = unwind_frame(&frame); + if (urc < 0) + break; + dump_backtrace_entry(where, frame.pc, frame.sp - 4); + } +} + +static int unwind_init(void) +{ + struct unwind_idx *idx; + + /* Convert the symbol addresses to absolute values */ + for (idx = __start_unwind_idx; idx < __stop_unwind_idx; idx++) + idx->addr = prel31_to_addr(&idx->addr); + + return 0; +} +core_initcall(unwind_init); diff --git a/arch/arm/mach-mxs/include/mach/mci.h b/arch/arm/mach-mxs/include/mach/mci.h index b924908..1090c1a 100644 --- a/arch/arm/mach-mxs/include/mach/mci.h +++ b/arch/arm/mach-mxs/include/mach/mci.h @@ -18,7 +18,7 @@ #ifndef __MACH_MMC_H #define __MACH_MMC_H -struct stm_mci_platform_data { +struct mxs_mci_platform_data { unsigned caps; /**< supported operating modes (MMC_MODE_*) */ unsigned voltages; /**< supported voltage range (MMC_VDD_*) */ unsigned f_min; /**< min operating frequency in Hz (0 -> no limit) */ diff --git a/arch/arm/mach-s3c24xx/include/mach/s3c24x0-nand.h b/arch/arm/mach-s3c24xx/include/mach/s3c24x0-nand.h index d06287e..7610b4e 100644 --- a/arch/arm/mach-s3c24xx/include/mach/s3c24x0-nand.h +++ b/arch/arm/mach-s3c24xx/include/mach/s3c24x0-nand.h @@ -19,7 +19,7 @@ */ #ifdef CONFIG_S3C24XX_NAND_BOOT -extern void s3c24x0_nand_load_image(void*, int, int, int); +extern void s3c24x0_nand_load_image(void*, int, int); #endif /** diff --git a/arch/nios2/Kconfig b/arch/nios2/Kconfig new file mode 100644 index 0000000..b4b0429 --- /dev/null +++ b/arch/nios2/Kconfig @@ -0,0 +1,39 @@ +config NIOS2 + bool + select HAS_KALLSYMS + select HAS_MODULES + select HAVE_CONFIGURABLE_MEMORY_LAYOUT + default y + +config ARCH_TEXT_BASE + hex + default 0x00000000 + +config BOARDINFO + default "Altera Generic Board" if GENERIC + +choice + prompt "Select your board" + +config GENERIC + bool "Generic " + select NIOS2 + + +endchoice + +menu "Board configuration " + +config EARLY_PRINTF + default n + bool "Enable early printf functions" + +endmenu + +source common/Kconfig +source commands/Kconfig +source net/Kconfig +source drivers/Kconfig +source fs/Kconfig +source lib/Kconfig + diff --git a/arch/nios2/Makefile b/arch/nios2/Makefile new file mode 100644 index 0000000..6603da5 --- /dev/null +++ b/arch/nios2/Makefile @@ -0,0 +1,25 @@ +CPPFLAGS += -fno-strict-aliasing + +board-$(CONFIG_GENERIC) := generic + +KALLSYMS += --symbol-prefix=_ + +archprepare: maketools + + @echo " SYMLINK include/nios_sopc.h -> arch/nios2/boards/$(board-y)/nios_sopc.h" + @ln -fsn ../arch/nios2/boards/$(board-y)/nios_sopc.h include/nios_sopc.h + +PHONY += maketools + +ifneq ($(board-y),) +BOARD := arch/nios2/boards/$(board-y)/ +else +BOARD := +endif + +common-y += $(BOARD) +common-y += arch/nios2/lib/ +common-y += arch/nios2/cpu/ + +lds-y += arch/nios2/cpu/barebox.lds + diff --git a/arch/nios2/boards/generic/Makefile b/arch/nios2/boards/generic/Makefile new file mode 100644 index 0000000..d8a3d7f --- /dev/null +++ b/arch/nios2/boards/generic/Makefile @@ -0,0 +1 @@ +obj-y += generic.o diff --git a/arch/nios2/boards/generic/config.h b/arch/nios2/boards/generic/config.h new file mode 100644 index 0000000..4bca902 --- /dev/null +++ b/arch/nios2/boards/generic/config.h @@ -0,0 +1,63 @@ +#ifndef _GENERIC_NAMES_H_ +#define _GENERIC_NAMES_H_ + +#include "nios_sopc.h" + +#ifndef MMU_PRESENT +#define IO_REGION_BASE 0x80000000 +#define KERNEL_REGION_BASE 0x00000000 +#endif + +/*Name of the RAM memory in your SOPC project */ +#define NIOS_SOPC_MEMORY_BASE (KERNEL_REGION_BASE | DDR_SDRAM_BASE) +#define NIOS_SOPC_MEMORY_SIZE DDR_SDRAM_SPAN + +/*Name of the timer in your SOPC project */ +#define NIOS_SOPC_TIMER_BASE (IO_REGION_BASE | SYS_CLK_TIMER_BASE) +#define NIOS_SOPC_TIMER_FREQ SYS_CLK_TIMER_FREQ + +/*Name of TSE and SGDMA in your SOPC project */ +#define NIOS_SOPC_SGDMA_RX_BASE (IO_REGION_BASE | SGDMA_RX_BASE) +#define NIOS_SOPC_SGDMA_TX_BASE (IO_REGION_BASE | SGDMA_TX_BASE) +#define NIOS_SOPC_TSE_BASE (IO_REGION_BASE | TSE_BASE) +#define NIOS_SOPC_TSE_DESC_MEM_BASE (IO_REGION_BASE | DESCRIPTOR_MEMORY_BASE) + +/*Name of the UART in your SOPC project */ +#define NIOS_SOPC_UART_BASE (IO_REGION_BASE | UART_BASE) + +/*Name of the JTAG UART in your SOPC project */ +#define NIOS_SOPC_JTAG_UART_BASE (IO_REGION_BASE | JTAG_UART_BASE) + +/*Name of the CFI flash in your SOPC project */ +#define NIOS_SOPC_FLASH_BASE (IO_REGION_BASE | CFI_FLASH_BASE) +#define NIOS_SOPC_FLASH_SIZE CFI_FLASH_SPAN + +/*Name of the EPCS flash controller in your SOPC project */ + +#define NIOS_SOPC_EPCS_BASE (IO_REGION_BASE | (EPCS_FLASH_CONTROLLER_BASE + EPCS_FLASH_CONTROLLER_REGISTER_OFFSET)) + +/* PHY MDIO Address */ +#define NIOS_SOPC_PHY_ADDR 1 + +/* We reserve 256K for barebox */ +#define BAREBOX_RESERVED_SIZE 0x80000 + +/* Barebox will be at top of main memory */ +#define NIOS_SOPC_TEXT_BASE (NIOS_SOPC_MEMORY_BASE + NIOS_SOPC_MEMORY_SIZE - BAREBOX_RESERVED_SIZE) + +/* +* TEXT_BASE is defined here because STACK_BASE definition +* in include/asm-generic/memory_layout.h uses this name +*/ + +#define TEXT_BASE NIOS_SOPC_TEXT_BASE + +/* Board banner */ + +#define BOARD_BANNER "\ +\033[44;1m***********************************************\e[0m\n\ +\033[44;1m* Altera generic board *\e[0m\n\ +\033[44;1m***********************************************\e[0m\ +\e[0m\n\n" + +#endif diff --git a/arch/nios2/boards/generic/env/config b/arch/nios2/boards/generic/env/config new file mode 100644 index 0000000..df7d09e --- /dev/null +++ b/arch/nios2/boards/generic/env/config @@ -0,0 +1,16 @@ +#!/bin/sh + +# can be either 'net' or 'flash' +kernel=flash +root=flash + +# use 'dhcp' todo dhcp in barebox and in kernel +ip=none + +autoboot_timeout=3 + +nor_parts="256k(barebox),128k(env),4M(kernel),-(rootfs)" + +# set a fancy prompt (if support is compiled in) +PS1="\e[1;33mbarebox@\e[1;32mgeneric:\w\e[0m " + diff --git a/arch/nios2/boards/generic/generic.c b/arch/nios2/boards/generic/generic.c new file mode 100644 index 0000000..99c855d --- /dev/null +++ b/arch/nios2/boards/generic/generic.c @@ -0,0 +1,74 @@ +#include +#include +#include +#include +#include + +static struct device_d cfi_dev = { + .id = -1, + .name = "cfi_flash", + .map_base = NIOS_SOPC_FLASH_BASE, + .size = NIOS_SOPC_FLASH_SIZE, +}; + +static struct device_d mac_dev = { + .id = -1, + .name = "altera_tse", + .map_base = NIOS_SOPC_TSE_BASE, + .size = 0x00000400, +}; + +static struct memory_platform_data ram_pdata = { + .name = "ram0", + .flags = DEVFS_RDWR, +}; + +static struct device_d ram_dev = { + .id = -1, + .name = "mem", + .map_base = NIOS_SOPC_MEMORY_BASE, + .size = NIOS_SOPC_MEMORY_SIZE, + .platform_data = &ram_pdata, +}; + +static struct device_d altera_serial_device = { + .id = -1, + .name = "altera_serial", + .map_base = NIOS_SOPC_UART_BASE, +}; + +/* +static struct device_d epcs_flash_device = { + .id = -1, + .name = "epcs_flash", + .map_base = NIOS_SOPC_EPCS_BASE, +}; +*/ + +static int comBoard_devices_init(void) +{ + register_device(&cfi_dev); + register_device(&ram_dev); + register_device(&mac_dev); + /*register_device(&epcs_flash_device);*/ + + devfs_add_partition("nor0", 0x00000, 0x40000, PARTITION_FIXED, "self0"); + devfs_add_partition("nor0", 0x40000, 0x20000, PARTITION_FIXED, "env0"); + + protect_file("/dev/env0", 1); + + return 0; +} + +device_initcall(comBoard_devices_init); + + +static int altera_console_init(void) +{ + register_device(&altera_serial_device); + + return 0; +} + +console_initcall(altera_console_init); + diff --git a/arch/nios2/boards/generic/nios_sopc.h b/arch/nios2/boards/generic/nios_sopc.h new file mode 100644 index 0000000..5ee3642 --- /dev/null +++ b/arch/nios2/boards/generic/nios_sopc.h @@ -0,0 +1,406 @@ +#ifndef _ALTERA_NIOSLINUX_H_ +#define _ALTERA_NIOSLINUX_H_ + +/* + * This file was automatically generated by the swinfo2header utility. + * + * Created from SOPC Builder system 'NiosLinux' in + * file 'NiosLinux.sopcinfo'. + */ + +/* + * This file contains macros for module 'LINUX_CPU' and devices + * connected to the following masters: + * instruction_master + * tightly_coupled_instruction_master_0 + * data_master + * tightly_coupled_data_master_0 + * + * Do not include this header file and another header file created for a + * different module or master group at the same time. + * Doing so may result in duplicate macro names. + * Instead, use the system header file which has macros with unique names. + */ + +/* + * Macros for module 'LINUX_CPU', class 'altera_nios2'. + * The macros have no prefix. + */ +#define CPU_IMPLEMENTATION "fast" +#define BIG_ENDIAN 0 +#define CPU_FREQ 50000000 +#define ICACHE_LINE_SIZE 32 +#define ICACHE_LINE_SIZE_LOG2 5 +#define ICACHE_SIZE 8192 +#define DCACHE_LINE_SIZE 32 +#define DCACHE_LINE_SIZE_LOG2 5 +#define DCACHE_SIZE 8192 +#define INITDA_SUPPORTED +#define FLUSHDA_SUPPORTED +#define HAS_JMPI_INSTRUCTION +#define MMU_PRESENT +#define KERNEL_REGION_BASE 0xc0000000 +#define IO_REGION_BASE 0xe0000000 +#define KERNEL_MMU_REGION_BASE 0x80000000 +#define USER_REGION_BASE 0x0 +#define PROCESS_ID_NUM_BITS 8 +#define TLB_NUM_WAYS 16 +#define TLB_NUM_WAYS_LOG2 4 +#define TLB_PTR_SZ 8 +#define TLB_NUM_ENTRIES 256 +#define FAST_TLB_MISS_EXCEPTION_ADDR 0xc4201000 +#define EXCEPTION_ADDR 0xc0000020 +#define RESET_ADDR 0xc30e0000 +#define BREAK_ADDR 0xc4203820 +#define HAS_DEBUG_STUB +#define HAS_DEBUG_CORE 1 +#define HAS_ILLEGAL_INSTRUCTION_EXCEPTION +#define HAS_ILLEGAL_MEMORY_ACCESS_EXCEPTION +#define HAS_EXTRA_EXCEPTION_INFO +#define CPU_ID_SIZE 1 +#define CPU_ID_VALUE 0x0 +#define HARDWARE_DIVIDE_PRESENT 0 +#define HARDWARE_MULTIPLY_PRESENT 1 +#define HARDWARE_MULX_PRESENT 0 +#define INST_ADDR_WIDTH 27 +#define DATA_ADDR_WIDTH 27 +#define NUM_OF_SHADOW_REG_SETS 0 + +/* + * Macros for device 'DDR_SDRAM', class 'altmemddr' + * The macros are prefixed with 'DDR_SDRAM_'. + * The prefix is the slave descriptor. + */ +#define DDR_SDRAM_COMPONENT_TYPE altmemddr +#define DDR_SDRAM_COMPONENT_NAME DDR_SDRAM +#define DDR_SDRAM_BASE 0x0 +#define DDR_SDRAM_SPAN 33554432 +#define DDR_SDRAM_END 0x1ffffff +#define DDR_SDRAM_MEMORY_INFO_MEM_INIT_DATA_WIDTH 32 +#define DDR_SDRAM_MEMORY_INFO_GENERATE_DAT_SYM 1 +#define DDR_SDRAM_MEMORY_INFO_DAT_SYM_INSTALL_DIR SIM_DIR + +/* + * Macros for device 'CFI_FLASH', class 'altera_avalon_cfi_flash' + * The macros are prefixed with 'CFI_FLASH_'. + * The prefix is the slave descriptor. + */ +#define CFI_FLASH_COMPONENT_TYPE altera_avalon_cfi_flash +#define CFI_FLASH_COMPONENT_NAME CFI_FLASH +#define CFI_FLASH_BASE 0x3000000 +#define CFI_FLASH_SPAN 16777216 +#define CFI_FLASH_END 0x3ffffff +#define CFI_FLASH_SETUP_VALUE 25 +#define CFI_FLASH_WAIT_VALUE 100 +#define CFI_FLASH_HOLD_VALUE 20 +#define CFI_FLASH_TIMING_UNITS "ns" +#define CFI_FLASH_SIZE 16777216 +#define CFI_FLASH_MEMORY_INFO_MEM_INIT_DATA_WIDTH 16 +#define CFI_FLASH_MEMORY_INFO_HAS_BYTE_LANE 1 +#define CFI_FLASH_MEMORY_INFO_IS_FLASH 1 +#define CFI_FLASH_MEMORY_INFO_GENERATE_DAT_SYM 1 +#define CFI_FLASH_MEMORY_INFO_GENERATE_FLASH 1 +#define CFI_FLASH_MEMORY_INFO_DAT_SYM_INSTALL_DIR SIM_DIR +#define CFI_FLASH_MEMORY_INFO_FLASH_INSTALL_DIR APP_DIR + +/* + * Macros for device 'SSRAM', class 'altera_avalon_cy7c1380_ssram' + * The macros are prefixed with 'SSRAM_'. + * The prefix is the slave descriptor. + */ +#define SSRAM_COMPONENT_TYPE altera_avalon_cy7c1380_ssram +#define SSRAM_COMPONENT_NAME SSRAM +#define SSRAM_BASE 0x4100000 +#define SSRAM_SPAN 1048576 +#define SSRAM_END 0x41fffff +#define SSRAM_SRAM_MEMORY_SIZE 1 +#define SSRAM_SRAM_MEMORY_UNITS 1048576 +#define SSRAM_SSRAM_DATA_WIDTH 32 +#define SSRAM_SSRAM_READ_LATENCY 2 +#define SSRAM_MEMORY_INFO_MEM_INIT_DATA_WIDTH 32 +#define SSRAM_MEMORY_INFO_HAS_BYTE_LANE 1 +#define SSRAM_MEMORY_INFO_GENERATE_DAT_SYM 1 +#define SSRAM_MEMORY_INFO_DAT_SYM_INSTALL_DIR SIM_DIR + +/* + * Macros for device 'TLB', class 'altera_avalon_onchip_memory2' + * The macros are prefixed with 'TLB_'. + * The prefix is the slave descriptor. + */ +#define TLB_COMPONENT_TYPE altera_avalon_onchip_memory2 +#define TLB_COMPONENT_NAME TLB +#define TLB_BASE 0x4201000 +#define TLB_SPAN 4096 +#define TLB_END 0x4201fff +#define TLB_ALLOW_MRAM_SIM_CONTENTS_ONLY_FILE 0 +#define TLB_INIT_CONTENTS_FILE "TLB" +#define TLB_NON_DEFAULT_INIT_FILE_ENABLED 0 +#define TLB_GUI_RAM_BLOCK_TYPE "Automatic" +#define TLB_WRITABLE 1 +#define TLB_DUAL_PORT 1 +#define TLB_SIZE_VALUE 4096 +#define TLB_SIZE_MULTIPLE 1 +#define TLB_CONTENTS_INFO "" +#define TLB_RAM_BLOCK_TYPE "Auto" +#define TLB_INIT_MEM_CONTENT 1 +#define TLB_ALLOW_IN_SYSTEM_MEMORY_CONTENT_EDITOR 0 +#define TLB_INSTANCE_ID "NONE" +#define TLB_READ_DURING_WRITE_MODE "DONT_CARE" +#define TLB_MEMORY_INFO_MEM_INIT_DATA_WIDTH 32 +#define TLB_MEMORY_INFO_HAS_BYTE_LANE 0 +#define TLB_MEMORY_INFO_GENERATE_HEX 1 +#define TLB_MEMORY_INFO_HEX_INSTALL_DIR QPF_DIR +#define TLB_MEMORY_INFO_GENERATE_DAT_SYM 1 +#define TLB_MEMORY_INFO_DAT_SYM_INSTALL_DIR SIM_DIR + +/* + * Macros for device 'DESCRIPTOR_MEMORY', class 'altera_avalon_onchip_memory2' + * The macros are prefixed with 'DESCRIPTOR_MEMORY_'. + * The prefix is the slave descriptor. + */ +#define DESCRIPTOR_MEMORY_COMPONENT_TYPE altera_avalon_onchip_memory2 +#define DESCRIPTOR_MEMORY_COMPONENT_NAME DESCRIPTOR_MEMORY +#define DESCRIPTOR_MEMORY_BASE 0x4202000 +#define DESCRIPTOR_MEMORY_SPAN 4096 +#define DESCRIPTOR_MEMORY_END 0x4202fff +#define DESCRIPTOR_MEMORY_ALLOW_MRAM_SIM_CONTENTS_ONLY_FILE 0 +#define DESCRIPTOR_MEMORY_INIT_CONTENTS_FILE "DESCRIPTOR_MEMORY" +#define DESCRIPTOR_MEMORY_NON_DEFAULT_INIT_FILE_ENABLED 0 +#define DESCRIPTOR_MEMORY_GUI_RAM_BLOCK_TYPE "Automatic" +#define DESCRIPTOR_MEMORY_WRITABLE 1 +#define DESCRIPTOR_MEMORY_DUAL_PORT 0 +#define DESCRIPTOR_MEMORY_SIZE_VALUE 4096 +#define DESCRIPTOR_MEMORY_SIZE_MULTIPLE 1 +#define DESCRIPTOR_MEMORY_CONTENTS_INFO "" +#define DESCRIPTOR_MEMORY_RAM_BLOCK_TYPE "Auto" +#define DESCRIPTOR_MEMORY_INIT_MEM_CONTENT 1 +#define DESCRIPTOR_MEMORY_ALLOW_IN_SYSTEM_MEMORY_CONTENT_EDITOR 0 +#define DESCRIPTOR_MEMORY_INSTANCE_ID "NONE" +#define DESCRIPTOR_MEMORY_READ_DURING_WRITE_MODE "DONT_CARE" +#define DESCRIPTOR_MEMORY_MEMORY_INFO_MEM_INIT_DATA_WIDTH 32 +#define DESCRIPTOR_MEMORY_MEMORY_INFO_HAS_BYTE_LANE 0 +#define DESCRIPTOR_MEMORY_MEMORY_INFO_GENERATE_HEX 1 +#define DESCRIPTOR_MEMORY_MEMORY_INFO_HEX_INSTALL_DIR QPF_DIR +#define DESCRIPTOR_MEMORY_MEMORY_INFO_GENERATE_DAT_SYM 1 +#define DESCRIPTOR_MEMORY_MEMORY_INFO_DAT_SYM_INSTALL_DIR SIM_DIR + +/* + * Macros for device 'TSE', class 'triple_speed_ethernet' + * The macros are prefixed with 'TSE_'. + * The prefix is the slave descriptor. + */ +#define TSE_COMPONENT_TYPE triple_speed_ethernet +#define TSE_COMPONENT_NAME TSE +#define TSE_BASE 0x4204000 +#define TSE_SPAN 1024 +#define TSE_END 0x42043ff +#define TSE_TRANSMIT "SGDMA_TX" +#define TSE_RECEIVE "SGDMA_RX" +#define TSE_TRANSMIT_FIFO_DEPTH 2048 +#define TSE_RECEIVE_FIFO_DEPTH 2048 +#define TSE_FIFO_WIDTH 32 +#define TSE_ENABLE_MACLITE 1 +#define TSE_MACLITE_GIGE 0 +#define TSE_USE_MDIO 1 +#define TSE_NUMBER_OF_CHANNEL 1 +#define TSE_NUMBER_OF_MAC_MDIO_SHARED 1 +#define TSE_IS_MULTICHANNEL_MAC 0 +#define TSE_MDIO_SHARED 0 +#define TSE_REGISTER_SHARED 0 +#define TSE_PCS 0 +#define TSE_PCS_SGMII 0 +#define TSE_PCS_ID 0 + +/* + * Macros for device 'SGDMA_TX', class 'altera_avalon_sgdma' + * The macros are prefixed with 'SGDMA_TX_'. + * The prefix is the slave descriptor. + */ +#define SGDMA_TX_COMPONENT_TYPE altera_avalon_sgdma +#define SGDMA_TX_COMPONENT_NAME SGDMA_TX +#define SGDMA_TX_BASE 0x4204400 +#define SGDMA_TX_SPAN 64 +#define SGDMA_TX_END 0x420443f +#define SGDMA_TX_IRQ 0 +#define SGDMA_TX_READ_BLOCK_DATA_WIDTH 32 +#define SGDMA_TX_WRITE_BLOCK_DATA_WIDTH 32 +#define SGDMA_TX_STREAM_DATA_WIDTH 32 +#define SGDMA_TX_ADDRESS_WIDTH 32 +#define SGDMA_TX_HAS_READ_BLOCK 1 +#define SGDMA_TX_HAS_WRITE_BLOCK 0 +#define SGDMA_TX_READ_BURSTCOUNT_WIDTH 4 +#define SGDMA_TX_WRITE_BURSTCOUNT_WIDTH 4 +#define SGDMA_TX_BURST_TRANSFER 0 +#define SGDMA_TX_ALWAYS_DO_MAX_BURST 1 +#define SGDMA_TX_DESCRIPTOR_READ_BURST 0 +#define SGDMA_TX_UNALIGNED_TRANSFER 0 +#define SGDMA_TX_CONTROL_SLAVE_DATA_WIDTH 32 +#define SGDMA_TX_CONTROL_SLAVE_ADDRESS_WIDTH 4 +#define SGDMA_TX_DESC_DATA_WIDTH 32 +#define SGDMA_TX_CHAIN_WRITEBACK_DATA_WIDTH 32 +#define SGDMA_TX_STATUS_TOKEN_DATA_WIDTH 24 +#define SGDMA_TX_BYTES_TO_TRANSFER_DATA_WIDTH 16 +#define SGDMA_TX_BURST_DATA_WIDTH 8 +#define SGDMA_TX_CONTROL_DATA_WIDTH 8 +#define SGDMA_TX_ATLANTIC_CHANNEL_DATA_WIDTH 4 +#define SGDMA_TX_COMMAND_FIFO_DATA_WIDTH 104 +#define SGDMA_TX_SYMBOLS_PER_BEAT 4 +#define SGDMA_TX_IN_ERROR_WIDTH 0 +#define SGDMA_TX_OUT_ERROR_WIDTH 1 + +/* + * Macros for device 'DDR_SDRAM', class 'altmemddr' + * Path to the device is from the master group 'SGDMA_TX_m_read'. + * The macros are prefixed with 'SGDMA_TX_M_READ_DDR_SDRAM_'. + * The prefix is the master group descriptor and the slave descriptor. + */ +#define SGDMA_TX_M_READ_DDR_SDRAM_COMPONENT_TYPE altmemddr +#define SGDMA_TX_M_READ_DDR_SDRAM_COMPONENT_NAME DDR_SDRAM +#define SGDMA_TX_M_READ_DDR_SDRAM_BASE 0x0 +#define SGDMA_TX_M_READ_DDR_SDRAM_SPAN 33554432 +#define SGDMA_TX_M_READ_DDR_SDRAM_END 0x1ffffff +#define SGDMA_TX_M_READ_DDR_SDRAM_MEMORY_INFO_MEM_INIT_DATA_WIDTH 32 +#define SGDMA_TX_M_READ_DDR_SDRAM_MEMORY_INFO_GENERATE_DAT_SYM 1 +#define SGDMA_TX_M_READ_DDR_SDRAM_MEMORY_INFO_DAT_SYM_INSTALL_DIR SIM_DIR + +/* + * Macros for device 'SGDMA_RX', class 'altera_avalon_sgdma' + * The macros are prefixed with 'SGDMA_RX_'. + * The prefix is the slave descriptor. + */ +#define SGDMA_RX_COMPONENT_TYPE altera_avalon_sgdma +#define SGDMA_RX_COMPONENT_NAME SGDMA_RX +#define SGDMA_RX_BASE 0x4204440 +#define SGDMA_RX_SPAN 64 +#define SGDMA_RX_END 0x420447f +#define SGDMA_RX_IRQ 3 +#define SGDMA_RX_READ_BLOCK_DATA_WIDTH 32 +#define SGDMA_RX_WRITE_BLOCK_DATA_WIDTH 32 +#define SGDMA_RX_STREAM_DATA_WIDTH 32 +#define SGDMA_RX_ADDRESS_WIDTH 32 +#define SGDMA_RX_HAS_READ_BLOCK 0 +#define SGDMA_RX_HAS_WRITE_BLOCK 1 +#define SGDMA_RX_READ_BURSTCOUNT_WIDTH 4 +#define SGDMA_RX_WRITE_BURSTCOUNT_WIDTH 4 +#define SGDMA_RX_BURST_TRANSFER 0 +#define SGDMA_RX_ALWAYS_DO_MAX_BURST 1 +#define SGDMA_RX_DESCRIPTOR_READ_BURST 0 +#define SGDMA_RX_UNALIGNED_TRANSFER 0 +#define SGDMA_RX_CONTROL_SLAVE_DATA_WIDTH 32 +#define SGDMA_RX_CONTROL_SLAVE_ADDRESS_WIDTH 4 +#define SGDMA_RX_DESC_DATA_WIDTH 32 +#define SGDMA_RX_CHAIN_WRITEBACK_DATA_WIDTH 32 +#define SGDMA_RX_STATUS_TOKEN_DATA_WIDTH 24 +#define SGDMA_RX_BYTES_TO_TRANSFER_DATA_WIDTH 16 +#define SGDMA_RX_BURST_DATA_WIDTH 8 +#define SGDMA_RX_CONTROL_DATA_WIDTH 8 +#define SGDMA_RX_ATLANTIC_CHANNEL_DATA_WIDTH 4 +#define SGDMA_RX_COMMAND_FIFO_DATA_WIDTH 104 +#define SGDMA_RX_SYMBOLS_PER_BEAT 4 +#define SGDMA_RX_IN_ERROR_WIDTH 6 +#define SGDMA_RX_OUT_ERROR_WIDTH 0 + +/* + * Macros for device 'DDR_SDRAM', class 'altmemddr' + * Path to the device is from the master group 'SGDMA_RX_m_write'. + * The macros are prefixed with 'SGDMA_RX_M_WRITE_DDR_SDRAM_'. + * The prefix is the master group descriptor and the slave descriptor. + */ +#define SGDMA_RX_M_WRITE_DDR_SDRAM_COMPONENT_TYPE altmemddr +#define SGDMA_RX_M_WRITE_DDR_SDRAM_COMPONENT_NAME DDR_SDRAM +#define SGDMA_RX_M_WRITE_DDR_SDRAM_BASE 0x0 +#define SGDMA_RX_M_WRITE_DDR_SDRAM_SPAN 33554432 +#define SGDMA_RX_M_WRITE_DDR_SDRAM_END 0x1ffffff +#define SGDMA_RX_M_WRITE_DDR_SDRAM_MEMORY_INFO_MEM_INIT_DATA_WIDTH 32 +#define SGDMA_RX_M_WRITE_DDR_SDRAM_MEMORY_INFO_GENERATE_DAT_SYM 1 +#define SGDMA_RX_M_WRITE_DDR_SDRAM_MEMORY_INFO_DAT_SYM_INSTALL_DIR SIM_DIR + +/* + * Macros for device 'UART', class 'altera_avalon_uart' + * The macros are prefixed with 'UART_'. + * The prefix is the slave descriptor. + */ +#define UART_COMPONENT_TYPE altera_avalon_uart +#define UART_COMPONENT_NAME UART +#define UART_BASE 0x4204480 +#define UART_SPAN 32 +#define UART_END 0x420449f +#define UART_IRQ 1 +#define UART_BAUD 9600 +#define UART_DATA_BITS 8 +#define UART_FIXED_BAUD 0 +#define UART_PARITY 'N' +#define UART_STOP_BITS 1 +#define UART_SYNC_REG_DEPTH 2 +#define UART_USE_CTS_RTS 0 +#define UART_USE_EOP_REGISTER 0 +#define UART_SIM_TRUE_BAUD 0 +#define UART_SIM_CHAR_STREAM "" +#define UART_FREQ 50000000 + +/* + * Macros for device 'SYS_CLK_TIMER', class 'altera_avalon_timer' + * The macros are prefixed with 'SYS_CLK_TIMER_'. + * The prefix is the slave descriptor. + */ +#define SYS_CLK_TIMER_COMPONENT_TYPE altera_avalon_timer +#define SYS_CLK_TIMER_COMPONENT_NAME SYS_CLK_TIMER +#define SYS_CLK_TIMER_BASE 0x42044a0 +#define SYS_CLK_TIMER_SPAN 32 +#define SYS_CLK_TIMER_END 0x42044bf +#define SYS_CLK_TIMER_IRQ 2 +#define SYS_CLK_TIMER_ALWAYS_RUN 0 +#define SYS_CLK_TIMER_FIXED_PERIOD 0 +#define SYS_CLK_TIMER_SNAPSHOT 1 +#define SYS_CLK_TIMER_PERIOD 1 +#define SYS_CLK_TIMER_PERIOD_UNITS "ms" +#define SYS_CLK_TIMER_RESET_OUTPUT 0 +#define SYS_CLK_TIMER_TIMEOUT_PULSE_OUTPUT 0 +#define SYS_CLK_TIMER_FREQ 50000000 +#define SYS_CLK_TIMER_LOAD_VALUE 49999ULL +#define SYS_CLK_TIMER_COUNTER_SIZE 32 +#define SYS_CLK_TIMER_MULT 0.0010 +#define SYS_CLK_TIMER_TICKS_PER_SEC 1000 + +/* + * Macros for device 'LED_STATUS', class 'altera_avalon_pio' + * The macros are prefixed with 'LED_STATUS_'. + * The prefix is the slave descriptor. + */ +#define LED_STATUS_COMPONENT_TYPE altera_avalon_pio +#define LED_STATUS_COMPONENT_NAME LED_STATUS +#define LED_STATUS_BASE 0x42044c0 +#define LED_STATUS_SPAN 16 +#define LED_STATUS_END 0x42044cf +#define LED_STATUS_DO_TEST_BENCH_WIRING 0 +#define LED_STATUS_DRIVEN_SIM_VALUE 0x0 +#define LED_STATUS_HAS_TRI 0 +#define LED_STATUS_HAS_OUT 1 +#define LED_STATUS_HAS_IN 0 +#define LED_STATUS_CAPTURE 0 +#define LED_STATUS_BIT_CLEARING_EDGE_REGISTER 0 +#define LED_STATUS_BIT_MODIFYING_OUTPUT_REGISTER 0 +#define LED_STATUS_DATA_WIDTH 2 +#define LED_STATUS_RESET_VALUE 0x3 +#define LED_STATUS_EDGE_TYPE "NONE" +#define LED_STATUS_IRQ_TYPE "NONE" +#define LED_STATUS_FREQ 50000000 + +/* + * Macros for device 'JTAG_UART', class 'altera_avalon_jtag_uart' + * The macros are prefixed with 'JTAG_UART_'. + * The prefix is the slave descriptor. + */ +#define JTAG_UART_COMPONENT_TYPE altera_avalon_jtag_uart +#define JTAG_UART_COMPONENT_NAME JTAG_UART +#define JTAG_UART_BASE 0x42044d0 +#define JTAG_UART_SPAN 8 +#define JTAG_UART_END 0x42044d7 +#define JTAG_UART_IRQ 4 +#define JTAG_UART_WRITE_DEPTH 64 +#define JTAG_UART_READ_DEPTH 64 +#define JTAG_UART_WRITE_THRESHOLD 8 +#define JTAG_UART_READ_THRESHOLD 8 + + +#endif /* _ALTERA_NIOSLINUX_H_ */ diff --git a/arch/nios2/configs/generic_defconfig b/arch/nios2/configs/generic_defconfig new file mode 100644 index 0000000..279a71e --- /dev/null +++ b/arch/nios2/configs/generic_defconfig @@ -0,0 +1,23 @@ +CONFIG_EARLY_PRINTF=y +CONFIG_BAUDRATE=9600 +CONFIG_LONGHELP=y +CONFIG_HUSH_FANCY_PROMPT=y +CONFIG_CMDLINE_EDITING=y +CONFIG_AUTO_COMPLETE=y +CONFIG_PARTITION=y +CONFIG_DEFAULT_ENVIRONMENT_GENERIC=y +CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/nios2/boards/generic/env" +CONFIG_CMD_EDIT=y +CONFIG_CMD_SLEEP=y +CONFIG_CMD_SAVEENV=y +CONFIG_CMD_LOADENV=y +CONFIG_CMD_EXPORT=y +CONFIG_CMD_PRINTENV=y +CONFIG_CMD_READLINE=y +CONFIG_CMD_FLASH=y +CONFIG_CMD_BOOTM_ZLIB=y +CONFIG_CMD_RESET=y +CONFIG_CMD_GO=y +CONFIG_CMD_TIMEOUT=y +CONFIG_CMD_PARTITION=y +CONFIG_DRIVER_CFI=y diff --git a/arch/nios2/cpu/Makefile b/arch/nios2/cpu/Makefile new file mode 100644 index 0000000..f15c721 --- /dev/null +++ b/arch/nios2/cpu/Makefile @@ -0,0 +1,6 @@ +obj-y += start.o +obj-y += exceptions.o +obj-y += cpu.o +obj-$(CONFIG_USE_IRQ) += interrupts.o +obj-y += traps.o +extra-y += barebox.lds diff --git a/arch/nios2/cpu/barebox.lds.S b/arch/nios2/cpu/barebox.lds.S new file mode 100644 index 0000000..2b626fb --- /dev/null +++ b/arch/nios2/cpu/barebox.lds.S @@ -0,0 +1,124 @@ +/* + * barebox - barebox.lds.S + * + * (C) Copyright 2011, Franck JULLIEN, + * + * (C) Copyright 2004, Psyent Corporation + * Scott McNutt + * + * Copyright (c) 2005-2007 Analog Device Inc. + * + * (C) Copyright 2000-2004 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include + +OUTPUT_FORMAT("elf32-littlenios2") +OUTPUT_ARCH("nios2") + +SECTIONS +{ + . = NIOS_SOPC_TEXT_BASE; + + . = ALIGN(4); + .text : + { + __stext = .; + __text = .; + _text = .; + *(.text_entry) + *(.text) + } + + . = ALIGN(4); + .rodata : { *(.rodata) } + + . = .; + __barebox_cmd_start = .; + .barebox_cmd : { BAREBOX_CMDS } + __barebox_cmd_end = .; + + __barebox_initcalls_start = .; + .barebox_initcalls : { INITCALLS } + __barebox_initcalls_end = .; + + ___usymtab_start = .; + __usymtab : { BAREBOX_SYMS } + ___usymtab_end = .; + + __etext = .; /* End of text and rodata section */ + + /* INIT DATA sections - "Small" data (see the gcc -G option) + * is always gp-relative. Here we make all init data sections + * adjacent to simplify the startup code -- and provide + * the global pointer for gp-relative access. + */ + _data = .; + .data : + { + *(.data) + *(.data.*) + *(.gnu.linkonce.d*) + } + + . = ALIGN(16); + _gp = .; /* Global pointer addr */ + PROVIDE (gp = .); + + .sdata : + { + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + } + . = ALIGN(4); + + _edata = .; + PROVIDE (edata = .); + + /* UNINIT DATA - Small uninitialized data is first so it's + * adjacent to sdata and can be referenced via gp. The normal + * bss follows. We keep it adjacent to simplify init code. + */ + __bss_start = .; + .sbss (NOLOAD) : + { + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + *(.scommon) + } + . = ALIGN(4); + .bss (NOLOAD) : + { + *(.bss) + *(.bss.*) + *(.dynbss) + *(COMMON) + *(.scommon) + } + __bss_stop = .; + + . = ALIGN(4); + _end = .; + PROVIDE (end = .); +} + diff --git a/arch/nios2/cpu/cpu.c b/arch/nios2/cpu/cpu.c new file mode 100644 index 0000000..102b12e --- /dev/null +++ b/arch/nios2/cpu/cpu.c @@ -0,0 +1,38 @@ +/* + * (C) Copyright 2004, Psyent Corporation + * Scott McNutt + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include + +void __noreturn reset_cpu(ulong ignored) +{ +#ifdef CONFIG_USE_IRQ + disable_interrupts(); +#endif + /* indirect call to go beyond 256MB limitation of toolchain */ + nios2_callr(RESET_ADDR); + + /* Not reached */ + while (1); +} + diff --git a/arch/nios2/cpu/exceptions.S b/arch/nios2/cpu/exceptions.S new file mode 100644 index 0000000..a949372 --- /dev/null +++ b/arch/nios2/cpu/exceptions.S @@ -0,0 +1,160 @@ +/* + * (C) Copyright 2004, Psyent Corporation + * Scott McNutt + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include + + + .text + .align 4 + + .global _exception + + .set noat + .set nobreak + +_exception: + /* SAVE ALL REGS -- this allows trap and unimplemented + * instruction handlers to be coded conveniently in C + */ + addi sp, sp, -(33*4) + stw r0, 0(sp) + stw r1, 4(sp) + stw r2, 8(sp) + stw r3, 12(sp) + stw r4, 16(sp) + stw r5, 20(sp) + stw r6, 24(sp) + stw r7, 28(sp) + stw r8, 32(sp) + stw r9, 36(sp) + stw r10, 40(sp) + stw r11, 44(sp) + stw r12, 48(sp) + stw r13, 52(sp) + stw r14, 56(sp) + stw r15, 60(sp) + stw r16, 64(sp) + stw r17, 68(sp) + stw r19, 72(sp) + stw r19, 76(sp) + stw r20, 80(sp) + stw r21, 84(sp) + stw r22, 88(sp) + stw r23, 92(sp) + stw r24, 96(sp) + stw r25, 100(sp) + stw r26, 104(sp) + stw r27, 108(sp) + stw r28, 112(sp) + stw r29, 116(sp) + stw r30, 120(sp) + stw r31, 124(sp) + rdctl et, estatus + stw et, 128(sp) + + /* If interrupts are disabled -- software interrupt */ + rdctl et, estatus + andi et, et, 1 + beq et, r0, 0f + + /* If no interrupts are pending -- software interrupt */ + rdctl et, ipending + beq et, r0, 0f + +#ifdef CONFIG_USE_IRQ + + /* HARDWARE INTERRUPT: Call interrupt handler */ + movhi r3, %hi(external_interrupt) + ori r3, r3, %lo(external_interrupt) + mov r4, sp /* ptr to regs */ + callr r3 +#else + br _exception_return +#endif + + /* Return address fixup: execution resumes by re-issue of + * interrupted instruction at ea-4 (ea == r29). Here we do + * simple fixup to allow common exception return. + */ + ldw r3, 116(sp) + addi r3, r3, -4 + stw r3, 116(sp) + br _exception_return + +0: + /* TRAP EXCEPTION */ + movhi r3, %hi(OPC_TRAP) + ori r3, r3, %lo(OPC_TRAP) + addi r1, ea, -4 + ldw r1, 0(r1) + bne r1, r3, 1f + movhi r3, %hi(trap_handler) + ori r3, r3, %lo(trap_handler) + mov r4, sp /* ptr to regs */ + callr r3 + br _exception_return + +1: + /* UNIMPLEMENTED INSTRUCTION EXCEPTION */ + movhi r3, %hi(soft_emulation) + ori r3, r3, %lo(soft_emulation) + mov r4, sp /* ptr to regs */ + callr r3 + + /* Restore regsisters and return from exception*/ +_exception_return: + ldw r1, 4(sp) + ldw r2, 8(sp) + ldw r3, 12(sp) + ldw r4, 16(sp) + ldw r5, 20(sp) + ldw r6, 24(sp) + ldw r7, 28(sp) + ldw r8, 32(sp) + ldw r9, 36(sp) + ldw r10, 40(sp) + ldw r11, 44(sp) + ldw r12, 48(sp) + ldw r13, 52(sp) + ldw r14, 56(sp) + ldw r15, 60(sp) + ldw r16, 64(sp) + ldw r17, 68(sp) + ldw r19, 72(sp) + ldw r19, 76(sp) + ldw r20, 80(sp) + ldw r21, 84(sp) + ldw r22, 88(sp) + ldw r23, 92(sp) + ldw r24, 96(sp) + ldw r25, 100(sp) + ldw r26, 104(sp) + ldw r27, 108(sp) + ldw r28, 112(sp) + ldw r29, 116(sp) + ldw r30, 120(sp) + ldw r31, 124(sp) + addi sp, sp, (33*4) + eret +/*-------------------------------------------------------------*/ diff --git a/arch/nios2/cpu/interrupts.c b/arch/nios2/cpu/interrupts.c new file mode 100644 index 0000000..5efbd5e --- /dev/null +++ b/arch/nios2/cpu/interrupts.c @@ -0,0 +1,140 @@ +/* + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * (C) Copyright 2004, Psyent Corporation + * Scott McNutt + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/****************************************************************************/ + +struct irq_action { + interrupt_handler_t *handler; + void *arg; + int count; +}; + +static struct irq_action vecs[32]; + +/****************************************************************************/ + +int disable_interrupts(void) +{ + int val = rdctl(CTL_STATUS); + wrctl(CTL_STATUS, val & ~STATUS_IE); + return val & STATUS_IE; +} + +void enable_interrupts(void) +{ + int val = rdctl(CTL_STATUS); + wrctl(CTL_STATUS, val | STATUS_IE); +} + +void external_interrupt(struct pt_regs *regs) +{ + unsigned irqs; + struct irq_action *act; + + /* Evaluate only irqs that are both enabled AND pending */ + irqs = rdctl(CTL_IENABLE) & rdctl(CTL_IPENDING); + act = vecs; + + /* Assume (as does the Nios2 HAL) that bit 0 is highest + * priority. NOTE: There is ALWAYS a handler assigned + * (the default if no other). + */ + while (irqs) { + if (irqs & 1) { + act->handler(act->arg); + act->count++; + } + irqs >>= 1; + act++; + } + +} + +static void def_hdlr(void *arg) +{ + unsigned irqs = rdctl(CTL_IENABLE); + + /* Disable the individual interrupt -- with gratuitous + * warning. + */ + irqs &= ~(1 << (int)arg); + wrctl(CTL_IENABLE, irqs); + printf("WARNING: Disabling unhandled interrupt: %d\n", + (int)arg); +} + +/*************************************************************************/ +void irq_install_handler(int irq, interrupt_handler_t *hdlr, void *arg) +{ + int flag; + struct irq_action *act; + unsigned ena = rdctl(CTL_IENABLE); + + if ((irq < 0) || (irq > 31)) + return; + act = &vecs[irq]; + + flag = disable_interrupts(); + if (hdlr) { + act->handler = hdlr; + act->arg = arg; + ena |= (1 << irq); /* enable */ + } else { + act->handler = def_hdlr; + act->arg = (void *)irq; + ena &= ~(1 << irq); /* disable */ + } + wrctl(CTL_IENABLE, ena); + + if (flag) + enable_interrupts(); +} + + +int interrupt_init(void) +{ + int i; + + /* Assign the default handler to all */ + for (i = 0; i < 32; i++) { + vecs[i].handler = def_hdlr; + vecs[i].arg = (void *)i; + vecs[i].count = 0; + } + + enable_interrupts(); + return 0; +} + diff --git a/arch/nios2/cpu/start.S b/arch/nios2/cpu/start.S new file mode 100644 index 0000000..adfb1f2 --- /dev/null +++ b/arch/nios2/cpu/start.S @@ -0,0 +1,165 @@ +/* + * (C) Copyright 2004, Psyent Corporation + * Scott McNutt + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include + +/************************************************************************* + * RESTART + ************************************************************************/ + +.section ".text_entry","ax" + +_start: + wrctl status, r0 /* Disable interrupts */ + /* ICACHE INIT -- only the icache line at the reset address + * is invalidated at reset. So the init must stay within + * the cache line size (8 words). If GERMS is used, we'll + * just be invalidating the cache a second time. If cache + * is not implemented initi behaves as nop. + */ + ori r4, r0, %lo(ICACHE_LINE_SIZE) + movhi r5, %hi(ICACHE_SIZE) + ori r5, r5, %lo(ICACHE_SIZE) +0: initi r5 + sub r5, r5, r4 + bgt r5, r0, 0b + br _except_end /* Skip the tramp */ + + /* EXCEPTION TRAMPOLINE -- the following gets copied + * to the exception address (below), but is otherwise at the + * default exception vector offset (0x0020). + */ +_except_start: + movhi et, %hi(_exception) + ori et, et, %lo(_exception) + jmp et +_except_end: + + /* INTERRUPTS -- for now, all interrupts masked and globally + * disabled. + */ + wrctl ienable, r0 /* All disabled */ + + /* DCACHE INIT -- if dcache not implemented, initd behaves as + * nop. + */ + movhi r4, %hi(DCACHE_LINE_SIZE) + ori r4, r4, %lo(DCACHE_LINE_SIZE) + movhi r5, %hi(DCACHE_SIZE) + ori r5, r5, %lo(DCACHE_SIZE) + mov r6, r0 +1: initd 0(r6) + add r6, r6, r4 + bltu r6, r5, 1b + + /* RELOCATE CODE, DATA & COMMAND TABLE -- the following code + * assumes code, data and the command table are all + * contiguous. This lets us relocate everything as a single + * block. Make sure the linker script matches this ;-) + */ + nextpc r4 +_cur: movhi r5, %hi(_cur - _start) + ori r5, r5, %lo(_cur - _start) + sub r4, r4, r5 /* r4 <- cur _start */ + mov r8, r4 + movhi r5, %hi(_start) + ori r5, r5, %lo(_start) /* r5 <- linked _start */ + beq r4, r5, 3f + + movhi r6, %hi(_edata) + ori r6, r6, %lo(_edata) +2: ldwio r7, 0(r4) + addi r4, r4, 4 + stwio r7, 0(r5) + addi r5, r5, 4 + bne r5, r6, 2b +3: + + /* ZERO BSS/SBSS -- bss and sbss are assumed to be adjacent + * and between __bss_start and _end. + */ + movhi r5, %hi(__bss_start) + ori r5, r5, %lo(__bss_start) + movhi r6, %hi(_end) + ori r6, r6, %lo(_end) + beq r5, r6, 5f + +4: stwio r0, 0(r5) + addi r5, r5, 4 + bne r5, r6, 4b +5: + + /* JUMP TO RELOC ADDR */ + movhi r4, %hi(_reloc) + ori r4, r4, %lo(_reloc) + jmp r4 +_reloc: + + /* COPY EXCEPTION TRAMPOLINE -- copy the tramp to the + * exception address. Define CONFIG_ROM_STUBS to prevent + * the copy (e.g. exception in flash or in other + * softare/firmware component). + */ +#if !defined(CONFIG_ROM_STUBS) + movhi r4, %hi(_except_start) + ori r4, r4, %lo(_except_start) + movhi r5, %hi(_except_end) + ori r5, r5, %lo(_except_end) + movhi r6, %hi(EXCEPTION_ADDR) + ori r6, r6, %lo(EXCEPTION_ADDR) + beq r4, r6, 7f /* Skip if at proper addr */ + +6: ldwio r7, 0(r4) + stwio r7, 0(r6) + addi r4, r4, 4 + addi r6, r6, 4 + bne r4, r5, 6b +7: +#endif + + /* STACK INIT -- zero top two words for call back chain. + */ + movhi sp, %hi(STACK_BASE) + ori sp, sp, %lo(STACK_BASE) + addi sp, sp, -8 + stw r0, 0(sp) + stw r0, 4(sp) + mov fp, sp + + /* Set the global pointer */ + movhi r26, %hi(_gp) + ori r26, r26, %lo(_gp) + + /* + * Call board_init -- never returns + */ + movhi r4, %hi(start_barebox@h) + ori r4, r4, %lo(start_barebox@h) + callr r4 + + /* NEVER RETURNS -- but branch to the _start just + * in case ;-) + */ + br _start + diff --git a/arch/nios2/cpu/traps.c b/arch/nios2/cpu/traps.c new file mode 100644 index 0000000..f1d6450 --- /dev/null +++ b/arch/nios2/cpu/traps.c @@ -0,0 +1,43 @@ +/* + * (C) Copyright 2004, Psyent Corporation + * Scott McNutt + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include + +void trap_handler (struct pt_regs *regs) +{ + /* Just issue warning */ + printf("\n\n*** WARNING: unimplemented trap @ %08x\n\n", + regs->reg[29] - 4); +} + +void soft_emulation(struct pt_regs *regs) +{ + /* TODO: Software emulation of mul/div etc. Until this is + * implemented, generate warning and hang. + */ + printf("\n\n*** ERROR: unimplemented instruction @ %08x\n", + regs->reg[29] - 4); + + hang(); +} diff --git a/arch/nios2/include/asm/barebox.h b/arch/nios2/include/asm/barebox.h new file mode 100644 index 0000000..9dd1df8 --- /dev/null +++ b/arch/nios2/include/asm/barebox.h @@ -0,0 +1,4 @@ +#ifndef _ASM_BAREBOX_H_ +#define _ASM_BAREBOX_H_ + +#endif /* _ASM_BAREBOX_H_ */ diff --git a/arch/nios2/include/asm/bitops.h b/arch/nios2/include/asm/bitops.h new file mode 100644 index 0000000..ab0e3d5 --- /dev/null +++ b/arch/nios2/include/asm/bitops.h @@ -0,0 +1,4 @@ +#ifndef _ASM_BITOPS_H +#define _ASM_BITOPS_H + +#endif /* _ASM_BITOPS_H */ diff --git a/arch/nios2/include/asm/bitsperlong.h b/arch/nios2/include/asm/bitsperlong.h new file mode 100644 index 0000000..6dc0bb0 --- /dev/null +++ b/arch/nios2/include/asm/bitsperlong.h @@ -0,0 +1 @@ +#include diff --git a/arch/nios2/include/asm/byteorder.h b/arch/nios2/include/asm/byteorder.h new file mode 100644 index 0000000..9558416 --- /dev/null +++ b/arch/nios2/include/asm/byteorder.h @@ -0,0 +1 @@ +#include diff --git a/arch/nios2/include/asm/cache.h b/arch/nios2/include/asm/cache.h new file mode 100644 index 0000000..d9de8f9 --- /dev/null +++ b/arch/nios2/include/asm/cache.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2003 Microtronix Datacom Ltd. + * Copyright (C) 2000-2002 Greg Ungerer + * + * Ported from m68knommu. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_NIOS2_CACHEFLUSH_H +#define _ASM_NIOS2_CACHEFLUSH_H + +void flush_cache_all(void); +void flush_dcache_all(void); +void flush_icache_all(void); +void flush_icache_range(unsigned long start, unsigned long end); +void flush_dcache_range(unsigned long start, unsigned long end); + +#endif /* _ASM_NIOS2_CACHEFLUSH_H */ diff --git a/arch/nios2/include/asm/common.h b/arch/nios2/include/asm/common.h new file mode 100644 index 0000000..027dca2 --- /dev/null +++ b/arch/nios2/include/asm/common.h @@ -0,0 +1,4 @@ +#ifndef _ASM_COMMON_H +#define __ASM_COMMON_H + +#endif /* _ASM_COMMON_H */ diff --git a/arch/nios2/include/asm/dma-mapping.h b/arch/nios2/include/asm/dma-mapping.h new file mode 100644 index 0000000..49ebf79 --- /dev/null +++ b/arch/nios2/include/asm/dma-mapping.h @@ -0,0 +1,25 @@ +#ifndef __ASM_NIOS2_DMA_MAPPING_H +#define __ASM_NIOS2_DMA_MAPPING_H + +#include + +/* dma_alloc_coherent() return cache-line aligned allocation which is mapped + * to uncached io region. + * + * IO_REGION_BASE should be defined in board config header file + * 0x80000000 for nommu, 0xe0000000 for mmu + */ + +static inline void *dma_alloc_coherent(size_t len, unsigned long *handle) +{ + void *addr = malloc(len + DCACHE_LINE_SIZE); + if (!addr) + return 0; + flush_dcache_range((unsigned long)addr, len + DCACHE_LINE_SIZE); + *handle = ((unsigned long)addr + + (DCACHE_LINE_SIZE - 1)) & + ~(DCACHE_LINE_SIZE - 1) & ~(IO_REGION_BASE); + return (void *)(*handle | IO_REGION_BASE); +} + +#endif /* __ASM_NIOS2_DMA_MAPPING_H */ diff --git a/arch/nios2/include/asm/early_printf.h b/arch/nios2/include/asm/early_printf.h new file mode 100644 index 0000000..e483e34 --- /dev/null +++ b/arch/nios2/include/asm/early_printf.h @@ -0,0 +1,10 @@ +#ifndef _EARLY_PRINTF_ +#define _EARLY_PRINTF_ + +#include + +void early_putc(char ch); +void early_puts(const char *s); +int early_printf(const char *fmt, ...); + +#endif /* _EARLY_PRINTF_ */ diff --git a/arch/nios2/include/asm/elf.h b/arch/nios2/include/asm/elf.h new file mode 100644 index 0000000..6060e1e --- /dev/null +++ b/arch/nios2/include/asm/elf.h @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2011 Tobias Klauser + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_NIOS2_ELF_H +#define _ASM_NIOS2_ELF_H + +/* Relocation types */ +#define R_NIOS2_NONE 0 +#define R_NIOS2_S16 1 +#define R_NIOS2_U16 2 +#define R_NIOS2_PCREL16 3 +#define R_NIOS2_CALL26 4 +#define R_NIOS2_IMM5 5 +#define R_NIOS2_CACHE_OPX 6 +#define R_NIOS2_IMM6 7 +#define R_NIOS2_IMM8 8 +#define R_NIOS2_HI16 9 +#define R_NIOS2_LO16 10 +#define R_NIOS2_HIADJ16 11 +#define R_NIOS2_BFD_RELOC_32 12 +#define R_NIOS2_BFD_RELOC_16 13 +#define R_NIOS2_BFD_RELOC_8 14 +#define R_NIOS2_GPREL 15 +#define R_NIOS2_GNU_VTINHERIT 16 +#define R_NIOS2_GNU_VTENTRY 17 +#define R_NIOS2_UJMP 18 +#define R_NIOS2_CJMP 19 +#define R_NIOS2_CALLR 20 +#define R_NIOS2_ALIGN 21 +/* Keep this the last entry. */ +#define R_NIOS2_NUM 22 + +#include + +typedef unsigned long elf_greg_t; + +#define ELF_NGREG (sizeof(struct pt_regs) / sizeof(elf_greg_t)) +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; + +typedef unsigned long elf_fpregset_t; + +/* + * This is used to ensure we don't load something for the wrong architecture. + */ +#define elf_check_arch(x) ((x)->e_machine == EM_ALTERA_NIOS2) + +/* + * These are used to set parameters in the core dumps. + */ +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2LSB +#define ELF_ARCH EM_ALTERA_NIOS2 + +#define ELF_PLAT_INIT(_r, load_addr) + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + +/* This is the location that an ET_DYN program is loaded if exec'ed. Typical + use of this is to invoke "./ld.so someprog" to test out a new version of + the loader. We need to make sure that it is out of the way of the program + that it will "exec", and that there is sufficient room for the brk. */ + +#define ELF_ET_DYN_BASE 0xD0000000UL + +/* regs is struct pt_regs, pr_reg is elf_gregset_t (which is + now struct_user_regs, they are different) */ + +#ifdef CONFIG_MMU +#define ELF_CORE_COPY_REGS(pr_reg, regs) \ + do { \ + pr_reg[0] = regs->r8; \ + pr_reg[1] = regs->r9; \ + pr_reg[2] = regs->r10; \ + pr_reg[3] = regs->r11; \ + pr_reg[4] = regs->r12; \ + pr_reg[5] = regs->r13; \ + pr_reg[6] = regs->r14; \ + pr_reg[7] = regs->r15; \ + pr_reg[8] = regs->r1; \ + pr_reg[9] = regs->r2; \ + pr_reg[10] = regs->r3; \ + pr_reg[11] = regs->r4; \ + pr_reg[12] = regs->r5; \ + pr_reg[13] = regs->r6; \ + pr_reg[14] = regs->r7 \ + pr_reg[15] = regs->orig_r2; \ + pr_reg[16] = regs->ra; \ + pr_reg[17] = regs->fp; \ + pr_reg[18] = regs->sp; \ + pr_reg[19] = regs->gp; \ + pr_reg[20] = regs->estatus; \ + pr_reg[21] = regs->ea; \ + pr_reg[22] = regs->orig_r7; \ + { \ + struct switch_stack *sw = ((struct switch_stack *)regs) - 1; \ + pr_reg[23] = sw->r16; \ + pr_reg[24] = sw->r17; \ + pr_reg[25] = sw->r18; \ + pr_reg[26] = sw->r19; \ + pr_reg[27] = sw->r20; \ + pr_reg[28] = sw->r21; \ + pr_reg[29] = sw->r22; \ + pr_reg[30] = sw->r23; \ + pr_reg[31] = sw->fp; \ + pr_reg[32] = sw->gp; \ + pr_reg[33] = sw->ra; \ + } \ + } while (0) +#else +#define ELF_CORE_COPY_REGS(pr_reg, regs) \ + do { \ + pr_reg[0] = regs->r1; \ + pr_reg[1] = regs->r2; \ + pr_reg[2] = regs->r3; \ + pr_reg[3] = regs->r4; \ + pr_reg[4] = regs->r5; \ + pr_reg[5] = regs->r6; \ + pr_reg[6] = regs->r7; \ + pr_reg[7] = regs->r8; \ + pr_reg[8] = regs->r9; \ + pr_reg[9] = regs->r10; \ + pr_reg[10] = regs->r11; \ + pr_reg[11] = regs->r12; \ + pr_reg[12] = regs->r13; \ + pr_reg[13] = regs->r14; \ + pr_reg[14] = regs->r15; \ + pr_reg[23] = regs->sp; \ + pr_reg[26] = regs->estatus; \ + { \ + struct switch_stack *sw = ((struct switch_stack *)regs) - 1; \ + pr_reg[15] = sw->r16; \ + pr_reg[16] = sw->r17; \ + pr_reg[17] = sw->r18; \ + pr_reg[18] = sw->r19; \ + pr_reg[19] = sw->r20; \ + pr_reg[20] = sw->r21; \ + pr_reg[21] = sw->r22; \ + pr_reg[22] = sw->r23; \ + pr_reg[24] = sw->fp; \ + pr_reg[25] = sw->gp; \ + } \ + } while (0) + +#endif /* CONFIG_MMU */ + +/* This yields a mask that user programs can use to figure out what + instruction set this cpu supports. */ + +#define ELF_HWCAP (0) + +/* This yields a string that ld.so will use to load implementation + specific libraries for optimization. This is more specific in + intent than poking at uname or /proc/cpuinfo. */ + +#define ELF_PLATFORM (NULL) + +#define SET_PERSONALITY(ex) set_personality(PER_LINUX_32BIT) + +#endif diff --git a/arch/nios2/include/asm/int-ll64.h b/arch/nios2/include/asm/int-ll64.h new file mode 100644 index 0000000..f394147 --- /dev/null +++ b/arch/nios2/include/asm/int-ll64.h @@ -0,0 +1,78 @@ +/* + * asm-generic/int-ll64.h + * + * Integer declarations for architectures which use "long long" + * for 64-bit types. + */ + +#ifndef _ASM_GENERIC_INT_LL64_H +#define _ASM_GENERIC_INT_LL64_H + +#include + +#ifndef __ASSEMBLY__ +/* + * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the + * header files exported to user space + */ + +typedef __signed__ char __s8; +typedef unsigned char __u8; + +typedef __signed__ short __s16; +typedef unsigned short __u16; + +typedef __signed__ int __s32; +typedef unsigned int __u32; + +#ifdef __GNUC__ +__extension__ typedef __signed__ long long __s64; +__extension__ typedef unsigned long long __u64; +#else +typedef __signed__ long long __s64; +typedef unsigned long long __u64; +#endif + +#endif /* __ASSEMBLY__ */ + +#ifdef __KERNEL__ + +#ifndef __ASSEMBLY__ + +typedef signed char s8; +typedef unsigned char u8; + +typedef signed short s16; +typedef unsigned short u16; + +typedef signed int s32; +typedef unsigned int u32; + +typedef signed long long s64; +typedef unsigned long long u64; + +#define S8_C(x) x +#define U8_C(x) x ## U +#define S16_C(x) x +#define U16_C(x) x ## U +#define S32_C(x) x +#define U32_C(x) x ## U +#define S64_C(x) x ## LL +#define U64_C(x) x ## ULL + +#else /* __ASSEMBLY__ */ + +#define S8_C(x) x +#define U8_C(x) x +#define S16_C(x) x +#define U16_C(x) x +#define S32_C(x) x +#define U32_C(x) x +#define S64_C(x) x +#define U64_C(x) x + +#endif /* __ASSEMBLY__ */ + +#endif /* __KERNEL__ */ + +#endif /* _ASM_GENERIC_INT_LL64_H */ diff --git a/arch/nios2/include/asm/io.h b/arch/nios2/include/asm/io.h new file mode 100644 index 0000000..0d24205 --- /dev/null +++ b/arch/nios2/include/asm/io.h @@ -0,0 +1,52 @@ +/* + * (C) Copyright 2004, Psyent Corporation + * Scott McNutt + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __ASM_NIOS2_IO_H_ +#define __ASM_NIOS2_IO_H_ + +#define __raw_writeb(v, a) (*(volatile unsigned char *)(a) = (v)) +#define __raw_writew(v, a) (*(volatile unsigned short *)(a) = (v)) +#define __raw_writel(v, a) (*(volatile unsigned int *)(a) = (v)) + +#define __raw_readb(a) (*(volatile unsigned char *)(a)) +#define __raw_readw(a) (*(volatile unsigned short *)(a)) +#define __raw_readl(a) (*(volatile unsigned int *)(a)) + +#define readb(addr)\ + ({unsigned char val;\ + asm volatile("ldbio %0, 0(%1)" : "=r"(val) : "r" (addr)); val; }) +#define readw(addr)\ + ({unsigned short val;\ + asm volatile("ldhio %0, 0(%1)" : "=r"(val) : "r" (addr)); val; }) +#define readl(addr)\ + ({unsigned long val;\ + asm volatile("ldwio %0, 0(%1)" : "=r"(val) : "r" (addr)); val; }) + +#define writeb(val, addr)\ + asm volatile("stbio %0, 0(%1)" : : "r" (val), "r" (addr)) +#define writew(val, addr)\ + asm volatile ("sthio %0, 0(%1)" : : "r" (val), "r" (addr)) +#define writel(val, addr)\ + asm volatile("stwio %0, 0(%1)" : : "r" (val), "r" (addr)) + +#endif /* __ASM_NIOS2_IO_H_ */ diff --git a/arch/nios2/include/asm/nios2-io.h b/arch/nios2/include/asm/nios2-io.h new file mode 100644 index 0000000..d8a4c67 --- /dev/null +++ b/arch/nios2/include/asm/nios2-io.h @@ -0,0 +1,182 @@ +/* + * (C) Copyright 2004, Psyent Corporation + * Scott McNutt + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/************************************************************************* + * Altera Nios2 Standard Peripherals + ************************************************************************/ + +#ifndef __NIOS2IO_H__ +#define __NIOS2IO_H__ + +/*------------------------------------------------------------------------ + * UART (http://www.altera.com/literature/ds/ds_nios_uart.pdf) + *----------------------------------------------------------------------*/ +struct nios_uart { + unsigned rxdata; /* Rx data reg */ + unsigned txdata; /* Tx data reg */ + unsigned status; /* Status reg */ + unsigned control; /* Control reg */ + unsigned divisor; /* Baud rate divisor reg */ + unsigned endofpacket; /* End-of-packet reg */ +}; + +/* status register */ +#define NIOS_UART_PE (1 << 0) /* parity error */ +#define NIOS_UART_FE (1 << 1) /* frame error */ +#define NIOS_UART_BRK (1 << 2) /* break detect */ +#define NIOS_UART_ROE (1 << 3) /* rx overrun */ +#define NIOS_UART_TOE (1 << 4) /* tx overrun */ +#define NIOS_UART_TMT (1 << 5) /* tx empty */ +#define NIOS_UART_TRDY (1 << 6) /* tx ready */ +#define NIOS_UART_RRDY (1 << 7) /* rx ready */ +#define NIOS_UART_E (1 << 8) /* exception */ +#define NIOS_UART_DCTS (1 << 10) /* cts change */ +#define NIOS_UART_CTS (1 << 11) /* cts */ +#define NIOS_UART_EOP (1 << 12) /* eop detected */ + +/* control register */ +#define NIOS_UART_IPE (1 << 0) /* parity error int ena*/ +#define NIOS_UART_IFE (1 << 1) /* frame error int ena */ +#define NIOS_UART_IBRK (1 << 2) /* break detect int ena */ +#define NIOS_UART_IROE (1 << 3) /* rx overrun int ena */ +#define NIOS_UART_ITOE (1 << 4) /* tx overrun int ena */ +#define NIOS_UART_ITMT (1 << 5) /* tx empty int ena */ +#define NIOS_UART_ITRDY (1 << 6) /* tx ready int ena */ +#define NIOS_UART_IRRDY (1 << 7) /* rx ready int ena */ +#define NIOS_UART_IE (1 << 8) /* exception int ena */ +#define NIOS_UART_TBRK (1 << 9) /* transmit break */ +#define NIOS_UART_IDCTS (1 << 10) /* cts change int ena */ +#define NIOS_UART_RTS (1 << 11) /* rts */ +#define NIOS_UART_IEOP (1 << 12) /* eop detected int ena */ + + +/*------------------------------------------------------------------------ + * TIMER (http://www.altera.com/literature/ds/ds_nios_timer.pdf) + *----------------------------------------------------------------------*/ +struct nios_timer { + unsigned status; /* Timer status reg */ + unsigned control; /* Timer control reg */ + unsigned periodl; /* Timeout period low */ + unsigned periodh; /* Timeout period high */ + unsigned snapl; /* Snapshot low */ + unsigned snaph; /* Snapshot high */ +}; + +struct nios_timer_64 { + unsigned status; /* Timer status reg */ + unsigned control; /* Timer control reg */ + unsigned period0; /* Timeout period low */ + unsigned period1; /* Timeout period high */ + unsigned period2; /* Timeout period low */ + unsigned period3; /* Timeout period high */ + unsigned snap0; /* Snapshot low */ + unsigned snap1; /* Snapshot high */ + unsigned snap2; /* Snapshot low */ + unsigned snap3; /* Snapshot high */ +}; + +/* status register */ +#define NIOS_TIMER_TO (1 << 0) /* Timeout */ +#define NIOS_TIMER_RUN (1 << 1) /* Timer running */ + +/* control register */ +#define NIOS_TIMER_ITO (1 << 0) /* Timeout int ena */ +#define NIOS_TIMER_CONT (1 << 1) /* Continuous mode */ +#define NIOS_TIMER_START (1 << 2) /* Start timer */ +#define NIOS_TIMER_STOP (1 << 3) /* Stop timer */ + + +/*------------------------------------------------------------------------ + * PIO (http://www.altera.com/literature/ds/ds_nios_pio.pdf) + *----------------------------------------------------------------------*/ +struct nios_pio { + unsigned int data; /* Data value at each PIO in/out */ + unsigned int direction; /* Data direct. for each PIO bit */ + unsigned int interruptmask; /* Per-bit IRQ enable/disable */ + unsigned int edgecapture; /* Per-bit sync. edge detect & hold */ +}; + +/* direction register */ +#define NIOS_PIO_OUT (1) /* PIO bit is output */ +#define NIOS_PIO_IN (0) /* PIO bit is input */ + + +/*------------------------------------------------------------------------ + * SPI (http://www.altera.com/literature/ds/ds_nios_spi.pdf) + *----------------------------------------------------------------------*/ +struct nios_spi { + unsigned rxdata; /* Rx data reg */ + unsigned txdata; /* Tx data reg */ + unsigned status; /* Status reg */ + unsigned control; /* Control reg */ + unsigned reserved; /* (master only) */ + unsigned slaveselect; /* SPI slave select mask (master only) */ +}; + +/* status register */ +#define NIOS_SPI_ROE (1 << 3) /* rx overrun */ +#define NIOS_SPI_TOE (1 << 4) /* tx overrun */ +#define NIOS_SPI_TMT (1 << 5) /* tx empty */ +#define NIOS_SPI_TRDY (1 << 6) /* tx ready */ +#define NIOS_SPI_RRDY (1 << 7) /* rx ready */ +#define NIOS_SPI_E (1 << 8) /* exception */ + +/* control register */ +#define NIOS_SPI_IROE (1 << 3) /* rx overrun int ena */ +#define NIOS_SPI_ITOE (1 << 4) /* tx overrun int ena */ +#define NIOS_SPI_ITRDY (1 << 6) /* tx ready int ena */ +#define NIOS_SPI_IRRDY (1 << 7) /* rx ready int ena */ +#define NIOS_SPI_IE (1 << 8) /* exception int ena */ +#define NIOS_SPI_SSO (1 << 10) /* override SS_n output */ + +/*------------------------------------------------------------------------ + * JTAG UART + *----------------------------------------------------------------------*/ +struct nios_jtag { + unsigned data; /* Data register */ + unsigned control; /* Control register */ +}; + +/* data register */ +#define NIOS_JTAG_RVALID (1<<15) /* Read valid */ +#define NIOS_JTAG_DATA(d) ((d)&0x0ff) /* Read data */ +#define NIOS_JTAG_RAVAIL(d) ((d)>>16) /* Read space avail */ + +/* control register */ +#define NIOS_JTAG_RE (1 << 0) /* read intr enable */ +#define NIOS_JTAG_WE (1 << 1) /* write intr enable */ +#define NIOS_JTAG_RI (1 << 8) /* read intr pending */ +#define NIOS_JTAG_WI (1 << 9) /* write intr pending*/ +#define NIOS_JTAG_AC (1 << 10) /* activity indicator */ +#define NIOS_JTAG_RRDY (1 << 12) /* read available */ +#define NIOS_JTAG_WSPACE(d) ((d)>>16) /* Write space avail */ + +/*------------------------------------------------------------------------ + * SYSTEM ID + *----------------------------------------------------------------------*/ +struct nios_sysid { + unsigned id; /* The system build id*/ + unsigned timestamp; /* Timestamp */ +}; + +#endif /* __NIOS2IO_H__ */ diff --git a/arch/nios2/include/asm/nios2.h b/arch/nios2/include/asm/nios2.h new file mode 100644 index 0000000..7c9eb65 --- /dev/null +++ b/arch/nios2/include/asm/nios2.h @@ -0,0 +1,63 @@ +/* + * (C) Copyright 2004, Psyent Corporation + * Scott McNutt + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __NIOS2_H__ +#define __NIOS2_H__ + +/*------------------------------------------------------------------------ + * Control registers -- use with wrctl() & rdctl() + *----------------------------------------------------------------------*/ +#define CTL_STATUS 0 /* Processor status reg */ +#define CTL_ESTATUS 1 /* Exception status reg */ +#define CTL_BSTATUS 2 /* Break status reg */ +#define CTL_IENABLE 3 /* Interrut enable reg */ +#define CTL_IPENDING 4 /* Interrut pending reg */ + +/*------------------------------------------------------------------------ + * Access to control regs + *----------------------------------------------------------------------*/ +#define _str_(x) #x + +#define rdctl(reg)\ + ({unsigned int val;\ + asm volatile("rdctl %0, ctl" _str_(reg)\ + : "=r" (val)); val; }) + +#define wrctl(reg, val)\ + asm volatile("wrctl ctl" _str_(reg) ",%0"\ + : : "r" (val)) + +/*------------------------------------------------------------------------ + * Control reg bit masks + *----------------------------------------------------------------------*/ +#define STATUS_IE (1<<0) /* Interrupt enable */ +#define STATUS_U (1<<1) /* User-mode */ + +/*------------------------------------------------------------------------ + * Bit-31 Cache bypass -- only valid for data access. When data cache + * is not implemented, bit 31 is ignored for compatibility. + *----------------------------------------------------------------------*/ +#define CACHE_BYPASS(a) ((a) | 0x80000000) +#define CACHE_NO_BYPASS(a) ((a) & ~0x80000000) + +#endif /* __NIOS2_H__ */ diff --git a/arch/nios2/include/asm/opcodes.h b/arch/nios2/include/asm/opcodes.h new file mode 100644 index 0000000..211f8ba --- /dev/null +++ b/arch/nios2/include/asm/opcodes.h @@ -0,0 +1,131 @@ +/* + * (C) Copyright 2004, Psyent Corporation + * Scott McNutt + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __ASM_NIOS2_OPCODES_H_ +#define __ASM_NIOS2_OPCODES_H_ + +#define OPCODE_OP(inst) ((inst) & 0x3f) +#define OPCODE_OPX(inst) (((inst)>>11) & 0x3f) +#define OPCODE_RA(inst) (((inst)>>27) & 01f) +#define OPCODE_RB(inst) (((inst)>>22) & 01f) +#define OPCODE_RC(inst) (((inst)>>17) & 01f) + +/* I-TYPE (immediate) and J-TYPE (jump) opcodes + */ +#define OPCODE_CALL 0x00 +#define OPCODE_LDBU 0x03 +#define OPCODE_ADDI 0x04 +#define OPCODE_STB 0x05 +#define OPCODE_BR 0x06 +#define OPCODE_LDB 0x07 +#define OPCODE_CMPGEI 0x08 +#define OPCODE_LDHU 0x0B +#define OPCODE_ANDI 0x0C +#define OPCODE_STH 0x0D +#define OPCODE_BGE 0x0E +#define OPCODE_LDH 0x0F +#define OPCODE_CMPLTI 0x10 +#define OPCODE_XORI 0x1C +#define OPCODE_ORI 0x14 +#define OPCODE_STW 0x15 +#define OPCODE_BLT 0x16 +#define OPCODE_LDW 0x17 +#define OPCODE_CMPNEI 0x18 +#define OPCODE_BNE 0x1E +#define OPCODE_CMPEQI 0x20 +#define OPCODE_LDBUIO 0x23 +#define OPCODE_MULI 0x24 +#define OPCODE_STBIO 0x25 +#define OPCODE_BEQ 0x26 +#define OPCODE_LDBIO 0x27 +#define OPCODE_CMPGEUI 0x28 +#define OPCODE_ANDHI 0x2C +#define OPCODE_STHIO 0x2D +#define OPCODE_BGEU 0x2E +#define OPCODE_LDHIO 0x2F +#define OPCODE_CMPLTUI 0x30 +#define OPCODE_CUSTOM 0x32 +#define OPCODE_INITD 0x33 +#define OPCODE_ORHI 0x34 +#define OPCODE_STWIO 0x35 +#define OPCODE_BLTU 0x36 +#define OPCODE_LDWIO 0x37 +#define OPCODE_RTYPE 0x3A +#define OPCODE_LDHUIO 0x2B +#define OPCODE_FLUSHD 0x3B +#define OPCODE_XORHI 0x3C + +/* R-Type (register) OPX field encodings + */ +#define OPCODE_ERET 0x01 +#define OPCODE_ROLI 0x02 +#define OPCODE_ROL 0x03 +#define OPCODE_FLUSHP 0x04 +#define OPCODE_RET 0x05 +#define OPCODE_NOR 0x06 +#define OPCODE_MULXUU 0x07 +#define OPCODE_CMPGE 0x08 +#define OPCODE_BRET 0x09 +#define OPCODE_ROR 0x0B +#define OPCODE_FLUSHI 0x0C +#define OPCODE_JMP 0x0D +#define OPCODE_AND 0x0E + +#define OPCODE_CMPLT 0x10 +#define OPCODE_SLLI 0x12 +#define OPCODE_SLL 0x13 +#define OPCODE_OR 0x16 +#define OPCODE_MULXSU 0x17 +#define OPCODE_CMPNE 0x18 +#define OPCODE_SRLI 0x1A +#define OPCODE_SRL 0x1B +#define OPCODE_NEXTPC 0x1C +#define OPCODE_CALLR 0x1D +#define OPCODE_XOR 0x1E +#define OPCODE_MULXSS 0x1F + +#define OPCODE_CMPEQ 0x20 +#define OPCODE_CMPLTU 0x30 +#define OPCODE_ADD 0x31 +#define OPCODE_DIVU 0x24 +#define OPCODE_DIV 0x25 +#define OPCODE_RDCTL 0x26 +#define OPCODE_MUL 0x27 +#define OPCODE_CMPGEU 0x28 +#define OPCODE_TRAP 0x2D +#define OPCODE_WRCTL 0x2E + +#define OPCODE_BREAK 0x34 +#define OPCODE_SYNC 0x36 +#define OPCODE_INITI 0x29 +#define OPCODE_SUB 0x39 +#define OPCODE_SRAI 0x3A +#define OPCODE_SRA 0x3B + +/*Full instruction encodings for R-Type, without the R's ;-) + * + * TODO: BREAK, BRET, ERET, RET, SYNC (as needed) + */ +#define OPC_TRAP 0x003b683a + +#endif /* __ASM_NIOS2_OPCODES_H_ */ diff --git a/arch/nios2/include/asm/posix_types.h b/arch/nios2/include/asm/posix_types.h new file mode 100644 index 0000000..12906b3 --- /dev/null +++ b/arch/nios2/include/asm/posix_types.h @@ -0,0 +1,77 @@ +/* + * arch/arm/include/asm/posix_types.h + * + * Copyright (C) 1996-1998 Russell King. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Changelog: + * 27-06-1996 RMK Created + */ +#ifndef __ARCH_ARM_POSIX_TYPES_H +#define __ARCH_ARM_POSIX_TYPES_H + +/* + * This file is generally used by user-level software, so you need to + * be a little careful about namespace pollution etc. Also, we cannot + * assume GCC is being used. + */ + +typedef unsigned long __kernel_ino_t; +typedef unsigned short __kernel_mode_t; +typedef unsigned short __kernel_nlink_t; +typedef long __kernel_off_t; +typedef int __kernel_pid_t; +typedef unsigned short __kernel_ipc_pid_t; +typedef unsigned short __kernel_uid_t; +typedef unsigned short __kernel_gid_t; +typedef unsigned int __kernel_size_t; +typedef int __kernel_ssize_t; +typedef int __kernel_ptrdiff_t; +typedef long __kernel_time_t; +typedef long __kernel_suseconds_t; +typedef long __kernel_clock_t; +typedef int __kernel_timer_t; +typedef int __kernel_clockid_t; +typedef int __kernel_daddr_t; +typedef char * __kernel_caddr_t; +typedef unsigned short __kernel_uid16_t; +typedef unsigned short __kernel_gid16_t; +typedef unsigned int __kernel_uid32_t; +typedef unsigned int __kernel_gid32_t; + +typedef unsigned short __kernel_old_uid_t; +typedef unsigned short __kernel_old_gid_t; +typedef unsigned short __kernel_old_dev_t; + +#ifdef __GNUC__ +typedef long long __kernel_loff_t; +#endif + +typedef struct { + int val[2]; +} __kernel_fsid_t; + +#if defined(__KERNEL__) + +#undef __FD_SET +#define __FD_SET(fd, fdsetp) \ + (((fd_set *)(fdsetp))->fds_bits[(fd) >> 5] |= (1<<((fd) & 31))) + +#undef __FD_CLR +#define __FD_CLR(fd, fdsetp) \ + (((fd_set *)(fdsetp))->fds_bits[(fd) >> 5] &= ~(1<<((fd) & 31))) + +#undef __FD_ISSET +#define __FD_ISSET(fd, fdsetp) \ + ((((fd_set *)(fdsetp))->fds_bits[(fd) >> 5] & (1<<((fd) & 31))) != 0) + +#undef __FD_ZERO +#define __FD_ZERO(fdsetp) \ + (memset(fdsetp, 0, sizeof(*(fd_set *)(fdsetp)))) + +#endif + +#endif diff --git a/arch/nios2/include/asm/ptrace.h b/arch/nios2/include/asm/ptrace.h new file mode 100644 index 0000000..5430880 --- /dev/null +++ b/arch/nios2/include/asm/ptrace.h @@ -0,0 +1,33 @@ +/* + * (C) Copyright 2004, Psyent Corporation + * Scott McNutt + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __ASM_NIOS2_PTRACE_H_ +#define __ASM_NIOS2_PTRACE_H_ + +struct pt_regs { + unsigned reg[32]; + unsigned status; +}; + + +#endif /* __ASM_NIOS2_PTRACE_H_ */ diff --git a/arch/nios2/include/asm/sections.h b/arch/nios2/include/asm/sections.h new file mode 100644 index 0000000..2b8c516 --- /dev/null +++ b/arch/nios2/include/asm/sections.h @@ -0,0 +1 @@ +#include diff --git a/arch/nios2/include/asm/string.h b/arch/nios2/include/asm/string.h new file mode 100644 index 0000000..7d150af --- /dev/null +++ b/arch/nios2/include/asm/string.h @@ -0,0 +1,47 @@ +/* + * (C) Copyright 2004, Psyent Corporation + * Scott McNutt + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#ifndef __ASM_NIOS2_STRING_H_ +#define __ASM_NIOS2_STRING_H_ +/* +#undef __HAVE_ARCH_STRRCHR +extern char *strrchr(const char * s, int c); + +#undef __HAVE_ARCH_STRCHR +extern char *strchr(const char * s, int c); +*/ +#undef __HAVE_ARCH_MEMCPY +extern void *memcpy(void *, const void *, __kernel_size_t); + +#undef __HAVE_ARCH_MEMMOVE +extern void *memmove(void *, const void *, __kernel_size_t); + +#undef __HAVE_ARCH_MEMCHR +extern void *memchr(const void *, int, __kernel_size_t); + +#undef __HAVE_ARCH_MEMSET +extern void *memset(void *, int, __kernel_size_t); + +#undef __HAVE_ARCH_MEMZERO +extern void memzero(void *ptr, __kernel_size_t n); + +#endif /* __ASM_NIOS2_STRING_H_ */ diff --git a/arch/nios2/include/asm/swab.h b/arch/nios2/include/asm/swab.h new file mode 100644 index 0000000..b07e1d5 --- /dev/null +++ b/arch/nios2/include/asm/swab.h @@ -0,0 +1,4 @@ +#ifndef _ASM_SWAB_H +#define _ASM_SWAB_H + +#endif /* _ASM_SWAB_H */ diff --git a/arch/nios2/include/asm/system.h b/arch/nios2/include/asm/system.h new file mode 100644 index 0000000..086d92b --- /dev/null +++ b/arch/nios2/include/asm/system.h @@ -0,0 +1,64 @@ +/* + * (C) Copyright 2004, Psyent Corporation + * Scott McNutt + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#ifndef __ASM_NIOS2_SYSTEM_H_ +#define __ASM_NIOS2_SYSTEM_H_ + +#define local_irq_enable() __asm__ __volatile__ ( \ + "rdctl r8, status\n" \ + "ori r8, r8, 1\n" \ + "wrctl status, r8\n" \ + : : : "r8") + +#define local_irq_disable() __asm__ __volatile__ ( \ + "rdctl r8, status\n" \ + "andi r8, r8, 0xfffe\n" \ + "wrctl status, r8\n" \ + : : : "r8") + +#define local_save_flags(x) __asm__ __volatile__ ( \ + "rdctl r8, status\n" \ + "mov %0, r8\n" \ + : "=r" (x) : : "r8", "memory") + +#define local_irq_restore(x) __asm__ __volatile__ ( \ + "mov r8, %0\n" \ + "wrctl status, r8\n" \ + : : "r" (x) : "r8", "memory") + +/* For spinlocks etc */ +#define local_irq_save(x) do { local_save_flags(x); local_irq_disable(); } \ + while (0) + +#define irqs_disabled() \ +({ \ + unsigned long flags; \ + local_save_flags(flags); \ + ((flags & NIOS2_STATUS_PIE_MSK) == 0x0); \ +}) + +/* indirect call to go beyond 256MB limitation of toolchain */ +#define nios2_callr(addr) __asm__ __volatile__ ( \ + "callr %0" \ + : : "r" (addr)) + +#endif /* __ASM_NIOS2_SYSTEM_H */ diff --git a/arch/nios2/include/asm/types.h b/arch/nios2/include/asm/types.h new file mode 100644 index 0000000..1f613d1 --- /dev/null +++ b/arch/nios2/include/asm/types.h @@ -0,0 +1,7 @@ +#ifndef __ASM_TYPES_H +#define __ASM_TYPES_H + +#include + +#endif + diff --git a/arch/nios2/lib/Makefile b/arch/nios2/lib/Makefile new file mode 100644 index 0000000..8776c61 --- /dev/null +++ b/arch/nios2/lib/Makefile @@ -0,0 +1,6 @@ +obj-y += board.o +obj-y += libgcc.o +obj-y += clock.o +obj-y += cache.o +obj-$(CONFIG_EARLY_PRINTF) += early_printf.o + diff --git a/arch/nios2/lib/board.c b/arch/nios2/lib/board.c new file mode 100644 index 0000000..7cbff40 --- /dev/null +++ b/arch/nios2/lib/board.c @@ -0,0 +1,47 @@ +/* + * (C) Copyright 2011 - Franck JULLIEN + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include + +int altera_mem_malloc_init(void) +{ + + mem_malloc_init((void *)(NIOS_SOPC_TEXT_BASE - MALLOC_SIZE), + (void *)(NIOS_SOPC_TEXT_BASE)); + + return 0; +} + +core_initcall(altera_mem_malloc_init); + +void arch_shutdown(void) +{ +#ifdef CONFIG_USE_IRQ + disable_interrupts(); +#endif +} + diff --git a/arch/nios2/lib/cache.c b/arch/nios2/lib/cache.c new file mode 100644 index 0000000..8d28221 --- /dev/null +++ b/arch/nios2/lib/cache.c @@ -0,0 +1,77 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2009, Wind River Systems Inc + * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com + */ + +#include + +static void __flush_dcache(unsigned long start, unsigned long end) +{ + unsigned long addr; + + start &= ~(DCACHE_LINE_SIZE - 1); + end += (DCACHE_LINE_SIZE - 1); + end &= ~(DCACHE_LINE_SIZE - 1); + + if (end > start + DCACHE_SIZE) + end = start + DCACHE_SIZE; + + for (addr = start; addr < end; addr += DCACHE_LINE_SIZE) { + __asm__ __volatile__ (" flushd 0(%0)\n" + : /* Outputs */ + : /* Inputs */ "r"(addr) + /* : No clobber */); + } +} + +static void __flush_icache(unsigned long start, unsigned long end) +{ + unsigned long addr; + + start &= ~(ICACHE_LINE_SIZE - 1); + end += (ICACHE_LINE_SIZE - 1); + end &= ~(ICACHE_LINE_SIZE - 1); + + if (end > start + ICACHE_SIZE) + end = start + ICACHE_SIZE; + + for (addr = start; addr < end; addr += ICACHE_LINE_SIZE) { + __asm__ __volatile__ (" flushi %0\n" + : /* Outputs */ + : /* Inputs */ "r"(addr) + /* : No clobber */); + } + __asm__ __volatile(" flushp\n"); +} + +void flush_dcache_all(void) +{ + __flush_dcache(0, DCACHE_SIZE); +} + +void flush_icache_all(void) +{ + __flush_icache(0, ICACHE_SIZE); +} + +void flush_cache_all(void) +{ + flush_dcache_all(); + flush_icache_all(); +} + +void flush_icache_range(unsigned long start, unsigned long end) +{ + __flush_icache(start, end); +} + +void flush_dcache_range(unsigned long start, unsigned long end) +{ + __flush_dcache(start, end); + /* FIXME: Maybe we should remove __flush_icache ? */ + __flush_icache(start, end); +} diff --git a/arch/nios2/lib/clock.c b/arch/nios2/lib/clock.c new file mode 100644 index 0000000..05008be --- /dev/null +++ b/arch/nios2/lib/clock.c @@ -0,0 +1,62 @@ +/* + * (C) Copyright 2011 - Franck JULLIEN + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +static struct nios_timer *timer = (struct nios_timer *)NIOS_SOPC_TIMER_BASE; + +static uint64_t nios_clocksource_read(void) +{ + uint64_t value; + + writew(0x5555, &timer->snapl); /* Dummy value*/ + value = (uint64_t)((readw(&timer->snaph) << 16) + readw(&timer->snapl)); + + return ~value; +} + +static struct clocksource cs = { + .read = nios_clocksource_read, + .mask = 0xffffffff, + .shift = 12, +}; + +static int clocksource_init(void) +{ + writew(0, &timer->control); + writew(0xFFFF, &timer->periodl); + writew(0xFFFF, &timer->periodh); + writew(NIOS_TIMER_CONT | NIOS_TIMER_START, &timer->control); + + cs.mult = clocksource_hz2mult(NIOS_SOPC_TIMER_FREQ, cs.shift); + + init_clock(&cs); + + return 0; +} + +core_initcall(clocksource_init); + diff --git a/arch/nios2/lib/early_printf.c b/arch/nios2/lib/early_printf.c new file mode 100644 index 0000000..637bb73 --- /dev/null +++ b/arch/nios2/lib/early_printf.c @@ -0,0 +1,56 @@ +/* + * (C) Copyright 2011 - Franck JULLIEN + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include +#include + +void early_putc(char ch) +{ + struct nios_uart *uart = (struct nios_uart *)NIOS_SOPC_UART_BASE; + + while ((readl(&uart->status) & NIOS_UART_TRDY) == 0); + writel((unsigned char)ch, &uart->txdata); +} + +void early_puts(const char *s) +{ + while (*s != 0) + early_putc(*s++); +} + +int early_printf(const char *fmt, ...) +{ + va_list args; + uint i; + char printbuffer[50]; + + va_start(args, fmt); + + i = vsprintf(printbuffer, fmt, args); + va_end(args); + + early_puts(printbuffer); + + return 0; +} diff --git a/arch/nios2/lib/libgcc.c b/arch/nios2/lib/libgcc.c new file mode 100644 index 0000000..27c899f --- /dev/null +++ b/arch/nios2/lib/libgcc.c @@ -0,0 +1,527 @@ +/* + * This file is part of GNU CC. + * + * GNU CC is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * GNU CC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with GNU CC; see the file COPYING. If not, write + * to the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#define W_TYPE_SIZE 32 +#define BITS_PER_UNIT 8 + +typedef unsigned int UWtype; +typedef unsigned int UHWtype; +typedef unsigned long long UDWtype; + +typedef unsigned char UQItype; +typedef long SItype; +typedef unsigned long USItype; +typedef long long DItype; +typedef unsigned long long DSItype; + +#include "longlong.h" + +typedef int word_type; +typedef long Wtype; +typedef long long DWtype; + +struct DWstruct { Wtype low, high; }; + +typedef union { + struct DWstruct s; + DWtype ll; +} DWunion; + +const UQItype __clz_tab[256] = { + 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 +}; + + +DWtype __ashldi3(DWtype u, word_type b) +{ + const DWunion uu = {.ll = u}; + const word_type bm = (sizeof(Wtype) * BITS_PER_UNIT) - b; + DWunion w; + UWtype carries; + + if (b == 0) + return u; + + if (bm <= 0) { + w.s.low = 0; + w.s.high = (UWtype) uu.s.low << -bm; + } else { + carries = (UWtype) uu.s.low >> bm; + w.s.low = (UWtype) uu.s.low << b; + w.s.high = ((UWtype) uu.s.high << b) | carries; + } + + return w.ll; +} + +DWtype __ashrdi3(DWtype u, word_type b) +{ + const DWunion uu = {.ll = u}; + const word_type bm = (sizeof(Wtype) * BITS_PER_UNIT) - b; + DWunion w; + UWtype carries; + + if (b == 0) + return u; + + if (bm <= 0) { + w.s.high = uu.s.high >> (sizeof(Wtype) * BITS_PER_UNIT - 1); + w.s.low = uu.s.high >> -bm; + } else { + carries = (UWtype) uu.s.high << bm; + w.s.high = uu.s.high >> b; + w.s.low = ((UWtype) uu.s.low >> b) | carries; + } + + return w.ll; +} + +DWtype __lshrdi3(DWtype u, word_type b) +{ + const DWunion uu = {.ll = u}; + const word_type bm = (sizeof(Wtype) * BITS_PER_UNIT) - b; + DWunion w; + UWtype carries; + + if (b == 0) + return u; + + if (bm <= 0) { + w.s.high = 0; + w.s.low = (UWtype) uu.s.high >> -bm; + } else { + carries = (UWtype) uu.s.high << bm; + w.s.high = (UWtype) uu.s.high >> b; + w.s.low = ((UWtype) uu.s.low >> b) | carries; + } + + return w.ll; +} + +word_type __cmpdi2(DWtype a, DWtype b) +{ + const DWunion au = {.ll = a}; + const DWunion bu = {.ll = b}; + + if (au.s.high < bu.s.high) + return 0; + else if (au.s.high > bu.s.high) + return 2; + + if ((UWtype) au.s.low < (UWtype) bu.s.low) + return 0; + else if ((UWtype) au.s.low > (UWtype) bu.s.low) + return 2; + + return 1; +} + +UDWtype __udivmoddi4(UDWtype n, UDWtype d, UDWtype *rp) +{ + const DWunion nn = {.ll = n}; + const DWunion dd = {.ll = d}; + + DWunion rr; + UWtype d0, d1, n0, n1, n2; + UWtype q0, q1; + UWtype b, bm; + + DWunion ww; + + d0 = dd.s.low; + d1 = dd.s.high; + n0 = nn.s.low; + n1 = nn.s.high; + +#if !UDIV_NEEDS_NORMALIZATION + if (d1 == 0) { + if (d0 > n1) { + udiv_qrnnd(q0, n0, n1, n0, d0); + q1 = 0; + } else { + if (d0 == 0) + d0 = 1 / d0; /* Divide intentionally by zero.*/ + udiv_qrnnd(q1, n1, 0, n1, d0); + udiv_qrnnd(q0, n0, n1, n0, d0); + /* Remainder in n0. */ + } + + if (rp != 0) { + rr.s.low = n0; + rr.s.high = 0; + *rp = rr.ll; + } + } + +#else /* UDIV_NEEDS_NORMALIZATION */ + + if (d1 == 0) { + if (d0 > n1) { + count_leading_zeros(bm, d0); + if (bm != 0) { + /* Normalize, i.e. make the most significant + bit of the denominator set. */ + d0 = d0 << bm; + n1 = (n1 << bm) | (n0 >> (W_TYPE_SIZE - bm)); + n0 = n0 << bm; + } + + udiv_qrnnd(q0, n0, n1, n0, d0); + q1 = 0; + /* Remainder in n0 >> bm. */ + } else { /* qq = NN / 0d */ + if (d0 == 0) + d0 = 1 / d0; /* Divide intentionally by zero. */ + + count_leading_zeros(bm, d0); + + if (bm == 0) { + /* From (n1 >= d0) /\ (the most significant bit + of d0 is set), conclude (the most significant + bit of n1 is set) /\ (the leading quotient digit + q1 = 1). + + This special case is necessary, not an + optimization.(Shifts counts of W_TYPE_SIZE are + undefined.) */ + + n1 -= d0; + q1 = 1; + } else { /* Normalize. */ + b = W_TYPE_SIZE - bm; + + d0 = d0 << bm; + n2 = n1 >> b; + n1 = (n1 << bm) | (n0 >> b); + n0 = n0 << bm; + + udiv_qrnnd(q1, n1, n2, n1, d0); + } + + /* n1 != d0... */ + udiv_qrnnd(q0, n0, n1, n0, d0); + } + + if (rp != 0) { + rr.s.low = n0 >> bm; + rr.s.high = 0; + *rp = rr.ll; + } + } +#endif /* UDIV_NEEDS_NORMALIZATION */ + + else { + if (d1 > n1) { /* 00 = nn / DD */ + q0 = 0; + q1 = 0; + /* Remainder in n1n0. */ + if (rp != 0) { + rr.s.low = n0; + rr.s.high = n1; + *rp = rr.ll; + } + } else { /* 0q = NN / dd */ + count_leading_zeros(bm, d1); + if (bm == 0) { + /* From (n1 >= d1) /\ (the most significant bit + of d1 is set), conclude (the most significant + bit of n1 is set) /\ (the quotient digit q0 = 0 + or 1). + + This special case is necessary, + not an optimization. */ + + /* The condition on the next line takes + advantage of that n1 >= d1 (true due to program + flow). */ + + if (n1 > d1 || n0 >= d0) { + q0 = 1; + sub_ddmmss(n1, n0, n1, n0, d1, d0); + } else + q0 = 0; + + q1 = 0; + + if (rp != 0) { + rr.s.low = n0; + rr.s.high = n1; + *rp = rr.ll; + } + } else { + UWtype m1, m0; + /* Normalize. */ + b = W_TYPE_SIZE - bm; + d1 = (d1 << bm) | (d0 >> b); + d0 = d0 << bm; + n2 = n1 >> b; + n1 = (n1 << bm) | (n0 >> b); + n0 = n0 << bm; + udiv_qrnnd(q0, n1, n2, n1, d1); + umul_ppmm(m1, m0, q0, d0); + + if (m1 > n1 || (m1 == n1 && m0 > n0)) { + q0--; + sub_ddmmss(m1, m0, m1, m0, d1, d0); + } + + q1 = 0; + + /* Remainder in (n1n0 - m1m0) >> bm. */ + if (rp != 0) { + sub_ddmmss(n1, n0, n1, n0, m1, m0); + rr.s.low = (n1 << b) | (n0 >> bm); + rr.s.high = n1 >> bm; + *rp = rr.ll; + } + } + } + } + + ww.s.low = q0; + ww.s.high = q1; + + return ww.ll; +} + +DWtype __divdi3(DWtype u, DWtype v) +{ + word_type c = 0; + DWunion uu = {.ll = u}; + DWunion vv = {.ll = v}; + DWtype w; + + if (uu.s.high < 0) + c = ~c, + + uu.ll = -uu.ll; + + if (vv.s.high < 0) + c = ~c, + + vv.ll = -vv.ll; + + w = __udivmoddi4(uu.ll, vv.ll, (UDWtype *) 0); + + if (c) + w = -w; + + return w; +} + +DWtype __negdi2(DWtype u) +{ + const DWunion uu = {.ll = u}; + const DWunion w = { {.low = -uu.s.low, + .high = -uu.s.high - ((UWtype) -uu.s.low > 0) } }; + + return w.ll; +} + + +DWtype __muldi3(DWtype u, DWtype v) +{ + const DWunion uu = {.ll = u}; + const DWunion vv = {.ll = v}; + DWunion w = {.ll = __umulsidi3(uu.s.low, vv.s.low)}; + + w.s.high += ((UWtype) uu.s.low * (UWtype) vv.s.high + + (UWtype) uu.s.high * (UWtype) vv.s.low); + + return w.ll; +} + +DWtype __moddi3(DWtype u, DWtype v) +{ + word_type c = 0; + DWunion uu = {.ll = u}; + DWunion vv = {.ll = v}; + DWtype w; + + if (uu.s.high < 0) + c = ~c, + uu.ll = -uu.ll; + + if (vv.s.high < 0) + vv.ll = -vv.ll; + + (void) __udivmoddi4(uu.ll, vv.ll, (UDWtype *)&w); + + if (c) + w = -w; + + return w; +} + +word_type __ucmpdi2(DWtype a, DWtype b) +{ + const DWunion au = {.ll = a}; + const DWunion bu = {.ll = b}; + + if ((UWtype) au.s.high < (UWtype) bu.s.high) + return 0; + else if ((UWtype) au.s.high > (UWtype) bu.s.high) + return 2; + if ((UWtype) au.s.low < (UWtype) bu.s.low) + return 0; + else if ((UWtype) au.s.low > (UWtype) bu.s.low) + return 2; + return 1; +} + + +UDWtype __udivdi3(UDWtype n, UDWtype d) +{ + return __udivmoddi4(n, d, (UDWtype *) 0); +} + +UDWtype __umoddi3(UDWtype u, UDWtype v) +{ + UDWtype w; + (void) __udivmoddi4(u, v, &w); + + return w; +} + +static USItype udivmodsi4(USItype num, USItype den, word_type modwanted) +{ + USItype bit = 1; + USItype res = 0; + + while (den < num && bit && !(den & (1L<<31))) { + den <<= 1; + bit <<= 1; + } + while (bit) { + if (num >= den) { + num -= den; + res |= bit; + } + + bit >>= 1; + den >>= 1; + } + + if (modwanted) + return num; + + return res; +} + +SItype __divsi3(SItype a, SItype b) +{ + word_type neg = 0; + SItype res; + + if (a < 0) { + a = -a; + neg = !neg; + } + + if (b < 0) { + b = -b; + neg = !neg; + } + + res = udivmodsi4(a, b, 0); + + if (neg) + res = -res; + + return res; +} + + +SItype __udivsi3(SItype a, SItype b) +{ + return udivmodsi4(a, b, 0); +} + + +SItype __modsi3(SItype a, SItype b) +{ + word_type neg = 0; + SItype res; + + if (a < 0) { + a = -a; + neg = 1; + } + + if (b < 0) + b = -b; + + res = udivmodsi4(a, b, 1); + + if (neg) + res = -res; + + return res; +} + +SItype __mulsi3(SItype a, SItype b) +{ + SItype res = 0; + USItype cnt = a; + + while (cnt) { + if (cnt & 1) + res += b; + b <<= 1; + cnt >>= 1; + } + + return res; +} + +SItype __umodsi3(SItype a, SItype b) +{ + return udivmodsi4(a, b, 1); +} + +int __gcc_bcmp(const unsigned char *s1, const unsigned char *s2, unsigned long size) +{ + unsigned char c1; + unsigned char c2; + + while (size > 0) { + c1 = *s1++; + c2 = *s2++; + if (c1 != c2) + return c1 - c2; + size--; + } + return 0; +} diff --git a/arch/nios2/lib/longlong.h b/arch/nios2/lib/longlong.h new file mode 100644 index 0000000..1e20269 --- /dev/null +++ b/arch/nios2/lib/longlong.h @@ -0,0 +1,258 @@ +/* longlong.h -- definitions for mixed size 32/64 bit arithmetic. + * Copyright (C) 1991, 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2004, + * 2005 Free Software Foundation, Inc. + * + * This definition file is free software; you can redistribute it + * and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2, or (at your option) any later version. + + * This definition file is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. */ + +/* You have to define the following before including this file: + + UWtype -- An unsigned type, default type for operations (typically a "word") + UHWtype -- An unsigned type, at least half the size of UWtype. + UDWtype -- An unsigned type, at least twice as large a UWtype + W_TYPE_SIZE -- size in bits of UWtype + + UQItype -- Unsigned 8 bit type. + SItype, USItype -- Signed and unsigned 32 bit types. + DItype, UDItype -- Signed and unsigned 64 bit types. + + On a 32 bit machine UWtype should typically be USItype; + on a 64 bit machine, UWtype should typically be UDItype. */ + +#define __BITS4 (W_TYPE_SIZE / 4) +#define __ll_B ((UWtype) 1 << (W_TYPE_SIZE / 2)) +#define __ll_lowpart(t) ((UWtype) (t) & (__ll_B - 1)) +#define __ll_highpart(t) ((UWtype) (t) >> (W_TYPE_SIZE / 2)) + +#ifndef W_TYPE_SIZE +#define W_TYPE_SIZE 32 +#define UWtype USItype +#define UHWtype USItype +#define UDWtype UDItype +#endif + +extern const UQItype __clz_tab[256]; + +/* Define auxiliary asm macros. + + 1) umul_ppmm(high_prod, low_prod, multiplier, multiplicand) multiplies two + UWtype integers MULTIPLIER and MULTIPLICAND, and generates a two UWtype + word product in HIGH_PROD and LOW_PROD. + + 2) __umulsidi3(a,b) multiplies two UWtype integers A and B, and returns a + UDWtype product. This is just a variant of umul_ppmm. + + 3) udiv_qrnnd(quotient, remainder, high_numerator, low_numerator, + denominator) divides a UDWtype, composed by the UWtype integers + HIGH_NUMERATOR and LOW_NUMERATOR, by DENOMINATOR and places the quotient + in QUOTIENT and the remainder in REMAINDER. HIGH_NUMERATOR must be less + than DENOMINATOR for correct operation. If, in addition, the most + significant bit of DENOMINATOR must be 1, then the pre-processor symbol + UDIV_NEEDS_NORMALIZATION is defined to 1. + + 4) sdiv_qrnnd(quotient, remainder, high_numerator, low_numerator, + denominator). Like udiv_qrnnd but the numbers are signed. The quotient + is rounded towards 0. + + 5) count_leading_zeros(count, x) counts the number of zero-bits from the + msb to the first nonzero bit in the UWtype X. This is the number of + steps X needs to be shifted left to set the msb. Undefined for X == 0, + unless the symbol COUNT_LEADING_ZEROS_0 is defined to some value. + + 6) count_trailing_zeros(count, x) like count_leading_zeros, but counts + from the least significant end. + + 7) add_ssaaaa(high_sum, low_sum, high_addend_1, low_addend_1, + high_addend_2, low_addend_2) adds two UWtype integers, composed by + HIGH_ADDEND_1 and LOW_ADDEND_1, and HIGH_ADDEND_2 and LOW_ADDEND_2 + respectively. The result is placed in HIGH_SUM and LOW_SUM. Overflow + (i.e. carry out) is not stored anywhere, and is lost. + + 8) sub_ddmmss(high_difference, low_difference, high_minuend, low_minuend, + high_subtrahend, low_subtrahend) subtracts two two-word UWtype integers, + composed by HIGH_MINUEND_1 and LOW_MINUEND_1, and HIGH_SUBTRAHEND_2 and + LOW_SUBTRAHEND_2 respectively. The result is placed in HIGH_DIFFERENCE + and LOW_DIFFERENCE. Overflow (i.e. carry out) is not stored anywhere, + and is lost. + + If any of these macros are left undefined for a particular CPU, + C macros are used. */ + +/* The CPUs come in alphabetical order below. + + Please add support for more CPUs here, or improve the current support + for the CPUs below! + (E.g. WE32100, IBM360.) */ + +/* Snipped per CPU support */ + +/* If this machine has no inline assembler, use C macros. */ + +#if !defined (add_ssaaaa) +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + do { \ + UWtype __x; \ + __x = (al) + (bl); \ + (sh) = (ah) + (bh) + (__x < (al)); \ + (sl) = __x; \ + } while (0) +#endif + +#if !defined (sub_ddmmss) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + do { \ + UWtype __x; \ + __x = (al) - (bl); \ + (sh) = (ah) - (bh) - (__x > (al)); \ + (sl) = __x; \ + } while (0) +#endif + +/* If we lack umul_ppmm but have smul_ppmm, define umul_ppmm in terms of + smul_ppmm. */ +#if !defined (umul_ppmm) && defined (smul_ppmm) +#define umul_ppmm(w1, w0, u, v) \ + do { \ + UWtype __w1; \ + UWtype __xm0 = (u), __xm1 = (v); \ + smul_ppmm (__w1, w0, __xm0, __xm1); \ + (w1) = __w1 + (-(__xm0 >> (W_TYPE_SIZE - 1)) & __xm1) \ + + (-(__xm1 >> (W_TYPE_SIZE - 1)) & __xm0); \ + } while (0) +#endif + +/* If we still don't have umul_ppmm, define it using plain C. */ +#if !defined (umul_ppmm) +#define umul_ppmm(w1, w0, u, v) \ + do { \ + UWtype __x0, __x1, __x2, __x3; \ + UHWtype __ul, __vl, __uh, __vh; \ + \ + __ul = __ll_lowpart (u); \ + __uh = __ll_highpart (u); \ + __vl = __ll_lowpart (v); \ + __vh = __ll_highpart (v); \ + \ + __x0 = (UWtype) __ul * __vl; \ + __x1 = (UWtype) __ul * __vh; \ + __x2 = (UWtype) __uh * __vl; \ + __x3 = (UWtype) __uh * __vh; \ + \ + __x1 += __ll_highpart (__x0);/* this can't give carry */ \ + __x1 += __x2; /* but this indeed can */ \ + if (__x1 < __x2) /* did we get it? */ \ + __x3 += __ll_B; /* yes, add it in the proper pos. */ \ + \ + (w1) = __x3 + __ll_highpart (__x1); \ + (w0) = __ll_lowpart (__x1) * __ll_B + __ll_lowpart (__x0); \ + } while (0) +#endif + +#if !defined (__umulsidi3) +#define __umulsidi3(u, v) \ + ({DWunion __w; \ + umul_ppmm (__w.s.high, __w.s.low, u, v); \ + __w.ll; }) +#endif + +/* Define this unconditionally, so it can be used for debugging. */ +#define __udiv_qrnnd_c(q, r, n1, n0, d) \ + do { \ + UWtype __d1, __d0, __q1, __q0; \ + UWtype __r1, __r0, __m; \ + __d1 = __ll_highpart (d); \ + __d0 = __ll_lowpart (d); \ + \ + __r1 = (n1) % __d1; \ + __q1 = (n1) / __d1; \ + __m = (UWtype) __q1 * __d0; \ + __r1 = __r1 * __ll_B | __ll_highpart (n0); \ + if (__r1 < __m) { \ + __q1--, __r1 += (d); \ + if (__r1 >= (d)) /* i.e. we didn't get carry when adding to __r1 */ \ + if (__r1 < __m) \ + __q1--, __r1 += (d); \ + } \ + __r1 -= __m; \ + \ + __r0 = __r1 % __d1; \ + __q0 = __r1 / __d1; \ + __m = (UWtype) __q0 * __d0; \ + __r0 = __r0 * __ll_B | __ll_lowpart (n0); \ + if (__r0 < __m) { \ + __q0--, __r0 += (d); \ + if (__r0 >= (d)) \ + if (__r0 < __m) \ + __q0--, __r0 += (d); \ + } \ + __r0 -= __m; \ + \ + (q) = (UWtype) __q1 * __ll_B | __q0; \ + (r) = __r0; \ + } while (0) + +/* If the processor has no udiv_qrnnd but sdiv_qrnnd, go through + __udiv_w_sdiv (defined in libgcc or elsewhere). */ +#if !defined (udiv_qrnnd) && defined (sdiv_qrnnd) +#define udiv_qrnnd(q, r, nh, nl, d) \ + do { \ + USItype __r; \ + (q) = __udiv_w_sdiv (&__r, nh, nl, d); \ + (r) = __r; \ + } while (0) +#endif + +/* If udiv_qrnnd was not defined for this processor, use __udiv_qrnnd_c. */ +#if !defined (udiv_qrnnd) +#define UDIV_NEEDS_NORMALIZATION 1 +#define udiv_qrnnd __udiv_qrnnd_c +#endif + +#if !defined (count_leading_zeros) +#define count_leading_zeros(count, x) \ + do { \ + UWtype __xr = (x); \ + UWtype __a; \ + \ + if (W_TYPE_SIZE <= 32) { \ + __a = __xr < ((UWtype)1<<2*__BITS4) \ + ? (__xr < ((UWtype)1<<__BITS4) ? 0 : __BITS4) \ + : (__xr < ((UWtype)1<<3*__BITS4) ? 2*__BITS4 : 3*__BITS4); \ + } \ + else { \ + for (__a = W_TYPE_SIZE - 8; __a > 0; __a -= 8) \ + if (((__xr >> __a) & 0xff) != 0) \ + break; \ + } \ + (count) = W_TYPE_SIZE - (__clz_tab[__xr >> __a] + __a); \ + } while (0) +#define COUNT_LEADING_ZEROS_0 W_TYPE_SIZE +#endif + +#if !defined (count_trailing_zeros) +/* Define count_trailing_zeros using count_leading_zeros. The latter might be + defined in asm, but if it is not, the C version above is good enough. */ +#define count_trailing_zeros(count, x) \ + do { \ + UWtype __ctz_x = (x); \ + UWtype __ctz_c; \ + count_leading_zeros (__ctz_c, __ctz_x & -__ctz_x); \ + (count) = W_TYPE_SIZE - 1 - __ctz_c; \ + } while (0) +#endif + +#ifndef UDIV_NEEDS_NORMALIZATION +#define UDIV_NEEDS_NORMALIZATION 0 +#endif diff --git a/commands/linux16.c b/commands/linux16.c index 5f412e2..8a1b5fe 100644 --- a/commands/linux16.c +++ b/commands/linux16.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -140,6 +141,10 @@ #endif } __attribute__ ((packed)); +/* This is -1. Keep this value in sync with the kernel */ +#define NORMAL_VGA 0xffff /* 80x25 mode */ +#define ASK_VGA 0xfffd /* ask for it at bootup */ + /** * Load an x86 Linux kernel bzImage and start it * @param cmdtp FIXME @@ -153,18 +158,37 @@ static int do_linux16(struct command *cmdtp, int argc, char *argv[]) { struct linux_kernel_header *lh = NULL; - int rc; + int rc, opt; unsigned setup_sects; unsigned real_mode_size; + int vid_mode = NORMAL_VGA; size_t image_size; const char *cmdline = getenv("bootargs"); + const char *kernel_file; - if (argc < 2) { - perror("linux16"); - return 1; + while((opt = getopt(argc, argv, "v:")) > 0) { + switch(opt) { + case 'v': + vid_mode = simple_strtoul(optarg, NULL, 0); + if (vid_mode == 0) { + if (!strcmp(optarg, "ask")) + vid_mode = ASK_VGA; + else { + printf("Unknown video mode: %s\n", optarg); + return 1; + } + } + break; + } } - lh = read_file(argv[1], &image_size); + if (optind == argc) { + printf("No kernel filename given\n"); + return 1; + } + kernel_file = argv[optind]; + + lh = read_file(kernel_file, &image_size); if (lh == NULL) { printf("Cannot read file '%s'\n", argv[1]); return 1; @@ -219,6 +243,14 @@ goto on_error; } + /* + * The kernel does not check for the "vga=" kernel command line + * parameter anymore. It expects this kind of information in the + * boot parameters instead. + */ + if (vid_mode != NORMAL_VGA) + lh->vid_mode = vid_mode; + /* If SETUP_SECTS is not set, set it to the default. */ if (setup_sects == 0) { printf("Fixing setup sector count\n"); @@ -228,7 +260,8 @@ if (setup_sects >= 15) { void *src = lh; if (lh->kernel_version != 0) - printf("Kernel version: '%s'\n", src + lh->kernel_version + DISK_SECTOR_SIZE); + printf("Kernel version: '%s'\n", + (char *)src + lh->kernel_version + DISK_SECTOR_SIZE); } /* @@ -289,16 +322,21 @@ } BAREBOX_CMD_HELP_START(linux16) -BAREBOX_CMD_HELP_USAGE("linux16 \n") -BAREBOX_CMD_HELP_SHORT("Boot a kernel on x86 via real mode code.\n") +BAREBOX_CMD_HELP_USAGE("linux16 [-v ]\n") +BAREBOX_CMD_HELP_SHORT("Boot a kernel on x86 via real mode code.\n") +BAREBOX_CMD_HELP_OPT ("-v ", "VESA video mode number or 'ask'\n") BAREBOX_CMD_HELP_END /** * @page linux16_command -

Only kernel images in bzImage format are supported by now. See \ref +

Only kernel images in bzImage format are supported by now. See \ref x86_boot_preparation for more info about how to use this command.

+

For the video mode refer the Linux kernel documentation +'Documentation/fb/vesafb.txt' for correct VESA mode numbers. If the keyword +'ask' instead of a number is given, the starting kernel will ask for a number. +

*/ BAREBOX_CMD_START(linux16) diff --git a/common/Kconfig b/common/Kconfig index 02bc67e..9e30579 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -148,13 +148,10 @@ config KALLSYMS depends on HAS_KALLSYMS - depends on BROKEN bool "kallsyms" help With Kallsyms enabled all symbols are compiled into the barebox image. This is useful to print a nice backtrace when an exception occurs. - No architecture supports backtraces at the moment, so this option - is quite useless at the moment config RELOCATABLE depends on PPC diff --git a/common/kallsyms.c b/common/kallsyms.c index 490adb9..0218991 100644 --- a/common/kallsyms.c +++ b/common/kallsyms.c @@ -1,6 +1,7 @@ #include #include #include +#include #ifndef DOXYGEN_SHOULD_SKIP_THIS @@ -16,6 +17,13 @@ #endif /* DOXYGEN_SHOULD_SKIP_THIS */ +static inline int is_kernel_text(unsigned long addr) +{ + if ((addr >= (unsigned long)_stext && addr <= (unsigned long)_etext)) + return 1; + return 0; +} + /* expand a compressed symbol data into the resulting uncompressed string, given the offset to where the symbol is in the compressed stream */ static unsigned int kallsyms_expand_symbol(unsigned int off, char *result) @@ -55,6 +63,33 @@ return off; } +/* + * Find the offset on the compressed stream given and index in the + * kallsyms array. + */ +static unsigned int get_symbol_offset(unsigned long pos) +{ + const u8 *name; + int i; + + /* + * Use the closest marker we have. We have markers every 256 positions, + * so that should be close enough. + */ + name = &kallsyms_names[kallsyms_markers[pos >> 8]]; + + /* + * Sequentially scan all the symbols up to the point we're searching + * for. Every symbol is stored in a [][ bytes of data] format, + * so we just need to add the len to the current pointer for every + * symbol we wish to skip. + */ + for (i = 0; i < (pos & 0xFF); i++) + name = name + (*name) + 1; + + return name - kallsyms_names; +} + /* Lookup the address for this symbol. Returns 0 if not found. */ unsigned long kallsyms_lookup_name(const char *name) { @@ -68,6 +103,117 @@ if (strcmp(namebuf, name) == 0) return kallsyms_addresses[i]; } -// return module_kallsyms_lookup_name(name); + + /* module kallsyms not yet supported */ return 0; } + +static unsigned long get_symbol_pos(unsigned long addr, + unsigned long *symbolsize, + unsigned long *offset) +{ + unsigned long symbol_start = 0, symbol_end = 0; + unsigned long i, low, high, mid; + + /* This kernel should never had been booted. */ + BUG_ON(!kallsyms_addresses); + + /* Do a binary search on the sorted kallsyms_addresses array. */ + low = 0; + high = kallsyms_num_syms; + + while (high - low > 1) { + mid = low + (high - low) / 2; + if (kallsyms_addresses[mid] <= addr) + low = mid; + else + high = mid; + } + + /* + * Search for the first aliased symbol. Aliased + * symbols are symbols with the same address. + */ + while (low && kallsyms_addresses[low-1] == kallsyms_addresses[low]) + --low; + + symbol_start = kallsyms_addresses[low]; + + /* Search for next non-aliased symbol. */ + for (i = low + 1; i < kallsyms_num_syms; i++) { + if (kallsyms_addresses[i] > symbol_start) { + symbol_end = kallsyms_addresses[i]; + break; + } + } + + /* If we found no next symbol, we use the end of the section. */ + if (!symbol_end) { + symbol_end = (unsigned long)_etext; + } + + if (symbolsize) + *symbolsize = symbol_end - symbol_start; + if (offset) + *offset = addr - symbol_start; + + return low; +} + +/* + * Lookup an address + * - modname is set to NULL if it's in the kernel. + * - We guarantee that the returned name is valid until we reschedule even if. + * It resides in a module. + * - We also guarantee that modname will be valid until rescheduled. + */ +const char *kallsyms_lookup(unsigned long addr, + unsigned long *symbolsize, + unsigned long *offset, + char **modname, char *namebuf) +{ + namebuf[KSYM_NAME_LEN - 1] = 0; + namebuf[0] = 0; + + if (is_kernel_text(addr)) { + unsigned long pos; + + pos = get_symbol_pos(addr, symbolsize, offset); + /* Grab name */ + kallsyms_expand_symbol(get_symbol_offset(pos), namebuf); + if (modname) + *modname = NULL; + return namebuf; + } + + /* moduled not yet supported in kallsyms */ + return NULL; +} + +/* Look up a kernel symbol and return it in a text buffer. */ +int sprint_symbol(char *buffer, unsigned long address) +{ + char *modname; + const char *name; + unsigned long offset, size; + int len; + + name = kallsyms_lookup(address, &size, &offset, &modname, buffer); + if (!name) + return sprintf(buffer, "0x%lx", address); + + if (name != buffer) + strcpy(buffer, name); + len = strlen(buffer); + buffer += len; + + if (modname) + len += sprintf(buffer, "+%#lx/%#lx [%s]", + offset, size, modname); + else + len += sprintf(buffer, "+%#lx/%#lx", offset, size); + + return len; +} +EXPORT_SYMBOL_GPL(sprint_symbol); + diff --git a/defaultenv/bin/boot b/defaultenv/bin/boot index 7497791..de4fa24 100644 --- a/defaultenv/bin/boot +++ b/defaultenv/bin/boot @@ -8,9 +8,12 @@ elif [ x$1 = xnor ]; then rootfs_loc=nor kernel_loc=nor -elif [ x$1 = xnet ]; then +elif [ x$1 = xnfs ]; then rootfs_loc=net - kernel_loc=net + kernel_loc=nfs +elif [ x$1 = xtftp ]; then + rootfs_loc=net + kernel_loc=tftp fi if [ x$ip = xdhcp ]; then @@ -71,7 +74,7 @@ addpart /dev/ram0 8M@8M(kernel) fi -if [ x$kernel_loc = xnet ]; then +if [ x$kernel_loc = xnfs ] || [ x$kernel_loc = xtftp ]; then if [ x$ip = xdhcp ]; then dhcp fi @@ -87,14 +90,14 @@ echo "error: set kernelimage_type to one of 'uimage', 'zimage', 'raw' or 'raw_lzo'" exit 1 fi - tftp $kernelimage $netload || exit 1 + $kernel_loc $kernelimage $netload || exit 1 kdev="$netload" elif [ x$kernel_loc = xnor ]; then kdev="/dev/nor0.kernel" elif [ x$kernel_loc = xnand ]; then kdev="/dev/nand0.kernel.bb" else - echo "error: set kernel_loc to one of 'net', 'nand' or 'nor'" + echo "error: set kernel_loc to one of 'nfs', 'tftp', 'nand' or 'nor'" exit 1 fi diff --git a/drivers/mci/Kconfig b/drivers/mci/Kconfig index 7d214ac..b11f267 100644 --- a/drivers/mci/Kconfig +++ b/drivers/mci/Kconfig @@ -27,7 +27,7 @@ comment "--- MCI host drivers ---" -config MCI_STM378X +config MCI_MXS bool "i.MX23/i.MX28" depends on ARCH_MXS help diff --git a/drivers/mci/Makefile b/drivers/mci/Makefile index a10cb47..f175bba 100644 --- a/drivers/mci/Makefile +++ b/drivers/mci/Makefile @@ -1,5 +1,5 @@ obj-$(CONFIG_MCI) += mci-core.o -obj-$(CONFIG_MCI_STM378X) += stm378x.o +obj-$(CONFIG_MCI_MXS) += mxs.o obj-$(CONFIG_MCI_S3C) += s3c.o obj-$(CONFIG_MCI_IMX) += imx.o obj-$(CONFIG_MCI_IMX_ESDHC) += imx-esdhc.o diff --git a/drivers/mci/mxs.c b/drivers/mci/mxs.c new file mode 100644 index 0000000..c6ae1cb --- /dev/null +++ b/drivers/mci/mxs.c @@ -0,0 +1,773 @@ +/* + * Copyright (C) 2010 Juergen Beisert, Pengutronix + * + * This code is based on: + * + * Copyright (C) 2007 SigmaTel, Inc., Ioannis Kappas + * + * Portions copyright (C) 2003 Russell King, PXA MMCI Driver + * Portions copyright (C) 2004-2005 Pierre Ossman, W83L51xD SD/MMC driver + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/** + * @file + * @brief MCI card host interface for i.MX23 CPU + */ + +/* #define DEBUG */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CLOCKRATE_MIN (1 * 1000 * 1000) +#define CLOCKRATE_MAX (480 * 1000 * 1000) + +#define HW_SSP_CTRL0 0x000 +# define SSP_CTRL0_SFTRST (1 << 31) +# define SSP_CTRL0_CLKGATE (1 << 30) +# define SSP_CTRL0_RUN (1 << 29) +# define SSP_CTRL0_LOCK_CS (1 << 27) +# define SSP_CTRL0_READ (1 << 25) +# define SSP_CTRL0_IGNORE_CRC (1 << 26) +# define SSP_CTRL0_DATA_XFER (1 << 24) +# define SSP_CTRL0_BUS_WIDTH(x) (((x) & 0x3) << 22) +# define SSP_CTRL0_WAIT_FOR_IRQ (1 << 21) +# define SSP_CTRL0_LONG_RESP (1 << 19) +# define SSP_CTRL0_GET_RESP (1 << 17) +# define SSP_CTRL0_ENABLE (1 << 16) +#ifdef CONFIG_ARCH_IMX23 +# define SSP_CTRL0_XFER_COUNT(x) ((x) & 0xffff) +#endif + +#define HW_SSP_CMD0 0x010 +# define SSP_CMD0_SLOW_CLK (1 << 22) +# define SSP_CMD0_CONT_CLK (1 << 21) +# define SSP_CMD0_APPEND_8CYC (1 << 20) +#ifdef CONFIG_ARCH_IMX23 +# define SSP_CMD0_BLOCK_SIZE(x) (((x) & 0xf) << 16) +# define SSP_CMD0_BLOCK_COUNT(x) (((x) & 0xff) << 8) +#endif +# define SSP_CMD0_CMD(x) ((x) & 0xff) + +#define HW_SSP_CMD1 0x020 + +#ifdef CONFIG_ARCH_IMX23 +# define HW_SSP_COMPREF 0x030 +# define HW_SSP_COMPMASK 0x040 +# define HW_SSP_TIMING 0x050 +# define HW_SSP_CTRL1 0x060 +# define HW_SSP_DATA 0x070 +#endif +#ifdef CONFIG_ARCH_IMX28 +# define HW_SSP_XFER_COUNT 0x30 +# define HW_SSP_BLOCK_SIZE 0x40 +# define SSP_BLOCK_SIZE(x) ((x) & 0xf) +# define SSP_BLOCK_COUNT(x) (((x) & 0xffffff) << 4) +# define HW_SSP_COMPREF 0x050 +# define HW_SSP_COMPMASK 0x060 +# define HW_SSP_TIMING 0x070 +# define HW_SSP_CTRL1 0x080 +# define HW_SSP_DATA 0x090 +#endif +/* bit definition for register HW_SSP_TIMING */ +# define SSP_TIMING_TIMEOUT_MASK (0xffff0000) +# define SSP_TIMING_TIMEOUT(x) ((x) << 16) +# define SSP_TIMING_CLOCK_DIVIDE(x) (((x) & 0xff) << 8) +# define SSP_TIMING_CLOCK_RATE(x) ((x) & 0xff) + +/* bit definition for register HW_SSP_CTRL1 */ +# define SSP_CTRL1_POLARITY (1 << 9) +# define SSP_CTRL1_WORD_LENGTH(x) (((x) & 0xf) << 4) +# define SSP_CTRL1_SSP_MODE(x) ((x) & 0xf) + +#ifdef CONFIG_ARCH_IMX23 +# define HW_SSP_SDRESP0 0x080 +# define HW_SSP_SDRESP1 0x090 +# define HW_SSP_SDRESP2 0x0A0 +# define HW_SSP_SDRESP3 0x0B0 +#endif +#ifdef CONFIG_ARCH_IMX28 +# define HW_SSP_SDRESP0 0x0A0 +# define HW_SSP_SDRESP1 0x0B0 +# define HW_SSP_SDRESP2 0x0C0 +# define HW_SSP_SDRESP3 0x0D0 +#endif + +#ifdef CONFIG_ARCH_IMX28 +# define HW_SSP_DDR_CTRL 0x0E0 +# define HW_SSP_DLL_CTRL 0x0F0 +#endif + +#ifdef CONFIG_ARCH_IMX23 +# define HW_SSP_STATUS 0x0C0 +#endif +#ifdef CONFIG_ARCH_IMX28 +# define HW_SSP_STATUS 0x100 +#endif + +/* bit definition for register HW_SSP_STATUS */ +# define SSP_STATUS_PRESENT (1 << 31) +# define SSP_STATUS_SD_PRESENT (1 << 29) +# define SSP_STATUS_CARD_DETECT (1 << 28) +# define SSP_STATUS_RESP_CRC_ERR (1 << 16) +# define SSP_STATUS_RESP_ERR (1 << 15) +# define SSP_STATUS_RESP_TIMEOUT (1 << 14) +# define SSP_STATUS_DATA_CRC_ERR (1 << 13) +# define SSP_STATUS_TIMEOUT (1 << 12) +# define SSP_STATUS_FIFO_OVRFLW (1 << 9) +# define SSP_STATUS_FIFO_FULL (1 << 8) +# define SSP_STATUS_FIFO_EMPTY (1 << 5) +# define SSP_STATUS_FIFO_UNDRFLW (1 << 4) +# define SSP_STATUS_CMD_BUSY (1 << 3) +# define SSP_STATUS_DATA_BUSY (1 << 2) +# define SSP_STATUS_BUSY (1 << 0) +# define SSP_STATUS_ERROR (SSP_STATUS_FIFO_OVRFLW | SSP_STATUS_FIFO_UNDRFLW | \ + SSP_STATUS_RESP_CRC_ERR | SSP_STATUS_RESP_ERR | \ + SSP_STATUS_RESP_TIMEOUT | SSP_STATUS_DATA_CRC_ERR | SSP_STATUS_TIMEOUT) + +#ifdef CONFIG_ARCH_IMX28 +# define HW_SSP_DLL_STS 0x110 +#endif + +#ifdef CONFIG_ARCH_IMX23 +# define HW_SSP_DEBUG 0x100 +# define HW_SSP_VERSION 0x110 +#endif + +#ifdef CONFIG_ARCH_IMX28 +# define HW_SSP_DEBUG 0x120 +# define HW_SSP_VERSION 0x130 +#endif + +struct mxs_mci_host { + struct mci_host host; + void __iomem *regs; + unsigned clock; /* current clock speed in Hz ("0" if disabled) */ + unsigned index; +#ifdef CONFIG_MCI_INFO + unsigned f_min; + unsigned f_max; +#endif + int bus_width:2; /* 0 = 1 bit, 1 = 4 bit, 2 = 8 bit */ +}; + +#define to_mxs_mci(mxs) container_of(mxs, struct mxs_mci_host, host) + +/** + * Get the SSP clock rate + * @param hw_dev Host interface device instance + * @return Unit's clock in [Hz] + */ +static unsigned mxs_mci_get_unit_clock(struct mxs_mci_host *mxs_mci) +{ + return imx_get_sspclk(mxs_mci->index); +} + +/** + * Get MCI cards response if defined for the type of command + * @param hw_dev Host interface device instance + * @param cmd Command description + * @return Response bytes count, -EINVAL for unsupported response types + */ +static int mxs_mci_get_cards_response(struct mxs_mci_host *mxs_mci, struct mci_cmd *cmd) +{ + switch (cmd->resp_type) { + case MMC_RSP_NONE: + return 0; + + case MMC_RSP_R1: + case MMC_RSP_R1b: + case MMC_RSP_R3: + cmd->response[0] = readl(mxs_mci->regs + HW_SSP_SDRESP0); + return 1; + + case MMC_RSP_R2: + cmd->response[3] = readl(mxs_mci->regs + HW_SSP_SDRESP0); + cmd->response[2] = readl(mxs_mci->regs + HW_SSP_SDRESP1); + cmd->response[1] = readl(mxs_mci->regs + HW_SSP_SDRESP2); + cmd->response[0] = readl(mxs_mci->regs + HW_SSP_SDRESP3); + return 4; + } + + return -EINVAL; +} + +/** + * Finish a request to the MCI card + * @param hw_dev Host interface device instance + * + * Can also stop the clock to save power + */ +static void mxs_mci_finish_request(struct mxs_mci_host *mxs_mci) +{ + /* stop the engines (normaly already done) */ + writel(SSP_CTRL0_RUN, mxs_mci->regs + HW_SSP_CTRL0 + 8); +} + +/** + * Check if the last command failed and if, why it failed + * @param status HW_SSP_STATUS's content + * @return 0 if no error, negative values else + */ +static int mxs_mci_get_cmd_error(unsigned status) +{ + if (status & SSP_STATUS_ERROR) + pr_debug("Status Reg reports %08X\n", status); + + if (status & SSP_STATUS_TIMEOUT) { + pr_debug("CMD timeout\n"); + return -ETIMEDOUT; + } else if (status & SSP_STATUS_RESP_TIMEOUT) { + pr_debug("RESP timeout\n"); + return -ETIMEDOUT; + } else if (status & SSP_STATUS_RESP_CRC_ERR) { + pr_debug("CMD crc error\n"); + return -EILSEQ; + } else if (status & SSP_STATUS_RESP_ERR) { + pr_debug("RESP error\n"); + return -EIO; + } + + return 0; +} + +/** + * Define the timout for the next command + * @param hw_dev Host interface device instance + * @param to Timeout value in MCI card's bus clocks + */ +static void mxs_mci_setup_timeout(struct mxs_mci_host *mxs_mci, unsigned to) +{ + uint32_t reg; + + reg = readl(mxs_mci->regs + HW_SSP_TIMING) & ~SSP_TIMING_TIMEOUT_MASK; + reg |= SSP_TIMING_TIMEOUT(to); + writel(reg, mxs_mci->regs + HW_SSP_TIMING); +} + +/** + * Read data from the MCI card + * @param hw_dev Host interface device instance + * @param buffer To write data into + * @param length Count of bytes to read (must be multiples of 4) + * @return 0 on success, negative values else + * + * @note This routine uses PIO to read in the data bytes from the FIFO. This + * may fail whith high clock speeds. If you receive -EIO errors you can try + * again with reduced clock speeds. + */ +static int mxs_mci_read_data(struct mxs_mci_host *mxs_mci, void *buffer, unsigned length) +{ + uint32_t *p = buffer; + + if (length & 0x3) { + pr_debug("Cannot read data sizes not multiple of 4 (request for %u detected)\n", + length); + return -EINVAL; + } + + while ((length != 0) && + ((readl(mxs_mci->regs + HW_SSP_STATUS) & SSP_STATUS_ERROR) == 0)) { + /* TODO sort out FIFO overflows and emit -EOI for this case */ + if ((readl(mxs_mci->regs + HW_SSP_STATUS) & SSP_STATUS_FIFO_EMPTY) == 0) { + *p = readl(mxs_mci->regs + HW_SSP_DATA); + p++; + length -= 4; + } + } + + if (length == 0) + return 0; + + return -EINVAL; +} + + +/** + * Write data into the MCI card + * @param hw_dev Host interface device instance + * @param buffer To read the data from + * @param length Count of bytes to write (must be multiples of 4) + * @return 0 on success, negative values else + * + * @note This routine uses PIO to write the data bytes into the FIFO. This + * may fail with high clock speeds. If you receive -EIO errors you can try + * again with reduced clock speeds. + */ +static int mxs_mci_write_data(struct mxs_mci_host *mxs_mci, const void *buffer, unsigned length) +{ + const uint32_t *p = buffer; + + if (length & 0x3) { + pr_debug("Cannot write data sizes not multiple of 4 (request for %u detected)\n", + length); + return -EINVAL; + } + + while ((length != 0) && + ((readl(mxs_mci->regs + HW_SSP_STATUS) & SSP_STATUS_ERROR) == 0)) { + /* TODO sort out FIFO overflows and emit -EOI for this case */ + if ((readl(mxs_mci->regs + HW_SSP_STATUS) & SSP_STATUS_FIFO_FULL) == 0) { + writel(*p, mxs_mci->regs + HW_SSP_DATA); + p++; + length -= 4; + } + } + if (length == 0) + return 0; + + return -EINVAL; +} + +/** + * Start the transaction with or without data + * @param hw_dev Host interface device instance + * @param data Data transfer description (might be NULL) + * @return 0 on success + */ +static int mxs_mci_transfer_data(struct mxs_mci_host *mxs_mci, struct mci_data *data) +{ + /* + * Everything is ready for the transaction now: + * - transfer configuration + * - command and its parameters + * + * Start the transaction right now + */ + writel(SSP_CTRL0_RUN, mxs_mci->regs + HW_SSP_CTRL0 + 4); + + if (data != NULL) { + unsigned length = data->blocks * data->blocksize; + + if (data->flags & MMC_DATA_READ) + return mxs_mci_read_data(mxs_mci, data->dest, length); + else + return mxs_mci_write_data(mxs_mci, data->src, length); + } + + return 0; +} + +/** + * Configure the MCI hardware for the next transaction + * @param cmd_flags Command information + * @param data_flags Data information (may be 0) + * @return Corresponding setting for the SSP_CTRL0 register + */ +static uint32_t mxs_mci_prepare_transfer_setup(unsigned cmd_flags, unsigned data_flags) +{ + uint32_t reg = 0; + + if (cmd_flags & MMC_RSP_PRESENT) + reg |= SSP_CTRL0_GET_RESP; + if ((cmd_flags & MMC_RSP_CRC) == 0) + reg |= SSP_CTRL0_IGNORE_CRC; + if (cmd_flags & MMC_RSP_136) + reg |= SSP_CTRL0_LONG_RESP; + if (cmd_flags & MMC_RSP_BUSY) + reg |= SSP_CTRL0_WAIT_FOR_IRQ; /* FIXME correct? */ +#if 0 + if (cmd_flags & MMC_RSP_OPCODE) + /* TODO */ +#endif + if (data_flags & MMC_DATA_READ) + reg |= SSP_CTRL0_READ; + + return reg; +} + +/** + * Handle MCI commands without data + * @param hw_dev Host interface device instance + * @param cmd The command to handle + * @return 0 on success + * + * This functions handles the following MCI commands: + * - "broadcast command (BC)" without a response + * - "broadcast commands with response (BCR)" + * - "addressed command (AC)" with response, but without data + */ +static int mxs_mci_std_cmds(struct mxs_mci_host *mxs_mci, struct mci_cmd *cmd) +{ + /* setup command and transfer parameters */ + writel(mxs_mci_prepare_transfer_setup(cmd->resp_type, 0) | + SSP_CTRL0_ENABLE, mxs_mci->regs + HW_SSP_CTRL0); + + /* prepare the command, when no response is expected add a few trailing clocks */ + writel(SSP_CMD0_CMD(cmd->cmdidx) | + (cmd->resp_type & MMC_RSP_PRESENT ? 0 : SSP_CMD0_APPEND_8CYC), + mxs_mci->regs + HW_SSP_CMD0); + + /* prepare command's arguments */ + writel(cmd->cmdarg, mxs_mci->regs + HW_SSP_CMD1); + + mxs_mci_setup_timeout(mxs_mci, 0xffff); + + /* start the transfer */ + writel(SSP_CTRL0_RUN, mxs_mci->regs + HW_SSP_CTRL0 + 4); + + /* wait until finished */ + while (readl(mxs_mci->regs + HW_SSP_CTRL0) & SSP_CTRL0_RUN) + ; + + if (cmd->resp_type & MMC_RSP_PRESENT) + mxs_mci_get_cards_response(mxs_mci, cmd); + + return mxs_mci_get_cmd_error(readl(mxs_mci->regs + HW_SSP_STATUS)); +} + +/** + * Handle an "addressed data transfer command " with or without data + * @param hw_dev Host interface device instance + * @param cmd The command to handle + * @param data The data information (buffer, direction aso.) May be NULL + * @return 0 on success + */ +static int mxs_mci_adtc(struct mxs_mci_host *mxs_mci, struct mci_cmd *cmd, + struct mci_data *data) +{ + uint32_t xfer_cnt, log2blocksize, block_cnt; + int err; + + /* Note: 'data' can be NULL! */ + if (data != NULL) { + xfer_cnt = data->blocks * data->blocksize; + block_cnt = data->blocks - 1; /* can be 0 */ + log2blocksize = find_first_bit((const unsigned long*)&data->blocksize, + 32); + } else + xfer_cnt = log2blocksize = block_cnt = 0; + + /* setup command and transfer parameters */ +#ifdef CONFIG_ARCH_IMX23 + writel(mxs_mci_prepare_transfer_setup(cmd->resp_type, data != NULL ? data->flags : 0) | + SSP_CTRL0_BUS_WIDTH(mxs_mci->bus_width) | + (xfer_cnt != 0 ? SSP_CTRL0_DATA_XFER : 0) | /* command plus data */ + SSP_CTRL0_ENABLE | + SSP_CTRL0_XFER_COUNT(xfer_cnt), /* byte count to be transfered */ + mxs_mci->regs + HW_SSP_CTRL0); + + /* prepare the command and the transfered data count */ + writel(SSP_CMD0_CMD(cmd->cmdidx) | + SSP_CMD0_BLOCK_SIZE(log2blocksize) | + SSP_CMD0_BLOCK_COUNT(block_cnt) | + (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION ? SSP_CMD0_APPEND_8CYC : 0), + mxs_mci->regs + HW_SSP_CMD0); +#endif +#ifdef CONFIG_ARCH_IMX28 + writel(mxs_mci_prepare_transfer_setup(cmd->resp_type, data != NULL ? data->flags : 0) | + SSP_CTRL0_BUS_WIDTH(mxs_mci->bus_width) | + (xfer_cnt != 0 ? SSP_CTRL0_DATA_XFER : 0) | /* command plus data */ + SSP_CTRL0_ENABLE, + mxs_mci->regs + HW_SSP_CTRL0); + writel(xfer_cnt, mxs_mci->regs + HW_SSP_XFER_COUNT); + + /* prepare the command and the transfered data count */ + writel(SSP_CMD0_CMD(cmd->cmdidx) | + (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION ? SSP_CMD0_APPEND_8CYC : 0), + mxs_mci->regs + HW_SSP_CMD0); + writel(SSP_BLOCK_SIZE(log2blocksize) | + SSP_BLOCK_COUNT(block_cnt), + mxs_mci->regs + HW_SSP_BLOCK_SIZE); +#endif + + /* prepare command's arguments */ + writel(cmd->cmdarg, mxs_mci->regs + HW_SSP_CMD1); + + mxs_mci_setup_timeout(mxs_mci, 0xffff); + + err = mxs_mci_transfer_data(mxs_mci, data); + if (err != 0) { + pr_debug(" Transfering data failed\n"); + return err; + } + + /* wait until finished */ + while (readl(mxs_mci->regs + HW_SSP_CTRL0) & SSP_CTRL0_RUN) + ; + + mxs_mci_get_cards_response(mxs_mci, cmd); + + return 0; +} + + +/** + * @param hw_dev Host interface device instance + * @param nc New Clock in [Hz] (may be 0 to disable the clock) + * @return The real clock frequency + * + * The SSP unit clock can base on the external 24 MHz or the internal 480 MHz + * Its unit clock value is derived from the io clock, from the SSP divider + * and at least the SSP bus clock itself is derived from the SSP unit's divider + * + * @code + * |------------------- generic -------------|-peripheral specific-|-----all SSPs-----|-per SSP unit-| + * 24 MHz ---------------------------- + * \ \ + * \ |----| FRAC |----IO CLK----| SSP unit DIV |---| SSP DIV |--- SSP output clock + * \- | PLL |--- 480 MHz ---/ + * @endcode + * + * @note Up to "SSP unit DIV" the outer world must care. This routine only + * handles the "SSP DIV". + */ +static unsigned mxs_mci_setup_clock_speed(struct mxs_mci_host *mxs_mci, unsigned nc) +{ + unsigned ssp, div, rate, reg; + + if (nc == 0U) { + /* TODO stop the clock */ + return 0; + } + + ssp = mxs_mci_get_unit_clock(mxs_mci); + + for (div = 2; div < 255; div += 2) { + rate = DIV_ROUND_CLOSEST(DIV_ROUND_CLOSEST(ssp, nc), div); + if (rate <= 0x100) + break; + } + if (div >= 255) { + pr_warning("Cannot set clock to %d Hz\n", nc); + return 0; + } + + reg = readl(mxs_mci->regs + HW_SSP_TIMING) & SSP_TIMING_TIMEOUT_MASK; + reg |= SSP_TIMING_CLOCK_DIVIDE(div) | SSP_TIMING_CLOCK_RATE(rate - 1); + writel(reg, mxs_mci->regs + HW_SSP_TIMING); + + return ssp / div / rate; +} + +/** + * Reset the MCI engine (the hard way) + * @param hw_dev Host interface instance + * + * This will reset everything in all registers of this unit! (FIXME) + */ +static void mxs_mci_reset(struct mxs_mci_host *mxs_mci) +{ + writel(SSP_CTRL0_SFTRST, mxs_mci->regs + HW_SSP_CTRL0 + 8); + while (readl(mxs_mci->regs + HW_SSP_CTRL0) & SSP_CTRL0_SFTRST) + ; +} + +/* ------------------------- MCI API -------------------------------------- */ + +/** + * Keep the attached MMC/SD unit in a well know state + * @param mci_pdata MCI platform data + * @param mci_dev MCI device instance + * @return 0 on success, negative value else + */ +static int mxs_mci_initialize(struct mci_host *host, struct device_d *mci_dev) +{ + struct mxs_mci_host *mxs_mci = to_mxs_mci(host); + + /* enable the clock to this unit to be able to reset it */ + writel(SSP_CTRL0_CLKGATE, mxs_mci->regs + HW_SSP_CTRL0 + 8); + + /* reset the unit */ + mxs_mci_reset(mxs_mci); + + /* restore the last settings */ + mxs_mci_setup_timeout(mxs_mci, 0xffff); + writel(SSP_CTRL0_IGNORE_CRC | + SSP_CTRL0_BUS_WIDTH(mxs_mci->bus_width), + mxs_mci->regs + HW_SSP_CTRL0); + writel(SSP_CTRL1_POLARITY | + SSP_CTRL1_SSP_MODE(3) | + SSP_CTRL1_WORD_LENGTH(7), mxs_mci->regs + HW_SSP_CTRL1); + + return 0; +} + +/** + * Process one command to the MCI card + * @param mci_pdata MCI platform data + * @param cmd The command to process + * @param data The data to handle in the command (can be NULL) + * @return 0 on success, negative value else + */ +static int mxs_mci_request(struct mci_host *host, struct mci_cmd *cmd, + struct mci_data *data) +{ + struct mxs_mci_host *mxs_mci = to_mxs_mci(host); + int rc; + + if ((cmd->resp_type == 0) || (data == NULL)) + rc = mxs_mci_std_cmds(mxs_mci, cmd); + else + rc = mxs_mci_adtc(mxs_mci, cmd, data); /* with response and data */ + + mxs_mci_finish_request(mxs_mci); /* TODO */ + return rc; +} + +/** + * Setup the bus width and IO speed + * @param mci_pdata MCI platform data + * @param mci_dev MCI device instance + * @param bus_width New bus width value (1, 4 or 8) + * @param clock New clock in Hz (can be '0' to disable the clock) + * + * Drivers currently realized values are stored in MCI's platformdata + */ +static void mxs_mci_set_ios(struct mci_host *host, struct device_d *mci_dev, + unsigned bus_width, unsigned clock) +{ + struct mxs_mci_host *mxs_mci = to_mxs_mci(host); + + switch (bus_width) { + case 8: + mxs_mci->bus_width = 2; + host->bus_width = 8; /* 8 bit is possible */ + break; + case 4: + mxs_mci->bus_width = 1; + host->bus_width = 4; /* 4 bit is possible */ + break; + default: + mxs_mci->bus_width = 0; + host->bus_width = 1; /* 1 bit is possible */ + break; + } + + mxs_mci->clock = mxs_mci_setup_clock_speed(mxs_mci, clock); + pr_debug("IO settings: bus width=%d, frequency=%u Hz\n", host->bus_width, + mxs_mci->clock); +} + +/* ----------------------------------------------------------------------- */ + +#ifdef CONFIG_MCI_INFO +const unsigned char bus_width[3] = { 1, 4, 8 }; + +static void mxs_mci_info(struct device_d *hw_dev) +{ + struct mxs_mci_host *mxs_mci = GET_HOST_DATA(hw_dev); + + printf(" Interface\n"); + printf(" Min. bus clock: %u Hz\n", mxs_mci->f_min); + printf(" Max. bus clock: %u Hz\n", mxs_mci->f_max); + printf(" Current bus clock: %u Hz\n", mxs_mci->clock); + printf(" Bus width: %u bit\n", bus_width[mxs_mci->bus_width]); + printf("\n"); +} +#endif + +static int mxs_mci_probe(struct device_d *hw_dev) +{ + struct mxs_mci_platform_data *pd = hw_dev->platform_data; + struct mxs_mci_host *mxs_mci; + struct mci_host *host; + + if (hw_dev->platform_data == NULL) { + pr_err("Missing platform data\n"); + return -EINVAL; + } + + mxs_mci = xzalloc(sizeof(*mxs_mci)); + host = &mxs_mci->host; + + hw_dev->priv = mxs_mci; + host->hw_dev = hw_dev; + host->send_cmd = mxs_mci_request, + host->set_ios = mxs_mci_set_ios, + host->init = mxs_mci_initialize, + mxs_mci->regs = (void *)hw_dev->map_base; + + /* feed forward the platform specific values */ + host->voltages = pd->voltages; + host->host_caps = pd->caps; + +#ifdef CONFIG_ARCH_IMX23 + mxs_mci->index = 0; /* there is only one clock for all */ +#endif +#ifdef CONFIG_ARCH_IMX28 + /* one dedicated clock per unit */ + switch (hw_dev->map_base) { + case IMX_SSP0_BASE: + mxs_mci->index = 0; + break; + case IMX_SSP1_BASE: + mxs_mci->index = 1; + break; + case IMX_SSP2_BASE: + mxs_mci->index = 2; + break; + case IMX_SSP3_BASE: + mxs_mci->index = 3; + break; + default: + pr_debug("Unknown SSP unit at address 0x%08x\n", mxs_mci->regs); + return 0; + } +#endif + if (pd->f_min == 0) { + host->f_min = mxs_mci_get_unit_clock(mxs_mci) / 254 / 256; + pr_debug("Min. frequency is %u Hz\n", host->f_min); + } else { + host->f_min = pd->f_min; + pr_debug("Min. frequency is %u Hz, could be %u Hz\n", + host->f_min, mxs_mci_get_unit_clock(mxs_mci) / 254 / 256); + } + if (pd->f_max == 0) { + host->f_max = mxs_mci_get_unit_clock(mxs_mci) / 2 / 1; + pr_debug("Max. frequency is %u Hz\n", host->f_max); + } else { + host->f_max = pd->f_max; + pr_debug("Max. frequency is %u Hz, could be %u Hz\n", + host->f_max, mxs_mci_get_unit_clock(mxs_mci) / 2 / 1); + } + +#ifdef CONFIG_MCI_INFO + mxs_mci->f_min = host->f_min; + mxs_mci->f_max = host->f_max; +#endif + + return mci_register(host); +} + +static struct driver_d mxs_mci_driver = { + .name = "mxs_mci", + .probe = mxs_mci_probe, +#ifdef CONFIG_MCI_INFO + .info = mxs_mci_info, +#endif +}; + +static int mxs_mci_init_driver(void) +{ + register_driver(&mxs_mci_driver); + return 0; +} + +device_initcall(mxs_mci_init_driver); diff --git a/drivers/mci/stm378x.c b/drivers/mci/stm378x.c deleted file mode 100644 index 94b0f4a..0000000 --- a/drivers/mci/stm378x.c +++ /dev/null @@ -1,804 +0,0 @@ -/* - * Copyright (C) 2010 Juergen Beisert, Pengutronix - * - * This code is based on: - * - * Copyright (C) 2007 SigmaTel, Inc., Ioannis Kappas - * - * Portions copyright (C) 2003 Russell King, PXA MMCI Driver - * Portions copyright (C) 2004-2005 Pierre Ossman, W83L51xD SD/MMC driver - * - * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. - * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -/** - * @file - * @brief MCI card host interface for i.MX23 CPU - */ - -/* #define DEBUG */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define CLOCKRATE_MIN (1 * 1000 * 1000) -#define CLOCKRATE_MAX (480 * 1000 * 1000) - -#define HW_SSP_CTRL0 0x000 -# define SSP_CTRL0_SFTRST (1 << 31) -# define SSP_CTRL0_CLKGATE (1 << 30) -# define SSP_CTRL0_RUN (1 << 29) -# define SSP_CTRL0_LOCK_CS (1 << 27) -# define SSP_CTRL0_READ (1 << 25) -# define SSP_CTRL0_IGNORE_CRC (1 << 26) -# define SSP_CTRL0_DATA_XFER (1 << 24) -# define SSP_CTRL0_BUS_WIDTH(x) (((x) & 0x3) << 22) -# define SSP_CTRL0_WAIT_FOR_IRQ (1 << 21) -# define SSP_CTRL0_LONG_RESP (1 << 19) -# define SSP_CTRL0_GET_RESP (1 << 17) -# define SSP_CTRL0_ENABLE (1 << 16) -#ifdef CONFIG_ARCH_IMX23 -# define SSP_CTRL0_XFER_COUNT(x) ((x) & 0xffff) -#endif - -#define HW_SSP_CMD0 0x010 -# define SSP_CMD0_SLOW_CLK (1 << 22) -# define SSP_CMD0_CONT_CLK (1 << 21) -# define SSP_CMD0_APPEND_8CYC (1 << 20) -#ifdef CONFIG_ARCH_IMX23 -# define SSP_CMD0_BLOCK_SIZE(x) (((x) & 0xf) << 16) -# define SSP_CMD0_BLOCK_COUNT(x) (((x) & 0xff) << 8) -#endif -# define SSP_CMD0_CMD(x) ((x) & 0xff) - -#define HW_SSP_CMD1 0x020 - -#ifdef CONFIG_ARCH_IMX23 -# define HW_SSP_COMPREF 0x030 -# define HW_SSP_COMPMASK 0x040 -# define HW_SSP_TIMING 0x050 -# define HW_SSP_CTRL1 0x060 -# define HW_SSP_DATA 0x070 -#endif -#ifdef CONFIG_ARCH_IMX28 -# define HW_SSP_XFER_COUNT 0x30 -# define HW_SSP_BLOCK_SIZE 0x40 -# define SSP_BLOCK_SIZE(x) ((x) & 0xf) -# define SSP_BLOCK_COUNT(x) (((x) & 0xffffff) << 4) -# define HW_SSP_COMPREF 0x050 -# define HW_SSP_COMPMASK 0x060 -# define HW_SSP_TIMING 0x070 -# define HW_SSP_CTRL1 0x080 -# define HW_SSP_DATA 0x090 -#endif -/* bit definition for register HW_SSP_TIMING */ -# define SSP_TIMING_TIMEOUT_MASK (0xffff0000) -# define SSP_TIMING_TIMEOUT(x) ((x) << 16) -# define SSP_TIMING_CLOCK_DIVIDE(x) (((x) & 0xff) << 8) -# define SSP_TIMING_CLOCK_RATE(x) ((x) & 0xff) - -/* bit definition for register HW_SSP_CTRL1 */ -# define SSP_CTRL1_POLARITY (1 << 9) -# define SSP_CTRL1_WORD_LENGTH(x) (((x) & 0xf) << 4) -# define SSP_CTRL1_SSP_MODE(x) ((x) & 0xf) - -#ifdef CONFIG_ARCH_IMX23 -# define HW_SSP_SDRESP0 0x080 -# define HW_SSP_SDRESP1 0x090 -# define HW_SSP_SDRESP2 0x0A0 -# define HW_SSP_SDRESP3 0x0B0 -#endif -#ifdef CONFIG_ARCH_IMX28 -# define HW_SSP_SDRESP0 0x0A0 -# define HW_SSP_SDRESP1 0x0B0 -# define HW_SSP_SDRESP2 0x0C0 -# define HW_SSP_SDRESP3 0x0D0 -#endif - -#ifdef CONFIG_ARCH_IMX28 -# define HW_SSP_DDR_CTRL 0x0E0 -# define HW_SSP_DLL_CTRL 0x0F0 -#endif - -#ifdef CONFIG_ARCH_IMX23 -# define HW_SSP_STATUS 0x0C0 -#endif -#ifdef CONFIG_ARCH_IMX28 -# define HW_SSP_STATUS 0x100 -#endif - -/* bit definition for register HW_SSP_STATUS */ -# define SSP_STATUS_PRESENT (1 << 31) -# define SSP_STATUS_SD_PRESENT (1 << 29) -# define SSP_STATUS_CARD_DETECT (1 << 28) -# define SSP_STATUS_RESP_CRC_ERR (1 << 16) -# define SSP_STATUS_RESP_ERR (1 << 15) -# define SSP_STATUS_RESP_TIMEOUT (1 << 14) -# define SSP_STATUS_DATA_CRC_ERR (1 << 13) -# define SSP_STATUS_TIMEOUT (1 << 12) -# define SSP_STATUS_FIFO_OVRFLW (1 << 9) -# define SSP_STATUS_FIFO_FULL (1 << 8) -# define SSP_STATUS_FIFO_EMPTY (1 << 5) -# define SSP_STATUS_FIFO_UNDRFLW (1 << 4) -# define SSP_STATUS_CMD_BUSY (1 << 3) -# define SSP_STATUS_DATA_BUSY (1 << 2) -# define SSP_STATUS_BUSY (1 << 0) -# define SSP_STATUS_ERROR (SSP_STATUS_FIFO_OVRFLW | SSP_STATUS_FIFO_UNDRFLW | \ - SSP_STATUS_RESP_CRC_ERR | SSP_STATUS_RESP_ERR | \ - SSP_STATUS_RESP_TIMEOUT | SSP_STATUS_DATA_CRC_ERR | SSP_STATUS_TIMEOUT) - -#ifdef CONFIG_ARCH_IMX28 -# define HW_SSP_DLL_STS 0x110 -#endif - -#ifdef CONFIG_ARCH_IMX23 -# define HW_SSP_DEBUG 0x100 -# define HW_SSP_VERSION 0x110 -#endif - -#ifdef CONFIG_ARCH_IMX28 -# define HW_SSP_DEBUG 0x120 -# define HW_SSP_VERSION 0x130 -#endif - -struct stm_mci_host { - unsigned clock; /* current clock speed in Hz ("0" if disabled) */ - unsigned index; -#ifdef CONFIG_MCI_INFO - unsigned f_min; - unsigned f_max; -#endif - int bus_width:2; /* 0 = 1 bit, 1 = 4 bit, 2 = 8 bit */ -}; - -/** - * Get the SSP clock rate - * @param hw_dev Host interface device instance - * @return Unit's clock in [Hz] - */ -static unsigned get_unit_clock(struct device_d *hw_dev) -{ - struct stm_mci_host *host_data = GET_HOST_DATA(hw_dev); - - return imx_get_sspclk(host_data->index); -} - -/** - * Get MCI cards response if defined for the type of command - * @param hw_dev Host interface device instance - * @param cmd Command description - * @return Response bytes count, -EINVAL for unsupported response types - */ -static int get_cards_response(struct device_d *hw_dev, struct mci_cmd *cmd) -{ - switch (cmd->resp_type) { - case MMC_RSP_NONE: - return 0; - - case MMC_RSP_R1: - case MMC_RSP_R1b: - case MMC_RSP_R3: - cmd->response[0] = readl(hw_dev->map_base + HW_SSP_SDRESP0); - return 1; - - case MMC_RSP_R2: - cmd->response[3] = readl(hw_dev->map_base + HW_SSP_SDRESP0); - cmd->response[2] = readl(hw_dev->map_base + HW_SSP_SDRESP1); - cmd->response[1] = readl(hw_dev->map_base + HW_SSP_SDRESP2); - cmd->response[0] = readl(hw_dev->map_base + HW_SSP_SDRESP3); - return 4; - } - - return -EINVAL; -} - -/** - * Finish a request to the MCI card - * @param hw_dev Host interface device instance - * - * Can also stop the clock to save power - */ -static void finish_request(struct device_d *hw_dev) -{ - /* stop the engines (normaly already done) */ - writel(SSP_CTRL0_RUN, hw_dev->map_base + HW_SSP_CTRL0 + 8); -} - -/** - * Check if the last command failed and if, why it failed - * @param status HW_SSP_STATUS's content - * @return 0 if no error, negative values else - */ -static int get_cmd_error(unsigned status) -{ - if (status & SSP_STATUS_ERROR) - pr_debug("Status Reg reports %08X\n", status); - - if (status & SSP_STATUS_TIMEOUT) { - pr_debug("CMD timeout\n"); - return -ETIMEDOUT; - } else if (status & SSP_STATUS_RESP_TIMEOUT) { - pr_debug("RESP timeout\n"); - return -ETIMEDOUT; - } else if (status & SSP_STATUS_RESP_CRC_ERR) { - pr_debug("CMD crc error\n"); - return -EILSEQ; - } else if (status & SSP_STATUS_RESP_ERR) { - pr_debug("RESP error\n"); - return -EIO; - } - - return 0; -} - -/** - * Define the timout for the next command - * @param hw_dev Host interface device instance - * @param to Timeout value in MCI card's bus clocks - */ -static void stm_setup_timout(struct device_d *hw_dev, unsigned to) -{ - uint32_t reg; - - reg = readl(hw_dev->map_base + HW_SSP_TIMING) & ~SSP_TIMING_TIMEOUT_MASK; - reg |= SSP_TIMING_TIMEOUT(to); - writel(reg, hw_dev->map_base + HW_SSP_TIMING); -} - -/** - * Read data from the MCI card - * @param hw_dev Host interface device instance - * @param buffer To write data into - * @param length Count of bytes to read (must be multiples of 4) - * @return 0 on success, negative values else - * - * @note This routine uses PIO to read in the data bytes from the FIFO. This - * may fail whith high clock speeds. If you receive -EIO errors you can try - * again with reduced clock speeds. - */ -static int read_data(struct device_d *hw_dev, void *buffer, unsigned length) -{ - uint32_t *p = buffer; - - if (length & 0x3) { - pr_debug("Cannot read data sizes not multiple of 4 (request for %u detected)\n", - length); - return -EINVAL; - } - - while ((length != 0) && - ((readl(hw_dev->map_base + HW_SSP_STATUS) & SSP_STATUS_ERROR) == 0)) { - /* TODO sort out FIFO overflows and emit -EOI for this case */ - if ((readl(hw_dev->map_base + HW_SSP_STATUS) & SSP_STATUS_FIFO_EMPTY) == 0) { - *p = readl(hw_dev->map_base + HW_SSP_DATA); - p++; - length -= 4; - } - } - - if (length == 0) - return 0; - - return -EINVAL; -} - - -/** - * Write data into the MCI card - * @param hw_dev Host interface device instance - * @param buffer To read the data from - * @param length Count of bytes to write (must be multiples of 4) - * @return 0 on success, negative values else - * - * @note This routine uses PIO to write the data bytes into the FIFO. This - * may fail with high clock speeds. If you receive -EIO errors you can try - * again with reduced clock speeds. - */ -static int write_data(struct device_d *hw_dev, const void *buffer, unsigned length) -{ - const uint32_t *p = buffer; - - if (length & 0x3) { - pr_debug("Cannot write data sizes not multiple of 4 (request for %u detected)\n", - length); - return -EINVAL; - } - - while ((length != 0) && - ((readl(hw_dev->map_base + HW_SSP_STATUS) & SSP_STATUS_ERROR) == 0)) { - /* TODO sort out FIFO overflows and emit -EOI for this case */ - if ((readl(hw_dev->map_base + HW_SSP_STATUS) & SSP_STATUS_FIFO_FULL) == 0) { - writel(*p, hw_dev->map_base + HW_SSP_DATA); - p++; - length -= 4; - } - } - if (length == 0) - return 0; - - return -EINVAL; -} - -/** - * Start the transaction with or without data - * @param hw_dev Host interface device instance - * @param data Data transfer description (might be NULL) - * @return 0 on success - */ -static int transfer_data(struct device_d *hw_dev, struct mci_data *data) -{ - unsigned length; - - if (data != NULL) { - length = data->blocks * data->blocksize; -#if 0 - /* - * For the records: When writing data with high clock speeds it - * could be a good idea to fill the FIFO prior starting the - * transaction. - * But last time I tried it, it failed badly. Don't know why yet - */ - if (data->flags & MMC_DATA_WRITE) { - err = write_data(host, data->src, 16); - data->src += 16; - length -= 16; - } -#endif - } - - /* - * Everything is ready for the transaction now: - * - transfer configuration - * - command and its parameters - * - * Start the transaction right now - */ - writel(SSP_CTRL0_RUN, hw_dev->map_base + HW_SSP_CTRL0 + 4); - - if (data != NULL) { - if (data->flags & MMC_DATA_READ) - return read_data(hw_dev, data->dest, length); - else - return write_data(hw_dev, data->src, length); - } - - return 0; -} - -/** - * Configure the MCI hardware for the next transaction - * @param cmd_flags Command information - * @param data_flags Data information (may be 0) - * @return Corresponding setting for the SSP_CTRL0 register - */ -static uint32_t prepare_transfer_setup(unsigned cmd_flags, unsigned data_flags) -{ - uint32_t reg = 0; - - if (cmd_flags & MMC_RSP_PRESENT) - reg |= SSP_CTRL0_GET_RESP; - if ((cmd_flags & MMC_RSP_CRC) == 0) - reg |= SSP_CTRL0_IGNORE_CRC; - if (cmd_flags & MMC_RSP_136) - reg |= SSP_CTRL0_LONG_RESP; - if (cmd_flags & MMC_RSP_BUSY) - reg |= SSP_CTRL0_WAIT_FOR_IRQ; /* FIXME correct? */ -#if 0 - if (cmd_flags & MMC_RSP_OPCODE) - /* TODO */ -#endif - if (data_flags & MMC_DATA_READ) - reg |= SSP_CTRL0_READ; - - return reg; -} - -/** - * Handle MCI commands without data - * @param hw_dev Host interface device instance - * @param cmd The command to handle - * @return 0 on success - * - * This functions handles the following MCI commands: - * - "broadcast command (BC)" without a response - * - "broadcast commands with response (BCR)" - * - "addressed command (AC)" with response, but without data - */ -static int stm_mci_std_cmds(struct device_d *hw_dev, struct mci_cmd *cmd) -{ - /* setup command and transfer parameters */ - writel(prepare_transfer_setup(cmd->resp_type, 0) | - SSP_CTRL0_ENABLE, hw_dev->map_base + HW_SSP_CTRL0); - - /* prepare the command, when no response is expected add a few trailing clocks */ - writel(SSP_CMD0_CMD(cmd->cmdidx) | - (cmd->resp_type & MMC_RSP_PRESENT ? 0 : SSP_CMD0_APPEND_8CYC), - hw_dev->map_base + HW_SSP_CMD0); - - /* prepare command's arguments */ - writel(cmd->cmdarg, hw_dev->map_base + HW_SSP_CMD1); - - stm_setup_timout(hw_dev, 0xffff); - - /* start the transfer */ - writel(SSP_CTRL0_RUN, hw_dev->map_base + HW_SSP_CTRL0 + 4); - - /* wait until finished */ - while (readl(hw_dev->map_base + HW_SSP_CTRL0) & SSP_CTRL0_RUN) - ; - - if (cmd->resp_type & MMC_RSP_PRESENT) - get_cards_response(hw_dev, cmd); - - return get_cmd_error(readl(hw_dev->map_base + HW_SSP_STATUS)); -} - -/** - * Handle an "addressed data transfer command " with or without data - * @param hw_dev Host interface device instance - * @param cmd The command to handle - * @param data The data information (buffer, direction aso.) May be NULL - * @return 0 on success - */ -static int stm_mci_adtc(struct device_d *hw_dev, struct mci_cmd *cmd, - struct mci_data *data) -{ - struct stm_mci_host *host_data = (struct stm_mci_host*)GET_HOST_DATA(hw_dev); - uint32_t xfer_cnt, log2blocksize, block_cnt; - int err; - - /* Note: 'data' can be NULL! */ - if (data != NULL) { - xfer_cnt = data->blocks * data->blocksize; - block_cnt = data->blocks - 1; /* can be 0 */ - log2blocksize = find_first_bit((const unsigned long*)&data->blocksize, - 32); - } else - xfer_cnt = log2blocksize = block_cnt = 0; - - /* setup command and transfer parameters */ -#ifdef CONFIG_ARCH_IMX23 - writel(prepare_transfer_setup(cmd->resp_type, data != NULL ? data->flags : 0) | - SSP_CTRL0_BUS_WIDTH(host_data->bus_width) | - (xfer_cnt != 0 ? SSP_CTRL0_DATA_XFER : 0) | /* command plus data */ - SSP_CTRL0_ENABLE | - SSP_CTRL0_XFER_COUNT(xfer_cnt), /* byte count to be transfered */ - hw_dev->map_base + HW_SSP_CTRL0); - - /* prepare the command and the transfered data count */ - writel(SSP_CMD0_CMD(cmd->cmdidx) | - SSP_CMD0_BLOCK_SIZE(log2blocksize) | - SSP_CMD0_BLOCK_COUNT(block_cnt) | - (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION ? SSP_CMD0_APPEND_8CYC : 0), - hw_dev->map_base + HW_SSP_CMD0); -#endif -#ifdef CONFIG_ARCH_IMX28 - writel(prepare_transfer_setup(cmd->resp_type, data != NULL ? data->flags : 0) | - SSP_CTRL0_BUS_WIDTH(host_data->bus_width) | - (xfer_cnt != 0 ? SSP_CTRL0_DATA_XFER : 0) | /* command plus data */ - SSP_CTRL0_ENABLE, - hw_dev->map_base + HW_SSP_CTRL0); - writel(xfer_cnt, hw_dev->map_base + HW_SSP_XFER_COUNT); - - /* prepare the command and the transfered data count */ - writel(SSP_CMD0_CMD(cmd->cmdidx) | - (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION ? SSP_CMD0_APPEND_8CYC : 0), - hw_dev->map_base + HW_SSP_CMD0); - writel(SSP_BLOCK_SIZE(log2blocksize) | - SSP_BLOCK_COUNT(block_cnt), - hw_dev->map_base + HW_SSP_BLOCK_SIZE); -#endif - - /* prepare command's arguments */ - writel(cmd->cmdarg, hw_dev->map_base + HW_SSP_CMD1); - - stm_setup_timout(hw_dev, 0xffff); - - err = transfer_data(hw_dev, data); - if (err != 0) { - pr_debug(" Transfering data failed\n"); - return err; - } - - /* wait until finished */ - while (readl(hw_dev->map_base + HW_SSP_CTRL0) & SSP_CTRL0_RUN) - ; - - get_cards_response(hw_dev, cmd); - - return 0; -} - - -/** - * @param hw_dev Host interface device instance - * @param nc New Clock in [Hz] (may be 0 to disable the clock) - * @return The real clock frequency - * - * The SSP unit clock can base on the external 24 MHz or the internal 480 MHz - * Its unit clock value is derived from the io clock, from the SSP divider - * and at least the SSP bus clock itself is derived from the SSP unit's divider - * - * @code - * |------------------- generic -------------|-peripheral specific-|-----all SSPs-----|-per SSP unit-| - * 24 MHz ---------------------------- - * \ \ - * \ |----| FRAC |----IO CLK----| SSP unit DIV |---| SSP DIV |--- SSP output clock - * \- | PLL |--- 480 MHz ---/ - * @endcode - * - * @note Up to "SSP unit DIV" the outer world must care. This routine only - * handles the "SSP DIV". - */ -static unsigned setup_clock_speed(struct device_d *hw_dev, unsigned nc) -{ - unsigned ssp, div, rate, reg; - - if (nc == 0U) { - /* TODO stop the clock */ - return 0; - } - - ssp = get_unit_clock(hw_dev); - - for (div = 2; div < 255; div += 2) { - rate = DIV_ROUND_CLOSEST(DIV_ROUND_CLOSEST(ssp, nc), div); - if (rate <= 0x100) - break; - } - if (div >= 255) { - pr_warning("Cannot set clock to %d Hz\n", nc); - return 0; - } - - reg = readl(hw_dev->map_base + HW_SSP_TIMING) & SSP_TIMING_TIMEOUT_MASK; - reg |= SSP_TIMING_CLOCK_DIVIDE(div) | SSP_TIMING_CLOCK_RATE(rate - 1); - writel(reg, hw_dev->map_base + HW_SSP_TIMING); - - return ssp / div / rate; -} - -/** - * Reset the MCI engine (the hard way) - * @param hw_dev Host interface instance - * - * This will reset everything in all registers of this unit! (FIXME) - */ -static void stm_mci_reset(struct device_d *hw_dev) -{ - writel(SSP_CTRL0_SFTRST, hw_dev->map_base + HW_SSP_CTRL0 + 8); - while (readl(hw_dev->map_base + HW_SSP_CTRL0) & SSP_CTRL0_SFTRST) - ; -} - -/** - * Initialize the engine - * @param hw_dev Host interface instance - * @param mci_dev MCI device instance - */ -static int stm_mci_initialize(struct device_d *hw_dev, struct device_d *mci_dev) -{ - struct mci_host *host = GET_MCI_PDATA(mci_dev); - struct stm_mci_host *host_data = (struct stm_mci_host*)GET_HOST_DATA(hw_dev); - - /* enable the clock to this unit to be able to reset it */ - writel(SSP_CTRL0_CLKGATE, hw_dev->map_base + HW_SSP_CTRL0 + 8); - - /* reset the unit */ - stm_mci_reset(hw_dev); - - /* restore the last settings */ - host->clock = host_data->clock = setup_clock_speed(hw_dev, host->clock); - stm_setup_timout(hw_dev, 0xffff); - writel(SSP_CTRL0_IGNORE_CRC | - SSP_CTRL0_BUS_WIDTH(host_data->bus_width), - hw_dev->map_base + HW_SSP_CTRL0); - writel(SSP_CTRL1_POLARITY | - SSP_CTRL1_SSP_MODE(3) | - SSP_CTRL1_WORD_LENGTH(7), hw_dev->map_base + HW_SSP_CTRL1); - - return 0; -} - -/* ------------------------- MCI API -------------------------------------- */ - -/** - * Keep the attached MMC/SD unit in a well know state - * @param mci_pdata MCI platform data - * @param mci_dev MCI device instance - * @return 0 on success, negative value else - */ -static int mci_reset(struct mci_host *mci_pdata, struct device_d *mci_dev) -{ - struct device_d *hw_dev = mci_pdata->hw_dev; - - return stm_mci_initialize(hw_dev, mci_dev); -} - -/** - * Process one command to the MCI card - * @param mci_pdata MCI platform data - * @param cmd The command to process - * @param data The data to handle in the command (can be NULL) - * @return 0 on success, negative value else - */ -static int mci_request(struct mci_host *mci_pdata, struct mci_cmd *cmd, - struct mci_data *data) -{ - struct device_d *hw_dev = mci_pdata->hw_dev; - int rc; - - if ((cmd->resp_type == 0) || (data == NULL)) - rc = stm_mci_std_cmds(hw_dev, cmd); - else - rc = stm_mci_adtc(hw_dev, cmd, data); /* with response and data */ - - finish_request(hw_dev); /* TODO */ - return rc; -} - -/** - * Setup the bus width and IO speed - * @param mci_pdata MCI platform data - * @param mci_dev MCI device instance - * @param bus_width New bus width value (1, 4 or 8) - * @param clock New clock in Hz (can be '0' to disable the clock) - * - * Drivers currently realized values are stored in MCI's platformdata - */ -static void mci_set_ios(struct mci_host *mci_pdata, struct device_d *mci_dev, - unsigned bus_width, unsigned clock) -{ - struct device_d *hw_dev = mci_pdata->hw_dev; - struct stm_mci_host *host_data = (struct stm_mci_host*)GET_HOST_DATA(hw_dev); - struct mci_host *host = GET_MCI_PDATA(mci_dev); - - switch (bus_width) { - case 8: - host_data->bus_width = 2; - host->bus_width = 8; /* 8 bit is possible */ - break; - case 4: - host_data->bus_width = 1; - host->bus_width = 4; /* 4 bit is possible */ - break; - default: - host_data->bus_width = 0; - host->bus_width = 1; /* 1 bit is possible */ - break; - } - - host->clock = host_data->clock = setup_clock_speed(hw_dev, clock); - pr_debug("IO settings: bus width=%d, frequency=%u Hz\n", host->bus_width, - host->clock); -} - -/* ----------------------------------------------------------------------- */ - -#ifdef CONFIG_MCI_INFO -const unsigned char bus_width[3] = { 1, 4, 8 }; - -static void stm_info(struct device_d *hw_dev) -{ - struct stm_mci_host *host_data = GET_HOST_DATA(hw_dev); - - printf(" Interface\n"); - printf(" Min. bus clock: %u Hz\n", host_data->f_min); - printf(" Max. bus clock: %u Hz\n", host_data->f_max); - printf(" Current bus clock: %u Hz\n", host_data->clock); - printf(" Bus width: %u bit\n", bus_width[host_data->bus_width]); - printf("\n"); -} -#endif - -static int stm_mci_probe(struct device_d *hw_dev) -{ - struct stm_mci_platform_data *pd = hw_dev->platform_data; - struct stm_mci_host *host_data; - struct mci_host *host; - - if (hw_dev->platform_data == NULL) { - pr_err("Missing platform data\n"); - return -EINVAL; - } - - host = xzalloc(sizeof(struct stm_mci_host) + sizeof(struct mci_host)); - host_data = (struct stm_mci_host*)&host[1]; - - hw_dev->priv = host_data; - host->hw_dev = hw_dev; - host->send_cmd = mci_request, - host->set_ios = mci_set_ios, - host->init = mci_reset, - - /* feed forward the platform specific values */ - host->voltages = pd->voltages; - host->host_caps = pd->caps; - -#ifdef CONFIG_ARCH_IMX23 - host_data->index = 0; /* there is only one clock for all */ -#endif -#ifdef CONFIG_ARCH_IMX28 - /* one dedicated clock per unit */ - switch (hw_dev->map_base) { - case IMX_SSP0_BASE: - host_data->index = 0; - break; - case IMX_SSP1_BASE: - host_data->index = 1; - break; - case IMX_SSP2_BASE: - host_data->index = 2; - break; - case IMX_SSP3_BASE: - host_data->index = 3; - break; - default: - pr_debug("Unknown SSP unit at address 0x%08x\n", hw_dev->map_base); - return 0; - } -#endif - if (pd->f_min == 0) { - host->f_min = get_unit_clock(hw_dev) / 254 / 256; - pr_debug("Min. frequency is %u Hz\n", host->f_min); - } else { - host->f_min = pd->f_min; - pr_debug("Min. frequency is %u Hz, could be %u Hz\n", - host->f_min, get_unit_clock(hw_dev) / 254 / 256); - } - if (pd->f_max == 0) { - host->f_max = get_unit_clock(hw_dev) / 2 / 1; - pr_debug("Max. frequency is %u Hz\n", host->f_max); - } else { - host->f_max = pd->f_max; - pr_debug("Max. frequency is %u Hz, could be %u Hz\n", - host->f_max, get_unit_clock(hw_dev) / 2 / 1); - } - -#ifdef CONFIG_MCI_INFO - host_data->f_min = host->f_min; - host_data->f_max = host->f_max; -#endif - - return mci_register(host); -} - -static struct driver_d stm_mci_driver = { - .name = "stm_mci", - .probe = stm_mci_probe, -#ifdef CONFIG_MCI_INFO - .info = stm_info, -#endif -}; - -static int stm_mci_init_driver(void) -{ - register_driver(&stm_mci_driver); - return 0; -} - -device_initcall(stm_mci_init_driver); diff --git a/drivers/mtd/nand/nand_imx.c b/drivers/mtd/nand/nand_imx.c index 661b190..a13f321 100644 --- a/drivers/mtd/nand/nand_imx.c +++ b/drivers/mtd/nand/nand_imx.c @@ -1145,7 +1145,7 @@ imx_nand_set_layout(mtd->writesize, pdata->width == 2 ? 16 : 8); - if (mtd->writesize == 2048) { + if (mtd->writesize >= 2048) { this->ecc.layout = oob_largepage; host->pagesize_2k = 1; if (nfc_is_v21()) diff --git a/drivers/mtd/nand/nand_s3c2410.c b/drivers/mtd/nand/nand_s3c2410.c index df0b7c1..88e89cd 100644 --- a/drivers/mtd/nand/nand_s3c2410.c +++ b/drivers/mtd/nand/nand_s3c2410.c @@ -99,7 +99,7 @@ }; /** - * oob placement block for use with hardware ecc generation + * oob placement block for use with hardware ecc generation on small page */ static struct nand_ecclayout nand_hw_eccoob = { .eccbytes = 3, @@ -247,13 +247,13 @@ /** * Check the ECC and try to repair the data if possible - * @param[in] mtd_info FIXME + * @param[in] mtd_info Not used * @param[inout] dat Pointer to the data buffer that might contain a bit error * @param[in] read_ecc ECC data from the OOB space * @param[in] calc_ecc ECC data calculated from the data * @return 0 no error, 1 repaired error, -1 no way... * - * @note: Alsways 512 byte of data + * @note: This routine works always on a 24 bit ECC */ static int s3c2410_nand_correct_data(struct mtd_info *mtd, uint8_t *dat, uint8_t *read_ecc, uint8_t *calc_ecc) @@ -272,8 +272,7 @@ * to see if we have an 0xff,0xff,0xff read ECC and then ignore * the error, on the assumption that this is an un-eccd page. */ - if (read_ecc[0] == 0xff && read_ecc[1] == 0xff && read_ecc[2] == 0xff - /* && info->platform->ignore_unset_ecc */) + if (read_ecc[0] == 0xff && read_ecc[1] == 0xff && read_ecc[2] == 0xff) return 0; /* Can we correct this ECC (ie, one row and column change). @@ -431,10 +430,7 @@ mtd->priv = chip; /* init the default settings */ -#if 0 - /* TODO: Will follow later */ - init_nand_chip_bw8(chip); -#endif + /* 50 us command delay time */ chip->chip_delay = 50; chip->priv = host; @@ -453,13 +449,25 @@ chip->ecc.calculate = s3c2410_nand_calculate_ecc; chip->ecc.correct = s3c2410_nand_correct_data; chip->ecc.hwctl = s3c2410_nand_enable_hwecc; - chip->ecc.calculate = s3c2410_nand_calculate_ecc; - /* our hardware capabilities */ + /* + * Setup ECC handling in accordance to the kernel + * - 1 times 512 bytes with 24 bit ECC for small page + * - 8 times 256 bytes with 24 bit ECC each for large page + */ chip->ecc.mode = NAND_ECC_HW; - chip->ecc.size = 512; - chip->ecc.bytes = 3; - chip->ecc.layout = &nand_hw_eccoob; + chip->ecc.bytes = 3; /* always 24 bit ECC per turn */ +#ifdef CONFIG_CPU_S3C2440 + if (readl(host->base) & 0x8) { + /* large page (2048 bytes per page) */ + chip->ecc.size = 256; + } else +#endif + { + /* small page (512 bytes per page) */ + chip->ecc.size = 512; + chip->ecc.layout = &nand_hw_eccoob; + } if (pdata->flash_bbt) { /* use a flash based bbt */ @@ -497,37 +505,78 @@ ; } -static void __nand_boot_init nfc_addr(void __iomem *host, uint32_t offs) +/** + * Convert a page offset into a page address for the NAND + * @param host Where to write the address to + * @param offs Page's offset in the NAND + * @param ps Page size (512 or 2048) + * @param c Address cycle count (3, 4 or 5) + * + * Uses the offset of the page to generate an page address into the NAND. This + * differs when using a 512 byte or 2048 bytes per page NAND. + * The collumn part of the page address to be generated is always forced to '0'. + */ +static void __nand_boot_init nfc_addr(void __iomem *host, uint32_t offs, + int ps, int c) { - send_addr(host, offs & 0xff); - send_addr(host, (offs >> 9) & 0xff); - send_addr(host, (offs >> 17) & 0xff); - send_addr(host, (offs >> 25) & 0xff); + send_addr(host, 0); /* collumn part 1 */ + + if (ps == 512) { + send_addr(host, offs >> 9); + send_addr(host, offs >> 17); + if (c > 3) + send_addr(host, offs >> 25); + } else { + send_addr(host, 0); /* collumn part 2 */ + send_addr(host, offs >> 11); + send_addr(host, offs >> 19); + if (c > 4) + send_addr(host, offs >> 27); + send_cmd(host, NAND_CMD_READSTART); + } } /** - * Load a sequential count of blocks from the NAND into memory + * Load a sequential count of pages from the NAND into memory * @param[out] dest Pointer to target area (in SDRAM) * @param[in] size Bytes to read from NAND device * @param[in] page Start page to read from - * @param[in] pagesize Size of each page in the NAND * * This function must be located in the first 4kiB of the barebox image - * (guess why). When this routine is running the SDRAM is up and running - * and it runs from the correct address (physical=linked address). - * TODO Could we access the platform data from the boardfile? - * Due to it makes no sense this function does not return in case of failure. + * (guess why). */ -void __nand_boot_init s3c24x0_nand_load_image(void *dest, int size, int page, int pagesize) +void __nand_boot_init s3c24x0_nand_load_image(void *dest, int size, int page) { void __iomem *host = (void __iomem *)S3C24X0_NAND_BASE; - int i; + unsigned pagesize; + int i, cycle; /* * Reenable the NFC and use the default (but slow) access * timing or the board specific setting if provided. */ enable_nand_controller(host, BOARD_DEFAULT_NAND_TIMING); + + /* use the current NAND hardware configuration */ + switch (readl(S3C24X0_NAND_BASE) & 0xf) { + case 0x6: /* 8 bit, 4 addr cycles, 512 bpp, normal NAND */ + pagesize = 512; + cycle = 4; + break; + case 0xc: /* 8 bit, 4 addr cycles, 2048 bpp, advanced NAND */ + pagesize = 2048; + cycle = 4; + break; + case 0xe: /* 8 bit, 5 addr cycles, 2048 bpp, advanced NAND */ + pagesize = 2048; + cycle = 5; + break; + default: + /* we cannot output an error message here :-( */ + disable_nand_controller(host); + return; + } + enable_cs(host); /* Reset the NAND device */ @@ -538,7 +587,7 @@ do { enable_cs(host); send_cmd(host, NAND_CMD_READ0); - nfc_addr(host, page * pagesize); + nfc_addr(host, page * pagesize, pagesize, cycle); wait_for_completion(host); /* copy one page (do *not* use readsb() here!)*/ for (i = 0; i < pagesize; i++) @@ -560,22 +609,25 @@ static int do_nand_boot_test(struct command *cmdtp, int argc, char *argv[]) { void *dest; - int size, pagesize; + int size; if (argc < 3) return COMMAND_ERROR_USAGE; dest = (void *)strtoul_suffix(argv[1], NULL, 0); size = strtoul_suffix(argv[2], NULL, 0); - pagesize = strtoul_suffix(argv[3], NULL, 0); - s3c24x0_nand_load_image(dest, size, 0, pagesize); + s3c24x0_nand_load_image(dest, size, 0); + + /* re-enable the controller again, as this was a test only */ + enable_nand_controller((void *)S3C24X0_NAND_BASE, + BOARD_DEFAULT_NAND_TIMING); return 0; } static const __maybe_unused char cmd_nand_boot_test_help[] = -"Usage: nand_boot_test \n"; +"Usage: nand_boot_test \n"; BAREBOX_CMD_START(nand_boot_test) .cmd = do_nand_boot_test, @@ -596,3 +648,18 @@ } device_initcall(s3c24x0_nand_init); + +/** + * @file + * @brief Support for various kinds of NAND devices + * + * ECC handling in this driver (in accordance to the current 2.6.38 kernel): + * - for small page NANDs it generates 3 ECC bytes out of 512 data bytes + * - for large page NANDs it generates 24 ECC bytes out of 2048 data bytes + * + * As small page NANDs are using 48 bits ECC per default, this driver uses a + * local OOB layout description, to shrink it down to 24 bits. This is a bad + * idea, but we cannot change it here, as the kernel is using this layout. + * + * For large page NANDs this driver uses the default layout, as the kernel does. + */ diff --git a/fs/ramfs.c b/fs/ramfs.c index 6222550..91001f1 100644 --- a/fs/ramfs.c +++ b/fs/ramfs.c @@ -30,7 +30,7 @@ #include #include -#define CHUNK_SIZE 512 +#define CHUNK_SIZE 4096 struct ramfs_chunk { char *data; diff --git a/include/kallsyms.h b/include/kallsyms.h index 5117be2..69b84d2 100644 --- a/include/kallsyms.h +++ b/include/kallsyms.h @@ -2,6 +2,11 @@ #define __KALLSYMS_H #define KSYM_NAME_LEN 128 +#define KSYM_SYMBOL_LEN (sizeof("%s+%#lx/%#lx [%s]") + (KSYM_NAME_LEN - 1) + \ + 2*(BITS_PER_LONG*3/10) + (MODULE_NAME_LEN - 1) + 1) unsigned long kallsyms_lookup_name(const char *name); +/* Look up a kernel symbol and return it in a text buffer. */ +int sprint_symbol(char *buffer, unsigned long address); + #endif /* __KALLSYMS_H */ diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 6671a72..8e20876 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -45,8 +45,8 @@ * is supported now. If you add a chip with bigger oobsize/page * adjust this accordingly. */ -#define NAND_MAX_OOBSIZE 64 -#define NAND_MAX_PAGESIZE 2048 +#define NAND_MAX_OOBSIZE 576 +#define NAND_MAX_PAGESIZE 8192 /* * Constants for hardware specific CLE/ALE/NCE function diff --git a/lib/vsprintf.c b/lib/vsprintf.c index fec87ba..ccccc5d 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include