From 9dbeb31891827802d2fce7b5b34dc865e6c7c237 Mon Sep 17 00:00:00 2001 From: cronyx Date: Fri, 21 Apr 2023 22:59:53 +0300 Subject: [PATCH] Prepare to add Ingenic T40 (#737) --- br-ext-chip-ingenic/Config.in | 1 + .../t40/kernel/patches/00000-Makefile.patch | 25 + .../00000-arch_mips_Kbuild.platforms.patch | 12 + .../00000-arch_mips_Kconfig.debug.patch | 12 + .../patches/00000-arch_mips_Kconfig.patch | 101 + .../patches/00000-arch_mips_Makefile.patch | 28 + .../00000-arch_mips_boot_Makefile.patch | 23 + ...-arch_mips_boot_dts_ingenic_Makefile.patch | 18 + ...mips_boot_dts_ingenic_halley2v20.dts.patch | 370 ++ ...-arch_mips_boot_dts_ingenic_seal.dts.patch | 305 + ...arch_mips_boot_dts_ingenic_shark.dts.patch | 309 + ...mips_boot_dts_ingenic_shark_fast.dts.patch | 295 + ...ps_boot_dts_ingenic_t40-pinctrl.dtsi.patch | 268 + ...-arch_mips_boot_dts_ingenic_t40.dtsi.patch | 559 ++ ...h_mips_boot_dts_ingenic_t40_fpga.dts.patch | 129 + ...t_dts_ingenic_x2000-v12-pinctrl.dtsi.patch | 512 ++ ...mips_boot_dts_ingenic_x2000-v12.dtsi.patch | 742 +++ ..._boot_dts_ingenic_x2000_v12_fpga.dts.patch | 197 + ...-arch_mips_boot_zcompressed_Makefile.patch | 73 + ...0-arch_mips_boot_zcompressed_dummy.c.patch | 8 + ...000-arch_mips_boot_zcompressed_entry.patch | 16 + ...-arch_mips_boot_zcompressed_filesize.patch | 11 + ...00-arch_mips_boot_zcompressed_head.S.patch | 91 + ...arch_mips_boot_zcompressed_ld.script.patch | 155 + ...00-arch_mips_boot_zcompressed_misc.c.patch | 389 ++ ...ch_mips_boot_zcompressed_tools_entry.patch | 16 + ...mips_boot_zcompressed_tools_filesize.patch | 11 + ...000-arch_mips_include_asm_bootinfo.h.patch | 12 + ...0-arch_mips_include_asm_cacheflush.h.patch | 25 + .../00000-arch_mips_include_asm_cop2.h.patch | 20 + ...arch_mips_include_asm_cpu-features.h.patch | 23 + .../00000-arch_mips_include_asm_cpu.h.patch | 65 + .../00000-arch_mips_include_asm_fpu.h.patch | 34 + ...000-arch_mips_include_asm_irqflags.h.patch | 24 + .../00000-arch_mips_include_asm_msa.h.patch | 21 + ...arch_mips_include_asm_pgtable-bits.h.patch | 21 + ...00-arch_mips_include_asm_processor.h.patch | 155 + ...000-arch_mips_include_asm_r4kcache.h.patch | 101 + ...00-arch_mips_include_asm_switch_to.h.patch | 60 + ...h_mips_include_uapi_asm_sigcontext.h.patch | 24 + .../00000-arch_mips_kernel_cpu-probe.c.patch | 134 + .../00000-arch_mips_kernel_genex.S.patch | 15 + .../00000-arch_mips_kernel_idle.c.patch | 55 + ...arch_mips_kernel_perf_event_mipsxx.c.patch | 137 + .../00000-arch_mips_kernel_proc.c.patch | 12 + .../00000-arch_mips_kernel_process.c.patch | 36 + .../00000-arch_mips_kernel_setup.c.patch | 172 + .../00000-arch_mips_kernel_signal.c.patch | 43 + .../00000-arch_mips_kernel_smp.c.patch | 23 + .../00000-arch_mips_kernel_traps.c.patch | 137 + .../patches/00000-arch_mips_mm_c-r4k.c.patch | 123 + .../00000-arch_mips_mm_dma-default.c.patch | 120 + .../00000-arch_mips_mm_tlb-r4k.c.patch | 31 + .../00000-arch_mips_vdso_Makefile.patch | 129 + .../00000-arch_mips_xburst2_Kconfig.patch | 87 + .../00000-arch_mips_xburst2_Makefile.patch | 9 + .../00000-arch_mips_xburst2_Platform.patch | 10 + ...00-arch_mips_xburst2_common_Makefile.patch | 14 + ...xburst2_common_cpu_ddr_test_Makefile.patch | 15 + ...2_common_cpu_ddr_test_cpu_ccu_test.c.patch | 74 + ...2_common_cpu_ddr_test_cpu_dma_test.c.patch | 266 + ...mon_cpu_ddr_test_cpu_spinlock_test.c.patch | 79 + ...urst2_common_cpu_ddr_test_cpu_tcsm.h.patch | 20 + ...common_cpu_ddr_test_cpu_watch_test.c.patch | 204 + ...cpu_ddr_test_ddr_bandwidth_monitor.c.patch | 475 ++ ...ommon_cpu_ddr_test_ddr_change_freq.c.patch | 527 ++ ...urst2_common_cpu_ddr_test_l2c_test.c.patch | 523 ++ ...mmon_cpu_ddr_test_multithread_test.c.patch | 266 + ...mmon_cpu_ddr_test_multithread_test.h.patch | 13 + ...2_common_cpu_ddr_test_raw_dma_test.c.patch | 270 + ...ps_xburst2_common_get-cpu-features.c.patch | 102 + ...ch_mips_xburst2_common_jz_notifier.c.patch | 87 + ...000-arch_mips_xburst2_common_mxuv3.c.patch | 698 +++ ...arch_mips_xburst2_common_proc-exec.c.patch | 70 + ...0000-arch_mips_xburst2_common_proc.c.patch | 97 + ...0000-arch_mips_xburst2_core_Makefile.patch | 10 + ...arch_mips_xburst2_core_include_ccu.h.patch | 46 + ...ips_xburst2_core_include_core_base.h.patch | 19 + ..._mips_xburst2_core_include_irq_cpu.h.patch | 10 + ...s_xburst2_core_include_jz_notifier.h.patch | 49 + ..._mips_xburst2_core_include_jz_proc.h.patch | 22 + ...arch_mips_xburst2_core_include_mxu.h.patch | 57 + ...ips_xburst2_core_include_mxu_media.h.patch | 1836 ++++++ ...ch_mips_xburst2_core_include_mxuv3.h.patch | 46 + .../00000-arch_mips_xburst2_core_prom.c.patch | 83 + .../00000-arch_mips_xburst2_core_sc.c.patch | 203 + .../00000-arch_mips_xburst2_core_smp.c.patch | 503 ++ ...arch_mips_xburst2_core_xburst_pmon.h.patch | 48 + ...arch_mips_xburst2_soc-t40_Kconfig.DT.patch | 6 + ...0-arch_mips_xburst2_soc-t40_Makefile.patch | 12 + ...000-arch_mips_xburst2_soc-t40_gpio.c.patch | 127 + ...-t40_include_cpu-feature-overrides.h.patch | 70 + ...h_mips_xburst2_soc-t40_include_irq.h.patch | 44 + ...ps_xburst2_soc-t40_include_libdmmu.h.patch | 18 + ...s_xburst2_soc-t40_include_soc_base.h.patch | 101 + ..._xburst2_soc-t40_include_soc_cache.h.patch | 77 + ...ps_xburst2_soc-t40_include_soc_cpm.h.patch | 146 + ...ps_xburst2_soc-t40_include_soc_ddr.h.patch | 104 + ..._xburst2_soc-t40_include_soc_extal.h.patch | 12 + ...s_xburst2_soc-t40_include_soc_gpio.h.patch | 44 + ...ps_xburst2_soc-t40_include_soc_mmc.h.patch | 9 + ...s_xburst2_soc-t40_include_soc_pdma.h.patch | 53 + ...ps_xburst2_soc-t40_include_soc_rtc.h.patch | 100 + ...ps_xburst2_soc-t40_include_soc_sfc.h.patch | 215 + ...t2_soc-t40_include_soc_tcsm_layout.h.patch | 57 + ...h_mips_xburst2_soc-t40_include_war.h.patch | 31 + ...-arch_mips_xburst2_soc-t40_libdmmu.c.patch | 905 +++ ...00000-arch_mips_xburst2_soc-t40_pm.c.patch | 374 ++ ..._xburst2_soc-t40_regs_save_restore.S.patch | 190 + ...xburst2_soc-t40_regs_save_restore.py.patch | 133 + ...00-arch_mips_xburst2_soc-t40_reset.c.patch | 335 ++ ...0-arch_mips_xburst2_soc-t40_serial.c.patch | 95 + ...00-arch_mips_xburst2_soc-t40_setup.c.patch | 113 + ...ips_xburst2_soc-x2000-v12_Kconfig.DT.patch | 6 + ..._mips_xburst2_soc-x2000-v12_Makefile.patch | 11 + ...-v12_include_cpu-feature-overrides.h.patch | 70 + ..._xburst2_soc-x2000-v12_include_irq.h.patch | 43 + ...rst2_soc-x2000-v12_include_libdmmu.h.patch | 18 + ...st2_soc-x2000-v12_include_soc_base.h.patch | 81 + ...t2_soc-x2000-v12_include_soc_cache.h.patch | 32 + ...rst2_soc-x2000-v12_include_soc_cpm.h.patch | 135 + ...rst2_soc-x2000-v12_include_soc_ddr.h.patch | 293 + ...rst2_soc-x2000-v12_include_soc_rtc.h.patch | 100 + ...rst2_soc-x2000-v12_include_soc_sfc.h.patch | 215 + ...-x2000-v12_include_soc_tcsm_layout.h.patch | 57 + ..._xburst2_soc-x2000-v12_include_war.h.patch | 31 + ...mips_xburst2_soc-x2000-v12_libdmmu.c.patch | 903 +++ ...arch_mips_xburst2_soc-x2000-v12_pm.c.patch | 374 ++ ...t2_soc-x2000-v12_regs_save_restore.S.patch | 190 + ...2_soc-x2000-v12_regs_save_restore.py.patch | 133 + ..._mips_xburst2_soc-x2000-v12_serial.c.patch | 95 + ...h_mips_xburst2_soc-x2000-v12_setup.c.patch | 88 + .../00000-arch_mips_xburst_Kconfig.patch | 78 + .../00000-arch_mips_xburst_Makefile.patch | 8 + .../00000-arch_mips_xburst_Platform.patch | 10 + ...000-arch_mips_xburst_common_Makefile.patch | 9 + ..._xburst_common_include_jz_notifier.h.patch | 49 + ...rch_mips_xburst_common_include_mxu.h.patch | 54 + ...ps_xburst_common_include_mxu_media.h.patch | 1836 ++++++ ...ch_mips_xburst_common_initrd-check.c.patch | 53 + ...rch_mips_xburst_common_jz_notifier.c.patch | 87 + ...arch_mips_xburst_common_mxu-xburst.c.patch | 87 + ...00000-arch_mips_xburst_common_prom.c.patch | 67 + ...-arch_mips_xburst_common_sc-xburst.c.patch | 227 + ...0000-arch_mips_xburst_debug_Makefile.patch | 5 + ...-arch_mips_xburst_debug_trace-exit.c.patch | 35 + ...rch_mips_xburst_soc-x1000_Kconfig.DT.patch | 6 + ...-arch_mips_xburst_soc-x1000_Makefile.patch | 9 + ...mips_xburst_soc-x1000_core_sleep.hex.patch | 1030 ++++ ...mips_xburst_soc-x1000_early_printk.c.patch | 78 + ...1000_include_cpu-feature-overrides.h.patch | 64 + ..._mips_xburst_soc-x1000_include_irq.h.patch | 34 + ..._xburst_soc-x1000_include_soc_base.h.patch | 94 + ...xburst_soc-x1000_include_soc_cache.h.patch | 120 + ...s_xburst_soc-x1000_include_soc_cpm.h.patch | 163 + ...s_xburst_soc-x1000_include_soc_ost.h.patch | 45 + ...s_xburst_soc-x1000_include_soc_sfc.h.patch | 156 + ..._soc-x1000_include_soc_tcsm_layout.h.patch | 57 + ...s_xburst_soc-x1000_include_soc_tcu.h.patch | 41 + ..._mips_xburst_soc-x1000_include_war.h.patch | 31 + ...0000-arch_mips_xburst_soc-x1000_pm.c.patch | 221 + ...xburst_soc-x1000_regs_save_restore.S.patch | 176 + ...0-arch_mips_xburst_soc-x1000_setup.c.patch | 84 + ...0-arch_mips_xburst_soc-x1000_socid.c.patch | 114 + ...-arch_mips_xburst_soc-x1800_Makefile.patch | 8 + ...mips_xburst_soc-x1800_core_sleep.hex.patch | 1030 ++++ ...mips_xburst_soc-x1800_early_printk.c.patch | 102 + ...1800_include_cpu-feature-overrides.h.patch | 65 + ..._mips_xburst_soc-x1800_include_irq.h.patch | 34 + ..._xburst_soc-x1800_include_soc_ahbm.h.patch | 37 + ..._xburst_soc-x1800_include_soc_base.h.patch | 91 + ...xburst_soc-x1800_include_soc_cache.h.patch | 99 + ...s_xburst_soc-x1800_include_soc_cpm.h.patch | 86 + ...s_xburst_soc-x1800_include_soc_ddr.h.patch | 104 + ...xburst_soc-x1800_include_soc_extal.h.patch | 12 + ...xburst_soc-x1800_include_soc_gpemc.h.patch | 289 + ...s_xburst_soc-x1800_include_soc_irq.h.patch | 88 + ...s_xburst_soc-x1800_include_soc_ost.h.patch | 45 + ...s_xburst_soc-x1800_include_soc_sfc.h.patch | 156 + ..._soc-x1800_include_soc_tcsm_layout.h.patch | 57 + ...s_xburst_soc-x1800_include_soc_tcu.h.patch | 88 + ..._mips_xburst_soc-x1800_include_war.h.patch | 31 + ...0000-arch_mips_xburst_soc-x1800_pm.c.patch | 221 + ...xburst_soc-x1800_regs_save_restore.S.patch | 176 + ...0-arch_mips_xburst_soc-x1800_setup.c.patch | 97 + .../00000-block_partitions_efi.c.patch | 13 + .../patches/00000-drivers_Kconfig.patch | 11 + .../patches/00000-drivers_Makefile.patch | 22 + .../00000-drivers_block_zram_zram_drv.c.patch | 12 + .../00000-drivers_bluetooth_Kconfig.patch | 21 + .../00000-drivers_bluetooth_Makefile.patch | 13 + .../00000-drivers_bluetooth_hci_ldisc.c.patch | 186 + ...00000-drivers_bluetooth_hci_rtk_h5.c.patch | 884 +++ .../00000-drivers_bluetooth_hci_uart.h.patch | 42 + .../00000-drivers_bluetooth_rtk_coex.c.patch | 2630 +++++++++ .../00000-drivers_bluetooth_rtk_coex.h.patch | 339 ++ .../patches/00000-drivers_char_Kconfig.patch | 12 + ...00000-drivers_char_hw_random_Kconfig.patch | 22 + ...0000-drivers_char_hw_random_Makefile.patch | 8 + ...drivers_char_hw_random_ingenic-rng.c.patch | 256 + .../patches/00000-drivers_char_random.c.patch | 15 + .../patches/00000-drivers_clk_Kconfig.patch | 20 + .../patches/00000-drivers_clk_Makefile.patch | 11 + .../00000-drivers_clk_clk-fixed-rate.c.patch | 12 + ...drivers_clk_clk-fractional-divider.c.patch | 16 + .../00000-drivers_clk_clk-gate.c.patch | 19 + .../patches/00000-drivers_clk_clk-mux.c.patch | 20 + .../patches/00000-drivers_clk_clk.c.patch | 20 + .../00000-drivers_clk_ingenic_Kconfig.patch | 31 + .../00000-drivers_clk_ingenic_Makefile.patch | 14 + .../00000-drivers_clk_ingenic_cgu.c.patch | 716 +++ .../00000-drivers_clk_ingenic_cgu.h.patch | 227 + .../00000-drivers_clk_ingenic_clk-bus.c.patch | 244 + .../00000-drivers_clk_ingenic_clk-bus.h.patch | 28 + .../00000-drivers_clk_ingenic_clk-div.c.patch | 265 + .../00000-drivers_clk_ingenic_clk-div.h.patch | 22 + .../00000-drivers_clk_ingenic_clk-pll.c.patch | 184 + .../00000-drivers_clk_ingenic_clk-pll.h.patch | 59 + .../00000-drivers_clk_ingenic_clk-t40.c.patch | 369 ++ ...-drivers_clk_ingenic_clk-x2000-v12.c.patch | 362 ++ .../00000-drivers_clk_ingenic_clk.c.patch | 516 ++ .../00000-drivers_clk_ingenic_clk.h.patch | 585 ++ ...000-drivers_clk_ingenic_jz4740-cgu.c.patch | 307 + ...000-drivers_clk_ingenic_jz4780-cgu.c.patch | 737 +++ ...000-drivers_clk_ingenic_power-gate.c.patch | 201 + ...000-drivers_clk_ingenic_power-gate.h.patch | 18 + .../00000-drivers_clocksource_Kconfig.patch | 19 + .../00000-drivers_clocksource_Makefile.patch | 9 + ...ivers_clocksource_ingenic_core_ost.c.patch | 566 ++ ...drivers_clocksource_ingenic_sysost.c.patch | 309 + .../00000-drivers_cpufreq_Kconfig.patch | 34 + .../00000-drivers_cpufreq_Makefile.patch | 8 + ...00-drivers_cpufreq_ingenic-cpufreq.c.patch | 346 ++ .../00000-drivers_crypto_Kconfig.patch | 39 + .../00000-drivers_crypto_Makefile.patch | 11 + .../00000-drivers_crypto_ingenic-aes.c.patch | 895 +++ .../00000-drivers_crypto_ingenic-aes.h.patch | 116 + .../00000-drivers_crypto_ingenic-hash.c.patch | 1088 ++++ .../00000-drivers_crypto_ingenic-hash.h.patch | 122 + .../patches/00000-drivers_dma_Kconfig.patch | 29 + .../patches/00000-drivers_dma_Makefile.patch | 8 + .../00000-drivers_dma_ingenic_Makefile.patch | 5 + ...00-drivers_dma_ingenic_ingenic_dma.c.patch | 1145 ++++ ...00-drivers_dma_ingenic_ingenic_dma.h.patch | 217 + .../00000-drivers_i2c_busses_Kconfig.patch | 36 + .../00000-drivers_i2c_busses_Makefile.patch | 11 + ...000-drivers_i2c_busses_i2c-ingenic.c.patch | 1098 ++++ .../00000-drivers_irqchip_Kconfig.patch | 25 + .../00000-drivers_irqchip_Makefile.patch | 11 + ...0-drivers_irqchip_irq-ingenic-chip.c.patch | 532 ++ ...00-drivers_irqchip_irq-ingenic-cpu.c.patch | 132 + .../00000-drivers_irqchip_irq-ingenic.c.patch | 353 ++ .../patches/00000-drivers_lzma_Kconfig.patch | 11 + .../patches/00000-drivers_lzma_Makefile.patch | 7 + .../patches/00000-drivers_lzma_lzma.c.patch | 142 + .../00000-drivers_lzma_lzma_debug.c.patch | 229 + ...drivers_media_i2c_soc_camera_Kconfig.patch | 34 + ...rivers_media_i2c_soc_camera_Makefile.patch | 20 + ...rivers_media_i2c_soc_camera_gc2155.c.patch | 1781 ++++++ ..._media_i2c_soc_camera_mt9v022_test.c.patch | 1457 +++++ ...rivers_media_i2c_soc_camera_ov5640.c.patch | 1786 ++++++ ...rivers_media_i2c_soc_camera_ov9281.c.patch | 1118 ++++ ...00000-drivers_media_platform_Kconfig.patch | 34 + ...0000-drivers_media_platform_Makefile.patch | 22 + ...media_platform_ingenic-jpeg_Makefile.patch | 6 + ...form_ingenic-jpeg_ingenic_jpeg_enc.h.patch | 190 + ...ia_platform_ingenic-jpeg_jpeg-core.c.patch | 1153 ++++ ...ia_platform_ingenic-jpeg_jpeg-core.h.patch | 178 + ...edia_platform_ingenic-jpeg_jpeg-hw.h.patch | 189 + ...ia_platform_ingenic-jpeg_jpeg-regs.h.patch | 293 + ...dia_platform_ingenic-rotate_Makefile.patch | 5 + ..._platform_ingenic-rotate_rotate-hw.c.patch | 295 + ...latform_ingenic-rotate_rotate-regs.h.patch | 207 + ...dia_platform_ingenic-rotate_rotate.c.patch | 832 +++ ...dia_platform_ingenic-rotate_rotate.h.patch | 153 + ...dia_platform_ingenic-vcodec_Makefile.patch | 6 + ...atform_ingenic-vcodec_felix_Makefile.patch | 16 + ...enic-vcodec_felix_api_jzm_h264_dec.c.patch | 1127 ++++ ...enic-vcodec_felix_api_jzm_h264_dec.h.patch | 126 + ...m_ingenic-vcodec_felix_api_jzm_vpu.h.patch | 2678 +++++++++ ...orm_ingenic-vcodec_felix_felix_drv.c.patch | 660 +++ ...orm_ingenic-vcodec_felix_felix_drv.h.patch | 157 + ...orm_ingenic-vcodec_felix_felix_ops.c.patch | 1076 ++++ ...orm_ingenic-vcodec_felix_felix_ops.h.patch | 18 + ...atform_ingenic-vcodec_helix_Makefile.patch | 22 + ...platform_ingenic-vcodec_helix_README.patch | 8 + ...orm_ingenic-vcodec_helix_api_helix.h.patch | 3463 ++++++++++++ ...ic-vcodec_helix_api_helix_jpeg_dec.c.patch | 55 + ...ic-vcodec_helix_api_helix_jpeg_dec.h.patch | 76 + ...ic-vcodec_helix_api_helix_jpeg_enc.c.patch | 245 + ...ic-vcodec_helix_api_helix_jpeg_enc.h.patch | 85 + ...ic-vcodec_helix_api_helix_x264_enc.c.patch | 1243 +++++ ...ic-vcodec_helix_api_helix_x264_enc.h.patch | 402 ++ ...nic-vcodec_helix_default_sliceinfo.c.patch | 366 ++ ...latform_ingenic-vcodec_helix_h264e.c.patch | 918 +++ ...latform_ingenic-vcodec_helix_h264e.h.patch | 134 + ...nic-vcodec_helix_h264enc_bitstream.h.patch | 246 + ...ingenic-vcodec_helix_h264enc_cabac.c.patch | 1366 +++++ ...ingenic-vcodec_helix_h264enc_cabac.h.patch | 32 + ...ngenic-vcodec_helix_h264enc_common.c.patch | 15 + ...ngenic-vcodec_helix_h264enc_common.h.patch | 54 + ...m_ingenic-vcodec_helix_h264enc_nal.h.patch | 63 + ...ingenic-vcodec_helix_h264enc_osdep.h.patch | 39 + ...m_ingenic-vcodec_helix_h264enc_set.c.patch | 159 + ...m_ingenic-vcodec_helix_h264enc_set.h.patch | 180 + ...ingenic-vcodec_helix_h264enc_slice.c.patch | 173 + ...ingenic-vcodec_helix_h264enc_slice.h.patch | 103 + ...orm_ingenic-vcodec_helix_helix_buf.h.patch | 49 + ...orm_ingenic-vcodec_helix_helix_drv.c.patch | 529 ++ ...orm_ingenic-vcodec_helix_helix_drv.h.patch | 170 + ...orm_ingenic-vcodec_helix_helix_ops.c.patch | 1302 +++++ ...orm_ingenic-vcodec_helix_helix_ops.h.patch | 21 + ...platform_ingenic-vcodec_helix_jpgd.c.patch | 580 ++ ...platform_ingenic-vcodec_helix_jpgd.h.patch | 58 + ...platform_ingenic-vcodec_helix_jpge.c.patch | 336 ++ ...platform_ingenic-vcodec_helix_jpge.h.patch | 50 + ...orm_ingenic-vcodec_helix_jpge_head.h.patch | 76 + ...tform_ingenic-vcodec_helix_jpge_ht.h.patch | 94 + ...tform_ingenic-vcodec_helix_jpge_qt.h.patch | 62 + ...rs_media_platform_soc_camera_Kconfig.patch | 8 + ...s_media_platform_soc_camera_Makefile.patch | 8 + ..._platform_soc_camera_ingenic_Kconfig.patch | 16 + ...platform_soc_camera_ingenic_Makefile.patch | 6 + ...orm_soc_camera_ingenic_x1000_Kconfig.patch | 10 + ...rm_soc_camera_ingenic_x1000_Makefile.patch | 6 + ...amera_ingenic_x1000_ingenic_camera.c.patch | 1115 ++++ ...amera_ingenic_x1000_ingenic_camera.h.patch | 206 + ...orm_soc_camera_ingenic_x2000_Kconfig.patch | 29 + ...rm_soc_camera_ingenic_x2000_Makefile.patch | 6 + ...amera_ingenic_x2000_ingenic_camera.c.patch | 2005 +++++++ ...amera_ingenic_x2000_ingenic_camera.h.patch | 455 ++ ..._soc_camera_ingenic_x2000_mipi_csi.c.patch | 144 + ..._soc_camera_ingenic_x2000_mipi_csi.h.patch | 85 + ...0000-drivers_media_v4l2-core_Kconfig.patch | 24 + ...000-drivers_media_v4l2-core_Makefile.patch | 11 + ...-core_videobuf2-dma-contig-ingenic.c.patch | 900 +++ .../patches/00000-drivers_mfd_Kconfig.patch | 56 + .../patches/00000-drivers_mfd_Makefile.patch | 21 + .../00000-drivers_mfd_ingenic-tcu.c.patch | 931 ++++ .../00000-drivers_mfd_ingenic_adc_aux.c.patch | 351 ++ .../00000-drivers_mfd_ingenic_adc_v13.c.patch | 585 ++ .../00000-drivers_mfd_rn5t567-irq.c.patch | 149 + .../patches/00000-drivers_mfd_rn5t567.c.patch | 216 + .../patches/00000-drivers_misc_Kconfig.patch | 41 + .../patches/00000-drivers_misc_Makefile.patch | 18 + ...00-drivers_misc_bt_power_bluesleep.c.patch | 294 + .../00000-drivers_misc_ingenic_rsa.c.patch | 487 ++ .../patches/00000-drivers_misc_logger.c.patch | 855 +++ .../patches/00000-drivers_misc_logger.h.patch | 93 + .../patches/00000-drivers_misc_rmem.c.patch | 169 + .../00000-drivers_mmc_core_core.c.patch | 30 + ...000-drivers_mmc_core_pwrseq_simple.c.patch | 42 + .../00000-drivers_mmc_host_Kconfig.patch | 45 + .../00000-drivers_mmc_host_Makefile.patch | 26 + ...00000-drivers_mmc_host_ingenic_mmc.c.patch | 1779 ++++++ ...00000-drivers_mmc_host_ingenic_mmc.h.patch | 157 + ...0-drivers_mmc_host_ingenic_mmc_reg.h.patch | 236 + ...0000-drivers_mmc_host_ingenic_sdio.c.patch | 216 + ...000-drivers_mmc_host_sdhci-ingenic.c.patch | 804 +++ ...000-drivers_mmc_host_sdhci-ingenic.h.patch | 101 + .../00000-drivers_mmc_host_sdhci.c.patch | 16 + .../00000-drivers_mtd_devices_Kconfig.patch | 13 + .../00000-drivers_mtd_devices_Makefile.patch | 11 + ...s_mtd_devices_ingenic_sfc_v1_Kconfig.patch | 48 + ..._mtd_devices_ingenic_sfc_v1_Makefile.patch | 11 + ..._ingenic_sfc_v1_ingenic_sfc_common.c.patch | 750 +++ ..._ingenic_sfc_v1_ingenic_sfc_common.h.patch | 32 + ...es_ingenic_sfc_v1_ingenic_sfc_nand.c.patch | 1037 ++++ ...ces_ingenic_sfc_v1_ingenic_sfc_nor.c.patch | 980 ++++ ...ces_ingenic_sfc_v1_ingenic_sfc_ops.c.patch | 255 + ..._ingenic_sfc_v1_nand_device_Makefile.patch | 6 + ...ngenic_sfc_v1_nand_device_ato_nand.c.patch | 124 + ...ingenic_sfc_v1_nand_device_gd_nand.c.patch | 352 ++ ...genic_sfc_v1_nand_device_mxic_nand.c.patch | 389 ++ ...nic_sfc_v1_nand_device_nand_common.c.patch | 359 ++ ...nic_sfc_v1_nand_device_nand_common.h.patch | 44 + ...ic_sfc_v1_nand_device_winbond_nand.c.patch | 420 ++ ...ngenic_sfc_v1_nand_device_xtx_nand.c.patch | 145 + ...ers_mtd_devices_ingenic_sfc_v1_sfc.h.patch | 62 + ...d_devices_ingenic_sfc_v1_sfc_flash.h.patch | 33 + ...mtd_devices_ingenic_sfc_v1_spinand.h.patch | 116 + ...devices_ingenic_sfc_v1_spinand_cmd.h.patch | 33 + ..._mtd_devices_ingenic_sfc_v1_spinor.h.patch | 121 + ..._devices_ingenic_sfc_v1_spinor_cmd.h.patch | 84 + ...s_mtd_devices_ingenic_sfc_v2_Kconfig.patch | 48 + ..._mtd_devices_ingenic_sfc_v2_Makefile.patch | 10 + ..._ingenic_sfc_v2_ingenic_sfc_common.c.patch | 795 +++ ..._ingenic_sfc_v2_ingenic_sfc_common.h.patch | 33 + ...es_ingenic_sfc_v2_ingenic_sfc_nand.c.patch | 1136 ++++ ...ces_ingenic_sfc_v2_ingenic_sfc_nor.c.patch | 1057 ++++ ...ces_ingenic_sfc_v2_ingenic_sfc_ops.c.patch | 233 + ..._ingenic_sfc_v2_nand_device_Makefile.patch | 6 + ...ngenic_sfc_v2_nand_device_ato_nand.c.patch | 109 + ..._sfc_v2_nand_device_dosilicon_nand.c.patch | 171 + ...sfc_v2_nand_device_esmt_mid2c_nand.c.patch | 120 + ...ic_sfc_v2_nand_device_foresee_nand.c.patch | 159 + ...ingenic_sfc_v2_nand_device_gd_nand.c.patch | 415 ++ ...nic_sfc_v2_nand_device_micron_nand.c.patch | 120 + ...genic_sfc_v2_nand_device_mxic_nand.c.patch | 214 + ...nic_sfc_v2_nand_device_nand_common.c.patch | 70 + ...nic_sfc_v2_nand_device_nand_common.h.patch | 78 + ...ic_sfc_v2_nand_device_winbond_nand.c.patch | 115 + ..._sfc_v2_nand_device_xtx_mid0b_nand.c.patch | 200 + ...ngenic_sfc_v2_nand_device_xtx_nand.c.patch | 172 + ...enic_sfc_v2_nand_device_zetta_nand.c.patch | 151 + ...ers_mtd_devices_ingenic_sfc_v2_sfc.h.patch | 114 + ...d_devices_ingenic_sfc_v2_sfc_flash.h.patch | 33 + ...mtd_devices_ingenic_sfc_v2_spinand.h.patch | 185 + ...devices_ingenic_sfc_v2_spinand_cmd.h.patch | 34 + ..._mtd_devices_ingenic_sfc_v2_spinor.h.patch | 1495 +++++ ..._devices_ingenic_sfc_v2_spinor_cmd.h.patch | 89 + .../patches/00000-drivers_net_Kconfig.patch | 35 + .../00000-drivers_net_ethernet_Kconfig.patch | 11 + .../00000-drivers_net_ethernet_Makefile.patch | 8 + ...drivers_net_ethernet_ingenic_Kconfig.patch | 32 + ...rivers_net_ethernet_ingenic_Makefile.patch | 35 + ...s_net_ethernet_ingenic_ingenic_mac.c.patch | 2447 ++++++++ ...s_net_ethernet_ingenic_ingenic_mac.h.patch | 136 + ...-drivers_net_ethernet_ingenic_readme.patch | 30 + ...net_ethernet_ingenic_synopGMAC_Dev.c.patch | 3842 +++++++++++++ ...net_ethernet_ingenic_synopGMAC_Dev.h.patch | 2019 +++++++ ...et_ethernet_ingenic_synopGMAC_plat.c.patch | 98 + ...et_ethernet_ingenic_synopGMAC_plat.h.patch | 211 + .../patches/00000-drivers_net_mii.c.patch | 78 + .../00000-drivers_pinctrl_Kconfig.patch | 16 + .../00000-drivers_pinctrl_Makefile.patch | 12 + ...00-drivers_pinctrl_pinctrl-ingenic.c.patch | 1794 ++++++ ...00-drivers_pinctrl_pinctrl-ingenic.h.patch | 281 + .../patches/00000-drivers_pwm_Kconfig.patch | 31 + .../patches/00000-drivers_pwm_Makefile.patch | 12 + .../patches/00000-drivers_pwm_core.c.patch | 11 + .../00000-drivers_pwm_pwm-ingenic-v2.c.patch | 925 +++ .../00000-drivers_pwm_pwm-ingenic.c.patch | 491 ++ .../00000-drivers_regulator_Kconfig.patch | 20 + .../00000-drivers_regulator_Makefile.patch | 11 + ...rivers_regulator_rn5t567-regulator.c.patch | 232 + .../patches/00000-drivers_rtc_Kconfig.patch | 35 + .../patches/00000-drivers_rtc_Makefile.patch | 16 + .../00000-drivers_rtc_rtc-bm8563.c.patch | 190 + .../00000-drivers_rtc_rtc-ingenic.c.patch | 599 ++ .../00000-drivers_rtc_rtc-ingenic.h.patch | 135 + .../patches/00000-drivers_spi_Kconfig.patch | 21 + .../patches/00000-drivers_spi_Makefile.patch | 8 + .../00000-drivers_spi_ingenic_spi.c.patch | 1490 +++++ .../00000-drivers_spi_ingenic_spi.h.patch | 682 +++ .../00000-drivers_tty_serial_Kconfig.patch | 80 + .../00000-drivers_tty_serial_Makefile.patch | 11 + ...00-drivers_tty_serial_ingenic_uart.c.patch | 1222 ++++ ...00-drivers_tty_serial_ingenic_uart.h.patch | 121 + ...000-drivers_tty_serial_serial_core.c.patch | 55 + .../00000-drivers_usb_core_hub.c.patch | 12 + .../00000-drivers_usb_dwc2_Kconfig.patch | 26 + .../00000-drivers_usb_dwc2_core.c.patch | 213 + .../00000-drivers_usb_dwc2_core.h.patch | 37 + .../00000-drivers_usb_dwc2_gadget.c.patch | 118 + .../00000-drivers_usb_dwc2_hcd.c.patch | 132 + .../00000-drivers_usb_dwc2_hcd_ddma.c.patch | 46 + .../00000-drivers_usb_dwc2_hcd_intr.c.patch | 15 + .../00000-drivers_usb_dwc2_hcd_queue.c.patch | 20 + .../patches/00000-drivers_usb_dwc2_hw.h.patch | 12 + .../00000-drivers_usb_dwc2_platform.c.patch | 260 + ...s_usb_gadget_function_uvc_configfs.c.patch | 31 + .../00000-drivers_usb_phy_Kconfig.patch | 37 + .../00000-drivers_usb_phy_Makefile.patch | 10 + ...0-drivers_usb_phy_phy-ingenic-inno.c.patch | 552 ++ ...00-drivers_usb_phy_phy-ingenic-usb.c.patch | 434 ++ ...-drivers_usb_phy_phy-ingenic-x1800.c.patch | 511 ++ .../patches/00000-drivers_video_Kconfig.patch | 13 + .../00000-drivers_video_Makefile.patch | 24 + .../00000-drivers_video_fbdev_Kconfig.patch | 110 + .../00000-drivers_video_fbdev_Makefile.patch | 11 + ...-drivers_video_fbdev_ingenic_Kconfig.patch | 84 + ...drivers_video_fbdev_ingenic_Makefile.patch | 7 + ...s_video_fbdev_ingenic_fb_v10_Kconfig.patch | 31 + ..._video_fbdev_ingenic_fb_v10_Makefile.patch | 6 + ...bdev_ingenic_fb_v10_displays_Kconfig.patch | 17 + ...dev_ingenic_fb_v10_displays_Makefile.patch | 5 + ...displays_panel_truly_tft240240_2_e.c.patch | 411 ++ ...deo_fbdev_ingenic_fb_v10_ingenicfb.c.patch | 2671 +++++++++ ...deo_fbdev_ingenic_fb_v10_ingenicfb.h.patch | 383 ++ ...ideo_fbdev_ingenic_fb_v10_lcd_regs.h.patch | 645 +++ ...s_video_fbdev_ingenic_fb_v11_Kconfig.patch | 12 + ..._video_fbdev_ingenic_fb_v11_Makefile.patch | 6 + ...bdev_ingenic_fb_v11_displays_Kconfig.patch | 29 + ...dev_ingenic_fb_v11_displays_Makefile.patch | 7 + ...b_v11_displays_panel-kd035hvfbd037.c.patch | 553 ++ ...b_v11_displays_panel-kd035hvfmd057.c.patch | 530 ++ ...video_fbdev_ingenic_fb_v11_dpu_reg.h.patch | 819 +++ ...deo_fbdev_ingenic_fb_v11_ingenicfb.c.patch | 2951 ++++++++++ ...deo_fbdev_ingenic_fb_v11_ingenicfb.h.patch | 298 + ...bdev_ingenic_fb_v11_uapi_ingenicfb.h.patch | 124 + ...s_video_fbdev_ingenic_fb_v12_Kconfig.patch | 48 + ..._video_fbdev_ingenic_fb_v12_Makefile.patch | 7 + ...bdev_ingenic_fb_v12_displays_Kconfig.patch | 114 + ...dev_ingenic_fb_v12_displays_Makefile.patch | 21 + ...dev_ingenic_fb_v12_displays_lt9211.c.patch | 571 ++ ...dev_ingenic_fb_v12_displays_lt9211.h.patch | 66 + ...genic_fb_v12_displays_panel-bm8766.c.patch | 315 ++ ...enic_fb_v12_displays_panel-ek79007.c.patch | 528 ++ ...enic_fb_v12_displays_panel-jd9161z.c.patch | 521 ++ ...b_v12_displays_panel-kd035hvfbd037.c.patch | 547 ++ ...b_v12_displays_panel-kd050hdfia019.c.patch | 478 ++ ...genic_fb_v12_displays_panel-ma0060.c.patch | 849 +++ ...genic_fb_v12_displays_panel-mtf070.c.patch | 624 +++ ...ngenic_fb_v12_displays_panel-px070.c.patch | 323 ++ ...enic_fb_v12_displays_panel-st7701s.c.patch | 547 ++ ...genic_fb_v12_displays_panel-st7703.c.patch | 566 ++ ...v12_displays_panel-st7789v_240_320.c.patch | 524 ++ ...fb_v12_displays_panel-tl040hds01ct.c.patch | 377 ++ ...fb_v12_displays_panel-tl040wvs03ct.c.patch | 740 +++ ...genic_fb_v12_displays_panel-y88249.c.patch | 301 + ...nic_fb_v12_displays_panel-ylym286a.c.patch | 464 ++ ...c_fb_v12_displays_panel-yts500xlai.c.patch | 478 ++ ...video_fbdev_ingenic_fb_v12_dpu_reg.h.patch | 890 +++ ...deo_fbdev_ingenic_fb_v12_ingenicfb.c.patch | 4387 +++++++++++++++ ...deo_fbdev_ingenic_fb_v12_ingenicfb.h.patch | 675 +++ ...video_fbdev_ingenic_fb_v12_jz_dsim.h.patch | 297 + ..._ingenic_fb_v12_jz_mipi_dsi_Makefile.patch | 5 + ...nic_fb_v12_jz_mipi_dsi_jz_mipi_dsi.c.patch | 1138 ++++ ...2_jz_mipi_dsi_jz_mipi_dsi_lowlevel.c.patch | 615 ++ ...2_jz_mipi_dsi_jz_mipi_dsi_lowlevel.h.patch | 33 + ...b_v12_jz_mipi_dsi_jz_mipi_dsi_regs.h.patch | 83 + ...b_v12_jz_mipi_dsi_jz_mipi_dsih_hal.c.patch | 1287 +++++ ...b_v12_jz_mipi_dsi_jz_mipi_dsih_hal.h.patch | 150 + ...rivers_video_ingenic_bscaler_Kconfig.patch | 7 + ...ivers_video_ingenic_bscaler_Makefile.patch | 5 + ...eo_ingenic_bscaler_ingenic_bscaler.c.patch | 401 ++ ...00-drivers_video_ingenic_i2d_Kconfig.patch | 17 + ...0-drivers_video_ingenic_i2d_Makefile.patch | 5 + ...vers_video_ingenic_i2d_ingenic_i2d.c.patch | 747 +++ ...vers_video_ingenic_i2d_ingenic_i2d.h.patch | 293 + ...00-drivers_video_ingenic_ipu_Kconfig.patch | 16 + ...0-drivers_video_ingenic_ipu_Makefile.patch | 5 + ..._video_ingenic_ipu_ingenic_drawbox.c.patch | 601 ++ ..._video_ingenic_ipu_ingenic_drawbox.h.patch | 164 + ..._video_ingenic_ipu_ingenic_ipu_v13.c.patch | 1246 +++++ ..._video_ingenic_ipu_ingenic_ipu_v13.h.patch | 212 + ...video_ingenic_ipu_ingenic_regs_v13.h.patch | 354 ++ .../00000-drivers_watchdog_Kconfig.patch | 17 + .../00000-drivers_watchdog_Makefile.patch | 11 + ...00000-drivers_watchdog_ingenic_wdt.c.patch | 584 ++ .../t40/kernel/patches/00000-fs_Kconfig.patch | 11 + .../kernel/patches/00000-fs_Makefile.patch | 8 + .../kernel/patches/00000-fs_seq_file.c.patch | 40 + .../patches/00000-fs_squashfs_Kconfig.patch | 56 + .../patches/00000-fs_squashfs_Makefile.patch | 9 + .../00000-fs_squashfs_decompressor.c.patch | 33 + .../00000-fs_squashfs_decompressor.h.patch | 12 + ...000-fs_squashfs_decompressor_multi.c.patch | 15 + ...00-fs_squashfs_decompressor_single.c.patch | 15 + .../00000-fs_squashfs_hardware_lzma.c.patch | 32 + .../patches/00000-fs_squashfs_jz-lzma.h.patch | 76 + .../00000-fs_squashfs_lzma_wrapper.c.patch | 159 + .../00000-fs_squashfs_squashfs.h.patch | 9 + .../patches/00000-fs_squashfs_super.c.patch | 14 + .../patches/00000-fs_yaffs2_Kconfig.patch | 175 + .../patches/00000-fs_yaffs2_Makefile.patch | 23 + .../00000-fs_yaffs2_yaffs_allocator.c.patch | 360 ++ .../00000-fs_yaffs2_yaffs_allocator.h.patch | 33 + .../00000-fs_yaffs2_yaffs_attribs.c.patch | 139 + .../00000-fs_yaffs2_yaffs_attribs.h.patch | 31 + .../00000-fs_yaffs2_yaffs_bitmap.c.patch | 102 + .../00000-fs_yaffs2_yaffs_bitmap.h.patch | 36 + .../00000-fs_yaffs2_yaffs_cache.c.patch | 329 ++ .../00000-fs_yaffs2_yaffs_cache.h.patch | 60 + .../00000-fs_yaffs2_yaffs_checkptrw.c.patch | 484 ++ .../00000-fs_yaffs2_yaffs_checkptrw.h.patch | 36 + .../patches/00000-fs_yaffs2_yaffs_ecc.c.patch | 284 + .../patches/00000-fs_yaffs2_yaffs_ecc.h.patch | 47 + .../00000-fs_yaffs2_yaffs_endian.c.patch | 109 + .../00000-fs_yaffs2_yaffs_endian.h.patch | 58 + ...00000-fs_yaffs2_yaffs_getblockinfo.h.patch | 39 + .../00000-fs_yaffs2_yaffs_guts.c.patch | 4954 +++++++++++++++++ .../00000-fs_yaffs2_yaffs_guts.h.patch | 1085 ++++ .../00000-fs_yaffs2_yaffs_linux.h.patch | 51 + .../00000-fs_yaffs2_yaffs_mtdif.c.patch | 319 ++ .../00000-fs_yaffs2_yaffs_mtdif.h.patch | 28 + .../00000-fs_yaffs2_yaffs_nameval.c.patch | 233 + .../00000-fs_yaffs2_yaffs_nameval.h.patch | 36 + .../00000-fs_yaffs2_yaffs_nand.c.patch | 125 + .../00000-fs_yaffs2_yaffs_nand.h.patch | 42 + .../00000-fs_yaffs2_yaffs_packedtags1.c.patch | 58 + .../00000-fs_yaffs2_yaffs_packedtags1.h.patch | 42 + .../00000-fs_yaffs2_yaffs_packedtags2.c.patch | 215 + .../00000-fs_yaffs2_yaffs_packedtags2.h.patch | 54 + .../00000-fs_yaffs2_yaffs_summary.c.patch | 313 ++ .../00000-fs_yaffs2_yaffs_summary.h.patch | 40 + .../00000-fs_yaffs2_yaffs_tagscompat.c.patch | 403 ++ .../00000-fs_yaffs2_yaffs_tagscompat.h.patch | 47 + ...00000-fs_yaffs2_yaffs_tagsmarshall.c.patch | 209 + ...00000-fs_yaffs2_yaffs_tagsmarshall.h.patch | 25 + .../00000-fs_yaffs2_yaffs_trace.h.patch | 60 + .../00000-fs_yaffs2_yaffs_verify.c.patch | 545 ++ .../00000-fs_yaffs2_yaffs_verify.h.patch | 46 + .../patches/00000-fs_yaffs2_yaffs_vfs.c.patch | 3817 +++++++++++++ .../00000-fs_yaffs2_yaffs_yaffs1.c.patch | 431 ++ .../00000-fs_yaffs2_yaffs_yaffs1.h.patch | 25 + .../00000-fs_yaffs2_yaffs_yaffs2.c.patch | 1717 ++++++ .../00000-fs_yaffs2_yaffs_yaffs2.h.patch | 42 + .../patches/00000-fs_yaffs2_yportenv.h.patch | 96 + ...dt-bindings_clock_ingenic-t40-fpga.h.patch | 134 + ...lude_dt-bindings_clock_ingenic-t40.h.patch | 140 + ...lude_dt-bindings_clock_ingenic-tcu.h.patch | 29 + ...de_dt-bindings_clock_ingenic-x1000.h.patch | 96 + ...de_dt-bindings_clock_ingenic-x1800.h.patch | 95 + ...dings_clock_ingenic-x2000-v12-fpga.h.patch | 134 + ...t-bindings_clock_ingenic-x2000-v12.h.patch | 203 + ...de_dt-bindings_clock_ingenic-x2000.h.patch | 115 + ...clude_dt-bindings_dma_ingenic-pdma.h.patch | 51 + ...ings_interrupt-controller_mips-irq.h.patch | 20 + ...dings_interrupt-controller_t40-irq.h.patch | 78 + ...interrupt-controller_x2000-v12-irq.h.patch | 76 + ...clude_dt-bindings_net_ingenic_gmac.h.patch | 13 + ...t-bindings_pinctrl_ingenic-pinctrl.h.patch | 78 + ...ude_dt-bindings_sound_ingenic-baic.h.patch | 38 + .../00000-include_linux_clk-provider.h.patch | 11 + ...nclude_linux_decompress_bunzip2_mm.h.patch | 17 + ...nclude_linux_decompress_inflate_mm.h.patch | 17 + .../00000-include_linux_decompress_mm.h.patch | 21 + ...include_linux_decompress_unlzma_mm.h.patch | 24 + ...-include_linux_decompress_unlzo_mm.h.patch | 17 + .../00000-include_linux_dmaengine.h.patch | 19 + .../00000-include_linux_ingenic_adc.h.patch | 326 ++ .../00000-include_linux_interrupt.h.patch | 11 + ...0000-include_linux_mfd_ingenic-tcu.h.patch | 206 + .../00000-include_linux_mfd_jz_tcu.h.patch | 157 + .../00000-include_linux_mfd_rn5t567.h.patch | 139 + .../00000-include_linux_seq_file.h.patch | 15 + .../00000-include_linux_wlan_plat.h.patch | 31 + .../00000-include_soc_xburst_reboot.h.patch | 33 + .../patches/00000-include_sound_soc.h.patch | 12 + .../kernel/patches/00000-init_Kconfig.patch | 32 + .../kernel/patches/00000-init_main.c.patch | 20 + .../kernel/patches/00000-lib_Kconfig.patch | 22 + .../00000-lib_decompress_bunzip2.c.patch | 11 + .../00000-lib_decompress_inflate.c.patch | 11 + .../00000-lib_decompress_unlz4.c.patch | 14 + .../00000-lib_decompress_unlzma.c.patch | 31 + .../00000-lib_decompress_unlzo.c.patch | 11 + .../patches/00000-lib_decompress_unxz.c.patch | 13 + .../00000-scripts_setlocalversion.patch | 19 + .../00000-sound_core_pcm_native.c.patch | 71 + .../patches/00000-sound_soc_Kconfig.patch | 11 + .../patches/00000-sound_soc_Makefile.patch | 8 + .../00000-sound_soc_ingenic_Kconfig.patch | 132 + .../00000-sound_soc_ingenic_Makefile.patch | 12 + .../00000-sound_soc_ingenic_README.patch | 35 + ...000-sound_soc_ingenic_as-v1_Makefile.patch | 12 + ...0-sound_soc_ingenic_as-v1_asoc-aic.c.patch | 277 + ...0-sound_soc_ingenic_as-v1_asoc-aic.h.patch | 638 +++ ...0-sound_soc_ingenic_as-v1_asoc-dma.c.patch | 593 ++ ...0-sound_soc_ingenic_as-v1_asoc-dma.h.patch | 35 + ...-sound_soc_ingenic_as-v1_asoc-dmic.c.patch | 528 ++ ...-sound_soc_ingenic_as-v1_asoc-dmic.h.patch | 304 + ...0-sound_soc_ingenic_as-v1_asoc-i2s.c.patch | 485 ++ ...0-sound_soc_ingenic_as-v1_asoc-pcm.c.patch | 423 ++ ...0-sound_soc_ingenic_as-v1_asoc-pcm.h.patch | 256 + ...sound_soc_ingenic_as-v1_asoc-spdif.c.patch | 494 ++ ...000-sound_soc_ingenic_as-v2_Makefile.patch | 14 + ...00-sound_soc_ingenic_as-v2_as-baic.c.patch | 703 +++ ...00-sound_soc_ingenic_as-v2_as-baic.h.patch | 167 + ...000-sound_soc_ingenic_as-v2_as-dma.c.patch | 729 +++ ...000-sound_soc_ingenic_as-v2_as-dma.h.patch | 194 + ...00-sound_soc_ingenic_as-v2_as-dmic.c.patch | 309 + ...00-sound_soc_ingenic_as-v2_as-dmic.h.patch | 68 + ...000-sound_soc_ingenic_as-v2_as-dsp.c.patch | 482 ++ ...000-sound_soc_ingenic_as-v2_as-dsp.h.patch | 152 + ...-sound_soc_ingenic_as-v2_as-fmtcov.c.patch | 176 + ...-sound_soc_ingenic_as-v2_as-fmtcov.h.patch | 61 + ...0-sound_soc_ingenic_as-v2_as-mixer.c.patch | 175 + ...0-sound_soc_ingenic_as-v2_as-mixer.h.patch | 54 + ...0-sound_soc_ingenic_as-v2_as-spdif.c.patch | 457 ++ ...0-sound_soc_ingenic_as-v2_as-spdif.h.patch | 103 + ...-sound_soc_ingenic_as-v2_as-vir-fe.c.patch | 158 + ...00-sound_soc_ingenic_boards_Makefile.patch | 9 + ...0000-sound_soc_ingenic_boards_seal.c.patch | 517 ++ ...und_soc_ingenic_boards_x1000-board.c.patch | 228 + ...000-sound_soc_ingenic_ecodec_Kconfig.patch | 16 + ...00-sound_soc_ingenic_ecodec_Makefile.patch | 9 + ...00-sound_soc_ingenic_ecodec_ak4458.c.patch | 689 +++ ...00-sound_soc_ingenic_ecodec_ak4458.h.patch | 92 + ...00-sound_soc_ingenic_ecodec_ak5558.c.patch | 429 ++ ...00-sound_soc_ingenic_ecodec_ak5558.h.patch | 56 + ...00-sound_soc_ingenic_ecodec_wm8594.c.patch | 1084 ++++ ...00-sound_soc_ingenic_ecodec_wm8594.h.patch | 65 + ...00-sound_soc_ingenic_icodec_Makefile.patch | 7 + ...0000-sound_soc_ingenic_icodec_dump.c.patch | 123 + ...0-sound_soc_ingenic_icodec_icdc_d3.c.patch | 765 +++ ...0-sound_soc_ingenic_icodec_icdc_d3.h.patch | 411 ++ .../patches/00000-sound_soc_soc-io.c.patch | 23 + .../00000-tools_pm-sleep_Makefile.patch | 42 + .../patches/00000-tools_pm-sleep_README.patch | 10 + ..._pm-sleep_chips_m200_include_cache.h.patch | 115 + ...ls_pm-sleep_chips_m200_include_cpu.h.patch | 42 + ...m-sleep_chips_m200_include_cpufreq.h.patch | 60 + ...pm-sleep_chips_x1000_include_cache.h.patch | 90 + ...s_pm-sleep_chips_x1000_include_cpu.h.patch | 19 + ...-sleep_chips_x1000_include_cpufreq.h.patch | 36 + ...00000-tools_pm-sleep_core_sleep.dump.patch | 1048 ++++ .../00000-tools_pm-sleep_core_sleep.hex.patch | 1030 ++++ .../00000-tools_pm-sleep_core_sleep.map.patch | 195 + .../patches/00000-tools_pm-sleep_gpio.c.patch | 71 + .../00000-tools_pm-sleep_i2c-gpio.c.patch | 276 + ...0000-tools_pm-sleep_include_common.h.patch | 9 + .../00000-tools_pm-sleep_include_cpm.h.patch | 97 + .../00000-tools_pm-sleep_include_ddr.h.patch | 106 + .../00000-tools_pm-sleep_include_gpio.h.patch | 71 + ...00-tools_pm-sleep_include_i2c-gpio.h.patch | 23 + ...00-tools_pm-sleep_include_mipsregs.h.patch | 862 +++ ...00-tools_pm-sleep_include_pm_sleep.h.patch | 26 + ...000-tools_pm-sleep_include_smp_cp0.h.patch | 50 + .../00000-tools_pm-sleep_include_uart.h.patch | 21 + .../00000-tools_pm-sleep_pm_sleep.c.patch | 317 ++ .../00000-tools_pm-sleep_start.S.patch | 193 + .../00000-tools_pm-sleep_u-boot.lds.patch | 97 + .../patches/00000-tools_pm-sleep_uart.c.patch | 64 + .../patches/00001-change_phy_clk_freq.patch | 12 + .../board/t40/kernel/t40.generic.config | 2244 ++++++++ br-ext-chip-ingenic/board/t40/t40.config | 2 + .../configs/t40_lite_defconfig | 108 + .../configs/t40_ultimate_defconfig | 114 + br-ext-chip-ingenic/package/ingenic-osdrv-t40 | 1 + general/package/ingenic-osdrv-t40/Config.in | 6 + .../ingenic-osdrv-t40/files/script/S95ingenic | 86 + .../ingenic-osdrv-t40/files/script/ircut_demo | 27 + .../files/script/load_ingenic | 87 + .../ingenic-osdrv-t40/ingenic-osdrv-t40.mk | 24 + 727 files changed, 192430 insertions(+) create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_Kbuild.platforms.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_Kconfig.debug.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_halley2v20.dts.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_seal.dts.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_shark.dts.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_shark_fast.dts.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_t40-pinctrl.dtsi.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_t40.dtsi.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_t40_fpga.dts.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_x2000-v12-pinctrl.dtsi.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_x2000-v12.dtsi.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_x2000_v12_fpga.dts.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_zcompressed_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_zcompressed_dummy.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_zcompressed_entry.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_zcompressed_filesize.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_zcompressed_head.S.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_zcompressed_ld.script.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_zcompressed_misc.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_zcompressed_tools_entry.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_zcompressed_tools_filesize.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_bootinfo.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_cacheflush.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_cop2.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_cpu-features.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_cpu.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_fpu.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_irqflags.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_msa.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_pgtable-bits.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_processor.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_r4kcache.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_switch_to.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_uapi_asm_sigcontext.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_kernel_cpu-probe.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_kernel_genex.S.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_kernel_idle.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_kernel_perf_event_mipsxx.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_kernel_proc.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_kernel_process.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_kernel_setup.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_kernel_signal.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_kernel_smp.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_kernel_traps.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_mm_c-r4k.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_mm_dma-default.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_mm_tlb-r4k.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_vdso_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_Platform.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_cpu_ccu_test.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_cpu_dma_test.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_cpu_spinlock_test.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_cpu_tcsm.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_cpu_watch_test.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_ddr_bandwidth_monitor.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_ddr_change_freq.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_l2c_test.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_multithread_test.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_multithread_test.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_raw_dma_test.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_get-cpu-features.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_jz_notifier.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_mxuv3.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_proc-exec.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_proc.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_include_ccu.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_include_core_base.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_include_irq_cpu.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_include_jz_notifier.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_include_jz_proc.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_include_mxu.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_include_mxu_media.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_include_mxuv3.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_prom.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_sc.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_smp.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_xburst_pmon.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_Kconfig.DT.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_gpio.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_cpu-feature-overrides.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_irq.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_libdmmu.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_base.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_cache.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_cpm.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_ddr.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_extal.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_gpio.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_mmc.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_pdma.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_rtc.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_sfc.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_tcsm_layout.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_war.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_libdmmu.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_pm.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_regs_save_restore.S.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_regs_save_restore.py.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_reset.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_serial.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_setup.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_Kconfig.DT.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_cpu-feature-overrides.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_irq.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_libdmmu.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_soc_base.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_soc_cache.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_soc_cpm.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_soc_ddr.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_soc_rtc.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_soc_sfc.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_soc_tcsm_layout.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_war.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_libdmmu.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_pm.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_regs_save_restore.S.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_regs_save_restore.py.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_serial.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_setup.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_Platform.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_common_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_common_include_jz_notifier.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_common_include_mxu.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_common_include_mxu_media.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_common_initrd-check.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_common_jz_notifier.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_common_mxu-xburst.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_common_prom.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_common_sc-xburst.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_debug_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_debug_trace-exit.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_Kconfig.DT.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_core_sleep.hex.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_early_printk.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_include_cpu-feature-overrides.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_include_irq.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_include_soc_base.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_include_soc_cache.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_include_soc_cpm.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_include_soc_ost.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_include_soc_sfc.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_include_soc_tcsm_layout.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_include_soc_tcu.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_include_war.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_pm.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_regs_save_restore.S.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_setup.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_socid.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_core_sleep.hex.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_early_printk.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_cpu-feature-overrides.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_irq.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_soc_ahbm.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_soc_base.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_soc_cache.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_soc_cpm.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_soc_ddr.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_soc_extal.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_soc_gpemc.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_soc_irq.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_soc_ost.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_soc_sfc.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_soc_tcsm_layout.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_soc_tcu.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_war.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_pm.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_regs_save_restore.S.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_setup.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-block_partitions_efi.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_block_zram_zram_drv.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_bluetooth_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_bluetooth_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_bluetooth_hci_ldisc.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_bluetooth_hci_rtk_h5.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_bluetooth_hci_uart.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_bluetooth_rtk_coex.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_bluetooth_rtk_coex.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_char_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_char_hw_random_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_char_hw_random_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_char_hw_random_ingenic-rng.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_char_random.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_clk-fixed-rate.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_clk-fractional-divider.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_clk-gate.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_clk-mux.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_clk.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_cgu.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_cgu.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_clk-bus.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_clk-bus.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_clk-div.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_clk-div.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_clk-pll.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_clk-pll.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_clk-t40.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_clk-x2000-v12.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_clk.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_clk.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_jz4740-cgu.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_jz4780-cgu.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_power-gate.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_power-gate.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clocksource_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clocksource_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clocksource_ingenic_core_ost.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clocksource_ingenic_sysost.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_cpufreq_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_cpufreq_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_cpufreq_ingenic-cpufreq.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_crypto_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_crypto_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_crypto_ingenic-aes.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_crypto_ingenic-aes.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_crypto_ingenic-hash.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_crypto_ingenic-hash.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_dma_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_dma_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_dma_ingenic_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_dma_ingenic_ingenic_dma.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_dma_ingenic_ingenic_dma.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_i2c_busses_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_i2c_busses_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_i2c_busses_i2c-ingenic.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_irqchip_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_irqchip_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_irqchip_irq-ingenic-chip.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_irqchip_irq-ingenic-cpu.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_irqchip_irq-ingenic.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_lzma_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_lzma_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_lzma_lzma.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_lzma_lzma_debug.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_i2c_soc_camera_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_i2c_soc_camera_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_i2c_soc_camera_gc2155.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_i2c_soc_camera_mt9v022_test.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_i2c_soc_camera_ov5640.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_i2c_soc_camera_ov9281.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-jpeg_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-jpeg_ingenic_jpeg_enc.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-jpeg_jpeg-core.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-jpeg_jpeg-core.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-jpeg_jpeg-hw.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-jpeg_jpeg-regs.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-rotate_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-rotate_rotate-hw.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-rotate_rotate-regs.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-rotate_rotate.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-rotate_rotate.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_felix_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_felix_api_jzm_h264_dec.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_felix_api_jzm_h264_dec.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_felix_api_jzm_vpu.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_felix_felix_drv.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_felix_felix_drv.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_felix_felix_ops.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_felix_felix_ops.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_README.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_api_helix.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_api_helix_jpeg_dec.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_api_helix_jpeg_dec.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_api_helix_jpeg_enc.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_api_helix_jpeg_enc.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_api_helix_x264_enc.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_api_helix_x264_enc.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_default_sliceinfo.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264e.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264e.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_bitstream.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_cabac.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_cabac.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_common.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_common.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_nal.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_osdep.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_set.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_set.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_slice.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_slice.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_helix_buf.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_helix_drv.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_helix_drv.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_helix_ops.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_helix_ops.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_jpgd.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_jpgd.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_jpge.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_jpge.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_jpge_head.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_jpge_ht.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_jpge_qt.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_x1000_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_x1000_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_x1000_ingenic_camera.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_x1000_ingenic_camera.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_x2000_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_x2000_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_x2000_ingenic_camera.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_x2000_ingenic_camera.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_x2000_mipi_csi.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_x2000_mipi_csi.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_v4l2-core_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_v4l2-core_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_v4l2-core_videobuf2-dma-contig-ingenic.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mfd_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mfd_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mfd_ingenic-tcu.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mfd_ingenic_adc_aux.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mfd_ingenic_adc_v13.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mfd_rn5t567-irq.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mfd_rn5t567.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_misc_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_misc_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_misc_bt_power_bluesleep.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_misc_ingenic_rsa.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_misc_logger.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_misc_logger.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_misc_rmem.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_core_core.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_core_pwrseq_simple.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_host_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_host_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_host_ingenic_mmc.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_host_ingenic_mmc.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_host_ingenic_mmc_reg.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_host_ingenic_sdio.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_host_sdhci-ingenic.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_host_sdhci-ingenic.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_host_sdhci.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_ingenic_sfc_common.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_ingenic_sfc_common.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_ingenic_sfc_nand.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_ingenic_sfc_nor.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_ingenic_sfc_ops.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_nand_device_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_nand_device_ato_nand.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_nand_device_gd_nand.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_nand_device_mxic_nand.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_nand_device_nand_common.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_nand_device_nand_common.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_nand_device_winbond_nand.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_nand_device_xtx_nand.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_sfc.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_sfc_flash.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_spinand.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_spinand_cmd.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_spinor.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_spinor_cmd.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_ingenic_sfc_common.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_ingenic_sfc_common.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_ingenic_sfc_nand.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_ingenic_sfc_nor.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_ingenic_sfc_ops.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_ato_nand.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_dosilicon_nand.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_esmt_mid2c_nand.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_foresee_nand.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_gd_nand.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_micron_nand.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_mxic_nand.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_nand_common.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_nand_common.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_winbond_nand.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_xtx_mid0b_nand.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_xtx_nand.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_zetta_nand.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_sfc.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_sfc_flash.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_spinand.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_spinand_cmd.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_spinor.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_spinor_cmd.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_ingenic_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_ingenic_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_ingenic_ingenic_mac.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_ingenic_ingenic_mac.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_ingenic_readme.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_ingenic_synopGMAC_Dev.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_ingenic_synopGMAC_Dev.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_ingenic_synopGMAC_plat.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_ingenic_synopGMAC_plat.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_mii.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_pinctrl_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_pinctrl_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_pinctrl_pinctrl-ingenic.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_pinctrl_pinctrl-ingenic.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_pwm_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_pwm_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_pwm_core.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_pwm_pwm-ingenic-v2.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_pwm_pwm-ingenic.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_regulator_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_regulator_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_regulator_rn5t567-regulator.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_rtc_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_rtc_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_rtc_rtc-bm8563.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_rtc_rtc-ingenic.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_rtc_rtc-ingenic.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_spi_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_spi_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_spi_ingenic_spi.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_spi_ingenic_spi.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_tty_serial_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_tty_serial_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_tty_serial_ingenic_uart.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_tty_serial_ingenic_uart.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_tty_serial_serial_core.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_core_hub.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_dwc2_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_dwc2_core.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_dwc2_core.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_dwc2_gadget.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_dwc2_hcd.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_dwc2_hcd_ddma.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_dwc2_hcd_intr.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_dwc2_hcd_queue.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_dwc2_hw.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_dwc2_platform.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_gadget_function_uvc_configfs.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_phy_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_phy_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_phy_phy-ingenic-inno.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_phy_phy-ingenic-usb.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_phy_phy-ingenic-x1800.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v10_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v10_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v10_displays_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v10_displays_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v10_displays_panel_truly_tft240240_2_e.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v10_ingenicfb.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v10_ingenicfb.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v10_lcd_regs.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v11_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v11_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v11_displays_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v11_displays_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v11_displays_panel-kd035hvfbd037.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v11_displays_panel-kd035hvfmd057.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v11_dpu_reg.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v11_ingenicfb.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v11_ingenicfb.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v11_uapi_ingenicfb.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_lt9211.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_lt9211.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-bm8766.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-ek79007.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-jd9161z.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-kd035hvfbd037.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-kd050hdfia019.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-ma0060.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-mtf070.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-px070.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-st7701s.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-st7703.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-st7789v_240_320.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-tl040hds01ct.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-tl040wvs03ct.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-y88249.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-ylym286a.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-yts500xlai.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_dpu_reg.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_ingenicfb.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_ingenicfb.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_jz_dsim.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_jz_mipi_dsi_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_jz_mipi_dsi_jz_mipi_dsi.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_jz_mipi_dsi_jz_mipi_dsi_lowlevel.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_jz_mipi_dsi_jz_mipi_dsi_lowlevel.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_jz_mipi_dsi_jz_mipi_dsi_regs.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_jz_mipi_dsi_jz_mipi_dsih_hal.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_jz_mipi_dsi_jz_mipi_dsih_hal.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_bscaler_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_bscaler_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_bscaler_ingenic_bscaler.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_i2d_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_i2d_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_i2d_ingenic_i2d.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_i2d_ingenic_i2d.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_ipu_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_ipu_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_ipu_ingenic_drawbox.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_ipu_ingenic_drawbox.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_ipu_ingenic_ipu_v13.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_ipu_ingenic_ipu_v13.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_ipu_ingenic_regs_v13.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_watchdog_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_watchdog_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_watchdog_ingenic_wdt.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_seq_file.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_decompressor.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_decompressor.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_decompressor_multi.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_decompressor_single.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_hardware_lzma.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_jz-lzma.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_lzma_wrapper.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_squashfs.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_super.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_allocator.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_allocator.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_attribs.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_attribs.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_bitmap.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_bitmap.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_cache.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_cache.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_checkptrw.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_checkptrw.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_ecc.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_ecc.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_endian.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_endian.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_getblockinfo.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_guts.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_guts.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_linux.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_mtdif.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_mtdif.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_nameval.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_nameval.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_nand.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_nand.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_packedtags1.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_packedtags1.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_packedtags2.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_packedtags2.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_summary.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_summary.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_tagscompat.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_tagscompat.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_tagsmarshall.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_tagsmarshall.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_trace.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_verify.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_verify.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_vfs.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_yaffs1.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_yaffs1.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_yaffs2.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_yaffs2.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yportenv.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_clock_ingenic-t40-fpga.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_clock_ingenic-t40.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_clock_ingenic-tcu.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_clock_ingenic-x1000.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_clock_ingenic-x1800.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_clock_ingenic-x2000-v12-fpga.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_clock_ingenic-x2000-v12.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_clock_ingenic-x2000.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_dma_ingenic-pdma.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_interrupt-controller_mips-irq.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_interrupt-controller_t40-irq.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_interrupt-controller_x2000-v12-irq.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_net_ingenic_gmac.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_pinctrl_ingenic-pinctrl.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_sound_ingenic-baic.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_clk-provider.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_decompress_bunzip2_mm.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_decompress_inflate_mm.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_decompress_mm.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_decompress_unlzma_mm.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_decompress_unlzo_mm.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_dmaengine.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_ingenic_adc.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_interrupt.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_mfd_ingenic-tcu.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_mfd_jz_tcu.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_mfd_rn5t567.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_seq_file.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_wlan_plat.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_soc_xburst_reboot.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_sound_soc.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-init_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-init_main.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-lib_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-lib_decompress_bunzip2.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-lib_decompress_inflate.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-lib_decompress_unlz4.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-lib_decompress_unlzma.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-lib_decompress_unlzo.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-lib_decompress_unxz.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-scripts_setlocalversion.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_core_pcm_native.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_README.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_asoc-aic.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_asoc-aic.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_asoc-dma.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_asoc-dma.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_asoc-dmic.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_asoc-dmic.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_asoc-i2s.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_asoc-pcm.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_asoc-pcm.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_asoc-spdif.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-baic.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-baic.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-dma.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-dma.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-dmic.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-dmic.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-dsp.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-dsp.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-fmtcov.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-fmtcov.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-mixer.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-mixer.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-spdif.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-spdif.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-vir-fe.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_boards_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_boards_seal.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_boards_x1000-board.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_ecodec_Kconfig.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_ecodec_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_ecodec_ak4458.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_ecodec_ak4458.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_ecodec_ak5558.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_ecodec_ak5558.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_ecodec_wm8594.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_ecodec_wm8594.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_icodec_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_icodec_dump.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_icodec_icdc_d3.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_icodec_icdc_d3.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_soc-io.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_Makefile.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_README.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_chips_m200_include_cache.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_chips_m200_include_cpu.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_chips_m200_include_cpufreq.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_chips_x1000_include_cache.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_chips_x1000_include_cpu.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_chips_x1000_include_cpufreq.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_core_sleep.dump.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_core_sleep.hex.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_core_sleep.map.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_gpio.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_i2c-gpio.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_include_common.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_include_cpm.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_include_ddr.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_include_gpio.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_include_i2c-gpio.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_include_mipsregs.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_include_pm_sleep.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_include_smp_cp0.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_include_uart.h.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_pm_sleep.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_start.S.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_u-boot.lds.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_uart.c.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/patches/00001-change_phy_clk_freq.patch create mode 100644 br-ext-chip-ingenic/board/t40/kernel/t40.generic.config create mode 100644 br-ext-chip-ingenic/board/t40/t40.config create mode 100644 br-ext-chip-ingenic/configs/t40_lite_defconfig create mode 100644 br-ext-chip-ingenic/configs/t40_ultimate_defconfig create mode 120000 br-ext-chip-ingenic/package/ingenic-osdrv-t40 create mode 100644 general/package/ingenic-osdrv-t40/Config.in create mode 100755 general/package/ingenic-osdrv-t40/files/script/S95ingenic create mode 100755 general/package/ingenic-osdrv-t40/files/script/ircut_demo create mode 100755 general/package/ingenic-osdrv-t40/files/script/load_ingenic create mode 100644 general/package/ingenic-osdrv-t40/ingenic-osdrv-t40.mk diff --git a/br-ext-chip-ingenic/Config.in b/br-ext-chip-ingenic/Config.in index 11cd87a6..e6c7812c 100644 --- a/br-ext-chip-ingenic/Config.in +++ b/br-ext-chip-ingenic/Config.in @@ -3,6 +3,7 @@ source "$BR2_EXTERNAL_INGENIC_PATH/package/ingenic-osdrv-t20/Config.in" source "$BR2_EXTERNAL_INGENIC_PATH/package/ingenic-osdrv-t21/Config.in" source "$BR2_EXTERNAL_INGENIC_PATH/package/ingenic-osdrv-t30/Config.in" source "$BR2_EXTERNAL_INGENIC_PATH/package/ingenic-osdrv-t31/Config.in" +source "$BR2_EXTERNAL_INGENIC_PATH/package/ingenic-osdrv-t40/Config.in" source "$BR2_EXTERNAL_INGENIC_PATH/package/ingenic_patcher/Config.in" source "$BR2_EXTERNAL_INGENIC_PATH/package/aura-httpd/Config.in" source "$BR2_EXTERNAL_INGENIC_PATH/package/comgt/Config.in" diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-Makefile.patch new file mode 100644 index 00000000..60725621 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-Makefile.patch @@ -0,0 +1,25 @@ +diff -drupN a/Makefile b/Makefile +--- a/Makefile 2017-10-21 18:09:07.000000000 +0300 ++++ b/Makefile 2022-06-09 05:02:26.000000000 +0300 +@@ -252,7 +252,7 @@ SUBARCH := $(shell uname -m | sed -e s/i + # "make" in the configured kernel build directory always uses that. + # Default value for CROSS_COMPILE is not to prefix executables + # Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile +-ARCH ?= $(SUBARCH) ++ARCH ?= mips + CROSS_COMPILE ?= $(CONFIG_CROSS_COMPILE:"%"=%) + + # Architecture as present in compile.h +@@ -1195,10 +1195,10 @@ CLEAN_DIRS += $(MODVERDIR) + MRPROPER_DIRS += include/config usr/include include/generated \ + arch/*/include/generated .tmp_objdiff + MRPROPER_FILES += .config .config.old .version .old_version \ +- Module.symvers tags TAGS cscope* GPATH GTAGS GRTAGS GSYMS \ ++ Module.symvers TAGS cscope* GPATH GTAGS GRTAGS GSYMS \ + signing_key.pem signing_key.priv signing_key.x509 \ + x509.genkey extra_certificates signing_key.x509.keyid \ +- signing_key.x509.signer vmlinux-gdb.py ++ signing_key.x509.signer vmlinux-gdb.py #tags \ + + # clean - Delete most, but leave enough to build external modules + # diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_Kbuild.platforms.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_Kbuild.platforms.patch new file mode 100644 index 00000000..450a1948 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_Kbuild.platforms.patch @@ -0,0 +1,12 @@ +diff -drupN a/arch/mips/Kbuild.platforms b/arch/mips/Kbuild.platforms +--- a/arch/mips/Kbuild.platforms 2017-10-21 18:09:07.000000000 +0300 ++++ b/arch/mips/Kbuild.platforms 2022-06-09 05:02:26.000000000 +0300 +@@ -34,6 +34,8 @@ platforms += sni + platforms += txx9 + platforms += vr41xx + platforms += xilfpga ++platforms += xburst ++platforms += xburst2 + + # include the platform specific files + include $(patsubst %, $(srctree)/arch/mips/%/Platform, $(platforms)) diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_Kconfig.debug.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_Kconfig.debug.patch new file mode 100644 index 00000000..743c0b68 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_Kconfig.debug.patch @@ -0,0 +1,12 @@ +diff -drupN a/arch/mips/Kconfig.debug b/arch/mips/Kconfig.debug +--- a/arch/mips/Kconfig.debug 2017-10-21 18:09:07.000000000 +0300 ++++ b/arch/mips/Kconfig.debug 2022-06-09 05:02:26.000000000 +0300 +@@ -8,7 +8,7 @@ source "lib/Kconfig.debug" + + config EARLY_PRINTK + bool "Early printk" if EXPERT +- depends on SYS_HAS_EARLY_PRINTK ++ depends on SYS_HAS_EARLY_PRINTK && !FAST_BOOT + default y + help + This option enables special console drivers which allow the kernel diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_Kconfig.patch new file mode 100644 index 00000000..de00c255 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_Kconfig.patch @@ -0,0 +1,101 @@ +diff -drupN a/arch/mips/Kconfig b/arch/mips/Kconfig +--- a/arch/mips/Kconfig 2017-10-21 18:09:07.000000000 +0300 ++++ b/arch/mips/Kconfig 2022-06-09 05:02:26.000000000 +0300 +@@ -299,7 +299,7 @@ config MACH_JAZZ + Olivetti M700-10 workstations. + + config MACH_INGENIC +- bool "Ingenic SoC based machines" ++ bool "Ingenic SoC based machines, only for jz4740,4780" + select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_LITTLE_ENDIAN + select SYS_SUPPORTS_ZBOOT_UART16550 +@@ -312,6 +312,53 @@ config MACH_INGENIC + select USE_OF + select LIBFDT + ++config MACH_XBURST ++ bool "Ingenic Xburst based machines" ++ select SYS_SUPPORTS_32BIT_KERNEL ++ select SYS_SUPPORTS_LITTLE_ENDIAN ++ select SYS_HAS_CPU_MIPS32_R1 ++ select SYS_HAS_CPU_MIPS32_R2 ++ select SYS_HAS_EARLY_PRINTK ++ select MIPS_EXTERNAL_TIMER ++ select DMA_NONCOHERENT ++ select HAVE_CLK ++ select ARCH_REQUIRE_GPIOLIB ++ select SYS_SUPPORTS_HIGHMEM ++ select XBURST_CPU_SCACHE ++ select DMA_INGENIC_HIGHMEM_FLUSH ++ select HAVE_KERNEL_LZMA ++ select IRQ_MIPS_CPU ++ select USE_OF ++ select LIBFDT ++ select COMMON_CLK ++ ++config MACH_XBURST2 ++ bool "Ingenic Xburst2 based machines" ++ select SYS_SUPPORTS_32BIT_KERNEL ++ select SYS_SUPPORTS_LITTLE_ENDIAN ++ select SYS_HAS_CPU_MIPS32_R1 ++ select SYS_HAS_CPU_MIPS32_R2 ++ select SYS_HAS_EARLY_PRINTK ++ select SYS_SUPPORTS_SMP ++ select SYS_SUPPORTS_HOTPLUG_CPU ++ select MIPS_EXTERNAL_TIMER ++ select DMA_NONCOHERENT ++ select HAVE_CLK ++ select ARCH_REQUIRE_GPIOLIB ++ select SYS_SUPPORTS_HIGHMEM ++ select XBURST2_CPU_SCACHE ++ select DMA_INGENIC_HIGHMEM_FLUSH ++ select SYS_SUPPORTS_ZBOOT ++ select IRQ_MIPS_CPU ++ select USE_OF ++ select LIBFDT ++ select MIPS_O32_FP64_SUPPORT ++ select WEAK_ORDERING ++ select WEAK_REORDERING_BEYOND_LLSC ++ select COMMON_CLK ++ select OF_RESERVED_MEM ++ ++ + config LANTIQ + bool "Lantiq based platforms" + select DMA_NONCOHERENT +@@ -994,6 +1041,8 @@ source "arch/mips/loongson64/Kconfig" + source "arch/mips/netlogic/Kconfig" + source "arch/mips/paravirt/Kconfig" + source "arch/mips/xilfpga/Kconfig" ++source "arch/mips/xburst/Kconfig" ++source "arch/mips/xburst2/Kconfig" + + endmenu + +@@ -1086,6 +1135,9 @@ config DMA_MAYBE_COHERENT + select DMA_NONCOHERENT + bool + ++config DMA_INGENIC_HIGHMEM_FLUSH ++ bool ++ + config DMA_COHERENT + bool + +@@ -2119,6 +2171,15 @@ config MIPS_CPU_SCACHE + bool + select BOARD_SCACHE + ++config XBURST_CPU_SCACHE ++ bool ++ select BOARD_SCACHE ++ ++config XBURST2_CPU_SCACHE ++ bool ++ select BOARD_SCACHE ++ select CPU_SUPPORTS_CPUFREQ ++ + config R5000_CPU_SCACHE + bool + select BOARD_SCACHE diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_Makefile.patch new file mode 100644 index 00000000..a90e1201 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_Makefile.patch @@ -0,0 +1,28 @@ +diff -drupN a/arch/mips/Makefile b/arch/mips/Makefile +--- a/arch/mips/Makefile 2017-10-21 18:09:07.000000000 +0300 ++++ b/arch/mips/Makefile 2022-06-09 05:02:26.000000000 +0300 +@@ -342,6 +342,16 @@ $(boot-y): $(vmlinux-32) FORCE + $(Q)$(MAKE) $(build)=arch/mips/boot VMLINUX=$(vmlinux-32) \ + $(bootvars-y) arch/mips/boot/$@ + ++# zImage ++zImage: $(vmlinux-32) FORCE ++ $(Q)$(MAKE) $(build)=arch/mips/boot/zcompressed VMLINUX=$(vmlinux-32) $@ ++ @cp arch/mips/boot/zcompressed/$@ arch/mips/boot/compressed/$@ ++ @echo ' Kernel: arch/mips/boot/compressed/$@ is ready' ++xImage: $(vmlinux-32) FORCE ++ $(Q)$(MAKE) $(build)=arch/mips/boot/zcompressed VMLINUX=$(vmlinux-32) $@ ++ @cp arch/mips/boot/zcompressed/$@ arch/mips/boot/compressed/$@ ++ @echo ' Kernel: arch/mips/boot/compressed/$@ is ready' ++ + ifdef CONFIG_SYS_SUPPORTS_ZBOOT + # boot/compressed + $(bootz-y): $(vmlinux-32) FORCE +@@ -409,6 +419,7 @@ define archhelp + echo ' uImage.gz - U-Boot image (gzip)' + echo ' uImage.lzma - U-Boot image (lzma)' + echo ' uImage.lzo - U-Boot image (lzo)' ++ echo ' xImage - U-Boot-spl xImage (ingenic spl boot)' + echo ' dtbs - Device-tree blobs for enabled boards' + echo ' dtbs_install - Install dtbs to $(INSTALL_DTBS_PATH)' + echo diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_Makefile.patch new file mode 100644 index 00000000..ec8951f5 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_Makefile.patch @@ -0,0 +1,23 @@ +diff -drupN a/arch/mips/boot/Makefile b/arch/mips/boot/Makefile +--- a/arch/mips/boot/Makefile 2017-10-21 18:09:07.000000000 +0300 ++++ b/arch/mips/boot/Makefile 2022-06-09 05:02:27.000000000 +0300 +@@ -75,7 +75,7 @@ $(obj)/vmlinux.bin.lzo: $(obj)/vmlinux.b + # Compressed u-boot images + # + +-targets += uImage ++#targets += uImage + targets += uImage.bin + targets += uImage.bz2 + targets += uImage.gz +@@ -97,6 +97,9 @@ $(obj)/uImage.lzma: $(obj)/vmlinux.bin.l + $(obj)/uImage.lzo: $(obj)/vmlinux.bin.lzo FORCE + $(call if_changed,uimage,lzo) + +-$(obj)/uImage: $(obj)/uImage.$(suffix-y) ++ ++ ++targets += uImage ++$(obj)/uImage: $(obj)/uImage.lzma $(obj)/uImage.lzo FORCE + @ln -sf $(notdir $<) $@ + @echo ' Image $@ is ready' diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_Makefile.patch new file mode 100644 index 00000000..eb2c2e05 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_Makefile.patch @@ -0,0 +1,18 @@ +diff -drupN a/arch/mips/boot/dts/ingenic/Makefile b/arch/mips/boot/dts/ingenic/Makefile +--- a/arch/mips/boot/dts/ingenic/Makefile 2017-10-21 18:09:07.000000000 +0300 ++++ b/arch/mips/boot/dts/ingenic/Makefile 2022-06-09 05:02:27.000000000 +0300 +@@ -1,6 +1,14 @@ + dtb-$(CONFIG_JZ4740_QI_LB60) += qi_lb60.dtb + dtb-$(CONFIG_JZ4780_CI20) += ci20.dtb ++dtb-$(CONFIG_DT_HALLEY2_V20) += halley2v20.dtb ++dtb-$(CONFIG_DT_SEAL) += seal.dtb ++dtb-$(CONFIG_DT_X2000_V12_FPGA) += x2000_v12_fpga.dtb + ++ifdef CONFIG_FAST_BOOT ++dtb-$(CONFIG_DT_T40_SHARK) += shark_fast.dtb ++else ++dtb-$(CONFIG_DT_T40_SHARK) += shark.dtb ++endif + obj-y += $(patsubst %.dtb, %.dtb.o, $(dtb-y)) + + # Force kbuild to make empty built-in.o if necessary diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_halley2v20.dts.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_halley2v20.dts.patch new file mode 100644 index 00000000..f1d32374 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_halley2v20.dts.patch @@ -0,0 +1,370 @@ +diff -drupN a/arch/mips/boot/dts/ingenic/halley2v20.dts b/arch/mips/boot/dts/ingenic/halley2v20.dts +--- a/arch/mips/boot/dts/ingenic/halley2v20.dts 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/boot/dts/ingenic/halley2v20.dts 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,366 @@ ++/dts-v1/; ++ ++/memreserve/ 0x01f00000 0x00100000; /* dmic reserved */ ++ ++#include ++#include ++#include "x1000.dtsi" ++ ++&msc0 { ++ status = "okay"; ++ pinctrl-names ="default"; ++ pinctrl-0 = <&msc0_4bit_pa>; ++ cap-sd-highspeed; ++ cap-mmc-highspeed; ++ cd-inverted; ++ max-frequency = <50000000>; ++ bus-width = <4>; ++ voltage-ranges = <1800 3300>; ++ ingenic,sdio_clk = <0>; ++ /* special property */ ++ ingenic,wp-gpios = <0>; ++ ingneic,cd-gpios = <0>; ++ ingenic,rst-gpios = <0>; ++ ingenic,removal-dontcare; /*removal-dontcare, removal-nonremovable, removal-removable, removal-manual*/ ++}; ++ ++&msc1 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ status = "okay"; ++ pinctrl-names ="default","enable", "disable"; ++ pinctrl-0 = <&msc1_4bit_pc>; ++ pinctrl-1 = <&rtc32k_enable>; ++ pinctrl-2 = <&rtc32k_disable>; ++ cap-sd-highspeed; ++ cap-mmc-highspeed; ++ max-frequency = <48000000>; ++ bus-width = <4>; ++ voltage-ranges = <1800 3300>; ++ non-removable; ++ ++ ingenic,sdio_clk = <1>; ++ keep-power-in-suspend; ++ /* special property */ ++ ingenic,wp-gpios = <0>; ++ ingneic,cd-gpios = <0>; ++ ingenic,rst-gpios = <0>; ++ ingenic,removal-manual; /*removal-dontcare, removal-nonremovable, removal-removable, removal-manual*/ ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ bcmdhd_wlan: bcmdhd_wlan { ++ compatible = "android,bcmdhd_wlan"; ++ ingenic,sdio-irq = <&gpc 16 IRQ_TYPE_LEVEL_HIGH INGENIC_GPIO_NOBIAS>; ++ ingenic,sdio-reset = <&gpc 17 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ }; ++}; ++ ++&i2c0 { ++ status = "okay"; ++ clock-frequency = <100000>; ++ timeout = <1000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c0_pb>; ++ ++ ov5640: ov5640@0x3c { ++ status = "disabled"; ++ compatible = "ovti,ov5640"; ++ reg = <0x3c>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&cim_pa>; ++ ++ resetb-gpios = <&gpd 5 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ pwdn-gpios = <&gpd 4 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ vcc-en-gpios = <&gpd 3 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ ++ /*gsensor-supply = <&LDO3>;*/ ++ /*lcd-supply = <&LDO5>;*/ ++ /*supplies-name = "vcc_gsensor", "lcd_3v3";*/ ++ ++ port { ++ ov5640_0: endpoint { ++ remote-endpoint = <&cim_0>; ++ }; ++ }; ++ }; ++ gc2155: gc2155@0x3c { ++ status = "okay"; ++ compatible = "ovti,gc2155"; ++ reg = <0x3c>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&cim_pa>; ++ ++ resetb-gpios = <&gpd 5 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ pwdn-gpios = <&gpd 4 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ vcc-en-gpios = <&gpd 3 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ ++ /*gsensor-supply = <&LDO3>;*/ ++ /*lcd-supply = <&LDO5>;*/ ++ /*supplies-name = "vcc_gsensor", "lcd_3v3";*/ ++ ++ port { ++ gc2155_0: endpoint { ++ remote-endpoint = <&cim_0>; ++ }; ++ }; ++ }; ++}; ++ ++&spi0 { ++ status = "disabled"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi_pd>; ++ ++ spi-max-frequency = <54000000>; ++ num-cs = <2>; ++ cs-gpios = <0>, <0>; ++/* cs-gpios = <&gpa 27 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>, <&gpa 27 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>;*/ ++ ingenic,chnl = <0>; ++ ingenic,allow_cs_same = <1>; ++ ingenic,bus_num = <0>; ++ ingenic,has_dma_support = <0>; ++ ingenic,spi-src-clk = <0>;/*0, ext; 1, sfc*/ ++ ++ dac0: dh2228@0 { ++ compatible = "spidev"; ++ reg = <2>; ++ chip_select= <0>; ++ spi-max-frequency = <100000>; ++ }; ++}; ++ ++&cim { ++ status = "okay"; ++ port { ++ cim_0: endpoint@0 { ++ /*remote-endpoint = <&ov5640_0>;*/ ++ remote-endpoint = <&gc2155_0>; ++ bus-width = <8>; ++ /*vsync-active = 1;*/ ++ /*hsync-active = 1;*/ ++ }; ++ }; ++}; ++ ++&lcd { ++ status = "okay"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&lcd_pa>, <&lcd_pb>; ++}; ++ ++&i2c1 { ++ clock-frequency = <400000>; ++ timeout = <1000>; ++ status = "disabled"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c1_pc>; ++}; ++ ++&i2c2 { ++ status = "disabled"; ++}; ++ ++&uart0 { ++ pinctrl-names = "default"; ++ status = "okay"; ++ pinctrl-0 = <&uart0_pc_fc>; ++}; ++ ++&uart2 { ++ pinctrl-names = "default"; ++ status = "okay"; ++ pinctrl-0 = <&uart2_pc>; ++}; ++ ++&pinctrl { ++ mac_rmii_p0: mac-rmii-p0 { ++ mac_rmii_p0_normal: mac-rmii-p0-normal { ++ ingenic,pinmux = <&gpb 7 9>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ mac_rmii_p0_rst: mac-rmii-p0-rst { ++ ingenic,pinmux = <&gpb 7 9>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ mac_rmii_p1: mac-rmii-p1 { ++ ingenic,pinmux = <&gpb 10 15>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ mac_rmii_nomdio_p1: mac-rmii-nomdio-p1 { ++ ingenic,pinmux = <&gpb 10 12>, <&gpb 15 15>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ gpiokeys: gpiokeys { ++ gpio_power_key:gpio_power_key { ++ ingenic,pinmux = <&gpb 31 31>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++}; ++ ++&mac { ++ pinctrl-names = "default", "reset"; ++ /* pinctrl-0 = <&mac_rmii_p0_normal>, <&mac_rmii_p1>; ++ pinctrl-1 = <&mac_rmii_p0_rst>, <&mac_rmii_p1>;*/ ++ pinctrl-0 = <&mac_rmii_p0_normal>, <&mac_rmii_nomdio_p1>; ++ pinctrl-1 = <&mac_rmii_p0_rst>, <&mac_rmii_nomdio_p1>; ++ status = "okay"; ++ ingenic,rst-gpio = <&gpb 3 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ ingenic,rst-ms = <10>; ++}; ++ ++&sfc { ++ status = "okay"; ++ ingenic,sfc-max-frequency = <150000000>; ++ ingenic,use_board_info = /bits/ 8 <0>; ++}; ++ ++&otg { ++ g-use-dma; ++ status = "okay"; ++}; ++ ++&otg_phy { ++ dr_mode = "otg"; ++ ingenic,drvvbus-gpio = <&gpb 25 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++}; ++ ++/ { ++ model = "halley2-v20"; ++ ++ memory { ++ device_type = "memory"; ++ linux,usable-memory = <0x00000000 0x2000000>; ++ }; ++ ++ aliases: aliases { ++ }; ++ dump_dmic_codec:dump_dmic_codec{ ++ compatible = "ingenic,dmic-dump-codec"; ++ status = "ok"; ++ }; ++ dump_spdif_codec:dump_spdif_codec{ ++ compatible = "ingenic,spdif-dump-codec"; ++ status = "ok"; ++ }; ++ dump_pcm_codec:dump_pcm_codec{ ++ compatible = "ingenic,pcm-dump-codec"; ++ status = "ok"; ++ }; ++ sound_halley2_icdc { ++ status = "ok"; ++ compatible = "ingenic,x1000-sound"; ++ ingenic,model = "halley2"; ++ ingenic,dai-link = "i2s-icdc", "dmic", "pcm"; ++ ingenic,stream = "main", "dmic", "pcm"; ++ ingenic,cpu-dai = <&i2s>, <&dmic>, <&pcm>; ++ ingenic,platform = <&aic>, <&dmic>, <&pcm>; ++ ingenic,codec = <&codec>, <&dump_dmic_codec>, <&dump_pcm_codec>; ++ ingenic,codec-dai = "icdc-d3-hifi", "dmic-dump", "pcm-dump"; ++ ingenic,audio-routing = "Speaker", "DO_LO_PWM", ++ "MICBIAS", "Mic Buildin", ++ "DMIC", "DMic"; ++ /*ingenic,spken-gpio = <&gpb 0 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>;*/ ++ }; ++ sound_halley2_spdif { ++ status = "disabled"; ++ compatible = "ingenic,x1000-sound"; ++ ingenic,model = "halley2"; ++ ingenic,dai-link = "spdif", "dmic", "pcm"; ++ ingenic,stream = "main", "dmic", "pcm"; ++ ingenic,cpu-dai = <&spdif>, <&dmic>, <&pcm>; ++ ingenic,platform = <&aic>, <&dmic>, <&pcm>; ++ ingenic,codec = <&dump_spdif_codec>, <&dump_dmic_codec>, <&dump_pcm_codec>; ++ ingenic,codec-dai = "spdif-dump", "dmic-dump", "pcm-dump"; ++ /*ingenic,spken-gpio = <&gpb 0 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>;*/ ++ }; ++ ++ panel_truly@0 { ++ compatible = "ingenic,truly_tft240240_2_e"; ++ status = "okay"; ++ ingenic,cs-gpio = <&gpb 18 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ ingenic,rst-gpio = <&gpd 0 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ ingenic,blken-gpio = <&gpd 1 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ /*ingenic,pwmen-gpio = <&gpc 25 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>;*/ ++ }; ++ ++ backlight { ++ compatible = "pwm-backlight"; ++ pwms = <&pwmz 0 500000>; ++ brightness-levels = <0 4 8 16 24 32 40 64 128 255>; ++ default-brightness-level = <5>; ++ }; ++ ++pwmz:pwm { ++ compatible = "ingenic,pwm"; ++ #pwm-cells = <2>; ++ pinctrl-0 = <&pwm0_pc>; ++ pinctrl-names = "default"; ++ pwm0:pwm@0 { ++ ingenic,timer-parent = <&channel0>; ++ status = "okay"; ++ }; ++ pwm1:pwm@1 { ++ ingenic,timer-parent = <&channel1>; ++ status = "okay"; ++ }; ++ pwm2:pwm@2 { ++ ingenic,timer-parent = <&channel2>; ++ status = "disabled"; ++ }; ++ pwm3:pwm@3 { ++ ingenic,timer-parent = <&channel3>; ++ status = "disabled"; ++ }; ++ pwm4:pwm@4 { ++ ingenic,timer-parent = <&channel4>; ++ status = "disabled"; ++ }; ++ }; ++ ++ extclk: extclk { ++ clock-frequency = <24000000>; ++ }; ++ gpio_keys: gpio_keys { ++ compatible = "gpio-keys"; ++ ++ power { ++ label = "Power"; ++ linux,code = ; ++ gpios = <&gpb 31 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ gpio-key,wakeup; ++ }; ++ }; ++ bt_power{ ++ compatible = "ingenic,bt_power"; ++ ingenic,reg-on-gpio = <&gpc 18 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ ingenic,wake-gpio = <&gpc 20 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ }; ++}; ++ ++&gpa { ++ ingenic,gpio-sleep-pull = <0 1 2 3 4 5 6 7 8 9 10 11 ++ 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 ++ 28 29 30 31>; ++ ingenic,gpio-sleep-high = <27>; ++}; ++ ++&gpb { ++ ingenic,gpio-sleep-pull = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ++ 15 16 17 18 19 20 21 22 23 24 26>; ++ ingenic,gpio-sleep-npul = <28 29 30>; ++ ingenic,gpio-sleep-low = <25 27>; ++}; ++ ++&gpc { ++ ingenic,gpio-sleep-pull = <21 23 24 25 26 27>; ++ ingenic,gpio-sleep-npul = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 22>; ++}; ++ ++&gpd { ++ ingenic,gpio-sleep-pull = <0 1 2 3 4 5>; ++}; ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_seal.dts.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_seal.dts.patch new file mode 100644 index 00000000..2306cfb6 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_seal.dts.patch @@ -0,0 +1,305 @@ +diff -drupN a/arch/mips/boot/dts/ingenic/seal.dts b/arch/mips/boot/dts/ingenic/seal.dts +--- a/arch/mips/boot/dts/ingenic/seal.dts 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/boot/dts/ingenic/seal.dts 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,301 @@ ++/dts-v1/; ++ ++#include ++#include ++#include "x2000.dtsi" ++ ++/ { ++ compatible = "img,seal", "ingenic,x2000"; ++}; ++ ++&uart0 { ++ status = "okay"; ++}; ++ ++&uart2 { ++ status = "okay"; ++}; ++ ++ ++&as_be_baic { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&baic1_tmclk_pb>, <&baic1_pb>, <&baic2_mclk_pb>, <&baic2_pb>, ++ <&baic3_mclk_pd>, <&baic3_pd>, <&baic4_pe>; ++ ingenic,dai-mode = , ++ , ++ , ++ , ++ ; ++}; ++ ++ ++&as_spdif { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spdif_pb>; ++}; ++ ++&as_dmic { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&dmic_pa>; ++}; ++ ++&sfc { ++ status = "okay"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sfc_pf>; ++ ingenic,use_board_info = /bits/ 8 <0>; ++ ++ ingenic,sfc-max-frequency = <150000000>; ++}; ++ ++&otg { ++ g-use-dma; ++ dr_mode = "otg"; ++ status = "okay"; ++}; ++ ++&otg_phy { ++ dr_mode = "otg"; ++ compatible = "ingenic,innophy", "syscon"; ++ reg = <0x10000000 0x100>; ++ ingenic,drvvbus-gpio = <&gpf 26 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ status = "okay"; ++}; ++ ++ ++&pinctrl { ++ mac_rmii_p0: mac-rmii-p0 { ++ mac_rmii_p0_normal: mac-rmii-normal { ++ ingenic,pinmux = <&gpc 1 3>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ mac_rmii_p0_rst: mac-rmii-p0-rst { ++ ingenic,pinmux = <&gpc 1 3>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ mac_rmii_p1: mac-rmii-p1 { ++ mac_rmii_p1_normal: mac-rmii-p1-normal { ++ ingenic,pinmux = <&gpc 0 0>, <&gpc 4 9>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ ++ mac_rmii_p1_nomdio: mac-rmii-p1-nomdio { ++ ingenic,pinmux = <&gpc 0 0>, <&gpc 4 7>, <&gpc 9 9>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ pwm_pins: pwm-pins { ++ ingenic,pinmux = <&gpb 8 8>; /* pwm0 - pwm15 */ ++ ingenic,pinmux-funcsel = ; ++ }; ++}; ++ ++&mac { ++ pinctrl-names = "default", "reset"; ++ pinctrl-0 = <&mac_rmii_p0_normal>, <&mac_rmii_p1_normal>; ++ pinctrl-1 = <&mac_rmii_p0_rst>, <&mac_rmii_p1_normal>; ++ status = "okay"; ++ ingenic,rst-gpio = <&gpf 26 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ ingenic,rst-ms = <10>; ++ ingenic,mac-mode = ; ++}; ++ ++&pwm { ++ ingenic,pwm-outputs = <0>; /* <1 2 3 4 5 6 7 8 9 10 11 12 ... 15>;Select which pwms are really used */ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pwm_pins>; ++}; ++ ++&msc0 { ++ status = "okay"; ++ /*mmc-hs200-1_8v;*/ ++ cap-mmc-highspeed; ++ non-removable; ++ max-frequency = <50000000>; ++ bus-width = <4>; ++ non-removable; ++ voltage-ranges = <1800 3300>; ++ ++ /* special property */ ++ ingenic,wp-gpios = <0>; ++ ingneic,cd-gpios = <0>; ++ ingenic,rst-gpios = <0>; ++}; ++ ++&msc1 { ++ status = "okay"; ++ pinctrl-names ="default","enable", "disable"; ++ pinctrl-0 = <&msc1_4bit>; ++ pinctrl-1 = <&rtc32k_enable>; ++ pinctrl-2 = <&rtc32k_disable>; ++ ++ max-frequency = <25000000>; ++ bus-width = <4>; ++ voltage-ranges = <1800 3300>; ++ /*non-removable;*/ ++ ++ ingenic,sdio_clk = <1>; ++ ingenic,poc-v1.8; ++ keep-power-in-suspend; ++ /* special property */ ++ ingenic,wp-gpios = <0>; ++ ingneic,cd-gpios = <0>; ++ ingenic,rst-gpios = <0>; ++ ingenic,removal-manual; /*removal-dontcare, removal-nonremovable, removal-removable, removal-manual*/ ++ ++ bcmdhd_wlan: bcmdhd_wlan { ++ compatible = "android,bcmdhd_wlan"; ++ ingenic,sdio-irq = <&gpd 1 IRQ_TYPE_LEVEL_HIGH INGENIC_GPIO_NOBIAS>; ++ ingenic,sdio-reset = <&gpd 0 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ }; ++}; ++ ++&cim { ++ status = "okay"; ++ port { ++ cim_0: endpoint@0 { ++ /*remote-endpoint = <&gc2155_0>;*/ ++ remote-endpoint = <&ov9281_0>; ++ bus-width = <8>; ++ }; ++ }; ++}; ++ ++&i2c4 { ++ status = "okay"; ++ clock-frequency = <100000>; ++ timeout = <1000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c4_pd>; ++ ++ ov9281: ov9281@0x60 { ++ status = "okay"; ++ compatible = "ovti,ov9281"; ++ reg = <0x60>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&cim_pd>; ++ ++ pwdn-gpios = <&gpc 1 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ vcc-en-gpios = <&gpc 3 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ ++ port { ++ ov9281_0: endpoint { ++ remote-endpoint = <&cim_0>; ++ }; ++ }; ++ }; ++ ++ gc2155: gc2155@0x3c { ++ status = "okay"; ++ compatible = "galaxycore,gc2155"; ++ reg = <0x3c>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&cim_pd>; ++ ++ resetb-gpios = <&gpb 13 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ pwdn-gpios = <&gpb 10 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ vcc-en-gpios = <&gpb 9 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ ++ port { ++ gc2155_0: endpoint { ++ remote-endpoint = <&cim_0>; ++ }; ++ }; ++ }; ++ ++ /* Audio */ ++ ak4458: dac@0x10 { ++ compatible = "asahi-kasei,ak4458"; ++ status = "okay"; ++ reg = <0x10>; ++ reset-gpios = <&gpd 7 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ xxmute-gpios = <&gpc 4 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ }; ++ ak5558: adc@0x13 { ++ compatible = "asahi-kasei,ak5558"; ++ status = "okay"; ++ reg = <0x13>; ++ reset-gpios = <&gpd 9 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ }; ++ ++}; ++ ++&dpu { ++ status = "okay"; ++ port { ++ dpu_out_ep: endpoint { ++ remote-endpoint = <&panel_kd035hvfmd057_ep>; ++ /*remote-endpoint = <&panel_kd035hvfbd037_ep>;*/ ++ }; ++ }; ++}; ++ ++/ { ++ display-dbi { ++ compatible = "simple-bus"; ++ #interrupt-cells = <1>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <>; ++ panel_byd9158B@0 { ++ compatible = "ingenic,byd9158B"; ++ status = "disable"; ++ ingenic,cs-gpio = <&gpb 26 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ ingenic,rst-gpio = <&gpb 25 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ }; ++ panel_kd035hvfmd057@0 { ++ compatible = "ingenic,kd035hvfmd057"; ++ status = "okay"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&tft_lcd_pb>; ++ ingenic,cs-gpio = <&gpc 5 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ ingenic,rst-gpio = <&gpb 11 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ ingenic,ssi-clk-gpio = <&gpc 2 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ ingenic,ssi-dt-gpio = <&gpc 4 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ ingenic,pwm-gpio = <&gpb 8 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ port { ++ panel_kd035hvfmd057_ep: endpoint { ++ remote-endpoint = <&dpu_out_ep>; ++ }; ++ }; ++ }; ++ panel_kd035hvfbd037@0 { ++ compatible = "ingenic,kd035hvfbd037"; ++ status = "disable"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&smart_lcd_pb>; ++ ingenic,cs-gpio = <&gpb 26 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ ingenic,rst-gpio = <&gpb 29 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ ingenic,pwm-gpio = <&gpb 8 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ ingenic,vdd-en-gpio = <&gpc 4 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ port { ++ panel_kd035hvfbd037_ep: endpoint { ++ remote-endpoint = <&dpu_out_ep>; ++ }; ++ }; ++ }; ++ }; ++ ++ ++ sound { ++ compatible = "ingenic,seal-sound"; ++ ingenic,model = "seal"; ++ }; ++ ++ extclk: extclk { ++ clock-frequency = <24000000>; ++ }; ++ ++ gpio_keys: gpio_keys { ++ compatible = "gpio-keys"; ++ ++ power { ++ label = "Power"; ++ linux,code = ; ++ gpios = <&gpf 31 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ gpio-key,wakeup; ++ }; ++ }; ++}; diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_shark.dts.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_shark.dts.patch new file mode 100644 index 00000000..9e7f1354 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_shark.dts.patch @@ -0,0 +1,309 @@ +diff -drupN a/arch/mips/boot/dts/ingenic/shark.dts b/arch/mips/boot/dts/ingenic/shark.dts +--- a/arch/mips/boot/dts/ingenic/shark.dts 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/boot/dts/ingenic/shark.dts 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,305 @@ ++/dts-v1/; ++ ++#include ++#include "t40.dtsi" ++#include ++ ++/ { ++ compatible = "ingenic,shark", "ingenic,t40"; ++ ++ mmc0_pwrseq: mmc0_pwrseq { ++ compatible = "mmc-pwrseq-simple"; ++ reset-gpios = <&gpd 22 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ }; ++}; ++ ++&uart0 { ++ status = "disable"; ++}; ++ ++&uart1 { ++ status = "okay"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart1_pb>; ++}; ++ ++&uart2 { ++ status = "disable"; ++}; ++ ++&i2c0 { ++ pinctrl-0 = <&i2c0_pa>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ ++&i2c1 { ++ pinctrl-0 = <&i2c1_pa>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ ++&i2c2 { ++ pinctrl-0 = <&i2c2_pc>; ++ pinctrl-names = "default"; ++ status = "disable"; ++}; ++ ++&i2c3 { ++ pinctrl-0 = <&i2c3_pa>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ ++&cpufreq { ++ status = "okay"; ++ operating-points = < ++ /*KHZ uV */ ++ 1200000 900000 ++ 750000 900000 ++ 600000 900000 ++ 500000 900000 ++ 400000 900000 ++ 375000 900000 ++ 300000 900000 ++ 200000 900000 ++ >; ++ ++}; ++ ++//&pwm { ++// ingenic,pwm-outputs = <0>; /* <0 - 15> select which pwms are really used */ ++//} ++ ++&pdma { ++ status = "okay"; ++}; ++ ++&msc0 { ++ status = "okay"; ++ pinctrl-names = "default"; ++ /*mmc-hs200-1_8v;*/ ++ cap-mmc-highspeed; ++ max-frequency = <25000000>; ++ bus-width = <4>; ++ voltage-ranges = <1800 3300>; ++ cd-inverted; ++ ++ /* special property */ ++ ingenic,wp-gpios = <0>; ++ ingenic,cd-gpios = <&gpc 6 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ ingenic,rst-gpios = <0>; ++ pinctrl-0 = <&msc0_pb>; ++ #mmc-pwrseq = <&mmc0_pwrseq>; ++}; ++ ++&msc1 { ++ status = "disable"; ++ pinctrl-names = "default"; ++ /*mmc-hs200-1_8v;*/ ++ cap-mmc-highspeed; ++ max-frequency = <50000000>; ++ bus-width = <4>; ++ voltage-ranges = <1800 3300>; ++ non-removable; ++ ++ /* special property */ ++ ingenic,wp-gpios = <0>; ++ ingenic,rst-gpios = <0>; ++ pinctrl-0 = <&msc1_pb>; ++}; ++ ++&mac0 { ++ pinctrl-names = "default", "reset"; ++ pinctrl-0 = <&mac0_rmii_p0_normal>, <&mac0_rmii_p1_normal>; ++ pinctrl-1 = <&mac0_rmii_p0_rst>, <&mac0_rmii_p1_normal>; ++ status = "okay"; ++ ingenic,rst-gpio = <&gpc 7 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ ingenic,rst-ms = <10>; ++ ingenic,mac-mode = ; ++ ingenic,mode-reg = <0xb00000e4>; ++ ingenic,phy-clk-freq = <50000000>; ++}; ++ ++&sfc { ++ status = "okay"; ++ pinctrl-names = "default"; ++ ingenic,sfc-max-frequency = <200000000>; ++ ingenic,use_board_info = /bits/ 8 <0>; ++ ingenic,spiflash_param_offset = <0>; ++ pinctrl-0 = <&sfc_pa>; ++}; ++ ++&spi0 { ++ status = "okay"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi0_pc>; ++ ++ spi-max-frequency = <48000000>; ++ num-cs = <2>; ++ cs-gpios = <0>, <0>; ++ ingenic,chnl = <0>; ++ ingenic,allow_cs_same = <1>; ++ ingenic,bus_num = <0>; ++ ingenic,has_dma_support = <1>; ++}; ++ ++&spi1 { ++ status = "disable"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi1_pb>; ++ ++ spi-max-frequency = <48000000>; ++ num-cs = <2>; ++ cs-gpios = <0>, <0>; ++ ingenic,chnl = <0>; ++ ingenic,allow_cs_same = <1>; ++ ingenic,bus_num = <1>; ++ ingenic,has_dma_support = <1>; ++}; ++ ++&dtrng { ++ status = "okay"; ++}; ++ ++&otg { ++ g-use-dma; ++ dr_mode = "otg"; ++ status = "okay"; ++}; ++ ++&otg_phy { ++ dr_mode = "otg"; ++ compatible = "ingenic,innophy", "syscon"; ++ ingenic,drvvbus-gpio = <&gpb 27 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ status = "okay"; ++}; ++ ++/ { ++ ++ extclk: extclk { ++ clock-frequency = <24000000>; ++ }; ++ ++ gpio_keys: gpio_keys { ++ compatible = "gpio-keys"; ++ ++ power { ++ label = "Power"; ++ linux,code = ; ++ gpios = <&gpa 31 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ gpio-key,wakeup; ++ }; ++ bootsel0 { ++ label = "bootsel0"; ++ linux,code = ; ++ gpios = <&gpc 0 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ }; ++ ++ bootsel1 { ++ label = "bootsel1"; ++ linux,code = ; ++ gpios = <&gpc 1 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ }; ++ ++ }; ++}; ++ ++&el150 { ++ status = "disable"; ++}; ++ ++&dpu { ++ status = "okay"; ++}; ++ ++/ { ++ display-dpi { ++ compatible = "simple-bus"; ++ #interrupt-cells = <1>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <>; ++ panel_bm8766@0 { ++ compatible = "ingenic,bm8766"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&tft_lcd_pd>; ++ ingenic,bl-gpio = <&gpb 25 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ status = "okay"; ++ }; ++ ++ }; ++}; ++ ++/ { ++ display-dbi { ++ compatible = "simple-bus"; ++ #interrupt-cells = <1>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <>; ++ panel_truly240240@0 { ++ compatible = "ingenic,truly240240"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&smart_lcd_pd>; ++ /*ingenic,rst-gpio = <&gpc 7 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>;*/ ++ ingenic,rst-gpio = <&gpd 9 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ ingenic,rd-gpio = <&gpd 12 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ ingenic,cs-gpio = <&gpd 10 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ status = "okay"; ++ }; ++ ++ panel_st7789v240320@0 { ++ compatible = "ingenic,st7789v240320"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&smart_lcd_pd>; ++ /*ingenic,rst-gpio = <&gpc 7 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>;*/ ++ ingenic,rst-gpio = <&gpd 9 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ ingenic,rd-gpio = <&gpd 12 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ ingenic,cs-gpio = <&gpd 10 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ ingenic,bl-gpio = <&gpd 27 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ status = "okay"; ++ }; ++ ++ }; ++}; ++ ++/ { ++ display-dsi { ++ compatible = "simple-bus"; ++ #interrupt-cells = <1>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <>; ++ panel_ek79007@0 { ++ compatible = "ingenic,ek79007"; ++ ingenic,bl-gpio = <&gpd 26 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ // ingenic,rst-gpio = <&gpd 17 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ status = "okay"; ++ }; ++ ++ panel_st7703@0 { ++ compatible = "ingenic,st7703"; ++ ingenic,bl-gpio = <&gpb 25 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ ingenic,rst-gpio = <&gpc 22 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ status = "okay"; ++ }; ++ ++ panel_ma0060@0 { ++ compatible = "ingenic,ma0060"; ++ ingenic,vdd-en-gpio = <&gpd 22 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ ingenic,rst-gpio = <&gpd 23 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ ingenic,lcd-pwm-gpio = <&gpd 25 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ status = "okay"; ++ }; ++ ++ panel_MTF070@0 { ++ compatible = "ingenic,mtf070"; ++ status = "okay"; ++ ingenic,bl-gpio = <&gpc 4 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ ingenic,rst-gpio = <&gpb 28 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ ingenic,pw-gpio = <&gpb 29 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ }; ++ }; ++ ++}; diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_shark_fast.dts.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_shark_fast.dts.patch new file mode 100644 index 00000000..fa29bbcc --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_shark_fast.dts.patch @@ -0,0 +1,295 @@ +diff -drupN a/arch/mips/boot/dts/ingenic/shark_fast.dts b/arch/mips/boot/dts/ingenic/shark_fast.dts +--- a/arch/mips/boot/dts/ingenic/shark_fast.dts 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/boot/dts/ingenic/shark_fast.dts 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,291 @@ ++/dts-v1/; ++ ++#include ++#include "t40.dtsi" ++#include ++ ++/ { ++ compatible = "ingenic,shark", "ingenic,t40"; ++ ++ mmc0_pwrseq: mmc0_pwrseq { ++ compatible = "mmc-pwrseq-simple"; ++ reset-gpios = <&gpd 22 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ }; ++}; ++ ++&uart0 { ++ status = "disable"; ++}; ++ ++&uart1 { ++ status = "okay"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart1_pb>; ++}; ++ ++&uart2 { ++ status = "disable"; ++}; ++ ++&i2c0 { ++ pinctrl-0 = <&i2c0_pa>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ ++&i2c1 { ++ pinctrl-0 = <&i2c1_pa>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ ++&i2c2 { ++ pinctrl-0 = <&i2c2_pc>; ++ pinctrl-names = "default"; ++ status = "disable"; ++}; ++ ++&i2c3 { ++ pinctrl-0 = <&i2c3_pa>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ ++&cpufreq { ++ status = "okay"; ++ operating-points = < ++ /*KHZ uV */ ++ 1200000 900000 ++ 750000 900000 ++ 600000 900000 ++ 500000 900000 ++ 400000 900000 ++ 375000 900000 ++ 300000 900000 ++ 200000 900000 ++ >; ++ ++}; ++ ++//&pwm { ++// ingenic,pwm-outputs = <0>; /* <0 - 15> select which pwms are really used */ ++//} ++ ++&pdma { ++ status = "okay"; ++}; ++ ++&msc0 { ++ status = "okay"; ++ pinctrl-names = "default"; ++ /*mmc-hs200-1_8v;*/ ++ cap-mmc-highspeed; ++ max-frequency = <25000000>; ++ bus-width = <4>; ++ voltage-ranges = <1800 3300>; ++ cd-inverted; ++ ++ /* special property */ ++ ingenic,wp-gpios = <0>; ++ ingenic,cd-gpios = <&gpc 6 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ ingenic,rst-gpios = <0>; ++ pinctrl-0 = <&msc0_pb>; ++ mmc-pwrseq = <&mmc0_pwrseq>; ++}; ++ ++&msc1 { ++ status = "disable"; ++ pinctrl-names = "default"; ++ /*mmc-hs200-1_8v;*/ ++ cap-mmc-highspeed; ++ max-frequency = <50000000>; ++ bus-width = <4>; ++ voltage-ranges = <1800 3300>; ++ non-removable; ++ ++ /* special property */ ++ ingenic,wp-gpios = <0>; ++ ingenic,rst-gpios = <0>; ++ pinctrl-0 = <&msc1_pb>; ++}; ++ ++&mac0 { ++ pinctrl-names = "default", "reset"; ++ pinctrl-0 = <&mac0_rmii_p0_normal>, <&mac0_rmii_p1_normal>; ++ pinctrl-1 = <&mac0_rmii_p0_rst>, <&mac0_rmii_p1_normal>; ++ status = "okay"; ++ ingenic,rst-gpio = <0>;//<&gpc 7 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ ingenic,rst-ms = <10>; ++ ingenic,mac-mode = ; ++ ingenic,mode-reg = <0xb00000e4>; ++ ingenic,phy-clk-freq = <50000000>; ++}; ++ ++&sfc { ++ status = "okay"; ++ pinctrl-names = "default"; ++ ingenic,sfc-max-frequency = <200000000>; ++ ingenic,use_board_info = /bits/ 8 <0>; ++ ingenic,spiflash_param_offset = <0>; ++ pinctrl-0 = <&sfc_pa>; ++}; ++ ++&spi0 { ++ status = "okay"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi0_pc>; ++ ++ spi-max-frequency = <48000000>; ++ num-cs = <2>; ++ cs-gpios = <0>, <0>; ++ ingenic,chnl = <0>; ++ ingenic,allow_cs_same = <1>; ++ ingenic,bus_num = <0>; ++ ingenic,has_dma_support = <1>; ++}; ++ ++&dtrng { ++ status = "okay"; ++}; ++ ++&otg { ++ g-use-dma; ++ dr_mode = "otg"; ++ status = "okay"; ++}; ++ ++&otg_phy { ++ dr_mode = "otg"; ++ compatible = "ingenic,innophy", "syscon"; ++ ingenic,drvvbus-gpio = <&gpb 27 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ status = "okay"; ++}; ++ ++/ { ++ ++ extclk: extclk { ++ clock-frequency = <24000000>; ++ }; ++ ++ gpio_keys: gpio_keys { ++ compatible = "gpio-keys"; ++ ++ power { ++ label = "Power"; ++ linux,code = ; ++ gpios = <&gpa 31 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ gpio-key,wakeup; ++ }; ++ bootsel0 { ++ label = "bootsel0"; ++ linux,code = ; ++ gpios = <&gpc 0 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ }; ++ ++ bootsel1 { ++ label = "bootsel1"; ++ linux,code = ; ++ gpios = <&gpc 1 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ }; ++ ++ }; ++}; ++ ++&el150 { ++ status = "disable"; ++}; ++ ++&dpu { ++ status = "okay"; ++}; ++ ++/ { ++ display-dpi { ++ compatible = "simple-bus"; ++ #interrupt-cells = <1>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <>; ++ panel_bm8766@0 { ++ compatible = "ingenic,bm8766"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&tft_lcd_pd>; ++ ingenic,bl-gpio = <&gpb 25 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ status = "okay"; ++ }; ++ ++ }; ++}; ++ ++/ { ++ display-dbi { ++ compatible = "simple-bus"; ++ #interrupt-cells = <1>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <>; ++ panel_truly240240@0 { ++ compatible = "ingenic,truly240240"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&smart_lcd_pd>; ++ /*ingenic,rst-gpio = <&gpc 7 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>;*/ ++ ingenic,rst-gpio = <&gpd 9 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ ingenic,rd-gpio = <&gpd 12 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ ingenic,cs-gpio = <&gpd 10 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ status = "okay"; ++ }; ++ ++ panel_st7789v240320@0 { ++ compatible = "ingenic,st7789v240320"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&smart_lcd_pd>; ++ /*ingenic,rst-gpio = <&gpc 7 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>;*/ ++ ingenic,rst-gpio = <&gpd 9 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ ingenic,rd-gpio = <&gpd 12 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ ingenic,cs-gpio = <&gpd 10 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ ingenic,bl-gpio = <&gpd 27 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ status = "okay"; ++ }; ++ ++ }; ++}; ++ ++/ { ++ display-dsi { ++ compatible = "simple-bus"; ++ #interrupt-cells = <1>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <>; ++ panel_ek79007@0 { ++ compatible = "ingenic,ek79007"; ++ ingenic,bl-gpio = <&gpd 26 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ // ingenic,rst-gpio = <&gpd 17 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ status = "okay"; ++ }; ++ ++ panel_st7703@0 { ++ compatible = "ingenic,st7703"; ++ ingenic,bl-gpio = <&gpb 25 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ ingenic,rst-gpio = <&gpc 22 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ status = "okay"; ++ }; ++ ++ panel_ma0060@0 { ++ compatible = "ingenic,ma0060"; ++ ingenic,vdd-en-gpio = <&gpd 22 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ ingenic,rst-gpio = <&gpd 23 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ ingenic,lcd-pwm-gpio = <&gpd 25 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ status = "okay"; ++ }; ++ ++ panel_MTF070@0 { ++ compatible = "ingenic,mtf070"; ++ status = "okay"; ++ ingenic,bl-gpio = <&gpc 4 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ ingenic,rst-gpio = <&gpb 28 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ ingenic,pw-gpio = <&gpb 29 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ }; ++ }; ++ ++}; diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_t40-pinctrl.dtsi.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_t40-pinctrl.dtsi.patch new file mode 100644 index 00000000..d420f0e8 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_t40-pinctrl.dtsi.patch @@ -0,0 +1,268 @@ +diff -drupN a/arch/mips/boot/dts/ingenic/t40-pinctrl.dtsi b/arch/mips/boot/dts/ingenic/t40-pinctrl.dtsi +--- a/arch/mips/boot/dts/ingenic/t40-pinctrl.dtsi 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/boot/dts/ingenic/t40-pinctrl.dtsi 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,264 @@ ++#include ++ ++&pinctrl { ++ uart0_pin: uart0-pin { ++ uart0_pc: uart0-pc { ++ ingenic,pinmux = <&gpc 2 5>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ uart0_pa: uart0-pa { ++ ingenic,pinmux = <&gpa 10 11>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ uart0_pc1: uart0-pc1 { ++ ingenic,pinmux = <&gpc 14 15>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ uart1_pin: uart1-pin { ++ uart1_pb: uart1-pb { ++ ingenic,pinmux = <&gpb 23 24>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ uart1_pa: uart1-pa { ++ ingenic,pinmux = <&gpa 17 18>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ uart2_pin: uart2-pin { ++ uart2_pc: uart2-pc { ++ ingenic,pinmux = <&gpc 18 19>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ uart2_pb: uart2-pb { ++ ingenic,pinmux = <&gpb 28 29>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ uart2_pa: uart2-pa { ++ ingenic,pinmux = <&gpa 6 7>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ uart3_pin: uart3-pin { ++ uart3_pc: uart3-pc { ++ ingenic,pinmux = <&gpc 6 7>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ uart3_pd: uart3-pd { ++ ingenic,pinmux = <&gpd 22 25>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ uart3_pa: uart3-pa { ++ ingenic,pinmux = <&gpa 2 3>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ i2c0_pin: i2c0-pin { ++ i2c0_pa: i2c0-pa { ++ ingenic,pinmux = <&gpa 12 13>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ i2c0_pc: i2c0-pc { ++ ingenic,pinmux = <&gpc 16 17>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ i2c1_pin: i2c1-pin { ++ i2c1_pa: i2c1-pa { ++ ingenic,pinmux = <&gpa 17 18>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ i2c1_pb: i2c1-pb { ++ ingenic,pinmux = <&gpb 17 18>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ i2c1_pd: i2c1-pd { ++ ingenic,pinmux = <&gpd 26 27>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ i2c2_pin: i2c2-pin { ++ i2c2_pc: i2c2-pc { ++ ingenic,pinmux = <&gpc 14 15>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ i2c2_pb: i2c2-pb { ++ ingenic,pinmux = <&gpb 25 26>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ i2c3_pin: i2c3-pin { ++ i2c3_pb: i2c3-pb { ++ ingenic,pinmux = <&gpb 28 29>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ i2c3_pb1: i2c3-pb1 { ++ ingenic,pinmux = <&gpb 20 21>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ i2c3_pa: i2c3-pa { ++ ingenic,pinmux = <&gpa 21 22>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ msc0_pin: msc0-pin { ++ msc0_pb: msc0-pb { ++ ingenic,pinmux = <&gpb 0 5>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ msc1_pin: msc1-pin { ++ msc1_pb: msc1-pb { ++ ingenic,pinmux = <&gpb 17 22>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ msc1_pc: msc1-pc { ++ ingenic,pinmux = <&gpc 8 13>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ mac0_rmii_p0: mac0-rmii-p0 { ++ mac0_rmii_p0_normal: mac0-rmii-normal { ++ ingenic,pinmux = <&gpb 15 16>, <&gpb 9 9>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ mac0_rmii_p0_rst: mac0-rmii-p0-rst { ++ ingenic,pinmux = <&gpb 15 16>, <&gpb 9 9>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ mac0_rmii_p1: mac0-rmii-p1 { ++ mac0_rmii_p1_normal: mac0-rmii-p1-normal { ++ ingenic,pinmux = <&gpb 7 7>, <&gpb 13 14>, <&gpb 8 8>, <&gpb 10 11>, <&gpb 6 6>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ ++ mac0_rmii_p1_nomdio: mac0-rmii-p1-nomdio { ++ ingenic,pinmux = <&gpb 7 7>, <&gpb 13 14>, <&gpb 8 8>, <&gpb 6 6>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ ++ pwm_pin: pwm-pin{ ++ pwm_pc: pwm-pc{ ++ ingenic,pinmux = <&gpc 2 7>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ sfc_pin: sfc-pin { ++ sfc_pa: sfc-pa { ++ ingenic,pinmux = <&gpa 23 28>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ vic_pin: vic-pin { ++ vic_pa_low_10bit: vic-pa-low-10bit { ++ ingenic,pinmux = <&gpa 0 9>, <&gpa 12 14>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ vic_pa_high_10bit: vic-pa-high-10bit { ++ ingenic,pinmux = <&gpa 2 14>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ vic_pa_12bit: vic-pa-12bit { ++ ingenic,pinmux = <&gpa 0 14>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ cim_vic_mclk: cim-vic-mclk { ++ cim0_vic_mclk_pc: cim0-vic-mclk-pc { ++ ingenic,pinmux = <&gpc 31 31>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ cim1_vic_mclk_pc: cim1-vic-mclk-pc { ++ ingenic,pinmux = <&gpc 30 30>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ cim2_vic_mclk_pc: cim2-vic-mclk-pc { ++ ingenic,pinmux = <&gpc 29 29>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ lcd_pins: lcd-pins { ++ tft_lcd_pd: tft-lcd-pd { ++ ingenic,pinmux = <&gpd 0 21>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ ++ smart_lcd_pd: smart-lcd-pd { ++ ingenic,pinmux = <&gpd 0 8>, <&gpd 11 11>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ dmic_pc: dmic-pc { ++ ingenic,pinmux = <&gpc 24 26>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ ++ spi0_pc: spi0-pc { ++ ingenic,pinmux = <&gpc 2 5>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ ++ spi1_pin: spi1_pin { ++ spi1_pb: spi1-pb { ++ ingenic,pinmux = <&gpb 25 30>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ spi1_pc: spi1-pc { ++ ingenic,pinmux = <&gpc 8 13>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ pwm_pins: pwm-pins { ++ pwm0_pc: pwm0_pc { ++ ingenic,pinmux = <&gpc 2 2>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ pwm1_pc: pwm1_pc { ++ ingenic,pinmux = <&gpc 3 3>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ pwm2_pc: pwm2_pc { ++ ingenic,pinmux = <&gpc 4 4>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ pwm3_pc: pwm3_pc { ++ ingenic,pinmux = <&gpc 5 5>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ pwm4_pc: pwm4_pc { ++ ingenic,pinmux = <&gpc 6 6>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ pwm5_pc: pwm5_pc { ++ ingenic,pinmux = <&gpc 7 7>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ pwm6_pd: pwm6_pd { ++ ingenic,pinmux = <&gpd 22 22>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ pwm7_pd: pwm7_pd { ++ ingenic,pinmux = <&gpd 23 23>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++}; ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_t40.dtsi.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_t40.dtsi.patch new file mode 100644 index 00000000..bd71239c --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_t40.dtsi.patch @@ -0,0 +1,559 @@ +diff -drupN a/arch/mips/boot/dts/ingenic/t40.dtsi b/arch/mips/boot/dts/ingenic/t40.dtsi +--- a/arch/mips/boot/dts/ingenic/t40.dtsi 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/boot/dts/ingenic/t40.dtsi 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,555 @@ ++#include ++#include ++#include ++#include ++#include ++ ++/ { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "ingenic,t40"; ++ ++ aliases: aliases { ++ i2c0 = &i2c0; ++ i2c1 = &i2c1; ++ i2c2 = &i2c2; ++ i2c3 = &i2c3; ++ uart0 = &uart0; ++ uart1 = &uart1; ++ uart2 = &uart2; ++ uart3 = &uart3; ++ msc0 = &msc0; ++ msc1 = &msc1; ++ mac0 = &mac0; ++ spi0 = &spi0; ++ spi1 = &spi1; ++ bscaler0 = &bscaler0; ++ }; ++ ++ cpus: cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cpu0: cpu@0 { ++ device_type = "cpu"; ++ compatible = "ingenic,xburst2"; ++ reg = <0x000>; ++ clock-frequency = <800000000>; ++ }; ++ ++ cpu1: cpu@1 { ++ device_type = "cpu"; ++ compatible = "ingenic,xburst2"; ++ reg = <0x001>; ++ clock-frequency = <800000000>; ++ }; ++ }; ++ ++ cpufreq: cpufreq-dt { ++ compatible = "ingenic,t40-cpufreq"; ++ status = "okay"; ++ }; ++ ++ cpuintc: interrupt-controller { ++ #address-cells = <0>; ++ #interrupt-cells = <1>; ++ interrupt-controller; ++ compatible = "ingenic,cpu-interrupt-controller"; ++ ++ }; ++ ++ core_intc: core-intc@0x12300000 { ++ compatible = "ingenic,core-intc"; ++ reg = <0x12300000 0x1000>; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ cpu-intc-map = <0 0x000>, ++ <1 0x100>, ++ <2 0x200>, ++ <3 0x300>; ++ ++ interrupt-parent = <&cpuintc>; ++ interrupts = ; ++ interrupt-names ="intc"; ++ }; ++ ++ core_ost: core-ost@0x12000000 { ++ compatible = "ingenic,core-ost"; ++ reg = <0x12000000 0x10000>, /*Global ost*/ ++ <0x12100000 0x10000>; /*Core ost*/ ++ interrupt-parent = <&cpuintc>; ++ interrupt-names = "sys_ost"; ++ interrupts = ; ++ cpu-ost-map = <0 0x000>, ++ <1 0x100>; ++ }; ++ ++ extclk: extclk { ++ compatible = "ingenic,fixed-clock"; ++ clock-output-names ="ext"; ++ #clock-cells = <0>; ++ clock-frequency = <24000000>; ++ }; ++ ++ rtcclk: rtcclk { ++ compatible = "ingenic,fixed-clock"; ++ clock-output-names ="rtc_ext"; ++ #clock-cells = <0>; ++ clock-frequency = <32768>; ++ }; ++ ++ clock: clock-controller@0x10000000 { ++ compatible = "ingenic,t40-clocks"; ++ reg = <0x10000000 0x100>; ++ clocks = <&extclk>, <&rtcclk>; ++ clock-names = "ext", "rtc_ext"; ++ #clock-cells = <1>; ++ little-endian; ++ }; ++ ++ apb { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <>; ++ tcu: tcu@0x10002000 { ++ compatible = "ingenic,tcu"; ++ reg = <0x10002000 0x140>; ++ interrupt-parent = <&core_intc>; ++ interrupt-names = "tcu_int0", "tcu_int1", "tcu_int2"; ++ interrupts = ; ++ interrupt-controller; ++ status = "ok"; ++ ++ channel0: channel0 { ++ compatible = "ingenic,tcu_chn0"; ++ ingenic,channel-info = ; ++ }; ++ channel1: channel1 { ++ compatible = "ingenic,tcu_chn1"; ++ ingenic,channel-info = ; ++ }; ++ channel2: channel2 { ++ compatible = "ingenic,tcu_chn2"; ++ ingenic,channel-info = ; ++ }; ++ channel3: channel3 { ++ compatible = "ingenic,tcu_chn3"; ++ ingenic,channel-info = ; ++ }; ++ channel4: channel4 { ++ compatible = "ingenic,tcu_chn4"; ++ ingenic,channel-info = ; ++ }; ++ channel5: channel5 { ++ compatible = "ingenic,tcu_chn5"; ++ ingenic,channel-info = ; ++ }; ++ channel6: channel6 { ++ compatible = "ingenic,tcu_chn6"; ++ ingenic,channel-info = ; ++ }; ++ channel7: channel7 { ++ compatible = "ingenic,tcu_chn7"; ++ ingenic,channel-info = ; ++ }; ++ channel15: channel15 { ++ compatible = "ingenic,tcu_chn15"; ++ ingenic,channel-info = ; ++ }; ++ channel16: channel16 { ++ compatible = "ingenic,watchdog"; ++ ingenic,channel-info = ; ++ }; ++ }; ++ ++ sadc: sadc@10070000 { ++ compatible = "ingenic,sadc"; ++ reg = <0x10070000 0x32>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ status = "okay"; ++ }; ++ ++ watchdog: watchdog@0x10002000 { ++ compatible = "ingenic,watchdog"; ++ reg = <0x10002000 0x40>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ ++ pinctrl: pinctrl@0x10010000 { ++ compatible = "ingenic,t40-pinctrl"; ++ reg = <0x10010000 0x1000>; ++ ingenic,num-chips = <6>; ++ ingenic,regs-offset = <0x100>; ++ ++ gpa: gpa { ++ gpio-controller; ++ #gpio-cells = <3>; ++ #ingenic,pincfg-cells = <3>; ++ #ingenic,pinmux-cells = <2>; ++ interrupts = ; ++ interrupt-parent = <&core_intc>; ++ interrupt-controller; ++ #interrupt-cells = <3>; ++ ingenic,num-gpios = <32>; ++ ingenic,pull-gpios-low = <0x55555555>; ++ ingenic,pull-gpios-high = <0x55555555>; ++ }; ++ ++ gpb: gpb { ++ gpio-controller; ++ #gpio-cells = <3>; ++ #ingenic,pincfg-cells = <3>; ++ #ingenic,pinmux-cells = <2>; ++ interrupts = ; ++ interrupt-parent = <&core_intc>; ++ interrupt-controller; ++ #interrupt-cells = <3>; ++ ingenic,num-gpios = <32>; ++ ingenic,pull-gpios-low = <0x55555555>; ++ ingenic,pull-gpios-high = <0x55555555>; ++ }; ++ ++ gpc: gpc { ++ gpio-controller; ++ #gpio-cells = <3>; ++ #ingenic,pincfg-cells = <3>; ++ #ingenic,pinmux-cells = <2>; ++ interrupts = ; ++ interrupt-parent = <&core_intc>; ++ interrupt-controller; ++ #interrupt-cells = <3>; ++ ingenic,num-gpios = <32>; ++ ingenic,pull-gpios-low = <0x55555555>; ++ ingenic,pull-gpios-high = <0x55555555>; ++ }; ++ ++ gpd: gpd { ++ gpio-controller; ++ #gpio-cells = <3>; ++ #ingenic,pincfg-cells = <3>; ++ #ingenic,pinmux-cells = <2>; ++ interrupts = ; ++ interrupt-parent = <&core_intc>; ++ interrupt-controller; ++ #interrupt-cells = <3>; ++ ingenic,num-gpios = <32>; ++ ingenic,pull-gpios-low = <0x55555555>; ++ ingenic,pull-gpios-high = <0x55555555>; ++ }; ++ ++ }; ++ ++ uart0: serial@0x10030000 { ++ compatible = "ingenic,8250-uart"; ++ reg = <0x10030000 0x1000>; ++ reg-shift = <2>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart0_pc>; ++ status = "disabled"; ++ }; ++ uart1: serial@0x10031000 { ++ compatible = "ingenic,8250-uart"; ++ reg = <0x10031000 0x1000>; ++ reg-shift = <2>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart1_pb>; ++ status = "disabled"; ++ }; ++ uart2: serial@0x10032000 { ++ compatible = "ingenic,8250-uart"; ++ reg = <0x10032000 0x1000>; ++ reg-shift = <2>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart2_pc>; ++ status = "disabled"; ++ }; ++ uart3: serial@0x10033000 { ++ compatible = "ingenic,8250-uart"; ++ reg = <0x10033000 0x1000>; ++ reg-shift = <2>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart3_pc>; ++ status = "disabled"; ++ }; ++ ++ i2c0: i2c@0x10050000 { ++ compatible = "ingenic,t40-i2c"; ++ reg = <0x10050000 0x1000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ }; ++ ++ i2c1: i2c@0x10051000 { ++ compatible = "ingenic,t40-i2c"; ++ reg = <0x10051000 0x1000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ }; ++ ++ i2c2: i2c@0x10052000 { ++ compatible = "ingenic,t40-i2c"; ++ reg = <0x10052000 0x1000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i2c3: i2c@0x10053000 { ++ compatible = "ingenic,t40-i2c"; ++ reg = <0x10053000 0x1000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ spi0: spi0@0x10043000 { ++ compatible = "ingenic,spi"; ++ reg = <0x10043000 0x1000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ dmas = <&pdma INGENIC_DMA_TYPE(INGENIC_DMA_REQ_SSI0_TX)>, ++ <&pdma INGENIC_DMA_TYPE(INGENIC_DMA_REQ_SSI0_RX)>; ++ dma-names = "tx", "rx"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ spi1: spi1@0x10044000 { ++ compatible = "ingenic,spi"; ++ reg = <0x10044000 0x1000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ dmas = <&pdma INGENIC_DMA_TYPE(INGENIC_DMA_REQ_SSI1_TX)>, ++ <&pdma INGENIC_DMA_TYPE(INGENIC_DMA_REQ_SSI1_RX)>; ++ dma-names = "tx", "rx"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ dtrng: dtrng@0x10072000 { ++ compatible = "ingenic,dtrng"; ++ reg = <0x10072000 0x100>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ ++ des: des@0x10061000 { ++ compatible = "ingenic,des"; ++ reg = <0x10043000 0x1000>; ++ dmas = <&pdma INGENIC_DMA_TYPE(INGENIC_DMA_REQ_DES_TX)>, ++ <&pdma INGENIC_DMA_TYPE(INGENIC_DMA_REQ_DES_RX)>; ++ dma-names = "tx", "rx"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ }; ++ ++ otg_phy: otg_phy { ++ compatible = "ingenic,innophy"; ++ reg = <0x10000000 0x1000 0x10060000 0x1000>; ++ }; ++ }; ++ ++ ahb2 { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <>; ++ ++ aes: aes@0x13430000 { ++ compatible = "ingenic,aes"; ++ reg = <0x13430000 0x10000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ status = "okay"; ++ }; ++ ++ hash: hash@0x13480000 { ++ compatible = "ingenic,hash"; ++ reg = <0x13480000 0x10000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ status = "okay"; ++ }; ++ ++ rsa: rsa@0x134c0000 { ++ compatible = "ingenic,rsa"; ++ reg = <0x134c0000 0x10000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ status = "okay"; ++ }; ++ ++ mac0: mac@0x134b0000 { ++ compatible = "ingenic,t40-mac"; ++ reg = <0x134b0000 0x2000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ status = "disabled"; ++ ingenic,rst-ms = <10>; ++ }; ++ ++ sfc: sfc@0x13440000 { ++ compatible = "ingenic,sfc"; ++ reg = <0x13440000 0x10000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sfc_pa>; ++ status = "disabled"; ++ }; ++ ++ pdma: dma@13420000 { ++ compatible = "ingenic,t40-pdma"; ++ reg = <0x13420000 0x10000>; ++ interrupt-parent = <&core_intc>; ++ interrupt-names = "pdma", "pdmam"; ++ interrupts = , ; ++ #dma-channels = <32>; ++ #dma-cells = <1>; ++ ingenic,reserved-chs = <0x3>; ++ }; ++ ++ otg: otg@0x13500000 { ++ compatible = "ingenic,dwc2-hsotg"; ++ reg = <0x13500000 0x40000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ ingenic,usbphy=<&otg_phy>; ++ status = "disabled"; ++ }; ++ ++ efuse: efuse@0x13540000 { ++ compatible = "ingenic,t40-efuse"; ++ reg = <0x13540000 0x10000>; ++ status = "okay"; ++ }; ++ }; ++ ++ ahb1 { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <>; ++ ++ el150: el150@0x13200000 { ++ compatible = "ingenic,t40-el150"; ++ reg = <0x13200000 0x100000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ ++ }; ++ ++ ahb0 { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <>; ++ ++ dpu: dpu@0x13050000 { ++ compatible = "ingenic,t40-dpu"; ++ reg = <0x13050000 0x10000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ ++ msc0: msc@0x13060000 { ++ compatible = "ingenic,sdhci"; ++ reg = <0x13060000 0x10000>; ++ status = "disabled"; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ pinctrl-names ="default"; ++ pinctrl-0 = <&msc0_4bit>; ++ }; ++ ++ msc1: msc@0x13070000 { ++ compatible = "ingenic,sdhci"; ++ reg = <0x13070000 0x10000>; ++ status = "disabled"; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ pinctrl-names ="default"; ++ pinctrl-0 = <&msc1_4bit>; ++ }; ++ ++ ipu: ipu@0x13080000 { ++ compatible = "ingenic,t40-ipu"; ++ reg = <0x13080000 0x10000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ status = "okay"; ++ }; ++ ++ drawbox: drawbox@0x130d0000 { ++ compatible = "ingenic,t40-drawbox"; ++ reg = <0x130d0000 0x10000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ status = "okay"; ++ }; ++ ++ i2d: i2d@0x130b0000 { ++ compatible = "ingenic,t40-i2d"; ++ reg = <0x130b0000 0x10000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ status = "okay"; ++ }; ++ ++ isp: isp@0x13300000 { ++ compatible = "ingenic,t40-isp"; ++ reg = <0x13300000 0x100000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ ++ bscaler0: bscaler@0x13090000 { ++ compatible = "ingenic,t40-bscaler"; ++ reg = <0x13090000 0x100>; ++ interrupt-parent = <&core_intc>; ++ interrupts = , ++ ; ++ status = "okay"; ++ }; ++ }; ++ ++}; ++#include "t40-pinctrl.dtsi" diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_t40_fpga.dts.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_t40_fpga.dts.patch new file mode 100644 index 00000000..ef6c47d7 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_t40_fpga.dts.patch @@ -0,0 +1,129 @@ +diff -drupN a/arch/mips/boot/dts/ingenic/t40_fpga.dts b/arch/mips/boot/dts/ingenic/t40_fpga.dts +--- a/arch/mips/boot/dts/ingenic/t40_fpga.dts 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/boot/dts/ingenic/t40_fpga.dts 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,125 @@ ++/dts-v1/; ++ ++#include ++#include "t40.dtsi" ++ ++/ { ++ compatible = "img,fpga", "ingenic,t40"; ++}; ++ ++&uart0 { ++ status = "okay"; ++}; ++ ++&uart1 { ++ status = "disable"; ++}; ++ ++&uart2 { ++ status = "disable"; ++}; ++ ++ ++//&pwm { ++// ingenic,pwm-outputs = <0>; /* <0 - 15> select which pwms are really used */ ++//} ++ ++ ++&msc0 { ++ status = "disable"; ++ /*mmc-hs200-1_8v;*/ ++ cap-mmc-highspeed; ++ non-removable; ++ max-frequency = <50000000>; ++ bus-width = <4>; ++ non-removable; ++ voltage-ranges = <1800 3300>; ++ ++ /* special property */ ++ ingenic,wp-gpios = <0>; ++ ingneic,cd-gpios = <0>; ++ ingenic,rst-gpios = <0>; ++}; ++ ++&msc1 { ++ status = "okay"; ++ /*mmc-hs200-1_8v;*/ ++ cap-mmc-highspeed; ++ non-removable; ++ max-frequency = <50000000>; ++ bus-width = <4>; ++ non-removable; ++ voltage-ranges = <1800 3300>; ++ ++ /* special property */ ++ ingenic,wp-gpios = <0>; ++ ingneic,cd-gpios = <0>; ++ ingenic,rst-gpios = <0>; ++}; ++ ++&mac0 { ++ pinctrl-names = "default", "reset"; ++ pinctrl-0 = <&mac0_rmii_p0_normal>, <&mac0_rmii_p1_normal>; ++ pinctrl-1 = <&mac0_rmii_p0_rst>, <&mac0_rmii_p1_normal>; ++ status = "okay"; ++ ingenic,rst-gpio = <&gpb 0 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ ingenic,rst-ms = <10>; ++ ingenic,mac-mode = ; ++ ingenic,mode-reg = <0xb00000e4>; ++}; ++ ++&sfc { ++ status = "okay"; ++ ingenic,sfc-max-frequency = <150000000>; ++ ingenic,use_board_info = /bits/ 8 <0>; ++ ingenic,spiflash_param_offset = <0>; ++}; ++ ++ ++/ { ++ ++ extclk: extclk { ++ clock-frequency = <24000000>; ++ }; ++ ++ gpio_keys: gpio_keys { ++ compatible = "gpio-keys"; ++ ++ power { ++ label = "Power"; ++ linux,code = ; ++ gpios = <&gpa 31 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ gpio-key,wakeup; ++ }; ++ }; ++}; ++ ++&radix { ++ status = "disable"; ++}; ++ ++&el150 { ++ status = "disable"; ++}; ++ ++&dpu { ++ status = "okay"; ++}; ++ ++/ { ++ display-dbi { ++ compatible = "simple-bus"; ++ #interrupt-cells = <1>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <>; ++ panel_bm8766@0 { ++ compatible = "ingenic,bm8766"; ++ status = "okay"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&tft_lcd_pb>; ++ }; ++ }; ++ ++ ++}; diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_x2000-v12-pinctrl.dtsi.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_x2000-v12-pinctrl.dtsi.patch new file mode 100644 index 00000000..18a654fd --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_x2000-v12-pinctrl.dtsi.patch @@ -0,0 +1,512 @@ +diff -drupN a/arch/mips/boot/dts/ingenic/x2000-v12-pinctrl.dtsi b/arch/mips/boot/dts/ingenic/x2000-v12-pinctrl.dtsi +--- a/arch/mips/boot/dts/ingenic/x2000-v12-pinctrl.dtsi 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/boot/dts/ingenic/x2000-v12-pinctrl.dtsi 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,508 @@ ++#include ++ ++&pinctrl { ++ uart0_pin: uart0-pin { ++ uart0_pd: uart0-pd { ++ ingenic,pinmux = <&gpd 23 26>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ uart1_pin: uart1-pin { ++ uart1_pc: uart1-pc { ++ ingenic,pinmux = <&gpc 21 24>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ uart2_pin: uart2-pin { ++ uart2_pd: uart2-pd { ++ ingenic,pinmux = <&gpd 30 31>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ uart3_pin: uart3-pin { ++ uart3_pd: uart3-pd { ++ ingenic,pinmux = <&gpd 0 3>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ uart4_pin: uart4-pin { ++ uart4_pa: uart4-pa { ++ ingenic,pinmux = <&gpa 0 3>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ uart4_pc: uart4-pc { ++ ingenic,pinmux = <&gpc 9 12>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ uart5_pin: uart5-pin { ++ uart5_pa: uart5-pa { ++ ingenic,pinmux = <&gpa 4 5>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ uart5_pc: uart5-pc { ++ ingenic,pinmux = <&gpc 5 6>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ uart6_pin: uart6-pin { ++ uart6_pa: uart6-pa { ++ ingenic,pinmux = <&gpa 6 7>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ uart6_pc: uart6-pc { ++ ingenic,pinmux = <&gpc 7 8>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ uart7_pin: uart7-pin { ++ uart7_pa: uart7-pa { ++ ingenic,pinmux = <&gpa 8 9>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ uart7_pc: uart7-pc { ++ ingenic,pinmux = <&gpc 1 2>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ uart8_pin: uart8-pin { ++ uart8_pb: uart8-pb { ++ ingenic,pinmux = <&gpb 28 29>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ uart9_pin: uart9-pin { ++ uart9_pb: uart9-pb { ++ ingenic,pinmux = <&gpb 30 31>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ i2c0_pin: i2c0-pin { ++ i2c0_pc: i2c0-pc { ++ ingenic,pinmux = <&gpc 13 14>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ i2c1_pin: i2c1-pin { ++ i2c1_pc: i2c1-pc { ++ ingenic,pinmux = <&gpc 23 24>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ i2c2_pin: i2c2-pin { ++ i2c2_pb: i2c2-pb { ++ ingenic,pinmux = <&gpb 22 23>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ i2c3_pin: i2c3-pin { ++ i2c3_pd: i2c3-pd { ++ ingenic,pinmux = <&gpd 30 31>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ i2c4_pin: i2c4-pin { ++ i2c4_pd: i2c4-pd { ++ ingenic,pinmux = <&gpd 0 1>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ i2c5_pin: i2c5-pin { ++ i2c5_pd: i2c5-pd { ++ ingenic,pinmux = <&gpd 4 5>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ msc0_pin: msc0-pin { ++ msc0_4bit: msc0-4bit { ++ ingenic,pinmux = <&gpd 17 22>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ msc0_8bit: msc0-8bit { ++ ingenic,pinmux = <&gpd 17 26>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ msc1_pin: msc1-pin { ++ msc1_4bit: msc1-4bit { ++ ingenic,pinmux = <&gpd 8 13>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ msc2_pin: msc2-pin { ++ msc2_4bit: msc2-4bit { ++ ingenic,pinmux = <&gpe 0 5>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ mac0_rmii_p0: mac0-rmii-p0 { ++ mac0_rmii_p0_normal: mac0-rmii-normal { ++ ingenic,pinmux = <&gpc 6 7>, <&gpc 11 11>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ mac0_rmii_p0_rst: mac0-rmii-p0-rst { ++ ingenic,pinmux = <&gpc 6 7>, <&gpc 11 11>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ mac0_rmii_p1: mac0-rmii-p1 { ++ mac0_rmii_p1_normal: mac0-rmii-p1-normal { ++ ingenic,pinmux = <&gpc 1 3>, <&gpc 10 10>, <&gpc 12 13>, <&gpc 15 15>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ ++ mac0_rmii_p1_nomdio: mac0-rmii-p1-nomdio { ++ ingenic,pinmux = <&gpc 1 3>, <&gpc 10 10>, <&gpc 15 15>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ ++ mac0_rgmii_p0: mac0-rgmii-p0 { ++ mac0_rgmii_p0_normal: mac0-rgmii-normal { ++ ingenic,pinmux = <&gpc 6 9>, <&gpc 11 11>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ mac0_rgmii_p0_rst: mac0-rmii-p0-rst { ++ ingenic,pinmux = <&gpc 6 9>, <&gpc 11 11>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ mac0_rgmii_p1: mac0-rgmii-p1 { ++ mac0_rgmii_p1_normal: mac0-rgmii-p1-normal { ++ ingenic,pinmux = <&gpc 1 5>, <&gpc 10 10>, <&gpc 12 15>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ ++ mac0_rgmii_p1_nomdio: mac0-rmii-p1-nomdio { ++ ingenic,pinmux = <&gpc 1 5>, <&gpc 10 10>, <&gpc 14 15>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ mac1_rmii_p0: mac1-rmii-p0 { ++ mac1_rmii_p0_normal: mac1-rmii-normal { ++ ingenic,pinmux = <&gpb 12 13>, <&gpb 18 18>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ mac1_rmii_p0_rst: mac1-rmii-p0-rst { ++ ingenic,pinmux = <&gpb 12 13>, <&gpb 18 18>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ mac1_rmii_p1: mac1-rmii-p1 { ++ mac1_rmii_p1_normal: mac1-rmii-p1-normal { ++ ingenic,pinmux = <&gpb 8 9>, <&gpb 17 17>, <&gpb 19 20>, <&gpb 22 23>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ ++ mac1_rmii_p1_nomdio: mac1-rmii-p1-nomdio { ++ ingenic,pinmux = <&gpb 8 9>, <&gpb 17 17>, <&gpb 22 23>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ mac1_rgmii_p0: mac1-rgmii-p0 { ++ mac1_rgmii_p0_normal: mac1-rgmii-normal { ++ ingenic,pinmux = <&gpb 12 15>, <&gpb 18 18>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ mac1_rgmii_p0_rst: mac1-rmii-p0-rst { ++ ingenic,pinmux = <&gpb 12 15>, <&gpb 18 18>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ mac1_rgmii_p1: mac1-rgmii-p1 { ++ mac1_rgmii_p1_normal: mac1-rgmii-p1-normal { ++ ingenic,pinmux = <&gpb 8 11>, <&gpb 17 17>, <&gpb 19 23>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ ++ mac1_rgmii_p1_nomdio: mac1-rmii-p1-nomdio { ++ ingenic,pinmux = <&gpb 8 11>, <&gpb 17 17>, <&gpb 21 23>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ pwm_pin: pwm-pin{ ++ pwm_pc: pwm-pc{ ++ ingenic,pinmux = <&gpc 0 15>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ sfc_pin: sfc-pin { ++ sfc_pd: sfc-pd { ++ ingenic,pinmux = <&gpd 17 26>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ ++ sfc_pe: sfc-pe { ++ ingenic,pinmux = <&gpe 16 21>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ cim_pin: cim-pin { ++ cim_pa: cim-pa { ++ ingenic,pinmux = <&gpa 0 7>, <&gpa 12 16>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ vic_pin: vic-pin { ++ vic_pa: vic-pa { ++ ingenic,pinmux = <&gpa 0 15>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ lcd_pins: lcd-pins { ++ tft_lcd_pb: tft-lcd-pb { ++ ingenic,pinmux = <&gpb 0 27>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ ++ smart_lcd_pb: smart-lcd-pb { ++ ingenic,pinmux = <&gpb 0 15>, <&gpb 25 27>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ baic1_tmclk_pc: baic1-tmclk-pc { ++ ingenic,pinmux = <&gpc 8 8>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ ++ baic1_rmclk_pc: baic1-rmclk-pc { ++ ingenic,pinmux = <&gpc 1 1>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ ++ baic1_pin: baic1-pin { ++ baic1_pc: baic1-pin-pc { ++ ingenic,pinmux = <&gpc 2 7>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ baic1_combine_pc: baic1-cpin-pc { ++ ingenic,pinmux = <&gpc 4 7>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ baic2_mclk_pa: baic2-mclk-pa { ++ ingenic,pinmux = <&gpa 7 7>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ ++ baic2_pa: baic2-pa { ++ ingenic,pinmux = <&gpa 8 13>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ ++ baic3_mclk_pa: baic3-mclk-pa { ++ ingenic,pinmux = <&gpa 0 0>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ ++ baic3_pa: baic3-pa { ++ ingenic,pinmux = <&gpa 1 6>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ ++ baic4_pin: baic4-pin { ++ baic4_pe: baic4-pe { ++ ingenic,pinmux = <&gpe 0 3>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ ++ baic4_pd: baic4-pd { ++ ingenic,pinmux = <&gpd 2 5>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ spdif_pc: spdif-pc { ++ ingenic,pinmux = <&gpc 13 14>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ ++ dmic_pc: dmic-pc { ++ ingenic,pinmux = <&gpc 20 24>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ ++ spi0_pb: spi0-pb { ++ ingenic,pinmux = <&gpb 28 31>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ ++ spi1_pc: spi0-pc { ++ ingenic,pinmux = <&gpc 9 12>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ ++ pwm_pins: pwm-pins { ++ pwm0_pc: pwm0_pc { ++ ingenic,pinmux = <&gpc 0 0>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ pwm1_pc: pwm1_pc { ++ ingenic,pinmux = <&gpc 1 1>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ pwm2_pc: pwm2_pc { ++ ingenic,pinmux = <&gpc 2 2>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ pwm3_pc: pwm3_pc { ++ ingenic,pinmux = <&gpc 3 3>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ pwm4_pc: pwm4_pc { ++ ingenic,pinmux = <&gpc 4 4>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ pwm5_pc: pwm5_pc { ++ ingenic,pinmux = <&gpc 5 5>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ pwm6_pc: pwm6_pc { ++ ingenic,pinmux = <&gpc 6 6>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ pwm7_pc: pwm7_pc { ++ ingenic,pinmux = <&gpc 7 7>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ pwm8_pc: pwm8_pc { ++ ingenic,pinmux = <&gpc 8 8>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ pwm9_pc: pwm9_pc { ++ ingenic,pinmux = <&gpc 9 9>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ pwm10_pc: pwm10_pc { ++ ingenic,pinmux = <&gpc 10 10>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ pwm10_pe: pwm10_pe { ++ ingenic,pinmux = <&gpe 16 16>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ pwm11_pc: pwm11_pc { ++ ingenic,pinmux = <&gpc 11 11>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ pwm11_pe: pwm11_pe { ++ ingenic,pinmux = <&gpe 17 17>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ pwm12_pc: pwm12_pc { ++ ingenic,pinmux = <&gpc 12 12>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ pwm12_pe: pwm12_pe { ++ ingenic,pinmux = <&gpe 18 18>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ pwm13_pc: pwm13_pc { ++ ingenic,pinmux = <&gpc 13 13>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ pwm13_pe: pwm13_pe { ++ ingenic,pinmux = <&gpe 19 19>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ pwm14_pc: pwm14_pc { ++ ingenic,pinmux = <&gpc 14 14>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ pwm14_pe: pwm14_pe { ++ ingenic,pinmux = <&gpe 20 20>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ pwm15_pc: pwm15_pc { ++ ingenic,pinmux = <&gpc 15 15>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ pwm15_pe: pwm15_pe { ++ ingenic,pinmux = <&gpe 21 21>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ tcu_pin: tcu-pin { ++ tcu0_pc: tcu0_pc { ++ ingenic,pinmux = <&gpc 0 1>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ tcu1_pc: tcu1_pc { ++ ingenic,pinmux = <&gpc 2 3>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ tcu2_pc: tcu2_pc { ++ ingenic,pinmux = <&gpc 4 5>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ tcu3_pc: tcu3_pc { ++ ingenic,pinmux = <&gpc 6 7>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ tcu4_pc: tcu4_pc { ++ ingenic,pinmux = <&gpc 8 9>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ tcu5_pc: tcu5_pc { ++ ingenic,pinmux = <&gpc 10 11>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ tcu5_pe: tcu5_pe { ++ ingenic,pinmux = <&gpe 16 17>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ tcu6_pc: tcu6_pc { ++ ingenic,pinmux = <&gpc 12 13>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ tcu6_pe: tcu6_pe { ++ ingenic,pinmux = <&gpe 18 19>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ tcu7_pc: tcu7_pc { ++ ingenic,pinmux = <&gpc 14 15>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ tcu7_pe: tcu7_pe { ++ ingenic,pinmux = <&gpe 20 21>; ++ ingenic,pinmux-funcsel = ; ++ }; ++ }; ++ ++ scc_pc: scc-pc { ++ ingenic,pinmux = <&gpc 3 4>; ++ ingenic,pinmux-funcsel = ; ++ }; ++}; ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_x2000-v12.dtsi.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_x2000-v12.dtsi.patch new file mode 100644 index 00000000..eb1e797a --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_x2000-v12.dtsi.patch @@ -0,0 +1,742 @@ +diff -drupN a/arch/mips/boot/dts/ingenic/x2000-v12.dtsi b/arch/mips/boot/dts/ingenic/x2000-v12.dtsi +--- a/arch/mips/boot/dts/ingenic/x2000-v12.dtsi 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/boot/dts/ingenic/x2000-v12.dtsi 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,738 @@ ++#include ++#include ++#include ++#include ++#include ++ ++/ { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "ingenic,x2000"; ++ ++ aliases: aliases { ++ i2c0 = &i2c0; ++ i2c1 = &i2c1; ++ i2c2 = &i2c2; ++ i2c3 = &i2c3; ++ i2c4 = &i2c4; ++ i2c5 = &i2c5; ++ uart0 = &uart0; ++ uart1 = &uart1; ++ uart2 = &uart2; ++ uart3 = &uart3; ++ uart4 = &uart4; ++ uart5 = &uart5; ++ uart6 = &uart6; ++ uart7 = &uart7; ++ uart8 = &uart8; ++ msc0 = &msc0; ++ msc2 = &msc2; ++ mac0 = &mac0; ++ mac1 = &mac1; ++ spi0 = &spi0; ++ spi1 = &spi1; ++ }; ++ ++ cpus: cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cpu0: cpu@0 { ++ device_type = "cpu"; ++ compatible = "ingenic,xburst2"; ++ reg = <0x000>; ++ clock-frequency = <800000000>; ++ }; ++ ++ cpu1: cpu@1 { ++ device_type = "cpu"; ++ compatible = "ingenic,xburst2"; ++ reg = <0x001>; ++ clock-frequency = <800000000>; ++ }; ++ ++ cpu2: cpu@2 { ++ device_type = "cpu"; ++ compatible = "ingenic,xburst2"; ++ reg = <0x002>; ++ clock-frequency = <800000000>; ++ }; ++ ++ cpu3: cpu@3 { ++ device_type = "cpu"; ++ compatible = "ingenic,xburst2"; ++ reg = <0x003>; ++ clock-frequency = <800000000>; ++ }; ++ }; ++ ++ cpuintc: interrupt-controller { ++ #address-cells = <0>; ++ #interrupt-cells = <1>; ++ interrupt-controller; ++ compatible = "ingenic,cpu-interrupt-controller"; ++ ++ }; ++ ++ core_intc: core-intc@0x12300000 { ++ compatible = "ingenic,core-intc"; ++ reg = <0x12300000 0x1000>; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ cpu-intc-map = <0 0x000>, ++ <1 0x100>, ++ <2 0x200>, ++ <3 0x300>; ++ ++ interrupt-parent = <&cpuintc>; ++ interrupts = ; ++ interrupt-names ="intc"; ++ }; ++ ++ core_ost: core-ost@0x12000000 { ++ compatible = "ingenic,core-ost"; ++ reg = <0x12000000 0x10000>, /*Global ost*/ ++ <0x12100000 0x10000>; /*Core ost*/ ++ interrupt-parent = <&cpuintc>; ++ interrupt-names = "sys_ost"; ++ interrupts = ; ++ cpu-ost-map = <0 0x000>, ++ <1 0x100>, ++ <2 0x200>, ++ <3 0x300>; ++ }; ++ ++ extclk: extclk { ++ compatible = "fixed-clock"; ++ clock-output-names ="ext"; ++ #clock-cells = <0>; ++ clock-frequency = <24000000>; ++ }; ++ ++ rtcclk: rtcclk { ++ compatible = "fixed-clock"; ++ clock-output-names ="rtc_ext"; ++ #clock-cells = <0>; ++ clock-frequency = <32768>; ++ }; ++ ++ clock: clock-controller@0x10000000 { ++ compatible = "ingenic,x2000-v12-fpga-clocks"; ++ reg = <0x10000000 0x100>; ++ clocks = <&extclk>, <&rtcclk>; ++ clock-names = "ext", "rtc_ext"; ++ #clock-cells = <1>; ++ little-endian; ++ }; ++ ++ apb { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <>; ++ tcu: tcu@0x10002000 { ++ compatible = "ingenic,tcu"; ++ reg = <0x10002000 0x140>; ++ interrupt-parent = <&core_intc>; ++ interrupt-names = "tcu_int0", "tcu_int1", "tcu_int2"; ++ interrupts = ; ++ interrupt-controller; ++ status = "ok"; ++ ++ channel0: channel0 { ++ compatible = "ingenic,tcu_chn0"; ++ ingenic,channel-info = ; ++ }; ++ channel1: channel1 { ++ compatible = "ingenic,tcu_chn1"; ++ ingenic,channel-info = ; ++ }; ++ channel2: channel2 { ++ compatible = "ingenic,tcu_chn2"; ++ ingenic,channel-info = ; ++ }; ++ channel3: channel3 { ++ compatible = "ingenic,tcu_chn3"; ++ ingenic,channel-info = ; ++ }; ++ channel4: channel4 { ++ compatible = "ingenic,tcu_chn4"; ++ ingenic,channel-info = ; ++ }; ++ channel5: channel5 { ++ compatible = "ingenic,tcu_chn5"; ++ ingenic,channel-info = ; ++ }; ++ channel6: channel6 { ++ compatible = "ingenic,tcu_chn6"; ++ ingenic,channel-info = ; ++ }; ++ channel7: channel7 { ++ compatible = "ingenic,tcu_chn7"; ++ ingenic,channel-info = ; ++ }; ++ channel15: channel15 { ++ compatible = "ingenic,tcu_chn15"; ++ ingenic,channel-info = ; ++ }; ++ channel16: channel16 { ++ compatible = "ingenic,watchdog"; ++ ingenic,channel-info = ; ++ }; ++ }; ++ ++ ++ rtc: rtc@0x10003000 { ++ compatible = "ingenic,rtc"; ++ reg = <0x10003000 0x4c>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ system-power-controller; ++ power-on-press-ms = <1000>; ++ }; ++ ++ pinctrl: pinctrl@0x10010000 { ++ compatible = "ingenic,x2000-v12-pinctrl"; ++ reg = <0x10010000 0x1000>; ++ ingenic,num-chips = <6>; ++ ingenic,regs-offset = <0x100>; ++ ++ gpa: gpa { ++ gpio-controller; ++ #gpio-cells = <3>; ++ #ingenic,pincfg-cells = <3>; ++ #ingenic,pinmux-cells = <2>; ++ interrupts = ; ++ interrupt-parent = <&core_intc>; ++ interrupt-controller; ++ #interrupt-cells = <3>; ++ ingenic,num-gpios = <17>; ++ ingenic,pull-gpios-low = <0x55555555>; ++ ingenic,pull-gpios-high = <0x55555555>; ++ }; ++ ++ gpb: gpb { ++ gpio-controller; ++ #gpio-cells = <3>; ++ #ingenic,pincfg-cells = <3>; ++ #ingenic,pinmux-cells = <2>; ++ interrupts = ; ++ interrupt-parent = <&core_intc>; ++ interrupt-controller; ++ #interrupt-cells = <3>; ++ ingenic,num-gpios = <32>; ++ ingenic,pull-gpios-low = <0x55565555>; ++ ingenic,pull-gpios-high = <0x55555555>; ++ }; ++ ++ gpc: gpc { ++ gpio-controller; ++ #gpio-cells = <3>; ++ #ingenic,pincfg-cells = <3>; ++ #ingenic,pinmux-cells = <2>; ++ interrupts = ; ++ interrupt-parent = <&core_intc>; ++ interrupt-controller; ++ #interrupt-cells = <3>; ++ ingenic,num-gpios = <25>; ++ ingenic,pull-gpios-low = <0x55555555>; ++ ingenic,pull-gpios-high = <0x55555555>; ++ }; ++ ++ gpd: gpd { ++ gpio-controller; ++ #gpio-cells = <3>; ++ #ingenic,pincfg-cells = <3>; ++ #ingenic,pinmux-cells = <2>; ++ interrupts = ; ++ interrupt-parent = <&core_intc>; ++ interrupt-controller; ++ #interrupt-cells = <3>; ++ ingenic,num-gpios = <32>; ++ ingenic,pull-gpios-low = <0x55555555>; ++ ingenic,pull-gpios-high = <0x55555555>; ++ }; ++ ++ gpe: gpe { ++ gpio-controller; ++ #gpio-cells = <3>; ++ #ingenic,pincfg-cells = <3>; ++ #ingenic,pinmux-cells = <2>; ++ interrupts = ; ++ interrupt-parent = <&core_intc>; ++ interrupt-controller; ++ #interrupt-cells = <3>; ++ ingenic,num-gpios = <32>; ++ ingenic,pull-gpios-low = <0x55555555>; ++ ingenic,pull-gpios-high = <0x55555555>; ++ }; ++ ++ }; ++ ++ uart0: serial@0x10030000 { ++ compatible = "ingenic,8250-uart"; ++ reg = <0x10030000 0x100>; ++ reg-shift = <2>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart0_pd>; ++ status = "disabled"; ++ }; ++ uart1: serial@0x10031000 { ++ compatible = "ingenic,8250-uart"; ++ reg = <0x10031000 0x100>; ++ reg-shift = <2>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart1_pc>; ++ status = "disabled"; ++ }; ++ uart2: serial@0x10032000 { ++ compatible = "ingenic,8250-uart"; ++ reg = <0x10032000 0x100>; ++ reg-shift = <2>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart2_pd>; ++ status = "disabled"; ++ }; ++ uart3: serial@0x10033000 { ++ compatible = "ingenic,8250-uart"; ++ reg = <0x10033000 0x100>; ++ reg-shift = <2>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart3_pd>; ++ status = "disabled"; ++ }; ++ ++ uart4: serial@0x10034000 { ++ compatible = "ingenic,8250-uart"; ++ reg = <0x10034000 0x100>; ++ reg-shift = <2>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ uart5: serial@0x10035000 { ++ compatible = "ingenic,8250-uart"; ++ reg = <0x10035000 0x100>; ++ reg-shift = <2>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ uart6: serial@0x10036000 { ++ compatible = "ingenic,8250-uart"; ++ reg = <0x10036000 0x100>; ++ reg-shift = <2>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ uart7: serial@0x10037000 { ++ compatible = "ingenic,8250-uart"; ++ reg = <0x10037000 0x100>; ++ reg-shift = <2>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ ++ uart8: serial@0x10038000 { ++ compatible = "ingenic,8250-uart"; ++ reg = <0x10038000 0x100>; ++ reg-shift = <2>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart8_pb>; ++ status = "disabled"; ++ }; ++ uart9: serial@0x10039000 { ++ compatible = "ingenic,8250-uart"; ++ reg = <0x10039000 0x100>; ++ reg-shift = <2>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart9_pb>; ++ status = "disabled"; ++ }; ++ ++ i2c0: i2c@0x10050000 { ++ compatible = "ingenic,x2000-i2c"; ++ reg = <0x10050000 0x1000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i2c1: i2c@0x10051000 { ++ compatible = "ingenic,x2000-i2c"; ++ reg = <0x10051000 0x1000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i2c2: i2c@0x10052000 { ++ compatible = "ingenic,x2000-i2c"; ++ reg = <0x10052000 0x1000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i2c3: i2c@0x10053000 { ++ compatible = "ingenic,x2000-i2c"; ++ reg = <0x10053000 0x1000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i2c4: i2c@0x10054000 { ++ compatible = "ingenic,x2000-i2c"; ++ reg = <0x10054000 0x1000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i2c5: i2c@0x10055000 { ++ compatible = "ingenic,x2000-i2c"; ++ reg = <0x10055000 0x1000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ spi0: spi0@0x10043000 { ++ compatible = "ingenic,spi"; ++ reg = <0x10043000 0x1000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ dmas = <&pdma INGENIC_DMA_TYPE(INGENIC_DMA_REQ_SSI0_TX)>, ++ <&pdma INGENIC_DMA_TYPE(INGENIC_DMA_REQ_SSI0_RX)>; ++ dma-names = "tx", "rx"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ spi1: spi1@0x10044000 { ++ compatible = "ingenic,spi"; ++ reg = <0x10044000 0x1000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ dmas = <&pdma INGENIC_DMA_TYPE(INGENIC_DMA_REQ_SSI1_TX)>, ++ <&pdma INGENIC_DMA_TYPE(INGENIC_DMA_REQ_SSI1_RX)>; ++ dma-names = "tx", "rx"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ scc: scc@0x10040000 { ++ compatible = "ingenic,scc"; ++ reg = <0x10040000 0x100>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ ++ dtrng: dtrng@0x10072000 { ++ compatible = "ingenic,dtrng"; ++ reg = <0x10072000 0x100>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ ++ otg_phy: otg_phy { ++ compatible = "ingenic,innophy"; ++ }; ++ }; ++ ++ ahb2 { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <>; ++ ++ as:as { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <>; ++ ++ as_platform: as-platform { ++ compatible = "ingenic,as-platform"; ++ reg = <0x134d0000 0x114>, <0x134d1000 0x100>; ++ reg-names = "dma", "fifo"; ++ ingenic,fifo-size = <4096>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ ingenic,fth_quirk; ++ }; ++ as_virtual_fe: as-virtual-fe { ++ compatible = "ingenic,as-vir-fe"; ++ reg = <0x00000000 0x0>; ++ ingenic,cap-dai-bm = <0xc>; ++ ingenic,num-dais = <4>; ++ }; ++ as_fmtcov: as-fmtcov { ++ compatible = "ingenic,as-fmtcov"; ++ reg = <0x134d2000 0x28>; ++ }; ++ as_fe_dsp: as-dsp { ++ compatible = "ingenic,as-dsp"; ++ reg = <0x134d4000 0x30>; ++ ingenic,li-port = <0 1 2 3 4 6 7 8 9 10 11 12>; ++ ingenic,lo-port = <0 1 2 3 4 5 6 7 8 9 10 11>; ++ ingenic,cap-dai-bm = <0x3e0>; ++ ingenic,num-dais = <10>; ++ }; ++ as_be_baic: as-baic { ++ compatible = "ingenic,as-baic"; ++ reg = <0x134d5000 0x5000>; ++ ingenic,num-dais = <5>; ++ ingenic,dai-mode = , ++ , ++ , ++ , ++ ; ++ ingenic,dai-pin-num = <1>, <1>, <1>, <1>, <1>; ++ ingenic,dai-pin-split = <0>, <1>, <2>, <3>; ++ }; ++ as_dmic: as-dmic { ++ compatible = "ingenic,as-dmic"; ++ reg = <0x134da000 0x10>; ++ }; ++ as_aux_mixer: as-mixer { ++ compatible = "ingenic,as-mixer"; ++ reg = <0x134dc000 0x8>; ++ ingenic,num-mixers = <1>; ++ }; ++ as_spdif: as-spdif { ++ compatible = "ingenic,as-spdif"; ++ reg = <0x134db000 0x14>, <0x134db100 0x14>; ++ reg-names = "out", "in"; ++ }; ++ }; ++ ++ msc0: msc@0x13450000 { ++ compatible = "ingenic,sdhci"; ++ reg = <0x13450000 0x10000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ pinctrl-names ="default"; ++ pinctrl-0 = <&msc0_8bit>; ++ }; ++ ++ msc1: msc@0x13460000 { ++ compatible = "ingenic,sdhci"; ++ reg = <0x13460000 0x10000>; ++ status = "disabled"; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ pinctrl-names ="default"; ++ pinctrl-0 = <&msc1_4bit>; ++ }; ++ ++ msc2: msc@0x13490000 { ++ compatible = "ingenic,sdhci"; ++ reg = <0x13490000 0x10000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ pinctrl-names ="default"; ++ pinctrl-0 = <&msc2_4bit>; ++ }; ++ ++ aes: aes@0x13430000 { ++ compatible = "ingenic,aes"; ++ reg = <0x13430000 0x10000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ status = "ok"; ++ }; ++ ++ hash: hash@0x13470000 { ++ compatible = "ingenic,hash"; ++ reg = <0x13470000 0x10000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ status = "ok"; ++ }; ++ ++ rsa: rsa@0x13480000 { ++ compatible = "ingenic,rsa"; ++ reg = <0x13480000 0x10000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ status = "ok"; ++ }; ++ ++ mac0: mac@0x134b0000 { ++ compatible = "ingenic,dwc-mac"; ++ reg = <0x134b0000 0x2000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ status = "disabled"; ++ ingenic,rst-ms = <10>; ++ }; ++ ++ mac1: mac@0x134a0000 { ++ compatible = "ingenic,dwc-mac"; ++ reg = <0x134a0000 0x2000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ status = "disabled"; ++ ingenic,rst-ms = <10>; ++ }; ++ ++ sfc: sfc@0x13440000 { ++ compatible = "ingenic,sfc"; ++ reg = <0x13440000 0x10000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sfc_pe>; ++ status = "disabled"; ++ }; ++ ++ pdma: dma@13420000 { ++ compatible = "ingenic,x1000-pdma"; ++ reg = <0x13420000 0x10000>; ++ interrupt-parent = <&core_intc>; ++ interrupt-names = "pdma", "pdmad"; ++ interrupts = , ; ++ #dma-channels = <8>; ++ #dma-cells = <1>; ++ ingenic,reserved-chs = <0x3>; ++ }; ++ ++ pwm: pwm@0x134c0000 { ++ compatible = "ingenic,x2000-pwm"; ++ reg = <0x134c0000 0x10000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pwm_pc>; ++ status = "ok"; ++ }; ++ ++ otg: otg@0x13500000 { ++ compatible = "ingenic,dwc2-hsotg"; ++ reg = <0x13500000 0x40000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ ingenic,usbphy=<&otg_phy>; ++ status = "disabled"; ++ }; ++ ++ efuse: efuse@0x13540000 { ++ compatible = "ingenic,x2000-efuse"; ++ reg = <0x13540000 0x10000>; ++ status = "okay"; ++ }; ++ }; ++ ++ ahb1 { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <>; ++ ++ }; ++ ++ ahb0 { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <>; ++ ++ cim: cim@0x13060000 { ++ compatible = "ingenic,cim"; ++ reg = <0x13060000 0x10000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ status = "disable"; ++ }; ++ ++ dpu: dpu@0x13050000 { ++ compatible = "ingenic,x2000-dpu"; ++ reg = <0x13050000 0x10000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ ++ rotate: rotate@0x13070000 { ++ compatible = "ingenic,x2000-rotate"; ++ reg = <0x13070000 0x10000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ status = "okay"; ++ }; ++ ++ helix: helix@0x13200000 { ++ compatible = "ingenic,x2000-helix"; ++ reg = <0x13200000 0x100000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ ++ felix: felix@0x13300000 { ++ compatible = "ingenic,x2000-felix"; ++ reg = <0x13300000 0x100000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ ++ isp0: isp0@0x13700000 { ++ compatible = "ingenic,x2000-isp0"; ++ reg = <0x13700000 0x100000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ ++ isp1: isp1@0x13800000 { ++ compatible = "ingenic,x2000-isp1"; ++ reg = <0x13800000 0x100000>; ++ interrupt-parent = <&core_intc>; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ }; ++ ++}; ++#include "x2000-v12-pinctrl.dtsi" diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_x2000_v12_fpga.dts.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_x2000_v12_fpga.dts.patch new file mode 100644 index 00000000..062ec7c3 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_dts_ingenic_x2000_v12_fpga.dts.patch @@ -0,0 +1,197 @@ +diff -drupN a/arch/mips/boot/dts/ingenic/x2000_v12_fpga.dts b/arch/mips/boot/dts/ingenic/x2000_v12_fpga.dts +--- a/arch/mips/boot/dts/ingenic/x2000_v12_fpga.dts 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/boot/dts/ingenic/x2000_v12_fpga.dts 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,193 @@ ++/dts-v1/; ++ ++#include ++#include "x2000-v12.dtsi" ++ ++/ { ++ compatible = "img,fpga", "ingenic,x2000"; ++}; ++ ++&uart0 { ++ status = "okay"; ++}; ++ ++&uart2 { ++ status = "disable"; ++}; ++ ++ ++//&pwm { ++// ingenic,pwm-outputs = <0>; /* <0 - 15> select which pwms are really used */ ++//} ++ ++ ++&msc0 { ++ status = "okay"; ++ /*mmc-hs200-1_8v;*/ ++ cap-mmc-highspeed; ++ non-removable; ++ max-frequency = <50000000>; ++ bus-width = <4>; ++ non-removable; ++ voltage-ranges = <1800 3300>; ++ ++ /* special property */ ++ ingenic,wp-gpios = <0>; ++ ingneic,cd-gpios = <0>; ++ ingenic,rst-gpios = <0>; ++}; ++ ++&msc2 { ++ status = "disable"; ++ /*mmc-hs200-1_8v;*/ ++ cap-mmc-highspeed; ++ non-removable; ++ max-frequency = <50000000>; ++ bus-width = <4>; ++ non-removable; ++ voltage-ranges = <1800 3300>; ++ ++ /* special property */ ++ ingenic,wp-gpios = <0>; ++ ingneic,cd-gpios = <0>; ++ ingenic,rst-gpios = <0>; ++}; ++ ++&mac0 { ++ pinctrl-names = "default", "reset"; ++ pinctrl-0 = <&mac0_rmii_p0_normal>, <&mac0_rmii_p1_normal>; ++ pinctrl-1 = <&mac0_rmii_p0_rst>, <&mac0_rmii_p1_normal>; ++ status = "okay"; ++ ingenic,rst-gpio = <&gpb 0 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ ingenic,rst-ms = <10>; ++ ingenic,mac-mode = ; ++ ingenic,mode-reg = <0xb00000e4>; ++}; ++ ++&mac1 { ++ pinctrl-names = "default", "reset"; ++ pinctrl-0 = <&mac1_rmii_p0_normal>, <&mac1_rmii_p1_normal>; ++ pinctrl-1 = <&mac1_rmii_p0_rst>, <&mac1_rmii_p1_normal>; ++ status = "okay"; ++ ingenic,rst-gpio = <&gpb 1 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ ingenic,rst-ms = <10>; ++ ingenic,mac-mode = ; ++ ingenic,mode-reg = <0xb00000e8>; ++}; ++ ++/* ++&mac0 { ++ pinctrl-names = "default", "reset"; ++ pinctrl-0 = <&mac0_rgmii_p0_normal>, <&mac0_rgmii_p1_normal>; ++ pinctrl-1 = <&mac0_rgmii_p0_rst>, <&mac0_rgmii_p1_normal>; ++ status = "okay"; ++ ingenic,rst-gpio = <&gpb 0 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ ingenic,rst-ms = <10>; ++ ingenic,mac-mode = ; ++ ingenic,mode-reg = <0xb00000e4>; ++}; ++ ++&mac1 { ++ pinctrl-names = "default", "reset"; ++ pinctrl-0 = <&mac1_rgmii_p0_normal>, <&mac1_rgmii_p1_normal>; ++ pinctrl-1 = <&mac1_rgmii_p0_rst>, <&mac1_rgmii_p1_normal>; ++ status = "okay"; ++ ingenic,rst-gpio = <&gpb 1 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ ingenic,rst-ms = <10>; ++ ingenic,mac-mode = ; ++ ingenic,mode-reg = <0xb00000e8>; ++}; ++*/ ++ ++&sfc { ++ status = "okay"; ++ ingenic,sfc-max-frequency = <150000000>; ++ ingenic,use_board_info = /bits/ 8 <0>; ++ ingenic,spiflash_param_offset = <0>; ++ ++ ++}; ++ ++&cim { ++ status = "okay"; ++ port { ++ cim_0: endpoint@0 { ++ remote-endpoint = <&mt9v022_0>; ++ bus-width = <8>; ++ }; ++ }; ++}; ++ ++ ++&i2c4 { ++ status = "okay"; ++ clock-frequency = <100000>; ++ timeout = <1000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c4_pd>; ++ ++ mt9v022: mt9v022@0x5c { ++ status = "okay"; ++ compatible = "micron,mt9v022"; ++ reg = <0x5c>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&cim_pa>; ++ ++ pwdn-gpios = <&gpe 4 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ vcc-en-gpios = <&gpe 3 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; ++ ++ port { ++ mt9v022_0: endpoint { ++ remote-endpoint = <&cim_0>; ++ }; ++ }; ++ }; ++}; ++ ++/ { ++ ++ extclk: extclk { ++ clock-frequency = <24000000>; ++ }; ++ ++ gpio_keys: gpio_keys { ++ compatible = "gpio-keys"; ++ ++ power { ++ label = "Power"; ++ linux,code = ; ++ gpios = <&gpa 31 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>; ++ gpio-key,wakeup; ++ }; ++ }; ++}; ++ ++&felix { ++ status = "okay"; ++}; ++ ++&helix { ++ status = "okay"; ++}; ++ ++&dpu { ++ status = "okay"; ++}; ++ ++/ { ++ display-dbi { ++ compatible = "simple-bus"; ++ #interrupt-cells = <1>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <>; ++ panel_bm8766@0 { ++ compatible = "ingenic,bm8766"; ++ status = "okay"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&tft_lcd_pb>; ++ }; ++ }; ++ ++ ++}; diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_zcompressed_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_zcompressed_Makefile.patch new file mode 100644 index 00000000..4ea01c00 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_zcompressed_Makefile.patch @@ -0,0 +1,73 @@ +diff -drupN a/arch/mips/boot/zcompressed/Makefile b/arch/mips/boot/zcompressed/Makefile +--- a/arch/mips/boot/zcompressed/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/boot/zcompressed/Makefile 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,69 @@ ++# ++# linux/arch/mips/boot/compressed/Makefile ++# ++# create a compressed zImage from the original vmlinux ++# ++ ++targets := zImage uImage vmlinuz vmlinux.bin.gz head.o misc.o piggy.o dummy.o ++ ++OBJS := $(obj)/head.o $(obj)/misc.o ++ ++LD_ARGS := -m elf32ltsmip -T $(obj)/ld.script -Ttext 0x80F00000 -Bstatic -EL ++OBJCOPY_ARGS := -O elf32-tradlittlemips ++ ++ENTRY := $(obj)/entry ++FILESIZE := $(obj)/filesize ++ ++KBUILD_CFLAGS := $(shell echo $(KBUILD_CFLAGS) | sed -e "s/-pg//") ++KBUILD_CFLAGS := $(filter-out -fstack-protector, $(KBUILD_CFLAGS)) ++KBUILD_CFLAGS := $(LINUXINCLUDE) $(KBUILD_CFLAGS) -D__KERNEL__ \ ++ -DBOOT_HEAP_SIZE=$(BOOT_HEAP_SIZE) -D"VMLINUX_LOAD_ADDRESS_ULL=$(VMLINUX_LOAD_ADDRESS)ull" ++ ++ ++drop-sections = .reginfo .mdebug .comment .note .pdr .options .MIPS.options ++strip-flags = $(addprefix --remove-section=,$(drop-sections)) ++ ++LOADADDR=0x80010000 ++ ++$(obj)/vmlinux.bin.gz: vmlinux ++ rm -f $(obj)/vmlinux.bin.gz ++ $(OBJCOPY) -O binary $(strip-flags) vmlinux $(obj)/vmlinux.bin ++ gzip -v9f $(obj)/vmlinux.bin ++ ++$(obj)/head.o: $(obj)/head.S $(obj)/vmlinux.bin.gz vmlinux ++ echo $(CC) ++ $(CC) $(KBUILD_AFLAGS) $(a_flags) \ ++ -DIMAGESIZE=$(shell sh $(FILESIZE) $(obj)/vmlinux.bin.gz) \ ++ -DKERNEL_ENTRY=$(shell sh $(ENTRY) $(NM) vmlinux ) \ ++ -DLOADADDR=0x80010000 \ ++ -I./include \ ++ -c -o $(obj)/head.o $< ++ ++$(obj)/vmlinuz: $(OBJS) $(obj)/ld.script $(obj)/vmlinux.bin.gz $(obj)/dummy.o ++ $(OBJCOPY) \ ++ --add-section=.image=$(obj)/vmlinux.bin.gz \ ++ --set-section-flags=.image=contents,alloc,load,readonly,data \ ++ $(obj)/dummy.o $(obj)/piggy.o ++ $(LD) $(LD_ARGS) -o $@ $(OBJS) $(obj)/piggy.o ++ $(OBJCOPY) $(OBJCOPY_ARGS) $@ $@ -R .comment -R .stab -R .stabstr -R .initrd -R .sysmap ++ ++zImage: $(obj)/vmlinuz ++ $(OBJCOPY) -O binary $(obj)/vmlinuz $(obj)/zImage ++ @rm -f $(obj)/vmlinuz ++ ++vmlinux.bin: $(VMLINUX) ++ $(OBJCOPY) -O binary $(strip-flags) $(VMLINUX) $(obj)/vmlinux.bin ++ ++uImage: $(VMLINUX) vmlinux.bin ++ rm -f $(obj)/vmlinux.bin.gz ++ gzip -9 $(obj)/vmlinux.bin ++ mkimage -A mips -O linux -T kernel -C gzip \ ++ -a $(LOADADDR) -e $(shell sh ./$(obj)/tools/entry $(NM) $(VMLINUX) ) \ ++ -n 'Linux-$(KERNELRELEASE)' \ ++ -d $(obj)/vmlinux.bin.gz $(obj)/uImage ++xImage: zImage ++ mkimage -A mips -O linux -T kernel -C none \ ++ -a 0x80F00000 -e 0x80F00000 \ ++ -n 'Linux-$(KERNELRELEASE)' \ ++ -d $(obj)/zImage $(obj)/xImage ++ @rm -f $(obj)/zImage diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_zcompressed_dummy.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_zcompressed_dummy.c.patch new file mode 100644 index 00000000..1d92acc9 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_zcompressed_dummy.c.patch @@ -0,0 +1,8 @@ +diff -drupN a/arch/mips/boot/zcompressed/dummy.c b/arch/mips/boot/zcompressed/dummy.c +--- a/arch/mips/boot/zcompressed/dummy.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/boot/zcompressed/dummy.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,4 @@ ++int main(void) ++{ ++ return 0; ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_zcompressed_entry.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_zcompressed_entry.patch new file mode 100644 index 00000000..85ba0ddf --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_zcompressed_entry.patch @@ -0,0 +1,16 @@ +diff -drupN a/arch/mips/boot/zcompressed/entry b/arch/mips/boot/zcompressed/entry +--- a/arch/mips/boot/zcompressed/entry 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/boot/zcompressed/entry 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,12 @@ ++#!/bin/sh ++ ++# grab the kernel_entry address from the vmlinux elf image ++entry=`$1 $2 | grep kernel_entry` -w ++ ++fs=`echo $entry | grep ffffffff` # check toolchain output ++ ++if [ -n "$fs" ]; then ++ echo "0x"`$1 $2 | grep kernel_entry -w | cut -c9- | awk '{print $1}'` ++else ++ echo "0x"`$1 $2 | grep kernel_entry -w | cut -c1- | awk '{print $1}'` ++fi diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_zcompressed_filesize.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_zcompressed_filesize.patch new file mode 100644 index 00000000..dd415dc0 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_zcompressed_filesize.patch @@ -0,0 +1,11 @@ +diff -drupN a/arch/mips/boot/zcompressed/filesize b/arch/mips/boot/zcompressed/filesize +--- a/arch/mips/boot/zcompressed/filesize 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/boot/zcompressed/filesize 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,7 @@ ++#!/bin/sh ++HOSTNAME=`uname` ++if [ "$HOSTNAME" = "Linux" ]; then ++echo `ls -l $1 | awk '{print $5}'` ++else ++echo `ls -l $1 | awk '{print $6}'` ++fi diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_zcompressed_head.S.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_zcompressed_head.S.patch new file mode 100644 index 00000000..d7c31880 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_zcompressed_head.S.patch @@ -0,0 +1,91 @@ +diff -drupN a/arch/mips/boot/zcompressed/head.S b/arch/mips/boot/zcompressed/head.S +--- a/arch/mips/boot/zcompressed/head.S 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/boot/zcompressed/head.S 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,87 @@ ++/* ++ * linux/arch/mips/boot/compressed/head.S ++ * ++ * Copyright (C) 2005-2008 Ingenic Semiconductor Inc. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#define IndexInvalidate_I 0x00 ++#define IndexWriteBack_D 0x01 ++ ++ .set noreorder ++ LEAF(startup) ++startup: ++ ++ move s0, a0 /* Save the boot loader transfered args */ ++ move s1, a1 ++ move s2, a2 ++ move s3, a3 ++ ++ la a0, _edata ++ la a1, _end ++1: sw zero, 0(a0) /* Clear BSS section */ ++ bne a1, a0, 1b ++ addu a0, 4 ++ ++ la sp, (.stack + 8192) ++ ++ la a0, __image_begin ++ la a1, IMAGESIZE ++ la a2, LOADADDR ++ la ra, 1f ++ la k0, decompress_kernel ++ jr k0 ++ nop ++1: ++ ++ move a0, s0 ++ move a1, s1 ++ move a2, s2 ++ move a3, s3 ++ ++ li k0, KERNEL_ENTRY ++ ++ jr k0 ++ nop ++ ++2: ++ b 2b ++ ++ END(startup) ++ ++ ++ LEAF(flushcaches) ++ li k0, 0x80000000 # start address ++ li k1, 0x80008000 # end address (32KB I-Cache) ++ la t0, 1f ++ la t1, 0xa0000000 ++ or t0, t0, t1 ++ jr.hb t0 ++ nop ++1: ++ cache IndexWriteBack_D, 0(k0) ++ cache IndexWriteBack_D, 32(k0) ++ cache IndexWriteBack_D, 64(k0) ++ cache IndexWriteBack_D, 96(k0) ++ cache IndexInvalidate_I, 0(k0) ++ cache IndexInvalidate_I, 32(k0) ++ cache IndexInvalidate_I, 64(k0) ++ cache IndexInvalidate_I, 96(k0) ++ ++ addu k0, k0, 128 ++ bne k0, k1, 1b ++ nop ++ sync ++ la t0, 3f ++ jr.hb t0 ++ nop ++3: ++ jr ra ++ nop ++ END(flushcaches) ++ ++ .comm .stack,4096*2,4 diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_zcompressed_ld.script.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_zcompressed_ld.script.patch new file mode 100644 index 00000000..41cdc82a --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_zcompressed_ld.script.patch @@ -0,0 +1,155 @@ +diff -drupN a/arch/mips/boot/zcompressed/ld.script b/arch/mips/boot/zcompressed/ld.script +--- a/arch/mips/boot/zcompressed/ld.script 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/boot/zcompressed/ld.script 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,151 @@ ++OUTPUT_ARCH(mips) ++ENTRY(startup) ++SECTIONS ++{ ++ /* Read-only sections, merged into text segment: */ ++ ++ .init : { *(.init) } =0 ++ .text : ++ { ++ _ftext = . ; ++ *(.text) ++ *(.rodata) ++ *(.rodata1) ++ /* .gnu.warning sections are handled specially by elf32.em. */ ++ *(.gnu.warning) ++ } =0 ++ .kstrtab : { *(.kstrtab) } ++ ++ . = ALIGN(16); /* Exception table */ ++ __start___ex_table = .; ++ __ex_table : { *(__ex_table) } ++ __stop___ex_table = .; ++ ++ __start___dbe_table = .; /* Exception table for data bus errors */ ++ __dbe_table : { *(__dbe_table) } ++ __stop___dbe_table = .; ++ ++ __start___ksymtab = .; /* Kernel symbol table */ ++ __ksymtab : { *(__ksymtab) } ++ __stop___ksymtab = .; ++ ++ _etext = .; ++ ++ . = ALIGN(8192); ++ .data.init_task : { *(.data.init_task) } ++ ++ /* Startup code */ ++ . = ALIGN(4096); ++ __init_begin = .; ++ .text.init : { *(.text.init) } ++ .data.init : { *(.data.init) } ++ . = ALIGN(16); ++ __setup_start = .; ++ .setup.init : { *(.setup.init) } ++ __setup_end = .; ++ __initcall_start = .; ++ .initcall.init : { *(.initcall.init) } ++ __initcall_end = .; ++ . = ALIGN(4096); /* Align double page for init_task_union */ ++ __init_end = .; ++ ++ . = ALIGN(4096); ++ .data.page_aligned : { *(.data.idt) } ++ ++ . = ALIGN(32); ++ .data.cacheline_aligned : { *(.data.cacheline_aligned) } ++ ++ .fini : { *(.fini) } =0 ++ .reginfo : { *(.reginfo) } ++ /* Adjust the address for the data segment. We want to adjust up to ++ the same address within the page on the next page up. It would ++ be more correct to do this: ++ . = .; ++ The current expression does not correctly handle the case of a ++ text segment ending precisely at the end of a page; it causes the ++ data segment to skip a page. The above expression does not have ++ this problem, but it will currently (2/95) cause BFD to allocate ++ a single segment, combining both text and data, for this case. ++ This will prevent the text segment from being shared among ++ multiple executions of the program; I think that is more ++ important than losing a page of the virtual address space (note ++ that no actual memory is lost; the page which is skipped can not ++ be referenced). */ ++ . = .; ++ .data : ++ { ++ _fdata = . ; ++ *(.data) ++ ++ /* Put the compressed image here, so bss is on the end. */ ++ __image_begin = .; ++ *(.image) ++ __image_end = .; ++ /* Align the initial ramdisk image (INITRD) on page boundaries. */ ++ . = ALIGN(4096); ++ __ramdisk_begin = .; ++ *(.initrd) ++ __ramdisk_end = .; ++ . = ALIGN(4096); ++ ++ CONSTRUCTORS ++ } ++ .data1 : { *(.data1) } ++ _gp = . + 0x8000; ++ .lit8 : { *(.lit8) } ++ .lit4 : { *(.lit4) } ++ .ctors : { *(.ctors) } ++ .dtors : { *(.dtors) } ++ .got : { *(.got.plt) *(.got) } ++ .dynamic : { *(.dynamic) } ++ /* We want the small data sections together, so single-instruction offsets ++ can access them all, and initialized data all before uninitialized, so ++ we can shorten the on-disk segment size. */ ++ .sdata : { *(.sdata) } ++ . = ALIGN(4); ++ _edata = .; ++ PROVIDE (edata = .); ++ ++ __bss_start = .; ++ _fbss = .; ++ .sbss : { *(.sbss) *(.scommon) } ++ .bss : ++ { ++ *(.dynbss) ++ *(.bss) ++ *(COMMON) ++ . = ALIGN(4); ++ _end = . ; ++ PROVIDE (end = .); ++ } ++ ++ /* Sections to be discarded */ ++ /DISCARD/ : ++ { ++ *(.text.exit) ++ *(.data.exit) ++ *(.exitcall.exit) ++ } ++ ++ /* This is the MIPS specific mdebug section. */ ++ .mdebug : { *(.mdebug) } ++ /* These are needed for ELF backends which have not yet been ++ converted to the new style linker. */ ++ .stab 0 : { *(.stab) } ++ .stabstr 0 : { *(.stabstr) } ++ /* DWARF debug sections. ++ Symbols in the .debug DWARF section are relative to the beginning of the ++ section so we begin .debug at 0. It's not clear yet what needs to happen ++ for the others. */ ++ .debug 0 : { *(.debug) } ++ .debug_srcinfo 0 : { *(.debug_srcinfo) } ++ .debug_aranges 0 : { *(.debug_aranges) } ++ .debug_pubnames 0 : { *(.debug_pubnames) } ++ .debug_sfnames 0 : { *(.debug_sfnames) } ++ .line 0 : { *(.line) } ++ /* These must appear regardless of . */ ++ .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) } ++ .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) } ++ .comment : { *(.comment) } ++ .note : { *(.note) } ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_zcompressed_misc.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_zcompressed_misc.c.patch new file mode 100644 index 00000000..81422d3d --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_zcompressed_misc.c.patch @@ -0,0 +1,389 @@ +diff -drupN a/arch/mips/boot/zcompressed/misc.c b/arch/mips/boot/zcompressed/misc.c +--- a/arch/mips/boot/zcompressed/misc.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/boot/zcompressed/misc.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,385 @@ ++/* ++ * linux/arch/mips/boot/compressed/misc.c ++ * ++ * This is a collection of several routines from gzip-1.0.3 ++ * adapted for Linux. ++ * ++ * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994 ++ * ++ * Adapted for JZSOC by Peter Wei, 2008 ++ * ++ */ ++ ++#include ++#include ++#include ++ ++#define size_t int ++#define NULL 0 ++ ++/* ++ * gzip declarations ++ */ ++ ++#define OF(args) args ++#define STATIC static ++ ++#undef memset ++#undef memcpy ++#define memzero(s, n) memset ((s), 0, (n)) ++ ++typedef unsigned char uch; ++typedef unsigned short ush; ++typedef unsigned long ulg; ++ ++#define WSIZE 0x8000 /* Window size must be at least 32k, */ ++ /* and a power of two */ ++ ++static uch *inbuf; /* input buffer */ ++static uch window[WSIZE]; /* Sliding window buffer */ ++ ++static unsigned insize = 0; /* valid bytes in inbuf */ ++static unsigned inptr = 0; /* index of next byte to be processed in inbuf */ ++static unsigned outcnt = 0; /* bytes in output buffer */ ++ ++/* gzip flag byte */ ++#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ ++#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ ++#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ ++#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ ++#define COMMENT 0x10 /* bit 4 set: file comment present */ ++#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ ++#define RESERVED 0xC0 /* bit 6,7: reserved */ ++ ++#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) ++ ++/* Diagnostic functions */ ++#ifdef DEBUG ++# define Assert(cond,msg) {if(!(cond)) error(msg);} ++# define Trace(x) fprintf x ++# define Tracev(x) {if (verbose) fprintf x ;} ++# define Tracevv(x) {if (verbose>1) fprintf x ;} ++# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} ++# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} ++#else ++# define Assert(cond,msg) ++# define Trace(x) ++# define Tracev(x) ++# define Tracevv(x) ++# define Tracec(c,x) ++# define Tracecv(c,x) ++#endif ++ ++static int fill_inbuf(void); ++static void flush_window(void); ++static void error(char *m); ++#if 0 ++static void gzip_mark(void **); ++static void gzip_release(void **); ++#endif ++void* memset(void* s, int c, size_t n); ++void* memcpy(void* __dest, __const void* __src, size_t __n); ++ ++extern void flushcaches(void); /* defined in head.S */ ++ ++char *input_data; ++int input_len; ++ ++static long bytes_out = 0; ++static uch *output_data; ++static unsigned long output_ptr = 0; ++ ++ ++static void *malloc(int size); ++static void free(void *where); ++static void error(char *m); ++ ++#if 1 ++ ++/* ++ * Add puts func just for debug. ++ * If it does not work,check the follows macro define. ++ * Have a pleasant debug day. ++ */ ++ ++static volatile int uart_base; ++ ++#define OFF_LSR (0x14) ++#define OFF_LCR (0x0C) ++#define OFF_TDR (0x00) ++#define UART_OFF 0x1000 ++#define UART_LSR_TDRQ (1 << 5) /* 1: transmit FIFO half "empty" */ ++#define UART_LSR_TEMT (1 << 6) /* 1: transmit FIFO and shift registers empty */ ++ ++void check_uart(void) ++{ ++ volatile char *base = (volatile char*)CKSEG1ADDR(UART0_IOBASE); ++ int i; ++ for(i=0; i<4; i++) { ++ if(base[OFF_LCR]) ++ break; ++ base += UART_OFF; ++ } ++ ++ uart_base = (int)base; ++} ++ ++static void serial_putc (const char c) ++{ ++ volatile char *uart_lsr = (volatile char *)(uart_base + OFF_LSR); ++ volatile char *uart_tdr = (volatile char *)(uart_base + OFF_TDR); ++ ++ if (c == '\n') serial_putc ('\r'); ++ ++ /* Wait for fifo to shift out some bytes */ ++ while ( !((*uart_lsr & (UART_LSR_TDRQ | UART_LSR_TEMT)) == 0x60) ); ++ ++ *uart_tdr = (char)c; ++} ++static void puts(const char *s) ++{ ++ while (*s) { ++ serial_putc (*s++); ++ } ++} ++ ++static int hex2asc(int n) ++{ ++ n &= 15; ++ if(n > 9){ ++ return ('a' - 10) + n; ++ } else { ++ return '0' + n; ++ } ++} ++ ++int printf(char *fmt,...) ++{ ++ va_list ap; ++ char scratch[16]; ++ va_start(ap,fmt); ++ ++ for(;;){ ++ switch(*fmt){ ++ case 0: ++ va_end(ap); ++ return 0; ++ case '%': ++ switch(fmt[1]) { ++ case 'p': ++ case 'X': ++ case 'x': { ++ unsigned n = va_arg(ap, unsigned); ++ char *p = scratch + 15; ++ *p = 0; ++ do { ++ *--p = hex2asc(n); ++ n = n >> 4; ++ } while(n != 0); ++ while(p > (scratch + 7)) *--p = '0'; ++ while (*p) serial_putc(*p++); ++ fmt += 2; ++ continue; ++ } ++ case 'd': { ++ int n = va_arg(ap, int); ++ char *p = scratch + 15; ++ *p = 0; ++ if(n < 0) { ++ serial_putc('-'); ++ n = -n; ++ } ++ do { ++ *--p = (n % 10) + '0'; ++ n /= 10; ++ } while(n != 0); ++ while (*p) serial_putc(*p++); ++ fmt += 2; ++ continue; ++ } ++ case 's': { ++ char *s = va_arg(ap, char*); ++ if(s == 0) s = "(null)"; ++ while (*s) serial_putc(*s++); ++ fmt += 2; ++ continue; ++ } ++ } ++ serial_putc(*fmt++); ++ break; ++ case '\n': ++ serial_putc('\r'); ++ default: ++ serial_putc(*fmt++); ++ } ++ } ++} ++ ++ ++#else ++static void puts(const char *str) ++{ ++} ++#endif ++ ++extern unsigned char _end[]; ++static unsigned long free_mem_ptr; ++static unsigned long free_mem_end_ptr; ++ ++#define HEAP_SIZE 0x10000 ++ ++#include "../../../../lib/inflate.c" ++ ++#if 0 ++static void *malloc(int size) ++{ ++ void *p; ++ ++ if (size <0) error("Malloc error\n"); ++ if (free_mem_ptr == 0) error("Memory error\n"); ++ ++ free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */ ++ ++ p = (void *)free_mem_ptr; ++ free_mem_ptr += size; ++ ++ if (free_mem_ptr >= free_mem_end_ptr) ++ error("\nOut of memory\n"); ++ ++ return p; ++} ++ ++static void free(void *where) ++{ /* Don't care */ ++} ++ ++ ++static void gzip_mark(void **ptr) ++{ ++ *ptr = (void *) free_mem_ptr; ++} ++ ++static void gzip_release(void **ptr) ++{ ++ free_mem_ptr = (long) *ptr; ++} ++#endif ++void* memset(void* s, int c, size_t n) ++{ ++ int i; ++ char *ss = (char*)s; ++ ++ for (i=0;i> 3; i > 0; i--) { ++ *d++ = *s++; ++ *d++ = *s++; ++ *d++ = *s++; ++ *d++ = *s++; ++ *d++ = *s++; ++ *d++ = *s++; ++ *d++ = *s++; ++ *d++ = *s++; ++ } ++ ++ if (__n & 1 << 2) { ++ *d++ = *s++; ++ *d++ = *s++; ++ *d++ = *s++; ++ *d++ = *s++; ++ } ++ ++ if (__n & 1 << 1) { ++ *d++ = *s++; ++ *d++ = *s++; ++ } ++ ++ if (__n & 1) ++ *d++ = *s++; ++ ++ return __dest; ++} ++ ++/* =========================================================================== ++ * Fill the input buffer. This is called only when the buffer is empty ++ * and at least one byte is really needed. ++ */ ++static int fill_inbuf(void) ++{ ++ if (insize != 0) { ++ error("ran out of input data\n"); ++ } ++ ++ inbuf = input_data; ++ insize = input_len; ++ inptr = 1; ++ return inbuf[0]; ++} ++ ++/* =========================================================================== ++ * Write the output window window[0..outcnt-1] and update crc and bytes_out. ++ * (Used for the decompressed data only.) ++ */ ++static void flush_window(void) ++{ ++ ulg c = crc; /* temporary variable */ ++ unsigned n; ++ uch *in, *out, ch; ++ ++ in = window; ++ out = &output_data[output_ptr]; ++ for (n = 0; n < outcnt; n++) { ++ ch = *out++ = *in++; ++ c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); ++ } ++ crc = c; ++ bytes_out += (ulg)outcnt; ++ output_ptr += (ulg)outcnt; ++ outcnt = 0; ++} ++ ++static void error(char *x) ++{ ++ puts("\n\n"); ++ puts(x); ++ puts("\n\n -- System halted"); ++ ++ while(1); /* Halt */ ++} ++ ++void decompress_kernel(unsigned int imageaddr, unsigned int imagesize, unsigned int loadaddr) ++{ ++ input_data = (char *)imageaddr; ++ input_len = imagesize; ++ output_ptr = 0; ++ output_data = (uch *)loadaddr; ++ free_mem_ptr = (unsigned long)_end; ++ free_mem_end_ptr = free_mem_ptr + HEAP_SIZE; ++ ++ check_uart(); ++ makecrc(); ++ puts("Uncompressing Linux...\n"); ++ gunzip(); ++ flushcaches(); ++ puts("Ok, booting the kernel.\n"); ++#if 0 ++ { ++ int i; ++ int *p = loadaddr; ++ for(i=0;i<512;i++) ++ { ++ if(i%4 == 0) ++ printf("\n"); ++ printf("%x ",p[i]); ++ } ++ printf("\n"); ++ } ++#endif ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_zcompressed_tools_entry.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_zcompressed_tools_entry.patch new file mode 100644 index 00000000..003d9427 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_zcompressed_tools_entry.patch @@ -0,0 +1,16 @@ +diff -drupN a/arch/mips/boot/zcompressed/tools/entry b/arch/mips/boot/zcompressed/tools/entry +--- a/arch/mips/boot/zcompressed/tools/entry 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/boot/zcompressed/tools/entry 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,12 @@ ++#!/bin/sh ++ ++# grab the kernel_entry address from the vmlinux elf image ++entry=`$1 $2 | grep kernel_entry` ++ ++fs=`echo $entry | grep ffffffff` # check toolchain output ++ ++if [ -n "$fs" ]; then ++ echo "0x"`$1 $2 | grep kernel_entry | cut -c9- | awk '{print $1}'` ++else ++ echo "0x"`$1 $2 | grep kernel_entry | cut -c1- | awk '{print $1}'` ++fi diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_zcompressed_tools_filesize.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_zcompressed_tools_filesize.patch new file mode 100644 index 00000000..61edb6fe --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_boot_zcompressed_tools_filesize.patch @@ -0,0 +1,11 @@ +diff -drupN a/arch/mips/boot/zcompressed/tools/filesize b/arch/mips/boot/zcompressed/tools/filesize +--- a/arch/mips/boot/zcompressed/tools/filesize 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/boot/zcompressed/tools/filesize 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,7 @@ ++#!/bin/sh ++HOSTNAME=`uname` ++if [ "$HOSTNAME" = "Linux" ]; then ++echo `ls -l $1 | awk '{print $5}'` ++else ++echo `ls -l $1 | awk '{print $6}'` ++fi diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_bootinfo.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_bootinfo.h.patch new file mode 100644 index 00000000..3a2cac41 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_bootinfo.h.patch @@ -0,0 +1,12 @@ +diff -drupN a/arch/mips/include/asm/bootinfo.h b/arch/mips/include/asm/bootinfo.h +--- a/arch/mips/include/asm/bootinfo.h 2017-10-21 18:09:07.000000000 +0300 ++++ b/arch/mips/include/asm/bootinfo.h 2022-06-09 05:02:27.000000000 +0300 +@@ -79,6 +79,8 @@ enum loongson_machine_type { + */ + #define MACH_INGENIC_JZ4730 0 /* JZ4730 SOC */ + #define MACH_INGENIC_JZ4740 1 /* JZ4740 SOC */ ++#define MACH_XBURST 2 /* Xburst based SOC */ ++#define MACH_XBURST2 3 /* Xburst2 based SOC */ + + extern char *system_type; + const char *get_system_type(void); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_cacheflush.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_cacheflush.h.patch new file mode 100644 index 00000000..820ffbb5 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_cacheflush.h.patch @@ -0,0 +1,25 @@ +diff -drupN a/arch/mips/include/asm/cacheflush.h b/arch/mips/include/asm/cacheflush.h +--- a/arch/mips/include/asm/cacheflush.h 2017-10-21 18:09:07.000000000 +0300 ++++ b/arch/mips/include/asm/cacheflush.h 2022-06-09 05:02:27.000000000 +0300 +@@ -58,7 +58,8 @@ static inline void flush_dcache_page(str + if (cpu_has_dc_aliases) + __flush_dcache_page(page); + else if (!cpu_has_ic_fills_f_dc) +- SetPageDcacheDirty(page); ++// SetPageDcacheDirty(page); ++ __flush_dcache_page(page); + } + + #define flush_dcache_mmap_lock(mapping) do { } while (0) +@@ -125,7 +126,10 @@ static inline void kunmap_noncoherent(vo + #define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE + static inline void flush_kernel_dcache_page(struct page *page) + { +- BUG_ON(cpu_has_dc_aliases && PageHighMem(page)); ++// BUG_ON(cpu_has_dc_aliases && PageHighMem(page)); ++ if (cpu_has_dc_aliases || !cpu_has_ic_fills_f_dc) ++ __flush_dcache_page(page); ++ + } + + /* diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_cop2.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_cop2.h.patch new file mode 100644 index 00000000..a4b6a2fb --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_cop2.h.patch @@ -0,0 +1,20 @@ +diff -drupN a/arch/mips/include/asm/cop2.h b/arch/mips/include/asm/cop2.h +--- a/arch/mips/include/asm/cop2.h 2017-10-21 18:09:07.000000000 +0300 ++++ b/arch/mips/include/asm/cop2.h 2022-06-09 05:02:27.000000000 +0300 +@@ -11,7 +11,15 @@ + + #include + +-#if defined(CONFIG_CPU_CAVIUM_OCTEON) ++#if defined(CONFIG_XBURST_MXUV2) ++#define cop2_present 1 ++extern void xburst_cop2_save(struct xburst_cop2_state *); ++extern void xburst_cop2_restore(struct xburst_cop2_state *); ++#define cop2_save(r) xburst_cop2_save(&(r)->thread.cp2) ++#define cop2_restore(r) xburst_cop2_restore(&(r)->thread.cp2) ++#define cop2_lazy_restore 0 ++ ++#elif defined(CONFIG_CPU_CAVIUM_OCTEON) + + extern void octeon_cop2_save(struct octeon_cop2_state *); + extern void octeon_cop2_restore(struct octeon_cop2_state *); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_cpu-features.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_cpu-features.h.patch new file mode 100644 index 00000000..77ae610a --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_cpu-features.h.patch @@ -0,0 +1,23 @@ +diff -drupN a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h +--- a/arch/mips/include/asm/cpu-features.h 2017-10-21 18:09:07.000000000 +0300 ++++ b/arch/mips/include/asm/cpu-features.h 2022-06-09 05:02:27.000000000 +0300 +@@ -311,6 +311,19 @@ + #define cpu_has_mipsmt (cpu_data[0].ases & MIPS_ASE_MIPSMT) + #endif + ++ ++#if defined(CONFIG_MACH_XBURST) && !defined(cpu_has_mxu) ++#define cpu_has_mxu (cpu_data[0].ases & MIPS_ASE_CU2) ++#elif !defined(cpu_has_mxu) ++#define cpu_has_mxu 0 ++#endif ++ ++#if defined(CONFIG_MACH_XBURST2) && !defined(cpu_has_mxuv3) ++#define cpu_has_mxuv3 (cpu_data[0].ases & MIPS_ASE_CU2) ++#elif !defined(cpu_has_mxu) ++#define cpu_has_mxuv3 0 ++#endif ++ + #ifndef cpu_has_userlocal + #define cpu_has_userlocal (cpu_data[0].options & MIPS_CPU_ULRI) + #endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_cpu.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_cpu.h.patch new file mode 100644 index 00000000..2bbd7158 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_cpu.h.patch @@ -0,0 +1,65 @@ +diff -drupN a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h +--- a/arch/mips/include/asm/cpu.h 2017-10-21 18:09:07.000000000 +0300 ++++ b/arch/mips/include/asm/cpu.h 2022-06-09 05:02:27.000000000 +0300 +@@ -45,6 +45,7 @@ + #define PRID_COMP_INGENIC_D0 0xd00000 /* JZ4740, JZ4750 */ + #define PRID_COMP_INGENIC_D1 0xd10000 /* JZ4770, JZ4775 */ + #define PRID_COMP_INGENIC_E1 0xe10000 /* JZ4780 */ ++#define PRID_COMP_INGENIC_13 0x130000 /* X2000 */ + + /* + * Assigned Processor ID (implementation) values for bits 15:8 of the PRId +@@ -170,11 +171,42 @@ + #define PRID_IMP_CAVIUM_CN78XX 0x9500 + #define PRID_IMP_CAVIUM_CN70XX 0x9600 + ++ ++ + /* +- * These are the PRID's for when 23:16 == PRID_COMP_INGENIC_* ++ * These are the PRID's for when 23:16 == PRID_COMP_INGENIC ++ * 31:24, Company Options is reserved; ++ * 23:16, Company ID is 0xd0; ++ * 15:8, Processor ID; ++ * -- 15:13, is the Generation of INGENIC's core. ++ * 0x0 is XBurst1, ++ * 0x1 is XBurst2, ++ * others are reserved. ++ * -- 12:8, the encode of micro-architecture(uA). ++ * 7:0, Revision; ++ * -- 7:4, the encode of process. ++ * 0x0 is SMIC40LP, ++ * 0x1 is TSMC40LP, ++ * others are reserved. ++ * -- 3:0, the version of a chip's package or upgrades. + */ ++#define PRID_COMPANY_ID_MASK 0x00FF0000 ++#define PRID_CPU_ARCH_MASK 0x00001F00 ++#define PRID_CPU_FEATURE_MASK 0xFFFF0000 ++#define PRID_CPU_CHIPS_MASK 0x000FF000 ++#define PRID_IMP_PROCESSOR_ID_MSK 0x0000E000 ++#define PRID_IMP_XBURST (0x0 << 13) ++#define PRID_IMP_XBURST2 (0x1 << 13) ++#define PRID_CPU_ISA_MASK 0x00000FFF + +-#define PRID_IMP_JZRISC 0x0200 ++#define PRID_IMP_JZRISC 0x00010000 ++#define PRID_CPU_JZ4775S 0x2ed00000 ++#define PRID_CPU_JZ4780 0x3ee00000 ++#define PRID_CPU_M200 0x7ae00000 ++#define PRID_CPU_X1000 0x2ed10000 ++#define PRID_CPU_X1800 0x00d00000 ++#define PRID_CPU_X2000 0x00130000 ++#define PRID_IMP_ISA_R2 0x0000024f + + /* + * These are the PRID's for when 23:16 == PRID_COMP_NETLOGIC +@@ -398,6 +430,6 @@ enum cpu_type_enum { + #define MIPS_ASE_MIPSMT 0x00000020 /* CPU supports MIPS MT */ + #define MIPS_ASE_DSP2P 0x00000040 /* Signal Processing ASE Rev 2 */ + #define MIPS_ASE_VZ 0x00000080 /* Virtualization ASE */ +-#define MIPS_ASE_MSA 0x00000100 /* MIPS SIMD Architecture */ +- ++#define MIPS_ASE_CU2 0x00000100 /* Coprocessor 2 implemented */ ++#define MIPS_ASE_MSA 0x00080000 /* MIPS SIMD Architecture */ + #endif /* _ASM_CPU_H */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_fpu.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_fpu.h.patch new file mode 100644 index 00000000..c732c285 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_fpu.h.patch @@ -0,0 +1,34 @@ +diff -drupN a/arch/mips/include/asm/fpu.h b/arch/mips/include/asm/fpu.h +--- a/arch/mips/include/asm/fpu.h 2017-10-21 18:09:07.000000000 +0300 ++++ b/arch/mips/include/asm/fpu.h 2022-06-09 05:02:27.000000000 +0300 +@@ -41,7 +41,7 @@ extern void _restore_fp(struct task_stru + */ + enum fpu_mode { + FPU_32BIT = 0, /* FR = 0 */ +- FPU_64BIT, /* FR = 1, FRE = 0 */ ++ FPU_64BIT, /* FR = 1 */ + FPU_AS_IS, + FPU_HYBRID, /* FR = 1, FRE = 1 */ + +@@ -74,11 +74,17 @@ static inline int __enable_fpu(enum fpu_ + goto fr_common; + + case FPU_64BIT: +-#if !(defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) \ +- || defined(CONFIG_64BIT)) +- /* we only have a 32-bit FPU */ ++ change_c0_status(ST0_CU1 | ST0_FR, ST0_CU1 | ST0_FR); ++ enable_fpu_hazard(); ++ /* check FR has the desired value */ ++ if (read_c0_status() & ST0_FR) ++ return 0; ++ ++ /* unsupported FR value */ ++ __disable_fpu(); ++ /* we only have a 32-bit FPU. not used for xburst2. qiao */ + return SIGFPE; +-#endif ++ + /* fall through */ + case FPU_32BIT: + if (cpu_has_fre) { diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_irqflags.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_irqflags.h.patch new file mode 100644 index 00000000..3a4c9f88 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_irqflags.h.patch @@ -0,0 +1,24 @@ +diff -drupN a/arch/mips/include/asm/irqflags.h b/arch/mips/include/asm/irqflags.h +--- a/arch/mips/include/asm/irqflags.h 2017-10-21 18:09:07.000000000 +0300 ++++ b/arch/mips/include/asm/irqflags.h 2022-06-09 05:02:27.000000000 +0300 +@@ -142,6 +142,20 @@ static inline void arch_local_irq_enable + : "memory"); + } + ++static inline unsigned long read_cp0_30_flags(void) ++{ ++ unsigned long flags; ++ ++ asm __volatile__( ++ " .set push \n" ++ " .set reorder \n" ++ " mfc0 %[flags], $30 \n" ++ " .set pop \n" ++ : [flags] "=r" (flags)); ++ ++ return flags; ++} ++ + static inline unsigned long arch_local_save_flags(void) + { + unsigned long flags; diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_msa.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_msa.h.patch new file mode 100644 index 00000000..8f7002ce --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_msa.h.patch @@ -0,0 +1,21 @@ +diff -drupN a/arch/mips/include/asm/msa.h b/arch/mips/include/asm/msa.h +--- a/arch/mips/include/asm/msa.h 2017-10-21 18:09:07.000000000 +0300 ++++ b/arch/mips/include/asm/msa.h 2022-06-09 05:02:27.000000000 +0300 +@@ -102,6 +102,8 @@ static inline void enable_msa(void) + { + if (cpu_has_msa) { + set_c0_config5(MIPS_CONF5_MSAEN); ++ set_c0_status(ST0_CU2); ++ KSTK_STATUS(current) |= ST0_CU2; + enable_fpu_hazard(); + } + } +@@ -110,6 +112,8 @@ static inline void disable_msa(void) + { + if (cpu_has_msa) { + clear_c0_config5(MIPS_CONF5_MSAEN); ++ clear_c0_status(ST0_CU2); ++ KSTK_STATUS(current) &= ~ST0_CU2; + disable_fpu_hazard(); + } + } diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_pgtable-bits.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_pgtable-bits.h.patch new file mode 100644 index 00000000..6a703939 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_pgtable-bits.h.patch @@ -0,0 +1,21 @@ +diff -drupN a/arch/mips/include/asm/pgtable-bits.h b/arch/mips/include/asm/pgtable-bits.h +--- a/arch/mips/include/asm/pgtable-bits.h 2017-10-21 18:09:07.000000000 +0300 ++++ b/arch/mips/include/asm/pgtable-bits.h 2022-06-09 05:02:27.000000000 +0300 +@@ -249,6 +249,17 @@ static inline uint64_t pte_to_entrylo(un + /* Ingenic uses the WA bit to achieve write-combine memory writes */ + #define _CACHE_UNCACHED_ACCELERATED (1<<_CACHE_SHIFT) + ++#elif defined(CONFIG_MACH_XBURST) || defined(CONFIG_MACH_XBURST2) ++ ++#define _CACHE_CACHABLE_WT_WA (0<<_CACHE_SHIFT) /* R4600 only */ ++#define _CACHE_UNCACHED_ACCELERATED (1<<_CACHE_SHIFT) /* R4600 only */ ++#define _CACHE_UNCACHED (2<<_CACHE_SHIFT) /* R4[0246]00 */ ++#define _CACHE_CACHABLE_WB_WA (3<<_CACHE_SHIFT) /* R4[0246]00 */ ++#define _CACHE_CACHABLE_WT_WA_S (4<<_CACHE_SHIFT) /* R4[04]00MC only */ ++#define _CACHE_CACHABLE_WB_WA_S (5<<_CACHE_SHIFT) /* R4[04]00MC only */ ++#define _CACHE_CACHABLE_WA _CACHE_UNCACHED_ACCELERATED ++#define _CACHE_CACHABLE_NONCOHERENT _CACHE_CACHABLE_WB_WA ++ + #endif + + #ifndef _CACHE_CACHABLE_NO_WA diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_processor.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_processor.h.patch new file mode 100644 index 00000000..7e6f5cd2 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_processor.h.patch @@ -0,0 +1,155 @@ +diff -drupN a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h +--- a/arch/mips/include/asm/processor.h 2017-10-21 18:09:07.000000000 +0300 ++++ b/arch/mips/include/asm/processor.h 2022-06-09 05:02:27.000000000 +0300 +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + + /* + * Return current * instruction pointer ("program counter"). +@@ -82,9 +83,19 @@ extern unsigned int vced_count, vcei_cou + */ + #define TASK_UNMAPPED_BASE PAGE_ALIGN(TASK_SIZE / 3) + +- + #define NUM_FPU_REGS 32 + ++#if cpu_has_mxu ++#define NUM_MXU_VPR_REGS 16 //vpr0~15 ++#define NUM_MXU_VSR_REGS 0 ++#endif ++ ++#if cpu_has_mxuv3 ++#define NUM_MXU_VPR_REGS 32 //vpr0~31 ++#define NUM_MXU_VSR_REGS 4 //vsr0~3 ++#endif ++ ++ + #ifdef CONFIG_CPU_HAS_MSA + # define FPU_REG_WIDTH 128 + #else +@@ -96,10 +107,30 @@ union fpureg { + __u64 val64[FPU_REG_WIDTH / 64]; + }; + ++typedef union mxuvec { ++#if cpu_has_mxu ++ uint8_t val128[16]; //simd128 ++#endif ++#if cpu_has_mxuv3 ++ uint8_t val512[64]; //simd512 ++#endif ++} mxuvec_t; ++ ++ ++//#ifdef CONFIG_MACH_XBURST ++struct xburst_mxu_struct { ++ mxuvec_t vpr[NUM_MXU_VPR_REGS]; ++ mxuvec_t vsr[NUM_MXU_VSR_REGS]; ++ uint32_t csr; ++}; ++//#endif ++ ++ ++ + #ifdef CONFIG_CPU_LITTLE_ENDIAN + # define FPR_IDX(width, idx) (idx) + #else +-# define FPR_IDX(width, idx) ((idx) ^ ((64 / (width)) - 1)) ++# define FPR_IDX(width, idx) ((FPU_REG_WIDTH / (width)) - 1 - (idx)) + #endif + + #define BUILD_FPR_ACCESS(width) \ +@@ -154,8 +185,20 @@ struct mips3264_watch_reg_state { + union mips_watch_reg_state { + struct mips3264_watch_reg_state mips3264; + }; ++#if defined(CONFIG_XBURST_MXUV2) ++typedef union { ++ u64 val64[2]; ++} vpr_t; + +-#if defined(CONFIG_CPU_CAVIUM_OCTEON) ++struct xburst_cop2_state { ++ u32 mxu_csr; ++ vpr_t vr[32]; ++}; ++ ++#define COP2_INIT \ ++ .cp2 = {0,}, ++ ++#elif defined(CONFIG_CPU_CAVIUM_OCTEON) + + struct octeon_cop2_state { + /* DMFC2 rt, 0x0201 */ +@@ -224,6 +267,13 @@ struct nlm_cop2_state { + #define COP2_INIT + #endif + ++#ifdef CONFIG_PMON_DEBUG ++struct xburst_perf_cnt { ++ u32 perfctrl; ++ u64 perfcnt; ++}; ++#endif ++ + typedef struct { + unsigned long seg; + } mm_segment_t; +@@ -262,6 +312,11 @@ struct thread_struct { + /* Saved state of the DSP ASE, if available. */ + struct mips_dsp_state dsp; + ++//#ifdef CONFIG_MACH_XBURST ++ /* Saved registers of the MXU, if available. */ ++ struct xburst_mxu_struct mxu; ++//#endif ++ + /* Saved watch register state, if available. */ + union mips_watch_reg_state watch; + +@@ -270,13 +325,18 @@ struct thread_struct { + unsigned long cp0_baduaddr; /* Last kernel fault accessing USEG */ + unsigned long error_code; + unsigned long trap_nr; +-#ifdef CONFIG_CPU_CAVIUM_OCTEON ++#if defined(CONFIG_XBURST_MXUV2) ++ struct xburst_cop2_state cp2; ++#elif defined(CONFIG_CPU_CAVIUM_OCTEON) + struct octeon_cop2_state cp2 __attribute__ ((__aligned__(128))); + struct octeon_cvmseg_state cvmseg __attribute__ ((__aligned__(128))); + #endif + #ifdef CONFIG_CPU_XLP + struct nlm_cop2_state cp2; + #endif ++#ifdef CONFIG_PMON_DEBUG ++ struct xburst_perf_cnt pfc[2]; ++#endif + struct mips_abi *abi; + }; + +@@ -288,6 +348,14 @@ struct thread_struct { + #define FPAFF_INIT + #endif /* CONFIG_MIPS_MT_FPAFF */ + ++#ifdef CONFIG_PMON_DEBUG ++#define PFC_INIT \ ++ .pfc = {{0, 0}, {0, 0}}, ++#else ++#define PFC_INIT ++#endif /* CONFIG_MACH_XBURST */ ++ ++ + #define INIT_THREAD { \ + /* \ + * Saved main processor registers \ +@@ -341,6 +409,7 @@ struct thread_struct { + * Platform specific cop2 registers(null if no COP2) \ + */ \ + COP2_INIT \ ++ PFC_INIT \ + } + + struct task_struct; diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_r4kcache.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_r4kcache.h.patch new file mode 100644 index 00000000..eae1a196 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_r4kcache.h.patch @@ -0,0 +1,101 @@ +diff -drupN a/arch/mips/include/asm/r4kcache.h b/arch/mips/include/asm/r4kcache.h +--- a/arch/mips/include/asm/r4kcache.h 2017-10-21 18:09:07.000000000 +0300 ++++ b/arch/mips/include/asm/r4kcache.h 2022-06-09 05:02:27.000000000 +0300 +@@ -48,6 +48,41 @@ extern void (*r4k_blast_icache)(void); + : \ + : "i" (op), "R" (*(unsigned char *)(addr))) + ++#ifdef CONFIG_MACH_XBURST ++#define __inv_btb() \ ++ do { \ ++ unsigned long tmp; \ ++ __asm__ __volatile__( \ ++ ".set push\n\t" \ ++ ".set noreorder\n\t" \ ++ ".set mips32\n\t" \ ++ "mfc0 %0, $16, 7\n\t" \ ++ "nop\n\t" \ ++ "ori %0, 2\n\t" \ ++ "mtc0 %0, $16, 7\n\t" \ ++ "nop\n\t" \ ++ ".set pop\n\t" \ ++ : "=&r" (tmp)); \ ++ } while(0) ++#define __sync_wb() __sync() ++#define __bridge_sync_war() \ ++ do { \ ++ if (MIPS_BRIDGE_SYNC_WAR) \ ++ __fast_iob(); \ ++ } while (0) ++static inline void blast_inclusive_scache(void) ++{ ++ __bridge_sync_war(); ++} ++#else ++#define __inv_btb() do {} while(0) ++#define __sync_wb() do {} while(0) ++#define __bridge_sync_war() do {} while(0) ++static inline void blast_inclusive_scache(void) ++{ ++} ++#endif ++ + #ifdef CONFIG_MIPS_MT + + #define __iflush_prologue \ +@@ -76,13 +111,13 @@ extern void (*r4k_blast_icache)(void); + #else /* CONFIG_MIPS_MT */ + + #define __iflush_prologue { +-#define __iflush_epilogue } ++#define __iflush_epilogue __inv_btb(); } /*CONFIG_MACH_XBURST*/ + #define __dflush_prologue { +-#define __dflush_epilogue } ++#define __dflush_epilogue __sync_wb(); } /*CONFIG_MACH_XBURST*/ + #define __inv_dflush_prologue { + #define __inv_dflush_epilogue } + #define __sflush_prologue { +-#define __sflush_epilogue } ++#define __sflush_epilogue __bridge_sync_war(); } /*CONFIG_MACH_XBURST*/ + #define __inv_sflush_prologue { + #define __inv_sflush_epilogue } + +@@ -105,6 +140,7 @@ static inline void flush_dcache_line_ind + static inline void flush_scache_line_indexed(unsigned long addr) + { + cache_op(Index_Writeback_Inv_SD, addr); ++ __bridge_sync_war(); /*CONFIG_MACH_XBURST*/ + } + + static inline void flush_icache_line(unsigned long addr) +@@ -144,6 +180,7 @@ static inline void invalidate_scache_lin + static inline void flush_scache_line(unsigned long addr) + { + cache_op(Hit_Writeback_Inv_SD, addr); ++ __bridge_sync_war(); /*CONFIG_MACH_XBURST*/ + } + + #define protected_cache_op(op,addr) \ +@@ -189,6 +226,7 @@ static inline void protected_flush_icach + #else + protected_cache_op(Hit_Invalidate_I, addr); + #endif ++ __inv_btb(); /*CONFIG_MACH_XBURST*/ + break; + } + } +@@ -206,11 +244,14 @@ static inline void protected_writeback_d + #else + protected_cache_op(Hit_Writeback_Inv_D, addr); + #endif ++ __sync_wb(); /*CONFIG_MACH_XBURST*/ + } + + static inline void protected_writeback_scache_line(unsigned long addr) + { + protected_cache_op(Hit_Writeback_Inv_SD, addr); ++ ++ __bridge_sync_war(); /*CONFIG_MACH_XBURST*/ + } + + /* diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_switch_to.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_switch_to.h.patch new file mode 100644 index 00000000..a4894990 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_asm_switch_to.h.patch @@ -0,0 +1,60 @@ +diff -drupN a/arch/mips/include/asm/switch_to.h b/arch/mips/include/asm/switch_to.h +--- a/arch/mips/include/asm/switch_to.h 2017-10-21 18:09:07.000000000 +0300 ++++ b/arch/mips/include/asm/switch_to.h 2022-06-09 05:02:27.000000000 +0300 +@@ -15,8 +15,18 @@ + #include + #include + #include ++#include + #include + #include ++#include ++ ++#ifdef CONFIG_PMON_DEBUG ++extern void save_perf_event_jz(void *tskvoid); ++extern void restore_perf_event_jz(void *tskvoid); ++#else ++#define save_perf_event_jz(tskvoid) ++#define restore_perf_event_jz(tskvoid) ++#endif + + struct task_struct; + +@@ -89,7 +99,24 @@ do { \ + __save_dsp(prev); \ + __restore_dsp(next); \ + } \ +- if (cop2_present) { \ ++ if(cpu_has_mxu) { \ ++ if (KSTK_STATUS(prev) & ST0_CU2) { \ ++ __save_mxu(prev); \ ++ } \ ++ if (KSTK_STATUS(next) & ST0_CU2) { \ ++ __restore_mxu(next); \ ++ } \ ++ } \ ++ if (cpu_has_mxuv3) { \ ++ if ((KSTK_STATUS(prev) & ST0_CU2)) { \ ++ __save_mxuv3(prev); \ ++ } \ ++ if ((KSTK_STATUS(next) & ST0_CU2)) { \ ++ set_c0_status(ST0_CU2); \ ++ __restore_mxuv3(next); \ ++ } \ ++ } \ ++ if (cop2_present) { \ + set_c0_status(ST0_CU2); \ + if ((KSTK_STATUS(prev) & ST0_CU2)) { \ + if (cop2_lazy_restore) \ +@@ -102,9 +129,11 @@ do { \ + } \ + clear_c0_status(ST0_CU2); \ + } \ ++ save_perf_event_jz(prev); \ + __clear_software_ll_bit(); \ + if (cpu_has_userlocal) \ + write_c0_userlocal(task_thread_info(next)->tp_value); \ ++ restore_perf_event_jz(next); \ + __restore_watch(next); \ + (last) = resume(prev, next, task_thread_info(next)); \ + } while (0) diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_uapi_asm_sigcontext.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_uapi_asm_sigcontext.h.patch new file mode 100644 index 00000000..56e304c6 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_include_uapi_asm_sigcontext.h.patch @@ -0,0 +1,24 @@ +diff -drupN a/arch/mips/include/uapi/asm/sigcontext.h b/arch/mips/include/uapi/asm/sigcontext.h +--- a/arch/mips/include/uapi/asm/sigcontext.h 2017-10-21 18:09:07.000000000 +0300 ++++ b/arch/mips/include/uapi/asm/sigcontext.h 2022-06-09 05:02:27.000000000 +0300 +@@ -11,7 +11,9 @@ + + #include + #include +- ++#ifdef CONFIG_MACH_XBURST ++#include ++#endif + /* scalar FP context was used */ + #define USED_FP (1 << 0) + +@@ -49,6 +51,9 @@ struct sigcontext { + unsigned long sc_lo2; + unsigned long sc_hi3; + unsigned long sc_lo3; ++#ifdef CONFIG_MACH_XBURST ++ unsigned long sc_mxu[NUM_MXU_REGS]; /* NUM_MXU_REGS = 16*/ ++#endif + }; + + #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_kernel_cpu-probe.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_kernel_cpu-probe.c.patch new file mode 100644 index 00000000..67a92207 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_kernel_cpu-probe.c.patch @@ -0,0 +1,134 @@ +diff -drupN a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c +--- a/arch/mips/kernel/cpu-probe.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/arch/mips/kernel/cpu-probe.c 2022-06-09 05:02:27.000000000 +0300 +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -414,6 +415,7 @@ static inline unsigned int decode_config + + config0 = read_c0_config(); + ++ + /* + * Look for Standard TLB or Dual VTLB and FTLB + */ +@@ -471,6 +473,8 @@ static inline unsigned int decode_config + + config1 = read_c0_config1(); + ++ if (config1 & MIPS_CONF1_C2) ++ c->ases |= MIPS_ASE_CU2; + if (config1 & MIPS_CONF1_MD) + c->ases |= MIPS_ASE_MDMX; + if (config1 & MIPS_CONF1_WR) +@@ -1332,18 +1336,65 @@ platform: + } + } + ++#ifdef CONFIG_XBURST_MXUV2 ++extern int soc_support_mxuv2(void); ++#endif + static inline void cpu_probe_ingenic(struct cpuinfo_mips *c, unsigned int cpu) + { ++ unsigned int errorpc; ++ static unsigned int showerrorpc[NR_CPUS]; ++ unsigned int config1; ++ ++ if(showerrorpc[cpu] == 0) { ++ __asm__ __volatile__ ( ++ "mfc0 %0, $30, 0 \n\t" ++ "nop \n\t" ++ :"=r"(errorpc) ++ :); ++ ++ printk("CPU%d RESET ERROR PC:%08X\n", cpu,errorpc); ++ if(kernel_text_address(errorpc)) ++ print_ip_sym(errorpc); ++ showerrorpc[cpu] = 1; ++ } ++ + decode_configs(c); + /* JZRISC does not implement the CP0 counter. */ ++ /* INGENIC RISC does not implement the CP0 counter. */ + c->options &= ~MIPS_CPU_COUNTER; + BUG_ON(!__builtin_constant_p(cpu_has_counter) || cpu_has_counter); +- switch (c->processor_id & PRID_IMP_MASK) { +- case PRID_IMP_JZRISC: ++ ++ switch (c->processor_id & PRID_IMP_PROCESSOR_ID_MSK) { ++ case PRID_IMP_XBURST: ++ { ++ unsigned int config7; + c->cputype = CPU_JZRISC; + c->writecombine = _CACHE_UNCACHED_ACCELERATED; +- __cpu_name[cpu] = "Ingenic JZRISC"; ++ __cpu_name[cpu] = "Xburst"; ++ /* ++ * When CPU enters the long cycle, it will reduce the CPU speed to save power. ++ * Set cp0 config7 bit 4 to disable this feature ++ * This feature will cause bogoMips and loops_per_jiffy calculate in error ++ */ ++ config7 = read_c0_config7(); ++ config7 |= (1 << 4); ++ write_c0_config7(config7); ++ ++ config1 = read_c0_config1(); ++#ifdef CONFIG_XBURST_MXUV2 ++ if(soc_support_mxuv2()) { ++ c->ases |= MIPS_ASE_XBURSTMXUV2; ++ } else ++#endif ++ //c->ases |= MIPS_ASE_XBURSTMXU; ++ } ++ break; ++ case PRID_IMP_XBURST2: ++ { ++ c->cputype = CPU_JZRISC; ++ __cpu_name[cpu] = "Ingenic XBurst@II"; + break; ++ } + default: + panic("Unknown Ingenic Processor ID!"); + break; +@@ -1444,6 +1495,7 @@ void cpu_probe(void) + { + struct cpuinfo_mips *c = ¤t_cpu_data; + unsigned int cpu = smp_processor_id(); ++ //unsigned long fpu_csr31 = 0; + + c->processor_id = PRID_IMP_UNKNOWN; + c->fpu_id = FPIR_IMP_NONE; +@@ -1482,6 +1534,7 @@ void cpu_probe(void) + case PRID_COMP_INGENIC_D0: + case PRID_COMP_INGENIC_D1: + case PRID_COMP_INGENIC_E1: ++ case PRID_COMP_INGENIC_13: + cpu_probe_ingenic(c, cpu); + break; + case PRID_COMP_NETLOGIC: +@@ -1512,7 +1565,20 @@ void cpu_probe(void) + } + + if (c->options & MIPS_CPU_FPU) ++ { ++ //fpu_fcr31 = cpu_test_fpu_csr31(FPU_CSR_DEFAULT); + cpu_set_fpu_opts(c); ++ #if 0 ++ if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M32R2 | ++ MIPS_CPU_ISA_M64R1 | MIPS_CPU_ISA_M64R2)) { ++ if (c->fpu_id & MIPS_FPIR_3D) ++ c->ases |= MIPS_ASE_MIPS3D; ++ if (c->fpu_id & MIPS_FPIR_HAS2008) ++ fpu_fcr31 = cpu_test_fpu_csr31(FPU_CSR_DEFAULT|FPU_CSR_MAC2008|FPU_CSR_ABS2008|FPU_CSR_NAN2008); ++ } ++ #endif ++ ++ } + else + cpu_set_nofpu_opts(c); + diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_kernel_genex.S.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_kernel_genex.S.patch new file mode 100644 index 00000000..561678ba --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_kernel_genex.S.patch @@ -0,0 +1,15 @@ +diff -drupN a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S +--- a/arch/mips/kernel/genex.S 2017-10-21 18:09:07.000000000 +0300 ++++ b/arch/mips/kernel/genex.S 2022-06-09 05:02:27.000000000 +0300 +@@ -506,7 +506,11 @@ NESTED(nmi_handler, PT_SIZE, sp) + BUILD_HANDLER tr tr sti silent /* #13 */ + BUILD_HANDLER msa_fpe msa_fpe msa_fpe silent /* #14 */ + BUILD_HANDLER fpe fpe fpe silent /* #15 */ ++#ifdef CONFIG_XBURST_MXUV2 ++ BUILD_HANDLER mfpe mfpe none silent /* #16 */ ++#else + BUILD_HANDLER ftlb ftlb none silent /* #16 */ ++#endif + BUILD_HANDLER msa msa sti silent /* #21 */ + BUILD_HANDLER mdmx mdmx sti silent /* #22 */ + #ifdef CONFIG_HARDWARE_WATCHPOINTS diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_kernel_idle.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_kernel_idle.c.patch new file mode 100644 index 00000000..e9d27631 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_kernel_idle.c.patch @@ -0,0 +1,55 @@ +diff -drupN a/arch/mips/kernel/idle.c b/arch/mips/kernel/idle.c +--- a/arch/mips/kernel/idle.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/arch/mips/kernel/idle.c 2022-06-09 05:02:27.000000000 +0300 +@@ -52,6 +52,30 @@ void r4k_wait(void) + __r4k_wait(); + } + ++#ifdef X2000_IDLE_PD ++extern int x2000_pm_enter(void); ++static void ingenic_wait_irqoff_pd(void) ++{ ++ WARN_ON_ONCE(!irqs_disabled()); ++ x2000_pm_enter(PM_SUSPEND_STANDBY); ++ local_irq_enable(); ++} ++#else ++void ingenic_wait_irqoff(void) ++{ ++ local_irq_disable(); ++ if (!need_resched()) ++ __asm__( ++ " .set push \n" ++ " .set arch=r4000 \n" ++ " sync \n" ++ " wait \n" ++ " .set pop \n"); ++ local_irq_enable(); ++} ++#endif ++ ++ + /* + * This variant is preferable as it allows testing need_resched and going to + * sleep depending on the outcome atomically. Unfortunately the "It is +@@ -175,12 +199,19 @@ void __init check_wait(void) + case CPU_CAVIUM_OCTEON_PLUS: + case CPU_CAVIUM_OCTEON2: + case CPU_CAVIUM_OCTEON3: +- case CPU_JZRISC: + case CPU_LOONGSON1: + case CPU_XLR: + case CPU_XLP: + cpu_wait = r4k_wait; + break; ++ case CPU_JZRISC: ++#ifdef X2000_IDLE_PD ++ cpu_wait = ingenic_wait_irqoff_pd; ++#else ++ cpu_wait = ingenic_wait_irqoff; ++#endif ++ ++ break; + case CPU_BMIPS5000: + cpu_wait = r4k_wait_irqoff; + break; diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_kernel_perf_event_mipsxx.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_kernel_perf_event_mipsxx.c.patch new file mode 100644 index 00000000..ba8e188e --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_kernel_perf_event_mipsxx.c.patch @@ -0,0 +1,137 @@ +diff -drupN a/arch/mips/kernel/perf_event_mipsxx.c b/arch/mips/kernel/perf_event_mipsxx.c +--- a/arch/mips/kernel/perf_event_mipsxx.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/arch/mips/kernel/perf_event_mipsxx.c 2022-06-09 05:02:27.000000000 +0300 +@@ -551,12 +551,33 @@ static atomic_t active_events = ATOMIC_I + static DEFINE_MUTEX(pmu_reserve_mutex); + static int (*save_perf_irq)(void); + ++static void enable_interrupt(void *args) ++{ ++ enable_percpu_irq(mipspmu.irq, IRQ_TYPE_LEVEL_HIGH); ++} ++static void disable_interrupt(void *args) ++{ ++ disable_percpu_irq(mipspmu.irq); ++} + static int mipspmu_get_irq(void) + { + int err; + + if (mipspmu.irq >= 0) { + /* Request my own irq handler. */ ++#ifdef CONFIG_MACH_XBURST2 ++ /* on ingenic xburst2 cpu, should request percpu interrupt. */ ++ err = request_percpu_irq(mipspmu.irq, mipsxx_pmu_handle_irq, ++ "mips_perf_pmu", &mipspmu); ++ ++ if (err) { ++ pr_warning("Unable to request IRQ%d for MIPS " ++ "performance counters!\n", mipspmu.irq); ++ } else { ++ /* enable all cpus interrtup here. */ ++ on_each_cpu(enable_interrupt, NULL, 1); ++ } ++#else + err = request_irq(mipspmu.irq, mipsxx_pmu_handle_irq, + IRQF_PERCPU | IRQF_NOBALANCING | + IRQF_NO_THREAD | IRQF_NO_SUSPEND | +@@ -566,6 +587,8 @@ static int mipspmu_get_irq(void) + pr_warn("Unable to request IRQ%d for MIPS performance counters!\n", + mipspmu.irq); + } ++ ++#endif + } else if (cp0_perfcount_irq < 0) { + /* + * We are sharing the irq number with the timer interrupt. +@@ -583,9 +606,15 @@ static int mipspmu_get_irq(void) + + static void mipspmu_free_irq(void) + { +- if (mipspmu.irq >= 0) +- free_irq(mipspmu.irq, &mipspmu); +- else if (cp0_perfcount_irq < 0) ++ if (mipspmu.irq >= 0) { ++#ifdef CONFIG_MACH_XBURST2 ++ /* disable interrupt on all cpus */ ++ on_each_cpu(disable_interrupt, NULL, 1); ++ free_percpu_irq(mipspmu.irq, &mipspmu); ++#else ++ free_irq(mipspmu.irq, NULL); ++#endif ++ } else if (cp0_perfcount_irq < 0) + perf_irq = save_perf_irq; + } + +@@ -858,6 +887,13 @@ static const struct mips_perf_event xlp_ + [PERF_COUNT_HW_BRANCH_MISSES] = { 0x1c, CNTR_ALL }, /* PAPI_BR_MSP */ + }; + ++static const struct mips_perf_event ingenic_event_map[PERF_COUNT_HW_MAX] = { ++ [PERF_COUNT_HW_CPU_CYCLES] = { 0x00, CNTR_EVEN | CNTR_ODD, P }, ++ [PERF_COUNT_HW_INSTRUCTIONS] = { 0x01, CNTR_EVEN | CNTR_ODD, T }, ++ [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = { 0x02, CNTR_EVEN, T }, ++ [PERF_COUNT_HW_BRANCH_MISSES] = { 0x02, CNTR_ODD, T }, ++}; ++ + /* 24K/34K/1004K/interAptiv/loongson1 cores share the same cache event map. */ + static const struct mips_perf_event mipsxxcore_cache_map + [PERF_COUNT_HW_CACHE_MAX] +@@ -1227,6 +1263,45 @@ static const struct mips_perf_event xlp_ + }, + }; + ++static const struct mips_perf_event ingenic_cache_map ++ [PERF_COUNT_HW_CACHE_MAX] ++ [PERF_COUNT_HW_CACHE_OP_MAX] ++ [PERF_COUNT_HW_CACHE_RESULT_MAX] = { ++[C(L1D)] = { ++ /* ++ * Like some other architectures (e.g. ARM), the performance ++ * counters don't differentiate between read and write ++ * accesses/misses, so this isn't strictly correct, but it's the ++ * best we can do. Writes and reads get combined. ++ */ ++ [C(OP_READ)] = { ++ [C(RESULT_ACCESS)] = { 0x04, CNTR_EVEN, T }, ++ [C(RESULT_MISS)] = { 0x04, CNTR_ODD, T }, ++ }, ++ [C(OP_WRITE)] = { ++ [C(RESULT_ACCESS)] = { 0x05, CNTR_EVEN, T }, ++ [C(RESULT_MISS)] = { 0x05, CNTR_ODD, T }, ++ }, ++}, ++[C(L1I)] = { ++ [C(OP_READ)] = { ++ [C(RESULT_ACCESS)] = { 0x07, CNTR_EVEN, T }, ++ [C(RESULT_MISS)] = { 0x07, CNTR_ODD, T }, ++ }, ++}, ++[C(DTLB)] = { ++ [C(OP_READ)] = { ++ [C(RESULT_ACCESS)] = { 0x09, CNTR_EVEN, T }, ++ [C(RESULT_MISS)] = { 0x09, CNTR_ODD, T }, ++ }, ++}, ++[C(ITLB)] = { ++ [C(OP_READ)] = { ++ [C(RESULT_ACCESS)] = { 0x08, CNTR_EVEN, T }, ++ [C(RESULT_MISS)] = { 0x08, CNTR_ODD, T }, ++ }, ++}, ++}; + #ifdef CONFIG_MIPS_MT_SMP + static void check_and_calc_range(struct perf_event *event, + const struct mips_perf_event *pev) +@@ -1767,6 +1842,11 @@ init_hw_perf_events(void) + mipspmu.cache_event_map = &xlp_cache_map; + mipspmu.map_raw_event = xlp_pmu_map_raw_event; + break; ++ case CPU_JZRISC: ++ mipspmu.name = "ingenic"; ++ mipspmu.general_event_map = &ingenic_event_map; ++ mipspmu.cache_event_map = &ingenic_cache_map; ++ break; + default: + pr_cont("Either hardware does not support performance " + "counters, or not yet implemented.\n"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_kernel_proc.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_kernel_proc.c.patch new file mode 100644 index 00000000..7df08cd9 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_kernel_proc.c.patch @@ -0,0 +1,12 @@ +diff -drupN a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c +--- a/arch/mips/kernel/proc.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/arch/mips/kernel/proc.c 2022-06-09 05:02:27.000000000 +0300 +@@ -121,6 +121,8 @@ static int show_cpuinfo(struct seq_file + if (cpu_has_eva) seq_printf(m, "%s", " eva"); + if (cpu_has_htw) seq_printf(m, "%s", " htw"); + if (cpu_has_xpa) seq_printf(m, "%s", " xpa"); ++ if (cpu_has_mxu) seq_printf(m, "%s", " mxu"); ++ if (cpu_has_mxuv3) seq_printf(m, "%s", " mxuv3"); + seq_printf(m, "\n"); + + if (cpu_has_mmips) { diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_kernel_process.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_kernel_process.c.patch new file mode 100644 index 00000000..b5128dfe --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_kernel_process.c.patch @@ -0,0 +1,36 @@ +diff -drupN a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c +--- a/arch/mips/kernel/process.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/arch/mips/kernel/process.c 2022-06-09 05:02:27.000000000 +0300 +@@ -45,6 +45,8 @@ + #include + #include + #include ++#include ++#include + + #ifdef CONFIG_HOTPLUG_CPU + void arch_cpu_idle_dead(void) +@@ -63,12 +65,13 @@ void start_thread(struct pt_regs * regs, + unsigned long status; + + /* New thread loses kernel privileges. */ +- status = regs->cp0_status & ~(ST0_CU0|ST0_CU1|ST0_FR|KU_MASK); ++ status = regs->cp0_status & ~(ST0_CU0|ST0_CU1|ST0_CU2|ST0_FR|KU_MASK); + status |= KU_USER; + regs->cp0_status = status; + clear_used_math(); + clear_fpu_owner(); + init_dsp(); ++ init_mxu(); + clear_thread_flag(TIF_USEDMSA); + clear_thread_flag(TIF_MSA_CTX_LIVE); + disable_msa(); +@@ -102,6 +105,8 @@ int arch_dup_task_struct(struct task_str + + save_dsp(current); + ++ //save_mxu(current); ++ + preempt_enable(); + + *dst = *src; diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_kernel_setup.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_kernel_setup.c.patch new file mode 100644 index 00000000..6a369723 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_kernel_setup.c.patch @@ -0,0 +1,172 @@ +diff -drupN a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c +--- a/arch/mips/kernel/setup.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/arch/mips/kernel/setup.c 2022-06-09 05:02:27.000000000 +0300 +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -625,6 +626,89 @@ static void __init request_crashkernel(s + #define USE_DTB_CMDLINE IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_DTB) + #define EXTEND_WITH_PROM IS_ENABLED(CONFIG_MIPS_CMDLINE_EXTEND) + ++#ifdef CONFIG_LINUX_PMEM ++static unsigned long g_pmem_total_size=0; ++static unsigned long g_pmem_start=0; ++static int g_pmem_set_by_cmdline=0; ++ ++#if 0 ++/* called in arch/mips/xburst2/soc-x2000-v12/setup.c */ ++unsigned long set_reserved_pmem_total_size(unsigned long size) ++{ ++ g_pmem_total_size = size; ++ return 0; ++} ++#endif ++ ++unsigned long get_reserved_pmem_size(void) ++{ ++ return g_pmem_total_size; ++} ++ ++unsigned long get_reserved_pmem_start(void) ++{ ++ return g_pmem_start; ++} ++ ++static int __init pmem_parse(char *str) ++{ ++ char *retptr; ++ unsigned long pmem_size; ++ unsigned long pmem_base = -1; ++ ++ pmem_size = memparse(str, &retptr); ++ if(pmem_size < 0) { ++ printk("pmem_size is error!\n"); ++ /* pmem_size = 0x4000000; */ ++ goto abort; ++ } ++ ++ if (*retptr == '@') ++ pmem_base = memparse(retptr + 1, NULL); ++ ++ if(pmem_base < 0) { ++ printk("pmem_base is error!\n"); ++ /* pmem_base = 0xc000000; */ ++ goto abort; ++ } ++ ++ g_pmem_start = pmem_base; ++ g_pmem_total_size = pmem_size; ++ g_pmem_set_by_cmdline = 1; ++ ++ return 1; ++abort: ++ return 0; ++} ++__setup("pmem=", pmem_parse); ++ ++static unsigned int str2(unsigned int *i, const char *str, int v) ++{ ++ unsigned int temp = 0; ++ ++ while(*str != 0) { ++ if((*str>='0') && (*str<='9') && (v == 10)) ++ temp = temp*v + (*str - '0'); ++ else if ((*str>='A') && (*str<='F') && (v == 16)) ++ temp = temp*v + (*str - 'A') + 10; ++ else ++ break; ++ str++; ++ } ++ ++ *i = temp; ++ ++ if (v == 10) { ++ if (*str == 'M') ++ return 1024 * 1024; ++ else if (*str == 'K') ++ return 1024; ++ } ++ ++ return 1; ++} ++#endif /* CONFIG_LINUX_PMEM */ ++ + static void __init arch_mem_init(char **cmdline_p) + { + struct memblock_region *reg; +@@ -678,6 +762,59 @@ static void __init arch_mem_init(char ** + pr_info("User-defined physical RAM map:\n"); + print_memory_map(); + } ++#ifdef CONFIG_LINUX_PMEM ++ /* reserve memory for pmem. */ ++ if (g_pmem_set_by_cmdline == 0) { ++ char *str = CONFIG_PMEM_RESERVE_SIZE; ++ unsigned int size; ++ ++ do { ++ if (strlen(str) == 1) { ++ g_pmem_total_size = 0; ++ break; ++ } else if ((*(str+1) == 'x') || (*(str+1) == 'X')) { ++ str2(&size, str+2, 16); ++ g_pmem_total_size = size; ++ break; ++ } else { ++ unsigned int f = str2(&size, str, 10); ++ g_pmem_total_size = size * f; ++ break; ++ } ++ } while(0); ++ } ++ ++ printk(KERN_INFO "reserve memory for pmem, g_pmem_total_size: %#x\n", (unsigned int)g_pmem_total_size); ++ if ( g_pmem_total_size > 0x10000 ) { ++ int i; ++ const int field = 2 * sizeof(unsigned long); ++ ++ for (i = boot_mem_map.nr_map-1; i>-1; i--) { ++ ++ if (BOOT_MEM_RAM == boot_mem_map.map[i].type ++ && (unsigned long)boot_mem_map.map[i].size > g_pmem_total_size) { ++ ++ printk(KERN_INFO " original, memory %d: %0*Lx @ %0*Lx \n", i, ++ field, (unsigned long long) boot_mem_map.map[i].size, ++ field, (unsigned long long) boot_mem_map.map[i].addr); ++ ++ boot_mem_map.map[i].size -= g_pmem_total_size; ++ g_pmem_start = (unsigned long)boot_mem_map.map[i].addr + (unsigned long)boot_mem_map.map[i].size; ++ ++ printk(KERN_INFO "after reserve pmem, memory %d: %0*Lx @ %0*Lx \n", i, ++ field, (unsigned long long) boot_mem_map.map[i].size, ++ field, (unsigned long long) boot_mem_map.map[i].addr); ++ ++ printk(KERN_INFO " reserve memory for pmem: %0*Lx @ %0*Lx ", ++ field, (unsigned long long) g_pmem_total_size, ++ field, (unsigned long long) g_pmem_start); ++ printk(KERN_INFO "\n"); ++ ++ break; ++ } ++ } ++ } ++#endif /* CONFIG_LINUX_PMEM */ + + bootmem_init(); + #ifdef CONFIG_PROC_VMCORE +@@ -701,6 +838,10 @@ static void __init arch_mem_init(char ** + plat_swiotlb_setup(); + paging_init(); + ++ ++ early_init_fdt_reserve_self(); ++ early_init_fdt_scan_reserved_mem(); ++ + dma_contiguous_reserve(PFN_PHYS(max_low_pfn)); + /* Tell bootmem about cma reserved memblock section */ + for_each_memblock(reserved, reg) diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_kernel_signal.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_kernel_signal.c.patch new file mode 100644 index 00000000..b0c86236 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_kernel_signal.c.patch @@ -0,0 +1,43 @@ +diff -drupN a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c +--- a/arch/mips/kernel/signal.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/arch/mips/kernel/signal.c 2022-06-09 05:02:27.000000000 +0300 +@@ -39,6 +39,7 @@ + #include + #include + #include ++#include + + #include "signal-common.h" + +@@ -440,6 +441,15 @@ int setup_sigcontext(struct pt_regs *reg + */ + err |= protected_save_fp_context(sc); + ++#ifdef CONFIG_MACH_XBURST ++ if (cpu_has_mxu) { ++ unsigned int *regs; ++ regs = __get_mxu_regs(current); ++ for (i = 0; i < NUM_MXU_REGS; i++){ ++ err |= __put_user(regs[i], &sc->sc_mxu[i]); ++ } ++ } ++#endif + return err; + } + +@@ -513,6 +523,15 @@ int restore_sigcontext(struct pt_regs *r + for (i = 1; i < 32; i++) + err |= __get_user(regs->regs[i], &sc->sc_regs[i]); + ++#ifdef CONFIG_MACH_XBURST ++ if (cpu_has_mxu) { ++ unsigned int regs[NUM_MXU_REGS]; ++ for (i = 0; i < NUM_MXU_REGS; i++){ ++ err |= __get_user(regs[i], &sc->sc_mxu[i]); ++ } ++ __let_mxu_regs(current,regs); ++ } ++#endif + return err ?: protected_restore_fp_context(sc); + } + diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_kernel_smp.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_kernel_smp.c.patch new file mode 100644 index 00000000..1a12e424 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_kernel_smp.c.patch @@ -0,0 +1,23 @@ +diff -drupN a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c +--- a/arch/mips/kernel/smp.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/arch/mips/kernel/smp.c 2022-06-09 05:02:27.000000000 +0300 +@@ -247,6 +247,8 @@ void smp_prepare_boot_cpu(void) + + int __cpu_up(unsigned int cpu, struct task_struct *tidle) + { ++ unsigned int timeout = 0xff; ++ + mp_ops->boot_secondary(cpu, tidle); + + /* +@@ -256,6 +258,10 @@ int __cpu_up(unsigned int cpu, struct ta + udelay(100); + schedule(); + } ++ while (!(cpumask_test_cpu(cpu, cpu_online_mask) || !timeout--)) { ++ udelay(100); ++ schedule(); ++ } + + synchronise_count_master(cpu); + return 0; diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_kernel_traps.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_kernel_traps.c.patch new file mode 100644 index 00000000..0d39d3d9 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_kernel_traps.c.patch @@ -0,0 +1,137 @@ +diff -drupN a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c +--- a/arch/mips/kernel/traps.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/arch/mips/kernel/traps.c 2022-06-09 05:02:27.000000000 +0300 +@@ -64,6 +64,8 @@ + #include + #include + #include ++#include ++ + + extern void check_wait(void); + extern asmlinkage void rollback_handle_int(void); +@@ -85,7 +87,11 @@ extern asmlinkage void handle_ov(void); + extern asmlinkage void handle_tr(void); + extern asmlinkage void handle_msa_fpe(void); + extern asmlinkage void handle_fpe(void); ++#ifdef CONFIG_XBURST_MXUV2 ++extern asmlinkage void handle_mfpe(void); ++#else + extern asmlinkage void handle_ftlb(void); ++#endif + extern asmlinkage void handle_msa(void); + extern asmlinkage void handle_mdmx(void); + extern asmlinkage void handle_watch(void); +@@ -873,6 +879,14 @@ out: + exception_exit(prev_state); + } + ++#ifdef CONFIG_MACH_XBURST ++asmlinkage void do_mfpe(struct pt_regs * regs) ++{ ++ die_if_kernel("Kernel bug detected", regs); ++ force_sig(SIGILL, current); ++} ++#endif ++ + void do_trap_or_bp(struct pt_regs *regs, unsigned int code, + const char *str) + { +@@ -1077,6 +1091,21 @@ asmlinkage void do_ri(struct pt_regs *re + unsigned int opcode = 0; + int status = -1; + ++ /* If Config1.CU2 is not set, the exc_code = 10 of cause reg */ ++ if (cpu_has_mxuv3 && (1 == smp_processor_id())) { ++ printk("%s(%d):reschedule to cpu0 to smp_processor_id()=%d, read_c0_status()=0x%x, task_cpu(current)=%d, KSTK_STATUS(current)=0x%lx, current->tgid=%d, current->pid=%d\n", __func__, __LINE__, smp_processor_id(), read_c0_status(), task_cpu(current), KSTK_STATUS(current), current->tgid, current->pid); ++ //resched_cpu(0); ++ write_c0_cache(0x2000ff0f); ++ smp_send_reschedule(0); ++ if (0 == smp_processor_id()) { ++ printk("%s(%d):open cu2 field to cpu0 to smp_processor_id()=%d, read_c0_status()=0x%x, task_cpu(current)=%d, KSTK_STATUS(current)=0x%lx, current->tgid=%d, current->pid=%d\n", __func__, __LINE__, smp_processor_id(), read_c0_status(), task_cpu(current), KSTK_STATUS(current), current->tgid, current->pid); ++ set_c0_status(ST0_CU2); ++ KSTK_STATUS(current) |= ST0_CU2; ++ } ++ printk("%s(%d):no cu2 coprocessor to smp_processor_id()=%d, read_c0_status()=0x%x, task_cpu(current)=%d, KSTK_STATUS(current)=0x%lx, current->tgid=%d, current->pid=%d\n", __func__, __LINE__, smp_processor_id(), read_c0_status(), task_cpu(current), KSTK_STATUS(current), current->tgid, current->pid); ++ return; ++ } ++ + /* + * Avoid any kernel code. Just emulate the R2 instruction + * as quickly as possible. +@@ -1445,10 +1474,38 @@ asmlinkage void do_cpu(struct pt_regs *r + break; + + case 2: ++#ifdef CONFIG_MACH_XBURST2 ++#if 0 ++ /* Processing of MXA instructions needs setting MSA enable. */ ++ if (cpu_has_mxuv3 && (KSTK_STATUS(current) & ST0_CU2)) { ++ err = enable_restore_fp_context(0); ++ if (err) { ++ printk("===debug CU2 exception, KSTK_STATUS(current) & ST0_CU2=0x%lx\n", KSTK_STATUS(current) & ST0_CU2); ++ force_sig(SIGILL, current); ++ } ++ } ++ ++#else ++ ++ /* To Xburst2 T40, If Status.CU2 is not set and Config1.CU2 is set, the exc_code is 10 and CE field is 2 to Cause Reg ++ * So here only need to open the Status.CU2 field */ ++ if (cpu_has_mxuv3 && (0 == smp_processor_id())) { ++ set_c0_status(ST0_CU2); ++ KSTK_STATUS(current) |= ST0_CU2; ++// printk("%s(%d):open cu2 field to cpu0 to smp_processor_id()=%d, read_c0_status()=0x%x, task_cpu(current)=%d, KSTK_STATUS(current)=0x%lx, current->tgid=%d, current->pid=%d\n", __func__, __LINE__, smp_processor_id(), read_c0_status(), task_cpu(current), KSTK_STATUS(current), current->tgid, current->pid); ++ goto out; ++ } else if (1 == smp_processor_id()) { ++ printk("%s(%d):no cu2 coprocessor to smp_processor_id()=%d, read_c0_status()=0x%x, task_cpu(current)=%d, KSTK_STATUS(current)=0x%lx, current->tgid=%d, current->pid=%d\n", __func__, __LINE__, smp_processor_id(), read_c0_status(), task_cpu(current), KSTK_STATUS(current), current->tgid, current->pid); ++ force_sig(SIGILL, current); ++ goto out; ++ } ++#endif ++#else + raw_notifier_call_chain(&cu2_chain, CU2_EXCEPTION, regs); +- break; ++#endif ++ goto out; + } +- ++out: + exception_exit(prev_state); + } + +@@ -2070,6 +2127,9 @@ static void configure_status(void) + status_set |= ST0_XX; + if (cpu_has_dsp) + status_set |= ST0_MX; ++ if (cpu_has_mxuv3 && (KSTK_STATUS(current) & ST0_CU2)) { ++ status_set |= ST0_CU2; ++ } + + change_c0_status(ST0_CU|ST0_MX|ST0_RE|ST0_FR|ST0_BEV|ST0_TS|ST0_KX|ST0_SX|ST0_UX, + status_set); +@@ -2087,7 +2147,7 @@ static void configure_hwrena(void) + hwrena |= (1 << 29); + + if (hwrena) +- write_c0_hwrena(hwrena); ++ write_c0_hwrena(0x2000ff0f); + } + + static void configure_exception_vector(void) +@@ -2321,8 +2381,14 @@ void __init trap_init(void) + if (cpu_has_fpu && !cpu_has_nofpuex) + set_except_vector(15, handle_fpe); + ++#ifdef CONFIG_XBURST_MXUV2 ++ if (cpu_has_mxu) ++ set_except_vector(16, handle_fpe); ++ if (cpu_has_mxuv3) ++ set_except_vector(16, handle_fpe); ++#else + set_except_vector(16, handle_ftlb); +- ++#endif + if (cpu_has_rixiex) { + set_except_vector(19, tlb_do_page_fault_0); + set_except_vector(20, tlb_do_page_fault_0); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_mm_c-r4k.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_mm_c-r4k.c.patch new file mode 100644 index 00000000..8a63be48 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_mm_c-r4k.c.patch @@ -0,0 +1,123 @@ +diff -drupN a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c +--- a/arch/mips/mm/c-r4k.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/arch/mips/mm/c-r4k.c 2022-06-09 05:02:27.000000000 +0300 +@@ -60,8 +60,10 @@ static inline void r4k_on_each_cpu(void + * to restrict that call when a CM is not present because both + * CM-based SMP protocols (CMP & CPS) restrict index-based cache ops. + */ ++#ifndef CONFIG_MACH_XBURST2 + if (!mips_cm_present()) + smp_call_function_many(&cpu_foreign_map, func, info, 1); ++#endif + func(info); + preempt_enable(); + } +@@ -378,9 +380,13 @@ static void r4k_blast_scache_page_setup( + { + unsigned long sc_lsize = cpu_scache_line_size(); + +- if (scache_size == 0) ++ if (scache_size == 0) { ++#ifdef MIPS_BRIDGE_SYNC_WAR ++ r4k_blast_scache_page = (void *)blast_inclusive_scache; /*CONFIG_MACH_XBURST*/ ++#else + r4k_blast_scache_page = (void *)cache_noop; +- else if (sc_lsize == 16) ++#endif ++ } else if (sc_lsize == 16) + r4k_blast_scache_page = blast_scache16_page; + else if (sc_lsize == 32) + r4k_blast_scache_page = blast_scache32_page; +@@ -396,9 +402,13 @@ static void r4k_blast_scache_page_indexe + { + unsigned long sc_lsize = cpu_scache_line_size(); + +- if (scache_size == 0) ++ if (scache_size == 0) { ++#ifdef MIPS_BRIDGE_SYNC_WAR ++ r4k_blast_scache_page_indexed = (void *)blast_inclusive_scache; /*CONFIG_MACH_XBURST*/ ++#else + r4k_blast_scache_page_indexed = (void *)cache_noop; +- else if (sc_lsize == 16) ++#endif ++ } else if (sc_lsize == 16) + r4k_blast_scache_page_indexed = blast_scache16_page_indexed; + else if (sc_lsize == 32) + r4k_blast_scache_page_indexed = blast_scache32_page_indexed; +@@ -414,9 +424,13 @@ static void r4k_blast_scache_setup(void) + { + unsigned long sc_lsize = cpu_scache_line_size(); + +- if (scache_size == 0) ++ if (scache_size == 0) { ++#ifdef MIPS_BRIDGE_SYNC_WAR ++ r4k_blast_scache = (void *)blast_inclusive_scache; /*CONFIG_MACH_XBURST*/ ++#else + r4k_blast_scache = (void *)cache_noop; +- else if (sc_lsize == 16) ++#endif ++ } else if (sc_lsize == 16) + r4k_blast_scache = blast_scache16; + else if (sc_lsize == 32) + r4k_blast_scache = blast_scache32; +@@ -770,7 +784,18 @@ static void r4k_dma_cache_inv(unsigned l + if (cpu_has_safe_index_cacheops && size >= dcache_size) { + r4k_blast_dcache(); + } else { ++#if defined(CONFIG_MACH_XBURST) || defined(CONFIG_MACH_XBURST2) ++ unsigned long lsize = cpu_dcache_line_size(); ++ unsigned long cmask = (lsize - 1); ++ unsigned long lmask = ~(cmask); ++#endif + R4600_HIT_CACHEOP_WAR_IMPL; ++#if defined(CONFIG_MACH_XBURST) || defined(CONFIG_MACH_XBURST2) ++ if (addr & cmask) ++ cache_op(Hit_Writeback_Inv_D, addr & lmask); ++ if ((addr + size) & cmask) ++ cache_op(Hit_Writeback_Inv_D, (addr + size - 1) & lmask); ++#endif + blast_inv_dcache_range(addr, addr + size); + } + preempt_enable(); +@@ -797,6 +822,10 @@ static void local_r4k_flush_cache_sigtra + protected_writeback_dcache_line(addr & ~(dc_lsize - 1)); + if (!cpu_icache_snoops_remote_store && scache_size) + protected_writeback_scache_line(addr & ~(sc_lsize - 1)); ++#ifdef MIPS_BRIDGE_SYNC_WAR ++ else if (!cpu_icache_snoops_remote_store && MIPS_BRIDGE_SYNC_WAR) /*CONFIG_MACH_XBURST*/ ++ __fast_iob(); ++#endif + if (ic_lsize) + protected_flush_icache_line(addr & ~(ic_lsize - 1)); + if (MIPS4K_ICACHE_REFILL_WAR) { +@@ -1487,6 +1516,9 @@ static void setup_scache(void) + case CPU_LOONGSON3: + loongson3_sc_init(); + return; ++ case CPU_JZRISC: ++ mips_sc_init(); ++ return; + + case CPU_CAVIUM_OCTEON3: + case CPU_XLP: +@@ -1497,7 +1529,7 @@ static void setup_scache(void) + if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M32R2 | + MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R1 | + MIPS_CPU_ISA_M64R2 | MIPS_CPU_ISA_M64R6)) { +-#ifdef CONFIG_MIPS_CPU_SCACHE ++#if defined(CONFIG_MIPS_CPU_SCACHE) + if (mips_sc_init ()) { + scache_size = c->scache.ways * c->scache.sets * c->scache.linesz; + printk("MIPS secondary cache %ldkB, %s, linesize %d bytes.\n", +@@ -1590,7 +1622,10 @@ static void coherency_setup(void) + if (cca < 0 || cca > 7) + cca = read_c0_config() & CONF_CM_CMASK; + _page_cachable_default = cca << _CACHE_SHIFT; +- ++#ifdef CONFIG_MACH_XBURST ++ if (cca == CONF_CM_UNCACHED || cca == CONF_CM_CACHABLE_ACCELERATED) ++ pr_warn("WARNNIGG: Using Uncacheable Kseg0\n"); ++#endif + pr_debug("Using cache attribute %d\n", cca); + change_c0_config(CONF_CM_CMASK, cca); + diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_mm_dma-default.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_mm_dma-default.c.patch new file mode 100644 index 00000000..d25152f7 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_mm_dma-default.c.patch @@ -0,0 +1,120 @@ +diff -drupN a/arch/mips/mm/dma-default.c b/arch/mips/mm/dma-default.c +--- a/arch/mips/mm/dma-default.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/arch/mips/mm/dma-default.c 2022-06-09 05:02:27.000000000 +0300 +@@ -72,7 +72,8 @@ static inline int cpu_needs_post_dma_flu + return !plat_device_is_coherent(dev) && + (boot_cpu_type() == CPU_R10000 || + boot_cpu_type() == CPU_R12000 || +- boot_cpu_type() == CPU_BMIPS5000); ++ boot_cpu_type() == CPU_BMIPS5000 || ++ boot_cpu_type() == CPU_JZRISC); + } + + static gfp_t massage_gfp_flags(const struct device *dev, gfp_t gfp) +@@ -112,22 +113,6 @@ static gfp_t massage_gfp_flags(const str + return gfp | dma_flag; + } + +-static void *mips_dma_alloc_noncoherent(struct device *dev, size_t size, +- dma_addr_t * dma_handle, gfp_t gfp) +-{ +- void *ret; +- +- gfp = massage_gfp_flags(dev, gfp); +- +- ret = (void *) __get_free_pages(gfp, get_order(size)); +- +- if (ret != NULL) { +- memset(ret, 0, size); +- *dma_handle = plat_map_dma_mem(dev, ret, size); +- } +- +- return ret; +-} + + static void *mips_dma_alloc_coherent(struct device *dev, size_t size, + dma_addr_t * dma_handle, gfp_t gfp, struct dma_attrs *attrs) +@@ -136,12 +121,6 @@ static void *mips_dma_alloc_coherent(str + struct page *page = NULL; + unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT; + +- /* +- * XXX: seems like the coherent and non-coherent implementations could +- * be consolidated. +- */ +- if (dma_get_attr(DMA_ATTR_NON_CONSISTENT, attrs)) +- return mips_dma_alloc_noncoherent(dev, size, dma_handle, gfp); + + gfp = massage_gfp_flags(dev, gfp); + +@@ -157,6 +136,13 @@ static void *mips_dma_alloc_coherent(str + ret = page_address(page); + memset(ret, 0, size); + *dma_handle = plat_map_dma_mem(dev, ret, size); ++ ++ /* non coherent memory.*/ ++ if(dma_get_attr(DMA_ATTR_NON_CONSISTENT, attrs)) { ++ return ret; ++ } ++ ++ /* coherent memory. */ + if (!plat_device_is_coherent(dev)) { + dma_cache_wback_inv((unsigned long) ret, size); + if (!hw_coherentio) +@@ -167,12 +153,6 @@ static void *mips_dma_alloc_coherent(str + } + + +-static void mips_dma_free_noncoherent(struct device *dev, size_t size, +- void *vaddr, dma_addr_t dma_handle) +-{ +- plat_unmap_dma_mem(dev, dma_handle, size, DMA_BIDIRECTIONAL); +- free_pages((unsigned long) vaddr, get_order(size)); +-} + + static void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr, + dma_addr_t dma_handle, struct dma_attrs *attrs) +@@ -181,15 +161,13 @@ static void mips_dma_free_coherent(struc + unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT; + struct page *page = NULL; + +- if (dma_get_attr(DMA_ATTR_NON_CONSISTENT, attrs)) { +- mips_dma_free_noncoherent(dev, size, vaddr, dma_handle); +- return; +- } +- + plat_unmap_dma_mem(dev, dma_handle, size, DMA_BIDIRECTIONAL); + +- if (!plat_device_is_coherent(dev) && !hw_coherentio) +- addr = CAC_ADDR(addr); ++ if (!dma_get_attr(DMA_ATTR_NON_CONSISTENT, attrs)) { ++ /* coherent dma memory.*/ ++ if (!plat_device_is_coherent(dev) && !hw_coherentio) ++ addr = CAC_ADDR(addr); ++ } + + page = virt_to_page((void *) addr); + +@@ -273,8 +251,22 @@ static inline void __dma_sync(struct pag + if (offset >= PAGE_SIZE) { + page += offset >> PAGE_SHIFT; + offset &= ~PAGE_MASK; ++#ifdef CONFIG_DMA_INGENIC_HIGHMEM_FLUSH ++ /** ++ * Explain: ++ * When offset + len is less than PAGE_SIZE, ++ * only need to flush the length of len; ++ * Rather than flush PAGE_SIZE ++ */ ++ len = PAGE_SIZE - offset; ++ len = min(left, len); ++ } else { ++ len = PAGE_SIZE - offset; ++ } ++#else + } + len = PAGE_SIZE - offset; ++#endif + } + + addr = kmap_atomic(page); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_mm_tlb-r4k.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_mm_tlb-r4k.c.patch new file mode 100644 index 00000000..f5184cde --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_mm_tlb-r4k.c.patch @@ -0,0 +1,31 @@ +diff -drupN a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c +--- a/arch/mips/mm/tlb-r4k.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/arch/mips/mm/tlb-r4k.c 2022-06-09 05:02:27.000000000 +0300 +@@ -52,7 +52,7 @@ void local_flush_tlb_all(void) + { + unsigned long flags; + unsigned long old_ctx; +- int entry, ftlbhighset; ++ int entry; + + local_irq_save(flags); + /* Save old context and create impossible VPN2 value */ +@@ -65,6 +65,8 @@ void local_flush_tlb_all(void) + + /* Blast 'em all away. */ + if (cpu_has_tlbinv) { ++#ifndef CONFIG_MACH_XBURST2 ++ int ftlbhighset; + if (current_cpu_data.tlbsizevtlb) { + write_c0_index(0); + mtc0_tlbw_hazard(); +@@ -79,6 +81,9 @@ void local_flush_tlb_all(void) + mtc0_tlbw_hazard(); + tlbinvf(); /* invalidate one FTLB set */ + } ++#else ++ tlbinvf(); /* invalide FTLB/VTLB set */ ++#endif + } else { + while (entry < current_cpu_data.tlbsize) { + /* Make sure all entries differ. */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_vdso_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_vdso_Makefile.patch new file mode 100644 index 00000000..62feefb6 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_vdso_Makefile.patch @@ -0,0 +1,129 @@ +diff -drupN a/arch/mips/vdso/Makefile b/arch/mips/vdso/Makefile +--- a/arch/mips/vdso/Makefile 2017-10-21 18:09:07.000000000 +0300 ++++ b/arch/mips/vdso/Makefile 2022-06-09 05:02:27.000000000 +0300 +@@ -5,12 +5,10 @@ obj-vdso-y := elf.o gettimeofday.o sigre + ccflags-vdso := \ + $(filter -I%,$(KBUILD_CFLAGS)) \ + $(filter -E%,$(KBUILD_CFLAGS)) \ +- $(filter -mmicromips,$(KBUILD_CFLAGS)) \ + $(filter -march=%,$(KBUILD_CFLAGS)) + cflags-vdso := $(ccflags-vdso) \ + $(filter -W%,$(filter-out -Wa$(comma)%,$(KBUILD_CFLAGS))) \ +- -O2 -g -fPIC -fno-strict-aliasing -fno-common -fno-builtin -G 0 \ +- -DDISABLE_BRANCH_PROFILING \ ++ -O2 -g -fPIC -fno-common -fno-builtin -G 0 -DDISABLE_BRANCH_PROFILING \ + $(call cc-option, -fno-stack-protector) + aflags-vdso := $(ccflags-vdso) \ + $(filter -I%,$(KBUILD_CFLAGS)) \ +@@ -28,7 +26,7 @@ aflags-vdso := $(ccflags-vdso) \ + # the comments on that file. + # + ifndef CONFIG_CPU_MIPSR6 +- ifeq ($(call ld-ifversion, -lt, 22500000, y),y) ++ ifeq ($(call ld-ifversion, -lt, 225000000, y),y) + $(warning MIPS VDSO requires binutils >= 2.25) + obj-vdso-y := $(filter-out gettimeofday.o, $(obj-vdso-y)) + ccflags-vdso += -DDISABLE_MIPS_VDSO +@@ -52,13 +50,17 @@ quiet_cmd_vdsold = VDSO $@ + cmd_vdsold = $(CC) $(c_flags) $(VDSO_LDFLAGS) \ + -Wl,-T $(filter %.lds,$^) $(filter %.o,$^) -o $@ + ++# Strip rule for the raw .so files ++$(obj)/%.so.raw: OBJCOPYFLAGS := -S ++$(obj)/%.so.raw: $(obj)/%.so.dbg.raw FORCE ++ $(call if_changed,objcopy) ++ + hostprogs-y := genvdso + + quiet_cmd_genvdso = GENVDSO $@ + define cmd_genvdso +- cp $< $(<:%.dbg=%) && \ +- $(OBJCOPY) -S $< $(<:%.dbg=%) && \ +- $(obj)/genvdso $< $(<:%.dbg=%) $@ $(VDSO_NAME) ++ $(foreach file,$(filter %.raw,$^),cp $(file) $(file:%.raw=%) &&) \ ++ $(obj)/genvdso $(<:%.raw=%) $(<:%.dbg.raw=%) $@ $(VDSO_NAME) + endef + + # +@@ -68,19 +70,23 @@ endef + native-abi := $(filter -mabi=%,$(KBUILD_CFLAGS)) + + targets += $(obj-vdso-y) +-targets += vdso.lds vdso.so.dbg vdso.so vdso-image.c ++targets += vdso.lds ++targets += vdso.so.dbg.raw vdso.so.raw ++targets += vdso.so.dbg vdso.so ++targets += vdso-image.c + + obj-vdso := $(obj-vdso-y:%.o=$(obj)/%.o) + + $(obj-vdso): KBUILD_CFLAGS := $(cflags-vdso) $(native-abi) + $(obj-vdso): KBUILD_AFLAGS := $(aflags-vdso) $(native-abi) + +-$(obj)/vdso.lds: KBUILD_CPPFLAGS := $(ccflags-vdso) $(native-abi) ++$(obj)/vdso.lds: KBUILD_CPPFLAGS := $(native-abi) + +-$(obj)/vdso.so.dbg: $(obj)/vdso.lds $(obj-vdso) FORCE ++$(obj)/vdso.so.dbg.raw: $(obj)/vdso.lds $(obj-vdso) FORCE + $(call if_changed,vdsold) + +-$(obj)/vdso-image.c: $(obj)/vdso.so.dbg $(obj)/genvdso FORCE ++$(obj)/vdso-image.c: $(obj)/vdso.so.dbg.raw $(obj)/vdso.so.raw \ ++ $(obj)/genvdso FORCE + $(call if_changed,genvdso) + + obj-y += vdso-image.o +@@ -91,7 +97,10 @@ obj-y += vdso-image.o + + # Define these outside the ifdef to ensure they are picked up by clean. + targets += $(obj-vdso-y:%.o=%-o32.o) +-targets += vdso-o32.lds vdso-o32.so.dbg vdso-o32.so vdso-o32-image.c ++targets += vdso-o32.lds ++targets += vdso-o32.so.dbg.raw vdso-o32.so.raw ++targets += vdso-o32.so.dbg vdso-o32.so ++targets += vdso-o32-image.c + + ifdef CONFIG_MIPS32_O32 + +@@ -111,11 +120,12 @@ $(obj)/vdso-o32.lds: KBUILD_CPPFLAGS := + $(obj)/vdso-o32.lds: $(src)/vdso.lds.S FORCE + $(call if_changed_dep,cpp_lds_S) + +-$(obj)/vdso-o32.so.dbg: $(obj)/vdso-o32.lds $(obj-vdso-o32) FORCE ++$(obj)/vdso-o32.so.dbg.raw: $(obj)/vdso-o32.lds $(obj-vdso-o32) FORCE + $(call if_changed,vdsold) + + $(obj)/vdso-o32-image.c: VDSO_NAME := o32 +-$(obj)/vdso-o32-image.c: $(obj)/vdso-o32.so.dbg $(obj)/genvdso FORCE ++$(obj)/vdso-o32-image.c: $(obj)/vdso-o32.so.dbg.raw $(obj)/vdso-o32.so.raw \ ++ $(obj)/genvdso FORCE + $(call if_changed,genvdso) + + obj-y += vdso-o32-image.o +@@ -127,7 +137,10 @@ endif + # + + targets += $(obj-vdso-y:%.o=%-n32.o) +-targets += vdso-n32.lds vdso-n32.so.dbg vdso-n32.so vdso-n32-image.c ++targets += vdso-n32.lds ++targets += vdso-n32.so.dbg.raw vdso-n32.so.raw ++targets += vdso-n32.so.dbg vdso-n32.so ++targets += vdso-n32-image.c + + ifdef CONFIG_MIPS32_N32 + +@@ -147,11 +160,12 @@ $(obj)/vdso-n32.lds: KBUILD_CPPFLAGS := + $(obj)/vdso-n32.lds: $(src)/vdso.lds.S FORCE + $(call if_changed_dep,cpp_lds_S) + +-$(obj)/vdso-n32.so.dbg: $(obj)/vdso-n32.lds $(obj-vdso-n32) FORCE ++$(obj)/vdso-n32.so.dbg.raw: $(obj)/vdso-n32.lds $(obj-vdso-n32) FORCE + $(call if_changed,vdsold) + + $(obj)/vdso-n32-image.c: VDSO_NAME := n32 +-$(obj)/vdso-n32-image.c: $(obj)/vdso-n32.so.dbg $(obj)/genvdso FORCE ++$(obj)/vdso-n32-image.c: $(obj)/vdso-n32.so.dbg.raw $(obj)/vdso-n32.so.raw \ ++ $(obj)/genvdso FORCE + $(call if_changed,genvdso) + + obj-y += vdso-n32-image.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_Kconfig.patch new file mode 100644 index 00000000..df6b619c --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_Kconfig.patch @@ -0,0 +1,87 @@ +diff -drupN a/arch/mips/xburst2/Kconfig b/arch/mips/xburst2/Kconfig +--- a/arch/mips/xburst2/Kconfig 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/Kconfig 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,83 @@ ++if MACH_XBURST2 ++ ++menu "SOC Type Selection" ++ depends on MACH_XBURST2 ++ ++ ++choice ++ prompt "SOC types" ++ depends on MACH_XBURST2 ++ default SOC_T40 ++ ++ ++config SOC_T40 ++ bool "t40" ++ select IRQ_INGENIC_CPU ++ select CLK_T40 ++ select INGENIC_INTC_CHIP ++ select PINCTRL ++ select PINCTRL_INGENIC ++ select CLKSRC_OF ++ select CLKDEV_LOOKUP ++ select CLKSRC_INGENIC_CORE_OST ++ ++ ++config SOC_X2000_V12 ++ bool "x2000-v12" ++ select IRQ_INGENIC_CPU ++ select CLK_X2000_V12 ++ select INGENIC_INTC_CHIP ++ select PINCTRL ++ select PINCTRL_INGENIC ++ select CLKSRC_OF ++ select CLKDEV_LOOKUP ++ select CLKSRC_INGENIC_CORE_OST ++ ++endchoice ++ ++config INGENIC_BUILTIN_DTB ++ select BUILTIN_DTB ++ depends on MACH_XBURST2 ++ bool "Ingenic Device Tree build into Kernel." ++ default y ++ ++choice ++ prompt "device tree select" ++ default DT_NONE ++config DT_NONE ++ ++if SOC_T40 ++source "arch/mips/xburst2/soc-t40/Kconfig.DT" ++endif ++ ++if SOC_X2000_V12 ++source "arch/mips/xburst2/soc-x2000-v12/Kconfig.DT" ++endif ++ ++endchoice ++ ++config DT_T40_MODULE_BASE_DTS_FILE ++ string "dts file for T40 module driver" ++ depends on DT_T40_MODULE_BASE ++ default shark.dts ++ help ++ the dts file location is arch/mips/boot/dts/ingenic/ ++ ++config RAW_BOOT ++ bool "Raw Boot Kernel" ++ select BOOT_RAW ++ default n ++ ++config EXTAL_CLOCK ++ depends on MACH_XBURST2 ++ int "extal clock in MHz" ++ default 24 ++ ++config FPGA_TEST ++ depends on MACH_XBURST2 ++ bool "FPGA_TEST" ++ default n ++ ++endmenu ++ ++endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_Makefile.patch new file mode 100644 index 00000000..fe5734c9 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_Makefile.patch @@ -0,0 +1,9 @@ +diff -drupN a/arch/mips/xburst2/Makefile b/arch/mips/xburst2/Makefile +--- a/arch/mips/xburst2/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/Makefile 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,5 @@ ++obj-y += core/ ++obj-y += common/ ++ ++obj-$(CONFIG_SOC_T40) += soc-t40/ ++obj-$(CONFIG_SOC_X2000_V12) += soc-x2000-v12/ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_Platform.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_Platform.patch new file mode 100644 index 00000000..3bccf41d --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_Platform.patch @@ -0,0 +1,10 @@ +diff -drupN a/arch/mips/xburst2/Platform b/arch/mips/xburst2/Platform +--- a/arch/mips/xburst2/Platform 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/Platform 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,6 @@ ++platform-$(CONFIG_MACH_XBURST2) += xburst2/ ++load-$(CONFIG_MACH_XBURST2) += 0xffffffff80010000 ++cflags-$(CONFIG_MACH_XBURST2) += -I$(srctree)/arch/mips/xburst2/core/include ++ ++cflags-$(CONFIG_SOC_T40) += -I$(srctree)/arch/mips/xburst2/soc-t40/include ++cflags-$(CONFIG_SOC_X2000_V12) += -I$(srctree)/arch/mips/xburst2/soc-x2000-v12/include diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_Makefile.patch new file mode 100644 index 00000000..ac6e8a31 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_Makefile.patch @@ -0,0 +1,14 @@ +diff -drupN a/arch/mips/xburst2/common/Makefile b/arch/mips/xburst2/common/Makefile +--- a/arch/mips/xburst2/common/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/common/Makefile 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,10 @@ ++ ++# add object if need ++ ++#obj-y += prom.o ++obj-y += get-cpu-features.o ++obj-y += proc-exec.o ++obj-y += proc.o ++obj-y += mxuv3.o ++obj-y += jz_notifier.o ++obj-$(CONFIG_XBURST2_CPU_TEST) += cpu_ddr_test/ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_Makefile.patch new file mode 100644 index 00000000..561e768b --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_Makefile.patch @@ -0,0 +1,15 @@ +diff -drupN a/arch/mips/xburst2/common/cpu_ddr_test/Makefile b/arch/mips/xburst2/common/cpu_ddr_test/Makefile +--- a/arch/mips/xburst2/common/cpu_ddr_test/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/common/cpu_ddr_test/Makefile 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,11 @@ ++ ++obj-y += multithread_test.o ++obj-y += ddr_bandwidth_monitor.o ++obj-y += ddr_change_freq.o ++obj-y += l2c_test.o ++obj-y += cpu_spinlock_test.o ++obj-y += cpu_ccu_test.o ++obj-y += raw_dma_test.o ++obj-y += cpu_dma_test.o ++obj-y += cpu_watch_test.o ++ccflags-y += -Wno-unused-function diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_cpu_ccu_test.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_cpu_ccu_test.c.patch new file mode 100644 index 00000000..96c90520 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_cpu_ccu_test.c.patch @@ -0,0 +1,74 @@ +diff -drupN a/arch/mips/xburst2/common/cpu_ddr_test/cpu_ccu_test.c b/arch/mips/xburst2/common/cpu_ddr_test/cpu_ccu_test.c +--- a/arch/mips/xburst2/common/cpu_ddr_test/cpu_ccu_test.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/common/cpu_ddr_test/cpu_ccu_test.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,70 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "multithread_test.h" ++#include ++ ++#define PALLADIUM_TRIGER_2() do {\ ++ volatile unsigned int *a; \ ++ a = (unsigned int *)0xAFFFFFFC; \ ++ *a = *a; \ ++ } while(0) ++ ++struct cpu_ccu_test { ++ void* multithread; ++ unsigned int cnt; ++} cpu_ccu; ++ ++ ++static int cpu_ccu_test_func(void * param) ++{ ++ struct cpu_ccu_test *p = (struct cpu_ccu_test *)param; ++ unsigned int cscr, cssr, csrr, rer; ++ ++ cscr = get_ccu_cscr(); ++ ++ cssr = get_ccu_cssr(); ++ ++ csrr = get_ccu_csrr(); ++ ++ rer = get_ccu_rer(); ++ ++ p->cnt++; ++ ++ if(p->cnt == 1000) { ++ p->cnt = 0; ++ printk("%s: cscr=0x%08x, cssr=0x%08x, csrr=0x%08x, rer=0x%08x\n", __func__, cscr, cssr, csrr, rer); ++ } ++#ifdef CONFIG_FPGA_TEST ++ mdelay(100); ++#endif ++ return 0; ++} ++ ++static int __init cpu_ccu_test_init(void) ++{ ++ cpu_ccu.multithread = multithread_test_init("cpu_ccu_test",1); ++ ++ if(cpu_ccu.multithread){ ++ multithread_test_add_func(cpu_ccu.multithread,"cpu_ccu_test",cpu_ccu_test_func,(void*)&cpu_ccu); ++ } ++ return 0; ++} ++static void __exit cpu_ccu_test_deinit(void) ++{ ++} ++ ++late_initcall(cpu_ccu_test_init); ++module_exit(cpu_ccu_test_deinit); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_cpu_dma_test.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_cpu_dma_test.c.patch new file mode 100644 index 00000000..cee9c591 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_cpu_dma_test.c.patch @@ -0,0 +1,266 @@ +diff -drupN a/arch/mips/xburst2/common/cpu_ddr_test/cpu_dma_test.c b/arch/mips/xburst2/common/cpu_ddr_test/cpu_dma_test.c +--- a/arch/mips/xburst2/common/cpu_ddr_test/cpu_dma_test.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/common/cpu_ddr_test/cpu_dma_test.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,262 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++//#include ++#include ++#include ++ ++#include "multithread_test.h" ++#include "../../../../../drivers/dma/ingenic/ingenic_dma.h" ++ ++struct cpu_dma_test{ ++ void* multithread; ++ struct list_head dma_top; ++}cpu_dma; ++struct dma_channel { ++ struct list_head list; ++ struct dma_chan *chan; ++ struct hdma_desc *desc; ++ void *from; ++ unsigned long pfrom; ++ void *to; ++ unsigned long pto; ++ unsigned long test_len; ++ struct mutex lock; ++ unsigned long test_cnt; ++}; ++static void init_buf(struct dma_channel *dc) ++{ ++ int i; ++ ++ unsigned long *p = dc->from; ++ for(i = 0;i < dc->test_len/4;i++){ ++ p[i] = (unsigned int)p + i * 4; ++ } ++ ++ p = dc->to; ++ for(i = 0;i < dc->test_len/4;i++){ ++ p[i] = 0x5a5a5a5a; ++ } ++ dma_cache_sync(NULL,dc->from,dc->test_len,DMA_TO_DEVICE); ++ dma_cache_sync(NULL,dc->to,dc->test_len,DMA_FROM_DEVICE); ++} ++ ++static int cpu_dma_test_func_nowait(void * param) ++{ ++ struct dma_channel *dc = (struct dma_channel *)param; ++ int i; ++ mutex_lock(&dc->lock); ++ init_buf(dc); ++ { ++ struct ingenic_dma_chan *dmac = to_ingenic_dma_chan(dc->chan); ++ writel((unsigned int)virt_to_phys(dc->desc), dmac->iomem + CH_DDA); ++ /* initiate descriptor fetch */ ++ writel(BIT(dmac->id), dmac->engine->iomem + DDRS); ++ writel(1 | (1 << 30),dmac->iomem + CH_DCS); ++ } ++ ++ dc->test_cnt ++; ++ { ++ volatile unsigned long *p = (unsigned long *)CKSEG1ADDR(dc->to); ++ unsigned long e = (unsigned long)dc->from; ++ int timeout = 0x10000; ++ for(i = 0;i < dc->test_len/4;i++){ ++ timeout = 0x10000; ++ while((p[i] != e) && --timeout); ++ if(timeout==0){ ++ printk("xxxxxx error data is not ready! xxxxxx\n"); ++ while(1); ++ } ++ e += 4; ++ } ++ } ++ mutex_unlock(&dc->lock); ++#ifdef CONFIG_FPGA_TEST ++ mdelay(100); ++#endif ++ return 0; ++} ++static int cpu_dma_test_func_wait(void * param) ++{ ++ struct dma_channel *dc = (struct dma_channel *)param; ++ unsigned long *p = (unsigned long*)((unsigned long)dc->to + dc->test_len - 4); ++ unsigned long e = (unsigned long)dc->from + dc->test_len - 4; ++ unsigned long r; ++ int timeout = 0x10000; ++ ++ mutex_lock(&dc->lock); ++ init_buf(dc); ++ { ++ struct ingenic_dma_chan *dmac = to_ingenic_dma_chan(dc->chan); ++ ++ writel((unsigned int)virt_to_phys(dc->desc), dmac->iomem + CH_DDA); ++ /* initiate descriptor fetch */ ++ writel(BIT(dmac->id), dmac->engine->iomem + DDRS); ++ writel(1 | (1 << 30),dmac->iomem + CH_DCS); ++ while(!(readl(dmac->iomem + CH_DCS) & (1 << 3)) && timeout--); ++ } ++ ++ dc->test_cnt ++; ++ ++ { ++ do ++ { ++ r = *p; ++ if(r != e){ ++ unsigned long *uc = (unsigned long *)((unsigned long)p | 0xa0000000); ++ ++ printk("error:from:%p to: %p data[%p] real: 0x%08lx, uc:0x%08lx expect: 0x%08lx, test_cnt: %ld\n", ++ dc->from, dc->to, p,r, *uc, e, dc->test_cnt); ++ break; ++ } ++ p--; ++ e -= 4; ++ }while((unsigned long)p != (unsigned long)dc->to - 4); ++ } ++ if(timeout==0){ ++ printk("xxxxxx error dmac is not ready! xxxxxx\n"); ++ while(1); ++ } ++ ++ mutex_unlock(&dc->lock); ++#ifdef CONFIG_FPGA_TEST ++ mdelay(100); ++#endif ++ return 0; ++} ++static bool filter(struct dma_chan *chan, void *param) ++{ ++#if 0 ++ if (!((unsigned int)chan->private == 8)) ++ return false; ++#endif ++ return true; ++} ++const static char dcm_tsz[8] = { 1, 2, 0, 0, 3, 4, 5, 6 }; ++static inline unsigned int get_max_tsz(unsigned long val, unsigned long *dcmp) ++{ ++ ++ int ord; ++ ++ ord = ffs(val) - 1; ++ if (ord < 0) ++ ord = 0; ++ else if (ord > 7) ++ ord = 7; ++ ++ *dcmp &= ~DCM_TSZ_MSK; ++ *dcmp |= dcm_tsz[ord] << DCM_TSZ_SFT; ++ ++ /* if tsz == 8, set it to 4 */ ++ return ord == 3 ? 4 : 1 << ord; ++} ++static struct dma_channel *new_dma_channel(struct cpu_dma_test* cd) ++{ ++ struct dma_channel *ch; ++ ch = (struct dma_channel *)vmalloc(sizeof(struct dma_channel)); ++ memset(ch,0,sizeof(struct dma_channel)); ++ if(ch == NULL){ ++ printk("mem alloc failed! %s %d\n",__FILE__,__LINE__); ++ return 0; ++ } ++ ++ mutex_init(&ch->lock); ++ ++ ch->test_len = 4096; ++ ch->from = (void *)kmalloc(ch->test_len,GFP_KERNEL); ++ ch->to = (void *)kmalloc(ch->test_len,GFP_KERNEL); ++ if(ch->to == 0 || ch->from == 0){ ++ printk("mem alloc failed! %s %d\n",__FILE__,__LINE__); ++ goto error_exit; ++ } ++ ch->pfrom = virt_to_phys(ch->from); ++ ch->pto = virt_to_phys(ch->to); ++ ++ { ++ dma_cap_mask_t mask; ++ struct hdma_desc *desc; ++ unsigned long burst_len = 128; ++ unsigned long burst_bits = 0; ++ dma_cap_zero(mask); ++ dma_cap_set(DMA_MEMCPY, mask); ++ ch->chan = dma_request_channel(mask, filter, 0); ++ if (!ch->chan) { ++ printk("dma channel request failed! %s %d\n",__FILE__,__LINE__); ++ goto error_exit; ++ } ++ ch->desc = (struct hdma_desc *)kmalloc(128,GFP_KERNEL); ++ if(!ch->desc){ ++ printk("dma channel request desc failed! %s %d\n",__FILE__,__LINE__); ++ goto error_exit; ++ } ++ desc = ch->desc; ++ burst_len = get_max_tsz(burst_len,&burst_bits); ++ desc->dcm = DCM_SAI | DCM_DAI | burst_bits; ++ desc->dsa = ch->pfrom; ++ desc->dta = ch->pto; ++ desc->dtc = ch->test_len / burst_len; ++ desc->drt = 8; ++ dma_cache_sync(NULL,desc,128,DMA_TO_DEVICE); ++ } ++ ++ list_add_tail(&ch->list,&cd->dma_top); ++ return ch; ++error_exit: ++ if(ch->desc) ++ kfree(ch->desc); ++ if(ch->from) ++ kfree(ch->from); ++ if(ch->to) ++ kfree(ch->to); ++ vfree(ch); ++ return 0; ++} ++static void free_dma_channel(struct dma_channel *dc) ++{ ++ if(dc->desc) ++ kfree(dc->desc); ++ if(dc->from) ++ kfree(dc->from); ++ if(dc->to) ++ kfree(dc->to); ++ vfree(dc); ++} ++static int __init cpu_dma_test_init(void) ++{ ++ struct dma_channel *dc; ++ INIT_LIST_HEAD(&cpu_dma.dma_top); ++ cpu_dma.multithread = multithread_test_init("cpu_dma_test",2); ++ if(cpu_dma.multithread){ ++ dc = new_dma_channel(&cpu_dma); ++ if(dc) ++ multithread_test_add_func(cpu_dma.multithread,"cpu-dma-nowait",cpu_dma_test_func_nowait,(void*)dc); ++ ++ dc = new_dma_channel(&cpu_dma); ++ if(dc) ++ multithread_test_add_func(cpu_dma.multithread,"cpu-dma-wait",cpu_dma_test_func_wait,(void*)dc); ++ ++ printk("cpu_dma_test register ok.\n"); ++ } ++ return 0; ++} ++static void __exit cpu_dma_test_deinit(void) ++{ ++ struct dma_channel *dc,*_dc; ++ ++ list_for_each_entry_safe(dc, _dc, &cpu_dma.dma_top, list) { ++ list_del(&dc->list); ++ free_dma_channel(dc); ++ } ++ multithread_test_deinit(cpu_dma.multithread); ++} ++late_initcall(cpu_dma_test_init); ++module_exit(cpu_dma_test_deinit); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_cpu_spinlock_test.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_cpu_spinlock_test.c.patch new file mode 100644 index 00000000..5db5ce5c --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_cpu_spinlock_test.c.patch @@ -0,0 +1,79 @@ +diff -drupN a/arch/mips/xburst2/common/cpu_ddr_test/cpu_spinlock_test.c b/arch/mips/xburst2/common/cpu_ddr_test/cpu_spinlock_test.c +--- a/arch/mips/xburst2/common/cpu_ddr_test/cpu_spinlock_test.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/common/cpu_ddr_test/cpu_spinlock_test.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,75 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "multithread_test.h" ++ ++#define PALLADIUM_TRIGER_2() do {\ ++ volatile unsigned int *a; \ ++ a = (unsigned int *)0xAFFFFFFC; \ ++ *a = *a; \ ++ } while(0) ++ ++struct cpu_spinlock_test { ++ void* multithread; ++ spinlock_t lock; ++ unsigned int cnt; ++ atomic_t acnt; ++} cpu_spinlock; ++ ++ ++static int cpu_spinlock_test_func(void * param) ++{ ++ struct cpu_spinlock_test *p = (struct cpu_spinlock_test *)param; ++ unsigned int c; ++ ++ spin_lock(&p->lock); ++ ++#if 1 ++ c = atomic_read(&p->acnt); ++ if(p->cnt != c) { ++ // PALLADIUM_TRIGER_2(); ++ printk("========= spinlock cnt %x != atomic cnt, %x\n",p->cnt, c); ++ return -1; ++ } ++#endif ++ p->cnt++; ++ ++ udelay(10); ++ ++ atomic_inc(&p->acnt); ++ spin_unlock(&p->lock); ++ ++#ifdef CONFIG_FPGA_TEST ++ mdelay(100); ++#endif ++ return 0; ++} ++ ++static int __init cpu_spinlock_test_init(void) ++{ ++ cpu_spinlock.multithread = multithread_test_init("cpu_spinlock_test",1); ++ spin_lock_init(&cpu_spinlock.lock); ++ ++ if(cpu_spinlock.multithread){ ++ multithread_test_add_func(cpu_spinlock.multithread,"cpu_spinlock_test",cpu_spinlock_test_func,(void*)&cpu_spinlock); ++ } ++ return 0; ++} ++static void __exit cpu_spinlock_test_deinit(void) ++{ ++} ++ ++late_initcall(cpu_spinlock_test_init); ++module_exit(cpu_spinlock_test_deinit); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_cpu_tcsm.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_cpu_tcsm.h.patch new file mode 100644 index 00000000..12a4205b --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_cpu_tcsm.h.patch @@ -0,0 +1,20 @@ +diff -drupN a/arch/mips/xburst2/common/cpu_ddr_test/cpu_tcsm.h b/arch/mips/xburst2/common/cpu_ddr_test/cpu_tcsm.h +--- a/arch/mips/xburst2/common/cpu_ddr_test/cpu_tcsm.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/common/cpu_ddr_test/cpu_tcsm.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,16 @@ ++#ifndef __CPU_TCSM_H__ ++#define __CPU_TCSM_H__ ++ ++#define CPU_TCSM_BASE (0xb2400000) ++ ++#define CPU_TCSM_BANK0 CPU_TCSM_BASE ++#define CPU_TCSM_BANK0_SIZE (4096) ++#define CPU_TCSM_FUNC CPU_TCSM_BANK0 ++#define CPU_TCSM_FUNC_SIZE 2048 ++#define CPU_TCSM_DATA (CPU_TCSM_FUNC + CPU_TCSM_FUNC_SIZE) ++#define CPU_TCSM_SP (CPU_TCSM_BANK0 + CPU_TCSM_BANK0_SIZE) ++ ++#define CPU_TCSM_DDR_CALIB (CPU_TCSM_DATA) ++#define CPU_TCSM_CPU_WAIT_STATUS (CPU_TCSM_DDR_CALIB + 0x4) ++ ++#endif /* __CPU_TCSM_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_cpu_watch_test.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_cpu_watch_test.c.patch new file mode 100644 index 00000000..12d0e067 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_cpu_watch_test.c.patch @@ -0,0 +1,204 @@ +diff -drupN a/arch/mips/xburst2/common/cpu_ddr_test/cpu_watch_test.c b/arch/mips/xburst2/common/cpu_ddr_test/cpu_watch_test.c +--- a/arch/mips/xburst2/common/cpu_ddr_test/cpu_watch_test.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/common/cpu_ddr_test/cpu_watch_test.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,200 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++//#include ++ ++#include ++#include ++ ++ ++#include"../../../../../include/linux/mfd/ingenic-tcu.h" ++ ++struct watch_struct ++{ ++ struct task_struct *child; ++ unsigned int watchhi; ++ unsigned int watchlo; ++ ++ /* debugfs */ ++ struct dentry *root; ++}; ++ ++struct watch_struct _cwt; /* cpu watch test */ ++struct watch_struct *cwt; /* cpu watch test */ ++ ++ ++static struct task_struct *trace_get_task_struct(pid_t pid) ++{ ++ struct task_struct *child; ++ ++ rcu_read_lock(); ++ child = find_task_by_vpid(pid); ++ if (child) ++ get_task_struct(child); ++ rcu_read_unlock(); ++ ++ if (!child) ++ return ERR_PTR(-ESRCH); ++ return child; ++} ++char g_buffer[256]; ++ ++static ssize_t cpu_watch_read_start(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ char *buf = g_buffer; ++ ++ return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); ++ ++} ++ ++static void local_set_watch(void *args) { ++ struct watch_struct *watch = (struct watch_struct *)args; ++ unsigned int cpu = smp_processor_id(); ++ unsigned int hi = 0; ++// struct mips3264_watch_reg_state *watches = ++ //&watch->child->thread.watch.mips3264; ++ ++ if(watch->watchhi & 0x40000000) ++ hi = watch->watchhi; ++ else ++ hi = (watch->watchhi & 0xffff) | (cpu_asid(cpu,watch->child->mm) << 16); ++ if(watch->watchlo == 0) hi = 0; ++// watches->watchlo[0][cpu] = watch->watchlo; ++// watches->watchhi[0][cpu] = hi; ++ ++ printk("watchlo: %x, watchhi: %x, cpu; %d\n", watch->watchlo, hi, cpu); ++ write_c0_watchlo0(watch->watchlo); ++ write_c0_watchhi0(hi); ++ ++} ++static inline void jz_on_each_cpu(void (*func) (void *info), void *info) ++{ ++ preempt_disable(); ++ smp_call_function(func, info, 1); ++ func(info); ++ preempt_enable(); ++} ++ ++static ssize_t cpu_watch_write_start(struct file *file, const char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ char s[20]; ++ char *s1,*s2; ++ pid_t pid; ++ unsigned int hi; ++ unsigned int lo; ++ struct task_struct *child = NULL; ++ struct watch_struct watch; ++// struct mips3264_watch_reg_state *watches; ++ ++ copy_from_user(g_buffer,user_buf,count); ++ ++ g_buffer[count] = 0; ++ printk("%s\n",g_buffer); ++ s1 = g_buffer; ++ s2 = strchr(s1,':'); ++ printk("s1 = %p s2 = %p\n",s1,s2); ++ if(!s2 || count == 0) { ++ pid = simple_strtoul(s1,0,0); ++ child = trace_get_task_struct(pid); ++ watch.child = child; ++ watch.watchlo = 0; ++ watch.watchhi = 0; ++ jz_on_each_cpu(local_set_watch,&watch); ++ //watches = &child->thread.watch.mips3264; ++ //watches->trace_type = 0; ++ clear_tsk_thread_flag(child, TIF_LOAD_WATCH); ++ ++ return count; ++ } ++ ++ memcpy(s,s1,s2 - s1); ++ s[s2 - s1] = 0; ++ pid = simple_strtoul(s,0,0); ++ ++ s1 = s2 + 1; ++ s2 = strchr(s1,':'); ++ printk("s1 = %p s2 = %p\n",s1,s2); ++ memcpy(s,s1,s2 - s1); ++ s[s2 - s1] = 0; ++ lo = simple_strtoul(s,0,0); ++ ++ s1 = s2 + 1; ++ hi = simple_strtoul(s1,0,0); ++ printk("pid = %d lo = 0x%08x hi = %d\n",pid,lo,hi); ++ child = trace_get_task_struct(pid); ++ printk("child = %p\n",child); ++ //child->thread.watch.mips3264.watchlo[0] = lo; ++ //child->thread.watch.mips3264.watchhi[0] = hi; ++ watch.child = child; ++ watch.watchlo = lo; ++ watch.watchhi = hi; ++ jz_on_each_cpu(local_set_watch,&watch); ++ //watches = &child->thread.watch.mips3264; ++ //watches->trace_type = 1; ++ ++ return count; ++} ++ ++static const struct file_operations cpu_watch_start_ops = { ++ .read = cpu_watch_read_start, ++ .write = cpu_watch_write_start, ++ .open = simple_open, ++ .llseek = default_llseek, ++}; ++ ++static int create_debugfs(struct watch_struct *cwt) ++{ ++ struct dentry *d; ++ d = debugfs_create_dir("cpu_watch", NULL); ++ if(IS_ERR(d)) { ++ pr_err("Create debugfs for tcu test failed!\n"); ++ return PTR_ERR(d); ++ } ++ ++ cwt->root = d; ++ ++ d = debugfs_create_file("start", S_IWUSR| S_IRUGO, cwt->root, cwt, &cpu_watch_start_ops); ++ if(IS_ERR_OR_NULL(d)) { ++ pr_err("Debugfs create failed!\n"); ++ goto err_node; ++ } ++ ++ return 0; ++ ++err_node: ++ debugfs_remove_recursive(cwt->root); ++ return -1; ++} ++ ++static int __init cpu_watch_test_init(void) ++{ ++ int ret; ++ ++ cwt = &_cwt; ++ ++ ret = create_debugfs(cwt); ++ ++ printk("cpu watch test probe ok!\n"); ++ return 0; ++} ++ ++static void __exit cpu_watch_test_deinit(void) ++{ ++ ++} ++ ++late_initcall(cpu_watch_test_init); ++module_exit(cpu_watch_test_deinit); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_ddr_bandwidth_monitor.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_ddr_bandwidth_monitor.c.patch new file mode 100644 index 00000000..0c60cb86 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_ddr_bandwidth_monitor.c.patch @@ -0,0 +1,475 @@ +diff -drupN a/arch/mips/xburst2/common/cpu_ddr_test/ddr_bandwidth_monitor.c b/arch/mips/xburst2/common/cpu_ddr_test/ddr_bandwidth_monitor.c +--- a/arch/mips/xburst2/common/cpu_ddr_test/ddr_bandwidth_monitor.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/common/cpu_ddr_test/ddr_bandwidth_monitor.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,471 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#define DDR_MONITOR_BASE 0x134F0000 ++#define DDR_DYNAMIC_CLK 0x13012068 ++#define DDR_DWCFG 0x13012000 ++#define DDR_CMONC0 0x13012050 ++ ++#define DB_MONITOR_BASE_OFF 0x88// DDR bandwidth monitor base offset address. ++ ++#define MAX_SUPPORTED_MONITORS 4 ++ ++struct dbw_channel_reg{ ++ volatile unsigned int write; ++ unsigned int reserve1; ++ volatile unsigned int read; ++ unsigned int reserve2; ++}; ++struct dbw_reg{ ++ volatile unsigned int dbwcfg; ++ unsigned int reserve; ++ volatile unsigned int period; ++ unsigned int reserver; ++ struct dbw_channel_reg chan[4]; ++}; ++ ++ ++#define GMAC_MSC_CHANNEL 0 //DDR ch0 ++#define VPU_CHANNEL 1 //DDR ch1 ++#define DPU_VPU_CHANNEL 3 //DDR ch3 ++#define AHB2_CHANNEL 5 //DDR ch5 ++#define CPU_CHANNEL 6 //DDR ch6 ++ ++struct ddr_mon_chan { ++ int chn; ++ const char *desc; ++}; ++ ++static struct ddr_mon_chan mon_chans[] = { ++ {0, "gmac&msc"}, ++ {1, "vpu&isp"}, ++ {3, "dpu&cim"}, ++ {5, "ahb2&audio&apb"}, ++ {6, "cpu"} ++}; ++ ++static unsigned int default_monitor_chn[MAX_SUPPORTED_MONITORS] = {0, 3, 5, 6}; ++ ++struct ddr_dbw_monitor { ++ struct ddr_mon_chan *ch; ++ unsigned int read; ++ unsigned int write; ++}; ++ ++ ++static inline struct ddr_mon_chan* get_mon_chn(int chn) ++{ ++ int i; ++ ++ for(i = 0; i < ARRAY_SIZE(mon_chans); i++) { ++ if(mon_chans[i].chn == chn) ++ return &mon_chans[i]; ++ } ++ ++ printk("Error find mon_chn, chn: %d\n", chn); ++ return NULL; ++} ++ ++static int set_mon_chn(struct ddr_dbw_monitor *monitors, int chn) ++{ ++ struct ddr_mon_chan *mon_chn = get_mon_chn(chn); ++ ++ printk("set _mon_chn :%d\n", chn); ++ ++ if(!mon_chn) { ++ return -EINVAL; ++ } ++ ++ monitors->ch = mon_chn; ++ ++ return 0; ++} ++ ++ ++struct ddr_statistics{ ++ struct dentry *root; ++ unsigned int periods; ++ unsigned int output; ++ int run; ++ ++ unsigned int ahb2_read_rate; ++ unsigned int ahb2_write_rate; ++ unsigned int cpu_read_rate; ++ unsigned int cpu_write_rate; ++ ++ /* 1 package = 4 * 32 = 8 * 16 */ ++ unsigned int pkg_cnt_to_cycle; ++ ++ int poll_periods_ms; ++ struct dbw_reg *reg; ++ ++ struct ddr_dbw_monitor dbw_monitors[4]; ++ ++ struct mutex lock; ++ struct timer_list timer; ++}; ++static struct ddr_statistics ddr_statistics = { ++ .periods = 25 * 1000 * 1000, ++ .run = 0, ++ .poll_periods_ms = 40, ++ .output = 1, ++}; ++#define BW_DONE (1 << 3) ++#define BW_INT_EN (1 << 2) ++#define BW_CLR (1 << 1) ++#define BW_EN (1 << 0) ++ ++#define DDR_PACKAGE_TO_CYCLE 4 ++static void ddr_stat_output(struct ddr_statistics *ddr) ++{ ++ uint64_t period = (uint64_t)ddr->reg->period; ++#define occupancy_show(title,chn,id) do{ \ ++ uint64_t w_occupancy = (uint64_t)ddr->dbw_monitors[id].write * ddr->pkg_cnt_to_cycle; \ ++ uint64_t r_occupancy = (uint64_t)ddr->dbw_monitors[id].read * ddr->pkg_cnt_to_cycle; \ ++ uint64_t d = 100000 * w_occupancy; \ ++ uint64_t hi; \ ++ do_div(d,period); \ ++ hi = (uint32_t)d / 1000; \ ++ printk("%s chn:%d write occupancy rate:%lld.%03lld%%\n",title,chn,hi,d - hi * 1000); \ ++ d = 100000 * r_occupancy; \ ++ do_div(d,period); \ ++ hi = (uint32_t)d / 1000; \ ++ printk("%s chn:%d read occupancy rate:%lld.%03lld%%\n",title,chn, hi,d - hi * 1000); \ ++ }while(0) ++ occupancy_show(ddr->dbw_monitors[0].ch->desc, ddr->dbw_monitors[0].ch->chn, 0); ++ occupancy_show(ddr->dbw_monitors[1].ch->desc, ddr->dbw_monitors[1].ch->chn, 1); ++ occupancy_show(ddr->dbw_monitors[2].ch->desc, ddr->dbw_monitors[2].ch->chn, 2); ++ occupancy_show(ddr->dbw_monitors[3].ch->desc, ddr->dbw_monitors[3].ch->chn, 3); ++#undef occupancy_show ++} ++ ++static struct ddr_dbw_monitor *get_dbw_monitor(struct ddr_statistics *ddr, int chn) ++{ ++ struct ddr_dbw_monitor *m; ++ int i = 0; ++ ++ for(i = 0; i < MAX_SUPPORTED_MONITORS; i++) { ++ m = &ddr->dbw_monitors[i]; ++ if(m->ch->chn == chn) ++ return m; ++ } ++ ++ return NULL; ++} ++ ++static ssize_t ddr_read_run(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ddr_statistics *ddr = file->private_data; ++ char *buf; ++ ++ mutex_lock(&ddr->lock); ++ if(ddr->reg->dbwcfg & BW_EN) ++ buf = "Runing\n"; ++ else ++ buf = "Stop\n"; ++ mutex_unlock(&ddr->lock); ++ return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); ++} ++ ++static ssize_t ddr_write_run(struct file *file, const char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ddr_statistics *ddr = file->private_data; ++ struct ddr_dbw_monitor *m; ++ char buf[16]; ++ bool bv; ++ int ret = 0; ++ unsigned int val; ++ int i = 0; ++ if (copy_from_user(buf, user_buf, min(count, (sizeof(buf) - 1)))) ++ return -EFAULT; ++ ++ if (strtobool(buf, &bv) == 0) { ++ mutex_lock(&ddr->lock); ++ ++ if(bv){ ++ val = readl((void*)CKSEG1ADDR(DDR_DYNAMIC_CLK)); ++ val &= ~(1 << 8); ++ writel(val,(void*)CKSEG1ADDR(DDR_DYNAMIC_CLK)); ++ ++ del_timer_sync(&ddr->timer); ++ if(ddr->reg->period != ddr->periods) ++ ddr->poll_periods_ms = 0; ++ ddr->run = 1; ++ ddr->reg->period = ddr->periods; ++ val = ddr->reg->period; ++ ++ ddr->reg->dbwcfg = BW_EN | BW_CLR; ++ while((ddr->reg->dbwcfg & (BW_CLR | BW_EN)) != BW_EN); ++ printk("run!\n"); ++ mod_timer(&ddr->timer,jiffies + msecs_to_jiffies(ddr->poll_periods_ms)); ++ }else{ ++ ++ del_timer_sync(&ddr->timer); ++ ddr->run = 0; ++ for(i = 0; i < MAX_SUPPORTED_MONITORS; i++) { ++ ddr->dbw_monitors[i].write = ddr->reg->chan[i].write; ++ ddr->dbw_monitors[i].read = ddr->reg->chan[i].read; ++ } ++ ++ if(ddr->output){ ++ ddr_stat_output(ddr); ++ } ++ ++ ddr->ahb2_write_rate = (m = get_dbw_monitor(ddr, AHB2_CHANNEL)) == NULL ? 0:m->write; ++ ddr->ahb2_read_rate = (m = get_dbw_monitor(ddr, AHB2_CHANNEL)) == NULL ? 0:m->read; ++ ddr->cpu_write_rate = (m = get_dbw_monitor(ddr, CPU_CHANNEL)) == NULL ? 0:m->write; ++ ddr->cpu_read_rate = (m = get_dbw_monitor(ddr, CPU_CHANNEL)) == NULL ? 0:m->read; ++ ++ ++ ddr->reg->dbwcfg = 0; ++ printk("stopping!\n"); ++ } ++ mutex_unlock(&ddr->lock); ++ } ++ ++ return ret ? ret : count; ++} ++ ++static const struct file_operations ddr_run_fops = { ++ .read = ddr_read_run, ++ .write = ddr_write_run, ++ .open = simple_open, ++ .llseek = default_llseek, ++}; ++static void ddr_stat_timer_handler(unsigned long data) ++{ ++ struct ddr_statistics *ddr = (struct ddr_statistics *)data; ++ unsigned int dbwcfg = ddr->reg->dbwcfg; ++ struct ddr_dbw_monitor *m; ++ int i = 0; ++ if(dbwcfg & BW_DONE) ++ { ++ if(ddr->run){ ++ for(i = 0; i < MAX_SUPPORTED_MONITORS; i++) { ++ ddr->dbw_monitors[i].write = ddr->reg->chan[i].write; ++ ddr->dbw_monitors[i].read = ddr->reg->chan[i].read; ++ } ++ ++ if(ddr->output){ ++ ddr_stat_output(ddr); ++ } ++ if(ddr->reg->dbwcfg != dbwcfg) ++ ddr->poll_periods_ms = 0; ++ ++ ++ ddr->ahb2_write_rate = (m = get_dbw_monitor(ddr, AHB2_CHANNEL)) == NULL ? 0:m->write; ++ ddr->ahb2_read_rate = (m = get_dbw_monitor(ddr, AHB2_CHANNEL)) == NULL ? 0:m->read; ++ ddr->cpu_write_rate = (m = get_dbw_monitor(ddr, CPU_CHANNEL)) == NULL ? 0:m->write; ++ ddr->cpu_read_rate = (m = get_dbw_monitor(ddr, CPU_CHANNEL)) == NULL ? 0:m->read; ++ ++ dbwcfg |= BW_CLR; ++ ddr->reg->dbwcfg = dbwcfg; ++ ++ while(ddr->reg->dbwcfg & BW_CLR); ++ mod_timer(&ddr->timer,jiffies + msecs_to_jiffies(ddr->poll_periods_ms)); ++ }else{ ++ ddr->reg->dbwcfg = 0; ++ } ++ } else { ++ mod_timer(&ddr->timer,jiffies + msecs_to_jiffies(10)); ++ ddr->poll_periods_ms += 10; ++ } ++} ++ ++static int dbw_monitors_init(struct ddr_statistics *ddr) ++{ ++ unsigned int cmonc0; ++ int i; ++ ++ for(i = 0; i < MAX_SUPPORTED_MONITORS; i++) { ++ ddr->dbw_monitors[i].ch = get_mon_chn(default_monitor_chn[i]); ++ } ++ ++#if 0 ++ ddr->dbw_monitors[0].ch = &mon_chans[0]; ++ ddr->dbw_monitors[1].ch = &mon_chans[1]; ++ ddr->dbw_monitors[2].ch = &mon_chans[2]; ++ ddr->dbw_monitors[3].ch = &mon_chans[3]; ++#endif ++ cmonc0 = readl((void *)CKSEG1ADDR(DDR_CMONC0)); ++ /*cmonc0[15:4]*/ ++ cmonc0 &= ~0xfff0; ++ cmonc0 |= (ddr->dbw_monitors[0].ch->chn << 13) \ ++ | (ddr->dbw_monitors[1].ch->chn << 10) \ ++ | (ddr->dbw_monitors[2].ch->chn << 7) \ ++ | (ddr->dbw_monitors[3].ch->chn << 4); ++ writel(cmonc0, (void *)CKSEG1ADDR(DDR_CMONC0)); ++ ++ return 0; ++} ++static ssize_t ddr_read_monitors(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ddr_statistics *ddr = file->private_data; ++ struct ddr_dbw_monitor *m = NULL; ++ int i = 0; ++ int ret = 0; ++ ++ unsigned char *buf = kzalloc(1024, GFP_KERNEL); ++ unsigned char *p = buf; ++ ++ if(!buf) { ++ printk("Error alloc mem!\n"); ++ return -ENOMEM; ++ } ++ ++ for(i = 0; i < MAX_SUPPORTED_MONITORS; i++) { ++ m = &ddr->dbw_monitors[i]; ++ ret = sprintf(p, "monitor:%d, chn:%d, desc:%s\n\t read:%d, write:%d\n", ++ i, m->ch->chn, m->ch->desc, m->read, m->write); ++ p += ret; ++ } ++ ++ ret = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); ++ kfree(buf); ++ return ret; ++} ++ ++static ssize_t ddr_write_monitors(struct file *file, const char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ ++ struct ddr_statistics *ddr = file->private_data; ++ char buf[16]; ++ int i = 0; ++ unsigned int val; ++ char *token, *cur = buf; ++ unsigned int cmonc0; ++ ++ if (copy_from_user(buf, user_buf, min(count, (sizeof(buf) - 1)))) ++ return -EFAULT; ++ ++ for(i = 0; i < MAX_SUPPORTED_MONITORS; i++) { ++ token = strsep(&cur, ":"); ++ if(!token) { ++ printk("Invalid monitor settings!\n"); ++ return -EINVAL; ++ } ++ val = simple_strtoul(token, NULL, 10); ++ ++ if(set_mon_chn(&ddr->dbw_monitors[i], val) < 0) { ++ return -EINVAL; ++ } ++ } ++ ++ cmonc0 = readl((void *)CKSEG1ADDR(DDR_CMONC0)); ++ /*cmonc0[15:4]*/ ++ cmonc0 &= ~0xfff0; ++ cmonc0 |= (ddr->dbw_monitors[0].ch->chn << 13) \ ++ | (ddr->dbw_monitors[1].ch->chn << 10) \ ++ | (ddr->dbw_monitors[2].ch->chn << 7) \ ++ | (ddr->dbw_monitors[3].ch->chn << 4); ++ writel(cmonc0, (void *)CKSEG1ADDR(DDR_CMONC0)); ++ ++ return count; ++} ++ ++static const struct file_operations ddr_monitors_fops = { ++ .read = ddr_read_monitors, ++ .write = ddr_write_monitors, ++ .open = simple_open, ++ .llseek = default_llseek, ++}; ++ ++ ++static int __init ddr_stat_init(void) ++{ ++ struct dentry * d; ++ struct ddr_statistics *ddr = &ddr_statistics; ++ ++ d = debugfs_create_dir("ddr", NULL); ++ if (IS_ERR(d)){ ++ pr_err("create debugfs for ddr failed.\n"); ++ return PTR_ERR(d); ++ } ++ ++ ++ ddr->root = d; ++ ++ d = debugfs_create_file("monitors", S_IWUSR | S_IRUGO, ddr->root, ++ ddr, &ddr_monitors_fops); ++ if (IS_ERR_OR_NULL(d)) ++ goto err_node; ++ ++ d = debugfs_create_u32("periods", S_IWUSR | S_IRUGO, ddr->root, ++ (u32 *)&ddr->periods); ++ if (IS_ERR_OR_NULL(d)) ++ goto err_node; ++ ++ d = debugfs_create_u32("output", S_IWUSR | S_IRUGO, ddr->root, ++ (u32 *)&ddr->output); ++ if (IS_ERR_OR_NULL(d)) ++ goto err_node; ++ ++ d = debugfs_create_u32("ahb2_read_rate", S_IWUSR | S_IRUGO, ddr->root, ++ (u32 *)&ddr->ahb2_read_rate); ++ if (IS_ERR_OR_NULL(d)) ++ goto err_node; ++ ++ d = debugfs_create_u32("ahb2_write_rate", S_IWUSR | S_IRUGO, ddr->root, ++ (u32 *)&ddr->ahb2_write_rate); ++ if (IS_ERR_OR_NULL(d)) ++ goto err_node; ++ d = debugfs_create_u32("cpu_read_rate", S_IWUSR | S_IRUGO, ddr->root, ++ (u32 *)&ddr->cpu_read_rate); ++ if (IS_ERR_OR_NULL(d)) ++ goto err_node; ++ d = debugfs_create_u32("cpu_write_rate", S_IWUSR | S_IRUGO, ddr->root, ++ (u32 *)&ddr->cpu_write_rate); ++ if (IS_ERR_OR_NULL(d)) ++ goto err_node; ++ ++ ++ d = debugfs_create_file("run", S_IWUSR | S_IRUGO, ddr->root, ++ ddr, &ddr_run_fops); ++ if (IS_ERR_OR_NULL(d)) ++ goto err_node; ++ mutex_init(&ddr->lock); ++ ++ ddr->reg = ioremap(DDR_MONITOR_BASE + DB_MONITOR_BASE_OFF,sizeof(struct dbw_reg)); ++ ++ if(readl((void *)CKSEG1ADDR(DDR_DWCFG)) & 1) { ++ /* 32bit ddr*/ ++ ddr->pkg_cnt_to_cycle = 4; ++ ++ } else { ++ ddr->pkg_cnt_to_cycle = 8; ++ ++ } ++ ++ dbw_monitors_init(ddr); ++ ++ ++ ++ init_timer(&ddr->timer); ++ ddr->timer.function = ddr_stat_timer_handler; ++ ddr->timer.data = (unsigned long)ddr; ++ ++ return 0; ++err_node: ++ debugfs_remove_recursive(ddr->root); ++ ++ return -1; ++} ++ ++static void __exit ddr_stat_deinit(void) ++{ ++ struct ddr_statistics *ddr = &ddr_statistics; ++ debugfs_remove_recursive(ddr->root); ++} ++ ++late_initcall(ddr_stat_init); ++module_exit(ddr_stat_deinit); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_ddr_change_freq.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_ddr_change_freq.c.patch new file mode 100644 index 00000000..7888c1b6 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_ddr_change_freq.c.patch @@ -0,0 +1,527 @@ +diff -drupN a/arch/mips/xburst2/common/cpu_ddr_test/ddr_change_freq.c b/arch/mips/xburst2/common/cpu_ddr_test/ddr_change_freq.c +--- a/arch/mips/xburst2/common/cpu_ddr_test/ddr_change_freq.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/common/cpu_ddr_test/ddr_change_freq.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,523 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include "cpu_tcsm.h" ++ ++/* #define ALL_OTHER_CPU_WAITE */ ++struct ddr_calib_value { ++ unsigned int rate; ++ unsigned int refcnt; ++ unsigned char bypass_al; ++ unsigned char bypass_ah; ++}; ++ ++typedef void (*ddr_change_code)(unsigned int, unsigned int, ++ unsigned int,unsigned int); ++ ++struct ddr_cfreq { ++ struct dentry *root; ++ spinlock_t lock; ++ struct timer_list timer; ++ struct clk *clk_ddr; ++ ++ unsigned int ddr_cur_rate; ++ ddr_change_code tcsm_change_ddr_rate; ++}; ++ ++struct ddr_cfreq ddr_cfreq; ++ ++#define CPM_DDRCDR (0xb000002c) ++ ++static ssize_t ddr_read_rate(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ char buf[4]; ++ int pos = 0; ++ ++ pos = scnprintf(buf, 4, "%d\n", ddr_cfreq.ddr_cur_rate); ++ return simple_read_from_buffer(user_buf, count, ppos, buf, pos); ++} ++ ++static unsigned int get_ddr_parent_rate(void) ++{ ++ unsigned int val; ++ struct clk *pll; ++ unsigned int pll_rate; ++ ++ val = REG32(CPM_DDRCDR); ++ switch(val >> 30) { ++ case 1: ++ pll = clk_get(NULL, "apll"); ++ break; ++ case 2: ++ pll = clk_get(NULL, "mpll"); ++ break; ++ default : ++ printk("not support\n"); ++ return 0; ++ } ++ ++ pll_rate = clk_get_rate(pll); ++ return pll_rate; ++} ++static unsigned int get_ddr_rate(void) ++{ ++ unsigned int pll_rate, ddr_rate; ++ unsigned int val; ++ ++ val = REG32(CPM_DDRCDR); ++ ++ pll_rate = get_ddr_parent_rate(); ++ ddr_rate = pll_rate / ((val & 0xf) + 1); ++ return ddr_rate; ++} ++ ++static unsigned int pp_mask, ost_mask, mailbox_mask; ++#ifdef ALL_OTHER_CPU_WAITE ++static unsigned int pp_pend,ost_pend, mailbox_pend; ++#endif ++ ++static inline void unmask_others_cpu(void); ++static void change_ddr_rate(unsigned char bal, unsigned char bah, unsigned int refcnt, int div) ++{ ++ unsigned int val, cur_div;//, div; ++ unsigned int hregpro, pregpro; ++ unsigned int autoself_en; ++#ifdef ALL_OTHER_CPU_WAITE ++ unsigned int wait_cpu; ++ unsigned int timeout = 10000; ++ ++ REG32(0xb0032000) = '0'; ++ ++ div = change_div & 0xffff; ++ wait_cpu = (change_div >> 16); ++ while(!REG32(0xb2407ff8) && timeout --) ++ ; ++ if(!timeout) ++ return; ++#endif ++ hregpro = ddr_readl(DDRC_HREGPRO); ++ pregpro = ddr_readl(DDRC_PREGPRO); ++ autoself_en = ddr_readl(DDRC_AUTOSR_EN); ++ ++ ddr_writel(0, DDRC_HREGPRO); ++ ddr_writel(0, DDRC_PREGPRO); ++ ddr_writel(0, DDRC_AUTOSR_EN); ++ ++ // Disable DFI lowpower handshake ++ /* val = ddr_readl(DDRC_DLP); */ ++ /* val &= ~(1); */ ++ /* ddr_writel(val, DDRC_DLP); */ ++ ++ val = REG32(CPM_DDRCDR); ++ cur_div = (val & 0xf); ++ ++ if(cur_div > div) { ++ val = ddr_readl(DDRC_REFCNT); ++ val &= ~(0x3ffff << 8 | 0xe); ++ val |= refcnt; ++ ddr_writel(val, DDRC_REFCNT); ++ } ++ /** ++ * don't use AHB0/2 APB BUS before freq exit. ++ */ ++ /** ++ * Set !change_en and ce ++ */ ++ val = REG32(CPM_DDRCDR); ++ val |= ((1 << 29) | (1 << 25)); ++ REG32(CPM_DDRCDR) = val; ++ /* while((REG32(CPM_DDRCDR) & (1 << 24))); */ ++ ++ /** ++ * Set clock divider ++ */ ++ val = REG32(CPM_DDRCDR); ++ val &= ~(0xf); ++ val |= div; ++ REG32(CPM_DDRCDR) = val; ++// while((REG32(CPM_DDRCDR) & (1 << 28))); ++ /** ++ * Polling PHY_FREQ_DONE ++ */ ++ while((ddr_readl(DDRC_DWSTATUS) & (1 << 3 | 1 << 1)) != 0xa) ++ ; ++ ++ ddr_writel(DDRP_TRAINING_CTRL_DSCSE_BP, DDRP_INNOPHY_TRAINING_CTRL); ++ ddr_writel(bal, DDRP_INNOPHY_CALIB_BYPASS_AL); ++ ddr_writel(bah, DDRP_INNOPHY_CALIB_BYPASS_AH); ++ ++ /** ++ * Set Controller Freq Exit ++ */ ++ val = ddr_readl(DDRC_DWCFG); ++ val |= (1 << 2); ++ ddr_writel(val, DDRC_DWCFG); ++ ++ /** ++ * Clear Controller Freq Exit ++ */ ++ val = ddr_readl(DDRC_DWCFG); ++ val &= ~(1 << 2); ++ ddr_writel(val, DDRC_DWCFG); ++ ++ /** ++ * clear change_en and ce ++ */ ++ val = REG32(CPM_DDRCDR); ++ val &= ~((1 << 29) | (1 << 25)); ++ REG32(CPM_DDRCDR) = val; ++ ++ unmask_others_cpu(); ++ ++#ifdef ALL_OTHER_CPU_WAITE ++ if(ost_pend) ++ set_ccu_oipr(get_ccu_oipr() | (1 << wait_cpu)); ++ if(pp_pend) ++ set_ccu_pipr(get_ccu_pipr() | (1 << wait_cpu)); ++ if(mailbox_pend) ++ set_ccu_mipr(get_ccu_mipr() | (1 << wait_cpu)); ++ ++ if(ost_mask) ++ set_ccu_oimr(get_ccu_oimr() | (1 << wait_cpu)); ++ if(pp_mask) ++ set_ccu_pimr(get_ccu_pimr() | (1 << wait_cpu)); ++ if(mailbox_mask) ++ set_ccu_mimr(get_ccu_mimr() | (1 << wait_cpu)); ++ /* REG32(0xb2407ff8) = 0; */ ++#endif ++ ++ if(cur_div < div) { ++ val = ddr_readl(DDRC_REFCNT); ++ val &= ~(0x3ffff << 8 | 0xe); ++ val |= refcnt; ++ ddr_writel(val, DDRC_REFCNT); ++ } ++ ++ if(autoself_en) ++ ddr_writel(1, DDRC_AUTOSR_EN); ++ if(hregpro & (1 << 1)) ++ ddr_writel(1, DDRC_HREGPRO); ++ if(pregpro & (1 << 1)) ++ ddr_writel(1, DDRC_PREGPRO); ++} ++ ++#define __read_32bit_register() \ ++ ({ int __res; \ ++ __asm__ __volatile__( \ ++ "move \t %0, $29\n\t" \ ++ : "=r" (__res)); \ ++ __res; \ ++ }) ++ ++#define __write_32bit_register(value) \ ++ do { \ ++ __asm__ __volatile__( \ ++ "move \t $29, %0\n\t" \ ++ : : "Jr" ((unsigned int)(value))); \ ++ } while (0) ++ ++#define read_sp_register() __read_32bit_register() ++#define write_sp_register(val) __write_32bit_register(val) ++static unsigned int change_count; ++static int try_and_lock_ccu(unsigned int cpu) ++{ ++ int timeout = 1000; ++ unsigned int cslr; ++ ++ do { ++ set_ccu_csar(cpu); ++ cslr = get_ccu_cslr(); ++ if((cslr & 1 << 31) && ((cslr & ((1 << CONFIG_NR_CPUS) -1)) == cpu)) ++ break; ++ } while(timeout --); ++ if(timeout < 0) ++ return -1; ++ return 0; ++} ++static void unlock_ccu(void) ++{ ++ set_ccu_cslr(0); ++} ++static int mask_and_wait_others_cpu(unsigned int cur_cpu) ++{ ++ unsigned int pp_mval, mb_mval, ost_mval; ++ unsigned int max_cpu_num = CONFIG_NR_CPUS; ++ unsigned int mask_cpus = ((1 << max_cpu_num) - 1); ++ unsigned int mask_other_cpus = (mask_cpus & (~(1 << cur_cpu))); ++ int timeout, ret = 0; ++ ++ pp_mval = get_ccu_pimr(); ++ mb_mval = get_ccu_mimr(); ++ ost_mval = get_ccu_oimr(); ++ ++ pp_mask = pp_mval & (mask_cpus); ++ mailbox_mask = mb_mval & (mask_cpus); ++ ost_mask = ost_mval & (mask_cpus); ++ ++ try_and_lock_ccu(cur_cpu); ++ if(ret < 0) { ++ printk("try to lock ccu failed\n"); ++ return ret; ++ } ++ ++ set_ccu_pimr(0); ++ set_ccu_mimr(0); ++ set_ccu_oimr(0); ++ ++ timeout = 100000; ++ while(((get_ccu_cssr() & mask_other_cpus) != mask_other_cpus) ++ && timeout--); ++ ++ if(!get_ccu_cssr() && timeout >= 0) { ++ printk("ERROR:get_ccu_cssr() %x timeout %d mask_other_cpus %x\n", get_ccu_cssr(), timeout, mask_other_cpus); ++ printk("ERROR:get_ccu_cssr() %x timeout %d mask_other_cpus %x\n", get_ccu_cssr(), timeout, mask_other_cpus); ++ printk("ERROR:get_ccu_cssr() %x timeout %d mask_other_cpus %x\n", get_ccu_cssr(), timeout, mask_other_cpus); ++ printk("ERROR:get_ccu_cssr() %x timeout %d mask_other_cpus %x\n", get_ccu_cssr(), timeout, mask_other_cpus); ++ printk("ERROR:get_ccu_cssr() %x timeout %d mask_other_cpus %x\n", get_ccu_cssr(), timeout, mask_other_cpus); ++ printk("get_ccu_cssr() %x timeout %d mask_other_cpus %x\n", get_ccu_cssr(), timeout, mask_other_cpus); ++ printk("SMP: ------------------wakeup--------CPU%d: cause %x\n", cur_cpu, read_c0_cause()); ++ printk("SMP: ------------------wakeup--------CPU%d: pp pending %x\n", cur_cpu, REG32(0xb2200100)); ++ printk("SMP: ------------------wakeup--------CPU%d: ost pending %x\n", cur_cpu, REG32(0xb2200180)); ++ printk("SMP: ------------------wakeup--------CPU%d: mailbox pending %x\n", cur_cpu, REG32(0xb2200140)); ++ ++ printk("SMP: ------------------wakeup--------CPU%d: pp mask %x\n", cur_cpu, get_ccu_pimr()); ++ printk("SMP: ------------------wakeup--------CPU%d: mailbox mask %x\n", cur_cpu, get_ccu_mimr()); ++ printk("SMP: ------------------wakeup--------CPU%d: os mask %x\n", cur_cpu, get_ccu_oimr()); ++ while(1); ++ } ++ ++ if(timeout < 0) { ++ set_ccu_pimr(pp_mask); ++ set_ccu_mimr(mailbox_mask); ++ set_ccu_oimr(ost_mask); ++ ret = -1; ++ } ++ unlock_ccu(); ++ ++ return ret; ++} ++static inline void unmask_others_cpu(void) ++{ ++ /* try_and_lock_ccu(cur_cpu); */ ++ /* if(ret < 0) { */ ++ /* printk("try to lock ccu failed\n"); */ ++ /* return ret; */ ++ /* } */ ++ set_ccu_pimr(pp_mask); ++ set_ccu_mimr(mailbox_mask); ++ set_ccu_oimr(ost_mask); ++ /* unlock_ccu(); */ ++} ++#ifdef ALL_OTHER_CPU_WAITE ++static void disable_interrupt(void *args) ++{ ++ unsigned int cpu = smp_processor_id(); ++ printk("SMP: --------------------------CPU%d is offline\n", cpu); ++ ++ if(cpu != *(unsigned int *)args) { ++ unsigned int pp_mval, mb_mval, ost_mval; ++ unsigned int pp_pval, mb_pval, ost_pval; ++ pp_mval = get_ccu_pimr(); ++ mb_mval = get_ccu_mimr(); ++ ost_mval = get_ccu_oimr(); ++ ++ pp_mask = pp_mval & (1 << cpu); ++ mailbox_mask = mb_mval & (1 << cpu); ++ ost_mask = ost_mval & (1 << cpu); ++ ++ set_ccu_pimr(pp_mval & (~(1 << cpu))); ++ set_ccu_mimr(mb_mval & (~(1 << cpu))); ++ set_ccu_oimr(ost_mval & (~(1 << cpu))); ++ ++ pp_pval = get_ccu_pipr(); ++ mb_pval = get_ccu_mipr(); ++ ost_pval = get_ccu_oipr(); ++ ++ pp_pend = pp_pval & (1 << cpu); ++ mailbox_pend = mb_pval & (1 << cpu); ++ ost_pend = ost_pval & (1 << cpu); ++ ++ set_ccu_pipr(pp_pval & (~(1 << cpu))); ++ set_ccu_mipr(mb_pval & (~(1 << cpu))); ++ set_ccu_oipr(ost_pval & (~(1 << cpu))); ++ } ++ ++ REG32(0xb2407ff8) = 0xa5a5a5a5; ++ __asm__ __volatile__ ("wait \n\t"); ++ ++ printk("SMP: ------------------wakeup--------CPU%d: cause %x\n", cpu, read_c0_cause()); ++ printk("SMP: ------------------wakeup--------CPU%d: pp pending %x\n", cpu, REG32(0xb2200100)); ++ printk("SMP: ------------------wakeup--------CPU%d: ost pending %x\n", cpu, REG32(0xb2200180)); ++ printk("SMP: ------------------wakeup--------CPU%d: mailbox pending %x\n", cpu, REG32(0xb2200140)); ++} ++#endif ++ ++static ssize_t ddr_write_rate(struct file *file, const char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ char buf[16]; ++ unsigned int change_rate; ++ unsigned long flags; ++ unsigned int cpu = smp_processor_id(); ++ unsigned int sp, change_div; ++ int ret; ++ struct ddr_calib_value *dcv, *curdcv; ++ ++ dcv = (struct ddr_calib_value *)(CPU_TCSM_DDR_CALIB); ++ ++ if (copy_from_user(buf, user_buf, min(count, (sizeof(buf) - 1)))) ++ return -EFAULT; ++ ++ change_rate = simple_strtoul(buf, NULL, 10) * 1000000; ++ printk("change_rate %d-----------------\n", change_rate); ++ if(change_rate == ddr_cfreq.ddr_cur_rate) { ++ printk("change rate equl current rate\n"); ++ return count; ++ } ++ ++ change_div = get_ddr_parent_rate() / change_rate - 1; ++ if(dcv[change_div].rate != change_rate) { ++ int i; ++ printk("rate %d not support %d\n", change_rate, dcv[change_div].rate); ++ for(i = 0; i< 6; i ++) ++ printk("div %d, rate %d\n", i, dcv[i].rate); ++ printk("change_div %d\n", change_div); ++ return count; ++ } ++ curdcv = &dcv[change_div]; ++ ++ change_count ++; ++ printk("------------cpu %d----------------%d------------------\n", cpu, change_count); ++ ++#ifdef ALL_OTHER_CPU_WAITE ++ REG32(0xb2407ff8) = 0; ++ change_div |= ((cpu?0:1) << 16); ++// preempt_disable(); ++ /* on_each_cpu(disable_interrupt, &cpu, 0); */ ++ smp_call_function(disable_interrupt, &cpu, 0); ++#endif ++ ++ spin_lock_irqsave(&ddr_cfreq.lock,flags); ++ ret = mask_and_wait_others_cpu(cpu); ++ if(ret < 0) { ++ printk("lock failed\n"); ++ change_count --; ++ spin_unlock_irqrestore(&ddr_cfreq.lock,flags); ++ return ret; ++ } ++ sp = read_sp_register(); ++ write_sp_register(CPU_TCSM_SP); ++ ddr_cfreq.tcsm_change_ddr_rate(curdcv->bypass_al, ++ curdcv->bypass_ah, curdcv->refcnt, change_div); ++ write_sp_register(sp); ++ spin_unlock_irqrestore(&ddr_cfreq.lock,flags); ++// preempt_enable(); ++ printk("change succeed\n"); ++ ++ ddr_cfreq.ddr_cur_rate = get_ddr_rate(); ++ clk_set_rate(ddr_cfreq.clk_ddr, ddr_cfreq.ddr_cur_rate); ++ /* ddr_cfreq.ddr_cur_rate = clk_get_rate(ddr_cfreq.clk_ddr); */ ++ printk("clk_get_rate(ddr_cfreq.clk_ddr) %d\n", (unsigned int)clk_get_rate(ddr_cfreq.clk_ddr)); ++ ++ return count; ++} ++ ++static const struct file_operations ddr_run_fops = { ++ .read = ddr_read_rate, ++ .write = ddr_write_rate, ++ .open = simple_open, ++ .llseek = default_llseek, ++}; ++ ++static void load_func_to_tcsm(unsigned int *tcsm_addr,unsigned int *f_addr,unsigned int size) ++{ ++ unsigned int instr; ++ int offset; ++ int i; ++ for(i = 0;i < size / 4;i++) { ++ instr = f_addr[i]; ++ if((instr >> 26) == 2){ ++ offset = instr & 0x3ffffff; ++ offset = (offset << 2) - ((unsigned int)f_addr & 0xfffffff); ++ if(offset > 0) { ++ printk("f_addr[i]%x: %x--------------------------------------------------\n", (unsigned int)&f_addr[i], f_addr[i]); ++ offset = ((unsigned int)tcsm_addr & 0xfffffff) + offset; ++ /* offset = ((unsigned int)0xf4000000 & 0xfffffff) + offset; */ ++ instr = (2 << 26) | (offset >> 2); ++ } ++ } ++ tcsm_addr[i] = instr; ++ } ++} ++ ++static int __init ddr_init(void) ++{ ++ struct dentry * d; ++ struct ddr_cfreq *cfreq = &ddr_cfreq; ++ ++ cfreq->clk_ddr = clk_get(NULL, "div_ddr"); ++ if(!cfreq->clk_ddr) { ++ printk("get ddr clk failed\n"); ++ return -1; ++ } ++ ++ cfreq->ddr_cur_rate = clk_get_rate(cfreq->clk_ddr); ++ { ++ unsigned int *tcsm_bank0 = (unsigned int *)CPU_TCSM_FUNC; ++ /* unsigned int *tcsm_bank0 = (unsigned int *)0xb3423000; */ ++ unsigned int *func0 = (unsigned int *)change_ddr_rate; ++ ++ load_func_to_tcsm(tcsm_bank0, func0, CPU_TCSM_FUNC_SIZE); ++ cfreq->tcsm_change_ddr_rate = (ddr_change_code)tcsm_bank0; ++ } ++ ++ ++ d = debugfs_create_dir("ddrfreq", NULL); ++ if (IS_ERR(d)){ ++ pr_err("create debugfs for ddr failed.\n"); ++ return PTR_ERR(d); ++ } ++ spin_lock_init(&cfreq->lock); ++ ++ cfreq->root = d; ++ d = debugfs_create_u32("ddr_cur_rate", S_IWUSR | S_IRUGO, cfreq->root, ++ (u32 *)&cfreq->ddr_cur_rate); ++ if (IS_ERR_OR_NULL(d)) ++ goto err_node; ++ ++ d = debugfs_create_file("rate", S_IWUSR | S_IRUGO, cfreq->root, ++ cfreq, &ddr_run_fops); ++ if (IS_ERR_OR_NULL(d)) ++ goto err_node; ++ ++ return 0; ++err_node: ++ debugfs_remove_recursive(cfreq->root); ++ ++ return -1; ++} ++ ++static void __exit ddr_deinit(void) ++{ ++ struct ddr_cfreq *cfreq = &ddr_cfreq; ++ debugfs_remove_recursive(cfreq->root); ++} ++ ++late_initcall(ddr_init); ++module_exit(ddr_deinit); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_l2c_test.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_l2c_test.c.patch new file mode 100644 index 00000000..2e324509 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_l2c_test.c.patch @@ -0,0 +1,523 @@ +diff -drupN a/arch/mips/xburst2/common/cpu_ddr_test/l2c_test.c b/arch/mips/xburst2/common/cpu_ddr_test/l2c_test.c +--- a/arch/mips/xburst2/common/cpu_ddr_test/l2c_test.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/common/cpu_ddr_test/l2c_test.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,519 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++/** ++ 1. start address align: 0-63 ++ 2. size align: 0-63 ++ 3. max size: 512k ++ 4. invalid: ++ 5. writeback: ++ 6. blast: ++ 7. 8 thread. ++*/ ++ ++struct l2c_test_thread; ++typedef int (*TEST_FUNC)(struct l2c_test_thread *); ++struct l2c_test_thread{ ++ struct list_head list; ++ struct task_struct *task; ++ TEST_FUNC test_func; ++ struct mutex *lock; ++ int id; ++ volatile int done; ++}; ++#define TO_UNC(x) ((unsigned int)x | 0x20000000) ++//#define TO_UNC(x) ((unsigned int)x) ++ ++#define L2C_SIZE (512 * 1024) ++#define L2C_LINESIZE (64) ++ ++#define PALLADIUM_TRIGER() do{ \ ++ void (*func)(void); \ ++ func = (void(*)(void)) 0xbfc00000; \ ++ func(); \ ++ }while(0) ++ ++#define info(x,y...) do{ \ ++ printk(x,##y); \ ++ }while(0) ++ ++static __maybe_unused int writeback_align_address(struct l2c_test_thread *data) ++{ ++ unsigned char *src; ++ unsigned char *src_org; ++ unsigned char *p; ++ unsigned char *unc_p; ++ int i,j; ++ src_org = (unsigned char*)kmalloc(L2C_LINESIZE * 4,GFP_KERNEL); ++ ++ if(IS_ERR_OR_NULL(src_org)){ ++ src = 0; ++ info("kmalloc error!\n"); ++ }else{ ++ src = src_org + L2C_LINESIZE; ++ info("%s test addr: %p\n",__func__,src); ++ for(j = 0;j= &src[j] && p < (&src[j] + L2C_LINESIZE)){ ++ if(*unc_p != (i & 255)){ ++ PALLADIUM_TRIGER(); ++ info("Err:addr:%p offset:%d e:0x%02x r:0x%02x\n",src,p-src,i & 255,*(unc_p)); ++ return -1; ++ } ++ }else{ ++ if(*p != (i & 255)){ ++ PALLADIUM_TRIGER(); ++ info("Err:addr:%p offset:%d e:0x%02x r:0x%02x\n",src,p-src,i & 255,*(p)); ++ return -1; ++ } ++ } ++ p++; ++ unc_p++; ++ } ++ for(i = 0;i= &src[j] && p < (&src[j] + L2C_LINESIZE * 2)){ ++ if(*p != (0xff - n)){ ++ PALLADIUM_TRIGER(); ++ info("Err:addr:%p offset:%d e:0x%02x r:0x%02x\n",src,p-src,0xff - n,*p); ++ return -1; ++ } ++ n++; ++ }else{ ++ if(*p != (i & 255)){ ++ PALLADIUM_TRIGER(); ++ info("Err:addr:%p offset:%d e:0x%02x r:0x%02x\n",src,p-src,i & 255,*p); ++ return -1; ++ } ++ } ++ p++; ++ } ++ for(i = 0;i= L2C_SIZE / 2) && (i < L2C_SIZE / 2 + L2C_SIZE)) ++ { ++ eq = 0xff - (j & 0xff); ++ j++; ++ }else { ++ eq = i & 0xff; ++ } ++ if(p[i] != eq){ ++ PALLADIUM_TRIGER(); ++ info("Err:addr:%p e:0x%02x r:0x%02x\n",p,eq,p[i]); ++ return -1; ++ } ++ } ++ } ++ if(src_org) ++ kfree(src_org); ++ return 0; ++} ++static __maybe_unused int blast_writeback_all(struct l2c_test_thread *data) ++{ ++ unsigned char *src; ++ unsigned char *src_org; ++ unsigned char *p; ++ unsigned char *unc_p; ++ int i; ++ unsigned char eq; ++ src_org = (unsigned char*)kmalloc(L2C_SIZE * 2 + L2C_LINESIZE * 2,GFP_KERNEL); ++ if(IS_ERR_OR_NULL(src_org)){ ++ src = 0; ++ info("kmalloc error!\n"); ++ }else{ ++ src = src_org + L2C_LINESIZE; ++ info("%s test addr: %p\n",__func__,src); ++ p = src; ++ unc_p = (unsigned char *)TO_UNC(p); ++ for(i = 0;i < L2C_SIZE;i++){ ++ unc_p[L2C_SIZE / 2 + i] = 0xff - (i & 0xff); ++ __sync(); ++ } ++ for(i = 0;i < L2C_SIZE * 2;i++){ ++ src[i] = i & 0xff; ++ } ++ dma_cache_sync(NULL,src,L2C_SIZE * 2,DMA_TO_DEVICE); ++ ++ for(i = 0;i < L2C_SIZE * 2;i++){ ++ eq = i & 0xff; ++ if(p[i] != eq){ ++ PALLADIUM_TRIGER(); ++ info("Err:addr:%p e:0x%02x r:0x%02x\n",p,eq,p[i]); ++ return -1; ++ } ++ } ++ } ++ if(src_org) ++ kfree(src_org); ++ return 0; ++} ++ ++struct l2c_test{ ++ struct dentry *root; ++ int run; ++ struct mutex lock; ++ struct mutex resultlock; ++ struct list_head top; ++ unsigned int thread_count; ++}; ++static TEST_FUNC g_test_func[] ={ ++ writeback_align_address, ++ writeback_align_size, ++ invalid_align_address, ++ invalid_align_size, ++ blast_invalid_all, ++ blast_writeback_all ++}; ++static int g_thread_id = 0; ++ ++ ++static int l2c_test_func(void *data) ++{ ++ struct l2c_test_thread *thread = data; ++ int index; ++ while (!kthread_should_stop()) ++ { ++ printk("d:%p\n",thread->test_func); ++ thread->test_func(thread); ++ index = prandom_u32() % ARRAY_SIZE(g_test_func); ++ thread->test_func = g_test_func[index]; ++ } ++ thread->done = 0; ++ return 0; ++} ++ ++ ++ ++static int l2c_test_add_threads(struct l2c_test *l2ctest) ++{ ++ struct l2c_test_thread *thread; ++ unsigned int index; ++ thread = (struct l2c_test_thread *)kmalloc(sizeof(struct l2c_test_thread), GFP_KERNEL); ++ if(IS_ERR_OR_NULL(thread)){ ++ printk("thread kmalloc failed!\n"); ++ return -1; ++ } ++ memset(thread,0,sizeof(struct l2c_test_thread)); ++ thread->done = -1; ++ index = prandom_u32() % ARRAY_SIZE(g_test_func); ++ thread->test_func = g_test_func[index]; ++ thread->id = g_thread_id; ++ thread->lock = &l2ctest->resultlock; ++ thread->task = kthread_run(l2c_test_func, thread, "l2c_test%d-func%u",g_thread_id++,index); ++ if (IS_ERR(thread->task)) { ++ info("l2c_test: Failed to run thread l2c_test%d-func%u\n",g_thread_id,index); ++ kfree(thread); ++ return -1; ++ } ++ list_add_tail(&thread->list, &l2ctest->top); ++ return 0; ++} ++static void stop_threaded_test(struct l2c_test *l2ctest) ++{ ++ struct l2c_test_thread *thread,*_thread; ++ ++ list_for_each_entry_safe(thread, _thread, &l2ctest->top, list) { ++ list_del(&thread->list); ++ kthread_stop(thread->task); ++ while(thread->done); ++ kfree(thread); ++ } ++} ++ ++static int run_l2c_test(struct l2c_test *l2c) ++{ ++ int i = 0; ++ if(l2c->thread_count > 0){ ++ for(i = 0;i < l2c->thread_count;i++){ ++ l2c_test_add_threads(l2c); ++ } ++ } ++ return 0; ++} ++ ++static ssize_t l2c_test_read_run(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct l2c_test *l2c = file->private_data; ++ char *buf; ++ mutex_lock(&l2c->lock); ++ if(!list_empty(&l2c->top)) ++ buf = "Runing\n"; ++ else ++ buf = "Stop\n"; ++ mutex_unlock(&l2c->lock); ++ return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); ++} ++static ssize_t l2c_test_write_run(struct file *file, const char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct l2c_test *l2c = file->private_data; ++ char buf[16]; ++ bool bv; ++ int ret = 0; ++ if (copy_from_user(buf, user_buf, min(count, (sizeof(buf) - 1)))) ++ return -EFAULT; ++ ++ if (strtobool(buf, &bv) == 0) { ++ mutex_lock(&l2c->lock); ++ if(bv){ ++ run_l2c_test(l2c); ++ }else{ ++ stop_threaded_test(l2c); ++ } ++ mutex_unlock(&l2c->lock); ++ } ++ ++ return ret ? ret : count; ++} ++ ++static const struct file_operations l2c_test_run_fops = { ++ .read = l2c_test_read_run, ++ .write = l2c_test_write_run, ++ .open = simple_open, ++ .llseek = default_llseek, ++}; ++struct l2c_test g_l2c_test; ++ ++static int __init l2c_test_init(void) ++{ ++ struct dentry * d; ++ struct l2c_test *l2c= &g_l2c_test; ++ ++ memset(l2c,0,sizeof(struct l2c_test)); ++ mutex_init(&l2c->lock); ++ mutex_init(&l2c->resultlock); ++ INIT_LIST_HEAD(&l2c->top); ++ l2c->thread_count = 1; ++ ++ d = debugfs_create_dir("l2c_test", NULL); ++ if (IS_ERR(d)){ ++ pr_err("create debugfs for l2c_test failed.\n"); ++ return PTR_ERR(d); ++ } ++ l2c->root = d; ++ ++ d = debugfs_create_u32("thread_count", S_IWUSR | S_IRUGO, l2c->root, ++ (u32 *)&l2c->thread_count); ++ if (IS_ERR_OR_NULL(d)){ ++ pr_err("debugfs create thread_count node failed\n"); ++ goto err_node; ++ } ++ ++ d = debugfs_create_file("run", S_IWUSR | S_IRUGO, l2c->root, ++ l2c, &l2c_test_run_fops); ++ if (IS_ERR_OR_NULL(d)){ ++ pr_err("debugfs create run node failed\n"); ++ goto err_node; ++ } ++ pr_info("l2c_test debugfs init ok.\n"); ++ return 0; ++err_node: ++ debugfs_remove_recursive(l2c->root); ++ pr_err("l2c_test debugfs init failed.\n"); ++ return -1; ++} ++late_initcall(l2c_test_init); ++ ++static void __exit l2c_test_deinit(void) ++{ ++ struct l2c_test *l2c= &g_l2c_test; ++ stop_threaded_test(l2c); ++ debugfs_remove_recursive(l2c->root); ++} ++module_exit(l2c_test_deinit); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_multithread_test.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_multithread_test.c.patch new file mode 100644 index 00000000..3351b864 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_multithread_test.c.patch @@ -0,0 +1,266 @@ +diff -drupN a/arch/mips/xburst2/common/cpu_ddr_test/multithread_test.c b/arch/mips/xburst2/common/cpu_ddr_test/multithread_test.c +--- a/arch/mips/xburst2/common/cpu_ddr_test/multithread_test.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/common/cpu_ddr_test/multithread_test.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,262 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "multithread_test.h" ++struct multithread_test{ ++ struct dentry *root; ++ const char *name; ++ int run; ++ struct mutex lock; ++ struct mutex resultlock; ++ struct list_head thread_top; ++ unsigned int thread_count; ++ struct list_head func_top; ++}; ++struct func_list { ++ struct list_head list; ++ const char *test_name; ++ TEST_FUNC testfunc; ++ void *param; ++ atomic_t testcount; ++}; ++struct thread_test{ ++ struct multithread_test *mt; ++ struct list_head list; ++ struct task_struct *task; ++ char thread_name[20]; ++ TEST_FUNC test_func; ++ void* param; ++ struct mutex *lock; ++ volatile int done; ++}; ++static int mt_test_func(void *data); ++static int mt_test_add_threads(struct multithread_test *mt) ++{ ++ struct thread_test *thread; ++ struct func_list *l_func; ++ struct func_list *min_func = NULL; ++ unsigned int testcount; ++ int retry = 100000; ++ ++ if(list_empty(&mt->func_top)) ++ { ++ printk("test func list is empty,please add func for multithread test.\n"); ++ return -1; ++ } ++ ++ thread = (struct thread_test *)vmalloc(sizeof(struct thread_test)); ++ if(IS_ERR_OR_NULL(thread)){ ++ printk("%s:thread kmalloc failed!\n",mt->name); ++ return -1; ++ } ++ memset(thread,0,sizeof(struct thread_test)); ++ thread->done = -1; ++ ++ testcount = 0xffffffff; ++ list_for_each_entry(l_func,&mt->func_top,list){ ++ unsigned int tc; ++ tc = atomic_read(&l_func->testcount); ++ if(testcount >= tc){ ++ min_func = l_func; ++ testcount = tc; ++ } ++ } ++ if(!min_func) ++ { ++ printk("Not find func %s %d\n",__FILE__,__LINE__); ++ goto err_exit; ++ } ++ atomic_inc(&min_func->testcount); ++ ++ thread->mt = mt; ++ thread->test_func = min_func->testfunc; ++ thread->param = min_func->param; ++ thread->lock = &mt->resultlock; ++ snprintf(thread->thread_name,sizeof(thread->thread_name),"%s-%d\n",min_func->test_name,atomic_read(&min_func->testcount)); ++ ++ do { ++ if(retry <= 0) { ++ break; ++ } ++ thread->task = kthread_run(mt_test_func, thread, thread->thread_name); ++ msleep(1); ++ ++ retry--; ++ ++ } while ((int)thread->task == -EAGAIN); ++ ++ if (IS_ERR(thread->task) || (retry == 0)) { ++ printk("%s: Failed to run thread func:%s, retry: %d\n",mt->name,thread->thread_name, retry); ++ goto err_exit; ++ } ++ list_add_tail(&thread->list, &mt->thread_top); ++ return 0; ++err_exit: ++ kfree(thread); ++ return -1; ++} ++ ++static int mt_test_func(void *data) ++{ ++ struct thread_test *thread = data; ++ while (!kthread_should_stop()) ++ { ++ if(thread->test_func(thread->param) == 0) ++ { ++ mutex_lock(&thread->mt->lock); ++ mt_test_add_threads(thread->mt); ++ mutex_unlock(&thread->mt->lock); ++ } ++ break; ++ } ++ ++ mutex_lock(&thread->mt->lock); ++ list_del(&thread->list); ++ thread->done = 0; ++ mutex_unlock(&thread->mt->lock); ++ ++ vfree(thread); ++ return 0; ++} ++ ++static int run_mt_test(struct multithread_test *mt) ++{ ++ int i = 0; ++ if(mt->thread_count > 0){ ++ for(i = 0;i < mt->thread_count;i++){ ++ mt_test_add_threads(mt); ++ } ++ } ++ return 0; ++} ++static void stop_threaded_test(struct multithread_test *mt) ++{ ++ struct thread_test *thread,*_thread; ++ ++ list_for_each_entry_safe(thread, _thread, &mt->thread_top, list) { ++ list_del(&thread->list); ++ kthread_stop(thread->task); ++ while(thread->done); ++ vfree(thread); ++ } ++} ++ ++static ssize_t mt_test_read_run(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct multithread_test *mt = file->private_data; ++ char *buf; ++ mutex_lock(&mt->lock); ++ if(!list_empty(&mt->thread_top)) ++ buf = "Runing\n"; ++ else ++ buf = "Stop\n"; ++ mutex_unlock(&mt->lock); ++ return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); ++} ++static ssize_t mt_test_write_run(struct file *file, const char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct multithread_test *mt = file->private_data; ++ char buf[16]; ++ bool bv; ++ int ret = 0; ++ if (copy_from_user(buf, user_buf, min(count, (sizeof(buf) - 1)))) ++ return -EFAULT; ++ ++ if (strtobool(buf, &bv) == 0) { ++ mutex_lock(&mt->lock); ++ if(bv){ ++ run_mt_test(mt); ++ }else{ ++ stop_threaded_test(mt); ++ } ++ mutex_unlock(&mt->lock); ++ } ++ return ret ? ret : count; ++} ++static const struct file_operations mt_test_run_fops = { ++ .read = mt_test_read_run, ++ .write = mt_test_write_run, ++ .open = simple_open, ++ .llseek = default_llseek, ++}; ++int multithread_test_add_func(void *handle,const char *name,TEST_FUNC testfunc,void *param) ++{ ++ struct multithread_test *mt = (struct multithread_test *)handle; ++ struct func_list *funclist = vmalloc(sizeof(struct multithread_test)); ++ if(funclist == NULL){ ++ printk("add func failed,%s %d\n",__FILE__,__LINE__); ++ return -1; ++ } ++ funclist->test_name = name; ++ funclist->testfunc = testfunc; ++ funclist->param = param; ++ atomic_set(&funclist->testcount,0); ++ list_add_tail(&funclist->list,&mt->func_top); ++ return 0; ++} ++void* multithread_test_init(const char *name,int threadcount) ++{ ++ struct dentry * d; ++ struct multithread_test *mt = vmalloc(sizeof(struct multithread_test)); ++ if(!mt){ ++ pr_err("%s:%s %d alloc struct multithread_test failed!\n",name,__FILE__,__LINE__); ++ return NULL; ++ } ++ memset(mt,0,sizeof(struct multithread_test)); ++ mutex_init(&mt->lock); ++ mutex_init(&mt->resultlock); ++ INIT_LIST_HEAD(&mt->thread_top); ++ INIT_LIST_HEAD(&mt->func_top); ++ mt->thread_count = threadcount; ++ mt->name = name; ++ d = debugfs_create_dir(name, NULL); ++ if (IS_ERR(d)){ ++ pr_err("create debugfs for %s failed.\n",name); ++ return NULL; ++ } ++ mt->root = d; ++ ++ d = debugfs_create_u32("thread_count", S_IWUSR | S_IRUGO, mt->root, ++ (u32 *)&mt->thread_count); ++ if (IS_ERR_OR_NULL(d)){ ++ pr_err("%s:debugfs create thread_count node failed\n",name); ++ goto err_node; ++ } ++ ++ d = debugfs_create_file("run", S_IWUSR | S_IRUGO, mt->root, ++ mt, &mt_test_run_fops); ++ if (IS_ERR_OR_NULL(d)){ ++ pr_err("%s:debugfs create run node failed\n",name); ++ goto err_node; ++ } ++ pr_info("%s:debugfs init ok.\n",name); ++ return (void*)mt; ++err_node: ++ debugfs_remove_recursive(mt->root); ++ pr_err("%s:debugfs init failed.\n",name); ++ return NULL; ++} ++ ++void multithread_test_deinit(void *handle) ++{ ++ struct multithread_test *mt = (struct multithread_test *)handle; ++ struct func_list *funclist,*_funclist; ++ stop_threaded_test(mt); ++ debugfs_remove_recursive(mt->root); ++ list_for_each_entry_safe(funclist, _funclist, &mt->thread_top, list) { ++ list_del(&funclist->list); ++ vfree(funclist); ++ } ++ vfree(mt); ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_multithread_test.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_multithread_test.h.patch new file mode 100644 index 00000000..8778e5d5 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_multithread_test.h.patch @@ -0,0 +1,13 @@ +diff -drupN a/arch/mips/xburst2/common/cpu_ddr_test/multithread_test.h b/arch/mips/xburst2/common/cpu_ddr_test/multithread_test.h +--- a/arch/mips/xburst2/common/cpu_ddr_test/multithread_test.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/common/cpu_ddr_test/multithread_test.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,9 @@ ++#ifndef _MULTITHREAD_TEST_H_ ++#define _MULTITHREAD_TEST_H_ ++ ++typedef int (*TEST_FUNC)(void *); ++int multithread_test_add_func(void *handle,const char *name,TEST_FUNC testfunc,void *param); ++void* multithread_test_init(const char *name,int threadcount); ++void multithread_test_deinit(void* handle); ++ ++#endif /* _MULTITHREAD_TEST_H_ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_raw_dma_test.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_raw_dma_test.c.patch new file mode 100644 index 00000000..b6b2dc6b --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_cpu_ddr_test_raw_dma_test.c.patch @@ -0,0 +1,270 @@ +diff -drupN a/arch/mips/xburst2/common/cpu_ddr_test/raw_dma_test.c b/arch/mips/xburst2/common/cpu_ddr_test/raw_dma_test.c +--- a/arch/mips/xburst2/common/cpu_ddr_test/raw_dma_test.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/common/cpu_ddr_test/raw_dma_test.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,266 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++//#include ++ ++#include "../../../../../drivers/dma/ingenic/ingenic_dma.h" ++ ++const int dma_test_burst_len[] = {1,4,8,16,32,64,128}; ++ ++struct dma_channel{ ++ struct list_head list; ++ struct dma_chan *chan; ++ unsigned char *desc; ++ unsigned int blen_per_desc; ++}; ++ ++struct cycle_raw_dma_test{ ++ struct dentry *root; ++ int run; ++ struct mutex lock; ++ struct list_head top; ++}; ++ ++static struct cycle_raw_dma_test g_raw_cycle_dma; ++ ++static bool filter(struct dma_chan *chan, void *param) ++{ ++#if 0 ++ if (!((unsigned int)chan->private == 8)) { ++ return false; ++ } ++#endif ++ return true; ++} ++const static char dcm_tsz[8] = { 1, 2, 0, 0, 3, 4, 5, 6 }; ++static inline unsigned int get_max_tsz(unsigned long val, unsigned long *dcmp) ++{ ++ ++ int ord; ++ ++ ord = ffs(val) - 1; ++ if (ord < 0) ++ ord = 0; ++ else if (ord > 7) ++ ord = 7; ++ ++ *dcmp &= ~DCM_TSZ_MSK; ++ *dcmp |= dcm_tsz[ord] << DCM_TSZ_SFT; ++ ++ /* if tsz == 8, set it to 4 */ ++ return ord == 3 ? 4 : 1 << ord; ++} ++static void dump_desc(char *title,struct hdma_desc *desc) ++{ ++ printk("=========== %s =========== \n",title); ++ printk("dcm:0x%08lx\n",desc->dcm); ++ printk("dsa:0x%08x\n",(unsigned int)desc->dsa); ++ printk("dta:0x%08x\n",(unsigned int)desc->dta); ++ printk("dtc:0x%08lx\n",desc->dtc); ++ printk("drt:0x%08lx\n",desc->drt); ++ ++} ++static void build_desc(unsigned char *desc,int burst,int len) ++{ ++ /** ++ * 4 series A B A' B' desc. ++ * A desc is transmite (A B) to (A' B') ++ * A next desc is B' ++ * B desc is transmite (A' B') to (A B) ++ * B next desc is A ++ */ ++ unsigned long burst_bits = 0; ++ struct hdma_desc *A = (struct hdma_desc *)desc; ++ struct hdma_desc *B = (struct hdma_desc *)(desc + len * 1); ++ struct hdma_desc *A1 = (struct hdma_desc *)(desc + len * 2); ++ struct hdma_desc *B1 = (struct hdma_desc *)(desc + len * 3); ++ ++ burst = get_max_tsz(burst,&burst_bits); ++ A->dcm = DCM_SAI | DCM_DAI | DCM_LINK | burst_bits; ++ A->dsa = virt_to_phys(A); ++ A->dta = virt_to_phys(A1); ++ A->dtc = (len * 2 / burst) | ((((unsigned int)B1 & 0xff0) >> 4) << 24); ++ A->drt = 8; ++ ++ B->dcm = DCM_SAI | DCM_DAI | DCM_LINK | burst_bits; ++ B->dsa = virt_to_phys(A1); ++ B->dta = virt_to_phys(A); ++ B->dtc = (len * 2 / burst) | ((((unsigned int)A & 0xff0) >> 4) << 24); ++ B->drt = 8; ++ ++ dump_desc("A",A); ++ dump_desc("B",B); ++ dma_cache_sync(NULL,A,len*4,DMA_TO_DEVICE); ++} ++static void start_dma_chans(struct cycle_raw_dma_test *dma) ++{ ++ struct dma_channel *ch; ++ list_for_each_entry(ch,&dma->top,list){ ++ struct ingenic_dma_chan *dmac = to_ingenic_dma_chan(ch->chan); ++ writel((unsigned int)virt_to_phys(ch->desc), dmac->iomem + CH_DDA); ++ printk("dda:%p->0x%08lx\n",dmac->iomem + CH_DDA,virt_to_phys(ch->desc)); ++ /* initiate descriptor fetch */ ++ writel(BIT(dmac->id), dmac->engine->iomem + DDRS); ++ printk("ddrs:%p->0x%08lx\n",dmac->engine->iomem + DDRS,BIT(dmac->id)); ++ writel(1 | (1 << 30),dmac->iomem + CH_DCS); ++ } ++} ++static void stop_dma_chans(struct cycle_raw_dma_test *dma) ++{ ++ struct dma_channel *ch; ++ list_for_each_entry(ch,&dma->top,list){ ++ struct hdma_desc *A,*B; ++ struct ingenic_dma_chan *dmac = to_ingenic_dma_chan(ch->chan); ++ int len = ch->blen_per_desc; ++ A = (struct hdma_desc *)(ch->desc); ++ B = (struct hdma_desc *)(ch->desc + len * 1); ++ A->dtc &= ~(0xff << 24); ++ B->dtc &= ~(0xff << 24); ++ dma_cache_sync(NULL,A,len*4,DMA_TO_DEVICE); ++ while(readl(dmac->iomem + CH_DCS) & (1 << 3)); ++ writel(0,dmac->iomem + CH_DCS); ++ } ++ ++} ++static void start_cycle_raw_dma(struct cycle_raw_dma_test *dma) ++{ ++ int i; ++ int max; ++ struct dma_channel *ch; ++ struct dma_chan *chan; ++ dma_cap_mask_t mask; ++ dma_cap_zero(mask); ++ dma_cap_set(DMA_MEMCPY, mask); ++ for(i = 0;i < ARRAY_SIZE(dma_test_burst_len);i++){ ++ chan = dma_request_channel(mask, filter, dma); ++ if (!chan) { ++ printk("dma channel request failed! curid = %d, burstlen: %d ignored\n",i,dma_test_burst_len[i]); ++// break; ++ continue; ++ } ++ if(dma_test_burst_len[i] < 32) ++ max = 32; ++ else ++ max = dma_test_burst_len[i]; ++ ++ //extra add 16 byte for descriptor align. ++ ch = kmalloc(sizeof(struct dma_channel) + max * 4 + 16,GFP_KERNEL); // max * 4 is (4's descs) ++ if(IS_ERR_OR_NULL(ch)){ ++ pr_err("dma request channel failed!\n"); ++ dma_release_channel(chan); ++ break; ++ } ++ ch->chan = chan; ++ ch->desc = (unsigned char*)(((unsigned int)(ch + 1) + 15) / 16 * 16); // aligned 16 byte for dma descriptor ++ ch->blen_per_desc = max; ++ build_desc(ch->desc,dma_test_burst_len[i],max); ++ list_add_tail(&ch->list,&dma->top); ++ } ++ start_dma_chans(dma); ++} ++static void stop_cycle_raw_dma(struct cycle_raw_dma_test *dma) ++{ ++ ++ struct list_head *pos; ++ struct list_head *next; ++ struct dma_channel *ch; ++ stop_dma_chans(dma); ++ list_for_each_safe(pos,next,&dma->top){ ++ ch = list_entry(pos,struct dma_channel,list); ++ dma_release_channel(ch->chan); ++ list_del(pos); ++ kfree(ch); ++ } ++} ++static int is_stop_cycle_raw_dma(struct cycle_raw_dma_test *dma) ++{ ++ return list_empty(&dma->top); ++} ++static ssize_t cycle_raw_dma_test_read_run(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct cycle_raw_dma_test *dma = file->private_data; ++ char *buf; ++ mutex_lock(&dma->lock); ++ if(!is_stop_cycle_raw_dma(dma)) ++ buf = "Runing\n"; ++ else ++ buf = "Stop\n"; ++ mutex_unlock(&dma->lock); ++ return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); ++} ++static ssize_t cycle_raw_dma_test_write_run(struct file *file, const char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct cycle_raw_dma_test *dma = file->private_data; ++ char buf[16]; ++ bool bv; ++ int ret = 0; ++ if (copy_from_user(buf, user_buf, min(count, (sizeof(buf) - 1)))) ++ return -EFAULT; ++ ++ if (strtobool(buf, &bv) == 0) { ++ mutex_lock(&dma->lock); ++ if(bv){ ++ start_cycle_raw_dma(dma); ++ }else{ ++ stop_cycle_raw_dma(dma); ++ } ++ mutex_unlock(&dma->lock); ++ } ++ ++ return ret ? ret : count; ++} ++ ++static const struct file_operations cycle_raw_dma_test_run_fops = { ++ .read = cycle_raw_dma_test_read_run, ++ .write = cycle_raw_dma_test_write_run, ++ .open = simple_open, ++ .llseek = default_llseek, ++}; ++static int __init cycle_raw_dma_test_init(void) ++{ ++ struct dentry * d; ++ ++ struct cycle_raw_dma_test *dma= &g_raw_cycle_dma; ++ ++ memset(dma,0,sizeof(struct cycle_raw_dma_test)); ++ INIT_LIST_HEAD(&dma->top); ++ mutex_init(&dma->lock); ++ d = debugfs_create_dir("cycle_raw_dma_test", NULL); ++ if (IS_ERR(d)){ ++ pr_err("create debugfs for cycle_raw_dma_test failed.\n"); ++ return PTR_ERR(d); ++ } ++ dma->root = d; ++ ++ d = debugfs_create_file("run", S_IWUSR | S_IRUGO, dma->root, ++ dma, &cycle_raw_dma_test_run_fops); ++ if (IS_ERR_OR_NULL(d)){ ++ pr_err("debugfs create run node failed\n"); ++ goto err_node; ++ } ++ pr_info("cycle raw dma_test debugfs init ok.\n"); ++ return 0; ++err_node: ++ debugfs_remove_recursive(dma->root); ++ pr_err("cycle_raw_dma_test debugfs init failed.\n"); ++ return -1; ++} ++late_initcall(cycle_raw_dma_test_init); ++ ++static void __exit cycle_raw_dma_test_deinit(void) ++{ ++ struct cycle_raw_dma_test *dma= &g_raw_cycle_dma; ++ debugfs_remove_recursive(dma->root); ++} ++module_exit(cycle_raw_dma_test_deinit); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_get-cpu-features.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_get-cpu-features.c.patch new file mode 100644 index 00000000..a5c17632 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_get-cpu-features.c.patch @@ -0,0 +1,102 @@ +diff -drupN a/arch/mips/xburst2/common/get-cpu-features.c b/arch/mips/xburst2/common/get-cpu-features.c +--- a/arch/mips/xburst2/common/get-cpu-features.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/common/get-cpu-features.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,98 @@ ++/* ++ * Use this function to generate cpu-feature-override.h head file. ++ * Make sure of that, here is no cpu-feature-override.h in mach-xxx directory. ++ * ++ */ ++ ++#include ++#include ++#include ++#define __ASM_MACH_INGENIC_CPU_FEATURE_OVERRIDES_H__ ++#include ++#include ++ ++static int cpu_proc_show(struct seq_file *m, void *v) ++{ ++ ++#define PRINT(ARGS...) seq_printf (m, ##ARGS) ++ ++#define PRT0(X,Y) PRINT("#define " "%s()\t(%d * 1024)\n",#X,(Y)/1024) ++#define PRT1(X,Y) PRINT("#define " "%s()\t%d\n",#X,(Y)) ++ PRT0(cpu_dcache_size,(1< ++ ++static BLOCKING_NOTIFIER_HEAD(jz_notifier_chain_high); ++static BLOCKING_NOTIFIER_HEAD(jz_notifier_chain_normal); ++static BLOCKING_NOTIFIER_HEAD(jz_notifier_chain_low); ++static int jz_notifier(struct notifier_block *nb, unsigned long cmd, void *data) ++{ ++ struct jz_notifier *jz_nb = container_of(nb,struct jz_notifier,nb); ++ int ret = 0; ++ if(jz_nb->msg == cmd) { ++ ret = jz_nb->jz_notify(jz_nb,data); ++ } ++ return ret; ++} ++ ++int jz_notifier_register(struct jz_notifier *notify, unsigned int priority) ++{ ++ unsigned int ret = 0; ++ ++ if((notify->level < NOTEFY_PROI_START) && (notify->level >= NOTEFY_PROI_END)) ++ { ++ printk("notify level can not support this %d\n",notify->level); ++ dump_stack(); ++ return -1; ++ } ++ if((int)notify->msg >= JZ_CMD_END && (int)notify->msg <= JZ_CMD_START) ++ { ++ printk("notify msg can not support this %d\n",notify->msg); ++ dump_stack(); ++ return -1; ++ } ++ if(notify->jz_notify == NULL) ++ { ++ printk("notify function(jz_notify) cand not support NULL\n"); ++ dump_stack(); ++ return -1; ++ } ++ notify->nb.priority = notify->level; ++ notify->nb.notifier_call = jz_notifier; ++ ++ if(priority == NOTEFY_PROI_HIGH) ++ ret = blocking_notifier_chain_register(&jz_notifier_chain_high, ¬ify->nb); ++ else if(priority == NOTEFY_PROI_NORMAL) ++ ret = blocking_notifier_chain_register(&jz_notifier_chain_normal, ¬ify->nb); ++ else if(priority == NOTEFY_PROI_LOW) ++ ret = blocking_notifier_chain_register(&jz_notifier_chain_low, ¬ify->nb); ++ else ++ printk("not support\n"); ++ return ret; ++} ++EXPORT_SYMBOL(jz_notifier_register); ++ ++int jz_notifier_unregister(struct jz_notifier *notify, unsigned int priority) ++{ ++ unsigned int ret = 0; ++ ++ if(priority == NOTEFY_PROI_HIGH) ++ ret = blocking_notifier_chain_unregister(&jz_notifier_chain_high, ¬ify->nb); ++ else if(priority == NOTEFY_PROI_NORMAL) ++ ret = blocking_notifier_chain_unregister(&jz_notifier_chain_normal, ¬ify->nb); ++ else if(priority == NOTEFY_PROI_LOW) ++ ret = blocking_notifier_chain_unregister(&jz_notifier_chain_low, ¬ify->nb); ++ else ++ printk("not support\n"); ++ return ret; ++} ++EXPORT_SYMBOL(jz_notifier_unregister); ++ ++int jz_notifier_call(unsigned int priority, unsigned long val, void *v) ++{ ++ unsigned int ret = 0; ++ ++ if(priority == NOTEFY_PROI_HIGH) ++ ret = blocking_notifier_call_chain(&jz_notifier_chain_high, val, v); ++ else if(priority == NOTEFY_PROI_NORMAL) ++ ret = blocking_notifier_call_chain(&jz_notifier_chain_normal, val, v); ++ else if(priority == NOTEFY_PROI_LOW) ++ ret = blocking_notifier_call_chain(&jz_notifier_chain_low, val, v); ++ else ++ printk("not support\n"); ++ return ret; ++} ++EXPORT_SYMBOL(jz_notifier_call); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_mxuv3.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_mxuv3.c.patch new file mode 100644 index 00000000..9b445240 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_mxuv3.c.patch @@ -0,0 +1,698 @@ +diff -drupN a/arch/mips/xburst2/common/mxuv3.c b/arch/mips/xburst2/common/mxuv3.c +--- a/arch/mips/xburst2/common/mxuv3.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/common/mxuv3.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,694 @@ ++#include ++#include ++#include ++ ++#define WORDCODE ++ ++__attribute__((optimize("O0"))) ++void __init_mxuv3(void) ++{ ++ unsigned int register val asm("t0"); ++ val = 0; ++ /* open mxuv3 and set thread status ST0_CU2 */ ++ set_c0_status(ST0_CU2); ++ KSTK_STATUS(current) |= ST0_CU2; ++ //printk("%s(%d):smp_processor_id()=%d, read_c0_status()=0x%x, task_cpu(current)=%d, KSTK_STATUS(current)=0x%lx, current->tgid=%d, current->pid=%d\n", __func__, __LINE__, smp_processor_id(), read_c0_status(), task_cpu(current), KSTK_STATUS(current), current->tgid, current->pid); ++ ++ /* dump mxuv3 control and status register */ ++#ifdef WORDCODE ++ //asm volatile(".word 0x70100203 | (0x0 << 11)\n\t":"=r"(val)); ++ //printk("%s(%d):smp_processor_id()=%d, read_c0_status()=0x%x, KSTK_STATUS(current)=0x%lx, current->tgid=%d, current->pid=%d, mir=0x%x\n", __func__, __LINE__, smp_processor_id(), read_c0_status(), KSTK_STATUS(current), current->tgid, current->pid, val); ++ //asm volatile(".word 0x70100203 | (0x1 << 11) \n\t":"=r"(val)); ++ //printk("%s(%d):smp_processor_id()=%d, read_c0_status()=0x%x, KSTK_STATUS(current)=0x%lx, current->tgid=%d, current->pid=%d, mscr=0x%x\n", __func__, __LINE__, smp_processor_id(), read_c0_status(), KSTK_STATUS(current), current->tgid, current->pid, val); ++ //dump_stack(); ++#else ++ CFCMXU(val, 0); ++ printk("mir=0x%x\n", val); ++ CFCMXU(val, 1); ++ printk("mcsr=0x%x\n", val); ++#endif ++} ++ ++__attribute__((optimize("O0"))) ++void __save_mxuv3(void *tsk_void) ++{ ++ register void *base asm("t0"); ++#ifndef WORDCODE ++ register void *base1 asm("t1"); ++#endif ++ struct task_struct *tsk = tsk_void; ++ struct xburst_mxu_struct *mxu = &tsk->thread.mxu; ++ //printk("%s(%d):smp_processor_id()=%d, read_c0_status()=0x%x, KSTK_STATUS(current)=0x%lx, current->tgid=%d, current->pid=%d, , KSTK_STATUS(tsk)=0x%lx, task->tgid=%d, task->pid=%d\n", __func__, __LINE__, smp_processor_id(), read_c0_status(), KSTK_STATUS(current), current->tgid, current->pid, KSTK_STATUS(tsk), tsk->tgid, tsk->pid); ++ //dump_stack(); ++ //printk("%s(%d):smp_processor_id()=%d, read_c0_status()=0x%x, task_cpu(current)=%d, KSTK_STATUS(current)=0x%lx, current->tgid=%d, current->pid=%d, task_cpu(p)=%d, KSTK_STATUS(p)=0x%lx, p->tgid=%d, p->pid=%d\n", __func__, __LINE__, smp_processor_id(), read_c0_status(), task_cpu(current), KSTK_STATUS(current), current->tgid, current->pid, task_cpu(tsk), KSTK_STATUS(tsk), tsk->tgid, tsk->pid); ++#ifdef WORDCODE ++ /** ++ * sao ins: hex(0x700000d5 | 8 << 21 | 1 << 16 | 0 << 11 | 1 << 9) ++ * 0x700000d5 ->sa0 ++ * 8 ->t0 ++ * 1 ->32>>5 ++ * 0 ->vpr0 ++ * 1 ->nn // o means to be divided by 512/256=2, so n=[0,1] ++ * because t0 is fixed, so 0x700000d5 | 8 << 21 = 0x710000d5 ++ * so the word format as follows: ++ * asm volatile(".word 0x710000d5 | offset << 16 | vprn << 11 | n << 9 \n\t"); ++ * mfsum ins: hex(0x4a60000f | vss << 11 | vrd << 7) ++ * for we fixed vrd to 0, so the word format as follows: ++ * asm volatile(".word 0x4a60000f | vss << 11 \n\t"); ++ */ ++ base = &mxu->vpr[0]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 0 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 0 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[1]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 1 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 1 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[2]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 2 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 2 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[3]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 3 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 3 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[4]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 4 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 4 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[5]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 5 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 5 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[6]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 6 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 6 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[7]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 7 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 7 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[8]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 8 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 8 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[9]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 9 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 9 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[10]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 10 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 10 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[11]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 11 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 11 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[12]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 12 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 12 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[13]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 13 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 13 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[14]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 14 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 14 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[15]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 15 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 15 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[16]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 16 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 16 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[17]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 17 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 17 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[18]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 18 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 18 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[19]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 19 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 19 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[20]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 20 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 20 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[21]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 21 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 21 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[22]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 22 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 22 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[23]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 23 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 23 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[24]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 24 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 24 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[25]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 25 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 25 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[26]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 26 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 26 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[27]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 27 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 27 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[28]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 28 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 28 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[29]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 29 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 29 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[30]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 30 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 30 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[31]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 31 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 31 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vsr[0]; ++ asm volatile(".word 0x4a60000f | 0 << 11 \n\t"); ++ asm volatile(".word 0x710000d5 | 0 << 16 | 0 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 0 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vsr[1]; ++ asm volatile(".word 0x4a60000f | 1 << 11 \n\t"); ++ asm volatile(".word 0x710000d5 | 0 << 16 | 0 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 0 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vsr[2]; ++ asm volatile(".word 0x4a60000f | 2 << 11 \n\t"); ++ asm volatile(".word 0x710000d5 | 0 << 16 | 0 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 0 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vsr[3]; ++ asm volatile(".word 0x4a60000f | 3 << 11 \n\t"); ++ asm volatile(".word 0x710000d5 | 0 << 16 | 0 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 0 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->csr; ++ asm volatile(".word 0x7010f803 | 9 << 6 \n\t"); // t1 <- mxu.csr ++ asm volatile(".word 0xac000000 | 8 << 21 | 9 << 16 \n\t"); // sw $t1 0($t0) ++#else ++ base = &mxu->vpr[0]; ++ SA(o, VR0, 0, base, 0); ++ SA(o, VR0, 1, base, 32); ++ ++ base = &mxu->vpr[1]; ++ SA(o, VR1, 0, base, 0); ++ SA(o, VR1, 1, base, 32); ++ ++ base = &mxu->vpr[2]; ++ SA(o, VR2, 0, base, 0); ++ SA(o, VR2, 1, base, 32); ++ ++ base = &mxu->vpr[3]; ++ SA(o, VR3, 0, base, 0); ++ SA(o, VR3, 1, base, 32); ++ ++ base = &mxu->vpr[4]; ++ SA(o, VR4, 0, base, 0); ++ SA(o, VR4, 1, base, 32); ++ ++ base = &mxu->vpr[5]; ++ SA(o, VR5, 0, base, 0); ++ SA(o, VR5, 1, base, 32); ++ ++ base = &mxu->vpr[6]; ++ SA(o, VR6, 0, base, 0); ++ SA(o, VR6, 1, base, 32); ++ ++ base = &mxu->vpr[7]; ++ SA(o, VR7, 0, base, 0); ++ SA(o, VR7, 1, base, 32); ++ ++ base = &mxu->vpr[8]; ++ SA(o, VR8, 0, base, 0); ++ SA(o, VR8, 1, base, 32); ++ ++ base = &mxu->vpr[9]; ++ SA(o, VR9, 0, base, 0); ++ SA(o, VR9, 1, base, 32); ++ ++ base = &mxu->vpr[10]; ++ SA(o, VR10, 0, base, 0); ++ SA(o, VR10, 1, base, 32); ++ ++ base = &mxu->vpr[11]; ++ SA(o, VR11, 0, base, 0); ++ SA(o, VR11, 1, base, 32); ++ ++ base = &mxu->vpr[12]; ++ SA(o, VR12, 0, base, 0); ++ SA(o, VR12, 1, base, 32); ++ ++ base = &mxu->vpr[13]; ++ SA(o, VR13, 0, base, 0); ++ SA(o, VR13, 1, base, 32); ++ ++ base = &mxu->vpr[14]; ++ SA(o, VR14, 0, base, 0); ++ SA(o, VR14, 1, base, 32); ++ ++ base = &mxu->vpr[15]; ++ SA(o, VR15, 0, base, 0); ++ SA(o, VR15, 1, base, 32); ++ ++ base = &mxu->vpr[16]; ++ SA(o, VR16, 0, base, 0); ++ SA(o, VR16, 1, base, 32); ++ ++ base = &mxu->vpr[17]; ++ SA(o, VR17, 0, base, 0); ++ SA(o, VR17, 1, base, 32); ++ ++ base = &mxu->vpr[18]; ++ SA(o, VR18, 0, base, 0); ++ SA(o, VR18, 1, base, 32); ++ ++ base = &mxu->vpr[19]; ++ SA(o, VR19, 0, base, 0); ++ SA(o, VR19, 1, base, 32); ++ ++ base = &mxu->vpr[20]; ++ SA(o, VR20, 0, base, 0); ++ SA(o, VR20, 1, base, 32); ++ ++ base = &mxu->vpr[21]; ++ SA(o, VR21, 0, base, 0); ++ SA(o, VR21, 1, base, 32); ++ ++ base = &mxu->vpr[22]; ++ SA(o, VR22, 0, base, 0); ++ SA(o, VR22, 1, base, 32); ++ ++ base = &mxu->vpr[23]; ++ SA(o, VR23, 0, base, 0); ++ SA(o, VR23, 1, base, 32); ++ ++ base = &mxu->vpr[24]; ++ SA(o, VR24, 0, base, 0); ++ SA(o, VR24, 1, base, 32); ++ ++ base = &mxu->vpr[25]; ++ SA(o, VR25, 0, base, 0); ++ SA(o, VR25, 1, base, 32); ++ ++ base = &mxu->vpr[26]; ++ SA(o, VR26, 0, base, 0); ++ SA(o, VR26, 1, base, 32); ++ ++ base = &mxu->vpr[27]; ++ SA(o, VR27, 0, base, 0); ++ SA(o, VR27, 1, base, 32); ++ ++ base = &mxu->vpr[28]; ++ SA(o, VR28, 0, base, 0); ++ SA(o, VR28, 1, base, 32); ++ ++ base = &mxu->vpr[29]; ++ SA(o, VR29, 0, base, 0); ++ SA(o, VR29, 1, base, 32); ++ ++ base = &mxu->vpr[30]; ++ SA(o, VR30, 0, base, 0); ++ SA(o, VR30, 1, base, 32); ++ ++ base = &mxu->vpr[31]; ++ SA(o, VR31, 0, base, 0); ++ SA(o, VR31, 1, base, 32); ++ ++ base = &mxu->vsr[0]; ++ MFSUM(VR0, VS0); ++ SA(o, VR0, 0, base, 0); ++ SA(o, VR0, 1, base, 32); ++ ++ base = &mxu->vsr[1]; ++ MFSUM(VR0, VS1); ++ SA(o, VR0, 0, base, 0); ++ SA(o, VR0, 1, base, 32); ++ ++ base = &mxu->vsr[2]; ++ MFSUM(VR0, VS2); ++ SA(o, VR0, 0, base, 0); ++ SA(o, VR0, 1, base, 32); ++ ++ base = &mxu->vsr[3]; ++ MFSUM(VR0, VS3); ++ SA(o, VR0, 0, base, 0); ++ SA(o, VR0, 1, base, 32); ++ ++ base = &mxu->csr; ++ CFCMXU(base1, 31); ++ asm volatile("sw $t1, 0($t0)\n\t"); ++#endif ++} ++ ++__attribute__((optimize("O0"))) ++void __restore_mxuv3(void * tsk_void) ++{ ++ register void *base asm("t0"); ++ struct task_struct *tsk = tsk_void; ++ struct xburst_mxu_struct *mxu = &tsk->thread.mxu; ++ //printk("%s(%d):smp_processor_id()=%d, read_c0_status()=0x%x, KSTK_STATUS(current)=0x%lx, current->tgid=%d, current->pid=%d, , KSTK_STATUS(tsk)=0x%lx, task->tgid=%d, task->pid=%d\n", __func__, __LINE__, smp_processor_id(), read_c0_status(), KSTK_STATUS(current), current->tgid, current->pid, KSTK_STATUS(tsk), tsk->tgid, tsk->pid); ++ //dump_stack(); ++ //printk("%s(%d):smp_processor_id()=%d, read_c0_status()=0x%x, task_cpu(current)=%d, KSTK_STATUS(current)=0x%lx, current->tgid=%d, current->pid=%d, task_cpu(p)=%d, KSTK_STATUS(p)=0x%lx, p->tgid=%d, p->pid=%d\n", __func__, __LINE__, smp_processor_id(), read_c0_status(), task_cpu(current), KSTK_STATUS(current), current->tgid, current->pid, task_cpu(tsk), KSTK_STATUS(tsk), tsk->tgid, tsk->pid); ++#ifdef WORDCODE ++ /** ++ * lao ins: hex(0x70001811 | 8 << 21 | 1 << 16 | 1 << 14 | 0 << 6) ++ * cmd: 0x70001811 ->la0 ++ * base: 8 ->t0 ++ * offset: 1 ->32>>5 ++ * nn: 1 ->nn // o means to be divided by 512/256=2, so n=[0,1] ++ * vpr: 0 ->vpr0 ++ * because t0 is fixed, so 0x70001811 | 8 << 21 = 0x71001811 ++ * so the word format as follows: ++ * asm volatile(".word 0x71001811 | offset << 16 | n << 14 | vprn << 6 \n\t"); ++ * ++ * mtsum ins: hex(0x4a60001d | vrs << 16 | vsd << 6) ++ * for we fixed vrs to 0, so the word format as follows: ++ * asm volatile(".word 0x4a60001d | vss << 6 \n\t"); ++ */ ++ base = &mxu->csr; ++ asm volatile(".word 0x8c000000 | 8 << 21 | 9 << 16\n\t");// lw $t1, 0($t0) ++ asm volatile(".word 0x7011f803 | 9 << 21 \n\t");// mxu.csr <- t1 ++ ++ base = &mxu->vsr[0]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 0 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 0 << 6 \n\t"); ++ asm volatile(".word 0x4a60001d | 0 << 6 \n\t"); ++ ++ base = &mxu->vsr[1]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 0 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 0 << 6 \n\t"); ++ asm volatile(".word 0x4a60001d | 1 << 6 \n\t"); ++ ++ base = &mxu->vsr[2]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 0 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 0 << 6 \n\t"); ++ asm volatile(".word 0x4a60001d | 2 << 6 \n\t"); ++ ++ base = &mxu->vsr[3]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 0 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 0 << 6 \n\t"); ++ asm volatile(".word 0x4a60001d | 3 << 6 \n\t"); ++ ++ base = &mxu->vpr[0]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 0 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 0 << 6 \n\t"); ++ ++ base = &mxu->vpr[1]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 1 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 1 << 6 \n\t"); ++ ++ base = &mxu->vpr[2]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 2 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 2 << 6 \n\t"); ++ ++ base = &mxu->vpr[3]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 3 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 3 << 6 \n\t"); ++ ++ base = &mxu->vpr[4]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 4 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 4 << 6 \n\t"); ++ ++ base = &mxu->vpr[5]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 5 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 5 << 6 \n\t"); ++ ++ base = &mxu->vpr[6]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 6 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 6 << 6 \n\t"); ++ ++ base = &mxu->vpr[7]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 7 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 7 << 6 \n\t"); ++ ++ base = &mxu->vpr[8]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 8 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 8 << 6 \n\t"); ++ ++ base = &mxu->vpr[9]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 9 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 9 << 6 \n\t"); ++ ++ base = &mxu->vpr[10]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 10 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 10 << 6 \n\t"); ++ ++ base = &mxu->vpr[11]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 11 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 11 << 6 \n\t"); ++ ++ base = &mxu->vpr[12]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 12 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 12 << 6 \n\t"); ++ ++ base = &mxu->vpr[13]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 13 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 13 << 6 \n\t"); ++ ++ base = &mxu->vpr[14]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 14 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 14 << 6 \n\t"); ++ ++ base = &mxu->vpr[15]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 15 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 15 << 6 \n\t"); ++ ++ base = &mxu->vpr[16]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 16 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 16 << 6 \n\t"); ++ ++ base = &mxu->vpr[17]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 17 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 17 << 6 \n\t"); ++ ++ base = &mxu->vpr[18]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 18 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 18 << 6 \n\t"); ++ ++ base = &mxu->vpr[19]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 19 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 19 << 6 \n\t"); ++ ++ base = &mxu->vpr[20]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 20 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 20 << 6 \n\t"); ++ ++ base = &mxu->vpr[21]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 21 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 21 << 6 \n\t"); ++ ++ base = &mxu->vpr[22]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 22 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 22 << 6 \n\t"); ++ ++ base = &mxu->vpr[23]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 23 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 23 << 6 \n\t"); ++ ++ base = &mxu->vpr[24]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 24 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 24 << 6 \n\t"); ++ ++ base = &mxu->vpr[25]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 25 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 25 << 6 \n\t"); ++ ++ base = &mxu->vpr[26]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 26 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 26 << 6 \n\t"); ++ ++ base = &mxu->vpr[27]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 27 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 27 << 6 \n\t"); ++ ++ base = &mxu->vpr[28]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 28 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 28 << 6 \n\t"); ++ ++ base = &mxu->vpr[29]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 29 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 29 << 6 \n\t"); ++ ++ base = &mxu->vpr[30]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 30 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 30 << 6 \n\t"); ++ ++ base = &mxu->vpr[31]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 31 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 31 << 6 \n\t"); ++#else ++ base = &mxu->csr; ++ asm volatile("lw $t1, 0($t0)\n\t"); ++ CTCMXU(31, base1); ++ ++ base = &mxu->vsr[0]; ++ LA(o, VR0, 0, base, 0); ++ LA(o, VR0, 1, base, 32); ++ MTSUM(VS0, VR0); ++ ++ base = &mxu->vsr[1]; ++ LA(o, VR0, 0, base, 0); ++ LA(o, VR0, 1, base, 32); ++ MTSUM(VS1, VR0); ++ ++ base = &mxu->vsr[2]; ++ LA(o, VR0, 0, base, 0); ++ LA(o, VR0, 1, base, 32); ++ MTSUM(VS2, VR0); ++ ++ base = &mxu->vsr[3]; ++ LA(o, VR0, 0, base, 0); ++ LA(o, VR0, 1, base, 32); ++ MTSUM(VS3, VR0); ++ ++ base = &mxu->vpr[0]; ++ LA(o, VR0, 0, base, 0); ++ LA(o, VR0, 1, base, 32); ++ ++ base = &mxu->vpr[1]; ++ LA(o, VR1, 0, base, 0); ++ LA(o, VR1, 1, base, 32); ++ ++ base = &mxu->vpr[2]; ++ LA(o, VR2, 0, base, 0); ++ LA(o, VR2, 1, base, 32); ++ ++ base = &mxu->vpr[3]; ++ LA(o, VR3, 0, base, 0); ++ LA(o, VR3, 1, base, 32); ++ ++ base = &mxu->vpr[4]; ++ LA(o, VR4, 0, base, 0); ++ LA(o, VR4, 1, base, 32); ++ ++ base = &mxu->vpr[5]; ++ LA(o, VR5, 0, base, 0); ++ LA(o, VR5, 1, base, 32); ++ ++ base = &mxu->vpr[6]; ++ LA(o, VR6, 0, base, 0); ++ LA(o, VR6, 1, base, 32); ++ ++ base = &mxu->vpr[7]; ++ LA(o, VR7, 0, base, 0); ++ LA(o, VR7, 1, base, 32); ++ ++ base = &mxu->vpr[8]; ++ LA(o, VR8, 0, base, 0); ++ LA(o, VR8, 1, base, 32); ++ ++ base = &mxu->vpr[9]; ++ LA(o, VR9, 0, base, 0); ++ LA(o, VR9, 1, base, 32); ++ ++ base = &mxu->vpr[10]; ++ LA(o, VR10, 0, base, 0); ++ LA(o, VR10, 1, base, 32); ++ ++ base = &mxu->vpr[11]; ++ LA(o, VR11, 0, base, 0); ++ LA(o, VR11, 1, base, 32); ++ ++ base = &mxu->vpr[12]; ++ LA(o, VR12, 0, base, 0); ++ LA(o, VR12, 1, base, 32); ++ ++ base = &mxu->vpr[13]; ++ LA(o, VR13, 0, base, 0); ++ LA(o, VR13, 1, base, 32); ++ ++ base = &mxu->vpr[14]; ++ LA(o, VR14, 0, base, 0); ++ LA(o, VR14, 1, base, 32); ++ ++ base = &mxu->vpr[15]; ++ LA(o, VR15, 0, base, 0); ++ LA(o, VR15, 1, base, 32); ++ ++ base = &mxu->vpr[16]; ++ LA(o, VR16, 0, base, 0); ++ LA(o, VR16, 1, base, 32); ++ ++ base = &mxu->vpr[17]; ++ LA(o, VR17, 0, base, 0); ++ LA(o, VR17, 1, base, 32); ++ ++ base = &mxu->vpr[18]; ++ LA(o, VR18, 0, base, 0); ++ LA(o, VR18, 1, base, 32); ++ ++ base = &mxu->vpr[19]; ++ LA(o, VR19, 0, base, 0); ++ LA(o, VR19, 1, base, 32); ++ ++ base = &mxu->vpr[20]; ++ LA(o, VR20, 0, base, 0); ++ LA(o, VR20, 1, base, 32); ++ ++ base = &mxu->vpr[21]; ++ LA(o, VR21, 0, base, 0); ++ LA(o, VR21, 1, base, 32); ++ ++ base = &mxu->vpr[22]; ++ LA(o, VR22, 0, base, 0); ++ LA(o, VR22, 1, base, 32); ++ ++ base = &mxu->vpr[23]; ++ LA(o, VR23, 0, base, 0); ++ LA(o, VR23, 1, base, 32); ++ ++ base = &mxu->vpr[24]; ++ LA(o, VR24, 0, base, 0); ++ LA(o, VR24, 1, base, 32); ++ ++ base = &mxu->vpr[25]; ++ LA(o, VR25, 0, base, 0); ++ LA(o, VR25, 1, base, 32); ++ ++ base = &mxu->vpr[26]; ++ LA(o, VR26, 0, base, 0); ++ LA(o, VR26, 1, base, 32); ++ ++ base = &mxu->vpr[27]; ++ LA(o, VR27, 0, base, 0); ++ LA(o, VR27, 1, base, 32); ++ ++ base = &mxu->vpr[28]; ++ LA(o, VR28, 0, base, 0); ++ LA(o, VR28, 1, base, 32); ++ ++ base = &mxu->vpr[29]; ++ LA(o, VR29, 0, base, 0); ++ LA(o, VR29, 1, base, 32); ++ ++ base = &mxu->vpr[30]; ++ LA(o, VR30, 0, base, 0); ++ LA(o, VR30, 1, base, 32); ++ ++ base = &mxu->vpr[31]; ++ LA(o, VR31, 0, base, 0); ++ LA(o, VR31, 1, base, 32); ++#endif ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_proc-exec.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_proc-exec.c.patch new file mode 100644 index 00000000..143c5679 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_proc-exec.c.patch @@ -0,0 +1,70 @@ +diff -drupN a/arch/mips/xburst2/common/proc-exec.c b/arch/mips/xburst2/common/proc-exec.c +--- a/arch/mips/xburst2/common/proc-exec.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/common/proc-exec.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,66 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++static int exec_write_proc(struct file *file, const char __user *buffer, size_t count, loff_t *data) ++{ ++ char buf[128]; ++ char tmp[3][64]; ++ char* argv[4]; ++ char* envp[] = {"HOME=/", "PATH=/sbin:/bin:/system/bin", NULL}; ++ char tmp_one; ++ int i,j=0,k=0; ++ ++ memset(buf, 0, sizeof(buf)); ++ memset(tmp, 0, sizeof(tmp)); ++ if (copy_from_user(buf, buffer, count)) ++ return -EFAULT; ++ for (i = 0; i < count; i++) { ++ strncpy(&tmp_one, &buf[i], 1); ++ if (!strncmp(&tmp_one, ":", 1)) { ++ if (j == 0) ++ strncpy(&tmp[j][0], buf, i); ++ else ++ strncpy(&tmp[j][0], &buf[i+1], (i - k)); ++ k = i; ++ j++; ++ } else if (i == (count - 1)) { ++ if (j == 0) ++ strncpy(tmp[j], buf, i); ++ else ++ strncpy(&tmp[j][0], &buf[k+1], (i - k)); ++ } ++ } ++ argv[0] = &tmp[0][0]; ++ argv[3] = NULL; ++ ++ if (j == 0) { ++ argv[1] = NULL; ++ argv[2] = NULL; ++ } else if (j == 1) { ++ argv[1] = &tmp[1][0]; ++ argv[2] = NULL; ++ } else if (j == 2) { ++ argv[1] = &tmp[1][0]; ++ argv[2] = &tmp[2][0]; ++ } ++ ++ call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC); ++ return count; ++} ++ ++static const struct file_operations exec_proc_fops ={ ++ .write = exec_write_proc, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++static int __init init_proc_exec(void) ++{ ++ proc_create("proc-exec",0600,NULL,&exec_proc_fops); ++ return 0; ++} ++ ++module_init(init_proc_exec); ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_proc.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_proc.c.patch new file mode 100644 index 00000000..0ddfd811 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_common_proc.c.patch @@ -0,0 +1,97 @@ +diff -drupN a/arch/mips/xburst2/common/proc.c b/arch/mips/xburst2/common/proc.c +--- a/arch/mips/xburst2/common/proc.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/common/proc.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,93 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++static struct proc_dir_entry *proc_jz_root; ++struct proc_dir_entry * jz_proc_mkdir(char *s) ++{ ++ struct proc_dir_entry *p; ++ if(!proc_jz_root) { ++ proc_jz_root = proc_mkdir("jz", 0); ++ if(!proc_jz_root) ++ return NULL; ++ } ++ p = proc_mkdir(s,proc_jz_root); ++ return p; ++} ++ ++EXPORT_SYMBOL(jz_proc_mkdir); ++ ++static int jz_proc_show(struct seq_file *filq, void *v) ++{ ++ int ret = 1; ++ struct jz_single_file_ops *proc_fops = filq->private; ++ filq->private = proc_fops->data; ++ ++ if(proc_fops->read) ++ ret = proc_fops->read(filq, v); ++ ++ filq->private = proc_fops; ++ return ret; ++} ++static int jz_proc_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, jz_proc_show, PDE_DATA(inode)); ++} ++static ssize_t jz_proc_write(struct file *file, const char __user *buffer, size_t usize, loff_t *off) ++{ ++ size_t ret; ++ struct jz_single_file_ops *proc_fops = ((struct seq_file *)file->private_data)->private; ++ ((struct seq_file *)file->private_data)->private = proc_fops->data; ++ ++ ret = proc_fops->write(file, buffer, usize, off); ++ ((struct seq_file *)file->private_data)->private = proc_fops; ++ ++ return ret; ++} ++ ++struct proc_dir_entry *jz_proc_create_data( ++ const char *name, umode_t mode, struct proc_dir_entry *parent, ++ struct jz_single_file_ops *proc_fops, void *data) ++{ ++ struct file_operations *jz_proc_fops; ++ ++ jz_proc_fops = kmalloc(sizeof(struct file_operations), GFP_KERNEL); ++ if(!jz_proc_fops) { ++ return NULL; ++ } ++ ++ jz_proc_fops->owner = THIS_MODULE; ++ jz_proc_fops->read = seq_read; ++ jz_proc_fops->llseek = seq_lseek; ++ jz_proc_fops->release = single_release; ++ jz_proc_fops->open = jz_proc_open; ++ jz_proc_fops->write = jz_proc_write; ++ proc_fops->data = data; ++ ++ return proc_create_data(name, mode, parent, jz_proc_fops, proc_fops); ++} ++ ++struct proc_dir_entry *jz_proc_create( ++ const char *name, umode_t mode, struct proc_dir_entry *parent, ++ struct jz_single_file_ops *proc_fops) ++{ ++ return jz_proc_create_data(name, mode, parent, proc_fops, NULL); ++} ++ ++struct proc_dir_entry * get_jz_proc_root(void) ++{ ++ if(!proc_jz_root) { ++ proc_jz_root = proc_mkdir("jz", 0); ++ if(!proc_jz_root) ++ return NULL; ++ } ++ return proc_jz_root; ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_Makefile.patch new file mode 100644 index 00000000..036534b5 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_Makefile.patch @@ -0,0 +1,10 @@ +diff -drupN a/arch/mips/xburst2/core/Makefile b/arch/mips/xburst2/core/Makefile +--- a/arch/mips/xburst2/core/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/core/Makefile 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,6 @@ ++obj-y += prom.o ++ ++obj-$(CONFIG_XBURST2_CPU_SCACHE) += sc.o ++obj-$(CONFIG_SMP) += smp.o ++obj-$(CONFIG_PMON_DEBUG) += perf_proc_jz.o perf_event_jz.o ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_include_ccu.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_include_ccu.h.patch new file mode 100644 index 00000000..8c9cefb6 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_include_ccu.h.patch @@ -0,0 +1,46 @@ +diff -drupN a/arch/mips/xburst2/core/include/ccu.h b/arch/mips/xburst2/core/include/ccu.h +--- a/arch/mips/xburst2/core/include/ccu.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/core/include/ccu.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,42 @@ ++ ++#ifndef __CCU_H__ ++#define __CCU_H__ ++ ++#include ++#define CCU_RESET_ENTRY 0xbfc00000 ++ ++#define get_ccu_cscr() inl(CCU_IO_BASE + 0) ++#define set_ccu_cscr(val) outl(val, CCU_IO_BASE + 0) ++ ++#define get_ccu_cssr() inl(CCU_IO_BASE + 0x20) ++ ++#define get_ccu_csrr() inl(CCU_IO_BASE + 0x40) ++#define set_ccu_csrr(val) outl(val, CCU_IO_BASE + 0x40) ++ ++#define get_ccu_pipr() inl(CCU_IO_BASE + 0x100) ++ ++#define get_ccu_pimr() inl(CCU_IO_BASE + 0x120) ++#define set_ccu_pimr(val) outl(val, CCU_IO_BASE + 0x120) ++ ++#define get_ccu_mipr() inl(CCU_IO_BASE + 0x140) ++ ++#define get_ccu_mimr() inl(CCU_IO_BASE + 0x160) ++#define set_ccu_mimr(val) outl(val, CCU_IO_BASE + 0x160) ++ ++#define get_ccu_oipr() inl(CCU_IO_BASE + 0x180) ++ ++#define get_ccu_oimr() inl(CCU_IO_BASE + 0x1a0) ++#define set_ccu_oimr(val) outl(val, CCU_IO_BASE + 0x1a0) ++ ++#define get_ccu_rer() inl(CCU_IO_BASE + 0xf00) ++#define set_ccu_rer(val) outl(val, CCU_IO_BASE + 0xf00) ++ ++#define get_ccu_cslr() inl(CCU_IO_BASE + 0xff8) ++#define set_ccu_cslr(val) outl(val, CCU_IO_BASE + 0xff8) ++ ++#define get_ccu_csar() inl(CCU_IO_BASE + 0xffc) ++#define set_ccu_csar(val) outl(val, CCU_IO_BASE + 0xffc) ++ ++//#define get_ccu_mbr(cpu_id) inl(CCU_IO_BASE + 0x1000 + cpu_id*4) ++//#define set_ccu_mbr(cpu_id, val) outl(val, CCU_IO_BASE + 0x1000 + cpu_id*4) ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_include_core_base.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_include_core_base.h.patch new file mode 100644 index 00000000..5436f766 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_include_core_base.h.patch @@ -0,0 +1,19 @@ +diff -drupN a/arch/mips/xburst2/core/include/core_base.h b/arch/mips/xburst2/core/include/core_base.h +--- a/arch/mips/xburst2/core/include/core_base.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/core/include/core_base.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,15 @@ ++#ifndef __CORE_BASE_H__ ++#define __CORE_BASE_H__ ++ ++/* for xburst2 INTC base 0x12300000*/ ++#define INTC_IOBASE 0x12300000 ++/* CCU IO base address */ ++//#define CCU_IO_BASE (read_c0_config7 & 0xffff0000) ++#define CCU_IO_BASE 0x12200000 ++ ++/* core system ost interrupte timer. core system ost. xburst2 */ ++#define CORE_OST_IOBASE 0x12100000 ++/* global system ost timer for jiffies. xburst2 */ ++#define G_OST_IOBASE 0x12000000 ++ ++#endif /* __CORE_BASE_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_include_irq_cpu.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_include_irq_cpu.h.patch new file mode 100644 index 00000000..35df23cc --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_include_irq_cpu.h.patch @@ -0,0 +1,10 @@ +diff -drupN a/arch/mips/xburst2/core/include/irq_cpu.h b/arch/mips/xburst2/core/include/irq_cpu.h +--- a/arch/mips/xburst2/core/include/irq_cpu.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/core/include/irq_cpu.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,6 @@ ++#ifndef IRQ_CPU_H ++#define IRQ_CPU_H ++ ++void ingenic_irq_migration(int lock); ++void ingenic_irq_cpumask_idle(int idle); ++#endif /* IRQ_CPU_H */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_include_jz_notifier.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_include_jz_notifier.h.patch new file mode 100644 index 00000000..fcecb572 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_include_jz_notifier.h.patch @@ -0,0 +1,49 @@ +diff -drupN a/arch/mips/xburst2/core/include/jz_notifier.h b/arch/mips/xburst2/core/include/jz_notifier.h +--- a/arch/mips/xburst2/core/include/jz_notifier.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/core/include/jz_notifier.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,45 @@ ++#ifndef _JZ_NOTIFIER_H_ ++#define _JZ_NOTIFIER_H_ ++ ++#include ++ ++/* ++ * Hibernation and suspend events ++ */ ++enum jz_notif_cmd { ++ JZ_CMD_START = 0, ++ JZ_CLK_PRECHANGE, ++ JZ_CLK_CHANGING, ++ JZ_CLK_CHANGED, ++ JZ_CLKGATE_CHANGE, ++ JZ_POST_HIBERNATION, /* Hibernation finished */ ++ JZ_PM_SUSPEND_STANDBY, /* Hibernation finished */ ++ MMU_CONTEXT_EXIT_MMAP, ++ JZ_CMD_END ++}; ++enum { ++ NOTEFY_PROI_START=1, ++ NOTEFY_PROI_HIGH, ++ NOTEFY_PROI_NORMAL, ++ NOTEFY_PROI_LOW, ++ NOTEFY_PROI_END ++}; ++ ++struct clk_notify_data ++{ ++ unsigned long current_rate; ++ unsigned long target_rate; ++}; ++ ++struct jz_notifier { ++ struct notifier_block nb; ++ int (*jz_notify)(struct jz_notifier *notify,void *d); ++ int level; ++ enum jz_notif_cmd msg; ++}; ++ ++int jz_notifier_register(struct jz_notifier *notify, unsigned int priority); ++int jz_notifier_unregister(struct jz_notifier *notify, unsigned int priority); ++int jz_notifier_call(unsigned int priority, unsigned long val, void *v); ++ ++#endif /* _JZ_NOTIFIER_H_ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_include_jz_proc.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_include_jz_proc.h.patch new file mode 100644 index 00000000..305c7e36 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_include_jz_proc.h.patch @@ -0,0 +1,22 @@ +diff -drupN a/arch/mips/xburst2/core/include/jz_proc.h b/arch/mips/xburst2/core/include/jz_proc.h +--- a/arch/mips/xburst2/core/include/jz_proc.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/core/include/jz_proc.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,18 @@ ++#ifndef _JZ_PROC_H_ ++#define _JZ_PROC_H_ ++ ++struct jz_single_file_ops { ++ ssize_t (*read) (struct seq_file *, void *); ++ ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); ++ void *data; ++}; ++ ++struct proc_dir_entry * jz_proc_mkdir(char *s); ++struct proc_dir_entry *jz_proc_create_data( ++ const char *name, umode_t mode, struct proc_dir_entry *parent, ++ struct jz_single_file_ops *proc_fops, void *data); ++struct proc_dir_entry *jz_proc_create( ++ const char *name, umode_t mode, struct proc_dir_entry *parent, ++ struct jz_single_file_ops *proc_fops); ++struct proc_dir_entry * get_jz_proc_root(void); ++#endif /* _JZ_PROC_H_ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_include_mxu.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_include_mxu.h.patch new file mode 100644 index 00000000..13a01bbf --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_include_mxu.h.patch @@ -0,0 +1,57 @@ +diff -drupN a/arch/mips/xburst2/core/include/mxu.h b/arch/mips/xburst2/core/include/mxu.h +--- a/arch/mips/xburst2/core/include/mxu.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/core/include/mxu.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,53 @@ ++/* ++ * Copyright (C) 2005 Mips Technologies ++ * Author: Chris Dearman, chris@mips.com derived from fpu.h ++ * ++ * 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. ++ */ ++#ifndef _ASM_MXU_H ++#define _ASM_MXU_H ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define NUM_MXU_REGS (0) ++ ++/* There is no mxu implement in XBURST2, leave empty */ ++static inline void __init_mxu(void) ++{ ++} ++static inline void __save_mxu(void * tsk_void) ++{ ++} ++static inline void __restore_mxu(void * tsk_void) ++{ ++} ++ ++static inline void init_mxu(void) ++{ ++ if(cpu_has_mxu) ++ __init_mxu(); ++} ++ ++ ++#define save_mxu(tsk) \ ++ do { \ ++ if (cpu_has_mxu) \ ++ __save_mxu(tsk); \ ++ } while (0) ++ ++#define restore_mxu(tsk) \ ++ do { \ ++ if (cpu_has_mxu) \ ++ __restore_mxu(tsk); \ ++ } while (0) ++ ++ ++#endif /* _ASM_MXU_H */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_include_mxu_media.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_include_mxu_media.h.patch new file mode 100644 index 00000000..f9c80cde --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_include_mxu_media.h.patch @@ -0,0 +1,1836 @@ +diff -drupN a/arch/mips/xburst2/core/include/mxu_media.h b/arch/mips/xburst2/core/include/mxu_media.h +--- a/arch/mips/xburst2/core/include/mxu_media.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/core/include/mxu_media.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,1832 @@ ++#ifndef _MXU_H_ ++#define _MXU_H_ ++ ++#define xr0 0 ++#define xr1 1 ++#define xr2 2 ++#define xr3 3 ++#define xr4 4 ++#define xr5 5 ++#define xr6 6 ++#define xr7 7 ++#define xr8 8 ++#define xr9 9 ++#define xr10 10 ++#define xr11 11 ++#define xr12 12 ++#define xr13 13 ++#define xr14 14 ++#define xr15 15 ++#define xr16 16 ++ ++#define ptn0 0 ++#define ptn1 1 ++#define ptn2 2 ++#define ptn3 3 ++#define ptn4 4 ++#define ptn5 5 ++#define ptn6 6 ++#define ptn7 7 ++ ++/***********************************LD/SD***********************************/ ++#define S32LDD(xra,rb,s12) \ ++ do { \ ++ __asm__ __volatile ("S32LDD xr%0,%z1,%2" \ ++ : \ ++ :"K"(xra),"d" (rb),"I"(s12)); \ ++ } while (0) ++ ++#define S32STD(xra,rb,s12) \ ++ do { \ ++ __asm__ __volatile ("S32STD xr%0,%z1,%2" \ ++ : \ ++ :"K"(xra),"d" (rb),"I"(s12):"memory"); \ ++ } while (0) ++ ++#define S32LDDV(xra,rb,rc,strd2)\ ++ do { \ ++ __asm__ __volatile ("S32LDDV xr%0,%z1,%z2,%3" \ ++ : \ ++ :"K"(xra),"d" (rb),"d"(rc),"K"(strd2)); \ ++ } while (0) ++ ++#define S32STDV(xra,rb,rc,strd2)\ ++ do { \ ++ __asm__ __volatile ("S32STDV xr%0,%z1,%z2,%3" \ ++ : \ ++ :"K"(xra),"d" (rb),"d"(rc),"K"(strd2):"memory"); \ ++ } while (0) ++ ++#define S32LDI(xra,rb,s12) \ ++ do { \ ++ __asm__ __volatile ("S32LDI xr%1,%z0,%2" \ ++ :"+d" (rb) \ ++ :"K"(xra),"I"(s12)); \ ++ } while (0) ++ ++#define S32SDI(xra,rb,s12) \ ++ do { \ ++ __asm__ __volatile ("S32SDI xr%1,%z0,%2" \ ++ :"+d" (rb) \ ++ :"K"(xra),"I"(s12):"memory"); \ ++ } while (0) ++ ++#define S32LDIV(xra,rb,rc,strd2)\ ++ do { \ ++ __asm__ __volatile ("S32LDIV xr%1,%z0,%z2,%3" \ ++ :"+d" (rb) \ ++ :"K"(xra),"d"(rc),"K"(strd2)); \ ++ } while (0) ++ ++#define S32SDIV(xra,rb,rc,strd2)\ ++ do { \ ++ __asm__ __volatile ("S32SDIV xr%1,%z0,%z2,%3" \ ++ :"+d" (rb) \ ++ :"K"(xra),"d"(rc),"K"(strd2):"memory"); \ ++ } while (0) ++//MXU enhancement ++#define S32LDDR(xra,rb,s12) \ ++ do { \ ++ __asm__ __volatile ("S32LDDR xr%0,%z1,%2" \ ++ : \ ++ :"K"(xra),"d" (rb),"I"(s12)); \ ++ } while (0) ++ ++#define S32STDR(xra,rb,s12) \ ++ do { \ ++ __asm__ __volatile ("S32STDR xr%0,%z1,%2" \ ++ : \ ++ :"K"(xra),"d" (rb),"I"(s12):"memory"); \ ++ } while (0) ++ ++#define S32LDDVR(xra,rb,rc,strd2)\ ++ do { \ ++ __asm__ __volatile ("S32LDDVR xr%0,%z1,%z2,%3" \ ++ : \ ++ :"K"(xra),"d" (rb),"d"(rc),"K"(strd2)); \ ++ } while (0) ++ ++#define S32STDVR(xra,rb,rc,strd2)\ ++ do { \ ++ __asm__ __volatile ("S32STDVR xr%0,%z1,%z2,%3" \ ++ : \ ++ :"K"(xra),"d" (rb),"d"(rc),"K"(strd2):"memory"); \ ++ } while (0) ++ ++#define S32LDIR(xra,rb,s12) \ ++ do { \ ++ __asm__ __volatile ("S32LDIR xr%1,%z0,%2" \ ++ :"+d" (rb) \ ++ :"K"(xra),"I"(s12)); \ ++ } while (0) ++ ++#define S32SDIR(xra,rb,s12) \ ++ do { \ ++ __asm__ __volatile ("S32SDIR xr%1,%z0,%2" \ ++ :"+d" (rb) \ ++ :"K"(xra),"I"(s12):"memory"); \ ++ } while (0) ++ ++#define S32LDIVR(xra,rb,rc,strd2)\ ++ do { \ ++ __asm__ __volatile ("S32LDIVR xr%1,%z0,%z2,%3" \ ++ :"+d" (rb) \ ++ :"K"(xra),"d"(rc),"K"(strd2)); \ ++ } while (0) ++ ++#define S32SDIVR(xra,rb,rc,strd2)\ ++ do { \ ++ __asm__ __volatile ("S32SDIVR xr%1,%z0,%z2,%3" \ ++ :"+d" (rb) \ ++ :"K"(xra),"d"(rc),"K"(strd2):"memory"); \ ++ } while (0) ++ ++#define S8LDD(xra,rb,s8,optn3) \ ++ do { \ ++ __asm__ __volatile ("S8LDD xr%0,%z1,%2,ptn%3" \ ++ : \ ++ :"K"(xra),"d" (rb),"I"(s8),"K"(optn3)); \ ++ } while (0) ++ ++#define S8STD(xra,rb,s8,optn3) \ ++ do { \ ++ __asm__ __volatile ("S8STD xr%0,%z1,%2,ptn%3" \ ++ : \ ++ :"K"(xra),"d" (rb),"I"(s8),"K"(optn3):"memory"); \ ++ } while (0) ++ ++#define S8LDI(xra,rb,s8,optn3) \ ++ do { \ ++ __asm__ __volatile ("S8LDI xr%1,%z0,%2,ptn%3" \ ++ :"+d" (rb) \ ++ :"K"(xra),"I"(s8),"K"(optn3)); \ ++ } while (0) ++ ++#define S8SDI(xra,rb,s8,optn3) \ ++ do { \ ++ __asm__ __volatile ("S8SDI xr%1,%z0,%2,ptn%3" \ ++ :"+d" (rb) \ ++ :"K"(xra),"I"(s8),"K"(optn3):"memory"); \ ++ } while (0) ++ ++#define S16LDD(xra,rb,s10,optn2) \ ++ do { \ ++ __asm__ __volatile ("S16LDD xr%0,%z1,%2,ptn%3" \ ++ : \ ++ :"K"(xra),"d" (rb),"I"(s10),"K"(optn2)); \ ++ } while (0) ++ ++#define S16STD(xra,rb,s10,optn2) \ ++ do { \ ++ __asm__ __volatile ("S16STD xr%0,%z1,%2,ptn%3" \ ++ : \ ++ :"K"(xra),"d" (rb),"I"(s10),"K"(optn2):"memory"); \ ++ } while (0) ++ ++#define S16LDI(xra,rb,s10,optn2) \ ++ do { \ ++ __asm__ __volatile ("S16LDI xr%1,%z0,%2,ptn%3" \ ++ :"+d" (rb) \ ++ :"K"(xra),"I"(s10),"K"(optn2)); \ ++ } while (0) ++ ++#define S16SDI(xra,rb,s10,optn2) \ ++ do { \ ++ __asm__ __volatile ("S16SDI xr%1,%z0,%2,ptn%3" \ ++ :"+d" (rb) \ ++ :"K"(xra),"I"(s10),"K"(optn2):"memory"); \ ++ } while (0) ++ ++#define LXW(rb,rc,strd2)\ ++({ \ ++unsigned int _dst_; \ ++__asm__ __volatile ("LXW %0,%1,%2,%3":"=d"(_dst_):"d"(rb),"d"(rc),"K"(strd2)); \ ++_dst_; \ ++ }) ++ ++#define LXH(rb,rc,strd2)\ ++({ \ ++unsigned int _dst_; \ ++__asm__ __volatile ("LXH %0,%1,%2,%3":"=d"(_dst_):"d"(rb),"d"(rc),"K"(strd2)); \ ++_dst_; \ ++ }) ++ ++#define LXHU(rb,rc,strd2)\ ++({ \ ++unsigned int _dst_; \ ++__asm__ __volatile ("LXHU %0,%1,%2,%3":"=d"(_dst_):"d"(rb),"d"(rc),"K"(strd2)); \ ++_dst_; \ ++ }) ++ ++#define LXB(rb,rc,strd2)\ ++({ \ ++unsigned int _dst_; \ ++__asm__ __volatile ("LXB %0,%1,%2,%3":"=d"(_dst_):"d"(rb),"d"(rc),"K"(strd2)); \ ++_dst_; \ ++ }) ++ ++#define LXBU(rb,rc,strd2)\ ++({ \ ++unsigned int _dst_; \ ++__asm__ __volatile ("LXBU %0,%1,%2,%3":"=d"(_dst_):"d"(rb),"d"(rc),"K"(strd2)); \ ++_dst_; \ ++ }) ++/***********************************D16MUL***********************************/ ++#define D16MUL_WW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MUL xr%0,xr%1,xr%2,xr%3,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MUL_LW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MUL xr%0,xr%1,xr%2,xr%3,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MUL_HW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MUL xr%0,xr%1,xr%2,xr%3,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MUL_XW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MUL xr%0,xr%1,xr%2,xr%3,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++ ++/**********************************D16MULF*******************************/ ++#define D16MULF_WW(xra,xrb,xrc) \ ++ do { \ ++ __asm__ __volatile ("D16MULF xr%0,xr%1,xr%2,WW"\ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ } while (0) ++ ++#define D16MULF_LW(xra,xrb,xrc) \ ++ do { \ ++ __asm__ __volatile ("D16MULF xr%0,xr%1,xr%2,LW"\ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ } while (0) ++ ++#define D16MULF_HW(xra,xrb,xrc) \ ++ do { \ ++ __asm__ __volatile ("D16MULF xr%0,xr%1,xr%2,HW"\ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ } while (0) ++ ++#define D16MULF_XW(xra,xrb,xrc) \ ++ do { \ ++ __asm__ __volatile ("D16MULF xr%0,xr%1,xr%2,XW"\ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ } while (0) ++// MXU enhancement ++#define D16MULE_WW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MULE xr%0,xr%1,xr%2,xr%3,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MULE_LW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MULE xr%0,xr%1,xr%2,xr%3,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MULE_HW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MULE xr%0,xr%1,xr%2,xr%3,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MULE_XW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MULE xr%0,xr%1,xr%2,xr%3,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++/***********************************D16MAC********************************/ ++#define D16MAC_AA_WW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MAC xr%0,xr%1,xr%2,xr%3,AA,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MAC_AA_LW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MAC xr%0,xr%1,xr%2,xr%3,AA,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MAC_AA_HW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MAC xr%0,xr%1,xr%2,xr%3,AA,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MAC_AA_XW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MAC xr%0,xr%1,xr%2,xr%3,AA,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MAC_AS_WW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MAC xr%0,xr%1,xr%2,xr%3,AS,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MAC_AS_LW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MAC xr%0,xr%1,xr%2,xr%3,AS,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MAC_AS_HW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MAC xr%0,xr%1,xr%2,xr%3,AS,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MAC_AS_XW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MAC xr%0,xr%1,xr%2,xr%3,AS,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MAC_SA_WW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MAC xr%0,xr%1,xr%2,xr%3,SA,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MAC_SA_LW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MAC xr%0,xr%1,xr%2,xr%3,SA,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MAC_SA_HW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MAC xr%0,xr%1,xr%2,xr%3,SA,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MAC_SA_XW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MAC xr%0,xr%1,xr%2,xr%3,SA,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MAC_SS_WW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MAC xr%0,xr%1,xr%2,xr%3,SS,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MAC_SS_LW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MAC xr%0,xr%1,xr%2,xr%3,SS,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MAC_SS_HW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MAC xr%0,xr%1,xr%2,xr%3,SS,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MAC_SS_XW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MAC xr%0,xr%1,xr%2,xr%3,SS,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++ ++/**********************************D16MACF*******************************/ ++#define D16MACF_AA_WW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MACF xr%0,xr%1,xr%2,xr%3,AA,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MACF_AA_LW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MACF xr%0,xr%1,xr%2,xr%3,AA,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MACF_AA_HW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MACF xr%0,xr%1,xr%2,xr%3,AA,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MACF_AA_XW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MACF xr%0,xr%1,xr%2,xr%3,AA,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MACF_AS_WW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MACF xr%0,xr%1,xr%2,xr%3,AS,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MACF_AS_LW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MACF xr%0,xr%1,xr%2,xr%3,AS,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MACF_AS_HW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MACF xr%0,xr%1,xr%2,xr%3,AS,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MACF_AS_XW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MACF xr%0,xr%1,xr%2,xr%3,AS,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MACF_SA_WW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MACF xr%0,xr%1,xr%2,xr%3,SA,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MACF_SA_LW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MACF xr%0,xr%1,xr%2,xr%3,SA,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MACF_SA_HW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MACF xr%0,xr%1,xr%2,xr%3,SA,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MACF_SA_XW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MACF xr%0,xr%1,xr%2,xr%3,SA,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MACF_SS_WW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MACF xr%0,xr%1,xr%2,xr%3,SS,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MACF_SS_LW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MACF xr%0,xr%1,xr%2,xr%3,SS,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MACF_SS_HW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MACF xr%0,xr%1,xr%2,xr%3,SS,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MACF_SS_XW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MACF xr%0,xr%1,xr%2,xr%3,SS,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++// MXU enhancement ++/**********************************D16MACE*******************************/ ++#define D16MACE_AA_WW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MACE xr%0,xr%1,xr%2,xr%3,AA,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MACE_AA_LW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MACE xr%0,xr%1,xr%2,xr%3,AA,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MACE_AA_HW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MACE xr%0,xr%1,xr%2,xr%3,AA,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MACE_AA_XW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MACE xr%0,xr%1,xr%2,xr%3,AA,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MACE_AS_WW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MACE xr%0,xr%1,xr%2,xr%3,AS,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MACE_AS_LW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MACE xr%0,xr%1,xr%2,xr%3,AS,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MACE_AS_HW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MACE xr%0,xr%1,xr%2,xr%3,AS,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MACE_AS_XW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MACE xr%0,xr%1,xr%2,xr%3,AS,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MACE_SA_WW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MACE xr%0,xr%1,xr%2,xr%3,SA,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MACE_SA_LW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MACE xr%0,xr%1,xr%2,xr%3,SA,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MACE_SA_HW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MACE xr%0,xr%1,xr%2,xr%3,SA,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MACE_SA_XW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MACE xr%0,xr%1,xr%2,xr%3,SA,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MACE_SS_WW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MACE xr%0,xr%1,xr%2,xr%3,SS,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MACE_SS_LW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MACE xr%0,xr%1,xr%2,xr%3,SS,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MACE_SS_HW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MACE xr%0,xr%1,xr%2,xr%3,SS,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MACE_SS_XW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MACE xr%0,xr%1,xr%2,xr%3,SS,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++ ++/**********************************D16MADL*******************************/ ++#define D16MADL_AA_WW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MADL xr%0,xr%1,xr%2,xr%3,AA,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MADL_AA_LW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MADL xr%0,xr%1,xr%2,xr%3,AA,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MADL_AA_HW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MADL xr%0,xr%1,xr%2,xr%3,AA,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MADL_AA_XW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MADL xr%0,xr%1,xr%2,xr%3,AA,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MADL_AS_WW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MADL xr%0,xr%1,xr%2,xr%3,AS,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MADL_AS_LW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MADL xr%0,xr%1,xr%2,xr%3,AS,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MADL_AS_HW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MADL xr%0,xr%1,xr%2,xr%3,AS,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MADL_AS_XW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MADL xr%0,xr%1,xr%2,xr%3,AS,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MADL_SA_WW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MADL xr%0,xr%1,xr%2,xr%3,SA,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MADL_SA_LW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MADL xr%0,xr%1,xr%2,xr%3,SA,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MADL_SA_HW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MADL xr%0,xr%1,xr%2,xr%3,SA,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MADL_SA_XW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MADL xr%0,xr%1,xr%2,xr%3,SA,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MADL_SS_WW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MADL xr%0,xr%1,xr%2,xr%3,SS,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MADL_SS_LW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MADL xr%0,xr%1,xr%2,xr%3,SS,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MADL_SS_HW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MADL xr%0,xr%1,xr%2,xr%3,SS,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D16MADL_SS_XW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16MADL xr%0,xr%1,xr%2,xr%3,SS,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++ ++/***********************************S16MAD*******************************/ ++#define S16MAD_A_HH(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("S16MAD xr%0,xr%1,xr%2,xr%3,A,0" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define S16MAD_A_LL(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("S16MAD xr%0,xr%1,xr%2,xr%3,A,1" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define S16MAD_A_HL(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("S16MAD xr%0,xr%1,xr%2,xr%3,A,2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define S16MAD_A_LH(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("S16MAD xr%0,xr%1,xr%2,xr%3,A,3" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define S16MAD_S_HH(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("S16MAD xr%0,xr%1,xr%2,xr%3,S,0" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define S16MAD_S_LL(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("S16MAD xr%0,xr%1,xr%2,xr%3,S,1" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define S16MAD_S_HL(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("S16MAD xr%0,xr%1,xr%2,xr%3,S,2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define S16MAD_S_LH(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("S16MAD xr%0,xr%1,xr%2,xr%3,S,3" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++ ++ ++/***********************************Q8MUL********************************/ ++#define Q8MUL(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q8MUL xr%0,xr%1,xr%2,xr%3" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++// MXU enhancement ++#define Q8MULSU(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q8MULSU xr%0,xr%1,xr%2,xr%3" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++ ++/***********************************Q8MAC********************************/ ++#define Q8MAC_AA(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q8MAC xr%0,xr%1,xr%2,xr%3,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define Q8MAC_AS(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q8MAC xr%0,xr%1,xr%2,xr%3,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define Q8MAC_SA(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q8MAC xr%0,xr%1,xr%2,xr%3,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define Q8MAC_SS(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q8MAC xr%0,xr%1,xr%2,xr%3,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++// MXU enhancement ++#define Q8MACSU_AA(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q8MACSU xr%0,xr%1,xr%2,xr%3,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define Q8MACSU_AS(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q8MACSU xr%0,xr%1,xr%2,xr%3,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define Q8MACSU_SA(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q8MACSU xr%0,xr%1,xr%2,xr%3,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define Q8MACSU_SS(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q8MACSU xr%0,xr%1,xr%2,xr%3,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++/***********************************Q8MADL********************************/ ++#define Q8MADL_AA(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q8MADL xr%0,xr%1,xr%2,xr%3,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define Q8MADL_AS(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q8MADL xr%0,xr%1,xr%2,xr%3,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define Q8MADL_SA(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q8MADL xr%0,xr%1,xr%2,xr%3,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define Q8MADL_SS(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q8MADL xr%0,xr%1,xr%2,xr%3,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++ ++/***********************************D32ADD********************************/ ++#define D32ADD_AA(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D32ADD xr%0,xr%1,xr%2,xr%3,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D32ADD_AS(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D32ADD xr%0,xr%1,xr%2,xr%3,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D32ADD_SA(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D32ADD xr%0,xr%1,xr%2,xr%3,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D32ADD_SS(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D32ADD xr%0,xr%1,xr%2,xr%3,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++ ++/***********************************D32ACC********************************/ ++#define D32ACC_AA(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D32ACC xr%0,xr%1,xr%2,xr%3,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D32ACC_AS(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D32ACC xr%0,xr%1,xr%2,xr%3,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D32ACC_SA(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D32ACC xr%0,xr%1,xr%2,xr%3,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D32ACC_SS(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D32ACC xr%0,xr%1,xr%2,xr%3,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++// MXU enhancement ++#define D32ACCM_AA(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D32ACCM xr%0,xr%1,xr%2,xr%3,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D32ACCM_AS(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D32ACCM xr%0,xr%1,xr%2,xr%3,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D32ACCM_SA(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D32ACCM xr%0,xr%1,xr%2,xr%3,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D32ACCM_SS(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D32ACCM xr%0,xr%1,xr%2,xr%3,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D32ASUM_AA(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D32ASUM xr%0,xr%1,xr%2,xr%3,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D32ASUM_AS(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D32ASUM xr%0,xr%1,xr%2,xr%3,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D32ASUM_SA(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D32ASUM xr%0,xr%1,xr%2,xr%3,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define D32ASUM_SS(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D32ASUM xr%0,xr%1,xr%2,xr%3,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++ ++/***********************************S32CPS********************************/ ++#define S32CPS(xra,xrb,xrc) \ ++ do { \ ++ __asm__ __volatile ("S32CPS xr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ } while (0) ++ ++// MXU enhancement ++#define S32SLT(xra,xrb,xrc) \ ++ do { \ ++ __asm__ __volatile ("S32SLT xr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ } while (0) ++ ++#define S32MOVZ(xra,xrb,xrc) \ ++ do { \ ++ __asm__ __volatile ("S32MOVZ xr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ } while (0) ++ ++#define S32MOVN(xra,xrb,xrc) \ ++ do { \ ++ __asm__ __volatile ("S32MOVN xr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ } while (0) ++ ++#define S32AND(xra,xrb,xrc) \ ++ do { \ ++ __asm__ __volatile ("S32AND xr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ } while (0) ++ ++#define S32OR(xra,xrb,xrc) \ ++ do { \ ++ __asm__ __volatile ("S32OR xr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ } while (0) ++ ++#define S32XOR(xra,xrb,xrc) \ ++ do { \ ++ __asm__ __volatile ("S32XOR xr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ } while (0) ++ ++#define S32NOR(xra,xrb,xrc) \ ++ do { \ ++ __asm__ __volatile ("S32NOR xr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ } while (0) ++ ++#define S32ABS(xra,xrb) \ ++ do { \ ++ __asm__ __volatile ("S32CPS xr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrb)); \ ++ } while (0) ++ ++/***********************************Q16ADD********************************/ ++#define Q16ADD_AA_WW(xra,xrb,xrc,xrd)\ ++ do { \ ++ __asm__ __volatile ("Q16ADD xr%0,xr%1,xr%2,xr%3,AA,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define Q16ADD_AA_LW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q16ADD xr%0,xr%1,xr%2,xr%3,AA,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define Q16ADD_AA_HW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q16ADD xr%0,xr%1,xr%2,xr%3,AA,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define Q16ADD_AA_XW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q16ADD xr%0,xr%1,xr%2,xr%3,AA,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++#define Q16ADD_AS_WW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q16ADD xr%0,xr%1,xr%2,xr%3,AS,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define Q16ADD_AS_LW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q16ADD xr%0,xr%1,xr%2,xr%3,AS,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define Q16ADD_AS_HW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q16ADD xr%0,xr%1,xr%2,xr%3,AS,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define Q16ADD_AS_XW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q16ADD xr%0,xr%1,xr%2,xr%3,AS,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define Q16ADD_SA_WW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q16ADD xr%0,xr%1,xr%2,xr%3,SA,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define Q16ADD_SA_LW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q16ADD xr%0,xr%1,xr%2,xr%3,SA,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define Q16ADD_SA_HW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q16ADD xr%0,xr%1,xr%2,xr%3,SA,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define Q16ADD_SA_XW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q16ADD xr%0,xr%1,xr%2,xr%3,SA,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define Q16ADD_SS_WW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q16ADD xr%0,xr%1,xr%2,xr%3,SS,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define Q16ADD_SS_LW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q16ADD xr%0,xr%1,xr%2,xr%3,SS,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define Q16ADD_SS_HW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q16ADD xr%0,xr%1,xr%2,xr%3,SS,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define Q16ADD_SS_XW(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q16ADD xr%0,xr%1,xr%2,xr%3,SS,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++ ++/***********************************Q16ACC********************************/ ++#define Q16ACC_AA(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q16ACC xr%0,xr%1,xr%2,xr%3,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define Q16ACC_AS(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q16ACC xr%0,xr%1,xr%2,xr%3,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define Q16ACC_SA(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q16ACC xr%0,xr%1,xr%2,xr%3,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define Q16ACC_SS(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q16ACC xr%0,xr%1,xr%2,xr%3,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++// MXU enhancement ++#define Q16ACCM_AA(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q16ACCM xr%0,xr%1,xr%2,xr%3,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define Q16ACCM_AS(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q16ACCM xr%0,xr%1,xr%2,xr%3,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define Q16ACCM_SA(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q16ACCM xr%0,xr%1,xr%2,xr%3,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define Q16ACCM_SS(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q16ACCM xr%0,xr%1,xr%2,xr%3,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define Q16ASUM_AA(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q16ASUM xr%0,xr%1,xr%2,xr%3,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define Q16ASUM_AS(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q16ASUM xr%0,xr%1,xr%2,xr%3,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define Q16ASUM_SA(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q16ASUM xr%0,xr%1,xr%2,xr%3,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define Q16ASUM_SS(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q16ASUM xr%0,xr%1,xr%2,xr%3,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++/***********************************D16CPS********************************/ ++#define D16CPS(xra,xrb,xrc) \ ++ do { \ ++ __asm__ __volatile ("D16CPS xr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ } while (0) ++ ++// MXU enhancement ++#define D16SLT(xra,xrb,xrc) \ ++ do { \ ++ __asm__ __volatile ("D16SLT xr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ } while (0) ++ ++#define D16MOVZ(xra,xrb,xrc) \ ++ do { \ ++ __asm__ __volatile ("D16MOVZ xr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ } while (0) ++ ++#define D16MOVN(xra,xrb,xrc) \ ++ do { \ ++ __asm__ __volatile ("D16MOVN xr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ } while (0) ++ ++#define D16ABS(xra,xrb) \ ++ do { \ ++ __asm__ __volatile ("D16CPS xr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrb)); \ ++ } while (0) ++ ++/*******************************D16ASUM************************************/ ++#define D16ASUM_AA(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16ASUM xr%0,xr%1,xr%2,xr%3,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++#define D16ASUM_AS(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16ASUM xr%0,xr%1,xr%2,xr%3,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++#define D16ASUM_SA(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16ASUM xr%0,xr%1,xr%2,xr%3,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++#define D16ASUM_SS(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("D16ASUM xr%0,xr%1,xr%2,xr%3,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++/*******************************D16AVG/D16AVGR*****************************/ ++#define D16AVG(xra,xrb,xrc) \ ++ do { \ ++ __asm__ __volatile ("D16AVG xr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ } while (0) ++#define D16AVGR(xra,xrb,xrc) \ ++ do { \ ++ __asm__ __volatile ("D16AVGR xr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ } while (0) ++ ++/************************************Q8ADD********************************/ ++#define Q8ADD_AA(xra,xrb,xrc) \ ++ do { \ ++ __asm__ __volatile ("Q8ADD xr%0,xr%1,xr%2,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ } while (0) ++ ++#define Q8ADD_AS(xra,xrb,xrc) \ ++ do { \ ++ __asm__ __volatile ("Q8ADD xr%0,xr%1,xr%2,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ } while (0) ++ ++#define Q8ADD_SA(xra,xrb,xrc) \ ++ do { \ ++ __asm__ __volatile ("Q8ADD xr%0,xr%1,xr%2,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ } while (0) ++ ++#define Q8ADD_SS(xra,xrb,xrc) \ ++ do { \ ++ __asm__ __volatile ("Q8ADD xr%0,xr%1,xr%2,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ } while (0) ++ ++ ++/************************************Q8ADDE********************************/ ++#define Q8ADDE_AA(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q8ADDE xr%0,xr%1,xr%2,xr%3,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define Q8ADDE_AS(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q8ADDE xr%0,xr%1,xr%2,xr%3,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define Q8ADDE_SA(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q8ADDE xr%0,xr%1,xr%2,xr%3,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define Q8ADDE_SS(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q8ADDE xr%0,xr%1,xr%2,xr%3,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++/************************************Q8ACCE********************************/ ++#define Q8ACCE_AA(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q8ACCE xr%0,xr%1,xr%2,xr%3,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define Q8ACCE_AS(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q8ACCE xr%0,xr%1,xr%2,xr%3,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define Q8ACCE_SA(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q8ACCE xr%0,xr%1,xr%2,xr%3,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++#define Q8ACCE_SS(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q8ACCE xr%0,xr%1,xr%2,xr%3,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++ ++/************************************Q8ABD********************************/ ++#define Q8ABD(xra,xrb,xrc) \ ++ do { \ ++ __asm__ __volatile ("Q8ABD xr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ } while (0) ++ ++ ++/************************************Q8SLT********************************/ ++#define Q8SLT(xra,xrb,xrc) \ ++ do { \ ++ __asm__ __volatile ("Q8SLT xr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ } while (0) ++ ++// MXU enhancement ++#define Q8SLTU(xra,xrb,xrc) \ ++ do { \ ++ __asm__ __volatile ("Q8SLTU xr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ } while (0) ++ ++#define Q8MOVZ(xra,xrb,xrc) \ ++ do { \ ++ __asm__ __volatile ("Q8MOVZ xr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ } while (0) ++ ++#define Q8MOVN(xra,xrb,xrc) \ ++ do { \ ++ __asm__ __volatile ("Q8MOVN xr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ } while (0) ++ ++#define D8SUM(xra,xrb,xrc) \ ++ do { \ ++ __asm__ __volatile ("D8SUM xr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ } while (0) ++ ++#define D8SUMC(xra,xrb,xrc) \ ++ do { \ ++ __asm__ __volatile ("D8SUMC xr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ } while (0) ++ ++/************************************Q8SAD********************************/ ++#define Q8SAD(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q8SAD xr%0,xr%1,xr%2,xr%3" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++/************************************Q16SCOP******************************/ ++#define Q16SCOP(xra,xrb,xrc,xrd) \ ++ do { \ ++ __asm__ __volatile ("Q16SCOP xr%0,xr%1,xr%2,xr%3" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ } while (0) ++ ++/********************************Q8AVG/Q8AVGR*****************************/ ++#define Q8AVG(xra,xrb,xrc) \ ++ do { \ ++ __asm__ __volatile ("Q8AVG xr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ } while (0) ++#define Q8AVGR(xra,xrb,xrc) \ ++ do { \ ++ __asm__ __volatile ("Q8AVGR xr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ } while (0) ++ ++ ++/**********************************D32SHIFT******************************/ ++#define D32SLL(xra,xrb,xrc,xrd,SFT4) \ ++ do { \ ++ __asm__ __volatile ("D32SLL xr%0,xr%1,xr%2,xr%3,%4" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd),"K"(SFT4)); \ ++ } while (0) ++ ++#define D32SLR(xra,xrb,xrc,xrd,SFT4) \ ++ do { \ ++ __asm__ __volatile ("D32SLR xr%0,xr%1,xr%2,xr%3,%4" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd),"K"(SFT4)); \ ++ } while (0) ++ ++#define D32SAR(xra,xrb,xrc,xrd,SFT4) \ ++ do { \ ++ __asm__ __volatile ("D32SAR xr%0,xr%1,xr%2,xr%3,%4" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd),"K"(SFT4)); \ ++ } while (0) ++ ++#define D32SARL(xra,xrb,xrc,SFT4) \ ++ do { \ ++ __asm__ __volatile ("D32SARL xr%0,xr%1,xr%2,%3" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(SFT4)); \ ++ } while (0) ++ ++#define D32SLLV(xra,xrd,rb) \ ++ do { \ ++ __asm__ __volatile ("D32SLLV xr%0,xr%1,%z2" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d"(rb)); \ ++ } while (0) ++ ++#define D32SLRV(xra,xrd,rb) \ ++ do { \ ++ __asm__ __volatile ("D32SLRV xr%0,xr%1,%z2" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d"(rb)); \ ++ } while (0) ++ ++#define D32SARV(xra,xrd,rb) \ ++ do { \ ++ __asm__ __volatile ("D32SARV xr%0,xr%1,%z2" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d"(rb)); \ ++ } while (0) ++ ++#define D32SARW(xra,xrb,xrc,rb) \ ++ do { \ ++ __asm__ __volatile ("D32SARW xr%0,xr%1,xr%2,%3" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"d"(rb)); \ ++ } while (0) ++ ++ ++/**********************************Q16SHIFT******************************/ ++#define Q16SLL(xra,xrb,xrc,xrd,SFT4) \ ++ do { \ ++ __asm__ __volatile ("Q16SLL xr%0,xr%1,xr%2,xr%3,%4" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd),"K"(SFT4)); \ ++ } while (0) ++ ++#define Q16SLR(xra,xrb,xrc,xrd,SFT4) \ ++ do { \ ++ __asm__ __volatile ("Q16SLR xr%0,xr%1,xr%2,xr%3,%4" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd),"K"(SFT4));\ ++ } while (0) ++ ++#define Q16SAR(xra,xrb,xrc,xrd,SFT4) \ ++ do { \ ++ __asm__ __volatile ("Q16SAR xr%0,xr%1,xr%2,xr%3,%4" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd),"K"(SFT4));\ ++ } while (0) ++ ++#define Q16SLLV(xra,xrd,rb) \ ++ do { \ ++ __asm__ __volatile ("Q16SLLV xr%0,xr%1,%z2" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d"(rb)); \ ++ } while (0) ++ ++#define Q16SLRV(xra,xrd,rb) \ ++ do { \ ++ __asm__ __volatile ("Q16SLRV xr%0,xr%1,%z2" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d"(rb)); \ ++ } while (0) ++ ++#define Q16SARV(xra,xrd,rb) \ ++ do { \ ++ __asm__ __volatile ("Q16SARV xr%0,xr%1,%z2" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d"(rb)); \ ++ } while (0) ++ ++ ++/*********************************MAX/MIN*********************************/ ++#define S32MAX(xra,xrb,xrc) \ ++ do { \ ++ __asm__ __volatile ("S32MAX xr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ } while (0) ++ ++#define S32MIN(xra,xrb,xrc) \ ++ do { \ ++ __asm__ __volatile ("S32MIN xr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ } while (0) ++ ++#define D16MAX(xra,xrb,xrc) \ ++ do { \ ++ __asm__ __volatile ("D16MAX xr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ } while (0) ++ ++#define D16MIN(xra,xrb,xrc) \ ++ do { \ ++ __asm__ __volatile ("D16MIN xr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ } while (0) ++ ++#define Q8MAX(xra,xrb,xrc) \ ++ do { \ ++ __asm__ __volatile ("Q8MAX xr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ } while (0) ++ ++#define Q8MIN(xra,xrb,xrc) \ ++ do { \ ++ __asm__ __volatile ("Q8MIN xr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ } while (0) ++ ++ ++/*************************************MOVE********************************/ ++#define S32I2M(xra,rb)\ ++ do { \ ++ __asm__ __volatile ("S32I2M xr%0,%z1" \ ++ : \ ++ :"K"(xra),"d"(rb)); \ ++ } while (0) ++ ++#define S32M2I(xra) \ ++__extension__ ({ \ ++ int __d; \ ++ __asm__ __volatile ("S32M2I xr%1, %0" \ ++ :"=d"(__d) \ ++ :"K"(xra)); \ ++ __d; \ ++}) ++ ++ ++/*********************************S32SFL**********************************/ ++#define S32SFL(xra,xrb,xrc,xrd,optn2) \ ++ do { \ ++ __asm__ __volatile ("S32SFL xr%0,xr%1,xr%2,xr%3,ptn%4" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd),"K"(optn2)); \ ++ } while (0) ++ ++// MXU enhancement ++#define S32ALNI(xra,xrb,xrc,optn3) \ ++ do { \ ++ __asm__ __volatile ("S32ALNI xr%0,xr%1,xr%2,ptn%3" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(optn3)); \ ++ } while (0) ++ ++#define S32LUI(xra,s8,optn3) \ ++ do { \ ++ __asm__ __volatile ("S32LUI xr%0,%1,ptn%2" \ ++ : \ ++ :"K"(xra),"I"(s8),"K"(optn3)); \ ++ } while (0) ++ ++ ++/*********************************S32ALN**********************************/ ++#define S32ALN(xra,xrb,xrc,rs) \ ++ do { \ ++ __asm__ __volatile ("S32ALN xr%0,xr%1,xr%2,%z3" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"d"(rs)); \ ++ } while (0) ++ ++ ++/*********************************Q16SAT**********************************/ ++#define Q16SAT(xra,xrb,xrc) \ ++ do { \ ++ __asm__ __volatile ("Q16SAT xr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ } while (0) ++ ++#define S32EXTR(xra,xrd,rs,bits5) \ ++ do { \ ++ __asm__ __volatile ("S32EXTR xr%0,xr%1,%z2,%3" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d" (rs),"I"(bits5));\ ++ } while (0) ++ ++#define S32EXTRV(xra,xrd,rs,rt) \ ++ do { \ ++ __asm__ __volatile ("S32EXTRV xr%0,xr%1,%z2,%z3" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d" (rs),"d"(rt));\ ++ } while (0) ++ ++/*********************************S32MUL**********************************/ ++#define S32MUL(xra,xrd,rs,rt) \ ++ do { \ ++ __asm__ __volatile ("S32MUL xr%0,xr%1,%z2,%z3" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d" (rs),"d"(rt));\ ++ } while (0) ++ ++#define S32MULU(xra,xrd,rs,rt) \ ++ do { \ ++ __asm__ __volatile ("S32MULU xr%0,xr%1,%z2,%z3" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d" (rs),"d"(rt));\ ++ } while (0) ++ ++#define S32MADD(xra,xrd,rs,rt) \ ++ do { \ ++ __asm__ __volatile ("S32MADD xr%0,xr%1,%z2,%z3" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d" (rs),"d"(rt));\ ++ } while (0) ++ ++#define S32MADDU(xra,xrd,rs,rt) \ ++ do { \ ++ __asm__ __volatile ("S32MADDU xr%0,xr%1,%z2,%z3" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d" (rs),"d"(rt));\ ++ } while (0) ++ ++#define S32MSUB(xra,xrd,rs,rt) \ ++ do { \ ++ __asm__ __volatile ("S32MSUB xr%0,xr%1,%z2,%z3" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d" (rs),"d"(rt));\ ++ } while (0) ++ ++#define S32MSUBU(xra,xrd,rs,rt) \ ++ do { \ ++ __asm__ __volatile ("S32MSUBU xr%0,xr%1,%z2,%z3" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d" (rs),"d"(rt));\ ++ } while (0) ++ ++#endif /*_MXU_H_*/ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_include_mxuv3.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_include_mxuv3.h.patch new file mode 100644 index 00000000..ef05ad52 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_include_mxuv3.h.patch @@ -0,0 +1,46 @@ +diff -drupN a/arch/mips/xburst2/core/include/mxuv3.h b/arch/mips/xburst2/core/include/mxuv3.h +--- a/arch/mips/xburst2/core/include/mxuv3.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/core/include/mxuv3.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,42 @@ ++/* ++ * Copyright (C) 2005 Mips Technologies ++ * Author: Chris Dearman, chris@mips.com derived from fpu.h ++ * ++ * 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. ++ */ ++#ifndef _ASM_MXU_V3_H ++#define _ASM_MXU_V3_H ++ ++#include ++#include ++#include ++#include ++#include ++ ++void __init_mxuv3(void); ++void __save_mxuv3(void *tsk_void); ++void __restore_mxuv3(void *tsk_void); ++ ++static inline void init_mxuv3(void) ++{ ++ if(cpu_has_mxuv3) ++ __init_mxuv3(); ++} ++ ++ ++#define save_mxuv3(tsk) \ ++ do { \ ++ if (cpu_has_mxuv3) \ ++ __save_mxuv3(tsk); \ ++ } while (0) ++ ++#define restore_mxuv3(tsk) \ ++ do { \ ++ if (cpu_has_mxuv3) \ ++ __restore_mxuv3(tsk); \ ++ } while (0) ++ ++#endif /* _ASM_MXU_V3_H */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_prom.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_prom.c.patch new file mode 100644 index 00000000..b7c1838f --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_prom.c.patch @@ -0,0 +1,83 @@ +diff -drupN a/arch/mips/xburst2/core/prom.c b/arch/mips/xburst2/core/prom.c +--- a/arch/mips/xburst2/core/prom.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/core/prom.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,79 @@ ++/* ++ * Copyright (C) 2010, Lars-Peter Clausen ++ * JZ4740 SoC prom code ++ * ++ * 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. ++ * ++ * 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., ++ * 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++static __init void prom_init_cmdline(int argc, char *argv[]) ++{ ++ unsigned int count = COMMAND_LINE_SIZE - 1; ++ int i; ++ char *dst = &(arcs_cmdline[0]); ++ char *src; ++ ++ for (i = 1; i < argc && count; ++i) { ++ src = argv[i]; ++ while (*src && count) { ++ *dst++ = *src++; ++ --count; ++ } ++ *dst++ = ' '; ++ } ++ if (i > 1) ++ --dst; ++ ++ *dst = 0; ++} ++extern struct plat_smp_ops xburst2_smp_ops; ++static void *_fw_fdt_addr; ++ ++void __init prom_init(void) ++{ ++ prom_init_cmdline((int)fw_arg0, (char **)fw_arg1); ++ ++ if (fw_arg0 == 0 && fw_arg1 == 0xffffffffUL) ++ _fw_fdt_addr = phys_to_virt(fw_arg2); ++ else if ((int)fw_arg0 == -2) /*UHI*/ ++ _fw_fdt_addr = (void *)fw_arg1; ++ else if (__dtb_start != __dtb_end) ++ _fw_fdt_addr = __dtb_start; ++ else ++ panic("no dtb found!\n"); ++ ++ mips_machtype = MACH_XBURST2; ++#ifdef CONFIG_SMP ++ register_smp_ops(&xburst2_smp_ops); ++#endif ++} ++ ++void __init prom_free_prom_memory(void) ++{ ++} ++ ++const char *get_system_type(void) ++{ ++// return CONFIG_BOARD_NAME; ++ return "xburst2-based"; ++} ++void __init *get_fdt_addr(void) ++{ ++ return _fw_fdt_addr; ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_sc.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_sc.c.patch new file mode 100644 index 00000000..066960d0 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_sc.c.patch @@ -0,0 +1,203 @@ +diff -drupN a/arch/mips/xburst2/core/sc.c b/arch/mips/xburst2/core/sc.c +--- a/arch/mips/xburst2/core/sc.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/core/sc.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,199 @@ ++/* ++ * Copyright (C) 2006 Chris Dearman (chris@mips.com), ++ */ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * MIPS32/MIPS64 L2 cache handling ++ */ ++static unsigned long scache_size __read_mostly; ++/* ++ * Writeback and invalidate the secondary cache before DMA. ++ */ ++static void mips_sc_wback_inv(unsigned long addr, unsigned long size) ++{ ++ __sync(); ++ if (size >= scache_size) { ++ unsigned long lsize = cpu_scache_line_size(); ++ if (lsize == 64) ++ blast_scache64(); ++ else if (lsize == 32) ++ blast_scache32(); ++ else ++ printk("Error: Second CacheLine size.\n"); ++ } else { ++ blast_scache_range(addr, addr + size); ++ } ++#ifdef MIPS_BRIDGE_SYNC_WAR ++ if (MIPS_BRIDGE_SYNC_WAR) ++ __fast_iob(); ++#endif ++} ++ ++/* ++ * Invalidate the secondary cache before DMA. ++ */ ++static void mips_sc_inv(unsigned long addr, unsigned long size) ++{ ++ unsigned long lsize = cpu_scache_line_size(); ++ unsigned long almask = ~(lsize - 1); ++ ++ if (size >= scache_size) { ++ if (lsize == 64) ++ blast_scache64(); ++ else if (lsize == 32) ++ blast_scache32(); ++ else ++ printk("Error: Second CacheLine size.\n"); ++ }else { ++ cache_op(Hit_Writeback_Inv_SD, addr & almask); ++ cache_op(Hit_Writeback_Inv_SD, (addr + size - 1) & almask); ++ blast_inv_scache_range(addr, addr + size); ++ } ++#ifdef MIPS_BRIDGE_SYNC_WAR ++ if (MIPS_BRIDGE_SYNC_WAR) ++ __fast_iob(); ++#endif ++} ++ ++static void mips_sc_enable(void) ++{ ++ /* L2 cache is permanently enabled */ ++} ++ ++static void mips_sc_disable(void) ++{ ++ /* L2 cache is permanently enabled */ ++} ++ ++static struct bcache_ops mips_sc_ops = { ++ .bc_enable = mips_sc_enable, ++ .bc_disable = mips_sc_disable, ++ .bc_wback_inv = mips_sc_wback_inv, ++ .bc_inv = mips_sc_inv ++}; ++ ++/* ++ * Check if the L2 cache controller is activated on a particular platform. ++ * MTI's L2 controller and the L2 cache controller of Broadcom's BMIPS ++ * cores both use c0_config2's bit 12 as "L2 Bypass" bit, that is the ++ * cache being disabled. However there is no guarantee for this to be ++ * true on all platforms. In an act of stupidity the spec defined bits ++ * 12..15 as implementation defined so below function will eventually have ++ * to be replaced by a platform specific probe. ++ */ ++//static inline int mips_sc_is_activated(struct cpuinfo_mips *c) ++//{ ++// unsigned int config2 = read_c0_config2(); ++// unsigned int tmp; ++// ++// /* Check the bypass bit (L2B) */ ++// /*switch (c->cputype) { ++// case CPU_34K: ++// case CPU_74K: ++// case CPU_1004K: ++// case CPU_BMIPS5000: ++// if (config2 & (1 << 12)) ++// return 0; ++// }*/ ++// ++// tmp = (config2 >> 4) & 0x0f; ++// if (0 < tmp && tmp <= 7) ++// c->scache.linesz = 2 << tmp; ++// else ++// return 0; ++// return 1; ++//} ++ ++static inline int __init mips_sc_probe(void) ++{ ++ struct cpuinfo_mips *c = ¤t_cpu_data; ++ unsigned int config1, config2; ++ unsigned int tmp; ++ ++ /* Mark as not present until probe completed */ ++ c->scache.flags |= MIPS_CACHE_NOT_PRESENT; ++ ++ /* Ignore anything but MIPSxx processors */ ++ if((c->isa_level & (MIPS_CPU_ISA_M32R1 ++ | MIPS_CPU_ISA_M32R1 ++ | MIPS_CPU_ISA_M64R1 ++ | MIPS_CPU_ISA_M64R2)) == 0) { ++ return 0; ++ } ++ ++ switch (c->processor_id & PRID_CPU_FEATURE_MASK) { ++ case PRID_CPU_X2000: ++ break; ++ default: ++ printk("pls check processor_id[0x%08x],sc_jz not support!\n",c->processor_id); ++ } ++ ++ /* Does this MIPS32/MIPS64 CPU have a config2 register? */ ++ config1 = read_c0_config1(); ++ if (!(config1 & MIPS_CONF_M)) ++ return 0; ++ ++ config2 = read_c0_config2(); ++ ++ //if (!mips_sc_is_activated(c)) ++ tmp = (config2 >> 4) & 0x0f; ++ if (0 < tmp && tmp <= 7) ++ c->scache.linesz = 2 << tmp; ++ else ++ return 0; ++ ++ tmp = (config2 >> 8) & 0x0f; ++ if (0 <= tmp && tmp <= 7) ++ c->scache.sets = 64 << tmp; ++ else ++ return 0; ++ ++ tmp = (config2 >> 0) & 0x0f; ++ if ((tmp == 7) || (tmp == 15)) ++ c->scache.ways = tmp + 1; ++ else ++ return 0; ++ ++ c->scache.waysize = c->scache.sets * c->scache.linesz; ++ c->scache.waybit = __ffs(c->scache.waysize); ++ ++ c->scache.flags &= ~MIPS_CACHE_NOT_PRESENT; ++ scache_size = c->scache.ways * c->scache.sets * c->scache.linesz; ++ //write_c0_ecc(0x0);//verify xburst2 whether CP0-$26-0 is implemented. ++ return 1; ++} ++ ++static char *way_string[] = { NULL, "direct mapped", "2-way", ++ "3-way", "4-way", "5-way", "6-way", "7-way", "8-way", ++ "9-way", "10-way", "11-way", "12-way", ++ "13-way", "14-way", "15-way", "16-way", ++}; ++ ++int mips_sc_init(void) ++{ ++ struct cpuinfo_mips *c = ¤t_cpu_data; ++ int found = mips_sc_probe(); ++ printk("=======found ...... ingenic sc cache ops ...!, found: %d\n\n", found); ++ if (found) { ++ mips_sc_enable(); ++ bcops = &mips_sc_ops; ++ } ++ ++ printk("Unified secondary cache %ldkB %s, linesize %d bytes.\n", ++ scache_size >> 10, way_string[c->scache.ways], c->scache.linesz); ++ ++ c->options |= MIPS_CPU_INCLUSIVE_CACHES; ++ return found; ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_smp.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_smp.c.patch new file mode 100644 index 00000000..152156b6 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_core_smp.c.patch @@ -0,0 +1,503 @@ +diff -drupN a/arch/mips/xburst2/core/smp.c b/arch/mips/xburst2/core/smp.c +--- a/arch/mips/xburst2/core/smp.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/core/smp.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,499 @@ ++/* ++ * Copyright (C) 2001, 2002, 2003 Broadcom Corporation ++ * ++ * 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. ++ */ ++ ++//#define DEBUG ++//#define SMP_DEBUG ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++ ++#include ++ ++#include ++#include ++ ++#ifdef SMP_DEBUG ++static void xburst2_ccu_showregs(void) ++{ ++ int cpu = smp_processor_id(); ++ unsigned int val; ++ printk("CPU%d:\n",cpu); ++#define P(reg) do { \ ++ val = get_ccu_##reg(); \ ++ printk(#reg ":\t%08x\n", val); \ ++ } while(0) ++ ++ P(cscr); P(cssr); P(csrr); P(pipr); P(pimr); ++ P(mipr); P(mimr); P(oipr); P(oimr); P(rer); ++ P(cslr); P(csar); ++ //P(val); P(lock); ++ printk("cp0 status:\t%08x\n", read_c0_status()); ++ printk("cp0 cause:\t%08x\n", read_c0_cause()); ++} ++static void dump_code(const unsigned int *handler, const int count) ++{ ++ int i; ++ pr_info("\t.set push\n"); ++ pr_info("\t.set noreorder\n"); ++ ++ for (i = 0; i < count; i++) ++ pr_info("\t.word\t0x%08x\t\t# %p\n", handler[i], &handler[i]); ++ ++ pr_info("\t.set\tpop\n"); ++} ++#else ++static inline void xburst2_ccu_showregs(void) {} ++static inline void dump_code(const unsigned int *handler, const int count) {} ++#endif ++struct xburst2_mailbox{ ++ raw_spinlock_t lock; ++ void *__iomem *iobase; ++}; ++struct xburst2_smp { ++ unsigned long context_sp, context_gp; ++ unsigned long entry_base; ++ struct xburst2_mailbox mailbox[NR_CPUS]; ++ struct xburst2_mailbox * __percpu* percpu_mailbox; ++}; ++static struct xburst2_smp smp_core; ++void ingenic_percpu_timerevent_init(unsigned int cpu_num); ++void ingenic_percpu_irq_init(unsigned int cpu_num); ++ ++static irqreturn_t xburst2_mbox_interrupt(int irq, void *data) ++{ ++ unsigned int action = 0; ++ struct xburst2_mailbox *mailbox = *(struct xburst2_mailbox **)data; ++ raw_spin_lock(&mailbox->lock); ++ action = readl(mailbox->iobase); ++ writel(0,mailbox->iobase); ++ raw_spin_unlock(&mailbox->lock); ++ if (!action) { ++ pr_err("SMP[%d]:invalid mailboxes action is NULL\n",smp_processor_id()); ++ goto ipi_finish; ++ } ++ if (action & SMP_CALL_FUNCTION) { ++ generic_smp_call_function_interrupt(); ++ } ++ ++ if (action & SMP_RESCHEDULE_YOURSELF) { ++ scheduler_ipi(); ++ } ++ipi_finish: ++ return IRQ_HANDLED; ++} ++ ++void percpu_mailbox_init(int cpu) ++{ ++ smp_core.mailbox[cpu].iobase = ioremap(CCU_IO_BASE + cpu * 4 + 0x1000,4); ++ raw_spin_lock_init(&smp_core.mailbox[cpu].lock); ++ *this_cpu_ptr(smp_core.percpu_mailbox) = &smp_core.mailbox[cpu]; ++ writel(0, smp_core.mailbox[cpu].iobase); ++ enable_percpu_irq(CORE_MAILBOX_IRQ, IRQ_TYPE_NONE); ++} ++/* ++ * Code to run on secondary just after probing the CPU ++ */ ++static void xburst2_init_secondary(void) ++{ ++ int cpu = smp_processor_id(); ++ unsigned int mb_msk = get_ccu_mimr(); ++ unsigned int pmsk = get_ccu_pimr(); ++ unsigned int cpu_num = read_c0_ebase() & 0x1ff; ++// unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2; ++// int ret; ++ if(cpu == 0){ ++ pr_info("BUG: cpu0 is booted.\n"); ++ dump_stack(); ++ while(1); ++ } ++ pr_info("#### now starting init for cpu : %d\n", cpu); ++ clear_c0_cause(CAUSEF_IP); ++ clear_c0_status(ST0_IM); ++ mb_msk |= 1 << cpu; ++ set_ccu_mimr(mb_msk); ++ percpu_mailbox_init(cpu); ++ pr_debug("percpu %x\n",read_c0_status()); ++ ingenic_percpu_irq_init(cpu_num); ++ pmsk |= (1 << cpu); ++ set_ccu_pimr(pmsk); ++ ++ /* jzcpu_timer_setup(); */ ++ ++ xburst2_ccu_showregs(); ++ ingenic_percpu_timerevent_init(cpu_num); ++ set_ccu_oimr((1<common->affinity; ++ struct irq_chip *c; ++ bool ret = false; ++ ++ if (irqd_is_per_cpu(d) || !cpumask_test_cpu(cpu, affinity)) ++ return false; ++ ++ c = irq_data_get_irq_chip(d); ++ if(!c->irq_set_affinity) ++ return false; ++ if (cpumask_any_and(affinity, cpu_online_mask) >= nr_cpu_ids) { ++ affinity = cpu_online_mask; ++ ret = true; ++ } ++ ++ if (c->irq_set_affinity(d, affinity, true) == IRQ_SET_MASK_OK && ret) ++ cpumask_copy(d->common->affinity, affinity); ++ ++ return ret; ++} ++ ++static void migrate_irqs(int cpu) ++{ ++ unsigned int i; ++ struct irq_desc *desc; ++ for_each_irq_desc(i, desc) { ++ raw_spin_lock(&desc->lock); ++ migrate_one_irq(cpu,desc); ++ raw_spin_unlock(&desc->lock); ++ } ++} ++ ++/* ++ * Do any tidying up before marking online and running the idle ++ * loop ++ */ ++static void xburst2_smp_finish(void) ++{ ++ int cpu = smp_processor_id(); ++ migrate_irqs(cpu); ++ xburst2_ccu_showregs(); ++ local_irq_enable(); ++ pr_info("[SMP] slave cpu%d start up finished.\n",smp_processor_id()); ++} ++static void build_bounce_code(struct xburst2_smp *smp) ++{ ++ unsigned long *spp,*gpp; ++ unsigned int entry = (unsigned int)smp_bootstrap; ++ unsigned int *p; ++ p = (unsigned int*)__get_free_pages(GFP_KERNEL, 0); ++ spp = (unsigned long *)&smp->context_sp; ++ gpp = (unsigned long *)&smp->context_gp; ++ smp->entry_base = (unsigned int)p; ++ ++#define STATUS_BITS (ST0_CU0) ++#define CAUSE_BITS (1 << 27) ++#define C0_CAUSE 13,0 ++#define C0_STATUS 12,0 ++#define C0_COUNT 9,0 ++ ++ ++#define C0_CONFIG_0 16,0 ++#define V0 2 ++#define V1 3 ++#define GP 28 ++#define SP 29 ++#define RA 31 ++ /* the instructions'max size is 128 byte */ ++ ++ /* Disable IFU Small Buffer, system low power opt. */ ++ UASM_i_MFC0(&p, V0, 16, 7); ++ uasm_i_ori(&p, V0, V0, 7 << 3); ++ UASM_i_MTC0(&p, V0, 16, 7); ++ ++ /* kseg0 cache attribute */ ++ UASM_i_MFC0(&p,V0,C0_CONFIG_0); ++ UASM_i_LA(&p,V1,~7); ++ uasm_i_and(&p,V0,V0,V1); ++ uasm_i_ori(&p,V0,V0,3); ++ UASM_i_MTC0(&p,V0,C0_CONFIG_0); ++ ++ /* cause to DC disable. and status regitster reset */ ++ UASM_i_LA(&p,V0,CAUSE_BITS); ++ UASM_i_MTC0(&p,V0,C0_CAUSE); ++ ++ UASM_i_MTC0(&p,0,C0_COUNT); ++ ++ UASM_i_LA(&p,V0,STATUS_BITS); ++ UASM_i_MTC0(&p,V0,C0_STATUS); ++ ++ UASM_i_LA(&p, SP, (unsigned long)spp); ++ UASM_i_LW(&p, SP, 0,SP); ++ UASM_i_LA(&p, GP, (unsigned long)gpp); ++ UASM_i_LW(&p, GP, 0,GP); ++ UASM_i_LA(&p, RA, entry); ++ uasm_i_jr(&p, RA); ++ uasm_i_nop(&p); ++ dump_code((const unsigned int*)smp->entry_base,24); ++ //the code in ddr should be sure. ++ dma_cache_wback_inv(smp->entry_base,128); ++} ++ ++/* ++ * Setup the PC, SP, and GP of a secondary processor and start it ++ * running! ++ */ ++static void xburst2_boot_secondary(int cpu, struct task_struct *idle) ++{ ++ unsigned int reset;//,mb_msk; ++//TODO: clk enable. ++ /* set soft reset. */ ++ pr_info("[SMP] Booting CPU%d ...\n", cpu); ++ /* set reset entry! */ ++ set_ccu_rer(smp_core.entry_base); ++ ++ reset = get_ccu_csrr(); ++ reset |= 1 << cpu; ++ set_ccu_csrr(reset); ++ smp_core.context_sp = __KSTK_TOS(idle); ++ smp_core.context_gp = (unsigned long)task_thread_info(idle); ++ wmb(); ++/* clear soft reset. */ ++ reset &= ~(1 << cpu); ++ set_ccu_csrr(reset); ++ pr_debug("percpu %x\n",read_c0_status()); ++} ++ ++// prepare smp all core register but core0 should be hold. ++// the code is initialise core ccu register. ++ ++static void __init xburst2_smp_setup(void) ++{ ++ int i, num; ++ //set smp all core register disable. ++ set_ccu_mimr(0); ++ //note:core reset register and core0 shouldn't be set. ++ set_ccu_csrr(0xfffe); ++ ++ ++ cpumask_clear_cpu(NR_CPUS, (struct cpumask *)cpu_possible_mask); ++ cpumask_clear_cpu(NR_CPUS, (struct cpumask *)cpu_present_mask); ++ ++ //initial core0 register. ++ ++ cpumask_set_cpu(0, (struct cpumask *)cpu_possible_mask); ++ cpumask_set_cpu(0, (struct cpumask *)cpu_present_mask); ++ ++ __cpu_number_map[0] = 0; ++ __cpu_logical_map[0] = 0; ++ ++ for (i = 1, num = 0; i < NR_CPUS; i++) { ++ cpumask_set_cpu(i, (struct cpumask *)cpu_possible_mask); ++ cpumask_set_cpu(i, (struct cpumask *)cpu_present_mask); ++ ++ __cpu_number_map[i] = ++num; ++ __cpu_logical_map[num] = i; ++ } ++ ++ pr_info("[SMP] Slave CPU(s) %i available.\n", num); ++} ++ ++//prepare initial code for every core. ++static void __init xburst2_prepare_cpus(unsigned int max_cpus) ++{ ++ int ret; ++ pr_info("[SMP] Prepare %d cores., cpu: %d\n", max_cpus, smp_processor_id());//qiao ++ ++ if (max_cpus <= 1) ++ return; ++ ++ smp_core.percpu_mailbox = alloc_percpu(struct xburst2_mailbox*); ++ if(!smp_core.percpu_mailbox) ++ pr_err("ERROR:alloc mailbox percpu fail!\n"); ++ ++ ret = request_percpu_irq(CORE_MAILBOX_IRQ,xburst2_mbox_interrupt,"jz-mailbox", ++ smp_core.percpu_mailbox); ++ if(ret) { ++ pr_err("ERROR: cpu%d request ost error\n",smp_processor_id()); ++ } ++ percpu_mailbox_init(0); ++ set_ccu_mimr(1 << 0); ++ /* prepare slave cpus entry code */ ++ build_bounce_code(&smp_core); ++ /* set reset entry point */ ++ set_ccu_rer(smp_core.entry_base);//qiao ++ pr_debug("smp_bounce.base: %08lx\n", smp_core.entry_base); ++} ++ ++static void xburst2_send_ipi_single(int cpu, unsigned int action) ++{ ++ //unsigned int timeout=0x1000000; ++ ++ struct xburst2_mailbox *mailbox = per_cpu(*smp_core.percpu_mailbox,cpu); ++ unsigned int val; ++ unsigned long flags; ++#if 0 ++ while((readl(mailbox->iobase) & action) && (--timeout)); ++ if(timeout == 0){ ++ pr_err("SMP[%d] action:%d will reenter\n",cpu,action); ++ } ++#endif ++ ++ raw_spin_lock_irqsave(&mailbox->lock,flags); ++ val = readl(mailbox->iobase); ++ writel(action | val,mailbox->iobase); ++ raw_spin_unlock_irqrestore(&mailbox->lock,flags); ++} ++ ++static void xburst2_send_ipi_mask(const struct cpumask *mask, unsigned int action) ++{ ++ int i; ++ for(i = 0; i < NR_CPUS;i++){ ++ if(cpumask_test_cpu(i,(struct cpumask *)mask)){ ++ xburst2_send_ipi_single(i,action); ++ } ++ } ++} ++/** ++ * all cpu finish ++ */ ++void xburst2_cpus_done(void) ++{ ++// FIXME: will remove this code. ++ pr_debug("[SMP]: xburst2_cpus_done\n"); ++} ++ ++#ifdef CONFIG_HOTPLUG_CPU ++ ++void ingenic_percpu_timerevent_deinit(void); ++void ingenic_percpu_irq_deinit(void); ++static int xburst2_cpu_disable(void) ++{ ++ unsigned int cpu = smp_processor_id(); ++ unsigned int val; ++ if (cpu == 0) ++ return -EBUSY; ++ pr_info("SMP: CPU%d is offline\n", cpu); ++ set_cpu_online(cpu, false); ++ cpumask_clear_cpu(cpu, &cpu_callin_map); ++ ++ val = get_ccu_pimr(); ++ val &= ~(1 << cpu); ++ set_ccu_pimr(val); ++ ++ val = get_ccu_oimr(); ++ val &= ~(1 << cpu); ++ set_ccu_oimr(val); ++ ++ //val = get_ccu_mimr(); ++ //val &= ~(1 << cpu); ++ //set_ccu_mimr(val); ++ ++ ingenic_percpu_irq_deinit(); ++ ingenic_percpu_timerevent_deinit(); ++ migrate_irqs(cpu); ++ clear_tasks_mm_cpumask(cpu); ++ ++ pr_debug("disabled cpu %d\n",cpu); ++ return 0; ++} ++ ++void xburst2_cpu_die(unsigned int cpu) ++{ ++ unsigned int timeout = 0x100000; ++ unsigned int reset; ++ if (cpu == 0) ++ return; ++ ++ while((get_ccu_cssr() & (1< ++#include ++#include ++#include ++#include ++#include ++ ++#define OPENPMON \ ++ char perf_array[256] = {0}; \ ++ int fperf = open("/proc/jz/pmon/perform",O_RDWR); \ ++ if(fperf <= 0) \ ++ printf("open pmon error!\n"); \ ++ ++#define CLOSEFS close(fperf) ++ ++#define START0 memset(perf_array,0,255); write(fperf,"perf0",5); ++#define START1 memset(perf_array,0,255); write(fperf,"perf1",5); ++#define START2 memset(perf_array,0,255); write(fperf,"perf2",5); ++#define START3 memset(perf_array,0,255); write(fperf,"perf3",5); ++#define START4 memset(perf_array,0,255); write(fperf,"perf4",5); ++#define START5 memset(perf_array,0,255); write(fperf,"perf5",5); ++#define START6 memset(perf_array,0,255); write(fperf,"perf6",5); ++#define START7 memset(perf_array,0,255); write(fperf,"perf7",5); ++#define START8 memset(perf_array,0,255); write(fperf,"perf8",5); ++#define START9 memset(perf_array,0,255); write(fperf,"perf9",5); ++#define START10 memset(perf_array,0,255); write(fperf,"perf10",6); ++#define START48 memset(perf_array,0,255); write(fperf,"perf48",6); ++#define START49 memset(perf_array,0,255); write(fperf,"perf49",6); ++#define START50 memset(perf_array,0,255); write(fperf,"perf50",6); ++#define START51 memset(perf_array,0,255); write(fperf,"perf51",6); ++#define START52 memset(perf_array,0,255); write(fperf,"perf52",6); ++#define START53 memset(perf_array,0,255); write(fperf,"perf53",6); ++#define START54 memset(perf_array,0,255); write(fperf,"perf54",6); ++#define START55 memset(perf_array,0,255); write(fperf,"perf55",6); ++#define START56 memset(perf_array,0,255); write(fperf,"perf56",6); ++#define START57 memset(perf_array,0,255); write(fperf,"perf57",6); ++#define START58 memset(perf_array,0,255); write(fperf,"perf58",6); ++#define START59 memset(perf_array,0,255); write(fperf,"perf59",6); ++#define STOP \ ++ lseek(fperf,0,SEEK_SET); \ ++ read(fperf,perf_array,255); \ ++ write(fperf,"perfstop",8); \ ++ printf("%s",perf_array); ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_Kconfig.DT.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_Kconfig.DT.patch new file mode 100644 index 00000000..a36b352d --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_Kconfig.DT.patch @@ -0,0 +1,6 @@ +diff -drupN a/arch/mips/xburst2/soc-t40/Kconfig.DT b/arch/mips/xburst2/soc-t40/Kconfig.DT +--- a/arch/mips/xburst2/soc-t40/Kconfig.DT 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-t40/Kconfig.DT 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,2 @@ ++config DT_T40_SHARK ++ bool "t40 shark" diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_Makefile.patch new file mode 100644 index 00000000..950c60b1 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_Makefile.patch @@ -0,0 +1,12 @@ +diff -drupN a/arch/mips/xburst2/soc-t40/Makefile b/arch/mips/xburst2/soc-t40/Makefile +--- a/arch/mips/xburst2/soc-t40/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-t40/Makefile 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,8 @@ ++obj-y += setup.o ++obj-y += serial.o ++ ++obj-y += pm.o ++obj-y += regs_save_restore.o ++obj-y += libdmmu.o ++obj-y += gpio.o ++obj-y += reset.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_gpio.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_gpio.c.patch new file mode 100644 index 00000000..32ec5848 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_gpio.c.patch @@ -0,0 +1,127 @@ +diff -drupN a/arch/mips/xburst2/soc-t40/gpio.c b/arch/mips/xburst2/soc-t40/gpio.c +--- a/arch/mips/xburst2/soc-t40/gpio.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-t40/gpio.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,123 @@ ++#include ++#include ++#include ++#include ++#include ++ ++#define GPIO_PORT_OFF 0x1000 ++#define GPIO_SHADOW_OFF 0x7000 ++ ++#define PXPIN 0x00 /* PIN Level Register */ ++#define PXINT 0x10 /* Port Interrupt Register */ ++#define PXINTS 0x14 /* Port Interrupt Set Register */ ++#define PXINTC 0x18 /* Port Interrupt Clear Register */ ++#define PXMSK 0x20 /* Port Interrupt Mask Reg */ ++#define PXMSKS 0x24 /* Port Interrupt Mask Set Reg */ ++#define PXMSKC 0x28 /* Port Interrupt Mask Clear Reg */ ++#define PXPAT1 0x30 /* Port Pattern 1 Set Reg. */ ++#define PXPAT1S 0x34 /* Port Pattern 1 Set Reg. */ ++#define PXPAT1C 0x38 /* Port Pattern 1 Clear Reg. */ ++#define PXPAT0 0x40 /* Port Pattern 0 Register */ ++#define PXPAT0S 0x44 /* Port Pattern 0 Set Register */ ++#define PXPAT0C 0x48 /* Port Pattern 0 Clear Register */ ++#define PXFLG 0x50 /* Port Flag Register */ ++#define PXFLGC 0x58 /* Port Flag clear Register */ ++#define PXPU 0x110 /* Port PULL-UP State Register */ ++#define PXPUS 0x114 /* Port PULL-UP State Set Register */ ++#define PXPUC 0x118 /* Port PULL-UP State Clear Register */ ++#define PXPD 0x120 /* Port PULL-DOWN State Register */ ++#define PXPDS 0x124 /* Port PULL-DOWN State Set Register */ ++#define PXPDC 0x128 /* Port PULL-DOWN State Clear Register */ ++ ++#define PZGID2LD 0xF0 /* GPIOZ Group ID to load */ ++ ++#define SHADOW 5 ++ ++static const unsigned long gpiobase[] = { ++ [0] = (unsigned long)CKSEG1ADDR(GPIO_IOBASE + 0 * GPIO_PORT_OFF), ++ [1] = (unsigned long)CKSEG1ADDR(GPIO_IOBASE + 1 * GPIO_PORT_OFF), ++ [2] = (unsigned long)CKSEG1ADDR(GPIO_IOBASE + 2 * GPIO_PORT_OFF), ++ [3] = (unsigned long)CKSEG1ADDR(GPIO_IOBASE + 3 * GPIO_PORT_OFF), ++ [4] = (unsigned long)CKSEG1ADDR(GPIO_IOBASE + 4 * GPIO_PORT_OFF), ++ ++ [SHADOW] = (unsigned long)CKSEG1ADDR(GPIO_IOBASE + GPIO_SHADOW_OFF), ++}; ++ ++#define GPIO_ADDR(port, reg) ((volatile unsigned long *)(gpiobase[port] + reg)) ++ ++static inline void gpio_write(int port, unsigned int reg, int val) ++{ ++ *GPIO_ADDR(port, reg) = val; ++} ++ ++static inline unsigned int gpio_read(int port, unsigned int reg) ++{ ++ return *GPIO_ADDR(port, reg); ++} ++ ++static void hal_gpio_port_set_func(int port, unsigned int pins, enum gpio_function func) ++{ ++ /* func option */ ++ if (func & 0x10) { ++ if (func & 0x8) ++ gpio_write(SHADOW, PXINTS, pins); ++ else ++ gpio_write(SHADOW, PXINTC, pins); ++ ++ if (func & 0x4) ++ gpio_write(SHADOW, PXMSKS, pins); ++ else ++ gpio_write(SHADOW, PXMSKC, pins); ++ ++ if (func & 0x2) ++ gpio_write(SHADOW, PXPAT1S, pins); ++ else ++ gpio_write(SHADOW, PXPAT1C, pins); ++ ++ if (func & 0x1) ++ gpio_write(SHADOW, PXPAT0S, pins); ++ else ++ gpio_write(SHADOW, PXPAT0C, pins); ++ ++ /* configure PzGID2LD to specify which port group to load */ ++ gpio_write(SHADOW, PZGID2LD, port); ++ } ++ ++ if (func & 0x80) { ++ int pull = (func >> 5) & 0x3; ++ if (pull == 0) { // no pull ++ gpio_write(port, PXPUC, pins); ++ gpio_write(port, PXPDC, pins); ++ } ++ if (pull == 1) { // pull up ++ gpio_write(port, PXPDC, pins); ++ gpio_write(port, PXPUS, pins); ++ } ++ if (pull == 2) { // pull down ++ gpio_write(port, PXPUC, pins); ++ gpio_write(port, PXPDS, pins); ++ } ++ } ++} ++ ++unsigned long ingenic_pinctrl_lock(int port); ++void ingenic_pinctrl_unlock(int port, unsigned long flags); ++ ++int jzgpio_set_func(int port, enum gpio_function func, unsigned long pins) ++{ ++ unsigned long flags; ++ ++ if (port < 0 || port > 4) { ++ printk(KERN_ERR "gpio: invalid gpio port for x2000: %d\n", port); ++ return -EINVAL; ++ } ++ ++ flags = ingenic_pinctrl_lock(port); ++ ++ hal_gpio_port_set_func(port, pins, func); ++ ++ ingenic_pinctrl_unlock(port, flags); ++ ++ return 0; ++} ++EXPORT_SYMBOL(jzgpio_set_func); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_cpu-feature-overrides.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_cpu-feature-overrides.h.patch new file mode 100644 index 00000000..90c0ad44 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_cpu-feature-overrides.h.patch @@ -0,0 +1,70 @@ +diff -drupN a/arch/mips/xburst2/soc-t40/include/cpu-feature-overrides.h b/arch/mips/xburst2/soc-t40/include/cpu-feature-overrides.h +--- a/arch/mips/xburst2/soc-t40/include/cpu-feature-overrides.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-t40/include/cpu-feature-overrides.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,66 @@ ++/* ++ * Copyright (C) 2008 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * 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. ++ */ ++ ++#ifndef __ASM_MACH_INGENIC_CPU_FEATURE_OVERRIDES_H__ ++#define __ASM_MACH_INGENIC_CPU_FEATURE_OVERRIDES_H__ ++ ++ ++#define cpu_dcache_size() (32 * 1024) ++#define cpu_dcache_ways() 8 ++#define cpu_dcache_line_size() 32 ++#define cpu_icache_size() (32 * 1024) ++#define cpu_icache_ways() 8 ++#define cpu_icache_line_size() 32 ++#define cpu_has_xpa 0 ++#define cpu_has_tlb 1 ++#define cpu_has_tlbinv 1 ++#define cpu_has_4kex 1 ++#define cpu_has_3k_cache 0 ++#define cpu_has_4k_cache 1 ++#define cpu_has_tx39_cache 0 ++#define cpu_has_fpu 1 ++#define cpu_has_32fpr 0 ++#define cpu_has_counter 0 ++#define cpu_has_watch 1 ++#define cpu_has_divec 1 ++#define cpu_has_vce 0 ++#define cpu_has_cache_cdex_p 0 ++#define cpu_has_cache_cdex_s 0 ++#define cpu_has_prefetch 1 ++#define cpu_has_mcheck 1 ++#define cpu_has_ejtag 0 ++#define cpu_has_llsc 1 ++#define kernel_uses_llsc cpu_has_llsc ++#define cpu_has_mips16 0 ++#define cpu_has_mdmx 0 ++#define cpu_has_mips3d 0 ++#define cpu_has_smartmips 0 ++#define cpu_has_vtag_icache 0 ++#define cpu_has_dc_aliases 0 ++#define cpu_has_ic_fills_f_dc 0 ++#define cpu_has_pindexed_dcache 0 ++#define cpu_icache_snoops_remote_store 0 ++#define cpu_has_mips32r1 0 ++#define cpu_has_mips32r2 1 ++#define cpu_has_mips64r1 0 ++#define cpu_has_mips64r2 0 ++#define cpu_has_dsp 0 ++#define cpu_has_mipsmt 0 ++#define cpu_has_userlocal 1 ++#define cpu_has_rixi 1 ++#define cpu_has_nofpuex 0 ++#define cpu_has_64bits 0 ++#define cpu_has_64bit_zero_reg 0 ++#define cpu_has_vint 0 ++#define cpu_has_veic 0 ++#define cpu_has_inclusive_pcaches 0 ++#define kernel_uses_smartmips_rixi 0 ++#define cpu_has_mxuv3 1 ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_irq.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_irq.h.patch new file mode 100644 index 00000000..63bd139c --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_irq.h.patch @@ -0,0 +1,44 @@ +diff -drupN a/arch/mips/xburst2/soc-t40/include/irq.h b/arch/mips/xburst2/soc-t40/include/irq.h +--- a/arch/mips/xburst2/soc-t40/include/irq.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-t40/include/irq.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,40 @@ ++/* ++ * Copyright (C) 2010 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * 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. ++ */ ++ ++#ifndef __ASM_MACH_INGENIC_IRQ_H__ ++#define __ASM_MACH_INGENIC_IRQ_H__ ++#include ++#include ++ ++enum { ++#define GPIO_NR_IRQS (32 * 5 + 16) ++ IRQ_GPIO_BASE = (IRQ_INTC_END + 1), ++ IRQ_GPIO_END = IRQ_GPIO_BASE + GPIO_NR_IRQS - 1, ++ ++#define TCU_NR_IRQS (8) ++ IRQ_TCU_BASE, ++ IRQ_TCU_END = IRQ_TCU_BASE + TCU_NR_IRQS - 1, ++ ++#define MCU_NR_IRQS (5) ++ IRQ_MCU_BASE, ++ IRQ_MCU_END = IRQ_MCU_BASE + MCU_NR_IRQS - 1, ++ ++#define SADC_NR_IRQS (8) ++ IRQ_SADC_BASE, ++ IRQ_SADC_END = IRQ_SADC_BASE + SADC_NR_IRQS - 1, ++ ++#define RESERVED_NR_IRQS (150) ++ IRQ_RESERVED_BASE, ++ IRQ_RESERVED_END = IRQ_RESERVED_BASE + RESERVED_NR_IRQS - 1, ++ ++ NR_IRQS, ++}; ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_libdmmu.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_libdmmu.h.patch new file mode 100644 index 00000000..9f0b4d08 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_libdmmu.h.patch @@ -0,0 +1,18 @@ +diff -drupN a/arch/mips/xburst2/soc-t40/include/libdmmu.h b/arch/mips/xburst2/soc-t40/include/libdmmu.h +--- a/arch/mips/xburst2/soc-t40/include/libdmmu.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-t40/include/libdmmu.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,14 @@ ++#ifndef _LIBDMMU_ ++#define _LIBDMMU_ ++ ++#include ++ ++unsigned long dmmu_map(struct device *dev,unsigned long vaddr,unsigned long len); ++int dmmu_flush_cache(unsigned long vaddr, unsigned long len); ++int dmmu_unmap(struct device *dev,unsigned long vaddr, int len); ++int dmmu_unmap_all(struct device *dev); ++void dmmu_dump_vaddr(unsigned long vaddr); ++int dmmu_memory_smash(unsigned long vaddr, int smash_mode); ++int dmmu_dump_map(unsigned long vaddr); ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_base.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_base.h.patch new file mode 100644 index 00000000..5525dda7 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_base.h.patch @@ -0,0 +1,101 @@ +diff -drupN a/arch/mips/xburst2/soc-t40/include/soc/base.h b/arch/mips/xburst2/soc-t40/include/soc/base.h +--- a/arch/mips/xburst2/soc-t40/include/soc/base.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-t40/include/soc/base.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,97 @@ ++ ++#ifndef __JZSOC_SOC_DEV_H__ ++#define __JZSOC_SOC_DEV_H__ ++ ++/* ++ * Define the module base addresses ++ */ ++ ++/* AHB0 BUS Devices Base */ ++#define HARB0_IOBASE 0x13000000 ++#define DDRC_BASE 0xb34f0000 ++#define DDRC1_IOBASE 0x13010000 /*DDR_APB_BASE*/ ++#define DDRC_IOBASE 0x134f0000 /*TODO:*/ ++#define DDRPHY_IOBASE 0x13011000 /*TODO:*/ ++#define AXI_ARB1_IOBASE 0x13013000 /*TODO:*/ ++#define AXI_ARB2_IOBASE 0x13014000 /*TODO:*/ ++#define LCDC_IOBASE 0x13050000 ++#define MSC0_IOBASE 0x13060000 ++#define MSC1_IOBASE 0x13070000 ++#define IPU_IOBASE 0x13080000 ++#define BSCALER_IOBASE 0x13090000 ++#define MONITOR_IOBASE 0x130a0000 ++#define I2D_IOBASE 0x130b0000 ++#define VO_IOBASE 0x130c0000 ++#define DRAW_BOX_IOBASE 0x130d0000 ++#define ISP_IOBASE 0x13300000 ++#define LZMA_IOBASE 0x13090000 ++ ++/* AHB1 BUS Devices Base */ ++#define RTC_IOBASE 0x132a0000 ++#define EL150_IOBASE 0x13200000 ++#define RADIX_IOBASE 0x13100000 ++#define RADIX_IOBASE_UNIT(ID) (RADIX_IOBASE + 0x400000 * ID) ++#define AVPU_IOBASE 0x13200000 ++#define AVPU_IOBASE_UNIT(ID) (AVPU_IOBASE + 0x400000 * ID) ++ ++/* AHB2 BUS Devices Base */ ++#define HARB2_IOBASE 0x13400000 ++#define NEMC_IOBASE 0x13410000 ++#define PDMA_IOBASE 0x13420000 ++#define AES_IOBASE 0x13430000 ++#define SFC_IOBASE 0x13440000 ++#define HASH_IOBASE 0x13480000 ++#define GMAC_IOBASE 0x134b0000 ++#define RSA_IOBASE 0x134c0000 ++#define OTG_IOBASE 0x13500000 ++#define EFUSE_IOBASE 0x13540000 ++#define INTC_IOBASE 0x10001000 ++ ++/* CPU and OST */ ++#define G_OST_IOBASE 0x12000000 /* G_OST_BASE */ ++#define N_OST_IOBASE 0x12100000 /* N_OST_BASE */ ++#define CCU_IOBASE 0x12200000 ++#define INTCN_IOBASE 0x12300000 ++#define SRAM_IOBASE 0x12400000 ++#define NNDMA_IOBASE 0x12500000 ++#define LEPOST_IOBASE 0x12600000 /* RISC-V OST */ ++#define LEPCCU_IOBASE 0x12700000 /* RISC-V CCU */ ++ ++/* APB BUS Devices Base */ ++#define CPM_IOBASE 0x10000000 ++#define TCU_IOBASE 0x10002000 ++#define MIPI_DSI_TX_IOBASE 0x10003000 ++#define MIPI_DSI_PHY_IOBASE 0x10004000 ++#define GPIO_IOBASE 0x10010000 ++#define AIC0_IOBASE 0x10020000 ++#define CODEC_IOBASE 0x10021000 ++#define MIPI_PHY_IOBASE 0x10022000 ++#define MIPI_CSI_IOBASE 0x10023000 ++#define UART0_IOBASE 0x10030000 ++#define UART1_IOBASE 0x10031000 ++#define UART2_IOBASE 0x10032000 ++#define UART3_IOBASE 0x10033000 ++#define DMIC_IOBASE 0x10034000 ++#define SSISLV_IOBASE 0x10040000 ++#define SSI0_IOBASE 0x10043000 ++#define SSI1_IOBASE 0x10044000 ++#define I2C0_IOBASE 0x10050000 ++#define I2C1_IOBASE 0x10051000 ++#define I2C2_IOBASE 0x10052000 ++#define I2C3_IOBASE 0x10053000 ++#define MIPI_RX_4L_IOBASE 0x10054000 ++#define USB_IOBASE 0x10060000 ++#define DES_IOBASE 0x10061000 ++#define SADC_IOBASE 0x10070000 ++#define DTRNG_IOBASE 0x10072000 ++#define WDT_IOBASE 0x10002000 ++ ++/* NAND CHIP Base Address*/ ++#define NEMC_CS1_IOBASE 0X1b000000 ++#define NEMC_CS2_IOBASE 0X1a000000 ++#define NEMC_CS3_IOBASE 0X19000000 ++#define NEMC_CS4_IOBASE 0X18000000 ++#define NEMC_CS5_IOBASE 0X17000000 ++#define NEMC_CS6_IOBASE 0X16000000 ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_cache.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_cache.h.patch new file mode 100644 index 00000000..e03b0e28 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_cache.h.patch @@ -0,0 +1,77 @@ +diff -drupN a/arch/mips/xburst2/soc-t40/include/soc/cache.h b/arch/mips/xburst2/soc-t40/include/soc/cache.h +--- a/arch/mips/xburst2/soc-t40/include/soc/cache.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-t40/include/soc/cache.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,73 @@ ++#ifndef __CHIP_CACHE_H__ ++#define __CHIP_CACHE_H__ ++#include ++#include ++ ++#define Index_Prefetch_I 0x1c ++ ++ ++#define cache_prefetch(label,size) \ ++do{ \ ++ unsigned long addr,end; \ ++ /* Prefetch codes from label */ \ ++ addr = (unsigned long)(&&label) & ~(32 - 1); \ ++ end = (unsigned long)(&&label + size) & ~(32 - 1); \ ++ end += 32; \ ++ for (; addr < end; addr += 32) { \ ++ __asm__ volatile ( \ ++ ".set push \n\t" \ ++ ".set mips32 \n\t" \ ++ " cache %0, 0(%1)\n\t" \ ++ ".set pop \n\t" \ ++ : \ ++ : "I" (Index_Prefetch_I), "r"(addr)); \ ++ } \ ++} \ ++while(0) ++ ++#define K0BASE KSEG0 ++#define CFG_DCACHE_SIZE 32768 ++#define CFG_ICACHE_SIZE 32768 ++#define CFG_CACHELINE_SIZE 32 ++ ++#define CFG_SDCACHE_SIZE (512*1024) ++#define CFG_SDCACHELINE_SIZE 64 ++ ++static inline void __jz_flush_cache_all(void) ++{ ++ register unsigned long addr; ++ /* Clear CP0 TagLo */ ++ for (addr = K0BASE; addr < (K0BASE + CFG_DCACHE_SIZE); addr += CFG_CACHELINE_SIZE) { ++ asm volatile (".set mips32\n\t" ++ " cache %0, 0(%1)\n\t" ++ ".set mips32\n\t" ++ : ++ : "I" (Index_Writeback_Inv_D), "r"(addr)); ++ } ++ ++ for (addr = K0BASE; addr < (K0BASE + CFG_ICACHE_SIZE); addr += CFG_CACHELINE_SIZE) { ++ asm volatile (".set mips32\n\t" ++ " cache %0, 0(%1)\n\t" ++ ".set mips32\n\t" ++ : ++ : "I" (Index_Invalidate_I), "r"(addr)); ++ } ++ ++ asm volatile ("sync\n\t" ++ "lw $0,0(%0)" ++ ::"r" (0xa0000000)); ++ /* 2nd cache */ ++ for (addr = K0BASE; addr < (K0BASE + CFG_SDCACHE_SIZE); addr += CFG_SDCACHELINE_SIZE) { ++ asm volatile (".set mips32\n\t" ++ " cache %0, 0(%1)\n\t" ++ ".set mips32\n\t" ++ : ++ : "I" (Index_Writeback_Inv_SD), "r"(addr)); ++ } ++ ++ asm volatile ("sync\n\t" ++ "lw $0,0(%0)" ++ ::"r" (0xa0000000)); ++} ++ ++#endif /* __CHIP_CACHE_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_cpm.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_cpm.h.patch new file mode 100644 index 00000000..b306540e --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_cpm.h.patch @@ -0,0 +1,146 @@ +diff -drupN a/arch/mips/xburst2/soc-t40/include/soc/cpm.h b/arch/mips/xburst2/soc-t40/include/soc/cpm.h +--- a/arch/mips/xburst2/soc-t40/include/soc/cpm.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-t40/include/soc/cpm.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,142 @@ ++/* ++ * JZSOC CPM register definition. ++ * ++ * CPM (Clock reset and Power control Management) ++ * ++ * Copyright (C) 2019 Ingenic Semiconductor Co., Ltd. ++ */ ++ ++#ifndef __CPM_H__ ++#define __CPM_H__ ++ ++#define CPM_CPCCR (0x00) ++#define CPM_CPPCR (0x0c) ++#define CPM_CPAPCR (0x10) ++#define CPM_CPMPCR (0x14) ++#define CPM_CPAPACR (0x18) ++#define CPM_CPMPACR (0x1c) ++#define CPM_DDRCDR (0x2c) ++#define CPM_EL150CDR (0x30) ++#define CPM_CPPSR (0x34) ++#define CPM_CPSPPR (0x38) ++#define CPM_USBPCR (0x3c) ++#define CPM_USBRDT (0x40) ++#define CPM_USBVBFIL (0x44) ++#define CPM_USBPCR1 (0x48) ++#define CPM_RSACDR (0x4c) ++#define CPM_MACCDR (0x54) ++#define CPM_CPEPCR (0x58) ++#define CPM_CPEPACR (0x5c) ++#define CPM_SFCCDR (0x60) ++#define CPM_LPCDR (0x64) ++#define CPM_MSC0CDR (0x68) ++#define CPM_MSC1CDR (0x6c) ++#define CPM_I2STCDR (0x70) ++#define CPM_I2STCDR1 (0x78) ++#define CPM_SSICDR (0x74) ++#define CPM_ISPCDR (0x80) ++#define CPM_I2SRCDR (0x84) ++#define CPM_I2SRCDR1 (0x88) ++#define CPM_BSCALERCDR (0xa0) ++#define CPM_EXCLKDS (0x8c) ++#define CPM_CIM0CDR (0x90) ++#define CPM_CIM1CDR (0x94) ++#define CPM_CIM2CDR (0x98) ++#define CPM_SOFTAPP (0x9c) ++#define CPM_BSCALERCDR (0xa0) ++#define CPM_RADIXCDR (0xa4) ++#define CPM_INTR (0xb0) ++#define CPM_INTRE (0xb4) ++#define CPM_BT0CDR (0xb8) ++#define CPM_DRCG (0xd0) ++#define CPM_CPCSR (0xd4) ++#define CPM_CPVPCR (0xe0) ++#define CPM_CPVPACR (0xe4) ++#define CPM_MACPHY (0xe8) ++ ++ ++#define CPM_LCR (0x04) ++#define CPM_CLKGR (0x20)/* def changed*/ ++#define CPM_OPCR (0x24) ++#define CPM_CLKGR1 (0x28)/* def changed*/ ++#define CPM_SRBC (0xc4) ++#define SRBC_USB_SR BIT (12) ++#define CPM_MESTSEL (0xec) ++ ++#define CPM_MEMCTRL_MA0 (0xf0) ++#define CPM_MEMCTRL_MA1 (0xf4) ++#define CPM_MEMCTRL_MA2 (0xf8) ++ ++#define CPM_RSR (0x08) ++ ++#ifndef BIT ++#define BIT(nr) (1UL << nr) ++#endif ++ ++/*USB Parameter Control Register*/ ++#define USBPCR_USB_MODE BIT(31) ++#define USBPCR_AVLD_REG BIT(30) ++#define USBPCR_IDPULLUP_MASK_BIT 28 ++#define USBPCR_IDPULLUP_MASK (0x3 << USBPCR_IDPULLUP_MASK_BIT) ++#define USBPCR_IDPULLUP_OTG (0x0 << USBPCR_IDPULLUP_MASK_BIT) ++#define USBPCR_IDPULLUP_ALWAYS_SUSPEND (0x1 << USBPCR_IDPULLUP_MASK_BIT) ++#define USBPCR_IDPULLUP_ALWAYS (0x2 << USBPCR_IDPULLUP_MASK_BIT) ++#define USBPCR_INCR_MASK BIT(27) ++#define USBPCR_POR_BIT 22 ++#define USBPCR_POR BIT(USBPCR_POR_BIT) ++ ++/*USB Reset Detect Timer Register*/ ++#define USBRDT_RESUME_INTEEN BIT(31) /*RW*/ ++#define USBRDT_RESUME_INTERCLR BIT(30) /*W0*/ ++#define USBRDT_RESUME_SPEED_BIT 28 /*RW*/ ++#define USBRDT_RESUME_SPEED_MSK (0x3 << USBRDT_RESUME_SPEED_BIT) ++#define USBRDT_RESUME_SPEED_HIGH (0x0 << USBRDT_RESUME_SPEED_BIT) ++#define USBRDT_RESUME_SPEED_FULL (0x1 << USBRDT_RESUME_SPEED_BIT) ++#define USBRDT_RESUME_SPEED_LOW (0x2 << USBRDT_RESUME_SPEED_BIT) ++#define USBRDT_RESUME_STATUS BIT(27) /*RO*/ ++#define USBRDT_HB_MASK BIT(26) ++#define USBRDT_VBFIL_LD_EN BIT(25) ++#define USBRDT_IDDIG_EN 24 ++#define USBRDT_IDDIG_REG 23 ++#define USBRDT_USBRDT_MSK (0x7fffff) ++#define USBRDT_USBRDT(x) ((x) & USBRDT_USBRDT_MSK) ++#define USBRDT_UTMI_RST BIT(27) ++ ++/*USB VBUS Jitter Filter Register*/ ++#define USBVBFIL_USBVBFIL(x) ((x) & 0xffff) ++#define USBVBFIL_IDDIGFIL(x) ((x) & (0xffff << 16)) ++ ++/*USB Parameter Control Register1*/ ++#define USBPCR1_BVLD_REG BIT(31) ++#define USBPCR1_DPPULLDOWN BIT(29) ++#define USBPCR1_DMPULLDOWN BIT(28) ++#define USBPCR1_PORT_RST BIT(21) ++ ++/*Oscillator and Power Control Register*/ ++#define OPCR_USB_SPENDN BIT(7) ++#define OPCR_USB_PHY_GATE BIT(23) ++ ++#define LCR_LPM_MASK (0x3) ++#define LCR_LPM_SLEEP (0x1) ++ ++#define CPM_LCR_PD_X2D (0x1<<31) ++#define CPM_LCR_PD_VPU (0x1<<30) ++#define CPM_LCR_PD_MASK (0x3<<30) ++#define CPM_LCR_X2DS (0x1<<27) ++#define CPM_LCR_VPUS (0x1<<26) ++#define CPM_LCR_STATUS_MASK (0x3<<26) ++ ++#define OPCR_ERCS (0x1<<2) ++#define OPCR_PD (0x1<<3) //T31 delete ++#define OPCR_IDLE (0x1<<31) ++ ++#define CLKGR1_VPU (0x1<<0) ++ ++#define cpm_inl(off) inl(CPM_IOBASE + (off)) ++#define cpm_outl(val,off) outl(val,CPM_IOBASE + (off)) ++#define cpm_clear_bit(val,off) do{cpm_outl((cpm_inl(off) & ~(1 << (val))),off);}while(0) ++#define cpm_set_bit(val,off) do{cpm_outl((cpm_inl(off) | (1 << (val))),off);}while(0) ++#define cpm_test_bit(val,off) (cpm_inl(off) & (0x1 << (val))) ++ ++#endif ++/* __CPM_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_ddr.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_ddr.h.patch new file mode 100644 index 00000000..0e31b3a0 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_ddr.h.patch @@ -0,0 +1,104 @@ +diff -drupN a/arch/mips/xburst2/soc-t40/include/soc/ddr.h b/arch/mips/xburst2/soc-t40/include/soc/ddr.h +--- a/arch/mips/xburst2/soc-t40/include/soc/ddr.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-t40/include/soc/ddr.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,100 @@ ++#ifndef _DDR_H_ ++#define _DDR_H_ ++#define DDRP_PIR_INIT (1 << 0) ++#define DDRP_PIR_DLLSRST (1 << 1) ++#define DDRP_PIR_DLLLOCK (1 << 2) ++#define DDRP_PIR_ZCAL (1 << 3) ++#define DDRP_PIR_ITMSRST (1 << 4) ++#define DDRP_PIR_DRAMRST (1 << 5) ++#define DDRP_PIR_DRAMINT (1 << 6) ++#define DDRP_PIR_QSTRN (1 << 7) ++#define DDRP_PIR_EYETRN (1 << 8) ++#define DDRP_PIR_DLLBYP (1 << 17) ++#define DDRP_PIR_LOCKBYP (1 << 29) ++#define DDRP_PGSR_IDONE (1 << 0) ++#define DDRP_PGSR_DLDONE (1 << 1) ++#define DDRP_PGSR_ZCDONE (1 << 2) ++#define DDRP_PGSR_DIDONE (1 << 3) ++#define DDRP_PGSR_DTDONE (1 << 4) ++#define DDRP_PGSR_DTERR (1 << 5) ++#define DDRP_PGSR_DTIERR (1 << 6) ++#define DDRP_PGSR_DFTEERR (1 << 7) ++#define DDRC_AUTOSR_ENABLE (1 << 0) ++ ++ ++#define DDR_PHY_OFFSET (-0x4e0000 + 0x1000) ++ ++#define DDRP_PIR (DDR_PHY_OFFSET + 0x4) /* PHY Initialization Register */ ++#define DDRP_PGCR (DDR_PHY_OFFSET + 0x8) /* PHY General Configuration Register*/ ++#define DDRP_PGSR (DDR_PHY_OFFSET + 0xc) /* PHY General Status Register*/ ++#define DDRP_DLLGCR (DDR_PHY_OFFSET + 0x10) /* DLL General Control Register*/ ++#define DDRP_ACDLLCR (DDR_PHY_OFFSET + 0x14) /* AC DLL Control Register*/ ++#define DDRP_PTR0 (DDR_PHY_OFFSET + 0x18) /* PHY Timing Register 0 */ ++#define DDRP_PTR1 (DDR_PHY_OFFSET + 0x1c) /* PHY Timing Register 1 */ ++#define DDRP_PTR2 (DDR_PHY_OFFSET + 0x20) /* PHY Timing Register 2 */ ++#define DDRP_ACIOCR (DDR_PHY_OFFSET + 0x24) /* AC I/O Configuration Register */ ++#define DDRP_DXCCR (DDR_PHY_OFFSET + 0x28) /* DATX8 Common Configuration Register */ ++#define DDRP_DSGCR (DDR_PHY_OFFSET + 0x2c) /* DDR System General Configuration Register */ ++#define DDRP_DCR (DDR_PHY_OFFSET + 0x30) /* DRAM Configuration Register*/ ++ ++#define DDRP_DTPR0 (DDR_PHY_OFFSET + 0x34) /* DRAM Timing Parameters Register 0 */ ++#define DDRP_DTPR1 (DDR_PHY_OFFSET + 0x38) /* DRAM Timing Parameters Register 1 */ ++#define DDRP_DTPR2 (DDR_PHY_OFFSET + 0x3c) /* DRAM Timing Parameters Register 2 */ ++#define DDRP_MR0 (DDR_PHY_OFFSET + 0x40) /* Mode Register 0 */ ++#define DDRP_MR1 (DDR_PHY_OFFSET + 0x44) /* Mode Register 1 */ ++#define DDRP_MR2 (DDR_PHY_OFFSET + 0x48) /* Mode Register 2 */ ++#define DDRP_MR3 (DDR_PHY_OFFSET + 0x4c) /* Mode Register 3 */ ++#define DDRP_ODTCR (DDR_PHY_OFFSET + 0x50) /* ODT Configure Register */ ++#define DDRP_DTAR (DDR_PHY_OFFSET + 0x54) /* Data Training Address Register */ ++#define DDRP_DTDR0 (DDR_PHY_OFFSET + 0x58) /* Data Training Data Register 0 */ ++#define DDRP_DTDR1 (DDR_PHY_OFFSET + 0x5c) /* Data Training Data Register 1 */ ++ ++#define DDRP_DCUAR (DDR_PHY_OFFSET + 0xc0) /* DCU Address Register */ ++#define DDRP_DCUDR (DDR_PHY_OFFSET + 0xc4) /* DCU Data Register */ ++#define DDRP_DCURR (DDR_PHY_OFFSET + 0xc8) /* DCU Run Register */ ++#define DDRP_DCULR (DDR_PHY_OFFSET + 0xcc) /* DCU Loop Register */ ++#define DDRP_DCUGCR (DDR_PHY_OFFSET + 0xd0) /* DCU Gerneral Configuration Register */ ++#define DDRP_DCUTPR (DDR_PHY_OFFSET + 0xd4) /* DCU Timing Parameters Register */ ++#define DDRP_DCUSR0 (DDR_PHY_OFFSET + 0xd8) /* DCU Status Register 0 */ ++#define DDRP_DCUSR1 (DDR_PHY_OFFSET + 0xdc) /* DCU Status Register 1 */ ++ ++#define DDRP_DXGCR(n) (DDR_PHY_OFFSET + 0x1c0 + n * 0x40) /* DATX8 n General Configuration Register */ ++#define DDRP_DXGSR0(n) (DDR_PHY_OFFSET + 0x1c4 + n * 0x40) /* DATX8 n General Status Register */ ++#define DDRP_DXGSR1(n) (DDR_PHY_OFFSET + 0x1c8 + n * 0x40) /* DATX8 n General Status Register */ ++#define DDRP_DXDLLCR(n) (DDR_PHY_OFFSET + 0x1cc + n * 0x40) /* DATX8 n General Status Register */ ++#define DDRP_DXDQSTR(n) (DDR_PHY_OFFSET + 0x1d4 + n * 0x40) /* DATX8 n DQS Timing Register */ ++#define DDRP_ZQXCR0(n) (DDR_PHY_OFFSET + 0x180 + n * 0x10) /* ZQ impedance Control Register 0 */ ++#define DDRP_ZQXCR1(n) (DDR_PHY_OFFSET + 0x184 + n * 0x10) /* ZQ impedance Control Register 1 */ ++#define DDRP_ZQXSR0(n) (DDR_PHY_OFFSET + 0x188 + n * 0x10) /* ZQ impedance Status Register 0 */ ++#define DDRP_ZQXSR1(n) (DDR_PHY_OFFSET + 0x18c + n * 0x10) /* ZQ impedance Status Register 1 */ ++ ++#define DDRP_DX0GSR (DDR_PHY_OFFSET + 0x71 * 4) ++ ++#define DDRC_STATUS 0x0 ++#define DDRC_CFG 0x4 ++#define DDRC_CTRL 0x8 ++#define DDRC_LMR 0xc ++#define DDRC_REFCNT 0x18 ++#define DDRC_MMAP0 0x24 ++#define DDRC_MMAP1 0x28 ++#define DDRC_DLP 0xbc ++#define DDRC_STRB 0x34 ++#define DDRC_AUTOSR_CNT 0x308 ++#define DDRC_AUTOSR_EN 0x304 ++#define DDRC_TIMING(n) (0x60 + 4 * (n - 1)) ++#define DDRC_REMAP(n) (0x9c + 4 * (n - 1)) ++ ++ ++#define DDRP_DXnDQSTR(n) (DDR_PHY_OFFSET + (0x10 * n + 0x75) * 4) ++#define DDRP_DXnDQTR(n) (DDR_PHY_OFFSET + (0x10 * n + 0x74) * 4) ++ ++#ifndef REG32 ++#define REG32(x) *(volatile unsigned int *)(x) ++#endif ++ ++#define ddr_writel(value, reg) REG32(DDRC_BASE + reg) = (value) ++#define ddr_readl(reg) REG32(DDRC_BASE + reg) ++ ++ ++ ++#endif /* _DDR_H_ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_extal.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_extal.h.patch new file mode 100644 index 00000000..590dfc1a --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_extal.h.patch @@ -0,0 +1,12 @@ +diff -drupN a/arch/mips/xburst2/soc-t40/include/soc/extal.h b/arch/mips/xburst2/soc-t40/include/soc/extal.h +--- a/arch/mips/xburst2/soc-t40/include/soc/extal.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-t40/include/soc/extal.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,8 @@ ++ ++#ifndef __JZSOC_EXTAL_H__ ++#define __JZSOC_EXTAL_H__ ++ ++#define JZ_EXTAL_RTC 32768 /* RTC extal freq: 32.768 KHz */ ++#define JZ_EXTAL (CONFIG_EXTAL_CLOCK * 1000000) ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_gpio.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_gpio.h.patch new file mode 100644 index 00000000..f01a5783 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_gpio.h.patch @@ -0,0 +1,44 @@ +diff -drupN a/arch/mips/xburst2/soc-t40/include/soc/gpio.h b/arch/mips/xburst2/soc-t40/include/soc/gpio.h +--- a/arch/mips/xburst2/soc-t40/include/soc/gpio.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-t40/include/soc/gpio.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,40 @@ ++#ifndef _SOC_GPIO_H_ ++#define _SOC_GPIO_H_ ++ ++enum gpio_function { ++ GPIO_FUNC_0 = 0x10, //0000, GPIO as function 0 / device 0 ++ GPIO_FUNC_1 = 0x11, //0001, GPIO as function 1 / device 1 ++ GPIO_FUNC_2 = 0x12, //0010, GPIO as function 2 / device 2 ++ GPIO_FUNC_3 = 0x13, //0011, GPIO as function 3 / device 3 ++ GPIO_OUTPUT0 = 0x14, //0100, GPIO output low level ++ GPIO_OUTPUT1 = 0x15, //0101, GPIO output high level ++ GPIO_INPUT = 0x16, //0110, GPIO as input.7 also. ++ GPIO_INT_LO = 0x18, //1000, Low Level trigger interrupt ++ GPIO_INT_HI = 0x19, //1001, High Level trigger interrupt ++ GPIO_INT_FE = 0x1a, //1010, Fall Edge trigger interrupt ++ GPIO_INT_RE = 0x1b, //1011, Rise Edge trigger interrupt ++ GPIO_INT_MASK_LO = 0x1c, //1100, Port is low level triggered interrupt input. Interrupt is masked. ++ GPIO_INT_MASK_HI = 0x1d, //1101, Port is high level triggered interrupt input. Interrupt is masked. ++ GPIO_INT_MASK_FE = 0x1e, //1110, Port is fall edge triggered interrupt input. Interrupt is masked. ++ GPIO_INT_MASK_RE = 0x1f, //1111, Port is rise edge triggered interrupt input. Interrupt is masked. ++ ++ GPIO_PULL_HIZ = 0x80, //no pull ++ GPIO_PULL_UP = 0xa0, //pull high ++ GPIO_PULL_DOWN = 0xc0, //pull low ++}; ++ ++#define GPIO_PA(n) (0 * 32 + (n)) ++#define GPIO_PB(n) (1 * 32 + (n)) ++#define GPIO_PC(n) (2 * 32 + (n)) ++#define GPIO_PD(n) (3 * 32 + (n)) ++ ++enum gpio_port { ++ GPIO_PORT_A, GPIO_PORT_B, ++ GPIO_PORT_C, GPIO_PORT_D, ++ /* this must be last */ ++ GPIO_NR_PORTS, ++}; ++ ++int jzgpio_set_func(int port, enum gpio_function func, unsigned long pins); ++ ++#endif /* _SOC_GPIO_H_ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_mmc.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_mmc.h.patch new file mode 100644 index 00000000..9c7d9405 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_mmc.h.patch @@ -0,0 +1,9 @@ +diff -drupN a/arch/mips/xburst2/soc-t40/include/soc/mmc.h b/arch/mips/xburst2/soc-t40/include/soc/mmc.h +--- a/arch/mips/xburst2/soc-t40/include/soc/mmc.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-t40/include/soc/mmc.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,5 @@ ++#ifndef __MMC_H ++#define __MMC_H ++ ++extern int jzmmc_manual_detect(int index, int on); ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_pdma.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_pdma.h.patch new file mode 100644 index 00000000..d5a45a32 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_pdma.h.patch @@ -0,0 +1,53 @@ +diff -drupN a/arch/mips/xburst2/soc-t40/include/soc/pdma.h b/arch/mips/xburst2/soc-t40/include/soc/pdma.h +--- a/arch/mips/xburst2/soc-t40/include/soc/pdma.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-t40/include/soc/pdma.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,49 @@ ++/* ++ * 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) 2021 by nick shen ++ */ ++#ifndef __ASM_MACH_INGENIC_PDMA_H__ ++#define __ASM_MACH_INGENIC_PDMA_H__ ++ ++#include ++#define INGENIC_DMA_REQ_AUTO 0xff ++#define INGENIC_DMA_CHAN_CNT 32 ++unsigned int pdma_maps[INGENIC_DMA_CHAN_CNT] = { ++ INGENIC_DMA_REQ_AUTO, ++ INGENIC_DMA_REQ_AUTO, ++ INGENIC_DMA_REQ_AIC_LOOP_RX, ++ INGENIC_DMA_REQ_AIC_TX, ++ INGENIC_DMA_REQ_AIC_F_RX, ++ INGENIC_DMA_REQ_AUTO_TX, ++ INGENIC_DMA_REQ_SADC_RX, ++ INGENIC_DMA_REQ_DMIC_RX, ++ INGENIC_DMA_REQ_UART3_TX, ++ INGENIC_DMA_REQ_UART3_RX, ++ INGENIC_DMA_REQ_UART2_TX, ++ INGENIC_DMA_REQ_UART2_RX, ++ INGENIC_DMA_REQ_UART1_TX, ++ INGENIC_DMA_REQ_UART1_RX, ++ INGENIC_DMA_REQ_UART0_TX, ++ INGENIC_DMA_REQ_UART0_RX, ++ INGENIC_DMA_REQ_SSI0_TX, ++ INGENIC_DMA_REQ_SSI0_RX, ++ INGENIC_DMA_REQ_SSI1_TX, ++ INGENIC_DMA_REQ_SSI1_RX, ++ INGENIC_DMA_REQ_SLV_TX, ++ INGENIC_DMA_REQ_SLV_RX, ++ INGENIC_DMA_REQ_I2C0_TX, ++ INGENIC_DMA_REQ_I2C0_RX, ++ INGENIC_DMA_REQ_I2C1_TX, ++ INGENIC_DMA_REQ_I2C1_RX, ++ INGENIC_DMA_REQ_I2C2_TX, ++ INGENIC_DMA_REQ_I2C2_RX, ++ INGENIC_DMA_REQ_I2C3_TX, ++ INGENIC_DMA_REQ_I2C3_RX, ++ INGENIC_DMA_REQ_DES_TX, ++ INGENIC_DMA_REQ_DES_RX, ++}; ++#endif ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_rtc.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_rtc.h.patch new file mode 100644 index 00000000..430c06db --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_rtc.h.patch @@ -0,0 +1,100 @@ +diff -drupN a/arch/mips/xburst2/soc-t40/include/soc/rtc.h b/arch/mips/xburst2/soc-t40/include/soc/rtc.h +--- a/arch/mips/xburst2/soc-t40/include/soc/rtc.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-t40/include/soc/rtc.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,96 @@ ++#ifndef __RTC_H__ ++#define __RTC_H__ ++ ++/* ++ * RTC registers offset address definition ++ */ ++#define RTC_RTCCR (0x00) /* rw, 32, 0x00000081 */ ++#define RTC_RTCSR (0x04) /* rw, 32, 0x???????? */ ++#define RTC_RTCSAR (0x08) /* rw, 32, 0x???????? */ ++#define RTC_RTCGR (0x0c) /* rw, 32, 0x0??????? */ ++ ++#define RTC_HCR (0x20) /* rw, 32, 0x00000000 */ ++#define RTC_HWFCR (0x24) /* rw, 32, 0x0000???0 */ ++#define RTC_HRCR (0x28) /* rw, 32, 0x00000??0 */ ++#define RTC_HWCR (0x2c) /* rw, 32, 0x00000008 */ ++#define RTC_HWRSR (0x30) /* rw, 32, 0x00000000 */ ++#define RTC_HSPR (0x34) /* rw, 32, 0x???????? */ ++#define RTC_WENR (0x3c) /* rw, 32, 0x00000000 */ ++#define RTC_WKUPPINCR (0x48) /* rw, 32, 0x00050064*/ ++ ++/* ++ * RTC registers common define ++ */ ++ ++/* RTC control register(RTCCR) */ ++#define RTCCR_WRDY BIT(7) ++#define RTCCR_1HZ BIT(6) ++#define RTCCR_1HZIE BIT(5) ++#define RTCCR_AF BIT(4) ++#define RTCCR_AIE BIT(3) ++#define RTCCR_AE BIT(2) ++#define RTCCR_SELEXC BIT(1) ++#define RTCCR_RTCE BIT(0) ++ ++ ++/* Generate the bit field mask from msb to lsb */ ++#define BITS_H2L(msb, lsb) ((0xFFFFFFFF >> (32-((msb)-(lsb)+1))) << (lsb)) ++ ++/* RTC regulator register(RTCGR) */ ++#define RTCGR_LOCK BIT(31) ++#define RTCGR_ADJC_LSB 16 ++#define RTCGR_ADJC_MASK BITS_H2L(25, RTCGR_ADJC_LSB) ++#define RTCGR_NC1HZ_LSB 0 ++#define RTCGR_NC1HZ_MASK BITS_H2L(15, RTCGR_NC1HZ_LSB) ++ ++/* Hibernate control register(HCR) */ ++#define HCR_PD BIT(0) ++ ++/* Hibernate wakeup filter counter register(HWFCR) */ ++#define HWFCR_LSB 5 ++#define HWFCR_MASK BITS_H2L(15, HWFCR_LSB) ++#define HWFCR_WAIT_TIME(ms, clk) (((ms)*(clk)/1000+0xf) > HWFCR_MASK ? HWFCR_MASK : ((ms)*(clk)/1000+0xf) & HWFCR_MASK) ++ ++/* Hibernate reset counter register(HRCR) */ ++#define HRCR_LSB 11 ++#define HRCR_MASK BITS_H2L(14, HRCR_LSB) ++#define HRCR_WAIT_TIME(ms, clk) (((ms)*(clk)/1000 + 0x3ff - 0x800) > HRCR_MASK ? HRCR_MASK : \ ++ ((ms)*(clk)/1000 + 0x3ff - 0x800) & HRCR_MASK) ++ ++ ++/* Hibernate wakeup control register(HWCR) */ ++/* Power detect default value; this value means enable */ ++#define EPDET_LSB 3 ++#define EPDET_DEFAULT (0x5aa5a5a << EPDET_LSB) ++#define EPDET_ENABLE (0x5aa5a5a << EPDET_LSB) ++#define EPDET_DISABLE (0x1a55a5a5 << EPDET_LSB) ++#define HWCR_EALM BIT(0) ++ ++ ++/* Hibernate wakeup status register(HWRSR) */ ++#define HWRSR_APD BIT(8) ++#define HWRSR_HR BIT(5) ++#define HWRSR_PPR BIT(4) ++#define HWRSR_PIN BIT(1) ++#define HWRSR_ALM BIT(0) ++ ++/* write enable pattern register(WENR) */ ++#define WENR_WEN BIT(31) ++#define WENR_WENPAT_LSB 0 ++#define WENR_WENPAT_MASK BITS_H2L(15, WENR_WENPAT_LSB) ++#define WENR_WENPAT_WRITABLE (0xa55a) ++ ++/* Hibernate scratch pattern register(HSPR) */ ++#define HSPR_RTCV 0x52544356 /* The value is 'RTCV', means rtc is valid */ ++ ++/*WKUP_PIN_RST control register (WKUPPINCR)*/ ++#define WKUPPINCR_BIAS_CTRL (0x1 << 16) /* fix value*/ ++#define WKUPPINCR_OSC_EN BIT(18) ++#define WKUPPINCR_P_JUD_LEN_LSB 4 ++#define WKUPPINCR_P_JUD_LEN_MASK BITS_H2L(7, WKUPPINCR_P_JUD_LEN_LSB) ++#define WKUPPINCR_P_JUD_LEN(s) ((s) << WKUPPINCR_P_JUD_LEN_LSB) > WKUPPINCR_P_JUD_LEN_MASK ? \ ++ WKUPPINCR_P_JUD_LEN_MASK : (s) << WKUPPINCR_P_JUD_LEN_LSB ++#define WKUPPINCR_P_JUD_EN (0x4) ++/* The divider is decided by the RTC clock frequency. */ ++#define RTC_FREQ_DIVIDER (32768 - 1) ++#endif /* __RTC_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_sfc.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_sfc.h.patch new file mode 100644 index 00000000..649153ba --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_sfc.h.patch @@ -0,0 +1,215 @@ +diff -drupN a/arch/mips/xburst2/soc-t40/include/soc/sfc.h b/arch/mips/xburst2/soc-t40/include/soc/sfc.h +--- a/arch/mips/xburst2/soc-t40/include/soc/sfc.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-t40/include/soc/sfc.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,211 @@ ++#ifndef __SFC_REGISTER_H ++#define __SFC_REGISTER_H ++ ++/* SFC register */ ++ ++#define SFC_GLB0 (0x0000) ++#define SFC_DEV_CONF (0x0004) ++#define SFC_DEV_STA_EXP (0x0008) ++#define SFC_DEV0_STA_RT (0x000c) ++#define SFC_DEV_STA_MSK (0x0010) ++#define SFC_TRAN_CONF0(n) (0x0014 + (n * 4)) ++#define SFC_TRAN_LEN (0x002c) ++#define SFC_DEV_ADDR(n) (0x0030 + (n * 4)) ++#define SFC_DEV_ADDR_PLUS(n) (0x0048 + (n * 4)) ++#define SFC_MEM_ADDR (0x0060) ++#define SFC_TRIG (0x0064) ++#define SFC_SR (0x0068) ++#define SFC_SCR (0x006c) ++#define SFC_INTC (0x0070) ++#define SFC_FSM (0x0074) ++#define SFC_CGE (0x0078) ++#define SFC_CMD_IDX (0x007c) ++#define SFC_COL_ADDR (0x0080) ++#define SFC_ROW_ADDR (0x0084) ++#define SFC_STA_ADDR0 (0x0088) ++#define SFC_STA_ADDR1 (0x008c) ++#define SFC_DES_ADDR (0x0090) ++#define SFC_GLB1 (0x0094) ++#define SFC_DEV1_STA_RT (0x0098) ++#define SFC_TRAN_CONF1(n) (0x009c + (n * 4)) ++#define SFC_CDT (0x0800) //0x800 ~ 0xbff ++#define SFC_RM_DR (0x1000) ++ ++/* For SFC_GLB0 */ ++#define GLB0_POLL_TIME_OFFSET (16) ++#define GLB0_POLL_TIME_MSK (0xffff << GLB0_POLL_TIME_OFFSET) ++#define GLB0_DES_EN (1 << 15) ++#define GLB0_CDT_EN (1 << 14) ++#define GLB0_TRAN_DIR (1 << 13) ++#define GLB0_TRAN_DIR_WRITE (1) ++#define GLB0_TRAN_DIR_READ (0) ++#define GLB0_THRESHOLD_OFFSET (7) ++#define GLB0_THRESHOLD_MSK (0x3f << GLB0_THRESHOLD_OFFSET) ++#define GLB0_OP_MODE (1 << 6) ++#define GLB0_OP_OFFSET (6) ++#define SLAVE_MODE (0x0) ++#define DMA_MODE (0x1) ++#define GLB0_PHASE_NUM_OFFSET (3) ++#define GLB0_PHASE_NUM_MSK (0x7 << GLB0_PHASE_NUM_OFFSET) ++#define GLB0_WP_EN (1 << 2) ++#define GLB0_BURST_MD_OFFSET (0) ++#define GLB0_BURST_MD_MSK (0x3 << GLB0_BURST_MD_OFFSET) ++ ++/* For SFC_DEV_CONF */ ++#define DEV_CONF_STA_ENDIAN_OFFSET (31) ++#define STA_ENDIAN_LSB (0) ++#define STA_ENDIAN_MSB (1) ++#define DEV_CONF_SMP_DELAY_OFFSET (16) ++#define DEV_CONF_SMP_DELAY_MSK (0x1f << DEV_CONF_SMP_DELAY_OFFSET) ++#define DEV_CONF_SMP_DELAY_0 (0) ++#define DEV_CONF_SMP_DELAY_45 (1) ++#define DEV_CONF_SMP_DELAY_90 (2) ++#define DEV_CONF_SMP_DELAY_135 (3) ++#define DEV_CONF_SMP_DELAY_180 (4) ++#define DEV_CONF_SMP_DELAY_225 (5) ++#define DEV_CONF_SMP_DELAY_270 (6) ++#define DEV_CONF_SMP_DELAY_315 (7) ++#define DEV_CONF_SMP_DELAY_1 (8) ++#define DEV_CONF_SMP_DELAY_2 (16) ++#define DEV_CONF_CMD_TYPE (0x1 << 15) ++#define DEV_CONF_STA_TYPE_OFFSET (13) ++#define DEV_CONF_STA_TYPE_MSK (0x3 << DEV_CONF_STA_TYPE_OFFSET) ++#define DEV_CONF_THOLD_OFFSET (11) ++#define DEV_CONF_THOLD_MSK (0x3 << DEV_CONF_THOLD_OFFSET) ++#define DEV_CONF_TSETUP_OFFSET (9) ++#define DEV_CONF_TSETUP_MSK (0x3 << DEV_CONF_TSETUP_OFFSET) ++#define DEV_CONF_TSH_OFFSET (5) ++#define DEV_CONF_TSH_MSK (0xf << DEV_CONF_TSH_OFFSET) ++#define DEV_CONF_CPHA (0x1 << 4) ++#define DEV_CONF_CPOL (0x1 << 3) ++#define DEV_CONF_CEDL (0x1 << 2) ++#define DEV_CONF_HOLDDL (0x1 << 1) ++#define DEV_CONF_WPDL (0x1 << 0) ++ ++/* For SFC_TRAN_CONF0 */ ++#define TRAN_CONF0_CLK_MODE (29) ++#define TRAN_CONF0_CLK_MODE_MSK (0x7 << TRAN_CONF0_CLK_MODE) ++#define TRAN_CONF0_CLK_MODE_SSS (0) ++#define TRAN_CONF0_CLK_MODE_SSD (1) ++#define TRAN_CONF0_CLK_MODE_SDS (2) ++#define TRAN_CONF0_CLK_MODE_SDD (3) ++#define TRAN_CONF0_CLK_MODE_DSS (4) ++#define TRAN_CONF0_CLK_MODE_DSD (5) ++#define TRAN_CONF0_CLK_MODE_DDS (6) ++#define TRAN_CONF0_CLK_MODE_DDD (7) ++#define TRAN_CONF0_ADDR_WIDTH_OFFSET (26) ++#define TRAN_CONF0_ADDR_WIDTH_MSK (0x7 << TRAN_CONF0_ADDR_WIDTH_OFFSET) ++#define TRAN_CONF0_POLLEN (1 << 25) ++#define TRAN_CONF0_POLL_OFFSET (25) ++#define TRAN_CONF0_CMDEN (1 << 24) ++#define TRAN_CONF0_FMAT (1 << 23) ++#define TRAN_CONF0_FMAT_OFFSET (23) ++#define TRAN_CONF0_DMYBITS_OFFSET (17) ++#define TRAN_CONF0_DMYBITS_MSK (0x3f << TRAN_CONF0_DMYBITS_OFFSET) ++#define TRAN_CONF0_DATEEN (1 << 16) ++#define TRAN_CONF0_DATEEN_OFFSET (16) ++#define TRAN_CONF0_CMD_OFFSET (0) ++#define TRAN_CONF0_CMD_MSK (0xffff << TRAN_CONF0_CMD_OFFSET) ++ ++/* For SFC_TRAN_CONF1 */ ++#define TRAN_CONF1_DATA_ENDIAN (1 << 18) ++#define TRAN_CONF1_DATA_ENDIAN_OFFSET (18) ++#define TRAN_CONF1_DATA_ENDIAN_LSB (0) ++#define TRAN_CONF1_DATA_ENDIAN_MSB (1) ++#define TRAN_CONF1_WORD_UNIT_OFFSET (16) ++#define TRAN_CONF1_WORD_UNIT_MSK (3 << 16) ++#define TRAN_CONF1_TRAN_MODE_OFFSET (4) ++#define TRAN_CONF1_TRAN_MODE_MSK (0xf << TRAN_CONF1_TRAN_MODE_OFFSET) ++#define TRAN_CONF1_SPI_STANDARD (0x0) ++#define TRAN_CONF1_SPI_DUAL (0x1) ++#define TRAN_CONF1_SPI_QUAD (0x5) ++#define TRAN_CONF1_SPI_IO_QUAD (0x6) ++#define TRAN_CONF1_SPI_OCTAL (0x9) ++#define TRAN_CONF1_SPI_IO_OCTAL (0xa) ++#define TRAN_CONF1_SPI_FULL_OCTAL (0xb) ++ ++ ++/* For SFC_TRIG */ ++#define TRIG_FLUSH (1 << 2) ++#define TRIG_STOP (1 << 1) ++#define TRIG_START (1 << 0) ++ ++/* For SFC_SR */ ++#define SFC_WORKING (1 << 7) ++#define SFC_BUSY (0x3 << 5) ++#define SFC_END (1 << 4) ++#define SFC_TREQ (1 << 3) ++#define SFC_RREQ (1 << 2) ++#define SFC_OVER (1 << 1) ++#define SFC_UNDER (1 << 0) ++ ++/* For SFC_SCR */ ++#define CLR_END (1 << 4) ++#define CLR_TREQ (1 << 3) ++#define CLR_RREQ (1 << 2) ++#define CLR_OVER (1 << 1) ++#define CLR_UNDER (1 << 0) ++ ++//SFC_CMD_IDX ++#define CMD_IDX_MSK (0x3f << 0) ++#define CDT_DATAEN_MSK (0x1 << 31) ++#define CDT_DATAEN_OFF (31) ++#define CDT_DIR_MSK (0x1 << 30) ++#define CDT_DIR_OFF (30) ++ ++/* For SFC_GLB1 */ ++#define GLB1_DQS_EN (1 << 2) ++#define GLB1_CHIP_SEL_OFFSET (0) ++#define GLB1_CHIP_SEL_MSK (0x3 << 0) ++#define GLB1_CHIP_SEL_0 (0) ++#define GLB1_CHIP_SEL_1 (1) ++#define GLB1_CHIP_SEL_01 (2) ++ ++#define N_MAX 6 ++#define MAX_SEGS 128 ++ ++#define CHANNEL_0 0 ++#define CHANNEL_1 1 ++#define CHANNEL_2 2 ++#define CHANNEL_3 3 ++#define CHANNEL_4 4 ++#define CHANNEL_5 5 ++ ++#define ENABLE 1 ++#define DISABLE 0 ++ ++#define COM_CMD 1 // common cmd ++#define POLL_CMD 2 // the cmd will poll the status of flash,ext: read status ++ ++#define DMA_OPS 1 ++#define CPU_OPS 0 ++ ++#define TM_STD_SPI 0 ++#define TM_DI_DO_SPI 1 ++#define TM_DIO_SPI 2 ++#define TM_FULL_DIO_SPI 3 ++#define TM_QI_QO_SPI 5 ++#define TM_QIO_SPI 6 ++#define TM_FULL_QIO_SPI 7 ++#define TM_OCTAL_SPT 9 ++#define TM_OCTAL_IO_SPI 10 ++#define TM_OCTAL_FULL_SPI 11 ++ ++ ++#define DEFAULT_CDT 1 ++#define UPDATE_CDT 2 ++#define DEFAULT_ADDRSIZE 3 ++#define DEFAULT_ADDRMODE 0 ++ ++ ++#define THRESHOLD 32 ++ ++#define SFC_NOR_RATE 110 ++#define DEF_ADDR_LEN 3 ++#define DEF_TCHSH 6 ++#define DEF_TSLCH 6 ++#define DEF_TSHSL_R 20 ++#define DEF_TSHSL_W 50 ++ ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_tcsm_layout.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_tcsm_layout.h.patch new file mode 100644 index 00000000..ef2f787c --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_soc_tcsm_layout.h.patch @@ -0,0 +1,57 @@ +diff -drupN a/arch/mips/xburst2/soc-t40/include/soc/tcsm_layout.h b/arch/mips/xburst2/soc-t40/include/soc/tcsm_layout.h +--- a/arch/mips/xburst2/soc-t40/include/soc/tcsm_layout.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-t40/include/soc/tcsm_layout.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,53 @@ ++#ifndef __TCSM_LAYOUT_H__ ++#define __TCSM_LAYOUT_H__ ++ ++/** ++ * |-------------| ++ * | BANK0 | ++ * |-------------| <--- SLEEP_TCSM_BOOTCODE_TEXT ++ * | BOOT CODE | ++ * |-------------| <--- SLEEP_TCSM_RESUMECODE_TEXT ++ * | ... | ++ * | RESUME CODE | ++ * | ... | ++ * |-------------| <--- SLEEP_TCSM_RESUME_DATA ++ * | ... | ++ * | RESUME DATA | ++ * | ... | ++ * |_____________| <--- SLEEP_TCSM_CPU_RESMUE_SP ++ * ++ * ++ * |-------------| ++ * | BANK1 | ++ * |-------------| <--- TO BE DEFINED ++ * | | ++ * | | ++ * | ... | ++ * | VOICE DATA | ++ * | ... | ++ * | | ++ * | | ++ * |_____________| ++ * ++ */ ++ ++#define SLEEP_TCSM_SPACE 0xb3422000 ++#define VOICE_TCSM_DATA_BUF 0xb3423000 ++#define TCSM_BANK_LEN 4096 ++ ++#define SLEEP_TCSM_BOOT_TEXT (SLEEP_TCSM_SPACE) ++#define SLEEP_TCSM_BOOT_LEN 64 ++#define SLEEP_TCSM_BOOT_END (SLEEP_TCSM_BOOT_TEXT + SLEEP_TCSM_BOOT_LEN) ++ ++#define SLEEP_TCSM_RESUME_TEXT (SLEEP_TCSM_BOOT_END) ++#define SLEEP_TCSM_RESUME_LEN 2048 ++#define SLEEP_TCSM_RESUME_END (SLEEP_TCSM_RESUME_TEXT + SLEEP_TCSM_RESUME_LEN) ++ ++#define SLEEP_TCSM_RESUME_DATA (SLEEP_TCSM_RESUME_END) ++ ++#define SLEEP_TCSM_SPACE_END (SLEEP_TCSM_SPACE + TCSM_BANK_LEN) ++ ++#define SLEEP_TCSM_CPU_RESMUE_SP SLEEP_TCSM_SPACE_END - 4 ++ ++ ++#endif /* __TCSM_LAYOUT_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_war.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_war.h.patch new file mode 100644 index 00000000..f0f66517 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_include_war.h.patch @@ -0,0 +1,31 @@ +diff -drupN a/arch/mips/xburst2/soc-t40/include/war.h b/arch/mips/xburst2/soc-t40/include/war.h +--- a/arch/mips/xburst2/soc-t40/include/war.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-t40/include/war.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,27 @@ ++/* ++ * 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) 2002, 2004, 2007 by Ralf Baechle ++ */ ++#ifndef __ASM_MACH_INGENIC_WAR_H__ ++#define __ASM_MACH_INGENIC_WAR_H__ ++ ++#define R4600_V1_INDEX_ICACHEOP_WAR 0 ++#define R4600_V1_HIT_CACHEOP_WAR 0 ++#define R4600_V2_HIT_CACHEOP_WAR 0 ++#define R5432_CP0_INTERRUPT_WAR 0 ++#define BCM1250_M3_WAR 0 ++#define SIBYTE_1956_WAR 0 ++#define MIPS4K_ICACHE_REFILL_WAR 0 ++#define MIPS_CACHE_SYNC_WAR 1 ++#define MIPS_BRIDGE_SYNC_WAR 1 ++#define TX49XX_ICACHE_INDEX_INV_WAR 0 ++#define RM9000_CDEX_SMP_WAR 0 ++#define ICACHE_REFILLS_WORKAROUND_WAR 0 ++#define R10000_LLSC_WAR 0 ++#define MIPS34K_MISSED_ITLB_WAR 0 ++ ++#endif ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_libdmmu.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_libdmmu.c.patch new file mode 100644 index 00000000..999e9aa4 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_libdmmu.c.patch @@ -0,0 +1,905 @@ +diff -drupN a/arch/mips/xburst2/soc-t40/libdmmu.c b/arch/mips/xburst2/soc-t40/libdmmu.c +--- a/arch/mips/xburst2/soc-t40/libdmmu.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-t40/libdmmu.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,901 @@ ++/* ++ * This driver is used by VPU driver. ++ * ++ * Copyright (C) 2015 Ingenic Semiconductor Co., Ltd. ++ * http://www.ingenic.com ++ * Author: Yan Zhengting ++ * Modify by: Sun Jiwei ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#define print_dbg(f, arg...) printk(KERN_INFO "dpu: %s, %d: " f "\n", __func__, __LINE__, ## arg) ++ ++#define MAP_COUNT 0x10 ++#define MAP_CONUT_MASK 0xff0 ++ ++#define DMMU_PTE_VLD 0x01 ++#define DMMU_PMD_VLD 0x01 ++ ++#define KSEG0_LOW_LIMIT 0x80000000 ++#define KSEG1_HEIGH_LIMIT 0xC0000000 ++ ++enum mem_break{ ++ MODE1, /* 13 24 57 68 911 1012 ... */ ++ MODE2, /* 13 24 35 46 57 68 79 810 ... */ ++ MODE3 /* 12 34 56 78 ... */ ++}; ++ ++LIST_HEAD(handle_list); ++static unsigned long reserved_pte = 0; ++static unsigned long res_pte_paddr; ++ ++struct pmd_node { ++ unsigned int count; ++ unsigned long index; ++ unsigned long page; ++ struct list_head list; ++}; ++ ++struct map_node { ++ struct device *dev; ++ unsigned long start; ++ unsigned long len; ++ struct list_head list; ++}; ++ ++struct dmmu_handle { ++ pid_t tgid; ++ unsigned long pdg; ++ struct mutex lock; ++ struct list_head list; ++ struct list_head pmd_list; ++ struct list_head map_list; ++}; ++ ++/* for test */ ++static struct dmmu_handle *find_handle(void); ++static struct dmmu_handle *create_handle(void); ++static void dmmu_cache_wback(struct dmmu_handle *h); ++ ++int dmmu_flush_cache(unsigned long vaddr, unsigned long len) ++{ ++ struct list_head *pos, *next; ++ struct dmmu_handle *h = NULL; ++ struct map_node *n = NULL; ++ unsigned long *pgd, *pte_phys, *pte; ++ unsigned long virpage_phy; ++ unsigned long v_end = vaddr+len; ++ int found = 0; ++ int index; ++ ++ h = find_handle(); ++ if(!h){ ++ printk("%s find handle err!\n",__func__); ++ return -1; ++ } ++ if (vaddr & 0xfff) { ++ printk("%s addr align page err!\n",__func__); ++ return -1; ++ } ++ list_for_each_safe(pos, next, &h->map_list) { ++ n = list_entry(pos, struct map_node, list); ++ if((vaddr >= n->start) && ++ ((vaddr+len) <= (n->start + n->len))) { ++ found = 1; ++ break; ++ } ++ } ++ if(!found) { ++ printk("%s addr err!\n",__func__); ++ return -1; ++ } ++ pgd = (unsigned long *)h->pdg; ++ while(vaddr < v_end) { ++ index = vaddr>>22; ++ pte_phys = (unsigned long *)(pgd[index] & ~DMMU_PMD_VLD); ++ pte = (unsigned long *)phys_to_virt((unsigned long)pte_phys); ++ index = ((vaddr & 0x3ff000) >> 12); ++ virpage_phy = pte[index] & ~DMMU_PTE_VLD; ++ dma_cache_wback((unsigned long)phys_to_virt(virpage_phy),PAGE_SIZE); ++ vaddr+=PAGE_SIZE; ++ } ++ return 0; ++} ++ ++static int make_smash_list(struct dmmu_handle *h, unsigned long vaddr, unsigned long (**base)[2], unsigned int *len) ++{ ++ unsigned long *pgd = (unsigned long *)h->pdg; ++ unsigned long (*list_smash)[2] = NULL; ++ unsigned int list_len = 0; ++ unsigned long *pte, *pte_phys; ++ unsigned int i, index; ++ ++ struct list_head *pos, *next; ++ struct map_node *n; ++ ++ list_for_each_safe(pos, next, &h->map_list) { ++ n = list_entry(pos, struct map_node, list); ++ if(vaddr == n->start) { ++ list_len = (n->len) >> 12; ++ break; ++ } ++ } ++ ++ if (list_len) { ++ list_smash = kmalloc(list_len * 2 * 4, GFP_KERNEL); ++ if (list_smash) { ++ i = 0; ++ while(i < list_len) { ++ list_smash[i][0] = (unsigned long)(vaddr & 0xfffff000); ++ ++ index = vaddr>>22; ++ pte_phys = (unsigned long *)(pgd[index] & ~DMMU_PMD_VLD); ++ ++ ++ pte = (unsigned long *)phys_to_virt((unsigned long)pte_phys); ++ ++ index = ((vaddr & 0x3ff000) >> 12); ++// printk(">>>>>>virt = 0x%lx, phys = 0x%lx\n", vaddr, ++// *((unsigned long int *) (((unsigned long)pte_phys+index*4) | 0xa0000000))); ++ list_smash[i][1] = pte[index]; ++ ++ vaddr+=0x1000; ++ i++; ++ } ++ } ++ } ++ ++ if (list_smash) { ++ *base = list_smash; ++ *len = list_len; ++ return 0; ++ } else { ++ return -1; ++ } ++} ++ ++int dmmu_dump_map(unsigned long vaddr) ++{ ++ struct dmmu_handle *h = NULL; ++ unsigned long (*list_smash)[2] = NULL; ++ unsigned int list_len = 0; ++ unsigned long *tmp; ++ ++ h = find_handle(); ++ if(!h) ++ h = create_handle(); ++ if(!h) ++ return -1; ++ /* 检查4k对齐 */ ++ if (vaddr & 0xfff) { ++ return -1; ++ } ++ ++ mutex_lock(&h->lock); ++ ++ if (make_smash_list(h, vaddr, &list_smash, &list_len)) { ++ mutex_unlock(&h->lock); ++ return -1; ++ } else { ++ unsigned int i; ++ for (i = 0; i phys: 0x%08lx] uncache: 0x%08lx\n", ++ list_smash[i][0],list_smash[i][1],(unsigned long)tmp); ++ ++ printk("value[0] = 0x%08lx, value[1] = 0x%08lx value[2] = 0x%08lx value[1013] = 0x%08lx\n", ++ tmp[0], tmp[1], tmp[2], tmp[1013]); ++ } ++ } ++ ++ mutex_unlock(&h->lock); ++ kfree((void*)list_smash); ++ ++ return 0; ++} ++ ++ /* 13 24 57 68 911 1012 ... */ ++static int smash_mode1(unsigned long (*base)[2], unsigned int len) ++{ ++ unsigned int i; ++ unsigned long tmp; ++ if (len >= 4) { ++ for (i=0; i= 4) { ++ for (i=0; ipdg; ++ unsigned long *pte; ++ unsigned int i, index; ++ ++ for (i=0; i>22; ++ pte = (unsigned long *)(pgd[index] & ~DMMU_PMD_VLD); ++ pte = (unsigned long *)phys_to_virt((unsigned long)pte); ++ ++ index = ((vaddr & 0x3ff000) >> 12); ++ pte[index] = (*base)[i][1]; ++ vaddr+=0x1000; ++ } ++ return 0; ++} ++ ++static int update_process_pte(unsigned long vaddr, unsigned long (**base)[2], unsigned int len) ++{ ++ unsigned int i; ++ pgd_t *pgdir; ++ pmd_t *pmdir; ++ pte_t *pte; ++ spin_lock(¤t->mm->page_table_lock); ++ for (i=0; imm, vaddr); ++ if(pgd_none(*pgdir) || pgd_bad(*pgdir)) ++ return 0; ++ pmdir = pmd_offset((pud_t *)pgdir, vaddr); ++ if(pmd_none(*pmdir) || pmd_bad(*pmdir)) ++ return 0; ++ pte = pte_offset(pmdir,vaddr); ++ if (pte_present(*pte)){ ++ pte->pte = (*base)[i][1]; ++ } ++ vaddr += 4096; ++ } ++ spin_unlock(¤t->mm->page_table_lock); ++ return 0; ++} ++ ++int dmmu_memory_smash(unsigned long vaddr, int smash_mode) ++{ ++ struct dmmu_handle *h = NULL; ++ unsigned long (*list_smash)[2] = NULL; ++ unsigned int list_len = 0; ++ struct vm_area_struct * vma; ++ ++ h = find_handle(); ++ if(!h){ ++ h = create_handle(); ++ } ++ if(!h) ++ return -1; ++ ++ /* 检查4k对齐 */ ++ if (vaddr & 0xfff) { ++ return -1; ++ } ++ ++ mutex_lock(&h->lock); ++ ++ if (make_smash_list(h, vaddr, &list_smash, &list_len)) { ++ mutex_unlock(&h->lock); ++ return -1; ++ } else { ++ switch (smash_mode) { ++ case MODE1: ++ print_dbg("smash_mode = %u\n",smash_mode); ++ smash_mode1(list_smash, list_len); ++ break; ++ case MODE2: ++ print_dbg("smash_mode = %u\n",smash_mode); ++ smash_mode2(list_smash, list_len); ++ break; ++ case MODE3: ++ print_dbg("smash_mode = %u\n",smash_mode); ++ smash_mode3(list_smash, list_len); ++ break; ++ default: ++ break; ++ } ++ } ++ update_dmmu_pte(h, vaddr, &list_smash, list_len); ++ update_process_pte(vaddr, &list_smash, list_len); ++ ++ dmmu_cache_wback(h); ++ vma = find_vma(current->mm, vaddr); ++ flush_tlb_range(vma, vaddr, vaddr+(list_len*PAGE_SIZE)); ++ ++ mutex_unlock(&h->lock); ++ kfree(list_smash); ++ ++ return 0; ++} ++ ++static struct map_node *check_map(struct dmmu_handle *h,unsigned long vaddr,unsigned long len) ++{ ++ struct list_head *pos, *next; ++ struct map_node *n; ++ list_for_each_safe(pos, next, &h->map_list) { ++ n = list_entry(pos, struct map_node, list); ++ if(vaddr == n->start && len == n->len) ++ return n; ++ } ++ return NULL; ++} ++ ++static void handle_add_map(struct device *dev,struct dmmu_handle *h,unsigned long vaddr,unsigned long len) ++{ ++ struct map_node *n = kmalloc(sizeof(*n),GFP_KERNEL); ++ n->dev = dev; ++ n->start = vaddr; ++ n->len = len; ++ INIT_LIST_HEAD(&n->list); ++ list_add(&n->list,&h->map_list); ++} ++ ++static unsigned int get_pfn(unsigned int vaddr) ++{ ++ pgd_t *pgdir; ++ pmd_t *pmdir; ++ pte_t *pte; ++ pgdir = pgd_offset(current->mm, vaddr); ++ if(pgd_none(*pgdir) || pgd_bad(*pgdir)) ++ return 0; ++ pmdir = pmd_offset((pud_t *)pgdir, vaddr); ++ if(pmd_none(*pmdir) || pmd_bad(*pmdir)) ++ return 0; ++ pte = pte_offset(pmdir,vaddr); ++ if (pte_present(*pte)) { ++ return pte_pfn(*pte) << PAGE_SHIFT; ++ } ++ return 0; ++} ++ ++static unsigned long dmmu_v2pfn(unsigned long vaddr) ++{ ++ if(vaddr < KSEG0_LOW_LIMIT) ++ return get_pfn(vaddr); ++ ++ if(vaddr >= KSEG0_LOW_LIMIT && vaddr < KSEG1_HEIGH_LIMIT) ++ return virt_to_phys((void *)vaddr); ++ ++ panic("dmmu_v2pfn error!"); ++ return 0; ++} ++ ++static unsigned long unmap_node(struct pmd_node *n,unsigned long vaddr,unsigned long end,int check) ++{ ++ unsigned int *pte = (unsigned int *)n->page; ++ int index = ((vaddr & 0x3ff000) >> 12); ++ int free = !check || (--n->count == 0); ++ if(vaddr && end) { ++ while(index < 1024 && vaddr < end) { ++ if(pte[index] & MAP_CONUT_MASK) { ++ pte[index] -= MAP_COUNT; ++ } else { ++ ClearPageReserved(virt_to_page((void *)vaddr)); ++ pte[index] = reserved_pte; ++ } ++ index++; ++ vaddr += 4096; ++ } ++ } ++ ++ if(free) { ++ ClearPageReserved(virt_to_page((void *)n->page)); ++ free_page(n->page); ++ list_del(&n->list); ++ kfree(n); ++ return vaddr+(1024-index)*4096; ++ } ++ ++ return vaddr; ++} ++ ++static unsigned long map_node(struct pmd_node *n,unsigned int vaddr,unsigned int end) ++{ ++ unsigned int *pte = (unsigned int *)n->page; ++ int index = ((vaddr & 0x3ff000) >> 12); ++ ++ while(index < 1024 && vaddr < end) { ++ if(pte[index] == reserved_pte) { ++ SetPageReserved(virt_to_page((void *)vaddr)); ++ pte[index] = dmmu_v2pfn(vaddr) | DMMU_PTE_VLD; ++ // printk(">>>>>vaddr = %d pte = %x, pte[%d] = %x<<<<<<\n\n",vaddr, (unsigned int)pte, index, pte[index]); ++ } else { ++ pte[index] += MAP_COUNT; ++ } ++ index++; ++ vaddr += 4096; ++ } ++ n->count++; ++ return vaddr; ++} ++ ++static struct pmd_node *find_node(struct dmmu_handle *h,unsigned int vaddr) ++{ ++ struct list_head *pos, *next; ++ struct pmd_node *n; ++ ++ list_for_each_safe(pos, next, &h->pmd_list) { ++ n = list_entry(pos, struct pmd_node, list); ++ if(n->index == (vaddr & 0xffc00000)) ++ return n; ++ } ++ return NULL; ++} ++ ++static struct pmd_node *add_node(struct dmmu_handle *h,unsigned int vaddr) ++{ ++ int i; ++ unsigned long *pte; ++ unsigned long *pgd = (unsigned long *)h->pdg; ++ struct pmd_node *n = kmalloc(sizeof(*n),GFP_KERNEL); ++ INIT_LIST_HEAD(&n->list); ++ n->count = 0; ++ n->index = vaddr & 0xffc00000; ++ n->page = __get_free_page(GFP_KERNEL); ++ SetPageReserved(virt_to_page((void *)n->page)); ++ ++ pte = (unsigned long *)n->page; ++ for(i=0;i<1024;i++) ++ pte[i] = reserved_pte; ++ ++ list_add(&n->list, &h->pmd_list); ++ ++ pgd[vaddr>>22] = dmmu_v2pfn(n->page) | DMMU_PMD_VLD; ++// printk(">>>>>>> n->page = %lx, pgd[vaddr>>22] = %lx <<<<<<<\n\n", n->page, pgd[vaddr>>22]); ++ return n; ++} ++ ++static struct dmmu_handle *find_handle(void) ++{ ++ struct list_head *pos, *next; ++ struct dmmu_handle *h; ++ ++ list_for_each_safe(pos, next, &handle_list) { ++ h = list_entry(pos, struct dmmu_handle, list); ++ if(h->tgid == current->tgid) ++ return h; ++ } ++ return NULL; ++} ++ ++static struct dmmu_handle *create_handle(void) ++{ ++ struct dmmu_handle *h; ++ unsigned int pgd_index; ++ unsigned long *pgd; ++ ++ h = kmalloc(sizeof(struct dmmu_handle),GFP_KERNEL); ++ if(!h) ++ return NULL; ++ ++ h->tgid = current->tgid; ++ h->pdg = __get_free_page(GFP_KERNEL); ++ if(!h->pdg) { ++ pr_err("%s %d, Get free page for PGD error\n", ++ __func__, __LINE__); ++ kfree(h); ++ return NULL; ++ } ++ SetPageReserved(virt_to_page((void *)h->pdg)); ++ ++ pgd = (unsigned long *)h->pdg; ++ ++ for (pgd_index=0; pgd_index < PTRS_PER_PGD; pgd_index++) ++ pgd[pgd_index] = res_pte_paddr; ++ ++ INIT_LIST_HEAD(&h->list); ++ INIT_LIST_HEAD(&h->pmd_list); ++ INIT_LIST_HEAD(&h->map_list); ++ list_add(&h->list, &handle_list); ++ ++ mutex_init(&h->lock); ++ return h; ++} ++ ++static int dmmu_make_present(unsigned long addr,unsigned long end) ++{ ++#if 0 ++ unsigned long i; ++ for(i = addr; i < end; i += 4096) { ++ *(volatile unsigned char *)(i) = 0; ++ } ++ *(volatile unsigned char *)(end - 1) = 0; ++ return 0; ++#else ++ int ret, len, write; ++ struct vm_area_struct * vma; ++ unsigned long vm_page_prot; ++ ++ vma = find_vma(current->mm, addr); ++ if (!vma) { ++ printk("dmmu_make_present error. addr=%lx len=%lx\n",addr,end-addr); ++ return -1; ++ } ++ ++ if(vma->vm_flags & VM_PFNMAP) ++ return 0; ++ ++ write = (vma->vm_flags & VM_WRITE) != 0; ++ BUG_ON(addr >= end); ++ BUG_ON(end > vma->vm_end); ++ ++ vm_page_prot = pgprot_val(vma->vm_page_prot); ++ vma->vm_page_prot = __pgprot(vm_page_prot | _PAGE_VALID| _PAGE_ACCESSED | _PAGE_PRESENT); ++ ++ len = DIV_ROUND_UP(end, PAGE_SIZE) - addr/PAGE_SIZE; ++ ret = get_user_pages(current, current->mm, addr, ++ len, write, 0, NULL, NULL); ++ vma->vm_page_prot = __pgprot(vm_page_prot); ++ if (ret < 0) { ++ printk("dmmu_make_present get_user_pages error(%d). addr=%lx len=%lx\n",0-ret,addr,end-addr); ++ return ret; ++ } ++ return ret == len ? 0 : -1; ++#endif ++} ++ ++static void dmmu_cache_wback(struct dmmu_handle *h) ++{ ++ struct list_head *pos, *next; ++ struct pmd_node *n; ++ ++ dma_cache_wback(h->pdg,PAGE_SIZE); ++ ++ list_for_each_safe(pos, next, &h->pmd_list) { ++ n = list_entry(pos, struct pmd_node, list); ++ dma_cache_wback(n->page,PAGE_SIZE); ++ } ++} ++ ++static void dmmu_dump_handle(struct seq_file *m, void *v, struct dmmu_handle *h); ++ ++unsigned long dmmu_map(struct device *dev,unsigned long vaddr,unsigned long len) ++{ ++ int end = vaddr + len; ++ struct dmmu_handle *h; ++ struct pmd_node *node; ++ ++ h = find_handle(); ++ if(!h) ++ h = create_handle(); ++ if(!h) ++ return 0; ++ ++ mutex_lock(&h->lock); ++#ifdef DEBUG ++ printk("(pid %d)dmmu_map %lx %lx================================================\n",h->tgid,vaddr,len); ++#endif ++ if(check_map(h,vaddr,len)) ++ { ++ mutex_unlock(&h->lock); ++ return dmmu_v2pfn(h->pdg); ++ } ++ ++ if(dmmu_make_present(vaddr,vaddr+len)) ++ { ++ mutex_unlock(&h->lock); ++ return 0; ++ } ++ ++ handle_add_map(dev,h,vaddr,len); ++ ++ while(vaddr < end) { ++ node = find_node(h,vaddr); ++ if(!node) { ++ node = add_node(h,vaddr); ++ } ++ vaddr = map_node(node,vaddr,end); ++ } ++ dmmu_cache_wback(h); ++#ifdef DEBUG ++ dmmu_dump_handle(NULL,NULL,h); ++#endif ++ mutex_unlock(&h->lock); ++ ++ return dmmu_v2pfn(h->pdg); ++} ++ ++int dmmu_unmap(struct device *dev,unsigned long vaddr, int len) ++{ ++ unsigned long end = vaddr + len; ++ struct dmmu_handle *h; ++ struct pmd_node *node; ++ struct map_node *n; ++ ++ h = find_handle(); ++ if(!h) ++ return 0; ++ ++ mutex_lock(&h->lock); ++#ifdef DEBUG ++ printk("dmmu_unmap %lx %x**********************************************\n",vaddr,len); ++#endif ++ n = check_map(h,vaddr,len); ++ if(!n) { ++ mutex_unlock(&h->lock); ++ return -EAGAIN; ++ } ++ if(n->dev != dev) { ++ mutex_unlock(&h->lock); ++ return -EAGAIN; ++ } ++ ++ list_del(&n->list); ++ kfree(n); ++ ++ while(vaddr < end) { ++ node = find_node(h,vaddr); ++ if(node) ++ vaddr = unmap_node(node,vaddr,end,1); ++ } ++ ++ if(list_empty(&h->pmd_list) && list_empty(&h->map_list)) { ++ list_del(&h->list); ++ ClearPageReserved(virt_to_page((void *)h->pdg)); ++ free_page(h->pdg); ++ mutex_unlock(&h->lock); ++ kfree(h); ++ return 0; ++ } ++ ++ mutex_unlock(&h->lock); ++ return 0; ++} ++ ++int dmmu_free_all(struct device *dev) ++{ ++ struct dmmu_handle *h; ++ struct pmd_node *node; ++ struct map_node *cn; ++ struct list_head *pos, *next; ++ ++ h = find_handle(); ++ if(!h) ++ return 0; ++ ++ mutex_lock(&h->lock); ++ ++ list_for_each_safe(pos, next, &h->map_list) { ++ cn = list_entry(pos, struct map_node, list); ++ node = find_node(h,cn->start); ++ if(node) ++ unmap_node(node,cn->start,cn->len,1); ++ list_del(&cn->list); ++ kfree(cn); ++ } ++ ++ list_for_each_safe(pos, next, &h->pmd_list) { ++ node = list_entry(pos, struct pmd_node, list); ++ if(node){ ++ printk("WARN: pmd list should NULL\n"); ++ unmap_node(node,0,0,0); ++ } ++ } ++ ++ list_del(&h->list); ++ ClearPageReserved(virt_to_page((void *)h->pdg)); ++ free_page(h->pdg); ++ kfree(h); ++ ++ mutex_unlock(&h->lock); ++ return 0; ++} ++ ++int dmmu_unmap_all(struct device *dev) ++{ ++ struct dmmu_handle *h; ++ struct map_node *cn; ++ struct list_head *pos, *next; ++ ++#ifdef DEBUG ++ printk("dmmu_unmap_all\n"); ++#endif ++ h = find_handle(); ++ if(!h) ++ return 0; ++ ++ list_for_each_safe(pos, next, &h->map_list) { ++ cn = list_entry(pos, struct map_node, list); ++ if(dev == cn->dev) ++ dmmu_unmap(dev,cn->start,cn->len); ++ } ++ ++ ++ if(list_empty(&h->map_list)) ++ dmmu_free_all(dev); ++ return 0; ++} ++ ++int __init dmmu_init(void) ++{ ++ int i; ++ unsigned int pte_index; ++ unsigned long res_page_paddr; ++ unsigned long reserved_page; ++ unsigned int *res_pte_vaddr; ++ ++ reserved_page = __get_free_page(GFP_KERNEL); ++ if (!reserved_page) { ++ pr_err("%s %d, Get reserved page error\n", ++ __func__, __LINE__); ++ return ENOMEM; ++ } ++ SetPageReserved(virt_to_page((void *)reserved_page)); ++ reserved_pte = dmmu_v2pfn(reserved_page) | DMMU_PTE_VLD; ++ ++ res_page_paddr = virt_to_phys((void *)reserved_page) | 0xFFF; ++ ++ res_pte_vaddr = (unsigned int *)__get_free_page(GFP_KERNEL); ++ if (!res_pte_vaddr) { ++ pr_err("%s %d, Get free page for PTE error\n", ++ __func__, __LINE__); ++ free_page(reserved_page); ++ return ENOMEM; ++ } ++ for(i = 0; i<1024; i++ ) ++ res_pte_vaddr[i] = 0xffffffff; ++ SetPageReserved(virt_to_page(res_pte_vaddr)); ++ res_pte_paddr = virt_to_phys((void *)res_pte_vaddr) | DMMU_PTE_VLD; ++ ++ for (pte_index = 0; pte_index < PTRS_PER_PTE; pte_index++) ++ res_pte_vaddr[pte_index] = res_page_paddr; ++ printk("%s %d PTRS_PER_PTE = %lu\n",__func__,__LINE__,PTRS_PER_PTE); ++ ++ return 0; ++} ++arch_initcall(dmmu_init); ++ ++void dmmu_dump_vaddr(unsigned long vaddr) ++{ ++ struct dmmu_handle *h; ++ struct pmd_node *node; ++ ++ unsigned long *pmd,*pte; ++ h = find_handle(); ++ if(!h) { ++ printk("dmmu_dump_vaddr %08lx error - h not found!\n",vaddr); ++ return; ++ } ++ ++ node = find_node(h,vaddr); ++ if(!node) { ++ printk("dmmu_dump_vaddr %08lx error - node not found!\n",vaddr); ++ return; ++ } ++ ++ pmd = (unsigned long *)h->pdg; ++ pte = (unsigned long *)node->page; ++ ++ printk("pmd base = %p; pte base = %p\n",pmd,pte); ++ printk("pmd = %08lx; pte = %08lx\n",pmd[vaddr>>22],pte[(vaddr&0x3ff000)>>12]); ++} ++ ++static void dmmu_dump_handle(struct seq_file *m, void *v, struct dmmu_handle *h) ++{ ++ struct list_head *pos, *next; ++ struct map_node *n; ++ ++ list_for_each_safe(pos, next, &h->map_list) { ++ n = list_entry(pos, struct map_node, list); ++ { ++ int i = 0; ++ int vaddr = n->start; ++ struct pmd_node *pn = find_node(h,vaddr); ++ unsigned int *pte = (unsigned int *)pn->page; ++ ++ while(vaddr < (n->start + n->len)) { ++ if(i++%8 == 0) ++ printk("\nvaddr %08x : ",vaddr & 0xfffff000); ++ printk("%08x ",pte[(vaddr & 0x3ff000)>>12]); ++ vaddr += 4096; ++ } ++ printk("\n\n"); ++ } ++ } ++} ++ ++static int dmmu_proc_show(struct seq_file *m, void *v) ++{ ++ struct list_head *pos, *next; ++ struct dmmu_handle *h; ++ volatile unsigned long flags; ++ local_irq_save(flags); ++ list_for_each_safe(pos, next, &handle_list) { ++ h = list_entry(pos, struct dmmu_handle, list); ++ dmmu_dump_handle(m, v, h); ++ } ++ local_irq_restore(flags); ++ return 0; ++} ++ ++static int dmmu_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, dmmu_proc_show, PDE_DATA(inode)); ++} ++ ++static const struct file_operations dmmus_proc_fops ={ ++ .read = seq_read, ++ .open = dmmu_open, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++ ++static int __init init_dmmu_proc(void) ++{ ++ struct proc_dir_entry *p; ++ p = jz_proc_mkdir("dmmu"); ++ if (!p) { ++ pr_warning("create_proc_entry for common dmmu failed.\n"); ++ return -ENODEV; ++ } ++ proc_create("dmmus", 0600,p,&dmmus_proc_fops); ++ ++ return 0; ++} ++ ++module_init(init_dmmu_proc); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_pm.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_pm.c.patch new file mode 100644 index 00000000..325ecaea --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_pm.c.patch @@ -0,0 +1,374 @@ +diff -drupN a/arch/mips/xburst2/soc-t40/pm.c b/arch/mips/xburst2/soc-t40/pm.c +--- a/arch/mips/xburst2/soc-t40/pm.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-t40/pm.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,370 @@ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++ ++#define SLEEP_MEMORY_START 0xb2400000 ++#define SLEEP_MEMORY_END 0xb2407ffc ++#define SLEEP_RESUME_SP SLEEP_MEMORY_END ++#define SLEEP_RESUME_BOOTUP_TEXT SLEEP_MEMORY_START ++ ++#define SLEEP_CPU_RESUME_BOOTUP_TEXT SLEEP_RESUME_BOOTUP_TEXT ++#define SLEEP_CPU_RESUME_BOOTUP_LEN 32 // 8 instructions ++#define SLEEP_CPU_RESUME_TEXT (SLEEP_CPU_RESUME_BOOTUP_TEXT + SLEEP_CPU_RESUME_BOOTUP_LEN) ++#define SLEEP_CPU_RESUME_LEN (1024) ++#define SLEEP_CPU_SLEEP_TEXT (SLEEP_CPU_RESUME_TEXT + SLEEP_CPU_RESUME_LEN) ++#define SLEEP_CPU_SLEEP_LEN (3072) ++#define SLEEP_CPU_RESUME_SP SLEEP_RESUME_SP ++ ++ ++/*************************************** debug ***************************************/ ++ ++#define PRINT_DEBUG ++ ++#ifdef PRINT_DEBUG ++ ++#define OFF_TDR (0x00) ++#define OFF_LCR (0x0C) ++#define OFF_LSR (0x14) ++#define LSR_TDRQ (1 << 5) ++#define LSR_TEMT (1 << 6) ++ ++#define U_IOBASE (UART0_IOBASE + 0xa0000000) ++#define TCSM_PCHAR(x) \ ++ *((volatile unsigned int*)(U_IOBASE+OFF_TDR)) = x; \ ++while ((*((volatile unsigned int*)(U_IOBASE + OFF_LSR)) & (LSR_TDRQ | LSR_TEMT)) != (LSR_TDRQ | LSR_TEMT)) ++#else ++#define TCSM_PCHAR(x) ++#endif ++ ++#define TCSM_DELAY(x) \ ++ do{ \ ++ register unsigned int i = x; \ ++ while(i--) \ ++ __asm__ volatile(".set mips32\n\t" \ ++ "nop\n\t" \ ++ ".set mips32"); \ ++ }while(0) \ ++ ++static inline void serial_put_hex(unsigned int x) { ++ int i; ++ unsigned int d; ++ for(i = 7;i >= 0;i--) { ++ d = (x >> (i * 4)) & 0xf; ++ if(d < 10) d += '0'; ++ else d += 'A' - 10; ++ TCSM_PCHAR(d); ++ } ++ TCSM_PCHAR('\r'); ++ TCSM_PCHAR('\n'); ++} ++ ++/*************************************************************************************/ ++ ++/*----------------------------------------------------------------------------- ++ * extern function declare ++ *-----------------------------------------------------------------------------*/ ++extern long long save_goto(unsigned int func, suspend_state_t state, unsigned int cpu_id); ++extern int restore_goto(unsigned int func, suspend_state_t state, unsigned int cpu_id); ++ ++ ++static void load_func_to_tcsm(unsigned int *tcsm_addr,unsigned int *f_addr,unsigned int size) ++{ ++ unsigned int instr; ++ int offset; ++ int i; ++#ifdef DEBUG_PM ++ printk("tcsm addr = %p %p size = %d\n",tcsm_addr,f_addr,size); ++#endif ++ for(i = 0;i < size / 4;i++) { ++ instr = f_addr[i]; ++ if((instr >> 26) == 2){ ++ offset = instr & 0x3ffffff; ++ offset = (offset << 2) - ((unsigned int)f_addr & 0xfffffff); ++ if(offset > 0) { ++ offset = ((unsigned int)tcsm_addr & 0xfffffff) + offset; ++ instr = (2 << 26) | (offset >> 2); ++ } ++ } ++ tcsm_addr[i] = instr; ++ } ++} ++ ++ ++static int soc_pm_idle(void) ++{ ++ unsigned int lcr = cpm_inl(CPM_LCR); ++ unsigned int opcr = cpm_inl(CPM_OPCR); ++ ++ lcr &=~ 0x3; // low power mode: IDLE ++ cpm_outl(lcr, CPM_LCR); ++ ++ opcr &= ~(1 << 30); ++ opcr &= ~(1 << 31); ++ cpm_outl(opcr, CPM_OPCR); ++ ++ return 0; ++} ++ ++#ifdef X2000_IDLE_PD ++static int soc_pm_idle_pd(void) ++{ ++ unsigned int lcr = cpm_inl(CPM_LCR); ++ unsigned int opcr = cpm_inl(CPM_OPCR); ++ ++ lcr &=~ 0x3; // low power mode: IDLE ++ lcr |= 2; ++ cpm_outl(lcr, CPM_LCR); ++ ++ opcr &= ~ (1<<31); ++ opcr |= (1 << 30); ++ opcr |= (1 << 26); //l2c retention ++ opcr |= 1 << 2; // select RTC clk ++ cpm_outl(opcr, CPM_OPCR); ++ ++ return 0; ++} ++#endif ++ ++static int soc_pm_sleep(void) ++{ ++ unsigned int lcr = cpm_inl(CPM_LCR); ++ unsigned int opcr = cpm_inl(CPM_OPCR); ++ ++ lcr &=~ 0x3; ++ lcr |= 1 << 0; // low power mode: SLEEP ++ cpm_outl(lcr, CPM_LCR); ++ ++ opcr &= ~(1 << 31); ++ opcr |= (1 << 30); ++ opcr |= (1 << 26); //L2C retention. ++ opcr |= (1 << 21); // cpu 32k ram retention. ++ opcr |= (1 << 3); // power down CPU ++ opcr &= ~(1 << 4); // exclk disable; ++ opcr |= (1 << 2); // select RTC clk ++ cpm_outl(opcr, CPM_OPCR); ++ ++ { ++ /* before power down cpu by set PD in OPCR, reduce cpu's frequency as the same as L2C's freq */ ++ unsigned int val, div; ++ ++ /* change disable */ ++ val = cpm_inl(CPM_CPCCR); ++ val &= ~(1 << 22); ++ cpm_outl(val, CPM_CPCCR); ++ ++ /* div cpu = div l2c */ ++ div = val & (0xf << 4); ++ val &= ~0xf; ++ val |= div; ++ cpm_outl(val, CPM_CPCCR); ++ ++ /* change enable */ ++ val |= (1 << 22); ++ cpm_outl(val, CPM_CPCCR); ++ } ++ ++ return 0; ++} ++ ++static int soc_post_wakeup(void) ++{ ++ unsigned int lcr = cpm_inl(CPM_LCR); ++ ++ printk("post wakeup!\n"); ++ ++ lcr &= ~0x3; // low power mode: IDLE ++ cpm_outl(lcr, CPM_LCR); ++ ++ return 0; ++} ++ ++static noinline void cpu_resume_bootup(void) ++{ ++ /* set reset entry */ ++ *(volatile unsigned int *)0xb2200f00 = 0xbfc00000; ++ ++ __asm__ volatile( ++ ".set push \n\t" ++ ".set mips32r2 \n\t" ++ "move $29, %0 \n\t" ++ "jr.hb %1 \n\t" ++ "nop \n\t" ++ ".set pop \n\t" ++ : ++ :"r" (SLEEP_CPU_RESUME_SP), "r"(SLEEP_CPU_RESUME_TEXT) ++ : ++ ); ++} ++ ++static noinline void cpu_resume(suspend_state_t state) ++{ ++ unsigned int cpu_id; ++ unsigned int ddrc_ctrl = ddr_readl(DDRC_CTRL); ++ ++ if (state == PM_SUSPEND_MEM) { ++ ddrc_ctrl &= ~(1<<5); ++ ddrc_ctrl |= 1 << 1; ++ ddr_writel(ddrc_ctrl, DDRC_CTRL); ++ ++ while(ddr_readl(DDRC_STATUS) & (1<<2)); ++ } ++ ++ cpu_id = read_c0_ebase() & 0x3ff; ++ ++ __asm__ volatile( ++ ".set push \n\t" ++ ".set mips32r2 \n\t" ++ "jr.hb %0 \n\t" ++ "nop \n\t" ++ ".set pop \n\t" ++ : ++ : "r" (restore_goto), ++ "r" (state), ++ "r" (cpu_id) ++ : ++ ); ++} ++ ++ ++static noinline void cpu_sleep(suspend_state_t state) ++{ ++ ++ unsigned int ddrc_ctrl = ddr_readl(DDRC_CTRL); ++ ++ blast_dcache32(); ++ blast_scache64(); ++ __sync(); ++ __fast_iob(); ++ ++ if (state == PM_SUSPEND_MEM) { ++ /* DDR self refresh, */ ++ ddrc_ctrl |= 1 << 5; ++ ddrc_ctrl &= ~(1<<1); ++ ddr_writel(ddrc_ctrl, DDRC_CTRL); ++ while(!(ddr_readl(DDRC_STATUS) & (1<<2))); ++ } ++ ++ __asm__ volatile( ++ ".set push \n\t" ++ ".set mips32r2 \n\t" ++ "wait \n\t" ++ "nop \n\t" ++ "nop \n\t" ++ "nop \n\t" ++ ".set pop \n\t" ++ ); ++ ++ TCSM_PCHAR('\r'); ++ TCSM_PCHAR('\n'); ++ TCSM_PCHAR('?'); ++ TCSM_PCHAR('?'); ++ TCSM_PCHAR('?'); ++ TCSM_PCHAR('\r'); ++ TCSM_PCHAR('\n'); ++ ++ __asm__ volatile( ++ ".set push \n\t" ++ ".set mips32r2 \n\t" ++ "jr.hb %0 \n\t" ++ "nop \n\t" ++ ".set pop \n\t" ++ : ++ : "r" (SLEEP_CPU_RESUME_BOOTUP_TEXT) ++ : ++ ); ++} ++ ++ ++int x2000_pm_enter(suspend_state_t state) ++{ ++ unsigned int cpu_id; ++ ++ printk("x2000 pm enter!!\n"); ++ ++ load_func_to_tcsm((unsigned int *)SLEEP_CPU_RESUME_BOOTUP_TEXT, (unsigned int *)cpu_resume_bootup, SLEEP_CPU_RESUME_BOOTUP_LEN); ++ load_func_to_tcsm((unsigned int *)SLEEP_CPU_RESUME_TEXT, (unsigned int *)cpu_resume, SLEEP_CPU_RESUME_LEN); ++ load_func_to_tcsm((unsigned int *)SLEEP_CPU_SLEEP_TEXT, (unsigned int *)cpu_sleep, SLEEP_CPU_SLEEP_LEN); ++ ++ if (state == PM_SUSPEND_STANDBY) { ++#ifdef X2000_IDLE_PD ++ soc_pm_idle_pd(); ++#else ++ soc_pm_idle(); ++#endif ++ } else if (state == PM_SUSPEND_MEM) { ++ soc_pm_sleep(); ++ } else { ++ printk("WARNING : unsupport pm suspend state\n"); ++ } ++ ++#ifdef DEBUG_PM ++ printk("LCR: %08x\n", cpm_inl(CPM_LCR)); ++ printk("OPCR: %08x\n", cpm_inl(CPM_OPCR)); ++#endif ++ ++ cpu_id = read_c0_ebase() & 0x1ff; ++ ++ /* set reset entry */ ++ *(volatile unsigned int *)0xb2200f00 = SLEEP_CPU_RESUME_BOOTUP_TEXT; ++ ++ mb(); ++ save_goto((unsigned int)SLEEP_CPU_SLEEP_TEXT, state, cpu_id); ++ mb(); ++ ++ soc_post_wakeup(); ++ ++ return 0; ++} ++ ++static int x2000_pm_begin(suspend_state_t state) ++{ ++ printk("x2000 suspend begin\n"); ++ return 0; ++} ++ ++static void x2000_pm_end(void) ++{ ++ printk("x2000 pm end!\n"); ++} ++ ++static int ingenic_pm_valid(suspend_state_t state) ++{ ++ switch (state) { ++ case PM_SUSPEND_ON: ++ case PM_SUSPEND_STANDBY: ++ case PM_SUSPEND_MEM: ++ return 1; ++ ++ default: ++ return 0; ++ } ++} ++static const struct platform_suspend_ops x2000_pm_ops = { ++ .valid = ingenic_pm_valid, ++ .begin = x2000_pm_begin, ++ .enter = x2000_pm_enter, ++ .end = x2000_pm_end, ++}; ++ ++/* ++ * Initialize suspend interface ++ */ ++static int __init pm_init(void) ++{ ++ ++ suspend_set_ops(&x2000_pm_ops); ++ ++ ++ return 0; ++} ++ ++late_initcall(pm_init); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_regs_save_restore.S.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_regs_save_restore.S.patch new file mode 100644 index 00000000..06fe3013 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_regs_save_restore.S.patch @@ -0,0 +1,190 @@ +diff -drupN a/arch/mips/xburst2/soc-t40/regs_save_restore.S b/arch/mips/xburst2/soc-t40/regs_save_restore.S +--- a/arch/mips/xburst2/soc-t40/regs_save_restore.S 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-t40/regs_save_restore.S 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,186 @@ ++#include ++#include ++ ++#define CP0_PAGEMASK $5,0 ++#define CP0_TLB_SPEC $5,4 ++#define CP0_STATUS $12,0 ++#define CP0_INTCTL $12,1 ++#define CP0_CAUSE $13,0 ++#define CP0_EBASE $15,1 ++#define CP0_CONFIG $16,0 ++#define CP0_CONFIG1 $16,1 ++#define CP0_CONFIG2 $16,2 ++#define CP0_CONFIG3 $16,3 ++#define CP0_CONFIG4 $16,4 ++#define CP0_CONFIG5 $16,5 ++#define CP0_CONFIG7 $16,7 ++#define CP0_LLADDR $17,0 ++#define PMON_CSR $17,7 ++#define PMON_HIGH $17,4 ++#define PMON_LC $17,5 ++#define PMON_RC $17,6 ++#define CP0_WATCHLo $18,0 ++#define CP0_WATCHHI $19,0 ++#define CP0_ERRCTL $26,0 ++#define CP0_CONTEXT $4,0 ++ ++ .data ++ .global _regs_stack ++_regs_stack: ++ .align 5 ++ .space 272,0 ++ ++ .text ++ .global save_goto ++ .align 2 ++ .ent save_goto,0 ++save_goto: ++ .set push ++ .set noreorder ++ .set noat ++ ++ la k0, _regs_stack ++ sllv k0, k0, a2 ++ sw s0,0(k0) ++ sw s1,4(k0) ++ sw s2,8(k0) ++ sw s3,12(k0) ++ sw s4,16(k0) ++ sw s5,20(k0) ++ sw s6,24(k0) ++ sw s7,28(k0) ++ sw gp,32(k0) ++ sw sp,36(k0) ++ sw fp,40(k0) ++ sw ra,44(k0) ++ ++ mfc0 k1,CP0_PAGEMASK ++ sw k1,48(k0) ++ mfc0 k1,CP0_TLB_SPEC ++ sw k1,52(k0) ++ mfc0 k1,CP0_STATUS ++ sw k1,56(k0) ++ mfc0 k1,CP0_INTCTL ++ sw k1,60(k0) ++ mfc0 k1,CP0_CAUSE ++ sw k1,64(k0) ++ mfc0 k1,CP0_EBASE ++ sw k1,68(k0) ++ mfc0 k1,CP0_CONFIG ++ sw k1,72(k0) ++ mfc0 k1,CP0_CONFIG1 ++ sw k1,76(k0) ++ mfc0 k1,CP0_CONFIG2 ++ sw k1,80(k0) ++ mfc0 k1,CP0_CONFIG3 ++ sw k1,84(k0) ++ mfc0 k1,CP0_CONFIG4 ++ sw k1,88(k0) ++ mfc0 k1,CP0_CONFIG5 ++ sw k1,92(k0) ++ mfc0 k1,CP0_CONFIG7 ++ sw k1,96(k0) ++ mfc0 k1,CP0_LLADDR ++ sw k1,100(k0) ++ mfc0 k1,PMON_CSR ++ sw k1,104(k0) ++ mfc0 k1,PMON_HIGH ++ sw k1,108(k0) ++ mfc0 k1,PMON_LC ++ sw k1,112(k0) ++ mfc0 k1,PMON_RC ++ sw k1,116(k0) ++ mfc0 k1,CP0_WATCHLo ++ sw k1,120(k0) ++ mfc0 k1,CP0_WATCHHI ++ sw k1,124(k0) ++ mfc0 k1,CP0_ERRCTL ++ sw k1,128(k0) ++ mfc0 k1,CP0_CONTEXT ++ sw k1,132(k0) ++ ++ move t0, a0 ++ move a0, a1 ++ jr.hb t0 ++ nop ++ ++ .set at ++ .set reorder ++ .set pop ++ END(save_goto) ++ .text ++ .global restore_goto ++ .align 2 ++ .ent restore_goto,0 ++restore_goto: ++ .set push ++ .set noreorder ++ .set noat ++ ++ la k0, _regs_stack ++ sllv k0, k0, a2 ++ lw s0,0(k0) ++ lw s1,4(k0) ++ lw s2,8(k0) ++ lw s3,12(k0) ++ lw s4,16(k0) ++ lw s5,20(k0) ++ lw s6,24(k0) ++ lw s7,28(k0) ++ lw gp,32(k0) ++ lw sp,36(k0) ++ lw fp,40(k0) ++ lw ra,44(k0) ++ ++ lw k1,48(k0) ++ mtc0 k1,CP0_PAGEMASK ++ lw k1,52(k0) ++ mtc0 k1,CP0_TLB_SPEC ++ lw k1,56(k0) ++ mtc0 k1,CP0_STATUS ++ lw k1,60(k0) ++ mtc0 k1,CP0_INTCTL ++ lw k1,64(k0) ++ mtc0 k1,CP0_CAUSE ++ lw k1,68(k0) ++ mtc0 k1,CP0_EBASE ++ lw k1,72(k0) ++ mtc0 k1,CP0_CONFIG ++ lw k1,76(k0) ++ mtc0 k1,CP0_CONFIG1 ++ lw k1,80(k0) ++ mtc0 k1,CP0_CONFIG2 ++ lw k1,84(k0) ++ mtc0 k1,CP0_CONFIG3 ++ lw k1,88(k0) ++ mtc0 k1,CP0_CONFIG4 ++ lw k1,92(k0) ++ mtc0 k1,CP0_CONFIG5 ++ lw k1,96(k0) ++ mtc0 k1,CP0_CONFIG7 ++ lw k1,100(k0) ++ mtc0 k1,CP0_LLADDR ++ lw k1,104(k0) ++ mtc0 k1,PMON_CSR ++ lw k1,108(k0) ++ mtc0 k1,PMON_HIGH ++ lw k1,112(k0) ++ mtc0 k1,PMON_LC ++ lw k1,116(k0) ++ mtc0 k1,PMON_RC ++ lw k1,120(k0) ++ mtc0 k1,CP0_WATCHLo ++ lw k1,124(k0) ++ mtc0 k1,CP0_WATCHHI ++ lw k1,128(k0) ++ mtc0 k1,CP0_ERRCTL ++ lw k1,132(k0) ++ mtc0 k1,CP0_CONTEXT ++ ++ jr.hb ra ++ nop ++ ++ .set at ++ .set reorder ++ .set pop ++ END(restore_goto) diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_regs_save_restore.py.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_regs_save_restore.py.patch new file mode 100644 index 00000000..5ed10bdd --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_regs_save_restore.py.patch @@ -0,0 +1,133 @@ +diff -drupN a/arch/mips/xburst2/soc-t40/regs_save_restore.py b/arch/mips/xburst2/soc-t40/regs_save_restore.py +--- a/arch/mips/xburst2/soc-t40/regs_save_restore.py 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-t40/regs_save_restore.py 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,129 @@ ++#!/usr/bin/env python ++import os ++import string ++ ++common_regs=["s0","s1","s2","s3", ++ "s4","s5","s6","s7", ++ "gp","sp","fp","ra"] ++cp0_regs=[ ++ ["CP0_PAGEMASK","$5","0"], ++ ["CP0_TLB_SPEC","$5","4"], ++ ["CP0_STATUS","$12","0"], ++ ["CP0_INTCTL","$12","1"], ++ ["CP0_CAUSE","$13","0"], ++ ["CP0_EBASE","$15","1"], ++ ["CP0_CONFIG","$16","0"], ++ ["CP0_CONFIG1","$16","1"], ++ ["CP0_CONFIG2","$16","2"], ++ ["CP0_CONFIG3","$16","3"], ++ ["CP0_CONFIG4", "$16", "4"], ++ ["CP0_CONFIG5", "$16", "5"], ++ ["CP0_CONFIG7","$16","7"], ++ ["CP0_LLADDR","$17","0"], ++ ["PMON_CSR","$17","7"], ++ ["PMON_HIGH","$17","4"], ++ ["PMON_LC","$17","5"], ++ ["PMON_RC","$17","6"], ++ ["CP0_WATCHLo","$18","0"], ++ ["CP0_WATCHHI","$19","0"], ++ ["CP0_ERRCTL","$26","0"], ++ ["CP0_CONTEXT", "$4", "0"], ++ ] ++def gen_get_array_size(): ++ size=0 ++ size+=len(common_regs) ++ size+=len(cp0_regs) ++ return size ++ ++def gen_print_head_and_macro(): ++ print("#include ") ++ print("#include ") ++ print("") ++ for s in cp0_regs: ++ print("#define %s\t%s,%s" %(s[0],s[1],s[2])) ++ print("") ++def gen_define_global_arg(str, num): ++ print("\t.data") ++ print("\t.global %s" %(str)) ++ print("%s:" %(str)) ++ print("\t.align 5") ++ print("\t.space %s,0" %(num)) ++ print("") ++ ++def gen_save_common_regs(index): ++ for s in common_regs: ++ print("\tsw\t%s,%d(k0)" % (s,index)) ++ index=index+4 ++ return index ++def gen_restore_common_regs(index): ++ for s in common_regs: ++ print("\tlw\t%s,%d(k0)" % (s,index)) ++ index=index+4 ++ return index ++def gen_save_cp0_regs(index): ++ for s in cp0_regs: ++ print("\tmfc0\tk1,%s" % (s[0])) ++ print("\tsw\tk1,%d(k0)" % (index)) ++ index=index+4 ++ return index ++def gen_restore_cp0_regs(index): ++ for s in cp0_regs: ++ print("\tlw\tk1,%d(k0)" % (index)) ++ print("\tmtc0\tk1,%s" % (s[0])) ++ index=index+4 ++ return index ++def gen_print_function(f_name, regs_stack): ++ index=0 ++ print("\t.text") ++ print("\t.global %s" %(f_name)) ++ print("\t.align 2") ++ print("\t.ent %s,0" %(f_name)) ++ print("%s:" %(f_name)) ++ print("\t.set\tpush") ++ print("\t.set\tnoreorder") ++ print("\t.set\tnoat") ++ print("") ++ print("\tla\tk0, %s" %(regs_stack)) ++ print("\tsllv\tk0, k0, a2") ++ ''' ++ save_goto(func, args, cpu) ++ ''' ++ if f_name == "save_goto": ++ index = gen_save_common_regs(index) ++ print("") ++ index = gen_save_cp0_regs(index) ++ print("") ++ print("\tmove\tt0, a0"); ++ print("\tmove\ta0, a1"); ++ print("\tjr.hb\tt0") ++ print("\tnop") ++ elif f_name == "restore_goto": ++ index = gen_restore_common_regs(index) ++ print("") ++ index = gen_restore_cp0_regs(index) ++ print("") ++ print("\tjr.hb\tra") ++ print("\tnop") ++ else: ++ print("not support") ++ print("") ++ print("\t.set\tat") ++ print("\t.set\treorder") ++ print("\t.set\tpop") ++ print("\tEND(%s)" %(f_name)) ++ ++ ++def main(): ++ regs_size=gen_get_array_size() ++ regs_size*=4 ++ nr_cpu = 2 ++ regs_size = nr_cpu * regs_size; ++ ++ gen_print_head_and_macro() ++ gen_define_global_arg("_regs_stack", regs_size) ++ gen_print_function("save_goto", "_regs_stack") ++ gen_print_function("restore_goto", "_regs_stack") ++ pass ++ ++if __name__ == '__main__': ++ main() diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_reset.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_reset.c.patch new file mode 100644 index 00000000..3cebea8f --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_reset.c.patch @@ -0,0 +1,335 @@ +diff -drupN a/arch/mips/xburst2/soc-t40/reset.c b/arch/mips/xburst2/soc-t40/reset.c +--- a/arch/mips/xburst2/soc-t40/reset.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-t40/reset.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,331 @@ ++/* ++ * 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. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#include ++#include ++#include ++ ++#include ++ ++#include ++ ++#define RTC_RTCCR (0x00) /* rw, 32, 0x00000081 */ ++#define RTC_RTCSR (0x04) /* rw, 32, 0x???????? */ ++#define RTC_RTCSAR (0x08) /* rw, 32, 0x???????? */ ++#define RTC_RTCGR (0x0c) /* rw, 32, 0x0??????? */ ++#define RTC_HCR (0x20) /* rw, 32, 0x00000000 */ ++#define RTC_HWFCR (0x24) /* rw, 32, 0x0000???0 */ ++#define RTC_HRCR (0x28) /* rw, 32, 0x00000??0 */ ++#define RTC_HWCR (0x2c) /* rw, 32, 0x00000008 */ ++#define RTC_HWRSR (0x30) /* rw, 32, 0x00000000 */ ++#define RTC_HSPR (0x34) /* rw, 32, 0x???????? */ ++#define RTC_WENR (0x3c) /* rw, 32, 0x00000000 */ ++#define RTC_CKPCR (0x40) /* rw, 32, 0x00000010 */ ++#define RTC_OWIPCR (0x44) /* rw, 32, 0x00000010 */ ++#define RTC_PWRONCR (0x48) /* rw, 32, 0x???????? */ ++ ++#define WDT_TCSR (0x0c) /* rw, 32, 0x???????? */ ++#define WDT_TCER (0x04) /* rw, 32, 0x???????? */ ++#define WDT_TDR (0x00) /* rw, 32, 0x???????? */ ++#define WDT_TCNT (0x08) /* rw, 32, 0x???????? */ ++ ++#define TCU_TSSR (0x2C) /* Timer Stop Set Register */ ++#define TCU_TSCR (0x3C) /* Timer Stop Clear Register */ ++ ++#define RTCCR_WRDY BIT(7) ++#define WENR_WEN BIT(31) ++ ++#define RECOVERY_SIGNATURE (0x001a1a) ++#define REBOOT_SIGNATURE (0x003535) ++#define UNMSAK_SIGNATURE (0x7c0000)//do not use these bits ++ ++#if 0 ++static void wdt_start_count(int msecs) ++{ ++ int time = JZ_EXTAL_RTC / 64 * msecs / 1000; ++ if(time > 65535) ++ time = 65535; ++ ++// outl(1 << 16,TCU_IOBASE + TCU_TSCR); ++ ++ outl(0,WDT_IOBASE + WDT_TCNT); //counter ++ outl(time,WDT_IOBASE + WDT_TDR); //data ++ outl((3<<3 | 2<<0 | 1 << 10),WDT_IOBASE + WDT_TCSR); ++ outl(0,WDT_IOBASE + WDT_TCER); ++ outl(1,WDT_IOBASE + WDT_TCER); ++} ++#endif ++static void __attribute__((unused)) wdt_stop_count(void) ++{ ++ outl(1 << 16,TCU_IOBASE + TCU_TSCR); ++ outl(0,WDT_IOBASE + WDT_TCNT); //counter ++ outl(65535,WDT_IOBASE + WDT_TDR); //data ++ outl(1 << 16,TCU_IOBASE + TCU_TSSR); ++} ++ ++static int inline rtc_write_reg(int reg,int value) ++{ ++ int timeout = 0x2000; ++ while(!(inl(RTC_IOBASE + RTC_RTCCR) & RTCCR_WRDY) && timeout--); ++ if(!timeout) ++ { ++ printk("WARN:NO USE RTC!!!!!\n"); ++ return -1; ++ } ++ outl(0xa55a,(RTC_IOBASE + RTC_WENR)); ++ while(!(inl(RTC_IOBASE + RTC_RTCCR) & RTCCR_WRDY)); ++ while(!(inl(RTC_IOBASE + RTC_WENR) & WENR_WEN)); ++ while(!(inl(RTC_IOBASE + RTC_RTCCR) & RTCCR_WRDY)); ++ outl(value,(RTC_IOBASE + reg)); ++ while(!(inl(RTC_IOBASE + RTC_RTCCR) & RTCCR_WRDY)); ++ ++ return 0; ++} ++ ++/* ++ * Function: Keep power for CPU core when reset. ++ * So that EPC, tcsm and so on can maintain it's status after reset-key pressed. ++ */ ++static int inline reset_keep_power(void) ++{ ++ return rtc_write_reg(RTC_PWRONCR, ++ inl(RTC_IOBASE + RTC_PWRONCR) & ~(1 << 0)); ++} ++ ++#define HWFCR_WAIT_TIME(x) ((x > 0x7fff ? 0x7fff: (0x7ff*(x)) / 2000) << 5) ++#define HRCR_WAIT_TIME(x) ((((x) > 1875 ? 1875: (x)) / 125) << 11) ++ ++void jz_hibernate(void) ++{ ++ uint32_t rtc_rtccr; ++ ++ local_irq_disable(); ++ /* Set minimum wakeup_n pin low-level assertion time for wakeup: 1000ms */ ++ rtc_write_reg(RTC_HWFCR, HWFCR_WAIT_TIME(1000)); ++ ++ /* Set reset pin low-level assertion time after wakeup: must > 60ms */ ++ rtc_write_reg(RTC_HRCR, HRCR_WAIT_TIME(125)); ++ ++ /* clear wakeup status register */ ++ rtc_write_reg(RTC_HWRSR, 0x0); ++ ++ rtc_write_reg(RTC_HWCR, 0x0); ++ ++ rtc_rtccr = inl(RTC_IOBASE + RTC_RTCCR); ++ rtc_rtccr |= 0x1 << 0; ++ rtc_write_reg(RTC_RTCCR,rtc_rtccr); ++ ++ /* Put CPU to hibernate mode */ ++ rtc_write_reg(RTC_HCR, 0x1); ++ ++ /*poweroff the pmu*/ ++// jz_notifier_call(NOTEFY_PROI_HIGH, JZ_POST_HIBERNATION, NULL); ++ ++ mdelay(200); ++ ++ while(1) ++ printk("%s:We should NOT come here.%08x\n",__func__, inl(RTC_IOBASE + RTC_HCR)); ++} ++ ++void jz_wdt_restart(char *command) ++{ ++ return; ++#if 0 ++ printk("Restarting after 4 ms\n"); ++ if ((command != NULL) && !strcmp(command, "recovery")) { ++ while(cpm_inl(CPM_CPPSR) != RECOVERY_SIGNATURE) { ++ printk("set RECOVERY_SIGNATURE\n"); ++ cpm_outl(0x5a5a,CPM_CPSPPR); ++ cpm_outl(RECOVERY_SIGNATURE,CPM_CPPSR); ++ cpm_outl(0x0,CPM_CPSPPR); ++ udelay(100); ++ } ++ } else { ++ cpm_outl(0x5a5a,CPM_CPSPPR); ++ cpm_outl(REBOOT_SIGNATURE,CPM_CPPSR); ++ cpm_outl(0x0,CPM_CPSPPR); ++ } ++ ++ wdt_start_count(4); ++ mdelay(200); ++ while(1) ++ printk("check wdt.\n"); ++#endif ++} ++ ++static void hibernate_restart(void) ++{ ++ uint32_t rtc_rtcsr,rtc_rtccr; ++ ++ while(!(inl(RTC_IOBASE + RTC_RTCCR) & RTCCR_WRDY)); ++ ++ rtc_rtcsr = inl(RTC_IOBASE + RTC_RTCSR); ++ rtc_rtccr = inl(RTC_IOBASE + RTC_RTCCR); ++ ++ rtc_write_reg(RTC_RTCSAR,rtc_rtcsr + 5); ++ rtc_rtccr &= ~(1 << 4 | 1 << 1); ++ rtc_rtccr |= 0x3 << 2; ++ rtc_write_reg(RTC_RTCCR,rtc_rtccr); ++ ++ /* Clear reset status */ ++ cpm_outl(0,CPM_RSR); ++ ++ /* Set minimum wakeup_n pin low-level assertion time for wakeup: 1000ms */ ++ rtc_write_reg(RTC_HWFCR, HWFCR_WAIT_TIME(1000)); ++ ++ /* Set reset pin low-level assertion time after wakeup: must > 60ms */ ++ rtc_write_reg(RTC_HRCR, HRCR_WAIT_TIME(125)); ++ ++ /* clear wakeup status register */ ++ rtc_write_reg(RTC_HWRSR, 0x0); ++ ++ rtc_write_reg(RTC_HWCR, 0x1); ++ ++ ++ rtc_rtccr = inl(RTC_IOBASE + RTC_RTCCR); ++ rtc_rtccr |= 0x1 << 0; ++ rtc_write_reg(RTC_RTCCR,rtc_rtccr); ++ ++ ++ /* Put CPU to hibernate mode */ ++ rtc_write_reg(RTC_HCR, 0x1); ++ ++ mdelay(200); ++ while(1) ++ printk("%s:We should NOT come here.%08x\n",__func__, inl(RTC_IOBASE + RTC_HCR)); ++} ++ ++#ifdef CONFIG_HIBERNATE_RESET ++void jz_hibernate_restart(char *command) ++{ ++ local_irq_disable(); ++ ++ if ((command != NULL) && !strcmp(command, "recovery")) { ++ jz_wdt_restart(command); ++ } ++ ++ hibernate_restart(); ++} ++#endif ++ ++int __init reset_init(void) ++{ ++ pm_power_off = jz_hibernate; ++#ifdef CONFIG_HIBERNATE_RESET ++ _machine_restart = jz_hibernate_restart; ++#else ++ _machine_restart = jz_wdt_restart; ++#endif ++ return 0; ++} ++arch_initcall(reset_init); ++ ++/////////////////////////////////////////////////////////////////////////////////////////////////// ++struct wdt_reset { ++ unsigned stop; ++ unsigned msecs; ++ unsigned count; ++}; ++ ++/* ============================reset proc=================================== */ ++static char *reset_command[] = {"wdt","hibernate","recovery", "poweroff"}; ++ ++static int reset_show(struct seq_file *filq, void *v) ++{ ++ int len = 0, i; ++ ++ for(i = 0; i < ARRAY_SIZE(reset_command); i++) ++ seq_printf(filq, "%s\t", reset_command[i]); ++ seq_printf(filq,"\n"); ++ ++ return len; ++} ++ ++static int reset_write(struct file *file, const char __user *buffer, ++ size_t usize, loff_t *off) ++{ ++ int command_size = 0; ++ int i; ++ ++ if(usize == 0) ++ return -EINVAL; ++ ++ command_size = ARRAY_SIZE(reset_command); ++ for(i = 0;i < command_size; i++) { ++ if(!strncmp(buffer, reset_command[i], strlen(reset_command[i]))) ++ break; ++ } ++ if(i == command_size) ++ return -EINVAL; ++ ++ local_irq_disable(); ++ switch(i) { ++ case 0: ++ jz_wdt_restart(NULL); ++ break; ++ case 1: ++ hibernate_restart(); ++ break; ++ case 2: ++ jz_wdt_restart("recovery"); ++ break; ++ case 3: ++ jz_hibernate(); ++ break; ++ default: ++ printk("not support command %d\n", i); ++ } ++ ++ return usize; ++} ++static struct jz_single_file_ops reset_proc_fops = { ++ .read = reset_show, ++ .write = reset_write, ++}; ++/* ============================reset proc end=============================== */ ++ ++static int __init init_reset(void) ++{ ++ struct wdt_reset *wdt; ++ struct proc_dir_entry *p, *res; ++ ++ wdt = kmalloc(sizeof(struct wdt_reset),GFP_KERNEL); ++ if(!wdt) { ++ return -ENOMEM; ++ } ++ ++ wdt->count = 0; ++ wdt->msecs = 3000; ++ ++ wdt->stop = 1; ++ ++ p = jz_proc_mkdir("reset"); ++ if (!p) { ++ pr_warning("create_proc_entry for common reset failed.\n"); ++ return -ENODEV; ++ } ++ ++ res = jz_proc_create_data("reset", 0444, p, &reset_proc_fops, wdt); ++ ++ return 0; ++} ++module_init(init_reset); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_serial.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_serial.c.patch new file mode 100644 index 00000000..5ba2716a --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_serial.c.patch @@ -0,0 +1,95 @@ +diff -drupN a/arch/mips/xburst2/soc-t40/serial.c b/arch/mips/xburst2/soc-t40/serial.c +--- a/arch/mips/xburst2/soc-t40/serial.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-t40/serial.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,91 @@ ++/* ++ * JZ SOC serial routines for early_printk. ++ * ++ * Copyright (C) 2006 Ingenic Semiconductor Inc. ++ * ++ */ ++ ++#include ++ ++#include ++ ++#define UART_BASE UART0_IOBASE ++#define UART_OFF 0x1000 ++ ++#define OFF_TDR (0x00) ++#define OFF_LCR (0x0C) ++#define OFF_LSR (0x14) ++ ++#define LSR_TDRQ (1 << 5) ++#define LSR_TEMT (1 << 6) ++ ++static void check_uart(char c); ++ ++static volatile u8 *uart_base; ++typedef void (*putchar_f_t)(char); ++static putchar_f_t putchar_f = check_uart; ++ ++static void putchar(char ch) ++{ ++ int timeout = 10000; ++ volatile u8 *base = uart_base; ++ /* Wait for fifo to shift out some bytes */ ++ while ((base[OFF_LSR] & (LSR_TDRQ | LSR_TEMT)) ++ != (LSR_TDRQ | LSR_TEMT) && timeout--) ++ ; ++ base[OFF_TDR] = (u8)ch; ++} ++ ++static void putchar_dummy(char ch) ++{ ++ return; ++} ++ ++static void check_uart(char c) ++{ ++ /* We Couldn't use ioremap() here */ ++ volatile u8 *base = (volatile u8*)CKSEG1ADDR(UART0_IOBASE); ++ int i = 0; ++ for(i=0; i<10; i++) { ++ if(base[OFF_LCR]) ++ break; ++ base += UART_OFF; ++ } ++ ++ if(i<10) { ++ uart_base = base; ++ putchar_f = putchar; ++ putchar_f(c); ++ } else { ++ putchar_f = putchar_dummy; ++ } ++} ++ ++/* used by early printk */ ++void prom_putchar(char c) ++{ ++ putchar_f(c); ++} ++ ++void prom_putstr(char *s) ++{ ++ while(*s) { ++ if(*s == '\n') ++ putchar_f('\r'); ++ putchar_f(*s); ++ s++; ++ } ++} ++ ++#if 1 ++static char pbuffer[4096]; ++void prom_printk(const char *fmt, ...) { ++ va_list args; ++ ++ va_start(args, fmt); ++ vsnprintf(pbuffer, 4096, fmt, args); ++ va_end(args); ++ ++ prom_putstr(pbuffer); ++} ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_setup.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_setup.c.patch new file mode 100644 index 00000000..e52a18e8 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-t40_setup.c.patch @@ -0,0 +1,113 @@ +diff -drupN a/arch/mips/xburst2/soc-t40/setup.c b/arch/mips/xburst2/soc-t40/setup.c +--- a/arch/mips/xburst2/soc-t40/setup.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-t40/setup.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,109 @@ ++/* ++ * Ingenic Soc Setup ++ * ++ * 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) 2006 Ingenic Semiconductor Inc. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++void __init cpm_reset(void) ++{ ++} ++ ++int __init setup_init(void) ++{ ++#if 0 ++ cpm_reset(); ++ /* Set bus priority here */ ++ *(volatile unsigned int *)0xb34f0240 = 0x00010003; ++ *(volatile unsigned int *)0xb34f0244 = 0x00010003; ++#endif ++ ++ return 0; ++} ++extern void __init init_all_clk(void); ++/* used by linux-mti code */ ++extern void *get_fdt_addr(void); ++void __init plat_mem_setup(void) ++{ ++ /* use IO_BASE, so that we can use phy addr on hard manual ++ * directly with in(bwlq)/out(bwlq) in io.h. ++ */ ++ set_io_port_base(IO_BASE); ++ ioport_resource.start = 0x00000000; ++ ioport_resource.end = 0xffffffff; ++ iomem_resource.start = 0x00000000; ++ iomem_resource.end = 0xffffffff; ++ setup_init(); ++ ++ __dt_setup_arch(get_fdt_addr()); ++ ++ return; ++} ++void __init device_tree_init(void) ++{ ++ unflatten_and_copy_device_tree(); ++} ++ ++static int __init plat_of_populate(void) ++{ ++ of_platform_default_populate(NULL, NULL, NULL); ++ return 0; ++} ++arch_initcall(plat_of_populate); ++ ++void __init plat_time_init(void) ++{ ++ of_clk_init(NULL); ++ ++ clocksource_probe(); ++} ++ ++void __init arch_init_irq(void) ++{ ++ irqchip_init(); ++} ++ ++unsigned long ispmem_base = 0; ++EXPORT_SYMBOL(ispmem_base); ++ ++unsigned long ispmem_size = 0; ++EXPORT_SYMBOL(ispmem_size); ++ ++static int __init ispmem_parse(char *str) ++{ ++ char *retptr; ++ ++ ispmem_size = memparse(str, &retptr); ++ if(ispmem_size < 0) { ++ ispmem_size = 0; ++ } ++ ++ if (*retptr == '@') ++ ispmem_base = memparse(retptr + 1, NULL); ++ ++ if(ispmem_base < 0) { ++ printk("## no ispmem! ##\n"); ++ } ++ return 1; ++} ++__setup("ispmem=", ispmem_parse); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_Kconfig.DT.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_Kconfig.DT.patch new file mode 100644 index 00000000..aad127fc --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_Kconfig.DT.patch @@ -0,0 +1,6 @@ +diff -drupN a/arch/mips/xburst2/soc-x2000-v12/Kconfig.DT b/arch/mips/xburst2/soc-x2000-v12/Kconfig.DT +--- a/arch/mips/xburst2/soc-x2000-v12/Kconfig.DT 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-x2000-v12/Kconfig.DT 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,2 @@ ++config DT_X2000_V12_FPGA ++ bool "x2000-v12 fpga" diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_Makefile.patch new file mode 100644 index 00000000..91546cfc --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_Makefile.patch @@ -0,0 +1,11 @@ +diff -drupN a/arch/mips/xburst2/soc-x2000-v12/Makefile b/arch/mips/xburst2/soc-x2000-v12/Makefile +--- a/arch/mips/xburst2/soc-x2000-v12/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-x2000-v12/Makefile 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,7 @@ ++obj-y += setup.o ++obj-y += serial.o ++ ++obj-y += pm.o ++obj-y += regs_save_restore.o ++obj-y += libdmmu.o ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_cpu-feature-overrides.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_cpu-feature-overrides.h.patch new file mode 100644 index 00000000..0db3b140 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_cpu-feature-overrides.h.patch @@ -0,0 +1,70 @@ +diff -drupN a/arch/mips/xburst2/soc-x2000-v12/include/cpu-feature-overrides.h b/arch/mips/xburst2/soc-x2000-v12/include/cpu-feature-overrides.h +--- a/arch/mips/xburst2/soc-x2000-v12/include/cpu-feature-overrides.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-x2000-v12/include/cpu-feature-overrides.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,66 @@ ++/* ++ * Copyright (C) 2008 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * 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. ++ */ ++ ++#ifndef __ASM_MACH_INGENIC_CPU_FEATURE_OVERRIDES_H__ ++#define __ASM_MACH_INGENIC_CPU_FEATURE_OVERRIDES_H__ ++ ++ ++#define cpu_dcache_size() (32 * 1024) ++#define cpu_dcache_ways() 8 ++#define cpu_dcache_line_size() 32 ++#define cpu_icache_size() (32 * 1024) ++#define cpu_icache_ways() 8 ++#define cpu_icache_line_size() 32 ++#define cpu_has_xpa 0 ++#define cpu_has_tlb 1 ++#define cpu_has_tlbinv 1 ++#define cpu_has_4kex 1 ++#define cpu_has_3k_cache 0 ++#define cpu_has_4k_cache 1 ++#define cpu_has_tx39_cache 0 ++#define cpu_has_fpu 1 ++#define cpu_has_32fpr 0 ++#define cpu_has_counter 0 ++#define cpu_has_watch 1 ++#define cpu_has_divec 1 ++#define cpu_has_vce 0 ++#define cpu_has_cache_cdex_p 0 ++#define cpu_has_cache_cdex_s 0 ++#define cpu_has_prefetch 1 ++#define cpu_has_mcheck 1 ++#define cpu_has_ejtag 0 ++#define cpu_has_llsc 1 ++#define kernel_uses_llsc cpu_has_llsc ++#define cpu_has_mips16 0 ++#define cpu_has_mdmx 0 ++#define cpu_has_mips3d 0 ++#define cpu_has_smartmips 0 ++#define cpu_has_vtag_icache 0 ++#define cpu_has_dc_aliases 0 ++#define cpu_has_ic_fills_f_dc 0 ++#define cpu_has_pindexed_dcache 0 ++#define cpu_icache_snoops_remote_store 0 ++#define cpu_has_mips32r1 0 ++#define cpu_has_mips32r2 1 ++#define cpu_has_mips64r1 0 ++#define cpu_has_mips64r2 0 ++#define cpu_has_dsp 0 ++#define cpu_has_mipsmt 0 ++#define cpu_has_userlocal 1 ++#define cpu_has_rixi 1 ++#define cpu_has_nofpuex 0 ++#define cpu_has_64bits 0 ++#define cpu_has_64bit_zero_reg 0 ++#define cpu_has_vint 0 ++#define cpu_has_veic 0 ++#define cpu_has_inclusive_pcaches 0 ++#define kernel_uses_smartmips_rixi 0 ++#define cpu_has_mxu 0 ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_irq.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_irq.h.patch new file mode 100644 index 00000000..3e35dcbb --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_irq.h.patch @@ -0,0 +1,43 @@ +diff -drupN a/arch/mips/xburst2/soc-x2000-v12/include/irq.h b/arch/mips/xburst2/soc-x2000-v12/include/irq.h +--- a/arch/mips/xburst2/soc-x2000-v12/include/irq.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-x2000-v12/include/irq.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,39 @@ ++/* ++ * Copyright (C) 2010 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * 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. ++ */ ++ ++#ifndef __ASM_MACH_INGENIC_IRQ_H__ ++#define __ASM_MACH_INGENIC_IRQ_H__ ++#include ++#include ++ ++enum { ++#define GPIO_NR_IRQS (32 * 5 + 16) ++ IRQ_GPIO_BASE = (IRQ_INTC_END + 1), ++ IRQ_GPIO_END = IRQ_GPIO_BASE + GPIO_NR_IRQS - 1, ++ ++#define TCU_NR_IRQS (8) ++ IRQ_TCU_BASE, ++ IRQ_TCU_END = IRQ_TCU_BASE + TCU_NR_IRQS - 1, ++ ++#define MCU_NR_IRQS (5) ++ IRQ_MCU_BASE, ++ IRQ_MCU_END = IRQ_MCU_BASE + MCU_NR_IRQS - 1, ++ ++#define RESERVED_NR_IRQS (150) ++ IRQ_RESERVED_BASE, ++ IRQ_RESERVED_END = IRQ_RESERVED_BASE + RESERVED_NR_IRQS - 1, ++ ++ NR_IRQS, ++ ++ ++ ++}; ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_libdmmu.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_libdmmu.h.patch new file mode 100644 index 00000000..c90dc823 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_libdmmu.h.patch @@ -0,0 +1,18 @@ +diff -drupN a/arch/mips/xburst2/soc-x2000-v12/include/libdmmu.h b/arch/mips/xburst2/soc-x2000-v12/include/libdmmu.h +--- a/arch/mips/xburst2/soc-x2000-v12/include/libdmmu.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-x2000-v12/include/libdmmu.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,14 @@ ++#ifndef _LIBDMMU_ ++#define _LIBDMMU_ ++ ++#include ++ ++unsigned long dmmu_map(struct device *dev,unsigned long vaddr,unsigned long len); ++int dmmu_flush_cache(unsigned long vaddr, unsigned long len); ++int dmmu_unmap(struct device *dev,unsigned long vaddr, int len); ++int dmmu_unmap_all(struct device *dev); ++void dmmu_dump_vaddr(unsigned long vaddr); ++int dmmu_memory_smash(unsigned long vaddr, int smash_mode); ++int dmmu_dump_map(unsigned long vaddr); ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_soc_base.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_soc_base.h.patch new file mode 100644 index 00000000..7fb98008 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_soc_base.h.patch @@ -0,0 +1,81 @@ +diff -drupN a/arch/mips/xburst2/soc-x2000-v12/include/soc/base.h b/arch/mips/xburst2/soc-x2000-v12/include/soc/base.h +--- a/arch/mips/xburst2/soc-x2000-v12/include/soc/base.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-x2000-v12/include/soc/base.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,77 @@ ++ ++#ifndef __JZSOC_SOC_DEV_H__ ++#define __JZSOC_SOC_DEV_H__ ++ ++/* ++ * Define the module base addresses ++ */ ++ ++/* AHB0 BUS Devices Base */ ++#define HARB0_IOBASE 0x13000000 /* 64KB, AHB Bus Aribtier */ ++#define DDR_PHY_IOBASE 0x13011000 /* 4KB, DDR PHY */ ++#define DDRC_H0_IOBASE 0x13012000 /* 4KB, DDR Controller Registers@ASHB0 */ ++#define DPU_IOBASE 0x13050000 /* 64KB, LCD Controller */ ++#define CIM_IOBASE 0x13060000 /* 64KB, Camera Interface Module */ ++#define ROTATE_IOBASE 0x13070000 /* 64KB, Rotate DMA */ ++#define JPEG_IOBASE 0x130d0000 /* 64KB, VPU-JPEG */ ++ ++ ++/* AHB2 Bus Devices Base */ ++#define HARB2_IOBASE 0x13400000 /* 64KB, AHB Bus Arbiter */ ++#define NEMC_IOBASE 0x13410000 /* 64KB, External Normal Memory/Boot ROM/OTP Controller */ ++#define PDMA_IOBASE 0x13420000 /* 64KB, Programmable DMA Controller */ ++#define AES_IOBASE 0x13430000 /* 64KB, AES */ ++#define SFC_IOBASE 0x13440000 /* 64KB, SPI Flash Controller */ ++#define MSC0_IOBASE 0x13450000 /* 64KB, MMC SD Controller0 */ ++#define MSC1_IOBASE 0x13460000 /* 64KB, MMC SD Controller1 */ ++#define HASH_IOBASE 0x13470000 /* 64KB, HASH */ ++#define MAC_IOBASE 0x134b0000 /* 64KB, GMAC/MAC */ ++#define PWM_IOBASE 0x134c0000 /* 64KB, PWM */ ++#define DDRC_H2_IOBASE 0x134f0000 /* 4KB, DDR Controller Register @AHB2 */ ++#define AUDIO_IOBASE 0x134e0000 /* 64KB, Aduio System */ ++#define OTG_IOBASE 0x13500000 /* 256KB, OTG2.0 Controller */ ++#define EFUSE_IOBASE 0x13540000 /* 64KB, EFUSE */ ++//#define INTC_IOBASE 0x135f0000 /* Interrupt Controller */ /* TODO: to be fix */ ++ ++ ++/* APB BUS Devices Base */ ++#define CPM_IOBASE 0x10000000 /* 4KB, Clocks and Power Manager */ ++#define TCU_IOBASE 0x10002000 /* 4KB, Timer/Count Unit,OperatingSystemTimer,Watchdog Timer */ ++#define WDT_IOBASE TCU_IOBASE /* 4KB, Timer/Count Unit,OperatingSystemTimer,Watchdog Timer */ ++ ++#define RTC_IOBASE 0x10003000 /* 4KB, Real-Time Clock */ ++#define GPIO_IOBASE 0x10010000 /* 4KB, General-Purpose I/O */ ++#define UART0_IOBASE 0x10030000 /* 4KB, UART0 Controller */ ++#define UART1_IOBASE 0x10031000 /* 4KB, UART1 Controller */ ++#define UART2_IOBASE 0x10032000 /* 4KB, UART2 Controller */ ++#define UART3_IOBASE 0x10033000 /* 4KB, UART3 Controller */ ++#define UART4_IOBASE 0x10034000 /* 4KB, UART4 Controller */ ++#define UART5_IOBASE 0x10035000 /* 4KB, UART4 Controller */ ++#define SCC_IOBASE 0x10040000 /* 4KB, Smart Card Controller */ ++#define SSI0_IOBASE 0x10043000 /* 4KB, Synchronous Serial Interface */ ++#define SSI1_IOBASE 0x10044000 /* 4KB, Synchronous Serial Interface */ ++#define I2C0_IOBASE 0x10050000 /* 4KB, I2C 0 Bus Interface */ ++#define I2C1_IOBASE 0x10051000 /* 4KB, I2C 1 Bus Interface */ ++#define I2C2_IOBASE 0x10052000 /* 4KB, I2C 2 Bus Interface */ ++#define I2C3_IOBASE 0x10053000 /* 4KB, I2C 3 Bus Interface */ ++#define I2C4_IOBASE 0x10054000 /* 4KB, I2C 4 Bus Interface */ ++#define I2C5_IOBASE 0x10055000 /* 4KB, I2C 5 Bus Interface */ ++ ++ ++ ++/* TODO: Others To Be add */ ++/* NAND CHIP Base Address */ ++#define NEMC_CS1_IOBASE 0X1b000000 ++#define NEMC_CS2_IOBASE 0X1a000000 ++#define NEMC_CS3_IOBASE 0X19000000 ++#define NEMC_CS4_IOBASE 0X18000000 ++#define NEMC_CS5_IOBASE 0X17000000 ++#define NEMC_CS6_IOBASE 0X16000000 ++ ++ ++#define OST_IOBASE 0x12000000 ++#define TCU_IOBASE 0x10002000 ++ ++#define DDRC_BASE 0xb34f0000 ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_soc_cache.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_soc_cache.h.patch new file mode 100644 index 00000000..0d726d03 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_soc_cache.h.patch @@ -0,0 +1,32 @@ +diff -drupN a/arch/mips/xburst2/soc-x2000-v12/include/soc/cache.h b/arch/mips/xburst2/soc-x2000-v12/include/soc/cache.h +--- a/arch/mips/xburst2/soc-x2000-v12/include/soc/cache.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-x2000-v12/include/soc/cache.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,28 @@ ++#ifndef __CHIP_CACHE_H__ ++#define __CHIP_CACHE_H__ ++#include ++#include ++ ++#define Index_Prefetch_I 0x1c ++ ++ ++#define cache_prefetch(label,size) \ ++do{ \ ++ unsigned long addr,end; \ ++ /* Prefetch codes from label */ \ ++ addr = (unsigned long)(&&label) & ~(32 - 1); \ ++ end = (unsigned long)(&&label + size) & ~(32 - 1); \ ++ end += 32; \ ++ for (; addr < end; addr += 32) { \ ++ __asm__ volatile ( \ ++ ".set push \n\t" \ ++ ".set mips32 \n\t" \ ++ " cache %0, 0(%1)\n\t" \ ++ ".set pop \n\t" \ ++ : \ ++ : "I" (Index_Prefetch_I), "r"(addr)); \ ++ } \ ++} \ ++while(0) ++ ++#endif /* __CHIP_CACHE_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_soc_cpm.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_soc_cpm.h.patch new file mode 100644 index 00000000..5ac32e6c --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_soc_cpm.h.patch @@ -0,0 +1,135 @@ +diff -drupN a/arch/mips/xburst2/soc-x2000-v12/include/soc/cpm.h b/arch/mips/xburst2/soc-x2000-v12/include/soc/cpm.h +--- a/arch/mips/xburst2/soc-x2000-v12/include/soc/cpm.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-x2000-v12/include/soc/cpm.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,131 @@ ++/* ++ * SOC CPM register definition. ++ * ++ * CPM (Clock reset and Power control Management) ++ * ++ * Copyright (C) 2010 Ingenic Semiconductor Co., Ltd. ++ */ ++ ++#ifndef __SOC_CPM_H__ ++#define __SOC_CPM_H__ ++ ++#define CPM_CPCCR (0x00) ++#define CPM_CPCSR (0xD4) ++ ++#define CPM_DDRCDR (0x2c) ++#define CPM_MACCDR (0x54) ++#define CPM_MACTXCDR (0x58) ++#define CPM_MACTXCDR1 (0xdc) ++#define CPM_I2S0CDR (0x60) ++#define CPM_I2S1CDR (0x7c) ++#define CPM_I2S2CDR (0x84) ++#define CPM_I2S3CDR (0x8c) ++#define CPM_I2S0CDR1 (0x70) ++#define CPM_I2S1CDR1 (0x80) ++#define CPM_I2S2CDR1 (0x88) ++#define CPM_I2S3CDR1 (0xa0) ++#define CPM_AUDIOCR (0xac) ++#define CPM_LPCDR (0x64) ++#define CPM_MSC0CDR (0x68) ++#define CPM_MSC1CDR (0xa4) ++#define CPM_MSC2CDR (0xa8) ++#define CPM_SFCCDR (0x74) ++#define CPM_SSICDR (0x5c) ++#define CPM_CIMCDR (0x78) ++#define CPM_PWMCDR (0x6c) ++#define CPM_ISPCDR (0x30) ++#define CPM_RSACDR (0x50) ++ ++#define CPM_INTR (0xB0) ++#define CPM_INTRE (0xB4) ++#define CPM_SFTINT (0xBC) ++#define CPM_DRCG (0xD0) ++#define CPM_CPPSR (0x34) ++#define CPM_CPSPPR (0x38) ++#define CPM_USBPCR (0x3C) ++#define CPM_USBRDT (0x40) ++#define CPM_USBVBFIL (0x44) ++#define CPM_USBPCR1 (0x48) ++ ++#define CPM_CPPCR (0x0C) ++#define CPM_CPAPCR (0x10) ++#define CPM_CPMPCR (0x14) ++#define CPM_CPEPCR (0x18) ++ ++#define CPM_LCR (0x04) ++#define CPM_PSWC0ST (0x90) ++#define CPM_PSWC1ST (0x94) ++#define CPM_PSWC2ST (0x98) ++#define CPM_PSWC3ST (0x9C) ++#define CPM_CLKGR (0x20) ++#define CPM_CLKGR1 (0x28) ++#define CPM_MESTSEL (0xEC) ++#define CPM_SRBC (0xC4) ++#define CPM_EXCLK_DS (0xE0) ++#define CPM_MPDCR (0xF8) ++#define CPM_MPDCR1 (0xFC) ++#define CPM_SLBC (0xC8) ++#define CPM_SLPC (0xCC) ++#define CPM_OPCR (0x24) ++ ++#ifndef BIT ++#define BIT(nr) (1UL << nr) ++#endif ++ ++/*USB Parameter Control Register*/ ++#define USBPCR_USB_MODE BIT(31) ++#define USBPCR_AVLD_REG BIT(30) ++#define USBPCR_IDPULLUP_MASK_BIT 28 ++#define USBPCR_IDPULLUP_MASK (0x3 << USBPCR_IDPULLUP_MASK_BIT) ++#define USBPCR_IDPULLUP_OTG (0x0 << USBPCR_IDPULLUP_MASK_BIT) ++#define USBPCR_IDPULLUP_ALWAYS_SUSPEND (0x1 << USBPCR_IDPULLUP_MASK_BIT) ++#define USBPCR_IDPULLUP_ALWAYS (0x2 << USBPCR_IDPULLUP_MASK_BIT) ++#define USBPCR_INCR_MASK BIT(27) ++#define USBPCR_POR_BIT 22 ++#define USBPCR_POR BIT(USBPCR_POR_BIT) ++ ++/*USB Reset Detect Timer Register*/ ++#define USBRDT_RESUME_INTEEN BIT(31) /*RW*/ ++#define USBRDT_RESUME_INTERCLR BIT(30) /*W0*/ ++#define USBRDT_RESUME_SPEED_BIT 28 /*RW*/ ++#define USBRDT_RESUME_SPEED_MSK (0x3 << RESUME_SPEED_BIT) ++#define USBRDT_RESUME_SPEED_HIGH (0x0 << RESUME_SPEED_BIT) ++#define USBRDT_RESUME_SPEED_FULL (0x1 << RESUME_SPEED_BIT) ++#define USBRDT_RESUME_SPEED_LOW (0x2 << RESUME_SPEED_BIT) ++#define USBRDT_RESUME_STATUS 27 /*RO*/ ++#define USBRDT_HB_MASK BIT(26) ++#define USBRDT_VBFIL_LD_EN BIT(25) ++#define USBRDT_IDDIG_EN 24 ++#define USBRDT_IDDIG_REG 23 ++#define USBRDT_USBRDT_MSK (0x7fffff) ++#define USBRDT_USBRDT(x) ((x) & USBRDT_USBRDT_MSK) ++ ++/*USB VBUS Jitter Filter Register*/ ++#define USBVBFIL_USBVBFIL(x) ((x) & 0xffff) ++#define USBVBFIL_IDDIGFIL(x) ((x) & (0xffff << 16)) ++ ++/*USB Parameter Control Register1*/ ++#define USBPCR1_BVLD_REG BIT(31) ++#define USBPCR1_DPPULLDOWN BIT(29) ++#define USBPCR1_DMPULLDOWN BIT(28) ++#define USBPCR1_PORT_RST BIT(21) ++ ++/*Oscillator and Power Control Register*/ ++#define OPCR_USB_SPENDN BIT(7) ++ ++ ++#define LCR_LPM_MASK (0x3) ++#define LCR_LPM_SLEEP (0x1) ++ ++#define OPCR_ERCS (0x1<<2) ++#define OPCR_PD (0x1<<3) ++#define OPCR_IDLE (0x1<<31) ++ ++ ++#define cpm_inl(off) inl(CPM_IOBASE + (off)) ++#define cpm_outl(val,off) outl(val,CPM_IOBASE + (off)) ++#define cpm_clear_bit(val,off) do{cpm_outl((cpm_inl(off) & ~(1<<(val))),off);}while(0) ++#define cpm_set_bit(val,off) do{cpm_outl((cpm_inl(off) | (1< ++ ++/* ++ * DDR Controller Registers ++ **/ ++#define DDR_MEM_PHY_BASE 0x20000000 ++ ++#define DDRC_STATUS 0x0 ++#define DDRC_CFG 0x8 ++#define DDRC_CTRL 0x10 ++#define DDRC_LMR 0x18 ++#define DDRC_DLP 0x20 ++#define DDRC_AUTOSR_EN 0x28 ++#define DDRC_AUTOSR_CNT 0x30 ++#define DDRC_REFCNT 0x38 ++#define DDRC_DBGINFO 0xE8 ++#define DDRC_TIMING(n) (0x40 + 8 * (n - 1)) ++#define DDRC_MMAP0 0x78 ++#define DDRC_MMAP1 0x80 ++#define DDRC_HREGPRO 0xd8 ++#define DDRC_DWCFG (DDRC_APB_OFFSET + 0x00) ++#define DDRC_DWSTATUS (DDRC_APB_OFFSET + 0x04) ++#define DDRC_REMAP(n) (DDRC_APB_OFFSET + 0x08 + 4 * (n - 1)) ++#define DDRC_CGUC0 (DDRC_APB_OFFSET + 0x64) ++#define DDRC_CGUC1 (DDRC_APB_OFFSET + 0x68) ++#define DDRC_PREGPRO (DDRC_APB_OFFSET + 0x6c) ++ ++/* ++ * DDR Innophy registers ++ * */ ++#define DDRP_INNOPHY_PHY_RST (DDR_PHY_OFFSET + 0x000) ++#define DDRP_INNOPHY_MEM_CFG (DDR_PHY_OFFSET + 0x004) ++#define DDRP_INNOPHY_DQ_WIDTH (DDR_PHY_OFFSET + 0x07c) ++#define DDRP_INNOPHY_CL (DDR_PHY_OFFSET + 0x014) ++#define DDRP_INNOPHY_CWL (DDR_PHY_OFFSET + 0x01c) ++#define DDRP_INNOPHY_AL (DDR_PHY_OFFSET + 0x018) ++#define DDRP_INNOPHY_PLL_FBDIV (DDR_PHY_OFFSET + 0x080) ++#define DDRP_INNOPHY_PLL_CTRL (DDR_PHY_OFFSET + 0x084) ++#define DDRP_INNOPHY_PLL_PDIV (DDR_PHY_OFFSET + 0x088) ++#define DDRP_INNOPHY_PLL_LOCK (DDR_PHY_OFFSET + 0xc8) ++#define DDRP_INNOPHY_TRAINING_CTRL (DDR_PHY_OFFSET + 0x008) ++#define DDRP_INNOPHY_CALIB_DONE (DDR_PHY_OFFSET + 0xcc) ++#define DDRP_INNOPHY_CALIB_DELAY_AL (DDR_PHY_OFFSET + 0x190) ++#define DDRP_INNOPHY_CALIB_DELAY_AH (DDR_PHY_OFFSET + 0x194) ++#define DDRP_INNOPHY_CALIB_BYPASS_AL (DDR_PHY_OFFSET + 0x118) ++#define DDRP_INNOPHY_CALIB_BYPASS_AH (DDR_PHY_OFFSET + 0x158) ++#define DDRP_INNOPHY_WL_MODE1 (DDR_PHY_OFFSET + 0x00c) ++#define DDRP_INNOPHY_WL_MODE2 (DDR_PHY_OFFSET + 0x010) ++#define DDRP_INNOPHY_WL_DONE (DDR_PHY_OFFSET + 0x0c0) ++#define DDRP_INNOPHY_INIT_COMP (DDR_PHY_OFFSET + 0x0d0) ++ ++ ++/* ++ * DDRC REGISTER BITS DEFINE ++ * */ ++ ++/* DDRC Status Register */ ++#define DDRC_DSTATUS_MISS (1 << 6) ++#define DDRC_ST_DPDN (1 << 5) /* 0 DDR memory is NOT in deep-power-down state ++ 1 DDR memory is in deep-power-down state */ ++#define DDRC_ST_PDN (1 << 4) /* 0 DDR memory is NOT in power-down state ++ 1 DDR memory is in power-down state */ ++#define DDRC_ST_AREF (1 << 3) /* 0 DDR memory is NOT in auto-refresh state ++ 1 DDR memory is in auto-refresh state */ ++#define DDRC_ST_SREF (1 << 2) /* 0 DDR memory is NOT in self-refresh state ++ 1 DDR memory is in self-refresh state */ ++#define DDRC_ST_CKE1 (1 << 1) /* 0 CKE1 Pin is low ++ 1 CKE1 Pin is high */ ++#define DDRC_ST_CKE0 (1 << 0) /* 0 CKE0 Pin is low ++ 1 CKE0 Pin is high */ ++ ++/* DDRC Configure Register */ ++#define DDRC_CFG_ROW1_BIT 29 /* Row Address width. */ ++#define DDRC_CFG_ROW1_MASK (0x7 << DDRC_CFG_ROW1_BIT) ++#define DDRC_CFG_COL1_BIT 26 /* Row Address width. */ ++#define DDRC_CFG_COL1_MASK (0x7 << DDRC_CFG_COL1_BIT) ++#define DDRC_CFG_BA1 25 /* Bank Address width of DDR memory */ ++#define DDRC_CFG_IMBA (1 << 16) ++#define DDRC_CFG_ROW0_BIT 13 /* Row Address width. */ ++#define DDRC_CFG_ROW0_MASK (0x7 << DDRC_CFG_ROW0_BIT) ++#define DDRC_CFG_COL0_BIT 10 /* Row Address width. */ ++#define DDRC_CFG_COL0_MASK (0x7 << DDRC_CFG_COL1_BIT) ++#define DDRC_CFG_BA0 9 /* Bank Address width of DDR memory */ ++ ++#define DDRC_CFG_TYPE_BIT 3 ++#define DDRC_CFG_TYPE_MASK (0x7 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_DDR1 (2 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_MDDR (3 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_DDR2 (4 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_LPDDR2 (5 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_DDR3 (6 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_LPDDR3 (7 << DDRC_CFG_TYPE_BIT) ++ ++#define DDRC_CFG_ODTEN (1 << 2) /* ODT EN */ ++#define DDRC_CFG_CS1EN (1 << 1) /* DDR Chip-Select-1 Enable */ ++#define DDRC_CFG_CS0EN (1 << 0) /* DDR Chip-Select-0 Enable */ ++ ++/* DDRC Control Register */ ++#define DDRC_CTRL_DFI_RST (1 << 23) ++#define DDRC_CTRL_DLL_RST (1 << 22) ++#define DDRC_CTRL_CTL_RST (1 << 21) ++#define DDRC_CTRL_CFG_RST (1 << 20) ++#define DDRC_CTRL_ACTPD (1 << 15) /* 0 Precharge all banks before entering power-down ++ 1 Do not precharge banks before entering power-down */ ++#define DDRC_CTRL_PDT_BIT 12 /* Power-Down Timer */ ++#define DDRC_CTRL_PDT_MASK (0x7 << DDRC_CTRL_PDT_BIT) ++#define DDRC_CTRL_PDT_DIS (0 << DDRC_CTRL_PDT_BIT) /* power-down disabled */ ++#define DDRC_CTRL_PDT_8 (1 << DDRC_CTRL_PDT_BIT) /* Enter power-down after 8 tCK idle */ ++#define DDRC_CTRL_PDT_16 (2 << DDRC_CTRL_PDT_BIT) /* Enter power-down after 16 tCK idle */ ++#define DDRC_CTRL_PDT_32 (3 << DDRC_CTRL_PDT_BIT) /* Enter power-down after 32 tCK idle */ ++#define DDRC_CTRL_PDT_64 (4 << DDRC_CTRL_PDT_BIT) /* Enter power-down after 64 tCK idle */ ++#define DDRC_CTRL_PDT_128 (5 << DDRC_CTRL_PDT_BIT) /* Enter power-down after 128 tCK idle */ ++ ++#define DDRC_CTRL_PD_CCE (1 << 7) /* Power down clk freq change enable */ ++#define DDRC_CTRL_DPD (1 << 6) /* 1 Drive external MDDR device entering Deep-Power-Down mode */ ++#define DDRC_CTRL_SR (1 << 5) /* 1 Drive external DDR device entering self-refresh mode ++ 0 Drive external DDR device exiting self-refresh mode */ ++#define DDRC_CTRL_SR_CCE (1 << 4) /* Self refresh clk stop request enable */ ++#define DDRC_CTRL_CKE (1 << 1) /* 0 Not set CKE Pin High, 1 Set CKE Pin HIGH */ ++#define DDRC_CTRL_RESET (1 << 0) /* 0 End resetting ddrc_controller, 1 Resetting ddrc_controller */ ++ ++/* DDRC DFI low power handshake control register */ ++#define DDRC_DDLP_TCTLUDP_BIT 24 ++#define DDRC_DDLP_TCTLUDP_FF (0xff << DDRC_DDLP_TCTLUDP_BIT) ++ ++/* DDRC Load-Mode-Register */ ++#define DDRC_LMR_DDR_ADDR_BIT 12 /* When performing a DDR command, DDRC_ADDR[13:0] ++ corresponding to external DDR address Pin A[13:0] */ ++#define DDRC_LMR_DDR_ADDR_MASK (0xfffff << DDRC_LMR_DDR_ADDR_BIT) ++ ++#define DDRC_LMR_MA_BIT 16 /* FOR LPDDR2, MA[9:0] */ ++#define DDRC_LMR_OP_BIT 24 /* FOR LPDDR2, OP[9:0] */ ++ ++#define DDRC_LMR_BA_BIT 9 /* When performing a DDR command, BA[2:0] ++ corresponding to external DDR address Pin BA[2:0]. */ ++#define DDRC_LMR_BA_MASK (0x7 << DDRC_LMR_BA_BIT) ++#define DDRC_LMR_CMD_BIT 6 ++#define DDRC_LMR_CMD_MASK (0x7 << DDRC_LMR_CMD_BIT) ++#define DDRC_LMR_CMD_PREC (0 << DDRC_LMR_CMD_BIT)/* Precharge one bank/All banks */ ++#define DDRC_LMR_CMD_AUREF (1 << DDRC_LMR_CMD_BIT)/* Auto-Refresh */ ++#define DDRC_LMR_CMD_LMR (2 << DDRC_LMR_CMD_BIT)/* Load Mode Register */ ++#define DDRC_LMR_CMD_ZQCL_CS0 (3 << DDRC_LMR_CMD_BIT)/* ZQCL for DDR3 on CS0 */ ++#define DDRC_LMR_CMD_ZQCL_CS1 (4 << DDRC_LMR_CMD_BIT)/* ZQCL for DDR3 on CS1 */ ++#define DDRC_LMR_CMD_ZQCS_CS0 (5 << DDRC_LMR_CMD_BIT)/* ZQCS for DDR3 on CS0 */ ++#define DDRC_LMR_CMD_ZQCS_CS1 (6 << DDRC_LMR_CMD_BIT)/* ZQCS for DDR3 on CS1 */ ++ ++#define DDRC_LMR_TMRD_BIT 1 ++#define DDRC_LMR_TMRD_MASK (0x1f << DDRC_LMR_TMRD_BIT) ++#define DDRC_LMR_START (1 << 0) /* 0 No command is performed ++ 1 On the posedge of START, perform a command ++ defined by CMD field */ ++ ++/* DDRC Auto-Refresh Counter */ ++#define DDRC_REFCNT_REF_EN (1 << 0) /* Enable Refresh Counter */ ++#define DDRC_REFCNT_CLK_DIV_BIT 1 /* Clock Divider for auto-refresh counter. */ ++#define DDRC_REFCNT_CLK_DIV_MASK (0x7 << DDRC_REFCNT_CLKDIV_BIT) ++ ++#define DDRC_REFCNT_PREREF_CNT_BIT 4 ++#define DDRC_REFCNT_PREREF_CNT_MASK (0xf << DDRC_REFCNT_PREREF_CNT_BIT) ++#define DDRC_REFCNT_PREREF_CNT(val) (val << DDRC_REFCNT_PREREF_CNT_BIT) ++#define DDRC_REFCNT_PREREF_CNT_DEFAULT DDRC_REFCNT_PREREF_CNT(8) ++ ++#define DDRC_REFCNT_CNT_BIT 8 /* 8-bit counter */ ++#define DDRC_REFCNT_CNT_MASK (0xff << DDRC_REFCNT_CNT_BIT) ++ ++#define DDRC_REFCNT_CON_BIT 16 /* Constant value used to compare with CNT value. */ ++#define DDRC_REFCNT_CON_MASK (0xff << DDRC_REFCNT_CON_BIT) ++ ++#define DDRC_REFCNT_TRFC_BIT 24 ++#define DDRC_REFCNT_TRFC_MASK (0x3f << DDRC_REFCNT_TRFC_BIT) ++ ++#define DDRC_REFCNT_PREREF_EN_BIT 30 ++#define DDRC_REFCNT_PREREF_EN (1 << DDRC_REFCNT_PREREF_EN_BIT) ++ ++#define DDRC_REFCNT_PBREF_EN_BIT 31 ++#define DDRC_REFCNT_PBREF_EN (1 << DDRC_REFCNT_PBREF_EN_BIT) ++ ++/* DDRC Memory Map Config Register */ ++#define DDRC_MMAP_BASE_BIT 8 /* base address */ ++#define DDRC_MMAP_BASE_MASK (0xff << DDRC_MMAP_BASE_BIT) ++#define DDRC_MMAP_MASK_BIT 0 /* address mask */ ++#define DDRC_MMAP_MASK_MASK (0xff << DDRC_MMAP_MASK_BIT) ++ ++#define DDRC_MMAP0_BASE (0x20 << DDRC_MMAP_BASE_BIT) ++#define DDRC_MMAP1_BASE_64M (0x24 << DDRC_MMAP_BASE_BIT) /*when bank0 is 128M*/ ++#define DDRC_MMAP1_BASE_128M (0x28 << DDRC_MMAP_BASE_BIT) /*when bank0 is 128M*/ ++#define DDRC_MMAP1_BASE_256M (0x30 << DDRC_MMAP_BASE_BIT) /*when bank0 is 128M*/ ++ ++#define DDRC_MMAP_MASK_64_64 (0xfc << DDRC_MMAP_MASK_BIT) /*mask for two 128M SDRAM*/ ++#define DDRC_MMAP_MASK_128_128 (0xf8 << DDRC_MMAP_MASK_BIT) /*mask for two 128M SDRAM*/ ++#define DDRC_MMAP_MASK_256_256 (0xf0 << DDRC_MMAP_MASK_BIT) /*mask for two 128M SDRAM*/ ++ ++/* DDR device data width configure register */ ++#define DDRC_DWCFG_DFI_INIT_START (1 << 3) ++ ++/* DDR device status register */ ++#define DDRC_DWSTATUS_DFI_INIT_COMP (1 << 0) ++ ++/* DDRC AHB Bus Register Protection Register */ ++#define DDRC_HREGPRO_HPRO_EN (1 << 0) ++ ++/* DDRC APB Bus Register Protection Register */ ++#define DDRC_PREGPRO_PPRO_EN (1 << 0) ++ ++ ++/* DDRC clock gate unit configure 0 */ ++#define DDRC_CGU_PORT7 (1 << 28) ++#define DDRC_CGU_PORT6 (1 << 24) ++#define DDRC_CGU_PORT5 (1 << 20) ++#define DDRC_CGU_PORT4 (1 << 16) ++#define DDRC_CGU_PORT3 (1 << 12) ++#define DDRC_CGU_PORT2 (1 << 8) ++#define DDRC_CGU_PORT1 (1 << 4) ++#define DDRC_CGU_PORT0 (1 << 0) ++ ++/* DDRC clock gate unit configure 1 */ ++#define DDRC_CGU_BWM (1 << 8) ++#define DDRC_CGU_PCTRL (1 << 4) ++#define DDRC_CGU_SCH (1 << 1) ++#define DDRC_CGU_PA (1 << 0) ++ ++ ++ ++/* ++ * DDR INNOPHY REGISTER BITS DEFINE ++ * */ ++ ++/* DDRP DQ Width Register */ ++#define DDRP_DQ_WIDTH_DQ_H (1 << 1) ++#define DDRP_DQ_WIDTH_DQ_L (1 << 0) ++ ++/* DDRP Pll Ctrl Register */ ++#define DDRP_PLL_CTRL_PLLPDEN (1 << 1) ++ ++/* DDRP Training Ctrl Register */ ++#define DDRP_TRAINING_CTRL_WL_BP (1 << 3) ++#define DDRP_TRAINING_CTRL_WL_START (1 << 2) ++#define DDRP_TRAINING_CTRL_DSCSE_BP (1 << 1) ++#define DDRP_TRAINING_CTRL_DSACE_START (1 << 0) ++ ++/* DDRP Training Done Register */ ++#define DDRP_CALIB_DONE_HDQCFB (1 << 3) ++#define DDRP_CALIB_DONE_LDQCFB (1 << 2) ++#define DDRP_CALIB_DONE_HDQCFA (1 << 1) ++#define DDRP_CALIB_DONE_LDQCFA (1 << 0) ++#define DDRP_CALIB_DONE_HWRLFB (1 << 3) ++#define DDRP_CALIB_DONE_LWRLFB (1 << 2) ++#define DDRP_CALIB_DONE_HWRLFA (1 << 1) ++#define DDRP_CALIB_DONE_LWRLFA (1 << 0) ++ ++/* DDRP CALIB BP Register */ ++#define DDRP_CALIB_BP_CYCLESELBH_BIT 4 ++#define DDRP_CALIB_BP_OPHCSELBH_BIT 3 ++#define DDRP_CALIB_BP_DLLSELBH_BIT 0 ++ ++/* DDRP Init Complete Register */ ++#define DDRP_INIT_COMP (1 << 0) ++ ++#define DDRP_PLL_LOCK (1 << 3) ++ ++#define REG32(addr) *(volatile unsigned int *)(addr) ++ ++#define ddr_writel(value, reg) (REG32(DDRC_BASE + reg) = (value)) ++#define ddr_readl(reg) REG32(DDRC_BASE + reg) ++#endif /* __DDR_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_soc_rtc.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_soc_rtc.h.patch new file mode 100644 index 00000000..a08b9e67 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_soc_rtc.h.patch @@ -0,0 +1,100 @@ +diff -drupN a/arch/mips/xburst2/soc-x2000-v12/include/soc/rtc.h b/arch/mips/xburst2/soc-x2000-v12/include/soc/rtc.h +--- a/arch/mips/xburst2/soc-x2000-v12/include/soc/rtc.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-x2000-v12/include/soc/rtc.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,96 @@ ++#ifndef __RTC_H__ ++#define __RTC_H__ ++ ++/* ++ * RTC registers offset address definition ++ */ ++#define RTC_RTCCR (0x00) /* rw, 32, 0x00000081 */ ++#define RTC_RTCSR (0x04) /* rw, 32, 0x???????? */ ++#define RTC_RTCSAR (0x08) /* rw, 32, 0x???????? */ ++#define RTC_RTCGR (0x0c) /* rw, 32, 0x0??????? */ ++ ++#define RTC_HCR (0x20) /* rw, 32, 0x00000000 */ ++#define RTC_HWFCR (0x24) /* rw, 32, 0x0000???0 */ ++#define RTC_HRCR (0x28) /* rw, 32, 0x00000??0 */ ++#define RTC_HWCR (0x2c) /* rw, 32, 0x00000008 */ ++#define RTC_HWRSR (0x30) /* rw, 32, 0x00000000 */ ++#define RTC_HSPR (0x34) /* rw, 32, 0x???????? */ ++#define RTC_WENR (0x3c) /* rw, 32, 0x00000000 */ ++#define RTC_WKUPPINCR (0x48) /* rw, 32, 0x00050064*/ ++ ++/* ++ * RTC registers common define ++ */ ++ ++/* RTC control register(RTCCR) */ ++#define RTCCR_WRDY BIT(7) ++#define RTCCR_1HZ BIT(6) ++#define RTCCR_1HZIE BIT(5) ++#define RTCCR_AF BIT(4) ++#define RTCCR_AIE BIT(3) ++#define RTCCR_AE BIT(2) ++#define RTCCR_SELEXC BIT(1) ++#define RTCCR_RTCE BIT(0) ++ ++ ++/* Generate the bit field mask from msb to lsb */ ++#define BITS_H2L(msb, lsb) ((0xFFFFFFFF >> (32-((msb)-(lsb)+1))) << (lsb)) ++ ++/* RTC regulator register(RTCGR) */ ++#define RTCGR_LOCK BIT(31) ++#define RTCGR_ADJC_LSB 16 ++#define RTCGR_ADJC_MASK BITS_H2L(25, RTCGR_ADJC_LSB) ++#define RTCGR_NC1HZ_LSB 0 ++#define RTCGR_NC1HZ_MASK BITS_H2L(15, RTCGR_NC1HZ_LSB) ++ ++/* Hibernate control register(HCR) */ ++#define HCR_PD BIT(0) ++ ++/* Hibernate wakeup filter counter register(HWFCR) */ ++#define HWFCR_LSB 5 ++#define HWFCR_MASK BITS_H2L(15, HWFCR_LSB) ++#define HWFCR_WAIT_TIME(ms, clk) (((ms)*(clk)/1000+0xf) > HWFCR_MASK ? HWFCR_MASK : ((ms)*(clk)/1000+0xf) & HWFCR_MASK) ++ ++/* Hibernate reset counter register(HRCR) */ ++#define HRCR_LSB 11 ++#define HRCR_MASK BITS_H2L(14, HRCR_LSB) ++#define HRCR_WAIT_TIME(ms, clk) (((ms)*(clk)/1000 + 0x3ff - 0x800) > HRCR_MASK ? HRCR_MASK : \ ++ ((ms)*(clk)/1000 + 0x3ff - 0x800) & HRCR_MASK) ++ ++ ++/* Hibernate wakeup control register(HWCR) */ ++/* Power detect default value; this value means enable */ ++#define EPDET_LSB 3 ++#define EPDET_DEFAULT (0x5aa5a5a << EPDET_LSB) ++#define EPDET_ENABLE (0x5aa5a5a << EPDET_LSB) ++#define EPDET_DISABLE (0x1a55a5a5 << EPDET_LSB) ++#define HWCR_EALM BIT(0) ++ ++ ++/* Hibernate wakeup status register(HWRSR) */ ++#define HWRSR_APD BIT(8) ++#define HWRSR_HR BIT(5) ++#define HWRSR_PPR BIT(4) ++#define HWRSR_PIN BIT(1) ++#define HWRSR_ALM BIT(0) ++ ++/* write enable pattern register(WENR) */ ++#define WENR_WEN BIT(31) ++#define WENR_WENPAT_LSB 0 ++#define WENR_WENPAT_MASK BITS_H2L(15, WENR_WENPAT_LSB) ++#define WENR_WENPAT_WRITABLE (0xa55a) ++ ++/* Hibernate scratch pattern register(HSPR) */ ++#define HSPR_RTCV 0x52544356 /* The value is 'RTCV', means rtc is valid */ ++ ++/*WKUP_PIN_RST control register (WKUPPINCR)*/ ++#define WKUPPINCR_BIAS_CTRL (0x1 << 16) /* fix value*/ ++#define WKUPPINCR_OSC_EN BIT(18) ++#define WKUPPINCR_P_JUD_LEN_LSB 4 ++#define WKUPPINCR_P_JUD_LEN_MASK BITS_H2L(7, WKUPPINCR_P_JUD_LEN_LSB) ++#define WKUPPINCR_P_JUD_LEN(s) ((s) << WKUPPINCR_P_JUD_LEN_LSB) > WKUPPINCR_P_JUD_LEN_MASK ? \ ++ WKUPPINCR_P_JUD_LEN_MASK : (s) << WKUPPINCR_P_JUD_LEN_LSB ++#define WKUPPINCR_P_JUD_EN (0x4) ++/* The divider is decided by the RTC clock frequency. */ ++#define RTC_FREQ_DIVIDER (32768 - 1) ++#endif /* __RTC_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_soc_sfc.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_soc_sfc.h.patch new file mode 100644 index 00000000..08852f0b --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_soc_sfc.h.patch @@ -0,0 +1,215 @@ +diff -drupN a/arch/mips/xburst2/soc-x2000-v12/include/soc/sfc.h b/arch/mips/xburst2/soc-x2000-v12/include/soc/sfc.h +--- a/arch/mips/xburst2/soc-x2000-v12/include/soc/sfc.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-x2000-v12/include/soc/sfc.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,211 @@ ++#ifndef __SFC_REGISTER_H ++#define __SFC_REGISTER_H ++ ++/* SFC register */ ++ ++#define SFC_GLB0 (0x0000) ++#define SFC_DEV_CONF (0x0004) ++#define SFC_DEV_STA_EXP (0x0008) ++#define SFC_DEV0_STA_RT (0x000c) ++#define SFC_DEV_STA_MSK (0x0010) ++#define SFC_TRAN_CONF0(n) (0x0014 + (n * 4)) ++#define SFC_TRAN_LEN (0x002c) ++#define SFC_DEV_ADDR(n) (0x0030 + (n * 4)) ++#define SFC_DEV_ADDR_PLUS(n) (0x0048 + (n * 4)) ++#define SFC_MEM_ADDR (0x0060) ++#define SFC_TRIG (0x0064) ++#define SFC_SR (0x0068) ++#define SFC_SCR (0x006c) ++#define SFC_INTC (0x0070) ++#define SFC_FSM (0x0074) ++#define SFC_CGE (0x0078) ++#define SFC_CMD_IDX (0x007c) ++#define SFC_COL_ADDR (0x0080) ++#define SFC_ROW_ADDR (0x0084) ++#define SFC_STA_ADDR0 (0x0088) ++#define SFC_STA_ADDR1 (0x008c) ++#define SFC_DES_ADDR (0x0090) ++#define SFC_GLB1 (0x0094) ++#define SFC_DEV1_STA_RT (0x0098) ++#define SFC_TRAN_CONF1(n) (0x009c + (n * 4)) ++#define SFC_CDT (0x0800) //0x800 ~ 0xbff ++#define SFC_RM_DR (0x1000) ++ ++/* For SFC_GLB0 */ ++#define GLB0_POLL_TIME_OFFSET (16) ++#define GLB0_POLL_TIME_MSK (0xffff << GLB0_POLL_TIME_OFFSET) ++#define GLB0_DES_EN (1 << 15) ++#define GLB0_CDT_EN (1 << 14) ++#define GLB0_TRAN_DIR (1 << 13) ++#define GLB0_TRAN_DIR_WRITE (1) ++#define GLB0_TRAN_DIR_READ (0) ++#define GLB0_THRESHOLD_OFFSET (7) ++#define GLB0_THRESHOLD_MSK (0x3f << GLB0_THRESHOLD_OFFSET) ++#define GLB0_OP_MODE (1 << 6) ++#define GLB0_OP_OFFSET (6) ++#define SLAVE_MODE (0x0) ++#define DMA_MODE (0x1) ++#define GLB0_PHASE_NUM_OFFSET (3) ++#define GLB0_PHASE_NUM_MSK (0x7 << GLB0_PHASE_NUM_OFFSET) ++#define GLB0_WP_EN (1 << 2) ++#define GLB0_BURST_MD_OFFSET (0) ++#define GLB0_BURST_MD_MSK (0x3 << GLB0_BURST_MD_OFFSET) ++ ++/* For SFC_DEV_CONF */ ++#define DEV_CONF_STA_ENDIAN_OFFSET (31) ++#define STA_ENDIAN_LSB (0) ++#define STA_ENDIAN_MSB (1) ++#define DEV_CONF_SMP_DELAY_OFFSET (16) ++#define DEV_CONF_SMP_DELAY_MSK (0x1f << DEV_CONF_SMP_DELAY_OFFSET) ++#define DEV_CONF_SMP_DELAY_0 (0) ++#define DEV_CONF_SMP_DELAY_45 (1) ++#define DEV_CONF_SMP_DELAY_90 (2) ++#define DEV_CONF_SMP_DELAY_135 (3) ++#define DEV_CONF_SMP_DELAY_180 (4) ++#define DEV_CONF_SMP_DELAY_225 (5) ++#define DEV_CONF_SMP_DELAY_270 (6) ++#define DEV_CONF_SMP_DELAY_315 (7) ++#define DEV_CONF_SMP_DELAY_1 (8) ++#define DEV_CONF_SMP_DELAY_2 (16) ++#define DEV_CONF_CMD_TYPE (0x1 << 15) ++#define DEV_CONF_STA_TYPE_OFFSET (13) ++#define DEV_CONF_STA_TYPE_MSK (0x3 << DEV_CONF_STA_TYPE_OFFSET) ++#define DEV_CONF_THOLD_OFFSET (11) ++#define DEV_CONF_THOLD_MSK (0x3 << DEV_CONF_THOLD_OFFSET) ++#define DEV_CONF_TSETUP_OFFSET (9) ++#define DEV_CONF_TSETUP_MSK (0x3 << DEV_CONF_TSETUP_OFFSET) ++#define DEV_CONF_TSH_OFFSET (5) ++#define DEV_CONF_TSH_MSK (0xf << DEV_CONF_TSH_OFFSET) ++#define DEV_CONF_CPHA (0x1 << 4) ++#define DEV_CONF_CPOL (0x1 << 3) ++#define DEV_CONF_CEDL (0x1 << 2) ++#define DEV_CONF_HOLDDL (0x1 << 1) ++#define DEV_CONF_WPDL (0x1 << 0) ++ ++/* For SFC_TRAN_CONF0 */ ++#define TRAN_CONF0_CLK_MODE (29) ++#define TRAN_CONF0_CLK_MODE_MSK (0x7 << TRAN_CONF0_CLK_MODE) ++#define TRAN_CONF0_CLK_MODE_SSS (0) ++#define TRAN_CONF0_CLK_MODE_SSD (1) ++#define TRAN_CONF0_CLK_MODE_SDS (2) ++#define TRAN_CONF0_CLK_MODE_SDD (3) ++#define TRAN_CONF0_CLK_MODE_DSS (4) ++#define TRAN_CONF0_CLK_MODE_DSD (5) ++#define TRAN_CONF0_CLK_MODE_DDS (6) ++#define TRAN_CONF0_CLK_MODE_DDD (7) ++#define TRAN_CONF0_ADDR_WIDTH_OFFSET (26) ++#define TRAN_CONF0_ADDR_WIDTH_MSK (0x7 << TRAN_CONF0_ADDR_WIDTH_OFFSET) ++#define TRAN_CONF0_POLLEN (1 << 25) ++#define TRAN_CONF0_POLL_OFFSET (25) ++#define TRAN_CONF0_CMDEN (1 << 24) ++#define TRAN_CONF0_FMAT (1 << 23) ++#define TRAN_CONF0_FMAT_OFFSET (23) ++#define TRAN_CONF0_DMYBITS_OFFSET (17) ++#define TRAN_CONF0_DMYBITS_MSK (0x3f << TRAN_CONF0_DMYBITS_OFFSET) ++#define TRAN_CONF0_DATEEN (1 << 16) ++#define TRAN_CONF0_DATEEN_OFFSET (16) ++#define TRAN_CONF0_CMD_OFFSET (0) ++#define TRAN_CONF0_CMD_MSK (0xffff << TRAN_CONF0_CMD_OFFSET) ++ ++/* For SFC_TRAN_CONF1 */ ++#define TRAN_CONF1_DATA_ENDIAN (1 << 18) ++#define TRAN_CONF1_DATA_ENDIAN_OFFSET (18) ++#define TRAN_CONF1_DATA_ENDIAN_LSB (0) ++#define TRAN_CONF1_DATA_ENDIAN_MSB (1) ++#define TRAN_CONF1_WORD_UNIT_OFFSET (16) ++#define TRAN_CONF1_WORD_UNIT_MSK (3 << 16) ++#define TRAN_CONF1_TRAN_MODE_OFFSET (4) ++#define TRAN_CONF1_TRAN_MODE_MSK (0xf << TRAN_CONF1_TRAN_MODE_OFFSET) ++#define TRAN_CONF1_SPI_STANDARD (0x0) ++#define TRAN_CONF1_SPI_DUAL (0x1) ++#define TRAN_CONF1_SPI_QUAD (0x5) ++#define TRAN_CONF1_SPI_IO_QUAD (0x6) ++#define TRAN_CONF1_SPI_OCTAL (0x9) ++#define TRAN_CONF1_SPI_IO_OCTAL (0xa) ++#define TRAN_CONF1_SPI_FULL_OCTAL (0xb) ++ ++ ++/* For SFC_TRIG */ ++#define TRIG_FLUSH (1 << 2) ++#define TRIG_STOP (1 << 1) ++#define TRIG_START (1 << 0) ++ ++/* For SFC_SR */ ++#define SFC_WORKING (1 << 7) ++#define SFC_BUSY (0x3 << 5) ++#define SFC_END (1 << 4) ++#define SFC_TREQ (1 << 3) ++#define SFC_RREQ (1 << 2) ++#define SFC_OVER (1 << 1) ++#define SFC_UNDER (1 << 0) ++ ++/* For SFC_SCR */ ++#define CLR_END (1 << 4) ++#define CLR_TREQ (1 << 3) ++#define CLR_RREQ (1 << 2) ++#define CLR_OVER (1 << 1) ++#define CLR_UNDER (1 << 0) ++ ++//SFC_CMD_IDX ++#define CMD_IDX_MSK (0x3f << 0) ++#define CDT_DATAEN_MSK (0x1 << 31) ++#define CDT_DATAEN_OFF (31) ++#define CDT_DIR_MSK (0x1 << 30) ++#define CDT_DIR_OFF (30) ++ ++/* For SFC_GLB1 */ ++#define GLB1_DQS_EN (1 << 2) ++#define GLB1_CHIP_SEL_OFFSET (0) ++#define GLB1_CHIP_SEL_MSK (0x3 << 0) ++#define GLB1_CHIP_SEL_0 (0) ++#define GLB1_CHIP_SEL_1 (1) ++#define GLB1_CHIP_SEL_01 (2) ++ ++#define N_MAX 6 ++#define MAX_SEGS 128 ++ ++#define CHANNEL_0 0 ++#define CHANNEL_1 1 ++#define CHANNEL_2 2 ++#define CHANNEL_3 3 ++#define CHANNEL_4 4 ++#define CHANNEL_5 5 ++ ++#define ENABLE 1 ++#define DISABLE 0 ++ ++#define COM_CMD 1 // common cmd ++#define POLL_CMD 2 // the cmd will poll the status of flash,ext: read status ++ ++#define DMA_OPS 1 ++#define CPU_OPS 0 ++ ++#define TM_STD_SPI 0 ++#define TM_DI_DO_SPI 1 ++#define TM_DIO_SPI 2 ++#define TM_FULL_DIO_SPI 3 ++#define TM_QI_QO_SPI 5 ++#define TM_QIO_SPI 6 ++#define TM_FULL_QIO_SPI 7 ++#define TM_OCTAL_SPT 9 ++#define TM_OCTAL_IO_SPI 10 ++#define TM_OCTAL_FULL_SPI 11 ++ ++ ++#define DEFAULT_CDT 1 ++#define UPDATE_CDT 2 ++#define DEFAULT_ADDRSIZE 3 ++#define DEFAULT_ADDRMODE 0 ++ ++ ++#define THRESHOLD 32 ++ ++#define SFC_NOR_RATE 110 ++#define DEF_ADDR_LEN 3 ++#define DEF_TCHSH 5 ++#define DEF_TSLCH 5 ++#define DEF_TSHSL_R 20 ++#define DEF_TSHSL_W 50 ++ ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_soc_tcsm_layout.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_soc_tcsm_layout.h.patch new file mode 100644 index 00000000..86fc8b3e --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_soc_tcsm_layout.h.patch @@ -0,0 +1,57 @@ +diff -drupN a/arch/mips/xburst2/soc-x2000-v12/include/soc/tcsm_layout.h b/arch/mips/xburst2/soc-x2000-v12/include/soc/tcsm_layout.h +--- a/arch/mips/xburst2/soc-x2000-v12/include/soc/tcsm_layout.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-x2000-v12/include/soc/tcsm_layout.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,53 @@ ++#ifndef __TCSM_LAYOUT_H__ ++#define __TCSM_LAYOUT_H__ ++ ++/** ++ * |-------------| ++ * | BANK0 | ++ * |-------------| <--- SLEEP_TCSM_BOOTCODE_TEXT ++ * | BOOT CODE | ++ * |-------------| <--- SLEEP_TCSM_RESUMECODE_TEXT ++ * | ... | ++ * | RESUME CODE | ++ * | ... | ++ * |-------------| <--- SLEEP_TCSM_RESUME_DATA ++ * | ... | ++ * | RESUME DATA | ++ * | ... | ++ * |_____________| <--- SLEEP_TCSM_CPU_RESMUE_SP ++ * ++ * ++ * |-------------| ++ * | BANK1 | ++ * |-------------| <--- TO BE DEFINED ++ * | | ++ * | | ++ * | ... | ++ * | VOICE DATA | ++ * | ... | ++ * | | ++ * | | ++ * |_____________| ++ * ++ */ ++ ++#define SLEEP_TCSM_SPACE 0xb3422000 ++#define VOICE_TCSM_DATA_BUF 0xb3423000 ++#define TCSM_BANK_LEN 4096 ++ ++#define SLEEP_TCSM_BOOT_TEXT (SLEEP_TCSM_SPACE) ++#define SLEEP_TCSM_BOOT_LEN 64 ++#define SLEEP_TCSM_BOOT_END (SLEEP_TCSM_BOOT_TEXT + SLEEP_TCSM_BOOT_LEN) ++ ++#define SLEEP_TCSM_RESUME_TEXT (SLEEP_TCSM_BOOT_END) ++#define SLEEP_TCSM_RESUME_LEN 2048 ++#define SLEEP_TCSM_RESUME_END (SLEEP_TCSM_RESUME_TEXT + SLEEP_TCSM_RESUME_LEN) ++ ++#define SLEEP_TCSM_RESUME_DATA (SLEEP_TCSM_RESUME_END) ++ ++#define SLEEP_TCSM_SPACE_END (SLEEP_TCSM_SPACE + TCSM_BANK_LEN) ++ ++#define SLEEP_TCSM_CPU_RESMUE_SP SLEEP_TCSM_SPACE_END - 4 ++ ++ ++#endif /* __TCSM_LAYOUT_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_war.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_war.h.patch new file mode 100644 index 00000000..7578b344 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_include_war.h.patch @@ -0,0 +1,31 @@ +diff -drupN a/arch/mips/xburst2/soc-x2000-v12/include/war.h b/arch/mips/xburst2/soc-x2000-v12/include/war.h +--- a/arch/mips/xburst2/soc-x2000-v12/include/war.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-x2000-v12/include/war.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,27 @@ ++/* ++ * 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) 2002, 2004, 2007 by Ralf Baechle ++ */ ++#ifndef __ASM_MACH_INGENIC_WAR_H__ ++#define __ASM_MACH_INGENIC_WAR_H__ ++ ++#define R4600_V1_INDEX_ICACHEOP_WAR 0 ++#define R4600_V1_HIT_CACHEOP_WAR 0 ++#define R4600_V2_HIT_CACHEOP_WAR 0 ++#define R5432_CP0_INTERRUPT_WAR 0 ++#define BCM1250_M3_WAR 0 ++#define SIBYTE_1956_WAR 0 ++#define MIPS4K_ICACHE_REFILL_WAR 0 ++#define MIPS_CACHE_SYNC_WAR 1 ++#define MIPS_BRIDGE_SYNC_WAR 1 ++#define TX49XX_ICACHE_INDEX_INV_WAR 0 ++#define RM9000_CDEX_SMP_WAR 0 ++#define ICACHE_REFILLS_WORKAROUND_WAR 0 ++#define R10000_LLSC_WAR 0 ++#define MIPS34K_MISSED_ITLB_WAR 0 ++ ++#endif ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_libdmmu.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_libdmmu.c.patch new file mode 100644 index 00000000..6bc46fb5 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_libdmmu.c.patch @@ -0,0 +1,903 @@ +diff -drupN a/arch/mips/xburst2/soc-x2000-v12/libdmmu.c b/arch/mips/xburst2/soc-x2000-v12/libdmmu.c +--- a/arch/mips/xburst2/soc-x2000-v12/libdmmu.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-x2000-v12/libdmmu.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,899 @@ ++/* ++ * This driver is used by VPU driver. ++ * ++ * Copyright (C) 2015 Ingenic Semiconductor Co., Ltd. ++ * http://www.ingenic.com ++ * Author: Yan Zhengting ++ * Modify by: Sun Jiwei ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#define print_dbg(f, arg...) printk(KERN_INFO "dpu: %s, %d: " f "\n", __func__, __LINE__, ## arg) ++ ++#define MAP_COUNT 0x10 ++#define MAP_CONUT_MASK 0xff0 ++ ++#define DMMU_PTE_VLD 0x01 ++#define DMMU_PMD_VLD 0x01 ++ ++#define KSEG0_LOW_LIMIT 0x80000000 ++#define KSEG1_HEIGH_LIMIT 0xC0000000 ++ ++enum mem_break{ ++ MODE1, /* 13 24 57 68 911 1012 ... */ ++ MODE2, /* 13 24 35 46 57 68 79 810 ... */ ++ MODE3 /* 12 34 56 78 ... */ ++}; ++ ++LIST_HEAD(handle_list); ++static unsigned long reserved_pte = 0; ++static unsigned long res_pte_paddr; ++ ++struct pmd_node { ++ unsigned int count; ++ unsigned long index; ++ unsigned long page; ++ struct list_head list; ++}; ++ ++struct map_node { ++ struct device *dev; ++ unsigned long start; ++ unsigned long len; ++ struct list_head list; ++}; ++ ++struct dmmu_handle { ++ pid_t tgid; ++ unsigned long pdg; ++ struct mutex lock; ++ struct list_head list; ++ struct list_head pmd_list; ++ struct list_head map_list; ++}; ++ ++/* for test */ ++static struct dmmu_handle *find_handle(void); ++static struct dmmu_handle *create_handle(void); ++static void dmmu_cache_wback(struct dmmu_handle *h); ++ ++int dmmu_flush_cache(unsigned long vaddr, unsigned long len) ++{ ++ struct list_head *pos, *next; ++ struct dmmu_handle *h = NULL; ++ struct map_node *n = NULL; ++ unsigned long *pgd, *pte_phys, *pte; ++ unsigned long virpage_phy; ++ unsigned long v_end = vaddr+len; ++ int found = 0; ++ int index; ++ ++ h = find_handle(); ++ if(!h){ ++ printk("%s find handle err!\n",__func__); ++ return -1; ++ } ++ if (vaddr & 0xfff) { ++ printk("%s addr align page err!\n",__func__); ++ return -1; ++ } ++ list_for_each_safe(pos, next, &h->map_list) { ++ n = list_entry(pos, struct map_node, list); ++ if((vaddr >= n->start) && ++ ((vaddr+len) <= (n->start + n->len))) { ++ found = 1; ++ break; ++ } ++ } ++ if(!found) { ++ printk("%s addr err!\n",__func__); ++ return -1; ++ } ++ pgd = (unsigned long *)h->pdg; ++ while(vaddr < v_end) { ++ index = vaddr>>22; ++ pte_phys = (unsigned long *)(pgd[index] & ~DMMU_PMD_VLD); ++ pte = (unsigned long *)phys_to_virt((unsigned long)pte_phys); ++ index = ((vaddr & 0x3ff000) >> 12); ++ virpage_phy = pte[index] & ~DMMU_PTE_VLD; ++ dma_cache_wback((unsigned long)phys_to_virt(virpage_phy),PAGE_SIZE); ++ vaddr+=PAGE_SIZE; ++ } ++ return 0; ++} ++ ++static int make_smash_list(struct dmmu_handle *h, unsigned long vaddr, unsigned long (**base)[2], unsigned int *len) ++{ ++ unsigned long *pgd = (unsigned long *)h->pdg; ++ unsigned long (*list_smash)[2] = NULL; ++ unsigned int list_len = 0; ++ unsigned long *pte, *pte_phys; ++ unsigned int i, index; ++ ++ struct list_head *pos, *next; ++ struct map_node *n; ++ ++ list_for_each_safe(pos, next, &h->map_list) { ++ n = list_entry(pos, struct map_node, list); ++ if(vaddr == n->start) { ++ list_len = (n->len) >> 12; ++ break; ++ } ++ } ++ ++ if (list_len) { ++ list_smash = kmalloc(list_len * 2 * 4, GFP_KERNEL); ++ if (list_smash) { ++ i = 0; ++ while(i < list_len) { ++ list_smash[i][0] = (unsigned long)(vaddr & 0xfffff000); ++ ++ index = vaddr>>22; ++ pte_phys = (unsigned long *)(pgd[index] & ~DMMU_PMD_VLD); ++ ++ ++ pte = (unsigned long *)phys_to_virt((unsigned long)pte_phys); ++ ++ index = ((vaddr & 0x3ff000) >> 12); ++// printk(">>>>>>virt = 0x%lx, phys = 0x%lx\n", vaddr, ++// *((unsigned long int *) (((unsigned long)pte_phys+index*4) | 0xa0000000))); ++ list_smash[i][1] = pte[index]; ++ ++ vaddr+=0x1000; ++ i++; ++ } ++ } ++ } ++ ++ if (list_smash) { ++ *base = list_smash; ++ *len = list_len; ++ return 0; ++ } else { ++ return -1; ++ } ++} ++ ++int dmmu_dump_map(unsigned long vaddr) ++{ ++ struct dmmu_handle *h = NULL; ++ unsigned long (*list_smash)[2] = NULL; ++ unsigned int list_len = 0; ++ unsigned long *tmp; ++ ++ h = find_handle(); ++ if(!h) ++ h = create_handle(); ++ if(!h) ++ return -1; ++ /* 检查4k对齐 */ ++ if (vaddr & 0xfff) ++ return -1; ++ ++ mutex_lock(&h->lock); ++ ++ if (make_smash_list(h, vaddr, &list_smash, &list_len)) { ++ mutex_unlock(&h->lock); ++ return -1; ++ } else { ++ unsigned int i; ++ for (i = 0; i phys: 0x%08lx] uncache: 0x%08lx\n", ++ list_smash[i][0],list_smash[i][1],(unsigned long)tmp); ++ ++ printk("value[0] = 0x%08lx, value[1] = 0x%08lx value[2] = 0x%08lx value[1013] = 0x%08lx\n", ++ tmp[0], tmp[1], tmp[2], tmp[1013]); ++ } ++ } ++ ++ mutex_unlock(&h->lock); ++ kfree((void*)list_smash); ++ ++ return 0; ++} ++ ++ /* 13 24 57 68 911 1012 ... */ ++static int smash_mode1(unsigned long (*base)[2], unsigned int len) ++{ ++ unsigned int i; ++ unsigned long tmp; ++ if (len >= 4) { ++ for (i=0; i= 4) { ++ for (i=0; ipdg; ++ unsigned long *pte; ++ unsigned int i, index; ++ ++ for (i=0; i>22; ++ pte = (unsigned long *)(pgd[index] & ~DMMU_PMD_VLD); ++ pte = (unsigned long *)phys_to_virt((unsigned long)pte); ++ ++ index = ((vaddr & 0x3ff000) >> 12); ++ pte[index] = (*base)[i][1]; ++ vaddr+=0x1000; ++ } ++ return 0; ++} ++ ++static int update_process_pte(unsigned long vaddr, unsigned long (**base)[2], unsigned int len) ++{ ++ unsigned int i; ++ pgd_t *pgdir; ++ pmd_t *pmdir; ++ pte_t *pte; ++ spin_lock(¤t->mm->page_table_lock); ++ for (i=0; imm, vaddr); ++ if(pgd_none(*pgdir) || pgd_bad(*pgdir)) ++ return 0; ++ pmdir = pmd_offset((pud_t *)pgdir, vaddr); ++ if(pmd_none(*pmdir) || pmd_bad(*pmdir)) ++ return 0; ++ pte = pte_offset(pmdir,vaddr); ++ if (pte_present(*pte)){ ++ pte->pte = (*base)[i][1]; ++ } ++ vaddr += 4096; ++ } ++ spin_unlock(¤t->mm->page_table_lock); ++ return 0; ++} ++ ++int dmmu_memory_smash(unsigned long vaddr, int smash_mode) ++{ ++ struct dmmu_handle *h = NULL; ++ unsigned long (*list_smash)[2] = NULL; ++ unsigned int list_len = 0; ++ struct vm_area_struct * vma; ++ ++ h = find_handle(); ++ if(!h){ ++ h = create_handle(); ++ } ++ if(!h) ++ return -1; ++ ++ /* 检查4k对齐 */ ++ if (vaddr & 0xfff) ++ return -1; ++ ++ mutex_lock(&h->lock); ++ ++ if (make_smash_list(h, vaddr, &list_smash, &list_len)) { ++ mutex_unlock(&h->lock); ++ return -1; ++ } else { ++ switch (smash_mode) { ++ case MODE1: ++ print_dbg("smash_mode = %u\n",smash_mode); ++ smash_mode1(list_smash, list_len); ++ break; ++ case MODE2: ++ print_dbg("smash_mode = %u\n",smash_mode); ++ smash_mode2(list_smash, list_len); ++ break; ++ case MODE3: ++ print_dbg("smash_mode = %u\n",smash_mode); ++ smash_mode3(list_smash, list_len); ++ break; ++ default: ++ break; ++ } ++ } ++ update_dmmu_pte(h, vaddr, &list_smash, list_len); ++ update_process_pte(vaddr, &list_smash, list_len); ++ ++ dmmu_cache_wback(h); ++ vma = find_vma(current->mm, vaddr); ++ flush_tlb_range(vma, vaddr, vaddr+(list_len*PAGE_SIZE)); ++ ++ mutex_unlock(&h->lock); ++ kfree(list_smash); ++ ++ return 0; ++} ++ ++static struct map_node *check_map(struct dmmu_handle *h,unsigned long vaddr,unsigned long len) ++{ ++ struct list_head *pos, *next; ++ struct map_node *n; ++ list_for_each_safe(pos, next, &h->map_list) { ++ n = list_entry(pos, struct map_node, list); ++ if(vaddr == n->start && len == n->len) ++ return n; ++ } ++ return NULL; ++} ++ ++static void handle_add_map(struct device *dev,struct dmmu_handle *h,unsigned long vaddr,unsigned long len) ++{ ++ struct map_node *n = kmalloc(sizeof(*n),GFP_KERNEL); ++ n->dev = dev; ++ n->start = vaddr; ++ n->len = len; ++ INIT_LIST_HEAD(&n->list); ++ list_add(&n->list,&h->map_list); ++} ++ ++static unsigned int get_pfn(unsigned int vaddr) ++{ ++ pgd_t *pgdir; ++ pmd_t *pmdir; ++ pte_t *pte; ++ pgdir = pgd_offset(current->mm, vaddr); ++ if(pgd_none(*pgdir) || pgd_bad(*pgdir)) ++ return 0; ++ pmdir = pmd_offset((pud_t *)pgdir, vaddr); ++ if(pmd_none(*pmdir) || pmd_bad(*pmdir)) ++ return 0; ++ pte = pte_offset(pmdir,vaddr); ++ if (pte_present(*pte)) { ++ return pte_pfn(*pte) << PAGE_SHIFT; ++ } ++ return 0; ++} ++ ++static unsigned long dmmu_v2pfn(unsigned long vaddr) ++{ ++ if(vaddr < KSEG0_LOW_LIMIT) ++ return get_pfn(vaddr); ++ ++ if(vaddr >= KSEG0_LOW_LIMIT && vaddr < KSEG1_HEIGH_LIMIT) ++ return virt_to_phys((void *)vaddr); ++ ++ panic("dmmu_v2pfn error!"); ++ return 0; ++} ++ ++static unsigned long unmap_node(struct pmd_node *n,unsigned long vaddr,unsigned long end,int check) ++{ ++ unsigned int *pte = (unsigned int *)n->page; ++ int index = ((vaddr & 0x3ff000) >> 12); ++ int free = !check || (--n->count == 0); ++ if(vaddr && end) { ++ while(index < 1024 && vaddr < end) { ++ if(pte[index] & MAP_CONUT_MASK) { ++ pte[index] -= MAP_COUNT; ++ } else { ++ ClearPageReserved(virt_to_page((void *)vaddr)); ++ pte[index] = reserved_pte; ++ } ++ index++; ++ vaddr += 4096; ++ } ++ } ++ ++ if(free) { ++ ClearPageReserved(virt_to_page((void *)n->page)); ++ free_page(n->page); ++ list_del(&n->list); ++ kfree(n); ++ return vaddr+(1024-index)*4096; ++ } ++ ++ return vaddr; ++} ++ ++static unsigned long map_node(struct pmd_node *n,unsigned int vaddr,unsigned int end) ++{ ++ unsigned int *pte = (unsigned int *)n->page; ++ int index = ((vaddr & 0x3ff000) >> 12); ++ ++ while(index < 1024 && vaddr < end) { ++ if(pte[index] == reserved_pte) { ++ SetPageReserved(virt_to_page((void *)vaddr)); ++ pte[index] = dmmu_v2pfn(vaddr) | DMMU_PTE_VLD; ++ // printk(">>>>>vaddr = %d pte = %x, pte[%d] = %x<<<<<<\n\n",vaddr, (unsigned int)pte, index, pte[index]); ++ } else { ++ pte[index] += MAP_COUNT; ++ } ++ index++; ++ vaddr += 4096; ++ } ++ n->count++; ++ return vaddr; ++} ++ ++static struct pmd_node *find_node(struct dmmu_handle *h,unsigned int vaddr) ++{ ++ struct list_head *pos, *next; ++ struct pmd_node *n; ++ ++ list_for_each_safe(pos, next, &h->pmd_list) { ++ n = list_entry(pos, struct pmd_node, list); ++ if(n->index == (vaddr & 0xffc00000)) ++ return n; ++ } ++ return NULL; ++} ++ ++static struct pmd_node *add_node(struct dmmu_handle *h,unsigned int vaddr) ++{ ++ int i; ++ unsigned long *pte; ++ unsigned long *pgd = (unsigned long *)h->pdg; ++ struct pmd_node *n = kmalloc(sizeof(*n),GFP_KERNEL); ++ INIT_LIST_HEAD(&n->list); ++ n->count = 0; ++ n->index = vaddr & 0xffc00000; ++ n->page = __get_free_page(GFP_KERNEL); ++ SetPageReserved(virt_to_page((void *)n->page)); ++ ++ pte = (unsigned long *)n->page; ++ for(i=0;i<1024;i++) ++ pte[i] = reserved_pte; ++ ++ list_add(&n->list, &h->pmd_list); ++ ++ pgd[vaddr>>22] = dmmu_v2pfn(n->page) | DMMU_PMD_VLD; ++// printk(">>>>>>> n->page = %lx, pgd[vaddr>>22] = %lx <<<<<<<\n\n", n->page, pgd[vaddr>>22]); ++ return n; ++} ++ ++static struct dmmu_handle *find_handle(void) ++{ ++ struct list_head *pos, *next; ++ struct dmmu_handle *h; ++ ++ list_for_each_safe(pos, next, &handle_list) { ++ h = list_entry(pos, struct dmmu_handle, list); ++ if(h->tgid == current->tgid) ++ return h; ++ } ++ return NULL; ++} ++ ++static struct dmmu_handle *create_handle(void) ++{ ++ struct dmmu_handle *h; ++ unsigned int pgd_index; ++ unsigned long *pgd; ++ ++ h = kmalloc(sizeof(struct dmmu_handle),GFP_KERNEL); ++ if(!h) ++ return NULL; ++ ++ h->tgid = current->tgid; ++ h->pdg = __get_free_page(GFP_KERNEL); ++ if(!h->pdg) { ++ pr_err("%s %d, Get free page for PGD error\n", ++ __func__, __LINE__); ++ kfree(h); ++ return NULL; ++ } ++ SetPageReserved(virt_to_page((void *)h->pdg)); ++ ++ pgd = (unsigned long *)h->pdg; ++ ++ for (pgd_index=0; pgd_index < PTRS_PER_PGD; pgd_index++) ++ pgd[pgd_index] = res_pte_paddr; ++ ++ INIT_LIST_HEAD(&h->list); ++ INIT_LIST_HEAD(&h->pmd_list); ++ INIT_LIST_HEAD(&h->map_list); ++ list_add(&h->list, &handle_list); ++ ++ mutex_init(&h->lock); ++ return h; ++} ++ ++static int dmmu_make_present(unsigned long addr,unsigned long end) ++{ ++#if 0 ++ unsigned long i; ++ for(i = addr; i < end; i += 4096) { ++ *(volatile unsigned char *)(i) = 0; ++ } ++ *(volatile unsigned char *)(end - 1) = 0; ++ return 0; ++#else ++ int ret, len, write; ++ struct vm_area_struct * vma; ++ unsigned long vm_page_prot; ++ ++ vma = find_vma(current->mm, addr); ++ if (!vma) { ++ printk("dmmu_make_present error. addr=%lx len=%lx\n",addr,end-addr); ++ return -1; ++ } ++ ++ if(vma->vm_flags & VM_PFNMAP) ++ return 0; ++ ++ write = (vma->vm_flags & VM_WRITE) != 0; ++ BUG_ON(addr >= end); ++ BUG_ON(end > vma->vm_end); ++ ++ vm_page_prot = pgprot_val(vma->vm_page_prot); ++ vma->vm_page_prot = __pgprot(vm_page_prot | _PAGE_VALID| _PAGE_ACCESSED | _PAGE_PRESENT); ++ ++ len = DIV_ROUND_UP(end, PAGE_SIZE) - addr/PAGE_SIZE; ++ ret = get_user_pages(current, current->mm, addr, ++ len, write, 0, NULL, NULL); ++ vma->vm_page_prot = __pgprot(vm_page_prot); ++ if (ret < 0) { ++ printk("dmmu_make_present get_user_pages error(%d). addr=%lx len=%lx\n",0-ret,addr,end-addr); ++ return ret; ++ } ++ return ret == len ? 0 : -1; ++#endif ++} ++ ++static void dmmu_cache_wback(struct dmmu_handle *h) ++{ ++ struct list_head *pos, *next; ++ struct pmd_node *n; ++ ++ dma_cache_wback(h->pdg,PAGE_SIZE); ++ ++ list_for_each_safe(pos, next, &h->pmd_list) { ++ n = list_entry(pos, struct pmd_node, list); ++ dma_cache_wback(n->page,PAGE_SIZE); ++ } ++} ++ ++static void dmmu_dump_handle(struct seq_file *m, void *v, struct dmmu_handle *h); ++ ++unsigned long dmmu_map(struct device *dev,unsigned long vaddr,unsigned long len) ++{ ++ int end = vaddr + len; ++ struct dmmu_handle *h; ++ struct pmd_node *node; ++ ++ h = find_handle(); ++ if(!h) ++ h = create_handle(); ++ if(!h) ++ return 0; ++ ++ mutex_lock(&h->lock); ++#ifdef DEBUG ++ printk("(pid %d)dmmu_map %lx %lx================================================\n",h->tgid,vaddr,len); ++#endif ++ if(check_map(h,vaddr,len)) ++ { ++ mutex_unlock(&h->lock); ++ return dmmu_v2pfn(h->pdg); ++ } ++ ++ if(dmmu_make_present(vaddr,vaddr+len)) ++ { ++ mutex_unlock(&h->lock); ++ return 0; ++ } ++ ++ handle_add_map(dev,h,vaddr,len); ++ ++ while(vaddr < end) { ++ node = find_node(h,vaddr); ++ if(!node) { ++ node = add_node(h,vaddr); ++ } ++ vaddr = map_node(node,vaddr,end); ++ } ++ dmmu_cache_wback(h); ++#ifdef DEBUG ++ dmmu_dump_handle(NULL,NULL,h); ++#endif ++ mutex_unlock(&h->lock); ++ ++ return dmmu_v2pfn(h->pdg); ++} ++ ++int dmmu_unmap(struct device *dev,unsigned long vaddr, int len) ++{ ++ unsigned long end = vaddr + len; ++ struct dmmu_handle *h; ++ struct pmd_node *node; ++ struct map_node *n; ++ ++ h = find_handle(); ++ if(!h) ++ return 0; ++ ++ mutex_lock(&h->lock); ++#ifdef DEBUG ++ printk("dmmu_unmap %lx %x**********************************************\n",vaddr,len); ++#endif ++ n = check_map(h,vaddr,len); ++ if(!n) { ++ mutex_unlock(&h->lock); ++ return -EAGAIN; ++ } ++ if(n->dev != dev) { ++ mutex_unlock(&h->lock); ++ return -EAGAIN; ++ } ++ ++ list_del(&n->list); ++ kfree(n); ++ ++ while(vaddr < end) { ++ node = find_node(h,vaddr); ++ if(node) ++ vaddr = unmap_node(node,vaddr,end,1); ++ } ++ ++ if(list_empty(&h->pmd_list) && list_empty(&h->map_list)) { ++ list_del(&h->list); ++ ClearPageReserved(virt_to_page((void *)h->pdg)); ++ free_page(h->pdg); ++ mutex_unlock(&h->lock); ++ kfree(h); ++ return 0; ++ } ++ ++ mutex_unlock(&h->lock); ++ return 0; ++} ++ ++int dmmu_free_all(struct device *dev) ++{ ++ struct dmmu_handle *h; ++ struct pmd_node *node; ++ struct map_node *cn; ++ struct list_head *pos, *next; ++ ++ h = find_handle(); ++ if(!h) ++ return 0; ++ ++ mutex_lock(&h->lock); ++ ++ list_for_each_safe(pos, next, &h->map_list) { ++ cn = list_entry(pos, struct map_node, list); ++ node = find_node(h,cn->start); ++ if(node) ++ unmap_node(node,cn->start,cn->len,1); ++ list_del(&cn->list); ++ kfree(cn); ++ } ++ ++ list_for_each_safe(pos, next, &h->pmd_list) { ++ node = list_entry(pos, struct pmd_node, list); ++ if(node){ ++ printk("WARN: pmd list should NULL\n"); ++ unmap_node(node,0,0,0); ++ } ++ } ++ ++ list_del(&h->list); ++ ClearPageReserved(virt_to_page((void *)h->pdg)); ++ free_page(h->pdg); ++ kfree(h); ++ ++ mutex_unlock(&h->lock); ++ return 0; ++} ++ ++int dmmu_unmap_all(struct device *dev) ++{ ++ struct dmmu_handle *h; ++ struct map_node *cn; ++ struct list_head *pos, *next; ++ ++#ifdef DEBUG ++ printk("dmmu_unmap_all\n"); ++#endif ++ h = find_handle(); ++ if(!h) ++ return 0; ++ ++ list_for_each_safe(pos, next, &h->map_list) { ++ cn = list_entry(pos, struct map_node, list); ++ if(dev == cn->dev) ++ dmmu_unmap(dev,cn->start,cn->len); ++ } ++ ++ ++ if(list_empty(&h->map_list)) ++ dmmu_free_all(dev); ++ return 0; ++} ++ ++int __init dmmu_init(void) ++{ ++ int i; ++ unsigned int pte_index; ++ unsigned long res_page_paddr; ++ unsigned long reserved_page; ++ unsigned int *res_pte_vaddr; ++ ++ reserved_page = __get_free_page(GFP_KERNEL); ++ if (!reserved_page) { ++ pr_err("%s %d, Get reserved page error\n", ++ __func__, __LINE__); ++ return ENOMEM; ++ } ++ SetPageReserved(virt_to_page((void *)reserved_page)); ++ reserved_pte = dmmu_v2pfn(reserved_page) | DMMU_PTE_VLD; ++ ++ res_page_paddr = virt_to_phys((void *)reserved_page) | 0xFFF; ++ ++ res_pte_vaddr = (unsigned int *)__get_free_page(GFP_KERNEL); ++ if (!res_pte_vaddr) { ++ pr_err("%s %d, Get free page for PTE error\n", ++ __func__, __LINE__); ++ free_page(reserved_page); ++ return ENOMEM; ++ } ++ for(i = 0; i<1024; i++ ) ++ res_pte_vaddr[i] = 0xffffffff; ++ SetPageReserved(virt_to_page(res_pte_vaddr)); ++ res_pte_paddr = virt_to_phys((void *)res_pte_vaddr) | DMMU_PTE_VLD; ++ ++ for (pte_index = 0; pte_index < PTRS_PER_PTE; pte_index++) ++ res_pte_vaddr[pte_index] = res_page_paddr; ++ printk("%s %d PTRS_PER_PTE = %lu\n",__func__,__LINE__,PTRS_PER_PTE); ++ ++ return 0; ++} ++arch_initcall(dmmu_init); ++ ++void dmmu_dump_vaddr(unsigned long vaddr) ++{ ++ struct dmmu_handle *h; ++ struct pmd_node *node; ++ ++ unsigned long *pmd,*pte; ++ h = find_handle(); ++ if(!h) { ++ printk("dmmu_dump_vaddr %08lx error - h not found!\n",vaddr); ++ return; ++ } ++ ++ node = find_node(h,vaddr); ++ if(!node) { ++ printk("dmmu_dump_vaddr %08lx error - node not found!\n",vaddr); ++ return; ++ } ++ ++ pmd = (unsigned long *)h->pdg; ++ pte = (unsigned long *)node->page; ++ ++ printk("pmd base = %p; pte base = %p\n",pmd,pte); ++ printk("pmd = %08lx; pte = %08lx\n",pmd[vaddr>>22],pte[(vaddr&0x3ff000)>>12]); ++} ++ ++static void dmmu_dump_handle(struct seq_file *m, void *v, struct dmmu_handle *h) ++{ ++ struct list_head *pos, *next; ++ struct map_node *n; ++ ++ list_for_each_safe(pos, next, &h->map_list) { ++ n = list_entry(pos, struct map_node, list); ++ { ++ int i = 0; ++ int vaddr = n->start; ++ struct pmd_node *pn = find_node(h,vaddr); ++ unsigned int *pte = (unsigned int *)pn->page; ++ ++ while(vaddr < (n->start + n->len)) { ++ if(i++%8 == 0) ++ printk("\nvaddr %08x : ",vaddr & 0xfffff000); ++ printk("%08x ",pte[(vaddr & 0x3ff000)>>12]); ++ vaddr += 4096; ++ } ++ printk("\n\n"); ++ } ++ } ++} ++ ++static int dmmu_proc_show(struct seq_file *m, void *v) ++{ ++ struct list_head *pos, *next; ++ struct dmmu_handle *h; ++ volatile unsigned long flags; ++ local_irq_save(flags); ++ list_for_each_safe(pos, next, &handle_list) { ++ h = list_entry(pos, struct dmmu_handle, list); ++ dmmu_dump_handle(m, v, h); ++ } ++ local_irq_restore(flags); ++ return 0; ++} ++ ++static int dmmu_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, dmmu_proc_show, PDE_DATA(inode)); ++} ++ ++static const struct file_operations dmmus_proc_fops ={ ++ .read = seq_read, ++ .open = dmmu_open, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++ ++static int __init init_dmmu_proc(void) ++{ ++ struct proc_dir_entry *p; ++ p = jz_proc_mkdir("dmmu"); ++ if (!p) { ++ pr_warning("create_proc_entry for common dmmu failed.\n"); ++ return -ENODEV; ++ } ++ proc_create("dmmus", 0600,p,&dmmus_proc_fops); ++ ++ return 0; ++} ++ ++module_init(init_dmmu_proc); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_pm.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_pm.c.patch new file mode 100644 index 00000000..d3ba1a43 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_pm.c.patch @@ -0,0 +1,374 @@ +diff -drupN a/arch/mips/xburst2/soc-x2000-v12/pm.c b/arch/mips/xburst2/soc-x2000-v12/pm.c +--- a/arch/mips/xburst2/soc-x2000-v12/pm.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-x2000-v12/pm.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,370 @@ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++ ++#define SLEEP_MEMORY_START 0xb2400000 ++#define SLEEP_MEMORY_END 0xb2407ffc ++#define SLEEP_RESUME_SP SLEEP_MEMORY_END ++#define SLEEP_RESUME_BOOTUP_TEXT SLEEP_MEMORY_START ++ ++#define SLEEP_CPU_RESUME_BOOTUP_TEXT SLEEP_RESUME_BOOTUP_TEXT ++#define SLEEP_CPU_RESUME_BOOTUP_LEN 32 // 8 instructions ++#define SLEEP_CPU_RESUME_TEXT (SLEEP_CPU_RESUME_BOOTUP_TEXT + SLEEP_CPU_RESUME_BOOTUP_LEN) ++#define SLEEP_CPU_RESUME_LEN (1024) ++#define SLEEP_CPU_SLEEP_TEXT (SLEEP_CPU_RESUME_TEXT + SLEEP_CPU_RESUME_LEN) ++#define SLEEP_CPU_SLEEP_LEN (3072) ++#define SLEEP_CPU_RESUME_SP SLEEP_RESUME_SP ++ ++ ++/*************************************** debug ***************************************/ ++ ++#define PRINT_DEBUG ++ ++#ifdef PRINT_DEBUG ++ ++#define OFF_TDR (0x00) ++#define OFF_LCR (0x0C) ++#define OFF_LSR (0x14) ++#define LSR_TDRQ (1 << 5) ++#define LSR_TEMT (1 << 6) ++ ++#define U_IOBASE (UART0_IOBASE + 0xa0000000) ++#define TCSM_PCHAR(x) \ ++ *((volatile unsigned int*)(U_IOBASE+OFF_TDR)) = x; \ ++while ((*((volatile unsigned int*)(U_IOBASE + OFF_LSR)) & (LSR_TDRQ | LSR_TEMT)) != (LSR_TDRQ | LSR_TEMT)) ++#else ++#define TCSM_PCHAR(x) ++#endif ++ ++#define TCSM_DELAY(x) \ ++ do{ \ ++ register unsigned int i = x; \ ++ while(i--) \ ++ __asm__ volatile(".set mips32\n\t" \ ++ "nop\n\t" \ ++ ".set mips32"); \ ++ }while(0) \ ++ ++static inline void serial_put_hex(unsigned int x) { ++ int i; ++ unsigned int d; ++ for(i = 7;i >= 0;i--) { ++ d = (x >> (i * 4)) & 0xf; ++ if(d < 10) d += '0'; ++ else d += 'A' - 10; ++ TCSM_PCHAR(d); ++ } ++ TCSM_PCHAR('\r'); ++ TCSM_PCHAR('\n'); ++} ++ ++/*************************************************************************************/ ++ ++/*----------------------------------------------------------------------------- ++ * extern function declare ++ *-----------------------------------------------------------------------------*/ ++extern long long save_goto(unsigned int func, suspend_state_t state, unsigned int cpu_id); ++extern int restore_goto(unsigned int func, suspend_state_t state, unsigned int cpu_id); ++ ++ ++static void load_func_to_tcsm(unsigned int *tcsm_addr,unsigned int *f_addr,unsigned int size) ++{ ++ unsigned int instr; ++ int offset; ++ int i; ++#ifdef DEBUG_PM ++ printk("tcsm addr = %p %p size = %d\n",tcsm_addr,f_addr,size); ++#endif ++ for(i = 0;i < size / 4;i++) { ++ instr = f_addr[i]; ++ if((instr >> 26) == 2){ ++ offset = instr & 0x3ffffff; ++ offset = (offset << 2) - ((unsigned int)f_addr & 0xfffffff); ++ if(offset > 0) { ++ offset = ((unsigned int)tcsm_addr & 0xfffffff) + offset; ++ instr = (2 << 26) | (offset >> 2); ++ } ++ } ++ tcsm_addr[i] = instr; ++ } ++} ++ ++ ++static int soc_pm_idle(void) ++{ ++ unsigned int lcr = cpm_inl(CPM_LCR); ++ unsigned int opcr = cpm_inl(CPM_OPCR); ++ ++ lcr &=~ 0x3; // low power mode: IDLE ++ cpm_outl(lcr, CPM_LCR); ++ ++ opcr &= ~(1 << 30); ++ opcr &= ~(1 << 31); ++ cpm_outl(opcr, CPM_OPCR); ++ ++ return 0; ++} ++ ++#ifdef X2000_IDLE_PD ++static int soc_pm_idle_pd(void) ++{ ++ unsigned int lcr = cpm_inl(CPM_LCR); ++ unsigned int opcr = cpm_inl(CPM_OPCR); ++ ++ lcr &=~ 0x3; // low power mode: IDLE ++ lcr |= 2; ++ cpm_outl(lcr, CPM_LCR); ++ ++ opcr &= ~ (1<<31); ++ opcr |= (1 << 30); ++ opcr |= (1 << 26); //l2c retention ++ opcr |= 1 << 2; // select RTC clk ++ cpm_outl(opcr, CPM_OPCR); ++ ++ return 0; ++} ++#endif ++ ++static int soc_pm_sleep(void) ++{ ++ unsigned int lcr = cpm_inl(CPM_LCR); ++ unsigned int opcr = cpm_inl(CPM_OPCR); ++ ++ lcr &=~ 0x3; ++ lcr |= 1 << 0; // low power mode: SLEEP ++ cpm_outl(lcr, CPM_LCR); ++ ++ opcr &= ~(1 << 31); ++ opcr |= (1 << 30); ++ opcr |= (1 << 26); //L2C retention. ++ opcr |= (1 << 21); // cpu 32k ram retention. ++ opcr |= (1 << 3); // power down CPU ++ opcr &= ~(1 << 4); // exclk disable; ++ opcr |= (1 << 2); // select RTC clk ++ cpm_outl(opcr, CPM_OPCR); ++ ++ { ++ /* before power down cpu by set PD in OPCR, reduce cpu's frequency as the same as L2C's freq */ ++ unsigned int val, div; ++ ++ /* change disable */ ++ val = cpm_inl(CPM_CPCCR); ++ val &= ~(1 << 22); ++ cpm_outl(val, CPM_CPCCR); ++ ++ /* div cpu = div l2c */ ++ div = val & (0xf << 4); ++ val &= ~0xf; ++ val |= div; ++ cpm_outl(val, CPM_CPCCR); ++ ++ /* change enable */ ++ val |= (1 << 22); ++ cpm_outl(val, CPM_CPCCR); ++ } ++ ++ return 0; ++} ++ ++static int soc_post_wakeup(void) ++{ ++ unsigned int lcr = cpm_inl(CPM_LCR); ++ ++ printk("post wakeup!\n"); ++ ++ lcr &= ~0x3; // low power mode: IDLE ++ cpm_outl(lcr, CPM_LCR); ++ ++ return 0; ++} ++ ++static noinline void cpu_resume_bootup(void) ++{ ++ /* set reset entry */ ++ *(volatile unsigned int *)0xb2200f00 = 0xbfc00000; ++ ++ __asm__ volatile( ++ ".set push \n\t" ++ ".set mips32r2 \n\t" ++ "move $29, %0 \n\t" ++ "jr.hb %1 \n\t" ++ "nop \n\t" ++ ".set pop \n\t" ++ : ++ :"r" (SLEEP_CPU_RESUME_SP), "r"(SLEEP_CPU_RESUME_TEXT) ++ : ++ ); ++} ++ ++static noinline void cpu_resume(suspend_state_t state) ++{ ++ unsigned int cpu_id; ++ unsigned int ddrc_ctrl = ddr_readl(DDRC_CTRL); ++ ++ if (state == PM_SUSPEND_MEM) { ++ ddrc_ctrl &= ~(1<<5); ++ ddrc_ctrl |= 1 << 1; ++ ddr_writel(ddrc_ctrl, DDRC_CTRL); ++ ++ while(ddr_readl(DDRC_STATUS) & (1<<2)); ++ } ++ ++ cpu_id = read_c0_ebase() & 0x3ff; ++ ++ __asm__ volatile( ++ ".set push \n\t" ++ ".set mips32r2 \n\t" ++ "jr.hb %0 \n\t" ++ "nop \n\t" ++ ".set pop \n\t" ++ : ++ : "r" (restore_goto), ++ "r" (state), ++ "r" (cpu_id) ++ : ++ ); ++} ++ ++ ++static noinline void cpu_sleep(suspend_state_t state) ++{ ++ ++ unsigned int ddrc_ctrl = ddr_readl(DDRC_CTRL); ++ ++ blast_dcache32(); ++ blast_scache64(); ++ __sync(); ++ __fast_iob(); ++ ++ if (state == PM_SUSPEND_MEM) { ++ /* DDR self refresh, */ ++ ddrc_ctrl |= 1 << 5; ++ ddrc_ctrl &= ~(1<<1); ++ ddr_writel(ddrc_ctrl, DDRC_CTRL); ++ while(!(ddr_readl(DDRC_STATUS) & (1<<2))); ++ } ++ ++ __asm__ volatile( ++ ".set push \n\t" ++ ".set mips32r2 \n\t" ++ "wait \n\t" ++ "nop \n\t" ++ "nop \n\t" ++ "nop \n\t" ++ ".set pop \n\t" ++ ); ++ ++ TCSM_PCHAR('\r'); ++ TCSM_PCHAR('\n'); ++ TCSM_PCHAR('?'); ++ TCSM_PCHAR('?'); ++ TCSM_PCHAR('?'); ++ TCSM_PCHAR('\r'); ++ TCSM_PCHAR('\n'); ++ ++ __asm__ volatile( ++ ".set push \n\t" ++ ".set mips32r2 \n\t" ++ "jr.hb %0 \n\t" ++ "nop \n\t" ++ ".set pop \n\t" ++ : ++ : "r" (SLEEP_CPU_RESUME_BOOTUP_TEXT) ++ : ++ ); ++} ++ ++ ++int x2000_pm_enter(suspend_state_t state) ++{ ++ unsigned int cpu_id; ++ ++ printk("x2000 pm enter!!\n"); ++ ++ load_func_to_tcsm((unsigned int *)SLEEP_CPU_RESUME_BOOTUP_TEXT, (unsigned int *)cpu_resume_bootup, SLEEP_CPU_RESUME_BOOTUP_LEN); ++ load_func_to_tcsm((unsigned int *)SLEEP_CPU_RESUME_TEXT, (unsigned int *)cpu_resume, SLEEP_CPU_RESUME_LEN); ++ load_func_to_tcsm((unsigned int *)SLEEP_CPU_SLEEP_TEXT, (unsigned int *)cpu_sleep, SLEEP_CPU_SLEEP_LEN); ++ ++ if (state == PM_SUSPEND_STANDBY) { ++#ifdef X2000_IDLE_PD ++ soc_pm_idle_pd(); ++#else ++ soc_pm_idle(); ++#endif ++ } else if (state == PM_SUSPEND_MEM) { ++ soc_pm_sleep(); ++ } else { ++ printk("WARNING : unsupport pm suspend state\n"); ++ } ++ ++#ifdef DEBUG_PM ++ printk("LCR: %08x\n", cpm_inl(CPM_LCR)); ++ printk("OPCR: %08x\n", cpm_inl(CPM_OPCR)); ++#endif ++ ++ cpu_id = read_c0_ebase() & 0x1ff; ++ ++ /* set reset entry */ ++ *(volatile unsigned int *)0xb2200f00 = SLEEP_CPU_RESUME_BOOTUP_TEXT; ++ ++ mb(); ++ save_goto((unsigned int)SLEEP_CPU_SLEEP_TEXT, state, cpu_id); ++ mb(); ++ ++ soc_post_wakeup(); ++ ++ return 0; ++} ++ ++static int x2000_pm_begin(suspend_state_t state) ++{ ++ printk("x2000 suspend begin\n"); ++ return 0; ++} ++ ++static void x2000_pm_end(void) ++{ ++ printk("x2000 pm end!\n"); ++} ++ ++static int ingenic_pm_valid(suspend_state_t state) ++{ ++ switch (state) { ++ case PM_SUSPEND_ON: ++ case PM_SUSPEND_STANDBY: ++ case PM_SUSPEND_MEM: ++ return 1; ++ ++ default: ++ return 0; ++ } ++} ++static const struct platform_suspend_ops x2000_pm_ops = { ++ .valid = ingenic_pm_valid, ++ .begin = x2000_pm_begin, ++ .enter = x2000_pm_enter, ++ .end = x2000_pm_end, ++}; ++ ++/* ++ * Initialize suspend interface ++ */ ++static int __init pm_init(void) ++{ ++ ++ suspend_set_ops(&x2000_pm_ops); ++ ++ ++ return 0; ++} ++ ++late_initcall(pm_init); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_regs_save_restore.S.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_regs_save_restore.S.patch new file mode 100644 index 00000000..d7a6c5cd --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_regs_save_restore.S.patch @@ -0,0 +1,190 @@ +diff -drupN a/arch/mips/xburst2/soc-x2000-v12/regs_save_restore.S b/arch/mips/xburst2/soc-x2000-v12/regs_save_restore.S +--- a/arch/mips/xburst2/soc-x2000-v12/regs_save_restore.S 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-x2000-v12/regs_save_restore.S 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,186 @@ ++#include ++#include ++ ++#define CP0_PAGEMASK $5,0 ++#define CP0_TLB_SPEC $5,4 ++#define CP0_STATUS $12,0 ++#define CP0_INTCTL $12,1 ++#define CP0_CAUSE $13,0 ++#define CP0_EBASE $15,1 ++#define CP0_CONFIG $16,0 ++#define CP0_CONFIG1 $16,1 ++#define CP0_CONFIG2 $16,2 ++#define CP0_CONFIG3 $16,3 ++#define CP0_CONFIG4 $16,4 ++#define CP0_CONFIG5 $16,5 ++#define CP0_CONFIG7 $16,7 ++#define CP0_LLADDR $17,0 ++#define PMON_CSR $17,7 ++#define PMON_HIGH $17,4 ++#define PMON_LC $17,5 ++#define PMON_RC $17,6 ++#define CP0_WATCHLo $18,0 ++#define CP0_WATCHHI $19,0 ++#define CP0_ERRCTL $26,0 ++#define CP0_CONTEXT $4,0 ++ ++ .data ++ .global _regs_stack ++_regs_stack: ++ .align 5 ++ .space 272,0 ++ ++ .text ++ .global save_goto ++ .align 2 ++ .ent save_goto,0 ++save_goto: ++ .set push ++ .set noreorder ++ .set noat ++ ++ la k0, _regs_stack ++ sllv k0, k0, a2 ++ sw s0,0(k0) ++ sw s1,4(k0) ++ sw s2,8(k0) ++ sw s3,12(k0) ++ sw s4,16(k0) ++ sw s5,20(k0) ++ sw s6,24(k0) ++ sw s7,28(k0) ++ sw gp,32(k0) ++ sw sp,36(k0) ++ sw fp,40(k0) ++ sw ra,44(k0) ++ ++ mfc0 k1,CP0_PAGEMASK ++ sw k1,48(k0) ++ mfc0 k1,CP0_TLB_SPEC ++ sw k1,52(k0) ++ mfc0 k1,CP0_STATUS ++ sw k1,56(k0) ++ mfc0 k1,CP0_INTCTL ++ sw k1,60(k0) ++ mfc0 k1,CP0_CAUSE ++ sw k1,64(k0) ++ mfc0 k1,CP0_EBASE ++ sw k1,68(k0) ++ mfc0 k1,CP0_CONFIG ++ sw k1,72(k0) ++ mfc0 k1,CP0_CONFIG1 ++ sw k1,76(k0) ++ mfc0 k1,CP0_CONFIG2 ++ sw k1,80(k0) ++ mfc0 k1,CP0_CONFIG3 ++ sw k1,84(k0) ++ mfc0 k1,CP0_CONFIG4 ++ sw k1,88(k0) ++ mfc0 k1,CP0_CONFIG5 ++ sw k1,92(k0) ++ mfc0 k1,CP0_CONFIG7 ++ sw k1,96(k0) ++ mfc0 k1,CP0_LLADDR ++ sw k1,100(k0) ++ mfc0 k1,PMON_CSR ++ sw k1,104(k0) ++ mfc0 k1,PMON_HIGH ++ sw k1,108(k0) ++ mfc0 k1,PMON_LC ++ sw k1,112(k0) ++ mfc0 k1,PMON_RC ++ sw k1,116(k0) ++ mfc0 k1,CP0_WATCHLo ++ sw k1,120(k0) ++ mfc0 k1,CP0_WATCHHI ++ sw k1,124(k0) ++ mfc0 k1,CP0_ERRCTL ++ sw k1,128(k0) ++ mfc0 k1,CP0_CONTEXT ++ sw k1,132(k0) ++ ++ move t0, a0 ++ move a0, a1 ++ jr.hb t0 ++ nop ++ ++ .set at ++ .set reorder ++ .set pop ++ END(save_goto) ++ .text ++ .global restore_goto ++ .align 2 ++ .ent restore_goto,0 ++restore_goto: ++ .set push ++ .set noreorder ++ .set noat ++ ++ la k0, _regs_stack ++ sllv k0, k0, a2 ++ lw s0,0(k0) ++ lw s1,4(k0) ++ lw s2,8(k0) ++ lw s3,12(k0) ++ lw s4,16(k0) ++ lw s5,20(k0) ++ lw s6,24(k0) ++ lw s7,28(k0) ++ lw gp,32(k0) ++ lw sp,36(k0) ++ lw fp,40(k0) ++ lw ra,44(k0) ++ ++ lw k1,48(k0) ++ mtc0 k1,CP0_PAGEMASK ++ lw k1,52(k0) ++ mtc0 k1,CP0_TLB_SPEC ++ lw k1,56(k0) ++ mtc0 k1,CP0_STATUS ++ lw k1,60(k0) ++ mtc0 k1,CP0_INTCTL ++ lw k1,64(k0) ++ mtc0 k1,CP0_CAUSE ++ lw k1,68(k0) ++ mtc0 k1,CP0_EBASE ++ lw k1,72(k0) ++ mtc0 k1,CP0_CONFIG ++ lw k1,76(k0) ++ mtc0 k1,CP0_CONFIG1 ++ lw k1,80(k0) ++ mtc0 k1,CP0_CONFIG2 ++ lw k1,84(k0) ++ mtc0 k1,CP0_CONFIG3 ++ lw k1,88(k0) ++ mtc0 k1,CP0_CONFIG4 ++ lw k1,92(k0) ++ mtc0 k1,CP0_CONFIG5 ++ lw k1,96(k0) ++ mtc0 k1,CP0_CONFIG7 ++ lw k1,100(k0) ++ mtc0 k1,CP0_LLADDR ++ lw k1,104(k0) ++ mtc0 k1,PMON_CSR ++ lw k1,108(k0) ++ mtc0 k1,PMON_HIGH ++ lw k1,112(k0) ++ mtc0 k1,PMON_LC ++ lw k1,116(k0) ++ mtc0 k1,PMON_RC ++ lw k1,120(k0) ++ mtc0 k1,CP0_WATCHLo ++ lw k1,124(k0) ++ mtc0 k1,CP0_WATCHHI ++ lw k1,128(k0) ++ mtc0 k1,CP0_ERRCTL ++ lw k1,132(k0) ++ mtc0 k1,CP0_CONTEXT ++ ++ jr.hb ra ++ nop ++ ++ .set at ++ .set reorder ++ .set pop ++ END(restore_goto) diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_regs_save_restore.py.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_regs_save_restore.py.patch new file mode 100644 index 00000000..0fe21f73 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_regs_save_restore.py.patch @@ -0,0 +1,133 @@ +diff -drupN a/arch/mips/xburst2/soc-x2000-v12/regs_save_restore.py b/arch/mips/xburst2/soc-x2000-v12/regs_save_restore.py +--- a/arch/mips/xburst2/soc-x2000-v12/regs_save_restore.py 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-x2000-v12/regs_save_restore.py 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,129 @@ ++#!/usr/bin/env python ++import os ++import string ++ ++common_regs=["s0","s1","s2","s3", ++ "s4","s5","s6","s7", ++ "gp","sp","fp","ra"] ++cp0_regs=[ ++ ["CP0_PAGEMASK","$5","0"], ++ ["CP0_TLB_SPEC","$5","4"], ++ ["CP0_STATUS","$12","0"], ++ ["CP0_INTCTL","$12","1"], ++ ["CP0_CAUSE","$13","0"], ++ ["CP0_EBASE","$15","1"], ++ ["CP0_CONFIG","$16","0"], ++ ["CP0_CONFIG1","$16","1"], ++ ["CP0_CONFIG2","$16","2"], ++ ["CP0_CONFIG3","$16","3"], ++ ["CP0_CONFIG4", "$16", "4"], ++ ["CP0_CONFIG5", "$16", "5"], ++ ["CP0_CONFIG7","$16","7"], ++ ["CP0_LLADDR","$17","0"], ++ ["PMON_CSR","$17","7"], ++ ["PMON_HIGH","$17","4"], ++ ["PMON_LC","$17","5"], ++ ["PMON_RC","$17","6"], ++ ["CP0_WATCHLo","$18","0"], ++ ["CP0_WATCHHI","$19","0"], ++ ["CP0_ERRCTL","$26","0"], ++ ["CP0_CONTEXT", "$4", "0"], ++ ] ++def gen_get_array_size(): ++ size=0 ++ size+=len(common_regs) ++ size+=len(cp0_regs) ++ return size ++ ++def gen_print_head_and_macro(): ++ print("#include ") ++ print("#include ") ++ print("") ++ for s in cp0_regs: ++ print("#define %s\t%s,%s" %(s[0],s[1],s[2])) ++ print("") ++def gen_define_global_arg(str, num): ++ print("\t.data") ++ print("\t.global %s" %(str)) ++ print("%s:" %(str)) ++ print("\t.align 5") ++ print("\t.space %s,0" %(num)) ++ print("") ++ ++def gen_save_common_regs(index): ++ for s in common_regs: ++ print("\tsw\t%s,%d(k0)" % (s,index)) ++ index=index+4 ++ return index ++def gen_restore_common_regs(index): ++ for s in common_regs: ++ print("\tlw\t%s,%d(k0)" % (s,index)) ++ index=index+4 ++ return index ++def gen_save_cp0_regs(index): ++ for s in cp0_regs: ++ print("\tmfc0\tk1,%s" % (s[0])) ++ print("\tsw\tk1,%d(k0)" % (index)) ++ index=index+4 ++ return index ++def gen_restore_cp0_regs(index): ++ for s in cp0_regs: ++ print("\tlw\tk1,%d(k0)" % (index)) ++ print("\tmtc0\tk1,%s" % (s[0])) ++ index=index+4 ++ return index ++def gen_print_function(f_name, regs_stack): ++ index=0 ++ print("\t.text") ++ print("\t.global %s" %(f_name)) ++ print("\t.align 2") ++ print("\t.ent %s,0" %(f_name)) ++ print("%s:" %(f_name)) ++ print("\t.set\tpush") ++ print("\t.set\tnoreorder") ++ print("\t.set\tnoat") ++ print("") ++ print("\tla\tk0, %s" %(regs_stack)) ++ print("\tsllv\tk0, k0, a2") ++ ''' ++ save_goto(func, args, cpu) ++ ''' ++ if f_name == "save_goto": ++ index = gen_save_common_regs(index) ++ print("") ++ index = gen_save_cp0_regs(index) ++ print("") ++ print("\tmove\tt0, a0"); ++ print("\tmove\ta0, a1"); ++ print("\tjr.hb\tt0") ++ print("\tnop") ++ elif f_name == "restore_goto": ++ index = gen_restore_common_regs(index) ++ print("") ++ index = gen_restore_cp0_regs(index) ++ print("") ++ print("\tjr.hb\tra") ++ print("\tnop") ++ else: ++ print("not support") ++ print("") ++ print("\t.set\tat") ++ print("\t.set\treorder") ++ print("\t.set\tpop") ++ print("\tEND(%s)" %(f_name)) ++ ++ ++def main(): ++ regs_size=gen_get_array_size() ++ regs_size*=4 ++ nr_cpu = 2 ++ regs_size = nr_cpu * regs_size; ++ ++ gen_print_head_and_macro() ++ gen_define_global_arg("_regs_stack", regs_size) ++ gen_print_function("save_goto", "_regs_stack") ++ gen_print_function("restore_goto", "_regs_stack") ++ pass ++ ++if __name__ == '__main__': ++ main() diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_serial.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_serial.c.patch new file mode 100644 index 00000000..c157622a --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_serial.c.patch @@ -0,0 +1,95 @@ +diff -drupN a/arch/mips/xburst2/soc-x2000-v12/serial.c b/arch/mips/xburst2/soc-x2000-v12/serial.c +--- a/arch/mips/xburst2/soc-x2000-v12/serial.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-x2000-v12/serial.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,91 @@ ++/* ++ * JZ SOC serial routines for early_printk. ++ * ++ * Copyright (C) 2006 Ingenic Semiconductor Inc. ++ * ++ */ ++ ++#include ++ ++#include ++ ++#define UART_BASE UART0_IOBASE ++#define UART_OFF 0x1000 ++ ++#define OFF_TDR (0x00) ++#define OFF_LCR (0x0C) ++#define OFF_LSR (0x14) ++ ++#define LSR_TDRQ (1 << 5) ++#define LSR_TEMT (1 << 6) ++ ++static void check_uart(char c); ++ ++static volatile u8 *uart_base; ++typedef void (*putchar_f_t)(char); ++static putchar_f_t putchar_f = check_uart; ++ ++static void putchar(char ch) ++{ ++ int timeout = 10000; ++ volatile u8 *base = uart_base; ++ /* Wait for fifo to shift out some bytes */ ++ while ((base[OFF_LSR] & (LSR_TDRQ | LSR_TEMT)) ++ != (LSR_TDRQ | LSR_TEMT) && timeout--) ++ ; ++ base[OFF_TDR] = (u8)ch; ++} ++ ++static void putchar_dummy(char ch) ++{ ++ return; ++} ++ ++static void check_uart(char c) ++{ ++ /* We Couldn't use ioremap() here */ ++ volatile u8 *base = (volatile u8*)CKSEG1ADDR(UART0_IOBASE); ++ int i = 0; ++ for(i=0; i<4; i++) { ++ if(base[OFF_LCR]) ++ break; ++ base += UART_OFF; ++ } ++ ++ if(i<4) { ++ uart_base = base; ++ putchar_f = putchar; ++ putchar_f(c); ++ } else { ++ putchar_f = putchar_dummy; ++ } ++} ++ ++/* used by early printk */ ++void prom_putchar(char c) ++{ ++ putchar_f(c); ++} ++ ++void prom_putstr(char *s) ++{ ++ while(*s) { ++ if(*s == '\n') ++ putchar_f('\r'); ++ putchar_f(*s); ++ s++; ++ } ++} ++ ++#if 1 ++static char pbuffer[4096]; ++void prom_printk(const char *fmt, ...) { ++ va_list args; ++ ++ va_start(args, fmt); ++ vsnprintf(pbuffer, 4096, fmt, args); ++ va_end(args); ++ ++ prom_putstr(pbuffer); ++} ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_setup.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_setup.c.patch new file mode 100644 index 00000000..e45a92bb --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst2_soc-x2000-v12_setup.c.patch @@ -0,0 +1,88 @@ +diff -drupN a/arch/mips/xburst2/soc-x2000-v12/setup.c b/arch/mips/xburst2/soc-x2000-v12/setup.c +--- a/arch/mips/xburst2/soc-x2000-v12/setup.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst2/soc-x2000-v12/setup.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,84 @@ ++/* ++ * Ingenic Soc Setup ++ * ++ * 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) 2006 Ingenic Semiconductor Inc. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++void __init cpm_reset(void) ++{ ++} ++ ++int __init setup_init(void) ++{ ++#if 0 ++ cpm_reset(); ++ /* Set bus priority here */ ++ *(volatile unsigned int *)0xb34f0240 = 0x00010003; ++ *(volatile unsigned int *)0xb34f0244 = 0x00010003; ++#endif ++ ++ return 0; ++} ++extern void __init init_all_clk(void); ++/* used by linux-mti code */ ++extern void *get_fdt_addr(void); ++void __init plat_mem_setup(void) ++{ ++ /* use IO_BASE, so that we can use phy addr on hard manual ++ * directly with in(bwlq)/out(bwlq) in io.h. ++ */ ++ set_io_port_base(IO_BASE); ++ ioport_resource.start = 0x00000000; ++ ioport_resource.end = 0xffffffff; ++ iomem_resource.start = 0x00000000; ++ iomem_resource.end = 0xffffffff; ++ setup_init(); ++ ++ __dt_setup_arch(get_fdt_addr()); ++ ++ return; ++} ++void __init device_tree_init(void) ++{ ++ unflatten_and_copy_device_tree(); ++} ++ ++static int __init plat_of_populate(void) ++{ ++ of_platform_default_populate(NULL, NULL, NULL); ++ return 0; ++} ++arch_initcall(plat_of_populate); ++ ++void __init plat_time_init(void) ++{ ++ of_clk_init(NULL); ++ ++ clocksource_probe(); ++} ++ ++void __init arch_init_irq(void) ++{ ++ irqchip_init(); ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_Kconfig.patch new file mode 100644 index 00000000..fc4ead12 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_Kconfig.patch @@ -0,0 +1,78 @@ +diff -drupN a/arch/mips/xburst/Kconfig b/arch/mips/xburst/Kconfig +--- a/arch/mips/xburst/Kconfig 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/Kconfig 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,74 @@ ++menuconfig SOC_TYPE ++ tristate "SOC type" ++ depends on MACH_XBURST ++ default y ++ ++if SOC_TYPE ++choice ++ prompt "SOC types" ++ depends on MACH_XBURST ++ default SOC_X1000 ++ ++config SOC_X1000 ++ bool "x1000 socs" ++ select INGENIC_INTC ++ select CLK_X1000 ++ select CLKSRC_OF ++ select PINCTRL ++ select BUILTIN_DTB ++ select CLKDEV_LOOKUP ++ select PINCTRL_INGENIC ++ select CLKSRC_INGENIC_SYS_OST ++ ++config SOC_X1800 ++ bool "x1800 socs" ++ select INGENIC_INTC ++ select CLK_X1800 ++ select CLKSRC_OF ++ select PINCTRL ++ select BUILTIN_DTB ++ select CLKDEV_LOOKUP ++ select PINCTRL_INGENIC ++ select PINCTRL_INGENIC_LEGACY_GPIO ++ select CLKSRC_INGENIC_SYS_OST ++ select XBURST_MXUV2 ++endchoice ++ ++ ++choice ++ prompt "device tree select" ++ default DT_NONE ++config DT_NONE ++ ++if SOC_X1000 ++source "arch/mips/xburst/soc-x1000/Kconfig.DT" ++endif ++if SOC_X1800 ++#source "arch/mips/xburst/soc-x1800/Kconfig.DT" ++endif ++endchoice ++ ++config EXTAL_CLOCK ++ depends on MACH_XBURST ++ int "extal clock in MHz" ++ default 24 ++ ++config INGENIC_GPT_CHECK ++ depends on MACH_XBURST ++ bool "The physical space is larger than the virtual space" ++ default y ++ ++config SUSPEND_TEST ++ bool "auto suspend test" ++ default n ++ ++config SUSPEND_ALARM_TIME ++ int "suspend alarm time(second)" ++ depends on SUSPEND_TEST ++ default 2 ++ ++config XBURST_MXUV2 ++ bool ++ default n ++ ++endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_Makefile.patch new file mode 100644 index 00000000..b370d076 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_Makefile.patch @@ -0,0 +1,8 @@ +diff -drupN a/arch/mips/xburst/Makefile b/arch/mips/xburst/Makefile +--- a/arch/mips/xburst/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/Makefile 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,4 @@ ++obj-y += common/ ++obj-y += debug/ ++obj-$(CONFIG_SOC_X1000) += soc-x1000/ ++obj-$(CONFIG_SOC_X1800) += soc-x1800/ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_Platform.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_Platform.patch new file mode 100644 index 00000000..8a70d300 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_Platform.patch @@ -0,0 +1,10 @@ +diff -drupN a/arch/mips/xburst/Platform b/arch/mips/xburst/Platform +--- a/arch/mips/xburst/Platform 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/Platform 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,6 @@ ++platform-$(CONFIG_MACH_XBURST) += xburst/ ++load-$(CONFIG_MACH_XBURST) += 0xffffffff80010000 ++ ++cflags-$(CONFIG_MACH_XBURST) += -I$(srctree)/arch/mips/xburst/common/include ++cflags-$(CONFIG_SOC_X1000) += -I$(srctree)/arch/mips/xburst/soc-x1000/include ++cflags-$(CONFIG_SOC_X1800) += -I$(srctree)/arch/mips/xburst/soc-x1800/include diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_common_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_common_Makefile.patch new file mode 100644 index 00000000..afbb6ecb --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_common_Makefile.patch @@ -0,0 +1,9 @@ +diff -drupN a/arch/mips/xburst/common/Makefile b/arch/mips/xburst/common/Makefile +--- a/arch/mips/xburst/common/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/common/Makefile 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,4 @@ ++obj-y += prom.o mxu-xburst.o jz_notifier.o ++obj-$(CONFIG_XBURST_CPU_SCACHE) += sc-xburst.o ++obj-y += initrd-check.o ++obj-$(CONFIG_XBURST_MXUV2) += mxu-v2-ex.obj +Двоичные файлы a/arch/mips/xburst/common/mxu-v2-ex.obj и b/arch/mips/xburst/common/mxu-v2-ex.obj различаются diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_common_include_jz_notifier.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_common_include_jz_notifier.h.patch new file mode 100644 index 00000000..1d97149c --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_common_include_jz_notifier.h.patch @@ -0,0 +1,49 @@ +diff -drupN a/arch/mips/xburst/common/include/jz_notifier.h b/arch/mips/xburst/common/include/jz_notifier.h +--- a/arch/mips/xburst/common/include/jz_notifier.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/common/include/jz_notifier.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,45 @@ ++#ifndef _JZ_NOTIFIER_H_ ++#define _JZ_NOTIFIER_H_ ++ ++#include ++ ++/* ++ * Hibernation and suspend events ++ */ ++enum jz_notif_cmd { ++ JZ_CMD_START = 0, ++ JZ_CLK_PRECHANGE, ++ JZ_CLK_CHANGING, ++ JZ_CLK_CHANGED, ++ JZ_CLKGATE_CHANGE, ++ JZ_POST_HIBERNATION, /* Hibernation finished */ ++ JZ_PM_SUSPEND_STANDBY, /* Hibernation finished */ ++ MMU_CONTEXT_EXIT_MMAP, ++ JZ_CMD_END ++}; ++enum { ++ NOTEFY_PROI_START=1, ++ NOTEFY_PROI_HIGH, ++ NOTEFY_PROI_NORMAL, ++ NOTEFY_PROI_LOW, ++ NOTEFY_PROI_END ++}; ++ ++struct clk_notify_data ++{ ++ unsigned long current_rate; ++ unsigned long target_rate; ++}; ++ ++struct jz_notifier { ++ struct notifier_block nb; ++ int (*jz_notify)(struct jz_notifier *notify,void *d); ++ int level; ++ enum jz_notif_cmd msg; ++}; ++ ++int jz_notifier_register(struct jz_notifier *notify, unsigned int priority); ++int jz_notifier_unregister(struct jz_notifier *notify, unsigned int priority); ++int jz_notifier_call(unsigned int priority, unsigned long val, void *v); ++ ++#endif /* _JZ_NOTIFIER_H_ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_common_include_mxu.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_common_include_mxu.h.patch new file mode 100644 index 00000000..8074fb3a --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_common_include_mxu.h.patch @@ -0,0 +1,54 @@ +diff -drupN a/arch/mips/xburst/common/include/mxu.h b/arch/mips/xburst/common/include/mxu.h +--- a/arch/mips/xburst/common/include/mxu.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/common/include/mxu.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,50 @@ ++/* ++ * Copyright (C) 2005 Mips Technologies ++ * Author: Chris Dearman, chris@mips.com derived from fpu.h ++ * ++ * 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. ++ */ ++#ifndef _ASM_MXU_H ++#define _ASM_MXU_H ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++static inline void __init_mxu(void) ++{ ++ unsigned int register val asm("t0"); ++ val = 3; ++ asm volatile(".word 0x7008042f \n\t"::"r"(val)); ++} ++ ++void __save_mxu(void *); ++void __restore_mxu(void * tsk_void); ++ ++static inline void init_mxu(void) ++{ ++ if(cpu_has_mxu) ++ __init_mxu(); ++} ++ ++ ++#define save_mxu(tsk) \ ++ do { \ ++ if (cpu_has_mxu) \ ++ __save_mxu(tsk); \ ++ } while (0) ++ ++#define restore_mxu(tsk) \ ++ do { \ ++ if (cpu_has_mxu) \ ++ __restore_mxu(tsk); \ ++ } while (0) ++ ++ ++#endif /* _ASM_MXU_H */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_common_include_mxu_media.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_common_include_mxu_media.h.patch new file mode 100644 index 00000000..6a1307cf --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_common_include_mxu_media.h.patch @@ -0,0 +1,1836 @@ +diff -drupN a/arch/mips/xburst/common/include/mxu_media.h b/arch/mips/xburst/common/include/mxu_media.h +--- a/arch/mips/xburst/common/include/mxu_media.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/common/include/mxu_media.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,1832 @@ ++#ifndef _MXU_H_ ++#define _MXU_H_ ++ ++#define xr00 ++#define xr11 ++#define xr22 ++#define xr33 ++#define xr44 ++#define xr55 ++#define xr66 ++#define xr77 ++#define xr88 ++#define xr99 ++#define xr1010 ++#define xr1111 ++#define xr1212 ++#define xr1313 ++#define xr1414 ++#define xr1515 ++#define xr1616 ++ ++#define ptn00 ++#define ptn11 ++#define ptn22 ++#define ptn33 ++#define ptn44 ++#define ptn55 ++#define ptn66 ++#define ptn77 ++ ++/***********************************LD/SD***********************************/ ++#define S32LDD(xra,rb,s12) \ ++ do{ \ ++ __asm____volatile("S32LDDxr%0,%z1,%2" \ ++ : \ ++ :"K"(xra),"d"(rb),"I"(s12)); \ ++ }while(0) ++ ++#define S32STD(xra,rb,s12) \ ++ do{ \ ++ __asm____volatile("S32STDxr%0,%z1,%2" \ ++ : \ ++ :"K"(xra),"d"(rb),"I"(s12):"memory"); \ ++ }while(0) ++ ++#define S32LDDV(xra,rb,rc,strd2) \ ++ do{ \ ++ __asm____volatile("S32LDDVxr%0,%z1,%z2,%3" \ ++ : \ ++ :"K"(xra),"d"(rb),"d"(rc),"K"(strd2)); \ ++ }while(0) ++ ++#define S32STDV(xra,rb,rc,strd2) \ ++ do{ \ ++ __asm____volatile("S32STDVxr%0,%z1,%z2,%3" \ ++ : \ ++ :"K"(xra),"d"(rb),"d"(rc),"K"(strd2):"memory"); \ ++ }while(0) ++ ++#define S32LDI(xra,rb,s12) \ ++ do{ \ ++ __asm____volatile("S32LDIxr%1,%z0,%2" \ ++ :"+d"(rb) \ ++ :"K"(xra),"I"(s12)); \ ++ }while(0) ++ ++#define S32SDI(xra,rb,s12) \ ++ do{ \ ++ __asm____volatile("S32SDIxr%1,%z0,%2" \ ++ :"+d"(rb) \ ++ :"K"(xra),"I"(s12):"memory"); \ ++ }while(0) ++ ++#define S32LDIV(xra,rb,rc,strd2) \ ++ do{ \ ++ __asm____volatile("S32LDIVxr%1,%z0,%z2,%3" \ ++ :"+d"(rb) \ ++ :"K"(xra),"d"(rc),"K"(strd2)); \ ++ }while(0) ++ ++#define S32SDIV(xra,rb,rc,strd2) \ ++ do{ \ ++ __asm____volatile("S32SDIVxr%1,%z0,%z2,%3" \ ++ :"+d"(rb) \ ++ :"K"(xra),"d"(rc),"K"(strd2):"memory"); \ ++ }while(0) ++//MXUenhancement ++#define S32LDDR(xra,rb,s12) \ ++ do{ \ ++ __asm____volatile("S32LDDRxr%0,%z1,%2" \ ++ : \ ++ :"K"(xra),"d"(rb),"I"(s12)); \ ++ }while(0) ++ ++#define S32STDR(xra,rb,s12) \ ++ do{ \ ++ __asm____volatile("S32STDRxr%0,%z1,%2" \ ++ : \ ++ :"K"(xra),"d"(rb),"I"(s12):"memory"); \ ++ }while(0) ++ ++#define S32LDDVR(xra,rb,rc,strd2) \ ++ do{ \ ++ __asm____volatile("S32LDDVRxr%0,%z1,%z2,%3" \ ++ : \ ++ :"K"(xra),"d"(rb),"d"(rc),"K"(strd2)); \ ++ }while(0) ++ ++#define S32STDVR(xra,rb,rc,strd2) \ ++ do{ \ ++ __asm____volatile("S32STDVRxr%0,%z1,%z2,%3" \ ++ : \ ++ :"K"(xra),"d"(rb),"d"(rc),"K"(strd2):"memory"); \ ++ }while(0) ++ ++#define S32LDIR(xra,rb,s12) \ ++ do{ \ ++ __asm____volatile("S32LDIRxr%1,%z0,%2" \ ++ :"+d"(rb) \ ++ :"K"(xra),"I"(s12)); \ ++ }while(0) ++ ++#define S32SDIR(xra,rb,s12) \ ++ do{ \ ++ __asm____volatile("S32SDIRxr%1,%z0,%2" \ ++ :"+d"(rb) \ ++ :"K"(xra),"I"(s12):"memory"); \ ++ }while(0) ++ ++#define S32LDIVR(xra,rb,rc,strd2) \ ++ do{ \ ++ __asm____volatile("S32LDIVRxr%1,%z0,%z2,%3" \ ++ :"+d"(rb) \ ++ :"K"(xra),"d"(rc),"K"(strd2)); \ ++ }while(0) ++ ++#define S32SDIVR(xra,rb,rc,strd2) \ ++ do{ \ ++ __asm____volatile("S32SDIVRxr%1,%z0,%z2,%3" \ ++ :"+d"(rb) \ ++ :"K"(xra),"d"(rc),"K"(strd2):"memory"); \ ++ }while(0) ++ ++#define S8LDD(xra,rb,s8,optn3) \ ++ do{ \ ++ __asm____volatile("S8LDDxr%0,%z1,%2,ptn%3" \ ++ : \ ++ :"K"(xra),"d"(rb),"I"(s8),"K"(optn3)); \ ++ }while(0) ++ ++#define S8STD(xra,rb,s8,optn3) \ ++ do{ \ ++ __asm____volatile("S8STDxr%0,%z1,%2,ptn%3" \ ++ : \ ++ :"K"(xra),"d"(rb),"I"(s8),"K"(optn3):"memory"); \ ++ }while(0) ++ ++#define S8LDI(xra,rb,s8,optn3) \ ++ do{ \ ++ __asm____volatile("S8LDIxr%1,%z0,%2,ptn%3" \ ++ :"+d"(rb) \ ++ :"K"(xra),"I"(s8),"K"(optn3)); \ ++ }while(0) ++ ++#define S8SDI(xra,rb,s8,optn3) \ ++ do{ \ ++ __asm____volatile("S8SDIxr%1,%z0,%2,ptn%3" \ ++ :"+d"(rb) \ ++ :"K"(xra),"I"(s8),"K"(optn3):"memory"); \ ++ }while(0) ++ ++#define S16LDD(xra,rb,s10,optn2) \ ++ do{ \ ++ __asm____volatile("S16LDDxr%0,%z1,%2,ptn%3" \ ++ : \ ++ :"K"(xra),"d"(rb),"I"(s10),"K"(optn2)); \ ++ }while(0) ++ ++#define S16STD(xra,rb,s10,optn2) \ ++ do{ \ ++ __asm____volatile("S16STDxr%0,%z1,%2,ptn%3" \ ++ : \ ++ :"K"(xra),"d"(rb),"I"(s10),"K"(optn2):"memory"); \ ++ }while(0) ++ ++#define S16LDI(xra,rb,s10,optn2) \ ++ do{ \ ++ __asm____volatile("S16LDIxr%1,%z0,%2,ptn%3" \ ++ :"+d"(rb) \ ++ :"K"(xra),"I"(s10),"K"(optn2)); \ ++ }while(0) ++ ++#define S16SDI(xra,rb,s10,optn2) \ ++ do{ \ ++ __asm____volatile("S16SDIxr%1,%z0,%2,ptn%3" \ ++ :"+d"(rb) \ ++ :"K"(xra),"I"(s10),"K"(optn2):"memory"); \ ++ }while(0) ++ ++#define LXW(rb,rc,strd2) \ ++ ({ \ ++ unsignedint_dst_; \ ++ __asm____volatile("LXW%0,%1,%2,%3":"=d"(_dst_):"d"(rb),"d"(rc),"K"(strd2)); \ ++ _dst_; \ ++ }) ++ ++#define LXH(rb,rc,strd2) \ ++ ({ \ ++ unsignedint_dst_; \ ++ __asm____volatile("LXH%0,%1,%2,%3":"=d"(_dst_):"d"(rb),"d"(rc),"K"(strd2)); \ ++ _dst_; \ ++ }) ++ ++#define LXHU(rb,rc,strd2) \ ++ ({ \ ++ unsignedint_dst_; \ ++ __asm____volatile("LXHU%0,%1,%2,%3":"=d"(_dst_):"d"(rb),"d"(rc),"K"(strd2)); \ ++ _dst_; \ ++ }) ++ ++#define LXB(rb,rc,strd2) \ ++ ({ \ ++ unsignedint_dst_; \ ++ __asm____volatile("LXB%0,%1,%2,%3":"=d"(_dst_):"d"(rb),"d"(rc),"K"(strd2)); \ ++ _dst_; \ ++ }) ++ ++#define LXBU(rb,rc,strd2) \ ++ ({ \ ++ unsignedint_dst_; \ ++ __asm____volatile("LXBU%0,%1,%2,%3":"=d"(_dst_):"d"(rb),"d"(rc),"K"(strd2)); \ ++ _dst_; \ ++ }) ++/***********************************D16MUL***********************************/ ++#define D16MUL_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MULxr%0,xr%1,xr%2,xr%3,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MUL_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MULxr%0,xr%1,xr%2,xr%3,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MUL_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MULxr%0,xr%1,xr%2,xr%3,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MUL_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MULxr%0,xr%1,xr%2,xr%3,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++ ++/**********************************D16MULF*******************************/ ++#define D16MULF_WW(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("D16MULFxr%0,xr%1,xr%2,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define D16MULF_LW(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("D16MULFxr%0,xr%1,xr%2,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define D16MULF_HW(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("D16MULFxr%0,xr%1,xr%2,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define D16MULF_XW(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("D16MULFxr%0,xr%1,xr%2,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++//MXUenhancement ++#define D16MULE_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MULExr%0,xr%1,xr%2,xr%3,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MULE_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MULExr%0,xr%1,xr%2,xr%3,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MULE_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MULExr%0,xr%1,xr%2,xr%3,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MULE_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MULExr%0,xr%1,xr%2,xr%3,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++/***********************************D16MAC********************************/ ++#define D16MAC_AA_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACxr%0,xr%1,xr%2,xr%3,AA,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MAC_AA_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACxr%0,xr%1,xr%2,xr%3,AA,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MAC_AA_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACxr%0,xr%1,xr%2,xr%3,AA,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MAC_AA_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACxr%0,xr%1,xr%2,xr%3,AA,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MAC_AS_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACxr%0,xr%1,xr%2,xr%3,AS,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MAC_AS_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACxr%0,xr%1,xr%2,xr%3,AS,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MAC_AS_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACxr%0,xr%1,xr%2,xr%3,AS,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MAC_AS_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACxr%0,xr%1,xr%2,xr%3,AS,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MAC_SA_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACxr%0,xr%1,xr%2,xr%3,SA,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MAC_SA_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACxr%0,xr%1,xr%2,xr%3,SA,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MAC_SA_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACxr%0,xr%1,xr%2,xr%3,SA,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MAC_SA_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACxr%0,xr%1,xr%2,xr%3,SA,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MAC_SS_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACxr%0,xr%1,xr%2,xr%3,SS,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MAC_SS_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACxr%0,xr%1,xr%2,xr%3,SS,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MAC_SS_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACxr%0,xr%1,xr%2,xr%3,SS,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MAC_SS_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACxr%0,xr%1,xr%2,xr%3,SS,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++ ++/**********************************D16MACF*******************************/ ++#define D16MACF_AA_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACFxr%0,xr%1,xr%2,xr%3,AA,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACF_AA_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACFxr%0,xr%1,xr%2,xr%3,AA,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACF_AA_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACFxr%0,xr%1,xr%2,xr%3,AA,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACF_AA_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACFxr%0,xr%1,xr%2,xr%3,AA,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACF_AS_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACFxr%0,xr%1,xr%2,xr%3,AS,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACF_AS_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACFxr%0,xr%1,xr%2,xr%3,AS,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACF_AS_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACFxr%0,xr%1,xr%2,xr%3,AS,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACF_AS_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACFxr%0,xr%1,xr%2,xr%3,AS,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACF_SA_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACFxr%0,xr%1,xr%2,xr%3,SA,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACF_SA_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACFxr%0,xr%1,xr%2,xr%3,SA,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACF_SA_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACFxr%0,xr%1,xr%2,xr%3,SA,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACF_SA_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACFxr%0,xr%1,xr%2,xr%3,SA,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACF_SS_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACFxr%0,xr%1,xr%2,xr%3,SS,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACF_SS_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACFxr%0,xr%1,xr%2,xr%3,SS,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACF_SS_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACFxr%0,xr%1,xr%2,xr%3,SS,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACF_SS_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACFxr%0,xr%1,xr%2,xr%3,SS,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++//MXUenhancement ++/**********************************D16MACE*******************************/ ++#define D16MACE_AA_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACExr%0,xr%1,xr%2,xr%3,AA,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACE_AA_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACExr%0,xr%1,xr%2,xr%3,AA,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACE_AA_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACExr%0,xr%1,xr%2,xr%3,AA,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACE_AA_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACExr%0,xr%1,xr%2,xr%3,AA,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACE_AS_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACExr%0,xr%1,xr%2,xr%3,AS,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACE_AS_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACExr%0,xr%1,xr%2,xr%3,AS,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACE_AS_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACExr%0,xr%1,xr%2,xr%3,AS,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACE_AS_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACExr%0,xr%1,xr%2,xr%3,AS,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACE_SA_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACExr%0,xr%1,xr%2,xr%3,SA,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACE_SA_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACExr%0,xr%1,xr%2,xr%3,SA,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACE_SA_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACExr%0,xr%1,xr%2,xr%3,SA,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACE_SA_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACExr%0,xr%1,xr%2,xr%3,SA,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACE_SS_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACExr%0,xr%1,xr%2,xr%3,SS,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACE_SS_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACExr%0,xr%1,xr%2,xr%3,SS,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACE_SS_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACExr%0,xr%1,xr%2,xr%3,SS,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACE_SS_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACExr%0,xr%1,xr%2,xr%3,SS,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++ ++/**********************************D16MADL*******************************/ ++#define D16MADL_AA_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MADLxr%0,xr%1,xr%2,xr%3,AA,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MADL_AA_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MADLxr%0,xr%1,xr%2,xr%3,AA,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MADL_AA_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MADLxr%0,xr%1,xr%2,xr%3,AA,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MADL_AA_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MADLxr%0,xr%1,xr%2,xr%3,AA,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MADL_AS_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MADLxr%0,xr%1,xr%2,xr%3,AS,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MADL_AS_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MADLxr%0,xr%1,xr%2,xr%3,AS,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MADL_AS_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MADLxr%0,xr%1,xr%2,xr%3,AS,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MADL_AS_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MADLxr%0,xr%1,xr%2,xr%3,AS,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MADL_SA_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MADLxr%0,xr%1,xr%2,xr%3,SA,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MADL_SA_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MADLxr%0,xr%1,xr%2,xr%3,SA,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MADL_SA_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MADLxr%0,xr%1,xr%2,xr%3,SA,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MADL_SA_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MADLxr%0,xr%1,xr%2,xr%3,SA,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MADL_SS_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MADLxr%0,xr%1,xr%2,xr%3,SS,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MADL_SS_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MADLxr%0,xr%1,xr%2,xr%3,SS,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MADL_SS_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MADLxr%0,xr%1,xr%2,xr%3,SS,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MADL_SS_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MADLxr%0,xr%1,xr%2,xr%3,SS,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++ ++/***********************************S16MAD*******************************/ ++#define S16MAD_A_HH(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("S16MADxr%0,xr%1,xr%2,xr%3,A,0" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define S16MAD_A_LL(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("S16MADxr%0,xr%1,xr%2,xr%3,A,1" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define S16MAD_A_HL(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("S16MADxr%0,xr%1,xr%2,xr%3,A,2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define S16MAD_A_LH(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("S16MADxr%0,xr%1,xr%2,xr%3,A,3" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define S16MAD_S_HH(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("S16MADxr%0,xr%1,xr%2,xr%3,S,0" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define S16MAD_S_LL(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("S16MADxr%0,xr%1,xr%2,xr%3,S,1" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define S16MAD_S_HL(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("S16MADxr%0,xr%1,xr%2,xr%3,S,2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define S16MAD_S_LH(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("S16MADxr%0,xr%1,xr%2,xr%3,S,3" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++ ++ ++/***********************************Q8MUL********************************/ ++#define Q8MUL(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8MULxr%0,xr%1,xr%2,xr%3" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++//MXUenhancement ++#define Q8MULSU(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8MULSUxr%0,xr%1,xr%2,xr%3" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++ ++/***********************************Q8MAC********************************/ ++#define Q8MAC_AA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8MACxr%0,xr%1,xr%2,xr%3,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q8MAC_AS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8MACxr%0,xr%1,xr%2,xr%3,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q8MAC_SA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8MACxr%0,xr%1,xr%2,xr%3,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q8MAC_SS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8MACxr%0,xr%1,xr%2,xr%3,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++//MXUenhancement ++#define Q8MACSU_AA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8MACSUxr%0,xr%1,xr%2,xr%3,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q8MACSU_AS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8MACSUxr%0,xr%1,xr%2,xr%3,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q8MACSU_SA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8MACSUxr%0,xr%1,xr%2,xr%3,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q8MACSU_SS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8MACSUxr%0,xr%1,xr%2,xr%3,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++/***********************************Q8MADL********************************/ ++#define Q8MADL_AA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8MADLxr%0,xr%1,xr%2,xr%3,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q8MADL_AS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8MADLxr%0,xr%1,xr%2,xr%3,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q8MADL_SA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8MADLxr%0,xr%1,xr%2,xr%3,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q8MADL_SS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8MADLxr%0,xr%1,xr%2,xr%3,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++ ++/***********************************D32ADD********************************/ ++#define D32ADD_AA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D32ADDxr%0,xr%1,xr%2,xr%3,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D32ADD_AS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D32ADDxr%0,xr%1,xr%2,xr%3,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D32ADD_SA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D32ADDxr%0,xr%1,xr%2,xr%3,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D32ADD_SS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D32ADDxr%0,xr%1,xr%2,xr%3,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++ ++/***********************************D32ACC********************************/ ++#define D32ACC_AA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D32ACCxr%0,xr%1,xr%2,xr%3,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D32ACC_AS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D32ACCxr%0,xr%1,xr%2,xr%3,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D32ACC_SA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D32ACCxr%0,xr%1,xr%2,xr%3,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D32ACC_SS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D32ACCxr%0,xr%1,xr%2,xr%3,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++//MXUenhancement ++#define D32ACCM_AA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D32ACCMxr%0,xr%1,xr%2,xr%3,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D32ACCM_AS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D32ACCMxr%0,xr%1,xr%2,xr%3,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D32ACCM_SA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D32ACCMxr%0,xr%1,xr%2,xr%3,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D32ACCM_SS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D32ACCMxr%0,xr%1,xr%2,xr%3,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D32ASUM_AA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D32ASUMxr%0,xr%1,xr%2,xr%3,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D32ASUM_AS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D32ASUMxr%0,xr%1,xr%2,xr%3,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D32ASUM_SA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D32ASUMxr%0,xr%1,xr%2,xr%3,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D32ASUM_SS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D32ASUMxr%0,xr%1,xr%2,xr%3,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++ ++/***********************************S32CPS********************************/ ++#define S32CPS(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("S32CPSxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++//MXUenhancement ++#define S32SLT(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("S32SLTxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define S32MOVZ(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("S32MOVZxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define S32MOVN(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("S32MOVNxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define S32AND(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("S32ANDxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define S32OR(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("S32ORxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define S32XOR(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("S32XORxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define S32NOR(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("S32NORxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define S32ABS(xra,xrb) \ ++ do{ \ ++ __asm____volatile("S32CPSxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrb)); \ ++ }while(0) ++ ++/***********************************Q16ADD********************************/ ++#define Q16ADD_AA_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ADDxr%0,xr%1,xr%2,xr%3,AA,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ADD_AA_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ADDxr%0,xr%1,xr%2,xr%3,AA,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ADD_AA_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ADDxr%0,xr%1,xr%2,xr%3,AA,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ADD_AA_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ADDxr%0,xr%1,xr%2,xr%3,AA,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++#define Q16ADD_AS_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ADDxr%0,xr%1,xr%2,xr%3,AS,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ADD_AS_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ADDxr%0,xr%1,xr%2,xr%3,AS,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ADD_AS_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ADDxr%0,xr%1,xr%2,xr%3,AS,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ADD_AS_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ADDxr%0,xr%1,xr%2,xr%3,AS,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ADD_SA_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ADDxr%0,xr%1,xr%2,xr%3,SA,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ADD_SA_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ADDxr%0,xr%1,xr%2,xr%3,SA,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ADD_SA_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ADDxr%0,xr%1,xr%2,xr%3,SA,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ADD_SA_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ADDxr%0,xr%1,xr%2,xr%3,SA,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ADD_SS_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ADDxr%0,xr%1,xr%2,xr%3,SS,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ADD_SS_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ADDxr%0,xr%1,xr%2,xr%3,SS,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ADD_SS_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ADDxr%0,xr%1,xr%2,xr%3,SS,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ADD_SS_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ADDxr%0,xr%1,xr%2,xr%3,SS,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++ ++/***********************************Q16ACC********************************/ ++#define Q16ACC_AA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ACCxr%0,xr%1,xr%2,xr%3,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ACC_AS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ACCxr%0,xr%1,xr%2,xr%3,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ACC_SA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ACCxr%0,xr%1,xr%2,xr%3,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ACC_SS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ACCxr%0,xr%1,xr%2,xr%3,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++//MXUenhancement ++#define Q16ACCM_AA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ACCMxr%0,xr%1,xr%2,xr%3,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ACCM_AS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ACCMxr%0,xr%1,xr%2,xr%3,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ACCM_SA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ACCMxr%0,xr%1,xr%2,xr%3,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ACCM_SS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ACCMxr%0,xr%1,xr%2,xr%3,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ASUM_AA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ASUMxr%0,xr%1,xr%2,xr%3,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ASUM_AS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ASUMxr%0,xr%1,xr%2,xr%3,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ASUM_SA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ASUMxr%0,xr%1,xr%2,xr%3,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ASUM_SS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ASUMxr%0,xr%1,xr%2,xr%3,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++/***********************************D16CPS********************************/ ++#define D16CPS(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("D16CPSxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++//MXUenhancement ++#define D16SLT(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("D16SLTxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define D16MOVZ(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("D16MOVZxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define D16MOVN(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("D16MOVNxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define D16ABS(xra,xrb) \ ++ do{ \ ++ __asm____volatile("D16CPSxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrb)); \ ++ }while(0) ++ ++/*******************************D16ASUM************************************/ ++#define D16ASUM_AA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16ASUMxr%0,xr%1,xr%2,xr%3,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++#define D16ASUM_AS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16ASUMxr%0,xr%1,xr%2,xr%3,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++#define D16ASUM_SA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16ASUMxr%0,xr%1,xr%2,xr%3,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++#define D16ASUM_SS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16ASUMxr%0,xr%1,xr%2,xr%3,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++/*******************************D16AVG/D16AVGR*****************************/ ++#define D16AVG(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("D16AVGxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++#define D16AVGR(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("D16AVGRxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++/************************************Q8ADD********************************/ ++#define Q8ADD_AA(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("Q8ADDxr%0,xr%1,xr%2,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define Q8ADD_AS(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("Q8ADDxr%0,xr%1,xr%2,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define Q8ADD_SA(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("Q8ADDxr%0,xr%1,xr%2,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define Q8ADD_SS(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("Q8ADDxr%0,xr%1,xr%2,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++ ++/************************************Q8ADDE********************************/ ++#define Q8ADDE_AA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8ADDExr%0,xr%1,xr%2,xr%3,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q8ADDE_AS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8ADDExr%0,xr%1,xr%2,xr%3,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q8ADDE_SA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8ADDExr%0,xr%1,xr%2,xr%3,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q8ADDE_SS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8ADDExr%0,xr%1,xr%2,xr%3,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++/************************************Q8ACCE********************************/ ++#define Q8ACCE_AA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8ACCExr%0,xr%1,xr%2,xr%3,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q8ACCE_AS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8ACCExr%0,xr%1,xr%2,xr%3,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q8ACCE_SA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8ACCExr%0,xr%1,xr%2,xr%3,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q8ACCE_SS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8ACCExr%0,xr%1,xr%2,xr%3,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++ ++/************************************Q8ABD********************************/ ++#define Q8ABD(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("Q8ABDxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++ ++/************************************Q8SLT********************************/ ++#define Q8SLT(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("Q8SLTxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++//MXUenhancement ++#define Q8SLTU(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("Q8SLTUxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define Q8MOVZ(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("Q8MOVZxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define Q8MOVN(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("Q8MOVNxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define D8SUM(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("D8SUMxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define D8SUMC(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("D8SUMCxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++/************************************Q8SAD********************************/ ++#define Q8SAD(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8SADxr%0,xr%1,xr%2,xr%3" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++/************************************Q16SCOP******************************/ ++#define Q16SCOP(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16SCOPxr%0,xr%1,xr%2,xr%3" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++/********************************Q8AVG/Q8AVGR*****************************/ ++#define Q8AVG(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("Q8AVGxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++#define Q8AVGR(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("Q8AVGRxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++ ++/**********************************D32SHIFT******************************/ ++#define D32SLL(xra,xrb,xrc,xrd,SFT4) \ ++ do{ \ ++ __asm____volatile("D32SLLxr%0,xr%1,xr%2,xr%3,%4" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd),"K"(SFT4)); \ ++ }while(0) ++ ++#define D32SLR(xra,xrb,xrc,xrd,SFT4) \ ++ do{ \ ++ __asm____volatile("D32SLRxr%0,xr%1,xr%2,xr%3,%4" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd),"K"(SFT4)); \ ++ }while(0) ++ ++#define D32SAR(xra,xrb,xrc,xrd,SFT4) \ ++ do{ \ ++ __asm____volatile("D32SARxr%0,xr%1,xr%2,xr%3,%4" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd),"K"(SFT4)); \ ++ }while(0) ++ ++#define D32SARL(xra,xrb,xrc,SFT4) \ ++ do{ \ ++ __asm____volatile("D32SARLxr%0,xr%1,xr%2,%3" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(SFT4)); \ ++ }while(0) ++ ++#define D32SLLV(xra,xrd,rb) \ ++ do{ \ ++ __asm____volatile("D32SLLVxr%0,xr%1,%z2" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d"(rb)); \ ++ }while(0) ++ ++#define D32SLRV(xra,xrd,rb) \ ++ do{ \ ++ __asm____volatile("D32SLRVxr%0,xr%1,%z2" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d"(rb)); \ ++ }while(0) ++ ++#define D32SARV(xra,xrd,rb) \ ++ do{ \ ++ __asm____volatile("D32SARVxr%0,xr%1,%z2" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d"(rb)); \ ++ }while(0) ++ ++#define D32SARW(xra,xrb,xrc,rb) \ ++ do{ \ ++ __asm____volatile("D32SARWxr%0,xr%1,xr%2,%3" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"d"(rb)); \ ++ }while(0) ++ ++ ++/**********************************Q16SHIFT******************************/ ++#define Q16SLL(xra,xrb,xrc,xrd,SFT4) \ ++ do{ \ ++ __asm____volatile("Q16SLLxr%0,xr%1,xr%2,xr%3,%4" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd),"K"(SFT4)); \ ++ }while(0) ++ ++#define Q16SLR(xra,xrb,xrc,xrd,SFT4) \ ++ do{ \ ++ __asm____volatile("Q16SLRxr%0,xr%1,xr%2,xr%3,%4" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd),"K"(SFT4)); \ ++ }while(0) ++ ++#define Q16SAR(xra,xrb,xrc,xrd,SFT4) \ ++ do{ \ ++ __asm____volatile("Q16SARxr%0,xr%1,xr%2,xr%3,%4" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd),"K"(SFT4)); \ ++ }while(0) ++ ++#define Q16SLLV(xra,xrd,rb) \ ++ do{ \ ++ __asm____volatile("Q16SLLVxr%0,xr%1,%z2" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d"(rb)); \ ++ }while(0) ++ ++#define Q16SLRV(xra,xrd,rb) \ ++ do{ \ ++ __asm____volatile("Q16SLRVxr%0,xr%1,%z2" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d"(rb)); \ ++ }while(0) ++ ++#define Q16SARV(xra,xrd,rb) \ ++ do{ \ ++ __asm____volatile("Q16SARVxr%0,xr%1,%z2" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d"(rb)); \ ++ }while(0) ++ ++ ++/*********************************MAX/MIN*********************************/ ++#define S32MAX(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("S32MAXxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define S32MIN(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("S32MINxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define D16MAX(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("D16MAXxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define D16MIN(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("D16MINxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define Q8MAX(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("Q8MAXxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define Q8MIN(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("Q8MINxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++ ++/*************************************MOVE********************************/ ++#define S32I2M(xra,rb) \ ++ do{ \ ++ __asm____volatile("S32I2Mxr%0,%z1" \ ++ : \ ++ :"K"(xra),"d"(rb)); \ ++ }while(0) ++ ++#define S32M2I(xra) \ ++ __extension__({ \ ++ int__d; \ ++ __asm____volatile("S32M2Ixr%1,%0" \ ++ :"=d"(__d) \ ++ :"K"(xra)); \ ++ __d; \ ++ }) ++ ++ ++/*********************************S32SFL**********************************/ ++#define S32SFL(xra,xrb,xrc,xrd,optn2) \ ++ do{ \ ++ __asm____volatile("S32SFLxr%0,xr%1,xr%2,xr%3,ptn%4" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd),"K"(optn2)); \ ++ }while(0) ++ ++//MXUenhancement ++#define S32ALNI(xra,xrb,xrc,optn3) \ ++ do{ \ ++ __asm____volatile("S32ALNIxr%0,xr%1,xr%2,ptn%3" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(optn3)); \ ++ }while(0) ++ ++#define S32LUI(xra,s8,optn3) \ ++ do{ \ ++ __asm____volatile("S32LUIxr%0,%1,ptn%2" \ ++ : \ ++ :"K"(xra),"I"(s8),"K"(optn3)); \ ++ }while(0) ++ ++ ++/*********************************S32ALN**********************************/ ++#define S32ALN(xra,xrb,xrc,rs) \ ++ do{ \ ++ __asm____volatile("S32ALNxr%0,xr%1,xr%2,%z3" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"d"(rs)); \ ++ }while(0) ++ ++ ++/*********************************Q16SAT**********************************/ ++#define Q16SAT(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("Q16SATxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define S32EXTR(xra,xrd,rs,bits5) \ ++ do{ \ ++ __asm____volatile("S32EXTRxr%0,xr%1,%z2,%3" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d"(rs),"I"(bits5)); \ ++ }while(0) ++ ++#define S32EXTRV(xra,xrd,rs,rt) \ ++ do{ \ ++ __asm____volatile("S32EXTRVxr%0,xr%1,%z2,%z3" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d"(rs),"d"(rt)); \ ++ }while(0) ++ ++/*********************************S32MUL**********************************/ ++#define S32MUL(xra,xrd,rs,rt) \ ++ do{ \ ++ __asm____volatile("S32MULxr%0,xr%1,%z2,%z3" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d"(rs),"d"(rt)); \ ++ }while(0) ++ ++#define S32MULU(xra,xrd,rs,rt) \ ++ do{ \ ++ __asm____volatile("S32MULUxr%0,xr%1,%z2,%z3" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d"(rs),"d"(rt)); \ ++ }while(0) ++ ++#define S32MADD(xra,xrd,rs,rt) \ ++ do{ \ ++ __asm____volatile("S32MADDxr%0,xr%1,%z2,%z3" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d"(rs),"d"(rt)); \ ++ }while(0) ++ ++#define S32MADDU(xra,xrd,rs,rt) \ ++ do{ \ ++ __asm____volatile("S32MADDUxr%0,xr%1,%z2,%z3" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d"(rs),"d"(rt)); \ ++ }while(0) ++ ++#define S32MSUB(xra,xrd,rs,rt) \ ++ do{ \ ++ __asm____volatile("S32MSUBxr%0,xr%1,%z2,%z3" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d"(rs),"d"(rt)); \ ++ }while(0) ++ ++#define S32MSUBU(xra,xrd,rs,rt) \ ++ do{ \ ++ __asm____volatile("S32MSUBUxr%0,xr%1,%z2,%z3" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d"(rs),"d"(rt)); \ ++ }while(0) ++ ++#endif/*_MXU_H_*/ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_common_initrd-check.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_common_initrd-check.c.patch new file mode 100644 index 00000000..9e767134 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_common_initrd-check.c.patch @@ -0,0 +1,53 @@ +diff -drupN a/arch/mips/xburst/common/initrd-check.c b/arch/mips/xburst/common/initrd-check.c +--- a/arch/mips/xburst/common/initrd-check.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/common/initrd-check.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,49 @@ ++ ++#include ++#include ++#include ++#include ++ ++static void check_file(char *fname) ++{ ++ int err; ++ pr_info("check file %s ... ",fname); ++ err = sys_access((const char __user *) fname, O_RDONLY); ++ if (err < 0) ++ pr_info("failed %d.\n", err); ++ else ++ pr_info("successed.\n"); ++} ++ ++static int __init check_rootfs(void) ++{ ++ int err; ++ ++ if (sys_access((const char __user *) "/dev", O_RDWR) < 0) { ++ pr_info("Dir /dev is not exist.\n"); ++ sys_mkdir((const char __user *) "/dev", O_RDWR); ++ } ++ ++ if (sys_access((const char __user *) "/dev/console", O_RDWR) < 0) { ++ printk("create /dev/console\n"); ++ err = sys_mknod((const char __user __force *) "/dev/console", ++ S_IFCHR | S_IRUSR | S_IWUSR, ++ new_encode_dev(MKDEV(5, 1))); ++ if (err < 0) ++ goto out; ++ } ++ ++ check_file("/linuxrc"); ++ check_file("/init"); ++ check_file("/init.rc"); ++ check_file("/sbin/adbd"); ++ check_file("/bin/busybox"); ++ ++ return 0; ++ ++out: ++ printk(KERN_WARNING "Failed to create dev\n"); ++ return err; ++} ++ ++late_initcall(check_rootfs); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_common_jz_notifier.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_common_jz_notifier.c.patch new file mode 100644 index 00000000..8320024c --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_common_jz_notifier.c.patch @@ -0,0 +1,87 @@ +diff -drupN a/arch/mips/xburst/common/jz_notifier.c b/arch/mips/xburst/common/jz_notifier.c +--- a/arch/mips/xburst/common/jz_notifier.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/common/jz_notifier.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,83 @@ ++#include ++ ++static BLOCKING_NOTIFIER_HEAD(jz_notifier_chain_high); ++static BLOCKING_NOTIFIER_HEAD(jz_notifier_chain_normal); ++static BLOCKING_NOTIFIER_HEAD(jz_notifier_chain_low); ++static int jz_notifier(struct notifier_block *nb, unsigned long cmd, void *data) ++{ ++ struct jz_notifier *jz_nb = container_of(nb,struct jz_notifier,nb); ++ int ret = 0; ++ if(jz_nb->msg == cmd) { ++ ret = jz_nb->jz_notify(jz_nb,data); ++ } ++ return ret; ++} ++ ++int jz_notifier_register(struct jz_notifier *notify, unsigned int priority) ++{ ++ unsigned int ret = 0; ++ ++ if((notify->level < NOTEFY_PROI_START) && (notify->level >= NOTEFY_PROI_END)) ++ { ++ printk("notify level can not support this %d\n",notify->level); ++ dump_stack(); ++ return -1; ++ } ++ if((int)notify->msg >= JZ_CMD_END && (int)notify->msg <= JZ_CMD_START) ++ { ++ printk("notify msg can not support this %d\n",notify->msg); ++ dump_stack(); ++ return -1; ++ } ++ if(notify->jz_notify == NULL) ++ { ++ printk("notify function(jz_notify) cand not support NULL\n"); ++ dump_stack(); ++ return -1; ++ } ++ notify->nb.priority = notify->level; ++ notify->nb.notifier_call = jz_notifier; ++ ++ if(priority == NOTEFY_PROI_HIGH) ++ ret = blocking_notifier_chain_register(&jz_notifier_chain_high, ¬ify->nb); ++ else if(priority == NOTEFY_PROI_NORMAL) ++ ret = blocking_notifier_chain_register(&jz_notifier_chain_normal, ¬ify->nb); ++ else if(priority == NOTEFY_PROI_LOW) ++ ret = blocking_notifier_chain_register(&jz_notifier_chain_low, ¬ify->nb); ++ else ++ printk("not support\n"); ++ return ret; ++} ++EXPORT_SYMBOL(jz_notifier_register); ++ ++int jz_notifier_unregister(struct jz_notifier *notify, unsigned int priority) ++{ ++ unsigned int ret = 0; ++ ++ if(priority == NOTEFY_PROI_HIGH) ++ ret = blocking_notifier_chain_unregister(&jz_notifier_chain_high, ¬ify->nb); ++ else if(priority == NOTEFY_PROI_NORMAL) ++ ret = blocking_notifier_chain_unregister(&jz_notifier_chain_normal, ¬ify->nb); ++ else if(priority == NOTEFY_PROI_LOW) ++ ret = blocking_notifier_chain_unregister(&jz_notifier_chain_low, ¬ify->nb); ++ else ++ printk("not support\n"); ++ return ret; ++} ++EXPORT_SYMBOL(jz_notifier_unregister); ++ ++int jz_notifier_call(unsigned int priority, unsigned long val, void *v) ++{ ++ unsigned int ret = 0; ++ ++ if(priority == NOTEFY_PROI_HIGH) ++ ret = blocking_notifier_call_chain(&jz_notifier_chain_high, val, v); ++ else if(priority == NOTEFY_PROI_NORMAL) ++ ret = blocking_notifier_call_chain(&jz_notifier_chain_normal, val, v); ++ else if(priority == NOTEFY_PROI_LOW) ++ ret = blocking_notifier_call_chain(&jz_notifier_chain_low, val, v); ++ else ++ printk("not support\n"); ++ return ret; ++} ++EXPORT_SYMBOL(jz_notifier_call); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_common_mxu-xburst.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_common_mxu-xburst.c.patch new file mode 100644 index 00000000..e3b8ca2e --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_common_mxu-xburst.c.patch @@ -0,0 +1,87 @@ +diff -drupN a/arch/mips/xburst/common/mxu-xburst.c b/arch/mips/xburst/common/mxu-xburst.c +--- a/arch/mips/xburst/common/mxu-xburst.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/common/mxu-xburst.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,83 @@ ++#include ++#include ++#include ++ ++void __save_mxu(void *tsk_void) ++{ ++ register unsigned int reg_val asm("t0"); ++ struct task_struct *tsk = tsk_void; ++ struct xburst_mxu_struct *mxu = tsk->thread.mxu; ++ asm volatile(".word 0x7008042e \n\t"); ++ mxu->vpr[0] = reg_val; ++ asm volatile(".word 0x7008006e \n\t"); ++ mxu->vpr[1] = reg_val; ++ asm volatile(".word 0x700800ae \n\t"); ++ mxu->vpr[2] = reg_val; ++ asm volatile(".word 0x700800ee \n\t"); ++ mxu->vpr[3] = reg_val; ++ asm volatile(".word 0x7008012e \n\t"); ++ mxu->vpr[4] = reg_val; ++ asm volatile(".word 0x7008016e \n\t"); ++ mxu->vpr[5] = reg_val; ++ asm volatile(".word 0x700801ae \n\t"); ++ mxu->vpr[6] = reg_val; ++ asm volatile(".word 0x700801ee \n\t"); ++ mxu->vpr[7] = reg_val; ++ asm volatile(".word 0x7008022e \n\t"); ++ mxu->vpr[8] = reg_val; ++ asm volatile(".word 0x7008026e \n\t"); ++ mxu->vpr[9] = reg_val; ++ asm volatile(".word 0x700802ae \n\t"); ++ mxu->vpr[10] = reg_val; ++ asm volatile(".word 0x700802ee \n\t"); ++ mxu->vpr[11] = reg_val; ++ asm volatile(".word 0x7008032e \n\t"); ++ mxu->vpr[12] = reg_val; ++ asm volatile(".word 0x7008036e \n\t"); ++ mxu->vpr[13] = reg_val; ++ asm volatile(".word 0x700803ae \n\t"); ++ mxu->vpr[14] = reg_val; ++ asm volatile(".word 0x700803ee \n\t"); ++ mxu->vpr[15] = reg_val; ++} ++ ++void __restore_mxu(void * tsk_void) ++{ ++ register unsigned int reg_val asm("t0"); ++ struct task_struct *tsk = tsk_void; ++ struct xburst_mxu_struct *mxu = tsk->thread.mxu; ++ ++ reg_val = mxu->vpr[0]; ++ asm volatile(".word 0x7008042f \n\t"::"r"(reg_val)); ++ reg_val = mxu->vpr[1]; ++ asm volatile(".word 0x7008006f \n\t"::"r"(reg_val)); ++ reg_val = mxu->vpr[2]; ++ asm volatile(".word 0x700800af \n\t"::"r"(reg_val)); ++ reg_val = mxu->vpr[3]; ++ asm volatile(".word 0x700800ef \n\t"::"r"(reg_val)); ++ reg_val = mxu->vpr[4]; ++ asm volatile(".word 0x7008012f \n\t"::"r"(reg_val)); ++ reg_val = mxu->vpr[5]; ++ asm volatile(".word 0x7008016f \n\t"::"r"(reg_val)); ++ reg_val = mxu->vpr[6]; ++ asm volatile(".word 0x700801af \n\t"::"r"(reg_val)); ++ reg_val = mxu->vpr[7]; ++ asm volatile(".word 0x700801ef \n\t"::"r"(reg_val)); ++ reg_val = mxu->vpr[8]; ++ asm volatile(".word 0x7008022f \n\t"::"r"(reg_val)); ++ reg_val = mxu->vpr[9]; ++ asm volatile(".word 0x7008026f \n\t"::"r"(reg_val)); ++ reg_val = mxu->vpr[10]; ++ asm volatile(".word 0x700802af \n\t"::"r"(reg_val)); ++ reg_val = mxu->vpr[11]; ++ asm volatile(".word 0x700802ef \n\t"::"r"(reg_val)); ++ reg_val = mxu->vpr[12]; ++ asm volatile(".word 0x7008032f \n\t"::"r"(reg_val)); ++ reg_val = mxu->vpr[13]; ++ asm volatile(".word 0x7008036f \n\t"::"r"(reg_val)); ++ reg_val = mxu->vpr[14]; ++ asm volatile(".word 0x700803af \n\t"::"r"(reg_val)); ++ reg_val = mxu->vpr[15]; ++ asm volatile(".word 0x700803ef \n\t"::"r"(reg_val)); ++} ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_common_prom.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_common_prom.c.patch new file mode 100644 index 00000000..5aa8ed70 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_common_prom.c.patch @@ -0,0 +1,67 @@ +diff -drupN a/arch/mips/xburst/common/prom.c b/arch/mips/xburst/common/prom.c +--- a/arch/mips/xburst/common/prom.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/common/prom.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,63 @@ ++/* ++ * Copyright (C) 2010, Lars-Peter Clausen ++ * INGENIC SoC prom code ++ * ++ * 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. ++ * ++ * 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., ++ * 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#ifdef CONFIG_XBURST_MXUV2 ++#include ++#include ++#endif ++ ++extern struct plat_smp_ops ingenic_soc_smp_ops; ++ ++static void *_fw_fdt_addr; ++ ++void __init prom_init(void) ++{ ++ fw_init_cmdline(); ++ ++ if (fw_arg0 == 0 && fw_arg1 == 0xffffffffUL) ++ _fw_fdt_addr = phys_to_virt(fw_arg2); ++ else if ((int)fw_arg0 == -2) /*UHI*/ ++ _fw_fdt_addr = (void *)fw_arg1; ++ else if (__dtb_start != __dtb_end) ++ _fw_fdt_addr = __dtb_start; ++ else ++ panic("no dtb found!\n"); ++ ++ mips_machtype = MACH_XBURST; ++} ++ ++void __init prom_free_prom_memory(void) ++{ ++} ++ ++const char *get_system_type(void) ++{ ++ return "XBurst-Based"; ++} ++ ++void __init *get_fdt_addr(void) ++{ ++ return _fw_fdt_addr; ++} ++#ifdef CONFIG_XBURST_MXUV2 ++noinline struct xburst_cop2_state *get_current_cp2(void) ++{ ++ return &(current->thread.cp2); ++} ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_common_sc-xburst.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_common_sc-xburst.c.patch new file mode 100644 index 00000000..212c1307 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_common_sc-xburst.c.patch @@ -0,0 +1,227 @@ +diff -drupN a/arch/mips/xburst/common/sc-xburst.c b/arch/mips/xburst/common/sc-xburst.c +--- a/arch/mips/xburst/common/sc-xburst.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/common/sc-xburst.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,223 @@ ++/* ++ * Copyright (C) 2006 Chris Dearman (chris@mips.com), ++ */ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * MIPS32/MIPS64 L2 cache handling ++ */ ++static unsigned long scache_size __read_mostly; ++static void (* r4k_blast_scache)(void); ++static void cache_noop(void) {} ++ ++void __weak platform_early_l2_init(void) ++{ ++} ++ ++static void mips_bridge_sync_war(unsigned long addr, unsigned long size) ++{ ++ __fast_iob(); ++} ++ ++static void r4k_blast_scache_setup(void) ++{ ++ unsigned long sc_lsize = cpu_scache_line_size(); ++ ++ /*default*/ ++ r4k_blast_scache = blast_scache32; ++ ++ if (scache_size == 0) ++ r4k_blast_scache = (void *)blast_inclusive_scache; ++ else if (sc_lsize == 16) ++ r4k_blast_scache = blast_scache16; ++ else if (sc_lsize == 32) ++ r4k_blast_scache = blast_scache32; ++ else if (sc_lsize == 64) ++ r4k_blast_scache = blast_scache64; ++ else if (sc_lsize == 128) ++ r4k_blast_scache = blast_scache128; ++} ++ ++/* ++ * Writeback and invalidate the secondary cache before DMA. ++ */ ++static void mips_sc_wback_inv(unsigned long addr, unsigned long size) ++{ ++ if (size >= scache_size) ++ r4k_blast_scache(); ++ else ++ blast_scache_range(addr, addr + size); ++} ++ ++/* ++ * Invalidate the secondary cache before DMA. ++ */ ++static void mips_sc_inv(unsigned long addr, unsigned long size) ++{ ++ unsigned long lsize = cpu_scache_line_size(); ++ unsigned long almask = ~(lsize - 1); ++ ++ if (size >= scache_size) { ++ r4k_blast_scache(); ++ }else { ++ cache_op(Hit_Writeback_Inv_SD, addr & almask); ++ cache_op(Hit_Writeback_Inv_SD, (addr + size - 1) & almask); ++ blast_inv_scache_range(addr, addr + size); ++ if (MIPS_BRIDGE_SYNC_WAR) ++ __fast_iob(); ++ } ++} ++ ++static struct bcache_ops mips_sc_ops = { ++ .bc_enable = (void *)cache_noop, ++ .bc_disable = (void *)cache_noop, ++ .bc_wback_inv = (void *)cache_noop, ++ .bc_inv = (void *)cache_noop, ++}; ++ ++/* ++ * Check if the L2 cache controller is activated on a particular platform. ++ * MTI's L2 controller and the L2 cache controller of Broadcom's BMIPS ++ * cores both use c0_config2's bit 12 as "L2 Bypass" bit, that is the ++ * cache being disabled. However there is no guarantee for this to be ++ * true on all platforms. In an act of stupidity the spec defined bits ++ * 12..15 as implementation defined so below function will eventually have ++ * to be replaced by a platform specific probe. ++ */ ++static inline int mips_sc_is_activated(struct cpuinfo_mips *c) ++{ ++ unsigned int config2 = read_c0_config2(); ++ unsigned int tmp; ++ ++ /* Check the bypass bit (L2B) */ ++ switch (current_cpu_type()) { ++ case CPU_34K: ++ case CPU_74K: ++ case CPU_1004K: ++ case CPU_1074K: ++ case CPU_INTERAPTIV: ++ case CPU_PROAPTIV: ++ case CPU_P5600: ++ case CPU_BMIPS5000: ++ case CPU_QEMU_GENERIC: ++ if (config2 & (1 << 12)) ++ return 0; ++ } ++ ++ tmp = (config2 >> 4) & 0x0f; ++ if (0 < tmp && tmp <= 7) ++ c->scache.linesz = 2 << tmp; ++ else ++ return 0; ++ return 1; ++} ++ ++static inline int __init mips_sc_probe(void) ++{ ++ struct cpuinfo_mips *c = ¤t_cpu_data; ++ unsigned int config1, config2; ++ unsigned int tmp; ++ ++ /* Mark as not present until probe completed */ ++ c->scache.flags |= MIPS_CACHE_NOT_PRESENT; ++ ++ /* Ignore anything but MIPSxx processors */ ++ if (!(c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M32R2 | ++ MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R1 | ++ MIPS_CPU_ISA_M64R2 | MIPS_CPU_ISA_M64R6))) ++ return 0; ++ ++ /* ++ * Do we need some platform specific probing before ++ * we configure L2? ++ */ ++ platform_early_l2_init(); ++ ++ switch(c->processor_id & PRID_CPU_FEATURE_MASK){ ++ case PRID_CPU_JZ4775S: ++ case PRID_CPU_JZ4780: ++ case PRID_CPU_X1000: ++ if (MIPS_BRIDGE_SYNC_WAR) { ++ mips_sc_ops.bc_wback_inv = mips_bridge_sync_war; ++ return 1; ++ } ++ return 0; ++ case PRID_CPU_X1800: ++ case PRID_CPU_M200: ++ mips_sc_ops.bc_wback_inv = mips_sc_wback_inv; ++ mips_sc_ops.bc_inv = mips_sc_inv; ++ break; ++ default: ++ pr_warn("processor_id[0x%08x] s-cache is not support\n", c->processor_id); ++ break; ++ } ++ ++ /* Does this MIPS32/MIPS64 CPU have a config2 register? */ ++ config1 = read_c0_config1(); ++ if (!(config1 & MIPS_CONF_M)) ++ return 0; ++ ++ config2 = read_c0_config2(); ++ ++ if (!mips_sc_is_activated(c)) ++ return 0; ++ ++ tmp = (config2 >> 8) & 0x0f; ++ if (tmp <= 7) ++ c->scache.sets = 64 << tmp; ++ else ++ return 0; ++ ++ tmp = (config2 >> 0) & 0x0f; ++ if (tmp <= 7) ++ c->scache.ways = tmp + 1; ++ else ++ return 0; ++ ++ c->scache.waysize = c->scache.sets * c->scache.linesz; ++ c->scache.waybit = __ffs(c->scache.waysize); ++ c->scache.flags &= ~MIPS_CACHE_NOT_PRESENT; ++ ++ scache_size = c->scache.ways * c->scache.sets * c->scache.linesz; ++ write_c0_ecc(0x0); ++ ++ r4k_blast_scache_setup(); ++ return 1; ++} ++ ++static char *way_string[] = { NULL, "direct mapped", "2-way", ++ "3-way", "4-way", "5-way", "6-way", "7-way", "8-way", ++ "9-way", "10-way", "11-way", "12-way", ++ "13-way", "14-way", "15-way", "16-way", ++}; ++ ++int mips_sc_init(void) ++{ ++ struct cpuinfo_mips *c = ¤t_cpu_data; ++ int found = mips_sc_probe(); ++ ++ if (found) { ++ bcops = &mips_sc_ops; ++ bc_enable(); ++ bc_prefetch_enable(); ++ } ++ ++ if (!scache_size) ++ return 0; ++ ++ printk("Unified secondary cache %ldkB %s, linesize %d bytes.\n", ++ scache_size >> 10, way_string[c->scache.ways], c->scache.linesz); ++ ++ return found; ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_debug_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_debug_Makefile.patch new file mode 100644 index 00000000..cc07716a --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_debug_Makefile.patch @@ -0,0 +1,5 @@ +diff -drupN a/arch/mips/xburst/debug/Makefile b/arch/mips/xburst/debug/Makefile +--- a/arch/mips/xburst/debug/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/debug/Makefile 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1 @@ ++obj-$(CONFIG_TRACEPOINTS) += trace-exit.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_debug_trace-exit.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_debug_trace-exit.c.patch new file mode 100644 index 00000000..3cb12eea --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_debug_trace-exit.c.patch @@ -0,0 +1,35 @@ +diff -drupN a/arch/mips/xburst/debug/trace-exit.c b/arch/mips/xburst/debug/trace-exit.c +--- a/arch/mips/xburst/debug/trace-exit.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/debug/trace-exit.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,31 @@ ++#include ++#include ++#include ++#include ++#include ++ ++static void ++probe_sched_process_exit(void *d,struct task_struct *p) ++{ ++ struct thread_struct *thread = &p->thread; ++ ++ printk("[EXIT] %s pid %d, ", p->comm, p->pid); ++ printk("exit_stat %d, exit_signal %d\n",p->exit_code,p->exit_signal); ++ printk(" badvaddr %lx, baduaddr %lx, error_code %ld\n", ++ thread->cp0_badvaddr,thread->cp0_baduaddr,thread->error_code); ++ ++ if (p->pid == 1) ++ ftrace_dump(DUMP_ALL); ++} ++ ++static int init_trace(void) ++{ ++ int ret = -1; ++ ++ ret = register_trace_sched_process_exit(probe_sched_process_exit, NULL); ++ if (ret) ++ printk("register process exit failed.\n"); ++ ++ return ret; ++} ++arch_initcall(init_trace); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_Kconfig.DT.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_Kconfig.DT.patch new file mode 100644 index 00000000..839864b2 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_Kconfig.DT.patch @@ -0,0 +1,6 @@ +diff -drupN a/arch/mips/xburst/soc-x1000/Kconfig.DT b/arch/mips/xburst/soc-x1000/Kconfig.DT +--- a/arch/mips/xburst/soc-x1000/Kconfig.DT 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/soc-x1000/Kconfig.DT 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,2 @@ ++config DT_HALLEY2_V20 ++ bool "halley2 v20" diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_Makefile.patch new file mode 100644 index 00000000..0d3ecb80 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_Makefile.patch @@ -0,0 +1,9 @@ +diff -drupN a/arch/mips/xburst/soc-x1000/Makefile b/arch/mips/xburst/soc-x1000/Makefile +--- a/arch/mips/xburst/soc-x1000/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/soc-x1000/Makefile 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,5 @@ ++obj-y += setup.o ++obj-y += socid.o ++obj-y += regs_save_restore.o ++obj-$(CONFIG_EARLY_PRINTK) += early_printk.o ++obj-$(CONFIG_PM) += pm.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_core_sleep.hex.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_core_sleep.hex.patch new file mode 100644 index 00000000..2788539c --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_core_sleep.hex.patch @@ -0,0 +1,1030 @@ +diff -drupN a/arch/mips/xburst/soc-x1000/core_sleep.hex b/arch/mips/xburst/soc-x1000/core_sleep.hex +--- a/arch/mips/xburst/soc-x1000/core_sleep.hex 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/soc-x1000/core_sleep.hex 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,1026 @@ ++0x27bdfff4, ++0xafbc0000, ++0xafbf0004, ++0xafb90008, ++0x04110007, ++0x00000000, ++0x00008bb0, ++0x00000c54, ++0x00000c1c, ++0x00000c1c, ++0x00000bc0, ++0x00000017, ++0x8ffc0000, ++0x0384e021, ++0x8feb0014, ++0x8fec0010, ++0x008c6021, ++0x218c0008, ++0x240a0002, ++0x8d890000, ++0x01244821, ++0xad890000, ++0x214a0001, ++0x014b082a, ++0x1420fffa, ++0x218c0004, ++0x8fea0004, ++0x8fe90008, ++0x01445021, ++0x01244821, ++0x1000000a, ++0x21290008, ++0x8d2bfffc, ++0x216bfffd, ++0x15600006, ++0x00000000, ++0x8d2bfff8, ++0x01645821, ++0x8d6c0000, ++0x01846021, ++0xad6c0000, ++0x012a082a, ++0x1420fff5, ++0x21290008, ++0x8f898018, ++0x8f8a8018, ++0xad200000, ++0x012a082a, ++0x1420fffd, ++0x21290004, ++0x8f88801c, ++0xad050000, ++0x00805825, ++0x8f888020, ++0xad0b0000, ++0x8f8a8024, ++0xad6a0000, ++0x256b0004, ++0x240affff, ++0x21690040, ++0xad6a0000, ++0x256b0004, ++0x152bfffd, ++0x00000000, ++0x8fbc0000, ++0x8fbf0004, ++0x8fb90008, ++0x27bd000c, ++0x03e00008, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x04110001, ++0x00000000, ++0x27f90004, ++0x3c1c0001, ++0x279c898c, ++0x0399e021, ++0x27fdfffc, ++0x8f998028, ++0x03200008, ++0x00000000, ++0x04110001, ++0x00000000, ++0x27f90004, ++0x3c1c0001, ++0x279c8964, ++0x0399e021, ++0x27fdfff0, ++0x8f99802c, ++0x03200008, ++0x00000000, ++0x27bdfff0, ++0xafbc0000, ++0xafbf0004, ++0xafb90008, ++0x0080c825, ++0x00a02025, ++0x0320f809, ++0x00000000, ++0x8fbc0000, ++0x8fbf0004, ++0x8fb90008, ++0x27bd0010, ++0x03e00008, ++0x00000000, ++0x4080e000, ++0x3c028000, ++0x24434000, ++0xbc490000, ++0x24420020, ++0x1443fffd, ++0x00000000, ++0x3c028000, ++0x24434000, ++0xbc480000, ++0x24420020, ++0x1443fffd, ++0x00000000, ++0x401a8007, ++0x00000000, ++0x375a0002, ++0x409a8007, ++0x00000000, ++0x03e00008, ++0x00000000, ++0x3c1c0001, ++0x279c88c0, ++0x0399e021, ++0x8c820000, ++0x27bdffe0, ++0x3c030040, ++0x00431025, ++0xafbc0010, ++0x3c03b000, ++0xafb00018, ++0xafbf001c, ++0x3c10b000, ++0xac620000, ++0x8e0200d4, ++0x30420001, ++0x10400005, ++0x8f998030, ++0x041101c5, ++0x24040055, ++0x1000fff9, ++0x8fbc0010, ++0x8fbf001c, ++0x8fb00018, ++0x03e00008, ++0x27bd0020, ++0x3c028000, ++0x24434000, ++0xbc400000, ++0xbc410000, ++0x24420020, ++0x1443fffc, ++0x00000000, ++0x0000000f, ++0x03e00008, ++0x00000000, ++0x3c1c0001, ++0x279c8834, ++0x0399e021, ++0x8f998034, ++0x1000fff1, ++0x00000000, ++0x3c1c0001, ++0x279c881c, ++0x0399e021, ++0x27bdffe0, ++0xafbc0010, ++0xafbf001c, ++0xafb00018, ++0x14800013, ++0x24020001, ++0x3c04b000, ++0x8c820000, ++0x2403ff00, ++0x3c10b000, ++0xaca20000, ++0x00431024, ++0x3c030040, ++0x24630073, ++0x00431025, ++0xac820000, ++0x8e0200d4, ++0x30420001, ++0x1040000d, ++0x8f998030, ++0x04110196, ++0x24040055, ++0x1000fff9, ++0x8fbc0010, ++0x14820008, ++0x8fbf001c, ++0x8f998038, ++0x8fb00018, ++0x00a02025, ++0x273902f0, ++0x1000ffb5, ++0x27bd0020, ++0x8fbf001c, ++0x8fb00018, ++0x03e00008, ++0x27bd0020, ++0x3c1c0001, ++0x279c8780, ++0x0399e021, ++0x27bdffd8, ++0xafb1001c, ++0x8f918020, ++0xafbc0010, ++0xafbf0024, ++0x8e220000, ++0xafb20020, ++0xafb00018, ++0x8f99803c, ++0x0411016d, ++0x9044000b, ++0x8fbc0010, ++0x8f998034, ++0x0411ffb8, ++0x00000000, ++0x8fbc0010, ++0x3c02b000, ++0x24030001, ++0x8f928040, ++0xac4300c8, ++0xac5200cc, ++0xac400008, ++0x8e220000, ++0x8c440014, ++0x2402ffff, ++0x10820004, ++0x8f998044, ++0x0411ff6f, ++0x00002825, ++0x8fbc0010, ++0x40028000, ++0x8f848038, ++0x24900c28, ++0xae020010, ++0x40026000, ++0x3c03b301, ++0xae020014, ++0xac601054, ++0x3c02b34f, ++0x8c450304, ++0xac850c28, ++0xac400304, ++0x8c4400bc, ++0xae040004, ++0x8c631004, ++0x7c630440, ++0x14600002, ++0x3403f003, ++0xac4300bc, ++0x3c04b34f, ++0x8c820008, ++0x3c03ffff, ++0x246307ff, ++0xae020008, ++0x8f858038, ++0x00431024, ++0x3c030002, ++0x24630020, ++0x8f998048, ++0x00431025, ++0xac820008, ++0x24a50c34, ++0x0411ff97, ++0x00002025, ++0x8fbc0010, ++0x40026002, ++0x3c038000, ++0xae020018, ++0x00431025, ++0x40826002, ++0x8e220000, ++0x240300ff, ++0x9044000a, ++0x1083000d, ++0x8f99804c, ++0x04110179, ++0x90440009, ++0x8fbc0010, ++0xa202001c, ++0x8f828020, ++0x8f998050, ++0x8c420000, ++0x9045000a, ++0x04110159, ++0x90440009, ++0x10000003, ++0x8fbc0010, ++0x2402ffff, ++0xa202001c, ++0x8e220000, ++0x8c440018, ++0x2402ffff, ++0x10820004, ++0x8f998044, ++0x0411ff2c, ++0x00002825, ++0x8fbc0010, ++0x8e020014, ++0x34420400, ++0x40826000, ++0x8f998030, ++0x0411011e, ++0x24040065, ++0x8fbc0010, ++0x0000000f, ++0x00000000, ++0x42000020, ++0x00000000, ++0x00000000, ++0x02400008, ++0x00000000, ++0x8f998030, ++0x04110113, ++0x24040045, ++0x1000fffc, ++0x8fbc0010, ++0x3c1c0001, ++0x279c85a4, ++0x0399e021, ++0x8f998030, ++0x27bdffc0, ++0xafbc0010, ++0xafb30028, ++0xafb0001c, ++0xafbf003c, ++0xafb70038, ++0xafb60034, ++0xafb50030, ++0xafb4002c, ++0xafb20024, ++0xafb10020, ++0x04110100, ++0x2404004f, ++0x8fbc0010, ++0x8f938038, ++0x26700c28, ++0x8e020010, ++0x40828000, ++0x8e020014, ++0x40826000, ++0x8f918020, ++0x8e220000, ++0x8c43000c, ++0x2402ffff, ++0x1062000b, ++0x8f998038, ++0x273902a0, ++0x0411ff05, ++0x00000000, ++0x8fbc0010, ++0x8e220000, ++0x8e05000c, ++0x8f998044, ++0x0411fef1, ++0x8c44000c, ++0x8fbc0010, ++0x8e220000, ++0x90440009, ++0x240200ff, ++0x10820004, ++0x8f998050, ++0x0411010b, ++0x9205001c, ++0x8fbc0010, ++0x8f848038, ++0x8f998038, ++0x273902f0, ++0x0411ff05, ++0x24840c34, ++0x3c02b301, ++0x8c521004, ++0x3c020002, ++0x02429024, ++0x16400060, ++0x8fbc0010, ++0x3c03b000, ++0x8c6200d0, ++0x34420002, ++0xac6200d0, ++0x24020200, ++0x2442ffff, ++0x10400004, ++0x3c03b000, ++0x00000000, ++0x1000fffc, ++0x2442ffff, ++0x8c6200d0, ++0x2404fffd, ++0x00441024, ++0xac6200d0, ++0x24020200, ++0x2442ffff, ++0x10400004, ++0x3c03b301, ++0x00000000, ++0x1000fffc, ++0x2442ffff, ++0x8c62102c, ++0x2404ffef, ++0x00441024, ++0xac62102c, ++0x24020010, ++0x2442ffff, ++0x10400004, ++0x3c03b000, ++0x00000000, ++0x1000fffc, ++0x2442ffff, ++0x8c6200d0, ++0x34420002, ++0xac6200d0, ++0x24020200, ++0x2442ffff, ++0x10400004, ++0x3c03b000, ++0x00000000, ++0x1000fffc, ++0x2442ffff, ++0x8c6200d0, ++0x2404fffd, ++0x00441024, ++0xac6200d0, ++0x24020200, ++0x2442ffff, ++0x10400004, ++0x24030017, ++0x00000000, ++0x1000fffc, ++0x2442ffff, ++0x3c02b301, ++0x3c14b301, ++0xac431004, ++0x2415000b, ++0x26971180, ++0x8e82100c, ++0x3042000b, ++0x10550079, ++0x2696100c, ++0x8e82100c, ++0x30420060, ++0x10400006, ++0x8f998054, ++0x8f998030, ++0x04110090, ++0x24040065, ++0x10000070, ++0x8fbc0010, ++0x8ee40000, ++0x0411009a, ++0x00000000, ++0x8fbc0010, ++0x8ec4017c, ++0x8f998054, ++0x04110095, ++0x00000000, ++0x8fbc0010, ++0x8e84100c, ++0x8f998054, ++0x04110090, ++0x00000000, ++0x8fbc0010, ++0x8f998030, ++0x0411007d, ++0x2404000d, ++0x8fbc0010, ++0x8f998030, ++0x04110079, ++0x2404000a, ++0x1000ffdd, ++0x8fbc0010, ++0x3c05b34f, ++0x8ca40008, ++0x3c03fffd, ++0x3463ffdf, ++0x00831824, ++0x34630002, ++0xaca30008, ++0x24420081, ++0x3c03b301, ++0xac621004, ++0x3c14b301, ++0x2415001b, ++0x8e82100c, ++0x3042001b, ++0x10550017, ++0x00000000, ++0x8e82100c, ++0x30420060, ++0x10400006, ++0x8f998054, ++0x8f998030, ++0x04110060, ++0x24040065, ++0x1000000e, ++0x8fbc0010, ++0x8e84100c, ++0x0411006a, ++0x00000000, ++0x8fbc0010, ++0x8f998030, ++0x04110057, ++0x2404000d, ++0x8fbc0010, ++0x8f998030, ++0x04110053, ++0x2404000a, ++0x1000ffe7, ++0x8fbc0010, ++0x12400006, ++0x3c03b301, ++0x8e020004, ++0x1040000d, ++0x8e620c28, ++0x10000010, ++0x00000000, ++0x8c62102c, ++0x34420010, ++0xac62102c, ++0x24020010, ++0x2442ffff, ++0x1040fff5, ++0x00000000, ++0x00000000, ++0x1000fffc, ++0x2442ffff, ++0x16400004, ++0x00000000, ++0x3c02b34f, ++0xac4000bc, ++0x8e620c28, ++0x10400003, ++0x24030001, ++0x3c02b34f, ++0xac430304, ++0x8e030008, ++0x8f998038, ++0x3c02b34f, ++0xac430008, ++0x273902a0, ++0x0411fe45, ++0x00000000, ++0x8fbc0010, ++0x8e020018, ++0x40826002, ++0x8e220000, ++0x8c440010, ++0x3c020fff, ++0x3442ffff, ++0x10820004, ++0x8f998044, ++0x0411fe2c, ++0x00002825, ++0x8fbc0010, ++0x8f998030, ++0x04110021, ++0x24040073, ++0x1000fffc, ++0x8fbc0010, ++0x3c04b34f, ++0x8c830008, ++0x3c02fffd, ++0x3442ffdf, ++0x00621024, ++0x34420002, ++0xac820008, ++0x1000ffa8, ++0x24020081, ++0x00000000, ++0x00000000, ++0x00000000, ++0x2484ffac, ++0x1c80fffd, ++0x00000000, ++0x03e00008, ++0x00000000, ++0x3c1c0001, ++0x279c8198, ++0x0399e021, ++0x240300ff, ++0x10830006, ++0x8f828038, ++0x3c03b003, ++0x00042300, ++0x00832021, ++0x03e00008, ++0xac440c50, ++0x03e00008, ++0xac400c50, ++0x3c1c0001, ++0x279c8164, ++0x0399e021, ++0x8f828038, ++0x8c430c50, ++0x10600007, ++0x7c042420, ++0xac640000, ++0x24040060, ++0x8c620014, ++0x30420060, ++0x1444fffd, ++0x00000000, ++0x03e00008, ++0x00000000, ++0x3c1c0001, ++0x279c8128, ++0x0399e021, ++0x8f998030, ++0x27bdffe0, ++0x00803825, ++0x2405001c, ++0xafbc0010, ++0xafbf001c, ++0x2406fffc, ++0x00a71006, ++0x3042000f, ++0x2c44000a, ++0x24430030, ++0x24420037, ++0x0044180a, ++0x0411ffe0, ++0x00602025, ++0x24a5fffc, ++0x14a6fff7, ++0x00a71006, ++0x8fbf001c, ++0x03e00008, ++0x27bd0020, ++0x00000000, ++0x00000000, ++0x3088001f, ++0x24030001, ++0x00042143, ++0x3c02b001, ++0x00042200, ++0x01031804, ++0x24420010, ++0x00031827, ++0x00822021, ++0x24060003, ++0x2409ffff, ++0x8c820000, ++0x24840010, ++0x00433824, ++0x00c51007, ++0x30420001, ++0x01021004, ++0x00471025, ++0x24c6ffff, ++0xac82fff0, ++0x14c9fff6, ++0x00000000, ++0x03e00008, ++0x00000000, ++0x3087001f, ++0x3c02b001, ++0x00042143, ++0x24420010, ++0x00042200, ++0x00822021, ++0x24050003, ++0x00001025, ++0x2406ffff, ++0x8c830000, ++0x24840010, ++0x00e31806, ++0x30630001, ++0x00a31804, ++0x24a5ffff, ++0x14a6fff9, ++0x00621025, ++0x03e00008, ++0x00000000, ++0x00000000, ++0x02200000, ++0x01000101, ++0x00000000, ++0x00000000, ++0x00000001, ++0x00000000, ++0x00000000, ++0xffffffff, ++0x00000000, ++0x80000000, ++0x00000c1c, ++0x00000c24, ++0x00000c20, ++0x00000218, ++0x00000430, ++0x0000060c, ++0x00000a4c, ++0x00000354, ++0x00000000, ++0x00000a18, ++0x00000240, ++0x00000268, ++0x00000394, ++0x00000b50, ++0x00000af0, ++0x00000a88, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000018, ++0x00000003, ++0x0000001c, ++0x00000003, ++0x00000020, ++0x00000003, ++0x00000024, ++0x00000003, ++0x00000028, ++0x00000003, ++0x0000002c, ++0x00000003, ++0xffffffff, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00010003, ++0x000000ad, ++0x00000c1c, ++0x00000000, ++0x00050010, ++0x00000001, ++0x00000001, ++0x00000000, ++0xfff10013, ++0x00000081, ++0x00000017, ++0x00000000, ++0xfff10010, ++0x0000003e, ++0x00000c20, ++0x00000004, ++0x00070211, ++0x00000059, ++0x00000240, ++0x00000028, ++0x00010012, ++0x0000004a, ++0x00000218, ++0x00000028, ++0x00010012, ++0x0000007d, ++0x00008bb0, ++0x00000000, ++0xfff10010, ++0x00000091, ++0x00000c1c, ++0x00000000, ++0x00050010, ++0x00000028, ++0x00000c1c, ++0x00000000, ++0x00070010, ++0x00000075, ++0x00000000, ++0x00000000, ++0x00010010, ++0x00000012, ++0x00000bb8, ++0x00000000, ++0x00030011, ++0x000000a2, ++0x00000c1c, ++0x00000000, ++0x00050010, ++0x00000032, ++0x00000c24, ++0x00000004, ++0x00070211, ++0x0000001c, ++0x00000c1c, ++0x00000000, ++0x00070010, ++0x00000067, ++0x00000268, ++0x00000038, ++0x00010012, ++0x000000c6, ++0x00000c58, ++0x00000000, ++0x00060010, ++0x000000bd, ++0x00000c54, ++0x00000000, ++0x00050010, ++0x59445f00, ++0x494d414e, ++0x494c5f43, ++0x4e494b4e, ++0x5f5f0047, ++0x5f444c52, ++0x0050414d, ++0x73625f5f, ++0x74735f73, ++0x00747261, ++0x73625f5f, ++0x6e655f73, ++0x78650064, ++0x6e726574, ++0x6e75665f, ++0x5f700063, ++0x5f706c73, ++0x61726170, ++0x6c73006d, ++0x5f706565, ++0x655f6d70, ++0x7265746e, ++0x656c7300, ++0x705f7065, ++0x78655f6d, ++0x63007469, ++0x5f6c6c61, ++0x636e7566, ++0x6e6f6974, ++0x735f5f00, ++0x74726174, ++0x70675f00, ++0x6d756e00, ++0x746f675f, ++0x746e655f, ++0x73656972, ++0x695f5f00, ++0x6567616d, ++0x706f635f, ++0x6e655f79, ++0x5f5f0064, ++0x74696e69, ++0x646e655f, ++0x725f5f00, ++0x645f6c65, ++0x735f6e79, ++0x74726174, ++0x725f5f00, ++0x645f6c65, ++0x655f6e79, ++0xff00646e, ++0x00000004, ++0x00000f70, ++0x00000005, ++0x00000d88, ++0x00000006, ++0x00000c58, ++0x0000000a, ++0x000000cb, ++0x0000000b, ++0x00000010, ++0x70000035, ++0xfffffd3c, ++0x00000015, ++0x00000000, ++0x00000016, ++0x00000000, ++0x00000003, ++0x00000bc0, ++0x00000011, ++0x00000c1c, ++0x00000012, ++0x00000038, ++0x00000013, ++0x00000008, ++0x70000001, ++0x00000001, ++0x70000005, ++0x00000002, ++0x70000006, ++0x00000000, ++0x7000000a, ++0x00000017, ++0x70000011, ++0x00000013, ++0x70000012, ++0x0000000f, ++0x70000013, ++0x00000013, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x7273752f, ++0x62696c2f, ++0x62696c2f, ++0x6f732e63, ++0xff00312e, ++0x00000f41, ++0x756e6700, ++0x00070100, ++0x01040000, ++0x00000f41, ++0x756e6700, ++0x00070100, ++0x01040000, ++0x00000f41, ++0x756e6700, ++0x00070100, ++0x01040000, ++0x00000f41, ++0x756e6700, ++0x00070100, ++0x01040000, ++0x00000011, ++0x00000013, ++0x00000000, ++0x0000000d, ++0x00000009, ++0x00000010, ++0x00000007, ++0x00000004, ++0x0000000a, ++0x0000000e, ++0x00000002, ++0x00000000, ++0x00000000, ++0x0000000f, ++0x00000000, ++0x00000011, ++0x00000012, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000003, ++0x00000000, ++0x00000000, ++0x00000006, ++0x00000005, ++0x00000008, ++0x00000000, ++0x00000000, ++0x0000000b, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x0000000c, ++0x00000000, diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_early_printk.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_early_printk.c.patch new file mode 100644 index 00000000..539555d0 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_early_printk.c.patch @@ -0,0 +1,78 @@ +diff -drupN a/arch/mips/xburst/soc-x1000/early_printk.c b/arch/mips/xburst/soc-x1000/early_printk.c +--- a/arch/mips/xburst/soc-x1000/early_printk.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/soc-x1000/early_printk.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,74 @@ ++/* ++ * INGENIC SOC serial routines for early_printk. ++ * ++ * Copyright (C) 2006 Ingenic Semiconductor Inc. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++#define UART_OFF (0x1000) ++ ++static void check_uart(char c); ++ ++static volatile u32 *uart_base; ++typedef void (*putchar_f_t)(char); ++ ++static putchar_f_t putchar_f = check_uart; ++ ++static void putchar(char ch) ++{ ++ int timeout = 10000; ++ volatile u32 *base = uart_base; ++ ++ /* Wait for fifo to shift out some bytes */ ++ while ((base[UART_LSR] & (UART_LSR_THRE | UART_LSR_TEMT)) ++ != (UART_LSR_THRE | UART_LSR_TEMT) && timeout--) ++ ; ++ base[UART_TX] = (u8)ch; ++} ++ ++static void putchar_dummy(char ch) ++{ ++ return; ++} ++ ++static void check_uart(char c) ++{ ++ /* We Couldn't use ioremap() here */ ++ volatile u32 *base = (volatile u32*)CKSEG1ADDR(UART0_IOBASE); ++ int i; ++ for(i=0; i < 3; i++) { ++ if(base[UART_LCR]) ++ break; ++ base += (UART_OFF/sizeof(u32)); ++ } ++ ++ if(i < 3) { ++ uart_base = base; ++ putchar_f = putchar; ++ putchar_f(c); ++ } else { ++ putchar_f = putchar_dummy; ++ } ++} ++ ++/* used by early printk */ ++void prom_putchar(char c) ++{ ++ putchar_f(c); ++} ++ ++static int __init early_parse_console(char *p) ++{ ++ unsigned char *param = "null"; ++ ++ if(strstr(p, param)){ ++ putchar_f = putchar_dummy; ++ } ++ return 0; ++} ++early_param("console", early_parse_console); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_include_cpu-feature-overrides.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_include_cpu-feature-overrides.h.patch new file mode 100644 index 00000000..c4284815 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_include_cpu-feature-overrides.h.patch @@ -0,0 +1,64 @@ +diff -drupN a/arch/mips/xburst/soc-x1000/include/cpu-feature-overrides.h b/arch/mips/xburst/soc-x1000/include/cpu-feature-overrides.h +--- a/arch/mips/xburst/soc-x1000/include/cpu-feature-overrides.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/soc-x1000/include/cpu-feature-overrides.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,60 @@ ++/* ++ * Copyright (C) 2008 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * 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. ++ */ ++ ++#ifndef __ASM_MACH_INGENIC_CPU_FEATURE_OVERRIDES_H__ ++#define __ASM_MACH_INGENIC_CPU_FEATURE_OVERRIDES_H__ ++ ++#define cpu_dcache_size() (16 * 1024) ++#define cpu_dcache_ways() 4 ++#define cpu_dcache_line_size() 32 ++#define cpu_icache_size() (16 * 1024) ++#define cpu_icache_ways() 4 ++#define cpu_icache_line_size() 32 ++#define cpu_has_tlb 1 ++#define cpu_has_4kex 1 ++#define cpu_has_3k_cache 0 ++#define cpu_has_4k_cache 1 ++#define cpu_has_tx39_cache 0 ++#define cpu_has_fpu 1 ++#define cpu_has_32fpr 1 ++#define cpu_has_counter 0 ++#define cpu_has_watch 1 ++#define cpu_has_divec 1 ++#define cpu_has_vce 0 ++#define cpu_has_cache_cdex_p 0 ++#define cpu_has_cache_cdex_s 0 ++#define cpu_has_prefetch 1 ++#define cpu_has_mcheck 1 ++#define cpu_has_ejtag 1 ++#define cpu_has_llsc 1 ++#define cpu_has_mips16 0 ++#define cpu_has_mdmx 0 ++#define cpu_has_mips3d 0 ++#define cpu_has_smartmips 0 ++#define cpu_has_vtag_icache 0 ++#define cpu_has_dc_aliases 0 ++#define cpu_has_ic_fills_f_dc 0 ++#define cpu_has_pindexed_dcache 0 ++#define cpu_icache_snoops_remote_store 0 ++#define cpu_has_mips32r1 1 ++#define cpu_has_mips32r2 1 ++#define cpu_has_mips64r1 0 ++#define cpu_has_mips64r2 0 ++#define cpu_has_dsp 0 ++#define cpu_has_mipsmt 0 ++#define cpu_has_userlocal 0 ++#define cpu_has_nofpuex 0 ++#define cpu_has_64bits 0 ++#define cpu_has_64bit_zero_reg 0 ++#define cpu_has_vint 0 ++#define cpu_has_veic 0 ++#define cpu_has_inclusive_pcaches 0 ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_include_irq.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_include_irq.h.patch new file mode 100644 index 00000000..40ce06ce --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_include_irq.h.patch @@ -0,0 +1,34 @@ +diff -drupN a/arch/mips/xburst/soc-x1000/include/irq.h b/arch/mips/xburst/soc-x1000/include/irq.h +--- a/arch/mips/xburst/soc-x1000/include/irq.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/soc-x1000/include/irq.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,30 @@ ++/* ++ * Copyright (C) 2010 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * 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. ++ */ ++ ++#ifndef __ASM_MACH_INGENIC_IRQ_H__ ++#define __ASM_MACH_INGENIC_IRQ_H__ ++ ++/* IRQ for MIPS CPU */ ++#define MIPS_CPU_IRQ_BASE 0 ++#define MIPS_CPU_IRQ(x) (MIPS_CPU_IRQ_BASE + (x)) ++ ++#define XBURST_INT MIPS_CPU_IRQ(2) ++#define XBURST_SYS_OST MIPS_CPU_IRQ(3) ++ ++#define MIPS_CPU_IRQS (MIPS_CPU_IRQ(7) + 1 - MIPS_CPU_IRQ_BASE) ++#define XBURST_SOC_IRQ_BASE MIPS_CPU_IRQS ++ ++#define INTC_CHIP_NUM 2 ++ ++#ifndef NR_IRQS ++#define NR_IRQS (200) ++#endif ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_include_soc_base.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_include_soc_base.h.patch new file mode 100644 index 00000000..d3ede564 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_include_soc_base.h.patch @@ -0,0 +1,94 @@ +diff -drupN a/arch/mips/xburst/soc-x1000/include/soc/base.h b/arch/mips/xburst/soc-x1000/include/soc/base.h +--- a/arch/mips/xburst/soc-x1000/include/soc/base.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/soc-x1000/include/soc/base.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,90 @@ ++ ++#ifndef __INGENIC_SOC_SOC_H__ ++#define __INGENIC_SOC_SOC_H__ ++ ++/* ++ * Define the module base addresses ++ */ ++ ++/* AHB0 BUS Devices Base */ ++#define HARB0_IOBASE 0x13000000 ++#define DDRC1_IOBASE 0x13010000 ++#define DDRC_IOBASE 0x13020000 ++#define X2D_IOBASE 0x13030000 ++#define GPU_IOBASE 0x13040000 ++#define LCDC_IOBASE 0x13050000 ++#define CIM_IOBASE 0x13060000 ++#define COMPRESS_IOBASE 0x13070000 ++#define IPU0_IOBASE 0x13080000 ++#define GPVLC_IOBASE 0x13090000 ++#define IPU1_IOBASE 0x130b0000 ++#define CIM1_IOBASE 0x130e0000 ++#define MONITOR_IOBASE 0x130f0000 ++#define EPDC_IOBASE 0x130c0000 ++#define EPDCE_IOBASE 0x130d0000 ++ ++/* AHB1 BUS Devices Base */ ++#define SCH_IOBASE 0x13200000 ++#define VDMA_IOBASE 0x13210000 ++#define EFE_IOBASE 0x13240000 ++#define MCE_IOBASE 0x13250000 ++#define DBLK_IOBASE 0x13270000 ++#define VMAU_IOBASE 0x13280000 ++#define SDE_IOBASE 0x13290000 ++#define AUX_IOBASE 0x132a0000 ++#define TCSM_IOBASE 0x132c0000 ++#define JPGC_IOBASE 0x132e0000 ++#define SRAM_IOBASE 0x132f0000 ++ ++/* AHB2 BUS Devices Base */ ++#define HARB2_IOBASE 0x13400000 ++#define NEMC_IOBASE 0x13410000 ++#define PDMA_IOBASE 0x13420000 ++#define SFC_IOBASE 0x13440000 ++#define MSC0_IOBASE 0x13450000 ++#define MSC1_IOBASE 0x13460000 ++#define MSC2_IOBASE 0x13470000 ++#define GPS_IOBASE 0x13480000 ++#define EHCI_IOBASE 0x13490000 ++#define OHCI_IOBASE 0x134a0000 ++#define ETHC_IOBASE 0x134b0000 ++#define BCH_IOBASE 0x134d0000 ++#define TSSI0_IOBASE 0x134e0000 ++#define TSSI1_IOBASE 0x134f0000 ++#define OTG_IOBASE 0x13500000 ++#define EFUSE_IOBASE 0x13540000 ++#define SECURITY_IOBASE 0x13430000 ++ ++ ++#define OST_IOBASE 0x12000000 ++#define HDMI_IOBASE 0x10180000 ++ ++/* APB BUS Devices Base */ ++#define CPM_IOBASE 0x10000000 ++#define INTC_IOBASE 0x10001000 ++#define TCU_IOBASE 0x10002000 ++#define RTC_IOBASE 0x10003000 ++#define GPIO_IOBASE 0x10010000 ++#define AIC_IOBASE 0x10020000 ++#define DMIC_IOBASE 0x10021000 ++#define SPDIF0_IOBASE 0x10020080 ++#define UART0_IOBASE 0x10030000 ++#define UART1_IOBASE 0x10031000 ++#define UART2_IOBASE 0x10032000 ++#define UART3_IOBASE 0x10033000 ++#define SSC_IOBASE 0x10040000 ++#define SSI0_IOBASE 0x10043000 ++#define SSI1_IOBASE 0x10044000 ++#define I2C0_IOBASE 0x10050000 ++#define I2C1_IOBASE 0x10051000 ++#define I2C2_IOBASE 0x10052000 ++#define KMC_IOBASE 0x10060000 ++#define DES_IOBASE 0x10061000 ++#define SADC_IOBASE 0x10070000 ++#define PCM_IOBASE 0x10071000 ++#define OWI_IOBASE 0x10072000 ++#define WDT_IOBASE 0x10002000 ++ ++#define AUX_IOBASE 0x132a0000 ++#define DDRC_BASE 0xb34f0000 ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_include_soc_cache.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_include_soc_cache.h.patch new file mode 100644 index 00000000..bc0126e0 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_include_soc_cache.h.patch @@ -0,0 +1,120 @@ +diff -drupN a/arch/mips/xburst/soc-x1000/include/soc/cache.h b/arch/mips/xburst/soc-x1000/include/soc/cache.h +--- a/arch/mips/xburst/soc-x1000/include/soc/cache.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/soc-x1000/include/soc/cache.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,116 @@ ++#ifndef __CHIP_CACHE_H__ ++#define __CHIP_CACHE_H__ ++ ++#include ++ ++ ++#define cache_prefetch(label,size) \ ++ do{ \ ++ unsigned long addr,end; \ ++ /* Prefetch codes from label */ \ ++ addr = (unsigned long)(&&label) & ~(32 - 1); \ ++ end = (unsigned long)(&&label + size) & ~(32 - 1); \ ++ end += 32; \ ++ for (; addr < end; addr += 32) { \ ++ __asm__ volatile ( \ ++ ".set mips32\n\t" \ ++ " cache %0, 0(%1)\n\t" \ ++ ".set mips32\n\t" \ ++ : \ ++ : "I" (Index_Prefetch_I), "r"(addr)); \ ++ } \ ++ } \ ++ while(0) ++ ++#define cache_prefetch_lable(label,l2) \ ++ do{ \ ++ unsigned long addr,end; \ ++ /* Prefetch codes from label */ \ ++ addr = (unsigned long)(&&label) & ~(32 - 1); \ ++ end = (unsigned long)(&&l2) & ~(32 - 1); \ ++ end += 32; \ ++ for (; addr < end; addr += 32) { \ ++ __asm__ volatile ( \ ++ ".set mips32\n\t" \ ++ " cache %0, 0(%1)\n\t" \ ++ ".set mips32\n\t" \ ++ : \ ++ : "I" (Index_Prefetch_I), "r"(addr)); \ ++ } \ ++ } \ ++ while(0) ++ ++#define K0BASE KSEG0 ++#define CFG_DCACHE_SIZE 16384 ++#define CFG_ICACHE_SIZE 16384 ++#define CFG_CACHELINE_SIZE 32 ++ ++static inline void __jz_flush_cache_all(void) ++{ ++ register unsigned long addr; ++ /* Clear CP0 TagLo */ ++ asm volatile ("mtc0 $0, $28\n\t"); ++ for (addr = K0BASE; addr < (K0BASE + CFG_DCACHE_SIZE); addr += CFG_CACHELINE_SIZE) { ++ asm volatile (".set mips32\n\t" ++ " cache %0, 0(%1)\n\t" ++ ".set mips32\n\t" ++ : ++ : "I" (Index_Writeback_Inv_D), "r"(addr)); ++ } ++ ++ for (addr = K0BASE; addr < (K0BASE + CFG_ICACHE_SIZE); addr += CFG_CACHELINE_SIZE) { ++ asm volatile (".set mips32\n\t" ++ " cache %0, 0(%1)\n\t" ++ ".set mips32\n\t" ++ : ++ : "I" (Index_Store_Tag_I), "r"(addr)); ++ } ++ /* invalidate BTB */ ++ asm volatile ( ++ ".set mips32\n\t" ++ " mfc0 $26, $16, 7\n\t" ++ " nop\n\t" ++ " ori $26, 2\n\t" ++ " mtc0 $26, $16, 7\n\t" ++ " nop\n\t" ++ ".set mips32\n\t" ++ ); ++ asm volatile ("sync\n\t" ++ "lw $0,0(%0)" ++ ::"r" (0xa0000000)); ++ ++} ++ ++static inline void __jz_cache_init(void) ++{ ++ register unsigned long addr; ++ asm volatile ("mtc0 $0, $28\n\t"::); ++ ++ for (addr = K0BASE; addr < (K0BASE + CFG_DCACHE_SIZE); addr += CFG_CACHELINE_SIZE) { ++ asm volatile (".set mips32\n\t" ++ " cache %0, 0(%1)\n\t" ++ ".set mips32\n\t" ++ : ++ : "I" (Index_Store_Tag_D), "r"(addr)); ++ } ++ for (addr = K0BASE; addr < (K0BASE + CFG_ICACHE_SIZE); addr += CFG_CACHELINE_SIZE) { ++ asm volatile (".set mips32\n\t" ++ " cache %0, 0(%1)\n\t" ++ ".set mips32\n\t" ++ : ++ : "I" (Index_Store_Tag_I), "r"(addr)); ++ } ++ /* invalidate BTB */ ++ asm volatile ( ".set mips32\n\t" ++ " mfc0 $26, $16, 7\n\t" ++ " nop\n\t" ++ " ori $26, 2\n\t" ++ " mtc0 $26, $16, 7\n\t" ++ " nop\n\t" ++ "nop\n\t" ++ ".set mips32\n\t" ++ ); ++} ++ ++ ++#endif /* __CHIP_CACHE_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_include_soc_cpm.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_include_soc_cpm.h.patch new file mode 100644 index 00000000..99ea3c32 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_include_soc_cpm.h.patch @@ -0,0 +1,163 @@ +diff -drupN a/arch/mips/xburst/soc-x1000/include/soc/cpm.h b/arch/mips/xburst/soc-x1000/include/soc/cpm.h +--- a/arch/mips/xburst/soc-x1000/include/soc/cpm.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/soc-x1000/include/soc/cpm.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,159 @@ ++/* ++ * SOC CPM register definition. ++ * ++ * CPM (Clock reset and Power control Management) ++ * ++ * Copyright (C) 2010 Ingenic Semiconductor Co., Ltd. ++ */ ++ ++#ifndef __SOC_CPM_H__ ++#define __SOC_CPM_H__ ++ ++#define CPM_CPCCR (0x00) ++#define CPM_CPCSR (0xd4) ++ ++#define CPM_DDRCDR (0x2c) ++#define CPM_I2SCDR (0x60) ++#define CPM_I2SCDR1 (0x70) ++#define CPM_LPCDR (0x64) ++#define CPM_MSC0CDR (0x68) ++#define CPM_MSC1CDR (0xa4) ++#define CPM_USBCDR (0x50) ++#define CPM_MACCDR (0x54) ++#define CPM_SFCCDR (0x74) ++#define CPM_CIMCDR (0x7c) ++#define CPM_PCMCDR (0x84) ++#define CPM_PCMCDR1 (0xe0) ++#define CPM_MPHYC (0xe8) ++ ++#define CPM_INTR (0xb0) ++#define CPM_INTRE (0xb4) ++#define CPM_DRCG (0xd0) ++#define CPM_CPSPPR (0x38) ++#define CPM_CPPSR (0x34) ++ ++#define CPM_USBPCR (0x3c) ++#define CPM_USBRDT (0x40) ++#define CPM_USBVBFIL (0x44) ++#define CPM_USBPCR1 (0x48) ++ ++#define CPM_CPAPCR (0x10) ++#define CPM_CPMPCR (0x14) ++ ++#define CPM_LCR (0x04) ++#define CPM_PSWC0ST (0x90) ++#define CPM_PSWC1ST (0x94) ++#define CPM_PSWC2ST (0x98) ++#define CPM_PSWC3ST (0x9c) ++#define CPM_CLKGR (0x20) ++#define CPM_MESTSEL (0xec) ++#define CPM_SRBC (0xc4) ++#define CPM_ERNG (0xd8) ++#define CPM_RNG (0xdc) ++#define CPM_SLBC (0xc8) ++#define CPM_SLPC (0xcc) ++#define CPM_OPCR (0x24) ++#define CPM_RSR (0x08) ++ ++#define LCR_LPM_MASK (0x3) ++#define LCR_LPM_SLEEP (0x1) ++ ++#ifndef BIT ++#define BIT(nr) (1UL << nr) ++#endif ++ ++/*USB Parameter Control Register*/ ++#define USBPCR_USB_MODE BIT(31) ++#define USBPCR_AVLD_REG BIT(30) ++#define USBPCR_IDPULLUP_MASK_BIT 28 ++#define USBPCR_IDPULLUP_MASK_MSK (0x3 << USBPCR_IDPULLUP_MASK_BIT) ++#define USBPCR_IDPULLUP_OTG (0x0 << USBPCR_IDPULLUP_MASK_BIT) ++#define USBPCR_IDPULLUP_ALWAYS_SUSPEND (0x1 << USBPCR_IDPULLUP_MASK_BIT) ++#define USBPCR_IDPULLUP_ALWAYS (0x2 << USBPCR_IDPULLUP_MASK_BIT) ++#define USBPCR_INCR_MASK BIT(27) ++#define USBPCR_TXRISETUNE BIT(26) /*0*/ ++#define USBPCR_COMMONONN BIT(25) ++#define USBPCR_VBUSVLDEXT BIT(24) ++#define USBPCR_VBUSVLDEXTSEL BIT(23) ++#define USBPCR_POR_BIT 22 ++#define USBPCR_POR BIT(USBPCR_POR_BIT) ++#define USBPCR_SIDDQ BIT(21) ++#define USBPCR_OTG_DISABLE BIT(20) ++#define USBPCR_COMPDISTUNE_BIT 17 ++#define USBPCR_COMPDISTUNE_MSK (0x7 << USBPCR_COMPDISTUNE_BIT) ++#define USBPCR_COMPDISTUNE(x) (((x) << USBPCR_COMPDISTUNE_BIT) & USBPCR_COMPDISTUNE_MSK) /*4*/ ++#define USBPCR_OTGTUNE_BIT 14 ++#define USBPCR_OTGTUNE_MSK (0x7 << USBPCR_OTGTUNE_BIT) ++#define USBPCR_OTGTUNE(x) (((x) << USBPCR_OTGTUNE_BIT) & USBPCR_OTGTUNE_MSK) /*4*/ ++#define USBPCR_SQRXTUNE_BIT 11 ++#define USBPCR_SQRXTUNE_MSK (0x7 << USBPCR_SQRXTUNE_BIT) ++#define USBPCR_SQRXTUNE(x) (((x) << USBPCR_SQRXTUNE_BIT) & USBPCR_SQRXTUNE_MSK) /*3*/ ++#define USBPCR_TXFSLSTUNE_BIT 7 ++#define USBPCR_TXFSLSTUNE_MSK (0xf << USBPCR_TXFSLSTUNE_BIT) ++#define USBPCR_TXFSLSTUNE(x) (((x) << USBPCR_TXFSLSTUNE_BIT) & USBPCR_TXFSLSTUNE_MSK) /*2*/ ++#define USBPCR_TXPREEMPHTUNE BIT(6) /*0*/ ++#define USBPCR_TXHSXVTUNE_BIT 4 ++#define USBPCR_TXHSXVTUNE_MSK (0x3 << USBPCR_TXHSXVTUNE_BIT) ++#define USBPCR_TXHSXVTUNE(x) (((x) << USBPCR_TXHSXVTUNE_BIT) & USBPCR_TXHSXVTUNE_MSK) /*3*/ ++#define USBPCR_TXVREFTUNE_BIT 0 ++#define USBPCR_TXVREFTUNE_MSK (0xf << USBPCR_TXVREFTUNE_BIT) ++#define USBPCR_TXVREFTUNE(x) (((x) << USBPCR_TXVREFTUNE_BIT) & USBPCR_TXVREFTUNE_MSK) /*4*/ ++ ++/*USB Reset Detect Timer Register*/ ++#define USBRDT_HB_MASK BIT(26) ++#define USBRDT_VBFIL_LD_EN BIT(25) ++#define USBRDT_IDDIG_EN 24 ++#define USBRDT_IDDIG_REG 23 ++#define USBRDT_USBRDT_MSK (0x7fffff) ++#define USBRDT_USBRDT(x) ((x) & USBRDT_USBRDT_MSK) ++ ++/*USB VBUS Jitter Filter Register*/ ++#define USBVBFIL_USBVBFIL(x) ((x) & 0xffff) ++#define USBVBFIL_IDDIGFIL(x) ((x) & (0xffff << 16)) ++ ++/*USB Parameter Control Register1*/ ++#define USBPCR1_BVLD_REG BIT(31) ++#define USBPCR1_REFCLKSEL (0x3 << 26) ++#define USBPCR1_REFCLKDIV_MSK (0x3 << 24) ++#define USBPCR1_REFCLKDIV(x) (((x) & 0x3) << 24) ++#define USBPCR1_REFCLKDIV_48M (0x2) ++#define USBPCR1_REFCLKDIV_24M (0x1) ++#define USBPCR1_REFCLKDIV_12M (0x0) ++#define USBPCR1_PORT_RST BIT(21) ++#define USBPCR1_PORT1_RST BIT(20) ++#define USBPCR1_WORD_IF_16BIT BIT(19) ++#define USBPCR1_WORD_IF1_16BIT BIT(18) ++#define USBPCR1_COMPDISTUNE1_BIT 15 ++#define USBPCR1_COMPDISTUNE1_MSK (0x7 << USBPCR1_COMPDISTUNE1_BIT) ++#define USBPCR1_COMPDISTUNE1(x) (((x) << USBPCR1_COMPDISTUNE1_BIT) & USBPCR1_COMPDISTUNE1_MSK) ++#define USBPCR1_SQRXTUNE1_BIT 12 ++#define USBPCR1_SQRXTUNE1_MSK (0x7 << USBPCR1_SQRXTUNE1_BIT) ++#define USBPCR1_SQRXTUNE1(x) (((x) << USBPCR1_SQRXTUNE1_BIT) & USBPCR1_SQRXTUNE1_MSK) /*3*/ ++#define USBPCR1_TXFSLSTUNE1_BIT 8 ++#define USBPCR1_TXFSLSTUNE1_MSK (0xf << USBPCR1_TXFSLSTUNE1_BIT) ++#define USBPCR1_TXFSLSTUNE1(x) (((x) << USBPCR1_TXFSLSTUNE1_BIT) & USBPCR1_TXFSLSTUNE1_MSK) /*2*/ ++#define USBPCR1_TXPREEMPHTUNE1 BIT(6) /*0*/ ++#define USBPCR1_TXHSXVTUNE1_BIT 5 ++#define USBPCR1_TXHSXVTUNE1_MSK (0x3 << USBPCR1_TXHSXVTUNE1_BIT) ++#define USBPCR1_TXHSXVTUNE1(x) (((x) << USBPCR1_TXHSXVTUNE1_BIT) & USBPCR1_TXHSXVTUNE1_MSK) /*3*/ ++#define USBPCR1_TXVREFTUNE1_BIT 1 ++#define USBPCR1_TXVREFTUNE1_MSK (0xf << USBPCR1_TXVREFTUNE1_BIT) ++#define USBPCR1_TXVREFTUNE1(x) (((x) << USBPCR1_TXVREFTUNE1_BIT) & USBPCR1_TXVREFTUNE1_MSK) /*4*/ ++#define USBPCR1_TXRISETUNE1 BIT(0) ++ ++/*Oscillator and Power Control Register*/ ++#define OPCR_IDLE BIT(31) ++#define OPCR_USB_SPENDN BIT(7) ++#define OPCR_USB_SPENDN1 BIT(6) ++#define OPCR_PD BIT(3) ++#define OPCR_ERCS BIT(2) ++ ++/*Soft Reset and Bus Control Register*/ ++#define SRBC_OTG_SR BIT(12) ++ ++#define cpm_inl(off) inl(CPM_IOBASE + (off)) ++#define cpm_outl(val,off) outl(val,CPM_IOBASE + (off)) ++#define cpm_clear_bit(val,off) do{cpm_outl((cpm_inl(off) & ~(1<<(val))),off);}while(0) ++#define cpm_set_bit(val,off) do{cpm_outl((cpm_inl(off) | (1<>= 2; n++; }; (n-1);}) ++#define TCCRDIV2(x) (TCCRDIV1((x)) << TCCRDIV_SFT2) ++ ++#define TESR_OSTEN1 (1 << 0) /* enable the counter1 in ost */ ++#define TESR_OSTEN2 (1 << 1) /* enable the counter2 in ost */ ++ ++#define TCR_OSTCLR1 (1 << 0) ++#define TCR_OSTCLR2 (1 << 1) ++ ++#define TMR_OSTM (1 << 0) /* ost comparison match interrupt mask */ ++ ++#define TFR_OSTM (1 << 0) /* Comparison match */ ++ ++#define ost_readl(reg) readl_relaxed(reg) ++#define ost_writel(reg, val) writel_relaxed(val, reg) ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_include_soc_sfc.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_include_soc_sfc.h.patch new file mode 100644 index 00000000..bb2d8c9c --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_include_soc_sfc.h.patch @@ -0,0 +1,156 @@ +diff -drupN a/arch/mips/xburst/soc-x1000/include/soc/sfc.h b/arch/mips/xburst/soc-x1000/include/soc/sfc.h +--- a/arch/mips/xburst/soc-x1000/include/soc/sfc.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/soc-x1000/include/soc/sfc.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,152 @@ ++#ifndef __SFC_REGISTER_H ++#define __SFC_REGISTER_H ++ ++/* SFC register */ ++ ++#define SFC_GLB (0x0000) ++#define SFC_DEV_CONF (0x0004) ++#define SFC_DEV_STA_EXP (0x0008) ++#define SFC_DEV_STA_RT (0x000c) ++#define SFC_DEV_STA_MSK (0x0010) ++#define SFC_TRAN_CONF(n) (0x0014 + (n * 4)) ++#define SFC_TRAN_LEN (0x002c) ++#define SFC_DEV_ADDR(n) (0x0030 + (n * 4)) ++#define SFC_DEV_ADDR_PLUS(n) (0x0048 + (n * 4)) ++#define SFC_MEM_ADDR (0x0060) ++#define SFC_TRIG (0x0064) ++#define SFC_SR (0x0068) ++#define SFC_SCR (0x006c) ++#define SFC_INTC (0x0070) ++#define SFC_FSM (0x0074) ++#define SFC_CGE (0x0078) ++#define SFC_RM_DR (0x1000) ++ ++/* For SFC_GLB */ ++#define GLB_TRAN_DIR (1 << 13) ++#define GLB_TRAN_DIR_WRITE (1) ++#define GLB_TRAN_DIR_READ (0) ++#define GLB_THRESHOLD_OFFSET (7) ++#define GLB_THRESHOLD_MSK (0x3f << GLB_THRESHOLD_OFFSET) ++#define GLB_OP_MODE (1 << 6) ++#define SLAVE_MODE (0x0) ++#define DMA_MODE (0x1) ++#define GLB_PHASE_NUM_OFFSET (3) ++#define GLB_PHASE_NUM_MSK (0x7 << GLB_PHASE_NUM_OFFSET) ++#define GLB_WP_EN (1 << 2) ++#define GLB_BURST_MD_OFFSET (0) ++#define GLB_BURST_MD_MSK (0x3 << GLB_BURST_MD_OFFSET) ++ ++/* For SFC_DEV_CONF */ ++#define DEV_CONF_ONE_AND_HALF_CYCLE_DELAY (3) ++#define DEV_CONF_ONE_CYCLE_DELAY (2) ++#define DEV_CONF_HALF_CYCLE_DELAY (1) ++#define DEV_CONF_NO_DELAY (0) ++#define DEV_CONF_SMP_DELAY_OFFSET (16) ++#define DEV_CONF_SMP_DELAY_MSK (0x3 << DEV_CONF_SMP_DELAY_OFFSET) ++#define DEV_CONF_CMD_TYPE (0x1 << 15) ++#define DEV_CONF_STA_TYPE_OFFSET (13) ++#define DEV_CONF_STA_TYPE_MSK (0x1 << DEV_CONF_STA_TYPE_OFFSET) ++#define DEV_CONF_THOLD_OFFSET (11) ++#define DEV_CONF_THOLD_MSK (0x3 << DEV_CONF_THOLD_OFFSET) ++#define DEV_CONF_TSETUP_OFFSET (9) ++#define DEV_CONF_TSETUP_MSK (0x3 << DEV_CONF_TSETUP_OFFSET) ++#define DEV_CONF_TSH_OFFSET (5) ++#define DEV_CONF_TSH_MSK (0xf << DEV_CONF_TSH_OFFSET) ++#define DEV_CONF_CPHA (0x1 << 4) ++#define DEV_CONF_CPOL (0x1 << 3) ++#define DEV_CONF_CEDL (0x1 << 2) ++#define DEV_CONF_HOLDDL (0x1 << 1) ++#define DEV_CONF_WPDL (0x1 << 0) ++ ++/* For SFC_TRAN_CONF */ ++#define TRAN_CONF_TRAN_MODE_OFFSET (29) ++#define TRAN_CONF_TRAN_MODE_MSK (0x7) ++#define TRAN_CONF_ADDR_WIDTH_OFFSET (26) ++#define TRAN_CONF_ADDR_WIDTH_MSK (0x7 << ADDR_WIDTH_OFFSET) ++#define TRAN_CONF_POLLEN (1 << 25) ++#define TRAN_CONF_POLL_OFFSET (25) ++#define TRAN_CONF_CMDEN (1 << 24) ++#define TRAN_CONF_FMAT (1 << 23) ++#define TRAN_CONF_FMAT_OFFSET (23) ++#define TRAN_CONF_DMYBITS_OFFSET (17) ++#define TRAN_CONF_DMYBITS_MSK (0x3f << DMYBITS_OFFSET) ++#define TRAN_CONF_DATEEN (1 << 16) ++#define TRAN_CONF_DATEEN_OFFSET (16) ++#define TRAN_CONF_CMD_OFFSET (0) ++#define TRAN_CONF_CMD_MSK (0xffff << CMD_OFFSET) ++#define TRAN_CONF_CMD_LEN (1 << 15) ++ ++/* For SFC_TRIG */ ++#define TRIG_FLUSH (1 << 2) ++#define TRIG_STOP (1 << 1) ++#define TRIG_START (1 << 0) ++ ++/* For SFC_SCR */ ++#define CLR_END (1 << 4) ++#define CLR_TREQ (1 << 3) ++#define CLR_RREQ (1 << 2) ++#define CLR_OVER (1 << 1) ++#define CLR_UNDER (1 << 0) ++ ++/* For SFC_TRAN_CONFx */ ++#define TRAN_MODE_OFFSET (29) ++#define TRAN_MODE_MSK (0x7 << TRAN_MODE_OFFSET) ++#define TRAN_SPI_STANDARD (0x0) ++#define TRAN_SPI_DUAL (0x1 ) ++#define TRAN_SPI_QUAD (0x5 ) ++#define TRAN_SPI_IO_QUAD (0x6 ) ++ ++ ++#define ADDR_WIDTH_OFFSET (26) ++#define ADDR_WIDTH_MSK (0x7 << ADDR_WIDTH_OFFSET) ++#define POLLEN (1 << 25) ++#define CMDEN (1 << 24) ++#define FMAT (1 << 23) ++#define DMYBITS_OFFSET (17) ++#define DMYBITS_MSK (0x3f << DMYBITS_OFFSET) ++#define DATEEN (1 << 16) ++#define CMD_OFFSET (0) ++#define CMD_MSK (0xffff << CMD_OFFSET) ++ ++#define N_MAX 6 ++#define MAX_SEGS 128 ++ ++#define CHANNEL_0 0 ++#define CHANNEL_1 1 ++#define CHANNEL_2 2 ++#define CHANNEL_3 3 ++#define CHANNEL_4 4 ++#define CHANNEL_5 5 ++ ++#define ENABLE 1 ++#define DISABLE 0 ++ ++#define COM_CMD 1 // common cmd ++#define POLL_CMD 2 // the cmd will poll the status of flash,ext: read status ++ ++#define DMA_OPS 1 ++#define CPU_OPS 0 ++ ++#define TM_STD_SPI 0 ++#define TM_DI_DO_SPI 1 ++#define TM_DIO_SPI 2 ++#define TM_FULL_DIO_SPI 3 ++#define TM_QI_QO_SPI 5 ++#define TM_QIO_SPI 6 ++#define TM_FULL_QIO_SPI 7 ++ ++ ++#define DEFAULT_ADDRSIZE 3 ++ ++ ++#define THRESHOLD 32 ++ ++#define SFC_NOR_RATE 110 ++#define DEF_ADDR_LEN 3 ++#define DEF_TCHSH 5 ++#define DEF_TSLCH 5 ++#define DEF_TSHSL_R 20 ++#define DEF_TSHSL_W 50 ++ ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_include_soc_tcsm_layout.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_include_soc_tcsm_layout.h.patch new file mode 100644 index 00000000..18548d60 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_include_soc_tcsm_layout.h.patch @@ -0,0 +1,57 @@ +diff -drupN a/arch/mips/xburst/soc-x1000/include/soc/tcsm_layout.h b/arch/mips/xburst/soc-x1000/include/soc/tcsm_layout.h +--- a/arch/mips/xburst/soc-x1000/include/soc/tcsm_layout.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/soc-x1000/include/soc/tcsm_layout.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,53 @@ ++#ifndef __TCSM_LAYOUT_H__ ++#define __TCSM_LAYOUT_H__ ++ ++/** ++ * |-------------| ++ * | BANK0 | ++ * |-------------| <--- SLEEP_TCSM_BOOTCODE_TEXT ++ * | | ++ * | | ++ * | | ++ * | | ++ * | | ++ * | | ++ * | | ++ * |-------------| ++ * | VO DMA DESC | ++ * |_____________| <--- VOICE_TCSM_DMA_DESC ++ * ++ * ++ * |-------------| ++ * | BANK1 | ++ * |-------------| <--- VOICE_TCSM_DATA_BUF ++ * | | ++ * | | ++ * | ... | ++ * | VOICE DATA | ++ * | ... | ++ * | | ++ * | | ++ * |_____________| ++ * ++ */ ++ ++/* ++ * If you use the VOICE TRIGGER, ++ * and you change the VOICE_* and TCSM_BANK_LEN, ++ * while compiling wakeup module ++ */ ++#define SLEEP_TCSM_SPACE 0xb3422000 ++#define VOICE_TCSM_DATA_BUF 0xb3423000 ++#define TCSM_BANK_LEN 4096 ++ ++#define SLEEP_TCSM_BOOT_TEXT (SLEEP_TCSM_SPACE) ++ ++#define VOICE_TCSM_DMA_DESC_LEN 512 ++#define SLEEP_TCSM_SPACE_END (SLEEP_TCSM_SPACE + TCSM_BANK_LEN - VOICE_TCSM_DMA_DESC_LEN) ++#define VOICE_TCSM_DMA_DESC_ADDR SLEEP_TCSM_SPACE_END ++ ++#define SLEEP_TCSM_CPU_RESMUE_SP SLEEP_TCSM_SPACE_END - 4 ++ ++#define VOICE_TCSM_DATA_BUF_SIZE TCSM_BANK_LEN ++ ++#endif /* __TCSM_LAYOUT_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_include_soc_tcu.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_include_soc_tcu.h.patch new file mode 100644 index 00000000..063ec287 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_include_soc_tcu.h.patch @@ -0,0 +1,41 @@ +diff -drupN a/arch/mips/xburst/soc-x1000/include/soc/tcu.h b/arch/mips/xburst/soc-x1000/include/soc/tcu.h +--- a/arch/mips/xburst/soc-x1000/include/soc/tcu.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/soc-x1000/include/soc/tcu.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,37 @@ ++#ifndef __TCU_H__ ++#define __TCU_H__ ++ ++#define WDT_TDR (0x00) /* rw, 32, 0x???????? */ ++#define WDT_TCER (0x04) /* rw, 32, 0x???????? */ ++#define WDT_TCNT (0x08) /* rw, 32, 0x???????? */ ++#define WDT_TCSR (0x0c) /* rw, 32, 0x???????? */ ++ ++#define TCU_TSTR (0xF0) /* Timer Status Register,Only Used In Tcu2 Mode */ ++#define TCU_TSTSR (0xF4) /* Timer Status Set Register */ ++#define TCU_TSTCR (0xF8) /* Timer Status Clear Register */ ++#define TCU_TSR (0x1C) /* Timer Stop Register */ ++#define TCU_TSSR (0x2C) /* Timer Stop Set Register */ ++#define TCU_TSCR (0x3C) /* Timer Stop Clear Register */ ++#define TCU_TER (0x10) /* Timer Counter Enable Register */ ++#define TCU_TESR (0x14) /* Timer Counter Enable Set Register */ ++#define TCU_TECR (0x18) /* Timer Counter Enable Clear Register */ ++#define TCU_TFR (0x20) /* Timer Flag Register */ ++#define TCU_TFSR (0x24) /* Timer Flag Set Register */ ++#define TCU_TFCR (0x28) /* Timer Flag Clear Register */ ++#define TCU_TMR (0x30) /* Timer Mask Register */ ++#define TCU_TMSR (0x34) /* Timer Mask Set Register */ ++#define TCU_TMCR (0x38) /* Timer Mask Clear Register */ ++ ++#define CH_TDFR(n) (0x40 + (n)*0x10) /* Timer Data Full Reg */ ++#define CH_TDHR(n) (0x44 + (n)*0x10) /* Timer Data Half Reg */ ++#define CH_TCNT(n) (0x48 + (n)*0x10) /* Timer Counter Reg */ ++#define CH_TCSR(n) (0x4C + (n)*0x10) /* Timer Control Reg */ ++ ++#define TCSR_PWM_BYPASS (1 << 11) /* clear counter to 0, only used in TCU2 mode */ ++#define TCSR_CNT_CLRZ (1 << 10) /* clear counter to 0, only used in TCU2 mode */ ++#define TCSR_PWM_SD (1 << 9) /* shut down the pwm output only used in TCU1 mode */ ++#define TCSR_PWM_HIGH (1 << 8) /* selects an initial output level for pwm output */ ++#define TCSR_PWM_EN (1 << 7) /* pwm pin output enable */ ++#define TCSR_PWM_IN (1 << 6) /* pwm pin output enable */ ++ ++#endif /* __TCU_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_include_war.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_include_war.h.patch new file mode 100644 index 00000000..8934b909 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_include_war.h.patch @@ -0,0 +1,31 @@ +diff -drupN a/arch/mips/xburst/soc-x1000/include/war.h b/arch/mips/xburst/soc-x1000/include/war.h +--- a/arch/mips/xburst/soc-x1000/include/war.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/soc-x1000/include/war.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,27 @@ ++/* ++ * 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) 2002, 2004, 2007 by Ralf Baechle ++ */ ++#ifndef __ASM_MACH_INGENIC_WAR_H__ ++#define __ASM_MACH_INGENIC_WAR_H__ ++ ++#define R4600_V1_INDEX_ICACHEOP_WAR 0 ++#define R4600_V1_HIT_CACHEOP_WAR 0 ++#define R4600_V2_HIT_CACHEOP_WAR 0 ++#define R5432_CP0_INTERRUPT_WAR 0 ++#define BCM1250_M3_WAR 0 ++#define SIBYTE_1956_WAR 0 ++#define MIPS4K_ICACHE_REFILL_WAR 0 ++#define MIPS_CACHE_SYNC_WAR 1 ++#define MIPS_BRIDGE_SYNC_WAR 1 ++#define TX49XX_ICACHE_INDEX_INV_WAR 0 ++#define RM9000_CDEX_SMP_WAR 0 ++#define ICACHE_REFILLS_WORKAROUND_WAR 0 ++#define R10000_LLSC_WAR 0 ++#define MIPS34K_MISSED_ITLB_WAR 0 ++ ++#endif ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_pm.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_pm.c.patch new file mode 100644 index 00000000..50bd9ecd --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_pm.c.patch @@ -0,0 +1,221 @@ +diff -drupN a/arch/mips/xburst/soc-x1000/pm.c b/arch/mips/xburst/soc-x1000/pm.c +--- a/arch/mips/xburst/soc-x1000/pm.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/soc-x1000/pm.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,217 @@ ++/* ++ * linux/arch/mips/xburst/soc-m200/common/pm_p0.c ++ * ++ * M200 Power Management Routines ++ * Copyright (C) 2006 - 2012 Ingenic Semiconductor Inc. ++ * ++ * This program is free software; you can distribute 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 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++extern long long save_goto(unsigned int); ++extern int restore_goto(void); ++ ++unsigned int pm_firmware_new[] ={ ++#include "core_sleep.hex" ++}; ++ ++void load_pm_firmware_new(unsigned int addr) ++{ ++ void (*func)(unsigned int addr,unsigned int to); ++ unsigned int firmware_size = sizeof(pm_firmware_new); ++ ++ if(firmware_size > TCSM_BANK_LEN * 1024) ++ printk("WARN: firmware_size %d bigger than" \ ++ "TCSM_BANK_LEN %d\n", firmware_size, TCSM_BANK_LEN * 1024); ++ ++ func = (void (*)(unsigned int,unsigned int))addr; ++ memcpy((void *)addr,pm_firmware_new,firmware_size); ++ func(addr,0); ++} ++struct sleep_param ++{ ++ unsigned int pm_core_enter; ++ unsigned char pmu_i2c_scl; //default 0xff ++ unsigned char pmu_i2c_sda; //default 0xff ++ unsigned char pmu_addr; //default 0xff ++ unsigned char pmu_reg; //default 0xff ++ unsigned char pmu_register_val; ++ ++ unsigned char pmu_pin; //default 0xff ++ unsigned char pmu_pin_func; //default 0xff ++ unsigned char uart_id; //default 0xff ++ ++ unsigned int prev_resume_pc; //ddr is self-reflash default 0xffffffff ++ unsigned int post_resume_pc; //ddr is ok. default 0xffffffff ++ unsigned int prev_sleep_pc; //after flush cache. default 0xffffffff ++ unsigned int post_sleep_pc; //before wait. default 0xffffffff ++ ++}; ++struct sleep_save_register ++{ ++ unsigned int lcr; ++ unsigned int opcr; ++ unsigned int clkgr; ++ unsigned int sleep_voice_enable; ++ unsigned int ddr_training_space[20]; ++ suspend_state_t pm_state; ++}; ++ ++static struct sleep_save_register s_reg; ++struct sleep_param *sleep_param; ++ ++static int soc_pm_enter(suspend_state_t state) ++{ ++ unsigned int lcr,opcr, clkgr; ++ ++ /** ++ sleep code use PDMA_TCSM, so must enable pdma and nemc ++ */ ++ s_reg.clkgr = clkgr = cpm_inl(CPM_CLKGR); ++ clkgr &= ~(1 << 21); ++ cpm_outl(clkgr, CPM_CLKGR); ++ ++ memcpy(&s_reg.ddr_training_space,(void*)0x80000000,sizeof(s_reg.ddr_training_space)); ++ s_reg.opcr = cpm_inl(CPM_OPCR); ++ s_reg.lcr = cpm_inl(CPM_LCR); ++ ++ load_pm_firmware_new(SLEEP_TCSM_SPACE); ++ sleep_param = (struct sleep_param *)SLEEP_TCSM_SPACE; ++ ++ sleep_param->post_resume_pc = (unsigned int)restore_goto; ++ sleep_param->uart_id = -1; ++ /* ++ * set OPCR. ++ */ ++ opcr = s_reg.opcr; ++ lcr = s_reg.lcr; ++ ++ opcr &= ~((1 << 25) | (1 << 22) | (0xfff << 8) | (1 << 4) | (1 << 3) | (1 << 2)); ++ opcr |= (1 << 31) | (1 << 30) | (1 << 25) | (0xfff << 8) | (1 << 4) | (1 << 3); ++ lcr &= ~3; ++ ++#ifdef CONFIG_RTC_DRV_INGENIC ++ opcr &= ~((1 << 4) | (1 << 2)); ++ opcr |= (1 << 2); ++#endif ++ ++ if(s_reg.pm_state == PM_SUSPEND_STANDBY) { ++ opcr &= ~((1 << 31) | (1 << 30)); ++ } else { ++ lcr |= LCR_LPM_SLEEP; ++ } ++ cpm_outl(opcr,CPM_OPCR); ++ cpm_outl(lcr,CPM_LCR); ++ ++ printk("#####lcr:%08x\n", cpm_inl(CPM_LCR)); ++ printk("#####gate:%08x\n", cpm_inl(CPM_CLKGR)); ++ printk("#####opcr:%08x\n", cpm_inl(CPM_OPCR)); ++ printk("#####INT_MASK0:%08x\n", *(volatile unsigned int*)(0xB0001004)); ++ printk("#####INT_MASK1:%08x\n", *(volatile unsigned int*)(0xB0001024)); ++ printk("#####INT_PEND0:%08x\n", *(volatile unsigned int*)(0xB0001010)); ++ printk("#####INT_PEND1:%08x\n", *(volatile unsigned int*)(0xB0001030)); ++ ++ mb(); ++ save_goto((unsigned int)sleep_param->pm_core_enter); ++ mb(); ++ ++ memcpy((void*)0x80000000,&s_reg.ddr_training_space,sizeof(s_reg.ddr_training_space)); ++ dma_cache_wback_inv(0x80000000,sizeof(s_reg.ddr_training_space)); ++ cpm_outl(s_reg.lcr,CPM_LCR); ++ cpm_outl(s_reg.opcr,CPM_OPCR); ++ cpm_outl(s_reg.clkgr, CPM_CLKGR); ++ ++ return 0; ++} ++ ++static int soc_valid(suspend_state_t state) ++{ ++ switch (state) { ++ case PM_SUSPEND_ON: ++ case PM_SUSPEND_STANDBY: ++ case PM_SUSPEND_MEM: ++ return 1; ++ ++ default: ++ return 0; ++ } ++} ++static void soc_finish(void) ++{ ++ s_reg.pm_state = 0; ++} ++static int soc_begin(suspend_state_t state) ++{ ++ s_reg.pm_state = state; ++ if(s_reg.pm_state == PM_SUSPEND_STANDBY) { ++ jz_notifier_call(NOTEFY_PROI_HIGH, JZ_PM_SUSPEND_STANDBY, &s_reg.pm_state); ++ } ++ return 0; ++} ++ ++/* ++ * Initialize power interface ++ */ ++struct platform_suspend_ops pm_ops = { ++ .valid = soc_valid, ++ .begin = soc_begin, ++ .enter = soc_pm_enter, ++ .end = soc_finish, ++}; ++ ++int __init soc_pm_init(void) ++{ ++ volatile unsigned int lcr,opcr; ++ ++ suspend_set_ops(&pm_ops); ++ ++ /* init opcr and lcr for idle */ ++ lcr = cpm_inl(CPM_LCR); ++ lcr &= ~(0x3); /* LCR.SLEEP.DS=1'b0,LCR.LPM=2'b00*/ ++ lcr |= 0xff << 8; /* power stable time */ ++ cpm_outl(lcr,CPM_LCR); ++ ++ opcr = cpm_inl(CPM_OPCR); ++ opcr |= 0xff << 8; /* EXCLK stable time */ ++ opcr &= ~(1 << 4); /* EXCLK oscillator is disabled in Sleep mode */ ++ cpm_outl(opcr,CPM_OPCR); ++ ++ /* sysfs */ ++ return 0; ++} ++ ++arch_initcall(soc_pm_init); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_regs_save_restore.S.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_regs_save_restore.S.patch new file mode 100644 index 00000000..6beeda96 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_regs_save_restore.S.patch @@ -0,0 +1,176 @@ +diff -drupN a/arch/mips/xburst/soc-x1000/regs_save_restore.S b/arch/mips/xburst/soc-x1000/regs_save_restore.S +--- a/arch/mips/xburst/soc-x1000/regs_save_restore.S 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/soc-x1000/regs_save_restore.S 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,172 @@ ++#include ++#include ++ ++#define CP0_CONTEXT $4,0 ++#define CP0_PAGEMASK $5,0 ++#define CP0_TLB_SPEC $5,4 ++#define CP0_STATUS $12,0 ++#define CP0_INTCTL $12,1 ++#define CP0_CAUSE $13,0 ++#define CP0_EBASE $15,1 ++#define CP0_CONFIG $16,0 ++#define CP0_CONFIG1 $16,1 ++#define CP0_CONFIG2 $16,2 ++#define CP0_CONFIG3 $16,3 ++#define CP0_CONFIG7 $16,7 ++#define CP0_LLADDR $17,0 ++#define PMON_CSR $17,7 ++#define PMON_HIGH $17,4 ++#define PMON_LC $17,5 ++#define PMON_RC $17,6 ++#define CP0_WATCHLo $18,0 ++#define CP0_WATCHHI $19,0 ++#define CP0_ERRCTL $26,0 ++ ++ .data ++ .global _regs_stack ++_regs_stack: ++ .align 5 ++ .space 128,0 ++ ++ .text ++ .global save_goto ++ .align 2 ++ .ent save_goto,0 ++save_goto: ++ .set push ++ .set noreorder ++ .set noat ++ ++ la k0, _regs_stack ++ sw s0,0(k0) ++ sw s1,4(k0) ++ sw s2,8(k0) ++ sw s3,12(k0) ++ sw s4,16(k0) ++ sw s5,20(k0) ++ sw s6,24(k0) ++ sw s7,28(k0) ++ sw gp,32(k0) ++ sw sp,36(k0) ++ sw fp,40(k0) ++ sw ra,44(k0) ++ ++ mfc0 k1,CP0_PAGEMASK ++ sw k1,48(k0) ++ mfc0 k1,CP0_TLB_SPEC ++ sw k1,52(k0) ++ mfc0 k1,CP0_STATUS ++ sw k1,56(k0) ++ mfc0 k1,CP0_INTCTL ++ sw k1,60(k0) ++ mfc0 k1,CP0_CAUSE ++ sw k1,64(k0) ++ mfc0 k1,CP0_EBASE ++ sw k1,68(k0) ++ mfc0 k1,CP0_CONFIG ++ sw k1,72(k0) ++ mfc0 k1,CP0_CONFIG1 ++ sw k1,76(k0) ++ mfc0 k1,CP0_CONFIG2 ++ sw k1,80(k0) ++ mfc0 k1,CP0_CONFIG3 ++ sw k1,84(k0) ++ mfc0 k1,CP0_CONFIG7 ++ sw k1,88(k0) ++ mfc0 k1,CP0_LLADDR ++ sw k1,92(k0) ++ mfc0 k1,PMON_CSR ++ sw k1,96(k0) ++ mfc0 k1,PMON_HIGH ++ sw k1,100(k0) ++ mfc0 k1,PMON_LC ++ sw k1,104(k0) ++ mfc0 k1,PMON_RC ++ sw k1,108(k0) ++ mfc0 k1,CP0_WATCHLo ++ sw k1,112(k0) ++ mfc0 k1,CP0_WATCHHI ++ sw k1,116(k0) ++ mfc0 k1,CP0_ERRCTL ++ sw k1,120(k0) ++ mfc0 k1,CP0_CONTEXT ++ sw k1,124(k0) ++ ++ jr a0 ++ nop ++ ++ .set at ++ .set reorder ++ .set pop ++ END(save_goto) ++ .text ++ .global restore_goto ++ .align 2 ++ .ent restore_goto,0 ++restore_goto: ++ .set push ++ .set noreorder ++ .set noat ++ ++ la k0, _regs_stack ++ lw s0,0(k0) ++ lw s1,4(k0) ++ lw s2,8(k0) ++ lw s3,12(k0) ++ lw s4,16(k0) ++ lw s5,20(k0) ++ lw s6,24(k0) ++ lw s7,28(k0) ++ lw gp,32(k0) ++ lw sp,36(k0) ++ lw fp,40(k0) ++ lw ra,44(k0) ++ ++ lw k1,48(k0) ++ mtc0 k1,CP0_PAGEMASK ++ lw k1,52(k0) ++ mtc0 k1,CP0_TLB_SPEC ++ lw k1,56(k0) ++ mtc0 k1,CP0_STATUS ++ lw k1,60(k0) ++ mtc0 k1,CP0_INTCTL ++ lw k1,64(k0) ++ mtc0 k1,CP0_CAUSE ++ lw k1,68(k0) ++ mtc0 k1,CP0_EBASE ++ lw k1,72(k0) ++ mtc0 k1,CP0_CONFIG ++ lw k1,76(k0) ++ mtc0 k1,CP0_CONFIG1 ++ lw k1,80(k0) ++ mtc0 k1,CP0_CONFIG2 ++ lw k1,84(k0) ++ mtc0 k1,CP0_CONFIG3 ++ lw k1,88(k0) ++ mtc0 k1,CP0_CONFIG7 ++ lw k1,92(k0) ++ mtc0 k1,CP0_LLADDR ++ lw k1,96(k0) ++ mtc0 k1,PMON_CSR ++ lw k1,100(k0) ++ mtc0 k1,PMON_HIGH ++ lw k1,104(k0) ++ mtc0 k1,PMON_LC ++ lw k1,108(k0) ++ mtc0 k1,PMON_RC ++ lw k1,112(k0) ++ mtc0 k1,CP0_WATCHLo ++ lw k1,116(k0) ++ mtc0 k1,CP0_WATCHHI ++ lw k1,120(k0) ++ mtc0 k1,CP0_ERRCTL ++ lw k1,124(k0) ++ mtc0 k1,CP0_CONTEXT ++ ++ jr ra ++ nop ++ ++ .set at ++ .set reorder ++ .set pop ++ END(restore_goto) diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_setup.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_setup.c.patch new file mode 100644 index 00000000..e31fe72c --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_setup.c.patch @@ -0,0 +1,84 @@ +diff -drupN a/arch/mips/xburst/soc-x1000/setup.c b/arch/mips/xburst/soc-x1000/setup.c +--- a/arch/mips/xburst/soc-x1000/setup.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/soc-x1000/setup.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,80 @@ ++/* ++ * INGENIC SOC Setup ++ * ++ * 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) 2006 Ingenic Semiconductor Inc. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++extern void *get_fdt_addr(void); ++extern void __init soc_is_x1000e(void); ++ ++void __init plat_mem_setup(void) ++{ ++ void __iomem *cpm_iobase = (void __iomem *)CKSEG1ADDR(CPM_IOBASE); ++ ++ /* ingenic mips cpu special */ ++ __asm__ ( ++ "li $2, 0xa9000000 \n\t" ++ "mtc0 $2, $5, 4 \n\t" ++ "nop \n\t" ++ ::"r"(2)); ++ ++ set_io_port_base(IO_BASE); ++ /*Not have ioport*/ ++ ioport_resource.start = 0x00000000; ++ ioport_resource.end = 0x00000000; ++ iomem_resource.start = 0x10000000; ++ iomem_resource.end = 0x1fffffff; ++ ++ /*x1000 cpu special*/ ++ writel( 0, cpm_iobase + CPM_PSWC0ST); ++ writel(16, cpm_iobase + CPM_PSWC1ST); ++ writel(24, cpm_iobase + CPM_PSWC2ST); ++ writel( 8, cpm_iobase + CPM_PSWC3ST); ++ ++ __dt_setup_arch(get_fdt_addr()); ++ ++ early_init_fdt_scan_reserved_mem(); ++ ++ soc_is_x1000e(); ++ ++ return; ++} ++ ++void __init device_tree_init(void) ++{ ++ unflatten_and_copy_device_tree(); ++} ++ ++static int __init plat_of_populate(void) ++{ ++ of_platform_default_populate(NULL, NULL, NULL); ++ return 0; ++} ++arch_initcall(plat_of_populate); ++ ++void __init plat_time_init(void) ++{ ++ of_clk_init(NULL); ++ ++ clocksource_probe(); ++} ++ ++void __init arch_init_irq(void) { ++ ++ irqchip_init(); ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_socid.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_socid.c.patch new file mode 100644 index 00000000..f4b91fe3 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1000_socid.c.patch @@ -0,0 +1,114 @@ +diff -drupN a/arch/mips/xburst/soc-x1000/socid.c b/arch/mips/xburst/soc-x1000/socid.c +--- a/arch/mips/xburst/soc-x1000/socid.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/soc-x1000/socid.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,110 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define CLKGATE 0x20 ++#define CTRL_OFF 0x0 ++#define STATUS_OFF 0x8 ++#define DATA0_OFF 0xc ++ ++enum socid { ++ X1000 = 0xff00, ++ X1000E = 0xff01, ++ X1500 = 0xff02, ++ X1000_NEW = 0xff08, ++ X1000E_NEW = 0xff09, ++ X1500_NEW = 0xff0a, ++}; ++ ++static int read_socid(void) ++{ ++ void __iomem *efuse_iobase = (void __iomem *)CKSEG1ADDR(EFUSE_IOBASE); ++ void __iomem *cpm_iobase = (void __iomem *)CKSEG1ADDR(CPM_IOBASE); ++ uint32_t val = 0, timeout = 10; ++ uint32_t clkgat, clk_efuse_enable = 0; ++ int ret = 0; ++ ++ clkgat = readl(cpm_iobase + CLKGATE); ++ if(clkgat & (0x1 << 1)) { ++ clk_efuse_enable = 1; ++ writel(clkgat & ~(0x1 << 1), cpm_iobase + CLKGATE); ++ } ++ ++ writel(0, efuse_iobase + STATUS_OFF); ++ ++ val = 0x3c << 21 | 1 << 16 | 1; ++ writel(val, efuse_iobase + CTRL_OFF); ++ ++ while(!(readl(efuse_iobase + STATUS_OFF) & 1)) { ++ timeout --; ++ if(!timeout) { ++ ret = -EBUSY; ++ goto efuse_fail; ++ } ++ } ++ ret = readl(efuse_iobase + DATA0_OFF); ++efuse_fail: ++ if(clk_efuse_enable) ++ writel(clkgat, cpm_iobase + CLKGATE); ++ return ret; ++} ++ ++static int __init check_socid(void) { ++ ++ int socid = read_socid(); ++ if (socid < 0) { ++ pr_err("socid: efuse busy !\n"); ++ return -EBUSY; ++ } ++ switch(socid) { ++ case X1000: ++ case X1500: ++ case X1000E: ++ case X1000_NEW: ++ case X1000E_NEW: ++ case X1500_NEW: ++ case 0: ++ break; ++ default: ++ pr_err("socid: unknown x1000 socid !\n"); ++ return -ENODEV; ++ } ++ ++ return socid; ++} ++ ++static void __init ddr_param_change(int ddr_size) ++{ ++ int off; ++ ++ off = strcspn(arcs_cmdline, "M@"); ++ switch(ddr_size) { ++ case 64: ++ arcs_cmdline[off - 2] = '6'; ++ arcs_cmdline[off - 1] = '4'; ++ break; ++ case 256: ++ arcs_cmdline[off - 3] = '2'; ++ arcs_cmdline[off - 2] = '5'; ++ arcs_cmdline[off - 1] = '6'; ++ break; ++ default: ++ return; ++ } ++} ++ ++void __init soc_is_x1000e(void) ++{ ++ int socid; ++ ++ socid = check_socid(); ++ if(socid == X1000E || socid == X1000E_NEW){ ++ ddr_param_change(64); ++ } ++} ++ ++MODULE_DESCRIPTION("x1000 socid driver special used by itself"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_Makefile.patch new file mode 100644 index 00000000..94bf8068 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_Makefile.patch @@ -0,0 +1,8 @@ +diff -drupN a/arch/mips/xburst/soc-x1800/Makefile b/arch/mips/xburst/soc-x1800/Makefile +--- a/arch/mips/xburst/soc-x1800/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/soc-x1800/Makefile 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,4 @@ ++obj-y += setup.o ++obj-y += regs_save_restore.o ++obj-$(CONFIG_EARLY_PRINTK) += early_printk.o ++obj-$(CONFIG_PM) += pm.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_core_sleep.hex.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_core_sleep.hex.patch new file mode 100644 index 00000000..d2ee9e26 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_core_sleep.hex.patch @@ -0,0 +1,1030 @@ +diff -drupN a/arch/mips/xburst/soc-x1800/core_sleep.hex b/arch/mips/xburst/soc-x1800/core_sleep.hex +--- a/arch/mips/xburst/soc-x1800/core_sleep.hex 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/soc-x1800/core_sleep.hex 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,1026 @@ ++0x27bdfff4, ++0xafbc0000, ++0xafbf0004, ++0xafb90008, ++0x04110007, ++0x00000000, ++0x00008bb0, ++0x00000c54, ++0x00000c1c, ++0x00000c1c, ++0x00000bc0, ++0x00000017, ++0x8ffc0000, ++0x0384e021, ++0x8feb0014, ++0x8fec0010, ++0x008c6021, ++0x218c0008, ++0x240a0002, ++0x8d890000, ++0x01244821, ++0xad890000, ++0x214a0001, ++0x014b082a, ++0x1420fffa, ++0x218c0004, ++0x8fea0004, ++0x8fe90008, ++0x01445021, ++0x01244821, ++0x1000000a, ++0x21290008, ++0x8d2bfffc, ++0x216bfffd, ++0x15600006, ++0x00000000, ++0x8d2bfff8, ++0x01645821, ++0x8d6c0000, ++0x01846021, ++0xad6c0000, ++0x012a082a, ++0x1420fff5, ++0x21290008, ++0x8f898018, ++0x8f8a8018, ++0xad200000, ++0x012a082a, ++0x1420fffd, ++0x21290004, ++0x8f88801c, ++0xad050000, ++0x00805825, ++0x8f888020, ++0xad0b0000, ++0x8f8a8024, ++0xad6a0000, ++0x256b0004, ++0x240affff, ++0x21690040, ++0xad6a0000, ++0x256b0004, ++0x152bfffd, ++0x00000000, ++0x8fbc0000, ++0x8fbf0004, ++0x8fb90008, ++0x27bd000c, ++0x03e00008, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x04110001, ++0x00000000, ++0x27f90004, ++0x3c1c0001, ++0x279c898c, ++0x0399e021, ++0x27fdfffc, ++0x8f998028, ++0x03200008, ++0x00000000, ++0x04110001, ++0x00000000, ++0x27f90004, ++0x3c1c0001, ++0x279c8964, ++0x0399e021, ++0x27fdfff0, ++0x8f99802c, ++0x03200008, ++0x00000000, ++0x27bdfff0, ++0xafbc0000, ++0xafbf0004, ++0xafb90008, ++0x0080c825, ++0x00a02025, ++0x0320f809, ++0x00000000, ++0x8fbc0000, ++0x8fbf0004, ++0x8fb90008, ++0x27bd0010, ++0x03e00008, ++0x00000000, ++0x4080e000, ++0x3c028000, ++0x24434000, ++0xbc490000, ++0x24420020, ++0x1443fffd, ++0x00000000, ++0x3c028000, ++0x24434000, ++0xbc480000, ++0x24420020, ++0x1443fffd, ++0x00000000, ++0x401a8007, ++0x00000000, ++0x375a0002, ++0x409a8007, ++0x00000000, ++0x03e00008, ++0x00000000, ++0x3c1c0001, ++0x279c88c0, ++0x0399e021, ++0x8c820000, ++0x27bdffe0, ++0x3c030040, ++0x00431025, ++0xafbc0010, ++0x3c03b000, ++0xafb00018, ++0xafbf001c, ++0x3c10b000, ++0xac620000, ++0x8e0200d4, ++0x30420001, ++0x10400005, ++0x8f998030, ++0x041101c5, ++0x24040055, ++0x1000fff9, ++0x8fbc0010, ++0x8fbf001c, ++0x8fb00018, ++0x03e00008, ++0x27bd0020, ++0x3c028000, ++0x24434000, ++0xbc400000, ++0xbc410000, ++0x24420020, ++0x1443fffc, ++0x00000000, ++0x0000000f, ++0x03e00008, ++0x00000000, ++0x3c1c0001, ++0x279c8834, ++0x0399e021, ++0x8f998034, ++0x1000fff1, ++0x00000000, ++0x3c1c0001, ++0x279c881c, ++0x0399e021, ++0x27bdffe0, ++0xafbc0010, ++0xafbf001c, ++0xafb00018, ++0x14800013, ++0x24020001, ++0x3c04b000, ++0x8c820000, ++0x2403ff00, ++0x3c10b000, ++0xaca20000, ++0x00431024, ++0x3c030040, ++0x24630073, ++0x00431025, ++0xac820000, ++0x8e0200d4, ++0x30420001, ++0x1040000d, ++0x8f998030, ++0x04110196, ++0x24040055, ++0x1000fff9, ++0x8fbc0010, ++0x14820008, ++0x8fbf001c, ++0x8f998038, ++0x8fb00018, ++0x00a02025, ++0x273902f0, ++0x1000ffb5, ++0x27bd0020, ++0x8fbf001c, ++0x8fb00018, ++0x03e00008, ++0x27bd0020, ++0x3c1c0001, ++0x279c8780, ++0x0399e021, ++0x27bdffd8, ++0xafb1001c, ++0x8f918020, ++0xafbc0010, ++0xafbf0024, ++0x8e220000, ++0xafb20020, ++0xafb00018, ++0x8f99803c, ++0x0411016d, ++0x9044000b, ++0x8fbc0010, ++0x8f998034, ++0x0411ffb8, ++0x00000000, ++0x8fbc0010, ++0x3c02b000, ++0x24030001, ++0x8f928040, ++0xac4300c8, ++0xac5200cc, ++0xac400008, ++0x8e220000, ++0x8c440014, ++0x2402ffff, ++0x10820004, ++0x8f998044, ++0x0411ff6f, ++0x00002825, ++0x8fbc0010, ++0x40028000, ++0x8f848038, ++0x24900c28, ++0xae020010, ++0x40026000, ++0x3c03b301, ++0xae020014, ++0xac601054, ++0x3c02b34f, ++0x8c450304, ++0xac850c28, ++0xac400304, ++0x8c4400bc, ++0xae040004, ++0x8c631004, ++0x7c630440, ++0x14600002, ++0x3403f003, ++0xac4300bc, ++0x3c04b34f, ++0x8c820008, ++0x3c03ffff, ++0x246307ff, ++0xae020008, ++0x8f858038, ++0x00431024, ++0x3c030002, ++0x24630020, ++0x8f998048, ++0x00431025, ++0xac820008, ++0x24a50c34, ++0x0411ff97, ++0x00002025, ++0x8fbc0010, ++0x40026002, ++0x3c038000, ++0xae020018, ++0x00431025, ++0x40826002, ++0x8e220000, ++0x240300ff, ++0x9044000a, ++0x1083000d, ++0x8f99804c, ++0x04110179, ++0x90440009, ++0x8fbc0010, ++0xa202001c, ++0x8f828020, ++0x8f998050, ++0x8c420000, ++0x9045000a, ++0x04110159, ++0x90440009, ++0x10000003, ++0x8fbc0010, ++0x2402ffff, ++0xa202001c, ++0x8e220000, ++0x8c440018, ++0x2402ffff, ++0x10820004, ++0x8f998044, ++0x0411ff2c, ++0x00002825, ++0x8fbc0010, ++0x8e020014, ++0x34420400, ++0x40826000, ++0x8f998030, ++0x0411011e, ++0x24040065, ++0x8fbc0010, ++0x0000000f, ++0x00000000, ++0x42000020, ++0x00000000, ++0x00000000, ++0x02400008, ++0x00000000, ++0x8f998030, ++0x04110113, ++0x24040045, ++0x1000fffc, ++0x8fbc0010, ++0x3c1c0001, ++0x279c85a4, ++0x0399e021, ++0x8f998030, ++0x27bdffc0, ++0xafbc0010, ++0xafb30028, ++0xafb0001c, ++0xafbf003c, ++0xafb70038, ++0xafb60034, ++0xafb50030, ++0xafb4002c, ++0xafb20024, ++0xafb10020, ++0x04110100, ++0x2404004f, ++0x8fbc0010, ++0x8f938038, ++0x26700c28, ++0x8e020010, ++0x40828000, ++0x8e020014, ++0x40826000, ++0x8f918020, ++0x8e220000, ++0x8c43000c, ++0x2402ffff, ++0x1062000b, ++0x8f998038, ++0x273902a0, ++0x0411ff05, ++0x00000000, ++0x8fbc0010, ++0x8e220000, ++0x8e05000c, ++0x8f998044, ++0x0411fef1, ++0x8c44000c, ++0x8fbc0010, ++0x8e220000, ++0x90440009, ++0x240200ff, ++0x10820004, ++0x8f998050, ++0x0411010b, ++0x9205001c, ++0x8fbc0010, ++0x8f848038, ++0x8f998038, ++0x273902f0, ++0x0411ff05, ++0x24840c34, ++0x3c02b301, ++0x8c521004, ++0x3c020002, ++0x02429024, ++0x16400060, ++0x8fbc0010, ++0x3c03b000, ++0x8c6200d0, ++0x34420002, ++0xac6200d0, ++0x24020200, ++0x2442ffff, ++0x10400004, ++0x3c03b000, ++0x00000000, ++0x1000fffc, ++0x2442ffff, ++0x8c6200d0, ++0x2404fffd, ++0x00441024, ++0xac6200d0, ++0x24020200, ++0x2442ffff, ++0x10400004, ++0x3c03b301, ++0x00000000, ++0x1000fffc, ++0x2442ffff, ++0x8c62102c, ++0x2404ffef, ++0x00441024, ++0xac62102c, ++0x24020010, ++0x2442ffff, ++0x10400004, ++0x3c03b000, ++0x00000000, ++0x1000fffc, ++0x2442ffff, ++0x8c6200d0, ++0x34420002, ++0xac6200d0, ++0x24020200, ++0x2442ffff, ++0x10400004, ++0x3c03b000, ++0x00000000, ++0x1000fffc, ++0x2442ffff, ++0x8c6200d0, ++0x2404fffd, ++0x00441024, ++0xac6200d0, ++0x24020200, ++0x2442ffff, ++0x10400004, ++0x24030017, ++0x00000000, ++0x1000fffc, ++0x2442ffff, ++0x3c02b301, ++0x3c14b301, ++0xac431004, ++0x2415000b, ++0x26971180, ++0x8e82100c, ++0x3042000b, ++0x10550079, ++0x2696100c, ++0x8e82100c, ++0x30420060, ++0x10400006, ++0x8f998054, ++0x8f998030, ++0x04110090, ++0x24040065, ++0x10000070, ++0x8fbc0010, ++0x8ee40000, ++0x0411009a, ++0x00000000, ++0x8fbc0010, ++0x8ec4017c, ++0x8f998054, ++0x04110095, ++0x00000000, ++0x8fbc0010, ++0x8e84100c, ++0x8f998054, ++0x04110090, ++0x00000000, ++0x8fbc0010, ++0x8f998030, ++0x0411007d, ++0x2404000d, ++0x8fbc0010, ++0x8f998030, ++0x04110079, ++0x2404000a, ++0x1000ffdd, ++0x8fbc0010, ++0x3c05b34f, ++0x8ca40008, ++0x3c03fffd, ++0x3463ffdf, ++0x00831824, ++0x34630002, ++0xaca30008, ++0x24420081, ++0x3c03b301, ++0xac621004, ++0x3c14b301, ++0x2415001b, ++0x8e82100c, ++0x3042001b, ++0x10550017, ++0x00000000, ++0x8e82100c, ++0x30420060, ++0x10400006, ++0x8f998054, ++0x8f998030, ++0x04110060, ++0x24040065, ++0x1000000e, ++0x8fbc0010, ++0x8e84100c, ++0x0411006a, ++0x00000000, ++0x8fbc0010, ++0x8f998030, ++0x04110057, ++0x2404000d, ++0x8fbc0010, ++0x8f998030, ++0x04110053, ++0x2404000a, ++0x1000ffe7, ++0x8fbc0010, ++0x12400006, ++0x3c03b301, ++0x8e020004, ++0x1040000d, ++0x8e620c28, ++0x10000010, ++0x00000000, ++0x8c62102c, ++0x34420010, ++0xac62102c, ++0x24020010, ++0x2442ffff, ++0x1040fff5, ++0x00000000, ++0x00000000, ++0x1000fffc, ++0x2442ffff, ++0x16400004, ++0x00000000, ++0x3c02b34f, ++0xac4000bc, ++0x8e620c28, ++0x10400003, ++0x24030001, ++0x3c02b34f, ++0xac430304, ++0x8e030008, ++0x8f998038, ++0x3c02b34f, ++0xac430008, ++0x273902a0, ++0x0411fe45, ++0x00000000, ++0x8fbc0010, ++0x8e020018, ++0x40826002, ++0x8e220000, ++0x8c440010, ++0x3c020fff, ++0x3442ffff, ++0x10820004, ++0x8f998044, ++0x0411fe2c, ++0x00002825, ++0x8fbc0010, ++0x8f998030, ++0x04110021, ++0x24040073, ++0x1000fffc, ++0x8fbc0010, ++0x3c04b34f, ++0x8c830008, ++0x3c02fffd, ++0x3442ffdf, ++0x00621024, ++0x34420002, ++0xac820008, ++0x1000ffa8, ++0x24020081, ++0x00000000, ++0x00000000, ++0x00000000, ++0x2484ffac, ++0x1c80fffd, ++0x00000000, ++0x03e00008, ++0x00000000, ++0x3c1c0001, ++0x279c8198, ++0x0399e021, ++0x240300ff, ++0x10830006, ++0x8f828038, ++0x3c03b003, ++0x00042300, ++0x00832021, ++0x03e00008, ++0xac440c50, ++0x03e00008, ++0xac400c50, ++0x3c1c0001, ++0x279c8164, ++0x0399e021, ++0x8f828038, ++0x8c430c50, ++0x10600007, ++0x7c042420, ++0xac640000, ++0x24040060, ++0x8c620014, ++0x30420060, ++0x1444fffd, ++0x00000000, ++0x03e00008, ++0x00000000, ++0x3c1c0001, ++0x279c8128, ++0x0399e021, ++0x8f998030, ++0x27bdffe0, ++0x00803825, ++0x2405001c, ++0xafbc0010, ++0xafbf001c, ++0x2406fffc, ++0x00a71006, ++0x3042000f, ++0x2c44000a, ++0x24430030, ++0x24420037, ++0x0044180a, ++0x0411ffe0, ++0x00602025, ++0x24a5fffc, ++0x14a6fff7, ++0x00a71006, ++0x8fbf001c, ++0x03e00008, ++0x27bd0020, ++0x00000000, ++0x00000000, ++0x3088001f, ++0x24030001, ++0x00042143, ++0x3c02b001, ++0x00042200, ++0x01031804, ++0x24420010, ++0x00031827, ++0x00822021, ++0x24060003, ++0x2409ffff, ++0x8c820000, ++0x24840010, ++0x00433824, ++0x00c51007, ++0x30420001, ++0x01021004, ++0x00471025, ++0x24c6ffff, ++0xac82fff0, ++0x14c9fff6, ++0x00000000, ++0x03e00008, ++0x00000000, ++0x3087001f, ++0x3c02b001, ++0x00042143, ++0x24420010, ++0x00042200, ++0x00822021, ++0x24050003, ++0x00001025, ++0x2406ffff, ++0x8c830000, ++0x24840010, ++0x00e31806, ++0x30630001, ++0x00a31804, ++0x24a5ffff, ++0x14a6fff9, ++0x00621025, ++0x03e00008, ++0x00000000, ++0x00000000, ++0x02200000, ++0x01000101, ++0x00000000, ++0x00000000, ++0x00000001, ++0x00000000, ++0x00000000, ++0xffffffff, ++0x00000000, ++0x80000000, ++0x00000c1c, ++0x00000c24, ++0x00000c20, ++0x00000218, ++0x00000430, ++0x0000060c, ++0x00000a4c, ++0x00000354, ++0x00000000, ++0x00000a18, ++0x00000240, ++0x00000268, ++0x00000394, ++0x00000b50, ++0x00000af0, ++0x00000a88, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000018, ++0x00000003, ++0x0000001c, ++0x00000003, ++0x00000020, ++0x00000003, ++0x00000024, ++0x00000003, ++0x00000028, ++0x00000003, ++0x0000002c, ++0x00000003, ++0xffffffff, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00010003, ++0x000000ad, ++0x00000c1c, ++0x00000000, ++0x00050010, ++0x00000001, ++0x00000001, ++0x00000000, ++0xfff10013, ++0x00000081, ++0x00000017, ++0x00000000, ++0xfff10010, ++0x0000003e, ++0x00000c20, ++0x00000004, ++0x00070211, ++0x00000059, ++0x00000240, ++0x00000028, ++0x00010012, ++0x0000004a, ++0x00000218, ++0x00000028, ++0x00010012, ++0x0000007d, ++0x00008bb0, ++0x00000000, ++0xfff10010, ++0x00000091, ++0x00000c1c, ++0x00000000, ++0x00050010, ++0x00000028, ++0x00000c1c, ++0x00000000, ++0x00070010, ++0x00000075, ++0x00000000, ++0x00000000, ++0x00010010, ++0x00000012, ++0x00000bb8, ++0x00000000, ++0x00030011, ++0x000000a2, ++0x00000c1c, ++0x00000000, ++0x00050010, ++0x00000032, ++0x00000c24, ++0x00000004, ++0x00070211, ++0x0000001c, ++0x00000c1c, ++0x00000000, ++0x00070010, ++0x00000067, ++0x00000268, ++0x00000038, ++0x00010012, ++0x000000c6, ++0x00000c58, ++0x00000000, ++0x00060010, ++0x000000bd, ++0x00000c54, ++0x00000000, ++0x00050010, ++0x59445f00, ++0x494d414e, ++0x494c5f43, ++0x4e494b4e, ++0x5f5f0047, ++0x5f444c52, ++0x0050414d, ++0x73625f5f, ++0x74735f73, ++0x00747261, ++0x73625f5f, ++0x6e655f73, ++0x78650064, ++0x6e726574, ++0x6e75665f, ++0x5f700063, ++0x5f706c73, ++0x61726170, ++0x6c73006d, ++0x5f706565, ++0x655f6d70, ++0x7265746e, ++0x656c7300, ++0x705f7065, ++0x78655f6d, ++0x63007469, ++0x5f6c6c61, ++0x636e7566, ++0x6e6f6974, ++0x735f5f00, ++0x74726174, ++0x70675f00, ++0x6d756e00, ++0x746f675f, ++0x746e655f, ++0x73656972, ++0x695f5f00, ++0x6567616d, ++0x706f635f, ++0x6e655f79, ++0x5f5f0064, ++0x74696e69, ++0x646e655f, ++0x725f5f00, ++0x645f6c65, ++0x735f6e79, ++0x74726174, ++0x725f5f00, ++0x645f6c65, ++0x655f6e79, ++0xff00646e, ++0x00000004, ++0x00000f70, ++0x00000005, ++0x00000d88, ++0x00000006, ++0x00000c58, ++0x0000000a, ++0x000000cb, ++0x0000000b, ++0x00000010, ++0x70000035, ++0xfffffd3c, ++0x00000015, ++0x00000000, ++0x00000016, ++0x00000000, ++0x00000003, ++0x00000bc0, ++0x00000011, ++0x00000c1c, ++0x00000012, ++0x00000038, ++0x00000013, ++0x00000008, ++0x70000001, ++0x00000001, ++0x70000005, ++0x00000002, ++0x70000006, ++0x00000000, ++0x7000000a, ++0x00000017, ++0x70000011, ++0x00000013, ++0x70000012, ++0x0000000f, ++0x70000013, ++0x00000013, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x7273752f, ++0x62696c2f, ++0x62696c2f, ++0x6f732e63, ++0xff00312e, ++0x00000f41, ++0x756e6700, ++0x00070100, ++0x01040000, ++0x00000f41, ++0x756e6700, ++0x00070100, ++0x01040000, ++0x00000f41, ++0x756e6700, ++0x00070100, ++0x01040000, ++0x00000f41, ++0x756e6700, ++0x00070100, ++0x01040000, ++0x00000011, ++0x00000013, ++0x00000000, ++0x0000000d, ++0x00000009, ++0x00000010, ++0x00000007, ++0x00000004, ++0x0000000a, ++0x0000000e, ++0x00000002, ++0x00000000, ++0x00000000, ++0x0000000f, ++0x00000000, ++0x00000011, ++0x00000012, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000003, ++0x00000000, ++0x00000000, ++0x00000006, ++0x00000005, ++0x00000008, ++0x00000000, ++0x00000000, ++0x0000000b, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x0000000c, ++0x00000000, diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_early_printk.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_early_printk.c.patch new file mode 100644 index 00000000..bd50fe66 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_early_printk.c.patch @@ -0,0 +1,102 @@ +diff -drupN a/arch/mips/xburst/soc-x1800/early_printk.c b/arch/mips/xburst/soc-x1800/early_printk.c +--- a/arch/mips/xburst/soc-x1800/early_printk.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/soc-x1800/early_printk.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,98 @@ ++/* ++ * INGENIC SOC serial routines for early_printk. ++ * ++ * Copyright (C) 2006 Ingenic Semiconductor Inc. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++#define UART_OFF (0x1000) ++ ++static void check_uart(char c); ++ ++static volatile u32 *uart_base; ++typedef void (*putchar_f_t)(char); ++ ++static putchar_f_t putchar_f = check_uart; ++ ++static void putchar(char ch) ++{ ++ int timeout = 10000; ++ volatile u32 *base = uart_base; ++ ++ /* Wait for fifo to shift out some bytes */ ++ while ((base[UART_LSR] & (UART_LSR_THRE | UART_LSR_TEMT)) ++ != (UART_LSR_THRE | UART_LSR_TEMT) && timeout--) ++ ; ++ base[UART_TX] = (u8)ch; ++} ++ ++static void putchar_dummy(char ch) ++{ ++ return; ++} ++ ++static void check_uart(char c) ++{ ++ /* We Couldn't use ioremap() here */ ++ volatile u32 *base = (volatile u32*)CKSEG1ADDR(UART0_IOBASE); ++ int i; ++ for(i=0; i < 3; i++) { ++ if(base[UART_LCR]) ++ break; ++ base += (UART_OFF/sizeof(u32)); ++ } ++ ++ if(i < 3) { ++ uart_base = base; ++ putchar_f = putchar; ++ putchar_f(c); ++ } else { ++ putchar_f = putchar_dummy; ++ } ++} ++ ++/* used by early printk */ ++void prom_putchar(char c) ++{ ++ putchar_f(c); ++} ++ ++static int __init early_parse_console(char *p) ++{ ++ unsigned char *param = "null"; ++ ++ if(strstr(p, param)){ ++ putchar_f = putchar_dummy; ++ } ++ return 0; ++} ++early_param("console", early_parse_console); ++ ++#if 0 ++void prom_putstr(char *s) ++{ ++ while(*s) { ++ if(*s == '\n') ++ putchar_f('\r'); ++ putchar_f(*s); ++ s++; ++ } ++} ++ ++static char pbuffer[4096]; ++void prom_printk(const char *fmt, ...) { ++ va_list args; ++ ++ va_start(args, fmt); ++ vsnprintf(pbuffer, 4096, fmt, args); ++ va_end(args); ++ ++ prom_putstr(pbuffer); ++} ++#endif ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_cpu-feature-overrides.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_cpu-feature-overrides.h.patch new file mode 100644 index 00000000..aa56e592 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_cpu-feature-overrides.h.patch @@ -0,0 +1,65 @@ +diff -drupN a/arch/mips/xburst/soc-x1800/include/cpu-feature-overrides.h b/arch/mips/xburst/soc-x1800/include/cpu-feature-overrides.h +--- a/arch/mips/xburst/soc-x1800/include/cpu-feature-overrides.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/soc-x1800/include/cpu-feature-overrides.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,61 @@ ++/* ++ * Copyright (C) 2008 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * 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. ++ */ ++ ++#ifndef __ASM_MACH_INGENIC_CPU_FEATURE_OVERRIDES_H__ ++#define __ASM_MACH_INGENIC_CPU_FEATURE_OVERRIDES_H__ ++ ++#define cpu_dcache_size() (32 * 1024) ++#define cpu_dcache_ways() 8 ++#define cpu_dcache_line_size() 32 ++#define cpu_icache_size() (32 * 1024) ++#define cpu_icache_ways() 8 ++#define cpu_icache_line_size() 32 ++#define cpu_has_tlb 1 ++#define cpu_has_4kex 1 ++#define cpu_has_3k_cache 0 ++#define cpu_has_4k_cache 1 ++#define cpu_has_tx39_cache 0 ++#define cpu_has_fpu 1 ++#define cpu_has_32fpr 1 ++#define cpu_has_counter 0 ++#define cpu_has_watch 1 ++#define cpu_has_divec 1 ++#define cpu_has_vce 0 ++#define cpu_has_cache_cdex_p 0 ++#define cpu_has_cache_cdex_s 0 ++#define cpu_has_prefetch 1 ++#define cpu_has_mcheck 1 ++#define cpu_has_ejtag 1 ++#define cpu_has_llsc 1 ++#define cpu_has_mips16 0 ++#define cpu_has_mdmx 0 ++#define cpu_has_mips3d 0 ++#define cpu_has_smartmips 0 ++#define cpu_has_vtag_icache 0 ++#define cpu_has_dc_aliases 0 ++#define cpu_has_ic_fills_f_dc 0 ++#define cpu_has_pindexed_dcache 0 ++#define cpu_icache_snoops_remote_store 0 ++#define cpu_has_mips32r1 1 ++#define cpu_has_mips32r2 0 ++#define cpu_has_mips64r1 0 ++#define cpu_has_mips64r2 0 ++#define cpu_has_dsp 0 ++#define cpu_has_mipsmt 0 ++#define cpu_has_userlocal 0 ++#define cpu_has_nofpuex 0 ++#define cpu_has_64bits 0 ++#define cpu_has_64bit_zero_reg 0 ++#define cpu_has_vint 0 ++#define cpu_has_veic 0 ++#define cpu_has_inclusive_pcaches 0 ++#define kernel_uses_smartmips_rixi 1 ++#define cpu_has_mxu 0 ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_irq.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_irq.h.patch new file mode 100644 index 00000000..f2b711ba --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_irq.h.patch @@ -0,0 +1,34 @@ +diff -drupN a/arch/mips/xburst/soc-x1800/include/irq.h b/arch/mips/xburst/soc-x1800/include/irq.h +--- a/arch/mips/xburst/soc-x1800/include/irq.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/soc-x1800/include/irq.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,30 @@ ++/* ++ * Copyright (C) 2010 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * 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. ++ */ ++ ++#ifndef __ASM_MACH_INGENIC_IRQ_H__ ++#define __ASM_MACH_INGENIC_IRQ_H__ ++ ++#define MIPS_CPU_IRQ_BASE 0 ++#define MIPS_CPU_IRQ(x) (MIPS_CPU_IRQ_BASE + (x)) ++ ++#define XBURST_INT MIPS_CPU_IRQ(2) ++#define XBURST_SYS_OST MIPS_CPU_IRQ(3) ++ ++#define MIPS_CPU_IRQS (MIPS_CPU_IRQ(7) + 1 - MIPS_CPU_IRQ_BASE) ++#define XBURST_SOC_IRQ_BASE MIPS_CPU_IRQS ++ ++#define INTC_CHIP_NUM 2 ++ ++#ifndef NR_IRQS ++#define NR_IRQS 200 ++#endif ++ ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_soc_ahbm.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_soc_ahbm.h.patch new file mode 100644 index 00000000..ea703daf --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_soc_ahbm.h.patch @@ -0,0 +1,37 @@ +diff -drupN a/arch/mips/xburst/soc-x1800/include/soc/ahbm.h b/arch/mips/xburst/soc-x1800/include/soc/ahbm.h +--- a/arch/mips/xburst/soc-x1800/include/soc/ahbm.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/soc-x1800/include/soc/ahbm.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,33 @@ ++ ++#ifndef __INCLUDE_AHBM_ ++#define __INCLUDE_AHBM_ ++ ++#define DDR_MC 0x130100E4 ++#define DDR_RESULT_1 0x130100D4 ++#define DDR_RESULT_2 0x130100D8 ++#define DDR_RESULT_3 0x130100DC ++#define DDR_RESULT_4 0x130100E0 ++ ++#define AHBM_CIM_IOB 0x130f0000 ++#define AHBM_AHB0_IOB 0x130f0100 ++#define AHBM_GPU_IOB 0x130f0200 ++#define AHBM_LCD_IOB 0x130f0300 ++#define AHBM_XXX_IOB 0x13230000 ++#define AHBM_AHB2_IOB 0x134c0000 ++ ++#define ahbm_restart(M) \ ++do{ \ ++ outl(0x1,AHBM_##M##_IOB); \ ++ outl(0x0,AHBM_##M##_IOB); \ ++}while(0) ++ ++#define ahbm_stop(M) \ ++do{ \ ++ outl(inl(AHBM_##M##_IOB) | 0x2,AHBM_##M##_IOB); \ ++}while(0) ++ ++#define ahbm_read(M,off) inl((AHBM_##M##_IOB)+(off)) ++ ++#endif ++ ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_soc_base.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_soc_base.h.patch new file mode 100644 index 00000000..613e2bbc --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_soc_base.h.patch @@ -0,0 +1,91 @@ +diff -drupN a/arch/mips/xburst/soc-x1800/include/soc/base.h b/arch/mips/xburst/soc-x1800/include/soc/base.h +--- a/arch/mips/xburst/soc-x1800/include/soc/base.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/soc-x1800/include/soc/base.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,87 @@ ++ ++#ifndef __JZSOC_SOC_DEV_H__ ++#define __JZSOC_SOC_DEV_H__ ++ ++/* ++ * Define the module base addresses ++ */ ++ ++/* AHB0 BUS Devices Base */ ++#define HARB0_IOBASE 0x13000000 ++#define DDRC1_IOBASE 0x13010000 ++#define DDRC_IOBASE 0x13020000 ++#define X2D_IOBASE 0x13030000 ++#define GPU_IOBASE 0x13040000 ++#define CIM_IOBASE 0x13060000 ++#define COMPRESS_IOBASE 0x13070000 ++#define IPU_IOBASE 0x13080000 ++#define GPVLC_IOBASE 0x13090000 ++#define IPU1_IOBASE 0x130b0000 ++#define MONITOR_IOBASE 0x130f0000 ++#define EPDC_IOBASE 0x130c0000 ++#define EPDCE_IOBASE 0x130d0000 ++#define MIPI_CSI_IOBASE 0x10040000 ++#define DSI_IOBASE 0x13014000 ++#define ISP_VIC_IOBASE 0x13300000 ++#define ISP_IRQ_IOBASE 0x13320000 ++#define ISP_CORE_IOBASE 0x13380000 ++ ++/* AHB1 BUS Devices Base */ ++#define SCH_IOBASE 0x13200000 ++#define VDMA_IOBASE 0x13210000 ++#define EFE_IOBASE 0x13240000 ++#define MCE_IOBASE 0x13250000 ++#define DBLK_IOBASE 0x13270000 ++#define VMAU_IOBASE 0x13280000 ++#define SDE_IOBASE 0x13290000 ++#define AUX_IOBASE 0x132a0000 ++#define TCSM_IOBASE 0x132c0000 ++#define JPGC_IOBASE 0x132e0000 ++#define SRAM_IOBASE 0x132f0000 ++#define VPU_IOBASE(ID) (SCH_IOBASE + 0x400000 * ID) ++ ++/* AHB2 BUS Devices Base */ ++#define HARB2_IOBASE 0x13400000 ++#define NFI_IOBASE 0x13410000 ++#define EFUSE_IOBASE 0x13540000 ++#define PDMA_IOBASE 0x13420000 ++#define DES_IOBASE 0x10061000 ++#define AES_IOBASE 0x13430000 ++#define SFC_IOBASE 0x13440000 ++#define MSC0_IOBASE 0x13450000 ++#define MSC1_IOBASE 0x13460000 ++/*#define ETHC_IOBASE 0x134b0000*/ ++#define TSSI0_IOBASE 0x134e0000 ++#define TSSI1_IOBASE 0x134f0000 ++#define OTG_IOBASE 0x13500000 ++ ++#define OST_IOBASE 0x12000000 ++#define HDMI_IOBASE 0x10180000 ++ ++/* APB BUS Devices Base */ ++#define CPM_IOBASE 0x10000000 ++#define INTC_IOBASE 0x10001000 ++#define TCU_IOBASE 0x10002000 ++#define RTC_IOBASE 0x10003000 ++#define GPIO_IOBASE 0x10010000 ++#define DMIC_IOBASE 0x10022000 ++#define CODEC_IOBASE 0x10021000 ++#define AIC0_IOBASE 0x10020000 ++#define UART0_IOBASE 0x10030000 ++#define UART1_IOBASE 0x10031000 ++#define SSI0_IOBASE 0x10043000 ++#define I2C0_IOBASE 0x10050000 ++#define I2C1_IOBASE 0x10051000 ++#define SADC_IOBASE 0x10070000 ++#define WDT_IOBASE 0x10002000 ++ ++/* NAND CHIP Base Address*/ ++#define NEMC_CS1_IOBASE 0X1b000000 ++#define NEMC_CS2_IOBASE 0X1a000000 ++#define NEMC_CS3_IOBASE 0X19000000 ++#define NEMC_CS4_IOBASE 0X18000000 ++#define NEMC_CS5_IOBASE 0X17000000 ++#define NEMC_CS6_IOBASE 0X16000000 ++#define DDRC_BASE 0xb34f0000 ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_soc_cache.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_soc_cache.h.patch new file mode 100644 index 00000000..3f351912 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_soc_cache.h.patch @@ -0,0 +1,99 @@ +diff -drupN a/arch/mips/xburst/soc-x1800/include/soc/cache.h b/arch/mips/xburst/soc-x1800/include/soc/cache.h +--- a/arch/mips/xburst/soc-x1800/include/soc/cache.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/soc-x1800/include/soc/cache.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,95 @@ ++#ifndef __CHIP_CACHE_H__ ++#define __CHIP_CACHE_H__ ++#include ++#define cache_prefetch(label,size) \ ++do{ \ ++ unsigned long addr,end; \ ++ /* Prefetch codes from label */ \ ++ addr = (unsigned long)(&&label) & ~(32 - 1); \ ++ end = (unsigned long)(&&label + size) & ~(32 - 1); \ ++ end += 32; \ ++ for (; addr < end; addr += 32) { \ ++ __asm__ volatile ( \ ++ ".set mips32\n\t" \ ++ " cache %0, 0(%1)\n\t" \ ++ ".set mips32\n\t" \ ++ : \ ++ : "I" (Index_Prefetch_I), "r"(addr)); \ ++ } \ ++} \ ++while(0) ++ ++#define K0BASE KSEG0 ++#define CFG_DCACHE_SIZE 32768 ++#define CFG_ICACHE_SIZE 32768 ++#define CFG_CACHELINE_SIZE 32 ++ ++static inline void __jz_flush_cache_all(void) ++{ ++ register unsigned long addr; ++ /* Clear CP0 TagLo */ ++ asm volatile ("mtc0 $0, $28\n\t"); ++ for (addr = K0BASE; addr < (K0BASE + CFG_DCACHE_SIZE); addr += CFG_CACHELINE_SIZE) { ++ asm volatile (".set mips32\n\t" ++ " cache %0, 0(%1)\n\t" ++ ".set mips32\n\t" ++ : ++ : "I" (Index_Writeback_Inv_D), "r"(addr)); ++ } ++ ++ for (addr = K0BASE; addr < (K0BASE + CFG_ICACHE_SIZE); addr += CFG_CACHELINE_SIZE) { ++ asm volatile (".set mips32\n\t" ++ " cache %0, 0(%1)\n\t" ++ ".set mips32\n\t" ++ : ++ : "I" (Index_Store_Tag_I), "r"(addr)); ++ } ++ /* invalidate BTB */ ++ asm volatile ( ++ ".set mips32\n\t" ++ " mfc0 $26, $16, 7\n\t" ++ " nop\n\t" ++ " ori $26, 2\n\t" ++ " mtc0 $26, $16, 7\n\t" ++ " nop\n\t" ++ ".set mips32\n\t" ++ ); ++ asm volatile ("sync\n\t" ++ "lw $0,0(%0)" ++ ::"r" (0xa0000000)); ++ ++} ++ ++static inline void __jz_cache_init(void) ++{ ++ register unsigned long addr; ++ asm volatile ("mtc0 $0, $28\n\t"::); ++ ++ for (addr = K0BASE; addr < (K0BASE + CFG_DCACHE_SIZE); addr += CFG_CACHELINE_SIZE) { ++ asm volatile (".set mips32\n\t" ++ " cache %0, 0(%1)\n\t" ++ ".set mips32\n\t" ++ : ++ : "I" (Index_Store_Tag_D), "r"(addr)); ++ } ++ for (addr = K0BASE; addr < (K0BASE + CFG_ICACHE_SIZE); addr += CFG_CACHELINE_SIZE) { ++ asm volatile (".set mips32\n\t" ++ " cache %0, 0(%1)\n\t" ++ ".set mips32\n\t" ++ : ++ : "I" (Index_Store_Tag_I), "r"(addr)); ++ } ++ /* invalidate BTB */ ++ asm volatile ( ".set mips32\n\t" ++ " mfc0 $26, $16, 7\n\t" ++ " nop\n\t" ++ " ori $26, 2\n\t" ++ " mtc0 $26, $16, 7\n\t" ++ " nop\n\t" ++ "nop\n\t" ++ ".set mips32\n\t" ++ ); ++} ++ ++ ++#endif /* __CHIP_CACHE_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_soc_cpm.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_soc_cpm.h.patch new file mode 100644 index 00000000..0f7c2bc2 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_soc_cpm.h.patch @@ -0,0 +1,86 @@ +diff -drupN a/arch/mips/xburst/soc-x1800/include/soc/cpm.h b/arch/mips/xburst/soc-x1800/include/soc/cpm.h +--- a/arch/mips/xburst/soc-x1800/include/soc/cpm.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/soc-x1800/include/soc/cpm.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,82 @@ ++/* ++ * SOC CPM register definition. ++ * ++ * CPM (Clock reset and Power control Management) ++ * ++ * Copyright (C) 2010 Ingenic Semiconductor Co., Ltd. ++ */ ++ ++#ifndef __SOC_CPM_H__ ++#define __SOC_CPM_H__ ++ ++#define CPM_CPCCR (0x00) ++#define CPM_CPCSR (0xd4) ++ ++#define CPM_DDRCDR (0x2c) ++#define CPM_I2SCDR (0x60) ++#define CPM_I2SCDR1 (0x70) ++#define CPM_LPCDR (0x64) ++#define CPM_MSC0CDR (0x68) ++#define CPM_MSC1CDR (0xa4) ++#define CPM_USBCDR (0x50) ++#define CPM_MACCDR (0x54) ++#define CPM_SFCCDR (0x74) ++#define CPM_CIMCDR (0x7c) ++#define CPM_PCMCDR (0x84) ++#define CPM_PCMCDR1 (0xe0) ++#define CPM_MPHYC (0xe8) ++#define CPM_ISPCDR (0x80) ++ ++#define CPM_INTR (0xb0) ++#define CPM_INTRE (0xb4) ++#define CPM_DRCG (0xd0) ++#define CPM_CPSPPR (0x38) ++#define CPM_CPPSR (0x34) ++ ++#define CPM_USBPCR (0x3c) ++#define CPM_USBRDT (0x40) ++#define CPM_USBVBFIL (0x44) ++#define CPM_USBPCR1 (0x48) ++ ++#define CPM_CPAPCR (0x10) ++#define CPM_CPMPCR (0x14) ++ ++#define CPM_LCR (0x04) ++#define CPM_PSWC0ST (0x90) ++#define CPM_PSWC1ST (0x94) ++#define CPM_PSWC2ST (0x98) ++#define CPM_PSWC3ST (0x9c) ++#define CPM_CLKGR (0x20) ++#define CPM_CLKGR1 (0x28) ++#define CPM_MESTSEL (0xec) ++#define CPM_SRBC (0xc4) ++#define CPM_ERNG (0xd8) ++#define CPM_RNG (0xdc) ++#define CPM_SLBC (0xc8) ++#define CPM_SLPC (0xcc) ++#define CPM_OPCR (0x24) ++#define CPM_RSR (0x08) ++ ++#define LCR_LPM_MASK (0x3) ++#define LCR_LPM_SLEEP (0x1) ++ ++#ifndef BIT ++#define BIT(nr) (1UL << nr) ++#endif ++ ++/*Oscillator and Power Control Register*/ ++#define OPCR_IDLE BIT(31) ++#define OPCR_USB_SPENDN BIT(7) ++#define OPCR_USB_SPENDN1 BIT(6) ++#define OPCR_PD BIT(3) ++#define OPCR_ERCS BIT(2) ++ ++/*Soft Reset and Bus Control Register*/ ++#define SRBC_OTG_SR BIT(12) ++ ++#define cpm_inl(off) inl(CPM_IOBASE + (off)) ++#define cpm_outl(val,off) outl(val,CPM_IOBASE + (off)) ++#define cpm_clear_bit(val,off) do{cpm_outl((cpm_inl(off) & ~(1<<(val))),off);}while(0) ++#define cpm_set_bit(val,off) do{cpm_outl((cpm_inl(off) | (1< ++ * GPEMC(NEMC) support functions ++ * ++ * 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. ++ * ++ * 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., ++ * 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef __SOC_GPEMC_H__ ++#define __SOC_GPEMC_H__ ++ ++typedef enum { ++ BANK_TYPE_SRAM = 0, ++ BANK_TYPE_NAND, ++ BANK_TYPE_TOGGLE, ++ ++ CNT_BANK_TYPES ++} bank_type_t; ++ ++typedef enum { ++ BUS_WIDTH_8 = 8 ++} bus_width_t; ++ ++typedef enum { ++ BURST_LENGTH_4 = 4, ++ BURST_LENGTH_8 = 8, ++ BURST_LENGTH_16 = 16, ++ BURST_LENGTH_32 = 32 ++} burst_length_t; ++ ++typedef enum { ++ SRAM_TYPE_NORMAL = 0, ++ SRAM_TYPE_BURST, ++ ++ CNT_SRAM_TYPES ++} sram_type_t; ++ ++typedef struct { ++ u64 clk_T_real_ps; ++ bus_width_t BW; ++ ++ struct { ++ ++ /* ++ * got from datasheet of SoC-jz4780, ++ * there are obvious errors on timing diagram ++ * ++ * CS/ADDR/DATA(write) ++ * ______<------- Tah+Tas+Taw<+2> ------> ________ ++ * |_____________________________________| ++ * + + ++ * | + + | ++ * |<--Tas-->| | | ++ * + | |<--- Tah --->| ++ * WE/RD |<--- Taw --->| + ++ * ________________+ +______________________ ++ * |_____________| ++ * DATA(read) ++ * _________________________ ___________________ ++ * |_______| ++ * ++ */ ++ ++ /* every timing parameter count in nanoseconds */ ++ u32 Tstrv; ++ u32 Taw; ++ u32 Tbp; ++ u32 Tah; ++ u32 Tas; ++ ++ /* access attributes */ ++ burst_length_t BL; ++ sram_type_t sram_type; ++ } sram_timing; ++ ++ /* ++ * TODO ++ */ ++ struct { ++ u32 Trv; ++ u32 Trw; ++ u32 Tww; ++ u32 Tah; ++ u32 Tas; ++ u32 Tdpht; ++ u32 Tdqsre; ++ u32 Tfda; ++ u32 Tclr; ++ u32 Tdphtd; ++ u32 Tcdqss; ++ u32 Tcwaw; ++ } toggle_timing; ++} gpemc_bank_timing_t; ++ ++typedef struct { ++ /* ++ * CLE Setup Time ++ */ ++ u32 Tcls; ++ ++ /* ++ * CLE Hold Time ++ */ ++ u32 Tclh; ++ ++ /* ++ * ALE Setup Time ++ */ ++ u32 Tals; ++ ++ /* ++ * ALE Hold Time ++ */ ++ u32 Talh; ++ ++ /* ++ * #CE Hold Time ++ */ ++ u32 Tch; ++ ++ /* ++ * Data Setup Time ++ */ ++ u32 Tds; ++ ++ /* ++ * Data Hold Time ++ */ ++ u32 Tdh; ++ ++ /* ++ * #WE Pulse Width ++ */ ++ u32 Twp; ++ ++ /* ++ * #WE High Hold Time ++ */ ++ u32 Twh; ++ ++ /* ++ * Write Cycle Time ++ */ ++ u32 Twc; ++ ++ /* ++ * Read Cycle Time ++ */ ++ u32 Trc; ++ ++ /* ++ * #RE High to #WE Low ++ */ ++ u32 Trhw; ++ ++ /* ++ * #RE Pulse Width ++ */ ++ u32 Trp; ++ ++ struct { ++ /* ++ * #CE Setup Time ++ */ ++ u32 Tcs; ++ ++ /* ++ * #WE High to #RE Low ++ */ ++ u32 Twhr; ++ ++ /* ++ * address to data loading delay for sequence in ++ */ ++ u32 Tadl; ++ ++ /* ++ * Change column setup time to data in/out or next command ++ * often used in Micron NAND chips ++ */ ++ u32 Tccs; ++ ++ /* ++ * Ready to #RE low ++ */ ++ u32 Trr; ++ ++ /* ++ * Command Write cycle to Address Write ++ * cycle Time for Random data input ++ */ ++ u32 Tcwaw; ++ ++ /* ++ * #WE high to Busy ++ */ ++ u32 Twb; ++ ++ /* ++ * #WP High/Low to #WE Low ++ */ ++ u32 Tww; ++ ++ /* ++ * Device Resetting Time(Read/Program/Erase) ++ */ ++ u32 Trst; ++ ++ /* ++ * Busy time for Set Feature and Get Feature ++ */ ++ u32 Tfeat; ++ ++ /* ++ * Cache Busy in Read Cache (following 31h and 3Fh) ++ */ ++ u32 Tdcbsyr; ++ ++ /* ++ * Dummy Busy Time for Intelligent Copy-Back Read ++ */ ++ u32 Tdcbsyr2; ++ ++ /* ++ * #WE High to #RE Low for Random data out ++ */ ++ u32 Twhr2; ++ } busy_wait_timing; ++ ++ bus_width_t BW; ++ ++ int32_t all_timings_plus; ++} common_nand_timing_t; ++ ++typedef struct { ++ /* ++ * TODO ++ */ ++} toggle_nand_timing_t; ++ ++typedef struct { ++ /* ++ * TODO ++ */ ++} sram_timing_t; ++ ++typedef struct { ++ int cs; ++ bank_type_t bank_type; ++ gpemc_bank_timing_t bank_timing; ++ ++ struct device* dev; ++ ++ unsigned int cnt_addr_pins; ++ void __iomem *io_base; ++ ++ void __iomem *io_nand_dat; ++ void __iomem *io_nand_addr; ++ void __iomem *io_nand_cmd; ++} gpemc_bank_t; ++ ++extern int gpemc_request_cs(struct device *dev, gpemc_bank_t *bank, int cs); ++extern void gpemc_release_cs(gpemc_bank_t *bank); ++ ++extern void gpemc_relax_bank_timing(gpemc_bank_t *bank); ++extern int gpemc_config_bank_timing(gpemc_bank_t *bank); ++extern int gpemc_config_toggle_bank_timing(gpemc_bank_t *bank); ++ ++extern void gpemc_set_bank_as_common_nand(gpemc_bank_t *bank); ++extern void gpemc_set_bank_as_toggle_nand(gpemc_bank_t *bank); ++ ++extern void gpemc_enable_nand_flash(gpemc_bank_t *bank, bool enable); ++ ++extern void gpemc_fill_timing_from_nand(gpemc_bank_t *bank, common_nand_timing_t *timing); ++extern void gpemc_fill_timing_from_toggle(gpemc_bank_t *bank, toggle_nand_timing_t *timing); ++extern void gpemc_fill_timing_from_sram(gpemc_bank_t *bank, sram_timing_t *timing); ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_soc_irq.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_soc_irq.h.patch new file mode 100644 index 00000000..c47487b4 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_soc_irq.h.patch @@ -0,0 +1,88 @@ +diff -drupN a/arch/mips/xburst/soc-x1800/include/soc/irq.h b/arch/mips/xburst/soc-x1800/include/soc/irq.h +--- a/arch/mips/xburst/soc-x1800/include/soc/irq.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/soc-x1800/include/soc/irq.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,84 @@ ++/* ++ * IRQ number in JZ47xx INTC definition. ++ * Only support 4770 now. 2011-9-23 ++ * ++ * Copyright (C) 2010 Ingenic Semiconductor Co., Ltd. ++ */ ++ ++#ifndef __INTC_IRQ_H__ ++#define __INTC_IRQ_H__ ++ ++#include ++ ++enum { ++// interrupt controller interrupts ++ IRQ_DMIC=XBURST_SOC_IRQ_BASE, ++ IRQ_AIC0, ++ IRQ_BCH, ++ IRQ_SYS_OST, ++ IRQ_CSI, ++ IRQ_OHCI, ++ IRQ_IPU, ++ IRQ_SFC, ++ IRQ_SSI1, ++ IRQ_SSI0, ++ IRQ_PDMA, ++ IRQ_RESERVED11, ++ IRQ_GPIO5, ++ IRQ_GPIO4, ++ IRQ_GPIO3, ++ IRQ_GPIO2, ++ IRQ_GPIO1, ++ IRQ_GPIO0, ++#define IRQ_GPIO_PORT(N) (IRQ_GPIO0 - (N)) ++ IRQ_SADC, ++ IRQ_VO, ++ IRQ_EHCI, ++ IRQ_OTG, ++ IRQ_RESERVED22, ++ IRQ_AES, ++ IRQ_DES, ++ IRQ_TCU2, ++ IRQ_TCU1, ++ IRQ_TCU0, ++ IRQ_RESERVED28, ++ IRQ_ISP, ++ IRQ_RESERVED30, ++ IRQ_LCD, ++ ++ IRQ_RTC, ++ IRQ_RESERVED33, ++ IRQ_RESERVED34, ++ IRQ_MSC2, ++ IRQ_MSC1, ++ IRQ_MSC0, ++ IRQ_RESERVED38, ++ IRQ_NFI, ++ IRQ_PCM0, ++ IRQ_RESERVED41, ++ IRQ_RESERVED42, ++ IRQ_RESERVED43, ++ IRQ_HARB2, ++ IRQ_HARB1, ++ IRQ_HARB0, ++ IRQ_CPM, ++ IRQ_UART3, ++ IRQ_UART2, ++ IRQ_UART1, ++ IRQ_UART0, ++ IRQ_DDR, ++ IRQ_RESERVED53, ++ IRQ_EFUSE, ++ IRQ_GMAC, ++ IRQ_I2C4, ++ IRQ_I2C3, ++ IRQ_I2C2, ++ IRQ_I2C1, ++ IRQ_I2C0, ++ IRQ_PDMAM, ++#define IRQ_VPU(ID) (IRQ_VPU0 + ID) ++ IRQ_VPU0, ++ IRQ_VPU1, ++}; ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_soc_ost.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_soc_ost.h.patch new file mode 100644 index 00000000..9a114d43 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_soc_ost.h.patch @@ -0,0 +1,45 @@ +diff -drupN a/arch/mips/xburst/soc-x1800/include/soc/ost.h b/arch/mips/xburst/soc-x1800/include/soc/ost.h +--- a/arch/mips/xburst/soc-x1800/include/soc/ost.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/soc-x1800/include/soc/ost.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,41 @@ ++/* ++ * JZ x1800 ost register definition. ++ * ++ * Copyright (C) 2010 Ingenic Semiconductor Co., Ltd. ++ */ ++ ++#ifndef __OST_H__ ++#define __OST_H__ ++ ++#define OST_TCCR (0x00) /* OS Timer Clock Control Register*/ ++#define OST_TER (0x04) /* OS Timer Counter Enable Register */ ++#define OST_TESR (0x34) /* OS Timer Counter Enable Set Register */ ++#define OST_TECR (0x38) /* OS Timer Counter Enable Clear Register */ ++#define OST_TCR (0x08) /* OS Timer clear Register */ ++#define OST_TFR (0x0C) /* OS Timer Flag Register */ ++#define OST_TMR (0x10) /* OS Timer Mask Register */ ++#define OST_T1DFR (0x14) /* OS Timer1 Data FULL Register */ ++#define OST_T1CNT (0x18) /* OS Timer1 Counter */ ++#define OST_T2CNTL (0x20) /* OS Timer2 Counter Lower 32 Bits */ ++#define OST_T2CNTH (0x1c) /* OS Timer2 Counter High 32 Bits */ ++#define OST_TCNT2HBUF (0x24) /* OS Timer2 Counter Higher 32 Bits Buffer */ ++ ++#define TCCRDIV_MSK1 (0x3) ++#define TCCRDIV_SFT2 (2) ++#define TCCRDIV_MSK2 (TCCRDIV_MSK1 << TCCRDIV_SFT2) ++#define TCCRDIV1(x) ({int n = 0; int d = (x); while(d) { d >>= 2; n++; }; (n-1);}) ++#define TCCRDIV2(x) (TCCRDIV1((x)) << TCCRDIV_SFT2) ++ ++#define TESR_OSTEN1 (1 << 0) /* enable the counter1 in ost */ ++#define TESR_OSTEN2 (1 << 1) /* enable the counter2 in ost */ ++ ++#define TCR_OSTCLR1 (1 << 0) ++#define TCR_OSTCLR2 (1 << 1) ++ ++#define TMR_OSTM (1 << 0) /* ost comparison match interrupt mask */ ++ ++#define TFR_OSTM (1 << 0) /* Comparison match */ ++ ++#define ost_readl(reg) readl_relaxed(reg) ++#define ost_writel(reg, val) writel_relaxed(val, reg) ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_soc_sfc.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_soc_sfc.h.patch new file mode 100644 index 00000000..6de986cc --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_soc_sfc.h.patch @@ -0,0 +1,156 @@ +diff -drupN a/arch/mips/xburst/soc-x1800/include/soc/sfc.h b/arch/mips/xburst/soc-x1800/include/soc/sfc.h +--- a/arch/mips/xburst/soc-x1800/include/soc/sfc.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/soc-x1800/include/soc/sfc.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,152 @@ ++#ifndef __SFC_REGISTER_H ++#define __SFC_REGISTER_H ++ ++/* SFC register */ ++ ++#define SFC_GLB (0x0000) ++#define SFC_DEV_CONF (0x0004) ++#define SFC_DEV_STA_EXP (0x0008) ++#define SFC_DEV_STA_RT (0x000c) ++#define SFC_DEV_STA_MSK (0x0010) ++#define SFC_TRAN_CONF(n) (0x0014 + (n * 4)) ++#define SFC_TRAN_LEN (0x002c) ++#define SFC_DEV_ADDR(n) (0x0030 + (n * 4)) ++#define SFC_DEV_ADDR_PLUS(n) (0x0048 + (n * 4)) ++#define SFC_MEM_ADDR (0x0060) ++#define SFC_TRIG (0x0064) ++#define SFC_SR (0x0068) ++#define SFC_SCR (0x006c) ++#define SFC_INTC (0x0070) ++#define SFC_FSM (0x0074) ++#define SFC_CGE (0x0078) ++#define SFC_RM_DR (0x1000) ++ ++/* For SFC_GLB */ ++#define GLB_TRAN_DIR (1 << 13) ++#define GLB_TRAN_DIR_WRITE (1) ++#define GLB_TRAN_DIR_READ (0) ++#define GLB_THRESHOLD_OFFSET (7) ++#define GLB_THRESHOLD_MSK (0x3f << GLB_THRESHOLD_OFFSET) ++#define GLB_OP_MODE (1 << 6) ++#define SLAVE_MODE (0x0) ++#define DMA_MODE (0x1) ++#define GLB_PHASE_NUM_OFFSET (3) ++#define GLB_PHASE_NUM_MSK (0x7 << GLB_PHASE_NUM_OFFSET) ++#define GLB_WP_EN (1 << 2) ++#define GLB_BURST_MD_OFFSET (0) ++#define GLB_BURST_MD_MSK (0x3 << GLB_BURST_MD_OFFSET) ++ ++/* For SFC_DEV_CONF */ ++#define DEV_CONF_ONE_AND_HALF_CYCLE_DELAY (3) ++#define DEV_CONF_ONE_CYCLE_DELAY (2) ++#define DEV_CONF_HALF_CYCLE_DELAY (1) ++#define DEV_CONF_NO_DELAY (0) ++#define DEV_CONF_SMP_DELAY_OFFSET (16) ++#define DEV_CONF_SMP_DELAY_MSK (0x3 << DEV_CONF_SMP_DELAY_OFFSET) ++#define DEV_CONF_CMD_TYPE (0x1 << 15) ++#define DEV_CONF_STA_TYPE_OFFSET (13) ++#define DEV_CONF_STA_TYPE_MSK (0x1 << DEV_CONF_STA_TYPE_OFFSET) ++#define DEV_CONF_THOLD_OFFSET (11) ++#define DEV_CONF_THOLD_MSK (0x3 << DEV_CONF_THOLD_OFFSET) ++#define DEV_CONF_TSETUP_OFFSET (9) ++#define DEV_CONF_TSETUP_MSK (0x3 << DEV_CONF_TSETUP_OFFSET) ++#define DEV_CONF_TSH_OFFSET (5) ++#define DEV_CONF_TSH_MSK (0xf << DEV_CONF_TSH_OFFSET) ++#define DEV_CONF_CPHA (0x1 << 4) ++#define DEV_CONF_CPOL (0x1 << 3) ++#define DEV_CONF_CEDL (0x1 << 2) ++#define DEV_CONF_HOLDDL (0x1 << 1) ++#define DEV_CONF_WPDL (0x1 << 0) ++ ++/* For SFC_TRAN_CONF */ ++#define TRAN_CONF_TRAN_MODE_OFFSET (29) ++#define TRAN_CONF_TRAN_MODE_MSK (0x7) ++#define TRAN_CONF_ADDR_WIDTH_OFFSET (26) ++#define TRAN_CONF_ADDR_WIDTH_MSK (0x7 << ADDR_WIDTH_OFFSET) ++#define TRAN_CONF_POLLEN (1 << 25) ++#define TRAN_CONF_POLL_OFFSET (25) ++#define TRAN_CONF_CMDEN (1 << 24) ++#define TRAN_CONF_FMAT (1 << 23) ++#define TRAN_CONF_FMAT_OFFSET (23) ++#define TRAN_CONF_DMYBITS_OFFSET (17) ++#define TRAN_CONF_DMYBITS_MSK (0x3f << DMYBITS_OFFSET) ++#define TRAN_CONF_DATEEN (1 << 16) ++#define TRAN_CONF_DATEEN_OFFSET (16) ++#define TRAN_CONF_CMD_OFFSET (0) ++#define TRAN_CONF_CMD_MSK (0xffff << CMD_OFFSET) ++#define TRAN_CONF_CMD_LEN (1 << 15) ++ ++/* For SFC_TRIG */ ++#define TRIG_FLUSH (1 << 2) ++#define TRIG_STOP (1 << 1) ++#define TRIG_START (1 << 0) ++ ++/* For SFC_SCR */ ++#define CLR_END (1 << 4) ++#define CLR_TREQ (1 << 3) ++#define CLR_RREQ (1 << 2) ++#define CLR_OVER (1 << 1) ++#define CLR_UNDER (1 << 0) ++ ++/* For SFC_TRAN_CONFx */ ++#define TRAN_MODE_OFFSET (29) ++#define TRAN_MODE_MSK (0x7 << TRAN_MODE_OFFSET) ++#define TRAN_SPI_STANDARD (0x0) ++#define TRAN_SPI_DUAL (0x1 ) ++#define TRAN_SPI_QUAD (0x5 ) ++#define TRAN_SPI_IO_QUAD (0x6 ) ++ ++ ++#define ADDR_WIDTH_OFFSET (26) ++#define ADDR_WIDTH_MSK (0x7 << ADDR_WIDTH_OFFSET) ++#define POLLEN (1 << 25) ++#define CMDEN (1 << 24) ++#define FMAT (1 << 23) ++#define DMYBITS_OFFSET (17) ++#define DMYBITS_MSK (0x3f << DMYBITS_OFFSET) ++#define DATEEN (1 << 16) ++#define CMD_OFFSET (0) ++#define CMD_MSK (0xffff << CMD_OFFSET) ++ ++#define N_MAX 6 ++#define MAX_SEGS 128 ++ ++#define CHANNEL_0 0 ++#define CHANNEL_1 1 ++#define CHANNEL_2 2 ++#define CHANNEL_3 3 ++#define CHANNEL_4 4 ++#define CHANNEL_5 5 ++ ++#define ENABLE 1 ++#define DISABLE 0 ++ ++#define COM_CMD 1 // common cmd ++#define POLL_CMD 2 // the cmd will poll the status of flash,ext: read status ++ ++#define DMA_OPS 1 ++#define CPU_OPS 0 ++ ++#define TM_STD_SPI 0 ++#define TM_DI_DO_SPI 1 ++#define TM_DIO_SPI 2 ++#define TM_FULL_DIO_SPI 3 ++#define TM_QI_QO_SPI 5 ++#define TM_QIO_SPI 6 ++#define TM_FULL_QIO_SPI 7 ++ ++ ++#define DEFAULT_ADDRSIZE 3 ++ ++ ++#define THRESHOLD 32 ++ ++#define SFC_NOR_RATE 110 ++#define DEF_ADDR_LEN 3 ++#define DEF_TCHSH 5 ++#define DEF_TSLCH 5 ++#define DEF_TSHSL_R 20 ++#define DEF_TSHSL_W 50 ++ ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_soc_tcsm_layout.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_soc_tcsm_layout.h.patch new file mode 100644 index 00000000..40da2aa5 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_soc_tcsm_layout.h.patch @@ -0,0 +1,57 @@ +diff -drupN a/arch/mips/xburst/soc-x1800/include/soc/tcsm_layout.h b/arch/mips/xburst/soc-x1800/include/soc/tcsm_layout.h +--- a/arch/mips/xburst/soc-x1800/include/soc/tcsm_layout.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/soc-x1800/include/soc/tcsm_layout.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,53 @@ ++#ifndef __TCSM_LAYOUT_H__ ++#define __TCSM_LAYOUT_H__ ++ ++/** ++ * |-------------| ++ * | BANK0 | ++ * |-------------| <--- SLEEP_TCSM_BOOTCODE_TEXT ++ * | | ++ * | | ++ * | | ++ * | | ++ * | | ++ * | | ++ * | | ++ * |-------------| ++ * | VO DMA DESC | ++ * |_____________| <--- VOICE_TCSM_DMA_DESC ++ * ++ * ++ * |-------------| ++ * | BANK1 | ++ * |-------------| <--- VOICE_TCSM_DATA_BUF ++ * | | ++ * | | ++ * | ... | ++ * | VOICE DATA | ++ * | ... | ++ * | | ++ * | | ++ * |_____________| ++ * ++ */ ++ ++/* ++ * If you use the VOICE TRIGGER, ++ * and you change the VOICE_* and TCSM_BANK_LEN, ++ * while compiling wakeup module ++ */ ++#define SLEEP_TCSM_SPACE 0xb3422000 ++#define VOICE_TCSM_DATA_BUF 0xb3423000 ++#define TCSM_BANK_LEN 4096 ++ ++#define SLEEP_TCSM_BOOT_TEXT (SLEEP_TCSM_SPACE) ++ ++#define VOICE_TCSM_DMA_DESC_LEN 512 ++#define SLEEP_TCSM_SPACE_END (SLEEP_TCSM_SPACE + TCSM_BANK_LEN - VOICE_TCSM_DMA_DESC_LEN) ++#define VOICE_TCSM_DMA_DESC_ADDR SLEEP_TCSM_SPACE_END ++ ++#define SLEEP_TCSM_CPU_RESMUE_SP SLEEP_TCSM_SPACE_END - 4 ++ ++#define VOICE_TCSM_DATA_BUF_SIZE TCSM_BANK_LEN ++ ++#endif /* __TCSM_LAYOUT_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_soc_tcu.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_soc_tcu.h.patch new file mode 100644 index 00000000..87bbecc8 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_soc_tcu.h.patch @@ -0,0 +1,88 @@ +diff -drupN a/arch/mips/xburst/soc-x1800/include/soc/tcu.h b/arch/mips/xburst/soc-x1800/include/soc/tcu.h +--- a/arch/mips/xburst/soc-x1800/include/soc/tcu.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/soc-x1800/include/soc/tcu.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,84 @@ ++/* ++ * JZ4770 tcu register definition. ++ * ++ * Copyright (C) 2010 Ingenic Semiconductor Co., Ltd. ++ */ ++ ++#ifndef __TCU_H__ ++#define __TCU_H__ ++ ++#define WDT_TDR (0x00) /* rw, 32, 0x???????? */ ++#define WDT_TCER (0x04) /* rw, 32, 0x???????? */ ++#define WDT_TCNT (0x08) /* rw, 32, 0x???????? */ ++#define WDT_TCSR (0x0c) /* rw, 32, 0x???????? */ ++ ++#define TCU_TSTR (0xF0) /* Timer Status Register,Only Used In Tcu2 Mode */ ++#define TCU_TSTSR (0xF4) /* Timer Status Set Register */ ++#define TCU_TSTCR (0xF8) /* Timer Status Clear Register */ ++#define TCU_TSR (0x1C) /* Timer Stop Register */ ++#define TCU_TSSR (0x2C) /* Timer Stop Set Register */ ++#define TCU_TSCR (0x3C) /* Timer Stop Clear Register */ ++#define TCU_TER (0x10) /* Timer Counter Enable Register */ ++#define TCU_TESR (0x14) /* Timer Counter Enable Set Register */ ++#define TCU_TECR (0x18) /* Timer Counter Enable Clear Register */ ++#define TCU_TFR (0x20) /* Timer Flag Register */ ++#define TCU_TFSR (0x24) /* Timer Flag Set Register */ ++#define TCU_TFCR (0x28) /* Timer Flag Clear Register */ ++#define TCU_TMR (0x30) /* Timer Mask Register */ ++#define TCU_TMSR (0x34) /* Timer Mask Set Register */ ++#define TCU_TMCR (0x38) /* Timer Mask Clear Register */ ++ ++#define CH_TDFR(n) (0x40 + (n)*0x10) /* Timer Data Full Reg */ ++#define CH_TDHR(n) (0x44 + (n)*0x10) /* Timer Data Half Reg */ ++#define CH_TCNT(n) (0x48 + (n)*0x10) /* Timer Counter Reg */ ++#define CH_TCSR(n) (0x4C + (n)*0x10) /* Timer Control Reg */ ++ ++#define TER_OSTEN (1 << 15) /* enable the counter in ost */ ++#define TMR_OSTM (1 << 15) /* ost comparison match interrupt mask */ ++#define TFR_OSTF (1 << 15) /* ost interrupt flag */ ++#define TSR_OSTS (1 << 15) /*the clock supplies to osts is stopped */ ++ ++#define TSR_WDTS (1 << 16) /*the clock supplies to wdt is stopped */ ++ ++#define CSR_EXT_EN (1 << 2) /* select extal as the timer clock input */ ++#define CSR_RTC_EN (1 << 1) /* select rtcclk as the timer clock input */ ++#define CSR_PCK_EN (1 << 0) /* select pclk as the timer clock input */ ++#define CSR_CLK_MSK (0x7) ++ ++#define CSR_DIV1 (0x0 << 3) ++#define CSR_DIV4 (0x1 << 3) ++#define CSR_DIV16 (0x2 << 3) ++#define CSR_DIV64 (0x3 << 3) ++#define CSR_DIV256 (0x4 << 3) ++#define CSR_DIV1024 (0x5 << 3) ++#define CSR_DIV_MSK (0x7 << 3) ++ ++// Register bits definitions ++#define TSTR_REAL2 (1 << 18) /* only used in TCU2 mode */ ++#define TSTR_REAL1 (1 << 17) /* only used in TCU2 mode */ ++#define TSTR_BUSY2 (1 << 2) /* only used in TCU2 mode */ ++#define TSTR_BUSY1 (1 << 1) /* only used in TCU2 mode */ ++ ++#define TCSR_PWM_BYPASS (1 << 11) /* clear counter to 0, only used in TCU2 mode */ ++#define TCSR_CNT_CLRZ (1 << 10) /* clear counter to 0, only used in TCU2 mode */ ++#define TCSR_PWM_SD (1 << 9) /* shut down the pwm output only used in TCU1 mode */ ++#define TCSR_PWM_HIGH (1 << 8) /* selects an initial output level for pwm output */ ++#define TCSR_PWM_EN (1 << 7) /* pwm pin output enable */ ++#define TCSR_PWM_IN (1 << 6) /* pwm pin output enable */ ++ ++ ++/* ++ * Operating system timer module(OST) address definition ++ */ ++ ++#define OST_DR (0xe0) ++#define OST_CNTL (0xe4) ++#define OST_CNTH (0xe8) ++#define OST_CSR (0xec) ++#define OST_CNTH_BUF (0xfc) ++ ++/* Operating system control register(OSTCSR) */ ++#define OSTCSR_CNT_MD (1 << 15) ++ ++#endif ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_war.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_war.h.patch new file mode 100644 index 00000000..9fdd4677 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_include_war.h.patch @@ -0,0 +1,31 @@ +diff -drupN a/arch/mips/xburst/soc-x1800/include/war.h b/arch/mips/xburst/soc-x1800/include/war.h +--- a/arch/mips/xburst/soc-x1800/include/war.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/soc-x1800/include/war.h 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,27 @@ ++/* ++ * 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) 2002, 2004, 2007 by Ralf Baechle ++ */ ++#ifndef __ASM_MACH_INGENIC_WAR_H__ ++#define __ASM_MACH_INGENIC_WAR_H__ ++ ++#define R4600_V1_INDEX_ICACHEOP_WAR 0 ++#define R4600_V1_HIT_CACHEOP_WAR 0 ++#define R4600_V2_HIT_CACHEOP_WAR 0 ++#define R5432_CP0_INTERRUPT_WAR 0 ++#define BCM1250_M3_WAR 0 ++#define SIBYTE_1956_WAR 0 ++#define MIPS4K_ICACHE_REFILL_WAR 0 ++#define MIPS_CACHE_SYNC_WAR 1 ++#define MIPS_BRIDGE_SYNC_WAR 1 ++#define TX49XX_ICACHE_INDEX_INV_WAR 0 ++#define RM9000_CDEX_SMP_WAR 0 ++#define ICACHE_REFILLS_WORKAROUND_WAR 0 ++#define R10000_LLSC_WAR 0 ++#define MIPS34K_MISSED_ITLB_WAR 0 ++ ++#endif ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_pm.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_pm.c.patch new file mode 100644 index 00000000..72c4a99e --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_pm.c.patch @@ -0,0 +1,221 @@ +diff -drupN a/arch/mips/xburst/soc-x1800/pm.c b/arch/mips/xburst/soc-x1800/pm.c +--- a/arch/mips/xburst/soc-x1800/pm.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/soc-x1800/pm.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,217 @@ ++/* ++ * linux/arch/mips/xburst/soc-m200/common/pm_p0.c ++ * ++ * M200 Power Management Routines ++ * Copyright (C) 2006 - 2012 Ingenic Semiconductor Inc. ++ * ++ * This program is free software; you can distribute 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 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++extern long long save_goto(unsigned int); ++extern int restore_goto(void); ++ ++unsigned int pm_firmware_new[] ={ ++#include "core_sleep.hex" ++}; ++ ++void load_pm_firmware_new(unsigned int addr) ++{ ++ void (*func)(unsigned int addr,unsigned int to); ++ unsigned int firmware_size = sizeof(pm_firmware_new); ++ ++ if(firmware_size > TCSM_BANK_LEN * 1024) ++ printk("WARN: firmware_size %d bigger than" \ ++ "TCSM_BANK_LEN %d\n", firmware_size, TCSM_BANK_LEN * 1024); ++ ++ func = (void (*)(unsigned int,unsigned int))addr; ++ memcpy((void *)addr,pm_firmware_new,firmware_size); ++ func(addr,0); ++} ++struct sleep_param ++{ ++ unsigned int pm_core_enter; ++ unsigned char pmu_i2c_scl; //default 0xff ++ unsigned char pmu_i2c_sda; //default 0xff ++ unsigned char pmu_addr; //default 0xff ++ unsigned char pmu_reg; //default 0xff ++ unsigned char pmu_register_val; ++ ++ unsigned char pmu_pin; //default 0xff ++ unsigned char pmu_pin_func; //default 0xff ++ unsigned char uart_id; //default 0xff ++ ++ unsigned int prev_resume_pc; //ddr is self-reflash default 0xffffffff ++ unsigned int post_resume_pc; //ddr is ok. default 0xffffffff ++ unsigned int prev_sleep_pc; //after flush cache. default 0xffffffff ++ unsigned int post_sleep_pc; //before wait. default 0xffffffff ++ ++}; ++struct sleep_save_register ++{ ++ unsigned int lcr; ++ unsigned int opcr; ++ unsigned int clkgr; ++ unsigned int sleep_voice_enable; ++ unsigned int ddr_training_space[20]; ++ suspend_state_t pm_state; ++}; ++ ++static struct sleep_save_register s_reg; ++struct sleep_param *sleep_param; ++ ++static int soc_pm_enter(suspend_state_t state) ++{ ++ unsigned int lcr,opcr, clkgr; ++ ++ /** ++ sleep code use PDMA_TCSM, so must enable pdma and nemc ++ */ ++ s_reg.clkgr = clkgr = cpm_inl(CPM_CLKGR); ++ clkgr &= ~(1 << 21); ++ cpm_outl(clkgr, CPM_CLKGR); ++ ++ memcpy(&s_reg.ddr_training_space,(void*)0x80000000,sizeof(s_reg.ddr_training_space)); ++ s_reg.opcr = cpm_inl(CPM_OPCR); ++ s_reg.lcr = cpm_inl(CPM_LCR); ++ ++ load_pm_firmware_new(SLEEP_TCSM_SPACE); ++ sleep_param = (struct sleep_param *)SLEEP_TCSM_SPACE; ++ ++ sleep_param->post_resume_pc = (unsigned int)restore_goto; ++ sleep_param->uart_id = -1; ++ /* ++ * set OPCR. ++ */ ++ opcr = s_reg.opcr; ++ lcr = s_reg.lcr; ++ ++ opcr &= ~((1 << 25) | (1 << 22) | (0xfff << 8) | (1 << 4) | (1 << 3) | (1 << 2)); ++ opcr |= (1 << 31) | (1 << 30) | (1 << 25) | (0xfff << 8) | (1 << 4) | (1 << 3); ++ lcr &= ~3; ++ ++#ifdef CONFIG_RTC_DRV_INGENIC ++ opcr &= ~((1 << 4) | (1 << 2)); ++ opcr |= (1 << 2); ++#endif ++ ++ if(s_reg.pm_state == PM_SUSPEND_STANDBY) { ++ opcr &= ~((1 << 31) | (1 << 30)); ++ } else { ++ lcr |= LCR_LPM_SLEEP; ++ } ++ cpm_outl(opcr,CPM_OPCR); ++ cpm_outl(lcr,CPM_LCR); ++ ++ printk("#####lcr:%08x\n", cpm_inl(CPM_LCR)); ++ printk("#####gate:%08x\n", cpm_inl(CPM_CLKGR)); ++ printk("#####opcr:%08x\n", cpm_inl(CPM_OPCR)); ++ printk("#####INT_MASK0:%08x\n", *(volatile unsigned int*)(0xB0001004)); ++ printk("#####INT_MASK1:%08x\n", *(volatile unsigned int*)(0xB0001024)); ++ printk("#####INT_PEND0:%08x\n", *(volatile unsigned int*)(0xB0001010)); ++ printk("#####INT_PEND1:%08x\n", *(volatile unsigned int*)(0xB0001030)); ++ ++ mb(); ++ save_goto((unsigned int)sleep_param->pm_core_enter); ++ mb(); ++ ++ memcpy((void*)0x80000000,&s_reg.ddr_training_space,sizeof(s_reg.ddr_training_space)); ++ dma_cache_wback_inv(0x80000000,sizeof(s_reg.ddr_training_space)); ++ cpm_outl(s_reg.lcr,CPM_LCR); ++ cpm_outl(s_reg.opcr,CPM_OPCR); ++ cpm_outl(s_reg.clkgr, CPM_CLKGR); ++ ++ return 0; ++} ++ ++static int soc_valid(suspend_state_t state) ++{ ++ switch (state) { ++ case PM_SUSPEND_ON: ++ case PM_SUSPEND_STANDBY: ++ case PM_SUSPEND_MEM: ++ return 1; ++ ++ default: ++ return 0; ++ } ++} ++static void soc_finish(void) ++{ ++ s_reg.pm_state = 0; ++} ++static int soc_begin(suspend_state_t state) ++{ ++ s_reg.pm_state = state; ++ if(s_reg.pm_state == PM_SUSPEND_STANDBY) { ++ jz_notifier_call(NOTEFY_PROI_HIGH, JZ_PM_SUSPEND_STANDBY, &s_reg.pm_state); ++ } ++ return 0; ++} ++ ++/* ++ * Initialize power interface ++ */ ++struct platform_suspend_ops pm_ops = { ++ .valid = soc_valid, ++ .begin = soc_begin, ++ .enter = soc_pm_enter, ++ .end = soc_finish, ++}; ++ ++int __init soc_pm_init(void) ++{ ++ volatile unsigned int lcr,opcr; ++ ++ suspend_set_ops(&pm_ops); ++ ++ /* init opcr and lcr for idle */ ++ lcr = cpm_inl(CPM_LCR); ++ lcr &= ~(0x3); /* LCR.SLEEP.DS=1'b0,LCR.LPM=2'b00*/ ++ lcr |= 0xff << 8; /* power stable time */ ++ cpm_outl(lcr,CPM_LCR); ++ ++ opcr = cpm_inl(CPM_OPCR); ++ opcr |= 0xff << 8; /* EXCLK stable time */ ++ opcr &= ~(1 << 4); /* EXCLK oscillator is disabled in Sleep mode */ ++ cpm_outl(opcr,CPM_OPCR); ++ ++ /* sysfs */ ++ return 0; ++} ++ ++arch_initcall(soc_pm_init); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_regs_save_restore.S.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_regs_save_restore.S.patch new file mode 100644 index 00000000..da5adbb2 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_regs_save_restore.S.patch @@ -0,0 +1,176 @@ +diff -drupN a/arch/mips/xburst/soc-x1800/regs_save_restore.S b/arch/mips/xburst/soc-x1800/regs_save_restore.S +--- a/arch/mips/xburst/soc-x1800/regs_save_restore.S 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/soc-x1800/regs_save_restore.S 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,172 @@ ++#include ++#include ++ ++#define CP0_CONTEXT $4,0 ++#define CP0_PAGEMASK $5,0 ++#define CP0_TLB_SPEC $5,4 ++#define CP0_STATUS $12,0 ++#define CP0_INTCTL $12,1 ++#define CP0_CAUSE $13,0 ++#define CP0_EBASE $15,1 ++#define CP0_CONFIG $16,0 ++#define CP0_CONFIG1 $16,1 ++#define CP0_CONFIG2 $16,2 ++#define CP0_CONFIG3 $16,3 ++#define CP0_CONFIG7 $16,7 ++#define CP0_LLADDR $17,0 ++#define PMON_CSR $17,7 ++#define PMON_HIGH $17,4 ++#define PMON_LC $17,5 ++#define PMON_RC $17,6 ++#define CP0_WATCHLo $18,0 ++#define CP0_WATCHHI $19,0 ++#define CP0_ERRCTL $26,0 ++ ++ .data ++ .global _regs_stack ++_regs_stack: ++ .align 5 ++ .space 128,0 ++ ++ .text ++ .global save_goto ++ .align 2 ++ .ent save_goto,0 ++save_goto: ++ .set push ++ .set noreorder ++ .set noat ++ ++ la k0, _regs_stack ++ sw s0,0(k0) ++ sw s1,4(k0) ++ sw s2,8(k0) ++ sw s3,12(k0) ++ sw s4,16(k0) ++ sw s5,20(k0) ++ sw s6,24(k0) ++ sw s7,28(k0) ++ sw gp,32(k0) ++ sw sp,36(k0) ++ sw fp,40(k0) ++ sw ra,44(k0) ++ ++ mfc0 k1,CP0_PAGEMASK ++ sw k1,48(k0) ++ mfc0 k1,CP0_TLB_SPEC ++ sw k1,52(k0) ++ mfc0 k1,CP0_STATUS ++ sw k1,56(k0) ++ mfc0 k1,CP0_INTCTL ++ sw k1,60(k0) ++ mfc0 k1,CP0_CAUSE ++ sw k1,64(k0) ++ mfc0 k1,CP0_EBASE ++ sw k1,68(k0) ++ mfc0 k1,CP0_CONFIG ++ sw k1,72(k0) ++ mfc0 k1,CP0_CONFIG1 ++ sw k1,76(k0) ++ mfc0 k1,CP0_CONFIG2 ++ sw k1,80(k0) ++ mfc0 k1,CP0_CONFIG3 ++ sw k1,84(k0) ++ mfc0 k1,CP0_CONFIG7 ++ sw k1,88(k0) ++ mfc0 k1,CP0_LLADDR ++ sw k1,92(k0) ++ mfc0 k1,PMON_CSR ++ sw k1,96(k0) ++ mfc0 k1,PMON_HIGH ++ sw k1,100(k0) ++ mfc0 k1,PMON_LC ++ sw k1,104(k0) ++ mfc0 k1,PMON_RC ++ sw k1,108(k0) ++ mfc0 k1,CP0_WATCHLo ++ sw k1,112(k0) ++ mfc0 k1,CP0_WATCHHI ++ sw k1,116(k0) ++ mfc0 k1,CP0_ERRCTL ++ sw k1,120(k0) ++ mfc0 k1,CP0_CONTEXT ++ sw k1,124(k0) ++ ++ jr a0 ++ nop ++ ++ .set at ++ .set reorder ++ .set pop ++ END(save_goto) ++ .text ++ .global restore_goto ++ .align 2 ++ .ent restore_goto,0 ++restore_goto: ++ .set push ++ .set noreorder ++ .set noat ++ ++ la k0, _regs_stack ++ lw s0,0(k0) ++ lw s1,4(k0) ++ lw s2,8(k0) ++ lw s3,12(k0) ++ lw s4,16(k0) ++ lw s5,20(k0) ++ lw s6,24(k0) ++ lw s7,28(k0) ++ lw gp,32(k0) ++ lw sp,36(k0) ++ lw fp,40(k0) ++ lw ra,44(k0) ++ ++ lw k1,48(k0) ++ mtc0 k1,CP0_PAGEMASK ++ lw k1,52(k0) ++ mtc0 k1,CP0_TLB_SPEC ++ lw k1,56(k0) ++ mtc0 k1,CP0_STATUS ++ lw k1,60(k0) ++ mtc0 k1,CP0_INTCTL ++ lw k1,64(k0) ++ mtc0 k1,CP0_CAUSE ++ lw k1,68(k0) ++ mtc0 k1,CP0_EBASE ++ lw k1,72(k0) ++ mtc0 k1,CP0_CONFIG ++ lw k1,76(k0) ++ mtc0 k1,CP0_CONFIG1 ++ lw k1,80(k0) ++ mtc0 k1,CP0_CONFIG2 ++ lw k1,84(k0) ++ mtc0 k1,CP0_CONFIG3 ++ lw k1,88(k0) ++ mtc0 k1,CP0_CONFIG7 ++ lw k1,92(k0) ++ mtc0 k1,CP0_LLADDR ++ lw k1,96(k0) ++ mtc0 k1,PMON_CSR ++ lw k1,100(k0) ++ mtc0 k1,PMON_HIGH ++ lw k1,104(k0) ++ mtc0 k1,PMON_LC ++ lw k1,108(k0) ++ mtc0 k1,PMON_RC ++ lw k1,112(k0) ++ mtc0 k1,CP0_WATCHLo ++ lw k1,116(k0) ++ mtc0 k1,CP0_WATCHHI ++ lw k1,120(k0) ++ mtc0 k1,CP0_ERRCTL ++ lw k1,124(k0) ++ mtc0 k1,CP0_CONTEXT ++ ++ jr ra ++ nop ++ ++ .set at ++ .set reorder ++ .set pop ++ END(restore_goto) diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_setup.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_setup.c.patch new file mode 100644 index 00000000..4b9158a3 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-arch_mips_xburst_soc-x1800_setup.c.patch @@ -0,0 +1,97 @@ +diff -drupN a/arch/mips/xburst/soc-x1800/setup.c b/arch/mips/xburst/soc-x1800/setup.c +--- a/arch/mips/xburst/soc-x1800/setup.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/arch/mips/xburst/soc-x1800/setup.c 2022-06-09 05:02:27.000000000 +0300 +@@ -0,0 +1,93 @@ ++/* ++ * INGENIC SOC Setup ++ * ++ * 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) 2006 Ingenic Semiconductor Inc. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++extern void *get_fdt_addr(void); ++ ++ ++static void __init cpm_reset(void) ++{ ++#ifndef CONFIG_FPGA_TEST ++ unsigned long clkgr = cpm_inl(CPM_CLKGR); ++ ++ clkgr &= ~(1 << 28 /* DES */ ++ | 1 << 26 /* TVE */ ++ | 1 << 13 /* SADC */ ++ ); ++ cpm_outl(clkgr, CPM_CLKGR); ++ ++ /* TODO set default clkgr here */ ++#endif ++} ++ ++static int __init setup_init(void) ++{ ++ cpm_reset(); ++ /* Set bus priority here */ ++ *(volatile unsigned int *)0xb34f0240 = 0x00010003; ++ *(volatile unsigned int *)0xb34f0244 = 0x00010003; ++ ++ return 0; ++} ++ ++ ++void __init plat_mem_setup(void) ++{ ++ ++ set_io_port_base(IO_BASE); ++ ++ /*Not have ioport*/ ++ ioport_resource.start = 0x00000000; ++ ioport_resource.end = 0xffffffff; ++ iomem_resource.start = 0x00000000; ++ iomem_resource.end = 0xffffffff; ++ ++ setup_init(); ++ ++ __dt_setup_arch(get_fdt_addr()); ++ ++ early_init_fdt_scan_reserved_mem(); ++ ++ return; ++} ++ ++void __init device_tree_init(void) ++{ ++ unflatten_and_copy_device_tree(); ++} ++ ++static int __init plat_of_populate(void) ++{ ++ of_platform_default_populate(NULL, NULL, NULL); ++ return 0; ++} ++arch_initcall(plat_of_populate); ++ ++void __init plat_time_init(void) ++{ ++ of_clk_init(NULL); ++ ++ clocksource_probe(); ++} ++ ++void __init arch_init_irq(void) { ++ ++ irqchip_init(); ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-block_partitions_efi.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-block_partitions_efi.c.patch new file mode 100644 index 00000000..28032b56 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-block_partitions_efi.c.patch @@ -0,0 +1,13 @@ +diff -drupN a/block/partitions/efi.c b/block/partitions/efi.c +--- a/block/partitions/efi.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/block/partitions/efi.c 2022-06-09 05:02:28.000000000 +0300 +@@ -420,7 +420,9 @@ static int is_gpt_valid(struct parsed_pa + pr_debug("GPT: last_usable_lba incorrect: %lld > %lld\n", + (unsigned long long)le64_to_cpu((*gpt)->last_usable_lba), + (unsigned long long)lastlba); ++#ifndef CONFIG_INGENIC_GPT_CHECK + goto fail; ++#endif + } + if (le64_to_cpu((*gpt)->last_usable_lba) < le64_to_cpu((*gpt)->first_usable_lba)) { + pr_debug("GPT: last_usable_lba incorrect: %lld > %lld\n", diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_Kconfig.patch new file mode 100644 index 00000000..2d74a40c --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_Kconfig.patch @@ -0,0 +1,11 @@ +diff -drupN a/drivers/Kconfig b/drivers/Kconfig +--- a/drivers/Kconfig 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/Kconfig 2022-06-09 05:02:28.000000000 +0300 +@@ -1,5 +1,7 @@ + menu "Device Drivers" + ++source "drivers/lzma/Kconfig" ++ + source "drivers/amba/Kconfig" + + source "drivers/base/Kconfig" diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_Makefile.patch new file mode 100644 index 00000000..d8eaa777 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_Makefile.patch @@ -0,0 +1,22 @@ +diff -drupN a/drivers/Makefile b/drivers/Makefile +--- a/drivers/Makefile 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/Makefile 2022-06-09 05:02:28.000000000 +0300 +@@ -20,6 +20,9 @@ obj-$(CONFIG_RAPIDIO) += rapidio/ + obj-y += video/ + obj-y += idle/ + ++# LZMA devices ++obj-y += lzma/ ++ + # IPMI must come before ACPI in order to provide IPMI opregion support + obj-$(CONFIG_IPMI_HANDLER) += char/ipmi/ + +@@ -66,7 +69,7 @@ obj-$(CONFIG_PARPORT) += parport/ + obj-$(CONFIG_NVM) += lightnvm/ + obj-y += base/ block/ misc/ mfd/ nfc/ + obj-$(CONFIG_LIBNVDIMM) += nvdimm/ +-obj-$(CONFIG_DMA_SHARED_BUFFER) += dma-buf/ ++obj-y += dma-buf/ + obj-$(CONFIG_NUBUS) += nubus/ + obj-y += macintosh/ + obj-$(CONFIG_IDE) += ide/ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_block_zram_zram_drv.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_block_zram_zram_drv.c.patch new file mode 100644 index 00000000..d7eb4762 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_block_zram_zram_drv.c.patch @@ -0,0 +1,12 @@ +diff -drupN a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c +--- a/drivers/block/zram/zram_drv.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/block/zram/zram_drv.c 2022-06-09 05:02:28.000000000 +0300 +@@ -41,7 +41,7 @@ static int zram_major; + static const char *default_compressor = "lzo"; + + /* Module params (documentation at end) */ +-static unsigned int num_devices = 1; ++static unsigned int num_devices = 2; + + static inline void deprecated_attr_warn(const char *name) + { diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_bluetooth_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_bluetooth_Kconfig.patch new file mode 100644 index 00000000..62978665 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_bluetooth_Kconfig.patch @@ -0,0 +1,21 @@ +diff -drupN a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig +--- a/drivers/bluetooth/Kconfig 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/bluetooth/Kconfig 2022-06-09 05:02:28.000000000 +0300 +@@ -86,6 +86,17 @@ config BT_HCIUART_H4 + + Say Y here to compile support for HCI UART (H4) protocol. + ++config BT_HCIUART_RTKH5 ++ bool "Realtek H5 protocol support" ++ depends on BT_HCIUART ++ help ++ Realtek H5 is serial protocol for communication ++ between Realtek Bluetooth device and host. This protocol is required for ++ Realtek uart h5 bluetooth controller ++ ++ Say Y here to compile support for Realtek HCI H5 protocol. ++ ++ + config BT_HCIUART_BCSP + bool "BCSP protocol support" + depends on BT_HCIUART diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_bluetooth_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_bluetooth_Makefile.patch new file mode 100644 index 00000000..e6ff8a47 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_bluetooth_Makefile.patch @@ -0,0 +1,13 @@ +diff -drupN a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile +--- a/drivers/bluetooth/Makefile 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/bluetooth/Makefile 2022-06-09 05:02:28.000000000 +0300 +@@ -2,6 +2,9 @@ + # Makefile for the Linux Bluetooth HCI device drivers. + # + ++obj-$(CONFIG_BT_HCIUART_RTKH5) += hci_rtk_h5.o ++obj-$(CONFIG_BT_HCIUART_RTKH5) += rtk_coex.o ++ + obj-$(CONFIG_BT_HCIVHCI) += hci_vhci.o + obj-$(CONFIG_BT_HCIUART) += hci_uart.o + obj-$(CONFIG_BT_HCIBCM203X) += bcm203x.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_bluetooth_hci_ldisc.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_bluetooth_hci_ldisc.c.patch new file mode 100644 index 00000000..54380538 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_bluetooth_hci_ldisc.c.patch @@ -0,0 +1,186 @@ +diff -drupN a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c +--- a/drivers/bluetooth/hci_ldisc.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/bluetooth/hci_ldisc.c 2022-06-09 05:02:28.000000000 +0300 +@@ -48,6 +48,13 @@ + #include "btintel.h" + #include "btbcm.h" + #include "hci_uart.h" ++#include ++#define DEVNAME "rtl_bt_en" ++ ++#ifdef BTCOEX ++#include ++#include "rtk_coex.h" ++#endif + + #define VERSION "2.3" + +@@ -208,6 +215,9 @@ static int hci_uart_open(struct hci_dev + BT_DBG("%s %p", hdev->name, hdev); + + /* Nothing to do for UART driver */ ++#ifdef BTCOEX ++ rtk_btcoex_open(hdev); ++#endif + return 0; + } + +@@ -238,8 +248,16 @@ static int hci_uart_close(struct hci_dev + { + BT_DBG("hdev %p", hdev); + ++ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) ++ return 0; ++ + hci_uart_flush(hdev); + hdev->flush = NULL; ++ ++#ifdef BTCOEX ++ rtk_btcoex_close(); ++#endif ++ + return 0; + } + +@@ -250,6 +268,13 @@ static int hci_uart_send_frame(struct hc + + BT_DBG("%s: type %d len %d", hdev->name, bt_cb(skb)->pkt_type, skb->len); + ++#ifdef BTCOEX ++ if (bt_cb(skb)->pkt_type == HCI_COMMAND_PKT) ++ rtk_btcoex_parse_cmd(skb->data, skb->len); ++ if (bt_cb(skb)->pkt_type == HCI_ACLDATA_PKT) ++ rtk_btcoex_parse_l2cap_data_tx(skb->data, skb->len); ++#endif ++ + hu->proto->enqueue(hu, skb); + + hci_uart_tx_wakeup(hu); +@@ -505,7 +530,9 @@ static void hci_uart_tty_close(struct tt + } + hu->proto->close(hu); + } +- ++#ifdef CONFIG_BT_HCIUART_RTKH5 ++ clear_bit(HCI_UART_PROTO_SET, &hu->flags); ++#endif + kfree(hu); + } + +@@ -625,7 +652,9 @@ static int hci_uart_register_dev(struct + } + + set_bit(HCI_UART_REGISTERED, &hu->flags); +- ++#ifdef BTCOEX ++ rtk_btcoex_probe(hdev); ++#endif + return 0; + } + +@@ -643,9 +672,15 @@ static int hci_uart_set_proto(struct hci + return err; + + hu->proto = p; ++#ifdef CONFIG_BT_HCIUART_RTKH5 ++ set_bit(HCI_UART_PROTO_SET, &hu->flags); ++#endif + + err = hci_uart_register_dev(hu); + if (err) { ++#ifdef CONFIG_BT_HCIUART_RTKH5 ++ clear_bit(HCI_UART_PROTO_SET, &hu->flags); ++#endif + p->close(hu); + return err; + } +@@ -810,6 +845,14 @@ static int __init hci_uart_init(void) + qca_init(); + #endif + ++#ifdef CONFIG_BT_HCIUART_RTKH5 ++ h5_init(); ++#endif ++ ++#ifdef BTCOEX ++ rtk_btcoex_init(); ++#endif ++ + return 0; + } + +@@ -841,15 +884,74 @@ static void __exit hci_uart_exit(void) + #ifdef CONFIG_BT_HCIUART_QCA + qca_deinit(); + #endif ++#ifdef CONFIG_BT_HCIUART_RTKH5 ++ h5_deinit(); ++#endif + ++#ifdef BTCOEX ++ rtk_btcoex_exit(); ++#endif + /* Release tty registration of line discipline */ + err = tty_unregister_ldisc(N_HCI); + if (err) + BT_ERR("Can't unregister HCI line discipline (%d)", err); + } ++#if (defined CONFIG_BT_HCIUART_RTKH5) && (defined CONFIG_BT_HCIUART_H4) ++ ++struct rtl_bt_data { ++ int (*rtl_bt_en)(void); ++}; ++ ++static int rtl_bt_probe (struct platform_device *pdev) ++{ ++ struct rtl_bt_data * bt_data = NULL; ++ int ret = 0; + ++ bt_data = (struct rtl_bt_data *)pdev->dev.platform_data; ++ if (bt_data->rtl_bt_en) ++ bt_data->rtl_bt_en(); ++ else ++ BT_ERR("rtl_bt_en pin enable failed\n"); ++ ++ ret = hci_uart_init(); ++ return ret; ++} ++ ++static int rtl_bt_remove (struct platform_device *pdev) ++{ ++ hci_uart_exit(); ++ return 0; ++} ++ ++static struct platform_driver bt_drv = { ++ .probe = rtl_bt_probe, ++ .remove = rtl_bt_remove, ++ .driver = { ++ .name = DEVNAME, ++ }, ++}; ++ ++static int __init rtk_bt_init(void) ++{ ++ int ret = 0; ++ ret = platform_driver_register(&bt_drv); ++ if (ret < 0) { ++ BT_ERR("register bt driver failed\n"); ++ } ++ return ret; ++} ++ ++static void __exit rtk_bt_exit(void) ++{ ++ platform_driver_unregister(&bt_drv); ++} ++ ++module_init(rtk_bt_init); ++module_exit(rtk_bt_exit); ++#else + module_init(hci_uart_init); + module_exit(hci_uart_exit); ++#endif + + MODULE_AUTHOR("Marcel Holtmann "); + MODULE_DESCRIPTION("Bluetooth HCI UART driver ver " VERSION); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_bluetooth_hci_rtk_h5.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_bluetooth_hci_rtk_h5.c.patch new file mode 100644 index 00000000..67f2fa91 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_bluetooth_hci_rtk_h5.c.patch @@ -0,0 +1,884 @@ +diff -drupN a/drivers/bluetooth/hci_rtk_h5.c b/drivers/bluetooth/hci_rtk_h5.c +--- a/drivers/bluetooth/hci_rtk_h5.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/bluetooth/hci_rtk_h5.c 2022-06-09 05:02:28.000000000 +0300 +@@ -0,0 +1,880 @@ ++/* ++ * ++ * Bluetooth HCI UART driver ++ * ++ * Copyright (C) 2011-2014 wifi_fae ++ * ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "hci_uart.h" ++ ++ ++ ++#ifdef BTCOEX ++#include "rtk_coex.h" ++#endif ++ ++//#define VERSION "1.0" ++ ++static int txcrc = 1; ++//static int hciextn = 1; ++ ++#define H5_TXWINSIZE 4 ++#define H5_ACK_PKT 0x00 ++#define H5_LE_PKT 0x0F ++#define H5_VDRSPEC_PKT 0x0E ++ ++struct h5_struct { ++ struct sk_buff_head unack; /* Unack'ed packets queue */ ++ struct sk_buff_head rel; /* Reliable packets queue */ ++ struct sk_buff_head unrel; /* Unreliable packets queue */ ++ ++ unsigned long rx_count; ++ struct sk_buff *rx_skb; ++ u8 rxseq_txack; /* rxseq == txack. */ ++ u8 rxack; /* Last packet sent by us that the peer ack'ed */ ++ struct timer_list th5; ++ ++ enum { ++ H5_W4_PKT_DELIMITER, ++ H5_W4_PKT_START, ++ H5_W4_HDR, ++ H5_W4_DATA, ++ H5_W4_CRC ++ } rx_state; ++ ++ enum { ++ H5_ESCSTATE_NOESC, ++ H5_ESCSTATE_ESC ++ } rx_esc_state; ++ ++ u8 use_crc; ++ u16 message_crc; ++ u8 txack_req; /* Do we need to send ack's to the peer? */ ++ ++ /* Reliable packet sequence number - used to assign seq to each rel pkt. */ ++ u8 msgq_txseq; ++}; ++ ++/* ---- H5 CRC calculation ---- */ ++ ++/* Table for calculating CRC for polynomial 0x1021, LSB processed first, ++initial value 0xffff, bits shifted in reverse order. */ ++ ++static const u16 crc_table[] = { ++ 0x0000, 0x1081, 0x2102, 0x3183, ++ 0x4204, 0x5285, 0x6306, 0x7387, ++ 0x8408, 0x9489, 0xa50a, 0xb58b, ++ 0xc60c, 0xd68d, 0xe70e, 0xf78f ++}; ++ ++/* Initialise the crc calculator */ ++#define H5_CRC_INIT(x) x = 0xffff ++ ++/* ++ Update crc with next data byte ++ ++ Implementation note ++ The data byte is treated as two nibbles. The crc is generated ++ in reverse, i.e., bits are fed into the register from the top. ++*/ ++static void h5_crc_update(u16 * crc, u8 d) ++{ ++ u16 reg = *crc; ++ ++ reg = (reg >> 4) ^ crc_table[(reg ^ d) & 0x000f]; ++ reg = (reg >> 4) ^ crc_table[(reg ^ (d >> 4)) & 0x000f]; ++ ++ *crc = reg; ++} ++ ++/* ---- H5 core ---- */ ++ ++static void h5_slip_msgdelim(struct sk_buff *skb) ++{ ++ const char pkt_delim = 0xc0; ++ ++ memcpy(skb_put(skb, 1), &pkt_delim, 1); ++} ++ ++static void h5_slip_one_byte(struct sk_buff *skb, u8 c) ++{ ++ const char esc_c0[2] = { 0xdb, 0xdc }; ++ const char esc_db[2] = { 0xdb, 0xdd }; ++ const char esc_11[2] = { 0xdb, 0xde }; ++ const char esc_13[2] = { 0xdb, 0xdf }; ++ ++ switch (c) { ++ case 0xc0: ++ memcpy(skb_put(skb, 2), &esc_c0, 2); ++ break; ++ case 0xdb: ++ memcpy(skb_put(skb, 2), &esc_db, 2); ++ break; ++ case 0x11: ++ memcpy(skb_put(skb, 2), &esc_11, 2); ++ break; ++ case 0x13: ++ memcpy(skb_put(skb, 2), &esc_13, 2); ++ break; ++ default: ++ memcpy(skb_put(skb, 1), &c, 1); ++ } ++} ++ ++static int h5_enqueue(struct hci_uart *hu, struct sk_buff *skb) ++{ ++ struct h5_struct *h5 = hu->priv; ++ ++ if (skb->len > 0xFFF) { //Pkt length must be less than 4095 bytes ++ BT_ERR("Packet too long"); ++ kfree_skb(skb); ++ return 0; ++ } ++ ++ switch (bt_cb(skb)->pkt_type) { ++ case HCI_ACLDATA_PKT: ++ case HCI_COMMAND_PKT: ++ skb_queue_tail(&h5->rel, skb); ++ break; ++ ++ case HCI_SCODATA_PKT: ++ skb_queue_tail(&h5->unrel, skb); ++ break; ++ case H5_LE_PKT: ++ case H5_ACK_PKT: ++ case H5_VDRSPEC_PKT: ++ skb_queue_tail(&h5->unrel, skb); /* 3-wire LinkEstablishment */ ++ break; ++ ++ default: ++ BT_ERR("Unknown packet type"); ++ kfree_skb(skb); ++ break; ++ } ++ ++ return 0; ++} ++ ++static struct sk_buff *h5_prepare_pkt(struct h5_struct *h5, u8 * data, ++ int len, int pkt_type) ++{ ++ struct sk_buff *nskb; ++ u8 hdr[4], chan; ++ u16 H5_CRC_INIT(h5_txmsg_crc); ++ int rel, i; ++ ++ switch (pkt_type) { ++ case HCI_ACLDATA_PKT: ++ chan = 2; /* 3-wire ACL channel */ ++ rel = 1; /* reliable channel */ ++ break; ++ case HCI_COMMAND_PKT: ++ chan = 1; /* 3-wire cmd channel */ ++ rel = 1; /* reliable channel */ ++ break; ++ case HCI_EVENT_PKT: ++ chan = 4; /* 3-wire cmd channel */ ++ rel = 1; /* reliable channel */ ++ break; ++ case HCI_SCODATA_PKT: ++ chan = 3; /* 3-wire SCO channel */ ++ rel = 0; /* unreliable channel */ ++ break; ++ case H5_LE_PKT: ++ chan = 15; /* 3-wire LinkEstablishment channel */ ++ rel = 0; /* unreliable channel */ ++ break; ++ case H5_ACK_PKT: ++ chan = 0; /* 3-wire ACK channel */ ++ rel = 0; /* unreliable channel */ ++ break; ++ case H5_VDRSPEC_PKT: ++ chan = 14; /* 3-wire Vendor Specific channel */ ++ rel = 0; /* unreliable channel */ ++ break; ++ default: ++ BT_ERR("Unknown packet type"); ++ return NULL; ++ } ++ ++ /* Max len of packet: (original len +4(h5 hdr) +2(crc))*2 ++ (because bytes 0xc0 and 0xdb are escaped, worst case is ++ when the packet is all made of 0xc0 and 0xdb :) ) ++ + 2 (0xc0 delimiters at start and end). */ ++ ++ nskb = alloc_skb((len + 6) * 2 + 2, GFP_ATOMIC); ++ if (!nskb) ++ return NULL; ++ ++ bt_cb(nskb)->pkt_type = pkt_type; ++ ++ h5_slip_msgdelim(nskb); ++ ++ hdr[0] = h5->rxseq_txack << 3; ++ h5->txack_req = 0; ++ BT_DBG("We request packet no %u to card", h5->rxseq_txack); ++ ++ if (rel) { ++ hdr[0] |= 0x80 + h5->msgq_txseq; ++ BT_DBG("Sending packet with seqno %u", h5->msgq_txseq); ++ h5->msgq_txseq = (h5->msgq_txseq + 1) & 0x07; ++ } ++ ++ if (h5->use_crc) ++ hdr[0] |= 0x40; ++ ++ hdr[1] = ((len << 4) & 0xff) | chan; ++ hdr[2] = len >> 4; ++ hdr[3] = ~(hdr[0] + hdr[1] + hdr[2]); ++ ++ /* Put H5 header */ ++ for (i = 0; i < 4; i++) { ++ h5_slip_one_byte(nskb, hdr[i]); ++ ++ if (h5->use_crc) ++ h5_crc_update(&h5_txmsg_crc, hdr[i]); ++ } ++ ++ /* Put payload */ ++ for (i = 0; i < len; i++) { ++ h5_slip_one_byte(nskb, data[i]); ++ ++ if (h5->use_crc) ++ h5_crc_update(&h5_txmsg_crc, data[i]); ++ } ++ ++ /* Put CRC */ ++ if (h5->use_crc) { ++ h5_txmsg_crc = bitrev16(h5_txmsg_crc); ++ h5_slip_one_byte(nskb, (u8) ((h5_txmsg_crc >> 8) & 0x00ff)); ++ h5_slip_one_byte(nskb, (u8) (h5_txmsg_crc & 0x00ff)); ++ } ++ ++ h5_slip_msgdelim(nskb); ++ return nskb; ++} ++ ++/* This is a rewrite of pkt_avail in AH5 */ ++static struct sk_buff *h5_dequeue(struct hci_uart *hu) ++{ ++ struct h5_struct *h5 = hu->priv; ++ unsigned long flags; ++ struct sk_buff *skb; ++ ++ /* First of all, check for unreliable messages in the queue, ++ since they have priority */ ++ ++ if ((skb = skb_dequeue(&h5->unrel)) != NULL) { ++ struct sk_buff *nskb = ++ h5_prepare_pkt(h5, skb->data, skb->len, ++ bt_cb(skb)->pkt_type); ++ if (nskb) { ++ kfree_skb(skb); ++ return nskb; ++ } else { ++ skb_queue_head(&h5->unrel, skb); ++ BT_ERR ++ ("Could not dequeue pkt because alloc_skb failed"); ++ } ++ } ++ ++ /* Now, try to send a reliable pkt. We can only send a ++ reliable packet if the number of packets sent but not yet ack'ed ++ is < than the winsize */ ++ ++ spin_lock_irqsave_nested(&h5->unack.lock, flags, SINGLE_DEPTH_NESTING); ++ ++ if (h5->unack.qlen < H5_TXWINSIZE ++ && (skb = skb_dequeue(&h5->rel)) != NULL) { ++ struct sk_buff *nskb = ++ h5_prepare_pkt(h5, skb->data, skb->len, ++ bt_cb(skb)->pkt_type); ++ if (nskb) { ++ __skb_queue_tail(&h5->unack, skb); ++ mod_timer(&h5->th5, jiffies + HZ / 4); ++ spin_unlock_irqrestore(&h5->unack.lock, flags); ++ return nskb; ++ } else { ++ skb_queue_head(&h5->rel, skb); ++ BT_ERR ++ ("Could not dequeue pkt because alloc_skb failed"); ++ } ++ } ++ ++ spin_unlock_irqrestore(&h5->unack.lock, flags); ++ ++ /* We could not send a reliable packet, either because there are ++ none or because there are too many unack'ed pkts. Did we receive ++ any packets we have not acknowledged yet ? */ ++ ++ if (h5->txack_req) { ++ /* if so, craft an empty ACK pkt and send it on H5 unreliable ++ channel 0 */ ++ struct sk_buff *nskb = h5_prepare_pkt(h5, NULL, 0, H5_ACK_PKT); ++ return nskb; ++ } ++ ++ /* We have nothing to send */ ++ return NULL; ++} ++ ++static int h5_flush(struct hci_uart *hu) ++{ ++ BT_DBG("hu %p", hu); ++ return 0; ++} ++ ++/* Remove ack'ed packets */ ++static void h5_pkt_cull(struct h5_struct *h5) ++{ ++ struct sk_buff *skb, *tmp; ++ unsigned long flags; ++ int i, pkts_to_be_removed; ++ u8 seqno; ++ ++ spin_lock_irqsave(&h5->unack.lock, flags); ++ ++ pkts_to_be_removed = skb_queue_len(&h5->unack); ++ seqno = h5->msgq_txseq; ++ ++ while (pkts_to_be_removed) { ++ if (h5->rxack == seqno) ++ break; ++ pkts_to_be_removed--; ++ seqno = (seqno - 1) & 0x07; ++ } ++ ++ if (h5->rxack != seqno) ++ BT_ERR("Peer acked invalid packet"); ++ ++ BT_DBG("Removing %u pkts out of %u, up to seqno %u", ++ pkts_to_be_removed, skb_queue_len(&h5->unack), ++ (seqno - 1) & 0x07); ++ ++ i = 0; ++ skb_queue_walk_safe(&h5->unack, skb, tmp) { ++ if (i >= pkts_to_be_removed) ++ break; ++ i++; ++ ++ __skb_unlink(skb, &h5->unack); ++ kfree_skb(skb); ++ } ++ ++ if (skb_queue_empty(&h5->unack)) ++ del_timer(&h5->th5); ++ ++ spin_unlock_irqrestore(&h5->unack.lock, flags); ++ ++ if (i != pkts_to_be_removed) ++ BT_ERR("Removed only %u out of %u pkts", i, pkts_to_be_removed); ++} ++ ++/* Handle H5 link-establishment packets. When we ++ detect a "sync" packet, symptom that the BT module has reset, ++ we do nothing :) (yet) */ ++#if 0 ++static void h5_handle_le_pkt(struct hci_uart *hu) ++{ ++ struct h5_struct *h5 = hu->priv; ++ u8 conf_pkt[2] = { 0x03, 0xfc }; ++ u8 conf_rsp_pkt[3] = { 0x04, 0x7b, 0x00 }; ++ u8 sync_pkt[2] = { 0x01, 0x7e }; ++ u8 sync_rsp_pkt[2] = { 0x02, 0x7d }; ++ ++ u8 wakeup_pkt[2] = { 0x05, 0xfa }; ++ u8 woken_pkt[2] = { 0x06, 0xf9 }; ++ u8 sleep_pkt[2] = { 0x07, 0x78 }; ++ ++ /* spot "conf" pkts and reply with a "conf rsp" pkt */ ++ if (h5->rx_skb->data[1] >> 4 == 2 && h5->rx_skb->data[2] == 0 && ++ !memcmp(&h5->rx_skb->data[4], conf_pkt, 2)) { ++ struct sk_buff *nskb = alloc_skb(3, GFP_ATOMIC); ++ ++ BT_DBG("Found a LE conf pkt"); ++ if (!nskb) ++ return; ++ ++ conf_rsp_pkt[2] |= txcrc << 0x4; //crc check enable, version no = 0. needed to be as avariable. ++ memcpy(skb_put(nskb, 3), conf_rsp_pkt, 3); ++ bt_cb(nskb)->pkt_type = H5_LE_PKT; ++ ++ skb_queue_head(&h5->unrel, nskb); ++ hci_uart_tx_wakeup(hu); ++ } ++ /* spot "conf resp" pkts */ ++ else if (h5->rx_skb->data[1] >> 4 == 2 && h5->rx_skb->data[2] == 0 && ++ !memcmp(&h5->rx_skb->data[4], conf_rsp_pkt, 2)) { ++ BT_DBG("Found a LE conf resp pkt, device go into active state"); ++ txcrc = (h5->rx_skb->data[6] >> 0x4) & 0x1; ++ } ++ ++ /* Spot "sync" pkts. If we find one...disaster! */ ++ else if (h5->rx_skb->data[1] >> 4 == 2 && h5->rx_skb->data[2] == 0 && ++ !memcmp(&h5->rx_skb->data[4], sync_pkt, 2)) { ++ BT_ERR("Found a LE sync pkt, card has reset"); ++ //DO Something here ++ } ++ /* Spot "sync resp" pkts. If we find one...disaster! */ ++ else if (h5->rx_skb->data[1] >> 4 == 2 && h5->rx_skb->data[2] == 0 && ++ !memcmp(&h5->rx_skb->data[4], sync_rsp_pkt, 2)) { ++ BT_ERR ++ ("Found a LE sync resp pkt, device go into initialized state"); ++ // DO Something here ++ } ++ /* Spot "wakeup" pkts. reply woken message when in active mode */ ++ else if (h5->rx_skb->data[1] >> 4 == 2 && h5->rx_skb->data[2] == 0 && ++ !memcmp(&h5->rx_skb->data[4], wakeup_pkt, 2)) { ++ struct sk_buff *nskb = alloc_skb(2, GFP_ATOMIC); ++ ++ BT_ERR("Found a LE Wakeup pkt, and reply woken message"); ++ // DO Something here ++ ++ memcpy(skb_put(nskb, 2), woken_pkt, 2); ++ bt_cb(nskb)->pkt_type = H5_LE_PKT; ++ ++ skb_queue_head(&h5->unrel, nskb); ++ hci_uart_tx_wakeup(hu); ++ } ++ /* Spot "woken" pkts. receive woken message from device */ ++ else if (h5->rx_skb->data[1] >> 4 == 2 && h5->rx_skb->data[2] == 0 && ++ !memcmp(&h5->rx_skb->data[4], woken_pkt, 2)) { ++ BT_ERR("Found a LE woken pkt from device"); ++ // DO Something here ++ } ++ /* Spot "Sleep" pkts */ ++ else if (h5->rx_skb->data[1] >> 4 == 2 && h5->rx_skb->data[2] == 0 && ++ !memcmp(&h5->rx_indent: Standard input:620: Error:Unmatched 'else' ++skb->data[4], sleep_pkt, 2)) { ++ BT_ERR("Found a LE Sleep pkt"); ++ // DO Something here ++ } ++} ++#endif ++ ++static inline void h5_unslip_one_byte(struct h5_struct *h5, unsigned char byte) ++{ ++ const u8 c0 = 0xc0, db = 0xdb; ++ const u8 oof1 = 0x11, oof2 = 0x13; ++ ++ switch (h5->rx_esc_state) { ++ case H5_ESCSTATE_NOESC: ++ switch (byte) { ++ case 0xdb: ++ h5->rx_esc_state = H5_ESCSTATE_ESC; ++ break; ++ default: ++ memcpy(skb_put(h5->rx_skb, 1), &byte, 1); ++ if ((h5->rx_skb->data[0] & 0x40) != 0 && ++ h5->rx_state != H5_W4_CRC) ++ h5_crc_update(&h5->message_crc, byte); ++ h5->rx_count--; ++ } ++ break; ++ ++ case H5_ESCSTATE_ESC: ++ switch (byte) { ++ case 0xdc: ++ memcpy(skb_put(h5->rx_skb, 1), &c0, 1); ++ if ((h5->rx_skb->data[0] & 0x40) != 0 && ++ h5->rx_state != H5_W4_CRC) ++ h5_crc_update(&h5->message_crc, 0xc0); ++ h5->rx_esc_state = H5_ESCSTATE_NOESC; ++ h5->rx_count--; ++ break; ++ ++ case 0xdd: ++ memcpy(skb_put(h5->rx_skb, 1), &db, 1); ++ if ((h5->rx_skb->data[0] & 0x40) != 0 && ++ h5->rx_state != H5_W4_CRC) ++ h5_crc_update(&h5->message_crc, 0xdb); ++ h5->rx_esc_state = H5_ESCSTATE_NOESC; ++ h5->rx_count--; ++ break; ++ ++ case 0xde: ++ memcpy(skb_put(h5->rx_skb, 1), &oof1, 1); ++ if ((h5->rx_skb->data[0] & 0x40) != 0 ++ && h5->rx_state != H5_W4_CRC) ++ h5_crc_update(&h5->message_crc, oof1); ++ h5->rx_esc_state = H5_ESCSTATE_NOESC; ++ h5->rx_count--; ++ break; ++ ++ case 0xdf: ++ memcpy(skb_put(h5->rx_skb, 1), &oof2, 1); ++ if ((h5->rx_skb->data[0] & 0x40) != 0 ++ && h5->rx_state != H5_W4_CRC) ++ h5_crc_update(&h5->message_crc, oof2); ++ h5->rx_esc_state = H5_ESCSTATE_NOESC; ++ h5->rx_count--; ++ break; ++ ++ default: ++ BT_ERR("Invalid byte %02x after esc byte", byte); ++ kfree_skb(h5->rx_skb); ++ h5->rx_skb = NULL; ++ h5->rx_state = H5_W4_PKT_DELIMITER; ++ h5->rx_count = 0; ++ } ++ } ++} ++ ++static void h5_complete_rx_pkt(struct hci_uart *hu) ++{ ++ struct h5_struct *h5 = hu->priv; ++ int pass_up; ++ ++ if (h5->rx_skb->data[0] & 0x80) { /* reliable pkt */ ++ BT_DBG("Received seqno %u from card", h5->rxseq_txack); ++ h5->rxseq_txack++; ++ h5->rxseq_txack %= 0x8; ++ h5->txack_req = 1; ++ ++ /* If needed, transmit an ack pkt */ ++ hci_uart_tx_wakeup(hu); ++ } ++ ++ h5->rxack = (h5->rx_skb->data[0] >> 3) & 0x07; ++ BT_DBG("Request for pkt %u from card", h5->rxack); ++ ++ h5_pkt_cull(h5); ++ ++ if ((h5->rx_skb->data[1] & 0x0f) == 2 && h5->rx_skb->data[0] & 0x80) { ++ bt_cb(h5->rx_skb)->pkt_type = HCI_ACLDATA_PKT; ++ pass_up = 1; ++ } else if ((h5->rx_skb->data[1] & 0x0f) == 4 && ++ h5->rx_skb->data[0] & 0x80) { ++ bt_cb(h5->rx_skb)->pkt_type = HCI_EVENT_PKT; ++ pass_up = 1; ++ } else if ((h5->rx_skb->data[1] & 0x0f) == 3) { ++ bt_cb(h5->rx_skb)->pkt_type = HCI_SCODATA_PKT; ++ pass_up = 1; ++ } else if ((h5->rx_skb->data[1] & 0x0f) == 15 && ++ !(h5->rx_skb->data[0] & 0x80)) { ++ //h5_handle_le_pkt(hu);//Link Establishment Pkt ++ pass_up = 0; ++ } else if ((h5->rx_skb->data[1] & 0x0f) == 1 && ++ h5->rx_skb->data[0] & 0x80) { ++ bt_cb(h5->rx_skb)->pkt_type = HCI_COMMAND_PKT; ++ pass_up = 1; ++ } else if ((h5->rx_skb->data[1] & 0x0f) == 14) { ++ bt_cb(h5->rx_skb)->pkt_type = H5_VDRSPEC_PKT; ++ pass_up = 1; ++ } else ++ pass_up = 0; ++ ++ if (!pass_up) { ++ /* struct hci_event_hdr hdr; */ ++ u8 desc = (h5->rx_skb->data[1] & 0x0f); ++ ++ if (desc != H5_ACK_PKT && desc != H5_LE_PKT) { ++ /* if (hciextn) { ++ * desc |= 0xc0; ++ * skb_pull(h5->rx_skb, 4); ++ * memcpy(skb_push(h5->rx_skb, 1), &desc, 1); ++ ++ * hdr.evt = 0xff; ++ * hdr.plen = h5->rx_skb->len; ++ * memcpy(skb_push(h5->rx_skb, HCI_EVENT_HDR_SIZE), ++ * &hdr, HCI_EVENT_HDR_SIZE); ++ * bt_cb(h5->rx_skb)->pkt_type = HCI_EVENT_PKT; ++ ++ * hci_recv_frame(h5->rx_skb); ++ * } else { */ ++ BT_ERR("Packet for unknown channel (%u %s)", ++ h5->rx_skb->data[1] & 0x0f, ++ h5->rx_skb->data[0] & 0x80 ? ++ "reliable" : "unreliable"); ++ kfree_skb(h5->rx_skb); ++ /* } */ ++ } else ++ kfree_skb(h5->rx_skb); ++ } else { ++ /* Pull out H5 hdr */ ++ skb_pull(h5->rx_skb, 4); ++ ++#ifdef BTCOEX ++ if (bt_cb(h5->rx_skb)->pkt_type == HCI_EVENT_PKT) ++ rtk_btcoex_parse_event(h5->rx_skb->data, ++ h5->rx_skb->len); ++ ++ if (bt_cb(h5->rx_skb)->pkt_type == HCI_ACLDATA_PKT) ++ rtk_btcoex_parse_l2cap_data_rx(h5->rx_skb->data, ++ h5->rx_skb->len); ++#endif ++ ++#if HCI_VERSION_CODE < KERNEL_VERSION(3, 13, 0) ++ hci_recv_frame(h5->rx_skb); ++#else ++ hci_recv_frame(hu->hdev, h5->rx_skb); ++#endif ++ } ++ ++ h5->rx_state = H5_W4_PKT_DELIMITER; ++ h5->rx_skb = NULL; ++} ++ ++static u16 bscp_get_crc(struct h5_struct *h5) { ++ return get_unaligned_be16(&h5->rx_skb-> ++ data[h5->rx_skb->len - 2]); ++} ++ ++/* Recv data */ ++static int h5_recv(struct hci_uart *hu, void *data, int count) ++{ ++ struct h5_struct *h5 = hu->priv; ++ register unsigned char *ptr; ++ ++ BT_DBG("hu %p count %d rx_state %d rx_count %ld", ++ hu, count, h5->rx_state, h5->rx_count); ++ ++ ptr = data; ++ while (count) { ++ if (h5->rx_count) { ++ if (*ptr == 0xc0) { ++ BT_ERR("Short H5 packet"); ++ kfree_skb(h5->rx_skb); ++ h5->rx_state = H5_W4_PKT_START; ++ h5->rx_count = 0; ++ } else ++ h5_unslip_one_byte(h5, *ptr); ++ ++ ptr++; ++ count--; ++ continue; ++ } ++ ++ switch (h5->rx_state) { ++ case H5_W4_HDR: ++ if ((0xff & (u8) ~ ++ (h5->rx_skb->data[0] + ++ h5->rx_skb->data[1] + ++ h5->rx_skb->data[2])) != h5->rx_skb->data[3]) { ++ BT_ERR("Error in H5 hdr checksum"); ++ kfree_skb(h5->rx_skb); ++ h5->rx_state = H5_W4_PKT_DELIMITER; ++ h5->rx_count = 0; ++ continue; ++ } ++ if (h5->rx_skb->data[0] & 0x80 /* reliable pkt */ ++ && (h5->rx_skb->data[0] & 0x07) != h5->rxseq_txack) { ++ BT_ERR ++ ("Out-of-order packet arrived, got %u expected %u", ++ h5->rx_skb->data[0] & 0x07, ++ h5->rxseq_txack); ++ ++ h5->txack_req = 1; ++ hci_uart_tx_wakeup(hu); ++ kfree_skb(h5->rx_skb); ++ h5->rx_state = H5_W4_PKT_DELIMITER; ++ h5->rx_count = 0; ++ continue; ++ } ++ h5->rx_state = H5_W4_DATA; ++ h5->rx_count = (h5->rx_skb->data[1] >> 4) + (h5->rx_skb->data[2] << 4); /* May be 0 */ ++ continue; ++ ++ case H5_W4_DATA: ++ if (h5->rx_skb->data[0] & 0x40) { /* pkt with crc */ ++ h5->rx_state = H5_W4_CRC; ++ h5->rx_count = 2; ++ } else ++ h5_complete_rx_pkt(hu); ++ continue; ++ ++ case H5_W4_CRC: ++ if (bitrev16(h5->message_crc) != bscp_get_crc(h5)) { ++ BT_ERR ++ ("Checksum failed: computed %04x received %04x", ++ bitrev16(h5->message_crc), ++ bscp_get_crc(h5)); ++ ++ kfree_skb(h5->rx_skb); ++ h5->rx_state = H5_W4_PKT_DELIMITER; ++ h5->rx_count = 0; ++ continue; ++ } ++ skb_trim(h5->rx_skb, h5->rx_skb->len - 2); ++ h5_complete_rx_pkt(hu); ++ continue; ++ ++ case H5_W4_PKT_DELIMITER: ++ switch (*ptr) { ++ case 0xc0: ++ h5->rx_state = H5_W4_PKT_START; ++ break; ++ default: ++ /*BT_ERR("Ignoring byte %02x", *ptr); */ ++ break; ++ } ++ ptr++; ++ count--; ++ break; ++ ++ case H5_W4_PKT_START: ++ switch (*ptr) { ++ case 0xc0: ++ ptr++; ++ count--; ++ break; ++ ++ default: ++ h5->rx_state = H5_W4_HDR; ++ h5->rx_count = 4; ++ h5->rx_esc_state = H5_ESCSTATE_NOESC; ++ H5_CRC_INIT(h5->message_crc); ++ ++ /* Do not increment ptr or decrement count ++ * Allocate packet. Max len of a H5 pkt= ++ * 0xFFF (payload) +4 (header) +2 (crc) */ ++ ++ h5->rx_skb = bt_skb_alloc(0x1005, GFP_ATOMIC); ++ if (!h5->rx_skb) { ++ BT_ERR ++ ("Can't allocate mem for new packet"); ++ h5->rx_state = H5_W4_PKT_DELIMITER; ++ h5->rx_count = 0; ++ return 0; ++ } ++ h5->rx_skb->dev = (void *)hu->hdev; ++ break; ++ } ++ break; ++ } ++ } ++ return count; ++} ++ ++/* Arrange to retransmit all messages in the relq. */ ++static void h5_timed_event(unsigned long arg) ++{ ++ struct hci_uart *hu = (struct hci_uart *)arg; ++ struct h5_struct *h5 = hu->priv; ++ struct sk_buff *skb; ++ unsigned long flags; ++ ++ BT_DBG("hu %p retransmitting %u pkts", hu, h5->unack.qlen); ++ ++ spin_lock_irqsave_nested(&h5->unack.lock, flags, SINGLE_DEPTH_NESTING); ++ ++ while ((skb = __skb_dequeue_tail(&h5->unack)) != NULL) { ++ h5->msgq_txseq = (h5->msgq_txseq - 1) & 0x07; ++ skb_queue_head(&h5->rel, skb); ++ } ++ ++ spin_unlock_irqrestore(&h5->unack.lock, flags); ++ ++ hci_uart_tx_wakeup(hu); ++} ++ ++static int h5_open(struct hci_uart *hu) ++{ ++ struct h5_struct *h5; ++ ++ BT_DBG("hu %p", hu); ++ ++ BT_INFO("h5_open"); ++ h5 = kzalloc(sizeof(*h5), GFP_ATOMIC); ++ if (!h5) ++ return -ENOMEM; ++ ++ hu->priv = h5; ++ skb_queue_head_init(&h5->unack); ++ skb_queue_head_init(&h5->rel); ++ skb_queue_head_init(&h5->unrel); ++ ++ init_timer(&h5->th5); ++ h5->th5.function = h5_timed_event; ++ h5->th5.data = (u_long) hu; ++ ++ h5->rx_state = H5_W4_PKT_DELIMITER; ++ ++ if (txcrc) ++ h5->use_crc = 1; ++ ++ return 0; ++} ++ ++static int h5_close(struct hci_uart *hu) ++{ ++ struct h5_struct *h5 = hu->priv; ++ ++ BT_INFO("h5_close"); ++ ++ del_timer_sync(&h5->th5); ++ ++ hu->priv = NULL; ++ ++ skb_queue_purge(&h5->unack); ++ skb_queue_purge(&h5->rel); ++ skb_queue_purge(&h5->unrel); ++ ++ kfree(h5); ++ ++ return 0; ++} ++ ++static struct hci_uart_proto h5 = { ++ .id = HCI_UART_3WIRE, ++ .open = h5_open, ++ .close = h5_close, ++ .enqueue = h5_enqueue, ++ .dequeue = h5_dequeue, ++ .recv = h5_recv, ++ .flush = h5_flush ++}; ++ ++int h5_init(void) ++{ ++ int err = hci_uart_register_proto(&h5); ++ ++ if (!err) ++ BT_INFO("HCI Realtek H5 protocol initialized"); ++ else ++ BT_ERR("HCI Realtek H5 protocol registration failed"); ++ ++ return err; ++} ++ ++int h5_deinit(void) ++{ ++ return hci_uart_unregister_proto(&h5); ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_bluetooth_hci_uart.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_bluetooth_hci_uart.h.patch new file mode 100644 index 00000000..6ac4667e --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_bluetooth_hci_uart.h.patch @@ -0,0 +1,42 @@ +diff -drupN a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h +--- a/drivers/bluetooth/hci_uart.h 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/bluetooth/hci_uart.h 2022-06-09 05:02:28.000000000 +0300 +@@ -23,6 +23,12 @@ + * + */ + ++#ifdef CONFIG_BT_HCIUART_RTKH5 ++#define BTCOEX ++#define HCI_VERSION_CODE LINUX_VERSION_CODE ++#endif ++ ++ + #ifndef N_HCI + #define N_HCI 15 + #endif +@@ -92,7 +98,11 @@ struct hci_uart { + }; + + /* HCI_UART proto flag bits */ +-#define HCI_UART_PROTO_SET 0 ++#ifdef CONFIG_BT_HCIUART_RTKH5 ++#define HCI_UART_PROTO_SET 2 ++#else ++#define HCI_UART_PROTO_SET 0 ++#endif + #define HCI_UART_REGISTERED 1 + + /* TX states */ +@@ -158,6 +168,12 @@ int ll_init(void); + int ll_deinit(void); + #endif + ++#ifdef CONFIG_BT_HCIUART_RTKH5 ++int h5_init(void); ++int h5_deinit(void); ++#endif ++ ++ + #ifdef CONFIG_BT_HCIUART_ATH3K + int ath_init(void); + int ath_deinit(void); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_bluetooth_rtk_coex.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_bluetooth_rtk_coex.c.patch new file mode 100644 index 00000000..ae961fa3 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_bluetooth_rtk_coex.c.patch @@ -0,0 +1,2630 @@ +diff -drupN a/drivers/bluetooth/rtk_coex.c b/drivers/bluetooth/rtk_coex.c +--- a/drivers/bluetooth/rtk_coex.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/bluetooth/rtk_coex.c 2022-06-09 05:02:28.000000000 +0300 +@@ -0,0 +1,2626 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "rtk_coex.h" ++ ++#if BTRTL_HCI_IF == BTRTL_HCIUSB ++#include ++#include "rtk_bt.h" ++#undef RTKBT_DBG ++#undef RTKBT_INFO ++#undef RTKBT_WARN ++#undef RTKBT_ERR ++ ++#elif BTRTL_HCI_IF == BTRTL_HCIUART ++/* #define HCI_VERSION_CODE KERNEL_VERSION(3, 14, 41) */ ++#define HCI_VERSION_CODE LINUX_VERSION_CODE ++ ++#else ++#error "Please set type of HCI interface" ++#endif ++ ++#define RTK_VERSION "1.2" ++ ++#define RTKBT_DBG(fmt, arg...) printk(KERN_INFO "rtk_btcoex: " fmt "\n" , ## arg) ++#define RTKBT_INFO(fmt, arg...) printk(KERN_INFO "rtk_btcoex: " fmt "\n" , ## arg) ++#define RTKBT_WARN(fmt, arg...) printk(KERN_WARNING "rtk_btcoex: " fmt "\n", ## arg) ++#define RTKBT_ERR(fmt, arg...) printk(KERN_WARNING "rtk_btcoex: " fmt "\n", ## arg) ++ ++static struct rtl_coex_struct btrtl_coex; ++ ++#define is_profile_connected(profile) ((btrtl_coex.profile_bitmap & BIT(profile)) > 0) ++#define is_profile_busy(profile) ((btrtl_coex.profile_status & BIT(profile)) > 0) ++ ++static void rtk_handle_event_from_wifi(uint8_t * msg); ++static void count_a2dp_packet_timeout(unsigned long data); ++static void count_pan_packet_timeout(unsigned long data); ++static void count_hogp_packet_timeout(unsigned long data); ++ ++static int rtl_alloc_buff(struct rtl_coex_struct *coex) ++{ ++ struct rtl_hci_ev *ev; ++ struct rtl_l2_buff *l2; ++ int i; ++ int order; ++ unsigned long addr; ++ unsigned long addr2; ++ int ev_size; ++ int l2_size; ++ int n; ++ ++ spin_lock_init(&coex->buff_lock); ++ ++ INIT_LIST_HEAD(&coex->ev_used_list); ++ INIT_LIST_HEAD(&coex->ev_free_list); ++ ++ INIT_LIST_HEAD(&coex->l2_used_list); ++ INIT_LIST_HEAD(&coex->l2_free_list); ++ ++ n = NUM_RTL_HCI_EV * sizeof(struct rtl_hci_ev); ++ ev_size = ALIGN(n, sizeof(unsigned long)); ++ ++ n = L2_MAX_PKTS * sizeof(struct rtl_l2_buff); ++ l2_size = ALIGN(n, sizeof(unsigned long)); ++ ++ RTKBT_DBG("alloc buffers %d, %d for ev and l2", ev_size, l2_size); ++ ++ order = get_order(ev_size + l2_size); ++ addr = __get_free_pages(GFP_KERNEL, order); ++ if (!addr) { ++ RTKBT_ERR("failed to alloc buffers for ev and l2."); ++ return -ENOMEM; ++ } ++ memset((void *)addr, 0, ev_size + l2_size); ++ ++ coex->pages_addr = addr; ++ coex->buff_size = ev_size + l2_size; ++ ++ ev = (struct rtl_hci_ev *)addr; ++ for (i = 0; i < NUM_RTL_HCI_EV; i++) { ++ list_add_tail(&ev->list, &coex->ev_free_list); ++ ev++; ++ } ++ ++ addr2 = addr + ev_size; ++ l2 = (struct rtl_l2_buff *)addr2; ++ for (i = 0; i < L2_MAX_PKTS; i++) { ++ list_add_tail(&l2->list, &coex->l2_free_list); ++ l2++; ++ } ++ ++ return 0; ++} ++ ++static void rtl_free_buff(struct rtl_coex_struct *coex) ++{ ++ struct rtl_hci_ev *ev; ++ struct rtl_l2_buff *l2; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&coex->buff_lock, flags); ++ ++ while (!list_empty(&coex->ev_used_list)) { ++ ev = list_entry(coex->ev_used_list.next, struct rtl_hci_ev, ++ list); ++ list_del(&ev->list); ++ } ++ ++ while (!list_empty(&coex->ev_free_list)) { ++ ev = list_entry(coex->ev_free_list.next, struct rtl_hci_ev, ++ list); ++ list_del(&ev->list); ++ } ++ ++ while (!list_empty(&coex->l2_used_list)) { ++ l2 = list_entry(coex->l2_used_list.next, struct rtl_l2_buff, ++ list); ++ list_del(&l2->list); ++ } ++ ++ while (!list_empty(&coex->l2_free_list)) { ++ l2 = list_entry(coex->l2_free_list.next, struct rtl_l2_buff, ++ list); ++ list_del(&l2->list); ++ } ++ ++ spin_unlock_irqrestore(&coex->buff_lock, flags); ++ ++ if (coex->buff_size > 0) { ++ free_pages(coex->pages_addr, get_order(coex->buff_size)); ++ coex->pages_addr = 0; ++ coex->buff_size = 0; ++ } ++} ++ ++static struct rtl_hci_ev *rtl_ev_node_get(struct rtl_coex_struct *coex) ++{ ++ struct rtl_hci_ev *ev; ++ unsigned long flags; ++ ++ if (!coex->buff_size) ++ return NULL; ++ ++ spin_lock_irqsave(&coex->buff_lock, flags); ++ if (!list_empty(&coex->ev_free_list)) { ++ ev = list_entry(coex->ev_free_list.next, struct rtl_hci_ev, ++ list); ++ list_del(&ev->list); ++ } else ++ ev = NULL; ++ spin_unlock_irqrestore(&coex->buff_lock, flags); ++ return ev; ++} ++ ++static int rtl_ev_node_to_used(struct rtl_coex_struct *coex, ++ struct rtl_hci_ev *ev) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&coex->buff_lock, flags); ++ list_add_tail(&ev->list, &coex->ev_used_list); ++ spin_unlock_irqrestore(&coex->buff_lock, flags); ++ ++ return 0; ++} ++ ++static struct rtl_l2_buff *rtl_l2_node_get(struct rtl_coex_struct *coex) ++{ ++ struct rtl_l2_buff *l2; ++ unsigned long flags; ++ ++ if (!coex->buff_size) ++ return NULL; ++ ++ spin_lock_irqsave(&coex->buff_lock, flags); ++ ++ if(!list_empty(&coex->l2_free_list)) { ++ l2 = list_entry(coex->l2_free_list.next, struct rtl_l2_buff, ++ list); ++ list_del(&l2->list); ++ } else ++ l2 = NULL; ++ ++ spin_unlock_irqrestore(&coex->buff_lock, flags); ++ return l2; ++} ++ ++static int rtl_l2_node_to_used(struct rtl_coex_struct *coex, ++ struct rtl_l2_buff *l2) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&coex->buff_lock, flags); ++ list_add_tail(&l2->list, &coex->l2_used_list); ++ spin_unlock_irqrestore(&coex->buff_lock, flags); ++ ++ return 0; ++} ++ ++static int8_t psm_to_profile_index(uint16_t psm) ++{ ++ switch (psm) { ++ case PSM_AVCTP: ++ case PSM_SDP: ++ return -1; //ignore ++ ++ case PSM_HID: ++ case PSM_HID_INT: ++ return profile_hid; ++ ++ case PSM_AVDTP: ++ return profile_a2dp; ++ ++ case PSM_PAN: ++ case PSM_OPP: ++ case PSM_FTP: ++ case PSM_BIP: ++ case PSM_RFCOMM: ++ return profile_pan; ++ ++ default: ++ return profile_pan; ++ } ++} ++ ++static rtk_conn_prof *find_connection_by_handle(struct rtl_coex_struct * coex, ++ uint16_t handle) ++{ ++ struct list_head *head = &coex->conn_hash; ++ struct list_head *iter = NULL, *temp = NULL; ++ rtk_conn_prof *desc = NULL; ++ ++ list_for_each_safe(iter, temp, head) { ++ desc = list_entry(iter, rtk_conn_prof, list); ++ if ((handle & 0xEFF) == desc->handle) { ++ return desc; ++ } ++ } ++ return NULL; ++} ++ ++static rtk_conn_prof *allocate_connection_by_handle(uint16_t handle) ++{ ++ rtk_conn_prof *phci_conn = NULL; ++ phci_conn = kmalloc(sizeof(rtk_conn_prof), GFP_ATOMIC); ++ if (phci_conn) ++ phci_conn->handle = handle; ++ ++ return phci_conn; ++} ++ ++static void init_connection_hash(struct rtl_coex_struct * coex) ++{ ++ struct list_head *head = &coex->conn_hash; ++ INIT_LIST_HEAD(head); ++} ++ ++static void add_connection_to_hash(struct rtl_coex_struct * coex, ++ rtk_conn_prof * desc) ++{ ++ struct list_head *head = &coex->conn_hash; ++ list_add_tail(&desc->list, head); ++} ++ ++static void delete_connection_from_hash(rtk_conn_prof * desc) ++{ ++ if (desc) { ++ list_del(&desc->list); ++ kfree(desc); ++ } ++} ++ ++static void flush_connection_hash(struct rtl_coex_struct * coex) ++{ ++ struct list_head *head = &coex->conn_hash; ++ struct list_head *iter = NULL, *temp = NULL; ++ rtk_conn_prof *desc = NULL; ++ ++ list_for_each_safe(iter, temp, head) { ++ desc = list_entry(iter, rtk_conn_prof, list); ++ if (desc) { ++ list_del(&desc->list); ++ kfree(desc); ++ } ++ } ++ //INIT_LIST_HEAD(head); ++} ++ ++static void init_profile_hash(struct rtl_coex_struct * coex) ++{ ++ struct list_head *head = &coex->profile_list; ++ INIT_LIST_HEAD(head); ++} ++ ++static uint8_t list_allocate_add(uint16_t handle, uint16_t psm, ++ int8_t profile_index, uint16_t dcid, ++ uint16_t scid) ++{ ++ rtk_prof_info *pprof_info = NULL; ++ ++ if (profile_index < 0) { ++ RTKBT_ERR("PSM(0x%x) do not need parse", psm); ++ return FALSE; ++ } ++ ++ pprof_info = kmalloc(sizeof(rtk_prof_info), GFP_ATOMIC); ++ ++ if (NULL == pprof_info) { ++ RTKBT_ERR("list_allocate_add: allocate error"); ++ return FALSE; ++ } ++ ++ pprof_info->handle = handle; ++ pprof_info->psm = psm; ++ pprof_info->scid = scid; ++ pprof_info->dcid = dcid; ++ pprof_info->profile_index = profile_index; ++ list_add_tail(&(pprof_info->list), &(btrtl_coex.profile_list)); ++ ++ return TRUE; ++} ++ ++static void delete_profile_from_hash(rtk_prof_info * desc) ++{ ++ RTKBT_DBG("Delete profile: hndl 0x%04x, psm 0x%04x, dcid 0x%04x, " ++ "scid 0x%04x", desc->handle, desc->psm, desc->dcid, ++ desc->scid); ++ if (desc) { ++ list_del(&desc->list); ++ kfree(desc); ++ desc = NULL; ++ } ++} ++ ++static void flush_profile_hash(struct rtl_coex_struct * coex) ++{ ++ struct list_head *head = &coex->profile_list; ++ struct list_head *iter = NULL, *temp = NULL; ++ rtk_prof_info *desc = NULL; ++ ++ spin_lock(&btrtl_coex.spin_lock_profile); ++ list_for_each_safe(iter, temp, head) { ++ desc = list_entry(iter, rtk_prof_info, list); ++ delete_profile_from_hash(desc); ++ } ++ //INIT_LIST_HEAD(head); ++ spin_unlock(&btrtl_coex.spin_lock_profile); ++} ++ ++static rtk_prof_info *find_profile_by_handle_scid(struct rtl_coex_struct * ++ coex, uint16_t handle, ++ uint16_t scid) ++{ ++ struct list_head *head = &coex->profile_list; ++ struct list_head *iter = NULL, *temp = NULL; ++ rtk_prof_info *desc = NULL; ++ ++ list_for_each_safe(iter, temp, head) { ++ desc = list_entry(iter, rtk_prof_info, list); ++ if (((handle & 0xFFF) == desc->handle) && (scid == desc->scid)) { ++ return desc; ++ } ++ } ++ return NULL; ++} ++ ++static rtk_prof_info *find_profile_by_handle_dcid(struct rtl_coex_struct * ++ coex, uint16_t handle, ++ uint16_t dcid) ++{ ++ struct list_head *head = &coex->profile_list; ++ struct list_head *iter = NULL, *temp = NULL; ++ rtk_prof_info *desc = NULL; ++ ++ list_for_each_safe(iter, temp, head) { ++ desc = list_entry(iter, rtk_prof_info, list); ++ if (((handle & 0xFFF) == desc->handle) && (dcid == desc->dcid)) { ++ return desc; ++ } ++ } ++ return NULL; ++} ++ ++static rtk_prof_info *find_profile_by_handle_dcid_scid(struct rtl_coex_struct ++ * coex, uint16_t handle, ++ uint16_t dcid, ++ uint16_t scid) ++{ ++ struct list_head *head = &coex->profile_list; ++ struct list_head *iter = NULL, *temp = NULL; ++ rtk_prof_info *desc = NULL; ++ ++ list_for_each_safe(iter, temp, head) { ++ desc = list_entry(iter, rtk_prof_info, list); ++ if (((handle & 0xFFF) == desc->handle) && (dcid == desc->dcid) ++ && (scid == desc->scid)) { ++ return desc; ++ } ++ } ++ return NULL; ++} ++ ++static void rtk_vendor_cmd_to_fw(uint16_t opcode, uint8_t parameter_len, ++ uint8_t * parameter) ++{ ++ int len = HCI_CMD_PREAMBLE_SIZE + parameter_len; ++ uint8_t *p; ++ struct sk_buff *skb; ++ struct hci_dev *hdev = btrtl_coex.hdev; ++ ++ skb = bt_skb_alloc(len, GFP_ATOMIC); ++ if (!skb) { ++ RTKBT_DBG("there is no room for cmd 0x%x", opcode); ++ return; ++ } ++ ++ p = (uint8_t *) skb_put(skb, HCI_CMD_PREAMBLE_SIZE); ++ UINT16_TO_STREAM(p, opcode); ++ *p++ = parameter_len; ++ ++ if (parameter_len) ++ memcpy(skb_put(skb, parameter_len), parameter, parameter_len); ++ ++ bt_cb(skb)->pkt_type = HCI_COMMAND_PKT; ++ ++#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 18, 0) ++#if HCI_VERSION_CODE < KERNEL_VERSION(4, 4, 0) ++ bt_cb(skb)->opcode = opcode; ++#else ++ bt_cb(skb)->hci.opcode = opcode; ++#endif ++#endif ++ ++ /* Stand-alone HCI commands must be flagged as ++ * single-command requests. ++ */ ++#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) ++#if HCI_VERSION_CODE < KERNEL_VERSION(4, 4, 0) ++ bt_cb(skb)->req.start = true; ++#else ++ ++#if HCI_VERSION_CODE < KERNEL_VERSION(4, 5, 0) ++ bt_cb(skb)->hci.req_start = true; ++#else ++ ++ bt_cb(skb)->hci.req_flags |= HCI_REQ_START; ++#endif ++ ++#endif /* 4.4.0 */ ++#endif /* 3.10.0 */ ++ RTKBT_DBG("%s: opcode 0x%x", __func__, opcode); ++ ++ /* It is harmless if set skb->dev twice. The dev will be used in ++ * btusb_send_frame() after or equal to kernel/hci 3.13.0, ++ * the hdev will not come from skb->dev. */ ++#if HCI_VERSION_CODE < KERNEL_VERSION(3, 13, 0) ++ skb->dev = (void *)btrtl_coex.hdev; ++#endif ++ /* Put the skb to the global hdev->cmd_q */ ++ skb_queue_tail(&hdev->cmd_q, skb); ++ ++#if HCI_VERSION_CODE < KERNEL_VERSION(3, 3, 0) ++ tasklet_schedule(&hdev->cmd_task); ++#else ++ queue_work(hdev->workqueue, &hdev->cmd_work); ++#endif ++ ++ return; ++} ++ ++static void rtk_notify_profileinfo_to_fw(void) ++{ ++ struct list_head *head = NULL; ++ struct list_head *iter = NULL; ++ struct list_head *temp = NULL; ++ rtk_conn_prof *hci_conn = NULL; ++ uint8_t handle_number = 0; ++ uint32_t buffer_size = 0; ++ uint8_t *p_buf = NULL; ++ uint8_t *p = NULL; ++ ++ head = &btrtl_coex.conn_hash; ++ list_for_each_safe(iter, temp, head) { ++ hci_conn = list_entry(iter, rtk_conn_prof, list); ++ if (hci_conn && hci_conn->profile_bitmap) ++ handle_number++; ++ } ++ ++ buffer_size = 1 + handle_number * 3 + 1; ++ ++ p_buf = kmalloc(buffer_size, GFP_ATOMIC); ++ ++ if (NULL == p_buf) { ++ RTKBT_ERR("%s: alloc error", __func__); ++ return; ++ } ++ p = p_buf; ++ ++ RTKBT_DBG("%s: BufferSize %u", __func__, buffer_size); ++ *p++ = handle_number; ++ RTKBT_DBG("%s: NumberOfHandles %u", __func__, handle_number); ++ head = &btrtl_coex.conn_hash; ++ list_for_each(iter, head) { ++ hci_conn = list_entry(iter, rtk_conn_prof, list); ++ if (hci_conn && hci_conn->profile_bitmap) { ++ UINT16_TO_STREAM(p, hci_conn->handle); ++ RTKBT_DBG("%s: handle 0x%04x", __func__, ++ hci_conn->handle); ++ *p++ = hci_conn->profile_bitmap; ++ RTKBT_DBG("%s: profile_bitmap 0x%02x", __func__, ++ hci_conn->profile_bitmap); ++ handle_number--; ++ } ++ if (0 == handle_number) ++ break; ++ } ++ ++ *p++ = btrtl_coex.profile_status; ++ RTKBT_DBG("%s: profile_status 0x%02x", __func__, ++ btrtl_coex.profile_status); ++ ++ rtk_vendor_cmd_to_fw(HCI_VENDOR_SET_PROFILE_REPORT_COMMAND, buffer_size, ++ p_buf); ++ ++ kfree(p_buf); ++ return; ++} ++ ++static void rtk_check_setup_timer(int8_t profile_index) ++{ ++ if (profile_index == profile_a2dp) { ++ btrtl_coex.a2dp_packet_count = 0; ++ setup_timer(&(btrtl_coex.a2dp_count_timer), ++ count_a2dp_packet_timeout, 0); ++ btrtl_coex.a2dp_count_timer.expires = ++ jiffies + msecs_to_jiffies(1000); ++ add_timer(&(btrtl_coex.a2dp_count_timer)); ++ } ++ ++ if (profile_index == profile_pan) { ++ btrtl_coex.pan_packet_count = 0; ++ setup_timer(&(btrtl_coex.pan_count_timer), ++ count_pan_packet_timeout, 0); ++ btrtl_coex.pan_count_timer.expires = ++ jiffies + msecs_to_jiffies(1000); ++ add_timer(&(btrtl_coex.pan_count_timer)); ++ } ++ ++ /* hogp & voice share one timer now */ ++ if ((profile_index == profile_hogp) || (profile_index == profile_voice)) { ++ if ((0 == btrtl_coex.profile_refcount[profile_hogp]) ++ && (0 == btrtl_coex.profile_refcount[profile_voice])) { ++ btrtl_coex.hogp_packet_count = 0; ++ btrtl_coex.voice_packet_count = 0; ++ setup_timer(&(btrtl_coex.hogp_count_timer), ++ count_hogp_packet_timeout, 0); ++ btrtl_coex.hogp_count_timer.expires = ++ jiffies + msecs_to_jiffies(1000); ++ add_timer(&(btrtl_coex.hogp_count_timer)); ++ } ++ } ++} ++ ++static void rtk_check_del_timer(int8_t profile_index) ++{ ++ if (profile_a2dp == profile_index) { ++ btrtl_coex.a2dp_packet_count = 0; ++ del_timer(&(btrtl_coex.a2dp_count_timer)); ++ } ++ if (profile_pan == profile_index) { ++ btrtl_coex.pan_packet_count = 0; ++ del_timer(&(btrtl_coex.pan_count_timer)); ++ } ++ if (profile_hogp == profile_index) { ++ btrtl_coex.hogp_packet_count = 0; ++ if (btrtl_coex.profile_refcount[profile_voice] == 0) { ++ del_timer(&(btrtl_coex.hogp_count_timer)); ++ } ++ } ++ if (profile_voice == profile_index) { ++ btrtl_coex.voice_packet_count = 0; ++ if (btrtl_coex.profile_refcount[profile_hogp] == 0) { ++ del_timer(&(btrtl_coex.hogp_count_timer)); ++ } ++ } ++} ++ ++static void update_profile_state(uint8_t profile_index, uint8_t is_busy) ++{ ++ uint8_t need_update = FALSE; ++ ++ if ((btrtl_coex.profile_bitmap & BIT(profile_index)) == 0) { ++ RTKBT_ERR("%s: : ERROR!!! profile(Index: %x) does not exist", ++ __func__, profile_index); ++ return; ++ } ++ ++ if (is_busy) { ++ if ((btrtl_coex.profile_status & BIT(profile_index)) == 0) { ++ need_update = TRUE; ++ btrtl_coex.profile_status |= BIT(profile_index); ++ } ++ } else { ++ if ((btrtl_coex.profile_status & BIT(profile_index)) > 0) { ++ need_update = TRUE; ++ btrtl_coex.profile_status &= ~(BIT(profile_index)); ++ } ++ } ++ ++ if (need_update) { ++ RTKBT_DBG("%s: btrtl_coex.profie_bitmap = %x", ++ __func__, btrtl_coex.profile_bitmap); ++ RTKBT_DBG("%s: btrtl_coex.profile_status = %x", ++ __func__, btrtl_coex.profile_status); ++ rtk_notify_profileinfo_to_fw(); ++ } ++} ++ ++static void update_profile_connection(rtk_conn_prof * phci_conn, ++ int8_t profile_index, uint8_t is_add) ++{ ++ uint8_t need_update = FALSE; ++ uint8_t kk; ++ ++ RTKBT_DBG("%s: is_add %d, profile_index %x", __func__, ++ is_add, profile_index); ++ if (profile_index < 0) ++ return; ++ ++ if (is_add) { ++ if (btrtl_coex.profile_refcount[profile_index] == 0) { ++ need_update = TRUE; ++ btrtl_coex.profile_bitmap |= BIT(profile_index); ++ ++ /* SCO is always busy */ ++ if (profile_index == profile_sco) ++ btrtl_coex.profile_status |= ++ BIT(profile_index); ++ ++ rtk_check_setup_timer(profile_index); ++ } ++ btrtl_coex.profile_refcount[profile_index]++; ++ ++ if (0 == phci_conn->profile_refcount[profile_index]) { ++ need_update = TRUE; ++ phci_conn->profile_bitmap |= BIT(profile_index); ++ } ++ phci_conn->profile_refcount[profile_index]++; ++ } else { ++ btrtl_coex.profile_refcount[profile_index]--; ++ RTKBT_DBG("%s: btrtl_coex.profile_refcount[%x] = %x", ++ __func__, profile_index, ++ btrtl_coex.profile_refcount[profile_index]); ++ if (btrtl_coex.profile_refcount[profile_index] == 0) { ++ need_update = TRUE; ++ btrtl_coex.profile_bitmap &= ~(BIT(profile_index)); ++ ++ /* if profile does not exist, status is meaningless */ ++ btrtl_coex.profile_status &= ~(BIT(profile_index)); ++ rtk_check_del_timer(profile_index); ++ } ++ ++ phci_conn->profile_refcount[profile_index]--; ++ if (0 == phci_conn->profile_refcount[profile_index]) { ++ need_update = TRUE; ++ phci_conn->profile_bitmap &= ~(BIT(profile_index)); ++ ++ /* clear profile_hid_interval if need */ ++ if ((profile_hid == profile_index) ++ && (phci_conn-> ++ profile_bitmap & (BIT(profile_hid_interval)))) { ++ phci_conn->profile_bitmap &= ++ ~(BIT(profile_hid_interval)); ++ btrtl_coex. ++ profile_refcount[profile_hid_interval]--; ++ } ++ } ++ } ++ ++ RTKBT_DBG("%s: btrtl_coex.profile_bitmap 0x%02x", __func__, ++ btrtl_coex.profile_bitmap); ++ for (kk = 0; kk < 8; kk++) ++ RTKBT_DBG("%s: btrtl_coex.profile_refcount[%d] = %d", ++ __func__, kk, ++ btrtl_coex.profile_refcount[kk]); ++ ++ if (need_update) ++ rtk_notify_profileinfo_to_fw(); ++} ++ ++static void update_hid_active_state(uint16_t handle, uint16_t interval) ++{ ++ uint8_t need_update = 0; ++ rtk_conn_prof *phci_conn = ++ find_connection_by_handle(&btrtl_coex, handle); ++ ++ if (phci_conn == NULL) ++ return; ++ ++ RTKBT_DBG("%s: handle 0x%04x, interval %u", __func__, handle, interval); ++ if (((phci_conn->profile_bitmap) & (BIT(profile_hid))) == 0) { ++ RTKBT_DBG("HID not connected, nothing to be down"); ++ return; ++ } ++ ++ if (interval < 60) { ++ if ((phci_conn->profile_bitmap & (BIT(profile_hid_interval))) == ++ 0) { ++ need_update = 1; ++ phci_conn->profile_bitmap |= BIT(profile_hid_interval); ++ ++ btrtl_coex.profile_refcount[profile_hid_interval]++; ++ if (btrtl_coex. ++ profile_refcount[profile_hid_interval] == 1) ++ btrtl_coex.profile_status |= ++ BIT(profile_hid); ++ } ++ } else { ++ if ((phci_conn->profile_bitmap & (BIT(profile_hid_interval)))) { ++ need_update = 1; ++ phci_conn->profile_bitmap &= ++ ~(BIT(profile_hid_interval)); ++ ++ btrtl_coex.profile_refcount[profile_hid_interval]--; ++ if (btrtl_coex. ++ profile_refcount[profile_hid_interval] == 0) ++ btrtl_coex.profile_status &= ++ ~(BIT(profile_hid)); ++ } ++ } ++ ++ if (need_update) ++ rtk_notify_profileinfo_to_fw(); ++} ++ ++static uint8_t handle_l2cap_con_req(uint16_t handle, uint16_t psm, ++ uint16_t scid, uint8_t direction) ++{ ++ uint8_t status = FALSE; ++ rtk_prof_info *prof_info = NULL; ++ int8_t profile_index = psm_to_profile_index(psm); ++ ++ if (profile_index < 0) { ++ RTKBT_DBG("PSM(0x%04x) do not need parse", psm); ++ return status; ++ } ++ ++ spin_lock(&btrtl_coex.spin_lock_profile); ++ if (direction) //1: out ++ prof_info = ++ find_profile_by_handle_scid(&btrtl_coex, handle, scid); ++ else // 0:in ++ prof_info = ++ find_profile_by_handle_dcid(&btrtl_coex, handle, scid); ++ ++ if (prof_info) { ++ RTKBT_DBG("%s: this profile is already exist!", __func__); ++ spin_unlock(&btrtl_coex.spin_lock_profile); ++ return status; ++ } ++ ++ if (direction) //1: out ++ status = list_allocate_add(handle, psm, profile_index, 0, scid); ++ else // 0:in ++ status = list_allocate_add(handle, psm, profile_index, scid, 0); ++ ++ spin_unlock(&btrtl_coex.spin_lock_profile); ++ ++ if (!status) ++ RTKBT_ERR("%s: list_allocate_add failed!", __func__); ++ ++ return status; ++} ++ ++static uint8_t handle_l2cap_con_rsp(uint16_t handle, uint16_t dcid, ++ uint16_t scid, uint8_t direction, ++ uint8_t result) ++{ ++ rtk_prof_info *prof_info = NULL; ++ rtk_conn_prof *phci_conn = NULL; ++ ++ spin_lock(&btrtl_coex.spin_lock_profile); ++ if (!direction) //0, in ++ prof_info = ++ find_profile_by_handle_scid(&btrtl_coex, handle, scid); ++ else //1, out ++ prof_info = ++ find_profile_by_handle_dcid(&btrtl_coex, handle, scid); ++ ++ if (!prof_info) { ++ //RTKBT_DBG("handle_l2cap_con_rsp: prof_info Not Find!!"); ++ spin_unlock(&btrtl_coex.spin_lock_profile); ++ return FALSE; ++ } ++ ++ if (!result) { //success ++ RTKBT_DBG("l2cap connection success, update connection"); ++ if (!direction) //0, in ++ prof_info->dcid = dcid; ++ else //1, out ++ prof_info->scid = dcid; ++ ++ phci_conn = find_connection_by_handle(&btrtl_coex, handle); ++ if (phci_conn) ++ update_profile_connection(phci_conn, ++ prof_info->profile_index, ++ TRUE); ++ } ++ ++ spin_unlock(&btrtl_coex.spin_lock_profile); ++ return TRUE; ++} ++ ++static uint8_t handle_l2cap_discon_req(uint16_t handle, uint16_t dcid, ++ uint16_t scid, uint8_t direction) ++{ ++ rtk_prof_info *prof_info = NULL; ++ rtk_conn_prof *phci_conn = NULL; ++ RTKBT_DBG("%s: handle 0x%04x, dcid 0x%04x, scid 0x%04x, dir %u", ++ __func__, handle, dcid, scid, direction); ++ ++ spin_lock(&btrtl_coex.spin_lock_profile); ++ if (!direction) //0: in ++ prof_info = ++ find_profile_by_handle_dcid_scid(&btrtl_coex, handle, ++ scid, dcid); ++ else //1: out ++ prof_info = ++ find_profile_by_handle_dcid_scid(&btrtl_coex, handle, ++ dcid, scid); ++ ++ if (!prof_info) { ++ //LogMsg("handle_l2cap_discon_req: prof_info Not Find!"); ++ spin_unlock(&btrtl_coex.spin_lock_profile); ++ return 0; ++ } ++ ++ phci_conn = find_connection_by_handle(&btrtl_coex, handle); ++ if (!phci_conn) { ++ spin_unlock(&btrtl_coex.spin_lock_profile); ++ return 0; ++ } ++ ++ update_profile_connection(phci_conn, prof_info->profile_index, FALSE); ++ delete_profile_from_hash(prof_info); ++ spin_unlock(&btrtl_coex.spin_lock_profile); ++ ++ return 1; ++} ++ ++static const char sample_freqs[4][8] = { ++ "16", "32", "44.1", "48" ++}; ++ ++static const uint8_t sbc_blocks[4] = { 4, 8, 12, 16 }; ++ ++static const char chan_modes[4][16] = { ++ "MONO", "DUAL_CHANNEL", "STEREO", "JOINT_STEREO" ++}; ++ ++static const char alloc_methods[2][12] = { ++ "LOUDNESS", "SNR" ++}; ++ ++static const uint8_t subbands[2] = { 4, 8 }; ++ ++void print_sbc_header(struct sbc_frame_hdr *hdr) ++{ ++ RTKBT_DBG("syncword: %02x", hdr->syncword); ++ RTKBT_DBG("freq %skHz", sample_freqs[hdr->sampling_frequency]); ++ RTKBT_DBG("blocks %u", sbc_blocks[hdr->blocks]); ++ RTKBT_DBG("channel mode %s", chan_modes[hdr->channel_mode]); ++ RTKBT_DBG("allocation method %s", ++ alloc_methods[hdr->allocation_method]); ++ RTKBT_DBG("subbands %u", subbands[hdr->subbands]); ++} ++ ++static void packets_count(uint16_t handle, uint16_t scid, uint16_t length, ++ uint8_t direction, u8 *user_data) ++{ ++ rtk_prof_info *prof_info = NULL; ++ ++ rtk_conn_prof *hci_conn = ++ find_connection_by_handle(&btrtl_coex, handle); ++ if (NULL == hci_conn) ++ return; ++ ++ if (0 == hci_conn->type) { ++ if (!direction) //0: in ++ prof_info = ++ find_profile_by_handle_scid(&btrtl_coex, handle, ++ scid); ++ else //1: out ++ prof_info = ++ find_profile_by_handle_dcid(&btrtl_coex, handle, ++ scid); ++ ++ if (!prof_info) { ++ //RTKBT_DBG("packets_count: prof_info Not Find!"); ++ return; ++ } ++ ++ if ((prof_info->profile_index == profile_a2dp) && (length > 100)) { //avdtp media data ++ if (!is_profile_busy(profile_a2dp)) { ++ struct sbc_frame_hdr *sbc_header; ++ struct rtp_header *rtph; ++ u8 bitpool; ++ update_profile_state(profile_a2dp, TRUE); ++ rtph = (struct rtp_header *)user_data; ++ ++ RTKBT_DBG("rtp: v %u, cc %u, pt %u", ++ rtph->v, rtph->cc, rtph->pt); ++ /* move forward */ ++ user_data += sizeof(struct rtp_header) + ++ rtph->cc * 4 + 1; ++ ++ /* point to the sbc frame header */ ++ sbc_header = (struct sbc_frame_hdr *)user_data; ++ bitpool = sbc_header->bitpool; ++ ++ print_sbc_header(sbc_header); ++ ++ RTKBT_DBG("bitpool %u", bitpool); ++ ++ rtk_vendor_cmd_to_fw(HCI_VENDOR_SET_BITPOOL, ++ 1, &bitpool); ++ } ++ btrtl_coex.a2dp_packet_count++; ++ } ++ ++ if (prof_info->profile_index == profile_pan) ++ btrtl_coex.pan_packet_count++; ++ } ++} ++ ++static void count_a2dp_packet_timeout(unsigned long data) ++{ ++ RTKBT_DBG("%s: a2dp_packet_count %d", __func__, ++ btrtl_coex.a2dp_packet_count); ++ if (btrtl_coex.a2dp_packet_count == 0) { ++ if (is_profile_busy(profile_a2dp)) { ++ RTKBT_DBG("%s: a2dp busy->idle!", __func__); ++ update_profile_state(profile_a2dp, FALSE); ++ } ++ } ++ btrtl_coex.a2dp_packet_count = 0; ++ mod_timer(&(btrtl_coex.a2dp_count_timer), ++ jiffies + msecs_to_jiffies(1000)); ++} ++ ++static void count_pan_packet_timeout(unsigned long data) ++{ ++ RTKBT_DBG("%s: pan_packet_count %d", __func__, ++ btrtl_coex.pan_packet_count); ++ if (btrtl_coex.pan_packet_count < PAN_PACKET_COUNT) { ++ if (is_profile_busy(profile_pan)) { ++ RTKBT_DBG("%s: pan busy->idle!", __func__); ++ update_profile_state(profile_pan, FALSE); ++ } ++ } else { ++ if (!is_profile_busy(profile_pan)) { ++ RTKBT_DBG("timeout_handler: pan idle->busy!"); ++ update_profile_state(profile_pan, TRUE); ++ } ++ } ++ btrtl_coex.pan_packet_count = 0; ++ mod_timer(&(btrtl_coex.pan_count_timer), ++ jiffies + msecs_to_jiffies(1000)); ++} ++ ++static void count_hogp_packet_timeout(unsigned long data) ++{ ++ RTKBT_DBG("%s: hogp_packet_count %d", __func__, ++ btrtl_coex.hogp_packet_count); ++ if (btrtl_coex.hogp_packet_count == 0) { ++ if (is_profile_busy(profile_hogp)) { ++ RTKBT_DBG("%s: hogp busy->idle!", __func__); ++ update_profile_state(profile_hogp, FALSE); ++ } ++ } ++ btrtl_coex.hogp_packet_count = 0; ++ ++ RTKBT_DBG("%s: voice_packet_count %d", __func__, ++ btrtl_coex.voice_packet_count); ++ if (btrtl_coex.voice_packet_count == 0) { ++ if (is_profile_busy(profile_voice)) { ++ RTKBT_DBG("%s: voice busy->idle!", __func__); ++ update_profile_state(profile_voice, FALSE); ++ } ++ } ++ btrtl_coex.voice_packet_count = 0; ++ mod_timer(&(btrtl_coex.hogp_count_timer), ++ jiffies + msecs_to_jiffies(1000)); ++} ++ ++static int udpsocket_send(char *tx_msg, int msg_size) ++{ ++ u8 error = 0; ++ struct msghdr udpmsg; ++ mm_segment_t oldfs; ++ struct iovec iov; ++ ++ RTKBT_DBG("send msg %s with len:%d", tx_msg, msg_size); ++ ++ if (btrtl_coex.sock_open) { ++ iov.iov_base = (void *)tx_msg; ++ iov.iov_len = msg_size; ++ udpmsg.msg_name = &btrtl_coex.wifi_addr; ++ udpmsg.msg_namelen = sizeof(struct sockaddr_in); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) ++ udpmsg.msg_iov = &iov; ++ udpmsg.msg_iovlen = 1; ++#else ++ iov_iter_init(&udpmsg.msg_iter, WRITE, &iov, 1, msg_size); ++#endif ++ udpmsg.msg_control = NULL; ++ udpmsg.msg_controllen = 0; ++ udpmsg.msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL; ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0) ++ error = sock_sendmsg(btrtl_coex.udpsock, &udpmsg, msg_size); ++#else ++ error = sock_sendmsg(btrtl_coex.udpsock, &udpmsg); ++#endif ++ set_fs(oldfs); ++ ++ if (error < 0) ++ RTKBT_DBG("Error when sendimg msg, error:%d", error); ++ } ++ ++ return error; ++} ++ ++static void udpsocket_recv_data(void) ++{ ++ u8 recv_data[512]; ++ u32 len = 0; ++ u16 recv_length; ++ struct sk_buff *skb; ++ ++ RTKBT_DBG("-"); ++ ++ spin_lock(&btrtl_coex.spin_lock_sock); ++ len = skb_queue_len(&btrtl_coex.sk->sk_receive_queue); ++ ++ while (len > 0) { ++ skb = skb_dequeue(&btrtl_coex.sk->sk_receive_queue); ++ ++ /*important: cut the udp header from skb->data! header length is 8 byte */ ++ recv_length = skb->len - 8; ++ memset(recv_data, 0, sizeof(recv_data)); ++ memcpy(recv_data, skb->data + 8, recv_length); ++ //RTKBT_DBG("received data: %s :with len %u", recv_data, recv_length); ++ ++ rtk_handle_event_from_wifi(recv_data); ++ ++ len--; ++ kfree_skb(skb); ++ } ++ ++ spin_unlock(&btrtl_coex.spin_lock_sock); ++} ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0) ++static void udpsocket_recv(struct sock *sk, int bytes) ++#else ++static void udpsocket_recv(struct sock *sk) ++#endif ++{ ++ spin_lock(&btrtl_coex.spin_lock_sock); ++ btrtl_coex.sk = sk; ++ spin_unlock(&btrtl_coex.spin_lock_sock); ++ queue_delayed_work(btrtl_coex.sock_wq, &btrtl_coex.sock_work, 0); ++} ++ ++static void create_udpsocket(void) ++{ ++ int err; ++ RTKBT_DBG("%s: connect_port: %d", __func__, CONNECT_PORT); ++ btrtl_coex.sock_open = 0; ++ ++ err = sock_create(AF_INET, SOCK_DGRAM, IPPROTO_UDP, ++ &btrtl_coex.udpsock); ++ if (err < 0) { ++ RTKBT_ERR("%s: sock create error, err = %d", __func__, err); ++ return; ++ } ++ ++ memset(&btrtl_coex.addr, 0, sizeof(struct sockaddr_in)); ++ btrtl_coex.addr.sin_family = AF_INET; ++ btrtl_coex.addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); ++ btrtl_coex.addr.sin_port = htons(CONNECT_PORT); ++ ++ memset(&btrtl_coex.wifi_addr, 0, sizeof(struct sockaddr_in)); ++ btrtl_coex.wifi_addr.sin_family = AF_INET; ++ btrtl_coex.wifi_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); ++ btrtl_coex.wifi_addr.sin_port = htons(CONNECT_PORT_WIFI); ++ ++ err = ++ btrtl_coex.udpsock->ops->bind(btrtl_coex.udpsock, ++ (struct sockaddr *)&btrtl_coex. ++ addr, sizeof(struct sockaddr)); ++ if (err < 0) { ++ sock_release(btrtl_coex.udpsock); ++ RTKBT_ERR("%s: sock bind error, err = %d",__func__, err); ++ return; ++ } ++ ++ btrtl_coex.sock_open = 1; ++ btrtl_coex.udpsock->sk->sk_data_ready = udpsocket_recv; ++} ++ ++static void rtk_notify_extension_version_to_wifi(void) ++{ ++ uint8_t para_length = 2; ++ char p_buf[para_length + HCI_CMD_PREAMBLE_SIZE]; ++ char *p = p_buf; ++ ++ if (!btrtl_coex.wifi_on) ++ return; ++ ++ UINT16_TO_STREAM(p, HCI_OP_HCI_EXTENSION_VERSION_NOTIFY); ++ *p++ = para_length; ++ UINT16_TO_STREAM(p, HCI_EXTENSION_VERSION); ++ RTKBT_DBG("extension version is 0x%x", HCI_EXTENSION_VERSION); ++ if (udpsocket_send(p_buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0) ++ RTKBT_ERR("%s: sock send error", __func__); ++} ++ ++static void rtk_notify_btpatch_version_to_wifi(void) ++{ ++ uint8_t para_length = 4; ++ char p_buf[para_length + HCI_CMD_PREAMBLE_SIZE]; ++ char *p = p_buf; ++ ++ if (!btrtl_coex.wifi_on) ++ return; ++ ++ UINT16_TO_STREAM(p, HCI_OP_HCI_BT_PATCH_VER_NOTIFY); ++ *p++ = para_length; ++ UINT16_TO_STREAM(p, btrtl_coex.hci_reversion); ++ UINT16_TO_STREAM(p, btrtl_coex.lmp_subversion); ++ RTKBT_DBG("btpatch ver: len %u, hci_rev 0x%04x, lmp_subver 0x%04x", ++ para_length, btrtl_coex.hci_reversion, ++ btrtl_coex.lmp_subversion); ++ ++ if (udpsocket_send(p_buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0) ++ RTKBT_ERR("%s: sock send error", __func__); ++} ++ ++static void rtk_notify_afhmap_to_wifi(void) ++{ ++ uint8_t para_length = 13; ++ char p_buf[para_length + HCI_CMD_PREAMBLE_SIZE]; ++ char *p = p_buf; ++ uint8_t kk = 0; ++ ++ if (!btrtl_coex.wifi_on) ++ return; ++ ++ UINT16_TO_STREAM(p, HCI_OP_HCI_BT_AFH_MAP_NOTIFY); ++ *p++ = para_length; ++ *p++ = btrtl_coex.piconet_id; ++ *p++ = btrtl_coex.mode; ++ *p++ = 10; ++ memcpy(p, btrtl_coex.afh_map, 10); ++ ++ RTKBT_DBG("afhmap, piconet_id is 0x%x, map type is 0x%x", ++ btrtl_coex.piconet_id, btrtl_coex.mode); ++ for (kk = 0; kk < 10; kk++) ++ RTKBT_DBG("afhmap data[%d] is 0x%x", kk, ++ btrtl_coex.afh_map[kk]); ++ ++ if (udpsocket_send(p_buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0) ++ RTKBT_ERR("%s: sock send error", __func__); ++} ++ ++static void rtk_notify_btcoex_to_wifi(uint8_t opcode, uint8_t status) ++{ ++ uint8_t para_length = 2; ++ char p_buf[para_length + HCI_CMD_PREAMBLE_SIZE]; ++ char *p = p_buf; ++ ++ if (!btrtl_coex.wifi_on) ++ return; ++ ++ UINT16_TO_STREAM(p, HCI_OP_HCI_BT_COEX_NOTIFY); ++ *p++ = para_length; ++ *p++ = opcode; ++ if (!status) ++ *p++ = 0; ++ else ++ *p++ = 1; ++ ++ RTKBT_DBG("btcoex, opcode is 0x%x, status is 0x%x", opcode, status); ++ ++ if (udpsocket_send(p_buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0) ++ RTKBT_ERR("%s: sock send error", __func__); ++} ++ ++static void rtk_notify_btoperation_to_wifi(uint8_t operation, ++ uint8_t append_data_length, ++ uint8_t * append_data) ++{ ++ uint8_t para_length = 3 + append_data_length; ++ char p_buf[para_length + HCI_CMD_PREAMBLE_SIZE]; ++ char *p = p_buf; ++ uint8_t kk = 0; ++ ++ if (!btrtl_coex.wifi_on) ++ return; ++ ++ UINT16_TO_STREAM(p, HCI_OP_BT_OPERATION_NOTIFY); ++ *p++ = para_length; ++ *p++ = operation; ++ *p++ = append_data_length; ++ if (append_data_length) ++ memcpy(p, append_data, append_data_length); ++ ++ RTKBT_DBG("btoperation: op 0x%02x, append_data_length %u", ++ operation, append_data_length); ++ if (append_data_length) { ++ for (kk = 0; kk < append_data_length; kk++) ++ RTKBT_DBG("append data is 0x%x", *(append_data + kk)); ++ } ++ ++ if (udpsocket_send(p_buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0) ++ RTKBT_ERR("%s: sock send error", __func__); ++} ++ ++static void rtk_notify_info_to_wifi(uint8_t reason, uint8_t length, ++ uint8_t *report_info) ++{ ++ uint8_t para_length = 4 + length; ++ char buf[para_length + HCI_CMD_PREAMBLE_SIZE]; ++ char *p = buf; ++ struct rtl_btinfo *report = (struct rtl_btinfo *)report_info; ++ ++ if (length) { ++ RTKBT_DBG("bt info: cmd %2.2X", report->cmd); ++ RTKBT_DBG("bt info: len %2.2X", report->len); ++ RTKBT_DBG("bt info: data %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X", ++ report->data[0], report->data[1], report->data[2], ++ report->data[3], report->data[4], report->data[5]); ++ } ++ RTKBT_DBG("bt info: reason 0x%2x, length 0x%2x", reason, length); ++ ++ if (!btrtl_coex.wifi_on) ++ return; ++ ++ UINT16_TO_STREAM(p, HCI_OP_HCI_BT_INFO_NOTIFY); ++ *p++ = para_length; ++ *p++ = btrtl_coex.polling_enable; ++ *p++ = btrtl_coex.polling_interval; ++ *p++ = reason; ++ *p++ = length; ++ ++ if (length) ++ memcpy(p, report_info, length); ++ ++ RTKBT_DBG("para length %2x, polling_enable %u, poiiling_interval %u", ++ para_length, btrtl_coex.polling_enable, ++ btrtl_coex.polling_interval); ++ /* send BT INFO to Wi-Fi driver */ ++ if (udpsocket_send(buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0) ++ RTKBT_ERR("%s: sock send error", __func__); ++} ++ ++static void rtk_notify_regester_to_wifi(uint8_t * reg_value) ++{ ++ uint8_t para_length = 9; ++ char p_buf[para_length + HCI_CMD_PREAMBLE_SIZE]; ++ char *p = p_buf; ++ hci_mailbox_register *reg = (hci_mailbox_register *) reg_value; ++ ++ if (!btrtl_coex.wifi_on) ++ return; ++ ++ UINT16_TO_STREAM(p, HCI_OP_HCI_BT_REGISTER_VALUE_NOTIFY); ++ *p++ = para_length; ++ memcpy(p, reg_value, para_length); ++ ++ RTKBT_DBG("bt register, register type is %x", reg->type); ++ RTKBT_DBG("bt register, register offset is %x", reg->offset); ++ RTKBT_DBG("bt register, register value is %x", reg->value); ++ ++ if (udpsocket_send(p_buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0) ++ RTKBT_ERR("%s: sock send error", __func__); ++} ++ ++void rtk_btcoex_parse_cmd(uint8_t *buffer, int count) ++{ ++ u16 opcode = (buffer[0]) + (buffer[1] << 8); ++ ++ if (!test_bit(RTL_COEX_RUNNING, &btrtl_coex.flags)) { ++ RTKBT_INFO("%s: Coex is closed, ignore", __func__); ++ return; ++ } ++ ++ if ((opcode == HCI_OP_INQUIRY) || (opcode == HCI_OP_PERIODIC_INQ)) { ++ if (!btrtl_coex.isinquirying) { ++ btrtl_coex.isinquirying = 1; ++ RTKBT_DBG("hci (periodic)inq, notify wifi " ++ "inquiry start"); ++ rtk_notify_btoperation_to_wifi(BT_OPCODE_INQUIRY_START, ++ 0, NULL); ++ } ++ } ++ ++ if ((opcode == HCI_OP_INQUIRY_CANCEL) ++ || (opcode == HCI_OP_EXIT_PERIODIC_INQ)) { ++ if (btrtl_coex.isinquirying) { ++ btrtl_coex.isinquirying = 0; ++ RTKBT_DBG("hci (periodic)inq cancel/exit, notify wifi " ++ "inquiry stop"); ++ rtk_notify_btoperation_to_wifi(BT_OPCODE_INQUIRY_END, 0, ++ NULL); ++ } ++ } ++ ++ if (opcode == HCI_OP_ACCEPT_CONN_REQ) { ++ if (!btrtl_coex.ispaging) { ++ btrtl_coex.ispaging = 1; ++ RTKBT_DBG("hci accept connreq, notify wifi page start"); ++ rtk_notify_btoperation_to_wifi(BT_OPCODE_PAGE_START, 0, ++ NULL); ++ } ++ } ++} ++ ++static void rtk_handle_inquiry_complete(void) ++{ ++ if (btrtl_coex.isinquirying) { ++ btrtl_coex.isinquirying = 0; ++ RTKBT_DBG("inq complete, notify wifi inquiry end"); ++ rtk_notify_btoperation_to_wifi(BT_OPCODE_INQUIRY_END, 0, NULL); ++ } ++} ++ ++static void rtk_handle_pin_code_req(void) ++{ ++ if (!btrtl_coex.ispairing) { ++ btrtl_coex.ispairing = 1; ++ RTKBT_DBG("pin code req, notify wifi pair start"); ++ rtk_notify_btoperation_to_wifi(BT_OPCODE_PAIR_START, 0, NULL); ++ } ++} ++ ++static void rtk_handle_io_capa_req(void) ++{ ++ if (!btrtl_coex.ispairing) { ++ btrtl_coex.ispairing = 1; ++ RTKBT_DBG("io cap req, notify wifi pair start"); ++ rtk_notify_btoperation_to_wifi(BT_OPCODE_PAIR_START, 0, NULL); ++ } ++} ++ ++static void rtk_handle_auth_request(void) ++{ ++ if (btrtl_coex.ispairing) { ++ btrtl_coex.ispairing = 0; ++ RTKBT_DBG("auth req, notify wifi pair end"); ++ rtk_notify_btoperation_to_wifi(BT_OPCODE_PAIR_END, 0, NULL); ++ } ++} ++ ++static void rtk_handle_link_key_notify(void) ++{ ++ if (btrtl_coex.ispairing) { ++ btrtl_coex.ispairing = 0; ++ RTKBT_DBG("link key notify, notify wifi pair end"); ++ rtk_notify_btoperation_to_wifi(BT_OPCODE_PAIR_END, 0, NULL); ++ } ++} ++ ++static void rtk_handle_mode_change_evt(u8 * p) ++{ ++ u16 mode_change_handle, mode_interval; ++ ++ p++; ++ STREAM_TO_UINT16(mode_change_handle, p); ++ p++; ++ STREAM_TO_UINT16(mode_interval, p); ++ update_hid_active_state(mode_change_handle, mode_interval); ++} ++ ++static void rtk_parse_vendor_mailbox_cmd_evt(u8 * p, u8 total_len) ++{ ++ u8 status, subcmd; ++ u8 temp_cmd[10]; ++ ++ status = *p++; ++ if (total_len <= 4) { ++ RTKBT_DBG("receive mailbox cmd from fw, total length <= 4"); ++ return; ++ } ++ subcmd = *p++; ++ RTKBT_DBG("receive mailbox cmd from fw, subcmd is 0x%x, status is 0x%x", ++ subcmd, status); ++ ++ switch (subcmd) { ++ case HCI_VENDOR_SUB_CMD_BT_REPORT_CONN_SCO_INQ_INFO: ++ if (status == 0) //success ++ rtk_notify_info_to_wifi(POLLING_RESPONSE, ++ RTL_BTINFO_LEN, (uint8_t *)p); ++ break; ++ ++ case HCI_VENDOR_SUB_CMD_WIFI_CHANNEL_AND_BANDWIDTH_CMD: ++ rtk_notify_btcoex_to_wifi(WIFI_BW_CHNL_NOTIFY, status); ++ break; ++ ++ case HCI_VENDOR_SUB_CMD_WIFI_FORCE_TX_POWER_CMD: ++ rtk_notify_btcoex_to_wifi(BT_POWER_DECREASE_CONTROL, status); ++ break; ++ ++ case HCI_VENDOR_SUB_CMD_BT_ENABLE_IGNORE_WLAN_ACT_CMD: ++ rtk_notify_btcoex_to_wifi(IGNORE_WLAN_ACTIVE_CONTROL, status); ++ break; ++ ++ case HCI_VENDOR_SUB_CMD_SET_BT_PSD_MODE: ++ rtk_notify_btcoex_to_wifi(BT_PSD_MODE_CONTROL, status); ++ break; ++ ++ case HCI_VENDOR_SUB_CMD_SET_BT_LNA_CONSTRAINT: ++ rtk_notify_btcoex_to_wifi(LNA_CONSTRAIN_CONTROL, status); ++ break; ++ ++ case HCI_VENDOR_SUB_CMD_BT_AUTO_REPORT_ENABLE: ++ break; ++ ++ case HCI_VENDOR_SUB_CMD_BT_SET_TXRETRY_REPORT_PARAM: ++ break; ++ ++ case HCI_VENDOR_SUB_CMD_BT_SET_PTATABLE: ++ break; ++ ++ case HCI_VENDOR_SUB_CMD_GET_AFH_MAP_L: ++ if (status == 0) { ++ memcpy(btrtl_coex.afh_map, p + 4, 4); /* cmd_idx, length, piconet_id, mode */ ++ temp_cmd[0] = HCI_VENDOR_SUB_CMD_GET_AFH_MAP_M; ++ temp_cmd[1] = 2; ++ temp_cmd[2] = btrtl_coex.piconet_id; ++ temp_cmd[3] = btrtl_coex.mode; ++ rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 4, ++ temp_cmd); ++ } else { ++ memset(btrtl_coex.afh_map, 0, 10); ++ rtk_notify_afhmap_to_wifi(); ++ } ++ break; ++ ++ case HCI_VENDOR_SUB_CMD_GET_AFH_MAP_M: ++ if (status == 0) { ++ memcpy(btrtl_coex.afh_map + 4, p + 4, 4); ++ temp_cmd[0] = HCI_VENDOR_SUB_CMD_GET_AFH_MAP_H; ++ temp_cmd[1] = 2; ++ temp_cmd[2] = btrtl_coex.piconet_id; ++ temp_cmd[3] = btrtl_coex.mode; ++ rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 4, ++ temp_cmd); ++ } else { ++ memset(btrtl_coex.afh_map, 0, 10); ++ rtk_notify_afhmap_to_wifi(); ++ } ++ break; ++ ++ case HCI_VENDOR_SUB_CMD_GET_AFH_MAP_H: ++ if (status == 0) ++ memcpy(btrtl_coex.afh_map + 8, p + 4, 2); ++ else ++ memset(btrtl_coex.afh_map, 0, 10); ++ ++ rtk_notify_afhmap_to_wifi(); ++ break; ++ ++ case HCI_VENDOR_SUB_CMD_RD_REG_REQ: ++ if (status == 0) ++ rtk_notify_regester_to_wifi(p + 3); /* cmd_idx,length,regist type */ ++ break; ++ ++ case HCI_VENDOR_SUB_CMD_WR_REG_REQ: ++ rtk_notify_btcoex_to_wifi(BT_REGISTER_ACCESS, status); ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++static void rtk_handle_cmd_complete_evt(u8 total_len, u8 * p) ++{ ++ u16 opcode; ++ ++ p++; ++ STREAM_TO_UINT16(opcode, p); ++ //RTKBT_DBG("cmd_complete, opcode is 0x%x", opcode); ++ ++ if (opcode == HCI_OP_PERIODIC_INQ) { ++ if (*p++ && btrtl_coex.isinquirying) { ++ btrtl_coex.isinquirying = 0; ++ RTKBT_DBG("hci period inq, start error, notify wifi " ++ "inquiry stop"); ++ rtk_notify_btoperation_to_wifi(BT_OPCODE_INQUIRY_END, 0, ++ NULL); ++ } ++ } ++ ++ if (opcode == HCI_OP_READ_LOCAL_VERSION) { ++ if (!(*p++)) { ++ p++; ++ STREAM_TO_UINT16(btrtl_coex.hci_reversion, p); ++ p += 3; ++ STREAM_TO_UINT16(btrtl_coex.lmp_subversion, p); ++ RTKBT_DBG("BTCOEX hci_rev 0x%04x", ++ btrtl_coex.hci_reversion); ++ RTKBT_DBG("BTCOEX lmp_subver 0x%04x", ++ btrtl_coex.lmp_subversion); ++ } ++ } ++ ++ if (opcode == HCI_VENDOR_MAILBOX_CMD) { ++ rtk_parse_vendor_mailbox_cmd_evt(p, total_len); ++ } ++} ++ ++static void rtk_handle_cmd_status_evt(u8 * p) ++{ ++ u16 opcode; ++ u8 status; ++ ++ status = *p++; ++ p++; ++ STREAM_TO_UINT16(opcode, p); ++ //RTKBT_DBG("cmd_status, opcode is 0x%x", opcode); ++ if ((opcode == HCI_OP_INQUIRY) && (status)) { ++ if (btrtl_coex.isinquirying) { ++ btrtl_coex.isinquirying = 0; ++ RTKBT_DBG("hci inq, start error, notify wifi inq stop"); ++ rtk_notify_btoperation_to_wifi(BT_OPCODE_INQUIRY_END, 0, ++ NULL); ++ } ++ } ++ ++ if (opcode == HCI_OP_CREATE_CONN) { ++ if (!status && !btrtl_coex.ispaging) { ++ btrtl_coex.ispaging = 1; ++ RTKBT_DBG("hci create conn, notify wifi start page"); ++ rtk_notify_btoperation_to_wifi(BT_OPCODE_PAGE_START, 0, ++ NULL); ++ } ++ } ++} ++ ++static void rtk_handle_connection_complete_evt(u8 * p) ++{ ++ u16 handle; ++ u8 status, link_type; ++ rtk_conn_prof *hci_conn = NULL; ++ ++ status = *p++; ++ STREAM_TO_UINT16(handle, p); ++ p += 6; ++ link_type = *p++; ++ ++ if (status == 0) { ++ if (btrtl_coex.ispaging) { ++ btrtl_coex.ispaging = 0; ++ RTKBT_DBG("notify wifi page success end"); ++ rtk_notify_btoperation_to_wifi ++ (BT_OPCODE_PAGE_SUCCESS_END, 0, NULL); ++ } ++ ++ hci_conn = find_connection_by_handle(&btrtl_coex, handle); ++ if (hci_conn == NULL) { ++ hci_conn = allocate_connection_by_handle(handle); ++ if (hci_conn) { ++ add_connection_to_hash(&btrtl_coex, ++ hci_conn); ++ hci_conn->profile_bitmap = 0; ++ memset(hci_conn->profile_refcount, 0, 8); ++ if ((0 == link_type) || (2 == link_type)) { //sco or esco ++ hci_conn->type = 1; ++ update_profile_connection(hci_conn, ++ profile_sco, ++ TRUE); ++ } else ++ hci_conn->type = 0; ++ } else { ++ RTKBT_ERR("hci connection allocate fail"); ++ } ++ } else { ++ RTKBT_DBG("hci conn handle 0x%04x already existed!", ++ handle); ++ hci_conn->profile_bitmap = 0; ++ memset(hci_conn->profile_refcount, 0, 8); ++ if ((0 == link_type) || (2 == link_type)) { //sco or esco ++ hci_conn->type = 1; ++ update_profile_connection(hci_conn, profile_sco, ++ TRUE); ++ } else ++ hci_conn->type = 0; ++ } ++ } else if (btrtl_coex.ispaging) { ++ btrtl_coex.ispaging = 0; ++ RTKBT_DBG("notify wifi page unsuccess end"); ++ rtk_notify_btoperation_to_wifi(BT_OPCODE_PAGE_UNSUCCESS_END, 0, ++ NULL); ++ } ++} ++ ++static void rtk_handle_le_connection_complete_evt(u8 * p) ++{ ++ u16 handle, interval; ++ u8 status; ++ rtk_conn_prof *hci_conn = NULL; ++ ++ status = *p++; ++ STREAM_TO_UINT16(handle, p); ++ p += 8; //role, address type, address ++ STREAM_TO_UINT16(interval, p); ++ ++ if (status == 0) { ++ if (btrtl_coex.ispaging) { ++ btrtl_coex.ispaging = 0; ++ RTKBT_DBG("notify wifi page success end"); ++ rtk_notify_btoperation_to_wifi ++ (BT_OPCODE_PAGE_SUCCESS_END, 0, NULL); ++ } ++ ++ hci_conn = find_connection_by_handle(&btrtl_coex, handle); ++ if (hci_conn == NULL) { ++ hci_conn = allocate_connection_by_handle(handle); ++ if (hci_conn) { ++ add_connection_to_hash(&btrtl_coex, ++ hci_conn); ++ hci_conn->profile_bitmap = 0; ++ memset(hci_conn->profile_refcount, 0, 8); ++ hci_conn->type = 2; ++ update_profile_connection(hci_conn, profile_hid, TRUE); //for coex, le is the same as hid ++ update_hid_active_state(handle, interval); ++ } else { ++ RTKBT_ERR("hci connection allocate fail"); ++ } ++ } else { ++ RTKBT_DBG("hci conn handle 0x%04x already existed!", ++ handle); ++ hci_conn->profile_bitmap = 0; ++ memset(hci_conn->profile_refcount, 0, 8); ++ hci_conn->type = 2; ++ update_profile_connection(hci_conn, profile_hid, TRUE); ++ update_hid_active_state(handle, interval); ++ } ++ } else if (btrtl_coex.ispaging) { ++ btrtl_coex.ispaging = 0; ++ RTKBT_DBG("notify wifi page unsuccess end"); ++ rtk_notify_btoperation_to_wifi(BT_OPCODE_PAGE_UNSUCCESS_END, 0, ++ NULL); ++ } ++} ++ ++static void rtk_handle_le_connection_update_complete_evt(u8 * p) ++{ ++ u16 handle, interval; ++ /* u8 status; */ ++ ++ /* status = *p++; */ ++ p++; ++ ++ STREAM_TO_UINT16(handle, p); ++ STREAM_TO_UINT16(interval, p); ++ update_hid_active_state(handle, interval); ++} ++ ++static void rtk_handle_le_meta_evt(u8 * p) ++{ ++ u8 sub_event = *p++; ++ switch (sub_event) { ++ case HCI_EV_LE_CONN_COMPLETE: ++ rtk_handle_le_connection_complete_evt(p); ++ break; ++ ++ case HCI_EV_LE_CONN_UPDATE_COMPLETE: ++ rtk_handle_le_connection_update_complete_evt(p); ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++static void disconn_acl(u16 handle, struct rtl_hci_conn *conn) ++{ ++ struct rtl_coex_struct *coex = &btrtl_coex; ++ rtk_prof_info *prof_info = NULL; ++ struct list_head *iter = NULL, *temp = NULL; ++ ++ spin_lock(&coex->spin_lock_profile); ++ ++ list_for_each_safe(iter, temp, &coex->profile_list) { ++ prof_info = list_entry(iter, rtk_prof_info, list); ++ if (handle == prof_info->handle && prof_info->scid ++ && prof_info->dcid) { ++ RTKBT_DBG("hci disconn, hndl %x, psm %x, dcid %x, " ++ "scid %x", prof_info->handle, ++ prof_info->psm, prof_info->dcid, ++ prof_info->scid); ++ //If both scid and dcid > 0, L2cap connection is exist. ++ update_profile_connection(conn, ++ prof_info->profile_index, FALSE); ++ delete_profile_from_hash(prof_info); ++ } ++ } ++ spin_unlock(&coex->spin_lock_profile); ++} ++ ++static void rtk_handle_disconnect_complete_evt(u8 * p) ++{ ++ u16 handle; ++ u8 status; ++ /* u8 reason; */ ++ rtk_conn_prof *hci_conn = NULL; ++ ++ if (btrtl_coex.ispairing) { //for slave: connection will be disconnected if authentication fail ++ btrtl_coex.ispairing = 0; ++ RTKBT_DBG("hci disc complete, notify wifi pair end"); ++ rtk_notify_btoperation_to_wifi(BT_OPCODE_PAIR_END, 0, NULL); ++ } ++ ++ status = *p++; ++ STREAM_TO_UINT16(handle, p); ++ ++ /* reason = *p; */ ++ ++ if (status == 0) { ++ RTKBT_DBG("process disconn complete event."); ++ hci_conn = find_connection_by_handle(&btrtl_coex, handle); ++ if (hci_conn) { ++ switch (hci_conn->type) { ++ case 0: ++ /* FIXME: If this is interrupted by l2cap rx, ++ * there may be deadlock on spin_lock_profile */ ++ disconn_acl(handle, hci_conn); ++ break; ++ ++ case 1: ++ update_profile_connection(hci_conn, profile_sco, ++ FALSE); ++ break; ++ ++ case 2: ++ update_profile_connection(hci_conn, profile_hid, ++ FALSE); ++ break; ++ ++ default: ++ break; ++ } ++ delete_connection_from_hash(hci_conn); ++ } else ++ RTKBT_ERR("hci conn handle 0x%04x not found", handle); ++ } ++} ++ ++static void rtk_handle_specific_evt(u8 * p) ++{ ++ u16 subcode; ++ ++ STREAM_TO_UINT16(subcode, p); ++ if (subcode == HCI_VENDOR_PTA_AUTO_REPORT_EVENT) { ++ RTKBT_DBG("notify wifi driver with autoreport data"); ++ rtk_notify_info_to_wifi(AUTO_REPORT, RTL_BTINFO_LEN, ++ (uint8_t *)p); ++ } ++} ++ ++static void rtk_parse_event_data(struct rtl_coex_struct *coex, ++ u8 *data, u16 len) ++{ ++ u8 *p = data; ++ u8 event_code = *p++; ++ u8 total_len = *p++; ++ ++ (void)coex; ++ (void)&len; ++ ++ switch (event_code) { ++ case HCI_EV_INQUIRY_COMPLETE: ++ rtk_handle_inquiry_complete(); ++ break; ++ ++ case HCI_EV_PIN_CODE_REQ: ++ rtk_handle_pin_code_req(); ++ break; ++ ++ case HCI_EV_IO_CAPA_REQUEST: ++ rtk_handle_io_capa_req(); ++ break; ++ ++ case HCI_EV_AUTH_COMPLETE: ++ rtk_handle_auth_request(); ++ break; ++ ++ case HCI_EV_LINK_KEY_NOTIFY: ++ rtk_handle_link_key_notify(); ++ break; ++ ++ case HCI_EV_MODE_CHANGE: ++ rtk_handle_mode_change_evt(p); ++ break; ++ ++ case HCI_EV_CMD_COMPLETE: ++ rtk_handle_cmd_complete_evt(total_len, p); ++ break; ++ ++ case HCI_EV_CMD_STATUS: ++ rtk_handle_cmd_status_evt(p); ++ break; ++ ++ case HCI_EV_CONN_COMPLETE: ++ case HCI_EV_SYNC_CONN_COMPLETE: ++ rtk_handle_connection_complete_evt(p); ++ break; ++ ++ case HCI_EV_DISCONN_COMPLETE: ++ rtk_handle_disconnect_complete_evt(p); ++ break; ++ ++ case HCI_EV_LE_META: ++ rtk_handle_le_meta_evt(p); ++ break; ++ ++ case HCI_EV_VENDOR_SPECIFIC: ++ rtk_handle_specific_evt(p); ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++const char l2_dir_str[][4] = { ++ "RX", "TX", ++}; ++ ++void rtl_process_l2_sig(struct rtl_l2_buff *l2) ++{ ++ /* u8 flag; */ ++ u8 code; ++ /* u8 identifier; */ ++ u16 handle; ++ /* u16 total_len; */ ++ /* u16 pdu_len, channel_id; */ ++ /* u16 command_len; */ ++ u16 psm, scid, dcid, result; ++ /* u16 status; */ ++ u8 *pp = l2->data; ++ ++ STREAM_TO_UINT16(handle, pp); ++ /* flag = handle >> 12; */ ++ handle = handle & 0x0FFF; ++ /* STREAM_TO_UINT16(total_len, pp); */ ++ pp += 2; /* data total length */ ++ ++ /* STREAM_TO_UINT16(pdu_len, pp); ++ * STREAM_TO_UINT16(channel_id, pp); */ ++ pp += 4; /* l2 len and channel id */ ++ ++ code = *pp++; ++ switch (code) { ++ case L2CAP_CONN_REQ: ++ /* identifier = *pp++; */ ++ pp++; ++ /* STREAM_TO_UINT16(command_len, pp); */ ++ pp += 2; ++ STREAM_TO_UINT16(psm, pp); ++ STREAM_TO_UINT16(scid, pp); ++ RTKBT_DBG("%s l2cap conn req, hndl 0x%04x, PSM 0x%04x, " ++ "scid 0x%04x", l2_dir_str[l2->out], handle, psm, ++ scid); ++ handle_l2cap_con_req(handle, psm, scid, l2->out); ++ break; ++ ++ case L2CAP_CONN_RSP: ++ /* identifier = *pp++; */ ++ pp++; ++ /* STREAM_TO_UINT16(command_len, pp); */ ++ pp += 2; ++ STREAM_TO_UINT16(dcid, pp); ++ STREAM_TO_UINT16(scid, pp); ++ STREAM_TO_UINT16(result, pp); ++ /* STREAM_TO_UINT16(status, pp); */ ++ pp += 2; ++ RTKBT_DBG("%s l2cap conn rsp, hndl 0x%04x, dcid 0x%04x, " ++ "scid 0x%04x, result 0x%04x", l2_dir_str[l2->out], ++ handle, dcid, scid, result); ++ handle_l2cap_con_rsp(handle, dcid, scid, l2->out, result); ++ break; ++ ++ case L2CAP_DISCONN_REQ: ++ /* identifier = *pp++; */ ++ pp++; ++ /* STREAM_TO_UINT16(command_len, pp); */ ++ pp += 2; ++ STREAM_TO_UINT16(dcid, pp); ++ STREAM_TO_UINT16(scid, pp); ++ RTKBT_DBG("%s l2cap disconn req, hndl 0x%04x, dcid 0x%04x, " ++ "scid 0x%04x", l2_dir_str[l2->out], handle, dcid, scid); ++ handle_l2cap_discon_req(handle, dcid, scid, l2->out); ++ break; ++ default: ++ RTKBT_DBG("undesired l2 command %u", code); ++ break; ++ } ++} ++ ++static void rtl_l2_data_process(u8 *pp, u16 len, int dir) ++{ ++ u8 code; ++ u8 flag; ++ u16 handle, pdu_len, channel_id; ++ /* u16 total_len; */ ++ struct rtl_l2_buff *l2 = NULL; ++ u8 *hd = pp; ++ ++ /* RTKBT_DBG("l2 sig data %p, len %u, dir %d", pp, len, dir); */ ++ ++ STREAM_TO_UINT16(handle, pp); ++ flag = handle >> 12; ++ handle = handle & 0x0FFF; ++ /* STREAM_TO_UINT16(total_len, pp); */ ++ pp += 2; /* data total length */ ++ ++ STREAM_TO_UINT16(pdu_len, pp); ++ STREAM_TO_UINT16(channel_id, pp); ++ ++ if (channel_id == 0x0001) { ++ code = *pp++; ++ switch (code) { ++ case L2CAP_CONN_REQ: ++ case L2CAP_CONN_RSP: ++ case L2CAP_DISCONN_REQ: ++ RTKBT_DBG("l2cap op %u, len %u, out %d", code, len, ++ dir); ++ l2 = rtl_l2_node_get(&btrtl_coex); ++ if (l2) { ++ u16 n; ++ n = min_t(uint, len, L2_MAX_SUBSEC_LEN); ++ memcpy(l2->data, hd, n); ++ l2->out = dir; ++ rtl_l2_node_to_used(&btrtl_coex, l2); ++ queue_delayed_work(btrtl_coex.fw_wq, ++ &btrtl_coex.l2_work, 0); ++ } else ++ RTKBT_ERR("%s: failed to get l2 node", ++ __func__); ++ break; ++ case L2CAP_DISCONN_RSP: ++ break; ++ default: ++ break; ++ } ++ } else { ++ if ((flag != 0x01) && (is_profile_connected(profile_a2dp) || ++ is_profile_connected(profile_pan))) ++ /* Do not count the continuous packets */ ++ packets_count(handle, channel_id, pdu_len, dir, pp); ++ } ++ return; ++} ++ ++ ++static void rtl_l2_work(struct work_struct *work) ++{ ++ struct rtl_coex_struct *coex; ++ struct rtl_l2_buff *l2; ++ unsigned long flags; ++ ++ coex = container_of(work, struct rtl_coex_struct, l2_work.work); ++ ++ spin_lock_irqsave(&coex->buff_lock, flags); ++ while (!list_empty(&coex->l2_used_list)) { ++ l2 = list_entry(coex->l2_used_list.next, struct rtl_l2_buff, ++ list); ++ list_del(&l2->list); ++ ++ spin_unlock_irqrestore(&coex->buff_lock, flags); ++ ++ rtl_process_l2_sig(l2); ++ ++ spin_lock_irqsave(&coex->buff_lock, flags); ++ ++ list_add_tail(&l2->list, &coex->l2_free_list); ++ } ++ spin_unlock_irqrestore(&coex->buff_lock, flags); ++ ++ return; ++} ++ ++static void rtl_ev_work(struct work_struct *work) ++{ ++ struct rtl_coex_struct *coex; ++ struct rtl_hci_ev *ev; ++ unsigned long flags; ++ ++ coex = container_of(work, struct rtl_coex_struct, fw_work.work); ++ ++ spin_lock_irqsave(&coex->buff_lock, flags); ++ while (!list_empty(&coex->ev_used_list)) { ++ ev = list_entry(coex->ev_used_list.next, struct rtl_hci_ev, ++ list); ++ list_del(&ev->list); ++ spin_unlock_irqrestore(&coex->buff_lock, flags); ++ ++ rtk_parse_event_data(coex, ev->data, ev->len); ++ ++ spin_lock_irqsave(&coex->buff_lock, flags); ++ list_add_tail(&ev->list, &coex->ev_free_list); ++ } ++ spin_unlock_irqrestore(&coex->buff_lock, flags); ++} ++ ++int ev_filter_out(u8 ev_code) ++{ ++ switch (ev_code) { ++ case HCI_EV_INQUIRY_COMPLETE: ++ case HCI_EV_PIN_CODE_REQ: ++ case HCI_EV_IO_CAPA_REQUEST: ++ case HCI_EV_AUTH_COMPLETE: ++ case HCI_EV_LINK_KEY_NOTIFY: ++ case HCI_EV_MODE_CHANGE: ++ case HCI_EV_CMD_COMPLETE: ++ case HCI_EV_CMD_STATUS: ++ case HCI_EV_CONN_COMPLETE: ++ case HCI_EV_SYNC_CONN_COMPLETE: ++ case HCI_EV_DISCONN_COMPLETE: ++ case HCI_EV_LE_META: ++ case HCI_EV_VENDOR_SPECIFIC: ++ return 0; ++ default: ++ return 1; ++ } ++} ++ ++static void rtk_btcoex_evt_enqueue(__u8 *s, __u16 count) ++{ ++ struct rtl_hci_ev *ev; ++ ++ if (ev_filter_out(s[0])) ++ return; ++ ++ ev = rtl_ev_node_get(&btrtl_coex); ++ if (!ev) { ++ RTKBT_ERR("%s: no free ev node.", __func__); ++ return; ++ } ++ ++ if (count > MAX_LEN_OF_HCI_EV) { ++ memcpy(ev->data, s, MAX_LEN_OF_HCI_EV); ++ ev->len = MAX_LEN_OF_HCI_EV; ++ } else { ++ memcpy(ev->data, s, count); ++ ev->len = count; ++ } ++ ++ rtl_ev_node_to_used(&btrtl_coex, ev); ++ ++ queue_delayed_work(btrtl_coex.fw_wq, &btrtl_coex.fw_work, 0); ++} ++ ++/* Context: in_interrupt() */ ++void rtk_btcoex_parse_event(uint8_t *buffer, int count) ++{ ++ struct rtl_coex_struct *coex = &btrtl_coex; ++ __u8 *tbuff; ++ __u16 elen = 0; ++ ++ /* RTKBT_DBG("%s: parse ev.", __func__); */ ++ if (!test_bit(RTL_COEX_RUNNING, &btrtl_coex.flags)) { ++ /* RTKBT_INFO("%s: Coex is closed, ignore", __func__); */ ++ RTKBT_INFO("%s: Coex is closed, ignore %x, %x", ++ __func__, buffer[0], buffer[1]); ++ return; ++ } ++ ++ spin_lock(&coex->rxlock); ++ ++ /* coex->tbuff will be set to NULL when initializing or ++ * there is a complete frame or there is start of a frame */ ++ tbuff = coex->tbuff; ++ ++ while (count) { ++ int len; ++ ++ /* Start of a frame */ ++ if (!tbuff) { ++ tbuff = coex->back_buff; ++ coex->tbuff = NULL; ++ coex->elen = 0; ++ ++ coex->pkt_type = HCI_EVENT_PKT; ++ coex->expect = HCI_EVENT_HDR_SIZE; ++ } ++ ++ len = min_t(uint, coex->expect, count); ++ memcpy(tbuff, buffer, len); ++ tbuff += len; ++ coex->elen += len; ++ ++ count -= len; ++ buffer += len; ++ coex->expect -= len; ++ ++ if (coex->elen == HCI_EVENT_HDR_SIZE) { ++ /* Complete event header */ ++ coex->expect = ++ ((struct hci_event_hdr *)coex->back_buff)->plen; ++ if (coex->expect > HCI_MAX_EVENT_SIZE - coex->elen) { ++ tbuff = NULL; ++ coex->elen = 0; ++ RTKBT_ERR("tbuff room is not enough"); ++ break; ++ } ++ } ++ ++ if (coex->expect == 0) { ++ /* Complete frame */ ++ elen = coex->elen; ++ spin_unlock(&coex->rxlock); ++ rtk_btcoex_evt_enqueue(coex->back_buff, elen); ++ spin_lock(&coex->rxlock); ++ ++ tbuff = NULL; ++ coex->elen = 0; ++ } ++ } ++ ++ /* coex->tbuff would be non-NULL if there isn't a complete frame ++ * And it will be updated next time */ ++ coex->tbuff = tbuff; ++ spin_unlock(&coex->rxlock); ++} ++ ++ ++void rtk_btcoex_parse_l2cap_data_tx(uint8_t *buffer, int count) ++{ ++ if (!test_bit(RTL_COEX_RUNNING, &btrtl_coex.flags)) { ++ RTKBT_INFO("%s: Coex is closed, ignore", __func__); ++ return; ++ } ++ ++ rtl_l2_data_process(buffer, count, 1); ++ //u16 handle, total_len, pdu_len, channel_ID, command_len, psm, scid, ++ // dcid, result, status; ++ //u8 flag, code, identifier; ++ //u8 *pp = (u8 *) (skb->data); ++ //STREAM_TO_UINT16(handle, pp); ++ //flag = handle >> 12; ++ //handle = handle & 0x0FFF; ++ //STREAM_TO_UINT16(total_len, pp); ++ //STREAM_TO_UINT16(pdu_len, pp); ++ //STREAM_TO_UINT16(channel_ID, pp); ++ ++ //if (channel_ID == 0x0001) { ++ // code = *pp++; ++ // switch (code) { ++ // case L2CAP_CONN_REQ: ++ // identifier = *pp++; ++ // STREAM_TO_UINT16(command_len, pp); ++ // STREAM_TO_UINT16(psm, pp); ++ // STREAM_TO_UINT16(scid, pp); ++ // RTKBT_DBG("TX l2cap conn req, hndl %x, PSM %x, scid=%x", ++ // handle, psm, scid); ++ // handle_l2cap_con_req(handle, psm, scid, 1); ++ // break; ++ ++ // case L2CAP_CONN_RSP: ++ // identifier = *pp++; ++ // STREAM_TO_UINT16(command_len, pp); ++ // STREAM_TO_UINT16(dcid, pp); ++ // STREAM_TO_UINT16(scid, pp); ++ // STREAM_TO_UINT16(result, pp); ++ // STREAM_TO_UINT16(status, pp); ++ // RTKBT_DBG("TX l2cap conn rsp, hndl %x, dcid %x, " ++ // "scid %x, result %x", ++ // handle, dcid, scid, result); ++ // handle_l2cap_con_rsp(handle, dcid, scid, 1, result); ++ // break; ++ ++ // case L2CAP_DISCONN_REQ: ++ // identifier = *pp++; ++ // STREAM_TO_UINT16(command_len, pp); ++ // STREAM_TO_UINT16(dcid, pp); ++ // STREAM_TO_UINT16(scid, pp); ++ // RTKBT_DBG("TX l2cap disconn req, hndl %x, dcid %x, " ++ // "scid %x", handle, dcid, scid); ++ // handle_l2cap_discon_req(handle, dcid, scid, 1); ++ // break; ++ ++ // case L2CAP_DISCONN_RSP: ++ // break; ++ ++ // default: ++ // break; ++ // } ++ //} else { ++ // if ((flag != 0x01) && (is_profile_connected(profile_a2dp) || is_profile_connected(profile_pan))) //Do not count the continuous packets ++ // packets_count(handle, channel_ID, pdu_len, 1, pp); ++ //} ++} ++ ++void rtk_btcoex_parse_l2cap_data_rx(uint8_t *buffer, int count) ++{ ++ if (!test_bit(RTL_COEX_RUNNING, &btrtl_coex.flags)) { ++ RTKBT_INFO("%s: Coex is closed, ignore", __func__); ++ return; ++ } ++ ++ rtl_l2_data_process(buffer, count, 0); ++ //u16 handle, total_len, pdu_len, channel_ID, command_len, psm, scid, ++ // dcid, result, status; ++ //u8 flag, code, identifier; ++ //u8 *pp = urb->transfer_buffer; ++ //STREAM_TO_UINT16(handle, pp); ++ //flag = handle >> 12; ++ //handle = handle & 0x0FFF; ++ //STREAM_TO_UINT16(total_len, pp); ++ //STREAM_TO_UINT16(pdu_len, pp); ++ //STREAM_TO_UINT16(channel_ID, pp); ++ ++ //if (channel_ID == 0x0001) { ++ // code = *pp++; ++ // switch (code) { ++ // case L2CAP_CONN_REQ: ++ // identifier = *pp++; ++ // STREAM_TO_UINT16(command_len, pp); ++ // STREAM_TO_UINT16(psm, pp); ++ // STREAM_TO_UINT16(scid, pp); ++ // RTKBT_DBG("RX l2cap conn req, hndl %x, PSM %x, scid %x", ++ // handle, psm, scid); ++ // handle_l2cap_con_req(handle, psm, scid, 0); ++ // break; ++ ++ // case L2CAP_CONN_RSP: ++ // identifier = *pp++; ++ // STREAM_TO_UINT16(command_len, pp); ++ // STREAM_TO_UINT16(dcid, pp); ++ // STREAM_TO_UINT16(scid, pp); ++ // STREAM_TO_UINT16(result, pp); ++ // STREAM_TO_UINT16(status, pp); ++ // RTKBT_DBG("RX l2cap conn rsp, hndl %x, dcid %x, " ++ // "scid %x, result %x", ++ // handle, dcid, scid, result); ++ // handle_l2cap_con_rsp(handle, dcid, scid, 0, result); ++ // break; ++ ++ // case L2CAP_DISCONN_REQ: ++ // identifier = *pp++; ++ // STREAM_TO_UINT16(command_len, pp); ++ // STREAM_TO_UINT16(dcid, pp); ++ // STREAM_TO_UINT16(scid, pp); ++ // RTKBT_DBG("RX l2cap disconn req, hndl %x, dcid %x, " ++ // "scid %x", handle, dcid, scid); ++ // handle_l2cap_discon_req(handle, dcid, scid, 0); ++ // break; ++ ++ // case L2CAP_DISCONN_RSP: ++ // break; ++ ++ // default: ++ // break; ++ // } ++ //} else { ++ // if ((flag != 0x01) && (is_profile_connected(profile_a2dp) || is_profile_connected(profile_pan))) //Do not count the continuous packets ++ // packets_count(handle, channel_ID, pdu_len, 0, pp); ++ //} ++} ++ ++static void polling_bt_info(unsigned long data) ++{ ++ uint8_t temp_cmd[1]; ++ RTKBT_DBG("polling timer"); ++ if (btrtl_coex.polling_enable) { ++ //temp_cmd[0] = HCI_VENDOR_SUB_CMD_BT_REPORT_CONN_SCO_INQ_INFO; ++ temp_cmd[0] = HCI_VENDOR_SUB_CMD_BT_AUTO_REPORT_STATUS_INFO; ++ rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 1, temp_cmd); ++ } ++ mod_timer(&(btrtl_coex.polling_timer), ++ jiffies + ++ msecs_to_jiffies(1000 * btrtl_coex.polling_interval)); ++} ++ ++static void rtk_handle_bt_info_control(uint8_t *p) ++{ ++ uint8_t temp_cmd[20]; ++ struct rtl_btinfo_ctl *ctl = (struct rtl_btinfo_ctl*)p; ++ RTKBT_DBG("Received polling_enable %u, polling_time %u, " ++ "autoreport_enable %u", ctl->polling_enable, ++ ctl->polling_time, ctl->autoreport_enable); ++ RTKBT_DBG("coex: original polling_enable %u", ++ btrtl_coex.polling_enable); ++ ++ if (ctl->polling_enable && !btrtl_coex.polling_enable) { ++ /* setup polling timer for getting bt info from firmware */ ++ setup_timer(&(btrtl_coex.polling_timer), polling_bt_info, 0); ++ btrtl_coex.polling_timer.expires = ++ jiffies + msecs_to_jiffies(ctl->polling_time * 1000); ++ add_timer(&(btrtl_coex.polling_timer)); ++ } ++ ++ /* Close bt info polling timer */ ++ if (!ctl->polling_enable && btrtl_coex.polling_enable) ++ del_timer(&(btrtl_coex.polling_timer)); ++ ++ if (btrtl_coex.autoreport != ctl->autoreport_enable) { ++ temp_cmd[0] = HCI_VENDOR_SUB_CMD_BT_AUTO_REPORT_ENABLE; ++ temp_cmd[1] = 1; ++ temp_cmd[2] = ctl->autoreport_enable; ++ rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 3, temp_cmd); ++ } ++ ++ btrtl_coex.polling_enable = ctl->polling_enable; ++ btrtl_coex.polling_interval = ctl->polling_time; ++ btrtl_coex.autoreport = ctl->autoreport_enable; ++ ++ rtk_notify_info_to_wifi(HOST_RESPONSE, 0, NULL); ++} ++ ++static void rtk_handle_bt_coex_control(uint8_t * p) ++{ ++ uint8_t temp_cmd[20]; ++ uint8_t opcode, opcode_len, value, power_decrease, psd_mode, ++ access_type; ++ ++ opcode = *p++; ++ RTKBT_DBG("receive bt coex control event from wifi, op 0x%02x", opcode); ++ ++ switch (opcode) { ++ case BT_PATCH_VERSION_QUERY: ++ rtk_notify_btpatch_version_to_wifi(); ++ break; ++ ++ case IGNORE_WLAN_ACTIVE_CONTROL: ++ opcode_len = *p++; ++ value = *p++; ++ temp_cmd[0] = HCI_VENDOR_SUB_CMD_BT_ENABLE_IGNORE_WLAN_ACT_CMD; ++ temp_cmd[1] = 1; ++ temp_cmd[2] = value; ++ rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 3, temp_cmd); ++ break; ++ ++ case LNA_CONSTRAIN_CONTROL: ++ opcode_len = *p++; ++ value = *p++; ++ temp_cmd[0] = HCI_VENDOR_SUB_CMD_SET_BT_LNA_CONSTRAINT; ++ temp_cmd[1] = 1; ++ temp_cmd[2] = value; ++ rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 3, temp_cmd); ++ break; ++ ++ case BT_POWER_DECREASE_CONTROL: ++ opcode_len = *p++; ++ power_decrease = *p++; ++ temp_cmd[0] = HCI_VENDOR_SUB_CMD_WIFI_FORCE_TX_POWER_CMD; ++ temp_cmd[1] = 1; ++ temp_cmd[2] = power_decrease; ++ rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 3, temp_cmd); ++ break; ++ ++ case BT_PSD_MODE_CONTROL: ++ opcode_len = *p++; ++ psd_mode = *p++; ++ temp_cmd[0] = HCI_VENDOR_SUB_CMD_SET_BT_PSD_MODE; ++ temp_cmd[1] = 1; ++ temp_cmd[2] = psd_mode; ++ rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 3, temp_cmd); ++ break; ++ ++ case WIFI_BW_CHNL_NOTIFY: ++ opcode_len = *p++; ++ temp_cmd[0] = HCI_VENDOR_SUB_CMD_WIFI_CHANNEL_AND_BANDWIDTH_CMD; ++ temp_cmd[1] = 3; ++ memcpy(temp_cmd + 2, p, 3); //wifi_state, wifi_centralchannel, chnnels_btnotuse ++ rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 5, temp_cmd); ++ break; ++ ++ case QUERY_BT_AFH_MAP: ++ opcode_len = *p++; ++ btrtl_coex.piconet_id = *p++; ++ btrtl_coex.mode = *p++; ++ temp_cmd[0] = HCI_VENDOR_SUB_CMD_GET_AFH_MAP_L; ++ temp_cmd[1] = 2; ++ temp_cmd[2] = btrtl_coex.piconet_id; ++ temp_cmd[3] = btrtl_coex.mode; ++ rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 4, temp_cmd); ++ break; ++ ++ case BT_REGISTER_ACCESS: ++ opcode_len = *p++; ++ access_type = *p++; ++ if (access_type == 0) { //read ++ temp_cmd[0] = HCI_VENDOR_SUB_CMD_RD_REG_REQ; ++ temp_cmd[1] = 5; ++ temp_cmd[2] = *p++; ++ memcpy(temp_cmd + 3, p, 4); ++ rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 7, ++ temp_cmd); ++ } else { //write ++ temp_cmd[0] = HCI_VENDOR_SUB_CMD_RD_REG_REQ; ++ temp_cmd[1] = 5; ++ temp_cmd[2] = *p++; ++ memcpy(temp_cmd + 3, p, 8); ++ rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 11, ++ temp_cmd); ++ } ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++static void rtk_handle_event_from_wifi(uint8_t * msg) ++{ ++ uint8_t *p = msg; ++ uint8_t event_code = *p++; ++ uint8_t total_length; ++ uint8_t extension_event; ++ uint8_t operation; ++ uint16_t wifi_opcode; ++ uint8_t op_status; ++ ++ if (memcmp(msg, invite_rsp, sizeof(invite_rsp)) == 0) { ++ RTKBT_DBG("receive invite rsp from wifi, wifi is already on"); ++ btrtl_coex.wifi_on = 1; ++ rtk_notify_extension_version_to_wifi(); ++ } ++ ++ if (memcmp(msg, attend_req, sizeof(attend_req)) == 0) { ++ RTKBT_DBG("receive attend req from wifi, wifi turn on"); ++ btrtl_coex.wifi_on = 1; ++ udpsocket_send(attend_ack, sizeof(attend_ack)); ++ rtk_notify_extension_version_to_wifi(); ++ } ++ ++ if (memcmp(msg, wifi_leave, sizeof(wifi_leave)) == 0) { ++ RTKBT_DBG("receive wifi leave from wifi, wifi turn off"); ++ btrtl_coex.wifi_on = 0; ++ udpsocket_send(leave_ack, sizeof(leave_ack)); ++ if (btrtl_coex.polling_enable) { ++ btrtl_coex.polling_enable = 0; ++ del_timer(&(btrtl_coex.polling_timer)); ++ } ++ } ++ ++ if (memcmp(msg, leave_ack, sizeof(leave_ack)) == 0) { ++ RTKBT_DBG("receive leave ack from wifi"); ++ } ++ ++ if (event_code == 0xFE) { ++ total_length = *p++; ++ extension_event = *p++; ++ switch (extension_event) { ++ case RTK_HS_EXTENSION_EVENT_WIFI_SCAN: ++ operation = *p; ++ RTKBT_DBG("Recv WiFi scan notify event from WiFi, " ++ "op 0x%02x", operation); ++ break; ++ ++ case RTK_HS_EXTENSION_EVENT_HCI_BT_INFO_CONTROL: ++ rtk_handle_bt_info_control(p); ++ break; ++ ++ case RTK_HS_EXTENSION_EVENT_HCI_BT_COEX_CONTROL: ++ rtk_handle_bt_coex_control(p); ++ break; ++ ++ default: ++ break; ++ } ++ } ++ ++ if (event_code == 0x0E) { ++ p += 2; //length, number of complete packets ++ STREAM_TO_UINT16(wifi_opcode, p); ++ op_status = *p; ++ RTKBT_DBG("Recv cmd complete event from WiFi, op 0x%02x, " ++ "status 0x%02x", wifi_opcode, op_status); ++ } ++} ++ ++static inline void rtl_free_frags(struct rtl_coex_struct *coex) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&coex->rxlock, flags); ++ ++ coex->elen = 0; ++ coex->tbuff = NULL; ++ ++ spin_unlock_irqrestore(&coex->rxlock, flags); ++} ++ ++void rtk_btcoex_open(struct hci_dev *hdev) ++{ ++ if (test_and_set_bit(RTL_COEX_RUNNING, &btrtl_coex.flags)) { ++ RTKBT_WARN("RTL COEX is already running."); ++ return; ++ } ++ ++ RTKBT_INFO("Open BTCOEX"); ++ ++ /* Just for test */ ++ //struct rtl_btinfo_ctl ctl; ++ ++ INIT_DELAYED_WORK(&btrtl_coex.fw_work, (void *)rtl_ev_work); ++ INIT_DELAYED_WORK(&btrtl_coex.sock_work, ++ (void *)udpsocket_recv_data); ++ INIT_DELAYED_WORK(&btrtl_coex.l2_work, (void *)rtl_l2_work); ++ ++ init_timer(&btrtl_coex.polling_timer); ++ init_timer(&btrtl_coex.a2dp_count_timer); ++ init_timer(&btrtl_coex.pan_count_timer); ++ init_timer(&btrtl_coex.hogp_count_timer); ++ ++ btrtl_coex.hdev = hdev; ++ btrtl_coex.wifi_on = 0; ++ ++ init_profile_hash(&btrtl_coex); ++ init_connection_hash(&btrtl_coex); ++ ++ btrtl_coex.pkt_type = 0; ++ btrtl_coex.expect = 0; ++ btrtl_coex.elen = 0; ++ btrtl_coex.tbuff = NULL; ++ ++ create_udpsocket(); ++ udpsocket_send(invite_req, sizeof(invite_req)); ++ ++ /* Just for test */ ++ //ctl.polling_enable = 1; ++ //ctl.polling_time = 1; ++ //ctl.autoreport_enable = 1; ++ //rtk_handle_bt_info_control((u8 *)&ctl); ++} ++ ++void rtk_btcoex_close(void) ++{ ++ int kk = 0; ++ ++ if (!test_and_clear_bit(RTL_COEX_RUNNING, &btrtl_coex.flags)) { ++ RTKBT_WARN("RTL COEX is already closed."); ++ return; ++ } ++ ++ RTKBT_INFO("Close BTCOEX"); ++ ++ /* Close coex socket */ ++ if (btrtl_coex.wifi_on) ++ udpsocket_send(bt_leave, sizeof(bt_leave)); ++ cancel_delayed_work_sync(&btrtl_coex.sock_work); ++ if (btrtl_coex.sock_open) { ++ btrtl_coex.sock_open = 0; ++ RTKBT_DBG("release udp socket"); ++ sock_release(btrtl_coex.udpsock); ++ } ++ ++ /* Delete all timers */ ++ if (btrtl_coex.polling_enable) { ++ btrtl_coex.polling_enable = 0; ++ del_timer_sync(&(btrtl_coex.polling_timer)); ++ } ++ del_timer_sync(&(btrtl_coex.a2dp_count_timer)); ++ del_timer_sync(&(btrtl_coex.pan_count_timer)); ++ ++ cancel_delayed_work_sync(&btrtl_coex.fw_work); ++ cancel_delayed_work_sync(&btrtl_coex.l2_work); ++ ++ flush_connection_hash(&btrtl_coex); ++ flush_profile_hash(&btrtl_coex); ++ btrtl_coex.profile_bitmap = 0; ++ btrtl_coex.profile_status = 0; ++ for (kk = 0; kk < 8; kk++) ++ btrtl_coex.profile_refcount[kk] = 0; ++ ++ rtl_free_frags(&btrtl_coex); ++ RTKBT_DBG("-x"); ++} ++ ++void rtk_btcoex_probe(struct hci_dev *hdev) ++{ ++ btrtl_coex.hdev = hdev; ++ spin_lock_init(&btrtl_coex.spin_lock_sock); ++ spin_lock_init(&btrtl_coex.spin_lock_profile); ++} ++ ++void rtk_btcoex_init(void) ++{ ++ RTKBT_DBG("%s: version: %s", __func__, RTK_VERSION); ++ RTKBT_DBG("create workqueue"); ++ btrtl_coex.sock_wq = create_workqueue("btudpwork"); ++ btrtl_coex.fw_wq = create_workqueue("btfwwork"); ++ rtl_alloc_buff(&btrtl_coex); ++ spin_lock_init(&btrtl_coex.rxlock); ++} ++ ++void rtk_btcoex_exit(void) ++{ ++ RTKBT_DBG("%s: destroy workqueue", __func__); ++ flush_workqueue(btrtl_coex.sock_wq); ++ destroy_workqueue(btrtl_coex.sock_wq); ++ flush_workqueue(btrtl_coex.fw_wq); ++ destroy_workqueue(btrtl_coex.fw_wq); ++ rtl_free_buff(&btrtl_coex); ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_bluetooth_rtk_coex.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_bluetooth_rtk_coex.h.patch new file mode 100644 index 00000000..88a2c8e3 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_bluetooth_rtk_coex.h.patch @@ -0,0 +1,339 @@ +diff -drupN a/drivers/bluetooth/rtk_coex.h b/drivers/bluetooth/rtk_coex.h +--- a/drivers/bluetooth/rtk_coex.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/bluetooth/rtk_coex.h 2022-06-09 05:02:28.000000000 +0300 +@@ -0,0 +1,335 @@ ++#include ++#include ++ ++/*********************************** ++** Realtek - For coexistence ** ++***********************************/ ++#define BTRTL_HCIUSB 0 ++#define BTRTL_HCIUART 1 ++ ++#define BTRTL_HCI_IF BTRTL_HCIUART ++ ++#define TRUE 1 ++#define FALSE 0 ++ ++#define CONNECT_PORT 30001 ++#define CONNECT_PORT_WIFI 30000 ++ ++#define invite_req "INVITE_REQ" ++#define invite_rsp "INVITE_RSP" ++#define attend_req "ATTEND_REQ" ++#define attend_ack "ATTEND_ACK" ++#define wifi_leave "WIFI_LEAVE" ++#define leave_ack "LEAVE_ACK" ++#define bt_leave "BT_LEAVE" ++ ++#define HCI_OP_PERIODIC_INQ 0x0403 ++#define HCI_EV_LE_META 0x3e ++#define HCI_EV_LE_CONN_COMPLETE 0x01 ++#define HCI_EV_LE_CONN_UPDATE_COMPLETE 0x03 ++ ++//vendor cmd to fw ++#define HCI_VENDOR_ENABLE_PROFILE_REPORT_COMMAND 0xfc18 ++#define HCI_VENDOR_SET_PROFILE_REPORT_COMMAND 0xfc19 ++#define HCI_VENDOR_MAILBOX_CMD 0xfc8f ++#define HCI_VENDOR_SET_BITPOOL 0xfc51 ++ ++//subcmd to fw ++#define HCI_VENDOR_SUB_CMD_WIFI_CHANNEL_AND_BANDWIDTH_CMD 0x11 ++#define HCI_VENDOR_SUB_CMD_WIFI_FORCE_TX_POWER_CMD 0x17 ++#define HCI_VENDOR_SUB_CMD_BT_ENABLE_IGNORE_WLAN_ACT_CMD 0x1B ++#define HCI_VENDOR_SUB_CMD_BT_REPORT_CONN_SCO_INQ_INFO 0x23 ++#define HCI_VENDOR_SUB_CMD_BT_AUTO_REPORT_STATUS_INFO 0x27 ++#define HCI_VENDOR_SUB_CMD_BT_AUTO_REPORT_ENABLE 0x28 ++#define HCI_VENDOR_SUB_CMD_BT_SET_TXRETRY_REPORT_PARAM 0x29 ++#define HCI_VENDOR_SUB_CMD_BT_SET_PTATABLE 0x2A ++#define HCI_VENDOR_SUB_CMD_SET_BT_PSD_MODE 0x31 ++#define HCI_VENDOR_SUB_CMD_SET_BT_LNA_CONSTRAINT 0x32 ++#define HCI_VENDOR_SUB_CMD_GET_AFH_MAP_L 0x40 ++#define HCI_VENDOR_SUB_CMD_GET_AFH_MAP_M 0x41 ++#define HCI_VENDOR_SUB_CMD_GET_AFH_MAP_H 0x42 ++#define HCI_VENDOR_SUB_CMD_RD_REG_REQ 0x43 ++#define HCI_VENDOR_SUB_CMD_WR_REG_REQ 0x44 ++ ++#define HCI_EV_VENDOR_SPECIFIC 0xff ++ ++//sub event from fw start ++#define HCI_VENDOR_PTA_REPORT_EVENT 0x24 ++#define HCI_VENDOR_PTA_AUTO_REPORT_EVENT 0x25 ++ ++//vendor cmd to wifi driver ++#define HCI_GRP_VENDOR_SPECIFIC (0x3f << 10) ++#define HCI_OP_HCI_EXTENSION_VERSION_NOTIFY (0x0100 | HCI_GRP_VENDOR_SPECIFIC) ++#define HCI_OP_BT_OPERATION_NOTIFY (0x0102 | HCI_GRP_VENDOR_SPECIFIC) ++#define HCI_OP_HCI_BT_INFO_NOTIFY (0x0106 | HCI_GRP_VENDOR_SPECIFIC) ++#define HCI_OP_HCI_BT_COEX_NOTIFY (0x0107 | HCI_GRP_VENDOR_SPECIFIC) ++#define HCI_OP_HCI_BT_PATCH_VER_NOTIFY (0x0108 | HCI_GRP_VENDOR_SPECIFIC) ++#define HCI_OP_HCI_BT_AFH_MAP_NOTIFY (0x0109 | HCI_GRP_VENDOR_SPECIFIC) ++#define HCI_OP_HCI_BT_REGISTER_VALUE_NOTIFY (0x010a | HCI_GRP_VENDOR_SPECIFIC) ++ ++//bt info reason to wifi ++#define HOST_RESPONSE 0 //Host response when receive the BT Info Control Event ++#define POLLING_RESPONSE 1 //The BT Info response for polling by BT firmware. ++#define AUTO_REPORT 2 //BT auto report by BT firmware. ++#define STACK_REPORT_WHILE_DEVICE_D2 3 //Stack report when BT firmware is under power save state(ex:D2) ++ ++// vendor event from wifi ++#define RTK_HS_EXTENSION_EVENT_WIFI_SCAN 0x01 ++#define RTK_HS_EXTENSION_EVENT_RADIO_STATUS_NOTIFY 0x02 ++#define RTK_HS_EXTENSION_EVENT_HCI_BT_INFO_CONTROL 0x03 ++#define RTK_HS_EXTENSION_EVENT_HCI_BT_COEX_CONTROL 0x04 ++ ++//op code from wifi ++#define BT_PATCH_VERSION_QUERY 0x00 ++#define IGNORE_WLAN_ACTIVE_CONTROL 0x01 ++#define LNA_CONSTRAIN_CONTROL 0x02 ++#define BT_POWER_DECREASE_CONTROL 0x03 ++#define BT_PSD_MODE_CONTROL 0x04 ++#define WIFI_BW_CHNL_NOTIFY 0x05 ++#define QUERY_BT_AFH_MAP 0x06 ++#define BT_REGISTER_ACCESS 0x07 ++ ++//bt operation to notify ++#define BT_OPCODE_NONE 0 ++#define BT_OPCODE_INQUIRY_START 1 ++#define BT_OPCODE_INQUIRY_END 2 ++#define BT_OPCODE_PAGE_START 3 ++#define BT_OPCODE_PAGE_SUCCESS_END 4 ++#define BT_OPCODE_PAGE_UNSUCCESS_END 5 ++#define BT_OPCODE_PAIR_START 6 ++#define BT_OPCODE_PAIR_END 7 ++#define BT_OPCODE_ENABLE_BT 8 ++#define BT_OPCODE_DISABLE_BT 9 ++ ++#define HCI_EXTENSION_VERSION 0x0004 ++#define HCI_CMD_PREAMBLE_SIZE 3 ++#define PAN_PACKET_COUNT 5 ++ ++#define STREAM_TO_UINT16(u16, p) {u16 = ((uint16_t)(*(p)) + (((uint16_t)(*((p) + 1))) << 8)); (p) += 2;} ++#define UINT16_TO_STREAM(p, u16) {*(p)++ = (uint8_t)(u16); *(p)++ = (uint8_t)((u16) >> 8);} ++ ++#define PSM_SDP 0x0001 ++#define PSM_RFCOMM 0x0003 ++#define PSM_PAN 0x000F ++#define PSM_HID 0x0011 ++#define PSM_HID_INT 0x0013 ++#define PSM_AVCTP 0x0017 ++#define PSM_AVDTP 0x0019 ++#define PSM_FTP 0x1001 ++#define PSM_BIP 0x1003 ++#define PSM_OPP 0x1015 ++//--add more if needed--// ++ ++enum { ++ profile_sco = 0, ++ profile_hid = 1, ++ profile_a2dp = 2, ++ profile_pan = 3, ++ profile_hid_interval = 4, ++ profile_hogp = 5, ++ profile_voice = 6, ++ profile_max = 7 ++}; ++ ++//profile info data ++typedef struct { ++ struct list_head list; ++ uint16_t handle; ++ uint16_t psm; ++ uint16_t dcid; ++ uint16_t scid; ++ uint8_t profile_index; ++} rtk_prof_info, *prtk_prof_info; ++ ++//profile info for each connection ++typedef struct rtl_hci_conn { ++ struct list_head list; ++ uint16_t handle; ++ uint8_t type; // 0:l2cap, 1:sco/esco, 2:le ++ uint8_t profile_bitmap; ++ int8_t profile_refcount[8]; ++} rtk_conn_prof, *prtk_conn_prof; ++ ++struct rtl_btinfo { ++ u8 cmd; ++ u8 len; ++ u8 data[6]; ++}; ++#define RTL_BTINFO_LEN (sizeof(struct rtl_btinfo)) ++/* typedef struct { ++ * uint8_t cmd_index; ++ * uint8_t cmd_length; ++ * uint8_t link_status; ++ * uint8_t retry_cnt; ++ * uint8_t rssi; ++ * uint8_t mailbox_info; ++ * uint16_t acl_throughput; ++ * } hci_linkstatus_report; */ ++ ++typedef struct { ++ uint8_t type; ++ uint32_t offset; ++ uint32_t value; ++} hci_mailbox_register; ++ ++struct rtl_btinfo_ctl { ++ uint8_t polling_enable; ++ uint8_t polling_time; ++ uint8_t autoreport_enable; ++}; ++ ++#define MAX_LEN_OF_HCI_EV 32 ++#define NUM_RTL_HCI_EV 32 ++struct rtl_hci_ev { ++ __u8 data[MAX_LEN_OF_HCI_EV]; ++ __u16 len; ++ struct list_head list; ++}; ++ ++#define L2_MAX_SUBSEC_LEN 128 ++#define L2_MAX_PKTS 16 ++struct rtl_l2_buff { ++ __u8 data[L2_MAX_SUBSEC_LEN]; ++ __u16 len; ++ __u16 out; ++ struct list_head list; ++}; ++ ++struct rtl_coex_struct { ++ struct list_head conn_hash; //hash for connections ++ struct list_head profile_list; //hash for profile info ++ struct hci_dev *hdev; ++ struct socket *udpsock; ++ struct sockaddr_in addr; ++ struct sockaddr_in wifi_addr; ++ struct timer_list polling_timer; ++ struct timer_list a2dp_count_timer; ++ struct timer_list pan_count_timer; ++ struct timer_list hogp_count_timer; ++ struct workqueue_struct *sock_wq; ++ struct workqueue_struct *fw_wq; ++ struct delayed_work sock_work; ++ struct delayed_work fw_work; ++ struct delayed_work l2_work; ++ struct sock *sk; ++ struct urb *urb; ++ spinlock_t spin_lock_sock; ++ spinlock_t spin_lock_profile; ++ uint32_t a2dp_packet_count; ++ uint32_t pan_packet_count; ++ uint32_t hogp_packet_count; ++ uint32_t voice_packet_count; ++ uint8_t profile_bitmap; ++ uint8_t profile_status; ++ int8_t profile_refcount[8]; ++ uint8_t ispairing; ++ uint8_t isinquirying; ++ uint8_t ispaging; ++ uint8_t wifi_state; ++ uint8_t autoreport; ++ uint8_t polling_enable; ++ uint8_t polling_interval; ++ uint8_t piconet_id; ++ uint8_t mode; ++ uint8_t afh_map[10]; ++ uint16_t hci_reversion; ++ uint16_t lmp_subversion; ++ uint8_t wifi_on; ++ uint8_t sock_open; ++ unsigned long cmd_last_tx; ++ ++ /* hci ev buff */ ++ struct list_head ev_used_list; ++ struct list_head ev_free_list; ++ ++ spinlock_t rxlock; ++ __u8 pkt_type; ++ __u16 expect; ++ __u8 *tbuff; ++ __u16 elen; ++ __u8 back_buff[HCI_MAX_EVENT_SIZE]; ++ ++ /* l2cap rx buff */ ++ struct list_head l2_used_list; ++ struct list_head l2_free_list; ++ ++ /* buff addr and size */ ++ spinlock_t buff_lock; ++ unsigned long pages_addr; ++ unsigned long buff_size; ++ ++#define RTL_COEX_RUNNING (1 << 0) ++ unsigned long flags; ++ ++}; ++ ++#ifdef __LITTLE_ENDIAN ++struct sbc_frame_hdr { ++ uint8_t syncword:8; /* Sync word */ ++ uint8_t subbands:1; /* Subbands */ ++ uint8_t allocation_method:1; /* Allocation method */ ++ uint8_t channel_mode:2; /* Channel mode */ ++ uint8_t blocks:2; /* Blocks */ ++ uint8_t sampling_frequency:2; /* Sampling frequency */ ++ uint8_t bitpool:8; /* Bitpool */ ++ uint8_t crc_check:8; /* CRC check */ ++} __attribute__ ((packed)); ++ ++/* NOTE: The code is copied from pa. ++ * only the bit field in 8-bit is affected by endian, not the 16-bit or 32-bit. ++ * why? ++ */ ++struct rtp_header { ++ unsigned cc:4; ++ unsigned x:1; ++ unsigned p:1; ++ unsigned v:2; ++ ++ unsigned pt:7; ++ unsigned m:1; ++ ++ uint16_t sequence_number; ++ uint32_t timestamp; ++ uint32_t ssrc; ++ uint32_t csrc[0]; ++} __attribute__ ((packed)); ++ ++#else ++/* big endian */ ++struct sbc_frame_hdr { ++ uint8_t syncword:8; /* Sync word */ ++ uint8_t sampling_frequency:2; /* Sampling frequency */ ++ uint8_t blocks:2; /* Blocks */ ++ uint8_t channel_mode:2; /* Channel mode */ ++ uint8_t allocation_method:1; /* Allocation method */ ++ uint8_t subbands:1; /* Subbands */ ++ uint8_t bitpool:8; /* Bitpool */ ++ uint8_t crc_check:8; /* CRC check */ ++} __attribute__ ((packed)); ++ ++struct rtp_header { ++ unsigned v:2; ++ unsigned p:1; ++ unsigned x:1; ++ unsigned cc:4; ++ ++ unsigned m:1; ++ unsigned pt:7; ++ ++ uint16_t sequence_number; ++ uint32_t timestamp; ++ uint32_t ssrc; ++ uint32_t csrc[0]; ++} __attribute__ ((packed)); ++#endif /* __LITTLE_ENDIAN */ ++ ++void rtk_btcoex_parse_event(uint8_t *buffer, int count); ++void rtk_btcoex_parse_cmd(uint8_t *buffer, int count); ++void rtk_btcoex_parse_l2cap_data_tx(uint8_t *buffer, int count); ++void rtk_btcoex_parse_l2cap_data_rx(uint8_t *buffer, int count); ++ ++void rtk_btcoex_open(struct hci_dev *hdev); ++void rtk_btcoex_close(void); ++void rtk_btcoex_probe(struct hci_dev *hdev); ++void rtk_btcoex_init(void); ++void rtk_btcoex_exit(void); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_char_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_char_Kconfig.patch new file mode 100644 index 00000000..84258393 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_char_Kconfig.patch @@ -0,0 +1,12 @@ +diff -drupN a/drivers/char/Kconfig b/drivers/char/Kconfig +--- a/drivers/char/Kconfig 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/char/Kconfig 2022-06-09 05:02:28.000000000 +0300 +@@ -15,6 +15,8 @@ config DEVMEM + memory. + When in doubt, say "Y". + ++ ++ + config DEVKMEM + bool "/dev/kmem virtual device support" + default y diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_char_hw_random_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_char_hw_random_Kconfig.patch new file mode 100644 index 00000000..f5c50b94 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_char_hw_random_Kconfig.patch @@ -0,0 +1,22 @@ +diff -drupN a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig +--- a/drivers/char/hw_random/Kconfig 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/char/hw_random/Kconfig 2022-06-09 05:02:28.000000000 +0300 +@@ -381,6 +381,18 @@ config HW_RANDOM_STM32 + + If unsure, say N. + ++config HW_RANDOM_INGENIC ++ tristate "Ingenic HW Random Number Generator support" ++ depends on MIPS && (SOC_X2000_V12 || SOC_M300) ++ help ++ This driver provides kernel-side support for the Random Number ++ Generator hardware found on Ingenic processors. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ingenic-rng. ++ ++ If unsure, say N. ++ + endif # HW_RANDOM + + config UML_RANDOM diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_char_hw_random_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_char_hw_random_Makefile.patch new file mode 100644 index 00000000..614ab781 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_char_hw_random_Makefile.patch @@ -0,0 +1,8 @@ +diff -drupN a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile +--- a/drivers/char/hw_random/Makefile 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/char/hw_random/Makefile 2022-06-09 05:02:28.000000000 +0300 +@@ -33,3 +33,4 @@ obj-$(CONFIG_HW_RANDOM_MSM) += msm-rng.o + obj-$(CONFIG_HW_RANDOM_ST) += st-rng.o + obj-$(CONFIG_HW_RANDOM_XGENE) += xgene-rng.o + obj-$(CONFIG_HW_RANDOM_STM32) += stm32-rng.o ++obj-$(CONFIG_HW_RANDOM_INGENIC) += ingenic-rng.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_char_hw_random_ingenic-rng.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_char_hw_random_ingenic-rng.c.patch new file mode 100644 index 00000000..409f33c7 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_char_hw_random_ingenic-rng.c.patch @@ -0,0 +1,256 @@ +diff -drupN a/drivers/char/hw_random/ingenic-rng.c b/drivers/char/hw_random/ingenic-rng.c +--- a/drivers/char/hw_random/ingenic-rng.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/char/hw_random/ingenic-rng.c 2022-06-09 05:02:28.000000000 +0300 +@@ -0,0 +1,252 @@ ++ ++/* ++ * dtrng driver of Ingenic's SoC X2000 ++ * ++ * Copyright (C) 2020 Ingenic Semiconductor Co., Ltd. ++ * http://www.ingenic.com ++ * Author: wenshuo.song ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define TRNG_INT_SWITCH ++#undef TRNG_INT_SWITCH ++ ++#define TRNG_CFG 0x00 ++#define TRNG_RANDOMNUM 0x04 ++#define TRNG_STATUS 0x08 ++ ++#define TRNG_CFG_RDY_CLR (1 << 12) ++#define TRNG_CFG_GEN_EN (1 << 0) ++#define TRNG_CFG_INT_MASK (1 << 11) ++ ++/*f(clk)=f(pclk)/(div_num+1)*/ ++#define TRNG_CFG_DIV_NUM 0x00 ++ ++struct ingenic_trng { ++ int irq; ++ struct clk *clk_gate; ++ void __iomem *base; ++ struct hwrng rng; ++}; ++ ++ ++ ++static irqreturn_t ingenic_trng_interrupt(int irq, void *dev_id) ++{ ++ ++ unsigned int trng_cfg; ++ unsigned int trng_randomnum; ++ struct ingenic_trng *trng = (struct ingenic_trng *)(dev_id); ++ ++ //TODO? ++ ++ trng_randomnum = readl(trng->base + TRNG_RANDOMNUM); ++ ++ /* Clear the interupt */ ++ trng_cfg = readl(trng->base + TRNG_CFG); ++ trng_cfg |= TRNG_CFG_RDY_CLR; ++ writel(trng_cfg,trng->base + TRNG_CFG); ++ trng_cfg &= ~TRNG_CFG_RDY_CLR; ++ writel(trng_cfg,trng->base + TRNG_CFG); ++ ++ return IRQ_HANDLED; ++} ++ ++static int ingenic_trng_init(struct hwrng *rng) ++{ ++ ++ unsigned int trng_cfg; ++ struct ingenic_trng *trng = container_of(rng, struct ingenic_trng, rng); ++ ++ trng_cfg = readl(trng->base + TRNG_CFG); ++ trng_cfg |= (1 << 0); ++ writel(trng_cfg, trng->base + TRNG_CFG); ++ ++ return 0; ++} ++ ++static void ingenic_trng_cleanup(struct hwrng *rng) ++{ ++ unsigned int trng_cfg; ++ struct ingenic_trng *trng = container_of(rng, struct ingenic_trng, rng); ++ ++ trng_cfg = readl(trng->base + TRNG_CFG); ++ trng_cfg &= ~TRNG_CFG_GEN_EN; ++ writel(trng_cfg, trng->base + TRNG_CFG); ++} ++ ++static int ingenic_trng_read(struct hwrng *rng, void *buf, size_t max, ++ bool wait) ++{ ++ ++ ++ struct ingenic_trng *trng = container_of(rng, struct ingenic_trng, rng); ++ unsigned int trng_cfg; ++ u32 val,tmp_data; ++ u32 *data = buf; ++ ++ /* data ready? */ ++ if (readl(trng->base + TRNG_STATUS) & 1) { ++ get_random_bytes(&val, sizeof(u32)); ++ tmp_data = readl(trng->base + TRNG_RANDOMNUM); ++ tmp_data ^= val; ++ *data = tmp_data; ++ ++ /* Clear the ramdom_rdy */ ++ trng_cfg = readl(trng->base + TRNG_CFG); ++ trng_cfg |= TRNG_CFG_RDY_CLR; ++ writel(trng_cfg,trng->base + TRNG_CFG); ++ trng_cfg &= ~TRNG_CFG_RDY_CLR; ++ writel(trng_cfg,trng->base + TRNG_CFG); ++ return 4; ++ } else ++ return 0; ++} ++ ++static int ingenic_trng_probe(struct platform_device *pdev) ++{ ++ struct ingenic_trng *trng; ++ struct resource *res; ++ int ret; ++ ++ trng = devm_kzalloc(&pdev->dev, sizeof(*trng), GFP_KERNEL); ++ if (!trng) ++ return -ENOMEM; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ trng->base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(trng->base)) ++ return PTR_ERR(trng->base); ++ ++ trng->irq = platform_get_irq(pdev, 0); ++ if(trng->irq < 0){ ++ dev_err(&pdev->dev, "Cannot get %d IORESOURCE_IRQ\n",trng->irq); ++ return -ENOENT; ++ } ++ ++ trng->clk_gate = devm_clk_get(&pdev->dev, "gate_dtrng"); ++ if (IS_ERR(trng->clk_gate)) ++ return PTR_ERR(trng->clk_gate); ++ ++ ret = clk_prepare_enable(trng->clk_gate); ++ if (ret) ++ return ret; ++ ++ ++ trng->rng.name = pdev->name; ++ trng->rng.init = ingenic_trng_init; ++ trng->rng.cleanup = ingenic_trng_cleanup; ++ trng->rng.read = ingenic_trng_read; ++ ++#ifdef TRNG_INT_SWITCH ++ writel(readl(TRNG_CFG) & ~TRNG_CFG_INT_MASK, TRNG_CFG); ++ ret = request_irq(trng->irq,ingenic_trng_interrupt, ++ IRQF_SHARED | IRQF_TRIGGER_LOW,"trng-interrupt",trng); ++ if (ret) { ++ dev_err(&pdev->dev, "request_irq failed !! %d-\n",trng->irq); ++ goto err_register; ++ } ++#endif ++ ret = hwrng_register(&trng->rng); ++ if (ret) ++ goto err_register; ++ ++ platform_set_drvdata(pdev, trng); ++ ++ dev_info(&pdev->dev, "ingenic HW dtrng Probe success!\n"); ++ return 0; ++ ++err_register: ++ clk_disable(trng->clk_gate); ++ return ret; ++} ++ ++static int ingenic_trng_remove(struct platform_device *pdev) ++{ ++ struct ingenic_trng *trng = platform_get_drvdata(pdev); ++ unsigned int trng_cfg; ++ ++ hwrng_unregister(&trng->rng); ++ ++ trng_cfg = readl(trng->base + TRNG_CFG); ++ trng_cfg &= ~(1 << 0); ++ writel(trng_cfg, trng->base + TRNG_CFG); ++ ++ clk_disable_unprepare(trng->clk_gate); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int ingenic_trng_suspend(struct device *dev) ++{ ++ struct ingenic_trng *trng = dev_get_drvdata(dev); ++ ++ clk_disable_unprepare(trng->clk_gate); ++ ++ return 0; ++} ++ ++static int ingenic_trng_resume(struct device *dev) ++{ ++ struct ingenic_trng *trng = dev_get_drvdata(dev); ++ ++ return clk_prepare_enable(trng->clk_gate); ++} ++ ++static const struct dev_pm_ops ingenic_trng_pm_ops = { ++ .suspend = ingenic_trng_suspend, ++ .resume = ingenic_trng_resume, ++}; ++#endif /* CONFIG_PM */ ++ ++static const struct of_device_id ingenic_trng_dt_ids[] = { ++ { .compatible = "ingenic,dtrng" }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, ingenic_trng_dt_ids); ++ ++static struct platform_driver ingenic_trng_driver = { ++ .probe = ingenic_trng_probe, ++ .remove = ingenic_trng_remove, ++ .driver = { ++ .name = "ingenic-trng", ++#ifdef CONFIG_PM ++ .pm = &ingenic_trng_pm_ops, ++#endif /* CONFIG_PM */ ++ .of_match_table = ingenic_trng_dt_ids, ++ }, ++}; ++ ++module_platform_driver(ingenic_trng_driver); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("wenshuo.song "); ++MODULE_DESCRIPTION("ingenic true random number generator driver"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_char_random.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_char_random.c.patch new file mode 100644 index 00000000..ada9ca3a --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_char_random.c.patch @@ -0,0 +1,15 @@ +diff -drupN a/drivers/char/random.c b/drivers/char/random.c +--- a/drivers/char/random.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/char/random.c 2022-06-09 05:02:28.000000000 +0300 +@@ -1467,9 +1467,9 @@ urandom_read(struct file *file, char __u + if (unlikely(nonblocking_pool.initialized == 0) && + maxwarn > 0) { + maxwarn--; +- printk(KERN_NOTICE "random: %s: uninitialized urandom read " ++ /* printk(KERN_NOTICE "random: %s: uninitialized urandom read " + "(%zd bytes read, %d bits of entropy available)\n", +- current->comm, nbytes, nonblocking_pool.entropy_total); ++ current->comm, nbytes, nonblocking_pool.entropy_total);*/ + } + + nbytes = min_t(size_t, nbytes, INT_MAX >> (ENTROPY_SHIFT + 3)); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_Kconfig.patch new file mode 100644 index 00000000..accdc0bc --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_Kconfig.patch @@ -0,0 +1,20 @@ +diff -drupN a/drivers/clk/Kconfig b/drivers/clk/Kconfig +--- a/drivers/clk/Kconfig 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/clk/Kconfig 2022-06-09 05:02:28.000000000 +0300 +@@ -10,8 +10,9 @@ config HAVE_MACH_CLKDEV + bool + + config COMMON_CLK +- bool +- select HAVE_CLK_PREPARE ++ bool "common clk" ++ default y ++ select HAVE_CLK_PREPARE + select CLKDEV_LOOKUP + select SRCU + select RATIONAL +@@ -198,3 +199,4 @@ source "drivers/clk/mvebu/Kconfig" + + source "drivers/clk/samsung/Kconfig" + source "drivers/clk/tegra/Kconfig" ++source "drivers/clk/ingenic/Kconfig" diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_Makefile.patch new file mode 100644 index 00000000..89bceab8 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_Makefile.patch @@ -0,0 +1,11 @@ +diff -drupN a/drivers/clk/Makefile b/drivers/clk/Makefile +--- a/drivers/clk/Makefile 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/clk/Makefile 2022-06-09 05:02:28.000000000 +0300 +@@ -54,6 +54,7 @@ obj-$(CONFIG_ARCH_BERLIN) += berlin/ + obj-$(CONFIG_ARCH_HISI) += hisilicon/ + obj-$(CONFIG_ARCH_MXC) += imx/ + obj-$(CONFIG_MACH_INGENIC) += ingenic/ ++obj-$(CONFIG_MACH_XBURST2) += ingenic/ + obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/ + obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/ + ifeq ($(CONFIG_COMMON_CLK), y) diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_clk-fixed-rate.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_clk-fixed-rate.c.patch new file mode 100644 index 00000000..9b7afd2b --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_clk-fixed-rate.c.patch @@ -0,0 +1,12 @@ +diff -drupN a/drivers/clk/clk-fixed-rate.c b/drivers/clk/clk-fixed-rate.c +--- a/drivers/clk/clk-fixed-rate.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/clk/clk-fixed-rate.c 2022-06-09 05:02:28.000000000 +0300 +@@ -85,6 +85,8 @@ struct clk *clk_register_fixed_rate_with + if (IS_ERR(clk)) + kfree(fixed); + ++ __clk_set_flags(clk, 1); ++ + return clk; + } + EXPORT_SYMBOL_GPL(clk_register_fixed_rate_with_accuracy); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_clk-fractional-divider.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_clk-fractional-divider.c.patch new file mode 100644 index 00000000..d0e045e2 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_clk-fractional-divider.c.patch @@ -0,0 +1,16 @@ +diff -drupN a/drivers/clk/clk-fractional-divider.c b/drivers/clk/clk-fractional-divider.c +--- a/drivers/clk/clk-fractional-divider.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/clk/clk-fractional-divider.c 2022-06-09 05:02:28.000000000 +0300 +@@ -149,8 +149,11 @@ struct clk *clk_register_fractional_divi + fd->hw.init = &init; + + clk = clk_register(dev, &fd->hw); +- if (IS_ERR(clk)) ++ if (IS_ERR(clk)) { + kfree(fd); ++ } else { ++ __clk_set_flags(clk, 1); ++ } + + return clk; + } diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_clk-gate.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_clk-gate.c.patch new file mode 100644 index 00000000..fa58162e --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_clk-gate.c.patch @@ -0,0 +1,19 @@ +diff -drupN a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c +--- a/drivers/clk/clk-gate.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/clk/clk-gate.c 2022-06-09 05:02:28.000000000 +0300 +@@ -79,6 +79,7 @@ static void clk_gate_endisable(struct cl + static int clk_gate_enable(struct clk_hw *hw) + { + clk_gate_endisable(hw, 1); ++ __clk_set_flags(hw->clk, 1); + + return 0; + } +@@ -86,6 +87,7 @@ static int clk_gate_enable(struct clk_hw + static void clk_gate_disable(struct clk_hw *hw) + { + clk_gate_endisable(hw, 0); ++ __clk_set_flags(hw->clk, 0); + } + + static int clk_gate_is_enabled(struct clk_hw *hw) diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_clk-mux.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_clk-mux.c.patch new file mode 100644 index 00000000..b4adc125 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_clk-mux.c.patch @@ -0,0 +1,20 @@ +diff -drupN a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c +--- a/drivers/clk/clk-mux.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/clk/clk-mux.c 2022-06-09 05:02:28.000000000 +0300 +@@ -161,11 +161,13 @@ struct clk *clk_register_mux_table(struc + mux->hw.init = &init; + + clk = clk_register(dev, &mux->hw); +- +- if (IS_ERR(clk)) ++ if (IS_ERR(clk)) { + kfree(mux); ++ } else { ++ __clk_set_flags(clk, 1); ++ } + +- return clk; ++ return clk; + } + EXPORT_SYMBOL_GPL(clk_register_mux_table); + diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_clk.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_clk.c.patch new file mode 100644 index 00000000..aa30f165 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_clk.c.patch @@ -0,0 +1,20 @@ +diff -drupN a/drivers/clk/clk.c b/drivers/clk/clk.c +--- a/drivers/clk/clk.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/clk/clk.c 2022-06-09 05:02:28.000000000 +0300 +@@ -410,6 +410,16 @@ static unsigned long __clk_get_accuracy( + return core->accuracy; + } + ++void __clk_set_flags(struct clk *clk, unsigned long enable) ++{ ++ if (1 == enable) { ++ clk->core->flags |= BIT(1); ++ } else { ++ clk->core->flags &= ~BIT(1); ++ } ++} ++EXPORT_SYMBOL_GPL(__clk_set_flags); ++ + unsigned long __clk_get_flags(struct clk *clk) + { + return !clk ? 0 : clk->core->flags; diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_Kconfig.patch new file mode 100644 index 00000000..a22f1113 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_Kconfig.patch @@ -0,0 +1,31 @@ +diff -drupN a/drivers/clk/ingenic/Kconfig b/drivers/clk/ingenic/Kconfig +--- a/drivers/clk/ingenic/Kconfig 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/clk/ingenic/Kconfig 2022-06-09 05:02:28.000000000 +0300 +@@ -0,0 +1,27 @@ ++config COMMON_CLK_INGENIC ++ bool ++ depends on MACH_XBURST || MACH_XBURST2 ++ select MFD_SYSCON ++ select COMMON_CLK ++ select INGENIC_CLK_DEBUG_FS ++ ++config INGENIC_CLK_DEBUG_FS ++ bool ++ depends on DEBUG_FS ++ help ++ enable ingenic common clock debugfs ++ ++ ++config CLK_X2000_V12 ++ bool ++ depends on SOC_X2000_V12 ++ select COMMON_CLK_INGENIC ++ help ++ build the ingenic x2000-v12 soc clock driver. ++ ++config CLK_T40 ++ bool ++ depends on SOC_T40 ++ select COMMON_CLK_INGENIC ++ help ++ build the ingenic t40 soc clock driver. diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_Makefile.patch new file mode 100644 index 00000000..43e862f5 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_Makefile.patch @@ -0,0 +1,14 @@ +diff -drupN a/drivers/clk/ingenic/Makefile b/drivers/clk/ingenic/Makefile +--- a/drivers/clk/ingenic/Makefile 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/clk/ingenic/Makefile 2022-06-09 05:02:28.000000000 +0300 +@@ -1,3 +1,7 @@ +-obj-y += cgu.o +-obj-$(CONFIG_MACH_JZ4740) += jz4740-cgu.o +-obj-$(CONFIG_MACH_JZ4780) += jz4780-cgu.o ++ ++ ++obj-$(CONFIG_COMMON_CLK) += clk.o clk-pll.o clk-div.o clk-bus.o power-gate.o ++obj-$(CONFIG_SOC_X2000_V12) += clk-x2000-v12.o ++obj-$(CONFIG_SOC_T40) += clk-t40.o ++ ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_cgu.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_cgu.c.patch new file mode 100644 index 00000000..667065c1 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_cgu.c.patch @@ -0,0 +1,716 @@ +diff -drupN a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c +--- a/drivers/clk/ingenic/cgu.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/clk/ingenic/cgu.c 1970-01-01 03:00:00.000000000 +0300 +@@ -1,712 +0,0 @@ +-/* +- * Ingenic SoC CGU driver +- * +- * Copyright (c) 2013-2015 Imagination Technologies +- * Author: Paul Burton +- * +- * 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. +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include "cgu.h" +- +-#define MHZ (1000 * 1000) +- +-/** +- * ingenic_cgu_gate_get() - get the value of clock gate register bit +- * @cgu: reference to the CGU whose registers should be read +- * @info: info struct describing the gate bit +- * +- * Retrieves the state of the clock gate bit described by info. The +- * caller must hold cgu->lock. +- * +- * Return: true if the gate bit is set, else false. +- */ +-static inline bool +-ingenic_cgu_gate_get(struct ingenic_cgu *cgu, +- const struct ingenic_cgu_gate_info *info) +-{ +- return readl(cgu->base + info->reg) & BIT(info->bit); +-} +- +-/** +- * ingenic_cgu_gate_set() - set the value of clock gate register bit +- * @cgu: reference to the CGU whose registers should be modified +- * @info: info struct describing the gate bit +- * @val: non-zero to gate a clock, otherwise zero +- * +- * Sets the given gate bit in order to gate or ungate a clock. +- * +- * The caller must hold cgu->lock. +- */ +-static inline void +-ingenic_cgu_gate_set(struct ingenic_cgu *cgu, +- const struct ingenic_cgu_gate_info *info, bool val) +-{ +- u32 clkgr = readl(cgu->base + info->reg); +- +- if (val) +- clkgr |= BIT(info->bit); +- else +- clkgr &= ~BIT(info->bit); +- +- writel(clkgr, cgu->base + info->reg); +-} +- +-/* +- * PLL operations +- */ +- +-static unsigned long +-ingenic_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) +-{ +- struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw); +- struct ingenic_cgu *cgu = ingenic_clk->cgu; +- const struct ingenic_cgu_clk_info *clk_info; +- const struct ingenic_cgu_pll_info *pll_info; +- unsigned m, n, od_enc, od; +- bool bypass, enable; +- unsigned long flags; +- u32 ctl; +- +- clk_info = &cgu->clock_info[ingenic_clk->idx]; +- BUG_ON(clk_info->type != CGU_CLK_PLL); +- pll_info = &clk_info->pll; +- +- spin_lock_irqsave(&cgu->lock, flags); +- ctl = readl(cgu->base + pll_info->reg); +- spin_unlock_irqrestore(&cgu->lock, flags); +- +- m = (ctl >> pll_info->m_shift) & GENMASK(pll_info->m_bits - 1, 0); +- m += pll_info->m_offset; +- n = (ctl >> pll_info->n_shift) & GENMASK(pll_info->n_bits - 1, 0); +- n += pll_info->n_offset; +- od_enc = ctl >> pll_info->od_shift; +- od_enc &= GENMASK(pll_info->od_bits - 1, 0); +- bypass = !!(ctl & BIT(pll_info->bypass_bit)); +- enable = !!(ctl & BIT(pll_info->enable_bit)); +- +- if (bypass) +- return parent_rate; +- +- if (!enable) +- return 0; +- +- for (od = 0; od < pll_info->od_max; od++) { +- if (pll_info->od_encoding[od] == od_enc) +- break; +- } +- BUG_ON(od == pll_info->od_max); +- od++; +- +- return div_u64((u64)parent_rate * m, n * od); +-} +- +-static unsigned long +-ingenic_pll_calc(const struct ingenic_cgu_clk_info *clk_info, +- unsigned long rate, unsigned long parent_rate, +- unsigned *pm, unsigned *pn, unsigned *pod) +-{ +- const struct ingenic_cgu_pll_info *pll_info; +- unsigned m, n, od; +- +- pll_info = &clk_info->pll; +- od = 1; +- +- /* +- * The frequency after the input divider must be between 10 and 50 MHz. +- * The highest divider yields the best resolution. +- */ +- n = parent_rate / (10 * MHZ); +- n = min_t(unsigned, n, 1 << clk_info->pll.n_bits); +- n = max_t(unsigned, n, pll_info->n_offset); +- +- m = (rate / MHZ) * od * n / (parent_rate / MHZ); +- m = min_t(unsigned, m, 1 << clk_info->pll.m_bits); +- m = max_t(unsigned, m, pll_info->m_offset); +- +- if (pm) +- *pm = m; +- if (pn) +- *pn = n; +- if (pod) +- *pod = od; +- +- return div_u64((u64)parent_rate * m, n * od); +-} +- +-static long +-ingenic_pll_round_rate(struct clk_hw *hw, unsigned long req_rate, +- unsigned long *prate) +-{ +- struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw); +- struct ingenic_cgu *cgu = ingenic_clk->cgu; +- const struct ingenic_cgu_clk_info *clk_info; +- +- clk_info = &cgu->clock_info[ingenic_clk->idx]; +- BUG_ON(clk_info->type != CGU_CLK_PLL); +- +- return ingenic_pll_calc(clk_info, req_rate, *prate, NULL, NULL, NULL); +-} +- +-static int +-ingenic_pll_set_rate(struct clk_hw *hw, unsigned long req_rate, +- unsigned long parent_rate) +-{ +- const unsigned timeout = 100; +- struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw); +- struct ingenic_cgu *cgu = ingenic_clk->cgu; +- const struct ingenic_cgu_clk_info *clk_info; +- const struct ingenic_cgu_pll_info *pll_info; +- unsigned long rate, flags; +- unsigned m, n, od, i; +- u32 ctl; +- +- clk_info = &cgu->clock_info[ingenic_clk->idx]; +- BUG_ON(clk_info->type != CGU_CLK_PLL); +- pll_info = &clk_info->pll; +- +- rate = ingenic_pll_calc(clk_info, req_rate, parent_rate, +- &m, &n, &od); +- if (rate != req_rate) +- pr_info("ingenic-cgu: request '%s' rate %luHz, actual %luHz\n", +- clk_info->name, req_rate, rate); +- +- spin_lock_irqsave(&cgu->lock, flags); +- ctl = readl(cgu->base + pll_info->reg); +- +- ctl &= ~(GENMASK(pll_info->m_bits - 1, 0) << pll_info->m_shift); +- ctl |= (m - pll_info->m_offset) << pll_info->m_shift; +- +- ctl &= ~(GENMASK(pll_info->n_bits - 1, 0) << pll_info->n_shift); +- ctl |= (n - pll_info->n_offset) << pll_info->n_shift; +- +- ctl &= ~(GENMASK(pll_info->od_bits - 1, 0) << pll_info->od_shift); +- ctl |= pll_info->od_encoding[od - 1] << pll_info->od_shift; +- +- ctl &= ~BIT(pll_info->bypass_bit); +- ctl |= BIT(pll_info->enable_bit); +- +- writel(ctl, cgu->base + pll_info->reg); +- +- /* wait for the PLL to stabilise */ +- for (i = 0; i < timeout; i++) { +- ctl = readl(cgu->base + pll_info->reg); +- if (ctl & BIT(pll_info->stable_bit)) +- break; +- mdelay(1); +- } +- +- spin_unlock_irqrestore(&cgu->lock, flags); +- +- if (i == timeout) +- return -EBUSY; +- +- return 0; +-} +- +-static const struct clk_ops ingenic_pll_ops = { +- .recalc_rate = ingenic_pll_recalc_rate, +- .round_rate = ingenic_pll_round_rate, +- .set_rate = ingenic_pll_set_rate, +-}; +- +-/* +- * Operations for all non-PLL clocks +- */ +- +-static u8 ingenic_clk_get_parent(struct clk_hw *hw) +-{ +- struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw); +- struct ingenic_cgu *cgu = ingenic_clk->cgu; +- const struct ingenic_cgu_clk_info *clk_info; +- u32 reg; +- u8 i, hw_idx, idx = 0; +- +- clk_info = &cgu->clock_info[ingenic_clk->idx]; +- +- if (clk_info->type & CGU_CLK_MUX) { +- reg = readl(cgu->base + clk_info->mux.reg); +- hw_idx = (reg >> clk_info->mux.shift) & +- GENMASK(clk_info->mux.bits - 1, 0); +- +- /* +- * Convert the hardware index to the parent index by skipping +- * over any -1's in the parents array. +- */ +- for (i = 0; i < hw_idx; i++) { +- if (clk_info->parents[i] != -1) +- idx++; +- } +- } +- +- return idx; +-} +- +-static int ingenic_clk_set_parent(struct clk_hw *hw, u8 idx) +-{ +- struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw); +- struct ingenic_cgu *cgu = ingenic_clk->cgu; +- const struct ingenic_cgu_clk_info *clk_info; +- unsigned long flags; +- u8 curr_idx, hw_idx, num_poss; +- u32 reg, mask; +- +- clk_info = &cgu->clock_info[ingenic_clk->idx]; +- +- if (clk_info->type & CGU_CLK_MUX) { +- /* +- * Convert the parent index to the hardware index by adding +- * 1 for any -1 in the parents array preceding the given +- * index. That is, we want the index of idx'th entry in +- * clk_info->parents which does not equal -1. +- */ +- hw_idx = curr_idx = 0; +- num_poss = 1 << clk_info->mux.bits; +- for (; hw_idx < num_poss; hw_idx++) { +- if (clk_info->parents[hw_idx] == -1) +- continue; +- if (curr_idx == idx) +- break; +- curr_idx++; +- } +- +- /* idx should always be a valid parent */ +- BUG_ON(curr_idx != idx); +- +- mask = GENMASK(clk_info->mux.bits - 1, 0); +- mask <<= clk_info->mux.shift; +- +- spin_lock_irqsave(&cgu->lock, flags); +- +- /* write the register */ +- reg = readl(cgu->base + clk_info->mux.reg); +- reg &= ~mask; +- reg |= hw_idx << clk_info->mux.shift; +- writel(reg, cgu->base + clk_info->mux.reg); +- +- spin_unlock_irqrestore(&cgu->lock, flags); +- return 0; +- } +- +- return idx ? -EINVAL : 0; +-} +- +-static unsigned long +-ingenic_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) +-{ +- struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw); +- struct ingenic_cgu *cgu = ingenic_clk->cgu; +- const struct ingenic_cgu_clk_info *clk_info; +- unsigned long rate = parent_rate; +- u32 div_reg, div; +- +- clk_info = &cgu->clock_info[ingenic_clk->idx]; +- +- if (clk_info->type & CGU_CLK_DIV) { +- div_reg = readl(cgu->base + clk_info->div.reg); +- div = (div_reg >> clk_info->div.shift) & +- GENMASK(clk_info->div.bits - 1, 0); +- div += 1; +- +- rate /= div; +- } +- +- return rate; +-} +- +-static unsigned +-ingenic_clk_calc_div(const struct ingenic_cgu_clk_info *clk_info, +- unsigned long parent_rate, unsigned long req_rate) +-{ +- unsigned div; +- +- /* calculate the divide */ +- div = DIV_ROUND_UP(parent_rate, req_rate); +- +- /* and impose hardware constraints */ +- div = min_t(unsigned, div, 1 << clk_info->div.bits); +- div = max_t(unsigned, div, 1); +- +- return div; +-} +- +-static long +-ingenic_clk_round_rate(struct clk_hw *hw, unsigned long req_rate, +- unsigned long *parent_rate) +-{ +- struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw); +- struct ingenic_cgu *cgu = ingenic_clk->cgu; +- const struct ingenic_cgu_clk_info *clk_info; +- long rate = *parent_rate; +- +- clk_info = &cgu->clock_info[ingenic_clk->idx]; +- +- if (clk_info->type & CGU_CLK_DIV) +- rate /= ingenic_clk_calc_div(clk_info, *parent_rate, req_rate); +- else if (clk_info->type & CGU_CLK_FIXDIV) +- rate /= clk_info->fixdiv.div; +- +- return rate; +-} +- +-static int +-ingenic_clk_set_rate(struct clk_hw *hw, unsigned long req_rate, +- unsigned long parent_rate) +-{ +- struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw); +- struct ingenic_cgu *cgu = ingenic_clk->cgu; +- const struct ingenic_cgu_clk_info *clk_info; +- const unsigned timeout = 100; +- unsigned long rate, flags; +- unsigned div, i; +- u32 reg, mask; +- int ret = 0; +- +- clk_info = &cgu->clock_info[ingenic_clk->idx]; +- +- if (clk_info->type & CGU_CLK_DIV) { +- div = ingenic_clk_calc_div(clk_info, parent_rate, req_rate); +- rate = parent_rate / div; +- +- if (rate != req_rate) +- return -EINVAL; +- +- spin_lock_irqsave(&cgu->lock, flags); +- reg = readl(cgu->base + clk_info->div.reg); +- +- /* update the divide */ +- mask = GENMASK(clk_info->div.bits - 1, 0); +- reg &= ~(mask << clk_info->div.shift); +- reg |= (div - 1) << clk_info->div.shift; +- +- /* clear the stop bit */ +- if (clk_info->div.stop_bit != -1) +- reg &= ~BIT(clk_info->div.stop_bit); +- +- /* set the change enable bit */ +- if (clk_info->div.ce_bit != -1) +- reg |= BIT(clk_info->div.ce_bit); +- +- /* update the hardware */ +- writel(reg, cgu->base + clk_info->div.reg); +- +- /* wait for the change to take effect */ +- if (clk_info->div.busy_bit != -1) { +- for (i = 0; i < timeout; i++) { +- reg = readl(cgu->base + clk_info->div.reg); +- if (!(reg & BIT(clk_info->div.busy_bit))) +- break; +- mdelay(1); +- } +- if (i == timeout) +- ret = -EBUSY; +- } +- +- spin_unlock_irqrestore(&cgu->lock, flags); +- return ret; +- } +- +- return -EINVAL; +-} +- +-static int ingenic_clk_enable(struct clk_hw *hw) +-{ +- struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw); +- struct ingenic_cgu *cgu = ingenic_clk->cgu; +- const struct ingenic_cgu_clk_info *clk_info; +- unsigned long flags; +- +- clk_info = &cgu->clock_info[ingenic_clk->idx]; +- +- if (clk_info->type & CGU_CLK_GATE) { +- /* ungate the clock */ +- spin_lock_irqsave(&cgu->lock, flags); +- ingenic_cgu_gate_set(cgu, &clk_info->gate, false); +- spin_unlock_irqrestore(&cgu->lock, flags); +- } +- +- return 0; +-} +- +-static void ingenic_clk_disable(struct clk_hw *hw) +-{ +- struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw); +- struct ingenic_cgu *cgu = ingenic_clk->cgu; +- const struct ingenic_cgu_clk_info *clk_info; +- unsigned long flags; +- +- clk_info = &cgu->clock_info[ingenic_clk->idx]; +- +- if (clk_info->type & CGU_CLK_GATE) { +- /* gate the clock */ +- spin_lock_irqsave(&cgu->lock, flags); +- ingenic_cgu_gate_set(cgu, &clk_info->gate, true); +- spin_unlock_irqrestore(&cgu->lock, flags); +- } +-} +- +-static int ingenic_clk_is_enabled(struct clk_hw *hw) +-{ +- struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw); +- struct ingenic_cgu *cgu = ingenic_clk->cgu; +- const struct ingenic_cgu_clk_info *clk_info; +- unsigned long flags; +- int enabled = 1; +- +- clk_info = &cgu->clock_info[ingenic_clk->idx]; +- +- if (clk_info->type & CGU_CLK_GATE) { +- spin_lock_irqsave(&cgu->lock, flags); +- enabled = !ingenic_cgu_gate_get(cgu, &clk_info->gate); +- spin_unlock_irqrestore(&cgu->lock, flags); +- } +- +- return enabled; +-} +- +-static const struct clk_ops ingenic_clk_ops = { +- .get_parent = ingenic_clk_get_parent, +- .set_parent = ingenic_clk_set_parent, +- +- .recalc_rate = ingenic_clk_recalc_rate, +- .round_rate = ingenic_clk_round_rate, +- .set_rate = ingenic_clk_set_rate, +- +- .enable = ingenic_clk_enable, +- .disable = ingenic_clk_disable, +- .is_enabled = ingenic_clk_is_enabled, +-}; +- +-/* +- * Setup functions. +- */ +- +-static int ingenic_register_clock(struct ingenic_cgu *cgu, unsigned idx) +-{ +- const struct ingenic_cgu_clk_info *clk_info = &cgu->clock_info[idx]; +- struct clk_init_data clk_init; +- struct ingenic_clk *ingenic_clk = NULL; +- struct clk *clk, *parent; +- const char *parent_names[4]; +- unsigned caps, i, num_possible; +- int err = -EINVAL; +- +- BUILD_BUG_ON(ARRAY_SIZE(clk_info->parents) > ARRAY_SIZE(parent_names)); +- +- if (clk_info->type == CGU_CLK_EXT) { +- clk = of_clk_get_by_name(cgu->np, clk_info->name); +- if (IS_ERR(clk)) { +- pr_err("%s: no external clock '%s' provided\n", +- __func__, clk_info->name); +- err = -ENODEV; +- goto out; +- } +- err = clk_register_clkdev(clk, clk_info->name, NULL); +- if (err) { +- clk_put(clk); +- goto out; +- } +- cgu->clocks.clks[idx] = clk; +- return 0; +- } +- +- if (!clk_info->type) { +- pr_err("%s: no clock type specified for '%s'\n", __func__, +- clk_info->name); +- goto out; +- } +- +- ingenic_clk = kzalloc(sizeof(*ingenic_clk), GFP_KERNEL); +- if (!ingenic_clk) { +- err = -ENOMEM; +- goto out; +- } +- +- ingenic_clk->hw.init = &clk_init; +- ingenic_clk->cgu = cgu; +- ingenic_clk->idx = idx; +- +- clk_init.name = clk_info->name; +- clk_init.flags = 0; +- clk_init.parent_names = parent_names; +- +- caps = clk_info->type; +- +- if (caps & (CGU_CLK_MUX | CGU_CLK_CUSTOM)) { +- clk_init.num_parents = 0; +- +- if (caps & CGU_CLK_MUX) +- num_possible = 1 << clk_info->mux.bits; +- else +- num_possible = ARRAY_SIZE(clk_info->parents); +- +- for (i = 0; i < num_possible; i++) { +- if (clk_info->parents[i] == -1) +- continue; +- +- parent = cgu->clocks.clks[clk_info->parents[i]]; +- parent_names[clk_init.num_parents] = +- __clk_get_name(parent); +- clk_init.num_parents++; +- } +- +- BUG_ON(!clk_init.num_parents); +- BUG_ON(clk_init.num_parents > ARRAY_SIZE(parent_names)); +- } else { +- BUG_ON(clk_info->parents[0] == -1); +- clk_init.num_parents = 1; +- parent = cgu->clocks.clks[clk_info->parents[0]]; +- parent_names[0] = __clk_get_name(parent); +- } +- +- if (caps & CGU_CLK_CUSTOM) { +- clk_init.ops = clk_info->custom.clk_ops; +- +- caps &= ~CGU_CLK_CUSTOM; +- +- if (caps) { +- pr_err("%s: custom clock may not be combined with type 0x%x\n", +- __func__, caps); +- goto out; +- } +- } else if (caps & CGU_CLK_PLL) { +- clk_init.ops = &ingenic_pll_ops; +- +- caps &= ~CGU_CLK_PLL; +- +- if (caps) { +- pr_err("%s: PLL may not be combined with type 0x%x\n", +- __func__, caps); +- goto out; +- } +- } else { +- clk_init.ops = &ingenic_clk_ops; +- } +- +- /* nothing to do for gates or fixed dividers */ +- caps &= ~(CGU_CLK_GATE | CGU_CLK_FIXDIV); +- +- if (caps & CGU_CLK_MUX) { +- if (!(caps & CGU_CLK_MUX_GLITCHFREE)) +- clk_init.flags |= CLK_SET_PARENT_GATE; +- +- caps &= ~(CGU_CLK_MUX | CGU_CLK_MUX_GLITCHFREE); +- } +- +- if (caps & CGU_CLK_DIV) { +- caps &= ~CGU_CLK_DIV; +- } else { +- /* pass rate changes to the parent clock */ +- clk_init.flags |= CLK_SET_RATE_PARENT; +- } +- +- if (caps) { +- pr_err("%s: unknown clock type 0x%x\n", __func__, caps); +- goto out; +- } +- +- clk = clk_register(NULL, &ingenic_clk->hw); +- if (IS_ERR(clk)) { +- pr_err("%s: failed to register clock '%s'\n", __func__, +- clk_info->name); +- err = PTR_ERR(clk); +- goto out; +- } +- +- err = clk_register_clkdev(clk, clk_info->name, NULL); +- if (err) +- goto out; +- +- cgu->clocks.clks[idx] = clk; +-out: +- if (err) +- kfree(ingenic_clk); +- return err; +-} +- +-struct ingenic_cgu * +-ingenic_cgu_new(const struct ingenic_cgu_clk_info *clock_info, +- unsigned num_clocks, struct device_node *np) +-{ +- struct ingenic_cgu *cgu; +- +- cgu = kzalloc(sizeof(*cgu), GFP_KERNEL); +- if (!cgu) +- goto err_out; +- +- cgu->base = of_iomap(np, 0); +- if (!cgu->base) { +- pr_err("%s: failed to map CGU registers\n", __func__); +- goto err_out_free; +- } +- +- cgu->np = np; +- cgu->clock_info = clock_info; +- cgu->clocks.clk_num = num_clocks; +- +- spin_lock_init(&cgu->lock); +- +- return cgu; +- +-err_out_free: +- kfree(cgu); +-err_out: +- return NULL; +-} +- +-int ingenic_cgu_register_clocks(struct ingenic_cgu *cgu) +-{ +- unsigned i; +- int err; +- +- cgu->clocks.clks = kcalloc(cgu->clocks.clk_num, sizeof(struct clk *), +- GFP_KERNEL); +- if (!cgu->clocks.clks) { +- err = -ENOMEM; +- goto err_out; +- } +- +- for (i = 0; i < cgu->clocks.clk_num; i++) { +- err = ingenic_register_clock(cgu, i); +- if (err) +- goto err_out_unregister; +- } +- +- err = of_clk_add_provider(cgu->np, of_clk_src_onecell_get, +- &cgu->clocks); +- if (err) +- goto err_out_unregister; +- +- return 0; +- +-err_out_unregister: +- for (i = 0; i < cgu->clocks.clk_num; i++) { +- if (!cgu->clocks.clks[i]) +- continue; +- if (cgu->clock_info[i].type & CGU_CLK_EXT) +- clk_put(cgu->clocks.clks[i]); +- else +- clk_unregister(cgu->clocks.clks[i]); +- } +- kfree(cgu->clocks.clks); +-err_out: +- return err; +-} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_cgu.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_cgu.h.patch new file mode 100644 index 00000000..1f2584f1 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_cgu.h.patch @@ -0,0 +1,227 @@ +diff -drupN a/drivers/clk/ingenic/cgu.h b/drivers/clk/ingenic/cgu.h +--- a/drivers/clk/ingenic/cgu.h 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/clk/ingenic/cgu.h 1970-01-01 03:00:00.000000000 +0300 +@@ -1,223 +0,0 @@ +-/* +- * Ingenic SoC CGU driver +- * +- * Copyright (c) 2013-2015 Imagination Technologies +- * Author: Paul Burton +- * +- * 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. +- */ +- +-#ifndef __DRIVERS_CLK_INGENIC_CGU_H__ +-#define __DRIVERS_CLK_INGENIC_CGU_H__ +- +-#include +-#include +-#include +- +-/** +- * struct ingenic_cgu_pll_info - information about a PLL +- * @reg: the offset of the PLL's control register within the CGU +- * @m_shift: the number of bits to shift the multiplier value by (ie. the +- * index of the lowest bit of the multiplier value in the PLL's +- * control register) +- * @m_bits: the size of the multiplier field in bits +- * @m_offset: the multiplier value which encodes to 0 in the PLL's control +- * register +- * @n_shift: the number of bits to shift the divider value by (ie. the +- * index of the lowest bit of the divider value in the PLL's +- * control register) +- * @n_bits: the size of the divider field in bits +- * @n_offset: the divider value which encodes to 0 in the PLL's control +- * register +- * @od_shift: the number of bits to shift the post-VCO divider value by (ie. +- * the index of the lowest bit of the post-VCO divider value in +- * the PLL's control register) +- * @od_bits: the size of the post-VCO divider field in bits +- * @od_max: the maximum post-VCO divider value +- * @od_encoding: a pointer to an array mapping post-VCO divider values to +- * their encoded values in the PLL control register, or -1 for +- * unsupported values +- * @bypass_bit: the index of the bypass bit in the PLL control register +- * @enable_bit: the index of the enable bit in the PLL control register +- * @stable_bit: the index of the stable bit in the PLL control register +- */ +-struct ingenic_cgu_pll_info { +- unsigned reg; +- const s8 *od_encoding; +- u8 m_shift, m_bits, m_offset; +- u8 n_shift, n_bits, n_offset; +- u8 od_shift, od_bits, od_max; +- u8 bypass_bit; +- u8 enable_bit; +- u8 stable_bit; +-}; +- +-/** +- * struct ingenic_cgu_mux_info - information about a clock mux +- * @reg: offset of the mux control register within the CGU +- * @shift: number of bits to shift the mux value by (ie. the index of +- * the lowest bit of the mux value within its control register) +- * @bits: the size of the mux value in bits +- */ +-struct ingenic_cgu_mux_info { +- unsigned reg; +- u8 shift; +- u8 bits; +-}; +- +-/** +- * struct ingenic_cgu_div_info - information about a divider +- * @reg: offset of the divider control register within the CGU +- * @shift: number of bits to shift the divide value by (ie. the index of +- * the lowest bit of the divide value within its control register) +- * @bits: the size of the divide value in bits +- * @ce_bit: the index of the change enable bit within reg, or -1 if there +- * isn't one +- * @busy_bit: the index of the busy bit within reg, or -1 if there isn't one +- * @stop_bit: the index of the stop bit within reg, or -1 if there isn't one +- */ +-struct ingenic_cgu_div_info { +- unsigned reg; +- u8 shift; +- u8 bits; +- s8 ce_bit; +- s8 busy_bit; +- s8 stop_bit; +-}; +- +-/** +- * struct ingenic_cgu_fixdiv_info - information about a fixed divider +- * @div: the divider applied to the parent clock +- */ +-struct ingenic_cgu_fixdiv_info { +- unsigned div; +-}; +- +-/** +- * struct ingenic_cgu_gate_info - information about a clock gate +- * @reg: offset of the gate control register within the CGU +- * @bit: offset of the bit in the register that controls the gate +- */ +-struct ingenic_cgu_gate_info { +- unsigned reg; +- u8 bit; +-}; +- +-/** +- * struct ingenic_cgu_custom_info - information about a custom (SoC) clock +- * @clk_ops: custom clock operation callbacks +- */ +-struct ingenic_cgu_custom_info { +- struct clk_ops *clk_ops; +-}; +- +-/** +- * struct ingenic_cgu_clk_info - information about a clock +- * @name: name of the clock +- * @type: a bitmask formed from CGU_CLK_* values +- * @parents: an array of the indices of potential parents of this clock +- * within the clock_info array of the CGU, or -1 in entries +- * which correspond to no valid parent +- * @pll: information valid if type includes CGU_CLK_PLL +- * @gate: information valid if type includes CGU_CLK_GATE +- * @mux: information valid if type includes CGU_CLK_MUX +- * @div: information valid if type includes CGU_CLK_DIV +- * @fixdiv: information valid if type includes CGU_CLK_FIXDIV +- * @custom: information valid if type includes CGU_CLK_CUSTOM +- */ +-struct ingenic_cgu_clk_info { +- const char *name; +- +- enum { +- CGU_CLK_NONE = 0, +- CGU_CLK_EXT = BIT(0), +- CGU_CLK_PLL = BIT(1), +- CGU_CLK_GATE = BIT(2), +- CGU_CLK_MUX = BIT(3), +- CGU_CLK_MUX_GLITCHFREE = BIT(4), +- CGU_CLK_DIV = BIT(5), +- CGU_CLK_FIXDIV = BIT(6), +- CGU_CLK_CUSTOM = BIT(7), +- } type; +- +- int parents[4]; +- +- union { +- struct ingenic_cgu_pll_info pll; +- +- struct { +- struct ingenic_cgu_gate_info gate; +- struct ingenic_cgu_mux_info mux; +- struct ingenic_cgu_div_info div; +- struct ingenic_cgu_fixdiv_info fixdiv; +- }; +- +- struct ingenic_cgu_custom_info custom; +- }; +-}; +- +-/** +- * struct ingenic_cgu - data about the CGU +- * @np: the device tree node that caused the CGU to be probed +- * @base: the ioremap'ed base address of the CGU registers +- * @clock_info: an array containing information about implemented clocks +- * @clocks: used to provide clocks to DT, allows lookup of struct clk* +- * @lock: lock to be held whilst manipulating CGU registers +- */ +-struct ingenic_cgu { +- struct device_node *np; +- void __iomem *base; +- +- const struct ingenic_cgu_clk_info *clock_info; +- struct clk_onecell_data clocks; +- +- spinlock_t lock; +-}; +- +-/** +- * struct ingenic_clk - private data for a clock +- * @hw: see Documentation/clk.txt +- * @cgu: a pointer to the CGU data +- * @idx: the index of this clock in cgu->clock_info +- */ +-struct ingenic_clk { +- struct clk_hw hw; +- struct ingenic_cgu *cgu; +- unsigned idx; +-}; +- +-#define to_ingenic_clk(_hw) container_of(_hw, struct ingenic_clk, hw) +- +-/** +- * ingenic_cgu_new() - create a new CGU instance +- * @clock_info: an array of clock information structures describing the clocks +- * which are implemented by the CGU +- * @num_clocks: the number of entries in clock_info +- * @np: the device tree node which causes this CGU to be probed +- * +- * Return: a pointer to the CGU instance if initialisation is successful, +- * otherwise NULL. +- */ +-struct ingenic_cgu * +-ingenic_cgu_new(const struct ingenic_cgu_clk_info *clock_info, +- unsigned num_clocks, struct device_node *np); +- +-/** +- * ingenic_cgu_register_clocks() - Registers the clocks +- * @cgu: pointer to cgu data +- * +- * Register the clocks described by the CGU with the common clock framework. +- * +- * Return: 0 on success or -errno if unsuccesful. +- */ +-int ingenic_cgu_register_clocks(struct ingenic_cgu *cgu); +- +-#endif /* __DRIVERS_CLK_INGENIC_CGU_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_clk-bus.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_clk-bus.c.patch new file mode 100644 index 00000000..f7331d24 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_clk-bus.c.patch @@ -0,0 +1,244 @@ +diff -drupN a/drivers/clk/ingenic/clk-bus.c b/drivers/clk/ingenic/clk-bus.c +--- a/drivers/clk/ingenic/clk-bus.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/clk/ingenic/clk-bus.c 2022-06-09 05:02:28.000000000 +0300 +@@ -0,0 +1,240 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "clk.h" ++ ++static int clk_bus_wait(void __iomem *reg, u8 shift) ++{ ++ unsigned int timeout = 0xfffff; ++ ++ while (((readl(reg) >> shift) & 1) && timeout--); ++ if (!timeout) { ++ printk("WARNING : why cannot wait bus stable ???\n"); ++ return -EIO; ++ } else { ++ return 0; ++ } ++} ++ ++struct clk_bus_divider { ++ struct clk_divider div; ++ const struct clk_ops *div_ops; ++ ++ void __iomem *busy_reg; ++ ++ int busy_shift; ++ int ce_shift; ++ ++ int shift1; ++ int width1; ++ int shift2; ++ int width2; ++ ++ int div_flags; ++ ++ spinlock_t * lock; ++}; ++ ++static inline struct clk_bus *to_clk_bus_divider(struct clk_hw *hw) ++{ ++ struct clk_divider *div = container_of(hw, struct clk_divider, hw); ++ ++ return container_of(div, struct clk_bus_divider, div); ++} ++ ++static unsigned long clk_bus_divider_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct clk_bus_divider *bus_div = to_clk_bus_divider(hw); ++ struct clk_divider *divider = &bus_div->div; ++ ++ divider->shift = bus_div->shift1; ++ divider->width = bus_div->width1; ++ ++ return bus_div->div_ops->recalc_rate(&bus_div->div.hw, parent_rate); ++} ++ ++static long clk_bus_divider_round_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long *prate) ++{ ++ struct clk_bus_divider *bus_div = to_clk_bus_divider(hw); ++ ++ return bus_div->div_ops->round_rate(&bus_div->div.hw, rate, prate); ++} ++ ++static int clk_bus_divider_set_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ struct clk_bus_divider *bus_div = to_clk_bus_divider(hw); ++ struct clk_divider *divider = &bus_div->div; ++ int ret; ++ unsigned long flags = 0; ++ unsigned int val; ++ int ce = bus_div->ce_shift; ++ ++ ++ if(bus_div->lock) { ++ spin_lock_irqsave(bus_div->lock, flags); ++ } ++ ++ /* set bus rate . */ ++ if (bus_div->div_flags == BUS_DIV_SELF) { ++ ret = bus_div->div_ops->set_rate(&bus_div->div.hw, rate, parent_rate); ++ } else if (bus_div->div_flags == BUS_DIV_ONE) { ++ ++ divider->shift = bus_div->shift1; ++ divider->width = bus_div->width1; ++ ret = bus_div->div_ops->set_rate(&bus_div->div.hw, rate, parent_rate); ++ ++ divider->shift = bus_div->shift2; ++ divider->width = bus_div->width2; ++ ret = bus_div->div_ops->set_rate(&bus_div->div.hw, rate, parent_rate); ++ } else if (bus_div->div_flags == BUS_DIV_TWO) { ++ ++ divider->shift = bus_div->shift1; ++ divider->width = bus_div->width1; ++ ret = bus_div->div_ops->set_rate(&bus_div->div.hw, rate, parent_rate); ++ ++ divider->shift = bus_div->shift2; ++ divider->width = bus_div->width2; ++ ret = bus_div->div_ops->set_rate(&bus_div->div.hw, rate / 2, parent_rate); ++ } ++ ++ /* ce */ ++ if(ce > 0) { ++ val = readl(bus_div->div.reg); ++ val |= (1 << ce); ++ writel(val, bus_div->div.reg); ++ ++ ret = clk_bus_wait(bus_div->busy_reg, bus_div->busy_shift); ++ if(ret < 0) { ++ pr_err("wait bus clk: (%s) stable timeout!\n", __clk_get_name(hw->clk)); ++ } ++ ++ val &= ~(1 << ce); ++ writel(val, bus_div->div.reg); ++ } ++ if(bus_div->lock) { ++ spin_unlock_irqrestore(bus_div->lock, flags); ++ } ++ ++ return ret; ++} ++ ++ ++static struct clk_ops clk_bus_divider_ops = { ++ .recalc_rate = clk_bus_divider_recalc_rate, ++ .round_rate = clk_bus_divider_round_rate, ++ .set_rate = clk_bus_divider_set_rate, ++}; ++ ++struct clk *_register_bus_divider(struct device *dev, const char *name, ++ const char *parent_name, unsigned long flags, ++ void __iomem *reg, u8 shift1, u8 width1, u8 shift2, u8 width2, ++ void __iomem *busy_reg, u8 busy_shift, ++ int ce_shift, ++ u8 clk_divider_flags, u8 div_flags, ++ const struct clk_div_table *table, ++ spinlock_t *lock) ++{ ++ struct clk_bus_divider *bus_div; ++ struct clk *clk; ++ struct clk_init_data init; ++ ++ bus_div = kzalloc(sizeof(*bus_div), GFP_KERNEL); ++ if (!bus_div) ++ return ERR_PTR(-ENOMEM); ++ ++ init.name = name; ++ init.ops = &clk_bus_divider_ops; ++ init.flags = flags | CLK_IS_BASIC; ++ init.parent_names = (parent_name ? &parent_name: NULL); ++ init.num_parents = (parent_name ? 1 : 0); ++ ++ bus_div->busy_reg = busy_reg; ++ bus_div->busy_shift = busy_shift; ++ bus_div->ce_shift = ce_shift; ++ bus_div->lock = lock; ++ ++ bus_div->div.reg = reg; ++ bus_div->div.shift = shift1; ++ bus_div->div.width = width1; ++ bus_div->shift1 = shift1; ++ bus_div->width1 = width1; ++ bus_div->shift2 = shift2; ++ bus_div->width2 = width2; ++ //bus_div->div.lock = lock; ++ bus_div->div.lock = NULL; /* keep common block unlocked. add lock in this file */ ++ bus_div->div.table = table; ++ bus_div->div.flags = clk_divider_flags ; ++ bus_div->div_ops = &clk_divider_ops; ++ bus_div->div_flags = div_flags ; ++ ++ ++ bus_div->div.hw.init = &init; ++ ++ clk = clk_register(dev, &bus_div->div.hw); ++ if (IS_ERR(clk)) { ++ kfree(bus_div); ++ } else { ++ __clk_set_flags(clk, 1); ++ } ++ ++ return clk; ++} ++ ++/** ++ * clk_register_bus_divider_table - register a table based divider clock with ++ * the clock framework ++ * @dev: device registering this clock ++ * @name: name of this clock ++ * @parent_name: name of clock's parent ++ * @flags: framework-specific flags ++ * @reg: register address to adjust divider ++ * @shift: number of bits to shift the bitfield ++ * @busy_reg: register address of busy bit waiting. ++ * @busy_shift: bit index of busy in busy register. ++ * @width: width of the bitfield ++ * @clk_divider_flags: divider-specific flags for this clock ++ * @table: array of divider/value pairs ending with a div set to 0 ++ * @lock: shared register lock for this clock ++ */ ++struct clk *clk_register_bus_divider_table(struct device *dev, const char *name, ++ const char *parent_name, unsigned long flags, ++ void __iomem *reg, u8 shift1, u8 width1, u8 shift2, u8 width2, ++ void __iomem *busy_reg, u8 busy_shift, int ce_shift, ++ u8 clk_divider_flags, u8 div_flags, ++ const struct clk_div_table *table, ++ spinlock_t *lock) ++{ ++ return _register_bus_divider(dev, name, parent_name, flags, reg, shift1, ++ width1, shift2, width2, busy_reg, busy_shift, ce_shift, clk_divider_flags, div_flags, table, lock); ++} ++ ++ ++/** ++ * clk_register_bus_divider - register a divider clock with the clock framework ++ * @dev: device registering this clock ++ * @name: name of this clock ++ * @parent_name: name of clock's parent ++ * @flags: framework-specific flags ++ * @reg: register address to adjust divider ++ * @shift: number of bits to shift the bitfield ++ * @width: width of the bitfield ++ * @busy_reg: register address of busy bit waiting. ++ * @busy_shift: bit index of busy in busy register. ++ * @clk_divider_flags: divider-specific flags for this clock ++ * @lock: shared register lock for this clock ++ */ ++struct clk *clk_register_bus_divider(struct device *dev, const char *name, ++ const char *parent_name, unsigned long flags, ++ void __iomem *reg, u8 shift1 , u8 width1, u8 shift2, u8 width2, ++ void __iomem *busy_reg, u8 busy_shift, int ce_shift, ++ u8 clk_divider_flags, u8 div_flags, spinlock_t *lock) ++{ ++ return _register_bus_divider(dev, name, parent_name, flags, reg, shift1, width1, shift2, width2, busy_reg, busy_shift, ce_shift, clk_divider_flags, div_flags, NULL, lock); ++} ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_clk-bus.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_clk-bus.h.patch new file mode 100644 index 00000000..61abafb8 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_clk-bus.h.patch @@ -0,0 +1,28 @@ +diff -drupN a/drivers/clk/ingenic/clk-bus.h b/drivers/clk/ingenic/clk-bus.h +--- a/drivers/clk/ingenic/clk-bus.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/clk/ingenic/clk-bus.h 2022-06-09 05:02:28.000000000 +0300 +@@ -0,0 +1,24 @@ ++#ifndef __INGENIC_CLK_BUS_DIVIDER_H ++#define __INGENIC_CLK_BUS_DIVIDER_H ++ ++#define BUS_DIV_SELF BIT(6) + 1 ++#define BUS_DIV_ONE BIT(6) + 2 ++#define BUS_DIV_TWO BIT(6) + 3 ++#define BUS_DIV_THREE BIT(6) + 4 ++#define BUS_DIV_FORE BIT(6) + 5 ++ ++ ++struct clk *clk_register_bus_divider_table(struct device *dev, const char *name, ++ const char *parent_name, unsigned long flags, ++ void __iomem *reg, u8 shift1, u8 width1, u8 shift2, u8 width2, ++ void __iomem *busy_reg, u8 busy_shift, int ce_shift, ++ u8 clk_divider_flags, u8 divider_flags, ++ const struct clk_div_table *table, ++ spinlock_t *lock); ++ ++struct clk *clk_register_bus_divider(struct device *dev, const char *name, ++ const char *parent_name, unsigned long flags, ++ void __iomem *reg, u8 shift1, u8 width1, u8 shift2, u8 width2, ++ void __iomem *busy_reg, u8 busy_shift, int ce_shift, ++ u8 clk_divider_flags, u8 divider_flags, spinlock_t *lock); ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_clk-div.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_clk-div.c.patch new file mode 100644 index 00000000..b4d26500 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_clk-div.c.patch @@ -0,0 +1,265 @@ +diff -drupN a/drivers/clk/ingenic/clk-div.c b/drivers/clk/ingenic/clk-div.c +--- a/drivers/clk/ingenic/clk-div.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/clk/ingenic/clk-div.c 2022-06-09 05:02:28.000000000 +0300 +@@ -0,0 +1,261 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "clk.h" ++ ++ ++struct clk_cgu_divider { ++ struct clk_divider div; ++ const struct clk_ops *div_ops; ++ int busy_shift; ++ int en_shift; ++ int stop_shift; ++ spinlock_t *lock; ++}; ++ ++ ++static int clk_cgu_wait(void __iomem *reg, u8 shift) ++{ ++ unsigned int timeout = 0xfffff; ++ ++ while (((readl(reg) >> shift) & 1) && timeout--); ++ if (!timeout) { ++ printk("WARNING : why cannot wait cgu stable ???\n"); ++ return -EIO; ++ } else { ++ return 0; ++ } ++ ++} ++ ++static int cgu_divider_enable(struct clk_cgu_divider *cgu_div) ++{ ++ int ret; ++ unsigned int val; ++ int ce, stop; ++ ++ val = readl(cgu_div->div.reg); ++ ++ ce = cgu_div->en_shift; ++ stop = cgu_div->stop_shift; ++ ++ val |= (1 << ce); ++ val &= ~(1 << stop); ++ writel(val, cgu_div->div.reg); ++ ++ ret = clk_cgu_wait(cgu_div->div.reg, cgu_div->busy_shift); ++ if(ret < 0) { ++ printk("wait cgu stable timeout!\n"); ++ } ++ ++ val &= ~(1 << ce); ++ writel(val, cgu_div->div.reg); ++ ++ return ret; ++} ++ ++static void cgu_divider_disable(struct clk_cgu_divider *cgu_div) ++{ ++ unsigned int val; ++ int ce, stop; ++ ++ val = readl(cgu_div->div.reg); ++ ++ ce = cgu_div->en_shift; ++ stop = cgu_div->stop_shift; ++ ++ val |= (1 << ce); ++ val |= (1 << stop); ++ writel(val, cgu_div->div.reg); ++ ++ val &= ~(1 << ce); ++ writel(val, cgu_div->div.reg); ++ ++} ++ ++static inline struct clk_cgu_divider *to_clk_cgu_divider(struct clk_hw *hw) ++{ ++ struct clk_divider *div = container_of(hw, struct clk_divider, hw); ++ ++ return container_of(div, struct clk_cgu_divider, div); ++} ++ ++static unsigned long clk_cgu_divider_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct clk_cgu_divider *cgu_div = to_clk_cgu_divider(hw); ++ struct clk_divider *divider = &cgu_div->div; ++ ++ return cgu_div->div_ops->recalc_rate(&cgu_div->div.hw, parent_rate); ++} ++ ++static long clk_cgu_divider_round_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long *prate) ++{ ++ struct clk_cgu_divider *cgu_div = to_clk_cgu_divider(hw); ++ unsigned long bestrate; ++ ++ return cgu_div->div_ops->round_rate(&cgu_div->div.hw, rate, prate); ++} ++ ++static int clk_cgu_divider_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) ++{ ++ struct clk_cgu_divider *cgu_div = to_clk_cgu_divider(hw); ++ struct clk_divider *divider = &cgu_div->div; ++ int ret; ++ unsigned long flags = 0; ++ ++ if(cgu_div->lock) ++ spin_lock_irqsave(cgu_div->lock, flags); ++ ++ ret = cgu_div->div_ops->set_rate(&cgu_div->div.hw, rate, parent_rate); ++ ++ cgu_divider_enable(cgu_div); ++ ++ ++ if(cgu_div->lock) ++ spin_unlock_irqrestore(cgu_div->lock, flags); ++ ++ return ret; ++} ++ ++static void clk_cgu_divider_disable(struct clk_hw *hw) ++{ ++ struct clk_cgu_divider *cgu_div = to_clk_cgu_divider(hw); ++ unsigned long flags = 0; ++ ++ if(cgu_div->lock) ++ spin_lock_irqsave(cgu_div->lock, flags); ++ ++ cgu_divider_disable(cgu_div); ++ ++ if(cgu_div->lock) ++ spin_unlock_irqrestore(cgu_div->lock, flags); ++ ++} ++ ++ ++static int clk_cgu_divider_enable(struct clk_hw *hw) ++{ ++ struct clk_cgu_divider *cgu_div = to_clk_cgu_divider(hw); ++ unsigned long flags = 0; ++ ++ if(cgu_div->lock) ++ spin_lock_irqsave(cgu_div->lock, flags); ++ ++ cgu_divider_enable(cgu_div); ++ ++ if(cgu_div->lock) ++ spin_unlock_irqrestore(cgu_div->lock, flags); ++ ++ return 0; ++} ++ ++static struct clk_ops clk_cgu_divider_ops = { ++ .recalc_rate = clk_cgu_divider_recalc_rate, ++ .round_rate = clk_cgu_divider_round_rate, ++ .set_rate = clk_cgu_divider_set_rate, ++ .enable = clk_cgu_divider_enable, ++ .disable = clk_cgu_divider_disable, ++}; ++ ++struct clk *_register_cgu_divider(struct device *dev, const char *name, ++ const char *parent_name, unsigned long flags, ++ void __iomem *reg, u8 shift, u8 width, u8 busy_shift, ++ int en_shift, u8 stop_shift, u8 clk_divider_flags, ++ const struct clk_div_table *table, ++ spinlock_t *lock) ++{ ++ struct clk_cgu_divider *cgu_div; ++ struct clk *clk; ++ struct clk_init_data init; ++ ++ cgu_div = kzalloc(sizeof(*cgu_div), GFP_KERNEL); ++ if (!cgu_div) ++ return ERR_PTR(-ENOMEM); ++ ++ init.name = name; ++ init.ops = &clk_cgu_divider_ops; ++ init.flags = flags | CLK_IS_BASIC; ++ init.parent_names = (parent_name ? &parent_name: NULL); ++ init.num_parents = (parent_name ? 1 : 0); ++ ++ cgu_div->busy_shift = busy_shift; ++ cgu_div->en_shift = en_shift; ++ cgu_div->stop_shift = stop_shift; ++ cgu_div->lock = lock; ++ ++ cgu_div->div.reg = reg; ++ cgu_div->div.shift = shift; ++ cgu_div->div.width = width; ++ //cgu_div->div.lock = lock; ++ cgu_div->div.lock = NULL; /* keep common block unlocked. add lock in this file */ ++ cgu_div->div.table = table; ++ cgu_div->div.flags = clk_divider_flags; ++ cgu_div->div_ops = &clk_divider_ops; ++ ++ ++ cgu_div->div.hw.init = &init; ++ ++ clk = clk_register(dev, &cgu_div->div.hw); ++ if (IS_ERR(clk)) { ++ kfree(cgu_div); ++ } else { ++ __clk_set_flags(clk, 1); ++ } ++ ++ return clk; ++} ++ ++/** ++ * clk_register_divider_table - register a table based divider clock with ++ * the clock framework ++ * @dev: device registering this clock ++ * @name: name of this clock ++ * @parent_name: name of clock's parent ++ * @flags: framework-specific flags ++ * @reg: register address to adjust divider ++ * @shift: number of bits to shift the bitfield ++ * @busy_shift: bit index of busy in busy register. ++ * @width: width of the bitfield ++ * @clk_divider_flags: divider-specific flags for this clock ++ * @table: array of divider/value pairs ending with a div set to 0 ++ * @lock: shared register lock for this clock ++ */ ++struct clk *clk_register_cgu_divider_table(struct device *dev, const char *name, ++ const char *parent_name, unsigned long flags, ++ void __iomem *reg, u8 shift, u8 width, u8 busy_shift, ++ int en_shift, u8 stop_shift, u8 clk_divider_flags, ++ const struct clk_div_table *table, ++ spinlock_t *lock) ++{ ++ return _register_cgu_divider(dev, name, parent_name, flags, reg, shift, ++ width, busy_shift, en_shift, stop_shift, clk_divider_flags, table, lock); ++} ++ ++ ++/** ++ * clk_register_divider - register a divider clock with the clock framework ++ * @dev: device registering this clock ++ * @name: name of this clock ++ * @parent_name: name of clock's parent ++ * @flags: framework-specific flags ++ * @reg: register address to adjust divider ++ * @shift: number of bits to shift the bitfield ++ * @width: width of the bitfield ++ * @busy_shift: bit index of busy in busy register. ++ * @clk_divider_flags: divider-specific flags for this clock ++ * @lock: shared register lock for this clock ++ */ ++struct clk *clk_register_cgu_divider(struct device *dev, const char *name, ++ const char *parent_name, unsigned long flags, ++ void __iomem *reg, u8 shift, u8 width, u8 busy_shift, ++ int en_shift, u8 stop_shift, ++ u8 clk_divider_flags, spinlock_t *lock) ++{ ++ return _register_cgu_divider(dev, name, parent_name, flags, reg, shift, width, busy_shift, en_shift, stop_shift, clk_divider_flags, NULL, lock); ++} ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_clk-div.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_clk-div.h.patch new file mode 100644 index 00000000..18f61926 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_clk-div.h.patch @@ -0,0 +1,22 @@ +diff -drupN a/drivers/clk/ingenic/clk-div.h b/drivers/clk/ingenic/clk-div.h +--- a/drivers/clk/ingenic/clk-div.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/clk/ingenic/clk-div.h 2022-06-09 05:02:28.000000000 +0300 +@@ -0,0 +1,18 @@ ++#ifndef __INGENIC_CLK_CGU_DIVIDER_H ++#define __INGENIC_CLK_CGU_DIVIDER_H ++ ++ ++struct clk *clk_register_cgu_divider_table(struct device *dev, const char *name, ++ const char *parent_name, unsigned long flags, ++ void __iomem *reg, u8 shift, u8 width, u8 busy_shift, ++ int en_shift, u8 stop_shift, u8 clk_divider_flags, ++ const struct clk_div_table *table, ++ spinlock_t *lock); ++ ++struct clk *clk_register_cgu_divider(struct device *dev, const char *name, ++ const char *parent_name, unsigned long flags, ++ void __iomem *reg, u8 shift, u8 width, u8 busy_shift, ++ int en_shift, u8 stop_shift, ++ u8 clk_divider_flags, spinlock_t *lock); ++ ++#endif /* __SAMSUNG_CLK_PLL_H */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_clk-pll.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_clk-pll.c.patch new file mode 100644 index 00000000..fc7fcb5c --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_clk-pll.c.patch @@ -0,0 +1,184 @@ +diff -drupN a/drivers/clk/ingenic/clk-pll.c b/drivers/clk/ingenic/clk-pll.c +--- a/drivers/clk/ingenic/clk-pll.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/clk/ingenic/clk-pll.c 2022-06-09 05:02:28.000000000 +0300 +@@ -0,0 +1,180 @@ ++#include ++#include ++#include ++#include ++#include ++#include "clk.h" ++#include "clk-pll.h" ++ ++#define PLL_TIMEOUT_MS 10 ++ ++struct ingenic_clk_pll { ++ struct clk_hw hw; ++ void __iomem *lock_reg; ++ void __iomem *con_reg; ++ unsigned int rate_count; ++ ++ struct ingenic_pll_hwdesc *hwdesc; ++ struct ingenic_pll_rate_table *rate_table; ++ ++}; ++ ++#define to_clk_pll(_hw) container_of(_hw, struct ingenic_clk_pll, hw) ++ ++static long ingenic_pll_round_rate(struct clk_hw *hw, unsigned long drate, unsigned long *prate) ++{ ++ struct ingenic_clk_pll *pll = to_clk_pll(hw); ++ const struct ingenic_pll_rate_table *rate_table = pll->rate_table; ++ int i; ++ unsigned int rate; ++ ++ /* if pll can't find rate in rate_table, pll can set to big than rate */ ++ for (i = 0; i < pll->rate_count; i++) { ++ if (drate == rate_table[i].rate) ++ return rate_table[i].rate; ++ } ++ ++ for (i = 0; i < pll->rate_count; i++) { ++ if (drate >= rate_table[i].rate) ++ return rate_table[i].rate; ++ } ++ ++ return rate_table[i - 1].rate; ++ ++} ++ ++static unsigned long ingenic_t40_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) ++{ ++ struct ingenic_clk_pll *pll = to_clk_pll(hw); ++ unsigned od0, m, n, od1; ++ uint32_t val; ++ uint32_t rate; ++ ++ val = readl(pll->con_reg); ++ ++ od0 = (val >> pll->hwdesc->od0_sft) & GENMASK(pll->hwdesc->od0_width - 1, 0); ++ od1 = (val >> pll->hwdesc->od1_sft) & GENMASK(pll->hwdesc->od1_width - 1, 0); ++ n = (val >> pll->hwdesc->n_sft) & GENMASK(pll->hwdesc->n_width - 1, 0); ++ m = (val >> pll->hwdesc->m_sft) & GENMASK(pll->hwdesc->m_width - 1, 0); ++ ++ rate = (parent_rate / 1000000 ) * m / n / od0 / od1; ++ ++ //printk("od0: %d, od1: %d, m: %d, n: %d, tmp: %x, tmp2: %x, rate:%ld\n", od0, od1, m, n, tmp, tmp2, rate); ++ rate = rate*1000000; ++ ++ return rate; ++} ++ ++static int wait_pll_stable(void __iomem *reg, u32 shift) ++{ ++ unsigned int timeout = 0xffff; ++ ++ while ((!((readl(reg) >> shift) & 1)) && timeout--); ++ if (!timeout) { ++ printk("WARNING : why cannot wait pll stable ???\n"); ++ return -EIO; ++ } else { ++ return 0; ++ } ++} ++ ++static int ingenic_t40_pll_set_rate(struct clk_hw *hw, unsigned long drate, unsigned long prate) ++{ ++ struct ingenic_clk_pll *pll = to_clk_pll(hw); ++ ++ unsigned int m, n, od1, od0; ++ unsigned int val, i; ++ ++ for (i = 0; i < pll->rate_count; i++) { ++ if (drate == pll->rate_table[i].rate) { ++ m = pll->rate_table[i].m; ++ n = pll->rate_table[i].n; ++ od1 = pll->rate_table[i].od1; ++ od0 = pll->rate_table[i].od0; ++ } ++ } ++ ++ writel(0, pll->con_reg); ++ val = (m << pll->hwdesc->m_sft) | (n << pll->hwdesc->n_sft) | (od1 << pll->hwdesc->od1_sft) | (od0 << pll->hwdesc->od0_sft) | 1; ++ writel(val, pll->con_reg); ++ ++ wait_pll_stable(pll->con_reg, pll->hwdesc->on_bit); ++ ++ return 0; ++} ++ ++static const struct clk_ops ingenic_t40_pll_clk_ops = { ++ .recalc_rate = ingenic_t40_pll_recalc_rate, ++ .round_rate = ingenic_pll_round_rate, ++ .set_rate = ingenic_t40_pll_set_rate, ++}; ++ ++static void __init _ingenic_clk_register_pll(struct ingenic_clk_provider *ctx, ++ const struct ingenic_pll_clock *pll_clk, ++ void __iomem *base) ++{ ++ struct ingenic_clk_pll *pll; ++ struct clk *clk; ++ struct clk_init_data init; ++ int ret, len; ++ ++ pll = kzalloc(sizeof(*pll), GFP_KERNEL); ++ if (!pll) { ++ pr_err("%s: could not allocate pll clk %s\n", ++ __func__, pll_clk->dev_name); ++ return; ++ } ++ ++ init.name = pll_clk->dev_name; ++// init.flags = pll_clk->flags; ++ init.parent_names = &pll_clk->parent_name; ++ init.num_parents = 1; ++ init.ops = &ingenic_t40_pll_clk_ops; ++ ++ ++ pll->hw.init = &init; ++ pll->hwdesc = pll_clk->hwdesc; ++ pll->con_reg = base + pll_clk->hwdesc->regoff; ++ ++ if (pll_clk->rate_table) { ++ /* find count of rates in rate_table */ ++ for (len = 0; pll_clk->rate_table[len].rate != 0; ) ++ len++; ++ ++ pll->rate_count = len - 1; ++ pll->rate_table = kmemdup(pll_clk->rate_table, ++ pll->rate_count * ++ sizeof(struct ingenic_pll_rate_table), ++ GFP_KERNEL); ++ WARN(!pll->rate_table, ++ "%s: could not allocate rate table for %s\n", ++ __func__, pll_clk->name); ++ } ++ ++ clk = clk_register(NULL, &pll->hw); ++ if (IS_ERR(clk)) { ++ pr_err("%s: failed to register pll clock %s : %ld\n", ++ __func__, pll_clk->dev_name, PTR_ERR(clk)); ++ kfree(pll); ++ return; ++ } ++ ++ __clk_set_flags(clk, 1); ++ ingenic_clk_add_lookup(ctx, clk, pll_clk->id); ++ ++ ++ ret = clk_register_clkdev(clk, pll_clk->dev_name, NULL); ++ if (ret) ++ pr_err("%s: failed to register lookup for %s : %d", ++ __func__, pll_clk->dev_name, ret); ++} ++ ++void __init ingenic_clk_register_pll(struct ingenic_clk_provider *ctx, ++ const struct ingenic_pll_clock *pll_list, ++ unsigned int nr_pll, void __iomem *base) ++{ ++ int cnt; ++ ++ for (cnt = 0; cnt < nr_pll; cnt++) ++ _ingenic_clk_register_pll(ctx, &pll_list[cnt], base); ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_clk-pll.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_clk-pll.h.patch new file mode 100644 index 00000000..2d48de44 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_clk-pll.h.patch @@ -0,0 +1,59 @@ +diff -drupN a/drivers/clk/ingenic/clk-pll.h b/drivers/clk/ingenic/clk-pll.h +--- a/drivers/clk/ingenic/clk-pll.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/clk/ingenic/clk-pll.h 2022-06-09 05:02:28.000000000 +0300 +@@ -0,0 +1,55 @@ ++#ifndef __INGENIC_CLK_PLLV_H__ ++#define __INGENIC_CLK_PLLV_H__ ++ ++ ++extern const struct clk_ops ingenic_pll_ro_ops; ++ ++#define PLL_RATE(_rate, _m, _n, _od1, _od0) \ ++{ \ ++ .rate = _rate, \ ++ .m = _m, \ ++ .n = _n, \ ++ .od1 = _od1, \ ++ .od0 = _od0, \ ++} ++ ++struct ingenic_pll_rate_table { ++ unsigned int rate; ++ unsigned int m; ++ unsigned int n; ++ unsigned int od1; ++ unsigned int od0; ++}; ++ ++#define PLL_DESC(_regoff, _m, _m_w, _n, _n_w, _od1, _od1_w, _od0, _od0_w, _on, _en, _bs) \ ++{ \ ++ .regoff = _regoff, \ ++ .m_sft = _m, \ ++ .m_width = _m_w, \ ++ .n_sft = _n, \ ++ .n_width = _n_w, \ ++ .od1_sft = _od1, \ ++ .od1_width = _od1_w, \ ++ .od0_sft = _od0, \ ++ .od0_width = _od0_w, \ ++ .on_bit = _on, \ ++ .en_bit = _en, \ ++ .bs_bit = _bs, \ ++} ++ ++struct ingenic_pll_hwdesc { ++ u32 regoff; ++ u8 m_sft; ++ u8 m_width; ++ u8 n_sft; ++ u8 n_width; ++ u8 od1_sft; ++ u8 od1_width; ++ u8 od0_sft; ++ u8 od0_width; ++ u8 on_bit; ++ u8 en_bit; ++ s8 bs_bit; ++}; ++ ++#endif /*__INGENIC_CLK_PLLV1_H__*/ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_clk-t40.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_clk-t40.c.patch new file mode 100644 index 00000000..15360788 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_clk-t40.c.patch @@ -0,0 +1,369 @@ +diff -drupN a/drivers/clk/ingenic/clk-t40.c b/drivers/clk/ingenic/clk-t40.c +--- a/drivers/clk/ingenic/clk-t40.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/clk/ingenic/clk-t40.c 2022-06-09 05:02:28.000000000 +0300 +@@ -0,0 +1,365 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include "clk.h" ++ ++#define CLK_FLG_ENABLE BIT(1) ++static struct ingenic_clk_provider *ctx; ++ ++ ++/******************************************************************************* ++ * FIXED CLK ++ ********************************************************************************/ ++static struct ingenic_fixed_rate_clock t40_fixed_rate_ext_clks[] __initdata = { ++ FRATE(CLK_EXT, "ext", NULL, CLK_IS_ROOT, 24000000), ++ FRATE(CLK_RTC_EXT, "rtc_ext", NULL, CLK_IS_ROOT, 32768), ++}; ++ ++ ++ ++/******************************************************************************* ++ * PLL ++ ********************************************************************************/ ++ ++static struct ingenic_pll_rate_table t40_pll_rate_table[] = { ++ PLL_RATE(1800000000, 150, 1, 2, 1), ++ PLL_RATE(1608000000, 134, 1, 2, 1), ++ PLL_RATE(1500000000, 125, 1, 2, 1), ++ PLL_RATE(1404000000, 117, 1, 2, 1), ++ PLL_RATE(1400000000, 350, 3, 2, 1), ++ PLL_RATE(1392000000, 116, 1, 2, 1), ++ PLL_RATE(1308000000, 109, 1, 2, 1), ++ PLL_RATE(1296000000, 108, 1, 2, 1), ++ PLL_RATE(1200000000, 100, 1, 2, 1), ++ PLL_RATE(1104000000, 92, 1, 2, 1), ++ PLL_RATE(1100000000, 275, 2, 3, 1), ++ PLL_RATE(1080000000, 90, 1, 2, 1), ++ PLL_RATE(1008000000, 84, 1, 2, 1), ++ PLL_RATE(1000000000, 125, 1, 3, 1), ++ PLL_RATE(900000000, 75, 1, 2, 1), ++ PLL_RATE(891000000, 297, 4, 2, 1), ++ PLL_RATE(864000000, 72, 1, 2, 1), ++ PLL_RATE(600000000, 75, 1, 3, 1), ++}; ++ ++ ++ ++/*PLL HWDESC*/ ++static struct ingenic_pll_hwdesc apll_hwdesc = \ ++ PLL_DESC(CPM_CPAPCR, 20, 12, 14, 6, 11, 3, 8, 3, 3, 0, 2); ++ ++static struct ingenic_pll_hwdesc mpll_hwdesc = \ ++ PLL_DESC(CPM_CPMPCR, 20, 12, 14, 6, 11, 3, 8, 3, 3, 0, 2); ++ ++static struct ingenic_pll_hwdesc vpll_hwdesc = \ ++ PLL_DESC(CPM_CPVPCR, 20, 12, 14, 6, 11, 3, 8, 3, 3, 0, 2); ++ ++static struct ingenic_pll_hwdesc epll_hwdesc = \ ++ PLL_DESC(CPM_CPEPCR, 20, 12, 14, 6, 11, 3, 8, 3, 3, 0, 2); ++ ++ ++ ++static struct ingenic_pll_clock t40_pll_clks[] __initdata = { ++ PLL(CLK_PLL_APLL, "apll", "ext", &apll_hwdesc, t40_pll_rate_table), ++ PLL(CLK_PLL_MPLL, "mpll", "ext", &mpll_hwdesc, t40_pll_rate_table), ++ PLL(CLK_PLL_VPLL, "vpll", "ext", &vpll_hwdesc, t40_pll_rate_table), ++ PLL(CLK_PLL_EPLL, "epll", "ext", &epll_hwdesc, t40_pll_rate_table), ++}; ++ ++ ++/******************************************************************************* ++ * MUX ++ ********************************************************************************/ ++PNAME(mux_table_0) = {"stop", "ext", "apll"}; ++PNAME(mux_table_1) = {"stop", "sclka", "mpll"}; ++PNAME(mux_table_2) = {"sclka", "mpll", "vpll", "epll"}; ++PNAME(mux_table_3) = {"sclka", "mpll", "epll", "ext"}; ++PNAME(mux_table_4) = {"sclka", "vpll", "ext"}; ++PNAME(mux_table_5) = {"mux_ahb2", "ext"}; ++ ++static unsigned int ingenic_mux_table[] = {0, 1, 2, 3}; ++ ++ ++static struct ingenic_mux_clock t40_mux_clks[] __initdata = { ++ MUX(CLK_MUX_SCLKA, "sclka", ingenic_mux_table, mux_table_0, CPM_CPCCR, 30, 2, 0), ++ MUX(CLK_MUX_CPU_L2C, "mux_cpu_l2c", ingenic_mux_table, mux_table_1, CPM_CPCCR, 28, 2, 0), ++ MUX(CLK_MUX_AHB0, "mux_ahb0", ingenic_mux_table, mux_table_1, CPM_CPCCR, 26, 2, 0), ++ MUX(CLK_MUX_AHB2, "mux_ahb2", ingenic_mux_table, mux_table_1, CPM_CPCCR, 24, 2, 0), ++ ++ MUX(CLK_MUX_DDR, "mux_ddr", ingenic_mux_table, mux_table_1, CPM_DDRCDR, 30, 2, 0), ++ MUX(CLK_MUX_EL150, "mux_el150", ingenic_mux_table, mux_table_2, CPM_EL150CDR, 30, 2, 0), ++ MUX(CLK_MUX_RSA, "mux_rsa", ingenic_mux_table, mux_table_2, CPM_RSACDR, 30, 2, 0), ++ MUX(CLK_MUX_MACPHY, "mux_macphy", ingenic_mux_table, mux_table_2, CPM_MACCDR, 30, 2, 0), ++ MUX(CLK_MUX_SFC, "mux_sfc", ingenic_mux_table, mux_table_2, CPM_SFCCDR, 30, 2, 0), ++ MUX(CLK_MUX_LCD, "mux_lcd", ingenic_mux_table, mux_table_2, CPM_LPCDR, 30, 2, 0), ++ MUX(CLK_MUX_MSC0, "mux_msc0", ingenic_mux_table, mux_table_2, CPM_MSC0CDR, 30, 2, 0), ++ MUX(CLK_MUX_MSC1, "mux_msc1", ingenic_mux_table, mux_table_2, CPM_MSC1CDR, 30, 2, 0), ++ MUX(CLK_MUX_SSI, "mux_ssi", ingenic_mux_table, mux_table_2, CPM_SSICDR, 30, 2, 0), ++ MUX(CLK_MUX_I2ST, "mux_i2st", ingenic_mux_table, mux_table_2, CPM_I2STCDR, 30, 2, 0), ++ MUX(CLK_MUX_ISP, "mux_isp", ingenic_mux_table, mux_table_2, CPM_ISPCDR, 30, 2, 0), ++ MUX(CLK_MUX_I2SR, "mux_i2sr", ingenic_mux_table, mux_table_2, CPM_I2STCDR, 30, 2, 0), ++ MUX(CLK_MUX_CIM0, "mux_cim0", ingenic_mux_table, mux_table_2, CPM_CIM0CDR, 30, 2, 0), ++ MUX(CLK_MUX_CIM1, "mux_cim1", ingenic_mux_table, mux_table_2, CPM_CIM1CDR, 30, 2, 0), ++ MUX(CLK_MUX_CIM2, "mux_cim2", ingenic_mux_table, mux_table_2, CPM_CIM2CDR, 30, 2, 0), ++ MUX(CLK_MUX_BSCALER, "mux_bscaler", ingenic_mux_table, mux_table_2, CPM_BSCALERCDR, 30, 2, 0), ++ MUX(CLK_MUX_BT0, "mux_bt0", ingenic_mux_table, mux_table_2, CPM_BT0CDR, 30, 2, 0), ++ ++}; ++ ++/******************************************************************************* ++ * DIV BUS ++ ********************************************************************************/ ++ ++static struct ingenic_bus_clock t40_bus_div_clks[] __initdata = { ++ BUS_DIV(CLK_DIV_CPU, "div_cpu", "mux_cpu_l2c", CPM_CPCCR, 0, 4, 0, 0, CPM_CPCSR, 0, 22, BUS_DIV_SELF), ++ BUS_DIV(CLK_DIV_L2C, "div_l2c", "mux_cpu_l2c", CPM_CPCCR, 4, 4, 0, 0, CPM_CPCSR, 0, 22, BUS_DIV_SELF), ++ BUS_DIV(CLK_DIV_AHB0, "div_ahb0", "mux_ahb0", CPM_CPCCR, 8, 4, 0, 0, CPM_CPCSR, 1, 21, BUS_DIV_SELF), ++ BUS_DIV(CLK_DIV_AHB2, "div_ahb2", "mux_ahb2", CPM_CPCCR, 12, 4, 0, 0, CPM_CPCSR, 2, 20, BUS_DIV_SELF), ++ BUS_DIV(CLK_DIV_APB, "div_apb", "mux_ahb2", CPM_CPCCR, 16, 4, 0, 0, CPM_CPCSR, 2, 20, BUS_DIV_SELF), ++ BUS_DIV(CLK_DIV_CPU_L2C_X1, "div_cpu_l2c_x1", "mux_cpu_l2c", CPM_CPCCR, 0, 4, 4, 4, CPM_CPCSR, 0, 22, BUS_DIV_ONE), ++ BUS_DIV(CLK_DIV_CPU_L2C_X2, "div_cpu_l2c_x2", "mux_cpu_l2c", CPM_CPCCR, 0, 4, 4, 4, CPM_CPCSR, 0, 22, BUS_DIV_TWO), ++}; ++ ++ ++/******************************************************************************* ++ * DIV ++ ********************************************************************************/ ++ ++static struct clk_div_table t40_clk_div_table[256] = {}; ++ ++static struct ingenic_div_clock t40_div_clks[] __initdata = { ++ DIV(CLK_DIV_DDR, "div_ddr", "mux_ddr", CPM_DDRCDR, 4, 0, NULL), ++ DIV(CLK_DIV_MACPHY, "div_macphy", "mux_macphy", CPM_MACCDR, 8, 0, NULL), ++ DIV(CLK_DIV_LCD, "div_lcd", "mux_lcd", CPM_LPCDR, 8, 0, NULL), ++ DIV(CLK_DIV_MSC0, "div_msc0", "mux_msc0", CPM_MSC0CDR, 8, 0, t40_clk_div_table), ++ DIV(CLK_DIV_MSC1, "div_msc1", "mux_msc1", CPM_MSC1CDR, 8, 0, t40_clk_div_table), ++ DIV(CLK_DIV_SFC, "div_sfc", "mux_sfc", CPM_SFCCDR, 8, 0, NULL), ++ DIV(CLK_DIV_SSI, "div_ssi", "mux_ssi", CPM_SSICDR, 8, 0, NULL), ++ DIV(CLK_DIV_CIM0, "div_cim0", "mux_cim0", CPM_CIM0CDR, 8, 0, NULL), ++ DIV(CLK_DIV_CIM1, "div_cim1", "mux_cim1", CPM_CIM1CDR, 8, 0, NULL), ++ DIV(CLK_DIV_CIM2, "div_cim2", "mux_cim2", CPM_CIM2CDR, 8, 0, NULL), ++ DIV(CLK_DIV_ISP, "div_isp", "mux_isp", CPM_ISPCDR, 4, 0, NULL), ++ DIV(CLK_DIV_RSA, "div_rsa", "mux_rsa", CPM_RSACDR, 4, 0, NULL), ++ DIV(CLK_DIV_EL150, "div_el150", "mux_el150", CPM_EL150CDR, 4, 0, NULL), ++ DIV(CLK_DIV_BSCALER, "div_bscaler", "mux_bscaler", CPM_BSCALERCDR, 4, 0, NULL), ++ DIV(CLK_DIV_BT0, "div_bt0", "mux_bt0", CPM_BT0CDR, 8, 0, NULL), ++ ++}; ++ ++/******************************************************************************* ++ * FRACTIONAL-DIVIDER ++ ********************************************************************************/ ++ ++static struct ingenic_fra_div_clock t40_fdiv_clks[] __initdata = { ++ FRA_DIV(CLK_DIV_I2ST, "div_i2st", "mux_i2st", CPM_I2STCDR, 20, 9, 0, 20), ++ FRA_DIV(CLK_DIV_I2SR, "div_i2sr", "mux_i2sr", CPM_I2SRCDR, 20, 9, 0, 20), ++}; ++ ++/******************************************************************************* ++ * GATE ++ ********************************************************************************/ ++static struct ingenic_gate_clock t40_gate_clks[] __initdata = { ++ ++ GATE(CLK_GATE_DDR, "gate_ddr", "div_ddr", CPM_CLKGR, 31, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_TCU, "gate_tcu", "div_apb", CPM_CLKGR, 30, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_DES, "gate_des", "div_apb", CPM_CLKGR, 28, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_RSA, "gate_rsa", "div_rsa", CPM_CLKGR, 27, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_MIPI_CSI, "gate_csi", "div_ahb0", CPM_CLKGR, 25, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_LCD, "gate_lcd", "div_lcd", CPM_CLKGR, 24, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_ISP, "gate_isp", "div_isp", CPM_CLKGR, 23, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_PDMA, "gate_pdma", "div_ahb2", CPM_CLKGR, 22, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SFC, "gate_sfc", "div_sfc", CPM_CLKGR, 21, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SSI1, "gate_ssi1", "div_ssi", CPM_CLKGR, 20, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_HASH, "gate_hash", "div_ahb2", CPM_CLKGR, 19, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SLV, "gate_slv", "div_apb", CPM_CLKGR, 18, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UART3, "gate_uart3", "div_apb", CPM_CLKGR, 17, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UART2, "gate_uart2", "div_apb", CPM_CLKGR, 16, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UART1, "gate_uart1", "div_apb", CPM_CLKGR, 15, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UART0, "gate_uart0", "div_apb", CPM_CLKGR, 14, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SADC, "gate_sadc", "div_apb", CPM_CLKGR, 13, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_DMIC, "gate_dmic", "mux_apb", CPM_CLKGR, 12, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_AIC, "gate_aic", "div_i2st", CPM_CLKGR, 11, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SMB3, "gate_i2c3", "div_apb", CPM_CLKGR, 10, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SMB2, "gate_i2c2", "div_apb", CPM_CLKGR, 9, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SMB1, "gate_i2c1", "div_apb", CPM_CLKGR, 8, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SMB0, "gate_i2c0", "div_apb", CPM_CLKGR, 7, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SSI0, "gate_ssi0", "div_ssi", CPM_CLKGR, 6, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_MSC1, "gate_msc1", "div_msc1", CPM_CLKGR, 5, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_MSC0, "gate_msc0", "div_msc0", CPM_CLKGR, 4, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_OTG, "gate_otg", "div_ahb2", CPM_CLKGR, 3, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_BSCALER, "gate_bscaler", "div_bscaler", CPM_CLKGR, 2, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_EFUSE, "gate_efuse", "div_ahb2", CPM_CLKGR, 1, 0, CLK_GATE_HIWORD_MASK), ++ GATE(CLK_GATE_NEMC, "gate_nemc", "div_ahb2", CPM_CLKGR, 0, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_CPU, "gate_cpu", "div_cpu", CPM_CLKGR1, 15, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_APB0, "gate_apb0", "div_ahb0", CPM_CLKGR1, 14, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_OST, "gate_ost", "ext", CPM_CLKGR1, 11, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_AHB0, "gate_ahb0", "div_ahb0", CPM_CLKGR1, 10, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_MONITOR, "gate_monitor", "div_ahb0", CPM_CLKGR1, 9, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_I2D, "gate_i2d", "div_ahb0", CPM_CLKGR1, 8, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_MIPI_DSI, "gate_dsi", "div_ahb0", CPM_CLKGR1, 7, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_DRAWBOX, "gate_drawbox", "div_ahb0", CPM_CLKGR1, 6, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_AES, "gate_aes", "div_ahb2", CPM_CLKGR1, 5, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_GMAC, "gate_gmac", "div_macphy", CPM_CLKGR1, 4, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_AHB1, "gate_ahb1", "div_ahb2", CPM_CLKGR1, 3, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_IPU, "gate_ipu", "div_ahb0", CPM_CLKGR1, 2, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_DTRNG, "gate_dtrng", "div_apb", CPM_CLKGR1, 1, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_EL150, "gate_el150", "div_el150", CPM_CLKGR1, 0, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_CE_I2ST, "ce_i2st", "div_i2st", CPM_I2STCDR, 29, 0, 0), ++ GATE(CLK_CE_I2SR, "ce_i2sr", "div_i2sr", CPM_I2SRCDR, 29, 0, 0), ++ GATE(CLK_GATE_USBPHY, "gate_usbphy", "div_apb", CPM_OPCR, 23, 0, CLK_GATE_SET_TO_DISABLE) ++}; ++ ++static void clk_div_table_generate(void) ++{ ++ int i; ++ for (i = 0; i < ARRAY_SIZE(t40_clk_div_table); i++) { ++ t40_clk_div_table[i].val = i; ++ t40_clk_div_table[i].div = (i + 1) * 4; ++ } ++ ++} ++ ++static const struct of_device_id ext_clk_match[] __initconst = { ++ { .compatible = "ingenic,fixed-clock", .data = (void *)0, }, ++ {}, ++}; ++ ++static int clocks_show(struct seq_file *m, void *v) ++{ ++ int i = 0; ++ struct clk_onecell_data * clk_data = NULL; ++ struct clk *clk = NULL; ++ ++ if(m->private != NULL) { ++ seq_printf(m, "CLKGR\t: %08x\n", cpm_inl(CPM_CLKGR)); ++ seq_printf(m, "CLKGR1\t: %08x\n", cpm_inl(CPM_CLKGR1)); ++ seq_printf(m, "LCR1\t: %08x\n", cpm_inl(CPM_LCR)); ++ } else { ++ seq_printf(m, " ID NAME FRE sta count parent\n"); ++ clk_data = &ctx->clk_data; ++ for(i = 0; i < clk_data->clk_num; i++) { ++ clk = clk_data->clks[i]; ++ if (clk != ERR_PTR(-ENOENT)) { ++ if (__clk_get_name(clk) == NULL) { ++ seq_printf(m, "--------------------------------------------------------\n"); ++ } else { ++ unsigned int mhz = _get_rate(__clk_get_name(clk)) / 1000; ++ seq_printf(m, "%3d %-15s %4d.%03dMHz %7sable %d %10s\n", i, __clk_get_name(clk) ++ , mhz/1000, mhz%1000 ++ , __clk_get_flags(clk) & CLK_FLG_ENABLE? "en": "dis" ++ , __clk_get_enable_count(clk) ++ , clk_get_parent(clk)? __clk_get_name(clk_get_parent(clk)): "root"); ++ } ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++static int clocks_open(struct inode *inode, struct file *file) ++{ ++ return single_open_size(file, clocks_show, PDE_DATA(inode),8192); ++} ++ ++static const struct file_operations clocks_proc_fops ={ ++ .read = seq_read, ++ .open = clocks_open, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++ ++/* Register t40 clocks. */ ++static void __init t40_clk_init(struct device_node *np, void __iomem *base) ++{ ++ void __iomem *reg_base; ++ ++ printk("t40 Clock Power Management Unit init!\n"); ++ ++ reg_base = base; ++ ++ if (np) { ++ reg_base = of_iomap(np, 0); ++ if (!reg_base) ++ panic("%s: failed to map registers\n", __func__); ++ } ++ ++ ++ ctx = ingenic_clk_init(np, reg_base, NR_CLKS); ++ if (!ctx) ++ panic("%s: unable to allocate context.\n", __func__); ++ ++ /* Register Ext Clocks From DT */ ++ ingenic_clk_of_register_fixed_ext(ctx, t40_fixed_rate_ext_clks, ++ ARRAY_SIZE(t40_fixed_rate_ext_clks), ext_clk_match); ++ ++ /* Register PLLs. */ ++ ingenic_clk_register_pll(ctx, t40_pll_clks, ++ ARRAY_SIZE(t40_pll_clks), reg_base); ++ ++ ++ /* Register Muxs */ ++ ingenic_clk_register_mux(ctx, t40_mux_clks, ARRAY_SIZE(t40_mux_clks)); ++ ++ /* Register Bus Divs */ ++ ingenic_clk_register_bus_div(ctx, t40_bus_div_clks, ARRAY_SIZE(t40_bus_div_clks)); ++ ++ /* Register Divs */ ++ clk_div_table_generate(); ++ ingenic_clk_register_cgu_div(ctx, t40_div_clks, ARRAY_SIZE(t40_div_clks)); ++ ++ /* Register Fractional Divs */ ++ ingenic_clk_register_fra_div(ctx, t40_fdiv_clks, ARRAY_SIZE(t40_fdiv_clks)); ++ ++ /* Register Gates */ ++ ingenic_clk_register_gate(ctx, t40_gate_clks, ARRAY_SIZE(t40_gate_clks)); ++ ++ /* Register Powers */ ++// ingenic_power_register_gate(ctx, t40_gate_power, ARRAY_SIZE(t40_gate_power)); ++ ++ ingenic_clk_of_add_provider(np, ctx); ++ ++ ++ //ingenic_clk_of_dump(ctx); ++ ++ ++ pr_info("=========== t40 clocks: =============\n" ++ "\tapll = %lu , mpll = %lu\n" ++ "\tcpu_clk = %lu , l2c_clk = %lu\n" ++ "\tahb0_clk = %lu , ahb2_clk = %lu\n" ++ "\tapb_clk = %lu , ext_clk = %lu\n\n", ++ _get_rate("apll"), _get_rate("mpll"), ++ _get_rate("div_cpu"), _get_rate("div_l2c"), ++ _get_rate("div_ahb0"), _get_rate("div_ahb2"), ++ _get_rate("div_apb"), _get_rate("ext")); ++ ++} ++ ++CLK_OF_DECLARE(t40_clk, "ingenic,t40-clocks", t40_clk_init); ++ ++static int __init init_clk_proc(void) ++{ ++ struct proc_dir_entry *p; ++ ++ p = jz_proc_mkdir("clock"); ++ if (!p) { ++ pr_warning("create_proc_entry for common clock failed!\n"); ++ } else { ++ proc_create_data("clocks", 0600, p, &clocks_proc_fops, 0); ++ proc_create_data("misc", 0600, p, &clocks_proc_fops, (void *)1); ++ } ++ return 0; ++} ++ ++module_init(init_clk_proc); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_clk-x2000-v12.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_clk-x2000-v12.c.patch new file mode 100644 index 00000000..60963352 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_clk-x2000-v12.c.patch @@ -0,0 +1,362 @@ +diff -drupN a/drivers/clk/ingenic/clk-x2000-v12.c b/drivers/clk/ingenic/clk-x2000-v12.c +--- a/drivers/clk/ingenic/clk-x2000-v12.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/clk/ingenic/clk-x2000-v12.c 2022-06-09 05:02:28.000000000 +0300 +@@ -0,0 +1,358 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "clk.h" ++ ++ ++ ++/******************************************************************************* ++ * FIXED CLK ++ ********************************************************************************/ ++static struct ingenic_fixed_rate_clock x2000_fixed_rate_ext_clks[] __initdata = { ++ FRATE(CLK_EXT, "ext", NULL, CLK_IS_ROOT, 24000000), ++ FRATE(CLK_RTC_EXT, "rtc_ext", NULL, CLK_IS_ROOT, 32768), ++}; ++ ++ ++ ++/******************************************************************************* ++ * PLL ++ ********************************************************************************/ ++ ++static struct ingenic_pll_rate_table x2000_pll_rate_table[] = { ++ PLL_RATE(1500000000, 124, 1, 1), ++ PLL_RATE(1200000000, 49, 0, 1), ++ PLL_RATE(800000000, 199, 2, 2), ++ PLL_RATE(600000000, 49, 0, 2), ++ PLL_RATE(300000000, 49, 0, 3), ++}; ++ ++ ++ ++/*PLL HWDESC*/ ++static struct ingenic_pll_hwdesc apll_hwdesc = \ ++ PLL_DESC(CPM_CPAPCR, 20, 9, 14, 6, 11, 3, 3, 0, pll_od_encode); ++ ++static struct ingenic_pll_hwdesc mpll_hwdesc = \ ++ PLL_DESC(CPM_CPMPCR, 20, 9, 14, 6, 11, 3, 3, 0, pll_od_encode); ++ ++static struct ingenic_pll_hwdesc epll_hwdesc = \ ++ PLL_DESC(CPM_CPEPCR, 20, 9, 14, 6, 11, 3, 3, 0, pll_od_encode); ++ ++ ++ ++static struct ingenic_pll_clock x2000_pll_clks[] __initdata = { ++ PLL(CLK_PLL_APLL, "apll", "ext", &apll_hwdesc, x2000_pll_rate_table), ++ PLL(CLK_PLL_MPLL, "mpll", "ext", &mpll_hwdesc, x2000_pll_rate_table), ++ PLL(CLK_PLL_EPLL, "epll", "ext", &epll_hwdesc, x2000_pll_rate_table), ++}; ++ ++ ++/******************************************************************************* ++ * MUX ++ ********************************************************************************/ ++PNAME(mux_table_0) = {"stop", "ext", "apll"}; ++PNAME(mux_table_1) = {"stop", "sclka", "mpll"}; ++PNAME(mux_table_2) = {"sclka", "mpll", "epll"}; ++PNAME(mux_table_3) = {"sclka", "mpll", "ext"}; ++PNAME(mux_table_4) = {"sclka", "epll"}; ++PNAME(mux_table_5) = {"mux_ahb2", "ext"}; ++PNAME(mux_table_6) = {"ext", "div_i2s3"}; ++PNAME(mux_table_7) = {"div_i2s0", "div_i2s1", "div_i2s2", "div_i2s3"}; ++ ++static unsigned int ingenic_mux_table[] = {0, 1, 2, 3}; ++ ++ ++static struct ingenic_mux_clock x2000_mux_clks[] __initdata = { ++ MUX(CLK_MUX_SCLKA, "sclka", ingenic_mux_table, mux_table_0, CPM_CPCCR, 30, 2, 0), ++ MUX(CLK_MUX_CPU_L2C, "mux_cpu_l2c", ingenic_mux_table, mux_table_1, CPM_CPCCR, 28, 2, 0), ++ MUX(CLK_MUX_AHB0, "mux_ahb0", ingenic_mux_table, mux_table_1, CPM_CPCCR, 26, 2, 0), ++ MUX(CLK_MUX_AHB2, "mux_ahb2", ingenic_mux_table, mux_table_1, CPM_CPCCR, 24, 2, 0), ++ ++ MUX(CLK_MUX_DDR, "mux_ddr", ingenic_mux_table, mux_table_1, CPM_DDRCDR, 30, 2, 0), ++ MUX(CLK_MUX_MACPHY, "mux_macphy", ingenic_mux_table, mux_table_2, CPM_MACCDR, 30, 2, 0), ++ MUX(CLK_MUX_MACTXPHY, "mux_mactxphy", ingenic_mux_table, mux_table_2, CPM_MACTXCDR, 30, 2, 0), ++ MUX(CLK_MUX_MACTXPHY1, "mux_mactxphy1", ingenic_mux_table, mux_table_2, CPM_MACTXCDR1, 30, 2, 0), ++ MUX(CLK_MUX_MACPTP, "mux_macptp", ingenic_mux_table, mux_table_2, CPM_MACPTP, 30, 2, 0), ++ MUX(CLK_MUX_I2S0, "mux_i2s0", ingenic_mux_table, mux_table_4, CPM_I2S0CDR, 30, 1, 0), ++ MUX(CLK_MUX_I2S1, "mux_i2s1", ingenic_mux_table, mux_table_4, CPM_I2S1CDR, 30, 1, 0), ++ MUX(CLK_MUX_I2S2, "mux_i2s2", ingenic_mux_table, mux_table_4, CPM_I2S2CDR, 30, 1, 0), ++ MUX(CLK_MUX_I2S3, "mux_i2s3", ingenic_mux_table, mux_table_4, CPM_I2S3CDR, 30, 1, 0), ++ MUX(CLK_MUX_AUDIO_RAM, "mux_audio_ram", ingenic_mux_table, mux_table_5, CPM_AUDIOCR, 30, 1, 0), ++ MUX(CLK_MUX_SPDIF, "mux_spdif", ingenic_mux_table, mux_table_7, CPM_AUDIOCR, 3, 2, CLK_SET_RATE_PARENT|CLK_SET_RATE_NO_REPARENT), ++ MUX(CLK_MUX_PCM, "mux_pcm", ingenic_mux_table, mux_table_7, CPM_AUDIOCR, 1, 2, CLK_SET_RATE_PARENT|CLK_SET_RATE_NO_REPARENT), ++ MUX(CLK_MUX_DMIC, "mux_dmic", ingenic_mux_table, mux_table_6, CPM_AUDIOCR, 0, 1, CLK_SET_RATE_PARENT|CLK_SET_RATE_NO_REPARENT), ++ MUX(CLK_MUX_LCD, "mux_lcd", ingenic_mux_table, mux_table_2, CPM_LPCDR, 30, 2, 0), ++ MUX(CLK_MUX_MSC0, "mux_msc0", ingenic_mux_table, mux_table_3, CPM_MSC0CDR, 30, 2, 0), ++ MUX(CLK_MUX_MSC1, "mux_msc1", ingenic_mux_table, mux_table_3, CPM_MSC1CDR, 30, 2, 0), ++ MUX(CLK_MUX_MSC2, "mux_msc2", ingenic_mux_table, mux_table_3, CPM_MSC2CDR, 30, 2, 0), ++ MUX(CLK_MUX_SFC, "mux_sfc", ingenic_mux_table, mux_table_2, CPM_SFCCDR, 30, 2, 0), ++ MUX(CLK_MUX_SSI, "mux_ssi", ingenic_mux_table, mux_table_2, CPM_SSICDR, 30, 2, 0), ++ MUX(CLK_MUX_CIM, "mux_cim", ingenic_mux_table, mux_table_2, CPM_CIMCDR, 30, 2, 0), ++ MUX(CLK_MUX_PWM, "mux_pwm", ingenic_mux_table, mux_table_2, CPM_PWMCDR, 30, 2, 0), ++ MUX(CLK_MUX_ISP, "mux_isp", ingenic_mux_table, mux_table_2, CPM_ISPCDR, 30, 2, 0), ++ MUX(CLK_MUX_RSA, "mux_rsa", ingenic_mux_table, mux_table_2, CPM_RSACDR, 30, 2, 0), ++ ++}; ++ ++/******************************************************************************* ++ * DIV BUS ++ ********************************************************************************/ ++ ++static struct ingenic_bus_clock x2000_bus_div_clks[] __initdata = { ++ BUS_DIV(CLK_DIV_CPU, "div_cpu", "mux_cpu_l2c", CPM_CPCCR, 0, 4, 0, 0, CPM_CPCSR, 0, 22, BUS_DIV_SELF), ++ BUS_DIV(CLK_DIV_L2C, "div_l2c", "mux_cpu_l2c", CPM_CPCCR, 4, 4, 0, 0, CPM_CPCSR, 0, 22, BUS_DIV_SELF), ++ BUS_DIV(CLK_DIV_AHB0, "div_ahb0", "mux_ahb0", CPM_CPCCR, 8, 4, 0, 0, CPM_CPCSR, 1, 21, BUS_DIV_SELF), ++ BUS_DIV(CLK_DIV_AHB2, "div_ahb2", "mux_ahb2", CPM_CPCCR, 12, 4, 0, 0, CPM_CPCSR, 2, 20, BUS_DIV_SELF), ++ BUS_DIV(CLK_DIV_APB, "div_apb", "mux_ahb2", CPM_CPCCR, 16, 4, 0, 0, CPM_CPCSR, 2, 20, BUS_DIV_SELF), ++ BUS_DIV(CLK_DIV_CPU_L2C_X1, "div_cpu_l2c_x1", "mux_cpu_l2c", CPM_CPCCR, 0, 4, 4, 4, CPM_CPCSR, 0, 22, BUS_DIV_ONE), ++ BUS_DIV(CLK_DIV_CPU_L2C_X2, "div_cpu_l2c_x2", "mux_cpu_l2c", CPM_CPCCR, 0, 4, 4, 4, CPM_CPCSR, 0, 22, BUS_DIV_TWO), ++}; ++ ++ ++/******************************************************************************* ++ * DIV ++ ********************************************************************************/ ++ ++static struct clk_div_table x2000_clk_div_table[256] = {}; ++ ++static struct ingenic_div_clock x2000_div_clks[] __initdata = { ++ DIV(CLK_DIV_DDR, "div_ddr", "mux_ddr", CPM_DDRCDR, 4, 0, NULL), ++ DIV(CLK_DIV_MACPHY, "div_macphy", "mux_macphy", CPM_MACCDR, 8, 0, NULL), ++ DIV(CLK_DIV_MACTXPHY, "div_mactxphy0", "mux_mactxphy", CPM_MACTXCDR, 8, 0, NULL), ++ DIV(CLK_DIV_MACTXPHY1, "div_mactxphy1", "mux_mactxphy1", CPM_MACTXCDR1, 8, 0, NULL), ++ DIV(CLK_DIV_MACPTP, "div_macptp", "mux_macptp", CPM_MACPTP, 8, 0, NULL), ++ DIV(CLK_DIV_LCD, "div_lcd", "mux_lcd", CPM_LPCDR, 8, 0, NULL), ++ DIV(CLK_DIV_MSC0, "div_msc0", "mux_msc0", CPM_MSC0CDR, 8, 0, x2000_clk_div_table), ++ DIV(CLK_DIV_MSC1, "div_msc1", "mux_msc1", CPM_MSC1CDR, 8, 0, x2000_clk_div_table), ++ DIV(CLK_DIV_MSC2, "div_msc2", "mux_msc2", CPM_MSC2CDR, 8, 0, x2000_clk_div_table), ++ DIV(CLK_DIV_SFC, "div_sfc", "mux_sfc", CPM_SFCCDR, 8, 0, NULL), ++ DIV(CLK_DIV_SSI, "div_ssi", "mux_ssi", CPM_SSICDR, 8, 0, NULL), ++ DIV(CLK_DIV_CIM, "div_cim", "mux_cim", CPM_CIMCDR, 8, 0, NULL), ++ DIV(CLK_DIV_PWM, "div_pwm", "mux_pwm", CPM_PWMCDR, 4, 0, NULL), ++ DIV(CLK_DIV_ISP, "div_isp", "mux_isp", CPM_ISPCDR, 4, 0, NULL), ++ DIV(CLK_DIV_RSA, "div_rsa", "mux_rsa", CPM_RSACDR, 4, 0, NULL), ++ ++}; ++ ++/******************************************************************************* ++ * FRACTIONAL-DIVIDER ++ ********************************************************************************/ ++ ++static struct ingenic_fra_div_clock x2000_fdiv_clks[] __initdata = { ++ FRA_DIV(CLK_DIV_I2S0, "div_i2s0", "mux_i2s0", CPM_I2S0CDR, 20, 9, 0, 20), ++ FRA_DIV(CLK_DIV_I2S1, "div_i2s1", "mux_i2s1", CPM_I2S1CDR, 20, 9, 0, 20), ++ FRA_DIV(CLK_DIV_I2S2, "div_i2s2", "mux_i2s2", CPM_I2S2CDR, 20, 9, 0, 20), ++ FRA_DIV(CLK_DIV_I2S3, "div_i2s3", "mux_i2s3", CPM_I2S3CDR, 20, 9, 0, 20), ++}; ++ ++/******************************************************************************* ++ * GATE ++ ********************************************************************************/ ++static struct ingenic_gate_clock x2000_gate_clks[] __initdata = { ++ ++ GATE(CLK_GATE_DDR, "gate_ddr", "div_ddr", CPM_CLKGR, 31, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE), ++// GATE(CLK_GATE_IPU, "gate_ipu", "div_ipu", CPM_CLKGR, 30, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_AHB0, "gate_ahb0", "div_ahb0", CPM_CLKGR, 29, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_APB0, "gate_apb0", "div_ahb0", CPM_CLKGR, 28, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_RTC, "gate_rtc", "rtc_ext", CPM_CLKGR, 27, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SSI1, "gate_ssi1", "div_ssi", CPM_CLKGR, 26, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_RSA, "gate_rsa", "div_rsa", CPM_CLKGR, 25, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_AES, "gate_aes", "div_ahb2", CPM_CLKGR, 24, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_LCD, "gate_lcd", "div_lcd", CPM_CLKGR, 23, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_CIM, "gate_cim", "div_cim", CPM_CLKGR, 22, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_PDMA, "gate_pdma", "div_ahb2", CPM_CLKGR, 21, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_OST, "gate_ost", "ext", CPM_CLKGR, 20, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SSI0, "gate_ssi0", "div_ssi", CPM_CLKGR, 19, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_TCU, "gate_tcu", "div_apb", CPM_CLKGR, 18, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_DTRNG, "gate_dtrng", "div_apb", CPM_CLKGR, 17, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UART2, "gate_uart2", "div_apb", CPM_CLKGR, 16, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UART1, "gate_uart1", "div_apb", CPM_CLKGR, 15, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UART0, "gate_uart0", "div_apb", CPM_CLKGR, 14, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SADC, "gate_sadc", "div_apb", CPM_CLKGR, 13, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_HELIX, "gate_helix", "div_ahb0", CPM_CLKGR, 12, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_AUDIO, "gate_audio", "div_ahb2", CPM_CLKGR, 11, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SMB3, "gate_i2c3", "div_apb", CPM_CLKGR, 10, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SMB2, "gate_i2c2", "div_apb", CPM_CLKGR, 9, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SMB1, "gate_i2c1", "div_apb", CPM_CLKGR, 8, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SMB0, "gate_i2c0", "div_apb", CPM_CLKGR, 7, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SCC, "gate_scc", "div_apb", CPM_CLKGR, 6, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_MSC1, "gate_msc1", "div_msc1", CPM_CLKGR, 5, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_MSC0, "gate_msc0", "div_msc0", CPM_CLKGR, 4, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_OTG, "gate_otg", "div_ahb2", CPM_CLKGR, 3, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SFC, "gate_sfc", "div_sfc", CPM_CLKGR, 2, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_EFUSE, "gate_efuse", "div_ahb2", CPM_CLKGR, 1, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_NEMC, "gate_nemc", "div_ahb2", CPM_CLKGR, 0, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_ARB, "gate_arb", "div_ahb0", CPM_CLKGR1, 30, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_MIPI_DSI, "gate_dsi", "div_ahb0", CPM_CLKGR1, 29, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_MIPI_CSI, "gate_csi", "div_ahb0", CPM_CLKGR1, 28, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_INTC, "gate_intc", "div_ahb2", CPM_CLKGR1, 26, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_MSC2, "gate_msc2", "div_msc2", CPM_CLKGR1, 25, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_GMAC1, "gate_gmac1", "div_ahb2", CPM_CLKGR1, 24, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_GMAC0, "gate_gmac0", "div_ahb2", CPM_CLKGR1, 23, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UART9, "gate_uart9", "div_apb", CPM_CLKGR1, 22, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UART8, "gate_uart8", "div_apb", CPM_CLKGR1, 21, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UART7, "gate_uart7", "div_apb", CPM_CLKGR1, 20, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UATR6, "gate_uart6", "div_apb", CPM_CLKGR1, 19, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UART5, "gate_uart5", "div_apb", CPM_CLKGR1, 18, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UART4, "gate_uart4", "div_apb", CPM_CLKGR1, 17, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UART3, "gate_uart3", "div_apb", CPM_CLKGR1, 16, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SPDIF, "gate_spdif", "mux_spdif", CPM_CLKGR1, 14, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_DMIC, "gate_dmic", "mux_dmic", CPM_CLKGR1, 13, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_PCM, "gate_pcm", "mux_pcm", CPM_CLKGR1, 12, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_I2S3, "gate_i2s3", "div_i2s3", CPM_CLKGR1, 11, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_I2S2, "gate_i2s2", "div_i2s2", CPM_CLKGR1, 10, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_I2S1, "gate_i2s1", "div_i2s1", CPM_CLKGR1, 9, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_I2S0, "gate_i2s0", "div_i2s0", CPM_CLKGR1, 8, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_ROT, "gate_rot", "div_ahb0", CPM_CLKGR1, 7, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_HASH, "gate_hash", "div_ahb2", CPM_CLKGR1, 6, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_PWM, "gate_pwm", "div_pwm", CPM_CLKGR1, 5, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_FELIX, "gate_felix", "div_ahb0", CPM_CLKGR1, 4, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_ISP1, "gate_isp1", "div_apb", CPM_CLKGR1, 3, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_ISP0, "gate_isp0", "div_apb", CPM_CLKGR1, 2, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SMB5, "gate_i2c5", "div_apb", CPM_CLKGR1, 1, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SMB4, "gate_i2c4", "div_apb", CPM_CLKGR1, 0, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_USBPHY, "gate_usbphy", "div_apb", CPM_OPCR, 23, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_CE_I2S0, "ce_i2s0", "div_i2s0", CPM_I2S0CDR, 29, 0, 0), ++ GATE(CLK_CE_I2S1, "ce_i2s1", "div_i2s1", CPM_I2S1CDR, 29, 0, 0), ++ GATE(CLK_CE_I2S2, "ce_i2s2", "div_i2s2", CPM_I2S2CDR, 29, 0, 0), ++ GATE(CLK_CE_I2S3, "ce_i2s3", "div_i2s3", CPM_I2S3CDR, 29, 0, 0), ++}; ++ ++static struct ingenic_gate_power x2000_gate_power[] __initdata = { ++ ++ POWER(POWER_ISP0, "power_isp0", "gate_isp0", CPM_LCR, 31, 27, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, POWER_GATE_WAIT), ++ POWER(POWER_ISP1, "power_isp1", "gate_isp1", CPM_LCR, 30, 26, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, POWER_GATE_WAIT), ++ POWER(POWER_FELIX, "power_felix", "gate_felix", CPM_LCR, 29, 25, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, POWER_GATE_WAIT), ++ POWER(POWER_HELIX, "power_helix", "gate_helix", CPM_LCR, 28, 24, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, POWER_GATE_WAIT), ++ ++ POWER(PD_MEM_NEMC, "pd_mem_nemc", "gate_nemc", CPM_MPDCR, 28, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_USB, "pd_mem_usb", "gate_usb", CPM_MPDCR, 27, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_SFC, "pd_mem_sfc", "gate_sfc", CPM_MPDCR, 26, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_PDMA_SEC, "pd_mem_pdma_sec", "gate_pdma", CPM_MPDCR, 25, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_PDMA, "pd_mem_pdma", "gate_pdma", CPM_MPDCR, 24, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_MSC2, "pd_mem_msc2", "gate_msc2", CPM_MPDCR, 23, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_MSC1, "pd_mem_msc1", "gate_msc1", CPM_MPDCR, 22, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_MSC0, "pd_mem_msc0", "gate_msc0", CPM_MPDCR, 21, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_GMAC1, "pd_mem_gmac1", "gate_gmac1", CPM_MPDCR, 20, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_GMAC0, "pd_mem_gmac0", "gate_gmac0", CPM_MPDCR, 19, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_DMIC, "pd_mem_dmic", "gate_dmic", CPM_MPDCR, 18, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_AUDIO, "pd_mem_audio", "gate_audio", CPM_MPDCR, 17, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_AES, "pd_mem_aes", "gate_aes", CPM_MPDCR, 16, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_DSI, "pd_mem_dsi", "gate_dsi", CPM_MPDCR, 12, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_SSI1, "pd_mem_ssi1", "gate_ssi1", CPM_MPDCR, 11, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_SSI0, "pd_mem_ssi0", "gate_ssi0", CPM_MPDCR, 10, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_UART9, "pd_mem_uart9", "gate_uart9", CPM_MPDCR, 9, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_UART8, "pd_mem_uart8", "gate_uart8", CPM_MPDCR, 8, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_UART7, "pd_mem_uart7", "gate_uart7", CPM_MPDCR, 7, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_UART6, "pd_mem_uart6", "gate_uart6", CPM_MPDCR, 6, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_UART5, "pd_mem_uart5", "gate_uart5", CPM_MPDCR, 5, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_UART4, "pd_mem_uart4", "gate_uart4", CPM_MPDCR, 4, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_UART3, "pd_mem_uart3", "gate_uart3", CPM_MPDCR, 3, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_UART2, "pd_mem_uart2", "gate_uart2", CPM_MPDCR, 2, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_UART1, "pd_mem_uart1", "gate_uart1", CPM_MPDCR, 1, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_UART0, "pd_mem_uart0", "gate_uart0", CPM_MPDCR, 0, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_ROT, "pd_mem_rot", "gate_rot", CPM_MPDCR1, 8, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_CIM, "pd_mem_cim", "gate_cim", CPM_MPDCR1, 7, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_DPU, "pd_mem_dpu", "gate_dpu", CPM_MPDCR1, 6, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_DDR_CH6, "pd_mem_ddr_ch6", "gate_ddr", CPM_MPDCR1, 5, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_DDR_CH5, "pd_mem_ddr_ch5", "gate_ddr", CPM_MPDCR1, 4, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_DDR_CH3, "pd_mem_ddr_ch3", "gate_ddr", CPM_MPDCR1, 3, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_DDR_CH1, "pd_mem_ddr_ch1", "gate_ddr", CPM_MPDCR1, 2, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_DDR_CH0, "pd_mem_ddr_ch0", "gate_ddr", CPM_MPDCR1, 1, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_DDR_TOP, "pd_mem_ddr_top", "gate_ddr", CPM_MPDCR1, 0, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ ++}; ++ ++static void clk_div_table_generate(void) ++{ ++ int i; ++ for (i = 0; i < ARRAY_SIZE(x2000_clk_div_table); i++) { ++ x2000_clk_div_table[i].val = i; ++ x2000_clk_div_table[i].div = (i + 1) * 4; ++ } ++ ++} ++ ++static const struct of_device_id ext_clk_match[] __initconst = { ++ { .compatible = "ingenic,fixed-clock", .data = (void *)0, }, ++ {}, ++}; ++ ++ ++/* Register x2000 clocks. */ ++static void __init x2000_clk_init(struct device_node *np, void __iomem *base) ++{ ++ struct ingenic_clk_provider *ctx; ++ void __iomem *reg_base; ++ ++ ++ printk("x2000 Clock Power Management Unit init!\n"); ++ ++ reg_base = base; ++ ++ if (np) { ++ reg_base = of_iomap(np, 0); ++ if (!reg_base) ++ panic("%s: failed to map registers\n", __func__); ++ } ++ ++ ++ ctx = ingenic_clk_init(np, reg_base, NR_CLKS); ++ if (!ctx) ++ panic("%s: unable to allocate context.\n", __func__); ++ ++ /* Register Ext Clocks From DT */ ++ ingenic_clk_of_register_fixed_ext(ctx, x2000_fixed_rate_ext_clks, ++ ARRAY_SIZE(x2000_fixed_rate_ext_clks), ext_clk_match); ++ ++ /* Register PLLs. */ ++ ingenic_clk_register_pll(ctx, x2000_pll_clks, ++ ARRAY_SIZE(x2000_pll_clks), reg_base); ++ ++ ++ /* Register Muxs */ ++ ingenic_clk_register_mux(ctx, x2000_mux_clks, ARRAY_SIZE(x2000_mux_clks)); ++ ++ /* Register Bus Divs */ ++ ingenic_clk_register_bus_div(ctx, x2000_bus_div_clks, ARRAY_SIZE(x2000_bus_div_clks)); ++ ++ /* Register Divs */ ++ clk_div_table_generate(); ++ ingenic_clk_register_cgu_div(ctx, x2000_div_clks, ARRAY_SIZE(x2000_div_clks)); ++ ++ /* Register Fractional Divs */ ++ ingenic_clk_register_fra_div(ctx, x2000_fdiv_clks, ARRAY_SIZE(x2000_fdiv_clks)); ++ ++ /* Register Gates */ ++ ingenic_clk_register_gate(ctx, x2000_gate_clks, ARRAY_SIZE(x2000_gate_clks)); ++ ++ /* Register Powers */ ++ ingenic_power_register_gate(ctx, x2000_gate_power, ARRAY_SIZE(x2000_gate_power)); ++ ++ ingenic_clk_of_add_provider(np, ctx); ++ ++ ++ //ingenic_clk_of_dump(ctx); ++ ++ ++ pr_info("=========== x2000 clocks: =============\n" ++ "\tapll = %lu , mpll = %lu\n" ++ "\tcpu_clk = %lu , l2c_clk = %lu\n" ++ "\tahb0_clk = %lu , ahb2_clk = %lu\n" ++ "\tapb_clk = %lu , ext_clk = %lu\n\n", ++ _get_rate("apll"), _get_rate("mpll"), ++ _get_rate("div_cpu"), _get_rate("div_l2c"), ++ _get_rate("div_ahb0"), _get_rate("div_ahb2"), ++ _get_rate("div_apb"), _get_rate("ext")); ++ ++} ++ ++CLK_OF_DECLARE(x2000_clk, "ingenic,x2000-v12-clocks", x2000_clk_init); ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_clk.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_clk.c.patch new file mode 100644 index 00000000..da380421 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_clk.c.patch @@ -0,0 +1,516 @@ +diff -drupN a/drivers/clk/ingenic/clk.c b/drivers/clk/ingenic/clk.c +--- a/drivers/clk/ingenic/clk.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/clk/ingenic/clk.c 2022-06-09 05:02:28.000000000 +0300 +@@ -0,0 +1,512 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "clk.h" ++ ++static LIST_HEAD(clock_reg_cache_list); ++ ++void ingenic_clk_save(void __iomem *base, ++ struct ingenic_clk_reg_dump *rd, ++ unsigned int num_regs) ++{ ++ for (; num_regs > 0; --num_regs, ++rd) ++ rd->value = readl(base + rd->offset); ++} ++ ++void ingenic_clk_restore(void __iomem *base, ++ const struct ingenic_clk_reg_dump *rd, ++ unsigned int num_regs) ++{ ++ for (; num_regs > 0; --num_regs, ++rd) ++ writel(rd->value, base + rd->offset); ++} ++ ++struct ingenic_clk_reg_dump *ingenic_clk_alloc_reg_dump( ++ const unsigned long *rdump, ++ unsigned long nr_rdump) ++{ ++ struct ingenic_clk_reg_dump *rd; ++ unsigned int i; ++ ++ rd = kcalloc(nr_rdump, sizeof(*rd), GFP_KERNEL); ++ if (!rd) ++ return NULL; ++ ++ for (i = 0; i < nr_rdump; ++i) ++ rd[i].offset = rdump[i]; ++ ++ return rd; ++} ++ ++/* setup the essentials required to support clock lookup using ccf */ ++struct ingenic_clk_provider *__init ingenic_clk_init(struct device_node *np, ++ void __iomem *base, unsigned long nr_clks) ++{ ++ struct ingenic_clk_provider *ctx; ++ struct clk **clk_table; ++ int i; ++ ++ ctx = kzalloc(sizeof(struct ingenic_clk_provider), GFP_KERNEL); ++ if (!ctx) ++ panic("could not allocate clock provider context.\n"); ++ ++ clk_table = kcalloc(nr_clks, sizeof(struct clk *), GFP_KERNEL); ++ if (!clk_table) ++ panic("could not allocate clock lookup table\n"); ++ ++ for (i = 0; i < nr_clks; ++i) ++ clk_table[i] = ERR_PTR(-ENOENT); ++ ++ ctx->reg_base = base; ++ ctx->clk_data.clks = clk_table; ++ ctx->clk_data.clk_num = nr_clks; ++ spin_lock_init(&ctx->lock); ++ ++ return ctx; ++} ++ ++void __init ingenic_clk_of_add_provider(struct device_node *np, ++ struct ingenic_clk_provider *ctx) ++{ ++ if (np) { ++ if (of_clk_add_provider(np, of_clk_src_onecell_get, ++ &ctx->clk_data)) ++ panic("could not register clk provider\n"); ++ } ++} ++ ++void ingenic_clk_of_dump(struct ingenic_clk_provider *ctx) ++{ ++ struct clk_onecell_data * clk_data; ++ struct clk *clk; ++ int i; ++ ++ clk_data = &ctx->clk_data; ++ ++ for(i = 0; i < clk_data->clk_num; i++) { ++ ++ clk = clk_data->clks[i]; ++ if(clk != ERR_PTR(-ENOENT)) { ++ printk("clk->id: %d clk->name: %s \n", i, __clk_get_name(clk)); ++ } else { ++ printk("clk->id: %d , clk: %p\n", i, clk); ++ } ++ } ++} ++ ++ ++/* add a clock instance to the clock lookup table used for dt based lookup */ ++void ingenic_clk_add_lookup(struct ingenic_clk_provider *ctx, struct clk *clk, ++ unsigned int id) ++{ ++ if (ctx->clk_data.clks && id) { ++ ctx->clk_data.clks[id] = clk; ++ } ++} ++ ++/* register a list of aliases */ ++void __init ingenic_clk_register_alias(struct ingenic_clk_provider *ctx, ++ const struct ingenic_clock_alias *list, ++ unsigned int nr_clk) ++{ ++ struct clk *clk; ++ unsigned int idx, ret; ++ ++ if (!ctx->clk_data.clks) { ++ pr_err("%s: clock table missing\n", __func__); ++ return; ++ } ++ ++ for (idx = 0; idx < nr_clk; idx++, list++) { ++ if (!list->id) { ++ pr_err("%s: clock id missing for index %d\n", __func__, ++ idx); ++ continue; ++ } ++ ++ clk = ctx->clk_data.clks[list->id]; ++ if (!clk) { ++ pr_err("%s: failed to find clock %d\n", __func__, ++ list->id); ++ continue; ++ } ++ ++ ret = clk_register_clkdev(clk, list->alias, list->dev_name); ++ if (ret) ++ pr_err("%s: failed to register lookup %s\n", ++ __func__, list->alias); ++ } ++} ++ ++/* register a list of fixed clocks */ ++void __init ingenic_clk_register_fixed_rate(struct ingenic_clk_provider *ctx, ++ const struct ingenic_fixed_rate_clock *list, ++ unsigned int nr_clk) ++{ ++ struct clk *clk; ++ unsigned int idx, ret; ++ ++ for (idx = 0; idx < nr_clk; idx++, list++) { ++ clk = clk_register_fixed_rate(NULL, list->name, ++ list->parent_name, list->flags, list->fixed_rate); ++ if (IS_ERR(clk)) { ++ pr_err("%s: failed to register clock %s\n", __func__, ++ list->name); ++ continue; ++ } ++ ++ ingenic_clk_add_lookup(ctx, clk, list->id); ++ ++ ret = clk_register_clkdev(clk, list->name, NULL); ++ if (ret) ++ pr_err("%s: failed to register clock lookup for %s", ++ __func__, list->name); ++ } ++} ++ ++/* register a list of fixed factor clocks */ ++void __init ingenic_clk_register_fixed_factor(struct ingenic_clk_provider *ctx, ++ const struct ingenic_fixed_factor_clock *list, unsigned int nr_clk) ++{ ++ struct clk *clk; ++ unsigned int idx; ++ ++ for (idx = 0; idx < nr_clk; idx++, list++) { ++ clk = clk_register_fixed_factor(NULL, list->name, ++ list->parent_name, list->flags, list->mult, list->div); ++ if (IS_ERR(clk)) { ++ pr_err("%s: failed to register clock %s\n", __func__, ++ list->name); ++ continue; ++ } ++ ++ ingenic_clk_add_lookup(ctx, clk, list->id); ++ } ++} ++ ++/* register a list of mux clocks */ ++void __init ingenic_clk_register_mux(struct ingenic_clk_provider *ctx, ++ const struct ingenic_mux_clock *list, ++ unsigned int nr_clk) ++{ ++ struct clk *clk; ++ unsigned int idx, ret; ++ ++ for (idx = 0; idx < nr_clk; idx++, list++) { ++ if(list->table) { ++ clk = clk_register_mux_table(NULL, list->name, list->parent_names, ++ list->num_parents, list->flags, ++ ctx->reg_base + list->offset, ++ list->shift, BIT(list->width) - 1, list->mux_flags, list->table, &ctx->lock); ++ } else { ++ clk = clk_register_mux(NULL, list->name, list->parent_names, ++ list->num_parents, list->flags, ++ ctx->reg_base + list->offset, ++ list->shift, list->width, list->mux_flags, &ctx->lock); ++ ++ } ++ if (IS_ERR(clk)) { ++ pr_err("%s: failed to register clock %s\n", __func__, ++ list->name); ++ continue; ++ } ++ ++ ingenic_clk_add_lookup(ctx, clk, list->id); ++ ++ /* register a clock lookup only if a clock alias is specified */ ++ if (list->alias) { ++ ret = clk_register_clkdev(clk, list->alias, ++ list->dev_name); ++ if (ret) ++ pr_err("%s: failed to register lookup %s\n", ++ __func__, list->alias); ++ } ++ } ++} ++ ++/* register a list of div clocks */ ++void __init ingenic_clk_register_cgu_div(struct ingenic_clk_provider *ctx, ++ const struct ingenic_div_clock *list, ++ unsigned int nr_clk) ++{ ++ struct clk *clk; ++ unsigned int idx, ret; ++ ++ for (idx = 0; idx < nr_clk; idx++, list++) { ++ if (list->table) ++ clk = clk_register_cgu_divider_table(NULL, list->name, ++ list->parent_name, list->flags, ++ ctx->reg_base + list->offset, ++ list->shift, list->width, ++ list->busy_shift, list->en_shift, list->stop_shift, ++ list->div_flags, list->table, &ctx->lock); ++ else ++ clk = clk_register_cgu_divider(NULL, list->name, ++ list->parent_name, list->flags, ++ ctx->reg_base + list->offset, ++ list->shift, list->width, ++ list->busy_shift, list->en_shift, list->stop_shift, ++ list->div_flags, &ctx->lock); ++ if (IS_ERR(clk)) { ++ pr_err("%s: failed to register clock %s\n", __func__, ++ list->name); ++ continue; ++ } ++ ++ ingenic_clk_add_lookup(ctx, clk, list->id); ++ ++ /* register a clock lookup only if a clock alias is specified */ ++ if (list->alias) { ++ ret = clk_register_clkdev(clk, list->alias, ++ list->dev_name); ++ if (ret) ++ pr_err("%s: failed to register lookup %s\n", ++ __func__, list->alias); ++ } ++ } ++} ++ ++/* register a list of div clocks */ ++void __init ingenic_clk_register_bus_div(struct ingenic_clk_provider *ctx, ++ const struct ingenic_bus_clock *list, ++ unsigned int nr_clk) ++{ ++ struct clk *clk; ++ unsigned int idx, ret; ++ ++ for (idx = 0; idx < nr_clk; idx++, list++) { ++ if (list->table) ++ clk = clk_register_bus_divider_table(NULL, list->name, ++ list->parent_name, list->flags, ++ ctx->reg_base + list->cfg_offset, ++ list->div_shift1, list->div_width1, ++ list->div_shift2, list->div_width2, ++ ctx->reg_base + list->busy_offset, ++ list->busy_shift, list->ce_shift, ++ list->div_flags, list->div_flags_2, ++ list->table, &ctx->lock); ++ else ++ clk = clk_register_bus_divider(NULL, list->name, ++ list->parent_name, list->flags, ++ ctx->reg_base + list->cfg_offset, ++ list->div_shift1, list->div_width1, ++ list->div_shift2, list->div_width2, ++ ctx->reg_base + list->busy_offset, ++ list->busy_shift, list->ce_shift, ++ list->div_flags, list->div_flags_2, ++ &ctx->lock); ++ if (IS_ERR(clk)) { ++ pr_err("%s: failed to register clock %s\n", __func__, ++ list->name); ++ continue; ++ } ++ ++ ingenic_clk_add_lookup(ctx, clk, list->id); ++ ++ /* register a clock lookup only if a clock alias is specified */ ++ if (list->alias) { ++ ret = clk_register_clkdev(clk, list->alias, ++ list->dev_name); ++ if (ret) ++ pr_err("%s: failed to register lookup %s\n", ++ __func__, list->alias); ++ } ++ } ++} ++ ++void __init ingenic_clk_register_fra_div(struct ingenic_clk_provider *ctx, ++ const struct ingenic_fra_div_clock *list, ++ unsigned int nr_clk) ++{ ++ struct clk *clk; ++ unsigned int idx, ret; ++ ++ for (idx = 0; idx < nr_clk; idx++, list++) { ++ clk = clk_register_fractional_divider(NULL, ++ list->name, list->parent_name, list->flags, ++ ctx->reg_base + list->offset, ++ list->mshift, list->mwidth, list->nshift, list->nwidth, ++ list->div_flags, &ctx->lock); ++ ++ if (IS_ERR(clk)) { ++ pr_err("%s: failed to register clock %s\n", __func__, ++ list->name); ++ continue; ++ } ++ ++ ingenic_clk_add_lookup(ctx, clk, list->id); ++ ++ /* register a clock lookup only if a clock alias is specified */ ++ if (list->alias) { ++ ret = clk_register_clkdev(clk, list->alias, ++ list->dev_name); ++ if (ret) ++ pr_err("%s: failed to register lookup %s\n", __func__, list->alias); ++ } ++ } ++} ++ ++ ++/* register a list of gate clocks */ ++void __init ingenic_clk_register_gate(struct ingenic_clk_provider *ctx, ++ const struct ingenic_gate_clock *list, ++ unsigned int nr_clk) ++{ ++ struct clk *clk; ++ unsigned int idx, ret; ++ ++ ++ for (idx = 0; idx < nr_clk; idx++, list++) { ++ ++ clk = clk_register_gate(NULL, list->name, list->parent_name, list->flags, ++ ctx->reg_base + list->offset, list->bit_idx, ++ list->gate_flags, &ctx->lock); ++ ++ if (IS_ERR(clk)) { ++ pr_err("%s: failed to register clock %s\n", __func__, ++ list->name); ++ continue; ++ } ++ ++ /* register a clock lookup only if a clock alias is specified */ ++ if (list->alias) { ++ ret = clk_register_clkdev(clk, list->alias, ++ list->dev_name); ++ if (ret) ++ pr_err("%s: failed to register lookup %s\n", ++ __func__, list->alias); ++ } ++ ++ ingenic_clk_add_lookup(ctx, clk, list->id); ++ ++ } ++} ++ ++void __init ingenic_power_register_gate(struct ingenic_clk_provider *ctx, ++ const struct ingenic_gate_power *list, ++ unsigned int nr_clk) ++{ ++ struct clk *clk; ++ unsigned int idx, ret; ++ ++ for (idx = 0; idx < nr_clk; idx++, list++) { ++ ++ clk = power_register_gate(NULL, list->name, list->parent_name, list->flags, ++ ctx->reg_base + list->offset, list->ctrl_bit, list->wait_bit, ++ list->gate_flags, list->power_flags, &ctx->lock); ++ ++ if (IS_ERR(clk)) { ++ pr_err("%s: failed to register clock %s\n", __func__, ++ list->name); ++ continue; ++ } ++ ++ /* register a clock lookup only if a clock alias is specified */ ++ if (list->alias) { ++ ret = clk_register_clkdev(clk, list->alias, ++ list->dev_name); ++ if (ret) ++ pr_err("%s: failed to register lookup %s\n", ++ __func__, list->alias); ++ } ++ ++ ingenic_clk_add_lookup(ctx, clk, list->id); ++ ++ } ++ ++} ++/* ++ * obtain the clock speed of all external fixed clock sources from device ++ * tree and register it ++ */ ++void __init ingenic_clk_of_register_fixed_ext(struct ingenic_clk_provider *ctx, ++ struct ingenic_fixed_rate_clock *fixed_rate_clk, ++ unsigned int nr_fixed_rate_clk, ++ const struct of_device_id *clk_matches) ++{ ++ const struct of_device_id *match; ++ struct device_node *clk_np; ++ u32 freq; ++ u32 index = 0; ++ ++ for_each_matching_node_and_match(clk_np, clk_matches, &match) { ++ if (of_property_read_u32(clk_np, "clock-frequency", &freq)) ++ continue; ++ fixed_rate_clk[index].fixed_rate = freq; ++ index++; ++ } ++ ingenic_clk_register_fixed_rate(ctx, fixed_rate_clk, nr_fixed_rate_clk); ++} ++ ++/* utility function to get the rate of a specified clock */ ++unsigned long _get_rate(const char *clk_name) ++{ ++ struct clk *clk; ++ ++ clk = __clk_lookup(clk_name); ++ if (!clk) { ++ pr_err("%s: could not find clock %s\n", __func__, clk_name); ++ return 0; ++ } ++ ++ return clk_get_rate(clk); ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int ingenic_clk_suspend(void) ++{ ++ struct ingenic_clock_reg_cache *reg_cache; ++ ++ list_for_each_entry(reg_cache, &clock_reg_cache_list, node) ++ ingenic_clk_save(reg_cache->reg_base, reg_cache->rdump, ++ reg_cache->rd_num); ++ return 0; ++} ++ ++static void ingenic_clk_resume(void) ++{ ++ struct ingenic_clock_reg_cache *reg_cache; ++ ++ list_for_each_entry(reg_cache, &clock_reg_cache_list, node) ++ ingenic_clk_restore(reg_cache->reg_base, reg_cache->rdump, ++ reg_cache->rd_num); ++} ++ ++static struct syscore_ops ingenic_clk_syscore_ops = { ++ .suspend = ingenic_clk_suspend, ++ .resume = ingenic_clk_resume, ++}; ++ ++static void ingenic_clk_sleep_init(void __iomem *reg_base, ++ const unsigned long *rdump, ++ unsigned long nr_rdump) ++{ ++ struct ingenic_clock_reg_cache *reg_cache; ++ ++ reg_cache = kzalloc(sizeof(struct ingenic_clock_reg_cache), ++ GFP_KERNEL); ++ if (!reg_cache) ++ panic("could not allocate register reg_cache.\n"); ++ reg_cache->rdump = ingenic_clk_alloc_reg_dump(rdump, nr_rdump); ++ ++ if (!reg_cache->rdump) ++ panic("could not allocate register dump storage.\n"); ++ ++ if (list_empty(&clock_reg_cache_list)) ++ register_syscore_ops(&ingenic_clk_syscore_ops); ++ ++ reg_cache->reg_base = reg_base; ++ reg_cache->rd_num = nr_rdump; ++ list_add_tail(®_cache->node, &clock_reg_cache_list); ++} ++ ++#else ++static void ingenic_clk_sleep_init(void __iomem *reg_base, ++ const unsigned long *rdump, ++ unsigned long nr_rdump) {} ++#endif ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_clk.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_clk.h.patch new file mode 100644 index 00000000..999ee850 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_clk.h.patch @@ -0,0 +1,585 @@ +diff -drupN a/drivers/clk/ingenic/clk.h b/drivers/clk/ingenic/clk.h +--- a/drivers/clk/ingenic/clk.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/clk/ingenic/clk.h 2022-06-09 05:02:28.000000000 +0300 +@@ -0,0 +1,581 @@ ++#ifndef __INGENIC_CLK_H ++#define __INGENIC_CLK_H ++ ++#include ++#include "clk-pll.h" ++#include "clk-div.h" ++#include "clk-bus.h" ++#include "power-gate.h" ++#include ++ ++struct clk; ++ ++/** ++ * struct ingenic_clk_provider: information about clock provider ++ * @reg_base: virtual address for the register base. ++ * @clk_data: holds clock related data like clk* and number of clocks. ++ * @lock: maintains exclusion between callbacks for a given clock-provider. ++ */ ++struct ingenic_clk_provider { ++ void __iomem *reg_base; ++ struct clk_onecell_data clk_data; ++ spinlock_t lock; ++}; ++ ++/** ++ * struct ingenic_clock_alias: information about mux clock ++ * @id: platform specific id of the clock. ++ * @dev_name: name of the device to which this clock belongs. ++ * @alias: optional clock alias name to be assigned to this clock. ++ */ ++struct ingenic_clock_alias { ++ unsigned int id; ++ const char *dev_name; ++ const char *alias; ++}; ++ ++#define ALIAS(_id, dname, a) \ ++ { \ ++ .id = _id, \ ++ .dev_name = dname, \ ++ .alias = a, \ ++ } ++ ++#define MHZ (1000 * 1000) ++ ++/** ++ * struct ingenic_fixed_rate_clock: information about fixed-rate clock ++ * @id: platform specific id of the clock. ++ * @name: name of this fixed-rate clock. ++ * @parent_name: optional parent clock name. ++ * @flags: optional fixed-rate clock flags. ++ * @fixed-rate: fixed clock rate of this clock. ++ */ ++struct ingenic_fixed_rate_clock { ++ unsigned int id; ++ char *name; ++ const char *parent_name; ++ unsigned long flags; ++ unsigned long fixed_rate; ++}; ++ ++#define FRATE(_id, cname, pname, f, frate) \ ++ { \ ++ .id = _id, \ ++ .name = cname, \ ++ .parent_name = pname, \ ++ .flags = (f | CLK_IGNORE_UNUSED), \ ++ .fixed_rate = frate, \ ++ } ++ ++/* ++ * struct ingenic_fixed_factor_clock: information about fixed-factor clock ++ * @id: platform specific id of the clock. ++ * @name: name of this fixed-factor clock. ++ * @parent_name: parent clock name. ++ * @mult: fixed multiplication factor. ++ * @div: fixed division factor. ++ * @flags: optional fixed-factor clock flags. ++ */ ++struct ingenic_fixed_factor_clock { ++ unsigned int id; ++ char *name; ++ const char *parent_name; ++ unsigned long mult; ++ unsigned long div; ++ unsigned long flags; ++}; ++ ++#define FFACTOR(_id, cname, pname, m, d, f) \ ++ { \ ++ .id = _id, \ ++ .name = cname, \ ++ .parent_name = pname, \ ++ .mult = m, \ ++ .div = d, \ ++ .flags = f, \ ++ } ++ ++/** ++ * struct ingenic_mux_clock: information about mux clock ++ * @id: platform specific id of the clock. ++ * @dev_name: name of the device to which this clock belongs. ++ * @name: name of this mux clock. ++ * @table: mux table in regs. ++ * @parent_names: array of pointer to parent clock names. ++ * @num_parents: number of parents listed in @parent_names. ++ * @flags: optional flags for basic clock. ++ * @offset: offset of the register for configuring the mux. ++ * @shift: starting bit location of the mux control bit-field in @reg. ++ * @width: width of the mux control bit-field in @reg. ++ * @mux_flags: flags for mux-type clock. ++ * @alias: optional clock alias name to be assigned to this clock. ++ */ ++struct ingenic_mux_clock { ++ unsigned int id; ++ const char *dev_name; ++ const char *name; ++ unsigned int *table; ++ const char **parent_names; ++ u8 num_parents; ++ unsigned long flags; ++ unsigned long offset; ++ u8 shift; ++ u8 width; ++ u8 mux_flags; ++ const char *alias; ++}; ++ ++#define __MUX(_id, dname, cname, tb, pnames, o, s, w, f, mf, a) \ ++ { \ ++ .id = _id, \ ++ .dev_name = dname, \ ++ .name = cname, \ ++ .table = tb, \ ++ .parent_names = pnames, \ ++ .num_parents = ARRAY_SIZE(pnames), \ ++ .flags = f, \ ++ .offset = o, \ ++ .shift = s, \ ++ .width = w, \ ++ .mux_flags = mf, \ ++ .alias = a, \ ++ } ++ ++#define MUX(_id, cname, tb, pnames, o, s, w, f) \ ++ __MUX(_id, NULL, cname, tb, pnames, o, s, w, f, 0, cname) ++ ++#define MUX_A(_id, cname, tb, pnames, o, s, w, a) \ ++ __MUX(_id, NULL, cname, tb, pnames, o, s, w, 0, 0, a) ++ ++#define MUX_F(_id, cname, tb, pnames, o, s, w, f, mf) \ ++ __MUX(_id, NULL, cname, tb, pnames, o, s, w, f, mf, NULL) ++ ++#define MUX_FA(_id, cname, tb, pnames, o, s, w, f, mf, a) \ ++ __MUX(_id, NULL, cname, tb, pnames, o, s, w, f, mf, a) ++ ++/** ++ * @id: platform specific id of the clock. ++ * struct ingenic_div_clock: information about div clock ++ * @dev_name: name of the device to which this clock belongs. ++ * @name: name of this div clock. ++ * @parent_name: name of the parent clock. ++ * @flags: optional flags for basic clock. ++ * @offset: offset of the register for configuring the div. ++ * @shift: starting bit location of the div control bit-field in @reg. ++ * @busy_offset: offset of the register waiting for div stable. ++ * @busy_shift: bit-field of the busy bit in busy_reg, by finding the busy shift, we can also find the ce, and stop bit. ++ * @en_shift: points to some gateble clk in div cfg, ugly we gate clock in div clocks. ++ * @div_flags: divider flags. ++ * @alias: optional clock alias name to be assigned to this clock. ++ * @table: clk div table if possible. ++ */ ++struct ingenic_div_clock { ++ unsigned int id; ++ const char *dev_name; ++ const char *name; ++ const char *parent_name; ++ unsigned long flags; ++ unsigned long offset; ++ u8 shift; ++ u8 width; ++ ++ unsigned long busy_offset; ++ int busy_shift; ++ int en_shift; ++ int stop_shift; ++ ++ int div_flags; ++ const char *alias; ++ struct clk_div_table *table; ++}; ++ ++#define __DIV(_id, dname, cname, pname, o, s, w, bs, e, st, f, df, a, t) \ ++ { \ ++ .id = _id, \ ++ .dev_name = dname, \ ++ .name = cname, \ ++ .parent_name = pname, \ ++ .flags = (f | CLK_IGNORE_UNUSED), \ ++ .offset = o, \ ++ .shift = s, \ ++ .width = w, \ ++ .div_flags = df, \ ++ .busy_shift = bs, \ ++ .en_shift = e, \ ++ .stop_shift = st, \ ++ .alias = a, \ ++ .table = t, \ ++ } ++ ++#define DIV(_id, cname, pname, o, w, df, t) \ ++ __DIV(_id, NULL, cname, pname, o, 0, w, 28, 29, 27, 0, df, cname, t) ++ ++#define DIV_EN(_id, cname, pname, o, s, w, bs, e) \ ++ __DIV(_id, NULL, cname, pname, o, s, w, bs, e, 0, 0, NULL, NULL) ++ ++/** ++ * @id: platform specific id of the clock. ++ * struct ingenic_bus_clock: information about div clock ++ * @dev_name: name of the device to which this clock belongs. ++ * @name: name of this div clock. ++ * @parent_name: name of the parent clock. ++ * @flags: optional flags for basic clock. ++ * @cfg_offset: offset of the register for configuring the div. ++ * @div_shift: starting bit location of the div control bit-field in @reg. ++ * @div_width: bit width of the div field. ++ * @busy_offset: offset of the register waiting for div stable. ++ * @busy_shift: bit-field of the busy bit in busy_reg, by finding the busy shift, we can also find the ce, and stop bit. ++ * @en_shift: points to some gateble clk in div cfg, ugly we gate clock in div clocks. ++ * @div_flags: flags for div-type clock, For example, DIV_NO_BUSY. ++ * @alias: optional clock alias name to be assigned to this clock. ++ * @table: clk div table if possible. ++ */ ++ ++ ++struct ingenic_bus_clock { ++ unsigned int id; ++ const char *dev_name; ++ const char *name; ++ const char *parent_name; ++ unsigned long flags; ++ unsigned long cfg_offset; ++ u8 div_shift1; ++ u8 div_width1; ++ u8 div_shift2; ++ u8 div_width2; ++ int ce_shift; ++ ++ int busy_offset; ++ int busy_shift; ++ ++ int div_flags; ++ int div_flags_2; ++ const char *alias; ++ struct clk_div_table *table; ++}; ++ ++#define __BUS_DIV(_id, dname, cname, pname, o, s1, w1, s2, w2, bo, bs, ce, f, df, df2, a, t) \ ++ { \ ++ .id = _id, \ ++ .dev_name = dname, \ ++ .name = cname, \ ++ .parent_name = pname, \ ++ .flags = (f | CLK_IGNORE_UNUSED), \ ++ .cfg_offset = o, \ ++ .div_shift1 = s1, \ ++ .div_width1 = w1, \ ++ .div_shift2 = s2, \ ++ .div_width2 = w2, \ ++ .ce_shift = ce, \ ++ .busy_offset = bo, \ ++ .busy_shift = bs, \ ++ .div_flags = df, \ ++ .alias = a, \ ++ .table = t, \ ++ .div_flags_2 = df2, \ ++ } ++ ++#define BUS_DIV(_id, cname, pname, o, s1, w1, s2, w2, bo, bs, ce, df2) \ ++ __BUS_DIV(_id, NULL, cname, pname, o, s1, w1, s2, w2, bo, bs, ce, CLK_GET_RATE_NOCACHE, 0, df2, cname, NULL) ++ ++ ++ ++struct ingenic_fra_div_clock { ++ unsigned int id; ++ const char *dev_name; ++ const char *name; ++ const char *parent_name; ++ unsigned long flags; ++ ++ unsigned long offset; ++ u8 mshift; ++ u8 mwidth; ++ u8 nshift; ++ u8 nwidth; ++ ++ int div_flags; ++ const char *alias; ++}; ++ ++#define __FRA_DIV(_id, dname, cname, pname, f, o, ms, mw, ns, nw, df, a) \ ++ { \ ++ .id = _id, \ ++ .dev_name = dname, \ ++ .name = cname, \ ++ .parent_name = pname, \ ++ .flags = f, \ ++ .offset = o, \ ++ .mshift = ms, \ ++ .mwidth = mw, \ ++ .nshift = ns, \ ++ .nwidth = nw, \ ++ .div_flags = df, \ ++ .alias = a, \ ++ } ++ ++#define FRA_DIV(_id, cname, pname, o, ms, mw, ns, nw) \ ++ __FRA_DIV(_id, NULL, cname, pname, 0, o, ms, mw, ns, nw, 0, cname) ++ ++/** ++ * struct ingenic_gate_clock: information about gate clock ++ * @id: platform specific id of the clock. ++ * @dev_name: name of the device to which this clock belongs. ++ * @name: name of this gate clock. ++ * @parent_name: name of the parent clock. ++ * @pwc_name: name of the power control clk under this clock gate. ++ * @flags: optional flags for basic clock. ++ * @offset: offset of the register for configuring the gate. ++ * @bit_idx: bit index of the gate control bit-field in @reg. ++ * @sram_offset: offset of the corresponding sram contrl reg. ++ * @sram_shift: shift for the sram control bit idx in sram_reg. ++ * @gate_flags: flags for gate-type clock. ++ * @alias: optional clock alias name to be assigned to this clock. ++ * @gate_flags: flags for gate clock. ++ * @alias: alias name for this clock. ++ */ ++struct ingenic_gate_clock { ++ unsigned int id; ++ const char *dev_name; ++ const char *name; ++ const char *parent_name; ++ ++ unsigned long flags; ++ unsigned long offset; ++ u8 bit_idx; ++ int sram_offset; ++ int sram_shift; ++ u8 gate_flags; ++ const char *alias; ++ ++}; ++ ++#define __GATE(_id, dname, cname, pname, o, b, f, so, sps, gf, a) \ ++ { \ ++ .id = _id, \ ++ .dev_name = dname, \ ++ .name = cname, \ ++ .parent_name = pname, \ ++ .flags = f, \ ++ .offset = o, \ ++ .bit_idx = b, \ ++ .sram_offset = so, \ ++ .sram_shift = sps, \ ++ .gate_flags = gf, \ ++ .alias = a, \ ++ } ++ ++#define GATE(_id, cname, pname, o, b, f, gf) \ ++ __GATE(_id, NULL, cname, pname, o, b, f, -1, -1, gf, cname) ++ ++ ++#define GATE_SRAM(_id, cname, pname, o, b, f, gf, so, sps) \ ++ __GATE(_id, NULL, cname, pname, NULL, o, b, f, so, sps, gf, cname) ++ ++ ++/** ++ * struct ingenic_power_clock: information about power clock ++ * @id: platform specific id of the clock. ++ * @dev_name: name of the device to which this clock belongs. ++ * @name: name of this gate clock. ++ * @parent_name: name of the parent clock. ++ * @flags: optional flags for basic clock. ++ * @offset: offset of the register for configuring the gate. ++ * @ctrl_bit: bit index of the power control bit-field in @reg. ++ * @wait_bit: bit index of the power status bit-field in @reg. ++ * @delay_ms: wait for ms time stable @reg. ++ * @gate_flags: flags for gate-type clock. ++ * @alias: optional clock alias name to be assigned to this clock. ++ * @clk_flags: ingneic special flags. ++ */ ++struct ingenic_gate_power { ++ unsigned int id; ++ const char *dev_name; ++ const char *name; ++ const char *parent_name; ++ ++ unsigned long flags; ++ unsigned long offset; ++ u8 ctrl_bit; ++ u8 wait_bit; ++ u8 gate_flags; ++ const char *alias; ++ unsigned long power_flags; ++}; ++ ++#define __POWER(_id, dname, cname, pname, f, o, cb, wb, gf, a, pf) \ ++ { \ ++ .id = _id, \ ++ .dev_name = dname, \ ++ .name = cname, \ ++ .parent_name = pname, \ ++ .flags = f, \ ++ .offset = o, \ ++ .ctrl_bit = cb, \ ++ .wait_bit = wb, \ ++ .gate_flags = gf, \ ++ .alias = a, \ ++ .power_flags = pf, \ ++ } ++ ++#define POWER(_id, cname, pname, o, cb, wb, f, gf, pf) \ ++ __POWER(_id, NULL, cname, pname, f, o, cb, wb, gf, cname, pf) ++ ++#define PNAME(x) static const char *x[] __initdata ++ ++/** ++ * struct ingenic_clk_reg_dump: register dump of clock controller registers. ++ * @offset: clock register offset from the controller base address. ++ * @value: the value to be register at offset. ++ */ ++struct ingenic_clk_reg_dump { ++ u32 offset; ++ u32 value; ++}; ++ ++/** ++ * struct ingenic_pll_clock: information about pll clock ++ * @id: platform specific id of the clock. ++ * @dev_name: name of the device to which this clock belongs. ++ * @name: name of this pll clock. ++ * @parent_name: name of the parent clock. ++ * @flags: optional flags for basic clock. ++ * @con_offset: offset of the register for configuring the PLL. ++ * @lock_offset: offset of the register for locking the PLL. ++ * @type: Type of PLL to be registered. ++ * @alias: optional clock alias name to be assigned to this clock. ++ */ ++struct ingenic_pll_clock { ++ unsigned int id; ++ const char *dev_name; ++ const char *name; ++ const char *parent_name; ++ ++ unsigned long flags; ++ int con_offset; ++ int lock_offset; ++ const char *alias; ++ struct ingenic_pll_hwdesc *hwdesc; ++ struct ingenic_pll_rate_table *rate_table; ++}; ++ ++#define PLL(_id, _name, _parent_name, _hwdesc, _rtable) \ ++{ \ ++ .id = _id, \ ++ .dev_name = _name, \ ++ .name = _name, \ ++ .parent_name = _parent_name, \ ++ .hwdesc = _hwdesc, \ ++ .rate_table = _rtable, \ ++} ++ ++struct ingenic_clock_reg_cache { ++ struct list_head node; ++ void __iomem *reg_base; ++ struct ingenic_clk_reg_dump *rdump; ++ unsigned int rd_num; ++}; ++ ++struct ingenic_cmu_info { ++ /* list of pll clocks and respective count */ ++ struct ingenic_pll_clock *pll_clks; ++ unsigned int nr_pll_clks; ++ /* list of mux clocks and respective count */ ++ struct ingenic_mux_clock *mux_clks; ++ unsigned int nr_mux_clks; ++ /* list of div clocks and respective count */ ++ struct ingenic_div_clock *div_clks; ++ unsigned int nr_div_clks; ++ /* list of gate clocks and respective count */ ++ struct ingenic_gate_clock *gate_clks; ++ unsigned int nr_gate_clks; ++ /* list of fixed clocks and respective count */ ++ struct ingenic_fixed_rate_clock *fixed_clks; ++ unsigned int nr_fixed_clks; ++ /* list of fixed factor clocks and respective count */ ++ struct ingenic_fixed_factor_clock *fixed_factor_clks; ++ unsigned int nr_fixed_factor_clks; ++ /* total number of clocks with IDs assigned*/ ++ unsigned int nr_clk_ids; ++ ++ /* list and number of clocks registers */ ++ unsigned long *clk_regs; ++ unsigned int nr_clk_regs; ++}; ++ ++struct ingenic_cpm_info { ++ struct ingenic_power_clock *pwc_clks; ++ unsigned int nr_pwc_clks; ++ ++}; ++ ++extern struct ingenic_clk_provider *__init ingenic_clk_init( ++ struct device_node *np, void __iomem *base, ++ unsigned long nr_clks); ++extern void __init ingenic_clk_of_add_provider(struct device_node *np, ++ struct ingenic_clk_provider *ctx); ++extern void __init ingenic_clk_of_register_fixed_ext( ++ struct ingenic_clk_provider *ctx, ++ struct ingenic_fixed_rate_clock *fixed_rate_clk, ++ unsigned int nr_fixed_rate_clk, ++ const struct of_device_id *clk_matches); ++ ++extern void ingenic_clk_add_lookup(struct ingenic_clk_provider *ctx, ++ struct clk *clk, unsigned int id); ++ ++extern void __init ingenic_clk_register_alias(struct ingenic_clk_provider *ctx, ++ const struct ingenic_clock_alias *list, ++ unsigned int nr_clk); ++extern void __init ingenic_clk_register_fixed_rate( ++ struct ingenic_clk_provider *ctx, ++ const struct ingenic_fixed_rate_clock *clk_list, ++ unsigned int nr_clk); ++extern void __init ingenic_clk_register_fixed_factor( ++ struct ingenic_clk_provider *ctx, ++ const struct ingenic_fixed_factor_clock *list, ++ unsigned int nr_clk); ++extern void __init ingenic_clk_register_mux(struct ingenic_clk_provider *ctx, ++ const struct ingenic_mux_clock *clk_list, ++ unsigned int nr_clk); ++extern void __init ingenic_clk_register_cgu_div(struct ingenic_clk_provider *ctx, ++ const struct ingenic_div_clock *clk_list, ++ unsigned int nr_clk); ++ ++extern void __init ingenic_clk_register_gate(struct ingenic_clk_provider *ctx, ++ const struct ingenic_gate_clock *list, ++ unsigned int nr_clk); ++ ++extern void __init ingenic_power_register_gate(struct ingenic_clk_provider *ctx, ++ const struct ingenic_gate_power *list, ++ unsigned int nr_clk); ++ ++extern void __init ingenic_clk_register_pll(struct ingenic_clk_provider *ctx, ++ const struct ingenic_pll_clock *pll_list, ++ unsigned int nr_clk, void __iomem *base); ++ ++extern struct ingenic_clk_provider __init *ingenic_cmu_register_one( ++ struct device_node *, ++ struct ingenic_cmu_info *); ++ ++extern unsigned long _get_rate(const char *clk_name); ++ ++extern void ingenic_clk_save(void __iomem *base, ++ struct ingenic_clk_reg_dump *rd, ++ unsigned int num_regs); ++extern void ingenic_clk_restore(void __iomem *base, ++ const struct ingenic_clk_reg_dump *rd, ++ unsigned int num_regs); ++extern struct ingenic_clk_reg_dump *ingenic_clk_alloc_reg_dump( ++ const unsigned long *rdump, ++ unsigned long nr_rdump); ++ ++extern void __init ingenic_clk_register_bus_div(struct ingenic_clk_provider *ctx, ++ const struct ingenic_bus_clock *list, ++ unsigned int nr_clk); ++ ++extern void __init ingenic_clk_register_fra_div(struct ingenic_clk_provider *ctx, ++ const struct ingenic_fra_div_clock *list, ++ unsigned int nr_clk); ++ ++void ingenic_clk_of_dump(struct ingenic_clk_provider *ctx); ++#endif /* __INGENIC_CLK_H */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_jz4740-cgu.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_jz4740-cgu.c.patch new file mode 100644 index 00000000..54211295 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_jz4740-cgu.c.patch @@ -0,0 +1,307 @@ +diff -drupN a/drivers/clk/ingenic/jz4740-cgu.c b/drivers/clk/ingenic/jz4740-cgu.c +--- a/drivers/clk/ingenic/jz4740-cgu.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/clk/ingenic/jz4740-cgu.c 1970-01-01 03:00:00.000000000 +0300 +@@ -1,303 +0,0 @@ +-/* +- * Ingenic JZ4740 SoC CGU driver +- * +- * Copyright (c) 2015 Imagination Technologies +- * Author: Paul Burton +- * +- * 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. +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include "cgu.h" +- +-/* CGU register offsets */ +-#define CGU_REG_CPCCR 0x00 +-#define CGU_REG_LCR 0x04 +-#define CGU_REG_CPPCR 0x10 +-#define CGU_REG_CLKGR 0x20 +-#define CGU_REG_SCR 0x24 +-#define CGU_REG_I2SCDR 0x60 +-#define CGU_REG_LPCDR 0x64 +-#define CGU_REG_MSCCDR 0x68 +-#define CGU_REG_UHCCDR 0x6c +-#define CGU_REG_SSICDR 0x74 +- +-/* bits within a PLL control register */ +-#define PLLCTL_M_SHIFT 23 +-#define PLLCTL_M_MASK (0x1ff << PLLCTL_M_SHIFT) +-#define PLLCTL_N_SHIFT 18 +-#define PLLCTL_N_MASK (0x1f << PLLCTL_N_SHIFT) +-#define PLLCTL_OD_SHIFT 16 +-#define PLLCTL_OD_MASK (0x3 << PLLCTL_OD_SHIFT) +-#define PLLCTL_STABLE (1 << 10) +-#define PLLCTL_BYPASS (1 << 9) +-#define PLLCTL_ENABLE (1 << 8) +- +-/* bits within the LCR register */ +-#define LCR_SLEEP (1 << 0) +- +-/* bits within the CLKGR register */ +-#define CLKGR_UDC (1 << 11) +- +-static struct ingenic_cgu *cgu; +- +-static const s8 pll_od_encoding[4] = { +- 0x0, 0x1, -1, 0x3, +-}; +- +-static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = { +- +- /* External clocks */ +- +- [JZ4740_CLK_EXT] = { "ext", CGU_CLK_EXT }, +- [JZ4740_CLK_RTC] = { "rtc", CGU_CLK_EXT }, +- +- [JZ4740_CLK_PLL] = { +- "pll", CGU_CLK_PLL, +- .parents = { JZ4740_CLK_EXT, -1, -1, -1 }, +- .pll = { +- .reg = CGU_REG_CPPCR, +- .m_shift = 23, +- .m_bits = 9, +- .m_offset = 2, +- .n_shift = 18, +- .n_bits = 5, +- .n_offset = 2, +- .od_shift = 16, +- .od_bits = 2, +- .od_max = 4, +- .od_encoding = pll_od_encoding, +- .stable_bit = 10, +- .bypass_bit = 9, +- .enable_bit = 8, +- }, +- }, +- +- /* Muxes & dividers */ +- +- [JZ4740_CLK_PLL_HALF] = { +- "pll half", CGU_CLK_DIV, +- .parents = { JZ4740_CLK_PLL, -1, -1, -1 }, +- .div = { CGU_REG_CPCCR, 21, 1, -1, -1, -1 }, +- }, +- +- [JZ4740_CLK_CCLK] = { +- "cclk", CGU_CLK_DIV, +- .parents = { JZ4740_CLK_PLL, -1, -1, -1 }, +- .div = { CGU_REG_CPCCR, 0, 4, 22, -1, -1 }, +- }, +- +- [JZ4740_CLK_HCLK] = { +- "hclk", CGU_CLK_DIV, +- .parents = { JZ4740_CLK_PLL, -1, -1, -1 }, +- .div = { CGU_REG_CPCCR, 4, 4, 22, -1, -1 }, +- }, +- +- [JZ4740_CLK_PCLK] = { +- "pclk", CGU_CLK_DIV, +- .parents = { JZ4740_CLK_PLL, -1, -1, -1 }, +- .div = { CGU_REG_CPCCR, 8, 4, 22, -1, -1 }, +- }, +- +- [JZ4740_CLK_MCLK] = { +- "mclk", CGU_CLK_DIV, +- .parents = { JZ4740_CLK_PLL, -1, -1, -1 }, +- .div = { CGU_REG_CPCCR, 12, 4, 22, -1, -1 }, +- }, +- +- [JZ4740_CLK_LCD] = { +- "lcd", CGU_CLK_DIV | CGU_CLK_GATE, +- .parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 }, +- .div = { CGU_REG_CPCCR, 16, 5, 22, -1, -1 }, +- .gate = { CGU_REG_CLKGR, 10 }, +- }, +- +- [JZ4740_CLK_LCD_PCLK] = { +- "lcd_pclk", CGU_CLK_DIV, +- .parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 }, +- .div = { CGU_REG_LPCDR, 0, 11, -1, -1, -1 }, +- }, +- +- [JZ4740_CLK_I2S] = { +- "i2s", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, +- .parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL_HALF, -1, -1 }, +- .mux = { CGU_REG_CPCCR, 31, 1 }, +- .div = { CGU_REG_I2SCDR, 0, 8, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR, 6 }, +- }, +- +- [JZ4740_CLK_SPI] = { +- "spi", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, +- .parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL, -1, -1 }, +- .mux = { CGU_REG_SSICDR, 31, 1 }, +- .div = { CGU_REG_SSICDR, 0, 4, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR, 4 }, +- }, +- +- [JZ4740_CLK_MMC] = { +- "mmc", CGU_CLK_DIV | CGU_CLK_GATE, +- .parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 }, +- .div = { CGU_REG_MSCCDR, 0, 5, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR, 7 }, +- }, +- +- [JZ4740_CLK_UHC] = { +- "uhc", CGU_CLK_DIV | CGU_CLK_GATE, +- .parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 }, +- .div = { CGU_REG_UHCCDR, 0, 4, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR, 14 }, +- }, +- +- [JZ4740_CLK_UDC] = { +- "udc", CGU_CLK_MUX | CGU_CLK_DIV, +- .parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL_HALF, -1, -1 }, +- .mux = { CGU_REG_CPCCR, 29, 1 }, +- .div = { CGU_REG_CPCCR, 23, 6, -1, -1, -1 }, +- .gate = { CGU_REG_SCR, 6 }, +- }, +- +- /* Gate-only clocks */ +- +- [JZ4740_CLK_UART0] = { +- "uart0", CGU_CLK_GATE, +- .parents = { JZ4740_CLK_EXT, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR, 0 }, +- }, +- +- [JZ4740_CLK_UART1] = { +- "uart1", CGU_CLK_GATE, +- .parents = { JZ4740_CLK_EXT, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR, 15 }, +- }, +- +- [JZ4740_CLK_DMA] = { +- "dma", CGU_CLK_GATE, +- .parents = { JZ4740_CLK_PCLK, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR, 12 }, +- }, +- +- [JZ4740_CLK_IPU] = { +- "ipu", CGU_CLK_GATE, +- .parents = { JZ4740_CLK_PCLK, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR, 13 }, +- }, +- +- [JZ4740_CLK_ADC] = { +- "adc", CGU_CLK_GATE, +- .parents = { JZ4740_CLK_EXT, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR, 8 }, +- }, +- +- [JZ4740_CLK_I2C] = { +- "i2c", CGU_CLK_GATE, +- .parents = { JZ4740_CLK_EXT, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR, 3 }, +- }, +- +- [JZ4740_CLK_AIC] = { +- "aic", CGU_CLK_GATE, +- .parents = { JZ4740_CLK_EXT, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR, 5 }, +- }, +-}; +- +-static void __init jz4740_cgu_init(struct device_node *np) +-{ +- int retval; +- +- cgu = ingenic_cgu_new(jz4740_cgu_clocks, +- ARRAY_SIZE(jz4740_cgu_clocks), np); +- if (!cgu) { +- pr_err("%s: failed to initialise CGU\n", __func__); +- return; +- } +- +- retval = ingenic_cgu_register_clocks(cgu); +- if (retval) +- pr_err("%s: failed to register CGU Clocks\n", __func__); +-} +-CLK_OF_DECLARE(jz4740_cgu, "ingenic,jz4740-cgu", jz4740_cgu_init); +- +-void jz4740_clock_set_wait_mode(enum jz4740_wait_mode mode) +-{ +- uint32_t lcr = readl(cgu->base + CGU_REG_LCR); +- +- switch (mode) { +- case JZ4740_WAIT_MODE_IDLE: +- lcr &= ~LCR_SLEEP; +- break; +- +- case JZ4740_WAIT_MODE_SLEEP: +- lcr |= LCR_SLEEP; +- break; +- } +- +- writel(lcr, cgu->base + CGU_REG_LCR); +-} +- +-void jz4740_clock_udc_disable_auto_suspend(void) +-{ +- uint32_t clkgr = readl(cgu->base + CGU_REG_CLKGR); +- +- clkgr &= ~CLKGR_UDC; +- writel(clkgr, cgu->base + CGU_REG_CLKGR); +-} +-EXPORT_SYMBOL_GPL(jz4740_clock_udc_disable_auto_suspend); +- +-void jz4740_clock_udc_enable_auto_suspend(void) +-{ +- uint32_t clkgr = readl(cgu->base + CGU_REG_CLKGR); +- +- clkgr |= CLKGR_UDC; +- writel(clkgr, cgu->base + CGU_REG_CLKGR); +-} +-EXPORT_SYMBOL_GPL(jz4740_clock_udc_enable_auto_suspend); +- +-#define JZ_CLOCK_GATE_UART0 BIT(0) +-#define JZ_CLOCK_GATE_TCU BIT(1) +-#define JZ_CLOCK_GATE_DMAC BIT(12) +- +-void jz4740_clock_suspend(void) +-{ +- uint32_t clkgr, cppcr; +- +- clkgr = readl(cgu->base + CGU_REG_CLKGR); +- clkgr |= JZ_CLOCK_GATE_TCU | JZ_CLOCK_GATE_DMAC | JZ_CLOCK_GATE_UART0; +- writel(clkgr, cgu->base + CGU_REG_CLKGR); +- +- cppcr = readl(cgu->base + CGU_REG_CPPCR); +- cppcr &= ~BIT(jz4740_cgu_clocks[JZ4740_CLK_PLL].pll.enable_bit); +- writel(cppcr, cgu->base + CGU_REG_CPPCR); +-} +- +-void jz4740_clock_resume(void) +-{ +- uint32_t clkgr, cppcr, stable; +- +- cppcr = readl(cgu->base + CGU_REG_CPPCR); +- cppcr |= BIT(jz4740_cgu_clocks[JZ4740_CLK_PLL].pll.enable_bit); +- writel(cppcr, cgu->base + CGU_REG_CPPCR); +- +- stable = BIT(jz4740_cgu_clocks[JZ4740_CLK_PLL].pll.stable_bit); +- do { +- cppcr = readl(cgu->base + CGU_REG_CPPCR); +- } while (!(cppcr & stable)); +- +- clkgr = readl(cgu->base + CGU_REG_CLKGR); +- clkgr &= ~JZ_CLOCK_GATE_TCU; +- clkgr &= ~JZ_CLOCK_GATE_DMAC; +- clkgr &= ~JZ_CLOCK_GATE_UART0; +- writel(clkgr, cgu->base + CGU_REG_CLKGR); +-} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_jz4780-cgu.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_jz4780-cgu.c.patch new file mode 100644 index 00000000..23936cbc --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_jz4780-cgu.c.patch @@ -0,0 +1,737 @@ +diff -drupN a/drivers/clk/ingenic/jz4780-cgu.c b/drivers/clk/ingenic/jz4780-cgu.c +--- a/drivers/clk/ingenic/jz4780-cgu.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/clk/ingenic/jz4780-cgu.c 1970-01-01 03:00:00.000000000 +0300 +@@ -1,733 +0,0 @@ +-/* +- * Ingenic JZ4780 SoC CGU driver +- * +- * Copyright (c) 2013-2015 Imagination Technologies +- * Author: Paul Burton +- * +- * 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. +- */ +- +-#include +-#include +-#include +-#include +-#include "cgu.h" +- +-/* CGU register offsets */ +-#define CGU_REG_CLOCKCONTROL 0x00 +-#define CGU_REG_PLLCONTROL 0x0c +-#define CGU_REG_APLL 0x10 +-#define CGU_REG_MPLL 0x14 +-#define CGU_REG_EPLL 0x18 +-#define CGU_REG_VPLL 0x1c +-#define CGU_REG_CLKGR0 0x20 +-#define CGU_REG_OPCR 0x24 +-#define CGU_REG_CLKGR1 0x28 +-#define CGU_REG_DDRCDR 0x2c +-#define CGU_REG_VPUCDR 0x30 +-#define CGU_REG_USBPCR 0x3c +-#define CGU_REG_USBRDT 0x40 +-#define CGU_REG_USBVBFIL 0x44 +-#define CGU_REG_USBPCR1 0x48 +-#define CGU_REG_LP0CDR 0x54 +-#define CGU_REG_I2SCDR 0x60 +-#define CGU_REG_LP1CDR 0x64 +-#define CGU_REG_MSC0CDR 0x68 +-#define CGU_REG_UHCCDR 0x6c +-#define CGU_REG_SSICDR 0x74 +-#define CGU_REG_CIMCDR 0x7c +-#define CGU_REG_PCMCDR 0x84 +-#define CGU_REG_GPUCDR 0x88 +-#define CGU_REG_HDMICDR 0x8c +-#define CGU_REG_MSC1CDR 0xa4 +-#define CGU_REG_MSC2CDR 0xa8 +-#define CGU_REG_BCHCDR 0xac +-#define CGU_REG_CLOCKSTATUS 0xd4 +- +-/* bits within the OPCR register */ +-#define OPCR_SPENDN0 (1 << 7) +-#define OPCR_SPENDN1 (1 << 6) +- +-/* bits within the USBPCR register */ +-#define USBPCR_USB_MODE BIT(31) +-#define USBPCR_IDPULLUP_MASK (0x3 << 28) +-#define USBPCR_COMMONONN BIT(25) +-#define USBPCR_VBUSVLDEXT BIT(24) +-#define USBPCR_VBUSVLDEXTSEL BIT(23) +-#define USBPCR_POR BIT(22) +-#define USBPCR_OTG_DISABLE BIT(20) +-#define USBPCR_COMPDISTUNE_MASK (0x7 << 17) +-#define USBPCR_OTGTUNE_MASK (0x7 << 14) +-#define USBPCR_SQRXTUNE_MASK (0x7 << 11) +-#define USBPCR_TXFSLSTUNE_MASK (0xf << 7) +-#define USBPCR_TXPREEMPHTUNE BIT(6) +-#define USBPCR_TXHSXVTUNE_MASK (0x3 << 4) +-#define USBPCR_TXVREFTUNE_MASK 0xf +- +-/* bits within the USBPCR1 register */ +-#define USBPCR1_REFCLKSEL_SHIFT 26 +-#define USBPCR1_REFCLKSEL_MASK (0x3 << USBPCR1_REFCLKSEL_SHIFT) +-#define USBPCR1_REFCLKSEL_CORE (0x2 << USBPCR1_REFCLKSEL_SHIFT) +-#define USBPCR1_REFCLKDIV_SHIFT 24 +-#define USBPCR1_REFCLKDIV_MASK (0x3 << USBPCR1_REFCLKDIV_SHIFT) +-#define USBPCR1_REFCLKDIV_19_2 (0x3 << USBPCR1_REFCLKDIV_SHIFT) +-#define USBPCR1_REFCLKDIV_48 (0x2 << USBPCR1_REFCLKDIV_SHIFT) +-#define USBPCR1_REFCLKDIV_24 (0x1 << USBPCR1_REFCLKDIV_SHIFT) +-#define USBPCR1_REFCLKDIV_12 (0x0 << USBPCR1_REFCLKDIV_SHIFT) +-#define USBPCR1_USB_SEL BIT(28) +-#define USBPCR1_WORD_IF0 BIT(19) +-#define USBPCR1_WORD_IF1 BIT(18) +- +-/* bits within the USBRDT register */ +-#define USBRDT_VBFIL_LD_EN BIT(25) +-#define USBRDT_USBRDT_MASK 0x7fffff +- +-/* bits within the USBVBFIL register */ +-#define USBVBFIL_IDDIGFIL_SHIFT 16 +-#define USBVBFIL_IDDIGFIL_MASK (0xffff << USBVBFIL_IDDIGFIL_SHIFT) +-#define USBVBFIL_USBVBFIL_MASK (0xffff) +- +-static struct ingenic_cgu *cgu; +- +-static u8 jz4780_otg_phy_get_parent(struct clk_hw *hw) +-{ +- /* we only use CLKCORE, revisit if that ever changes */ +- return 0; +-} +- +-static int jz4780_otg_phy_set_parent(struct clk_hw *hw, u8 idx) +-{ +- unsigned long flags; +- u32 usbpcr1; +- +- if (idx > 0) +- return -EINVAL; +- +- spin_lock_irqsave(&cgu->lock, flags); +- +- usbpcr1 = readl(cgu->base + CGU_REG_USBPCR1); +- usbpcr1 &= ~USBPCR1_REFCLKSEL_MASK; +- /* we only use CLKCORE */ +- usbpcr1 |= USBPCR1_REFCLKSEL_CORE; +- writel(usbpcr1, cgu->base + CGU_REG_USBPCR1); +- +- spin_unlock_irqrestore(&cgu->lock, flags); +- return 0; +-} +- +-static unsigned long jz4780_otg_phy_recalc_rate(struct clk_hw *hw, +- unsigned long parent_rate) +-{ +- u32 usbpcr1; +- unsigned refclk_div; +- +- usbpcr1 = readl(cgu->base + CGU_REG_USBPCR1); +- refclk_div = usbpcr1 & USBPCR1_REFCLKDIV_MASK; +- +- switch (refclk_div) { +- case USBPCR1_REFCLKDIV_12: +- return 12000000; +- +- case USBPCR1_REFCLKDIV_24: +- return 24000000; +- +- case USBPCR1_REFCLKDIV_48: +- return 48000000; +- +- case USBPCR1_REFCLKDIV_19_2: +- return 19200000; +- } +- +- BUG(); +- return parent_rate; +-} +- +-static long jz4780_otg_phy_round_rate(struct clk_hw *hw, unsigned long req_rate, +- unsigned long *parent_rate) +-{ +- if (req_rate < 15600000) +- return 12000000; +- +- if (req_rate < 21600000) +- return 19200000; +- +- if (req_rate < 36000000) +- return 24000000; +- +- return 48000000; +-} +- +-static int jz4780_otg_phy_set_rate(struct clk_hw *hw, unsigned long req_rate, +- unsigned long parent_rate) +-{ +- unsigned long flags; +- u32 usbpcr1, div_bits; +- +- switch (req_rate) { +- case 12000000: +- div_bits = USBPCR1_REFCLKDIV_12; +- break; +- +- case 19200000: +- div_bits = USBPCR1_REFCLKDIV_19_2; +- break; +- +- case 24000000: +- div_bits = USBPCR1_REFCLKDIV_24; +- break; +- +- case 48000000: +- div_bits = USBPCR1_REFCLKDIV_48; +- break; +- +- default: +- return -EINVAL; +- } +- +- spin_lock_irqsave(&cgu->lock, flags); +- +- usbpcr1 = readl(cgu->base + CGU_REG_USBPCR1); +- usbpcr1 &= ~USBPCR1_REFCLKDIV_MASK; +- usbpcr1 |= div_bits; +- writel(usbpcr1, cgu->base + CGU_REG_USBPCR1); +- +- spin_unlock_irqrestore(&cgu->lock, flags); +- return 0; +-} +- +-static struct clk_ops jz4780_otg_phy_ops = { +- .get_parent = jz4780_otg_phy_get_parent, +- .set_parent = jz4780_otg_phy_set_parent, +- +- .recalc_rate = jz4780_otg_phy_recalc_rate, +- .round_rate = jz4780_otg_phy_round_rate, +- .set_rate = jz4780_otg_phy_set_rate, +-}; +- +-static const s8 pll_od_encoding[16] = { +- 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, +- 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, +-}; +- +-static const struct ingenic_cgu_clk_info jz4780_cgu_clocks[] = { +- +- /* External clocks */ +- +- [JZ4780_CLK_EXCLK] = { "ext", CGU_CLK_EXT }, +- [JZ4780_CLK_RTCLK] = { "rtc", CGU_CLK_EXT }, +- +- /* PLLs */ +- +-#define DEF_PLL(name) { \ +- .reg = CGU_REG_ ## name, \ +- .m_shift = 19, \ +- .m_bits = 13, \ +- .m_offset = 1, \ +- .n_shift = 13, \ +- .n_bits = 6, \ +- .n_offset = 1, \ +- .od_shift = 9, \ +- .od_bits = 4, \ +- .od_max = 16, \ +- .od_encoding = pll_od_encoding, \ +- .stable_bit = 6, \ +- .bypass_bit = 1, \ +- .enable_bit = 0, \ +-} +- +- [JZ4780_CLK_APLL] = { +- "apll", CGU_CLK_PLL, +- .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 }, +- .pll = DEF_PLL(APLL), +- }, +- +- [JZ4780_CLK_MPLL] = { +- "mpll", CGU_CLK_PLL, +- .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 }, +- .pll = DEF_PLL(MPLL), +- }, +- +- [JZ4780_CLK_EPLL] = { +- "epll", CGU_CLK_PLL, +- .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 }, +- .pll = DEF_PLL(EPLL), +- }, +- +- [JZ4780_CLK_VPLL] = { +- "vpll", CGU_CLK_PLL, +- .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 }, +- .pll = DEF_PLL(VPLL), +- }, +- +-#undef DEF_PLL +- +- /* Custom (SoC-specific) OTG PHY */ +- +- [JZ4780_CLK_OTGPHY] = { +- "otg_phy", CGU_CLK_CUSTOM, +- .parents = { -1, -1, JZ4780_CLK_EXCLK, -1 }, +- .custom = { &jz4780_otg_phy_ops }, +- }, +- +- /* Muxes & dividers */ +- +- [JZ4780_CLK_SCLKA] = { +- "sclk_a", CGU_CLK_MUX, +- .parents = { -1, JZ4780_CLK_APLL, JZ4780_CLK_EXCLK, +- JZ4780_CLK_RTCLK }, +- .mux = { CGU_REG_CLOCKCONTROL, 30, 2 }, +- }, +- +- [JZ4780_CLK_CPUMUX] = { +- "cpumux", CGU_CLK_MUX, +- .parents = { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, +- JZ4780_CLK_EPLL }, +- .mux = { CGU_REG_CLOCKCONTROL, 28, 2 }, +- }, +- +- [JZ4780_CLK_CPU] = { +- "cpu", CGU_CLK_DIV, +- .parents = { JZ4780_CLK_CPUMUX, -1, -1, -1 }, +- .div = { CGU_REG_CLOCKCONTROL, 0, 4, 22, -1, -1 }, +- }, +- +- [JZ4780_CLK_L2CACHE] = { +- "l2cache", CGU_CLK_DIV, +- .parents = { JZ4780_CLK_CPUMUX, -1, -1, -1 }, +- .div = { CGU_REG_CLOCKCONTROL, 4, 4, -1, -1, -1 }, +- }, +- +- [JZ4780_CLK_AHB0] = { +- "ahb0", CGU_CLK_MUX | CGU_CLK_DIV, +- .parents = { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, +- JZ4780_CLK_EPLL }, +- .mux = { CGU_REG_CLOCKCONTROL, 26, 2 }, +- .div = { CGU_REG_CLOCKCONTROL, 8, 4, 21, -1, -1 }, +- }, +- +- [JZ4780_CLK_AHB2PMUX] = { +- "ahb2_apb_mux", CGU_CLK_MUX, +- .parents = { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, +- JZ4780_CLK_RTCLK }, +- .mux = { CGU_REG_CLOCKCONTROL, 24, 2 }, +- }, +- +- [JZ4780_CLK_AHB2] = { +- "ahb2", CGU_CLK_DIV, +- .parents = { JZ4780_CLK_AHB2PMUX, -1, -1, -1 }, +- .div = { CGU_REG_CLOCKCONTROL, 12, 4, 20, -1, -1 }, +- }, +- +- [JZ4780_CLK_PCLK] = { +- "pclk", CGU_CLK_DIV, +- .parents = { JZ4780_CLK_AHB2PMUX, -1, -1, -1 }, +- .div = { CGU_REG_CLOCKCONTROL, 16, 4, 20, -1, -1 }, +- }, +- +- [JZ4780_CLK_DDR] = { +- "ddr", CGU_CLK_MUX | CGU_CLK_DIV, +- .parents = { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, -1 }, +- .mux = { CGU_REG_DDRCDR, 30, 2 }, +- .div = { CGU_REG_DDRCDR, 0, 4, 29, 28, 27 }, +- }, +- +- [JZ4780_CLK_VPU] = { +- "vpu", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, +- .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, +- JZ4780_CLK_EPLL, -1 }, +- .mux = { CGU_REG_VPUCDR, 30, 2 }, +- .div = { CGU_REG_VPUCDR, 0, 4, 29, 28, 27 }, +- .gate = { CGU_REG_CLKGR1, 2 }, +- }, +- +- [JZ4780_CLK_I2SPLL] = { +- "i2s_pll", CGU_CLK_MUX | CGU_CLK_DIV, +- .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_EPLL, -1, -1 }, +- .mux = { CGU_REG_I2SCDR, 30, 1 }, +- .div = { CGU_REG_I2SCDR, 0, 8, 29, 28, 27 }, +- }, +- +- [JZ4780_CLK_I2S] = { +- "i2s", CGU_CLK_MUX, +- .parents = { JZ4780_CLK_EXCLK, JZ4780_CLK_I2SPLL, -1, -1 }, +- .mux = { CGU_REG_I2SCDR, 31, 1 }, +- }, +- +- [JZ4780_CLK_LCD0PIXCLK] = { +- "lcd0pixclk", CGU_CLK_MUX | CGU_CLK_DIV, +- .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, +- JZ4780_CLK_VPLL, -1 }, +- .mux = { CGU_REG_LP0CDR, 30, 2 }, +- .div = { CGU_REG_LP0CDR, 0, 8, 28, 27, 26 }, +- }, +- +- [JZ4780_CLK_LCD1PIXCLK] = { +- "lcd1pixclk", CGU_CLK_MUX | CGU_CLK_DIV, +- .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, +- JZ4780_CLK_VPLL, -1 }, +- .mux = { CGU_REG_LP1CDR, 30, 2 }, +- .div = { CGU_REG_LP1CDR, 0, 8, 28, 27, 26 }, +- }, +- +- [JZ4780_CLK_MSCMUX] = { +- "msc_mux", CGU_CLK_MUX, +- .parents = { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, -1 }, +- .mux = { CGU_REG_MSC0CDR, 30, 2 }, +- }, +- +- [JZ4780_CLK_MSC0] = { +- "msc0", CGU_CLK_DIV | CGU_CLK_GATE, +- .parents = { JZ4780_CLK_MSCMUX, -1, -1, -1 }, +- .div = { CGU_REG_MSC0CDR, 0, 8, 29, 28, 27 }, +- .gate = { CGU_REG_CLKGR0, 3 }, +- }, +- +- [JZ4780_CLK_MSC1] = { +- "msc1", CGU_CLK_DIV | CGU_CLK_GATE, +- .parents = { JZ4780_CLK_MSCMUX, -1, -1, -1 }, +- .div = { CGU_REG_MSC1CDR, 0, 8, 29, 28, 27 }, +- .gate = { CGU_REG_CLKGR0, 11 }, +- }, +- +- [JZ4780_CLK_MSC2] = { +- "msc2", CGU_CLK_DIV | CGU_CLK_GATE, +- .parents = { JZ4780_CLK_MSCMUX, -1, -1, -1 }, +- .div = { CGU_REG_MSC2CDR, 0, 8, 29, 28, 27 }, +- .gate = { CGU_REG_CLKGR0, 12 }, +- }, +- +- [JZ4780_CLK_UHC] = { +- "uhc", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, +- .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, +- JZ4780_CLK_EPLL, JZ4780_CLK_OTGPHY }, +- .mux = { CGU_REG_UHCCDR, 30, 2 }, +- .div = { CGU_REG_UHCCDR, 0, 8, 29, 28, 27 }, +- .gate = { CGU_REG_CLKGR0, 24 }, +- }, +- +- [JZ4780_CLK_SSIPLL] = { +- "ssi_pll", CGU_CLK_MUX | CGU_CLK_DIV, +- .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, -1, -1 }, +- .mux = { CGU_REG_SSICDR, 30, 1 }, +- .div = { CGU_REG_SSICDR, 0, 8, 29, 28, 27 }, +- }, +- +- [JZ4780_CLK_SSI] = { +- "ssi", CGU_CLK_MUX, +- .parents = { JZ4780_CLK_EXCLK, JZ4780_CLK_SSIPLL, -1, -1 }, +- .mux = { CGU_REG_SSICDR, 31, 1 }, +- }, +- +- [JZ4780_CLK_CIMMCLK] = { +- "cim_mclk", CGU_CLK_MUX | CGU_CLK_DIV, +- .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, -1, -1 }, +- .mux = { CGU_REG_CIMCDR, 31, 1 }, +- .div = { CGU_REG_CIMCDR, 0, 8, 30, 29, 28 }, +- }, +- +- [JZ4780_CLK_PCMPLL] = { +- "pcm_pll", CGU_CLK_MUX | CGU_CLK_DIV, +- .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, +- JZ4780_CLK_EPLL, JZ4780_CLK_VPLL }, +- .mux = { CGU_REG_PCMCDR, 29, 2 }, +- .div = { CGU_REG_PCMCDR, 0, 8, 28, 27, 26 }, +- }, +- +- [JZ4780_CLK_PCM] = { +- "pcm", CGU_CLK_MUX | CGU_CLK_GATE, +- .parents = { JZ4780_CLK_EXCLK, JZ4780_CLK_PCMPLL, -1, -1 }, +- .mux = { CGU_REG_PCMCDR, 31, 1 }, +- .gate = { CGU_REG_CLKGR1, 3 }, +- }, +- +- [JZ4780_CLK_GPU] = { +- "gpu", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, +- .parents = { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, +- JZ4780_CLK_EPLL }, +- .mux = { CGU_REG_GPUCDR, 30, 2 }, +- .div = { CGU_REG_GPUCDR, 0, 4, 29, 28, 27 }, +- .gate = { CGU_REG_CLKGR1, 4 }, +- }, +- +- [JZ4780_CLK_HDMI] = { +- "hdmi", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, +- .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, +- JZ4780_CLK_VPLL, -1 }, +- .mux = { CGU_REG_HDMICDR, 30, 2 }, +- .div = { CGU_REG_HDMICDR, 0, 8, 29, 28, 26 }, +- .gate = { CGU_REG_CLKGR1, 9 }, +- }, +- +- [JZ4780_CLK_BCH] = { +- "bch", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, +- .parents = { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, +- JZ4780_CLK_EPLL }, +- .mux = { CGU_REG_BCHCDR, 30, 2 }, +- .div = { CGU_REG_BCHCDR, 0, 4, 29, 28, 27 }, +- .gate = { CGU_REG_CLKGR0, 1 }, +- }, +- +- /* Gate-only clocks */ +- +- [JZ4780_CLK_NEMC] = { +- "nemc", CGU_CLK_GATE, +- .parents = { JZ4780_CLK_AHB2, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR0, 0 }, +- }, +- +- [JZ4780_CLK_OTG0] = { +- "otg0", CGU_CLK_GATE, +- .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR0, 2 }, +- }, +- +- [JZ4780_CLK_SSI0] = { +- "ssi0", CGU_CLK_GATE, +- .parents = { JZ4780_CLK_SSI, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR0, 4 }, +- }, +- +- [JZ4780_CLK_SMB0] = { +- "smb0", CGU_CLK_GATE, +- .parents = { JZ4780_CLK_PCLK, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR0, 5 }, +- }, +- +- [JZ4780_CLK_SMB1] = { +- "smb1", CGU_CLK_GATE, +- .parents = { JZ4780_CLK_PCLK, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR0, 6 }, +- }, +- +- [JZ4780_CLK_SCC] = { +- "scc", CGU_CLK_GATE, +- .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR0, 7 }, +- }, +- +- [JZ4780_CLK_AIC] = { +- "aic", CGU_CLK_GATE, +- .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR0, 8 }, +- }, +- +- [JZ4780_CLK_TSSI0] = { +- "tssi0", CGU_CLK_GATE, +- .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR0, 9 }, +- }, +- +- [JZ4780_CLK_OWI] = { +- "owi", CGU_CLK_GATE, +- .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR0, 10 }, +- }, +- +- [JZ4780_CLK_KBC] = { +- "kbc", CGU_CLK_GATE, +- .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR0, 13 }, +- }, +- +- [JZ4780_CLK_SADC] = { +- "sadc", CGU_CLK_GATE, +- .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR0, 14 }, +- }, +- +- [JZ4780_CLK_UART0] = { +- "uart0", CGU_CLK_GATE, +- .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR0, 15 }, +- }, +- +- [JZ4780_CLK_UART1] = { +- "uart1", CGU_CLK_GATE, +- .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR0, 16 }, +- }, +- +- [JZ4780_CLK_UART2] = { +- "uart2", CGU_CLK_GATE, +- .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR0, 17 }, +- }, +- +- [JZ4780_CLK_UART3] = { +- "uart3", CGU_CLK_GATE, +- .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR0, 18 }, +- }, +- +- [JZ4780_CLK_SSI1] = { +- "ssi1", CGU_CLK_GATE, +- .parents = { JZ4780_CLK_SSI, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR0, 19 }, +- }, +- +- [JZ4780_CLK_SSI2] = { +- "ssi2", CGU_CLK_GATE, +- .parents = { JZ4780_CLK_SSI, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR0, 20 }, +- }, +- +- [JZ4780_CLK_PDMA] = { +- "pdma", CGU_CLK_GATE, +- .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR0, 21 }, +- }, +- +- [JZ4780_CLK_GPS] = { +- "gps", CGU_CLK_GATE, +- .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR0, 22 }, +- }, +- +- [JZ4780_CLK_MAC] = { +- "mac", CGU_CLK_GATE, +- .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR0, 23 }, +- }, +- +- [JZ4780_CLK_SMB2] = { +- "smb2", CGU_CLK_GATE, +- .parents = { JZ4780_CLK_PCLK, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR0, 24 }, +- }, +- +- [JZ4780_CLK_CIM] = { +- "cim", CGU_CLK_GATE, +- .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR0, 26 }, +- }, +- +- [JZ4780_CLK_LCD] = { +- "lcd", CGU_CLK_GATE, +- .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR0, 28 }, +- }, +- +- [JZ4780_CLK_TVE] = { +- "tve", CGU_CLK_GATE, +- .parents = { JZ4780_CLK_LCD, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR0, 27 }, +- }, +- +- [JZ4780_CLK_IPU] = { +- "ipu", CGU_CLK_GATE, +- .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR0, 29 }, +- }, +- +- [JZ4780_CLK_DDR0] = { +- "ddr0", CGU_CLK_GATE, +- .parents = { JZ4780_CLK_DDR, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR0, 30 }, +- }, +- +- [JZ4780_CLK_DDR1] = { +- "ddr1", CGU_CLK_GATE, +- .parents = { JZ4780_CLK_DDR, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR0, 31 }, +- }, +- +- [JZ4780_CLK_SMB3] = { +- "smb3", CGU_CLK_GATE, +- .parents = { JZ4780_CLK_PCLK, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR1, 0 }, +- }, +- +- [JZ4780_CLK_TSSI1] = { +- "tssi1", CGU_CLK_GATE, +- .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR1, 1 }, +- }, +- +- [JZ4780_CLK_COMPRESS] = { +- "compress", CGU_CLK_GATE, +- .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR1, 5 }, +- }, +- +- [JZ4780_CLK_AIC1] = { +- "aic1", CGU_CLK_GATE, +- .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR1, 6 }, +- }, +- +- [JZ4780_CLK_GPVLC] = { +- "gpvlc", CGU_CLK_GATE, +- .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR1, 7 }, +- }, +- +- [JZ4780_CLK_OTG1] = { +- "otg1", CGU_CLK_GATE, +- .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR1, 8 }, +- }, +- +- [JZ4780_CLK_UART4] = { +- "uart4", CGU_CLK_GATE, +- .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR1, 10 }, +- }, +- +- [JZ4780_CLK_AHBMON] = { +- "ahb_mon", CGU_CLK_GATE, +- .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR1, 11 }, +- }, +- +- [JZ4780_CLK_SMB4] = { +- "smb4", CGU_CLK_GATE, +- .parents = { JZ4780_CLK_PCLK, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR1, 12 }, +- }, +- +- [JZ4780_CLK_DES] = { +- "des", CGU_CLK_GATE, +- .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR1, 13 }, +- }, +- +- [JZ4780_CLK_X2D] = { +- "x2d", CGU_CLK_GATE, +- .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR1, 14 }, +- }, +- +- [JZ4780_CLK_CORE1] = { +- "core1", CGU_CLK_GATE, +- .parents = { JZ4780_CLK_CPU, -1, -1, -1 }, +- .gate = { CGU_REG_CLKGR1, 15 }, +- }, +- +-}; +- +-static void __init jz4780_cgu_init(struct device_node *np) +-{ +- int retval; +- +- cgu = ingenic_cgu_new(jz4780_cgu_clocks, +- ARRAY_SIZE(jz4780_cgu_clocks), np); +- if (!cgu) { +- pr_err("%s: failed to initialise CGU\n", __func__); +- return; +- } +- +- retval = ingenic_cgu_register_clocks(cgu); +- if (retval) { +- pr_err("%s: failed to register CGU Clocks\n", __func__); +- return; +- } +-} +-CLK_OF_DECLARE(jz4780_cgu, "ingenic,jz4780-cgu", jz4780_cgu_init); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_power-gate.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_power-gate.c.patch new file mode 100644 index 00000000..e8b1d6d1 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_power-gate.c.patch @@ -0,0 +1,201 @@ +diff -drupN a/drivers/clk/ingenic/power-gate.c b/drivers/clk/ingenic/power-gate.c +--- a/drivers/clk/ingenic/power-gate.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/clk/ingenic/power-gate.c 2022-06-09 05:02:28.000000000 +0300 +@@ -0,0 +1,197 @@ ++/* ++ * Copyright (C) 2010-2011 Canonical Ltd ++ * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd ++ * ++ * 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. ++ * ++ * Gated clock implementation ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "power-gate.h" ++ ++ ++struct power_gate { ++ struct clk_hw hw; ++ void __iomem *reg; ++ u8 ctrl_bit; ++ u8 wait_bit; ++ u8 flags; ++ unsigned long power_flags; ++ spinlock_t *lock; ++ ++}; ++ ++ ++/** ++ * DOC: basic gatable clock which can gate and ungate it's output ++ * ++ * Traits of this clock: ++ * prepare - clk_(un)prepare only ensures parent is (un)prepared ++ * enable - clk_enable and clk_disable are functional & control gating ++ * rate - inherits rate from parent. No clk_set_rate support ++ * parent - fixed parent. No clk_set_parent support ++ */ ++ ++#define to_power_gate(_hw) container_of(_hw, struct power_gate, hw) ++ ++/* ++ * It works on following logic: ++ * ++ * For enabling clock, enable = 1 ++ * set2dis = 1 -> clear bit -> set = 0 ++ * set2dis = 0 -> set bit -> set = 1 ++ * ++ * For disabling clock, enable = 0 ++ * set2dis = 1 -> set bit -> set = 1 ++ * set2dis = 0 -> clear bit -> set = 0 ++ * ++ * So, result is always: enable xor set2dis. ++ */ ++static int power_gate_is_enabled(struct clk_hw *hw) ++{ ++ u32 reg; ++ struct power_gate *gate = to_power_gate(hw); ++ ++ reg = clk_readl(gate->reg); ++ ++ /* if a set bit disables this clk, flip it before masking */ ++ if (gate->flags & CLK_GATE_SET_TO_DISABLE) ++ reg ^= BIT(gate->wait_bit); ++ ++ reg &= BIT(gate->wait_bit); ++ ++ return reg ? 1 : 0; ++} ++ ++static void power_gate_endisable(struct clk_hw *hw, int enable) ++{ ++ struct power_gate *gate = to_power_gate(hw); ++ int set = gate->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0; ++ unsigned long uninitialized_var(flags); ++ u32 reg; ++ ++ set ^= enable; ++ ++ if (gate->lock) ++ spin_lock_irqsave(gate->lock, flags); ++ else ++ __acquire(gate->lock); ++ ++ reg = clk_readl(gate->reg); ++ ++ if (set) ++ reg |= BIT(gate->ctrl_bit); ++ else ++ reg &= ~BIT(gate->ctrl_bit); ++ clk_writel(reg, gate->reg); ++ ++ if (gate->lock) ++ spin_unlock_irqrestore(gate->lock, flags); ++ else ++ __release(gate->lock); ++} ++ ++static int power_gate_enable(struct clk_hw *hw) ++{ ++ struct power_gate *gate = to_power_gate(hw); ++ ++ power_gate_endisable(hw, 1); ++ ++ if (gate->power_flags & POWER_GATE_WAIT) { ++ while (!power_gate_is_enabled(hw)); ++ } ++ ++ return 0; ++} ++ ++static void power_gate_disable(struct clk_hw *hw) ++{ ++ struct power_gate *gate = to_power_gate(hw); ++ ++ power_gate_endisable(hw, 0); ++ ++ if (gate->power_flags & POWER_GATE_WAIT) { ++ while (power_gate_is_enabled(hw)); ++ } ++} ++ ++const struct clk_ops power_gate_ops = { ++ .enable = power_gate_enable, ++ .disable = power_gate_disable, ++ .is_enabled = power_gate_is_enabled, ++}; ++EXPORT_SYMBOL_GPL(power_gate_ops); ++ ++/** ++ * clk_register_gate - register a gate clock with the clock framework ++ * @dev: device that is registering this clock ++ * @name: name of this clock ++ * @parent_name: name of this clock's parent ++ * @flags: framework-specific flags for this clock ++ * @reg: register address to control gating of this clock ++ * @bit_idx: which bit in the register controls gating of this clock ++ * @clk_gate_flags: gate-specific flags for this clock ++ * @lock: shared register lock for this clock ++ */ ++struct clk *power_register_gate(struct device *dev, const char *name, ++ const char *parent_name, unsigned long flags, ++ void __iomem *reg, u8 ctrl_bit, u8 wait_bit, ++ u8 clk_gate_flags, unsigned long power_flags, spinlock_t *lock) ++{ ++ struct power_gate *gate; ++ struct clk *clk; ++ struct clk_init_data init; ++ ++ /* allocate the gate */ ++ gate = kzalloc(sizeof(*gate), GFP_KERNEL); ++ if (!gate) ++ return ERR_PTR(-ENOMEM); ++ ++ init.name = name; ++ init.ops = &power_gate_ops; ++ init.flags = flags | CLK_IS_BASIC; ++ init.parent_names = (parent_name ? &parent_name: NULL); ++ init.num_parents = (parent_name ? 1 : 0); ++ ++ /* struct power_gate assignments */ ++ gate->reg = reg; ++ gate->ctrl_bit = ctrl_bit; ++ gate->wait_bit = wait_bit; ++ gate->flags = clk_gate_flags; ++ gate->power_flags = power_flags; ++ gate->lock = lock; ++ gate->hw.init = &init; ++ ++ clk = clk_register(dev, &gate->hw); ++ ++ if (IS_ERR(clk)) ++ kfree(gate); ++ ++ return clk; ++} ++EXPORT_SYMBOL_GPL(power_register_gate); ++ ++void power_unregister_gate(struct clk *clk) ++{ ++ struct power_gate *gate; ++ struct clk_hw *hw; ++ ++ hw = __clk_get_hw(clk); ++ if (!hw) ++ return; ++ ++ gate = to_power_gate(hw); ++ ++ clk_unregister(clk); ++ kfree(gate); ++} ++EXPORT_SYMBOL_GPL(power_unregister_gate); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_power-gate.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_power-gate.h.patch new file mode 100644 index 00000000..11f0b199 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clk_ingenic_power-gate.h.patch @@ -0,0 +1,18 @@ +diff -drupN a/drivers/clk/ingenic/power-gate.h b/drivers/clk/ingenic/power-gate.h +--- a/drivers/clk/ingenic/power-gate.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/clk/ingenic/power-gate.h 2022-06-09 05:02:28.000000000 +0300 +@@ -0,0 +1,14 @@ ++#ifndef __INGENIC_POWER_GATE_H ++#define __INGENIC_CLK_CGU_DIVIDER_H ++ ++ ++#define POWER_GATE_WAIT BIT(1) ++ ++struct clk *power_register_gate(struct device *dev, const char *name, ++ const char *parent_name, unsigned long flags, ++ void __iomem *reg, u8 ctrl_bit, u8 wait_bit, ++ u8 clk_gate_flags, unsigned long power_flags, spinlock_t *lock); ++ ++void power_unregister_gate(struct clk *clk); ++ ++#endif /* __SAMSUNG_CLK_PLL_H */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clocksource_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clocksource_Kconfig.patch new file mode 100644 index 00000000..5eae3a53 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clocksource_Kconfig.patch @@ -0,0 +1,19 @@ +diff -drupN a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig +--- a/drivers/clocksource/Kconfig 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/clocksource/Kconfig 2022-06-09 05:02:28.000000000 +0300 +@@ -327,4 +327,15 @@ config CLKSRC_ST_LPC + Enable this option to use the Low Power controller timer + as clocksource. + ++config CLKSRC_INGENIC_SYS_OST ++ bool ++ select CLKSRC_OF ++ ++config CLKSRC_INGENIC_CORE_OST ++ bool ++ select CLKSRC_OF ++ help ++ core sys ost for ingenic xburst2 based SOCs. each cpu has ++ an ost and all cpu shares a global clocksource. ++ + endmenu diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clocksource_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clocksource_Makefile.patch new file mode 100644 index 00000000..a1c2cd33 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clocksource_Makefile.patch @@ -0,0 +1,9 @@ +diff -drupN a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile +--- a/drivers/clocksource/Makefile 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/clocksource/Makefile 2022-06-09 05:02:28.000000000 +0300 +@@ -65,3 +65,5 @@ obj-$(CONFIG_H8300_TMR16) += h8300_time + obj-$(CONFIG_H8300_TPU) += h8300_tpu.o + obj-$(CONFIG_CLKSRC_ST_LPC) += clksrc_st_lpc.o + obj-$(CONFIG_X86_NUMACHIP) += numachip.o ++obj-$(CONFIG_CLKSRC_INGENIC_SYS_OST) += ingenic_sysost.o ++obj-$(CONFIG_CLKSRC_INGENIC_CORE_OST) += ingenic_core_ost.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clocksource_ingenic_core_ost.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clocksource_ingenic_core_ost.c.patch new file mode 100644 index 00000000..ac0fd532 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clocksource_ingenic_core_ost.c.patch @@ -0,0 +1,566 @@ +diff -drupN a/drivers/clocksource/ingenic_core_ost.c b/drivers/clocksource/ingenic_core_ost.c +--- a/drivers/clocksource/ingenic_core_ost.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/clocksource/ingenic_core_ost.c 2022-06-09 05:02:28.000000000 +0300 +@@ -0,0 +1,562 @@ ++/* ++ * Setting up the xburst2 system ost, including: ++ * ----> core system ost; ++ * ----> global system ost. ++ * ++ * Copyright (C) 2016 Ingenic Semiconductor Inc. ++ * ++ * Author: dongsheng.qiu, dongsheng.qiu@ingenic.com ++ * Modified by qipengzhen, aric.pzqi@ingenic.com ++ * ++ * This program is free software; you can distribute 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 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. ++ * ++ */ ++ ++/* #define DEBUG */ ++/* #define VERBOSE_DEBUG */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define OSTCCR 0x00 ++#define OSTER 0x04 ++#define OSTCR 0x08 ++#define OSTFR 0x0C ++#define OSTMR 0x10 ++#define OSTDFR 0x14 ++#define OSTCNT 0x18 ++ ++#define G_OSTCCR 0x00 ++#define G_OSTER 0x04 ++#define G_OSTCR 0x08 ++#define G_OSTCNTH 0x0C ++#define G_OSTCNTL 0x10 ++#define G_OSTCNTB 0x14 ++/*----------------------------------------------------------------------------- ++ * -- global ost, clocksource, the whole system shares only one. ++ * -- core ost, each cpu owns one. ++ * ++ * ----------------------------------------------- ++ * | | | | ++ * | -------- -------- -------- ++ * | | cpu0 | | cpu1 | | cpuN | ++ * | -------- -------- -------- ++ * | ^ ^ ^ ++ * V | | | ++ * ------------ ------------ ----------- ----------- ++ * | global OST | | core ost0 | | core ost1 | ... | core ostN | ++ * ------------ ----------- ----------- ----------- ++ * ++ *-----------------------------------------------------------------------------*/ ++ ++struct cpu_ost_map { ++ unsigned int cpu_num; ++ unsigned int dev_base; ++}; ++static struct cpu_ost_map cpu_ost_map[NR_CPUS]; ++ ++struct core_timerevent { ++ struct clock_event_device clkevt; ++ struct irqaction evt_action; ++ void __iomem *iobase; ++ unsigned int rate; ++ raw_spinlock_t lock; ++ unsigned int prev_set; ++}; ++ ++static struct core_timerevent timerevent_buf[NR_CPUS]; ++#define CLK_DIV 1 ++#define CSRDIV(x) ({int n = 0;int d = x; while(d){ d >>= 2;n++;};(n-1);}) ++ ++#define ost_readl(reg) readl(reg) ++#define ost_writel(value,reg) writel(value, reg) ++ ++struct tmr_src { ++ struct clocksource cs; ++ struct core_global_ost_resource *resource; ++ struct clk *clk_gate; ++ void __iomem *iobase; ++ raw_spinlock_t lock; ++}; ++#ifdef CONFIG_SMP ++#define ost_lock(lock,flags) raw_spin_lock_irqsave(&(lock),flags) ++#define ost_unlock(lock,flags) raw_spin_unlock_irqrestore(&(lock),flags) ++#else ++#define ost_lock(lock,flags) (flags = 0) ++#define ost_unlock(lock,flags) (flags = 0) ++#endif ++ ++struct core_ost_chip{ ++ struct tmr_src *tmrsrc; ++ ++ struct core_timerevent* __percpu *percpu_timerevent; ++ struct clk *core_gate; ++ void __iomem *iobase; ++ unsigned int rate; ++ int irq; ++} g_core_ost; ++ ++ ++static cycle_t core_clocksource_get_cycles(struct clocksource *cs) ++{ ++ union clycle_type { ++ cycle_t cycle64; ++ unsigned int cycle32[2]; ++ } cycle; ++ struct tmr_src *tmr = container_of(cs,struct tmr_src,cs); ++ void __iomem *iobase = tmr->iobase; ++ ++ do { ++ cycle.cycle32[1] = ost_readl(iobase + G_OSTCNTH); ++ cycle.cycle32[0] = ost_readl(iobase + G_OSTCNTL); ++ } while(cycle.cycle32[1] != ost_readl(iobase + G_OSTCNTH)); ++ ++ return cycle.cycle64; ++} ++ ++static int tmr_src_enable(struct clocksource *cs) ++{ ++ struct tmr_src *tmr = container_of(cs,struct tmr_src,cs); ++ void __iomem *iobase = tmr->iobase; ++ unsigned long flags; ++ ost_lock(tmr->lock,flags); ++ ost_writel(1,iobase + G_OSTER); ++ ost_unlock(tmr->lock,flags); ++ return 0; ++} ++ ++static void tmr_src_disable(struct clocksource *cs) ++{ ++ struct tmr_src *tmr = container_of(cs,struct tmr_src,cs); ++ void __iomem *iobase = tmr->iobase; ++ unsigned long flags; ++ ost_lock(tmr->lock,flags); ++ ost_writel(0,iobase + G_OSTER); ++ ost_unlock(tmr->lock,flags); ++} ++static void tmr_src_suspend(struct clocksource *cs) ++{ ++ struct tmr_src *tmr = container_of(cs,struct tmr_src,cs); ++ struct core_ost_chip *core_ost = &g_core_ost; ++ ++ if(core_ost->core_gate) ++ clk_disable_unprepare(core_ost->core_gate); ++ if(tmr->clk_gate) ++ clk_disable_unprepare(tmr->clk_gate); ++} ++static void tmr_src_resume(struct clocksource *cs) ++{ ++ struct tmr_src *tmr = container_of(cs,struct tmr_src,cs); ++ struct core_ost_chip *core_ost = &g_core_ost; ++ ++ if(tmr->clk_gate) ++ clk_prepare_enable(tmr->clk_gate); ++ if(core_ost->core_gate) ++ clk_prepare_enable(core_ost->core_gate); ++ ++} ++static struct tmr_src g_tmr_src = { ++ .cs = { ++ .name = "jz_clocksource", ++ .rating = 400, ++ .read = core_clocksource_get_cycles, ++ .mask = 0x7FFFFFFFFFFFFFFFULL, ++ .shift = 10, ++ .flags = CLOCK_SOURCE_WATCHDOG | CLOCK_SOURCE_IS_CONTINUOUS, ++ .enable = tmr_src_enable, ++ .disable = tmr_src_disable, ++ .suspend = tmr_src_suspend, ++ .resume = tmr_src_resume, ++ } ++}; ++ ++static unsigned long long sched_clock(void) ++{ ++ struct tmr_src *tmr = &g_tmr_src; ++ if(!tmr->iobase) ++ return 0LL; ++ if(!ost_readl(tmr->iobase + G_OSTER)) ++ return 0LL; ++ return ((cycle_t)core_clocksource_get_cycles(&tmr->cs)); // * tmr_src.cs.mult) >> tmr_src.cs.shift; ++} ++ ++void __init core_clocksource_init(struct core_ost_chip *core_ost, struct tmr_src *tmr) ++{ ++ unsigned long hz; ++ void __iomem *iobase; ++ ++ core_ost->tmrsrc = tmr; ++ tmr->cs.mult = clocksource_hz2mult(core_ost->rate, tmr->cs.shift); ++ iobase = tmr->iobase; ++ ++ if(tmr->clk_gate) ++ clk_prepare_enable(tmr->clk_gate); ++ ++ hz = core_ost->rate; ++ ++ raw_spin_lock_init(&tmr->lock); ++ ost_writel(0,iobase + G_OSTER); ++ ost_writel(CSRDIV(CLK_DIV),iobase + OSTCCR); ++ ost_writel(1,iobase + G_OSTCR); ++ ++ clocksource_register_hz(&tmr->cs, hz); ++ sched_clock_register(sched_clock, 64, hz); ++ ++ ost_writel(1,iobase + G_OSTER);//Enable OST in advance ++} ++ ++static int core_timerevent_set_next_event(unsigned long evt, ++ struct clock_event_device *clk_evt_dev) ++{ ++ struct core_timerevent *evt_dev = container_of(clk_evt_dev, struct core_timerevent, clkevt); ++ void __iomem *iobase = evt_dev->iobase; ++ unsigned long flags; ++ ost_lock(evt_dev->lock,flags); ++ if(evt <= 1) { ++ WARN_ON(1); ++ evt = 2; ++ } ++ ost_writel(0,iobase + OSTER); ++ if(!ost_readl(iobase + OSTFR)) ++ { ++ ost_writel(evt,iobase + OSTDFR); ++ ost_writel(1,iobase + OSTCR); ++ ost_writel(1,iobase + OSTER); ++ }else{ ++ //pr_err("OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO evt = %ld\n",evt); ++ evt_dev->prev_set = evt; ++ } ++ ++ ost_unlock(evt_dev->lock,flags); ++ return 0; ++} ++ ++static int time_count[4] = {100,100,100,100}; ++static irqreturn_t core_timerevent_interrupt(int irq, void *dev_id) ++{ ++ struct core_timerevent *evt_dev = *(struct core_timerevent **)dev_id; ++ void __iomem *iobase = evt_dev->iobase; ++ int cpu = smp_processor_id(); ++ unsigned long flags; ++ if (ost_readl(iobase + OSTFR)){ ++ if(time_count[cpu] >= 100) { ++#if 0 ++ printk("\n\n---timer interrupt , 100 count, on cpu: %d %x %x\n", cpu,read_c0_status(),read_c0_cause()); ++ printk("intc src0:%x: %x\n", 0xb2300000 + cpu * 0x1000, *(volatile unsigned int *)(0xb2300000 + cpu * 0x1000 )); ++ printk("intc msk0:%x: %x\n", 0xb2300004 + cpu * 0x1000, *(volatile unsigned int *)(0xb2300004 + cpu * 0x1000 )); ++ printk("intc pnd0:%x: %x\n", 0xb2300010 + cpu * 0x1000, *(volatile unsigned int *)(0xb2300010 + cpu * 0x1000 )); ++ printk("intc src1:%x: %x\n", 0xb2300020 + cpu * 0x1000, *(volatile unsigned int *)(0xb2300020 + cpu * 0x1000 )); ++ printk("intc msk1:%x: %x\n", 0xb2300024 + cpu * 0x1000, *(volatile unsigned int *)(0xb2300024 + cpu * 0x1000 )); ++ printk("intc pnd1:%x: %x\n", 0xb2300030 + cpu * 0x1000, *(volatile unsigned int *)(0xb2300030 + cpu * 0x1000 )); ++ printk("ccu msk: %x: %x\n", 0xb2200120, *(volatile unsigned int *)(0xb2200120)); ++ printk("ccu pnd: %x: %x\n", 0xb2200100, *(volatile unsigned int *)(0xb2200100)); ++ ++ printk("uart0 ier: %x\n", *(volatile unsigned int *)0xb0030004); ++ printk("uart0 isr: %x\n", *(volatile unsigned int *)0xb0030014); ++ ++ printk("\n\n"); ++#endif ++ time_count[cpu] = 0; ++ } ++ time_count[cpu]++; ++ ost_lock(evt_dev->lock,flags); ++ ost_writel(0,iobase + OSTFR); ++ ++ if( clockevent_state_oneshot(&evt_dev->clkevt) || ++ clockevent_state_oneshot_stopped(&evt_dev->clkevt)) { ++ if(evt_dev->prev_set == 0){ ++ ost_writel(0,iobase + OSTER); ++ }else{ ++ ost_writel(evt_dev->prev_set,iobase + OSTDFR); ++ ost_writel(1,iobase + OSTCR); ++ ost_writel(1,iobase + OSTER); ++ evt_dev->prev_set = 0; ++ } ++ ++ } ++ ++ ost_unlock(evt_dev->lock,flags); ++ evt_dev->clkevt.event_handler(&evt_dev->clkevt); ++ }else{ ++ pr_err("\nERROR: cpu: %d c0_status:%x c0_cause:%x\n", cpu,read_c0_status(),read_c0_cause()); ++ pr_err("CPU[%d]: ost couldn't find ostfr.\n",cpu); ++ } ++ return IRQ_HANDLED; ++} ++ ++static int set_state_periodic(struct clock_event_device *clkevt) ++{ ++ struct core_timerevent *evt_dev = container_of(clkevt,struct core_timerevent,clkevt); ++ void __iomem *iobase = evt_dev->iobase; ++ unsigned int latch = (evt_dev->rate + (HZ >> 1)) / HZ; ++ unsigned long flags; ++ ++ ost_lock(evt_dev->lock,flags); ++ ++ ost_writel(latch,iobase + OSTDFR); ++ ost_writel(1,iobase + OSTER); ++ ost_unlock(evt_dev->lock,flags); ++ return 0; ++} ++#if 0 ++static int set_state_oneshot(struct clock_event_device *clkevt) ++{ ++ struct core_timerevent *evt_dev = container_of(clkevt,struct core_timerevent,clkevt); ++ void __iomem *iobase = evt_dev->iobase; ++ unsigned int latch = (evt_dev->rate + (HZ >> 1)) / HZ; ++ unsigned long flags; ++ ++ ost_lock(evt_dev->lock,flags); ++ ost_writel(latch,iobase + OSTDFR); ++ ost_writel(1,iobase + OSTER); ++ ost_unlock(evt_dev->lock,flags); ++ return 0; ++ ++} ++static int set_state_oneshot_stopped(struct clock_event_device *clkevt) ++{ ++ struct core_timerevent *evt_dev = container_of(clkevt,struct core_timerevent,clkevt); ++ void __iomem *iobase = evt_dev->iobase; ++ unsigned long flags; ++ ++ ost_lock(evt_dev->lock,flags); ++ ost_writel(1,iobase + OSTER); ++ ost_unlock(evt_dev->lock,flags); ++ return 0; ++} ++#endif ++ ++static int set_state_shutdown(struct clock_event_device *clkevt) ++{ ++ struct core_timerevent *evt_dev = container_of(clkevt,struct core_timerevent,clkevt); ++ void __iomem *iobase = evt_dev->iobase; ++ unsigned long flags; ++ ++ ost_lock(evt_dev->lock,flags); ++ ost_writel(0,iobase + OSTER); ++ ost_unlock(evt_dev->lock,flags); ++ return 0; ++} ++#if 0 ++static int tick_resume(struct clock_event_device *clkevt) ++{ ++ struct core_timerevent *evt_dev = container_of(clkevt,struct core_timerevent,clkevt); ++ void __iomem *iobase = evt_dev->iobase; ++ unsigned int latch = (evt_dev->rate + (HZ >> 1)) / HZ; ++ unsigned long flags; ++ unsigned int val; ++ ++ ost_lock(evt_dev->lock,flags); ++ val = ost_readl(iobase + OSTCNT); ++ if(val >= latch) ++ ost_writel(latch,iobase + OSTDFR); ++ ost_writel(1,iobase + OSTER); ++ ++ ost_unlock(evt_dev->lock,flags); ++ ++ return 0; ++} ++#endif ++ ++static void percpu_timerevent_init(struct core_ost_chip *core_ost, int cpu_num) ++{ ++ int i; ++ void __iomem *iobase; ++ unsigned int base = 0; ++ struct core_timerevent *timerevent = NULL; ++ struct clock_event_device *cd = NULL; ++ pr_info("percpu cpu_num:%d timerevent init\n",cpu_num); ++ for(i = 0;i < NR_CPUS;i++) ++ { ++ if(cpu_ost_map[i].cpu_num == cpu_num) { ++ base = cpu_ost_map[i].dev_base; ++ timerevent = &timerevent_buf[i]; ++ break; ++ } ++ } ++ ++ if(base == 0){ ++ pr_err("Error: CPU[%d] don't finded ost base address\n",cpu_num); ++ return; ++ } ++ ++ iobase = (void *)base; ++ if(timerevent->iobase == NULL) ++ { ++ timerevent->iobase = iobase; ++ timerevent->rate = core_ost->rate; ++ ++ raw_spin_lock_init(&timerevent->lock); ++ cd = &timerevent->clkevt; ++ memset(cd,0,sizeof(struct clock_event_device)); ++ cd->name = "clockenvent"; ++ cd->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC; ++ cd->shift = 10; ++ cd->rating = 400; ++ cd->set_state_periodic = set_state_periodic; ++ cd->set_state_oneshot = set_state_shutdown; ++ cd->set_state_oneshot_stopped = set_state_shutdown; ++ cd->set_state_shutdown = set_state_shutdown; ++ cd->tick_resume = set_state_shutdown; ++ cd->set_next_event = core_timerevent_set_next_event; ++ cd->irq = core_ost->irq; ++ cd->cpumask = cpumask_of(smp_processor_id()); ++ }else { ++ iobase = timerevent->iobase; ++ cd = &timerevent->clkevt; ++ } ++ ost_writel(0,iobase + OSTER); //disable ost ++ ost_writel(CSRDIV(CLK_DIV),iobase + OSTCCR); ++ ost_writel(1,iobase + OSTCR); ++ ost_writel(0,iobase + OSTMR); ++ ++ clockevents_config_and_register(cd, timerevent->rate, 0xf, 0xffffffff); ++ ++ *this_cpu_ptr(core_ost->percpu_timerevent) = timerevent; ++ ++ enable_percpu_irq(core_ost->irq, IRQ_TYPE_NONE); ++ printk("clockevents_config_and_register success.\n"); ++} ++void ingenic_percpu_timerevent_init(unsigned int cpu_num) ++{ ++ percpu_timerevent_init(&g_core_ost, cpu_num); ++} ++EXPORT_SYMBOL_GPL(ingenic_percpu_timerevent_init); ++ ++ ++static void percpu_timerevent_deinit(struct core_ost_chip * core_ost) ++{ ++ struct core_timerevent *timerevent = *this_cpu_ptr(core_ost->percpu_timerevent); ++ disable_percpu_irq(core_ost->irq); ++ ost_writel(0,timerevent->iobase + OSTER); //disable ost ++ ost_writel(1,timerevent->iobase + OSTMR); ++} ++void ingenic_percpu_timerevent_deinit(void) ++{ ++ percpu_timerevent_deinit(&g_core_ost); ++} ++EXPORT_SYMBOL_GPL(ingenic_percpu_timerevent_deinit); ++ ++ ++static void __init core_ost_setup(struct core_ost_chip *core_ost, unsigned long ext_rate) ++{ ++ int ret; ++ ++ if(core_ost->core_gate) { ++ clk_prepare_enable(core_ost->core_gate); ++ } ++ ++ core_ost->rate = (ext_rate / CLK_DIV); /* TODO: should be clk_get_rate(extclk) / CLK_DIV in real chip */ ++ ++ core_ost->percpu_timerevent = alloc_percpu(struct core_timerevent *); ++ if(!core_ost->percpu_timerevent) { ++ pr_err("ost percpu alloc fail!\n"); ++ return; ++ } ++ ret = request_percpu_irq(core_ost->irq, core_timerevent_interrupt,"core_timerevent",core_ost->percpu_timerevent); ++ if(ret < 0) { ++ pr_err("dddd timer request ost error %d \n",ret); ++ } ++ memset(timerevent_buf,0,sizeof(timerevent_buf)); ++ ++} ++ ++static void __init ingenic_ost_init(struct device_node *np) ++{ ++ struct core_ost_chip *core_ost = &g_core_ost; ++ struct tmr_src *tmr = &g_tmr_src ; ++ struct clk *ext_clk = NULL; ++ unsigned long ext_rate; ++ void __iomem *g_iobase = NULL; ++ void __iomem *core_iobase = NULL; ++ int irq = -1; ++ struct property *prop; ++ const unsigned int *vp; ++ unsigned int pv; ++ int index = 0; ++ ++ g_iobase = of_io_request_and_map(np, 0, "ost"); ++ if(g_iobase == NULL) { ++ pr_err("Failed to map global clocksource iobase!\n"); ++ return; ++ } ++ core_iobase = of_io_request_and_map(np, 1, "core-ost"); ++ if(core_iobase == NULL) { ++ pr_err("Failed to map core clockevent iobase!\n"); ++ return; ++ } ++ ++ irq = of_irq_get_byname(np, "sys_ost"); ++ if (irq < 0) { ++ pr_err("ftm: unable to get IRQ from DT, %d\n", irq); ++ return; ++ } ++ ++ of_property_for_each_u32(np, "cpu-ost-map", prop, vp, pv) { ++ if(index % 2) { ++ cpu_ost_map[index/2].dev_base = (unsigned int)core_iobase + pv; ++ } else { ++ cpu_ost_map[index/2].cpu_num = pv; ++ } ++ index ++; ++ if(index > NR_CPUS * 2 - 1) { ++ printk("parse cpu-ost-iomap, ost number define in dt is too large!\n"); ++ break; ++ } ++ } ++ ++ ext_clk = clk_get(NULL, "ext"); ++ if (IS_ERR_OR_NULL(ext_clk)) { ++ pr_err("Warnning ... Ingenic Ost: Failed to get ext clk, Using default clk rate(24MHz),\n"); ++ ext_rate = 24000000; ++ } else { ++ ext_rate = clk_get_rate(ext_clk); ++ clk_put(ext_clk); ++ } ++ ++ tmr->iobase = g_iobase; ++ core_ost->iobase = core_iobase; ++ core_ost->irq = irq; ++ ++ tmr->clk_gate = clk_get(NULL, "gate_ost"); ++ if(IS_ERR_OR_NULL(tmr->clk_gate)) { ++ pr_err("Failed to get global ost clk gate!\n"); ++ tmr->clk_gate = NULL; ++ } ++ ++ core_ost->core_gate = clk_get(NULL, "gate_ost"); ++ if(IS_ERR_OR_NULL(core_ost->core_gate)) { ++ pr_err("Failed to get core ost clk gate!\n"); ++ core_ost->core_gate = NULL; ++ } ++ ++ core_ost_setup(core_ost, ext_rate); ++ percpu_timerevent_init(core_ost, 0); ++ core_clocksource_init(core_ost, tmr); ++} ++ ++CLOCKSOURCE_OF_DECLARE(ingenic_ost_init, "ingenic,core-ost", ingenic_ost_init); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clocksource_ingenic_sysost.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clocksource_ingenic_sysost.c.patch new file mode 100644 index 00000000..85d2afb1 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_clocksource_ingenic_sysost.c.patch @@ -0,0 +1,309 @@ +diff -drupN a/drivers/clocksource/ingenic_sysost.c b/drivers/clocksource/ingenic_sysost.c +--- a/drivers/clocksource/ingenic_sysost.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/clocksource/ingenic_sysost.c 2022-06-09 05:02:28.000000000 +0300 +@@ -0,0 +1,305 @@ ++/* ++ * Copyright (C) 2015 Ingenic Semiconductor Co., Ltd. ++ * Author: xyfu (kernel.3.10.14) ++ * Modified: cli ++ * ++ * Operating System Timer interface for Ingenic's SOC, such as X1000, ++ * and so on. (kernel.4.4) ++ * ++ * 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. ++ */ ++ ++/* #define DEBUG */ ++/* #define VERBOSE_DEBUG */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define CLKSOURCE_DIV (16) ++#define CLKEVENT_DIV (16) ++ ++/*----------------------------------------------------------------------------- ++ * C L O C K S O U R C E ++ *-----------------------------------------------------------------------------*/ ++struct tmr_src { ++ struct clocksource cs; ++ struct clk *clk_gate; ++ void __iomem *iobase; ++}; ++ ++static cycle_t ingenic_read_cycles(struct clocksource *cs) ++{ ++ struct tmr_src *tmr = container_of(cs, struct tmr_src, cs); ++ union clycle_type ++ { ++ cycle_t cycle64; ++ unsigned int cycle32[2]; ++ } cycle; ++ ++ cycle.cycle32[0] = ost_readl(tmr->iobase + OST_T2CNTL); ++ cycle.cycle32[1] = ost_readl(tmr->iobase + OST_TCNT2HBUF); ++ ++ return cycle.cycle64; ++} ++ ++static int tmr_src_enable(struct clocksource *cs) ++{ ++ struct tmr_src *tmr = container_of(cs,struct tmr_src,cs); ++ ++ ost_writel(tmr->iobase + OST_TESR, TESR_OSTEN2); ++ return 0; ++} ++static void tmr_src_disable(struct clocksource *cs) ++{ ++ struct tmr_src *tmr = container_of(cs,struct tmr_src,cs); ++ ++ ost_writel(tmr->iobase + OST_TCR, TCR_OSTCLR2); ++ ost_writel(tmr->iobase + OST_TECR, TESR_OSTEN2); ++} ++static void tmr_src_suspend(struct clocksource *cs) ++{ ++ struct tmr_src *tmr = container_of(cs, struct tmr_src, cs); ++ ++ ost_writel(tmr->iobase + OST_TFR , ~TFR_OSTM); ++ if (tmr->clk_gate) { ++ clk_disable_unprepare(tmr->clk_gate); ++ ++ } ++} ++static void tmr_src_resume(struct clocksource *cs) ++{ ++ struct tmr_src *tmr = container_of(cs, struct tmr_src, cs); ++ if (tmr->clk_gate) ++ clk_prepare_enable(tmr->clk_gate); ++} ++ ++static struct tmr_src tmr_src = { ++ .cs = { ++ .name = "ingenic_clocksource", ++ .rating = 400, ++ .read = ingenic_read_cycles, ++ .mask = CLOCKSOURCE_MASK(64), ++ .flags = CLOCK_SOURCE_WATCHDOG | CLOCK_SOURCE_IS_CONTINUOUS, ++ .enable = tmr_src_enable, ++ .disable = tmr_src_disable, ++ .suspend = tmr_src_suspend, ++ .resume = tmr_src_resume, ++ } ++}; ++ ++static u64 notrace ingenic_read_sched_clock(void) ++{ ++ union clycle_type { ++ uint64_t cycle64; ++ uint32_t cycle32[2]; ++ } cycle; ++ cycle.cycle32[0] = ost_readl(tmr_src.iobase + OST_T2CNTL); ++ cycle.cycle32[1] = ost_readl(tmr_src.iobase + OST_TCNT2HBUF); ++ ++ return cycle.cycle64; ++} ++ ++static void __init ingenic_clocksource_init(struct tmr_src *tmr, unsigned long ext_rate) ++{ ++ unsigned long hz = ext_rate / CLKSOURCE_DIV; ++ unsigned int val; ++ ++ tmr->clk_gate = clk_get(NULL, "gate_ost"); ++ if (IS_ERR_OR_NULL(tmr->clk_gate)) { ++ pr_err("ERROR: Failed to get clk, Please check clk driver.\n"); ++ pr_err("%s, incase of Debug at the very beginning, we ignore the clk_gate. \n \ ++ You must implemented clk driver immediately\n\n\t\n", __func__); ++ } else { ++ clk_prepare_enable(tmr->clk_gate); ++ } ++ ++ val = ost_readl(tmr->iobase + OST_TCCR); ++ if (ost_readl(tmr->iobase + OST_TER) & TESR_OSTEN2) { ++ u32 div = 0; ++ /* ++ * get previous boot time ++ */ ++ switch ((val & TCCRDIV_MSK2) >> TCCRDIV_SFT2) { ++ case 0: div = 1; break; ++ case 1: div = 4; break; ++ case 2: div = 16; break; ++ } ++ if (likely(div)) { ++ u64 cycles = ingenic_read_sched_clock(); ++ u32 pre_hz = ext_rate / div; ++ cycles = cycles * USEC_PER_SEC; ++ do_div(cycles, pre_hz); ++ pr_info("Previous Boot Time is %u us\n", (u32)cycles); ++ } ++ ost_writel(tmr->iobase + OST_TECR, TESR_OSTEN2); ++ } ++ val &= ~TCCRDIV_MSK2; ++ val |= TCCRDIV2(CLKSOURCE_DIV); ++ ost_writel(tmr->iobase + OST_TCCR, val); ++ ost_writel(tmr->iobase + OST_TCR, TCR_OSTCLR2); ++ ost_writel(tmr->iobase + OST_TESR, TESR_OSTEN2); ++ ++ clocksource_register_hz(&tmr->cs, hz); ++ sched_clock_register(ingenic_read_sched_clock, 64, hz); ++} ++ ++/*----------------------------------------------------------------------------- ++ * C L O C K E V E N T ++ *-----------------------------------------------------------------------------*/ ++struct ingenic_timerevent { ++ struct clock_event_device clkevt; ++ void __iomem *iobase; ++ unsigned int periodic_ticks; ++ struct clk *clk_gate; ++ unsigned int rate; ++ int irq; ++ struct irqaction evt_action; ++} ingenic_clockevent; ++ ++ ++static int ingenic_set_state_periodic(struct clock_event_device *cd) ++{ ++ struct ingenic_timerevent *evt_dev = container_of(cd, ++ struct ingenic_timerevent, clkevt); ++ ++ ost_writel(evt_dev->iobase + OST_TMR , TMR_OSTM); ++ ost_writel(evt_dev->iobase + OST_TECR , TESR_OSTEN1); ++ ost_writel(evt_dev->iobase + OST_TFR , ~TFR_OSTM); ++ ost_writel(evt_dev->iobase + OST_T1DFR, evt_dev->periodic_ticks); ++ ost_writel(evt_dev->iobase + OST_TCR , TCR_OSTCLR1); ++ ost_writel(evt_dev->iobase + OST_TESR , TESR_OSTEN1); ++ ost_writel(evt_dev->iobase + OST_TMR , ~TMR_OSTM); ++ return 0; ++} ++ ++static int ingenic_set_state_shutdown(struct clock_event_device *cd) ++{ ++ struct ingenic_timerevent *evt_dev = container_of(cd, ++ struct ingenic_timerevent, clkevt); ++ ost_writel(evt_dev->iobase + OST_TECR , TESR_OSTEN1); ++ return 0; ++ ++} ++static int ingenic_set_next_event(unsigned long evt, struct clock_event_device *cd) ++{ ++ struct ingenic_timerevent *evt_dev = container_of(cd, ++ struct ingenic_timerevent, clkevt); ++ ++ ost_writel(evt_dev->iobase + OST_TMR , TMR_OSTM); ++ ost_writel(evt_dev->iobase + OST_TECR , TESR_OSTEN1); ++ ost_writel(evt_dev->iobase + OST_TFR , ~TFR_OSTM); ++ ost_writel(evt_dev->iobase + OST_T1DFR, evt); ++ ost_writel(evt_dev->iobase + OST_TCR , TCR_OSTCLR1); ++ ost_writel(evt_dev->iobase + OST_TESR , TESR_OSTEN1); ++ ost_writel(evt_dev->iobase + OST_TMR , ~TMR_OSTM); ++ return 0; ++} ++ ++static irqreturn_t ingenic_timer_interrupt(int irq, void *dev_id) ++{ ++ struct ingenic_timerevent *evt_dev = dev_id; ++ struct clock_event_device *cd = &evt_dev->clkevt; ++ ++ ost_writel(evt_dev->iobase + OST_TFR, ~TFR_OSTM); ++ ++ if (clockevent_state_oneshot(cd)) ++ ost_writel(evt_dev->iobase + OST_TECR , TESR_OSTEN1); ++ ++ evt_dev->clkevt.event_handler(&evt_dev->clkevt); ++ return IRQ_HANDLED; ++} ++ ++static void __init ingenic_clockevent_init(struct ingenic_timerevent *evt_dev, unsigned long ext_rate) ++{ ++ struct clock_event_device *cd = &evt_dev->clkevt; ++ unsigned int val; ++ ++ ost_writel(evt_dev->iobase + OST_TMR, TMR_OSTM); ++ ost_writel(evt_dev->iobase + OST_TECR, TESR_OSTEN1); ++ ost_writel(evt_dev->iobase + OST_TFR, ~TFR_OSTM); ++ val = ost_readl(evt_dev->iobase + OST_TCCR); ++ val &= ~TCCRDIV_MSK1; ++ val |= TCCRDIV1(CLKEVENT_DIV); ++ ost_writel(evt_dev->iobase + OST_TCCR, val); ++ ost_writel(evt_dev->iobase + OST_TCR, TCR_OSTCLR1); ++ ++ evt_dev->evt_action.handler = ingenic_timer_interrupt; ++ evt_dev->evt_action.flags = IRQF_TIMER; ++ evt_dev->evt_action.name = "ingenic-timerost"; ++ evt_dev->evt_action.dev_id = (void*)evt_dev; ++ evt_dev->rate = ext_rate / CLKEVENT_DIV; ++ evt_dev->periodic_ticks = ((evt_dev->rate + (HZ >> 1)) / HZ) - 1; /* - 1 for scroll back */ ++ ++ if (setup_irq(evt_dev->irq, &evt_dev->evt_action) < 0) ++ panic("timer request ost error\n"); ++ ++ memset(cd, 0, sizeof(struct clock_event_device)); ++ cd->name = "ingenic-clockenvent"; ++ cd->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC; ++ cd->rating = 400; ++ cd->set_state_periodic = ingenic_set_state_periodic; ++ cd->set_state_oneshot = ingenic_set_state_shutdown; ++ cd->set_state_shutdown = ingenic_set_state_shutdown; ++ cd->set_next_event = ingenic_set_next_event; ++ cd->irq = evt_dev->irq; ++ cd->cpumask = cpumask_of(0); ++ ++ clockevents_config_and_register(cd, evt_dev->rate, 4, 0xffffffff); ++} ++ ++static void __init ingenic_ost_init(struct device_node *np) ++{ ++ struct ingenic_timerevent *evt = &ingenic_clockevent; ++ struct tmr_src *tmr = &tmr_src ; ++ struct clk *ext_clk = NULL; ++ unsigned long ext_rate; ++ void __iomem *iobase = NULL; ++ int irq_ost = -1; ++ ++ iobase = of_io_request_and_map(np, 0, "ost"); ++ if(iobase == NULL) { ++ pr_err("Failed to map clocksource iobase!\n"); ++ return; ++ } ++ ++ irq_ost = of_irq_get_byname(np, "sys_ost"); ++ if (irq_ost < 0) { ++ pr_err("ftm: unable to get IRQ from DT, %d\n", irq_ost); ++ return; ++ } ++ ++ ext_clk = clk_get(NULL, "ext"); ++ if (IS_ERR_OR_NULL(ext_clk)) { ++ pr_warn("Warning Ingenic Ost: Can not get extern clock, Please check clk driver !!\n\n\t\n"); ++ ext_rate = 24000000; ++ } else { ++ ++ ext_rate = clk_get_rate(ext_clk); ++ clk_put(ext_clk); ++ } ++ ++ tmr->iobase = iobase; ++ evt->iobase = iobase; ++ evt->irq = irq_ost; ++ ++ ingenic_clocksource_init(tmr, ext_rate); ++ ingenic_clockevent_init(evt, ext_rate); ++} ++ ++CLOCKSOURCE_OF_DECLARE(x1000_ost_init, "ingenic,x1000-ost", ingenic_ost_init); ++CLOCKSOURCE_OF_DECLARE(x1800_ost_init, "ingenic,x1800-ost", ingenic_ost_init); ++CLOCKSOURCE_OF_DECLARE(t40_ost_init, "ingenic,t40-ost", ingenic_ost_init); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_cpufreq_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_cpufreq_Kconfig.patch new file mode 100644 index 00000000..6c7443e7 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_cpufreq_Kconfig.patch @@ -0,0 +1,34 @@ +diff -drupN a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig +--- a/drivers/cpufreq/Kconfig 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/cpufreq/Kconfig 2022-06-09 05:02:28.000000000 +0300 +@@ -234,6 +234,30 @@ config IA64_ACPI_CPUFREQ + endif + + if MIPS ++config T40_CPUFREQ ++ tristate "t40 CPUFreq Driver" ++ help ++ This option adds a CPUFreq driver for ingenic processors which ++ support software configurable cpu frequency. ++ ++ T40 and it's successors support this feature. ++ ++ For details, take a look at . ++ ++ If in doubt, say N. ++ ++config X2000_V12_CPUFREQ ++ tristate "x2000-v12 CPUFreq Driver" ++ help ++ This option adds a CPUFreq driver for ingenic processors which ++ support software configurable cpu frequency. ++ ++ X2000-v12 and it's successors support this feature. ++ ++ For details, take a look at . ++ ++ If in doubt, say N. ++ + config LOONGSON2_CPUFREQ + tristate "Loongson2 CPUFreq Driver" + help diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_cpufreq_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_cpufreq_Makefile.patch new file mode 100644 index 00000000..c8a19753 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_cpufreq_Makefile.patch @@ -0,0 +1,8 @@ +diff -drupN a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile +--- a/drivers/cpufreq/Makefile 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/cpufreq/Makefile 2022-06-09 05:02:28.000000000 +0300 +@@ -104,3 +104,4 @@ obj-$(CONFIG_SH_CPU_FREQ) += sh-cpufreq + obj-$(CONFIG_SPARC_US2E_CPUFREQ) += sparc-us2e-cpufreq.o + obj-$(CONFIG_SPARC_US3_CPUFREQ) += sparc-us3-cpufreq.o + obj-$(CONFIG_UNICORE32) += unicore2-cpufreq.o ++obj-$(CONFIG_T40_CPUFREQ) += ingenic-cpufreq.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_cpufreq_ingenic-cpufreq.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_cpufreq_ingenic-cpufreq.c.patch new file mode 100644 index 00000000..d6ffe709 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_cpufreq_ingenic-cpufreq.c.patch @@ -0,0 +1,346 @@ +diff -drupN a/drivers/cpufreq/ingenic-cpufreq.c b/drivers/cpufreq/ingenic-cpufreq.c +--- a/drivers/cpufreq/ingenic-cpufreq.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/cpufreq/ingenic-cpufreq.c 2022-06-09 05:02:28.000000000 +0300 +@@ -0,0 +1,342 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define PARENT_APLL 1 ++#define PARENT_MPLL 2 ++#define BIU_FREQ_THRESHOLD 750000000 ++ ++static struct ingenic_cpufreq { ++ struct device *dev; ++ unsigned int latency; ++ struct cpufreq_frequency_table *freq_table_dt; ++ struct cpufreq_frequency_table *freq_table; ++ unsigned int freq_count; ++ struct mutex mutex; ++ ++ struct clk *mux; ++ struct clk *mclk; ++ struct clk *sclka; ++ struct clk *clk_cpu_l2c_x1; ++ struct clk *clk_cpu_l2c_x2; ++ unsigned int arate; ++ unsigned int mrate; ++ ++ struct regulator *regulator; ++}; ++ ++static struct ingenic_cpufreq *ingenic_cpufreq; ++ ++ ++static unsigned long lpj_ref; ++static int ingenic_cpu_freq_notifier(struct notifier_block *nb, unsigned long val, void *data) ++{ ++ struct cpufreq_freqs *freqs = data; ++ static unsigned int lpj_ref_freq; ++ ++ if (val == CPUFREQ_PRECHANGE) { ++ lpj_ref = loops_per_jiffy; ++ } ++ ++ if (val == CPUFREQ_POSTCHANGE) { ++ lpj_ref_freq = freqs->old; ++ loops_per_jiffy = cpufreq_scale(lpj_ref, lpj_ref_freq, freqs->new); ++ } ++ ++ return NOTIFY_OK; ++} ++ ++static struct notifier_block ingenic_cpufreq_notifier_block = { ++ .notifier_call = ingenic_cpu_freq_notifier, ++}; ++ ++ ++static void ingenic_cpufreq_get_freq_table(void) ++{ ++ unsigned int a_rate = ingenic_cpufreq->arate; ++ unsigned int m_rate = ingenic_cpufreq->mrate; ++ unsigned int div[16] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; ++ unsigned int count = 0, dt_freq; ++ int i, j; ++ ++ ++ for (i = 0; i < ingenic_cpufreq->freq_count; i++) { ++ dt_freq = ingenic_cpufreq->freq_table_dt[i].frequency * 1000; ++ for (j = 0; j < 16; j++) { ++ if (dt_freq == a_rate / div[j]) { ++ ingenic_cpufreq->freq_table[count].frequency = ingenic_cpufreq->freq_table_dt[i].frequency; ++ ingenic_cpufreq->freq_table[count].driver_data = PARENT_APLL; ++ ingenic_cpufreq->freq_table[count].flags = ingenic_cpufreq->freq_table_dt[i].flags; ++ count++; ++ break; ++ } ++ if (dt_freq == m_rate / div[j]) { ++ ingenic_cpufreq->freq_table[count].frequency = ingenic_cpufreq->freq_table_dt[i].frequency; ++ ingenic_cpufreq->freq_table[count].driver_data = PARENT_MPLL; ++ ingenic_cpufreq->freq_table[count].flags = ingenic_cpufreq->freq_table_dt[i].flags; ++ count++; ++ break; ++ } ++ } ++ } ++ ingenic_cpufreq->freq_count = count; ++ ++ ingenic_cpufreq->freq_table[count].driver_data = count; ++ ingenic_cpufreq->freq_table[count].frequency = CPUFREQ_TABLE_END; ++ ++} ++ ++static int ingenic_cpufreq_init(struct cpufreq_policy *policy) ++{ ++ ingenic_cpufreq->mclk = clk_get(NULL, "mpll"); ++ ingenic_cpufreq->sclka = clk_get(NULL, "sclka"); ++ ingenic_cpufreq->mux = clk_get(NULL, "mux_cpu_l2c"); ++ ingenic_cpufreq->clk_cpu_l2c_x1 = clk_get(NULL, "div_cpu_l2c_x1"); ++ ingenic_cpufreq->clk_cpu_l2c_x2 = clk_get(NULL, "div_cpu_l2c_x2"); ++ ++ ingenic_cpufreq->arate = clk_get_rate(ingenic_cpufreq->sclka); ++ ingenic_cpufreq->mrate = clk_get_rate(ingenic_cpufreq->mclk); ++ ++ ingenic_cpufreq_get_freq_table(); ++ ++ if (ingenic_cpufreq->arate > BIU_FREQ_THRESHOLD) ++ policy->clk = ingenic_cpufreq->clk_cpu_l2c_x2; ++ else ++ policy->clk = ingenic_cpufreq->clk_cpu_l2c_x1; ++ ++ ingenic_cpufreq->latency = 4000; ++ ++ return cpufreq_generic_init(policy, ingenic_cpufreq->freq_table, ingenic_cpufreq->latency); ++} ++ ++static int ingenic_cpufreq_target(struct cpufreq_policy *policy, unsigned int index) ++{ ++ struct cpufreq_frequency_table *freq_table = ingenic_cpufreq->freq_table; ++ unsigned long freq_new, freq_old; ++ unsigned long freq_round; ++ struct clk *mux, *sclka, *mclk, *clk_cpu_l2c; ++ unsigned int a_rate, m_rate, parent; ++ struct dev_pm_opp *opp; ++ unsigned long v; ++ ++ mutex_lock(&ingenic_cpufreq->mutex); ++ freq_new = freq_table[index].frequency * 1000; ++ freq_old = clk_get_rate(policy->clk); ++ ++ if (freq_old == freq_new) { ++ mutex_unlock(&ingenic_cpufreq->mutex); ++ return 0; ++ } ++ ++ parent = freq_table[index].driver_data; ++ mclk = ingenic_cpufreq->mclk; ++ sclka = ingenic_cpufreq->sclka; ++ mux = ingenic_cpufreq->mux; ++ ++ a_rate = ingenic_cpufreq->arate; ++ m_rate = ingenic_cpufreq->mrate; ++ ++ if (freq_new > BIU_FREQ_THRESHOLD) { ++ clk_cpu_l2c = ingenic_cpufreq->clk_cpu_l2c_x2; ++ } else { ++ clk_cpu_l2c = ingenic_cpufreq->clk_cpu_l2c_x1; ++ } ++ clk_get_rate(clk_cpu_l2c); ++ ++#ifdef CONFIG_REGULATOR ++ freq_round = clk_round_rate(clk_cpu_l2c, freq_new); ++ ++ opp = dev_pm_opp_find_freq_ceil(ingenic_cpufreq->dev, &freq_round); ++ v = dev_pm_opp_get_voltage(opp); ++ ++ if (freq_round > freq_old) { ++ regulator_set_voltage(ingenic_cpufreq->regulator, v, v); ++ clk_set_rate(clk_cpu_l2c, freq_round); ++ } ++ if (freq_round < freq_old) { ++ clk_set_rate(clk_cpu_l2c, freq_round); ++ regulator_set_voltage(ingenic_cpufreq->regulator, v, v); ++ } ++#else ++ clk_set_rate(clk_cpu_l2c, freq_new); ++#endif ++ ++ if (parent == PARENT_APLL) { ++ clk_set_parent(mux, sclka); ++ } else if (parent == PARENT_MPLL) { ++ clk_set_parent(mux, mclk); ++ } else { ++ printk("wrong clk parent\n"); ++ } ++ ++#ifdef CONFIG_REGULATOR ++ opp = dev_pm_opp_find_freq_exact(ingenic_cpufreq->dev, freq_new, 1); ++ v = dev_pm_opp_get_voltage(opp); ++ ++ if (freq_new >= freq_round) { ++ regulator_set_voltage(ingenic_cpufreq->regulator, v, v); ++ clk_set_rate(clk_cpu_l2c, freq_new); ++ } ++ if (freq_new < freq_round) { ++ clk_set_rate(clk_cpu_l2c, freq_new); ++ regulator_set_voltage(ingenic_cpufreq->regulator, v, v); ++ } ++#else ++ clk_set_rate(clk_cpu_l2c, freq_new); ++#endif ++ ++ policy->clk = clk_cpu_l2c; ++ policy->cur = freq_new / 1000; ++ ++#ifdef CONFIG_REGULATOR ++ if ((freq_new != clk_get_rate(clk_cpu_l2c)) || (v != regulator_get_voltage(ingenic_cpufreq->regulator))) { ++ printk("warning : "); ++ printk("from %dKHZ to %dKHZ(%duV) now: %dKHZ(%duV)\n", freq_old/1000, freq_new/1000, v, clk_get_rate(clk_cpu_l2c)/1000, regulator_get_voltage(ingenic_cpufreq->regulator)); ++ } ++#else ++ if (freq_new != clk_get_rate(clk_cpu_l2c)) { ++ printk("warning : "); ++ printk("from %dKHZ to %dKHZ now: %dKHZ\n", freq_old/1000, freq_new/1000, clk_get_rate(clk_cpu_l2c)/1000); ++ } ++#endif ++ ++ mutex_unlock(&ingenic_cpufreq->mutex); ++ ++ return 0; ++} ++ ++static int ingenic_cpufreq_suspend(struct cpufreq_policy *policy) ++{ ++ return 0; ++} ++ ++static int ingenic_cpufreq_resume(struct cpufreq_policy *policy) ++{ ++ return 0; ++} ++ ++static struct cpufreq_driver ingenic_cpufreq_driver = { ++ .name = "ingenic-cpufreq", ++ .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK, ++ .init = ingenic_cpufreq_init, ++ .verify = cpufreq_generic_frequency_table_verify, ++ .target_index = ingenic_cpufreq_target, ++ .get = cpufreq_generic_get, ++ .suspend = ingenic_cpufreq_suspend, ++ .resume = ingenic_cpufreq_resume, ++ .attr = cpufreq_generic_attr, ++}; ++ ++static const struct of_device_id ingenic_cpufreq_match[] = { ++ { ++ .compatible = "ingenic,t40-cpufreq", ++ .compatible = "ingenic,x2000-v12-cpufreq", ++ }, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(of, ingenic_cpufreq_match); ++ ++static int ingenic_cpufreq_probe(struct platform_device *pdev) ++{ ++ int ret; ++ struct device_node *np; ++ ++ np = pdev->dev.of_node; ++ if (!np) ++ return -ENODEV; ++ ++ ingenic_cpufreq = devm_kzalloc(&pdev->dev, sizeof(struct ingenic_cpufreq), GFP_KERNEL); ++ if (!ingenic_cpufreq) { ++ ret = -ENOMEM; ++ goto err_put_node; ++ } ++ ++ ingenic_cpufreq->dev = &pdev->dev; ++ ++ ret = dev_pm_opp_of_add_table(ingenic_cpufreq->dev); ++ if (ret) { ++ dev_err(ingenic_cpufreq->dev, "failed to init OPP table : %d\n", ret); ++ goto err_put_node; ++ } ++ ++ ret = dev_pm_opp_init_cpufreq_table(ingenic_cpufreq->dev, &ingenic_cpufreq->freq_table_dt); ++ if (ret) { ++ dev_err(ingenic_cpufreq->dev, "failed to init cpufreq table : %d\n", ret); ++ goto err_free_opp; ++ } ++ ++ ingenic_cpufreq->freq_count = dev_pm_opp_get_opp_count(ingenic_cpufreq->dev); ++ ++ ingenic_cpufreq->freq_table = kcalloc(ingenic_cpufreq->freq_count + 1, sizeof(struct cpufreq_frequency_table), GFP_ATOMIC); ++ ++#ifdef CONFIG_REGULATOR ++ ingenic_cpufreq->regulator = devm_regulator_get(ingenic_cpufreq->dev, "cpu-core"); ++ if (!ingenic_cpufreq->regulator) ++ printk("cannot get regulator for cpufreq\n"); ++ ++#endif ++ ++ mutex_init(&ingenic_cpufreq->mutex); ++ ++ cpufreq_register_notifier(&ingenic_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); ++ ++ ret = cpufreq_register_driver(&ingenic_cpufreq_driver); ++ if (ret) { ++ dev_err(ingenic_cpufreq->dev, "%s : failed to register cpufreq driver\n", __func__); ++ goto err_free_table; ++ } ++ ++ of_node_put(np); ++ ++ printk("cpufreq register succeed\n"); ++ ++ return 0; ++ ++err_free_table: ++ dev_pm_opp_free_cpufreq_table(ingenic_cpufreq->dev, &ingenic_cpufreq->freq_table_dt); ++ ++err_free_opp: ++ dev_pm_opp_of_remove_table(ingenic_cpufreq->dev); ++ ++err_put_node: ++ of_node_put(np); ++ dev_err(&pdev->dev, "%s : failed initialization\n", __func__); ++ ++ return ret; ++} ++ ++ ++static int ingenic_cpufreq_remove(struct platform_device *pdev) ++{ ++ cpufreq_unregister_driver(&ingenic_cpufreq_driver); ++ cpufreq_unregister_notifier(&ingenic_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); ++ ++ return 0; ++} ++ ++static struct platform_driver ingenic_cpufreq_platdrv = { ++ .driver = { ++ .name = "ingenic-cpufreq", ++ .of_match_table = ingenic_cpufreq_match, ++ }, ++ .probe = ingenic_cpufreq_probe, ++ .remove = ingenic_cpufreq_remove, ++}; ++module_platform_driver(ingenic_cpufreq_platdrv); ++ ++MODULE_AUTHOR("Liu Si Hui "); ++MODULE_DESCRIPTION("ingenic t40 cpufreq driver"); ++MODULE_LICENSE("GPL"); ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_crypto_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_crypto_Kconfig.patch new file mode 100644 index 00000000..fb8c0070 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_crypto_Kconfig.patch @@ -0,0 +1,39 @@ +diff -drupN a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig +--- a/drivers/crypto/Kconfig 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/crypto/Kconfig 2022-06-09 05:02:28.000000000 +0300 +@@ -308,6 +308,15 @@ config CRYPTO_DEV_OMAP_DES + the ECB and CBC modes of operation supported by the driver. Also + accesses made on unaligned boundaries are also supported. + ++config CRYPTO_DEV_INGENIC_AES ++ tristate "Support for INGENIC AES hw engine" ++ depends on MARCH_XBURST1 || MACH_XBURST2 ++ select CRYPTO_AES ++ select CRYPTO_BLKCIPHER2 ++ help ++ INGENIC processors have AES module accelerator. Select this if you ++ want to use the INGENIC module for AES algorithms. ++ + config CRYPTO_DEV_PICOXCELL + tristate "Support for picoXcell IPSEC and Layer2 crypto engines" + depends on ARCH_PICOXCELL && HAVE_CLK +@@ -481,6 +490,19 @@ config CRYPTO_DEV_IMGTEC_HASH + hardware hash accelerator. Supporting MD5/SHA1/SHA224/SHA256 + hashing algorithms. + ++config CRYPTO_DEV_INGENIC_SHA ++ tristate "Support for Ingenic SHA hw accelerator" ++ depends on MARCH_XBURST1 || MACH_XBURST2 ++ select CRYPTO_ALGAPI ++ help ++ Some Ingenic processors have MD5/SHA1/SHA224/SHA256/SHA384/SHA512 ++ hw accelerator. ++ Select this if you want to use the Ingenic module for ++ MD5/SHA1/SHA224/SHA256/SHA384/SHA512 algorithms. ++ ++ To compile this driver as a module, choose M here: the module ++ will be called ingenic-sha. ++ + config CRYPTO_DEV_SUN4I_SS + tristate "Support for Allwinner Security System cryptographic accelerator" + depends on ARCH_SUNXI diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_crypto_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_crypto_Makefile.patch new file mode 100644 index 00000000..35310417 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_crypto_Makefile.patch @@ -0,0 +1,11 @@ +diff -drupN a/drivers/crypto/Makefile b/drivers/crypto/Makefile +--- a/drivers/crypto/Makefile 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/crypto/Makefile 2022-06-09 05:02:28.000000000 +0300 +@@ -29,3 +29,6 @@ obj-$(CONFIG_CRYPTO_DEV_QAT) += qat/ + obj-$(CONFIG_CRYPTO_DEV_QCE) += qce/ + obj-$(CONFIG_CRYPTO_DEV_VMX) += vmx/ + obj-$(CONFIG_CRYPTO_DEV_SUN4I_SS) += sunxi-ss/ ++ ++obj-$(CONFIG_CRYPTO_DEV_INGENIC_AES) += ingenic-aes.o ++obj-$(CONFIG_CRYPTO_DEV_INGENIC_SHA) += ingenic-hash.o +\ В конце файла нет новой строки diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_crypto_ingenic-aes.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_crypto_ingenic-aes.c.patch new file mode 100644 index 00000000..50aafbd0 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_crypto_ingenic-aes.c.patch @@ -0,0 +1,895 @@ +diff -drupN a/drivers/crypto/ingenic-aes.c b/drivers/crypto/ingenic-aes.c +--- a/drivers/crypto/ingenic-aes.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/crypto/ingenic-aes.c 2022-06-09 05:02:28.000000000 +0300 +@@ -0,0 +1,891 @@ ++/* ++ * Cryptographic API. ++ * ++ * Support for Ingenic AES HW acceleration. ++ * ++ * 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. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "ingenic-aes.h" ++ ++/* keep registered devices data here */ ++static LIST_HEAD(dev_list); ++static DEFINE_SPINLOCK(list_lock); ++ ++ ++static inline unsigned long aes_read(struct ingenic_aes_dev *aes, unsigned long offset) ++{ ++ return readl(aes->io_base + offset); ++} ++ ++static inline void aes_write(struct ingenic_aes_dev *aes, unsigned long offset, ++ unsigned long value) ++{ ++ writel(value, aes->io_base + offset); ++} ++ ++void dump_aes_reg(struct ingenic_aes_dev *aes){ ++ dev_info(aes->dev,"AES_ASCR: 0x%08lx\n",aes_read(aes,AES_ASCR)); ++ dev_info(aes->dev,"AES_ASSR: 0x%08lx\n",aes_read(aes,AES_ASSR)); ++ dev_info(aes->dev,"AES_ASINTM: 0x%08lx\n",aes_read(aes,AES_ASINTM)); ++ dev_info(aes->dev,"AES_ASSA: 0x%08lx\n",aes_read(aes,AES_ASSA)); ++ dev_info(aes->dev,"AES_ASDA: 0x%08lx\n",aes_read(aes,AES_ASDA)); ++ dev_info(aes->dev,"AES_ASTC: 0x%08lx\n",aes_read(aes,AES_ASTC)); ++} ++ ++static inline int ingenic_aes_hw_init(struct ingenic_aes_dev *aes) ++{ ++ /* ++ * clocks are enabled when request starts and disabled when finished. ++ * It may be long delays between requests. ++ * Device might go to off mode to save power. ++ */ ++ pm_runtime_get_sync(aes->dev); ++ ++ if (!(aes->flags & FLAGS_INIT)) { ++ aes->flags |= FLAGS_INIT; ++ aes->err = 0; ++ } ++ ++ return 0; ++} ++ ++static inline int check_keydone(struct ingenic_aes_dev *aes) ++{ ++ unsigned long timeout = 1000; ++ while(!(aes_read(aes,AES_ASSR) & (1 << 0)) && --timeout); ++ if(timeout == 0){ ++ dev_err(aes->dev,"Write keys is timeout.\n"); ++ return -1; ++ } ++ return 0; ++} ++ ++static inline void ingenic_aes_stop(struct ingenic_aes_dev *aes) ++{ ++ unsigned long d; ++ d = aes_read(aes, AES_ASCR); ++ d &= ~1; ++ aes_write(aes, AES_ASCR,d); ++ aes->flags = 0; ++ pm_runtime_put_sync(aes->dev); ++ pr_debug("ingenic aes stop. finished!\n"); ++} ++static inline int ingenic_aes_write_ctrl(struct ingenic_aes_dev *aes) ++{ ++ unsigned int key32; ++ int i; ++ unsigned long val,init_data,mode,alg; ++ int err; ++ err = ingenic_aes_hw_init(aes); ++ if (err){ ++ dev_err(aes->dev,"aes hw init failed.\n"); ++ return err; ++ } ++ // 1. Mask interrupt and clear interrupt. ++ aes_write(aes,AES_ASINTM,0); ++ aes_read(aes,AES_ASSR); ++ ++ // 2. AES enable and clear data for new process. ++ init_data = ASCR_PS_DEF | ASCR_CLR | ASCR_EN; ++ aes_write(aes,AES_ASCR,init_data); ++ ++ // 3. configure AES ++ ++ key32 = aes->ctx->keylen / sizeof(unsigned long); ++ switch(aes->ctx->keylen){ ++ case AES_KEYSIZE_128: ++ val = 0; ++ break; ++ case AES_KEYSIZE_192: ++ val = 1; ++ break; ++ case AES_KEYSIZE_256: ++ val = 2; ++ break; ++ default: ++ dev_err(aes->dev,"len error\n"); ++ return -EINVAL; ++ } ++ alg = (aes->flags & FLAGS_CBC) == FLAGS_CBC ? CBC_ALG:ECB_ALG; ++ mode = (aes->flags & FLAGS_DECRYPT) == FLAGS_DECRYPT ? DECRYPTO_MODE : ENCRYPTO_MODE; ++ ++ init_data = ASCR_PS_DEF | ASCR_KEYL(val) | ASCR_ALGS(alg) | ASCR_DECE(mode) | ASCR_EN; ++ aes_write(aes,AES_ASCR,init_data); ++ ++ if (alg == CBC_ALG){ ++ // Initialize IV of cbc alg ++ unsigned int *dat = aes->req->info; ++ if(dat == NULL){ ++ dev_err(aes->dev,"no set iv data in cbc(aes)\n"); ++ } ++ for (i = 0; i < 4; i++) { ++ aes_write(aes, AES_ASIV,__be32_to_cpu(dat[i])); ++ /* printk("======== iv:0x%08lx 0x%08x\n",dat[i],__be32_to_cpu(dat[i])); */ ++ } ++ init_data = aes_read(aes,AES_ASCR); ++ aes_write(aes,AES_ASCR,init_data | ASCR_INIT_IV); ++ } ++ // Initialize Key. ++ for (i = 0; i < key32; i++) { ++ aes_write(aes, AES_ASKY, ++ __be32_to_cpu(aes->ctx->key[i])); ++ /* printk("======== 0x%08lx 0x%08x\n",aes->ctx->key[i],__be32_to_cpu(aes->ctx->key[i])); */ ++ } ++ ++ init_data = aes_read(aes,AES_ASCR); ++ aes_write(aes,AES_ASCR,init_data | ASCR_KEYS); // check key done in dma process. ++ return 0; ++} ++ ++static struct ingenic_aes_dev *ingenic_aes_find_dev(struct ingenic_aes_ctx *ctx) ++{ ++ struct ingenic_aes_dev *aes = NULL, *tmp; ++ ++ spin_lock(&list_lock); ++ if (!ctx->aes) { ++ list_for_each_entry(tmp, &dev_list, list) { ++ /* FIXME: take fist available aes core */ ++ aes = tmp; ++ break; ++ } ++ ctx->aes = aes; ++ } else { ++ /* already found before */ ++ aes = ctx->aes; ++ } ++ spin_unlock(&list_lock); ++ ++ return aes; ++} ++ ++static int ingenic_aes_dma_init(struct ingenic_aes_dev *aes) ++{ ++ int err = -ENOMEM; ++ aes->buf_in = (void *)__get_free_pages(GFP_KERNEL, INGENIC_AES_CACHE_PAGE_SHIFT); ++ aes->buf_out = (void *)__get_free_pages(GFP_KERNEL, INGENIC_AES_CACHE_PAGE_SHIFT); ++ aes->buflen = PAGE_SIZE << INGENIC_AES_CACHE_PAGE_SHIFT; ++ aes->buflen &= ~(AES_BLOCK_SIZE - 1); ++ ++ if (!aes->buf_in || !aes->buf_out) { ++ dev_err(aes->dev, "unable to alloc pages.\n"); ++ goto err_alloc; ++ } ++ aes->dma_addr_in = dma_map_single(aes->dev, aes->buf_in, aes->buflen, ++ DMA_TO_DEVICE); ++ if (dma_mapping_error(aes->dev, aes->dma_addr_in)) { ++ dev_err(aes->dev, "dma %d bytes error\n", aes->buflen); ++ err = -EINVAL; ++ goto err_map_in; ++ } ++ ++ aes->dma_addr_out = dma_map_single(aes->dev, aes->buf_out, aes->buflen, ++ DMA_FROM_DEVICE); ++ if (dma_mapping_error(aes->dev, aes->dma_addr_out)) { ++ dev_err(aes->dev, "dma %d bytes error\n", aes->buflen); ++ err = -EINVAL; ++ goto err_map_out; ++ } ++ return 0; ++err_map_out: ++ dma_unmap_single(aes->dev, aes->dma_addr_in, aes->buflen, DMA_TO_DEVICE); ++err_map_in: ++ free_pages((unsigned long)aes->buf_out, INGENIC_AES_CACHE_PAGE_SHIFT); ++ free_pages((unsigned long)aes->buf_in, INGENIC_AES_CACHE_PAGE_SHIFT); ++err_alloc: ++ if (err) ++ pr_err("error: %d\n", err); ++ return err; ++} ++ ++static void ingenic_aes_dma_cleanup(struct ingenic_aes_dev *aes) ++{ ++ free_pages((unsigned long)aes->buf_out, INGENIC_AES_CACHE_PAGE_SHIFT); ++ free_pages((unsigned long)aes->buf_in, INGENIC_AES_CACHE_PAGE_SHIFT); ++} ++ ++static void sg_copy_buf(void *buf, struct scatterlist *sg, ++ unsigned int start, unsigned int nbytes, int out) ++{ ++ struct scatter_walk walk; ++ ++ if (!nbytes) ++ return; ++ ++ scatterwalk_start(&walk, sg); ++ scatterwalk_advance(&walk, start); ++ scatterwalk_copychunks(buf, &walk, nbytes, out); ++ scatterwalk_done(&walk, out, 0); ++} ++ ++static int sg_copy(struct scatterlist **sg, size_t *offset, void *buf, ++ size_t buflen, size_t total, int out) ++{ ++ unsigned int count, off = 0; ++ ++ while (buflen && total) { ++ count = min((*sg)->length - *offset, total); ++ count = min(count, buflen); ++ ++ if (!count) ++ return off; ++ ++ /* ++ * buflen and total are AES_BLOCK_SIZE size aligned, ++ * so count should be also aligned ++ */ ++ ++ sg_copy_buf(buf + off, *sg, *offset, count, out); ++ ++ off += count; ++ buflen -= count; ++ *offset += count; ++ total -= count; ++ ++ if (*offset == (*sg)->length) { ++ *sg = sg_next(*sg); ++ if (*sg) ++ *offset = 0; ++ else ++ total = 0; ++ } ++ } ++ ++ return off; ++} ++ ++void dump_sgdata(struct scatterlist *sg) ++{ ++ int i; ++ unsigned int *d = sg_virt(sg); ++ for(i = 0;i < sg->length;i += 4) ++ { ++ printk("%5d:0x%08x\n",i,d[i/4]); ++ } ++} ++ ++void prep_sgdata(struct scatterlist *sg) ++{ ++ int i; ++ unsigned int *d = sg_virt(sg); ++ unsigned int dat; ++ for(i = 0;i < sg->length;i += 4) ++ { ++ dat = d[i/4]; ++ d[i/4] = __be32_to_cpu(dat); ++ } ++} ++ ++ ++static int ingenic_aes_crypt_dma(struct crypto_tfm *tfm, ++ struct scatterlist *in_sg, struct scatterlist *out_sg) ++{ ++ struct ingenic_aes_ctx *ctx = crypto_tfm_ctx(tfm); ++ struct ingenic_aes_dev *aes = ctx->aes; ++ ++ dma_addr_t dma_addr_in = sg_dma_address(in_sg); ++ dma_addr_t dma_addr_out = sg_dma_address(out_sg); ++ int length = sg_dma_len(in_sg); ++ int blen = 0; ++ ++ unsigned int config; ++// dev_info(aes->dev,"len: %d\n", length); ++ if(check_keydone(aes) != 0){ ++ dev_err(aes->dev,"check key done failed!\n"); ++ return -EINPROGRESS; ++ } ++ ++ config = aes_read(aes,AES_ASCR); ++ ++ aes->dma_size = length; ++ aes_write(aes,AES_ASSA,dma_addr_in); ++ aes_write(aes,AES_ASDA,dma_addr_out); ++ ++ blen = length / 8; // perblock is 128bit. ++ ++ if(length % 8) ++ return -EINVAL; ++ ++ aes_write(aes,AES_ASTC,blen); ++ aes_write(aes,AES_ASINTM,4); ++ config |= (ASCR_DMAE | ASCR_DMAS); ++ aes_write(aes,AES_ASCR,config); ++ return 0; ++} ++static int ingenic_aes_crypt_dma_start(struct ingenic_aes_dev *aes) ++{ ++ struct crypto_tfm *tfm = crypto_ablkcipher_tfm( ++ crypto_ablkcipher_reqtfm(aes->req)); ++ int err, fast = 0, in, out; ++ size_t count; ++ dma_addr_t addr_in, addr_out; ++ struct scatterlist *in_sg, *out_sg; ++ int len32; ++ ++ dev_dbg(aes->dev,"total: %d\n", aes->total); ++ ++ if (sg_is_last(aes->in_sg) && sg_is_last(aes->out_sg)) { ++ /* check for alignment */ ++ in = IS_ALIGNED((unsigned long)aes->in_sg->offset, sizeof(unsigned long)); ++ out = IS_ALIGNED((unsigned long)aes->out_sg->offset, sizeof(unsigned long)); ++ ++ fast = in && out; ++ } ++ if (fast) { ++ count = min(aes->total, sg_dma_len(aes->in_sg)); ++ count = min(count, sg_dma_len(aes->out_sg)); ++ ++ if (count != aes->total) { ++ pr_err("request length != buffer length\n"); ++ return -EINVAL; ++ } ++ ++ prep_sgdata(aes->in_sg); ++ //dump_sgdata(aes->in_sg); ++ ++ pr_debug("fast\n"); ++ err = dma_map_sg(aes->dev, aes->in_sg, 1, DMA_TO_DEVICE); ++ ++ if (!err) { ++ dev_err(aes->dev, "dma_map_sg() error\n"); ++ return -EINVAL; ++ } ++ ++ err = dma_map_sg(aes->dev, aes->out_sg, 1, DMA_FROM_DEVICE); ++ if (!err) { ++ dev_err(aes->dev, "dma_map_sg() error\n"); ++ dma_unmap_sg(aes->dev, aes->in_sg, 1, DMA_TO_DEVICE); ++ return -EINVAL; ++ } ++ ++ addr_in = sg_dma_address(aes->in_sg); ++ addr_out = sg_dma_address(aes->out_sg); ++ ++ in_sg = aes->in_sg; ++ out_sg = aes->out_sg; ++ ++ aes->flags |= FLAGS_FAST; ++ ++ } else { ++ /* use cache buffers */ ++ count = sg_copy(&aes->in_sg, &aes->in_offset, aes->buf_in, ++ aes->buflen, aes->total, 0); ++ ++ len32 = DIV_ROUND_UP(count, DMA_MIN) * DMA_MIN; ++ ++ /* ++ * The data going into the AES module has been copied ++ * to a local buffer and the data coming out will go ++ * into a local buffer so set up local SG entries for ++ * both. ++ */ ++ ++ sg_init_one(&aes->in_sgl,aes->buf_in,len32); ++ sg_dma_len(&aes->in_sgl) = len32; ++ sg_dma_address(&aes->in_sgl) = aes->dma_addr_in; ++ sg_init_one(&aes->out_sgl,aes->buf_out,len32); ++ sg_dma_len(&aes->out_sgl) = len32; ++ sg_dma_address(&aes->out_sgl) = aes->dma_addr_out; ++ ++ in_sg = &aes->in_sgl; ++ out_sg = &aes->out_sgl; ++ ++ addr_in = aes->dma_addr_in; ++ addr_out = aes->dma_addr_out; ++ ++ prep_sgdata(in_sg); ++ //dump_sgdata(in_sg); ++ ++ aes->flags &= ~FLAGS_FAST; ++ dma_cache_sync(aes->dev, sg_virt(in_sg), len32,DMA_TO_DEVICE); ++ dma_cache_sync(aes->dev, sg_virt(out_sg),len32,DMA_FROM_DEVICE); ++ } ++ ++ aes->total -= count; ++ err = ingenic_aes_crypt_dma(tfm, in_sg, out_sg); ++ if (err) { ++ dma_unmap_sg(aes->dev, aes->in_sg, 1, DMA_TO_DEVICE); ++ dma_unmap_sg(aes->dev, aes->out_sg, 1, DMA_TO_DEVICE); ++ } ++ ++ return err; ++} ++ ++static void ingenic_aes_finish_req(struct ingenic_aes_dev *aes, int err) ++{ ++ struct ablkcipher_request *req = aes->req; ++ ++ pr_debug("err: %d\n", err); ++ ++ aes->flags &= ~FLAGS_BUSY; ++ req->base.complete(&req->base, err); ++} ++ ++static int ingenic_aes_crypt_dma_stop(struct ingenic_aes_dev *aes) ++{ ++ int err = 0; ++ size_t count; ++ /* unsigned int val; */ ++ pr_debug("total: %d\n", aes->total); ++ ++ /* val = aes_read(aes,AES_ASCR); */ ++ /* val &= ~(3 << 8); */ ++ /* aes_write(aes,AES_ASCR,val); */ ++ ++ if (aes->flags & FLAGS_FAST) ++ { ++ dma_unmap_sg(aes->dev, aes->out_sg, 1, DMA_FROM_DEVICE); ++ prep_sgdata(aes->out_sg); ++ //dump_sgdata(aes->out_sg); ++ dma_unmap_sg(aes->dev, aes->in_sg, 1, DMA_TO_DEVICE); ++ } else { ++ dma_sync_single_for_device(aes->dev, aes->dma_addr_out, ++ aes->dma_size, DMA_FROM_DEVICE); ++ ++ prep_sgdata(&aes->out_sgl); ++ //dump_sgdata(&aes->out_sgl); ++ ++ /* copy data */ ++ count = sg_copy(&aes->out_sg, &aes->out_offset, aes->buf_out, ++ aes->buflen, aes->dma_size, 1); ++ ++ if (count != aes->dma_size) { ++ err = -EINVAL; ++ pr_err("not all data converted: %u\n", count); ++ } ++ } ++ return err; ++} ++ ++static int ingenic_aes_start(struct ingenic_aes_dev *aes, ++ struct ablkcipher_request *req) ++{ ++ struct crypto_async_request *async_req, *backlog; ++ struct ingenic_aes_ctx *ctx; ++ struct ingenic_aes_reqctx *rctx; ++ unsigned long flags; ++ int err, ret = 0; ++ spin_lock_irqsave(&aes->lock, flags); ++ if (req) ++ ret = ablkcipher_enqueue_request(&aes->queue, req); ++ if (aes->flags & FLAGS_BUSY) { ++ spin_unlock_irqrestore(&aes->lock, flags); ++ return ret; ++ } ++ backlog = crypto_get_backlog(&aes->queue); ++ async_req = crypto_dequeue_request(&aes->queue); ++ if (async_req) ++ aes->flags |= FLAGS_BUSY; ++ spin_unlock_irqrestore(&aes->lock, flags); ++ ++ if (!async_req){ ++ ingenic_aes_stop(aes); ++ return ret; ++ } ++ if (backlog) ++ backlog->complete(backlog, -EINPROGRESS); ++ req = ablkcipher_request_cast(async_req); ++ ++ /* assign new request to device */ ++ aes->req = req; ++ aes->total = req->nbytes; ++ aes->in_offset = 0; ++ aes->in_sg = req->src; ++ aes->out_offset = 0; ++ aes->out_sg = req->dst; ++ ++ rctx = ablkcipher_request_ctx(req); ++ ctx = crypto_ablkcipher_ctx(crypto_ablkcipher_reqtfm(req)); ++ rctx->mode &= FLAGS_MODE_MASK; ++ aes->flags = (aes->flags & ~FLAGS_MODE_MASK) | rctx->mode; ++ ++ aes->ctx = ctx; ++ ctx->aes = aes; ++ ++ err = ingenic_aes_write_ctrl(aes); ++ if (!err) ++ err = ingenic_aes_crypt_dma_start(aes); ++ ++ if (err) { ++ ++ dev_err(aes->dev,"dma start failed.!\n"); ++ ingenic_aes_stop(aes); ++ /* aes_task will not finish it, so do it here */ ++ ingenic_aes_finish_req(aes, err); ++ } ++ return ret; /* return ret, which is enqueue return value */ ++} ++ ++static int ingenic_aes_crypt(struct ablkcipher_request *req, unsigned long mode) ++{ ++ struct ingenic_aes_ctx *ctx = crypto_ablkcipher_ctx( ++ crypto_ablkcipher_reqtfm(req)); ++ struct ingenic_aes_reqctx *rctx = ablkcipher_request_ctx(req); ++ struct ingenic_aes_dev *aes; ++ pr_info("nbytes: %d, enc: %d, cbc: %d\n", req->nbytes, ++ !(mode & FLAGS_DECRYPT), ++ !!(mode & FLAGS_CBC)); ++ ++ if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE)) { ++ pr_err("request size is not exact amount of AES blocks\n"); ++ return -EINVAL; ++ } ++ aes = ingenic_aes_find_dev(ctx); ++ if (!aes) ++ return -ENODEV; ++ rctx->mode = mode; ++ return ingenic_aes_start(aes, req); ++} ++static irqreturn_t ingenic_aec_irqthread(int irq, void *data) ++{ ++ struct ingenic_aes_dev *aes = (struct ingenic_aes_dev *)data; ++ unsigned long val; ++ unsigned long mask; ++ ++ val = aes_read(aes,AES_ASSR); ++ mask = aes_read(aes,AES_ASINTM); ++ val = val & mask; ++ ++ if(val & 4){ ++ int err; ++ err = ingenic_aes_crypt_dma_stop(aes); ++ aes_write(aes,AES_ASSR,4); ++ err = aes->err ? : err; ++ if (aes->total && !err) { ++ err = ingenic_aes_crypt_dma_start(aes); ++ if (!err) ++ return IRQ_HANDLED; /* DMA started. Not fininishing. */ ++ } ++ ingenic_aes_finish_req(aes, err); ++ ingenic_aes_start(aes,NULL); ++ }else if(val & 2){ ++ aes_write(aes,AES_ASSR,2); ++ }else if(val & 1){ ++ aes_write(aes,AES_ASSR,1); ++ }else{ ++ dev_err(aes->dev,"unknown irq!!!\n"); ++ dump_aes_reg(aes); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++/* ********************** ALG API ************************************ */ ++ ++static int ingenic_aes_setkey(struct crypto_ablkcipher *tfm, const u8 *key, ++ unsigned int keylen) ++{ ++ struct ingenic_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm); ++ ++ if (keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_192 && ++ keylen != AES_KEYSIZE_256) ++ return -EINVAL; ++ ++ pr_debug("enter, keylen: %d\n", keylen); ++ ++ memcpy(ctx->key, key, keylen); ++ ctx->keylen = keylen; ++ ++ return 0; ++} ++ ++static int ingenic_aes_ecb_encrypt(struct ablkcipher_request *req) ++{ ++ return ingenic_aes_crypt(req, 0); ++} ++ ++static int ingenic_aes_ecb_decrypt(struct ablkcipher_request *req) ++{ ++ return ingenic_aes_crypt(req, FLAGS_DECRYPT); ++} ++ ++static int ingenic_aes_cbc_encrypt(struct ablkcipher_request *req) ++{ ++ return ingenic_aes_crypt(req, FLAGS_CBC); ++} ++ ++static int ingenic_aes_cbc_decrypt(struct ablkcipher_request *req) ++{ ++ return ingenic_aes_crypt(req, FLAGS_DECRYPT | FLAGS_CBC); ++} ++static int ingenic_aes_cra_init(struct crypto_tfm *tfm) ++{ ++ pr_debug("enter\n"); ++ tfm->crt_ablkcipher.reqsize = sizeof(struct ingenic_aes_reqctx); ++ return 0; ++} ++ ++static void ingenic_aes_cra_exit(struct crypto_tfm *tfm) ++{ ++ pr_debug("exit\n"); ++} ++ ++ ++/* ********************** ALGS ************************************ */ ++ ++static struct crypto_alg algs_ecb_cbc[] = { ++ { ++ .cra_name = "ecb(aes)", ++ .cra_driver_name = "ecb-aes-ingenic", ++ .cra_priority = 100, ++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | ++ CRYPTO_ALG_ASYNC, ++ .cra_blocksize = AES_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct ingenic_aes_ctx), ++ .cra_alignmask = 0, ++ .cra_type = &crypto_ablkcipher_type, ++ .cra_module = THIS_MODULE, ++ .cra_init = ingenic_aes_cra_init, ++ .cra_exit = ingenic_aes_cra_exit, ++ .cra_u.ablkcipher = { ++ .min_keysize = AES_MIN_KEY_SIZE, ++ .max_keysize = AES_MAX_KEY_SIZE, ++ .setkey = ingenic_aes_setkey, ++ .encrypt = ingenic_aes_ecb_encrypt, ++ .decrypt = ingenic_aes_ecb_decrypt, ++ } ++ }, ++ { ++ .cra_name = "cbc(aes)", ++ .cra_driver_name = "cbc-aes-ingenic", ++ .cra_priority = 100, ++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | ++ CRYPTO_ALG_ASYNC, ++ .cra_blocksize = AES_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct ingenic_aes_ctx), ++ .cra_alignmask = 0, ++ .cra_type = &crypto_ablkcipher_type, ++ .cra_module = THIS_MODULE, ++ .cra_init = ingenic_aes_cra_init, ++ .cra_exit = ingenic_aes_cra_exit, ++ .cra_u.ablkcipher = { ++ .min_keysize = AES_MIN_KEY_SIZE, ++ .max_keysize = AES_MAX_KEY_SIZE, ++ .ivsize = AES_BLOCK_SIZE, ++ .setkey = ingenic_aes_setkey, ++ .encrypt = ingenic_aes_cbc_encrypt, ++ .decrypt = ingenic_aes_cbc_decrypt, ++ } ++ }, ++}; ++ ++static struct ingenic_aes_pdata ingenic_aes_pdata = { ++ .algs_list = algs_ecb_cbc, ++ .size = ARRAY_SIZE(algs_ecb_cbc), ++}; ++static int ingenic_aes_get_res_pdev(struct ingenic_aes_dev *aes, ++ struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct resource *r; ++ int err; ++ int ret = 0; ++ /* Get the base address */ ++ r = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!r) { ++ dev_err(dev, "no MEM resource info\n"); ++ err = -ENODEV; ++ goto err; ++ } ++ ++ aes->io_base = devm_ioremap(aes->dev, r->start, resource_size(r)); ++ if(IS_ERR_OR_NULL(aes->io_base)) { ++ dev_err(&pdev->dev, "Failed to remap io resources!\n"); ++ ret = -ENOMEM; ++ goto err; ++ } ++ ++ aes->irq = platform_get_irq(pdev,0); ++ if(aes->irq < 0){ ++ dev_err(dev,"Failed to request irq resource info\n"); ++ ret = -EBUSY; ++ goto err; ++ } ++ ++ err = request_threaded_irq(aes->irq,NULL,ingenic_aec_irqthread, ++ IRQF_ONESHOT,dev_name(dev),aes); ++ ++ aes->pdata = &ingenic_aes_pdata; ++ ++err: ++ return ret; ++} ++static noinline void pdma_wait(void) ++{ ++ __asm__ volatile ( ++ " .set push \n\t" ++ " .set noreorder \n\t" ++ " .set mips32 \n\t" ++ " li $26, 0 \n\t" ++ " mtc0 $26, $12 \n\t" ++ " nop \n\t" ++ "1: \n\t" ++ " wait \n\t" ++ " b 1b \n\t" ++ " nop \n\t" ++ " .set reorder \n\t" ++ " .set pop \n\t" ++ ); ++} ++ ++static int ingenic_aes_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct ingenic_aes_dev *aes; ++ struct crypto_alg *algp; ++ int err = -ENOMEM, i; ++ ++ aes = devm_kzalloc(dev,sizeof(struct ingenic_aes_dev), GFP_KERNEL); ++ if (aes == NULL) { ++ dev_err(dev, "unable to alloc data struct.\n"); ++ goto err_data; ++ } ++ aes->dev = dev; ++ aes->clk_gate = devm_clk_get(&pdev->dev, "gate_aes"); ++ if (IS_ERR(aes->clk_gate)) { ++ dev_err(&pdev->dev, "cannot find RTC clock\n"); ++ err = PTR_ERR(aes->clk_gate); ++ goto err_data; ++ } ++ ++ clk_prepare_enable(aes->clk_gate); ++ aes->clk_gate = devm_clk_get(&pdev->dev, "gate_pdma"); ++ if (IS_ERR(aes->clk_gate)) { ++ dev_err(&pdev->dev, "cannot find aes clock\n"); ++ err = PTR_ERR(aes->clk_gate); ++ goto err_data; ++ } ++ ++ clk_prepare_enable(aes->clk_gate); ++ printk("gate = %x\n", *(unsigned long*)0xb0000020); ++ ++ platform_set_drvdata(pdev, aes); ++ ++ reset_mcu(); ++ memcpy((void*)MCU_BOOT,pdma_wait,64); ++ boot_up_mcu(); ++ ++ mdelay(100); ++ /* *(unsigned long*)0xb3421030 = 1; */ ++ ++ spin_lock_init(&aes->lock); ++ crypto_init_queue(&aes->queue, INGENIC_AES_QUEUE_LENGTH); ++ ++ err = ingenic_aes_get_res_pdev(aes, pdev); ++ if (err) ++ goto err_data; ++ ++ err = ingenic_aes_dma_init(aes); ++ if (err) ++ goto err_data; ++ ++ INIT_LIST_HEAD(&aes->list); ++ spin_lock(&list_lock); ++ list_add_tail(&aes->list, &dev_list); ++ spin_unlock(&list_lock); ++ for (i = 0; i < aes->pdata->size; i++) { ++ algp = &aes->pdata->algs_list[i]; ++ pr_info("reg alg: %s\n", algp->cra_name); ++ err = crypto_register_alg(algp); ++ if (err) ++ goto err_algs; ++ aes->pdata->registered++; ++ } ++ printk("ingenic aes[%d] register ok.",aes->pdata->registered); ++ return 0; ++err_algs: ++ for (i = aes->pdata->registered - 1; i >= 0; i--) ++ crypto_unregister_alg( ++ &aes->pdata->algs_list[i]); ++ ingenic_aes_dma_cleanup(aes); ++err_data: ++ dev_err(dev, "initialization failed.\n"); ++ return err; ++} ++ ++static int ingenic_aes_remove(struct platform_device *pdev) ++{ ++ struct ingenic_aes_dev *aes = platform_get_drvdata(pdev); ++ int i; ++ ++ if (!aes) ++ return -ENODEV; ++ ++ spin_lock(&list_lock); ++ list_del(&aes->list); ++ spin_unlock(&list_lock); ++ for (i = aes->pdata->registered - 1; i >= 0; i--) ++ crypto_unregister_alg( ++ &aes->pdata->algs_list[i]); ++ aes->pdata->registered = 0; ++ ingenic_aes_dma_cleanup(aes); ++ pm_runtime_disable(aes->dev); ++ kfree(aes); ++ aes = NULL; ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int ingenic_aes_suspend(struct device *dev) ++{ ++ pm_runtime_put_sync(dev); ++ return 0; ++} ++ ++static int ingenic_aes_resume(struct device *dev) ++{ ++ pm_runtime_get_sync(dev); ++ return 0; ++} ++#endif ++ ++static const struct dev_pm_ops ingenic_aes_pm_ops = { ++ SET_SYSTEM_SLEEP_PM_OPS(ingenic_aes_suspend, ingenic_aes_resume) ++}; ++ ++static const struct of_device_id ingenic_aes_dt_match[] = { ++ { .compatible = "ingenic,aes", .data = NULL }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, aic_dt_match); ++ ++ ++static struct platform_driver ingenic_aes_driver = { ++ .probe = ingenic_aes_probe, ++ .remove = ingenic_aes_remove, ++ .driver = { ++ .name = "aes", ++ .owner = THIS_MODULE, ++ .pm = &ingenic_aes_pm_ops, ++ .of_match_table = of_match_ptr(ingenic_aes_dt_match), ++ }, ++}; ++ ++module_platform_driver(ingenic_aes_driver); ++ ++MODULE_DESCRIPTION("Ingenic AES hw acceleration support."); ++MODULE_LICENSE("GPL v2"); ++MODULE_AUTHOR("Stephon.Qiu"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_crypto_ingenic-aes.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_crypto_ingenic-aes.h.patch new file mode 100644 index 00000000..14273f29 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_crypto_ingenic-aes.h.patch @@ -0,0 +1,116 @@ +diff -drupN a/drivers/crypto/ingenic-aes.h b/drivers/crypto/ingenic-aes.h +--- a/drivers/crypto/ingenic-aes.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/crypto/ingenic-aes.h 2022-06-09 05:02:28.000000000 +0300 +@@ -0,0 +1,112 @@ ++#ifndef __INGENIC_AES_H__ ++#define __INGENIC_AES_H__ ++ ++#define INGENIC_AES_QUEUE_LENGTH (50) ++#define INGENIC_AES_CACHE_PAGE_SHIFT (0) ++#define DMA_MIN 4 ++ ++#define AES_ASCR (0x00) ++#define AES_ASSR (0x04) ++#define AES_ASINTM (0x08) ++#define AES_ASSA (0x0c) ++#define AES_ASDA (0x10) ++#define AES_ASTC (0x14) ++#define AES_ASDI (0x18) ++#define AES_ASDO (0x1c) ++#define AES_ASKY (0x20) ++#define AES_ASIV (0x24) ++ ++#define ASCR_PS_DEF (3 << 28) ++#define ASCR_CLR (1 << 10) ++ ++#define ASCR_DMAS (1 << 9) ++#define ASCR_DMAE (1 << 8) ++ ++#define ASCR_KEYL(len) ((len) << 6) ++ ++#define ECB_ALG (0) ++#define CBC_ALG (1) ++#define ASCR_ALGS(alg) ((alg) << 5) ++ ++#define ENCRYPTO_MODE (0) ++#define DECRYPTO_MODE (1) ++#define ASCR_DECE(m) ((m) << 4) ++ ++ ++#define ASCR_AESS (1 << 3) ++#define ASCR_KEYS (1 << 2) ++#define ASCR_INIT_IV (1 << 1) ++#define ASCR_EN (1 << 0) ++ ++struct ingenic_aes_reqctx { ++ unsigned long mode; ++}; ++ ++struct ingenic_aes_ctx { ++ struct ingenic_aes_dev *aes; ++ ++ int keylen; ++ unsigned long key[AES_KEYSIZE_256 / sizeof(unsigned long)]; ++ unsigned long flags; ++}; ++ ++/* struct ingenic_aes_algs_info { */ ++/* struct crypto_alg *algs_list; */ ++/* unsigned int size; */ ++/* unsigned int registered; */ ++/* }; */ ++struct ingenic_aes_pdata { ++ struct crypto_alg *algs_list; ++ unsigned int size; ++ unsigned int registered; ++}; ++ ++struct ingenic_aes_dev { ++ struct list_head list; ++ void __iomem *io_base; ++ int irq; ++ struct clk *clk_gate; ++ struct ingenic_aes_ctx *ctx; ++ struct device *dev; ++ unsigned long flags; ++ int err; ++ ++ spinlock_t lock; ++ struct crypto_queue queue; ++ struct ablkcipher_request *req; ++ size_t total; ++ ++ struct scatterlist *in_sg; ++ ++ struct scatterlist in_sgl; ++ size_t in_offset; ++ struct scatterlist *out_sg; ++ struct scatterlist out_sgl; ++ size_t out_offset; ++ ++ size_t buflen; ++ void *buf_in; ++ void *buf_out; ++ dma_addr_t dma_addr_in; ++ dma_addr_t dma_addr_out; ++ ++ size_t dma_size; ++ struct ingenic_aes_pdata *pdata; ++}; ++ ++ ++#define FLAGS_MODE_MASK 0x000f ++#define FLAGS_DECRYPT BIT(0) ++#define FLAGS_CBC BIT(1) ++ ++#define FLAGS_INIT BIT(4) ++#define FLAGS_FAST BIT(5) ++#define FLAGS_BUSY BIT(6) ++ ++#define MCU_BOOT 0xb3422000 ++ ++#define DMCS 0xb3421030 ++#define boot_up_mcu() *(volatile unsigned int *)(DMCS) = 0; ++#define reset_mcu() *(volatile unsigned int *)(DMCS) = 1; ++ ++#endif /*__INGENIC_AES_H__*/ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_crypto_ingenic-hash.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_crypto_ingenic-hash.c.patch new file mode 100644 index 00000000..db601fa3 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_crypto_ingenic-hash.c.patch @@ -0,0 +1,1088 @@ +diff -drupN a/drivers/crypto/ingenic-hash.c b/drivers/crypto/ingenic-hash.c +--- a/drivers/crypto/ingenic-hash.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/crypto/ingenic-hash.c 2022-06-09 05:02:28.000000000 +0300 +@@ -0,0 +1,1084 @@ ++/* ++ * Cryptographic API. ++ * ++ * Support for Ingenic HASH HW acceleration. ++ * ++ * 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. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "ingenic-hash.h" ++ ++ ++/* keep registered devices data here */ ++static LIST_HEAD(dev_list); ++static DEFINE_SPINLOCK(list_lock); ++ ++ ++static inline unsigned long hash_read(struct ingenic_hash_dev *hash, unsigned long offset) ++{ ++ return readl(hash->io_base + offset); ++} ++ ++static inline void hash_write(struct ingenic_hash_dev *hash, unsigned long offset, ++ unsigned long value) ++{ ++ writel(value, hash->io_base + offset); ++} ++ ++static inline void dump_reg(struct ingenic_hash_dev *hash) ++{ ++ dev_info(hash->dev,"HASH_HSCR: 0x%08lx\n",hash_read(hash,HASH_HSCR)); ++ dev_info(hash->dev,"HASH_HSSR: 0x%08lx\n",hash_read(hash,HASH_HSSR)); ++ dev_info(hash->dev,"hash_ASINTM: 0x%08lx\n",hash_read(hash,HASH_HSINTM)); ++ dev_info(hash->dev,"HASH_HSSA: 0x%08lx\n",hash_read(hash,HASH_HSSA)); ++ dev_info(hash->dev,"HASH_HSTC: 0x%08lx\n",hash_read(hash,HASH_HSTC)); ++} ++static inline int ingenic_hash_hw_init(struct ingenic_hash_dev *hash,struct ingenic_hash_reqctx *ctx) ++{ ++ /* ++ * clocks are enabled when request starts and disabled when finished. ++ * It may be long delays between requests. ++ * Device might go to off mode to save power. ++ */ ++ unsigned int alg = -1; ++ unsigned int init_data = 0; ++ pm_runtime_get_sync(hash->dev); ++ ++ if(ctx->flags & HASH_FLAGS_MD5){ ++ alg = 0; ++ init_data = 0; ++ }else if(ctx->flags & HASH_FLAGS_SHA1) ++ { ++ init_data = 3 << 7; ++ alg = 1; ++ }else if(ctx->flags & HASH_FLAGS_SHA224) ++ { ++ init_data = 3 << 7; ++ alg = 2; ++ }else if(ctx->flags & HASH_FLAGS_SHA256) ++ { ++ init_data = 3 << 7; ++ alg = 3; ++ }else if(ctx->flags & HASH_FLAGS_SHA384) ++ { ++ init_data = 3 << 7; ++ alg = 4; ++ }else if(ctx->flags & HASH_FLAGS_SHA512) ++ { ++ init_data = 3 << 7; ++ alg = 5; ++ } ++ init_data |= 3 << 28 | 1 << 4 | alg << 1 | 1; ++ hash_write(hash, HASH_HSCR,init_data); ++ hash_write(hash,HASH_HSINTM,0); ++ hash->flags |= HASH_FLAGS_INIT; ++ return 0; ++} ++static int ingenic_hash_update_dma_stop(struct ingenic_hash_dev *hash) ++{ ++ struct ingenic_hash_reqctx *ctx = ahash_request_ctx(hash->req); ++ ++ if (ctx->flags & HASH_FLAGS_SG) { ++ dma_unmap_sg(hash->dev, ctx->sg, 1, DMA_TO_DEVICE); ++ if (ctx->sg->length == ctx->offset) { ++ ctx->sg = sg_next(ctx->sg); ++ if (ctx->sg) ++ ctx->offset = 0; ++ } ++ if (ctx->flags & HASH_FLAGS_PAD) { ++ dma_unmap_single(hash->dev, ctx->dma_addr, ++ ctx->buflen + ctx->block_size, DMA_TO_DEVICE); ++ } ++ } else { ++ dma_unmap_single(hash->dev, ctx->dma_addr, ctx->buflen + ++ ctx->block_size, DMA_TO_DEVICE); ++ } ++ ++ return 0; ++} ++static void ingenic_hash_copy_hash(struct ahash_request *req) ++{ ++ struct ingenic_hash_reqctx *ctx = ahash_request_ctx(req); ++ u32 *hash = (u32 *)ctx->digest; ++ int i; ++ if(ctx->flags & HASH_FLAGS_MD5){ ++ for (i = 0; i < MD5_DIGEST_SIZE / sizeof(u32); i++) ++ hash[i] = hash_read(ctx->hash, HASH_HSDO); ++ }else if (ctx->flags & HASH_FLAGS_SHA1) ++ for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(u32); i++) ++ hash[i] = hash_read(ctx->hash, HASH_HSDO); ++ else if (ctx->flags & HASH_FLAGS_SHA224) ++ for (i = 0; i < SHA224_DIGEST_SIZE / sizeof(u32); i++) ++ hash[i] = hash_read(ctx->hash, HASH_HSDO); ++ else if (ctx->flags & HASH_FLAGS_SHA256) ++ for (i = 0; i < SHA256_DIGEST_SIZE / sizeof(u32); i++) ++ hash[i] = hash_read(ctx->hash, HASH_HSDO); ++ else if (ctx->flags & HASH_FLAGS_SHA384) ++ for (i = 0; i < SHA384_DIGEST_SIZE / sizeof(u32); i++) ++ hash[i] = hash_read(ctx->hash, HASH_HSDO); ++ else ++ for (i = 0; i < SHA512_DIGEST_SIZE / sizeof(u32); i++) ++ hash[i] = hash_read(ctx->hash, HASH_HSDO); ++} ++ ++static void ingenic_hash_copy_ready_hash(struct ahash_request *req) ++{ ++ struct ingenic_hash_reqctx *ctx = ahash_request_ctx(req); ++ if (!req->result) ++ return; ++ if (ctx->flags & HASH_FLAGS_MD5) ++ memcpy(req->result, ctx->digest, MD5_DIGEST_SIZE); ++ if (ctx->flags & HASH_FLAGS_SHA1) ++ memcpy(req->result, ctx->digest, SHA1_DIGEST_SIZE); ++ else if (ctx->flags & HASH_FLAGS_SHA224) ++ memcpy(req->result, ctx->digest, SHA224_DIGEST_SIZE); ++ else if (ctx->flags & HASH_FLAGS_SHA256) ++ memcpy(req->result, ctx->digest, SHA256_DIGEST_SIZE); ++ else if (ctx->flags & HASH_FLAGS_SHA384) ++ memcpy(req->result, ctx->digest, SHA384_DIGEST_SIZE); ++ else ++ memcpy(req->result, ctx->digest, SHA512_DIGEST_SIZE); ++} ++ ++static int ingenic_hash_finish(struct ahash_request *req) ++{ ++ struct ingenic_hash_reqctx *ctx = ahash_request_ctx(req); ++ struct ingenic_hash_dev *hash = ctx->hash; ++ int err = 0; ++ ++ if (ctx->digcnt[0] || ctx->digcnt[1]) ++ ingenic_hash_copy_ready_hash(req); ++ ++ dev_dbg(hash->dev, "digcnt: 0x%llx 0x%llx, bufcnt: %d\n", ctx->digcnt[1], ++ ctx->digcnt[0], ctx->bufcnt); ++ ++ return err; ++} ++static void ingenic_hash_finish_req(struct ahash_request *req, int err) ++{ ++ struct ingenic_hash_reqctx *ctx = ahash_request_ctx(req); ++ struct ingenic_hash_dev *hash = ctx->hash; ++ if(ctx->bufcnt == 0){ ++ if (!err) { ++ ingenic_hash_copy_hash(req); ++ if (HASH_FLAGS_FINAL & hash->flags) ++ err = ingenic_hash_finish(req); ++ } else { ++ ctx->flags |= HASH_FLAGS_ERROR; ++ } ++ ++ /* atomic operation is not needed here */ ++ hash->flags &= ~(HASH_FLAGS_BUSY | HASH_FLAGS_FINAL | HASH_FLAGS_INIT); ++ pm_runtime_put_sync(hash->dev); ++ } ++ /* clk_disable_unprepare(hash->iclk); */ ++ if (req->base.complete) ++ req->base.complete(&req->base, err); ++} ++ ++static struct ingenic_hash_dev *ingenic_hash_find_dev(struct ingenic_hash_ctx *ctx) ++{ ++ struct ingenic_hash_dev *hash = NULL, *tmp; ++ ++ spin_lock(&list_lock); ++ hash = ctx->hash; ++ if (!hash) { ++ list_for_each_entry(tmp, &dev_list, list) { ++ /* FIXME: take fist available hash core */ ++ hash = tmp; ++ ctx->hash = tmp; ++ break; ++ } ++ } ++ spin_unlock(&list_lock); ++ return hash; ++} ++/* ++ * The purpose of this padding is to ensure that the padded message is a ++ * multiple of 512 bits (SHA1/SHA224/SHA256) or 1024 bits (SHA384/SHA512). ++ * The bit "1" is appended at the end of the message followed by ++ * "padlen-1" zero bits. Then a 64 bits block (SHA1/SHA224/SHA256) or ++ * 128 bits block (SHA384/SHA512) equals to the message length in bits ++ * is appended. ++ * ++ * For SHA1/SHA224/SHA256, padlen is calculated as followed: ++ * - if message length < 56 bytes then padlen = 56 - message length ++ * - else padlen = 64 + 56 - message length ++ * ++ * For SHA384/SHA512, padlen is calculated as followed: ++ * - if message length < 112 bytes then padlen = 112 - message length ++ * - else padlen = 128 + 112 - message length ++ */ ++static void ingenic_hash_fill_padding(struct ingenic_hash_reqctx *ctx, int length) ++{ ++ ++ unsigned int index, padlen; ++ u64 bits[2]; ++ u64 size[2]; ++ ++ size[0] = ctx->digcnt[0]; ++ size[1] = ctx->digcnt[1]; ++ ++ size[0] += ctx->bufcnt; ++ if (size[0] < ctx->bufcnt) ++ size[1]++; ++ ++ size[0] += length; ++ if (size[0] < length) ++ size[1]++; ++ ++ bits[1] = cpu_to_be64(size[0] << 3); ++ bits[0] = cpu_to_be64(size[1] << 3 | size[0] >> 61); ++ if (ctx->flags & (HASH_FLAGS_SHA384 | HASH_FLAGS_SHA512)) { ++ index = ctx->bufcnt & 0x7f; ++ padlen = (index < 112) ? (112 - index) : ((128+112) - index); ++ *(ctx->buffer + ctx->bufcnt) = 0x80; ++ memset(ctx->buffer + ctx->bufcnt + 1, 0, padlen-1); ++ memcpy(ctx->buffer + ctx->bufcnt + padlen, bits, 16); ++ ctx->bufcnt += padlen + 16; ++ ctx->flags |= HASH_FLAGS_PAD; ++ } else if(ctx->flags & HASH_FLAGS_MD5){ ++ unsigned int *d; ++ index = ctx->bufcnt & 0x3f; ++ padlen = (index < 56) ? (56 - index) : ((64+56) - index); ++ *(ctx->buffer + ctx->bufcnt) = 0x80; ++ memset(ctx->buffer + ctx->bufcnt + 1, 0, padlen-1); ++ d = (unsigned int *)((unsigned char*)ctx->buffer + ctx->bufcnt + padlen); ++ d[0] = cpu_to_le32(size[0] << 3); ++ d[1] = cpu_to_le32(size[0] >> 29); ++ //memcpy(ctx->buffer + ctx->bufcnt + padlen + 1, &bits1[1], 4); ++ ctx->bufcnt += padlen + 8; ++ ctx->flags |= HASH_FLAGS_PAD; ++ }else { ++ index = ctx->bufcnt & 0x3f; ++ padlen = (index < 56) ? (56 - index) : ((64+56) - index); ++ *(ctx->buffer + ctx->bufcnt) = 0x80; ++ memset(ctx->buffer + ctx->bufcnt + 1, 0, padlen-1); ++ memcpy(ctx->buffer + ctx->bufcnt + padlen, &bits[1], 8); ++ ctx->bufcnt += padlen + 8; ++ ctx->flags |= HASH_FLAGS_PAD; ++ } ++ /* for(int i = 0;i < 64/4;i++){ */ ++ /* unsigned int *d = ctx->buffer; */ ++ /* d +=(ctx->bufcnt - 64) / sizeof(unsigned int); */ ++ /* printk("buffer[%p]%03d: 0x%08x\n",d+i,i,d[i]); */ ++ /* } */ ++} ++ ++static size_t ingenic_hash_append_sg(struct ingenic_hash_reqctx *ctx) ++{ ++ size_t count; ++ ++ while ((ctx->bufcnt < ctx->buflen) && ctx->total) { ++ count = min(ctx->sg->length - ctx->offset, ctx->total); ++ count = min(count, ctx->buflen - ctx->bufcnt); ++ ++ if (count <= 0) ++ break; ++ ++ scatterwalk_map_and_copy(ctx->buffer + ctx->bufcnt, ctx->sg, ++ ctx->offset, count, 0); ++ ++ ctx->bufcnt += count; ++ ctx->offset += count; ++ ctx->total -= count; ++ ++ if (ctx->offset == ctx->sg->length) { ++ ctx->sg = sg_next(ctx->sg); ++ if (ctx->sg) ++ ctx->offset = 0; ++ else ++ ctx->total = 0; ++ } ++ } ++ return 0; ++} ++static int ingenic_hash_xmit_start(struct ingenic_hash_dev *hash, dma_addr_t dma_addr, ++ size_t length, int final) ++{ ++ struct ingenic_hash_reqctx *ctx = ahash_request_ctx(hash->req); ++ ctx->digcnt[0] += length; ++ if (ctx->digcnt[0] < length) ++ ctx->digcnt[1]++; ++ ++ if (final) ++ hash->flags |= HASH_FLAGS_FINAL; ++ hash->flags |= HASH_FLAGS_DMA_ACTIVE; ++ hash_write(hash,HASH_HSSA,dma_addr); ++ hash_write(hash, HASH_HSTC, length / (512 / 8)); ++ ++ hash_write(hash, HASH_HSINTM,2); ++// dump_reg(hash); ++ { ++ unsigned int val; ++ val = hash_read(hash, HASH_HSCR); ++ hash_write(hash, HASH_HSCR, val | (3 << 5)); ++ } ++ return -EINPROGRESS; ++} ++ ++static int ingenic_hash_xmit_dma_map(struct ingenic_hash_dev *hash, ++ struct ingenic_hash_reqctx *ctx, ++ size_t length, int final) ++{ ++ ctx->dma_addr = dma_map_single(hash->dev, ctx->buffer, ++ ctx->buflen + ctx->block_size, DMA_TO_DEVICE); ++ ++ if (dma_mapping_error(hash->dev, ctx->dma_addr)) { ++ dev_err(hash->dev, "dma %u bytes error\n", ctx->buflen + ++ ctx->block_size); ++ return -EINVAL; ++ } ++ ++ ctx->flags &= ~HASH_FLAGS_SG; ++ ++ /* next call does not fail... so no unmap in the case of error */ ++ return ingenic_hash_xmit_start(hash, ctx->dma_addr, length, final); ++} ++static int ingenic_hash_final_req(struct ingenic_hash_dev *hash) ++{ ++ struct ahash_request *req = hash->req; ++ struct ingenic_hash_reqctx *ctx = ahash_request_ctx(req); ++ int err = 0; ++ int count; ++ ++ ingenic_hash_fill_padding(ctx, 0); ++ count = ctx->bufcnt; ++ ctx->bufcnt = 0; ++ err = ingenic_hash_xmit_dma_map(hash, ctx, count, 1); ++ dev_dbg(hash->dev, "final_req: err: %d\n", err); ++ ++ return err; ++} ++ ++static int ingenic_hash_update_dma_slow(struct ingenic_hash_dev *hash) ++{ ++ struct ingenic_hash_reqctx *ctx = ahash_request_ctx(hash->req); ++ unsigned int final; ++ size_t count; ++ ++ ingenic_hash_append_sg(ctx); ++ ++ final = (ctx->flags & HASH_FLAGS_FINUP) && !ctx->total; ++ ++ dev_dbg(hash->dev, "slow: bufcnt: %u, digcnt: 0x%llx 0x%llx, final: %d\n", ++ ctx->bufcnt, ctx->digcnt[1], ctx->digcnt[0], final); ++ ++ if (final) ++ ingenic_hash_fill_padding(ctx, 0); ++ ++ if (final || (ctx->bufcnt == ctx->buflen && ctx->total)) { ++ count = ctx->bufcnt; ++ ctx->bufcnt = 0; ++ return ingenic_hash_xmit_dma_map(hash, ctx, count, final); ++ } ++ ++ return 0; ++} ++ ++ ++static int ingenic_hash_update_dma_start(struct ingenic_hash_dev *hash) ++{ ++ struct ingenic_hash_reqctx *ctx = ahash_request_ctx(hash->req); ++ unsigned int length, final, tail; ++ struct scatterlist *sg; ++ unsigned int count; ++ sg = ctx->sg; ++ if (!ctx->total && !ctx->bufcnt){ ++ return 0; ++ } ++ if(ctx->flags & HASH_FLAGS_FINUP) ++ { ++ if (ctx->bufcnt || ctx->offset) ++ return ingenic_hash_update_dma_slow(hash); ++ dev_dbg(hash->dev, "fast: digcnt: 0x%llx 0x%llx, bufcnt: %u, total: %u\n", ++ ctx->digcnt[1], ctx->digcnt[0], ctx->bufcnt, ctx->total); ++ ++ if (!IS_ALIGNED(sg->offset, sizeof(u32))) ++ return ingenic_hash_update_dma_slow(hash); ++ ++ if (!sg_is_last(sg) && !IS_ALIGNED(sg->length, ctx->block_size)){ ++ /* size is not ctx->block_size aligned */ ++ return ingenic_hash_update_dma_slow(hash); ++ } ++ } ++ length = min(ctx->total, sg->length); ++ if (sg_is_last(sg)) { ++ if (!(ctx->flags & HASH_FLAGS_FINUP)) ++ { ++ /* not last sg must be ctx->block_size aligned */ ++ tail = length & (ctx->block_size - 1); ++ length -= tail; ++ if(length == 0){ ++ ingenic_hash_append_sg(ctx); ++ hash->flags &= ~HASH_FLAGS_BUSY; ++ return 0; ++ } ++ }else if(length + ctx->bufcnt > ctx->buflen) ++ { ++ length = ctx->buflen - ctx->bufcnt; ++ } ++ } ++ final = (ctx->flags & HASH_FLAGS_FINUP) && !(ctx->total - length); ++ /* Add padding */ ++ if (final) { ++ ++ sg = ctx->sg; ++ ingenic_hash_append_sg(ctx); ++ ++ ingenic_hash_fill_padding(ctx, 0); ++ ++ ctx->dma_addr = dma_map_single(hash->dev, ctx->buffer, ++ ctx->buflen + ctx->block_size, DMA_TO_DEVICE); ++ ++ if (dma_mapping_error(hash->dev, ctx->dma_addr)) { ++ dev_err(hash->dev, "dma %u bytes error\n", ++ ctx->buflen + ctx->block_size); ++ return -EINVAL; ++ } ++ ++ if (ctx->bufcnt != 0) { ++ ctx->flags &= ~HASH_FLAGS_SG; ++ count = ctx->bufcnt; ++ ctx->bufcnt = 0; ++ return ingenic_hash_xmit_start(hash, ctx->dma_addr, count, final); ++ } ++ }else if(ctx->bufcnt && (ctx->flags & HASH_FLAGS_FINUP)){ ++ return ingenic_hash_update_dma_slow(hash); ++ }else{ ++ ctx->total -= length; ++ ctx->offset = length; /* offset where to start slow */ ++ } ++ ++ if (!dma_map_sg(hash->dev, ctx->sg, 1, DMA_TO_DEVICE)) { ++ dev_err(hash->dev, "dma_map_sg error\n"); ++ return -EINVAL; ++ } ++ ctx->flags |= HASH_FLAGS_SG; ++ ++ /* next call does not fail... so no unmap in the case of error */ ++ return ingenic_hash_xmit_start(hash, sg_dma_address(ctx->sg), length, final); ++} ++ ++static int ingenic_hash_update_req(struct ingenic_hash_dev *hash) ++{ ++ struct ahash_request *req = hash->req; ++ struct ingenic_hash_reqctx *ctx = ahash_request_ctx(req); ++ int err; ++ ++ dev_dbg(hash->dev, "update_req: total: %u, digcnt: 0x%llx 0x%llx\n", ++ ctx->total, ctx->digcnt[1], ctx->digcnt[0]); ++ ++ err = ingenic_hash_update_dma_start(hash); ++ ++ /* wait for dma completion before can take more data */ ++ dev_dbg(hash->dev, "update: err: %d, digcnt: 0x%llx 0%llx\n", ++ err, ctx->digcnt[1], ctx->digcnt[0]); ++ ++ return err; ++} ++static int ingenic_hash_handle_queue(struct ingenic_hash_dev *hash, ++ struct ahash_request *req) ++{ ++ struct crypto_async_request *async_req, *backlog; ++ struct ingenic_hash_reqctx *ctx; ++ unsigned long flags; ++ int err = 0, ret = 0; ++ spin_lock_irqsave(&hash->lock, flags); ++ if (req) ++ ret = ahash_enqueue_request(&hash->queue, req); ++ ++ if (HASH_FLAGS_BUSY & hash->flags) { ++ spin_unlock_irqrestore(&hash->lock, flags); ++ return ret; ++ } ++ ++ backlog = crypto_get_backlog(&hash->queue); ++ async_req = crypto_dequeue_request(&hash->queue); ++ if (async_req) ++ hash->flags |= HASH_FLAGS_BUSY; ++ ++ spin_unlock_irqrestore(&hash->lock, flags); ++ ++ if (!async_req) ++ return ret; ++ ++ if (backlog) ++ backlog->complete(backlog, -EINPROGRESS); ++ ++ req = ahash_request_cast(async_req); ++ hash->req = req; ++ ctx = ahash_request_ctx(req); ++ ++ dev_dbg(hash->dev, "handling new req, op: %lu, nbytes: %d\n", ++ ctx->op, req->nbytes); ++ ++ if(!(hash->flags & HASH_FLAGS_INIT)){ ++ err = ingenic_hash_hw_init(hash,ctx); ++ if (err) ++ goto err1; ++ } ++ /* if (ctx->op == HASH_OP_UPDATE) { */ ++ err = ingenic_hash_update_req(hash); ++ /* if (err != -EINPROGRESS && (ctx->flags & HASH_FLAGS_FINUP)) */ ++ /* /\* no final() after finup() *\/ */ ++ /* err = ingenic_hash_final_req(hash); */ ++ /* } else if (ctx->op == HASH_OP_FINAL) { */ ++ /* err = ingenic_hash_final_req(hash); */ ++ /* } */ ++err1: ++ return err; ++#if 0 ++err1: ++ if (err != -EINPROGRESS) ++ /* done_task will not finish it, so do it here */ ++ ingenic_hash_finish_req(req, err); ++ ++ dev_dbg(hash->dev, "exit, err: %d\n", err); ++ ++ return err; ++#endif ++} ++ ++static int ingenic_hash_enqueue(struct ahash_request *req, unsigned int op) ++{ ++ struct ingenic_hash_reqctx *ctx = ahash_request_ctx(req); ++ struct ingenic_hash_ctx *tctx = crypto_tfm_ctx(req->base.tfm); ++ struct ingenic_hash_dev *hash = tctx->hash; ++ ++ ctx->op = op; ++ ++ return ingenic_hash_handle_queue(hash, req); ++} ++static void hash_dma_done(struct ingenic_hash_dev *hash) ++{ ++ int err = 0; ++ if (HASH_FLAGS_DMA_ACTIVE & hash->flags) { ++ hash->flags &= ~HASH_FLAGS_DMA_ACTIVE; ++ ingenic_hash_update_dma_stop(hash); ++ } ++ err = ingenic_hash_update_dma_start(hash); ++ if (err != -EINPROGRESS){ ++ ingenic_hash_finish_req(hash->req, err); ++ }else if (!(HASH_FLAGS_BUSY & hash->flags)) { ++ ingenic_hash_handle_queue(hash, NULL); ++ } ++} ++static irqreturn_t ingenic_hash_irqthread(int irq, void *data) ++{ ++ struct ingenic_hash_dev *hash = (struct ingenic_hash_dev *)data; ++ unsigned int val; ++ val = hash_read(hash,HASH_HSSR); ++ hash_write(hash,HASH_HSSR,val); ++ if(val & 2){ ++ hash_dma_done(hash); ++ }else{ ++ printk("Don't support the irq"); ++ } ++ return IRQ_HANDLED; ++} ++ ++/* ********************** ALG API ************************************ */ ++ ++static int ingenic_hash_init(struct ahash_request *req) ++{ ++ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); ++ struct ingenic_hash_ctx *ctx = crypto_ahash_ctx(tfm); ++ struct ingenic_hash_reqctx *rctx = ahash_request_ctx(req); ++ struct ingenic_hash_dev *hash = NULL; ++ /* struct ingenic_hash_dev *tmp; */ ++ ENTER(); ++ hash = ingenic_hash_find_dev(ctx); ++ ++ rctx->hash = hash; ++ rctx->flags = 0; ++ dev_dbg(hash->dev, "init: digest size: %d\n", ++ crypto_ahash_digestsize(tfm)); ++ ++ switch (crypto_ahash_digestsize(tfm)) { ++ case MD5_DIGEST_SIZE: ++ rctx->flags |= HASH_FLAGS_MD5; ++ rctx->block_size = MD5_BLOCK_SIZE; ++ case SHA1_DIGEST_SIZE: ++ rctx->flags |= HASH_FLAGS_SHA1; ++ rctx->block_size = SHA1_BLOCK_SIZE; ++ break; ++ case SHA224_DIGEST_SIZE: ++ rctx->flags |= HASH_FLAGS_SHA224; ++ rctx->block_size = SHA224_BLOCK_SIZE; ++ break; ++ case SHA256_DIGEST_SIZE: ++ rctx->flags |= HASH_FLAGS_SHA256; ++ rctx->block_size = SHA256_BLOCK_SIZE; ++ break; ++ case SHA384_DIGEST_SIZE: ++ rctx->flags |= HASH_FLAGS_SHA384; ++ rctx->block_size = SHA384_BLOCK_SIZE; ++ break; ++ case SHA512_DIGEST_SIZE: ++ rctx->flags |= HASH_FLAGS_SHA512; ++ rctx->block_size = SHA512_BLOCK_SIZE; ++ break; ++ default: ++ return -EINVAL; ++ break; ++ } ++ rctx->bufcnt = 0; ++ rctx->total = 0; ++ rctx->digcnt[0] = 0; ++ rctx->digcnt[1] = 0; ++ rctx->buflen = HASH_BUFFER_LEN; ++ EXIT(); ++ ++ return 0; ++} ++static int ingenic_hash_final(struct ahash_request *req) ++{ ++ struct ingenic_hash_reqctx *ctx = ahash_request_ctx(req); ++ struct ingenic_hash_ctx *tctx = crypto_tfm_ctx(req->base.tfm); ++ struct ingenic_hash_dev *hash = tctx->hash; ++ ++ int err = 0; ++ ENTER(); ++ ctx->flags |= HASH_FLAGS_FINUP; ++ if (ctx->flags & HASH_FLAGS_ERROR){ ++ EXIT(); ++ return 0; /* uncompleted hash is not needed */ ++ } ++ if (ctx->bufcnt) { ++ err = ingenic_hash_enqueue(req, HASH_OP_FINAL); ++ EXIT(); ++ return err; ++ } else if (!(ctx->flags & HASH_FLAGS_PAD)) { /* add padding */ ++ err = ingenic_hash_hw_init(hash,ctx); ++ if (err) ++ goto err1; ++ hash->req = req; ++ hash->flags |= HASH_FLAGS_BUSY; ++ err = ingenic_hash_final_req(hash); ++ } else { ++ /* copy ready hash (+ finalize hmac) */ ++ return ingenic_hash_finish(req); ++ } ++err1: ++ if (err != -EINPROGRESS) ++ /* done_task will not finish it, so do it here */ ++ ingenic_hash_finish_req(req, err); ++ EXIT(); ++ return err; ++} ++ ++static int ingenic_hash_update(struct ahash_request *req) ++{ ++ struct ingenic_hash_reqctx *ctx = ahash_request_ctx(req); ++ int ret; ++ ENTER(); ++ if (!req->nbytes){ ++ EXIT(); ++ return 0; ++ } ++ ++ ctx->total = req->nbytes; ++ ctx->sg = req->src; ++ ++ ctx->offset = 0; ++ if (ctx->bufcnt + ctx->total < ctx->buflen) { ++ ingenic_hash_append_sg(ctx); ++ return 0; ++ } ++ ret = ingenic_hash_enqueue(req, HASH_OP_UPDATE); ++ EXIT(); ++ return ret; ++} ++ ++static int ingenic_hash_finup(struct ahash_request *req) ++{ ++ struct ingenic_hash_reqctx *ctx = ahash_request_ctx(req); ++ int err1, err2; ++ ENTER(); ++ ctx->flags |= HASH_FLAGS_FINUP; ++ ++ err1 = ingenic_hash_update(req); ++ if (err1 == -EINPROGRESS || err1 == -EBUSY) ++ return err1; ++ ++ /* ++ * final() has to be always called to cleanup resources ++ * even if udpate() failed, except EINPROGRESS ++ */ ++ err2 = ingenic_hash_final(req); ++ EXIT(); ++ return err1 ?: err2; ++} ++ ++static int ingenic_hash_digest(struct ahash_request *req) ++{ ++ return ingenic_hash_init(req) ?: ingenic_hash_finup(req); ++} ++ ++static int ingenic_hash_cra_init_alg(struct crypto_tfm *tfm, const char *alg_base) ++{ ++// struct ingenic_hash_ctx *tctx = crypto_tfm_ctx(tfm); ++// const char *alg_name = crypto_tfm_alg_name(tfm); ++// ENTER(); ++// /* Allocate a fallback and abort if it failed. */ ++// tctx->fallback = crypto_alloc_shash(alg_name, 0, ++// CRYPTO_ALG_NEED_FALLBACK); ++// if (IS_ERR(tctx->fallback)) { ++// pr_err("ingenic-hash: fallback driver '%s' could not be loaded.\n", ++// alg_name); ++// EXIT(); ++// return PTR_ERR(tctx->fallback); ++// } ++ crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), ++ sizeof(struct ingenic_hash_reqctx) + ++ HASH_BUFFER_LEN + SHA512_BLOCK_SIZE); ++ EXIT(); ++ return 0; ++} ++ ++static int ingenic_hash_cra_init(struct crypto_tfm *tfm) ++{ ++ return ingenic_hash_cra_init_alg(tfm, NULL); ++} ++ ++static void ingenic_hash_cra_exit(struct crypto_tfm *tfm) ++{ ++ struct ingenic_hash_ctx *tctx = crypto_tfm_ctx(tfm); ++ ENTER(); ++ crypto_free_shash(tctx->fallback); ++ tctx->fallback = NULL; ++ EXIT(); ++} ++ ++ ++/* ********************** ALGS ************************************ */ ++static struct ahash_alg hash_md5_algs[] = { ++#if 0 ++ { ++ .init = ingenic_hash_init, ++ .update = ingenic_hash_update, ++ .final = ingenic_hash_final, ++ .finup = ingenic_hash_finup, ++ .digest = ingenic_hash_digest, ++ .halg = { ++ .digestsize = MD5_DIGEST_SIZE, ++ .statesize = 1, ++ .base = { ++ .cra_name = "md5", ++ .cra_driver_name= "ingenic-sha1", ++ .cra_priority = 100, ++ .cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, ++ .cra_blocksize = MD5_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct ingenic_hash_ctx), ++ .cra_alignmask = 0, ++ .cra_module = THIS_MODULE, ++ .cra_init = ingenic_hash_cra_init, ++ .cra_exit = ingenic_hash_cra_exit, ++ } ++ } ++ }, ++#endif ++ { ++ .init = ingenic_hash_init, ++ .update = ingenic_hash_update, ++ .final = ingenic_hash_final, ++ .finup = ingenic_hash_finup, ++ .digest = ingenic_hash_digest, ++ .halg = { ++ .digestsize = SHA1_DIGEST_SIZE, ++ .statesize = 1, ++ .base = { ++ .cra_name = "sha1", ++ .cra_driver_name = "ingenic-sha1", ++ .cra_priority = 100, ++ .cra_flags = CRYPTO_ALG_ASYNC, ++ .cra_blocksize = SHA1_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct ingenic_hash_ctx), ++ .cra_alignmask = 0, ++ .cra_module = THIS_MODULE, ++ .cra_init = ingenic_hash_cra_init, ++ .cra_exit = ingenic_hash_cra_exit, ++ } ++ } ++ }, ++ { ++ .init = ingenic_hash_init, ++ .update = ingenic_hash_update, ++ .final = ingenic_hash_final, ++ .finup = ingenic_hash_finup, ++ .digest = ingenic_hash_digest, ++ .halg = { ++ .digestsize = SHA224_DIGEST_SIZE, ++ .statesize = 1, ++ .base = { ++ .cra_name = "sha224", ++ .cra_driver_name = "ingenic-sha224", ++ .cra_priority = 100, ++ .cra_flags = CRYPTO_ALG_ASYNC, ++ .cra_blocksize = SHA224_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct ingenic_hash_ctx), ++ .cra_alignmask = 0, ++ .cra_module = THIS_MODULE, ++ .cra_init = ingenic_hash_cra_init, ++ .cra_exit = ingenic_hash_cra_exit, ++ } ++ } ++ }, ++ { ++ .init = ingenic_hash_init, ++ .update = ingenic_hash_update, ++ .final = ingenic_hash_final, ++ .finup = ingenic_hash_finup, ++ .digest = ingenic_hash_digest, ++ .halg = { ++ .digestsize = SHA256_DIGEST_SIZE, ++ .statesize = 1, ++ .base = { ++ .cra_name = "sha256", ++ .cra_driver_name = "ingenic-sha256", ++ .cra_priority = 100, ++ .cra_flags = CRYPTO_ALG_ASYNC, ++ .cra_blocksize = SHA256_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct ingenic_hash_ctx), ++ .cra_alignmask = 0, ++ .cra_module = THIS_MODULE, ++ .cra_init = ingenic_hash_cra_init, ++ .cra_exit = ingenic_hash_cra_exit, ++ } ++ } ++ }, ++ { ++ .init = ingenic_hash_init, ++ .update = ingenic_hash_update, ++ .final = ingenic_hash_final, ++ .finup = ingenic_hash_finup, ++ .digest = ingenic_hash_digest, ++ .halg = { ++ .digestsize = SHA384_DIGEST_SIZE, ++ .statesize = 1, ++ .base = { ++ .cra_name = "sha384", ++ .cra_driver_name = "ingenic-sha384", ++ .cra_priority = 100, ++ .cra_flags = CRYPTO_ALG_ASYNC, ++ .cra_blocksize = SHA384_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct ingenic_hash_ctx), ++ .cra_alignmask = 0x3, ++ .cra_module = THIS_MODULE, ++ .cra_init = ingenic_hash_cra_init, ++ .cra_exit = ingenic_hash_cra_exit, ++ } ++ } ++ }, ++ { ++ .init = ingenic_hash_init, ++ .update = ingenic_hash_update, ++ .final = ingenic_hash_final, ++ .finup = ingenic_hash_finup, ++ .digest = ingenic_hash_digest, ++ .halg = { ++ .digestsize = SHA512_DIGEST_SIZE, ++ .statesize = 1, ++ .base = { ++ .cra_name = "sha512", ++ .cra_driver_name = "ingenic-sha512", ++ .cra_priority = 100, ++ .cra_flags = CRYPTO_ALG_ASYNC, ++ .cra_blocksize = SHA512_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct ingenic_hash_ctx), ++ .cra_alignmask = 0x3, ++ .cra_module = THIS_MODULE, ++ .cra_init = ingenic_hash_cra_init, ++ .cra_exit = ingenic_hash_cra_exit, ++ } ++ } ++ }, ++}; ++ ++static struct ingenic_hash_pdata ingenic_hash_pdata = { ++ .algs_list = hash_md5_algs, ++ .size = ARRAY_SIZE(hash_md5_algs), ++}; ++static int ingenic_hash_get_res_pdev(struct ingenic_hash_dev *hash, ++ struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct resource *r; ++ int err; ++ int ret = 0; ++ /* Get the base address */ ++ r = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!r) { ++ dev_err(dev, "no MEM resource info\n"); ++ err = -ENODEV; ++ goto err; ++ } ++ ++ hash->io_base = devm_ioremap(hash->dev, r->start, resource_size(r)); ++ if(IS_ERR_OR_NULL(hash->io_base)) { ++ dev_err(&pdev->dev, "Failed to remap io resources!\n"); ++ ret = -ENOMEM; ++ goto err; ++ } ++ ++ hash->irq = platform_get_irq(pdev,0); ++ if(hash->irq < 0){ ++ dev_err(dev,"Failed to request irq resource info\n"); ++ ret = -EBUSY; ++ goto err; ++ } ++ ++ err = request_threaded_irq(hash->irq,NULL,ingenic_hash_irqthread, ++ IRQF_ONESHOT,dev_name(dev),hash); ++ ++ hash->pdata = &ingenic_hash_pdata; ++ ++err: ++ return ret; ++} ++ ++static int ingenic_hash_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct ingenic_hash_dev *hash; ++ struct ahash_alg *algp; ++ int err = -ENOMEM, i; ++ ++ hash = devm_kzalloc(dev,sizeof(struct ingenic_hash_dev), GFP_KERNEL); ++ if (hash == NULL) { ++ dev_err(dev, "unable to alloc data struct.\n"); ++ goto err_data; ++ } ++ hash->dev = dev; ++ ++ hash->clk_gate = devm_clk_get(&pdev->dev, "gate_hash"); ++ if (IS_ERR(hash->clk_gate)) { ++ dev_err(&pdev->dev, "cannot find hash clock\n"); ++ err = PTR_ERR(hash->clk_gate); ++ goto err_data; ++ } ++ ++ clk_prepare_enable(hash->clk_gate); ++ ++ platform_set_drvdata(pdev, hash); ++ ++ crypto_init_queue(&hash->queue, INGENIC_HASH_QUEUE_LENGTH); ++ spin_lock_init(&hash->lock); ++ err = ingenic_hash_get_res_pdev(hash, pdev); ++ if (err) ++ goto err_data; ++ ++ pm_runtime_enable(dev); ++ ++ INIT_LIST_HEAD(&hash->list); ++ spin_lock(&list_lock); ++ list_add_tail(&hash->list, &dev_list); ++ ++ spin_unlock(&list_lock); ++ for (i = 0; i < hash->pdata->size; i++) { ++ algp = &hash->pdata->algs_list[i]; ++ pr_info("reg alg: %s\n", algp->halg.base.cra_name); ++// INIT_LIST_HEAD(&algp->cra_list); ++ err = crypto_register_ahash(algp); ++ if (err) ++ goto err_algs; ++ hash->pdata->registered++; ++ } ++ printk("ingenic hash[%d] register ok.",hash->pdata->registered); ++ return 0; ++err_algs: ++ for (i = hash->pdata->registered - 1; i >= 0; i--) ++ crypto_unregister_ahash( ++ &hash->pdata->algs_list[i]); ++ pm_runtime_disable(dev); ++err_data: ++ dev_err(dev, "initialization failed.\n"); ++ return err; ++} ++ ++static int ingenic_hash_remove(struct platform_device *pdev) ++{ ++ struct ingenic_hash_dev *hash = platform_get_drvdata(pdev); ++ int i; ++ ++ if (!hash) ++ return -ENODEV; ++ ++ spin_lock(&list_lock); ++ list_del(&hash->list); ++ spin_unlock(&list_lock); ++ for (i = hash->pdata->registered - 1; i >= 0; i--) ++ crypto_unregister_ahash( ++ &hash->pdata->algs_list[i]); ++ hash->pdata->registered = 0; ++ pm_runtime_disable(hash->dev); ++ kfree(hash); ++ hash = NULL; ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int ingenic_hash_suspend(struct device *dev) ++{ ++ pm_runtime_put_sync(dev); ++ return 0; ++} ++ ++static int ingenic_hash_resume(struct device *dev) ++{ ++ pm_runtime_get_sync(dev); ++ return 0; ++} ++#endif ++ ++static const struct dev_pm_ops ingenic_hash_pm_ops = { ++ SET_SYSTEM_SLEEP_PM_OPS(ingenic_hash_suspend, ingenic_hash_resume) ++}; ++ ++static const struct of_device_id ingenic_hash_dt_match[] = { ++ { .compatible = "ingenic,hash", .data = NULL }, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(of, aic_dt_match); ++static struct platform_driver ingenic_hash_driver = { ++ .probe = ingenic_hash_probe, ++ .remove = ingenic_hash_remove, ++ .driver = { ++ .name = "hash", ++ .owner = THIS_MODULE, ++ .pm = &ingenic_hash_pm_ops, ++ .of_match_table = of_match_ptr(ingenic_hash_dt_match), ++ }, ++}; ++ ++module_platform_driver(ingenic_hash_driver); ++ ++MODULE_DESCRIPTION("Ingenic MD5,SHA(160,224,256,384,512) hw acceleration support."); ++MODULE_LICENSE("GPL v2"); ++MODULE_AUTHOR("Stephon.Qiu"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_crypto_ingenic-hash.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_crypto_ingenic-hash.h.patch new file mode 100644 index 00000000..1001bea1 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_crypto_ingenic-hash.h.patch @@ -0,0 +1,122 @@ +diff -drupN a/drivers/crypto/ingenic-hash.h b/drivers/crypto/ingenic-hash.h +--- a/drivers/crypto/ingenic-hash.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/crypto/ingenic-hash.h 2022-06-09 05:02:28.000000000 +0300 +@@ -0,0 +1,118 @@ ++#ifndef __INGENIC_HASH_H__ ++#define __INGENIC_HASH_H__ ++ ++#define ENTER() ++#define EXIT() ++ ++#define INGENIC_HASH_QUEUE_LENGTH (50) ++#define INGENIC_HASH_CACHE_PAGE_SHIFT (0) ++#define DMA_MIN 4 ++#define HASH_BUFFER_LEN (PAGE_SIZE << INGENIC_HASH_CACHE_PAGE_SHIFT) ++ ++/* HASH flags */ ++#define HASH_FLAGS_BUSY BIT(0) ++#define HASH_FLAGS_FINAL BIT(1) ++#define HASH_FLAGS_DMA_ACTIVE BIT(2) ++#define HASH_FLAGS_OUTPUT_READY BIT(3) ++#define HASH_FLAGS_INIT BIT(4) ++#define HASH_FLAGS_CPU BIT(5) ++#define HASH_FLAGS_DMA_READY BIT(6) ++ ++#define HASH_FLAGS_FINUP BIT(16) ++#define HASH_FLAGS_SG BIT(17) ++#define HASH_FLAGS_MD5 BIT(18) ++#define HASH_FLAGS_SHA1 BIT(19) ++#define HASH_FLAGS_SHA224 BIT(20) ++#define HASH_FLAGS_SHA256 BIT(21) ++#define HASH_FLAGS_SHA384 BIT(22) ++#define HASH_FLAGS_SHA512 BIT(23) ++#define HASH_FLAGS_ERROR BIT(24) ++#define HASH_FLAGS_PAD BIT(25) ++ ++#define HASH_OP_UPDATE 1 ++#define HASH_OP_FINAL 2 ++ ++ ++#define INGENIC_HASH_DMA_THRESHOLD 56 ++ ++#define MD5_DIGEST_SIZE 16 ++#define MD5_BLOCK_SIZE 64 ++ ++#define SHA1_DIGEST_SIZE 20 ++#define SHA1_BLOCK_SIZE 64 ++ ++#define SHA224_DIGEST_SIZE 28 ++#define SHA224_BLOCK_SIZE 64 ++ ++#define SHA256_DIGEST_SIZE 32 ++#define SHA256_BLOCK_SIZE 64 ++ ++#define SHA384_DIGEST_SIZE 48 ++#define SHA384_BLOCK_SIZE 128 ++ ++#define SHA512_DIGEST_SIZE 64 ++#define SHA512_BLOCK_SIZE 128 ++ ++#define HASH_HSCR 0 ++#define HASH_HSSR 4 ++#define HASH_HSINTM 8 ++#define HASH_HSSA 0xc ++#define HASH_HSTC 0x10 ++#define HASH_HSDI 0x14 ++#define HASH_HSDO 0x18 ++ ++ ++struct ingenic_hash_reqctx { ++ struct ingenic_hash_dev *hash; ++ unsigned long flags; ++ unsigned long op; ++ ++ u8 digest[SHA512_DIGEST_SIZE] __aligned(sizeof(u32)); ++ u64 digcnt[2]; ++ size_t bufcnt; ++ size_t buflen; ++ dma_addr_t dma_addr; ++ ++ /* walk state */ ++ struct scatterlist *sg; ++ unsigned int offset; /* offset in current sg */ ++ unsigned int total; /* total request */ ++ ++ size_t block_size; ++ u8 buffer[0] __aligned(8); ++ ++}; ++ ++struct ingenic_hash_ctx { ++ struct ingenic_hash_dev *hash; ++ unsigned long flags; ++ /* fallback stuff */ ++ struct crypto_shash *fallback; ++}; ++ ++struct ingenic_hash_pdata { ++ struct ahash_alg *algs_list; ++ unsigned int size; ++ unsigned int registered; ++}; ++ ++struct ingenic_hash_dev { ++ struct list_head list; ++ void __iomem *io_base; ++ int irq; ++ struct clk *clk_gate; ++ struct ingenic_hash_ctx *ctx; ++ struct device *dev; ++ unsigned long flags; ++ spinlock_t lock; ++ struct crypto_queue queue; ++ struct ahash_request *req; ++ struct ingenic_hash_pdata *pdata; ++}; ++ ++#define MCU_BOOT 0xb3422000 ++ ++#define DMCS 0xb3421030 ++#define boot_up_mcu() *(volatile unsigned int *)(DMCS) = 0; ++ ++#endif /*__INGENIC_HASH_H__*/ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_dma_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_dma_Kconfig.patch new file mode 100644 index 00000000..db7071a6 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_dma_Kconfig.patch @@ -0,0 +1,29 @@ +diff -drupN a/drivers/dma/Kconfig b/drivers/dma/Kconfig +--- a/drivers/dma/Kconfig 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/dma/Kconfig 2022-06-09 05:02:28.000000000 +0300 +@@ -277,6 +277,16 @@ config INTEL_MIC_X100_DMA + OS and tools for MIC to use with this driver are available from + . + ++config INGENIC_PDMAC ++ bool "Ingenic programmable dma controller (Of Driver)" ++ depends on MACH_XBURST || MACH_XBURST2 ++ select DMA_VIRTUAL_CHANNELS ++ select DMA_ENGINE ++ help ++ This selects support for the DMA controller in Ingenic X1000 M200 SoCs. ++ If you have a board based on such a SoC and wish to use DMA for ++ devices which can use the DMA controller, say Y or M here. ++ + config K3_DMA + tristate "Hisilicon K3 DMA support" + depends on ARCH_HI3xxx +@@ -320,7 +330,7 @@ config MOXART_DMA + select DMA_VIRTUAL_CHANNELS + help + Enable support for the MOXA ART SoC DMA controller. +- ++ + Say Y here if you enabled MMP ADMA, otherwise say N. + + config MPC512X_DMA diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_dma_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_dma_Makefile.patch new file mode 100644 index 00000000..d8bf619a --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_dma_Makefile.patch @@ -0,0 +1,8 @@ +diff -drupN a/drivers/dma/Makefile b/drivers/dma/Makefile +--- a/drivers/dma/Makefile 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/dma/Makefile 2022-06-09 05:02:28.000000000 +0300 +@@ -67,3 +67,4 @@ obj-$(CONFIG_XGENE_DMA) += xgene-dma.o + obj-$(CONFIG_ZX_DMA) += zx296702_dma.o + + obj-y += xilinx/ ++obj-y += ingenic/ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_dma_ingenic_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_dma_ingenic_Makefile.patch new file mode 100644 index 00000000..6caa9db7 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_dma_ingenic_Makefile.patch @@ -0,0 +1,5 @@ +diff -drupN a/drivers/dma/ingenic/Makefile b/drivers/dma/ingenic/Makefile +--- a/drivers/dma/ingenic/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/dma/ingenic/Makefile 2022-06-09 05:02:28.000000000 +0300 +@@ -0,0 +1 @@ ++obj-$(CONFIG_INGENIC_PDMAC) += ingenic_dma.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_dma_ingenic_ingenic_dma.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_dma_ingenic_ingenic_dma.c.patch new file mode 100644 index 00000000..5072ffc2 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_dma_ingenic_ingenic_dma.c.patch @@ -0,0 +1,1145 @@ +diff -drupN a/drivers/dma/ingenic/ingenic_dma.c b/drivers/dma/ingenic/ingenic_dma.c +--- a/drivers/dma/ingenic/ingenic_dma.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/dma/ingenic/ingenic_dma.c 2022-06-09 05:02:28.000000000 +0300 +@@ -0,0 +1,1141 @@ ++/* ++ * Copyright (C) 2016 Ingenic Semiconductor Co., Ltd. ++ * Author: cli ++ * ++ * Programmable DMA Controller Driver For Ingenic's SOC, ++ * such as X1000, and so on. (kernel.4.4) ++ * ++ * Author: cli ++ * ++ * 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. ++ */ ++ ++#undef DEBUG ++/* #define VERBOSE_DEBUG */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include "ingenic_dma.h" ++ ++#if 0 ++static void dump_dma(struct ingenic_dma_chan *master) ++{ ++ printk("CH_DSA = 0x%08x\n", readl(master->iomem + CH_DSA)); ++ printk("CH_DTA = 0x%08x\n", readl(master->iomem + CH_DTA)); ++ printk("CH_DTC = 0x%08x\n", readl(master->iomem + CH_DTC)); ++ printk("CH_DRT = 0x%08x\n", readl(master->iomem + CH_DRT)); ++ printk("CH_DCS = 0x%08x\n", readl(master->iomem + CH_DCS)); ++ printk("CH_DCM = 0x%08x\n", readl(master->iomem + CH_DCM)); ++ printk("CH_DDA = 0x%08x\n", readl(master->iomem + CH_DDA)); ++ printk("CH_DSD = 0x%08x\n", readl(master->iomem + CH_DSD)); ++} ++void jzdma_dump(struct dma_chan *chan) ++{ ++ struct ingenic_dma_chan *dmac = to_ingenic_dma_chan(chan); ++// dump_dma_desc(dmac); ++ dump_dma(dmac); ++} ++EXPORT_SYMBOL_GPL(jzdma_dump); ++#endif ++ ++ ++/* tsz for 1,2,4,8,16,32,64 128bytes */ ++const static char dcm_tsz[8] = { 1, 2, 0, 0, 3, 4, 5, 6}; ++static inline unsigned int get_current_tsz(unsigned long dcmp) ++{ ++ int i; ++ int val = (dcmp & DCM_TSZ_MSK) >> DCM_TSZ_SFT; ++ ++ if (DCM_TSZ_AUTO == val) ++ return 0; ++ ++ for (i = 0; i < ARRAY_SIZE(dcm_tsz); i++) { ++ if (val == dcm_tsz[i]) ++ break; ++ } ++ ++ return i; ++} ++ ++static inline unsigned get_max_tsz(unsigned long val, unsigned int *shift) ++{ ++ int ord = ffs(val) - 1; ++ ++ /* ++ * 8 byte transfer sizes unsupported so fall back on 4. If it's larger ++ * than the maximum, just limit it. It is perfectly safe to fall back ++ * in this way since we won't exceed the maximum burst size supported ++ * by the device, the only effect is reduced efficiency. This is better ++ * than refusing to perform the request at all. ++ */ ++ if (ord == 3) ++ ord = 2; ++ else if (ord > 7) ++ ord = 7; ++ ++ if (shift) ++ *shift = ord; ++ ++ return dcm_tsz[ord]; ++} ++ ++static const struct of_device_id ingenic_dma_dt_match[]; ++static struct ingenic_dma_engine *ingenic_dma_parse_dt(struct platform_device *pdev) ++{ ++ const struct of_device_id *match; ++ struct ingenic_dma_engine *ingenic_dma; ++ u32 nr_chs; ++ ++ if (!pdev->dev.of_node) ++ return ERR_PTR(-ENODEV); ++ ++ match = of_match_node(ingenic_dma_dt_match, pdev->dev.of_node); ++ if (!match) ++ return ERR_PTR(-ENODEV); ++ ++ if (of_property_read_u32(pdev->dev.of_node, "#dma-channels", &nr_chs)) ++ nr_chs = 32; ++ ++ ingenic_dma = devm_kzalloc(&pdev->dev, sizeof(*ingenic_dma) + ++ sizeof(struct ingenic_dma_chan *) * nr_chs, GFP_KERNEL); ++ if (!ingenic_dma) ++ return ERR_PTR(-ENOMEM); ++ ++ ingenic_dma->dev = &pdev->dev; ++ ingenic_dma->nr_chs = nr_chs; ++ ingenic_dma->hwattr = (unsigned int)match->data; ++ ++ /* Property is optional, if it doesn't exist the value will remain 0. */ ++ of_property_read_u32(pdev->dev.of_node, "ingenic,reserved-chs", ++ &ingenic_dma->chan_reserved); ++ ++ if (!of_property_read_u32(pdev->dev.of_node, "ingenic,programed-chs", ++ &ingenic_dma->chan_programed)) ++ ingenic_dma->chan_reserved |= ingenic_dma->chan_programed; ++ ++ if (HWATTR_SPECIAL_CH01_SUP(ingenic_dma->hwattr) && ++ of_property_read_bool(pdev->dev.of_node, "ingenic,special-chs")) { ++ ingenic_dma->chan_reserved |= DMA_SPECAIL_CHS; ++ ingenic_dma->chan_programed |= DMA_SPECAIL_CHS; ++ ingenic_dma->special_ch = true; ++ } ++ ++ ingenic_dma->intc_ch = -1; ++ if (HWATTR_INTC_IRQ_SUP(ingenic_dma->hwattr) && ++ !of_property_read_u32(pdev->dev.of_node, "ingenic,intc-ch", ++ (u32 *)&ingenic_dma->intc_ch)) { ++ ++ if (ingenic_dma->intc_ch >= ingenic_dma->nr_chs) ++ ingenic_dma->intc_ch = (ingenic_dma->nr_chs - 1); ++ ++ if (BIT(ingenic_dma->intc_ch) & ingenic_dma->chan_reserved) ++ dev_warn(ingenic_dma->dev, "WARN: intc irq channel %d is already reserved\n", ++ ingenic_dma->intc_ch); ++ ++ ingenic_dma->chan_reserved |= BIT(ingenic_dma->intc_ch); ++ } ++ return ingenic_dma; ++} ++ ++#define ALIGN_DOWN(addr, size) ((addr)&(~((size)-1))) ++ ++static int dump_dma_hdesc(struct hdma_desc * desc, const char * d) ++{ ++ int i; ++ unsigned long *p; ++ printk(KERN_DEBUG "%s(): %s\n", __func__, d); ++ p = (unsigned long *)desc; ++ for (i=0;i<8;i++) { ++ printk(KERN_DEBUG "\t%08lx\n", (unsigned long)*p); ++ p++; ++ } ++ ++ return 0; ++} ++ ++static unsigned int build_one_desc(dma_addr_t saddr, dma_addr_t daddr, ++ unsigned int length, struct hdma_desc *desc) ++{ ++ unsigned len = length; ++ ++ if (length < DTC_TC_MSK) { ++ desc->dcm = DCM_DAI | DCM_SAI | \ ++ (DCM_TSZ_AUTO << DCM_TSZ_SFT) | (DCM_RDIL_MAX << DCM_RDIL_SFT); ++ desc->dtc = len; /* DCM_TSZ_AUTO in bytes */ ++ } else { ++ unsigned int tsz, transfer_shift; ++ len = ALIGN_DOWN(len, sizeof(uint32_t)); ++ tsz = get_max_tsz(len , &transfer_shift); ++ desc->dcm = DCM_DAI | DCM_SAI | tsz << DCM_TSZ_SFT; ++ desc->dtc = len >> transfer_shift; /* in burst unit */ ++ barrier(); ++ len = desc->dtc << transfer_shift; ++ } ++ ++ desc->dsa = saddr; ++ desc->dta = daddr; ++ desc->sd = 0; ++ desc->drt = INGENIC_DMA_REQ_AUTO_TX; ++ ++ return len; ++} ++ ++static unsigned int build_one_slave_desc(struct ingenic_dma_chan *dmac, dma_addr_t addr, ++ unsigned int length, ++ enum dma_transfer_direction direction, ++ struct hdma_desc *desc) ++{ ++ enum dma_transfer_direction dir; ++ unsigned int rdil; ++// unsigned int tsz, transfer_shift; ++ ++ desc->dcm = dmac->dcm; ++ desc->drt = dmac->slave_id; ++ desc->sd = 0; ++ ++ if ((direction != DMA_DEV_TO_MEM) && (direction != DMA_MEM_TO_DEV)) ++ dir = dmac->direction; ++ else ++ dir = direction; ++ ++ if (dir == DMA_DEV_TO_MEM) { ++ desc->dta = addr; ++ desc->dsa = dmac->slave_addr; ++ desc->dcm |= DCM_DAI; ++ } else { ++ desc->dsa = addr; ++ desc->dta = dmac->slave_addr; ++ desc->dcm |= DCM_SAI; ++ } ++ ++#if 1 ++ rdil = dmac->maxburst * dmac->transfer_width; ++ if (rdil > 4) ++ rdil = min((int)fls(rdil) + 1, (int)DCM_RDIL_MAX); ++ ++ WARN_ON(length & (~DTC_TC_MSK)); ++ if (WARN_ON(!IS_ALIGNED(length, dmac->transfer_width))) { ++ desc->dtc = ALIGN_DOWN((length & DTC_TC_MSK), dmac->transfer_width); ++ } else { ++ desc->dtc = (length & DTC_TC_MSK); ++ } ++ desc->dcm |= DCM_TSZ_MSK | (rdil << DCM_RDIL_SFT); ++#else ++ tsz = get_max_tsz(length | dmac->maxburst , &transfer_shift); ++ desc->dcm |= tsz << DCM_TSZ_SFT; ++ desc->dtc = length >> transfer_shift; /* in burst unit */ ++#endif ++ return desc->dtc; ++} ++ ++static void ingenic_dma_free_swdesc(struct virt_dma_desc *vd) ++{ ++ struct ingenic_dma_sdesc *sdesc = to_ingenic_dma_sdesc(vd); ++ struct ingenic_dma_chan *dmac = sdesc->dmac; ++ unsigned long flags; ++ int i; ++ ++ WARN_ON(!sdesc->dmac); ++ ++ spin_lock_irqsave(&dmac->hdesc_lock, flags); ++ if (dmac->hdesc_pool) { ++ for (i = 0; i < sdesc->nb_desc; i++) ++ dma_pool_free(dmac->hdesc_pool, sdesc->hw_desc[i], sdesc->hw_desc_dma[i]); ++ dmac->hdesc_num -= sdesc->nb_desc; ++ } ++ spin_unlock_irqrestore(&dmac->hdesc_lock, flags); ++ ++ kfree(sdesc); ++ return; ++} ++ ++static struct ingenic_dma_sdesc *ingenic_dma_alloc_swdesc(struct ingenic_dma_chan *dmac, int num_hdesc) ++{ ++ struct ingenic_dma_sdesc *sdesc; ++ int i; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&dmac->hdesc_lock, flags); ++ if (num_hdesc > (dmac->hdesc_max - dmac->hdesc_num) || !dmac->hdesc_pool) { ++ spin_unlock_irqrestore(&dmac->hdesc_lock, flags); ++ return NULL; ++ } ++ ++ sdesc = (struct ingenic_dma_sdesc *)kzalloc(sizeof(struct ingenic_dma_sdesc) + ++ num_hdesc * (sizeof(void **) + sizeof(dma_addr_t)), ++ GFP_NOWAIT); ++ if (!sdesc) { ++ spin_unlock_irqrestore(&dmac->hdesc_lock, flags); ++ return NULL; ++ } ++ ++ sdesc->hw_desc = (struct hdma_desc**)(sdesc + 1); ++ sdesc->hw_desc_dma = (dma_addr_t *)(sdesc->hw_desc + num_hdesc); ++ sdesc->dmac = dmac; ++ ++ for (i = 0; i < num_hdesc; i++) { ++ sdesc->hw_desc[i] = dma_pool_alloc(dmac->hdesc_pool, GFP_NOWAIT, &sdesc->hw_desc_dma[i]); ++ pr_debug("sdesc->hw_desc[%d] = %p, sdesc->hw_desc_dma[%d] = 0x%08x\n", ++ i, sdesc->hw_desc[i], ++ i, sdesc->hw_desc_dma[i]); ++ if (!sdesc->hw_desc[i]) { ++ dev_err(&dmac->vc.chan.dev->device, ++ "%s(): Couldn't allocate the hw_desc from dma_pool %p\n", ++ __func__, dmac->hdesc_pool); ++ spin_unlock_irqrestore(&dmac->hdesc_lock, flags); ++ goto err; ++ } ++ sdesc->nb_desc++; ++ } ++ dmac->hdesc_num += sdesc->nb_desc; ++ spin_unlock_irqrestore(&dmac->hdesc_lock, flags); ++ return sdesc; ++err: ++ ingenic_dma_free_swdesc(&sdesc->vd); ++ return NULL; ++} ++ ++static struct dma_async_tx_descriptor *ingenic_dma_prep_slave_sg( ++ struct dma_chan *chan, struct scatterlist *sgl, ++ unsigned int sg_len, enum dma_transfer_direction direction, ++ unsigned long flags, void *context) ++{ ++ struct ingenic_dma_chan *dmac = to_ingenic_dma_chan(chan); ++ struct ingenic_dma_sdesc *sdesc; ++ int i; ++ ++ sdesc = ingenic_dma_alloc_swdesc(dmac, sg_len); ++ if (!sdesc) ++ return NULL; ++ ++ for (i = 0; i < sg_len; i++) { ++ sdesc->len += build_one_slave_desc(dmac, sg_dma_address(&sgl[i]), ++ sg_dma_len(&sgl[i]), direction, sdesc->hw_desc[i]); ++ if (i) { ++ sdesc->hw_desc[i - 1]->dcm |= DCM_LINK; ++ sdesc->hw_desc[i - 1]->dtc |= PHY_TO_DESC_DOA(sdesc->hw_desc_dma[i]); ++ } ++ } ++ sdesc->hw_desc[i - 1]->dcm |= DCM_TIE; ++ ++ /* use 8-word descriptors */ ++ sdesc->dcs = DCS_DES8; ++ ++ return vchan_tx_prep(&dmac->vc, &sdesc->vd, flags); ++} ++ ++static struct dma_async_tx_descriptor *ingenic_dma_prep_dma_cyclic( ++ struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, ++ size_t period_len, enum dma_transfer_direction direction, ++ unsigned long flags) ++{ ++ struct ingenic_dma_chan *dmac = to_ingenic_dma_chan(chan); ++ unsigned int periods = buf_len / period_len; ++ struct ingenic_dma_sdesc *sdesc; ++ int i; ++ ++ sdesc = ingenic_dma_alloc_swdesc(dmac, periods); ++ if (!sdesc) ++ return NULL; ++ ++ for (i = 0; i < periods; i++) { ++ sdesc->len += build_one_slave_desc(dmac, buf_addr + (i * period_len), ++ period_len, direction, sdesc->hw_desc[i]); ++ if (i) { ++ sdesc->hw_desc[i - 1]->dcm |= DCM_LINK | DCM_TIE; ++ sdesc->hw_desc[i - 1]->dtc |= PHY_TO_DESC_DOA(sdesc->hw_desc_dma[i]); ++ } ++ } ++ ++ /*make it cyclic*/ ++ sdesc->hw_desc[i - 1]->dcm |= DCM_LINK | DCM_TIE; ++ sdesc->hw_desc[i - 1]->dtc |= PHY_TO_DESC_DOA(sdesc->hw_desc_dma[0]); ++ sdesc->cyclic = true; ++ ++ /* use 8-word descriptors */ ++ sdesc->dcs = DCS_DES8; ++ ++ return vchan_tx_prep(&dmac->vc, &sdesc->vd, flags); ++} ++ ++static struct dma_async_tx_descriptor *ingenic_dma_prep_dma_memcpy(struct dma_chan *chan, ++ dma_addr_t dma_dest, ++ dma_addr_t dma_src, ++ size_t len, ++ unsigned long flags) ++{ ++ struct ingenic_dma_chan *dmac = to_ingenic_dma_chan(chan); ++ struct ingenic_dma_sdesc *sdesc; ++ ++ sdesc = ingenic_dma_alloc_swdesc(dmac, 1); ++ if (!sdesc) ++ return NULL; ++ ++ sdesc->len = build_one_desc(dma_src, dma_dest, len, sdesc->hw_desc[0]); ++ sdesc->hw_desc[0]->dcm |= DCM_TIE; ++ ++ /* use 8-word descriptors */ ++ sdesc->dcs = DCS_DES8; ++ ++ return vchan_tx_prep(&dmac->vc, &sdesc->vd, flags); ++} ++ ++static int build_dma_sg_desc(struct ingenic_dma_sdesc *sdesc, ++ struct scatterlist *dst_sg, unsigned int dst_nents, ++ struct scatterlist *src_sg, unsigned int src_nents) ++{ ++ int src_sg_avail = 0; ++ int dst_sg_avail = 0; ++ int size; ++ dma_addr_t src_addr; ++ dma_addr_t dst_addr; ++ int i = 0; ++ ++ src_nents--; ++ dst_nents--; ++ dst_sg_avail = sg_dma_len(src_sg); ++ src_sg_avail = sg_dma_len(dst_sg); ++ while (true) { ++ src_addr = sg_dma_address(src_sg) + sg_dma_len(src_sg) - src_sg_avail; ++ dst_addr = sg_dma_address(dst_sg) + sg_dma_len(dst_sg) - dst_sg_avail; ++ ++ size = min(src_sg_avail, dst_sg_avail); ++ size = min(size, (DTC_TC_MSK & (~0x3))); ++ ++ if (NULL != sdesc) { ++ sdesc->len += build_one_desc(src_addr, dst_addr, size, sdesc->hw_desc[i]); ++ if (i) { ++ sdesc->hw_desc[i - 1]->dcm |= DCM_LINK; ++ sdesc->hw_desc[i - 1]->dtc |= PHY_TO_DESC_DOA(sdesc->hw_desc_dma[i]); ++ } ++ } ++ ++ dst_sg_avail -= size; ++ src_sg_avail -= size; ++ ++ if (0 == src_sg_avail) { ++ if (0 == src_nents) ++ break; ++ src_sg = sg_next(src_sg); ++ src_sg_avail = sg_dma_len(src_sg); ++ src_nents--; ++ } ++ ++ if (0 == dst_sg_avail) { ++ if (0 == dst_nents) ++ break; ++ dst_sg = sg_next(dst_sg); ++ dst_sg_avail = sg_dma_len(dst_sg); ++ dst_nents--; ++ } ++ i++; ++ } ++ if (sdesc) ++ sdesc->hw_desc[i]->dcm |= DCM_TIE; ++ return ++i; ++} ++ ++static struct dma_async_tx_descriptor* ingenic_dma_prep_dma_sg( ++ struct dma_chan *chan, ++ struct scatterlist *dst_sg, unsigned int dst_nents, ++ struct scatterlist *src_sg, unsigned int src_nents, ++ unsigned long flags) ++{ ++ struct ingenic_dma_chan *dmac = to_ingenic_dma_chan(chan); ++ struct ingenic_dma_sdesc *sdesc; ++ int hw_nums; ++ ++ if (0 == dst_nents || 0 == src_nents) ++ return NULL; ++ ++ if (NULL == dst_sg || NULL == src_sg) ++ return NULL; ++ ++ hw_nums = build_dma_sg_desc(NULL, dst_sg, dst_nents, src_sg, src_nents); ++ ++ sdesc = ingenic_dma_alloc_swdesc(dmac, hw_nums); ++ if (!sdesc) ++ return NULL; ++ ++ build_dma_sg_desc(sdesc, dst_sg, dst_nents, src_sg, src_nents); ++ ++ /* use 8-word descriptors */ ++ sdesc->dcs = DCS_DES8; ++ ++ return vchan_tx_prep(&dmac->vc, &sdesc->vd, flags); ++} ++ ++static size_t ingenic_dma_desc_residue(struct ingenic_dma_chan *dmac, struct ingenic_dma_sdesc *sdesc) ++{ ++ unsigned int residue = 0, shift, pass = 0; ++ unsigned int i; ++ bool dsa = false; ++ dma_addr_t start, end, compare; ++ ++ if (sdesc->hw_desc[0]->dcm & DCM_SAI) { ++ compare = readl(dmac->iomem + CH_DSA); ++ dsa = true; ++ } else { ++ compare = readl(dmac->iomem + CH_DTA); ++ } ++ ++ for (i = 0; i < sdesc->nb_desc; i++) { ++ start = dsa ? sdesc->hw_desc[i]->dsa : sdesc->hw_desc[i]->dta; ++ shift = get_current_tsz(sdesc->hw_desc[i]->dcm); ++ end = start + (sdesc->hw_desc[i]->dtc << shift); ++ if (start <= compare && end > compare) { ++ pass += (compare - start); ++ break; ++ } else { ++ pass += sdesc->hw_desc[i]->dtc << shift; ++ } ++ } ++ ++ residue = sdesc->len - pass; ++ return residue; ++} ++ ++static enum dma_status ingenic_dma_tx_status(struct dma_chan *chan, ++ dma_cookie_t cookie, ++ struct dma_tx_state *txstate) ++{ ++ struct ingenic_dma_chan *dmac = to_ingenic_dma_chan(chan); ++ struct virt_dma_desc *vd; ++ enum dma_status status; ++ unsigned long flags; ++ ++ status = dma_cookie_status(chan, cookie, txstate); ++ if ((status == DMA_COMPLETE) || (txstate == NULL)) ++ return status; ++ ++ spin_lock_irqsave(&dmac->vc.lock, flags); ++ ++ vd = vchan_find_desc(&dmac->vc, cookie); ++ if (vd) { ++ dma_set_residue(txstate, to_ingenic_dma_sdesc(vd)->len); ++ } else if (dmac->sdesc && cookie == dmac->sdesc->vd.tx.cookie) { ++ dma_set_residue(txstate, ingenic_dma_desc_residue(dmac, dmac->sdesc)); ++ } else ++ dma_set_residue(txstate, 0); ++ ++ spin_unlock_irqrestore(&dmac->vc.lock, flags); ++ return status; ++} ++ ++static void ingenic_dma_start_trans(struct ingenic_dma_chan *dmac) ++{ ++ struct virt_dma_desc *vd = NULL; ++ struct ingenic_dma_sdesc *sdesc; ++ int i; ++ ++ if (!dmac->sdesc) { ++ vd = vchan_next_desc(&dmac->vc); ++ if (!vd) ++ return; ++ ++ list_del(&vd->node); ++ ++ sdesc = dmac->sdesc = to_ingenic_dma_sdesc(vd); ++ ++ if (dmac->fake_cyclic && sdesc->cyclic && vd->tx.callback) { ++ /* ++ * The DMA controller doesn't support triggering an interrupt ++ * after processing each descriptor, only after processing an ++ * entire terminated list of descriptors.For a cyclic DMA ++ * setup the list of descriptors is not terminated so we can ++ * never get an interrupt. ++ * ++ * If the user requested a callback for a cyclic DMA setup then ++ * we workaround this hardware limitation here by degrading to ++ * a set of unlinked descriptors which we will submit in ++ * sequence in response to the completion of processing the ++ * previous descriptor ++ */ ++ for (i = 0; i < sdesc->nb_desc; i++) { ++ sdesc->hw_desc[i]->dcm &= ~DCM_LINK; ++ } ++ } ++ ++ for (i = 0; i < sdesc->nb_desc; i++) { ++ int j; ++ uint32_t *vaddr = (void *)sdesc->hw_desc[i]; ++ for (j = 0; j < 8; j++) { ++ pr_debug("<%d>: &vaddr[0] %p vaddr[0] %x\n",i, &vaddr[j], vaddr[j]); ++ } ++ pr_debug("sdesc->hw_desc_dma[0] 0x%08x dmac->iomem %p\n", sdesc->hw_desc_dma[i], dmac->iomem); ++ } ++ ++ sdesc->curr_desc = 0; ++ sdesc->status = STAT_RUNNING; ++ } else { ++ sdesc = dmac->sdesc; ++ WARN_ON_ONCE((!sdesc->cyclic)); ++ WARN_ON_ONCE((!vd->tx.callback)); ++ WARN_ON_ONCE((!dmac->fake_cyclic)); ++ sdesc->status = STAT_RUNNING; ++ sdesc->curr_desc++; ++ sdesc->curr_desc = sdesc->curr_desc % sdesc->nb_desc; ++ } ++ ++ //dump_dma_hdesc(sdesc->hw_desc[sdesc->curr_desc], __func__); ++ /* dma descriptor address */ ++ writel(sdesc->hw_desc_dma[sdesc->curr_desc], dmac->iomem + CH_DDA); ++ /* initiate descriptor fetch */ ++ writel(BIT(dmac->id), dmac->engine->iomem + DDRS); ++ /* transfer start */ ++ dev_dbg(chan2dev(&dmac->vc.chan), "dcs:%x start transfer\n", ++ readl(dmac->iomem + CH_DCS)); ++ ++ writel(sdesc->dcs | DCS_CTE, dmac->iomem + CH_DCS); ++ return; ++} ++ ++static void ingenic_dma_issue_pending(struct dma_chan *chan) ++{ ++ struct ingenic_dma_chan *dmac = to_ingenic_dma_chan(chan); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&dmac->vc.lock, flags); ++ ++ if (vchan_issue_pending(&dmac->vc) && !dmac->sdesc) ++ ingenic_dma_start_trans(dmac); ++ ++ spin_unlock_irqrestore(&dmac->vc.lock, flags); ++} ++ ++/* ++ * get dma current transfer address ++ */ ++static dma_addr_t jzdma_get_current_trans_addr(struct dma_chan *chan, ++ dma_addr_t * dst_addr, ++ dma_addr_t * src_addr, ++ enum dma_transfer_direction ++ direction) ++{ ++ struct ingenic_dma_chan *dmac = to_ingenic_dma_chan(chan); ++ dma_addr_t ret_val = 0; ++ ++ if(!dmac->sdesc) ++ return 0; ++ if (dmac->sdesc->status == STAT_STOPPED) ++ return 0; ++ ++ if (direction == DMA_MEM_TO_DEV) { ++ ret_val = readl(dmac->iomem + CH_DSA); ++ if (src_addr) ++ *src_addr = ret_val; ++ if (dst_addr) ++ *dst_addr = readl(dmac->iomem + CH_DTA); ++ } else if (direction == DMA_DEV_TO_MEM) { ++ ret_val = readl(dmac->iomem + CH_DTA); ++ if (dst_addr) ++ *dst_addr = ret_val; ++ if (src_addr) ++ *src_addr = readl(dmac->iomem + CH_DSA); ++ } else if (direction == DMA_MEM_TO_MEM) { ++ if (dst_addr) ++ *dst_addr = readl(dmac->iomem + CH_DTA); ++ if (src_addr) ++ *src_addr = readl(dmac->iomem + CH_DSA); ++ } ++ ++ return ret_val; ++} ++ ++static int ingenic_dma_terminate_all(struct dma_chan *chan) ++{ ++ struct ingenic_dma_chan *dmac = to_ingenic_dma_chan(chan); ++ unsigned long flags; ++ int ret = 0; ++ LIST_HEAD(head); ++ ++ spin_lock_irqsave(&dmac->vc.lock, flags); ++ ++ /* the part handler audio driver */ ++ if(dmac->slave_id == INGENIC_DMA_REQ_AIC_LOOP_RX || dmac->slave_id == INGENIC_DMA_REQ_AIC_TX ++ || dmac->slave_id == INGENIC_DMA_REQ_AIC_F_RX || dmac->slave_id == INGENIC_DMA_REQ_DMIC_RX) ++ { ++ if (dmac->sdesc) { /*DMA transfer is running*/ ++ if (dmac->sdesc->status != STAT_STOPPED) { ++ dmac->sdesc->status = STAT_STOPPED; ++ writel(0, dmac->iomem + CH_DCS); ++ } ++ ingenic_dma_free_swdesc(&dmac->sdesc->vd); ++ dmac->sdesc = NULL; ++ } ++ ++// printk("%s[%d]: pdma%d\n",__func__,__LINE__,dmac->slave_id); ++ goto done; ++ } ++ ++ if (dmac->sdesc) { /*DMA transfer is running*/ ++ int i; ++ ret = -EBUSY; ++ if (dmac->sdesc->status != STAT_STOPPED) { ++ dmac->sdesc->status = STAT_STOPPED; ++ reinit_completion(&dmac->completion); ++ ++ for (i = 0; i < dmac->sdesc->nb_desc; i++) { ++ dmac->sdesc->hw_desc[i]->dcm |= DCM_TIE; ++ dmac->sdesc->hw_desc[i]->dcm &= ~DCM_LINK; ++ } ++ ++ if (HWATTR_DESC_INTER_SUP(dmac->engine->hwattr)) { ++ /* ++ * The version of controller support descriptor interrupt ++ * can clear LINK on runtime ++ */ ++ unsigned int dcm = readl(dmac->iomem + CH_DCM); ++ if (dcm & DCM_LINK) { ++ dcm &= ~DCM_LINK; ++ writel(dcm, dmac->iomem + CH_DCM); ++ } ++ } ++ } else if (readl(dmac->iomem + CH_DRT) != INGENIC_DMA_REQ_AUTO_TX) { ++ writel(0, dmac->iomem + CH_DCS); ++ ingenic_dma_free_swdesc(&dmac->sdesc->vd); ++ dmac->sdesc = NULL; ++ complete(&dmac->completion); ++ ret = 0; /*DMA transfer force stop !!!!!*/ ++ } ++ } else { /*DMA transfer already stoped*/ ++ writel(0, dmac->iomem + CH_DCS); ++ } ++done: ++ vchan_get_all_descriptors(&dmac->vc, &head); ++ ++ spin_unlock_irqrestore(&dmac->vc.lock, flags); ++ ++ vchan_dma_desc_free_list(&dmac->vc, &head); ++ ++ return ret; ++} ++ ++static int ingenic_dma_wait_terminate_complete(struct dma_chan *chan) ++{ ++ struct ingenic_dma_chan *dmac = to_ingenic_dma_chan(chan); ++ ++ if (dmac->sdesc) ++ wait_for_completion(&dmac->completion); ++ return 0; ++} ++ ++static int ingenic_dma_config(struct dma_chan *chan, struct dma_slave_config *config) ++{ ++ struct ingenic_dma_chan* dmac = to_ingenic_dma_chan(chan); ++ enum dma_slave_buswidth transfer_width; ++ ++ if (!config) ++ return -EINVAL; ++ ++ switch (config->direction) { ++ case DMA_MEM_TO_DEV: ++ if (!config->dst_addr_width || !config->dst_addr) ++ return -EINVAL; ++ if (!config->dst_maxburst) ++ config->dst_maxburst = 1; ++ transfer_width = config->dst_addr_width; ++ dmac->slave_addr = config->dst_addr; ++ dmac->maxburst = config->dst_maxburst; ++ break; ++ case DMA_DEV_TO_MEM: ++ if (!config->src_addr_width || !config->src_addr) ++ return -EINVAL; ++ if (!config->src_maxburst) ++ config->src_maxburst = 1; ++ transfer_width = config->src_addr_width; ++ dmac->slave_addr = config->src_addr; ++ dmac->maxburst = config->src_maxburst; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ switch (transfer_width) { ++ case DMA_SLAVE_BUSWIDTH_1_BYTE: ++ dmac->dcm = DCM_PORT_8; ++ dmac->transfer_width = 1; ++ break; ++ case DMA_SLAVE_BUSWIDTH_2_BYTES: ++ dmac->dcm = DCM_PORT_16; ++ dmac->transfer_width = 2; ++ break; ++ case DMA_SLAVE_BUSWIDTH_4_BYTES: ++ dmac->dcm = DCM_PORT_32; ++ dmac->transfer_width = 4; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ /* must be delete it */ ++// if (config->slave_id & INGENIC_DMA_TYPE_REQ_MSK) ++// dmac->slave_id = config->slave_id & INGENIC_DMA_TYPE_REQ_MSK; ++ ++ return 0; ++} ++ ++static void pdma_handle_chan_irq(struct ingenic_dma_engine *ingenic_dma, int ch_id) ++{ ++ struct ingenic_dma_chan *dmac = ingenic_dma->chan[ch_id]; ++ struct ingenic_dma_sdesc *sdesc; ++ unsigned int dcs; ++ ++ spin_lock(&dmac->vc.lock); ++ ++ dcs = readl(dmac->iomem + CH_DCS); ++ writel(0, dmac->iomem + CH_DCS); ++ ++ if (dcs & DCS_AR) ++ dev_warn(&dmac->vc.chan.dev->device, ++ "address error (DCS=0x%x)\n", dcs); ++ ++ if (dcs & DCS_HLT) ++ dev_warn(&dmac->vc.chan.dev->device, ++ "channel halt (DCS=0x%x)\n", dcs); ++ sdesc = dmac->sdesc; ++ if (sdesc) { ++ if (sdesc->status == STAT_STOPPED) { ++ dma_cookie_complete(&sdesc->vd.tx); ++ dmac->sdesc = NULL; ++ ingenic_dma_free_swdesc(&sdesc->vd); ++ complete(&dmac->completion); ++ } else if (dmac->fake_cyclic && sdesc->cyclic) { ++ vchan_cyclic_callback(&sdesc->vd); ++ } else { ++ vchan_cookie_complete(&sdesc->vd); ++ dmac->sdesc = NULL; ++ } ++ ingenic_dma_start_trans(dmac); ++ } else { ++ dev_warn(&dmac->vc.chan.dev->device, ++ "channel irq with no active transfer, channel stop\n"); ++ } ++ ++ spin_unlock(&dmac->vc.lock); ++} ++ ++static irqreturn_t pdma_int_handler(int irq, void *dev) ++{ ++ struct ingenic_dma_engine *ingenic_dma = (struct ingenic_dma_engine *)dev; ++ unsigned long pending, dmac; ++ int i; ++ ++ pending = readl(ingenic_dma->iomem + DIRQP); ++ writel(~pending, ingenic_dma->iomem + DIRQP); ++ ++ for (i = 0; i < ingenic_dma->nr_chs ; i++) { ++ if (!(pending & (1 << i))) ++ continue; ++ pdma_handle_chan_irq(ingenic_dma, i); ++ } ++ ++ dmac = readl(ingenic_dma->iomem + DMAC); ++ dmac &= ~(DMAC_HLT | DMAC_AR); ++ writel(dmac, ingenic_dma->iomem + DMAC); ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t pdmam_int_handler(int irq, void *dev) ++{ ++ /*TODO*/ ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t pdmad_int_handler(int irq, void *dev) ++{ ++ struct ingenic_dma_engine *ingenic_dma = (struct ingenic_dma_engine *)dev; ++ unsigned long pending; ++ int i; ++ ++ pending = readl(ingenic_dma->iomem + DIP); ++ writel(readl(ingenic_dma->iomem + DIP) & (~pending), ingenic_dma->iomem + DIC); ++ ++ for (i = 0; i < ingenic_dma->nr_chs; i++) { ++ struct ingenic_dma_chan *dmac = ingenic_dma->chan[i]; ++ struct ingenic_dma_sdesc *sdesc; ++ ++ if (!(pending & (1 << i))) ++ continue; ++ sdesc = dmac->sdesc; ++ if (sdesc && sdesc->cyclic) { ++ spin_lock(&dmac->vc.lock); ++ vchan_cyclic_callback(&sdesc->vd); ++ spin_unlock(&dmac->vc.lock); ++ } ++ } ++ return IRQ_HANDLED; ++ ++} ++ ++static int ingenic_dma_alloc_chan_resources(struct dma_chan *chan) ++{ ++ struct ingenic_dma_chan *dmac = to_ingenic_dma_chan(chan); ++ ++ dmac->hdesc_pool = dma_pool_create(dev_name(&chan->dev->device), ++ chan->device->dev, ++ sizeof(struct hdma_desc), ++ 0, PAGE_SIZE); ++ if (!dmac->hdesc_pool) { ++ dev_err(&chan->dev->device, ++ "failed to allocate descriptor pool\n"); ++ return -ENOMEM; ++ } ++ dmac->hdesc_max = PAGE_SIZE / sizeof(struct hdma_desc); ++ dmac->hdesc_num = 0; ++ return 0; ++} ++ ++static void ingenic_dma_free_chan_resources(struct dma_chan *chan) ++{ ++ struct ingenic_dma_chan *dmac = to_ingenic_dma_chan(chan); ++ unsigned long flags; ++ ++ ingenic_dma_terminate_all(chan); ++ ++ ingenic_dma_wait_terminate_complete(chan); ++ ++ dma_pool_destroy(dmac->hdesc_pool); ++ spin_lock_irqsave(&dmac->hdesc_lock, flags); ++ dmac->hdesc_pool = NULL; ++ dmac->hdesc_max = 0; ++ dmac->hdesc_num = 0; ++ spin_unlock_irqrestore(&dmac->hdesc_lock, flags); ++} ++ ++static bool ingenic_dma_filter_fn(struct dma_chan *chan, void *param) ++{ ++ struct ingenic_dma_chan *dmac = to_ingenic_dma_chan(chan); ++ unsigned int private = *(unsigned int *)param; ++ unsigned int type = (unsigned int)chan->private; ++ int channel = -1; ++ ++ if (private & INGENIC_DMA_TYPE_CH_EN) { ++ channel = (private & INGENIC_DMA_TYPE_CH_MSK) >> INGENIC_DMA_TYPE_CH_SFT; ++ if (dmac->id == channel){ ++ printk("%s:%d assignment channle is %d\n",__func__,__LINE__, channel); ++ return true; ++ } ++ return false; ++ } ++ ++ if (dmac->engine->chan_reserved & BIT(dmac->id)) ++ return false; ++ ++ if((private & INGENIC_DMA_TYPE_REQ_MSK) != type) ++ return false; ++ ++ dmac->slave_id = private & INGENIC_DMA_TYPE_REQ_MSK; ++ return true; ++} ++ ++static struct of_dma_filter_info of_ingenic_dma_info = { ++ .filter_fn = ingenic_dma_filter_fn, ++}; ++ ++static int ingenic_dma_chan_init(struct ingenic_dma_engine *dma, int id) ++{ ++ struct ingenic_dma_chan *dmac = NULL; ++ ++ if(id < 0 || id >= INGENIC_DMA_CHAN_CNT) ++ return -EINVAL; ++ dmac = devm_kzalloc(dma->dev, sizeof(*dmac), GFP_KERNEL); ++ if (!dmac) ++ return -ENOMEM; ++ dmac->id = id; ++ dmac->iomem = dma->iomem + dmac->id * DMACH_OFF; ++ dmac->engine = dma; ++ dmac->fake_cyclic = HWATTR_DESC_INTER_SUP(dma->hwattr) ? false : true; ++ spin_lock_init(&dmac->hdesc_lock); ++ init_completion(&dmac->completion); ++ ++ vchan_init(&dmac->vc, &dma->dma_device); ++ ++ dmac->vc.desc_free = ingenic_dma_free_swdesc; ++ dmac->vc.chan.private = (void*)pdma_maps[id]; ++ dmac->slave_id = pdma_maps[id] & INGENIC_DMA_TYPE_REQ_MSK; ++ dma->chan[id] = dmac; ++ return 0; ++} ++ ++static int __init ingenic_dma_probe(struct platform_device *pdev) ++{ ++ struct ingenic_dma_engine *dma = NULL; ++ struct resource *iores; ++ u32 reg_dmac = DMAC_DMAE; ++ int i, ret = 0; ++ ++ /* check of first. if of failed, use platform */ ++ dma = ingenic_dma_parse_dt(pdev); ++ if (IS_ERR(dma)) ++ return PTR_ERR(dma); ++ ++ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ dma->iomem = devm_ioremap_resource(&pdev->dev, iores); ++ if (IS_ERR(dma->iomem)) ++ return PTR_ERR(dma->iomem); ++ ++ /* PDMA interrupt*/ ++ dma->irq_pdma = platform_get_irq_byname(pdev, "pdma"); ++ if (dma->irq_pdma < 0) ++ return dma->irq_pdma; ++ ret = devm_request_irq(&pdev->dev, dma->irq_pdma, pdma_int_handler, ++ 0, "pdma", dma); ++ if (ret) ++ return ret; ++ ++ /* PDMA mcu interrupt*/ ++ dma->irq_pdmam = platform_get_irq_byname(pdev, "pdmam"); ++ if (dma->irq_pdmam >= 0) { ++ ret = devm_request_irq(&pdev->dev, dma->irq_pdmam, pdmam_int_handler, ++ 0, "pdmam", dma); ++ if (ret) ++ return ret; ++ } ++ ++ /* PDMA descriptor interrupt */ ++ if (HWATTR_DESC_INTER_SUP(dma->hwattr)) { ++ dma->irq_pdmad = platform_get_irq_byname(pdev, "pdmad"); ++ if (dma->irq_pdmad < 0){ ++ printk("##ERROR %s[%d]: \n",__func__,__LINE__); ++ return dma->irq_pdmad; ++ } ++ ret = devm_request_irq(&pdev->dev, dma->irq_pdmad, pdmad_int_handler, ++ 0, "pdmad", dma); ++ if (ret) ++ return ret; ++ } ++ ++ /* Initialize dma engine */ ++ INIT_LIST_HEAD(&dma->dma_device.channels); ++ for (i = 0; i < dma->nr_chs; i++ ) { ++ /*reserved one channel for intc interrupt*/ ++ if (dma->intc_ch == i) ++ continue; ++ ingenic_dma_chan_init(dma, i); ++ } ++ dma_cap_set(DMA_MEMCPY, dma->dma_device.cap_mask); ++ dma_cap_set(DMA_SG, dma->dma_device.cap_mask); ++ dma_cap_set(DMA_SLAVE, dma->dma_device.cap_mask); ++ dma_cap_set(DMA_CYCLIC, dma->dma_device.cap_mask); ++ ++ dma->dma_device.dev = &pdev->dev; ++ dma->dma_device.device_alloc_chan_resources = ingenic_dma_alloc_chan_resources; ++ dma->dma_device.device_free_chan_resources = ingenic_dma_free_chan_resources; ++ dma->dma_device.device_tx_status = ingenic_dma_tx_status; ++ dma->dma_device.device_prep_slave_sg = ingenic_dma_prep_slave_sg; ++ dma->dma_device.device_prep_dma_sg = ingenic_dma_prep_dma_sg; ++ dma->dma_device.device_prep_dma_cyclic = ingenic_dma_prep_dma_cyclic; ++ dma->dma_device.device_prep_dma_memcpy = ingenic_dma_prep_dma_memcpy; ++ dma->dma_device.device_config = ingenic_dma_config; ++ dma->dma_device.get_current_trans_addr = jzdma_get_current_trans_addr; ++ dma->dma_device.device_terminate_all = ingenic_dma_terminate_all; ++ dma->dma_device.device_issue_pending = ingenic_dma_issue_pending; ++ dma->dma_device.copy_align = DMAENGINE_ALIGN_4_BYTES; ++ dma->dma_device.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) ++ | BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); ++ dma->dma_device.dst_addr_widths = dma->dma_device.src_addr_widths; ++ dma->dma_device.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV) | BIT(DMA_MEM_TO_MEM); ++ dma->dma_device.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; ++ dma->dma_device.dev->dma_parms = &dma->dma_parms; ++ dma_set_max_seg_size(dma->dma_device.dev, DTC_TC_MSK); /*At least*/ ++ ++ dma->gate_clk = devm_clk_get(&pdev->dev, "gate_pdma"); ++ if (IS_ERR(dma->gate_clk)) ++ return PTR_ERR(dma->gate_clk); ++ ++ ret = dma_async_device_register(&dma->dma_device); ++ if (ret) { ++ dev_err(&pdev->dev, "unable to register\n"); ++ clk_disable(dma->gate_clk); ++ return ret; ++ } ++ ++ of_ingenic_dma_info.dma_cap = dma->dma_device.cap_mask; ++ ret = of_dma_controller_register(pdev->dev.of_node, ++ of_dma_simple_xlate, &of_ingenic_dma_info); ++ if (ret) { ++ dev_err(&pdev->dev, "unable to register dma to device tree\n"); ++ dma_async_device_unregister(&dma->dma_device); ++ clk_disable(dma->gate_clk); ++ return ret; ++ } ++ platform_set_drvdata(pdev, dma); ++ ++ /*enable pdma controller*/ ++ clk_prepare_enable(dma->gate_clk); ++ ++ if (dma->chan_programed) ++ writel(dma->chan_programed, dma->iomem + DMACP); ++ if (dma->intc_ch >= 0) ++ reg_dmac |= DMAC_INTCE | ((dma->intc_ch << DMAC_INTCC_SFT) & DMAC_INTCC_MSK); ++ if (dma->special_ch) ++ reg_dmac |= DMAC_CH01; ++ writel(reg_dmac, dma->iomem + DMAC); ++ dev_info(dma->dev, "INGENIC SoC DMA initialized\n"); ++ return 0; ++} ++ ++static int ingenic_dma_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ struct ingenic_dma_engine *ingenic_dma = platform_get_drvdata(pdev); ++ struct dma_chan *chan; ++ ++ list_for_each_entry(chan, &ingenic_dma->dma_device.channels, device_node) { ++ struct ingenic_dma_chan *dmac = to_ingenic_dma_chan(chan); ++ if (dmac->sdesc) ++ return -EBUSY; ++ } ++ clk_disable_unprepare(ingenic_dma->gate_clk); ++ return 0; ++} ++ ++static int ingenic_dma_resume(struct platform_device * pdev) ++{ ++ struct ingenic_dma_engine *ingenic_dma = platform_get_drvdata(pdev); ++ clk_prepare_enable(ingenic_dma->gate_clk); ++ return 0; ++} ++ ++static const struct of_device_id ingenic_dma_dt_match[] = { ++ { .compatible = "ingenic,m200-pdma", .data = (void *)(HWATTR_SPECIAL_CH01|HWATTR_INTC_IRQ)}, ++ { .compatible = "ingenic,x1000-pdma", .data = (void *)HWATTR_DESC_INTER}, ++ { .compatible = "ingenic,t40-pdma", .data = (void *)HWATTR_INTC_IRQ}, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ingenic_dma_dt_match); ++ ++static struct platform_driver ingenic_dma_driver = { ++ .driver = { ++ .name = "ingenic-dma", ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(ingenic_dma_dt_match), ++ }, ++ .suspend = ingenic_dma_suspend, ++ .resume = ingenic_dma_resume, ++}; ++ ++static int __init ingenic_dma_module_init(void) ++{ ++ return platform_driver_probe(&ingenic_dma_driver, ingenic_dma_probe); ++} ++subsys_initcall(ingenic_dma_module_init); ++MODULE_AUTHOR("Chen.li "); ++MODULE_DESCRIPTION("Ingenic dma driver"); ++MODULE_LICENSE("GPL"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_dma_ingenic_ingenic_dma.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_dma_ingenic_ingenic_dma.h.patch new file mode 100644 index 00000000..90861376 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_dma_ingenic_ingenic_dma.h.patch @@ -0,0 +1,217 @@ +diff -drupN a/drivers/dma/ingenic/ingenic_dma.h b/drivers/dma/ingenic/ingenic_dma.h +--- a/drivers/dma/ingenic/ingenic_dma.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/dma/ingenic/ingenic_dma.h 2022-06-09 05:02:28.000000000 +0300 +@@ -0,0 +1,213 @@ ++/* ++ * Copyright (C) 2016 Ingenic Semiconductor Co., Ltd. ++ * ++ * 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. ++ */ ++ ++ ++#ifndef __INGENIC_DMA_H__ ++#define __INGENIC_DMA_H__ ++#include ++#include "../virt-dma.h" ++#include "../dmaengine.h" ++#define CH_DSA 0x00 ++#define CH_DTA 0x04 ++#define CH_DTC 0x08 ++#define CH_DRT 0x0C ++#define CH_DCS 0x10 ++#define CH_DCM 0x14 ++#define CH_DDA 0x18 ++#define CH_DSD 0x1C ++ ++#define TCSM 0x2000 ++ ++#define DMAC 0x1000 ++#define DIRQP 0x1004 ++#define DDR 0x1008 ++#define DDRS 0x100C ++#define DIP 0x1010 ++#define DIC 0x1014 ++#define DMACP 0x101C ++#define DSIRQP 0x1020 ++#define DSIRQM 0x1024 ++#define DCIRQP 0x1028 ++#define DCIRQM 0x102C ++ ++#define DMACH_OFF 0x20 ++/* DCS */ ++#define DCS_NDES BIT(31) ++#define DCS_DES8 BIT(30) ++#define DCS_CDOA_SFT 8 ++#define DCS_CDOA_MSK (0xff << DCS_CDOA_SFT) ++#define DCS_AR BIT(4) ++#define DCS_TT BIT(3) ++#define DCS_HLT BIT(2) ++#define DCS_CTE BIT(0) ++ ++/* DTC */ ++#define DTC_TC_SFT 0 ++#define DTC_TC_MSK 0xffffff ++ ++/* DCM */ ++#define DCM_SAI BIT(23) ++#define DCM_DAI BIT(22) ++#define DCM_PORT_MSK (0xf << 12) ++#define DCM_PORT_8 (0x1 << 14 | 0x1 <<12) ++#define DCM_PORT_16 (0x2 << 14 | 0x2 <<12) ++#define DCM_PORT_32 (0x0 << 14 | 0x0 <<12) ++#define DCM_RDIL_SFT 16 ++#define DCM_RDIL_MAX 0x9 ++#define DCM_RDIL_MSK (0xf << DCM_RDIL_SFT) ++#define DCM_TSZ_SFT 8 ++#define DCM_TSZ_AUTO 0x7 ++#define DCM_TSZ_MSK (0x7 << DCM_TSZ_SFT) ++#define DCM_STDE BIT(2) ++#define DCM_TIE BIT(1) ++#define DCM_LINK BIT(0) ++ ++/* DDA */ ++#define DDA_DBA_SFT 12 ++#define DDA_DBA_MSK (0xfffff << DDA_DBA_SFT) ++#define DDA_DOA_SFT 4 ++#define DDA_DOA_MSK (0xff << DDA_DOA_SFT) ++#define PHY_TO_DESC_DOA(dma) ((((dma) & DDA_DOA_MSK) >> DDA_DOA_SFT) << 24) ++ ++/* DSD */ ++#define DSD_TSD_SFT 16 ++#define DSD_TSD_MSK (0xffff << DSD_TSD_SFT) ++#define DSD_SSD_SFT 0 ++#define DSD_SSD_MSK (0xffff << DSD_SSD_SFT) ++ ++/* DMAC */ ++#define DMAC_FMSC BIT(31) ++#define DMAC_FSSI BIT(30) ++#define DMAC_FTSSI BIT(29) ++#define DMAC_FUART BIT(28) ++#define DMAC_FAIC BIT(27) ++#define DMAC_INTCC_SFT 17 ++#define DMAC_INTCC_MSK (0x1f << 17) ++#define DMAC_INTCE BIT(16) ++#define DMAC_HLT BIT(3) ++#define DMAC_AR BIT(2) ++#define DMAC_CH01 BIT(1) ++#define DMAC_DMAE BIT(0) ++ ++/* MCU of PDMA */ ++#define DMCS 0x1030 ++#define DMNMB 0x1034 ++#define DMSMB 0x1038 ++#define DMINT 0x103C ++ ++/* MCU of PDMA */ ++#define DMINT_S_IP BIT(17) ++#define DMINT_N_IP BIT(16) ++ ++#define DMA_SPECAIL_CHS 0x3 /*Channel 0 & 1*/ ++ ++ ++/*8-word hardware dma descriptor*/ ++struct hdma_desc { ++ unsigned long dcm; ++ dma_addr_t dsa; ++ dma_addr_t dta; ++ unsigned long dtc; ++ unsigned long sd; ++ unsigned long drt; ++ unsigned long reserved[2]; ++}; ++ ++enum sdesc_status { ++ STAT_STOPPED = 0, STAT_RUNNING, STAT_ERROR ++}; ++ ++struct ingenic_dma_chan; ++struct ingenic_dma_sdesc { ++ struct virt_dma_desc vd; /* Virtual descriptor */ ++ int nb_desc; /* Number of hw. descriptors */ ++ size_t len; /* Number of bytes xfered */ ++ bool cyclic; ++ struct hdma_desc **hw_desc; /* DMA coherent descriptors */ ++ dma_addr_t *hw_desc_dma; /* DMA address of the Descriptors*/ ++ struct ingenic_dma_chan *dmac; /* for free*/ ++ int dcs; /* The DCS initial value */ ++ int curr_desc; ++ enum sdesc_status status; ++}; ++ ++struct ingenic_dma_chan { ++ struct virt_dma_chan vc; /* Virtual channel */ ++ int id; /* Channel id*/ ++ void __iomem *iomem; ++ struct ingenic_dma_engine *engine; ++ bool fake_cyclic; ++ ++ /*dma slave channel config*/ ++ unsigned int slave_id; /* Request type of the channel */ ++ enum dma_transfer_direction direction; ++ dma_addr_t slave_addr; ++ unsigned int maxburst; ++ unsigned int transfer_width; ++ unsigned int fast_mode; /* The fast mode bit of dmac*/ ++ unsigned int dcm; /* The DCM of HW Descriptor initial value*/ ++ ++ ++ /*Descriptors*/ ++ struct dma_pool *hdesc_pool; /*HW Descriptors pool */ ++ spinlock_t hdesc_lock; /*HW Descriptor assign lock*/ ++ int hdesc_num; /*HW Descriptors assigned num*/ ++ int hdesc_max; /*HW Descriptors maxnum capacity*/ ++ ++ struct ingenic_dma_sdesc *sdesc; /*Current Running Async Tx Desc*/ ++ ++ /*channel terminated completion*/ ++ struct completion completion; ++}; ++ ++struct ingenic_dma_engine { ++ struct device *dev; ++ void __iomem *iomem; ++ struct clk *gate_clk; ++ struct dma_device dma_device; ++ struct device_dma_parameters dma_parms; ++ ++ uint32_t chan_reserved; ++ uint32_t chan_programed; ++ int intc_ch; ++ bool special_ch; ++ ++ /*hardware interrupt*/ ++ int irq_pdma; /* pdma interrupt*/ ++ int irq_pdmam; /* pdma mcu interrupt */ ++ int irq_pdmad; /* pdma per-descriptor interrupt*/ ++ ++ /*hardware params*/ ++#define HWATTR_INTC_IRQ (1 << 0) ++#define HWATTR_SPECIAL_CH01 (1 << 1) ++#define HWATTR_DESC_INTER (1 << 2) ++#define HWATTR_INTC_IRQ_SUP(x) (HWATTR_INTC_IRQ & (x)) ++#define HWATTR_SPECIAL_CH01_SUP(x) (HWATTR_SPECIAL_CH01 & (x)) ++#define HWATTR_DESC_INTER_SUP(x) (HWATTR_DESC_INTER & (x)) ++ unsigned int hwattr; ++ /*channels*/ ++ int nr_chs; ++ struct ingenic_dma_chan* chan[]; ++}; ++ ++static inline struct device *chan2dev(struct dma_chan *chan) ++{ ++ return &chan->dev->device; ++} ++ ++static inline struct ingenic_dma_chan *to_ingenic_dma_chan(struct dma_chan *chan) ++{ ++ return container_of(chan, struct ingenic_dma_chan, vc.chan); ++} ++ ++static inline struct ingenic_dma_sdesc *to_ingenic_dma_sdesc(struct virt_dma_desc *vd) ++{ ++ return container_of(vd, struct ingenic_dma_sdesc, vd); ++} ++#endif /*__INGENIC_DMA_H__*/ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_i2c_busses_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_i2c_busses_Kconfig.patch new file mode 100644 index 00000000..ab5094c9 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_i2c_busses_Kconfig.patch @@ -0,0 +1,36 @@ +diff -drupN a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig +--- a/drivers/i2c/busses/Kconfig 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/i2c/busses/Kconfig 2022-06-09 05:02:29.000000000 +0300 +@@ -993,6 +993,32 @@ config I2C_RCAR + This driver can also be built as a module. If so, the module + will be called i2c-rcar. + ++config I2C_INGENIC ++ bool "Ingenic SoC based on Xburst2 arch's I2C controler Driver support" ++ help ++ Say Y here in order to support Ingenic SoC's I2C Controller Drvier ++ ++config I2C_NON_RESTART_MODE ++ bool "controler i2c no restart mode" ++ depends on I2C_INGENIC ++ default n ++ ++config I2C_FIFO_LEN ++ int "INGENIC I2C Controller FIFO length" ++ default 64 ++ depends on I2C_INGENIC ++ help ++ M200 and JZ4775 have 64 entries FIFO. ++ ++config I2C_DEBUG_INFO ++ bool "enable or disable Ingenic Soc's I2C driver debug info" ++ default n ++ depends on I2C_INGENIC ++ help ++ I2C debug print info, you can get the debug information from ++ /sys/devices/platform/i2c-ingenic.x/debug_info, ++ for example, echo 3 > /sys/devices/platform/i2c-ingenic.x/debug ++ + comment "External I2C/SMBus adapter drivers" + + config I2C_DIOLAN_U2C diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_i2c_busses_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_i2c_busses_Makefile.patch new file mode 100644 index 00000000..de49eb34 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_i2c_busses_Makefile.patch @@ -0,0 +1,11 @@ +diff -drupN a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile +--- a/drivers/i2c/busses/Makefile 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/i2c/busses/Makefile 2022-06-09 05:02:29.000000000 +0300 +@@ -96,6 +96,7 @@ obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o + obj-$(CONFIG_I2C_XLR) += i2c-xlr.o + obj-$(CONFIG_I2C_XLP9XX) += i2c-xlp9xx.o + obj-$(CONFIG_I2C_RCAR) += i2c-rcar.o ++obj-$(CONFIG_I2C_INGENIC) += i2c-ingenic.o + + # External I2C/SMBus adapter drivers + obj-$(CONFIG_I2C_DIOLAN_U2C) += i2c-diolan-u2c.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_i2c_busses_i2c-ingenic.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_i2c_busses_i2c-ingenic.c.patch new file mode 100644 index 00000000..42e16eb9 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_i2c_busses_i2c-ingenic.c.patch @@ -0,0 +1,1098 @@ +diff -drupN a/drivers/i2c/busses/i2c-ingenic.c b/drivers/i2c/busses/i2c-ingenic.c +--- a/drivers/i2c/busses/i2c-ingenic.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/i2c/busses/i2c-ingenic.c 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,1094 @@ ++/* drivers/i2c/busses/i2c-v12-ingenic.c ++ * ++ * Copyright (C) 2014 Ingenic Semiconductor Co., Ltd. ++ * http://www.ingenic.com ++ * Sun Jiwei ++ * ++ * I2C adapter driver for the Ingenic I2C controller ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define I2C_CTRL (0x00) ++#define I2C_TAR (0x04) ++#define I2C_SAR (0x08) ++#define I2C_DC (0x10) ++#define I2C_SHCNT (0x14) ++#define I2C_SLCNT (0x18) ++#define I2C_FHCNT (0x1C) ++#define I2C_FLCNT (0x20) ++#define I2C_INTST (0x2C) ++#define I2C_INTM (0x30) ++#define I2C_RAW_INTR_STAT (0x34) ++#define I2C_RXTL (0x38) ++#define I2C_TXTL (0x3c) ++#define I2C_CINTR (0x40) ++#define I2C_CRXUF (0x44) ++#define I2C_CRXOF (0x48) ++#define I2C_CTXOF (0x4C) ++#define I2C_CRXREQ (0x50) ++#define I2C_CTXABRT (0x54) ++#define I2C_CRXDONE (0x58) ++#define I2C_CACT (0x5C) ++#define I2C_CSTP (0x60) ++#define I2C_CSTT (0x64) ++#define I2C_CGC (0x68) ++#define I2C_ENB (0x6C) ++#define I2C_STA (0x70) ++#define I2C_TXFLR (0x74) ++#define I2C_RXFLR (0x78) ++#define I2C_SDAHD (0x7C) ++#define I2C_TXABRT (0x80) ++#define I2C_DMACR (0x88) ++#define I2C_DMATDLR (0x8c) ++#define I2C_DMARDLR (0x90) ++#define I2C_SDASU (0x94) ++#define I2C_ACKGC (0x98) ++#define I2C_ENSTA (0x9C) ++#define I2C_FLT (0xA0) ++ ++/* I2C Control Register (I2C_CTRL) */ ++#define I2C_CTRL_SLVDIS (1 << 6) /* after reset slave is disabled */ ++#define I2C_CTRL_REST (1 << 5) ++#define I2C_CTRL_MATP (1 << 4) /* 1: 10bit address 0: 7bit addressing */ ++#define I2C_CTRL_SATP (1 << 3) /* 1: 10bit address 0: 7bit address */ ++#define I2C_CTRL_SPDF (2 << 1) /* fast mode 400kbps */ ++#define I2C_CTRL_SPDS (1 << 1) /* standard mode 100kbps */ ++#define I2C_CTRL_MD (1 << 0) /* master enabled */ ++ ++/* I2C Status Register (I2C_STA) */ ++#define I2C_STA_SLVACT (1 << 6) /* Slave FSM is not in IDLE state */ ++#define I2C_STA_MSTACT (1 << 5) /* Master FSM is not in IDLE state */ ++#define I2C_STA_RFF (1 << 4) /* RFIFO if full */ ++#define I2C_STA_RFNE (1 << 3) /* RFIFO is not empty */ ++#define I2C_STA_TFE (1 << 2) /* TFIFO is empty */ ++#define I2C_STA_TFNF (1 << 1) /* TFIFO is not full */ ++#define I2C_STA_ACT (1 << 0) /* I2C Activity Status */ ++ ++/* i2c interrupt status (I2C_INTST) */ ++#define I2C_INTST_IGC (1 << 11) ++#define I2C_INTST_ISTT (1 << 10) ++#define I2C_INTST_ISTP (1 << 9) ++#define I2C_INTST_IACT (1 << 8) ++#define I2C_INTST_RXDN (1 << 7) ++#define I2C_INTST_TXABT (1 << 6) ++#define I2C_INTST_RDREQ (1 << 5) ++#define I2C_INTST_TXEMP (1 << 4) ++#define I2C_INTST_TXOF (1 << 3) ++#define I2C_INTST_RXFL (1 << 2) ++#define I2C_INTST_RXOF (1 << 1) ++#define I2C_INTST_RXUF (1 << 0) ++ ++/* i2c interrupt mask status (I2C_INTM) */ ++#define I2C_INTM_MIGC (1 << 11) ++#define I2C_INTM_MISTT (1 << 10) ++#define I2C_INTM_MISTP (1 << 9) ++#define I2C_INTM_MIACT (1 << 8) ++#define I2C_INTM_MRXDN (1 << 7) ++#define I2C_INTM_MTXABT (1 << 6) ++#define I2C_INTM_MRDREQ (1 << 5) ++#define I2C_INTM_MTXEMP (1 << 4) ++#define I2C_INTM_MTXOF (1 << 3) ++#define I2C_INTM_MRXFL (1 << 2) ++#define I2C_INTM_MRXOF (1 << 1) ++#define I2C_INTM_MRXUF (1 << 0) ++ ++#define I2C_DC_REST (1 << 10) ++#define I2C_DC_STP (1 << 9) ++#define I2C_DC_READ (1 << 8) ++ ++#define I2C_ENB_I2CENB (1 << 0) /* Enable the i2c */ ++ ++#ifdef CONFIG_I2C_FIFO_LEN ++#define I2C_FIFO_LEN (CONFIG_I2C_FIFO_LEN) ++#else ++#define I2C_FIFO_LEN (64) ++#endif ++ ++#define TX_LEVEL (I2C_FIFO_LEN / 2) ++#define RX_LEVEL (I2C_FIFO_LEN / 2 - 1) ++#define TIMEOUT 0xff ++#define DEBUG_INFO 2 ++#define DEBUG_WARN 1 ++ ++//#define I2C_DEBUG ++/* ++ * msg_end_type: The bus control which need to be send at end of transfer. ++ * @MSG_END_STOP: Send stop pulse at end of transfer. ++ * @MSG_END_REPEAT_START: Send repeat start at end of transfer. ++ */ ++enum msg_end_type { ++ MSG_END_STOP, ++ MSG_END_CONTINUE, ++ MSG_END_REPEAT_START, ++}; ++ ++/* I2C Transmit Abort Status Register (I2C_TXABRT) */ ++static const char *abrt_src[] = { ++ "I2C_TXABRT_ABRT_7B_ADDR_NOACK", ++ "I2C_TXABRT_ABRT_10ADDR1_NOACK", ++ "I2C_TXABRT_ABRT_10ADDR2_NOACK", ++ "I2C_TXABRT_ABRT_XDATA_NOACK", ++ "I2C_TXABRT_ABRT_GCALL_NOACK", ++ "I2C_TXABRT_ABRT_GCALL_READ", ++ "I2C_TXABRT_ABRT_HS_ACKD", ++ "I2C_TXABRT_SBYTE_ACKDET", ++ "I2C_TXABRT_ABRT_HS_NORSTRT", ++ "I2C_TXABRT_SBYTE_NORSTRT", ++ "I2C_TXABRT_ABRT_10B_RD_NORSTRT", ++ "I2C_TXABRT_ABRT_MASTER_DIS", ++ "I2C_TXABRT_ARB_LOST", ++ "I2C_TXABRT_SLVFLUSH_TXFIFO", ++ "I2C_TXABRT_SLV_ARBLOST", ++ "I2C_TXABRT_SLVRD_INTX", ++}; ++ ++/* I2C standard mode high count register(I2CSHCNT) */ ++#define I2CSHCNT_ADJUST(n) (((n) - 8) < 6 ? 6 : ((n) - 8)) ++/* I2C standard mode low count register(I2CSLCNT) */ ++#define I2CSLCNT_ADJUST(n) (((n) - 1) < 8 ? 8 : ((n) - 1)) ++/* I2C fast mode high count register(I2CFHCNT) */ ++#define I2CFHCNT_ADJUST(n) (((n) - 8) < 6 ? 6 : ((n) - 8)) ++/* I2C fast mode low count register(I2CFLCNT) */ ++#define I2CFLCNT_ADJUST(n) (((n) - 1) < 8 ? 8 : ((n) - 1)) ++ ++struct i2c_ingenic { ++ void __iomem *iomem; ++ struct device *dev; ++ int irq; ++ struct clk *clk; ++ struct i2c_adapter adap; ++ ++ enum msg_end_type w_end_type; ++ enum msg_end_type r_end_type; ++ unsigned char *rbuf; ++ unsigned char *wbuf; ++ unsigned int rd_len; ++ int len; ++ ++ struct completion complete; ++ ++ int debug; ++ unsigned int rate; ++ ++ unsigned int timeout_ms; /*ms*/ ++ unsigned int speed_hz; /*hz*/ ++ unsigned int id; /*chip id*/ ++}; ++ ++static inline unsigned short i2c_readl(struct i2c_ingenic *i2c, ++ unsigned short offset); ++#ifdef I2C_DEBUG ++static void i2c_ingenic_dump_regs(struct i2c_ingenic *i2c) ++{ ++ struct i2c_ingenic *i2c_id = i2c; ++ ++#define PRINT_REG_WITH_ID(reg_name, id) \ ++ dev_info(&(i2c->adap.dev),"--"#reg_name " 0x%08x\n",i2c_readl(id, reg_name)) ++ ++ PRINT_REG_WITH_ID(I2C_CTRL, i2c_id); ++ PRINT_REG_WITH_ID(I2C_INTST, i2c_id); ++ PRINT_REG_WITH_ID(I2C_INTM, i2c_id); ++ PRINT_REG_WITH_ID(I2C_RAW_INTR_STAT, i2c_id); ++ PRINT_REG_WITH_ID(I2C_RXTL, i2c_id); ++ PRINT_REG_WITH_ID(I2C_TXTL, i2c_id); ++ PRINT_REG_WITH_ID(I2C_STA, i2c_id); ++ PRINT_REG_WITH_ID(0x78, i2c_id); ++ return; ++ ++ PRINT_REG_WITH_ID(I2C_CTRL, i2c_id); ++ PRINT_REG_WITH_ID(I2C_TAR, i2c_id); ++ PRINT_REG_WITH_ID(I2C_SAR, i2c_id); ++ // PRINT_REG_WITH_ID(I2C_DC, i2c_id); ++ PRINT_REG_WITH_ID(I2C_SHCNT, i2c_id); ++ PRINT_REG_WITH_ID(I2C_SLCNT, i2c_id); ++ PRINT_REG_WITH_ID(I2C_FHCNT, i2c_id); ++ PRINT_REG_WITH_ID(I2C_FLCNT, i2c_id); ++ PRINT_REG_WITH_ID(I2C_INTST, i2c_id); ++ PRINT_REG_WITH_ID(I2C_INTM, i2c_id); ++ PRINT_REG_WITH_ID(I2C_RXTL, i2c_id); ++ PRINT_REG_WITH_ID(I2C_TXTL, i2c_id); ++ PRINT_REG_WITH_ID(I2C_CINTR, i2c_id); ++ PRINT_REG_WITH_ID(I2C_CRXUF, i2c_id); ++ PRINT_REG_WITH_ID(I2C_CRXOF, i2c_id); ++ PRINT_REG_WITH_ID(I2C_CTXOF, i2c_id); ++ PRINT_REG_WITH_ID(I2C_CRXREQ, i2c_id); ++ PRINT_REG_WITH_ID(I2C_CTXABRT, i2c_id); ++ PRINT_REG_WITH_ID(I2C_CRXDONE, i2c_id); ++ PRINT_REG_WITH_ID(I2C_CACT, i2c_id); ++ PRINT_REG_WITH_ID(I2C_CSTP, i2c_id); ++ PRINT_REG_WITH_ID(I2C_CSTT, i2c_id); ++ PRINT_REG_WITH_ID(I2C_CGC, i2c_id); ++ PRINT_REG_WITH_ID(I2C_ENB, i2c_id); ++ PRINT_REG_WITH_ID(I2C_STA, i2c_id); ++ /*debug trans & recive fifo count */ ++ PRINT_REG_WITH_ID(0x74, i2c_id); ++ PRINT_REG_WITH_ID(0x78, i2c_id); ++ ++ PRINT_REG_WITH_ID(I2C_TXABRT, i2c_id); ++ PRINT_REG_WITH_ID(I2C_DMACR, i2c_id); ++ PRINT_REG_WITH_ID(I2C_DMATDLR, i2c_id); ++ PRINT_REG_WITH_ID(I2C_DMARDLR, i2c_id); ++ PRINT_REG_WITH_ID(I2C_SDASU, i2c_id); ++ PRINT_REG_WITH_ID(I2C_ACKGC, i2c_id); ++ PRINT_REG_WITH_ID(I2C_ENSTA, i2c_id); ++ PRINT_REG_WITH_ID(I2C_SDAHD, i2c_id); ++#undef PRINT_REG_WITH_ID ++} ++#else /* I2C_DEBUG */ ++static void i2c_ingenic_dump_regs(struct i2c_ingenic *i2c) {} ++#endif /* !I2C_DEBUG */ ++ ++static inline unsigned short i2c_readl(struct i2c_ingenic *i2c, ++ unsigned short offset) ++{ ++ return readl(i2c->iomem + offset); ++} ++ ++static inline void i2c_writel(struct i2c_ingenic *i2c, unsigned short offset, ++ unsigned short value) ++{ ++ writel(value, i2c->iomem + offset); ++} ++ ++static int i2c_ingenic_enable(struct i2c_ingenic *i2c, int enable) ++{ ++ int timeout = TIMEOUT; ++ ++ i2c_writel(i2c, I2C_ENB, enable); ++ while (((i2c_readl(i2c, I2C_ENSTA) & I2C_ENB_I2CENB) == !enable) && (--timeout > 0)) ++ msleep(1); ++ ++ if (timeout) ++ return 0; ++ ++ dev_err(&(i2c->adap.dev), "%s i2c%d failed\n", enable?"enable":"disable", i2c->adap.nr); ++ return -ETIMEDOUT; ++} ++ ++static void i2c_ingenic_reset(struct i2c_ingenic *i2c) ++{ ++ i2c_readl(i2c, I2C_CTXABRT); ++ i2c_readl(i2c, I2C_INTST); ++ ++ i2c_ingenic_enable(i2c, 0); ++ udelay(10); /* Don't know why to wait for 10us */ ++ i2c_ingenic_enable(i2c, 1); ++} ++ ++/* function: send read command ++ * return: 0, successful ++ * 1, txfifo valid entry is more than receive fifo, before send read command, ++ * must be read. ++ * 2, txfifo count is 0 or rxfifo count is 0. ++ * */ ++static inline unsigned int i2c_send_rcmd(struct i2c_ingenic *i2c) ++{ ++ unsigned int tx_count, rx_count, count, tx_valid, rx_valid; ++ ++ tx_valid = i2c_readl(i2c, I2C_TXFLR); ++ rx_valid = i2c_readl(i2c, I2C_RXFLR); ++ tx_count = I2C_FIFO_LEN - tx_valid; ++ rx_count = I2C_FIFO_LEN - rx_valid; ++ ++#ifdef CONFIG_I2C_DEBUG_INFO ++ if(i2c->debug > DEBUG_INFO) ++ dev_info(&(i2c->adap.dev), ++ "%s, tx_valid = %d, rx_valid = %d," ++ " tx_count = %d, rx_count = %d\n", ++ __func__, tx_valid, rx_valid, tx_count, rx_count); ++#endif ++ ++ if (tx_valid > rx_count) { ++ dev_warn(&(i2c->adap.dev), ++ "\n\n###Warrning: I2C transfer fifo valid entry is more receive fifo, " ++ "before send read cmd, please read data from " ++ "the read fifo.\n\n"); ++ return 1; ++ } ++ ++ if (!tx_count || !rx_count) { ++ dev_warn(&(i2c->adap.dev), ++ "\n\n###Warrning: I2C receive fifo or transfer fifo is full, " ++ "before send read cmd, please read data from " ++ "the read fifo or wait some time.\n\n"); ++ return 2; ++ } ++ ++ count = min3(i2c->rd_len, tx_count, rx_count); ++ ++#ifdef CONFIG_I2C_DEBUG_INFO ++ if (i2c->debug > DEBUG_INFO) ++ dev_info(&(i2c->adap.dev), ++ "%s, Before send read cmd, " ++ "need_send = %d, left_send = %d\n", ++ __func__, count ,i2c->rd_len); ++#endif ++ ++ i2c->rd_len -= count; ++ ++ if (!i2c->rd_len) { ++ while (count > 1) { ++ i2c_writel(i2c, I2C_DC, I2C_DC_READ); ++ count--; ++ } ++ if (i2c->r_end_type == MSG_END_STOP) { ++ i2c_writel(i2c, I2C_DC, I2C_DC_READ | I2C_DC_STP); ++ } else { ++ i2c_writel(i2c, I2C_DC, I2C_DC_READ); ++ } ++ } else { ++ while (count > 0) { ++ i2c_writel(i2c, I2C_DC, I2C_DC_READ); ++ count--; ++ } ++ } ++ ++#ifdef CONFIG_I2C_DEBUG_INFO ++ if(i2c->debug > DEBUG_INFO) ++ dev_info(&(i2c->adap.dev), ++ "%s, After send read cmd, " ++ "left_send = %d\n", ++ __func__, i2c->rd_len); ++#endif ++ return 0; ++} ++ ++#ifdef CONFIG_I2C_DEBUG_INFO ++static ssize_t enable_debug(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t size) ++{ ++ int rc; ++ unsigned long enable; ++ struct i2c_ingenic *i2c = (struct i2c_ingenic *)dev_get_drvdata(dev); ++ ++ rc = kstrtol(buf, 0, &enable); ++ if (rc) ++ return rc; ++ ++ if ((enable >= 0) && (enable <= DEBUG_INFO + 1)) ++ i2c->debug = enable; ++ else ++ goto err; ++ ++ return size; ++err: ++ pr_err("Please input correct number(enable >= 0 && enable <= 5)" ++ " to disable or enable debug info print\n"); ++ return -EAGAIN; ++} ++ ++static struct device_attribute attributes[] = { ++ __ATTR(debug_info, 0200, NULL, enable_debug), ++}; ++ ++static int create_debug_sysfs_interface(struct device *dev) ++{ ++ int i; ++ for (i = 0; i < ARRAY_SIZE(attributes); i++) ++ if (device_create_file(dev, attributes + i)) ++ goto err; ++ return 0; ++ ++err: ++ for( ; i >= 0; i--) ++ device_remove_file(dev, attributes + i); ++ return -1; ++} ++#endif ++ ++static irqreturn_t i2c_ingenic_irq(int irqno, void *dev_id) ++{ ++ unsigned short tmp, intst, intmsk; ++ struct i2c_ingenic *i2c = dev_id; ++ ++ intst = i2c_readl(i2c, I2C_INTST); ++ intmsk = i2c_readl(i2c, I2C_INTM); ++ ++#ifdef CONFIG_I2C_DEBUG_INFO ++ if (i2c->debug > DEBUG_INFO) ++ dev_info(&(i2c->adap.dev), "--I2C irq register INTST:0x%08x\n", intst); ++#endif ++ ++ if ((intst & I2C_INTST_TXABT) && (intmsk & I2C_INTM_MTXABT)) { ++ dev_err(&(i2c->adap.dev), ++ "%s %d, I2C transfer error, ABORT interrupt\n", ++ __func__, __LINE__); ++ goto END_TRSF_IRQ_HND; ++ } ++ ++ if ((intst & I2C_INTST_ISTP) && (intmsk & I2C_INTM_MISTP)) { ++ i2c_readl(i2c, I2C_CSTP); /* clear STP bit */ ++#ifdef CONFIG_I2C_DEBUG_INFO ++ if (i2c->debug > DEBUG_INFO) { ++ dev_info(&(i2c->adap.dev), ++ "%s, Now stop condition has occurred," ++ "and left data length is %d\n", ++ __func__, i2c->len); ++ } ++#endif ++ ++ if (i2c->len == 0) ++ goto END_TRSF_IRQ_HND; ++ } ++ ++ if ((intmsk & I2C_INTM_MTXEMP) && (intst & I2C_INTST_TXEMP)) { ++ if (!i2c->len) { ++ if (i2c->w_end_type == MSG_END_REPEAT_START) { ++ goto END_TRSF_IRQ_HND; ++ } else { ++ tmp = i2c_readl(i2c, I2C_INTM); ++ tmp &= ~I2C_INTM_MTXEMP; ++ i2c_writel(i2c, I2C_INTM, tmp); ++ } ++ } else { ++ while ((i2c->len > 0) && ++ (i2c_readl(i2c, I2C_STA) & I2C_STA_TFNF)) { ++ tmp = *i2c->wbuf++; ++ if (i2c->len == 1) { ++ if (i2c->w_end_type == MSG_END_STOP) ++ tmp |= I2C_DC_STP; ++ } ++ ++ i2c_writel(i2c, I2C_DC, tmp); ++ i2c->len -= 1; ++ } ++ ++ if (i2c->len == 0) { ++ i2c_writel(i2c, I2C_TXTL, 0); ++ } ++ } ++ } ++ ++ if ((intst & I2C_INTST_RXFL) && (intmsk & I2C_INTM_MRXFL)) { ++#ifdef CONFIG_I2C_DEBUG_INFO ++ if (i2c->debug >= DEBUG_INFO) { ++ dev_info(&(i2c->adap.dev), ++ "%s, Before read I2C_DC, " ++ "left_send_cmd = %d, left_read_cnt = %d," ++ " rx_valid = %d, tx_valid = %d\n", ++ __func__, i2c->rd_len, i2c->len, ++ i2c_readl(i2c, I2C_RXFLR), i2c_readl(i2c, I2C_TXFLR)); ++ } ++#endif ++ ++ while ((i2c_readl(i2c, I2C_STA) & I2C_STA_RFNE) && ++ (i2c->len > 0)) { ++ tmp = i2c_readl(i2c, I2C_DC) & 0xff; ++ *i2c->rbuf++ = tmp; ++ i2c->len--; ++ } ++ ++#ifdef CONFIG_I2C_DEBUG_INFO ++ if (i2c->debug >= DEBUG_INFO) ++ dev_info(&(i2c->adap.dev), ++ "%s, After read I2C_DC, " ++ "left_read_cnt = %d," ++ " rx_valid = %d, tx_valid = %d\n", ++ __func__, i2c->len, ++ i2c_readl(i2c, I2C_RXFLR), i2c_readl(i2c, I2C_TXFLR)); ++#endif ++ ++ if (i2c->len == 0) { ++ goto END_RECE_IRQ_HND; ++ } ++ ++ if (i2c->len <= I2C_FIFO_LEN) { ++ i2c_writel(i2c, I2C_RXTL, i2c->len - 1); ++ } ++ ++ if (i2c_send_rcmd(i2c)) { ++ dev_err(&(i2c->adap.dev), ++ "%s %d, I2C controller has BUG," ++ " RXFLR or TXFLR can not clear\n", ++ __func__, __LINE__); ++ BUG(); ++ } ++ ++#ifdef CONFIG_I2C_DEBUG_INFO ++ if (i2c->debug > DEBUG_INFO) ++ dev_info(&(i2c->adap.dev), ++ "%s, After send read command, " ++ "left_send_cmd = %d, " ++ "left_read_cnt = %d\n", ++ __func__, i2c->rd_len, i2c->len); ++#endif ++ } ++ ++ if ((intst & I2C_INTST_RXOF) && (intmsk & I2C_INTM_MRXOF)) { ++ dev_err(&(i2c->adap.dev), ++ "%s %d, I2C transfer error, RXFIFO over full\n", ++ __func__, __LINE__); ++ i2c_readl(i2c, I2C_CRXOF); /* clear RXOF bit */ ++ } ++ ++ if ((intst & I2C_INTST_TXOF) && (intmsk & I2C_INTM_MTXOF)) { ++ dev_err(&(i2c->adap.dev), ++ "%s %d, I2C transfer error, TXFIFO over full\n", ++ __func__, __LINE__); ++ i2c_readl(i2c, I2C_CTXOF); /* clear TXOF bit */ ++ goto END_TRSF_IRQ_HND; ++ } ++ ++ return IRQ_HANDLED; ++END_RECE_IRQ_HND: ++END_TRSF_IRQ_HND: ++ i2c_writel(i2c, I2C_INTM, 0); ++ complete(&i2c->complete); ++ return IRQ_HANDLED; ++} ++ ++static void txabrt(struct i2c_ingenic *i2c, int src) ++{ ++ int i; ++ ++ dev_err(&(i2c->adap.dev), "--I2C txabrt:\n"); ++ for (i = 0; i < 16; i++) { ++ if (src & (0x1 << i)) ++ dev_info(&(i2c->adap.dev), "--I2C TXABRT[%d]=%s\n", i, ++ abrt_src[i]); ++ } ++} ++ ++static inline int xfer_read(struct i2c_ingenic *i2c, unsigned char *buf, int len, ++ enum msg_end_type end_type) ++{ ++ int ret = 0; ++ long timeout; ++ unsigned short tmp; ++ unsigned int wait_complete_timeout_ms; ++ ++ wait_complete_timeout_ms = ++ len * 1000 * 9 * 2 / i2c->rate + i2c->timeout_ms; ++ ++#ifdef CONFIG_I2C_DEBUG_INFO ++ if (i2c->debug > DEBUG_WARN) ++ dev_info(&(i2c->adap.dev), ++ "%s, Begin read msg, want to read length is %d\n", ++ __func__, len); ++ memset(buf, 0, len); ++#endif ++ ++ i2c->rd_len = len; ++ i2c->len = len; ++ i2c->rbuf = buf; ++ i2c->r_end_type = end_type; ++ ++ i2c_readl(i2c, I2C_CSTP); /* clear STP bit */ ++ i2c_readl(i2c, I2C_CTXOF); /* clear TXOF bit */ ++ i2c_readl(i2c, I2C_CTXABRT); /* clear TXABRT bit */ ++ ++ if (len <= I2C_FIFO_LEN) { ++ i2c_writel(i2c, I2C_RXTL, len - 1); ++ } else { ++ i2c_writel(i2c, I2C_RXTL, RX_LEVEL); ++ } ++ ++ while (i2c_readl(i2c, I2C_STA) & I2C_STA_RFNE) { ++ i2c_readl(i2c, I2C_DC); ++ } ++ if (i2c_send_rcmd(i2c)) ++ BUG(); ++ ++ tmp = I2C_INTM_MRXFL | I2C_INTM_MTXABT; ++ if (end_type == MSG_END_STOP) ++ tmp |= I2C_INTM_MISTP; ++ i2c_writel(i2c, I2C_INTM, tmp); ++ ++ ++ timeout = wait_for_completion_timeout(&i2c->complete, ++ msecs_to_jiffies ++ (wait_complete_timeout_ms)); ++ if (!timeout) { ++ dev_err(&(i2c->adap.dev), "--I2C irq read timeout\n"); ++ i2c_ingenic_dump_regs(i2c); ++ ret = -ETIMEDOUT; ++ } ++ ++ tmp = i2c_readl(i2c, I2C_TXABRT); ++ if (tmp) { ++ txabrt(i2c, tmp); ++ if (tmp > 0x1 && tmp < 0x10) ++ ret = -ENXIO; ++ else ++ ret = -EIO; ++ // ABRT_GCALL_READ ++ if (tmp & (1 << 5)) { ++ ret = -EAGAIN; ++ } ++ i2c_readl(i2c, I2C_CTXABRT); ++ } ++ ++ if (ret < 0) ++ i2c_ingenic_reset(i2c); ++ ++#ifdef CONFIG_I2C_DEBUG_INFO ++ if (i2c->debug > DEBUG_WARN) ++ dev_info(&(i2c->adap.dev), ++ "%s, Reading msg over\n", __func__); ++#endif ++ ++ return ret; ++} ++ ++static inline int xfer_write(struct i2c_ingenic *i2c, unsigned char *buf, int len, ++ enum msg_end_type end_type) ++{ ++ int ret = 0; ++ long timeout = TIMEOUT; ++ unsigned short reg_tmp; ++ unsigned int wait_complete_timeout_ms; ++ ++ wait_complete_timeout_ms = ++ len * 1000 * 9 * 2 / i2c->rate + i2c->timeout_ms; ++ ++#ifdef CONFIG_I2C_DEBUG_INFO ++ if (i2c->debug > DEBUG_WARN) ++ dev_info(&(i2c->adap.dev), ++ "%s, Begin write msg, want to write length is %d\n", ++ __func__, len); ++#endif ++ i2c->wbuf = buf; ++ i2c->len = len; ++ ++ i2c_writel(i2c, I2C_TXTL, TX_LEVEL); ++ ++ i2c_readl(i2c, I2C_CSTP); /* clear STP bit */ ++ i2c_readl(i2c, I2C_CTXOF); /* clear TXOF bit */ ++ i2c_readl(i2c, I2C_CTXABRT); /* clear TXABRT bit */ ++ ++ i2c->w_end_type = end_type; ++ while ((i2c_readl(i2c, I2C_STA) & I2C_STA_TFNF) && (i2c->len > 0)) { ++ reg_tmp = *i2c->wbuf++; ++ if (i2c->len == 1) { ++ if (end_type == MSG_END_STOP) { ++ reg_tmp |= I2C_DC_STP; ++ } ++ } ++ i2c_writel(i2c, I2C_DC, reg_tmp); ++ ++ i2c->len -= 1; ++ } ++ ++ if (i2c->len == 0) { ++ i2c_writel(i2c, I2C_TXTL, 0); ++ } ++ ++ reg_tmp = I2C_INTM_MTXEMP | I2C_INTM_MTXABT | I2C_INTM_MTXOF; ++ if (end_type == MSG_END_STOP) ++ reg_tmp |= I2C_INTM_MISTP; ++ ++ i2c_writel(i2c, I2C_INTM, reg_tmp); ++ ++ timeout = wait_for_completion_timeout(&i2c->complete, ++ msecs_to_jiffies ++ (wait_complete_timeout_ms)); ++ ++ if (!timeout) { ++ dev_err(&(i2c->adap.dev), "--I2C pio write wait timeout\n"); ++ i2c_ingenic_dump_regs(i2c); ++ ret = -ETIMEDOUT; ++ } ++ ++ reg_tmp = i2c_readl(i2c, I2C_TXABRT); ++ if (reg_tmp) { ++ txabrt(i2c, reg_tmp); ++ if (reg_tmp > 0x1 && reg_tmp < 0x10) ++ ret = -ENXIO; ++ else ++ ret = -EIO; ++ //after I2C_TXABRT_ABRT_XDATA_NOACK error,this required core to resend ++ if (reg_tmp & 8) { ++ ret = -EAGAIN; ++ } ++ i2c_readl(i2c, I2C_CTXABRT); ++ } ++ ++#ifdef CONFIG_I2C_DEBUG_INFO ++ if (i2c->debug > DEBUG_WARN) ++ dev_info(&(i2c->adap.dev), ++ "%s, Write msg over\n", __func__); ++#endif ++ return ret; ++} ++ ++static int i2c_disable_clk(struct i2c_ingenic *i2c) ++{ ++ int timeout = 10; ++ int tmp = i2c_readl(i2c, I2C_STA); ++ ++ while ((tmp & I2C_STA_MSTACT) && (--timeout > 0)) { ++ udelay(90); ++ tmp = i2c_readl(i2c, I2C_STA); ++ } ++ if (timeout > 0) { ++ clk_disable_unprepare(i2c->clk); ++ return 0; ++ } else { ++ dev_err(&(i2c->adap.dev), ++ "--I2C disable clk timeout, I2C_STA = 0x%x\n", tmp); ++ i2c_ingenic_reset(i2c); ++ clk_disable_unprepare(i2c->clk); ++ return -ETIMEDOUT; ++ } ++} ++ ++static int i2c_ingenic_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int count) ++{ ++ int i, ret = 0; ++ struct i2c_ingenic *i2c = adap->algo_data; ++ ++#ifdef CONFIG_I2C_DEBUG_INFO ++ if (i2c->debug > DEBUG_WARN) { ++ dev_info(&(i2c->adap.dev), ++ "\n\n\n%s, Begin master xfer, want to transfer msg count is %d\n", ++ __func__, count); ++ } ++#endif ++ clk_prepare_enable(i2c->clk); ++ ++ i2c_writel(i2c, I2C_TAR, msg->addr); ++ ++ for (i = 0; i < count; i++, msg++) { ++ enum msg_end_type end_type = MSG_END_STOP; ++ if (i < (count - 1)) { ++ if (msg[i + 1].flags & I2C_M_NOSTART) { ++ end_type = MSG_END_CONTINUE; /* have no STOP and START */ ++ } else { ++ end_type = MSG_END_REPEAT_START; /* have no STOP but have RESTART */ ++ } ++ } ++ ++ reinit_completion(&i2c->complete); ++ ++#ifdef CONFIG_I2C_DEBUG_INFO ++ if (i2c->debug > DEBUG_WARN) ++ dev_info(&(i2c->adap.dev), ++ "%s, Now transfer msg: %d\n", __func__, i); ++#endif ++ if (msg->flags & I2C_M_RD) { ++ ret = xfer_read(i2c, msg->buf, msg->len, end_type); ++ } else { ++ ret = xfer_write(i2c, msg->buf, msg->len, end_type); ++ } ++ if (ret < 0) { ++ i2c_ingenic_reset(i2c); ++ clk_disable_unprepare(i2c->clk); ++ goto ERR; ++ } ++ } ++ ++ if (i2c_disable_clk(i2c)) { ++ ret = -ETIMEDOUT; ++ goto ERR; ++ } ++ ++#ifdef CONFIG_I2C_DEBUG_INFO ++ if (i2c->debug > DEBUG_WARN) ++ dev_info(&(i2c->adap.dev), ++ "%s, Transfer msg over\n\n\n", __func__); ++#endif ++ ++ERR: ++ return ret ? : i; ++} ++ ++static u32 i2c_ingenic_functionality(struct i2c_adapter *adap) ++{ ++ unsigned int ret; ++ ret = I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR; ++ ++ return ret; ++} ++ ++static const struct i2c_algorithm i2c_ingenic_algorithm = { ++ .master_xfer = i2c_ingenic_xfer, ++ .functionality = i2c_ingenic_functionality, ++}; ++ ++static int i2c_set_speed(struct i2c_ingenic *i2c, int rate) ++{ ++ long dev_clk = clk_get_rate(i2c->clk); ++ long cnt_high = 0; /* HIGH period count of the SCL clock */ ++ long cnt_low = 0; /* LOW period count of the SCL clock */ ++ long setup_time = 0; ++ long hold_time = 0; ++ unsigned short tmp; ++ ++ i2c->rate = rate; ++ if (i2c_ingenic_enable(i2c, 0)) ++ dev_info(&(i2c->adap.dev), "i2c not disable\n"); ++ if (rate <= 100000) { ++ tmp = 0x43 | (1 << 5); /* standard speed mode */ ++ i2c_writel(i2c, I2C_CTRL, tmp); ++ } else { ++ tmp = 0x45 | (1 << 5); /* fast speed mode */ ++ i2c_writel(i2c, I2C_CTRL, tmp); ++ } ++ ++ /* high ++ * ____ ____ ____ ____ ++ * clk __| | |___| |____| |____| |___ ++ * | | | ++ * | | | ++ * |_|_| _________ ____ ++ * data __/ | |\___/ \____/ \____ ++ * setup->| |<| ++ * ->| |<-hold ++ */ ++ ++ //setup_time = (10 000 000/(rate*4)) + 1; ++ setup_time = (dev_clk / (rate * 4)); ++ if (setup_time > 1) ++ setup_time -= 1; ++ //hold_time = (10000000/(rate*4)) - 1; ++ hold_time = (dev_clk / (rate * 4)); ++ ++ /* high ++ * ____ ____ ++ * clk __| |___| |____ ++ * low ++ * |<--period--->| ++ * ++ */ ++ cnt_high = dev_clk / (rate * 2); ++ cnt_low = dev_clk / (rate * 2); ++ ++ /*dev_info(&(i2c->adap.dev), "set:%ld hold:%ld dev=%ld h=%ld l=%ld\n", ++ setup_time, hold_time, dev_clk, cnt_high, cnt_low);*/ ++ if (setup_time > 255) ++ setup_time = 255; ++ if (setup_time <= 0) ++ setup_time = 1; ++ if (hold_time > 0xFFFF) ++ hold_time = 0xFFFF; ++ ++ if (rate <= 100000) { ++ i2c_writel(i2c, I2C_SHCNT, I2CSHCNT_ADJUST(cnt_high)); ++ i2c_writel(i2c, I2C_SLCNT, I2CSLCNT_ADJUST(cnt_low)); ++ } else { ++ i2c_writel(i2c, I2C_FHCNT, I2CFHCNT_ADJUST(cnt_high)); ++ i2c_writel(i2c, I2C_FLCNT, I2CFLCNT_ADJUST(cnt_low)); ++ } ++ ++ i2c_writel(i2c, I2C_SDASU, setup_time & 0xff); ++ i2c_writel(i2c, I2C_SDAHD, hold_time); ++ ++ return 0; ++} ++ ++#ifndef CONFIG_I2C_INGENICV10_WAIT_MS ++#define DEF_INGENIC_I2C_WAIT_TIMEOUT_MS (1000) ++#else ++#define DEF_INGENIC_I2C_WAIT_TIMEOUT_MS (CONFIG_I2C_INGENICV10_WAIT_MS) ++#endif ++ ++#define DEF_INGENIC_I2C_SPEED_HZ (400000) ++static void ingenic_i2c_parse_dt(struct device_node *np, struct i2c_ingenic *i2c) ++{ ++ u32 timeout, speed; ++ int id; ++ ++ if (!of_property_read_u32(np, "timeout", &timeout)) ++ i2c->timeout_ms = timeout; ++ else ++ i2c->timeout_ms = DEF_INGENIC_I2C_WAIT_TIMEOUT_MS; ++ ++ if (!of_property_read_u32(np, "clock-frequency", &speed)) ++ i2c->speed_hz = speed; ++ else ++ i2c->speed_hz = DEF_INGENIC_I2C_SPEED_HZ; ++ ++ if ((id = of_alias_get_id(np, "i2c")) >= 0) ++ i2c->id = id; ++ else ++ i2c->id = -1; ++} ++ ++ ++static int i2c_ingenic_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ struct i2c_ingenic *i2c; ++ struct resource *res; ++ unsigned int reg_tmp; ++ char name[20]; ++ int i2c_id; ++ ++ i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); ++ if (!i2c) ++ return -ENOMEM; ++ ++ i2c->dev = &pdev->dev; ++ if (!pdev->dev.of_node) { ++ i2c->timeout_ms = DEF_INGENIC_I2C_WAIT_TIMEOUT_MS; ++ i2c->speed_hz = DEF_INGENIC_I2C_SPEED_HZ; ++ i2c->id = pdev->id; ++ res = platform_get_resource(pdev, IORESOURCE_BUS, 0); ++ if (res) ++ i2c->speed_hz = res->start * 1000; ++ } else ++ ingenic_i2c_parse_dt(pdev->dev.of_node, i2c); ++ ++ i2c->adap.owner = THIS_MODULE; ++ i2c->adap.algo = &i2c_ingenic_algorithm; ++ i2c->adap.retries = 5; ++ i2c->adap.timeout = 5; ++ i2c->adap.algo_data = i2c; ++ i2c->adap.dev.parent = &pdev->dev; ++ i2c->adap.nr = i2c->id; ++ ++ i2c->adap.dev.of_node = pdev->dev.of_node; ++ ++ i2c_id = i2c->id; ++ if (i2c_id >= 0) ++ sprintf(i2c->adap.name, "i2c%u", i2c->id); ++ else ++ sprintf(i2c->adap.name, "%s", dev_name(&pdev->dev)); ++ ++ sprintf(name, "gate_%s", i2c->adap.name); ++ ++ i2c->clk = devm_clk_get(&pdev->dev, name); ++ if (!i2c->clk) ++ return -ENODEV; ++ ++ if(clk_prepare(i2c->clk) < 0) { ++ dev_err(&pdev->dev, "failed to prepare for clk %s\n", __clk_get_name(i2c->clk)); ++ return -ENODEV; ++ } ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) ++ return -ENOENT; ++ ++ i2c->iomem = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(i2c->iomem)) ++ return PTR_ERR(i2c->iomem); ++ ++ i2c->irq = platform_get_irq(pdev, 0); ++ if (i2c->irq < 0) ++ return i2c->irq; ++ ++ ret = devm_request_irq(&pdev->dev, i2c->irq, ++ i2c_ingenic_irq, 0, i2c->adap.name, i2c); ++ if (ret) ++ return -ENODEV; ++ ++ ++ clk_enable(i2c->clk); ++ ++ i2c_set_speed(i2c, i2c->speed_hz); ++ ++#if 0 ++ reg_tmp = i2c_readl(i2c, I2C_DC); ++ reg_tmp &= ~I2C_DC_STP; ++ i2c_writel(i2c, I2C_DC, reg_tmp); ++#endif ++ ++ reg_tmp = i2c_readl(i2c, I2C_CTRL); ++#if defined(CONFIG_I2C_NON_RESTART_MODE) ++ reg_tmp &= ~I2C_CTRL_REST; ++#else ++ reg_tmp |= I2C_CTRL_REST; ++#endif ++ i2c_writel(i2c, I2C_CTRL, reg_tmp); ++ ++ // for jgao WHY? ++ // i2c_writel(i2c, I2C_FLT, 0xF); /*set filter*/ ++ ++ i2c_writel(i2c, I2C_INTM, 0x0); ++ ++ platform_set_drvdata(pdev, i2c); ++ ++ i2c_ingenic_enable(i2c, 1); ++ ++ clk_disable_unprepare(i2c->clk); ++ ++ init_completion(&i2c->complete); ++ ++ ret = i2c_add_numbered_adapter(&i2c->adap); ++ if (ret < 0) { ++ dev_err(&pdev->dev, KERN_INFO"I2C: Failed to add bus\n"); ++ clk_disable_unprepare(i2c->clk); ++ return ret; ++ } ++ ++#ifdef CONFIG_I2C_DEBUG_INFO ++ ret = create_debug_sysfs_interface(&pdev->dev); ++ if (ret < 0) ++ dev_err(&pdev->dev, "create debug sysfs interface failed\n"); ++#endif ++ dev_info(&pdev->dev, "register i2c%d success.\n", i2c->id); ++ return 0; ++} ++ ++static int i2c_ingenic_remove(struct platform_device *pdev) ++{ ++ struct i2c_ingenic *i2c = platform_get_drvdata(pdev); ++ clk_disable_unprepare(i2c->clk); ++ i2c_del_adapter(&i2c->adap); ++ return 0; ++} ++ ++static const struct of_device_id ingenic_i2c_dt_match[] = { ++ { .compatible = "ingenic,i2c" }, ++ { .compatible = "ingenic,x2000-i2c" }, ++ { .compatible = "ingenic,t40-i2c" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ingenic_i2c_dt_match); ++ ++static struct platform_driver i2c_ingenic_driver = { ++ .probe = i2c_ingenic_probe, ++ .remove = i2c_ingenic_remove, ++ .driver = { ++ .name = "ingenic-i2c", ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(ingenic_i2c_dt_match), ++ }, ++}; ++ ++static int __init i2c_ingenic_init(void) ++{ ++ return platform_driver_register(&i2c_ingenic_driver); ++} ++module_init(i2c_ingenic_init); ++ ++static void __exit i2c_ingenic_exit(void) ++{ ++ platform_driver_unregister(&i2c_ingenic_driver); ++} ++module_exit(i2c_ingenic_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("i2c driver for INGENIC SoCs"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_irqchip_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_irqchip_Kconfig.patch new file mode 100644 index 00000000..803cef6b --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_irqchip_Kconfig.patch @@ -0,0 +1,25 @@ +diff -drupN a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig +--- a/drivers/irqchip/Kconfig 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/irqchip/Kconfig 2022-06-09 05:02:29.000000000 +0300 +@@ -193,3 +193,21 @@ config IRQ_MXS + def_bool y if MACH_ASM9260 || ARCH_MXS + select IRQ_DOMAIN + select STMP_DEVICE ++ ++config INGENIC_INTC ++ bool ++ select IRQ_DOMAIN ++ ++config IRQ_INGENIC_CPU ++ bool ++ select IRQ_DOMAIN ++ help ++ Support for ingenic cpu core irq handler. ++ ++config INGENIC_INTC_CHIP ++ bool ++ depends on MACH_XBURST2 ++ select IRQ_DOMAIN ++ help ++ Support for ingenic XBURST2 based SOCs, which intc is ++ near cpu core,and each logic cpu has an intc. diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_irqchip_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_irqchip_Makefile.patch new file mode 100644 index 00000000..0651f2bf --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_irqchip_Makefile.patch @@ -0,0 +1,11 @@ +diff -drupN a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile +--- a/drivers/irqchip/Makefile 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/irqchip/Makefile 2022-06-09 05:02:29.000000000 +0300 +@@ -55,3 +55,7 @@ obj-$(CONFIG_RENESAS_H8S_INTC) += irq-r + obj-$(CONFIG_ARCH_SA1100) += irq-sa11x0.o + obj-$(CONFIG_INGENIC_IRQ) += irq-ingenic.o + obj-$(CONFIG_IMX_GPCV2) += irq-imx-gpcv2.o ++obj-$(CONFIG_INGENIC_INTC) += irq-ingenic.o ++obj-$(CONFIG_IRQ_INGENIC_CPU) += irq-ingenic-cpu.o ++obj-$(CONFIG_INGENIC_INTC_CHIP) += irq-ingenic-chip.o ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_irqchip_irq-ingenic-chip.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_irqchip_irq-ingenic-chip.c.patch new file mode 100644 index 00000000..4c993f2a --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_irqchip_irq-ingenic-chip.c.patch @@ -0,0 +1,532 @@ +diff -drupN a/drivers/irqchip/irq-ingenic-chip.c b/drivers/irqchip/irq-ingenic-chip.c +--- a/drivers/irqchip/irq-ingenic-chip.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/irqchip/irq-ingenic-chip.c 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,528 @@ ++/* ++ * Copyright (C) 2017 Ingenic Semiconductor Co., Ltd. ++ * ++ * Author: dongsheng.qiu, dongsheng.qiu@ingenic.com bo.liu@ingenic.com ++ * ++ * 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. ++ */ ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++#include ++#include ++ ++#define PART_OFF 0x20 ++#define ISR_OFF (0x00) ++#define IMR_OFF (0x04) ++#define IMSR_OFF (0x08) ++#define IMCR_OFF (0x0c) ++#define IPR_OFF (0x10) ++ ++ ++struct cpu_intc_map ++{ ++ unsigned int cpu_num; ++ unsigned int dev_base; ++}; ++static struct cpu_intc_map cpu_intc_map[NR_CPUS]; ++ ++struct core_irq_chip{ ++ void __iomem *iobase; ++ unsigned int next_irq_resp; ++}; ++struct irq_chip_data { ++ void __iomem *iobase[NR_CPUS]; ++ raw_spinlock_t lock; ++ struct cpumask irq_idle_mask; ++ unsigned int wake_up_flag[(INTC_NR_IRQS + 31) / 32]; /* Interrupts which can generate wakeup signal when cpu asleep. */ ++ unsigned char intc_num[INTC_NR_IRQS]; /* Which CPU/INTC does an interrupt current connect to, */ ++ struct cpumask affinity[INTC_NR_IRQS]; /* Which CPU does an interrupt src affinity to. */ ++}; ++struct core_irq_chips { ++ struct core_irq_chip *__percpu *percpu_irq_chip; ++ struct irq_chip_data chip_data; ++ int irq; ++}; ++ ++static struct core_irq_chip irq_chip_buf[NR_CPUS]; ++static struct core_irq_chips g_irq_chips; ++ ++ ++static void percpu_irq_init(struct core_irq_chips *irq_chips, unsigned int cpu_num) ++{ ++ unsigned int base = 0; ++ struct core_irq_chip *irq_chip; ++ int cpu = smp_processor_id(); ++ void __iomem * iobase; ++ int i; ++ ++ for(i = 0;i < NR_CPUS;i++) ++ { ++ if(cpu_intc_map[i].cpu_num == cpu_num) { ++ base = cpu_intc_map[i].dev_base; ++ irq_chip = &irq_chip_buf[i]; ++ break; ++ } ++ } ++ ++ if(base == 0){ ++ pr_err("Error: CPU[%d] don't finded intc base address\n",cpu_num); ++ return; ++ } ++ ++ iobase = (void *)base; ++ ++ irq_chip = &irq_chip_buf[cpu]; ++ ++ irq_chip->iobase = iobase; ++ irq_chip->next_irq_resp = 0; ++ irq_chips->chip_data.iobase[cpu] = iobase; ++ ++ *this_cpu_ptr(irq_chips->percpu_irq_chip) = irq_chip; ++ enable_percpu_irq(irq_chips->irq, IRQ_TYPE_NONE); ++ ++ pr_info("percpu irq inited.\n"); ++} ++int ingenic_percpu_irq_init(int cpu_num) ++{ ++ percpu_irq_init(&g_irq_chips, cpu_num); ++ return 0; ++} ++EXPORT_SYMBOL_GPL(ingenic_percpu_irq_init); ++ ++static void percpu_irq_deinit(struct core_irq_chips *irq_chips) ++{ ++ disable_percpu_irq(irq_chips->irq); ++} ++ ++void ingenic_percpu_irq_deinit(void) ++{ ++ percpu_irq_deinit(&g_irq_chips); ++} ++EXPORT_SYMBOL_GPL(ingenic_percpu_irq_deinit); ++ ++ ++#ifdef CONFIG_SMP ++static inline void irq_lock(struct irq_chip_data *chip) ++{ ++ raw_spin_lock(&chip->lock); ++} ++ ++static inline void irq_unlock(struct irq_chip_data *chip) ++{ ++ raw_spin_unlock(&chip->lock); ++} ++#else ++static inline void irq_lock(struct irq_chip_data *chip) { } ++static inline void irq_unlock(struct irq_chip_data *chip) { } ++#endif ++ ++ ++static void xburst2_irq_unmask(struct irq_data *data) ++{ ++ struct irq_chip_data *chip = (struct irq_chip_data *)irq_data_get_irq_chip_data(data); ++ void __iomem * iobase; ++ int hwirq = data->hwirq; ++ unsigned int group; ++ unsigned int bit; ++ int intc_num; ++ ++ group = hwirq / 32; ++ bit = 1 << ((hwirq) & 31); ++ irq_lock(chip); ++ intc_num = chip->intc_num[hwirq]; ++ iobase = chip->iobase[intc_num]; ++ writel(bit, iobase + group * PART_OFF + IMCR_OFF); ++ irq_unlock(chip); ++} ++ ++ ++static void xburst2_irq_mask(struct irq_data *data) ++{ ++ struct irq_chip_data *chip = (struct irq_chip_data *)irq_data_get_irq_chip_data(data); ++ void __iomem * iobase; ++ int hwirq = data->hwirq; ++ unsigned int group; ++ unsigned int bit; ++ int intc_num; ++ ++ group = hwirq / 32; ++ bit = 1 << ((hwirq) & 31); ++ irq_lock(chip); ++ intc_num = chip->intc_num[hwirq]; ++ iobase = chip->iobase[intc_num]; ++ writel(bit, iobase + group * PART_OFF + IMSR_OFF); ++ ++#ifdef CONFIG_SMP ++ ingenic_irq_migration(0); ++#endif ++ irq_unlock(chip); ++} ++ ++static int xburst2_irq_set_wake(struct irq_data *data, unsigned int on) ++{ ++ struct irq_chip_data *chip = (struct irq_chip_data *)irq_data_get_irq_chip_data(data); ++ unsigned int group = (data->irq - IRQ_INTC_BASE) / 32; ++ unsigned int bit = 1 << ((data->irq - IRQ_INTC_BASE) & 31); ++ ++ irq_lock(chip); ++ if(on) { ++ chip->wake_up_flag[group] |= bit; ++ }else { ++ chip->wake_up_flag[group] &= ~bit; ++ } ++ irq_unlock(chip); ++ return 0; ++} ++ ++#ifdef CONFIG_SMP ++static int xburst2_set_affinity(struct irq_data *data, const struct cpumask *dest, bool force) ++{ ++ struct irq_chip_data *chip = (struct irq_chip_data *)irq_data_get_irq_chip_data(data); ++ int hwirq = data->hwirq; ++ unsigned int cpu = cpumask_any_and(dest,cpu_online_mask); ++ void __iomem * prev_iobase; ++ void __iomem * iobase; ++ int prev_intc_num; ++ int group; ++ unsigned int bit; ++ ++// printk("########%s, %d, dest->bits %lx, cpu_online_mask->bits: %lx\n", __func__, __LINE__, dest->bits[0], cpu_online_mask->bits[0]); ++ ++ irq_lock(chip); ++ ++ cpumask_and(&chip->affinity[hwirq],dest,cpu_online_mask); ++ ++ prev_intc_num = chip->intc_num[hwirq]; ++ prev_iobase = chip->iobase[prev_intc_num]; ++ iobase = chip->iobase[cpu]; ++ group = hwirq / 32; ++ bit = 1 << ((hwirq) & 31); ++ ++ if(!(readl(prev_iobase + PART_OFF * group + IMR_OFF) & bit)){ ++ writel(bit,prev_iobase + PART_OFF * group + IMSR_OFF); ++ writel(bit,iobase + PART_OFF * group + IMCR_OFF); ++ } else { ++ writel(bit,prev_iobase + PART_OFF * group + IMSR_OFF); ++ } ++ chip->intc_num[hwirq] = cpu; ++ ++ irq_unlock(chip); ++ ++ return IRQ_SET_MASK_OK; ++} ++#endif ++ ++static struct irq_chip xburst2_irq_chip = { ++ .name = "XBurst2-irqchip", ++ .irq_mask = xburst2_irq_mask, ++ .irq_mask_ack = xburst2_irq_mask, ++ .irq_unmask = xburst2_irq_unmask, ++ .irq_ack = xburst2_irq_mask, ++ .irq_eoi = xburst2_irq_unmask, ++ .irq_set_wake = xburst2_irq_set_wake, ++#ifdef CONFIG_SMP ++ .irq_set_affinity = xburst2_set_affinity, ++#endif ++}; ++ ++ ++static irqreturn_t xburst2_irq_handler(int irq, void *data) ++{ ++ struct core_irq_chip *irq_chip = *(struct core_irq_chip **)data; ++ void __iomem * iobase = irq_chip->iobase; ++ unsigned int irq_num = 0xffffffff; ++ int n = 0,i; ++ unsigned int next_irq_resp = irq_chip->next_irq_resp; ++ unsigned int ipr = readl(iobase + (next_irq_resp / 32) * PART_OFF + IPR_OFF); ++ ++ do{ ++ if(irq) { ++ for(i = next_irq_resp & 31;i < 32;i++) ++ { ++ if(ipr & (1 << i)) ++ { ++ irq_num = (next_irq_resp & (~31)) + i; ++ break; ++ } ++ } ++ } ++ if(irq_num != 0xffffffff) ++ break; ++ next_irq_resp = (next_irq_resp & (~31)) + 32; ++ if(next_irq_resp >= INTC_NR_IRQS) ++ next_irq_resp = 0; ++ ipr = readl(iobase + (next_irq_resp / 32) * PART_OFF + IPR_OFF); ++ n++; ++ }while(n < ((INTC_NR_IRQS + 31) / 32 + 1)); ++ ++ if(irq_num != 0xffffffff) ++ { ++#ifdef CONFIG_SMP ++ irq_chip->next_irq_resp = irq_num; ++#else ++ irq_chip->next_irq_resp = irq_num + 1; ++ if(irq_chip->next_irq_resp >= INTC_NR_IRQS) ++ irq_chip->next_irq_resp = 0; ++#endif ++ do_IRQ(irq_num + IRQ_INTC_BASE); ++ }else{ ++ pr_err("Error: Not Find any irq,check me %s %d.\n",__FILE__,__LINE__); ++ } ++ return IRQ_HANDLED; ++} ++ ++static void __init core_irq_setup(struct core_irq_chips *irq_chips) ++{ ++ struct irq_chip_data *chip = &irq_chips->chip_data; ++ int ret; ++ int i; ++ ++ irq_chips->percpu_irq_chip = alloc_percpu(struct core_irq_chip *); ++ if (!irq_chips->percpu_irq_chip) { ++ pr_err("ERROR:alloc cpu intc dev percpu fail!\n"); ++ return; ++ } ++ ++ ret = request_percpu_irq(irq_chips->irq, xburst2_irq_handler, "xburst2-intc", irq_chips->percpu_irq_chip); ++ if(ret) { ++ pr_err("ERROR:intc request error,ret: %d check %s %d\n", ret, __FILE__,__LINE__); ++ return; ++ } ++ ++ cpumask_clear(&chip->irq_idle_mask); ++ raw_spin_lock_init(&chip->lock); ++ ++ ++ for(i = 0;i < ARRAY_SIZE(chip->wake_up_flag);i++) ++ chip->wake_up_flag[i] = 0; ++ ++ for (i = 0; i < INTC_NR_IRQS; i++) { ++ cpumask_clear(&chip->affinity[i]); ++ chip->intc_num[i] = 0; ++ } ++ ++ pr_info("core irq setup finished\n"); ++} ++ ++static int ingenic_irq_domain_map(struct irq_domain *d, unsigned int irq, ++ irq_hw_number_t hw) ++{ ++ ++ irq_set_chip_data(irq, (void *)d->host_data); ++ irq_set_chip_and_handler(irq, &xburst2_irq_chip, handle_level_irq); ++ ++ return 0; ++} ++ ++static const struct irq_domain_ops ingenic_irq_domain_ops = { ++ .map = ingenic_irq_domain_map, ++ .xlate = irq_domain_xlate_onetwocell, ++}; ++ ++static int __init ingenic_intc_of_init(struct device_node *node) ++{ ++ struct core_irq_chips *irq_chips = &g_irq_chips; ++ void __iomem * iobase; ++ struct irq_domain *domain; ++ struct irq_chip_data *chip = &irq_chips->chip_data; ++ int irq; ++ struct property *prop; ++ const unsigned int *vp; ++ unsigned int pv; ++ int index = 0; ++ ++ if(WARN_ON(!node)) ++ return -ENODEV; ++ ++ iobase = of_iomap(node, 0); ++ WARN(!iobase, "Unbale to map intc iobase registers!\n"); ++ ++ irq = irq_of_parse_and_map(node, 0); ++ WARN(irq < 0, "Failed to get intc irq from DT!\n"); ++ ++ irq_chips->irq = irq; ++ ++ ++ of_property_for_each_u32(node, "cpu-intc-map", prop, vp, pv) { ++ if(index % 2) { ++ cpu_intc_map[index/2].dev_base = (unsigned int)iobase + pv; ++ } else { ++ cpu_intc_map[index/2].cpu_num = pv; ++ } ++ ++ index ++; ++ if(index > NR_CPUS * 2 - 1) { ++ printk("parse cpu-intc-iomap, intc define in dt is too large!\n"); ++ break; ++ } ++ } ++ ++ core_irq_setup(irq_chips); ++ ++ domain = irq_domain_add_legacy(node, INTC_NR_IRQS, 8, 0, &ingenic_irq_domain_ops, chip); ++ WARN(!iobase, "Unable to register IRQ domain!\n"); ++ ++ percpu_irq_init(irq_chips, 0); ++ ++ return 0; ++} ++ ++ ++ ++static int __init ingenic_intc_init(struct device_node *node, ++ struct device_node *parent) ++{ ++ return ingenic_intc_of_init(node); ++} ++IRQCHIP_DECLARE(ingenic_intc, "ingenic,core-intc", ingenic_intc_init); ++ ++ ++asmlinkage void plat_irq_dispatch(void) ++{ ++ unsigned long status = read_c0_status(); ++ unsigned long cause = read_c0_cause(); ++ volatile unsigned long r = ((status & cause) >> 8) & 0xff; ++ ++ if(r) { ++ if (r & 8) { /* IPI */ ++ do_IRQ(MIPS_CPU_IRQ_BASE + 3); ++ } else if(r & 16) { /* OST */ ++ do_IRQ(MIPS_CPU_IRQ_BASE + 4); ++ } else if (r & 4) { /* INTC */ ++ do_IRQ(MIPS_CPU_IRQ_BASE + 2); ++ } else { /* Others */ ++ do_IRQ(MIPS_CPU_IRQ_BASE + __ffs(r)); ++ } ++ ++ } else { ++ printk("IRQ Error, cpu: %d Cause:0x%08lx, Status:0x%08lx\n", smp_processor_id(), cause, status); ++ } ++} ++ ++void ingenic_irq_migration(int lock) ++{ ++ struct core_irq_chips *irq_chips = &g_irq_chips; ++ struct irq_chip_data *chip = &irq_chips->chip_data; ++ unsigned int cpu = smp_processor_id(); ++ void __iomem * iobase = NULL; ++ void __iomem * prev_iobase = NULL; ++ int i; ++ struct cpumask resp_mask; ++ unsigned int ipr = 0; ++ ++ if(lock){ ++ irq_lock(chip); ++ } ++ ++ prev_iobase = chip->iobase[cpu]; ++ for(i = 0;i < INTC_NR_IRQS;i++) ++ { ++ int group = i / 32; ++ int bitcount = i & 31; ++ unsigned int bit = 1 << bitcount; ++ int resp_cpu; ++ ++ if(bitcount == 0) { ++ ipr = readl(prev_iobase + group * PART_OFF + IPR_OFF); ++ } ++ ++ if(ipr == 0){ ++ i = (i & (~31)) + 31; ++ continue; ++ } ++ ++ if(ipr & bit){ ++ cpumask_and(&resp_mask,&chip->affinity[i],&chip->irq_idle_mask); ++ for_each_cpu(resp_cpu,&resp_mask){ ++ if(resp_cpu != cpu){ ++ //printk("migrate irq from cpu[%d] to cpu[%d], i: %d\n", cpu, resp_cpu, i); ++ iobase = chip->iobase[resp_cpu]; ++ if(!(readl(prev_iobase + PART_OFF * group + IMR_OFF) & bit)){ ++ writel(bit,prev_iobase + PART_OFF * group + IMSR_OFF); ++ writel(bit,iobase + PART_OFF * group + IMCR_OFF); ++ }else{ ++ writel(bit,iobase + PART_OFF * group + IMSR_OFF); ++ } ++ cpumask_clear_cpu(resp_cpu,&chip->irq_idle_mask); ++ chip->intc_num[i] = resp_cpu; ++ break; ++ } ++ } ++ } ++ } ++ if(lock){ ++ irq_unlock(chip); ++ } ++} ++EXPORT_SYMBOL_GPL(ingenic_irq_migration); ++ ++ ++void ingenic_irq_cpumask_idle(int idle) ++{ ++ struct core_irq_chips *irq_chips = &g_irq_chips; ++ struct irq_chip_data *chip = &irq_chips->chip_data; ++ int cpu = smp_processor_id(); ++ irq_lock(chip); ++ if(idle){ ++ cpumask_set_cpu(cpu,&chip->irq_idle_mask); ++ }else{ ++ cpumask_clear_cpu(cpu,&chip->irq_idle_mask); ++ } ++ irq_unlock(chip); ++} ++EXPORT_SYMBOL_GPL(ingenic_irq_cpumask_idle); ++ ++ ++ ++static unsigned long intc_saved[2]; ++extern void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume); ++ ++void arch_suspend_disable_irqs(void) ++{ ++ struct irq_chip_data *chip_data = &g_irq_chips.chip_data; ++ struct core_irq_chip *irq_chip = *this_cpu_ptr(g_irq_chips.percpu_irq_chip); ++ ++ unsigned int *intc_wakeup = chip_data->wake_up_flag; ++ void __iomem * intc_base = irq_chip->iobase; ++ ++ local_irq_disable(); ++ ++ intc_saved[0] = readl(intc_base + IMR_OFF); ++ intc_saved[1] = readl(intc_base + PART_OFF + IMR_OFF); ++ ++ /* Mask interrupts which are not wakeup src. */ ++ writel(0xffffffff & ~intc_wakeup[0], intc_base + IMSR_OFF); ++ writel(0xffffffff & ~intc_wakeup[1], intc_base + PART_OFF + IMSR_OFF); ++} ++ ++void arch_suspend_enable_irqs(void) ++{ ++ struct core_irq_chip *irq_chip = *this_cpu_ptr(g_irq_chips.percpu_irq_chip); ++ void __iomem * intc_base = irq_chip->iobase; ++ ++ writel(0xffffffff & ~intc_saved[0], intc_base + IMCR_OFF); ++ writel(0xffffffff & ~intc_saved[1], intc_base + PART_OFF + IMCR_OFF); ++ ++ local_irq_enable(); ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_irqchip_irq-ingenic-cpu.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_irqchip_irq-ingenic-cpu.c.patch new file mode 100644 index 00000000..2066485e --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_irqchip_irq-ingenic-cpu.c.patch @@ -0,0 +1,132 @@ +diff -drupN a/drivers/irqchip/irq-ingenic-cpu.c b/drivers/irqchip/irq-ingenic-cpu.c +--- a/drivers/irqchip/irq-ingenic-cpu.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/irqchip/irq-ingenic-cpu.c 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,128 @@ ++/* ++ * Copyright (C) 2014 Ingenic Semiconductor Co., Ltd. ++ * ++ * Author: dongsheng.qiu, dongsheng.qiu@ingenic.com bo.liu@ingenic.com ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++#include ++#include ++ ++static inline void unmask_ingenic_irq(struct irq_data *d) ++{ ++ set_c0_status(0x100 << (d->irq - MIPS_CPU_IRQ_BASE)); ++#ifdef CONFIG_SMP ++ ingenic_irq_cpumask_idle(1); ++#endif ++} ++ ++static inline void mask_ingenic_irq(struct irq_data *d) ++{ ++ clear_c0_status(0x100 << (d->irq - MIPS_CPU_IRQ_BASE)); ++#ifdef CONFIG_SMP ++ ingenic_irq_cpumask_idle(0); ++ if(d->irq != CORE_INTC_IRQ){ ++ ingenic_irq_migration(1); ++ } ++#endif ++} ++ ++static struct irq_chip ingenic_cpu_irq_controller = { ++ .name = "XBurst2", ++ .irq_ack = mask_ingenic_irq, ++ .irq_mask = mask_ingenic_irq, ++ .irq_mask_ack = mask_ingenic_irq, ++ .irq_unmask = unmask_ingenic_irq, ++ .irq_eoi = unmask_ingenic_irq, ++ .irq_disable = mask_ingenic_irq, ++ .irq_enable = unmask_ingenic_irq, ++}; ++ ++asmlinkage void __weak plat_irq_dispatch(void) ++{ ++ unsigned int status = read_c0_status(); ++ unsigned int cause = read_c0_cause(); ++ ++ unsigned long pending = ((status & cause) >> 8) & 0xff; ++ int irq; ++ ++ if (!pending) { ++ spurious_interrupt(); ++ return; ++ } ++ ++ if(pending) { ++ if (pending & 8) { /* IPI */ ++ do_IRQ(MIPS_CPU_IRQ_BASE + 3); ++ } else if(pending & 16) { /* OST */ ++ do_IRQ(MIPS_CPU_IRQ_BASE + 4); ++ } else if (pending & 4) { /* INTC */ ++ do_IRQ(MIPS_CPU_IRQ_BASE + 2); ++ } else { /* Others */ ++ do_IRQ(MIPS_CPU_IRQ_BASE + __ffs(pending)); ++ } ++ ++ } else { ++ //printk("IRQ Error, cpu: %d Cause:0x%08lx, Status:0x%08lx\n", smp_processor_id(), cause, status); ++ } ++} ++ ++static int ingenic_cpu_intc_map(struct irq_domain *d, unsigned int irq, ++ irq_hw_number_t hw) ++{ ++ static struct irq_chip *chip; ++ ++ chip = &ingenic_cpu_irq_controller; ++ ++ irq_set_percpu_devid(irq); ++ irq_set_chip_and_handler(irq, chip, handle_percpu_devid_irq); ++ ++ return 0; ++} ++ ++static const struct irq_domain_ops ingenic_cpu_intc_irq_domain_ops = { ++ .map = ingenic_cpu_intc_map, ++ .xlate = irq_domain_xlate_onecell, ++}; ++ ++static void __init __ingenic_cpu_irq_init(struct device_node *of_node) ++{ ++ struct irq_domain *domain; ++ ++ /* Mask interrupts. */ ++ clear_c0_status(ST0_IM); ++ clear_c0_cause(CAUSEF_IP); ++ ++ domain = irq_domain_add_legacy(of_node, 8, MIPS_CPU_IRQ_BASE, 0, ++ &ingenic_cpu_intc_irq_domain_ops, NULL); ++ if (!domain) ++ panic("Failed to add irqdomain for MIPS CPU"); ++} ++ ++void __init ingenic_cpu_irq_init(void) ++{ ++ __ingenic_cpu_irq_init(NULL); ++} ++ ++int __init ingenic_cpu_irq_of_init(struct device_node *of_node, ++ struct device_node *parent) ++{ ++ __ingenic_cpu_irq_init(of_node); ++ return 0; ++} ++IRQCHIP_DECLARE(cpu_intc, "ingenic,cpu-interrupt-controller", ingenic_cpu_irq_of_init); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_irqchip_irq-ingenic.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_irqchip_irq-ingenic.c.patch new file mode 100644 index 00000000..76ad783d --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_irqchip_irq-ingenic.c.patch @@ -0,0 +1,353 @@ +diff -drupN a/drivers/irqchip/irq-ingenic.c b/drivers/irqchip/irq-ingenic.c +--- a/drivers/irqchip/irq-ingenic.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/irqchip/irq-ingenic.c 2022-06-09 05:02:29.000000000 +0300 +@@ -1,6 +1,6 @@ + /* + * Copyright (C) 2009-2010, Lars-Peter Clausen +- * JZ4740 platform IRQ support ++ * ingenic platform IRQ support + * + * 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 +@@ -18,159 +18,253 @@ + #include + #include + #include +-#include +-#include + #include + #include ++#include + #include + #include + #include + ++#include ++#include ++#include + #include +-#include ++#include ++#include ++#include + +-struct ingenic_intc_data { +- void __iomem *base; +- unsigned num_chips; +-}; ++static void __iomem *intc_base; ++static unsigned ingenic_num_chips; + +-#define JZ_REG_INTC_STATUS 0x00 +-#define JZ_REG_INTC_MASK 0x04 +-#define JZ_REG_INTC_SET_MASK 0x08 +-#define JZ_REG_INTC_CLEAR_MASK 0x0c +-#define JZ_REG_INTC_PENDING 0x10 +-#define CHIP_SIZE 0x20 ++#define TRACE_IRQ 1 ++#define PART_OFF 0x20 + +-static irqreturn_t intc_cascade(int irq, void *data) ++#define ISR_OFF (0x00) ++#define IMR_OFF (0x04) ++#define IMSR_OFF (0x08) ++#define IMCR_OFF (0x0c) ++#define IPR_OFF (0x10) ++ ++#define DSR0_OFF (0x34) ++#define DMR0_OFF (0x38) ++#define DPR0_OFF (0x3c) ++#define DSR1_OFF (0x40) ++#define DMR1_OFF (0x44) ++#define DPR1_OFF (0x48) ++ ++static irqreturn_t ingenic_cascade(int irq, void *data) + { +- struct ingenic_intc_data *intc = irq_get_handler_data(irq); + uint32_t irq_reg; + unsigned i; + +- for (i = 0; i < intc->num_chips; i++) { +- irq_reg = readl(intc->base + (i * CHIP_SIZE) + +- JZ_REG_INTC_PENDING); ++ for (i = 0; i < ingenic_num_chips; i++) { ++ irq_reg = readl(intc_base + (i * PART_OFF) + IPR_OFF); + if (!irq_reg) + continue; +- +- generic_handle_irq(__fls(irq_reg) + (i * 32) + JZ4740_IRQ_BASE); ++ generic_handle_irq(__fls(irq_reg) + (i * 32) + XBURST_SOC_IRQ_BASE); + } + + return IRQ_HANDLED; + } + +-static void intc_irq_set_mask(struct irq_chip_generic *gc, uint32_t mask) ++static void ingenic_irq_pm_set_mask(struct irq_chip_generic *gc, uint32_t unmask) + { + struct irq_chip_regs *regs = &gc->chip_types->regs; + +- writel(mask, gc->reg_base + regs->enable); +- writel(~mask, gc->reg_base + regs->disable); ++ writel(unmask, gc->reg_base + regs->enable); ++ writel(~unmask, gc->reg_base + regs->disable); + } + +-void ingenic_intc_irq_suspend(struct irq_data *data) ++void ingenic_irq_suspend(struct irq_data *data) + { + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); +- intc_irq_set_mask(gc, gc->wake_active); ++ ingenic_irq_pm_set_mask(gc, gc->wake_active); + } + +-void ingenic_intc_irq_resume(struct irq_data *data) ++void ingenic_irq_resume(struct irq_data *data) + { + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); +- intc_irq_set_mask(gc, gc->mask_cache); ++ ingenic_irq_pm_set_mask(gc, gc->mask_cache); + } + +-static struct irqaction intc_cascade_action = { +- .handler = intc_cascade, +- .name = "SoC intc cascade interrupt", ++static struct irqaction ingenic_cascade_action = { ++ .handler = ingenic_cascade, ++ .name = "ingenic cascade interrupt", + }; + +-static int __init ingenic_intc_of_init(struct device_node *node, +- unsigned num_chips) ++static int __init ingenic_intc_of_init(struct device_node *node, unsigned num_chips) + { +- struct ingenic_intc_data *intc; + struct irq_chip_generic *gc; + struct irq_chip_type *ct; + struct irq_domain *domain; +- int parent_irq, err = 0; ++ struct resource res; ++ int ret, parent_irq; + unsigned i; + +- intc = kzalloc(sizeof(*intc), GFP_KERNEL); +- if (!intc) { +- err = -ENOMEM; +- goto out_err; +- } +- + parent_irq = irq_of_parse_and_map(node, 0); +- if (!parent_irq) { +- err = -EINVAL; +- goto out_free; +- } ++ if (!parent_irq) ++ return -EINVAL; + +- err = irq_set_handler_data(parent_irq, intc); +- if (err) +- goto out_unmap_irq; ++ ret = of_address_to_resource(node, 0, &res); ++ if (ret < 0) ++ return ret; + +- intc->num_chips = num_chips; +- intc->base = of_iomap(node, 0); +- if (!intc->base) { +- err = -ENODEV; +- goto out_unmap_irq; +- } ++ ingenic_num_chips = num_chips; ++ intc_base = ioremap(res.start, ++ ((num_chips - 1) * PART_OFF) + 0x14); ++ ++ domain = irq_domain_add_legacy(node, num_chips * 32, XBURST_SOC_IRQ_BASE, 0, ++ &irq_domain_simple_ops, NULL); ++ if (!domain) ++ pr_warn("unable to register IRQ domain\n"); + + for (i = 0; i < num_chips; i++) { + /* Mask all irqs */ +- writel(0xffffffff, intc->base + (i * CHIP_SIZE) + +- JZ_REG_INTC_SET_MASK); ++ writel(0xffffffff, intc_base + (i * PART_OFF) + IMSR_OFF); + +- gc = irq_alloc_generic_chip("INTC", 1, +- JZ4740_IRQ_BASE + (i * 32), +- intc->base + (i * CHIP_SIZE), ++ gc = irq_alloc_generic_chip("INTC", 1, XBURST_SOC_IRQ_BASE + (i * 32), ++ intc_base + (i * PART_OFF), + handle_level_irq); +- + gc->wake_enabled = IRQ_MSK(32); +- + ct = gc->chip_types; +- ct->regs.enable = JZ_REG_INTC_CLEAR_MASK; +- ct->regs.disable = JZ_REG_INTC_SET_MASK; ++ ct->regs.enable = IMCR_OFF; ++ ct->regs.disable = IMSR_OFF; + ct->chip.irq_unmask = irq_gc_unmask_enable_reg; + ct->chip.irq_mask = irq_gc_mask_disable_reg; + ct->chip.irq_mask_ack = irq_gc_mask_disable_reg; + ct->chip.irq_set_wake = irq_gc_set_wake; +- ct->chip.irq_suspend = ingenic_intc_irq_suspend; +- ct->chip.irq_resume = ingenic_intc_irq_resume; +- +- irq_setup_generic_chip(gc, IRQ_MSK(32), 0, 0, +- IRQ_NOPROBE | IRQ_LEVEL); ++ ct->chip.irq_suspend = ingenic_irq_suspend; ++ ct->chip.irq_resume = ingenic_irq_resume; ++#ifdef CONFIG_SPARSE_IRQ ++ irq_alloc_descs(gc->irq_base, -1, gc->num_ct, of_node_to_nid(domain->of_node)); ++#endif ++ irq_setup_generic_chip(gc, IRQ_MSK(32), 0, 0, IRQ_NOPROBE | IRQ_LEVEL); + } + +- domain = irq_domain_add_legacy(node, num_chips * 32, JZ4740_IRQ_BASE, 0, +- &irq_domain_simple_ops, NULL); +- if (!domain) +- pr_warn("unable to register IRQ domain\n"); ++ setup_irq(parent_irq, &ingenic_cascade_action); + +- setup_irq(parent_irq, &intc_cascade_action); ++ /* enable cpu interrupt mask */ ++ set_c0_status(IE_IRQ0 | IE_IRQ1); + return 0; ++} + +-out_unmap_irq: +- irq_dispose_mapping(parent_irq); +-out_free: +- kfree(intc); +-out_err: +- return err; ++static int __init ingenic_intc_init(struct device_node *node, ++ struct device_node *parent) ++{ ++ return ingenic_intc_of_init(node, INTC_CHIP_NUM); + } ++IRQCHIP_DECLARE(ingenic_intc, "ingenic,ingenic-intc", ingenic_intc_init); + +-static int __init intc_1chip_of_init(struct device_node *node, +- struct device_node *parent) ++#if 0 ++/************************************************************************* ++if nand was config: ++ After cpu was woke up,the mcu should be handler ++those interruptions of GPIO0,so that it was convenient to read/write nand, ++the process of GPIO's interruption as follows ++ |----------------------------------| ++ | GPIO | ++ | | | ++ | |--****--INTC---------->| | ++ | | MASK UNMASK | | ++ | CPU MCU | ++ | | | ++ | MAILEBOX | ++ | | <---------------------| | ++ | | | ++ | ingenicdma | ++ | | | ++ | soft intc | ++ | | | ++ | handler func of intc | ++ |__________________________________| ++ ++ On the contraty, when cpu will go to sleep, the cpu should be handler ++GPIO0's interruptions, it was convenient to the next step, which is that cpu was ++woke up. ++ GPIO ++ | ++ |---------INTC-------->| ++ | unmask mask | ++ CPU MCU ++ | ++ | ++ handler func of intc ++************************************************************************/ ++ ++#define IRQ_IS_GGPIO(irq) (irq >= IRQ_GPIO0 && irq <= IRQ_GPIO_END) ++extern void mcu_gpio_register(unsigned int ggpio, unsigned int reg); ++extern void mcu_gpio_unregister(unsigned int ggpio); ++ ++void ingenic_change_irq_destination(int irq, bool cpu_to_mcu, unsigned gpio_pending_reg) + { +- return ingenic_intc_of_init(node, 1); ++ int reg = 0; ++ if (WARN((irq < 0 || irq > 63), ++ "irq %d not support switch between cpu and mcu\n", ++ irq)) ++ return; ++ ++ if (cpu_to_mcu) { ++ if (irq < 32) { ++ writel((1 << irq), intc_base + IMSR_OFF); ++ if (IRQ_IS_GGPIO(irq)) ++ mcu_gpio_register((irq-IRQ_GPIO0), gpio_pending_reg); ++ reg = readl(intc_base + DMR0_OFF); ++ writel((reg & (~(1 << irq))), intc_base + DMR0_OFF); ++ } else { ++ writel((1 << (irq - 32)), intc_base + PART_OFF + IMSR_OFF); ++ reg = readl(intc_base + DMR1_OFF); ++ writel((reg & (~(1 << (irq - 32)))), intc_base + DMR1_OFF); ++ } ++ } else { ++ if (irq < 32) { ++ reg = readl(intc_base + DMR0_OFF); ++ writel((reg | (1 << irq)), intc_base + DMR0_OFF); ++ if (IRQ_IS_GGPIO(irq)) ++ mcu_gpio_unregister((irq-IRQ_GPIO0)); ++ writel((1 << irq), intc_base + IMCR_OFF); ++ } else { ++ reg = readl(intc_base + DMR1_OFF); ++ writel((reg | (1 << (irq - 32))), intc_base + DMR1_OFF); ++ writel((1 << (irq - 32)), intc_base + PART_OFF + IMCR_OFF); ++ } ++ } ++ return; ++} ++EXPORT_SYMBOL_GPL(ingenic_change_irq_destination); ++#endif ++#ifdef CONFIG_DEBUG_FS ++static inline void intc_seq_reg(struct seq_file *s, const char *name, ++ unsigned int reg) ++{ ++ seq_printf(s, "%s:\t\t%08x\n", name, readl(intc_base + reg)); + } +-IRQCHIP_DECLARE(jz4740_intc, "ingenic,jz4740-intc", intc_1chip_of_init); + +-static int __init intc_2chip_of_init(struct device_node *node, +- struct device_node *parent) ++static int intc_regs_show(struct seq_file *s, void *unused) + { +- return ingenic_intc_of_init(node, 2); ++ intc_seq_reg(s, "Status", ISR_OFF); ++ intc_seq_reg(s, "Mask", IMR_OFF); ++ intc_seq_reg(s, "Pending", IPR_OFF); ++ ++ return 0; + } +-IRQCHIP_DECLARE(jz4770_intc, "ingenic,jz4770-intc", intc_2chip_of_init); +-IRQCHIP_DECLARE(jz4775_intc, "ingenic,jz4775-intc", intc_2chip_of_init); +-IRQCHIP_DECLARE(jz4780_intc, "ingenic,jz4780-intc", intc_2chip_of_init); ++ ++static int intc_regs_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, intc_regs_show, NULL); ++} ++ ++static const struct file_operations intc_regs_operations = { ++ .open = intc_regs_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++ ++static int __init intc_debugfs_init(void) ++{ ++ (void) debugfs_create_file("intc_regs", S_IFREG | S_IRUGO, ++ NULL, NULL, &intc_regs_operations); ++ return 0; ++} ++subsys_initcall(intc_debugfs_init); ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_lzma_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_lzma_Kconfig.patch new file mode 100644 index 00000000..98629aa0 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_lzma_Kconfig.patch @@ -0,0 +1,11 @@ +diff -drupN a/drivers/lzma/Kconfig b/drivers/lzma/Kconfig +--- a/drivers/lzma/Kconfig 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/lzma/Kconfig 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,7 @@ ++# ++# LZMA device configuration ++# ++ ++config LZMADEVICE ++ bool "LZMA support" ++ default y diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_lzma_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_lzma_Makefile.patch new file mode 100644 index 00000000..5839dc8b --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_lzma_Makefile.patch @@ -0,0 +1,7 @@ +diff -drupN a/drivers/lzma/Makefile b/drivers/lzma/Makefile +--- a/drivers/lzma/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/lzma/Makefile 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,3 @@ ++ ++ ++obj-$(CONFIG_LZMADEVICE)+=lzma.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_lzma_lzma.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_lzma_lzma.c.patch new file mode 100644 index 00000000..4f83e0c7 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_lzma_lzma.c.patch @@ -0,0 +1,142 @@ +diff -drupN a/drivers/lzma/lzma.c b/drivers/lzma/lzma.c +--- a/drivers/lzma/lzma.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/lzma/lzma.c 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,138 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++//#include ++#include <../drivers/media/platform/ingenic-jpeg/jpeg-regs.h> ++ ++#define LZMA_CTRL 0x00 ++#define LZMA_BS_BASE 0x04 ++#define LZMA_BS_SIZE 0x08 ++#define LZMA_DST_BASE 0x0C ++#define LZMA_ICRC 0x10 ++#define LZMA_OCRC 0x14 ++#define LZMA_TIMEOUT 0x18 ++#define LZMA_FINAL 0x1c ++ ++#define CPM_BASE_M (char *)0xb0000000 ++#define CPM_CLKGR0 0x20 ++#define CPM_BSCCDR 0xa0 ++ ++#define LZMA_BASE (char *)0xb3090000 ++#define BSCALER_BASE (char *)0xb3090000 ++#define REG32(x) *(volatile unsigned int *)(x) ++ ++void dump_lzma_reg(void) ++{ ++ printk("\nDUMP CPM LZMA REG : \n"); ++ printk("CPM_BSCCDR = 0x%x \n", readl( CPM_BASE_M + CPM_BSCCDR)); ++ printk("CPM_CLKGR0 = 0x%x \n", readl( CPM_BASE_M + CPM_CLKGR0)); ++ ++ printk("DUMP LZMA REG : \n"); ++ printk("LZMA_CTRL = 0x%x \n", readl( LZMA_BASE+ LZMA_CTRL)); ++ printk("LZMA_BS_BASE = 0x%x \n", readl(LZMA_BASE + LZMA_BS_BASE)); ++ printk("LZMA_BS_SIZE = 0x%x \n", readl(LZMA_BASE + LZMA_BS_SIZE)); ++ printk("LZMA_DST_BASE = 0x%x \n", readl( LZMA_BASE + LZMA_DST_BASE)); ++ printk("LZMA_FINAL = 0x%x \n", readl(LZMA_BASE + LZMA_FINAL)); ++} ++ ++int jz_lzma_decompress(unsigned char *src, size_t size, unsigned char *dst) ++{ ++ unsigned int value = 0, outlen = 0; ++ unsigned int clk_val = 0, clk_gate = 0,ret = 0; ++ unsigned long out_file ,in_file; ++ unsigned int out_reg = 0,in_reg=0; ++ ++ /* config clk */ ++ clk_val = readl(CPM_BASE_M + CPM_BSCCDR); ++ clk_val |= ((2 << 30) | (1 << 29) | (1 <<0)); ++ writel(clk_val, CPM_BASE_M + CPM_BSCCDR); ++ ++ clk_gate = readl(CPM_BASE_M + CPM_CLKGR0); ++ clk_gate &= ~(1 << 2); ++ writel(clk_gate, CPM_BASE_M + CPM_CLKGR0); ++ ++ /* start set lzma */ ++ ++ value = readl(BSCALER_BASE + LZMA_CTRL); ++ value |= 1<<2; ++ writel(1 << 2, BSCALER_BASE + LZMA_CTRL); ++ value = readl(BSCALER_BASE + LZMA_CTRL); ++ while(value & 0x04) { ++ value = readl(BSCALER_BASE + LZMA_CTRL); ++ } ++ ++ /* set lzma mode */ ++ value = readl(BSCALER_BASE + LZMA_CTRL); ++ ++ while(!(value & (1 << 31))) { ++ value |= 1 << 31; ++ writel(value, BSCALER_BASE + LZMA_CTRL); ++ value = readl(BSCALER_BASE + LZMA_CTRL); ++ }; ++ ++ /* reset lzma */ ++ writel(1 << 2, BSCALER_BASE + LZMA_CTRL); ++ while(readl(BSCALER_BASE + LZMA_CTRL) & (1 << 2)); ++ ++ /* init ram */ ++ writel(1 << 1 ,BSCALER_BASE + LZMA_CTRL); ++ while(readl(BSCALER_BASE + LZMA_CTRL) & (1 << 1)); ++ ++ /* config */ ++ in_file = __get_free_pages(GFP_KERNEL, 11);//10 == 1024 == 4M ,if page_size=4096bytes,11==8M ++ if (in_file <= 0){ ++ printk("input file space request failed!\n"); ++ ret = -ENOMEM; ++ return -1; ++ } ++ memset((void*)in_file, 0xff, 1024*1024*8); ++ out_file = __get_free_pages(GFP_KERNEL, 12); //10 == 1024 == 4M ,if page_size=4096bytes,12==16M ++ if (out_file <= 0){ ++ printk("input file space request failed!\n"); ++ ret = -ENOMEM; ++ return -1; ++ } ++ memset((void*)out_file, 0xff, 1024*1024*16); ++ memmove((void *)in_file,(void* )src,size); ++ in_reg = virt_to_phys((void *)in_file ); ++ out_reg = virt_to_phys((void*)out_file); ++ mm_segment_t fs; ++ fs = get_fs(); ++ set_fs(KERNEL_DS); ++ ++ dma_cache_sync(NULL, (void *)in_file, 1*1024*1024, DMA_BIDIRECTIONAL); ++ memmove((void *)in_file,(void *)src,size); ++ dma_cache_sync(NULL, (void*)in_file, 1*1024*1024, DMA_BIDIRECTIONAL); ++ set_fs(fs); ++ ++ writel(in_reg , BSCALER_BASE + LZMA_BS_BASE); ++ writel(size, BSCALER_BASE + LZMA_BS_SIZE); ++ writel(out_reg , BSCALER_BASE + LZMA_DST_BASE); ++ ++ /* close intr and start lzma*/ ++ writel((1 << 0) | (1 << 3), BSCALER_BASE + LZMA_CTRL); ++ ++ /* wait end */ ++ while(readl(BSCALER_BASE + LZMA_CTRL) & (1 << 0)); ++ outlen = readl(BSCALER_BASE + LZMA_FINAL); ++ ++ memmove((void *)dst,(void *)out_file,outlen); ++ ++ ++ free_pages(in_file, 11);; ++ free_pages(out_file, 12); ++ return outlen; ++} ++EXPORT_SYMBOL(jz_lzma_decompress); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_lzma_lzma_debug.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_lzma_lzma_debug.c.patch new file mode 100644 index 00000000..78922e7c --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_lzma_lzma_debug.c.patch @@ -0,0 +1,229 @@ +diff -drupN a/drivers/lzma/lzma_debug.c b/drivers/lzma/lzma_debug.c +--- a/drivers/lzma/lzma_debug.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/lzma/lzma_debug.c 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,225 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++//#include ++#include <../drivers/media/platform/ingenic-jpeg/jpeg-regs.h> ++ ++#define LZMA_CTRL 0x00 ++#define LZMA_BS_BASE 0x04 ++#define LZMA_BS_SIZE 0x08 ++#define LZMA_DST_BASE 0x0C ++#define LZMA_ICRC 0x10 ++#define LZMA_OCRC 0x14 ++#define LZMA_TIMEOUT 0x18 ++#define LZMA_FINAL 0x1c ++ ++#define CPM_BASE_M (char *)0xb0000000 ++#define CPM_CLKGR0 0x20 ++#define CPM_BSCCDR 0xa0 ++ ++#define LZMA_BASE (char *)0xb3090000 ++#define BSCALER_BASE (char *)0xb3090000 ++#define REG32(x) *(volatile unsigned int *)(x) ++static void *clk_io_mem; ++static void *lzma_io_mem; ++/*void dump_lzma_reg(void) ++{ ++ printk("\nDUMP CPM LZMA REG : \n"); ++ printk("CPM_BSCCDR = 0x%x \n", REG32(CPM_BASE + CPM_BSCCDR)); ++ printk("CPM_CLKGR0 = 0x%x \n", REG32(CPM_BASE + CPM_CLKGR0)); ++ ++ printk("DUMP LZMA REG : \n"); ++ printk("LZMA_CTRL = 0x%x \n", REG32(LZMA_BASE + LZMA_CTRL)); ++ printk("LZMA_BS_BASE = 0x%x \n", REG32(LZMA_BASE + LZMA_BS_BASE)); ++ printk("LZMA_BS_SIZE = 0x%x \n", REG32(LZMA_BASE + LZMA_BS_SIZE)); ++ printk("LZMA_DST_BASE = 0x%x \n", REG32(LZMA_BASE + LZMA_DST_BASE)); ++ printk("LZMA_FINAL = 0x%x \n", REG32(LZMA_BASE + LZMA_FINAL)); ++}*/ ++void dump_lzma_reg(void) ++{ ++ printk("\nDUMP CPM LZMA REG : \n"); ++ printk("CPM_BSCCDR = 0x%x \n", readl( CPM_BASE_M + CPM_BSCCDR)); ++ printk("CPM_CLKGR0 = 0x%x \n", readl( CPM_BASE_M + CPM_CLKGR0)); ++ ++ printk("DUMP LZMA REG : \n"); ++ printk("LZMA_CTRL = 0x%x \n", readl( LZMA_BASE+ LZMA_CTRL)); ++ printk("LZMA_BS_BASE = 0x%x \n", readl(LZMA_BASE + LZMA_BS_BASE)); ++ printk("LZMA_BS_SIZE = 0x%x \n", readl(LZMA_BASE + LZMA_BS_SIZE)); ++ printk("LZMA_DST_BASE = 0x%x \n", readl( LZMA_BASE + LZMA_DST_BASE)); ++ printk("LZMA_FINAL = 0x%x \n", readl(LZMA_BASE + LZMA_FINAL)); ++ ++/* printk("\nDUMP CPM LZMA REG : \n"); ++ printk("CPM_BSCCDR = 0x%x \n", readl( clk_io_mem + CPM_BSCCDR)); ++ printk("CPM_CLKGR0 = 0x%x \n", readl( clk_io_mem + CPM_CLKGR0)); ++ ++ printk("DUMP LZMA REG : \n"); ++ printk("LZMA_CTRL = 0x%x \n", readl( lzma_io_mem+ LZMA_CTRL)); ++ printk("LZMA_BS_BASE = 0x%x \n", readl(lzma_io_mem + LZMA_BS_BASE)); ++ printk("LZMA_BS_SIZE = 0x%x \n", readl( lzma_io_mem+ LZMA_BS_SIZE)); ++ printk("LZMA_DST_BASE = 0x%x \n", readl( lzma_io_mem + LZMA_DST_BASE)); ++ printk("LZMA_FINAL = 0x%x \n", readl(lzma_io_mem + LZMA_FINAL));*/ ++ ++ ++} ++ ++int jz_lzma_decompress(unsigned char *src, size_t size, unsigned char *dst)// char int* ++{ ++ unsigned int value = 0, outlen = 0; ++ unsigned int clk_val = 0, clk_gate = 0; ++ unsigned long out_file ,in_file; ++ unsigned int out_reg = 0,in_reg=0; ++ //printk("THIS IS HARWARE_UNCOMPRESS!\n"); ++ ++ //printk("src addr=0x%x, dst addr=0x%x\n",*src,*dst); ++ ++ /* config clk */ ++ clk_val = readl(CPM_BASE_M + CPM_BSCCDR); ++ clk_val |= ((2 << 30) | (1 << 29) | (1 <<0)); ++ writel(clk_val, CPM_BASE_M + CPM_BSCCDR); ++ ++ clk_gate = readl(CPM_BASE_M + CPM_CLKGR0); ++ clk_gate &= ~(1 << 2); ++ writel(clk_gate, CPM_BASE_M + CPM_CLKGR0); ++/*if (!request_mem_region(CPM_BASE, 8, "clk_io_mem")){ ++ return -EINVAL; ++} ++clk_io_mem = ioremap(CPM_BASE,8); ++clk_val = readl(clk_io_mem + CPM_BSCCDR); ++clk_val |= ((2 << 30) | (1 << 29) | (1 <<0)); ++writel(clk_val, clk_io_mem + CPM_BSCCDR); ++printk("clk_val=0x%x\n",clk_val); ++printk("clk_io_mem + CPM_BSCCDR=0x%x\n",readl(clk_io_mem + CPM_BSCCDR)); ++printk("000000000000\n"); ++clk_gate = readl( clk_io_mem + CPM_CLKGR0); ++clk_gate &= ~(1 << 2); ++writel(clk_gate, clk_io_mem + CPM_CLKGR0); ++printk("clk_gate=0x%x\n",clk_gate); ++printk("clk_io_mem + CPM_CLKGR0=0x%x\n",readl(clk_io_mem + CPM_CLKGR0));*/ ++ ++ /* start set lzma */ ++ ++ value = readl(BSCALER_BASE + LZMA_CTRL); ++ value |= 1<<2; ++ writel(1 << 2, BSCALER_BASE + LZMA_CTRL); ++ value = readl(BSCALER_BASE + LZMA_CTRL); ++ while(value & 0x04) { ++ value = readl(BSCALER_BASE + LZMA_CTRL); ++ } ++/*printk("1\n"); ++if (!request_mem_region(LZMA_BASE, 40, "lzma_io_mem")){ ++ return -EINVAL; ++} ++lzma_io_mem = ioremap(LZMA_BASE,40); ++value = readl(lzma_io_mem + LZMA_CTRL); ++ value |= 1<<2; ++ writel(1 << 2, lzma_io_mem + LZMA_CTRL); ++ value = readl(lzma_io_mem + LZMA_CTRL); ++ while(value & 0x04) { ++ value = readl( lzma_io_mem + LZMA_CTRL); ++ }*/ ++ ++ ++ /* set lzma mode */ ++ value = readl(BSCALER_BASE + LZMA_CTRL); ++ ++ while(!(value & (1 << 31))) { ++ value |= 1 << 31; ++ writel(value, BSCALER_BASE + LZMA_CTRL); ++ value = readl(BSCALER_BASE + LZMA_CTRL); ++ }; ++/*printk("3\n"); ++ value = readl(lzma_io_mem + LZMA_CTRL); ++ ++ while(!(value & (1 << 31))) { ++ value |= 1 << 31; ++ writel(value, lzma_io_mem + LZMA_CTRL); ++ value = readl( lzma_io_mem+ LZMA_CTRL); ++ }*/ ++ ++ /* reset lzma */ ++ writel(1 << 2, BSCALER_BASE + LZMA_CTRL); ++ while(readl(BSCALER_BASE + LZMA_CTRL) & (1 << 2)); ++/*printk("5\n"); ++ writel(1 << 2, lzma_io_mem + LZMA_CTRL); ++printk("6\n"); ++ while(readl(lzma_io_mem + LZMA_CTRL) & (1 << 2));*/ ++ ++ /* init ram */ ++ writel(1 << 1 ,BSCALER_BASE + LZMA_CTRL); ++ while(readl(BSCALER_BASE + LZMA_CTRL) & (1 << 1)); ++/* writel(1 << 1 ,lzma_io_mem + LZMA_CTRL); ++printk("7\n"); ++ while(readl( lzma_io_mem + LZMA_CTRL) & (1 << 1));*/ ++ ++ /* config */ ++in_file = __get_free_pages(GFP_KERNEL, 11);//10 == 1024 == 4M ,if page_size=4096bytes,11==8M ++ if (in_file <= 0){ ++ printk("input file space request failed!\n"); ++ return -ENOMEM; ++ } ++ //lzma_debug("in size = 0x%x, virt_to_phys=0x%x\n", lzma_ope->in_file, virt_to_phys((void*)lzma_ope->in_file)); ++ memset((void*)in_file, 0xff, 1024*1024*8); ++ out_file = __get_free_pages(GFP_KERNEL, 12); //10 == 1024 == 4M ,if page_size=4096bytes,12==16M ++ if (out_file <= 0){ ++ printk("input file space request failed!\n"); ++ return -ENOMEM; ++ } ++ memset((void*)out_file, 0xff, 1024*1024*16); ++ memmove((void *)in_file,(void* )src,size); ++ in_reg = virt_to_phys((void *)in_file ); ++ out_reg = virt_to_phys((void*)out_file); ++ mm_segment_t fs; ++ fs = get_fs(); ++ set_fs(KERNEL_DS); ++ ++ printk("dma_cache_sync()...\n"); ++ dma_cache_sync(NULL, (void *)in_file, 1*1024*1024, DMA_BIDIRECTIONAL); ++ printk("memmove...\n"); ++ memmove((void *)in_file,(void *)src,size); ++ printk("dma_cache_sync()...\n"); ++ dma_cache_sync(NULL, (void*)in_file, 1*1024*1024, DMA_BIDIRECTIONAL); ++ set_fs(fs); ++ ++ writel(in_reg , BSCALER_BASE + LZMA_BS_BASE); ++ writel(size, BSCALER_BASE + LZMA_BS_SIZE); ++ writel(out_reg , BSCALER_BASE + LZMA_DST_BASE); ++/* writel(src- 0x80000000 , lzma_io_mem+ LZMA_BS_BASE); ++ writel(size, lzma_io_mem + LZMA_BS_SIZE); ++ writel(dst - 0x80000000,lzma_io_mem + LZMA_DST_BASE);*/ ++ ++ /* close intr and start lzma*/ ++ writel((1 << 0) | (1 << 3), BSCALER_BASE + LZMA_CTRL); ++// writel((1 << 0) | (1 << 3), lzma_io_mem + LZMA_CTRL); ++ ++ /* wait end */ ++ printk(" LZMA_CTRL=0x%x\n",readl(BSCALER_BASE + LZMA_CTRL)); ++ while(readl(BSCALER_BASE + LZMA_CTRL) & (1 << 0)); ++ outlen = readl(BSCALER_BASE + LZMA_FINAL); ++// while(readl(lzma_io_mem + LZMA_CTRL) & (1 << 0)); ++ ++ memmove((void *)dst,(void *)out_file,outlen); ++ dump_lzma_reg(); ++ ++ ++//release ++/* iounmap( clk_io_mem); ++ iounmap(lzma_io_mem); ++ release_mem_region(CPM_BASE,8); ++ release_mem_region( LZMA_BASE,40);*/ ++ free_pages(in_file, 11);; ++ free_pages(out_file, 12); ++ return outlen; ++} ++EXPORT_SYMBOL(jz_lzma_decompress); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_i2c_soc_camera_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_i2c_soc_camera_Kconfig.patch new file mode 100644 index 00000000..d21261ee --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_i2c_soc_camera_Kconfig.patch @@ -0,0 +1,34 @@ +diff -drupN a/drivers/media/i2c/soc_camera/Kconfig b/drivers/media/i2c/soc_camera/Kconfig +--- a/drivers/media/i2c/soc_camera/Kconfig 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/media/i2c/soc_camera/Kconfig 2022-06-09 05:02:29.000000000 +0300 +@@ -1,5 +1,17 @@ + comment "soc_camera sensor drivers" + ++config SOC_CAMERA_OV5640 ++ tristate "ov5640 camera support" ++ depends on SOC_CAMERA && I2C ++ help ++ This is a ov5640 camera driver ++ ++config SOC_CAMERA_GC2155 ++ tristate "gc2155 camera support" ++ depends on SOC_CAMERA && I2C ++ help ++ This is a gc2155 camera driver ++ + config SOC_CAMERA_IMX074 + tristate "imx074 support" + depends on SOC_CAMERA && I2C +@@ -50,6 +62,12 @@ config SOC_CAMERA_OV5642 + help + This is a V4L2 camera driver for the OmniVision OV5642 sensor + ++config SOC_CAMERA_OV9281 ++ tristate "ov9281 camera support" ++ depends on SOC_CAMERA && I2C ++ help ++ This is a V4L2 camera driver for the OmniVision OV9281 sensor ++ + config SOC_CAMERA_OV6650 + tristate "ov6650 sensor support" + depends on SOC_CAMERA && I2C diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_i2c_soc_camera_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_i2c_soc_camera_Makefile.patch new file mode 100644 index 00000000..0678c4a3 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_i2c_soc_camera_Makefile.patch @@ -0,0 +1,20 @@ +diff -drupN a/drivers/media/i2c/soc_camera/Makefile b/drivers/media/i2c/soc_camera/Makefile +--- a/drivers/media/i2c/soc_camera/Makefile 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/media/i2c/soc_camera/Makefile 2022-06-09 05:02:29.000000000 +0300 +@@ -3,7 +3,8 @@ obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m + obj-$(CONFIG_SOC_CAMERA_MT9M111) += mt9m111.o + obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o + obj-$(CONFIG_SOC_CAMERA_MT9T112) += mt9t112.o +-obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o ++#obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o ++obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022_test.o + obj-$(CONFIG_SOC_CAMERA_OV2640) += ov2640.o + obj-$(CONFIG_SOC_CAMERA_OV5642) += ov5642.o + obj-$(CONFIG_SOC_CAMERA_OV6650) += ov6650.o +@@ -12,3 +13,6 @@ obj-$(CONFIG_SOC_CAMERA_OV9640) += ov96 + obj-$(CONFIG_SOC_CAMERA_OV9740) += ov9740.o + obj-$(CONFIG_SOC_CAMERA_RJ54N1) += rj54n1cb0c.o + obj-$(CONFIG_SOC_CAMERA_TW9910) += tw9910.o ++obj-$(CONFIG_SOC_CAMERA_OV5640) += ov5640.o ++obj-$(CONFIG_SOC_CAMERA_GC2155) += gc2155.o ++obj-$(CONFIG_SOC_CAMERA_OV9281) += ov9281.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_i2c_soc_camera_gc2155.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_i2c_soc_camera_gc2155.c.patch new file mode 100644 index 00000000..e9836757 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_i2c_soc_camera_gc2155.c.patch @@ -0,0 +1,1781 @@ +diff -drupN a/drivers/media/i2c/soc_camera/gc2155.c b/drivers/media/i2c/soc_camera/gc2155.c +--- a/drivers/media/i2c/soc_camera/gc2155.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/i2c/soc_camera/gc2155.c 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,1777 @@ ++/* ++ * gc2155 Camera Driver ++ * ++ * Copyright (C) 2010 Alberto Panizzo ++ * ++ * Based on ov772x, ov9640 drivers and previous non merged implementations. ++ * ++ * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. ++ * Copyright (C) 2006, OmniVision ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#define REG_CHIP_ID_HIGH 0xf0 ++#define REG_CHIP_ID_LOW 0xf1 ++ ++#define CHIP_ID_HIGH 0x21 ++#define CHIP_ID_LOW 0x55 ++ ++/* Private v4l2 controls */ ++#define V4L2_CID_PRIVATE_BALANCE (V4L2_CID_PRIVATE_BASE + 0) ++#define V4L2_CID_PRIVATE_EFFECT (V4L2_CID_PRIVATE_BASE + 1) ++ ++#define REG14 0x14 ++#define REG14_HFLIP_IMG 0x01 /* Horizontal mirror image ON/OFF */ ++#define REG14_VFLIP_IMG 0x02 /* Vertical flip image ON/OFF */ ++ ++/* whether sensor support high resolution (> vga) preview or not */ ++#define SUPPORT_HIGH_RESOLUTION_PRE 1 ++ ++/* ++ * Struct ++ */ ++struct regval_list { ++ u8 reg_num; ++ u8 value; ++}; ++ ++struct mode_list { ++ u8 index; ++ const struct regval_list *mode_regs; ++}; ++ ++/* Supported resolutions */ ++enum gc2155_width { ++ W_QVGA = 320, ++ W_VGA = 640, ++ W_720P = 1280, ++}; ++ ++enum gc2155_height { ++ H_QVGA = 240, ++ H_VGA = 480, ++ H_720P = 720, ++}; ++ ++struct gc2155_win_size { ++ char *name; ++ enum gc2155_width width; ++ enum gc2155_height height; ++ const struct regval_list *regs; ++}; ++ ++struct gc2155_priv { ++ struct v4l2_subdev subdev; ++ struct v4l2_ctrl_handler hdl; ++ u32 cfmt_code; ++ struct v4l2_clk *clk; ++ const struct gc2155_win_size *win; ++ ++ int model; ++ u16 balance_value; ++ u16 effect_value; ++ u16 flag_vflip:1; ++ u16 flag_hflip:1; ++ ++ struct soc_camera_subdev_desc ssdd_dt; ++ struct gpio_desc *resetb_gpio; ++ struct gpio_desc *pwdn_gpio; ++ struct gpio_desc *vcc_en_gpio; ++ ++ struct regulator *reg; ++ struct regulator *reg1; ++}; ++ ++static int gc2155_s_power(struct v4l2_subdev *sd, int on); ++static int gc2155_set_params(struct i2c_client *client, u32 *width, u32 *height, u32 code); ++ ++static inline int gc2155_write_reg(struct i2c_client * client, unsigned char addr, unsigned char value) ++{ ++ return i2c_smbus_write_byte_data(client, addr, value); ++} ++static inline char gc2155_read_reg(struct i2c_client *client, unsigned char addr) ++{ ++ char ret; ++ ret = i2c_smbus_read_byte_data(client, addr); ++ return ret; ++} ++/* ++ * Registers settings ++ */ ++ ++#define ENDMARKER { 0xff, 0xff } ++ ++static const struct regval_list gc2155_init_regs[] = { ++ {0xfe,0xf0}, ++ {0xfe,0xf0}, ++ {0xfe,0xf0}, ++ {0xfc,0x06}, ++ {0xf6,0x00}, ++ {0xf7,0x1d}, ++ {0xf8,0x84}, ++ {0xfa,0x00}, ++ {0xf9,0xfe}, ++ {0xf2,0x00}, ++ {0xfe,0x00}, ++ {0x03,0x04}, ++ {0x04,0xe2}, ++ {0x09,0x00}, ++ {0x0a,0x00}, ++ {0x0b,0x00}, ++ {0x0c,0x00}, ++ {0x0d,0x04}, ++ {0x0e,0xc0}, ++ {0x0f,0x06}, ++ {0x10,0x50}, ++ {0x12,0x2e}, ++ {0x17,0x14}, // mirror ++ {0x18,0x02}, ++ {0x19,0x0e}, ++ {0x1a,0x01}, ++ {0x1b,0x4b}, ++ {0x1c,0x07}, ++ {0x1d,0x10}, ++ {0x1e,0x98}, ++ {0x1f,0x78}, ++ {0x20,0x05}, ++ {0x21,0x40}, ++ {0x22,0xf0}, ++ {0x24,0x16}, ++ {0x25,0x01}, ++ {0x26,0x10}, ++ {0x2d,0x40}, ++ {0x30,0x01}, ++ {0x31,0x90}, ++ {0x33,0x04}, ++ {0x34,0x01}, ++ {0xfe,0x00}, ++ {0x80,0xff}, ++ {0x81,0x2c}, ++ {0x82,0xfa}, ++ {0x83,0x00}, ++ {0x84,0x02}, //y u yv ++ {0x85,0x08}, ++ {0x86,0x02}, ++ {0x89,0x03}, ++ {0x8a,0x00}, ++ {0x8b,0x00}, ++ {0xb0,0x55}, ++ {0xc3,0x11}, //00 ++ {0xc4,0x20}, ++ {0xc5,0x30}, ++ {0xc6,0x38}, ++ {0xc7,0x40}, ++ {0xec,0x02}, ++ {0xed,0x04}, ++ {0xee,0x60}, ++ {0xef,0x90}, ++ {0xb6,0x01}, ++ {0x90,0x01}, ++ {0x91,0x00}, ++ {0x92,0x00}, ++ {0x93,0x00}, ++ {0x94,0x00}, ++ {0x95,0x04}, ++ {0x96,0xb0}, ++ {0x97,0x06}, ++ {0x98,0x40}, ++ {0xfe,0x00}, ++ {0x18,0x02}, ++ {0x40,0x42}, ++ {0x41,0x00}, ++ {0x43,0x5b},//0X54 ++ {0x5e,0x00}, ++ {0x5f,0x00}, ++ {0x60,0x00}, ++ {0x61,0x00}, ++ {0x62,0x00}, ++ {0x63,0x00}, ++ {0x64,0x00}, ++ {0x65,0x00}, ++ {0x66,0x20}, ++ {0x67,0x20}, ++ {0x68,0x20}, ++ {0x69,0x20}, ++ {0x6a,0x08}, ++ {0x6b,0x08}, ++ {0x6c,0x08}, ++ {0x6d,0x08}, ++ {0x6e,0x08}, ++ {0x6f,0x08}, ++ {0x70,0x08}, ++ {0x71,0x08}, ++ {0x72,0xf0}, ++ {0x7e,0x3c}, ++ {0x7f,0x00}, ++ {0xfe,0x00}, ++ {0xfe,0x01}, ++ {0x01,0x08}, ++ {0x02,0xc0}, ++ {0x03,0x04}, ++ {0x04,0x90}, ++ {0x05,0x30}, ++ {0x06,0x98}, ++ {0x07,0x28}, ++ {0x08,0x6c}, ++ {0x09,0x00}, ++ {0x0a,0xc2}, ++ {0x0b,0x11}, ++ {0x0c,0x10}, ++ {0x13,0x2d}, ++ {0x17,0x00}, ++ {0x1c,0x11}, ++ {0x1e,0x61}, ++ {0x1f,0x30}, ++ {0x20,0x40}, ++ {0x22,0x80}, ++ {0x23,0x20}, ++ {0x12,0x35}, ++ {0x15,0x50}, ++ {0x10,0x31}, ++ {0x3e,0x28}, ++ {0x3f,0xe0}, ++ {0x40,0xe0}, ++ {0x41,0x08}, ++ {0xfe,0x02}, ++ {0x0f,0x05}, ++ {0xfe,0x02}, ++ {0x90,0x6c}, ++ {0x91,0x03}, ++ {0x92,0xc4}, ++ {0x97,0x64}, ++ {0x98,0x88}, ++ {0x9d,0x08}, ++ {0xa2,0x11}, ++ {0xfe,0x00}, ++ {0xfe,0x02}, ++ {0x80,0xc1}, ++ {0x81,0x08}, ++ {0x82,0x05}, ++ {0x83,0x04}, ++ {0x86,0x80}, ++ {0x87,0x30}, ++ {0x88,0x15}, ++ {0x89,0x80}, ++ {0x8a,0x60}, ++ {0x8b,0x30}, ++ {0xfe,0x01}, ++ {0x21,0x14}, ++ {0xfe,0x02}, ++ {0x3c,0x06}, ++ {0x3d,0x40}, ++ {0x48,0x30}, ++ {0x49,0x06}, ++ {0x4b,0x08}, ++ {0x4c,0x20}, ++ {0xa3,0x50}, ++ {0xa4,0x30}, ++ {0xa5,0x40}, ++ {0xa6,0x80}, ++ {0xab,0x40}, ++ {0xae,0x0c}, ++ {0xb3,0x42}, ++ {0xb4,0x24}, ++ {0xb6,0x50}, ++ {0xb7,0x01}, ++ {0xb9,0x28}, ++ {0xfe,0x00}, ++ {0xfe,0x02}, ++ {0x10,0x0d}, ++ {0x11,0x12}, ++ {0x12,0x17}, ++ {0x13,0x1c}, ++ {0x14,0x27}, ++ {0x15,0x34}, ++ {0x16,0x44}, ++ {0x17,0x55}, ++ {0x18,0x6e}, ++ {0x19,0x81}, ++ {0x1a,0x91}, ++ {0x1b,0x9c}, ++ {0x1c,0xaa}, ++ {0x1d,0xbb}, ++ {0x1e,0xca}, ++ {0x1f,0xd5}, ++ {0x20,0xe0}, ++ {0x21,0xe7}, ++ {0x22,0xed}, ++ {0x23,0xf6}, ++ {0x24,0xfb}, ++ {0x25,0xff}, ++ {0xfe,0x02}, ++ {0x26,0x0d}, ++ {0x27,0x12}, ++ {0x28,0x17}, ++ {0x29,0x1c}, ++ {0x2a,0x27}, ++ {0x2b,0x34}, ++ {0x2c,0x44}, ++ {0x2d,0x55}, ++ {0x2e,0x6e}, ++ {0x2f,0x81}, ++ {0x30,0x91}, ++ {0x31,0x9c}, ++ {0x32,0xaa}, ++ {0x33,0xbb}, ++ {0x34,0xca}, ++ {0x35,0xd5}, ++ {0x36,0xe0}, ++ {0x37,0xe7}, ++ {0x38,0xed}, ++ {0x39,0xf6}, ++ {0x3a,0xfb}, ++ {0x3b,0xff}, ++ {0xfe,0x02}, ++ {0xd1,0x28}, ++ {0xd2,0x28}, ++ {0xdd,0x14}, ++ {0xde,0x88}, ++ {0xed,0x80}, ++ {0xfe,0x01}, ++ {0xc2,0x1f}, ++ {0xc3,0x13}, ++ {0xc4,0x0e}, ++ {0xc8,0x16}, ++ {0xc9,0x0f}, ++ {0xca,0x0c}, ++ {0xbc,0x52}, ++ {0xbd,0x2c}, ++ {0xbe,0x27}, ++ {0xb6,0x47}, ++ {0xb7,0x32}, ++ {0xb8,0x30}, ++ {0xc5,0x00}, ++ {0xc6,0x00}, ++ {0xc7,0x00}, ++ {0xcb,0x00}, ++ {0xcc,0x00}, ++ {0xcd,0x00}, ++ {0xbf,0x0e}, ++ {0xc0,0x00}, ++ {0xc1,0x00}, ++ {0xb9,0x08}, ++ {0xba,0x00}, ++ {0xbb,0x00}, ++ {0xaa,0x0a}, ++ {0xab,0x0c}, ++ {0xac,0x0d}, ++ {0xad,0x02}, ++ {0xae,0x06}, ++ {0xaf,0x05}, ++ {0xb0,0x00}, ++ {0xb1,0x05}, ++ {0xb2,0x02}, ++ {0xb3,0x04}, ++ {0xb4,0x04}, ++ {0xb5,0x05}, ++ {0xd0,0x00}, ++ {0xd1,0x00}, ++ {0xd2,0x00}, ++ {0xd6,0x02}, ++ {0xd7,0x00}, ++ {0xd8,0x00}, ++ {0xd9,0x00}, ++ {0xda,0x00}, ++ {0xdb,0x00}, ++ {0xd3,0x00}, ++ {0xd4,0x00}, ++ {0xd5,0x00}, ++ {0xa4,0x04}, ++ {0xa5,0x00}, ++ {0xa6,0x77}, ++ {0xa7,0x77}, ++ {0xa8,0x77}, ++ {0xa9,0x77}, ++ {0xa1,0x80}, ++ {0xa2,0x80}, ++ {0xfe,0x01}, ++ {0xdc,0x35}, ++ {0xdd,0x28}, ++ {0xdf,0x0d}, ++ {0xe0,0x70}, ++ {0xe1,0x78}, ++ {0xe2,0x70}, ++ {0xe3,0x78}, ++ {0xe6,0x90}, ++ {0xe7,0x70}, ++ {0xe8,0x90}, ++ {0xe9,0x70}, ++ {0xfe,0x00}, ++ {0xfe,0x01}, ++ {0x4f,0x00}, ++ {0x4f,0x00}, ++ {0x4b,0x01}, ++ {0x4f,0x00}, ++ {0x4c,0x01}, ++ {0x4d,0x71}, ++ {0x4e,0x02}, ++ {0x4c,0x01}, ++ {0x4d,0x91}, ++ {0x4e,0x02}, ++ {0x4c,0x01}, ++ {0x4d,0x50}, ++ {0x4e,0x02}, ++ {0x4c,0x01}, ++ {0x4d,0x70}, ++ {0x4e,0x02}, ++ {0x4c,0x01}, ++ {0x4d,0x90}, ++ {0x4e,0x02}, ++ {0x4c,0x01}, ++ {0x4d,0xb0}, ++ {0x4e,0x02}, ++ {0x4c,0x01}, ++ {0x4d,0xd0}, ++ {0x4e,0x02}, ++ {0x4c,0x01}, ++ {0x4d,0x4f}, ++ {0x4e,0x02}, ++ {0x4c,0x01}, ++ {0x4d,0x6f}, ++ {0x4e,0x02}, ++ {0x4c,0x01}, ++ {0x4d,0x8f}, ++ {0x4e,0x02}, ++ {0x4c,0x01}, ++ {0x4d,0xaf}, ++ {0x4e,0x02}, ++ {0x4c,0x01}, ++ {0x4d,0xcf}, ++ {0x4e,0x02}, ++ {0x4c,0x01}, ++ {0x4d,0x6e}, ++ {0x4e,0x03}, ++ {0x4c,0x01}, ++ {0x4d,0x8e}, ++ {0x4e,0x03}, ++ {0x4c,0x01}, ++ {0x4d,0xae}, ++ {0x4e,0x03}, ++ {0x4c,0x01}, ++ {0x4d,0xce}, ++ {0x4e,0x03}, ++ {0x4c,0x01}, ++ {0x4d,0x4d}, ++ {0x4e,0x03}, ++ {0x4c,0x01}, ++ {0x4d,0x6d}, ++ {0x4e,0x03}, ++ {0x4c,0x01}, ++ {0x4d,0x8d}, ++ {0x4e,0x03}, ++ {0x4c,0x01}, ++ {0x4d,0xad}, ++ {0x4e,0x03}, ++ {0x4c,0x01}, ++ {0x4d,0xcd}, ++ {0x4e,0x03}, ++ {0x4c,0x01}, ++ {0x4d,0x4c}, ++ {0x4e,0x03}, ++ {0x4c,0x01}, ++ {0x4d,0x6c}, ++ {0x4e,0x03}, ++ {0x4c,0x01}, ++ {0x4d,0x8c}, ++ {0x4e,0x03}, ++ {0x4c,0x01}, ++ {0x4d,0xac}, ++ {0x4e,0x03}, ++ {0x4c,0x01}, ++ {0x4d,0xcc}, ++ {0x4e,0x03}, ++ {0x4c,0x01}, ++ {0x4d,0xec}, ++ {0x4e,0x03}, ++ {0x4c,0x01}, ++ {0x4d,0x4b}, ++ {0x4e,0x03}, ++ {0x4c,0x01}, ++ {0x4d,0x6b}, ++ {0x4e,0x03}, ++ {0x4c,0x01}, ++ {0x4d,0x8b}, ++ {0x4e,0x03}, ++ {0x4c,0x01}, ++ {0x4d,0xab}, ++ {0x4e,0x03}, ++ {0x4c,0x01}, ++ {0x4d,0x8a}, ++ {0x4e,0x04}, ++ {0x4c,0x01}, ++ {0x4d,0xaa}, ++ {0x4e,0x04}, ++ {0x4c,0x01}, ++ {0x4d,0xca}, ++ {0x4e,0x04}, ++ {0x4c,0x01}, ++ {0x4d,0xa9}, ++ {0x4e,0x04}, ++ {0x4c,0x01}, ++ {0x4d,0xc9}, ++ {0x4e,0x04}, ++ {0x4c,0x01}, ++ {0x4d,0xcb}, ++ {0x4e,0x05}, ++ {0x4c,0x01}, ++ {0x4d,0xeb}, ++ {0x4e,0x05}, ++ {0x4c,0x02}, ++ {0x4d,0x0b}, ++ {0x4e,0x05}, ++ {0x4c,0x02}, ++ {0x4d,0x2b}, ++ {0x4e,0x05}, ++ {0x4c,0x02}, ++ {0x4d,0x4b}, ++ {0x4e,0x05}, ++ {0x4c,0x01}, ++ {0x4d,0xea}, ++ {0x4e,0x05}, ++ {0x4c,0x02}, ++ {0x4d,0x0a}, ++ {0x4e,0x05}, ++ {0x4c,0x02}, ++ {0x4d,0x2a}, ++ {0x4e,0x05}, ++ {0x4c,0x02}, ++ {0x4d,0x6a}, ++ {0x4e,0x06}, ++ {0x4c,0x02}, ++ {0x4d,0x29}, ++ {0x4e,0x06}, ++ {0x4c,0x02}, ++ {0x4d,0x49}, ++ {0x4e,0x06}, ++ {0x4c,0x02}, ++ {0x4d,0x69}, ++ {0x4e,0x06}, ++ {0x4c,0x02}, ++ {0x4d,0x89}, ++ {0x4e,0x06}, ++ {0x4c,0x02}, ++ {0x4d,0xa9}, ++ {0x4e,0x06}, ++ {0x4c,0x02}, ++ {0x4d,0xc9}, ++ {0x4e,0x06}, ++ {0x4c,0x02}, ++ {0x4d,0x48}, ++ {0x4e,0x06}, ++ {0x4c,0x02}, ++ {0x4d,0x68}, ++ {0x4e,0x06}, ++ {0x4c,0x03}, ++ {0x4d,0x09}, ++ {0x4e,0x07}, ++ {0x4c,0x02}, ++ {0x4d,0xa8}, ++ {0x4e,0x07}, ++ {0x4c,0x02}, ++ {0x4d,0xc8}, ++ {0x4e,0x07}, ++ {0x4c,0x02}, ++ {0x4d,0xe8}, ++ {0x4e,0x07}, ++ {0x4c,0x03}, ++ {0x4d,0x08}, ++ {0x4e,0x07}, ++ {0x4c,0x03}, ++ {0x4d,0x28}, ++ {0x4e,0x07}, ++ {0x4c,0x02}, ++ {0x4d,0x87}, ++ {0x4e,0x07}, ++ {0x4c,0x02}, ++ {0x4d,0xa7}, ++ {0x4e,0x07}, ++ {0x4c,0x02}, ++ {0x4d,0xc7}, ++ {0x4e,0x07}, ++ {0x4c,0x02}, ++ {0x4d,0xe7}, ++ {0x4e,0x07}, ++ {0x4c,0x03}, ++ {0x4d,0x07}, ++ {0x4e,0x07}, ++ {0x4f,0x01}, ++ {0xfe,0x01}, ++ {0x50,0x80}, ++ {0x51,0xa8}, ++ {0x52,0x57}, ++ {0x53,0x38}, ++ {0x54,0xc7}, ++ {0x56,0x0e}, ++ {0x58,0x08}, ++ {0x5b,0x00}, ++ {0x5c,0x74}, ++ {0x5d,0x8b}, ++ {0x61,0xd3}, ++ {0x62,0x90}, ++ {0x63,0xaa}, ++ {0x65,0x04}, ++ {0x67,0xb2}, ++ {0x68,0xac}, ++ {0x69,0x00}, ++ {0x6a,0xb2}, ++ {0x6b,0xac}, ++ {0x6c,0xdc}, ++ {0x6d,0xb0}, ++ {0x6e,0x30}, ++ {0x6f,0x40}, ++ {0x70,0x05}, ++ {0x71,0x80}, ++ {0x72,0x80}, ++ {0x73,0x30}, ++ {0x74,0x01}, ++ {0x75,0x01}, ++ {0x7f,0x08}, ++ {0x76,0x70}, ++ {0x77,0x48}, ++ {0x78,0xa0}, ++ {0xfe,0x00}, ++ {0xfe,0x02}, ++ {0xc0,0x01}, ++ {0xc1,0x4a}, ++ {0xc2,0xf3}, ++ {0xc3,0xfc}, ++ {0xc4,0xe4}, ++ {0xc5,0x48}, ++ {0xc6,0xec}, ++ {0xc7,0x45}, ++ {0xc8,0xf8}, ++ {0xc9,0x02}, ++ {0xca,0xfe}, ++ {0xcb,0x42}, ++ {0xcc,0x00}, ++ {0xcd,0x45}, ++ {0xce,0xf0}, ++ {0xcf,0x00}, ++ {0xe3,0xf0}, ++ {0xe4,0x45}, ++ {0xe5,0xe8}, ++ {0xfe,0x01}, ++ {0x9f,0x42}, ++ {0xfe,0x00}, ++ {0xfe,0x00}, ++ {0xf2,0x0f}, ++ {0xfe,0x00}, ++ {0x05,0x01}, ++ {0x06,0x56}, ++ {0x07,0x00}, ++ {0x08,0x32}, ++ {0xfe,0x01}, ++ {0x25,0x00}, ++ {0x26,0xfa}, ++ {0x27,0x04}, ++ {0x28,0xe2}, //20fps ++ {0x29,0x06}, ++ {0x2a,0xd6}, //16fps ++ {0x2b,0x07}, ++ {0x2c,0xd0}, //12fps ++ {0x2d,0x0b}, ++ {0x2e,0xb8}, //8fps ++ {0xfe,0x00}, ++ {0xfe,0x00}, ++ {0xfa,0x00}, ++ {0xfd,0x01}, ++ {0xfe,0x00}, ++ {0x90,0x01}, ++ {0x91,0x00}, ++ {0x92,0x00}, ++ {0x93,0x00}, ++ {0x94,0x00}, ++ {0x95,0x04},// win_size 320 * 240 ++ {0x96,0xb0}, ++ {0x97,0x06}, ++ {0x98,0x40}, ++ ++ ++ {0x99,0x11}, ++ {0x9a,0x06}, ++ {0xfe,0x01}, ++ {0xec,0x01}, ++ {0xed,0x02}, ++ {0xee,0x30}, ++ {0xef,0x48}, ++ {0xfe,0x01}, ++ {0x74,0x00}, ++ {0xfe,0x01}, ++ {0x01,0x04}, ++ {0x02,0x60}, ++ {0x03,0x02}, ++ {0x04,0x48}, ++ {0x05,0x18}, ++ {0x06,0x4c}, ++ {0x07,0x14}, ++ {0x08,0x36}, ++ {0x0a,0xc0}, ++ {0x21,0x14}, ++ {0xfe,0x00}, ++ {0xfe,0x00}, ++ {0xc3,0x11}, ++ {0xc4,0x20}, ++ {0xc5,0x30}, ++ {0xfa,0x11},//pclk rate ++ {0x86,0x06},//pclk polar ++ {0xfe,0x00}, ++ ENDMARKER, ++}; ++ ++/* qvga Center crop */ ++static const struct regval_list gc2155_qvga_regs[] = { ++ {0xfe,0x00}, ++ {0xfd,0x01}, ++ // crop window ++ {0xfe,0x00}, ++ {0x90,0x01}, ++ {0x91,0x00}, ++ {0x92,0xb4}, ++ {0x93,0x00}, ++ {0x94,0xf0}, ++ {0x95,0x00}, ++ {0x96,0xf0}, ++ {0x97,0x01}, ++ {0x98,0x40}, ++ // AWB ++ {0xfe,0x00}, ++ {0xec,0x01}, ++ {0xed,0x02}, ++ {0xee,0x30}, ++ {0xef,0x48}, ++ {0xfe,0x01}, ++ {0x74,0x00}, ++ //// AEC ++ {0xfe,0x01}, ++ {0x01,0x04}, ++ {0x02,0x60}, ++ {0x03,0x02}, ++ {0x04,0x48}, ++ {0x05,0x18}, ++ {0x06,0x4c}, ++ {0x07,0x14}, ++ {0x08,0x36}, ++ {0x0a,0xc0}, ++ {0x21,0x14}, ++#if 0 ++ {0x25,0x01}, ++ {0x26,0x90}, ++ {0x27,0x03}, ++ {0x28,0x20}, //50fps ++ {0x29,0x03}, ++ {0x2a,0x20}, ++ {0x2b,0x03}, ++ {0x2c,0x20}, ++ {0x2d,0x03}, ++ {0x2e,0x20}, ++#endif ++ {0xfe,0x00}, ++ //// gamma ++ {0xfe,0x00}, ++ {0xc3,0x11}, ++ {0xc4,0x20}, ++ {0xc5,0x30}, ++ {0xfe,0x00}, ++ ENDMARKER, ++}; ++ ++/* vga center crop */ ++static const struct regval_list gc2155_vga_regs[] = { ++ {0xfe,0x00}, ++ {0xfd,0x01}, ++ // crop window ++ {0xfe,0x00}, ++ {0x90,0x01}, ++ {0x91,0x00}, ++ {0x92,0x3c}, ++ {0x93,0x00}, ++ {0x94,0x50}, ++ {0x95,0x01}, ++ {0x96,0xe0}, ++ {0x97,0x02}, ++ {0x98,0x80}, ++ // AWB ++ {0xfe,0x00}, ++ {0xec,0x01}, ++ {0xed,0x02}, ++ {0xee,0x30}, ++ {0xef,0x48}, ++ {0xfe,0x01}, ++ {0x74,0x00}, ++ //// AEC ++ {0xfe,0x01}, ++ {0x01,0x04}, ++ {0x02,0x60}, ++ {0x03,0x02}, ++ {0x04,0x48}, ++ {0x05,0x18}, ++ {0x06,0x4c}, ++ {0x07,0x14}, ++ {0x08,0x36}, ++ {0x0a,0xc0}, ++ {0x21,0x14}, ++#if 0 ++ {0x25,0x01}, ++ {0x26,0x90}, ++ {0x27,0x03}, ++ {0x28,0x20}, //50fps ++ {0x29,0x03}, ++ {0x2a,0x20}, ++ {0x2b,0x03}, ++ {0x2c,0x20}, ++ {0x2d,0x03}, ++ {0x2e,0x20}, ++#endif ++ {0xfe,0x00}, ++ //// gamma ++ {0xfe,0x00}, ++ {0xc3,0x11}, ++ {0xc4,0x20}, ++ {0xc5,0x30}, ++ {0xfe,0x00}, ++ ENDMARKER, ++}; ++ ++static const struct regval_list gc2155_720p_regs[] = { ++ // 720P init ++ {0xfe,0x00}, ++ {0xb6,0x01}, ++ {0xfd,0x00}, ++ ++ //subsample ++ {0xfe,0x00}, ++ {0x99,0x55}, ++ {0x9a,0x06}, ++ {0x9b,0x00}, ++ {0x9c,0x00}, ++ {0x9d,0x01}, ++ {0x9e,0x23}, ++ {0x9f,0x00}, ++ {0xa0,0x00}, ++ {0xa1,0x01}, ++ {0xa2,0x23}, ++ //crop window ++ {0x90,0x01}, ++ {0x91,0x00}, ++ {0x92,0x78}, ++ {0x93,0x00}, ++ {0x94,0x00}, ++ {0x95,0x02}, ++ {0x96,0xd0}, ++ {0x97,0x05}, ++ {0x98,0x00}, ++ // AWB ++ {0xfe,0x00}, ++ {0xec,0x02}, ++ {0xed,0x04}, ++ {0xee,0x60}, ++ {0xef,0x90}, ++ {0xfe,0x01}, ++ {0x74,0x01}, ++ // AEC ++ {0xfe,0x01}, ++ {0x01,0x08}, ++ {0x02,0xc0}, ++ {0x03,0x04}, ++ {0x04,0x90}, ++ {0x05,0x30}, ++ {0x06,0x98}, ++ {0x07,0x28}, ++ {0x08,0x6c}, ++ {0x0a,0xc2}, ++ {0x21,0x15}, ++ {0xfe,0x00}, ++ //banding setting 20fps fixed/// ++ {0xfe,0x00}, ++ {0x03,0x03}, ++ {0x04,0xe8}, ++ {0x05,0x01}, ++ {0x06,0x56}, ++ {0x07,0x00}, ++ {0x08,0x32}, ++ {0xfe,0x01}, ++ {0x25,0x00}, ++ {0x26,0xfa}, ++ {0x27,0x04}, ++ {0x28,0xe2}, //20fps ++ {0x29,0x04}, ++ {0x2a,0xe2}, //16fps 5dc ++ {0x2b,0x04}, ++ {0x2c,0xe2}, //16fps 6d6 5dc ++ {0x2d,0x04}, ++ {0x2e,0xe2}, //8fps bb8 ++ {0x3c,0x00}, //8fps ++ {0xfe,0x00}, ++ ENDMARKER, ++}; ++ ++static const struct regval_list gc2155_wb_auto_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list gc2155_wb_incandescence_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list gc2155_wb_daylight_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list gc2155_wb_fluorescent_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list gc2155_wb_cloud_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct mode_list gc2155_balance[] = { ++ {0, gc2155_wb_auto_regs}, {1, gc2155_wb_incandescence_regs}, ++ {2, gc2155_wb_daylight_regs}, {3, gc2155_wb_fluorescent_regs}, ++ {4, gc2155_wb_cloud_regs}, ++}; ++ ++ ++static const struct regval_list gc2155_effect_normal_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list gc2155_effect_grayscale_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list gc2155_effect_sepia_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list gc2155_effect_colorinv_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list gc2155_effect_sepiabluel_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct mode_list gc2155_effect[] = { ++ {0, gc2155_effect_normal_regs}, {1, gc2155_effect_grayscale_regs}, ++ {2, gc2155_effect_sepia_regs}, {3, gc2155_effect_colorinv_regs}, ++ {4, gc2155_effect_sepiabluel_regs}, ++}; ++ ++#define GC2155_SIZE(n, w, h, r) \ ++ {.name = n, .width = w , .height = h, .regs = r } ++ ++static const struct gc2155_win_size gc2155_supported_win_sizes[] = { ++ GC2155_SIZE("QVGA", W_QVGA, H_QVGA, gc2155_qvga_regs), ++ GC2155_SIZE("VGA", W_VGA, H_VGA, gc2155_vga_regs), ++ GC2155_SIZE("720P", W_720P, H_720P, gc2155_720p_regs), ++}; ++ ++#define N_WIN_SIZES (ARRAY_SIZE(gc2155_supported_win_sizes)) ++ ++static const struct regval_list gc2155_yuv422_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list gc2155_rgb565_regs[] = { ++ ENDMARKER, ++}; ++ ++static u32 gc2155_codes[] = { ++ MEDIA_BUS_FMT_YUYV8_2X8, ++ MEDIA_BUS_FMT_YUYV8_1_5X8, ++ MEDIA_BUS_FMT_UYVY8_1X16, ++}; ++ ++/* ++ * Supported balance menus ++ */ ++static const struct v4l2_querymenu gc2155_balance_menus[] = { ++ { ++ .id = V4L2_CID_PRIVATE_BALANCE, ++ .index = 0, ++ .name = "auto", ++ }, { ++ .id = V4L2_CID_PRIVATE_BALANCE, ++ .index = 1, ++ .name = "incandescent", ++ }, { ++ .id = V4L2_CID_PRIVATE_BALANCE, ++ .index = 2, ++ .name = "fluorescent", ++ }, { ++ .id = V4L2_CID_PRIVATE_BALANCE, ++ .index = 3, ++ .name = "daylight", ++ }, { ++ .id = V4L2_CID_PRIVATE_BALANCE, ++ .index = 4, ++ .name = "cloudy-daylight", ++ }, ++ ++}; ++ ++/* ++ * Supported effect menus ++ */ ++static const struct v4l2_querymenu gc2155_effect_menus[] = { ++ { ++ .id = V4L2_CID_PRIVATE_EFFECT, ++ .index = 0, ++ .name = "none", ++ }, { ++ .id = V4L2_CID_PRIVATE_EFFECT, ++ .index = 1, ++ .name = "mono", ++ }, { ++ .id = V4L2_CID_PRIVATE_EFFECT, ++ .index = 2, ++ .name = "sepia", ++ }, { ++ .id = V4L2_CID_PRIVATE_EFFECT, ++ .index = 3, ++ .name = "negative", ++ }, { ++ .id = V4L2_CID_PRIVATE_EFFECT, ++ .index = 4, ++ .name = "aqua", ++ }, ++}; ++ ++ ++/* ++ * General functions ++ */ ++static struct gc2155_priv *to_gc2155(const struct i2c_client *client) ++{ ++ return container_of(i2c_get_clientdata(client), struct gc2155_priv, ++ subdev); ++} ++ ++static int gc2155_write_array(struct i2c_client *client, ++ const struct regval_list *vals) ++{ ++ int ret; ++ ++ while ((vals->reg_num != 0xff) || (vals->value != 0xff)) { ++ ret = gc2155_write_reg(client, vals->reg_num, vals->value); ++ dev_vdbg(&client->dev, "array: 0x%02x, 0x%02x", ++ vals->reg_num, vals->value); ++ ++// msleep(100); ++// my_num = gc2155_read_reg(client, vals->reg_num); ++// if (my_num != vals->value) ++// { ++// printk("vals_old->reg_num is 0x%x, vals_old->value is 0x%x, ret is 0x%x\n", vals->reg_num, vals->value, my_num); ++// } ++ if (ret < 0) ++ return ret; ++ vals++; ++ } ++ return 0; ++} ++ ++static int gc2155_mask_set(struct i2c_client *client, ++ u8 reg, u8 mask, u8 set) ++{ ++ s32 val = gc2155_read_reg(client, reg); ++ if (val < 0) ++ return val; ++ ++ val &= ~mask; ++ val |= set & mask; ++ ++ dev_vdbg(&client->dev, "masks: 0x%02x, 0x%02x", reg, val); ++ ++ return gc2155_write_reg(client, reg, val); ++} ++ ++static int gc2155_reset(struct i2c_client *client) ++{ ++ return 0; ++} ++ ++/* ++ * soc_camera_ops functions ++ */ ++static int gc2155_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ return 0; ++} ++ ++static int gc2155_g_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = ++ &container_of(ctrl->handler, struct gc2155_priv, hdl)->subdev; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct gc2155_priv *priv = to_gc2155(client); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_VFLIP: ++ ctrl->val = priv->flag_vflip; ++ break; ++ case V4L2_CID_HFLIP: ++ ctrl->val = priv->flag_hflip; ++ break; ++ case V4L2_CID_PRIVATE_BALANCE: ++ ctrl->val = priv->balance_value; ++ break; ++ case V4L2_CID_PRIVATE_EFFECT: ++ ctrl->val = priv->effect_value; ++ break; ++ default: ++ break; ++ } ++ return 0; ++} ++ ++static int gc2155_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = ++ &container_of(ctrl->handler, struct gc2155_priv, hdl)->subdev; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct gc2155_priv *priv = to_gc2155(client); ++ int ret = 0; ++ int i = 0; ++ u8 value; ++ ++ int balance_count = ARRAY_SIZE(gc2155_balance); ++ int effect_count = ARRAY_SIZE(gc2155_effect); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_PRIVATE_BALANCE: ++ if(ctrl->val > balance_count) ++ return -EINVAL; ++ ++ for(i = 0; i < balance_count; i++) { ++ if(ctrl->val == gc2155_balance[i].index) { ++ ret = gc2155_write_array(client, ++ gc2155_balance[ctrl->val].mode_regs); ++ priv->balance_value = ctrl->val; ++ break; ++ } ++ } ++ break; ++ ++ case V4L2_CID_PRIVATE_EFFECT: ++ if(ctrl->val > effect_count) ++ return -EINVAL; ++ ++ for(i = 0; i < effect_count; i++) { ++ if(ctrl->val == gc2155_effect[i].index) { ++ ret = gc2155_write_array(client, ++ gc2155_effect[ctrl->val].mode_regs); ++ priv->effect_value = ctrl->val; ++ break; ++ } ++ } ++ break; ++ ++ case V4L2_CID_VFLIP: ++ value = ctrl->val ? REG14_VFLIP_IMG : 0x00; ++ priv->flag_vflip = ctrl->val ? 1 : 0; ++ ret = gc2155_mask_set(client, REG14, REG14_VFLIP_IMG, value); ++ break; ++ ++ case V4L2_CID_HFLIP: ++ value = ctrl->val ? REG14_HFLIP_IMG : 0x00; ++ priv->flag_hflip = ctrl->val ? 1 : 0; ++ ret = gc2155_mask_set(client, REG14, REG14_HFLIP_IMG, value); ++ break; ++ ++ default: ++ dev_err(&client->dev, "no V4L2 CID: 0x%x ", ctrl->id); ++ return -EINVAL; ++ } ++ ++ return ret; ++} ++ ++static int gc2155_querymenu(struct v4l2_subdev *sd, ++ struct v4l2_querymenu *qm) ++{ ++ switch (qm->id) { ++ case V4L2_CID_PRIVATE_BALANCE: ++ memcpy(qm->name, gc2155_balance_menus[qm->index].name, ++ sizeof(qm->name)); ++ break; ++ ++ case V4L2_CID_PRIVATE_EFFECT: ++ memcpy(qm->name, gc2155_effect_menus[qm->index].name, ++ sizeof(qm->name)); ++ break; ++ } ++ ++ return 0; ++} ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int gc2155_g_register(struct v4l2_subdev *sd, ++ struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ int ret; ++ ++ reg->size = 1; ++ if (reg->reg > 0xff) ++ return -EINVAL; ++ ++ ret = gc2155_read_reg(client, reg->reg); ++ if (ret < 0) ++ return ret; ++ ++ reg->val = ret; ++ ++ return 0; ++} ++ ++static int gc2155_s_register(struct v4l2_subdev *sd, ++ const struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ if (reg->reg > 0xff || ++ reg->val > 0xff) ++ return -EINVAL; ++ ++ return gc2155_write_reg(client, reg->reg, reg->val); ++} ++#endif ++ ++/* Select the nearest higher resolution for capture */ ++static const struct gc2155_win_size *gc2155_select_win(u32 *width, u32 *height) ++{ ++ int i, default_size = ARRAY_SIZE(gc2155_supported_win_sizes) - 1; ++ ++ for (i = 0; i < ARRAY_SIZE(gc2155_supported_win_sizes); i++) { ++ if ((gc2155_supported_win_sizes[i].width >= *width) && ++ (gc2155_supported_win_sizes[i].height >= *height)) { ++ *width = gc2155_supported_win_sizes[i].width; ++ *height = gc2155_supported_win_sizes[i].height; ++ return &gc2155_supported_win_sizes[i]; ++ } ++ } ++ ++ *width = gc2155_supported_win_sizes[default_size].width; ++ *height = gc2155_supported_win_sizes[default_size].height; ++ return &gc2155_supported_win_sizes[default_size]; ++} ++ ++static int gc2155_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct gc2155_priv *priv = to_gc2155(client); ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ if (!priv->win) { ++ u32 width = W_VGA, height = H_VGA; ++ priv->win = gc2155_select_win(&width, &height); ++ priv->cfmt_code = MEDIA_BUS_FMT_YUYV8_2X8; ++ } ++ ++ mf->width = priv->win->width; ++ mf->height = priv->win->height; ++ mf->code = priv->cfmt_code; ++ ++ mf->colorspace = V4L2_COLORSPACE_JPEG; ++ mf->field = V4L2_FIELD_NONE; ++ ++ return 0; ++} ++ ++static int gc2155_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ /* ++ * select suitable win, but don't store it ++ */ ++ gc2155_select_win(&mf->width, &mf->height); ++ ++ mf->field = V4L2_FIELD_NONE; ++ ++ switch (mf->code) { ++ case MEDIA_BUS_FMT_RGB565_2X8_BE: ++ case MEDIA_BUS_FMT_RGB565_2X8_LE: ++ mf->colorspace = V4L2_COLORSPACE_SRGB; ++ break; ++ default: ++ mf->code = MEDIA_BUS_FMT_UYVY8_2X8; ++ case MEDIA_BUS_FMT_YUYV8_2X8: ++ case MEDIA_BUS_FMT_UYVY8_2X8: ++ mf->colorspace = V4L2_COLORSPACE_JPEG; ++ } ++ ++ if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) ++ return gc2155_set_params(client, &mf->width, ++ &mf->height, mf->code); ++ cfg->try_fmt = *mf; ++ return 0; ++} ++ ++static int gc2155_set_params(struct i2c_client *client, u32 *width, u32 *height, u32 code) ++{ ++ struct gc2155_priv *priv = to_gc2155(client); ++ int ret; ++ ++ int bala_index = priv->balance_value; ++ int effe_index = priv->effect_value; ++ ++ /* select win */ ++ priv->win = gc2155_select_win(width, height); ++ ++ /* select format */ ++ priv->cfmt_code = 0; ++ ++ /* reset hardware */ ++ gc2155_reset(client); ++ ++ /* initialize the sensor with default data */ ++ dev_dbg(&client->dev, "%s: Init default", __func__); ++ ret = gc2155_write_array(client, gc2155_init_regs); ++ if (ret < 0) ++ goto err; ++ ++ /* set balance */ ++ ret = gc2155_write_array(client, gc2155_balance[bala_index].mode_regs); ++ if (ret < 0) ++ goto err; ++ ++ /* set effect */ ++ ret = gc2155_write_array(client, gc2155_effect[effe_index].mode_regs); ++ if (ret < 0) ++ goto err; ++ ++ /* set size win */ ++ ret = gc2155_write_array(client, priv->win->regs); ++ if (ret < 0) ++ goto err; ++ ++ priv->cfmt_code = code; ++ *width = priv->win->width; ++ *height = priv->win->height; ++ ++ return 0; ++ ++err: ++ dev_err(&client->dev, "%s: Error %d", __func__, ret); ++ gc2155_reset(client); ++ priv->win = NULL; ++ ++ return ret; ++} ++ ++static int gc2155_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ if (code->pad || code->index >= ARRAY_SIZE(gc2155_codes)) ++ return -EINVAL; ++ ++ code->code = gc2155_codes[code->index]; ++ return 0; ++} ++ ++static int gc2155_enum_frame_size(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_frame_size_enum *fse) ++{ ++ int i, j; ++ int num_valid = -1; ++ __u32 index = fse->index; ++ ++ if(index >= N_WIN_SIZES) ++ return -EINVAL; ++ ++ j = ARRAY_SIZE(gc2155_codes); ++ while(--j) ++ if(fse->code == gc2155_codes[j]) ++ break; ++ ++ for (i = 0; i < N_WIN_SIZES; i++) { ++ if (index == ++num_valid) { ++ fse->code = gc2155_codes[j]; ++ fse->min_width = gc2155_supported_win_sizes[index].width; ++ fse->max_width = fse->min_width; ++ fse->min_height = gc2155_supported_win_sizes[index].height; ++ fse->max_height = fse->min_height; ++ return 0; ++ } ++ } ++ ++ return -EINVAL; ++} ++ ++ ++static int gc2155_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) ++{ ++ a->c.left = 0; ++ a->c.top = 0; ++ a->c.width = W_720P; ++ a->c.height = H_720P; ++ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ ++ return 0; ++} ++ ++static int gc2155_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) ++{ ++ a->bounds.left = 0; ++ a->bounds.top = 0; ++ a->bounds.width = W_720P; ++ a->bounds.height = H_720P; ++ a->defrect = a->bounds; ++ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ a->pixelaspect.numerator = 1; ++ a->pixelaspect.denominator = 1; ++ ++ return 0; ++} ++ ++static int gc2155_video_probe(struct i2c_client *client) ++{ ++ unsigned char retval_high = 0, retval_low = 0; ++ struct gc2155_priv *priv = to_gc2155(client); ++ int ret; ++ ++ ret = gc2155_s_power(&priv->subdev, 1); ++ if (ret < 0) ++ return ret; ++ /* ++ * check and show product ID and manufacturer ID ++ */ ++ ++ retval_high = gc2155_read_reg(client, REG_CHIP_ID_HIGH); ++ if (retval_high != CHIP_ID_HIGH) { ++ dev_err(&client->dev, "read sensor %s chip_id high %x is error\n", ++ client->name, retval_high); ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ ++ retval_low = gc2155_read_reg(client, REG_CHIP_ID_LOW); ++ if (retval_low != CHIP_ID_LOW) { ++ dev_err(&client->dev, "read sensor %s chip_id low %x is error\n", ++ client->name, retval_low); ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ dev_info(&client->dev, "read sensor %s id high:0x%x,low:%x successed!\n", ++ client->name, retval_high, retval_low); ++ ++ ret = v4l2_ctrl_handler_setup(&priv->hdl); ++ ++done: ++ gc2155_s_power(&priv->subdev, 0); ++ return ret; ++} ++ ++static int gc2155_s_power(struct v4l2_subdev *sd, int on) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); ++ struct gc2155_priv *priv = to_gc2155(client); ++ ++ return soc_camera_set_power(&client->dev, ssdd, priv->clk, on); ++} ++ ++static const struct v4l2_ctrl_ops gc2155_ctrl_ops = { ++ .s_ctrl = gc2155_s_ctrl, ++ .g_volatile_ctrl = gc2155_g_ctrl, ++}; ++ ++static struct v4l2_subdev_core_ops gc2155_subdev_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = gc2155_g_register, ++ .s_register = gc2155_s_register, ++#endif ++ .s_power = gc2155_s_power, ++ .querymenu = gc2155_querymenu, ++}; ++ ++static int gc2155_g_mbus_config(struct v4l2_subdev *sd, ++ struct v4l2_mbus_config *cfg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); ++ ++ cfg->flags = V4L2_MBUS_PCLK_SAMPLE_FALLING | V4L2_MBUS_MASTER | ++ V4L2_MBUS_VSYNC_ACTIVE_LOW | V4L2_MBUS_HSYNC_ACTIVE_HIGH | ++ V4L2_MBUS_DATA_ACTIVE_HIGH; ++ cfg->type = V4L2_MBUS_PARALLEL; ++ ++ cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); ++ ++ return 0; ++} ++ ++static struct v4l2_subdev_video_ops gc2155_subdev_video_ops = { ++ .s_stream = gc2155_s_stream, ++ .cropcap = gc2155_cropcap, ++ .g_crop = gc2155_g_crop, ++ .g_mbus_config = gc2155_g_mbus_config, ++}; ++ ++static const struct v4l2_subdev_pad_ops gc2155_subdev_pad_ops = { ++ .enum_mbus_code = gc2155_enum_mbus_code, ++ .enum_frame_size = gc2155_enum_frame_size, ++ .get_fmt = gc2155_get_fmt, ++ .set_fmt = gc2155_set_fmt, ++}; ++ ++static struct v4l2_subdev_ops gc2155_subdev_ops = { ++ .core = &gc2155_subdev_core_ops, ++ .video = &gc2155_subdev_video_ops, ++ .pad = &gc2155_subdev_pad_ops, ++}; ++ ++/* OF probe functions */ ++static int gc2155_hw_power(struct device *dev, int on) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct gc2155_priv *priv = to_gc2155(client); ++ ++ dev_dbg(&client->dev, "%s: %s the camera\n", ++ __func__, on ? "ENABLE" : "DISABLE"); ++ ++ /* thses gpio should be set according to the active level in dt defines */ ++ if(priv->vcc_en_gpio) { ++ gpiod_direction_output(priv->vcc_en_gpio, on); ++ } ++ ++ if (priv->pwdn_gpio) { ++ gpiod_direction_output(priv->pwdn_gpio, !on); ++ } ++ ++ msleep(10); ++ return 0; ++} ++ ++static int gc2155_hw_reset(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct gc2155_priv *priv = to_gc2155(client); ++ ++ if (priv->resetb_gpio) { ++ /* Active the resetb pin to perform a reset pulse */ ++ gpiod_direction_output(priv->resetb_gpio, 1); ++ usleep_range(3000, 5000); ++ gpiod_direction_output(priv->resetb_gpio, 0); ++ } ++ ++ return 0; ++} ++ ++ ++static int gc2155_probe_dt(struct i2c_client *client, ++ struct gc2155_priv *priv) ++{ ++ ++ struct soc_camera_subdev_desc *ssdd_dt = &priv->ssdd_dt; ++ struct v4l2_subdev_platform_data *sd_pdata = &ssdd_dt->sd_pdata; ++ struct device_node *np = client->dev.of_node; ++ int supplies = 0, index = 0; ++ ++ supplies = of_property_count_strings(np, "supplies-name"); ++ if(supplies <= 0) { ++ goto no_supply; ++ } ++ ++ sd_pdata->num_regulators = supplies; ++ sd_pdata->regulators = devm_kzalloc(&client->dev, supplies * sizeof(struct regulator_bulk_data), GFP_KERNEL); ++ if(!sd_pdata->regulators) { ++ dev_err(&client->dev, "Failed to allocate regulators.!\n"); ++ goto no_supply; ++ } ++ ++ for(index = 0; index < sd_pdata->num_regulators; index ++) { ++ of_property_read_string_index(np, "supplies-name", index, ++ &(sd_pdata->regulators[index].supply)); ++ ++ dev_dbg(&client->dev, "sd_pdata->regulators[%d].supply: %s\n", ++ index, sd_pdata->regulators[index].supply); ++ } ++ ++ soc_camera_power_init(&client->dev, ssdd_dt); ++ ++no_supply: ++ ++ /* Request the reset GPIO deasserted */ ++ priv->resetb_gpio = devm_gpiod_get_optional(&client->dev, "resetb", ++ GPIOD_OUT_LOW); ++ if (!priv->resetb_gpio) ++ dev_dbg(&client->dev, "resetb gpio is not assigned!\n"); ++ else if (IS_ERR(priv->resetb_gpio)) ++ return PTR_ERR(priv->resetb_gpio); ++ ++ /* Request the power down GPIO asserted */ ++ priv->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "pwdn", ++ GPIOD_OUT_HIGH); ++ if (!priv->pwdn_gpio) ++ dev_dbg(&client->dev, "pwdn gpio is not assigned!\n"); ++ else if (IS_ERR(priv->pwdn_gpio)) ++ return PTR_ERR(priv->pwdn_gpio); ++ ++ /* Request the power down GPIO asserted */ ++ priv->vcc_en_gpio = devm_gpiod_get_optional(&client->dev, "vcc-en", ++ GPIOD_OUT_HIGH); ++ if (!priv->vcc_en_gpio) ++ dev_dbg(&client->dev, "vcc_en gpio is not assigned!\n"); ++ else if (IS_ERR(priv->vcc_en_gpio)) ++ return PTR_ERR(priv->vcc_en_gpio); ++ ++ /* Initialize the soc_camera_subdev_desc */ ++ priv->ssdd_dt.power = gc2155_hw_power; ++ priv->ssdd_dt.reset = gc2155_hw_reset; ++ client->dev.platform_data = &priv->ssdd_dt; ++ return 0; ++} ++ ++#include ++/* ++ * i2c_driver functions ++ */ ++static int gc2155_probe(struct i2c_client *client, ++ const struct i2c_device_id *did) ++{ ++ struct gc2155_priv *priv; ++ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); ++ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); ++ int ret; ++ ++ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA)) { ++ dev_err(&adapter->dev, ++ "GC2155: I2C-Adapter doesn't support SMBUS\n"); ++ return -EIO; ++ } ++ ++ priv = devm_kzalloc(&client->dev, sizeof(struct gc2155_priv), GFP_KERNEL); ++ if (!priv) { ++ dev_err(&adapter->dev, ++ "Failed to allocate memory for private data!\n"); ++ return -ENOMEM; ++ } ++ ++ priv->clk = v4l2_clk_get(&client->dev, "cgu_cim"); ++ if (IS_ERR(priv->clk)) ++ return -EPROBE_DEFER; ++ ++ v4l2_clk_set_rate(priv->clk, 24000000); ++ ++ if (!ssdd && !client->dev.of_node) { ++ dev_err(&client->dev, "Missing platform_data for driver\n"); ++ ret = -EINVAL; ++ goto err_videoprobe; ++ } ++ ++ if (!ssdd) { ++ ret = gc2155_probe_dt(client, priv); ++ if (ret) ++ goto err_clk; ++ } ++ ++ ++ v4l2_i2c_subdev_init(&priv->subdev, client, &gc2155_subdev_ops); ++ ++ /* add handler */ ++ v4l2_ctrl_handler_init(&priv->hdl, 2); ++ v4l2_ctrl_new_std(&priv->hdl, &gc2155_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&priv->hdl, &gc2155_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ priv->subdev.ctrl_handler = &priv->hdl; ++ if (priv->hdl.error) { ++ ret = priv->hdl.error; ++ goto err_clk; ++ } ++ ++ ret = gc2155_video_probe(client); ++ if (ret < 0) ++ goto err_videoprobe; ++ ++ ret = v4l2_async_register_subdev(&priv->subdev); ++ if (ret < 0) ++ goto err_videoprobe; ++ ++ dev_info(&adapter->dev, "GC2155 Probed\n"); ++ ++ return 0; ++ ++err_videoprobe: ++ v4l2_ctrl_handler_free(&priv->hdl); ++err_clk: ++ v4l2_clk_put(priv->clk); ++ return ret; ++} ++ ++static int gc2155_remove(struct i2c_client *client) ++{ ++ struct gc2155_priv *priv = to_gc2155(client); ++ ++ v4l2_async_unregister_subdev(&priv->subdev); ++ v4l2_clk_put(priv->clk); ++ v4l2_device_unregister_subdev(&priv->subdev); ++ v4l2_ctrl_handler_free(&priv->hdl); ++ return 0; ++} ++ ++static const struct i2c_device_id gc2155_id[] = { ++ { "gc2155", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, gc2155_id); ++static const struct of_device_id gc2155_of_match[] = { ++ {.compatible = "galaxycore,gc2155", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, gc2155_of_match); ++static struct i2c_driver gc2155_i2c_driver = { ++ .driver = { ++ .name = "gc2155", ++ .of_match_table = of_match_ptr(gc2155_of_match), ++ }, ++ .probe = gc2155_probe, ++ .remove = gc2155_remove, ++ .id_table = gc2155_id, ++}; ++module_i2c_driver(gc2155_i2c_driver); ++ ++MODULE_DESCRIPTION("SoC Camera driver for galaxycore gc2155 sensor"); ++MODULE_AUTHOR("Alberto Panizzo"); ++MODULE_LICENSE("GPL v2"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_i2c_soc_camera_mt9v022_test.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_i2c_soc_camera_mt9v022_test.c.patch new file mode 100644 index 00000000..eccc7cb1 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_i2c_soc_camera_mt9v022_test.c.patch @@ -0,0 +1,1457 @@ +diff -drupN a/drivers/media/i2c/soc_camera/mt9v022_test.c b/drivers/media/i2c/soc_camera/mt9v022_test.c +--- a/drivers/media/i2c/soc_camera/mt9v022_test.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/i2c/soc_camera/mt9v022_test.c 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,1453 @@ ++/* ++ * mt9v022 Camera Driver ++ * ++ * Copyright (C) 2010 Alberto Panizzo ++ * ++ * Based on ov772x, ov9640 drivers and previous non merged implementations. ++ * ++ * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. ++ * Copyright (C) 2006, OmniVision ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#define REG_CHIP_ID_HIGH 0x300a ++#define REG_CHIP_ID_LOW 0x300b ++#define CHIP_ID_HIGH 0x56 ++#define CHIP_ID_LOW 0x40 ++ ++#define MT9V022_DEFAULT_WIDTH 320 ++#define MT9V022_DEFAULT_HEIGHT 240 ++ ++/* Private v4l2 controls */ ++#define V4L2_CID_PRIVATE_BALANCE (V4L2_CID_PRIVATE_BASE + 0) ++#define V4L2_CID_PRIVATE_EFFECT (V4L2_CID_PRIVATE_BASE + 1) ++ ++#define REG_TC_VFLIP 0x3820 ++#define REG_TC_MIRROR 0x3821 ++#define MT9V022_FLIP_VAL ((unsigned char)0x04) ++#define MT9V022_FLIP_MASK ((unsigned char)0x04) ++ ++/* whether sensor support high resolution (> vga) preview or not */ ++#define SUPPORT_HIGH_RESOLUTION_PRE 1 ++ ++#define MT9V022_SNAPSHOT ++/* ++ * Struct ++ */ ++struct regval_list { ++ u16 reg_num; ++ u16 value; ++}; ++ ++struct mode_list { ++ u16 index; ++ const struct regval_list *mode_regs; ++}; ++ ++/* Supported resolutions */ ++enum mt9v022_width { ++ W_720P = MT9V022_DEFAULT_WIDTH, ++}; ++ ++enum mt9v022_height { ++ H_720P = MT9V022_DEFAULT_HEIGHT, ++}; ++ ++struct mt9v022_win_size { ++ char *name; ++ enum mt9v022_width width; ++ enum mt9v022_height height; ++ const struct regval_list *regs; ++}; ++ ++struct mt9v022_priv { ++ struct v4l2_subdev subdev; ++ struct v4l2_ctrl_handler hdl; ++ u32 cfmt_code; ++ struct v4l2_clk *clk; ++ const struct mt9v022_win_size *win; ++ ++ int model; ++ u16 balance_value; ++ u16 effect_value; ++ u16 flag_vflip:1; ++ u16 flag_hflip:1; ++ ++ struct soc_camera_subdev_desc ssdd_dt; ++ struct gpio_desc *resetb_gpio; ++ struct gpio_desc *pwdn_gpio; ++ struct gpio_desc *vcc_en_gpio; ++ ++ struct regulator *reg; ++ struct regulator *reg1; ++}; ++ ++static int mt9v022_s_power(struct v4l2_subdev *sd, int on); ++static inline int sensor_i2c_master_send(struct i2c_client *client, ++ const char *buf ,int count) ++{ ++ return 0; ++} ++ ++static inline int sensor_i2c_master_recv(struct i2c_client *client, ++ char *buf ,int count) ++{ ++ return 0; ++} ++ ++ ++s32 mt9v022_read_reg(struct i2c_client *client, u16 reg) ++{ ++ return i2c_smbus_read_word_swapped(client, reg); ++} ++ ++s32 mt9v022_write_reg(struct i2c_client *client, u8 reg, u16 val) ++{ ++ return i2c_smbus_write_word_swapped(client, reg, val); ++} ++ ++/* ++ * Registers settings ++ */ ++ ++#define ENDMARKER { 0xff, 0xff } ++ ++static const struct regval_list mt9v022_init_regs[] = { ++#ifndef MT9V022_SNAPSHOT ++ {0x0031, 0x001F}, //V1_CONTROL ++ {0x0032, 0x001A}, //V2_CONTROL ++ {0x0033, 0x0012}, //V3_CONTROL ++ {0x00AF, 0x0000}, //AUTO_BLOCK_CONTROL ++ {0x002B, 0x0003}, ++ {0x0010, 0x0040}, ++ ++ {0x000F, 0x0051}, //PIXEL_OPERATION_MODE ++ {0x0010, 0x0040}, ++ {0x0015, 0x7F32}, ++ {0x001C, 0x0003}, //DATA_COMPRESSION ++ {0x0020, 0x01D5}, ++ {0x002B, 0x0000}, ++ {0x0048, 0x0000}, //TARGET_CALIB_VALUE ++ {0x0070, 0x0004}, //ROW_NOISE_CONTROL ++ {0x0073, 0x02F7}, //DARK_COL_START ++ {0x00AB, 0x0000}, //GAIN_LPF_H ++ {0x00BF, 0x0014}, //INTERLACE_VBLANK ++ {0x00C2, 0x0940}, ++ ++ {0x000F, 0x0011}, //PIXEL_OPERATION_MODE ++ {0x0015, 0x7F32}, ++ {0x001C, 0x0002}, //DATA_COMPRESSION ++ {0x0020, 0x01D1}, ++ {0x00C2, 0x0840}, ++ ++ {0x0001, 0x0001}, // [0:00:01.449] REG=1, 1 //COL_WINDOW_START_REG ++ {0x0002, 0x0004}, // [0:00:01.452] REG=2, 4 //ROW_WINDOW_START_REG ++ {0x0003, 0x01E0}, // [0:00:01.454] REG=3, 480 //ROW_WINDOW_SIZE_REG ++// {0x0004, 0x02F0}, // [0:00:01.456] REG=4, 752 //COL_WINDOW_SIZE_REG ++ {0x0004, 0x0280}, // [0:00:01.456] REG=4, 640 //COL_WINDOW_SIZE_REG ++ {0x0005, 0x005E}, // [0:00:01.457] REG=5, 94 //HORZ_BLANK_REG ++ {0x0006, 0x002D}, // [0:00:01.458] REG=6, 45 //VERT_BLANK_REG ++ {0x0007, 0x0388}, // [0:00:01.459] REG=7, 904 //CONTROL_MODE_REG ++ {0x0008, 0x01BB}, // [0:00:01.460] REG=8, 443 //SHUTTER_WIDTH_REG_1 ++ {0x0009, 0x01D9}, // [0:00:01.461] REG=9, 473 //SHUTTER_WIDTH_REG_2 ++ {0x000A, 0x0164}, // [0:00:01.462] REG=10, 356 //SHUTTER_WIDTH_CONTROL ++ {0x000B, 0x01E0}, // [0:00:01.463] REG=11, 480 //INTEG_TIME_REG ++ {0x000C, 0x0000}, // [0:00:01.464] REG=12, 0 //RESET_REG ++ {0x000D, 0x0304}, // [0:00:01.465] REG=13, 768 //READ_MODE_REG ++ {0x000E, 0x0000}, // [0:00:01.466] REG=14, 0 //MONITOR_MODE_CONTROL ++ {0x000F, 0x0011}, // [0:00:01.467] REG=15, 17 //PIXEL_OPERATION_MODE ++ {0x0010, 0x0040}, // [0:00:01.468] REG=16, 0x40 ++ {0x0011, 0x8042}, // [0:00:01.469]REG=17, 32834 ++ {0x0012, 0x0022}, // [0:00:01.470] REG=18, 34 ++ {0x0013, 0x2D32}, // [0:00:01.471]REG=19, 0x2D32 ++ {0x0014, 0x0E02}, // [0:00:01.472] REG=20, 3586 ++ {0x0015, 0x7F32}, // [0:00:01.473]REG=21, 0x7F32 ++ {0x0016, 0x2802}, // [0:00:01.474]REG=22, 10242 ++ {0x0017, 0x3E38}, // [0:00:01.475]REG=23, 15928 ++ {0x0018, 0x3E38}, // [0:00:01.476]REG=24, 15928 ++ {0x0019, 0x2802}, // [0:00:01.477]REG=25, 10242 ++ {0x001A, 0x0428}, // [0:00:01.478] REG=26, 1064 ++ {0x001B, 0x0000}, // [0:00:01.479] REG=27, 0 //LED_OUT_CONTROL ++ {0x001C, 0x0002}, // [0:00:01.482] REG=28, 2 //DATA_COMPRESSION ++ {0x001D, 0x0000}, // [0:00:01.483] REG=29, 0 ++ {0x001E, 0x0000}, // [0:00:01.484] REG=30, 0 ++ {0x001F, 0x0000}, // [0:00:01.485] REG=31, 0 ++ {0x0020, 0x01D1}, // [0:00:01.486] REG=32, 0x1D1 ++ {0x0021, 0x0020}, // [0:00:01.487] REG=33, 32 ++ {0x0022, 0x0020}, // [0:00:01.488] REG=34, 32 ++ {0x0023, 0x0010}, // [0:00:01.489] REG=35, 16 ++ {0x0024, 0x0010}, // [0:00:01.490] REG=36, 16 ++ {0x0025, 0x0020}, // [0:00:01.491] REG=37, 32 ++ {0x0026, 0x0010}, // [0:00:01.492] REG=38, 16 ++ {0x0027, 0x0010}, // [0:00:01.493] REG=39, 16 ++ {0x0028, 0x0010}, // [0:00:01.494] REG=40, 16 ++ {0x0029, 0x0010}, // [0:00:01.495] REG=41, 16 ++ {0x002A, 0x0020}, // [0:00:01.496] REG=42, 32 ++ {0x002B, 0x0004}, // [0:00:01.497] REG=43, 4 ++ {0x002C, 0x0004}, // [0:00:01.498] REG=44, 4 ++ {0x002D, 0x0004}, // [0:00:01.499] REG=45, 4 ++ {0x002E, 0x0007}, // [0:00:01.500] REG=46, 7 ++ {0x002F, 0x0004}, // [0:00:01.501] REG=47, 4 ++ {0x0030, 0x0003}, // [0:00:01.502] REG=48, 3 ++ {0x0031, 0x001D}, // [0:00:01.503] REG=49, 29 //V1_CONTROL ++ {0x0032, 0x0018}, // [0:00:01.504] REG=50, 24 //V2_CONTROL ++ {0x0033, 0x0015}, // [0:00:01.505] REG=51, 21 //V3_CONTROL ++ {0x0034, 0x0004}, // [0:00:01.506] REG=52, 4 //V4_CONTROL ++ {0x0035, 0x0010}, // [0:00:01.507] REG=53, 16 //GLOBAL_GAIN_REG ++ {0x0036, 0x0040}, // [0:00:01.508] REG=54, 64 //MAXIMUM_GAIN_REG ++ {0x0037, 0x0000}, // [0:00:01.509] REG=55, 0 ++ {0x0038, 0x0000}, // [0:00:01.510] REG=56, 0 ++ {0x0046, 0x231D}, // [0:00:01.511]REG=70, 8989 //DARK_AVG_THRESHOLDS ++ {0x0047, 0x8080}, // [0:00:01.512]REG=71, 32896 //CALIB_CONTROL_REG ++ {0x004C, 0x0002}, // [0:00:01.513] REG=76, 2 //STEP_SIZE_AVG_MODE ++ {0x0060, 0x0000}, // [0:00:01.514] REG=96, 0 ++ {0x0061, 0x0000}, // [0:00:01.515] REG=97, 0 ++ {0x0062, 0x0000}, // [0:00:01.516] REG=98, 0 ++ {0x0063, 0x0000}, // [0:00:01.517] REG=99, 0 ++ {0x0064, 0x0000}, // [0:00:01.518] REG=100, 0 ++ {0x0065, 0x0000}, // [0:00:01.519] REG=101, 0 ++ {0x0066, 0x0000}, // [0:00:01.520] REG=102, 0 ++ {0x0067, 0x0000}, // [0:00:01.521] REG=103, 0 ++ {0x006C, 0x0000}, // [0:00:01.522] REG=108, 0 ++ {0x0070, 0x0034}, // [0:00:01.523] REG=112, 52 //ROW_NOISE_CONTROL ++ {0x0071, 0x0000}, // [0:00:01.524] REG=113, 0 ++ {0x0072, 0x002A}, // [0:00:01.525] REG=114, 42 //NOISE_CONSTANT ++ {0x0073, 0x02F7}, // [0:00:01.526] REG=115, 759 //DARK_COL_START ++// {0x0074, 0x0000}, // [0:00:01.527] REG=116, 0 //PIXCLK_CONTROL ++ {0x0074, 0x0012}, // [0:00:01.527] REG=116, 0 //PIXCLK_CONTROL ++ {0x007F, 0x0000}, // [0:00:01.528] REG=127, 0 //TEST_DATA ++ {0x0080, 0x00F4}, // [0:00:01.529] REG=128, 244 //TILE_X0_Y0 ++ {0x0081, 0x00F4}, // [0:00:01.530] REG=129, 244 //TILE_X1_Y0 ++ {0x0082, 0x00F4}, // [0:00:01.531] REG=130, 244 //TILE_X2_Y0 ++ {0x0083, 0x00F4}, // [0:00:01.532] REG=131, 244 //TILE_X3_Y0 ++ {0x0084, 0x00F4}, // [0:00:01.533] REG=132, 244 //TILE_X4_Y0 ++ {0x0085, 0x00F4}, // [0:00:01.534] REG=133, 244 //TILE_X0_Y1 ++ {0x0086, 0x00F4}, // [0:00:01.535] REG=134, 244 //TILE_X1_Y1 ++ {0x0087, 0x00F4}, // [0:00:01.536] REG=135, 244 //TILE_X2_Y1 ++ {0x0088, 0x00F4}, // [0:00:01.537] REG=136, 244 //TILE_X3_Y1 ++ {0x0089, 0x00F4}, // [0:00:01.538] REG=137, 244 //TILE_X4_Y1 ++ {0x008A, 0x00F4}, // [0:00:01.539] REG=138, 244 //TILE_X0_Y2 ++ {0x008B, 0x00F4}, // [0:00:01.540] REG=139, 244 //TILE_X1_Y2 ++ {0x008C, 0x00F4}, // [0:00:01.541] REG=140, 244 //TILE_X2_Y2 ++ {0x008D, 0x00F4}, // [0:00:01.542] REG=141, 244 //TILE_X3_Y2 ++ {0x008E, 0x00F4}, // [0:00:01.543] REG=142, 244 //TILE_X4_Y2 ++ {0x008F, 0x00F4}, // [0:00:01.544] REG=143, 244 //TILE_X0_Y3 ++ {0x0090, 0x00F4}, // [0:00:01.545] REG=144, 244 //TILE_X1_Y3 ++ {0x0091, 0x00F4}, // [0:00:01.546] REG=145, 244 //TILE_X2_Y3 ++ {0x0092, 0x00F4}, // [0:00:01.547] REG=146, 244 //TILE_X3_Y3 ++ {0x0093, 0x00F4}, // [0:00:01.548] REG=147, 244 //TILE_X4_Y3 ++ {0x0094, 0x00F4}, // [0:00:01.549] REG=148, 244 //TILE_X0_Y4 ++ {0x0095, 0x00F4}, // [0:00:01.550] REG=149, 244 //TILE_X1_Y4 ++ {0x0096, 0x00F4}, // [0:00:01.551] REG=150, 244 //TILE_X2_Y4 ++ {0x0097, 0x00F4}, // [0:00:01.552] REG=151, 244 //TILE_X3_Y4 ++ {0x0098, 0x00F4}, // [0:00:01.553] REG=152, 244 //TILE_X4_Y4 ++ {0x0099, 0x0000}, // [0:00:01.554] REG=153, 0 //X0_SLASH5 ++ {0x009A, 0x0096}, // [0:00:01.555] REG=154, 150 //X1_SLASH5 ++ {0x009B, 0x012C}, // [0:00:01.556] REG=155, 300 //X2_SLASH5 ++ {0x009C, 0x01C2}, // [0:00:01.557] REG=156, 450 //X3_SLASH5 ++ {0x009D, 0x0258}, // [0:00:01.558] REG=157, 600 //X4_SLASH5 ++ {0x009E, 0x02F0}, // [0:00:01.559] REG=158, 752 //X5_SLASH5 ++ {0x009F, 0x0000}, // [0:00:01.560] REG=159, 0 //Y0_SLASH5 ++ {0x00A0, 0x0060}, // [0:00:01.561] REG=160, 96 //Y1_SLASH5 ++ {0x00A1, 0x00C0}, // [0:00:01.563] REG=161, 192 //Y2_SLASH5 ++ {0x00A2, 0x0120}, // [0:00:01.564] REG=162, 288 //Y3_SLASH5 ++ {0x00A3, 0x0180}, // [0:00:01.565] REG=163, 384 //Y4_SLASH5 ++ {0x00A4, 0x01E0}, // [0:00:01.566] REG=164, 480 //Y5_SLASH5 ++ {0x00A5, 0x003A}, // [0:00:01.567] REG=165, 58 //DESIRED_BIN ++ {0x00A6, 0x0002}, // [0:00:01.568] REG=166, 2 //EXP_SKIP_FRM ++ {0x00A7, 0x0000}, // [0:00:01.570] REG=167, 0 ++ {0x00A8, 0x0000}, // [0:00:01.572] REG=168, 0 //EXP_LPF ++ {0x00A9, 0x0002}, // [0:00:01.573] REG=169, 2 //GAIN_SKIP_FRM_H ++ {0x00AA, 0x0000}, // [0:00:01.574] REG=170, 0 ++ {0x00AB, 0x0002}, // [0:00:01.575] REG=171, 2 //GAIN_LPF_H ++ {0x00AF, 0x0003}, // [0:00:01.576] REG=175, 3 //AUTO_BLOCK_CONTROL ++ {0x00B0, 0xABE0}, // [0:00:01.577]REG=176, 44000 //PIXEL_COUNT ++ {0x00B1, 0x0002}, // [0:00:01.578] REG=177, 2 //LVDS_MASTER_CONTROL ++ {0x00B2, 0x0010}, // [0:00:01.579] REG=178, 16 //SHFT_CLK_CONTROL ++ {0x00B3, 0x0010}, // [0:00:01.580] REG=179, 16 //LVDS_DATA_CONTROL ++ {0x00B4, 0x0000}, // [0:00:01.581] REG=180, 0 //STREAM_LATENCY_SELECT ++ {0x00B5, 0x0000}, // [0:00:01.582] REG=181, 0 //LVDS_INTERNAL_SYNC ++ {0x00B6, 0x0000}, // [0:00:01.583] REG=182, 0 //USE_10BIT_PIXELS ++ {0x00B7, 0x0000}, // [0:00:01.584] REG=183, 0 //STEREO_ERROR_CONTROL ++ {0x00BD, 0x01E0}, // [0:00:01.585] REG=189, 480 //MAX_EXPOSURE ++ {0x00BE, 0x0014}, // [0:00:01.586] REG=190, 20 ++ {0x00BF, 0x0016}, // [0:00:01.588] REG=191, 22 //INTERLACE_VBLANK ++ {0x00C0, 0x000A}, // [0:00:01.589] REG=192, 10 //IMAGE_CAPTURE_NUM ++ {0x00C2, 0x0840}, // [0:00:01.590] REG=194, 0x840 ++ {0x00C3, 0x0000}, // [0:00:01.591] REG=195, 0 //NTSC_FV_CONTROL ++ {0x00C4, 0x4416}, // [0:00:01.592]REG=196, 17430 //NTSC_HBLANK ++ {0x00C5, 0x4421}, // [0:00:01.593]REG=197, 17441 //NTSC_VBLANK ++ {0x00F1, 0x0000}, // [0:00:01.594] REG=241, 0 //BYTEWISE_ADDR_REG ++ {0x00FE, 0xBEEF}, // [0:00:01.595]REG=254, 48879 //REGISTER_LOCK_REG ++#else ++#if 1 ++ {0x0031, 0x001F}, //V1_CONTROL ++ {0x0032, 0x001A}, //V2_CONTROL ++ {0x0033, 0x0012}, //V3_CONTROL ++ {0x00AF, 0x0000}, //AUTO_BLOCK_CONTROL ++ {0x002B, 0x0003}, ++ {0x0010, 0x0040}, ++ ++ {0x000F, 0x0051}, //PIXEL_OPERATION_MODE ++ {0x0010, 0x0040}, ++ {0x0015, 0x7F32}, ++ {0x001C, 0x0003}, //DATA_COMPRESSION ++// {0x0020, 0x01D5}, ++ /*change*/ ++ {0x0020, 0x03D5}, ++ {0x002B, 0x0000}, ++ {0x0048, 0x0000}, //TARGET_CALIB_VALUE ++ {0x0070, 0x0004}, //ROW_NOISE_CONTROL ++ {0x0073, 0x02F7}, //DARK_COL_START ++ {0x00AB, 0x0000}, //GAIN_LPF_H ++ {0x00BF, 0x0014}, //INTERLACE_VBLANK ++ {0x00C2, 0x0940}, ++ ++ {0x000F, 0x0011}, //PIXEL_OPERATION_MODE ++ {0x0015, 0x7F32}, ++ {0x001C, 0x0002}, //DATA_COMPRESSION ++// {0x0020, 0x01D1}, ++ /*change*/ ++ {0x0020, 0x03D5}, ++ {0x00C2, 0x0840}, ++ ++ {0x0001, 0x0001}, // [0:00:01.449] REG=1, 1 //COL_WINDOW_START_REG ++ {0x0002, 0x0004}, // [0:00:01.452] REG=2, 4 //ROW_WINDOW_START_REG ++ {0x0003, 0x01E0}, // [0:00:01.454] REG=3, 480 //ROW_WINDOW_SIZE_REG ++// {0x0004, 0x02F0}, // [0:00:01.456] REG=4, 752 //COL_WINDOW_SIZE_REG ++ {0x0004, 0x0280}, // [0:00:01.456] REG=4, 640 //COL_WINDOW_SIZE_REG ++ {0x0005, 0x005E}, // [0:00:01.457] REG=5, 94 //HORZ_BLANK_REG ++ {0x0006, 0x002D}, // [0:00:01.458] REG=6, 45 //VERT_BLANK_REG ++// {0x0007, 0x0388}, // [0:00:01.459] REG=7, 904 //CONTROL_MODE_REG ++ {0x0007, 0x0398}, // [0:00:01.459] REG=7, 904 //CONTROL_MODE_REG ++ {0x0008, 0x01BB}, // [0:00:01.460] REG=8, 443 //SHUTTER_WIDTH_REG_1 ++ {0x0009, 0x01D9}, // [0:00:01.461] REG=9, 473 //SHUTTER_WIDTH_REG_2 ++ {0x000A, 0x0164}, // [0:00:01.462] REG=10, 356 //SHUTTER_WIDTH_CONTROL ++ {0x000B, 0x01E0}, // [0:00:01.463] REG=11, 480 //INTEG_TIME_REG ++ {0x000C, 0x0000}, // [0:00:01.464] REG=12, 0 //RESET_REG ++ /*pclk reduce*/ ++ {0x000D, 0x0304}, // [0:00:01.465] REG=13, 768 //READ_MODE_REG ++ {0x000E, 0x0000}, // [0:00:01.466] REG=14, 0 //MONITOR_MODE_CONTROL ++ /*monochrome color choice*/ ++ {0x000F, 0x0015}, // [0:00:01.467] REG=15, 17 //PIXEL_OPERATION_MODE ++ {0x0010, 0x0040}, // [0:00:01.468] REG=16, 0x40 ++ {0x0011, 0x8042}, // [0:00:01.469]REG=17, 32834 ++ {0x0012, 0x0022}, // [0:00:01.470] REG=18, 34 ++ {0x0013, 0x2D32}, // [0:00:01.471]REG=19, 0x2D32 ++ {0x0014, 0x0E02}, // [0:00:01.472] REG=20, 3586 ++ {0x0015, 0x7F32}, // [0:00:01.473]REG=21, 0x7F32 ++ {0x0016, 0x2802}, // [0:00:01.474]REG=22, 10242 ++ {0x0017, 0x3E38}, // [0:00:01.475]REG=23, 15928 ++ {0x0018, 0x3E38}, // [0:00:01.476]REG=24, 15928 ++ {0x0019, 0x2802}, // [0:00:01.477]REG=25, 10242 ++ {0x001A, 0x0428}, // [0:00:01.478] REG=26, 1064 ++ {0x001B, 0x0000}, // [0:00:01.479] REG=27, 0 //LED_OUT_CONTROL ++ {0x001C, 0x0002}, // [0:00:01.482] REG=28, 2 //DATA_COMPRESSION ++ {0x001D, 0x0000}, // [0:00:01.483] REG=29, 0 ++ {0x001E, 0x0000}, // [0:00:01.484] REG=30, 0 ++ {0x001F, 0x0000}, // [0:00:01.485] REG=31, 0 ++// {0x0020, 0x01D1}, // [0:00:01.486] REG=32, 0x1D1 ++// {0x0020, 0x0204}, // [0:00:01.486] REG=32, 0x1D1 ++ /*change*/ ++ {0x0020, 0x03D5}, ++ {0x0021, 0x0020}, // [0:00:01.487] REG=33, 32 ++ {0x0022, 0x0020}, // [0:00:01.488] REG=34, 32 ++ {0x0023, 0x0010}, // [0:00:01.489] REG=35, 16 ++ {0x0024, 0x0010}, // [0:00:01.490] REG=36, 16 ++ {0x0025, 0x0020}, // [0:00:01.491] REG=37, 32 ++ {0x0026, 0x0010}, // [0:00:01.492] REG=38, 16 ++ {0x0027, 0x0010}, // [0:00:01.493] REG=39, 16 ++ {0x0028, 0x0010}, // [0:00:01.494] REG=40, 16 ++ {0x0029, 0x0010}, // [0:00:01.495] REG=41, 16 ++ {0x002A, 0x0020}, // [0:00:01.496] REG=42, 32 ++ {0x002B, 0x0004}, // [0:00:01.497] REG=43, 4 ++ {0x002C, 0x0004}, // [0:00:01.498] REG=44, 4 ++ {0x002D, 0x0004}, // [0:00:01.499] REG=45, 4 ++ {0x002E, 0x0007}, // [0:00:01.500] REG=46, 7 ++ {0x002F, 0x0004}, // [0:00:01.501] REG=47, 4 ++ {0x0030, 0x0003}, // [0:00:01.502] REG=48, 3 ++ {0x0031, 0x001D}, // [0:00:01.503] REG=49, 29 //V1_CONTROL ++ {0x0032, 0x0018}, // [0:00:01.504] REG=50, 24 //V2_CONTROL ++ {0x0033, 0x0015}, // [0:00:01.505] REG=51, 21 //V3_CONTROL ++ {0x0034, 0x0004}, // [0:00:01.506] REG=52, 4 //V4_CONTROL ++ {0x0035, 0x0010}, // [0:00:01.507] REG=53, 16 //GLOBAL_GAIN_REG ++ {0x0036, 0x0040}, // [0:00:01.508] REG=54, 64 //MAXIMUM_GAIN_REG ++ {0x0037, 0x0000}, // [0:00:01.509] REG=55, 0 ++ {0x0038, 0x0000}, // [0:00:01.510] REG=56, 0 ++ {0x0046, 0x231D}, // [0:00:01.511]REG=70, 8989 //DARK_AVG_THRESHOLDS ++ {0x0047, 0x8080}, // [0:00:01.512]REG=71, 32896 //CALIB_CONTROL_REG ++ {0x004C, 0x0002}, // [0:00:01.513] REG=76, 2 //STEP_SIZE_AVG_MODE ++ {0x0060, 0x0000}, // [0:00:01.514] REG=96, 0 ++ {0x0061, 0x0000}, // [0:00:01.515] REG=97, 0 ++ {0x0062, 0x0000}, // [0:00:01.516] REG=98, 0 ++ {0x0063, 0x0000}, // [0:00:01.517] REG=99, 0 ++ {0x0064, 0x0000}, // [0:00:01.518] REG=100, 0 ++ {0x0065, 0x0000}, // [0:00:01.519] REG=101, 0 ++ {0x0066, 0x0000}, // [0:00:01.520] REG=102, 0 ++ {0x0067, 0x0000}, // [0:00:01.521] REG=103, 0 ++ {0x006C, 0x0000}, // [0:00:01.522] REG=108, 0 ++ {0x0070, 0x0034}, // [0:00:01.523] REG=112, 52 //ROW_NOISE_CONTROL ++ {0x0071, 0x0000}, // [0:00:01.524] REG=113, 0 ++ {0x0072, 0x002A}, // [0:00:01.525] REG=114, 42 //NOISE_CONSTANT ++ {0x0073, 0x02F7}, // [0:00:01.526] REG=115, 759 //DARK_COL_START ++// {0x0074, 0x0000}, // [0:00:01.527] REG=116, 0 //PIXCLK_CONTROL ++ {0x0074, 0x0012}, // [0:00:01.527] REG=116, 0 //PIXCLK_CONTROL ++ {0x007F, 0x0000}, // [0:00:01.528] REG=127, 0 //TEST_DATA ++ {0x0080, 0x00F4}, // [0:00:01.529] REG=128, 244 //TILE_X0_Y0 ++ {0x0081, 0x00F4}, // [0:00:01.530] REG=129, 244 //TILE_X1_Y0 ++ {0x0082, 0x00F4}, // [0:00:01.531] REG=130, 244 //TILE_X2_Y0 ++ {0x0083, 0x00F4}, // [0:00:01.532] REG=131, 244 //TILE_X3_Y0 ++ {0x0084, 0x00F4}, // [0:00:01.533] REG=132, 244 //TILE_X4_Y0 ++ {0x0085, 0x00F4}, // [0:00:01.534] REG=133, 244 //TILE_X0_Y1 ++ {0x0086, 0x00F4}, // [0:00:01.535] REG=134, 244 //TILE_X1_Y1 ++ {0x0087, 0x00F4}, // [0:00:01.536] REG=135, 244 //TILE_X2_Y1 ++ {0x0088, 0x00F4}, // [0:00:01.537] REG=136, 244 //TILE_X3_Y1 ++ {0x0089, 0x00F4}, // [0:00:01.538] REG=137, 244 //TILE_X4_Y1 ++ {0x008A, 0x00F4}, // [0:00:01.539] REG=138, 244 //TILE_X0_Y2 ++ {0x008B, 0x00F4}, // [0:00:01.540] REG=139, 244 //TILE_X1_Y2 ++ {0x008C, 0x00F4}, // [0:00:01.541] REG=140, 244 //TILE_X2_Y2 ++ {0x008D, 0x00F4}, // [0:00:01.542] REG=141, 244 //TILE_X3_Y2 ++ {0x008E, 0x00F4}, // [0:00:01.543] REG=142, 244 //TILE_X4_Y2 ++ {0x008F, 0x00F4}, // [0:00:01.544] REG=143, 244 //TILE_X0_Y3 ++ {0x0090, 0x00F4}, // [0:00:01.545] REG=144, 244 //TILE_X1_Y3 ++ {0x0091, 0x00F4}, // [0:00:01.546] REG=145, 244 //TILE_X2_Y3 ++ {0x0092, 0x00F4}, // [0:00:01.547] REG=146, 244 //TILE_X3_Y3 ++ {0x0093, 0x00F4}, // [0:00:01.548] REG=147, 244 //TILE_X4_Y3 ++ {0x0094, 0x00F4}, // [0:00:01.549] REG=148, 244 //TILE_X0_Y4 ++ {0x0095, 0x00F4}, // [0:00:01.550] REG=149, 244 //TILE_X1_Y4 ++ {0x0096, 0x00F4}, // [0:00:01.551] REG=150, 244 //TILE_X2_Y4 ++ {0x0097, 0x00F4}, // [0:00:01.552] REG=151, 244 //TILE_X3_Y4 ++ {0x0098, 0x00F4}, // [0:00:01.553] REG=152, 244 //TILE_X4_Y4 ++ {0x0099, 0x0000}, // [0:00:01.554] REG=153, 0 //X0_SLASH5 ++ {0x009A, 0x0096}, // [0:00:01.555] REG=154, 150 //X1_SLASH5 ++ {0x009B, 0x012C}, // [0:00:01.556] REG=155, 300 //X2_SLASH5 ++ {0x009C, 0x01C2}, // [0:00:01.557] REG=156, 450 //X3_SLASH5 ++ {0x009D, 0x0258}, // [0:00:01.558] REG=157, 600 //X4_SLASH5 ++ {0x009E, 0x02F0}, // [0:00:01.559] REG=158, 752 //X5_SLASH5 ++ {0x009F, 0x0000}, // [0:00:01.560] REG=159, 0 //Y0_SLASH5 ++ {0x00A0, 0x0060}, // [0:00:01.561] REG=160, 96 //Y1_SLASH5 ++ {0x00A1, 0x00C0}, // [0:00:01.563] REG=161, 192 //Y2_SLASH5 ++ {0x00A2, 0x0120}, // [0:00:01.564] REG=162, 288 //Y3_SLASH5 ++ {0x00A3, 0x0180}, // [0:00:01.565] REG=163, 384 //Y4_SLASH5 ++ {0x00A4, 0x01E0}, // [0:00:01.566] REG=164, 480 //Y5_SLASH5 ++ {0x00A5, 0x003A}, // [0:00:01.567] REG=165, 58 //DESIRED_BIN ++ {0x00A6, 0x0002}, // [0:00:01.568] REG=166, 2 //EXP_SKIP_FRM ++ {0x00A7, 0x0000}, // [0:00:01.570] REG=167, 0 ++ {0x00A8, 0x0000}, // [0:00:01.572] REG=168, 0 //EXP_LPF ++ {0x00A9, 0x0002}, // [0:00:01.573] REG=169, 2 //GAIN_SKIP_FRM_H ++ {0x00AA, 0x0000}, // [0:00:01.574] REG=170, 0 ++ {0x00AB, 0x0002}, // [0:00:01.575] REG=171, 2 //GAIN_LPF_H ++// {0x00AF, 0x0003}, // [0:00:01.576] REG=175, 3 //AUTO_BLOCK_CONTROL ++// {0x00AF, 0x0002}, // [0:00:01.576] REG=175, 3 //AUTO_BLOCK_CONTROL ++ /* change */ ++ {0x00AF, 0x0000}, // [0:00:01.576] REG=175, 3 //AUTO_BLOCK_CONTROL ++ {0x00B0, 0xABE0}, // [0:00:01.577]REG=176, 44000 //PIXEL_COUNT ++ {0x00B1, 0x0002}, // [0:00:01.578] REG=177, 2 //LVDS_MASTER_CONTROL ++ {0x00B2, 0x0010}, // [0:00:01.579] REG=178, 16 //SHFT_CLK_CONTROL ++ {0x00B3, 0x0010}, // [0:00:01.580] REG=179, 16 //LVDS_DATA_CONTROL ++ {0x00B4, 0x0000}, // [0:00:01.581] REG=180, 0 //STREAM_LATENCY_SELECT ++ {0x00B5, 0x0000}, // [0:00:01.582] REG=181, 0 //LVDS_INTERNAL_SYNC ++ {0x00B6, 0x0000}, // [0:00:01.583] REG=182, 0 //USE_10BIT_PIXELS ++ {0x00B7, 0x0000}, // [0:00:01.584] REG=183, 0 //STEREO_ERROR_CONTROL ++ {0x00BD, 0x01E0}, // [0:00:01.585] REG=189, 480 //MAX_EXPOSURE ++ {0x00BE, 0x0014}, // [0:00:01.586] REG=190, 20 ++ {0x00BF, 0x0016}, // [0:00:01.588] REG=191, 22 //INTERLACE_VBLANK ++ {0x00C0, 0x000A}, // [0:00:01.589] REG=192, 10 //IMAGE_CAPTURE_NUM ++ {0x00C2, 0x0840}, // [0:00:01.590] REG=194, 0x840 ++ {0x00C3, 0x0000}, // [0:00:01.591] REG=195, 0 //NTSC_FV_CONTROL ++ {0x00C4, 0x4416}, // [0:00:01.592]REG=196, 17430 //NTSC_HBLANK ++ {0x00C5, 0x4421}, // [0:00:01.593]REG=197, 17441 //NTSC_VBLANK ++ {0x00F1, 0x0000}, // [0:00:01.594] REG=241, 0 //BYTEWISE_ADDR_REG ++ {0x00FE, 0xBEEF}, // [0:00:01.595]REG=254, 48879 //REGISTER_LOCK_REG ++#else ++ {0x00, 0x1313}, //CHIP_VERSION_REG ++ {0x01, 0x0001}, //COL_WINDOW_START_REG ++ {0x02, 0x0004}, //ROW_WINDOW_START_REG ++ ++ {0x03, 0x00F0}, //ROW_WINDOW_SIZE_REG ++ {0x04, 0x0140}, //COL_WINDOW_SIZE_REG ++ ++ {0x05, 0x005E}, //HORZ_BLANK_REG ++ {0x06, 0x002D}, //VERT_BLANK_REG ++ {0x07, 0x0398}, //CONTROL_MODE_REG ++ {0x08, 0x01BB}, //SHUTTER_WIDTH_REG_1 ++ {0x09, 0x01D9}, //SHUTTER_WIDTH_REG_2 ++ {0x0A, 0x0164}, //SHUTTER_WIDTH_CONTROL ++ {0x0B, 0x01E0}, //INTEG_TIME_REG ++ {0x0C, 0x0000}, //RESET_REG ++ {0x0D, 0x0300}, //READ_MODE_REG ++ {0x0E, 0x0000}, //MONITOR_MODE_CONTROL ++ {0x0F, 0x0011}, //PIXEL_OPERATION_MODE ++ {0x10, 0x0040}, //RAMP_START_DELAY ++ {0x11, 0x8042}, //OFFSET_CONTROL ++ {0x12, 0x0022}, //AMP_RESET_BAR_CONTROL ++ {0x13, 0x2D32}, //5T_PIXEL_RESET_CONTROL ++ {0x14, 0x0E02}, //6T_PIXEL_RESET_CONTROL ++ {0x15, 0x7F32}, //TX_CONTROL ++ {0x16, 0x2802}, //5T_PIXEL_SHS_CONTROL ++ {0x17, 0x3E38}, //6T_PIXEL_SHS_CONTROL ++ {0x18, 0x3E38}, //5T_PIXEL_SHR_CONTROL ++ {0x19, 0x2802}, //6T_PIXEL_SHR_CONTROL ++ {0x1A, 0x0428}, //COMPARATOR_RESET_CONTROL ++ {0x1B, 0x0000}, //LED_OUT_CONTROL ++ {0x1C, 0x0003}, //DATA_COMPRESSION ++ {0x1D, 0x0000}, //ANALOG_TEST_CONTROL ++ {0x1E, 0x0000}, //SRAM_TEST_DATA_ODD ++ {0x1F, 0x0000}, //SRAM_TEST_DATA_EVEN ++ {0x20, 0x03D5}, //BOOST_ROW_EN ++ {0x21, 0x0020}, //I_VLN_CONTROL ++ {0x22, 0x0020}, //I_VLN_AMP_CONTROL ++ {0x23, 0x0010}, //I_VLN_CMP_CONTROL ++ {0x24, 0x0010}, //I_OFFSET_CONTROL ++ {0x25, 0x0020}, //I_FUSE_CONTROL ++ {0x26, 0x0010}, //I_VLN_VREF_ADC_CONTROL ++ {0x27, 0x0010}, //I_VLN_STEP_CONTROL ++ {0x28, 0x0010}, //I_VLN_BUF_CONTROL ++ {0x29, 0x0010}, //I_MASTER_CONTROL ++ {0x2A, 0x0020}, //I_VLN_AMP_60MHZ_CONTROL ++ {0x2B, 0x0003}, //VREF_AMP_CONTROL ++ {0x2C, 0x0004}, //VREF_ADC_CONTROL ++ {0x2D, 0x0004}, //VBOOST_CONTROL ++ {0x2E, 0x0007}, //V_HI_CONTROL ++ {0x2F, 0x0004}, //V_LO_CONTROL ++ {0x30, 0x0003}, //V_RST_LIM_CONTROL ++ {0x31, 0x001F}, //V1_CONTROL ++ {0x32, 0x001A}, //V2_CONTROL ++ {0x33, 0x0012}, //V3_CONTROL ++ {0x34, 0x0004}, //V4_CONTROL ++ {0x35, 0x0010}, //GLOBAL_GAIN_REG ++ {0x36, 0x0040}, //MAXIMUM_GAIN_REG ++ {0x37, 0x0000}, //VOLTAGE_CONTROL ++ {0x38, 0x0000}, //IDAC_VOLTAGE_MONITOR ++ {0x42, 0x0022}, //TARGET_DARK_AVG ++ {0x46, 0x231D}, //DARK_AVG_THRESHOLDS ++ {0x47, 0x8080}, //CALIB_CONTROL_REG ++ {0x48, 0x005C}, //TARGET_CALIB_VAL ++ {0x4C, 0x0002}, //STEP_SIZE_AVG_MODE ++ {0x60, 0x0000}, //READ_FUSE_ADDR ++ {0x61, 0x0000}, //DEFECT_ADDRESS_1 ++ {0x62, 0x0000}, //DEFECT_ADDRESS_2 ++ {0x63, 0x0000}, //DEFECT_ADDRESS_3 ++ {0x64, 0x0000}, //DEFECT_ADDRESS_4 ++ {0x65, 0x0000}, //DEFECT_ADDRESS_5 ++ {0x66, 0x0000}, //DEFECT_ADDRESS_6 ++ {0x67, 0x0000}, //FUSE_CONTROL_REG ++ {0x68, 0x51FF}, //FUSE_ID_1 ++ {0x69, 0xA5AE}, //FUSE_ID_2 ++ {0x6A, 0x1098}, //FUSE_ID_3 ++ {0x6B, 0x6028}, //FUSE_ID_4 ++ {0x6C, 0x0000}, //FUSE_RELOAD ++ {0x70, 0x0034}, //ROW_NOISE_CONTROL ++ {0x71, 0x0000}, //RESERVED_71 ++ {0x72, 0x002A}, //NOISE_CONSTANT ++ {0x73, 0x02F7}, //DARK_COL_START ++ {0x74, 0x0000}, //PIXCLK_CONTROL ++ {0x7F, 0x0000}, //TEST_DATA ++ {0x80, 0x00F4}, //TILE_X0_Y0 ++ {0x81, 0x00F4}, //TILE_X1_Y0 ++ {0x82, 0x00F4}, //TILE_X2_Y0 ++ {0x83, 0x00F4}, //TILE_X3_Y0 ++ {0x84, 0x00F4}, //TILE_X4_Y0 ++ {0x85, 0x00F4}, //TILE_X0_Y1 ++ {0x86, 0x00F4}, //TILE_X1_Y1 ++ {0x87, 0x00F4}, //TILE_X2_Y1 ++ {0x88, 0x00F4}, //TILE_X3_Y1 ++ {0x89, 0x00F4}, //TILE_X4_Y1 ++ {0x8A, 0x00F4}, //TILE_X0_Y2 ++ {0x8B, 0x00F4}, //TILE_X1_Y2 ++ {0x8C, 0x00F4}, //TILE_X2_Y2 ++ {0x8D, 0x00F4}, //TILE_X3_Y2 ++ {0x8E, 0x00F4}, //TILE_X4_Y2 ++ {0x8F, 0x00F4}, //TILE_X0_Y3 ++ {0x90, 0x00F4}, //TILE_X1_Y3 ++ {0x91, 0x00F4}, //TILE_X2_Y3 ++ {0x92, 0x00F4}, //TILE_X3_Y3 ++ {0x93, 0x00F4}, //TILE_X4_Y3 ++ {0x94, 0x00F4}, //TILE_X0_Y4 ++ {0x95, 0x00F4}, //TILE_X1_Y4 ++ {0x96, 0x00F4}, //TILE_X2_Y4 ++ {0x97, 0x00F4}, //TILE_X3_Y4 ++ {0x98, 0x00F4}, //TILE_X4_Y4 ++ {0x99, 0x0000}, //X0_SLASH5 ++ {0x9A, 0x0096}, //X1_SLASH5 ++ {0x9B, 0x012C}, //X2_SLASH5 ++ {0x9C, 0x01C2}, //X3_SLASH5 ++ {0x9D, 0x0258}, //X4_SLASH5 ++ {0x9E, 0x02F0}, //X5_SLASH5 ++ {0x9F, 0x0000}, //Y0_SLASH5 ++ {0xA0, 0x0060}, //Y1_SLASH5 ++ {0xA1, 0x00C0}, //Y2_SLASH5 ++ {0xA2, 0x0120}, //Y3_SLASH5 ++ {0xA3, 0x0180}, //Y4_SLASH5 ++ {0xA4, 0x01E0}, //Y5_SLASH5 ++ {0xA5, 0x003A}, //DESIRED_BIN ++ {0xA6, 0x0002}, //EXP_SKIP_FRM ++ {0xA7, 0x0000}, //RESERVED_A7 ++ {0xA8, 0x0000}, //EXP_LPF ++ {0xA9, 0x0002}, //GAIN_SKIP_FRM_H ++ {0xAA, 0x0000}, //RESERVED_AA ++ {0xAB, 0x0002}, //GAIN_LPF_H ++ {0xAF, 0x0000}, //AUTO_BLOCK_CONTROL ++ {0xB0, 0xABE0}, //PIXEL_COUNT ++ {0xB1, 0x0002}, //LVDS_MASTER_CONTROL ++ {0xB2, 0x0010}, //SHFT_CLK_CONTROL ++ {0xB3, 0x0010}, //LVDS_DATA_CONTROL ++ {0xB4, 0x0000}, //STREAM_LATENCY_SELECT ++ {0xB5, 0x0000}, //LVDS_INTERNAL_SYNC ++ {0xB6, 0x0000}, //USE_10BIT_PIXELS ++ {0xB7, 0x0000}, //STEREO_ERROR_CONTROL ++ {0xB8, 0x0000}, //STEREO_ERROR_FLAG ++ {0xB9, 0x0000}, //LVDS_DATA_OUTPUT ++ {0xBA, 0x0010}, //AGC_GAIN ++ {0xBB, 0x01E0}, //AEC_EXPOSURE ++ {0xBC, 0x002A}, //CURRENT_BIN ++ {0xBD, 0x01E0}, //MAX_EXPOSURE ++ {0xBE, 0x0014}, //BIN_DIFF_THRESHOLD ++ {0xBF, 0x0016}, //INTERLACE_VBLANK ++ {0xC0, 0x000A}, //IMAGE_CAPTURE_NUM ++ {0xC1, 0x024C}, //THERMAL_INFO ++ {0xC2, 0x0840}, //ANALOG_CONTROLS ++ {0xC3, 0x0000}, //NTSC_FV_CONTROL ++ {0xC4, 0x4416}, //NTSC_HBLANK ++ {0xC5, 0x4421}, //NTSC_VBLANK ++ {0xF0, 0x2100}, //PAGE_REGISTER ++ {0xF1, 0x0000}, //BYTEWISE_ADDR_REG ++ {0xFE, 0x0000}, //REGISTER_LOCK_REG ++ {0xFF, 0x0000}, //CHIP_VERSION_REG2 ++#endif ++ ++#endif ++ ENDMARKER, ++}; ++ ++static const struct regval_list mt9v022_vga_itu656[] = { ++ ENDMARKER, ++}; ++static const struct regval_list mt9v022_qvga_regs[] = { ++ ++ ENDMARKER, ++}; ++ ++static const struct regval_list mt9v022_vga_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list mt9v022_720p_regs[] = { ++ ++ ENDMARKER, ++}; ++ ++static const struct regval_list mt9v022_1080p_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list mt9v022_wb_auto_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list mt9v022_wb_incandescence_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list mt9v022_wb_daylight_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list mt9v022_wb_fluorescent_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list mt9v022_wb_cloud_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct mode_list mt9v022_balance[] = { ++ {0, mt9v022_wb_auto_regs}, {1, mt9v022_wb_incandescence_regs}, ++ {2, mt9v022_wb_daylight_regs}, {3, mt9v022_wb_fluorescent_regs}, ++ {4, mt9v022_wb_cloud_regs}, ++}; ++ ++ ++static const struct regval_list mt9v022_effect_normal_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list mt9v022_effect_grayscale_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list mt9v022_effect_sepia_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list mt9v022_effect_colorinv_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list mt9v022_effect_sepiabluel_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct mode_list mt9v022_effect[] = { ++ {0, mt9v022_effect_normal_regs}, {1, mt9v022_effect_grayscale_regs}, ++ {2, mt9v022_effect_sepia_regs}, {3, mt9v022_effect_colorinv_regs}, ++ {4, mt9v022_effect_sepiabluel_regs}, ++}; ++ ++#define MT9V022_SIZE(n, w, h, r) \ ++ {.name = n, .width = w , .height = h, .regs = r } ++ ++static struct mt9v022_win_size mt9v022_supported_win_sizes[] = { ++ MT9V022_SIZE("720P", W_720P, H_720P, mt9v022_720p_regs), ++}; ++ ++#define N_WIN_SIZES (ARRAY_SIZE(mt9v022_supported_win_sizes)) ++ ++ ++static u32 mt9v022_codes[] = { ++ MEDIA_BUS_FMT_Y8_1X8, ++// V4L2_MBUS_FMT_Y8_1X8 ++}; ++ ++/* ++ * Supported balance menus ++ */ ++static const struct v4l2_querymenu mt9v022_balance_menus[] = { ++ { ++ .id = V4L2_CID_PRIVATE_BALANCE, ++ .index = 0, ++ .name = "auto", ++ }, { ++ .id = V4L2_CID_PRIVATE_BALANCE, ++ .index = 1, ++ .name = "incandescent", ++ }, { ++ .id = V4L2_CID_PRIVATE_BALANCE, ++ .index = 2, ++ .name = "fluorescent", ++ }, { ++ .id = V4L2_CID_PRIVATE_BALANCE, ++ .index = 3, ++ .name = "daylight", ++ }, { ++ .id = V4L2_CID_PRIVATE_BALANCE, ++ .index = 4, ++ .name = "cloudy-daylight", ++ }, ++ ++}; ++ ++/* ++ * Supported effect menus ++ */ ++static const struct v4l2_querymenu mt9v022_effect_menus[] = { ++ { ++ .id = V4L2_CID_PRIVATE_EFFECT, ++ .index = 0, ++ .name = "none", ++ }, { ++ .id = V4L2_CID_PRIVATE_EFFECT, ++ .index = 1, ++ .name = "mono", ++ }, { ++ .id = V4L2_CID_PRIVATE_EFFECT, ++ .index = 2, ++ .name = "sepia", ++ }, { ++ .id = V4L2_CID_PRIVATE_EFFECT, ++ .index = 3, ++ .name = "negative", ++ }, { ++ .id = V4L2_CID_PRIVATE_EFFECT, ++ .index = 4, ++ .name = "aqua", ++ }, ++}; ++ ++ ++/* ++ * General functions ++ */ ++static struct mt9v022_priv *to_mt9v022(const struct i2c_client *client) ++{ ++ return container_of(i2c_get_clientdata(client), struct mt9v022_priv, ++ subdev); ++} ++ ++static int mt9v022_write_array(struct i2c_client *client, ++ const struct regval_list *vals) ++{ ++ int ret; ++ ++ while ((vals->reg_num != 0xff) || (vals->value != 0xff)) { ++ ++ ret = mt9v022_write_reg(client, vals->reg_num, vals->value); ++ dev_vdbg(&client->dev, "array: 0x%02x, 0x%02x", ++ vals->reg_num, vals->value); ++ ++ if (ret < 0) ++ return ret; ++ vals++; ++ } ++ return 0; ++} ++ ++static int mt9v022_mask_set(struct i2c_client *client, ++ u16 reg, u16 mask, u16 set) ++{ ++ s32 val = mt9v022_read_reg(client, reg); ++ if (val < 0) ++ return val; ++ ++ val &= ~mask; ++ val |= set & mask; ++ ++ dev_vdbg(&client->dev, "masks: 0x%02x, 0x%02x", reg, val); ++ ++ return mt9v022_write_reg(client, reg, val); ++} ++ ++static int mt9v022_reset(struct i2c_client *client) ++{ ++ return 0; ++} ++ ++/* ++ * soc_camera_ops functions ++ */ ++static int mt9v022_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ return 0; ++} ++ ++static int mt9v022_g_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = ++ &container_of(ctrl->handler, struct mt9v022_priv, hdl)->subdev; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct mt9v022_priv *priv = to_mt9v022(client); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_VFLIP: ++ ctrl->val = priv->flag_vflip; ++ break; ++ case V4L2_CID_HFLIP: ++ ctrl->val = priv->flag_hflip; ++ break; ++ case V4L2_CID_PRIVATE_BALANCE: ++ ctrl->val = priv->balance_value; ++ break; ++ case V4L2_CID_PRIVATE_EFFECT: ++ ctrl->val = priv->effect_value; ++ break; ++ default: ++ break; ++ } ++ return 0; ++} ++ ++static int mt9v022_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = ++ &container_of(ctrl->handler, struct mt9v022_priv, hdl)->subdev; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct mt9v022_priv *priv = to_mt9v022(client); ++ int ret = 0; ++ int i = 0; ++ u16 value; ++ ++ int balance_count = ARRAY_SIZE(mt9v022_balance); ++ int effect_count = ARRAY_SIZE(mt9v022_effect); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_PRIVATE_BALANCE: ++ if(ctrl->val > balance_count) ++ return -EINVAL; ++ ++ for(i = 0; i < balance_count; i++) { ++ if(ctrl->val == mt9v022_balance[i].index) { ++ ret = mt9v022_write_array(client, ++ mt9v022_balance[ctrl->val].mode_regs); ++ priv->balance_value = ctrl->val; ++ break; ++ } ++ } ++ break; ++ ++ case V4L2_CID_PRIVATE_EFFECT: ++ if(ctrl->val > effect_count) ++ return -EINVAL; ++ ++ for(i = 0; i < effect_count; i++) { ++ if(ctrl->val == mt9v022_effect[i].index) { ++ ret = mt9v022_write_array(client, ++ mt9v022_effect[ctrl->val].mode_regs); ++ priv->effect_value = ctrl->val; ++ break; ++ } ++ } ++ break; ++ ++ case V4L2_CID_VFLIP: ++ value = ctrl->val ? MT9V022_FLIP_VAL : 0x00; ++ priv->flag_vflip = ctrl->val ? 1 : 0; ++ ret = mt9v022_mask_set(client, REG_TC_VFLIP, MT9V022_FLIP_MASK, value); ++ break; ++ ++ case V4L2_CID_HFLIP: ++ value = ctrl->val ? MT9V022_FLIP_VAL : 0x00; ++ priv->flag_hflip = ctrl->val ? 1 : 0; ++ ret = mt9v022_mask_set(client, REG_TC_MIRROR, MT9V022_FLIP_MASK, value); ++ break; ++ ++ default: ++ dev_err(&client->dev, "no V4L2 CID: 0x%x ", ctrl->id); ++ return -EINVAL; ++ } ++ ++ return ret; ++} ++ ++static int mt9v022_querymenu(struct v4l2_subdev *sd, ++ struct v4l2_querymenu *qm) ++{ ++ switch (qm->id) { ++ case V4L2_CID_PRIVATE_BALANCE: ++ memcpy(qm->name, mt9v022_balance_menus[qm->index].name, ++ sizeof(qm->name)); ++ break; ++ ++ case V4L2_CID_PRIVATE_EFFECT: ++ memcpy(qm->name, mt9v022_effect_menus[qm->index].name, ++ sizeof(qm->name)); ++ break; ++ } ++ ++ return 0; ++} ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int mt9v022_g_register(struct v4l2_subdev *sd, ++ struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ int ret; ++ ++ reg->size = 1; ++ if (reg->reg > 0xff) ++ return -EINVAL; ++ ++ ret = mt9v022_read_reg(client, reg->reg); ++ if (ret < 0) ++ return ret; ++ ++ reg->val = ret; ++ ++ return 0; ++} ++ ++static int mt9v022_s_register(struct v4l2_subdev *sd, ++ const struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ if (reg->reg > 0xff || ++ reg->val > 0xff) ++ return -EINVAL; ++ ++ return mt9v022_write_reg(client, reg->reg, reg->val); ++} ++#endif ++ ++/* Select the nearest higher resolution for capture */ ++static const struct mt9v022_win_size *mt9v022_select_win(u32 *width, u32 *height) ++{ ++ int i, default_size = ARRAY_SIZE(mt9v022_supported_win_sizes) - 1; ++ ++ for (i = 0; i < ARRAY_SIZE(mt9v022_supported_win_sizes); i++) { ++ if ((*width >= mt9v022_supported_win_sizes[i].width) && ++ (*height >= mt9v022_supported_win_sizes[i].height)) { ++ *width = mt9v022_supported_win_sizes[i].width; ++ *height = mt9v022_supported_win_sizes[i].height; ++ return &mt9v022_supported_win_sizes[i]; ++ } ++ } ++ ++ *width = mt9v022_supported_win_sizes[default_size].width; ++ *height = mt9v022_supported_win_sizes[default_size].height; ++ return &mt9v022_supported_win_sizes[default_size]; ++} ++ ++static int mt9v022_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct mt9v022_priv *priv = to_mt9v022(client); ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ mf->width = MT9V022_DEFAULT_WIDTH;//priv->win->width; ++ mf->height = MT9V022_DEFAULT_HEIGHT;//priv->win->height; ++ mf->code = priv->cfmt_code; ++ ++ mf->colorspace = V4L2_COLORSPACE_SRGB; ++ mf->field = V4L2_FIELD_NONE; ++ ++ return 0; ++} ++ ++static int mt9v022_set_params(struct i2c_client *client, u32 *width, u32 *height, u32 code) ++{ ++ struct mt9v022_priv *priv = to_mt9v022(client); ++ int ret; ++ ++ int bala_index = priv->balance_value; ++ int effe_index = priv->effect_value; ++ ++ /* select win */ ++ priv->win = mt9v022_select_win(width, height); ++ ++ /* select format */ ++ priv->cfmt_code = 0; ++ ++ /* reset hardware */ ++ mt9v022_reset(client); ++ ++ /* initialize the sensor with default data */ ++ dev_dbg(&client->dev, "%s: Init default", __func__); ++ ret = mt9v022_write_array(client, mt9v022_init_regs); ++ if (ret < 0) ++ goto err; ++ ++ /* set balance */ ++ ret = mt9v022_write_array(client, mt9v022_balance[bala_index].mode_regs); ++ if (ret < 0) ++ goto err; ++ ++ /* set effect */ ++ ret = mt9v022_write_array(client, mt9v022_effect[effe_index].mode_regs); ++ if (ret < 0) ++ goto err; ++ ++ /* set size win */ ++ ret = mt9v022_write_array(client, priv->win->regs); ++ if (ret < 0) ++ goto err; ++ ++ priv->cfmt_code = code; ++ *width = priv->win->width; ++ *height = priv->win->height; ++ ++ return 0; ++ ++err: ++ dev_err(&client->dev, "%s: Error %d", __func__, ret); ++ mt9v022_reset(client); ++ priv->win = NULL; ++ ++ return ret; ++} ++ ++static int mt9v022_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ /* ++ * select suitable win, but don't store it ++ */ ++ mt9v022_select_win(&mf->width, &mf->height); ++ ++ mf->field = V4L2_FIELD_NONE; ++ mf->colorspace = V4L2_COLORSPACE_SRGB; ++ ++ if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) ++ return mt9v022_set_params(client, &mf->width, ++ &mf->height, mf->code); ++ cfg->try_fmt = *mf; ++ return 0; ++} ++ ++static int mt9v022_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ if (code->pad || code->index >= ARRAY_SIZE(mt9v022_codes)) ++ return -EINVAL; ++ ++ code->code = mt9v022_codes[code->index]; ++ return 0; ++} ++ ++static int mt9v022_enum_frame_size(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_frame_size_enum *fse) ++{ ++ int i, j; ++ int num_valid = -1; ++ __u32 index = fse->index; ++ ++ if(index >= N_WIN_SIZES) ++ return -EINVAL; ++ ++ j = ARRAY_SIZE(mt9v022_codes); ++ while(--j) ++ if(fse->code == mt9v022_codes[j]) ++ break; ++ ++ for (i = 0; i < N_WIN_SIZES; i++) { ++ if (index == ++num_valid) { ++ fse->code = mt9v022_codes[j]; ++ fse->min_width = mt9v022_supported_win_sizes[index].width; ++ fse->max_width = fse->min_width; ++ fse->min_height = mt9v022_supported_win_sizes[index].height; ++ fse->max_height = fse->min_height; ++ return 0; ++ } ++ } ++ ++ return -EINVAL; ++} ++ ++static int mt9v022_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) ++{ ++ a->c.left = 0; ++ a->c.top = 0; ++ a->c.width = MT9V022_DEFAULT_WIDTH; ++ a->c.height = MT9V022_DEFAULT_HEIGHT; ++ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ ++ return 0; ++} ++ ++static int mt9v022_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) ++{ ++ a->bounds.left = 0; ++ a->bounds.top = 0; ++ a->bounds.width = MT9V022_DEFAULT_WIDTH; ++ a->bounds.height = MT9V022_DEFAULT_HEIGHT; ++ a->defrect = a->bounds; ++ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ a->pixelaspect.numerator = 1; ++ a->pixelaspect.denominator = 1; ++ ++ return 0; ++} ++ ++static int mt9v022_video_probe(struct i2c_client *client) ++{ ++ struct mt9v022_priv *priv = to_mt9v022(client); ++ int ret; ++ int data = 0; ++ ++ ret = mt9v022_s_power(&priv->subdev, 1); ++ if (ret < 0) ++ return ret; ++ /* Read out the chip version register */ ++ data = mt9v022_read_reg(client, 0x0000); ++ ++ /* must be 0x1311, 0x1313 or 0x1324 */ ++ if (data != 0x1311 && data != 0x1313 && data != 0x1324) { ++ ret = -ENODEV; ++ dev_info(&client->dev, "No MT9V022 found, ID register 0x%x\n", ++ data); ++ return ret; } ++ dev_info(&client->dev, "Detected a MT9V022 chip ID %x\n", data); ++ ++ ++ /* Soft reset */ ++ ret = mt9v022_write_reg(client, 0x000c, 1); ++ ++ /*******/ ++ ret = v4l2_ctrl_handler_setup(&priv->hdl); ++ ++ mt9v022_s_power(&priv->subdev, 0); ++ return ret; ++} ++ ++static int mt9v022_s_power(struct v4l2_subdev *sd, int on) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); ++ struct mt9v022_priv *priv = to_mt9v022(client); ++ ++ return soc_camera_set_power(&client->dev, ssdd, priv->clk, on); ++} ++ ++static const struct v4l2_ctrl_ops mt9v022_ctrl_ops = { ++ .s_ctrl = mt9v022_s_ctrl, ++ .g_volatile_ctrl = mt9v022_g_ctrl, ++}; ++ ++static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = mt9v022_g_register, ++ .s_register = mt9v022_s_register, ++#endif ++ .s_power = mt9v022_s_power, ++ .querymenu = mt9v022_querymenu, ++}; ++ ++static int mt9v022_g_mbus_config(struct v4l2_subdev *sd, ++ struct v4l2_mbus_config *cfg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); ++ ++ cfg->flags = V4L2_MBUS_PCLK_SAMPLE_FALLING | V4L2_MBUS_MASTER | ++ V4L2_MBUS_VSYNC_ACTIVE_LOW | V4L2_MBUS_HSYNC_ACTIVE_HIGH | ++ V4L2_MBUS_DATA_ACTIVE_HIGH; ++ cfg->type = V4L2_MBUS_PARALLEL; ++ ++ cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); ++ ++ return 0; ++} ++ ++static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = { ++ .s_stream = mt9v022_s_stream, ++ .cropcap = mt9v022_cropcap, ++ .g_crop = mt9v022_g_crop, ++ .g_mbus_config = mt9v022_g_mbus_config, ++}; ++ ++static const struct v4l2_subdev_pad_ops mt9v022_subdev_pad_ops = { ++ .enum_mbus_code = mt9v022_enum_mbus_code, ++ .enum_frame_size = mt9v022_enum_frame_size, ++ .get_fmt = mt9v022_get_fmt, ++ .set_fmt = mt9v022_set_fmt, ++}; ++ ++static struct v4l2_subdev_ops mt9v022_subdev_ops = { ++ .core = &mt9v022_subdev_core_ops, ++ .video = &mt9v022_subdev_video_ops, ++ .pad = &mt9v022_subdev_pad_ops, ++}; ++ ++/* OF probe functions */ ++static int mt9v022_hw_power(struct device *dev, int on) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct mt9v022_priv *priv = to_mt9v022(client); ++ ++ dev_dbg(&client->dev, "%s: %s the camera\n", ++ __func__, on ? "ENABLE" : "DISABLE"); ++ ++ /* thses gpio should be set according to the active level in dt defines */ ++ if(priv->vcc_en_gpio) { ++ gpiod_direction_output(priv->vcc_en_gpio, on); ++ } ++ ++ if (priv->pwdn_gpio) { ++ gpiod_direction_output(priv->pwdn_gpio, !on); ++ } ++ ++ msleep(10); ++ return 0; ++} ++ ++static int mt9v022_hw_reset(struct device *dev) ++{ ++ return 0; ++} ++ ++ ++static int mt9v022_probe_dt(struct i2c_client *client, ++ struct mt9v022_priv *priv) ++{ ++ ++ struct soc_camera_subdev_desc *ssdd_dt = &priv->ssdd_dt; ++ struct v4l2_subdev_platform_data *sd_pdata = &ssdd_dt->sd_pdata; ++ struct device_node *np = client->dev.of_node; ++ int supplies = 0, index = 0; ++ ++ supplies = of_property_count_strings(np, "supplies-name"); ++ if(supplies <= 0) { ++ goto no_supply; ++ } ++ ++ sd_pdata->num_regulators = supplies; ++ sd_pdata->regulators = devm_kzalloc(&client->dev, supplies * sizeof(struct regulator_bulk_data), GFP_KERNEL); ++ if(!sd_pdata->regulators) { ++ dev_err(&client->dev, "Failed to allocate regulators.!\n"); ++ goto no_supply; ++ } ++ ++ for(index = 0; index < sd_pdata->num_regulators; index ++) { ++ of_property_read_string_index(np, "supplies-name", index, ++ &(sd_pdata->regulators[index].supply)); ++ ++ dev_dbg(&client->dev, "sd_pdata->regulators[%d].supply: %s\n", ++ index, sd_pdata->regulators[index].supply); ++ } ++ ++ soc_camera_power_init(&client->dev, ssdd_dt); ++ ++no_supply: ++ ++ /* Request the power down GPIO asserted */ ++ priv->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "pwdn", ++ GPIOD_OUT_HIGH); ++ if (!priv->pwdn_gpio) ++ dev_dbg(&client->dev, "pwdn gpio is not assigned!\n"); ++ else if (IS_ERR(priv->pwdn_gpio)) ++ return PTR_ERR(priv->pwdn_gpio); ++ ++ /* Request the power down GPIO asserted */ ++ priv->vcc_en_gpio = devm_gpiod_get_optional(&client->dev, "vcc-en", ++ GPIOD_OUT_HIGH); ++ if (!priv->vcc_en_gpio) ++ dev_dbg(&client->dev, "vcc_en gpio is not assigned!\n"); ++ else if (IS_ERR(priv->vcc_en_gpio)) ++ return PTR_ERR(priv->vcc_en_gpio); ++ ++ /* Initialize the soc_camera_subdev_desc */ ++ priv->ssdd_dt.power = mt9v022_hw_power; ++ priv->ssdd_dt.reset = mt9v022_hw_reset; ++ client->dev.platform_data = &priv->ssdd_dt; ++ return 0; ++} ++ ++#include ++/* ++ * i2c_driver functions ++ */ ++static int mt9v022_probe(struct i2c_client *client, ++ const struct i2c_device_id *did) ++{ ++ struct mt9v022_priv *priv; ++ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); ++ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); ++ int ret; ++ ++ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA)) { ++ dev_err(&adapter->dev, ++ "mt9v022: I2C-Adapter doesn't support SMBUS\n"); ++ return -EIO; ++ } ++ ++ priv = devm_kzalloc(&client->dev, sizeof(struct mt9v022_priv), GFP_KERNEL); ++ if (!priv) { ++ dev_err(&adapter->dev, ++ "Failed to allocate memory for private data!\n"); ++ return -ENOMEM; ++ } ++ ++ priv->clk = v4l2_clk_get(&client->dev, "cgu_cim"); ++ if (IS_ERR(priv->clk)) ++ return -EPROBE_DEFER; ++ ++ v4l2_clk_set_rate(priv->clk, 24000000); ++ ++ if (!ssdd && !client->dev.of_node) { ++ dev_err(&client->dev, "Missing platform_data for driver\n"); ++ ret = -EINVAL; ++ goto err_videoprobe; ++ } ++ ++ if (!ssdd) { ++ ret = mt9v022_probe_dt(client, priv); ++ if (ret) ++ goto err_clk; ++ } ++ ++ ++ v4l2_i2c_subdev_init(&priv->subdev, client, &mt9v022_subdev_ops); ++ ++ /* add handler */ ++ v4l2_ctrl_handler_init(&priv->hdl, 2); ++ v4l2_ctrl_new_std(&priv->hdl, &mt9v022_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&priv->hdl, &mt9v022_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ priv->subdev.ctrl_handler = &priv->hdl; ++ if (priv->hdl.error) { ++ ret = priv->hdl.error; ++ goto err_clk; ++ } ++ ++ ret = mt9v022_video_probe(client); ++ if (ret < 0) ++ goto err_videoprobe; ++ ++ ret = v4l2_async_register_subdev(&priv->subdev); ++ if (ret < 0) ++ goto err_videoprobe; ++ ++ dev_info(&adapter->dev, "mt9v022 Probed\n"); ++ ++ return 0; ++ ++err_videoprobe: ++ v4l2_ctrl_handler_free(&priv->hdl); ++err_clk: ++ v4l2_clk_put(priv->clk); ++ return ret; ++} ++ ++static int mt9v022_remove(struct i2c_client *client) ++{ ++ struct mt9v022_priv *priv = to_mt9v022(client); ++ ++ v4l2_async_unregister_subdev(&priv->subdev); ++ v4l2_clk_put(priv->clk); ++ v4l2_device_unregister_subdev(&priv->subdev); ++ v4l2_ctrl_handler_free(&priv->hdl); ++ return 0; ++} ++ ++static const struct i2c_device_id mt9v022_id[] = { ++ { "mt9v022", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, mt9v022_id); ++static const struct of_device_id mt9v022_of_match[] = { ++ {.compatible = "micron,mt9v022", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, mt9v022_of_match); ++static struct i2c_driver mt9v022_i2c_driver = { ++ .driver = { ++ .name = "mt9v022", ++ .of_match_table = of_match_ptr(mt9v022_of_match), ++ }, ++ .probe = mt9v022_probe, ++ .remove = mt9v022_remove, ++ .id_table = mt9v022_id, ++}; ++module_i2c_driver(mt9v022_i2c_driver); ++ ++MODULE_DESCRIPTION("SoC Camera driver for micron mt9v022 sensor"); ++MODULE_AUTHOR("Alberto Panizzo"); ++MODULE_LICENSE("GPL v2"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_i2c_soc_camera_ov5640.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_i2c_soc_camera_ov5640.c.patch new file mode 100644 index 00000000..cf9b6c8b --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_i2c_soc_camera_ov5640.c.patch @@ -0,0 +1,1786 @@ +diff -drupN a/drivers/media/i2c/soc_camera/ov5640.c b/drivers/media/i2c/soc_camera/ov5640.c +--- a/drivers/media/i2c/soc_camera/ov5640.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/i2c/soc_camera/ov5640.c 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,1782 @@ ++/* ++ * ov5640 Camera Driver ++ * ++ * Copyright (C) 2010 Alberto Panizzo ++ * ++ * Based on ov772x, ov9640 drivers and previous non merged implementations. ++ * ++ * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. ++ * Copyright (C) 2006, OmniVision ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#define REG_CHIP_ID_HIGH 0x300a ++#define REG_CHIP_ID_LOW 0x300b ++#define REG_CHIP_REVISION 0x302a ++#define CHIP_ID_HIGH 0x56 ++#define CHIP_ID_LOW 0x40 ++ ++/* Private v4l2 controls */ ++#define V4L2_CID_PRIVATE_BALANCE (V4L2_CID_PRIVATE_BASE + 0) ++#define V4L2_CID_PRIVATE_EFFECT (V4L2_CID_PRIVATE_BASE + 1) ++ ++/* In flip, the OV5640 does not need additional settings because the ISP block ++ * will auto-detect whether the pixel is in the red line or blue line and make ++ * the necessary adjustments. ++ */ ++#define REG_TC_VFLIP 0x3820 ++#define REG_TC_MIRROR 0x3821 ++#define OV5640_HFLIP 0x1 ++#define OV5640_VFLIP 0x2 ++#define OV5640_FLIP_VAL ((unsigned char)0x06) ++#define OV5640_FLIP_MASK ((unsigned char)0x06) ++ ++ /* whether sensor support high resolution (> vga) preview or not */ ++#define SUPPORT_HIGH_RESOLUTION_PRE 1 ++ ++/* ++ * Struct ++ */ ++struct regval_list { ++ u16 reg_num; ++ u16 value; ++}; ++ ++struct mode_list { ++ u16 index; ++ const struct regval_list *mode_regs; ++}; ++ ++/* Supported resolutions */ ++enum ov5640_width { ++ W_QVGA = 320, ++ W_VGA = 640, ++ W_720P = 1280, ++ W_1080P = 1920, ++}; ++ ++enum ov5640_height { ++ H_QVGA = 240, ++ H_VGA = 480, ++ H_720P = 720, ++ H_1080P = 1080, ++}; ++ ++struct ov5640_win_size { ++ char *name; ++ enum ov5640_width width; ++ enum ov5640_height height; ++ const struct regval_list *regs; ++}; ++ ++struct ov5640_priv { ++ struct v4l2_subdev subdev; ++ struct v4l2_ctrl_handler hdl; ++ u32 cfmt_code; ++ struct v4l2_clk *clk; ++ const struct ov5640_win_size *win; ++ ++ int model; ++ u16 balance_value; ++ u16 effect_value; ++ u16 flag_vflip:1; ++ u16 flag_hflip:1; ++ ++ struct soc_camera_subdev_desc ssdd_dt; ++ struct gpio_desc *resetb_gpio; ++ struct gpio_desc *pwdn_gpio; ++ struct gpio_desc *vcc_en_gpio; ++ ++ struct regulator *reg; ++ struct regulator *reg1; ++}; ++ ++int cam_t_j = 0, cam_t_i = 0; ++unsigned long long cam_t0_buf[10]; ++unsigned long long cam_t1_buf[10]; ++static int ov5640_s_power(struct v4l2_subdev *sd, int on); ++static inline int sensor_i2c_master_send(struct i2c_client *client, ++ const char *buf ,int count) ++{ ++ int ret; ++ struct i2c_adapter *adap=client->adapter; ++ struct i2c_msg msg; ++ ++ msg.addr = client->addr; ++ msg.flags = client->flags & I2C_M_TEN; ++ msg.len = count; ++ msg.buf = (char *)buf; ++#if 0 ++ { ++ if (cam_t_i < 10) ++ cam_t0_buf[cam_t_i] = cpu_clock(smp_processor_id()); ++ } ++#endif ++ ++ ret = i2c_transfer(adap, &msg, 1); ++ ++#if 0 ++ { ++ if (cam_t_i < 10) { ++ cam_t1_buf[cam_t_i] = cpu_clock(smp_processor_id()); ++ cam_t_i++; ++ } ++ if (cam_t_i == 10) { ++ cam_t_j = cam_t_i; ++ cam_t_i = 11; ++ while(--cam_t_j) ++ printk("cam%d : i2c1_time 0 = %lld, i2c1_time 1" ++ "= %lld, time = %lld\n", ++ cam_t_j, ++ cam_t0_buf[cam_t_j], ++ cam_t1_buf[cam_t_j], ++ cam_t1_buf[cam_t_j] ++ - cam_t0_buf[cam_t_j]); ++ } ++ } ++#endif ++ ++ ++ /* If everything went ok (i.e. 1 msg transmitted), return #bytes ++ transmitted, else error code. */ ++ return (ret == 1) ? count : ret; ++} ++ ++static inline int sensor_i2c_master_recv(struct i2c_client *client, ++ char *buf ,int count) ++{ ++ struct i2c_adapter *adap=client->adapter; ++ struct i2c_msg msg; ++ int ret; ++ ++ msg.addr = client->addr; ++ msg.flags = client->flags & I2C_M_TEN; ++ msg.flags |= I2C_M_RD; ++ msg.len = count; ++ msg.buf = buf; ++ ret = i2c_transfer(adap, &msg, 1); ++ ++ /* If everything went ok (i.e. 1 msg transmitted), return #bytes ++ transmitted, else error code. */ ++ return (ret == 1) ? count : ret; ++} ++ ++static s32 ov5640_read_reg(struct i2c_client *client, u16 reg) ++{ ++ int ret; ++ u8 retval; ++ u16 r = cpu_to_be16(reg); ++ ++ ret = sensor_i2c_master_send(client,(u8 *)&r,2); ++ ++ if (ret < 0) ++ return ret; ++ if (ret != 2) ++ return -EIO; ++ ++ ret = sensor_i2c_master_recv(client, &retval, 1); ++ if (ret < 0) ++ return ret; ++ if (ret != 1) ++ return -EIO; ++ return retval; ++ ++} ++ ++static s32 ov5640_write_reg(struct i2c_client *client, u16 reg, u8 val) ++{ ++ unsigned char msg[3]; ++ int ret; ++ ++ ++ reg = cpu_to_be16(reg); ++ ++ memcpy(&msg[0], ®, 2); ++ memcpy(&msg[2], &val, 1); ++ ++ ret = sensor_i2c_master_send(client, msg, 3); ++ ++ if (ret < 0) ++ { ++ printk("RET<0\n"); ++ return ret; ++ } ++ if (ret < 3) ++ { ++ printk("RET<3\n"); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Registers settings ++ */ ++ ++#define ENDMARKER { 0xff, 0xff } ++ ++static const struct regval_list ov5640_init_regs[] = { ++ {0x3103, 0x11}, ++ {0x3008, 0x82}, // sw reset ++ {0x3008, 0x42}, // sw powerdown ++ {0x3103, 0x03}, ++ {0x3017, 0xff}, ++ {0x3018, 0xff}, // i/o control ++ {0x3034, 0x18}, ++ {0x3035, 0x11}, ++ {0x3036, 0x46}, ++ {0x3037, 0x13}, ++ {0x3108, 0x01}, ++ {0x3630, 0x36}, //?? ++ {0x3631, 0x0e}, ++ {0x3632, 0xe2}, ++ {0x3633, 0x12}, ++ {0x3621, 0xe0}, ++ {0x3704, 0xa0}, //?? ++ {0x3703, 0x5a}, ++ {0x3715, 0x78}, ++ {0x3717, 0x01}, ++ {0x370b, 0x60}, ++ {0x3705, 0x1a}, ++ {0x3905, 0x02}, ++ {0x3906, 0x10}, ++ {0x3901, 0x0a}, ++ {0x3731, 0x12}, ++ {0x3600, 0x08}, ++ {0x3601, 0x33}, ++ {0x302d, 0x60}, ++ {0x3620, 0x52}, ++ {0x371b, 0x20}, ++ {0x471c, 0x50}, ++ {0x3a13, 0x43}, ++ {0x3a18, 0x00}, ++ {0x3a19, 0xf8}, ++ {0x3635, 0x13}, ++ {0x3636, 0x03}, ++ {0x3634, 0x40}, ++ {0x3622, 0x01}, ++ {0x3c01, 0x34}, ++ {0x3c04, 0x28}, ++ {0x3c05, 0x98}, ++ {0x3c06, 0x00}, ++ {0x3c07, 0x08}, ++ {0x3c08, 0x00}, ++ {0x3c09, 0x1c}, ++ {0x3c0a, 0x9c}, ++ {0x3c0b, 0x40}, ++ {0x3820, 0x41}, ++ {0x3821, 0x07}, ++ {0x3814, 0x31}, ++ {0x3815, 0x31}, ++ {0x3800, 0x00}, ++ {0x3801, 0x00}, ++ {0x3802, 0x00}, ++ {0x3803, 0x04}, ++ {0x3804, 0x0a}, ++ {0x3805, 0x3f}, ++ {0x3806, 0x07}, ++ {0x3807, 0x9b}, ++ {0x3808, 0x02}, ++ {0x3809, 0x80}, ++ {0x380a, 0x01}, ++ {0x380b, 0xe0}, ++ {0x380c, 0x07}, ++ {0x380d, 0x68}, ++ {0x380e, 0x03}, ++ {0x380f, 0xd8}, ++ {0x3810, 0x00}, ++ {0x3811, 0x10}, ++ {0x3812, 0x00}, ++ {0x3813, 0x06}, ++ {0x3618, 0x00}, ++ {0x3612, 0x29}, ++ {0x3708, 0x62}, ++ {0x3709, 0x52}, ++ {0x370c, 0x03}, ++ {0x3a02, 0x03}, ++ {0x3a03, 0xd8}, ++ {0x3a08, 0x01}, ++ {0x3a09, 0x27}, ++ {0x3a0a, 0x00}, ++ {0x3a0b, 0xf6}, ++ {0x3a0e, 0x03}, ++ {0x3a0d, 0x04}, ++ {0x3a14, 0x03}, ++ {0x3a15, 0xd8}, ++ {0x4000, 0x81}, ++ {0x4001, 0x02}, ++ {0x4004, 0x02}, ++ {0x3000, 0x00}, ++ {0x3002, 0x1c}, ++ {0x3004, 0xff}, ++ {0x3006, 0xc3}, ++ {0x300e, 0x58}, //set output interface is DVP ++ {0x302e, 0x00}, ++ {0x4300, 0x30}, //YUV422, sequence YUYV ++ {0x4740, 0x00}, //pclk polarity HSYNC, VSYNC, PCLK, 0: active low, 1: active high. ++ {0x501f, 0x00}, ++ {0x4713, 0x03}, ++ {0x4407, 0x04}, ++ {0x440e, 0x00}, ++ {0x460b, 0x35}, ++ {0x460c, 0x22}, ++ {0x3824, 0x02}, ++ {0x5000, 0xa7}, ++ {0x5001, 0xa3}, ++ {0x5180, 0xff}, ++ {0x5181, 0xf2}, ++ {0x5182, 0x00}, ++ {0x5183, 0x14}, ++ {0x5184, 0x25}, ++ {0x5185, 0x24}, ++ {0x5186, 0x09}, ++ {0x5187, 0x09}, ++ {0x5188, 0x09}, ++ {0x5189, 0x75}, ++ {0x518a, 0x54}, ++ {0x518b, 0xe0}, ++ {0x518c, 0xb2}, ++ {0x518d, 0x42}, ++ {0x518e, 0x3d}, ++ {0x518f, 0x56}, ++ {0x5190, 0x46}, ++ {0x5191, 0xf8}, ++ {0x5192, 0x04}, ++ {0x5193, 0x70}, ++ {0x5194, 0xf0}, ++ {0x5195, 0xf0}, ++ {0x5196, 0x03}, ++ {0x5197, 0x01}, ++ {0x5198, 0x04}, ++ {0x5199, 0x12}, ++ {0x519a, 0x04}, ++ {0x519b, 0x00}, ++ {0x519c, 0x06}, ++ {0x519d, 0x82}, ++ {0x519e, 0x38}, ++ {0x5381, 0x1e}, ++ {0x5382, 0x5b}, ++ {0x5383, 0x08}, ++ {0x5384, 0x0a}, ++ {0x5385, 0x7e}, ++ {0x5386, 0x88}, ++ {0x5387, 0x7c}, ++ {0x5388, 0x6c}, ++ {0x5389, 0x10}, ++ {0x538a, 0x01}, ++ {0x538b, 0x98}, ++ {0x5300, 0x08}, ++ {0x5301, 0x30}, ++ {0x5302, 0x10}, ++ {0x5303, 0x00}, ++ {0x5304, 0x08}, ++ {0x5305, 0x30}, ++ {0x5306, 0x08}, ++ {0x5307, 0x16}, ++ {0x5309, 0x08}, ++ {0x530a, 0x30}, ++ {0x530b, 0x04}, ++ {0x530c, 0x06}, ++ {0x5480, 0x01}, ++ {0x5481, 0x08}, ++ {0x5482, 0x14}, ++ {0x5483, 0x28}, ++ {0x5484, 0x51}, ++ {0x5485, 0x65}, ++ {0x5486, 0x71}, ++ {0x5487, 0x7d}, ++ {0x5488, 0x87}, ++ {0x5489, 0x91}, ++ {0x548a, 0x9a}, ++ {0x548b, 0xaa}, ++ {0x548c, 0xb8}, ++ {0x548d, 0xcd}, ++ {0x548e, 0xdd}, ++ {0x548f, 0xea}, ++ {0x5490, 0x1d}, ++ {0x5580, 0x06}, ++ {0x5583, 0x40}, ++ {0x5584, 0x10}, ++ {0x5589, 0x10}, ++ {0x558a, 0x00}, ++ {0x558b, 0xf8}, ++ {0x5800, 0x23}, ++ {0x5801, 0x14}, ++ {0x5802, 0x0f}, ++ {0x5803, 0x0f}, ++ {0x5804, 0x12}, ++ {0x5805, 0x26}, ++ {0x5806, 0x0c}, ++ {0x5807, 0x08}, ++ {0x5808, 0x05}, ++ {0x5809, 0x05}, ++ {0x580a, 0x08}, ++ {0x580b, 0x0d}, ++ {0x580c, 0x08}, ++ {0x580d, 0x03}, ++ {0x580e, 0x00}, ++ {0x580f, 0x00}, ++ {0x5810, 0x03}, ++ {0x5811, 0x09}, ++ {0x5812, 0x07}, ++ {0x5813, 0x03}, ++ {0x5814, 0x00}, ++ {0x5815, 0x01}, ++ {0x5816, 0x03}, ++ {0x5817, 0x08}, ++ {0x5818, 0x0d}, ++ {0x5819, 0x08}, ++ {0x581a, 0x05}, ++ {0x581b, 0x06}, ++ {0x581c, 0x08}, ++ {0x581d, 0x0e}, ++ {0x581e, 0x29}, ++ {0x581f, 0x17}, ++ {0x5820, 0x11}, ++ {0x5821, 0x11}, ++ {0x5822, 0x15}, ++ {0x5823, 0x28}, ++ {0x5824, 0x46}, ++ {0x5825, 0x26}, ++ {0x5826, 0x08}, ++ {0x5827, 0x26}, ++ {0x5828, 0x64}, ++ {0x5829, 0x26}, ++ {0x582a, 0x24}, ++ {0x582b, 0x22}, ++ {0x582c, 0x24}, ++ {0x582d, 0x24}, ++ {0x582e, 0x06}, ++ {0x582f, 0x22}, ++ {0x5830, 0x40}, ++ {0x5831, 0x42}, ++ {0x5832, 0x24}, ++ {0x5833, 0x26}, ++ {0x5834, 0x24}, ++ {0x5835, 0x22}, ++ {0x5836, 0x22}, ++ {0x5837, 0x26}, ++ {0x5838, 0x44}, ++ {0x5839, 0x24}, ++ {0x583a, 0x26}, ++ {0x583b, 0x28}, ++ {0x583c, 0x42}, ++ {0x583d, 0xce}, ++ {0x5025, 0x00}, ++ {0x3a0f, 0x30}, ++ {0x3a10, 0x28}, ++ {0x3a1b, 0x30}, ++ {0x3a1e, 0x26}, ++ {0x3a11, 0x60}, ++ {0x3a1f, 0x14}, ++ {0x3008, 0x02}, ++ {0x3035, 0x21}, ++ //{0x503d, 0x80}, // color bar ++ {0x4202, 0X0F}, ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov5640_qvga_regs[] = { ++ {0x4202, 0x0f}, ++ ++ {0x3c07, 0x08}, ++ {0x5189, 0x72}, ++ ++ {0x3503, 0x00}, ++ {0x3a00, 0x3c}, ++ {0x3a02, 0x09}, ++ {0x3a03, 0x3a}, ++ {0x3a14, 0x09}, ++ {0x3a15, 0x3a}, ++ ++ {0x5302, 0x3f}, ++ {0x5303, 0x10}, ++ {0x5306, 0x04}, ++ {0x5307, 0x14}, ++ ++ {0x3820, 0x41}, ++ {0x3821, 0x07}, ++ ++ {0x3800, 0x00}, ++ {0x3801, 0x00}, ++ {0x3802, 0x00}, ++ {0x3803, 0x04}, ++ {0x3804, 0x0a}, ++ {0x3805, 0x3f}, ++ {0x3806, 0x07}, ++ {0x3807, 0x9b}, ++ {0x3808, 0x01}, ++ {0x3809, 0x40}, ++ {0x380a, 0x00}, ++ {0x380b, 0xf0}, ++ {0x3810, 0x00}, ++ {0x3811, 0x10}, ++ {0x3812, 0x00}, ++ {0x3813, 0x06}, ++ {0x3814, 0x31}, ++ {0x3815, 0x31}, ++ ++ {0x3034, 0x1a}, ++ //{0x3035, 0x11}, ++ {0x3035, 0x21}, ++ ++ {0x3036, 0x46}, ++ {0x3037, 0x13}, ++ ++ {0x380c, 0x07}, ++ {0x380d, 0x68}, ++ {0x380e, 0x03}, ++ {0x380f, 0xd8}, ++ ++ {0x3a08, 0x01}, ++ {0x3a09, 0x27}, ++ {0x3a0e, 0x03}, ++ {0x3a0a, 0x00}, ++ {0x3a0b, 0xf6}, ++ {0x3a0d, 0x04}, ++ ++ {0x3618, 0x00}, ++ {0x3612, 0x29}, ++ {0x3709, 0x52}, ++ {0x370c, 0x03}, ++ ++ {0x4004, 0x02}, ++ {0x3002, 0x1c}, ++ {0x3006, 0xc3}, ++ {0x3824, 0x02}, ++ {0x5001, 0xa3}, ++ ++ {0x4713, 0x03}, ++ {0x4407, 0x04}, ++ {0x460b, 0x35}, ++ {0x460c, 0x22}, ++ {0x4837, 0x22}, ++ ++ {0x5586, 0x24}, ++ {0x5585, 0x10}, ++ {0x5587, 0x20}, ++ {0x5588, 0x01}, ++ ++ //{0x4202, 0x00}, ++ ++ {0x3023, 0x01}, ++ {0x3022, 0x04}, ++ ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov5640_vga_regs[] = { ++ {0x4202, 0x0f}, ++ ++ {0x3c07, 0x08}, ++ {0x5189, 0x72}, ++ ++ {0x3503, 0x00}, ++ {0x3a00, 0x3c}, ++ {0x3a02, 0x09}, ++ {0x3a03, 0x3a}, ++ {0x3a14, 0x09}, ++ {0x3a15, 0x3a}, ++ ++ {0x5302, 0x3f}, ++ {0x5303, 0x10}, ++ {0x5306, 0x04}, ++ {0x5307, 0x14}, ++ ++ {0x3820, 0x41}, ++ {0x3821, 0x07}, ++ ++ {0x3800, 0x00}, ++ {0x3801, 0x00}, ++ {0x3802, 0x00}, ++ {0x3803, 0x04}, ++ {0x3804, 0x0a}, ++ {0x3805, 0x3f}, ++ {0x3806, 0x07}, ++ {0x3807, 0x9b}, ++ {0x3808, 0x02}, ++ {0x3809, 0x80}, ++ {0x380a, 0x01}, ++ {0x380b, 0xe0}, ++ {0x3810, 0x00}, ++ {0x3811, 0x10}, ++ {0x3812, 0x00}, ++ {0x3813, 0x06}, ++ {0x3814, 0x31}, ++ {0x3815, 0x31}, ++ ++ {0x3034, 0x1a}, ++ {0x3035, 0x11}, ++ {0x3036, 0x46}, ++ {0x3037, 0x13}, ++ ++ {0x380c, 0x07}, ++ {0x380d, 0x68}, ++ {0x380e, 0x03}, ++ {0x380f, 0xd8}, ++ ++ {0x3a08, 0x01}, ++ {0x3a09, 0x27}, ++ {0x3a0e, 0x03}, ++ {0x3a0a, 0x00}, ++ {0x3a0b, 0xf6}, ++ {0x3a0d, 0x04}, ++ ++ {0x3618, 0x00}, ++ {0x3612, 0x29}, ++ {0x3709, 0x52}, ++ {0x370c, 0x03}, ++ ++ {0x4004, 0x02}, ++ {0x3002, 0x1c}, ++ {0x3006, 0xc3}, ++ {0x3824, 0x02}, ++ {0x5001, 0xa3}, ++ ++ {0x4713, 0x03}, ++ {0x4407, 0x04}, ++ {0x460b, 0x35}, ++ {0x460c, 0x22}, ++ {0x4837, 0x22}, ++ ++ {0x5586, 0x24}, ++ {0x5585, 0x10}, ++ {0x5587, 0x20}, ++ {0x5588, 0x01}, ++ ++// {0x4202, 0x00}, ++ ++ {0x3023, 0x01}, ++ {0x3022, 0x04}, ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov5640_720p_regs[] = { ++ {0x4202, 0x0f}, ++ ++ {0x3c07, 0x07}, ++ {0x5189, 0x72}, ++ ++ {0x3503, 0x00}, ++ ++ {0x5302, 0x3f}, ++ {0x5303, 0x10}, ++ {0x5306, 0x04}, ++ {0x5307, 0x14}, ++ ++ {0x3820, 0x41}, ++ {0x3821, 0x07}, ++ ++ {0x3800, 0x00}, ++ {0x3801, 0x00}, ++ {0x3802, 0x00}, ++ {0x3803, 0xfa}, ++ {0x3804, 0x0a}, ++ {0x3805, 0x3f}, ++ {0x3806, 0x06}, ++ {0x3807, 0xa9}, ++ {0x3808, 0x05}, ++ {0x3809, 0x00}, ++ {0x380a, 0x02}, ++ {0x380b, 0xd0}, ++ {0x3813, 0x04}, ++ {0x3814, 0x31}, ++ {0x3815, 0x31}, ++ ++ {0x3034, 0x1a}, ++ {0x3035, 0x41}, //30fps ++ {0x3036, 0x69}, ++ {0x3037, 0x13}, ++ ++ {0x380c, 0x07}, ++ {0x380d, 0x64}, ++ {0x380e, 0x02}, ++ {0x380f, 0xe4}, ++ ++ {0x3a08, 0x00}, ++ {0x3a09, 0xde}, ++ {0x3a0e, 0x03}, ++ {0x3a0a, 0x00}, ++ {0x3a0b, 0xb9}, ++ {0x3a0d, 0x04}, ++ ++ {0x3a00, 0x38}, ++ {0x3a02, 0x02}, ++ {0x3a03, 0xe4}, ++ {0x3a14, 0x02}, ++ {0x3a15, 0xe4}, ++ ++ {0x3618, 0x00}, ++ {0x3612, 0x29}, ++ {0x3709, 0x52}, ++ {0x370c, 0x03}, ++ ++ {0x4004, 0x02}, ++ {0x3002, 0x1c}, ++ {0x3006, 0xc3}, ++ {0x3824, 0x04}, ++ {0x5001, 0x83}, ++ ++ {0x4713, 0x03}, ++ {0x4407, 0x04}, ++ {0x460b, 0x37}, ++ {0x460c, 0x20}, ++ {0x4837, 0x16}, ++ ++ {0x5586, 0x24}, ++ {0x5585, 0x10}, ++ {0x5587, 0x20}, ++ {0x5588, 0x01}, ++ ++// {0x4202, 0x00}, ++ ++ {0x3023, 0x01}, ++ {0x3022, 0x04}, ++ ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov5640_1080p_regs[] = { ++ {0x4202, 0x0f}, ++ ++ {0x3c07, 0x07}, ++ {0x5189, 0x72}, ++ ++ {0x3503, 0x00}, ++ ++ {0x5302, 0x3f}, ++ {0x5303, 0x10}, ++ {0x5306, 0x04}, ++ {0x5307, 0x14}, ++ ++ {0x3820, 0x40}, ++ {0x3821, 0x00}, ++ ++ {0x3800, 0x01}, ++ {0x3801, 0x50}, ++ {0x3802, 0x01}, ++ {0x3803, 0xb2}, ++ {0x3804, 0x08}, ++ {0x3805, 0xef}, ++ {0x3806, 0x05}, ++ {0x3807, 0xf1}, ++ {0x3808, 0x07}, ++ {0x3809, 0x80}, ++ {0x380a, 0x04}, ++ {0x380b, 0x38}, ++ {0x3813, 0x04}, ++ {0x3814, 0x11}, ++ {0x3815, 0x11}, ++ ++ {0x3034, 0x1a}, ++ {0x3035, 0x41}, //3.75fps ++ {0x3036, 0x69}, ++ {0x3037, 0x13}, ++ ++ {0x380c, 0x09}, ++ {0x380d, 0xc4}, ++ {0x380e, 0x04}, ++ {0x380f, 0x60}, ++ ++ {0x3a08, 0x01}, ++ {0x3a09, 0x50}, ++ {0x3a0e, 0x03}, ++ {0x3a0a, 0x01}, ++ {0x3a0b, 0x18}, ++ {0x3a0d, 0x04}, ++ ++ {0x3a00, 0x38}, ++ {0x3a02, 0x04}, ++ {0x3a03, 0x60}, ++ {0x3a14, 0x04}, ++ {0x3a15, 0x60}, ++ ++ {0x3618, 0x04}, ++ {0x3612, 0x2b}, ++ {0x3709, 0x12}, ++ {0x370c, 0x00}, ++ ++ {0x4004, 0x06}, ++ {0x3002, 0x1c}, ++ {0x3006, 0xc3}, ++ {0x3824, 0x04}, ++ {0x5001, 0x83}, ++ ++ {0x4713, 0x02}, ++ {0x4407, 0x04}, ++ {0x460b, 0x37}, ++ {0x460c, 0x20}, ++ {0x4837, 0x0a}, ++ ++ {0x5586, 0x24}, ++ {0x5585, 0x10}, ++ {0x5587, 0x20}, ++ {0x5588, 0x01}, ++ ++ //{0x4202, 0x00}, ++ ++ {0x3023, 0x01}, ++ {0x3022, 0x04}, ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov5640_wb_auto_regs[] = { ++ {0x3406, 0x00}, ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov5640_wb_incandescence_regs[] = { ++ {0x3212, 0x03}, ++ ++ {0x3406, 0x01}, ++ {0x3400, 0x05}, ++ {0x3401, 0x48}, ++ {0x3402, 0x04}, ++ {0x3403, 0x00}, ++ {0x3404, 0x07}, ++ {0x3405, 0xcf}, ++ ++ {0x3212, 0x13}, ++ {0x3212, 0xa3}, ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov5640_wb_daylight_regs[] = { ++ {0x3212, 0x03}, ++ ++ {0x3406, 0x01}, ++ {0x3400, 0x06}, ++ {0x3401, 0x1c}, ++ {0x3402, 0x04}, ++ {0x3403, 0x00}, ++ {0x3404, 0x04}, ++ {0x3405, 0xf3}, ++ ++ {0x3212, 0x13}, ++ {0x3212, 0xa3}, ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov5640_wb_fluorescent_regs[] = { ++ {0x3212, 0x03}, ++ ++ {0x3406, 0x01}, ++ {0x3400, 0x05}, ++ {0x3401, 0x8c}, ++ {0x3402, 0x04}, ++ {0x3403, 0x00}, ++ {0x3404, 0x06}, ++ {0x3405, 0xe8}, ++ ++ {0x3212, 0x13}, ++ {0x3212, 0xa3}, ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov5640_wb_cloud_regs[] = { ++ {0x3212, 0x03}, ++ ++ {0x3406, 0x01}, ++ {0x3400, 0x06}, ++ {0x3401, 0x48}, ++ {0x3402, 0x04}, ++ {0x3403, 0x00}, ++ {0x3404, 0x04}, ++ {0x3405, 0xd3}, ++ ++ {0x3212, 0x13}, ++ {0x3212, 0xa3}, ++ ENDMARKER, ++}; ++ ++static const struct mode_list ov5640_balance[] = { ++ {0, ov5640_wb_auto_regs}, {1, ov5640_wb_incandescence_regs}, ++ {2, ov5640_wb_daylight_regs}, {3, ov5640_wb_fluorescent_regs}, ++ {4, ov5640_wb_cloud_regs}, ++}; ++ ++static const struct regval_list ov5640_effect_normal_regs[] = { ++ {0x3212, 0x03}, ++ ++ {0x5580, 0x06}, ++ {0x5583, 0x40}, ++ {0x5584, 0x10}, ++ ++ {0x3212, 0x13}, ++ {0x3212, 0xa3}, ++ ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov5640_effect_grayscale_regs[] = { ++ {0x3212, 0x03}, ++ ++ {0x5580, 0x1e}, ++ {0x5583, 0x80}, ++ {0x5584, 0x80}, ++ ++ {0x3212, 0x13}, ++ {0x3212, 0xa3}, ++ ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov5640_effect_sepia_regs[] = { ++ {0x3212, 0x03}, ++ ++ {0x5580, 0x1e}, ++ {0x5583, 0x40}, ++ {0x5584, 0xa0}, ++ ++ {0x3212, 0x13}, ++ {0x3212, 0xa3}, ++ ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov5640_effect_colorinv_regs[] = { ++ {0x3212, 0x03}, ++ ++ {0x5580, 0x46}, ++ {0x5583, 0x40}, ++ {0x5584, 0x10}, ++ ++ {0x3212, 0x13}, ++ {0x3212, 0xa3}, ++ ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov5640_effect_sepiabluel_regs[] = { ++ {0x3212, 0x03}, ++ ++ {0x5580, 0x1e}, ++ {0x5583, 0xa0}, ++ {0x5584, 0x40}, ++ ++ {0x3212, 0x13}, ++ {0x3212, 0xa3}, ++ ++ ENDMARKER, ++}; ++ ++static const struct mode_list ov5640_effect[] = { ++ {0, ov5640_effect_normal_regs}, {1, ov5640_effect_grayscale_regs}, ++ {2, ov5640_effect_sepia_regs}, {3, ov5640_effect_colorinv_regs}, ++ {4, ov5640_effect_sepiabluel_regs}, ++}; ++ ++#define OV5640_SIZE(n, w, h, r) \ ++ {.name = n, .width = w , .height = h, .regs = r } ++ ++static struct ov5640_win_size ov5640_supported_win_sizes[] = { ++ OV5640_SIZE("1080P", W_1080P, H_1080P, ov5640_1080p_regs), ++ OV5640_SIZE("720P", W_720P, H_720P, ov5640_720p_regs), ++ OV5640_SIZE("VGA", W_VGA, H_VGA, ov5640_vga_regs), ++ OV5640_SIZE("QVGA", W_QVGA, H_QVGA, ov5640_qvga_regs), ++}; ++ ++#define N_WIN_SIZES (ARRAY_SIZE(ov5640_supported_win_sizes)) ++ ++static const struct regval_list ov5640_yuv422_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov5640_rgb565_regs[] = { ++ ENDMARKER, ++}; ++ ++static u32 ov5640_codes[] = { ++ MEDIA_BUS_FMT_YUYV8_2X8, ++ MEDIA_BUS_FMT_UYVY8_2X8, ++}; ++ ++/* ++ * Supported balance menus ++ */ ++static const struct v4l2_querymenu ov5640_balance_menus[] = { ++ { ++ .id = V4L2_CID_PRIVATE_BALANCE, ++ .index = 0, ++ .name = "auto", ++ }, { ++ .id = V4L2_CID_PRIVATE_BALANCE, ++ .index = 1, ++ .name = "incandescent", ++ }, { ++ .id = V4L2_CID_PRIVATE_BALANCE, ++ .index = 2, ++ .name = "fluorescent", ++ }, { ++ .id = V4L2_CID_PRIVATE_BALANCE, ++ .index = 3, ++ .name = "daylight", ++ }, { ++ .id = V4L2_CID_PRIVATE_BALANCE, ++ .index = 4, ++ .name = "cloudy-daylight", ++ }, ++ ++}; ++ ++/* ++ * Supported effect menus ++ */ ++static const struct v4l2_querymenu ov5640_effect_menus[] = { ++ { ++ .id = V4L2_CID_PRIVATE_EFFECT, ++ .index = 0, ++ .name = "none", ++ }, { ++ .id = V4L2_CID_PRIVATE_EFFECT, ++ .index = 1, ++ .name = "mono", ++ }, { ++ .id = V4L2_CID_PRIVATE_EFFECT, ++ .index = 2, ++ .name = "sepia", ++ }, { ++ .id = V4L2_CID_PRIVATE_EFFECT, ++ .index = 3, ++ .name = "negative", ++ }, { ++ .id = V4L2_CID_PRIVATE_EFFECT, ++ .index = 4, ++ .name = "aqua", ++ }, ++}; ++/* ++ * General functions ++ */ ++static struct ov5640_priv *to_ov5640(const struct i2c_client *client) ++{ ++ return container_of(i2c_get_clientdata(client), struct ov5640_priv, ++ subdev); ++} ++ ++static int ov5640_write_array(struct i2c_client *client, ++ const struct regval_list *vals) ++{ ++ int ret; ++ ++ while ((vals->reg_num != 0xff) || (vals->value != 0xff)) { ++ ret = ov5640_write_reg(client, vals->reg_num, vals->value); ++ dev_vdbg(&client->dev, "array: 0x%02x, 0x%02x", ++ vals->reg_num, vals->value); ++ ++ if (ret < 0) ++ return ret; ++ vals++; ++ } ++ ++ return 0; ++} ++ ++static int ov5640_mask_set(struct i2c_client *client, ++ u16 reg, u16 mask, u16 set) ++{ ++ s32 val = ov5640_read_reg(client, reg); ++ if (val < 0) ++ return val; ++ ++ val &= ~mask; ++ val |= set & mask; ++ ++ dev_vdbg(&client->dev, "masks: 0x%02x, 0x%02x", reg, val); ++ ++ return ov5640_write_reg(client, reg, val); ++} ++ ++static int ov5640_reset(struct i2c_client *client) ++{ ++ return 0; ++} ++ ++/* ++ * soc_camera_ops functions ++ */ ++static int ov5640_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ if (!enable ) { ++ dev_dbg(&client->dev, "stream down\n"); ++ ov5640_write_reg(client, 0x4202, 0x0f); ++ return 0; ++ } ++ ++ dev_dbg(&client->dev, "stream on\n"); ++ ov5640_write_reg(client, 0x4202, 0x00); ++ ++ return 0; ++} ++ ++static int ov5640_g_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = ++ &container_of(ctrl->handler, struct ov5640_priv, hdl)->subdev; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov5640_priv *priv = to_ov5640(client); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_VFLIP: ++ ctrl->val = priv->flag_vflip; ++ break; ++ case V4L2_CID_HFLIP: ++ ctrl->val = priv->flag_hflip; ++ break; ++ case V4L2_CID_PRIVATE_BALANCE: ++ ctrl->val = priv->balance_value; ++ break; ++ case V4L2_CID_PRIVATE_EFFECT: ++ ctrl->val = priv->effect_value; ++ break; ++ default: ++ break; ++ } ++ return 0; ++} ++ ++static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = ++ &container_of(ctrl->handler, struct ov5640_priv, hdl)->subdev; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov5640_priv *priv = to_ov5640(client); ++ int ret = 0; ++ int i = 0; ++ u16 value; ++ ++ int balance_count = ARRAY_SIZE(ov5640_balance); ++ int effect_count = ARRAY_SIZE(ov5640_effect); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_PRIVATE_BALANCE: ++ if(ctrl->val > balance_count) ++ return -EINVAL; ++ ++ for(i = 0; i < balance_count; i++) { ++ if(ctrl->val == ov5640_balance[i].index) { ++ ret = ov5640_write_array(client, ++ ov5640_balance[ctrl->val].mode_regs); ++ priv->balance_value = ctrl->val; ++ break; ++ } ++ } ++ break; ++ ++ case V4L2_CID_PRIVATE_EFFECT: ++ if(ctrl->val > effect_count) ++ return -EINVAL; ++ ++ for(i = 0; i < effect_count; i++) { ++ if(ctrl->val == ov5640_effect[i].index) { ++ ret = ov5640_write_array(client, ++ ov5640_effect[ctrl->val].mode_regs); ++ priv->effect_value = ctrl->val; ++ break; ++ } ++ } ++ break; ++ ++ case V4L2_CID_VFLIP: ++ value = ctrl->val ? OV5640_FLIP_VAL : 0x00; ++ priv->flag_vflip = ctrl->val ? 1 : 0; ++ ret = ov5640_mask_set(client, REG_TC_VFLIP, OV5640_FLIP_MASK, value); ++ break; ++ ++ case V4L2_CID_HFLIP: ++ value = ctrl->val ? OV5640_FLIP_VAL : 0x00; ++ priv->flag_hflip = ctrl->val ? 1 : 0; ++ ret = ov5640_mask_set(client, REG_TC_MIRROR, OV5640_FLIP_MASK, value); ++ break; ++ ++ default: ++ dev_err(&client->dev, "no V4L2 CID: 0x%x ", ctrl->id); ++ return -EINVAL; ++ } ++ ++ return ret; ++} ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int ov5640_g_register(struct v4l2_subdev *sd, ++ struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ int ret; ++ ++ reg->size = 1; ++ if (reg->reg == 0xff) ++ return -EINVAL; ++ ++ ret = ov5640_read_reg(client, reg->reg); ++ if (ret < 0) ++ return ret; ++ ++ reg->val = ret; ++ ++ return 0; ++} ++ ++static int ov5640_s_register(struct v4l2_subdev *sd, ++ const struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ if (reg->reg == 0xff || ++ reg->val == 0xff) ++ return -EINVAL; ++ ++ return ov5640_write_reg(client, reg->reg, reg->val); ++} ++#endif ++ ++static int ov5640_s_power(struct v4l2_subdev *sd, int on) ++ ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); ++ struct ov5640_priv *priv = to_ov5640(client); ++ ++ return soc_camera_set_power(&client->dev, ssdd, priv->clk, on); ++} ++ ++static int ov5640_querymenu(struct v4l2_subdev *sd, ++ struct v4l2_querymenu *qm) ++{ ++ switch (qm->id) { ++ case V4L2_CID_PRIVATE_BALANCE: ++ memcpy(qm->name, ov5640_balance_menus[qm->index].name, ++ sizeof(qm->name)); ++ break; ++ ++ case V4L2_CID_PRIVATE_EFFECT: ++ memcpy(qm->name, ov5640_effect_menus[qm->index].name, ++ sizeof(qm->name)); ++ break; ++ } ++ ++ return 0; ++} ++ ++ ++/* Select the nearest higher resolution for capture */ ++static const struct ov5640_win_size *ov5640_select_win(u32 *width, u32 *height) ++{ ++ int i, default_size = ARRAY_SIZE(ov5640_supported_win_sizes) - 1; ++ ++ ++ for (i = 0; i < ARRAY_SIZE(ov5640_supported_win_sizes); i++) { ++ if ((*width >= ov5640_supported_win_sizes[i].width) && ++ (*height >= ov5640_supported_win_sizes[i].height)) { ++ *width = ov5640_supported_win_sizes[i].width; ++ *height = ov5640_supported_win_sizes[i].height; ++ return &ov5640_supported_win_sizes[i]; ++ } ++ } ++ ++ *width = ov5640_supported_win_sizes[default_size].width; ++ *height = ov5640_supported_win_sizes[default_size].height; ++ return &ov5640_supported_win_sizes[default_size]; ++} ++ ++static int ov5640_set_params(struct i2c_client *client, u32 *width, u32 *height, ++ u32 code) ++{ ++ struct ov5640_priv *priv = to_ov5640(client); ++ int ret; ++ ++ int bala_index = priv->balance_value; ++ int effe_index = priv->effect_value; ++ ++ /* select win */ ++ priv->win = ov5640_select_win(width, height); ++ ++ /* select format */ ++ priv->cfmt_code = 0; ++ ++ /* reset hardware */ ++ ov5640_reset(client); ++ ++ /* initialize the sensor with default data */ ++ dev_dbg(&client->dev, "%s: Init default", __func__); ++ ret = ov5640_write_array(client, ov5640_init_regs); ++ if (ret < 0) ++ goto err; ++ ++ /* set balance */ ++ ret = ov5640_write_array(client, ov5640_balance[bala_index].mode_regs); ++ if (ret < 0) ++ goto err; ++ ++ /* set effect */ ++ ret = ov5640_write_array(client, ov5640_effect[effe_index].mode_regs); ++ if (ret < 0) ++ goto err; ++ ++ /* set size win */ ++ ret = ov5640_write_array(client, priv->win->regs); ++ if (ret < 0) ++ goto err; ++ ++ priv->cfmt_code = code; ++ *width = priv->win->width; ++ *height = priv->win->height; ++ ++ return 0; ++ ++err: ++ dev_err(&client->dev, "%s: Error %d", __func__, ret); ++ ov5640_reset(client); ++ priv->win = NULL; ++ ++ return ret; ++} ++ ++static int ov5640_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov5640_priv *priv = to_ov5640(client); ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ if (!priv->win) { ++ u32 width = W_VGA, height = H_VGA; ++ priv->win = ov5640_select_win(&width, &height); ++ priv->cfmt_code = MEDIA_BUS_FMT_UYVY8_2X8; ++ } ++ ++ mf->width = priv->win->width; ++ mf->height = priv->win->height; ++ mf->code = priv->cfmt_code; ++ ++ switch (mf->code) { ++ case MEDIA_BUS_FMT_RGB565_2X8_BE: ++ case MEDIA_BUS_FMT_RGB565_2X8_LE: ++ mf->colorspace = V4L2_COLORSPACE_SRGB; ++ break; ++ default: ++ case MEDIA_BUS_FMT_YUYV8_2X8: ++ case MEDIA_BUS_FMT_UYVY8_2X8: ++ mf->colorspace = V4L2_COLORSPACE_JPEG; ++ } ++ mf->field = V4L2_FIELD_NONE; ++ ++ return 0; ++} ++ ++static int ov5640_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ /* ++ * select suitable win, but don't store it ++ */ ++ ov5640_select_win(&mf->width, &mf->height); ++ ++ mf->field = V4L2_FIELD_NONE; ++ ++ switch (mf->code) { ++ case MEDIA_BUS_FMT_RGB565_2X8_BE: ++ case MEDIA_BUS_FMT_RGB565_2X8_LE: ++ mf->colorspace = V4L2_COLORSPACE_SRGB; ++ break; ++ default: ++ mf->code = MEDIA_BUS_FMT_UYVY8_2X8; ++ case MEDIA_BUS_FMT_YUYV8_2X8: ++ case MEDIA_BUS_FMT_UYVY8_2X8: ++ mf->colorspace = V4L2_COLORSPACE_JPEG; ++ } ++ ++ if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) ++ return ov5640_set_params(client, &mf->width, ++ &mf->height, mf->code); ++ cfg->try_fmt = *mf; ++ return 0; ++} ++ ++static int ov5640_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ if (code->pad || code->index >= ARRAY_SIZE(ov5640_codes)) ++ return -EINVAL; ++ ++ code->code = ov5640_codes[code->index]; ++ return 0; ++} ++ ++static int ov5640_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) ++{ ++ a->c.left = 0; ++ a->c.top = 0; ++ a->c.width = UXGA_WIDTH; ++ a->c.height = UXGA_HEIGHT; ++ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ ++ return 0; ++} ++ ++static int ov5640_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) ++{ ++ a->bounds.left = 0; ++ a->bounds.top = 0; ++ a->bounds.width = UXGA_WIDTH; ++ a->bounds.height = UXGA_HEIGHT; ++ a->defrect = a->bounds; ++ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ a->pixelaspect.numerator = 1; ++ a->pixelaspect.denominator = 1; ++ ++ return 0; ++} ++ ++static int ov5640_video_probe(struct i2c_client *client) ++{ ++ unsigned char retval = 0, retval_high = 0, retval_low = 0; ++ struct ov5640_priv *priv = to_ov5640(client); ++ int ret; ++ ++ ret = ov5640_s_power(&priv->subdev, 1); ++ if (ret < 0) ++ return ret; ++ /* ++ * check and show product ID and manufacturer ID ++ */ ++ ++ retval = ov5640_write_reg(client, 0x3008, 0x80); ++ if(retval) { ++ dev_err(&client->dev, "i2c write failed!\n"); ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ retval_high = ov5640_read_reg(client, REG_CHIP_ID_HIGH); ++ if (retval_high != CHIP_ID_HIGH) { ++ dev_err(&client->dev, "read sensor %s chip_id high %x is error\n", ++ client->name, retval_high); ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ ++ retval_low = ov5640_read_reg(client, REG_CHIP_ID_LOW); ++ if (retval_low != CHIP_ID_LOW) { ++ dev_err(&client->dev, "read sensor %s chip_id low %x is error\n", ++ client->name, retval_low); ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ dev_info(&client->dev, "read sensor %s id high:0x%x,low:%x successed!\n", ++ client->name, retval_high, retval_low); ++ ++ ret = v4l2_ctrl_handler_setup(&priv->hdl); ++ ++done: ++ ov5640_s_power(&priv->subdev, 0); ++ return ret; ++} ++ ++static const struct v4l2_ctrl_ops ov5640_ctrl_ops = { ++ .s_ctrl = ov5640_s_ctrl, ++ .g_volatile_ctrl = ov5640_g_ctrl, ++}; ++ ++static struct v4l2_subdev_core_ops ov5640_subdev_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = ov5640_g_register, ++ .s_register = ov5640_s_register, ++#endif ++ .s_power = ov5640_s_power, ++ .querymenu = ov5640_querymenu, ++}; ++ ++static int ov5640_g_mbus_config(struct v4l2_subdev *sd, ++ struct v4l2_mbus_config *cfg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); ++ ++ cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | ++ V4L2_MBUS_VSYNC_ACTIVE_LOW | V4L2_MBUS_HSYNC_ACTIVE_HIGH | ++ V4L2_MBUS_DATA_ACTIVE_HIGH; ++ cfg->type = V4L2_MBUS_PARALLEL; ++ ++ cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); ++ ++ return 0; ++} ++ ++static struct v4l2_subdev_video_ops ov5640_subdev_video_ops = { ++ .s_stream = ov5640_s_stream, ++ .cropcap = ov5640_cropcap, ++ .g_crop = ov5640_g_crop, ++ .g_mbus_config = ov5640_g_mbus_config, ++}; ++ ++static const struct v4l2_subdev_pad_ops ov5640_subdev_pad_ops = { ++ .enum_mbus_code = ov5640_enum_mbus_code, ++ .get_fmt = ov5640_get_fmt, ++ .set_fmt = ov5640_set_fmt, ++}; ++ ++static struct v4l2_subdev_ops ov5640_subdev_ops = { ++ .core = &ov5640_subdev_core_ops, ++ .video = &ov5640_subdev_video_ops, ++ .pad = &ov5640_subdev_pad_ops, ++}; ++ ++/* OF probe functions */ ++static int ov5640_hw_power(struct device *dev, int on) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct ov5640_priv *priv = to_ov5640(client); ++ ++ dev_dbg(&client->dev, "%s: %s the camera\n", ++ __func__, on ? "ENABLE" : "DISABLE"); ++ ++ /* thses gpio should be set according to the active level in dt defines */ ++ if(priv->vcc_en_gpio) { ++ gpiod_direction_output(priv->vcc_en_gpio, on); ++ } ++ ++ if (priv->pwdn_gpio) { ++ gpiod_direction_output(priv->pwdn_gpio, !on); ++ } ++ ++ msleep(10); ++ return 0; ++} ++ ++static int ov5640_hw_reset(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct ov5640_priv *priv = to_ov5640(client); ++ ++ if (priv->resetb_gpio) { ++ /* Active the resetb pin to perform a reset pulse */ ++ gpiod_direction_output(priv->resetb_gpio, 1); ++ usleep_range(3000, 5000); ++ gpiod_direction_output(priv->resetb_gpio, 0); ++ } ++ ++ return 0; ++} ++ ++ ++static int ov5640_probe_dt(struct i2c_client *client, ++ struct ov5640_priv *priv) ++{ ++ ++ struct soc_camera_subdev_desc *ssdd_dt = &priv->ssdd_dt; ++ struct v4l2_subdev_platform_data *sd_pdata = &ssdd_dt->sd_pdata; ++ struct device_node *np = client->dev.of_node; ++ int supplies = 0, index = 0; ++ ++ supplies = of_property_count_strings(np, "supplies-name"); ++ if(supplies <= 0) { ++ goto no_supply; ++ } ++ ++ sd_pdata->num_regulators = supplies; ++ sd_pdata->regulators = devm_kzalloc(&client->dev, supplies * sizeof(struct regulator_bulk_data), GFP_KERNEL); ++ if(!sd_pdata->regulators) { ++ dev_err(&client->dev, "Failed to allocate regulators.!\n"); ++ goto no_supply; ++ } ++ ++ for(index = 0; index < sd_pdata->num_regulators; index ++) { ++ of_property_read_string_index(np, "supplies-name", index, ++ &(sd_pdata->regulators[index].supply)); ++ ++ dev_dbg(&client->dev, "sd_pdata->regulators[%d].supply: %s\n", ++ index, sd_pdata->regulators[index].supply); ++ } ++ ++ soc_camera_power_init(&client->dev, ssdd_dt); ++ ++no_supply: ++ ++ /* Request the reset GPIO deasserted */ ++ priv->resetb_gpio = devm_gpiod_get_optional(&client->dev, "resetb", ++ GPIOD_OUT_LOW); ++ if (!priv->resetb_gpio) ++ dev_dbg(&client->dev, "resetb gpio is not assigned!\n"); ++ else if (IS_ERR(priv->resetb_gpio)) ++ return PTR_ERR(priv->resetb_gpio); ++ ++ /* Request the power down GPIO asserted */ ++ priv->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "pwdn", ++ GPIOD_OUT_HIGH); ++ if (!priv->pwdn_gpio) ++ dev_dbg(&client->dev, "pwdn gpio is not assigned!\n"); ++ else if (IS_ERR(priv->pwdn_gpio)) ++ return PTR_ERR(priv->pwdn_gpio); ++ ++ /* Request the power down GPIO asserted */ ++ priv->vcc_en_gpio = devm_gpiod_get_optional(&client->dev, "vcc-en", ++ GPIOD_OUT_HIGH); ++ if (!priv->vcc_en_gpio) ++ dev_dbg(&client->dev, "vcc_en gpio is not assigned!\n"); ++ else if (IS_ERR(priv->vcc_en_gpio)) ++ return PTR_ERR(priv->vcc_en_gpio); ++ ++ /* Initialize the soc_camera_subdev_desc */ ++ priv->ssdd_dt.power = ov5640_hw_power; ++ priv->ssdd_dt.reset = ov5640_hw_reset; ++ client->dev.platform_data = &priv->ssdd_dt; ++ return 0; ++} ++ ++#include ++/* ++ * i2c_driver functions ++ */ ++static int ov5640_probe(struct i2c_client *client, ++ const struct i2c_device_id *did) ++{ ++ struct ov5640_priv *priv; ++ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); ++ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); ++ int ret; ++ ++ ++ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA)) { ++ dev_err(&adapter->dev, ++ "OV5640: I2C-Adapter doesn't support SMBUS\n"); ++ return -EIO; ++ } ++ ++ priv = devm_kzalloc(&client->dev, sizeof(struct ov5640_priv), GFP_KERNEL); ++ if (!priv) { ++ dev_err(&adapter->dev, ++ "Failed to allocate memory for private data!\n"); ++ return -ENOMEM; ++ } ++ ++ priv->clk = v4l2_clk_get(&client->dev, "cgu_cim"); ++ if (IS_ERR(priv->clk)) ++ return -EPROBE_DEFER; ++ ++ v4l2_clk_set_rate(priv->clk, 24000000); ++ ++ if (!ssdd && !client->dev.of_node) { ++ dev_err(&client->dev, "Missing platform_data for driver\n"); ++ ret = -EINVAL; ++ goto err_videoprobe; ++ } ++ ++ if (!ssdd) { ++ ret = ov5640_probe_dt(client, priv); ++ if (ret) ++ goto err_clk; ++ } ++ ++ ++ v4l2_i2c_subdev_init(&priv->subdev, client, &ov5640_subdev_ops); ++ ++ /* add handler */ ++ v4l2_ctrl_handler_init(&priv->hdl, 2); ++ v4l2_ctrl_new_std(&priv->hdl, &ov5640_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&priv->hdl, &ov5640_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ priv->subdev.ctrl_handler = &priv->hdl; ++ if (priv->hdl.error) { ++ ret = priv->hdl.error; ++ goto err_clk; ++ } ++ ++ ret = ov5640_video_probe(client); ++ if (ret < 0) ++ goto err_videoprobe; ++ ++ ret = v4l2_async_register_subdev(&priv->subdev); ++ if (ret < 0) ++ goto err_videoprobe; ++ ++ dev_info(&adapter->dev, "OV5640 Probed\n"); ++ ++ return 0; ++ ++err_videoprobe: ++ v4l2_ctrl_handler_free(&priv->hdl); ++err_clk: ++ v4l2_clk_put(priv->clk); ++ return ret; ++} ++ ++static int ov5640_remove(struct i2c_client *client) ++{ ++ struct ov5640_priv *priv = to_ov5640(client); ++ ++ v4l2_async_unregister_subdev(&priv->subdev); ++ v4l2_clk_put(priv->clk); ++ v4l2_device_unregister_subdev(&priv->subdev); ++ v4l2_ctrl_handler_free(&priv->hdl); ++ return 0; ++} ++ ++static const struct i2c_device_id ov5640_id[] = { ++ { "ov5640", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, ov5640_id); ++ ++static const struct of_device_id ov5640_of_match[] = { ++ {.compatible = "ovti,ov5640", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ov5640_of_match); ++ ++static struct i2c_driver ov5640_i2c_driver = { ++ .driver = { ++ .name = "ov5640", ++ .of_match_table = of_match_ptr(ov5640_of_match), ++ }, ++ .probe = ov5640_probe, ++ .remove = ov5640_remove, ++ .id_table = ov5640_id, ++}; ++ ++module_i2c_driver(ov5640_i2c_driver); ++ ++MODULE_DESCRIPTION("SoC Camera driver for Omni Vision 5640 sensor"); ++MODULE_AUTHOR("Alberto Panizzo"); ++MODULE_LICENSE("GPL v2"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_i2c_soc_camera_ov9281.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_i2c_soc_camera_ov9281.c.patch new file mode 100644 index 00000000..8bb6460e --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_i2c_soc_camera_ov9281.c.patch @@ -0,0 +1,1118 @@ +diff -drupN a/drivers/media/i2c/soc_camera/ov9281.c b/drivers/media/i2c/soc_camera/ov9281.c +--- a/drivers/media/i2c/soc_camera/ov9281.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/i2c/soc_camera/ov9281.c 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,1114 @@ ++/* ++ * ov9281 Camera Driver ++ * ++ * Copyright (C) 2010 Alberto Panizzo ++ * ++ * Based on ov772x, ov9640 drivers and previous non merged implementations. ++ * ++ * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. ++ * Copyright (C) 2006, OmniVision ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#define REG_CHIP_ID_HIGH 0x300a ++#define REG_CHIP_ID_LOW 0x300b ++#define CHIP_ID_HIGH 0x92 ++#define CHIP_ID_LOW 0x81 ++ ++#define OV9281_DEFAULT_WIDTH 1280 ++#define OV9281_DEFAULT_HEIGHT 720 ++ ++/* Private v4l2 controls */ ++#define V4L2_CID_PRIVATE_BALANCE (V4L2_CID_PRIVATE_BASE + 0) ++#define V4L2_CID_PRIVATE_EFFECT (V4L2_CID_PRIVATE_BASE + 1) ++ ++#define REG_TC_VFLIP 0x3820 ++#define REG_TC_MIRROR 0x3821 ++#define OV9281_FLIP_VAL ((unsigned char)0x04) ++#define OV9281_FLIP_MASK ((unsigned char)0x04) ++ ++/* whether sensor support high resolution (> vga) preview or not */ ++#define SUPPORT_HIGH_RESOLUTION_PRE 1 ++ ++/* ++ * Struct ++ */ ++struct regval_list { ++ u16 reg_num; ++ u16 value; ++}; ++ ++struct mode_list { ++ u16 index; ++ const struct regval_list *mode_regs; ++}; ++ ++/* Supported resolutions */ ++enum ov9281_width { ++ W_720P = OV9281_DEFAULT_WIDTH, ++}; ++ ++enum ov9281_height { ++ H_720P = OV9281_DEFAULT_HEIGHT, ++}; ++ ++struct ov9281_win_size { ++ char *name; ++ enum ov9281_width width; ++ enum ov9281_height height; ++ const struct regval_list *regs; ++}; ++ ++struct ov9281_priv { ++ struct v4l2_subdev subdev; ++ struct v4l2_ctrl_handler hdl; ++ u32 cfmt_code; ++ struct v4l2_clk *clk; ++ const struct ov9281_win_size *win; ++ ++ int model; ++ u16 balance_value; ++ u16 effect_value; ++ u16 flag_vflip:1; ++ u16 flag_hflip:1; ++ ++ struct soc_camera_subdev_desc ssdd_dt; ++ struct gpio_desc *resetb_gpio; ++ struct gpio_desc *pwdn_gpio; ++ struct gpio_desc *vcc_en_gpio; ++ ++ struct regulator *reg; ++ struct regulator *reg1; ++}; ++ ++static int ov9281_s_power(struct v4l2_subdev *sd, int on); ++static inline int sensor_i2c_master_send(struct i2c_client *client, ++ const char *buf ,int count) ++{ ++ int ret; ++ struct i2c_adapter *adap=client->adapter; ++ struct i2c_msg msg; ++ ++ msg.addr = client->addr; ++ msg.flags = client->flags & I2C_M_TEN; ++ msg.len = count; ++ msg.buf = (char *)buf; ++ ++ ret = i2c_transfer(adap, &msg, 1); ++ ++ return (ret == 1) ? count : ret; ++} ++ ++static inline int sensor_i2c_master_recv(struct i2c_client *client, ++ char *buf ,int count) ++{ ++ struct i2c_adapter *adap=client->adapter; ++ struct i2c_msg msg; ++ int ret; ++ ++ msg.addr = client->addr; ++ msg.flags = client->flags & I2C_M_TEN; ++ msg.flags |= I2C_M_RD; ++ msg.len = count; ++ msg.buf = buf; ++ ret = i2c_transfer(adap, &msg, 1); ++ ++ return (ret == 1) ? count : ret; ++} ++ ++ ++unsigned char ov9281_read_reg(struct i2c_client *client, u16 reg) ++{ ++ int ret; ++ unsigned char retval; ++ unsigned short r = cpu_to_be16(reg); ++ ++ ret = sensor_i2c_master_send(client,(u8 *)&r,2); ++ ++ if (ret < 0) ++ return ret; ++ if (ret != 2) ++ return -EIO; ++ ++ ret = sensor_i2c_master_recv(client, &retval, 1); ++ if (ret < 0) ++ return ret; ++ if (ret != 1) ++ return -EIO; ++ return retval; ++} ++ ++int ov9281_write_reg(struct i2c_client *client, u16 reg, u8 val) ++{ ++ unsigned char msg[3]; ++ int ret; ++ ++ reg = cpu_to_be16(reg); ++ ++ memcpy(&msg[0], ®, 2); ++ memcpy(&msg[2], &val, 1); ++ ++ ret = sensor_i2c_master_send(client, msg, 3); ++ ++ if (ret < 0) ++ { ++ printk("RET<0\n"); ++ return ret; ++ } ++ if (ret < 3) ++ { ++ printk("RET<3\n"); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Registers settings ++ */ ++ ++#define ENDMARKER { 0xffff, 0xff } ++ ++static const struct regval_list ov9281_init_regs[] = { ++ { 0x0103, 0x01}, ++ { 0x0302, 0x32}, ++ { 0x030d, 0x50}, ++ { 0x030e, 0x02}, ++ { 0x3001, 0x00}, ++ { 0x3004, 0x00}, ++ { 0x3005, 0x00}, ++ { 0x3006, 0x04}, ++ { 0x3011, 0x0a}, ++ { 0x3013, 0x18}, ++ { 0x3022, 0x01}, ++ { 0x3030, 0x10}, ++ { 0x3039, 0x32}, ++ { 0x303a, 0x00}, ++ { 0x3500, 0x00}, ++ { 0x3501, 0x2a}, ++ { 0x3502, 0x90}, ++ { 0x3503, 0x08}, ++ { 0x3505, 0x8c}, ++ { 0x3507, 0x03}, ++ { 0x3508, 0x00}, ++ { 0x3509, 0x10}, ++ { 0x3610, 0x80}, ++ { 0x3611, 0xa0}, ++ { 0x3620, 0x6f}, ++ { 0x3632, 0x56}, ++ { 0x3633, 0x78}, ++ { 0x3662, 0x03}, /* 1 lane raw8 */ ++ { 0x3666, 0x00}, ++ { 0x366f, 0x5a}, ++ { 0x3680, 0x84}, ++ { 0x3712, 0x80}, ++ { 0x372d, 0x22}, ++ { 0x3731, 0x80}, ++ { 0x3732, 0x30}, ++ { 0x3778, 0x00}, ++ { 0x377d, 0x22}, ++ { 0x3788, 0x02}, ++ { 0x3789, 0xa4}, ++ { 0x378a, 0x00}, ++ { 0x378b, 0x4a}, ++ { 0x3799, 0x20}, ++ { 0x3800, 0x00}, ++ { 0x3801, 0x00}, ++ { 0x3802, 0x00}, ++ { 0x3803, 0x00}, ++ { 0x3804, 0x05}, ++ { 0x3805, 0x0f}, ++ { 0x3806, 0x03}, ++ { 0x3807, 0x2f}, ++ { 0x3808, 0x05}, ++ { 0x3809, 0x00}, ++ { 0x380a, 0x02}, ++ { 0x380b, 0xd0}, ++#if 0 /* 30 fps */ ++ { 0x380c, 0x05}, /* hsync */ ++ { 0x380d, 0xd8}, ++ { 0x380e, 0x06}, /* vsync */ ++ { 0x380f, 0x8e}, ++#endif ++#if 1 /* 45 fps */ ++ { 0x380c, 0x05}, /* hsync */ ++ { 0x380d, 0xd8}, ++ { 0x380e, 0x04}, /* vsync */ ++ { 0x380f, 0x8e}, ++#endif ++#if 0 /* 60 fps */ ++ { 0x380c, 0x04}, /* hsync */ ++ { 0x380d, 0xd8}, ++ { 0x380e, 0x03}, /* vsync */ ++ { 0x380f, 0x8e}, ++#endif ++ { 0x3810, 0x00}, ++ { 0x3811, 0x08}, ++ { 0x3812, 0x00}, ++ { 0x3813, 0x08}, ++ { 0x3814, 0x11}, ++ { 0x3815, 0x11}, ++ { 0x3820, 0x40}, ++ { 0x3821, 0x00}, ++ { 0x3881, 0x42}, ++ { 0x38b1, 0x00}, ++ { 0x3920, 0xff}, ++ { 0x4003, 0x40}, ++ { 0x4008, 0x04}, ++ { 0x4009, 0x0b}, ++ { 0x400c, 0x00}, ++ { 0x400d, 0x07}, ++ { 0x4010, 0x40}, ++ { 0x4043, 0x40}, ++ { 0x4307, 0x30}, ++ { 0x4317, 0x00}, ++ { 0x4501, 0x00}, ++ { 0x4507, 0x00}, ++ { 0x4509, 0x00}, ++ { 0x450a, 0x08}, ++ { 0x4601, 0x04}, ++ { 0x470f, 0x00}, ++ { 0x4f07, 0x00}, ++ { 0x4800, 0x00}, ++ { 0x5000, 0x9f}, ++ { 0x5001, 0x00}, ++ { 0x5e00, 0x00}, ++ { 0x5d00, 0x07}, ++ { 0x5d01, 0x00}, ++// { 0x0100, 0x00}, ++ ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov9281_wb_auto_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov9281_wb_incandescence_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov9281_wb_daylight_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov9281_wb_fluorescent_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov9281_wb_cloud_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct mode_list ov9281_balance[] = { ++ {0, ov9281_wb_auto_regs}, {1, ov9281_wb_incandescence_regs}, ++ {2, ov9281_wb_daylight_regs}, {3, ov9281_wb_fluorescent_regs}, ++ {4, ov9281_wb_cloud_regs}, ++}; ++ ++ ++static const struct regval_list ov9281_effect_normal_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov9281_effect_grayscale_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov9281_effect_sepia_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov9281_effect_colorinv_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov9281_effect_sepiabluel_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct mode_list ov9281_effect[] = { ++ {0, ov9281_effect_normal_regs}, {1, ov9281_effect_grayscale_regs}, ++ {2, ov9281_effect_sepia_regs}, {3, ov9281_effect_colorinv_regs}, ++ {4, ov9281_effect_sepiabluel_regs}, ++}; ++ ++static const struct regval_list ov9281_720p_regs[] = { ++ ENDMARKER, ++}; ++ ++#define OV9281_SIZE(n, w, h, r) \ ++ {.name = n, .width = w , .height = h, .regs = r } ++ ++static struct ov9281_win_size ov9281_supported_win_sizes[] = { ++ OV9281_SIZE("720P", W_720P, H_720P, ov9281_720p_regs), ++}; ++ ++#define N_WIN_SIZES (ARRAY_SIZE(ov9281_supported_win_sizes)) ++ ++static u32 ov9281_codes[] = { ++ MEDIA_BUS_FMT_Y8_1X8, ++}; ++ ++/* ++ * Supported balance menus ++ */ ++static const struct v4l2_querymenu ov9281_balance_menus[] = { ++ { ++ .id = V4L2_CID_PRIVATE_BALANCE, ++ .index = 0, ++ .name = "auto", ++ }, { ++ .id = V4L2_CID_PRIVATE_BALANCE, ++ .index = 1, ++ .name = "incandescent", ++ }, { ++ .id = V4L2_CID_PRIVATE_BALANCE, ++ .index = 2, ++ .name = "fluorescent", ++ }, { ++ .id = V4L2_CID_PRIVATE_BALANCE, ++ .index = 3, ++ .name = "daylight", ++ }, { ++ .id = V4L2_CID_PRIVATE_BALANCE, ++ .index = 4, ++ .name = "cloudy-daylight", ++ }, ++ ++}; ++ ++/* ++ * Supported effect menus ++ */ ++static const struct v4l2_querymenu ov9281_effect_menus[] = { ++ { ++ .id = V4L2_CID_PRIVATE_EFFECT, ++ .index = 0, ++ .name = "none", ++ }, { ++ .id = V4L2_CID_PRIVATE_EFFECT, ++ .index = 1, ++ .name = "mono", ++ }, { ++ .id = V4L2_CID_PRIVATE_EFFECT, ++ .index = 2, ++ .name = "sepia", ++ }, { ++ .id = V4L2_CID_PRIVATE_EFFECT, ++ .index = 3, ++ .name = "negative", ++ }, { ++ .id = V4L2_CID_PRIVATE_EFFECT, ++ .index = 4, ++ .name = "aqua", ++ }, ++}; ++ ++ ++/* ++ * General functions ++ */ ++static struct ov9281_priv *to_ov9281(const struct i2c_client *client) ++{ ++ return container_of(i2c_get_clientdata(client), struct ov9281_priv, ++ subdev); ++} ++ ++static int ov9281_write_array(struct i2c_client *client, ++ const struct regval_list *vals) ++{ ++ int ret; ++ ++ while ((vals->reg_num != 0xffff) || (vals->value != 0xff)) { ++ ret = ov9281_write_reg(client, vals->reg_num, vals->value); ++ dev_vdbg(&client->dev, "array: 0x%02x, 0x%02x", ++ vals->reg_num, vals->value); ++ ++ if (ret < 0) ++ return ret; ++ vals++; ++ } ++ return 0; ++} ++ ++static int ov9281_mask_set(struct i2c_client *client, ++ u16 reg, u16 mask, u16 set) ++{ ++ s32 val = ov9281_read_reg(client, reg); ++ if (val < 0) ++ return val; ++ ++ val &= ~mask; ++ val |= set & mask; ++ ++ dev_vdbg(&client->dev, "masks: 0x%02x, 0x%02x", reg, val); ++ ++ return ov9281_write_reg(client, reg, val); ++} ++ ++static int ov9281_reset(struct i2c_client *client) ++{ ++ return 0; ++} ++ ++/* ++ * soc_camera_ops functions ++ */ ++static int ov9281_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ if (!enable ) { ++ dev_info(&client->dev, "stream down\n"); ++ ov9281_write_reg(client, 0x0100, 0x00); ++ return 0; ++ } ++ ++ dev_info(&client->dev, "stream on\n"); ++ ov9281_write_reg(client, 0x0100, 0x01); ++ ++ return 0; ++} ++ ++static int ov9281_g_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = ++ &container_of(ctrl->handler, struct ov9281_priv, hdl)->subdev; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov9281_priv *priv = to_ov9281(client); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_VFLIP: ++ ctrl->val = priv->flag_vflip; ++ break; ++ case V4L2_CID_HFLIP: ++ ctrl->val = priv->flag_hflip; ++ break; ++ case V4L2_CID_PRIVATE_BALANCE: ++ ctrl->val = priv->balance_value; ++ break; ++ case V4L2_CID_PRIVATE_EFFECT: ++ ctrl->val = priv->effect_value; ++ break; ++ default: ++ break; ++ } ++ return 0; ++} ++ ++static int ov9281_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = ++ &container_of(ctrl->handler, struct ov9281_priv, hdl)->subdev; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov9281_priv *priv = to_ov9281(client); ++ int ret = 0; ++ int i = 0; ++ u16 value; ++ ++ int balance_count = ARRAY_SIZE(ov9281_balance); ++ int effect_count = ARRAY_SIZE(ov9281_effect); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_PRIVATE_BALANCE: ++ if(ctrl->val > balance_count) ++ return -EINVAL; ++ ++ for(i = 0; i < balance_count; i++) { ++ if(ctrl->val == ov9281_balance[i].index) { ++ ret = ov9281_write_array(client, ++ ov9281_balance[ctrl->val].mode_regs); ++ priv->balance_value = ctrl->val; ++ break; ++ } ++ } ++ break; ++ ++ case V4L2_CID_PRIVATE_EFFECT: ++ if(ctrl->val > effect_count) ++ return -EINVAL; ++ ++ for(i = 0; i < effect_count; i++) { ++ if(ctrl->val == ov9281_effect[i].index) { ++ ret = ov9281_write_array(client, ++ ov9281_effect[ctrl->val].mode_regs); ++ priv->effect_value = ctrl->val; ++ break; ++ } ++ } ++ break; ++ ++ case V4L2_CID_VFLIP: ++ value = ctrl->val ? OV9281_FLIP_VAL : 0x00; ++ priv->flag_vflip = ctrl->val ? 1 : 0; ++ ret = ov9281_mask_set(client, REG_TC_VFLIP, OV9281_FLIP_MASK, value); ++ break; ++ ++ case V4L2_CID_HFLIP: ++ value = ctrl->val ? OV9281_FLIP_VAL : 0x00; ++ priv->flag_hflip = ctrl->val ? 1 : 0; ++ ret = ov9281_mask_set(client, REG_TC_MIRROR, OV9281_FLIP_MASK, value); ++ break; ++ ++ default: ++ dev_err(&client->dev, "no V4L2 CID: 0x%x ", ctrl->id); ++ return -EINVAL; ++ } ++ ++ return ret; ++} ++ ++static int ov9281_querymenu(struct v4l2_subdev *sd, ++ struct v4l2_querymenu *qm) ++{ ++ switch (qm->id) { ++ case V4L2_CID_PRIVATE_BALANCE: ++ memcpy(qm->name, ov9281_balance_menus[qm->index].name, ++ sizeof(qm->name)); ++ break; ++ ++ case V4L2_CID_PRIVATE_EFFECT: ++ memcpy(qm->name, ov9281_effect_menus[qm->index].name, ++ sizeof(qm->name)); ++ break; ++ } ++ ++ return 0; ++} ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int ov9281_g_register(struct v4l2_subdev *sd, ++ struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ int ret; ++ ++ reg->size = 1; ++ if (reg->reg > 0xff) ++ return -EINVAL; ++ ++ ret = ov9281_read_reg(client, reg->reg); ++ if (ret < 0) ++ return ret; ++ ++ reg->val = ret; ++ ++ return 0; ++} ++ ++static int ov9281_s_register(struct v4l2_subdev *sd, ++ const struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ if (reg->reg > 0xff || ++ reg->val > 0xff) ++ return -EINVAL; ++ ++ return ov9281_write_reg(client, reg->reg, reg->val); ++} ++#endif ++ ++/* Select the nearest higher resolution for capture */ ++static const struct ov9281_win_size *ov9281_select_win(u32 *width, u32 *height) ++{ ++ int i, default_size = ARRAY_SIZE(ov9281_supported_win_sizes) - 1; ++ ++ for (i = 0; i < ARRAY_SIZE(ov9281_supported_win_sizes); i++) { ++ if ((*width >= ov9281_supported_win_sizes[i].width) && ++ (*height >= ov9281_supported_win_sizes[i].height)) { ++ *width = ov9281_supported_win_sizes[i].width; ++ *height = ov9281_supported_win_sizes[i].height; ++ return &ov9281_supported_win_sizes[i]; ++ } ++ } ++ ++ *width = ov9281_supported_win_sizes[default_size].width; ++ *height = ov9281_supported_win_sizes[default_size].height; ++ return &ov9281_supported_win_sizes[default_size]; ++} ++ ++static int ov9281_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov9281_priv *priv = to_ov9281(client); ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ mf->width = OV9281_DEFAULT_WIDTH;//priv->win->width; ++ mf->height = OV9281_DEFAULT_HEIGHT;//priv->win->height; ++ mf->code = priv->cfmt_code; ++ ++ mf->colorspace = V4L2_COLORSPACE_JPEG; ++ mf->field = V4L2_FIELD_NONE; ++ ++ return 0; ++} ++ ++static int ov9281_set_params(struct i2c_client *client, u32 *width, u32 *height, u32 code) ++{ ++ struct ov9281_priv *priv = to_ov9281(client); ++ int ret; ++ ++ int bala_index = priv->balance_value; ++ int effe_index = priv->effect_value; ++ ++ /* select win */ ++ priv->win = ov9281_select_win(width, height); ++ ++ /* select format */ ++ priv->cfmt_code = 0; ++ ++ /* reset hardware */ ++ ov9281_reset(client); ++ ++ /* initialize the sensor with default data */ ++ dev_dbg(&client->dev, "%s: Init default", __func__); ++ ret = ov9281_write_array(client, ov9281_init_regs); ++ if (ret < 0) ++ goto err; ++ ++ /* set balance */ ++ ret = ov9281_write_array(client, ov9281_balance[bala_index].mode_regs); ++ if (ret < 0) ++ goto err; ++ ++ /* set effect */ ++ ret = ov9281_write_array(client, ov9281_effect[effe_index].mode_regs); ++ if (ret < 0) ++ goto err; ++ ++ /* set size win */ ++ ret = ov9281_write_array(client, priv->win->regs); ++ if (ret < 0) ++ goto err; ++ ++ priv->cfmt_code = code; ++ *width = priv->win->width; ++ *height = priv->win->height; ++ ++ return 0; ++ ++err: ++ dev_err(&client->dev, "%s: Error %d", __func__, ret); ++ ov9281_reset(client); ++ priv->win = NULL; ++ ++ return ret; ++} ++ ++static int ov9281_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ /* ++ * select suitable win, but don't store it ++ */ ++ ov9281_select_win(&mf->width, &mf->height); ++ ++ mf->field = V4L2_FIELD_NONE; ++ mf->colorspace = V4L2_COLORSPACE_JPEG; ++ ++ if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) ++ return ov9281_set_params(client, &mf->width, ++ &mf->height, mf->code); ++ cfg->try_fmt = *mf; ++ return 0; ++} ++ ++static int ov9281_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ if (code->pad || code->index >= ARRAY_SIZE(ov9281_codes)) ++ return -EINVAL; ++ ++ code->code = ov9281_codes[code->index]; ++ return 0; ++} ++ ++static int ov9281_enum_frame_size(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_frame_size_enum *fse) ++{ ++ int i, j; ++ int num_valid = -1; ++ __u32 index = fse->index; ++ ++ if(index >= N_WIN_SIZES) ++ return -EINVAL; ++ ++ j = ARRAY_SIZE(ov9281_codes); ++ while(--j) ++ if(fse->code == ov9281_codes[j]) ++ break; ++ ++ for (i = 0; i < N_WIN_SIZES; i++) { ++ if (index == ++num_valid) { ++ fse->code = ov9281_codes[j]; ++ fse->min_width = ov9281_supported_win_sizes[index].width; ++ fse->max_width = fse->min_width; ++ fse->min_height = ov9281_supported_win_sizes[index].height; ++ fse->max_height = fse->min_height; ++ return 0; ++ } ++ } ++ ++ return -EINVAL; ++} ++ ++static int ov9281_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) ++{ ++ a->c.left = 0; ++ a->c.top = 0; ++ a->c.width = OV9281_DEFAULT_WIDTH; ++ a->c.height = OV9281_DEFAULT_HEIGHT; ++ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ ++ return 0; ++} ++ ++static int ov9281_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) ++{ ++ a->bounds.left = 0; ++ a->bounds.top = 0; ++ a->bounds.width = OV9281_DEFAULT_WIDTH; ++ a->bounds.height = OV9281_DEFAULT_HEIGHT; ++ a->defrect = a->bounds; ++ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ a->pixelaspect.numerator = 1; ++ a->pixelaspect.denominator = 1; ++ ++ return 0; ++} ++ ++static int ov9281_video_probe(struct i2c_client *client) ++{ ++ unsigned char retval_high = 0, retval_low = 0; ++ struct ov9281_priv *priv = to_ov9281(client); ++ int ret; ++ ++ ret = ov9281_s_power(&priv->subdev, 1); ++ if (ret < 0) ++ return ret; ++ /* ++ * check and show product ID and manufacturer ID ++ */ ++ ++ retval_high = ov9281_read_reg(client, REG_CHIP_ID_HIGH); ++ if (retval_high != CHIP_ID_HIGH) { ++ dev_err(&client->dev, "read sensor %s chip_id high %x is error\n", ++ client->name, retval_high); ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ ++ retval_low = ov9281_read_reg(client, REG_CHIP_ID_LOW); ++ if (retval_low != CHIP_ID_LOW) { ++ dev_err(&client->dev, "read sensor %s chip_id low %x is error\n", ++ client->name, retval_low); ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ dev_info(&client->dev, "read sensor %s id high:0x%x,low:%x successed!\n", ++ client->name, retval_high, retval_low); ++ ++ ret = v4l2_ctrl_handler_setup(&priv->hdl); ++ ++done: ++ ov9281_s_power(&priv->subdev, 0); ++ return ret; ++} ++ ++static int ov9281_s_power(struct v4l2_subdev *sd, int on) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); ++ struct ov9281_priv *priv = to_ov9281(client); ++ ++ return soc_camera_set_power(&client->dev, ssdd, priv->clk, on); ++} ++ ++static const struct v4l2_ctrl_ops ov9281_ctrl_ops = { ++ .s_ctrl = ov9281_s_ctrl, ++ .g_volatile_ctrl = ov9281_g_ctrl, ++}; ++ ++static struct v4l2_subdev_core_ops ov9281_subdev_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = ov9281_g_register, ++ .s_register = ov9281_s_register, ++#endif ++ .s_power = ov9281_s_power, ++ .querymenu = ov9281_querymenu, ++}; ++ ++static int ov9281_g_mbus_config(struct v4l2_subdev *sd, ++ struct v4l2_mbus_config *cfg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); ++ ++ cfg->type = V4L2_MBUS_CSI2; ++ cfg->flags = V4L2_MBUS_CSI2_CHANNEL_0 | V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; ++ cfg->flags |= V4L2_MBUS_CSI2_1_LANE; ++ ++ cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); ++ return 0; ++ ++ return 0; ++} ++ ++static struct v4l2_subdev_video_ops ov9281_subdev_video_ops = { ++ .s_stream = ov9281_s_stream, ++ .cropcap = ov9281_cropcap, ++ .g_crop = ov9281_g_crop, ++ .g_mbus_config = ov9281_g_mbus_config, ++}; ++ ++static const struct v4l2_subdev_pad_ops ov9281_subdev_pad_ops = { ++ .enum_mbus_code = ov9281_enum_mbus_code, ++ .enum_frame_size = ov9281_enum_frame_size, ++ .get_fmt = ov9281_get_fmt, ++ .set_fmt = ov9281_set_fmt, ++}; ++ ++static struct v4l2_subdev_ops ov9281_subdev_ops = { ++ .core = &ov9281_subdev_core_ops, ++ .video = &ov9281_subdev_video_ops, ++ .pad = &ov9281_subdev_pad_ops, ++}; ++ ++/* OF probe functions */ ++static int ov9281_hw_power(struct device *dev, int on) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct ov9281_priv *priv = to_ov9281(client); ++ ++ dev_dbg(&client->dev, "%s: %s the camera\n", ++ __func__, on ? "ENABLE" : "DISABLE"); ++ ++ /* thses gpio should be set according to the active level in dt defines */ ++ if(priv->vcc_en_gpio) { ++ gpiod_direction_output(priv->vcc_en_gpio, on); ++ } ++ ++ if (priv->pwdn_gpio) { ++ gpiod_direction_output(priv->pwdn_gpio, on); ++ } ++ ++ msleep(10); ++ return 0; ++} ++ ++static int ov9281_hw_reset(struct device *dev) ++{ ++ return 0; ++} ++ ++ ++static int ov9281_probe_dt(struct i2c_client *client, ++ struct ov9281_priv *priv) ++{ ++ ++ struct soc_camera_subdev_desc *ssdd_dt = &priv->ssdd_dt; ++ struct v4l2_subdev_platform_data *sd_pdata = &ssdd_dt->sd_pdata; ++ struct device_node *np = client->dev.of_node; ++ int supplies = 0, index = 0; ++ ++ supplies = of_property_count_strings(np, "supplies-name"); ++ if(supplies <= 0) { ++ goto no_supply; ++ } ++ ++ sd_pdata->num_regulators = supplies; ++ sd_pdata->regulators = devm_kzalloc(&client->dev, supplies * sizeof(struct regulator_bulk_data), GFP_KERNEL); ++ if(!sd_pdata->regulators) { ++ dev_err(&client->dev, "Failed to allocate regulators.!\n"); ++ goto no_supply; ++ } ++ ++ for(index = 0; index < sd_pdata->num_regulators; index ++) { ++ of_property_read_string_index(np, "supplies-name", index, ++ &(sd_pdata->regulators[index].supply)); ++ ++ dev_dbg(&client->dev, "sd_pdata->regulators[%d].supply: %s\n", ++ index, sd_pdata->regulators[index].supply); ++ } ++ ++ soc_camera_power_init(&client->dev, ssdd_dt); ++ ++no_supply: ++ ++ /* Request the power down GPIO asserted */ ++ priv->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "pwdn", ++ GPIOD_OUT_HIGH); ++ if (!priv->pwdn_gpio) ++ dev_dbg(&client->dev, "pwdn gpio is not assigned!\n"); ++ else if (IS_ERR(priv->pwdn_gpio)) ++ return PTR_ERR(priv->pwdn_gpio); ++ ++ /* Request the power down GPIO asserted */ ++ priv->vcc_en_gpio = devm_gpiod_get_optional(&client->dev, "vcc-en", ++ GPIOD_OUT_HIGH); ++ if (!priv->vcc_en_gpio) ++ dev_dbg(&client->dev, "vcc_en gpio is not assigned!\n"); ++ else if (IS_ERR(priv->vcc_en_gpio)) ++ return PTR_ERR(priv->vcc_en_gpio); ++ ++ /* Initialize the soc_camera_subdev_desc */ ++ priv->ssdd_dt.power = ov9281_hw_power; ++ priv->ssdd_dt.reset = ov9281_hw_reset; ++ client->dev.platform_data = &priv->ssdd_dt; ++ return 0; ++} ++ ++#include ++/* ++ * i2c_driver functions ++ */ ++static int ov9281_probe(struct i2c_client *client, ++ const struct i2c_device_id *did) ++{ ++ struct ov9281_priv *priv; ++ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); ++ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); ++ int ret; ++ ++ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA)) { ++ dev_err(&adapter->dev, ++ "ov9281: I2C-Adapter doesn't support SMBUS\n"); ++ return -EIO; ++ } ++ ++ priv = devm_kzalloc(&client->dev, sizeof(struct ov9281_priv), GFP_KERNEL); ++ if (!priv) { ++ dev_err(&adapter->dev, ++ "Failed to allocate memory for private data!\n"); ++ return -ENOMEM; ++ } ++ ++ priv->clk = v4l2_clk_get(&client->dev, "cgu_cim"); ++ if (IS_ERR(priv->clk)) ++ return -EPROBE_DEFER; ++ ++ v4l2_clk_set_rate(priv->clk, 24000000); ++ ++ if (!ssdd && !client->dev.of_node) { ++ dev_err(&client->dev, "Missing platform_data for driver\n"); ++ ret = -EINVAL; ++ goto err_videoprobe; ++ } ++ ++ if (!ssdd) { ++ ret = ov9281_probe_dt(client, priv); ++ if (ret) ++ goto err_clk; ++ } ++ ++ ++ v4l2_i2c_subdev_init(&priv->subdev, client, &ov9281_subdev_ops); ++ ++ /* add handler */ ++ v4l2_ctrl_handler_init(&priv->hdl, 2); ++ v4l2_ctrl_new_std(&priv->hdl, &ov9281_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&priv->hdl, &ov9281_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ priv->subdev.ctrl_handler = &priv->hdl; ++ if (priv->hdl.error) { ++ ret = priv->hdl.error; ++ goto err_clk; ++ } ++ ++ ret = ov9281_video_probe(client); ++ if (ret < 0) ++ goto err_videoprobe; ++ ++ ret = v4l2_async_register_subdev(&priv->subdev); ++ if (ret < 0) ++ goto err_videoprobe; ++ ++ dev_info(&adapter->dev, "ov9281 Probed\n"); ++ ++ return 0; ++ ++err_videoprobe: ++ v4l2_ctrl_handler_free(&priv->hdl); ++err_clk: ++ v4l2_clk_put(priv->clk); ++ return ret; ++} ++ ++static int ov9281_remove(struct i2c_client *client) ++{ ++ struct ov9281_priv *priv = to_ov9281(client); ++ ++ v4l2_async_unregister_subdev(&priv->subdev); ++ v4l2_clk_put(priv->clk); ++ v4l2_device_unregister_subdev(&priv->subdev); ++ v4l2_ctrl_handler_free(&priv->hdl); ++ return 0; ++} ++ ++static const struct i2c_device_id ov9281_id[] = { ++ { "ov9281", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, ov9281_id); ++static const struct of_device_id ov9281_of_match[] = { ++ {.compatible = "ovti,ov9281", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ov9281_of_match); ++static struct i2c_driver ov9281_i2c_driver = { ++ .driver = { ++ .name = "ov9281", ++ .of_match_table = of_match_ptr(ov9281_of_match), ++ }, ++ .probe = ov9281_probe, ++ .remove = ov9281_remove, ++ .id_table = ov9281_id, ++}; ++module_i2c_driver(ov9281_i2c_driver); ++ ++MODULE_DESCRIPTION("SoC Camera driver for Omni Vision ov9281 sensor"); ++MODULE_AUTHOR("Alberto Panizzo"); ++MODULE_LICENSE("GPL v2"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_Kconfig.patch new file mode 100644 index 00000000..28ab4a1b --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_Kconfig.patch @@ -0,0 +1,34 @@ +diff -drupN a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig +--- a/drivers/media/platform/Kconfig 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/media/platform/Kconfig 2022-06-09 05:02:29.000000000 +0300 +@@ -157,6 +157,30 @@ config VIDEO_MEM2MEM_DEINTERLACE + help + Generic deinterlacing V4L2 driver. + ++config VIDEO_INGENIC_JPEG ++ depends on VIDEO_DEV && VIDEO_V4L2 ++ depends on SOC_X1000 || SOC_X2000 ++ tristate "Ingenic JPEG codec driver" ++ select VIDEOBUF2_DMA_CONTIG ++ select V4L2_MEM2MEM_DEV ++ ---help--- ++ This is a v4l2 driver for Ingenic X1000 codec ++ ++config VIDEO_INGENIC_ROTATE ++ depends on VIDEO_DEV && VIDEO_V4L2 ++ depends on SOC_X2000 ++ tristate "Ingenic rotate driver" ++ select VIDEOBUF2_DMA_CONTIG ++ select V4L2_MEM2MEM_DEV ++ ---help--- ++ This is a v4l2 driver for Ingenic X2000 rotate ++ ++config VIDEO_INGENIC_VCODEC ++ tristate "V4L2 driver for ingenic Video Codec" ++ depends on VIDEO_DEV && VIDEO_V4L2 ++ select V4L2_MEM2MEM_DEV ++ select VIDEOBUF2_DMA_CONTIG ++ + config VIDEO_SAMSUNG_S5P_G2D + tristate "Samsung S5P and EXYNOS4 G2D 2d graphics accelerator driver" + depends on VIDEO_DEV && VIDEO_V4L2 diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_Makefile.patch new file mode 100644 index 00000000..0a69cc81 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_Makefile.patch @@ -0,0 +1,22 @@ +diff -drupN a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile +--- a/drivers/media/platform/Makefile 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/media/platform/Makefile 2022-06-09 05:02:29.000000000 +0300 +@@ -25,6 +25,9 @@ obj-$(CONFIG_VIDEO_SH_VEU) += sh_veu.o + + obj-$(CONFIG_VIDEO_MEM2MEM_DEINTERLACE) += m2m-deinterlace.o + ++obj-$(CONFIG_VIDEO_INGENIC_JPEG) += ingenic-jpeg/ ++obj-$(CONFIG_VIDEO_INGENIC_ROTATE) += ingenic-rotate/ ++ + obj-$(CONFIG_VIDEO_S3C_CAMIF) += s3c-camif/ + obj-$(CONFIG_VIDEO_SAMSUNG_EXYNOS4_IS) += exynos4-is/ + obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) += s5p-jpeg/ +@@ -34,6 +37,8 @@ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_TV) += s5 + obj-$(CONFIG_VIDEO_SAMSUNG_S5P_G2D) += s5p-g2d/ + obj-$(CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC) += exynos-gsc/ + ++obj-$(CONFIG_VIDEO_INGENIC_VCODEC) += ingenic-vcodec/ ++ + obj-$(CONFIG_VIDEO_STI_BDISP) += sti/bdisp/ + obj-$(CONFIG_DVB_C8SECTPFE) += sti/c8sectpfe/ + diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-jpeg_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-jpeg_Makefile.patch new file mode 100644 index 00000000..3bc1700f --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-jpeg_Makefile.patch @@ -0,0 +1,6 @@ +diff -drupN a/drivers/media/platform/ingenic-jpeg/Makefile b/drivers/media/platform/ingenic-jpeg/Makefile +--- a/drivers/media/platform/ingenic-jpeg/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-jpeg/Makefile 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,2 @@ ++ ++obj-$(CONFIG_VIDEO_INGENIC_JPEG) += jpeg-core.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-jpeg_ingenic_jpeg_enc.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-jpeg_ingenic_jpeg_enc.h.patch new file mode 100644 index 00000000..9efd1f1f --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-jpeg_ingenic_jpeg_enc.h.patch @@ -0,0 +1,190 @@ +diff -drupN a/drivers/media/platform/ingenic-jpeg/ingenic_jpeg_enc.h b/drivers/media/platform/ingenic-jpeg/ingenic_jpeg_enc.h +--- a/drivers/media/platform/ingenic-jpeg/ingenic_jpeg_enc.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-jpeg/ingenic_jpeg_enc.h 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,186 @@ ++#ifndef __INGENIC_JPEG_ENC_H__ ++#define __INGENIC_JPEG_ENC_H__ ++ ++#define HUFFENC_LEN (384) /* Huffman encoder table lenth */ ++#define QMEM_LEN (256) /* Quantization table lenth */ ++#define HUFNUM (1) /* Huffman encode table number */ ++#define QTNUM (3) /* Quantization table number */ ++#define YUV420P0C (0x30) /* component 0 configure information NBLK<<4| QT<<2| HA<<1| HD */ ++#define YUV420P1C (0x07) /* component 1 configure information NBLK<<4| QT<<2| HA<<1| HD */ ++#define YUV420P2C (0x07) /* component 2 configure information NBLK<<4| QT<<2| HA<<1| HD */ ++#define YUV420PVH (0x0a<<16) /* component vertical/horizontal size of MCU:P3H P3V P2H P2V P1H P1V P0H P0V */ ++#define JPGC_RSM (0x1<<2) /* JPGC rstart marker enable signal */ ++#define JPGC_SPEC (0x0<<1) /* YUV420 mode */ ++#define JPGC_UNIV (0x1<<1) /* YUV444 or YUV422 mode */ ++#define JPGC_EN (0x1) /* JPGC enable signal */ ++#define OPEN_CLOCK (0x1) /* open the core clock */ ++#define JPGC_NCOL (0x2<<4) /* color numbers of a MCU minus 1,it always 2 for YUV color space */ ++#define STAT_CLEAN (0x0) /* clean the STAT register */ ++#define CORE_RST (0x1<<6) /* JPGC core reset ,high active */ ++#define JPGC_EFE (0x1<<8) /* JPGC EFE source */ ++#define YUV_YUY2 (0x1<<29) /* YUY-YUY2 mode */ ++#define VRAM_RAWY_BA (VPU_BASE | 0xF0000) ++#define VRAM_RAWC_BA (VRAM_RAWY_BA + 256) ++ ++static const uint32_t huffenc[HUFNUM][HUFFENC_LEN] = { ++ { ++ 0x100, 0x101, 0x204, 0x30b, 0x41a, 0x678, 0x7f8, 0x9f6, ++ 0xf82, 0xf83, 0x30c, 0x41b, 0x679, 0x8f6, 0xaf6, 0xf84, ++ 0xf85, 0xf86, 0xf87, 0xf88, 0x41c, 0x7f9, 0x9f7, 0xbf4, ++ 0xf89, 0xf8a, 0xf8b, 0xf8c, 0xf8d, 0xf8e, 0x53a, 0x8f7, ++ 0xbf5, 0xf8f, 0xf90, 0xf91, 0xf92, 0xf93, 0xf94, 0xf95, ++ 0x53b, 0x9f8, 0xf96, 0xf97, 0xf98, 0xf99, 0xf9a, 0xf9b, ++ 0xf9c, 0xf9d, 0x67a, 0xaf7, 0xf9e, 0xf9f, 0xfa0, 0xfa1, ++ 0xfa2, 0xfa3, 0xfa4, 0xfa5, 0x67b, 0xbf6, 0xfa6, 0xfa7, ++ 0xfa8, 0xfa9, 0xfaa, 0xfab, 0xfac, 0xfad, 0x7fa, 0xbf7, ++ 0xfae, 0xfaf, 0xfb0, 0xfb1, 0xfb2, 0xfb3, 0xfb4, 0xfb5, ++ 0x8f8, 0xec0, 0xfb6, 0xfb7, 0xfb8, 0xfb9, 0xfba, 0xfbb, ++ 0xfbc, 0xfbd, 0x8f9, 0xfbe, 0xfbf, 0xfc0, 0xfc1, 0xfc2, ++ 0xfc3, 0xfc4, 0xfc5, 0xfc6, 0x8fa, 0xfc7, 0xfc8, 0xfc9, ++ 0xfca, 0xfcb, 0xfcc, 0xfcd, 0xfce, 0xfcf, 0x9f9, 0xfd0, ++ 0xfd1, 0xfd2, 0xfd3, 0xfd4, 0xfd5, 0xfd6, 0xfd7, 0xfd8, ++ 0x9fa, 0xfd9, 0xfda, 0xfdb, 0xfdc, 0xfdd, 0xfde, 0xfdf, ++ 0xfe0, 0xfe1, 0xaf8, 0xfe2, 0xfe3, 0xfe4, 0xfe5, 0xfe6, ++ 0xfe7, 0xfe8, 0xfe9, 0xfea, 0xfeb, 0xfec, 0xfed, 0xfee, ++ 0xfef, 0xff0, 0xff1, 0xff2, 0xff3, 0xff4, 0xff5, 0xff6, ++ 0xff7, 0xff8, 0xff9, 0xffa, 0xffb, 0xffc, 0xffd, 0xffe, ++ 0x30a, 0xaf9, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, ++ 0xfd0, 0xfd1, 0xfd2, 0xfd3, 0xfd4, 0xfd5, 0xfd6, 0xfd7, ++ 0x101, 0x204, 0x30a, 0x418, 0x419, 0x538, 0x678, 0x8f4, ++ 0x9f6, 0xbf4, 0x30b, 0x539, 0x7f6, 0x8f5, 0xaf6, 0xbf5, ++ 0xf88, 0xf89, 0xf8a, 0xf8b, 0x41a, 0x7f7, 0x9f7, 0xbf6, ++ 0xec2, 0xf8c, 0xf8d, 0xf8e, 0xf8f, 0xf90, 0x41b, 0x7f8, ++ 0x9f8, 0xbf7, 0xf91, 0xf92, 0xf93, 0xf94, 0xf95, 0xf96, ++ 0x53a, 0x8f6, 0xf97, 0xf98, 0xf99, 0xf9a, 0xf9b, 0xf9c, ++ 0xf9d, 0xf9e, 0x53b, 0x9f9, 0xf9f, 0xfa0, 0xfa1, 0xfa2, ++ 0xfa3, 0xfa4, 0xfa5, 0xfa6, 0x679, 0xaf7, 0xfa7, 0xfa8, ++ 0xfa9, 0xfaa, 0xfab, 0xfac, 0xfad, 0xfae, 0x67a, 0xaf8, ++ 0xfaf, 0xfb0, 0xfb1, 0xfb2, 0xfb3, 0xfb4, 0xfb5, 0xfb6, ++ 0x7f9, 0xfb7, 0xfb8, 0xfb9, 0xfba, 0xfbb, 0xfbc, 0xfbd, ++ 0xfbe, 0xfbf, 0x8f7, 0xfc0, 0xfc1, 0xfc2, 0xfc3, 0xfc4, ++ 0xfc5, 0xfc6, 0xfc7, 0xfc8, 0x8f8, 0xfc9, 0xfca, 0xfcb, ++ 0xfcc, 0xfcd, 0xfce, 0xfcf, 0xfd0, 0xfd1, 0x8f9, 0xfd2, ++ 0xfd3, 0xfd4, 0xfd5, 0xfd6, 0xfd7, 0xfd8, 0xfd9, 0xfda, ++ 0x8fa, 0xfdb, 0xfdc, 0xfdd, 0xfde, 0xfdf, 0xfe0, 0xfe1, ++ 0xfe2, 0xfe3, 0xaf9, 0xfe4, 0xfe5, 0xfe6, 0xfe7, 0xfe8, ++ 0xfe9, 0xfea, 0xfeb, 0xfec, 0xde0, 0xfed, 0xfee, 0xfef, ++ 0xff0, 0xff1, 0xff2, 0xff3, 0xff4, 0xff5, 0xec3, 0xff6, ++ 0xff7, 0xff8, 0xff9, 0xffa, 0xffb, 0xffc, 0xffd, 0xffe, ++ 0x100, 0x9fa, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, ++ 0xfd0, 0xfd1, 0xfd2, 0xfd3, 0xfd4, 0xfd5, 0xfd6, 0xfd7, ++ 0x100, 0x202, 0x203, 0x204, 0x205, 0x206, 0x30e, 0x41e, ++ 0x53e, 0x67e, 0x7fe, 0x8fe, 0xfff, 0xfff, 0xfff, 0xfff, ++ 0x100, 0x101, 0x102, 0x206, 0x30e, 0x41e, 0x53e, 0x67e, ++ 0x7fe, 0x8fe, 0x9fe, 0xafe, 0xfff, 0xfff, 0xfff, 0xfff ++ } ++}; ++ ++static const uint32_t qmem[QTNUM][QMEM_LEN] = { ++ //normal quantization table ++ { ++ 0x0100, 0x0155, 0x0155, 0x0a49, 0x0155, 0x0b33, 0x0100, 0x0a49, ++ 0x0a49, 0x0a49, 0x09c7, 0x09c7, 0x0100, 0x00cd, 0x0955, 0x08cd, ++ 0x093b, 0x0955, 0x12e9, 0x12e9, 0x0955, 0x251f, 0x11c7, 0x11af, ++ 0x0911, 0x08cd, 0x1a35, 0x113b, 0x2421, 0x1111, 0x1a35, 0x113b, ++ 0x1a49, 0x1a49, 0x0880, 0x19c7, 0x10b2, 0x10d2, 0x0880, 0x10f1, ++ 0x10ba, 0x10ea, 0x1a49, 0x1a49, 0x10cd, 0x1095, 0x231f, 0x10ba, ++ 0x1955, 0x229d, 0x193b, 0x193b, 0x193b, 0x2421, 0x10d2, 0x223f, ++ 0x2219, 0x2249, 0x10a4, 0x1911, 0x10b2, 0x2d05, 0x193b, 0x10a4, ++ 0x09c7, 0x09c7, 0x09c7, 0x0955, 0x12e9, 0x0955, 0x1155, 0x093b, ++ 0x093b, 0x1155, 0x10a4, 0x23e1, 0x1a49, 0x23e1, 0x10a4, 0x10a4, ++ 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, ++ 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, ++ 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, ++ 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, ++ 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, ++ 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 ++ }, ++ //finer quantization table ++ { ++ 0x0155, 0x0200, 0x0200, 0x0b33, 0x0200, 0x0200, 0x0155, 0x0b33, ++ 0x0b33, 0x0b33, 0x0155, 0x0155, 0x0155, 0x0155, 0x0100, 0x093b, ++ 0x09c7, 0x0100, 0x0a49, 0x0a49, 0x0100, 0x0911, 0x12e9, 0x0955, ++ 0x09c7, 0x093b, 0x11c7, 0x0080, 0x11af, 0x11af, 0x11c7, 0x0080, ++ 0x11c7, 0x08f1, 0x08cd, 0x08ba, 0x1a49, 0x1155, 0x08cd, 0x08c3, ++ 0x1a5f, 0x08c3, 0x08f1, 0x11c7, 0x251f, 0x23e1, 0x251f, 0x1a5f, ++ 0x1a35, 0x1111, 0x0880, 0x0880, 0x0880, 0x11af, 0x1155, 0x10ea, ++ 0x19bb, 0x10f1, 0x2421, 0x19bb, 0x1a49, 0x2421, 0x0880, 0x1111, ++ 0x0155, 0x0155, 0x0155, 0x0100, 0x0a49, 0x0100, 0x0911, 0x09c7, ++ 0x09c7, 0x0911, 0x1111, 0x08c3, 0x11c7, 0x08c3, 0x1111, 0x1111, ++ 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, ++ 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, ++ 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, ++ 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, ++ 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, ++ 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 ++ }, ++ //finer quantization table ++ { ++ 0x02ab, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x02ab, 0x0400, ++ 0x0400, 0x0400, 0x02ab, 0x02ab, 0x02ab, 0x02ab, 0x02ab, 0x0b33, ++ 0x0200, 0x02ab, 0x02ab, 0x02ab, 0x02ab, 0x0155, 0x0200, 0x0b33, ++ 0x0200, 0x0b33, 0x0a49, 0x0155, 0x0a49, 0x0a49, 0x0a49, 0x0155, ++ 0x0a49, 0x0155, 0x0a49, 0x0100, 0x00cd, 0x09c7, 0x0a49, 0x0100, ++ 0x00cd, 0x0100, 0x0155, 0x0a49, 0x09c7, 0x0955, 0x09c7, 0x00cd, ++ 0x00cd, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x0a49, 0x09c7, 0x0955, ++ 0x093b, 0x0955, 0x12e9, 0x093b, 0x00cd, 0x12e9, 0x12e9, 0x12e9, ++ 0x02ab, 0x02ab, 0x02ab, 0x02ab, 0x02ab, 0x02ab, 0x0155, 0x0200, ++ 0x0200, 0x0155, 0x12e9, 0x0100, 0x0a49, 0x0100, 0x12e9, 0x12e9, ++ 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, ++ 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, ++ 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, ++ 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, ++ 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, ++ 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 ++ } ++}; ++ ++#endif /* __INGENIC_JPEG_ENC_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-jpeg_jpeg-core.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-jpeg_jpeg-core.c.patch new file mode 100644 index 00000000..ea17563d --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-jpeg_jpeg-core.c.patch @@ -0,0 +1,1153 @@ +diff -drupN a/drivers/media/platform/ingenic-jpeg/jpeg-core.c b/drivers/media/platform/ingenic-jpeg/jpeg-core.c +--- a/drivers/media/platform/ingenic-jpeg/jpeg-core.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-jpeg/jpeg-core.c 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,1149 @@ ++/* ++ * ++ * Copyright (c) 2012 Ingenic Semiconductor Co., Ltd. ++ * http://www.ingenic.com/ ++ * ++ * Author: Gao Wei ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "jpeg-core.h" ++#include "jpeg-hw.h" ++#include "ingenic_jpeg_enc.h" ++ ++static struct ingenic_jpeg_fmt formats_enc[] = { ++ { ++ .name = "JPEG JFIF", ++ .fourcc = V4L2_PIX_FMT_JPEG, ++ .colplanes = 1, ++ .types = MEM2MEM_CAPTURE, ++ }, ++ { ++ .name = "YUV 4:2:2 packed, YCbYCr", ++ .fourcc = V4L2_PIX_FMT_YUYV, ++ .depth = 16, ++ .colplanes = 1, ++ .types = MEM2MEM_OUTPUT, ++ }, ++}; ++#define NUM_FORMATS_ENC ARRAY_SIZE(formats_enc) ++ ++static inline struct ingenic_jpeg_ctx *ctrl_to_ctx(struct v4l2_ctrl *c) ++{ ++ return container_of(c->handler, struct ingenic_jpeg_ctx, ctrl_handler); ++} ++ ++static inline struct ingenic_jpeg_ctx *fh_to_ctx(struct v4l2_fh *fh) ++{ ++ return container_of(fh, struct ingenic_jpeg_ctx, fh); ++} ++ ++/* ++ * ============================================================================ ++ * Device file operations ++ * ============================================================================ ++ */ ++ ++static int queue_init(void *priv, struct vb2_queue *src_vq, ++ struct vb2_queue *dst_vq); ++static struct ingenic_jpeg_fmt *ingenic_jpeg_find_format(unsigned int mode, ++ __u32 pixelformat); ++static int ingenic_jpeg_controls_create(struct ingenic_jpeg_ctx *ctx); ++ ++static int ingenic_jpeg_open(struct file *file) ++{ ++ struct ingenic_jpeg *jpeg = video_drvdata(file); ++ struct video_device *vfd = video_devdata(file); ++ struct ingenic_jpeg_ctx *ctx = NULL; ++ struct ingenic_jpeg_fmt *out_fmt; ++ int ret = 0; ++ ++ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); ++ if (!ctx) ++ return -ENOMEM; ++ ++ if (mutex_lock_interruptible(&jpeg->lock)) { ++ ret = -ERESTARTSYS; ++ goto free; ++ } ++ ++ ctx->desc_vidmem = dma_alloc_coherent(jpeg->dev, ++ DESC_SIZE_MAX, ++ &ctx->desc_phys, ++ GFP_KERNEL); ++ if (!ctx->desc_vidmem) { ++ ret = -ENOMEM; ++ goto dma_alloc_err; ++ } ++ ++ v4l2_fh_init(&ctx->fh, vfd); ++ /* Use separate control handler per file handle */ ++ ctx->fh.ctrl_handler = &ctx->ctrl_handler; ++ file->private_data = &ctx->fh; ++ v4l2_fh_add(&ctx->fh); ++ ++ ctx->jpeg = jpeg; ++ if (vfd == jpeg->vfd_encoder) { ++ ctx->mode = INGENIC_JPEG_ENCODE; ++ out_fmt = ingenic_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_YUYV); ++ } ++ ++ ret = ingenic_jpeg_controls_create(ctx); ++ if (ret < 0) ++ goto error; ++ ++ ctx->m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx, queue_init); ++ if (IS_ERR(ctx->m2m_ctx)) { ++ ret = PTR_ERR(ctx->m2m_ctx); ++ goto error; ++ } ++ ctx->fh.m2m_ctx = ctx->m2m_ctx; ++ ++ ctx->out_q.fmt = out_fmt; ++ ctx->cap_q.fmt = ingenic_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_YUYV); ++ ++ mutex_unlock(&jpeg->lock); ++ return 0; ++ ++error: ++ v4l2_fh_del(&ctx->fh); ++ v4l2_fh_exit(&ctx->fh); ++dma_alloc_err: ++ mutex_unlock(&jpeg->lock); ++free: ++ kfree(ctx); ++ return ret; ++} ++ ++static int ingenic_jpeg_release(struct file *file) ++{ ++ struct ingenic_jpeg *jpeg = video_drvdata(file); ++ struct ingenic_jpeg_ctx *ctx = fh_to_ctx(file->private_data); ++ ++ mutex_lock(&jpeg->lock); ++ v4l2_m2m_ctx_release(ctx->m2m_ctx); ++ mutex_unlock(&jpeg->lock); ++ v4l2_ctrl_handler_free(&ctx->ctrl_handler); ++ v4l2_fh_del(&ctx->fh); ++ v4l2_fh_exit(&ctx->fh); ++ dma_free_coherent(jpeg->dev, DESC_SIZE_MAX, ++ ctx->desc_vidmem, ctx->desc_phys); ++ kfree(ctx); ++ ++ return 0; ++} ++ ++static const struct v4l2_file_operations ingenic_jpeg_fops = { ++ .owner = THIS_MODULE, ++ .open = ingenic_jpeg_open, ++ .release = ingenic_jpeg_release, ++ .poll = v4l2_m2m_fop_poll, ++ .unlocked_ioctl = video_ioctl2, ++ .mmap = v4l2_m2m_fop_mmap, ++}; ++ ++/* ++ * ============================================================================ ++ * video ioctl operations ++ * ============================================================================ ++ */ ++ ++static int ingenic_jpeg_querycap(struct file *file, void *priv, ++ struct v4l2_capability *cap) ++{ ++ struct ingenic_jpeg_ctx *ctx = fh_to_ctx(priv); ++ ++ if (ctx->mode == INGENIC_JPEG_ENCODE) { ++ strlcpy(cap->driver, INGENIC_JPEG_M2M_NAME " encoder", ++ sizeof(cap->driver)); ++ strlcpy(cap->card, INGENIC_JPEG_M2M_NAME " encoder", ++ sizeof(cap->card)); ++ } ++ cap->bus_info[0] = 0; ++ /* ++ * This is only a mem-to-mem video device. The capture and output ++ * device capability flags are left only for backward compatibility ++ * and are scheduled for removal. ++ */ ++ cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M; ++ cap->capabilities = cap->device_caps | ++ V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT | ++ V4L2_CAP_DEVICE_CAPS; ++ return 0; ++} ++ ++static int enum_fmt(struct ingenic_jpeg_fmt *formats, int n, ++ struct v4l2_fmtdesc *f, u32 type) ++{ ++ int i, num = 0; ++ ++ for (i = 0; i < n; ++i) { ++ if (formats[i].types & type) { ++ /* index-th format of type type found ? */ ++ if (num == f->index) ++ break; ++ /* Correct type but haven't reached our index yet, ++ * just increment per-type index */ ++ ++num; ++ } ++ } ++ ++ /* Format not found */ ++ if (i >= n) ++ return -EINVAL; ++ ++ strlcpy(f->description, formats[i].name, sizeof(f->description)); ++ f->pixelformat = formats[i].fourcc; ++ ++ return 0; ++} ++ ++static int ingenic_jpeg_enum_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_fmtdesc *f) ++{ ++ struct ingenic_jpeg_ctx *ctx = fh_to_ctx(priv); ++ ++ if (ctx->mode == INGENIC_JPEG_ENCODE) ++ return enum_fmt(formats_enc, NUM_FORMATS_ENC, f, ++ MEM2MEM_CAPTURE); ++ return -1; ++} ++ ++static int ingenic_jpeg_enum_fmt_vid_out(struct file *file, void *priv, ++ struct v4l2_fmtdesc *f) ++{ ++ struct ingenic_jpeg_ctx *ctx = fh_to_ctx(priv); ++ ++ if (ctx->mode == INGENIC_JPEG_ENCODE) ++ return enum_fmt(formats_enc, NUM_FORMATS_ENC, f, ++ MEM2MEM_OUTPUT); ++ return -1; ++} ++ ++static struct ingenic_jpeg_q_data *get_q_data(struct ingenic_jpeg_ctx *ctx, ++ enum v4l2_buf_type type) ++{ ++ if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ++ return &ctx->out_q; ++ if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return &ctx->cap_q; ++ ++ return NULL; ++} ++ ++static int ingenic_jpeg_g_fmt(struct file *file, void *priv, struct v4l2_format *f) ++{ ++ struct vb2_queue *vq; ++ struct ingenic_jpeg_q_data *q_data = NULL; ++ struct v4l2_pix_format *pix = &f->fmt.pix; ++ struct ingenic_jpeg_ctx *ct = fh_to_ctx(priv); ++ ++ vq = v4l2_m2m_get_vq(ct->m2m_ctx, f->type); ++ if (!vq) ++ return -EINVAL; ++ ++ q_data = get_q_data(ct, f->type); ++ BUG_ON(q_data == NULL); ++ ++ pix->width = q_data->w; ++ pix->height = q_data->h; ++ pix->field = V4L2_FIELD_NONE; ++ pix->pixelformat = q_data->fmt->fourcc; ++ pix->bytesperline = 0; ++ if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG) { ++ u32 bpl = q_data->w; ++ if (q_data->fmt->colplanes == 1) ++ bpl = (bpl * q_data->fmt->depth) >> 3; ++ pix->bytesperline = bpl; ++ } ++ pix->sizeimage = q_data->size; ++ ++ return 0; ++} ++ ++static struct ingenic_jpeg_fmt *ingenic_jpeg_find_format(unsigned int mode, ++ u32 pixelformat) ++{ ++ unsigned int k; ++ struct ingenic_jpeg_fmt *formats; ++ int n; ++ ++ if (mode == INGENIC_JPEG_ENCODE) { ++ formats = formats_enc; ++ n = NUM_FORMATS_ENC; ++ } ++ ++ for (k = 0; k < n; k++) { ++ struct ingenic_jpeg_fmt *fmt = &formats[k]; ++ if (fmt->fourcc == pixelformat) ++ return fmt; ++ } ++ ++ return NULL; ++} ++ ++static void jpeg_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax, ++ unsigned int walign, ++ u32 *h, unsigned int hmin, unsigned int hmax, ++ unsigned int halign) ++{ ++ int width, height, w_step, h_step; ++ ++ width = *w; ++ height = *h; ++ ++ w_step = 1 << walign; ++ h_step = 1 << halign; ++ v4l_bound_align_image(w, wmin, wmax, walign, h, hmin, hmax, halign, 0); ++ ++ if (*w < width && (*w + w_step) < wmax) ++ *w += w_step; ++ if (*h < height && (*h + h_step) < hmax) ++ *h += h_step; ++} ++ ++static int vidioc_try_fmt(struct v4l2_format *f, struct ingenic_jpeg_fmt *fmt, ++ struct ingenic_jpeg_ctx *ctx, int q_type) ++{ ++ struct v4l2_pix_format *pix = &f->fmt.pix; ++ ++ if (pix->field == V4L2_FIELD_ANY) ++ pix->field = V4L2_FIELD_NONE; ++ else if (pix->field != V4L2_FIELD_NONE) ++ return -EINVAL; ++ ++ /* V4L2 specification suggests the driver corrects the format struct ++ * if any of the dimensions is unsupported */ ++ if (q_type == MEM2MEM_OUTPUT) ++ jpeg_bound_align_image(&pix->width, INGENIC_JPEG_MIN_WIDTH, ++ INGENIC_JPEG_MAX_WIDTH, 0, ++ &pix->height, INGENIC_JPEG_MIN_HEIGHT, ++ INGENIC_JPEG_MAX_HEIGHT, 0); ++ else ++ jpeg_bound_align_image(&pix->width, INGENIC_JPEG_MIN_WIDTH, ++ INGENIC_JPEG_MAX_WIDTH, fmt->h_align, ++ &pix->height, INGENIC_JPEG_MIN_HEIGHT, ++ INGENIC_JPEG_MAX_HEIGHT, fmt->v_align); ++ ++ if (fmt->fourcc == V4L2_PIX_FMT_JPEG) { ++ if (pix->sizeimage <= 0) ++ pix->sizeimage = (pix->width * pix->height * 16) >> 3; ++ pix->bytesperline = 0; ++ } else { ++ u32 bpl = pix->bytesperline; ++ ++ if (fmt->colplanes > 1 && bpl < pix->width) ++ bpl = pix->width; /* planar */ ++ ++ if (fmt->colplanes == 1 && /* packed */ ++ (bpl << 3) * fmt->depth < pix->width) ++ bpl = (pix->width * fmt->depth) >> 3; ++ ++ pix->bytesperline = bpl; ++ pix->sizeimage = (pix->width * pix->height * fmt->depth) >> 3; ++ } ++ ++ return 0; ++} ++ ++static int ingenic_jpeg_try_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct ingenic_jpeg_ctx *ctx = fh_to_ctx(priv); ++ struct ingenic_jpeg_fmt *fmt; ++ ++ fmt = ingenic_jpeg_find_format(ctx->mode, f->fmt.pix.pixelformat); ++ if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) { ++ v4l2_err(&ctx->jpeg->v4l2_dev, ++ "Fourcc format (0x%08x) invalid.\n", ++ f->fmt.pix.pixelformat); ++ return -EINVAL; ++ } ++ ++ return vidioc_try_fmt(f, fmt, ctx, MEM2MEM_CAPTURE); ++} ++ ++static int ingenic_jpeg_try_fmt_vid_out(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct ingenic_jpeg_ctx *ctx = fh_to_ctx(priv); ++ struct ingenic_jpeg_fmt *fmt; ++ ++ fmt = ingenic_jpeg_find_format(ctx->mode, f->fmt.pix.pixelformat); ++ if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) { ++ v4l2_err(&ctx->jpeg->v4l2_dev, ++ "Fourcc format (0x%08x) invalid.\n", ++ f->fmt.pix.pixelformat); ++ return -EINVAL; ++ } ++ ++ return vidioc_try_fmt(f, fmt, ctx, MEM2MEM_OUTPUT); ++} ++ ++static int ingenic_jpeg_s_fmt(struct ingenic_jpeg_ctx *ct, struct v4l2_format *f) ++{ ++ struct vb2_queue *vq; ++ struct ingenic_jpeg_q_data *q_data = NULL; ++ struct v4l2_pix_format *pix = &f->fmt.pix; ++ ++ vq = v4l2_m2m_get_vq(ct->m2m_ctx, f->type); ++ if (!vq) ++ return -EINVAL; ++ ++ q_data = get_q_data(ct, f->type); ++ BUG_ON(q_data == NULL); ++ ++ if (vb2_is_busy(vq)) { ++ v4l2_err(&ct->jpeg->v4l2_dev, "%s queue busy\n", __func__); ++ return -EBUSY; ++ } ++ ++ q_data->fmt = ingenic_jpeg_find_format(ct->mode, pix->pixelformat); ++ q_data->w = pix->width; ++ q_data->h = pix->height; ++ if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG) ++ q_data->size = q_data->w * q_data->h * q_data->fmt->depth >> 3; ++ else ++ q_data->size = pix->sizeimage; ++ ++ return 0; ++} ++ ++static int ingenic_jpeg_s_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ int ret; ++ ++ ret = ingenic_jpeg_try_fmt_vid_cap(file, priv, f); ++ if (ret) ++ return ret; ++ ++ return ingenic_jpeg_s_fmt(fh_to_ctx(priv), f); ++} ++ ++static int ingenic_jpeg_s_fmt_vid_out(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ int ret; ++ ++ ret = ingenic_jpeg_try_fmt_vid_out(file, priv, f); ++ if (ret) ++ return ret; ++ ++ return ingenic_jpeg_s_fmt(fh_to_ctx(priv), f); ++} ++ ++static int ingenic_jpeg_streamon(struct file *file, void *priv, ++ enum v4l2_buf_type type) ++{ ++ struct ingenic_jpeg_ctx *ctx = fh_to_ctx(priv); ++ struct ingenic_jpeg *jpeg = ctx->jpeg; ++ ++ clk_prepare_enable(jpeg->clk); ++ return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); ++} ++ ++static int ingenic_jpeg_streamoff(struct file *file, void *priv, ++ enum v4l2_buf_type type) ++{ ++ struct ingenic_jpeg_ctx *ctx = fh_to_ctx(priv); ++ struct ingenic_jpeg *jpeg = ctx->jpeg; ++ ++ clk_disable_unprepare(jpeg->clk); ++ return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); ++} ++ ++static int ingenic_jpeg_g_selection(struct file *file, void *priv, ++ struct v4l2_selection *s) ++{ ++ struct ingenic_jpeg_ctx *ctx = fh_to_ctx(priv); ++ ++ if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && ++ s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ ++ /* For JPEG blob active == default == bounds */ ++ switch (s->target) { ++ case V4L2_SEL_TGT_CROP: ++ case V4L2_SEL_TGT_CROP_BOUNDS: ++ case V4L2_SEL_TGT_CROP_DEFAULT: ++ case V4L2_SEL_TGT_COMPOSE: ++ case V4L2_SEL_TGT_COMPOSE_DEFAULT: ++ s->r.width = ctx->out_q.w; ++ s->r.height = ctx->out_q.h; ++ break; ++ case V4L2_SEL_TGT_COMPOSE_BOUNDS: ++ case V4L2_SEL_TGT_COMPOSE_PADDED: ++ s->r.width = ctx->cap_q.w; ++ s->r.height = ctx->cap_q.h; ++ break; ++ default: ++ return -EINVAL; ++ } ++ s->r.left = 0; ++ s->r.top = 0; ++ return 0; ++} ++ ++/* ++ * V4L2 controls ++ */ ++ ++static int ingenic_jpeg_g_volatile_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct ingenic_jpeg_ctx *ctx = ctrl_to_ctx(ctrl); ++ struct ingenic_jpeg *jpeg = ctx->jpeg; ++ unsigned long flags; ++ ++ switch (ctrl->id) { ++ case V4L2_CID_JPEG_COMPRESSION_QUALITY: ++ spin_lock_irqsave(&jpeg->slock, flags); ++ ctrl->val = ctx->compr_quality; ++ spin_unlock_irqrestore(&jpeg->slock, flags); ++ break; ++ } ++ ++ return 0; ++} ++ ++static int ingenic_jpeg_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct ingenic_jpeg_ctx *ctx = ctrl_to_ctx(ctrl); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ctx->jpeg->slock, flags); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_JPEG_COMPRESSION_QUALITY: ++ ctx->compr_quality = ctrl->val; ++ break; ++ default: ++ break; ++ } ++ ++ spin_unlock_irqrestore(&ctx->jpeg->slock, flags); ++ return 0; ++} ++ ++static const struct v4l2_ctrl_ops ingenic_jpeg_ctrl_ops = { ++ .g_volatile_ctrl = ingenic_jpeg_g_volatile_ctrl, ++ .s_ctrl = ingenic_jpeg_s_ctrl, ++}; ++ ++static int ingenic_jpeg_controls_create(struct ingenic_jpeg_ctx *ctx) ++{ ++ unsigned int mask = ~0x27; /* 444, 422, 420, GRAY */ ++ struct v4l2_ctrl *ctrl; ++ ++ v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3); ++ ++ if (ctx->mode == INGENIC_JPEG_ENCODE) { ++ v4l2_ctrl_new_std(&ctx->ctrl_handler, &ingenic_jpeg_ctrl_ops, ++ V4L2_CID_JPEG_COMPRESSION_QUALITY, ++ 0, 3, 1, 3); ++ ++ /* v4l2_ctrl_new_std(&ctx->ctrl_handler, &ingenic_jpeg_ctrl_ops, */ ++ /* V4L2_CID_JPEG_RESTART_INTERVAL, */ ++ /* 0, 3, 0xffff, 0); */ ++ mask = ~0x06; /* 422, 420 */ ++ } ++ ++ //XXX: didn't test. ++ ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &ingenic_jpeg_ctrl_ops, ++ V4L2_CID_JPEG_CHROMA_SUBSAMPLING, ++ V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY, mask, ++ V4L2_JPEG_CHROMA_SUBSAMPLING_422); ++ ++ if (ctx->ctrl_handler.error) ++ return ctx->ctrl_handler.error; ++ ++ return 0; ++} ++ ++static const struct v4l2_ioctl_ops ingenic_jpeg_ioctl_ops = { ++ .vidioc_querycap = ingenic_jpeg_querycap, ++ ++ .vidioc_enum_fmt_vid_cap = ingenic_jpeg_enum_fmt_vid_cap, ++ .vidioc_enum_fmt_vid_out = ingenic_jpeg_enum_fmt_vid_out, ++ ++ .vidioc_g_fmt_vid_cap = ingenic_jpeg_g_fmt, ++ .vidioc_g_fmt_vid_out = ingenic_jpeg_g_fmt, ++ ++ .vidioc_try_fmt_vid_cap = ingenic_jpeg_try_fmt_vid_cap, ++ .vidioc_try_fmt_vid_out = ingenic_jpeg_try_fmt_vid_out, ++ ++ .vidioc_s_fmt_vid_cap = ingenic_jpeg_s_fmt_vid_cap, ++ .vidioc_s_fmt_vid_out = ingenic_jpeg_s_fmt_vid_out, ++ ++ ++ .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, ++ .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, ++ .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, ++ .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, ++ ++ .vidioc_streamon = ingenic_jpeg_streamon, ++ .vidioc_streamoff = ingenic_jpeg_streamoff, ++ ++ .vidioc_g_selection = ingenic_jpeg_g_selection, ++}; ++ ++/* ++ * ============================================================================ ++ * mem2mem callbacks ++ * ============================================================================ ++ */ ++ ++static void JPEGE_SliceInit(JPEGE_SliceInfo *s) ++{ ++ unsigned int i; ++ volatile unsigned int *chn = (volatile unsigned int *)s->des_va; ++ ++ GEN_VDMA_ACFG(chn, TCSM_FLUSH, 0, 0x0); ++ ++ /* Open clock configuration */ ++ GEN_VDMA_ACFG(chn, REG_JPGC_GLBI, 0, OPEN_CLOCK); ++ ++ /** ++ * Huffman Encode Table configuration ++ */ ++ for(i = 0; i < HUFFENC_LEN; i++) ++ GEN_VDMA_ACFG(chn, REG_JPGC_HUFE+i*4, 0, huffenc[s->huffenc_sel][i]); ++ ++ /** ++ * Quantization Table configuration ++ */ ++ for(i = 0; i < QMEM_LEN; i++) ++ GEN_VDMA_ACFG(chn, REG_JPGC_QMEM+i*4, 0, qmem[s->ql_sel][i]); ++ ++ /** ++ * REGs configuration ++ */ ++ GEN_VDMA_ACFG(chn, REG_JPGC_STAT, 0,STAT_CLEAN); ++ GEN_VDMA_ACFG(chn,REG_JPGC_BSA, 0, (unsigned int)s->bsa); ++ GEN_VDMA_ACFG(chn, REG_JPGC_P0A, 0, VRAM_RAWY_BA); ++ ++ GEN_VDMA_ACFG(chn,REG_JPGC_NMCU, 0,s->nmcu); ++ GEN_VDMA_ACFG(chn,REG_JPGC_NRSM, 0,s->nrsm); ++ ++ GEN_VDMA_ACFG(chn,REG_JPGC_P0C, 0,YUV420P0C); ++ GEN_VDMA_ACFG(chn,REG_JPGC_P1C, 0,YUV420P1C); ++ GEN_VDMA_ACFG(chn,REG_JPGC_P2C, 0,YUV420P2C); ++ ++ GEN_VDMA_ACFG(chn, REG_JPGC_GLBI, 0, (YUV420PVH | ++ JPGC_NCOL | ++ JPGC_SPEC/* MODE */| ++ JPGC_EFE | ++ JPGC_EN)); ++ GEN_VDMA_ACFG(chn, REG_JPGC_TRIG, 0, \ ++ JPGC_BS_TRIG | JPGC_PP_TRIG | JPGC_CORE_OPEN); ++ /** ++ * EFE configuration ++ */ ++ GEN_VDMA_ACFG(chn, REG_EFE_GEOM, 0, (EFE_JPGC_LST_MBY(s->mb_height-1) | ++ EFE_JPGC_LST_MBX(s->mb_width-1))); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_RAWY_SBA, 0, s->raw[0]); ++ GEN_VDMA_ACFG(chn, REG_EFE_RAWU_SBA, 0, s->raw[1]); ++ GEN_VDMA_ACFG(chn, REG_EFE_RAWV_SBA, 0, s->raw[2]); ++ GEN_VDMA_ACFG(chn, REG_EFE_RAW_STRD, 0, (EFE_RAW_STRDY(s->stride[0]) | ++ EFE_RAW_STRDC(s->stride[1]))); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_RAW_DBA, 0, VRAM_RAWY_BA); ++ GEN_VDMA_ACFG(chn, REG_EFE_CTRL, VDMA_ACFG_TERM, (YUV_YUY2 | ++ EFE_PLANE_NV12 | ++ EFE_ID_JPEG | ++ EFE_EN | ++ (s->raw_format)| ++ EFE_RUN)); ++} ++ ++static void ingenic_jpeg_device_run(void *priv) ++{ ++ struct ingenic_jpeg_ctx *ctx = priv; ++ struct ingenic_jpeg *jpeg = ctx->jpeg; ++ JPEGE_SliceInfo vpu_s; ++ ++ jpeg_clear_stat(jpeg->regs); ++ if (jpeg_reset(jpeg->regs)) ++ dev_warn(jpeg->dev, "[%d:%d] wait stop ack timeout\n", ++ current->tgid, current->pid); ++ ++ jpeg_set_hiaxi(jpeg->regs); ++ jpeg_clear_int(jpeg->regs); ++ ++ { ++ int width = ctx->out_q.w; ++ int height = ctx->out_q.h; ++ ++ struct vb2_buffer *src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); ++ struct vb2_buffer *dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); ++ ++ vpu_s.des_va = (unsigned int)ctx->desc_vidmem; ++ vpu_s.des_pa = ctx->desc_phys; ++ ++ vpu_s.raw[0] = vb2_dma_contig_plane_dma_addr(src_buf, 0); ++ vpu_s.bsa = (uint8_t*)vb2_dma_contig_plane_dma_addr(dst_buf, 0); ++ ++ vpu_s.mb_width = width/16; ++ vpu_s.mb_height = height/16; ++ vpu_s.stride[0] = width * 2; ++ vpu_s.stride[1] = width; ++ vpu_s.nmcu = width * height / 256 - 1; ++ ++ vpu_s.nrsm = 0; ++ vpu_s.rsm = 0; ++ vpu_s.ncol = 2; /* yuv(3) - 1 */ ++ vpu_s.raw_format = JPGE_NV21_MODE; /* EFE working, RAW data is NV21 */ ++ ++ vpu_s.huffenc_sel = 0; ++ vpu_s.ql_sel = ctx->compr_quality; ++ } ++ ++ JPEGE_SliceInit(&vpu_s); ++ ++ jpeg_start(jpeg->regs, ctx->desc_phys); ++} ++ ++static int ingenic_jpeg_job_ready(void *priv) ++{ ++ return 1; ++} ++ ++static void ingenic_jpeg_job_abort(void *priv) ++{ ++} ++ ++static struct v4l2_m2m_ops ingenic_jpeg_m2m_ops = { ++ .device_run = ingenic_jpeg_device_run, ++ .job_ready = ingenic_jpeg_job_ready, ++ .job_abort = ingenic_jpeg_job_abort, ++}; ++ ++ ++/* ++ * ============================================================================ ++ * Queue operations ++ * ============================================================================ ++ */ ++ ++static int ingenic_jpeg_queue_setup(struct vb2_queue *vq, ++ const void *parg, ++ unsigned int *nbuffers, unsigned int *nplanes, ++ unsigned int sizes[], void *alloc_ctxs[]) ++{ ++ struct ingenic_jpeg_ctx *ctx = vb2_get_drv_priv(vq); ++ struct ingenic_jpeg_q_data *q_data = NULL; ++ unsigned int size, count = *nbuffers; ++ ++ q_data = get_q_data(ctx, vq->type); ++ BUG_ON(q_data == NULL); ++ ++ size = q_data->size; ++ ++ *nbuffers = count; ++ *nplanes = 1; ++ sizes[0] = size; ++ alloc_ctxs[0] = ctx->jpeg->alloc_ctx; ++ ++ return 0; ++} ++ ++static int ingenic_jpeg_buf_prepare(struct vb2_buffer *vb) ++{ ++ struct ingenic_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); ++ struct ingenic_jpeg_q_data *q_data = NULL; ++ ++ q_data = get_q_data(ctx, vb->vb2_queue->type); ++ BUG_ON(q_data == NULL); ++ ++ if (vb2_plane_size(vb, 0) < q_data->size) { ++ pr_err("%s data will not fit into plane (%lu < %lu)\n", ++ __func__, vb2_plane_size(vb, 0), ++ (long)q_data->size); ++ return -EINVAL; ++ } ++ ++ vb2_set_plane_payload(vb, 0, q_data->size); ++ ++ return 0; ++} ++ ++static void ingenic_jpeg_buf_queue(struct vb2_buffer *vb) ++{ ++ struct ingenic_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); ++ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); ++ ++ if (ctx->m2m_ctx) ++ v4l2_m2m_buf_queue(ctx->m2m_ctx, vbuf); ++} ++ ++static void ingenic_jpeg_wait_prepare(struct vb2_queue *vq) ++{ ++ struct ingenic_jpeg_ctx *ctx = vb2_get_drv_priv(vq); ++ ++ mutex_unlock(&ctx->jpeg->lock); ++} ++ ++static void ingenic_jpeg_wait_finish(struct vb2_queue *vq) ++{ ++ struct ingenic_jpeg_ctx *ctx = vb2_get_drv_priv(vq); ++ ++ mutex_lock(&ctx->jpeg->lock); ++} ++ ++static int ingenic_jpeg_start_streaming(struct vb2_queue *q, unsigned int count) ++{ ++ struct ingenic_jpeg_ctx *ctx = vb2_get_drv_priv(q); ++ int ret; ++ ++ ret = pm_runtime_get_sync(ctx->jpeg->dev); ++ ++ return ret > 0 ? 0 : ret; ++} ++ ++static void ingenic_jpeg_stop_streaming(struct vb2_queue *q) ++{ ++ struct ingenic_jpeg_ctx *ctx = vb2_get_drv_priv(q); ++ ++ pm_runtime_put(ctx->jpeg->dev); ++} ++ ++static struct vb2_ops ingenic_jpeg_qops = { ++ .queue_setup = ingenic_jpeg_queue_setup, ++ .buf_prepare = ingenic_jpeg_buf_prepare, ++ .buf_queue = ingenic_jpeg_buf_queue, ++ .wait_prepare = ingenic_jpeg_wait_prepare, ++ .wait_finish = ingenic_jpeg_wait_finish, ++ .start_streaming = ingenic_jpeg_start_streaming, ++ .stop_streaming = ingenic_jpeg_stop_streaming, ++}; ++ ++static int queue_init(void *priv, struct vb2_queue *src_vq, ++ struct vb2_queue *dst_vq) ++{ ++ struct ingenic_jpeg_ctx *ctx = priv; ++ int ret; ++ ++ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; ++ src_vq->io_modes = VB2_MMAP | VB2_USERPTR; ++ src_vq->drv_priv = ctx; ++ src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); ++ src_vq->ops = &ingenic_jpeg_qops; ++ src_vq->mem_ops = &vb2_dma_contig_memops; ++ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; ++ src_vq->lock = &ctx->jpeg->lock; ++ ++ ret = vb2_queue_init(src_vq); ++ if (ret) ++ return ret; ++ ++ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ dst_vq->io_modes = VB2_MMAP | VB2_USERPTR; ++ dst_vq->drv_priv = ctx; ++ dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); ++ dst_vq->ops = &ingenic_jpeg_qops; ++ dst_vq->mem_ops = &vb2_dma_contig_memops; ++ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; ++ dst_vq->lock = &ctx->jpeg->lock; ++ ++ return vb2_queue_init(dst_vq); ++} ++/* ++ * ============================================================================ ++ * ISR ++ * ============================================================================ ++ */ ++ ++static irqreturn_t ingenic_jpeg_irq(int irq, void *dev_id) ++{ ++ unsigned int sch_stat, aux_stat; ++ ++ struct ingenic_jpeg *jpeg = dev_id; ++ struct ingenic_jpeg_ctx *curr_ctx; ++ struct vb2_v4l2_buffer *src_buf, *dst_buf; ++ unsigned long payload_size = 0; ++ enum vb2_buffer_state state = VB2_BUF_STATE_DONE; ++ ++ spin_lock(&jpeg->slock); ++ ++ curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev); ++ if(unlikely(curr_ctx == NULL)) { ++ printk("JPEG:ctx == NULL, Dev stopped,interrupt come in.\n"); ++ spin_unlock(&jpeg->slock); ++ return IRQ_HANDLED; ++ } ++ ++ src_buf = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx); ++ if(unlikely(src_buf == NULL)) { ++ printk("JPEG:src_buf == NULL, Dev stopped,interrupt come in.\n"); ++ spin_unlock(&jpeg->slock); ++ return IRQ_HANDLED; ++ } ++ dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx); ++ if(unlikely(dst_buf == NULL)) { ++ printk("JPEG:dst_buf == NULL, Dev stopped,interrupt come in.\n"); ++ spin_unlock(&jpeg->slock); ++ return IRQ_HANDLED; ++ } ++ ++ sch_stat = jpeg_get_sch_stat(jpeg->regs); ++ ++ if(sch_stat) { ++ if(sch_stat & SCH_STAT_ENDF) { ++ if(sch_stat & SCH_STAT_JPGEND) { ++ payload_size = jpeg_compressed_size(jpeg->regs); ++ dev_dbg(jpeg->dev, "JPG successfully done!\n"); ++ CLEAR_REG_BIT(jpeg->regs,REG_JPGC_STAT,JPGC_STAT_ENDF); ++ } else { ++ dev_dbg(jpeg->dev, "SCH successfully done!\n"); ++ CLEAR_REG_BIT(jpeg->regs,REG_SDE_STAT,SDE_STAT_BSEND); ++ CLEAR_REG_BIT(jpeg->regs,REG_DBLK_STAT,DBLK_STAT_DOEND); ++ } ++ } else { ++ CHECK_SCH_STAT(SCH_STAT_SLDERR, "SHLD error!\n"); ++ CHECK_SCH_STAT(SCH_STAT_TLBERR, "TLB error! Addr is 0x%08x\n", ++ jpeg_get_sch_stat(jpeg->regs)); ++ CHECK_SCH_STAT(SCH_STAT_BSERR, "BS error!\n"); ++ CHECK_SCH_STAT(SCH_STAT_ACFGERR, "ACFG error!\n"); ++ CHECK_SCH_STAT(SCH_STAT_TIMEOUT, "TIMEOUT error!\n"); ++ CLEAR_REG_BIT(jpeg->regs,REG_SCH_GLBC, ++ (SCH_INTE_ACFGERR | SCH_INTE_TLBERR | ++ SCH_INTE_BSERR | SCH_INTE_ENDF)); ++ state = VB2_BUF_STATE_ERROR; ++ } ++ } else { ++ aux_stat = jpeg_get_aux_stat(jpeg->regs); ++ if(aux_stat & AUX_STAT_MIRQP) { ++ dev_dbg(jpeg->dev, "AUX successfully done!\n"); ++ CLEAR_REG_BIT(jpeg->regs,REG_AUX_STAT,AUX_STAT_MIRQP); ++ } else { ++ dev_dbg(jpeg->dev, "illegal interrupt happened!\n"); ++ } ++ } ++ ++ dst_buf->timecode = src_buf->timecode; ++ dst_buf->timestamp = src_buf->timestamp; ++ // XXX working bad! ++ /* dst_buf->v4l2_buf.length = payload_size; */ ++ ++ v4l2_m2m_buf_done(src_buf, state); ++ if (curr_ctx->mode == INGENIC_JPEG_ENCODE) ++ vb2_set_plane_payload(&dst_buf->vb2_buf, 0, payload_size); ++ ++ v4l2_m2m_buf_done(dst_buf, state); ++ v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->m2m_ctx); ++ ++ spin_unlock(&jpeg->slock); ++ ++ return IRQ_HANDLED; ++} ++/* ++ * ============================================================================ ++ * Driver basic infrastructure ++ * ============================================================================ ++ */ ++ ++static int ingenic_jpeg_probe(struct platform_device *pdev) ++{ ++ struct ingenic_jpeg *jpeg; ++ struct resource *res; ++ int ret; ++ ++ /* JPEG IP abstraction struct */ ++ jpeg = devm_kzalloc(&pdev->dev, sizeof(struct ingenic_jpeg), GFP_KERNEL); ++ if (!jpeg) ++ return -ENOMEM; ++ ++ mutex_init(&jpeg->lock); ++ spin_lock_init(&jpeg->slock); ++ jpeg->dev = &pdev->dev; ++ ++ /* memory-mapped registers */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ ++ jpeg->regs = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(jpeg->regs)) ++ return PTR_ERR(jpeg->regs); ++ ++ /* interrupt service routine registration */ ++ jpeg->irq = ret = platform_get_irq(pdev, 0); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "cannot find IRQ\n"); ++ return ret; ++ } ++ ++ ret = devm_request_irq(&pdev->dev, jpeg->irq, ingenic_jpeg_irq, 0, ++ dev_name(&pdev->dev), jpeg); ++ if (ret) { ++ dev_err(&pdev->dev, "cannot claim IRQ %d\n", jpeg->irq); ++ return ret; ++ } ++ ++ jpeg->clk = clk_get(&pdev->dev, "gate_jpeg"); ++ if (IS_ERR(jpeg->clk)) { ++ dev_err(&pdev->dev, "cannot get clock\n"); ++ ret = PTR_ERR(jpeg->clk); ++ return ret; ++ } ++ dev_dbg(&pdev->dev, "clock source %p\n", jpeg->clk); ++ ++ /* v4l2 device */ ++ ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev); ++ if (ret) { ++ dev_err(&pdev->dev, "Failed to register v4l2 device\n"); ++ goto clk_get_rollback; ++ } ++ ++ /* mem2mem device */ ++ jpeg->m2m_dev = v4l2_m2m_init(&ingenic_jpeg_m2m_ops); ++ if (IS_ERR(jpeg->m2m_dev)) { ++ v4l2_err(&jpeg->v4l2_dev, "Failed to init mem2mem device\n"); ++ ret = PTR_ERR(jpeg->m2m_dev); ++ goto device_register_rollback; ++ } ++ ++ jpeg->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); ++ if (IS_ERR(jpeg->alloc_ctx)) { ++ v4l2_err(&jpeg->v4l2_dev, "Failed to init memory allocator\n"); ++ ret = PTR_ERR(jpeg->alloc_ctx); ++ goto m2m_init_rollback; ++ } ++ ++ /* JPEG encoder /dev/videoX node */ ++ jpeg->vfd_encoder = video_device_alloc(); ++ if (!jpeg->vfd_encoder) { ++ v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n"); ++ ret = -ENOMEM; ++ goto vb2_allocator_rollback; ++ } ++ strlcpy(jpeg->vfd_encoder->name, INGENIC_JPEG_M2M_NAME, ++ sizeof(jpeg->vfd_encoder->name)); ++ jpeg->vfd_encoder->fops = &ingenic_jpeg_fops; ++ jpeg->vfd_encoder->ioctl_ops = &ingenic_jpeg_ioctl_ops; ++ jpeg->vfd_encoder->minor = -1; ++ jpeg->vfd_encoder->release = video_device_release; ++ jpeg->vfd_encoder->lock = &jpeg->lock; ++ jpeg->vfd_encoder->v4l2_dev = &jpeg->v4l2_dev; ++ jpeg->vfd_encoder->vfl_dir = VFL_DIR_M2M; ++ ++ ret = video_register_device(jpeg->vfd_encoder, VFL_TYPE_GRABBER, -1); ++ if (ret) { ++ v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n"); ++ goto enc_vdev_alloc_rollback; ++ } ++ ++ video_set_drvdata(jpeg->vfd_encoder, jpeg); ++ v4l2_info(&jpeg->v4l2_dev, ++ "encoder device registered as /dev/video%d\n", ++ jpeg->vfd_encoder->num); ++ ++ /* final statements & power management */ ++ platform_set_drvdata(pdev, jpeg); ++ ++ pm_runtime_enable(&pdev->dev); ++ ++ v4l2_info(&jpeg->v4l2_dev, "Ingenic INGENIC JPEG codec\n"); ++ ++ return 0; ++ ++enc_vdev_alloc_rollback: ++ video_device_release(jpeg->vfd_encoder); ++ ++vb2_allocator_rollback: ++ vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx); ++ ++m2m_init_rollback: ++ v4l2_m2m_release(jpeg->m2m_dev); ++ ++device_register_rollback: ++ v4l2_device_unregister(&jpeg->v4l2_dev); ++ ++clk_get_rollback: ++ clk_put(jpeg->clk); ++ ++ return ret; ++} ++ ++static int ingenic_jpeg_remove(struct platform_device *pdev) ++{ ++ struct ingenic_jpeg *jpeg = platform_get_drvdata(pdev); ++ ++ pm_runtime_disable(jpeg->dev); ++ ++ video_unregister_device(jpeg->vfd_encoder); ++ video_device_release(jpeg->vfd_encoder); ++ vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx); ++ v4l2_m2m_release(jpeg->m2m_dev); ++ v4l2_device_unregister(&jpeg->v4l2_dev); ++ ++ clk_put(jpeg->clk); ++ ++ return 0; ++} ++ ++static int ingenic_jpeg_runtime_suspend(struct device *dev) ++{ ++ // TODO ++ return 0; ++} ++ ++static int ingenic_jpeg_runtime_resume(struct device *dev) ++{ ++ // TODO ++ return 0; ++} ++ ++static const struct dev_pm_ops ingenic_jpeg_pm_ops = { ++ .runtime_suspend = ingenic_jpeg_runtime_suspend, ++ .runtime_resume = ingenic_jpeg_runtime_resume, ++}; ++ ++static const struct of_device_id ingenic_jpeg_match[] = { ++ { ++ .compatible = "ingenic,x1000-jpeg", ++ .data = NULL, ++ }, ++ { ++ .compatible = "ingenic,x2000-jpeg", ++ .data = NULL, ++ }, ++}; ++ ++MODULE_DEVICE_TABLE(of, ingenic_jpeg_match); ++ ++static struct platform_driver ingenic_jpeg_driver = { ++ .probe = ingenic_jpeg_probe, ++ .remove = ingenic_jpeg_remove, ++ .driver = { ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(ingenic_jpeg_match), ++ .name = INGENIC_JPEG_M2M_NAME, ++ .pm = &ingenic_jpeg_pm_ops, ++ }, ++}; ++ ++module_platform_driver(ingenic_jpeg_driver); ++ ++MODULE_DESCRIPTION("Ingenic JPEG codec driver"); ++MODULE_LICENSE("GPL"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-jpeg_jpeg-core.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-jpeg_jpeg-core.h.patch new file mode 100644 index 00000000..6f012b76 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-jpeg_jpeg-core.h.patch @@ -0,0 +1,178 @@ +diff -drupN a/drivers/media/platform/ingenic-jpeg/jpeg-core.h b/drivers/media/platform/ingenic-jpeg/jpeg-core.h +--- a/drivers/media/platform/ingenic-jpeg/jpeg-core.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-jpeg/jpeg-core.h 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,174 @@ ++/* ++ * ++ * Copyright (c) 2012 Ingenic Semiconductor Co., Ltd. ++ * http://www.ingenic.com/ ++ * ++ * Author: Gao Wei ++ * ++ * 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. ++ */ ++ ++#ifndef JPEG_CORE_H_ ++#define JPEG_CORE_H_ ++ ++/*#include */ ++#include ++#include ++#include ++#include ++ ++#define INGENIC_JPEG_M2M_NAME "jz-vpu" ++ ++/* a selection of JPEG markers */ ++#define TEM 0x01 ++#define SOF0 0xc0 ++#define RST 0xd0 ++#define SOI 0xd8 ++#define EOI 0xd9 ++#define DHP 0xde ++ ++/* Flags that indicate a format can be used for capture/output */ ++#define MEM2MEM_CAPTURE (1 << 0) ++#define MEM2MEM_OUTPUT (1 << 1) ++ ++/** ++ * struct ingenic_jpeg - JPEG IP abstraction ++ * @lock: the mutex protecting this structure ++ * @slock: spinlock protecting the device contexts ++ * @v4l2_dev: v4l2 device for mem2mem mode ++ * @vfd_encoder: video device node for encoder mem2mem mode ++ * @vfd_decoder: video device node for decoder mem2mem mode ++ * @m2m_dev: v4l2 mem2mem device data ++ * @regs: JPEG IP registers mapping ++ * @irq: JPEG IP irq ++ * @clk: JPEG IP clock ++ * @dev: JPEG IP struct device ++ * @alloc_ctx: videobuf2 memory allocator's context ++ */ ++struct ingenic_jpeg { ++ struct mutex lock; ++ /*struct wake_lock wake_lock;*/ ++ spinlock_t slock; ++ ++ struct v4l2_device v4l2_dev; ++ struct video_device *vfd_encoder; ++ struct v4l2_m2m_dev *m2m_dev; ++ ++ void __iomem *regs; ++ unsigned int irq; ++ struct clk *clk; ++ struct device *dev; ++ void *alloc_ctx; ++}; ++ ++/** ++ * struct jpeg_fmt - driver's internal color format data ++ * @name: format descritpion ++ * @fourcc: the fourcc code, 0 if not applicable ++ * @depth: number of bits per pixel ++ * @colplanes: number of color planes (1 for packed formats) ++ * @h_align: horizontal alignment order (align to 2^h_align) ++ * @v_align: vertical alignment order (align to 2^v_align) ++ * @types: types of queue this format is applicable to ++ */ ++struct ingenic_jpeg_fmt { ++ char *name; ++ u32 fourcc; ++ int depth; ++ int colplanes; ++ int h_align; ++ int v_align; ++ u32 types; ++}; ++ ++/** ++ * ingenic_jpeg_q_data - parameters of one queue ++ * @fmt: driver-specific format of this queue ++ * @w: image width ++ * @h: image height ++ * @size: image buffer size in bytes ++ */ ++struct ingenic_jpeg_q_data { ++ struct ingenic_jpeg_fmt *fmt; ++ u32 w; ++ u32 h; ++ u32 size; ++}; ++ ++/** ++ * ingenic_jpeg_ctx - the device context data ++ * @jpeg: JPEG IP device for this context ++ * @mode: compression (encode) operation or decompression (decode) ++ * @compr_quality: destination image quality in compression (encode) mode ++ * @m2m_ctx: mem2mem device context ++ * @out_q: source (output) queue information ++ * @cap_fmt: destination (capture) queue queue information ++ * @hdr_parsed: set if header has been parsed during decompression ++ * @ctrl_handler: controls handler ++ */ ++struct ingenic_jpeg_ctx { ++ struct ingenic_jpeg *jpeg; ++ unsigned int mode; ++ unsigned short compr_quality; ++ unsigned short restart_interval; ++ unsigned short subsampling; ++ struct v4l2_m2m_ctx *m2m_ctx; ++ struct ingenic_jpeg_q_data out_q; ++ struct ingenic_jpeg_q_data cap_q; ++ struct v4l2_fh fh; ++ bool hdr_parsed; ++ struct v4l2_ctrl_handler ctrl_handler; ++ ++ void *desc_vidmem; ++ dma_addr_t desc_phys; ++}; ++ ++/** ++ * ingenic_jpeg_buffer - description of memory containing input JPEG data ++ * @size: buffer size ++ * @curr: current position in the buffer ++ * @data: pointer to the data ++ */ ++struct ingenic_jpeg_buffer { ++ unsigned long size; ++ unsigned long curr; ++ unsigned long data; ++}; ++ ++/* JPEG encode quantization table select level */ ++typedef enum { ++ LOW_QUALITY, ++ MEDIUMS_QUALITY, ++ HIGH_QUALITY, ++} QUANT_QUALITY; ++ ++typedef struct _JPEGE_SliceInfo { ++ unsigned int des_va; /* descriptor virtual address */ ++ unsigned int des_pa; /* descriptor physical address */ ++ uint8_t ncol; /* number of color/components of a MCU minus one */ ++ uint8_t rsm; /* Re-sync-marker enable */ ++ uint8_t *bsa; /* bitstream buffer address */ ++ uint8_t nrsm; /* Re-Sync-Marker gap number */ ++ uint32_t nmcu; /* number of MCU minus one */ ++ uint32_t raw[3]; /* {rawy, rawu, rawv} or {rawy, rawc, N/C} */ ++ uint32_t stride[2]; /* {stride_y, stride_c}, only used in raster raw */ ++ uint32_t mb_width; ++ uint32_t mb_height; ++ uint8_t raw_format; ++ ++ /* Quantization level select,0-2 level */ ++ QUANT_QUALITY ql_sel; ++ uint8_t huffenc_sel; /* Huffman ENC Table select */ ++}JPEGE_SliceInfo; ++ ++/*The actual size required is 5000-6000*/ ++#define DESC_SIZE_MAX 8192 ++ ++#define JPGE_TILE_MODE 0 ++#define JPGE_NV12_MODE 8 ++#define JPGE_NV21_MODE 12 ++ ++ ++#endif /* JPEG_CORE_H */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-jpeg_jpeg-hw.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-jpeg_jpeg-hw.h.patch new file mode 100644 index 00000000..ff52ce69 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-jpeg_jpeg-hw.h.patch @@ -0,0 +1,189 @@ +diff -drupN a/drivers/media/platform/ingenic-jpeg/jpeg-hw.h b/drivers/media/platform/ingenic-jpeg/jpeg-hw.h +--- a/drivers/media/platform/ingenic-jpeg/jpeg-hw.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-jpeg/jpeg-hw.h 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,185 @@ ++/* ++ * ++ * Copyright (c) 2012 Ingenic Semiconductor Co., Ltd. ++ * http://www.ingenic.com/ ++ * ++ * Author: Gao Wei ++ * ++ * 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. ++ */ ++ ++#ifndef JPEG_HW_H_ ++#define JPEG_HW_H_ ++#include ++#include ++#include ++/*#include */ ++#include ++#include ++/* #include */ ++ ++#include ++#include ++#include ++#include ++ ++#include "jpeg-regs.h" ++ ++#define INGENIC_JPEG_MIN_WIDTH 32 ++#define INGENIC_JPEG_MIN_HEIGHT 32 ++#define INGENIC_JPEG_MAX_WIDTH 8192 ++#define INGENIC_JPEG_MAX_HEIGHT 8192 ++#define INGENIC_JPEG_ENCODE 0 ++#define INGENIC_JPEG_RAW_IN_565 0 ++#define INGENIC_JPEG_RAW_IN_422 1 ++#define INGENIC_JPEG_RAW_OUT_422 0 ++#define INGENIC_JPEG_RAW_OUT_420 1 ++ ++#define vpu_readl(vpu, offset) __raw_readl((vpu)->iomem + offset) ++#define vpu_writel(vpu, offset, value) __raw_writel((value), (vpu)->iomem + offset) ++ ++#define CLEAR_REG_BIT(regs,offset,bm) \ ++ do { \ ++ unsigned int stat; \ ++ stat = readl(regs + offset); \ ++ writel(stat & ~(bm), regs + offset); \ ++ } while(0) ++ ++#define CHECK_SCH_STAT(STAT, fmt, args...) do { \ ++ if(sch_stat & STAT) \ ++ dev_err(jpeg->dev, fmt, ##args); \ ++ }while(0) ++ ++static inline void cpm_writel(unsigned int val, unsigned int off) ++{ ++ writel(val, (void __iomem *)0xb0000000 + off); ++} ++ ++static inline unsigned int cpm_readl(unsigned int off) ++{ ++ return readl((void __iomem *)0xb0000000 + off); ++} ++ ++static int inline jpeg_reset(void __iomem *regs) ++{ ++ int timeout = 0xffffff; ++ unsigned int srbc = cpm_readl(CPM_SRBC); ++ ++ cpm_writel(srbc | (1 << 30), CPM_SRBC); ++ while (!(cpm_readl(CPM_SRBC) & (1 << 29)) && --timeout); ++ ++ if (timeout == 0) { ++ cpm_writel(srbc, CPM_SRBC); ++ return -1; ++ } else { ++ cpm_writel(srbc | (1 << 31), CPM_SRBC); ++ cpm_writel(srbc, CPM_SRBC); ++ } ++ ++ return 0; ++} ++ ++#if 0 ++static inline int jpeg_poweron(struct x1000_jpeg *jpeg) ++{ ++ if (cpm_readl(CPM_OPCR) & OPCR_IDLE) ++ return -EBUSY; ++ ++ clk_enable(jpeg->clk); ++ __asm__ __volatile__ ( ++ "mfc0 $2, $16, 7 \n\t" ++ "ori $2, $2, 0x340 \n\t" ++ "andi $2, $2, 0x3ff \n\t" ++ "mtc0 $2, $16, 7 \n\t" ++ "nop \n\t"); ++ jpeg_reset(jpeg->regs); ++ enable_irq(jpeg->irq); ++ wake_lock(&jpeg->wake_lock); ++ dev_dbg(jpeg->dev, "[%d:%d] on\n", current->tgid, current->pid); ++ ++ return 0; ++} ++ ++static long jpeg_off(struct x1000_jpeg *jpeg) ++{ ++ disable_irq_nosync(jpeg->irq); ++ ++ __asm__ __volatile__ ( ++ "mfc0 $2, $16, 7 \n\t" ++ "andi $2, $2, 0xbf \n\t" ++ "mtc0 $2, $16, 7 \n\t" ++ "nop \n\t"); ++ ++ cpm_clear_bit(31,CPM_OPCR); ++ clk_disable(jpeg->clk); ++ /* Clear completion use_count here to avoid a unhandled irq after vpu off */ ++ wake_unlock(&jpeg->wake_lock); ++ dev_dbg(jpeg->dev, "[%d:%d] off\n", current->tgid, current->pid); ++ ++ return 0; ++} ++#endif ++#if 0 ++static inline void jpeg_input_raw_mode(void __iomem *regs, unsigned long mode) ++{ ++} ++ ++static inline void jpeg_proc_mode(void __iomem *regs, unsigned long mode) ++{ ++} ++ ++static inline void jpeg_subsampling_mode(void __iomem *regs, unsigned int mode) ++{ ++} ++ ++static inline unsigned int jpeg_get_subsampling_mode(void __iomem *regs) ++{ ++} ++#endif ++ ++static inline void jpeg_start(void __iomem *regs, unsigned int desc_phys) ++{ ++ writel(desc_phys | VDMA_ACFG_RUN, regs + REG_VMDA_TRIG); ++} ++ ++static inline unsigned int jpeg_get_sch_stat(void __iomem *regs) ++{ ++ return readl(regs + REG_SCH_STAT); ++} ++ ++static inline unsigned int jpeg_get_aux_stat(void __iomem *regs) ++{ ++ return readl(regs + REG_AUX_STAT); ++} ++ ++static inline void jpeg_set_hiaxi(void __iomem *regs) ++{ ++ writel(SCH_GLBC_HIAXI, regs + REG_SCH_GLBC); ++} ++ ++static inline void jpeg_clear_stat(void __iomem *regs) ++{ ++ writel(0, regs + REG_JPGC_STAT); ++} ++static inline void jpeg_clear_int(void __iomem *regs) ++{ ++ unsigned long reg; ++ ++ reg = readl(regs + REG_SCH_GLBC); ++ writel(reg | SCH_INTE_ACFGERR | SCH_INTE_TLBERR ++ | SCH_INTE_BSERR | SCH_INTE_ENDF, regs + REG_SCH_GLBC); ++} ++ ++static inline unsigned int jpeg_compressed_size(void __iomem *regs) ++{ ++ unsigned long reg, jpeg_size = 0; ++ ++ reg = readl(regs + REG_JPGC_STAT); ++ jpeg_size = reg & 0xffffff; ++ ++ return (unsigned int)jpeg_size; ++} ++ ++#endif /* JPEG_HW_H_ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-jpeg_jpeg-regs.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-jpeg_jpeg-regs.h.patch new file mode 100644 index 00000000..5bba8b38 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-jpeg_jpeg-regs.h.patch @@ -0,0 +1,293 @@ +diff -drupN a/drivers/media/platform/ingenic-jpeg/jpeg-regs.h b/drivers/media/platform/ingenic-jpeg/jpeg-regs.h +--- a/drivers/media/platform/ingenic-jpeg/jpeg-regs.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-jpeg/jpeg-regs.h 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,289 @@ ++/* ++ * ++ * Register definition file for Ingenic JPEG codec driver ++ * ++ * Copyright (c) 2012 Ingenic Semiconductor Co., Ltd. ++ * http://www.ingenic.com/ ++ * ++ * Author: Gao Wei ++ * ++ * 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. ++ */ ++ ++#ifndef JPEG_REGS_H_ ++#define JPEG_REGS_H_ ++ ++#define DEVICES_VPU_NAME "/dev/ingenic-vpu" ++ ++#define VPU_BASE 0x13200000 ++#define VPU_SIZE 0x000FFFFF ++#define CPM_BASE 0x10000000 ++#define CPM_SIZE 0x00001000 ++/******************************************** ++ CPM (CPM) ++*********************************************/ ++#define REG_CPM_SRBC 0xC4 ++#define CPM_VPU_SR (0x1<<31) ++#define CPM_VPU_STP (0x1<<30) ++#define CPM_VPU_ACK (0x1<<29) ++ ++/******************************************** ++ SCH (Scheduler) ++*********************************************/ ++#define TCSM_FLUSH 0xc0000 ++#define REG_SCH_GLBC 0x00000 ++#define SCH_GLBC_SLDE (0x1<<31) ++#ifdef INGENIC_V2_TLB ++# define SCH_TLBE_JPGC (0x1<<26) ++# define SCH_TLBE_DBLK (0x1<<25) ++# define SCH_TLBE_SDE (0x1<<24) ++# define SCH_TLBE_EFE (0x1<<23) ++# define SCH_TLBE_VDMA (0x1<<22) ++# define SCH_TLBE_MCE (0x1<<21) ++#else ++# define SCH_GLBC_TLBE (0x1<<30) ++# define SCH_GLBC_TLBINV (0x1<<29) ++#endif ++#define SCH_INTE_ACFGERR (0x1<<20) ++#define SCH_INTE_TLBERR (0x1<<18) ++#define SCH_INTE_BSERR (0x1<<17) ++#define SCH_INTE_ENDF (0x1<<16) ++#define SCH_GLBC_HIMAP (0x1<<15) ++#define SCH_GLBC_HIAXI (0x1<<9) ++#define SCH_GLBC_EPRI0 (0x0<<7) ++#define SCH_GLBC_EPRI1 (0x1<<7) ++#define SCH_GLBC_EPRI2 (0x2<<7) ++#define SCH_GLBC_EPRI3 (0x3<<7) ++ ++#define REG_SCH_TLBA 0x00030 ++ ++#ifdef INGENIC_V2_TLB ++# define REG_SCH_TLBC 0x00050 ++# define SCH_TLBC_VPN (0xFFFFF000) ++# define SCH_TLBC_RIDX(idx) (((idx) & 0xFF)<<4) ++# define SCH_TLBC_INVLD (0x1<<1) ++# define SCH_TLBC_RETRY (0x1<<0) ++ ++# define REG_SCH_TLBV 0x00054 ++# define SCH_TLBV_CNM(cnm) (((cnm) & 0xFFF)<<16) ++# define SCH_TLBV_GCN(gcn) (((gcn) & 0xFFF)<<0) ++# define SCH_TLBV_RCI_MC (0x1<<30) ++# define SCH_TLBV_RCI_EFE (0x1<<31) ++#endif ++ ++#define REG_SCH_STAT 0x00034 ++#define SCH_STAT_ENDF (0x1<<0) ++#define SCH_STAT_BPF (0x1<<1) ++#define SCH_STAT_ACFGERR (0x1<<2) ++#define SCH_STAT_TIMEOUT (0x1<<3) ++#define SCH_STAT_JPGEND (0x1<<4) ++#define SCH_STAT_BSERR (0x1<<7) ++#define SCH_STAT_TLBERR (0x1F<<10) ++#define SCH_STAT_SLDERR (0x1<<16) ++ ++ ++ ++ ++ ++#define REG_SCH_SLDE0 0x00040 ++#define REG_SCH_SLDE1 0x00044 ++#define REG_SCH_SLDE2 0x00048 ++#define REG_SCH_SLDE3 0x0004C ++#define SCH_SLD_VTAG(val) (((val) & 0xFFF)<<20) ++#define SCH_SLD_MASK(val) (((val) & 0xFFF)<<8) ++#define SCH_SLD_VLD (0x1<<0) ++ ++#define REG_SCH_SCHC 0x00060 ++#define SCH_CH1_PCH(ch) (((ch) & 0x3)<<0) ++#define SCH_CH2_PCH(ch) (((ch) & 0x3)<<8) ++#define SCH_CH3_PCH(ch) (((ch) & 0x3)<<16) ++#define SCH_CH4_PCH(ch) (((ch) & 0x3)<<24) ++#define SCH_CH1_PE (0x1<<2) ++#define SCH_CH2_PE (0x1<<10) ++#define SCH_CH3_PE (0x1<<18) ++#define SCH_CH4_PE (0x1<<26) ++#define SCH_CH1_GS0 (0x0<<3) ++#define SCH_CH1_GS1 (0x1<<3) ++#define SCH_CH2_GS0 (0x0<<11) ++#define SCH_CH2_GS1 (0x1<<11) ++#define SCH_CH3_GS0 (0x0<<19) ++#define SCH_CH3_GS1 (0x1<<19) ++#define SCH_CH4_GS0 (0x0<<27) ++#define SCH_CH4_GS1 (0x1<<27) ++ ++#define REG_SCH_BND 0x00064 ++#define SCH_CH1_HID(hid) (((hid) & 0xF)<<16) ++#define SCH_CH2_HID(hid) (((hid) & 0xF)<<20) ++#define SCH_CH3_HID(hid) (((hid) & 0xF)<<24) ++#define SCH_CH4_HID(hid) (((hid) & 0xF)<<28) ++#define SCH_BND_G0F1 (0x1<<0) ++#define SCH_BND_G0F2 (0x1<<1) ++#define SCH_BND_G0F3 (0x1<<2) ++#define SCH_BND_G0F4 (0x1<<3) ++#define SCH_BND_G1F1 (0x1<<4) ++#define SCH_BND_G1F2 (0x1<<5) ++#define SCH_BND_G1F3 (0x1<<6) ++#define SCH_BND_G1F4 (0x1<<7) ++#define SCH_DEPTH(val) (((val-1) & 0xF)<<8) ++ ++#define REG_SCH_SCHG0 0x00068 ++#define REG_SCH_SCHG1 0x0006C ++#define REG_SCH_SCHE1 0x00070 ++#define REG_SCH_SCHE2 0x00074 ++#define REG_SCH_SCHE3 0x00078 ++#define REG_SCH_SCHE4 0x0007C ++ ++#define DSA_SCH_CH1 (VPU_BASE | REG_SCH_SCHE1) ++#define DSA_SCH_CH2 (VPU_BASE | REG_SCH_SCHE2) ++#define DSA_SCH_CH3 (VPU_BASE | REG_SCH_SCHE3) ++#define DSA_SCH_CH4 (VPU_BASE | REG_SCH_SCHE4) ++/******************************************** ++ VDMA (VPU general-purpose DMA) ++*********************************************/ ++#define REG_VDMA_LOCK 0x10000 ++#define REG_VDMA_UNLK 0x10004 ++#define REG_VMDA_TRIG 0x10008 ++#define VDMA_ACFG_RUN (0x1) ++#define VDMA_DESC_RUN (0x3) ++#define VDMA_ACFG_CLR (0x8) ++#define VDMA_ACFG_SAFE (0x4) ++#define VDMA_ACFG_DHA(a) (((unsigned int)(a)) & 0xFFFFFF80) ++#define VDMA_DESC_DHA(a) (((unsigned int)(a)) & 0xFFFF0) ++ ++#define REG_VDMA_TASKST 0x1000C ++#define VDMA_ACFG_ERR (0x1<<3) ++#define VDMA_ACFG_END (0x1<<2) ++#define VDMA_DESC_END (0x1<<1) ++#define VDMA_VPU_BUSY (0x1<<0) ++ ++#define VDMA_DESC_EXTSEL (0x1<<0) ++#define VDMA_DESC_TLBSEL (0x1<<1) ++#define VDMA_DESC_LK (0x1<<31) ++ ++#define VDMA_ACFG_VLD (0x1<<31) ++#define VDMA_ACFG_TERM (0x1<<30) ++#define VDMA_ACFG_IDX(a) (((unsigned int)(a)) & 0xFFFFC) ++ ++#define GEN_VDMA_ACFG(chn, reg, lk, val) \ ++({*chn++ = val; \ ++ *chn++ = (VDMA_ACFG_VLD | (lk) | VDMA_ACFG_IDX(reg)); \ ++}) ++ ++/**************************************************************** ++ JPGC (jpeg codec) ++*****************************************************************/ ++#define REG_JPGC_TRIG 0xE0000 ++#define REG_JPGC_GLBI 0xE0004 ++#define REG_JPGC_STAT 0xE0008 ++#define JPGC_STAT_ENDF (0x1<<31) ++#define REG_JPGC_BSA 0xE000C ++#define REG_JPGC_P0A 0xE0010 ++#define REG_JPGC_P1A 0xE0014 ++#define REG_JPGC_P2A 0xE0018 ++#define REG_JPGC_P3A 0xE001C ++#define REG_JPGC_NMCU 0xE0028 ++#define REG_JPGC_NRSM 0xE002C ++#define REG_JPGC_P0C 0xE0030 ++#define REG_JPGC_P1C 0xE0034 ++#define REG_JPGC_P2C 0xE0038 ++#define REG_JPGC_P3C 0xE003C ++#define REG_JPGC_MCUS 0xE0064 ++#define REG_JPGC_ZIGM0 0xE1000 ++#define REG_JPGC_ZIGM1 0xE1100 ++#define REG_JPGC_HUFB 0xE1200 ++#define REG_JPGC_HUFM 0xE1300 ++#define REG_JPGC_QMEM 0xE1400 ++#define REG_JPGC_HUFE 0xE1800 ++#define REG_JPGC_HUFS 0xE1800 ++ ++#define JPGC_CORE_OPEN (0x1<<0) ++#define JPGC_BS_TRIG (0x1<<1) ++#define JPGC_PP_TRIG (0x1<<2) ++#define JPGC_TERM (0x1<<3) ++#define JPGC_RSTER_MD (0x1<<8) ++ ++ ++/******************************************** ++ EFE (Encoder Front End) ++*********************************************/ ++#define REG_EFE_CTRL 0x40000 ++#define EFE_TSE(en) (((en) & 0x1)<<31) ++#define EFE_FMVP(en) (((en) & 0x1)<<30) ++#define EFE_ID_X264 (0x0<<14) ++#define EFE_ID_JPEG (0x1<<14) ++#define EFE_ID_VP8 (0x2<<14) ++#define EFE_X264_QP(qp) (((qp) & 0x3F)<<8) ++#define EFE_VP8_QTB(qtb) (((qtb) & 0x7f)<<22) ++#define EFE_VP8_QIDX(qp) (((qp) & 0x3F)<<8) ++#define EFE_VP8_LF(lf) ((lf & 0x3F)<<16) ++#define EFE_DBLK_EN (0x1<<5) ++#define EFE_SLICE_TYPE(a) (((a) & 0x1)<<4) ++#define EFE_PLANE_TILE (0x0<<2) ++#define EFE_PLANE_420P (0x1<<2) ++#define EFE_PLANE_NV12 (0x2<<2) ++#define EFE_PLANE_NV21 (0x3<<2) ++#define EFE_EN (0x1<<1) ++#define EFE_RUN (0x1<<0) ++ ++#define REG_EFE_GEOM 0x40004 ++#define EFE_FST_MBY(mb) (((mb) & 0xFF)<<24) ++#define EFE_FST_MBX(mb) (((0/*FIXME*/) & 0xFF)<<16) ++#define EFE_LST_MBY(mb) (((mb) & 0xFF)<<8) ++#define EFE_LST_MBX(mb) (((mb) & 0xFF)<<0) ++#define EFE_JPGC_LST_MBY(mb) (((mb) & 0xFFFF)<<16) ++#define EFE_JPGC_LST_MBX(mb) ((mb) & 0xFFFF) ++ ++#define REG_EFE_COEF_BA 0x4000C ++#define REG_EFE_RAWY_SBA 0x40010 ++#define REG_EFE_RAWC_SBA 0x40014 ++#define REG_EFE_RAWU_SBA 0x40014 ++#define REG_EFE_TOPMV_BA 0x40018 ++#define REG_EFE_TOPPA_BA 0x4001C ++#define REG_EFE_MECHN_BA 0x40020 ++#define REG_EFE_MAUCHN_BA 0x40024 ++#define REG_EFE_DBLKCHN_BA 0x40028 ++#define REG_EFE_SDECHN_BA 0x4002C ++#define REG_EFE_RAW_DBA 0x40030 ++#define REG_EFE_RAWV_SBA 0x40034 ++ ++#define REG_EFE_ROI_MAX_QP 0x40040 ++#define REG_EFE_ROI_BASE_INFO0 0x40044 ++#define REG_EFE_ROI_BASE_INFO1 0x40048 ++#define REG_EFE_ROI_POS_INFO0 0x4004C ++#define REG_EFE_ROI_POS_INFO1 0x40050 ++#define REG_EFE_ROI_POS_INFO2 0x40054 ++#define REG_EFE_ROI_POS_INFO3 0x40058 ++#define REG_EFE_ROI_POS_INFO4 0x4005C ++#define REG_EFE_ROI_POS_INFO5 0x40060 ++#define REG_EFE_ROI_POS_INFO6 0x40064 ++#define REG_EFE_ROI_POS_INFO7 0x40068 ++#define REG_EFE_RAW_STRD 0x40038 ++#define EFE_RAW_STRDY(y) (((y) & 0xFFFF)<<16) ++#define EFE_RAW_STRDC(c) (((c) & 0xFFFF)<<0) ++ ++#define REG_EFE_DBG_INFO 0x4003C ++#define EFE_DBG_EN (0x1<<31) ++#define EFE_DBG_BP_MBX(x) (((x) & 0xFFF)<<0) ++#define EFE_DBG_BP_MBY(y) (((y) & 0xFFF)<<16) ++ ++#define REG_EFE_MVRP 0x40100 ++#define REG_EFE_SSAD 0x40108 ++#define REG_EFE_DCS 0x4010C ++#define EFE_DCS_CLR(th) (0x1<<(th & 0xF)) ++#define EFE_DCS_EN(en) (((en) & 0x1)<<16) ++#define EFE_DCS_RT(rt) (((rt) & 0xF)<<20) ++#define EFE_DCS_OTH(oth) (((oth) & 0xF)<<24) ++#define REG_EFE_STAT 0x40110 ++ ++#define REG_SDE_STAT 0x90000 ++#define SDE_STAT_BSEND (0x1<<1) ++ ++#define REG_DBLK_STAT 0x70070 ++#define DBLK_STAT_DOEND (0x1<<0) ++ ++#define REG_AUX_STAT 0xA0010 ++#define AUX_STAT_MIRQP (0x1<<0) ++ ++#endif /* JPEG_REGS_H_ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-rotate_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-rotate_Makefile.patch new file mode 100644 index 00000000..277fc250 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-rotate_Makefile.patch @@ -0,0 +1,5 @@ +diff -drupN a/drivers/media/platform/ingenic-rotate/Makefile b/drivers/media/platform/ingenic-rotate/Makefile +--- a/drivers/media/platform/ingenic-rotate/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-rotate/Makefile 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1 @@ ++obj-$(CONFIG_VIDEO_INGENIC_ROTATE) += rotate.o rotate-hw.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-rotate_rotate-hw.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-rotate_rotate-hw.c.patch new file mode 100644 index 00000000..eaf05fab --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-rotate_rotate-hw.c.patch @@ -0,0 +1,295 @@ +diff -drupN a/drivers/media/platform/ingenic-rotate/rotate-hw.c b/drivers/media/platform/ingenic-rotate/rotate-hw.c +--- a/drivers/media/platform/ingenic-rotate/rotate-hw.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-rotate/rotate-hw.c 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,291 @@ ++/* * drivers/media/platform/ingenic_rotate/rotate-hw.c ++ * ++ * Copyright (C) 2016 Ingenic Semiconductor Inc. ++ * ++ * Author:clwang ++ * ++ * 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. ++ */ ++ ++#include ++#include ++ ++#include "rotate.h" ++#include "rotate-regs.h" ++ ++void dump_rot_reg(struct ingenic_rot_dev *dev) ++{ ++ printk("-----------------rot_reg------------------\n"); ++ printk("ROT_FRM_CFG_ADDR: 0x%lx\n",reg_read(dev, ROT_FRM_CFG_ADDR)); ++ printk("ROT_FRM_SIZE: 0x%lx\n",reg_read(dev, ROT_FRM_SIZE)); ++ printk("ROT_GLB_CFG: 0x%lx\n",reg_read(dev, ROT_GLB_CFG)); ++ printk("ROT_CTRL: 0x%lx\n",reg_read(dev, ROT_CTRL)); ++ printk("ROT_ST: 0x%lx\n",reg_read(dev, ROT_ST)); ++ printk("ROT_CLR_ST: 0x%lx\n",reg_read(dev, ROT_CLR_ST)); ++ printk("ROT_INT_MASK: 0x%lx\n",reg_read(dev, ROT_INT_MASK)); ++ printk("ROT_RDMA_SITE: 0x%lx\n",reg_read(dev, ROT_RDMA_SITE)); ++ printk("ROT_WDMA_SITE: 0x%lx\n",reg_read(dev, ROT_WDMA_SITE)); ++ printk("ROT_QOS: 0x%lx\n",reg_read(dev, ROT_QOS)); ++ printk("-----------------rot_reg------------------\n"); ++} ++ ++void dump_rot_desc(struct ingenic_rot_desc *desc) ++{ ++ printk("-----------------rot_desc------------------\n"); ++ printk("rot_des 0x%x\n",(uint32_t)desc); ++ printk("NextCfgAddr: 0x%x\n",desc->NextCfgAddr); ++ printk("SrcBufferAddr: 0x%x\n",desc->SrcBufferAddr); ++ printk("SrcStride: 0x%x\n",desc->SrcStride); ++ printk("FrameStop: 0x%x\n",desc->FrameStop.d32); ++ printk("TargetBufferAddr: 0x%x\n",desc->TargetBufferAddr); ++ printk("TargetStride: 0x%x\n",desc->TargetStride); ++ printk("irq_ctrl: 0x%x\n",desc->irq_ctrl.d32); ++ printk("-----------------rot_desc------------------\n"); ++} ++ ++void dump_rot_desc_reg(struct ingenic_rot_dev *dev) ++{ ++ reg_write(dev, ROT_CTRL, ROT_DES_CNT_RST); ++ printk("-----------------rot_desc_reg------------------\n"); ++ printk("NextCfgAddr: 0x%lx\n",reg_read(dev, ROT_DS_FRM_DES)); ++ printk("SrcBufferAddr: 0x%lx\n",reg_read(dev, ROT_DS_FRM_DES)); ++ printk("SrcStride: 0x%lx\n",reg_read(dev, ROT_DS_FRM_DES)); ++ printk("FrameStop: 0x%lx\n",reg_read(dev, ROT_DS_FRM_DES)); ++ printk("TargetBufferAddr: 0x%lx\n",reg_read(dev, ROT_DS_FRM_DES)); ++ printk("TargetStride: 0x%lx\n",reg_read(dev, ROT_DS_FRM_DES)); ++ printk("irq_ctrl: 0x%lx\n",reg_read(dev, ROT_DS_FRM_DES)); ++ printk("-----------------rot_desc_reg------------------\n"); ++} ++ ++void dump_all(struct ingenic_rot_dev *dev) ++{ ++ struct ingenic_rot_ctx *ctx; ++ ++ ctx = dev->curr; ++ ++ dump_rot_reg(dev); ++ dump_rot_desc_reg(dev); ++ dump_rot_desc(ctx->desc[0]); ++} ++ ++void rot_clr_irq(struct ingenic_rot_dev *dev) ++{ ++ uint32_t flag; ++ ++ flag = reg_read(dev, ROT_INT_MASK) & reg_read(dev, ROT_ST); ++ if(flag & ROT_EOF) { ++ reg_write(dev, ROT_CLR_ST, ROT_CLR_EOF); ++ } ++ if(flag & ROT_SOF) { ++ reg_write(dev, ROT_CLR_ST, ROT_CLR_SOF); ++ } ++ if(flag & ROT_GEN_STOP_ACK) { ++ reg_write(dev, ROT_CLR_ST, ROT_GEN_STOP_ACK); ++ } ++} ++ ++int wait_rot_state(struct ingenic_rot_dev *dev, int32_t state, uint32_t flag) ++{ ++ unsigned long timeout = 100000; ++ while(( (!(reg_read(dev, ROT_ST) & state)) == flag) && timeout) { ++ timeout--; ++ udelay(10); ++ } ++ if(timeout <= 0) { ++ printk("wait state timeout! state = %d, ROT_ST = 0x%lx\n", state, reg_read(dev, ROT_ST)); ++ return -1; ++ } ++ return 0; ++} ++ ++void rot_set_src_desc(struct ingenic_rot_dev *dev, dma_addr_t addr) ++{ ++ struct ingenic_rot_ctx *ctx; ++ struct ingenic_rot_desc *desc; ++ struct rot_frm_info *frm_info; ++ ++ ctx = dev->curr; ++ desc = ctx->desc[0]; ++ frm_info = &ctx->in; ++ ++ desc->NextCfgAddr = ctx->desc_phys[0]; ++ desc->SrcBufferAddr = addr; ++ desc->SrcStride = frm_info->width; ++} ++ ++void rot_set_dst_desc(struct ingenic_rot_dev *dev, dma_addr_t addr) ++{ ++ struct ingenic_rot_ctx *ctx; ++ struct ingenic_rot_desc *desc; ++ struct rot_frm_info *frm_info; ++ ++ ctx = dev->curr; ++ desc = ctx->desc[0]; ++ frm_info = &ctx->out; ++ ++ desc->TargetBufferAddr = addr; ++ ++ if((ctx->angle == 90) || (ctx->angle == 270)) ++ desc->TargetStride = frm_info->height; ++ else ++ desc->TargetStride = frm_info->width; ++} ++ ++void rot_set_hflip(struct ingenic_rot_dev *dev, uint32_t hflip) ++{ ++ uint32_t cfg; ++ ++ cfg = reg_read(dev, ROT_GLB_CFG); ++ if(hflip) ++ cfg |= ROT_H_MIRROR; ++ else ++ cfg &= ~ROT_H_MIRROR; ++ ++ reg_write(dev, ROT_GLB_CFG, cfg); ++} ++ ++void rot_set_vflip(struct ingenic_rot_dev *dev, uint32_t vflip) ++{ ++ uint32_t cfg; ++ ++ cfg = reg_read(dev, ROT_GLB_CFG); ++ if(vflip) ++ cfg |= ROT_V_MIRROR; ++ else ++ cfg &= ~ROT_V_MIRROR; ++ ++ reg_write(dev, ROT_GLB_CFG, cfg); ++} ++ ++void rot_set_angle(struct ingenic_rot_dev *dev, uint32_t angle) ++{ ++ uint32_t cfg; ++ ++ cfg = reg_read(dev, ROT_GLB_CFG); ++ switch(angle) { ++ case 0: ++ cfg |= ROT_ANGLE_0; ++ break; ++ case 90: ++ cfg |= ROT_ANGLE_90; ++ break; ++ case 180: ++ cfg |= ROT_ANGLE_180; ++ break; ++ case 270: ++ cfg |= ROT_ANGLE_270; ++ break; ++ default: ++ printk("!!!!!Not support angle!\n"); ++ break; ++ } ++ ++ reg_write(dev, ROT_GLB_CFG, cfg); ++} ++ ++void rot_set_dst_cfg(struct ingenic_rot_dev *dev, struct rot_frm_info *out) ++{ ++ uint32_t cfg; ++ ++ cfg = reg_read(dev, ROT_GLB_CFG); ++ switch(out->fmt->fourcc) { ++ case V4L2_PIX_FMT_RGB32: ++ cfg |= ROT_WDMA_FMT_ARGB8888; ++ break; ++ case V4L2_PIX_FMT_RGB565: ++ cfg |= ROT_WDMA_FMT_RGB565; ++ break; ++ case V4L2_PIX_FMT_RGB555: ++ cfg |= ROT_WDMA_FMT_RGB555; ++ break; ++ case V4L2_PIX_FMT_YUYV: ++ cfg |= ROT_WDMA_FMT_YUV422; ++ break; ++ default: ++ printk("!!!!!Not support fmt!\n"); ++ break; ++ } ++ reg_write(dev, ROT_GLB_CFG, cfg); ++} ++ ++void rot_set_src_cfg(struct ingenic_rot_dev *dev, struct rot_frm_info *in) ++{ ++ uint32_t cfg; ++ uint32_t frm_size = 0; ++ ++ frm_size |= in->width << ROT_FRM_WIDTH_LBIT; ++ frm_size |= in->height << ROT_FRM_HEIGHT_LBIT; ++ reg_write(dev, ROT_FRM_SIZE, frm_size); ++ ++ cfg = reg_read(dev, ROT_GLB_CFG); ++ switch(in->fmt->fourcc) { ++ case V4L2_PIX_FMT_RGB32: ++ cfg |= ROT_RDMA_FMT_ARGB8888; ++ break; ++ case V4L2_PIX_FMT_RGB24: ++ cfg |= ROT_RDMA_FMT_RGB888; ++ break; ++ case V4L2_PIX_FMT_RGB565: ++ cfg |= ROT_RDMA_FMT_RGB565; ++ break; ++ case V4L2_PIX_FMT_RGB555: ++ cfg |= ROT_RDMA_FMT_RGB555; ++ break; ++ case V4L2_PIX_FMT_RGB555X: ++ cfg |= ROT_RDMA_FMT_RGB1555; ++ break; ++ case V4L2_PIX_FMT_YUYV: ++ cfg |= ROT_RDMA_FMT_YUV422; ++ break; ++ default: ++ printk("!!!!!Not support fmt!\n"); ++ break; ++ } ++ reg_write(dev, ROT_GLB_CFG, cfg); ++} ++ ++void rot_reset(struct ingenic_rot_dev *dev) ++{ ++ struct ingenic_rot_ctx *ctx; ++ uint32_t cfg = 0; ++ int i; ++ ++ ctx = dev->curr; ++ ++ for(i = 0; i < ROT_DESC_NUM; i++) { ++ memset(ctx->desc[i], 0, sizeof(struct ingenic_rot_desc)); ++ } ++#if defined(ROT_GEN_STOP) || defined(ROT_QCK_STOP) ++ ctx->desc[0]->FrameStop.b.stop = 0; ++#else ++ ctx->desc[0]->FrameStop.b.stop = 1; ++#endif ++ ctx->desc[0]->irq_ctrl.d32 = ROT_EOF_MASK | ROT_SOF_MASK; ++ cfg = ROT_WDMA_BURST_32 | ROT_RDMA_BURST_32; ++ cfg |= ROT_RDMA_ORDER_RGB; ++ ++ reg_write(dev, ROT_GLB_CFG, cfg); ++ reg_write(dev, ROT_FRM_CFG_ADDR, ctx->desc_phys[0]); ++} ++ ++void rot_start(struct ingenic_rot_dev *dev) ++{ ++ reg_write(dev, ROT_INT_MASK, ROT_EOF_MASK); ++ reg_write(dev, ROT_CTRL, ROT_START); ++} ++ ++void rot_qck_stop(struct ingenic_rot_dev *dev) ++{ ++ reg_write(dev, ROT_CTRL, ROT_QCK_STP); ++ return; ++} ++ ++void rot_gen_stop(struct ingenic_rot_dev *dev) ++{ ++ reg_write(dev, ROT_CTRL, ROT_GEN_STP); ++ return; ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-rotate_rotate-regs.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-rotate_rotate-regs.h.patch new file mode 100644 index 00000000..9e97fb5e --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-rotate_rotate-regs.h.patch @@ -0,0 +1,207 @@ +diff -drupN a/drivers/media/platform/ingenic-rotate/rotate-regs.h b/drivers/media/platform/ingenic-rotate/rotate-regs.h +--- a/drivers/media/platform/ingenic-rotate/rotate-regs.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-rotate/rotate-regs.h 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,203 @@ ++/* * drivers/media/platform/ingenic_rotate/rotate-regs.h ++ * ++ * Copyright (C) 2016 Ingenic Semiconductor Inc. ++ * ++ * Author:clwang ++ * ++ * 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. ++ */ ++ ++#ifndef __ROTATER_REG_H__ ++#define __ROTATER_REG_H__ ++ ++/*------------------------------------------------------------------------------- ++ * Rotater Register Offset ++ * -----------------------------------------------------------------------------*/ ++ ++ ++/* RW 32 0x0000_0000 frame descriptor's addres */ ++#define ROT_FRM_CFG_ADDR (0x0000) ++/* RW 32 0x0000_0000 frame's size */ ++#define ROT_FRM_SIZE (0x0004) ++/* RW 32 0x0000_0000 global config */ ++#define ROT_GLB_CFG (0x0008) ++/* -W 32 0x0000_0000 rotate control */ ++#define ROT_CTRL (0x000c) ++/* R- 32 0x0000_0000 rotate status */ ++#define ROT_ST (0x0010) ++/* R- 32 0x0000_0000 rotarer clear status */ ++#define ROT_CLR_ST (0x0014) ++/* -W 32 0x0000_0000 rotator interrupt mask */ ++#define ROT_INT_MASK (0x0018) ++/* RW 32 0x0000_0000 RDMA`s current site */ ++#define ROT_RDMA_SITE (0x0020) ++/* RW 32 0x0000_0000 WDMA`s current site */ ++#define ROT_WDMA_SITE (0x0024) ++/* R- 32 0x0000_0000 Read the frame configure */ ++#define ROT_DS_FRM_DES (0x0028) ++/* RW 32 0x0000_0000 Rotator QOS config */ ++#define ROT_QOS (0x0030) ++ ++ ++/*------------------------------------------------------------------------------- ++ * DPU Registers Bits Field Define ++ * -----------------------------------------------------------------------------*/ ++ ++ ++/* frame's size(ROT_FRM_SIZE) bit field define */ ++ ++/* Frame's width */ ++#define ROT_FRM_WIDTH_LBIT (0) ++#define ROT_FRM_WIDTH_HBIT (10) ++#define ROT_FRM_WIDTH_MASK \ ++ GENMASK(ROT_FRM_WIDTH_HBIT, ROT_FRM_WIDTH_LBIT) ++/* Frame's height */ ++#define ROT_FRM_HEIGHT_LBIT (16) ++#define ROT_FRM_HEIGHT_HBIT (26) ++#define ROT_FRM_HEIGHT_MASK \ ++ GENMASK(ROT_FRM_HEIGHT_HBIT, ROT_FRM_HEIGHT_LBIT) ++ ++/* global config(ROT_GLB_CFG) bit field define */ ++ ++/* RDMA max length of the block DMA's burst. */ ++#define ROT_RDMA_BURST_LEN_LBIT (0) ++#define ROT_RDMA_BURST_LEN_HBIT (1) ++#define ROT_RDMA_BURST_LEN_MASK \ ++ GENMASK(ROT_RDMA_BURST_LEN_HBIT, ROT_RDMA_BURST_LEN_LBIT) ++ ++#define ROT_RDMA_BURST_4 (0) << ROT_RDMA_BURST_LEN_LBIT ++#define ROT_RDMA_BURST_8 (1) << ROT_RDMA_BURST_LEN_LBIT ++#define ROT_RDMA_BURST_16 (2) << ROT_RDMA_BURST_LEN_LBIT ++#define ROT_RDMA_BURST_32 (3) << ROT_RDMA_BURST_LEN_LBIT ++/* WDMA max length of the block DMA's burst. */ ++#define ROT_WDMA_BURST_LEN_LBIT (2) ++#define ROT_WDMA_BURST_LEN_HBIT (3) ++#define ROT_WDMA_BURST_LEN_MASK \ ++ GENMASK(ROT_WDMA_BURST_LEN_HBIT, ROT_WDMA_BURST_LEN_LBIT) ++ ++#define ROT_WDMA_BURST_4 (0) << ROT_WDMA_BURST_LEN_LBIT ++#define ROT_WDMA_BURST_8 (1) << ROT_WDMA_BURST_LEN_LBIT ++#define ROT_WDMA_BURST_16 (2) << ROT_WDMA_BURST_LEN_LBIT ++#define ROT_WDMA_BURST_32 (3) << ROT_WDMA_BURST_LEN_LBIT ++/* Rotater angle. */ ++#define ROT_ANGLE_LBIT (4) ++#define ROT_ANGLE_HBIT (5) ++#define ROT_ANGLE_MASK \ ++ GENMASK(ROT_ANGLE_HBIT, ROT_ANGLE_LBIT) ++ ++#define ROT_ANGLE_0 (0) << ROT_ANGLE_LBIT ++#define ROT_ANGLE_90 (1) << ROT_ANGLE_LBIT ++#define ROT_ANGLE_180 (2) << ROT_ANGLE_LBIT ++#define ROT_ANGLE_270 (3) << ROT_ANGLE_LBIT ++/* Vertical mirror */ ++#define ROT_V_MIRROR BIT(6) ++/* Horizontal mirror */ ++#define ROT_H_MIRROR BIT(7) ++/* Target format. */ ++#define ROT_WDMA_FMT_LBIT (12) ++#define ROT_WDMA_FMT_HBIT (13) ++#define ROT_WDMA_FMT_MASK \ ++ GENMASK(ROT_WDMA_FMT_HBIT, ROT_WDMA_FMT_LBIT) ++ ++#define ROT_WDMA_FMT_ARGB8888 (0) << ROT_WDMA_FMT_LBIT ++#define ROT_WDMA_FMT_RGB565 (1) << ROT_WDMA_FMT_LBIT ++#define ROT_WDMA_FMT_RGB555 (2) << ROT_WDMA_FMT_LBIT ++#define ROT_WDMA_FMT_YUV422 (3) << ROT_WDMA_FMT_LBIT ++/* RDMA ORDER. */ ++#define ROT_RDMA_ORDER_LBIT (16) ++#define ROT_RDMA_ORDER_HBIT (18) ++#define ROT_RDMA_ORDER_MASK \ ++ GENMASK(ROT_RDMA_ORDER_HBIT, ROT_RDMA_ORDER_LBIT) ++ ++#define ROT_RDMA_ORDER_RGB (0) << ROT_RDMA_ORDER_LBIT ++#define ROT_RDMA_ORDER_RBG (1) << ROT_RDMA_ORDER_LBIT ++#define ROT_RDMA_ORDER_GRB (2) << ROT_RDMA_ORDER_LBIT ++#define ROT_RDMA_ORDER_GBR (3) << ROT_RDMA_ORDER_LBIT ++#define ROT_RDMA_ORDER_BRG (4) << ROT_RDMA_ORDER_LBIT ++#define ROT_RDMA_ORDER_BGR (5) << ROT_RDMA_ORDER_LBIT ++/* RDMA format. */ ++#define ROT_RDMA_FMT_LBIT (24) ++#define ROT_RDMA_FMT_HBIT (27) ++#define ROT_RDMA_FMT_MASK \ ++ GENMASK(ROT_RDMA_FMT_HBIT, ROT_RDMA_FMT_LBIT) ++ ++#define ROT_RDMA_FMT_RGB555 (0) << ROT_RDMA_FMT_LBIT ++#define ROT_RDMA_FMT_RGB1555 (1) << ROT_RDMA_FMT_LBIT ++#define ROT_RDMA_FMT_RGB565 (2) << ROT_RDMA_FMT_LBIT ++#define ROT_RDMA_FMT_RGB888 (4) << ROT_RDMA_FMT_LBIT ++#define ROT_RDMA_FMT_ARGB8888 (5) << ROT_RDMA_FMT_LBIT ++#define ROT_RDMA_FMT_YUV422 (10) << ROT_RDMA_FMT_LBIT ++ ++/* rotate control(ROT_CTRL) bit field define */ ++ ++/* START */ ++#define ROT_START BIT(0) ++/* QCK_STOP */ ++#define ROT_QCK_STP BIT(1) ++/* GEN_STOP */ ++#define ROT_GEN_STP BIT(2) ++/* Reset the counter of FRM_DES */ ++#define ROT_DES_CNT_RST BIT(3) ++ ++/* rotate status(ROT_SATUS) bit field define */ ++ ++/* Rotater is working */ ++#define ROT_WORKING BIT(0) ++/* Rotater is general stop */ ++#define ROT_GEN_STOP_ACK BIT(1) ++/* One frame read end */ ++#define ROT_EOF BIT(2) ++/* One frme read start */ ++#define ROT_SOF BIT(3) ++/* Mask of ROT_GEN_STOP_ACK */ ++#define ROT_GSA_MASK_ST BIT(17) ++/* Mask of FRM_END */ ++#define ROT_EOF_MASK_ST BIT(18) ++/* Mask of FRM_START */ ++#define ROT_SOF_MASK_ST BIT(19) ++ ++/* rotarer clear status(ROT_CLR_ST) bit field define */ ++ ++/* Clear general stop acknowledge */ ++#define ROT_CLR_GEN_STOP_ACK BIT(1) ++/* Clear FRM_END */ ++#define ROT_CLR_EOF BIT(2) ++/* Clear FRM_START */ ++#define ROT_CLR_SOF BIT(3) ++ ++/* rotator interrupt mask(ROT_INT_MASK) bit field define */ ++ ++/* Mask general stop acknowledge */ ++#define ROT_GSA_MASK BIT(1) ++/* Mask FRM_END */ ++#define ROT_EOF_MASK BIT(2) ++/* Mask FRM_START */ ++#define ROT_SOF_MASK BIT(3) ++ ++/* rotator QOS config (ROT_QOS) bit field define */ ++ ++/* STD_CLK */ ++#define ROT_STD_CLK_LBIT (0) ++#define ROT_STD_CLK_HBIT (7) ++#define ROT_STD_CLK_MASK \ ++ GENMASK(ROT_STD_CLK_HBIT, ROT_STD_CLK_LBIT) ++/* STD_THR0 */ ++#define ROT_STD_THR0_LBIT (8) ++#define ROT_STD_THR0_HBIT (15) ++#define ROT_STD_THR0_MASK \ ++ GENMASK(ROT_STD_THR0_HBIT, ROT_STD_THR0_LBIT) ++/* STD_THR1 */ ++#define ROT_STD_THR1_LBIT (16) ++#define ROT_STD_THR1_HBIT (23) ++#define ROT_STD_THR1_MASK \ ++ GENMASK(ROT_STD_THR1_HBIT, ROT_STD_THR1_LBIT) ++/* STD_THR2 */ ++#define ROT_STD_THR2_LBIT (24) ++#define ROT_STD_THR2_HBIT (31) ++#define ROT_STD_THR2_MASK \ ++ GENMASK(ROT_STD_THR2_HBIT, ROT_STD_THR2_LBIT) ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-rotate_rotate.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-rotate_rotate.c.patch new file mode 100644 index 00000000..6ab182b6 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-rotate_rotate.c.patch @@ -0,0 +1,832 @@ +diff -drupN a/drivers/media/platform/ingenic-rotate/rotate.c b/drivers/media/platform/ingenic-rotate/rotate.c +--- a/drivers/media/platform/ingenic-rotate/rotate.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-rotate/rotate.c 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,828 @@ ++/* * drivers/media/platform/ingenic_rotate/rotate.c ++ * ++ * Copyright (C) 2016 Ingenic Semiconductor Inc. ++ * ++ * Author:clwang ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "rotate.h" ++#include "rotate-regs.h" ++ ++#define fh2ctx(__fh) container_of(__fh, struct ingenic_rot_ctx, fh) ++ ++static struct timeval time_now, time_last; ++static long interval_in_us; ++ ++static struct rot_fmt formats[] = { ++ { ++ .name = "ARGB_8888", ++ .fourcc = V4L2_PIX_FMT_RGB32, ++ .depth = 32, ++ .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, ++ }, ++ { ++ .name = "RGB_888", ++ .fourcc = V4L2_PIX_FMT_RGB24, ++ .depth = 32, ++ .types = MEM2MEM_OUTPUT, ++ }, ++ { ++ .name = "RGB_565", ++ .fourcc = V4L2_PIX_FMT_RGB565, ++ .depth = 16, ++ .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, ++ }, ++ { ++ .name = "RGB_555", ++ .fourcc = V4L2_PIX_FMT_RGB555, ++ .depth = 16, ++ .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, ++ }, ++ { ++ .name = "XRGB_1555", ++ .fourcc = V4L2_PIX_FMT_RGB555X, ++ .depth = 16, ++ .types = MEM2MEM_OUTPUT, ++ }, ++ { ++ .name = "YUV 422P", ++ .fourcc = V4L2_PIX_FMT_YUYV, ++ .depth = 16, ++ .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, ++ }, ++}; ++#define NUM_FORMATS ARRAY_SIZE(formats) ++ ++static struct rot_fmt *find_fmt(struct v4l2_format *f) ++{ ++ unsigned int i; ++ for (i = 0; i < NUM_FORMATS; i++) { ++ if (formats[i].fourcc == f->fmt.pix.pixelformat) ++ return &formats[i]; ++ } ++ return NULL; ++} ++ ++ ++static struct rot_frm_info *get_frame(struct ingenic_rot_ctx *ctx, ++ enum v4l2_buf_type type) ++{ ++ switch (type) { ++ case V4L2_BUF_TYPE_VIDEO_OUTPUT: ++ return &ctx->in; ++ case V4L2_BUF_TYPE_VIDEO_CAPTURE: ++ return &ctx->out; ++ default: ++ return ERR_PTR(-EINVAL); ++ } ++} ++ ++static int rot_queue_setup(struct vb2_queue *vq, const void *parg, ++ unsigned int *nbuffers, unsigned int *nplanes, ++ unsigned int sizes[], void *alloc_ctxs[]) ++{ ++ struct ingenic_rot_ctx *ctx = vb2_get_drv_priv(vq); ++ struct rot_frm_info *f = get_frame(ctx, vq->type); ++ ++ if (IS_ERR(f)) ++ return PTR_ERR(f); ++ ++ *nplanes = 1; ++ sizes[0] = f->size; ++ alloc_ctxs[0] = ctx->dev->alloc_ctx; ++ ++ if (*nbuffers == 0) ++ *nbuffers = 1; ++ ++ return 0; ++} ++ ++static int rot_buf_prepare(struct vb2_buffer *vb) ++{ ++ struct ingenic_rot_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); ++ struct rot_frm_info *f = get_frame(ctx, vb->vb2_queue->type); ++ ++ if (IS_ERR(f)) ++ return PTR_ERR(f); ++ vb2_set_plane_payload(vb, 0, f->size); ++ return 0; ++} ++ ++static void rot_buf_queue(struct vb2_buffer *vb) ++{ ++ struct ingenic_rot_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); ++ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); ++ ++ if (ctx->m2m_ctx) ++ v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); ++} ++ ++ ++static struct vb2_ops rot_qops = { ++ .queue_setup = rot_queue_setup, ++ .buf_prepare = rot_buf_prepare, ++ .buf_queue = rot_buf_queue, ++}; ++ ++static int queue_init(void *priv, struct vb2_queue *src_vq, ++ struct vb2_queue *dst_vq) ++{ ++ struct ingenic_rot_ctx *ctx = priv; ++ int ret; ++ ++ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; ++ src_vq->io_modes = VB2_MMAP | VB2_USERPTR; ++ src_vq->drv_priv = ctx; ++ src_vq->ops = &rot_qops; ++ src_vq->mem_ops = &vb2_dma_contig_memops; ++ src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); ++ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; ++ src_vq->lock = &ctx->dev->mutex; ++ ++ ret = vb2_queue_init(src_vq); ++ if (ret) ++ return ret; ++ ++ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ dst_vq->io_modes = VB2_MMAP | VB2_USERPTR; ++ dst_vq->drv_priv = ctx; ++ dst_vq->ops = &rot_qops; ++ dst_vq->mem_ops = &vb2_dma_contig_memops; ++ dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); ++ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; ++ dst_vq->lock = &ctx->dev->mutex; ++ ++ return vb2_queue_init(dst_vq); ++} ++ ++static int rot_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct ingenic_rot_ctx *ctx = container_of(ctrl->handler, struct ingenic_rot_ctx, ++ ctrl_handler); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ctx->dev->ctrl_lock, flags); ++ switch (ctrl->id) { ++ case V4L2_CID_HFLIP: ++ ctx->hflip = ctx->ctrl_hflip->val; ++ break; ++ case V4L2_CID_VFLIP: ++ ctx->vflip = ctx->ctrl_vflip->val; ++ break; ++ case V4L2_CID_ROTATE: ++ ctx->angle = ctx->ctrl_rot->val; ++ break; ++ } ++ spin_unlock_irqrestore(&ctx->dev->ctrl_lock, flags); ++ return 0; ++} ++ ++static const struct v4l2_ctrl_ops rot_ctrl_ops = { ++ .s_ctrl = rot_s_ctrl, ++}; ++ ++static int rot_setup_ctrls(struct ingenic_rot_ctx *ctx) ++{ ++ struct ingenic_rot_dev *dev = ctx->dev; ++ ++ v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3); ++ ++ ctx->ctrl_hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &rot_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ ++ ctx->ctrl_vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &rot_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ ctx->ctrl_rot = v4l2_ctrl_new_std(&ctx->ctrl_handler, &rot_ctrl_ops, ++ V4L2_CID_ROTATE, 0, 270, 90, 0); ++ ++ if (ctx->ctrl_handler.error) { ++ int err = ctx->ctrl_handler.error; ++ v4l2_err(&dev->v4l2_dev, "rot_setup_ctrls failed\n"); ++ v4l2_ctrl_handler_free(&ctx->ctrl_handler); ++ return err; ++ } ++ ++ return 0; ++} ++ ++static void rot_update_info(struct ingenic_rot_ctx *ctx) ++{ ++ struct rot_frm_info *in, *out; ++ ++ in = &ctx->in; ++ out = &ctx->out; ++ ++ in->width = DEFAULT_WIDTH; ++ in->height = DEFAULT_HEIGHT; ++ in->fmt = &formats[1]; ++ in->bytesperline = DEFAULT_WIDTH * in->fmt->depth >> 3; ++ in->size = in->bytesperline * in->height; ++ ++ out->width = DEFAULT_WIDTH; ++ out->height = DEFAULT_HEIGHT; ++ out->fmt = &formats[0]; ++ out->bytesperline = DEFAULT_WIDTH * out->fmt->depth >> 3; ++ out->size = out->bytesperline * out->height; ++} ++ ++static int rot_reqdesc(struct ingenic_rot_ctx *ctx) ++{ ++ struct ingenic_rot_dev *dev = ctx->dev; ++ struct video_device *vfd = dev->vfd; ++ int i, size; ++ ++ size = sizeof(struct ingenic_rot_desc) * ROT_DESC_NUM; ++ ctx->desc[0] = (struct ingenic_rot_desc *)dma_alloc_coherent(&vfd->dev, size, ++ &ctx->desc_phys[0], GFP_KERNEL); ++ if (!ctx->desc[0]) { ++ dev_err(&vfd->dev, "dma_alloc_coherent of size %d failed\n", size); ++ return -ENOMEM; ++ } ++ ++ for(i = 1; i < ROT_DESC_NUM; i++) { ++ ctx->desc[i] = ctx->desc[0] + i; ++ ctx->desc_phys[i] = ctx->desc_phys[0] + i*sizeof(struct ingenic_rot_desc); ++ } ++ return 0; ++} ++ ++static void rot_freedesc(struct ingenic_rot_ctx *ctx) ++{ ++ struct ingenic_rot_dev *dev = ctx->dev; ++ struct video_device *vfd = dev->vfd; ++ int size; ++ ++ size = sizeof(struct ingenic_rot_desc) * ROT_DESC_NUM; ++ dma_free_coherent(&vfd->dev, size, ctx->desc[0], ctx->desc_phys[0]); ++} ++ ++static int rot_open(struct file *file) ++{ ++ struct ingenic_rot_dev *dev = video_drvdata(file); ++ struct ingenic_rot_ctx *ctx = NULL; ++ int ret = 0; ++ ++ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); ++ if (!ctx) ++ return -ENOMEM; ++ ++ if (mutex_lock_interruptible(&dev->mutex)) { ++ kfree(ctx); ++ return -ERESTARTSYS; ++ } ++ ctx->dev = dev; ++ ++ /* Set default formats */ ++ rot_update_info(ctx); ++ ++ ret = rot_reqdesc(ctx); ++ if(ret) { ++ goto free; ++ } ++ ++ v4l2_fh_init(&ctx->fh, video_devdata(file)); ++ ctx->fh.ctrl_handler = &ctx->ctrl_handler; ++ file->private_data = &ctx->fh; ++ v4l2_fh_add(&ctx->fh); ++ ++ ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init); ++ if (IS_ERR(ctx->m2m_ctx)) { ++ ret = PTR_ERR(ctx->m2m_ctx); ++ goto err; ++ } ++ ctx->fh.m2m_ctx = ctx->m2m_ctx; ++ ++ ret = rot_setup_ctrls(ctx); ++ if(ret) ++ goto err; ++ ++ /* Write the default values to the ctx struct */ ++ v4l2_ctrl_handler_setup(&ctx->ctrl_handler); ++ ++ mutex_unlock(&dev->mutex); ++ ++ return 0; ++err: ++ rot_freedesc(ctx); ++ v4l2_fh_del(&ctx->fh); ++ v4l2_fh_exit(&ctx->fh); ++free: ++ mutex_unlock(&dev->mutex); ++ kfree(ctx); ++ return ret; ++} ++ ++static int rot_release(struct file *file) ++{ ++ struct ingenic_rot_dev *dev = video_drvdata(file); ++ struct ingenic_rot_ctx *ctx = fh2ctx(file->private_data); ++ ++ mutex_lock(&dev->mutex); ++ v4l2_m2m_ctx_release(ctx->m2m_ctx); ++ mutex_unlock(&dev->mutex); ++ v4l2_ctrl_handler_free(&ctx->ctrl_handler); ++ v4l2_fh_del(&ctx->fh); ++ v4l2_fh_exit(&ctx->fh); ++ rot_freedesc(ctx); ++ kfree(ctx); ++ return 0; ++} ++ ++static int vidioc_querycap(struct file *file, void *priv, ++ struct v4l2_capability *cap) ++{ ++ strncpy(cap->driver, JZ_ROT_NAME, sizeof(cap->driver) - 1); ++ strncpy(cap->card, JZ_ROT_NAME, sizeof(cap->card) - 1); ++ cap->bus_info[0] = 0; ++ cap->version = KERNEL_VERSION(1, 0, 0); ++ /* ++ * This is only a mem-to-mem video device. The capture and output ++ * device capability flags are left only for backward compatibility ++ * and are scheduled for removal. ++ */ ++ cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M; ++ cap->capabilities = cap->device_caps | ++ V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT | ++ V4L2_CAP_DEVICE_CAPS; ++ ++ return 0; ++} ++ ++static int enum_fmt(struct v4l2_fmtdesc *f, u32 type) ++{ ++ int i, num; ++ struct rot_fmt *fmt; ++ ++ num = 0; ++ for (i = 0; i < NUM_FORMATS; ++i) { ++ if (formats[i].types & type) { ++ /* index-th format of type type found ? */ ++ if (num == f->index) ++ break; ++ /* Correct type but haven't reached our index yet, ++ * just increment per-type index */ ++ ++num; ++ } ++ } ++ ++ if (i < NUM_FORMATS) { ++ /* Format found */ ++ fmt = &formats[i]; ++ strncpy(f->description, fmt->name, sizeof(f->description) - 1); ++ f->pixelformat = fmt->fourcc; ++ return 0; ++ } ++ ++ /* Format not found */ ++ return -EINVAL; ++} ++ ++static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_fmtdesc *f) ++{ ++ return enum_fmt(f, MEM2MEM_CAPTURE); ++} ++ ++static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, ++ struct v4l2_fmtdesc *f) ++{ ++ return enum_fmt(f, MEM2MEM_OUTPUT); ++} ++ ++static inline struct ingenic_rot_ctx *fh_to_ctx(struct v4l2_fh *fh) ++{ ++ return container_of(fh, struct ingenic_rot_ctx, fh); ++} ++ ++static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f) ++{ ++ struct ingenic_rot_ctx *ctx = fh_to_ctx(prv); ++ struct vb2_queue *vq; ++ struct rot_frm_info *frm; ++ ++ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); ++ if (!vq) ++ return -EINVAL; ++ frm = get_frame(ctx, f->type); ++ if (IS_ERR(frm)) ++ return PTR_ERR(frm); ++ ++ f->fmt.pix.width = frm->width; ++ f->fmt.pix.height = frm->height; ++ f->fmt.pix.field = V4L2_FIELD_NONE; ++ f->fmt.pix.pixelformat = frm->fmt->fourcc; ++ f->fmt.pix.bytesperline = (frm->width * frm->fmt->depth) >> 3; ++ f->fmt.pix.sizeimage = frm->size; ++ return 0; ++} ++ ++static int vidioc_try_fmt(struct file *file, void *prv, struct v4l2_format *f) ++{ ++ struct rot_fmt *fmt; ++ enum v4l2_field *field; ++ ++ fmt = find_fmt(f); ++ if (!fmt) ++ return -EINVAL; ++ ++ field = &f->fmt.pix.field; ++ if (*field == V4L2_FIELD_ANY) ++ *field = V4L2_FIELD_NONE; ++ else if (*field != V4L2_FIELD_NONE) ++ return -EINVAL; ++ ++ if (f->fmt.pix.width > MAX_WIDTH ++ || f->fmt.pix.height > MAX_HEIGHT ++ || f->fmt.pix.width < MIN_WIDTH ++ || f->fmt.pix.height < MIN_HEIGHT) { ++ return -EINVAL; ++ } ++ ++ f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; ++ f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; ++ return 0; ++} ++ ++static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f) ++{ ++ struct ingenic_rot_ctx *ctx = fh_to_ctx(prv); ++ struct ingenic_rot_dev *dev = ctx->dev; ++ struct vb2_queue *vq; ++ struct rot_frm_info *frm; ++ struct rot_fmt *fmt; ++ int ret = 0; ++ ++ /* Adjust all values accordingly to the hardware capabilities ++ * and chosen format. */ ++ ret = vidioc_try_fmt(file, prv, f); ++ if (ret) ++ return ret; ++ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); ++ if (vb2_is_busy(vq)) { ++ v4l2_err(&dev->v4l2_dev, "queue (%d) bust\n", f->type); ++ return -EBUSY; ++ } ++ frm = get_frame(ctx, f->type); ++ if (IS_ERR(frm)) ++ return PTR_ERR(frm); ++ fmt = find_fmt(f); ++ if (!fmt) ++ return -EINVAL; ++ frm->width = f->fmt.pix.width; ++ frm->height = f->fmt.pix.height; ++ frm->size = f->fmt.pix.sizeimage; ++ frm->fmt = fmt; ++ frm->bytesperline = f->fmt.pix.bytesperline; ++ return 0; ++} ++ ++static inline long timeval_sub_to_us(struct timeval lhs, ++ struct timeval rhs) ++{ ++ long sec, usec; ++ sec = lhs.tv_sec - rhs.tv_sec; ++ usec = lhs.tv_usec - rhs.tv_usec; ++ ++ return (sec*1000000 + usec); ++} ++ ++static int vidioc_streamon(struct file *file, void *priv, ++ enum v4l2_buf_type type) ++{ ++ struct ingenic_rot_ctx *ctx = priv; ++ struct ingenic_rot_dev *dev = ctx->dev; ++ ++ clk_prepare_enable(dev->clk); ++ ++ return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); ++} ++ ++static int vidioc_streamoff(struct file *file, void *priv, ++ enum v4l2_buf_type type) ++{ ++ struct ingenic_rot_ctx *ctx = priv; ++ struct ingenic_rot_dev *dev = ctx->dev; ++ ++ clk_disable_unprepare(dev->clk); ++ ++ return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); ++} ++ ++/* Need change, One frame spends times */ ++#define ROT_TIMEOUT 400 ++ ++static void job_abort(void *prv) ++{ ++ struct ingenic_rot_ctx *ctx = prv; ++ struct ingenic_rot_dev *dev = ctx->dev; ++ int ret; ++ ++ if (dev->curr == NULL) /* No job currently running */ ++ return; ++ ++ ret = wait_event_timeout(dev->irq_queue, ++ dev->curr == NULL, ++ msecs_to_jiffies(ROT_TIMEOUT)); ++} ++ ++static void device_run(void *prv) ++{ ++ struct ingenic_rot_ctx *ctx = prv; ++ struct ingenic_rot_dev *dev = ctx->dev; ++ struct vb2_buffer *src, *dst; ++ unsigned long flags; ++ ++ dev->curr = ctx; ++ ++ src = v4l2_m2m_next_src_buf(ctx->m2m_ctx); ++ dst = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); ++ ++ spin_lock_irqsave(&dev->ctrl_lock, flags); ++ ++ rot_reset(dev); ++ ++ rot_set_src_cfg(dev, &ctx->in); ++ rot_set_src_desc(dev, vb2_dma_contig_plane_dma_addr(src, 0)); ++ ++ rot_set_dst_cfg(dev, &ctx->out); ++ rot_set_dst_desc(dev, vb2_dma_contig_plane_dma_addr(dst, 0)); ++ ++ rot_set_angle(dev, ctx->angle); ++ rot_set_vflip(dev, ctx->vflip); ++ rot_set_hflip(dev, ctx->hflip); ++ ++ do_gettimeofday(&time_now); ++ ++ rot_start(dev); ++ ++#ifdef ROT_GEN_STOP ++ rot_gen_stop(dev); ++#endif ++ ++ spin_unlock_irqrestore(&dev->ctrl_lock, flags); ++} ++ ++static irqreturn_t rot_irq_handler(int irq, void *prv) ++{ ++ struct ingenic_rot_dev *dev = prv; ++ struct ingenic_rot_ctx *ctx = dev->curr; ++ struct vb2_v4l2_buffer *src, *dst; ++ ++ do_gettimeofday(&time_last); ++ interval_in_us = timeval_sub_to_us(time_last, time_now); ++ ++ rot_clr_irq(dev); ++ ++ if(unlikely(ctx == NULL)) { ++ printk("Rotater:ctx == NULL\n"); ++ return IRQ_HANDLED; ++ } ++ ++ src = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); ++ if(unlikely(src == NULL)) { ++ printk("Rotater:src == NULL\n"); ++ return IRQ_HANDLED; ++ } ++ dst = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); ++ if(unlikely(dst == NULL)) { ++ printk("Rotater:dst == NULL\n"); ++ return IRQ_HANDLED; ++ } ++ ++ dst->timecode = src->timecode; ++ dst->timestamp = src->timestamp; ++ ++ v4l2_m2m_buf_done(src, VB2_BUF_STATE_DONE); ++ v4l2_m2m_buf_done(dst, VB2_BUF_STATE_DONE); ++ v4l2_m2m_job_finish(dev->m2m_dev, ctx->m2m_ctx); ++ ++ dev->curr = NULL; ++#ifdef ROT_QCK_STOP ++ rot_qck_stop(dev); ++#endif ++#if defined(ROT_GEN_STOP) || defined(ROT_QCK_STOP) ++ schedule_work(&dev->rot_work); ++#endif ++ wake_up(&dev->irq_queue); ++ return IRQ_HANDLED; ++} ++ ++#if defined(ROT_GEN_STOP) || defined(ROT_QCK_STOP) ++static void rot_wait_dev_end(struct work_struct *rot_work) ++{ ++ struct ingenic_rot_dev *dev; ++ ++ dev = container_of(rot_work, struct ingenic_rot_dev, rot_work); ++ wait_rot_state(dev, ROT_WORKING, 0); ++} ++#endif ++ ++static const struct v4l2_file_operations rot_fops = { ++ .owner = THIS_MODULE, ++ .open = rot_open, ++ .release = rot_release, ++ .poll = v4l2_m2m_fop_poll, ++ .unlocked_ioctl = video_ioctl2, ++ .mmap = v4l2_m2m_fop_mmap, ++}; ++ ++static const struct v4l2_ioctl_ops rot_ioctl_ops = { ++ .vidioc_querycap = vidioc_querycap, ++ ++ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, ++ .vidioc_g_fmt_vid_cap = vidioc_g_fmt, ++ .vidioc_try_fmt_vid_cap = vidioc_try_fmt, ++ .vidioc_s_fmt_vid_cap = vidioc_s_fmt, ++ ++ .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, ++ .vidioc_g_fmt_vid_out = vidioc_g_fmt, ++ .vidioc_try_fmt_vid_out = vidioc_try_fmt, ++ .vidioc_s_fmt_vid_out = vidioc_s_fmt, ++ ++ .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, ++ .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, ++ .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, ++ .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, ++ ++ .vidioc_streamon = vidioc_streamon, ++ .vidioc_streamoff = vidioc_streamoff, ++}; ++ ++static struct video_device rot_videodev = { ++ .name = "ingenic-rot", ++ .fops = &rot_fops, ++ .ioctl_ops = &rot_ioctl_ops, ++ .minor = -1, ++ .release = video_device_release, ++ .vfl_dir = VFL_DIR_M2M, ++}; ++ ++static struct v4l2_m2m_ops rot_m2m_ops = { ++ .device_run = device_run, ++ .job_abort = job_abort, ++}; ++ ++static int ingenic_rot_probe(struct platform_device *pdev) ++{ ++ struct ingenic_rot_dev *dev; ++ struct video_device *vfd; ++ struct resource *res; ++ int ret = 0; ++ ++ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); ++ if (!dev) ++ return -ENOMEM; ++ ++ dev->dev = &pdev->dev; ++ spin_lock_init(&dev->ctrl_lock); ++ mutex_init(&dev->mutex); ++ atomic_set(&dev->num_inst, 0); ++ init_waitqueue_head(&dev->irq_queue); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ ++ dev->regs = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(dev->regs)) ++ return PTR_ERR(dev->regs); ++ ++ /* interrupt service routine registration */ ++ dev->irq = ret = platform_get_irq(pdev, 0); ++ if (dev->irq < 0) { ++ dev_err(&pdev->dev, "cannot find IRQ\n"); ++ return ret; ++ } ++ ++ ret = devm_request_irq(&pdev->dev, dev->irq, rot_irq_handler, ++ 0, pdev->name, dev); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to install IRQ\n"); ++ return ret; ++ } ++ ++ /* clocks */ ++ dev->clk = clk_get(&pdev->dev, "gate_rot"); ++ if (IS_ERR(dev->clk)) { ++ dev_err(&pdev->dev, "cannot get clock\n"); ++ ret = PTR_ERR(dev->clk); ++ return ret; ++ } ++ dev_dbg(&pdev->dev, "rot clock source %p\n", dev->clk); ++ ++#if defined(ROT_QCK_STOP) || defined(ROT_GEN_STOP) ++ INIT_WORK(&dev->rot_work, rot_wait_dev_end); ++#endif ++ dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); ++ if (IS_ERR(dev->alloc_ctx)) { ++ ret = PTR_ERR(dev->alloc_ctx); ++ goto clk_get_rollback; ++ } ++ ++ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); ++ if (ret) ++ goto alloc_ctx_cleanup; ++ vfd = video_device_alloc(); ++ if (!vfd) { ++ v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n"); ++ ret = -ENOMEM; ++ goto unreg_v4l2_dev; ++ } ++ *vfd = rot_videodev; ++ vfd->lock = &dev->mutex; ++ vfd->v4l2_dev = &dev->v4l2_dev; ++ ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); ++ if (ret) { ++ v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); ++ goto rel_vdev; ++ } ++ video_set_drvdata(vfd, dev); ++ snprintf(vfd->name, sizeof(vfd->name), "%s", rot_videodev.name); ++ dev->vfd = vfd; ++ v4l2_info(&dev->v4l2_dev, "device registered as /dev/video%d\n", ++ vfd->num); ++ platform_set_drvdata(pdev, dev); ++ dev->m2m_dev = v4l2_m2m_init(&rot_m2m_ops); ++ if (IS_ERR(dev->m2m_dev)) { ++ v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n"); ++ ret = PTR_ERR(dev->m2m_dev); ++ goto unreg_video_dev; ++ } ++ return 0; ++ ++unreg_video_dev: ++ video_unregister_device(dev->vfd); ++rel_vdev: ++ video_device_release(vfd); ++unreg_v4l2_dev: ++ v4l2_device_unregister(&dev->v4l2_dev); ++alloc_ctx_cleanup: ++ vb2_dma_contig_cleanup_ctx(dev->alloc_ctx); ++clk_get_rollback: ++ clk_put(dev->clk); ++ ++ return ret; ++} ++ ++static int ingenic_rot_remove(struct platform_device *pdev) ++{ ++ struct ingenic_rot_dev *dev = (struct ingenic_rot_dev *)platform_get_drvdata(pdev); ++ ++ v4l2_info(&dev->v4l2_dev, "Removing " JZ_ROT_NAME); ++ v4l2_m2m_release(dev->m2m_dev); ++ video_unregister_device(dev->vfd); ++ video_device_release(dev->vfd); ++ v4l2_device_unregister(&dev->v4l2_dev); ++ vb2_dma_contig_cleanup_ctx(dev->alloc_ctx); ++ clk_put(dev->clk); ++ return 0; ++} ++ ++static const struct of_device_id ingenic_rotate_match[] = { ++ { ++ .compatible = "ingenic,x2000-rotate", ++ .data = NULL, ++ }, ++}; ++ ++MODULE_DEVICE_TABLE(of, ingenic_rotate_match); ++ ++ ++static struct platform_driver rot_pdrv = { ++ .probe = ingenic_rot_probe, ++ .remove = ingenic_rot_remove, ++ .driver = { ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(ingenic_rotate_match), ++ .name = JZ_ROT_NAME, ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++module_platform_driver(rot_pdrv); ++ ++MODULE_AUTHOR("clwang"); ++MODULE_DESCRIPTION("X2000 rotate driver"); ++MODULE_LICENSE("GPL"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-rotate_rotate.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-rotate_rotate.h.patch new file mode 100644 index 00000000..bc852224 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-rotate_rotate.h.patch @@ -0,0 +1,153 @@ +diff -drupN a/drivers/media/platform/ingenic-rotate/rotate.h b/drivers/media/platform/ingenic-rotate/rotate.h +--- a/drivers/media/platform/ingenic-rotate/rotate.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-rotate/rotate.h 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,149 @@ ++/* * drivers/media/platform/ingenic_rotate/rotate.h ++ * ++ * Copyright (C) 2016 Ingenic Semiconductor Inc. ++ * ++ * Author:clwang ++ * ++ * 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. ++ */ ++ ++#ifndef __ROTATER_H__ ++#define __ROTATER_H__ ++ ++#include ++#include ++#include ++ ++#define JZ_ROT_NAME "jz-rot" ++#define ROT_DESC_NUM 1 ++ ++#define DEFAULT_WIDTH (100) ++#define DEFAULT_HEIGHT (100) ++ ++#define MIN_WIDTH (4) ++#define MIN_HEIGHT (4) ++#define MAX_WIDTH (1280) ++#define MAX_HEIGHT (1280) ++ ++#define MEM2MEM_CAPTURE (1 << 0) ++#define MEM2MEM_OUTPUT (1 << 1) ++ ++//#define ROT_QCK_STOP ++//#define ROT_GEN_STOP ++ ++typedef unsigned int uint32_t; ++typedef unsigned short uint16_t; ++typedef unsigned char uint8_t; ++ ++typedef union frame_stop { ++ uint32_t d32; ++ struct { ++ uint32_t stop:1; ++ uint32_t reserve31_1:31; ++ } b; ++} frame_stop_t; ++ ++typedef union irq_ctrl { ++ uint32_t d32; ++ struct { ++ uint32_t reserve1_0:2; ++ uint32_t eof_mask:1; ++ uint32_t sof_mask:1; ++ uint32_t reserve31_4:28; ++ } b; ++} irq_ctrl_t; ++ ++struct ingenic_rot_desc { ++ uint32_t NextCfgAddr; ++ uint32_t SrcBufferAddr; ++ uint32_t SrcStride; ++ frame_stop_t FrameStop; ++ uint32_t TargetBufferAddr; ++ uint32_t TargetStride; ++ irq_ctrl_t irq_ctrl; ++} __attribute__ ((aligned(8))); ++ ++struct rot_fmt { ++ char *name; ++ u32 fourcc; ++ int depth; ++ u32 types; ++}; ++ ++struct rot_frm_info { ++ uint32_t width; ++ uint32_t height; ++ ++ struct rot_fmt *fmt; ++ ++ uint32_t bytesperline; ++ uint32_t size; ++}; ++ ++struct ingenic_rot_ctx { ++ struct v4l2_fh fh; ++ struct ingenic_rot_dev *dev; ++ struct v4l2_m2m_ctx *m2m_ctx; ++ struct v4l2_ctrl_handler ctrl_handler; ++ struct rot_frm_info in; ++ struct rot_frm_info out; ++ struct v4l2_ctrl *ctrl_hflip; ++ struct v4l2_ctrl *ctrl_vflip; ++ struct v4l2_ctrl *ctrl_rot; ++ uint32_t vflip; ++ uint32_t hflip; ++ uint32_t angle; ++ struct ingenic_rot_desc *desc[ROT_DESC_NUM]; ++ dma_addr_t desc_phys[ROT_DESC_NUM]; ++}; ++ ++struct ingenic_rot_dev { ++ struct device *dev; ++ struct v4l2_device v4l2_dev; ++ struct v4l2_m2m_dev *m2m_dev; ++ struct video_device *vfd; ++ struct mutex mutex; ++ spinlock_t ctrl_lock; ++ atomic_t num_inst; ++ struct vb2_alloc_ctx *alloc_ctx; ++ void __iomem *regs; ++ struct clk *clk; ++ struct ingenic_rot_ctx *curr; ++ int irq; ++ wait_queue_head_t irq_queue; ++#if defined(ROT_QCK_STOP) || defined(ROT_GEN_STOP) ++ struct work_struct rot_work; ++#endif ++}; ++ ++static inline unsigned long reg_read(struct ingenic_rot_dev *dev, int offset) ++{ ++ return readl(dev->regs + offset); ++} ++ ++static inline void reg_write(struct ingenic_rot_dev *dev, int offset, unsigned long val) ++{ ++ writel(val, dev->regs + offset); ++} ++ ++void rot_set_src_desc(struct ingenic_rot_dev *dev, dma_addr_t addr); ++void rot_set_dst_desc(struct ingenic_rot_dev *dev, dma_addr_t addr); ++void rot_set_hflip(struct ingenic_rot_dev *dev, uint32_t hflip); ++void rot_set_vflip(struct ingenic_rot_dev *dev, uint32_t vflip); ++void rot_set_angle(struct ingenic_rot_dev *dev, uint32_t angle); ++void rot_set_dst_cfg(struct ingenic_rot_dev *dev, struct rot_frm_info *out); ++void rot_set_src_cfg(struct ingenic_rot_dev *dev, struct rot_frm_info *in); ++int wait_rot_state(struct ingenic_rot_dev *dev, int32_t state, uint32_t flag); ++void dump_all(struct ingenic_rot_dev *dev); ++void dump_rot_desc_reg(struct ingenic_rot_dev *dev); ++void dump_rot_desc(struct ingenic_rot_desc *desc); ++void rot_clr_irq(struct ingenic_rot_dev *dev); ++void rot_gen_stop(struct ingenic_rot_dev *dev); ++void rot_qck_stop(struct ingenic_rot_dev *dev); ++void rot_start(struct ingenic_rot_dev *dev); ++void rot_reset(struct ingenic_rot_dev *dev); ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_Makefile.patch new file mode 100644 index 00000000..42b89170 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_Makefile.patch @@ -0,0 +1,6 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/Makefile b/drivers/media/platform/ingenic-vcodec/Makefile +--- a/drivers/media/platform/ingenic-vcodec/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/Makefile 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,2 @@ ++obj-y += helix/ ++obj-n += felix/ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_felix_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_felix_Makefile.patch new file mode 100644 index 00000000..f744da1b --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_felix_Makefile.patch @@ -0,0 +1,16 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/felix/Makefile b/drivers/media/platform/ingenic-vcodec/felix/Makefile +--- a/drivers/media/platform/ingenic-vcodec/felix/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/felix/Makefile 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,12 @@ ++ ++ccflags-y += -Idrivers/media/platform/ingenic-vcodec/felix/libh264/ ++ccflags-y += -Idrivers/media/platform/ingenic-vcodec/felix/libh264/libavcodec/ ++ccflags-y += -Idrivers/media/platform/ingenic-vcodec/felix/libh264/libavutil/ ++ ++obj-y += felix_ops.o ++obj-y += felix_drv.o ++ ++obj-y += libh264/ ++ ++ ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_felix_api_jzm_h264_dec.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_felix_api_jzm_h264_dec.c.patch new file mode 100644 index 00000000..a533ccdd --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_felix_api_jzm_h264_dec.c.patch @@ -0,0 +1,1127 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/felix/api/jzm_h264_dec.c b/drivers/media/platform/ingenic-vcodec/felix/api/jzm_h264_dec.c +--- a/drivers/media/platform/ingenic-vcodec/felix/api/jzm_h264_dec.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/felix/api/jzm_h264_dec.c 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,1123 @@ ++#ifndef _JZM_H264_API_C_ ++#define _JZM_H264_API_C_ ++ ++#include "jzm_h264_dec.h" ++ ++__place_k0_data__ unsigned lps_comb[128]={ ++ 0xefcfaffe,0xefcfafff,0xe2c4a6fe,0xe2c4a6ff,0xd7ba9dfe,0xd7ba9dff,0xccb195f4,0xccb195f5, ++ 0xc2a88de6,0xc2a88de7,0xb89f86dc,0xb89f86dd,0xae977fd0,0xae977fd1,0xa58f79c6,0xa58f79c7, ++ 0x9d8873bc,0x9d8873bd,0x95816db2,0x95816db3,0x8d7a67a8,0x8d7a67a9,0x867462a0,0x867462a1, ++ 0x7f6e5d98,0x7f6e5d99,0x79685890,0x79685891,0x73635488,0x73635489,0x6d5e4f82,0x6d5e4f83, ++ 0x67594b7a,0x67594b7b,0x62554774,0x62554775,0x5d50446e,0x5d50446f,0x584c4068,0x584c4069, ++ 0x54483d64,0x54483d65,0x4f443a5e,0x4f443a5f,0x4b41375a,0x4b41375b,0x473e3454,0x473e3455, ++ 0x443a3150,0x443a3151,0x40372f4c,0x40372f4d,0x3d352c48,0x3d352c49,0x3a322a44,0x3a322a45, ++ 0x372f2840,0x372f2841,0x342d263e,0x342d263f,0x312a243a,0x312a243b,0x2f282238,0x2f282239, ++ 0x2c262034,0x2c262035,0x2a241e32,0x2a241e33,0x28221d2e,0x28221d2f,0x26201b2c,0x26201b2d, ++ 0x241f1a2a,0x241f1a2b,0x221d1928,0x221d1929,0x201c1726,0x201c1727,0x1e1a1624,0x1e1a1625, ++ 0x1d191522,0x1d191523,0x1b181420,0x1b181421,0x1a16131e,0x1a16131f,0x1815121c,0x1815121d, ++ 0x1714111a,0x1714111b,0x1613101a,0x1613101b,0x15120f18,0x15120f19,0x14110e16,0x14110e17, ++ 0x13100d16,0x13100d17,0x120f0d14,0x120f0d15,0x110e0c14,0x110e0c15,0x100e0b12,0x100e0b13, ++ 0xf0d0b12,0xf0d0b13,0xe0c0a10,0xe0c0a11,0xd0b0a10,0xd0b0a11,0xd0b090e,0xd0b090f,0xc0a080e, ++ 0xc0a080f,0xb0a080c,0xb0a080d,0xb09080c,0xb09080d,0xa09070c,0xa09070d,0xa08070a,0xa08070b, ++ 0x908060a,0x908060b,0x807060a,0x807060b,0x1010102,0x1010103 ++}; ++ ++__place_k0_data__ struct SDE_VLC_STA sde_vlc2_sta[7] = { ++ {0 , 128, 6}, // vlc_tables_coeff_token_table_0 ++ {128, 116, 5}, // vlc_tables_coeff_token_table_1 ++ {256, 104, 6}, // vlc_tables_coeff_token_table_2 ++ {384, 64, 6}, // vlc_tables_coeff_token_table_3 ++ {512, 70, 6}, // vlc_tables_chroma_dc_coeff_token_table ++ {640, 74, 6}, // vlc_tables_total_zeros_table_0 ++ {768, 96, 6}, // vlc_tables_run7_table ++}; ++__place_k0_data__ unsigned short sde_vlc2_table[7][128]={ ++ { // 0 ++ 0xa020, 0x887c, 0x806c, 0x200f, 0x100a, 0x100a, 0x100a, 0x100a, ++ 0x0805, 0x0805, 0x0805, 0x0805, 0x0805, 0x0805, 0x0805, 0x0805, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 32 ++ 0xa040, 0x9070, 0x8078, 0x807a, 0x2023, 0x201a, 0x2015, 0x2010, ++ 0x181f, 0x181f, 0x1816, 0x1816, 0x1811, 0x1811, 0x180c, 0x180c, ++ 0x101b, 0x101b, 0x101b, 0x101b, 0x1012, 0x1012, 0x1012, 0x1012, ++ 0x100d, 0x100d, 0x100d, 0x100d, 0x1008, 0x1008, 0x1008, 0x1008, // 64 ++ 0x4001, 0x2035, 0x8060, 0x8062, 0x8064, 0x8066, 0x8068, 0x806a, ++ 0x203b, 0x2036, 0x2031, 0x2030, 0x2037, 0x2032, 0x202d, 0x202c, ++ 0x1833, 0x1833, 0x182e, 0x182e, 0x1829, 0x1829, 0x1828, 0x1828, ++ 0x182f, 0x182f, 0x182a, 0x182a, 0x1825, 0x1825, 0x1824, 0x1824, // 96 ++ 0x0040, 0x0042, 0x0041, 0x003c, 0x0043, 0x003e, 0x003d, 0x0038, // 104 ++ 0x003f, 0x003a, 0x0039, 0x0034, 0x0009, 0x0004, 0x4000, 0x4000, // 112 ++ 0x1020, 0x1026, 0x1021, 0x101c, 0x102b, 0x1022, 0x101d, 0x1018, // 120 ++ 0x0027, 0x001e, 0x0019, 0x0014, 0x0817, 0x080e, 0x0013, 0x0013, // 128 ++ }, ++ { // 1 ++ 0xa020, 0x8868, 0x806c, 0x806e, 0x8070, 0x8072, 0x2017, 0x2009, ++ 0x1813, 0x1813, 0x180f, 0x180f, 0x100a, 0x100a, 0x100a, 0x100a, ++ 0x0805, 0x0805, 0x0805, 0x0805, 0x0805, 0x0805, 0x0805, 0x0805, ++ 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, ++ 0x9840, 0x9050, 0x8858, 0x885c, 0x8060, 0x8062, 0x8064, 0x8066, ++ 0x1827, 0x1827, 0x181e, 0x181e, 0x181d, 0x181d, 0x1818, 0x1818, ++ 0x1014, 0x1014, 0x1014, 0x1014, 0x101a, 0x101a, 0x101a, 0x101a, ++ 0x1019, 0x1019, 0x1019, 0x1019, 0x1010, 0x1010, 0x1010, 0x1010, ++ 0x4001, 0x4001, 0x103f, 0x103f, 0x1843, 0x1842, 0x1841, 0x1840, ++ 0x183d, 0x183c, 0x183e, 0x1839, 0x103a, 0x103a, 0x1038, 0x1038, ++ 0x103b, 0x1036, 0x1035, 0x1034, 0x1037, 0x1032, 0x1031, 0x1030, ++ 0x082c, 0x082e, 0x082d, 0x0828, 0x0833, 0x082a, 0x0829, 0x0824, ++ 0x002f, 0x0026, 0x0025, 0x0020, 0x002b, 0x0022, 0x0021, 0x001c, ++ 0x0823, 0x0816, 0x0815, 0x080c, 0x001f, 0x0012, 0x0011, 0x0008, ++ 0x001b, 0x000e, 0x000d, 0x0004, ++ }, ++ { // 2 ++ 0x9840, 0x9050, 0x8858, 0x885c, 0x8060, 0x8062, 0x8064, 0x8066, ++ 0x280c, 0x281e, 0x281d, 0x2808, 0x2827, 0x281a, 0x2819, 0x2804, ++ 0x2015, 0x2015, 0x2016, 0x2016, 0x2011, 0x2011, 0x2012, 0x2012, ++ 0x200d, 0x200d, 0x2023, 0x2023, 0x200e, 0x200e, 0x2009, 0x2009, ++ 0x181f, 0x181f, 0x181f, 0x181f, 0x181b, 0x181b, 0x181b, 0x181b, ++ 0x1817, 0x1817, 0x1817, 0x1817, 0x1813, 0x1813, 0x1813, 0x1813, ++ 0x180f, 0x180f, 0x180f, 0x180f, 0x180a, 0x180a, 0x180a, 0x180a, ++ 0x1805, 0x1805, 0x1805, 0x1805, 0x1800, 0x1800, 0x1800, 0x1800, ++ 0x4001, 0x1840, 0x1843, 0x1842, 0x1841, 0x183c, 0x183f, 0x183e, ++ 0x183d, 0x1838, 0x183b, 0x183a, 0x1839, 0x1834, 0x1035, 0x1035, ++ 0x1030, 0x1036, 0x1031, 0x102c, 0x1037, 0x1032, 0x102d, 0x1028, ++ 0x0833, 0x082e, 0x0829, 0x0824, 0x082f, 0x082a, 0x0825, 0x0820, ++ 0x001c, 0x0018, 0x0026, 0x0014, 0x002b, 0x0022, 0x0021, 0x0010, ++ }, ++ { // 3 ++ 0x2804, 0x2805, 0x4001, 0x2800, 0x2808, 0x2809, 0x280a, 0x4001, ++ 0x280c, 0x280d, 0x280e, 0x280f, 0x2810, 0x2811, 0x2812, 0x2813, ++ 0x2814, 0x2815, 0x2816, 0x2817, 0x2818, 0x2819, 0x281a, 0x281b, ++ 0x281c, 0x281d, 0x281e, 0x281f, 0x2820, 0x2821, 0x2822, 0x2823, ++ 0x2824, 0x2825, 0x2826, 0x2827, 0x2828, 0x2829, 0x282a, 0x282b, ++ 0x282c, 0x282d, 0x282e, 0x282f, 0x2830, 0x2831, 0x2832, 0x2833, ++ 0x2834, 0x2835, 0x2836, 0x2837, 0x2838, 0x2839, 0x283a, 0x283b, ++ 0x283c, 0x283d, 0x283e, 0x283f, 0x2840, 0x2841, 0x2842, 0x2843, ++ }, ++ { // 4 ++ 0x8840, 0x8044, 0x2810, 0x280c, 0x2808, 0x280f, 0x2809, 0x2804, ++ 0x100a, 0x100a, 0x100a, 0x100a, 0x100a, 0x100a, 0x100a, 0x100a, ++ 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, ++ 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, ++ 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, ++ 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, ++ 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, ++ 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, ++ 0x0013, 0x0013, 0x0812, 0x0811, 0x000e, 0x000d, ++ }, ++ { ++ 0x9040, 0x8048, 0x2808, 0x2807, 0x2006, 0x2006, 0x2005, 0x2005, ++ 0x1804, 0x1804, 0x1804, 0x1804, 0x1803, 0x1803, 0x1803, 0x1803, ++ 0x1002, 0x1002, 0x1002, 0x1002, 0x1002, 0x1002, 0x1002, 0x1002, ++ 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x4001, 0x100f, 0x100e, 0x100d, 0x080c, 0x080c, 0x080b, 0x080b, ++ 0x000a, 0x0009, ++ }, ++ { ++ 0xa040, 0x2809, 0x2008, 0x2008, 0x1807, 0x1807, 0x1807, 0x1807, ++ 0x1006, 0x1006, 0x1006, 0x1006, 0x1006, 0x1006, 0x1006, 0x1006, ++ 0x1005, 0x1005, 0x1005, 0x1005, 0x1005, 0x1005, 0x1005, 0x1005, ++ 0x1004, 0x1004, 0x1004, 0x1004, 0x1004, 0x1004, 0x1004, 0x1004, ++ 0x1003, 0x1003, 0x1003, 0x1003, 0x1003, 0x1003, 0x1003, 0x1003, ++ 0x1002, 0x1002, 0x1002, 0x1002, 0x1002, 0x1002, 0x1002, 0x1002, ++ 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, ++ 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, ++ 0x4001, 0x200e, 0x180d, 0x180d, 0x100c, 0x100c, 0x100c, 0x100c, ++ 0x080b, 0x080b, 0x080b, 0x080b, 0x080b, 0x080b, 0x080b, 0x080b, ++ 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, ++ 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, ++ }, ++}; ++ ++__place_k0_data__ char cabac_context_init_I[460][2] = ++{ ++ /* 0 - 10 */ ++ { 20, -15 }, { 2, 54 }, { 3, 74 }, { 20, -15 }, ++ { 2, 54 }, { 3, 74 }, { -28,127 }, { -23, 104 }, ++ { -6, 53 }, { -1, 54 }, { 7, 51 }, ++ ++ /* 11 - 23 unsused for I */ ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ { 0, 0 }, ++ ++ /* 24- 39 */ ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ ++ /* 40 - 53 */ ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ { 0, 0 }, { 0, 0 }, ++ ++ /* 54 - 59 */ ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ { 0, 0 }, { 0, 0 }, ++ ++ /* 60 - 69 */ ++ { 0, 41 }, { 0, 63 }, { 0, 63 }, { 0, 63 }, ++ { -9, 83 }, { 4, 86 }, { 0, 97 }, { -7, 72 }, ++ { 13, 41 }, { 3, 62 }, ++ ++ /* 70 -> 87 */ ++ { 0, 11 }, { 1, 55 }, { 0, 69 }, { -17, 127 }, ++ { -13, 102 },{ 0, 82 }, { -7, 74 }, { -21, 107 }, ++ { -27, 127 },{ -31, 127 },{ -24, 127 }, { -18, 95 }, ++ { -27, 127 },{ -21, 114 },{ -30, 127 }, { -17, 123 }, ++ { -12, 115 },{ -16, 122 }, ++ ++ /* 88 -> 104 */ ++ { -11, 115 },{ -12, 63 }, { -2, 68 }, { -15, 84 }, ++ { -13, 104 },{ -3, 70 }, { -8, 93 }, { -10, 90 }, ++ { -30, 127 },{ -1, 74 }, { -6, 97 }, { -7, 91 }, ++ { -20, 127 },{ -4, 56 }, { -5, 82 }, { -7, 76 }, ++ { -22, 125 }, ++ ++ /* 105 -> 135 */ ++ { -7, 93 }, { -11, 87 }, { -3, 77 }, { -5, 71 }, ++ { -4, 63 }, { -4, 68 }, { -12, 84 }, { -7, 62 }, ++ { -7, 65 }, { 8, 61 }, { 5, 56 }, { -2, 66 }, ++ { 1, 64 }, { 0, 61 }, { -2, 78 }, { 1, 50 }, ++ { 7, 52 }, { 10, 35 }, { 0, 44 }, { 11, 38 }, ++ { 1, 45 }, { 0, 46 }, { 5, 44 }, { 31, 17 }, ++ { 1, 51 }, { 7, 50 }, { 28, 19 }, { 16, 33 }, ++ { 14, 62 }, { -13, 108 },{ -15, 100 }, ++ ++ /* 136 -> 165 */ ++ { -13, 101 },{ -13, 91 }, { -12, 94 }, { -10, 88 }, ++ { -16, 84 }, { -10, 86 }, { -7, 83 }, { -13, 87 }, ++ { -19, 94 }, { 1, 70 }, { 0, 72 }, { -5, 74 }, ++ { 18, 59 }, { -8, 102 }, { -15, 100 }, { 0, 95 }, ++ { -4, 75 }, { 2, 72 }, { -11, 75 }, { -3, 71 }, ++ { 15, 46 }, { -13, 69 }, { 0, 62 }, { 0, 65 }, ++ { 21, 37 }, { -15, 72 }, { 9, 57 }, { 16, 54 }, ++ { 0, 62 }, { 12, 72 }, ++ ++ /* 166 -> 196 */ ++ { 24, 0 }, { 15, 9 }, { 8, 25 }, { 13, 18 }, ++ { 15, 9 }, { 13, 19 }, { 10, 37 }, { 12, 18 }, ++ { 6, 29 }, { 20, 33 }, { 15, 30 }, { 4, 45 }, ++ { 1, 58 }, { 0, 62 }, { 7, 61 }, { 12, 38 }, ++ { 11, 45 }, { 15, 39 }, { 11, 42 }, { 13, 44 }, ++ { 16, 45 }, { 12, 41 }, { 10, 49 }, { 30, 34 }, ++ { 18, 42 }, { 10, 55 }, { 17, 51 }, { 17, 46 }, ++ { 0, 89 }, { 26, -19 }, { 22, -17 }, ++ ++ /* 197 -> 226 */ ++ { 26, -17 }, { 30, -25 }, { 28, -20 }, { 33, -23 }, ++ { 37, -27 }, { 33, -23 }, { 40, -28 }, { 38, -17 }, ++ { 33, -11 }, { 40, -15 }, { 41, -6 }, { 38, 1 }, ++ { 41, 17 }, { 30, -6 }, { 27, 3 }, { 26, 22 }, ++ { 37, -16 }, { 35, -4 }, { 38, -8 }, { 38, -3 }, ++ { 37, 3 }, { 38, 5 }, { 42, 0 }, { 35, 16 }, ++ { 39, 22 }, { 14, 48 }, { 27, 37 }, { 21, 60 }, ++ { 12, 68 }, { 2, 97 }, ++ ++ /* 227 -> 251 */ ++ { -3, 71 }, { -6, 42 }, { -5, 50 }, { -3, 54 }, ++ { -2, 62 }, { 0, 58 }, { 1, 63 }, { -2, 72 }, ++ { -1, 74 }, { -9, 91 }, { -5, 67 }, { -5, 27 }, ++ { -3, 39 }, { -2, 44 }, { 0, 46 }, { -16, 64 }, ++ { -8, 68 }, { -10, 78 }, { -6, 77 }, { -10, 86 }, ++ { -12, 92 }, { -15, 55 }, { -10, 60 }, { -6, 62 }, ++ { -4, 65 }, ++ ++ /* 252 -> 275 */ ++ { -12, 73 }, { -8, 76 }, { -7, 80 }, { -9, 88 }, ++ { -17, 110 },{ -11, 97 }, { -20, 84 }, { -11, 79 }, ++ { -6, 73 }, { -4, 74 }, { -13, 86 }, { -13, 96 }, ++ { -11, 97 }, { -19, 117 },{ -8, 78 }, { -5, 33 }, ++ { -4, 48 }, { -2, 53 }, { -3, 62 }, { -13, 71 }, ++ { -10, 79 }, { -12, 86 }, { -13, 90 }, { -14, 97 }, ++ ++ /* 276 a bit special (not used, bypass is used instead) */ ++ { 0, 0 }, ++ ++ /* 277 -> 307 */ ++ { -6, 93 }, { -6, 84 }, { -8, 79 }, { 0, 66 }, ++ { -1, 71 }, { 0, 62 }, { -2, 60 }, { -2, 59 }, ++ { -5, 75 }, { -3, 62 }, { -4, 58 }, { -9, 66 }, ++ { -1, 79 }, { 0, 71 }, { 3, 68 }, { 10, 44 }, ++ { -7, 62 }, { 15, 36 }, { 14, 40 }, { 16, 27 }, ++ { 12, 29 }, { 1, 44 }, { 20, 36 }, { 18, 32 }, ++ { 5, 42 }, { 1, 48 }, { 10, 62 }, { 17, 46 }, ++ { 9, 64 }, { -12, 104 },{ -11, 97 }, ++ ++ /* 308 -> 337 */ ++ { -16, 96 }, { -7, 88 }, { -8, 85 }, { -7, 85 }, ++ { -9, 85 }, { -13, 88 }, { 4, 66 }, { -3, 77 }, ++ { -3, 76 }, { -6, 76 }, { 10, 58 }, { -1, 76 }, ++ { -1, 83 }, { -7, 99 }, { -14, 95 }, { 2, 95 }, ++ { 0, 76 }, { -5, 74 }, { 0, 70 }, { -11, 75 }, ++ { 1, 68 }, { 0, 65 }, { -14, 73 }, { 3, 62 }, ++ { 4, 62 }, { -1, 68 }, { -13, 75 }, { 11, 55 }, ++ { 5, 64 }, { 12, 70 }, ++ ++ /* 338 -> 368 */ ++ { 15, 6 }, { 6, 19 }, { 7, 16 }, { 12, 14 }, ++ { 18, 13 }, { 13, 11 }, { 13, 15 }, { 15, 16 }, ++ { 12, 23 }, { 13, 23 }, { 15, 20 }, { 14, 26 }, ++ { 14, 44 }, { 17, 40 }, { 17, 47 }, { 24, 17 }, ++ { 21, 21 }, { 25, 22 }, { 31, 27 }, { 22, 29 }, ++ { 19, 35 }, { 14, 50 }, { 10, 57 }, { 7, 63 }, ++ { -2, 77 }, { -4, 82 }, { -3, 94 }, { 9, 69 }, ++ { -12, 109 },{ 36, -35 }, { 36, -34 }, ++ ++ /* 369 -> 398 */ ++ { 32, -26 }, { 37, -30 }, { 44, -32 }, { 34, -18 }, ++ { 34, -15 }, { 40, -15 }, { 33, -7 }, { 35, -5 }, ++ { 33, 0 }, { 38, 2 }, { 33, 13 }, { 23, 35 }, ++ { 13, 58 }, { 29, -3 }, { 26, 0 }, { 22, 30 }, ++ { 31, -7 }, { 35, -15 }, { 34, -3 }, { 34, 3 }, ++ { 36, -1 }, { 34, 5 }, { 32, 11 }, { 35, 5 }, ++ { 34, 12 }, { 39, 11 }, { 30, 29 }, { 34, 26 }, ++ { 29, 39 }, { 19, 66 }, ++ ++ /* 399 -> 435 */ ++ { 31, 21 }, { 31, 31 }, { 25, 50 }, ++ { -17, 120 }, { -20, 112 }, { -18, 114 }, { -11, 85 }, ++ { -15, 92 }, { -14, 89 }, { -26, 71 }, { -15, 81 }, ++ { -14, 80 }, { 0, 68 }, { -14, 70 }, { -24, 56 }, ++ { -23, 68 }, { -24, 50 }, { -11, 74 }, { 23, -13 }, ++ { 26, -13 }, { 40, -15 }, { 49, -14 }, { 44, 3 }, ++ { 45, 6 }, { 44, 34 }, { 33, 54 }, { 19, 82 }, ++ { -3, 75 }, { -1, 23 }, { 1, 34 }, { 1, 43 }, ++ { 0, 54 }, { -2, 55 }, { 0, 61 }, { 1, 64 }, ++ { 0, 68 }, { -9, 92 }, ++ ++ /* 436 -> 459 */ ++ { -14, 106 }, { -13, 97 }, { -15, 90 }, { -12, 90 }, ++ { -18, 88 }, { -10, 73 }, { -9, 79 }, { -14, 86 }, ++ { -10, 73 }, { -10, 70 }, { -10, 69 }, { -5, 66 }, ++ { -9, 64 }, { -5, 58 }, { 2, 59 }, { 21, -10 }, ++ { 24, -11 }, { 28, -8 }, { 28, -1 }, { 29, 3 }, ++ { 29, 9 }, { 35, 20 }, { 29, 36 }, { 14, 67 } ++}; ++__place_k0_data__ char cabac_context_init_PB[3][460][2] = ++{ ++ /* i_cabac_init_idc == 0 */ ++ { ++ /* 0 - 10 */ ++ { 20, -15 }, { 2, 54 }, { 3, 74 }, { 20, -15 }, ++ { 2, 54 }, { 3, 74 }, { -28, 127 }, { -23, 104 }, ++ { -6, 53 }, { -1, 54 }, { 7, 51 }, ++ ++ /* 11 - 23 */ ++ { 23, 33 }, { 23, 2 }, { 21, 0 }, { 1, 9 }, ++ { 0, 49 }, { -37, 118 }, { 5, 57 }, { -13, 78 }, ++ { -11, 65 }, { 1, 62 }, { 12, 49 }, { -4, 73 }, ++ { 17, 50 }, ++ ++ /* 24 - 39 */ ++ { 18, 64 }, { 9, 43 }, { 29, 0 }, { 26, 67 }, ++ { 16, 90 }, { 9, 104 }, { -46, 127 }, { -20, 104 }, ++ { 1, 67 }, { -13, 78 }, { -11, 65 }, { 1, 62 }, ++ { -6, 86 }, { -17, 95 }, { -6, 61 }, { 9, 45 }, ++ ++ /* 40 - 53 */ ++ { -3, 69 }, { -6, 81 }, { -11, 96 }, { 6, 55 }, ++ { 7, 67 }, { -5, 86 }, { 2, 88 }, { 0, 58 }, ++ { -3, 76 }, { -10, 94 }, { 5, 54 }, { 4, 69 }, ++ { -3, 81 }, { 0, 88 }, ++ ++ /* 54 - 59 */ ++ { -7, 67 }, { -5, 74 }, { -4, 74 }, { -5, 80 }, ++ { -7, 72 }, { 1, 58 }, ++ ++ /* 60 - 69 */ ++ { 0, 41 }, { 0, 63 }, { 0, 63 }, { 0, 63 }, ++ { -9, 83 }, { 4, 86 }, { 0, 97 }, { -7, 72 }, ++ { 13, 41 }, { 3, 62 }, ++ ++ /* 70 - 87 */ ++ { 0, 45 }, { -4, 78 }, { -3, 96 }, { -27, 126 }, ++ { -28, 98 }, { -25, 101 }, { -23, 67 }, { -28, 82 }, ++ { -20, 94 }, { -16, 83 }, { -22, 110 }, { -21, 91 }, ++ { -18, 102 }, { -13, 93 }, { -29, 127 }, { -7, 92 }, ++ { -5, 89 }, { -7, 96 }, { -13, 108 }, { -3, 46 }, ++ { -1, 65 }, { -1, 57 }, { -9, 93 }, { -3, 74 }, ++ { -9, 92 }, { -8, 87 }, { -23, 126 }, { 5, 54 }, ++ { 6, 60 }, { 6, 59 }, { 6, 69 }, { -1, 48 }, ++ { 0, 68 }, { -4, 69 }, { -8, 88 }, ++ ++ /* 105 -> 165 */ ++ { -2, 85 }, { -6, 78 }, { -1, 75 }, { -7, 77 }, ++ { 2, 54 }, { 5, 50 }, { -3, 68 }, { 1, 50 }, ++ { 6, 42 }, { -4, 81 }, { 1, 63 }, { -4, 70 }, ++ { 0, 67 }, { 2, 57 }, { -2, 76 }, { 11, 35 }, ++ { 4, 64 }, { 1, 61 }, { 11, 35 }, { 18, 25 }, ++ { 12, 24 }, { 13, 29 }, { 13, 36 }, { -10, 93 }, ++ { -7, 73 }, { -2, 73 }, { 13, 46 }, { 9, 49 }, ++ { -7, 100 }, { 9, 53 }, { 2, 53 }, { 5, 53 }, ++ { -2, 61 }, { 0, 56 }, { 0, 56 }, { -13, 63 }, ++ { -5, 60 }, { -1, 62 }, { 4, 57 }, { -6, 69 }, ++ { 4, 57 }, { 14, 39 }, { 4, 51 }, { 13, 68 }, ++ { 3, 64 }, { 1, 61 }, { 9, 63 }, { 7, 50 }, ++ { 16, 39 }, { 5, 44 }, { 4, 52 }, { 11, 48 }, ++ { -5, 60 }, { -1, 59 }, { 0, 59 }, { 22, 33 }, ++ { 5, 44 }, { 14, 43 }, { -1, 78 }, { 0, 60 }, ++ { 9, 69 }, ++ ++ /* 166 - 226 */ ++ { 11, 28 }, { 2, 40 }, { 3, 44 }, { 0, 49 }, ++ { 0, 46 }, { 2, 44 }, { 2, 51 }, { 0, 47 }, ++ { 4, 39 }, { 2, 62 }, { 6, 46 }, { 0, 54 }, ++ { 3, 54 }, { 2, 58 }, { 4, 63 }, { 6, 51 }, ++ { 6, 57 }, { 7, 53 }, { 6, 52 }, { 6, 55 }, ++ { 11, 45 }, { 14, 36 }, { 8, 53 }, { -1, 82 }, ++ { 7, 55 }, { -3, 78 }, { 15, 46 }, { 22, 31 }, ++ { -1, 84 }, { 25, 7 }, { 30, -7 }, { 28, 3 }, ++ { 28, 4 }, { 32, 0 }, { 34, -1 }, { 30, 6 }, ++ { 30, 6 }, { 32, 9 }, { 31, 19 }, { 26, 27 }, ++ { 26, 30 }, { 37, 20 }, { 28, 34 }, { 17, 70 }, ++ { 1, 67 }, { 5, 59 }, { 9, 67 }, { 16, 30 }, ++ { 18, 32 }, { 18, 35 }, { 22, 29 }, { 24, 31 }, ++ { 23, 38 }, { 18, 43 }, { 20, 41 }, { 11, 63 }, ++ { 9, 59 }, { 9, 64 }, { -1, 94 }, { -2, 89 }, ++ { -9, 108 }, ++ ++ /* 227 - 275 */ ++ { -6, 76 }, { -2, 44 }, { 0, 45 }, { 0, 52 }, ++ { -3, 64 }, { -2, 59 }, { -4, 70 }, { -4, 75 }, ++ { -8, 82 }, { -17, 102 }, { -9, 77 }, { 3, 24 }, ++ { 0, 42 }, { 0, 48 }, { 0, 55 }, { -6, 59 }, ++ { -7, 71 }, { -12, 83 }, { -11, 87 }, { -30, 119 }, ++ { 1, 58 }, { -3, 29 }, { -1, 36 }, { 1, 38 }, ++ { 2, 43 }, { -6, 55 }, { 0, 58 }, { 0, 64 }, ++ { -3, 74 }, { -10, 90 }, { 0, 70 }, { -4, 29 }, ++ { 5, 31 }, { 7, 42 }, { 1, 59 }, { -2, 58 }, ++ { -3, 72 }, { -3, 81 }, { -11, 97 }, { 0, 58 }, ++ { 8, 5 }, { 10, 14 }, { 14, 18 }, { 13, 27 }, ++ { 2, 40 }, { 0, 58 }, { -3, 70 }, { -6, 79 }, ++ { -8, 85 }, ++ ++ /* 276 a bit special (not used, bypass is used instead) */ ++ { 0, 0 }, ++ ++ /* 277 - 337 */ ++ { -13, 106 }, { -16, 106 }, { -10, 87 }, { -21, 114 }, ++ { -18, 110 }, { -14, 98 }, { -22, 110 }, { -21, 106 }, ++ { -18, 103 }, { -21, 107 }, { -23, 108 }, { -26, 112 }, ++ { -10, 96 }, { -12, 95 }, { -5, 91 }, { -9, 93 }, ++ { -22, 94 }, { -5, 86 }, { 9, 67 }, { -4, 80 }, ++ { -10, 85 }, { -1, 70 }, { 7, 60 }, { 9, 58 }, ++ { 5, 61 }, { 12, 50 }, { 15, 50 }, { 18, 49 }, ++ { 17, 54 }, { 10, 41 }, { 7, 46 }, { -1, 51 }, ++ { 7, 49 }, { 8, 52 }, { 9, 41 }, { 6, 47 }, ++ { 2, 55 }, { 13, 41 }, { 10, 44 }, { 6, 50 }, ++ { 5, 53 }, { 13, 49 }, { 4, 63 }, { 6, 64 }, ++ { -2, 69 }, { -2, 59 }, { 6, 70 }, { 10, 44 }, ++ { 9, 31 }, { 12, 43 }, { 3, 53 }, { 14, 34 }, ++ { 10, 38 }, { -3, 52 }, { 13, 40 }, { 17, 32 }, ++ { 7, 44 }, { 7, 38 }, { 13, 50 }, { 10, 57 }, ++ { 26, 43 }, ++ ++ /* 338 - 398 */ ++ { 14, 11 }, { 11, 14 }, { 9, 11 }, { 18, 11 }, ++ { 21, 9 }, { 23, -2 }, { 32, -15 }, { 32, -15 }, ++ { 34, -21 }, { 39, -23 }, { 42, -33 }, { 41, -31 }, ++ { 46, -28 }, { 38, -12 }, { 21, 29 }, { 45, -24 }, ++ { 53, -45 }, { 48, -26 }, { 65, -43 }, { 43, -19 }, ++ { 39, -10 }, { 30, 9 }, { 18, 26 }, { 20, 27 }, ++ { 0, 57 }, { -14, 82 }, { -5, 75 }, { -19, 97 }, ++ { -35, 125 }, { 27, 0 }, { 28, 0 }, { 31, -4 }, ++ { 27, 6 }, { 34, 8 }, { 30, 10 }, { 24, 22 }, ++ { 33, 19 }, { 22, 32 }, { 26, 31 }, { 21, 41 }, ++ { 26, 44 }, { 23, 47 }, { 16, 65 }, { 14, 71 }, ++ { 8, 60 }, { 6, 63 }, { 17, 65 }, { 21, 24 }, ++ { 23, 20 }, { 26, 23 }, { 27, 32 }, { 28, 23 }, ++ { 28, 24 }, { 23, 40 }, { 24, 32 }, { 28, 29 }, ++ { 23, 42 }, { 19, 57 }, { 22, 53 }, { 22, 61 }, ++ { 11, 86 }, ++ ++ /* 399 - 435 */ ++ { 12, 40 }, { 11, 51 }, { 14, 59 }, ++ { -4, 79 }, { -7, 71 }, { -5, 69 }, { -9, 70 }, ++ { -8, 66 }, { -10, 68 }, { -19, 73 }, { -12, 69 }, ++ { -16, 70 }, { -15, 67 }, { -20, 62 }, { -19, 70 }, ++ { -16, 66 }, { -22, 65 }, { -20, 63 }, { 9, -2 }, ++ { 26, -9 }, { 33, -9 }, { 39, -7 }, { 41, -2 }, ++ { 45, 3 }, { 49, 9 }, { 45, 27 }, { 36, 59 }, ++ { -6, 66 }, { -7, 35 }, { -7, 42 }, { -8, 45 }, ++ { -5, 48 }, { -12, 56 }, { -6, 60 }, { -5, 62 }, ++ { -8, 66 }, { -8, 76 }, ++ ++ /* 436 - 459 */ ++ { -5, 85 }, { -6, 81 }, { -10, 77 }, { -7, 81 }, ++ { -17, 80 }, { -18, 73 }, { -4, 74 }, { -10, 83 }, ++ { -9, 71 }, { -9, 67 }, { -1, 61 }, { -8, 66 }, ++ { -14, 66 }, { 0, 59 }, { 2, 59 }, { 21, -13 }, ++ { 33, -14 }, { 39, -7 }, { 46, -2 }, { 51, 2 }, ++ { 60, 6 }, { 61, 17 }, { 55, 34 }, { 42, 62 }, ++ }, ++ ++ /* i_cabac_init_idc == 1 */ ++ { ++ /* 0 - 10 */ ++ { 20, -15 }, { 2, 54 }, { 3, 74 }, { 20, -15 }, ++ { 2, 54 }, { 3, 74 }, { -28, 127 }, { -23, 104 }, ++ { -6, 53 }, { -1, 54 }, { 7, 51 }, ++ ++ /* 11 - 23 */ ++ { 22, 25 }, { 34, 0 }, { 16, 0 }, { -2, 9 }, ++ { 4, 41 }, { -29, 118 }, { 2, 65 }, { -6, 71 }, ++ { -13, 79 }, { 5, 52 }, { 9, 50 }, { -3, 70 }, ++ { 10, 54 }, ++ ++ /* 24 - 39 */ ++ { 26, 34 }, { 19, 22 }, { 40, 0 }, { 57, 2 }, ++ { 41, 36 }, { 26, 69 }, { -45, 127 }, { -15, 101 }, ++ { -4, 76 }, { -6, 71 }, { -13, 79 }, { 5, 52 }, ++ { 6, 69 }, { -13, 90 }, { 0, 52 }, { 8, 43 }, ++ ++ /* 40 - 53 */ ++ { -2, 69 },{ -5, 82 },{ -10, 96 },{ 2, 59 }, ++ { 2, 75 },{ -3, 87 },{ -3, 100 },{ 1, 56 }, ++ { -3, 74 },{ -6, 85 },{ 0, 59 },{ -3, 81 }, ++ { -7, 86 },{ -5, 95 }, ++ ++ /* 54 - 59 */ ++ { -1, 66 },{ -1, 77 },{ 1, 70 },{ -2, 86 }, ++ { -5, 72 },{ 0, 61 }, ++ ++ /* 60 - 69 */ ++ { 0, 41 }, { 0, 63 }, { 0, 63 }, { 0, 63 }, ++ { -9, 83 }, { 4, 86 }, { 0, 97 }, { -7, 72 }, ++ { 13, 41 }, { 3, 62 }, ++ ++ /* 70 - 104 */ ++ { 13, 15 }, { 7, 51 }, { 2, 80 }, { -39, 127 }, ++ { -18, 91 }, { -17, 96 }, { -26, 81 }, { -35, 98 }, ++ { -24, 102 }, { -23, 97 }, { -27, 119 }, { -24, 99 }, ++ { -21, 110 }, { -18, 102 }, { -36, 127 }, { 0, 80 }, ++ { -5, 89 }, { -7, 94 }, { -4, 92 }, { 0, 39 }, ++ { 0, 65 }, { -15, 84 }, { -35, 127 }, { -2, 73 }, ++ { -12, 104 }, { -9, 91 }, { -31, 127 }, { 3, 55 }, ++ { 7, 56 }, { 7, 55 }, { 8, 61 }, { -3, 53 }, ++ { 0, 68 }, { -7, 74 }, { -9, 88 }, ++ ++ /* 105 -> 165 */ ++ { -13, 103 }, { -13, 91 }, { -9, 89 }, { -14, 92 }, ++ { -8, 76 }, { -12, 87 }, { -23, 110 }, { -24, 105 }, ++ { -10, 78 }, { -20, 112 }, { -17, 99 }, { -78, 127 }, ++ { -70, 127 }, { -50, 127 }, { -46, 127 }, { -4, 66 }, ++ { -5, 78 }, { -4, 71 }, { -8, 72 }, { 2, 59 }, ++ { -1, 55 }, { -7, 70 }, { -6, 75 }, { -8, 89 }, ++ { -34, 119 }, { -3, 75 }, { 32, 20 }, { 30, 22 }, ++ { -44, 127 }, { 0, 54 }, { -5, 61 }, { 0, 58 }, ++ { -1, 60 }, { -3, 61 }, { -8, 67 }, { -25, 84 }, ++ { -14, 74 }, { -5, 65 }, { 5, 52 }, { 2, 57 }, ++ { 0, 61 }, { -9, 69 }, { -11, 70 }, { 18, 55 }, ++ { -4, 71 }, { 0, 58 }, { 7, 61 }, { 9, 41 }, ++ { 18, 25 }, { 9, 32 }, { 5, 43 }, { 9, 47 }, ++ { 0, 44 }, { 0, 51 }, { 2, 46 }, { 19, 38 }, ++ { -4, 66 }, { 15, 38 }, { 12, 42 }, { 9, 34 }, ++ { 0, 89 }, ++ ++ /* 166 - 226 */ ++ { 4, 45 }, { 10, 28 }, { 10, 31 }, { 33, -11 }, ++ { 52, -43 }, { 18, 15 }, { 28, 0 }, { 35, -22 }, ++ { 38, -25 }, { 34, 0 }, { 39, -18 }, { 32, -12 }, ++ { 102, -94 }, { 0, 0 }, { 56, -15 }, { 33, -4 }, ++ { 29, 10 }, { 37, -5 }, { 51, -29 }, { 39, -9 }, ++ { 52, -34 }, { 69, -58 }, { 67, -63 }, { 44, -5 }, ++ { 32, 7 }, { 55, -29 }, { 32, 1 }, { 0, 0 }, ++ { 27, 36 }, { 33, -25 }, { 34, -30 }, { 36, -28 }, ++ { 38, -28 }, { 38, -27 }, { 34, -18 }, { 35, -16 }, ++ { 34, -14 }, { 32, -8 }, { 37, -6 }, { 35, 0 }, ++ { 30, 10 }, { 28, 18 }, { 26, 25 }, { 29, 41 }, ++ { 0, 75 }, { 2, 72 }, { 8, 77 }, { 14, 35 }, ++ { 18, 31 }, { 17, 35 }, { 21, 30 }, { 17, 45 }, ++ { 20, 42 }, { 18, 45 }, { 27, 26 }, { 16, 54 }, ++ { 7, 66 }, { 16, 56 }, { 11, 73 }, { 10, 67 }, ++ { -10, 116 }, ++ ++ /* 227 - 275 */ ++ { -23, 112 }, { -15, 71 }, { -7, 61 }, { 0, 53 }, ++ { -5, 66 }, { -11, 77 }, { -9, 80 }, { -9, 84 }, ++ { -10, 87 }, { -34, 127 }, { -21, 101 }, { -3, 39 }, ++ { -5, 53 }, { -7, 61 }, { -11, 75 }, { -15, 77 }, ++ { -17, 91 }, { -25, 107 }, { -25, 111 }, { -28, 122 }, ++ { -11, 76 }, { -10, 44 }, { -10, 52 }, { -10, 57 }, ++ { -9, 58 }, { -16, 72 }, { -7, 69 }, { -4, 69 }, ++ { -5, 74 }, { -9, 86 }, { 2, 66 }, { -9, 34 }, ++ { 1, 32 }, { 11, 31 }, { 5, 52 }, { -2, 55 }, ++ { -2, 67 }, { 0, 73 }, { -8, 89 }, { 3, 52 }, ++ { 7, 4 }, { 10, 8 }, { 17, 8 }, { 16, 19 }, ++ { 3, 37 }, { -1, 61 }, { -5, 73 }, { -1, 70 }, ++ { -4, 78 }, ++ ++ /* 276 a bit special (not used, bypass is used instead) */ ++ { 0, 0 }, ++ ++ /* 277 - 337 */ ++ { -21, 126 }, { -23, 124 }, { -20, 110 }, { -26, 126 }, ++ { -25, 124 }, { -17, 105 }, { -27, 121 }, { -27, 117 }, ++ { -17, 102 }, { -26, 117 }, { -27, 116 }, { -33, 122 }, ++ { -10, 95 }, { -14, 100 }, { -8, 95 }, { -17, 111 }, ++ { -28, 114 }, { -6, 89 }, { -2, 80 }, { -4, 82 }, ++ { -9, 85 }, { -8, 81 }, { -1, 72 }, { 5, 64 }, ++ { 1, 67 }, { 9, 56 }, { 0, 69 }, { 1, 69 }, ++ { 7, 69 }, { -7, 69 }, { -6, 67 }, { -16, 77 }, ++ { -2, 64 }, { 2, 61 }, { -6, 67 }, { -3, 64 }, ++ { 2, 57 }, { -3, 65 }, { -3, 66 }, { 0, 62 }, ++ { 9, 51 }, { -1, 66 }, { -2, 71 }, { -2, 75 }, ++ { -1, 70 }, { -9, 72 }, { 14, 60 }, { 16, 37 }, ++ { 0, 47 }, { 18, 35 }, { 11, 37 }, { 12, 41 }, ++ { 10, 41 }, { 2, 48 }, { 12, 41 }, { 13, 41 }, ++ { 0, 59 }, { 3, 50 }, { 19, 40 }, { 3, 66 }, ++ { 18, 50 }, ++ ++ /* 338 - 398 */ ++ { 19, -6 }, { 18, -6 }, { 14, 0 }, { 26, -12 }, ++ { 31, -16 }, { 33, -25 }, { 33, -22 }, { 37, -28 }, ++ { 39, -30 }, { 42, -30 }, { 47, -42 }, { 45, -36 }, ++ { 49, -34 }, { 41, -17 }, { 32, 9 }, { 69, -71 }, ++ { 63, -63 }, { 66, -64 }, { 77, -74 }, { 54, -39 }, ++ { 52, -35 }, { 41, -10 }, { 36, 0 }, { 40, -1 }, ++ { 30, 14 }, { 28, 26 }, { 23, 37 }, { 12, 55 }, ++ { 11, 65 }, { 37, -33 }, { 39, -36 }, { 40, -37 }, ++ { 38, -30 }, { 46, -33 }, { 42, -30 }, { 40, -24 }, ++ { 49, -29 }, { 38, -12 }, { 40, -10 }, { 38, -3 }, ++ { 46, -5 }, { 31, 20 }, { 29, 30 }, { 25, 44 }, ++ { 12, 48 }, { 11, 49 }, { 26, 45 }, { 22, 22 }, ++ { 23, 22 }, { 27, 21 }, { 33, 20 }, { 26, 28 }, ++ { 30, 24 }, { 27, 34 }, { 18, 42 }, { 25, 39 }, ++ { 18, 50 }, { 12, 70 }, { 21, 54 }, { 14, 71 }, ++ { 11, 83 }, ++ ++ /* 399 - 435 */ ++ { 25, 32 }, { 21, 49 }, { 21, 54 }, ++ { -5, 85 }, { -6, 81 }, { -10, 77 }, { -7, 81 }, ++ { -17, 80 }, { -18, 73 }, { -4, 74 }, { -10, 83 }, ++ { -9, 71 }, { -9, 67 }, { -1, 61 }, { -8, 66 }, ++ { -14, 66 }, { 0, 59 }, { 2, 59 }, { 17, -10 }, ++ { 32, -13 }, { 42, -9 }, { 49, -5 }, { 53, 0 }, ++ { 64, 3 }, { 68, 10 }, { 66, 27 }, { 47, 57 }, ++ { -5, 71 }, { 0, 24 }, { -1, 36 }, { -2, 42 }, ++ { -2, 52 }, { -9, 57 }, { -6, 63 }, { -4, 65 }, ++ { -4, 67 }, { -7, 82 }, ++ ++ /* 436 - 459 */ ++ { -3, 81 }, { -3, 76 }, { -7, 72 }, { -6, 78 }, ++ { -12, 72 }, { -14, 68 }, { -3, 70 }, { -6, 76 }, ++ { -5, 66 }, { -5, 62 }, { 0, 57 }, { -4, 61 }, ++ { -9, 60 }, { 1, 54 }, { 2, 58 }, { 17, -10 }, ++ { 32, -13 }, { 42, -9 }, { 49, -5 }, { 53, 0 }, ++ { 64, 3 }, { 68, 10 }, { 66, 27 }, { 47, 57 }, ++ }, ++ ++ /* i_cabac_init_idc == 2 */ ++ { ++ /* 0 - 10 */ ++ { 20, -15 }, { 2, 54 }, { 3, 74 }, { 20, -15 }, ++ { 2, 54 }, { 3, 74 }, { -28, 127 }, { -23, 104 }, ++ { -6, 53 }, { -1, 54 }, { 7, 51 }, ++ ++ /* 11 - 23 */ ++ { 29, 16 }, { 25, 0 }, { 14, 0 }, { -10, 51 }, ++ { -3, 62 }, { -27, 99 }, { 26, 16 }, { -4, 85 }, ++ { -24, 102 }, { 5, 57 }, { 6, 57 }, { -17, 73 }, ++ { 14, 57 }, ++ ++ /* 24 - 39 */ ++ { 20, 40 }, { 20, 10 }, { 29, 0 }, { 54, 0 }, ++ { 37, 42 }, { 12, 97 }, { -32, 127 }, { -22, 117 }, ++ { -2, 74 }, { -4, 85 }, { -24, 102 }, { 5, 57 }, ++ { -6, 93 }, { -14, 88 }, { -6, 44 }, { 4, 55 }, ++ ++ /* 40 - 53 */ ++ { -11, 89 },{ -15, 103 },{ -21, 116 },{ 19, 57 }, ++ { 20, 58 },{ 4, 84 },{ 6, 96 },{ 1, 63 }, ++ { -5, 85 },{ -13, 106 },{ 5, 63 },{ 6, 75 }, ++ { -3, 90 },{ -1, 101 }, ++ ++ /* 54 - 59 */ ++ { 3, 55 },{ -4, 79 },{ -2, 75 },{ -12, 97 }, ++ { -7, 50 },{ 1, 60 }, ++ ++ /* 60 - 69 */ ++ { 0, 41 }, { 0, 63 }, { 0, 63 }, { 0, 63 }, ++ { -9, 83 }, { 4, 86 }, { 0, 97 }, { -7, 72 }, ++ { 13, 41 }, { 3, 62 }, ++ ++ /* 70 - 104 */ ++ { 7, 34 }, { -9, 88 }, { -20, 127 }, { -36, 127 }, ++ { -17, 91 }, { -14, 95 }, { -25, 84 }, { -25, 86 }, ++ { -12, 89 }, { -17, 91 }, { -31, 127 }, { -14, 76 }, ++ { -18, 103 }, { -13, 90 }, { -37, 127 }, { 11, 80 }, ++ { 5, 76 }, { 2, 84 }, { 5, 78 }, { -6, 55 }, ++ { 4, 61 }, { -14, 83 }, { -37, 127 }, { -5, 79 }, ++ { -11, 104 }, { -11, 91 }, { -30, 127 }, { 0, 65 }, ++ { -2, 79 }, { 0, 72 }, { -4, 92 }, { -6, 56 }, ++ { 3, 68 }, { -8, 71 }, { -13, 98 }, ++ ++ /* 105 -> 165 */ ++ { -4, 86 }, { -12, 88 }, { -5, 82 }, { -3, 72 }, ++ { -4, 67 }, { -8, 72 }, { -16, 89 }, { -9, 69 }, ++ { -1, 59 }, { 5, 66 }, { 4, 57 }, { -4, 71 }, ++ { -2, 71 }, { 2, 58 }, { -1, 74 }, { -4, 44 }, ++ { -1, 69 }, { 0, 62 }, { -7, 51 }, { -4, 47 }, ++ { -6, 42 }, { -3, 41 }, { -6, 53 }, { 8, 76 }, ++ { -9, 78 }, { -11, 83 }, { 9, 52 }, { 0, 67 }, ++ { -5, 90 }, { 1, 67 }, { -15, 72 }, { -5, 75 }, ++ { -8, 80 }, { -21, 83 }, { -21, 64 }, { -13, 31 }, ++ { -25, 64 }, { -29, 94 }, { 9, 75 }, { 17, 63 }, ++ { -8, 74 }, { -5, 35 }, { -2, 27 }, { 13, 91 }, ++ { 3, 65 }, { -7, 69 }, { 8, 77 }, { -10, 66 }, ++ { 3, 62 }, { -3, 68 }, { -20, 81 }, { 0, 30 }, ++ { 1, 7 }, { -3, 23 }, { -21, 74 }, { 16, 66 }, ++ { -23, 124 }, { 17, 37 }, { 44, -18 }, { 50, -34 }, ++ { -22, 127 }, ++ ++ /* 166 - 226 */ ++ { 4, 39 }, { 0, 42 }, { 7, 34 }, { 11, 29 }, ++ { 8, 31 }, { 6, 37 }, { 7, 42 }, { 3, 40 }, ++ { 8, 33 }, { 13, 43 }, { 13, 36 }, { 4, 47 }, ++ { 3, 55 }, { 2, 58 }, { 6, 60 }, { 8, 44 }, ++ { 11, 44 }, { 14, 42 }, { 7, 48 }, { 4, 56 }, ++ { 4, 52 }, { 13, 37 }, { 9, 49 }, { 19, 58 }, ++ { 10, 48 }, { 12, 45 }, { 0, 69 }, { 20, 33 }, ++ { 8, 63 }, { 35, -18 }, { 33, -25 }, { 28, -3 }, ++ { 24, 10 }, { 27, 0 }, { 34, -14 }, { 52, -44 }, ++ { 39, -24 }, { 19, 17 }, { 31, 25 }, { 36, 29 }, ++ { 24, 33 }, { 34, 15 }, { 30, 20 }, { 22, 73 }, ++ { 20, 34 }, { 19, 31 }, { 27, 44 }, { 19, 16 }, ++ { 15, 36 }, { 15, 36 }, { 21, 28 }, { 25, 21 }, ++ { 30, 20 }, { 31, 12 }, { 27, 16 }, { 24, 42 }, ++ { 0, 93 }, { 14, 56 }, { 15, 57 }, { 26, 38 }, ++ { -24, 127 }, ++ ++ /* 227 - 275 */ ++ { -24, 115 }, { -22, 82 }, { -9, 62 }, { 0, 53 }, ++ { 0, 59 }, { -14, 85 }, { -13, 89 }, { -13, 94 }, ++ { -11, 92 }, { -29, 127 }, { -21, 100 }, { -14, 57 }, ++ { -12, 67 }, { -11, 71 }, { -10, 77 }, { -21, 85 }, ++ { -16, 88 }, { -23, 104 }, { -15, 98 }, { -37, 127 }, ++ { -10, 82 }, { -8, 48 }, { -8, 61 }, { -8, 66 }, ++ { -7, 70 }, { -14, 75 }, { -10, 79 }, { -9, 83 }, ++ { -12, 92 }, { -18, 108 }, { -4, 79 }, { -22, 69 }, ++ { -16, 75 }, { -2, 58 }, { 1, 58 }, { -13, 78 }, ++ { -9, 83 }, { -4, 81 }, { -13, 99 }, { -13, 81 }, ++ { -6, 38 }, { -13, 62 }, { -6, 58 }, { -2, 59 }, ++ { -16, 73 }, { -10, 76 }, { -13, 86 }, { -9, 83 }, ++ { -10, 87 }, ++ ++ /* 276 a bit special (not used, bypass is used instead) */ ++ { 0, 0 }, ++ ++ /* 277 - 337 */ ++ { -22, 127 }, { -25, 127 }, { -25, 120 }, { -27, 127 }, ++ { -19, 114 }, { -23, 117 }, { -25, 118 }, { -26, 117 }, ++ { -24, 113 }, { -28, 118 }, { -31, 120 }, { -37, 124 }, ++ { -10, 94 }, { -15, 102 }, { -10, 99 }, { -13, 106 }, ++ { -50, 127 }, { -5, 92 }, { 17, 57 }, { -5, 86 }, ++ { -13, 94 }, { -12, 91 }, { -2, 77 }, { 0, 71 }, ++ { -1, 73 }, { 4, 64 }, { -7, 81 }, { 5, 64 }, ++ { 15, 57 }, { 1, 67 }, { 0, 68 }, { -10, 67 }, ++ { 1, 68 }, { 0, 77 }, { 2, 64 }, { 0, 68 }, ++ { -5, 78 }, { 7, 55 }, { 5, 59 }, { 2, 65 }, ++ { 14, 54 }, { 15, 44 }, { 5, 60 }, { 2, 70 }, ++ { -2, 76 }, { -18, 86 }, { 12, 70 }, { 5, 64 }, ++ { -12, 70 }, { 11, 55 }, { 5, 56 }, { 0, 69 }, ++ { 2, 65 }, { -6, 74 }, { 5, 54 }, { 7, 54 }, ++ { -6, 76 }, { -11, 82 }, { -2, 77 }, { -2, 77 }, ++ { 25, 42 }, ++ ++ /* 338 - 398 */ ++ { 17, -13 }, { 16, -9 }, { 17, -12 }, { 27, -21 }, ++ { 37, -30 }, { 41, -40 }, { 42, -41 }, { 48, -47 }, ++ { 39, -32 }, { 46, -40 }, { 52, -51 }, { 46, -41 }, ++ { 52, -39 }, { 43, -19 }, { 32, 11 }, { 61, -55 }, ++ { 56, -46 }, { 62, -50 }, { 81, -67 }, { 45, -20 }, ++ { 35, -2 }, { 28, 15 }, { 34, 1 }, { 39, 1 }, ++ { 30, 17 }, { 20, 38 }, { 18, 45 }, { 15, 54 }, ++ { 0, 79 }, { 36, -16 }, { 37, -14 }, { 37, -17 }, ++ { 32, 1 }, { 34, 15 }, { 29, 15 }, { 24, 25 }, ++ { 34, 22 }, { 31, 16 }, { 35, 18 }, { 31, 28 }, ++ { 33, 41 }, { 36, 28 }, { 27, 47 }, { 21, 62 }, ++ { 18, 31 }, { 19, 26 }, { 36, 24 }, { 24, 23 }, ++ { 27, 16 }, { 24, 30 }, { 31, 29 }, { 22, 41 }, ++ { 22, 42 }, { 16, 60 }, { 15, 52 }, { 14, 60 }, ++ { 3, 78 }, { -16, 123 }, { 21, 53 }, { 22, 56 }, ++ { 25, 61 }, ++ ++ /* 399 - 435 */ ++ { 21, 33 }, { 19, 50 }, { 17, 61 }, ++ { -3, 78 }, { -8, 74 }, { -9, 72 }, { -10, 72 }, ++ { -18, 75 }, { -12, 71 }, { -11, 63 }, { -5, 70 }, ++ { -17, 75 }, { -14, 72 }, { -16, 67 }, { -8, 53 }, ++ { -14, 59 }, { -9, 52 }, { -11, 68 }, { 9, -2 }, ++ { 30, -10 }, { 31, -4 }, { 33, -1 }, { 33, 7 }, ++ { 31, 12 }, { 37, 23 }, { 31, 38 }, { 20, 64 }, ++ { -9, 71 }, { -7, 37 }, { -8, 44 }, { -11, 49 }, ++ { -10, 56 }, { -12, 59 }, { -8, 63 }, { -9, 67 }, ++ { -6, 68 }, { -10, 79 }, ++ ++ /* 436 - 459 */ ++ { -3, 78 }, { -8, 74 }, { -9, 72 }, { -10, 72 }, ++ { -18, 75 }, { -12, 71 }, { -11, 63 }, { -5, 70 }, ++ { -17, 75 }, { -14, 72 }, { -16, 67 }, { -8, 53 }, ++ { -14, 59 }, { -9, 52 }, { -11, 68 }, { 9, -2 }, ++ { 30, -10 }, { 31, -4 }, { 33, -1 }, { 33, 7 }, ++ { 31, 12 }, { 37, 23 }, { 31, 38 }, { 20, 64 }, ++ } ++}; ++ ++ ++ ++static inline int jzm_clip2(int a, int min, int max) ++{ ++ if (a < min) return min; ++ else if (a > max) return max; ++ else return a; ++} ++ ++void jzm_h264_slice_init_vdma(struct JZM_H264 * st_h264) ++{ ++ int i, j, k; ++ volatile unsigned int *chn = (volatile unsigned int *)st_h264->des_va; ++ ++ /*------------------------------------------------------ ++ scheduler ++ ------------------------------------------------------*/ ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHC, 0, 0x0); ++ if (st_h264->slice_type == JZM_H264_I_TYPE) { ++ GEN_VDMA_ACFG(chn, REG_SCH_BND, 0, SCH_CH3_HID(HID_DBLK) | SCH_CH2_HID(HID_VMAU) | SCH_DEPTH(DESP_FIFO_WIDTH)); ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHG0, 0, 0x0); ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHE1, 0, 0x0); ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHE2, 0, 0x0); ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHE3, 0, 0x0); ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHE4, 0, 0x0); ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHC, 0, SCH_CH2_PE | SCH_CH3_PE); ++ GEN_VDMA_ACFG(chn, REG_SCH_BND, 0, SCH_CH3_HID(HID_DBLK) | SCH_CH2_HID(HID_VMAU) | ++ SCH_DEPTH(DESP_FIFO_WIDTH) | SCH_BND_G0F2 | SCH_BND_G0F3); ++ } else { ++ GEN_VDMA_ACFG(chn, REG_SCH_BND, 0, SCH_CH3_HID(HID_DBLK) | SCH_CH2_HID(HID_VMAU) | SCH_CH1_HID(HID_MCE) | ++ SCH_DEPTH(DESP_FIFO_WIDTH)); ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHG0, 0, 0x0); ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHE1, 0, 0x0); ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHE2, 0, 0x0); ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHE3, 0, 0x0); ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHE4, 0, 0x0); ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHC, 0, SCH_CH1_PE | SCH_CH2_PE | SCH_CH3_PE); ++ GEN_VDMA_ACFG(chn, REG_SCH_BND, 0, SCH_CH3_HID(HID_DBLK) | SCH_CH2_HID(HID_VMAU) | SCH_CH1_HID(HID_MCE) | ++ SCH_DEPTH(DESP_FIFO_WIDTH) | SCH_BND_G0F1 | SCH_BND_G0F2 | SCH_BND_G0F3); ++ } ++ ++ /*------------------------------------------------------ ++ vmau ++ ------------------------------------------------------*/ ++ GEN_VDMA_ACFG(chn, REG_VMAU_GBL_RUN, 0, VMAU_RESET); ++ GEN_VDMA_ACFG(chn, REG_VMAU_GBL_CTR, 0, 0); ++ GEN_VDMA_ACFG(chn, REG_VMAU_VIDEO_TYPE, 0, VMAU_FMT_H264); ++ GEN_VDMA_ACFG(chn, REG_VMAU_NCCHN_ADDR, 0, VMAU_DESP_ADDR); ++ GEN_VDMA_ACFG(chn, REG_VMAU_DEC_DONE, 0, VPU_BASE + REG_SCH_SCHE2); ++ GEN_VDMA_ACFG(chn, REG_VMAU_Y_GS, 0, st_h264->mb_width*16); ++ GEN_VDMA_ACFG(chn, REG_VMAU_GBL_CTR, 0, (VMAU_CTRL_FIFO_M | VMAU_CTRL_TO_DBLK)); ++ GEN_VDMA_ACFG(chn, REG_VMAU_POS, 0, ((st_h264->start_mb_x & 0xff) | ((st_h264->start_mb_y & 0xff)<<16))); ++ unsigned int qt_ram_addr = REG_VMAU_QT; ++ unsigned int *tbl_ptr = st_h264->scaling_matrix8; ++ for ( i = 0 ; i < 32; i++) { ++ GEN_VDMA_ACFG(chn, (qt_ram_addr+i*4), 0, tbl_ptr[i]); ++ } ++ qt_ram_addr = REG_VMAU_QT + 32*4; ++ tbl_ptr = st_h264->scaling_matrix4; ++ for ( i = 0 ; i < 24; i++) { ++ GEN_VDMA_ACFG(chn, (qt_ram_addr+i*4), 0, tbl_ptr[i]); ++ } ++ ++ /*------------------------------------------------------ ++ dblk ++ ------------------------------------------------------*/ ++ GEN_VDMA_ACFG(chn, REG_DBLK_TRIG, 0, DBLK_RESET); ++ GEN_VDMA_ACFG(chn, REG_DBLK_DHA, 0, DBLK_DESP_ADDR); ++ GEN_VDMA_ACFG(chn, REG_DBLK_GENDA, 0, VPU_BASE + REG_SCH_SCHE3); ++ GEN_VDMA_ACFG(chn, REG_DBLK_GSIZE, 0, st_h264->mb_width | (st_h264->mb_height << 16)); ++ int normal_first_slice = (st_h264->start_mb_x == 0) && (st_h264->start_mb_y == 0); ++ GEN_VDMA_ACFG(chn, REG_DBLK_GPOS, 0, ((st_h264->start_mb_x & 0x3ff) | ++ ((st_h264->start_mb_y & 0x3ff)<<16) | ++ ((!normal_first_slice)<<31)) ++ ); ++ GEN_VDMA_ACFG(chn, REG_DBLK_GPIC_YA, 0, st_h264->dec_result_y); ++ GEN_VDMA_ACFG(chn, REG_DBLK_GPIC_CA, 0, st_h264->dec_result_uv); ++ GEN_VDMA_ACFG(chn, REG_DBLK_GP_ENDA, 0, DBLK_GP_ENDF_BASE); ++#define DEBLK_VTR_FMT_I 0 ++#define DEBLK_VTR_FMT_P (1<<3) ++#define DEBLK_VTR_FMT_B (2<<3) ++#define DEBLK_VTR_BETA_SFT (16) ++#define DEBLK_VTR_BETA_MSK (0xff) ++#define DEBLK_VTR_ALPHA_SFT (24) ++#define DEBLK_VTR_ALPHA_MSK (0xff) ++ unsigned int h264_vtr = ((st_h264->slice_type == JZM_H264_I_TYPE) ? DEBLK_VTR_FMT_I : ++ ((st_h264->slice_type == JZM_H264_P_TYPE) ? DEBLK_VTR_FMT_P : DEBLK_VTR_FMT_B) ++ ) | DBLK_FMT_H264; ++ h264_vtr = h264_vtr | ((st_h264->slice_beta_offset & DEBLK_VTR_BETA_MSK) << DEBLK_VTR_BETA_SFT) ++ | ((st_h264->slice_alpha_c0_offset & DEBLK_VTR_ALPHA_MSK) << DEBLK_VTR_ALPHA_SFT); ++ GEN_VDMA_ACFG(chn, REG_DBLK_VTR, 0, h264_vtr); ++ GEN_VDMA_ACFG(chn, REG_DBLK_GPIC_STR, 0, (st_h264->mb_width*256) | (st_h264->mb_width*128)<<16); ++ ++ GEN_VDMA_ACFG(chn, REG_DBLK_GPIC_Y1A, 0, st_h264->dec_result1_y); ++ GEN_VDMA_ACFG(chn, REG_DBLK_GPIC_C1A, 0, st_h264->dec_result1_uv); ++ GEN_VDMA_ACFG(chn, REG_DBLK_GPIC_STR1, 0, (st_h264->frm_y_stride) | (st_h264->frm_c_stride)<<16); ++ GEN_VDMA_ACFG(chn, REG_DBLK_CTRL, 0, 0x1 | (st_h264->new_odma_flag)<<6 | (st_h264->new_odma_format)<<7 ); ++ ++ GEN_VDMA_ACFG(chn, REG_DBLK_TRIG, 0, DBLK_SLICE_RUN); ++ //GEN_VDMA_ACFG(chn, REG_DBLK_CTRL, 0, 0x1); ++ //write_reg(DBLK_GP_ENDF_BASE, -1); ++ ++ /*------------------------------------------------------ ++ motion ++ ------------------------------------------------------*/ ++ //video_motion_init(H264_QPEL, H264_EPEL); ++ int intpid = H264_QPEL; ++ int cintpid = H264_EPEL; ++ for(i=0; i<16; i++){ ++ GEN_VDMA_ACFG(chn, REG_MCE_CH1_ILUT+i*8, 0, ++ MCE_CH1_IINFO(IntpFMT[intpid][i].intp[0],/*intp1*/ ++ IntpFMT[intpid][i].tap,/*tap*/ ++ IntpFMT[intpid][i].intp_pkg[0],/*intp1_pkg*/ ++ IntpFMT[intpid][i].hldgl,/*hldgl*/ ++ IntpFMT[intpid][i].avsdgl,/*avsdgl*/ ++ IntpFMT[intpid][i].intp_dir[0],/*intp0_dir*/ ++ IntpFMT[intpid][i].intp_rnd[0],/*intp0_rnd*/ ++ IntpFMT[intpid][i].intp_sft[0],/*intp0_sft*/ ++ IntpFMT[intpid][i].intp_sintp[0],/*sintp0*/ ++ IntpFMT[intpid][i].intp_srnd[0],/*sintp0_rnd*/ ++ IntpFMT[intpid][i].intp_sbias[0]/*sintp0_bias*/ ++ )); ++ GEN_VDMA_ACFG(chn, REG_MCE_CH1_ILUT+i*8+4, 0, ++ MCE_CH1_IINFO(IntpFMT[intpid][i].intp[1],/*intp1*/ ++ 0,/*tap*/ ++ IntpFMT[intpid][i].intp_pkg[1],/*intp1_pkg*/ ++ IntpFMT[intpid][i].hldgl,/*hldgl*/ ++ IntpFMT[intpid][i].avsdgl,/*avsdgl*/ ++ IntpFMT[intpid][i].intp_dir[1],/*intp1_dir*/ ++ IntpFMT[intpid][i].intp_rnd[1],/*intp1_rnd*/ ++ IntpFMT[intpid][i].intp_sft[1],/*intp1_sft*/ ++ IntpFMT[intpid][i].intp_sintp[1],/*sintp1*/ ++ IntpFMT[intpid][i].intp_srnd[1],/*sintp1_rnd*/ ++ IntpFMT[intpid][i].intp_sbias[1]/*sintp1_bias*/ ++ )); ++ GEN_VDMA_ACFG(chn, REG_MCE_CH1_CLUT+i*8+4, 0, ++ MCE_RLUT_WT(IntpFMT[intpid][i].intp_coef[0][7],/*coef8*/ ++ IntpFMT[intpid][i].intp_coef[0][6],/*coef7*/ ++ IntpFMT[intpid][i].intp_coef[0][5],/*coef6*/ ++ IntpFMT[intpid][i].intp_coef[0][4]/*coef5*/ ++ )); ++ GEN_VDMA_ACFG(chn, REG_MCE_CH1_CLUT+i*8, 0, ++ MCE_RLUT_WT(IntpFMT[intpid][i].intp_coef[0][3],/*coef8*/ ++ IntpFMT[intpid][i].intp_coef[0][2],/*coef7*/ ++ IntpFMT[intpid][i].intp_coef[0][1],/*coef6*/ ++ IntpFMT[intpid][i].intp_coef[0][0]/*coef5*/ ++ )); ++ GEN_VDMA_ACFG(chn, REG_MCE_CH1_CLUT+(i+16)*8+4, 0, ++ MCE_RLUT_WT(IntpFMT[intpid][i].intp_coef[1][7],/*coef8*/ ++ IntpFMT[intpid][i].intp_coef[1][6],/*coef7*/ ++ IntpFMT[intpid][i].intp_coef[1][5],/*coef6*/ ++ IntpFMT[intpid][i].intp_coef[1][4]/*coef5*/ ++ )); ++ GEN_VDMA_ACFG(chn, REG_MCE_CH1_CLUT+(i+16)*8, 0, ++ MCE_RLUT_WT(IntpFMT[intpid][i].intp_coef[1][3],/*coef8*/ ++ IntpFMT[intpid][i].intp_coef[1][2],/*coef7*/ ++ IntpFMT[intpid][i].intp_coef[1][1],/*coef6*/ ++ IntpFMT[intpid][i].intp_coef[1][0]/*coef5*/ ++ )); ++ GEN_VDMA_ACFG(chn, REG_MCE_CH2_ILUT+i*8, 0, ++ MCE_CH2_IINFO(IntpFMT[cintpid][i].intp[0], ++ IntpFMT[cintpid][i].intp_dir[0], ++ IntpFMT[cintpid][i].intp_sft[0], ++ IntpFMT[cintpid][i].intp_coef[0][0], ++ IntpFMT[cintpid][i].intp_coef[0][1], ++ IntpFMT[cintpid][i].intp_rnd[0]) ); ++ GEN_VDMA_ACFG(chn, REG_MCE_CH2_ILUT+i*8+4, 0, ++ MCE_CH2_IINFO(IntpFMT[cintpid][i].intp[1], ++ IntpFMT[cintpid][i].intp_dir[1], ++ IntpFMT[cintpid][i].intp_sft[1], ++ IntpFMT[cintpid][i].intp_coef[1][0], ++ IntpFMT[cintpid][i].intp_coef[1][1], ++ IntpFMT[cintpid][i].intp_rnd[1]) ); ++ } ++#define STAT_PFE_SFT 2 ++#define STAT_PFE_MSK 0x1 ++#define STAT_LKE_SFT 1 ++#define STAT_LKE_MSK 0x1 ++#define STAT_TKE_SFT 0 ++#define STAT_TKE_MSK 0x1 ++#define MCE_PRI (0x3 << 9) ++ GEN_VDMA_ACFG(chn, REG_MCE_CH1_STAT, 0, ((1 & STAT_PFE_MSK )<luma_weight[0][i], st_h264->luma_offset[0][i])); ++ GEN_VDMA_ACFG(chn, REG_MCE_CH1_RLUT+(i)*8+4, 0, st_h264->mc_ref_y[0][i]); ++ GEN_VDMA_ACFG(chn, REG_MCE_CH2_RLUT+(i)*8, 0, MCE_RLUT_WT(st_h264->chroma_weight[0][i][1], st_h264->chroma_offset[0][i][1], ++ st_h264->chroma_weight[0][i][0], st_h264->chroma_offset[0][i][0])); ++ GEN_VDMA_ACFG(chn, REG_MCE_CH2_RLUT+(i)*8+4, 0, st_h264->mc_ref_c[0][i]); ++ GEN_VDMA_ACFG(chn, REG_MCE_CH1_RLUT+(16+i)*8, 0, MCE_RLUT_WT(0,0,st_h264->luma_weight[1][i], st_h264->luma_offset[1][i])); ++ GEN_VDMA_ACFG(chn, REG_MCE_CH1_RLUT+(16+i)*8+4, 0, st_h264->mc_ref_y[1][i]); ++ GEN_VDMA_ACFG(chn, REG_MCE_CH2_RLUT+(16+i)*8, 0, MCE_RLUT_WT(st_h264->chroma_weight[1][i][1], st_h264->chroma_offset[1][i][1], ++ st_h264->chroma_weight[1][i][0], st_h264->chroma_offset[1][i][0])); ++ GEN_VDMA_ACFG(chn, REG_MCE_CH2_RLUT+(16+i)*8+4, 0, st_h264->mc_ref_c[1][i]); ++ } ++ ++ for(j=0; j<16; j++){ ++ for(i=0; i<16; i+=4){ ++ GEN_VDMA_ACFG(chn, (MOTION_IWTA_BASE+j*16+i), 0, *((int*)(&st_h264->implicit_weight[j][i]))); ++ } ++ } ++ GEN_VDMA_ACFG(chn, REG_MCE_IWTA, 0, MOTION_IWTA_BASE); ++ ++ GEN_VDMA_ACFG(chn, (REG_MCE_CH1_WINFO), 0, MCE_WINFO(0, (st_h264->use_weight == IS_WT1), ++ st_h264->use_weight, 1, st_h264->luma_log2_weight_denom, 5, 0, 0)); ++ GEN_VDMA_ACFG(chn, (REG_MCE_CH1_WTRND), 0, MCE_WTRND(0, 1<<5)); ++ GEN_VDMA_ACFG(chn, (REG_MCE_CH2_WINFO1), 0, MCE_WINFO(0, st_h264->use_weight_chroma && (st_h264->use_weight == IS_WT1), ++ st_h264->use_weight, 1, st_h264->chroma_log2_weight_denom, 5, 0, 0)); ++ GEN_VDMA_ACFG(chn, (REG_MCE_CH2_WINFO2), 0, MCE_WINFO(0, 0, 0, 0, 0, 5, 0, 0)); ++ GEN_VDMA_ACFG(chn, (REG_MCE_CH2_WTRND), 0, MCE_WTRND(1<<5, 1<<5)); ++ ++ GEN_VDMA_ACFG(chn, REG_MCE_CH1_STRD, 0, MCE_STRD(st_h264->mb_width*16, 0, DOUT_Y_STRD)); ++ GEN_VDMA_ACFG(chn, REG_MCE_GEOM, 0, MCE_GEOM(st_h264->mb_height*16,st_h264->mb_width*16)); ++ GEN_VDMA_ACFG(chn, REG_MCE_CH2_STRD, 0, MCE_STRD(st_h264->mb_width*16, 0, DOUT_C_STRD)); ++ GEN_VDMA_ACFG(chn, REG_MCE_DSA, 0, VPU_BASE + REG_SCH_SCHE1); ++ GEN_VDMA_ACFG(chn, REG_MCE_DDC, 0, MC_DESP_ADDR); ++ ++ /*------------------------------------------------------ ++ sde ++ ------------------------------------------------------*/ ++ // multi-slice ++#if 0 ++ int start_mb_num= st_h264->start_mb_x + st_h264->start_mb_y * st_h264->mb_width; ++ int slice_start_mx = st_h264->start_mb_x; ++ int slice_start_my = st_h264->start_mb_y; ++ if (st_h264->slice_num == 0) { ++ for (i=0; i<32; i++) ++ st_h264->curr_frm_slice_start_mb[i] = INT_MAX; ++ } ++ int ref_frm_start_mb = 0; ++ if ( (st_h264->slice_type == JZM_H264_B_TYPE) && (st_h264->slice_num)) { ++ for (i=0; i<32; i++){ ++ if ( (start_mb_num >= st_h264->ref_frm_slice_start_mb[i]) && ++ (start_mb_num < st_h264->ref_frm_slice_start_mb[i+1]) ) ++ break; ++ } ++ ref_frm_start_mb = st_h264->ref_frm_slice_start_mb[i]; ++ } ++ st_h264->curr_frm_slice_start_mb[st_h264->slice_num] = start_mb_num; ++#else ++ int start_mb_num = st_h264->start_mb_x + st_h264->start_mb_y * st_h264->mb_width; ++ int slice_start_mx = st_h264->start_mb_x; ++ int slice_start_my = st_h264->start_mb_y; ++ int ref_frm_start_mb = start_mb_num; ++#endif ++ ++ // bs init ++ unsigned int bs_addr = st_h264->bs_buffer; ++ unsigned int bs_ofst = st_h264->bs_index; ++#if 0 ++ for (i=0; imb_height,st_h264->mb_width,slice_start_my,slice_start_mx)); ++ GEN_VDMA_ACFG(chn, REG_SDE_GL_CTRL, 0, 1); ++ GEN_VDMA_ACFG(chn, REG_SDE_CODEC_ID, 0, (1 << 0)); ++ unsigned int cfg_0 = (((!st_h264->cabac) << 0) + ++ (((st_h264->slice_type) & 0x7) << 1) + ++ (((st_h264->field_picture) & 0x1) << 4) + ++ (((st_h264->transform_8x8_mode) & 0x1) << 5) + ++ (((st_h264->constrained_intra_pred) & 0x1) << 6) + ++ (((st_h264->direct_8x8_inference_flag) & 0x1) << 7) + ++ (((st_h264->direct_spatial_mv_pred) & 0x1) << 8) + ++ ((1 & 0x1) << 9) + /*dir_max_word_64*/ ++ (((st_h264->x264_build > 33) & 0x1) << 10) + ++ (((!st_h264->x264_build) & 0x1) << 11) + ++ ((st_h264->dblk_left_en & 0x1) << 14) + ++ ((st_h264->dblk_top_en & 0x1) << 15) + ++ ((st_h264->ref_count_0 & 0xF) << 16) + ++ ((st_h264->ref_count_1 & 0xF) << 20) + ++ ((bs_ofst & 0x1F) << 24) + ++ 0 ); ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG0, 0, cfg_0); ++ unsigned int cfg_1 = (((st_h264->qscale & 0xFF) << 0) + ++ (((st_h264->deblocking_filter) & 0x1) << 8) + ++ 0); ++ //GEN_VDMA_ACFG(chn, REG_SDE_CFG1, 0, cfg_1 ); ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG1, 0, (cfg_1 + ++ ((st_h264->bs_rbsp_en & 0x1) << 16)) ); ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG2, 0, bs_addr); ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG3, 0, TOP_NEI_ADDR); ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG4, 0, RESIDUAL_DOUT_ADDR); ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG5, 0, VMAU_DESP_ADDR); ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG6, 0, DBLK_DESP_ADDR); ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG7, 0, DBLK_MV_ADDR); ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG8, 0, MC_DESP_ADDR); ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG9, 0, st_h264->ref_frm_ctrl + ref_frm_start_mb*2*4); ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG10, 0, st_h264->ref_frm_mv + ref_frm_start_mb*32*4); ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG11, 0, st_h264->curr_frm_ctrl + start_mb_num*2*4); ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG12, 0, st_h264->curr_frm_mv + start_mb_num*32*4); ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG13, 0, (start_mb_num & 0xFFFF) + (((start_mb_num - ref_frm_start_mb) & 0xFFFF) << 16)); ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG14, 0, st_h264->bs_size_in_bits); ++ ++ // ctx table init ++ unsigned int * sde_table_base = REG_SDE_CTX_TBL; ++ if (st_h264->cabac) { ++ unsigned char state; ++ for( i= 0; i < 460; i++ ) { ++ int pre; ++ if( st_h264->slice_type == JZM_H264_I_TYPE ) ++ pre = jzm_clip2( ((cabac_context_init_I[i][0] * st_h264->qscale) >>4 ) + cabac_context_init_I[i][1], 1, 126 ); ++ else ++ pre = jzm_clip2( ((cabac_context_init_PB[st_h264->cabac_init_idc][i][0] * st_h264->qscale) >>4 ) + cabac_context_init_PB[st_h264->cabac_init_idc][i][1], 1, 126 ); ++ if( pre <= 63 ) ++ state = 2 * ( 63 - pre ) + 0; ++ else ++ state = 2 * ( pre - 64 ) + 1; ++ GEN_VDMA_ACFG(chn, sde_table_base+i, 0, lps_comb[state]); ++ } ++ GEN_VDMA_ACFG(chn, sde_table_base+276, 0, lps_comb[126]); ++ } else { ++ int tbl, size; ++ for (tbl = 0; tbl < 7; tbl++) { ++ unsigned int * hw_base = sde_table_base + (sde_vlc2_sta[tbl].ram_ofst >> 1); ++ unsigned int * tbl_base = &sde_vlc2_table[tbl][0]; ++ int size = (sde_vlc2_sta[tbl].size + 1) >> 1; ++ for (i = 0; i < size; i++){ ++ GEN_VDMA_ACFG(chn, hw_base+i, 0, tbl_base[i]); ++ } ++ } ++ } ++ // direct prediction scal table ++ for (i=0; i<16; i++) { ++ GEN_VDMA_ACFG(chn, sde_table_base + 480 + i, 0, st_h264->dir_scale_table[i]); ++ } ++ // set chroma_qp table ++ unsigned int * sde_cqp_tbl = REG_SDE_CQP_TBL; ++ for(i=0;i<128;i++) { ++ GEN_VDMA_ACFG(chn, sde_cqp_tbl + i, 0, st_h264->chroma_qp_table[i]); ++ } ++ ++ GEN_VDMA_ACFG(chn, (REG_SDE_SL_CTRL), VDMA_ACFG_TERM, SDE_MB_RUN); ++} ++ ++#endif // _JZM_H264_API_C_ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_felix_api_jzm_h264_dec.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_felix_api_jzm_h264_dec.h.patch new file mode 100644 index 00000000..90f21377 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_felix_api_jzm_h264_dec.h.patch @@ -0,0 +1,126 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/felix/api/jzm_h264_dec.h b/drivers/media/platform/ingenic-vcodec/felix/api/jzm_h264_dec.h +--- a/drivers/media/platform/ingenic-vcodec/felix/api/jzm_h264_dec.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/felix/api/jzm_h264_dec.h 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,122 @@ ++#ifndef _JZM_H264_API_H_ ++#define _JZM_H264_API_H_ ++ ++#include "jzm_vpu.h" ++ ++/*-------------- vmem def --------------*/ ++#define VRAM_TCSM1_BASE (VPU_BASE + 0xC0000) ++#define VRAM_SRAM_BASE (VPU_BASE + 0xF0000) ++#ifdef JZM_SIMPLE ++#define DESP_FIFO_WIDTH 3 ++#else ++#define DESP_FIFO_WIDTH 4 ++#endif //JZM_SIMPLE ++#define DESP_FIFO_DEPTH (1 << DESP_FIFO_WIDTH) ++#define VRAM_SCH_FIFO_DEPTH DESP_FIFO_DEPTH ++#define TOP_NEI_ADDR (VRAM_TCSM1_BASE) ++#ifdef JZM_SIMPLE ++#define TOP_NEI_SIZE (80*16*4) ++#else ++#define TOP_NEI_SIZE (128*16*4) ++#endif //JZM_SIMPLE ++#define MC_DESP_ADDR (TOP_NEI_ADDR + TOP_NEI_SIZE) ++#define MC_DESP_ONE_SIZE (128*4) ++#define MC_DESP_SIZE (MC_DESP_ONE_SIZE*DESP_FIFO_DEPTH) ++#define DBLK_MV_ADDR (MC_DESP_ADDR + MC_DESP_SIZE) ++#define DBLK_MV_ONE_SIZE (64*4) ++#define DBLK_MV_SIZE (DBLK_MV_ONE_SIZE*DESP_FIFO_DEPTH) ++#define VMAU_DESP_ADDR (DBLK_MV_ADDR + DBLK_MV_SIZE) ++#define VMAU_DESP_ONE_SIZE (16*4) ++#define VMAU_DESP_SIZE (VMAU_DESP_ONE_SIZE*DESP_FIFO_DEPTH) ++#define DBLK_DESP_ADDR (VMAU_DESP_ADDR + VMAU_DESP_SIZE) ++#define DBLK_DESP_ONE_SIZE (8*4) ++#define DBLK_DESP_SIZE (DBLK_DESP_ONE_SIZE*DESP_FIFO_DEPTH) ++#define MOTION_IWTA_BASE ((DBLK_DESP_ADDR+DBLK_DESP_SIZE + 1024) & 0xFFFFFC00) ++#define MOTION_IWTA_SIZE (2048) ++#define MOTION_DSA_BASE (MOTION_IWTA_BASE + MOTION_IWTA_SIZE) ++#define MAU_ENDF_BASE (MOTION_DSA_BASE+4)//(MAU_SRC_BASE + MAU_SRC_SIZE) ++#define DBLK_ENDF_BASE ( MAU_ENDF_BASE + 4 ) ++#define DBLK_GP_ENDF_BASE ( DBLK_ENDF_BASE + 4 ) ++#define TCSM1_END (MAU_SRC_BASE+MAU_SRC_SIZE) ++#define RESIDUAL_DOUT_ADDR (VRAM_SRAM_BASE) ++#define RESIDUAL_DOUT_ONE_SIZE (256*4) ++#define RESIDUAL_DOUT_SIZE (RESIDUAL_DOUT_ONE_SIZE*DESP_FIFO_DEPTH) ++#define SRAM_END (RESIDUAL_DOUT_ADDR+RESIDUAL_DOUT_SIZE) ++#define PMON_BUF (SRAM_END) ++ ++/*----------------------------*/ ++#define JZM_H264_I_TYPE 1 ++#define JZM_H264_P_TYPE 2 ++#define JZM_H264_B_TYPE 4 ++ ++#define ROA_ALN 256 ++#define DOUT_Y_STRD 16 ++#define DOUT_C_STRD 8 ++ ++typedef struct JZM_H264{ ++ unsigned short start_mb_x; ++ unsigned short start_mb_y; ++ unsigned short mb_width; ++ unsigned short mb_height; ++ unsigned char slice_num; ++ unsigned char slice_type; ++ unsigned char qscale; /* s->qscale */ ++ unsigned char field_picture; ++ unsigned char cabac; /* h->pps.cabac */ ++ unsigned char transform_8x8_mode; /* !!h->pps.transform_8x8_mode */ ++ unsigned char constrained_intra_pred; /* !!h->pps.constrained_intra_pred */ ++ unsigned char direct_8x8_inference_flag; /* !!h->pps.direct_8x8_inference_flag */ ++ unsigned char direct_spatial_mv_pred; /* !!h->direct_spatial_mv_pred */ ++ unsigned char ref_count_0; /* h->ref_count[0] */ ++ unsigned char ref_count_1; /* h->ref_count[1] */ ++ unsigned char deblocking_filter; /* !!h->deblocking_filter */ ++ int dblk_left_en; ++ int dblk_top_en; ++ int x264_build; /* h->x264_build */ ++ int slice_alpha_c0_offset; ++ int slice_beta_offset; ++ unsigned int bs_buffer; /* s->gb.buffer */ ++ unsigned int bs_index; /* s->gb.index */ ++ unsigned int bs_size_in_bits; /* s->gb.index */ ++ int cabac_init_idc; ++/* int * curr_frm_slice_start_mb; */ ++/* int * ref_frm_slice_start_mb; */ ++ unsigned int ref_frm_ctrl; ++ unsigned int ref_frm_mv; ++ unsigned int curr_frm_ctrl; ++ unsigned int curr_frm_mv; ++ unsigned int dir_scale_table[16]; ++ unsigned int chroma_qp_table[128]; ++ unsigned char scaling_matrix8[2][64]; //2x64 ++ unsigned char scaling_matrix4[6][16]; ++ unsigned int tlb_phy_addr; ++ unsigned int dec_result_y; ++ unsigned int dec_result_uv; ++ unsigned int mc_ref_y[2][16]; ++ unsigned int mc_ref_c[2][16]; ++ unsigned int luma_weight[2][16]; ++ unsigned int luma_offset[2][16]; ++ unsigned int chroma_weight[2][16][2]; ++ unsigned int chroma_offset[2][16][2]; ++ unsigned char implicit_weight[16][16]; ++ unsigned int use_weight; ++ unsigned int use_weight_chroma; ++ unsigned int luma_log2_weight_denom; ++ unsigned int chroma_log2_weight_denom; ++ int * des_va, * des_pa; ++ unsigned char new_odma_flag; ++ unsigned char new_odma_format; //0: nv12, 1: nv21. ++ unsigned int dec_result1_y; ++ unsigned int dec_result1_uv; ++ unsigned int frm_y_stride; ++ unsigned int frm_c_stride; ++ unsigned int bs_rbsp_en; ++} jzm_h264; ++ ++typedef struct SDE_VLC_STA ++{ ++ int ram_ofst; ++ int size; ++ int lvl0_len; ++}; ++#endif // _JZM_H264_API_H_ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_felix_api_jzm_vpu.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_felix_api_jzm_vpu.h.patch new file mode 100644 index 00000000..69646551 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_felix_api_jzm_vpu.h.patch @@ -0,0 +1,2678 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/felix/api/jzm_vpu.h b/drivers/media/platform/ingenic-vcodec/felix/api/jzm_vpu.h +--- a/drivers/media/platform/ingenic-vcodec/felix/api/jzm_vpu.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/felix/api/jzm_vpu.h 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,2674 @@ ++/**************************************************************** ++*****************************************************************/ ++#ifndef __JZM_VPU_H__ ++#define __JZM_VPU_H__ ++ ++/**************************************************************** ++ VPU register map ++*****************************************************************/ ++ ++#ifdef JZM_HUNT_SIM ++# include "hunt.h" ++#else ++# define __place_k0_data__ ++# define __place_k0_text__ ++#endif ++ ++#define VPU_BASE 0x13200000 ++ ++#define HID_SCH 0x0 ++#define HID_VDMA 0x1 ++#define HID_EFE 0x4 ++#define HID_MCE 0x5 ++#define HID_DBLK 0x7 ++#define HID_VMAU 0x8 ++#define HID_SDE 0x9 ++#define HID_AUX 0xA ++#define HID_TCSM 0xB ++#define HID_JPGC 0xE ++#define HID_SRAM 0xF ++ ++#define VPU_MAX_MB_WIDTH 256 ++ ++#define MSCOPE_START(mbnum) write_reg(VPU_BASE+0x24, mbnum) ++#define MSCOPE_STOP() write_reg(VPU_BASE+0x28, 0) ++ ++/******************************************** ++ SCH (Scheduler) ++*********************************************/ ++#define TCSM_FLUSH 0xc0000 ++#define REG_SCH_GLBC 0x00000 ++#define SCH_GLBC_SLDE (0x1<<31) ++#define SCH_GLBC_TLBE (0x1<<30) ++#define SCH_GLBC_TLBINV (0x1<<29) ++#define SCH_INTE_ACFGERR (0x1<<20) ++#define SCH_INTE_TLBERR (0x1<<18) ++#define SCH_INTE_BSERR (0x1<<17) ++#define SCH_INTE_ENDF (0x1<<16) ++#define SCH_GLBC_HIMAP (0x1<<15) ++#define SCH_GLBC_HIAXI (0x1<<9) ++#define SCH_GLBC_EPRI0 (0x0<<7) ++#define SCH_GLBC_EPRI1 (0x1<<7) ++#define SCH_GLBC_EPRI2 (0x2<<7) ++#define SCH_GLBC_EPRI3 (0x3<<7) ++ ++#define REG_SCH_TLBA 0x00030 ++ ++#define REG_SCH_STAT 0x00034 ++ ++#define REG_SCH_SLDE0 0x00040 ++#define REG_SCH_SLDE1 0x00044 ++#define REG_SCH_SLDE2 0x00048 ++#define REG_SCH_SLDE3 0x0004C ++#define SCH_SLD_VTAG(val) (((val) & 0xFFF)<<20) ++#define SCH_SLD_MASK(val) (((val) & 0xFFF)<<8) ++#define SCH_SLD_VLD (0x1<<0) ++ ++#define REG_SCH_SCHC 0x00060 ++#define SCH_CH1_PCH(ch) (((ch) & 0x3)<<0) ++#define SCH_CH2_PCH(ch) (((ch) & 0x3)<<8) ++#define SCH_CH3_PCH(ch) (((ch) & 0x3)<<16) ++#define SCH_CH4_PCH(ch) (((ch) & 0x3)<<24) ++#define SCH_CH1_PE (0x1<<2) ++#define SCH_CH2_PE (0x1<<10) ++#define SCH_CH3_PE (0x1<<18) ++#define SCH_CH4_PE (0x1<<26) ++#define SCH_CH1_GS0 (0x0<<3) ++#define SCH_CH1_GS1 (0x1<<3) ++#define SCH_CH2_GS0 (0x0<<11) ++#define SCH_CH2_GS1 (0x1<<11) ++#define SCH_CH3_GS0 (0x0<<19) ++#define SCH_CH3_GS1 (0x1<<19) ++#define SCH_CH4_GS0 (0x0<<27) ++#define SCH_CH4_GS1 (0x1<<27) ++ ++#define REG_SCH_BND 0x00064 ++#define SCH_CH1_HID(hid) (((hid) & 0xF)<<16) ++#define SCH_CH2_HID(hid) (((hid) & 0xF)<<20) ++#define SCH_CH3_HID(hid) (((hid) & 0xF)<<24) ++#define SCH_CH4_HID(hid) (((hid) & 0xF)<<28) ++#define SCH_BND_G0F1 (0x1<<0) ++#define SCH_BND_G0F2 (0x1<<1) ++#define SCH_BND_G0F3 (0x1<<2) ++#define SCH_BND_G0F4 (0x1<<3) ++#define SCH_BND_G1F1 (0x1<<4) ++#define SCH_BND_G1F2 (0x1<<5) ++#define SCH_BND_G1F3 (0x1<<6) ++#define SCH_BND_G1F4 (0x1<<7) ++#define SCH_DEPTH(val) (((val-1) & 0xF)<<8) ++ ++#define REG_SCH_SCHG0 0x00068 ++#define REG_SCH_SCHG1 0x0006C ++#define REG_SCH_SCHE1 0x00070 ++#define REG_SCH_SCHE2 0x00074 ++#define REG_SCH_SCHE3 0x00078 ++#define REG_SCH_SCHE4 0x0007C ++ ++#define DSA_SCH_CH1 (VPU_BASE | REG_SCH_SCHE1) ++#define DSA_SCH_CH2 (VPU_BASE | REG_SCH_SCHE2) ++#define DSA_SCH_CH3 (VPU_BASE | REG_SCH_SCHE3) ++#define DSA_SCH_CH4 (VPU_BASE | REG_SCH_SCHE4) ++ ++/******************************************** ++ VDMA (VPU general-purpose DMA) ++*********************************************/ ++#define REG_VDMA_LOCK 0x10000 ++#define REG_VDMA_UNLK 0x10004 ++ ++#define REG_VDMA_TASKRG 0x10008 ++#define VDMA_ACFG_RUN (0x1) ++#define VDMA_DESC_RUN (0x3) ++#define VDMA_ACFG_CLR (0x8) ++#define VDMA_ACFG_SAFE (0x4) ++#define VDMA_ACFG_DHA(a) (((unsigned int)(a)) & 0xFFFFFF80) ++#define VDMA_DESC_DHA(a) (((unsigned int)(a)) & 0xFFFF0) ++ ++#define REG_VDMA_TASKST 0x1000C ++#define VDMA_ACFG_ERR (0x1<<3) ++#define VDMA_ACFG_END (0x1<<2) ++#define VDMA_DESC_END (0x1<<1) ++#define VDMA_VPU_BUSY (0x1<<0) ++ ++#define VDMA_DESC_EXTSEL (0x1<<0) ++#define VDMA_DESC_TLBSEL (0x1<<1) ++#define VDMA_DESC_LK (0x1<<31) ++ ++#define VDMA_ACFG_VLD (0x1<<31) ++#define VDMA_ACFG_TERM (0x1<<30) ++#define VDMA_ACFG_IDX(a) (((unsigned int)(a)) & 0xFFFFC) ++ ++#define GEN_VDMA_ACFG(chn, reg, lk, val) \ ++({*chn++ = val; \ ++ *chn++ = (VDMA_ACFG_VLD | (lk) | VDMA_ACFG_IDX(reg)); \ ++}) ++ ++/******************************************** ++ EFE (Encoder Front End) ++*********************************************/ ++#define REG_EFE_CTRL 0x40000 ++#define EFE_BP_MBY(mb) (((mb) & 0xFF)<<24) ++#define EFE_BP_MBX(mb) (((mb) & 0xFF)<<16) ++#define EFE_X264_QP(qp) (((qp) & 0x3F)<<8) ++#define EFE_DBLK_EN (0x1<<5) ++#define EFE_SLICE_TYPE(a) (((a) & 0x1)<<4) ++#define EFE_DEBUG_EN (0x1<<2) ++#define EFE_EN (0x1<<1) ++#define EFE_RUN (0x1<<0) ++ ++#define REG_EFE_GEOM 0x40004 ++#define EFE_FST_MBY(mb) (((mb) & 0xFF)<<24) ++#define EFE_FST_MBX(mb) (((0/*FIXME*/) & 0xFF)<<16) ++#define EFE_LST_MBY(mb) (((mb) & 0xFF)<<8) ++#define EFE_LST_MBX(mb) (((mb) & 0xFF)<<0) ++ ++#define REG_EFE_COEF_BA 0x4000C ++#define REG_EFE_RAWY_SBA 0x40010 ++#define REG_EFE_RAWC_SBA 0x40014 ++#define REG_EFE_TOPMV_BA 0x40018 ++#define REG_EFE_TOPPA_BA 0x4001C ++#define REG_EFE_MECHN_BA 0x40020 ++#define REG_EFE_MAUCHN_BA 0x40024 ++#define REG_EFE_DBLKCHN_BA 0x40028 ++#define REG_EFE_SDECHN_BA 0x4002C ++#define REG_EFE_RAW_DBA 0x40030 ++#define REG_EFE_MVRP 0x40100 ++#define REG_EFE_STAT 0x40110 ++ ++/******************************************** ++ MCE (Motion Compensation/Estimation COMBO) ++*********************************************/ ++#define REG_MCE_CTRL 0x50000 ++#define MCE_ESTI_MAX_BDIA(a) (((a) & 0xF)<<28) ++#define MCE_ESTI_MAX_SDIA(a) (((a) & 0xF)<<24) ++#define MCE_ESTI_USE_PMV (0x1<<22) ++#define MCE_ESTI_INTPEL (0x0<<20) ++#define MCE_ESTI_HPEL (0x2<<20) ++#define MCE_ESTI_QPEL (0x3<<20) ++#define MCE_ESTI_PUT_MET (0x1<<19) ++#define MCE_COMP_AUTO_EXPD (0x1<<17) ++#define MCE_CH2_EN (0x1<<11) ++#define MCE_CLKG_EN (0x1<<8) ++#define MCE_OFA_EN (0x1<<7) ++#define MCE_MODE_COMP (0x0<<4) ++#define MCE_MODE_ESTI (0x1<<4) ++#define MCE_CACHE_FLUSH (0x1<<3) ++#define MCE_EN (0x1<<0) ++ ++#define REG_MCE_CH1_STAT 0x50004 ++#define REG_MCE_CH2_STAT 0x50804 ++#define MCE_PREF_END (0x1<<2) ++#define MCE_LINK_END (0x1<<1) ++#define MCE_TASK_END (0x1<<0) ++ ++#define REG_MCE_MVPA 0x5000C ++#define REG_MCE_IWTA 0x5000C ++ ++#define REG_MCE_CH1_PINFO 0x50020 ++#define REG_MCE_CH2_PINFO 0x50820 ++#define MCE_PINFO(rgr, its, its_sft, its_scale, its_rnd) \ ++( ((rgr) & 0x1)<<31 | \ ++ ((its) & 0x1)<<28 | \ ++ ((its_sft) & 0x7)<<24 | \ ++ ((its_scale) & 0xFF)<<16 | \ ++ ((its_rnd) & 0xFFFF)<<0 \ ++) ++ ++#define REG_MCE_CH1_WINFO 0x50024 ++#define REG_MCE_CH2_WINFO1 0x50824 ++#define REG_MCE_CH2_WINFO2 0x50828 ++#define MCE_WINFO(wt, wtpd, wtmd, biavg_rnd, wt_denom, \ ++ wt_sft, wt_lcoef, wt_rcoef) \ ++( ((wt) & 0x1)<<31 | \ ++ ((wtpd) & 0x1)<<30 | \ ++ ((wtmd) & 0x3)<<28 | \ ++ ((biavg_rnd) & 0x1)<<27 | \ ++ ((wt_denom) & 0x7)<<24 | \ ++ ((wt_sft) & 0xF)<<16 | \ ++ ((wt_lcoef) & 0xFF)<<8 | \ ++ ((wt_rcoef) & 0xFF)<<0 \ ++) ++ ++#define REG_MCE_CH1_WTRND 0x5002C ++#define REG_MCE_CH2_WTRND 0x5082C ++#define MCE_WTRND(wt2_rnd, wt1_rnd) \ ++( ((wt2_rnd) & 0xFFFF)<<16 | \ ++ ((wt1_rnd) & 0xFFFF)<<0 \ ++) ++ ++#define REG_MCE_CH1_BINFO 0x50030 ++#define REG_MCE_CH2_BINFO 0x50830 ++#define MCE_BINFO(ary, expdy, expdx, ilmd, pel) \ ++( ((ary) & 0x1)<<31 | \ ++ ((expdy) & 0xF)<<24 | \ ++ ((expdx) & 0xF)<<20 | \ ++ ((ilmd) & 0x3)<<16 | \ ++ ((pel) & 0x3)<<14 \ ++) ++ ++#define REG_MCE_CH1_IINFO1 0x50034 ++#define REG_MCE_CH1_IINFO2 0x50038 ++#define MCE_CH1_IINFO(intp, tap, pkg, hldgl, avsdgl, \ ++ intp_dir, intp_rnd, intp_sft, \ ++ sintp, sintp_rnd, sintp_bias) \ ++( ((intp) & 0x1)<<31 | \ ++ ((tap) & 0x3)<<28 | \ ++ ((pkg) & 0x1)<<27 | \ ++ ((hldgl) & 0x1)<<26 | \ ++ ((avsdgl) & 0x1)<<25 | \ ++ ((intp_dir) & 0x1)<<24 | \ ++ ((intp_rnd) & 0xFF)<<16 | \ ++ ((intp_sft) & 0xF)<<8 | \ ++ ((sintp) & 0x1)<<2 | \ ++ ((sintp_rnd) & 0x1)<<1 | \ ++ ((sintp_bias) & 0x1)<<0 \ ++) ++ ++#define REG_MCE_CH2_IINFO1 0x50834 ++#define REG_MCE_CH2_IINFO2 0x50838 ++#define MCE_CH2_IINFO(intp, intp_dir, intp_sft, \ ++ intp_lcoef, intp_rcoef, intp_rnd) \ ++( ((intp) & 0x1)<<31 | \ ++ ((intp_dir) & 0x1)<<15 | \ ++ ((intp_sft) & 0x7)<<12 | \ ++ ((intp_lcoef) & 0x7)<<9 | \ ++ ((intp_rcoef) & 0x7)<<6 | \ ++ ((intp_rnd) & 0x3F)<<0 \ ++) ++ ++#define REG_MCE_CH1_TAP1L 0x5003C ++#define REG_MCE_CH1_TAP2L 0x50040 ++#define REG_MCE_CH1_TAP1M 0x50044 ++#define REG_MCE_CH1_TAP2M 0x50048 ++#define MCE_CH1_TAP(c1, c2, c3, c4) \ ++( ((c4) & 0xFF)<<24 | \ ++ ((c3) & 0xFF)<<16 | \ ++ ((c2) & 0xFF)<<8 | \ ++ ((c1) & 0xFF)<<0 \ ++) ++ ++#define REG_MCE_CH1_STRD 0x5004C ++#define REG_MCE_CH2_STRD 0x5084C ++#define MCE_STRD(ref_strd, raw_strd, dst_strd) \ ++( ((ref_strd) & 0xFFF)<<16 | \ ++ ((raw_strd) & 0xFF)<<8 | \ ++ ((dst_strd) & 0xFF)<<0 \ ++) ++ ++#define REG_MCE_GEOM 0x50050 ++#define MCE_GEOM(frm_height, frm_width) \ ++( ((frm_height) & 0xFFF)<<16 | \ ++ ((frm_width) & 0xFFF)<<0 \ ++) ++ ++#define REG_MCE_DDC 0x50054 ++#define MCE_TDD_RUN 0x1<<0 ++ ++#define REG_MCE_DSA 0x50058 ++ ++#define REG_MCE_ESTIC 0x5005C ++#define MCE_ESTIC(fsct, fsst, fsce, fsse) \ ++( ((fsct) & 0xFFFF)<<16 | \ ++ ((fsst) & 0xF)<<4 | \ ++ ((fsce) & 0x1)<<1 | \ ++ ((fsse) & 0x1)<<0 \ ++) ++ ++#define REG_MCE_CH1_RLUT 0x50300 ++#define REG_MCE_CH2_RLUT 0x50B00 ++#define MCE_RLUT_WT(wcoef2, wofst2, wcoef1, wofst1) \ ++( ((wcoef2) & 0xFF)<<24 | \ ++ ((wofst2) & 0xFF)<<16 | \ ++ ((wcoef1) & 0xFF)<<8 | \ ++ ((wofst1) & 0xFF)<<0 \ ++) ++ ++#define REG_MCE_CH1_CLUT 0x50400 ++ ++#define REG_MCE_CH1_ILUT 0x50500 ++#define REG_MCE_CH2_ILUT 0x50D00 ++ ++/*Motion TDD*/ ++#define MCE_TDD_COMP_HEAD(vld, lk, ch1pel, ch2pel, \ ++ posmd, mvmd, tkn, mby, mbx) \ ++( ((vld) & 0x1)<<31 | \ ++ ((lk) & 0x1)<<30 | \ ++ ((ch1pel) & 0x1)<<27 | \ ++ ((ch2pel) & 0x3)<<25 | \ ++ ((posmd) & 0x1)<<24 | \ ++ ((mvmd) & 0x1)<<23 | \ ++ ((tkn) & 0x7F)<<16 | \ ++ ((mby) & 0xFF)<<8 | \ ++ ((mbx) & 0xFF)<<0 \ ++) ++#define MCE_TDD_COMP_MV(mvy, mvx) \ ++( ((mvy) & 0xFFFF)<<16 | \ ++ ((mvx) & 0xFFFF)<<0 \ ++) ++#define MCE_TDD_COMP_CMD(bidir, refdir, fld, fldsel, \ ++ rgr, its, doe, cflo, ypos, \ ++ lilmd, cilmd, list, \ ++ boy, box, bh, bw, pos) \ ++( ((bidir) & 0x1)<<31 | \ ++ ((refdir) & 0x1)<<30 | \ ++ ((fld) & 0x1)<<29 | \ ++ ((fldsel) & 0x1)<<28 | \ ++ ((rgr) & 0x1)<<27 | \ ++ ((its) & 0x1)<<26 | \ ++ ((doe) & 0x1)<<25 | \ ++ ((cflo) & 0x1)<<24 | \ ++ ((ypos) & 0xF)<<20 | \ ++ ((lilmd) & 0x3)<<18 | \ ++ ((cilmd) & 0x3)<<16 | \ ++ ((list) & 0xF)<<12 | \ ++ ((boy) & 0x3)<<10 | \ ++ ((box) & 0x3)<<8 | \ ++ ((bh) & 0x3)<<6 | \ ++ ((bw) & 0x3)<<4 | \ ++ ((pos) & 0xF)<<0 \ ++) ++#define MCE_TDD_ESTI(vld, lk, dmy, pmc, list, \ ++ boy, box, bh, bw, mby, mbx) \ ++( ((vld) & 0x1)<<31 | \ ++ ((lk) & 0x1)<<30 | \ ++ ((dmy) & 0x1)<<27 | \ ++ ((pmc) & 0x1)<<26 | \ ++ ((list) & 0x3)<<24 | \ ++ ((boy) & 0x3)<<22 | \ ++ ((box) & 0x3)<<20 | \ ++ ((bh) & 0x3)<<18 | \ ++ ((bw) & 0x3)<<16 | \ ++ ((mby) & 0xFF)<<8 | \ ++ ((mbx) & 0xFF)<<0 \ ++) ++#define MCE_TDD_CFG(vld, lk, cidx) \ ++( 0x1<<28 | \ ++ ((vld) & 0x1)<<31 | \ ++ ((lk) & 0x1)<<30 | \ ++ ((cidx) & 0xFFF)<<0 \ ++) ++#define MCE_TDD_SYNC(vld, lk, crst, id) \ ++( 0x1<<29 | \ ++ ((vld) & 0x1)<<31 | \ ++ ((lk) & 0x1)<<30 | \ ++ ((crst) & 0x1)<<27 | \ ++ ((id) & 0xFFFF)<<0 \ ++) ++ ++/******************************************** ++ VMAU (VPU Matrix Arithmetic Unit) ++*********************************************/ ++#define REG_VMAU_MCBP 0x80000 ++ ++#define REG_VMAU_QTPARA 0x80004 ++ ++#define REG_VMAU_MAIN_ADDR 0x80008 ++ ++#define REG_VMAU_NCCHN_ADDR 0x8000C ++ ++#define REG_VMAU_CHN_LEN 0x80010 ++ ++#define REG_VMAU_ACBP 0x80014 ++ ++#define REG_VMAU_CPREDM_TLV 0x80018 ++ ++#define REG_VMAU_YPREDM0 0x8001C ++ ++#define REG_VMAU_YPREDM1 0x80020 ++ ++#define REG_VMAU_GBL_RUN 0x80040 ++#define VMAU_RUN 0x1 ++#define VMAU_STOP 0x2 ++#define VMAU_RESET 0x4 ++ ++#define REG_VMAU_GBL_CTR 0x80044 ++#define VMAU_CTRL_FIFO_M 0x1 ++#define VMAU_CTRL_IRQ_EN 0x10 ++#define VMAU_CTRL_SLPOW 0x10000 ++#define VMAU_CTRL_TO_DBLK 0x1000000 ++ ++#define REG_VMAU_STATUS 0x80048 ++ ++#define REG_VMAU_CCHN_ADDR 0x8004C ++ ++#define REG_VMAU_VIDEO_TYPE 0x80050 ++#define VMAU_FMT_H264 0x1 ++#define VMAU_FMT_RV9 0x2 ++#define VMAU_FMT_VC1 0x3 ++#define VMAU_FMT_MPEG2 0x4 ++#define VMAU_FMT_MPEG4 0x5 ++#define VMAU_FMT_VP8 0x6 ++#define VMAU_MODE_DEC (0x0<<11) ++#define VMAU_MODE_ENC (0x1<<11) ++ ++#define REG_VMAU_Y_GS 0x80054 ++ ++#define REG_VMAU_DEC_DONE 0x80058 ++ ++#define REG_VMAU_ENC_DONE 0x8005C ++ ++#define REG_VMAU_POS 0x80060 ++ ++#define REG_VMAU_MCF_STA 0x80064 ++ ++#define REG_VMAU_DEC_YADDR 0x80068 ++ ++#define REG_VMAU_DEC_UADDR 0x8006C ++ ++#define REG_VMAU_DEC_VADDR 0x80070 ++ ++#define REG_VMAU_DEC_STR 0x80074 ++ ++#define REG_VMAU_MEML 0x84000 ++#define REG_VMAU_QT 0x88000 ++ ++/******************************************** ++ DBLK (deblock) ++*********************************************/ ++#define REG_DBLK_DHA 0x70000 ++ ++#define REG_DBLK_TRIG 0x70060 ++#define DBLK_RUN 0x1 ++#define DBLK_STOP 0x2 ++#define DBLK_RESET 0x4 ++#define DBLK_SLICE_RUN 0x8 ++ ++#define REG_DBLK_CTRL 0x70064 ++#define DBLK_CTRL(expand, rotate, loop_filter) \ ++( ((expand) & 0x1)<<4 | \ ++ ((rotate) & 0x3)<<1 | \ ++ ((loop_filter) & 0x1)<<0 \ ++) ++ ++#define REG_DBLK_VTR 0x70068 ++#define DBLK_FMT_H264 0x1 ++#define DBLK_FMT_RV9 0x2 ++#define DBLK_FMT_VC1 0x3 ++#define DBLK_FMT_MPEG2 0x4 ++#define DBLK_FMT_MPEG4 0x5 ++#define DBLK_FMT_VP8 0x6 ++#define DBLK_FRM_I 0x0 ++#define DBLK_FRM_P 0x1 ++#define DBLK_FRM_B 0x2 ++#define DBLK_VTR(beta, alpha, vp8_spl, vp8_kf, \ ++ frm_typ, video_fmt) \ ++( ((beta) & 0xFF)<<24 | \ ++ ((alpha) & 0xFF)<<16 | \ ++ ((vp8_spl) & 0x1)<<9 | \ ++ ((vp8_kf) & 0x1)<<5 | \ ++ ((frm_typ) & 0x3)<<3 | \ ++ ((video_fmt) & 0x7)<<0 \ ++) ++ ++#define REG_DBLK_FSTA 0x7006C ++ ++#define REG_DBLK_GSTA 0x70070 ++ ++#define REG_DBLK_GSIZE 0x70074 ++#define DBLK_GSIZE(mb_height, mb_width) \ ++( ((mb_height) & 0xFFFF)<<16 | \ ++ ((mb_width) & 0xFFFF)<<0 \ ++) ++ ++#define REG_DBLK_GENDA 0x70078 ++ ++#define REG_DBLK_GPOS 0x7007C ++#define DBLK_GPOS(first_mby, first_mbx) \ ++( ((first_mby) & 0xFFFF)<<16 | \ ++ ((first_mbx) & 0xFFFF)<<0 \ ++) ++ ++#define REG_DBLK_GPIC_STR 0x70080 ++#define DBLK_GPIC_STR(dst_strd_c, dst_strd_y) \ ++( ((dst_strd_c) & 0xFFFF)<<16 | \ ++ ((dst_strd_y) & 0xFFFF)<<0 \ ++) ++ ++#define REG_DBLK_GPIC_YA 0x70084 ++ ++#define REG_DBLK_GPIC_CA 0x70088 ++ ++#define REG_DBLK_GP_ENDA 0x7008C ++ ++#define REG_DBLK_SLICE_ENDA 0x70090 ++ ++#define REG_DBLK_BLK_CTRL 0x70094 ++ ++#define REG_DBLK_BLK_FIFO 0x70098 ++ ++#define REG_DBLK_GPIC_Y1A 0x700A0 ++ ++#define REG_DBLK_GPIC_C1A 0x700A4 ++ ++#define REG_DBLK_GPIC_STR1 0x700A8 ++ ++/******************************************** ++ SDE (stream parser/encoding) ++*********************************************/ ++#define REG_SDE_STAT 0x90000 ++ ++#define REG_SDE_SL_CTRL 0x90004 ++#define SDE_SLICE_INIT (0x1<<1) ++#define SDE_MB_RUN (0x1<<0) ++ ++#define REG_SDE_SL_GEOM 0x90008 ++#define SDE_SL_GEOM(mb_height, mb_width, \ ++ first_mby, first_mbx) \ ++( ((mb_height) & 0xFF)<<24 | \ ++ ((mb_width) & 0xFF)<<16 | \ ++ ((first_mby) & 0xFF)<<8 | \ ++ ((first_mbx) & 0xFF)<<0 \ ++) ++ ++#define REG_SDE_GL_CTRL 0x9000C ++#define SDE_BP(mby, mbx) \ ++( ((mby) & 0xFF)<<24 | \ ++ ((mbx) & 0xFF)<<16 \ ++) ++#define SDE_MODE_AUTO (0x0<<4) ++#define SDE_MODE_STEP (0x1<<4) ++#define SDE_MODE_DEBUG (0x2<<4) ++#define SDE_EN (0x1<<0) ++ ++#define REG_SDE_CODEC_ID 0x90010 ++#define SDE_FMT_H264_DEC (0x1<<0) ++#define SDE_FMT_H264_ENC (0x1<<1) ++#define SDE_FMT_VP8_DEC (0x1<<2) ++#define SDE_FMT_VC1_DEC (0x1<<3) ++#define SDE_FMT_MPEG2_DEC (0x1<<4) ++ ++#define REG_SDE_CFG0 0x90014 ++#define REG_SDE_CFG1 0x90018 ++#define REG_SDE_CFG2 0x9001C ++#define REG_SDE_CFG3 0x90020 ++#define REG_SDE_CFG4 0x90024 ++#define REG_SDE_CFG5 0x90028 ++#define REG_SDE_CFG6 0x9002C ++#define REG_SDE_CFG7 0x90030 ++#define REG_SDE_CFG8 0x90034 ++#define REG_SDE_CFG9 0x90038 ++#define REG_SDE_CFG10 0x9003C ++#define REG_SDE_CFG11 0x90040 ++#define REG_SDE_CFG12 0x90044 ++#define REG_SDE_CFG13 0x90048 ++#define REG_SDE_CFG14 0x9004C ++#define REG_SDE_CFG15 0x90050 ++ ++#define REG_SDE_CTX_TBL 0x92000 ++#define REG_SDE_CQP_TBL 0x93800 ++ ++/**************************************************************** ++ VPU tables ++*****************************************************************/ ++/******************************************** ++ Motion interpolation programable table ++*********************************************/ ++#define IS_SKIRT 0 ++#define IS_MIRROR 1 ++ ++#define IS_BIAVG 0 ++#define IS_WT1 1 ++#define IS_WT2 2 ++#define IS_FIXWT 3 ++ ++#define IS_ILUT0 0 ++#define IS_ILUT1 2 ++#define IS_EC 1 ++ ++#define IS_TCS 1 ++#define NOT_TCS 0 ++#define IS_SCS 1 ++#define NOT_SCS 0 ++#define IS_HLDGL 1 ++#define NOT_HLDGL 0 ++#define IS_AVSDGL 1 ++#define NOT_AVSDGL 0 ++ ++#define INTP_HDIR 0 ++#define INTP_VDIR 1 ++ ++enum IntpID { ++ MPEG_HPEL = 0, ++ MPEG_QPEL, ++ H264_QPEL, ++ H264_EPEL, ++ RV8_TPEL, ++ RV9_QPEL, ++ RV9_CPEL, ++ WMV2_QPEL, ++ VC1_QPEL, ++ AVS_QPEL, ++ VP6_QPEL, ++ VP8_QPEL, ++ VP8_EPEL, ++ VP8_BIL, ++ VP8_FPEL, /*full-pixel for chroma*/ ++}; ++ ++enum PosID { ++ H0V0 = 0, ++ H1V0, ++ H2V0, ++ H3V0, ++ H0V1, ++ H1V1, ++ H2V1, ++ H3V1, ++ H0V2, ++ H1V2, ++ H2V2, ++ H3V2, ++ H0V3, ++ H1V3, ++ H2V3, ++ H3V3, ++}; ++ ++enum TapTYP { ++ TAP2 = 0, ++ TAP4, ++ TAP6, ++ TAP8, ++}; ++ ++enum SPelSFT { ++ HPEL = 1, ++ QPEL, ++ EPEL, ++}; ++ ++typedef struct IntpFMT_t{ ++ char tap; ++ char intp_pkg[2]; ++ char hldgl; ++ char avsdgl; ++ char intp[2]; ++ char intp_dir[2]; ++ char intp_coef[2][8]; ++ char intp_rnd[2]; ++ char intp_sft[2]; ++ char intp_sintp[2]; ++ char intp_srnd[2]; ++ char intp_sbias[2]; ++}IntpFMT_t; ++ ++__place_k0_data__ ++static char AryFMT[] = {IS_SKIRT, IS_MIRROR, IS_SKIRT, IS_SKIRT, ++ IS_SKIRT, IS_SKIRT, IS_SKIRT, IS_SKIRT, ++ IS_SKIRT, IS_SKIRT, IS_SKIRT, IS_SKIRT, ++ IS_SKIRT, IS_SKIRT, IS_SKIRT, IS_SKIRT}; ++ ++__place_k0_data__ ++static char SubPel[] = {HPEL, QPEL, QPEL, EPEL, ++ QPEL, QPEL, QPEL, QPEL, ++ QPEL, QPEL, QPEL, QPEL, ++ EPEL, HPEL, QPEL, QPEL}; ++ ++__place_k0_data__ ++static IntpFMT_t IntpFMT[][16] = { ++ { ++ /************* MPEG_HPEL ***************/ ++ {/*H0V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/1, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H2V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/1, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/1, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H0V1*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/1, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V1*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0} }, ++ {/*intp_rnd*/0, 2}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H2V1*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0} }, ++ {/*intp_rnd*/0, 2}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V1*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0} }, ++ {/*intp_rnd*/0, 2}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H0V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/1, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0} }, ++ {/*intp_rnd*/0, 2}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H2V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0} }, ++ {/*intp_rnd*/0, 2}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0} }, ++ {/*intp_rnd*/0, 2}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H0V3*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/1, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V3*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0} }, ++ {/*intp_rnd*/0, 2}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H2V3*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0} }, ++ {/*intp_rnd*/0, 2}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V3*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0} }, ++ {/*intp_rnd*/0, 2}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ }, ++ ++ { ++ /************* MPEG_QPEL ***************/ ++ {/*H0V0*/ ++ TAP8, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1},{0},}, ++ {/*intp_rnd*/15, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1},{0},}, ++ {/*intp_rnd*/15, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1},{0},}, ++ {/*intp_rnd*/15, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/1, 0}, ++ }, ++ {/*H0V1*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1},{0},}, ++ {/*intp_rnd*/15, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V1*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1}, {-1, 3, -6, 20, 20, -6, 3, -1},}, ++ {/*intp_rnd*/15, 15}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/1, 1}, ++ {/*intp_srnd*/1, 1}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V1*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1}, {-1, 3, -6, 20, 20, -6, 3, -1},}, ++ {/*intp_rnd*/15, 15}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V1*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1}, {-1, 3, -6, 20, 20, -6, 3, -1},}, ++ {/*intp_rnd*/15, 15}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/1, 1}, ++ {/*intp_srnd*/1, 1}, ++ {/*intp_sbias*/1, 0}, ++ }, ++ {/*H0V2*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1},{0},}, ++ {/*intp_rnd*/15, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1}, {-1, 3, -6, 20, 20, -6, 3, -1},}, ++ {/*intp_rnd*/15, 15}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1}, {-1, 3, -6, 20, 20, -6, 3, -1},}, ++ {/*intp_rnd*/15, 15}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1}, {-1, 3, -6, 20, 20, -6, 3, -1},}, ++ {/*intp_rnd*/15, 15}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/1, 0}, ++ }, ++ {/*H0V3*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1},{0},}, ++ {/*intp_rnd*/15, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/1, 0}, ++ }, ++ {/*H1V3*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1}, {-1, 3, -6, 20, 20, -6, 3, -1},}, ++ {/*intp_rnd*/15, 15}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/1, 1}, ++ {/*intp_srnd*/1, 1}, ++ {/*intp_sbias*/0, 1}, ++ }, ++ {/*H2V3*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1}, {-1, 3, -6, 20, 20, -6, 3, -1},}, ++ {/*intp_rnd*/15, 15}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 1}, ++ }, ++ {/*H3V3*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1}, {-1, 3, -6, 20, 20, -6, 3, -1},}, ++ {/*intp_rnd*/15, 15}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/1, 1}, ++ {/*intp_srnd*/1, 1}, ++ {/*intp_sbias*/1, 1}, ++ }, ++ }, ++ ++ { ++ /************* H264_QPEL ***************/ ++ {/*H0V0*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/1, 0}, ++ }, ++ {/*H0V1*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V1*/ ++ TAP6, {NOT_TCS, IS_SCS}, IS_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 16}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V1*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 10}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V1*/ ++ TAP6, {NOT_TCS, IS_SCS}, IS_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 16}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/1, 0}, ++ }, ++ {/*H0V2*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 10}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 10}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 10}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 1}, ++ }, ++ {/*H0V3*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/1, 0}, ++ }, ++ {/*H1V3*/ ++ TAP6, {NOT_TCS, IS_SCS}, IS_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 16}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 1}, ++ }, ++ {/*H2V3*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 10}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 1}, ++ }, ++ {/*H3V3*/ ++ TAP6, {NOT_TCS, IS_SCS}, IS_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 16}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/1, 1}, ++ }, ++ }, ++ ++ { ++ /************* H264_EPEL ***************/ ++ {/*H0V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/0}, ++ {/*H2V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{0},{0},}, ++ {/*intp_rnd*/4, 0}, ++ {/*intp_sft*/3, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V0*/0}, ++ {/*H0V1*/0}, ++ {/*H1V1*/0}, ++ {/*H2V1*/0}, ++ {/*H3V1*/0}, ++ {/*H0V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{0},{0},}, ++ {/*intp_rnd*/4, 0}, ++ {/*intp_sft*/3, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V2*/0}, ++ {/*H2V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{0},{0},}, ++ {/*intp_rnd*/0, 32}, ++ {/*intp_sft*/0, 6}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V2*/0}, ++ {/*H0V3*/0}, ++ {/*H1V3*/0}, ++ {/*H2V3*/0}, ++ {/*H3V3*/0}, ++ }, ++ ++ { ++ /************* RV8_TPEL ***************/ ++ {/*H0V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 12, 6, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/8, 0}, ++ {/*intp_sft*/4, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 6, 12, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/8, 0}, ++ {/*intp_sft*/4, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/0}, ++ {/*H0V1*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, 12, 6, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/8, 0}, ++ {/*intp_sft*/4, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V1*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 12, 6, -1, 0, 0, 0, 0}, {-1, 12, 6, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/8, 0}, //{0,128} ++ {/*intp_sft*/0, 8}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V1*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 6, 12, -1, 0, 0, 0, 0}, {-1, 12, 6, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/8, 0}, //{0,128} ++ {/*intp_sft*/0, 8}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V1*/0}, ++ {/*H0V2*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, 6, 12, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/8, 0}, ++ {/*intp_sft*/4, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 12, 6, -1, 0, 0, 0, 0}, {-1, 6, 12, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/8, 0}, //{0,128} ++ {/*intp_sft*/0, 8}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 6, 12, -1, 0, 0, 0, 0}, {-1, 6, 12, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/8, 0}, //{0,128} ++ {/*intp_sft*/0, 8}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/0}, ++ {/*H0V3*/0}, ++ {/*H1V3*/0}, ++ {/*H2V3*/0}, ++ {/*H3V3*/0}, ++ }, ++ ++ { ++ /************* RV9_QPEL ***************/ ++ {/*H0V0*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, -5, 52, 20, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, -5, 20, 52, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V1*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, -5, 52, 20, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V1*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 52, 20, -5, 1, 0, 0}, {1, -5, 52, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/32, 32}, ++ {/*intp_sft*/6, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V1*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 52, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 32}, ++ {/*intp_sft*/5, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V1*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 52, -5, 1, 0, 0}, {1, -5, 52, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/32, 32}, ++ {/*intp_sft*/6, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V2*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 52, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/32, 16}, ++ {/*intp_sft*/6, 5}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 16}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 52, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/32, 16}, ++ {/*intp_sft*/6, 5}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V3*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, -5, 20, 52, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V3*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 52, 20, -5, 1, 0, 0}, {1, -5, 20, 52, -5, 1, 0, 0},}, ++ {/*intp_rnd*/32, 32}, ++ {/*intp_sft*/6, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V3*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 52, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 32}, ++ {/*intp_sft*/5, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V3*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 2}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ }, ++ ++ { ++ /************* RV9_CPEL ***************/ ++ {/*H0V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{3, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/2, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/1, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, 3, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/2, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V1*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{3, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/2, 0}, ++ {/*intp_sft*/2, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V1*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{3, 1, 0, 0, 0, 0, 0, 0}, {3, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 7}, ++ {/*intp_sft*/0, 4}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V1*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {3, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 4}, ++ {/*intp_sft*/0, 3}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V1*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 3, 0, 0, 0, 0, 0, 0}, {3, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 7}, ++ {/*intp_sft*/0, 4}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/1, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{3, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 4}, ++ {/*intp_sft*/0, 3}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 1}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 3, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 4}, ++ {/*intp_sft*/0, 3}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V3*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, 3, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/2, 0}, ++ {/*intp_sft*/2, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V3*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{3, 1, 0, 0, 0, 0, 0, 0}, {1, 3, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 7}, ++ {/*intp_sft*/0, 4}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V3*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 3, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 4}, ++ {/*intp_sft*/0, 3}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V3*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 1}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ }, ++ ++ { ++ /************* WMV2_QPEL ***************/ ++ {/*H0V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/8, 0}, ++ {/*intp_sft*/4, 0}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/8, 0}, ++ {/*intp_sft*/4, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/8, 0}, ++ {/*intp_sft*/4, 0}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/1, 0}, ++ }, ++ {/*H0V1*/0}, ++ {/*H1V1*/0}, ++ {/*H2V1*/0}, ++ {/*H3V1*/0}, ++ {/*H0V2*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/8, 0}, ++ {/*intp_sft*/4, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0}, {-1, 9, 9, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/8, 8}, ++ {/*intp_sft*/4, 4}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0}, {-1, 9, 9, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/8, 8}, ++ {/*intp_sft*/4, 4}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0}, {-1, 9, 9, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/8, 8}, ++ {/*intp_sft*/4, 4}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 1}, ++ }, ++ {/*H0V3*/0}, ++ {/*H1V3*/0}, ++ {/*H2V3*/0}, ++ {/*H3V3*/0}, ++ }, ++ ++ { ++ /************* VC1_QPEL ***************/ ++ {/*H0V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-4, 53, 18, -3, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/8, 0}, ++ {/*intp_sft*/4, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-3, 18, 53, -4, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V1*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-4, 53, 18, -3, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/31, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V1*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-4, 53, 18, -3, 0, 0, 0, 0}, {-4, 53, 18, -3, 0, 0, 0, 0},}, ++ {/*intp_rnd*/31, 32}, ++ {/*intp_sft*/6, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V1*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-4, 53, 18, -3, 0, 0, 0, 0}, {-1, 9, 9, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/31, 8}, ++ {/*intp_sft*/6, 4}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V1*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-4, 53, 18, -3, 0, 0, 0, 0}, {-3, 18, 53, -4, 0, 0, 0, 0},}, ++ {/*intp_rnd*/31, 32}, ++ {/*intp_sft*/6, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V2*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/7, 0}, ++ {/*intp_sft*/4, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0}, {-4, 53, 18, -3, 0, 0, 0, 0},}, ++ {/*intp_rnd*/7, 32}, ++ {/*intp_sft*/4, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0}, {-1, 9, 9, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/7, 8}, ++ {/*intp_sft*/4, 4}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0}, {-3, 18, 53, -4, 0, 0, 0, 0},}, ++ {/*intp_rnd*/7, 32}, ++ {/*intp_sft*/4, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V3*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-3, 18, 53, -4, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/31, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V3*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-3, 18, 53, -4, 0, 0, 0, 0}, {-4, 53, 18, -3, 0, 0, 0, 0},}, ++ {/*intp_rnd*/31, 32}, ++ {/*intp_sft*/6, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V3*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-3, 18, 53, -4, 0, 0, 0, 0}, {-1, 9, 9, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/31, 8}, ++ {/*intp_sft*/6, 4}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V3*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-3, 18, 53, -4, 0, 0, 0, 0}, {-3, 18, 53, -4, 0, 0, 0, 0},}, ++ {/*intp_rnd*/31, 32}, ++ {/*intp_sft*/6, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ }, ++ ++ { ++ /************* AVS_QPEL ***************/ ++ {/*H0V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, -2, 96, 42, -7, 0, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 5, 5, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/4, 0}, ++ {/*intp_sft*/3, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{0, -7, 42, 96, -2, -1, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V1*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, -2, 96, 42, -7, 0, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V1*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, IS_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 5, 5, -1, 0, 0, 0, 0}, {-1, 5, -5, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 32}, ++ {/*intp_sft*/0, 6}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V1*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{0, -1, 5, 5, -1, 0, 0, 0}, {-1, -2, 96, 42, -7, 0, 0, 0},}, ++ {/*intp_rnd*/64, 0}, //{0,512} ++ {/*intp_sft*/0, 10}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V1*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, IS_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 5, 5, -1, 0, 0, 0, 0}, {-1, 5, -5, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 32}, ++ {/*intp_sft*/0, 6}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/1, 0}, ++ }, ++ {/*H0V2*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, 5, 5, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/4, 0}, ++ {/*intp_sft*/3, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, -2, 96, 42, -7, 0, 0, 0}, {0, -1, 5, 5, -1, 0, 0, 0},}, ++ {/*intp_rnd*/64, 0}, //{0,512} ++ {/*intp_sft*/0, 10}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 5, 5, -1, 0, 0, 0, 0}, {-1, 5, 5, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 32}, ++ {/*intp_sft*/0, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{0, -7, 42, 96, -2, -1, 0, 0}, {0, -1, 5, 5, -1, 0, 0, 0},}, ++ {/*intp_rnd*/64, 0}, //{0,512} ++ {/*intp_sft*/0, 10}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V3*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{0, -7, 42, 96, -2, -1, 0, 0}, {0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V3*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, IS_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 5, 5, -1, 0, 0, 0, 0}, {-1, 5, -5, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 32}, ++ {/*intp_sft*/0, 6}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 1}, ++ }, ++ {/*H2V3*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{0, -1, 5, 5, -1, 0, 0, 0}, {0, -7, 42, 96, -2, -1, 0, 0},}, ++ {/*intp_rnd*/64, 0}, //{0,512} ++ {/*intp_sft*/0, 10}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V3*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, IS_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 5, 5, -1, 0, 0, 0, 0}, {-1, 5, -5, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 32}, ++ {/*intp_sft*/0, 6}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/1, 1}, ++ }, ++ }, ++ ++ { ++ /************* VP6_QPEL ***************/ ++ {/*H0V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-4, 109, 24, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-4, 68, 68, -4, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 24, 109, -4, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V1*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-4, 109, 24, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V1*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-4, 109, 24, -1, 0, 0, 0, 0}, {-4, 109, 24, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V1*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-4, 68, 68, -4, 0, 0, 0, 0}, {-4, 109, 24, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V1*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 24, 109, -4, 0, 0, 0, 0}, {-4, 109, 24, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V2*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-4, 68, 68, -4, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-4, 109, 24, -1, 0, 0, 0, 0}, {-4, 68, 68, -4, 0, 0, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-4, 68, 68, -4, 0, 0, 0, 0}, {-4, 68, 68, -4, 0, 0, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 24, 109, -4, 0, 0, 0, 0}, {-4, 68, 68, -4, 0, 0, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V3*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, 24, 109, -4, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V3*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-4, 109, 24, -1, 0, 0, 0, 0}, {-1, 24, 109, -4, 0, 0, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V3*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-4, 68, 68, -4, 0, 0, 0, 0}, {-1, 24, 109, -4, 0, 0, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V3*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 24, 109, -4, 0, 0, 0, 0}, {-1, 24, 109, -4, 0, 0, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ }, ++ ++ { ++ /************* VP8_QPEL ***************/ ++ {/*H0V0*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{2, -11, 108, 36, -8, 1, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{3, -16, 77, 77, -16, 3, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, -8, 36, 108, -11, 2, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V1*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{2, -11, 108, 36, -8, 1, 0, 0}, {0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V1*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{2, -11, 108, 36, -8, 1, 0, 0}, {2, -11, 108, 36, -8, 1, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V1*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{3, -16, 77, 77, -16, 3, 0, 0}, {2, -11, 108, 36, -8, 1, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V1*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -8, 36, 108, -11, 2, 0, 0}, {2, -11, 108, 36, -8, 1, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V2*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{3, -16, 77, 77, -16, 3, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{2, -11, 108, 36, -8, 1, 0, 0}, {3, -16, 77, 77, -16, 3, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{3, -16, 77, 77, -16, 3, 0, 0}, {3, -16, 77, 77, -16, 3, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -8, 36, 108, -11, 2, 0, 0}, {3, -16, 77, 77, -16, 3, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V3*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, -8, 36, 108, -11, 2, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V3*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{2, -11, 108, 36, -8, 1, 0, 0}, {1, -8, 36, 108, -11, 2, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V3*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{3, -16, 77, 77, -16, 3, 0, 0}, {1, -8, 36, 108, -11, 2, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V3*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -8, 36, 108, -11, 2, 0, 0}, {1, -8, 36, 108, -11, 2, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ }, ++ ++ { ++ /************* VP8_EPEL ***************/ ++ {/*H0V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/0}, ++ {/*H2V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{0},{0},}, ++ {/*intp_rnd*/4, 0}, ++ {/*intp_sft*/3, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V0*/0}, ++ {/*H0V1*/0}, ++ {/*H1V1*/0}, ++ {/*H2V1*/0}, ++ {/*H3V1*/0}, ++ {/*H0V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{0},{0},}, ++ {/*intp_rnd*/4, 0}, ++ {/*intp_sft*/3, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V2*/0}, ++ {/*H2V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{0},{0},}, ++ {/*intp_rnd*/4, 4}, ++ {/*intp_sft*/3, 3}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V2*/0}, ++ {/*H0V3*/0}, ++ {/*H1V3*/0}, ++ {/*H2V3*/0}, ++ {/*H3V3*/0}, ++ }, ++ ++ { ++ /************* VP8_BIL ***************/ ++ {/*H0V0*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{3, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/2, 0}, ++ {/*intp_sft*/2, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H2V0*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/1, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V0*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, 3, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/2, 0}, ++ {/*intp_sft*/2, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H0V1*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{3, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/2, 0}, ++ {/*intp_sft*/2, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V1*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{3, 1, 0, 0, 0, 0, 0, 0},{3, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/2, 2}, ++ {/*intp_sft*/2, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H2V1*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{3, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/1, 2}, ++ {/*intp_sft*/1, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V1*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 3, 0, 0, 0, 0, 0, 0},{3, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/2, 2}, ++ {/*intp_sft*/2, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H0V2*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/1, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V2*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{3, 1, 0, 0, 0, 0, 0, 0},{1, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/2, 1}, ++ {/*intp_sft*/2, 1}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H2V2*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{1, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/1, 1}, ++ {/*intp_sft*/1, 1}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V2*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 3, 0, 0, 0, 0, 0, 0},{1, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/2, 1}, ++ {/*intp_sft*/2, 1}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H0V3*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, 3, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/2, 0}, ++ {/*intp_sft*/2, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V3*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{3, 1, 0, 0, 0, 0, 0, 0},{1, 3, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/2, 2}, ++ {/*intp_sft*/2, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H2V3*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{1, 3, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/1, 2}, ++ {/*intp_sft*/1, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V3*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 3, 0, 0, 0, 0, 0, 0},{1, 3, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/2, 2}, ++ {/*intp_sft*/2, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ }, ++ ++ { ++ /************* VP8_FPEL ***************/ ++ {/*H0V0*/0}, ++ {/*H1V0*/0}, ++ {/*H2V0*/0}, ++ {/*H3V0*/0}, ++ {/*H0V1*/0}, ++ {/*H1V1*/0}, ++ {/*H2V1*/0}, ++ {/*H3V1*/0}, ++ {/*H0V2*/0}, ++ {/*H1V2*/0}, ++ {/*H2V2*/0}, ++ {/*H3V2*/0}, ++ {/*H0V3*/0}, ++ {/*H1V3*/0}, ++ {/*H2V3*/0}, ++ {/*H3V3*/0}, ++ }, ++}; ++ ++#endif /*__JZM_VPU_H__*/ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_felix_felix_drv.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_felix_felix_drv.c.patch new file mode 100644 index 00000000..ac28e302 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_felix_felix_drv.c.patch @@ -0,0 +1,660 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/felix/felix_drv.c b/drivers/media/platform/ingenic-vcodec/felix/felix_drv.c +--- a/drivers/media/platform/ingenic-vcodec/felix/felix_drv.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/felix/felix_drv.c 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,656 @@ ++/* ++ * Copyright (c) 2014 Ingenic Inc. ++ * Author: qipengzhen ++ * ++ * 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. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "felix_drv.h" ++#include "felix_ops.h" ++ ++#include "libh264/libavcodec/h264dec.h" ++ ++#undef pr_debug ++#define pr_debug pr_info ++ ++ ++/* ++TODO: do not support multi ctx for now. ++*/ ++ ++extern struct vpu_ops ingenic_vpu_ops; ++ ++static int fops_vcodec_open(struct file *file) ++{ ++ struct ingenic_vdec_dev *dev = video_drvdata(file); ++ struct ingenic_vdec_ctx *ctx = NULL; ++ int ret = 0; ++ ++ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); ++ if(!ctx) ++ return -ENOMEM; ++ ctx->avctx = kzalloc(sizeof(AVCodecContext), GFP_KERNEL); ++ if(!ctx->avctx) { ++ kfree(ctx); ++ return -ENOMEM; ++ } ++ ++ ctx->h = kzalloc(sizeof(H264Context), GFP_KERNEL); ++ if(!ctx->h) { ++ kfree(ctx->avctx); ++ kfree(ctx); ++ return -ENOMEM; ++ } ++ ctx->avctx->priv_data = ctx->h; ++ //ctx->avctx->flags2 |= AV_CODEC_FLAG2_CHUNKS; ++ //ctx->avctx->debug |= FF_DEBUG_PICT_INFO; ++ ++ ret = h264_decode_init(ctx->avctx); ++ if(ret < 0) { ++ kfree(ctx->h); ++ kfree(ctx->avctx); ++ kfree(ctx); ++ return -EINVAL; ++ } ++ ++#ifdef CONFIG_SOC_M200 ++ h264_set_soc_type(ctx->h, SOC_TYPE_M200); ++ h264_set_output_format(ctx->h, VPU_FORMAT_TILE420); ++#else ++ h264_set_soc_type(ctx->h, SOC_TYPE_X2000); ++ h264_set_output_format(ctx->h, VPU_FORMAT_NV12); /*TODO: move to set format.*/ ++#endif ++ ++ ++ h264_set_vpu_ops(ctx->h, ctx, &ingenic_vpu_ops); ++ ++ ++ mutex_lock(&dev->dev_mutex); ++ ++ mutex_init(&ctx->lock); ++ ++ ctx->id = dev->id_counter++; ++ v4l2_fh_init(&ctx->fh, video_devdata(file)); ++ file->private_data = &ctx->fh; ++ v4l2_fh_add(&ctx->fh); ++ //INIT_LIST_HEAD(&ctx->list); ++ ctx->dev = dev; ++ init_waitqueue_head(&ctx->queue); ++ ++ ingenic_vcodec_init_default_params(ctx); ++ ++ ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &ingenic_vcodec_vdec_queue_init); ++ if(IS_ERR((__force void *)ctx->m2m_ctx)) { ++ ret = PTR_ERR((__force void *)ctx->m2m_ctx); ++ ++ goto err_m2m_ctx_init; ++ } ++ ++ pr_debug("Create instance [%d]@%p m2m_ctx=%p\n", ++ ctx->id, ctx, ctx->m2m_ctx); ++ ++ mutex_unlock(&dev->dev_mutex); ++ ++ pr_debug("%s vcodec [%d]\n", dev_name(dev->dev), ctx->id); ++ ++ return ret; ++err_m2m_ctx_init: ++ v4l2_ctrl_handler_free(&ctx->ctrl_hdl); ++err_ctrls_setup: ++ v4l2_fh_del(&ctx->fh); ++ v4l2_fh_exit(&ctx->fh); ++ kfree(ctx); ++ mutex_unlock(&dev->dev_mutex); ++ return ret; ++} ++ ++static int fops_vcodec_release(struct file *file) ++{ ++ ++ struct ingenic_vdec_dev *dev = video_drvdata(file); ++ struct ingenic_vdec_ctx *ctx = fh_to_ctx(file->private_data); ++ ++ pr_debug("[%d] vcodec release\n", ctx->id); ++ ++ mutex_lock(&dev->dev_mutex); ++ ++ v4l2_fh_del(&ctx->fh); ++ v4l2_fh_exit(&ctx->fh); ++ v4l2_ctrl_handler_free(&ctx->ctrl_hdl); ++ v4l2_m2m_ctx_release(ctx->m2m_ctx); ++ ++ ++ ingenic_vcodec_deinit_default_params(ctx); ++ ++ h264_decode_end(ctx->avctx); ++ ++ if(ctx->avctx) ++ kfree(ctx->avctx); ++ ++ if(ctx->h) ++ kfree(ctx->h); ++ ++ kfree(ctx); ++ ++ mutex_unlock(&dev->dev_mutex); ++ ++ return 0; ++} ++ ++static unsigned int fops_vcodec_poll(struct file *file, ++ struct poll_table_struct *wait) ++{ ++ struct ingenic_vdec_dev *dev = video_drvdata(file); ++ struct ingenic_vdec_ctx *ctx = fh_to_ctx(file->private_data); ++ unsigned int ret = 0; ++ ++ if(mutex_lock_interruptible(&dev->dev_mutex)) { ++ return -ERESTARTSYS; ++ } ++ ++ ret = v4l2_m2m_poll(file, ctx->m2m_ctx, wait); ++ ++ mutex_unlock(&dev->dev_mutex); ++ ++ return ret; ++} ++ ++static int fops_vcodec_mmap(struct file *file, ++ struct vm_area_struct *vma) ++{ ++ struct ingenic_vdec_ctx *ctx = fh_to_ctx(file->private_data); ++ ++ return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); ++} ++ ++static const struct v4l2_file_operations ingenic_vdec_fops = { ++ .owner = THIS_MODULE, ++ .open = fops_vcodec_open, ++ .release = fops_vcodec_release, ++ .poll = fops_vcodec_poll, ++ .unlocked_ioctl = video_ioctl2, ++ .mmap = fops_vcodec_mmap, ++}; ++ ++ ++#define vpu_readl(dev, offset) \ ++ readl(dev->reg_base + (offset)) ++ ++#define vpu_writel(dev, offset, data) \ ++ writel((data), dev->reg_base + (offset)) ++ ++static void inline vpu_clear_bits(struct ingenic_vdec_dev *dev, unsigned int offset, unsigned int bits) ++{ ++ unsigned int val = vpu_readl(dev, offset); ++ val &= ~bits; ++ vpu_writel(dev, offset, val); ++} ++ ++ ++#define REG_VPU_STATUS ( *(volatile unsigned int*)0xb3200034 ) ++#define REG_VPU_LOCK ( *(volatile unsigned int*)0xb329004c ) ++#define REG_VPUCDR ( *(volatile unsigned int*)0xb0000030 ) ++#define REG_CPM_VPU_SWRST ( *(volatile unsigned int*)0xb00000c4 ) ++#define REG_VPU_TLBBASE (*(volatile unsigned int *)(0x30 + 0xb3200000)) ++#define CPM_VPU_SR (0x1<<31) ++#define CPM_VPU_STP (0x1<<30) ++#define CPM_VPU_ACK (0x1<<29) ++ ++ ++ ++#define REG_VPU_GLBC 0x00000 ++#define VPU_INTE_ACFGERR (0x1<<20) ++#define VPU_INTE_TLBERR (0x1<<18) ++#define VPU_INTE_BSERR (0x1<<17) ++#define VPU_INTE_ENDF (0x1<<16) ++ ++#define REG_VPU_STAT 0x00034 ++#define VPU_STAT_ENDF (0x1<<0) ++#define VPU_STAT_BPF (0x1<<1) ++#define VPU_STAT_ACFGERR (0x1<<2) ++#define VPU_STAT_TIMEOUT (0x1<<3) ++#define VPU_STAT_JPGEND (0x1<<4) ++#define VPU_STAT_BSERR (0x1<<7) ++#define VPU_STAT_TLBERR (0x1F<<10) ++#define VPU_STAT_SLDERR (0x1<<16) ++ ++#define REG_VPU_JPGC_STAT 0xE0008 ++#define JPGC_STAT_ENDF (0x1<<31) ++ ++#define REG_VPU_SDE_STAT 0x90000 ++#define SDE_STAT_BSEND (0x1<<1) ++ ++#define REG_VPU_DBLK_STAT 0x70070 ++#define DBLK_STAT_DOEND (0x1<<0) ++ ++#define REG_VPU_AUX_STAT 0xA0010 ++#define AUX_STAT_MIRQP (0x1<<0) ++ ++static irqreturn_t ingenic_vpu_irq(int irq, void *priv) ++{ ++ struct ingenic_vdec_dev *dev = (struct ingenic_vdec_dev *)priv; ++ struct ingenic_vdec_ctx *ctx = dev->curr_ctx; ++ unsigned long flags; ++ ++ unsigned int vpu_stat; ++ ++#define check_vpu_status(STAT, fmt, args...) do { \ ++ if(vpu_stat & STAT) \ ++ dev_err(dev->dev, fmt, ##args); \ ++ }while(0) ++ ++ spin_lock_irqsave(&dev->spinlock, flags); ++ ++ vpu_stat = vpu_readl(dev, REG_SCH_STAT); ++ ++ if(vpu_stat) { ++ if(vpu_stat & VPU_STAT_ENDF) { ++ if(vpu_stat & VPU_STAT_JPGEND) { ++ dev_dbg(dev->dev, "JPG successfully done!\n"); ++ vpu_stat = vpu_readl(dev, REG_VPU_JPGC_STAT); ++ vpu_clear_bits(dev, REG_VPU_JPGC_STAT, ++ JPGC_STAT_ENDF); ++ } else { ++ dev_dbg(dev->dev, "SCH successfully done!\n"); ++ vpu_clear_bits(dev, REG_VPU_SDE_STAT, ++ SDE_STAT_BSEND); ++ vpu_clear_bits(dev, REG_VPU_DBLK_STAT, ++ DBLK_STAT_DOEND); ++ } ++ } else { ++ check_vpu_status(VPU_STAT_SLDERR, "SHLD error!\n"); ++ check_vpu_status(VPU_STAT_TLBERR, "TLB error! Addr is 0x%08x\n", ++ vpu_readl(dev, REG_VPU_STAT)); ++ check_vpu_status(VPU_STAT_BSERR, "BS error!\n"); ++ check_vpu_status(VPU_STAT_ACFGERR, "ACFG error!\n"); ++ check_vpu_status(VPU_STAT_TIMEOUT, "TIMEOUT error!\n"); ++ vpu_clear_bits(dev,REG_VPU_GLBC, (VPU_INTE_ACFGERR | ++ VPU_INTE_TLBERR | VPU_INTE_BSERR | ++ VPU_INTE_ENDF)); ++ } ++ } else { ++ if(vpu_readl(dev,REG_VPU_AUX_STAT) & AUX_STAT_MIRQP) { ++ dev_dbg(dev->dev, "AUX successfully done!\n"); ++ vpu_clear_bits(dev, REG_VPU_AUX_STAT, AUX_STAT_MIRQP); ++ } else { ++ dev_dbg(dev->dev, "illegal interrupt happened!\n"); ++ return IRQ_HANDLED; ++ } ++ } ++ ++ ctx->int_cond = 1; ++ //ctx->int_status = vpu_stat; ++ spin_unlock_irqrestore(&dev->spinlock, flags); ++ ++ wake_up_interruptible(&ctx->queue); ++ ++ return IRQ_HANDLED; ++} ++ ++ ++static void vpu_dump_regs(struct ingenic_vdec_dev *dev) ++{ ++ ++#if 0 ++ /* EMC */ ++ printk("REG_EMC_FRM_SIZE : %d\n", vpu_readl(dev, REG_EMC_FRM_SIZE)); ++ printk("REG_EMC_BS_ADDR : 0x%x\n", vpu_readl(dev, REG_EMC_BS_ADDR)); ++ printk("REG_EMC_DBLK_ADDR: 0x%x\n", vpu_readl(dev, REG_EMC_DBLK_ADDR)); ++ printk("REG_EMC_RECON_ADDR: 0x%x\n", vpu_readl(dev, REG_EMC_RECON_ADDR)); ++ printk("REG_EMC_MV_ADDR: 0x%x\n", vpu_readl(dev, REG_EMC_MV_ADDR)); ++ printk("REG_EMC_SE_ADDR: 0x%x\n", vpu_readl(dev, REG_EMC_SE_ADDR)); ++ printk("REG_EMC_QPT_ADDR: 0x%x\n", vpu_readl(dev, REG_EMC_QPT_ADDR)); ++ printk("REG_EMC_RC_RADDR: 0x%x\n", vpu_readl(dev, REG_EMC_RC_RADDR)); ++ printk("REG_EMC_MOS_ADDR: 0x%x\n", vpu_readl(dev, REG_EMC_MOS_ADDR)); ++ printk("REG_EMC_SLV_INIT: 0x%x\n", vpu_readl(dev, REG_EMC_SLV_INIT)); ++ printk("REG_EMC_BS_SIZE: 0x%x\n", vpu_readl(dev, REG_EMC_BS_SIZE)); ++ printk("REG_EMC_BS_STAT: 0x%x\n", vpu_readl(dev, REG_EMC_BS_STAT)); ++#endif ++} ++ ++ ++#define VPU_RUN_TIMEOUT_MS (3000) ++ ++#ifdef CONFIG_SOC_M200 ++static int vpu_reset_m200(struct ingenic_vdec_dev *dev) ++{ ++ int timeout = 0xffffff; ++ ++ REG_CPM_VPU_SWRST |= CPM_VPU_STP; ++ while(!(REG_CPM_VPU_SWRST & CPM_VPU_ACK) && --timeout) ++ ; ++ ++ if(!timeout) { ++ dev_err(dev->dev, ++ "[%d:%d] wait stop ack timeout when stop VPU\n", ++ current->tgid, current->pid); ++ } ++ ++ REG_CPM_VPU_SWRST = ((REG_CPM_VPU_SWRST | CPM_VPU_SR) & ~CPM_VPU_STP); ++ REG_CPM_VPU_SWRST = (REG_CPM_VPU_SWRST & ~CPM_VPU_SR & ~CPM_VPU_STP); ++ REG_VPU_LOCK = 0; ++ ++ return 0; ++} ++#endif ++ ++/******************************************** ++ SW_RESET (VPU software reset) ++*********************************************/ ++#define REG_CFGC_SW_RESET 0x00000 ++#define REG_CFGC_RST (0x1<<30) ++#define REG_CFGC_RST_CLR (0x0<<30) ++#define REG_CFGC_EARB_STAT 0x0000d ++#define REG_CFGC_EARB_EMPT (0x20000) ++ ++static int vpu_reset_x2000(struct ingenic_vdec_dev *dev) ++{ ++ int timeout = 0xffff; ++ vpu_writel(dev, REG_CFGC_SW_RESET, REG_CFGC_RST); ++ ++ while((vpu_readl(dev, REG_CFGC_EARB_STAT) & REG_CFGC_EARB_EMPT) && --timeout); ++ ++ if(!timeout) { ++ printk("vpu reset timeout!\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++static int vpu_reset(struct ingenic_vdec_dev *dev) ++{ ++#ifdef CONFIG_SOC_M200 ++ return vpu_reset_m200(dev); ++#else ++ return vpu_reset_x2000(dev); ++#endif ++} ++ ++/*global clk on.*/ ++static int vpu_on(struct ingenic_vdec_dev *dev) ++{ ++ clk_enable(dev->clk); ++ clk_enable(dev->clk_gate); ++ __asm__ __volatile__ ( ++ "mfc0 $2, $16, 7 \n\t" ++ "ori $2, $2, 0x340 \n\t" ++ "andi $2, $2, 0x3ff \n\t" ++ "mtc0 $2, $16, 7 \n\t" ++ "nop \n\t"); ++ ++ return 0; ++} ++ ++/* shutdown */ ++//static int vpu_off(struct ingenic_vdec_dev *dev) ++//{ ++// ++// //clk_disable(); ++// ++//} ++ ++ ++int ingenic_vpu_start(void *priv) ++{ ++ struct ingenic_vdec_ctx *ctx = (struct ingenic_vdec_ctx *)priv; ++ struct ingenic_vdec_dev *dev = ctx->dev; ++ H264Context *h = ctx->h; ++ vpu_ctx_t *vpu_ctx = &h->vpu_ctx; ++ ++ unsigned int sch_glbc = 0; ++ unsigned int des_pa; ++ unsigned long flags; ++ int timeout = 0xffff; ++ int ret = 0; ++ ++ mutex_lock(&ctx->lock); ++ ++ des_pa = vpu_ctx->desc_pa; ++ ++ spin_lock_irqsave(&dev->spinlock, flags); ++ ++ /* 是不是将vpu_start 和 wait放在一起,更加合理一些 ++ * 针对ctx 做加锁处理, 保证curr_ctx在一次处理期间不会发生变化. ++ * */ ++ dev->curr_ctx = ctx; ++ ctx->int_cond = 0; ++ ++ /* vpu reset ... */ ++ vpu_reset(dev); ++ ++ /*TODO: 如果使用tlb,此处要修改.*/ ++ sch_glbc = SCH_GLBC_HIAXI | SCH_INTE_ACFGERR | SCH_INTE_BSERR | SCH_INTE_ENDF; ++ /*|SCH_INTE_ENDF | SCH_INTE_TLBERR | SCH_INTE_BSFULL;*/ ++ ++ vpu_writel(dev, REG_SCH_GLBC, sch_glbc); ++ ++ /*trigger start.*/ ++ vpu_writel(dev, REG_VDMA_TASKRG, VDMA_ACFG_DHA(des_pa) | VDMA_ACFG_RUN); ++ ++ /* wait event time out ... */ ++ spin_unlock_irqrestore(&dev->spinlock, flags); ++ ++ ret = wait_event_interruptible_timeout(ctx->queue, ctx->int_cond, msecs_to_jiffies(VPU_RUN_TIMEOUT_MS)); ++ if(!ret) { ++ pr_err("wait vpu run timeout!\n"); ++ printk("efe_stat %x, sch_stat %x\n", vpu_readl(dev, REG_EFE_STAT), vpu_readl(dev, REG_SCH_STAT)); ++ ++ vpu_dump_regs(dev); ++ ret = -ETIMEDOUT; ++ } else if(ret == -ERESTARTSYS) { ++ pr_err("vpu interrupted by a signal!\n"); ++ ++ } ++ ++ mutex_unlock(&ctx->lock); ++ return ret; ++} ++ ++static int ingenic_vpu_wait(void *priv) ++{ ++ return 0; ++} ++ ++static int ingenic_vpu_stop(struct ingenic_vdec_dev *dev) ++{ ++ return 0; ++} ++ ++struct vpu_ops ingenic_vpu_ops = { ++ .start = ingenic_vpu_start, ++ .wait = ingenic_vpu_wait, ++ .end = ingenic_vpu_stop, ++}; ++ ++static int ingenic_vcodec_probe(struct platform_device *pdev) ++{ ++ struct ingenic_vdec_dev *dev; ++ struct video_device *vfd; ++ struct resource *res; ++ int ret; ++ ++ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); ++ if(!dev) ++ return -ENOMEM; ++ ++ dev->dev = &pdev->dev; ++ dev->plat_dev = pdev; ++ ++ /*io,clk,irq*/ ++ ++ dev->reg_base = of_iomap(pdev->dev.of_node, 0);; ++ if(IS_ERR(dev->reg_base)) { ++ ret = -ENODEV; ++ goto err_ioremap; ++ } ++ ++ /*TODO: clk pm ...*/ ++ dev->irq = platform_get_irq(pdev, 0); ++ ret = devm_request_irq(&pdev->dev, dev->irq, ingenic_vpu_irq, 0, pdev->name, dev); ++ if(ret ) { ++ dev_err(&pdev->dev, "Failed to request vpu irq!\n"); ++ goto err_irq; ++ } ++ ++ printk("-------dev->reg_base: %x, dev->irq: %x\n", dev->reg_base, dev->irq); ++ ++ dev->clk_gate = clk_get(&pdev->dev, "gate_vpu"); ++ if (IS_ERR(dev->clk_gate)) { ++ ret = PTR_ERR(dev->clk_gate); ++ goto err_get_clk_gate; ++ } ++ ++ dev->clk = clk_get(dev->dev,"cgu_vpu"); ++ if (IS_ERR(dev->clk)) { ++ ret = PTR_ERR(dev->clk); ++ goto err_get_clk_cgu; ++ } ++ ++ clk_set_rate(dev->clk, 300000000); ++ /*TODO: move to open close.*/ ++ vpu_on(dev); ++ ++ ++ ++ spin_lock_init(&dev->spinlock); ++ mutex_init(&dev->dev_mutex); ++ ++ dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); ++ if(IS_ERR(dev->alloc_ctx)) { ++ ret = -ENOMEM; ++ goto err_ctx; ++ } ++ ++ snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), "%s", "ingenic-v4l2-felix"); ++ ++ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); ++ if(ret) { ++ dev_err(&pdev->dev, "Failed to register v4l2_dev\n"); ++ goto err_v4l2; ++ } ++ ++ vfd = video_device_alloc(); ++ if(!vfd) { ++ dev_err(&pdev->dev, "Failed to alloc video device!\n"); ++ ret = -ENOMEM; ++ goto err_vdev; ++ } ++ ++ ++ vfd->fops = &ingenic_vdec_fops; ++ vfd->ioctl_ops = &ingenic_vdec_ioctl_ops; ++ vfd->release = video_device_release; ++ vfd->lock = &dev->dev_mutex; ++ vfd->v4l2_dev = &dev->v4l2_dev; ++ vfd->vfl_dir = VFL_DIR_M2M; ++ //vfd->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; ++ ++ snprintf(vfd->name, sizeof(vfd->name), "%s", INGENIC_VCODEC_DEC_NAME); ++ ++ video_set_drvdata(vfd, dev); ++ dev->vfd = vfd; ++ platform_set_drvdata(pdev, dev); ++ ++ dev->m2m_dev = v4l2_m2m_init(&ingenic_vdec_m2m_ops); ++ if(IS_ERR((__force void *)dev->m2m_dev)) { ++ dev_err(&pdev->dev, "Failed to init m2m device!\n"); ++ ret = PTR_ERR((__force void *)dev->m2m_dev); ++ goto err_m2m; ++ } ++ ++#if 0 ++ dev->encode_workqueue = alloc_ordered_workqueue(INGENIC_VCODEC_DEC_NAME, ++ WQ_MEM_RECLAIM | WQ_FREEZABLE); ++ if(!dev->encode_workqueue) { ++ dev_err(&pdev->dev, "Failed to create encode workqueue\n"); ++ ret = -EINVAL; ++ goto err_workq; ++ } ++#endif ++ ++ ret = video_register_device(vfd, VFL_TYPE_GRABBER, 1); ++ if(ret) { ++ dev_err(&pdev->dev, "Failed to register video device!\n"); ++ goto err_video_reg; ++ } ++ ++ ++ dev_info(&pdev->dev, "h264decoder(felix) registered as /dev/video%d\n", ++ vfd->num); ++ ++ return 0; ++err_video_reg: ++err_workq: ++err_m2m: ++err_vdev: ++err_v4l2: ++err_ctx: ++err_get_clk_cgu: ++err_get_clk_gate: ++err_irq: ++err_ioremap: ++ return ret; ++} ++ ++static int ingenic_vcodec_remove(struct platform_device *pdev) ++{ ++ ++ return 0; ++} ++ ++static const struct of_device_id felix_of_match[] = { ++ { .compatible = "ingenic,x2000-felix"}, ++ {}, ++}; ++ ++static struct platform_driver ingenic_vcodec_driver = { ++ .probe = ingenic_vcodec_probe, ++ .remove = ingenic_vcodec_remove, ++ .driver = { ++ .name = INGENIC_VCODEC_DEC_NAME, ++ .of_match_table = felix_of_match, ++ }, ++}; ++ ++static int __init felix_device_init(void) ++{ ++ platform_driver_register(&ingenic_vcodec_driver); ++ return 0; ++} ++ ++static void __exit felix_device_exit(void) ++{ ++ platform_driver_unregister(&ingenic_vcodec_driver); ++} ++ ++module_init(felix_device_init); ++module_exit(felix_device_exit); ++ ++ ++ ++MODULE_LICENSE("GPL V2"); ++MODULE_DESCRIPTION("Ingenic Video Codec v4l2 encoder driver."); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_felix_felix_drv.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_felix_felix_drv.h.patch new file mode 100644 index 00000000..34541b11 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_felix_felix_drv.h.patch @@ -0,0 +1,157 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/felix/felix_drv.h b/drivers/media/platform/ingenic-vcodec/felix/felix_drv.h +--- a/drivers/media/platform/ingenic-vcodec/felix/felix_drv.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/felix/felix_drv.h 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,153 @@ ++#ifndef __INGENIC_FELIX_DRV_H__ ++#define __INGENIC_FELIX_DRV_H__ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "libh264/libavcodec/avcodec.h" ++#include "libh264/libavcodec/frame.h" ++#include "libh264/libavcodec/h264dec.h" ++ ++ ++#define INGENIC_VCODEC_DEC_NAME "felix-vdec" ++#define INGENIC_VCODEC_MAX_PLANES 3 ++ ++enum ingenic_fmt_type { ++ INGENIC_FMT_FRAME = 0, ++ INGENIC_FMT_DEC = 1, ++}; ++ ++enum helix_h264_raw_format { ++ X264E_TILE_MODE = 0, ++ X264E_420P_MODE = 4, ++ X264E_NV12_MODE = 8, ++ X264E_NV21_MODE = 12, ++}; ++ ++struct ingenic_video_fmt { ++ u32 fourcc; ++ enum ingenic_fmt_type type; ++ u32 num_planes; ++ enum helix_h264_raw_format format; ++}; ++ ++struct ingenic_vcodec_framesizes { ++ u32 fourcc; ++ struct v4l2_frmsize_stepwise stepwise; ++}; ++ ++enum ingenic_vcodec_state { ++ INGENIC_STATE_IDLE = 0, ++ INGENIC_STATE_HEADER, ++ INGENIC_STATE_RUNNING, ++ INGENIC_STATE_ABORT, ++}; ++ ++ ++/* private vcode buf related to each vb2, TODO: will implement in future. */ ++/* ++ * 这里的大小必须是struct v4l2_m2m_buffer. ++ * */ ++struct ingenic_vcodec_buf { ++ struct vb2_buffer vb; ++ struct list_head list; //struct v4l2_m2m_buffer ++ ++ /*下面才是自己私有的数据结构.*/ ++ AVFrame frame; ++}; ++ ++enum ingenic_q_type { ++ INGENIC_Q_DATA_SRC = 0, ++ INGENIC_Q_DATA_DST = 1, ++}; ++ ++struct ingenic_vcodec_q_data { ++ unsigned int visible_width; ++ unsigned int visible_height; ++ unsigned int coded_width; ++ unsigned int coded_height; ++ enum v4l2_field field; ++ unsigned int bytesperline[INGENIC_VCODEC_MAX_PLANES]; ++ unsigned int sizeimage[INGENIC_VCODEC_MAX_PLANES]; ++ struct ingenic_video_fmt *fmt; ++}; ++ ++/* vpu hw ctx ?? */ ++ ++ ++ ++ ++/* Each open creates a ctx ? */ ++struct ingenic_vdec_ctx { ++ ++ struct ingenic_vdec_dev *dev; ++ struct v4l2_fh fh; ++ struct v4l2_m2m_ctx *m2m_ctx; ++ ++ struct v4l2_ctrl_handler ctrl_hdl; ++ ++ int id; /* used for debug ?*/ ++ ++ struct ingenic_vcodec_q_data q_data[2]; ++ ++ wait_queue_head_t queue; ++ int output_stopped; ++ int capture_stopped; ++ ++ enum ingenic_vcodec_state state; ++ ++ enum v4l2_colorspace colorspace; ++ ++ int int_cond; ++ struct mutex lock; ++ ++ AVCodecContext *avctx; ++ H264Context *h; ++ ++}; ++ ++ ++struct ingenic_vdec_dev { ++ struct v4l2_device v4l2_dev; ++ struct video_device *vfd; ++ struct device *dev; ++ ++ struct v4l2_m2m_dev *m2m_dev; ++ struct platform_device *plat_dev; ++ ++ struct mutex dev_mutex; ++ ++ /* TODO: add workqueue*/ ++ //struct workqueue_struct *dec_workqueue; ++ ++ spinlock_t spinlock; ++ ++ struct ingenic_vdec_ctx *curr_ctx; ++ struct vb2_dc_conf *alloc_ctx; ++ ++ int id_counter; ++ ++ void __iomem *reg_base; ++ int irq; ++ struct clk *clk_gate; ++ struct clk *clk; ++}; ++ ++ ++/* -----------------------------------helpler-------------------------------------*/ ++static inline struct ingenic_vdec_ctx *fh_to_ctx(struct v4l2_fh *fh) ++{ ++ return container_of(fh, struct ingenic_vdec_ctx, fh); ++} ++ ++static inline struct ingenic_vdec_ctx *ctrl_to_ctx(struct v4l2_ctrl *ctrl) ++{ ++ return container_of(ctrl->handler, struct ingenic_vdec_ctx, ctrl_hdl); ++} ++ ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_felix_felix_ops.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_felix_felix_ops.c.patch new file mode 100644 index 00000000..8f6ef807 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_felix_felix_ops.c.patch @@ -0,0 +1,1076 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/felix/felix_ops.c b/drivers/media/platform/ingenic-vcodec/felix/felix_ops.c +--- a/drivers/media/platform/ingenic-vcodec/felix/felix_ops.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/felix/felix_ops.c 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,1072 @@ ++/* ++* Copyright (c) 2014 Ingenic Inc. ++* Author: qipengzhen ++* ++* 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. ++* ++*/ ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include "felix_drv.h" ++#include "felix_ops.h" ++ ++#undef pr_debug ++#define pr_debug pr_info ++ ++#define fh_to_ctx(__fh) container_of(__fh, struct ingenic_vdec_ctx, fh) ++#define NUM_SUPPORTED_FRAMESIZE 1 ++ ++#define INGENIC_VDEC_MIN_W 160U ++#define INGENIC_VDEC_MIN_H 120U ++#define INGENIC_VDEC_MAX_W 2560U ++#define INGENIC_VDEC_MAX_H 2048U ++#define MAX_SUPPORT_FRAME_BUFFERS 16 ++ ++static struct ingenic_video_fmt ingenic_video_formats[] = { ++ /* out */ ++ { ++ .fourcc = V4L2_PIX_FMT_H264, ++ .type = INGENIC_FMT_DEC, ++ .num_planes = 1, ++ .format = 0, //maybe unused? ++ }, ++ ++ /* cap */ ++ { ++ .fourcc = V4L2_PIX_FMT_NV12, ++ .type = INGENIC_FMT_FRAME, ++ .num_planes = 2, ++ .format = 0, //maybe unused?? ++ } ++}; ++ ++#define NUM_FORMATS ARRAY_SIZE(ingenic_video_formats) ++#define OUT_FMT_IDX 0 ++#define CAP_FMT_IDX ARRAY_SIZE(ingenic_video_formats) - 1 ++ ++static const struct ingenic_vcodec_framesizes ingenic_vcodec_framesizes[] = { ++ { ++ .fourcc = V4L2_PIX_FMT_H264, ++ .stepwise = { INGENIC_VDEC_MIN_W, INGENIC_VDEC_MAX_W, 16, ++ INGENIC_VDEC_MIN_H, INGENIC_VDEC_MAX_H, 16}, ++ }, ++}; ++ ++ ++static int vidioc_querycap(struct file *file, void *priv, ++ struct v4l2_capability *cap) ++{ ++ strlcpy(cap->driver, INGENIC_VCODEC_DEC_NAME, sizeof(cap->driver)); ++ strlcpy(cap->bus_info, "vpu-felix", sizeof(cap->bus_info)); ++ strlcpy(cap->card, "vpu-felix", sizeof(cap->card)); ++ ++ cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE; ++ cap->capabilities = cap->device_caps | V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING | ++ V4L2_CAP_VIDEO_CAPTURE_MPLANE | ++ V4L2_CAP_VIDEO_OUTPUT_MPLANE | ++ V4L2_CAP_DEVICE_CAPS; ++ ++ return 0; ++} ++ ++ ++static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool output_queue) ++{ ++ struct ingenic_video_fmt *fmt; ++ int i,j = 0; ++ ++ ++ for(i = 0; i < NUM_FORMATS; i++) { ++ if(output_queue && ingenic_video_formats[i].type != INGENIC_FMT_DEC) ++ continue; ++ if(!output_queue && ingenic_video_formats[i].type != INGENIC_FMT_FRAME) ++ continue; ++ ++ if(j == f->index) { ++ fmt = &ingenic_video_formats[i]; ++ f->pixelformat = fmt->fourcc; ++ memset(f->reserved, 0, sizeof(f->reserved)); ++ return 0; ++ } ++ ++ j++; ++ } ++ ++ return -EINVAL; ++} ++ ++static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *priv, ++ struct v4l2_fmtdesc *f) ++{ ++ return vidioc_enum_fmt(f, false); ++} ++static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *priv, ++ struct v4l2_fmtdesc *f) ++{ ++ return vidioc_enum_fmt(f, true); ++} ++ ++static int vidioc_try_fmt(struct v4l2_format *f, struct ingenic_video_fmt *fmt) ++{ ++ struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; ++ int i; ++ ++ pix_fmt_mp->field = V4L2_FIELD_NONE; ++ ++ if(f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { ++ pix_fmt_mp->num_planes = 1; ++ pix_fmt_mp->plane_fmt[0].bytesperline = 0; ++ } else if(f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE){ ++ int tmp_w, tmp_h; ++ ++ pix_fmt_mp->height = clamp(pix_fmt_mp->height, ++ INGENIC_VDEC_MIN_H, ++ INGENIC_VDEC_MAX_H); ++ pix_fmt_mp->width = clamp(pix_fmt_mp->width, ++ INGENIC_VDEC_MIN_W, ++ INGENIC_VDEC_MAX_W); ++ ++ tmp_w = pix_fmt_mp->width; ++ tmp_h = pix_fmt_mp->height; ++ ++ tmp_w = (tmp_w + 15) / 16 - 1; ++ tmp_w = (tmp_w / 8) + 1; ++ pix_fmt_mp->width = tmp_w * 128; ++ ++#if 0 ++ v4l_bound_align_image(&pix_fmt_mp->width, ++ INGENIC_VDEC_MIN_W, ++ INGENIC_VDEC_MAX_W, 8, ++ &pix_fmt_mp->height, ++ INGENIC_VDEC_MIN_H, ++ INGENIC_VDEC_MAX_H, 0, 0); ++#endif ++ pr_debug("tmp_w %d tmp_h %d, w %d h %d\n", ++ tmp_w, tmp_h, ++ pix_fmt_mp->width, ++ pix_fmt_mp->height); ++ ++ ++ /* TODO: alignment handle ....*/ ++ pix_fmt_mp->num_planes = fmt->num_planes; ++ pix_fmt_mp->plane_fmt[0].sizeimage = ++ pix_fmt_mp->width * pix_fmt_mp->height; ++ ++ pix_fmt_mp->plane_fmt[0].bytesperline = pix_fmt_mp->width; ++ ++ if(pix_fmt_mp->num_planes == 2) { ++ pix_fmt_mp->plane_fmt[1].sizeimage = ++ pix_fmt_mp->width * pix_fmt_mp->height / 2; ++ pix_fmt_mp->plane_fmt[2].sizeimage = 0; ++ ++ pix_fmt_mp->plane_fmt[1].bytesperline = pix_fmt_mp->width; ++ pix_fmt_mp->plane_fmt[2].bytesperline = 0; ++ } else if(pix_fmt_mp->num_planes == 3) { ++ pix_fmt_mp->plane_fmt[1].sizeimage = ++ pix_fmt_mp->plane_fmt[2].sizeimage = ++ (pix_fmt_mp->width * pix_fmt_mp->height) / 4; ++ ++ pix_fmt_mp->plane_fmt[1].bytesperline = ++ pix_fmt_mp->plane_fmt[2].bytesperline = ++ pix_fmt_mp->width / 2; ++ } ++ } ++ ++ for(i = 0; i < pix_fmt_mp->num_planes; i++) { ++ memset(&(pix_fmt_mp->plane_fmt[i].reserved[0]), 0x0, ++ sizeof(pix_fmt_mp->plane_fmt[0].reserved)); ++ } ++ ++// pix_fmt_mp->flags = 0; ++ ++ memset(&pix_fmt_mp->reserved, 0x0, ++ sizeof(pix_fmt_mp->reserved)); ++ ++ return 0; ++} ++ ++static struct ingenic_vcodec_q_data *ingenic_vcodec_get_q_data(struct ingenic_vdec_ctx *ctx, ++ enum v4l2_buf_type type) ++{ ++ if(V4L2_TYPE_IS_OUTPUT(type)) ++ return &ctx->q_data[INGENIC_Q_DATA_SRC]; ++ ++ return &ctx->q_data[INGENIC_Q_DATA_DST]; ++} ++ ++static struct ingenic_video_fmt *ingenic_vcodec_find_format(struct v4l2_format *f) ++{ ++ struct ingenic_video_fmt *fmt; ++ int i; ++ ++ pr_debug("=========%s, %d, f->fmt.pix_mp.pixelformat %x\n", __func__, __LINE__, f->fmt.pix_mp.pixelformat); ++ ++ for(i = 0; i < NUM_FORMATS; i++) { ++ fmt = &ingenic_video_formats[i]; ++ pr_debug("fmt->fourcc %x\n", fmt->fourcc); ++ if(fmt->fourcc == f->fmt.pix_mp.pixelformat) ++ return fmt; ++ } ++ ++ pr_debug("=========Format not found ??????!\n"); ++ return NULL; ++} ++ ++static int vidioc_s_fmt_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ ++ struct ingenic_vdec_ctx *ctx = fh_to_ctx(priv); ++ struct vb2_queue *vq; ++ struct ingenic_vcodec_q_data *q_data; ++ struct ingenic_video_fmt *fmt; ++ int i, ret; ++ ++ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); ++ if(!vq) { ++ pr_err("failed to get cap vq !\n"); ++ return -EINVAL; ++ } ++ ++ if(vb2_is_busy(vq)) { ++ pr_err("cap vq is busy!\n"); ++ return -EINVAL; ++ } ++ ++ q_data = ingenic_vcodec_get_q_data(ctx, f->type); ++ if(!q_data) { ++ pr_err("fail to get cap q data!\n"); ++ return -EINVAL; ++ } ++ ++ ++ fmt = ingenic_vcodec_find_format(f); ++ if(!fmt) { ++ /* change to the first support cap format.*/ ++ f->fmt.pix.pixelformat = ingenic_video_formats[CAP_FMT_IDX].fourcc; ++ /* if buf type MPLANE, use pix_mp ..*/ ++ f->fmt.pix_mp.pixelformat = ingenic_video_formats[CAP_FMT_IDX].fourcc; ++ fmt = ingenic_vcodec_find_format(f); ++ } ++ ++ ++ q_data->fmt = fmt; ++ ++ ret = vidioc_try_fmt(f, q_data->fmt); ++ if(ret) ++ return ret; ++ ++ q_data->coded_width = f->fmt.pix_mp.width; ++ q_data->coded_height = f->fmt.pix_mp.height; ++ q_data->field = f->fmt.pix_mp.field; ++ ++ printk("-------s_fmt_cap: coded_width %d, coded_height %d\n", q_data->coded_width, q_data->coded_height); ++ ++ for(i = 0; i < f->fmt.pix_mp.num_planes; i++) { ++ struct v4l2_plane_pix_format *plane_fmt; ++ ++ plane_fmt = &f->fmt.pix_mp.plane_fmt[i]; ++ q_data->bytesperline[i] = plane_fmt->bytesperline; ++ q_data->sizeimage[i] = plane_fmt->sizeimage; ++ } ++ ++ ++ return 0; ++} ++ ++static int vidioc_s_fmt_out(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct ingenic_vdec_ctx *ctx = fh_to_ctx(priv); ++ struct vb2_queue *vq; ++ struct ingenic_vcodec_q_data *q_data; ++ struct ingenic_video_fmt *fmt; ++ struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; ++ int ret, i; ++ ++ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); ++ if(!vq) { ++ pr_err("fail to get out vq!\n"); ++ return -EINVAL; ++ } ++ if(vb2_is_busy(vq)) { ++ pr_err("out vq is busy!\n"); ++ return -EINVAL; ++ } ++ ++ q_data = ingenic_vcodec_get_q_data(ctx, f->type); ++ if(!q_data) { ++ pr_err("failed to get out q_data!\n"); ++ return -EINVAL; ++ } ++ ++ ++ pr_debug("s_fmt_out ... f->fmt %x %c%c%c%c\n", f->fmt.pix.pixelformat, f->fmt.pix.pixelformat); ++ pr_debug("s_fmt_out ... f->fmt %x\n", f->fmt.pix_mp.pixelformat); ++ fmt = ingenic_vcodec_find_format(f); ++ if(!fmt) { ++ /* change to the first support cap format.*/ ++ f->fmt.pix.pixelformat = ingenic_video_formats[OUT_FMT_IDX].fourcc; ++ f->fmt.pix_mp.pixelformat = ingenic_video_formats[OUT_FMT_IDX].fourcc; ++ fmt = ingenic_vcodec_find_format(f); ++ } ++ ++ ++ pix_fmt_mp->height = clamp(pix_fmt_mp->height, ++ INGENIC_VDEC_MIN_H, ++ INGENIC_VDEC_MAX_H); ++ pix_fmt_mp->width = clamp(pix_fmt_mp->width, ++ INGENIC_VDEC_MIN_W, ++ INGENIC_VDEC_MAX_W); ++ ++ q_data->visible_width = f->fmt.pix_mp.width; ++ q_data->visible_height = f->fmt.pix_mp.height; ++ q_data->fmt = fmt; ++ ret = vidioc_try_fmt(f, q_data->fmt); ++ if (ret) ++ return ret; ++ ++ q_data->coded_width = f->fmt.pix_mp.width; ++ q_data->coded_height = f->fmt.pix_mp.height; ++ ++ printk("--------s_fmt_out coded_width %d, coded_height %d\n", q_data->coded_width, q_data->coded_height); ++ ++ q_data->field = f->fmt.pix_mp.field; ++ ctx->colorspace = f->fmt.pix_mp.colorspace; ++ //ctx->ycbcr_enc = f->fmt.pix_mp.ycbcr_enc; ++ //ctx->quantization = f->fmt.pix_mp.quantization; ++ //ctx->xfer_func = f->fmt.pix_mp.xfer_func; ++ ++ ++ for (i = 0; i < f->fmt.pix_mp.num_planes; i++) { ++ struct v4l2_plane_pix_format *plane_fmt; ++ ++ plane_fmt = &f->fmt.pix_mp.plane_fmt[i]; ++ q_data->bytesperline[i] = plane_fmt->bytesperline; ++ q_data->sizeimage[i] = plane_fmt->sizeimage; ++ } ++ ++ ++ return 0; ++} ++ ++static int vidioc_g_fmt(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ ++ struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; ++ struct ingenic_vdec_ctx *ctx = fh_to_ctx(priv); ++ struct vb2_queue *vq; ++ struct ingenic_vcodec_q_data *q_data; ++ int i; ++ ++ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); ++ if (!vq) ++ return -EINVAL; ++ ++ q_data = ingenic_vcodec_get_q_data(ctx, f->type); ++ ++ pix->width = q_data->coded_width; ++ pix->height = q_data->coded_height; ++ pix->pixelformat = q_data->fmt->fourcc; ++ pix->field = q_data->field; ++ pix->num_planes = q_data->fmt->num_planes; ++ for (i = 0; i < pix->num_planes; i++) { ++ pix->plane_fmt[i].bytesperline = q_data->bytesperline[i]; ++ pix->plane_fmt[i].sizeimage = q_data->sizeimage[i]; ++ memset(&(pix->plane_fmt[i].reserved[0]), 0x0, ++ sizeof(pix->plane_fmt[i].reserved)); ++ } ++ ++// pix->flags = 0; ++ pix->colorspace = ctx->colorspace; ++// pix->ycbcr_enc = ctx->ycbcr_enc; ++// pix->quantization = ctx->quantization; ++// pix->xfer_func = ctx->xfer_func; ++ ++ ++ pr_debug("g_fmt f->type %d\n", f->type); ++ ++ pr_debug("pixel_format = %x\n", pix->pixelformat); ++ pr_debug("pix->num_planes %d\n", pix->num_planes); ++ ++ return 0; ++} ++ ++static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct ingenic_video_fmt *fmt; ++ struct ingenic_vdec_ctx *ctx = fh_to_ctx(priv); ++ ++ fmt = ingenic_vcodec_find_format(f); ++ if (!fmt) { ++ f->fmt.pix.pixelformat = ingenic_video_formats[CAP_FMT_IDX].fourcc; ++ f->fmt.pix_mp.pixelformat = ingenic_video_formats[CAP_FMT_IDX].fourcc; ++ fmt = ingenic_vcodec_find_format(f); ++ } ++ f->fmt.pix_mp.colorspace = ctx->colorspace; ++ //f->fmt.pix_mp.ycbcr_enc = ctx->ycbcr_enc; ++ //f->fmt.pix_mp.quantization = ctx->quantization; ++ //f->fmt.pix_mp.xfer_func = ctx->xfer_func; ++ ++ return vidioc_try_fmt(f, fmt); ++} ++ ++static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ ++ struct ingenic_video_fmt *fmt; ++ ++ pr_debug("==== %s, %d, fmt %x\n", __func__, __LINE__, f->fmt.pix.pixelformat); ++ pr_debug("==== %s, %d,pix_mp %x\n", __func__, __LINE__, f->fmt.pix_mp.pixelformat); ++ fmt = ingenic_vcodec_find_format(f); ++ if (!fmt) { ++ f->fmt.pix.pixelformat = ingenic_video_formats[OUT_FMT_IDX].fourcc; ++ f->fmt.pix_mp.pixelformat = ingenic_video_formats[OUT_FMT_IDX].fourcc; ++ fmt = ingenic_vcodec_find_format(f); ++ } ++ if (!f->fmt.pix_mp.colorspace) { ++ f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_REC709; ++ // f->fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; ++ // f->fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT; ++ // f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT; ++ } ++ ++ pr_debug("==== %s, %d, fmt %x\n", __func__, __LINE__, f->fmt.pix.pixelformat); ++ pr_debug("==== %s, %d,pix_mp %x\n", __func__, __LINE__, f->fmt.pix_mp.pixelformat); ++ ++ return vidioc_try_fmt(f, fmt); ++} ++ ++static int vidioc_reqbufs(struct file *file, void *priv, ++ struct v4l2_requestbuffers *reqbufs) ++{ ++ struct ingenic_vdec_ctx *ctx = fh_to_ctx(priv); ++ ++ pr_debug("%s--%d\n", __func__, __LINE__); ++ pr_debug("====== %s, %d, buf->type %d\n", __func__, __LINE__, reqbufs->type); ++ pr_debug("============================ reqbufs: count: %d\n", reqbufs->count); ++ ++ return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); ++ ++} ++ ++static int vidioc_querybuf(struct file *file, void *priv, ++ struct v4l2_buffer *buf) ++{ ++ struct ingenic_vdec_ctx *ctx = fh_to_ctx(priv); ++ ++ return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); ++ ++} ++ ++static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) ++{ ++ struct ingenic_vdec_ctx *ctx = fh_to_ctx(priv); ++ ++ if(ctx->state == INGENIC_STATE_ABORT) { ++ return -EIO; ++ } ++#if 0 ++ printk("---%s, %d, index: %d, type:%d [%s]\n", ++ __func__, __LINE__, buf->index, buf->type, buf->type == 10 ? "OUTPUT":"CAPTUR"); ++#endif ++ return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); ++} ++ ++static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) ++{ ++ struct ingenic_vdec_ctx *ctx = fh_to_ctx(priv); ++#if 0 ++ printk("---%s, %d, index: %d, type:%d [%s]\n", ++ __func__, __LINE__, buf->index, buf->type, buf->type == 10 ? "OUTPUT":"CAPTUR"); ++#endif ++ return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); ++} ++ ++static int vidioc_expbuf(struct file *file, void *priv, ++ struct v4l2_exportbuffer *eb) ++{ ++ ++ struct ingenic_vdec_ctx *ctx = fh_to_ctx(priv); ++ ++ return v4l2_m2m_expbuf(file, ctx->m2m_ctx, eb); ++} ++ ++static int vidioc_create_bufs(struct file *file, void *priv, ++ struct v4l2_create_buffers *create) ++{ ++ struct ingenic_vdec_ctx *ctx = fh_to_ctx(priv); ++ ++ return v4l2_m2m_create_bufs(file, ctx->m2m_ctx, create); ++} ++static int vidioc_prepare_buf(struct file *file, void *fh, struct v4l2_buffer *b) ++{ ++ //TODO ....??? ++ ++ return 0; ++} ++ ++static int vidioc_streamon(struct file *file, void *priv, ++ enum v4l2_buf_type type) ++{ ++ struct ingenic_vdec_ctx *ctx = fh_to_ctx(priv); ++ pr_debug("====== %s, %d\n", __func__, __LINE__); ++ ++ return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); ++} ++ ++static int vidioc_streamoff(struct file *file, void *priv, ++ enum v4l2_buf_type type) ++{ ++ struct ingenic_vdec_ctx *ctx = fh_to_ctx(priv); ++ pr_debug("====== %s, %d\n", __func__, __LINE__); ++ ++ ++ return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); ++} ++ ++ ++static int vidioc_g_selection(struct file *file, void *priv, ++ struct v4l2_selection *s) ++{ ++ // TODO ++ ++ return 0; ++} ++ ++static int vidioc_s_selection(struct file *file, void *priv, ++ struct v4l2_selection *s) ++{ ++ //TODO ++ return 0; ++} ++ ++static int vidioc_enum_framesizes(struct file *file, void *fh, ++ struct v4l2_frmsizeenum *fsize) ++{ ++ int i = 0; ++ if(fsize->index != 0) ++ return -EINVAL; ++ ++ for(i = 0; i < NUM_SUPPORTED_FRAMESIZE; i++) { ++ if(fsize->pixel_format != ingenic_vcodec_framesizes[i].fourcc) ++ continue; ++ ++ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; ++ fsize->stepwise = ingenic_vcodec_framesizes[i].stepwise; ++ return 0; ++ } ++ ++ return -EINVAL; ++} ++ ++const struct v4l2_ioctl_ops ingenic_vdec_ioctl_ops = { ++ ++ /* VIDIOC_QUERYCAP handler */ ++ .vidioc_querycap = vidioc_querycap, ++ ++ /* VIDIOC_ENUM_FMT handlers */ ++ .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane, ++ .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane, ++ ++ /* VIDIOC_G_FMT handlers */ ++ .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt, ++ .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt, ++ ++ /* VIDIOC_S_FMT handlers */ ++ .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_cap, ++ .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_out, ++ ++ /* VIDIOC_TRY_FMT handlers */ ++ .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap_mplane, ++ .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_vid_out_mplane, ++ ++ /* Buffer handlers */ ++ .vidioc_reqbufs = vidioc_reqbufs, ++ .vidioc_querybuf = vidioc_querybuf, ++ .vidioc_qbuf = vidioc_qbuf, ++ .vidioc_dqbuf = vidioc_dqbuf, ++ .vidioc_expbuf = vidioc_expbuf, ++ ++ .vidioc_create_bufs = vidioc_create_bufs, ++ .vidioc_prepare_buf = vidioc_prepare_buf, ++ ++ /* Stream on/off */ ++ .vidioc_streamon = vidioc_streamon, ++ .vidioc_streamoff = vidioc_streamoff, ++ ++ /* Crop ioctls */ ++ .vidioc_g_selection = vidioc_g_selection, ++ .vidioc_s_selection = vidioc_s_selection, ++ ++ .vidioc_enum_framesizes = vidioc_enum_framesizes, ++ ++ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, ++ .vidioc_unsubscribe_event = v4l2_event_unsubscribe, ++ ++}; ++ ++ ++static void dump_vb2_buffer(struct vb2_buffer *vb2, const char *str) ++{ ++ int i; ++ printk("======dump vb2: %s=========\n", str); ++ printk("vb2->num_planes: %d\n", vb2->num_planes); ++ printk("vb2->v4l2_buf.index: %d\n", vb2->index); ++ printk("vb2->v4l2_buf.type: %d\n", vb2->type); ++ //printk("vb2->v4l2_buf.sequence: %d\n", vb2->v4l2_buf.sequence); ++ //printk("vb2->v4l2_buf.length: %d\n", vb2->v4l2_buf.length); ++ for(i = 0; i < vb2->num_planes; i++) { ++ printk("planes@ %d : \n", i); ++ printk("\tbyteused: %d\n", vb2->planes[i].bytesused); ++ printk("\tlength: %d\n", vb2->planes[i].length); ++ ++ printk("\tvaddr: 0x%08x\n", vb2_plane_vaddr(vb2, i)); ++ printk("\tpaddr: 0x%08x\n", vb2_dma_contig_plane_dma_addr(vb2, i)); ++ ++ /* data from vaddr to vaddr + length */ ++ print_hex_dump(KERN_INFO, "data@ ", DUMP_PREFIX_ADDRESS, 16, 1, vb2_plane_vaddr(vb2, i), 128, true); ++ ++ printk("----------------------------------------\n"); ++ } ++} ++ ++static AVFrame frame; ++#define av_frame_to_vcode_buf(f) \ ++ container_of(f, struct ingenic_vcodec_buf, frame) \ ++ ++static void m2mops_vdec_device_run(void *priv) ++{ ++ struct ingenic_vdec_ctx *ctx = priv; ++ struct ingenic_vdec_dev *dev = ctx->dev; ++ struct vb2_v4l2_buffer *src_buf, *dst_buf; ++ AVCodecContext *avctx = ctx->avctx; ++ H264Context *h = ctx->h; ++ AVFrame *f = NULL; ++ AVPacket avpkt; ++ int got_frame = 0; ++ ++ ++ ++ src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); ++ dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); ++ ++ //dump_vb2_buffer(src_buf, "src_buf"); ++ //dump_vb2_buffer(dst_buf, "dst_buf"); ++ ++ ++ avpkt.data = vb2_plane_vaddr(src_buf, 0); ++ avpkt.size = vb2_get_plane_payload(src_buf, 0); ++ avpkt.data_pa = vb2_dma_contig_plane_dma_addr(src_buf, 0); ++ ++ /*如果获取到了目标buffer,就将该buffer给到vpu.*/ ++ if(dst_buf) { ++ struct ingenic_vcodec_buf *buf = container_of(dst_buf, ++ struct ingenic_vcodec_buf, vb); ++ ++ /*TODO: copy timestamp, display 顺序号可能不一样,这样dst_buf的时间戳可能会前后颠倒,这样会有问题吗?如何避免?*/ ++ dst_buf->timestamp = src_buf->timestamp; ++ dst_buf->timecode = src_buf->timecode; ++ dst_buf->sequence = src_buf->sequence; ++ ++ h264_enqueue_frame(h, &buf->frame); ++ } ++ ++ h264_decode_frame(avctx, &frame, &got_frame, &avpkt); ++ if(got_frame) { ++ /*如果解码完一帧了,那就将所有的可显示的buffer都标记为buffer_done.*/ ++ /*drain display frame*/ ++ f = h264_dequeue_frame(h); ++ if(f) { ++ struct ingenic_vcodec_buf *done_buf = av_frame_to_vcode_buf(f); ++ //printk("------done_buf: %x done frame f: %x-----buf->index:%d, f->index: %d\n", done_buf, f, done_buf->vb.v4l2_buf.index, f->index); ++ ++ ++ vb2_set_plane_payload(&done_buf->vb, 0, f->buf[0]->size); ++ vb2_set_plane_payload(&done_buf->vb, 1, f->buf[1]->size); ++ v4l2_m2m_buf_done(&done_buf->vb, VB2_BUF_STATE_DONE); ++ } ++ } ++ ++ /*src_buf 只需要返回STATE_DONE.*/ ++ v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); ++ ++ ++ v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->m2m_ctx); ++} ++ ++ ++static int m2mops_vdec_job_ready(void *m2m_priv) ++{ ++ struct ingenic_vdec_ctx *ctx = m2m_priv; ++ ++ if(ctx->state == INGENIC_STATE_ABORT || ctx->state == INGENIC_STATE_IDLE) { ++ pr_info("job not ready, ctx->state %d\n", ctx->state); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++ ++static void m2mops_vdec_job_abort(void *priv) ++{ ++ struct ingenic_vdec_ctx *ctx = priv; ++ ctx->state = INGENIC_STATE_ABORT; ++} ++ ++ ++static void m2mops_vdec_lock(void *m2m_priv) ++{ ++ struct ingenic_vdec_ctx *ctx = m2m_priv; ++ ++ //TODO ++ mutex_lock(&ctx->dev->dev_mutex); ++} ++ ++static void m2mops_vdec_unlock(void *m2m_priv) ++{ ++ struct ingenic_vdec_ctx *ctx = m2m_priv; ++ ++ mutex_unlock(&ctx->dev->dev_mutex); ++} ++ ++const struct v4l2_m2m_ops ingenic_vdec_m2m_ops = { ++ .device_run = m2mops_vdec_device_run, ++ .job_ready = m2mops_vdec_job_ready, ++ .job_abort = m2mops_vdec_job_abort, ++ .lock = m2mops_vdec_lock, ++ .unlock = m2mops_vdec_unlock, ++}; ++ ++static int vb2ops_vcodec_queue_setup(struct vb2_queue *vq, ++ const struct v4l2_format *fmt, ++ unsigned int *nbuffers, ++ unsigned int *nplanes, ++ unsigned int sizes[], ++ void *alloc_ctxs[]) ++{ ++ struct ingenic_vdec_ctx *ctx = vb2_get_drv_priv(vq); ++ struct ingenic_vcodec_q_data *q_data; ++ int i; ++ ++ pr_debug("%s--%d\n", __func__, __LINE__); ++ ++ q_data = ingenic_vcodec_get_q_data(ctx, vq->type); ++ if(q_data == NULL) ++ return -EINVAL; ++ ++ pr_debug("%s--%d, vq->type %d\n", __func__, __LINE__, vq->type); ++ ++ if(*nplanes) { ++ for(i = 0; i < *nplanes; i++) { ++ if(sizes[i] < q_data->sizeimage[i]) { ++ pr_debug("---sizes %d %d, %d\n", *nplanes, sizes[i], q_data->sizeimage[i]); ++ return -EINVAL; ++ } ++ } ++ } else { ++ *nplanes = q_data->fmt->num_planes; ++ for (i = 0; i < *nplanes; i++) { ++ sizes[i] = q_data->sizeimage[i]; ++ alloc_ctxs[i] = ctx->dev->alloc_ctx; ++ } ++ } ++ ++ ++ pr_debug("*nplanes %d, sizes[0] %d\n", *nplanes, sizes[0]); ++ for(i = 0; i<*nplanes ; i++) { ++ pr_debug("plane %d, sizes[%d] %d, type %d\n", i, i, sizes[i], vq->type); ++ } ++ ++ if(*nbuffers > MAX_SUPPORT_FRAME_BUFFERS) ++ *nbuffers = MAX_SUPPORT_FRAME_BUFFERS; ++ ++ pr_debug("%s--%d\n", __func__, __LINE__); ++ return 0; ++} ++ ++static int vb2ops_vcodec_buf_prepare(struct vb2_buffer *vb) ++{ ++ struct ingenic_vdec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); ++ struct ingenic_vcodec_q_data *q_data; ++ int i; ++ ++#if 0 ++ printk("---%s, %d, index: %d, type:%d\n", ++ __func__, __LINE__, vb->v4l2_buf.index, vb->vb2_queue->type); ++#endif ++ q_data = ingenic_vcodec_get_q_data(ctx, vb->vb2_queue->type); ++ ++ for(i = 0; i < q_data->fmt->num_planes; i++) { ++ if(vb2_plane_size(vb, i) > q_data->sizeimage[i]) { ++ ++ pr_err("Failed to prepare buf!\n"); ++ ++ return -EINVAL; ++ } ++ } ++ ++#if 0 ++ pr_debug("%s--%d\n", __func__, __LINE__); ++#endif ++ return 0; ++} ++ ++ ++static int vb2ops_vcodec_buf_init(struct vb2_buffer *vb) ++{ ++ struct ingenic_vcodec_buf *buf = container_of(vb, ++ struct ingenic_vcodec_buf, vb); ++ ++ int i; ++ AVFrame *f = &buf->frame; ++ ++ f->index = vb->index; ++ for(i = 0; i < vb->num_planes; i++) { ++ f->buf[i] = av_buffer_create(vb2_plane_vaddr(vb, i), ++ vb2_dma_contig_plane_dma_addr(vb, i), ++ vb2_plane_size(vb, i) ++ ); ++ } ++ return 0; ++} ++static int vb2ops_vcodec_buf_cleanup(struct vb2_buffer *vb) ++{ ++ struct ingenic_vcodec_buf *buf = container_of(vb, ++ struct ingenic_vcodec_buf, vb); ++ int i; ++ AVFrame *f = &buf->frame; ++ ++ for(i = 0; i < vb->num_planes; i++) { ++ av_buffer_del(f->buf[i]); ++ } ++ ++ return 0; ++} ++ ++static void vb2ops_vcodec_buf_queue(struct vb2_buffer *vb) ++{ ++ struct ingenic_vdec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); ++ struct ingenic_vcodec_buf *buf = container_of(vb, ++ struct ingenic_vcodec_buf, vb); ++ H264Context *h = ctx->h; ++ ++ v4l2_m2m_buf_queue(ctx->m2m_ctx, vb); ++ return; ++} ++ ++static int vb2ops_vcodec_buf_finish(struct vb2_buffer *vb) ++{ ++ /* call back before dqbuf to user. */ ++ struct ingenic_vdec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); ++ ++ return 0; ++} ++ ++ ++static int vb2ops_vcodec_start_streaming(struct vb2_queue *q, unsigned int count) ++{ ++ struct ingenic_vdec_ctx *ctx = vb2_get_drv_priv(q); ++// struct venc_sw_param *sw = ctx->sw; ++ struct ingenic_vcodec_q_data *q_data_src; ++ struct ingenic_vcodec_q_data *q_data_dst; ++ int ret = 0; ++ ++ pr_debug("%s--%d\n", __func__, __LINE__); ++ ++ pr_debug("%s--%d, type: %d, count: %d", __func__, __LINE__, q->type, count); ++ ++ if(V4L2_TYPE_IS_OUTPUT(q->type)) { ++ ctx->output_stopped = 0; ++ } else { ++ ctx->capture_stopped = 0; ++ } ++ ++ pr_debug("ctx->output_stopped: %d, ctx->capture_stopped: %d\n", ctx->output_stopped, ctx->capture_stopped); ++ ++ if(ctx->output_stopped || ctx->capture_stopped) ++ return 0; ++ ++ /* 如果两个queue都start了,就可以初始化workbuf了,这里主要根据输入的格式,输出的格式,申请除了用户空间q 和 dq之外的自己使用的buffer.*/ ++ ++ q_data_src = ingenic_vcodec_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); ++ q_data_dst = ingenic_vcodec_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); ++ ++#if 0 ++ sw->width = q_data_src->visible_width; ++ sw->height = q_data_src->visible_height; ++ sw->format = q_data_src->fmt->format; ++ sw->vdma_chain_len = 40960 + 256; ++ ++ sw->src_crc = 0; ++ ++ ret = helix_vcodec_alloc_workbuf(ctx); ++ if(ret < 0) { ++ pr_err("Falied to alloc vpu workbuf!\n"); ++ return ret; ++ } ++ ++ ++ ++// ctx->state = INGENIC_STATE_HEADER; ++ ++ /* do sps/pps encoder and stored it in ctx.*/ ++ helix_vcodec_h264_encode_headers(ctx); ++ /* State -> started?? */ ++ ++ if(sw->i_cabac) { ++ h264_cabac_init(); ++ } else { ++ printk("Only support cabac.!\n"); ++ } ++#endif ++ ctx->state = INGENIC_STATE_RUNNING; ++ pr_debug("%s--%d\n", __func__, __LINE__); ++ return 0; ++} ++ ++static int vb2ops_vcodec_stop_streaming(struct vb2_queue *q) ++{ ++ ++ struct ingenic_vdec_ctx *ctx = vb2_get_drv_priv(q); ++ struct vb2_v4l2_buffer *src_buf, *dst_buf; ++ int ret = 0; ++ pr_debug("%s--%d\n", __func__, __LINE__); ++ ++// printk("------ sw->src_crc %x\n", ctx->sw->src_crc); ++ /* stop both output and capture .*/ ++ ++ /* 当上层输入的数据没有了,就会draining, 只会停止OUTPUT stream, ++ 但是,此时,上层还是会进行dequeue CAPTURE stream, ++ 而此时,CAPTURE stream又没有数据,肯定会失败。 ++ ++ 所以应该上层判断是否没有原始数据了,如果没有原始数据,就不要再polling了。 ++ ++ 上层实现有问题了?????? ++ ++ */ ++ ++// if(q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { ++ ++ /* KERNEL 3.10 .*/ ++ while((dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx))) { ++ dst_buf->vb2_buf.planes[0].bytesused = 0; ++ dst_buf->flags |= V4L2_BUF_FLAG_DONE; ++ do_gettimeofday(&dst_buf->timestamp); ++ /*保证两个的时间戳不一样.*/ ++ dst_buf->timestamp = ns_to_timeval((timeval_to_ns(&dst_buf->timestamp) + 10)); ++ /* work around, return buffer to userspace with 0 byteused. */ ++ v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); ++ } ++// } else { ++ while((src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx))) { ++ v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); ++ } ++// } ++ ++ if(q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) ++ ctx->capture_stopped = 1; ++ else ++ ctx->output_stopped = 1; ++ ++ if((ctx->capture_stopped && ctx->output_stopped) == 0) { ++ return ret; ++ } ++ ++#if 0 ++ /* State -> stopped ?? */ ++ ++ helix_vcodec_free_workbuf(ctx); ++ ++ ctx->state = INGENIC_STATE_IDLE; ++#endif ++ ++ pr_debug("%s--%d\n", __func__, __LINE__); ++ return ret; ++} ++ ++static const struct vb2_ops ingenic_vcodec_vb2_ops = { ++ .queue_setup = vb2ops_vcodec_queue_setup, ++ .buf_prepare = vb2ops_vcodec_buf_prepare, ++ .buf_init = vb2ops_vcodec_buf_init, ++ .buf_cleanup = vb2ops_vcodec_buf_cleanup, ++ .buf_queue = vb2ops_vcodec_buf_queue, ++ .buf_finish = vb2ops_vcodec_buf_finish, ++ .wait_prepare = vb2_ops_wait_prepare, ++ .wait_finish = vb2_ops_wait_finish, ++ .start_streaming = vb2ops_vcodec_start_streaming, ++ .stop_streaming = vb2ops_vcodec_stop_streaming, ++}; ++ ++int ingenic_vcodec_vdec_queue_init(void *priv, struct vb2_queue *src_vq, ++ struct vb2_queue *dst_vq) ++{ ++ struct ingenic_vdec_ctx *ctx = priv; ++ int ret = 0; ++ ++ /* TODO: to support VB2_USERPTR with dmmu?. */ ++ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; ++ src_vq->io_modes = VB2_DMABUF | VB2_MMAP; ++ src_vq->drv_priv = ctx; ++ src_vq->buf_struct_size = sizeof(struct ingenic_vcodec_buf); ++ src_vq->ops = &ingenic_vcodec_vb2_ops; ++ src_vq->mem_ops = &vb2_dma_contig_memops; ++ src_vq->lock = &ctx->dev->dev_mutex; ++ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; ++// src_vq->dev = ctx->dev->dev; ++ ++ ret = vb2_queue_init(src_vq); ++ if(ret) ++ return ret; ++ ++ ++ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; ++ dst_vq->io_modes = VB2_DMABUF | VB2_MMAP; ++ dst_vq->drv_priv = ctx; ++ dst_vq->buf_struct_size = sizeof(struct ingenic_vcodec_buf); ++ dst_vq->ops = &ingenic_vcodec_vb2_ops; ++ dst_vq->mem_ops = &vb2_dma_contig_memops; ++ dst_vq->lock = &ctx->dev->dev_mutex; ++ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; ++// dst_vq->dev = ctx->dev->dev; ++ ++ ret = vb2_queue_init(dst_vq); ++ if(ret) { ++ vb2_queue_release(src_vq); ++ } ++ ++ return ret; ++} ++ ++ ++int ingenic_vcodec_init_default_params(struct ingenic_vdec_ctx *ctx) ++{ ++ int ret = 0; ++ ctx->capture_stopped = 1; ++ ctx->output_stopped = 1; ++ ctx->state = INGENIC_STATE_IDLE; ++ ++ return ret; ++} ++ ++int ingenic_vcodec_deinit_default_params(struct ingenic_vdec_ctx *ctx) ++{ ++ ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_felix_felix_ops.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_felix_felix_ops.h.patch new file mode 100644 index 00000000..a3ce877e --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_felix_felix_ops.h.patch @@ -0,0 +1,18 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/felix/felix_ops.h b/drivers/media/platform/ingenic-vcodec/felix/felix_ops.h +--- a/drivers/media/platform/ingenic-vcodec/felix/felix_ops.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/felix/felix_ops.h 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,14 @@ ++#ifndef __FELIX_OPS_H__ ++#define __FELIX_OPS_H__ ++ ++extern const struct v4l2_ioctl_ops ingenic_vdec_ioctl_ops; ++extern const struct v4l2_m2m_ops ingenic_vdec_m2m_ops; ++ ++int ingenic_vcodec_vdec_queue_init(void *priv, struct vb2_queue *src_vq, ++ struct vb2_queue *dst_vq); ++ ++int ingenic_vcodec_init_default_params(struct ingenic_vdec_ctx *ctx); ++ ++int ingenic_vcodec_deinit_default_params(struct ingenic_vdec_ctx *ctx); ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_Makefile.patch new file mode 100644 index 00000000..c43a28fd --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_Makefile.patch @@ -0,0 +1,22 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/helix/Makefile b/drivers/media/platform/ingenic-vcodec/helix/Makefile +--- a/drivers/media/platform/ingenic-vcodec/helix/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/helix/Makefile 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,18 @@ ++obj-y += helix_drv.o ++obj-y += default_sliceinfo.o ++obj-y += helix_ops.o ++#obj-y += helix_ctrl.o ++obj-y += api/helix_x264_enc.o ++obj-y += api/helix_jpeg_enc.o ++obj-y += api/helix_jpeg_dec.o ++ ++obj-y += h264enc/set.o ++obj-y += h264enc/cabac.o ++obj-y += h264enc/common.o ++obj-y += h264enc/slice.o ++ ++obj-y += h264e.o ++obj-y += jpge.o ++obj-y += jpgd.o ++ ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_README.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_README.patch new file mode 100644 index 00000000..2f98dd9c --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_README.patch @@ -0,0 +1,8 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/helix/README b/drivers/media/platform/ingenic-vcodec/helix/README +--- a/drivers/media/platform/ingenic-vcodec/helix/README 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/helix/README 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,4 @@ ++ ++helix-drv.c <---- v4l2 implementation. ++helix-ctrl.c <---- helix controller driver. ++helix-x264-enc.c <---- encoder APIs. diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_api_helix.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_api_helix.h.patch new file mode 100644 index 00000000..1ca975bb --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_api_helix.h.patch @@ -0,0 +1,3463 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/helix/api/helix.h b/drivers/media/platform/ingenic-vcodec/helix/api/helix.h +--- a/drivers/media/platform/ingenic-vcodec/helix/api/helix.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/helix/api/helix.h 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,3459 @@ ++/**************************************************************** ++*****************************************************************/ ++#ifndef __HELIX_H__ ++#define __HELIX_H__ ++ ++/**************************************************************** ++ VPU register map ++*****************************************************************/ ++#define JZM_V2_TLB ++ ++#ifdef JZM_HUNT_SIM ++#include "hunt.h" ++#else ++#ifndef __place_k0_data__ ++#define __place_k0_data__ ++#endif ++#ifndef __place_k0_text__ ++#define __place_k0_text__ ++#endif ++#endif ++ ++#define VPU_BASE 0x13300000 ++ ++#define HID_SCH 0x0 ++#define HID_JRFD 0x1 ++#define HID_EMC 0x3 ++#define HID_EFE 0x4 ++#define HID_MCE 0x5 ++#define HID_ODMA 0x6 ++#define HID_DBLK 0x7 ++#define HID_VMAU 0x8 ++#define HID_SDE 0x9 ++#define HID_AUX 0xA ++#define HID_TCSM 0xB ++#define HID_IFA 0xB //fixme ++#define HID_JPGC 0xE ++#define HID_SRAM 0xF ++ ++#define VPU_MAX_MB_WIDTH 256 ++ ++#define MSCOPE_START(mbnum) write_reg(VPU_BASE+0x24, mbnum) ++#define MSCOPE_STOP() write_reg(VPU_BASE+0x28, 0) ++ ++/******************************************** ++ SCH (Scheduler) ++*********************************************/ ++#define TCSM_FLUSH 0xc0000 ++#define REG_SCH_GLBC 0x00000 ++#define SCH_GLBC_SLDE (0x1<<31) ++#ifdef JZM_V2_TLB ++# define SCH_TLBE_JPGC (0x1<<26) ++# define SCH_TLBE_DBLK (0x1<<25) ++# define SCH_TLBE_SDE (0x1<<24) ++# define SCH_TLBE_EFE (0x1<<23) ++# define SCH_TLBE_VDMA (0x1<<22) ++# define SCH_TLBE_MCE (0x1<<21) ++#else ++# define SCH_GLBC_TLBE (0x1<<30) ++# define SCH_GLBC_TLBINV (0x1<<29) ++#endif ++#define SCH_INTE_RESERR (0x1<<29) ++#define SCH_INTE_BSFULL (0x1<<28) ++#define SCH_INTE_ACFGERR (0x1<<20) ++#define SCH_INTE_TLBERR (0x1<<18) ++#define SCH_INTE_BSERR (0x1<<17) ++#define SCH_INTE_ENDF (0x1<<16) ++#define SCH_GLBC_HIMAP (0x1<<15) ++#define SCH_GLBC_HIAXI (0x1<<9) ++#define SCH_GLBC_EPRI0 (0x0<<7) ++#define SCH_GLBC_EPRI1 (0x1<<7) ++#define SCH_GLBC_EPRI2 (0x2<<7) ++#define SCH_GLBC_EPRI3 (0x3<<7) ++ ++#define REG_SCH_TLBA 0x00030 ++ ++#ifdef JZM_V2_TLB ++# define REG_SCH_TLBC 0x00050 ++# define SCH_TLBC_VPN (0xFFFFF000) ++# define SCH_TLBC_RIDX(idx) (((idx) & 0xFF)<<4) ++# define SCH_TLBC_INVLD (0x1<<1) ++# define SCH_TLBC_RETRY (0x1<<0) ++ ++# define REG_SCH_TLBV 0x00054 ++# define SCH_TLBV_CNM(cnm) (((cnm) & 0xFFF)<<16) ++# define SCH_TLBV_GCN(gcn) (((gcn) & 0xFFF)<<0) ++# define SCH_TLBV_RCI_MC (0x1<<30) ++# define SCH_TLBV_RCI_EFE (0x1<<31) ++#endif ++ ++#define REG_SCH_STAT 0x00034 ++#define SCH_STAT_ENDF (0x1<<0) ++#define SCH_STAT_BPF (0x1<<1) ++#define SCH_STAT_ACFGERR (0x1<<2) ++#define SCH_STAT_TIMEOUT (0x1<<3) ++#define SCH_STAT_JPGEND (0x1<<4) ++#define SCH_STAT_BSERR (0x1<<7) ++#define SCH_STAT_TLBERR (0x1F<<10) ++#define SCH_STAT_SLDERR (0x1<<16) ++ ++ ++#define REG_SCH_SLDE0 0x00040 ++#define REG_SCH_SLDE1 0x00044 ++#define REG_SCH_SLDE2 0x00048 ++#define REG_SCH_SLDE3 0x0004C ++#define SCH_SLD_VTAG(val) (((val) & 0xFFF)<<20) ++#define SCH_SLD_MASK(val) (((val) & 0xFFF)<<8) ++#define SCH_SLD_VLD (0x1<<0) ++ ++#define REG_SCH_SCHC 0x00060 ++#define SCH_CH1_PCH(ch) (((ch) & 0x3)<<0) ++#define SCH_CH2_PCH(ch) (((ch) & 0x3)<<8) ++#define SCH_CH3_PCH(ch) (((ch) & 0x3)<<16) ++#define SCH_CH4_PCH(ch) (((ch) & 0x3)<<24) ++#define SCH_CH1_PE (0x1<<2) ++#define SCH_CH2_PE (0x1<<10) ++#define SCH_CH3_PE (0x1<<18) ++#define SCH_CH4_PE (0x1<<26) ++#define SCH_CH1_GS0 (0x0<<3) ++#define SCH_CH1_GS1 (0x1<<3) ++#define SCH_CH2_GS0 (0x0<<11) ++#define SCH_CH2_GS1 (0x1<<11) ++#define SCH_CH3_GS0 (0x0<<19) ++#define SCH_CH3_GS1 (0x1<<19) ++#define SCH_CH4_GS0 (0x0<<27) ++#define SCH_CH4_GS1 (0x1<<27) ++ ++#define REG_SCH_BND 0x00064 ++#define SCH_CH1_HID(hid) (((hid) & 0xF)<<16) ++#define SCH_CH2_HID(hid) (((hid) & 0xF)<<20) ++#define SCH_CH3_HID(hid) (((hid) & 0xF)<<24) ++#define SCH_CH4_HID(hid) (((hid) & 0xF)<<28) ++#define SCH_BND_G0F1 (0x1<<0) ++#define SCH_BND_G0F2 (0x1<<1) ++#define SCH_BND_G0F3 (0x1<<2) ++#define SCH_BND_G0F4 (0x1<<3) ++#define SCH_BND_G1F1 (0x1<<4) ++#define SCH_BND_G1F2 (0x1<<5) ++#define SCH_BND_G1F3 (0x1<<6) ++#define SCH_BND_G1F4 (0x1<<7) ++#define SCH_DEPTH(val) (((val-1) & 0xF)<<8) ++ ++#define REG_SCH_SCHG0 0x00068 ++#define REG_SCH_SCHG1 0x0006C ++#define REG_SCH_SCHE1 0x00070 ++#define REG_SCH_SCHE2 0x00074 ++#define REG_SCH_SCHE3 0x00078 ++#define REG_SCH_SCHE4 0x0007C ++ ++#define DSA_SCH_CH1 (VPU_BASE | REG_SCH_SCHE1) ++#define DSA_SCH_CH2 (VPU_BASE | REG_SCH_SCHE2) ++#define DSA_SCH_CH3 (VPU_BASE | REG_SCH_SCHE3) ++#define DSA_SCH_CH4 (VPU_BASE | REG_SCH_SCHE4) ++ ++/******************************************** ++ SW_RESET (VPU software reset) ++*********************************************/ ++#define REG_CFGC_SW_RESET 0x00004 ++#define CFGC_SW_RESET_RST (0x1<<1) ++#define CFGC_SW_RESET_RST_CLR (0x0<<1) ++#define CFGC_SW_RESET_EARB_EMPT (0x4) ++/******************************************** ++ VDMA (VPU general-purpose DMA) ++*********************************************/ ++#define REG_VDMA_LOCK 0x10000 ++#define REG_VDMA_UNLK 0x10004 ++ ++#define REG_VDMA_TASKRG 0x10008 ++#define VDMA_ACFG_RUN (0x1) ++#define VDMA_DESC_RUN (0x3) ++#define VDMA_ACFG_CLR (0x8) ++#define VDMA_ACFG_SAFE (0x4) ++#define VDMA_ACFG_DHA(a) (((unsigned int)(a)) & 0xFFFFFF80) ++#define VDMA_DESC_DHA(a) (((unsigned int)(a)) & 0xFFFF0) ++ ++#define REG_CFGC_ACM_CTRL 0x00084 ++#define REG_CFGC_ACM_STAT 0x00088 ++#define REG_CFGC_ACM_DHA 0x0008C ++ ++#define REG_VDMA_TASKST 0x1000C ++#define VDMA_ACFG_ERR (0x1<<3) ++#define VDMA_ACFG_END (0x1<<2) ++#define VDMA_DESC_END (0x1<<1) ++#define VDMA_VPU_BUSY (0x1<<0) ++ ++#define VDMA_DESC_EXTSEL (0x1<<0) ++#define VDMA_DESC_TLBSEL (0x1<<1) ++#define VDMA_DESC_LK (0x1<<31) ++ ++#define VDMA_ACFG_VLD (0x1<<31) ++#define VDMA_ACFG_TERM (0x1<<30) ++#define VDMA_ACFG_IDX(a) (((unsigned int)(a)) & 0xFFFFC) ++ ++#ifdef RW_REG_TEST ++#define GEN_VDMA_ACFG(chn, reg, term, val) write_reg(VPU_BASE+(reg), val) ++#else ++#define GEN_VDMA_ACFG(chn, reg, term, val) \ ++ ({*chn++ = val; \ ++ *chn++ = (VDMA_ACFG_VLD | (term) | VDMA_ACFG_IDX(reg)); \ ++ }) ++#endif ++ ++#define REG_EMC_FRM_SIZE 0x30000 ++#define REG_EMC_BS_ADDR 0x30004 ++#define REG_EMC_DBLK_ADDR 0x30008 ++#define REG_EMC_RECON_ADDR 0x3000c ++#define REG_EMC_MV_ADDR 0x30010 ++#define REG_EMC_SE_ADDR 0x30014 ++#define REG_EMC_QPT_ADDR 0x30018 ++#define REG_EMC_RC_RADDR 0x3001c ++#define REG_EMC_MOS_ADDR 0x30020 ++#define REG_EMC_SLV_INIT 0x30024 ++#define REG_EMC_DEBUG_INFO0 0x30028 ++#define REG_EMC_DEBUG_INFO1 0x3002c ++#define REG_EMC_CRC_INFO0 0x30030 ++#define REG_EMC_CRC_INFO1 0x30034 ++#define REG_EMC_CRC_INFO2 0x30038 ++#define REG_EMC_CRC_INFO3 0x3003c ++#define REG_EMC_BS_SIZE 0x30040 ++#define REG_EMC_BS_STAT 0x30044 ++#define REG_EMC_RC_WADDR 0x30048 ++#define REG_EMC_CPX_ADDR 0x3004c ++#define REG_EMC_MOD_ADDR 0x30050 ++#define REG_EMC_SAD_ADDR 0x30054 ++#define REG_EMC_NCU_ADDR 0x30058 ++ ++/******************************************** ++ EFE (Encoder Front End) ++*********************************************/ ++#define REG_EFE_CTRL 0x40000 ++#define EFE_TSE(en) (((en) & 0x1)<<31) ++#define EFE_FMVP(en) (((en) & 0x1)<<30) ++#define EFE_ID_X264 (0x0<<14) ++#define EFE_ID_JPEG (0x1<<14) ++#define EFE_ID_VP8 (0x2<<14) ++#define EFE_X264_QP(qp) (((qp) & 0x3F)<<8) ++#define EFE_VP8_QTB(qtb) (((qtb) & 0x7f)<<22) ++#define EFE_VP8_QIDX(qp) (((qp) & 0x3F)<<8) ++#define EFE_VP8_LF(lf) ((lf & 0x3F)<<16) ++#define EFE_HALN8_FLAG(en) (((en) & 0x1)<<7) ++#define EFE_STEP_MODE(en) (((en) & 0x1)<<6) ++#define EFE_DBLK_EN (0x1<<5) ++#define EFE_SLICE_TYPE(a) (((a) & 0x1)<<4) ++#define EFE_PLANE_TILE (0x0<<2) ++#define EFE_PLANE_420P (0x1<<2) ++#define EFE_PLANE_NV12 (0x2<<2) ++#define EFE_PLANE_NV21 (0x3<<2) ++#define EFE_EN (0x1<<1) ++#define EFE_RUN (0x1<<0) ++ ++#define REG_EFE_GEOM 0x40004 ++#define EFE_FST_MBY(mb) (((mb) & 0xFF)<<24) ++#define EFE_FST_MBX(mb) (((0/*FIXME*/) & 0xFF)<<16) ++#define EFE_LST_MBY(mb) (((mb) & 0xFF)<<8) ++#define EFE_LST_MBX(mb) (((mb) & 0xFF)<<0) ++#define EFE_JPGC_LST_MBY(mb) (((mb) & 0xFFFF)<<16) ++#define EFE_JPGC_LST_MBX(mb) ((mb) & 0xFFFF) ++ ++#define REG_EFE_COEF_BA 0x4000C ++#define REG_EFE_RAWY_SBA 0x40010 ++#define REG_EFE_RAWC_SBA 0x40014 ++#define REG_EFE_RAWU_SBA 0x40014 ++#define REG_EFE_TOPMV_BA 0x40018 ++#define REG_EFE_TOPPA_BA 0x4001C ++#define REG_EFE_MECHN_BA 0x40020 ++#define REG_EFE_MAUCHN_BA 0x40024 ++#define REG_EFE_DBLKCHN_BA 0x40028 ++#define REG_EFE_SDECHN_BA 0x4002C ++#define REG_EFE_RAW_DBA 0x40030 ++#define REG_EFE_RAWV_SBA 0x40034 ++ ++#define REG_EFE_ROI_MAX_QP 0x40040 ++#define REG_EFE_ROI_BASE_INFO0 0x40044 ++#define REG_EFE_ROI_BASE_INFO1 0x40048 ++#define REG_EFE_ROI_POS_INFO0 0x4004C ++#define REG_EFE_ROI_POS_INFO1 0x40050 ++#define REG_EFE_ROI_POS_INFO2 0x40054 ++#define REG_EFE_ROI_POS_INFO3 0x40058 ++#define REG_EFE_ROI_POS_INFO4 0x4005C ++#define REG_EFE_ROI_POS_INFO5 0x40060 ++#define REG_EFE_ROI_POS_INFO6 0x40064 ++#define REG_EFE_ROI_POS_INFO7 0x40068 ++ ++#define REG_EFE_QP_GEN_TAB 0x4006C ++ ++#define REG_EFE_QPG_CTRL 0x40074 ++#define REG_EFE_QPG_CFG0 0x40078 ++#define REG_EFE_QPG_CFG1 0x4007C ++#define REG_EFE_QPG_CFG2 0x40080 ++#define REG_EFE_QPG_CFG3 0x40084 ++#define REG_EFE_QPG_CFG4 0x40088 ++#define REG_EFE_QPG_CFG5 0x4008C ++#define REG_EFE_QPG_CFG6 0x40090 ++#define REG_EFE_QPG_RGNC_A 0x40094 ++#define REG_EFE_QPG_RGNC_B 0x40098 ++#define REG_EFE_QPG_RGNC_C 0x4009C ++#define REG_EFE_QPG_RGNC_D 0x400A0 ++#define REG_EFE_QP_SUM 0x400A4 ++ ++#define REG_EFE_EIGEN_CFG0 0x400C0 ++#define REG_EFE_EIGEN_CFG1 0x400C4 ++#define REG_EFE_EIGEN_CFG2 0x400C8 ++#define REG_EFE_EIGEN_CFG3 0x400CC ++#define REG_EFE_EIGEN_CFG4 0x400D0 ++#define REG_EFE_EIGEN_CFG5 0x400D4 ++#define REG_EFE_EIGEN_CFG6 0x400D8 ++#define REG_EFE_DIFFY_CFG 0x400DC ++#define REG_EFE_DIFFU_CFG 0x400E0 ++#define REG_EFE_DIFFV_CFG 0x400E4 ++ ++#define REG_EFE_SKIN_CTRL 0x400AC ++#define REG_EFE_SKIN_PTHD0 0x400B0 ++#define REG_EFE_SKIN_PTHD1 0x400B4 ++#define REG_EFE_SKIN_PTHD2 0x400B8 ++#define REG_EFE_SKIN_QP_OFST 0x400BC ++#define REG_EFE_SKIN_PARAM0 0x400E8 ++#define REG_EFE_SKIN_PARAM1 0x400EC ++#define REG_EFE_SKIN_PARAM2 0x400F0 ++ ++#define REG_EFE_RAW_STRD 0x40038 ++#define EFE_RAW_STRDY(y) (((y) & 0xFFFF)<<16) ++#define EFE_RAW_STRDC(c) (((c) & 0xFFFF)<<0) ++ ++#define REG_EFE_DBG_INFO 0x4003C ++#define EFE_DBG_EN (0x1<<31) ++#define EFE_DBG_BP_MBX(x) (((x) & 0xFFF)<<0) ++#define EFE_DBG_BP_MBY(y) (((y) & 0xFFF)<<16) ++ ++#define REG_EFE_MVRP 0x40100 ++#define REG_EFE_SSAD 0x40108 ++#define REG_EFE_DCS 0x4010C ++#define EFE_DCS_CLR(th) (0x1<<(th & 0xF)) ++#define EFE_DCS_EN(en) (((en) & 0x1)<<16) ++#define EFE_DCS_RT(rt) (((rt) & 0xF)<<20) ++#define EFE_DCS_OTH(oth) (((oth) & 0xF)<<24) ++#define REG_EFE_STAT 0x40110 ++#define REG_EFE_CQP_OFST 0x40120 ++ ++#define EFE_RC_QPO_CFG(c4, c3, c2, c1) \ ++( ((c4) & 0x3F)<<18 | \ ++ ((c3) & 0x3F)<<12 | \ ++ ((c2) & 0x3F)<<6 | \ ++ ((c1) & 0x3F)<<0 \ ++) ++ ++#define REG_EFE_RC_MINFO 0x40128 ++#define EFE_RC_MB_EN (0x1<<0) ++#define EFE_RC_MBGP_NUM(a) (((a) & 0x3fff)<<1) ++#define EFE_RC_MAD_CFG_RDY (0x1<<15) ++#define REG_EFE_RC_BINFO0 0x4012C ++#define EFE_RC_BU_EN (0x1<<0) ++#define EFE_RC_BU_NUM(a) (((a) & 0x7f)<<1) ++#define EFE_RC_BU_CFG(a) (((a) & 0x1)<<8) ++#define EFE_RC_SLICE_TP(a) (((a) & 0x1)<<10) ++#define REG_EFE_RC_BINFO1 0x40130 ++#define EFE_RC_BU_SIZE(a) (((a) & 0x3fff)<<0) ++#define EFE_RC_BU_LSIZE(a) (((a) & 0x3fff)<<14) ++#define REG_EFE_RC_GP0THD 0x40134 ++#define REG_EFE_RC_GP1THD 0x40138 ++#define REG_EFE_RC_GP2THD 0x4013C ++#define REG_EFE_RC_TBS 0x40140 ++#define REG_EFE_RC_BNQA0 0x40144 ++#define REG_EFE_RC_BPQA0 0x40148 ++#define REG_EFE_RC_BNQA1 0x4014C ++#define REG_EFE_RC_BPQA1 0x40150 ++#define REG_EFE_RC_MNQCS 0x40154 ++#define REG_EFE_RC_MPQCS 0x40158 ++#define REG_EFE_RC_MTBQ 0x4015C ++#define REG_EFE_RC_MRFQ 0x40160 ++#define REG_EFE_RC_MAMIN 0x40164 ++#define REG_EFE_RC_MAMAX 0x40168 ++#define REG_EFE_RC_BBS 0x4016C ++ ++/******************************************** ++ MCE (Motion Compensation/Estimation COMBO) ++*********************************************/ ++//GLB_CTRL ++#define REG_MCE_GLB_CTRL 0x50000 ++#define MCE_GLB_CTRL_FMV0(a) (((a) & 0xf)<<31) ++#define MCE_GLB_CTRL_STEP1(a) (((a) & 0xf)<<27) ++#define MCE_GLB_CTRL_STEP0(a) (((a) & 0xf)<<23) ++#define MCE_GLB_CTRL_MSTEP(a) (((a) & 0x1)<<22) ++#define MCE_GLB_CTRL_RBS(a) (((a) & 0xff)<<14) ++#define MCE_GLB_CTRL_FMS(a) (((a) & 0x7)<<11) ++#define MCE_GLB_CTRL_FRMMV(a) (((a) & 0x1)<<10) ++#define MCE_GLB_CTRL_GLBMV(a) (((a) & 0x1)<<9) ++#define MCE_GLB_CTRL_DCT8(a) (((a) & 0x1)<<8) ++#define MCE_GLB_CTRL_JRFD(a) (((a) & 0x1)<<7) ++#define MCE_GLB_CTRL_MREF(a) (((a) & 0x1)<<6) ++#define MCE_GLB_CTRL_PSKIP(a) (((a) & 0x1)<<5) ++#define MCE_GLB_CTRL_RM(a) (((a) & 0x1)<<4) ++#define MCE_GLB_CTRL_BF (0x1<<3) ++#define MCE_GLB_CTRL_CGE (0x1<<2) ++#define MCE_GLB_CTRL_WM (0x1<<1) ++#define MCE_GLB_CTRL_INIT (0x1<<0) ++ ++//COMP_CTRL ++#define REG_MCE_COMP_CTRL 0x50010 ++#define MCE_COMP_CTRL_CCE (0x1<<31) ++#define MCE_COMP_CTRL_CWT(a) (((a) & 0x3)<<26) ++#define MCE_COMP_CTRL_CRR (0x1<<25) ++#define MCE_COMP_CTRL_CIC (0x1<<24) ++#define MCE_COMP_CTRL_CAT (0x1<<23) ++#define MCE_COMP_CTRL_CTAP(a) (((a) & 0x3)<<20) ++#define MCE_COMP_CTRL_CSPT(a) (((a) & 0x3)<<18) ++#define MCE_COMP_CTRL_CSPP(a) (((a) & 0x3)<<16) ++#define MCE_COMP_CTRL_YCE (0x1<<15) ++#define MCE_COMP_CTRL_YWT(a) (((a) & 0x3)<<10) ++#define MCE_COMP_CTRL_YRR (0x1<<9) ++#define MCE_COMP_CTRL_YIC (0x1<<8) ++#define MCE_COMP_CTRL_YAT (0x1<<7) ++#define MCE_COMP_CTRL_YTAP(a) (((a) & 0x3)<<4) ++#define MCE_COMP_CTRL_YSPT(a) (((a) & 0x3)<<2) ++#define MCE_COMP_CTRL_YSPP(a) (((a) & 0x3)<<0) ++ ++#define MCE_WT_BIAVG 0 ++#define MCE_WT_UNIWT 1 ++#define MCE_WT_BIWT 2 ++#define MCE_WT_IMWT 3 ++ ++#define MCE_TAP_TAP2 0 ++#define MCE_TAP_TAP4 1 ++#define MCE_TAP_TAP6 2 ++#define MCE_TAP_TAP8 3 ++ ++#define MCE_SPT_AUTO 0 ++#define MCE_SPT_SPEC 1 ++#define MCE_SPT_BILI 2 ++#define MCE_SPT_SYMM 3 ++ ++#define MCE_SPP_HPEL 0 ++#define MCE_SPP_QPEL 1 ++#define MCE_SPP_EPEL 2 ++ ++//ESTI_CTRL ++#define REG_MCE_ESTI_CTRL 0x50040 ++#define MCE_ESTI_CTRL_LSP(a) (((a) & 0xF)<<28) ++#define MCE_ESTI_CTRL_FBG(a) (((a) & 0x1)<<27) ++#define MCE_ESTI_CTRL_CLMV (0x1<<26) ++#define MCE_ESTI_CTRL_SCL(a) (((a) & 0x3)<<24) ++#define MCE_ESTI_CTRL_MSS(a) (((a) & 0xFF)<<16) ++#define MCE_ESTI_CTRL_QRL(a) (((a) & 0x3)<<14) ++#define MCE_ESTI_CTRL_HRL(a) (((a) & 0x3)<<12) ++#define MCE_ESTI_CTRL_BDIR(a) (((a) & 0x1)<<10) ++#define MCE_ESTI_CTRL_PUE_64X64 (0x1<<9) ++#define MCE_ESTI_CTRL_PUE_32X32 (0x1<<6) ++#define MCE_ESTI_CTRL_PUE_32X16 (0x1<<5) ++#define MCE_ESTI_CTRL_PUE_16X32 (0x1<<4) ++#define MCE_ESTI_CTRL_PUE_16X16 (0x1<<3) ++#define MCE_ESTI_CTRL_PUE_16X8 (0x1<<2) ++#define MCE_ESTI_CTRL_PUE_8X16 (0x1<<1) ++#define MCE_ESTI_CTRL_PUE_8X8 (0x1<<0) ++ ++//MRGI ++#define REG_MCE_MRGI 0x50044 ++#define MCE_MRGI_MRGE_64X64 (0x1<<9) ++#define MCE_MRGI_MRGE_32X32 (0x1<<6) ++#define MCE_MRGI_MRGE_32X16 (0x1<<5) ++#define MCE_MRGI_MRGE_16X32 (0x1<<4) ++#define MCE_MRGI_MRGE_16X16 (0x1<<3) ++#define MCE_MRGI_MRGE_16X8 (0x1<<2) ++#define MCE_MRGI_MRGE_8X16 (0x1<<1) ++#define MCE_MRGI_MRGE_8X8 (0x1<<0) ++ ++//MVR ++#define REG_MCE_MVR 0x50048 ++#define MCE_MVR_MVRY(a) (((a) & 0xFFFF)<<16) ++#define MCE_MVR_MVRX(a) (((a) & 0xFFFF)<<0) ++ ++//FRM_SIZE ++#define REG_MCE_FRM_SIZE 0x50060 ++#define MCE_FRM_SIZE_FH(a) (((a) & 0xFFFF)<<16) ++#define MCE_FRM_SIZE_FW(a) (((a) & 0xFFFF)<<0) ++#define MCE_FRM_SIZE_LRE(a) (((a) & 0x1)<<14) ++#define MCE_FRM_SIZE_RRE(a) (((a) & 0x1)<<15) ++#define MCE_FRM_SIZE_TRE(a) (((a) & 0x1)<<30) ++#define MCE_FRM_SIZE_BRE(a) (((a) & 0x1)<<31) ++ ++//FSC ++#define REG_MCE_FSC 0x5004C ++#define MCE_FSC_FSE(a) (((a) & 0x1)<<31) ++#define MCE_FSC_FSMD(a) (((a) & 0x1)<<30) ++#define MCE_FSC_RECY(a) (((a) & 0x7F)<<24) ++#define MCE_FSC_RECX(a) (((a) & 0xFF)<<16) ++#define MCE_FSC_PERY(a) (((a) & 0xFF)<<8) ++#define MCE_FSC_PERX(a) (((a) & 0xFF)<<0) ++ ++//FRM_STRD ++#define REG_MCE_FRM_STRD 0x50064 ++#define MCE_FRM_STRD_STRDC(a) (((a) & 0xFFFF)<<16) ++#define MCE_FRM_STRD_STRDY(a) (((a) & 0xFFFF)<<0) ++ ++//SLC_SPOS ++#define REG_MCE_SLC_SPOS 0x50068 ++#define MCE_SLC_SPOS_CU64Y(a) (((a) & 0xFF)<<8) ++#define MCE_SLC_SPOS_CU64X(a) (((a) & 0xFF)<<0) ++ ++//REF ++#define REG_MCE_REFY0 0x5006C ++#define REG_MCE_REFC0 0x50070 ++ ++#define REG_MCE_REFY1 0x50074 ++#define REG_MCE_REFC1 0x50078 ++ ++#define REG_MCE_REFY0_1 0x50110 //!!! ++#define REG_MCE_REFC0_1 0x50114 ++ ++//GLB MV ++#define REG_MCE_GLB_MV 0x5007C ++#define MCE_GLB_MVX(a) (((a) & 0xFFF)<<0) ++#define MCE_GLB_MVY(a) (((a) & 0xFFF)<<16) ++ ++//RLUT ++#define SLUT_MCE_RLUT(l, i) (0x50800 + (i)*8 + (l)*0x80) ++ ++//ILUT ++#define SLUT_MCE_ILUT_Y 0x50900 ++#define SLUT_MCE_ILUT_C 0x50980 ++#define MCE_ILUT_INFO(fir, clip, idgl, edgl, dir, \ ++ rnd, sft, savg, srnd, sbias) \ ++( ((fir) & 0x1)<<31 | \ ++ ((clip) & 0x1)<<27 | \ ++ ((idgl) & 0x1)<<26 | \ ++ ((edgl) & 0x1)<<25 | \ ++ ((dir) & 0x1)<<24 | \ ++ ((rnd) & 0xFF)<<16 | \ ++ ((sft) & 0xF)<<8 | \ ++ ((savg) & 0x1)<<2 | \ ++ ((srnd) & 0x1)<<1 | \ ++ ((sbias) & 0x1)<<0 \ ++) ++ ++//CLUT ++#define SLUT_MCE_CLUT_Y 0x50A00 ++#define SLUT_MCE_CLUT_C 0x50B00 ++#define MCE_CLUT_INFO(c4, c3, c2, c1) \ ++( ((c4) & 0xFF)<<24 | \ ++ ((c3) & 0xFF)<<16 | \ ++ ((c2) & 0xFF)<<8 | \ ++ ((c1) & 0xFF)<<0 \ ++) ++ ++//CHAIN/TMV/SYNC ADDR ++ ++#define REG_MCE_TMV_BA 0x50104 ++#define REG_MCE_CHN_SYNC 0x50108 ++#define REG_MCE_CHN_BA 0x5010C ++ ++/******************************************** ++ VMAU (VPU Matrix Arithmetic Unit) ++*********************************************/ ++#define REG_VMAU_MCBP 0x80000 ++ ++#define REG_VMAU_QTPARA 0x80004 ++ ++#define REG_VMAU_MAIN_ADDR 0x80008 ++ ++#define REG_VMAU_NCCHN_ADDR 0x8000C ++ ++#define REG_VMAU_CHN_LEN 0x80010 ++ ++#define REG_VMAU_ACBP 0x80014 ++ ++#define REG_VMAU_CPREDM_TLV 0x80018 ++ ++#define REG_VMAU_YPREDM0 0x8001C ++ ++#define REG_VMAU_YPREDM1 0x80020 ++ ++ ++#define REG_VMAU_TOP_BASE 0x80028 ++ ++#define REG_VMAU_CTX 0x8002C ++ ++#define REG_VMAU_MD_CFG0 0x80030 ++#define VMAU_MD_SLICE_I(a) (((a) & 0x1)<<0) ++#define VMAU_MD_SLICE_P(a) (((a) & 0x1)<<1) ++#define VMAU_MD_IS_DECODE(a) (((a) & 0x1)<<4) ++#define VMAU_MD_I4_DIS(a) (((a) & 0x1)<<8) ++#define VMAU_MD_I16_DIS(a) (((a) & 0x1)<<9) ++#define VMAU_MD_PSKIP_DIS(a) (((a) & 0x1)<<10) ++#define VMAU_MD_P_L0_DIS(a) (((a) & 0x1)<<11) ++#define VMAU_MD_I8_DIS(a) (((a) & 0x1)<<12) ++#define VMAU_MD_PT8_DIS(a) (((a) & 0x1)<<13) ++#define VMAU_MD_DREF_EN(a) (((a) & 0x1)<<14) ++#define VMAU_MD_DCT8_EN(a) (((a) & 0x1)<<15) ++#define VMAU_MD_FRM_REDGE(a) (((a) & 0xFF)<<16) ++#define VMAU_MD_FRM_BEDGE(a) (((a) & 0xFF)<<24) ++ ++#define REG_VMAU_MD_CFG1 0x80034 ++#define VMAU_IPMY_BIAS_EN(a) (((a) & 0x1)<<0) ++#define VMAU_IPMC_BIAS_EN(a) (((a) & 0x1)<<1) ++#define VMAU_COST_BIAS_EN(a) (((a) & 0x1)<<2) ++#define VMAU_CSSE_BIAS_EN(a) (((a) & 0x1)<<3) ++#define VMAU_JMLAMBDA2_EN(a) (((a) & 0x1)<<4) ++#define VMAU_INTER_NEI_EN(a) (((a) & 0x1)<<5) ++#define VMAU_SKIP_BIAS_EN(a) (((a) & 0x3)<<6) ++#define VMAU_LMD_BIAS_EN(a) (((a) & 0x1)<<8) ++#define VMAU_INFO_EN(a) (((a) & 0x1)<<9) ++#define VMAU_DCM_EN(a) (((a) & 0x1)<<10) ++#define VMAU_MVDS_ALL(a) (((a) & 0x1)<<12) ++#define VMAU_MVDS_ABS(a) (((a) & 0x1)<<13) ++#define VMAU_MVS_ALL(a) (((a) & 0x1)<<14) ++#define VMAU_MVS_ABS(a) (((a) & 0x1)<<15) ++#define VMAU_P_L0_BIAS(a) (((a) & 0xF)<<16) ++#define VMAU_PSKIP_BIAS(a) (((a) & 0xF)<<20) ++#define VMAU_I4_BIAS(a) (((a) & 0xF)<<24) ++#define VMAU_I16_BIAS(a) (((a) & 0xF)<<28) ++ ++#define REG_VMAU_MD_CFG2 0x80038 ++#define VMAU_IPM_BIAS_0(a) (((a) & 0xF)<<0) ++#define VMAU_IPM_BIAS_1(a) (((a) & 0xF)<<4) ++#define VMAU_IPM_BIAS_2(a) (((a) & 0xF)<<8) ++#define VMAU_IPM_BIAS_QP0(a) (((a) & 0x3F)<<12) ++#define VMAU_IPM_BIAS_QP1(a) (((a) & 0x3F)<<18) ++#define VMAU_MD_FBC_EP(a) (((a) & 0xFF)<<24) ++ ++#define REG_VMAU_MD_CFG3 0x8003C ++#define VMAU_CSSE_BIAS_0(a) (((a) & 0xF)<<0) ++#define VMAU_CSSE_BIAS_1(a) (((a) & 0xF)<<4) ++#define VMAU_CSSE_BIAS_2(a) (((a) & 0xF)<<8) ++#define VMAU_CSSE_BIAS_QP0(a) (((a) & 0x3F)<<12) ++#define VMAU_CSSE_BIAS_QP1(a) (((a) & 0x3F)<<18) ++#define VMAU_LMD_BIAS(a) (((a) & 0xF)<<24) ++#define VMAU_PL0_FS_DIS(a) (((a) & 0x1)<<28) ++#define VMAU_PT8_FS_DIS(a) (((a) & 0x1)<<29) ++#define VMAU_PL0_COST_MAX(a) (((a) & 0x1)<<30) ++#define VMAU_PT8_COST_MAX(a) (((a) & 0x1)<<31) ++ ++#define REG_VMAU_GBL_RUN 0x80040 ++#define VMAU_RUN 0x1 ++#define VMAU_STOP 0x2 ++#define VMAU_RESET 0x4 ++ ++#define REG_VMAU_GBL_CTR 0x80044 ++#define VMAU_CTRL_FIFO_M 0x1 ++#define VMAU_CTRL_IRQ_EN 0x10 ++#define VMAU_CTRL_SLPOW 0x10000 ++#define VMAU_CTRL_TO_DBLK 0x1000000 ++#define VMAU_LAMBDA_THRETH(a) (((a) & 0x3)<<25) ++ ++#define REG_VMAU_STATUS 0x80048 ++ ++#define REG_VMAU_CCHN_ADDR 0x8004C ++ ++#define REG_VMAU_VIDEO_TYPE 0x80050 ++#define VMAU_FMT_H264 0x1 ++#define VMAU_FMT_RV9 0x2 ++#define VMAU_FMT_VC1 0x3 ++#define VMAU_FMT_MPEG2 0x4 ++#define VMAU_FMT_MPEG4 0x5 ++#define VMAU_FMT_VP8 0x6 ++#define VMAU_I4_MSK(a) (((a) & 0x1)<<3) ++#define VMAU_I16_MSK(a) (((a) & 0x1)<<4) ++#define VMAU_I8_MSK(a) (((a) & 0x1)<<5) ++#define VMAU_PT8_MSK(a) (((a) & 0x1)<<6) ++#define VMAU_MODE_DEC (0x0<<11) ++#define VMAU_MODE_ENC (0x1<<11) ++#define VMAU_IS_ISLICE(a) (((a) & 0x1)<<12) ++#define VMAU_PREDM_MSK(a) (((a) & 0x1FFFF)<<14) ++#define VMAU_TSE(en) (((en) & 0x1)<<31) ++ ++#define REG_VMAU_Y_GS 0x80054 ++#define VMAU_FRM_WID(a) (((a) & 0x3FFF)<<0) ++#define VMAU_FRM_HEI(a) (((a) & 0x3FFF)<<16) ++ ++#define REG_VMAU_DEC_DONE 0x80058 ++ ++#define REG_VMAU_ENC_DONE 0x8005C ++ ++#define REG_VMAU_POS 0x80060 ++ ++#define REG_VMAU_MCF_STA 0x80064 ++ ++#define REG_VMAU_DEC_YADDR 0x80068 ++ ++#define REG_VMAU_DEC_UADDR 0x8006C ++ ++#define REG_VMAU_DEC_VADDR 0x80070 ++ ++#define REG_VMAU_DEC_STR 0x80074 ++ ++#define REG_VMAU_DEADZONE 0x80078 ++#define VMAU_DEADZONE0_IY(a) (((a) & 0xFF)<<0) ++#define VMAU_DEADZONE1_PY(a) (((a) & 0xFF)<<8) ++#define VMAU_DEADZONE2_IC(a) (((a) & 0xFF)<<16) ++#define VMAU_DEADZONE3_PC(a) (((a) & 0xFF)<<24) ++ ++#define REG_VMAU_ACMASK 0x8007C ++ ++#define REG_VMAU_MD_CFG4 0x800D8 ++#define VMAU_YSSE_THR(a) (((a) & 0xFFFFFF)<<0) ++#define VMAU_I8_BIAS(a) (((a) & 0xF)<<24) ++#define VMAU_PT8_BIAS(a) (((a) & 0xF)<<28) ++ ++#define REG_VMAU_MD_CFG5 0x800DC ++#define VMAU_CSSE_THR(a) (((a) & 0xFFFFFF)<<0) ++#define VMAU_CQP_OFFSET(a) (((a) & 0x1F)<<24) ++#define VMAU_I4_COST_MAX(a) (((a) & 0x1)<<29) ++#define VMAU_I8_COST_MAX(a) (((a) & 0x1)<<30) ++#define VMAU_I16_COST_MAX(a) (((a) & 0x1)<<31) ++ ++#define REG_VMAU_MD_CFG6 0x800FC ++#define VMAU_DCM_PARAM(a) (((a) & 0xFFFFFF)<<0) ++#define VMAU_SDE_PRIOR(a) (((a) & 0xF)<<24) ++#define VMAU_DB_PRIOR(a) (((a) & 0xF)<<28) ++ ++#define REG_VMAU_MD_CFG7 0x80114 ++#define VMAU_CFG_SIZE_X(a) (((a) & 0xF)<<0) ++#define VMAU_CFG_SIZE_Y(a) (((a) & 0xF)<<4) ++#define VMAU_CFG_IW_THR(a) (((a) & 0x1FF)<<8) ++#define VMAU_CFG_BASEQP(a) (((a) & 0x3F)<<17) ++#define VMAU_CFG_ALPHA(a) (((a) & 0xFF)<<23) ++#define VMAU_PS_COST_MAX(a) (((a) & 0x1)<<31) ++ ++#define REG_VMAU_MD_CFG8 0x80118 ++#define VMAU_CFG_MVR_THR1(a) (((a) & 0x7FFF)<<0) ++#define VMAU_CFG_MVR_THR2(a) (((a) & 0x1FFFF)<<15) ++ ++#define REG_VMAU_MD_CFG9 0x8011C ++#define VMAU_CFG_MVR_THR3(a) (((a) & 0xFFFFF)<<0) ++#define VMAU_CFG_BETA(a) (((a) & 0xFF)<<20) ++ ++#define REG_VMAU_MD_CFG10 0x80190 ++ ++#define REG_VMAU_MD_CFG11 0x80194 ++#define VMAU_CFG_MD_RBIAS(a) (((a) & 0xf) << 21) ++#define VMAU_CFG_MD_RBIAS_EN(a) (((a) & 1) << 25) ++#define VMAU_CFG_MD_PCDC_N0(a) (((a) & 7) << 26) ++#define VMAU_CFG_MD_IFA_VLD(a) (((a) & 1) << 29) ++#define VMAU_CFG_MD_SLV_VLD(a) (((a) & 1) << 30) ++#define VMAU_CFG_MD_SET_VLD(a) (((a) & 1) << 31) ++ ++#define REG_VMAU_MD_MODE 0x80198 ++ ++#define REG_VMAU_DEADZONE1 0x8019C ++ ++#define REG_VMAU_IPRED_CFG0 0x801C0 ++#define VMAU_IP_MD_VAL(a) (((a) & 0x1)<<30) ++#define VMAU_IP_REF_NEB_4(a) (((a) & 0x1)<<29) ++#define VMAU_IP_REF_NEB_8(a) (((a) & 0x1)<<28) ++#define VMAU_IP_REF_PRD_C(a) (((a) & 0xF)<<24) ++#define VMAU_IP_REF_PRD_4(a) (((a) & 0xF)<<20) ++#define VMAU_IP_REF_PRD_8(a) (((a) & 0xF)<<16) ++#define VMAU_IP_REF_PRD_16(a) (((a) & 0xF)<<12) ++#define VMAU_IP_REF_CUV_EN(a) (((a) & 0x1)<<11) ++#define VMAU_IP_REF_C4_EN(a) (((a) & 0x1)<<10) ++#define VMAU_IP_REF_C8_EN(a) (((a) & 0x1)<<9) ++#define VMAU_IP_REF_C16_EN(a) (((a) & 0x1)<<8) ++#define VMAU_IP_REF_LMDUV_EN(a) (((a) & 0x1)<<7) ++#define VMAU_IP_REF_LMD4_EN(a) (((a) & 0x1)<<6) ++#define VMAU_IP_REF_LMD8_EN(a) (((a) & 0x1)<<5) ++#define VMAU_IP_REF_LMD16_EN(a) (((a) & 0x1)<<4) ++#define VMAU_IP_REF_BITUV_EN(a) (((a) & 0x1)<<3) ++#define VMAU_IP_REF_BIT4_EN(a) (((a) & 0x1)<<2) ++#define VMAU_IP_REF_BIT8_EN(a) (((a) & 0x1)<<1) ++#define VMAU_IP_REF_BIT16_EN(a) (((a) & 0x1)<<0) ++ ++#define REG_VMAU_IPRED_CFG1 0x801C4 ++#define VMAU_IP_REF_4_BIT0(a) (((a) & 0xF)<<0) ++#define VMAU_IP_REF_4_BIT1(a) (((a) & 0xF)<<4) ++#define VMAU_IP_REF_4_BIT2(a) (((a) & 0xF)<<8) ++#define VMAU_IP_REF_4_BIT3(a) (((a) & 0xF)<<12) ++#define VMAU_IP_REF_8_BIT0(a) (((a) & 0xF)<<16) ++#define VMAU_IP_REF_8_BIT1(a) (((a) & 0xF)<<20) ++#define VMAU_IP_REF_8_BIT2(a) (((a) & 0xF)<<24) ++#define VMAU_IP_REF_8_BIT3(a) (((a) & 0xF)<<28) ++ ++#define REG_VMAU_IPRED_CFG2 0x801C8 ++#define VMAU_IP_REF_16_BIT0(a) (((a) & 0xF)<<0) ++#define VMAU_IP_REF_16_BIT1(a) (((a) & 0xF)<<4) ++#define VMAU_IP_REF_16_BIT2(a) (((a) & 0xF)<<8) ++#define VMAU_IP_REF_16_BIT3(a) (((a) & 0xF)<<12) ++#define VMAU_IP_REF_C_BIT0(a) (((a) & 0xF)<<16) ++#define VMAU_IP_REF_C_BIT1(a) (((a) & 0xF)<<20) ++#define VMAU_IP_REF_C_BIT2(a) (((a) & 0xF)<<24) ++#define VMAU_IP_REF_C_BIT3(a) (((a) & 0xF)<<28) ++ ++#define REG_VMAU_IPRED_CFG3 0x801CC ++#define VMAU_IP_REF_LMD16_IFO(a) (((a) & 0xF)<<0) ++#define VMAU_IP_REF_LMD8_IFO(a) (((a) & 0xF)<<4) ++#define VMAU_IP_REF_LMD4_IFO(a) (((a) & 0xF)<<8) ++#define VMAU_IP_REF_LMDUV_IFO(a) (((a) & 0xF)<<12) ++#define VMAU_IP_REF_NEB_8REF(a) (((a) & 0xF)<<16) ++#define VMAU_IP_REF_NEB_4REF(a) (((a) & 0xF)<<20) ++ ++#define REG_VMAU_IPRED_CFG4 0x801D0 ++#define VMAU_IP_REF_C4_IFO(a) (((a) & 0xFFFF)<<0) ++#define VMAU_IP_REF_C8_IFO(a) (((a) & 0xFFFF)<<16) ++ ++#define REG_VMAU_IPRED_CFG5 0x801D4 ++#define VMAU_IP_REF_C16_IFO(a) (((a) & 0xFFFF)<<0) ++#define VMAU_IP_REF_CUV_IFO(a) (((a) & 0xFFFF)<<16) ++ ++#define REG_VMAU_MEML 0x84000 ++ ++#define REG_VMAU_QT 0x88000 ++ ++#define REG_VMAU_CTX_CFBC 0x80174 ++ ++/******************************************** ++ DBLK (deblock) ++*********************************************/ ++#define REG_DBLK_DHA 0x70000 ++ ++#define REG_DBLK_CFG 0x7005C ++#define DBLK_CFG_ALPHA(a) (((a) & 0x1F)<<0) ++#define DBLK_CFG_BETA(a) (((a) & 0x1F)<<8) ++#define DBLK_CFG_NO_LFT(a) (((a) & 0x1)<<17) ++ ++#define REG_DBLK_TRIG 0x70060 ++#define DBLK_RUN 0x1 ++#define DBLK_STOP 0x2 ++#define DBLK_RESET 0x4 ++#define DBLK_SLICE_RUN 0x8 ++ ++#define REG_DBLK_CTRL 0x70064 ++#define DBLK_CTRL(expand, rotate, loop_filter) \ ++( ((expand) & 0x1)<<4 | \ ++ ((rotate) & 0x3)<<1 | \ ++ ((loop_filter) & 0x1)<<0 \ ++) ++ ++#define REG_DBLK_VTR 0x70068 ++#define DBLK_FMT_H264 0x1 ++#define DBLK_FMT_RV9 0x2 ++#define DBLK_FMT_VC1 0x3 ++#define DBLK_FMT_MPEG2 0x4 ++#define DBLK_FMT_MPEG4 0x5 ++#define DBLK_FMT_VP8 0x6 ++#define DBLK_FRM_I 0x0 ++#define DBLK_FRM_P 0x1 ++#define DBLK_FRM_B 0x2 ++#define DBLK_VTR(beta, alpha, vp8_spl, vp8_kf, \ ++ frm_typ, video_fmt) \ ++( ((beta) & 0xFF)<<24 | \ ++ ((alpha) & 0xFF)<<16 | \ ++ ((vp8_spl) & 0x1)<<9 | \ ++ ((vp8_kf) & 0x1)<<5 | \ ++ ((frm_typ) & 0x3)<<3 | \ ++ ((video_fmt) & 0x7)<<0 \ ++) ++ ++#define REG_DBLK_FSTA 0x7006C ++ ++#define REG_DBLK_GSTA 0x70070 ++#define DBLK_STAT_DOEND (0x1<<0) ++ ++#define REG_DBLK_GSIZE 0x70074 ++#define DBLK_GSIZE(mb_height, mb_width) \ ++( ((mb_height) & 0xFFFF)<<16 | \ ++ ((mb_width) & 0xFFFF)<<0 \ ++) ++ ++#define REG_DBLK_GENDA 0x70078 ++ ++#define REG_DBLK_GPOS 0x7007C ++#define DBLK_GPOS(first_mby, first_mbx) \ ++( ((first_mby) & 0xFFFF)<<16 | \ ++ ((first_mbx) & 0xFFFF)<<0 \ ++) ++ ++#define REG_DBLK_GPIC_STR 0x70080 ++#define DBLK_GPIC_STR(dst_strd_c, dst_strd_y) \ ++( ((dst_strd_c) & 0xFFFF)<<16 | \ ++ ((dst_strd_y) & 0xFFFF)<<0 \ ++) ++ ++#define REG_DBLK_GPIC_YA 0x70084 ++ ++#define REG_DBLK_GPIC_CA 0x70088 ++ ++#define REG_DBLK_GP_ENDA 0x7008C ++ ++#define REG_DBLK_SLICE_ENDA 0x70090 ++ ++#define REG_DBLK_BLK_CTRL 0x70094 ++ ++#define REG_DBLK_BLK_FIFO 0x70098 ++ ++#define REG_DBLK_MOS_CFG 0x70240 ++#define REG_DBLK_MOS_ADDR 0x70244 ++#define DBLK_MOS_BASE_ADDR VPU_BASE + 0xC7000 ++#define REG_DBLK_MOS_CRC 0x70248 ++/******************************************** ++ SDE (stream parser/encoding) ++*********************************************/ ++#define REG_SDE_STAT 0x90000 ++#define SDE_STAT_BSEND (0x1<<1) ++ ++#define REG_SDE_SL_CTRL 0x90004 ++#define SDE_SLICE_INIT (0x1<<1) ++#define SDE_MB_RUN (0x1<<0) ++ ++#define REG_SDE_SL_GEOM 0x90008 ++#define SDE_SL_GEOM(mb_height, mb_width, \ ++ first_mby, first_mbx) \ ++( ((mb_height) & 0xFF)<<24 | \ ++ ((mb_width) & 0xFF)<<16 | \ ++ ((first_mby) & 0xFF)<<8 | \ ++ ((first_mbx) & 0xFF)<<0 \ ++) ++ ++#define REG_SDE_GL_CTRL 0x9000C ++#define SDE_BP(mby, mbx) \ ++( ((mby) & 0xFF)<<24 | \ ++ ((mbx) & 0xFF)<<16 \ ++) ++#define SDE_MODE_AUTO (0x0<<4) ++#define SDE_MODE_STEP (0x1<<4) ++#define SDE_MODE_DEBUG (0x2<<4) ++#define SDE_EN (0x1<<0) ++ ++#define REG_SDE_CODEC_ID 0x90010 ++#define SDE_FMT_H264_DEC (0x1<<0) ++#define SDE_FMT_H264_ENC (0x1<<1) ++#define SDE_FMT_VP8_DEC (0x1<<2) ++#define SDE_FMT_VC1_DEC (0x1<<3) ++#define SDE_FMT_MPEG2_DEC (0x1<<4) ++#define SDE_FMT_VP8_ENC (0x1<<5) ++ ++#define REG_SDE_CFG0 0x90014 ++#define REG_SDE_CFG1 0x90018 ++#define REG_SDE_CFG2 0x9001C ++#define REG_SDE_CFG3 0x90020 ++#define REG_SDE_CFG4 0x90024 ++#define REG_SDE_CFG5 0x90028 ++#define REG_SDE_CFG6 0x9002C ++#define REG_SDE_CFG7 0x90030 ++#define REG_SDE_CFG8 0x90034 ++#define REG_SDE_CFG9 0x90038 ++#define REG_SDE_CFG10 0x9003C ++#define REG_SDE_CFG11 0x90040 ++#define REG_SDE_CFG12 0x90044 ++#define REG_SDE_CFG13 0x90048 ++#define REG_SDE_CFG14 0x9004C ++#define REG_SDE_CFG15 0x90050 ++ ++#define REG_SDE_CTX_TBL 0x92000 ++#define REG_SDE_CQP_TBL 0x93800 ++ ++/**************************************************************** ++ JPGC (jpeg codec) ++*****************************************************************/ ++#define REG_JPGC_TRIG 0xE0000 ++#define REG_JPGC_GLBI 0xE0004 ++#define REG_JPGC_STAT 0xE0008 ++#define JPGC_STAT_ENDF (0x1<<31) ++#define REG_JPGC_BSA 0xE000C ++#define REG_JPGC_P0A 0xE0010 ++#define REG_JPGC_P1A 0xE0014 ++#define REG_JPGC_P2A 0xE0018 ++#define REG_JPGC_P3A 0xE001C ++#define REG_JPGC_NMCU 0xE0028 ++#define REG_JPGC_NRSM 0xE002C ++#define REG_JPGC_P0C 0xE0030 ++#define REG_JPGC_P1C 0xE0034 ++#define REG_JPGC_P2C 0xE0038 ++#define REG_JPGC_P3C 0xE003C ++#define REG_JPGC_WIDTH 0xE0040 ++#define REG_JPGC_MCUS 0xE0064 ++#define REG_JPGC_ZIGM0 0xE1000 ++#define REG_JPGC_ZIGM1 0xE1100 ++#define REG_JPGC_HUFB 0xE1200 ++#define REG_JPGC_HUFM 0xE1300 ++#define REG_JPGC_QMEM 0xE1400 ++#define REG_JPGC_HUFE 0xE1800 ++#define REG_JPGC_HUFS 0xE1800 ++ ++#define JPGC_CORE_OPEN (0x1<<0) ++#define JPGC_BS_TRIG (0x1<<1) ++#define JPGC_PP_TRIG (0x1<<2) ++#define JPGC_TERM (0x1<<3) ++#define JPGC_RSTER_MD (0x1<<8) ++ ++/**************************************************************** ++ ODMA ++*****************************************************************/ ++ ++#define REG_ODMA_TRIG 0x60000 ++#define REG_ODMA_CTRL 0x60004 ++#define REG_ODMA_BDYA 0x60008 ++#define REG_ODMA_BDCA 0x6000C ++#define REG_ODMA_BSTR 0x60010 ++#define REG_ODMA_HDYA 0x60014 ++#define REG_ODMA_HDCA 0x60018 ++#define REG_ODMA_SPYA 0x6001C ++#define REG_ODMA_SPCA 0x60020 ++ ++#define ODMA_REC_STRDY(y) (((y) & 0xFFFF)<<16) ++#define ODMA_REC_STRDC(c) (((c) & 0xFFFF)<<0) ++ ++/**************************************************************** ++ JRFD ++*****************************************************************/ ++ ++#define REG_JRFD_TRIG 0x10000 ++#define REG_JRFD_CTRL 0x10004 ++#define REG_JRFD_HDYA 0x10008 ++#define REG_JRFD_HDCA 0x1000C ++#define REG_JRFD_HSTR 0x10010 ++#define REG_JRFD_BDYA 0x10014 ++#define REG_JRFD_BDCA 0x10018 ++#define REG_JRFD_BSTR 0x1001C ++#define REG_JRFD_MHDY 0x10020 ++#define REG_JRFD_MHDC 0x10024 ++#define REG_JRFD_MBDY 0x10028 ++#define REG_JRFD_MBDC 0x1002C ++ ++#define JRFD_BODY_STRDY(y) (((y) & 0xFFFF)<<16) ++#define JRFD_BODY_STRDC(c) (((c) & 0xFFFF)<<0) ++ ++/**************************************************************** ++ IFA ++*****************************************************************/ ++#define REG_IFA_CTRL 0xB0000 ++#define REG_IFA_FRM_SIZE 0xB0004 ++#define REG_IFA_RAWY_BA 0xB0008 ++#define REG_IFA_RAWC_BA 0xB000C ++#define REG_IFA_RAW_STR 0xB0010 ++#define REG_IFA_REFY_BA0 0xB0014 ++#define REG_IFA_REFC_BA0 0xB0018 ++#define REG_IFA_THRD_Y 0xB001C ++#define REG_IFA_THRD_C 0xB0020 ++#define REG_IFA_REFY_BA1 0xB0030 ++#define REG_IFA_REFC_BA1 0xB0034 ++ ++#define IFA_CTRL_INIT ( 0x1 << 0 ) ++#define IFA_CTRL_UV_EN(a) ( (a&0x1) << 1 ) ++#define IFA_CTRL_RRS_SY(a) ( (a&0x3) << 2 ) ++#define IFA_CTRL_RRS_SC(a) ( (a&0x1) << 4 ) ++#define IFA_CTRL_DDR_DW(a) ( (a&0x1) << 5 ) ++#define IFA_CTRL_RRS_EN(a) ( (a&0x1) << 6 ) ++#define IFA_CTRL_DUMP_EN(a) ( (a&0x1) << 7 ) ++#define IFA_CTRL_REF_BIDX(a) ( (a&0xff) << 8 ) ++#define IFA_CTRL_CGE (0x1<<16) //1 mean close clk-gate, 0 default open ++#define IFA_CTRL_RAW_TYPE(a) ( (a&0x1) << 17 ) ++ ++#define IFA_FRM_W(a) ( (a&0xFFF) << 0 ) ++#define IFA_FRM_H(a) ( (a&0xFFF) << 16 ) ++ ++#define IFA_STR_Y(a) ( (a&0xFFFF) << 0 ) ++#define IFA_STR_C(a) ( (a&0xFFFF) << 16 ) ++ ++#define IFA_THRD_U(a) ( (a&0x3FFF) << 0 ) ++#define IFA_THRD_V(a) ( (a&0x3FFF) << 16 ) ++ ++ ++/**************************************************************** ++ VPU tables ++*****************************************************************/ ++ ++/******************************************** ++ Motion interpolation programable table ++*********************************************/ ++#define IS_SKIRT 0 ++#define IS_MIRROR 1 ++ ++#define IS_BIAVG 0 ++#define IS_WT1 1 ++#define IS_WT2 2 ++#define IS_FIXWT 3 ++ ++#define IS_ILUT0 0 ++#define IS_ILUT1 2 ++#define IS_EC 1 ++ ++#define IS_TCS 1 ++#define NOT_TCS 0 ++#define IS_SCS 1 ++#define NOT_SCS 0 ++#define IS_HLDGL 1 ++#define NOT_HLDGL 0 ++#define IS_AVSDGL 1 ++#define NOT_AVSDGL 0 ++ ++#define INTP_HDIR 0 ++#define INTP_VDIR 1 ++ ++enum IntpID { ++ MPEG_HPEL = 0, ++ MPEG_QPEL, ++ H264_QPEL, ++ H264_EPEL, ++ RV8_TPEL, ++ RV9_QPEL, ++ RV9_CPEL, ++ WMV2_QPEL, ++ VC1_QPEL, ++ AVS_QPEL, ++ VP6_QPEL, ++ VP8_QPEL, ++ VP8_EPEL, ++ VP8_BIL, ++ VP8_FPEL, /*full-pixel for chroma*/ ++ HEVC_QPEL, ++ HEVC_EPEL, ++}; ++ ++enum PosID { ++ H0V0 = 0, ++ H1V0, ++ H2V0, ++ H3V0, ++ H0V1, ++ H1V1, ++ H2V1, ++ H3V1, ++ H0V2, ++ H1V2, ++ H2V2, ++ H3V2, ++ H0V3, ++ H1V3, ++ H2V3, ++ H3V3, ++}; ++ ++enum TapTYP { ++ TAP2 = 0, ++ TAP4, ++ TAP6, ++ TAP8, ++}; ++ ++enum SPelSFT { ++ HPEL = 0, ++ QPEL, ++ EPEL, ++}; ++ ++typedef struct IntpFMT_t{ ++ char tap; ++ char intp_pkg[2]; ++ char hldgl; ++ char avsdgl; ++ char intp[2]; ++ char intp_dir[2]; ++ char intp_coef[2][8]; ++ char intp_rnd[2]; ++ char intp_sft[2]; ++ char intp_sintp[2]; ++ char intp_srnd[2]; ++ char intp_sbias[2]; ++}IntpFMT_t; ++ ++//__place_k0_data__ ++//static char AryFMT[] = { ++// IS_SKIRT, IS_MIRROR, IS_SKIRT, IS_SKIRT, ++// IS_SKIRT, IS_SKIRT, IS_SKIRT, IS_SKIRT, ++// IS_SKIRT, IS_SKIRT, IS_SKIRT, IS_SKIRT, ++// IS_SKIRT, IS_SKIRT, IS_SKIRT, IS_SKIRT, IS_SKIRT, ++//}; ++// ++//__place_k0_data__ ++//static char SubPel[] = { ++// HPEL, QPEL, QPEL, EPEL, ++// QPEL, QPEL, QPEL, QPEL, ++// QPEL, QPEL, QPEL, QPEL, ++// EPEL, HPEL, QPEL, QPEL, EPEL ++//}; ++ ++__place_k0_data__ ++static IntpFMT_t IntpFMT[][16] = { ++ { ++ /************* MPEG_HPEL ***************/ ++ {/*H0V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/1, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H2V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/1, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/1, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H0V1*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/1, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V1*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0} }, ++ {/*intp_rnd*/0, 2}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H2V1*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0} }, ++ {/*intp_rnd*/0, 2}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V1*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0} }, ++ {/*intp_rnd*/0, 2}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H0V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/1, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0} }, ++ {/*intp_rnd*/0, 2}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H2V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0} }, ++ {/*intp_rnd*/0, 2}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0} }, ++ {/*intp_rnd*/0, 2}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H0V3*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/1, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V3*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0} }, ++ {/*intp_rnd*/0, 2}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H2V3*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0} }, ++ {/*intp_rnd*/0, 2}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V3*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0} }, ++ {/*intp_rnd*/0, 2}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ }, ++ ++ { ++ /************* MPEG_QPEL ***************/ ++ {/*H0V0*/ ++ TAP8, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1},{0},}, ++ {/*intp_rnd*/15, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1},{0},}, ++ {/*intp_rnd*/15, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1},{0},}, ++ {/*intp_rnd*/15, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/1, 0}, ++ }, ++ {/*H0V1*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1},{0},}, ++ {/*intp_rnd*/15, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V1*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1}, {-1, 3, -6, 20, 20, -6, 3, -1},}, ++ {/*intp_rnd*/15, 15}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/1, 1}, ++ {/*intp_srnd*/1, 1}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V1*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1}, {-1, 3, -6, 20, 20, -6, 3, -1},}, ++ {/*intp_rnd*/15, 15}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V1*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1}, {-1, 3, -6, 20, 20, -6, 3, -1},}, ++ {/*intp_rnd*/15, 15}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/1, 1}, ++ {/*intp_srnd*/1, 1}, ++ {/*intp_sbias*/1, 0}, ++ }, ++ {/*H0V2*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1},{0},}, ++ {/*intp_rnd*/15, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1}, {-1, 3, -6, 20, 20, -6, 3, -1},}, ++ {/*intp_rnd*/15, 15}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1}, {-1, 3, -6, 20, 20, -6, 3, -1},}, ++ {/*intp_rnd*/15, 15}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1}, {-1, 3, -6, 20, 20, -6, 3, -1},}, ++ {/*intp_rnd*/15, 15}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/1, 0}, ++ }, ++ {/*H0V3*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1},{0},}, ++ {/*intp_rnd*/15, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/1, 0}, ++ }, ++ {/*H1V3*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1}, {-1, 3, -6, 20, 20, -6, 3, -1},}, ++ {/*intp_rnd*/15, 15}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/1, 1}, ++ {/*intp_srnd*/1, 1}, ++ {/*intp_sbias*/0, 1}, ++ }, ++ {/*H2V3*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1}, {-1, 3, -6, 20, 20, -6, 3, -1},}, ++ {/*intp_rnd*/15, 15}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 1}, ++ }, ++ {/*H3V3*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1}, {-1, 3, -6, 20, 20, -6, 3, -1},}, ++ {/*intp_rnd*/15, 15}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/1, 1}, ++ {/*intp_srnd*/1, 1}, ++ {/*intp_sbias*/1, 1}, ++ }, ++ }, ++ ++ { ++ /************* H264_QPEL ***************/ ++ {/*H0V0*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/1, 0}, ++ }, ++ {/*H0V1*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V1*/ ++ TAP6, {IS_TCS, IS_SCS}, IS_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 16}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V1*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 10}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V1*/ ++ TAP6, {IS_TCS, IS_SCS}, IS_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 16}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/1, 0}, ++ }, ++ {/*H0V2*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 10}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 10}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 10}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 1}, ++ }, ++ {/*H0V3*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/1, 0}, ++ }, ++ {/*H1V3*/ ++ TAP6, {IS_TCS, IS_SCS}, IS_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 16}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 1}, ++ }, ++ {/*H2V3*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 10}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 1}, ++ }, ++ {/*H3V3*/ ++ TAP6, {IS_TCS, IS_SCS}, IS_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 16}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/1, 1}, ++ }, ++ }, ++ ++ { ++ /************* H264_EPEL ***************/ ++ {/*H0V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/0}, ++ {/*H2V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{0},{0},}, ++ {/*intp_rnd*/4, 0}, ++ {/*intp_sft*/3, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V0*/0}, ++ {/*H0V1*/0}, ++ {/*H1V1*/0}, ++ {/*H2V1*/0}, ++ {/*H3V1*/0}, ++ {/*H0V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{0},{0},}, ++ {/*intp_rnd*/4, 0}, ++ {/*intp_sft*/3, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V2*/0}, ++ {/*H2V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{0},{0},}, ++ {/*intp_rnd*/0, 32}, ++ {/*intp_sft*/0, 6}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V2*/0}, ++ {/*H0V3*/0}, ++ {/*H1V3*/0}, ++ {/*H2V3*/0}, ++ {/*H3V3*/0}, ++ }, ++ ++ { ++ /************* RV8_TPEL ***************/ ++ {/*H0V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 12, 6, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/8, 0}, ++ {/*intp_sft*/4, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 6, 12, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/8, 0}, ++ {/*intp_sft*/4, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/0}, ++ {/*H0V1*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, 12, 6, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/8, 0}, ++ {/*intp_sft*/4, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V1*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 12, 6, -1, 0, 0, 0, 0}, {-1, 12, 6, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/8, 0}, //{0,128} ++ {/*intp_sft*/0, 8}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V1*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 6, 12, -1, 0, 0, 0, 0}, {-1, 12, 6, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/8, 0}, //{0,128} ++ {/*intp_sft*/0, 8}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V1*/0}, ++ {/*H0V2*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, 6, 12, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/8, 0}, ++ {/*intp_sft*/4, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 12, 6, -1, 0, 0, 0, 0}, {-1, 6, 12, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/8, 0}, //{0,128} ++ {/*intp_sft*/0, 8}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 6, 12, -1, 0, 0, 0, 0}, {-1, 6, 12, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/8, 0}, //{0,128} ++ {/*intp_sft*/0, 8}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/0}, ++ {/*H0V3*/0}, ++ {/*H1V3*/0}, ++ {/*H2V3*/0}, ++ {/*H3V3*/0}, ++ }, ++ ++ { ++ /************* RV9_QPEL ***************/ ++ {/*H0V0*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, -5, 52, 20, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, -5, 20, 52, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V1*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, -5, 52, 20, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V1*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 52, 20, -5, 1, 0, 0}, {1, -5, 52, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/32, 32}, ++ {/*intp_sft*/6, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V1*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 52, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 32}, ++ {/*intp_sft*/5, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V1*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 52, -5, 1, 0, 0}, {1, -5, 52, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/32, 32}, ++ {/*intp_sft*/6, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V2*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 52, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/32, 16}, ++ {/*intp_sft*/6, 5}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 16}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 52, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/32, 16}, ++ {/*intp_sft*/6, 5}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V3*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, -5, 20, 52, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V3*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 52, 20, -5, 1, 0, 0}, {1, -5, 20, 52, -5, 1, 0, 0},}, ++ {/*intp_rnd*/32, 32}, ++ {/*intp_sft*/6, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V3*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 52, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 32}, ++ {/*intp_sft*/5, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V3*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 2}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ }, ++ ++ { ++ /************* RV9_CPEL ***************/ ++ {/*H0V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{3, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/2, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/1, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, 3, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/2, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V1*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{3, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/2, 0}, ++ {/*intp_sft*/2, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V1*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{3, 1, 0, 0, 0, 0, 0, 0}, {3, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 7}, ++ {/*intp_sft*/0, 4}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V1*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {3, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 4}, ++ {/*intp_sft*/0, 3}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V1*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 3, 0, 0, 0, 0, 0, 0}, {3, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 7}, ++ {/*intp_sft*/0, 4}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/1, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{3, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 4}, ++ {/*intp_sft*/0, 3}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 1}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 3, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 4}, ++ {/*intp_sft*/0, 3}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V3*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, 3, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/2, 0}, ++ {/*intp_sft*/2, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V3*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{3, 1, 0, 0, 0, 0, 0, 0}, {1, 3, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 7}, ++ {/*intp_sft*/0, 4}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V3*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 3, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 4}, ++ {/*intp_sft*/0, 3}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V3*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 1}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ }, ++ ++ { ++ /************* WMV2_QPEL ***************/ ++ {/*H0V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/8, 0}, ++ {/*intp_sft*/4, 0}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/8, 0}, ++ {/*intp_sft*/4, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/8, 0}, ++ {/*intp_sft*/4, 0}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/1, 0}, ++ }, ++ {/*H0V1*/0}, ++ {/*H1V1*/0}, ++ {/*H2V1*/0}, ++ {/*H3V1*/0}, ++ {/*H0V2*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/8, 0}, ++ {/*intp_sft*/4, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0}, {-1, 9, 9, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/8, 8}, ++ {/*intp_sft*/4, 4}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0}, {-1, 9, 9, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/8, 8}, ++ {/*intp_sft*/4, 4}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0}, {-1, 9, 9, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/8, 8}, ++ {/*intp_sft*/4, 4}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 1}, ++ }, ++ {/*H0V3*/0}, ++ {/*H1V3*/0}, ++ {/*H2V3*/0}, ++ {/*H3V3*/0}, ++ }, ++ ++ { ++ /************* VC1_QPEL ***************/ ++ {/*H0V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-4, 53, 18, -3, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/8, 0}, ++ {/*intp_sft*/4, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-3, 18, 53, -4, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V1*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-4, 53, 18, -3, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/31, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V1*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-4, 53, 18, -3, 0, 0, 0, 0}, {-4, 53, 18, -3, 0, 0, 0, 0},}, ++ {/*intp_rnd*/31, 32}, ++ {/*intp_sft*/6, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V1*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-4, 53, 18, -3, 0, 0, 0, 0}, {-1, 9, 9, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/31, 8}, ++ {/*intp_sft*/6, 4}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V1*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-4, 53, 18, -3, 0, 0, 0, 0}, {-3, 18, 53, -4, 0, 0, 0, 0},}, ++ {/*intp_rnd*/31, 32}, ++ {/*intp_sft*/6, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V2*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/7, 0}, ++ {/*intp_sft*/4, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0}, {-4, 53, 18, -3, 0, 0, 0, 0},}, ++ {/*intp_rnd*/7, 32}, ++ {/*intp_sft*/4, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0}, {-1, 9, 9, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/7, 8}, ++ {/*intp_sft*/4, 4}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0}, {-3, 18, 53, -4, 0, 0, 0, 0},}, ++ {/*intp_rnd*/7, 32}, ++ {/*intp_sft*/4, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V3*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-3, 18, 53, -4, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/31, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V3*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-3, 18, 53, -4, 0, 0, 0, 0}, {-4, 53, 18, -3, 0, 0, 0, 0},}, ++ {/*intp_rnd*/31, 32}, ++ {/*intp_sft*/6, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V3*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-3, 18, 53, -4, 0, 0, 0, 0}, {-1, 9, 9, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/31, 8}, ++ {/*intp_sft*/6, 4}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V3*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-3, 18, 53, -4, 0, 0, 0, 0}, {-3, 18, 53, -4, 0, 0, 0, 0},}, ++ {/*intp_rnd*/31, 32}, ++ {/*intp_sft*/6, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ }, ++ ++ { ++ /************* AVS_QPEL ***************/ ++ {/*H0V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, -2, 96, 42, -7, 0, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 5, 5, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/4, 0}, ++ {/*intp_sft*/3, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{0, -7, 42, 96, -2, -1, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V1*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, -2, 96, 42, -7, 0, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V1*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, IS_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 5, 5, -1, 0, 0, 0, 0}, {-1, 5, -5, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 32}, ++ {/*intp_sft*/0, 6}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V1*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{0, -1, 5, 5, -1, 0, 0, 0}, {-1, -2, 96, 42, -7, 0, 0, 0},}, ++ {/*intp_rnd*/64, 0}, //{0,512} ++ {/*intp_sft*/0, 10}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V1*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, IS_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 5, 5, -1, 0, 0, 0, 0}, {-1, 5, -5, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 32}, ++ {/*intp_sft*/0, 6}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/1, 0}, ++ }, ++ {/*H0V2*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, 5, 5, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/4, 0}, ++ {/*intp_sft*/3, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, -2, 96, 42, -7, 0, 0, 0}, {0, -1, 5, 5, -1, 0, 0, 0},}, ++ {/*intp_rnd*/64, 0}, //{0,512} ++ {/*intp_sft*/0, 10}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 5, 5, -1, 0, 0, 0, 0}, {-1, 5, 5, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 32}, ++ {/*intp_sft*/0, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{0, -7, 42, 96, -2, -1, 0, 0}, {0, -1, 5, 5, -1, 0, 0, 0},}, ++ {/*intp_rnd*/64, 0}, //{0,512} ++ {/*intp_sft*/0, 10}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V3*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{0, -7, 42, 96, -2, -1, 0, 0}, {0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V3*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, IS_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 5, 5, -1, 0, 0, 0, 0}, {-1, 5, -5, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 32}, ++ {/*intp_sft*/0, 6}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 1}, ++ }, ++ {/*H2V3*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{0, -1, 5, 5, -1, 0, 0, 0}, {0, -7, 42, 96, -2, -1, 0, 0},}, ++ {/*intp_rnd*/64, 0}, //{0,512} ++ {/*intp_sft*/0, 10}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V3*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, IS_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 5, 5, -1, 0, 0, 0, 0}, {-1, 5, -5, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 32}, ++ {/*intp_sft*/0, 6}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/1, 1}, ++ }, ++ }, ++ ++ { ++ /************* VP6_QPEL ***************/ ++ {/*H0V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-4, 109, 24, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-4, 68, 68, -4, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 24, 109, -4, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V1*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-4, 109, 24, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V1*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-4, 109, 24, -1, 0, 0, 0, 0}, {-4, 109, 24, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V1*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-4, 68, 68, -4, 0, 0, 0, 0}, {-4, 109, 24, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V1*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 24, 109, -4, 0, 0, 0, 0}, {-4, 109, 24, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V2*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-4, 68, 68, -4, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-4, 109, 24, -1, 0, 0, 0, 0}, {-4, 68, 68, -4, 0, 0, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-4, 68, 68, -4, 0, 0, 0, 0}, {-4, 68, 68, -4, 0, 0, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 24, 109, -4, 0, 0, 0, 0}, {-4, 68, 68, -4, 0, 0, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V3*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, 24, 109, -4, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V3*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-4, 109, 24, -1, 0, 0, 0, 0}, {-1, 24, 109, -4, 0, 0, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V3*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-4, 68, 68, -4, 0, 0, 0, 0}, {-1, 24, 109, -4, 0, 0, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V3*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 24, 109, -4, 0, 0, 0, 0}, {-1, 24, 109, -4, 0, 0, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ }, ++ ++ { ++ /************* VP8_QPEL ***************/ ++ {/*H0V0*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{2, -11, 108, 36, -8, 1, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{3, -16, 77, 77, -16, 3, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, -8, 36, 108, -11, 2, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V1*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{2, -11, 108, 36, -8, 1, 0, 0}, {0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V1*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{2, -11, 108, 36, -8, 1, 0, 0}, {2, -11, 108, 36, -8, 1, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V1*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{3, -16, 77, 77, -16, 3, 0, 0}, {2, -11, 108, 36, -8, 1, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V1*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -8, 36, 108, -11, 2, 0, 0}, {2, -11, 108, 36, -8, 1, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V2*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{3, -16, 77, 77, -16, 3, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{2, -11, 108, 36, -8, 1, 0, 0}, {3, -16, 77, 77, -16, 3, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{3, -16, 77, 77, -16, 3, 0, 0}, {3, -16, 77, 77, -16, 3, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -8, 36, 108, -11, 2, 0, 0}, {3, -16, 77, 77, -16, 3, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V3*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, -8, 36, 108, -11, 2, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V3*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{2, -11, 108, 36, -8, 1, 0, 0}, {1, -8, 36, 108, -11, 2, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V3*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{3, -16, 77, 77, -16, 3, 0, 0}, {1, -8, 36, 108, -11, 2, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V3*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -8, 36, 108, -11, 2, 0, 0}, {1, -8, 36, 108, -11, 2, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ }, ++ ++ { ++ /************* VP8_EPEL ***************/ ++ {/*H0V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/0}, ++ {/*H2V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{0},{0},}, ++ {/*intp_rnd*/4, 0}, ++ {/*intp_sft*/3, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V0*/0}, ++ {/*H0V1*/0}, ++ {/*H1V1*/0}, ++ {/*H2V1*/0}, ++ {/*H3V1*/0}, ++ {/*H0V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{0},{0},}, ++ {/*intp_rnd*/4, 0}, ++ {/*intp_sft*/3, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V2*/0}, ++ {/*H2V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{0},{0},}, ++ {/*intp_rnd*/4, 4}, ++ {/*intp_sft*/3, 3}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V2*/0}, ++ {/*H0V3*/0}, ++ {/*H1V3*/0}, ++ {/*H2V3*/0}, ++ {/*H3V3*/0}, ++ }, ++ ++ { ++ /************* VP8_BIL ***************/ ++ {/*H0V0*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{3, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/2, 0}, ++ {/*intp_sft*/2, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H2V0*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/1, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V0*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, 3, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/2, 0}, ++ {/*intp_sft*/2, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H0V1*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{3, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/2, 0}, ++ {/*intp_sft*/2, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V1*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{3, 1, 0, 0, 0, 0, 0, 0},{3, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/2, 2}, ++ {/*intp_sft*/2, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H2V1*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{3, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/1, 2}, ++ {/*intp_sft*/1, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V1*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 3, 0, 0, 0, 0, 0, 0},{3, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/2, 2}, ++ {/*intp_sft*/2, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H0V2*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/1, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V2*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{3, 1, 0, 0, 0, 0, 0, 0},{1, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/2, 1}, ++ {/*intp_sft*/2, 1}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H2V2*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{1, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/1, 1}, ++ {/*intp_sft*/1, 1}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V2*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 3, 0, 0, 0, 0, 0, 0},{1, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/2, 1}, ++ {/*intp_sft*/2, 1}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H0V3*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, 3, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/2, 0}, ++ {/*intp_sft*/2, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V3*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{3, 1, 0, 0, 0, 0, 0, 0},{1, 3, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/2, 2}, ++ {/*intp_sft*/2, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H2V3*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{1, 3, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/1, 2}, ++ {/*intp_sft*/1, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V3*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 3, 0, 0, 0, 0, 0, 0},{1, 3, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/2, 2}, ++ {/*intp_sft*/2, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ }, ++ ++ { ++ /************* VP8_FPEL ***************/ ++ {/*H0V0*/0}, ++ {/*H1V0*/0}, ++ {/*H2V0*/0}, ++ {/*H3V0*/0}, ++ {/*H0V1*/0}, ++ {/*H1V1*/0}, ++ {/*H2V1*/0}, ++ {/*H3V1*/0}, ++ {/*H0V2*/0}, ++ {/*H1V2*/0}, ++ {/*H2V2*/0}, ++ {/*H3V2*/0}, ++ {/*H0V3*/0}, ++ {/*H1V3*/0}, ++ {/*H2V3*/0}, ++ {/*H3V3*/0}, ++ }, ++ ++ { ++ /************* HEVC_QPEL ***************/ ++ {/*H0V0*/ ++ TAP8, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP8, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 4, -10, 58, 17, -5, 1, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP8, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 4, -11, 40, 40, -11, 4, -1},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/ ++ TAP8, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{0, 1, -5, 17, 58, -10, 4, -1},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V1*/ ++ TAP8, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, 4, -10, 58, 17, -5, 1, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V1*/ ++ TAP8, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 4, -10, 58, 17, -5, 1, 0},{-1, 4, -10, 58, 17, -5, 1, 0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/0, 12}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V1*/ ++ TAP8, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 4, -11, 40, 40, -11, 4, -1},{-1, 4, -10, 58, 17, -5, 1, 0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/0, 12}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V1*/ ++ TAP8, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{0, 1, -5, 17, 58, -10, 4, -1},{-1, 4, -10, 58, 17, -5, 1, 0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/0, 12}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V2*/ ++ TAP8, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, 4, -11, 40, 40, -11, 4, -1},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP8, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 4, -10, 58, 17, -5, 1, 0},{-1, 4, -11, 40, 40, -11, 4, -1},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/0, 12}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP8, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 4, -11, 40, 40, -11, 4, -1},{-1, 4, -11, 40, 40, -11, 4, -1},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/0, 12}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/ ++ TAP8, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{0, 1, -5, 17, 58, -10, 4, -1},{-1, 4, -11, 40, 40, -11, 4, -1},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/0, 12}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V3*/ ++ TAP8, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{0, 1, -5, 17, 58, -10, 4, -1},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V3*/ ++ TAP8, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 4, -10, 58, 17, -5, 1, 0},{0, 1, -5, 17, 58, -10, 4, -1},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/0, 12}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V3*/ ++ TAP8, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 4, -11, 40, 40, -11, 4, -1},{0, 1, -5, 17, 58, -10, 4, -1},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/0, 12}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V3*/ ++ TAP8, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{0, 1, -5, 17, 58, -10, 4, -1},{0, 1, -5, 17, 58, -10, 4, -1},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/0, 12}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ }, ++ ++ { ++ /************* HEVC_EPEL ***************/ ++ {/*H0V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-2, 58, 10, -2, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 12}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-4, 54, 16, -2, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 12}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-6, 46, 28, -4, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 12}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H4V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-4, 36, 36, -4, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 12}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H5V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-4, 28, 46, -6, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 12}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H6V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-2, 16, 54, -4, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 12}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H7V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-2, 10, 58, -2, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 12}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V2*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0, 0}, ++ {/*intp_coef*/{0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0, 0}, ++ {/*intp_coef*/{0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0, 0}, ++ {/*intp_coef*/{0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0, 0}, ++ {/*intp_coef*/{0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V3*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0, 0}, ++ {/*intp_coef*/{0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V3*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0, 0}, ++ {/*intp_coef*/{0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V3*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0, 0}, ++ {/*intp_coef*/{0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V3*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0, 0}, ++ {/*intp_coef*/{0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ }, ++ ++}; ++ ++#endif /*__HELIX_H__*/ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_api_helix_jpeg_dec.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_api_helix_jpeg_dec.c.patch new file mode 100644 index 00000000..d53767ac --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_api_helix_jpeg_dec.c.patch @@ -0,0 +1,55 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/helix/api/helix_jpeg_dec.c b/drivers/media/platform/ingenic-vcodec/helix/api/helix_jpeg_dec.c +--- a/drivers/media/platform/ingenic-vcodec/helix/api/helix_jpeg_dec.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/helix/api/helix_jpeg_dec.c 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,51 @@ ++#include "helix_jpeg_dec.h" ++ ++void JPEGD_SliceInit(_JPEGD_SliceInfo *s) ++{ ++ unsigned int i; ++ volatile unsigned int *chn = (volatile unsigned int *)s->des_va; ++ ++ GEN_VDMA_ACFG(chn, TCSM_FLUSH, 0, 0x0); ++ ++ /* Open clock configuration */ ++ GEN_VDMA_ACFG(chn, REG_JPGC_GLBI, 0, OPEN_CLOCK); ++ ++ /************************************************** ++ Huffman Encode Table configuration ++ *************************************************/ ++ for(i=0; ihuffmin++) ); ++ for(i=0; ihuffbase++)); ++ for(i=0; ihuffsymb++)); ++ /************************************************** ++ Quantization Table configuration ++ *************************************************/ ++ for(i=0; iqmem++)); ++ ++ /************************************************** ++ REGs configuration ++ *************************************************/ ++ GEN_VDMA_ACFG(chn, REG_JPGC_STAT, 0, 0); ++ GEN_VDMA_ACFG(chn, REG_JPGC_BSA, 0,(uint32_t)s->bsa); ++ GEN_VDMA_ACFG(chn,REG_JPGC_P0A,0, (uint32_t)s->p0a); ++ GEN_VDMA_ACFG(chn,REG_JPGC_P1A, 0,(uint32_t)s->p1a ); ++ GEN_VDMA_ACFG(chn,REG_JPGC_NMCU,0, s->nmcu); ++ GEN_VDMA_ACFG(chn,REG_JPGC_NRSM,0, s->nrsm); ++ GEN_VDMA_ACFG(chn,REG_JPGC_WIDTH,0, s->width); ++ GEN_VDMA_ACFG(chn,REG_JPGC_P0C,0, s->pxc[0]);/* component 0 configure information NBLK<<4| QT<<2| HA<<1| HD */ ++ GEN_VDMA_ACFG(chn,REG_JPGC_P1C,0, s->pxc[1]); ++ GEN_VDMA_ACFG(chn,REG_JPGC_P2C,0, s->pxc[2]); ++ GEN_VDMA_ACFG(chn,REG_JPGC_P3C,0, s->pxc[3]); ++ ++ GEN_VDMA_ACFG(chn,REG_JPGC_GLBI,0, (YUV420PVH /*P0V|P0H*/| ++ JPGC_NCOL /*NCOL*/ | ++ JPGC_DEC/*DE*/ | ++ JPGC_EN /*ENABLE*/) ); ++ ++ GEN_VDMA_ACFG(chn,REG_JPGC_TRIG,VDMA_ACFG_TERM,JPGC_BS_TRIG|JPGC_PP_TRIG | JPGC_CORE_OPEN); ++ ++ ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_api_helix_jpeg_dec.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_api_helix_jpeg_dec.h.patch new file mode 100644 index 00000000..73d22d7a --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_api_helix_jpeg_dec.h.patch @@ -0,0 +1,76 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/helix/api/helix_jpeg_dec.h b/drivers/media/platform/ingenic-vcodec/helix/api/helix_jpeg_dec.h +--- a/drivers/media/platform/ingenic-vcodec/helix/api/helix_jpeg_dec.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/helix/api/helix_jpeg_dec.h 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,72 @@ ++/**************************************************************** ++*****************************************************************/ ++ ++#ifndef __JZM_JPEG_DEC_H__ ++#define __JZM_JPEG_DEC_H__ ++#include "helix.h" ++ ++#ifdef __KERNEL__ ++#include ++#include ++#include ++#define printf printk ++#endif ++ ++ ++#define JPGC_EN (0x1) /* JPGC enable signal */ ++ ++#define YUV420P0C (0x30) /* component 0 configure information NBLK<<4| QT<<2| HA<<1| HD */ ++#define YUV420P1C (0x03) /* component 1 configure information NBLK<<4| QT<<2| HA<<1| HD */ ++#define YUV420P2C (0x03) /* component 2 configure information NBLK<<4| QT<<2| HA<<1| HD */ ++#define YUV420P3C (0xf0) /* component 3 configure information NBLK<<4| QT<<2| HA<<1| HD */ ++ ++#define YUV420PVH (0x0a<<16) /* component vertical/horizontal size of MCU:P3H P3V P2H P2V P1H P1V P0H P0V */ ++#define JPGC_RSM (0x1<<2) /* JPGC rstart marker enable signal */ ++#define JPGC_SPEC (0x0<<1) /* YUV420 mode */ ++#define JPGC_UNIV (0x1<<1) /* YUV444 or YUV422 mode */ ++#define JPGC_DEC (0x1<<3) /* JPGC decode signal: 1 (decode); 0(encode) */ ++#define OPEN_CLOCK (0x1) /* open the core clock */ ++#define JPGC_NCOL (0x2<<4) /* color numbers of a MCU minus 1,it always 2 for YUV color space */ ++#define STAT_CLEAN (0x0) /* clean the STAT register */ ++#define CORE_RST (0x1<<6) /* JPGC core reset ,high active */ ++#define JPGC_EFE (0x1<<8) /* JPGC EFE source */ ++#define VRAM_RAWY_BA (VPU_BASE | 0xF0000) ++#define VRAM_RAWC_BA (VRAM_RAWY_BA + 256) ++ ++#if 0 ++/* JPEG Decode quantization table select level */ ++typedef enum { ++ LOW_QUALITY, ++ MEDIUMS_QUALITY, ++ HIGH_QUALITY ++} QUANT_QUALITY; ++#endif ++ ++#define HUFFMIN_LEN 16 ++#define HUFFBASE_LEN 64 ++#define HUFFSYMB_LEN 336 ++#define QMEM_LEN 256 ++ ++/* ++ _JPEGD_SliceInfo: ++ JPEG Decoder Slice Level Information ++ */ ++typedef struct{ ++ uint32_t *des_va, des_pa; ++ uint32_t bsa; /* bitstream buffer address */ ++ uint32_t p0a, p1a; /* componet 0-3 plane buffer address */ ++ uint8_t nrsm; /* Re-Sync-Marker gap number */ ++ uint32_t nmcu; /* number of MCU minus one */ ++ uint32_t width; /* yuv nv12 frame width, bit15: 1,NV12, 0,TILE .(1 << 15) | (mb_width - 1)*/ ++ int *huffmin ; ++ int *huffbase ; ++ int *huffsymb ; ++ int *qmem ; ++ uint32_t pxc[4]; /* component 0~3 config info */ ++ ++}_JPEGD_SliceInfo; ++ ++ ++ ++void JPEGD_SliceInit(_JPEGD_SliceInfo *s); ++#endif// __JZM_JPEG_ENC_H__ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_api_helix_jpeg_enc.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_api_helix_jpeg_enc.c.patch new file mode 100644 index 00000000..337d4688 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_api_helix_jpeg_enc.c.patch @@ -0,0 +1,245 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/helix/api/helix_jpeg_enc.c b/drivers/media/platform/ingenic-vcodec/helix/api/helix_jpeg_enc.c +--- a/drivers/media/platform/ingenic-vcodec/helix/api/helix_jpeg_enc.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/helix/api/helix_jpeg_enc.c 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,241 @@ ++#include "helix_jpeg_enc.h" ++ ++__place_k0_data__ ++uint32_t huffenc[HUFNUM][HUFFENC_LEN] = { ++ {0x100, 0x101, 0x204, 0x30b, 0x41a, 0x678, 0x7f8, 0x9f6, ++ 0xf82, 0xf83, 0x30c, 0x41b, 0x679, 0x8f6, 0xaf6, 0xf84, ++ 0xf85, 0xf86, 0xf87, 0xf88, 0x41c, 0x7f9, 0x9f7, 0xbf4, ++ 0xf89, 0xf8a, 0xf8b, 0xf8c, 0xf8d, 0xf8e, 0x53a, 0x8f7, ++ 0xbf5, 0xf8f, 0xf90, 0xf91, 0xf92, 0xf93, 0xf94, 0xf95, ++ 0x53b, 0x9f8, 0xf96, 0xf97, 0xf98, 0xf99, 0xf9a, 0xf9b, ++ 0xf9c, 0xf9d, 0x67a, 0xaf7, 0xf9e, 0xf9f, 0xfa0, 0xfa1, ++ 0xfa2, 0xfa3, 0xfa4, 0xfa5, 0x67b, 0xbf6, 0xfa6, 0xfa7, ++ 0xfa8, 0xfa9, 0xfaa, 0xfab, 0xfac, 0xfad, 0x7fa, 0xbf7, ++ 0xfae, 0xfaf, 0xfb0, 0xfb1, 0xfb2, 0xfb3, 0xfb4, 0xfb5, ++ 0x8f8, 0xec0, 0xfb6, 0xfb7, 0xfb8, 0xfb9, 0xfba, 0xfbb, ++ 0xfbc, 0xfbd, 0x8f9, 0xfbe, 0xfbf, 0xfc0, 0xfc1, 0xfc2, ++ 0xfc3, 0xfc4, 0xfc5, 0xfc6, 0x8fa, 0xfc7, 0xfc8, 0xfc9, ++ 0xfca, 0xfcb, 0xfcc, 0xfcd, 0xfce, 0xfcf, 0x9f9, 0xfd0, ++ 0xfd1, 0xfd2, 0xfd3, 0xfd4, 0xfd5, 0xfd6, 0xfd7, 0xfd8, ++ 0x9fa, 0xfd9, 0xfda, 0xfdb, 0xfdc, 0xfdd, 0xfde, 0xfdf, ++ 0xfe0, 0xfe1, 0xaf8, 0xfe2, 0xfe3, 0xfe4, 0xfe5, 0xfe6, ++ 0xfe7, 0xfe8, 0xfe9, 0xfea, 0xfeb, 0xfec, 0xfed, 0xfee, ++ 0xfef, 0xff0, 0xff1, 0xff2, 0xff3, 0xff4, 0xff5, 0xff6, ++ 0xff7, 0xff8, 0xff9, 0xffa, 0xffb, 0xffc, 0xffd, 0xffe, ++ 0x30a, 0xaf9, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, ++ 0xfd0, 0xfd1, 0xfd2, 0xfd3, 0xfd4, 0xfd5, 0xfd6, 0xfd7, ++ 0x101, 0x204, 0x30a, 0x418, 0x419, 0x538, 0x678, 0x8f4, ++ 0x9f6, 0xbf4, 0x30b, 0x539, 0x7f6, 0x8f5, 0xaf6, 0xbf5, ++ 0xf88, 0xf89, 0xf8a, 0xf8b, 0x41a, 0x7f7, 0x9f7, 0xbf6, ++ 0xec2, 0xf8c, 0xf8d, 0xf8e, 0xf8f, 0xf90, 0x41b, 0x7f8, ++ 0x9f8, 0xbf7, 0xf91, 0xf92, 0xf93, 0xf94, 0xf95, 0xf96, ++ 0x53a, 0x8f6, 0xf97, 0xf98, 0xf99, 0xf9a, 0xf9b, 0xf9c, ++ 0xf9d, 0xf9e, 0x53b, 0x9f9, 0xf9f, 0xfa0, 0xfa1, 0xfa2, ++ 0xfa3, 0xfa4, 0xfa5, 0xfa6, 0x679, 0xaf7, 0xfa7, 0xfa8, ++ 0xfa9, 0xfaa, 0xfab, 0xfac, 0xfad, 0xfae, 0x67a, 0xaf8, ++ 0xfaf, 0xfb0, 0xfb1, 0xfb2, 0xfb3, 0xfb4, 0xfb5, 0xfb6, ++ 0x7f9, 0xfb7, 0xfb8, 0xfb9, 0xfba, 0xfbb, 0xfbc, 0xfbd, ++ 0xfbe, 0xfbf, 0x8f7, 0xfc0, 0xfc1, 0xfc2, 0xfc3, 0xfc4, ++ 0xfc5, 0xfc6, 0xfc7, 0xfc8, 0x8f8, 0xfc9, 0xfca, 0xfcb, ++ 0xfcc, 0xfcd, 0xfce, 0xfcf, 0xfd0, 0xfd1, 0x8f9, 0xfd2, ++ 0xfd3, 0xfd4, 0xfd5, 0xfd6, 0xfd7, 0xfd8, 0xfd9, 0xfda, ++ 0x8fa, 0xfdb, 0xfdc, 0xfdd, 0xfde, 0xfdf, 0xfe0, 0xfe1, ++ 0xfe2, 0xfe3, 0xaf9, 0xfe4, 0xfe5, 0xfe6, 0xfe7, 0xfe8, ++ 0xfe9, 0xfea, 0xfeb, 0xfec, 0xde0, 0xfed, 0xfee, 0xfef, ++ 0xff0, 0xff1, 0xff2, 0xff3, 0xff4, 0xff5, 0xec3, 0xff6, ++ 0xff7, 0xff8, 0xff9, 0xffa, 0xffb, 0xffc, 0xffd, 0xffe, ++ 0x100, 0x9fa, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, ++ 0xfd0, 0xfd1, 0xfd2, 0xfd3, 0xfd4, 0xfd5, 0xfd6, 0xfd7, ++ 0x100, 0x202, 0x203, 0x204, 0x205, 0x206, 0x30e, 0x41e, ++ 0x53e, 0x67e, 0x7fe, 0x8fe, 0xfff, 0xfff, 0xfff, 0xfff, ++ 0x100, 0x101, 0x102, 0x206, 0x30e, 0x41e, 0x53e, 0x67e, ++ 0x7fe, 0x8fe, 0x9fe, 0xafe, 0xfff, 0xfff, 0xfff, 0xfff} ++}; ++ ++__place_k0_data__ ++uint32_t qmem[QTNUM][QMEM_LEN] = { ++ //normal quantization table ++ {0x0100, 0x0155, 0x0155, 0x0a49, 0x0155, 0x0b33, 0x0100, 0x0a49, ++ 0x0a49, 0x0a49, 0x09c7, 0x09c7, 0x0100, 0x00cd, 0x0955, 0x08cd, ++ 0x093b, 0x0955, 0x12e9, 0x12e9, 0x0955, 0x251f, 0x11c7, 0x11af, ++ 0x0911, 0x08cd, 0x1a35, 0x113b, 0x2421, 0x1111, 0x1a35, 0x113b, ++ 0x1a49, 0x1a49, 0x0880, 0x19c7, 0x10b2, 0x10d2, 0x0880, 0x10f1, ++ 0x10ba, 0x10ea, 0x1a49, 0x1a49, 0x10cd, 0x1095, 0x231f, 0x10ba, ++ 0x1955, 0x229d, 0x193b, 0x193b, 0x193b, 0x2421, 0x10d2, 0x223f, ++ 0x2219, 0x2249, 0x10a4, 0x1911, 0x10b2, 0x2d05, 0x193b, 0x10a4, ++ 0x09c7, 0x09c7, 0x09c7, 0x0955, 0x12e9, 0x0955, 0x1155, 0x093b, ++ 0x093b, 0x1155, 0x10a4, 0x23e1, 0x1a49, 0x23e1, 0x10a4, 0x10a4, ++ 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, ++ 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, ++ 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, ++ 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, ++ 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, ++ 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, ++ //finer quantization table ++ {0x0155, 0x0200, 0x0200, 0x0b33, 0x0200, 0x0200, 0x0155, 0x0b33, ++ 0x0b33, 0x0b33, 0x0155, 0x0155, 0x0155, 0x0155, 0x0100, 0x093b, ++ 0x09c7, 0x0100, 0x0a49, 0x0a49, 0x0100, 0x0911, 0x12e9, 0x0955, ++ 0x09c7, 0x093b, 0x11c7, 0x0080, 0x11af, 0x11af, 0x11c7, 0x0080, ++ 0x11c7, 0x08f1, 0x08cd, 0x08ba, 0x1a49, 0x1155, 0x08cd, 0x08c3, ++ 0x1a5f, 0x08c3, 0x08f1, 0x11c7, 0x251f, 0x23e1, 0x251f, 0x1a5f, ++ 0x1a35, 0x1111, 0x0880, 0x0880, 0x0880, 0x11af, 0x1155, 0x10ea, ++ 0x19bb, 0x10f1, 0x2421, 0x19bb, 0x1a49, 0x2421, 0x0880, 0x1111, ++ 0x0155, 0x0155, 0x0155, 0x0100, 0x0a49, 0x0100, 0x0911, 0x09c7, ++ 0x09c7, 0x0911, 0x1111, 0x08c3, 0x11c7, 0x08c3, 0x1111, 0x1111, ++ 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, ++ 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, ++ 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, ++ 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, ++ 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, ++ 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, ++ //finest quantization table ++ {0x02ab, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x02ab, 0x0400, ++ 0x0400, 0x0400, 0x02ab, 0x02ab, 0x02ab, 0x02ab, 0x02ab, 0x0b33, ++ 0x0200, 0x02ab, 0x02ab, 0x02ab, 0x02ab, 0x0155, 0x0200, 0x0b33, ++ 0x0200, 0x0b33, 0x0a49, 0x0155, 0x0a49, 0x0a49, 0x0a49, 0x0155, ++ 0x0a49, 0x0155, 0x0a49, 0x0100, 0x00cd, 0x09c7, 0x0a49, 0x0100, ++ 0x00cd, 0x0100, 0x0155, 0x0a49, 0x09c7, 0x0955, 0x09c7, 0x00cd, ++ 0x00cd, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x0a49, 0x09c7, 0x0955, ++ 0x093b, 0x0955, 0x12e9, 0x093b, 0x00cd, 0x12e9, 0x12e9, 0x12e9, ++ 0x02ab, 0x02ab, 0x02ab, 0x02ab, 0x02ab, 0x02ab, 0x0155, 0x0200, ++ 0x0200, 0x0155, 0x12e9, 0x0100, 0x0a49, 0x0100, 0x12e9, 0x12e9, ++ 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, ++ 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, ++ 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, ++ 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, ++ 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, ++ 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000} ++}; ++ ++ ++void JPEGE_SliceInit(_JPEGE_SliceInfo *s) ++{ ++ unsigned int i; ++ volatile unsigned int *chn = (volatile unsigned int *)s->des_va; ++ ++ GEN_VDMA_ACFG(chn, TCSM_FLUSH, 0, 0x0); ++ ++ /* Open clock configuration */ ++ GEN_VDMA_ACFG(chn, REG_JPGC_GLBI, 0, OPEN_CLOCK); ++ ++ /************************************************** ++ Huffman Encode Table configuration ++ *************************************************/ ++ for(i=0; ihuffenc_sel][i]); ++ ++ /************************************************** ++ Quantization Table configuration ++ *************************************************/ ++ for(i=0; iql_sel][i]); ++ ++ /************************************************** ++ REGs configuration ++ *************************************************/ ++ GEN_VDMA_ACFG(chn, REG_JPGC_STAT, 0, STAT_CLEAN); ++ GEN_VDMA_ACFG(chn, REG_JPGC_BSA, 0, s->bsa); ++ ++ if(s->raw_format) { /* NV12 or NV21 */ ++ GEN_VDMA_ACFG(chn, REG_JPGC_P0A, 0, VRAM_RAWY_BA); ++ } else {/* TILE */ ++ GEN_VDMA_ACFG(chn, REG_JPGC_P0A, 0, s->p0a); ++ GEN_VDMA_ACFG(chn, REG_JPGC_P1A, 0, s->p1a); ++ } ++ ++ GEN_VDMA_ACFG(chn, REG_JPGC_NMCU, 0, s->nmcu); ++ GEN_VDMA_ACFG(chn, REG_JPGC_NRSM, 0, s->nrsm); ++ ++ GEN_VDMA_ACFG(chn, REG_JPGC_P0C, 0, YUV420P0C); ++ GEN_VDMA_ACFG(chn, REG_JPGC_P1C, 0, YUV420P1C); ++ GEN_VDMA_ACFG(chn, REG_JPGC_P2C, 0, YUV420P2C); ++ ++ if(s->raw_format) { ++ GEN_VDMA_ACFG(chn, REG_JPGC_GLBI, 0, (YUV420PVH | ++ JPGC_NCOL | ++ JPGC_SPEC /* MODE */ | ++ JPGC_EFE | ++ JPGC_EN)); ++ ++ GEN_VDMA_ACFG(chn, REG_JPGC_TRIG, 0, JPGC_BS_TRIG | JPGC_PP_TRIG | JPGC_CORE_OPEN); ++ ++ }else{ ++ GEN_VDMA_ACFG(chn, REG_JPGC_GLBI, 0, (YUV420PVH | ++ JPGC_NCOL | ++ JPGC_SPEC /* MODE */ | ++ JPGC_EN)); ++ ++ GEN_VDMA_ACFG(chn, REG_JPGC_TRIG, VDMA_ACFG_TERM, JPGC_BS_TRIG | JPGC_PP_TRIG | JPGC_CORE_OPEN); ++ } ++ ++ ++ /************************************************** ++ EFE configuration ++ *************************************************/ ++ if(s->raw_format) { ++ GEN_VDMA_ACFG(chn, REG_EFE_GEOM, 0, (EFE_JPGC_LST_MBY(s->mb_height-1) | ++ EFE_JPGC_LST_MBX(s->mb_width-1) ) ); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_RAWY_SBA, 0, s->raw[0]); ++ GEN_VDMA_ACFG(chn, REG_EFE_RAWU_SBA, 0, s->raw[1]); ++ GEN_VDMA_ACFG(chn, REG_EFE_RAWV_SBA, 0, s->raw[2]); ++ GEN_VDMA_ACFG(chn, REG_EFE_RAW_STRD, 0, (EFE_RAW_STRDY(s->stride[0]) | ++ EFE_RAW_STRDC(s->stride[1]) ) ); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_RAW_DBA, 0, VRAM_RAWY_BA); ++ GEN_VDMA_ACFG(chn, REG_EFE_CTRL, VDMA_ACFG_TERM, (EFE_PLANE_NV12 | ++ EFE_ID_JPEG | ++ EFE_EN | ++ (s->raw_format)| ++ EFE_RUN) ); ++ } ++ ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_api_helix_jpeg_enc.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_api_helix_jpeg_enc.h.patch new file mode 100644 index 00000000..111c2132 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_api_helix_jpeg_enc.h.patch @@ -0,0 +1,85 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/helix/api/helix_jpeg_enc.h b/drivers/media/platform/ingenic-vcodec/helix/api/helix_jpeg_enc.h +--- a/drivers/media/platform/ingenic-vcodec/helix/api/helix_jpeg_enc.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/helix/api/helix_jpeg_enc.h 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,81 @@ ++/**************************************************************** ++*****************************************************************/ ++ ++#ifndef __JZM_JPEG_ENC_H__ ++#define __JZM_JPEG_ENC_H__ ++#include "helix.h" ++ ++#ifdef __KERNEL__ ++#include ++#include ++#include ++#define printf printk ++#endif ++ ++#define HUFFENC_LEN (384) /* Huffman encoder table lenth */ ++#define QMEM_LEN (256) /* Quantization table lenth */ ++#define HUFNUM (1) /* Huffman encode table number */ ++#define QTNUM (3) /* Quantization table number */ ++#define YUV420P0C (0x30) /* component 0 configure information NBLK<<4| QT<<2| HA<<1| HD */ ++#define YUV420P1C (0x07) /* component 1 configure information NBLK<<4| QT<<2| HA<<1| HD */ ++#define YUV420P2C (0x07) /* component 2 configure information NBLK<<4| QT<<2| HA<<1| HD */ ++#define YUV420PVH (0x0a<<16) /* component vertical/horizontal size of MCU:P3H P3V P2H P2V P1H P1V P0H P0V */ ++#define JPGC_RSM (0x1<<2) /* JPGC rstart marker enable signal */ ++#define JPGC_SPEC (0x0<<1) /* YUV420 mode */ ++#define JPGC_UNIV (0x1<<1) /* YUV444 or YUV422 mode */ ++#define JPGC_EN (0x1) /* JPGC enable signal */ ++#define OPEN_CLOCK (0x1) /* open the core clock */ ++#define JPGC_NCOL (0x2<<4) /* color numbers of a MCU minus 1,it always 2 for YUV color space */ ++#define STAT_CLEAN (0x0) /* clean the STAT register */ ++#define CORE_RST (0x1<<6) /* JPGC core reset ,high active */ ++#define JPGC_EFE (0x1<<8) /* JPGC EFE source */ ++#define VRAM_RAWY_BA (VPU_BASE | 0xF0000) ++#define VRAM_RAWC_BA (VRAM_RAWY_BA + 256) ++ ++#if 0 ++/* JPEG encode quantization table select level */ ++typedef enum { ++ LOW_QUALITY, ++ MEDIUMS_QUALITY, ++ HIGH_QUALITY ++} QUANT_QUALITY; ++#endif ++ ++/* ++ _JPEGE_SliceInfo: ++ JPEG Encoder Slice Level Information ++ */ ++ ++typedef struct _JPEGE_SliceInfo { ++ uint32_t *des_va, des_pa; ++ uint8_t ncol; /* number of color/components of a MCU minus one */ ++ uint8_t rsm; /* Re-sync-marker enable */ ++ uint32_t bsa; /* bitstream buffer address */ ++ uint32_t p0a, p1a; /* componet 0-3 plane buffer address */ ++ uint8_t nrsm; /* Re-Sync-Marker gap number */ ++ uint32_t nmcu; /* number of MCU minus one */ ++ uint32_t raw[3]; /*{rawy, rawu, rawv} or {rawy, rawc, N/C}*/ ++ uint32_t stride[2]; /*{stride_y, stride_c}, only used in raster raw*/ ++ uint32_t mb_height; ++ uint32_t mb_width; ++ uint8_t raw_format; ++ ++ /* Quantization level select,0-2 level */ ++ int ql_sel; ++ uint8_t huffenc_sel; /* Huffman ENC Table select */ ++}_JPEGE_SliceInfo; ++ ++ ++__place_k0_data__ ++extern uint32_t huffenc[HUFNUM][HUFFENC_LEN]; ++ ++__place_k0_data__ ++extern uint32_t qmem[QTNUM][QMEM_LEN]; ++ ++/* ++ JPEGE_SliceInit(_JPEGE_SliceInfo *s) ++ @param s: slice information structure ++ */ ++ ++void JPEGE_SliceInit(_JPEGE_SliceInfo *s); ++#endif// __JZM_JPEG_ENC_H__ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_api_helix_x264_enc.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_api_helix_x264_enc.c.patch new file mode 100644 index 00000000..095a1624 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_api_helix_x264_enc.c.patch @@ -0,0 +1,1243 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/helix/api/helix_x264_enc.c b/drivers/media/platform/ingenic-vcodec/helix/api/helix_x264_enc.c +--- a/drivers/media/platform/ingenic-vcodec/helix/api/helix_x264_enc.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/helix/api/helix_x264_enc.c 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,1239 @@ ++#include "helix_x264_enc.h" ++#define MB_WID ((s->frame_width + 15) / 16) ++#define MB_HEI ((s->frame_height + 15) / 16) ++__place_k0_data__ ++static uint32_t lps_range[64] = { ++ 0xeeceaefc, 0xe1c3a5fc, 0xd6b99cfc, 0xcbb094f2, ++ 0xc1a78ce4, 0xb79e85da, 0xad967ece, 0xa48e78c4, ++ 0x9c8772ba, 0x94806cb0, 0x8c7966a6, 0x8573619e, ++ 0x7e6d5c96, 0x7867578e, 0x72625386, 0x6c5d4e80, ++ 0x66584a78, 0x61544672, 0x5c4f436c, 0x574b3f66, ++ 0x53473c62, 0x4e43395c, 0x4a403658, 0x463d3352, ++ 0x4339304e, 0x3f362e4a, 0x3c342b46, 0x39312942, ++ 0x362e273e, 0x332c253c, 0x30292338, 0x2e272136, ++ 0x2b251f32, 0x29231d30, 0x27211c2c, 0x251f1a2a, ++ 0x231e1928, 0x211c1826, 0x1f1b1624, 0x1d191522, ++ 0x1c181420, 0x1a17131e, 0x1915121c, 0x1714111a, ++ 0x16131018, 0x15120f18, 0x14110e16, 0x13100d14, ++ 0x120f0c14, 0x110e0c12, 0x100d0b12, 0x0f0d0a10, ++ 0x0e0c0a10, 0x0d0b090e, 0x0c0a090e, 0x0c0a080c, ++ 0x0b09070c, 0x0a09070a, 0x0a08070a, 0x0908060a, ++ 0x09070608, 0x08070508, 0x07060508, 0x00000000, ++}; ++ ++ ++ ++#define C_SPE_ADD_MB_NUM 3 ++void BUF_SHARE_CFG(_H264E_SliceInfo *s, uint32_t *buf_addr_group, uint8_t *buf_ref_mby_size, uint8_t *buf_odma_spe_flag, uint8_t *buf_odma_alg_flag) ++{ ++ int beyond_size = (s->buf_share_size + 1) * 64; ++ ++ int c_pxl_space = (s->mb_width*16)*(s->mb_height*8); ++ int y_space = (s->mb_width*16)*(s->mb_height*16+beyond_size); ++ int c_space = (s->mb_width*16)*(s->mb_height*8+(beyond_size/2)); ++ int y_every_space = (s->mb_width*16)*beyond_size; ++ int c_every_space = (s->mb_width*16)*(beyond_size/2); ++ ++ int mb_total = s->mb_width * s->mb_height; ++ ++ int spe_frm = 0; ++ int spe_ad_flag = 0; ++ int spe_mi_flag = 0; ++ int last_spe_ad_flag = 0; ++ int last_spe_mi_flag = 0; ++ int c_ofst_addr_n = ((s->frame_idx)*c_every_space)/c_space; ++ int last_c_ofst_addr_n = ((s->frame_idx-1)*c_every_space)/c_space; ++ ++ if(mb_total%2){ ++ //spe_frm = 1; ++ } ++ ++ //buf_beyond_yaddr ++ buf_addr_group[0] = s->fb[0][0] + y_space; ++ //buf_beyond_caddr ++ buf_addr_group[1] = spe_frm ? s->fb[0][1] + c_space + (128*C_SPE_ADD_MB_NUM) : s->fb[0][1] + c_space; ++ int tmp_beyond_caddr = spe_frm ? s->fb[0][1] + c_space + 128 : s->fb[0][1] + c_space; ++ ++ //calc last frame addr ++ int last_y_ofst_addr = s->frame_idx == 0 ? 0 : ((s->frame_idx-1)*y_every_space)%y_space; ++ int last_y_tmp_addr = last_y_ofst_addr ? (buf_addr_group[0] - last_y_ofst_addr) : s->fb[0][0]; ++ ++ int last_c_ofst_addr = s->frame_idx == 0 ? 0 : ((s->frame_idx-1)*c_every_space)%c_space; ++ int last_c_tmp_addr = last_c_ofst_addr ? (tmp_beyond_caddr - last_c_ofst_addr) : s->fb[0][1]; ++ ++ if(spe_frm & last_c_tmp_addr != s->fb[0][1]){ ++ if(last_c_ofst_addr_n%2){ ++ last_c_tmp_addr -= 256; ++ last_spe_mi_flag = 1; ++ } ++ ++ if(last_c_tmp_addr%256){ ++ last_c_tmp_addr += 128; ++ last_spe_ad_flag = 1; ++ } ++ ++ if((last_c_tmp_addr + c_every_space > buf_addr_group[1]) & last_spe_mi_flag){ ++ last_c_tmp_addr += 256; ++ } ++ } ++ ++ ++ //refy_addr_ba0 ++ buf_addr_group[4] = s->frame_idx == 0 ? s->fb[0][0] : last_y_tmp_addr; ++ //refy_addr_ba1 ++ buf_addr_group[5] = s->fb[0][0]; ++ //refc_addr_ba0 ++ buf_addr_group[6] = s->frame_idx == 0 ? s->fb[0][1] : last_c_tmp_addr; ++ //refc_addr_ba1 ++ buf_addr_group[7] = s->fb[0][1]; ++ //ref_mby_size ++ *buf_ref_mby_size = !s->buf_share_en ? 0xff : ((buf_addr_group[0] - buf_addr_group[4])/(s->mb_width*16))/16 - 1; ++ ++ ++ int y_ofst_addr = (s->frame_idx*y_every_space)%y_space; ++ int y_tmp_addr = y_ofst_addr ? (buf_addr_group[0] - y_ofst_addr) : s->fb[0][0]; ++ //buf_start_yaddr ++ buf_addr_group[2] = s->frame_idx == 0 ? s->fb[0][0] : y_tmp_addr; ++ ++ int c_ofst_addr = (s->frame_idx*c_every_space)%c_space; ++ int c_tmp_addr = c_ofst_addr ? (tmp_beyond_caddr - c_ofst_addr) : s->fb[0][1]; ++ //buf_start_caddr ++ buf_addr_group[3] = s->frame_idx == 0 ? s->fb[0][1] : c_tmp_addr; ++ ++ int spe_flag = 1; ++ if(spe_frm & buf_addr_group[3] != s->fb[0][1]){ ++ if(c_ofst_addr_n%2){ ++ buf_addr_group[3] -= 256; ++ spe_mi_flag = 1; ++ } ++ ++ if(buf_addr_group[3]%256){ ++ buf_addr_group[3] += 128; ++ spe_ad_flag = 1; ++ } ++ ++ if((buf_addr_group[3] + c_every_space > buf_addr_group[1]) & spe_mi_flag){ ++ buf_addr_group[3] += 256; ++ spe_flag = 0; ++ } ++ ++ } ++ ++ *buf_odma_spe_flag = spe_flag; ++ ++ int alg_flag = 0; ++ int c_pxl_space_row = s->mb_width*16*8; ++ if(((buf_addr_group[1] - (128*C_SPE_ADD_MB_NUM)) - buf_addr_group[3])% c_pxl_space_row == 0 ) ++ alg_flag = 1; ++ ++ *buf_odma_alg_flag = alg_flag; ++} ++ ++ ++ ++void H264E_SliceInit(_H264E_SliceInfo *s) ++{ ++ unsigned int i, j/*, tmp = 0*/; ++ volatile unsigned int *chn = (volatile unsigned int *)s->des_va; ++ ++ GEN_VDMA_ACFG(chn, TCSM_FLUSH, 0, 0); ++ ++ ++ /************************************************** ++ buf share cfg ++ *************************************************/ ++ ++ uint32_t buf_addr_group[8]; ++ uint8_t buf_ref_mby_size; ++ uint8_t buf_odma_spe_flag; ++ uint8_t buf_odma_alg_flag; ++ ++ BUF_SHARE_CFG(s, buf_addr_group, &buf_ref_mby_size, &buf_odma_spe_flag, &buf_odma_alg_flag); ++ ++ uint32_t buf_beyond_yaddr = buf_addr_group[0]; ++ uint32_t buf_beyond_caddr = buf_addr_group[1]; ++ uint32_t buf_start_yaddr = buf_addr_group[2]; ++ uint32_t buf_start_caddr = buf_addr_group[3]; ++ uint32_t refy_addr_ba0 = buf_addr_group[4]; ++ uint32_t refy_addr_ba1 = buf_addr_group[5]; ++ uint32_t refc_addr_ba0 = buf_addr_group[6]; ++ uint32_t refc_addr_ba1 = buf_addr_group[7]; ++ uint8_t ref_mby_size = buf_ref_mby_size; ++ uint8_t odma_spe_flag = buf_odma_spe_flag; ++ uint8_t odma_alg_flag = buf_odma_alg_flag; ++ ++ if(0){ ++ printf("[BUF_SHARE] frame_idx: %d, y_start: 0x%x, y_base: 0x%x, y_beyond: 0x%x, spe_flag: %d, alg_flag: %d\n", ++ s->frame_idx,buf_addr_group[2],s->fb[0][0],buf_addr_group[0],odma_spe_flag,odma_alg_flag); ++ printf(" c_start: 0x%x, c_base: 0x%x, c_beyond: 0x%x\n", ++ buf_addr_group[3],s->fb[0][1],buf_addr_group[1]); ++ printf(" ifa_y0: 0x%x, ifa_y1: 0x%x, ifa_c0: 0x%x, ifa_c1: 0x%x, mby: %d\n", ++ buf_addr_group[4],buf_addr_group[5],buf_addr_group[6],buf_addr_group[7],buf_ref_mby_size); ++ } ++ ++ /************************************************** ++ EFE configuration ++ *************************************************/ ++ GEN_VDMA_ACFG(chn, REG_EFE_GEOM, 0, (EFE_FST_MBY(s->first_mby) | ++ EFE_LST_MBY(s->last_mby) | ++ EFE_LST_MBX(MB_WID-1)) ); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_COEF_BA, 0, VRAM_MAU_RESA); ++ GEN_VDMA_ACFG(chn, REG_EFE_RAWY_SBA, 0, s->raw[0]); ++ GEN_VDMA_ACFG(chn, REG_EFE_RAWU_SBA, 0, s->raw[1]); ++ GEN_VDMA_ACFG(chn, REG_EFE_RAWV_SBA, 0, s->raw[2]); ++ GEN_VDMA_ACFG(chn, REG_EFE_RAW_STRD, 0, (EFE_RAW_STRDY(s->stride[0]) | ++ EFE_RAW_STRDC(s->stride[1]) ) ); ++ GEN_VDMA_ACFG(chn, REG_EFE_TOPMV_BA, 0, VRAM_TOPMV_BA); ++ GEN_VDMA_ACFG(chn, REG_EFE_TOPPA_BA, 0, VRAM_TOPPA_BA); ++ GEN_VDMA_ACFG(chn, REG_EFE_MECHN_BA, 0, VRAM_ME_CHN_BASE); ++ GEN_VDMA_ACFG(chn, REG_EFE_MAUCHN_BA, 0, VRAM_MAU_CHN_BASE); ++ GEN_VDMA_ACFG(chn, REG_EFE_DBLKCHN_BA, 0, VRAM_DBLK_CHN_BASE); ++ GEN_VDMA_ACFG(chn, REG_EFE_SDECHN_BA, 0, VRAM_SDE_CHN_BASE); ++ GEN_VDMA_ACFG(chn, REG_EFE_RAW_DBA, 0, VRAM_RAWY_BA); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_ROI_MAX_QP, 0, s->max_qp); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_ROI_BASE_INFO0, 0, ++ (( (s->roi_info[3].roi_qp & 0x3F) <<2 | ++ (s->roi_info[3].roi_md & 0x1) <<1 | ++ (s->roi_info[3].roi_en & 0x1) <<0 ) << 24) | ++ (( (s->roi_info[2].roi_qp & 0x3F) <<2 | ++ (s->roi_info[2].roi_md & 0x1) <<1 | ++ (s->roi_info[2].roi_en & 0x1) <<0 ) << 16) | ++ (( (s->roi_info[1].roi_qp & 0x3F) <<2 | ++ (s->roi_info[1].roi_md & 0x1) <<1 | ++ (s->roi_info[1].roi_en & 0x1) <<0 ) << 8) | ++ (( (s->roi_info[0].roi_qp & 0x3F) <<2 | ++ (s->roi_info[0].roi_md & 0x1) <<1 | ++ (s->roi_info[0].roi_en & 0x1) <<0 ) << 0) ++ ); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_ROI_BASE_INFO1, 0, ++ (( (s->roi_info[7].roi_qp & 0x3F) <<2 | ++ (s->roi_info[7].roi_md & 0x1) <<1 | ++ (s->roi_info[7].roi_en & 0x1) <<0 ) << 24) | ++ (( (s->roi_info[6].roi_qp & 0x3F) <<2 | ++ (s->roi_info[6].roi_md & 0x1) <<1 | ++ (s->roi_info[6].roi_en & 0x1) <<0 ) << 16) | ++ (( (s->roi_info[5].roi_qp & 0x3F) <<2 | ++ (s->roi_info[5].roi_md & 0x1) <<1 | ++ (s->roi_info[5].roi_en & 0x1) <<0 ) << 8) | ++ (( (s->roi_info[4].roi_qp & 0x3F) <<2 | ++ (s->roi_info[4].roi_md & 0x1) <<1 | ++ (s->roi_info[4].roi_en & 0x1) <<0 ) << 0) ++ ); ++ ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_ROI_POS_INFO0, 0, ++ ( (s->roi_info[0].roi_bmby & 0xFF) << 24 | ++ (s->roi_info[0].roi_umby & 0xFF) << 16 | ++ (s->roi_info[0].roi_rmbx & 0xFF) << 8 | ++ (s->roi_info[0].roi_lmbx & 0xFF) << 0 ) ++ ); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_ROI_POS_INFO1, 0, ++ ( (s->roi_info[1].roi_bmby & 0xFF) << 24 | ++ (s->roi_info[1].roi_umby & 0xFF) << 16 | ++ (s->roi_info[1].roi_rmbx & 0xFF) << 8 | ++ (s->roi_info[1].roi_lmbx & 0xFF) << 0 ) ++ ); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_ROI_POS_INFO2, 0, ++ ( (s->roi_info[2].roi_bmby & 0xFF) << 24 | ++ (s->roi_info[2].roi_umby & 0xFF) << 16 | ++ (s->roi_info[2].roi_rmbx & 0xFF) << 8 | ++ (s->roi_info[2].roi_lmbx & 0xFF) << 0 ) ++ ); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_ROI_POS_INFO3, 0, ++ ( (s->roi_info[3].roi_bmby & 0xFF) << 24 | ++ (s->roi_info[3].roi_umby & 0xFF) << 16 | ++ (s->roi_info[3].roi_rmbx & 0xFF) << 8 | ++ (s->roi_info[3].roi_lmbx & 0xFF) << 0 ) ++ ); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_ROI_POS_INFO4, 0, ++ ( (s->roi_info[4].roi_bmby & 0xFF) << 24 | ++ (s->roi_info[4].roi_umby & 0xFF) << 16 | ++ (s->roi_info[4].roi_rmbx & 0xFF) << 8 | ++ (s->roi_info[4].roi_lmbx & 0xFF) << 0 ) ++ ); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_ROI_POS_INFO5, 0, ++ ( (s->roi_info[5].roi_bmby & 0xFF) << 24 | ++ (s->roi_info[5].roi_umby & 0xFF) << 16 | ++ (s->roi_info[5].roi_rmbx & 0xFF) << 8 | ++ (s->roi_info[5].roi_lmbx & 0xFF) << 0 ) ++ ); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_ROI_POS_INFO6, 0, ++ ( (s->roi_info[6].roi_bmby & 0xFF) << 24 | ++ (s->roi_info[6].roi_umby & 0xFF) << 16 | ++ (s->roi_info[6].roi_rmbx & 0xFF) << 8 | ++ (s->roi_info[6].roi_lmbx & 0xFF) << 0 ) ++ ); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_ROI_POS_INFO7, 0, ++ ( (s->roi_info[7].roi_bmby & 0xFF) << 24 | ++ (s->roi_info[7].roi_umby & 0xFF) << 16 | ++ (s->roi_info[7].roi_rmbx & 0xFF) << 8 | ++ (s->roi_info[7].roi_lmbx & 0xFF) << 0 ) ++ ); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_QP_GEN_TAB, 0, ( (VRAM_QP_TAB_BA & 0xFFFFF) | ++ ((s->qp_tab_len & 0x7FF) << 20) | ++ (s->qp_tab_mode & 0x1)<<31) ); ++ /* ++ for(i=0; iqp_tab_len;i++){ ++ GEN_VDMA_ACFG(chn, VRAM_QP_TAB_BA+i*4, 0, *(s->qp_tab+i)); ++ } ++ */ ++ GEN_VDMA_ACFG(chn, REG_EFE_CQP_OFST, 0, (s->cqp_offset & 0x1F)); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_SSAD, 0, 0); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_DCS, 0, ++ ( EFE_DCS_EN(s->daisy_chain_en) | ++ EFE_DCS_OTH(s->curr_thread_id) | ++ EFE_DCS_RT(4) ) ++ ); ++ /* ++ GEN_VDMA_ACFG(chn, REG_EFE_QPG_CTRL , 0, (s->sas_en << 0 | ++ s->crp_en << 1 | ++ s->sas_mthd << 2 | ++ 0 << 3 | ++ s->rc_bu_level << 4 | ++ s->rc_wait_en << 7 | ++ s->base_qp << 8 | ++ s->rc_mb_level << 14 | ++ s->min_qp << 16 | ++ s->qp_tab_en << 22 | ++ s->mbrc_qpg_sel << 23 | // 0 : only mbrc_ofst valid; 1: both mbrc_ofst and qpg_ofst valid ++ s->max_qp << 24 | ++ s->mbrc_enable << 30 | ++ s->mbrc_wait << 31 )); ++ */ ++ GEN_VDMA_ACFG(chn, REG_EFE_QPG_CTRL , 0, (s->sas_en << 0 | ++ s->crp_en << 1 | ++ s->sas_mthd << 2 | ++ 0 << 3 | ++ s->rc_bu_level << 4 | ++ s->rc_bu_wait_en << 7 | ++ s->base_qp << 8 | ++ s->rc_mb_level << 14 | ++ s->min_qp << 16 | ++ s->qp_tab_en << 22 | ++ s->mbrc_qpg_sel << 23 |//0:mb_rc effect, 1:mb_rc + qpg effect ++ s->max_qp << 24 | ++ s->rc_mb_wait_en << 30 | ++ (s->rc_mb_en & 0x1) << 31 ));//mb_rc_en ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_QPG_CFG0, 0, ((s->qpg_flt_thd[0] & 0x7) << 0 | ++ (s->qpg_flt_thd[1] & 0x7) << 4 | ++ (s->qpg_flt_thd[2] & 0xF) << 8 | ++ (s->qpg_flt_thd[3] & 0x7) << 12 | ++ (s->qpg_flt_thd[4] & 0x7) << 16 )); ++ ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_QPG_CFG1 , 0, (s->qpg_mb_thd[0] << 0 | ++ s->qpg_mb_thd[1] << 16 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_QPG_CFG2 , 0, (s->qpg_mb_thd[2] << 0 | ++ s->qpg_mb_thd[3] << 16 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_QPG_CFG3 , 0, (s->qpg_mb_thd[4] << 0 | ++ s->qpg_mb_thd[5] << 16 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_QPG_CFG4 , 0, (s->qpg_mb_thd[6] << 0 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_QPG_CFG5 , 0, ((s->qpg_mbqp_ofst[0] & 0x3F) << 0 | ++ (s->qpg_mbqp_ofst[1] & 0x3F) << 8 | ++ (s->qpg_mbqp_ofst[2] & 0x3F) << 16 | ++ (s->qpg_mbqp_ofst[3] & 0x3F) << 24 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_QPG_CFG6 , 0, ((s->qpg_mbqp_ofst[4] & 0x3F) << 0 | ++ (s->qpg_mbqp_ofst[5] & 0x3F) << 8 | ++ (s->qpg_mbqp_ofst[6] & 0x3F) << 16 | ++ (s->qpg_mbqp_ofst[7] & 0x3F) << 24 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_EIGEN_CFG0 , 0, ((s->force_i16 & 0x1) << 0 | ++ (s->refresh_en & 0x1) << 1 | ++ (s->refresh_mode & 0x1) << 2 | ++ (s->refresh_bias & 0x7) << 3 | ++ (s->sas_eigen_en & 0x1) << 6 | ++ (s->crp_eigen_en & 0x1) << 7 | ++ (s->sas_eigen_dump & 0x1) << 8 | ++ (s->crp_eigen_dump & 0x1) << 9 | ++ (s->cplx_thd_sel & 0x1) << 10 | ++ (s->diff_cplx_sel & 0x1) << 11 | ++ (s->diff_thd_sel & 0x3) << 12 | ++ (s->mb_mode_use & 0x1) << 14 | ++ (s->rrs_en & 0x1) << 15 | ++ (s->refresh_cplx_thd & 0xFF) << 16 | ++ (s->i16dc_cplx_thd & 0xFF) << 24 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_EIGEN_CFG1 , 0, ((s->i16dc_qp_base & 0x3F) << 0 | ++ (s->i16dc_qp_sel & 0x1) << 6 | ++ (s->i16_qp_base & 0x3F) << 8 | ++ (s->i16_qp_sel & 0x1) << 14 | ++ (s->diff_qp_base[0] & 0x3F) << 16 | ++ (s->diff_qp_sel[0] & 0x1) << 22 | ++ (s->diff_qp_base[1] & 0x3F) << 24 | ++ (s->diff_qp_sel[1] & 0x1) << 30 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_EIGEN_CFG2 , 0, ((s->cplx_thd_idx[0] & 0x7) << 0 | ++ (s->cplx_thd_idx[1] & 0x7) << 3 | ++ (s->cplx_thd_idx[2] & 0x7) << 6 | ++ (s->cplx_thd_idx[3] & 0x7) << 9 | ++ (s->cplx_thd_idx[4] & 0x7) << 12 | ++ (s->cplx_thd_idx[5] & 0x7) << 15 | ++ (s->cplx_thd_idx[6] & 0x7) << 18 | ++ (s->cplx_thd_idx[7] & 0x7) << 21 | ++ (s->cplx_thd_idx[8] & 0x7) << 24 | ++ (s->cplx_thd_idx[9] & 0x7) << 27 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_EIGEN_CFG3 , 0, ((s->cplx_thd_idx[10] & 0x7) << 0 | ++ (s->cplx_thd_idx[11] & 0x7) << 3 | ++ (s->cplx_thd_idx[12] & 0x7) << 6 | ++ (s->cplx_thd_idx[13] & 0x7) << 9 | ++ (s->cplx_thd_idx[14] & 0x7) << 12 | ++ (s->cplx_thd_idx[15] & 0x7) << 15 | ++ (s->cplx_thd_idx[16] & 0x7) << 18 | ++ (s->cplx_thd_idx[17] & 0x7) << 21 | ++ (s->cplx_thd_idx[18] & 0x7) << 24 | ++ (s->cplx_thd_idx[19] & 0x7) << 27 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_EIGEN_CFG4 , 0, ((s->cplx_thd_idx[20] & 0x7) << 0 | ++ (s->cplx_thd_idx[21] & 0x7) << 3 | ++ (s->cplx_thd_idx[22] & 0x7) << 6 | ++ (s->cplx_thd_idx[23] & 0x7) << 9 | ++ (s->diff_cplx_thd & 0xFF) << 24 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_EIGEN_CFG5 , 0, ((s->cplx_thd[0] & 0xFF) << 0 | ++ (s->cplx_thd[1] & 0xFF) << 8 | ++ (s->cplx_thd[2] & 0xFF) << 16 | ++ (s->cplx_thd[3] & 0xFF) << 24 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_EIGEN_CFG6 , 0, ((s->cplx_thd[4] & 0xFF) << 0 | ++ (s->cplx_thd[5] & 0xFF) << 8 | ++ (s->cplx_thd[6] & 0xFF) << 16 | ++ (s->cplx_thd[7] & 0xFF) << 24 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_DIFFY_CFG , 0, ((s->diff_thd_base[0] & 0xFFFF) << 0 | ++ (s->diff_thd_ofst[0] & 0xFFFF) << 16 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_DIFFU_CFG , 0, ((s->diff_thd_base[1] & 0xFFFF) << 0 | ++ (s->diff_thd_ofst[1] & 0xFFFF) << 16 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_DIFFV_CFG , 0, ((s->diff_thd_base[2] & 0xFFFF) << 0 | ++ (s->diff_thd_ofst[2] & 0xFFFF) << 16 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_SKIN_CTRL , 0, ((s->skin_dt_en & 0x1) << 0 | ++ (s->skin_lvl & 0x3) << 1 | ++ (s->ncu_mov_en & 0x1) << 3 | ++ (s->skin_cnt_thd & 0x7F) << 8 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_SKIN_PTHD0 , 0, ((s->skin_pxlu_thd[0][0] & 0xFF) << 0 | ++ (s->skin_pxlu_thd[0][1] & 0xFF) << 8 | ++ (s->skin_pxlv_thd[0][0] & 0xFF) << 16 | ++ (s->skin_pxlv_thd[0][1] & 0xFF) << 24 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_SKIN_PTHD1 , 0, ((s->skin_pxlu_thd[1][0] & 0xFF) << 0 | ++ (s->skin_pxlu_thd[1][1] & 0xFF) << 8 | ++ (s->skin_pxlv_thd[1][0] & 0xFF) << 16 | ++ (s->skin_pxlv_thd[1][1] & 0xFF) << 24 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_SKIN_PTHD2 , 0, ((s->skin_pxlu_thd[2][0] & 0xFF) << 0 | ++ (s->skin_pxlu_thd[2][1] & 0xFF) << 8 | ++ (s->skin_pxlv_thd[2][0] & 0xFF) << 16 | ++ (s->skin_pxlv_thd[2][1] & 0xFF) << 24 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_SKIN_QP_OFST , 0, ((s->skin_qp_ofst[0] & 0x3F) << 0 | ++ (s->skin_qp_ofst[1] & 0x3F) << 8 | ++ (s->skin_qp_ofst[2] & 0x3F) << 16 | ++ (s->skin_qp_ofst[3] & 0x3F) << 24 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_SKIN_PARAM0 , 0, ((s->mult_factor[0] & 0xF) << 0 | ++ (s->shift_factor[0][0] & 0x7) << 4 | ++ (s->shift_factor[0][1] & 0x7) << 8 | ++ (s->skin_ofst[1] & 0x3FF) << 11 | ++ (s->skin_ofst[0] & 0x3FF) << 21 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_SKIN_PARAM1 , 0, ((s->mult_factor[1] & 0xF) << 0 | ++ (s->shift_factor[1][0] & 0x7) << 8 | ++ (s->shift_factor[1][1] & 0x7) << 12 | ++ (s->shift_factor[1][2] & 0x7) << 16 | ++ (s->skin_ofst[2] & 0x3FF) << 20 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_SKIN_PARAM2 , 0, ((s->mult_factor[2] & 0xF) << 0 | ++ (s->shift_factor[2][0] & 0x7) << 8 | ++ (s->shift_factor[2][1] & 0x7) << 12 | ++ (s->shift_factor[2][2] & 0x7) << 16 | ++ (s->skin_ofst[3] & 0x3FF) << 20 )); ++ ++ /************************************************** ++ RC configuration ++ *************************************************/ ++ if(s->rc_mb_en){ //rate ctrl ++ //fprintf(stderr,"s->rc_bu_wait_en:%d\n",s->rc_bu_wait_en); ++ //fprintf(stderr,"s->last_bu_size:%d, s->rc_bu_size:%d\n",s->last_bu_size, s->rc_bu_size); ++ GEN_VDMA_ACFG(chn, REG_EFE_RC_BINFO1, 0, EFE_RC_BU_LSIZE(s->last_bu_size) | EFE_RC_BU_SIZE(s->rc_bu_size)); ++ //fprintf(stderr,"s->tar_bs_thd[0]:%d, s->tar_bs_thd[1]:%d\n",s->tar_bs_thd[0],s->tar_bs_thd[1]); ++ GEN_VDMA_ACFG(chn, REG_EFE_RC_GP0THD, 0, ((s->tar_bs_thd[0] & 0xFFFF) << 0 | ++ (s->tar_bs_thd[1] & 0xFFFF) << 16)); ++ //fprintf(stderr,"s->tar_bs_thd[2]:%d, s->tar_bs_thd[3]:%d\n",s->tar_bs_thd[2],s->tar_bs_thd[3]); ++ GEN_VDMA_ACFG(chn, REG_EFE_RC_GP1THD, 0, ((s->tar_bs_thd[2] & 0xFFFF) << 0 | ++ (s->tar_bs_thd[3] & 0xFFFF) << 16)); ++ //fprintf(stderr,"s->tar_bs_thd[4]:%d, s->tar_bs_thd[5]:%d\n",s->tar_bs_thd[4],s->tar_bs_thd[5]); ++ GEN_VDMA_ACFG(chn, REG_EFE_RC_GP2THD, 0, ((s->tar_bs_thd[4] & 0xFFFF) << 0 | ++ (s->tar_bs_thd[5] & 0xFFFF) << 16)); ++ //fprintf(stderr,"s->rc_frm_tbs:%d\n",s->rc_frm_tbs & 0x7FFFFFFF); ++ GEN_VDMA_ACFG(chn, REG_EFE_RC_TBS, 0, s->rc_frm_tbs & 0x7FFFFFFF); ++ //fprintf(stderr,"s->bu_alg0_qpo[2]:%d, s->bu_alg0_qpo[1]:%d, s->bu_alg0_qpo[0]:%d\n",s->bu_alg0_qpo[2], s->bu_alg0_qpo[1], s->bu_alg0_qpo[0]); ++ GEN_VDMA_ACFG(chn, REG_EFE_RC_BNQA0, 0, EFE_RC_QPO_CFG(0, s->bu_alg0_qpo[2], s->bu_alg0_qpo[1], s->bu_alg0_qpo[0])); ++ //fprintf(stderr,"s->bu_alg0_qpo[5]:%d, s->bu_alg0_qpo[4]:%d, s->bu_alg0_qpo[3]:%d\n",s->bu_alg0_qpo[5], s->bu_alg0_qpo[4], s->bu_alg0_qpo[3]); ++ GEN_VDMA_ACFG(chn, REG_EFE_RC_BPQA0, 0, EFE_RC_QPO_CFG(0, s->bu_alg0_qpo[5], s->bu_alg0_qpo[4], s->bu_alg0_qpo[3])); ++ //fprintf(stderr,"s->bu_alg1_qpo[2]:%d, s->bu_alg1_qpo[1]:%d, s->bu_alg1_qpo[0]:%d\n",s->bu_alg1_qpo[2], s->bu_alg1_qpo[1], s->bu_alg1_qpo[0]); ++ GEN_VDMA_ACFG(chn, REG_EFE_RC_BNQA1, 0, EFE_RC_QPO_CFG(0, s->bu_alg1_qpo[2], s->bu_alg1_qpo[1], s->bu_alg1_qpo[0])); ++ //fprintf(stderr,"s->bu_alg1_qpo[5]:%d, s->bu_alg1_qpo[4]:%d, s->bu_alg1_qpo[3]:%d\n",s->bu_alg1_qpo[5], s->bu_alg1_qpo[4], s->bu_alg1_qpo[3]); ++ GEN_VDMA_ACFG(chn, REG_EFE_RC_BPQA1, 0, EFE_RC_QPO_CFG(0, s->bu_alg1_qpo[5], s->bu_alg1_qpo[4], s->bu_alg1_qpo[3])); ++ //fprintf(stderr,"s->mb_cs_qpo[2]:%d, s->mb_cs_qpo[1]:%d, s->mb_cs_qpo[0]:%d\n",s->mb_cs_qpo[2], s->mb_cs_qpo[1], s->mb_cs_qpo[0]); ++ GEN_VDMA_ACFG(chn, REG_EFE_RC_MNQCS, 0, EFE_RC_QPO_CFG(0, s->mb_cs_qpo[2], s->mb_cs_qpo[1], s->mb_cs_qpo[0])); ++ //fprintf(stderr,"s->mb_cs_qpo[6]:%d, s->mb_cs_qpo[5]:%d, s->mb_cs_qpo[4]:%d, s->mb_cs_qpo[3]:%d\n", ++ //s->mb_cs_qpo[6], s->mb_cs_qpo[5], s->mb_cs_qpo[4], s->mb_cs_qpo[3]); ++ GEN_VDMA_ACFG(chn, REG_EFE_RC_MPQCS, 0, EFE_RC_QPO_CFG(s->mb_cs_qpo[6], s->mb_cs_qpo[5], s->mb_cs_qpo[4], s->mb_cs_qpo[3])); ++ //fprintf(stderr,"s->mb_top_bs_qpo[1]:%d, s->mb_top_bs_qpo[0]:%d\n",s->mb_top_bs_qpo[1], s->mb_top_bs_qpo[0]); ++ GEN_VDMA_ACFG(chn, REG_EFE_RC_MTBQ, 0, EFE_RC_QPO_CFG(0, 0, s->mb_top_bs_qpo[1], s->mb_top_bs_qpo[0])); ++ //fprintf(stderr,"s->mb_rinfo_qpo[1]:%d, s->mb_rinfo_qpo[0]:%d\n",s->mb_rinfo_qpo[1], s->mb_rinfo_qpo[0]); ++ GEN_VDMA_ACFG(chn, REG_EFE_RC_MRFQ, 0, EFE_RC_QPO_CFG(0, 0, s->mb_rinfo_qpo[1], s->mb_rinfo_qpo[0])); ++ //fprintf(stderr,"s->mb_target_avg_bs[1]:%d, s->mb_target_avg_bs[0]:%d\n",s->mb_target_avg_bs[1], s->mb_target_avg_bs[0]); ++ GEN_VDMA_ACFG(chn, REG_EFE_RC_MAMIN, 0, s->mb_target_avg_bs[0] & 0x3FFFF); ++ GEN_VDMA_ACFG(chn, REG_EFE_RC_MAMAX, 0, s->mb_target_avg_bs[1] & 0x3FFFF); ++ //fprintf(stderr,"s->rc_bu_num:%d, s->mb_gp_num:%d\n",s->rc_bu_num, s->mb_gp_num); ++ GEN_VDMA_ACFG(chn, REG_EFE_RC_BBS, 0, s->avg_bu_bs & 0x7FFFFF); ++ GEN_VDMA_ACFG(chn, REG_EFE_RC_MINFO, 0, (//EFE_RC_MAD_CFG_RDY | ++ EFE_RC_MBGP_NUM(s->mb_gp_num) | ++ (s->rc_mb_en & 0x1))); ++ char rc_slice_type = s->rc_frm_tbs ? s->frame_type : 0; ++ GEN_VDMA_ACFG(chn, REG_EFE_RC_BINFO0, 0, (EFE_RC_SLICE_TP(rc_slice_type) | ++ EFE_RC_BU_CFG(s->rc_bcfg_mode) | ++ EFE_RC_BU_NUM(s->rc_bu_num) | ++ ((s->rc_mb_en>>1) & 0x1))); ++ } ++ ++ /************************************************** ++ JRFD configuration ++ *************************************************/ ++ GEN_VDMA_ACFG(chn, REG_JRFD_CTRL, 0, (((1==2)<<31) | /* 2:NV21 ,1:NV12*/ ++ (2 << 28) |//sim_lvl ++ (s->jrfd_enable << 27) | ++ (s->frame_height << 14) | ++ s->frame_width)); ++ GEN_VDMA_ACFG(chn, REG_JRFD_HDYA, 0, s->jh[1][0]); ++ GEN_VDMA_ACFG(chn, REG_JRFD_HDCA, 0, s->jh[1][1]); ++ ++ GEN_VDMA_ACFG(chn, REG_JRFD_HSTR, 0, (((s->cm_head_total & 0xffff) << 16) | (s->lm_head_total & 0xffff)) ); ++ ++ GEN_VDMA_ACFG(chn, REG_JRFD_BDYA, 0, s->fb[1][0]);//tile Y address ++ GEN_VDMA_ACFG(chn, REG_JRFD_BDCA, 0, s->fb[1][1]); //tile C address ++ ++ GEN_VDMA_ACFG(chn, REG_JRFD_BSTR, 0, ++ JRFD_BODY_STRDY(((s->frame_width+15)/16)*16) | ++ JRFD_BODY_STRDC(((s->frame_width+15)/16)*8) ); ++ ++ GEN_VDMA_ACFG(chn, REG_JRFD_MHDY, 0, s->jh[2][0]); ++ GEN_VDMA_ACFG(chn, REG_JRFD_MHDC, 0, s->jh[2][1]); ++ GEN_VDMA_ACFG(chn, REG_JRFD_MBDY, 0, s->fb[2][0]); ++ GEN_VDMA_ACFG(chn, REG_JRFD_MBDC, 0, s->fb[2][1]); ++ ++ GEN_VDMA_ACFG(chn, REG_JRFD_TRIG, 0, ((1 << 5) |//init ++ (0 << 4) //ckg low means do clock-gating ++ ));//enable_tile ++ ++ /************************************************** ++ Motion configuration ++ *************************************************/ ++ if(s->frame_type){ ++ //set CHAIN/TMV/SYNC ADDR ++ GEN_VDMA_ACFG(chn, REG_MCE_CHN_BA, 0, VRAM_ME_CHN_BASE);//chn ++ GEN_VDMA_ACFG(chn, REG_MCE_TMV_BA, 0, VRAM_TOPMV_BA);//tmv ++ GEN_VDMA_ACFG(chn, REG_MCE_CHN_SYNC, 0, VRAM_ME_DSA);//sync ++ ++ //set frame size ++ GEN_VDMA_ACFG(chn, REG_MCE_FRM_SIZE, 0, ++ MCE_FRM_SIZE_FH(s->frame_height-1) | ++ MCE_FRM_SIZE_FW(s->frame_width-1) | ++ MCE_FRM_SIZE_LRE(s->frm_re[0]) | ++ MCE_FRM_SIZE_RRE(s->frm_re[1]) | ++ MCE_FRM_SIZE_TRE(s->frm_re[2]) | ++ MCE_FRM_SIZE_BRE(s->frm_re[3]) ); ++ ++ //set frame stride ++ GEN_VDMA_ACFG(chn, REG_MCE_FRM_STRD, 0, ++ MCE_FRM_STRD_STRDC(((s->frame_width+15)/16)*16) | ++ MCE_FRM_STRD_STRDY(((s->frame_width+15)/16)*16) ); ++ ++ //set COMP_CTRL ++ GEN_VDMA_ACFG(chn, REG_MCE_COMP_CTRL, 0, ++ MCE_COMP_CTRL_CCE | ++ MCE_COMP_CTRL_CTAP(MCE_TAP_TAP2) | ++ MCE_COMP_CTRL_CSPT(MCE_SPT_BILI) | ++ MCE_COMP_CTRL_CSPP(MCE_SPP_EPEL) | ++ MCE_COMP_CTRL_YCE | ++ MCE_COMP_CTRL_YTAP(MCE_TAP_TAP6) | ++ MCE_COMP_CTRL_YSPT(MCE_SPT_AUTO) | ++ MCE_COMP_CTRL_YSPP(MCE_SPP_QPEL) ); ++ ++ //set ESTI_CTRL ++ unsigned int esti_ctrl = 0; ++ esti_ctrl |= (MCE_ESTI_CTRL_LSP(s->lambda_scale_parameter) | ++ MCE_ESTI_CTRL_SCL(s->scl)/*trbl mvp*/ | ++ MCE_ESTI_CTRL_FBG(0) | ++ MCE_ESTI_CTRL_CLMV | ++ MCE_ESTI_CTRL_MSS(s->max_sech_step_i) | ++ MCE_ESTI_CTRL_QRL(s->qpel_en) | ++ MCE_ESTI_CTRL_HRL(s->hpel_en) ); ++ ++ esti_ctrl |= MCE_ESTI_CTRL_PUE_16X16; ++ ++ GEN_VDMA_ACFG(chn, REG_MCE_ESTI_CTRL, 0, esti_ctrl); ++ ++ //set MRGI ++ unsigned int merg_info = 0; ++ GEN_VDMA_ACFG(chn, REG_MCE_MRGI, 0, merg_info); ++ ++ //set MVR ++ GEN_VDMA_ACFG(chn, REG_MCE_MVR, 0, ++ MCE_MVR_MVRY(s->max_mvry_i*4) | ++ MCE_MVR_MVRX(s->max_mvrx_i*4) ); ++ if(s->buf_share_en){ ++ GEN_VDMA_ACFG(chn, REG_MCE_REFY0, 0, refy_addr_ba0); ++ GEN_VDMA_ACFG(chn, REG_MCE_REFC0, 0, refc_addr_ba0); ++ GEN_VDMA_ACFG(chn, REG_MCE_REFY0_1, 0, refy_addr_ba1); ++ GEN_VDMA_ACFG(chn, REG_MCE_REFC0_1, 0, refc_addr_ba1); ++ } ++ else { ++ GEN_VDMA_ACFG(chn, REG_MCE_REFY0, 0, s->fb[1][0]); ++ GEN_VDMA_ACFG(chn, REG_MCE_REFC0, 0, s->fb[1][1]); ++ GEN_VDMA_ACFG(chn, REG_MCE_REFY0_1, 0, s->fb[3][0]); ++ GEN_VDMA_ACFG(chn, REG_MCE_REFC0_1, 0, s->fb[3][1]); ++ } ++ GEN_VDMA_ACFG(chn, REG_MCE_REFY1, 0, s->fb[2][0]); ++ GEN_VDMA_ACFG(chn, REG_MCE_REFC1, 0, s->fb[2][1]); ++ ++ GEN_VDMA_ACFG(chn, REG_MCE_SLC_SPOS, 0, 0); ++ GEN_VDMA_ACFG(chn, REG_MCE_FSC, 0, ++ MCE_FSC_FSE(s->fs_en) | ++ MCE_FSC_FSMD(s->fs_md) | ++ MCE_FSC_PERX(s->fs_px) | ++ MCE_FSC_PERY(s->fs_py) | ++ MCE_FSC_RECX(s->fs_rx) | ++ MCE_FSC_RECY(s->fs_ry) ++ ); ++ GEN_VDMA_ACFG(chn, REG_MCE_GLB_MV, 0, MCE_GLB_MVX(s->glb_mvx) | MCE_GLB_MVY(s->glb_mvy)); ++ /**/ ++ GEN_VDMA_ACFG(chn, REG_MCE_GLB_CTRL, 0, (MCE_GLB_CTRL_FMV0(s->force_mv0_en) | ++ MCE_GLB_CTRL_MSTEP(s->me_step_en) | ++ MCE_GLB_CTRL_STEP1(s->me_step_1) | ++ MCE_GLB_CTRL_STEP0(s->me_step_0) | ++ MCE_GLB_CTRL_RBS(ref_mby_size) | ++ MCE_GLB_CTRL_FMS(s->frm_mv_size) | ++ MCE_GLB_CTRL_FRMMV(s->frm_mv_en) | ++ MCE_GLB_CTRL_GLBMV(s->glb_mv_en) | ++ MCE_GLB_CTRL_DCT8(s->dct8x8_en) | ++ MCE_GLB_CTRL_PSKIP(s->pskip_en) | MCE_GLB_CTRL_INIT | ++ MCE_GLB_CTRL_MREF(s->mref_en) | MCE_GLB_CTRL_RM(s->ref_mode) | ++ MCE_GLB_CTRL_JRFD(!s->jrfd_enable))); ++ } ++ /************************************************** ++ VMAU configuration ++ *************************************************/ ++ GEN_VDMA_ACFG(chn, REG_VMAU_GBL_RUN, 0, VMAU_RESET); ++ GEN_VDMA_ACFG(chn, REG_VMAU_VIDEO_TYPE, 0, (VMAU_MODE_ENC | 6<<7 ++ | VMAU_I4_MSK(0) ++ | VMAU_I16_MSK(0) ++ | VMAU_I8_MSK(0) ++ | VMAU_PT8_MSK(0) ++ | VMAU_IS_ISLICE(!s->frame_type) ++ | VMAU_PREDM_MSK(s->intra_mode_msk & 0x1ffff) ++ | VMAU_TSE(s->use_intra_in_pframe)) ); ++ GEN_VDMA_ACFG(chn, REG_VMAU_NCCHN_ADDR, 0, VRAM_MAU_CHN_BASE); ++ GEN_VDMA_ACFG(chn, REG_VMAU_ENC_DONE, 0, VRAM_MAU_ENC_SYNA); ++ GEN_VDMA_ACFG(chn, REG_VMAU_DEC_DONE, 0, VRAM_MAU_DEC_SYNA); ++ GEN_VDMA_ACFG(chn, REG_VMAU_Y_GS, 0, (VMAU_FRM_WID(MB_WID*16) ++ | VMAU_FRM_HEI(MB_HEI*16)) ); ++ GEN_VDMA_ACFG(chn, REG_VMAU_GBL_CTR, 0, (VMAU_CTRL_TO_DBLK ++ | VMAU_CTRL_FIFO_M ++ | VMAU_LAMBDA_THRETH((s->intra_mode_msk >> 17) & 0x3) ) ); ++ GEN_VDMA_ACFG(chn, REG_VMAU_DEADZONE, 0, ( VMAU_DEADZONE0_IY(s->deadzone[0]) ++ | VMAU_DEADZONE1_PY(s->deadzone[1]) ++ | VMAU_DEADZONE2_IC(s->deadzone[2]) ++ | VMAU_DEADZONE3_PC(s->deadzone[3]) ) ); ++ GEN_VDMA_ACFG(chn, REG_VMAU_DEADZONE1, 0, ((s->deadzone[4] & 0x3f) << 0 | ++ (s->deadzone[5] & 0x3f) << 6 | ++ (s->deadzone[6] & 0x3f) << 12 | ++ (s->deadzone[7] & 0x3f) << 18 | ++ (s->deadzone[8] & 0x3f) << 24)); ++ GEN_VDMA_ACFG(chn, REG_VMAU_TOP_BASE, 0, VRAM_TOPPA_BA ); ++ GEN_VDMA_ACFG(chn, REG_VMAU_MD_CFG0, 0, ( VMAU_MD_SLICE_I(!s->frame_type) ++ | VMAU_MD_SLICE_P(s->frame_type) ++ | VMAU_MD_I4_DIS(0) ++ | VMAU_MD_I16_DIS(0) ++ | VMAU_MD_PSKIP_DIS(0) ++ | VMAU_MD_P_L0_DIS(0) ++ | VMAU_MD_I8_DIS(0) ++ | VMAU_MD_PT8_DIS(0) ++ | VMAU_MD_DREF_EN(s->mref_en) ++ | VMAU_MD_DCT8_EN(s->dct8x8_en) ++ | VMAU_MD_FRM_REDGE(MB_WID - 1) ++ | VMAU_MD_FRM_BEDGE(MB_HEI - 1) ) ); ++ GEN_VDMA_ACFG(chn, REG_VMAU_MD_CFG1, 0, ( VMAU_IPMY_BIAS_EN(s->intra_lambda_y_bias_en) ++ | VMAU_IPMC_BIAS_EN(s->intra_lambda_c_bias_en) ++ | VMAU_COST_BIAS_EN(s->cost_bias_en) ++ | VMAU_CSSE_BIAS_EN(s->chroma_sse_bias_en) ++ | VMAU_JMLAMBDA2_EN(s->jm_lambda2_en) ++ | VMAU_INTER_NEI_EN(s->inter_nei_en) ++ | VMAU_SKIP_BIAS_EN(s->skip_bias_en) ++ | VMAU_LMD_BIAS_EN(s->sse_lambda_bias_en) ++ | VMAU_INFO_EN(s->info_en) ++ | VMAU_DCM_EN(s->dcm_en) ++ | VMAU_MVDS_ALL(s->mvd_sum_all) ++ | VMAU_MVDS_ABS(s->mvd_sum_abs) ++ | VMAU_MVS_ALL(s->mv_sum_all) ++ | VMAU_MVS_ABS(s->mv_sum_abs) ++ | VMAU_P_L0_BIAS(s->cost_bias_p_l0) ++ | VMAU_PSKIP_BIAS(s->cost_bias_p_skip) ++ | VMAU_I4_BIAS(s->cost_bias_i_4x4) ++ | VMAU_I16_BIAS(s->cost_bias_i_16x16) ) ); ++ GEN_VDMA_ACFG(chn, REG_VMAU_MD_CFG2, 0, ( VMAU_IPM_BIAS_0(s->intra_lambda_bias_0) ++ | VMAU_IPM_BIAS_1(s->intra_lambda_bias_1) ++ | VMAU_IPM_BIAS_2(s->intra_lambda_bias_2) ++ | VMAU_IPM_BIAS_QP0(s->intra_lambda_bias_qp0) ++ | VMAU_IPM_BIAS_QP1(s->intra_lambda_bias_qp1) ++ | VMAU_MD_FBC_EP(s->fbc_ep) ) ); ++ GEN_VDMA_ACFG(chn, REG_VMAU_MD_CFG3, 0, ( VMAU_CSSE_BIAS_0(s->chroma_sse_bias_0) ++ | VMAU_CSSE_BIAS_1(s->chroma_sse_bias_1) ++ | VMAU_CSSE_BIAS_2(s->chroma_sse_bias_2) ++ | VMAU_CSSE_BIAS_QP0(s->chroma_sse_bias_qp0) ++ | VMAU_CSSE_BIAS_QP1(s->chroma_sse_bias_qp1) ++ | VMAU_LMD_BIAS(s->sse_lambda_bias) ++ | VMAU_PL0_FS_DIS(s->p_skip_pl0f_dis) ++ | VMAU_PT8_FS_DIS(s->p_skip_pt8f_dis) ++ | VMAU_PL0_COST_MAX(s->p_l0_dis) ++ | VMAU_PT8_COST_MAX(s->p_t8_dis) ++ ) ); ++ GEN_VDMA_ACFG(chn, REG_VMAU_MD_CFG4, 0, ( VMAU_YSSE_THR(s->ysse_thr) ++ | VMAU_I8_BIAS(s->cost_bias_i_8x8) ++ | VMAU_PT8_BIAS(s->cost_bias_p_t8) ++ ) ); ++ GEN_VDMA_ACFG(chn, REG_VMAU_MD_CFG5, 0, ( VMAU_CSSE_THR(s->csse_thr) ++ | VMAU_CQP_OFFSET(s->cqp_offset) ++ | VMAU_I4_COST_MAX(s->i_4x4_dis) ++ | VMAU_I8_COST_MAX(s->i_8x8_dis) ++ | VMAU_I16_COST_MAX(s->i_16x16_dis) ++ ) ); ++ GEN_VDMA_ACFG(chn, REG_VMAU_MD_CFG6, 0, ( VMAU_DCM_PARAM(s->dcm_param) ++ | VMAU_SDE_PRIOR(s->sde_prior) ++ | VMAU_DB_PRIOR(s->db_prior) ++ ) ); ++ GEN_VDMA_ACFG(chn, REG_VMAU_MD_CFG7, 0, ( VMAU_CFG_SIZE_X(s->cfg_size_x) ++ | VMAU_CFG_SIZE_Y(s->cfg_size_y) ++ | VMAU_CFG_IW_THR(s->cfg_iw_thr) ++ | VMAU_CFG_BASEQP(s->base_qp) ++ | VMAU_CFG_ALPHA(s->alpha_c0_offset) ++ | VMAU_PS_COST_MAX(s->p_skip_dis) ++ ) ); ++ GEN_VDMA_ACFG(chn, REG_VMAU_MD_CFG8, 0, ( VMAU_CFG_MVR_THR1(s->cfg_mvr_thr1) ++ | VMAU_CFG_MVR_THR2(s->cfg_mvr_thr2) ) ); ++ GEN_VDMA_ACFG(chn, REG_VMAU_MD_CFG9, 0, ( VMAU_CFG_MVR_THR3(s->cfg_mvr_thr3) ++ | VMAU_CFG_BETA(s->beta_offset) ++ ) ); ++ ++ /* eigen leverages mode decision */ ++ int set_modectrl_bit0 = s->mb_mode_use & 0x1; ++ int set_modectrl_bit2 = s->rrs_en || s->force_i16 || s->refresh_en; ++ GEN_VDMA_ACFG(chn, REG_VMAU_MD_CFG11, 0, ( VMAU_CFG_MD_RBIAS(s->refresh_bias) ++ | VMAU_CFG_MD_RBIAS_EN(1) ++ | VMAU_CFG_MD_PCDC_N0(s->mode_ctrl >> 3 & 7) ++ | VMAU_CFG_MD_IFA_VLD(set_modectrl_bit2) ++ | VMAU_CFG_MD_SLV_VLD(0) ++ | VMAU_CFG_MD_SET_VLD((s->mode_ctrl & 0x2) || set_modectrl_bit0) ++ ) ); ++ ++ GEN_VDMA_ACFG(chn, REG_VMAU_ACMASK, 0, (s->acmask_mode<<14) + 2 ); /* 2 for TEST: rd file */ ++ ++ for (j = 0; j < 40; ++j) ++ GEN_VDMA_ACFG(chn, REG_VMAU_MD_MODE, 0, s->mode_ctrl_param[j] ); ++ ++ for (j = 0; j < 42; j++) ++ GEN_VDMA_ACFG(chn, REG_VMAU_CTX, 0, s->state[ j<10 ? ( !s->frame_type ? j+3 : j+14 ) ++ : j<22 ? j-10+73 ++ : j<28 ? j-22+64 : j-28+40 ] ); ++ ++ for( j = 0; j < 225; j++) ++ GEN_VDMA_ACFG(chn, REG_VMAU_CTX_CFBC, 0, s->state[ j<4 ? j+85 : //LUMA_DC_SIGNCG ++ j<19 ? j-4+105 : //LUMA_DC_SIGN ++ j<34 ? j-19+166 : //LUMA_DC_LAST ++ j<44 ? j-34+227 : //LUMA_DC_LEVEL ++ j<48 ? j-44+89 : //LUMA_AC_SIGNCG ++ j<62 ? j-48+120 : //LUMA_AC_SIGN ++ j<76 ? j-62+181 : //LUMA_AC_LAST ++ j<86 ? j-76+237 : //LUMA_AC_LEVEL ++ j<90 ? j-86+93 : //LUMA_44_SIGNCG ++ j<105 ? j-90+134 : //LUMA_44_SIGN ++ j<120 ? j-105+195 : //LUMA_44_LAST ++ j<130 ? j-120+247 : //LUMA_44_LEVEL ++ j<134 ? j-130+97 : //CHROMA_DC_SIGNCG ++ j<137 ? j-134+149 : //CHROMA_DC_SIGN ++ j<140 ? j-137+210 : //CHROMA_DC_LAST ++ j<149 ? j-140+257 : //CHROMA_DC_LEVEL ++ j<153 ? j-149+101 : //CHROMA_AC_SIGNCG ++ j<167 ? j-153+152 : //CHROMA_AC_SIGN ++ j<181 ? j-167+213 : //CHROMA_AC_LAST ++ j<191 ? j-181+266 : //CHROMA_AC_LEVEL ++ j<206 ? j-191+402 : //LUMA_88_SIGN ++ j<215 ? j-206+417 : //LUMA_88_LAST ++ j-215+426 //LUMA_88_LEVEL ++ ] ); ++ ++ ++ ++#if 0 ++ for(j=0; j<4; j++){ ++ for(i=0; i<4; i++){ ++ GEN_VDMA_ACFG(chn, REG_VMAU_QT+tmp, 0, *(int *)(&s->scaling_list[j][i*4]) ); ++ tmp += 4; ++ } ++ } ++ for(j=0; j<4; j++){ ++ for (i=0; i<8; i++){ ++ int tmp0 = (1ULL << 8) / s->scaling_list[j][2*i]; ++ int tmp1 = (1ULL << 8) / s->scaling_list[j][2*i+1]; ++ GEN_VDMA_ACFG(chn, REG_VMAU_QT+tmp, 0, ((tmp0 & 0xFFFF) | (tmp1<<16)) ); ++ tmp += 4; ++ } ++ } ++#endif ++ GEN_VDMA_ACFG(chn, REG_VMAU_IPRED_CFG0, 0, (VMAU_IP_MD_VAL(s->force_i16dc) | ++ VMAU_IP_REF_NEB_4(s->ref_neb_4) | ++ VMAU_IP_REF_NEB_8(s->ref_neb_8) | ++ VMAU_IP_REF_PRD_C(s->pri_uv) | ++ VMAU_IP_REF_PRD_16(s->pri_16) | ++ VMAU_IP_REF_PRD_8(s->pri_8) | ++ VMAU_IP_REF_PRD_4(s->pri_4) | ++ VMAU_IP_REF_C4_EN(s->c_4_en) | ++ VMAU_IP_REF_C8_EN(s->c_8_en) | ++ VMAU_IP_REF_C16_EN(s->c_16_en) | ++ VMAU_IP_REF_CUV_EN(s->c_uv_en) | ++ VMAU_IP_REF_LMD4_EN(s->lamb_4_en) | ++ VMAU_IP_REF_LMD8_EN(s->lamb_8_en) | ++ VMAU_IP_REF_LMD16_EN(s->lamb_16_en) | ++ VMAU_IP_REF_LMDUV_EN(s->lamb_uv_en) | ++ VMAU_IP_REF_BIT4_EN(s->bit_4_en) | ++ VMAU_IP_REF_BIT8_EN(s->bit_8_en) | ++ VMAU_IP_REF_BIT16_EN(s->bit_16_en) | ++ VMAU_IP_REF_BITUV_EN(s->bit_uv_en) ) ); ++ GEN_VDMA_ACFG(chn, REG_VMAU_IPRED_CFG1, 0, (VMAU_IP_REF_4_BIT0(s->bit_4[0]) | ++ VMAU_IP_REF_4_BIT1(s->bit_4[1]) | ++ VMAU_IP_REF_4_BIT2(s->bit_4[2]) | ++ VMAU_IP_REF_4_BIT3(s->bit_4[3]) | ++ VMAU_IP_REF_8_BIT0(s->bit_8[0]) | ++ VMAU_IP_REF_8_BIT1(s->bit_8[1]) | ++ VMAU_IP_REF_8_BIT2(s->bit_8[2]) | ++ VMAU_IP_REF_8_BIT3(s->bit_8[3]) ) ); ++ GEN_VDMA_ACFG(chn, REG_VMAU_IPRED_CFG2, 0, (VMAU_IP_REF_C_BIT0(s->bit_uv[0]) | ++ VMAU_IP_REF_C_BIT1(s->bit_uv[1]) | ++ VMAU_IP_REF_C_BIT2(s->bit_uv[2]) | ++ VMAU_IP_REF_C_BIT3(s->bit_uv[3]) | ++ VMAU_IP_REF_16_BIT0(s->bit_16[0]) | ++ VMAU_IP_REF_16_BIT1(s->bit_16[1]) | ++ VMAU_IP_REF_16_BIT2(s->bit_16[2]) | ++ VMAU_IP_REF_16_BIT3(s->bit_16[3]) ) ); ++ GEN_VDMA_ACFG(chn, REG_VMAU_IPRED_CFG3, 0, (VMAU_IP_REF_LMDUV_IFO(s->lambda_infouv) | ++ VMAU_IP_REF_LMD16_IFO(s->lambda_info16) | ++ VMAU_IP_REF_LMD8_IFO(s->lambda_info8) | ++ VMAU_IP_REF_LMD4_IFO(s->lambda_info4) | ++ VMAU_IP_REF_NEB_4REF(s->ref_4) | ++ VMAU_IP_REF_NEB_8REF(s->ref_8) ) ); ++ GEN_VDMA_ACFG(chn, REG_VMAU_IPRED_CFG4, 0, (VMAU_IP_REF_C4_IFO((s->const_4[0]<<0) | ++ (s->const_4[1]<<4) | ++ (s->const_4[2]<<8) | ++ (s->const_4[3]<<12) ) | ++ VMAU_IP_REF_C8_IFO((s->const_8[0]<<0) | ++ (s->const_8[1]<<4) | ++ (s->const_8[2]<<8) | ++ (s->const_8[3]<<12) ) ) ); ++ GEN_VDMA_ACFG(chn, REG_VMAU_IPRED_CFG5, 0, (VMAU_IP_REF_C16_IFO((s->const_16[0]<<0) | ++ (s->const_16[1]<<4) | ++ (s->const_16[2]<<8) | ++ (s->const_16[3]<<12) ) | ++ VMAU_IP_REF_CUV_IFO((s->const_uv[0]<<0) | ++ (s->const_uv[1]<<4) | ++ (s->const_uv[2]<<8) | ++ (s->const_uv[3]<<12) ) ) ); ++ ++ ++ if (1) { //configure scalinglist8 ++ uint8_t scaling_list_z[2][64]; ++ int kk, jj; ++ for (kk = 0; kk < 2; kk++) { ++ for (jj = 0; jj < 64; jj++) { ++ int jj_x = jj%8; //0 ~ 7 ++ int jj_y = jj/8; //0 ~ 7 ++ int jj_xx = jj_x%4; //0~3 ++ int jj_xy = jj_x/4; //0~1 ++ int jj_yx = jj_y%4; //0~3 ++ int jj_yy = jj_y/4; //0~1 ++ int zz = 16 * (jj_yy*2 + jj_xy) + 4*jj_yx + jj_xx; ++ scaling_list_z[kk][zz] = s->scaling_list8[kk][jj]; ++ } ++ } ++ int ofst = 0 ; ++ for (kk = 0; kk < 2; kk++) { ++ for (jj = 0; jj < 32; jj++) { ++#ifdef __KERNEL__ ++ unsigned long long t = 1ULL << 12; ++ do_div(t, scaling_list_z[kk][2*jj + 0]); ++ int t0 = (int)t; ++ ++ t = 1ULL << 12; ++ do_div(t, scaling_list_z[kk][2*jj + 1]); ++ int t1 = (int)t; ++#else ++ int t0 = (1ULL << 12)/scaling_list_z[kk][2*jj+0]; ++ int t1 = (1ULL << 12)/scaling_list_z[kk][2*jj+1]; ++#endif ++ int tt = ((t0 & 0xfff) | ++ (t1 & 0xfff) << 12); ++ GEN_VDMA_ACFG(chn, (VPU_BASE | 0x80800) + ofst, 0, tt ); ++ ++ ofst += 4; ++ } ++ } ++ for (kk = 0; kk < 2; kk++) { ++ for (jj = 0; jj < 16; jj++) { ++ int t0 = scaling_list_z[kk][4*jj+0]; ++ int t1 = scaling_list_z[kk][4*jj+1]; ++ int t2 = scaling_list_z[kk][4*jj+2]; ++ int t3 = scaling_list_z[kk][4*jj+3]; ++ int tt = ((t0 & 0x3f) | ++ (t1 & 0x3f) << 6 | ++ (t2 & 0x3f) << 12 | ++ (t3 & 0x3f) << 18); ++ GEN_VDMA_ACFG(chn, (VPU_BASE | 0x80800) + ofst, 0, tt ); ++ ofst += 4; ++ } ++ } ++ } ++ ++ GEN_VDMA_ACFG(chn, REG_VMAU_GBL_RUN, 0, VMAU_RUN ); ++ ++ /************************************************** ++ DBLK configuration ++ *************************************************/ ++#if 0 ++ GEN_VDMA_ACFG(chn, REG_DBLK_TRIG, 0, DBLK_RESET); ++ GEN_VDMA_ACFG(chn, REG_DBLK_DHA, 0, VRAM_DBLK_CHN_BASE); ++ GEN_VDMA_ACFG(chn, REG_DBLK_GENDA, 0, VRAM_DBLK_CHN_SYNA); ++ GEN_VDMA_ACFG(chn, REG_DBLK_GSIZE, 0, DBLK_GSIZE(MB_HEI, MB_WID) ); ++ GEN_VDMA_ACFG(chn, REG_DBLK_GPOS, 0, DBLK_GPOS(s->first_mby, 0) ); ++ GEN_VDMA_ACFG(chn, REG_DBLK_CTRL, 0, DBLK_CTRL(0, s->rotate, s->deblock) ); ++ GEN_VDMA_ACFG(chn, REG_DBLK_GPIC_YA, 0, s->fb[0][0]/* - (MB_WID+3)*256*/); ++ GEN_VDMA_ACFG(chn, REG_DBLK_GPIC_CA, 0, s->fb[0][1]/* - (MB_WID+3)*128*/); ++ GEN_VDMA_ACFG(chn, REG_DBLK_GP_ENDA, 0, VRAM_DBLK_DOUT_SYNA); ++ GEN_VDMA_ACFG(chn, REG_DBLK_GPIC_STR, 0, DBLK_GPIC_STR(MB_WID*128, MB_WID*256) ); ++ GEN_VDMA_ACFG(chn, REG_DBLK_VTR, 0, DBLK_VTR(s->beta_offset, s->alpha_c0_offset, 0, 0, ++ s->frame_type, DBLK_FMT_H264) ); ++ GEN_VDMA_ACFG(chn, REG_DBLK_TRIG, 0, DBLK_SLICE_RUN); ++ //mosaic ++ GEN_VDMA_ACFG(chn, REG_DBLK_MOS_CFG, 0, ( ((s->mos_sthd[1] & 0xF) << 28) | ++ ((s->mos_sthd[0] & 0xF) << 24) | ++ ((s->mos_gthd[1] & 0xFF) << 16) | ++ ((s->mos_gthd[0] & 0xFF) << 8) | ++ (s->mosaic_en & 0x1) ) ); ++ GEN_VDMA_ACFG(chn, REG_DBLK_MOS_ADDR, 0, DBLK_MOS_BASE_ADDR); ++#else ++ GEN_VDMA_ACFG(chn, REG_DBLK_CFG, 0, ( DBLK_CFG_ALPHA(s->alpha_c0_offset + 12) ++ | DBLK_CFG_BETA(s->beta_offset + 12) ++ | DBLK_CFG_NO_LFT(!s->deblock) ) ); ++ GEN_VDMA_ACFG(chn, REG_DBLK_TRIG, 0, DBLK_SLICE_RUN); ++#endif ++ /************************************************** ++ SDE configuration ++ *************************************************/ ++ GEN_VDMA_ACFG(chn, REG_SDE_STAT, 0, 0); ++ GEN_VDMA_ACFG(chn, REG_SDE_GL_CTRL, 0, (SDE_MODE_STEP | SDE_EN) ); ++ GEN_VDMA_ACFG(chn, REG_SDE_SL_GEOM, 0, SDE_SL_GEOM(MB_HEI, MB_WID, ++ s->first_mby, 0) ); ++ GEN_VDMA_ACFG(chn, REG_SDE_CODEC_ID, 0, SDE_FMT_H264_ENC); ++ //slice_info0 {desp_link_en[1], auto_syn_en[0]} ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG0, 0, 0x3); ++ //slice_info1 {qp[8], slice_type[0]} ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG1, 0, ((s->qp << 8) | ++ (s->bs_head_en << 20) |//rbsp enable ++ (s->bs_rbsp_en << 7) |//rbsp enable ++ (s->mref_en << 6) | /*dual-ref enable*/ ++ (s->dct8x8_en << 5) | /*dct8x8 enable*/ ++ (s->skip_en << 4) | ++ (s->frame_type + 1)) ); ++ //desp_addr ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG2, 0, VRAM_SDE_CHN_BASE); ++ //sync_addr ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG3, 0, VRAM_SDE_SYNA); ++ //bs_addr ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG4, 0, s->bs); ++ //context table ++ for(i=0; i<460; i++){ ++ int idx = s->state[i]; ++ if(idx <= 63) ++ idx = 63 - idx; ++ else ++ idx -= 64; ++ GEN_VDMA_ACFG(chn, REG_SDE_CTX_TBL+i*4, 0, ++ (lps_range[idx] | ((s->state[i]>>6) & 0x1)) ); ++ } ++ //init sync ++ GEN_VDMA_ACFG(chn, REG_SDE_SL_CTRL, 0, SDE_SLICE_INIT); ++ /************************************************** ++ EMC init ++ *************************************************/ ++ char use_ddr_slow_mode=0; ++ if((((s->frame_width+15)/16)-1)>32) ++ use_ddr_slow_mode = 0; ++ else ++ use_ddr_slow_mode = 1; ++ ++ GEN_VDMA_ACFG(chn, REG_EMC_FRM_SIZE, 0, ++ (0x0) << 20 | //bs_full intc before slice end ++ (s->bs_size_en) << 19 | //bs space ctrl by bs_size ++ use_ddr_slow_mode << 18 | //ddr use slow mode ++ (s->qp_tab_en & 0x1) << 17 | //qp table en ++ //(s->i_4x4_dis & 0x1) << 16 | //4x4 close ++ (((s->frame_height+15)/16)-1) << 8 | ++ (((s->frame_width+15)/16)-1) ); ++ GEN_VDMA_ACFG(chn, REG_EMC_BS_ADDR, 0, VDMA_ACFG_DHA(s->emc_bs_pa)); ++ GEN_VDMA_ACFG(chn, REG_EMC_DBLK_ADDR, 0, VDMA_ACFG_DHA(s->emc_dblk_pa)); ++ GEN_VDMA_ACFG(chn, REG_EMC_RECON_ADDR, 0, VDMA_ACFG_DHA(s->emc_recon_pa)); ++ GEN_VDMA_ACFG(chn, REG_EMC_MV_ADDR, 0, VDMA_ACFG_DHA(s->emc_mv_pa)); ++ GEN_VDMA_ACFG(chn, REG_EMC_SE_ADDR, 0, VDMA_ACFG_DHA(s->emc_se_pa)); ++ ++ ++ if((s->rc_mb_en & 0x1) && s->frame_type){//mb_rc+bu_rc or only mb_rc ++ for(i=0;imb_gp_num;i++){ ++ ++ int mb_gp_wth = (s->mb_width + 1) / 2; ++ int mb_gp_wth_for_bu = mb_gp_wth << (s->rc_bu_level - 1); ++ uint32_t r_idx = i; ++ uint32_t bdry_2algn = (s->mb_width % 2) == 0; ++ uint32_t mb_rinfo0_valid = 1; ++ uint32_t mb_rinfo1_valid = !bdry_2algn && ((r_idx % mb_gp_wth) == (mb_gp_wth-1)) ? 0 : 1; ++ uint32_t bu_rinfo_valid = (r_idx % mb_gp_wth_for_bu) == (mb_gp_wth_for_bu-1) ? 1 : 0; ++ uint32_t bu_rinfo_idx = r_idx / mb_gp_wth_for_bu; ++ uint32_t bdry_n2algn_num; ++ if(bdry_2algn) ++ bdry_n2algn_num = 0; ++ else ++ bdry_n2algn_num = r_idx / ((s->mb_width+1)/2); ++ ++ uint32_t mb_ref_info0 = s->mb_ref_info[r_idx*2 - bdry_n2algn_num] & 0x7fff; ++ uint32_t mb_ref_info1 = s->mb_ref_info[r_idx*2+1 - bdry_n2algn_num] & 0x7fff; ++ uint32_t mb_rinfo0 = (mb_rinfo0_valid<<15) | mb_ref_info0; ++ uint32_t mb_rinfo1 = (mb_rinfo1_valid<<31) | (mb_ref_info1<<16); ++ uint32_t bu_rinfo = (bu_rinfo_valid<<31) | (s->bu_ref_info[bu_rinfo_idx] & 0x7fffffff); ++ //fprintf(stderr,"i:%d,mb_ref_info0:0x%x,mb_ref_info1:0x%x,s->bu_ref_info:0x%x\n",i,mb_ref_info0,mb_ref_info1,s->bu_ref_info[bu_rinfo_idx] & 0x7fffffff); ++ //fprintf(stderr,"s->mb_width:%d, mb_gp_wth:%d, s->rc_bu_level:%d, mb_gp_wth_for_bu:%d, r_idx:%d\n",s->mb_width, mb_gp_wth, s->rc_bu_level, mb_gp_wth_for_bu, r_idx); ++ //fprintf(stderr,"mb_rinfo0:0x%x,mb_rinfo1:0x%x,bu_rinfo:0x%x\n",mb_rinfo0,mb_rinfo1,bu_rinfo); ++ s->emc_rc_va[i*2] = mb_rinfo1 | mb_rinfo0; ++ s->emc_rc_va[i*2+1] = bu_rinfo; ++ //fprintf(stderr,"s->emc_rc_va[%d]:0x%x,s->emc_rc_va[%d]:0x%x\n",i*2,s->emc_rc_va[i*2],i*2+1,s->emc_rc_va[i*2+1]); ++ } ++ GEN_VDMA_ACFG(chn, REG_EMC_RC_RADDR, 0, VDMA_ACFG_DHA(s->emc_rc_pa)); ++ }else if((s->rc_mb_en & 0x2) && s->frame_type){//only bu_rc ++ for(i=0;irc_bu_num;i++){ ++ uint32_t bu_rinfo = (1<<31) | (s->bu_ref_info[i] & 0x7fffffff); ++ s->emc_rc_va[i*2+1] = bu_rinfo; ++ } ++ GEN_VDMA_ACFG(chn, REG_EMC_RC_RADDR, 0, VDMA_ACFG_DHA(s->emc_rc_pa)); ++ } ++ if(s->rc_mb_en) ++ GEN_VDMA_ACFG(chn, REG_EMC_RC_WADDR, 0, VDMA_ACFG_DHA(s->emc_rc_pa)); ++ ++ if(s->qp_tab_en){ ++ for(i=0;iqp_tab_len;i++) ++ s->emc_qpt_va[i] = s->qp_tab[i]; ++ } ++ if(s->ncu_mov_en){ ++ for(i=0;incu_move_len;i++) ++ s->emc_ncu_va[i] = s->ncu_move_info[i]; ++ } ++ ++ if(s->mb_mode_use){ ++ int mb_mode_len = (s->mb_width * s->mb_height + 1) / 2; ++ for(i=0;iemc_mod_va[i] = s->mb_mode_info[i]; ++ } ++ ++ ++ //rintf(stderr,"s->emc_qpt_va[0]=%x\n",s->emc_qpt_va[0]); ++ //rintf(stderr,"s->emc_qpt_va[1]=%x\n",s->emc_qpt_va[1]); ++ //rintf(stderr,"s->emc_qpt_va[2]=%x\n",s->emc_qpt_va[2]); ++ GEN_VDMA_ACFG(chn, REG_EMC_QPT_ADDR, 0, VDMA_ACFG_DHA(s->emc_qpt_pa)); ++ GEN_VDMA_ACFG(chn, REG_EMC_CPX_ADDR, 0, VDMA_ACFG_DHA(s->emc_cpx_pa)); ++ GEN_VDMA_ACFG(chn, REG_EMC_MOD_ADDR, 0, VDMA_ACFG_DHA(s->emc_mod_pa)); ++ GEN_VDMA_ACFG(chn, REG_EMC_NCU_ADDR, 0, VDMA_ACFG_DHA(s->emc_ncu_pa)); ++ GEN_VDMA_ACFG(chn, REG_EMC_SAD_ADDR, 0, VDMA_ACFG_DHA(s->emc_sad_pa)); ++ GEN_VDMA_ACFG(chn, REG_EMC_BS_SIZE, 0, s->bs_size); ++ GEN_VDMA_ACFG(chn, REG_EMC_SLV_INIT, 0, 0x1); ++ /************************************************** ++ TOPMV/TOPPA init ++ *************************************************/ ++/* for(i=0; i<256; i++){ */ ++/* write_reg(VRAM_TOPMV_BA+i*4, 0); */ ++/* write_reg(VRAM_TOPPA_BA+i*4, 0); */ ++/* } */ ++ ++ /************************************************** ++ SCH configuration ++ *************************************************/ ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHC, 0, 0); ++ GEN_VDMA_ACFG(chn, REG_SCH_BND, 0, 0); ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHG0, 0, 0); ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHG1, 0, 0); ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHE1, 0, 0); ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHE2, 0, 0); ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHE3, 0, 0); ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHE4, 0, 0); ++ ++#if 1 ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHC, 0, (SCH_CH4_GS1 | SCH_CH4_PCH(0) | ++ SCH_CH3_GS1 | SCH_CH3_PCH(0) | ++ SCH_CH2_GS0 | SCH_CH2_PE | SCH_CH2_PCH(0) | ++ SCH_CH1_GS0 | SCH_CH1_PCH(0) | ++ (s->frame_type & 0x1)<<2 ) ); ++ ++ GEN_VDMA_ACFG(chn, REG_SCH_BND, 0, (SCH_CH4_HID(HID_SDE) | SCH_CH3_HID(HID_DBLK) | ++ SCH_CH2_HID(HID_VMAU) | SCH_CH1_HID(HID_MCE) | ++ SCH_DEPTH(SCH_FIFO_DEPTH) | ++ SCH_BND_G0F2 | ++ (s->frame_type & 0x1)<<0 ) ); ++#else ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHC, 0, (SCH_CH4_GS1 | SCH_CH4_PE | SCH_CH4_PCH(0) | ++ SCH_CH3_GS1 | SCH_CH3_PE | SCH_CH3_PCH(0) | ++ SCH_CH2_GS0 | SCH_CH2_PE | SCH_CH2_PCH(0) | ++ SCH_CH1_GS0 | SCH_CH1_PCH(0) | ++ (s->frame_type & 0x1)<<2 ) ); ++ ++ GEN_VDMA_ACFG(chn, REG_SCH_BND, 0, (SCH_CH4_HID(HID_SDE) | SCH_CH3_HID(HID_DBLK) | ++ SCH_CH2_HID(HID_VMAU) | SCH_CH1_HID(HID_MCE) | ++ SCH_DEPTH(SCH_FIFO_DEPTH) | ++ SCH_BND_G1F4 | SCH_BND_G1F3 | ++ SCH_BND_G0F4 | SCH_BND_G0F3 | SCH_BND_G0F2 | ++ (s->frame_type & 0x1)<<0 ) ); ++#endif ++ ++ /************************************************** ++ ODMA configuration ++ *************************************************/ ++ //when buf share is new addr(dynamic), else old addr(static) ++ paddr_t odma_y_addr = s->buf_share_en ? buf_start_yaddr : s->fb[0][0]; ++ paddr_t odma_c_addr = s->buf_share_en ? buf_start_caddr : s->fb[0][1]; ++ //when buf share is base addr, else head addr ++ paddr_t odma_com_addr0 = s->buf_share_en ? s->fb[0][0] : s->jh[0][0]; ++ paddr_t odma_com_addr1 = s->buf_share_en ? s->fb[0][1] : s->jh[0][1]; ++ //when buf share is beyond addr, else head spe addr ++ paddr_t odma_com_addr2 = s->buf_share_en ? buf_beyond_yaddr : s->spe_y_addr; ++ paddr_t odma_com_addr3 = s->buf_share_en ? buf_beyond_caddr : s->spe_c_addr; ++ ++ GEN_VDMA_ACFG(chn, REG_ODMA_CTRL, 0, (odma_spe_flag << 31 | ++ (s->buf_share_en << 30) |//buf share ++ (odma_alg_flag << 29) | ++ (s->jrfc_enable << 28) |//compress_flag ++ (s->frame_height << 14) | ++ s->frame_width)); ++ ++ GEN_VDMA_ACFG(chn, REG_ODMA_BDYA, 0, odma_y_addr); ++ GEN_VDMA_ACFG(chn, REG_ODMA_BDCA, 0, odma_c_addr); ++ ++ GEN_VDMA_ACFG(chn, REG_ODMA_BSTR, 0, ++ ODMA_REC_STRDY(((s->frame_width+15)/16)*16) | ++ ODMA_REC_STRDC(((s->frame_width+15)/16)*8) ); ++ ++ ++ GEN_VDMA_ACFG(chn, REG_ODMA_HDYA, 0, odma_com_addr0); ++ GEN_VDMA_ACFG(chn, REG_ODMA_HDCA, 0, odma_com_addr1); ++ GEN_VDMA_ACFG(chn, REG_ODMA_SPYA, 0, odma_com_addr2); ++ GEN_VDMA_ACFG(chn, REG_ODMA_SPCA, 0, odma_com_addr3); ++ ++ ++ GEN_VDMA_ACFG(chn, REG_ODMA_TRIG, 0, ++ ((0 << 6) | //0 is crc en ++ (1 << 5) | //init ++ (0 << 4) //ckg low means do clock-gating ++ )); ++ ++ ++ /************************************************** ++ IFA configuration ++ *************************************************/ ++ ++ GEN_VDMA_ACFG(chn, REG_IFA_FRM_SIZE, 0, (IFA_FRM_W(s->frame_width-1) | ++ IFA_FRM_H(s->frame_height-1) ) ); ++ GEN_VDMA_ACFG(chn, REG_IFA_RAWY_BA, 0, s->raw[0]); ++ GEN_VDMA_ACFG(chn, REG_IFA_RAWC_BA, 0, s->raw[1]); ++ if(s->buf_share_en){ ++ GEN_VDMA_ACFG(chn, REG_IFA_REFY_BA0, 0, refy_addr_ba0); ++ GEN_VDMA_ACFG(chn, REG_IFA_REFC_BA0, 0, refc_addr_ba0); ++ GEN_VDMA_ACFG(chn, REG_IFA_REFY_BA1, 0, refy_addr_ba1); ++ GEN_VDMA_ACFG(chn, REG_IFA_REFC_BA1, 0, refc_addr_ba1); ++ } ++ else { ++ GEN_VDMA_ACFG(chn, REG_IFA_REFY_BA0, 0, s->fb[1][0]); ++ GEN_VDMA_ACFG(chn, REG_IFA_REFC_BA0, 0, s->fb[1][1]); ++ GEN_VDMA_ACFG(chn, REG_IFA_REFY_BA1, 0, s->fb[3][0]); ++ GEN_VDMA_ACFG(chn, REG_IFA_REFC_BA1, 0, s->fb[3][1]); ++ } ++ ++ GEN_VDMA_ACFG(chn, REG_IFA_RAW_STR, 0, (IFA_STR_Y(s->stride[0]) | ++ IFA_STR_C(s->stride[1]) ) ); ++ GEN_VDMA_ACFG(chn, REG_IFA_THRD_Y, 0, s->rrs_thrd_y); ++ GEN_VDMA_ACFG(chn, REG_IFA_THRD_C, 0, (IFA_THRD_U(s->rrs_thrd_u) | ++ IFA_THRD_V(s->rrs_thrd_v) ) ); ++ GEN_VDMA_ACFG(chn, REG_IFA_CTRL, 0, (IFA_CTRL_RAW_TYPE(s->raw_format == EFE_PLANE_NV12) | ++ IFA_CTRL_REF_BIDX(ref_mby_size) | ++ IFA_CTRL_RRS_EN(s->rrs_en) | ++ IFA_CTRL_DUMP_EN(s->rrs_dump_en) | ++ IFA_CTRL_DDR_DW(!s->jrfd_enable) | ++ IFA_CTRL_RRS_SC(s->rrs_size_c) | ++ IFA_CTRL_RRS_SY(s->rrs_size_y) | ++ IFA_CTRL_UV_EN(s->rrs_uv_en) | ++ IFA_CTRL_INIT ) ); ++ ++ //sde slice header ++ if(s->bs_head_en){ ++ //printf("bs_head_rest\n"); ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG5, 0, 0x1); ++ //slice header lenth ++ //printf("s->bs_head_len=0x%x\n",s->bs_head_len-1); ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG6, 0, s->bs_head_len-1); ++ for(i=0; i<(s->bs_head_len+3)/4; i++){ ++ //printf("s->bs_head_va[%x]=%x\n",i,s->bs_head_va[i]); ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG7, 0, s->bs_head_va[i]); ++ } ++ //printf("bs_head_work\n"); ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG5, 0, 0x2); ++ } ++ //efe start ++ uint8_t align8_flag = (s->frame_height & 0xF) != 0; ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_CTRL, VDMA_ACFG_TERM, (EFE_TSE(s->use_intra_in_pframe) | ++ EFE_FMVP(s->use_fast_mvp) | ++ (0/*s->size_mode*/ << 29) | ++ s->raw_format | ++ EFE_X264_QP(s->qp) | ++ EFE_HALN8_FLAG(align8_flag) | ++ EFE_STEP_MODE(s->step_mode) | ++ EFE_DBLK_EN | ++ EFE_SLICE_TYPE(s->frame_type) | ++ EFE_EN | EFE_RUN) ); ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_api_helix_x264_enc.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_api_helix_x264_enc.h.patch new file mode 100644 index 00000000..6ff7ad09 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_api_helix_x264_enc.h.patch @@ -0,0 +1,402 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/helix/api/helix_x264_enc.h b/drivers/media/platform/ingenic-vcodec/helix/api/helix_x264_enc.h +--- a/drivers/media/platform/ingenic-vcodec/helix/api/helix_x264_enc.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/helix/api/helix_x264_enc.h 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,398 @@ ++/**************************************************************** ++*****************************************************************/ ++ ++#ifndef __JZM_X264_ENC_H__ ++#define __JZM_X264_ENC_H__ ++#include "helix.h" ++ ++#ifdef __KERNEL__ ++#include ++#include ++#include ++#define printf printk ++#endif ++ ++#define SCH_FIFO_DEPTH 16 ++ ++/************************************************************ ++ CHN Space Allocation ++ ************************************************************/ ++#define VRAM_DUMMY (VPU_BASE | 0xFFFFC) ++ ++#define VRAM_MAU_RESA (VPU_BASE | 0xC0000) //residual address ++#define VRAM_MAU_RES_SIZE (SCH_FIFO_DEPTH*256*4) ++ ++#define VRAM_RAWY_BA (VPU_BASE | 0xF0000) ++#define VRAM_RAWC_BA (VRAM_RAWY_BA + 256) ++#define VRAM_RAW_SIZE (SCH_FIFO_DEPTH*128*4) ++ ++#define VRAM_TOPPA_BA (VRAM_MAU_RESA+VRAM_MAU_RES_SIZE) //recover address ++#define VRAM_TOPMV_BA (VRAM_TOPPA_BA+VPU_MAX_MB_WIDTH*8) ++ ++#define VRAM_MAU_CHN_BASE (VRAM_TOPMV_BA+VPU_MAX_MB_WIDTH*4) ++#define VRAM_MAU_CHN_SIZE (SCH_FIFO_DEPTH*16*4) ++#define VRAM_DBLK_CHN_BASE (VRAM_MAU_CHN_BASE + VRAM_MAU_CHN_SIZE) ++#define VRAM_DBLK_CHN_SIZE (SCH_FIFO_DEPTH*16*4) ++#define VRAM_ME_CHN_BASE (VRAM_DBLK_CHN_BASE + VRAM_DBLK_CHN_SIZE) ++#define VRAM_ME_CHN_SIZE (SCH_FIFO_DEPTH*8*4) ++#define VRAM_SDE_CHN_BASE (VRAM_ME_CHN_BASE + VRAM_ME_CHN_SIZE) ++#define VRAM_SDE_CHN_SIZE (SCH_FIFO_DEPTH*8*4) ++#define VRAM_QP_TAB_BA (VRAM_SDE_CHN_BASE + VRAM_SDE_CHN_SIZE) ++ ++#define VRAM_ME_DSA DSA_SCH_CH1 ++#define VRAM_MAU_DEC_SYNA DSA_SCH_CH2 ++#define VRAM_DBLK_CHN_SYNA DSA_SCH_CH3 ++#define VRAM_SDE_SYNA DSA_SCH_CH4 ++ ++#define VRAM_MAU_ENC_SYNA VRAM_DUMMY ++#define VRAM_DBLK_DOUT_SYNA VRAM_DUMMY ++ ++#define VRAM_ME_MVPA (VPU_BASE | REG_EFE_MVRP) ++ ++typedef unsigned int paddr_t; ++ ++#define __ALN32__ __attribute__ ((aligned(4))) ++ ++typedef struct ROI_info{ ++ uint8_t roi_en; ++ uint8_t roi_md; ++ int8_t roi_qp; ++ uint8_t roi_lmbx; ++ uint8_t roi_rmbx; ++ uint8_t roi_umby; ++ uint8_t roi_bmby; ++} roi_info_t; ++ ++/* ++ _H264E_SliceInfo: ++ H264 Encoder Slice Level Information ++ */ ++typedef struct _H264E_SliceInfo { ++ /*basic*/ ++ uint8_t frame_type; ++ uint8_t mb_width; ++ uint8_t mb_height; ++ uint8_t first_mby; ++ uint8_t last_mby; //for multi-slice ++ ++ /* motion */ ++ int frame_width; ++ int frame_height; ++ uint8_t frm_re[4]; ++ uint8_t pskip_en; ++ uint8_t force_mv0_en; ++ uint8_t mref_en; ++ uint8_t dct8x8_en; ++ uint8_t scl; ++ uint8_t hpel_en; ++ uint8_t qpel_en; ++ uint8_t ref_mode; ++ uint32_t max_sech_step_i; ++ uint32_t max_mvrx_i; ++ uint32_t max_mvry_i; ++ uint8_t lambda_scale_parameter; ++ uint8_t fs_en; //fs function enable ++ uint32_t fs_md; //fs step mode, 0: 1, 1: 3 ++ uint8_t fs_px; //fs period x ++ uint8_t fs_py; //fs period y ++ uint8_t fs_rx; //fs range x, must be multiples of 3 ++ uint8_t fs_ry; //fs range y, must be multiples of 3 ++ uint8_t frm_mv_en; //add a frame level mv ++ uint8_t frm_mv_size; //mv enable after x mb, x=2^(size+8) ++ uint8_t glb_mv_en; //global mv enable ++ int glb_mvx; //global mvx value ++ int glb_mvy; //global mvy value ++ uint8_t me_step_en; //auto-modify max step number ++ uint8_t me_step_0; //step number threshold 0 ++ uint8_t me_step_1; //step number threshold 1 ++ /*vmau scaling list*/ ++ uint8_t __ALN32__ scaling_list[4][16]; ++ uint8_t __ALN32__ scaling_list8[2][64]; ++ int deadzone[9]; ++ uint32_t acmask_mode; ++ ++ uint32_t intra_mode_msk; ++ ++ uint8_t i_4x4_dis; ++ uint8_t i_8x8_dis; ++ uint8_t i_16x16_dis; ++ uint8_t p_l0_dis; ++ uint8_t p_t8_dis; ++ uint8_t p_skip_dis; ++ uint8_t p_skip_pl0f_dis; ++ uint8_t p_skip_pt8f_dis; ++ ++ uint8_t cost_bias_en; ++ uint8_t cost_bias_i_4x4; ++ uint8_t cost_bias_i_8x8; ++ uint8_t cost_bias_i_16x16; ++ uint8_t cost_bias_p_l0; ++ uint8_t cost_bias_p_t8; ++ uint8_t cost_bias_p_skip; ++ ++ uint8_t intra_lambda_y_bias_en; ++ uint8_t intra_lambda_c_bias_en; ++ uint8_t intra_lambda_bias_qp0; ++ uint8_t intra_lambda_bias_qp1; ++ uint8_t intra_lambda_bias_0; ++ uint8_t intra_lambda_bias_1; ++ uint8_t intra_lambda_bias_2; ++ ++ uint8_t chroma_sse_bias_en; ++ uint8_t chroma_sse_bias_qp0; ++ uint8_t chroma_sse_bias_qp1; ++ uint8_t chroma_sse_bias_0; ++ uint8_t chroma_sse_bias_1; ++ uint8_t chroma_sse_bias_2; ++ ++ uint8_t sse_lambda_bias_en; ++ uint8_t sse_lambda_bias; ++ ++ uint8_t fbc_ep; ++ uint8_t jm_lambda2_en; ++ uint8_t inter_nei_en; ++ uint8_t skip_bias_en; ++ ++ uint8_t info_en; ++ uint8_t mvd_sum_all; ++ uint8_t mvd_sum_abs; ++ uint8_t mv_sum_all; ++ uint8_t mv_sum_abs; ++ ++ uint32_t ysse_thr; ++ uint32_t csse_thr; ++ ++ uint8_t cfg_size_x; ++ uint8_t cfg_size_y; ++ uint16_t cfg_iw_thr; ++ ++ uint16_t cfg_mvr_thr1; ++ uint32_t cfg_mvr_thr2; ++ uint32_t cfg_mvr_thr3; ++ ++ uint8_t dcm_en; ++ uint32_t dcm_param; ++ ++ uint8_t sde_prior; ++ uint8_t db_prior; ++ /*ipred bit&lambda ctrl*/ ++ uint8_t mb_mode_val; ++ uint8_t bit_16_en; ++ uint8_t bit_8_en; ++ uint8_t bit_4_en; ++ uint8_t bit_uv_en; ++ uint8_t lamb_16_en; ++ uint8_t lamb_8_en; ++ uint8_t lamb_4_en; ++ uint8_t lamb_uv_en; ++ uint8_t c_16_en; ++ uint8_t c_8_en; ++ uint8_t c_4_en; ++ uint8_t c_uv_en; ++ uint8_t pri_16; ++ uint8_t pri_8; ++ uint8_t pri_4; ++ uint8_t pri_uv; ++ uint8_t ref_neb_4; ++ uint8_t ref_neb_8; ++ uint8_t bit_16[4]; ++ uint8_t bit_uv[4]; ++ uint8_t bit_4[4]; ++ uint8_t bit_8[4]; ++ uint8_t lambda_info16; ++ uint8_t lambda_info8; ++ uint8_t lambda_info4; ++ uint8_t lambda_infouv; ++ uint8_t ref_4; ++ uint8_t ref_8; ++ uint8_t const_16[4]; ++ uint8_t const_uv[4]; ++ uint8_t const_4[4]; ++ uint8_t const_8[4]; ++ ++ /*loop filter*/ ++ uint8_t deblock; ++ uint8_t rotate; ++ int8_t alpha_c0_offset; ++ int8_t beta_offset; ++ ++ /*cabac*/ ++ uint8_t *state; ++ paddr_t bs; /*BS output address*/ ++ uint8_t bs_rbsp_en; /*BS rbsp enable*/ ++ uint8_t bs_head_en; /*read BS header enable*/ ++ uint8_t bs_head_len; /*read BS header lenth*/ ++ paddr_t *bs_head_va; /*read BS header data addr*/ ++ paddr_t bs_head_pa; /*read BS header data addr*/ ++ uint8_t qp; ++ uint8_t bs_size_en; ++ uint32_t bs_size; ++ ++ uint8_t skip_en; ++ int8_t cqp_offset; ++ /*mode decision*/ ++ uint8_t use_intra_in_pframe; ++ uint8_t use_fast_mvp; ++ ++ uint8_t mode_ctrl; ++ uint32_t mode_ctrl_param[40]; ++ ++ /*frame buffer address: all of the buffers should be 256byte aligned!*/ ++ paddr_t fb[3][2]; /*{curr, ref}{tile_y, tile_c}*/ ++ paddr_t raw[3]; /*{rawy, rawu, rawv} or {rawy, rawc, N/C}*/ ++ int stride[2]; /*{stride_y, stride_c}, only used in raster raw*/ ++ ++ /* RAW plane format */ ++ uint8_t raw_format; ++ ++ uint8_t size_mode; ++ uint8_t step_mode; ++ /*descriptor address*/ ++ paddr_t *des_va, des_pa; ++ paddr_t emc_bs_pa; ++ paddr_t *emc_dblk_va,emc_dblk_pa; ++ paddr_t *emc_recon_va,emc_recon_pa; ++ paddr_t *emc_mv_va,emc_mv_pa; ++ paddr_t *emc_se_va,emc_se_pa; ++ paddr_t *emc_qpt_va, emc_qpt_pa; ++ paddr_t *emc_rc_va, emc_rc_pa; ++ paddr_t *emc_cpx_va, emc_cpx_pa; ++ paddr_t *emc_mod_va, emc_mod_pa; ++ paddr_t *emc_ncu_va, emc_ncu_pa; ++ paddr_t *emc_sad_va, emc_sad_pa; ++ ++ /*TLB address*/ ++ paddr_t tlba; ++ ++ /* ROI info */ ++ roi_info_t roi_info[8]; ++ uint8_t base_qp; ++ uint8_t max_qp; ++ uint8_t min_qp; ++ ++ uint8_t qp_tab_mode; ++ uint8_t qp_tab_en; ++ uint32_t qp_tab_len; ++ uint32_t *qp_tab; ++ uint8_t sas_en; ++ uint8_t crp_en; ++ uint8_t sas_mthd; ++ uint16_t qpg_mb_thd[7]; ++ int8_t qpg_mbqp_ofst[8]; ++ uint8_t qpg_flt_thd[5]; ++ uint8_t mbrc_qpg_sel; //whether use crp/sas qp offset or not, when MB rate control enable. ++ ++ /* rate ctrl */ ++ uint8_t rc_mb_en; ++ uint8_t rc_bu_wait_en;// efe chn wait rc qp offset en ++ uint8_t rc_mb_wait_en;// efe chn wait rc qp offset en ++ uint8_t rc_bu_num;// total basic unit number ++ uint16_t rc_bu_size;// mb number in a basic unit ++ uint8_t rc_bu_level;// 1:1line 2:2line 3:4line 4:8line 5:16line 6:32line 7:64line ++ uint8_t rc_mb_level;// 0:skip 1mb, 1:skip 2mb, 2:skip 4mb, 3:skip 8mb ++ int32_t *mb_ref_info; ++ int32_t *bu_ref_info; ++ uint32_t rc_frm_tbs; ++ uint32_t avg_bu_bs; ++ uint16_t tar_bs_thd[6]; ++ int8_t bu_alg0_qpo[6]; ++ int8_t bu_alg1_qpo[6]; ++ int8_t mb_cs_qpo[7]; ++ int8_t mb_top_bs_qpo[2]; ++ int8_t mb_rinfo_qpo[2]; ++ uint16_t mb_target_avg_bs[2]; ++ uint16_t mb_gp_num; ++ uint16_t last_bu_size; ++ uint8_t rc_bcfg_mode; ++ ++ //mosaic ++ uint8_t mosaic_en; ++ uint8_t mos_gthd[2]; ++ uint8_t mos_sthd[2]; ++ /* VPU Daisy Chain setting */ ++ uint8_t daisy_chain_en; ++ uint8_t curr_thread_id; ++ ++ //odma,jrfc,jrfd ++ uint8_t jrfcd_flag; ++ uint8_t jrfc_enable; ++ uint8_t jrfd_enable; ++ uint32_t lm_head_total; ++ uint32_t cm_head_total; ++ paddr_t jh[3][2]; /*head addr {curr, ref0, ref1}{y, c}*/ ++ paddr_t spe_y_addr; ++ paddr_t spe_c_addr; ++ ++ //eigen cfg ++ uint8_t mb_mode_use; ++ uint32_t *mb_mode_info; ++ uint8_t force_i16dc;//ipred ++ uint8_t force_i16; ++ uint8_t refresh_en; ++ uint8_t refresh_mode; ++ uint8_t refresh_bias; ++ uint8_t refresh_cplx_thd; ++ uint8_t cplx_thd_sel; ++ uint8_t diff_cplx_sel; ++ uint8_t diff_thd_sel; ++ uint8_t i16dc_cplx_thd; ++ uint8_t i16dc_qp_base; ++ uint8_t i16dc_qp_sel; ++ uint8_t i16_qp_base; ++ uint8_t i16_qp_sel; ++ uint8_t diff_cplx_thd; ++ uint8_t diff_qp_base[2]; ++ uint8_t diff_qp_sel[2]; ++ uint8_t cplx_thd_idx[24]; ++ uint8_t cplx_thd[8]; ++ uint16_t diff_thd_base[3]; ++ uint16_t diff_thd_ofst[3]; ++ uint8_t sas_eigen_en; ++ uint8_t crp_eigen_en; ++ uint8_t sas_eigen_dump; ++ uint8_t crp_eigen_dump; ++ //ifa ++ uint8_t rrs_en; ++ uint8_t rrs_dump_en; ++ uint8_t rrs_uv_en; ++ uint8_t rrs_size_y; //0: 4, 1: 8, 2: 12, 3: 16 ++ uint8_t rrs_size_c; //0: 4, 1: 8 ++ uint16_t rrs_thrd_y; //threshold ++ uint16_t rrs_thrd_u; ++ uint16_t rrs_thrd_v; ++ ++ //skin ++ uint8_t skin_dt_en; ++ uint8_t skin_lvl; ++ uint8_t skin_cnt_thd; ++ uint8_t skin_pxlu_thd[3][2]; ++ uint8_t skin_pxlv_thd[3][2]; ++ int8_t skin_qp_ofst[4]; ++ uint8_t mult_factor[3]; ++ uint8_t shift_factor[3][3];//[0][]:0.4, [1][]:0.6, [2][]: 5.1 ++ uint16_t skin_ofst[4];//[0]: 1.5, [1]:0.4, [2]:0.6, [3]: 5.1 ++ uint8_t ncu_mov_en; ++ uint32_t ncu_move_len; ++ uint32_t *ncu_move_info; ++ //buf-share ++ uint8_t buf_share_en; ++ uint8_t buf_share_size; ++ uint32_t frame_idx; ++}_H264E_SliceInfo; ++ ++typedef struct _H264E_SliceInfo H264E_SliceInfo_t; ++ ++ ++/* ++ H264E_SliceInit(_H264E_SliceInfo *s) ++ @param s: slice information structure ++ */ ++void H264E_SliceInit(_H264E_SliceInfo *s); ++ ++ ++/* ++ default _H264_SliceInfo. ++*/ ++extern _H264E_SliceInfo default_H264E_Sliceinfo; ++ ++#endif /*__JZM_H264E_H__*/ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_default_sliceinfo.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_default_sliceinfo.c.patch new file mode 100644 index 00000000..08517752 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_default_sliceinfo.c.patch @@ -0,0 +1,366 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/helix/default_sliceinfo.c b/drivers/media/platform/ingenic-vcodec/helix/default_sliceinfo.c +--- a/drivers/media/platform/ingenic-vcodec/helix/default_sliceinfo.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/helix/default_sliceinfo.c 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,362 @@ ++#include "api/helix_x264_enc.h" ++ ++_H264E_SliceInfo default_H264E_Sliceinfo = { ++ .frame_type = 1, ++ .mb_width = 22, ++ .mb_height = 18, ++ .first_mby = 0, ++ .last_mby = 17, ++ .frame_width = 352, ++ .frame_height = 288, ++ ++ .frm_re = {0x00, 0x00, 0x00, 0x00}, ++ .pskip_en = 1, ++ .mref_en = 0, ++ .dct8x8_en = 0, ++ .scl = 0x03, ++ .hpel_en = 0x01, ++ .qpel_en = 0x01, ++ .ref_mode = 0x01, ++ .max_sech_step_i = 0x3f, ++ .max_mvrx_i = 0x1f4, ++ .max_mvry_i = 0x1f4, ++ .lambda_scale_parameter = 0x08, ++ .fs_en = 0x00, ++ .fs_md = 0x00, ++ .fs_px = 0x00, ++ .fs_py = 0x00, ++ .fs_rx = -1, ++ .fs_ry = -1, ++ .frm_mv_en = 0x00, ++ .frm_mv_size = 0x00, ++ .glb_mv_en = 0x00, ++ .glb_mvx = 0, ++ .glb_mvy = 0, ++ .me_step_en = 0x0, ++ .me_step_0 = 0x0, ++ .me_step_1 = 0x0, ++ .scaling_list = { ++ {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, }, ++ {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, }, ++ {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, }, ++ {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, }, ++ }, ++ .scaling_list8 = { ++ {0x06, 0x0a, 0x0d, 0x10, 0x12, 0x16, 0x18, 0x1a, 0x0a, 0x0b, 0x10, 0x12, 0x16, 0x18, 0x1a, 0x1c, 0x0d, 0x10, 0x12, 0x16, 0x18, 0x1a, 0x1c, 0x1e, 0x10, 0x12, 0x16, 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x12, 0x16, 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x23, 0x16, 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x23, 0x25, 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x23, 0x25, 0x27, 0x1a, 0x1c, 0x1e, 0x20, 0x23, 0x25, 0x27, 0x29, }, ++ {0x09, 0x0d, 0x0f, 0x11, 0x13, 0x15, 0x16, 0x18, 0x0d, 0x0d, 0x11, 0x13, 0x15, 0x16, 0x18, 0x19, 0x0f, 0x11, 0x13, 0x15, 0x16, 0x18, 0x19, 0x1b, 0x11, 0x13, 0x15, 0x16, 0x18, 0x19, 0x1b, 0x1c, 0x13, 0x15, 0x16, 0x18, 0x19, 0x1b, 0x1c, 0x1e, 0x15, 0x16, 0x18, 0x19, 0x1b, 0x1c, 0x1e, 0x20, 0x16, 0x18, 0x19, 0x1b, 0x1c, 0x1e, 0x20, 0x21, 0x18, 0x19, 0x1b, 0x1c, 0x1e, 0x20, 0x21, 0x23, }, ++ }, ++ ++ .deadzone = { 0x00000015, 0x0000000b, 0x00000015, 0x0000000b, 0x00000015, 0x0000000b, 0x00000015, 0x00000015, 0x0000000b}, ++ .acmask_mode = 0x000095ea, ++ .intra_mode_msk = 0x0, ++ .i_4x4_dis = 0x0, ++ .i_8x8_dis = 0x0, ++ .i_16x16_dis = 0x0, ++ .p_l0_dis = 0x0, ++ .p_t8_dis = 0x0, ++ .p_skip_dis = 0x0, ++ .p_skip_pl0f_dis = 0x0, ++ .p_skip_pt8f_dis = 0x0, ++ .cost_bias_en = 0x0, ++ .cost_bias_i_4x4 = 0x0, ++ .cost_bias_i_8x8 = 0x0, ++ .cost_bias_i_16x16 = 0x0, ++ .cost_bias_p_l0 = 0x0, ++ .cost_bias_p_t8 = 0x0, ++ .cost_bias_p_skip = 0x0, ++ .intra_lambda_y_bias_en = 0x0, ++ .intra_lambda_c_bias_en = 0x0, ++ .intra_lambda_bias_qp0 = 0x0, ++ .intra_lambda_bias_qp1 = 0x0, ++ .intra_lambda_bias_0 = 0x0, ++ .intra_lambda_bias_1 = 0x0, ++ .intra_lambda_bias_2 = 0x0, ++ .chroma_sse_bias_en = 0x0, ++ .chroma_sse_bias_qp0 = 0x0, ++ .chroma_sse_bias_qp1 = 0x0, ++ .chroma_sse_bias_0 = 0x0, ++ .chroma_sse_bias_1 = 0x0, ++ .chroma_sse_bias_2 = 0x0, ++ .sse_lambda_bias_en = 0x0, ++ .sse_lambda_bias = 0x0, ++ .fbc_ep = 0xcc, ++ .jm_lambda2_en = 0x0, ++ .inter_nei_en = 0x0, ++ .skip_bias_en = 0x0, ++ .info_en = 0x1, ++ .mvd_sum_all = 0x0, ++ .mvd_sum_abs = 0x0, ++ .mv_sum_all = 0x0, ++ .mv_sum_abs = 0x0, ++ .ysse_thr = 0x0, ++ .csse_thr = 0x0, ++ .cfg_size_x = 0x4, ++ .cfg_size_y = 0x4, ++ .cfg_iw_thr = 0x0, ++ .cfg_mvr_thr1 = 0x0, ++ .cfg_mvr_thr2 = 0x0, ++ .cfg_mvr_thr3 = 0x0, ++ .dcm_en = 0x0, ++ .dcm_param = 0x4304, ++ .sde_prior = 0x5, ++ .db_prior = 0x5, ++ .mb_mode_val = 0x1, ++ .bit_16_en = 0x0, ++ .bit_8_en = 0x1, ++ .bit_4_en = 0x1, ++ .bit_uv_en = 0x0, ++ .lamb_16_en = 0x0, ++ .lamb_8_en = 0x0, ++ .lamb_4_en = 0x0, ++ .lamb_uv_en = 0x0, ++ .c_16_en = 0x0, ++ .c_8_en = 0x0, ++ .c_4_en = 0x0, ++ .c_uv_en = 0x0, ++ .pri_16 = 0x0, ++ .pri_8 = 0x0, ++ .pri_4 = 0x0, ++ .pri_uv = 0x0, ++ .ref_neb_4 = 0x1, ++ .ref_neb_8 = 0x1, ++ .bit_16 = {0,0,0,0}, ++ .bit_uv = {0,0,0,0}, ++ .bit_4 = {4,4,4,4}, ++ .bit_8 = {4,4,4,4}, ++ .lambda_info16 = 0x0, ++ .lambda_info8 = 0x0, ++ .lambda_info4 = 0x0, ++ .lambda_infouv = 0x0, ++ .ref_4 = 0x4, ++ .ref_8 = 0x3, ++ .const_16 = {0,0,0,0}, ++ .const_uv = {0,0,0,0}, ++ .const_4 = {0,0,0,0}, ++ .const_8 = {0,0,0,0}, ++ .deblock = 1, ++ .rotate = 0, ++ .alpha_c0_offset = 0, ++ .beta_offset = 0, ++ .state = 0xf7edfc94, ++ .bs = 0x00000000, ++ .qp = 0x26, ++ .bs_size_en = 0x1, ++ .bs_size = 0x800, ++ .skip_en = 1, ++ .cqp_offset = 0, ++ .use_intra_in_pframe = 0x1, ++ .use_fast_mvp = 0x0, ++ .mode_ctrl = 0x0, ++ .mode_ctrl_param = {0}, ++ .fb = {{0,0},{0,0},{0,0}}, ++ .raw = {0,0,0}, ++ .stride = {0,0}, ++ .raw_format = 8, ++ .size_mode = 0, ++ .step_mode = 0, ++ .des_va = 0, ++ .des_pa = 0, ++ .emc_bs_pa = 0, ++ .emc_dblk_pa = 0, ++// .emc_bs_va = 0, ++ .emc_dblk_va = 0, ++ .emc_recon_va = 0, ++ .emc_mv_va = 0, ++ .emc_se_va = 0, ++ .emc_recon_va = 0, ++ .emc_recon_pa = 0, ++ .emc_mv_pa = 0, ++ .emc_se_pa = 0, ++ .emc_qpt_va = 0, ++ .emc_qpt_pa = 0, ++ .emc_rc_va = 0, ++ .emc_rc_pa = 0, ++ .emc_cpx_va = 0, ++ .emc_cpx_pa = 0, ++ .emc_mod_va = 0, ++ .emc_mod_pa = 0, ++ .emc_ncu_va = 0, ++ .emc_ncu_pa = 0, ++ .emc_sad_va = 0, ++ .emc_sad_pa = 0, ++ .tlba = 0, ++ .roi_info = { ++ {0,0,0,0,0,0,0}, ++ {0,0,0,0,0,0,0}, ++ {0,0,0,0,0,0,0}, ++ {0,0,0,0,0,0,0}, ++ {0,0,0,0,0,0,0}, ++ {0,0,0,0,0,0,0}, ++ {0,0,0,0,0,0,0}, ++ {0,0,0,0,0,0,0}, ++ }, ++ .base_qp = 38, ++ .max_qp = 51, ++ .min_qp = 26, ++ .qp_tab_mode = 0, ++ .qp_tab_en = 0, ++ .qp_tab_len = 0, ++ .qp_tab = NULL, ++ .sas_en = 0, ++ .crp_en = 0, ++ .sas_mthd = 0, ++ .qpg_mb_thd = {0,0,0,0,0,0,0}, ++ .qpg_mbqp_ofst = {0,0,0,0,0,0,0}, ++ .qpg_flt_thd = {0,0,0,0,0}, ++ .mbrc_qpg_sel = 0, ++ .rc_mb_en = 0, ++ .rc_bu_wait_en = 0, ++ .rc_mb_wait_en = 0, ++ .rc_bu_num = 0x00000012, ++ .rc_bu_size = 0x00000016, ++ .rc_bu_level = 1, ++ .rc_mb_level = 2, ++ .mb_ref_info = NULL, ++ .bu_ref_info = NULL, ++ .rc_frm_tbs = 1000, ++ .avg_bu_bs = 55, ++ .tar_bs_thd = {500, 1000, 1500, 2000, 2500, 3000}, ++ .bu_alg0_qpo = {1,2,3,4,5,6}, ++ .bu_alg1_qpo = {1,1,1,1,1,1}, ++ .mb_cs_qpo = {-3,-2,-1,0,1,2,3}, ++ .mb_top_bs_qpo = {-1, 1}, ++ .mb_rinfo_qpo = {-1, 1}, ++ .mb_target_avg_bs = {2,2}, ++ .mb_gp_num = 198, ++ .last_bu_size = 22, ++ .rc_bcfg_mode = 0, ++ .mosaic_en = 0, ++ .mos_gthd = {1,4}, ++ .mos_sthd = {8,6}, ++ .daisy_chain_en = 0, ++ .curr_thread_id = 5, ++ .jrfcd_flag = 0, ++ .jrfc_enable = 0, ++ .jrfd_enable = 0, ++ .lm_head_total = 0, ++ .cm_head_total = 0, ++ .jh = {{0,0}, {0,0}, {0,0}}, ++ .spe_y_addr = 0, ++ .spe_c_addr = 0, ++ .mb_mode_use = 0, ++ .mb_mode_info = NULL, ++ .force_i16dc = 1, ++ .force_i16 = 1, ++ .refresh_en = 0, ++ .refresh_mode = 0, ++ .refresh_bias = 10, ++ .refresh_cplx_thd = 4, ++ .cplx_thd_sel = 0, ++ .diff_cplx_sel = 0, ++ .diff_thd_sel = 0, ++ .i16dc_cplx_thd = 3, ++ .i16dc_qp_base = 33, ++ .i16dc_qp_sel = 0, ++ .i16_qp_base = 28, ++ .i16_qp_sel = 0, ++ .diff_cplx_thd = 10, ++ .diff_qp_base = {33,33}, ++ .diff_qp_sel = {0, 0}, ++ .cplx_thd_idx = { ++ 0, /*cplx_thd_idx[0]*/ ++ 0, /*cplx_thd_idx[1]*/ ++ 1, /*cplx_thd_idx[2]*/ ++ 1, /*cplx_thd_idx[3]*/ ++ 1, /*cplx_thd_idx[4]*/ ++ 1, /*cplx_thd_idx[5]*/ ++ 1, /*cplx_thd_idx[6]*/ ++ 2, /*cplx_thd_idx[7]*/ ++ 2, /*cplx_thd_idx[8]*/ ++ 2, /*cplx_thd_idx[9]*/ ++ 2, /*cplx_thd_idx[10]*/ ++ 2, /*cplx_thd_idx[11]*/ ++ 2, /*cplx_thd_idx[12]*/ ++ 2, /*cplx_thd_idx[13]*/ ++ 2, /*cplx_thd_idx[14]*/ ++ 2, /*cplx_thd_idx[15]*/ ++ 2, /*cplx_thd_idx[16]*/ ++ 2, /*cplx_thd_idx[17]*/ ++ 2, /*cplx_thd_idx[18]*/ ++ 2, /*cplx_thd_idx[19]*/ ++ 3, /*cplx_thd_idx[20]*/ ++ 3, /*cplx_thd_idx[21]*/ ++ 3, /*cplx_thd_idx[22]*/ ++ 3, /*cplx_thd_idx[23]*/ ++ }, ++ ++ .cplx_thd = { ++ 0, /*cplx_thd[0]*/ ++ 5, /*cplx_thd[1]*/ ++ 10, /*cplx_thd[2]*/ ++ 15, /*cplx_thd[3]*/ ++ 0, /*cplx_thd[4]*/ ++ 0, /*cplx_thd[5]*/ ++ 0, /*cplx_thd[6]*/ ++ 0, /*cplx_thd[7]*/ ++ }, ++ ++ .diff_thd_base = { ++ 384, /*diff_thd_base[0]*/ ++ 96, /*diff_thd_base[1]*/ ++ 96, /*diff_thd_base[2]*/ ++ }, ++ ++ .diff_thd_ofst = { ++ 48, /*diff_thd_ofst[0]*/ ++ 12, /*diff_thd_ofst[1]*/ ++ 12, /*diff_thd_ofst[2]*/ ++ }, ++ .sas_eigen_en = 0, ++ .crp_eigen_en = 0, ++ .sas_eigen_dump = 0, ++ .crp_eigen_dump = 0, ++ .rrs_en = 0, ++ .rrs_dump_en = 1, ++ .rrs_uv_en = 0, ++ .rrs_size_y = 16, ++ .rrs_size_c = 8, ++ .rrs_thrd_y = 624, ++ .rrs_thrd_u = 156, ++ .rrs_thrd_v = 156, ++ .skin_dt_en = 0, ++ .skin_lvl = 0, ++ .skin_cnt_thd = 20, ++ .skin_pxlu_thd = { ++ {100, 130, }, ++ {40, 110, }, ++ {120, 160, }, ++ }, ++ .skin_pxlv_thd = { ++ {140, 175, }, ++ {120, 155, }, ++ {165, 225, }, ++ }, ++ .skin_qp_ofst = { ++ -8, /*skin_qp_ofst[0]*/ ++ -4, /*skin_qp_ofst[1]*/ ++ -2, /*skin_qp_ofst[2]*/ ++ 1, /*skin_qp_ofst[3]*/ ++ }, ++ .mult_factor = { ++ 3, /*mult_factor[0]*/ ++ 9, /*mult_factor[1]*/ ++ 5, /*mult_factor[2]*/ ++ }, ++ .shift_factor = { ++ {3, 5, 8, }, ++ {4, 5, 6, }, ++ {4, 5, 6, }, ++ }, ++ .skin_ofst = { ++ 97, /*skin_ofst[0]*/ ++ 183, /*skin_ofst[1]*/ ++ 271, /*skin_ofst[2]*/ ++ 884, /*skin_ofst[3]*/ ++ }, ++ .ncu_mov_en = 0, ++ .ncu_move_len = 0, ++ .ncu_move_info = NULL, ++ .buf_share_en = 0, ++ .buf_share_size = 0, ++ .frame_idx = 2, ++}; diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264e.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264e.c.patch new file mode 100644 index 00000000..ad47260e --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264e.c.patch @@ -0,0 +1,918 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/helix/h264e.c b/drivers/media/platform/ingenic-vcodec/helix/h264e.c +--- a/drivers/media/platform/ingenic-vcodec/helix/h264e.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/helix/h264e.c 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,914 @@ ++/* ++* Copyright© 2014 Ingenic Semiconductor Co.,Ltd ++* ++* Author: qipengzhen ++* ++* 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. ++* ++*/ ++#include ++#include ++ ++#include "api/helix_x264_enc.h" ++ ++#include "h264enc/common.h" ++#include "h264enc/set.h" ++#include "h264e.h" ++ ++ ++static uint8_t cqm_8iy_tab[64] = { ++ 6+10,10+10,13+10,16+10,18+10,23+10,25+10,27+10, ++ 10+10,11+10,16+10,18+10,23+10,25+10,27+10,29+10, ++ 13+10,16+10,18+10,23+10,25+10,27+10,29+10,31+10, ++ 16+10,18+10,23+10,25+10,27+10,29+10,31+10,33+10, ++ 18+10,23+10,25+10,27+10,29+10,31+10,33+10,36+10, ++ 23+10,25+10,27+10,29+10,31+10,33+10,36+10,38+10, ++ 25+10,27+10,29+10,31+10,33+10,36+10,38+10,40+10, ++ 27+10,29+10,31+10,33+10,36+10,38+10,40+10,42+10 ++}; ++static uint8_t cqm_8py_tab[64] = { ++ 9+10,13+10,15+10,17+10,19+10,21+10,22+10,24+10, ++ 13+10,13+10,17+10,19+10,21+10,22+10,24+10,25+10, ++ 15+10,17+10,19+10,21+10,22+10,24+10,25+10,27+10, ++ 17+10,19+10,21+10,22+10,24+10,25+10,27+10,28+10, ++ 19+10,21+10,22+10,24+10,25+10,27+10,28+10,30+10, ++ 21+10,22+10,24+10,25+10,27+10,28+10,30+10,32+10, ++ 22+10,24+10,25+10,27+10,28+10,30+10,32+10,33+10, ++ 24+10,25+10,27+10,28+10,30+10,32+10,33+10,35+10 ++}; ++ ++ ++/* static int rc_deadzone[9] = {0x1d,0x12,0x15,0xb,0x1d,0x12,0x1d,0x15,0xb}; */ ++static uint16_t rc_skin_ofst[4] = {97, 183, 271, 884};//[0]: 1.5, [1]:0.4, [2]:0.6, [3]: 5.1 ++static uint8_t rc_mult_factor[3] = {3,9,5}; ++//static int8_t rc_skin_qp_ofst[4] = {-3, -2, -1, 0}; ++static int8_t rc_skin_qp_ofst[4] = {-6, -4, -2, 0}; ++static uint8_t rc_skin_pxlu_thd[3][2] = {{100, 120},{50, 100},{120, 150}}; ++static uint8_t rc_skin_pxlv_thd[3][2] = {{140, 175},{125, 140},{175, 225}}; ++static uint8_t rc_shift_factor[3][3] = {{3,5,8},{4,5,6},{4,5,6}};//[0][]:0.4, [1][]:0.6, [2][]: 5.1 ++ ++ ++ ++/*TODO: export to high level ????*/ ++int h264e_set_params(struct h264e_ctx *ctx, unsigned id, unsigned int val) ++{ ++ return 0; ++} ++ ++int h264e_get_params(struct h264e_ctx *ctx, int id) ++{ ++ //struct h264e_params *p = &ctx->p; ++ unsigned int val = 0; ++ /*switch*/ ++ ++ return val; ++} ++ ++int h264e_set_fmt(struct h264e_ctx *ctx, int width, int height, int format) ++{ ++ struct h264e_params *p = &ctx->p; ++ int ret = 0; ++ ++ p->width = width; ++ p->height = height; ++ switch(format) { ++ case HELIX_NV12_MODE: ++ case HELIX_NV21_MODE: ++ case HELIX_TILE_MODE: ++ p->format = format; ++ break; ++ default: ++ pr_err("Unsupported pix fmt: %x\n", format); ++ ret = -EINVAL; ++ break; ++ } ++ ++ ctx->framesize = width * height; ++ ++ return ret; ++} ++ ++//to profile_idc ++static int v4l2_profile(int i_profile_idc) ++{ ++ switch (i_profile_idc) { ++ case PROFILE_BASELINE: return V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE; ++ case PROFILE_MAIN: return V4L2_MPEG_VIDEO_H264_PROFILE_MAIN; ++ case PROFILE_HIGH10: return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10; ++ case PROFILE_HIGH422: return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422; ++ case PROFILE_HIGH444_PREDICTIVE: return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE; ++ default: return -EINVAL; ++ } ++ ++} ++ ++static int h264e_profile_idc(int v4l2_profile) ++{ ++ switch (v4l2_profile) { ++ case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE: return PROFILE_BASELINE; ++ case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN: return PROFILE_MAIN; ++ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10: return PROFILE_HIGH10; ++ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422: return PROFILE_HIGH422; ++ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE: return PROFILE_HIGH444_PREDICTIVE; ++ default: return -EINVAL; ++ } ++} ++ ++static int v4l2_h264_level(int i_level_idc) ++{ ++ switch (i_level_idc) { ++ case 10: return V4L2_MPEG_VIDEO_H264_LEVEL_1_0; ++ case 9: return V4L2_MPEG_VIDEO_H264_LEVEL_1B; ++ case 11: return V4L2_MPEG_VIDEO_H264_LEVEL_1_1; ++ case 12: return V4L2_MPEG_VIDEO_H264_LEVEL_1_2; ++ case 13: return V4L2_MPEG_VIDEO_H264_LEVEL_1_3; ++ case 20: return V4L2_MPEG_VIDEO_H264_LEVEL_2_0; ++ case 21: return V4L2_MPEG_VIDEO_H264_LEVEL_2_1; ++ case 22: return V4L2_MPEG_VIDEO_H264_LEVEL_2_2; ++ case 30: return V4L2_MPEG_VIDEO_H264_LEVEL_3_0; ++ case 31: return V4L2_MPEG_VIDEO_H264_LEVEL_3_1; ++ case 32: return V4L2_MPEG_VIDEO_H264_LEVEL_3_2; ++ case 40: return V4L2_MPEG_VIDEO_H264_LEVEL_4_0; ++ case 41: return V4L2_MPEG_VIDEO_H264_LEVEL_4_1; ++ default: return -EINVAL; ++ } ++} ++ ++static int h264e_level_idc(int level) ++{ ++ switch (level) { ++ case V4L2_MPEG_VIDEO_H264_LEVEL_1_0: return 10; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_1B: return 9; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_1_1: return 11; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_1_2: return 12; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_1_3: return 13; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_2_0: return 20; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_2_1: return 21; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_2_2: return 22; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_3_0: return 30; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_3_1: return 31; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_3_2: return 32; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_4_0: return 40; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_4_1: return 41; ++ default: return -EINVAL; ++ } ++} ++ ++/* ----------------------------- Picture Parameter Sets ---------------*/ ++static void h264e_sps_init(struct h264e_ctx *ctx, h264_sps_t *sps, int i_id) ++{ ++ struct h264e_params *p = &ctx->p; ++ int max_frame_num; ++ ++ sps->i_id = i_id; ++ sps->i_mb_width = C_ALIGN(p->width, 16) / 16; ++ sps->i_mb_height = C_ALIGN(p->height, 16) / 16; ++ sps->i_chroma_format_idc = CHROMA_420; //vpu格式决定的... ++ sps->b_qpprime_y_zero_transform_bypass = 0; //TODO,bool值,先设置为0.与rc有关,。。。 ++ sps->i_profile_idc = h264e_profile_idc(p->h264_profile); //要转换成协议规定的值 ++ sps->b_constraint_set0 = sps->i_profile_idc == PROFILE_BASELINE; //与profile有关的规定. ++ sps->b_constraint_set1 = sps->i_profile_idc <= PROFILE_MAIN; ++ sps->b_constraint_set2 = 0; ++ sps->b_constraint_set3 = 0; ++ ++ sps->i_level_idc = h264e_level_idc(p->h264_level); ++ if((sps->i_level_idc == 9) && (sps->i_profile_idc == PROFILE_BASELINE || sps->i_profile_idc == PROFILE_MAIN)) { ++ sps->b_constraint_set0 = 1; /* level 1b with Baseline or Main profile is signalled via constraint_set3 */ ++ sps->i_level_idc = 11; ++ } ++ ++ ++ sps->i_num_ref_frames = p->max_ref_pic; //参考帧数为一帧?是软件参数决定还是vpu硬件决定的。。 ++ ++ sps->vui.i_num_reorder_frames = 0; //TODO ++ sps->vui.i_max_dec_frame_buffering = sps->i_num_ref_frames; //TODO, 不知道vui是什么意思? ++ ++ max_frame_num = 1; /* TODO: Num of refs + current frame */ ++ sps->i_log2_max_frame_num = 4; ++ while((1 << sps->i_log2_max_frame_num) <= max_frame_num) ++ sps->i_log2_max_frame_num++; ++ ++ //sps->i_poc_type = p->num_bframe || p->interlaced ? 0 : 2; //TODO, 0个B帧,不支持场分离模式。这个应该是由vpu硬件决定的吧?, 最好还是从param传过来. ++ /*固定2,图像顺序与解码顺序一致.*/ ++ sps->i_poc_type = 2; //TODO, 0个B帧,不支持场分离模式。这个应该是由vpu硬件决定的吧?, 最好还是从param传过来. ++ ++ if(sps->i_poc_type == 0) { ++ /*目前不支持*/ ++ } ++ ++ sps->b_vui = 0; //vui信息可以从哪里来的??, 编码层用来干什么? ++ ++ sps->b_gaps_in_frame_num_value_allowed = 0; ++ sps->b_frame_mbs_only = 1; //不支持场分离模式. ++ if(!sps->b_frame_mbs_only) ++ sps->i_mb_height = (sps->i_mb_height + 1) & ~1; ++ sps->b_mb_adaptive_frame_field = p->interlaced; ++ sps->b_direct8x8_inference = 1; ++ sps->b_crop = 0; /*TODO .... From sw */ ++ ++ //TODO:干什么用的还不知道. ++// h264_sps_init_reconfigurable(sps, sw); ++ ++ ++ sps->vui.b_overscan_info_present = 0; ++ sps->vui.b_overscan_info = 0; ++ ++ sps->i_cqm_preset = 0; //使用flat16量化表?? ++ sps->b_avcintra = 0; //不处理这类的. seq_scaling_list_present_flag=0, 解码时应该推断出来.??怎么推断? ++ ++} ++ ++static void h264e_pps_init(struct h264e_ctx *ctx, h264_pps_t *pps, int i_id, h264_sps_t *sps) ++{ ++ struct h264e_params *p = &ctx->p; ++ ++ pps->i_id = i_id; ++ pps->i_sps_id = sps->i_id; ++ pps->b_cabac = p->i_cabac; ++ ++ pps->b_pic_order = 0; ++ pps->i_num_slice_groups = 1; /* base & main profile.*/ ++ ++ pps->i_num_ref_idx_l0_default_active = p->max_ref_pic; ++ pps->i_num_ref_idx_l1_default_active = 1; ++ ++ pps->b_weighted_pred = 0; ++ pps->b_weighted_bipred = 0; ++ ++ pps->i_pic_init_qp = 0; //TODO; ++ pps->i_pic_init_qs = 26; //TODO ++ ++ pps->i_chroma_qp_index_offset = 0; //TODO; ++ pps->b_deblocking_filter_control = 0; //TODO, 应该为1 ++ pps->b_constrained_intra_pred = 0; ++ pps->b_redundant_pic_cnt = 0; ++ ++ pps->b_transform_8x8_mode = p->h264_8x8_transform; //base and main 不支持,应该固定为0. ++} ++ ++ ++static int encapsulate_nal(bs_t *s, int s_off, char *dst, int i_type, int i_ref_idc) ++{ ++ ++ uint8_t *src = s->p_start + s_off; ++ uint8_t *end = src + (bs_pos(s) / 8); ++ char *orig_dst = dst; ++ ++ printk("======i_nal_type %d\n", i_type); ++ printk("======i_nal_ref_idc= %d\n", i_ref_idc); ++ printk("=====bs_pos(s) %d\n", bs_pos(s)); ++ ++ /* prefix */ ++ *dst++ = 0x00; ++ *dst++ = 0x00; ++ *dst++ = 0x00; ++ *dst++ = 0x01; ++ ++ /* nal header */ ++ *dst++ = (0 << 7) | (i_ref_idc << 5) | (i_type); ++ ++ ++ if(src < end) *dst++ = *src++; ++ if(src < end) *dst++ = *src++; ++ while( src < end ) ++ { ++ if( src[0] <= 0x03 && !dst[-2] && !dst[-1] ) ++ *dst++ = 0x03; ++ *dst++ = *src++; ++ } ++ ++ return dst - orig_dst; // 打包的总大小. framesize; ++} ++ ++/** ++* @h264e_generate_headers generate sps/pps headers according to params. ++* and store the header until encoder closed. ++* @ctx h264e_ctx. ++* ++* @Return 0 ++*/ ++int h264e_generate_headers(struct h264e_ctx *ctx) ++{ ++ //struct h264e_params *p = &ctx->p; ++ int framesize = ctx->framesize; ++ /* used to encode header for tmp.*/ ++ char *bs_tmp = NULL; ++ char *bs_header = ctx->bs_header; ++ bs_t bs; ++ int bs_size = 0; ++ h264_sps_t *sps = &ctx->sps; ++ h264_pps_t *pps = &ctx->pps; ++ ++ bs_tmp = kzalloc(framesize, GFP_KERNEL); ++ if(!bs_tmp) { ++ return -ENOMEM; ++ } ++ ++ h264e_sps_init(ctx, sps, 0); ++ h264e_pps_init(ctx, pps, 0, sps); ++ ++ /* 1. encode sps */ ++ bs_init(&bs, bs_tmp, framesize); ++ h264e_sps_write(&bs, sps); ++ ++ bs_size = encapsulate_nal(&bs, 0, bs_header, NAL_SPS, NAL_PRIORITY_HIGHEST); ++ ++ ctx->bs_header_size += bs_size; ++ bs_header += bs_size; ++ ++ /* 2. encode pps */ ++ bs_init(&bs, bs_tmp, framesize); ++ h264e_pps_write(&bs, sps, pps); ++ ++ bs_size = encapsulate_nal(&bs, 0, bs_header, NAL_PPS, NAL_PRIORITY_HIGHEST); ++ ctx->bs_header_size += bs_size; ++ bs_header += bs_size; ++ ++ ++ if(ctx->bs_header_size > (MAX_BS_HEADER_SIZE - 512)) { ++ pr_warn("bs_header buffer almost overflow!\n"); ++ } ++ ++ /* 3. encode sei */ ++ ++ /* 4. encode more */ ++ ++ /* release temp buffer. */ ++ kfree(bs_tmp); ++ return 0; ++} ++ ++static int h264e_slice_init(struct h264e_ctx * ctx, int i_nal_type) ++{ ++ if(i_nal_type == NAL_SLICE_IDR) { ++ ++ h264e_slice_header_init(&ctx->sh, &ctx->sps, &ctx->pps, ctx->p.i_idr_pic_id, ctx->i_frame, ctx->p.i_qp); ++ ctx->p.i_idr_pic_id ^= 1; ++ } else { ++ h264e_slice_header_init(&ctx->sh, &ctx->sps, &ctx->pps, -1, ctx->i_frame, ctx->p.p_qp); ++ ++ ctx->sh.i_num_ref_idx_l0_active = 1; ++ ctx->sh.i_num_ref_idx_l1_active = 1; ++ } ++ ++ return 0; ++} ++ ++void H264E_DumpInfo(_H264E_SliceInfo *s) ++{ ++ printk("s->des_va = 0x%08x\n", (unsigned int)s->des_va); ++ printk("s->des_pa = 0x%08x\n", s->des_pa); ++// printk("s->emc_bs_va = 0x%08x\n", s->emc_bs_va); ++ printk("s->emc_bs_pa = 0x%08x\n", s->emc_bs_pa); ++ printk("s->frame_type = 0x%x\n", s->frame_type); ++ printk("s->raw_format = %d\n", s->raw_format); ++ printk("s->mb_width = %d\n", s->mb_width); ++ printk("s->mb_height = %d\n", s->mb_height); ++ printk("s->first_mby = %d\n", s->first_mby); ++ printk("s->last_mby = %d\n", s->last_mby); ++ printk("s->frame_width = %d\n", s->frame_width); ++ printk("s->frame_height = %d\n", s->frame_height); ++ printk("s->stride[0] = %d\n", s->stride[0]); ++ printk("s->stride[1] = %d\n", s->stride[1]); ++ printk("s->state = %x\n", (unsigned int)s->state); ++ printk("s->raw[0] = 0x%08x\n", s->raw[0]); ++ printk("s->raw[1] = 0x%08x\n", s->raw[1]); ++ printk("s->raw[2] = 0x%08x\n", s->raw[2]); ++ printk("s->fb[0][0] = 0x%08x\n", s->fb[0][0]); ++ printk("s->fb[0][1] = 0x%08x\n", s->fb[0][1]); ++ printk("s->fb[1][0] = 0x%08x\n", s->fb[1][0]); ++ printk("s->fb[1][1] = 0x%08x\n", s->fb[1][1]); ++ printk("s->fb[2][0] = 0x%08x\n", s->fb[2][0]); ++ printk("s->fb[2][1] = 0x%08x\n", s->fb[2][1]); ++ printk("s->jh[0][0] = 0x%08x\n", s->jh[0][0]); ++ printk("s->jh[0][1] = 0x%08x\n", s->jh[0][1]); ++ printk("s->jh[1][0] = 0x%08x\n", s->jh[1][0]); ++ printk("s->jh[1][1] = 0x%08x\n", s->jh[1][1]); ++ printk("s->jh[2][0] = 0x%08x\n", s->jh[2][0]); ++ printk("s->jh[2][1] = 0x%08x\n", s->jh[2][1]); ++ printk("s->spe_y_addr = 0x%08x\n", s->spe_y_addr); ++ printk("s->spe_c_addr = 0x%08x\n", s->spe_c_addr); ++ printk("s->emc_recon_pa= 0x%08x\n", s->emc_recon_pa); ++ printk("s->emc_qpt_pa = 0x%08x\n", s->emc_qpt_pa); ++ printk("s->emc_mv_pa = 0x%08x\n", s->emc_mv_pa); ++ printk("s->emc_se_pa = 0x%08x\n", s->emc_se_pa); ++ printk("s->emc_rc_pa = 0x%08x\n", s->emc_rc_pa); ++ printk("s->emc_cpx_pa = 0x%08x\n", s->emc_cpx_pa); ++ printk("s->emc_mod_pa = 0x%08x\n", s->emc_mod_pa); ++ printk("s->emc_ncu_pa = 0x%08x\n", s->emc_ncu_pa); ++ printk("s->emc_sad_pa = 0x%08x\n", s->emc_sad_pa); ++} ++ ++ ++ ++/** ++* @h264e_fill_slice_info ++* ++* @ctx ++* @bs_off 指定vpu输出码流相对bs起始位置的偏移. ++* ++* @Return - ++*/ ++static int h264e_fill_slice_info(struct h264e_ctx *ctx, int bs_off) ++{ ++ int i = 0; ++ int ret = 0; ++ unsigned char bmap[3][3] = { ++ {0, 2, 1}, ++ {1, 0, 2}, ++ {2, 1, 0} ++ }; ++ ++ //unsigned char *bufidx = bmap[sw->i_frame % (sw->max_ref_pic + 1)]; /*TODO ,只参考一帧*/ ++ unsigned char *bufidx = bmap[ctx->i_frame % 3]; /*TODO ,只参考一帧*/ ++ H264E_SliceInfo_t *s = ctx->s; ++ ++ ++ h264_sps_t *sps = &ctx->sps; ++ //h264_pps_t *pps = &ctx->pps; ++ ++ /* 1. rc output [11] */ ++ { ++ s->mb_width = sps->i_mb_width; ++ s->mb_height = sps->i_mb_height; ++ ++ s->frame_type = ctx->sh.i_type == SLICE_TYPE_I ? 0:1; /*全部用I帧.*/ ++ s->first_mby = 0; ++ s->last_mby = s->mb_height - 1; ++ s->frame_width = ctx->p.width; ++ s->frame_height = ctx->p.height; ++ s->qp = ctx->sh.i_type == SLICE_TYPE_I ? ctx->p.i_qp : ctx->p.p_qp; /* 使用CBR码率控制.*/ ++ s->base_qp = s->qp; ++ s->max_qp = ctx->p.h264_max_qp; ++ s->min_qp = ctx->p.h264_min_qp; ++ } ++ ++ /*2. motion cfg [25]*/ ++ { ++ } ++ ++ /*3. quant cfg [4]*/ ++ { ++ s->dct8x8_en = 0; ++ /*TODO: 既然是常量,没必要每次都更改,放到初始化更合适?*/ ++ memset(s->scaling_list, 0x10, sizeof(s->scaling_list)); ++ memcpy(s->scaling_list8[0], cqm_8iy_tab, sizeof(uint8_t) * 64); ++ memcpy(s->scaling_list8[1], cqm_8py_tab, sizeof(uint8_t) * 64); ++ ++ /*TODO: deadzone 是如何得到的?*/ ++ //s->deadzone[0] = ; ++ //s->deadzone[1] = ; ++ //s->deadzone[2] = ; ++ //s->deadzone[3] = ; ++ //s->deadzone[4] = ; ++ //s->deadzone[5] = ; ++ //s->deadzone[6] = ; ++ //s->deadzone[7] = ; ++ //s->deadzone[8] = ; ++ } ++ /*4.loop filter cfg [4] */ ++ { ++ s->deblock = ctx->p.deblock; ++ s->rotate = 0; ++ s->alpha_c0_offset = 0; ++ s->beta_offset = 0; ++ } ++ ++ /*11. skin judge cfg[14]*/ ++ { ++ /*TODO.*/ ++ s->skin_dt_en = 0; //sipe->skin_dt_en; ++ s->skin_lvl = 0; //sipe->skin_lvl; ++ s->skin_cnt_thd = 20; //sipe->skin_cnt_thd; ++ s->ncu_mov_en = 0; ++ s->ncu_move_len = 20; ++ s->ncu_move_info = NULL; ++ s->buf_share_en = 0; ++ s->buf_share_size = 0; ++ s->frame_idx = 0; ++ //s->is_first_Pframe = 0; ++ ++ memcpy(s->skin_pxlu_thd, rc_skin_pxlu_thd, sizeof(s->skin_pxlu_thd)); ++ memcpy(s->skin_pxlv_thd, rc_skin_pxlv_thd, sizeof(s->skin_pxlv_thd)); ++ memcpy(s->skin_qp_ofst, rc_skin_qp_ofst, sizeof(s->skin_qp_ofst)); ++ memcpy(s->mult_factor, rc_mult_factor, sizeof(s->mult_factor)); ++ memcpy(s->shift_factor, rc_shift_factor, sizeof(s->shift_factor)); ++ memcpy(s->skin_ofst, rc_skin_ofst, sizeof(s->skin_ofst)); ++ } ++ ++ s->state = ctx->cb.state; ++ /*输出码流.*/ ++ /*新版硬件使用emc_bs替换了bs*/ ++ s->raw_format = ctx->p.format; ++ s->stride[0] = s->frame_width; /*Y SRIDE*/ ++ s->stride[1] = s->raw_format == HELIX_420P_MODE ? ++ s->frame_width / 2 : s->frame_width; ++ /*VPU输入, CPU输出*/ ++ for(i = 0; i < ctx->frame->num_planes; i++) { ++ s->raw[i] = ctx->frame->fb_addr[i].pa; ++ printk("raw.pa %x\n", ctx->frame->fb_addr[i].pa); ++ printk("raw.va %x\n", (unsigned int)ctx->frame->fb_addr[i].va); ++ } ++ ++ /* ++ s->fb[0][0], --> 当前帧输出重构帧y ++ s->fb[0][1], --> 当前帧输出重构帧c,与输入raw数据接近一致 ++ s->fb[1][0], --> 当前帧的参考帧y, I帧没有参考帧,P帧参考前一帧. ++ s->fb[1][1], --> 当前帧的参考帧c ++ s->fb[2][0], --> 前两帧, 当前mref开启时使用. ++ s->fb[2][1], ++ ++ I 帧 I P P P ++ s->fb[0][0] = sw->fb[0][0] 0->1->2 ++ s->fb[1][0] = ? 0->1->2 ++ s->fb[2][0] = ? 0->1->2 ++ P 帧 ++ s->fb[0][0] = sw->fb[1][0] ++ s->fb[1][0] = sw->fb[0][0] ++ s->fb[2][0] = ? ++ P 帧 ++ s->fb[0][0] = sw->fb[2][0] ++ s->fb[1][0] = sw->fb[1][0] ++ s->fb[2][0] = sw->fb[0][0] ++ */ ++ ++ for(i = 0; i < 3; i++) { ++ s->fb[i][0] = ctx->fb[bufidx[i]].yaddr_pa; ++ s->fb[i][1] = ctx->fb[bufidx[i]].caddr_pa; ++#if 0 ++ s->jh[i][0] = sw->fb[bufidx[i]].yaddr_pa; ++ s->jh[i][1] = sw->fb[bufidx[i]].caddr_pa; ++#endif ++ } ++ ++ s->des_va = ctx->desc; ++ s->des_pa = ctx->desc_pa; ++ ++ /*VPU输出,CPU输入*/ ++ //s->emc_bs_va = sw->bs_tmp_buf.va + bs_off; ++ /*TODO , replace this to bs in X2000 chips. bs->va or bs->pa*/ ++ s->emc_bs_pa = ctx->bs_tmp_buf.pa + bs_off; ++ ++ /*VPU使用?*/ ++ s->emc_dblk_va = ctx->emc_buf; ++ s->emc_recon_va = s->emc_dblk_va + DBLK_SIZE; ++ s->emc_mv_va = s->emc_recon_va + RECON_SIZE; ++ s->emc_se_va = s->emc_mv_va + MV_SIZE; ++ s->emc_qpt_va = s->emc_se_va + SE_SIZE; ++ s->emc_rc_va = s->emc_qpt_va + QPT_SIZE; ++ s->emc_cpx_va = s->emc_rc_va + RC_SIZE; ++ s->emc_mod_va = s->emc_cpx_va + CPX_SIZE; ++ s->emc_sad_va = s->emc_mod_va + MOD_SIZE; ++ s->emc_ncu_va = s->emc_sad_va + SAD_SIZE; ++ ++ s->emc_dblk_pa = ctx->emc_buf_pa; ++ s->emc_recon_pa = s->emc_dblk_pa + DBLK_SIZE; ++ s->emc_mv_pa = s->emc_recon_pa + RECON_SIZE; ++ s->emc_se_pa = s->emc_mv_pa + MV_SIZE; ++ s->emc_qpt_pa = s->emc_se_pa + SE_SIZE; ++ s->emc_rc_pa = s->emc_qpt_pa + QPT_SIZE; ++ s->emc_cpx_pa = s->emc_rc_pa + RC_SIZE; ++ s->emc_mod_pa = s->emc_cpx_pa + CPX_SIZE; ++ s->emc_sad_pa = s->emc_mod_pa + MOD_SIZE; ++ s->emc_ncu_pa = s->emc_sad_pa + SAD_SIZE; ++ ++ ++ H264E_SliceInit(s); ++ H264E_DumpInfo(s); ++ ++ /*TODO: 当使用非一致性缓存时,需要刷cache, 未来是要改成非一致性缓存的.*/ ++ //dma_cache_wback_inv(ctx->desc, ctx->vdma_chain_len); ++ ++ return ret; ++} ++ ++static int h264e_encode_slice(struct h264e_ctx *ctx, int force_idr, int *keyframe) ++{ ++ int idr = 0; ++ int i_nal_type = 0; ++ int i_nal_ref_idc = 0; ++ bs_t bs; ++ int ret = 0; ++ int tmp_align; ++ ++ /*decide I/P Frame*/ ++ if(!(ctx->i_frame % ctx->p.gop_size) || force_idr) { ++ ctx->i_frame = 0; ++ idr = 1; ++ } ++ ++ /* only I/P support.*/ ++ if(idr) { ++ i_nal_type = NAL_SLICE_IDR; ++ i_nal_ref_idc = NAL_PRIORITY_HIGHEST; ++ ctx->sh.i_type = SLICE_TYPE_I; ++ *keyframe = 1; ++ } else { ++ i_nal_type = NAL_SLICE; ++ i_nal_ref_idc = NAL_PRIORITY_HIGH; ++ ctx->sh.i_type = SLICE_TYPE_P; ++ //ctx->sh.i_type = SLICE_TYPE_I; ++ *keyframe = 0; ++ } ++ ++ /* TODO: replace bs_tmp_buf.va to bs.va*/ ++ bs_init(&bs, ctx->bs_tmp_buf.va, ctx->bs_tmp_buf.size); ++ ++ ret = h264e_slice_init(ctx, i_nal_type); ++ if(ret < 0) ++ return ret; ++ ++ h264e_slice_header_write(&bs, &ctx->sh, i_nal_ref_idc); ++ ++ if(ctx->p.i_cabac) { ++ bs_align_1(&bs); ++ h264_cabac_context_init(&ctx->cb, ctx->sh.i_type, ctx->sh.i_qp_delta, ctx->sh.i_cabac_init_idc); ++ } ++ ++ /*由于VPU可能不支持动态插入0x03的处理,暂时输出到tmp_bs_buf后插入0x03*/ ++ tmp_align = 256; ++ /*TODO , 假设了slice_header小于256 bytes.*/ ++ h264e_fill_slice_info(ctx, tmp_align); ++ /*fill slice info*/ ++ ++ ret = ingenic_vpu_start(ctx->priv); ++ if(ret < 0) { ++ return ret; ++ } ++ ++ /*编码后处理.*/ ++ if(bs.i_left == 32) { ++ memcpy(bs.p, ctx->bs_tmp_buf.va + tmp_align, ctx->encoded_bs_len); ++ bs.p += ctx->encoded_bs_len; ++ } else { ++ ++ int len = ctx->encoded_bs_len; ++ volatile unsigned char *p = ctx->bs_tmp_buf.va + tmp_align; ++ ++ while(len --) { ++ bs_write(&bs, 8, *p++); ++ } ++ bs_rbsp_trailing(&bs); ++ } ++ ++ /* 修正 encoded_bs_len, 包含0x03的插入.*/ ++ ctx->encoded_bs_len = encapsulate_nal(&bs, 0, ctx->bs->va, i_nal_type, i_nal_ref_idc); ++ ++ printk("-----h264e_ctx->r_bs_len %d\n", ctx->r_bs_len); ++ printk("-----h264e_ctx->encoded_bs_len: %d\n", ctx->encoded_bs_len); ++ /*done!*/ ++ ++ ctx->i_frame++; ++ ctx->frameindex++; ++ ++ return ret; ++} ++ ++/* add 0xff nal .*/ ++static int h264e_filler_nal(int size, char *p) ++{ ++ if (size < 6) ++ return -EINVAL; ++ ++ p[0] = 0x00; ++ p[1] = 0x00; ++ p[2] = 0x00; ++ p[3] = 0x01; ++ p[4] = 0x0c; ++ memset(p + 5, 0xff, size - 6); ++ /* Add rbsp stop bit and trailing at the end */ ++ p[size - 1] = 0x80; ++ ++ return 0; ++} ++ ++static int h264e_padding(int size, char *p) ++{ ++ int ret = 0; ++ ++ if(size == 0) ++ return 0; ++ ++ ret = h264e_filler_nal(size, p); ++ if(ret < 0) ++ return ret; ++ ++ return size; ++} ++ ++int h264e_encode_headers(struct h264e_ctx *ctx, struct ingenic_vcodec_mem *bs) ++{ ++ int ret = 0; ++ unsigned int align = 0; ++ ++ if(ctx->encoded_bs_len != 0) { ++ pr_info("set encoded_bs_len to 0 before encode!\n"); ++ } ++ ++ printk("----%s, %d, ctx->bs_header_size: %d\n", __func__, __LINE__, ctx->bs_header_size); ++ memcpy(bs->va, ctx->bs_header, ctx->bs_header_size); ++ ++ /*align to 256*/ ++ align = (ctx->bs_header_size + 255) / 256 * 256; ++ ++ ++ ret = h264e_padding(align - ctx->bs_header_size, bs->va + ctx->bs_header_size); ++ ++ ctx->encoded_bs_len = align; ++ ++ return ret; ++} ++ ++/* ++ input: ++ @h264e_ctx ++ @vframe_buffer ++ output: ++ @bs_buffer ++ @keyframe ++*/ ++int h264e_encode(struct h264e_ctx *ctx, struct video_frame_buffer *frame, ++ struct ingenic_vcodec_mem *bs, int *keyframe) ++{ ++ int ret = 0; ++ ctx->frame = frame; ++ ctx->bs = bs; ++ ++ ret = h264e_encode_slice(ctx, 0, keyframe); ++ ++ /* output bistream */ ++ ++ return ret; ++} ++ ++ ++ ++/* start streaming.*/ ++int h264e_alloc_workbuf(struct h264e_ctx *ctx) ++{ ++ int allocate_fb = 0; ++ int ret = 0; ++ int i = 0; ++ ++ pr_info("----%s, %d\n", __func__, __LINE__); ++ ++ ctx->bs_header = kzalloc(MAX_BS_HEADER_SIZE, GFP_KERNEL); ++ if(!ctx->bs_header) { ++ pr_err("Failed to alloc memory for bs_header\n"); ++ return -ENOMEM; ++ } ++ ctx->bs_header_size = 0; ++ ++ ++ /* TODO, 使用非一致性申请方式.*/ ++ ctx->desc = dma_alloc_coherent(NULL, ctx->vdma_chain_len, &ctx->desc_pa, GFP_KERNEL); ++ if(!ctx->desc) { ++ pr_err("Failed to alloc vpu desc buffer!\n"); ++ ret = -ENOMEM; ++ goto err_desc; ++ } ++ ++ /* TODO: 使用非一致性内存,这些内存分配完只给VPU使用,所以也无所谓.*/ ++ for(i = 0; i < 3; i++) { ++ ctx->fb[i].yaddr = dma_alloc_coherent(NULL, ctx->framesize, &ctx->fb[i].yaddr_pa, GFP_KERNEL); ++ ctx->fb[i].caddr = dma_alloc_coherent(NULL, ctx->framesize/2, &ctx->fb[i].caddr_pa, GFP_KERNEL); ++ ++ allocate_fb = i; ++ if(!ctx->fb[i].yaddr || !ctx->fb[i].caddr) { ++ ret = -ENOMEM; ++ goto err_fb; ++ } ++ printk("-------------ctx->fb[%d].yaddr: 0x%08x\n", i, (unsigned int)ctx->fb[i].yaddr); ++ printk("-------------ctx->fb[%d].caddr: 0x%08x\n", i, (unsigned int)ctx->fb[i].caddr); ++ } ++ ++ /*TODO: */ ++ ctx->emc_buf = dma_alloc_coherent(NULL, EMC_SIZE, &ctx->emc_buf_pa, GFP_KERNEL); ++ if(!ctx->emc_buf) { ++ pr_err("Failed to alloc vpu emc_buf!\n"); ++ ret = -ENOMEM; ++ goto err_emc_buf; ++ } ++ ++ ctx->bs_tmp_buf.size = ctx->framesize * 2; ++ ctx->bs_tmp_buf.va = dma_alloc_coherent(NULL, ctx->bs_tmp_buf.size, &ctx->bs_tmp_buf.pa, GFP_KERNEL); ++ if(!ctx->bs_tmp_buf.va) { ++ ret = -ENOMEM; ++ goto err_bs_tmp; ++ } ++ ++ return ret; ++ ++err_bs_tmp: ++ dma_free_coherent(NULL, EMC_SIZE, ctx->emc_buf, ctx->emc_buf_pa); ++err_emc_buf: ++err_fb: ++ i = allocate_fb; ++ while(i--) { ++ if(ctx->fb[i].yaddr) { ++ dma_free_coherent(NULL, ctx->framesize, ctx->fb[i].yaddr, ctx->fb[i].yaddr_pa); ++ } ++ if(ctx->fb[i].caddr) { ++ dma_free_coherent(NULL, ctx->framesize/2, ctx->fb[i].caddr, ctx->fb[i].caddr_pa); ++ } ++ } ++ ++err_desc: ++ kfree(ctx->bs_header); ++ ctx->bs_header = NULL; ++ ++ return ret; ++} ++ ++/* stop streaming.*/ ++int h264e_free_workbuf(struct h264e_ctx *ctx) ++{ ++ int i; ++ ++ kfree(ctx->bs_header); ++ dma_free_coherent(NULL, ctx->vdma_chain_len, ctx->desc, ctx->desc_pa); ++ dma_free_coherent(NULL, EMC_SIZE, ctx->emc_buf, ctx->emc_buf_pa); ++ ++ for(i = 0; i < 3; i++) { ++ dma_free_coherent(NULL, ctx->framesize, ctx->fb[i].yaddr, ctx->fb[i].yaddr_pa); ++ dma_free_coherent(NULL, ctx->framesize/2, ctx->fb[i].caddr, ctx->fb[i].caddr_pa); ++ } ++ ++ dma_free_coherent(NULL, ctx->bs_tmp_buf.size, ctx->bs_tmp_buf.va, ctx->bs_tmp_buf.pa); ++ ++ return 0; ++} ++ ++/*ctx init*/ ++/* TODO: 删除默认的结构体,想到一种方法可以修改默认的sliceinfo, ++方便调试, 比如导出sys节点?, 配合合肥已经调好的参数??*/ ++static void h264e_init_slice_info(H264E_SliceInfo_t *s) ++{ ++ memcpy(s, &default_H264E_Sliceinfo, sizeof(default_H264E_Sliceinfo)); ++} ++ ++int h264e_encoder_init(struct h264e_ctx *ctx) ++{ ++ struct h264e_params *p = NULL; ++ H264E_SliceInfo_t *s = NULL; ++ ++ /*TODO: 尽量减小h264e_ctx直接占用的内存大小,将占用大内存的数据结构使用动态分配.*/ ++ s = kzalloc(sizeof(H264E_SliceInfo_t), GFP_KERNEL); ++ if(!s) { ++ return -ENOMEM; ++ } ++ ++ p = &ctx->p; ++ ctx->s = s; ++ ++ /* default params. */ ++ ctx->vdma_chain_len = 40960 + 256; ++ ctx->frameindex = 0; ++ ctx->i_frame = 0; ++ ++ p->height = 240; ++ p->width = 160; ++ p->max_ref_pic = 1; ++ p->gop_size = 16; ++ p->i_idr_pic_id = 0; ++ p->i_global_qp = 26; ++ p->h264_profile = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE; ++ p->h264_level = V4L2_MPEG_VIDEO_H264_LEVEL_1_0; ++ p->i_cabac = 1; ++ p->interlaced = 0; ++ p->h264_8x8_transform = 0; ++ p->h264_hdr_mode = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME; ++ p->h264_min_qp = 0; ++ p->h264_max_qp = 51; ++ p->i_qp = 0; ++ p->p_qp = 26; ++ p->deblock = 0; ++ ++ h264_cabac_init(); ++ /*TODO: default sliceinfo*/ ++ ++ h264e_init_slice_info(s); ++ return 0; ++} ++ ++int h264e_encoder_deinit(struct h264e_ctx *ctx) ++{ ++ if(!ctx) ++ return 0; ++ ++ if(ctx->s) ++ kfree(ctx->s); ++ return 0; ++} ++ ++void h264e_set_priv(struct h264e_ctx *ctx, void *data) ++{ ++ ctx->priv = data; ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264e.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264e.h.patch new file mode 100644 index 00000000..4ba4835c --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264e.h.patch @@ -0,0 +1,134 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/helix/h264e.h b/drivers/media/platform/ingenic-vcodec/helix/h264e.h +--- a/drivers/media/platform/ingenic-vcodec/helix/h264e.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/helix/h264e.h 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,130 @@ ++#ifndef __H264E_H__ ++#define __H264E_H__ ++ ++#include "api/helix_x264_enc.h" ++ ++#include "h264enc/common.h" ++#include "helix_buf.h" ++ ++/** ++* @bitrate, set by V4L2_CID_MPEG_VIDEO_BITRATE. ++* @gop_size, group of picture when h264 encoding. ++*/ ++struct h264e_params { ++ ++ /* params modify by s_ctrl*/ ++ uint32_t bitrate; ++ uint32_t framerate; ++ int h264_hdr_mode; ++#if 0 ++ uint8_t h264_intra_qp; ++ uint8_t h264_inter_qp; ++#endif ++ uint8_t i_qp; ++ uint8_t p_qp; ++ uint8_t h264_min_qp; ++ uint8_t h264_max_qp; ++ uint8_t h264_profile; ++ uint8_t h264_level; ++ uint8_t gop_size; ++ uint8_t frame_rc_enable; ++ uint8_t mb_rc_enable; ++ uint8_t num_bframe; ++ uint8_t interlaced; ++ uint8_t max_ref_pic; ++ uint8_t h264_8x8_transform; ++ ++ uint8_t i_cabac; /*is cabac entropy?*/ ++ ++ int i_idr_pic_id; ++ int i_global_qp; ++ ++ uint8_t deblock; ++ ++ ++ ++ int height; ++ int width; ++ int format; ++ ++}; ++ ++ ++#define MAX_BS_HEADER_SIZE 4096 /* 4k maybe enough for header only.*/ ++ ++struct h264e_ctx { ++ unsigned char *bs_header; /* buffer to store sps/pps/sei headers. */ ++ unsigned int bs_header_size; /* buffer size. */ ++ ++ int vdma_chain_len; ++ unsigned int framesize; ++ /*根据height,width分配的,*/ ++ struct h264_ref_tile fb[3]; /*参考body buffer.按frame申请*/ ++ struct h264_ref_tile jh[3]; /*参考header buffer.按frame申请*/ ++ ++ unsigned int *emc_buf; /* 128KBytes固定空间*/ ++ dma_addr_t emc_buf_pa; ++ ++ unsigned int *desc; /* descriptor, 40960+256, 固定大小*/ ++ dma_addr_t desc_pa; ++ ++ ++ struct video_frame_buffer *frame; /* input picture frame. */ ++ struct ingenic_vcodec_mem *bs; /* output slice data. exclude slice header? */ ++ struct ingenic_vcodec_mem bs_tmp_buf; /* temperary buf for now., used to store vpu output buffer. then memory cp to userspace. */ ++ ++ unsigned int src_crc; /*Debug*/ ++ ++ ++ h264_sps_t sps; ++ h264_pps_t pps; ++ h264_slice_header_t sh; ++ h264_cabac_t cb; /*cabac state*/ ++ ++ int i_frame; /* (i_frame + 1) % gop_size */ ++ ++ /* modify after encode frame*/ ++ unsigned long frameindex; ++ unsigned int status; ++ unsigned int r_bs_len; /*result bs len.*/ ++ unsigned int encoded_bs_len; /* encoded bs_len */ ++ ++ struct h264e_params p; ++ H264E_SliceInfo_t *s; ++ ++ void *priv; ++}; ++ ++#define EMC_SIZE (1<<21) ++#define DBLK_SIZE (1 << 20) ++#define RECON_SIZE (1 << 18) ++#define MV_SIZE (1 << 11) ++#define SE_SIZE (1 << 11) ++#define QPT_SIZE (1<<14) ++#define RC_SIZE (1<<15) ++#define CPX_SIZE (1<<17) ++#define MOD_SIZE (1<<15) ++#define SAD_SIZE (1<<17) ++#define ENCU_SIZE (1<<13) ++#define BEYOND_MAX_SIZE 64*3 ++ ++ ++ ++extern int h264e_generate_headers(struct h264e_ctx *ctx); ++ ++extern int h264e_encode_headers(struct h264e_ctx *ctx, struct ingenic_vcodec_mem *bs); ++ ++extern int h264e_encode(struct h264e_ctx *ctx, struct video_frame_buffer *frame, struct ingenic_vcodec_mem *bs, int *keyframe); ++ ++extern int h264e_set_fmt(struct h264e_ctx *ctx, int width, int height, int format); ++extern int h264e_alloc_workbuf(struct h264e_ctx *ctx); ++ ++extern int h264e_free_workbuf(struct h264e_ctx *ctx); ++ ++extern int h264e_encoder_init(struct h264e_ctx *ctx); ++ ++extern int h264e_encoder_deinit(struct h264e_ctx *ctx); ++ ++extern void h264e_set_priv(struct h264e_ctx *ctx, void *data); ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_bitstream.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_bitstream.h.patch new file mode 100644 index 00000000..34b6ee31 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_bitstream.h.patch @@ -0,0 +1,246 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/helix/h264enc/bitstream.h b/drivers/media/platform/ingenic-vcodec/helix/h264enc/bitstream.h +--- a/drivers/media/platform/ingenic-vcodec/helix/h264enc/bitstream.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/helix/h264enc/bitstream.h 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,242 @@ ++#ifndef __BITSTREAM_H__ ++#define __BITSTREAM_H__ ++ ++typedef struct { ++ uint8_t *p_start; ++ uint8_t *p; ++ uint8_t *p_end; ++ ++ uintptr_t cur_bits; ++ int i_left; ++ int i_bits_encoded; ++} bs_t; ++ ++ ++ ++ ++/* Unions for type-punning. ++ * Mn: load or store n bits, aligned, native-endian ++ * CPn: copy n bits, aligned, native-endian ++ * we don't use memcpy for CPn because memcpy's args aren't assumed to be aligned */ ++typedef union { uint16_t i; uint8_t c[2]; } h264_union16_t; ++typedef union { uint32_t i; uint16_t b[2]; uint8_t c[4]; } h264_union32_t; ++typedef union { uint64_t i; uint32_t a[2]; uint16_t b[4]; uint8_t c[8]; } h264_union64_t; ++typedef struct { uint64_t i[2]; } h264_uint128_t; ++typedef union { h264_uint128_t i; uint64_t a[2]; uint32_t b[4]; uint16_t c[8]; uint8_t d[16]; } h264_union128_t; ++#define M16(src) (((h264_union16_t*)(src))->i) ++#define M32(src) (((h264_union32_t*)(src))->i) ++#define M64(src) (((h264_union64_t*)(src))->i) ++#define M128(src) (((h264_union128_t*)(src))->i) ++#define M128_ZERO ((h264_uint128_t){{0,0}}) ++#define CP16(dst,src) M16(dst) = M16(src) ++#define CP32(dst,src) M32(dst) = M32(src) ++#define CP64(dst,src) M64(dst) = M64(src) ++#define CP128(dst,src) M128(dst) = M128(src) ++ ++ ++ ++ ++/* ++ p_data必须按WORD地址对齐。 ++*/ ++static inline void bs_init(bs_t *s, void *p_data, int i_data) ++{ ++ s->p = s->p_start = (uint8_t *)p_data; ++ s->p_end = (uint8_t *)p_data + i_data; ++ s->i_left = WORD_SIZE * 8; ++ s->cur_bits = endian_fix32(M32(s->p)); ++ s->cur_bits >>= 32; ++} ++ ++static inline int bs_pos(bs_t *s) ++{ ++ return (8 * (s->p - s->p_start) + (WORD_SIZE*8) - s->i_left); ++} ++ ++static inline void bs_flush(bs_t *s) ++{ ++ M32( s->p ) = endian_fix32( s->cur_bits << (s->i_left&31) ); ++ s->p += WORD_SIZE - (s->i_left >> 3); ++ s->i_left = WORD_SIZE*8; ++} ++ ++static inline void bs_realign(bs_t *s) ++{ ++ int offset = ((intptr_t)s->p & 3); ++ if( offset ) ++ { ++ s->p = (uint8_t*)s->p - offset; ++ s->i_left = (WORD_SIZE - offset)*8; ++ s->cur_bits = endian_fix32( M32(s->p) ); ++ s->cur_bits >>= (4-offset)*8; ++ } ++} ++ ++static inline void bs_write( bs_t *s, int i_count, uint32_t i_bits ) ++{ ++ if( i_count < s->i_left ) ++ { ++ s->cur_bits = (s->cur_bits << i_count) | i_bits; ++ s->i_left -= i_count; ++ } ++ else ++ { ++ i_count -= s->i_left; ++ s->cur_bits = (s->cur_bits << s->i_left) | (i_bits >> i_count); ++ M32( s->p ) = endian_fix( s->cur_bits ); ++ s->p += 4; ++ s->cur_bits = i_bits; ++ s->i_left = 32 - i_count; ++ } ++} ++ ++ ++/* Special case to eliminate branch in normal bs_write. */ ++/* Golomb never writes an even-size code, so this is only used in slice headers. */ ++static inline void bs_write32( bs_t *s, uint32_t i_bits ) ++{ ++ bs_write( s, 16, i_bits >> 16 ); ++ bs_write( s, 16, i_bits ); ++} ++ ++static inline void bs_write1( bs_t *s, uint32_t i_bit ) ++{ ++ s->cur_bits <<= 1; ++ s->cur_bits |= i_bit; ++ s->i_left--; ++ if( s->i_left == WORD_SIZE*8-32 ) ++ { ++ M32( s->p ) = endian_fix32( s->cur_bits ); ++ s->p += 4; ++ s->i_left = WORD_SIZE*8; ++ } ++} ++ ++static inline void bs_align_0( bs_t *s ) ++{ ++ bs_write( s, s->i_left&7, 0 ); ++ bs_flush( s ); ++} ++static inline void bs_align_1( bs_t *s ) ++{ ++ bs_write( s, s->i_left&7, (1 << (s->i_left&7)) - 1 ); ++ bs_flush( s ); ++} ++static inline void bs_align_10( bs_t *s ) ++{ ++ if( s->i_left&7 ) ++ bs_write( s, s->i_left&7, 1 << ( (s->i_left&7) - 1 ) ); ++ bs_flush( s ); ++} ++ ++/* golomb functions */ ++ ++static const uint8_t x264_ue_size_tab[256] = ++{ ++ 1, 1, 3, 3, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 7, 7, ++ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, ++ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, ++ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, ++ 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, ++ 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, ++ 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, ++ 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, ++ 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, ++ 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, ++ 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, ++ 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, ++ 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, ++ 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, ++ 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, ++ 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, ++}; ++ ++static inline void bs_write_ue_big( bs_t *s, unsigned int val ) ++{ ++ int size = 0; ++ int tmp = ++val; ++ if( tmp >= 0x10000 ) ++ { ++ size = 32; ++ tmp >>= 16; ++ } ++ if( tmp >= 0x100 ) ++ { ++ size += 16; ++ tmp >>= 8; ++ } ++ size += x264_ue_size_tab[tmp]; ++ bs_write( s, size>>1, 0 ); ++ bs_write( s, (size>>1)+1, val ); ++} ++ ++/* Only works on values under 255. */ ++static inline void bs_write_ue( bs_t *s, int val ) ++{ ++ bs_write( s, x264_ue_size_tab[val+1], val+1 ); ++} ++static inline void bs_write_se( bs_t *s, int val ) ++{ ++ int size = 0; ++ /* Faster than (val <= 0 ? -val*2+1 : val*2) */ ++ /* 4 instructions on x86, 3 on ARM */ ++ int tmp = 1 - val*2; ++ if( tmp < 0 ) tmp = val*2; ++ val = tmp; ++ ++ if( tmp >= 0x100 ) ++ { ++ size = 16; ++ tmp >>= 8; ++ } ++ size += x264_ue_size_tab[tmp]; ++ bs_write( s, size, val ); ++} ++ ++static inline void bs_write_te( bs_t *s, int x, int val ) ++{ ++ if( x == 1 ) ++ bs_write1( s, 1^val ); ++ else //if( x > 1 ) ++ bs_write_ue( s, val ); ++} ++ ++static inline void bs_rbsp_trailing( bs_t *s ) ++{ ++ bs_write1( s, 1 ); ++ bs_write( s, s->i_left&7, 0 ); ++} ++ ++static inline int bs_size_ue( unsigned int val ) ++{ ++ return x264_ue_size_tab[val+1]; ++} ++ ++static inline int bs_size_ue_big( unsigned int val ) ++{ ++ if( val < 255 ) ++ return x264_ue_size_tab[val+1]; ++ else ++ return x264_ue_size_tab[(val+1)>>8] + 16; ++} ++ ++static inline int bs_size_se( int val ) ++{ ++ int tmp = 1 - val*2; ++ if( tmp < 0 ) tmp = val*2; ++ if( tmp < 256 ) ++ return x264_ue_size_tab[tmp]; ++ else ++ return x264_ue_size_tab[tmp>>8]+16; ++} ++ ++static inline int bs_size_te( int x, int val ) ++{ ++ if( x == 1 ) ++ return 1; ++ else //if( x > 1 ) ++ return x264_ue_size_tab[val+1]; ++} ++ ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_cabac.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_cabac.c.patch new file mode 100644 index 00000000..65d651fa --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_cabac.c.patch @@ -0,0 +1,1366 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/helix/h264enc/cabac.c b/drivers/media/platform/ingenic-vcodec/helix/h264enc/cabac.c +--- a/drivers/media/platform/ingenic-vcodec/helix/h264enc/cabac.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/helix/h264enc/cabac.c 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,1362 @@ ++/***************************************************************************** ++ * cabac.c: arithmetic coder ++ * copy from x264 project ++ ***************************************************************************** ++ * Copyright (C) 2003-2014 x264 project ++ * ++ * Authors: Laurent Aimar ++ * Loren Merritt ++ * Fiona Glaser ++ * ++ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. ++ * ++ * This program is also available under a commercial proprietary license. ++ * For more information, contact us at licensing@x264.com. ++ *****************************************************************************/ ++ ++#include "common.h" ++ ++static const int8_t h264_cabac_context_init_I[1024][2] = ++{ ++ /* 0 - 10 */ ++ { 20, -15 }, { 2, 54 }, { 3, 74 }, { 20, -15 }, ++ { 2, 54 }, { 3, 74 }, { -28,127 }, { -23, 104 }, ++ { -6, 53 }, { -1, 54 }, { 7, 51 }, ++ ++ /* 11 - 23 unused for I */ ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ { 0, 0 }, ++ ++ /* 24- 39 */ ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ ++ /* 40 - 53 */ ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ { 0, 0 }, { 0, 0 }, ++ ++ /* 54 - 59 */ ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ { 0, 0 }, { 0, 0 }, ++ ++ /* 60 - 69 */ ++ { 0, 41 }, { 0, 63 }, { 0, 63 }, { 0, 63 }, ++ { -9, 83 }, { 4, 86 }, { 0, 97 }, { -7, 72 }, ++ { 13, 41 }, { 3, 62 }, ++ ++ /* 70 -> 87 */ ++ { 0, 11 }, { 1, 55 }, { 0, 69 }, { -17, 127 }, ++ { -13, 102 },{ 0, 82 }, { -7, 74 }, { -21, 107 }, ++ { -27, 127 },{ -31, 127 },{ -24, 127 }, { -18, 95 }, ++ { -27, 127 },{ -21, 114 },{ -30, 127 }, { -17, 123 }, ++ { -12, 115 },{ -16, 122 }, ++ ++ /* 88 -> 104 */ ++ { -11, 115 },{ -12, 63 }, { -2, 68 }, { -15, 84 }, ++ { -13, 104 },{ -3, 70 }, { -8, 93 }, { -10, 90 }, ++ { -30, 127 },{ -1, 74 }, { -6, 97 }, { -7, 91 }, ++ { -20, 127 },{ -4, 56 }, { -5, 82 }, { -7, 76 }, ++ { -22, 125 }, ++ ++ /* 105 -> 135 */ ++ { -7, 93 }, { -11, 87 }, { -3, 77 }, { -5, 71 }, ++ { -4, 63 }, { -4, 68 }, { -12, 84 }, { -7, 62 }, ++ { -7, 65 }, { 8, 61 }, { 5, 56 }, { -2, 66 }, ++ { 1, 64 }, { 0, 61 }, { -2, 78 }, { 1, 50 }, ++ { 7, 52 }, { 10, 35 }, { 0, 44 }, { 11, 38 }, ++ { 1, 45 }, { 0, 46 }, { 5, 44 }, { 31, 17 }, ++ { 1, 51 }, { 7, 50 }, { 28, 19 }, { 16, 33 }, ++ { 14, 62 }, { -13, 108 },{ -15, 100 }, ++ ++ /* 136 -> 165 */ ++ { -13, 101 },{ -13, 91 }, { -12, 94 }, { -10, 88 }, ++ { -16, 84 }, { -10, 86 }, { -7, 83 }, { -13, 87 }, ++ { -19, 94 }, { 1, 70 }, { 0, 72 }, { -5, 74 }, ++ { 18, 59 }, { -8, 102 }, { -15, 100 }, { 0, 95 }, ++ { -4, 75 }, { 2, 72 }, { -11, 75 }, { -3, 71 }, ++ { 15, 46 }, { -13, 69 }, { 0, 62 }, { 0, 65 }, ++ { 21, 37 }, { -15, 72 }, { 9, 57 }, { 16, 54 }, ++ { 0, 62 }, { 12, 72 }, ++ ++ /* 166 -> 196 */ ++ { 24, 0 }, { 15, 9 }, { 8, 25 }, { 13, 18 }, ++ { 15, 9 }, { 13, 19 }, { 10, 37 }, { 12, 18 }, ++ { 6, 29 }, { 20, 33 }, { 15, 30 }, { 4, 45 }, ++ { 1, 58 }, { 0, 62 }, { 7, 61 }, { 12, 38 }, ++ { 11, 45 }, { 15, 39 }, { 11, 42 }, { 13, 44 }, ++ { 16, 45 }, { 12, 41 }, { 10, 49 }, { 30, 34 }, ++ { 18, 42 }, { 10, 55 }, { 17, 51 }, { 17, 46 }, ++ { 0, 89 }, { 26, -19 }, { 22, -17 }, ++ ++ /* 197 -> 226 */ ++ { 26, -17 }, { 30, -25 }, { 28, -20 }, { 33, -23 }, ++ { 37, -27 }, { 33, -23 }, { 40, -28 }, { 38, -17 }, ++ { 33, -11 }, { 40, -15 }, { 41, -6 }, { 38, 1 }, ++ { 41, 17 }, { 30, -6 }, { 27, 3 }, { 26, 22 }, ++ { 37, -16 }, { 35, -4 }, { 38, -8 }, { 38, -3 }, ++ { 37, 3 }, { 38, 5 }, { 42, 0 }, { 35, 16 }, ++ { 39, 22 }, { 14, 48 }, { 27, 37 }, { 21, 60 }, ++ { 12, 68 }, { 2, 97 }, ++ ++ /* 227 -> 251 */ ++ { -3, 71 }, { -6, 42 }, { -5, 50 }, { -3, 54 }, ++ { -2, 62 }, { 0, 58 }, { 1, 63 }, { -2, 72 }, ++ { -1, 74 }, { -9, 91 }, { -5, 67 }, { -5, 27 }, ++ { -3, 39 }, { -2, 44 }, { 0, 46 }, { -16, 64 }, ++ { -8, 68 }, { -10, 78 }, { -6, 77 }, { -10, 86 }, ++ { -12, 92 }, { -15, 55 }, { -10, 60 }, { -6, 62 }, ++ { -4, 65 }, ++ ++ /* 252 -> 275 */ ++ { -12, 73 }, { -8, 76 }, { -7, 80 }, { -9, 88 }, ++ { -17, 110 },{ -11, 97 }, { -20, 84 }, { -11, 79 }, ++ { -6, 73 }, { -4, 74 }, { -13, 86 }, { -13, 96 }, ++ { -11, 97 }, { -19, 117 },{ -8, 78 }, { -5, 33 }, ++ { -4, 48 }, { -2, 53 }, { -3, 62 }, { -13, 71 }, ++ { -10, 79 }, { -12, 86 }, { -13, 90 }, { -14, 97 }, ++ ++ /* 276 a bit special (not used, h264_cabac_encode_bypass is used instead) */ ++ { 0, 0 }, ++ ++ /* 277 -> 307 */ ++ { -6, 93 }, { -6, 84 }, { -8, 79 }, { 0, 66 }, ++ { -1, 71 }, { 0, 62 }, { -2, 60 }, { -2, 59 }, ++ { -5, 75 }, { -3, 62 }, { -4, 58 }, { -9, 66 }, ++ { -1, 79 }, { 0, 71 }, { 3, 68 }, { 10, 44 }, ++ { -7, 62 }, { 15, 36 }, { 14, 40 }, { 16, 27 }, ++ { 12, 29 }, { 1, 44 }, { 20, 36 }, { 18, 32 }, ++ { 5, 42 }, { 1, 48 }, { 10, 62 }, { 17, 46 }, ++ { 9, 64 }, { -12, 104 },{ -11, 97 }, ++ ++ /* 308 -> 337 */ ++ { -16, 96 }, { -7, 88 }, { -8, 85 }, { -7, 85 }, ++ { -9, 85 }, { -13, 88 }, { 4, 66 }, { -3, 77 }, ++ { -3, 76 }, { -6, 76 }, { 10, 58 }, { -1, 76 }, ++ { -1, 83 }, { -7, 99 }, { -14, 95 }, { 2, 95 }, ++ { 0, 76 }, { -5, 74 }, { 0, 70 }, { -11, 75 }, ++ { 1, 68 }, { 0, 65 }, { -14, 73 }, { 3, 62 }, ++ { 4, 62 }, { -1, 68 }, { -13, 75 }, { 11, 55 }, ++ { 5, 64 }, { 12, 70 }, ++ ++ /* 338 -> 368 */ ++ { 15, 6 }, { 6, 19 }, { 7, 16 }, { 12, 14 }, ++ { 18, 13 }, { 13, 11 }, { 13, 15 }, { 15, 16 }, ++ { 12, 23 }, { 13, 23 }, { 15, 20 }, { 14, 26 }, ++ { 14, 44 }, { 17, 40 }, { 17, 47 }, { 24, 17 }, ++ { 21, 21 }, { 25, 22 }, { 31, 27 }, { 22, 29 }, ++ { 19, 35 }, { 14, 50 }, { 10, 57 }, { 7, 63 }, ++ { -2, 77 }, { -4, 82 }, { -3, 94 }, { 9, 69 }, ++ { -12, 109 },{ 36, -35 }, { 36, -34 }, ++ ++ /* 369 -> 398 */ ++ { 32, -26 }, { 37, -30 }, { 44, -32 }, { 34, -18 }, ++ { 34, -15 }, { 40, -15 }, { 33, -7 }, { 35, -5 }, ++ { 33, 0 }, { 38, 2 }, { 33, 13 }, { 23, 35 }, ++ { 13, 58 }, { 29, -3 }, { 26, 0 }, { 22, 30 }, ++ { 31, -7 }, { 35, -15 }, { 34, -3 }, { 34, 3 }, ++ { 36, -1 }, { 34, 5 }, { 32, 11 }, { 35, 5 }, ++ { 34, 12 }, { 39, 11 }, { 30, 29 }, { 34, 26 }, ++ { 29, 39 }, { 19, 66 }, ++ ++ /* 399 -> 435 */ ++ { 31, 21 }, { 31, 31 }, { 25, 50 }, ++ { -17, 120 }, { -20, 112 }, { -18, 114 }, { -11, 85 }, ++ { -15, 92 }, { -14, 89 }, { -26, 71 }, { -15, 81 }, ++ { -14, 80 }, { 0, 68 }, { -14, 70 }, { -24, 56 }, ++ { -23, 68 }, { -24, 50 }, { -11, 74 }, { 23, -13 }, ++ { 26, -13 }, { 40, -15 }, { 49, -14 }, { 44, 3 }, ++ { 45, 6 }, { 44, 34 }, { 33, 54 }, { 19, 82 }, ++ { -3, 75 }, { -1, 23 }, { 1, 34 }, { 1, 43 }, ++ { 0, 54 }, { -2, 55 }, { 0, 61 }, { 1, 64 }, ++ { 0, 68 }, { -9, 92 }, ++ ++ /* 436 -> 459 */ ++ { -14, 106 }, { -13, 97 }, { -15, 90 }, { -12, 90 }, ++ { -18, 88 }, { -10, 73 }, { -9, 79 }, { -14, 86 }, ++ { -10, 73 }, { -10, 70 }, { -10, 69 }, { -5, 66 }, ++ { -9, 64 }, { -5, 58 }, { 2, 59 }, { 21, -10 }, ++ { 24, -11 }, { 28, -8 }, { 28, -1 }, { 29, 3 }, ++ { 29, 9 }, { 35, 20 }, { 29, 36 }, { 14, 67 }, ++ ++ /* 460 -> 1024 */ ++ { -17, 123 }, { -12, 115 }, { -16, 122 }, { -11, 115 }, ++ { -12, 63 }, { -2, 68 }, { -15, 84 }, { -13, 104 }, ++ { -3, 70 }, { -8, 93 }, { -10, 90 }, { -30, 127 }, ++ { -17, 123 }, { -12, 115 }, { -16, 122 }, { -11, 115 }, ++ { -12, 63 }, { -2, 68 }, { -15, 84 }, { -13, 104 }, ++ { -3, 70 }, { -8, 93 }, { -10, 90 }, { -30, 127 }, ++ { -7, 93 }, { -11, 87 }, { -3, 77 }, { -5, 71 }, ++ { -4, 63 }, { -4, 68 }, { -12, 84 }, { -7, 62 }, ++ { -7, 65 }, { 8, 61 }, { 5, 56 }, { -2, 66 }, ++ { 1, 64 }, { 0, 61 }, { -2, 78 }, { 1, 50 }, ++ { 7, 52 }, { 10, 35 }, { 0, 44 }, { 11, 38 }, ++ { 1, 45 }, { 0, 46 }, { 5, 44 }, { 31, 17 }, ++ { 1, 51 }, { 7, 50 }, { 28, 19 }, { 16, 33 }, ++ { 14, 62 }, { -13, 108 }, { -15, 100 }, { -13, 101 }, ++ { -13, 91 }, { -12, 94 }, { -10, 88 }, { -16, 84 }, ++ { -10, 86 }, { -7, 83 }, { -13, 87 }, { -19, 94 }, ++ { 1, 70 }, { 0, 72 }, { -5, 74 }, { 18, 59 }, ++ { -7, 93 }, { -11, 87 }, { -3, 77 }, { -5, 71 }, ++ { -4, 63 }, { -4, 68 }, { -12, 84 }, { -7, 62 }, ++ { -7, 65 }, { 8, 61 }, { 5, 56 }, { -2, 66 }, ++ { 1, 64 }, { 0, 61 }, { -2, 78 }, { 1, 50 }, ++ { 7, 52 }, { 10, 35 }, { 0, 44 }, { 11, 38 }, ++ { 1, 45 }, { 0, 46 }, { 5, 44 }, { 31, 17 }, ++ { 1, 51 }, { 7, 50 }, { 28, 19 }, { 16, 33 }, ++ { 14, 62 }, { -13, 108 }, { -15, 100 }, { -13, 101 }, ++ { -13, 91 }, { -12, 94 }, { -10, 88 }, { -16, 84 }, ++ { -10, 86 }, { -7, 83 }, { -13, 87 }, { -19, 94 }, ++ { 1, 70 }, { 0, 72 }, { -5, 74 }, { 18, 59 }, ++ { 24, 0 }, { 15, 9 }, { 8, 25 }, { 13, 18 }, ++ { 15, 9 }, { 13, 19 }, { 10, 37 }, { 12, 18 }, ++ { 6, 29 }, { 20, 33 }, { 15, 30 }, { 4, 45 }, ++ { 1, 58 }, { 0, 62 }, { 7, 61 }, { 12, 38 }, ++ { 11, 45 }, { 15, 39 }, { 11, 42 }, { 13, 44 }, ++ { 16, 45 }, { 12, 41 }, { 10, 49 }, { 30, 34 }, ++ { 18, 42 }, { 10, 55 }, { 17, 51 }, { 17, 46 }, ++ { 0, 89 }, { 26, -19 }, { 22, -17 }, { 26, -17 }, ++ { 30, -25 }, { 28, -20 }, { 33, -23 }, { 37, -27 }, ++ { 33, -23 }, { 40, -28 }, { 38, -17 }, { 33, -11 }, ++ { 40, -15 }, { 41, -6 }, { 38, 1 }, { 41, 17 }, ++ { 24, 0 }, { 15, 9 }, { 8, 25 }, { 13, 18 }, ++ { 15, 9 }, { 13, 19 }, { 10, 37 }, { 12, 18 }, ++ { 6, 29 }, { 20, 33 }, { 15, 30 }, { 4, 45 }, ++ { 1, 58 }, { 0, 62 }, { 7, 61 }, { 12, 38 }, ++ { 11, 45 }, { 15, 39 }, { 11, 42 }, { 13, 44 }, ++ { 16, 45 }, { 12, 41 }, { 10, 49 }, { 30, 34 }, ++ { 18, 42 }, { 10, 55 }, { 17, 51 }, { 17, 46 }, ++ { 0, 89 }, { 26, -19 }, { 22, -17 }, { 26, -17 }, ++ { 30, -25 }, { 28, -20 }, { 33, -23 }, { 37, -27 }, ++ { 33, -23 }, { 40, -28 }, { 38, -17 }, { 33, -11 }, ++ { 40, -15 }, { 41, -6 }, { 38, 1 }, { 41, 17 }, ++ { -17, 120 }, { -20, 112 }, { -18, 114 }, { -11, 85 }, ++ { -15, 92 }, { -14, 89 }, { -26, 71 }, { -15, 81 }, ++ { -14, 80 }, { 0, 68 }, { -14, 70 }, { -24, 56 }, ++ { -23, 68 }, { -24, 50 }, { -11, 74 }, { -14, 106 }, ++ { -13, 97 }, { -15, 90 }, { -12, 90 }, { -18, 88 }, ++ { -10, 73 }, { -9, 79 }, { -14, 86 }, { -10, 73 }, ++ { -10, 70 }, { -10, 69 }, { -5, 66 }, { -9, 64 }, ++ { -5, 58 }, { 2, 59 }, { 23, -13 }, { 26, -13 }, ++ { 40, -15 }, { 49, -14 }, { 44, 3 }, { 45, 6 }, ++ { 44, 34 }, { 33, 54 }, { 19, 82 }, { 21, -10 }, ++ { 24, -11 }, { 28, -8 }, { 28, -1 }, { 29, 3 }, ++ { 29, 9 }, { 35, 20 }, { 29, 36 }, { 14, 67 }, ++ { -3, 75 }, { -1, 23 }, { 1, 34 }, { 1, 43 }, ++ { 0, 54 }, { -2, 55 }, { 0, 61 }, { 1, 64 }, ++ { 0, 68 }, { -9, 92 }, { -17, 120 }, { -20, 112 }, ++ { -18, 114 }, { -11, 85 }, { -15, 92 }, { -14, 89 }, ++ { -26, 71 }, { -15, 81 }, { -14, 80 }, { 0, 68 }, ++ { -14, 70 }, { -24, 56 }, { -23, 68 }, { -24, 50 }, ++ { -11, 74 }, { -14, 106 }, { -13, 97 }, { -15, 90 }, ++ { -12, 90 }, { -18, 88 }, { -10, 73 }, { -9, 79 }, ++ { -14, 86 }, { -10, 73 }, { -10, 70 }, { -10, 69 }, ++ { -5, 66 }, { -9, 64 }, { -5, 58 }, { 2, 59 }, ++ { 23, -13 }, { 26, -13 }, { 40, -15 }, { 49, -14 }, ++ { 44, 3 }, { 45, 6 }, { 44, 34 }, { 33, 54 }, ++ { 19, 82 }, { 21, -10 }, { 24, -11 }, { 28, -8 }, ++ { 28, -1 }, { 29, 3 }, { 29, 9 }, { 35, 20 }, ++ { 29, 36 }, { 14, 67 }, { -3, 75 }, { -1, 23 }, ++ { 1, 34 }, { 1, 43 }, { 0, 54 }, { -2, 55 }, ++ { 0, 61 }, { 1, 64 }, { 0, 68 }, { -9, 92 }, ++ { -6, 93 }, { -6, 84 }, { -8, 79 }, { 0, 66 }, ++ { -1, 71 }, { 0, 62 }, { -2, 60 }, { -2, 59 }, ++ { -5, 75 }, { -3, 62 }, { -4, 58 }, { -9, 66 }, ++ { -1, 79 }, { 0, 71 }, { 3, 68 }, { 10, 44 }, ++ { -7, 62 }, { 15, 36 }, { 14, 40 }, { 16, 27 }, ++ { 12, 29 }, { 1, 44 }, { 20, 36 }, { 18, 32 }, ++ { 5, 42 }, { 1, 48 }, { 10, 62 }, { 17, 46 }, ++ { 9, 64 }, { -12, 104 }, { -11, 97 }, { -16, 96 }, ++ { -7, 88 }, { -8, 85 }, { -7, 85 }, { -9, 85 }, ++ { -13, 88 }, { 4, 66 }, { -3, 77 }, { -3, 76 }, ++ { -6, 76 }, { 10, 58 }, { -1, 76 }, { -1, 83 }, ++ { -6, 93 }, { -6, 84 }, { -8, 79 }, { 0, 66 }, ++ { -1, 71 }, { 0, 62 }, { -2, 60 }, { -2, 59 }, ++ { -5, 75 }, { -3, 62 }, { -4, 58 }, { -9, 66 }, ++ { -1, 79 }, { 0, 71 }, { 3, 68 }, { 10, 44 }, ++ { -7, 62 }, { 15, 36 }, { 14, 40 }, { 16, 27 }, ++ { 12, 29 }, { 1, 44 }, { 20, 36 }, { 18, 32 }, ++ { 5, 42 }, { 1, 48 }, { 10, 62 }, { 17, 46 }, ++ { 9, 64 }, { -12, 104 }, { -11, 97 }, { -16, 96 }, ++ { -7, 88 }, { -8, 85 }, { -7, 85 }, { -9, 85 }, ++ { -13, 88 }, { 4, 66 }, { -3, 77 }, { -3, 76 }, ++ { -6, 76 }, { 10, 58 }, { -1, 76 }, { -1, 83 }, ++ { 15, 6 }, { 6, 19 }, { 7, 16 }, { 12, 14 }, ++ { 18, 13 }, { 13, 11 }, { 13, 15 }, { 15, 16 }, ++ { 12, 23 }, { 13, 23 }, { 15, 20 }, { 14, 26 }, ++ { 14, 44 }, { 17, 40 }, { 17, 47 }, { 24, 17 }, ++ { 21, 21 }, { 25, 22 }, { 31, 27 }, { 22, 29 }, ++ { 19, 35 }, { 14, 50 }, { 10, 57 }, { 7, 63 }, ++ { -2, 77 }, { -4, 82 }, { -3, 94 }, { 9, 69 }, ++ { -12, 109 }, { 36, -35 }, { 36, -34 }, { 32, -26 }, ++ { 37, -30 }, { 44, -32 }, { 34, -18 }, { 34, -15 }, ++ { 40, -15 }, { 33, -7 }, { 35, -5 }, { 33, 0 }, ++ { 38, 2 }, { 33, 13 }, { 23, 35 }, { 13, 58 }, ++ { 15, 6 }, { 6, 19 }, { 7, 16 }, { 12, 14 }, ++ { 18, 13 }, { 13, 11 }, { 13, 15 }, { 15, 16 }, ++ { 12, 23 }, { 13, 23 }, { 15, 20 }, { 14, 26 }, ++ { 14, 44 }, { 17, 40 }, { 17, 47 }, { 24, 17 }, ++ { 21, 21 }, { 25, 22 }, { 31, 27 }, { 22, 29 }, ++ { 19, 35 }, { 14, 50 }, { 10, 57 }, { 7, 63 }, ++ { -2, 77 }, { -4, 82 }, { -3, 94 }, { 9, 69 }, ++ { -12, 109 }, { 36, -35 }, { 36, -34 }, { 32, -26 }, ++ { 37, -30 }, { 44, -32 }, { 34, -18 }, { 34, -15 }, ++ { 40, -15 }, { 33, -7 }, { 35, -5 }, { 33, 0 }, ++ { 38, 2 }, { 33, 13 }, { 23, 35 }, { 13, 58 }, ++ { -3, 71 }, { -6, 42 }, { -5, 50 }, { -3, 54 }, ++ { -2, 62 }, { 0, 58 }, { 1, 63 }, { -2, 72 }, ++ { -1, 74 }, { -9, 91 }, { -5, 67 }, { -5, 27 }, ++ { -3, 39 }, { -2, 44 }, { 0, 46 }, { -16, 64 }, ++ { -8, 68 }, { -10, 78 }, { -6, 77 }, { -10, 86 }, ++ { -12, 92 }, { -15, 55 }, { -10, 60 }, { -6, 62 }, ++ { -4, 65 }, { -12, 73 }, { -8, 76 }, { -7, 80 }, ++ { -9, 88 }, { -17, 110 }, { -3, 71 }, { -6, 42 }, ++ { -5, 50 }, { -3, 54 }, { -2, 62 }, { 0, 58 }, ++ { 1, 63 }, { -2, 72 }, { -1, 74 }, { -9, 91 }, ++ { -5, 67 }, { -5, 27 }, { -3, 39 }, { -2, 44 }, ++ { 0, 46 }, { -16, 64 }, { -8, 68 }, { -10, 78 }, ++ { -6, 77 }, { -10, 86 }, { -12, 92 }, { -15, 55 }, ++ { -10, 60 }, { -6, 62 }, { -4, 65 }, { -12, 73 }, ++ { -8, 76 }, { -7, 80 }, { -9, 88 }, { -17, 110 }, ++ { -3, 70 }, { -8, 93 }, { -10, 90 }, { -30, 127 }, ++ { -3, 70 }, { -8, 93 }, { -10, 90 }, { -30, 127 }, ++ { -3, 70 }, { -8, 93 }, { -10, 90 }, { -30, 127 } ++}; ++ ++static const int8_t h264_cabac_context_init_PB[3][1024][2] = ++{ ++ /* i_cabac_init_idc == 0 */ ++ { ++ /* 0 - 10 */ ++ { 20, -15 }, { 2, 54 }, { 3, 74 }, { 20, -15 }, ++ { 2, 54 }, { 3, 74 }, { -28, 127 }, { -23, 104 }, ++ { -6, 53 }, { -1, 54 }, { 7, 51 }, ++ ++ /* 11 - 23 */ ++ { 23, 33 }, { 23, 2 }, { 21, 0 }, { 1, 9 }, ++ { 0, 49 }, { -37, 118 }, { 5, 57 }, { -13, 78 }, ++ { -11, 65 }, { 1, 62 }, { 12, 49 }, { -4, 73 }, ++ { 17, 50 }, ++ ++ /* 24 - 39 */ ++ { 18, 64 }, { 9, 43 }, { 29, 0 }, { 26, 67 }, ++ { 16, 90 }, { 9, 104 }, { -46, 127 }, { -20, 104 }, ++ { 1, 67 }, { -13, 78 }, { -11, 65 }, { 1, 62 }, ++ { -6, 86 }, { -17, 95 }, { -6, 61 }, { 9, 45 }, ++ ++ /* 40 - 53 */ ++ { -3, 69 }, { -6, 81 }, { -11, 96 }, { 6, 55 }, ++ { 7, 67 }, { -5, 86 }, { 2, 88 }, { 0, 58 }, ++ { -3, 76 }, { -10, 94 }, { 5, 54 }, { 4, 69 }, ++ { -3, 81 }, { 0, 88 }, ++ ++ /* 54 - 59 */ ++ { -7, 67 }, { -5, 74 }, { -4, 74 }, { -5, 80 }, ++ { -7, 72 }, { 1, 58 }, ++ ++ /* 60 - 69 */ ++ { 0, 41 }, { 0, 63 }, { 0, 63 }, { 0, 63 }, ++ { -9, 83 }, { 4, 86 }, { 0, 97 }, { -7, 72 }, ++ { 13, 41 }, { 3, 62 }, ++ ++ /* 70 - 87 */ ++ { 0, 45 }, { -4, 78 }, { -3, 96 }, { -27, 126 }, ++ { -28, 98 }, { -25, 101 }, { -23, 67 }, { -28, 82 }, ++ { -20, 94 }, { -16, 83 }, { -22, 110 }, { -21, 91 }, ++ { -18, 102 }, { -13, 93 }, { -29, 127 }, { -7, 92 }, ++ { -5, 89 }, { -7, 96 }, { -13, 108 }, { -3, 46 }, ++ { -1, 65 }, { -1, 57 }, { -9, 93 }, { -3, 74 }, ++ { -9, 92 }, { -8, 87 }, { -23, 126 }, { 5, 54 }, ++ { 6, 60 }, { 6, 59 }, { 6, 69 }, { -1, 48 }, ++ { 0, 68 }, { -4, 69 }, { -8, 88 }, ++ ++ /* 105 -> 165 */ ++ { -2, 85 }, { -6, 78 }, { -1, 75 }, { -7, 77 }, ++ { 2, 54 }, { 5, 50 }, { -3, 68 }, { 1, 50 }, ++ { 6, 42 }, { -4, 81 }, { 1, 63 }, { -4, 70 }, ++ { 0, 67 }, { 2, 57 }, { -2, 76 }, { 11, 35 }, ++ { 4, 64 }, { 1, 61 }, { 11, 35 }, { 18, 25 }, ++ { 12, 24 }, { 13, 29 }, { 13, 36 }, { -10, 93 }, ++ { -7, 73 }, { -2, 73 }, { 13, 46 }, { 9, 49 }, ++ { -7, 100 }, { 9, 53 }, { 2, 53 }, { 5, 53 }, ++ { -2, 61 }, { 0, 56 }, { 0, 56 }, { -13, 63 }, ++ { -5, 60 }, { -1, 62 }, { 4, 57 }, { -6, 69 }, ++ { 4, 57 }, { 14, 39 }, { 4, 51 }, { 13, 68 }, ++ { 3, 64 }, { 1, 61 }, { 9, 63 }, { 7, 50 }, ++ { 16, 39 }, { 5, 44 }, { 4, 52 }, { 11, 48 }, ++ { -5, 60 }, { -1, 59 }, { 0, 59 }, { 22, 33 }, ++ { 5, 44 }, { 14, 43 }, { -1, 78 }, { 0, 60 }, ++ { 9, 69 }, ++ ++ /* 166 - 226 */ ++ { 11, 28 }, { 2, 40 }, { 3, 44 }, { 0, 49 }, ++ { 0, 46 }, { 2, 44 }, { 2, 51 }, { 0, 47 }, ++ { 4, 39 }, { 2, 62 }, { 6, 46 }, { 0, 54 }, ++ { 3, 54 }, { 2, 58 }, { 4, 63 }, { 6, 51 }, ++ { 6, 57 }, { 7, 53 }, { 6, 52 }, { 6, 55 }, ++ { 11, 45 }, { 14, 36 }, { 8, 53 }, { -1, 82 }, ++ { 7, 55 }, { -3, 78 }, { 15, 46 }, { 22, 31 }, ++ { -1, 84 }, { 25, 7 }, { 30, -7 }, { 28, 3 }, ++ { 28, 4 }, { 32, 0 }, { 34, -1 }, { 30, 6 }, ++ { 30, 6 }, { 32, 9 }, { 31, 19 }, { 26, 27 }, ++ { 26, 30 }, { 37, 20 }, { 28, 34 }, { 17, 70 }, ++ { 1, 67 }, { 5, 59 }, { 9, 67 }, { 16, 30 }, ++ { 18, 32 }, { 18, 35 }, { 22, 29 }, { 24, 31 }, ++ { 23, 38 }, { 18, 43 }, { 20, 41 }, { 11, 63 }, ++ { 9, 59 }, { 9, 64 }, { -1, 94 }, { -2, 89 }, ++ { -9, 108 }, ++ ++ /* 227 - 275 */ ++ { -6, 76 }, { -2, 44 }, { 0, 45 }, { 0, 52 }, ++ { -3, 64 }, { -2, 59 }, { -4, 70 }, { -4, 75 }, ++ { -8, 82 }, { -17, 102 }, { -9, 77 }, { 3, 24 }, ++ { 0, 42 }, { 0, 48 }, { 0, 55 }, { -6, 59 }, ++ { -7, 71 }, { -12, 83 }, { -11, 87 }, { -30, 119 }, ++ { 1, 58 }, { -3, 29 }, { -1, 36 }, { 1, 38 }, ++ { 2, 43 }, { -6, 55 }, { 0, 58 }, { 0, 64 }, ++ { -3, 74 }, { -10, 90 }, { 0, 70 }, { -4, 29 }, ++ { 5, 31 }, { 7, 42 }, { 1, 59 }, { -2, 58 }, ++ { -3, 72 }, { -3, 81 }, { -11, 97 }, { 0, 58 }, ++ { 8, 5 }, { 10, 14 }, { 14, 18 }, { 13, 27 }, ++ { 2, 40 }, { 0, 58 }, { -3, 70 }, { -6, 79 }, ++ { -8, 85 }, ++ ++ /* 276 a bit special (not used, h264_cabac_encode_bypass is used instead) */ ++ { 0, 0 }, ++ ++ /* 277 - 337 */ ++ { -13, 106 }, { -16, 106 }, { -10, 87 }, { -21, 114 }, ++ { -18, 110 }, { -14, 98 }, { -22, 110 }, { -21, 106 }, ++ { -18, 103 }, { -21, 107 }, { -23, 108 }, { -26, 112 }, ++ { -10, 96 }, { -12, 95 }, { -5, 91 }, { -9, 93 }, ++ { -22, 94 }, { -5, 86 }, { 9, 67 }, { -4, 80 }, ++ { -10, 85 }, { -1, 70 }, { 7, 60 }, { 9, 58 }, ++ { 5, 61 }, { 12, 50 }, { 15, 50 }, { 18, 49 }, ++ { 17, 54 }, { 10, 41 }, { 7, 46 }, { -1, 51 }, ++ { 7, 49 }, { 8, 52 }, { 9, 41 }, { 6, 47 }, ++ { 2, 55 }, { 13, 41 }, { 10, 44 }, { 6, 50 }, ++ { 5, 53 }, { 13, 49 }, { 4, 63 }, { 6, 64 }, ++ { -2, 69 }, { -2, 59 }, { 6, 70 }, { 10, 44 }, ++ { 9, 31 }, { 12, 43 }, { 3, 53 }, { 14, 34 }, ++ { 10, 38 }, { -3, 52 }, { 13, 40 }, { 17, 32 }, ++ { 7, 44 }, { 7, 38 }, { 13, 50 }, { 10, 57 }, ++ { 26, 43 }, ++ ++ /* 338 - 398 */ ++ { 14, 11 }, { 11, 14 }, { 9, 11 }, { 18, 11 }, ++ { 21, 9 }, { 23, -2 }, { 32, -15 }, { 32, -15 }, ++ { 34, -21 }, { 39, -23 }, { 42, -33 }, { 41, -31 }, ++ { 46, -28 }, { 38, -12 }, { 21, 29 }, { 45, -24 }, ++ { 53, -45 }, { 48, -26 }, { 65, -43 }, { 43, -19 }, ++ { 39, -10 }, { 30, 9 }, { 18, 26 }, { 20, 27 }, ++ { 0, 57 }, { -14, 82 }, { -5, 75 }, { -19, 97 }, ++ { -35, 125 }, { 27, 0 }, { 28, 0 }, { 31, -4 }, ++ { 27, 6 }, { 34, 8 }, { 30, 10 }, { 24, 22 }, ++ { 33, 19 }, { 22, 32 }, { 26, 31 }, { 21, 41 }, ++ { 26, 44 }, { 23, 47 }, { 16, 65 }, { 14, 71 }, ++ { 8, 60 }, { 6, 63 }, { 17, 65 }, { 21, 24 }, ++ { 23, 20 }, { 26, 23 }, { 27, 32 }, { 28, 23 }, ++ { 28, 24 }, { 23, 40 }, { 24, 32 }, { 28, 29 }, ++ { 23, 42 }, { 19, 57 }, { 22, 53 }, { 22, 61 }, ++ { 11, 86 }, ++ ++ /* 399 -> 435 */ ++ { 12, 40 }, { 11, 51 }, { 14, 59 }, ++ { -4, 79 }, { -7, 71 }, { -5, 69 }, { -9, 70 }, ++ { -8, 66 }, { -10, 68 }, { -19, 73 }, { -12, 69 }, ++ { -16, 70 }, { -15, 67 }, { -20, 62 }, { -19, 70 }, ++ { -16, 66 }, { -22, 65 }, { -20, 63 }, { 9, -2 }, ++ { 26, -9 }, { 33, -9 }, { 39, -7 }, { 41, -2 }, ++ { 45, 3 }, { 49, 9 }, { 45, 27 }, { 36, 59 }, ++ { -6, 66 }, { -7, 35 }, { -7, 42 }, { -8, 45 }, ++ { -5, 48 }, { -12, 56 }, { -6, 60 }, { -5, 62 }, ++ { -8, 66 }, { -8, 76 }, ++ ++ /* 436 -> 459 */ ++ { -5, 85 }, { -6, 81 }, { -10, 77 }, { -7, 81 }, ++ { -17, 80 }, { -18, 73 }, { -4, 74 }, { -10, 83 }, ++ { -9, 71 }, { -9, 67 }, { -1, 61 }, { -8, 66 }, ++ { -14, 66 }, { 0, 59 }, { 2, 59 }, { 21, -13 }, ++ { 33, -14 }, { 39, -7 }, { 46, -2 }, { 51, 2 }, ++ { 60, 6 }, { 61, 17 }, { 55, 34 }, { 42, 62 }, ++ ++ /* 460 - 1024 */ ++ { -7, 92 }, { -5, 89 }, { -7, 96 }, { -13, 108 }, ++ { -3, 46 }, { -1, 65 }, { -1, 57 }, { -9, 93 }, ++ { -3, 74 }, { -9, 92 }, { -8, 87 }, { -23, 126 }, ++ { -7, 92 }, { -5, 89 }, { -7, 96 }, { -13, 108 }, ++ { -3, 46 }, { -1, 65 }, { -1, 57 }, { -9, 93 }, ++ { -3, 74 }, { -9, 92 }, { -8, 87 }, { -23, 126 }, ++ { -2, 85 }, { -6, 78 }, { -1, 75 }, { -7, 77 }, ++ { 2, 54 }, { 5, 50 }, { -3, 68 }, { 1, 50 }, ++ { 6, 42 }, { -4, 81 }, { 1, 63 }, { -4, 70 }, ++ { 0, 67 }, { 2, 57 }, { -2, 76 }, { 11, 35 }, ++ { 4, 64 }, { 1, 61 }, { 11, 35 }, { 18, 25 }, ++ { 12, 24 }, { 13, 29 }, { 13, 36 }, { -10, 93 }, ++ { -7, 73 }, { -2, 73 }, { 13, 46 }, { 9, 49 }, ++ { -7, 100 }, { 9, 53 }, { 2, 53 }, { 5, 53 }, ++ { -2, 61 }, { 0, 56 }, { 0, 56 }, { -13, 63 }, ++ { -5, 60 }, { -1, 62 }, { 4, 57 }, { -6, 69 }, ++ { 4, 57 }, { 14, 39 }, { 4, 51 }, { 13, 68 }, ++ { -2, 85 }, { -6, 78 }, { -1, 75 }, { -7, 77 }, ++ { 2, 54 }, { 5, 50 }, { -3, 68 }, { 1, 50 }, ++ { 6, 42 }, { -4, 81 }, { 1, 63 }, { -4, 70 }, ++ { 0, 67 }, { 2, 57 }, { -2, 76 }, { 11, 35 }, ++ { 4, 64 }, { 1, 61 }, { 11, 35 }, { 18, 25 }, ++ { 12, 24 }, { 13, 29 }, { 13, 36 }, { -10, 93 }, ++ { -7, 73 }, { -2, 73 }, { 13, 46 }, { 9, 49 }, ++ { -7, 100 }, { 9, 53 }, { 2, 53 }, { 5, 53 }, ++ { -2, 61 }, { 0, 56 }, { 0, 56 }, { -13, 63 }, ++ { -5, 60 }, { -1, 62 }, { 4, 57 }, { -6, 69 }, ++ { 4, 57 }, { 14, 39 }, { 4, 51 }, { 13, 68 }, ++ { 11, 28 }, { 2, 40 }, { 3, 44 }, { 0, 49 }, ++ { 0, 46 }, { 2, 44 }, { 2, 51 }, { 0, 47 }, ++ { 4, 39 }, { 2, 62 }, { 6, 46 }, { 0, 54 }, ++ { 3, 54 }, { 2, 58 }, { 4, 63 }, { 6, 51 }, ++ { 6, 57 }, { 7, 53 }, { 6, 52 }, { 6, 55 }, ++ { 11, 45 }, { 14, 36 }, { 8, 53 }, { -1, 82 }, ++ { 7, 55 }, { -3, 78 }, { 15, 46 }, { 22, 31 }, ++ { -1, 84 }, { 25, 7 }, { 30, -7 }, { 28, 3 }, ++ { 28, 4 }, { 32, 0 }, { 34, -1 }, { 30, 6 }, ++ { 30, 6 }, { 32, 9 }, { 31, 19 }, { 26, 27 }, ++ { 26, 30 }, { 37, 20 }, { 28, 34 }, { 17, 70 }, ++ { 11, 28 }, { 2, 40 }, { 3, 44 }, { 0, 49 }, ++ { 0, 46 }, { 2, 44 }, { 2, 51 }, { 0, 47 }, ++ { 4, 39 }, { 2, 62 }, { 6, 46 }, { 0, 54 }, ++ { 3, 54 }, { 2, 58 }, { 4, 63 }, { 6, 51 }, ++ { 6, 57 }, { 7, 53 }, { 6, 52 }, { 6, 55 }, ++ { 11, 45 }, { 14, 36 }, { 8, 53 }, { -1, 82 }, ++ { 7, 55 }, { -3, 78 }, { 15, 46 }, { 22, 31 }, ++ { -1, 84 }, { 25, 7 }, { 30, -7 }, { 28, 3 }, ++ { 28, 4 }, { 32, 0 }, { 34, -1 }, { 30, 6 }, ++ { 30, 6 }, { 32, 9 }, { 31, 19 }, { 26, 27 }, ++ { 26, 30 }, { 37, 20 }, { 28, 34 }, { 17, 70 }, ++ { -4, 79 }, { -7, 71 }, { -5, 69 }, { -9, 70 }, ++ { -8, 66 }, { -10, 68 }, { -19, 73 }, { -12, 69 }, ++ { -16, 70 }, { -15, 67 }, { -20, 62 }, { -19, 70 }, ++ { -16, 66 }, { -22, 65 }, { -20, 63 }, { -5, 85 }, ++ { -6, 81 }, { -10, 77 }, { -7, 81 }, { -17, 80 }, ++ { -18, 73 }, { -4, 74 }, { -10, 83 }, { -9, 71 }, ++ { -9, 67 }, { -1, 61 }, { -8, 66 }, { -14, 66 }, ++ { 0, 59 }, { 2, 59 }, { 9, -2 }, { 26, -9 }, ++ { 33, -9 }, { 39, -7 }, { 41, -2 }, { 45, 3 }, ++ { 49, 9 }, { 45, 27 }, { 36, 59 }, { 21, -13 }, ++ { 33, -14 }, { 39, -7 }, { 46, -2 }, { 51, 2 }, ++ { 60, 6 }, { 61, 17 }, { 55, 34 }, { 42, 62 }, ++ { -6, 66 }, { -7, 35 }, { -7, 42 }, { -8, 45 }, ++ { -5, 48 }, { -12, 56 }, { -6, 60 }, { -5, 62 }, ++ { -8, 66 }, { -8, 76 }, { -4, 79 }, { -7, 71 }, ++ { -5, 69 }, { -9, 70 }, { -8, 66 }, { -10, 68 }, ++ { -19, 73 }, { -12, 69 }, { -16, 70 }, { -15, 67 }, ++ { -20, 62 }, { -19, 70 }, { -16, 66 }, { -22, 65 }, ++ { -20, 63 }, { -5, 85 }, { -6, 81 }, { -10, 77 }, ++ { -7, 81 }, { -17, 80 }, { -18, 73 }, { -4, 74 }, ++ { -10, 83 }, { -9, 71 }, { -9, 67 }, { -1, 61 }, ++ { -8, 66 }, { -14, 66 }, { 0, 59 }, { 2, 59 }, ++ { 9, -2 }, { 26, -9 }, { 33, -9 }, { 39, -7 }, ++ { 41, -2 }, { 45, 3 }, { 49, 9 }, { 45, 27 }, ++ { 36, 59 }, { 21, -13 }, { 33, -14 }, { 39, -7 }, ++ { 46, -2 }, { 51, 2 }, { 60, 6 }, { 61, 17 }, ++ { 55, 34 }, { 42, 62 }, { -6, 66 }, { -7, 35 }, ++ { -7, 42 }, { -8, 45 }, { -5, 48 }, { -12, 56 }, ++ { -6, 60 }, { -5, 62 }, { -8, 66 }, { -8, 76 }, ++ { -13, 106 }, { -16, 106 }, { -10, 87 }, { -21, 114 }, ++ { -18, 110 }, { -14, 98 }, { -22, 110 }, { -21, 106 }, ++ { -18, 103 }, { -21, 107 }, { -23, 108 }, { -26, 112 }, ++ { -10, 96 }, { -12, 95 }, { -5, 91 }, { -9, 93 }, ++ { -22, 94 }, { -5, 86 }, { 9, 67 }, { -4, 80 }, ++ { -10, 85 }, { -1, 70 }, { 7, 60 }, { 9, 58 }, ++ { 5, 61 }, { 12, 50 }, { 15, 50 }, { 18, 49 }, ++ { 17, 54 }, { 10, 41 }, { 7, 46 }, { -1, 51 }, ++ { 7, 49 }, { 8, 52 }, { 9, 41 }, { 6, 47 }, ++ { 2, 55 }, { 13, 41 }, { 10, 44 }, { 6, 50 }, ++ { 5, 53 }, { 13, 49 }, { 4, 63 }, { 6, 64 }, ++ { -13, 106 }, { -16, 106 }, { -10, 87 }, { -21, 114 }, ++ { -18, 110 }, { -14, 98 }, { -22, 110 }, { -21, 106 }, ++ { -18, 103 }, { -21, 107 }, { -23, 108 }, { -26, 112 }, ++ { -10, 96 }, { -12, 95 }, { -5, 91 }, { -9, 93 }, ++ { -22, 94 }, { -5, 86 }, { 9, 67 }, { -4, 80 }, ++ { -10, 85 }, { -1, 70 }, { 7, 60 }, { 9, 58 }, ++ { 5, 61 }, { 12, 50 }, { 15, 50 }, { 18, 49 }, ++ { 17, 54 }, { 10, 41 }, { 7, 46 }, { -1, 51 }, ++ { 7, 49 }, { 8, 52 }, { 9, 41 }, { 6, 47 }, ++ { 2, 55 }, { 13, 41 }, { 10, 44 }, { 6, 50 }, ++ { 5, 53 }, { 13, 49 }, { 4, 63 }, { 6, 64 }, ++ { 14, 11 }, { 11, 14 }, { 9, 11 }, { 18, 11 }, ++ { 21, 9 }, { 23, -2 }, { 32, -15 }, { 32, -15 }, ++ { 34, -21 }, { 39, -23 }, { 42, -33 }, { 41, -31 }, ++ { 46, -28 }, { 38, -12 }, { 21, 29 }, { 45, -24 }, ++ { 53, -45 }, { 48, -26 }, { 65, -43 }, { 43, -19 }, ++ { 39, -10 }, { 30, 9 }, { 18, 26 }, { 20, 27 }, ++ { 0, 57 }, { -14, 82 }, { -5, 75 }, { -19, 97 }, ++ { -35, 125 }, { 27, 0 }, { 28, 0 }, { 31, -4 }, ++ { 27, 6 }, { 34, 8 }, { 30, 10 }, { 24, 22 }, ++ { 33, 19 }, { 22, 32 }, { 26, 31 }, { 21, 41 }, ++ { 26, 44 }, { 23, 47 }, { 16, 65 }, { 14, 71 }, ++ { 14, 11 }, { 11, 14 }, { 9, 11 }, { 18, 11 }, ++ { 21, 9 }, { 23, -2 }, { 32, -15 }, { 32, -15 }, ++ { 34, -21 }, { 39, -23 }, { 42, -33 }, { 41, -31 }, ++ { 46, -28 }, { 38, -12 }, { 21, 29 }, { 45, -24 }, ++ { 53, -45 }, { 48, -26 }, { 65, -43 }, { 43, -19 }, ++ { 39, -10 }, { 30, 9 }, { 18, 26 }, { 20, 27 }, ++ { 0, 57 }, { -14, 82 }, { -5, 75 }, { -19, 97 }, ++ { -35, 125 }, { 27, 0 }, { 28, 0 }, { 31, -4 }, ++ { 27, 6 }, { 34, 8 }, { 30, 10 }, { 24, 22 }, ++ { 33, 19 }, { 22, 32 }, { 26, 31 }, { 21, 41 }, ++ { 26, 44 }, { 23, 47 }, { 16, 65 }, { 14, 71 }, ++ { -6, 76 }, { -2, 44 }, { 0, 45 }, { 0, 52 }, ++ { -3, 64 }, { -2, 59 }, { -4, 70 }, { -4, 75 }, ++ { -8, 82 }, { -17, 102 }, { -9, 77 }, { 3, 24 }, ++ { 0, 42 }, { 0, 48 }, { 0, 55 }, { -6, 59 }, ++ { -7, 71 }, { -12, 83 }, { -11, 87 }, { -30, 119 }, ++ { 1, 58 }, { -3, 29 }, { -1, 36 }, { 1, 38 }, ++ { 2, 43 }, { -6, 55 }, { 0, 58 }, { 0, 64 }, ++ { -3, 74 }, { -10, 90 }, { -6, 76 }, { -2, 44 }, ++ { 0, 45 }, { 0, 52 }, { -3, 64 }, { -2, 59 }, ++ { -4, 70 }, { -4, 75 }, { -8, 82 }, { -17, 102 }, ++ { -9, 77 }, { 3, 24 }, { 0, 42 }, { 0, 48 }, ++ { 0, 55 }, { -6, 59 }, { -7, 71 }, { -12, 83 }, ++ { -11, 87 }, { -30, 119 }, { 1, 58 }, { -3, 29 }, ++ { -1, 36 }, { 1, 38 }, { 2, 43 }, { -6, 55 }, ++ { 0, 58 }, { 0, 64 }, { -3, 74 }, { -10, 90 }, ++ { -3, 74 }, { -9, 92 }, { -8, 87 }, { -23, 126 }, ++ { -3, 74 }, { -9, 92 }, { -8, 87 }, { -23, 126 }, ++ { -3, 74 }, { -9, 92 }, { -8, 87 }, { -23, 126 } ++ }, ++ ++ /* i_cabac_init_idc == 1 */ ++ { ++ /* 0 - 10 */ ++ { 20, -15 }, { 2, 54 }, { 3, 74 }, { 20, -15 }, ++ { 2, 54 }, { 3, 74 }, { -28, 127 }, { -23, 104 }, ++ { -6, 53 }, { -1, 54 }, { 7, 51 }, ++ ++ /* 11 - 23 */ ++ { 22, 25 }, { 34, 0 }, { 16, 0 }, { -2, 9 }, ++ { 4, 41 }, { -29, 118 }, { 2, 65 }, { -6, 71 }, ++ { -13, 79 }, { 5, 52 }, { 9, 50 }, { -3, 70 }, ++ { 10, 54 }, ++ ++ /* 24 - 39 */ ++ { 26, 34 }, { 19, 22 }, { 40, 0 }, { 57, 2 }, ++ { 41, 36 }, { 26, 69 }, { -45, 127 }, { -15, 101 }, ++ { -4, 76 }, { -6, 71 }, { -13, 79 }, { 5, 52 }, ++ { 6, 69 }, { -13, 90 }, { 0, 52 }, { 8, 43 }, ++ ++ /* 40 - 53 */ ++ { -2, 69 },{ -5, 82 },{ -10, 96 },{ 2, 59 }, ++ { 2, 75 },{ -3, 87 },{ -3, 100 },{ 1, 56 }, ++ { -3, 74 },{ -6, 85 },{ 0, 59 },{ -3, 81 }, ++ { -7, 86 },{ -5, 95 }, ++ ++ /* 54 - 59 */ ++ { -1, 66 },{ -1, 77 },{ 1, 70 },{ -2, 86 }, ++ { -5, 72 },{ 0, 61 }, ++ ++ /* 60 - 69 */ ++ { 0, 41 }, { 0, 63 }, { 0, 63 }, { 0, 63 }, ++ { -9, 83 }, { 4, 86 }, { 0, 97 }, { -7, 72 }, ++ { 13, 41 }, { 3, 62 }, ++ ++ /* 70 - 104 */ ++ { 13, 15 }, { 7, 51 }, { 2, 80 }, { -39, 127 }, ++ { -18, 91 }, { -17, 96 }, { -26, 81 }, { -35, 98 }, ++ { -24, 102 }, { -23, 97 }, { -27, 119 }, { -24, 99 }, ++ { -21, 110 }, { -18, 102 }, { -36, 127 }, { 0, 80 }, ++ { -5, 89 }, { -7, 94 }, { -4, 92 }, { 0, 39 }, ++ { 0, 65 }, { -15, 84 }, { -35, 127 }, { -2, 73 }, ++ { -12, 104 }, { -9, 91 }, { -31, 127 }, { 3, 55 }, ++ { 7, 56 }, { 7, 55 }, { 8, 61 }, { -3, 53 }, ++ { 0, 68 }, { -7, 74 }, { -9, 88 }, ++ ++ /* 105 -> 165 */ ++ { -13, 103 }, { -13, 91 }, { -9, 89 }, { -14, 92 }, ++ { -8, 76 }, { -12, 87 }, { -23, 110 }, { -24, 105 }, ++ { -10, 78 }, { -20, 112 }, { -17, 99 }, { -78, 127 }, ++ { -70, 127 }, { -50, 127 }, { -46, 127 }, { -4, 66 }, ++ { -5, 78 }, { -4, 71 }, { -8, 72 }, { 2, 59 }, ++ { -1, 55 }, { -7, 70 }, { -6, 75 }, { -8, 89 }, ++ { -34, 119 }, { -3, 75 }, { 32, 20 }, { 30, 22 }, ++ { -44, 127 }, { 0, 54 }, { -5, 61 }, { 0, 58 }, ++ { -1, 60 }, { -3, 61 }, { -8, 67 }, { -25, 84 }, ++ { -14, 74 }, { -5, 65 }, { 5, 52 }, { 2, 57 }, ++ { 0, 61 }, { -9, 69 }, { -11, 70 }, { 18, 55 }, ++ { -4, 71 }, { 0, 58 }, { 7, 61 }, { 9, 41 }, ++ { 18, 25 }, { 9, 32 }, { 5, 43 }, { 9, 47 }, ++ { 0, 44 }, { 0, 51 }, { 2, 46 }, { 19, 38 }, ++ { -4, 66 }, { 15, 38 }, { 12, 42 }, { 9, 34 }, ++ { 0, 89 }, ++ ++ /* 166 - 226 */ ++ { 4, 45 }, { 10, 28 }, { 10, 31 }, { 33, -11 }, ++ { 52, -43 }, { 18, 15 }, { 28, 0 }, { 35, -22 }, ++ { 38, -25 }, { 34, 0 }, { 39, -18 }, { 32, -12 }, ++ { 102, -94 }, { 0, 0 }, { 56, -15 }, { 33, -4 }, ++ { 29, 10 }, { 37, -5 }, { 51, -29 }, { 39, -9 }, ++ { 52, -34 }, { 69, -58 }, { 67, -63 }, { 44, -5 }, ++ { 32, 7 }, { 55, -29 }, { 32, 1 }, { 0, 0 }, ++ { 27, 36 }, { 33, -25 }, { 34, -30 }, { 36, -28 }, ++ { 38, -28 }, { 38, -27 }, { 34, -18 }, { 35, -16 }, ++ { 34, -14 }, { 32, -8 }, { 37, -6 }, { 35, 0 }, ++ { 30, 10 }, { 28, 18 }, { 26, 25 }, { 29, 41 }, ++ { 0, 75 }, { 2, 72 }, { 8, 77 }, { 14, 35 }, ++ { 18, 31 }, { 17, 35 }, { 21, 30 }, { 17, 45 }, ++ { 20, 42 }, { 18, 45 }, { 27, 26 }, { 16, 54 }, ++ { 7, 66 }, { 16, 56 }, { 11, 73 }, { 10, 67 }, ++ { -10, 116 }, ++ ++ /* 227 - 275 */ ++ { -23, 112 }, { -15, 71 }, { -7, 61 }, { 0, 53 }, ++ { -5, 66 }, { -11, 77 }, { -9, 80 }, { -9, 84 }, ++ { -10, 87 }, { -34, 127 }, { -21, 101 }, { -3, 39 }, ++ { -5, 53 }, { -7, 61 }, { -11, 75 }, { -15, 77 }, ++ { -17, 91 }, { -25, 107 }, { -25, 111 }, { -28, 122 }, ++ { -11, 76 }, { -10, 44 }, { -10, 52 }, { -10, 57 }, ++ { -9, 58 }, { -16, 72 }, { -7, 69 }, { -4, 69 }, ++ { -5, 74 }, { -9, 86 }, { 2, 66 }, { -9, 34 }, ++ { 1, 32 }, { 11, 31 }, { 5, 52 }, { -2, 55 }, ++ { -2, 67 }, { 0, 73 }, { -8, 89 }, { 3, 52 }, ++ { 7, 4 }, { 10, 8 }, { 17, 8 }, { 16, 19 }, ++ { 3, 37 }, { -1, 61 }, { -5, 73 }, { -1, 70 }, ++ { -4, 78 }, ++ ++ /* 276 a bit special (not used, h264_cabac_encode_bypass is used instead) */ ++ { 0, 0 }, ++ ++ /* 277 - 337 */ ++ { -21, 126 }, { -23, 124 }, { -20, 110 }, { -26, 126 }, ++ { -25, 124 }, { -17, 105 }, { -27, 121 }, { -27, 117 }, ++ { -17, 102 }, { -26, 117 }, { -27, 116 }, { -33, 122 }, ++ { -10, 95 }, { -14, 100 }, { -8, 95 }, { -17, 111 }, ++ { -28, 114 }, { -6, 89 }, { -2, 80 }, { -4, 82 }, ++ { -9, 85 }, { -8, 81 }, { -1, 72 }, { 5, 64 }, ++ { 1, 67 }, { 9, 56 }, { 0, 69 }, { 1, 69 }, ++ { 7, 69 }, { -7, 69 }, { -6, 67 }, { -16, 77 }, ++ { -2, 64 }, { 2, 61 }, { -6, 67 }, { -3, 64 }, ++ { 2, 57 }, { -3, 65 }, { -3, 66 }, { 0, 62 }, ++ { 9, 51 }, { -1, 66 }, { -2, 71 }, { -2, 75 }, ++ { -1, 70 }, { -9, 72 }, { 14, 60 }, { 16, 37 }, ++ { 0, 47 }, { 18, 35 }, { 11, 37 }, { 12, 41 }, ++ { 10, 41 }, { 2, 48 }, { 12, 41 }, { 13, 41 }, ++ { 0, 59 }, { 3, 50 }, { 19, 40 }, { 3, 66 }, ++ { 18, 50 }, ++ ++ /* 338 - 398 */ ++ { 19, -6 }, { 18, -6 }, { 14, 0 }, { 26, -12 }, ++ { 31, -16 }, { 33, -25 }, { 33, -22 }, { 37, -28 }, ++ { 39, -30 }, { 42, -30 }, { 47, -42 }, { 45, -36 }, ++ { 49, -34 }, { 41, -17 }, { 32, 9 }, { 69, -71 }, ++ { 63, -63 }, { 66, -64 }, { 77, -74 }, { 54, -39 }, ++ { 52, -35 }, { 41, -10 }, { 36, 0 }, { 40, -1 }, ++ { 30, 14 }, { 28, 26 }, { 23, 37 }, { 12, 55 }, ++ { 11, 65 }, { 37, -33 }, { 39, -36 }, { 40, -37 }, ++ { 38, -30 }, { 46, -33 }, { 42, -30 }, { 40, -24 }, ++ { 49, -29 }, { 38, -12 }, { 40, -10 }, { 38, -3 }, ++ { 46, -5 }, { 31, 20 }, { 29, 30 }, { 25, 44 }, ++ { 12, 48 }, { 11, 49 }, { 26, 45 }, { 22, 22 }, ++ { 23, 22 }, { 27, 21 }, { 33, 20 }, { 26, 28 }, ++ { 30, 24 }, { 27, 34 }, { 18, 42 }, { 25, 39 }, ++ { 18, 50 }, { 12, 70 }, { 21, 54 }, { 14, 71 }, ++ { 11, 83 }, ++ ++ /* 399 -> 435 */ ++ { 25, 32 }, { 21, 49 }, { 21, 54 }, ++ { -5, 85 }, { -6, 81 }, { -10, 77 }, { -7, 81 }, ++ { -17, 80 }, { -18, 73 }, { -4, 74 }, { -10, 83 }, ++ { -9, 71 }, { -9, 67 }, { -1, 61 }, { -8, 66 }, ++ { -14, 66 }, { 0, 59 }, { 2, 59 }, { 17, -10 }, ++ { 32, -13 }, { 42, -9 }, { 49, -5 }, { 53, 0 }, ++ { 64, 3 }, { 68, 10 }, { 66, 27 }, { 47, 57 }, ++ { -5, 71 }, { 0, 24 }, { -1, 36 }, { -2, 42 }, ++ { -2, 52 }, { -9, 57 }, { -6, 63 }, { -4, 65 }, ++ { -4, 67 }, { -7, 82 }, ++ ++ /* 436 -> 459 */ ++ { -3, 81 }, { -3, 76 }, { -7, 72 }, { -6, 78 }, ++ { -12, 72 }, { -14, 68 }, { -3, 70 }, { -6, 76 }, ++ { -5, 66 }, { -5, 62 }, { 0, 57 }, { -4, 61 }, ++ { -9, 60 }, { 1, 54 }, { 2, 58 }, { 17, -10 }, ++ { 32, -13 }, { 42, -9 }, { 49, -5 }, { 53, 0 }, ++ { 64, 3 }, { 68, 10 }, { 66, 27 }, { 47, 57 }, ++ ++ /* 460 - 1024 */ ++ { 0, 80 }, { -5, 89 }, { -7, 94 }, { -4, 92 }, ++ { 0, 39 }, { 0, 65 }, { -15, 84 }, { -35, 127 }, ++ { -2, 73 }, { -12, 104 }, { -9, 91 }, { -31, 127 }, ++ { 0, 80 }, { -5, 89 }, { -7, 94 }, { -4, 92 }, ++ { 0, 39 }, { 0, 65 }, { -15, 84 }, { -35, 127 }, ++ { -2, 73 }, { -12, 104 }, { -9, 91 }, { -31, 127 }, ++ { -13, 103 }, { -13, 91 }, { -9, 89 }, { -14, 92 }, ++ { -8, 76 }, { -12, 87 }, { -23, 110 }, { -24, 105 }, ++ { -10, 78 }, { -20, 112 }, { -17, 99 }, { -78, 127 }, ++ { -70, 127 }, { -50, 127 }, { -46, 127 }, { -4, 66 }, ++ { -5, 78 }, { -4, 71 }, { -8, 72 }, { 2, 59 }, ++ { -1, 55 }, { -7, 70 }, { -6, 75 }, { -8, 89 }, ++ { -34, 119 }, { -3, 75 }, { 32, 20 }, { 30, 22 }, ++ { -44, 127 }, { 0, 54 }, { -5, 61 }, { 0, 58 }, ++ { -1, 60 }, { -3, 61 }, { -8, 67 }, { -25, 84 }, ++ { -14, 74 }, { -5, 65 }, { 5, 52 }, { 2, 57 }, ++ { 0, 61 }, { -9, 69 }, { -11, 70 }, { 18, 55 }, ++ { -13, 103 }, { -13, 91 }, { -9, 89 }, { -14, 92 }, ++ { -8, 76 }, { -12, 87 }, { -23, 110 }, { -24, 105 }, ++ { -10, 78 }, { -20, 112 }, { -17, 99 }, { -78, 127 }, ++ { -70, 127 }, { -50, 127 }, { -46, 127 }, { -4, 66 }, ++ { -5, 78 }, { -4, 71 }, { -8, 72 }, { 2, 59 }, ++ { -1, 55 }, { -7, 70 }, { -6, 75 }, { -8, 89 }, ++ { -34, 119 }, { -3, 75 }, { 32, 20 }, { 30, 22 }, ++ { -44, 127 }, { 0, 54 }, { -5, 61 }, { 0, 58 }, ++ { -1, 60 }, { -3, 61 }, { -8, 67 }, { -25, 84 }, ++ { -14, 74 }, { -5, 65 }, { 5, 52 }, { 2, 57 }, ++ { 0, 61 }, { -9, 69 }, { -11, 70 }, { 18, 55 }, ++ { 4, 45 }, { 10, 28 }, { 10, 31 }, { 33, -11 }, ++ { 52, -43 }, { 18, 15 }, { 28, 0 }, { 35, -22 }, ++ { 38, -25 }, { 34, 0 }, { 39, -18 }, { 32, -12 }, ++ { 102, -94 }, { 0, 0 }, { 56, -15 }, { 33, -4 }, ++ { 29, 10 }, { 37, -5 }, { 51, -29 }, { 39, -9 }, ++ { 52, -34 }, { 69, -58 }, { 67, -63 }, { 44, -5 }, ++ { 32, 7 }, { 55, -29 }, { 32, 1 }, { 0, 0 }, ++ { 27, 36 }, { 33, -25 }, { 34, -30 }, { 36, -28 }, ++ { 38, -28 }, { 38, -27 }, { 34, -18 }, { 35, -16 }, ++ { 34, -14 }, { 32, -8 }, { 37, -6 }, { 35, 0 }, ++ { 30, 10 }, { 28, 18 }, { 26, 25 }, { 29, 41 }, ++ { 4, 45 }, { 10, 28 }, { 10, 31 }, { 33, -11 }, ++ { 52, -43 }, { 18, 15 }, { 28, 0 }, { 35, -22 }, ++ { 38, -25 }, { 34, 0 }, { 39, -18 }, { 32, -12 }, ++ { 102, -94 }, { 0, 0 }, { 56, -15 }, { 33, -4 }, ++ { 29, 10 }, { 37, -5 }, { 51, -29 }, { 39, -9 }, ++ { 52, -34 }, { 69, -58 }, { 67, -63 }, { 44, -5 }, ++ { 32, 7 }, { 55, -29 }, { 32, 1 }, { 0, 0 }, ++ { 27, 36 }, { 33, -25 }, { 34, -30 }, { 36, -28 }, ++ { 38, -28 }, { 38, -27 }, { 34, -18 }, { 35, -16 }, ++ { 34, -14 }, { 32, -8 }, { 37, -6 }, { 35, 0 }, ++ { 30, 10 }, { 28, 18 }, { 26, 25 }, { 29, 41 }, ++ { -5, 85 }, { -6, 81 }, { -10, 77 }, { -7, 81 }, ++ { -17, 80 }, { -18, 73 }, { -4, 74 }, { -10, 83 }, ++ { -9, 71 }, { -9, 67 }, { -1, 61 }, { -8, 66 }, ++ { -14, 66 }, { 0, 59 }, { 2, 59 }, { -3, 81 }, ++ { -3, 76 }, { -7, 72 }, { -6, 78 }, { -12, 72 }, ++ { -14, 68 }, { -3, 70 }, { -6, 76 }, { -5, 66 }, ++ { -5, 62 }, { 0, 57 }, { -4, 61 }, { -9, 60 }, ++ { 1, 54 }, { 2, 58 }, { 17, -10 }, { 32, -13 }, ++ { 42, -9 }, { 49, -5 }, { 53, 0 }, { 64, 3 }, ++ { 68, 10 }, { 66, 27 }, { 47, 57 }, { 17, -10 }, ++ { 32, -13 }, { 42, -9 }, { 49, -5 }, { 53, 0 }, ++ { 64, 3 }, { 68, 10 }, { 66, 27 }, { 47, 57 }, ++ { -5, 71 }, { 0, 24 }, { -1, 36 }, { -2, 42 }, ++ { -2, 52 }, { -9, 57 }, { -6, 63 }, { -4, 65 }, ++ { -4, 67 }, { -7, 82 }, { -5, 85 }, { -6, 81 }, ++ { -10, 77 }, { -7, 81 }, { -17, 80 }, { -18, 73 }, ++ { -4, 74 }, { -10, 83 }, { -9, 71 }, { -9, 67 }, ++ { -1, 61 }, { -8, 66 }, { -14, 66 }, { 0, 59 }, ++ { 2, 59 }, { -3, 81 }, { -3, 76 }, { -7, 72 }, ++ { -6, 78 }, { -12, 72 }, { -14, 68 }, { -3, 70 }, ++ { -6, 76 }, { -5, 66 }, { -5, 62 }, { 0, 57 }, ++ { -4, 61 }, { -9, 60 }, { 1, 54 }, { 2, 58 }, ++ { 17, -10 }, { 32, -13 }, { 42, -9 }, { 49, -5 }, ++ { 53, 0 }, { 64, 3 }, { 68, 10 }, { 66, 27 }, ++ { 47, 57 }, { 17, -10 }, { 32, -13 }, { 42, -9 }, ++ { 49, -5 }, { 53, 0 }, { 64, 3 }, { 68, 10 }, ++ { 66, 27 }, { 47, 57 }, { -5, 71 }, { 0, 24 }, ++ { -1, 36 }, { -2, 42 }, { -2, 52 }, { -9, 57 }, ++ { -6, 63 }, { -4, 65 }, { -4, 67 }, { -7, 82 }, ++ { -21, 126 }, { -23, 124 }, { -20, 110 }, { -26, 126 }, ++ { -25, 124 }, { -17, 105 }, { -27, 121 }, { -27, 117 }, ++ { -17, 102 }, { -26, 117 }, { -27, 116 }, { -33, 122 }, ++ { -10, 95 }, { -14, 100 }, { -8, 95 }, { -17, 111 }, ++ { -28, 114 }, { -6, 89 }, { -2, 80 }, { -4, 82 }, ++ { -9, 85 }, { -8, 81 }, { -1, 72 }, { 5, 64 }, ++ { 1, 67 }, { 9, 56 }, { 0, 69 }, { 1, 69 }, ++ { 7, 69 }, { -7, 69 }, { -6, 67 }, { -16, 77 }, ++ { -2, 64 }, { 2, 61 }, { -6, 67 }, { -3, 64 }, ++ { 2, 57 }, { -3, 65 }, { -3, 66 }, { 0, 62 }, ++ { 9, 51 }, { -1, 66 }, { -2, 71 }, { -2, 75 }, ++ { -21, 126 }, { -23, 124 }, { -20, 110 }, { -26, 126 }, ++ { -25, 124 }, { -17, 105 }, { -27, 121 }, { -27, 117 }, ++ { -17, 102 }, { -26, 117 }, { -27, 116 }, { -33, 122 }, ++ { -10, 95 }, { -14, 100 }, { -8, 95 }, { -17, 111 }, ++ { -28, 114 }, { -6, 89 }, { -2, 80 }, { -4, 82 }, ++ { -9, 85 }, { -8, 81 }, { -1, 72 }, { 5, 64 }, ++ { 1, 67 }, { 9, 56 }, { 0, 69 }, { 1, 69 }, ++ { 7, 69 }, { -7, 69 }, { -6, 67 }, { -16, 77 }, ++ { -2, 64 }, { 2, 61 }, { -6, 67 }, { -3, 64 }, ++ { 2, 57 }, { -3, 65 }, { -3, 66 }, { 0, 62 }, ++ { 9, 51 }, { -1, 66 }, { -2, 71 }, { -2, 75 }, ++ { 19, -6 }, { 18, -6 }, { 14, 0 }, { 26, -12 }, ++ { 31, -16 }, { 33, -25 }, { 33, -22 }, { 37, -28 }, ++ { 39, -30 }, { 42, -30 }, { 47, -42 }, { 45, -36 }, ++ { 49, -34 }, { 41, -17 }, { 32, 9 }, { 69, -71 }, ++ { 63, -63 }, { 66, -64 }, { 77, -74 }, { 54, -39 }, ++ { 52, -35 }, { 41, -10 }, { 36, 0 }, { 40, -1 }, ++ { 30, 14 }, { 28, 26 }, { 23, 37 }, { 12, 55 }, ++ { 11, 65 }, { 37, -33 }, { 39, -36 }, { 40, -37 }, ++ { 38, -30 }, { 46, -33 }, { 42, -30 }, { 40, -24 }, ++ { 49, -29 }, { 38, -12 }, { 40, -10 }, { 38, -3 }, ++ { 46, -5 }, { 31, 20 }, { 29, 30 }, { 25, 44 }, ++ { 19, -6 }, { 18, -6 }, { 14, 0 }, { 26, -12 }, ++ { 31, -16 }, { 33, -25 }, { 33, -22 }, { 37, -28 }, ++ { 39, -30 }, { 42, -30 }, { 47, -42 }, { 45, -36 }, ++ { 49, -34 }, { 41, -17 }, { 32, 9 }, { 69, -71 }, ++ { 63, -63 }, { 66, -64 }, { 77, -74 }, { 54, -39 }, ++ { 52, -35 }, { 41, -10 }, { 36, 0 }, { 40, -1 }, ++ { 30, 14 }, { 28, 26 }, { 23, 37 }, { 12, 55 }, ++ { 11, 65 }, { 37, -33 }, { 39, -36 }, { 40, -37 }, ++ { 38, -30 }, { 46, -33 }, { 42, -30 }, { 40, -24 }, ++ { 49, -29 }, { 38, -12 }, { 40, -10 }, { 38, -3 }, ++ { 46, -5 }, { 31, 20 }, { 29, 30 }, { 25, 44 }, ++ { -23, 112 }, { -15, 71 }, { -7, 61 }, { 0, 53 }, ++ { -5, 66 }, { -11, 77 }, { -9, 80 }, { -9, 84 }, ++ { -10, 87 }, { -34, 127 }, { -21, 101 }, { -3, 39 }, ++ { -5, 53 }, { -7, 61 }, { -11, 75 }, { -15, 77 }, ++ { -17, 91 }, { -25, 107 }, { -25, 111 }, { -28, 122 }, ++ { -11, 76 }, { -10, 44 }, { -10, 52 }, { -10, 57 }, ++ { -9, 58 }, { -16, 72 }, { -7, 69 }, { -4, 69 }, ++ { -5, 74 }, { -9, 86 }, { -23, 112 }, { -15, 71 }, ++ { -7, 61 }, { 0, 53 }, { -5, 66 }, { -11, 77 }, ++ { -9, 80 }, { -9, 84 }, { -10, 87 }, { -34, 127 }, ++ { -21, 101 }, { -3, 39 }, { -5, 53 }, { -7, 61 }, ++ { -11, 75 }, { -15, 77 }, { -17, 91 }, { -25, 107 }, ++ { -25, 111 }, { -28, 122 }, { -11, 76 }, { -10, 44 }, ++ { -10, 52 }, { -10, 57 }, { -9, 58 }, { -16, 72 }, ++ { -7, 69 }, { -4, 69 }, { -5, 74 }, { -9, 86 }, ++ { -2, 73 }, { -12, 104 }, { -9, 91 }, { -31, 127 }, ++ { -2, 73 }, { -12, 104 }, { -9, 91 }, { -31, 127 }, ++ { -2, 73 }, { -12, 104 }, { -9, 91 }, { -31, 127 } ++ }, ++ ++ /* i_cabac_init_idc == 2 */ ++ { ++ /* 0 - 10 */ ++ { 20, -15 }, { 2, 54 }, { 3, 74 }, { 20, -15 }, ++ { 2, 54 }, { 3, 74 }, { -28, 127 }, { -23, 104 }, ++ { -6, 53 }, { -1, 54 }, { 7, 51 }, ++ ++ /* 11 - 23 */ ++ { 29, 16 }, { 25, 0 }, { 14, 0 }, { -10, 51 }, ++ { -3, 62 }, { -27, 99 }, { 26, 16 }, { -4, 85 }, ++ { -24, 102 }, { 5, 57 }, { 6, 57 }, { -17, 73 }, ++ { 14, 57 }, ++ ++ /* 24 - 39 */ ++ { 20, 40 }, { 20, 10 }, { 29, 0 }, { 54, 0 }, ++ { 37, 42 }, { 12, 97 }, { -32, 127 }, { -22, 117 }, ++ { -2, 74 }, { -4, 85 }, { -24, 102 }, { 5, 57 }, ++ { -6, 93 }, { -14, 88 }, { -6, 44 }, { 4, 55 }, ++ ++ /* 40 - 53 */ ++ { -11, 89 },{ -15, 103 },{ -21, 116 },{ 19, 57 }, ++ { 20, 58 },{ 4, 84 },{ 6, 96 },{ 1, 63 }, ++ { -5, 85 },{ -13, 106 },{ 5, 63 },{ 6, 75 }, ++ { -3, 90 },{ -1, 101 }, ++ ++ /* 54 - 59 */ ++ { 3, 55 },{ -4, 79 },{ -2, 75 },{ -12, 97 }, ++ { -7, 50 },{ 1, 60 }, ++ ++ /* 60 - 69 */ ++ { 0, 41 }, { 0, 63 }, { 0, 63 }, { 0, 63 }, ++ { -9, 83 }, { 4, 86 }, { 0, 97 }, { -7, 72 }, ++ { 13, 41 }, { 3, 62 }, ++ ++ /* 70 - 104 */ ++ { 7, 34 }, { -9, 88 }, { -20, 127 }, { -36, 127 }, ++ { -17, 91 }, { -14, 95 }, { -25, 84 }, { -25, 86 }, ++ { -12, 89 }, { -17, 91 }, { -31, 127 }, { -14, 76 }, ++ { -18, 103 }, { -13, 90 }, { -37, 127 }, { 11, 80 }, ++ { 5, 76 }, { 2, 84 }, { 5, 78 }, { -6, 55 }, ++ { 4, 61 }, { -14, 83 }, { -37, 127 }, { -5, 79 }, ++ { -11, 104 }, { -11, 91 }, { -30, 127 }, { 0, 65 }, ++ { -2, 79 }, { 0, 72 }, { -4, 92 }, { -6, 56 }, ++ { 3, 68 }, { -8, 71 }, { -13, 98 }, ++ ++ /* 105 -> 165 */ ++ { -4, 86 }, { -12, 88 }, { -5, 82 }, { -3, 72 }, ++ { -4, 67 }, { -8, 72 }, { -16, 89 }, { -9, 69 }, ++ { -1, 59 }, { 5, 66 }, { 4, 57 }, { -4, 71 }, ++ { -2, 71 }, { 2, 58 }, { -1, 74 }, { -4, 44 }, ++ { -1, 69 }, { 0, 62 }, { -7, 51 }, { -4, 47 }, ++ { -6, 42 }, { -3, 41 }, { -6, 53 }, { 8, 76 }, ++ { -9, 78 }, { -11, 83 }, { 9, 52 }, { 0, 67 }, ++ { -5, 90 }, { 1, 67 }, { -15, 72 }, { -5, 75 }, ++ { -8, 80 }, { -21, 83 }, { -21, 64 }, { -13, 31 }, ++ { -25, 64 }, { -29, 94 }, { 9, 75 }, { 17, 63 }, ++ { -8, 74 }, { -5, 35 }, { -2, 27 }, { 13, 91 }, ++ { 3, 65 }, { -7, 69 }, { 8, 77 }, { -10, 66 }, ++ { 3, 62 }, { -3, 68 }, { -20, 81 }, { 0, 30 }, ++ { 1, 7 }, { -3, 23 }, { -21, 74 }, { 16, 66 }, ++ { -23, 124 }, { 17, 37 }, { 44, -18 }, { 50, -34 }, ++ { -22, 127 }, ++ ++ /* 166 - 226 */ ++ { 4, 39 }, { 0, 42 }, { 7, 34 }, { 11, 29 }, ++ { 8, 31 }, { 6, 37 }, { 7, 42 }, { 3, 40 }, ++ { 8, 33 }, { 13, 43 }, { 13, 36 }, { 4, 47 }, ++ { 3, 55 }, { 2, 58 }, { 6, 60 }, { 8, 44 }, ++ { 11, 44 }, { 14, 42 }, { 7, 48 }, { 4, 56 }, ++ { 4, 52 }, { 13, 37 }, { 9, 49 }, { 19, 58 }, ++ { 10, 48 }, { 12, 45 }, { 0, 69 }, { 20, 33 }, ++ { 8, 63 }, { 35, -18 }, { 33, -25 }, { 28, -3 }, ++ { 24, 10 }, { 27, 0 }, { 34, -14 }, { 52, -44 }, ++ { 39, -24 }, { 19, 17 }, { 31, 25 }, { 36, 29 }, ++ { 24, 33 }, { 34, 15 }, { 30, 20 }, { 22, 73 }, ++ { 20, 34 }, { 19, 31 }, { 27, 44 }, { 19, 16 }, ++ { 15, 36 }, { 15, 36 }, { 21, 28 }, { 25, 21 }, ++ { 30, 20 }, { 31, 12 }, { 27, 16 }, { 24, 42 }, ++ { 0, 93 }, { 14, 56 }, { 15, 57 }, { 26, 38 }, ++ { -24, 127 }, ++ ++ /* 227 - 275 */ ++ { -24, 115 }, { -22, 82 }, { -9, 62 }, { 0, 53 }, ++ { 0, 59 }, { -14, 85 }, { -13, 89 }, { -13, 94 }, ++ { -11, 92 }, { -29, 127 }, { -21, 100 }, { -14, 57 }, ++ { -12, 67 }, { -11, 71 }, { -10, 77 }, { -21, 85 }, ++ { -16, 88 }, { -23, 104 }, { -15, 98 }, { -37, 127 }, ++ { -10, 82 }, { -8, 48 }, { -8, 61 }, { -8, 66 }, ++ { -7, 70 }, { -14, 75 }, { -10, 79 }, { -9, 83 }, ++ { -12, 92 }, { -18, 108 }, { -4, 79 }, { -22, 69 }, ++ { -16, 75 }, { -2, 58 }, { 1, 58 }, { -13, 78 }, ++ { -9, 83 }, { -4, 81 }, { -13, 99 }, { -13, 81 }, ++ { -6, 38 }, { -13, 62 }, { -6, 58 }, { -2, 59 }, ++ { -16, 73 }, { -10, 76 }, { -13, 86 }, { -9, 83 }, ++ { -10, 87 }, ++ ++ /* 276 a bit special (not used, h264_cabac_encode_bypass is used instead) */ ++ { 0, 0 }, ++ ++ /* 277 - 337 */ ++ { -22, 127 }, { -25, 127 }, { -25, 120 }, { -27, 127 }, ++ { -19, 114 }, { -23, 117 }, { -25, 118 }, { -26, 117 }, ++ { -24, 113 }, { -28, 118 }, { -31, 120 }, { -37, 124 }, ++ { -10, 94 }, { -15, 102 }, { -10, 99 }, { -13, 106 }, ++ { -50, 127 }, { -5, 92 }, { 17, 57 }, { -5, 86 }, ++ { -13, 94 }, { -12, 91 }, { -2, 77 }, { 0, 71 }, ++ { -1, 73 }, { 4, 64 }, { -7, 81 }, { 5, 64 }, ++ { 15, 57 }, { 1, 67 }, { 0, 68 }, { -10, 67 }, ++ { 1, 68 }, { 0, 77 }, { 2, 64 }, { 0, 68 }, ++ { -5, 78 }, { 7, 55 }, { 5, 59 }, { 2, 65 }, ++ { 14, 54 }, { 15, 44 }, { 5, 60 }, { 2, 70 }, ++ { -2, 76 }, { -18, 86 }, { 12, 70 }, { 5, 64 }, ++ { -12, 70 }, { 11, 55 }, { 5, 56 }, { 0, 69 }, ++ { 2, 65 }, { -6, 74 }, { 5, 54 }, { 7, 54 }, ++ { -6, 76 }, { -11, 82 }, { -2, 77 }, { -2, 77 }, ++ { 25, 42 }, ++ ++ /* 338 - 398 */ ++ { 17, -13 }, { 16, -9 }, { 17, -12 }, { 27, -21 }, ++ { 37, -30 }, { 41, -40 }, { 42, -41 }, { 48, -47 }, ++ { 39, -32 }, { 46, -40 }, { 52, -51 }, { 46, -41 }, ++ { 52, -39 }, { 43, -19 }, { 32, 11 }, { 61, -55 }, ++ { 56, -46 }, { 62, -50 }, { 81, -67 }, { 45, -20 }, ++ { 35, -2 }, { 28, 15 }, { 34, 1 }, { 39, 1 }, ++ { 30, 17 }, { 20, 38 }, { 18, 45 }, { 15, 54 }, ++ { 0, 79 }, { 36, -16 }, { 37, -14 }, { 37, -17 }, ++ { 32, 1 }, { 34, 15 }, { 29, 15 }, { 24, 25 }, ++ { 34, 22 }, { 31, 16 }, { 35, 18 }, { 31, 28 }, ++ { 33, 41 }, { 36, 28 }, { 27, 47 }, { 21, 62 }, ++ { 18, 31 }, { 19, 26 }, { 36, 24 }, { 24, 23 }, ++ { 27, 16 }, { 24, 30 }, { 31, 29 }, { 22, 41 }, ++ { 22, 42 }, { 16, 60 }, { 15, 52 }, { 14, 60 }, ++ { 3, 78 }, { -16, 123 }, { 21, 53 }, { 22, 56 }, ++ { 25, 61 }, ++ ++ /* 399 -> 435 */ ++ { 21, 33 }, { 19, 50 }, { 17, 61 }, ++ { -3, 78 }, { -8, 74 }, { -9, 72 }, { -10, 72 }, ++ { -18, 75 }, { -12, 71 }, { -11, 63 }, { -5, 70 }, ++ { -17, 75 }, { -14, 72 }, { -16, 67 }, { -8, 53 }, ++ { -14, 59 }, { -9, 52 }, { -11, 68 }, { 9, -2 }, ++ { 30, -10 }, { 31, -4 }, { 33, -1 }, { 33, 7 }, ++ { 31, 12 }, { 37, 23 }, { 31, 38 }, { 20, 64 }, ++ { -9, 71 }, { -7, 37 }, { -8, 44 }, { -11, 49 }, ++ { -10, 56 }, { -12, 59 }, { -8, 63 }, { -9, 67 }, ++ { -6, 68 }, { -10, 79 }, ++ ++ /* 436 -> 459 */ ++ { -3, 78 }, { -8, 74 }, { -9, 72 }, { -10, 72 }, ++ { -18, 75 }, { -12, 71 }, { -11, 63 }, { -5, 70 }, ++ { -17, 75 }, { -14, 72 }, { -16, 67 }, { -8, 53 }, ++ { -14, 59 }, { -9, 52 }, { -11, 68 }, { 9, -2 }, ++ { 30, -10 }, { 31, -4 }, { 33, -1 }, { 33, 7 }, ++ { 31, 12 }, { 37, 23 }, { 31, 38 }, { 20, 64 }, ++ ++ /* 460 - 1024 */ ++ { 11, 80 }, { 5, 76 }, { 2, 84 }, { 5, 78 }, ++ { -6, 55 }, { 4, 61 }, { -14, 83 }, { -37, 127 }, ++ { -5, 79 }, { -11, 104 }, { -11, 91 }, { -30, 127 }, ++ { 11, 80 }, { 5, 76 }, { 2, 84 }, { 5, 78 }, ++ { -6, 55 }, { 4, 61 }, { -14, 83 }, { -37, 127 }, ++ { -5, 79 }, { -11, 104 }, { -11, 91 }, { -30, 127 }, ++ { -4, 86 }, { -12, 88 }, { -5, 82 }, { -3, 72 }, ++ { -4, 67 }, { -8, 72 }, { -16, 89 }, { -9, 69 }, ++ { -1, 59 }, { 5, 66 }, { 4, 57 }, { -4, 71 }, ++ { -2, 71 }, { 2, 58 }, { -1, 74 }, { -4, 44 }, ++ { -1, 69 }, { 0, 62 }, { -7, 51 }, { -4, 47 }, ++ { -6, 42 }, { -3, 41 }, { -6, 53 }, { 8, 76 }, ++ { -9, 78 }, { -11, 83 }, { 9, 52 }, { 0, 67 }, ++ { -5, 90 }, { 1, 67 }, { -15, 72 }, { -5, 75 }, ++ { -8, 80 }, { -21, 83 }, { -21, 64 }, { -13, 31 }, ++ { -25, 64 }, { -29, 94 }, { 9, 75 }, { 17, 63 }, ++ { -8, 74 }, { -5, 35 }, { -2, 27 }, { 13, 91 }, ++ { -4, 86 }, { -12, 88 }, { -5, 82 }, { -3, 72 }, ++ { -4, 67 }, { -8, 72 }, { -16, 89 }, { -9, 69 }, ++ { -1, 59 }, { 5, 66 }, { 4, 57 }, { -4, 71 }, ++ { -2, 71 }, { 2, 58 }, { -1, 74 }, { -4, 44 }, ++ { -1, 69 }, { 0, 62 }, { -7, 51 }, { -4, 47 }, ++ { -6, 42 }, { -3, 41 }, { -6, 53 }, { 8, 76 }, ++ { -9, 78 }, { -11, 83 }, { 9, 52 }, { 0, 67 }, ++ { -5, 90 }, { 1, 67 }, { -15, 72 }, { -5, 75 }, ++ { -8, 80 }, { -21, 83 }, { -21, 64 }, { -13, 31 }, ++ { -25, 64 }, { -29, 94 }, { 9, 75 }, { 17, 63 }, ++ { -8, 74 }, { -5, 35 }, { -2, 27 }, { 13, 91 }, ++ { 4, 39 }, { 0, 42 }, { 7, 34 }, { 11, 29 }, ++ { 8, 31 }, { 6, 37 }, { 7, 42 }, { 3, 40 }, ++ { 8, 33 }, { 13, 43 }, { 13, 36 }, { 4, 47 }, ++ { 3, 55 }, { 2, 58 }, { 6, 60 }, { 8, 44 }, ++ { 11, 44 }, { 14, 42 }, { 7, 48 }, { 4, 56 }, ++ { 4, 52 }, { 13, 37 }, { 9, 49 }, { 19, 58 }, ++ { 10, 48 }, { 12, 45 }, { 0, 69 }, { 20, 33 }, ++ { 8, 63 }, { 35, -18 }, { 33, -25 }, { 28, -3 }, ++ { 24, 10 }, { 27, 0 }, { 34, -14 }, { 52, -44 }, ++ { 39, -24 }, { 19, 17 }, { 31, 25 }, { 36, 29 }, ++ { 24, 33 }, { 34, 15 }, { 30, 20 }, { 22, 73 }, ++ { 4, 39 }, { 0, 42 }, { 7, 34 }, { 11, 29 }, ++ { 8, 31 }, { 6, 37 }, { 7, 42 }, { 3, 40 }, ++ { 8, 33 }, { 13, 43 }, { 13, 36 }, { 4, 47 }, ++ { 3, 55 }, { 2, 58 }, { 6, 60 }, { 8, 44 }, ++ { 11, 44 }, { 14, 42 }, { 7, 48 }, { 4, 56 }, ++ { 4, 52 }, { 13, 37 }, { 9, 49 }, { 19, 58 }, ++ { 10, 48 }, { 12, 45 }, { 0, 69 }, { 20, 33 }, ++ { 8, 63 }, { 35, -18 }, { 33, -25 }, { 28, -3 }, ++ { 24, 10 }, { 27, 0 }, { 34, -14 }, { 52, -44 }, ++ { 39, -24 }, { 19, 17 }, { 31, 25 }, { 36, 29 }, ++ { 24, 33 }, { 34, 15 }, { 30, 20 }, { 22, 73 }, ++ { -3, 78 }, { -8, 74 }, { -9, 72 }, { -10, 72 }, ++ { -18, 75 }, { -12, 71 }, { -11, 63 }, { -5, 70 }, ++ { -17, 75 }, { -14, 72 }, { -16, 67 }, { -8, 53 }, ++ { -14, 59 }, { -9, 52 }, { -11, 68 }, { -3, 78 }, ++ { -8, 74 }, { -9, 72 }, { -10, 72 }, { -18, 75 }, ++ { -12, 71 }, { -11, 63 }, { -5, 70 }, { -17, 75 }, ++ { -14, 72 }, { -16, 67 }, { -8, 53 }, { -14, 59 }, ++ { -9, 52 }, { -11, 68 }, { 9, -2 }, { 30, -10 }, ++ { 31, -4 }, { 33, -1 }, { 33, 7 }, { 31, 12 }, ++ { 37, 23 }, { 31, 38 }, { 20, 64 }, { 9, -2 }, ++ { 30, -10 }, { 31, -4 }, { 33, -1 }, { 33, 7 }, ++ { 31, 12 }, { 37, 23 }, { 31, 38 }, { 20, 64 }, ++ { -9, 71 }, { -7, 37 }, { -8, 44 }, { -11, 49 }, ++ { -10, 56 }, { -12, 59 }, { -8, 63 }, { -9, 67 }, ++ { -6, 68 }, { -10, 79 }, { -3, 78 }, { -8, 74 }, ++ { -9, 72 }, { -10, 72 }, { -18, 75 }, { -12, 71 }, ++ { -11, 63 }, { -5, 70 }, { -17, 75 }, { -14, 72 }, ++ { -16, 67 }, { -8, 53 }, { -14, 59 }, { -9, 52 }, ++ { -11, 68 }, { -3, 78 }, { -8, 74 }, { -9, 72 }, ++ { -10, 72 }, { -18, 75 }, { -12, 71 }, { -11, 63 }, ++ { -5, 70 }, { -17, 75 }, { -14, 72 }, { -16, 67 }, ++ { -8, 53 }, { -14, 59 }, { -9, 52 }, { -11, 68 }, ++ { 9, -2 }, { 30, -10 }, { 31, -4 }, { 33, -1 }, ++ { 33, 7 }, { 31, 12 }, { 37, 23 }, { 31, 38 }, ++ { 20, 64 }, { 9, -2 }, { 30, -10 }, { 31, -4 }, ++ { 33, -1 }, { 33, 7 }, { 31, 12 }, { 37, 23 }, ++ { 31, 38 }, { 20, 64 }, { -9, 71 }, { -7, 37 }, ++ { -8, 44 }, { -11, 49 }, { -10, 56 }, { -12, 59 }, ++ { -8, 63 }, { -9, 67 }, { -6, 68 }, { -10, 79 }, ++ { -22, 127 }, { -25, 127 }, { -25, 120 }, { -27, 127 }, ++ { -19, 114 }, { -23, 117 }, { -25, 118 }, { -26, 117 }, ++ { -24, 113 }, { -28, 118 }, { -31, 120 }, { -37, 124 }, ++ { -10, 94 }, { -15, 102 }, { -10, 99 }, { -13, 106 }, ++ { -50, 127 }, { -5, 92 }, { 17, 57 }, { -5, 86 }, ++ { -13, 94 }, { -12, 91 }, { -2, 77 }, { 0, 71 }, ++ { -1, 73 }, { 4, 64 }, { -7, 81 }, { 5, 64 }, ++ { 15, 57 }, { 1, 67 }, { 0, 68 }, { -10, 67 }, ++ { 1, 68 }, { 0, 77 }, { 2, 64 }, { 0, 68 }, ++ { -5, 78 }, { 7, 55 }, { 5, 59 }, { 2, 65 }, ++ { 14, 54 }, { 15, 44 }, { 5, 60 }, { 2, 70 }, ++ { -22, 127 }, { -25, 127 }, { -25, 120 }, { -27, 127 }, ++ { -19, 114 }, { -23, 117 }, { -25, 118 }, { -26, 117 }, ++ { -24, 113 }, { -28, 118 }, { -31, 120 }, { -37, 124 }, ++ { -10, 94 }, { -15, 102 }, { -10, 99 }, { -13, 106 }, ++ { -50, 127 }, { -5, 92 }, { 17, 57 }, { -5, 86 }, ++ { -13, 94 }, { -12, 91 }, { -2, 77 }, { 0, 71 }, ++ { -1, 73 }, { 4, 64 }, { -7, 81 }, { 5, 64 }, ++ { 15, 57 }, { 1, 67 }, { 0, 68 }, { -10, 67 }, ++ { 1, 68 }, { 0, 77 }, { 2, 64 }, { 0, 68 }, ++ { -5, 78 }, { 7, 55 }, { 5, 59 }, { 2, 65 }, ++ { 14, 54 }, { 15, 44 }, { 5, 60 }, { 2, 70 }, ++ { 17, -13 }, { 16, -9 }, { 17, -12 }, { 27, -21 }, ++ { 37, -30 }, { 41, -40 }, { 42, -41 }, { 48, -47 }, ++ { 39, -32 }, { 46, -40 }, { 52, -51 }, { 46, -41 }, ++ { 52, -39 }, { 43, -19 }, { 32, 11 }, { 61, -55 }, ++ { 56, -46 }, { 62, -50 }, { 81, -67 }, { 45, -20 }, ++ { 35, -2 }, { 28, 15 }, { 34, 1 }, { 39, 1 }, ++ { 30, 17 }, { 20, 38 }, { 18, 45 }, { 15, 54 }, ++ { 0, 79 }, { 36, -16 }, { 37, -14 }, { 37, -17 }, ++ { 32, 1 }, { 34, 15 }, { 29, 15 }, { 24, 25 }, ++ { 34, 22 }, { 31, 16 }, { 35, 18 }, { 31, 28 }, ++ { 33, 41 }, { 36, 28 }, { 27, 47 }, { 21, 62 }, ++ { 17, -13 }, { 16, -9 }, { 17, -12 }, { 27, -21 }, ++ { 37, -30 }, { 41, -40 }, { 42, -41 }, { 48, -47 }, ++ { 39, -32 }, { 46, -40 }, { 52, -51 }, { 46, -41 }, ++ { 52, -39 }, { 43, -19 }, { 32, 11 }, { 61, -55 }, ++ { 56, -46 }, { 62, -50 }, { 81, -67 }, { 45, -20 }, ++ { 35, -2 }, { 28, 15 }, { 34, 1 }, { 39, 1 }, ++ { 30, 17 }, { 20, 38 }, { 18, 45 }, { 15, 54 }, ++ { 0, 79 }, { 36, -16 }, { 37, -14 }, { 37, -17 }, ++ { 32, 1 }, { 34, 15 }, { 29, 15 }, { 24, 25 }, ++ { 34, 22 }, { 31, 16 }, { 35, 18 }, { 31, 28 }, ++ { 33, 41 }, { 36, 28 }, { 27, 47 }, { 21, 62 }, ++ { -24, 115 }, { -22, 82 }, { -9, 62 }, { 0, 53 }, ++ { 0, 59 }, { -14, 85 }, { -13, 89 }, { -13, 94 }, ++ { -11, 92 }, { -29, 127 }, { -21, 100 }, { -14, 57 }, ++ { -12, 67 }, { -11, 71 }, { -10, 77 }, { -21, 85 }, ++ { -16, 88 }, { -23, 104 }, { -15, 98 }, { -37, 127 }, ++ { -10, 82 }, { -8, 48 }, { -8, 61 }, { -8, 66 }, ++ { -7, 70 }, { -14, 75 }, { -10, 79 }, { -9, 83 }, ++ { -12, 92 }, { -18, 108 }, { -24, 115 }, { -22, 82 }, ++ { -9, 62 }, { 0, 53 }, { 0, 59 }, { -14, 85 }, ++ { -13, 89 }, { -13, 94 }, { -11, 92 }, { -29, 127 }, ++ { -21, 100 }, { -14, 57 }, { -12, 67 }, { -11, 71 }, ++ { -10, 77 }, { -21, 85 }, { -16, 88 }, { -23, 104 }, ++ { -15, 98 }, { -37, 127 }, { -10, 82 }, { -8, 48 }, ++ { -8, 61 }, { -8, 66 }, { -7, 70 }, { -14, 75 }, ++ { -10, 79 }, { -9, 83 }, { -12, 92 }, { -18, 108 }, ++ { -5, 79 }, { -11, 104 }, { -11, 91 }, { -30, 127 }, ++ { -5, 79 }, { -11, 104 }, { -11, 91 }, { -30, 127 }, ++ { -5, 79 }, { -11, 104 }, { -11, 91 }, { -30, 127 } ++ } ++}; ++ ++const uint8_t h264_cabac_range_lps[64][4] = ++{ ++ { 2, 2, 2, 2}, { 6, 7, 8, 9}, { 6, 7, 9, 10}, { 6, 8, 9, 11}, ++ { 7, 8, 10, 11}, { 7, 9, 10, 12}, { 7, 9, 11, 12}, { 8, 9, 11, 13}, ++ { 8, 10, 12, 14}, { 9, 11, 12, 14}, { 9, 11, 13, 15}, { 10, 12, 14, 16}, ++ { 10, 12, 15, 17}, { 11, 13, 15, 18}, { 11, 14, 16, 19}, { 12, 14, 17, 20}, ++ { 12, 15, 18, 21}, { 13, 16, 19, 22}, { 14, 17, 20, 23}, { 14, 18, 21, 24}, ++ { 15, 19, 22, 25}, { 16, 20, 23, 27}, { 17, 21, 25, 28}, { 18, 22, 26, 30}, ++ { 19, 23, 27, 31}, { 20, 24, 29, 33}, { 21, 26, 30, 35}, { 22, 27, 32, 37}, ++ { 23, 28, 33, 39}, { 24, 30, 35, 41}, { 26, 31, 37, 43}, { 27, 33, 39, 45}, ++ { 29, 35, 41, 48}, { 30, 37, 43, 50}, { 32, 39, 46, 53}, { 33, 41, 48, 56}, ++ { 35, 43, 51, 59}, { 37, 45, 54, 62}, { 39, 48, 56, 65}, { 41, 50, 59, 69}, ++ { 43, 53, 63, 72}, { 46, 56, 66, 76}, { 48, 59, 69, 80}, { 51, 62, 73, 85}, ++ { 53, 65, 77, 89}, { 56, 69, 81, 94}, { 59, 72, 86, 99}, { 62, 76, 90, 104}, ++ { 66, 80, 95, 110}, { 69, 85, 100, 116}, { 73, 89, 105, 122}, { 77, 94, 111, 128}, ++ { 81, 99, 117, 135}, { 85, 104, 123, 142}, { 90, 110, 130, 150}, { 95, 116, 137, 158}, ++ {100, 122, 144, 166}, {105, 128, 152, 175}, {111, 135, 160, 185}, {116, 142, 169, 195}, ++ {123, 150, 178, 205}, {128, 158, 187, 216}, {128, 167, 197, 227}, {128, 176, 208, 240} ++}; ++ ++const uint8_t h264_cabac_transition[128][2] = ++{ ++ { 0, 0}, { 1, 1}, { 2, 50}, { 51, 3}, { 2, 50}, { 51, 3}, { 4, 52}, { 53, 5}, ++ { 6, 52}, { 53, 7}, { 8, 52}, { 53, 9}, { 10, 54}, { 55, 11}, { 12, 54}, { 55, 13}, ++ { 14, 54}, { 55, 15}, { 16, 56}, { 57, 17}, { 18, 56}, { 57, 19}, { 20, 56}, { 57, 21}, ++ { 22, 58}, { 59, 23}, { 24, 58}, { 59, 25}, { 26, 60}, { 61, 27}, { 28, 60}, { 61, 29}, ++ { 30, 60}, { 61, 31}, { 32, 62}, { 63, 33}, { 34, 62}, { 63, 35}, { 36, 64}, { 65, 37}, ++ { 38, 66}, { 67, 39}, { 40, 66}, { 67, 41}, { 42, 66}, { 67, 43}, { 44, 68}, { 69, 45}, ++ { 46, 68}, { 69, 47}, { 48, 70}, { 71, 49}, { 50, 72}, { 73, 51}, { 52, 72}, { 73, 53}, ++ { 54, 74}, { 75, 55}, { 56, 74}, { 75, 57}, { 58, 76}, { 77, 59}, { 60, 78}, { 79, 61}, ++ { 62, 78}, { 79, 63}, { 64, 80}, { 81, 65}, { 66, 82}, { 83, 67}, { 68, 82}, { 83, 69}, ++ { 70, 84}, { 85, 71}, { 72, 84}, { 85, 73}, { 74, 88}, { 89, 75}, { 76, 88}, { 89, 77}, ++ { 78, 90}, { 91, 79}, { 80, 90}, { 91, 81}, { 82, 94}, { 95, 83}, { 84, 94}, { 95, 85}, ++ { 86, 96}, { 97, 87}, { 88, 96}, { 97, 89}, { 90, 100}, {101, 91}, { 92, 100}, {101, 93}, ++ { 94, 102}, {103, 95}, { 96, 104}, {105, 97}, { 98, 104}, {105, 99}, {100, 108}, {109, 101}, ++ {102, 108}, {109, 103}, {104, 110}, {111, 105}, {106, 112}, {113, 107}, {108, 114}, {115, 109}, ++ {110, 116}, {117, 111}, {112, 118}, {119, 113}, {114, 118}, {119, 115}, {116, 122}, {123, 117}, ++ {118, 122}, {123, 119}, {120, 124}, {125, 121}, {122, 126}, {127, 123}, {124, 127}, {126, 125} ++}; ++ ++const uint8_t h264_cabac_renorm_shift[64] = ++{ ++ 6,5,4,4,3,3,3,3,2,2,2,2,2,2,2,2, ++ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, ++ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, ++ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, ++}; ++ ++/* -ln2(probability) */ ++const uint16_t h264_cabac_entropy[128] = ++{ ++ C_FIX8(0.0273), C_FIX8(5.7370), C_FIX8(0.0288), C_FIX8(5.6618), ++ C_FIX8(0.0303), C_FIX8(5.5866), C_FIX8(0.0320), C_FIX8(5.5114), ++ C_FIX8(0.0337), C_FIX8(5.4362), C_FIX8(0.0355), C_FIX8(5.3610), ++ C_FIX8(0.0375), C_FIX8(5.2859), C_FIX8(0.0395), C_FIX8(5.2106), ++ C_FIX8(0.0416), C_FIX8(5.1354), C_FIX8(0.0439), C_FIX8(5.0602), ++ C_FIX8(0.0463), C_FIX8(4.9851), C_FIX8(0.0488), C_FIX8(4.9099), ++ C_FIX8(0.0515), C_FIX8(4.8347), C_FIX8(0.0543), C_FIX8(4.7595), ++ C_FIX8(0.0572), C_FIX8(4.6843), C_FIX8(0.0604), C_FIX8(4.6091), ++ C_FIX8(0.0637), C_FIX8(4.5339), C_FIX8(0.0671), C_FIX8(4.4588), ++ C_FIX8(0.0708), C_FIX8(4.3836), C_FIX8(0.0747), C_FIX8(4.3083), ++ C_FIX8(0.0788), C_FIX8(4.2332), C_FIX8(0.0832), C_FIX8(4.1580), ++ C_FIX8(0.0878), C_FIX8(4.0828), C_FIX8(0.0926), C_FIX8(4.0076), ++ C_FIX8(0.0977), C_FIX8(3.9324), C_FIX8(0.1032), C_FIX8(3.8572), ++ C_FIX8(0.1089), C_FIX8(3.7820), C_FIX8(0.1149), C_FIX8(3.7068), ++ C_FIX8(0.1214), C_FIX8(3.6316), C_FIX8(0.1282), C_FIX8(3.5565), ++ C_FIX8(0.1353), C_FIX8(3.4813), C_FIX8(0.1429), C_FIX8(3.4061), ++ C_FIX8(0.1510), C_FIX8(3.3309), C_FIX8(0.1596), C_FIX8(3.2557), ++ C_FIX8(0.1686), C_FIX8(3.1805), C_FIX8(0.1782), C_FIX8(3.1053), ++ C_FIX8(0.1884), C_FIX8(3.0301), C_FIX8(0.1992), C_FIX8(2.9549), ++ C_FIX8(0.2107), C_FIX8(2.8797), C_FIX8(0.2229), C_FIX8(2.8046), ++ C_FIX8(0.2358), C_FIX8(2.7294), C_FIX8(0.2496), C_FIX8(2.6542), ++ C_FIX8(0.2642), C_FIX8(2.5790), C_FIX8(0.2798), C_FIX8(2.5038), ++ C_FIX8(0.2964), C_FIX8(2.4286), C_FIX8(0.3142), C_FIX8(2.3534), ++ C_FIX8(0.3331), C_FIX8(2.2782), C_FIX8(0.3532), C_FIX8(2.2030), ++ C_FIX8(0.3748), C_FIX8(2.1278), C_FIX8(0.3979), C_FIX8(2.0527), ++ C_FIX8(0.4226), C_FIX8(1.9775), C_FIX8(0.4491), C_FIX8(1.9023), ++ C_FIX8(0.4776), C_FIX8(1.8271), C_FIX8(0.5082), C_FIX8(1.7519), ++ C_FIX8(0.5412), C_FIX8(1.6767), C_FIX8(0.5768), C_FIX8(1.6015), ++ C_FIX8(0.6152), C_FIX8(1.5263), C_FIX8(0.6568), C_FIX8(1.4511), ++ C_FIX8(0.7020), C_FIX8(1.3759), C_FIX8(0.7513), C_FIX8(1.3008), ++ C_FIX8(0.8050), C_FIX8(1.2256), C_FIX8(0.8638), C_FIX8(1.1504), ++ C_FIX8(0.9285), C_FIX8(1.0752), C_FIX8(1.0000), C_FIX8(1.0000) ++}; ++ ++uint8_t h264_cabac_contexts[4][QP_MAX_SPEC+1][1024]; ++ ++void h264_cabac_init(void) ++{ ++ int i = 0, j = 0, qp = 0; ++ int ctx_count = 460; ++ for( i = 0; i < 4; i++ ) ++ { ++ const int8_t (*cabac_context_init)[1024][2] = i == 0 ? &h264_cabac_context_init_I ++ : &h264_cabac_context_init_PB[i-1]; ++ for( qp = 0; qp <= QP_MAX_SPEC; qp++ ) ++ for( j = 0; j < ctx_count; j++ ) ++ { ++ h264_cabac_contexts[i][qp][j] = c_clip3( (((*cabac_context_init)[j][0] * qp) >> 4) + (*cabac_context_init)[j][1], 1, 126 ); ++ } ++ } ++} ++ ++/***************************************************************************** ++ * ++ *****************************************************************************/ ++void h264_cabac_context_init(h264_cabac_t *cb, int i_slice_type, int i_qp, int i_model ) ++{ ++ memcpy( cb->state, h264_cabac_contexts[i_slice_type == SLICE_TYPE_I ? 0 : i_model + 1][i_qp], 460); ++} ++ ++#if 0 ++void h264_cabac_encode_init_core( h264_cabac_t *cb ) ++{ ++ cb->i_low = 0; ++ cb->i_range = 0x01FE; ++ cb->i_queue = -9; // the first bit will be shifted away and not written ++ cb->i_bytes_outstanding = 0; ++} ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_cabac.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_cabac.h.patch new file mode 100644 index 00000000..eea2bdae --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_cabac.h.patch @@ -0,0 +1,32 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/helix/h264enc/cabac.h b/drivers/media/platform/ingenic-vcodec/helix/h264enc/cabac.h +--- a/drivers/media/platform/ingenic-vcodec/helix/h264enc/cabac.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/helix/h264enc/cabac.h 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,28 @@ ++#ifndef __CABAC_H__ ++#define __CABAC_H__ ++ ++#include "common.h" ++ ++typedef struct ++{ ++ /* state */ ++ int i_low; ++ int i_range; ++ ++ uint8_t *p_start; ++ uint8_t *p; ++ uint8_t *p_end; ++ ++ /* context */ ++ uint8_t state[1024]; ++ ++} h264_cabac_t; ++ ++extern void h264_cabac_init(void); ++extern void h264_cabac_context_init(h264_cabac_t *cb, int i_slice_type, int i_qp, int i_model ); ++ ++ ++ ++ ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_common.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_common.c.patch new file mode 100644 index 00000000..926d219e --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_common.c.patch @@ -0,0 +1,15 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/helix/h264enc/common.c b/drivers/media/platform/ingenic-vcodec/helix/h264enc/common.c +--- a/drivers/media/platform/ingenic-vcodec/helix/h264enc/common.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/helix/h264enc/common.c 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,11 @@ ++#include "common.h" ++ ++ ++ ++int c_clip3(int v, int i_min, int i_max) ++{ ++ return ((v < i_min) ? i_min : ((v > i_max) ? i_max : v)); ++} ++ ++ ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_common.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_common.h.patch new file mode 100644 index 00000000..3b74d058 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_common.h.patch @@ -0,0 +1,54 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/helix/h264enc/common.h b/drivers/media/platform/ingenic-vcodec/helix/h264enc/common.h +--- a/drivers/media/platform/ingenic-vcodec/helix/h264enc/common.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/helix/h264enc/common.h 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,50 @@ ++#ifndef __H264ENC_COMMON_H__ ++#define __H264ENC_COMMON_H__ ++ ++#include ++#include ++#include "osdep.h" ++#include "bitstream.h" ++#include "set.h" ++#include "slice.h" ++#include "cabac.h" ++#include "nal.h" ++ ++#define C_MIN(a,b) ((a)<(b) ? (a) : (b)) ++#define C_MAX(a,b) ((a)>(b) ? (a) : (b)) ++#define C_MIN3(a,b,c) C_MIN((a),C_MIN((b),(c))) ++#define C_MAX3(a,b,c) C_MAX((a),C_MAX((b),(c))) ++#define C_MIN4(a,b,c,d) C_MIN((a),C_MIN3((b),(c),(d))) ++#define C_MAX4(a,b,c,d) C_MAX((a),C_MAX3((b),(c),(d))) ++#define C_XCHG(type,a,b) do{ type t = a; a = b; b = t; } while(0) ++#define C_FIX8(f) ((int)(f*(1<<8)+.5)) ++#define C_ALIGN(x,a) (((x)+((a)-1))&~((a)-1)) ++#define ARRAY_ELEMS(a) ((sizeof(a))/(sizeof(a[0]))) ++ ++ ++extern int c_clip3(int v, int i_min, int i_max); ++ ++enum profile_e ++{ ++ PROFILE_BASELINE = 66, ++ PROFILE_MAIN = 77, ++ PROFILE_HIGH = 100, ++ PROFILE_HIGH10 = 110, ++ PROFILE_HIGH422 = 122, ++ PROFILE_HIGH444_PREDICTIVE = 244, ++}; ++ ++ ++enum chroma_format_e ++{ ++ CHROMA_400 = 0, ++ CHROMA_420 = 1, ++ CHROMA_422 = 2, ++ CHROMA_444 = 3, ++}; ++ ++ ++ ++ ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_nal.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_nal.h.patch new file mode 100644 index 00000000..092a936d --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_nal.h.patch @@ -0,0 +1,63 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/helix/h264enc/nal.h b/drivers/media/platform/ingenic-vcodec/helix/h264enc/nal.h +--- a/drivers/media/platform/ingenic-vcodec/helix/h264enc/nal.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/helix/h264enc/nal.h 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,59 @@ ++#ifndef __H264_NAL_H__ ++#define __H264_NAL_H__ ++ ++ ++/**************************************************************************** ++ * NAL structure and functions ++ ****************************************************************************/ ++ ++enum nal_unit_type_e ++{ ++ NAL_UNKNOWN = 0, ++ NAL_SLICE = 1, ++ NAL_SLICE_DPA = 2, ++ NAL_SLICE_DPB = 3, ++ NAL_SLICE_DPC = 4, ++ NAL_SLICE_IDR = 5, /* ref_idc != 0 */ ++ NAL_SEI = 6, /* ref_idc == 0 */ ++ NAL_SPS = 7, ++ NAL_PPS = 8, ++ NAL_AUD = 9, ++ NAL_FILLER = 12, ++ /* ref_idc == 0 for 6,9,10,11,12 */ ++}; ++ ++enum nal_priority_e ++{ ++ NAL_PRIORITY_DISPOSABLE = 0, ++ NAL_PRIORITY_LOW = 1, ++ NAL_PRIORITY_HIGH = 2, ++ NAL_PRIORITY_HIGHEST = 3, ++}; ++ ++ ++/* The data within the payload is already NAL-encapsulated; the ref_idc and type ++ * are merely in the struct for easy access by the calling application. ++ * All data returned in an h264_nal_t, including the data in p_payload, is no longer ++ * valid after the next call to h264_encoder_encode. Thus it must be used or copied ++ * before calling h264_encoder_encode or h264_encoder_headers again. */ ++typedef struct h264_nal_t ++{ ++ int i_ref_idc; /* nal_priority_e */ ++ int i_type; /* nal_unit_type_e */ ++ int b_long_startcode; ++ int i_first_mb; /* If this NAL is a slice, the index of the first MB in the slice. */ ++ int i_last_mb; /* If this NAL is a slice, the index of the last MB in the slice. */ ++ ++ /* Size of payload (including any padding) in bytes. */ ++ int i_payload; ++ /* If param->b_annexb is set, Annex-B bytestream with startcode. ++ * Otherwise, startcode is replaced with a 4-byte size. ++ * This size is the size used in mp4/similar muxing; it is equal to i_payload-4 */ ++ uint8_t *p_payload; ++ ++ /* Size of padding in bytes. */ ++ int i_padding; ++} h264_nal_t; ++ ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_osdep.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_osdep.h.patch new file mode 100644 index 00000000..17dbef71 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_osdep.h.patch @@ -0,0 +1,39 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/helix/h264enc/osdep.h b/drivers/media/platform/ingenic-vcodec/helix/h264enc/osdep.h +--- a/drivers/media/platform/ingenic-vcodec/helix/h264enc/osdep.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/helix/h264enc/osdep.h 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,35 @@ ++#ifndef __OSDEP_H__ ++#define __OSDEP_H__ ++ ++#define WORD_SIZE sizeof(void *) /*4 Bytes*/ ++typedef long intptr_t; ++ ++typedef unsigned char uint8_t; ++typedef unsigned short uint16_t; ++typedef unsigned int uint32_t; ++typedef unsigned long long uint64_t; ++ ++ ++static inline uint32_t endian_fix32( uint32_t x ) ++{ ++ return (x<<24) + ((x<<8)&0xff0000) + ((x>>8)&0xff00) + (x>>24); ++ ++} ++static inline uint64_t endian_fix64( uint64_t x ) ++{ ++ return endian_fix32(x>>32) + ((uint64_t)endian_fix32(x)<<32); ++} ++static inline intptr_t endian_fix( intptr_t x ) ++{ ++ return WORD_SIZE == 8 ? endian_fix64(x) : endian_fix32(x); ++} ++static inline uint16_t endian_fix16( uint16_t x ) ++{ ++ return (x<<8)|(x>>8); ++} ++ ++ ++ ++ ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_set.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_set.c.patch new file mode 100644 index 00000000..4a24ccf7 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_set.c.patch @@ -0,0 +1,159 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/helix/h264enc/set.c b/drivers/media/platform/ingenic-vcodec/helix/h264enc/set.c +--- a/drivers/media/platform/ingenic-vcodec/helix/h264enc/set.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/helix/h264enc/set.c 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,155 @@ ++#include ++#include "common.h" ++ ++static void dump_sps(h264_sps_t *sps) ++{ ++ printk("---sps->i_profile_idc %d\n", sps->i_profile_idc); ++ printk("---sps->b_constraint_set0 %d\n", sps->b_constraint_set0); ++ printk("---sps->b_constraint_set1 %d\n", sps->b_constraint_set1); ++ printk("---sps->b_constraint_set2 %d\n", sps->b_constraint_set2); ++ printk("---sps->b_constraint_set3 %d\n", sps->b_constraint_set3); ++ ++ printk("---sps->i_level_idc %d\n", sps->i_level_idc); ++ printk("---sps->i_id %d\n", sps->i_id); ++ printk("---sps->i_num_ref_frames %d\n", sps->i_num_ref_frames); ++ printk("---sps->i_mb_width %d\n", sps->i_mb_width); ++ printk("---sps->i_mb_height %d\n", sps->i_mb_height); ++} ++ ++static void dump_pps(h264_pps_t *pps) ++{ ++ printk("---pps->i_sps_id %d\n", pps->i_sps_id); ++ printk("---pps->b_cabac %d\n", pps->b_cabac); ++ printk("---pps->i_num_slice_groups %d\n", pps->i_num_slice_groups); ++} ++ ++void h264e_sps_write(bs_t *s, h264_sps_t *sps) ++{ ++ bs_realign(s); ++ bs_write(s, 8, sps->i_profile_idc); ++ ++ bs_write1(s, sps->b_constraint_set0); ++ bs_write1(s, sps->b_constraint_set1); ++ bs_write1(s, sps->b_constraint_set2); ++ bs_write1(s, sps->b_constraint_set3); ++ ++ bs_write(s, 4, 0); //reserved_zero_4bits; /* equal to 0*/ ++ bs_write(s, 8, sps->i_level_idc); ++ bs_write_ue(s, sps->i_id); ++ ++#if 0 ++ if(sps->i_profile_idc >= PROFILE_HIGH) { ++ bs_write_ue(s, sps->i_chroma_format_idc); ++ ++ if(sps->i_chroma_format_idc == CHROMA_444) ++ bs_write1(s, 0); ++ ++ bs_write_ue(s, 0); // bit_depth_luma_minus8; ++ bs_write_ue(s, 0); // bit_depth_chroma_minus8; ++ ++ bs_write1(s, sps->b_qpprime_y_zero_transform_bypass); ++ bs_write1(s, sps->b_avcintra); //seq_scaling_matrix_present_flag. ++ if(sps->b_avcintra){ ++ /* TODO: 固定不支持吗,谁决定的?*/ ++ } ++ } ++#endif ++ ++ bs_write_ue(s, sps->i_log2_max_frame_num - 4); // log2_max_frame_num_minus4; ++ bs_write_ue(s, sps->i_poc_type); // pic_order_cnt_type; ++ if(sps->i_poc_type == 0) ++ bs_write_ue(s, sps->i_log2_max_poc_lsb - 4); ++ ++ bs_write_ue( s, sps->i_num_ref_frames ); ++ bs_write1( s, sps->b_gaps_in_frame_num_value_allowed ); ++ bs_write_ue( s, sps->i_mb_width - 1 ); /*pic_width_in_mbs_minus1*/ ++ bs_write_ue( s, (sps->i_mb_height >> !sps->b_frame_mbs_only) - 1); ++ bs_write1( s, sps->b_frame_mbs_only ); ++ ++ if( !sps->b_frame_mbs_only ) ++ bs_write1( s, sps->b_mb_adaptive_frame_field ); ++ bs_write1( s, sps->b_direct8x8_inference ); ++ ++ bs_write1( s, sps->b_crop ); ++ if( sps->b_crop ) ++ { ++ int h_shift = sps->i_chroma_format_idc == CHROMA_420 || sps->i_chroma_format_idc == CHROMA_422; ++ int v_shift = sps->i_chroma_format_idc == CHROMA_420; ++ bs_write_ue( s, sps->crop.i_left >> h_shift ); ++ bs_write_ue( s, sps->crop.i_right >> h_shift ); ++ bs_write_ue( s, sps->crop.i_top >> v_shift ); ++ bs_write_ue( s, sps->crop.i_bottom >> v_shift ); ++ } ++ ++ bs_write1( s, sps->b_vui ); ++ if(sps->b_vui) { ++ /* TODO: 需要弄清楚这些参数的含义,什么是vui??*/ ++ } ++ ++ bs_rbsp_trailing( s ); ++ bs_flush( s ); ++} ++ ++void h264e_pps_write(bs_t *s, h264_sps_t *sps, h264_pps_t *pps) ++{ ++ bs_realign(s); ++ bs_write_ue(s, pps->i_id); ++ bs_write_ue(s, pps->i_sps_id); ++ ++ bs_write1(s, pps->b_cabac); ++ bs_write1(s, pps->b_pic_order); ++ bs_write_ue(s, pps->i_num_slice_groups - 1); ++ ++ bs_write_ue(s, pps->i_num_ref_idx_l0_default_active - 1); ++ bs_write_ue(s, pps->i_num_ref_idx_l1_default_active - 1); ++ bs_write1(s, pps->b_weighted_pred); ++ bs_write(s, 2, pps->b_weighted_bipred); ++ ++ bs_write_se(s, pps->i_pic_init_qp - 26); ++ bs_write_se(s, pps->i_pic_init_qs - 26); ++ bs_write_se(s, pps->i_chroma_qp_index_offset); ++ ++ bs_write1(s, pps->b_deblocking_filter_control); ++ bs_write1(s, pps->b_constrained_intra_pred); ++ bs_write1(s, pps->b_redundant_pic_cnt); ++ ++ if(pps->b_transform_8x8_mode) { ++ ++ bs_write1(s, pps->b_transform_8x8_mode); ++ bs_write1(s, 0); ++ ++ bs_write_se(s, pps->i_chroma_qp_index_offset); ++ ++ } ++ ++ bs_rbsp_trailing(s); ++ bs_flush(s); ++} ++ ++ ++void h264e_sei_write(bs_t *s, uint8_t *payload, int payload_size, int payload_type) ++{ ++ int i; ++ bs_realign( s ); ++ for( i = 0; i <= payload_type-255; i += 255 ) ++ bs_write( s, 8, 255 ); ++ bs_write( s, 8, payload_type-i ); ++ ++ for( i = 0; i <= payload_size-255; i += 255 ) ++ bs_write( s, 8, 255 ); ++ bs_write( s, 8, payload_size-i ); ++ ++ for( i = 0; i < payload_size; i++ ) ++ bs_write( s, 8, payload[i] ); ++ ++ bs_rbsp_trailing( s ); ++ bs_flush( s ); ++} ++ ++int h264e_sei_version_write(bs_t *s) ++{ ++ ++} ++ ++ ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_set.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_set.h.patch new file mode 100644 index 00000000..bd2ce9ba --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_set.h.patch @@ -0,0 +1,180 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/helix/h264enc/set.h b/drivers/media/platform/ingenic-vcodec/helix/h264enc/set.h +--- a/drivers/media/platform/ingenic-vcodec/helix/h264enc/set.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/helix/h264enc/set.h 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,176 @@ ++/***************************************************************************** ++ * set.h: quantization init ++ ***************************************************************************** ++ * Copyright (C) 2003-2018 x264 project ++ * ++ * Authors: Loren Merritt ++ * Laurent Aimar ++ * ++ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. ++ * ++ * This program is also available under a commercial proprietary license. ++ * For more information, contact us at licensing@x264.com. ++ *****************************************************************************/ ++ ++#ifndef H264_SET_H ++#define H264_SET_H ++ ++#include "bitstream.h" ++ ++typedef struct ++{ ++ int i_id; ++ ++ int i_profile_idc; ++ int i_level_idc; ++ ++ int b_constraint_set0; ++ int b_constraint_set1; ++ int b_constraint_set2; ++ int b_constraint_set3; ++ ++ int i_log2_max_frame_num; ++ ++ int i_poc_type; ++ /* poc 0 */ ++ int i_log2_max_poc_lsb; ++ ++ int i_num_ref_frames; ++ int b_gaps_in_frame_num_value_allowed; ++ int i_mb_width; ++ int i_mb_height; ++ int b_frame_mbs_only; ++ int b_mb_adaptive_frame_field; ++ int b_direct8x8_inference; ++ ++ int b_crop; ++ struct ++ { ++ int i_left; ++ int i_right; ++ int i_top; ++ int i_bottom; ++ } crop; ++ ++ int b_vui; ++ struct ++ { ++ int b_aspect_ratio_info_present; ++ int i_sar_width; ++ int i_sar_height; ++ ++ int b_overscan_info_present; ++ int b_overscan_info; ++ ++ int b_signal_type_present; ++ int i_vidformat; ++ int b_fullrange; ++ int b_color_description_present; ++ int i_colorprim; ++ int i_transfer; ++ int i_colmatrix; ++ ++ int b_chroma_loc_info_present; ++ int i_chroma_loc_top; ++ int i_chroma_loc_bottom; ++ ++ int b_timing_info_present; ++ uint32_t i_num_units_in_tick; ++ uint32_t i_time_scale; ++ int b_fixed_frame_rate; ++ ++ int b_nal_hrd_parameters_present; ++ int b_vcl_hrd_parameters_present; ++ ++ struct ++ { ++ int i_cpb_cnt; ++ int i_bit_rate_scale; ++ int i_cpb_size_scale; ++ int i_bit_rate_value; ++ int i_cpb_size_value; ++ int i_bit_rate_unscaled; ++ int i_cpb_size_unscaled; ++ int b_cbr_hrd; ++ ++ int i_initial_cpb_removal_delay_length; ++ int i_cpb_removal_delay_length; ++ int i_dpb_output_delay_length; ++ int i_time_offset_length; ++ } hrd; ++ ++ int b_pic_struct_present; ++ int b_bitstream_restriction; ++ int b_motion_vectors_over_pic_boundaries; ++ int i_max_bytes_per_pic_denom; ++ int i_max_bits_per_mb_denom; ++ int i_log2_max_mv_length_horizontal; ++ int i_log2_max_mv_length_vertical; ++ int i_num_reorder_frames; ++ int i_max_dec_frame_buffering; ++ ++ /* FIXME to complete */ ++ } vui; ++ ++ int b_qpprime_y_zero_transform_bypass; ++ int i_chroma_format_idc; ++ ++ int b_avcintra; ++ int i_cqm_preset; ++ const uint8_t *scaling_list[8]; /* could be 12, but we don't allow separate Cb/Cr lists */ ++ ++} h264_sps_t; ++ ++typedef struct ++{ ++ int i_id; ++ int i_sps_id; ++ ++ int b_cabac; ++ ++ int b_pic_order; ++ int i_num_slice_groups; ++ ++ int i_num_ref_idx_l0_default_active; ++ int i_num_ref_idx_l1_default_active; ++ ++ int b_weighted_pred; ++ int b_weighted_bipred; ++ ++ int i_pic_init_qp; ++ int i_pic_init_qs; ++ ++ int i_chroma_qp_index_offset; ++ ++ int b_deblocking_filter_control; ++ int b_constrained_intra_pred; ++ int b_redundant_pic_cnt; ++ ++ int b_transform_8x8_mode; ++ ++} h264_pps_t; ++ ++ ++ ++extern void h264e_sps_write(bs_t *s, h264_sps_t *sps); ++ ++extern void h264e_pps_write(bs_t *s, h264_sps_t *sps, h264_pps_t *pps); ++ ++extern void h264e_sei_write(bs_t *s, uint8_t *payload, int payload_size, int payload_type); ++ ++extern int h264e_sei_version_write(bs_t *s); ++ ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_slice.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_slice.c.patch new file mode 100644 index 00000000..36d417e0 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_slice.c.patch @@ -0,0 +1,173 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/helix/h264enc/slice.c b/drivers/media/platform/ingenic-vcodec/helix/h264enc/slice.c +--- a/drivers/media/platform/ingenic-vcodec/helix/h264enc/slice.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/helix/h264enc/slice.c 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,169 @@ ++#include "cabac.h" ++#include "slice.h" ++ ++ ++void h264e_slice_header_init(h264_slice_header_t *sh, ++ h264_sps_t *sps, h264_pps_t *pps, ++ int i_idr_pic_id, int i_frame, int i_qp) ++{ ++ sh->sps = sps; ++ sh->pps = pps; ++ ++ sh->i_first_mb = 0; ++ sh->i_last_mb = sps->i_mb_width * sps->i_mb_height - 1; ++ sh->i_pps_id = pps->i_id; ++ sh->i_frame_num = i_frame; ++ ++ sh->b_mbaff = 0; ++ sh->b_field_pic = 0; ++ sh->b_bottom_field = 0; ++ ++ sh->i_idr_pic_id = i_idr_pic_id; ++ ++ /* poc stuff, fixed later */ ++ /* vpu用不着 ..., 固定顺序编码 ...*/ ++ sh->i_poc = 0; ++ sh->i_delta_poc_bottom = 0; ++ sh->i_delta_poc[0] = 0; ++ sh->i_delta_poc[1] = 0; ++ ++ ++ /*VPU 当前硬件用不着.*/ ++ sh->i_redundant_pic_cnt = 0; ++ ++ /*也用不着,写固定值就好了.*/ ++ sh->b_num_ref_idx_override = 0; ++ sh->i_num_ref_idx_l0_active = 1; ++ sh->i_num_ref_idx_l1_active = 1; ++ ++ /*不做重排序了,重排序有什么好处?,软件去做的.*/ ++ sh->b_ref_pic_list_reordering[0] = 0; ++ sh->b_ref_pic_list_reordering[1] = 0; ++ ++ ++ /* TODO : value to be */ ++ sh->i_cabac_init_idc = 0; /* TODO, 是否可以使用该变量来表示初始化cabac_init???*/ ++ ++ sh->i_qp = SPEC_QP(i_qp); ++ sh->i_qp_delta = sh->i_qp - pps->i_pic_init_qp; ++ ++ sh->b_sp_for_swidth = 0; ++ sh->i_qs_delta = 0; ++ ++ ++ /*TODO: 是否要关闭 快过滤功能,先关闭,后面再打开. */ ++ sh->i_disable_deblocking_filter_idc = 1; ++ sh->i_alpha_c0_offset = 0; ++ sh->i_beta_offset = 0; ++ ++} ++ ++ ++void h264e_slice_header_write(bs_t *s, h264_slice_header_t *sh, int i_nal_ref_idc) ++{ ++ /*Do not support mbaff*/ ++ bs_write_ue(s, sh->i_first_mb); ++ bs_write_ue(s, sh->i_type + 5); ++ bs_write_ue(s, sh->i_pps_id); ++ bs_write(s, sh->sps->i_log2_max_frame_num, sh->i_frame_num & ((1 << sh->sps->i_log2_max_frame_num) - 1)); ++ ++ /*mbs only*/ ++ ++ if(sh->i_idr_pic_id >= 0) ++ bs_write_ue(s, sh->i_idr_pic_id); ++ ++#if 0 ++ /* poc_type 只支持 2. */ ++ if(sh->sps->i_poc_type == 0) { ++ bs_write(s, sh->sps->i_log2_max_poc_lsb, sh->i_poc & ((1 << sh->sps->i_log2_max_poc_lsb) - 1)); ++ if(sh->pps->b_pic_order && !sh->b_field_pic) ++ bs_write_se(s, sh->i_delta_poc_bottom); ++ } ++#endif ++ ++#if 0 ++ /*main profile 0就是0,不改了*/ ++ if(sh->pps->b_redundant_pic_cnt) ++ bs_write_ue(s, sh->i_redundant_pic_cnt); ++#endif ++#if 0 ++ if(sh->i_type == SLICE_TYPE_B) { ++ /*not support*/ ++ bs_write1(s, sh->b_direct_spatial_mv_pred); ++ } ++#endif ++ ++ if(sh->i_type == SLICE_TYPE_P || sh->i_type == SLICE_TYPE_B) { ++ bs_write1(s, sh->b_num_ref_idx_override); ++ if(sh->b_num_ref_idx_override) { ++ bs_write_ue(s, sh->i_num_ref_idx_l0_active - 1); ++ if(sh->i_type == SLICE_TYPE_B) ++ bs_write_ue(s, sh->i_num_ref_idx_l1_active - 1); ++ } ++ ++ } ++ ++ /* 不reorder了。。, 初始化为0就好了. */ ++ if(sh->i_type != SLICE_TYPE_I) { ++ bs_write1(s, sh->b_ref_pic_list_reordering[0]); ++ if(sh->b_ref_pic_list_reordering[0]) { ++ int i; ++ for(i = 0; i < sh->i_num_ref_idx_l0_active; i++) { ++ bs_write_ue(s, sh->ref_pic_list_order[0][i].idc); ++ bs_write_ue(s, sh->ref_pic_list_order[0][i].arg); ++ } ++ ++ bs_write_ue(s, 3); ++ } ++ } ++ ++#if 0 ++ /*不支持 SLICE_TYPE_B */ ++ if(sh->i_type == SLICE_TYPE_B) { ++ /*not support, IGNORE...*/ ++ } ++#endif ++#if 0 ++ /*使用默认的加权预测方式*/ ++ sh->b_weighted_pred = 0; ++ if(sh->pps->b_weighted_pred && sh->i_type == SLICE_TYPE_P) { ++ /*TODO, 暂时先不管预测 */ ++ } ++#endif ++ ++ if(i_nal_ref_idc != 0) { ++ if(sh->i_idr_pic_id >= 0) { ++ bs_write1(s, 0); ++ bs_write1(s, 0); ++ } else { ++ bs_write1( s, sh->i_mmco_command_count > 0 ); /* adaptive_ref_pic_marking_mode_flag */ ++ if( sh->i_mmco_command_count > 0 ) ++ { ++ int i = 0; ++ for(i = 0; i < sh->i_mmco_command_count; i++ ) ++ { ++ bs_write_ue( s, 1 ); /* mark short term ref as unused */ ++ bs_write_ue( s, sh->mmco[i].i_difference_of_pic_nums - 1 ); ++ } ++ bs_write_ue( s, 0 ); /* end command list */ ++ } ++ ++ } ++ ++ } ++ ++ if( sh->pps->b_cabac && sh->i_type != SLICE_TYPE_I ) ++ bs_write_ue( s, sh->i_cabac_init_idc ); ++ ++ bs_write_se( s, sh->i_qp_delta ); /* slice qp delta */ ++ ++ if( sh->pps->b_deblocking_filter_control ) ++ { ++ bs_write_ue( s, sh->i_disable_deblocking_filter_idc ); ++ if( sh->i_disable_deblocking_filter_idc != 1 ) ++ { ++ bs_write_se( s, sh->i_alpha_c0_offset >> 1 ); ++ bs_write_se( s, sh->i_beta_offset >> 1 ); ++ } ++ } ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_slice.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_slice.h.patch new file mode 100644 index 00000000..e0014b89 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_h264enc_slice.h.patch @@ -0,0 +1,103 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/helix/h264enc/slice.h b/drivers/media/platform/ingenic-vcodec/helix/h264enc/slice.h +--- a/drivers/media/platform/ingenic-vcodec/helix/h264enc/slice.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/helix/h264enc/slice.h 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,99 @@ ++#ifndef __H264_SLICE_H__ ++#define __H264_SLICE_H__ ++ ++#include "common.h" ++ ++enum slice_type_e ++{ ++ SLICE_TYPE_P = 0, ++ SLICE_TYPE_B = 1, ++ SLICE_TYPE_I = 2, ++}; ++ ++ ++ ++ ++#define MAX(X, Y) ((X) >= (Y) ? (X) : (Y)) ++#define MIN(X, Y) ((X) <= (Y) ? (X) : (Y)) ++ ++#define QP_MAX_SPEC (51) ++ ++#define X264_REF_MAX 1 ++#define SPEC_QP(x) MIN((x), QP_MAX_SPEC) ++ ++ ++typedef struct ++{ ++ h264_sps_t *sps; ++ h264_pps_t *pps; ++ ++ int i_type; ++ int i_first_mb; ++ int i_last_mb; ++ ++ int i_pps_id; ++ ++ int i_frame_num; ++ ++ int b_mbaff; ++ int b_field_pic; ++ int b_bottom_field; ++ ++ int i_idr_pic_id; /* -1 if nal_type != 5 */ ++ ++ int i_poc; ++ int i_delta_poc_bottom; ++ ++ int i_delta_poc[2]; ++ int i_redundant_pic_cnt; ++ ++ int b_direct_spatial_mv_pred; ++ ++ int b_num_ref_idx_override; ++ int i_num_ref_idx_l0_active; ++ int i_num_ref_idx_l1_active; ++ ++ int b_ref_pic_list_reordering[2]; ++ struct ++ { ++ int idc; ++ int arg; ++ } ref_pic_list_order[2][X264_REF_MAX]; ++ ++#if 0 ++ /* 使用默认的加权预测 */ ++ /* P-frame weighting */ ++ int b_weighted_pred; ++ x264_weight_t weight[X264_REF_MAX*2][3]; ++#endif ++ int i_mmco_remove_from_end; ++ int i_mmco_command_count; ++ struct /* struct for future expansion */ ++ { ++ int i_difference_of_pic_nums; ++ int i_poc; ++ } mmco[X264_REF_MAX]; ++ ++ int i_cabac_init_idc; ++ ++ int i_qp; ++ int i_qp_delta; ++ int b_sp_for_swidth; ++ int i_qs_delta; ++ ++ /* deblocking filter */ ++ int i_disable_deblocking_filter_idc; ++ int i_alpha_c0_offset; ++ int i_beta_offset; ++} h264_slice_header_t; ++ ++ ++extern void h264e_slice_header_init(h264_slice_header_t *sh, ++ h264_sps_t *sps, h264_pps_t *pps, ++ int i_idr_pic_id, int i_frame, int i_qp); ++ ++extern void h264e_slice_header_write(bs_t *s, h264_slice_header_t *sh, int i_nal_ref_idc); ++ ++ ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_helix_buf.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_helix_buf.h.patch new file mode 100644 index 00000000..9c9a79c3 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_helix_buf.h.patch @@ -0,0 +1,49 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/helix/helix_buf.h b/drivers/media/platform/ingenic-vcodec/helix/helix_buf.h +--- a/drivers/media/platform/ingenic-vcodec/helix/helix_buf.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/helix/helix_buf.h 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,45 @@ ++#ifndef __HELIX_BUF_H__ ++#define __HELIX_BUF_H__ ++ ++enum helix_raw_format { ++ HELIX_TILE_MODE = 0, ++ HELIX_420P_MODE = 4, ++ HELIX_NV12_MODE = 8, ++ HELIX_NV21_MODE = 12, ++}; ++ ++ ++/* JPEG encode quantization table select level */ ++typedef enum { ++ LOW_QUALITY, ++ MEDIUMS_QUALITY, ++ HIGH_QUALITY ++} QUANT_QUALITY; ++ ++ ++struct h264_ref_tile { ++ unsigned int *yaddr; ++ unsigned int *caddr; ++ ++ dma_addr_t yaddr_pa; ++ dma_addr_t caddr_pa; ++}; ++ ++ ++/* basic memory description. */ ++struct ingenic_vcodec_mem { ++ size_t size; ++ void *va; ++ dma_addr_t pa; ++}; ++ ++struct video_frame_buffer { ++ struct ingenic_vcodec_mem fb_addr[3];// MAX_PLANES. ++ int num_planes; ++}; ++ ++ ++ ++extern int ingenic_vpu_start(void *priv); ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_helix_drv.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_helix_drv.c.patch new file mode 100644 index 00000000..e73a8c25 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_helix_drv.c.patch @@ -0,0 +1,529 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/helix/helix_drv.c b/drivers/media/platform/ingenic-vcodec/helix/helix_drv.c +--- a/drivers/media/platform/ingenic-vcodec/helix/helix_drv.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/helix/helix_drv.c 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,525 @@ ++/* ++* Copyright© 2014 Ingenic Semiconductor Co.,Ltd ++* ++* Author: qipengzhen ++* ++* 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. ++* ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "helix_drv.h" ++#include "helix_ops.h" ++ ++#undef pr_debug ++#define pr_debug pr_info ++ ++ ++static int fops_vcodec_open(struct file *file) ++{ ++ struct ingenic_venc_dev *dev = video_drvdata(file); ++ struct ingenic_venc_ctx *ctx = NULL; ++ int ret = 0; ++ ++ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); ++ if(!ctx) ++ return -ENOMEM; ++ ++ mutex_lock(&dev->dev_mutex); ++ ++ ctx->id = dev->id_counter++; ++ v4l2_fh_init(&ctx->fh, video_devdata(file)); ++ file->private_data = &ctx->fh; ++ v4l2_fh_add(&ctx->fh); ++ //INIT_LIST_HEAD(&ctx->list); ++ ctx->dev = dev; ++ init_waitqueue_head(&ctx->queue); ++ ++ printk("---%s, %d, sizeof(ctx->hw_ctx): %d, sizeof(ctx): %d\n", __func__, __LINE__, sizeof(ctx->h264e_ctx), sizeof(*ctx)); ++ ++ ingenic_vcodec_enc_init_default_params(ctx); ++ ++ ret = ingenic_vcodec_enc_ctrls_setup(ctx); ++ if(ret) { ++ pr_err("Failed to setup ctrls() %d\n", ret); ++ goto err_ctrls_setup; ++ } ++ ++ ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev_enc, ctx, &ingenic_vcodec_enc_queue_init); ++ if(IS_ERR((__force void *)ctx->m2m_ctx)) { ++ ret = PTR_ERR((__force void *)ctx->m2m_ctx); ++ ++ goto err_m2m_ctx_init; ++ } ++ ++ ++ ++ pr_debug("Create instance [%d]@%p m2m_ctx=%p\n", ++ ctx->id, ctx, ctx->m2m_ctx); ++ ++ mutex_unlock(&dev->dev_mutex); ++ ++ pr_debug("%s encoder [%d]\n", dev_name(dev->dev), ctx->id); ++ ++ return ret; ++err_m2m_ctx_init: ++ v4l2_ctrl_handler_free(&ctx->ctrl_hdl); ++err_ctrls_setup: ++ v4l2_fh_del(&ctx->fh); ++ v4l2_fh_exit(&ctx->fh); ++ kfree(ctx); ++ mutex_unlock(&dev->dev_mutex); ++ return ret; ++} ++ ++static int fops_vcodec_release(struct file *file) ++{ ++ ++ struct ingenic_venc_dev *dev = video_drvdata(file); ++ struct ingenic_venc_ctx *ctx = fh_to_ctx(file->private_data); ++ ++ pr_debug("[%d] encoder release\n", ctx->id); ++ ++ mutex_lock(&dev->dev_mutex); ++ ++ v4l2_fh_del(&ctx->fh); ++ v4l2_fh_exit(&ctx->fh); ++ v4l2_ctrl_handler_free(&ctx->ctrl_hdl); ++ v4l2_m2m_ctx_release(ctx->m2m_ctx); ++ ingenic_vcodec_enc_deinit_default_params(ctx); ++ ++ kfree(ctx); ++ ++ mutex_unlock(&dev->dev_mutex); ++ ++ return 0; ++} ++ ++static unsigned int fops_vcodec_poll(struct file *file, ++ struct poll_table_struct *wait) ++{ ++ struct ingenic_venc_dev *dev = video_drvdata(file); ++ struct ingenic_venc_ctx *ctx = fh_to_ctx(file->private_data); ++ unsigned int ret = 0; ++ ++ if(mutex_lock_interruptible(&dev->dev_mutex)) { ++ return -ERESTARTSYS; ++ } ++ ++ ret = v4l2_m2m_poll(file, ctx->m2m_ctx, wait); ++ ++ mutex_unlock(&dev->dev_mutex); ++ ++ return ret; ++} ++ ++static int fops_vcodec_mmap(struct file *file, ++ struct vm_area_struct *vma) ++{ ++ struct ingenic_venc_ctx *ctx = fh_to_ctx(file->private_data); ++ ++ return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); ++} ++ ++static const struct v4l2_file_operations ingenic_venc_fops = { ++ .owner = THIS_MODULE, ++ .open = fops_vcodec_open, ++ .release = fops_vcodec_release, ++ .poll = fops_vcodec_poll, ++ .unlocked_ioctl = video_ioctl2, ++ .mmap = fops_vcodec_mmap, ++}; ++ ++ ++#define vpu_readl(dev, offset) \ ++ readl(dev->reg_base + (offset)) ++ ++#define vpu_writel(dev, offset, data) \ ++ writel((data), dev->reg_base + (offset)) ++ ++static void inline vpu_clear_bits(struct ingenic_venc_dev *dev, unsigned int offset, unsigned int bits) ++{ ++ unsigned int val = vpu_readl(dev, offset); ++ val &= ~bits; ++ vpu_writel(dev, offset, val); ++} ++ ++ ++static irqreturn_t ingenic_vpu_irq(int irq, void *priv) ++{ ++ struct ingenic_venc_dev *dev = (struct ingenic_venc_dev *)priv; ++ struct ingenic_venc_ctx *ctx = dev->curr_ctx; ++ struct h264e_ctx *h264e_ctx = &ctx->h264e_ctx; ++ struct jpge_ctx *jpge_ctx = &ctx->jpge_ctx; ++ ++ unsigned long flags; ++ ++ unsigned int efe_stat; ++ unsigned int sch_stat; ++ ++ printk("-- vpu irq --\n"); ++ spin_lock_irqsave(&dev->spinlock, flags); ++ ++ ctx->int_cond = 1; ++ ++ efe_stat = vpu_readl(dev, REG_EFE_STAT); ++ sch_stat = vpu_readl(dev, REG_SCH_STAT); ++ ++ printk("--- sch_stat %x\n", sch_stat); ++ /* disable all interrupts. */ ++ vpu_clear_bits(dev, REG_SCH_GLBC, 0x3f << 16); ++ if(sch_stat & SCH_STAT_ENDF){ ++ ++ if(sch_stat & SCH_STAT_JPGEND) { ++ printk("Sch jpeg end!\n"); ++ ++ jpge_ctx->bslen = vpu_readl(dev, REG_JPGC_STAT) & 0xffffff; ++ ++ vpu_clear_bits(dev, REG_JPGC_STAT, JPGC_STAT_ENDF); ++ } else if(sch_stat & SCH_STAT_ENDF) { ++ printk("Sch h264 end ???!\n"); ++ h264e_ctx->r_bs_len = vpu_readl(dev, REG_SDE_CFG9); ++ h264e_ctx->encoded_bs_len = h264e_ctx->r_bs_len; ++ ++ vpu_clear_bits(dev, REG_SDE_STAT, SDE_STAT_BSEND); ++ vpu_clear_bits(dev, REG_DBLK_GSTA, DBLK_STAT_DOEND); ++ /*wakeup ...*/ ++ } else if(sch_stat & SCH_STAT_TIMEOUT){ ++ printk("Sch h264 Timeout !\n"); ++ } else { ++ /*Error handling ...!*/ ++ ++ printk("stat error %x\n", sch_stat); ++ /*wakeup ...*/ ++ } ++ ++ } ++ ctx->int_status = sch_stat; ++ spin_unlock_irqrestore(&dev->spinlock, flags); ++ ++ wake_up_interruptible(&ctx->queue); ++ ++ ++ return IRQ_HANDLED; ++} ++ ++ ++static void vpu_dump_regs(struct ingenic_venc_dev *dev) ++{ ++ ++ /* EMC */ ++ printk("REG_EMC_FRM_SIZE : %d\n", vpu_readl(dev, REG_EMC_FRM_SIZE)); ++ printk("REG_EMC_BS_ADDR : 0x%x\n", vpu_readl(dev, REG_EMC_BS_ADDR)); ++ printk("REG_EMC_DBLK_ADDR: 0x%x\n", vpu_readl(dev, REG_EMC_DBLK_ADDR)); ++ printk("REG_EMC_RECON_ADDR: 0x%x\n", vpu_readl(dev, REG_EMC_RECON_ADDR)); ++ printk("REG_EMC_MV_ADDR: 0x%x\n", vpu_readl(dev, REG_EMC_MV_ADDR)); ++ printk("REG_EMC_SE_ADDR: 0x%x\n", vpu_readl(dev, REG_EMC_SE_ADDR)); ++ printk("REG_EMC_QPT_ADDR: 0x%x\n", vpu_readl(dev, REG_EMC_QPT_ADDR)); ++ printk("REG_EMC_RC_RADDR: 0x%x\n", vpu_readl(dev, REG_EMC_RC_RADDR)); ++ printk("REG_EMC_MOS_ADDR: 0x%x\n", vpu_readl(dev, REG_EMC_MOS_ADDR)); ++ printk("REG_EMC_SLV_INIT: 0x%x\n", vpu_readl(dev, REG_EMC_SLV_INIT)); ++ printk("REG_EMC_BS_SIZE: 0x%x\n", vpu_readl(dev, REG_EMC_BS_SIZE)); ++ printk("REG_EMC_BS_STAT: 0x%x\n", vpu_readl(dev, REG_EMC_BS_STAT)); ++} ++ ++#define REG_VPU_STATUS ( *(volatile unsigned int*)0xb3200034 ) ++#define REG_VPU_LOCK ( *(volatile unsigned int*)0xb329004c ) ++#define REG_VPUCDR ( *(volatile unsigned int*)0xb0000030 ) ++#define REG_CPM_VPU_SWRST ( *(volatile unsigned int*)0xb00000c4 ) ++#define REG_VPU_TLBBASE (*(volatile unsigned int *)(0x30 + 0xb3200000)) ++#define CPM_VPU_SR (0x1<<31) ++#define CPM_VPU_STP (0x1<<30) ++#define CPM_VPU_ACK (0x1<<29) ++ ++static int vpu_reset(struct ingenic_venc_dev *dev) ++{ ++ int timeout = 0xffffff; ++ ++ REG_CPM_VPU_SWRST |= CPM_VPU_STP; ++ while(!(REG_CPM_VPU_SWRST & CPM_VPU_ACK) && --timeout) ++ ; ++ ++ if(!timeout) { ++ printk("wait reset timeout!\n"); ++ } ++ ++ REG_CPM_VPU_SWRST = ((REG_CPM_VPU_SWRST | CPM_VPU_SR) & ~CPM_VPU_STP); ++ REG_CPM_VPU_SWRST = (REG_CPM_VPU_SWRST & ~CPM_VPU_SR & ~CPM_VPU_STP); ++ REG_VPU_LOCK = 0; ++ ++ return 0; ++} ++/*global clk on.*/ ++static int vpu_on(struct ingenic_venc_dev *dev) ++{ ++ clk_enable(dev->clk); ++ clk_enable(dev->clk_gate); ++ __asm__ __volatile__ ( ++ "mfc0 $2, $16, 7 \n\t" ++ "ori $2, $2, 0x340 \n\t" ++ "andi $2, $2, 0x3ff \n\t" ++ "mtc0 $2, $16, 7 \n\t" ++ "nop \n\t"); ++ ++ return 0; ++} ++ ++#define VPU_RUN_TIMEOUT_MS (3000) ++int ingenic_vpu_start(void *priv) ++{ ++ struct ingenic_venc_ctx *ctx = (struct ingenic_venc_ctx *)priv; ++ struct ingenic_venc_dev *dev = ctx->dev; ++ struct h264e_ctx *h264e_ctx = &ctx->h264e_ctx; ++ struct jpge_ctx *jpge_ctx = &ctx->jpge_ctx; ++ unsigned int sch_glbc = 0; ++ unsigned int des_pa; ++ unsigned long flags; ++ int timeout = 0xffff; ++ int ret = 0; ++ ++ /* TODO: add lock.*/ ++ dev->curr_ctx = ctx; ++ ++ if(ctx->codec_id == CODEC_ID_H264E) { ++ des_pa = h264e_ctx->desc_pa; ++ } else if(ctx->codec_id = CODEC_ID_JPGE) { ++ des_pa = jpge_ctx->desc_pa; ++ } ++ ++ spin_lock_irqsave(&dev->spinlock, flags); ++ ctx->int_cond = 0; ++ ++#if 1 ++ ++ /*X2000 RESET*/ ++ /* vpu reset ... */ ++ printk("-- vpu reset --\n"); ++ vpu_writel(dev, REG_CFGC_SW_RESET, CFGC_SW_RESET_RST); ++ while(!(vpu_readl(dev, REG_CFGC_SW_RESET) & CFGC_SW_RESET_EARB_EMPT) && --timeout); ++ if(!timeout) { ++ pr_err("%s, vpu_reset timeout!\n", __func__); ++ spin_unlock_irqrestore(&dev->spinlock, flags); ++ return -EINVAL; ++ } ++#else ++ vpu_reset(dev); ++#endif ++ ++ /*TODO: 如果使用tlb,此处要修改.*/ ++ sch_glbc = SCH_GLBC_HIAXI | SCH_INTE_ACFGERR | SCH_INTE_BSERR | ++ SCH_INTE_ENDF | SCH_INTE_TLBERR | SCH_INTE_BSFULL; ++ ++ ++ /* type jpege, jpegd, h264e.*/ ++ vpu_writel(dev, REG_SCH_GLBC, sch_glbc); ++ ++ /*trigger start.*/ ++ printk("-- vpu start --\n"); ++ vpu_writel(dev, REG_CFGC_ACM_CTRL, VDMA_ACFG_DHA(des_pa) | VDMA_ACFG_RUN); ++ ++ /* wait event time out ... */ ++ spin_unlock_irqrestore(&dev->spinlock, flags); ++ ++ ret = wait_event_interruptible_timeout(ctx->queue, ctx->int_cond, msecs_to_jiffies(VPU_RUN_TIMEOUT_MS)); ++ if(!ret) { ++ pr_err("wait vpu run timeout!\n"); ++ printk("efe_stat %x, sch_stat %x\n", vpu_readl(dev, REG_EFE_STAT), vpu_readl(dev, REG_SCH_STAT)); ++ ++ vpu_dump_regs(dev); ++ ret = -ETIMEDOUT; ++ } else if(ret == -ERESTARTSYS) { ++ pr_err("vpu interrupted by a signal!\n"); ++ ++ } ++ ++ ++ return ret; ++} ++ ++int ingenic_vpu_stop(struct ingenic_venc_dev *dev) ++{ ++ return 0; ++} ++ ++static int ingeic_vcodec_probe(struct platform_device *pdev) ++{ ++ struct ingenic_venc_dev *dev; ++ struct video_device *vfd_enc; ++ int ret; ++ ++ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); ++ if(!dev) ++ return -ENOMEM; ++ ++ dev->dev = &pdev->dev; ++ dev->plat_dev = pdev; ++ ++ /*io,clk,irq*/ ++ ++ dev->reg_base = of_iomap(pdev->dev.of_node, 0);; ++ if(IS_ERR(dev->reg_base)) { ++ ret = -ENODEV; ++ goto err_ioremap; ++ } ++ /*TODO: clk pm ...*/ ++ dev->irq = platform_get_irq(pdev, 0); ++ ret = devm_request_irq(&pdev->dev, dev->irq, ingenic_vpu_irq, 0, pdev->name, dev); ++ if(ret ) { ++ dev_err(&pdev->dev, "Failed to request vpu irq!\n"); ++ goto err_irq; ++ } ++ ++ dev->clk_gate = clk_get(&pdev->dev, "gate_vpu"); ++ if (IS_ERR(dev->clk_gate)) { ++ ret = PTR_ERR(dev->clk_gate); ++ goto err_get_clk_gate; ++ } ++ ++ dev->clk = clk_get(dev->dev,"cgu_vpu"); ++ if (IS_ERR(dev->clk)) { ++ ret = PTR_ERR(dev->clk); ++ goto err_get_clk_cgu; ++ } ++ ++ clk_set_rate(dev->clk, 300000000); ++ /*TODO: move to open close.*/ ++ vpu_on(dev); ++ ++ ++ ++ spin_lock_init(&dev->spinlock); ++ mutex_init(&dev->dev_mutex); ++ ++ dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); ++ if(IS_ERR(dev->alloc_ctx)) { ++ ret = -ENOMEM; ++ goto err_ctx; ++ } ++ ++ snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), "%s", "ingenic-v4l2-helix"); ++ ++ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); ++ if(ret) { ++ dev_err(&pdev->dev, "Failed to register v4l2_dev\n"); ++ goto err_v4l2; ++ } ++ ++ vfd_enc = video_device_alloc(); ++ if(!vfd_enc) { ++ dev_err(&pdev->dev, "Failed to alloc video device!\n"); ++ ret = -ENOMEM; ++ goto err_vdev; ++ } ++ ++ ++ vfd_enc->fops = &ingenic_venc_fops; ++ vfd_enc->ioctl_ops = &ingenic_venc_ioctl_ops; ++ vfd_enc->release = video_device_release; ++ vfd_enc->lock = &dev->dev_mutex; ++ vfd_enc->v4l2_dev = &dev->v4l2_dev; ++ vfd_enc->vfl_dir = VFL_DIR_M2M; ++ //vfd_enc->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; ++ ++ snprintf(vfd_enc->name, sizeof(vfd_enc->name), "%s", INGENIC_VCODEC_ENC_NAME); ++ ++ video_set_drvdata(vfd_enc, dev); ++ dev->vfd_enc = vfd_enc; ++ platform_set_drvdata(pdev, dev); ++ ++ dev->m2m_dev_enc = v4l2_m2m_init(&ingenic_venc_m2m_ops); ++ if(IS_ERR((__force void *)dev->m2m_dev_enc)) { ++ dev_err(&pdev->dev, "Failed to init m2m device!\n"); ++ ret = PTR_ERR((__force void *)dev->m2m_dev_enc); ++ goto err_m2m; ++ } ++ ++ dev->encode_workqueue = alloc_ordered_workqueue(INGENIC_VCODEC_ENC_NAME, ++ WQ_MEM_RECLAIM | WQ_FREEZABLE); ++ if(!dev->encode_workqueue) { ++ dev_err(&pdev->dev, "Failed to create encode workqueue\n"); ++ ret = -EINVAL; ++ goto err_workq; ++ } ++ ++ ++ ret = video_register_device(vfd_enc, VFL_TYPE_GRABBER, 1); ++ if(ret) { ++ dev_err(&pdev->dev, "Failed to register video device!\n"); ++ goto err_video_reg; ++ } ++ ++ dev_info(&pdev->dev, "encoder(helix) registered as /dev/video%d\n", ++ vfd_enc->num); ++ ++ return 0; ++err_video_reg: ++err_workq: ++err_m2m: ++err_vdev: ++err_v4l2: ++err_ctx: ++err_get_clk_cgu: ++err_get_clk_gate: ++err_irq: ++err_ioremap: ++ return ret; ++} ++ ++static int ingeic_vcodec_remove(struct platform_device *pdev) ++{ ++ ++ return 0; ++} ++ ++static const struct of_device_id helix_of_match[] = { ++ { .compatible = "ingenic,x2000-helix"}, ++ {}, ++}; ++ ++static struct platform_driver ingenic_vcodec_driver = { ++ .probe = ingeic_vcodec_probe, ++ .remove = ingeic_vcodec_remove, ++ .driver = { ++ .name = INGENIC_VCODEC_ENC_NAME, ++ .of_match_table = helix_of_match, ++ }, ++}; ++ ++static int __init helix_driver_init(void) ++{ ++ return platform_driver_register(&ingenic_vcodec_driver); ++} ++ ++static void __exit helix_driver_exit(void) ++{ ++ platform_driver_unregister(&ingenic_vcodec_driver); ++} ++module_init(helix_driver_init); ++module_exit(helix_driver_exit); ++ ++ ++ ++MODULE_LICENSE("GPL V2"); ++MODULE_DESCRIPTION("Ingenic Video Codec v4l2 encoder driver."); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_helix_drv.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_helix_drv.h.patch new file mode 100644 index 00000000..7bfbc333 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_helix_drv.h.patch @@ -0,0 +1,170 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/helix/helix_drv.h b/drivers/media/platform/ingenic-vcodec/helix/helix_drv.h +--- a/drivers/media/platform/ingenic-vcodec/helix/helix_drv.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/helix/helix_drv.h 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,166 @@ ++#ifndef __INGENIC_HELIX_DRV_H__ ++#define __INGENIC_HELIX_DRV_H__ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++//#include "api/helix_x264_enc.h" ++//#include "api/helix_jpeg_enc.h" ++#include "api/helix.h" ++#include "helix_buf.h" ++ ++ ++#include "h264e.h" ++#include "jpge.h" ++#include "jpgd.h" ++ ++ ++#define INGENIC_VCODEC_ENC_NAME "helix-venc" ++#define INGENIC_VCODEC_MAX_PLANES 3 ++ ++ ++enum ingenic_fmt_type { ++ INGENIC_FMT_FRAME = 0, ++ INGENIC_FMT_ENC = 1, ++ INGENIC_FMT_DEC = 2, ++}; ++ ++struct ingenic_video_fmt { ++ u32 fourcc; ++ enum ingenic_fmt_type type; ++ u32 num_planes; ++ enum helix_raw_format format; ++}; ++ ++struct ingenic_codec_framesizes { ++ u32 fourcc; ++ struct v4l2_frmsize_stepwise stepwise; ++}; ++ ++struct ingenic_video_buf { ++ struct vb2_buffer vb; ++ struct list_head list; ++ ++ struct video_frame_buffer buf; ++}; ++ ++ ++enum ingenic_q_type { ++ INGENIC_Q_DATA_SRC = 0, ++ INGENIC_Q_DATA_DST = 1, ++}; ++ ++/* Queue Data. */ ++struct ingenic_venc_q_data { ++ unsigned int visible_width; ++ unsigned int visible_height; ++ unsigned int coded_width; ++ unsigned int coded_height; ++ enum v4l2_field field; ++ unsigned int bytesperline[INGENIC_VCODEC_MAX_PLANES]; ++ unsigned int sizeimage[INGENIC_VCODEC_MAX_PLANES]; ++ struct ingenic_video_fmt *fmt; ++ ++ ++}; ++ ++/* ++ when ctx is created, IDLE ++ when start_streaming, START, ++ when abort, ABORT, ++*/ ++ ++enum ingenic_venc_state { ++ INGENIC_STATE_IDLE = 0, ++ INGENIC_STATE_HEADER, ++ INGENIC_STATE_RUNNING, ++ INGENIC_STATE_ABORT, ++}; ++ ++/* v4l2 set parm to sw_parm, */ ++/* sw_parm api to sliceinfo. */ ++/* Sliceinfo to dma desc. */ ++ ++/* helix_ctrl_if_start. */ ++ ++struct ingenic_venc_ctx { ++ struct ingenic_venc_dev *dev; ++ ++ struct v4l2_fh fh; ++ struct v4l2_m2m_ctx *m2m_ctx; ++ ++ ++ struct v4l2_ctrl_handler ctrl_hdl; ++ ++ int id; ++ ++ int capture_stopped; ++ int output_stopped; ++ ++ struct ingenic_venc_q_data q_data[2]; ++ enum ingenic_venc_state state; ++ ++ wait_queue_head_t queue; ++ ++ int int_cond; ++ int int_status; ++ ++ enum v4l2_colorspace colorspace; ++ //enum v4l2_ycbcr_encoding ycbcr_enc; ++ //enum v4l2_quantization quantization; ++ //enum v4l2_xfer_func xfer_func; ++ ++ int codec_id; ++#define CODEC_ID_H264E 1 ++#define CODEC_ID_JPGE 2 ++#define CODEC_ID_JPGD 3 ++ union { ++ struct h264e_ctx h264e_ctx; ++ struct jpge_ctx jpge_ctx; ++ struct jpgd_ctx jpgd_ctx; ++ }; ++ ++}; ++ ++ ++struct ingenic_venc_dev { ++ ++ struct v4l2_device v4l2_dev; ++ struct video_device *vfd_enc; ++ struct device *dev; ++ ++ struct v4l2_m2m_dev *m2m_dev_enc; ++ struct platform_device *plat_dev; ++ ++ struct mutex dev_mutex; ++ struct workqueue_struct *encode_workqueue; ++ ++ spinlock_t spinlock; ++ ++ struct ingenic_venc_ctx *curr_ctx; ++ struct vb2_dc_conf *alloc_ctx; ++ ++ int id_counter; ++ ++ void __iomem *reg_base; ++ int irq; ++ struct clk *clk_gate; ++ struct clk *clk; ++}; ++ ++ ++static inline struct ingenic_venc_ctx *fh_to_ctx(struct v4l2_fh *fh) ++{ ++ return container_of(fh, struct ingenic_venc_ctx, fh); ++} ++ ++static inline struct ingenic_venc_ctx *ctrl_to_ctx(struct v4l2_ctrl *ctrl) ++{ ++ return container_of(ctrl->handler, struct ingenic_venc_ctx, ctrl_hdl); ++} ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_helix_ops.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_helix_ops.c.patch new file mode 100644 index 00000000..c5ff3011 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_helix_ops.c.patch @@ -0,0 +1,1302 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/helix/helix_ops.c b/drivers/media/platform/ingenic-vcodec/helix/helix_ops.c +--- a/drivers/media/platform/ingenic-vcodec/helix/helix_ops.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/helix/helix_ops.c 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,1298 @@ ++/* ++* Copyright© 2014 Ingenic Semiconductor Co.,Ltd ++* ++* Author: qipengzhen ++* ++* 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. ++* ++*/ ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include "helix_drv.h" ++#include "helix_ops.h" ++ ++#include "api/helix.h" ++ ++#include "h264e.h" ++#include "jpge.h" ++#include "jpgd.h" ++ ++ ++#define fh_to_ctx(__fh) container_of(__fh, struct ingenic_venc_ctx, fh) ++#define NUM_SUPPORTED_FRAMESIZE 3 ++ ++#define INGENIC_VENC_MIN_W 160U ++#define INGENIC_VENC_MIN_H 120U ++#define INGENIC_VENC_MAX_W 2560U ++#define INGENIC_VENC_MAX_H 2048U ++ ++ ++ ++#define pixelformat_str(a) a >> 0, a >> 8, a >> 16, a >> 24 ++ ++#undef pr_debug ++#define pr_debug pr_info ++ ++static struct ingenic_video_fmt ingenic_video_formats[] = { ++ /* output */ ++ { ++ .fourcc = V4L2_PIX_FMT_NV12, ++ .type = INGENIC_FMT_FRAME, ++ .num_planes = 2, ++ .format = HELIX_NV12_MODE, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV21, ++ .type = INGENIC_FMT_FRAME, ++ .num_planes = 2, ++ .format = HELIX_NV21_MODE, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_YUV420, ++ .type = INGENIC_FMT_FRAME, ++ .num_planes = 3, ++ .format = HELIX_420P_MODE, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_JPEG, ++ .type = INGENIC_FMT_DEC, ++ .num_planes = 1, ++ }, ++ /*capture*/ ++ /* video encoder idx */ ++ { ++ .fourcc = V4L2_PIX_FMT_H264, ++ .type = INGENIC_FMT_ENC, ++ .num_planes = 1, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_JPEG, ++ .type = INGENIC_FMT_ENC, ++ .num_planes = 1, ++ }, ++ { /* jpeg decoder */ ++ .fourcc = V4L2_PIX_FMT_NV12, ++ .type = INGENIC_FMT_FRAME, ++ .num_planes = 2, ++ .format = HELIX_NV12_MODE, ++ }, ++ ++}; ++ ++#define NUM_FORMATS ARRAY_SIZE(ingenic_video_formats) ++#define OUT_FMT_IDX 0 ++#define CAP_FMT_IDX ARRAY_SIZE(ingenic_video_formats) - 4 ++ ++static const struct ingenic_codec_framesizes ingenic_venc_framesizes[] = { ++ { ++ .fourcc = V4L2_PIX_FMT_H264, ++ .stepwise = { INGENIC_VENC_MIN_W, INGENIC_VENC_MAX_W, 16, ++ INGENIC_VENC_MIN_H, INGENIC_VENC_MAX_H, 16}, ++ }, ++}; ++ ++static int vidioc_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct ingenic_venc_ctx *ctx = ctrl_to_ctx(ctrl); ++ struct h264e_ctx *h264e_ctx = &ctx->h264e_ctx; ++ struct h264e_params *h264_p = &h264e_ctx->p; ++ struct jpge_ctx *jpge_ctx = &ctx->jpge_ctx; ++ struct jpge_params *jpge_p = &jpge_ctx->p; ++ int ret = 0; ++ ++ switch(ctrl->id) { ++ case V4L2_CID_MPEG_VIDEO_BITRATE: ++ pr_debug("V4L2_CID_MPEG_VIDEO_BITRATE val = %d\n", ctrl->val); ++ h264_p->bitrate = ctrl->val; ++ break; ++#if 0 ++ case V4L2_CID_MPEG_VIDEO_B_FRAMES: ++ pr_debug("V4L2_CID_MPEG_VIDEO_B_FRAMES val = %d\n", ctrl->val); ++ break; ++#endif ++ case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: ++ pr_debug("V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP val = %d\n", ctrl->val); ++ h264_p->i_qp = ctrl->val; ++ case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP: ++ pr_debug("V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP val = %d\n", ctrl->val); ++ h264_p->p_qp = ctrl->val; ++ break; ++ case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE: ++ pr_debug("V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE val = %d\n", ctrl->val); ++ h264_p->frame_rc_enable = ctrl->val; ++ break; ++ case V4L2_CID_MPEG_VIDEO_H264_MIN_QP: ++ pr_debug("V4L2_CID_MPEG_VIDEO_H264_MIN_QP val = %d\n", ctrl->val); ++ h264_p->h264_min_qp = ctrl->val; ++ break; ++ case V4L2_CID_MPEG_VIDEO_H264_MAX_QP: ++ pr_debug("V4L2_CID_MPEG_VIDEO_H264_MAX_QP val = %d\n", ctrl->val); ++ h264_p->h264_max_qp = ctrl->val; ++ break; ++ case V4L2_CID_MPEG_VIDEO_HEADER_MODE: ++ pr_debug("V4L2_CID_MPEG_VIDEO_HEADER_MODE val = %d\n", ctrl->val); ++ h264_p->h264_hdr_mode = ctrl->val; ++ break; ++ case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE: ++ pr_debug("V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE val = %d\n", ctrl->val); ++ h264_p->mb_rc_enable = ctrl->val; ++ break; ++ case V4L2_CID_MPEG_VIDEO_H264_PROFILE: ++ pr_debug("V4L2_CID_MPEG_VIDEO_H264_PROFILE val = %d\n", ctrl->val); ++ h264_p->h264_profile = ctrl->val; ++ break; ++ case V4L2_CID_MPEG_VIDEO_H264_LEVEL: ++ pr_debug("V4L2_CID_MPEG_VIDEO_H264_LEVEL val = %d\n", ctrl->val); ++ h264_p->h264_level = ctrl->val; ++ break; ++ ++ case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD: ++ pr_debug("V4L2_CID_MPEG_VIDEO_H264_I_PERIOD val = %d\n", ctrl->val); ++ break; ++ ++ case V4L2_CID_MPEG_VIDEO_GOP_SIZE: ++ pr_debug("V4L2_CID_MPEG_VIDEO_GOP_SIZE val = %d\n", ctrl->val); ++ h264_p->gop_size = ctrl->val; ++ break; ++ ++ case V4L2_CID_JPEG_COMPRESSION_QUALITY: ++ jpge_p->compr_quality = ctrl->val; ++ break; ++ ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++ ++} ++ ++static const struct v4l2_ctrl_ops ingenic_venc_ctrl_ops = { ++ .s_ctrl = vidioc_s_ctrl, ++}; ++ ++static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool output_queue) ++{ ++ struct ingenic_video_fmt *fmt; ++ int i,j = 0; ++ ++ int start_index = output_queue ? OUT_FMT_IDX : CAP_FMT_IDX; ++ ++ for(i = start_index; i < NUM_FORMATS; i++) { ++ ++ if(j == f->index) { ++ fmt = &ingenic_video_formats[i]; ++ f->pixelformat = fmt->fourcc; ++ memset(f->reserved, 0, sizeof(f->reserved)); ++ return 0; ++ } ++ ++ j++; ++ } ++ ++ return -EINVAL; ++} ++ ++ ++static int vidioc_enum_framesizes(struct file *file, void *fh, ++ struct v4l2_frmsizeenum *fsize) ++{ ++ int i = 0; ++ if(fsize->index != 0) ++ return -EINVAL; ++ ++ for(i = 0; i < NUM_SUPPORTED_FRAMESIZE; i++) { ++ if(fsize->pixel_format != ingenic_venc_framesizes[i].fourcc) ++ continue; ++ ++ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; ++ fsize->stepwise = ingenic_venc_framesizes[i].stepwise; ++ return 0; ++ } ++ ++ return -EINVAL; ++} ++ ++static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *priv, ++ struct v4l2_fmtdesc *f) ++{ ++ return vidioc_enum_fmt(f, false); ++} ++static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *priv, ++ struct v4l2_fmtdesc *f) ++{ ++ return vidioc_enum_fmt(f, true); ++} ++ ++static int vidioc_querycap(struct file *file, void *priv, ++ struct v4l2_capability *cap) ++{ ++ strlcpy(cap->driver, INGENIC_VCODEC_ENC_NAME, sizeof(cap->driver)); ++ strlcpy(cap->bus_info, "vpu-helix", sizeof(cap->bus_info)); ++ strlcpy(cap->card, "vpu-helix", sizeof(cap->card)); ++ ++ cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE; ++ cap->capabilities = cap->device_caps | V4L2_CAP_VIDEO_CAPTURE_MPLANE ++ | V4L2_CAP_VIDEO_OUTPUT_MPLANE ++ | V4L2_CAP_DEVICE_CAPS; ++ ++ return 0; ++} ++ ++ ++static int vidioc_s_parm(struct file *file, void *priv, ++ struct v4l2_streamparm *a) ++{ ++ if(a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ++ return -EINVAL; ++ ++ ++ /* TODO: what's the matter??? */ ++ ++ //a->parm.output.capability = V4L2_CAP_TIMEPERFRAME; ++ ++ return 0; ++} ++ ++static int vidioc_g_parm(struct file *file, void *priv, ++ struct v4l2_streamparm *a) ++{ ++ /* TODO: what's the matter??? */ ++ return 0; ++} ++ ++static struct ingenic_venc_q_data *ingenic_venc_get_q_data(struct ingenic_venc_ctx *ctx, ++ enum v4l2_buf_type type) ++{ ++ if(V4L2_TYPE_IS_OUTPUT(type)) ++ return &ctx->q_data[INGENIC_Q_DATA_SRC]; ++ ++ return &ctx->q_data[INGENIC_Q_DATA_DST]; ++} ++ ++static struct ingenic_video_fmt *ingenic_venc_find_format(struct v4l2_format *f, int isout) ++{ ++ struct ingenic_video_fmt *fmt; ++ int i; ++ int start_index = isout ? OUT_FMT_IDX : CAP_FMT_IDX; ++ ++ pr_debug("=========%s, %d, f->fmt.pix_mp.pixelformat %x, %c%c%c%c\n", __func__, __LINE__, f->fmt.pix_mp.pixelformat, pixelformat_str(f->fmt.pix_mp.pixelformat)); ++ ++ for(i = start_index; i < NUM_FORMATS; i++) { ++ fmt = &ingenic_video_formats[i]; ++ pr_debug("fmt->fourcc %x\n", fmt->fourcc); ++ if(fmt->fourcc == f->fmt.pix_mp.pixelformat) ++ return fmt; ++ } ++ ++ pr_debug("=========Formate not found ??????!\n"); ++ return NULL; ++} ++ ++static int vidioc_try_fmt(struct v4l2_format *f, struct ingenic_video_fmt *fmt) ++{ ++ struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; ++ int i; ++ ++ pix_fmt_mp->field = V4L2_FIELD_NONE; ++ ++ if(fmt->type == INGENIC_FMT_FRAME) { ++ int tmp_w, tmp_h; ++ ++ pix_fmt_mp->height = clamp(pix_fmt_mp->height, ++ INGENIC_VENC_MIN_H, ++ INGENIC_VENC_MAX_H); ++ pix_fmt_mp->width = clamp(pix_fmt_mp->width, ++ INGENIC_VENC_MIN_W, ++ INGENIC_VENC_MAX_W); ++ ++ tmp_w = pix_fmt_mp->width; ++ tmp_h = pix_fmt_mp->height; ++ ++#if 0 ++ v4l_bound_align_image(&pix_fmt_mp->width, ++ INGENIC_VENC_MIN_W, ++ INGENIC_VENC_MAX_W, 0, ++ &pix_fmt_mp->height, ++ INGENIC_VENC_MIN_H, ++ INGENIC_VENC_MAX_H, 0, 0); ++#endif ++ pr_debug("tmp_w %d tmp_h %d, w %d h %d\n", ++ tmp_w, tmp_h, ++ pix_fmt_mp->width, ++ pix_fmt_mp->height); ++ ++ ++ pix_fmt_mp->num_planes = fmt->num_planes; ++ pix_fmt_mp->plane_fmt[0].sizeimage = ++ pix_fmt_mp->width * pix_fmt_mp->height; ++ ++ pix_fmt_mp->plane_fmt[0].bytesperline = pix_fmt_mp->width; ++ ++ if(pix_fmt_mp->num_planes == 2) { ++ pix_fmt_mp->plane_fmt[1].sizeimage = ++ pix_fmt_mp->width * pix_fmt_mp->height / 2; ++ pix_fmt_mp->plane_fmt[2].sizeimage = 0; ++ ++ pix_fmt_mp->plane_fmt[1].bytesperline = pix_fmt_mp->width; ++ pix_fmt_mp->plane_fmt[2].bytesperline = 0; ++ } else if(pix_fmt_mp->num_planes == 3) { ++ pix_fmt_mp->plane_fmt[1].sizeimage = ++ pix_fmt_mp->plane_fmt[2].sizeimage = ++ (pix_fmt_mp->width * pix_fmt_mp->height) / 4; ++ ++ pix_fmt_mp->plane_fmt[1].bytesperline = ++ pix_fmt_mp->plane_fmt[2].bytesperline = ++ pix_fmt_mp->width / 2; ++ } ++ ++ } else { ++ pix_fmt_mp->num_planes = 1; ++ pix_fmt_mp->plane_fmt[0].bytesperline = 0; ++ } ++ ++ for(i = 0; i < pix_fmt_mp->num_planes; i++) { ++ memset(&(pix_fmt_mp->plane_fmt[i].reserved[0]), 0x0, ++ sizeof(pix_fmt_mp->plane_fmt[0].reserved)); ++ } ++ ++// pix_fmt_mp->flags = 0; ++ ++ memset(&pix_fmt_mp->reserved, 0x0, ++ sizeof(pix_fmt_mp->reserved)); ++ ++ return 0; ++} ++ ++static int vidioc_s_fmt_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ ++ struct ingenic_venc_ctx *ctx = fh_to_ctx(priv); ++ struct vb2_queue *vq; ++ struct ingenic_venc_q_data *q_data; ++ struct ingenic_video_fmt *fmt; ++ struct h264e_ctx *h264e_ctx = &ctx->h264e_ctx; ++ struct jpge_ctx *jpge_ctx = &ctx->jpge_ctx; ++ int i, ret; ++ ++ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); ++ if(!vq) { ++ pr_err("failed to get cap vq !\n"); ++ return -EINVAL; ++ } ++ ++ if(vb2_is_busy(vq)) { ++ pr_err("cap vq is busy!\n"); ++ return -EINVAL; ++ } ++ ++ q_data = ingenic_venc_get_q_data(ctx, f->type); ++ if(!q_data) { ++ pr_err("fail to get cap q data!\n"); ++ return -EINVAL; ++ } ++ ++ ++ fmt = ingenic_venc_find_format(f, 0); ++ if(!fmt) { ++ /* change to the first support cap format.*/ ++ f->fmt.pix.pixelformat = ingenic_video_formats[CAP_FMT_IDX].fourcc; ++ /* if buf type MPLANE, use pix_mp ..*/ ++ f->fmt.pix_mp.pixelformat = ingenic_video_formats[CAP_FMT_IDX].fourcc; ++ fmt = ingenic_venc_find_format(f, 0); ++ } ++ ++ ++ q_data->fmt = fmt; ++ ++ ret = vidioc_try_fmt(f, q_data->fmt); ++ if(ret) ++ return ret; ++ ++ q_data->coded_width = f->fmt.pix_mp.width; ++ q_data->coded_height = f->fmt.pix_mp.height; ++ q_data->field = f->fmt.pix_mp.field; ++ ++ printk("-------s_fmt_cap: coded_width %d, coded_height %d\n", q_data->coded_width, q_data->coded_height); ++ ++ for(i = 0; i < f->fmt.pix_mp.num_planes; i++) { ++ struct v4l2_plane_pix_format *plane_fmt; ++ ++ plane_fmt = &f->fmt.pix_mp.plane_fmt[i]; ++ q_data->bytesperline[i] = plane_fmt->bytesperline; ++ q_data->sizeimage[i] = plane_fmt->sizeimage; ++ } ++ ++ /* init hw interface. */ ++ if(f->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_H264) { ++ ctx->codec_id = CODEC_ID_H264E; ++ ++ h264e_encoder_init(h264e_ctx); ++ h264e_set_priv(h264e_ctx, ctx); ++ ++ } else if(f->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_JPEG) { ++ ctx->codec_id = CODEC_ID_JPGE; ++ ++ jpeg_encoder_init(jpge_ctx); ++ jpeg_encoder_set_priv(jpge_ctx, ctx); ++ ++ } ++ ++ return 0; ++} ++ ++ ++static int vidioc_s_fmt_out(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct ingenic_venc_ctx *ctx = fh_to_ctx(priv); ++ struct vb2_queue *vq; ++ struct ingenic_venc_q_data *q_data; ++ struct ingenic_video_fmt *fmt; ++ struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; ++ struct jpgd_ctx *jpgd_ctx = &ctx->jpgd_ctx; ++ int ret, i; ++ ++ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); ++ if(!vq) { ++ pr_err("fail to get out vq!\n"); ++ return -EINVAL; ++ } ++ if(vb2_is_busy(vq)) { ++ pr_err("out vq is busy!\n"); ++ return -EINVAL; ++ } ++ ++ q_data = ingenic_venc_get_q_data(ctx, f->type); ++ if(!q_data) { ++ pr_err("failed to get out q_data!\n"); ++ return -EINVAL; ++ } ++ ++ ++ pr_debug("s_fmt_out ... f->fmt %x, %c%c%c%c \n", f->fmt.pix_mp.pixelformat, pixelformat_str(f->fmt.pix_mp.pixelformat)); ++ fmt = ingenic_venc_find_format(f, 1); ++ if(!fmt) { ++ /* change to the first support cap format.*/ ++ f->fmt.pix.pixelformat = ingenic_video_formats[OUT_FMT_IDX].fourcc; ++ f->fmt.pix_mp.pixelformat = ingenic_video_formats[OUT_FMT_IDX].fourcc; ++ fmt = ingenic_venc_find_format(f, 1); ++ } ++ ++ ++ pix_fmt_mp->height = clamp(pix_fmt_mp->height, ++ INGENIC_VENC_MIN_H, ++ INGENIC_VENC_MAX_H); ++ pix_fmt_mp->width = clamp(pix_fmt_mp->width, ++ INGENIC_VENC_MIN_W, ++ INGENIC_VENC_MAX_W); ++ ++ q_data->visible_width = f->fmt.pix_mp.width; ++ q_data->visible_height = f->fmt.pix_mp.height; ++ q_data->fmt = fmt; ++ ret = vidioc_try_fmt(f, q_data->fmt); ++ if (ret) ++ return ret; ++ ++ q_data->coded_width = f->fmt.pix_mp.width; ++ q_data->coded_height = f->fmt.pix_mp.height; ++ ++ q_data->field = f->fmt.pix_mp.field; ++ ctx->colorspace = f->fmt.pix_mp.colorspace; ++ //ctx->ycbcr_enc = f->fmt.pix_mp.ycbcr_enc; ++ //ctx->quantization = f->fmt.pix_mp.quantization; ++ //ctx->xfer_func = f->fmt.pix_mp.xfer_func; ++ ++ ++ for (i = 0; i < f->fmt.pix_mp.num_planes; i++) { ++ struct v4l2_plane_pix_format *plane_fmt; ++ ++ plane_fmt = &f->fmt.pix_mp.plane_fmt[i]; ++ q_data->bytesperline[i] = plane_fmt->bytesperline; ++ q_data->sizeimage[i] = plane_fmt->sizeimage; ++ } ++ ++ if(f->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_JPEG) { ++ ctx->codec_id = CODEC_ID_JPGD; ++ ++ jpeg_decoder_init(jpgd_ctx); ++ jpeg_decoder_set_priv(jpgd_ctx, ctx); ++ } ++ ++ ++ return 0; ++} ++ ++static int vidioc_g_fmt(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ ++ struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; ++ struct ingenic_venc_ctx *ctx = fh_to_ctx(priv); ++ struct vb2_queue *vq; ++ struct ingenic_venc_q_data *q_data; ++ int i; ++ ++ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); ++ if (!vq) ++ return -EINVAL; ++ ++ q_data = ingenic_venc_get_q_data(ctx, f->type); ++ ++ pix->width = q_data->coded_width; ++ pix->height = q_data->coded_height; ++ pix->pixelformat = q_data->fmt->fourcc; ++ pix->field = q_data->field; ++ pix->num_planes = q_data->fmt->num_planes; ++ for (i = 0; i < pix->num_planes; i++) { ++ pix->plane_fmt[i].bytesperline = q_data->bytesperline[i]; ++ pix->plane_fmt[i].sizeimage = q_data->sizeimage[i]; ++ memset(&(pix->plane_fmt[i].reserved[0]), 0x0, ++ sizeof(pix->plane_fmt[i].reserved)); ++ } ++ ++// pix->flags = 0; ++ pix->colorspace = ctx->colorspace; ++// pix->ycbcr_enc = ctx->ycbcr_enc; ++// pix->quantization = ctx->quantization; ++// pix->xfer_func = ctx->xfer_func; ++ ++ ++ pr_debug("g_fmt f->type %d\n", f->type); ++ ++ pr_debug("pixel_format = %x, %c%c%c%c\n", pix->pixelformat, pixelformat_str(pix->pixelformat)); ++ pr_debug("pix->num_planes %d\n", pix->num_planes); ++ ++ return 0; ++} ++ ++ ++static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct ingenic_video_fmt *fmt; ++ struct ingenic_venc_ctx *ctx = fh_to_ctx(priv); ++ ++ fmt = ingenic_venc_find_format(f, 0); ++ if (!fmt) { ++ f->fmt.pix.pixelformat = ingenic_video_formats[CAP_FMT_IDX].fourcc; ++ f->fmt.pix_mp.pixelformat = ingenic_video_formats[CAP_FMT_IDX].fourcc; ++ fmt = ingenic_venc_find_format(f, 0); ++ } ++ f->fmt.pix_mp.colorspace = ctx->colorspace; ++ //f->fmt.pix_mp.ycbcr_enc = ctx->ycbcr_enc; ++ //f->fmt.pix_mp.quantization = ctx->quantization; ++ //f->fmt.pix_mp.xfer_func = ctx->xfer_func; ++ ++ return vidioc_try_fmt(f, fmt); ++} ++ ++static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ ++ struct ingenic_video_fmt *fmt; ++ ++ fmt = ingenic_venc_find_format(f, 1); ++ if (!fmt) { ++ f->fmt.pix.pixelformat = ingenic_video_formats[OUT_FMT_IDX].fourcc; ++ f->fmt.pix_mp.pixelformat = ingenic_video_formats[OUT_FMT_IDX].fourcc; ++ fmt = ingenic_venc_find_format(f, 1); ++ } ++ if (!f->fmt.pix_mp.colorspace) { ++ f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_REC709; ++ // f->fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; ++ // f->fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT; ++ // f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT; ++ } ++ ++ return vidioc_try_fmt(f, fmt); ++} ++ ++static int vidioc_g_selection(struct file *file, void *priv, ++ struct v4l2_selection *s) ++{ ++ // TODO ++ ++ return 0; ++} ++ ++static int vidioc_s_selection(struct file *file, void *priv, ++ struct v4l2_selection *s) ++{ ++ //TODO ++ return 0; ++} ++ ++ ++static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) ++{ ++ struct ingenic_venc_ctx *ctx = fh_to_ctx(priv); ++ ++ if(ctx->state == INGENIC_STATE_ABORT) { ++ return -EIO; ++ } ++ ++ pr_debug("====== %s, %d, buf->type %d\n", __func__, __LINE__, buf->type); ++ return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); ++} ++ ++static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) ++{ ++ struct ingenic_venc_ctx *ctx = fh_to_ctx(priv); ++ pr_debug("====== %s, %d\n", __func__, __LINE__); ++ return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); ++} ++ ++static int vidioc_streamon(struct file *file, void *priv, ++ enum v4l2_buf_type type) ++{ ++ struct ingenic_venc_ctx *ctx = fh_to_ctx(priv); ++ pr_debug("====== %s, %d\n", __func__, __LINE__); ++ ++ return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); ++} ++ ++static int vidioc_streamoff(struct file *file, void *priv, ++ enum v4l2_buf_type type) ++{ ++ struct ingenic_venc_ctx *ctx = fh_to_ctx(priv); ++ ++ return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); ++} ++ ++static int vidioc_reqbufs(struct file *file, void *priv, ++ struct v4l2_requestbuffers *reqbufs) ++{ ++ struct ingenic_venc_ctx *ctx = fh_to_ctx(priv); ++ ++ return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); ++ ++} ++ ++static int vidioc_querybuf(struct file *file, void *priv, ++ struct v4l2_buffer *buf) ++{ ++ struct ingenic_venc_ctx *ctx = fh_to_ctx(priv); ++ ++ return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); ++ ++} ++ ++static int vidioc_expbuf(struct file *file, void *priv, ++ struct v4l2_exportbuffer *eb) ++{ ++ ++ struct ingenic_venc_ctx *ctx = fh_to_ctx(priv); ++ ++ return v4l2_m2m_expbuf(file, ctx->m2m_ctx, eb); ++} ++ ++static int vidioc_create_bufs(struct file *file, void *priv, ++ struct v4l2_create_buffers *create) ++{ ++ struct ingenic_venc_ctx *ctx = fh_to_ctx(priv); ++ ++ return v4l2_m2m_create_bufs(file, ctx->m2m_ctx, create); ++} ++static int vidioc_prepare_buf(struct file *file, void *fh, struct v4l2_buffer *b) ++{ ++ //TODO ....??? ++ ++ return 0; ++} ++ ++const struct v4l2_ioctl_ops ingenic_venc_ioctl_ops = { ++ ++ .vidioc_streamon = vidioc_streamon, ++ .vidioc_streamoff = vidioc_streamoff, ++ ++ .vidioc_reqbufs = vidioc_reqbufs, ++ .vidioc_querybuf = vidioc_querybuf, ++ .vidioc_qbuf = vidioc_qbuf, ++ .vidioc_dqbuf = vidioc_dqbuf, ++ ++ .vidioc_querycap = vidioc_querycap, ++ .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane, ++ .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane, ++ .vidioc_enum_framesizes = vidioc_enum_framesizes, ++ ++ .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap_mplane, ++ .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_vid_out_mplane, ++ .vidioc_expbuf = vidioc_expbuf, ++ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, ++ .vidioc_unsubscribe_event = v4l2_event_unsubscribe, ++ ++ .vidioc_s_parm = vidioc_s_parm, ++ .vidioc_g_parm = vidioc_g_parm, ++ .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_cap, ++ .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_out, ++ ++ .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt, ++ .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt, ++ ++ .vidioc_create_bufs = vidioc_create_bufs, ++ .vidioc_prepare_buf = vidioc_prepare_buf, ++ ++ .vidioc_g_selection = vidioc_g_selection, ++ .vidioc_s_selection = vidioc_s_selection, ++}; ++ ++ ++static int vb2ops_venc_queue_setup(struct vb2_queue *vq, ++ const struct v4l2_format *fmt, ++ unsigned int *nbuffers, ++ unsigned int *nplanes, ++ unsigned int sizes[], ++ void *alloc_ctxs[]) ++{ ++ struct ingenic_venc_ctx *ctx = vb2_get_drv_priv(vq); ++ struct ingenic_venc_q_data *q_data; ++ int i; ++ ++ pr_debug("%s--%d\n", __func__, __LINE__); ++ ++ q_data = ingenic_venc_get_q_data(ctx, vq->type); ++ if(q_data == NULL) ++ return -EINVAL; ++ ++ pr_debug("%s--%d, vq->type %d\n", __func__, __LINE__, vq->type); ++ ++ if(*nplanes) { ++ for(i = 0; i < *nplanes; i++) { ++ if(sizes[i] < q_data->sizeimage[i]) { ++ pr_debug("---sizes %d %d, %d\n", *nplanes, sizes[i], q_data->sizeimage[i]); ++ return -EINVAL; ++ } ++ } ++ } else { ++ *nplanes = q_data->fmt->num_planes; ++ for (i = 0; i < *nplanes; i++) { ++ sizes[i] = q_data->sizeimage[i]; ++ alloc_ctxs[i] = ctx->dev->alloc_ctx; ++ } ++ } ++ ++ ++ pr_debug("*nplanes %d, sizes[0] %d\n", *nplanes, sizes[0]); ++ for(i = 0; i<*nplanes ; i++) { ++ pr_debug("plane %d, sizes[%d] %d, type %d\n", i, i, sizes[i], vq->type); ++ } ++ ++ ++ pr_debug("%s--%d\n", __func__, __LINE__); ++ return 0; ++} ++ ++static int vb2ops_venc_buf_prepare(struct vb2_buffer *vb) ++{ ++ struct ingenic_venc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); ++ struct ingenic_venc_q_data *q_data; ++ int i; ++ ++ pr_debug("%s--%d\n", __func__, __LINE__); ++ q_data = ingenic_venc_get_q_data(ctx, vb->vb2_queue->type); ++ ++ for(i = 0; i < q_data->fmt->num_planes; i++) { ++ if(vb2_plane_size(vb, i) > q_data->sizeimage[i]) { ++ ++ pr_err("Failed to prepare buf!\n"); ++ ++ return -EINVAL; ++ } ++ } ++ ++ pr_debug("%s--%d\n", __func__, __LINE__); ++ return 0; ++} ++ ++static void vb2ops_venc_buf_queue(struct vb2_buffer *vb) ++{ ++ struct ingenic_venc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); ++ struct vb2_v4l2_buffer *vbuf = container_of(vb, struct vb2_v4l2_buffer, vb2_buf); ++ ++ v4l2_m2m_buf_queue(ctx->m2m_ctx, vbuf); ++ return; ++} ++ ++ ++static int vb2ops_venc_start_streaming(struct vb2_queue *q, unsigned int count) ++{ ++ struct ingenic_venc_ctx *ctx = vb2_get_drv_priv(q); ++ struct ingenic_venc_q_data *q_data_src; ++ struct ingenic_venc_q_data *q_data_dst; ++ struct h264e_ctx *h264e_ctx = &ctx->h264e_ctx; ++ struct jpge_ctx *jpge_ctx = &ctx->jpge_ctx; ++ struct jpgd_ctx *jpgd_ctx = &ctx->jpgd_ctx; ++ int ret = 0; ++ ++ pr_debug("%s--%d\n", __func__, __LINE__); ++ ++ if(V4L2_TYPE_IS_OUTPUT(q->type)) { ++ ctx->output_stopped = 0; ++ } else { ++ ctx->capture_stopped = 0; ++ } ++ ++ /*有一个没开始,就返回.*/ ++ if(ctx->output_stopped || ctx->capture_stopped) ++ return 0; ++ ++ /* 如果两个queue都start了,就可以初始化workbuf了,这里主要根据输入的格式,输出的格式,申请除了用户空间q 和 dq之外的自己使用的buffer.*/ ++ ++ q_data_src = ingenic_venc_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); ++ q_data_dst = ingenic_venc_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); ++ ++ if(ctx->codec_id == CODEC_ID_H264E) { ++ pr_info("h264 start streaming \n"); ++ h264e_set_fmt(h264e_ctx, q_data_src->visible_width, ++ q_data_src->visible_height, q_data_src->fmt->format); ++ ret = h264e_alloc_workbuf(h264e_ctx); ++ if(ret < 0) ++ return ret; ++ ++ ctx->state = INGENIC_STATE_HEADER; ++ ++ ret = h264e_generate_headers(h264e_ctx); ++ if(ret < 0) ++ return ret; ++ ++ } else if(ctx->codec_id == CODEC_ID_JPGE) { ++ pr_info("jpge start streaming \n"); ++ ++ ret = jpeg_encoder_set_fmt(jpge_ctx, q_data_src->visible_width, ++ q_data_src->visible_height, q_data_src->fmt->format); ++ if(ret < 0) { ++ return ret; ++ } ++ ret = jpeg_encoder_alloc_workbuf(jpge_ctx); ++ if(ret < 0) { ++ return ret; ++ } ++ ctx->state = INGENIC_STATE_RUNNING; ++ ++ } else if(ctx->codec_id == CODEC_ID_JPGD) { ++ pr_info("jpgd start streaming \n"); ++ ++ ret = jpeg_decoder_set_fmt(jpgd_ctx, q_data_dst->visible_width, ++ q_data_dst->visible_height, q_data_dst->fmt->format); ++ if(ret < 0) { ++ return ret; ++ } ++ ret = jpeg_decoder_alloc_workbuf(jpgd_ctx); ++ if(ret < 0) { ++ return ret; ++ } ++ ctx->state = INGENIC_STATE_RUNNING; ++ ++ } else { ++ pr_err("Invalid Codec ID: %d\n", ctx->codec_id); ++ return -EINVAL; ++ } ++ ++ pr_debug("%s--%d\n", __func__, __LINE__); ++ return 0; ++} ++ ++static int vb2ops_venc_stop_streaming(struct vb2_queue *q) ++{ ++ ++ struct ingenic_venc_ctx *ctx = vb2_get_drv_priv(q); ++ struct vb2_v4l2_buffer *src_buf, *dst_buf; ++ struct ingenic_venc_q_data *q_data_src; ++ struct ingenic_venc_q_data *q_data_dst; ++ struct h264e_ctx *h264e_ctx = &ctx->h264e_ctx; ++ struct jpge_ctx *jpge_ctx = &ctx->jpge_ctx; ++ struct jpgd_ctx *jpgd_ctx = &ctx->jpgd_ctx; ++ int ret = 0; ++ pr_debug("%s--%d\n", __func__, __LINE__); ++ ++ /* stop both output and capture .*/ ++ ++ /* 当上层输入的数据没有了,就会draining, 只会停止OUTPUT stream, ++ 但是,此时,上层还是会进行dequeue CAPTURE stream, ++ 而此时,CAPTURE stream又没有数据,肯定会失败。 ++ ++ 所以应该上层判断是否没有原始数据了,如果没有原始数据,就不要再polling了。 ++ ++ 上层实现有问题了?????? ++ ++ */ ++ ++// if(q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { ++ ++ /* KERNEL 3.10 .*/ ++ while((dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx))) { ++ dst_buf->vb2_buf.planes[0].bytesused = 0; ++ dst_buf->flags |= V4L2_BUF_FLAG_DONE; ++ do_gettimeofday(&dst_buf->timestamp); ++ /*保证两个的时间戳不一样.*/ ++ dst_buf->timestamp = ns_to_timeval((timeval_to_ns(&dst_buf->timestamp) + 10)); ++ /* work around, return buffer to userspace with 0 byteused. */ ++ v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); ++ } ++// } else { ++ while((src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx))) { ++ v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); ++ } ++// } ++ ++ if(q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) ++ ctx->capture_stopped = 1; ++ else ++ ctx->output_stopped = 1; ++ ++ if((ctx->capture_stopped && ctx->output_stopped) == 0) { ++ return ret; ++ } ++ ++ q_data_src = ingenic_venc_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); ++ q_data_dst = ingenic_venc_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); ++ ++ switch(ctx->codec_id) { ++ case CODEC_ID_H264E: ++ pr_info("h264 stop streaming !\n"); ++ h264e_free_workbuf(h264e_ctx); ++ ++ h264e_encoder_deinit(h264e_ctx); ++ break; ++ case CODEC_ID_JPGE: ++ jpeg_encoder_free_workbuf(jpge_ctx); ++ jpeg_encoder_deinit(jpge_ctx); ++ break; ++ case CODEC_ID_JPGD: ++ jpeg_decoder_free_workbuf(jpgd_ctx); ++ jpeg_decoder_deinit(jpgd_ctx); ++ break; ++ default: ++ break; ++ } ++ ++ ctx->state = INGENIC_STATE_IDLE; ++ pr_debug("%s--%d\n", __func__, __LINE__); ++ return ret; ++} ++ ++static const struct vb2_ops ingenic_venc_vb2_ops = { ++ .queue_setup = vb2ops_venc_queue_setup, ++ .buf_prepare = vb2ops_venc_buf_prepare, ++ .buf_queue = vb2ops_venc_buf_queue, ++ .wait_prepare = vb2_ops_wait_prepare, ++ .wait_finish = vb2_ops_wait_finish, ++ .start_streaming = vb2ops_venc_start_streaming, ++ .stop_streaming = vb2ops_venc_stop_streaming, ++}; ++ ++static void m2mops_venc_device_run(void *priv) ++{ ++ ++ struct ingenic_venc_ctx *ctx = priv; ++ struct vb2_v4l2_buffer *src_buf, *dst_buf; ++ struct vb2_buffer *src_buffer, *dst_buffer; ++ struct ingenic_video_buf *src_video_buf, *dst_video_buf; ++ ++ struct video_frame_buffer *src_frame = NULL; ++ struct video_frame_buffer *dst_frame = NULL; ++ ++ struct h264e_ctx *h264e_ctx = &ctx->h264e_ctx; ++ struct jpge_ctx *jpge_ctx = &ctx->jpge_ctx; ++ struct jpgd_ctx *jpgd_ctx = &ctx->jpgd_ctx; ++ ++ int i = 0; ++ int ret = 0; ++ int keyframe = 0; ++ ++ pr_debug("---- %s, %d\n", __func__, __LINE__); ++ ++ src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); ++ src_buffer = (struct vb2_buffer *)src_buf; ++ src_video_buf = container_of(src_buffer, struct ingenic_video_buf, vb); ++ src_frame = &src_video_buf->buf; ++ /* everything is ok, encode one frame. */ ++ ++ /* 构造源buffer. */ ++ printk("-----src_buf->vb2_buf.num_planes %d\n", src_buf->vb2_buf.num_planes); ++ memset(src_frame, 0, sizeof(src_frame)); ++ src_frame->num_planes = src_buf->vb2_buf.num_planes; ++ for(i = 0; i < src_buf->vb2_buf.num_planes; i++) { ++ src_frame->fb_addr[i].va = vb2_plane_vaddr(src_buffer, i); ++ src_frame->fb_addr[i].pa = vb2_dma_contig_plane_dma_addr(src_buffer, i); ++ src_frame->fb_addr[i].size = vb2_get_plane_payload(src_buffer, i); //(size_t)src_buf->vb2_buf.planes[i].length; ++ ++ printk("---va %x, length %d, bytesused %d\n", (unsigned int)vb2_plane_vaddr(src_buffer, i), ++ (size_t)src_buf->vb2_buf.planes[i].length, ++ src_buf->vb2_buf.planes[i].bytesused); ++ ++ print_hex_dump(KERN_INFO, "input", DUMP_PREFIX_ADDRESS, 16, 1, src_frame->fb_addr[i].va, 64, 1); ++ } ++ ++ dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); ++ dst_buffer = (struct vb2_buffer *)dst_buf; ++ dst_buf->vb2_buf.planes[0].bytesused = 0; ++ dst_video_buf = container_of(dst_buffer, struct ingenic_video_buf, vb); ++ dst_frame = &dst_video_buf->buf; ++ dst_frame->num_planes = dst_buf->vb2_buf.num_planes; ++ ++ /*将header和bs码流放在一个目标buffer中,先编码header,注意填充FF,达到地址对齐的目的*/ ++ if(ctx->state == INGENIC_STATE_HEADER) { ++ ++ printk("------------h264e_ctx->bs_header_size: %d\n", h264e_ctx->bs_header_size); ++ if(ctx->codec_id != CODEC_ID_H264E) { ++ pr_err("invalid state!\n"); ++ ctx->state = INGENIC_STATE_ABORT; ++ return; ++ } ++ dst_frame->fb_addr[0].va = vb2_plane_vaddr(dst_buffer, 0); ++ dst_frame->fb_addr[0].pa = vb2_dma_contig_plane_dma_addr(dst_buffer, 0); ++ h264e_ctx->encoded_bs_len = 0; ++ ret = h264e_encode_headers(h264e_ctx, &dst_frame->fb_addr[0]); ++ if(ret < 0) ++ return; ++ ++ if(h264e_ctx->p.h264_hdr_mode == V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME) { ++ /* 如果 sps/pps 和第一帧打包到一起,先放头信息。*/ ++ dst_frame->fb_addr[0].va += h264e_ctx->encoded_bs_len; ++ dst_frame->fb_addr[0].pa += h264e_ctx->encoded_bs_len; ++ dst_buf->vb2_buf.planes[0].bytesused = h264e_ctx->encoded_bs_len; ++ } else { ++ ++ dst_buf->vb2_buf.planes[0].bytesused = h264e_ctx->encoded_bs_len; ++ dst_buf->timestamp = src_buf->timestamp; ++ dst_buf->timecode = src_buf->timecode; ++ ++ v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); ++ ++ dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); ++ if(!dst_buf) { ++ pr_err("Failed to get dst buf!\n"); ++ ctx->state = INGENIC_STATE_ABORT; ++ return; ++ } ++ ++ dst_frame->fb_addr[0].va = vb2_plane_vaddr(dst_buffer, 0); ++ dst_frame->fb_addr[0].pa = vb2_dma_contig_plane_dma_addr(dst_buffer, 0); ++ dst_buf->vb2_buf.planes[0].bytesused = 0; ++ } ++ ++ ctx->state = INGENIC_STATE_RUNNING; ++ } else { ++ /*再取一个dst_buf,编码数据*/ ++ for(i = 0; i < dst_buf->vb2_buf.num_planes; i++) { ++ dst_frame->fb_addr[i].va = vb2_plane_vaddr(dst_buffer, i); ++ dst_frame->fb_addr[i].pa = vb2_dma_contig_plane_dma_addr(dst_buffer, i); ++ } ++ //bs_buf->size = (size_t)dst_buf->vb2_buf.planes[0].length; ++ } ++ ++ switch(ctx->codec_id) { ++ case CODEC_ID_H264E: ++ h264e_ctx->encoded_bs_len = 0; ++ ret = h264e_encode(h264e_ctx, src_frame, &dst_frame->fb_addr[0], &keyframe); ++ ++ if(keyframe) { ++ dst_buf->flags |= V4L2_BUF_FLAG_KEYFRAME; ++ } else { ++ dst_buf->flags &= ~V4L2_BUF_FLAG_KEYFRAME; ++ } ++ dst_buf->vb2_buf.planes[0].bytesused += h264e_ctx->encoded_bs_len; /* returned bs size. */ ++ break; ++ case CODEC_ID_JPGE: ++ ++ ret = jpeg_encoder_encode(jpge_ctx, src_frame, &dst_frame->fb_addr[0]); ++ if(ret < 0) { ++ ctx->state = INGENIC_STATE_ABORT; ++ } ++ ++ vb2_set_plane_payload(dst_buffer, 0, jpge_ctx->bslen); ++ ++ //dst_buf->vb2.buf.planes[0].bytesused = jpge_ctx->bslen; ++ break; ++ case CODEC_ID_JPGD: ++ /*src bs? dst raw? */ ++ ret = jpeg_decoder_decode(jpgd_ctx, &src_frame->fb_addr[0], dst_frame); ++ if(ret < 0) { ++ ctx->state = INGENIC_STATE_ABORT; ++ } ++ ++ break; ++ default: ++ break; ++ } ++ ++ /* get results ... */ ++ v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); ++ ++ //dst_buf->vb2.buf.planes[0].bytesused = 640*480; /* bs size. */ ++ dst_buf->timestamp = src_buf->timestamp; ++ dst_buf->timecode = src_buf->timecode; ++ dst_buf->sequence = src_buf->sequence; ++ ++ v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); ++ ++ v4l2_m2m_job_finish(ctx->dev->m2m_dev_enc, ctx->m2m_ctx); ++} ++ ++static int m2mops_venc_job_ready(void *m2m_priv) ++{ ++ struct ingenic_venc_ctx *ctx = m2m_priv; ++ ++ if(ctx->state == INGENIC_STATE_ABORT || ctx->state == INGENIC_STATE_IDLE) { ++ pr_info("job not ready, ctx->state %d\n", ctx->state); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++ ++static void m2mops_venc_job_abort(void *priv) ++{ ++ struct ingenic_venc_ctx *ctx = priv; ++ ++ ctx->state = INGENIC_STATE_ABORT; ++} ++ ++ ++static void m2mops_venc_lock(void *m2m_priv) ++{ ++ struct ingenic_venc_ctx *ctx = m2m_priv; ++ ++ //TODO ++ mutex_lock(&ctx->dev->dev_mutex); ++} ++ ++static void m2mops_venc_unlock(void *m2m_priv) ++{ ++ struct ingenic_venc_ctx *ctx = m2m_priv; ++ ++ mutex_unlock(&ctx->dev->dev_mutex); ++} ++ ++const struct v4l2_m2m_ops ingenic_venc_m2m_ops = { ++ .device_run = m2mops_venc_device_run, ++ .job_ready = m2mops_venc_job_ready, ++ .job_abort = m2mops_venc_job_abort, ++ .lock = m2mops_venc_lock, ++ .unlock = m2mops_venc_unlock, ++}; ++ ++ ++ ++int ingenic_vcodec_enc_init_default_params(struct ingenic_venc_ctx *ctx) ++{ ++ ++ int ret = 0; ++ ++ ++ ctx->capture_stopped = 1; ++ ctx->output_stopped = 1; ++ ++ //ctx->m2m_ctx->q_lock = &ctx->dev->dev_mutex; ++ //ctx->fh.m2m_ctx = ctx->m2m_ctx; ++ ctx->fh.ctrl_handler = &ctx->ctrl_hdl; ++ ++ return ret; ++} ++ ++int ingenic_vcodec_enc_deinit_default_params(struct ingenic_venc_ctx *ctx) ++{ ++ return 0; ++} ++ ++ ++#define INGENIC_MAX_CTRLS_HINT 20 ++int ingenic_vcodec_enc_ctrls_setup(struct ingenic_venc_ctx *ctx) ++{ ++ const struct v4l2_ctrl_ops *ops = &ingenic_venc_ctrl_ops; ++ struct v4l2_ctrl_handler *handler = &ctx->ctrl_hdl; ++ ++ v4l2_ctrl_handler_init(handler, INGENIC_MAX_CTRLS_HINT); ++ ++ v4l2_ctrl_new_std(handler, ops, V4L2_CID_JPEG_COMPRESSION_QUALITY, ++ 0, 3, 1, 3); ++ ++ v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_BITRATE, ++ 1, 4000000, 1, 4000000); ++ v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_B_FRAMES, ++ 0, 2, 1, 0); ++ v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE, ++ 0, 1, 1, 1); ++ v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_H264_MAX_QP, ++ 0, 51, 1, 51); ++ v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_H264_I_PERIOD, ++ 0, 65535, 1, 0); ++ v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_GOP_SIZE, ++ 0, 65535, 1, 0); ++ v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE, ++ 0, 1, 1, 0); ++ v4l2_ctrl_new_std_menu(handler, ops, ++ V4L2_CID_MPEG_VIDEO_HEADER_MODE, ++ V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, ++ 0, V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE); ++ v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_MPEG_VIDEO_H264_PROFILE, ++ V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, ++ 0, V4L2_MPEG_VIDEO_H264_PROFILE_HIGH); ++ v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_MPEG_VIDEO_H264_LEVEL, ++ V4L2_MPEG_VIDEO_H264_LEVEL_4_2, ++ 0, V4L2_MPEG_VIDEO_H264_LEVEL_4_0); ++ if (handler->error) { ++ pr_err("Init control handler fail %d\n", ++ handler->error); ++ return handler->error; ++ } ++ ++ v4l2_ctrl_handler_setup(&ctx->ctrl_hdl); ++ ++ return 0; ++} ++ ++int ingenic_vcodec_enc_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) ++{ ++ struct ingenic_venc_ctx *ctx = priv; ++ int ret = 0; ++ ++ /* TODO: to support VB2_USERPTR with dmmu?. */ ++ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; ++ src_vq->io_modes = VB2_DMABUF | VB2_MMAP; ++ src_vq->drv_priv = ctx; ++ src_vq->buf_struct_size = sizeof(struct ingenic_video_buf); ++ src_vq->ops = &ingenic_venc_vb2_ops; ++ src_vq->mem_ops = &vb2_dma_contig_memops; ++ src_vq->lock = &ctx->dev->dev_mutex; ++ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; ++// src_vq->dev = ctx->dev->dev; ++ ++ printk("src_vq init ..!\n"); ++ ret = vb2_queue_init(src_vq); ++ if(ret) ++ return ret; ++ ++ ++ printk("dst_vq init ...!\n"); ++ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; ++ dst_vq->io_modes = VB2_DMABUF | VB2_MMAP; ++ dst_vq->drv_priv = ctx; ++ dst_vq->buf_struct_size = sizeof(struct ingenic_video_buf); ++ dst_vq->ops = &ingenic_venc_vb2_ops; ++ dst_vq->mem_ops = &vb2_dma_contig_memops; ++ dst_vq->lock = &ctx->dev->dev_mutex; ++ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; ++// dst_vq->dev = ctx->dev->dev; ++ ++ return vb2_queue_init(dst_vq); ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_helix_ops.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_helix_ops.h.patch new file mode 100644 index 00000000..9c018287 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_helix_ops.h.patch @@ -0,0 +1,21 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/helix/helix_ops.h b/drivers/media/platform/ingenic-vcodec/helix/helix_ops.h +--- a/drivers/media/platform/ingenic-vcodec/helix/helix_ops.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/helix/helix_ops.h 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,17 @@ ++#ifndef __INGENIC_HELIX_OPS_H__ ++#define __INGENIC_HELIX_OPS_H__ ++ ++ ++extern const struct v4l2_ioctl_ops ingenic_venc_ioctl_ops; ++extern const struct v4l2_m2m_ops ingenic_venc_m2m_ops; ++ ++ ++ ++int ingenic_vcodec_enc_init_default_params(struct ingenic_venc_ctx *ctx); ++int ingenic_vcodec_enc_deinit_default_params(struct ingenic_venc_ctx *ctx); ++ ++int ingenic_vcodec_enc_ctrls_setup(struct ingenic_venc_ctx *ctx); ++int ingenic_vcodec_enc_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq); ++ ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_jpgd.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_jpgd.c.patch new file mode 100644 index 00000000..632c48e1 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_jpgd.c.patch @@ -0,0 +1,580 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/helix/jpgd.c b/drivers/media/platform/ingenic-vcodec/helix/jpgd.c +--- a/drivers/media/platform/ingenic-vcodec/helix/jpgd.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/helix/jpgd.c 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,576 @@ ++/* ++* Copyright© 2014 Ingenic Semiconductor Co.,Ltd ++* ++* Author: qipengzhen ++* ++* 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. ++* ++*/ ++ ++#include ++#include ++ ++ ++#include "helix_buf.h" ++#include "jpgd.h" ++ ++static void dump_slice_info(_JPEGD_SliceInfo *s) ++{ ++ printk("s->des_va: %08x\n", (unsigned int)s->des_va); ++ printk("s->des_pa: %08x\n", s->des_pa); ++ printk("s->bsa: %08x\n", s->bsa); ++ printk("s->p0a: %08x\n", s->p0a); ++ printk("s->p1a: %08x\n", s->p1a); ++ printk("s->nrsm: %d\n", s->nrsm); ++ printk("s->nmcu: %d\n", s->nmcu); ++ printk("s->pxc[0]: %x\n", s->pxc[0]); ++ printk("s->pxc[1]: %x\n", s->pxc[1]); ++ printk("s->pxc[2]: %x\n", s->pxc[2]); ++ printk("s->pxc[3]: %x\n", s->pxc[3]); ++} ++ ++static int jpgd_fill_slice_info(struct jpgd_ctx *ctx) ++{ ++ struct jpgd_params *p = &ctx->p; ++ _JPEGD_SliceInfo *s = ctx->s; ++ int ret = 0; ++ ++ s->des_va = ctx->desc; ++ s->des_pa = ctx->desc_pa; ++ s->bsa = ctx->bs->pa; ++ s->p0a = ctx->frame->fb_addr[0].pa; ++ s->p1a = ctx->frame->fb_addr[1].pa; ++ s->nrsm = 0; ++ s->nmcu = (p->height / 16) * (p->width / 16) - 1; ++ s->huffmin = p->huffmin; ++ s->huffbase = p->hea; ++ s->huffsymb = p->heb; ++ s->qmem = p->qt; ++ ++ if(p->format == HELIX_NV12_MODE) { ++ s->width = 1 << 15 | (p->width / 16 - 1); ++ } ++ s->pxc[0] = p->pxc[0]; ++ s->pxc[1] = p->pxc[1]; ++ s->pxc[2] = p->pxc[2]; ++ s->pxc[3] = p->pxc[3]; ++ ++ return ret; ++} ++ ++/* decode header info to params ??*/ ++static int jpgd_decode_header(struct jpgd_ctx *ctx) ++{ ++ struct ingenic_vcodec_mem *bs = ctx->bs; ++ struct jpgd_params *p = &ctx->p; ++ unsigned char *pbuf = bs->va; ++ int bslen = bs->size; ++ unsigned char *bsend = bs->va + bs->size; ++ ++ int hbase, hb, abase, bbase, dc, ht; ++ int i,j,n,v,c,nrst,nm,code,hid; ++ unsigned int min0, min1, min2, min3; ++ ++ int ncol, len; ++ int l[16]; ++ int nblk[4] = {0}; ++ int qt_sel[4] = {0}; ++ int ha_sel[4] = {0}; ++ int hd_sel[4] = {0}; ++ int is_sos = 0; ++ //unsigned int pxc[4]; ++ ++ unsigned char *dst_bs = bs->va; ++ unsigned char *dst_bslen = 0; ++ ++ nrst = nm = ncol = 0; ++ /* init default table ?*/ ++ for(i = 0; i < 384; i++) { ++ p->huffenc[i] = 0xfff; ++ } ++ for(i = 168, j = 0xfd0; i < 176; i++, j++) { ++ p->huffenc[i] = j; ++ } ++ for(i = 344, j = 0xfd0; i < 352; i++, j++) { ++ p->huffenc[i] = j; ++ } ++ ++ for(i=162;i<174;i++) ++ p->heb[i]=0; ++ ++ for(i=0;i<4;i++) ++ for(j=0;j<64;j++) ++ p->qt[i][j] = 0; ++ ++ while(1) { ++ ++ if(is_sos || pbuf >= bsend) { ++ break; ++ } ++ ++ c = *pbuf++; ++ if(c != 0xff) ++ continue; ++ ++ ++ while((c = *pbuf++) == 0xff); ++ if(c == 0) { ++ /* not a marker */ ++ continue; ++ } ++marker: ++ switch(c) { ++ case 0xc0 : // Baseline (0, 0) ++ case 0xc1 : // Ext. Sequential, Huffman (0, 0) ++ case 0xc2 : // Progressive, Huffman (1, 0) ++ case 0xc3 : // Lossless, Huffman ++ case 0xc5 : // Differential Sequential, Huffman ++ case 0xc6 : // Differential Progressive, Huffman ++ case 0xc7 : // Differential Lossless, Huffman ++ case 0xc9 : // Extended Sequential, Arithmetic (0, 1) ++ case 0xca : // Progressive, Arithmetic (1, 1) ++ case 0xcb : // Lossless, Huffman ++ case 0xcd : // Differential Sequential, Arithmetic ++ case 0xce : // Differential Progressive, Arithmetic ++ case 0xcf : // Differential Lossless, Arithmetic ++ ++ pbuf += 3; ++ p->height = (*pbuf++ << 8) | *pbuf++; ++ p->width = (*pbuf++ << 8) | *pbuf++; ++ ncol = *pbuf++; ++ ++ for(i = 0; i < ncol; i++) { ++ pbuf++; ++ nblk[i] = *pbuf++; ++ qt_sel[i] = *pbuf++; ++ } ++ break; ++ case 0xc4 : ++ /* DHT marker detected */ ++ /* Get the lenght of the marker segment */ ++ // Lh : HT length (16b) ++ n = (*pbuf++ << 8) | *pbuf++; ++ ++ /* reduce 2 ?*/ ++ n -= 2; ++ ++ while(n) { ++ /* Get the type of table */ ++ v= *pbuf++; // Tc & Th ++ // Tc : Table class (4b) ++ // 0 = DC or lossless table ++ // 1 = AC table ++ // Th : HT destination identifier ++ // - specifies 1 of 4 possible destinations at the decoder into ++ // which HT shall be installed. ++ ++ /* Reduce marker segment byte count */ ++ n--; ++ ++ hid = v>>4 ? 2 : 0; ++ hid |= v&15 ? 1 : 0; ++ switch(hid){ ++ case 1: ++ hbase = 368; ++ break; ++ case 2: ++ hbase = 0; ++ break; ++ case 3: ++ hbase = 176; ++ break; ++ default : ++ hbase = 352; ++ break; ++ } ++ if((v>>4)) ++ abase = 0; ++ else ++ abase = 1; ++ ++ dc = abase; ++ ht = v&15; ++ abase |=ht<<1; ++ switch(abase){ ++ case 1 : ++ case 3 : ++ bbase = 162; ++ break; ++ case 2 : ++ bbase = 174; ++ break; ++ default : ++ bbase = 0; ++ break; ++ } ++ abase <<= 4; ++ ++ /* Memory initialization */ ++ for(i = abase; i < abase+16; i++) ++ p->hea[i] = 255; ++ /* Get the number of codes for each length */ ++ // Lj : # of Huffman codes of length i ++ // - specifies the # of Huffman codes for each of 16 possible lengths ++ // allowed by spec. BITS ++ for(i = 0; i < 16; i++) { ++ l[i] = *pbuf++; ++ } ++ /* Reduce marker segment byte count */ ++ n -= 16; ++ code = 0; ++ for(i=0; i<16; i++,abase++) { ++ p->min[abase] = code; ++ p->hea[abase] = bbase - code; ++ if(l[i]) { ++ // Vi,j : associated with each Huffman code ++ // - specifies, for each i the value associated with each Huffman code ++ // of length i. HUFFVAL ++ for(j=0; jhuffenc[hbase+v]= (i<<8) | (code&0xff); ++ v &= 15; ++ if(ht) ++ v <<= 4; ++ p->heb[bbase] |= v; ++ } else{ ++ if(v == 0) ++ hb = 160; ++ else if(v == 0xf0) ++ hb = 161; ++ else ++ hb = (v>>4)*10 + (v&0xf) - 1; ++ p->huffenc[hbase+hb] = (i<<8) | (code&0xff); ++ p->heb[bbase] = v; ++ } ++ code++; ++ } ++ ++ } ++ code <<= 1; ++ } ++ } ++ break; ++ case 0xc8 : ++ break; ++ ++ case 0xcc : ++ break; ++ /* M_RST0 ~ M_RST7, ignore? */ ++ case 0xd0 : ++ case 0xd1 : ++ case 0xd2 : ++ case 0xd3 : ++ case 0xd4 : ++ case 0xd5 : ++ case 0xd6 : ++ case 0xd7 : ++ break; ++ /* M_SOI */ ++ case 0xd8 : ++ break; ++ /* M_EOI */ ++ case 0xd9 : ++ *dst_bs++ = 0xff; ++ dst_bslen++; ++ *dst_bs++ = 0xd9; ++ dst_bslen++; ++ break; ++ /* M_SOS */ ++ case 0xda : ++ pbuf += 2; ++ n= *pbuf++; //Ns (# of image components) ++ ++ for(i=0;i>4; ++ hd_sel[i] = hd_sel[i] & 0x3; ++ } ++ pbuf++; //Ss ++ pbuf++; //Se ++ pbuf++; //Ah&Al ++ /* TODO... */ ++ /* BS left can be decoded by vpu.*/ ++ is_sos = 1; ++ ++ break; ++ case 0xdb : ++ // Lq : QT Length (16b) ++ v = (*pbuf++ << 8) | *pbuf++; ++ len = v-2; ++ while (len > 0) { ++ int prec; ++ v = *pbuf++; ++ // Pq : QT element precision (4b) ++ // - specifies the precision of the Qk values. ++ // 0 indicates 8-bits Qk values. ++ // 1 indicates 16-bits Qk values ++ prec = v >> 4; ++ // Tq : QT destination identifier (4b) ++ // - specifies one of 4 possible destnations at the decoder into ++ // which the QT shall be installed. ++ n = v&15; ++ if(n > 3){ ++ /*ijpegd_log(h, C_LOG_DEBUG, "error QT\n");*/ ++ } ++ for(i=0;i<64;i++) { ++ // Qk: Quantization table element ++ // k is the index in the zigzag ordering of the DCT coeff ++ // JPC only do 8-bit Qk! (ie, Pq shall be 0) ++ if(prec){ ++ p->qt[n][i] = (*pbuf++ << 8) | *pbuf++; ++ } else { ++ p->qt[n][i] = (*pbuf++); ++ } ++ } ++ len -= 64+1; ++ if(prec) { ++ len -= 64; ++ } ++ } ++ break; ++ case 0xdd : ++ // Lr : restart interval segment length (16b) ++ // - specifies the length of the paramenters in the DRI segment ++ pbuf += 2; ++ // Ri : restart interval (16b) ++ // - specifies the number of MCU in the restart interval. ++ nrst = (*pbuf++ << 8) | *pbuf++; ++ break; ++ case 0xe0 :/* All these markers are ignored */ ++ case 0xe1 : ++ case 0xe2 : ++ case 0xe3 : ++ case 0xe4 : ++ case 0xe5 : ++ case 0xe6 : ++ case 0xe7 : ++ case 0xe8 : ++ case 0xe9 : ++ case 0xea : ++ case 0xeb : ++ case 0xec : ++ case 0xed : ++ case 0xee : ++ case 0xef : ++ case 0xf0 : ++ case 0xf1 : ++ case 0xf2 : ++ case 0xf3 : ++ case 0xf4 : ++ case 0xf5 : ++ case 0xf6 : ++ case 0xf7 : ++ case 0xf8 : ++ case 0xf9 : ++ case 0xfa : ++ case 0xfb : ++ case 0xfc : ++ case 0xfd : ++ case 0xfe : ++ v = (*pbuf++ << 8) | *pbuf++; ++ v-=2; ++ pbuf += v; ++ break; ++ default : ++ break; ++ } ++ ++ } ++ ++ for(i = 0; i < 64;) { ++ v = p->min[i++]&1; ++ v <<= 2; ++ v |= p->min[i++]&3; ++ v <<= 3; ++ v |= p->min[i++]&7; ++ min3 = (v>>2) & 0xF; ++ //ijpegd_log(h, C_LOG_DEBUG, fpo,"%x",v>>2); ++ v <<= 4; ++ v |= p->min[i++]&15; ++ v <<= 5; ++ v |= p->min[i++]&31; ++ v <<= 6; ++ v |= p->min[i++]&63; ++ v <<=7; ++ v |= p->min[i++]&127; ++ v <<=8; ++ v |=p->min[i++]&255; ++ min2 = v & 0xFFFFFFFF; ++ //ijpegd_log(h, C_LOG_DEBUG, fpo,"%08x",v); ++ v = p->min[i++]&255; ++ v <<= 8; ++ v |= p->min[i++]&255; ++ v <<= 8; ++ v |= p->min[i++]&255; ++ v <<= 8; ++ v |= p->min[i++]&255; ++ //ijpegd_log(h, C_LOG_DEBUG, fpo,"%08x",v); ++ min1 = v & 0xFFFFFFFF; ++ v = p->min[i++]&255; ++ v <<= 8; ++ v |= p->min[i++]&255; ++ v <<= 8; ++ v |= p->min[i++]&255; ++ v <<= 8; ++ v |= p->min[i++]&255; ++ min0 = v & 0xFFFFFFFF; ++ ++ ++ p->huffmin[i / 4 - 4] = min0; ++ p->huffmin[i / 4 - 3] = min1; ++ p->huffmin[i / 4 - 2] = min2; ++ p->huffmin[i / 4 - 1] = min3; ++ } ++ ++ /* huffbase */ ++ for(i = 0; i < 64; i++) {// hea ++ p->hea[i] = p->hea[i] & 0x1FF; ++ } ++ /* huffsymb */ ++ for(i = 0; i < 336; i++) { ++ p->heb[i] = p->heb[i] & 0xFF; ++ } ++ ++ for(i = 0; i < 4; i++) { ++ p->pxc[i] = (nblk[i] & 0x3) * ((nblk[i] & 0x30) >> 4) - 1; ++ p->pxc[i] = (p->pxc[i] & 0xf) << 4; ++ p->pxc[i] |= qt_sel[i] << 2 | ++ ((ha_sel[i] & 0x1) << 1) | ++ ((hd_sel[i] & 0x1) << 0); ++ } ++ ++ /* TODO: ???*/ ++ ctx->header_size = pbuf - (unsigned char *)bs->va; ++ ++ /*将SOS之后的码流,copy到起始位置,做地址对齐处理,vpu才能够正常解码, 影响性能.*/ ++ memcpy(bs->va, pbuf, bslen - ctx->header_size); ++ ++#if 0 ++ printk("p->width = %d, p->height = %d, ctx->header_size: %d\n", p->width, p->height, ctx->header_size); ++ printk("ncol: %d, nrst: %d\n", ncol, nrst); ++ for(i = 0; i < 4; i++) { ++ printk("nblk[%d]: %x, qt_sel[%d]: %d, hd_sel[%d], %d, ha_sel[%d]:%d\n", i, nblk[i], i, qt_sel[i], i, hd_sel[i], i, ha_sel[i]); ++ } ++ ++ ++ print_hex_dump(KERN_INFO, "bs@start ", DUMP_PREFIX_ADDRESS, 16, 1, bs->va, 64, 1); ++ printk("=====\n"); ++ print_hex_dump(KERN_INFO, "bs@end ", DUMP_PREFIX_ADDRESS, 16, 1, bs->va + bslen - ctx->header_size - 32, 64, 1); ++#endif ++ return 0; ++} ++ ++int jpeg_decoder_decode(struct jpgd_ctx *ctx, struct ingenic_vcodec_mem *bs, struct video_frame_buffer *frame) ++{ ++ int ret = 0; ++ //char *pbuf = NULL; ++ ++ ctx->frame = frame; ++ ctx->bs = bs; ++ ++ ret = jpgd_decode_header(ctx); ++ ++ jpgd_fill_slice_info(ctx); ++ dump_slice_info(ctx->s); ++ ++ JPEGD_SliceInit(ctx->s); ++ ++ ret = ingenic_vpu_start(ctx->priv); ++ if(ret < 0) { ++ return ret; ++ } ++ ++ return ret; ++} ++ ++ ++int jpeg_decoder_set_fmt(struct jpgd_ctx *ctx, int width, int height, int format) ++{ ++ struct jpgd_params *p = &ctx->p; ++ int ret = 0; ++ ++ switch(format) { ++ case HELIX_NV12_MODE: ++ case HELIX_TILE_MODE: ++ p->format = format; ++ break; ++ default: ++ pr_err("Unsupported pix fmt: %x\n", format); ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++ ++int jpeg_decoder_alloc_workbuf(struct jpgd_ctx *ctx) ++{ ++ int ret = 0; ++ ++ ctx->desc = dma_alloc_coherent(NULL, ctx->vdma_chain_len, &ctx->desc_pa, GFP_KERNEL); ++ if(!ctx->desc) { ++ pr_err("Failed to alloc desc memory!\n"); ++ ret = -ENOMEM; ++ goto err_desc; ++ } ++ ++ ++ return ret; ++err_desc: ++ return ret; ++} ++int jpeg_decoder_free_workbuf(struct jpgd_ctx *ctx) ++{ ++ dma_free_coherent(NULL, ctx->vdma_chain_len, ctx->desc, ctx->desc_pa); ++ ++ return 0; ++} ++ ++ ++int jpeg_decoder_init(struct jpgd_ctx *ctx) ++{ ++ struct jpgd_params *p = NULL; ++ _JPEGD_SliceInfo *s = NULL; ++ ++ printk("----%s, %d\n", __func__, __LINE__); ++ ++ s = kzalloc(sizeof(_JPEGD_SliceInfo), GFP_KERNEL); ++ if(!s) { ++ return -ENOMEM; ++ } ++ ++ p = &ctx->p; ++ ctx->s = s; ++ ctx->vdma_chain_len = 40960 + 256; ++ ++ return 0; ++} ++ ++ ++int jpeg_decoder_deinit(struct jpgd_ctx *ctx) ++{ ++ if(!ctx) ++ return 0; ++ ++ ++ return 0; ++} ++ ++void jpeg_decoder_set_priv(struct jpgd_ctx *ctx, void *data) ++{ ++ ctx->priv = data; ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_jpgd.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_jpgd.h.patch new file mode 100644 index 00000000..fe4f827c --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_jpgd.h.patch @@ -0,0 +1,58 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/helix/jpgd.h b/drivers/media/platform/ingenic-vcodec/helix/jpgd.h +--- a/drivers/media/platform/ingenic-vcodec/helix/jpgd.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/helix/jpgd.h 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,54 @@ ++#ifndef __JPGD_H__ ++#define __JPGD_H__ ++ ++ ++#include "api/helix_jpeg_dec.h" ++ ++struct jpgd_params { ++ int hea[64]; ++ int heb[336]; ++ int huffmin[64]; ++ int qt[4][64]; ++ ++ int huffenc[384]; ++ int min[64]; ++ unsigned int pxc[4]; /* component x config */ ++ ++ int width; ++ int height; ++ int format; /*input format?*/ ++}; ++ ++struct jpgd_ctx { ++ int vdma_chain_len; ++ ++ unsigned int *desc; ++ dma_addr_t desc_pa; ++ ++ struct video_frame_buffer *frame; /* raw frame.*/ ++ struct ingenic_vcodec_mem *bs; /* output bs.*/ ++ ++ unsigned int header_size; /*jpg header*/ ++ unsigned int bslen; /*decoder output bslen*/ ++ ++ struct jpgd_params p; ++ _JPEGD_SliceInfo *s; ++ void *priv; ++}; ++ ++ ++extern int jpeg_decoder_decode(struct jpgd_ctx *ctx, struct ingenic_vcodec_mem *bs, struct video_frame_buffer *frame); ++ ++extern int jpeg_decoder_set_fmt(struct jpgd_ctx *ctx, int width, int height, int format); ++ ++extern int jpeg_decoder_alloc_workbuf(struct jpgd_ctx *ctx); ++ ++extern int jpeg_decoder_free_workbuf(struct jpgd_ctx *ctx); ++ ++extern int jpeg_decoder_init(struct jpgd_ctx *ctx); ++ ++extern int jpeg_decoder_deinit(struct jpgd_ctx *ctx); ++ ++extern void jpeg_decoder_set_priv(struct jpgd_ctx *ctx, void *data); ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_jpge.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_jpge.c.patch new file mode 100644 index 00000000..aa8d21a8 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_jpge.c.patch @@ -0,0 +1,336 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/helix/jpge.c b/drivers/media/platform/ingenic-vcodec/helix/jpge.c +--- a/drivers/media/platform/ingenic-vcodec/helix/jpge.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/helix/jpge.c 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,332 @@ ++/* ++* Copyright© 2014 Ingenic Semiconductor Co.,Ltd ++* ++* Author: qipengzhen ++* ++* 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. ++* ++*/ ++ ++ ++#include ++#include ++ ++ ++#include "helix_buf.h" ++ ++#include "jpge.h" ++ ++#include "jpge/ht.h" ++#include "jpge/qt.h" ++#include "jpge/head.h" ++ ++static void dump_slice_info(_JPEGE_SliceInfo *s) ++{ ++ printk("s->des_va: %08x\n", (unsigned int)s->des_va); ++ printk("s->des_pa: %08x\n", s->des_pa); ++ printk("s->ncol: %d\n", s->ncol); ++ printk("s->rsm: %d\n", s->rsm); ++ printk("s->bsa: %08x\n", s->bsa); ++ printk("s->p0a: %08x\n", s->p0a); ++ printk("s->p1a: %08x\n", s->p1a); ++ printk("s->nrsm: %d\n", s->nrsm); ++ printk("s->raw[0]: %08x\n", s->raw[0]); ++ printk("s->raw[1]: %08x\n", s->raw[1]); ++ printk("s->raw[2]: %08x\n", s->raw[2]); ++ printk("s->stride[0]: %d\n", s->stride[0]); ++ printk("s->stride[1]: %d\n", s->stride[1]); ++ printk("s->mb_height: %d\n", s->mb_height); ++ printk("s->mb_width: %d\n", s->mb_width); ++ printk("s->nmcu: %d\n", s->nmcu); ++ printk("s->raw_format: %d(%s)\n", s->raw_format, ++ s->raw_format == 8 ? "NV12" : ++ s->raw_format == 12 ? "NV21" : ++ s->raw_format == 0 ? "TILE(unsupported)" : "invalid"); ++ printk("s->ql_sel: %d(%s)\n", s->ql_sel, ++ s->ql_sel == LOW_QUALITY ? "low_quality": ++ s->ql_sel == MEDIUMS_QUALITY ? "mediums_quality": ++ s->ql_sel == HIGH_QUALITY ? "high_quality" : "invld"); ++ printk("s->huffenc_sel: %d\n", s->huffenc_sel); ++} ++ ++static int jpge_fill_slice_info(struct jpge_ctx *ctx) ++{ ++ struct jpge_params *p = &ctx->p; ++ _JPEGE_SliceInfo *s = ctx->s; ++ int ret = 0; ++ ++ s->des_va = ctx->desc; ++ s->des_pa = ctx->desc_pa; ++ ++ s->ncol = 2; /* unused? */ ++ s->rsm = 0; ++ s->bsa = ctx->bs->pa + ctx->header_size; ++ s->p0a = 0; ++ s->p1a = 0; ++ s->nrsm = 0; ++ ++ s->raw[0] = ctx->frame->fb_addr[0].pa; /*Y*/ ++ s->raw[1] = ctx->frame->fb_addr[1].pa; /*U for 420p or UV for nv12*/ ++ s->raw[2] = ctx->frame->fb_addr[2].pa; /*V for 420p*/ ++ ++ s->stride[0] = s->stride[1] = p->width; ++ ++ s->mb_height = p->height / 16; ++ s->mb_width = p->width / 16; ++ s->nmcu = s->mb_height * s->mb_width - 1; ++ s->raw_format = p->format; ++ s->ql_sel = p->compr_quality; ++ s->huffenc_sel = 0; /*only one huffenc table?*/ ++ ++ return ret; ++} ++ ++static int jpge_gen_header(struct jpge_ctx *ctx) ++{ ++ struct ingenic_vcodec_mem *bs = ctx->bs; ++ struct jpge_params *p = &ctx->p; ++ int ql_sel = p->compr_quality; ++ char *pbuf = bs->va; ++ char *ptr = NULL; ++ int i,j; ++ int header_size; ++ int padsize; ++ ++ /* SOI 文件开始 */ ++ *pbuf++ = 0xff; ++ *pbuf++ = M_SOI; ++ ++ /* DQT -- 0 */ ++ *pbuf++ = 0xff; ++ *pbuf++ = M_DQT; ++ *pbuf++ = 0x0; ++ *pbuf++ = 0x43; ++ *pbuf++ = 0x0; ++ ++ ptr = (char *)&qt[ql_sel][0]; ++ for(i = 0; i < 64; i++) ++ *pbuf++ = *ptr++; ++ ++ /* DQT -- 1*/ ++ *pbuf++ = 0xff; ++ *pbuf++ = M_DQT; ++ *pbuf++ = 0; ++ *pbuf++ = 0x43; ++ *pbuf++ = 0x01; ++ for(i = 0; i < 64; i++) { ++ *pbuf++ = *ptr++; ++ } ++ ++ /* SOF */ ++ *pbuf++ = 0xff; ++ *pbuf++ = M_SOF0; ++ *pbuf++ = 0x0; ++ *pbuf++ = 0x11; //Lf = 17 ++ *pbuf++ = 8; //8bit sample ++ *pbuf++ = (p->height & 0xff00) >> 8; //Y=height ++ *pbuf++ = p->height & 0xff; ++ *pbuf++ = (p->width & 0xff00) >> 8; //X=width ++ *pbuf++ = p->width & 0xff; ++ *pbuf++ = 3; //Nf=3, number of component, Y U V ++ *pbuf++ = 1; //采样系数, Component Y 设置. ++ *pbuf++ = 0x22; //Hori:2 Vertical:2 水平采样系数和垂直采样系数. ++ *pbuf++ = 0x00; //使用量化表0. ++ *pbuf++ = 2; //Component Cb. ++ *pbuf++ = 0x11; //H:1 V:1 ++ *pbuf++ = 0x1; //使用量化表1. ++ *pbuf++ = 3; //Component Cr. ++ *pbuf++ = 0x11; //H:1 V:1 ++ *pbuf++ = 0x1; //使用量化表1. ++ ++ /* DHT -- lumia DC/AC, Chromia DC/AC */ ++ for(j = 0; j < 4; j++) { ++ *pbuf++ = 0xff; ++ *pbuf++ = M_DHT; ++ *pbuf++ = (ht_size[j] & 0xff00) >> 8; //ht_size ++ *pbuf++ = ht_size[j] & 0xff; ++ *pbuf++ = dht_sel[j]; //dht_sel; ? ++ for(i = 0; i < 16; i++) { ++ *pbuf++ = ht_len[j][i]; ++ } ++ ++ for(i = 0; i < 16; i++) { ++ int m; ++ for(m = 0; m < ht_len[j][i]; m++) { ++ *pbuf++ = ht_val[j][i][m]; ++ } ++ } ++ } ++ ++ ++ /*添加0xff,填充header到256字节对齐. 已知SOS 段14字节*/ ++ header_size = pbuf - (char *)bs->va + 14; ++ padsize = 256 - header_size % 256; ++ ++ memset(pbuf, 0xff, padsize); ++ pbuf += padsize; ++ ++ //header_size = (header_size + 255) / 256 * 256; // align to 256; ++ ++ /* SOS */ ++ *pbuf++ = 0xff; ++ *pbuf++ = M_SOS; ++ //Ls = 12 ++ *pbuf++ = 0x0; ++ *pbuf++ = 0xC; ++ //Ns ++ *pbuf++ = 0x3; ++ //Cs1 - Y ++ *pbuf++ = 0x1; ++ //Td, Ta ++ *pbuf++ = 0x00; ++ //Cs2 - U ++ *pbuf++ = 0x2; ++ //Td, Ta ++ *pbuf++ = 0x11; ++ //Cs3 - V ++ *pbuf++ = 0x3; ++ //Td, Ta ++ *pbuf++ = 0x11; ++ //Ss ++ *pbuf++ = 0x00; ++ //Se ++ *pbuf++ = 0x3f; ++ //Ah, Al ++ *pbuf++ = 0x0; ++ ++ ctx->header_size = pbuf - (char *)bs->va; ++ return 0; ++} ++ ++int jpeg_encoder_encode(struct jpge_ctx *ctx, struct video_frame_buffer *frame, struct ingenic_vcodec_mem *bs) ++{ ++ int ret = 0; ++ char *pbuf = NULL; ++ ++ ctx->frame = frame; ++ ctx->bs = bs; ++ printk("-----%s, %d\n", __func__, __LINE__); ++ ++ ret = jpge_gen_header(ctx); ++ ++ jpge_fill_slice_info(ctx); ++ dump_slice_info(ctx->s); ++ ++ JPEGE_SliceInit(ctx->s); ++ ++ ret = ingenic_vpu_start(ctx->priv); ++ if(ret < 0) { ++ return ret; ++ } ++ ++ /* Modify bslen. ++ total bslen = header_size + vpu encoded bslen. ++ */ ++ printk("---%s, %d, vpu bslen: %d\n", __func__, __LINE__, ctx->bslen); ++ ctx->bslen = ctx->header_size + ctx->bslen; ++ ++ pbuf = bs->va + ctx->bslen; ++ /* EOI */ ++ *pbuf++ = 0xff; ++ *pbuf++ = 0xd9; ++ ++ ctx->bslen += 2; ++ ++ return ret; ++} ++ ++ ++int jpeg_encoder_set_fmt(struct jpge_ctx *ctx, int width, int height, int format) ++{ ++ struct jpge_params *p = &ctx->p; ++ int ret = 0; ++ ++ p->width = width; ++ p->height = height; ++ ++ switch(format) { ++ case HELIX_NV12_MODE: ++ case HELIX_NV21_MODE: ++ p->format = format; ++ break; ++ default: ++ pr_err("Unsupported pix fmt: %x\n", format); ++ ret = -EINVAL; ++ break; ++ } ++ ++ printk("-----%s, %d\n", __func__, __LINE__); ++ ++ return ret; ++} ++ ++ ++int jpeg_encoder_alloc_workbuf(struct jpge_ctx *ctx) ++{ ++ int ret = 0; ++ ++ ctx->desc = dma_alloc_coherent(NULL, ctx->vdma_chain_len, &ctx->desc_pa, GFP_KERNEL); ++ if(!ctx->desc) { ++ pr_err("Failed to alloc desc memory!\n"); ++ ret = -ENOMEM; ++ goto err_desc; ++ } ++ ++ ++ return ret; ++err_desc: ++ return ret; ++} ++ ++int jpeg_encoder_free_workbuf(struct jpge_ctx *ctx) ++{ ++ dma_free_coherent(NULL, ctx->vdma_chain_len, ctx->desc, ctx->desc_pa); ++ ++ return 0; ++} ++ ++ ++int jpeg_encoder_init(struct jpge_ctx *ctx) ++{ ++ struct jpge_params *p = NULL; ++ _JPEGE_SliceInfo *s = NULL; ++ ++ printk("----%s, %d\n", __func__, __LINE__); ++ ++ s = kzalloc(sizeof(_JPEGE_SliceInfo), GFP_KERNEL); ++ if(!s) { ++ return -ENOMEM; ++ } ++ ++ p = &ctx->p; ++ ctx->s = s; ++ ctx->vdma_chain_len = 40960 + 256; ++ ++ p->compr_quality = MEDIUMS_QUALITY; ++ ++ ++ ++ return 0; ++} ++ ++ ++int jpeg_encoder_deinit(struct jpge_ctx *ctx) ++{ ++ if(!ctx) ++ return 0; ++ ++ ++ return 0; ++} ++ ++void jpeg_encoder_set_priv(struct jpge_ctx *ctx, void *data) ++{ ++ ctx->priv = data; ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_jpge.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_jpge.h.patch new file mode 100644 index 00000000..5151d756 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_jpge.h.patch @@ -0,0 +1,50 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/helix/jpge.h b/drivers/media/platform/ingenic-vcodec/helix/jpge.h +--- a/drivers/media/platform/ingenic-vcodec/helix/jpge.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/helix/jpge.h 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,46 @@ ++#ifndef __JPGE_H__ ++#define __JPGE_H__ ++ ++#include "api/helix_jpeg_enc.h" ++ ++struct jpge_params { ++ int compr_quality; ++ ++ int width; ++ int height; ++ int format; /*input format?*/ ++}; ++ ++struct jpge_ctx { ++ int vdma_chain_len; ++ ++ unsigned int *desc; ++ dma_addr_t desc_pa; ++ ++ struct video_frame_buffer *frame; /* raw frame.*/ ++ struct ingenic_vcodec_mem *bs; /* output bs.*/ ++ ++ unsigned int header_size; /*jpg header*/ ++ unsigned int bslen; /*encoder output bslen*/ ++ ++ struct jpge_params p; ++ _JPEGE_SliceInfo *s; ++ void *priv; ++}; ++ ++ ++extern int jpeg_encoder_encode(struct jpge_ctx *ctx, struct video_frame_buffer *frame, struct ingenic_vcodec_mem *bs); ++ ++extern int jpeg_encoder_set_fmt(struct jpge_ctx *ctx, int width, int height, int format); ++ ++extern int jpeg_encoder_alloc_workbuf(struct jpge_ctx *ctx); ++ ++extern int jpeg_encoder_free_workbuf(struct jpge_ctx *ctx); ++ ++extern int jpeg_encoder_init(struct jpge_ctx *ctx); ++ ++extern int jpeg_encoder_deinit(struct jpge_ctx *ctx); ++ ++extern void jpeg_encoder_set_priv(struct jpge_ctx *ctx, void *data); ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_jpge_head.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_jpge_head.h.patch new file mode 100644 index 00000000..1acf3be1 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_jpge_head.h.patch @@ -0,0 +1,76 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/helix/jpge/head.h b/drivers/media/platform/ingenic-vcodec/helix/jpge/head.h +--- a/drivers/media/platform/ingenic-vcodec/helix/jpge/head.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/helix/jpge/head.h 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,72 @@ ++#ifndef __HEAD_H__ ++#define __HEAD_H__ ++ ++char dht_sel[] = {0x00, 0x10, 0x01, 0x11}; ++ ++typedef enum { /* JPEG marker codes */ ++ M_SOF0 = 0xc0, ++ M_SOF1 = 0xc1, ++ M_SOF2 = 0xc2, ++ M_SOF3 = 0xc3, ++ ++ M_SOF5 = 0xc5, ++ M_SOF6 = 0xc6, ++ M_SOF7 = 0xc7, ++ ++ M_JPG = 0xc8, ++ M_SOF9 = 0xc9, ++ M_SOF10 = 0xca, ++ M_SOF11 = 0xcb, ++ ++ M_SOF13 = 0xcd, ++ M_SOF14 = 0xce, ++ M_SOF15 = 0xcf, ++ ++ M_DHT = 0xc4, ++ ++ M_DAC = 0xcc, ++ ++ M_RST0 = 0xd0, ++ M_RST1 = 0xd1, ++ M_RST2 = 0xd2, ++ M_RST3 = 0xd3, ++ M_RST4 = 0xd4, ++ M_RST5 = 0xd5, ++ M_RST6 = 0xd6, ++ M_RST7 = 0xd7, ++ ++ M_SOI = 0xd8, ++ M_EOI = 0xd9, ++ M_SOS = 0xda, ++ M_DQT = 0xdb, ++ M_DNL = 0xdc, ++ M_DRI = 0xdd, ++ M_DHP = 0xde, ++ M_EXP = 0xdf, ++ ++ M_APP0 = 0xe0, ++ M_APP1 = 0xe1, ++ M_APP2 = 0xe2, ++ M_APP3 = 0xe3, ++ M_APP4 = 0xe4, ++ M_APP5 = 0xe5, ++ M_APP6 = 0xe6, ++ M_APP7 = 0xe7, ++ M_APP8 = 0xe8, ++ M_APP9 = 0xe9, ++ M_APP10 = 0xea, ++ M_APP11 = 0xeb, ++ M_APP12 = 0xec, ++ M_APP13 = 0xed, ++ M_APP14 = 0xee, ++ M_APP15 = 0xef, ++ ++ M_JPG0 = 0xf0, ++ M_JPG13 = 0xfd, ++ M_COM = 0xfe, ++ ++ M_TEM = 0x01, ++ ++ M_ERROR = 0x100 ++} JPEG_MARKER; ++#endif /* __HEAD_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_jpge_ht.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_jpge_ht.h.patch new file mode 100644 index 00000000..d2dc8ee3 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_jpge_ht.h.patch @@ -0,0 +1,94 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/helix/jpge/ht.h b/drivers/media/platform/ingenic-vcodec/helix/jpge/ht.h +--- a/drivers/media/platform/ingenic-vcodec/helix/jpge/ht.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/helix/jpge/ht.h 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,90 @@ ++#ifndef __HT_H__ ++#define __HT_H__ ++unsigned int ht_size[4] = {31, 181, 31, 181, }; ++ ++unsigned char ht_len[4][16] = { ++ {0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, }, ++ {0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 125, }, ++ {0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, }, ++ {0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 119, }, ++}; ++ ++unsigned char ht_val[4][16][256] = { ++ { {0}, ++ {0x00, }, ++ {0x01, 0x02, 0x03, 0x04, 0x05, }, ++ {0x06, }, ++ {0x07, }, ++ {0x08, }, ++ {0x09, }, ++ {0x0a, }, ++ {0x0b, }, ++ {0}, ++ {0}, ++ {0}, ++ {0}, ++ {0}, ++ {0}, ++ {0}, ++ }, ++ { {0}, ++ {0x01, 0x02, }, ++ {0x03, }, ++ {0x00, 0x04, 0x11, }, ++ {0x05, 0x12, 0x21, }, ++ {0x31, 0x41, }, ++ {0x06, 0x13, 0x51, 0x61, }, ++ {0x07, 0x22, 0x71, }, ++ {0x14, 0x32, 0x81, 0x91, 0xa1, }, ++ {0x08, 0x23, 0x42, 0xb1, 0xc1, }, ++ {0x15, 0x52, 0xd1, 0xf0, }, ++ {0x24, 0x33, 0x62, 0x72, }, ++ {0}, ++ {0}, ++ {0x82, }, ++ {0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, ++ 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, ++ 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, ++ 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, ++ 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, }, ++ }, ++ { {0}, ++ {0x00, 0x01, 0x02, }, ++ {0x03, }, ++ {0x04, }, ++ {0x05, }, ++ {0x06, }, ++ {0x07, }, ++ {0x08, }, ++ {0x09, }, ++ {0x0a, }, ++ {0x0b, }, ++ {0}, ++ {0}, ++ {0}, ++ {0}, ++ {0}, ++ }, ++ { {0}, ++ {0x00, 0x01, }, ++ {0x02, }, ++ {0x03, 0x11, }, ++ {0x04, 0x05, 0x21, 0x31, }, ++ {0x06, 0x12, 0x41, 0x51, }, ++ {0x07, 0x61, 0x71, }, ++ {0x13, 0x22, 0x32, 0x81, }, ++ {0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, }, ++ {0x09, 0x23, 0x33, 0x52, 0xf0, }, ++ {0x15, 0x62, 0x72, 0xd1, }, ++ {0x0a, 0x16, 0x24, 0x34, }, ++ {0}, ++ {0xe1, }, ++ {0x25, 0xf1, }, ++ {0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, ++ 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, ++ 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, ++ 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, ++ 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, }, ++ }, ++}; ++#endif /* __HT_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_jpge_qt.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_jpge_qt.h.patch new file mode 100644 index 00000000..f65c1b30 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_ingenic-vcodec_helix_jpge_qt.h.patch @@ -0,0 +1,62 @@ +diff -drupN a/drivers/media/platform/ingenic-vcodec/helix/jpge/qt.h b/drivers/media/platform/ingenic-vcodec/helix/jpge/qt.h +--- a/drivers/media/platform/ingenic-vcodec/helix/jpge/qt.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/ingenic-vcodec/helix/jpge/qt.h 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,58 @@ ++unsigned char qt[3][128] = { ++ { ++ 0x08,0x06,0x06,0x07,0x06,0x05,0x08,0x07, ++ 0x07,0x07,0x09,0x09,0x08,0x0a,0x0c,0x14, ++ 0x0d,0x0c,0x0b,0x0b,0x0c,0x19,0x12,0x13, ++ 0x0f,0x14,0x1d,0x1a,0x1f,0x1e,0x1d,0x1a, ++ 0x1c,0x1c,0x20,0x24,0x2e,0x27,0x20,0x22, ++ 0x2c,0x23,0x1c,0x1c,0x28,0x37,0x29,0x2c, ++ 0x30,0x31,0x34,0x34,0x34,0x1f,0x27,0x39, ++ 0x3d,0x38,0x32,0x3c,0x2e,0x33,0x34,0x32, ++ 0x09,0x09,0x09,0x0c,0x0b,0x0c,0x18,0x0d, ++ 0x0d,0x18,0x32,0x21,0x1c,0x21,0x32,0x32, ++ 0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32, ++ 0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32, ++ 0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32, ++ 0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32, ++ 0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32, ++ 0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32, ++ }, ++ ++ { ++ 0x06, 0x04, 0x04, 0x05, 0x04, 0x04, 0x06, 0x05, ++ 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x08, 0x0d, ++ 0x09, 0x08, 0x07, 0x07, 0x08, 0x0f, 0x0b, 0x0c, ++ 0x09, 0x0d, 0x12, 0x10, 0x13, 0x13, 0x12, 0x10, ++ 0x12, 0x11, 0x14, 0x16, 0x1c, 0x18, 0x14, 0x15, ++ 0x1b, 0x15, 0x11, 0x12, 0x19, 0x21, 0x19, 0x1b, ++ 0x1d, 0x1e, 0x20, 0x20, 0x20, 0x13, 0x18, 0x23, ++ 0x25, 0x22, 0x1f, 0x25, 0x1c, 0x1f, 0x20, 0x1e, ++ 0x06, 0x06, 0x06, 0x08, 0x07, 0x08, 0x0f, 0x09, ++ 0x09, 0x0f, 0x1e, 0x15, 0x12, 0x15, 0x1e, 0x1e, ++ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, ++ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, ++ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, ++ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, ++ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, ++ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, ++ }, ++ ++ { ++ 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x02, ++ 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x05, ++ 0x04, 0x03, 0x03, 0x03, 0x03, 0x06, 0x04, 0x05, ++ 0x04, 0x05, 0x07, 0x06, 0x07, 0x07, 0x07, 0x06, ++ 0x07, 0x06, 0x07, 0x08, 0x0a, 0x09, 0x07, 0x08, ++ 0x0a, 0x08, 0x06, 0x07, 0x09, 0x0c, 0x09, 0x0a, ++ 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x07, 0x09, 0x0c, ++ 0x0d, 0x0c, 0x0b, 0x0d, 0x0a, 0x0b, 0x0b, 0x0b, ++ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x06, 0x04, ++ 0x04, 0x06, 0x0b, 0x08, 0x07, 0x08, 0x0b, 0x0b, ++ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, ++ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, ++ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, ++ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, ++ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, ++ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, ++ } ++}; diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_Kconfig.patch new file mode 100644 index 00000000..53674040 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_Kconfig.patch @@ -0,0 +1,8 @@ +diff -drupN a/drivers/media/platform/soc_camera/Kconfig b/drivers/media/platform/soc_camera/Kconfig +--- a/drivers/media/platform/soc_camera/Kconfig 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/media/platform/soc_camera/Kconfig 2022-06-09 05:02:29.000000000 +0300 +@@ -89,3 +89,4 @@ config VIDEO_ATMEL_ISI + This module makes the ATMEL Image Sensor Interface available + as a v4l2 device. + ++source "drivers/media/platform/soc_camera/ingenic/Kconfig" diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_Makefile.patch new file mode 100644 index 00000000..ad9ec147 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_Makefile.patch @@ -0,0 +1,8 @@ +diff -drupN a/drivers/media/platform/soc_camera/Makefile b/drivers/media/platform/soc_camera/Makefile +--- a/drivers/media/platform/soc_camera/Makefile 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/media/platform/soc_camera/Makefile 2022-06-09 05:02:29.000000000 +0300 +@@ -14,3 +14,4 @@ obj-$(CONFIG_VIDEO_PXA27x) += pxa_camer + obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o + obj-$(CONFIG_VIDEO_SH_MOBILE_CSI2) += sh_mobile_csi2.o + obj-$(CONFIG_VIDEO_RCAR_VIN) += rcar_vin.o ++obj-$(CONFIG_VIDEO_INGENIC) += ingenic/ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_Kconfig.patch new file mode 100644 index 00000000..ad187a88 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_Kconfig.patch @@ -0,0 +1,16 @@ +diff -drupN a/drivers/media/platform/soc_camera/ingenic/Kconfig b/drivers/media/platform/soc_camera/ingenic/Kconfig +--- a/drivers/media/platform/soc_camera/ingenic/Kconfig 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/soc_camera/ingenic/Kconfig 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,12 @@ ++config VIDEO_INGENIC ++ tristate "Ingenic Camera Sensor Interface driver" ++ depends on VIDEO_DEV && SOC_CAMERA ++ depends on HAS_DMA ++ select VIDEOBUF2_DMA_CONTIG ++ ---help--- ++ This is a v4l2 driver for the ingenic Camera Sensor Interface ++ ++if VIDEO_INGENIC ++source "drivers/media/platform/soc_camera/ingenic/x1000/Kconfig" ++source "drivers/media/platform/soc_camera/ingenic/x2000/Kconfig" ++endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_Makefile.patch new file mode 100644 index 00000000..7ae7624e --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_Makefile.patch @@ -0,0 +1,6 @@ +diff -drupN a/drivers/media/platform/soc_camera/ingenic/Makefile b/drivers/media/platform/soc_camera/ingenic/Makefile +--- a/drivers/media/platform/soc_camera/ingenic/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/soc_camera/ingenic/Makefile 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,2 @@ ++obj-$(CONFIG_VIDEO_INGENIC_X1000) += x1000/ ++obj-$(CONFIG_VIDEO_INGENIC_X2000) += x2000/ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_x1000_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_x1000_Kconfig.patch new file mode 100644 index 00000000..1d808326 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_x1000_Kconfig.patch @@ -0,0 +1,10 @@ +diff -drupN a/drivers/media/platform/soc_camera/ingenic/x1000/Kconfig b/drivers/media/platform/soc_camera/ingenic/x1000/Kconfig +--- a/drivers/media/platform/soc_camera/ingenic/x1000/Kconfig 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/soc_camera/ingenic/x1000/Kconfig 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,6 @@ ++config VIDEO_INGENIC_X1000 ++ tristate "Ingenic Soc camera Driver for X1000" ++ depends on VIDEO_INGENIC ++ help ++ CIM Driver for X1000 ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_x1000_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_x1000_Makefile.patch new file mode 100644 index 00000000..53f9c348 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_x1000_Makefile.patch @@ -0,0 +1,6 @@ +diff -drupN a/drivers/media/platform/soc_camera/ingenic/x1000/Makefile b/drivers/media/platform/soc_camera/ingenic/x1000/Makefile +--- a/drivers/media/platform/soc_camera/ingenic/x1000/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/soc_camera/ingenic/x1000/Makefile 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,2 @@ ++obj-y += ingenic_camera.o ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_x1000_ingenic_camera.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_x1000_ingenic_camera.c.patch new file mode 100644 index 00000000..4976098d --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_x1000_ingenic_camera.c.patch @@ -0,0 +1,1115 @@ +diff -drupN a/drivers/media/platform/soc_camera/ingenic/x1000/ingenic_camera.c b/drivers/media/platform/soc_camera/ingenic/x1000/ingenic_camera.c +--- a/drivers/media/platform/soc_camera/ingenic/x1000/ingenic_camera.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/soc_camera/ingenic/x1000/ingenic_camera.c 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,1111 @@ ++/* ++ * V4L2 Driver for Ingenic camera (CIM) host ++ * ++ * Copyright (C) 2014, Ingenic Semiconductor Inc. ++ * ++ * 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 support Continuous physical address mapping, ++ * not support sg mode now. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "ingenic_camera.h" ++ ++ ++//#define CIM_DUMP_DESC ++//#define CIM_DUMP_REG ++//#define CIM_DEBUG_FPS ++ ++#ifdef CIM_DUMP_REG ++static void cim_dump_reg(struct ingenic_camera_dev *pcdev) ++{ ++ if(pcdev == NULL) { ++ printk("===>>%s,%d pcdev is NULL!\n",__func__,__LINE__); ++ return; ++ } ++#define STRING "\t=\t0x%08x\n" ++ printk("REG_CIM_CFG" STRING, readl(pcdev->base + CIM_CFG)); ++ printk("REG_CIM_CTRL" STRING, readl(pcdev->base + CIM_CTRL)); ++ printk("REG_CIM_CTRL2" STRING, readl(pcdev->base + CIM_CTRL2)); ++ printk("REG_CIM_STATE" STRING, readl(pcdev->base + CIM_STATE)); ++ ++ printk("REG_CIM_IMR" STRING, readl(pcdev->base + CIM_IMR)); ++ printk("REG_CIM_IID" STRING, readl(pcdev->base + CIM_IID)); ++ printk("REG_CIM_DA" STRING, readl(pcdev->base + CIM_DA)); ++ printk("REG_CIM_FA" STRING, readl(pcdev->base + CIM_FA)); ++ ++ printk("REG_CIM_FID" STRING, readl(pcdev->base + CIM_FID)); ++ printk("REG_CIM_CMD" STRING, readl(pcdev->base + CIM_CMD)); ++ printk("REG_CIM_WSIZE" STRING, readl(pcdev->base + CIM_SIZE)); ++ printk("REG_CIM_WOFFSET" STRING, readl(pcdev->base + CIM_OFFSET)); ++ ++ printk("REG_CIM_FS" STRING, readl(pcdev->base + CIM_FS)); ++} ++#endif ++ ++static int ingenic_camera_querycap(struct soc_camera_host *ici, struct v4l2_capability *cap) ++{ ++ strlcpy(cap->card, "ingenic-Camera", sizeof(cap->card)); ++ cap->version = VERSION_CODE; ++ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; ++ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; ++ ++ return 0; ++} ++ ++static unsigned int ingenic_camera_poll(struct file *file, poll_table *pt) ++{ ++ struct soc_camera_device *icd = file->private_data; ++ ++ return vb2_poll(&icd->vb2_vidq, file, pt); ++} ++ ++static int ingenic_dma_alloc_desc(struct ingenic_camera_dev *pcdev, int count) ++{ ++ struct ingenic_camera_dma_desc *dma_desc_paddr; ++ struct ingenic_camera_dma_desc *dma_desc; ++ ++ pcdev->buf_cnt = count; ++ pcdev->desc_vaddr = dma_alloc_coherent(pcdev->soc_host.v4l2_dev.dev, ++ sizeof(*pcdev->dma_desc) * pcdev->buf_cnt, ++ (dma_addr_t *)&pcdev->dma_desc, GFP_KERNEL); ++ ++ dma_desc_paddr = (struct ingenic_camera_dma_desc *) pcdev->dma_desc; ++ dma_desc = (struct ingenic_camera_dma_desc *) pcdev->desc_vaddr; ++ ++ if (!pcdev->dma_desc) ++ return -ENOMEM; ++ ++ ++#ifdef CIM_DUMP_DESC ++ int i = 0; ++ printk("pcdev->desc_vaddr = 0x%p, pcdev->dma_desc = 0x%p\n",pcdev->desc_vaddr, (dma_addr_t *)pcdev->dma_desc); ++ for(i = 0; i < pcdev->buf_cnt; i++){ ++ printk("pcdev->desc_vaddr[%d] = 0x%p\n", i, &dma_desc[i]); ++ } ++ for(i = 0; i < pcdev->buf_cnt; i++){ ++ printk("dma_desc_paddr[%d] = 0x%p\n", i, &dma_desc_paddr[i]); ++ } ++#endif ++ ++ return 0; ++} ++static void ingenic_dma_free_desc(struct ingenic_camera_dev *pcdev) ++{ ++ if(pcdev && pcdev->desc_vaddr) { ++ dma_free_coherent(pcdev->soc_host.v4l2_dev.dev, ++ sizeof(*pcdev->dma_desc) * pcdev->buf_cnt, ++ pcdev->desc_vaddr, (dma_addr_t )pcdev->dma_desc); ++ ++ pcdev->desc_vaddr = NULL; ++ } ++} ++ ++static void dump_dma_desc(struct ingenic_camera_dev *pcdev) ++{ ++#ifdef CIM_DUMP_DESC ++ struct ingenic_camera_dma_desc *dma_desc; ++ int nr; ++ int i; ++ dma_desc = (struct ingenic_camera_dma_desc *) pcdev->desc_vaddr; ++ nr = pcdev->buf_cnt; ++ ++ printk("=============> dma_desc: %x\n", dma_desc); ++ ++ for(i = 0; i < nr; i++) { ++ printk("dma_desc[%d].next: %08x\n", i, dma_desc[i].next); ++ printk("dma_desc[%d].id: %08x\n", i, dma_desc[i].id); ++ printk("dma_desc[%d].buf: %08x\n", i, dma_desc[i].buf); ++ printk("dma_desc[%d].cmd: %08x\n", i, dma_desc[i].cmd); ++ printk("dma_desc[%d].cb_frame: %08x\n", i, dma_desc[i].cb_frame); ++ printk("dma_desc[%d].cb_len: %08x\n", i, dma_desc[i].cb_len); ++ printk("dma_desc[%d].cr_frame: %08x\n", i, dma_desc[i].cr_frame); ++ printk("dma_desc[%d].cr_len: %08x\n", i, dma_desc[i].cr_len); ++ ++ } ++#endif ++} ++static void ingenic_dma_start(struct ingenic_camera_dev *pcdev) ++{ ++ unsigned long temp = 0; ++ unsigned int regval; ++ ++ /* please enable dma first, enable cim ctrl later. ++ * if enable cim ctrl first, RXFIFO can easily overflow. ++ */ ++ regval = (unsigned int)(pcdev->dma_desc); ++ writel(regval, pcdev->base + CIM_DA); ++ ++ writel(0, pcdev->base + CIM_STATE); ++ ++ /*enable dma*/ ++ temp = readl(pcdev->base + CIM_CTRL); ++ temp |= CIM_CTRL_DMA_EN; ++ writel(temp, pcdev->base + CIM_CTRL); ++ ++ /* clear rx fifo */ ++ temp = readl(pcdev->base + CIM_CTRL); ++ temp |= CIM_CTRL_RXF_RST; ++ writel(temp, pcdev->base + CIM_CTRL); ++ ++ temp = readl(pcdev->base + CIM_CTRL); ++ temp &= ~(CIM_CTRL_RXF_RST); ++ writel(temp, pcdev->base + CIM_CTRL); ++ ++ /* enable cim */ ++ temp = readl(pcdev->base + CIM_CTRL); ++ temp |= CIM_CTRL_ENA; ++ writel(temp, pcdev->base + CIM_CTRL); ++} ++ ++static void ingenic_dma_stop(struct ingenic_camera_dev *pcdev) ++{ ++ unsigned long temp = 0; ++ ++ /* unmask all interrupts. */ ++ writel(0xffffffff, pcdev->base + CIM_IMR); ++ ++ /* clear rx fifo */ ++ temp = readl(pcdev->base + CIM_CTRL); ++ temp |= CIM_CTRL_RXF_RST | CIM_CTRL_CIM_RST; ++ writel(temp, pcdev->base + CIM_CTRL); ++ ++ writel(0, pcdev->base + CIM_STATE); ++ ++ /* disable dma & cim */ ++ temp = readl(pcdev->base + CIM_CTRL); ++ temp &= ~(CIM_CTRL_ENA | CIM_CTRL_DMA_EN); ++ writel(temp, pcdev->base + CIM_CTRL); ++} ++ ++ ++static int ingenic_videobuf_setup(struct vb2_queue *q, const void *parg, ++ unsigned int *num_buffers, unsigned int *num_planes, ++ unsigned int sizes[], void *alloc_ctxs[]) ++{ ++ struct soc_camera_device *icd = soc_camera_from_vb2q(q); ++ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); ++ struct ingenic_camera_dev *pcdev = ici->priv; ++ unsigned long size; ++ ++ size = icd->sizeimage; ++ ++ if (!*num_buffers || *num_buffers > MAX_BUFFER_NUM) ++ *num_buffers = MAX_BUFFER_NUM; ++ ++ if (size * *num_buffers > MAX_VIDEO_MEM) ++ *num_buffers = MAX_VIDEO_MEM / size; ++ ++ *num_planes = 1; ++ sizes[0] = size; ++ alloc_ctxs[0] = pcdev->alloc_ctx; ++ ++ ++ pcdev->start_streaming_called = 0; ++ pcdev->sequence = 0; ++ ++ if(ingenic_dma_alloc_desc(pcdev, *num_buffers)) ++ return -ENOMEM; ++ ++ dev_dbg(icd->parent, "%s, count=%d, size=%ld\n", __func__, ++ *num_buffers, size); ++ ++ return 0; ++} ++ ++ ++static int ingenic_init_dma(struct vb2_buffer *vb) ++{ ++ struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); ++ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); ++ struct ingenic_camera_dev *pcdev = ici->priv; ++ struct ingenic_camera_dma_desc *dma_desc; ++ dma_addr_t dma_address; ++ ++ dma_desc = (struct ingenic_camera_dma_desc *) pcdev->desc_vaddr; ++ ++ dma_address = *(dma_addr_t *)vb2_plane_cookie(vb, 0); ++ if(!dma_address) { ++ dev_err(icd->parent, "Failed to setup DMA address\n"); ++ return -ENOMEM; ++ } ++ ++ dma_desc[vb->index].id = vb->index; ++ ++ dma_desc[vb->index].buf = dma_address; ++ ++ dma_desc[vb->index].cmd = icd->sizeimage >> 2 | CIM_CMD_EOFINT | CIM_CMD_OFRCV; ++ ++ if(vb->index == 0) { ++ pcdev->dma_desc_head = (struct ingenic_camera_dma_desc *)(pcdev->desc_vaddr); ++ } ++ ++ if(vb->index == (pcdev->buf_cnt - 1)) { ++ dma_desc[vb->index].next = (dma_addr_t) (pcdev->dma_desc); ++ dma_desc[vb->index].cmd |= CIM_CMD_STOP; ++ ++ pcdev->dma_desc_tail = (struct ingenic_camera_dma_desc *)(&dma_desc[vb->index]); ++ } else { ++ dma_desc[vb->index].next = (dma_addr_t) (&pcdev->dma_desc[vb->index + 1]); ++ } ++ ++ return 0; ++} ++ ++ ++static int ingenic_videobuf_init(struct vb2_buffer *vb) ++{ ++ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); ++ struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); ++ struct ingenic_buffer *buf = container_of(vbuf, struct ingenic_buffer, vb); ++ int ret; ++ ++ ret = ingenic_init_dma(vb); ++ if(ret) { ++ dev_err(icd->parent,"%s:DMA initialization for Y/RGB failed\n", __func__); ++ return ret; ++ } ++ INIT_LIST_HEAD(&buf->queue); ++ ++ return 0; ++} ++ ++static int ingenic_videobuf_prepare(struct vb2_buffer *vb) ++{ ++ struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); ++ int ret = 0; ++ ++ dev_vdbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, ++ vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); ++ ++ vb2_set_plane_payload(vb, 0, icd->sizeimage); ++ if (vb2_plane_vaddr(vb, 0) && ++ vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) { ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ return 0; ++ ++out: ++ return ret; ++} ++ ++static void ingenic_videobuf_queue(struct vb2_buffer *vb) ++{ ++ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); ++ struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); ++ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); ++ ++ struct ingenic_camera_dev *pcdev = ici->priv; ++ struct ingenic_buffer *buf = container_of(vbuf, struct ingenic_buffer, vb); ++ unsigned long flags; ++ unsigned int regval = 0; ++ struct ingenic_camera_dma_desc *dma_desc_vaddr; ++ struct ingenic_camera_dma_desc *dma_desc_paddr; ++ ++ dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, ++ vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); ++ ++ spin_lock_irqsave(&pcdev->lock, flags); ++ ++ list_add_tail(&buf->queue, &pcdev->capture); ++ ++ if(pcdev->active == NULL) { ++ pcdev->active = buf; /* to be transfered buffer. */ ++ } ++ ++ ++ if(!pcdev->start_streaming_called) { ++ goto out; ++ } ++ ++ /* judged vb->i */ ++ if((vb->index > pcdev->buf_cnt) || (vb->index < 0)) { ++ dev_dbg(icd->parent, "Warning: %s, %d, vb->i > pcdev->buf_cnt || vb->i < 0, please check vb->i !!!\n", ++ __func__, vb->index); ++ goto out; ++ } ++ ++ ++ dma_desc_vaddr = (struct ingenic_camera_dma_desc *) pcdev->desc_vaddr; ++ ++ if(pcdev->dma_desc_head != pcdev->dma_desc_tail) { /* Dynamic add dma desc */ ++ dma_desc_vaddr[vb->index].cmd |= CIM_CMD_STOP; ++ ++ pcdev->dma_desc_tail->next = (dma_addr_t) (&pcdev->dma_desc[vb->index]); ++ pcdev->dma_desc_tail->cmd &= (~CIM_CMD_STOP); /* unlink link last dma desc */ ++ ++ pcdev->dma_desc_tail = (struct ingenic_camera_dma_desc *)(&dma_desc_vaddr[vb->index]); /* update newly tail */ ++ } else { ++ if(pcdev->dma_stopped) { ++ /* dma stoped could happen when all buffers are dequeued by user app. ++ * 1. set CIM_CMD_STOP for current vb. ++ * 2. and reconfigure CIM_DA, to start a new dma transfer. ++ * BUGs: ++ * cim will keep drop one frame when userspace failed to queue buffer in time. ++ * */ ++ dma_desc_vaddr[vb->index].cmd |= CIM_CMD_STOP; ++ ++ pcdev->dma_desc_head = (struct ingenic_camera_dma_desc *)(&dma_desc_vaddr[vb->index]); ++ pcdev->dma_desc_tail = (struct ingenic_camera_dma_desc *)(&dma_desc_vaddr[vb->index]); ++ ++ dma_desc_paddr = (struct ingenic_camera_dma_desc *) pcdev->dma_desc; ++ ++ /* Configure register CIMDA */ ++ regval = (unsigned int) (&dma_desc_paddr[vb->index]); ++ writel(regval, pcdev->base + CIM_DA); ++ ++ pcdev->dma_stopped = 0; ++ ++ } else { ++ ++ dma_desc_vaddr[vb->index].cmd |= CIM_CMD_STOP; ++ ++ pcdev->dma_desc_tail->next = (dma_addr_t) (&pcdev->dma_desc[vb->index]); ++ pcdev->dma_desc_tail->cmd &= (~CIM_CMD_STOP); ++ ++ pcdev->dma_desc_tail = (struct ingenic_camera_dma_desc *)(&dma_desc_vaddr[vb->index]); ++ } ++ } ++ ++out: ++ spin_unlock_irqrestore(&pcdev->lock, flags); ++ return; ++} ++ ++static int test_platform_param(struct ingenic_camera_dev *pcdev, ++ unsigned char buswidth, unsigned long *flags) ++{ ++ /* ++ * Platform specified synchronization and pixel clock polarities are ++ * only a recommendation and are only used during probing. The PXA270 ++ * quick capture interface supports both. ++ */ ++ *flags = V4L2_MBUS_MASTER | ++ V4L2_MBUS_HSYNC_ACTIVE_HIGH | ++ V4L2_MBUS_HSYNC_ACTIVE_LOW | ++ V4L2_MBUS_VSYNC_ACTIVE_HIGH | ++ V4L2_MBUS_VSYNC_ACTIVE_LOW | ++ V4L2_MBUS_DATA_ACTIVE_HIGH | ++ V4L2_MBUS_PCLK_SAMPLE_RISING | ++ V4L2_MBUS_PCLK_SAMPLE_FALLING; ++ ++ return 0; ++} ++ ++ ++static int ingenic_start_streaming(struct vb2_queue *q, unsigned int count) ++{ ++ struct soc_camera_device *icd = soc_camera_from_vb2q(q); ++ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); ++ struct ingenic_camera_dev *pcdev = ici->priv; ++ unsigned long flags = 0; ++ ++ spin_lock_irqsave(&pcdev->lock, flags); ++ ++ dump_dma_desc(pcdev); ++ ingenic_dma_start(pcdev); ++ pcdev->start_streaming_called = 1; ++ pcdev->dma_stopped = 0; ++ ++ spin_unlock_irqrestore(&pcdev->lock, flags); ++ ++ ++ return 0; ++} ++ ++static void ingenic_stop_streaming(struct vb2_queue *q) ++{ ++ struct soc_camera_device *icd = soc_camera_from_vb2q(q); ++ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); ++ struct ingenic_camera_dev *pcdev = ici->priv; ++ struct ingenic_buffer *buf, *node; ++ unsigned long flags = 0; ++ ++ spin_lock_irqsave(&pcdev->lock, flags); ++ ++ pcdev->active = NULL; ++ ++ ingenic_dma_stop(pcdev); ++ ++ list_for_each_entry_safe(buf, node, &pcdev->capture, queue) { ++ list_del_init(&buf->queue); ++ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); ++ } ++ ++ pcdev->start_streaming_called = 0; ++ pcdev->dma_stopped = 1; ++ spin_unlock_irqrestore(&pcdev->lock, flags); ++ ++ ingenic_dma_free_desc(pcdev); ++} ++static struct vb2_ops ingenic_videobuf_ops = { ++ .queue_setup = ingenic_videobuf_setup, ++ .buf_init = ingenic_videobuf_init, ++ .buf_prepare = ingenic_videobuf_prepare, ++ .buf_queue = ingenic_videobuf_queue, ++ .start_streaming = ingenic_start_streaming, ++ .stop_streaming = ingenic_stop_streaming, ++ .wait_prepare = vb2_ops_wait_prepare, ++ .wait_finish = vb2_ops_wait_finish, ++}; ++static int ingenic_camera_init_videobuf(struct vb2_queue *q, struct soc_camera_device *icd) ++{ ++ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ q->io_modes = VB2_MMAP | VB2_USERPTR; ++ q->drv_priv = icd; ++ q->ops = &ingenic_videobuf_ops; ++ q->mem_ops = &vb2_dma_contig_memops; ++ q->buf_struct_size = sizeof(struct ingenic_buffer); ++ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ++ ++ return vb2_queue_init(q); ++} ++ ++static int ingenic_camera_try_fmt(struct soc_camera_device *icd, struct v4l2_format *f) ++{ ++ struct v4l2_subdev *sd = soc_camera_to_subdev(icd); ++ const struct soc_camera_format_xlate *xlate; ++ struct v4l2_pix_format *pix = &f->fmt.pix; ++ struct v4l2_subdev_pad_config pad_cfg; ++ struct v4l2_subdev_format format = { ++ .which = V4L2_SUBDEV_FORMAT_TRY, ++ }; ++ struct v4l2_mbus_framefmt *mf = &format.format; ++ u32 pixfmt = pix->pixelformat; ++ int ret; ++ ++ dev_dbg(icd->parent, "%s: requested params: width = %d, height = %d\n", ++ __func__, pix->width, pix->height); ++ ++ xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); ++ if (!xlate) { ++ dev_warn(icd->parent, "Format %x not found\n", pixfmt); ++ return -EINVAL; ++ } ++ ++ /* limit to sensor capabilities */ ++ mf->width = pix->width; ++ mf->height = pix->height; ++ mf->field = pix->field; ++ mf->colorspace = pix->colorspace; ++ mf->code = xlate->code; ++ ++ ret = v4l2_subdev_call(sd, pad, set_fmt, &pad_cfg, &format); ++ if (ret < 0) ++ return ret; ++ ++ pix->width = mf->width; ++ pix->height = mf->height; ++ pix->colorspace = mf->colorspace; ++ ++ switch (mf->field) { ++ case V4L2_FIELD_ANY: ++ pix->field = V4L2_FIELD_NONE; ++ break; ++ case V4L2_FIELD_NONE: ++ break; ++ default: ++ dev_err(icd->parent, "Field type %d unsupported.\n", ++ mf->field); ++ ret = -EINVAL; ++ } ++ ++ dev_dbg(icd->parent, "%s: returned params: width = %d, height = %d\n", ++ __func__, pix->width, pix->height); ++ ++ return ret; ++} ++ ++static int ingenic_camera_set_fmt(struct soc_camera_device *icd, struct v4l2_format *f) ++{ ++ struct v4l2_subdev *sd = soc_camera_to_subdev(icd); ++ const struct soc_camera_format_xlate *xlate; ++ struct v4l2_pix_format *pix = &f->fmt.pix; ++ struct v4l2_subdev_format format = { ++ .which = V4L2_SUBDEV_FORMAT_ACTIVE, ++ }; ++ struct v4l2_mbus_framefmt *mf = &format.format; ++ int ret; ++ ++ /* limit to hw supported fmts */ ++ dev_dbg(icd->parent, "%s: requested params: width = %d, height = %d\n", ++ __func__, pix->width, pix->height); ++ ++ xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); ++ if (!xlate) { ++ dev_warn(icd->parent, "Format %x not found\n", ++ pix->pixelformat); ++ return -EINVAL; ++ } ++ ++ dev_dbg(icd->parent, "Plan to set format %dx%d\n", ++ pix->width, pix->height); ++ ++ mf->width = pix->width; ++ mf->height = pix->height; ++ mf->field = pix->field; ++ mf->colorspace = pix->colorspace; ++ mf->code = xlate->code; ++ ++ ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &format); ++ if (ret < 0) ++ return ret; ++ ++ if (mf->code != xlate->code) ++ return -EINVAL; ++ ++ pix->width = mf->width; ++ pix->height = mf->height; ++ pix->field = mf->field; ++ pix->colorspace = mf->colorspace; ++ icd->current_fmt = xlate; ++ ++ dev_dbg(icd->parent, "Finally set format %dx%d\n", ++ pix->width, pix->height); ++ ++ return ret; ++} ++ ++static int ingenic_camera_set_crop(struct soc_camera_device *icd, const struct v4l2_crop *a) ++{ ++ struct v4l2_crop a_writable = *a; ++ struct v4l2_rect *rect = &a_writable.c; ++ struct v4l2_subdev *sd = soc_camera_to_subdev(icd); ++ struct v4l2_subdev_format fmt = { ++ .which = V4L2_SUBDEV_FORMAT_ACTIVE, ++ }; ++ struct v4l2_mbus_framefmt *mf = &fmt.format; ++ int ret; ++ ++ soc_camera_limit_side(&rect->left, &rect->width, 0, 2, 4096); ++ soc_camera_limit_side(&rect->top, &rect->height, 0, 2, 4096); ++ ++ ret = v4l2_subdev_call(sd, video, s_crop, a); ++ if (ret < 0) ++ return ret; ++ ++ /* The capture device might have changed its output */ ++ ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); ++ if (ret < 0) ++ return ret; ++ ++ dev_dbg(icd->parent, "Sensor cropped %dx%d\n", ++ mf->width, mf->height); ++ ++ icd->user_width = mf->width; ++ icd->user_height = mf->height; ++ ++ return ret; ++} ++ ++static int ingenic_camera_set_bus_param(struct soc_camera_device *icd) ++{ ++ struct v4l2_subdev *sd = soc_camera_to_subdev(icd); ++ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); ++ struct ingenic_camera_dev *pcdev = ici->priv; ++ struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; ++ u32 pixfmt = icd->current_fmt->host_fmt->fourcc; ++ unsigned long common_flags; ++ unsigned long bus_flags = 0; ++ unsigned long cfg_reg = 0; ++ unsigned long ctrl_reg = 0; ++ unsigned long ctrl2_reg = 0; ++ unsigned long fs_reg = 0; ++ unsigned long temp = 0; ++ int ret; ++ ++ ret = test_platform_param(pcdev, icd->current_fmt->host_fmt->bits_per_sample, ++ &bus_flags); ++ ++ ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); ++ if (!ret) { ++ common_flags = soc_mbus_config_compatible(&cfg, ++ bus_flags); ++ if (!common_flags) { ++ dev_warn(icd->parent, ++ "Flags incompatible: camera 0x%x, host 0x%lx\n", ++ cfg.flags, bus_flags); ++ return -EINVAL; ++ } ++ } else if (ret != -ENOIOCTLCMD) { ++ return ret; ++ } else { ++ common_flags = bus_flags; ++ } ++ ++ /* Make choises, based on platform preferences */ ++ if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) && ++ (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) { ++ if (pcdev->pdata->flags & INGENIC_CAMERA_VSYNC_HIGH) ++ common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH; ++ else ++ common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW; ++ } ++ ++ if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && ++ (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { ++ if (pcdev->pdata->flags & INGENIC_CAMERA_PCLK_RISING) ++ common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; ++ else ++ common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; ++ } ++ ++ if ((common_flags & V4L2_MBUS_DATA_ACTIVE_HIGH) && ++ (common_flags & V4L2_MBUS_DATA_ACTIVE_LOW)) { ++ if (pcdev->pdata->flags & INGENIC_CAMERA_DATA_HIGH) ++ common_flags &= ~V4L2_MBUS_DATA_ACTIVE_LOW; ++ else ++ common_flags &= ~V4L2_MBUS_DATA_ACTIVE_HIGH; ++ } ++ ++ cfg.flags = common_flags; ++ ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); ++ if (ret < 0 && ret != -ENOIOCTLCMD) { ++ dev_dbg(icd->parent, "camera s_mbus_config(0x%lx) returned %d\n", ++ common_flags, ret); ++ return ret; ++ } ++ ++ /*PCLK Polarity Set*/ ++ cfg_reg = (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) ? ++ cfg_reg | CIM_CFG_PCP_HIGH : cfg_reg & (~CIM_CFG_PCP_HIGH); ++ ++ /*VSYNC Polarity Set*/ ++ cfg_reg = (common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) ? ++ cfg_reg | CIM_CFG_VSP_HIGH : cfg_reg & (~CIM_CFG_VSP_HIGH); ++ ++ /*HSYNC Polarity Set*/ ++ cfg_reg = (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) ? ++ cfg_reg | CIM_CFG_HSP_HIGH : cfg_reg & (~CIM_CFG_HSP_HIGH); ++ ++ cfg_reg |= CIM_CFG_DMA_BURST_INCR64 | CIM_CFG_DSM_GCM | CIM_CFG_PACK_Y0UY1V; ++ ++ ctrl_reg |= CIM_CTRL_DMA_SYNC | CIM_CTRL_FRC_1; ++ ++ ctrl2_reg |= CIM_CTRL2_APM | CIM_CTRL2_OPE | ++ (1 << CIM_CTRL2_OPG_BIT) | CIM_CTRL2_FSC | CIM_CTRL2_ARIF; ++ ++ fs_reg = (icd->user_width -1) << CIM_FS_FHS_BIT | (icd->user_height -1) ++ << CIM_FS_FVS_BIT | 1 << CIM_FS_BPP_BIT; ++ ++ if(pixfmt == V4L2_PIX_FMT_SBGGR8) { ++ fs_reg = (icd->user_width -1) << CIM_FS_FHS_BIT | (icd->user_height -1) ++ << CIM_FS_FVS_BIT | 0 << CIM_FS_BPP_BIT; ++ } ++ ++ /*BS0 BS1 BS2 BS3 must be 00,01,02,03 when pack is b100*/ ++ ++ if(cfg_reg & CIM_CFG_PACK_Y0UY1V) ++ cfg_reg |= CIM_CFG_BS1_2_OBYT1 | CIM_CFG_BS2_2_OBYT2 | CIM_CFG_BS3_2_OBYT3; ++ ++ writel(cfg_reg, pcdev->base + CIM_CFG); ++ writel(ctrl_reg, pcdev->base + CIM_CTRL); ++ writel(ctrl2_reg, pcdev->base + CIM_CTRL2); ++ writel(fs_reg, pcdev->base + CIM_FS); ++ ++#ifdef CIM_DUMP_REG ++ cim_dump_reg(pcdev); ++#endif ++ ++ /* enable end of frame interrupt */ ++ temp = readl(pcdev->base + CIM_IMR); ++ temp &= ~(CIM_IMR_EOFM | CIM_IMR_STPM | CIM_IMR_STPM_1); ++ writel(temp, pcdev->base + CIM_IMR); ++ ++ return 0; ++} ++ ++static void ingenic_camera_clock_start(struct soc_camera_host *ici) ++{ ++ struct ingenic_camera_dev *pcdev = ici->priv; ++ clk_prepare_enable(pcdev->clk); ++ clk_prepare_enable(pcdev->lcd_clk); ++} ++ ++static void ingenic_camera_clock_stop(struct soc_camera_host *ici) ++{ ++ struct ingenic_camera_dev *pcdev = ici->priv; ++ clk_disable_unprepare(pcdev->clk); ++ clk_disable_unprepare(pcdev->lcd_clk); ++} ++ ++static int ingenic_camera_add_device(struct soc_camera_device *icd) ++{ ++ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); ++ struct ingenic_camera_dev *pcdev = ici->priv; ++ ++ int icd_index = icd->devnum; ++ ++ if (pcdev->icd[icd_index]) ++ return -EBUSY; ++ ++ pcdev->icd[icd_index] = icd; ++ ++ ingenic_camera_clock_start(ici); ++ ++ dev_dbg(icd->parent, "Camera Driver attached to Camera %d\n", icd->devnum); ++ return 0; ++} ++static void ingenic_camera_remove_device(struct soc_camera_device *icd) ++{ ++ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); ++ struct ingenic_camera_dev *pcdev = ici->priv; ++ ++ int icd_index = icd->devnum; ++ ++ BUG_ON(icd != pcdev->icd[icd_index]); ++ ++ pcdev->icd[icd_index] = NULL; ++ ingenic_camera_clock_stop(ici); ++ ++ dev_dbg(icd->parent, "Camera driver detached from camera %d\n", icd->devnum); ++} ++ ++ ++static irqreturn_t ingenic_camera_irq_handler(int irq, void *data) ++{ ++ struct ingenic_camera_dev *pcdev = (struct ingenic_camera_dev *)data; ++ struct ingenic_camera_dma_desc *dma_desc_paddr; ++ unsigned long status = 0, temp = 0; ++ unsigned long flags = 0; ++ int index = 0, regval = 0; ++ ++ for (index = 0; index < ARRAY_SIZE(pcdev->icd); index++) { ++ if (pcdev->icd[index]) { ++ break; ++ } ++ } ++ ++ if(index == MAX_SOC_CAM_NUM) { ++ return IRQ_HANDLED; ++ } ++ ++ /* judged pcdev->dma_desc_head->id */ ++ if((pcdev->dma_desc_head->id > pcdev->buf_cnt) || (pcdev->dma_desc_head->id < 0)) { ++ dev_warn(NULL, "Warning: %s, %d, pcdev->dma_desc_head->id >pcdev->buf_cnt || pcdev->dma_desc_head->id < 0, please check pcdev->dma_desc_head->id !!!\n", ++ __func__, pcdev->dma_desc_head->id); ++ return IRQ_NONE; ++ } ++ ++ spin_lock_irqsave(&pcdev->lock, flags); ++ ++ /* read interrupt status register */ ++ status = readl(pcdev->base + CIM_STATE); ++ if (!status) { ++ dev_warn(NULL, " cim status is NULL! \n"); ++ spin_unlock_irqrestore(&pcdev->lock, flags); ++ ++ return IRQ_NONE; ++ } ++ ++ if(!(status & CIM_STATE_RXOF_STOP_EOF)) { ++ /* other irq */ ++ dev_warn(NULL, "irq_handle status is 0x%lx, not judged in irq_handle\n", status); ++ spin_unlock_irqrestore(&pcdev->lock, flags); ++ return IRQ_HANDLED; ++ } ++ ++ if(status & CIM_STATE_DMA_STOP) { ++ /* clear dma interrupt status */ ++ temp = readl(pcdev->base + CIM_STATE); ++ temp &= (~CIM_STATE_DMA_STOP); ++ writel(temp, pcdev->base + CIM_STATE); ++ ++ pcdev->dma_stopped = 1; ++ } ++ ++ if(status & CIM_STATE_DMA_EOF) { ++ /* clear dma interrupt status */ ++ temp = readl(pcdev->base + CIM_STATE); ++ temp &= (~CIM_STATE_DMA_EOF); ++ writel(temp, pcdev->base + CIM_STATE); ++ ++ if(pcdev->active) { ++ struct vb2_v4l2_buffer *vbuf = &pcdev->active->vb; ++ struct ingenic_buffer *buf = container_of(vbuf, struct ingenic_buffer, vb); ++ ++ list_del_init(&buf->queue); ++ v4l2_get_timestamp(&vbuf->timestamp); ++ vbuf->field = pcdev->field; ++ vbuf->sequence = pcdev->sequence++; ++ vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_DONE); ++ ++#ifdef CIM_DEBUG_FPS ++ if((vbuf->sequence % 60) == 0) { ++ pcdev->debug_ms_start = ktime_to_ms(ktime_get_real()); ++ } else if((vbuf->sequence % 60) == 59) { ++ unsigned long long debug_ms_end = ktime_to_ms(ktime_get_real()); ++ unsigned int ms = debug_ms_end - pcdev->debug_ms_start; ++ ++ unsigned long long fps = 60 * 1000; ++ do_div(fps, ms); ++ ++ dev_info(NULL, "===fps: %lld, start: %lld, end: %lld, sequence: %d\n",\ ++ fps, pcdev->debug_ms_start, debug_ms_end, pcdev->sequence); ++ } ++#endif ++ } ++ ++ if(list_empty(&pcdev->capture)) { ++ pcdev->active = NULL; ++ spin_unlock_irqrestore(&pcdev->lock, flags); ++ return IRQ_HANDLED; ++ } ++ ++ if(pcdev->dma_desc_head != pcdev->dma_desc_tail) { ++ pcdev->dma_desc_head = ++ (struct ingenic_camera_dma_desc *)UNCAC_ADDR(phys_to_virt(pcdev->dma_desc_head->next)); ++ } ++ ++ if(pcdev->dma_stopped && !list_empty(&pcdev->capture)) { ++ /* dma stop condition: ++ * 1. dma desc reach the end, and there is no more desc to be transferd. ++ * dma need to stop. ++ * 2. if the capture list not empty, we should restart dma here. ++ * ++ * */ ++ ++ dma_desc_paddr = (struct ingenic_camera_dma_desc *) pcdev->dma_desc; ++ regval = (unsigned int) (&dma_desc_paddr[pcdev->dma_desc_head->id]); ++ writel(regval, pcdev->base + CIM_DA); ++ ++ pcdev->dma_stopped = 0; ++ } ++ ++ /* update dma active buffer. ++ * Bug: ++ * we assume that a EOF interrupt, dma only transfered one frame, ++ * But , what if two or more frames transfered in a EOF interrupt ++ * when system is really busy ?? ++ * */ ++ pcdev->active = list_first_entry(&pcdev->capture, struct ingenic_buffer, queue); ++ ++ spin_unlock_irqrestore(&pcdev->lock, flags); ++ ++ return IRQ_HANDLED; ++ } ++ spin_unlock_irqrestore(&pcdev->lock, flags); ++ return IRQ_HANDLED; ++} ++ ++static struct soc_camera_host_ops ingenic_soc_camera_host_ops = { ++ .owner = THIS_MODULE, ++ .add = ingenic_camera_add_device, ++ .remove = ingenic_camera_remove_device, ++ .set_bus_param = ingenic_camera_set_bus_param, ++ .set_crop = ingenic_camera_set_crop, ++ .set_fmt = ingenic_camera_set_fmt, ++ .try_fmt = ingenic_camera_try_fmt, ++ .init_videobuf2 = ingenic_camera_init_videobuf, ++ .poll = ingenic_camera_poll, ++ .querycap = ingenic_camera_querycap, ++}; ++ ++static int __init ingenic_camera_probe(struct platform_device *pdev) { ++ int err = 0; ++ unsigned int irq; ++ struct resource *res; ++ void __iomem *base; ++ struct ingenic_camera_dev *pcdev; ++ ++ pcdev = kzalloc(sizeof(*pcdev), GFP_KERNEL); ++ if (!pcdev) { ++ dev_err(&pdev->dev, "Could not allocate pcdev\n"); ++ err = -ENOMEM; ++ goto err_kzalloc; ++ } ++ ++ pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); ++ if(IS_ERR(pcdev->alloc_ctx)) { ++ err = PTR_ERR(pcdev->alloc_ctx); ++ goto err_alloc_ctx; ++ } ++ ++ INIT_LIST_HEAD(&pcdev->capture); ++ pcdev->active = NULL; ++ ++ /* resource */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if(!res) { ++ dev_err(&pdev->dev, "Could not get resource!\n"); ++ err = -ENODEV; ++ goto err_get_resource; ++ } ++ ++ /* irq */ ++ irq = platform_get_irq(pdev, 0); ++ if (irq <= 0) { ++ dev_err(&pdev->dev, "Could not get irq!\n"); ++ err = -ENODEV; ++ goto err_get_irq; ++ } ++ ++ pcdev->clk = devm_clk_get(&pdev->dev, "gate_cim"); ++ if (IS_ERR(pcdev->clk)) { ++ err = PTR_ERR(pcdev->clk); ++ dev_err(&pdev->dev, "%s:can't get clk %s\n", __func__, "cim"); ++ goto err_clk_get_cim; ++ } ++ ++ /* ++ * Get gate_lcd clk, for bugs: ++ * CIM module can work only with lcd clk enabled. ++ * */ ++ pcdev->lcd_clk = devm_clk_get(&pdev->dev, "gate_lcd"); ++ if (IS_ERR(pcdev->lcd_clk)) { ++ err = PTR_ERR(pcdev->lcd_clk); ++ dev_err(&pdev->dev, "%s:can't get clk %s\n", __func__, "cim"); ++ goto err_clk_get_lcd; ++ } ++ ++ pcdev->pdata = pdev->dev.platform_data; ++ ++ /* Request the regions. */ ++ if (!request_mem_region(res->start, resource_size(res), DRIVER_NAME)) { ++ err = -EBUSY; ++ goto err_request_mem_region; ++ } ++ base = ioremap(res->start, resource_size(res)); ++ if (!base) { ++ err = -ENOMEM; ++ goto err_ioremap; ++ } ++ ++ spin_lock_init(&pcdev->lock); ++ ++ pcdev->res = res; ++ pcdev->irq = irq; ++ pcdev->base = base; ++ ++ /* request irq */ ++ err = devm_request_irq(&pdev->dev, pcdev->irq, ingenic_camera_irq_handler, 0, ++ dev_name(&pdev->dev), pcdev); ++ if(err) { ++ dev_err(&pdev->dev, "request irq failed!\n"); ++ goto err_request_irq; ++ } ++ ++ pcdev->soc_host.drv_name = DRIVER_NAME; ++ pcdev->soc_host.ops = &ingenic_soc_camera_host_ops; ++ pcdev->soc_host.priv = pcdev; ++ pcdev->soc_host.v4l2_dev.dev = &pdev->dev; ++ pcdev->soc_host.nr = pdev->id; ++ ++ err = soc_camera_host_register(&pcdev->soc_host); ++ if (err) ++ goto err_soc_camera_host_register; ++ ++ dev_info(&pdev->dev, "ingenic Camera driver loaded!\n"); ++ ++ return 0; ++ ++err_soc_camera_host_register: ++ devm_free_irq(&pdev->dev, pcdev->irq, pcdev); ++err_request_irq: ++ iounmap(base); ++err_ioremap: ++ release_mem_region(res->start, resource_size(res)); ++err_request_mem_region: ++ devm_clk_put(&pdev->dev, pcdev->lcd_clk); ++err_clk_get_lcd: ++ devm_clk_put(&pdev->dev, pcdev->clk); ++err_clk_get_cim: ++err_get_irq: ++err_get_resource: ++ vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); ++err_alloc_ctx: ++ kfree(pcdev); ++err_kzalloc: ++ return err; ++ ++} ++ ++static int __exit ingenic_camera_remove(struct platform_device *pdev) ++{ ++ struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); ++ struct ingenic_camera_dev *pcdev = container_of(soc_host, ++ struct ingenic_camera_dev, soc_host); ++ struct resource *res; ++ ++ devm_free_irq(&pdev->dev, pcdev->irq, pcdev); ++ ++ devm_clk_put(&pdev->dev, pcdev->lcd_clk); ++ devm_clk_put(&pdev->dev, pcdev->clk); ++ ++ soc_camera_host_unregister(soc_host); ++ ++ vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); ++ ++ iounmap(pcdev->base); ++ ++ res = pcdev->res; ++ release_mem_region(res->start, resource_size(res)); ++ ++ kfree(pcdev); ++ ++ dev_info(&pdev->dev, "ingenic Camera driver unloaded\n"); ++ ++ return 0; ++} ++ ++ ++static const struct of_device_id ingenic_camera_of_match[] = { ++ { .compatible = "ingenic,cim" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, ingenic_camera_of_match); ++ ++static struct platform_driver ingenic_camera_driver = { ++ .remove = __exit_p(ingenic_camera_remove), ++ .driver = { ++ .name = DRIVER_NAME, ++ .owner = THIS_MODULE, ++ .of_match_table = ingenic_camera_of_match, ++ }, ++}; ++ ++static int __init ingenic_camera_init(void) { ++ /* ++ * platform_driver_probe() can save memory, ++ * but this Driver can bind to one device only. ++ */ ++ return platform_driver_probe(&ingenic_camera_driver, ingenic_camera_probe); ++} ++ ++static void __exit ingenic_camera_exit(void) { ++ return platform_driver_unregister(&ingenic_camera_driver); ++} ++ ++module_init(ingenic_camera_init); ++module_exit(ingenic_camera_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("qipengzhen "); ++MODULE_DESCRIPTION("ingenic Soc Camera Host Driver With videobuf2 interface"); ++MODULE_ALIAS("a ingenic-cim platform"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_x1000_ingenic_camera.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_x1000_ingenic_camera.h.patch new file mode 100644 index 00000000..2f2cc9ac --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_x1000_ingenic_camera.h.patch @@ -0,0 +1,206 @@ +diff -drupN a/drivers/media/platform/soc_camera/ingenic/x1000/ingenic_camera.h b/drivers/media/platform/soc_camera/ingenic/x1000/ingenic_camera.h +--- a/drivers/media/platform/soc_camera/ingenic/x1000/ingenic_camera.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/soc_camera/ingenic/x1000/ingenic_camera.h 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,202 @@ ++ ++#ifndef __INGENIC_CAMERA_H__ ++#define __INGENIC_CAMERA_H__ ++ ++#include ++#include ++#include ++ ++#define INGENIC_CAMERA_DATA_HIGH 1 ++#define INGENIC_CAMERA_PCLK_RISING 2 ++#define INGENIC_CAMERA_VSYNC_HIGH 4 ++ ++/* define the maximum number of camera sensor that attach to cim controller */ ++#define MAX_SOC_CAM_NUM 2 ++struct ingenic_camera_pdata { ++ unsigned long mclk_10khz; ++ unsigned long flags; ++}; ++ ++/* ++ * CIM registers ++ */ ++#define CIM_CFG (0x00) ++#define CIM_CTRL (0x04) ++#define CIM_STATE (0x08) ++#define CIM_IID (0x0c) ++#define CIM_DA (0x20) ++#define CIM_FA (0x24) ++#define CIM_FID (0x28) ++#define CIM_CMD (0x2c) ++#define CIM_SIZE (0x30) ++#define CIM_OFFSET (0x34) ++#define CIM_CTRL2 (0x50) ++#define CIM_FS (0x54) ++#define CIM_IMR (0x58) ++ ++/*CIM Configuration Register (CIMCFG)*/ ++#define CIM_CFG_VSP_HIGH (1 << 14) /* VSYNC Polarity: 1-falling edge active */ ++#define CIM_CFG_HSP_HIGH (1 << 13) /* HSYNC Polarity: 1-falling edge active */ ++#define CIM_CFG_PCP_HIGH (1 << 12) /* PCLK working edge: 1-falling */ ++ ++#define CIM_CFG_DMA_BURST_TYPE 10 ++#define CIM_CFG_DMA_BURST_INCR8 (0 << CIM_CFG_DMA_BURST_TYPE) ++#define CIM_CFG_DMA_BURST_INCR16 (1 << CIM_CFG_DMA_BURST_TYPE) ++#define CIM_CFG_DMA_BURST_INCR32 (2 << CIM_CFG_DMA_BURST_TYPE) ++#define CIM_CFG_DMA_BURST_INCR64 (3 << CIM_CFG_DMA_BURST_TYPE) ++ ++#define CIM_CFG_PACK 4 ++#define CIM_CFG_PACK_VY1UY0 (0 << CIM_CFG_PACK) ++#define CIM_CFG_PACK_Y0VY1U (1 << CIM_CFG_PACK) ++#define CIM_CFG_PACK_UY0VY1 (2 << CIM_CFG_PACK) ++#define CIM_CFG_PACK_Y1UY0V (3 << CIM_CFG_PACK) ++#define CIM_CFG_PACK_Y0UY1V (4 << CIM_CFG_PACK) ++#define CIM_CFG_PACK_UY1VY0 (5 << CIM_CFG_PACK) ++#define CIM_CFG_PACK_Y1VY0U (6 << CIM_CFG_PACK) ++#define CIM_CFG_PACK_VY0UY1 (7 << CIM_CFG_PACK) ++ ++#define CIM_CFG_BS0 16 ++#define CIM_CFG_BS0_2_OBYT0 (0 << CIM_CFG_BS0) ++#define CIM_CFG_BS1_2_OBYT0 (1 << CIM_CFG_BS0) ++#define CIM_CFG_BS2_2_OBYT0 (2 << CIM_CFG_BS0) ++#define CIM_CFG_BS3_2_OBYT0 (3 << CIM_CFG_BS0) ++ ++#define CIM_CFG_BS1 18 ++#define CIM_CFG_BS0_2_OBYT1 (0 << CIM_CFG_BS1) ++#define CIM_CFG_BS1_2_OBYT1 (1 << CIM_CFG_BS1) ++#define CIM_CFG_BS2_2_OBYT1 (2 << CIM_CFG_BS1) ++#define CIM_CFG_BS3_2_OBYT1 (3 << CIM_CFG_BS1) ++ ++#define CIM_CFG_BS2 20 ++#define CIM_CFG_BS0_2_OBYT2 (0 << CIM_CFG_BS2) ++#define CIM_CFG_BS1_2_OBYT2 (1 << CIM_CFG_BS2) ++#define CIM_CFG_BS2_2_OBYT2 (2 << CIM_CFG_BS2) ++#define CIM_CFG_BS3_2_OBYT2 (3 << CIM_CFG_BS2) ++ ++#define CIM_CFG_BS3 22 ++#define CIM_CFG_BS0_2_OBYT3 (0 << CIM_CFG_BS3) ++#define CIM_CFG_BS1_2_OBYT3 (1 << CIM_CFG_BS3) ++#define CIM_CFG_BS2_2_OBYT3 (2 << CIM_CFG_BS3) ++#define CIM_CFG_BS3_2_OBYT3 (3 << CIM_CFG_BS3) ++ ++#define CIM_CFG_DSM 0 ++#define CIM_CFG_DSM_CPM (0 << CIM_CFG_DSM) /* CCIR656 Progressive Mode */ ++#define CIM_CFG_DSM_CIM (1 << CIM_CFG_DSM) /* CCIR656 Interlace Mode */ ++#define CIM_CFG_DSM_GCM (2 << CIM_CFG_DSM) /* Gated Clock Mode */ ++ ++/* CIM State Register (CIM_STATE) */ ++#define CIM_STATE_DMA_EEOF (1 << 11) /* DMA Line EEOf irq */ ++#define CIM_STATE_DMA_STOP (1 << 10) /* DMA stop irq */ ++#define CIM_STATE_DMA_EOF (1 << 9) /* DMA end irq */ ++#define CIM_STATE_DMA_SOF (1 << 8) /* DMA start irq */ ++#define CIM_STATE_SIZE_ERR (1 << 3) /* Frame size check error */ ++#define CIM_STATE_RXF_OF (1 << 2) /* RXFIFO over flow irq */ ++#define CIM_STATE_RXF_EMPTY (1 << 1) /* RXFIFO empty irq */ ++#define CIM_STATE_STP_ACK (1 << 0) /* CIM disabled status */ ++#define CIM_STATE_RXOF_STOP_EOF (CIM_STATE_RXF_OF | CIM_STATE_DMA_STOP | CIM_STATE_DMA_EOF) ++ ++/* CIM DMA Command Register (CIM_CMD) */ ++#define CIM_CMD_SOFINT (1 << 31) /* enable DMA start irq */ ++#define CIM_CMD_EOFINT (1 << 30) /* enable DMA end irq */ ++#define CIM_CMD_EEOFINT (1 << 29) /* enable DMA EEOF irq */ ++#define CIM_CMD_STOP (1 << 28) /* enable DMA stop irq */ ++#define CIM_CMD_OFRCV (1 << 27) ++ ++/*CIM Control Register (CIMCR)*/ ++#define CIM_CTRL_FRC_BIT 16 ++#define CIM_CTRL_FRC_1 (0x0 << CIM_CTRL_FRC_BIT) /* Sample every n+1 frame */ ++#define CIM_CTRL_FRC_10 (0x9 << CIM_CTRL_FRC_BIT) ++ ++#define CIM_CTRL_DMA_SYNC (1 << 7) /*when change DA, do frame sync */ ++#define CIM_CTRL_STP_REQ (1 << 4) /*request to stop */ ++#define CIM_CTRL_CIM_RST (1 << 3) ++#define CIM_CTRL_DMA_EN (1 << 2) /* Enable DMA */ ++#define CIM_CTRL_RXF_RST (1 << 1) /* RxFIFO reset */ ++#define CIM_CTRL_ENA (1 << 0) /* Enable CIM */ ++ ++/* CIM Control Register 2 (CIMCR2) */ ++#define CIM_CTRL2_FSC (1 << 23) /* enable frame size check */ ++#define CIM_CTRL2_ARIF (1 << 22) /* enable auto-recovery for incomplete frame */ ++#define CIM_CTRL2_OPG_BIT 4 /* option priority configuration */ ++#define CIM_CTRL2_OPG_MASK (0x3 << CIM_CTRL2_OPG_BIT) ++#define CIM_CTRL2_OPE (1 << 2) /* optional priority mode enable */ ++#define CIM_CTRL2_APM (1 << 0) /* auto priority mode enable*/ ++ ++/*CIM Interrupt Mask Register (CIMIMR)*/ ++#define CIM_IMR_STPM (1<<10) ++#define CIM_IMR_EOFM (1<<9) ++#define CIM_IMR_SOFM (1<<8) ++#define CIM_IMR_FSEM (1<<3) ++#define CIM_IMR_RFIFO_OFM (1<<2) ++#define CIM_IMR_STPM_1 (1<<0) ++ ++/* CIM Frame Size Register (CIM_FS) */ ++#define CIM_FS_FVS_BIT 16 /* vertical size of the frame */ ++#define CIM_FS_FVS_MASK (0x1fff << CIM_FS_FVS_BIT) ++#define CIM_FS_BPP_BIT 14 /* bytes per pixel */ ++#define CIM_FS_BPP_MASK (0x3 << CIM_FS_BPP_BIT) ++#define CIM_FS_FHS_BIT 0 /* horizontal size of the frame */ ++#define CIM_FS_FHS_MASK (0x1fff << CIM_FS_FHS_BIT) ++ ++#define VERSION_CODE KERNEL_VERSION(0, 0, 1) ++#define DRIVER_NAME "ingenic-cim" ++ ++#define MAX_BUFFER_NUM (32) ++#define MAX_VIDEO_MEM (16*1024*1024) ++ ++/* ++ * Structures ++ */ ++struct ingenic_camera_dma_desc { ++ dma_addr_t next; ++ unsigned int id; ++ unsigned int buf; ++ unsigned int cmd; ++ /* only used when SEP = 1 */ ++ unsigned int cb_frame; ++ unsigned int cb_len; ++ unsigned int cr_frame; ++ unsigned int cr_len; ++} __attribute__ ((aligned (32))); ++ ++/* buffer for one video frame */ ++struct ingenic_buffer { ++ /* common v4l buffer stuff -- must be first */ ++ struct vb2_v4l2_buffer vb; ++ struct list_head queue; ++}; ++ ++struct ingenic_camera_dev { ++ struct soc_camera_host soc_host; ++ struct soc_camera_device *icd[MAX_SOC_CAM_NUM]; ++ struct ingenic_camera_pdata *pdata; ++ ++ struct resource *res; ++ struct clk *clk; ++ struct clk *lcd_clk; ++ struct clk *mclk; ++ void __iomem *base; ++ unsigned int irq; ++ ++ spinlock_t lock; ++ struct list_head capture; ++ struct ingenic_buffer *active; ++ ++ struct vb2_alloc_ctx *alloc_ctx; ++ unsigned int buf_cnt; ++ struct ingenic_camera_dma_desc *dma_desc; ++ void *desc_vaddr; ++ ++ struct ingenic_camera_dma_desc *dma_desc_head; ++ struct ingenic_camera_dma_desc *dma_desc_tail; ++ ++ int start_streaming_called; ++ unsigned int field; ++ unsigned int sequence; ++ int dma_stopped; ++ ++ /* for debug */ ++ long long debug_ms_start; ++}; ++ ++#endif /* __INGENIC_CAMERA_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_x2000_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_x2000_Kconfig.patch new file mode 100644 index 00000000..7f991c2c --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_x2000_Kconfig.patch @@ -0,0 +1,29 @@ +diff -drupN a/drivers/media/platform/soc_camera/ingenic/x2000/Kconfig b/drivers/media/platform/soc_camera/ingenic/x2000/Kconfig +--- a/drivers/media/platform/soc_camera/ingenic/x2000/Kconfig 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/soc_camera/ingenic/x2000/Kconfig 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,25 @@ ++config VIDEO_INGENIC_X2000 ++ tristate "Ingenic Soc Camera Driver for X2000" ++ depends on VIDEO_INGENIC ++ help ++ CIM Driver for X2000 ++ ++config CAMERA_USE_SNAPSHOT ++ bool "Sensor support snapshot function" ++ depends on VIDEO_INGENIC_X2000 ++ help ++ Sensor support snapshot function ++ ++config SNAPSHOT_PULSE_WIDTH ++ int "Snapshot pulse width" ++ depends on CAMERA_USE_SNAPSHOT ++ default 8 ++ help ++ Snapshot pulse width ++ ++config SNAPSHOT_FRAME_DELAY ++ int "One frame end delay" ++ depends on CAMERA_USE_SNAPSHOT ++ default 100 ++ help ++ One frame end delay diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_x2000_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_x2000_Makefile.patch new file mode 100644 index 00000000..65d54af1 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_x2000_Makefile.patch @@ -0,0 +1,6 @@ +diff -drupN a/drivers/media/platform/soc_camera/ingenic/x2000/Makefile b/drivers/media/platform/soc_camera/ingenic/x2000/Makefile +--- a/drivers/media/platform/soc_camera/ingenic/x2000/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/soc_camera/ingenic/x2000/Makefile 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,2 @@ ++obj-y += ingenic_camera.o mipi_csi.o ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_x2000_ingenic_camera.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_x2000_ingenic_camera.c.patch new file mode 100644 index 00000000..2a6a9701 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_x2000_ingenic_camera.c.patch @@ -0,0 +1,2005 @@ +diff -drupN a/drivers/media/platform/soc_camera/ingenic/x2000/ingenic_camera.c b/drivers/media/platform/soc_camera/ingenic/x2000/ingenic_camera.c +--- a/drivers/media/platform/soc_camera/ingenic/x2000/ingenic_camera.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/soc_camera/ingenic/x2000/ingenic_camera.c 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,2001 @@ ++/* ++ * Copyright (c) 2012 Ingenic Semiconductor Co., Ltd. ++ * http://www.ingenic.com/ ++ * ++ * Core file for Ingenic Display Controller driver ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "ingenic_camera.h" ++#include "mipi_csi.h" ++ ++static int frame_size_check_flag = 0; ++static int showFPS = 0; ++ ++void cim_dump_reg(struct ingenic_camera_dev *pcdev) ++{ ++ if(!pcdev) { ++ printk("===>>%s,%d pcdev is NULL!\n",__func__,__LINE__); ++ return; ++ } ++ printk("\n***************************************\n"); ++ printk("GLB_CFG 0x%08x\n", cim_readl(pcdev, GLB_CFG)); ++ printk("FRM_SIZE 0x%08x\n", cim_readl(pcdev, FRM_SIZE)); ++ printk("CROP_SITE 0x%08x\n", cim_readl(pcdev, CROP_SITE)); ++ printk("SCAN_CFG 0x%08x\n", cim_readl(pcdev, SCAN_CFG)); ++ printk("QOS_CTRL 0x%08x\n", cim_readl(pcdev, QOS_CTRL)); ++ printk("QOS_CFG 0x%08x\n", cim_readl(pcdev, QOS_CFG)); ++ printk("DLY_CFG 0x%08x\n", cim_readl(pcdev, DLY_CFG)); ++ printk("DES_ADDR 0x%08x\n", cim_readl(pcdev, DES_ADDR)); ++ printk("CIM_ST 0x%08x\n", cim_readl(pcdev, CIM_ST)); ++ printk("CIM_CLR_ST 0x%08x\n", cim_readl(pcdev, CIM_CLR_ST)); ++ printk("CIM_INTC 0x%08x\n", cim_readl(pcdev, CIM_INTC)); ++ printk("INT_FLAG 0x%08x\n", cim_readl(pcdev, INT_FLAG)); ++ printk("FRAME_ID 0x%08x\n", cim_readl(pcdev, FRAME_ID)); ++ printk("ACT_SIZE 0x%08x\n", cim_readl(pcdev, ACT_SIZE)); ++ printk("DBG_CGC 0x%08x\n", cim_readl(pcdev, DBG_CGC)); ++ printk("***************************************\n\n"); ++} ++ ++void cim_dump_reg_des(struct ingenic_camera_dev *pcdev) ++{ ++ printk("\n***************************************\n"); ++ printk("DBG_DES next 0x%08x\n", cim_readl(pcdev, DBG_DES)); ++ printk("DBG_DES WRBK_ADDR: 0x%08x\n", cim_readl(pcdev, DBG_DES)); ++ printk("DBG_DES WRBK_STRD: 0x%08x\n", cim_readl(pcdev, DBG_DES)); ++ printk("DBG_DES DES_INTC_t: 0x%08x\n", cim_readl(pcdev, DBG_DES)); ++ printk("DBG_DES DES_CFG_t: 0x%08x\n", cim_readl(pcdev, DBG_DES)); ++ printk("DES_HIST_CFG_t: 0x%08x\n", cim_readl(pcdev, DBG_DES)); ++ printk("HIST_WRBK_ADDR: 0x%08x\n", cim_readl(pcdev, DBG_DES)); ++ printk("SF_WRBK_ADDR: 0x%08x\n", cim_readl(pcdev, DBG_DES)); ++ printk("DBG_DMA: 0x%08x\n", cim_readl(pcdev, DBG_DMA)); ++ printk("***************************************\n\n"); ++} ++ ++void cim_dump_des(struct ingenic_camera_dev *pcdev) ++{ ++ struct ingenic_camera_desc *desc = (struct ingenic_camera_desc *)pcdev->desc_vaddr; ++ int i; ++ printk("\n***************************************\n"); ++ for(i = 0; i < pcdev->buf_cnt; i++) { ++ printk("print des %d\n",i); ++ printk("next: 0x%08x\n", desc[i].next); ++ printk("WRBK_ADDR: 0x%08x\n", desc[i].WRBK_ADDR); ++ printk("WRBK_STRD: 0x%08x\n", desc[i].WRBK_STRD); ++ printk("DES_INTC_t: 0x%08x\n", desc[i].DES_INTC_t.d32); ++ printk("DES_CFG_t: 0x%08x\n", desc[i].DES_CFG_t.d32); ++ printk("DES_HIST_CFG_t: 0x%08x\n", desc[i].DES_HIST_CFG_t.d32); ++ printk("HIST_WRBK_ADDR: 0x%08x\n", desc[i].HIST_WRBK_ADDR); ++ printk("SF_WRBK_ADDR: 0x%08x\n", desc[i].SF_WRBK_ADDR); ++ } ++ printk("***************************************\n\n"); ++} ++ ++static inline int timeval_sub_to_us(struct timeval lhs, ++ struct timeval rhs) ++{ ++ int sec, usec; ++ sec = lhs.tv_sec - rhs.tv_sec; ++ usec = lhs.tv_usec - rhs.tv_usec; ++ ++ return (sec*1000000 + usec); ++} ++ ++static inline int time_us2ms(int us) ++{ ++ return (us/1000); ++} ++ ++static void calculate_frame_rate(void) ++{ ++ static struct timeval time_now, time_last; ++ unsigned int interval_in_us; ++ unsigned int interval_in_ms; ++ static unsigned int fpsCount = 0; ++ ++ switch(showFPS){ ++ case 1: ++ fpsCount++; ++ do_gettimeofday(&time_now); ++ interval_in_us = timeval_sub_to_us(time_now, time_last); ++ if ( interval_in_us > (USEC_PER_SEC) ) { /* 1 second = 1000000 us. */ ++ printk(" CIM FPS: %d\n",fpsCount); ++ fpsCount = 0; ++ time_last = time_now; ++ } ++ break; ++ case 2: ++ do_gettimeofday(&time_now); ++ interval_in_us = timeval_sub_to_us(time_now, time_last); ++ interval_in_ms = time_us2ms(interval_in_us); ++ printk(" CIM tow frame interval ms: %d\n",interval_in_ms); ++ time_last = time_now; ++ break; ++ default: ++ if (showFPS > 2) { ++ int d, f; ++ fpsCount++; ++ do_gettimeofday(&time_now); ++ interval_in_us = timeval_sub_to_us(time_now, time_last); ++ if (interval_in_us > USEC_PER_SEC * showFPS ) { /* 1 second = 1000000 us. */ ++ d = fpsCount / showFPS; ++ f = (fpsCount * 10) / showFPS - d * 10; ++ printk(" CIM FPS: %d.%01d\n", d, f); ++ fpsCount = 0; ++ time_last = time_now; ++ } ++ } ++ break; ++ } ++} ++ ++static int ingenic_camera_querycap(struct soc_camera_host *ici, struct v4l2_capability *cap) ++{ ++ strlcpy(cap->card, "ingenic-Camera", sizeof(cap->card)); ++ cap->version = VERSION_CODE; ++ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; ++ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; ++ ++ return 0; ++} ++ ++static unsigned int ingenic_camera_poll(struct file *file, poll_table *pt) ++{ ++ struct soc_camera_device *icd = file->private_data; ++ ++ return vb2_poll(&icd->vb2_vidq, file, pt); ++} ++ ++static int ingenic_camera_alloc_desc(struct ingenic_camera_dev *pcdev, unsigned int count) ++{ ++ pcdev->buf_cnt = count; ++ pcdev->desc_vaddr = dma_alloc_coherent(pcdev->soc_host.v4l2_dev.dev, ++ sizeof(*pcdev->desc_paddr) * pcdev->buf_cnt, ++ (dma_addr_t *)&pcdev->desc_paddr, GFP_KERNEL); ++ ++ if (!pcdev->desc_paddr) ++ return -ENOMEM; ++ ++ return 0; ++} ++ ++static void ingenic_camera_free_desc(struct ingenic_camera_dev *pcdev) ++{ ++ if(pcdev && pcdev->desc_vaddr) { ++ dma_free_coherent(pcdev->soc_host.v4l2_dev.dev, ++ sizeof(*pcdev->desc_paddr) * pcdev->buf_cnt, ++ pcdev->desc_vaddr, (dma_addr_t )pcdev->desc_paddr); ++ ++ pcdev->desc_vaddr = NULL; ++ } ++} ++ ++static int ingenic_videobuf_setup(struct vb2_queue *vq, const void *parg, ++ unsigned int *num_buffers, unsigned int *nplanes, ++ unsigned int sizes[], void *alloc_ctxs[]) { ++ struct soc_camera_device *icd = soc_camera_from_vb2q(vq); ++ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); ++ struct ingenic_camera_dev *pcdev = ici->priv; ++ int size; ++ ++ if(pcdev->hist_en) ++ size = icd->sizeimage + CIM_HIST_SIZE; ++ else ++ size = icd->sizeimage; ++ ++ if (!*num_buffers || *num_buffers > MAX_BUFFER_NUM) ++ *num_buffers = MAX_BUFFER_NUM; ++ ++ if (size * *num_buffers > MAX_VIDEO_MEM) ++ *num_buffers = MAX_VIDEO_MEM / size; ++ ++ *nplanes = 1; ++ sizes[0] = size; ++ alloc_ctxs[0] = pcdev->alloc_ctx; ++ ++ pcdev->start_streaming_called = 0; ++ pcdev->sequence = 0; ++ pcdev->active = NULL; ++ ++ if(ingenic_camera_alloc_desc(pcdev, *num_buffers)) ++ return -ENOMEM; ++ dev_dbg(icd->parent, "%s, count=%d, size=%d\n", __func__, ++ *num_buffers, size); ++ ++ return 0; ++} ++ ++static int ingenic_init_desc(struct vb2_buffer *vb2) { ++ struct soc_camera_device *icd = soc_camera_from_vb2q(vb2->vb2_queue); ++ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); ++ struct ingenic_camera_dev *pcdev = ici->priv; ++ struct ingenic_camera_desc *desc; ++ dma_addr_t dma_address; ++ u32 index = vb2->index; ++ u32 pixfmt = icd->current_fmt->host_fmt->fourcc; ++ ++ desc = (struct ingenic_camera_desc *) pcdev->desc_vaddr; ++ ++ dma_address = *(dma_addr_t *)vb2_plane_cookie(vb2, 0); ++ if(!dma_address) { ++ dev_err(icd->parent, "Failed to setup DMA address\n"); ++ return -ENOMEM; ++ } ++ ++ desc[index].DES_CFG_t.data.ID = index; ++ desc[index].WRBK_ADDR = dma_address; ++ ++ switch (pixfmt){ ++ case V4L2_PIX_FMT_RGB565: ++ desc[index].DES_CFG_t.data.WRBK_FMT = WRBK_FMT_RGB565; ++ break; ++ case V4L2_PIX_FMT_RGB32: ++ desc[index].DES_CFG_t.data.WRBK_FMT = WRBK_FMT_RGB888; ++ break; ++ case V4L2_PIX_FMT_YUYV: ++ desc[index].DES_CFG_t.data.WRBK_FMT = WRBK_FMT_YUV422; ++ break; ++ case V4L2_PIX_FMT_GREY: ++ desc[index].DES_CFG_t.data.WRBK_FMT = WRBK_FMT_MONO; ++ break; ++ default: ++ dev_err(icd->parent, "No support format!\n"); ++ return -EINVAL; ++ } ++ ++ if(!pcdev->desc_head && ++ !pcdev->desc_tail) { ++ pcdev->desc_head = &desc[index]; ++ pcdev->desc_tail = &desc[index]; ++ desc[index].DES_INTC_t.data.EOF_MSK = 0; ++ desc[index].DES_CFG_t.data.DES_END = 1; ++ desc[index].next = 0; ++ } else if(pcdev->desc_head != NULL && ++ pcdev->desc_tail != NULL) { ++ pcdev->desc_tail->next = (dma_addr_t)(&pcdev->desc_paddr[index]); ++ pcdev->desc_tail->DES_INTC_t.data.EOF_MSK = 1; ++ pcdev->desc_tail->DES_CFG_t.data.DES_END = 0; ++ pcdev->desc_tail = &desc[index]; ++ ++ desc[index].DES_INTC_t.data.EOF_MSK = 0; ++ desc[index].DES_CFG_t.data.DES_END = 1; ++ desc[index].next = 0; ++ } ++ ++ if(!pcdev->hist_en) { ++ desc[index].DES_HIST_CFG_t.d32 = 0; ++ desc[index].HIST_WRBK_ADDR = 0; ++ } else { ++ if(pixfmt != V4L2_PIX_FMT_YUYV && ++ pixfmt != V4L2_PIX_FMT_GREY) { ++ dev_err(icd->parent,"fmt not support hist!\n"); ++ return -EINVAL; ++ } ++ desc[index].DES_HIST_CFG_t.HIST_EN = 1; ++ desc[index].DES_HIST_CFG_t.GAIN_MUL = pcdev->hist_gain_mul; ++ desc[index].DES_HIST_CFG_t.GAIN_ADD = pcdev->hist_gain_add; ++ desc[index].HIST_WRBK_ADDR ++ = desc[index].WRBK_ADDR + icd->sizeimage; ++ } ++ ++ if(!pcdev->interlace) { ++ desc[index].WRBK_STRD = icd->user_width; ++ desc[index].SF_WRBK_ADDR = 0; ++ } else { ++ desc[index].WRBK_STRD = icd->user_width * 2; ++ desc[index].SF_WRBK_ADDR = ++ desc[index].WRBK_ADDR + icd->user_width * 2; ++ } ++ ++ return 0; ++} ++ ++static int check_platform_param(struct ingenic_camera_dev *pcdev, ++ unsigned char buswidth, unsigned long *flags) ++{ ++ /* ++ * Platform specified synchronization and pixel clock polarities are ++ * only a recommendation and are only used during probing. The PXA270 ++ * quick capture interface supports both. ++ */ ++ *flags = V4L2_MBUS_MASTER | ++ V4L2_MBUS_HSYNC_ACTIVE_HIGH | ++ V4L2_MBUS_HSYNC_ACTIVE_LOW | ++ V4L2_MBUS_VSYNC_ACTIVE_HIGH | ++ V4L2_MBUS_VSYNC_ACTIVE_LOW | ++ V4L2_MBUS_DATA_ACTIVE_HIGH | ++ V4L2_MBUS_PCLK_SAMPLE_RISING | ++ V4L2_MBUS_PCLK_SAMPLE_FALLING; ++ ++ return 0; ++ ++} ++ ++static int ingenic_videobuf_init(struct vb2_buffer *vb2) ++{ ++ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb2); ++ struct ingenic_buffer *buf = container_of(vbuf, struct ingenic_buffer, vb); ++ ++ INIT_LIST_HEAD(&buf->list); ++ ++ return 0; ++} ++ ++static int is_cim_disabled(struct ingenic_camera_dev *pcdev) ++{ ++ return !(cim_readl(pcdev, CIM_ST) & CIM_ST_WORKING); ++} ++ ++static void ingenic_buffer_queue(struct vb2_buffer *vb2) ++{ ++ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb2); ++ struct soc_camera_device *icd = soc_camera_from_vb2q(vb2->vb2_queue); ++ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); ++ struct ingenic_camera_dev *pcdev = ici->priv; ++ struct ingenic_buffer *buf = container_of(vbuf, struct ingenic_buffer, vb); ++ struct ingenic_camera_desc *desc_v; ++ struct ingenic_camera_desc *desc_p; ++ unsigned long flags; ++ unsigned int regval; ++ int index = vb2->index; ++ ++ spin_lock_irqsave(&pcdev->lock, flags); ++ ++ list_add_tail(&buf->list, &pcdev->video_buffer_list); ++ if (!pcdev->active) { ++ pcdev->active = buf; ++ } ++ ++ if(!pcdev->start_streaming_called) { ++ goto out; ++ } ++ ++ if((index > pcdev->buf_cnt) || (index < 0)) { ++ dev_err(icd->parent,"Warning: index %d out of range!\n", index); ++ goto out; ++ } ++ ++ desc_v = (struct ingenic_camera_desc *) pcdev->desc_vaddr; ++ desc_p = pcdev->desc_paddr; ++ ++ if(is_cim_disabled(pcdev) && list_is_singular(&pcdev->video_buffer_list)) { ++ desc_v[index].DES_CFG_t.data.DES_END = 1; ++ desc_v[index].DES_INTC_t.data.EOF_MSK = 0; ++ ++ pcdev->desc_head = &desc_v[index]; ++ pcdev->desc_tail = &desc_v[index]; ++ ++ regval = (dma_addr_t)(&desc_p[index]); ++ cim_writel(pcdev, regval, DES_ADDR); ++ cim_writel(pcdev, CIM_CTRL_START, CIM_CTRL); ++ } else { ++ pcdev->desc_tail->next = (dma_addr_t)(&desc_p[index]); ++ pcdev->desc_tail->DES_INTC_t.data.EOF_MSK = 1; ++ pcdev->desc_tail->DES_CFG_t.data.DES_END = 0; ++ pcdev->desc_tail = &desc_v[index]; ++ ++ desc_v[index].DES_CFG_t.data.DES_END = 1; ++ desc_v[index].DES_INTC_t.data.EOF_MSK = 0; ++ } ++ ++out: ++ spin_unlock_irqrestore(&pcdev->lock, flags); ++ ++ if(showFPS){ ++ calculate_frame_rate(); ++ } ++ ++ return; ++} ++ ++static int ingenic_buffer_prepare(struct vb2_buffer *vb) ++{ ++ struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); ++ int ret = 0; ++ ++ dev_vdbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, ++ vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); ++ ++ vb2_set_plane_payload(vb, 0, icd->sizeimage); ++ if (vb2_plane_vaddr(vb, 0) && ++ vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) { ++ ret = -EINVAL; ++ return ret; ++ } ++ ++ return 0; ++ ++} ++ ++static void ingenic_cim_start(struct ingenic_camera_dev *pcdev) ++{ ++ struct vb2_buffer *vb2 = &pcdev->active->vb.vb2_buf; ++ unsigned regval = 0; ++ int index; ++ ++ BUG_ON(!pcdev->active); ++ ++ /* clear status register */ ++ cim_writel(pcdev, CIM_CLR_ALL, CIM_CLR_ST); ++ ++ /* configure dma desc addr*/ ++ index = vb2->index; ++ regval = (dma_addr_t)(&(pcdev->desc_paddr[index])); ++ cim_writel(pcdev, regval, DES_ADDR); ++ ++ cim_writel(pcdev, CIM_CTRL_START, CIM_CTRL); ++} ++ ++static void ingenic_cim_stop(struct ingenic_camera_dev *pcdev) ++{ ++ cim_writel(pcdev, CIM_CTRL_QCK_STOP, CIM_CTRL); ++ cim_writel(pcdev, CIM_CLR_ALL, CIM_CLR_ST); ++} ++ ++static int ingenic_cim_soft_reset(struct soc_camera_device *icd) { ++ struct v4l2_subdev *sd = soc_camera_to_subdev(icd); ++ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); ++ struct ingenic_camera_dev *pcdev = ici->priv; ++ int count = 4000; ++ ++ v4l2_subdev_call(sd, video, s_stream, 1); ++ ++ cim_writel(pcdev, CIM_CTRL_SOFT_RST, CIM_CTRL); ++ while((!(cim_readl(pcdev,CIM_ST) & CIM_ST_SRST)) && count--) { ++ udelay(1000); ++ } ++ ++ if (count < 0) { ++ dev_err(icd->parent, "cim soft reset failed!\n"); ++ v4l2_subdev_call(sd, video, s_stream, 0); ++ return -ENODEV; ++ } ++ cim_writel(pcdev,CIM_CLR_SRST,CIM_CLR_ST); ++ ++ return 0; ++} ++ ++static int ingenic_start_streaming(struct vb2_queue *q, unsigned int count) ++{ ++ struct soc_camera_device *icd = soc_camera_from_vb2q(q); ++ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); ++ struct ingenic_camera_dev *pcdev = ici->priv; ++ struct ingenic_buffer *buf, *node; ++ unsigned long flags; ++ int ret; ++ ++ list_for_each_entry_safe(buf, node, &pcdev->video_buffer_list, list) { ++ ret = ingenic_init_desc(&buf->vb.vb2_buf); ++ if(ret) { ++ dev_err(icd->parent, "%s:Desc initialization failed\n", ++ __func__); ++ return ret; ++ } ++ } ++ ++ ret = ingenic_cim_soft_reset(icd); ++ if(ret) ++ return ret; ++ ++ spin_lock_irqsave(&pcdev->lock, flags); ++ ingenic_cim_start(pcdev); ++ pcdev->start_streaming_called = 1; ++ spin_unlock_irqrestore(&pcdev->lock, flags); ++ ++ return 0; ++} ++ ++static void ingenic_stop_streaming(struct vb2_queue *q) ++{ ++ struct soc_camera_device *icd = soc_camera_from_vb2q(q); ++ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); ++ struct ingenic_camera_dev *pcdev = ici->priv; ++ struct ingenic_buffer *buf, *node; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&pcdev->lock, flags); ++ ingenic_cim_stop(pcdev); ++ ++ /* Release all active buffers */ ++ list_for_each_entry_safe(buf, node, &pcdev->video_buffer_list, list) { ++ list_del_init(&buf->list); ++ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); ++ } ++ ++ pcdev->start_streaming_called = 0; ++ pcdev->desc_head = NULL; ++ pcdev->desc_tail = NULL; ++ pcdev->active = NULL; ++ ++ spin_unlock_irqrestore(&pcdev->lock, flags); ++} ++ ++static struct vb2_ops ingenic_videobuf2_ops = { ++ .buf_init = ingenic_videobuf_init, ++ .queue_setup = ingenic_videobuf_setup, ++ .buf_prepare = ingenic_buffer_prepare, ++ .buf_queue = ingenic_buffer_queue, ++ .start_streaming = ingenic_start_streaming, ++ .stop_streaming = ingenic_stop_streaming, ++ .wait_prepare = vb2_ops_wait_prepare, ++ .wait_finish = vb2_ops_wait_finish, ++}; ++ ++static int ingenic_camera_init_videobuf2(struct vb2_queue *q, struct soc_camera_device *icd) { ++ ++ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ q->io_modes = VB2_MMAP | VB2_USERPTR; ++ q->drv_priv = icd; ++ q->buf_struct_size = sizeof(struct ingenic_buffer); ++ q->ops = &ingenic_videobuf2_ops; ++ q->mem_ops = &vb2_dma_contig_memops; ++ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ++ ++ return vb2_queue_init(q); ++} ++ ++static int ingenic_camera_cropcap(struct soc_camera_device *icd, struct v4l2_cropcap *a) ++{ ++ struct v4l2_subdev *sd = soc_camera_to_subdev(icd); ++ ++ return v4l2_subdev_call(sd, video, cropcap, a); ++} ++ ++static int ingenic_camera_get_crop(struct soc_camera_device *icd, struct v4l2_crop *a) ++{ ++ struct v4l2_subdev *sd = soc_camera_to_subdev(icd); ++ struct v4l2_rect *rect = &a->c; ++ struct ingenic_image_sz *img_sz = icd->host_priv; ++ int ret = 0; ++ ++ switch(img_sz->rsz_way) { ++ case IMG_RESIZE_CROP: ++ rect->left = img_sz->c_left; ++ rect->top = img_sz->c_top; ++ rect->width = img_sz->c_w; ++ rect->height = img_sz->c_h; ++ break; ++ case IMG_NO_RESIZE: ++ ret = v4l2_subdev_call(sd, video, g_crop, a); ++ break; ++ default: ++ dev_err(icd->parent,"resize way not supported!\n"); ++ return -EINVAL; ++ } ++ ++ return ret; ++} ++ ++static int ingenic_camera_enum_framesizes(struct soc_camera_device *icd, ++ struct v4l2_frmsizeenum *fsize) ++{ ++ int ret; ++ struct v4l2_subdev *sd = soc_camera_to_subdev(icd); ++ const struct soc_camera_format_xlate *xlate; ++ struct v4l2_subdev_frame_size_enum fse = { ++ .index = fsize->index, ++ .which = V4L2_SUBDEV_FORMAT_ACTIVE, ++ }; ++ ++ xlate = soc_camera_xlate_by_fourcc(icd, fsize->pixel_format); ++ if (!xlate) ++ return -EINVAL; ++ fse.code = xlate->code; ++ ++ ret = v4l2_subdev_call(sd, pad, enum_frame_size, NULL, &fse); ++ if (ret < 0) ++ return ret; ++ ++ if (fse.min_width == fse.max_width && ++ fse.min_height == fse.max_height) { ++ fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; ++ fsize->discrete.width = fse.min_width; ++ fsize->discrete.height = fse.min_height; ++ return 0; ++ } ++ fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; ++ fsize->stepwise.min_width = fse.min_width; ++ fsize->stepwise.max_width = fse.max_width; ++ fsize->stepwise.min_height = fse.min_height; ++ fsize->stepwise.max_height = fse.max_height; ++ fsize->stepwise.step_width = 1; ++ fsize->stepwise.step_height = 1; ++ return 0; ++} ++ ++static int ingenic_camera_check_crop(struct soc_camera_device *icd, struct v4l2_rect *r) ++{ ++ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); ++ struct ingenic_camera_dev *pcdev = ici->priv; ++ struct v4l2_rect rect_w = *r; ++ u32 pixfmt = icd->current_fmt->host_fmt->fourcc; ++ ++ if(pcdev->field != V4L2_FIELD_NONE) { ++ dev_err(icd->parent, "field not supported by crop!\n"); ++ return -EINVAL; ++ } ++ ++ if((rect_w.width + rect_w.left > 2046) || ++ (rect_w.height + rect_w.top > 2046)) { ++ dev_err(icd->parent, "crop bounds check failed!\n"); ++ return -EINVAL; ++ } ++ ++ v4l_bound_align_image(&rect_w.width, 100, 2046, ++ (pixfmt == V4L2_PIX_FMT_YUYV ? 1 : 0), ++ &rect_w.height, 100, 2046, 0, 0); ++ if((rect_w.width != r->width) || ++ (rect_w.height != r->height)) { ++ dev_err(icd->parent, "crop sizes check failed!\n"); ++ return -EINVAL; ++ } ++ ++ if((pixfmt == V4L2_PIX_FMT_YUYV) ++ && (rect_w.left % 2)) { ++ dev_err(icd->parent, "crop align check failed!\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int ingenic_camera_set_host_crop(struct soc_camera_device *icd, const struct v4l2_crop *a) ++{ ++ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); ++ struct v4l2_subdev *sd = soc_camera_to_subdev(icd); ++ struct ingenic_camera_dev *pcdev = ici->priv; ++ struct ingenic_image_sz *img_sz = icd->host_priv; ++ struct v4l2_crop a_w = *a; ++ struct v4l2_rect *rect_s = &a_w.c; ++ struct v4l2_rect rect_w = *rect_s; ++ struct v4l2_subdev_format format = { ++ .which = V4L2_SUBDEV_FORMAT_TRY, ++ }; ++ struct v4l2_mbus_framefmt *mf = &format.format; ++ unsigned int tmp; ++ int width, height; ++ int ret; ++ ++ ++ ret = ingenic_camera_check_crop(icd, &rect_w); ++ if (ret) ++ return ret; ++ ++ width = img_sz->src_w; ++ height = img_sz->src_h; ++ ++ if(((rect_w.left + rect_w.width) > width) || ++ ((rect_w.top + rect_w.height) > height)) { ++ dev_err(icd->parent, "please enum appropriate framesizes!\n"); ++ return -EINVAL; ++ } ++ ++ ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &format); ++ if (ret < 0) ++ return ret; ++ ++ mf->width = width; ++ mf->height = height; ++ ++ ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &format); ++ if (ret < 0) ++ return ret; ++ ++ if ((mf->width != width) || ++ (mf->height != height)) { ++ dev_err(icd->parent, "please enum appropriate framesizes!\n"); ++ return -EINVAL; ++ } ++ ++ if (mf->code != icd->current_fmt->code) { ++ dev_err(icd->parent, "current size and format do not match!\n"); ++ return -EINVAL; ++ } ++ ++ icd->user_width = rect_s->width; ++ icd->user_height = rect_s->height; ++ ++ img_sz->rsz_way = IMG_RESIZE_CROP; ++ img_sz->src_w = mf->width; ++ img_sz->src_h = mf->height; ++ img_sz->c_left = rect_w.left; ++ img_sz->c_top = rect_w.top; ++ img_sz->c_w = rect_s->width; ++ img_sz->c_h = rect_s->height; ++ ++ tmp = (img_sz->c_w << CIM_CROP_WIDTH_LBIT) | ++ (img_sz->c_h << CIM_CROP_HEIGHT_LBIT); ++ cim_writel(pcdev, tmp, FRM_SIZE); ++ tmp = (img_sz->c_left << CIM_CROP_X_LBIT) | ++ (img_sz->c_top << CIM_CROP_Y_LBIT); ++ cim_writel(pcdev, tmp, CROP_SITE); ++ ++ return ret; ++} ++ ++static int ingenic_camera_set_client_crop(struct soc_camera_device *icd, const struct v4l2_crop *a) ++{ ++ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); ++ struct v4l2_subdev *sd = soc_camera_to_subdev(icd); ++ struct ingenic_camera_dev *pcdev = ici->priv; ++ struct ingenic_image_sz *img_sz = icd->host_priv; ++ struct v4l2_subdev_format format = { ++ .which = V4L2_SUBDEV_FORMAT_TRY, ++ }; ++ struct v4l2_mbus_framefmt *mf = &format.format; ++ unsigned int tmp; ++ int ret; ++ ++ ret = v4l2_subdev_call(sd, video, s_crop, a); ++ if (ret < 0) ++ return ret; ++ ++ /* The capture device might have changed its output */ ++ ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &format); ++ if (ret < 0) ++ return ret; ++ ++ dev_dbg(icd->parent, "Sensor cropped %dx%d\n", ++ mf->width, mf->height); ++ ++ icd->user_width = mf->width; ++ icd->user_height = mf->height; ++ ++ img_sz->rsz_way = IMG_NO_RESIZE; ++ img_sz->src_w = mf->width; ++ img_sz->src_h = mf->height; ++ tmp = (img_sz->src_w << CIM_CROP_WIDTH_LBIT) | ++ (img_sz->src_h << CIM_CROP_HEIGHT_LBIT); ++ cim_writel(pcdev, tmp, FRM_SIZE); ++ cim_writel(pcdev, 0, CROP_SITE); ++ ++ return ret; ++} ++ ++static int ingenic_camera_set_crop(struct soc_camera_device *icd, const struct v4l2_crop *a) ++{ ++ int ret; ++ ++ ret = ingenic_camera_set_client_crop(icd, a); ++ if(!ret) ++ return ret; ++ /*sensor not support crop*/ ++ return ingenic_camera_set_host_crop(icd, a); ++} ++ ++static int ingenic_camera_get_selection(struct soc_camera_device *icd, struct v4l2_selection *sel) ++{ ++ struct v4l2_subdev *sd = soc_camera_to_subdev(icd); ++ struct v4l2_cropcap a; ++ int ret; ++ ++ if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ ++ ret = v4l2_subdev_call(sd, video, cropcap, &a); ++ if(ret) ++ return ret; ++ ++ switch (sel->target) { ++ case V4L2_SEL_TGT_CROP_BOUNDS: ++ sel->r = a.bounds; ++ return 0; ++ case V4L2_SEL_TGT_CROP_DEFAULT: ++ sel->r = a.defrect; ++ return 0; ++ } ++ ++ return -EINVAL; ++} ++ ++static int ingenic_camera_set_selection(struct soc_camera_device *icd, struct v4l2_selection *sel) ++{ ++ return 0; ++} ++ ++static int ingenic_camera_try_fmt(struct soc_camera_device *icd, struct v4l2_format *f) { ++ struct v4l2_subdev *sd = soc_camera_to_subdev(icd); ++ const struct soc_camera_format_xlate *xlate; ++ struct v4l2_pix_format *pix = &f->fmt.pix; ++ struct v4l2_subdev_pad_config pad_cfg; ++ struct v4l2_subdev_format format = { ++ .which = V4L2_SUBDEV_FORMAT_TRY, ++ }; ++ struct v4l2_mbus_framefmt *mf = &format.format; ++ __u32 pixfmt = pix->pixelformat; ++ int ret; ++ ++ xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); ++ if (!xlate) { ++ dev_err(icd->parent,"Format %x not found\n", pix->pixelformat); ++ return -EINVAL; ++ } ++ ++ v4l_bound_align_image(&pix->width, 100, 2046, ++ (pixfmt == V4L2_PIX_FMT_YUYV ? 1 : 0), ++ &pix->height, 100, 2046, 0, 0); ++ ++ mf->width = pix->width; ++ mf->height = pix->height; ++ mf->field = pix->field; ++ mf->colorspace = pix->colorspace; ++ mf->code = xlate->code; ++ ++ /* limit to sensor capabilities */ ++ ret = v4l2_subdev_call(sd, pad, set_fmt, &pad_cfg, &format); ++ if (ret < 0) ++ return ret; ++ ++ if ((mf->width < pix->width) || ++ (mf->height < pix->height)) { ++ dev_err(icd->parent, "fmt not supported!\n"); ++ return -EINVAL; ++ } ++ ++ pix->field = mf->field; ++ pix->colorspace = mf->colorspace; ++ ++ return 0; ++} ++ ++static int ingenic_camera_set_fmt(struct soc_camera_device *icd, struct v4l2_format *f) { ++ struct v4l2_subdev *sd = soc_camera_to_subdev(icd); ++ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); ++ struct ingenic_camera_dev *pcdev = ici->priv; ++ const struct soc_camera_format_xlate *xlate; ++ struct v4l2_pix_format *pix = &f->fmt.pix; ++ struct ingenic_image_sz *img_sz = icd->host_priv; ++ struct v4l2_subdev_format format = { ++ .which = V4L2_SUBDEV_FORMAT_ACTIVE, ++ }; ++ struct v4l2_mbus_framefmt *mf = &format.format; ++ int ret; ++ ++ xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); ++ if (!xlate) { ++ dev_err(icd->parent, "Format %x not found\n", pix->pixelformat); ++ return -EINVAL; ++ } ++ ++ mf->width = pix->width; ++ mf->height = pix->height; ++ mf->field = pix->field; ++ mf->colorspace = pix->colorspace; ++ mf->code = xlate->code; ++ ++ ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &format); ++ if (ret < 0) ++ return ret; ++ ++ if (mf->code != xlate->code) ++ return -EINVAL; ++ ++ img_sz->src_w = mf->width; ++ img_sz->src_h = mf->height; ++ ++ /*when set_crop before set_fmt, entry first if*/ ++ if(unlikely(img_sz->rsz_way == IMG_RESIZE_CROP)) { ++ dev_err(icd->parent, "Set_crop should be behind set_fmt!\n"); ++ return -EINVAL; ++ } else { ++ img_sz->rsz_way = IMG_NO_RESIZE; ++ if((pix->width != mf->width) || (pix->height != mf->height)) ++ printk("image will be crop by cim\n"); ++ } ++ pix->field = mf->field; ++ pix->colorspace = mf->colorspace; ++ ++ pcdev->field = mf->field; ++ icd->current_fmt = xlate; ++ ++ return ret; ++} ++ ++static int ingenic_get_dvp_mbus_config(struct soc_camera_device *icd, unsigned long *flags) { ++ struct v4l2_subdev *sd = soc_camera_to_subdev(icd); ++ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); ++ struct ingenic_camera_dev *pcdev = ici->priv; ++ struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; ++ unsigned long common_flags; ++ unsigned long bus_flags = 0; ++ int ret; ++ ++ check_platform_param(pcdev, icd->current_fmt->host_fmt->bits_per_sample, ++ &bus_flags); ++ ++ ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); ++ if (!ret) { ++ if(cfg.type != V4L2_MBUS_PARALLEL) { ++ dev_err(icd->parent, "Device type error!\n"); ++ return -EINVAL; ++ } ++ common_flags = soc_mbus_config_compatible(&cfg, ++ bus_flags); ++ if (!common_flags) { ++ dev_warn(icd->parent, ++ "Flags incompatible: camera 0x%x, host 0x%lx\n", ++ cfg.flags, bus_flags); ++ return -EINVAL; ++ } ++ } else if (ret != -ENOIOCTLCMD) { ++ return ret; ++ } else { ++ common_flags = bus_flags; ++ } ++ ++ /* Make choises, based on platform preferences */ ++ ++ if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) && ++ (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) { ++ if (pcdev->pdata->flags & INGENIC_CAMERA_VSYNC_HIGH) ++ common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW; ++ else ++ common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH; ++ } ++ ++ if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && ++ (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { ++ if (pcdev->pdata->flags & INGENIC_CAMERA_PCLK_RISING) ++ common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; ++ else ++ common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; ++ } ++ ++ if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) && ++ (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) { ++ if (pcdev->pdata->flags & INGENIC_CAMERA_HSYNC_HIGH) ++ common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW; ++ else ++ common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH; ++ } ++ ++ cfg.flags = common_flags; ++ ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); ++ if (ret < 0 && ret != -ENOIOCTLCMD) { ++ dev_dbg(icd->parent, "camera s_mbus_config(0x%lx) returned %d\n", ++ common_flags, ret); ++ return ret; ++ } ++ ++ *flags = common_flags; ++ ++ return 0; ++} ++ ++static int ingenic_get_itu656_mbus_config(struct soc_camera_device *icd, unsigned long *flags) { ++ struct v4l2_subdev *sd = soc_camera_to_subdev(icd); ++ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); ++ struct ingenic_camera_dev *pcdev = ici->priv; ++ struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_BT656,}; ++ unsigned long common_flags; ++ unsigned long bus_flags = 0; ++ int ret; ++ ++ ++ bus_flags = V4L2_MBUS_PCLK_SAMPLE_RISING | ++ V4L2_MBUS_PCLK_SAMPLE_FALLING | ++ V4L2_MBUS_DATA_ACTIVE_HIGH | ++ V4L2_MBUS_DATA_ACTIVE_LOW | ++ V4L2_MBUS_MASTER | ++ V4L2_MBUS_SLAVE; ++ ++ ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); ++ if (!ret) { ++ if(cfg.type != V4L2_MBUS_BT656) { ++ dev_err(icd->parent, "Device type error!\n"); ++ return -EINVAL; ++ } ++ common_flags = soc_mbus_config_compatible(&cfg, ++ bus_flags); ++ if (!common_flags) { ++ dev_warn(icd->parent, ++ "Flags incompatible: camera 0x%x, host 0x%lx\n", ++ cfg.flags, bus_flags); ++ return -EINVAL; ++ } ++ } else if (ret != -ENOIOCTLCMD) { ++ return ret; ++ } else { ++ common_flags = bus_flags; ++ } ++ ++ /* Make choises, based on platform preferences */ ++ ++ if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && ++ (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { ++ if (pcdev->pdata->flags & INGENIC_CAMERA_PCLK_RISING) ++ common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; ++ else ++ common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; ++ } ++ ++ cfg.flags = common_flags; ++ ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); ++ if (ret < 0 && ret != -ENOIOCTLCMD) { ++ dev_dbg(icd->parent, "camera s_mbus_config(0x%lx) returned %d\n", ++ common_flags, ret); ++ return ret; ++ } ++ ++ *flags = common_flags; ++ ++ return 0; ++} ++ ++static int ingenic_get_csi2_mbus_config(struct soc_camera_device *icd, ++ unsigned long *flags) { ++ struct v4l2_subdev *sd = soc_camera_to_subdev(icd); ++ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); ++ struct ingenic_camera_dev *pcdev = ici->priv; ++ struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_CSI2,}; ++ unsigned long common_flags; ++ unsigned long csi2_flags; ++ int ret; ++ ++ csi2_flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK | ++ V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK | ++ V4L2_MBUS_CSI2_2_LANE | ++ V4L2_MBUS_CSI2_1_LANE; ++ ++ ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); ++ if (!ret) { ++ if(cfg.type != V4L2_MBUS_CSI2) { ++ dev_err(icd->parent, "Device type error!\n"); ++ return -EINVAL; ++ } ++ common_flags = soc_mbus_config_compatible(&cfg, csi2_flags); ++ if (!common_flags) { ++ dev_warn(icd->parent, ++ "Flags incompatible: camera 0x%x, host 0x%lx\n", ++ cfg.flags, csi2_flags); ++ return -EINVAL; ++ } ++ } else if (ret != -ENOIOCTLCMD) { ++ return ret; ++ } else { ++ common_flags = csi2_flags; ++ } ++ ++ if ((common_flags & V4L2_MBUS_CSI2_1_LANE) && ++ (common_flags & V4L2_MBUS_CSI2_2_LANE)) { ++ if (pcdev->pdata->flags & INGENIC_CAMERA_CSI2_2_LANE) ++ common_flags &= ~V4L2_MBUS_CSI2_1_LANE; ++ else ++ common_flags &= ~V4L2_MBUS_CSI2_2_LANE; ++ } ++ ++ if (!common_flags) ++ return -EINVAL; ++ ++ cfg.flags = common_flags; ++ ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); ++ if (ret < 0 && ret != -ENOIOCTLCMD) { ++ dev_dbg(icd->parent, "camera s_mbus_config(0x%lx) returned %d\n", ++ common_flags, ret); ++ return ret; ++ } ++ ++ *flags = common_flags; ++ ++ return 0; ++} ++ ++static struct soc_camera_device *ctrl_to_icd(struct v4l2_ctrl *ctrl) ++{ ++ return container_of(ctrl->handler, struct soc_camera_device, ++ ctrl_handler); ++} ++ ++static int ingenic_camera_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct soc_camera_device *icd = ctrl_to_icd(ctrl); ++ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); ++ struct ingenic_camera_dev *pcdev = ici->priv; ++ struct ingenic_image_sz *img_sz = icd->host_priv; ++ struct ingenic_camera_desc *desc; ++ unsigned int tmp; ++ int i; ++ ++ switch (ctrl->id) { ++ case INGENIC_CID_CROP_WAY: ++ img_sz->crop_way = ctrl->val; ++ break; ++ case INGENIC_CID_HIST_EN: ++ pcdev->hist_en = 1; ++ break; ++ case INGENIC_CID_HIST_GAIN_ADD: ++ pcdev->hist_gain_add = ctrl->val; ++ desc = (struct ingenic_camera_desc *) pcdev->desc_vaddr; ++ if(!pcdev->hist_en || !desc) { ++ dev_dbg(icd->parent, "setting hist_add are not satisfied!\n"); ++ return 0; ++ } ++ for(i = 0; i < pcdev->buf_cnt; i++) ++ desc[i].DES_HIST_CFG_t.GAIN_ADD = pcdev->hist_gain_add; ++ break; ++ case INGENIC_CID_HIST_GAIN_MUL: ++ pcdev->hist_gain_mul = ctrl->val; ++ desc = (struct ingenic_camera_desc *) pcdev->desc_vaddr; ++ if(!pcdev->hist_en || !desc) { ++ dev_dbg(icd->parent, "setting hist_mul are not satisfied!\n"); ++ return 0; ++ } ++ for(i = 0; i < pcdev->buf_cnt; i++) ++ desc[i].DES_HIST_CFG_t.GAIN_MUL = pcdev->hist_gain_mul; ++ break; ++ default: ++ dev_err(icd->parent, "ctrl id not supported!\n"); ++ break; ++ } ++ return 0; ++} ++ ++static const struct v4l2_ctrl_ops ingenic_camera_ctrl_ops = { ++ .s_ctrl = ingenic_camera_s_ctrl, ++}; ++ ++static const struct v4l2_ctrl_config img_crop_way = { ++ .ops = &ingenic_camera_ctrl_ops, ++ .id = INGENIC_CID_CROP_WAY, ++ .name = "crop way", ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ .def = CROP_SPECIFY_ZONE, ++ .min = CROP_SPECIFY_ZONE, ++ .max = CROP_BASE_MAX_PIC, ++ .step = 1, ++}; ++ ++static const struct v4l2_ctrl_config hist_en = { ++ .ops = &ingenic_camera_ctrl_ops, ++ .id = INGENIC_CID_HIST_EN, ++ .type = V4L2_CTRL_TYPE_BUTTON, ++ .name = "histgram enable", ++}; ++ ++static const struct v4l2_ctrl_config hist_gain_add = { ++ .ops = &ingenic_camera_ctrl_ops, ++ .id = INGENIC_CID_HIST_GAIN_ADD, ++ .name = "hist gain add", ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ .def = 0, ++ .min = 0, ++ .max = 0xff, ++ .step = 1, ++}; ++ ++static const struct v4l2_ctrl_config hist_gain_mul = { ++ .ops = &ingenic_camera_ctrl_ops, ++ .id = INGENIC_CID_HIST_GAIN_MUL, ++ .name = "hist gain mul", ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ .def = 0x20, ++ .min = 0, ++ .max = 0xff, ++ .step = 1, ++}; ++ ++static const struct soc_mbus_pixelfmt ingenic_camera_formats[] = { ++ [0] = { ++ .fourcc = V4L2_PIX_FMT_RGB32, ++ .name = "RGB888/32bpp", ++ .bits_per_sample = 8, ++ .packing = SOC_MBUS_PACKING_EXTEND32, ++ .order = SOC_MBUS_ORDER_LE, ++ }, ++}; ++ ++ ++static int ingenic_camera_get_formats(struct soc_camera_device *icd, unsigned int idx, ++ struct soc_camera_format_xlate *xlate) ++{ ++ struct v4l2_subdev *sd = soc_camera_to_subdev(icd); ++ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); ++ struct ingenic_camera_dev *pcdev = ici->priv; ++ struct device *dev = icd->parent; ++ struct ingenic_image_sz *img_sz; ++ struct v4l2_subdev_mbus_code_enum code = { ++ .which = V4L2_SUBDEV_FORMAT_ACTIVE, ++ .index = idx, ++ }; ++ const struct soc_mbus_pixelfmt *fmt; ++ int formats = 0, ret; ++ int buswidth; ++ ++ ret = v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code); ++ if (ret < 0) ++ /* No more formats */ ++ return 0; ++ ++ fmt = soc_mbus_get_fmtdesc(code.code); ++ if (!fmt) { ++ dev_dbg(icd->parent, ++ "Unsupported format code #%u: %d\n", idx, code.code); ++ return 0; ++ } ++ ++ buswidth = fmt->bits_per_sample; ++ if (buswidth > 8) { ++ dev_dbg(icd->parent, "bits-per-sample %d for code %x unsupported\n", ++ buswidth, code.code); ++ return 0; ++ } ++ ++ if (!icd->host_priv) { ++ struct v4l2_mbus_config cfg; ++ ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); ++ if(!ret) ++ pcdev->dat_if = cfg.type; ++ else ++ return ret; ++ v4l2_ctrl_new_custom(&icd->ctrl_handler, &img_crop_way, NULL); ++ v4l2_ctrl_new_custom(&icd->ctrl_handler, &hist_en, NULL); ++ v4l2_ctrl_new_custom(&icd->ctrl_handler, &hist_gain_add, NULL); ++ v4l2_ctrl_new_custom(&icd->ctrl_handler, &hist_gain_mul, NULL); ++ if (icd->ctrl_handler.error) ++ return icd->ctrl_handler.error; ++ img_sz = kzalloc(sizeof(*img_sz), GFP_KERNEL); ++ if(!img_sz) ++ return -ENOMEM; ++ icd->host_priv = img_sz; ++ } ++ ++ switch (code.code) { ++ case MEDIA_BUS_FMT_UYVY8_2X8: ++ case MEDIA_BUS_FMT_VYUY8_2X8: ++ case MEDIA_BUS_FMT_YUYV8_2X8: ++ case MEDIA_BUS_FMT_YVYU8_2X8: ++ case MEDIA_BUS_FMT_Y8_1X8: ++ break; ++ case MEDIA_BUS_FMT_RGB565_2X8_LE: ++ formats++; ++ if (xlate) { ++ xlate->host_fmt = &ingenic_camera_formats[0]; ++ xlate->code = code.code; ++ xlate++; ++ dev_dbg(dev, "Providing format %s using code %d\n", ++ ingenic_camera_formats[0].name, code.code); ++ } ++ break; ++ default: ++ dev_dbg(dev, "Providing code %d not support\n", code.code); ++ return 0; ++ } ++ ++ /* Generic pass-through */ ++ formats++; ++ if (xlate) { ++ xlate->host_fmt = fmt; ++ xlate->code = code.code; ++ xlate++; ++ dev_dbg(dev, "Format %s pass-through mode\n", ++ fmt->name); ++ } ++ ++ return formats; ++} ++ ++static void ingenic_camera_put_formats(struct soc_camera_device *icd) ++{ ++ kfree(icd->host_priv); ++ icd->host_priv = NULL; ++} ++ ++static int ingenic_camera_set_bus_param(struct soc_camera_device *icd) { ++ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); ++ struct ingenic_camera_dev *pcdev = ici->priv; ++ struct ingenic_image_sz *img_sz = icd->host_priv; ++ struct v4l2_subdev *sd = soc_camera_to_subdev(icd); ++ struct v4l2_mbus_config cfg; ++ unsigned long common_flags; ++ unsigned long csi2_flags; ++ unsigned long glb_cfg = 0; ++ unsigned long intc = 0; ++ unsigned long tmp; ++ int csi2_lanes; ++ int ret; ++ ++ ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); ++ pcdev->dat_if = cfg.type; ++ ++ if(pcdev->dat_if == V4L2_MBUS_CSI2) { ++ ret = ingenic_get_csi2_mbus_config(icd, &csi2_flags); ++ if(ret) { ++ dev_err(icd->parent, "get csi mbus_config failed!\n"); ++ return ret; ++ } ++ ++ if(csi2_flags & V4L2_MBUS_CSI2_2_LANE) ++ csi2_lanes = 2; ++ else if(csi2_flags & V4L2_MBUS_CSI2_1_LANE) ++ csi2_lanes = 1; ++ else { ++ dev_err(icd->parent, "csi lanes not supported!\n"); ++ return -EINVAL; ++ } ++ ++ if(icd->current_fmt->code == MEDIA_BUS_FMT_Y8_1X8 && ++ csi2_lanes == 2) { ++ dev_err(icd->parent, "grey not support two lanes!\n"); ++ return ret; ++ } ++ ++ ret = csi_phy_start(0, 24000000, csi2_lanes); ++ if(ret < 0) { ++ dev_err(icd->parent, "csi starting failed!\n"); ++ return ret; ++ } ++ ++ /***Csi2 interface requirements***/ ++ common_flags = V4L2_MBUS_MASTER | ++ V4L2_MBUS_HSYNC_ACTIVE_HIGH | ++ V4L2_MBUS_VSYNC_ACTIVE_HIGH | ++ V4L2_MBUS_PCLK_SAMPLE_RISING; ++ ++ } else if(pcdev->dat_if == V4L2_MBUS_PARALLEL) { ++ ret = ingenic_get_dvp_mbus_config(icd, &common_flags); ++ if(ret) { ++ dev_err(icd->parent, "Get dvp mbus_config failed!\n"); ++ return ret; ++ } ++ } else if(pcdev->dat_if == V4L2_MBUS_BT656) { ++ ret = ingenic_get_itu656_mbus_config(icd, &common_flags); ++ if(ret) { ++ dev_err(icd->parent, "Get bt656 mbus_config failed!\n"); ++ return ret; ++ } ++ if(common_flags & V4L2_MBUS_SLAVE) { ++ dev_err(icd->parent, "bt656_mbus slave mode not supported!\n"); ++ return ret; ++ } ++ } else { ++ dev_err(icd->parent, "cim interface not supported!\n"); ++ return -EINVAL; ++ } ++ ++ glb_cfg = cim_readl(pcdev,GLB_CFG); ++ ++ /*PCLK Polarity Set*/ ++ glb_cfg = (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) ? ++ (glb_cfg | GLB_CFG_DE_PCLK) : (glb_cfg & (~GLB_CFG_DE_PCLK)); ++ ++ /*VSYNC Polarity Set*/ ++ glb_cfg = (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) ? ++ (glb_cfg | GLB_CFG_DL_VSYNC) : (glb_cfg & (~GLB_CFG_DL_VSYNC)); ++ ++ /*HSYNC Polarity Set*/ ++ glb_cfg = (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) ? ++ (glb_cfg | GLB_CFG_DL_HSYNC) : (glb_cfg & (~GLB_CFG_DL_HSYNC)); ++ ++ glb_cfg &= ~GLB_CFG_C_ORDER_MASK; ++ glb_cfg &= ~GLB_CFG_ORG_FMT_MASK; ++ if(pcdev->dat_if != V4L2_MBUS_BT656) { ++ switch(icd->current_fmt->code) { ++ case MEDIA_BUS_FMT_RGB565_2X8_LE: ++ glb_cfg |= (GLB_CFG_ORG_FMT_RGB565 | GLB_CFG_C_ORDER_RGB); ++ break; ++ case MEDIA_BUS_FMT_UYVY8_2X8: ++ glb_cfg |= (GLB_CFG_ORG_FMT_YUYV422 | GLB_CFG_C_ORDER_UYVY); ++ break; ++ case MEDIA_BUS_FMT_VYUY8_2X8: ++ glb_cfg |= (GLB_CFG_ORG_FMT_YUYV422 | GLB_CFG_C_ORDER_VYUY); ++ break; ++ case MEDIA_BUS_FMT_YUYV8_2X8: ++ glb_cfg |= (GLB_CFG_ORG_FMT_YUYV422 | GLB_CFG_C_ORDER_YUYV); ++ break; ++ case MEDIA_BUS_FMT_YVYU8_2X8: ++ glb_cfg |= (GLB_CFG_ORG_FMT_YUYV422 | GLB_CFG_C_ORDER_YVYU); ++ break; ++ case MEDIA_BUS_FMT_Y8_1X8: ++ glb_cfg |= GLB_CFG_ORG_FMT_MONO; ++ break; ++ default: ++ dev_err(icd->parent, "Providing code %d not support\n", ++ icd->current_fmt->code); ++ return -EINVAL; ++ } ++ } else { ++ unsigned int sf_cfg = 0; ++ if(icd->current_fmt->code != MEDIA_BUS_FMT_YUYV8_2X8) { ++ dev_err(icd->parent, "Providing code %d not support\n", ++ icd->current_fmt->code); ++ } ++ glb_cfg |= (GLB_CFG_ORG_FMT_ITU656 | GLB_CFG_C_ORDER_YUYV); ++ ++ if(pcdev->field == V4L2_FIELD_NONE) { ++ pcdev->interlace = 0; ++ } else { ++ switch(pcdev->field) { ++ case V4L2_FIELD_INTERLACED_TB: ++ case V4L2_FIELD_INTERLACED: ++ sf_cfg &= ~CIM_F_ORDER; ++ break; ++ case V4L2_FIELD_INTERLACED_BT: ++ sf_cfg |= CIM_F_ORDER; ++ break; ++ default: ++ dev_err(icd->parent, ++ "itu656 unsupported field"); ++ break; ++ } ++ sf_cfg |= CIM_SCAN_MD; ++ sf_cfg &= ~CIM_SF_HEIGHT_MASK; ++ sf_cfg |= ((img_sz->src_h / 2) & 0xfff); ++ pcdev->interlace = 1; ++ } ++ cim_writel(pcdev, sf_cfg, SCAN_CFG); ++ } ++ ++ glb_cfg |= GLB_CFG_BURST_LEN_32; ++ glb_cfg |= GLB_CFG_AUTO_RECOVERY; ++ if(frame_size_check_flag == 1) ++ glb_cfg |= GLB_CFG_SIZE_CHK; ++ else ++ glb_cfg &= ~GLB_CFG_SIZE_CHK; ++ ++#ifdef CONFIG_CAMERA_USE_SNAPSHOT ++ tmp = CONFIG_SNAPSHOT_PULSE_WIDTH; ++ if(!tmp) { ++ tmp = 0x08; ++ } ++ glb_cfg |= GLB_CFG_DAT_MODE; ++ glb_cfg &= ~GLB_CFG_EXPO_WIDTH_MASK; ++ glb_cfg |= (((tmp-1) & 0x7) << GLB_CFG_EXPO_WIDTH_LBIT); ++ ++ tmp = CONFIG_SNAPSHOT_FRAME_DELAY & 0xffffff; ++ tmp |= CIM_DLY_EN; ++ tmp |= CIM_DLY_MD; ++ cim_writel(pcdev, tmp, DLY_CFG); ++#else ++ cim_writel(pcdev, 0, DLY_CFG); ++#endif ++ ++ if(pcdev->dat_if == V4L2_MBUS_CSI2) ++ glb_cfg |= GLB_CFG_DAT_IF_SEL; ++ else ++ glb_cfg &= ~GLB_CFG_DAT_IF_SEL; ++ ++ ++ if(img_sz->rsz_way == IMG_NO_RESIZE) { ++ tmp = (img_sz->src_w << CIM_CROP_WIDTH_LBIT) | ++ (img_sz->src_h << CIM_CROP_HEIGHT_LBIT); ++ cim_writel(pcdev, tmp, FRM_SIZE); ++ cim_writel(pcdev, 0, CROP_SITE); ++ } else if(img_sz->rsz_way == IMG_RESIZE_CROP){ ++ if(pcdev->field != V4L2_FIELD_NONE) { ++ dev_err(icd->parent, "field not supported by crop!\n"); ++ return -EINVAL; ++ } ++ tmp = (img_sz->c_w << CIM_CROP_WIDTH_LBIT) | ++ (img_sz->c_h << CIM_CROP_HEIGHT_LBIT); ++ cim_writel(pcdev, tmp, FRM_SIZE); ++ tmp = (img_sz->c_left << CIM_CROP_Y_LBIT) | ++ (img_sz->c_top << CIM_CROP_X_LBIT); ++ cim_writel(pcdev, tmp, CROP_SITE); ++ } else { ++ dev_err(icd->parent, "resize way err!!\n"); ++ return -EINVAL; ++ } ++ /* enable stop of frame interrupt. */ ++ intc |= CIM_INTC_MSK_EOW; ++ ++ /* enable end of frame interrupt, ++ * Work together with DES_INTC.EOF_MSK, ++ * only when both are 1 will generate interrupt. */ ++ intc |= CIM_INTC_MSK_EOF; ++ ++ /* enable general stop of frame interrupt. */ ++ intc |= CIM_INTC_MSK_GSA; ++ ++ /* enable rxfifo overflow interrupt */ ++ intc |= CIM_INTC_MSK_OVER; ++ ++ /* enable size check err */ ++ if(frame_size_check_flag == 1) ++ intc |= CIM_INTC_MSK_SZ_ERR; ++ else ++ intc &= ~CIM_INTC_MSK_SZ_ERR; ++ ++ cim_writel(pcdev, 0, DBG_CGC); ++ cim_writel(pcdev, glb_cfg, GLB_CFG); ++ cim_writel(pcdev, intc, CIM_INTC); ++ cim_writel(pcdev, 0, QOS_CTRL); ++ ++ return 0; ++} ++ ++static void ingenic_camera_activate(struct ingenic_camera_dev *pcdev) { ++ int ret = -1; ++ ++ if(pcdev->clk) { ++ ret = clk_prepare_enable(pcdev->clk); ++ } ++ if(pcdev->mipi_clk) { ++ ret = clk_prepare_enable(pcdev->mipi_clk); ++ } ++} ++ ++static void ingenic_camera_deactivate(struct ingenic_camera_dev *pcdev) { ++ if( pcdev->mipi_clk) { ++ clk_disable_unprepare(pcdev->mipi_clk); ++ } ++ if(pcdev->clk) { ++ clk_disable_unprepare(pcdev->clk); ++ } ++} ++ ++static int ingenic_camera_add_device(struct soc_camera_device *icd) { ++ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); ++ struct ingenic_camera_dev *pcdev = ici->priv; ++ struct ingenic_image_sz *img_sz = icd->host_priv; ++ ++ if (pcdev->icd) ++ return -EBUSY; ++ ++ dev_dbg(icd->parent, "ingenic Camera driver attached to camera %d\n", ++ icd->devnum); ++ ++ pcdev->icd = icd; ++ ++ if(img_sz) ++ img_sz->rsz_way = IMG_NO_RESIZE; ++ ++ ingenic_camera_activate(pcdev); ++ ++ return 0; ++} ++ ++static void ingenic_camera_remove_device(struct soc_camera_device *icd) { ++ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); ++ struct ingenic_camera_dev *pcdev = ici->priv; ++ ++ BUG_ON(icd != pcdev->icd); ++ ++ if(pcdev->dat_if == V4L2_MBUS_CSI2) ++ csi_phy_stop(0); ++ ++ ingenic_camera_deactivate(pcdev); ++ ingenic_camera_free_desc(pcdev); ++ dev_dbg(icd->parent, "ingenic Camera driver detached from camera %d\n", ++ icd->devnum); ++ ++ pcdev->icd = NULL; ++ pcdev->hist_en = 0; ++} ++ ++static int ingenic_camera_wakeup(struct ingenic_camera_dev *pcdev) { ++ struct ingenic_buffer *buf = pcdev->active; ++ struct vb2_v4l2_buffer *vbuf = &pcdev->active->vb; ++ int id = cim_readl(pcdev, FRAME_ID); ++ ++ if(!buf || vbuf->vb2_buf.index != id) { ++ dev_err(pcdev->dev, "cim buf synchronous problems!\n"); ++ return -EINVAL; ++ } ++ ++ list_del_init(&buf->list); ++ v4l2_get_timestamp(&vbuf->timestamp); ++ vbuf->sequence = pcdev->sequence++; ++ vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_DONE); ++ ++ return 0; ++} ++ ++static irqreturn_t ingenic_camera_irq_handler(int irq, void *data) { ++ struct ingenic_camera_dev *pcdev = (struct ingenic_camera_dev *)data; ++ struct ingenic_camera_desc *desc_p; ++ unsigned long status = 0; ++ unsigned long flags = 0; ++ unsigned long regval = 0; ++ ++ if(!pcdev->icd) ++ return IRQ_HANDLED; ++ ++ spin_lock_irqsave(&pcdev->lock, flags); ++ ++ /* read interrupt flag register */ ++ status = cim_readl(pcdev,INT_FLAG); ++ if (!status) { ++ dev_err(pcdev->dev, "cim irq_flag is NULL! \n"); ++ goto out; ++ } ++ ++ if(status & CIM_INT_FLAG_EOW) { ++ cim_writel(pcdev, CIM_INT_FLAG_EOW, CIM_CLR_ST); ++ ++ if(status & CIM_INT_FLAG_EOF) { ++ cim_writel(pcdev, CIM_INT_FLAG_EOF, CIM_CLR_ST); ++ } ++ ++ if(ingenic_camera_wakeup(pcdev)) ++ goto out; ++ ++ if (list_empty(&pcdev->video_buffer_list)) { ++ pcdev->active = NULL; ++ goto out; ++ } ++ ++ /* start next dma frame. */ ++ desc_p = pcdev->desc_paddr; ++ regval = (unsigned long)(pcdev->desc_head->next); ++ cim_writel(pcdev, regval, DES_ADDR); ++ cim_writel(pcdev, CIM_CTRL_START, CIM_CTRL); ++ ++ pcdev->active = ++ list_entry(pcdev->video_buffer_list.next, struct ingenic_buffer, list); ++ pcdev->desc_head = ++ (struct ingenic_camera_desc *)UNCAC_ADDR(phys_to_virt(regval)); ++ goto out; ++ } ++ ++ if(status & CIM_INT_FLAG_EOF) { ++ cim_writel(pcdev, CIM_INT_FLAG_EOF, CIM_CLR_ST); ++ ++ if(ingenic_camera_wakeup(pcdev)) ++ goto out; ++ ++ pcdev->active = ++ list_entry(pcdev->video_buffer_list.next, struct ingenic_buffer, list); ++ pcdev->desc_head = ++ (struct ingenic_camera_desc *)UNCAC_ADDR(phys_to_virt(pcdev->desc_head->next)); ++ ++ goto out; ++ } ++ ++ if (status & CIM_INT_FLAG_SZ_ERR) { ++ unsigned int val; ++ val = cim_readl(pcdev, ACT_SIZE); ++ cim_writel(pcdev, CIM_CLR_SZ_ERR, CIM_CLR_ST); ++ dev_err(pcdev->dev, "cim size err! w = %d h = %d\n", val&0x3ff, val>>16&0x3ff); ++ goto out; ++ } ++ ++ if (status & CIM_INT_FLAG_OVER) { ++ cim_writel(pcdev, CIM_INT_FLAG_OVER, CIM_CLR_ST); ++ dev_err(pcdev->dev, "cim overflow! \n"); ++ goto out; ++ } ++ ++ if(status & CIM_INT_FLAG_GSA) { ++ cim_writel(pcdev, CIM_INT_FLAG_GSA, CIM_CLR_ST); ++ printk("cim general stop! \n"); ++ goto out; ++ } ++ ++ if(status & CIM_INT_FLAG_SOF) { ++ cim_writel(pcdev, CIM_INT_FLAG_SOF, CIM_CLR_ST); ++ goto out; ++ } ++ ++out: ++ spin_unlock_irqrestore(&pcdev->lock, flags); ++ return IRQ_HANDLED; ++} ++ ++static ssize_t frame_size_check_r(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ snprintf(buf, 100, " 0: disable frame size check.\n 1: enable frame size check.\n"); ++ return 100; ++} ++ ++static ssize_t frame_size_check_w(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ if (count != 2) ++ return -EINVAL; ++ ++ if (*buf == '0') { ++ frame_size_check_flag = 0; ++ } else if (*buf == '1') { ++ frame_size_check_flag = 1; ++ } else { ++ return -EINVAL; ++ } ++ ++ return count; ++} ++ ++static ssize_t fps_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ printk("\n-----you can choice print way:\n"); ++ printk("Example: echo NUM > show_fps\n"); ++ printk("NUM = 0: close fps statistics\n"); ++ printk("NUM = 1: print recently fps\n"); ++ printk("NUM = 2: print interval between last and this queue buffers\n"); ++ printk("NUM > 2: print fps after NUM second\n"); ++ return 0; ++} ++ ++static ssize_t fps_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++ int num = 0; ++ num = simple_strtoul(buf, NULL, 0); ++ if(num < 0){ ++ printk("\n--please 'cat show_fps' to view using the method\n\n"); ++ return n; ++ } ++ showFPS = num; ++ return n; ++} ++ ++extern void dump_csi_reg(void); ++static ssize_t cim_dump_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct jz_camera_dev *pcdev = (struct jz_camera_dev *)dev_get_drvdata(dev); ++ ++ cim_dump_reg(pcdev); ++ cim_dump_reg_des(pcdev); ++ dump_csi_reg(); ++ return 0; ++} ++ ++static ssize_t cim_dump_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++ struct jz_camera_dev *pcdev = (struct jz_camera_dev *)dev_get_drvdata(dev); ++ int num = 0; ++ num = simple_strtoul(buf, NULL, 0); ++ if(num < 0) { ++ printk("error input\n"); ++ return n; ++ } ++ int csi2_lanes = num; ++ int ret = 0; ++ ++ ret = csi_phy_start(0, 24000000, csi2_lanes); ++ return n; ++} ++ ++/**********************cim_debug***************************/ ++static DEVICE_ATTR(frame_size_check, S_IRUGO|S_IWUSR, frame_size_check_r, frame_size_check_w); ++static DEVICE_ATTR(show_fps, S_IRUGO|S_IWUSR, fps_show, fps_store); ++static DEVICE_ATTR(cim_dump, S_IRUGO|S_IWUSR, cim_dump_show, cim_dump_store); ++ ++static struct attribute *cim_debug_attrs[] = { ++ &dev_attr_frame_size_check.attr, ++ &dev_attr_show_fps.attr, ++ &dev_attr_cim_dump.attr, ++ NULL, ++}; ++ ++const char cim_group_name[] = "debug"; ++static struct attribute_group cim_debug_attr_group = { ++ .name = cim_group_name, ++ .attrs = cim_debug_attrs, ++}; ++ ++static struct soc_camera_host_ops ingenic_soc_camera_host_ops = { ++ .owner = THIS_MODULE, ++ .add = ingenic_camera_add_device, ++ .remove = ingenic_camera_remove_device, ++ .set_fmt = ingenic_camera_set_fmt, ++ .try_fmt = ingenic_camera_try_fmt, ++ .get_formats = ingenic_camera_get_formats, ++ .put_formats = ingenic_camera_put_formats, ++ .init_videobuf2 = ingenic_camera_init_videobuf2, ++ .poll = ingenic_camera_poll, ++ .querycap = ingenic_camera_querycap, ++ .cropcap = ingenic_camera_cropcap, ++ .get_crop = ingenic_camera_get_crop, ++ .set_crop = ingenic_camera_set_crop, ++ .get_selection = ingenic_camera_get_selection, ++ .set_selection = ingenic_camera_set_selection, ++ .enum_framesizes = ingenic_camera_enum_framesizes, ++ .set_bus_param = ingenic_camera_set_bus_param, ++}; ++ ++static int __init ingenic_camera_probe(struct platform_device *pdev) { ++ int err = 0, ret = 0; ++ unsigned int irq; ++ struct resource *res; ++ void __iomem *base; ++ struct ingenic_camera_dev *pcdev; ++ ++ /* malloc */ ++ pcdev = kzalloc(sizeof(*pcdev), GFP_KERNEL); ++ if (!pcdev) { ++ dev_err(&pdev->dev, "Could not allocate pcdev\n"); ++ err = -ENOMEM; ++ goto err_kzalloc; ++ } ++ ++ /* resource */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if(!res) { ++ dev_err(&pdev->dev, "Could not get resource!\n"); ++ err = -ENODEV; ++ goto err_get_resource; ++ } ++ ++ /* irq */ ++ irq = platform_get_irq(pdev, 0); ++ if (irq <= 0) { ++ dev_err(&pdev->dev, "Could not get irq!\n"); ++ err = -ENODEV; ++ goto err_get_irq; ++ } ++ ++ /*get cim clk*/ ++ pcdev->clk = devm_clk_get(&pdev->dev, "gate_cim"); ++ if (IS_ERR(pcdev->clk)) { ++ err = PTR_ERR(pcdev->clk); ++ dev_err(&pdev->dev, "%s:can't get clk %s\n", __func__, "cim"); ++ goto err_clk_get_cim; ++ } ++ ++ /*get mipi clk*/ ++ pcdev->mipi_clk = devm_clk_get(&pdev->dev, "gate_mipi"); ++ if (IS_ERR(pcdev->mipi_clk)) { ++ err = PTR_ERR(pcdev->mipi_clk); ++ dev_err(&pdev->dev, "%s:can't get mipi_clk %s\n", __func__, "mipi"); ++ goto err_clk_get_mipi; ++ } ++ ++ /* Request the regions. */ ++ if (!request_mem_region(res->start, resource_size(res), DRIVER_NAME)) { ++ err = -EBUSY; ++ goto err_request_mem_region; ++ } ++ base = ioremap(res->start, resource_size(res)); ++ if (!base) { ++ err = -ENOMEM; ++ goto err_ioremap; ++ } ++ ++ spin_lock_init(&pcdev->lock); ++ INIT_LIST_HEAD(&pcdev->video_buffer_list); ++ ++ pcdev->dev = &pdev->dev; ++ pcdev->res = res; ++ pcdev->irq = irq; ++ pcdev->base = base; ++ pcdev->active = NULL; ++ ++ /* request irq */ ++ err = devm_request_irq(&pdev->dev, pcdev->irq, ingenic_camera_irq_handler, 0, ++ dev_name(&pdev->dev), pcdev); ++ if(err) { ++ dev_err(&pdev->dev, "request irq failed!\n"); ++ goto err_request_irq; ++ } ++ ++ pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); ++ if (IS_ERR(pcdev->alloc_ctx)) { ++ ret = PTR_ERR(pcdev->alloc_ctx); ++ goto err_alloc_ctx; ++ } ++ pcdev->soc_host.drv_name = DRIVER_NAME; ++ pcdev->soc_host.ops = &ingenic_soc_camera_host_ops; ++ pcdev->soc_host.priv = pcdev; ++ pcdev->soc_host.v4l2_dev.dev = &pdev->dev; ++ pcdev->soc_host.nr = pdev->id; /* use one cim0 or cim1 */ ++ ++ err = soc_camera_host_register(&pcdev->soc_host); ++ if (err) ++ goto err_soc_camera_host_register; ++ ++ ret = sysfs_create_group(&pcdev->dev->kobj, &cim_debug_attr_group); ++ if (ret) { ++ dev_err(&pdev->dev, "device create sysfs group failed\n"); ++ ++ ret = -EINVAL; ++ goto err_free_file; ++ } ++ ++ ++ dev_dbg(&pdev->dev, "ingenic Camera driver loaded!\n"); ++ ++ return 0; ++ ++err_free_file: ++ sysfs_remove_group(&pcdev->dev->kobj, &cim_debug_attr_group); ++err_soc_camera_host_register: ++ vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); ++err_alloc_ctx: ++ free_irq(pcdev->irq, pcdev); ++err_request_irq: ++ iounmap(base); ++err_ioremap: ++ release_mem_region(res->start, resource_size(res)); ++err_request_mem_region: ++ devm_clk_put(&pdev->dev, pcdev->mipi_clk); ++err_clk_get_mipi: ++ devm_clk_put(&pdev->dev, pcdev->clk); ++err_clk_get_cim: ++err_get_irq: ++err_get_resource: ++ kfree(pcdev); ++err_kzalloc: ++ return err; ++ ++} ++ ++static int __exit ingenic_camera_remove(struct platform_device *pdev) ++{ ++ struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); ++ struct ingenic_camera_dev *pcdev = container_of(soc_host, ++ struct ingenic_camera_dev, soc_host); ++ struct resource *res; ++ ++ free_irq(pcdev->irq, pcdev); ++ ++ vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); ++ ++ devm_clk_put(pcdev->dev, pcdev->clk); ++ devm_clk_put(pcdev->dev, pcdev->mipi_clk); ++ ++ soc_camera_host_unregister(soc_host); ++ ++ sysfs_remove_group(&pcdev->dev->kobj, &cim_debug_attr_group); ++ ++ iounmap(pcdev->base); ++ ++ res = pcdev->res; ++ release_mem_region(res->start, resource_size(res)); ++ ++ kfree(pcdev); ++ ++ dev_dbg(&pdev->dev, "ingenic Camera driver unloaded\n"); ++ ++ return 0; ++} ++ ++static const struct of_device_id ingenic_camera_of_match[] = { ++ { .compatible = "ingenic,cim" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, ingenic_camera_of_match); ++ ++static struct platform_driver ingenic_camera_driver = { ++ .remove = __exit_p(ingenic_camera_remove), ++ .driver = { ++ .name = DRIVER_NAME, ++ .owner = THIS_MODULE, ++ .of_match_table = ingenic_camera_of_match, ++ }, ++}; ++ ++static int __init ingenic_camera_init(void) { ++ /* ++ * platform_driver_probe() can save memory, ++ * but this Driver can bind to one device only. ++ */ ++ return platform_driver_probe(&ingenic_camera_driver, ingenic_camera_probe); ++} ++ ++static void __exit ingenic_camera_exit(void) { ++ return platform_driver_unregister(&ingenic_camera_driver); ++} ++ ++late_initcall(ingenic_camera_init); ++module_exit(ingenic_camera_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("wangchunlei "); ++MODULE_DESCRIPTION("ingenic Soc Camera Host Driver"); ++MODULE_ALIAS("a ingenic-cim platform"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_x2000_ingenic_camera.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_x2000_ingenic_camera.h.patch new file mode 100644 index 00000000..99f044b9 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_x2000_ingenic_camera.h.patch @@ -0,0 +1,455 @@ +diff -drupN a/drivers/media/platform/soc_camera/ingenic/x2000/ingenic_camera.h b/drivers/media/platform/soc_camera/ingenic/x2000/ingenic_camera.h +--- a/drivers/media/platform/soc_camera/ingenic/x2000/ingenic_camera.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/soc_camera/ingenic/x2000/ingenic_camera.h 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,451 @@ ++/* ++ * Copyright (c) 2012 Ingenic Semiconductor Co., Ltd. ++ * http://www.ingenic.com/ ++ * ++ * Core file for Ingenic Display Controller driver ++ * ++ * 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. ++ */ ++ ++#ifndef __INGENIC_CAMERA_H__ ++#define __INGENIC_CAMERA_H__ ++ ++#include ++#include ++#include ++#include ++ ++#define VERSION_CODE KERNEL_VERSION(0, 0, 1) ++#define DRIVER_NAME "jz-cim" ++#define CAMERA_GSENSOR_VCC "vcc_gsensor" ++#define CIM_BUS_FLAGS \ ++ (SOCAM_MASTER | SOCAM_VSYNC_ACTIVE_HIGH | \ ++ SOCAM_VSYNC_ACTIVE_LOW | SOCAM_HSYNC_ACTIVE_HIGH | \ ++ SOCAM_HSYNC_ACTIVE_LOW | SOCAM_PCLK_SAMPLE_RISING | \ ++ SOCAM_PCLK_SAMPLE_FALLING | SOCAM_DATAWIDTH_8) ++ ++#define MAX_BUFFER_NUM (3) ++#define CIM_HIST_SIZE (256 * 4) ++#define MAX_VIDEO_MEM (16 * 2046 * 2046 + CIM_HIST_SIZE) ++#define INGENIC_CAMERA_CSI2_2_LANE 1 ++#define INGENIC_CAMERA_HSYNC_HIGH 2 ++#define INGENIC_CAMERA_PCLK_RISING 4 ++#define INGENIC_CAMERA_VSYNC_HIGH 6 ++ ++/* ingenic cim ctrl id */ ++#define INGENIC_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0xf000) ++#define INGENIC_CID_SCALE_SHARP (INGENIC_CID_CUSTOM_BASE + 1) ++#define INGENIC_CID_HIST_EN (INGENIC_CID_CUSTOM_BASE + 2) ++#define INGENIC_CID_HIST_GAIN_ADD (INGENIC_CID_CUSTOM_BASE + 3) ++#define INGENIC_CID_HIST_GAIN_MUL (INGENIC_CID_CUSTOM_BASE + 4) ++#define INGENIC_CID_CROP_WAY (INGENIC_CID_CUSTOM_BASE + 5) ++ ++typedef union DES_INTC{ ++ unsigned int d32; ++ struct{ ++ unsigned reserved0:1; ++ unsigned EOF_MSK:1; ++ unsigned SOF_MSK:1; ++ unsigned reserved3_31:29; ++ }data; ++ ++}DES_INTC_t; ++ ++typedef union DES_CFG{ ++ unsigned int d32; ++ struct{ ++ unsigned DES_END:1; ++ unsigned reserved1_15:15; ++ unsigned WRBK_FMT:3; ++ unsigned reserved19_25:7; ++ unsigned ID:6; ++ }data; ++ ++}DES_CFG_t; ++ ++typedef union DES_HIST_CFG { ++ unsigned int d32; ++ struct{ ++ unsigned int GAIN_MUL:8; ++ unsigned int GAIN_ADD:8; ++ unsigned int reserved16_30:15; ++ unsigned int HIST_EN:1; ++ }; ++}DES_HIST_CFG_t; ++ ++struct ingenic_camera_desc{ ++ dma_addr_t next; ++ unsigned int WRBK_ADDR; ++ unsigned int WRBK_STRD; ++ DES_INTC_t DES_INTC_t; ++ DES_CFG_t DES_CFG_t; ++ DES_HIST_CFG_t DES_HIST_CFG_t; ++ unsigned int HIST_WRBK_ADDR; ++ unsigned int SF_WRBK_ADDR; ++}__attribute__ ((aligned (8))); ++ ++struct sensor_pdata { ++ unsigned int gpio_rst; ++ unsigned int gpio_power; ++ unsigned int gpio_en; ++ enum v4l2_mbus_type dat_if; ++ /* senser support snapshot function */ ++ unsigned short snapshot; ++ /* snapshot exposure pulse time, unit pixclk cycle */ ++ unsigned short exp_pulse_w; ++ /* the time it takes to end a frame ++ * to the next frame start*/ ++ unsigned int delay_t; ++}; ++ ++struct ingenic_camera_pdata { ++ unsigned long mclk_10khz; ++ unsigned long flags; ++ struct sensor_pdata sensor_pdata; ++}; ++ ++/* buffer for one video frame */ ++struct ingenic_buffer { ++ /* common v4l buffer stuff -- must be first */ ++ struct vb2_v4l2_buffer vb; ++ struct list_head list; ++}; ++ ++enum { ++ IMG_NO_RESIZE, ++ IMG_RESIZE_CROP, ++ IMG_RESIZE_SCALE, ++}; ++ ++enum { ++ CROP_SPECIFY_ZONE, ++ CROP_BASE_MAX_PIC, ++}; ++ ++struct ingenic_image_sz{ ++ unsigned int rsz_way; ++ unsigned int src_w; //camera input size ++ unsigned int src_h; ++ ++ unsigned int scl_w; //sclae size ++ unsigned int scl_h; ++ unsigned int sharp; ++ ++ unsigned int crop_way; ++ unsigned int c_left; //crop size ++ unsigned int c_top; ++ unsigned int c_w; ++ unsigned int c_h; ++ ++ struct v4l2_rect *rect_s; //enum sensor output size ++ unsigned short fs_cnt; ++ unsigned short fs_use; ++}; ++ ++struct ingenic_camera_dev { ++ struct soc_camera_host soc_host; ++ struct soc_camera_device *icd; ++ struct ingenic_camera_pdata *pdata; ++ ++ int sequence; ++ int start_streaming_called; ++ unsigned int buf_cnt; ++ ++ struct vb2_alloc_ctx *alloc_ctx; ++ struct ingenic_buffer *active; ++ struct list_head video_buffer_list; ++ ++ struct resource *res; ++ struct clk *clk; ++ struct clk *mclk; ++ struct clk *mipi_clk; ++ void __iomem *base; ++ struct device *dev; ++ ++ ++ unsigned int irq; ++ unsigned long mclk_freq; ++ spinlock_t lock; ++ ++ void *desc_vaddr; ++ struct ingenic_camera_desc *desc_paddr; ++ struct ingenic_camera_desc *desc_head; ++ struct ingenic_camera_desc *desc_tail; ++ ++ /* for debug */ ++ long long debug_ms_start; ++ ++ unsigned int interlace; ++ unsigned int field; ++ ++ unsigned int hist_en; ++ unsigned int hist_gain_add; ++ unsigned int hist_gain_mul; ++ ++ enum v4l2_mbus_type dat_if; ++}; ++ ++#define GENMASK(h, l) \ ++ (((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) ++ ++#define GLB_CFG (0x0000) ++#define FRM_SIZE (0x0004) ++#define CROP_SITE (0x0008) ++#define RESIZE_CFG (0x000c) ++#define RESIZE_COEF_X (0x0010) ++#define RESIZE_COEF_Y (0x0014) ++#define SCAN_CFG (0x0018) ++#define DLY_CFG (0x001C) ++#define QOS_CTRL (0x0020) ++#define QOS_CFG (0x0024) ++#define DES_ADDR (0x1000) ++#define CIM_CTRL (0x2000) ++#define CIM_ST (0x2004) ++#define CIM_CLR_ST (0x2008) ++#define CIM_INTC (0x200c) ++#define INT_FLAG (0x2010) ++#define FRAME_ID (0x2014) ++#define ACT_SIZE (0x2018) ++#define DBG_DES (0x3000) ++#define DBG_DMA (0x3004) ++#define DBG_CGC (0x3008) ++ ++/** GLOBAL register*/ ++#define GLB_CFG_C_ORDER_HBIT 23 ++#define GLB_CFG_C_ORDER_LBIT 20 ++#define GLB_CFG_C_ORDER_MASK \ ++ GENMASK(GLB_CFG_C_ORDER_HBIT, GLB_CFG_C_ORDER_LBIT) ++#define GLB_CFG_C_ORDER_RGB (0x0 << GLB_CFG_C_ORDER_LBIT) ++#define GLB_CFG_C_ORDER_RBG (0x1 << GLB_CFG_C_ORDER_LBIT) ++#define GLB_CFG_C_ORDER_GRB (0x2 << GLB_CFG_C_ORDER_LBIT) ++#define GLB_CFG_C_ORDER_GBR (0x3 << GLB_CFG_C_ORDER_LBIT) ++#define GLB_CFG_C_ORDER_BRG (0x4 << GLB_CFG_C_ORDER_LBIT) ++#define GLB_CFG_C_ORDER_BGR (0x5 << GLB_CFG_C_ORDER_LBIT) ++#define GLB_CFG_C_ORDER_YUYV (0x8 << GLB_CFG_C_ORDER_LBIT) ++#define GLB_CFG_C_ORDER_YVYU (0x9 << GLB_CFG_C_ORDER_LBIT) ++#define GLB_CFG_C_ORDER_UYVY (0xa << GLB_CFG_C_ORDER_LBIT) ++#define GLB_CFG_C_ORDER_VYUY (0xb << GLB_CFG_C_ORDER_LBIT) ++ ++#define GLB_CFG_ORG_FMT_HBIT 18 ++#define GLB_CFG_ORG_FMT_LBIT 16 ++#define GLB_CFG_ORG_FMT_MASK \ ++ GENMASK(GLB_CFG_ORG_FMT_HBIT, GLB_CFG_ORG_FMT_LBIT) ++#define GLB_CFG_ORG_FMT_RGB565 (0x0 << GLB_CFG_ORG_FMT_LBIT) ++#define GLB_CFG_ORG_FMT_RGB888 (0x1 << GLB_CFG_ORG_FMT_LBIT) ++#define GLB_CFG_ORG_FMT_YUYV422 (0x2 << GLB_CFG_ORG_FMT_LBIT) ++#define GLB_CFG_ORG_FMT_ITU656 (0x3 << GLB_CFG_ORG_FMT_LBIT) ++#define GLB_CFG_ORG_FMT_MONO (0x4 << GLB_CFG_ORG_FMT_LBIT) ++ ++#define GLB_CFG_DE_PCLK BIT(15) ++#define GLB_CFG_DL_VSYNC BIT(14) ++#define GLB_CFG_DL_HSYNC BIT(13) ++ ++#define GLB_CFG_EXPO_WIDTH_HBIT 10 ++#define GLB_CFG_EXPO_WIDTH_LBIT 8 ++#define GLB_CFG_EXPO_WIDTH_MASK \ ++ GENMASK(GLB_CFG_EXPO_WIDTH_HBIT, GLB_CFG_EXPO_WIDTH_LBIT) ++#define GLB_CFG_SIZE_CHK BIT(5) ++#define GLB_CFG_DAT_IF_SEL BIT(4) ++#define GLB_CFG_DAT_MODE BIT(3) ++ ++#define GLB_CFG_BURST_LEN_HBIT 2 ++#define GLB_CFG_BURST_LEN_LBIT 1 ++#define GLB_CFG_BURST_LEN_MASK \ ++ GENMASK(GLB_CFG_BURST_LEN_HBIT, GLB_CFG_BURST_LEN_LBIT) ++#define GLB_CFG_BURST_LEN_4 (0x0 << GLB_CFG_BURST_LEN_LBIT) ++#define GLB_CFG_BURST_LEN_8 (0x1 << GLB_CFG_BURST_LEN_LBIT) ++#define GLB_CFG_BURST_LEN_16 (0x2 << GLB_CFG_BURST_LEN_LBIT) ++#define GLB_CFG_BURST_LEN_32 (0x3 << GLB_CFG_BURST_LEN_LBIT) ++ ++#define GLB_CFG_AUTO_RECOVERY BIT(0) ++ ++ ++/**Frame size register*/ ++#define CIM_CROP_WIDTH_HBIT 10 ++#define CIM_CROP_WIDTH_LBIT 0 ++#define CIM_CROP_WIDTH_MASK \ ++ GENMASK(CIM_CROP_WIDTH_HBIT, CIM_CROP_WIDTH_LBIT) ++ ++#define CIM_CROP_HEIGHT_HBIT 26 ++#define CIM_CROP_HEIGHT_LBIT 16 ++#define CIM_CROP_HEIGHT_MASK \ ++ GENMASK(CIM_CROP_HEIGHT_HBIT, CIM_CROP_HEIGHT_LBIT) ++ ++/**Crop site register*/ ++ ++#define CIM_CROP_X_HBIT 10 ++#define CIM_CROP_X_LBIT 0 ++#define CIM_CROP_X_MASK \ ++ GENMASK(CIM_CROP_X_HBIT, CIM_CROP_X_LBIT) ++ ++#define CIM_CROP_Y_HBIT 26 ++#define CIM_CROP_Y_LBIT 16 ++#define CIM_CROP_Y_MASK \ ++ GENMASK(CIM_CROP_Y_HBIT, CIM_CROP_Y_LBIT) ++ ++/** Scale size register*/ ++#define CIM_TAR_WIDTH_HBIT 10 ++#define CIM_TAR_WIDTH_LBIT 0 ++#define CIM_TAR_WIDTH_MASK \ ++ GENMASK(CIM_TAR_WIDTH_HBIT, CIM_TAR_WIDTH_LBIT) ++ ++#define CIM_TAR_HEIGHT_HBIT 26 ++#define CIM_TAR_HEIGHT_LBIT 16 ++#define CIM_TAR_HEIGHT_MASK \ ++ GENMASK(CIM_TAR_HEIGHT_HBIT, CIM_TAR_HEIGHT_LBIT) ++ ++#define CIM_SHARPL_HBIT 15 ++#define CIM_SHARPL_LBIT 14 ++#define CIM_SHARPL_MASK \ ++ GENMASK(CIM_SHARPL_HBIT, CIM_SHARPL_LBIT) ++#define CIM_LOWST_SHARPL (0x0 << CIM_SHARPL_LBIT) ++#define CIM_HIGST_SHARPL (0x3 << CIM_SHARPL_LBIT) ++ ++#define CIM_SCALE_EN BIT(31) ++ ++/**Resize Coef X register*/ ++#define CIM_RESIZE_COEF_X_HBIT 19 ++#define CIM_RESIZE_COEF_X_LBIT 0 ++#define CIM_RESIZE_COEF_X_MASK \ ++ GENMASK(CIM_RESIZE_COEF_X_HBIT, CIM_RESIZE_COEF_X_LBIT) ++ ++/**Resize Coef Y register*/ ++ ++#define CIM_RESIZE_COEF_Y_HBIT 19 ++#define CIM_RESIZE_COEF_Y_LBIT 0 ++#define CIM_RESIZE_COEF_Y_MASK \ ++ GENMASK(CIM_RESIZE_COEF_Y_HBIT, CIM_RESIZE_COEF_Y_LBIT) ++ ++/**Second Field Height register*/ ++#define CIM_SF_HEIGHT_HBIT 11 ++#define CIM_SF_HEIGHT_LBIT 0 ++#define CIM_SF_HEIGHT_MASK \ ++ GENMASK(CIM_SF_HEIGHT_HBIT, CIM_SF_HEIGHT_LBIT) ++ ++#define CIM_F_ORDER BIT(30) ++#define CIM_SCAN_MD BIT(31) ++ ++/**Delay counter register*/ ++#define CIM_DLY_NUM_HBIT 23 ++#define CIM_DLY_NUM_LBIT 0 ++#define CIM_DLY_NUM_MASK \ ++ GENMASK(CIM_DLY_NUM_HBIT, CIM_DLY_NUM_LBIT) ++ ++#define CIM_DLY_MD BIT(30) ++#define CIM_DLY_EN BIT(31) ++ ++#define CIM_QOS_CTRL BIT(0) ++#define CIM_QOS_VAL_HBIT 2 ++#define CIM_QOS_VAL_LBIT 1 ++#define CIM_QOS_VAL_MASK \ ++ GENMASK(CIM_QOS_VAL_HBIT, CIM_QOS_VAL_LBIT) ++ ++#define CIM_QOS_CFG_TH2_LBIT (26) ++#define CIM_QOS_CFG_TH2_HBIT (18) ++#define CIM_QOS_CFG_TH2_MASK \ ++ GENMASK(CIM_QOS_CFG_TH2_HBIT, CIM_QOS_CFG_TH2_LBIT) ++#define CIM_QOS_CFG_TH1_LBIT (17) ++#define CIM_QOS_CFG_TH1_HBIT (9) ++#define CIM_QOS_CFG_TH1_MASK \ ++ GENMASK(CIM_QOS_CFG_TH1_HBIT, CIM_QOS_CFG_TH1_LBIT) ++#define CIM_QOS_CFG_TH0_LBIT (0) ++#define CIM_QOS_CFG_TH0_HBIT (8) ++#define CIM_QOS_CFG_TH0_MASK \ ++ GENMASK(CIM_QOS_CFG_TH0_HBIT, CIM_QOS_CFG_TH0_LBIT) ++ ++/**Descriptor address register*/ ++#define CIM_DES_ADDR_HBIT 31 ++#define CIM_DES_ADDR_LBIT 0 ++#define CIM_DES_ADDR_MASK \ ++ GENMASK(CIM_DES_ADDR_HBIT, CIM_DES_ADDR_LBIT) ++ ++/**Control register*/ ++#define CIM_CTRL_START BIT(0) ++#define CIM_CTRL_QCK_STOP BIT(1) ++#define CIM_CTRL_GEN_STOP BIT(2) ++#define CIM_CTRL_SOFT_RST BIT(3) ++#define CIM_CTRL_DBG_DES_RST BIT(4) ++ ++/**status register*/ ++#define CIM_ST_WORKING BIT(0) ++#define CIM_ST_EOF BIT(1) ++#define CIM_ST_SOF BIT(2) ++#define CIM_ST_GSA BIT(3) ++#define CIM_ST_OVER BIT(4) ++#define CIM_ST_EOW BIT(5) ++#define CIM_ST_SZ_ERR BIT(6) ++#define CIM_ST_SRST BIT(7) ++ ++/**Clear status register*/ ++#define CIM_CLR_FRM_END BIT(1) ++#define CIM_CLR_FRM_START BIT(2) ++#define CIM_CLR_GSA BIT(3) ++#define CIM_CLR_OVER BIT(4) ++#define CIM_CLR_EOW BIT(5) ++#define CIM_CLR_SZ_ERR BIT(6) ++#define CIM_CLR_SRST BIT(7) ++#define CIM_CLR_ALL \ ++ (CIM_CLR_FRM_END | CIM_CLR_FRM_START | \ ++ CIM_CLR_GSA | CIM_CLR_OVER | \ ++ CIM_CLR_EOW | CIM_CLR_SZ_ERR) ++ ++/**CIM INTC register*/ ++#define CIM_INTC_MSK_EOF BIT(1) ++#define CIM_INTC_MSK_SOF BIT(2) ++#define CIM_INTC_MSK_GSA BIT(3) ++#define CIM_INTC_MSK_OVER BIT(4) ++#define CIM_INTC_MSK_EOW BIT(5) ++#define CIM_INTC_MSK_SZ_ERR BIT(6) ++ ++/**CIM_INT_FLAG*/ ++#define CIM_INT_FLAG_EOF BIT(1) ++#define CIM_INT_FLAG_SOF BIT(2) ++#define CIM_INT_FLAG_GSA BIT(3) ++#define CIM_INT_FLAG_OVER BIT(4) ++#define CIM_INT_FLAG_EOW BIT(5) ++#define CIM_INT_FLAG_SZ_ERR BIT(6) ++ ++#define CIM_CGC_FLOW BIT(0) ++#define CIM_CGC_DVP BIT(1) ++#define CIM_CGC_SCALE BIT(2) ++#define CIM_CGC_DES BIT(3) ++#define CIM_CGC_WRBK BIT(4) ++#define CIM_CGC_REG BIT(5) ++ ++/**dma Write back format*/ ++#define DES_CFG_WRBK_FMT_HBIT 18 ++#define DES_CFG_WRBK_FMT_LBIT 16 ++#define DES_CFG_WRBK_FMT_MASK \ ++ GENMASK(DES_CFG_WRBK_FMT_HBIT, DES_CFG_WRBK_FMT_LBIT) ++ ++#define WRBK_FMT_RGB888 (6) ++#define WRBK_FMT_MONO (4) ++#define WRBK_FMT_YUV422 (3) ++#define WRBK_FMT_RGB565 (1) ++ ++ ++#define CIM_HSIT_EN BIT(31) ++#define CIM_GAIN_ADD_HBIT 15 ++#define CIM_GAIN_ADD_LBIT 8 ++#define CIM_GAIN_ADD_MASK \ ++ GENMASK(CIM_GAIN_ADD_HBIT, CIM_GAIN_ADD_LBIT) ++#define CIM_GAIN_MUL_HBIT 7 ++#define CIM_GAIN_MUL_LBIT 0 ++#define CIM_GAIN_MUL_MASK \ ++ GENMASK(CIM_GAIN_MUL_HBIT, CIM_GAIN_MUL_LBIT) ++ ++static inline void cim_writel(struct ingenic_camera_dev *pcdev, ++ unsigned int val, unsigned int off) ++{ ++ writel(val, pcdev->base + off); ++} ++ ++static inline unsigned int cim_readl(struct ingenic_camera_dev *pcdev, ++ unsigned int off) ++{ ++ return readl(pcdev->base + off); ++} ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_x2000_mipi_csi.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_x2000_mipi_csi.c.patch new file mode 100644 index 00000000..e52d6368 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_x2000_mipi_csi.c.patch @@ -0,0 +1,144 @@ +diff -drupN a/drivers/media/platform/soc_camera/ingenic/x2000/mipi_csi.c b/drivers/media/platform/soc_camera/ingenic/x2000/mipi_csi.c +--- a/drivers/media/platform/soc_camera/ingenic/x2000/mipi_csi.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/soc_camera/ingenic/x2000/mipi_csi.c 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,140 @@ ++/* ++ * Copyright (c) 2012 Ingenic Semiconductor Co., Ltd. ++ * http://www.ingenic.com/ ++ * ++ * Core file for Ingenic Display Controller driver ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "mipi_csi.h" ++ ++void dump_csi_reg(void) ++{ ++ printk("****>>>>> dump csi reg <<<<<******\n"); ++ printk("**********VERSION =%08x\n", csi_core_read(VERSION)); ++ printk("**********N_LANES =%08x\n", csi_core_read(N_LANES)); ++ printk("**********PHY_SHUTDOWNZ = %08x\n", csi_core_read(PHY_SHUTDOWNZ)); ++ printk("**********DPHY_RSTZ = %08x\n", csi_core_read(DPHY_RSTZ)); ++ printk("**********CSI2_RESETN =%08x\n", csi_core_read(CSI2_RESETN)); ++ printk("**********PHY_STATE = %08x\n", csi_core_read(PHY_STATE)); ++ printk("**********DATA_IDS_1 = %08x\n", csi_core_read(DATA_IDS_1)); ++ printk("**********DATA_IDS_2 = %08x\n", csi_core_read(DATA_IDS_2)); ++ printk("**********ERR1 = %08x\n", csi_core_read(ERR1)); ++ printk("**********ERR2 = %08x\n", csi_core_read(ERR2)); ++ printk("**********MASK1 =%08x\n", csi_core_read(MASK1)); ++ printk("**********MASK2 =%08x\n", csi_core_read(MASK2)); ++ printk("**********PHY_TST_CTRL0 = %08x\n", csi_core_read(PHY_TST_CTRL0)); ++ printk("**********PHY_TST_CTRL1 = %08x\n", csi_core_read(PHY_TST_CTRL1)); ++} ++ ++void check_csi_error(void) { ++ ++ unsigned int temp1, temp2; ++ while(1){ ++ dump_csi_reg(); ++ temp1 = csi_core_read(ERR1); ++ temp2 = csi_core_read(ERR2); ++ if(temp1 != 0) ++ printk("error-------- 1:0x%08x\n", temp1); ++ if(temp2 != 0) ++ printk("error-------- 2:0x%08x\n", temp2); ++ } ++} ++ ++static unsigned char csi_core_write_part(unsigned int address, unsigned int data, unsigned char shift, unsigned char width) ++{ ++ unsigned int mask = (1 << width) - 1; ++ unsigned int temp = csi_core_read(address); ++ temp &= ~(mask << shift); ++ temp |= (data & mask) << shift; ++ csi_core_write(address, temp); ++ ++ return 0; ++} ++ ++static unsigned char csi_event_disable(unsigned int mask, unsigned char err_reg_no) ++{ ++ switch (err_reg_no) ++ { ++ case 1: ++ csi_core_write(MASK1, mask | csi_core_read(MASK1)); ++ break; ++ case 2: ++ csi_core_write(MASK2, mask | csi_core_read(MASK2)); ++ break; ++ default: ++ return ERR_OUT_OF_BOUND; ++ } ++ ++ return 0; ++} ++ ++unsigned char csi_set_on_lanes(unsigned char lanes) ++{ ++ csi_core_write_part(N_LANES, (lanes - 1), 0, 2); ++ return 0; ++} ++ ++int csi_phy_start(unsigned int id, unsigned int freq, unsigned int lans) ++{ ++ csi_set_on_lanes(lans); ++ ++ /*reset phy*/ ++ csi_core_write_part(PHY_SHUTDOWNZ, 0, 0, 1); ++ csi_core_write_part(PHY_SHUTDOWNZ, 1, 0, 1); ++ csi_core_write_part(DPHY_RSTZ, 0, 0, 1); ++ csi_core_write_part(DPHY_RSTZ, 1, 0, 1); ++ ++ csi_phy_write(LANE_EN, 0x7d); ++ csi_phy_write(CLK_CON_MODE, 0x3f); ++ csi_phy_write(SWITCH_LVDS_BANK, 0x3f); ++ csi_phy_write(LVDS_LOGICAL_EN, 0x1e); ++ csi_phy_write(SWITCH_LVDS_BANK, 0x1f); ++ csi_phy_write(L0_CNT_TIME, 0x8b); ++ csi_phy_write(L1_CNT_TIME, 0x8b); ++ ++ csi_core_write_part(CSI2_RESETN, 0, 0, 1); ++ csi_core_write_part(CSI2_RESETN, 1, 0, 1); ++ ++ /* MASK all interrupts */ ++ csi_event_disable(0xffffffff, 1); ++ csi_event_disable(0xffffffff, 2); ++ ++ return 0; ++} ++ ++int csi_phy_stop(unsigned int id) ++{ ++ ++ printk("csi_phy_stop being called \n"); ++ /*reset phy*/ ++ csi_core_write_part(PHY_SHUTDOWNZ, 0, 0, 1); ++ csi_core_write_part(DPHY_RSTZ, 0, 0, 1); ++ csi_core_write_part(CSI2_RESETN, 0, 0, 1); ++ ++ return 0; ++} ++ ++int csi_phy_init(void) ++{ ++ //printk("csi_phy_init being called ....\n"); ++ return 0; ++} ++ ++int csi_phy_release(void) ++{ ++ csi_core_write_part(CSI2_RESETN, 0, 0, 1); ++ csi_core_write_part(CSI2_RESETN, 1, 0, 1); ++ return 0; ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_x2000_mipi_csi.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_x2000_mipi_csi.h.patch new file mode 100644 index 00000000..fe5a9c0b --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_platform_soc_camera_ingenic_x2000_mipi_csi.h.patch @@ -0,0 +1,85 @@ +diff -drupN a/drivers/media/platform/soc_camera/ingenic/x2000/mipi_csi.h b/drivers/media/platform/soc_camera/ingenic/x2000/mipi_csi.h +--- a/drivers/media/platform/soc_camera/ingenic/x2000/mipi_csi.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/platform/soc_camera/ingenic/x2000/mipi_csi.h 2022-06-09 05:02:29.000000000 +0300 +@@ -0,0 +1,81 @@ ++/* ++ * Copyright (c) 2012 Ingenic Semiconductor Co., Ltd. ++ * http://www.ingenic.com/ ++ * ++ * Core file for Ingenic Display Controller driver ++ * ++ * 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. ++ */ ++ ++#ifndef __MIPI_CSI_H__ ++#define __MIPI_CSI_H__ ++ ++/* csi host regs, base addr should be defined in board cfg */ ++#define DWC_CSI_CTRL_BASE 0xB3015000 ++#define INNO_CSI_PHY_BASE 0xB3016000 ++ ++/* csi controller */ ++#define VERSION 0x00 ++#define N_LANES 0x04 ++#define PHY_SHUTDOWNZ 0x08 ++#define DPHY_RSTZ 0x0C ++#define CSI2_RESETN 0x10 ++#define PHY_STATE 0x14 ++#define DATA_IDS_1 0x18 ++#define DATA_IDS_2 0x1C ++#define ERR1 0x20 ++#define ERR2 0x24 ++#define MASK1 0x28 ++#define MASK2 0x2C ++#define PHY_TST_CTRL0 0x30 ++#define PHY_TST_CTRL1 0x34 ++ ++/* csi d-phy */ ++#define LANE_EN 0x000 ++#define CLK_CNT_TIME 0x100 ++#define L0_CNT_TIME 0x180 ++#define L1_CNT_TIME 0x200 ++#define L2_CNT_TIME 0x280 ++#define L3_CNT_TIME 0x300 ++#define CLK_CON_MODE 0x128 ++#define SWITCH_LVDS_BANK 0x080 ++#define MODEL_EN 0x2cc ++#define LVDS_LOGICAL_EN 0x300 ++ ++typedef enum ++{ ++ ERR_NOT_INIT = 0xFE, ++ ERR_ALREADY_INIT = 0xFD, ++ ERR_NOT_COMPATIBLE = 0xFC, ++ ERR_UNDEFINED = 0xFB, ++ ERR_OUT_OF_BOUND = 0xFA, ++ SUCCESS = 0 ++} csi_error_t; ++ ++ ++#define dwc_csi_readl(reg) \ ++ readl((unsigned int *)(DWC_CSI_CTRL_BASE + reg)) ++#define dwc_csi_writel(reg, value) \ ++ writel((value), (unsigned int *)(DWC_CSI_CTRL_BASE + reg)) ++ ++#define csi_core_write(addr, value) dwc_csi_writel(addr, value) ++#define csi_core_read(addr) dwc_csi_readl(addr) ++ ++#define csi_phy_read(reg) \ ++ readl((unsigned int *)(INNO_CSI_PHY_BASE + reg)) ++#define csi_phy_write(reg, value) \ ++ writel((value), (unsigned int *)(INNO_CSI_PHY_BASE + reg)) ++ ++/* function */ ++extern int csi_phy_init(void); ++extern int csi_phy_release(void); ++extern int csi_phy_start(unsigned int id, unsigned int freq, unsigned int lans); ++extern int csi_phy_stop(unsigned int id); ++ ++extern void dump_csi_reg(void); ++extern void check_csi_error(void); ++extern unsigned char csi_set_on_lanes(unsigned char lanes); ++ ++#endif/*__MIPI_CSI_H__*/ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_v4l2-core_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_v4l2-core_Kconfig.patch new file mode 100644 index 00000000..320d9a32 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_v4l2-core_Kconfig.patch @@ -0,0 +1,24 @@ +diff -drupN a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig +--- a/drivers/media/v4l2-core/Kconfig 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/media/v4l2-core/Kconfig 2022-06-09 05:02:30.000000000 +0300 +@@ -99,6 +99,20 @@ config VIDEOBUF2_VMALLOC + select VIDEOBUF2_MEMOPS + select DMA_SHARED_BUFFER + ++config VIDEOBUF2_DMA_CONTIG_INGENIC ++ tristate ++ depends on HAS_DMA ++ select VIDEOBUF2_CORE ++ select VIDEOBUF2_MEMOPS ++ select DMA_SHARED_BUFFER ++ ++config CAMERA_RESERVE_KB_SIZE ++ int "Reserve memory for camera noncoherent memory. Unit:KByte" ++ default 0 ++ depends on VIDEOBUF2_DMA_CONTIG_INGENIC ++ ++ ++ + config VIDEOBUF2_DMA_SG + tristate + depends on HAS_DMA diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_v4l2-core_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_v4l2-core_Makefile.patch new file mode 100644 index 00000000..c5a4d111 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_v4l2-core_Makefile.patch @@ -0,0 +1,11 @@ +diff -drupN a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile +--- a/drivers/media/v4l2-core/Makefile 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/media/v4l2-core/Makefile 2022-06-09 05:02:30.000000000 +0300 +@@ -37,6 +37,7 @@ obj-$(CONFIG_VIDEOBUF2_CORE) += videobuf + obj-$(CONFIG_VIDEOBUF2_MEMOPS) += videobuf2-memops.o + obj-$(CONFIG_VIDEOBUF2_VMALLOC) += videobuf2-vmalloc.o + obj-$(CONFIG_VIDEOBUF2_DMA_CONTIG) += videobuf2-dma-contig.o ++obj-$(CONFIG_VIDEOBUF2_DMA_CONTIG_INGENIC) += videobuf2-dma-contig-ingenic.o + obj-$(CONFIG_VIDEOBUF2_DMA_SG) += videobuf2-dma-sg.o + obj-$(CONFIG_VIDEOBUF2_DVB) += videobuf2-dvb.o + diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_v4l2-core_videobuf2-dma-contig-ingenic.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_v4l2-core_videobuf2-dma-contig-ingenic.c.patch new file mode 100644 index 00000000..ef9574ed --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_media_v4l2-core_videobuf2-dma-contig-ingenic.c.patch @@ -0,0 +1,900 @@ +diff -drupN a/drivers/media/v4l2-core/videobuf2-dma-contig-ingenic.c b/drivers/media/v4l2-core/videobuf2-dma-contig-ingenic.c +--- a/drivers/media/v4l2-core/videobuf2-dma-contig-ingenic.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/media/v4l2-core/videobuf2-dma-contig-ingenic.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,896 @@ ++/* ++ * videobuf2-dma-contig.c - DMA contig memory allocator for videobuf2 ++ * ++ * Copyright (C) 2010 Samsung Electronics ++ * ++ * Author: Pawel Osciak ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++struct reserve_memmg{ ++ struct list_head list; ++ long start; ++ long size; ++ ++}; ++struct vb2_dc_conf { ++ struct device *dev; ++ void *reserve_addr; ++ dma_addr_t reserve_phy_addr; ++ unsigned long reserve_size; ++ struct list_head top; ++}; ++ ++struct vb2_dc_buf { ++ struct device *dev; ++ void *vaddr; ++ unsigned long size; ++ dma_addr_t dma_addr; ++ enum dma_data_direction dma_dir; ++ struct sg_table *dma_sgt; ++ struct frame_vector *vec; ++ ++ /* MMAP related */ ++ struct vb2_vmarea_handler handler; ++ atomic_t refcount; ++ struct sg_table *sgt_base; ++ ++ /* DMABUF related */ ++ struct dma_buf_attachment *db_attach; ++ struct reserve_memmg *rsvmem; ++}; ++ ++/*********************************************/ ++/* scatterlist table functions */ ++/*********************************************/ ++ ++ ++static void vb2_dc_sgt_foreach_page(struct sg_table *sgt, ++ void (*cb)(struct page *pg)) ++{ ++ struct scatterlist *s; ++ unsigned int i; ++ ++ for_each_sg(sgt->sgl, s, sgt->orig_nents, i) { ++ struct page *page = sg_page(s); ++ unsigned int n_pages = PAGE_ALIGN(s->offset + s->length) ++ >> PAGE_SHIFT; ++ unsigned int j; ++ ++ for (j = 0; j < n_pages; ++j, ++page) ++ cb(page); ++ } ++} ++ ++static unsigned long vb2_dc_get_contiguous_size(struct sg_table *sgt) ++{ ++ struct scatterlist *s; ++ dma_addr_t expected = sg_dma_address(sgt->sgl); ++ unsigned int i; ++ unsigned long size = 0; ++ ++ for_each_sg(sgt->sgl, s, sgt->nents, i) { ++ if (sg_dma_address(s) != expected) ++ break; ++ expected = sg_dma_address(s) + sg_dma_len(s); ++ size += sg_dma_len(s); ++ } ++ return size; ++} ++ ++/*********************************************/ ++/* callbacks for all buffers */ ++/*********************************************/ ++ ++static void *vb2_dc_cookie(void *buf_priv) ++{ ++ struct vb2_dc_buf *buf = buf_priv; ++ ++ return &buf->dma_addr; ++} ++ ++static void *vb2_dc_vaddr(void *buf_priv) ++{ ++ struct vb2_dc_buf *buf = buf_priv; ++ ++ if (!buf->vaddr && buf->db_attach) ++ buf->vaddr = dma_buf_vmap(buf->db_attach->dmabuf); ++ ++ return buf->vaddr; ++} ++ ++static unsigned int vb2_dc_num_users(void *buf_priv) ++{ ++ struct vb2_dc_buf *buf = buf_priv; ++ ++ return atomic_read(&buf->refcount); ++} ++ ++static void vb2_dc_prepare(void *buf_priv) ++{ ++ struct vb2_dc_buf *buf = buf_priv; ++ struct sg_table *sgt = buf->dma_sgt; ++ ++ /* DMABUF exporter will flush the cache for us */ ++ //if (!sgt || buf->db_attach) ++ if (buf->db_attach) ++ return; ++ if(!sgt) ++ { ++// dma_sync_single_for_device(buf->dev,(unsigned long)buf->vaddr,buf->size,buf->dma_dir); ++ dma_sync_single_for_device(buf->dev,(unsigned long)buf->dma_addr,buf->size,buf->dma_dir); ++ }else { ++ dma_sync_sg_for_device(buf->dev, sgt->sgl, sgt->orig_nents, buf->dma_dir); ++ } ++} ++ ++static void vb2_dc_finish(void *buf_priv) ++{ ++ struct vb2_dc_buf *buf = buf_priv; ++ struct sg_table *sgt = buf->dma_sgt; ++ ++ /* DMABUF exporter will flush the cache for us */ ++ //if (!sgt || buf->db_attach) ++ if(buf->db_attach) ++ return; ++ if(!sgt) ++ dma_sync_single_for_device(buf->dev,(unsigned long)buf->dma_addr,buf->size,buf->dma_dir); ++ else ++ dma_sync_sg_for_cpu(buf->dev, sgt->sgl, sgt->orig_nents, buf->dma_dir); ++} ++ ++/*********************************************/ ++/* callbacks for MMAP buffers */ ++/*********************************************/ ++static void vb2_dc_put(void *buf_priv) ++{ ++ struct vb2_dc_buf *buf = buf_priv; ++ if (!atomic_dec_and_test(&buf->refcount)) ++ return; ++ ++ if (buf->sgt_base) { ++ sg_free_table(buf->sgt_base); ++ kfree(buf->sgt_base); ++ } ++ ++ if(buf->rsvmem) ++ { ++ list_del(&buf->rsvmem->list); ++ vfree(buf->rsvmem); ++ }else ++ dma_free_noncoherent(buf->dev, buf->size, buf->vaddr, buf->dma_addr); ++ ++ ++ ++ put_device(buf->dev); ++ kfree(buf); ++} ++ ++static struct reserve_memmg* reserve_mem_alloc(struct vb2_dc_conf *conf,int size) ++{ ++ struct reserve_memmg *pos,*next,*alloc_list = NULL; ++ ++ list_for_each_entry(pos,&conf->top,list){ ++ if(!list_is_last(&pos->list,&conf->top)) ++ { ++ next = list_entry(pos->list.next,struct reserve_memmg,list); ++ //printk("-->pos: %ld next: %ld\n",pos->start,next->start); ++ if(next->start - (pos->start + pos->size) >= size){ ++ alloc_list = vzalloc(sizeof(struct reserve_memmg)); ++ alloc_list->start = pos->start + pos->size; ++ alloc_list->size = size; ++ list_add(&alloc_list->list,&pos->list); ++ printk("->alloc: %ld\n",alloc_list->start); ++ return alloc_list; ++ } ++ }else break; ++ } ++ if(list_empty(&conf->top)) ++ { ++ if(conf->reserve_size < size){ ++ return 0; ++ } ++ alloc_list = vzalloc(sizeof(struct reserve_memmg)); ++ alloc_list->start = 0; ++ alloc_list->size = size; ++ list_add(&alloc_list->list,&conf->top); ++ printk("first alloc: %ld\n",alloc_list->start); ++ }else{ ++ if(conf->reserve_size - (pos->start + pos->size) < size) ++ return 0; ++ alloc_list = vzalloc(sizeof(struct reserve_memmg)); ++ ++ alloc_list->start = pos->start + pos->size; ++ alloc_list->size = size; ++ list_add_tail(&alloc_list->list,&conf->top); ++ printk("tail alloc: %ld\n",alloc_list->start); ++ } ++ return alloc_list; ++ ++} ++static void *vb2_dc_alloc(void *alloc_ctx, unsigned long size, ++ enum dma_data_direction dma_dir, gfp_t gfp_flags) ++{ ++ struct vb2_dc_conf *conf = alloc_ctx; ++ struct device *dev = conf->dev; ++ struct vb2_dc_buf *buf; ++ ++ buf = kzalloc(sizeof *buf, GFP_KERNEL); ++ if (!buf) ++ return ERR_PTR(-ENOMEM); ++ ++ if(conf->reserve_size > 0){ ++ struct reserve_memmg* m; ++ m = reserve_mem_alloc(conf,size); ++ if(m) ++ { ++ buf->vaddr = m->start + conf->reserve_addr; ++ buf->dma_addr = m->start + (unsigned long)conf->reserve_phy_addr; ++ buf->rsvmem = m; ++ printk("alloc addr %p\n",buf->vaddr); ++ } ++ } ++ if(!buf->vaddr) ++ { ++ buf->vaddr = dma_alloc_noncoherent(dev, size, &buf->dma_addr, ++ GFP_KERNEL | gfp_flags); ++ if (!buf->vaddr) { ++ dev_err(dev, "dma_alloc_noncoherent of size %ld failed\n", size); ++ kfree(buf); ++ return ERR_PTR(-ENOMEM); ++ } ++ } ++ /* Prevent the device from being released while the buffer is used */ ++ buf->dev = get_device(dev); ++ buf->size = size; ++ buf->dma_dir = dma_dir; ++ ++ buf->handler.refcount = &buf->refcount; ++ buf->handler.put = vb2_dc_put; ++ buf->handler.arg = buf; ++ ++ atomic_inc(&buf->refcount); ++ ++ return buf; ++} ++ ++int dma_common_mmap_cached(struct device *dev, struct vm_area_struct *vma, ++ void *cpu_addr, dma_addr_t dma_addr, size_t size) ++{ ++ int ret = -ENXIO; ++#ifdef CONFIG_MMU ++ unsigned long user_count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; ++ unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT; ++ unsigned long pfn = page_to_pfn(virt_to_page(cpu_addr)); ++ unsigned long off = vma->vm_pgoff; ++ ++// vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); ++ pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK; ++// pgprot_val(vma->vm_page_prot) |= _CACHE_CACHABLE_WA; /* Write-Acceleration */ ++ pgprot_val(vma->vm_page_prot) |= _CACHE_CACHABLE_NONCOHERENT; ++// pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED; ++// printk(KERN_DEBUG "__videobuf_mmap_mapper() vma->vm_page_prot=%x cpu_addr:%p\n", vma->vm_page_prot,cpu_addr); ++ ++ //if (dma_mmap_from_coherent(dev, vma, cpu_addr, size, &ret)) ++ // return ret; ++ ++ if (off < count && user_count <= (count - off)) { ++ ret = remap_pfn_range(vma, vma->vm_start, ++ pfn + off, ++ user_count << PAGE_SHIFT, ++ vma->vm_page_prot); ++ } ++#endif /* CONFIG_MMU */ ++ ++ return ret; ++} ++ ++static int vb2_dc_mmap(void *buf_priv, struct vm_area_struct *vma) ++{ ++ struct vb2_dc_buf *buf = buf_priv; ++ int ret; ++ ++ if (!buf) { ++ printk(KERN_ERR "No buffer to map\n"); ++ return -EINVAL; ++ } ++ ++ /* ++ * dma_mmap_* uses vm_pgoff as in-buffer offset, but we want to ++ * map whole buffer ++ */ ++ vma->vm_pgoff = 0; ++ ++ /* ret = dma_mmap_coherent(buf->dev, vma, buf->vaddr, */ ++ /* buf->dma_addr, buf->size); */ ++ ret = dma_common_mmap_cached(buf->dev, vma, buf->vaddr, ++ buf->dma_addr, buf->size); ++ ++ if (ret) { ++ pr_err("Remapping memory failed, error: %d\n", ret); ++ return ret; ++ } ++ ++ vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; ++ vma->vm_private_data = &buf->handler; ++ vma->vm_ops = &vb2_common_vm_ops; ++ ++ vma->vm_ops->open(vma); ++ ++ pr_debug("%s: mapped dma addr 0x%08lx at 0x%08lx, size %ld\n", ++ __func__, (unsigned long)buf->dma_addr, vma->vm_start, ++ buf->size); ++ ++ return 0; ++} ++ ++/*********************************************/ ++/* DMABUF ops for exporters */ ++/*********************************************/ ++ ++struct vb2_dc_attachment { ++ struct sg_table sgt; ++ enum dma_data_direction dma_dir; ++}; ++ ++static int vb2_dc_dmabuf_ops_attach(struct dma_buf *dbuf, struct device *dev, ++ struct dma_buf_attachment *dbuf_attach) ++{ ++ struct vb2_dc_attachment *attach; ++ unsigned int i; ++ struct scatterlist *rd, *wr; ++ struct sg_table *sgt; ++ struct vb2_dc_buf *buf = dbuf->priv; ++ int ret; ++ ++ attach = kzalloc(sizeof(*attach), GFP_KERNEL); ++ if (!attach) ++ return -ENOMEM; ++ ++ sgt = &attach->sgt; ++ /* Copy the buf->base_sgt scatter list to the attachment, as we can't ++ * map the same scatter list to multiple attachments at the same time. ++ */ ++ ret = sg_alloc_table(sgt, buf->sgt_base->orig_nents, GFP_KERNEL); ++ if (ret) { ++ kfree(attach); ++ return -ENOMEM; ++ } ++ ++ rd = buf->sgt_base->sgl; ++ wr = sgt->sgl; ++ for (i = 0; i < sgt->orig_nents; ++i) { ++ sg_set_page(wr, sg_page(rd), rd->length, rd->offset); ++ rd = sg_next(rd); ++ wr = sg_next(wr); ++ } ++ ++ attach->dma_dir = DMA_NONE; ++ dbuf_attach->priv = attach; ++ ++ return 0; ++} ++ ++static void vb2_dc_dmabuf_ops_detach(struct dma_buf *dbuf, ++ struct dma_buf_attachment *db_attach) ++{ ++ struct vb2_dc_attachment *attach = db_attach->priv; ++ struct sg_table *sgt; ++ ++ if (!attach) ++ return; ++ ++ sgt = &attach->sgt; ++ ++ /* release the scatterlist cache */ ++ if (attach->dma_dir != DMA_NONE) ++ dma_unmap_sg(db_attach->dev, sgt->sgl, sgt->orig_nents, ++ attach->dma_dir); ++ sg_free_table(sgt); ++ kfree(attach); ++ db_attach->priv = NULL; ++} ++ ++static struct sg_table *vb2_dc_dmabuf_ops_map( ++ struct dma_buf_attachment *db_attach, enum dma_data_direction dma_dir) ++{ ++ struct vb2_dc_attachment *attach = db_attach->priv; ++ /* stealing dmabuf mutex to serialize map/unmap operations */ ++ struct mutex *lock = &db_attach->dmabuf->lock; ++ struct sg_table *sgt; ++ ++ mutex_lock(lock); ++ ++ sgt = &attach->sgt; ++ /* return previously mapped sg table */ ++ if (attach->dma_dir == dma_dir) { ++ mutex_unlock(lock); ++ return sgt; ++ } ++ ++ /* release any previous cache */ ++ if (attach->dma_dir != DMA_NONE) { ++ dma_unmap_sg(db_attach->dev, sgt->sgl, sgt->orig_nents, ++ attach->dma_dir); ++ attach->dma_dir = DMA_NONE; ++ } ++ ++ /* mapping to the client with new direction */ ++ sgt->nents = dma_map_sg(db_attach->dev, sgt->sgl, sgt->orig_nents, ++ dma_dir); ++ if (!sgt->nents) { ++ pr_err("failed to map scatterlist\n"); ++ mutex_unlock(lock); ++ return ERR_PTR(-EIO); ++ } ++ ++ attach->dma_dir = dma_dir; ++ ++ mutex_unlock(lock); ++ ++ return sgt; ++} ++ ++static void vb2_dc_dmabuf_ops_unmap(struct dma_buf_attachment *db_attach, ++ struct sg_table *sgt, enum dma_data_direction dma_dir) ++{ ++ /* nothing to be done here */ ++} ++ ++static void vb2_dc_dmabuf_ops_release(struct dma_buf *dbuf) ++{ ++ /* drop reference obtained in vb2_dc_get_dmabuf */ ++ vb2_dc_put(dbuf->priv); ++} ++ ++static void *vb2_dc_dmabuf_ops_kmap(struct dma_buf *dbuf, unsigned long pgnum) ++{ ++ struct vb2_dc_buf *buf = dbuf->priv; ++ ++ return buf->vaddr + pgnum * PAGE_SIZE; ++} ++ ++static void *vb2_dc_dmabuf_ops_vmap(struct dma_buf *dbuf) ++{ ++ struct vb2_dc_buf *buf = dbuf->priv; ++ ++ return buf->vaddr; ++} ++ ++static int vb2_dc_dmabuf_ops_mmap(struct dma_buf *dbuf, ++ struct vm_area_struct *vma) ++{ ++ return vb2_dc_mmap(dbuf->priv, vma); ++} ++ ++static struct dma_buf_ops vb2_dc_dmabuf_ops = { ++ .attach = vb2_dc_dmabuf_ops_attach, ++ .detach = vb2_dc_dmabuf_ops_detach, ++ .map_dma_buf = vb2_dc_dmabuf_ops_map, ++ .unmap_dma_buf = vb2_dc_dmabuf_ops_unmap, ++ .kmap = vb2_dc_dmabuf_ops_kmap, ++ .kmap_atomic = vb2_dc_dmabuf_ops_kmap, ++ .vmap = vb2_dc_dmabuf_ops_vmap, ++ .mmap = vb2_dc_dmabuf_ops_mmap, ++ .release = vb2_dc_dmabuf_ops_release, ++}; ++ ++static struct sg_table *vb2_dc_get_base_sgt(struct vb2_dc_buf *buf) ++{ ++ int ret; ++ struct sg_table *sgt; ++ ++ sgt = kmalloc(sizeof(*sgt), GFP_KERNEL); ++ if (!sgt) { ++ dev_err(buf->dev, "failed to alloc sg table\n"); ++ return NULL; ++ } ++ ++ ret = dma_get_sgtable(buf->dev, sgt, buf->vaddr, buf->dma_addr, ++ buf->size); ++ if (ret < 0) { ++ dev_err(buf->dev, "failed to get scatterlist from DMA API\n"); ++ kfree(sgt); ++ return NULL; ++ } ++ ++ return sgt; ++} ++ ++static struct dma_buf *vb2_dc_get_dmabuf(void *buf_priv, unsigned long flags) ++{ ++ struct vb2_dc_buf *buf = buf_priv; ++ struct dma_buf *dbuf; ++ DEFINE_DMA_BUF_EXPORT_INFO(exp_info); ++ ++ exp_info.ops = &vb2_dc_dmabuf_ops; ++ exp_info.size = buf->size; ++ exp_info.flags = flags; ++ exp_info.priv = buf; ++ ++ if (!buf->sgt_base) ++ buf->sgt_base = vb2_dc_get_base_sgt(buf); ++ ++ if (WARN_ON(!buf->sgt_base)) ++ return NULL; ++ ++ dbuf = dma_buf_export(&exp_info); ++ if (IS_ERR(dbuf)) ++ return NULL; ++ ++ /* dmabuf keeps reference to vb2 buffer */ ++ atomic_inc(&buf->refcount); ++ ++ return dbuf; ++} ++ ++/*********************************************/ ++/* callbacks for USERPTR buffers */ ++/*********************************************/ ++ ++static void vb2_dc_put_userptr(void *buf_priv) ++{ ++ struct vb2_dc_buf *buf = buf_priv; ++ struct sg_table *sgt = buf->dma_sgt; ++ int i; ++ struct page **pages; ++ ++ if (sgt) { ++ DEFINE_DMA_ATTRS(attrs); ++ ++ dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs); ++ /* ++ * No need to sync to CPU, it's already synced to the CPU ++ * since the finish() memop will have been called before this. ++ */ ++ dma_unmap_sg_attrs(buf->dev, sgt->sgl, sgt->orig_nents, ++ buf->dma_dir, &attrs); ++ pages = frame_vector_pages(buf->vec); ++ /* sgt should exist only if vector contains pages... */ ++ BUG_ON(IS_ERR(pages)); ++ for (i = 0; i < frame_vector_count(buf->vec); i++) ++ set_page_dirty_lock(pages[i]); ++ sg_free_table(sgt); ++ kfree(sgt); ++ } ++ vb2_destroy_framevec(buf->vec); ++ kfree(buf); ++} ++ ++/* ++ * For some kind of reserved memory there might be no struct page available, ++ * so all that can be done to support such 'pages' is to try to convert ++ * pfn to dma address or at the last resort just assume that ++ * dma address == physical address (like it has been assumed in earlier version ++ * of videobuf2-dma-contig ++ */ ++ ++#ifdef __arch_pfn_to_dma ++static inline dma_addr_t vb2_dc_pfn_to_dma(struct device *dev, unsigned long pfn) ++{ ++ return (dma_addr_t)__arch_pfn_to_dma(dev, pfn); ++} ++#elif defined(__pfn_to_bus) ++static inline dma_addr_t vb2_dc_pfn_to_dma(struct device *dev, unsigned long pfn) ++{ ++ return (dma_addr_t)__pfn_to_bus(pfn); ++} ++#elif defined(__pfn_to_phys) ++static inline dma_addr_t vb2_dc_pfn_to_dma(struct device *dev, unsigned long pfn) ++{ ++ return (dma_addr_t)__pfn_to_phys(pfn); ++} ++#else ++static inline dma_addr_t vb2_dc_pfn_to_dma(struct device *dev, unsigned long pfn) ++{ ++ /* really, we cannot do anything better at this point */ ++ return (dma_addr_t)(pfn) << PAGE_SHIFT; ++} ++#endif ++ ++static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned long vaddr, ++ unsigned long size, enum dma_data_direction dma_dir) ++{ ++ struct vb2_dc_conf *conf = alloc_ctx; ++ struct vb2_dc_buf *buf; ++ struct frame_vector *vec; ++ unsigned long offset; ++ int n_pages, i; ++ int ret = 0; ++ struct sg_table *sgt; ++ unsigned long contig_size; ++ unsigned long dma_align = dma_get_cache_alignment(); ++ DEFINE_DMA_ATTRS(attrs); ++ ++ dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs); ++ ++ /* Only cache aligned DMA transfers are reliable */ ++ if (!IS_ALIGNED(vaddr | size, dma_align)) { ++ pr_debug("user data must be aligned to %lu bytes\n", dma_align); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ if (!size) { ++ pr_debug("size is zero\n"); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ buf = kzalloc(sizeof *buf, GFP_KERNEL); ++ if (!buf) ++ return ERR_PTR(-ENOMEM); ++ ++ buf->dev = conf->dev; ++ buf->dma_dir = dma_dir; ++ ++ offset = vaddr & ~PAGE_MASK; ++ vec = vb2_create_framevec(vaddr, size, dma_dir == DMA_FROM_DEVICE); ++ if (IS_ERR(vec)) { ++ ret = PTR_ERR(vec); ++ goto fail_buf; ++ } ++ buf->vec = vec; ++ n_pages = frame_vector_count(vec); ++ ret = frame_vector_to_pages(vec); ++ if (ret < 0) { ++ unsigned long *nums = frame_vector_pfns(vec); ++ ++ /* ++ * Failed to convert to pages... Check the memory is physically ++ * contiguous and use direct mapping ++ */ ++ for (i = 1; i < n_pages; i++) ++ if (nums[i-1] + 1 != nums[i]) ++ goto fail_pfnvec; ++ buf->dma_addr = vb2_dc_pfn_to_dma(buf->dev, nums[0]); ++ goto out; ++ } ++ ++ sgt = kzalloc(sizeof(*sgt), GFP_KERNEL); ++ if (!sgt) { ++ pr_err("failed to allocate sg table\n"); ++ ret = -ENOMEM; ++ goto fail_pfnvec; ++ } ++ ++ ret = sg_alloc_table_from_pages(sgt, frame_vector_pages(vec), n_pages, ++ offset, size, GFP_KERNEL); ++ if (ret) { ++ pr_err("failed to initialize sg table\n"); ++ goto fail_sgt; ++ } ++ ++ /* ++ * No need to sync to the device, this will happen later when the ++ * prepare() memop is called. ++ */ ++ sgt->nents = dma_map_sg_attrs(buf->dev, sgt->sgl, sgt->orig_nents, ++ buf->dma_dir, &attrs); ++ if (sgt->nents <= 0) { ++ pr_err("failed to map scatterlist\n"); ++ ret = -EIO; ++ goto fail_sgt_init; ++ } ++ ++ contig_size = vb2_dc_get_contiguous_size(sgt); ++ if (contig_size < size) { ++ pr_err("contiguous mapping is too small %lu/%lu\n", ++ contig_size, size); ++ ret = -EFAULT; ++ goto fail_map_sg; ++ } ++ ++ buf->dma_addr = sg_dma_address(sgt->sgl); ++ buf->dma_sgt = sgt; ++out: ++ buf->size = size; ++ ++ return buf; ++ ++fail_map_sg: ++ dma_unmap_sg_attrs(buf->dev, sgt->sgl, sgt->orig_nents, ++ buf->dma_dir, &attrs); ++ ++fail_sgt_init: ++ sg_free_table(sgt); ++ ++fail_sgt: ++ kfree(sgt); ++ ++fail_pfnvec: ++ vb2_destroy_framevec(vec); ++ ++fail_buf: ++ kfree(buf); ++ ++ return ERR_PTR(ret); ++} ++ ++/*********************************************/ ++/* callbacks for DMABUF buffers */ ++/*********************************************/ ++ ++static int vb2_dc_map_dmabuf(void *mem_priv) ++{ ++ struct vb2_dc_buf *buf = mem_priv; ++ struct sg_table *sgt; ++ unsigned long contig_size; ++ ++ if (WARN_ON(!buf->db_attach)) { ++ pr_err("trying to pin a non attached buffer\n"); ++ return -EINVAL; ++ } ++ ++ if (WARN_ON(buf->dma_sgt)) { ++ pr_err("dmabuf buffer is already pinned\n"); ++ return 0; ++ } ++ ++ /* get the associated scatterlist for this buffer */ ++ sgt = dma_buf_map_attachment(buf->db_attach, buf->dma_dir); ++ if (IS_ERR(sgt)) { ++ pr_err("Error getting dmabuf scatterlist\n"); ++ return -EINVAL; ++ } ++ ++ /* checking if dmabuf is big enough to store contiguous chunk */ ++ contig_size = vb2_dc_get_contiguous_size(sgt); ++ if (contig_size < buf->size) { ++ pr_err("contiguous chunk is too small %lu/%lu b\n", ++ contig_size, buf->size); ++ dma_buf_unmap_attachment(buf->db_attach, sgt, buf->dma_dir); ++ return -EFAULT; ++ } ++ ++ buf->dma_addr = sg_dma_address(sgt->sgl); ++ buf->dma_sgt = sgt; ++ buf->vaddr = NULL; ++ ++ return 0; ++} ++ ++static void vb2_dc_unmap_dmabuf(void *mem_priv) ++{ ++ struct vb2_dc_buf *buf = mem_priv; ++ struct sg_table *sgt = buf->dma_sgt; ++ ++ if (WARN_ON(!buf->db_attach)) { ++ pr_err("trying to unpin a not attached buffer\n"); ++ return; ++ } ++ ++ if (WARN_ON(!sgt)) { ++ pr_err("dmabuf buffer is already unpinned\n"); ++ return; ++ } ++ ++ if (buf->vaddr) { ++ dma_buf_vunmap(buf->db_attach->dmabuf, buf->vaddr); ++ buf->vaddr = NULL; ++ } ++ dma_buf_unmap_attachment(buf->db_attach, sgt, buf->dma_dir); ++ ++ buf->dma_addr = 0; ++ buf->dma_sgt = NULL; ++} ++ ++static void vb2_dc_detach_dmabuf(void *mem_priv) ++{ ++ struct vb2_dc_buf *buf = mem_priv; ++ ++ /* if vb2 works correctly you should never detach mapped buffer */ ++ if (WARN_ON(buf->dma_addr)) ++ vb2_dc_unmap_dmabuf(buf); ++ ++ /* detach this attachment */ ++ dma_buf_detach(buf->db_attach->dmabuf, buf->db_attach); ++ kfree(buf); ++} ++ ++static void *vb2_dc_attach_dmabuf(void *alloc_ctx, struct dma_buf *dbuf, ++ unsigned long size, enum dma_data_direction dma_dir) ++{ ++ struct vb2_dc_conf *conf = alloc_ctx; ++ struct vb2_dc_buf *buf; ++ struct dma_buf_attachment *dba; ++ ++ if (dbuf->size < size) ++ return ERR_PTR(-EFAULT); ++ ++ buf = kzalloc(sizeof(*buf), GFP_KERNEL); ++ if (!buf) ++ return ERR_PTR(-ENOMEM); ++ ++ buf->dev = conf->dev; ++ /* create attachment for the dmabuf with the user device */ ++ dba = dma_buf_attach(dbuf, buf->dev); ++ if (IS_ERR(dba)) { ++ pr_err("failed to attach dmabuf\n"); ++ kfree(buf); ++ return dba; ++ } ++ ++ buf->dma_dir = dma_dir; ++ buf->size = size; ++ buf->db_attach = dba; ++ ++ return buf; ++} ++ ++/*********************************************/ ++/* DMA CONTIG exported functions */ ++/*********************************************/ ++ ++const struct vb2_mem_ops ingenic_vb2_dma_contig_memops = { ++ .alloc = vb2_dc_alloc, ++ .put = vb2_dc_put, ++ .get_dmabuf = vb2_dc_get_dmabuf, ++ .cookie = vb2_dc_cookie, ++ .vaddr = vb2_dc_vaddr, ++ .mmap = vb2_dc_mmap, ++ .get_userptr = vb2_dc_get_userptr, ++ .put_userptr = vb2_dc_put_userptr, ++ .prepare = vb2_dc_prepare, ++ .finish = vb2_dc_finish, ++ .map_dmabuf = vb2_dc_map_dmabuf, ++ .unmap_dmabuf = vb2_dc_unmap_dmabuf, ++ .attach_dmabuf = vb2_dc_attach_dmabuf, ++ .detach_dmabuf = vb2_dc_detach_dmabuf, ++ .num_users = vb2_dc_num_users, ++}; ++EXPORT_SYMBOL_GPL(ingenic_vb2_dma_contig_memops); ++ ++static int reserve_size = CONFIG_CAMERA_RESERVE_KB_SIZE; //unit: kb. ++static int __init set_camera_reserve(char *str) ++{ ++ reserve_size = simple_strtoul(str, &str, 0); ++ return 1; ++} ++ ++__setup("camera_reserve", set_camera_reserve); ++ ++ ++void *ingenic_vb2_dma_contig_init_ctx(struct device *dev) ++{ ++ struct vb2_dc_conf *conf; ++ ++ conf = kzalloc(sizeof *conf, GFP_KERNEL); ++ if (!conf) ++ return ERR_PTR(-ENOMEM); ++ ++ conf->dev = dev; ++ if(reserve_size > 0){ ++ conf->reserve_addr = dma_alloc_noncoherent(dev, reserve_size * 1024, &conf->reserve_phy_addr,GFP_KERNEL); ++ if(conf->reserve_addr) ++ conf->reserve_size = reserve_size * 1024; ++ printk("camera reserve memory size %dKByte Addr:%p\n",reserve_size,conf->reserve_addr); ++ } ++ ++ INIT_LIST_HEAD(&conf->top); ++ return conf; ++} ++EXPORT_SYMBOL_GPL(ingenic_vb2_dma_contig_init_ctx); ++ ++void ingenic_vb2_dma_contig_cleanup_ctx(void *alloc_ctx) ++{ ++ if (!IS_ERR_OR_NULL(alloc_ctx)) ++ kfree(alloc_ctx); ++} ++EXPORT_SYMBOL_GPL(ingenic_vb2_dma_contig_cleanup_ctx); ++ ++MODULE_DESCRIPTION("DMA-contig memory handling routines for videobuf2"); ++MODULE_AUTHOR("Pawel Osciak "); ++MODULE_LICENSE("GPL"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mfd_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mfd_Kconfig.patch new file mode 100644 index 00000000..1d935024 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mfd_Kconfig.patch @@ -0,0 +1,56 @@ +diff -drupN a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig +--- a/drivers/mfd/Kconfig 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/mfd/Kconfig 2022-06-09 05:02:30.000000000 +0300 +@@ -414,6 +414,31 @@ config MFD_JZ4740_ADC + Say yes here if you want support for the ADC unit in the JZ4740 SoC. + This driver is necessary for jz4740-battery and jz4740-hwmon driver. + ++config MFD_INGENIC_SADC_V13 ++ tristate "Support for the Ingenic T40 SADC core" ++ select MFD_CORE ++ depends on SOC_T40 || MACH_XBURST2 ++ help ++ Say yes here if you want support for the SADC unit in the T40 SoC. ++ This driver is necessary for Ingenic_battery driver. ++ ++config MFD_INGENIC_SADC_AUX ++ tristate "Support for the Ingenic T40 SADC AUX" ++ select MFD_CORE ++ depends on SOC_T40 || MACH_XBURST2 ++ help ++ Say yes here if you want support for the SADC unit in the T40 SoC. ++ This driver is necessary for ingenic_battery driver. ++ ++config MFD_INGENIC_TCU ++ bool "Ingenic tcu driver" ++ select MFD_CORE ++ select GENERIC_IRQ_CHIP ++ depends on MACH_XBURST || MACH_XBURST2 ++ help ++ Say yes here if you want support for the TCU unit in the ingenic SoC. ++ This driver is necessary for ingenic pwm or counter. ++ + config MFD_KEMPLD + tristate "Kontron module PLD device" + select MFD_CORE +@@ -774,6 +799,20 @@ config MFD_RC5T583 + Management system device. + This driver provides common support for accessing the device + through i2c interface. The device supports multiple sub-devices ++ like GPIO, interrupts, RTC, LDO and DCDC regulators, onkey. ++ Additional drivers must be enabled in order to use the ++ different functionality of the device. ++ ++config MFD_RN5T567 ++ bool "Ricoh RC5T567 Power Management system device" ++ depends on I2C=y ++ select MFD_CORE ++ select REGMAP_I2C ++ help ++ Select this option to get support for the RICOH567 Power ++ Management system device. ++ This driver provides common support for accessing the device ++ through i2c interface. The device supports multiple sub-devices + like GPIO, interrupts, RTC, LDO and DCDC regulators, onkey. + Additional drivers must be enabled in order to use the + different functionality of the device. diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mfd_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mfd_Makefile.patch new file mode 100644 index 00000000..014889bc --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mfd_Makefile.patch @@ -0,0 +1,21 @@ +diff -drupN a/drivers/mfd/Makefile b/drivers/mfd/Makefile +--- a/drivers/mfd/Makefile 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/mfd/Makefile 2022-06-09 05:02:30.000000000 +0300 +@@ -149,6 +149,9 @@ obj-$(CONFIG_LPC_ICH) += lpc_ich.o + obj-$(CONFIG_MFD_RDC321X) += rdc321x-southbridge.o + obj-$(CONFIG_MFD_JANZ_CMODIO) += janz-cmodio.o + obj-$(CONFIG_MFD_JZ4740_ADC) += jz4740-adc.o ++obj-$(CONFIG_MFD_INGENIC_SADC_V13) += ingenic_adc_v13.o ++obj-$(CONFIG_MFD_INGENIC_SADC_AUX) += ingenic_adc_aux.o ++obj-$(CONFIG_MFD_INGENIC_TCU) += ingenic-tcu.o + obj-$(CONFIG_MFD_TPS6586X) += tps6586x.o + obj-$(CONFIG_MFD_VX855) += vx855.o + obj-$(CONFIG_MFD_WL1273_CORE) += wl1273-core.o +@@ -173,6 +176,7 @@ obj-$(CONFIG_MFD_INTEL_MSIC) += intel_ms + obj-$(CONFIG_MFD_PALMAS) += palmas.o + obj-$(CONFIG_MFD_VIPERBOARD) += viperboard.o + obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o ++obj-$(CONFIG_MFD_RN5T567) += rn5t567.o rn5t567-irq.o + obj-$(CONFIG_MFD_RK808) += rk808.o + obj-$(CONFIG_MFD_RN5T618) += rn5t618.o + obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mfd_ingenic-tcu.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mfd_ingenic-tcu.c.patch new file mode 100644 index 00000000..9c108277 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mfd_ingenic-tcu.c.patch @@ -0,0 +1,931 @@ +diff -drupN a/drivers/mfd/ingenic-tcu.c b/drivers/mfd/ingenic-tcu.c +--- a/drivers/mfd/ingenic-tcu.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mfd/ingenic-tcu.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,927 @@ ++/* ++ * ingenic-tcu.c - Inegnic Soc TCU MFD driver. ++ * ++ * Copyright (C) 2015 Ingenic Semiconductor Co., Ltd. ++ * Written by bo.liu . ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++//#include ++#include ++#include ++#include ++#include ++ ++#define WDT_TDR (0x00) /* rw, 32, 0x???????? */ ++#define WDT_TCER (0x04) /* rw, 32, 0x???????? */ ++#define WDT_TCNT (0x08) /* rw, 32, 0x???????? */ ++#define WDT_TCSR (0x0c) /* rw, 32, 0x???????? */ ++ ++#define TCU_TSTR (0xF0) /* Timer Status Register,Only Used In Tcu2 Mode */ ++#define TCU_TSTSR (0xF4) /* Timer Status Set Register */ ++#define TCU_TSTCR (0xF8) /* Timer Status Clear Register */ ++#define TCU_TSR (0x1C) /* Timer Stop Register */ ++#define TCU_TSSR (0x2C) /* Timer Stop Set Register */ ++#define TCU_TSCR (0x3C) /* Timer Stop Clear Register */ ++#define TCU_TER (0x10) /* Timer Counter Enable Register */ ++#define TCU_TESR (0x14) /* Timer Counter Enable Set Register */ ++#define TCU_TECR (0x18) /* Timer Counter Enable Clear Register */ ++#define TCU_TFR (0x20) /* Timer Flag Register */ ++#define TCU_TFSR (0x24) /* Timer Flag Set Register */ ++#define TCU_TFCR (0x28) /* Timer Flag Clear Register */ ++#define TCU_TMR (0x30) /* Timer Mask Register */ ++#define TCU_TMSR (0x34) /* Timer Mask Set Register */ ++#define TCU_TMCR (0x38) /* Timer Mask Clear Register */ ++ ++#define CH_TDFR(n) (0x40 + (n)*0x10) /* Timer Data Full Reg */ ++#define CH_TDHR(n) (0x44 + (n)*0x10) /* Timer Data Half Reg */ ++#define CH_TCNT(n) (0x48 + (n)*0x10) /* Timer Counter Reg */ ++#define CH_TCSR(n) (0x4C + (n)*0x10) /* Timer Control Reg */ ++ ++#define TCSR_PWM_BYPASS (1 << 11) /* clear counter to 0, only used in TCU2 mode */ ++#define TCSR_CNT_CLRZ (1 << 10) /* clear counter to 0, only used in TCU2 mode */ ++#define TCSR_PWM_SD (1 << 9) /* shut down the pwm output only used in TCU1 mode */ ++#define TCSR_PWM_HIGH (1 << 8) /* selects an initial output level for pwm output */ ++#define TCSR_PWM_EN (1 << 7) /* pwm pin output enable */ ++#define TCSR_PWM_IN (1 << 6) /* pwm pin output enable */ ++ ++struct ingenic_tcu { ++ void __iomem *base; ++ struct device *dev; ++ struct clk *clk; ++ struct device_node *np; ++ struct irq_domain *irq_domain; ++ struct mfd_cell * tcu_cells; ++ struct ingenic_tcu_chn *tcu_chn; ++ ++ char idmap[32]; ++ int channel_mask; ++ int irq_tcu0; ++ int irq_tcu1; ++ int irq_tcu2; ++ int channel_num; ++ int channel_irq_num; ++ spinlock_t lock; ++}; ++ ++#define TCU_DEBUG 0 ++ ++static struct ingenic_tcu *tcu; ++ ++static inline int tcu_readl(struct ingenic_tcu *tcu, unsigned int reg_addr) ++{ ++ return readl(tcu->base + reg_addr); ++} ++static inline void tcu_writel(struct ingenic_tcu *tcu, unsigned int reg_addr, ++ unsigned int val) ++{ ++ writel(val, tcu->base + reg_addr); ++} ++#if TCU_DEBUG ++static void tcu_dump(int id) ++{ ++ printk("====================================channel %d===================================\n", id); ++ ++ if(id == 16){ ++ printk("tcu_readl(WDT_TDR %x) = %x\n", (unsigned int)(tcu->base + WDT_TDR), tcu_readl(tcu, WDT_TDR)); ++ printk("tcu_readl(WDT_TCER %x) = %x\n", (unsigned int)(tcu->base + WDT_TCER), tcu_readl(tcu, WDT_TCER)); ++ printk("tcu_readl(WDT_TCNT %x) = %x\n", (unsigned int)(tcu->base + WDT_TCNT), tcu_readl(tcu, WDT_TCNT)); ++ printk("tcu_readl(WDT_TCSR %x) = %x\n", (unsigned int)(tcu->base + WDT_TCSR), tcu_readl(tcu, WDT_TCSR)); ++ printk("tcu_readl(TCU_TSR %x) = %x\n", (unsigned int)(tcu->base + TCU_TSR), tcu_readl(tcu, TCU_TSR)); ++ return; ++ } ++ ++ printk("tcu_readl(CH_TDFR(id) %x) = %x\n", (unsigned int)(tcu->base + CH_TDFR(id)), tcu_readl(tcu, CH_TDFR(id))); ++ printk("tcu_readl(CH_TDHR(id) %x) = %x\n", (unsigned int)(tcu->base + CH_TDHR(id)), tcu_readl(tcu, CH_TDHR(id))); ++ printk("tcu_readl(CH_TCNT(id) %x) = %x\n", (unsigned int)(tcu->base + CH_TCNT(id)), tcu_readl(tcu, CH_TCNT(id))); ++ printk("tcu_readl(CH_TCSR(id) %x) = %x\n", (unsigned int)(tcu->base + CH_TCSR(id)), tcu_readl(tcu, CH_TCSR(id))); ++ ++ printk("tcu_readl(TCU_TSTR %x) = %x\n", (unsigned int)(tcu->base + TCU_TSTR), tcu_readl(tcu, TCU_TSTR)); ++ printk("tcu_readl(TCU_TSR %x) = %x\n", (unsigned int)(tcu->base + TCU_TSR), tcu_readl(tcu, TCU_TSR)); ++ printk("tcu_readl(TCU_TER %x) = %x\n", (unsigned int)(tcu->base + TCU_TER), tcu_readl(tcu, TCU_TER)); ++ printk("tcu_readl(TCU_TFR %x) = %x\n", (unsigned int)(tcu->base + TCU_TFR), tcu_readl(tcu, TCU_TFR)); ++ printk("tcu_readl(TCU_TMR %x) = %x\n", (unsigned int)(tcu->base + TCU_TMR), tcu_readl(tcu, TCU_TMR)); ++ printk("=======================================================================\n"); ++} ++#endif ++ ++static inline void tcu_mask_full_irq(int id) ++{ ++ tcu_writel(tcu, TCU_TMSR, 1 << id); ++} ++static inline void tcu_unmask_full_irq(int id) ++{ ++ tcu_writel(tcu, TCU_TMCR, 1 << id); ++} ++static inline void tcu_clear_full_irq(int id) ++{ ++ tcu_writel(tcu, TCU_TFCR, 1 << id); ++} ++static inline void tcu_mask_half_irq(int id) ++{ ++ tcu_writel(tcu, TCU_TMSR, 1 << (id + 16)); ++} ++static inline void tcu_unmask_half_irq(int id) ++{ ++ tcu_writel(tcu, TCU_TMCR, 1 << (id + 16)); ++} ++static inline void tcu_clear_half_irq(int id) ++{ ++ tcu_writel(tcu, TCU_TFCR, 1 << (id + 16)); ++} ++ ++void tcu_enable_counter(int id) ++{ ++ tcu_writel(tcu, TCU_TESR, BIT(id)); ++} ++EXPORT_SYMBOL_GPL(tcu_enable_counter); ++ ++void tcu_disable_counter(int id) ++{ ++ int index = tcu->idmap[id]; ++ struct ingenic_tcu_chn *chn = &tcu->tcu_chn[index]; ++ tcu_writel(tcu, TCU_TECR, BIT(id)); ++ if (chn->cib.mode == TCU_MODE2) { ++ int timeout = 5000; ++ while ((tcu_readl(tcu, TCU_TSTR) & (1 << id)) || (timeout--)); ++ if(!timeout){ ++ dev_err(tcu->dev, "channel %d:the reset of counter is not finished now\n", id); ++ } ++ } ++} ++EXPORT_SYMBOL_GPL(tcu_disable_counter); ++ ++void tcu_start_counter(int id) ++{ ++ tcu_writel(tcu, TCU_TSCR, BIT(id)); ++} ++EXPORT_SYMBOL_GPL(tcu_start_counter); ++ ++void tcu_stop_counter(int id) ++{ ++ tcu_writel(tcu, TCU_TSSR, BIT(id)); ++} ++EXPORT_SYMBOL_GPL(tcu_stop_counter); ++ ++void tcu_set_counter(int id, unsigned int val) ++{ ++ tcu_writel(tcu, CH_TCNT(id), val); ++} ++EXPORT_SYMBOL_GPL(tcu_set_counter); ++ ++int tcu_get_counter(int id) ++{ ++ return tcu_readl(tcu, CH_TCNT(id)); ++} ++EXPORT_SYMBOL_GPL(tcu_get_counter); ++ ++static inline void tcu_disable_all_channel(void) ++{ ++ /* Timer irqs are unmasked by default, mask them */ ++ /*tcu_writel(tcu, TCU_TMSR, 0x00ff00ff);*/ ++ tcu_writel(tcu, TCU_TMSR, 0x00ff00f7);/*tcu3 no set*/ ++ /* Stop all timer counter */ ++ /*tcu_writel(tcu, TCU_TECR, 0x000080ff);*/ ++ tcu_writel(tcu, TCU_TECR, 0x000080f7);/*tcu3 no stop*/ ++ /* Disable all timer clocks except for those used as system timers */ ++ /*tcu_writel(tcu, TCU_TSSR, 0x000000ff);*/ ++ tcu_writel(tcu, TCU_TSSR, 0x000000f7);/*tcu3 no stop*/ ++} ++ ++static int tcu_pwm_output_enable(int id) ++{ ++ unsigned int val; ++ ++ val = tcu_readl(tcu, CH_TCSR(id)); ++ val |= TCSR_PWM_EN; ++ tcu_writel(tcu, CH_TCSR(id), val); ++ ++ return 0; ++} ++ ++static void tcu_pwm_output_disable(int id) ++{ ++ unsigned int val; ++ val = tcu_readl(tcu, CH_TCSR(id)); ++ val &= ~TCSR_PWM_EN; ++ tcu_writel(tcu, CH_TCSR(id), val); ++} ++ ++static int tcu_pwm_bypass_enable(int id) ++{ ++ unsigned int val; ++ ++ val = tcu_readl(tcu, CH_TCSR(id)); ++ if(val & TCU_CLKSRC_PCK) { ++ dev_err(tcu->dev, "TCU %d pwm bypass is not support clk source pck\n", id); ++ return -ENXIO; ++ } ++ val |= TCSR_PWM_BYPASS; ++ tcu_writel(tcu, CH_TCSR(id), val); ++ ++ return 0; ++} ++ ++static int tcu_pwm_bypass_disable(int id) ++{ ++ unsigned int val; ++ ++ val = tcu_readl(tcu, CH_TCSR(id)); ++ val &= ~TCSR_PWM_BYPASS; ++ tcu_writel(tcu, CH_TCSR(id), val); ++ ++ return 0; ++} ++ ++static void tcu_clear_counter_to_zero(int id) ++{ ++ int index = tcu->idmap[id]; ++ struct ingenic_tcu_chn *chn = &tcu->tcu_chn[index]; ++ if (chn->cib.mode == TCU_MODE2) { ++ unsigned int val = tcu_readl(tcu, CH_TCSR(id)); ++ tcu_writel(tcu, CH_TCSR(id), (val | TCSR_CNT_CLRZ)); ++ } ++ ++ tcu_writel(tcu, CH_TCNT(id), 0); ++} ++ ++static void set_tcu_full_half_value(int id, unsigned int full_num, ++ unsigned int half_num) ++{ ++ tcu_writel(tcu, CH_TDFR(id), full_num); ++ tcu_writel(tcu, CH_TDHR(id), half_num); ++} ++ ++static void tcu_set_pwm_shutdown(int id, unsigned int shutdown) ++{ ++ unsigned int val; ++ ++ val = tcu_readl(tcu, CH_TCSR(id)); ++ if (shutdown) ++ val |= TCSR_PWM_SD; ++ else ++ val &= ~TCSR_PWM_SD; ++ tcu_writel(tcu, CH_TCSR(id), val); ++} ++ ++static void tcu_set_start_state(int id) ++{ ++ /*fix this*/ ++ /*tcu_disable_counter(id);*/ ++ tcu_start_counter(id); ++ tcu_writel(tcu, CH_TCSR(id), 0); ++} ++ ++static void tcu_pwm_input_enable(int id) ++{ ++ unsigned int val; ++ ++ val = tcu_readl(tcu, CH_TCSR(id)); ++ val |= TCSR_PWM_IN; ++ tcu_writel(tcu, CH_TCSR(id), val); ++} ++ ++static void tcu_pwm_input_disable(int id) ++{ ++ unsigned int val; ++ ++ val = tcu_readl(tcu, CH_TCSR(id)); ++ val &= ~TCSR_PWM_IN; ++ tcu_writel(tcu, CH_TCSR(id), val); ++} ++ ++static int tcu_clock_enable(struct platform_device *pdev) ++{ ++ if (!(tcu->channel_mask & BIT(pdev->id))) { ++ dev_err(&pdev->dev, ++ "current tcu channel %d busy\n",pdev->id); ++ return -EINVAL; ++ } ++ ++ if(pdev->id != 16) ++ tcu_enable_counter(pdev->id); ++ ++ tcu_start_counter(pdev->id); ++ tcu->channel_mask &= ~(BIT(pdev->id)); ++ return 0; ++} ++ ++static int tcu_clock_disable(struct platform_device *pdev) ++{ ++ struct ingenic_tcu *tcu = dev_get_drvdata(pdev->dev.parent); ++ int id = pdev->id; ++ int index = tcu->idmap[id]; ++ struct ingenic_tcu_chn *chn = &tcu->tcu_chn[index]; ++ ++ if(id != 16) { ++ switch (chn->irq_type) { ++ case FULL_IRQ_MODE : ++ tcu_unmask_full_irq(id); ++ tcu_clear_full_irq(id); ++ break; ++ case HALF_IRQ_MODE : ++ tcu_unmask_half_irq(id); ++ tcu_clear_half_irq(id); ++ break; ++ case FULL_HALF_IRQ_MODE : ++ tcu_unmask_full_irq(id); ++ tcu_unmask_half_irq(id); ++ tcu_clear_full_irq(id); ++ tcu_clear_half_irq(id); ++ break; ++ default : ++ break; ++ } ++ if(chn->is_count_clear) { ++ unsigned long flags; ++ ++ tcu_disable_counter(id); ++ spin_lock_irqsave(&tcu->lock, flags); ++ tcu_clear_counter_to_zero(id); ++ spin_unlock_irqrestore(&tcu->lock, flags); ++ } ++ } ++ tcu_stop_counter(id); ++ tcu->channel_mask |= BIT(pdev->id); ++ return 0; ++} ++ ++int ingenic_tcu_counter_begin(struct ingenic_tcu_chn *chn) ++{ ++ int ret = 0; ++ ++ if (chn->is_pwm) { ++ unsigned long flags; ++ ++ spin_lock_irqsave(&tcu->lock, flags); ++ tcu_pwm_output_enable(chn->cib.id); ++ spin_unlock_irqrestore(&tcu->lock, flags); ++ } ++ tcu_enable_counter(chn->cib.id); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(ingenic_tcu_counter_begin); ++ ++void ingenic_tcu_counter_stop(struct ingenic_tcu_chn *chn) ++{ ++ if (chn->is_pwm) { ++ unsigned long flags; ++ ++ spin_lock_irqsave(&tcu->lock, flags); ++ tcu_pwm_output_disable(chn->cib.id); ++ spin_unlock_irqrestore(&tcu->lock, flags); ++ } ++ ++ tcu_disable_counter(chn->cib.id); ++} ++EXPORT_SYMBOL_GPL(ingenic_tcu_counter_stop); ++ ++void ingenic_tcu_set_period(int id, uint16_t period) ++{ ++ tcu_writel(tcu, CH_TDFR(id), period); ++} ++EXPORT_SYMBOL_GPL(ingenic_tcu_set_period); ++ ++void ingenic_tcu_set_duty(int id, uint16_t duty) ++{ ++ tcu_writel(tcu, CH_TDHR(id), duty); ++} ++EXPORT_SYMBOL_GPL(ingenic_tcu_set_duty); ++ ++void ingenic_tcu_set_prescale(int id, enum tcu_prescale prescale) ++{ ++ unsigned int val; ++ unsigned long flags; ++ ++ //spin_lock_irqsave(&tcu->lock, flags); ++ val = tcu_readl(tcu, CH_TCSR(id)); ++ val &= ~(0x7 << 3); ++ val |= (prescale << 3); ++ tcu_writel(tcu, CH_TCSR(id), val); ++ //spin_unlock_irqrestore(&tcu->lock, flags); ++} ++EXPORT_SYMBOL_GPL(ingenic_tcu_set_prescale); ++ ++void ingenic_tcu_set_pwm_output_init_level(int id, int level) ++{ ++ unsigned int val; ++ unsigned long flags; ++ ++ //spin_lock_irqsave(&tcu->lock, flags); ++ val = tcu_readl(tcu, CH_TCSR(id)); ++ if (level) ++ val |= (TCSR_PWM_HIGH); ++ else ++ val &= ~(TCSR_PWM_HIGH); ++ tcu_writel(tcu, CH_TCSR(id), val); ++ //spin_unlock_irqrestore(&tcu->lock, flags); ++} ++EXPORT_SYMBOL_GPL(ingenic_tcu_set_pwm_output_init_level); ++ ++void ingenic_tcu_set_clksrc(int id, enum tcu_clksrc src) ++{ ++ unsigned int val; ++ unsigned long flags; ++ ++ //spin_lock_irqsave(&tcu->lock, flags); ++ val = tcu_readl(tcu, CH_TCSR(id)); ++ val &= ~0x7; ++ val |= src; ++ tcu_writel(tcu, CH_TCSR(id), val); ++ ++ //spin_unlock_irqrestore(&tcu->lock, flags); ++} ++EXPORT_SYMBOL_GPL(ingenic_tcu_set_clksrc); ++ ++int ingenic_tcu_get_count(int id) ++{ ++ if(id == 1 || id == 2) { ++ int i = 0; ++ int tmp = 0; ++ ++ while ((tmp == 0) && (i < 5)) { ++ tmp = tcu_readl(tcu, TCU_TSTR) & (1 << (id + 16)); ++ i++; ++ } ++ if (tmp == 0) ++ return -EINVAL; ++ } ++ return tcu_get_counter(id); ++} ++EXPORT_SYMBOL_GPL(ingenic_tcu_get_count); ++ ++void ingenic_tcu_channel_to_virq(struct ingenic_tcu_chn *chn) ++{ ++ int index; ++ ++ if(chn->cib.id == 5) { ++ chn->virq[0] = tcu->irq_tcu1; ++ return; ++ } ++ if(chn->cib.id == 15) { ++ chn->virq[0] = tcu->irq_tcu0; ++ return; ++ } ++ index = chn->cib.id * 2; ++ ++ switch (chn->irq_type) { ++ case FULL_IRQ_MODE : ++ chn->virq[0] = irq_create_mapping(tcu->irq_domain, index); ++ break; ++ case HALF_IRQ_MODE : ++ chn->virq[1] = irq_create_mapping(tcu->irq_domain, index + 1); ++ break; ++ case FULL_HALF_IRQ_MODE : ++ chn->virq[0] = irq_create_mapping(tcu->irq_domain, index); ++ chn->virq[1] = irq_create_mapping(tcu->irq_domain, index + 1); ++ break; ++ default: ++ break; ++ } ++ ++ if(chn->virq[0] < 0 || chn->virq[1] < 0) ++ return; ++ ++ if(chn->virq[0]) ++ irq_set_chip_data(chn->virq[0], chn); ++ ++ if(chn->virq[1]) ++ irq_set_chip_data(chn->virq[1], chn); ++} ++EXPORT_SYMBOL_GPL(ingenic_tcu_channel_to_virq); ++ ++void ingenic_watchdog_set_count(unsigned int value) ++{ ++ tcu_writel(tcu, WDT_TCNT, value); ++} ++EXPORT_SYMBOL_GPL(ingenic_watchdog_set_count); ++ ++void ingenic_watchdog_config(unsigned int tcsr_val, unsigned int timeout_value) ++{ ++ tcu_writel(tcu, WDT_TCER, 0); ++ tcu_writel(tcu, WDT_TCSR, tcsr_val); ++ tcu_writel(tcu, WDT_TDR, timeout_value); ++ tcu_writel(tcu, WDT_TCNT, 0); ++ tcu_writel(tcu, WDT_TCER, 1); ++} ++EXPORT_SYMBOL_GPL(ingenic_watchdog_config); ++ ++struct mfd_cell *request_cell(int id) ++{ ++ int i; ++ if (!(tcu->channel_mask & BIT(id))) { ++ dev_err(tcu->dev, ++ "current tcu channel %d busy\n",id); ++ return NULL; ++ } ++ ++ i = tcu->idmap[id]; ++ tcu->channel_mask &= ~(BIT(id)); ++ ++ return &(tcu->tcu_cells[i]); ++} ++EXPORT_SYMBOL_GPL(request_cell); ++ ++void free_cell(int id) ++{ ++ tcu->channel_mask |= BIT(id); ++} ++EXPORT_SYMBOL_GPL(free_cell); ++ ++static int check_pwm_is_availabl(struct ingenic_tcu_chn *chn) ++{ ++ int id = chn->cib.id; ++ if(id != 15) { ++ if(chn->is_pwm && !(chn->cib.func & PWM_FUNC)) { ++ dev_err(tcu->dev, "channel %d not support pwm function\n", id); ++ return -1; ++ } else if(!chn->is_pwm && !(chn->cib.func & TRACKBALL_FUNC)) { ++ dev_err(tcu->dev, "channel %d not support trackball function\n", id); ++ return -1; ++ } ++ if(chn->pwm_in_en && !chn->cib.pwmin) { ++ dev_err(tcu->dev, "channel %d not support pwm in function\n", id); ++ return -1; ++ } ++ } ++ return 0; ++} ++ ++int ingenic_tcu_config(struct ingenic_tcu_chn *chn) ++{ ++ unsigned long flags; ++ int id = chn->cib.id; ++ ++ if(check_pwm_is_availabl(chn) < 0) ++ return -1; ++ ++ tcu_set_start_state(id); ++ ++ tcu_clear_full_irq(id); ++ tcu_clear_half_irq(id); ++ ++ switch (chn->irq_type) { ++ case NULL_IRQ_MODE : ++ tcu_mask_full_irq(id); ++ tcu_mask_half_irq(id); ++ tcu_clear_full_irq(id); ++ tcu_clear_half_irq(id); ++ break; ++ case FULL_IRQ_MODE : ++ tcu_unmask_full_irq(id); ++ tcu_mask_half_irq(id); ++ tcu_clear_full_irq(id); ++ break; ++ case HALF_IRQ_MODE : ++ tcu_mask_full_irq(id); ++ tcu_unmask_half_irq(id); ++ tcu_clear_half_irq(id); ++ break; ++ case FULL_HALF_IRQ_MODE : ++ tcu_unmask_full_irq(id); ++ tcu_unmask_half_irq(id); ++ tcu_clear_full_irq(id); ++ tcu_clear_half_irq(id); ++ break; ++ default : ++ break; ++ } ++ spin_lock_irqsave(&tcu->lock, flags); ++ ++ ingenic_tcu_set_pwm_output_init_level(id, chn->init_level); ++ ++ if(chn->cib.mode == TCU_MODE1) { ++ tcu_set_pwm_shutdown(id, chn->shutdown_mode); ++ } ++ ++ if (chn->is_pwm) { ++ tcu_pwm_output_enable(id); ++ if(chn->pwm_bapass_mode) { ++ if(chn->clk_src == TCU_CLKSRC_PCK) { ++ dev_err(tcu->dev, "the current version can not bypass pclk\n"); ++ } ++ tcu_pwm_bypass_enable(id); ++ } else { ++ tcu_pwm_bypass_disable(id); ++ } ++ } else { ++ tcu_pwm_output_disable(id); ++ } ++ ++ ingenic_tcu_set_prescale(id, chn->clk_div); ++ set_tcu_full_half_value(id, chn->full_num, chn->half_num); ++ if (chn->pwm_in_en) ++ tcu_pwm_input_enable(id); ++ else ++ tcu_pwm_input_disable(id); ++ ingenic_tcu_set_clksrc(id, chn->clk_src); ++ tcu_clear_counter_to_zero(id); ++ ++ spin_unlock_irqrestore(&tcu->lock, flags); ++ return 0; ++} ++EXPORT_SYMBOL_GPL(ingenic_tcu_config); ++ ++static void tcu_irq_mask(struct irq_data *data) ++{ ++ struct ingenic_tcu_chn *chn = irq_data_get_irq_chip_data(data); ++ int id = chn->cib.id; ++ ++ switch (chn->irq_type) { ++ case FULL_IRQ_MODE : ++ tcu_mask_full_irq(id); ++ break; ++ case HALF_IRQ_MODE : ++ tcu_mask_half_irq(id); ++ break; ++ case FULL_HALF_IRQ_MODE : ++ tcu_mask_full_irq(id); ++ tcu_mask_half_irq(id); ++ break; ++ default: ++ break; ++ } ++} ++ ++static void tcu_irq_unmask(struct irq_data *data) ++{ ++ struct ingenic_tcu_chn *chn = irq_data_get_irq_chip_data(data); ++ int id = chn->cib.id; ++ ++ switch (chn->irq_type) { ++ case FULL_IRQ_MODE : ++ tcu_unmask_full_irq(id); ++ break; ++ case HALF_IRQ_MODE : ++ tcu_unmask_half_irq(id); ++ break; ++ case FULL_HALF_IRQ_MODE : ++ tcu_unmask_full_irq(id); ++ tcu_unmask_half_irq(id); ++ break; ++ default: ++ break; ++ } ++} ++ ++static void tcu_mask_and_ack_irq(struct irq_data *data) ++{ ++ struct ingenic_tcu_chn *chn = irq_data_get_irq_chip_data(data); ++ int id = chn->cib.id; ++ ++ switch (chn->irq_type) { ++ case FULL_IRQ_MODE : ++ tcu_mask_full_irq(id); ++ tcu_clear_full_irq(id); ++ break; ++ case HALF_IRQ_MODE : ++ tcu_mask_half_irq(id); ++ tcu_clear_half_irq(id); ++ break; ++ case FULL_HALF_IRQ_MODE : ++ tcu_mask_full_irq(id); ++ tcu_mask_half_irq(id); ++ tcu_clear_full_irq(id); ++ tcu_clear_half_irq(id); ++ break; ++ default : ++ break; ++ } ++} ++ ++static struct irq_chip tcu_irq_chip = { ++ .name = "ingenic-tcu", ++ .irq_disable = tcu_mask_and_ack_irq, ++ .irq_enable = tcu_irq_unmask, ++ .irq_unmask = tcu_irq_unmask, ++ .irq_mask = tcu_irq_mask, ++ .irq_mask_ack = tcu_mask_and_ack_irq, ++}; ++ ++static int tcu2_irq_domain_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw) ++{ ++ struct ingenic_tcu *tcu = d->host_data; ++ ++ irq_set_chip_data(virq, tcu); ++ irq_set_chip_and_handler(virq, &tcu_irq_chip, handle_level_irq); ++ return 0; ++} ++ ++static const struct irq_domain_ops tcu2_irq_domain_ops = { ++ .map = tcu2_irq_domain_map, ++ .xlate = irq_domain_xlate_onetwocell, ++}; ++ ++static void tcu_irq_demux(struct irq_desc *desc) ++{ ++ struct ingenic_tcu *tcu = irq_desc_get_handler_data(desc); ++ unsigned long pend, mask, tcu2_pend = 0; ++ ++ pend = readl(tcu->base + TCU_TFR); ++ mask = readl(tcu->base + TCU_TMR) | (1 << 5 | 1 << (5 + 16)); ++ ++ pend = pend & ~(mask); ++ while(pend) { ++ struct ingenic_tcu_chn *chn; ++ int index; ++ ++ tcu2_pend = ffs(pend) - 1; ++ index = tcu->idmap[tcu2_pend]; ++ chn = &tcu->tcu_chn[index]; ++ if ((pend & 0xffff)){ ++ generic_handle_irq(chn->virq[FULL_BIT]); ++ } else { ++ generic_handle_irq(chn->virq[HALF_BIT]); ++ } ++ pend &= ~(1 << tcu2_pend); ++ } ++} ++ ++static int __init setup_tcu_irq(struct ingenic_tcu *tcu) ++{ ++ irq_set_chip_and_handler(tcu->irq_tcu0, &tcu_irq_chip, handle_level_irq); ++ irq_set_chip_and_handler(tcu->irq_tcu1, &tcu_irq_chip, handle_level_irq); ++ ++ tcu->irq_domain = irq_domain_add_linear(tcu->np, tcu->channel_irq_num, &tcu2_irq_domain_ops, (void *)tcu); ++ if(!tcu->irq_domain) { ++ pr_err("Failed to add tcu irq into irq domain\n"); ++ return -ENOMEM; ++ } ++ irq_set_chained_handler_and_data(tcu->irq_tcu2, tcu_irq_demux, tcu); ++ ++ return 0; ++} ++ ++static int init_mfd_cells(struct ingenic_tcu *tcu, struct mfd_cell *cells) ++{ ++ struct device_node *child; ++ int i = 0, ret; ++ ++ for_each_child_of_node(tcu->np, child) { ++ const char *tmp = NULL; ++ int id; ++ struct ingenic_tcu_chn *chn = &tcu->tcu_chn[i]; ++ ++ ret = of_property_read_u32(child, "ingenic,channel-info", &chn->chn_info); ++ if (ret < 0) { ++ dev_err(tcu->dev, "Cannot get ingenic,channel-info\n"); ++ return -ENOENT; ++ } ++ ret = of_property_read_string(child, "compatible", &tmp); ++ if (ret < 0) { ++ dev_err(tcu->dev, "Cannot get compatible string\n"); ++ return -ENOENT; ++ } ++ ++ id = chn->cib.id; ++ tcu->idmap[id] = i; ++ tcu->channel_mask |= BIT(id); ++ chn->enable = tcu_start_counter; ++ chn->disable = tcu_stop_counter; ++ cells[i].id = id; ++ cells[i].name = tmp; ++ cells[i].pdata_size = sizeof(struct ingenic_tcu_chn); ++ cells[i].of_compatible = tmp; ++ cells[i].platform_data = chn; ++ cells[i].enable = tcu_clock_enable; ++ cells[i].disable = tcu_clock_disable; ++ i ++; ++ } ++ /* for(i = 0; i < tcu->channel_num; i++) { */ ++ /* printk("id = %d, name = %s, of_com = %s\n", cells[i].id, cells[i].name, cells[i].of_compatible); */ ++ /* } */ ++ return 0; ++} ++static int ingenic_tcu_probe(struct platform_device *pdev) ++{ ++ struct resource *res; ++ int ret = 0; ++ ++ tcu = devm_kzalloc(&pdev->dev, sizeof(struct ingenic_tcu), GFP_KERNEL); ++ if (!tcu) { ++ dev_err(&pdev->dev, "Failed to allocate driver structure\n"); ++ return -ENOMEM; ++ } ++ ++ tcu->np = pdev->dev.of_node; ++ tcu->dev = &pdev->dev; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (res == NULL) { ++ dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n"); ++ return -ENOENT; ++ } ++ tcu->base = devm_ioremap_resource(&pdev->dev, res); ++ if (tcu->base == NULL) { ++ dev_err(&pdev->dev, "Cannot map IO\n"); ++ return -ENXIO; ++ } ++ tcu->irq_tcu0 = of_irq_get_byname(tcu->np, "tcu_int0"); ++ if (tcu->irq_tcu0 < 0) { ++ dev_err(tcu->dev, "int0:unable to get IRQ from DT, %d\n", tcu->irq_tcu0); ++ return -ENXIO; ++ } ++ tcu->irq_tcu1 = of_irq_get_byname(tcu->np, "tcu_int1"); ++ if (tcu->irq_tcu1 < 0) { ++ dev_err(tcu->dev, "int1:unable to get IRQ from DT, %d\n", tcu->irq_tcu1); ++ return -ENXIO; ++ } ++ tcu->irq_tcu2 = of_irq_get_byname(tcu->np, "tcu_int2"); ++ if (tcu->irq_tcu2 < 0) { ++ dev_err(tcu->dev, "int2:unable to get IRQ from DT, %d\n", tcu->irq_tcu2); ++ return -ENXIO; ++ } ++ ++ tcu->clk = devm_clk_get(tcu->dev,"gate_tcu"); ++ clk_prepare_enable(tcu->clk); ++ ++ tcu->channel_num = of_get_child_count(tcu->np); ++ tcu->tcu_chn = devm_kzalloc(tcu->dev, sizeof(struct ingenic_tcu_chn) * tcu->channel_num, ++ GFP_KERNEL); ++ if (!tcu->tcu_chn) { ++ dev_err(tcu->dev, "Failed to allocate driver structure tcu_channel\n"); ++ return -ENOMEM; ++ } ++ tcu->channel_irq_num = (tcu->channel_num - 1) * 2; ++ ++ setup_tcu_irq(tcu); ++ ++ spin_lock_init(&tcu->lock); ++ platform_set_drvdata(pdev, tcu); ++ ++ tcu_disable_all_channel(); ++ ++ tcu->tcu_cells = devm_kzalloc(tcu->dev, sizeof(struct mfd_cell) * tcu->channel_num, ++ GFP_KERNEL); ++ if (!tcu->tcu_cells) { ++ dev_err(tcu->dev, "Failed to allocate driver structure cells\n"); ++ return -ENOMEM; ++ } ++ ++ init_mfd_cells(tcu, tcu->tcu_cells); ++ ++ ret = mfd_add_devices(&pdev->dev, 0, tcu->tcu_cells, ++ tcu->channel_num, res, tcu->irq_tcu0, NULL); ++ ++ dev_info(&pdev->dev, "Ingenic TCU driver register completed ret = %d\n", ret); ++ ++ return 0; ++} ++ ++static int ingenic_tcu_remove(struct platform_device *pdev) ++{ ++ struct ingenic_tcu *tcu = platform_get_drvdata(pdev); ++ ++ clk_disable_unprepare(tcu->clk); ++ ++ mfd_remove_devices(&pdev->dev); ++ ++ irq_set_handler_data(tcu->irq_tcu0, NULL); ++ irq_set_chained_handler(tcu->irq_tcu0, NULL); ++ ++ irq_set_handler_data(tcu->irq_tcu1, NULL); ++ irq_set_chained_handler(tcu->irq_tcu1, NULL); ++ ++ platform_set_drvdata(pdev, NULL); ++ ++ devm_kfree(&pdev->dev, tcu); ++ ++ return 0; ++} ++ ++static const struct of_device_id tcu_match[] = { ++ { .compatible = "ingenic,tcu", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, tcu_match); ++ ++static struct platform_driver ingenic_tcu_driver = { ++ .probe = ingenic_tcu_probe, ++ .remove = ingenic_tcu_remove, ++ .driver = { ++ .name = "ingenic-tcu", ++ .of_match_table = tcu_match, ++ }, ++}; ++ ++module_platform_driver(ingenic_tcu_driver); ++ ++MODULE_DESCRIPTION("ingenic SoC TCU driver"); ++MODULE_AUTHOR("bo.liu "); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:ingenic-tcu"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mfd_ingenic_adc_aux.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mfd_ingenic_adc_aux.c.patch new file mode 100644 index 00000000..4e9077a0 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mfd_ingenic_adc_aux.c.patch @@ -0,0 +1,351 @@ +diff -drupN a/drivers/mfd/ingenic_adc_aux.c b/drivers/mfd/ingenic_adc_aux.c +--- a/drivers/mfd/ingenic_adc_aux.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mfd/ingenic_adc_aux.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,347 @@ ++/** ++ * drivers/mfd/ingenic-adc-aux.c ++ * ++ * aux1 aux2 channels voltage sample interface for Ingenic SoC ++ * ++ * Copyright(C)2012 Ingenic Semiconductor Co., LTD. ++ * http://www.ingenic.cn ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include /*for vfree*/ ++#include ++ ++#include ++ ++static unsigned long int VREF_ADC = 1800; ++ ++#define AUXCONST 4096 ++ ++#define ADC_MAGIC_NUMBER 'A' ++#define ADC_ENABLE _IO(ADC_MAGIC_NUMBER, 11) ++#define ADC_DISABLE _IO(ADC_MAGIC_NUMBER, 22) ++#define ADC_SET_VREF _IOW(ADC_MAGIC_NUMBER, 33, unsigned int) ++ ++#ifndef BITS_H2L ++#define BITS_H2L(msb, lsb) ((0xFFFFFFFF >> (32-((msb)-(lsb)+1))) << (lsb)) ++#endif ++ ++/** ++ * * INIT_COMPLETION - reinitialize a completion structure ++ * * @x: completion structure to be reinitialized ++ * * ++ * * This macro should be used to reinitialize a completion structure so it can ++ * * be reused. This is especially important after complete_all() is used. ++ * */ ++#define INIT_COMPLETION(x) ((x).done = 0) ++ ++ ++struct ingenic_adc_aux { ++ struct platform_device *pdev; ++ ++ struct resource *mem; ++ void __iomem *base; ++ ++ int irq; ++ ++ const struct mfd_cell *cell; ++ ++ unsigned int voltage; ++ ++ struct completion read_completion; ++ ++ struct miscdevice mdev; ++}; ++ ++ ++enum aux_ch { ++ SADC_AUX0, ++ SADC_AUX1, ++ SADC_AUX2, ++ SADC_AUX3, ++}; ++extern int ingenic_adc_set_config(struct device *dev, uint32_t mask, uint32_t val); ++ ++static irqreturn_t ingenic_ingenic_adc_aux_irq_handler(int irq, void *devid) ++{ ++ struct ingenic_adc_aux *ingenic_adc_aux = (struct ingenic_adc_aux *)devid; ++ ++ complete(&ingenic_adc_aux->read_completion); ++ ++ return IRQ_HANDLED; ++} ++ ++static int ingenic_adc_aux_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ //struct ingenic_adc_aux *adc_aux = platform_get_drvdata(pdev); ++ //adc_aux->cell->disable(pdev); ++ return 0; ++} ++ ++static int ingenic_adc_aux_resume(struct platform_device *pdev) ++{ ++ //struct ingenic_adc_aux *adc_aux = platform_get_drvdata(pdev); ++ //adc_aux->cell->enable(pdev); ++ return 0; ++} ++ ++int ingenic_adc_aux_sample_volt(enum aux_ch channels,struct ingenic_adc_aux *ingenic_adc_aux) ++{ ++ unsigned long tmp; ++ unsigned long int sadc_volt = 0; ++ ++ if (!ingenic_adc_aux) { ++ printk("ingenic_adc_aux is null ! return\n"); ++ return -EINVAL; ++ } ++ ++ INIT_COMPLETION(ingenic_adc_aux->read_completion); ++ ++ ingenic_adc_aux->cell->enable(ingenic_adc_aux->pdev); ++ enable_irq(ingenic_adc_aux->irq); ++ ++restart: ++ tmp = wait_for_completion_interruptible_timeout(&ingenic_adc_aux->read_completion, HZ); ++ if (tmp > 0) { ++ if( (channels == 0) || (channels ==2 ) ) ++ sadc_volt = readl(ingenic_adc_aux->base) & 0xfff; ++ else ++ sadc_volt = (readl(ingenic_adc_aux->base - 2) & 0xfff0000) >> 16; ++ } else if(tmp == -ERESTARTSYS){ ++ goto restart; ++ } ++ else { ++ sadc_volt = tmp ? tmp : -ETIMEDOUT; ++ } ++ ++ if (sadc_volt < 0) { ++ printk("ingenic_adc_aux read value error!!\n"); ++ disable_irq(ingenic_adc_aux->irq); ++ ingenic_adc_aux->cell->disable(ingenic_adc_aux->pdev); ++ return -EIO; ++ } ++ ++ disable_irq(ingenic_adc_aux->irq); ++ ingenic_adc_aux->cell->disable(ingenic_adc_aux->pdev); ++ ++ sadc_volt = sadc_volt * VREF_ADC*10 / AUXCONST; ++ ++ return sadc_volt; ++} ++ ++ ++int ingenic_adc_aux_open(struct inode *inode, struct file *filp) ++{ ++ //struct miscdevice *dev = filp->private_data; ++ //struct ingenic_adc_aux *axu = container_of(dev, struct ingenic_adc_aux, mdev); ++ return 0; ++} ++ ++int ingenic_adc_aux_release(struct inode *inode, struct file *filp) ++{ ++ return 0; ++} ++ ++ssize_t ingenic_adc_aux_read(struct file *filp, char *buf, size_t len, loff_t *off) ++{ ++ unsigned long int sadc_val = 0; ++ struct miscdevice *dev = filp->private_data; ++ struct ingenic_adc_aux *aux = container_of(dev, struct ingenic_adc_aux, mdev); ++ ++ sadc_val = ingenic_adc_aux_sample_volt(aux->pdev->id,aux); ++ if (sadc_val < 0) { ++ printk("ingenic_adc_aux read value error !!\n"); ++ return -EINVAL; ++ } ++ ++ if(copy_to_user(buf, &sadc_val, sizeof(long int))) { ++ return -EFAULT; ++ } ++ ++ return sizeof(int); ++} ++ ++static long ingenic_adc_aux_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ int ret = 0; ++ struct miscdevice *dev = filp->private_data; ++ struct ingenic_adc_aux *adc_aux = container_of(dev, struct ingenic_adc_aux, mdev); ++ ++ if(_IOC_TYPE(cmd) == ADC_MAGIC_NUMBER) { ++ switch (cmd) { ++ case ADC_ENABLE: ++ ret = adc_aux->cell->enable(adc_aux->pdev); ++ break; ++ case ADC_DISABLE: ++ ret = adc_aux->cell->disable(adc_aux->pdev); ++ break; ++ case ADC_SET_VREF: ++ VREF_ADC = *(unsigned int *)arg; ++ printk("VREF_ADC=%ld\n",VREF_ADC); ++ break; ++ default: ++ ret = -1; ++ printk("%s:unsupported ioctl cmd\n",__func__); ++ } ++ } ++ ++ return ret; ++} ++ ++struct file_operations ingenic_adc_aux_fops= { ++ .owner= THIS_MODULE, ++ .open= ingenic_adc_aux_open, ++ .release= ingenic_adc_aux_release, ++ .read= ingenic_adc_aux_read, ++ .unlocked_ioctl= ingenic_adc_aux_ioctl, ++}; ++ ++extern int key_fun_init(struct ingenic_adc_aux *ingenic_adc_aux); ++static int ingenic_adc_aux_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ char aux_name[16]; ++ ++ struct ingenic_adc_aux *ingenic_adc_aux = NULL; ++ ++ ingenic_adc_aux = kzalloc(sizeof(*ingenic_adc_aux), GFP_KERNEL); ++ if (!ingenic_adc_aux) { ++ dev_err(&pdev->dev, "Failed to allocate driver structre\n"); ++ return -ENOMEM; ++ } ++ ++ ingenic_adc_aux->cell = mfd_get_cell(pdev); ++ if (!ingenic_adc_aux->cell) { ++ ret = -ENOENT; ++ dev_err(&pdev->dev, "Failed to get mfd cell for ingenic_adc_aux!\n"); ++ goto err_free; ++ } ++ ++ ingenic_adc_aux->irq = platform_get_irq(pdev, 0); ++ if (ingenic_adc_aux->irq < 0) { ++ ret = ingenic_adc_aux->irq; ++ dev_err(&pdev->dev, "Failed to get platform irq: %d\n", ret); ++ goto err_free; ++ } ++ ++ ingenic_adc_aux->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!ingenic_adc_aux->mem) { ++ ret = -ENOENT; ++ dev_err(&pdev->dev, "Failed to get platform mmio resource\n"); ++ goto err_free; ++ } ++ ++ ingenic_adc_aux->mem = request_mem_region(ingenic_adc_aux->mem->start, ++ resource_size(ingenic_adc_aux->mem), pdev->name); ++ if (!ingenic_adc_aux->mem) { ++ ret = -EBUSY; ++ dev_err(&pdev->dev, "Failed to request mmio memory region\n"); ++ goto err_free; ++ } ++ ++ ingenic_adc_aux->base = ioremap_nocache(ingenic_adc_aux->mem->start,resource_size(ingenic_adc_aux->mem)); ++ if (!ingenic_adc_aux->base) { ++ ret = -EBUSY; ++ dev_err(&pdev->dev, "Failed to ioremap mmio memory\n"); ++ goto err_free; ++ } ++ ++ ingenic_adc_aux->pdev = pdev; ++ ingenic_adc_aux->mdev.minor = MISC_DYNAMIC_MINOR; ++ sprintf(aux_name, "ingenic_adc_aux_%d", pdev->id); ++ ingenic_adc_aux->mdev.name = aux_name; ++ ingenic_adc_aux->mdev.fops = &ingenic_adc_aux_fops; ++ ++ ret = misc_register(&ingenic_adc_aux->mdev); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "misc_register failed\n"); ++ goto err_free; ++ } ++ ++ init_completion(&ingenic_adc_aux->read_completion); ++ ++ ret = request_irq(ingenic_adc_aux->irq, ingenic_ingenic_adc_aux_irq_handler, 0, pdev->name, ingenic_adc_aux); ++ if (ret) { ++ dev_err(&pdev->dev, "Failed to request irq %d\n", ret); ++ goto err_free; ++ } ++ ++ disable_irq(ingenic_adc_aux->irq); ++ ++ platform_set_drvdata(pdev, ingenic_adc_aux); ++ ++#ifdef CONFIG_ADC_BASED_KEY_FUN ++ if (!strncmp(aux_name, "ingenic_adc_aux_1", strlen("ingenic_adc_aux_1"))) ++ key_fun_init(ingenic_adc_aux); ++#endif ++ ++ printk("ingenic sadc aux probe success\n"); ++ return 0; ++ ++err_free : ++ kfree(ingenic_adc_aux); ++ return ret; ++ ++} ++ ++static int ingenic_adc_aux_remove(struct platform_device *pdev) ++{ ++ struct ingenic_adc_aux *ingenic_adc_aux = platform_get_drvdata(pdev); ++ ++ misc_deregister(&ingenic_adc_aux->mdev); ++ free_irq(ingenic_adc_aux->irq, ingenic_adc_aux); ++ iounmap(ingenic_adc_aux->base); ++ release_mem_region(ingenic_adc_aux->mem->start,resource_size(ingenic_adc_aux->mem)); ++ kfree(ingenic_adc_aux); ++ ++ return 0; ++} ++ ++static struct platform_driver ingenic_adc_aux_driver = { ++ .probe = ingenic_adc_aux_probe, ++ .remove = ingenic_adc_aux_remove, ++ .driver = { ++ .name = "ingenic-aux", ++ .owner = THIS_MODULE, ++ }, ++ .suspend = ingenic_adc_aux_suspend, ++ .resume = ingenic_adc_aux_resume, ++}; ++ ++static int __init ingenic_adc_aux_init(void) ++{ ++ platform_driver_register(&ingenic_adc_aux_driver); ++ ++ return 0; ++} ++ ++static void __exit ingenic_adc_aux_exit(void) ++{ ++ platform_driver_unregister(&ingenic_adc_aux_driver); ++} ++ ++module_init(ingenic_adc_aux_init); ++module_exit(ingenic_adc_aux_exit); ++ ++MODULE_ALIAS("platform: ingenic ingenic_adc_aux"); ++MODULE_AUTHOR("Guo Xu"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("ingenic adc aux sample driver"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mfd_ingenic_adc_v13.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mfd_ingenic_adc_v13.c.patch new file mode 100644 index 00000000..7f6b3964 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mfd_ingenic_adc_v13.c.patch @@ -0,0 +1,585 @@ +diff -drupN a/drivers/mfd/ingenic_adc_v13.c b/drivers/mfd/ingenic_adc_v13.c +--- a/drivers/mfd/ingenic_adc_v13.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mfd/ingenic_adc_v13.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,581 @@ ++/* drivers/mfd/ingenic_adc.c ++ * ++ * Copyright (C) 2012 Ingenic Semiconductor Co., Ltd. ++ * http://www.ingenic.com ++ * Sun Jiwei ++ * ingenic4780 SOC ADC device core ++ * ++ * 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 driver is designed to control the usage of the ADC block between ++ * the touchscreen and any other drivers that may need to use it, such as ++ * the hwmon driver. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#define INGENIC_REG_ADC_ENABLE 0x00 ++#define INGENIC_REG_ADC_CTRL 0x08 ++#define INGENIC_REG_ADC_STATUS 0x0c ++ ++#define INGENIC_REG_ADC_AUX_BASE 0x10 ++#define INGENIC_REG_ADC_CLKDIV 0x20 ++/* ++ *the following registeres is for touchscreen ++ */ ++#define CLKDIV 120 ++#define CLKDIV_US 2 ++#define CLKDIV_MS 200 ++ ++enum { ++ INGENIC_ADC_IRQ_AUX = 0, ++ INGENIC_ADC_IRQ_AUX1, ++ INGENIC_ADC_IRQ_AUX2, ++ INGENIC_ADC_IRQ_AUX3, ++ INGENIC_ADC_IRQ_AUX4, ++ INGENIC_ADC_IRQ_AUX5, ++}; ++ ++#define INGENIC_ADC_IRQ_NUM 8 ++#define SADC_NR_IRQS (8) ++/* This value is unique to avoid overlap.*/ ++#define SADC_IRQ_BASE 200 ++ ++/* #if ( INGENIC_ADC_IRQ_NUM > SADC_NR_IRQS ) */ ++/* #error "SADC module get error irq number!" */ ++/* #endif */ ++ ++struct ingenic_adc { ++ struct resource *mem; ++ void __iomem *base; ++ ++ int irq; ++ int irq_base; ++ ++ struct clk *clk; ++ atomic_t clk_ref; ++ ++ spinlock_t lock; ++}; ++ ++static inline void ingenic_adc_irq_set_masked(struct ingenic_adc *adc, int irq, ++ bool masked) ++{ ++ unsigned long flags; ++ uint8_t val; ++ ++ irq -= adc->irq_base; ++ ++ spin_lock_irqsave(&adc->lock, flags); ++ ++ val = readb(adc->base + INGENIC_REG_ADC_CTRL); ++ if (masked) { ++ val |= BIT(irq); ++ } ++ else { ++ val &= ~BIT(irq); ++ } ++ writeb(val, adc->base + INGENIC_REG_ADC_CTRL); ++ ++ spin_unlock_irqrestore(&adc->lock, flags); ++} ++ ++static void ingenic_adc_irq_mask(struct irq_data *data) ++{ ++ struct ingenic_adc *adc = irq_data_get_irq_chip_data(data); ++ ingenic_adc_irq_set_masked(adc, data->irq, true); ++} ++ ++static void ingenic_adc_irq_unmask(struct irq_data *data) ++{ ++ struct ingenic_adc *adc = irq_data_get_irq_chip_data(data); ++ ingenic_adc_irq_set_masked(adc, data->irq, false); ++} ++ ++static void ingenic_adc_irq_ack(struct irq_data *data) ++{ ++ struct ingenic_adc *adc = irq_data_get_irq_chip_data(data); ++ unsigned int irq = data->irq - adc->irq_base; ++ writeb(BIT(irq), adc->base + INGENIC_REG_ADC_STATUS); ++} ++ ++static struct irq_chip ingenic_adc_irq_chip = { ++ .name = "ingenic-adc", ++ .irq_mask = ingenic_adc_irq_mask, ++ .irq_disable = ingenic_adc_irq_mask, ++ .irq_unmask = ingenic_adc_irq_unmask, ++ .irq_ack = ingenic_adc_irq_ack, ++}; ++ ++static void ingenic_adc_irq_demux(struct irq_desc *desc) ++{ ++ struct ingenic_adc *adc = irq_desc_get_handler_data(desc); ++ uint8_t status; ++ unsigned int i; ++ ++ status = readb(adc->base + INGENIC_REG_ADC_STATUS); ++ ++ for (i = 0; i < SADC_NR_IRQS; i++) { ++ if (status & BIT(i)) { ++ generic_handle_irq(adc->irq_base + i); ++ } ++ } ++} ++ ++ ++ ++ ++static inline void ingenic_adc_enable(struct ingenic_adc *adc) ++{ ++ uint16_t val; ++ ++ if (atomic_inc_return(&adc->clk_ref) == 1) { ++ val = readw(adc->base + INGENIC_REG_ADC_ENABLE); ++ val &= ~BIT(15); ++ writew(val, adc->base + INGENIC_REG_ADC_ENABLE); ++ msleep(5); ++ } ++} ++ ++static inline void ingenic_adc_disable(struct ingenic_adc *adc) ++{ ++ uint16_t val; ++ ++ if (atomic_dec_return(&adc->clk_ref) == 0) { ++ val = readw(adc->base + INGENIC_REG_ADC_ENABLE); ++ val |= BIT(15); ++ writew(val, adc->base + INGENIC_REG_ADC_ENABLE); ++ } ++} ++ ++static inline void ingenic_adc_set_enabled(struct ingenic_adc *adc, int engine, ++ bool enabled) ++{ ++ unsigned long flags; ++ uint16_t val; ++ ++ spin_lock_irqsave(&adc->lock, flags); ++ ++ val = readw(adc->base + INGENIC_REG_ADC_ENABLE); ++ if (enabled) { ++ val |= BIT(engine); ++ } ++ else { ++ val &= ~BIT(engine); ++ } ++ writew(val, adc->base + INGENIC_REG_ADC_ENABLE); ++ ++ spin_unlock_irqrestore(&adc->lock, flags); ++} ++ ++static int ingenic_adc_cell_enable(struct platform_device *pdev) ++{ ++ struct ingenic_adc *adc = dev_get_drvdata(pdev->dev.parent); ++ ++ ingenic_adc_enable(adc); ++ ingenic_adc_set_enabled(adc, pdev->id, true); ++ ++ return 0; ++} ++ ++static int ingenic_adc_cell_disable(struct platform_device *pdev) ++{ ++ struct ingenic_adc *adc = dev_get_drvdata(pdev->dev.parent); ++ ++ ingenic_adc_set_enabled(adc, pdev->id, false); ++ ingenic_adc_disable(adc); ++ ++ return 0; ++} ++ ++ ++int adc_write_reg(struct device *dev ,uint8_t addr_offset,uint32_t mask,uint32_t val) ++{ ++ struct ingenic_adc *adc = dev_get_drvdata(dev); ++ unsigned long flags; ++ uint32_t value; ++ if(!adc) ++ return -ENODEV; ++ spin_lock_irqsave(&adc->lock,flags); ++ ++ value = readl(adc->base + addr_offset); ++ value &= ~mask; ++ value |= val; ++ writel(value,adc->base + addr_offset); ++ spin_unlock_irqrestore(&adc->lock,flags); ++ return 0; ++} ++uint32_t adc_read_reg(struct device *dev,uint8_t addr_offset) ++{ ++ struct ingenic_adc *adc = dev_get_drvdata(dev); ++ unsigned long flags; ++ uint32_t ret; ++ if(!adc) ++ return -ENODEV; ++ spin_lock_irqsave(&adc->lock,flags); ++ ret = readl(adc->base + addr_offset); ++ spin_unlock_irqrestore(&adc->lock,flags); ++ return ret; ++} ++ ++ ++static void ingenic_adc_clk_div(struct ingenic_adc *adc, const unsigned char clkdiv, ++ const unsigned char clkdiv_us, const unsigned short clkdiv_ms) ++{ ++ unsigned int val; ++ ++ val = clkdiv | (clkdiv_us << 8) | (clkdiv_ms << 16); ++ writel(val, adc->base + INGENIC_REG_ADC_CLKDIV); ++} ++ ++static struct resource ingenic_aux_resources[] = { ++ { ++ .start = INGENIC_ADC_IRQ_AUX, ++ .flags = IORESOURCE_IRQ, ++ }, ++ { ++ .start = INGENIC_REG_ADC_AUX_BASE, ++ .end = INGENIC_REG_ADC_AUX_BASE + 1, ++ .flags = IORESOURCE_MEM, ++ }, ++}; ++ ++static struct resource ingenic_aux_resources1[] = { ++ { ++ .start = INGENIC_ADC_IRQ_AUX1, ++ .flags = IORESOURCE_IRQ, ++ }, ++ { ++ .start = INGENIC_REG_ADC_AUX_BASE + 2, ++ .end = INGENIC_REG_ADC_AUX_BASE + 3, ++ .flags = IORESOURCE_MEM, ++ }, ++}; ++ ++static struct resource ingenic_aux_resources2[] = { ++ { ++ .start = INGENIC_ADC_IRQ_AUX2, ++ .flags = IORESOURCE_IRQ, ++ }, ++ { ++ .start = INGENIC_REG_ADC_AUX_BASE + 4, ++ .end = INGENIC_REG_ADC_AUX_BASE + 5, ++ .flags = IORESOURCE_MEM, ++ }, ++}; ++ ++static struct resource ingenic_aux_resources3[] = { ++ { ++ .start = INGENIC_ADC_IRQ_AUX3, ++ .flags = IORESOURCE_IRQ, ++ }, ++ { ++ .start = INGENIC_REG_ADC_AUX_BASE + 6, ++ .end = INGENIC_REG_ADC_AUX_BASE + 7, ++ .flags = IORESOURCE_MEM, ++ }, ++}; ++ ++static struct resource ingenic_aux_resources4[] = { ++ { ++ .start = INGENIC_ADC_IRQ_AUX4, ++ .flags = IORESOURCE_IRQ, ++ }, ++ { ++ .start = INGENIC_REG_ADC_AUX_BASE + 8, ++ .end = INGENIC_REG_ADC_AUX_BASE + 9, ++ .flags = IORESOURCE_MEM, ++ }, ++}; ++ ++static struct resource ingenic_aux_resources5[] = { ++ { ++ .start = INGENIC_ADC_IRQ_AUX5, ++ .flags = IORESOURCE_IRQ, ++ }, ++ { ++ .start = INGENIC_REG_ADC_AUX_BASE + 10, ++ .end = INGENIC_REG_ADC_AUX_BASE + 11, ++ .flags = IORESOURCE_MEM, ++ }, ++}; ++ ++#if 0 ++static struct resource ingenic_aux_resources6[] = { ++ { ++ .start = INGENIC_ADC_IRQ_AUX6, ++ .flags = IORESOURCE_IRQ, ++ }, ++ { ++ .start = INGENIC_REG_ADC_AUX_BASE + 12, ++ .end = INGENIC_REG_ADC_AUX_BASE + 13, ++ .flags = IORESOURCE_MEM, ++ }, ++}; ++ ++static struct resource ingenic_aux_resources7[] = { ++ { ++ .start = INGENIC_ADC_IRQ_AUX7, ++ .flags = IORESOURCE_IRQ, ++ }, ++ { ++ .start = INGENIC_REG_ADC_AUX_BASE + 14, ++ .end = INGENIC_REG_ADC_AUX_BASE + 15, ++ .flags = IORESOURCE_MEM, ++ }, ++}; ++ ++#endif ++ ++static struct mfd_cell ingenic_adc_cells[] = { ++ { ++ .id = 0, ++ .name = "ingenic-aux", ++ .num_resources = ARRAY_SIZE(ingenic_aux_resources), ++ .resources = ingenic_aux_resources, ++ ++ .enable = ingenic_adc_cell_enable, ++ .disable = ingenic_adc_cell_disable, ++ }, ++ { ++ .id = 1, ++ .name = "ingenic-aux", ++ .num_resources = ARRAY_SIZE(ingenic_aux_resources1), ++ .resources = ingenic_aux_resources1, ++ ++ .enable = ingenic_adc_cell_enable, ++ .disable = ingenic_adc_cell_disable, ++ }, ++ { ++ .id = 2, ++ .name = "ingenic-aux", ++ .num_resources = ARRAY_SIZE(ingenic_aux_resources2), ++ .resources = ingenic_aux_resources2, ++ ++ .enable = ingenic_adc_cell_enable, ++ .disable = ingenic_adc_cell_disable, ++ }, ++ { ++ .id = 3, ++ .name = "ingenic-aux", ++ .num_resources = ARRAY_SIZE(ingenic_aux_resources), ++ .resources = ingenic_aux_resources3, ++ ++ .enable = ingenic_adc_cell_enable, ++ .disable = ingenic_adc_cell_disable, ++ }, ++ { ++ .id = 4, ++ .name = "ingenic-aux", ++ .num_resources = ARRAY_SIZE(ingenic_aux_resources), ++ .resources = ingenic_aux_resources4, ++ ++ .enable = ingenic_adc_cell_enable, ++ .disable = ingenic_adc_cell_disable, ++ }, ++ { ++ .id = 5, ++ .name = "ingenic-aux", ++ .num_resources = ARRAY_SIZE(ingenic_aux_resources), ++ .resources = ingenic_aux_resources5, ++ ++ .enable = ingenic_adc_cell_enable, ++ .disable = ingenic_adc_cell_disable, ++ }, ++#if 0 ++ { ++ .id = 6, ++ .name = "ingenic-aux", ++ .num_resources = ARRAY_SIZE(ingenic_aux_resources), ++ .resources = ingenic_aux_resources6, ++ ++ .enable = ingenic_adc_cell_enable, ++ .disable = ingenic_adc_cell_disable, ++ }, ++ { ++ .id = 7, ++ .name = "ingenic-aux", ++ .num_resources = ARRAY_SIZE(ingenic_aux_resources), ++ .resources = ingenic_aux_resources7, ++ ++ .enable = ingenic_adc_cell_enable, ++ .disable = ingenic_adc_cell_disable, ++ }, ++#endif ++ ++}; ++ ++ ++ ++static int ingenic_adc_probe(struct platform_device *pdev) ++{ ++ int ret; ++ struct ingenic_adc *adc; ++ struct resource *mem_base; ++ int irq; ++ unsigned char clkdiv, clkdiv_us; ++ unsigned short clkdiv_ms; ++ ++ adc = kmalloc(sizeof(*adc), GFP_KERNEL); ++ if (!adc) { ++ dev_err(&pdev->dev, "Failed to allocate driver structre\n"); ++ return -ENOMEM; ++ } ++ ++ adc->irq = platform_get_irq(pdev, 0); ++ if (adc->irq < 0) { ++ ret = adc->irq; ++ dev_err(&pdev->dev, "Failed to get platform irq: %d\n", ret); ++ goto err_free; ++ } ++ ++ adc->irq_base = SADC_IRQ_BASE; ++ ++ mem_base = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!mem_base) { ++ ret = -ENOENT; ++ dev_err(&pdev->dev, "Failed to get platform mmio resource"); ++ goto err_free; ++ } ++ ++ adc->mem = request_mem_region(mem_base->start, INGENIC_REG_ADC_STATUS, ++ pdev->name); ++ if (!adc->mem) { ++ ret = -EBUSY; ++ dev_err(&pdev->dev, "Failed to request mmio memory region\n"); ++ goto err_free; ++ } ++ ++ adc->base = ioremap_nocache(adc->mem->start, resource_size(adc->mem)); ++ if (!adc->base) { ++ ret = -EBUSY; ++ dev_err(&pdev->dev, "Failed to ioremap mmio memory\n"); ++ goto err_release_mem_region; ++ } ++ ++ adc->clk = clk_get(&pdev->dev, "gate_sadc"); ++ if (IS_ERR(adc->clk)) { ++ ret = PTR_ERR(adc->clk); ++ dev_err(&pdev->dev, "Failed to get clock: %d\n", ret); ++ goto err_iounmap; ++ } ++ ++ spin_lock_init(&adc->lock); ++ atomic_set(&adc->clk_ref, 0); ++ ++ platform_set_drvdata(pdev, adc); ++ ++ for (irq = adc->irq_base; irq < adc->irq_base + SADC_NR_IRQS; ++irq) { ++ irq_set_chip_data(irq, adc); ++ irq_set_chip_and_handler(irq, &ingenic_adc_irq_chip, ++ handle_level_irq); ++ } ++ ++ irq_set_handler_data(adc->irq, adc); ++ irq_set_chained_handler(adc->irq, ingenic_adc_irq_demux); ++ ++ clk_prepare_enable(adc->clk); ++ ++ writew(0x8000, adc->base + INGENIC_REG_ADC_ENABLE); ++ writew(0xffff, adc->base + INGENIC_REG_ADC_CTRL); ++ ++ clkdiv = CLKDIV - 1; ++ clkdiv_us = CLKDIV_US - 1; ++ clkdiv_ms = CLKDIV_MS - 1; ++ ++ ingenic_adc_clk_div(adc, clkdiv, clkdiv_us, clkdiv_ms); ++ ++ ret = mfd_add_devices(&pdev->dev, 0, ingenic_adc_cells, ++ ARRAY_SIZE(ingenic_adc_cells), mem_base, adc->irq_base,NULL); ++ if (ret < 0) { ++ goto err_clk_put; ++ } ++ ++ printk("ingenic SADC driver registeres over!\n"); ++ ++ return 0; ++ ++err_clk_put: ++ clk_put(adc->clk); ++err_iounmap: ++ platform_set_drvdata(pdev, NULL); ++ iounmap(adc->base); ++err_release_mem_region: ++ release_mem_region(adc->mem->start, resource_size(adc->mem)); ++err_free: ++ kfree(adc); ++ ++ return ret; ++} ++ ++static int ingenic_adc_remove(struct platform_device *pdev) ++{ ++ struct ingenic_adc *adc = platform_get_drvdata(pdev); ++ ++ clk_disable_unprepare(adc->clk); ++ mfd_remove_devices(&pdev->dev); ++ ++ irq_set_handler_data(adc->irq, NULL); ++ irq_set_chained_handler(adc->irq, NULL); ++ ++ iounmap(adc->base); ++ release_mem_region(adc->mem->start, resource_size(adc->mem)); ++ ++ clk_put(adc->clk); ++ ++ platform_set_drvdata(pdev, NULL); ++ ++ kfree(adc); ++ ++ return 0; ++} ++ ++static const struct of_device_id sadc_match[] = { ++ { .compatible = "ingenic,sadc", .data = NULL }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, sadc_match); ++ ++struct platform_driver ingenic_adc_driver = { ++ .probe = ingenic_adc_probe, ++ .remove = ingenic_adc_remove, ++ .driver = { ++ .name = "ingenic-adc", ++ .owner = THIS_MODULE, ++ .of_match_table = sadc_match, ++ }, ++}; ++ ++static int __init ingenic_adc_init(void) ++{ ++ return platform_driver_register(&ingenic_adc_driver); ++} ++module_init(ingenic_adc_init); ++ ++static void __exit ingenic_adc_exit(void) ++{ ++ platform_driver_unregister(&ingenic_adc_driver); ++} ++module_exit(ingenic_adc_exit); ++ ++MODULE_DESCRIPTION("ingenic SOC ADC driver"); ++MODULE_AUTHOR("Guo Xu"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:T15-adc"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mfd_rn5t567-irq.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mfd_rn5t567-irq.c.patch new file mode 100644 index 00000000..631e5bfc --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mfd_rn5t567-irq.c.patch @@ -0,0 +1,149 @@ +diff -drupN a/drivers/mfd/rn5t567-irq.c b/drivers/mfd/rn5t567-irq.c +--- a/drivers/mfd/rn5t567-irq.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mfd/rn5t567-irq.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,145 @@ ++/* ++ * Interrupt driver for RICOH567 power management chip. ++ * ++ * Copyright (C) 2016 Ingenic Semiconductor Co., Ltd. ++ * ++ * Author: cli ++ * ++ * Based on code ++ * Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved. ++ * Author: Laxman dewangan ++ * ++ * 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, see . ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct rn5t567_irq_data { ++ struct device *dev; ++ struct regmap *regmap; ++ struct mutex irq_lock; ++ struct irq_domain *irq_domain; ++}; ++ ++static struct rn5t567_irq_data *rn5t567 = NULL; ++ ++static irqreturn_t rn5t567_irq_thread_handler(int virq, void *data) ++{ ++ struct rn5t567_irq_data *pdata = data; ++ int enable, pending = 0, ret; ++ ++ might_sleep(); ++ ++ mutex_lock(&pdata->irq_lock); ++ ++ ret = regmap_read(pdata->regmap, RN5T567_INTMON, &pending); ++ ret |=regmap_read(pdata->regmap, RN5T567_INTEN, &enable); ++ if (!ret) { ++ dev_warn(pdata->dev, "irq read i2c reg faild: %d\n", ret); ++ mutex_unlock(&pdata->irq_lock); ++ return IRQ_HANDLED; ++ } ++ pending = (pending & enable); ++ mutex_unlock(&pdata->irq_lock); ++ ++ while (pending) { ++ int cur_irq , i; ++ i = fls(pending) - 1; ++ cur_irq = irq_find_mapping(pdata->irq_domain, i); ++ handle_nested_irq(cur_irq); ++ pending &= ~BIT(i); ++ }; ++ ++ return IRQ_HANDLED; ++} ++ ++static int rn5t567_domain_xlate_onecell(struct irq_domain *d, struct device_node *ctrlr, ++ const u32 *intspec, unsigned int intsize, ++ unsigned long *out_hwirq, unsigned int *out_type) ++{ ++ struct regmap *regmap = (struct regmap *)d->host_data; ++ int ret; ++ ++ if (!regmap) ++ return -EINVAL; ++ ++ ret = irq_domain_xlate_onecell(d, ctrlr, intspec, intsize, ++ out_hwirq, out_type); ++ if (ret) ++ return ret; ++ ++ switch (*out_hwirq) { ++ case RN5T567_IRQ_WDG: ++ break; ++ case RN5T567_IRQ_SYSTEM: ++ case RN5T567_IRQ_DCDC: ++ case RN5T567_IRQ_GPIO: ++ regmap_update_bits(regmap, RN5T567_INTEN, BIT(*out_hwirq), BIT(*out_hwirq)); ++ break; ++ default: ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static const struct irq_domain_ops rn5t567_irq_domain_ops = { ++ .xlate = rn5t567_domain_xlate_onecell, ++}; ++ ++int rn5t567_irq_init(struct i2c_client *i2c, struct regmap *regmap) ++{ ++ int ret; ++ ++ i2c->irq = irq_of_parse_and_map(i2c->dev.of_node, 0); ++ if (!i2c->irq) ++ return 0; ++ ++ rn5t567 = devm_kzalloc(&i2c->dev, sizeof(struct rn5t567_irq_data), GFP_KERNEL); ++ if (!rn5t567) ++ return -ENOMEM; ++ ++ mutex_init(&rn5t567->irq_lock); ++ rn5t567->regmap = regmap; ++ ++ regmap_write(rn5t567->regmap, RN5T567_INTEN, 0); ++ regmap_write(rn5t567->regmap, RN5T567_INTPOL, 0); ++ ++ ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL, rn5t567_irq_thread_handler, ++ IRQF_TRIGGER_LOW | IRQF_ONESHOT, i2c->name, rn5t567); ++ if (ret) { ++ dev_err(&i2c->dev, "irq request failed: %d\n", ret); ++ return ret; ++ } ++ ++ rn5t567->irq_domain = irq_domain_add_linear(i2c->dev.of_node, RN5T567_IRQ_NUM, ++ &rn5t567_irq_domain_ops, regmap); ++ if (IS_ERR(rn5t567->irq_domain)) { ++ ret = PTR_ERR(rn5t567->irq_domain); ++ dev_err(&i2c->dev, "irq domain add failed: %d\n", ret); ++ return ret; ++ } ++ ++ rn5t567->dev = &i2c->dev; ++ ++ return 0; ++} ++ ++void rn5t567_irq_deinit(void) ++{ ++ if (rn5t567->irq_domain) ++ irq_domain_remove(rn5t567->irq_domain); ++ ++ regmap_write(rn5t567->regmap, RN5T567_INTEN, 0); ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mfd_rn5t567.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mfd_rn5t567.c.patch new file mode 100644 index 00000000..52d93f7d --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mfd_rn5t567.c.patch @@ -0,0 +1,216 @@ +diff -drupN a/drivers/mfd/rn5t567.c b/drivers/mfd/rn5t567.c +--- a/drivers/mfd/rn5t567.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mfd/rn5t567.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,212 @@ ++/* ++ * Core driver access RC5T567 power management chip. ++ * ++ * Copyright (C) 2016 Ingenic Semiconductor Co., Ltd. ++ * Author: cli ++ * ++ * Based on code ++ * drivers/mfd/rc5t583.c ++ * Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved. ++ * Author: Laxman dewangan ++ * ++ * 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, see . ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static const struct mfd_cell rn5t567_cells[] = { ++ { .name = "rn5t567-regulator" }, ++ /*{ .name = "rn5t567-wdt" }, ++ { .name = "rn5t567-pinctrl" }, ++ { .name = "rn5t567-pm" }, */ ++}; ++ ++static bool rn5t567_reg_hole(unsigned int reg) ++{ ++#define RN5T567_REG_SINGLE_HOLE_NUM 10 ++ unsigned char single_hole[RN5T567_REG_SINGLE_HOLE_NUM] = { ++ 0x4, 0x8, 0x1a, 0x29, 0x2b, ++ 0x34, 0x35, 0x3a, 0x3f, 0x43}; ++ int i; ++ ++ for (i = 0; i < RN5T567_REG_SINGLE_HOLE_NUM; i++) ++ if ((unsigned char)reg == single_hole[i]) ++ return true; ++ if (reg > RN5T567_LDO5_SLOT && reg < RN5T567_PSO0_SLOT) ++ return true; ++ if (reg > RN5T567_LDODIS && reg < RN5T567_LDO1DAC) ++ return true; ++ if (reg > RN5T567_LDO5DAC && reg < RN5T567_LDORTCDAC) ++ return true; ++ if (reg > RN5T567_LDO5DAC_SLP && reg < RN5T567_IOSEL) ++ return true; ++ if (reg > RN5T567_GPLED_FUNC && reg < RN5T567_INTPOL) ++ return true; ++ if (reg > RN5T567_INTMON && reg < RN5T567_PREVINDAC) ++ return true; ++ if (reg > RN5T567_PREVINDAC && reg < RN5T567_DIESET) ++ return true; ++ if (reg > RN5T567_MAX_REG) ++ return true; ++#undef RN5T567_REG_SINGLE_HOLE_NUM ++ return false; ++} ++ ++static bool rn5t567_opable_reg(struct device *dev, unsigned int reg) ++{ ++ return !rn5t567_reg_hole(reg); ++} ++ ++static bool rn5t567_volatile_reg(struct device *dev, unsigned int reg) ++{ ++ switch (reg) { ++ case RN5T567_WATCHDOGCNT: ++ case RN5T567_DCIRQ: ++ case RN5T567_IR_GPR: ++ case RN5T567_IR_GPF: ++ case RN5T567_MON_IOIN: ++ case RN5T567_INTMON: ++ return true; ++ default: ++ return false; ++ } ++} ++ ++static struct reg_default rn5t567_reg_default[RN5T567_REG_NUM]; ++static const struct regmap_config rn5t567_regmap_config = { ++ .reg_bits = 8, ++ .val_bits = 8, ++ .volatile_reg = rn5t567_volatile_reg, ++ .writeable_reg = rn5t567_opable_reg, ++ .readable_reg = rn5t567_opable_reg, ++ .max_register = RN5T567_MAX_REG, ++ .reg_defaults = rn5t567_reg_default, ++ .num_reg_defaults = ARRAY_SIZE(rn5t567_reg_default), ++ .cache_type = REGCACHE_RBTREE, ++}; ++ ++static int __rn57567_reg_read(struct i2c_client *i2c, u8 reg) ++{ ++ return i2c_smbus_read_byte_data(i2c, reg); ++} ++ ++static void rn5t567_reg_default_init(struct i2c_client *i2c) ++{ ++ unsigned int reg, def; ++ int i; ++ ++ for (i = 0, reg = 0; i < RN5T567_REG_NUM && ++ reg <= RN5T567_MAX_REG; reg++) { ++ if (rn5t567_reg_hole(reg) || ++ rn5t567_volatile_reg(NULL, reg)) ++ continue; ++ rn5t567_reg_default[i].reg = reg; ++ def = __rn57567_reg_read(i2c, (u8)reg); ++ if (def < 0) { ++ dev_warn(&i2c->dev, "register %x read failed: %d\n", reg, def); ++ rn5t567_reg_default[i++].def = 0; ++ } else ++ rn5t567_reg_default[i++].def = def; ++ } ++} ++ ++static int rn5t567_i2c_probe(struct i2c_client *i2c, ++ const struct i2c_device_id *id) ++{ ++ struct regmap *regmap = NULL; ++ int ret; ++ ++ rn5t567_reg_default_init(i2c); ++ ++ regmap = devm_regmap_init_i2c(i2c, &rn5t567_regmap_config); ++ if (IS_ERR(regmap)) { ++ ret = PTR_ERR(regmap); ++ dev_err(&i2c->dev, "regmap init failed: %d\n", ret); ++ return ret; ++ } ++ i2c_set_clientdata(i2c, regmap); ++ ++ ret = rn5t567_irq_init(i2c, regmap); ++ if (ret) ++ return ret; ++ ++ ret = mfd_add_devices(&i2c->dev, -1, rn5t567_cells, ++ ARRAY_SIZE(rn5t567_cells), NULL, 0, NULL); ++ if (ret) { ++ dev_err(&i2c->dev, "failed to add sub-devices: %d\n", ret); ++ goto out_irq_domain_remove; ++ } ++ ++ dev_info(&i2c->dev, "%s success\n", __func__); ++ return 0; ++ ++out_irq_domain_remove: ++ rn5t567_irq_deinit(); ++ return ret; ++} ++ ++static int rn5t567_i2c_remove(struct i2c_client *i2c) ++{ ++ mfd_remove_devices(&i2c->dev); ++ return 0; ++} ++ ++static const struct of_device_id rn5t567_of_match[] = { ++ { .compatible = "ricoh,rn5t567" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, rn5t567_of_match); ++ ++static const struct i2c_device_id rc5t567_i2c_id[] = { ++ {.name = "rc5t567", .driver_data = 0}, ++ {} ++}; ++ ++ ++static struct i2c_driver rn5t567_i2c_driver = { ++ .driver = { ++ .name = "rn5t567", ++ .of_match_table = of_match_ptr(rn5t567_of_match), ++ }, ++ .probe = rn5t567_i2c_probe, ++ .remove = rn5t567_i2c_remove, ++ .id_table = rc5t567_i2c_id, ++}; ++ ++static int __init rn5t567_i2c_init(void) ++{ ++ int ret = -ENODEV; ++ ++ ret = i2c_add_driver(&rn5t567_i2c_driver); ++ if (ret != 0) ++ pr_err("Failed to register I2C driver: %d\n", ret); ++ return ret; ++} ++subsys_initcall(rn5t567_i2c_init); ++ ++static void __exit rn5t567_i2c_exit(void) ++{ ++ i2c_del_driver(&rn5t567_i2c_driver); ++} ++ ++module_exit(rn5t567_i2c_exit); ++ ++MODULE_AUTHOR("cli "); ++MODULE_DESCRIPTION("Ricoh RN5T567 MFD driver"); ++MODULE_LICENSE("GPL v2"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_misc_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_misc_Kconfig.patch new file mode 100644 index 00000000..055b0b25 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_misc_Kconfig.patch @@ -0,0 +1,41 @@ +diff -drupN a/drivers/misc/Kconfig b/drivers/misc/Kconfig +--- a/drivers/misc/Kconfig 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/misc/Kconfig 2022-06-09 05:02:30.000000000 +0300 +@@ -496,6 +496,14 @@ config USB_SWITCH_FSA9480 + stereo and mono audio, video, microphone and UART data to use + a common connector port. + ++config BCM_43438_RFKILL ++ tristate "Bluetooth power control driver for BCM-43438 module" ++ depends on RFKILL ++ default n ++ ---help--- ++ Creates an rfkill entry in sysfs for power control of Bluetooth ++ bcm-xxxx chips. ++ + config LATTICE_ECP3_CONFIG + tristate "Lattice ECP3 FPGA bitstream configuration via SPI" + depends on SPI && SYSFS +@@ -525,6 +533,22 @@ config VEXPRESS_SYSCFG + bus. System Configuration interface is one of the possible means + of generating transactions on this bus. + ++config INGENIC_RSA ++ bool "JZ RSA Driver" ++ depends on MACH_XBURST2 ++ help ++ this driver is used to Encrypt/Decrypt by RSA. ++ default n ++ ++config RMEM ++ bool "Reserved memory driver(rmem)" ++ default y ++ ++config LOGGER ++ tristate "Log driver porting from Android" ++ default y ++ ++ + source "drivers/misc/c2port/Kconfig" + source "drivers/misc/eeprom/Kconfig" + source "drivers/misc/cb710/Kconfig" diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_misc_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_misc_Makefile.patch new file mode 100644 index 00000000..5521e10a --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_misc_Makefile.patch @@ -0,0 +1,18 @@ +diff -drupN a/drivers/misc/Makefile b/drivers/misc/Makefile +--- a/drivers/misc/Makefile 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/misc/Makefile 2022-06-09 05:02:30.000000000 +0300 +@@ -45,6 +45,7 @@ obj-$(CONFIG_ARM_CHARLCD) += arm-charlcd + obj-$(CONFIG_PCH_PHUB) += pch_phub.o + obj-y += ti-st/ + obj-y += lis3lv02d/ ++obj-$(CONFIG_BCM_43438_RFKILL) += bt_power_bluesleep.o + obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o + obj-$(CONFIG_ALTERA_STAPL) +=altera-stapl/ + obj-$(CONFIG_INTEL_MEI) += mei/ +@@ -56,3 +57,6 @@ obj-$(CONFIG_GENWQE) += genwqe/ + obj-$(CONFIG_ECHO) += echo/ + obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o + obj-$(CONFIG_CXL_BASE) += cxl/ ++obj-$(CONFIG_RMEM) += rmem.o ++obj-$(CONFIG_INGENIC_RSA) += ingenic_rsa.o ++obj-$(CONFIG_LOGGER) += logger.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_misc_bt_power_bluesleep.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_misc_bt_power_bluesleep.c.patch new file mode 100644 index 00000000..96eaf38e --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_misc_bt_power_bluesleep.c.patch @@ -0,0 +1,294 @@ +diff -drupN a/drivers/misc/bt_power_bluesleep.c b/drivers/misc/bt_power_bluesleep.c +--- a/drivers/misc/bt_power_bluesleep.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/misc/bt_power_bluesleep.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,290 @@ ++/* ++ * Description: ++ * Bluetooth power driver with rfkill interface ,work in with bluesleep.c , version of running consume. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++/*#include */ ++/*#include */ ++#include ++#include ++ ++#define DEV_NAME "bt_power" ++ ++struct bt_rfkill_platform_data { ++ struct rfkill *rfkill; /* for driver only */ ++ void (*restore_pin_status)(int); ++ void (*set_pin_status)(int); ++}; ++ ++static struct bt_rfkill_platform_data pdata; ++#if 1 ++#define DBG_MSG(fmt, ...) printk(fmt, ##__VA_ARGS__) ++#else ++#define DBG_MSG(fmt, ...) ++#endif ++ ++int bt_power_state = 0; ++static int bt_power_control(int enable); ++static int bt_rst_n ; ++static int bt_reg_on; ++static int bt_wake; ++unsigned bt_wake_irq; ++static DEFINE_MUTEX(bt_power_lock); ++ ++extern void rtc32k_enable(void); ++extern void rtc32k_disable(void); ++ ++/* For compile only, remove later */ ++#define RFKILL_STATE_SOFT_BLOCKED 0 ++#define RFKILL_STATE_UNBLOCKED 1 ++ ++static void bt_enable_power(void) ++{ ++ gpio_set_value(bt_reg_on, 1); ++} ++ ++static void bt_disable_power(void) ++{ ++ gpio_set_value(bt_reg_on, 0); ++} ++ ++static int bt_power_control(int enable) ++{ ++ if (enable == bt_power_state) ++ return 0; ++ ++ switch (enable) { ++ case RFKILL_STATE_SOFT_BLOCKED: ++ rtc32k_disable(); ++ bt_disable_power(); ++ mdelay(1000); ++ if (pdata.set_pin_status != NULL){ ++ (*pdata.set_pin_status)(enable); ++ printk("set_pin_status is defined\n"); ++ }else{ ++ printk("set_pin_status is not defined\n"); ++ } ++ break; ++ case RFKILL_STATE_UNBLOCKED: ++ if (pdata.restore_pin_status != NULL){ ++ (*pdata.restore_pin_status)(enable); ++ }else{ ++ rtc32k_enable(); ++ printk("restore_pin_status is not defined\n"); ++ } ++ rtc32k_enable(); ++ if (bt_rst_n > 0){ ++ gpio_direction_output(bt_rst_n,0); ++ } ++ bt_enable_power(); ++ mdelay(300); ++ if(bt_rst_n > 0){ ++ gpio_set_value(bt_rst_n,1); ++ } ++ break; ++ default: ++ break; ++ } ++ ++ bt_power_state = enable; ++ ++ return 0; ++} ++ ++static bool first_called = true; ++ ++static int bt_rfkill_set_block(void *data, bool blocked) ++{ ++ int ret; ++ ++ if (!first_called) { ++ mutex_lock(&bt_power_lock); ++ ret = bt_power_control(blocked ? 0 : 1); ++ mutex_unlock(&bt_power_lock); ++ } else { ++ first_called = false; ++ return 0; ++ } ++ ++ return ret; ++} ++ ++static const struct rfkill_ops bt_rfkill_ops = { ++ .set_block = bt_rfkill_set_block, ++}; ++ ++static int bt_power_rfkill_probe(struct platform_device *pdev) ++{ ++ struct device_node *np = pdev->dev.of_node; ++ enum of_gpio_flags flags; ++ int ret = -ENOMEM; ++ ++ bt_rst_n = of_get_named_gpio_flags(np, "ingenic,rst-n-gpio", 0, &flags); ++ if(!gpio_is_valid(bt_rst_n)) { ++ bt_rst_n = -1; ++ } ++ bt_reg_on = of_get_named_gpio_flags(np, "ingenic,reg-on-gpio", 0, &flags); ++ if(!gpio_is_valid(bt_reg_on)) { ++ bt_reg_on = -1; ++ } ++ bt_wake = of_get_named_gpio_flags(np, "ingenic,wake-gpio", 0, &flags); ++ if(!gpio_is_valid(bt_wake)) { ++ bt_wake = -1; ++ } ++ ++ pdata.restore_pin_status = NULL; ++ pdata.set_pin_status = NULL; ++ pdata.rfkill = rfkill_alloc("bluetooth", &pdev->dev, RFKILL_TYPE_BLUETOOTH, ++ &bt_rfkill_ops, NULL); ++ ++ if (!pdata.rfkill) { ++ goto exit; ++ } ++ ++ ret = rfkill_register(pdata.rfkill); ++ if (ret) { ++ rfkill_destroy(pdata.rfkill); ++ return ret; ++ } else { ++ platform_set_drvdata(pdev, pdata.rfkill); ++ } ++exit: ++ return ret; ++} ++ ++static void bt_power_rfkill_remove(struct platform_device *pdev) ++{ ++ pdata.rfkill = platform_get_drvdata(pdev); ++ if (pdata.rfkill) ++ rfkill_unregister(pdata.rfkill); ++ ++ platform_set_drvdata(pdev, NULL); ++} ++ ++static irqreturn_t bt_wake_host_cb(int i, void *data) ++{ ++ return IRQ_HANDLED; ++} ++ ++static int bluesleep_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ ++ if(bt_wake >= 0) ++ enable_irq_wake(bt_wake_irq); ++ ++ return 0; ++} ++ ++static int bluesleep_resume(struct platform_device *pdev) ++{ ++ if(bt_wake >= 0) ++ disable_irq_wake(bt_wake_irq); ++ ++ return 0; ++} ++static int __init_or_module bt_power_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ ret = bt_power_rfkill_probe(pdev); ++ if (ret) { ++ return ret; ++ } ++ ++ if(bt_rst_n > 0){ ++ ret = gpio_request(bt_rst_n,"bt_rst_n"); ++ if(unlikely(ret)){ ++ return ret; ++ } ++ } ++ ++ if (bt_reg_on > 0){ ++ ret = gpio_request(bt_reg_on,"bt_reg_on"); ++ if(unlikely(ret)){ ++ gpio_free(bt_rst_n); ++ return ret; ++ } ++ gpio_direction_output(bt_reg_on, 0); ++ } ++ ++ if(bt_wake >= 0){ ++ ret = gpio_request(bt_wake,"bt_wake"); ++ if(unlikely(ret)){ ++ printk("bt_wake request failed\n"); ++ return ret; ++ } ++ } ++ ++ ret = gpio_direction_input(bt_wake); ++ if (ret < 0) { ++ pr_err("gpio-keys: failed to configure input" ++ " direction for GPIO %d, error %d\n", ++ bt_wake, ret); ++ return ret; ++ } ++ ++ bt_wake_irq = gpio_to_irq(bt_wake); ++ if (bt_wake_irq < 0) { ++ printk("couldn't find host_wake irq\n"); ++ return -1; ++ } ++ ret = request_irq(bt_wake_irq, bt_wake_host_cb, ++ /*IRQF_DISABLED |*/ IRQF_TRIGGER_RISING, ++ "bluetooth bthostwake", NULL); ++ if (ret < 0) { ++ printk("Couldn't acquire BT_HOST_WAKE IRQ err (%d)\n", ret); ++ return -1; ++ } ++ ++ if(bt_rst_n > 0){ ++ gpio_direction_output(bt_rst_n,1); ++ } ++ return 0; ++} ++ ++static int bt_power_remove(struct platform_device *pdev) ++{ ++ int ret; ++ ++ bt_power_rfkill_remove(pdev); ++ ++ mutex_lock(&bt_power_lock); ++ bt_power_state = 0; ++ ret = bt_power_control(bt_power_state); ++ mutex_unlock(&bt_power_lock); ++ ++ return ret; ++} ++ ++static const struct of_device_id bt_power_match[] = { ++ {.compatible = "ingenic,bt_power",}, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, bt_power_match); ++static struct platform_driver bt_power_driver = { ++ .probe = bt_power_probe, ++ .remove = bt_power_remove, ++ .suspend = bluesleep_suspend, ++ .resume = bluesleep_resume, ++ .driver = { ++ .name = DEV_NAME, ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(bt_power_match), ++ }, ++}; ++ ++module_platform_driver(bt_power_driver); ++MODULE_LICENSE("GPL v2"); ++MODULE_DESCRIPTION("Bluetooth power control driver"); ++MODULE_VERSION("1.0"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_misc_ingenic_rsa.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_misc_ingenic_rsa.c.patch new file mode 100644 index 00000000..81bf1291 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_misc_ingenic_rsa.c.patch @@ -0,0 +1,487 @@ +diff -drupN a/drivers/misc/ingenic_rsa.c b/drivers/misc/ingenic_rsa.c +--- a/drivers/misc/ingenic_rsa.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/misc/ingenic_rsa.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,483 @@ ++/* ++ * drivers/misc/ingenic_rsa.c - Ingenic rsa driver ++ * ++ * Copyright (C) 2012 Ingenic Semiconductor Co., Ltd. ++ * Author: mayuanjun ++ * ++ * 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. ++ */ ++ ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MAX_KEY_LEN_WORD 64 ++#define DEV_NAME "rsa" ++ ++#define MCU_BOOT_DDR 0xb3422000 ++ ++#define DRV_NAME "jz-rsa" ++#define MAX_KEY_LEN_WORD 64 ++ ++struct jz_rsa { ++ struct miscdevice mdev; ++ struct device *dev; ++ ++ struct clk *clk_gate; ++ void __iomem *iomem; ++ unsigned int irq; ++ ++ bool busy; ++ ++ struct mutex mutex; ++ ++ wait_queue_head_t wq; ++ ++ unsigned int n_len; ++ unsigned int per_done; ++ unsigned int rsa_done; ++}; ++ ++struct rsa_key { ++ unsigned int *e; ++ unsigned int *n; ++ unsigned int rsa_mode; ++}; ++ ++struct rsa_data { ++ unsigned int *input; ++ unsigned int inlen; ++ unsigned int *output; ++}; ++ ++#define RSA_PERPARE_KEY 0x1 ++#define RSA_DO_CRYPT 0x2 ++ ++#define RSAC 0x0 ++#define RSAE 0x4 ++#define RSAN 0x8 ++#define RSAM 0xc ++#define RSAP 0x10 ++ ++#define RSAC_RSA_INT_M (1 << 17) ++#define RSAC_PER_INT_M (1 << 16) ++#define RSAC_RSA_2048 (1 << 7) ++#define RSAC_RSAC (1 << 6) ++#define RSAC_RSAD (1 << 5) ++#define RSAC_RSAS (1 << 4) ++#define RSAC_PERC (1 << 3) ++#define RSAC_PERD (1 << 2) ++#define RSAC_PERS (1 << 1) ++#define RSAC_EN (1 << 0) ++ ++#define mcu_boot() \ ++ do { \ ++ *(volatile unsigned int *)0xb3421030 &= ~1; \ ++ } while(0) ++ ++#define mcu_reset() \ ++ do { \ ++ *(volatile unsigned int *)0xb3421030 |= 1; \ ++ } while(0) ++ ++static int inline rsa_readl(struct jz_rsa *rsa, unsigned int offset) ++{ ++ return readl(rsa->iomem + offset); ++} ++ ++static void inline rsa_writel(struct jz_rsa *rsa, unsigned int offset, unsigned int val) ++{ ++ writel(val, rsa->iomem + offset); ++} ++ ++static int rsa_perpare_key(struct jz_rsa *rsa, struct rsa_key *rsa_key) ++{ ++ unsigned int n[MAX_KEY_LEN_WORD]; ++ unsigned int e[MAX_KEY_LEN_WORD]; ++ unsigned int keylen = rsa_key->rsa_mode/32; ++ ++ unsigned int tmp; ++ unsigned int i; ++ int ret = 0; ++ ++ mutex_lock(&rsa->mutex); ++ ++ rsa->per_done = 0; ++ rsa->n_len = keylen; ++ ++ if(copy_from_user(e, rsa_key->e, keylen * 4)) { ++ dev_err(rsa->dev, "Failed to copy rsa_key->e form user!\n"); ++ ret = -EFAULT; ++ goto err; ++ } ++ if(copy_from_user(n, rsa_key->n, keylen * 4)) { ++ dev_err(rsa->dev, "Failed to copy rsa_key->n form user!\n"); ++ ret = -EFAULT; ++ goto err; ++ } ++ ++ tmp = rsa_readl(rsa, RSAC); ++ if(rsa_key->rsa_mode == 2048) ++ tmp |= RSAC_RSA_2048; ++ else if (rsa_key->rsa_mode == 1024) ++ tmp &= ~RSAC_RSA_2048; ++ tmp &= ~RSAC_PER_INT_M; ++ rsa_writel(rsa, RSAC, tmp); ++ ++ for(i = 0; i < keylen; i++) { ++ rsa_writel(rsa, RSAE, e[i]); ++ } ++ for(i = 0; i < keylen; i++){ ++ rsa_writel(rsa, RSAN, n[i]); ++ } ++ rsa_writel(rsa, RSAC, RSAC_PERS | rsa_readl(rsa, RSAC)); ++ ++ ret = wait_event_interruptible(rsa->wq, rsa->per_done == 1); ++ if(ret < 0) { ++ dev_err(rsa->dev, "key perpare can't wait irq\n"); ++ ret = -EFAULT; ++ goto err; ++ } ++ ++ rsa_writel(rsa, RSAC, RSAC_PERC | rsa_readl(rsa, RSAC)); ++ rsa_writel(rsa, RSAC, ~RSAC_PERC & rsa_readl(rsa, RSAC)); ++ ++ mutex_unlock(&rsa->mutex); ++ return 0; ++ ++err: ++ mutex_unlock(&rsa->mutex); ++ return ret; ++} ++ ++static int rsa_do_crypt(struct jz_rsa *rsa, struct rsa_data *rsa_data) ++{ ++ unsigned int input[MAX_KEY_LEN_WORD]; ++ unsigned int output[MAX_KEY_LEN_WORD]; ++ unsigned int *id = rsa_data->input; ++ unsigned int *od = rsa_data->output; ++ unsigned int keylen = rsa->n_len; ++ unsigned int len = rsa_data->inlen; ++ ++ unsigned int i; ++ int ret = 0; ++ ++ mutex_lock(&rsa->mutex); ++ ++ if(len % keylen) { ++ pr_err("Data len err \n"); ++ ret = -EINVAL; ++ goto err; ++ } ++ ++ while(len > 0) { ++ ++ rsa->rsa_done = 0; ++ ++ if(copy_from_user(input, id, keylen * 4)) { ++ dev_err(rsa->dev, "Failed to copy rsa_data->input form user!\n"); ++ ret = -EFAULT; ++ goto err; ++ } ++ ++ for(i = 0; i < keylen; i++) { ++ rsa_writel(rsa, RSAM, input[i]); ++ } ++ ++ rsa_writel(rsa, RSAC, ~RSAC_RSA_INT_M & rsa_readl(rsa, RSAC)); ++ rsa_writel(rsa, RSAC, RSAC_RSAS | rsa_readl(rsa, RSAC)); ++ ++ ret = wait_event_interruptible(rsa->wq, rsa->rsa_done == 1); ++ if(ret < 0) { ++ dev_err(rsa->dev, "rsa crypt can't wait irq\n"); ++ ret = -EFAULT; ++ goto err; ++ } ++ ++ for(i = 0; i < keylen; i++) { ++ output[keylen -1 - i] = rsa_readl(rsa, RSAP); ++ } ++ ++ rsa_writel(rsa, RSAC, rsa_readl(rsa, RSAC) | RSAC_RSAC); ++ rsa_writel(rsa, RSAC, rsa_readl(rsa, RSAC) & ~RSAC_RSAC); ++ ++ if(copy_to_user(od, output, keylen * 4)) { ++ dev_err(rsa->dev, "Failed to copy rsa_data->input form user!\n"); ++ ret = -EFAULT; ++ goto err; ++ } ++ ++ len -= keylen; ++ id += keylen; ++ od += keylen; ++ ++ } ++ ++ mutex_unlock(&rsa->mutex); ++ return 0; ++ ++err: ++ mutex_unlock(&rsa->mutex); ++ return ret; ++ ++} ++ ++static int rsa_open(struct inode *inode, struct file *flip) ++{ ++ struct miscdevice *mdev = flip->private_data; ++ struct jz_rsa *rsa = container_of(mdev, struct jz_rsa, mdev); ++ int tmp; ++ ++ mutex_lock(&rsa->mutex); ++ if(rsa->busy) { ++ dev_err(rsa->dev, "Device is busy!\n"); ++ mutex_unlock(&rsa->mutex); ++ return -EBUSY; ++ } ++ ++ rsa->busy = 1; ++ ++ rsa_writel(rsa, RSAC, RSAC_EN | rsa_readl(rsa, RSAC)); ++ ++ mutex_unlock(&rsa->mutex); ++ ++ return 0; ++} ++ ++static int rsa_release(struct inode *inode, struct file *flip) ++{ ++ struct miscdevice *mdev = flip->private_data; ++ struct jz_rsa *rsa = container_of(mdev, struct jz_rsa, mdev); ++ ++ mutex_lock(&rsa->mutex); ++ ++ rsa->busy = 0; ++ ++ rsa_writel(rsa, RSAC, ~RSAC_EN & rsa_readl(rsa, RSAC)); ++ ++ mutex_unlock(&rsa->mutex); ++ ++ return 0; ++} ++ ++static long rsa_ioctl(struct file *flip, unsigned int cmd, unsigned long args) ++{ ++ struct miscdevice *mdev = flip->private_data; ++ struct jz_rsa *rsa = container_of(mdev, struct jz_rsa, mdev); ++ struct rsa_key rsa_key; ++ struct rsa_data rsa_data; ++ int ret = 0; ++ ++ switch (cmd) { ++ case RSA_PERPARE_KEY: ++ ++ if(copy_from_user(&rsa_key, (void *)args, sizeof(struct rsa_key))) { ++ dev_err(rsa->dev, "Failed to copy rsa_key form user!\n"); ++ ret = -EFAULT; ++ goto err; ++ } ++ ++ ret = rsa_perpare_key(rsa, &rsa_key); ++ ++ break; ++ case RSA_DO_CRYPT: ++ if(rsa->n_len != 32 && rsa->n_len != 64) { ++ dev_err(rsa->dev, "RSA key len err!\n"); ++ ret = -EINVAL; ++ goto err; ++ } ++ if(copy_from_user(&rsa_data, (void *)args, sizeof(struct rsa_data))) { ++ dev_err(rsa->dev, "Could not copy data from user!\n"); ++ ret = -EFAULT; ++ goto err; ++ } ++ ++ ret = rsa_do_crypt(rsa, &rsa_data); ++ if(ret < 0) { ++ dev_err(rsa->dev, "Failed to crypt data!\n"); ++ goto err; ++ } ++ ++ break; ++ default: ++ dev_err(rsa->dev, "Unsupport IO cmd: %x\n", cmd); ++ ++ } ++ ++ return 0; ++err: ++ return ret; ++} ++ ++static struct file_operations rsa_misc_fops = { ++ .owner = THIS_MODULE, ++ .open = rsa_open, ++ .release = rsa_release, ++ .unlocked_ioctl = rsa_ioctl, ++}; ++ ++static irqreturn_t rsa_irq(int irq, void *data) ++{ ++ struct jz_rsa *rsa = (struct jz_rsa *)data; ++ ++ if (rsa_readl(rsa, RSAC) & RSAC_RSAD) { ++ rsa_writel(rsa, RSAC, ~RSAC_RSAS & rsa_readl(rsa, RSAC)); ++ rsa_writel(rsa, RSAC, RSAC_RSA_INT_M | rsa_readl(rsa, RSAC)); ++ rsa->rsa_done = 1; ++ } else if (rsa_readl(rsa, RSAC) & RSAC_PERD) { ++ rsa_writel(rsa, RSAC, ~RSAC_PERS & rsa_readl(rsa, RSAC)); ++ rsa_writel(rsa, RSAC, RSAC_PER_INT_M | rsa_readl(rsa, RSAC)); ++ rsa->per_done = 1; ++ } ++ ++ wake_up(&rsa->wq); ++ ++ return IRQ_HANDLED; ++} ++ ++#define cpm_readl(o) (*(volatile unsigned int *)(o)) ++#define cpm_writel(b, o) (*(volatile unsigned int *)(o)) = (b) ++#define CPM_RSACDR (0xb0000050) ++#define CPM_CLKGR0 (0xb0000020) ++static int jz_rsa_probe(struct platform_device * pdev) ++{ ++ int ret = 0; ++ struct jz_rsa *rsa; ++ struct resource *res; ++ unsigned int tmp; ++ ++ rsa = kzalloc(sizeof(struct jz_rsa), GFP_KERNEL); ++ if(IS_ERR_OR_NULL(rsa)) { ++ pr_err("Failed to alloc mem fir jz_rsa!\n"); ++ ret = -ENOMEM; ++ goto err; ++ } ++ ++ rsa->dev = &pdev->dev; ++ ++ rsa->clk_gate = devm_clk_get(&pdev->dev, "gate_rsa"); ++ if (IS_ERR(rsa->clk_gate)) { ++ dev_err(&pdev->dev, "cannot find rsa clock\n"); ++ ret = PTR_ERR(rsa->clk_gate); ++ goto err1; ++ } ++ clk_prepare_enable(rsa->clk_gate); ++ ++ /* rsa cguclk SACLK/2 */ ++ tmp = cpm_readl(CPM_RSACDR); ++ tmp &= ~(2<<30 | 0xf | 1 << 27); ++ tmp |= 1 << 29; ++ tmp |= 2 << 0; ++ ++ cpm_writel(tmp, CPM_RSACDR); ++ while(cpm_readl(CPM_RSACDR) & (1<<28)); ++ tmp &= ~(1<<29); ++ cpm_writel(tmp, CPM_RSACDR); ++ cpm_writel(0, CPM_CLKGR0); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if(IS_ERR_OR_NULL(res)) { ++ dev_err(rsa->dev, "No iomem resource!\n"); ++ ret = -ENOMEM; ++ goto err1; ++ } ++ ++ rsa->irq = platform_get_irq(pdev, 0); ++ if(rsa->irq < 0) { ++ dev_err(&pdev->dev, "No irq resource!\n"); ++ ret = -ENOMEM; ++ goto err1; ++ } ++ ++ rsa->iomem = devm_ioremap(rsa->dev, res->start, resource_size(res)); ++ if(IS_ERR_OR_NULL(rsa->iomem)) { ++ dev_err(&pdev->dev, "Failed to remap io resources!\n"); ++ ret = -ENOMEM; ++ goto err1; ++ } ++ ++ ret = devm_request_irq(&pdev->dev, rsa->irq, rsa_irq, IRQF_ONESHOT, dev_name(&pdev->dev), rsa); ++ if(ret < 0) { ++ dev_err(&pdev->dev, "Failed to request irq!\n"); ++ goto err_request_irq; ++ } ++ ++ init_waitqueue_head(&rsa->wq); ++ ++ platform_set_drvdata(pdev, rsa); ++ ++ mutex_init(&rsa->mutex); ++ ++ rsa->mdev.minor = MISC_DYNAMIC_MINOR; ++ rsa->mdev.name = DEV_NAME; ++ rsa->mdev.fops = &rsa_misc_fops; ++ ret = misc_register(&rsa->mdev); ++ if(ret < 0) { ++ dev_err(&pdev->dev, "Failed to register misc driver!\n"); ++ goto err_misc_register; ++ } ++ ++ dev_info(&pdev->dev, "rsa driver probe ok!\n"); ++ ++ return 0; ++ ++err_misc_register: ++ mutex_destroy(&rsa->mutex); ++err_request_irq: ++ devm_iounmap(rsa->dev, rsa->iomem); ++err1: ++ kfree(rsa); ++err: ++ dev_err(rsa->dev, "initialization failed.\n"); ++ return ret; ++ ++} ++ ++static int jz_rsa_remove(struct platform_device *pdev) ++{ ++ struct jz_rsa *rsa = platform_get_drvdata(pdev); ++ ++ misc_deregister(&rsa->mdev); ++ devm_iounmap(rsa->dev, rsa->iomem); ++ kfree(rsa); ++ ++ return 0; ++} ++ ++static const struct of_device_id ingenic_rsa_dt_match[] = { ++ { .compatible = "ingenic,rsa", .data = NULL }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, aic_dt_match); ++ ++static struct platform_driver ingenic_rsa_driver = { ++ .probe = jz_rsa_probe, ++ .remove = jz_rsa_remove, ++ .driver = { ++ .name = "rsa", ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(ingenic_rsa_dt_match), ++ }, ++}; ++ ++module_platform_driver(ingenic_rsa_driver); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("mayuanjun "); ++MODULE_DESCRIPTION("ingenic rsa driver"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_misc_logger.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_misc_logger.c.patch new file mode 100644 index 00000000..b9bb747f --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_misc_logger.c.patch @@ -0,0 +1,855 @@ +diff -drupN a/drivers/misc/logger.c b/drivers/misc/logger.c +--- a/drivers/misc/logger.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/misc/logger.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,851 @@ ++/* ++ * drivers/misc/logger.c ++ * ++ * A Logging Subsystem ++ * ++ * Copyright (C) 2007-2008 Google, Inc. ++ * ++ * Robert Love ++ * ++ * This software is licensed under the terms of the GNU General Public ++ * License version 2, as published by the Free Software Foundation, and ++ * may be copied, distributed, and modified under those terms. ++ * ++ * 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. ++ */ ++ ++#define pr_fmt(fmt) "logger: " fmt ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "logger.h" ++ ++#include ++ ++/** ++ * struct logger_log - represents a specific log, such as 'main' or 'radio' ++ * @buffer: The actual ring buffer ++ * @misc: The "misc" device representing the log ++ * @wq: The wait queue for @readers ++ * @readers: This log's readers ++ * @mutex: The mutex that protects the @buffer ++ * @w_off: The current write head offset ++ * @head: The head, or location that readers start reading at. ++ * @size: The size of the log ++ * @logs: The list of log channels ++ * ++ * This structure lives from module insertion until module removal, so it does ++ * not need additional reference counting. The structure is protected by the ++ * mutex 'mutex'. ++ */ ++struct logger_log { ++ unsigned char *buffer; ++ struct miscdevice misc; ++ wait_queue_head_t wq; ++ struct list_head readers; ++ struct mutex mutex; ++ size_t w_off; ++ size_t head; ++ size_t size; ++ struct list_head logs; ++}; ++ ++static LIST_HEAD(log_list); ++ ++ ++/** ++ * struct logger_reader - a logging device open for reading ++ * @log: The associated log ++ * @list: The associated entry in @logger_log's list ++ * @r_off: The current read head offset. ++ * @r_all: Reader can read all entries ++ * @r_ver: Reader ABI version ++ * ++ * This object lives from open to release, so we don't need additional ++ * reference counting. The structure is protected by log->mutex. ++ */ ++struct logger_reader { ++ struct logger_log *log; ++ struct list_head list; ++ size_t r_off; ++ bool r_all; ++ int r_ver; ++}; ++ ++/* logger_offset - returns index 'n' into the log via (optimized) modulus */ ++static size_t logger_offset(struct logger_log *log, size_t n) ++{ ++ return n & (log->size - 1); ++} ++ ++ ++/* ++ * file_get_log - Given a file structure, return the associated log ++ * ++ * This isn't aesthetic. We have several goals: ++ * ++ * 1) Need to quickly obtain the associated log during an I/O operation ++ * 2) Readers need to maintain state (logger_reader) ++ * 3) Writers need to be very fast (open() should be a near no-op) ++ * ++ * In the reader case, we can trivially go file->logger_reader->logger_log. ++ * For a writer, we don't want to maintain a logger_reader, so we just go ++ * file->logger_log. Thus what file->private_data points at depends on whether ++ * or not the file was opened for reading. This function hides that dirtiness. ++ */ ++static inline struct logger_log *file_get_log(struct file *file) ++{ ++ if (file->f_mode & FMODE_READ) { ++ struct logger_reader *reader = file->private_data; ++ return reader->log; ++ } else ++ return file->private_data; ++} ++ ++/* ++ * get_entry_header - returns a pointer to the logger_entry header within ++ * 'log' starting at offset 'off'. A temporary logger_entry 'scratch' must ++ * be provided. Typically the return value will be a pointer within ++ * 'logger->buf'. However, a pointer to 'scratch' may be returned if ++ * the log entry spans the end and beginning of the circular buffer. ++ */ ++static struct logger_entry *get_entry_header(struct logger_log *log, ++ size_t off, struct logger_entry *scratch) ++{ ++ size_t len = min(sizeof(struct logger_entry), log->size - off); ++ if (len != sizeof(struct logger_entry)) { ++ memcpy(((void *) scratch), log->buffer + off, len); ++ memcpy(((void *) scratch) + len, log->buffer, ++ sizeof(struct logger_entry) - len); ++ return scratch; ++ } ++ ++ return (struct logger_entry *) (log->buffer + off); ++} ++ ++/* ++ * get_entry_msg_len - Grabs the length of the message of the entry ++ * starting from from 'off'. ++ * ++ * An entry length is 2 bytes (16 bits) in host endian order. ++ * In the log, the length does not include the size of the log entry structure. ++ * This function returns the size including the log entry structure. ++ * ++ * Caller needs to hold log->mutex. ++ */ ++static __u32 get_entry_msg_len(struct logger_log *log, size_t off) ++{ ++ struct logger_entry scratch; ++ struct logger_entry *entry; ++ ++ entry = get_entry_header(log, off, &scratch); ++ return entry->len; ++} ++ ++static size_t get_user_hdr_len(int ver) ++{ ++ if (ver < 2) ++ return sizeof(struct user_logger_entry_compat); ++ else ++ return sizeof(struct logger_entry); ++} ++ ++static ssize_t copy_header_to_user(int ver, struct logger_entry *entry, ++ char __user *buf) ++{ ++ void *hdr; ++ size_t hdr_len; ++ struct user_logger_entry_compat v1; ++ ++ if (ver < 2) { ++ v1.len = entry->len; ++ v1.__pad = 0; ++ v1.pid = entry->pid; ++ v1.tid = entry->tid; ++ v1.sec = entry->sec; ++ v1.nsec = entry->nsec; ++ hdr = &v1; ++ hdr_len = sizeof(struct user_logger_entry_compat); ++ } else { ++ hdr = entry; ++ hdr_len = sizeof(struct logger_entry); ++ } ++ ++ return copy_to_user(buf, hdr, hdr_len); ++} ++ ++/* ++ * do_read_log_to_user - reads exactly 'count' bytes from 'log' into the ++ * user-space buffer 'buf'. Returns 'count' on success. ++ * ++ * Caller must hold log->mutex. ++ */ ++static ssize_t do_read_log_to_user(struct logger_log *log, ++ struct logger_reader *reader, ++ char __user *buf, ++ size_t count) ++{ ++ struct logger_entry scratch; ++ struct logger_entry *entry; ++ size_t len; ++ size_t msg_start; ++ ++ /* ++ * First, copy the header to userspace, using the version of ++ * the header requested ++ */ ++ entry = get_entry_header(log, reader->r_off, &scratch); ++ if (copy_header_to_user(reader->r_ver, entry, buf)) ++ return -EFAULT; ++ ++ count -= get_user_hdr_len(reader->r_ver); ++ buf += get_user_hdr_len(reader->r_ver); ++ msg_start = logger_offset(log, ++ reader->r_off + sizeof(struct logger_entry)); ++ ++ /* ++ * We read from the msg in two disjoint operations. First, we read from ++ * the current msg head offset up to 'count' bytes or to the end of ++ * the log, whichever comes first. ++ */ ++ len = min(count, log->size - msg_start); ++ if (copy_to_user(buf, log->buffer + msg_start, len)) ++ return -EFAULT; ++ ++ /* ++ * Second, we read any remaining bytes, starting back at the head of ++ * the log. ++ */ ++ if (count != len) ++ if (copy_to_user(buf + len, log->buffer, count - len)) ++ return -EFAULT; ++ ++ reader->r_off = logger_offset(log, reader->r_off + ++ sizeof(struct logger_entry) + count); ++ ++ return count + get_user_hdr_len(reader->r_ver); ++} ++ ++/* ++ * get_next_entry_by_uid - Starting at 'off', returns an offset into ++ * 'log->buffer' which contains the first entry readable by 'euid' ++ */ ++static size_t get_next_entry_by_uid(struct logger_log *log, ++ size_t off, kuid_t euid) ++{ ++ while (off != log->w_off) { ++ struct logger_entry *entry; ++ struct logger_entry scratch; ++ size_t next_len; ++ ++ entry = get_entry_header(log, off, &scratch); ++ ++ if (uid_eq(entry->euid, euid)) ++ return off; ++ ++ next_len = sizeof(struct logger_entry) + entry->len; ++ off = logger_offset(log, off + next_len); ++ } ++ ++ return off; ++} ++ ++/* ++ * logger_read - our log's read() method ++ * ++ * Behavior: ++ * ++ * - O_NONBLOCK works ++ * - If there are no log entries to read, blocks until log is written to ++ * - Atomically reads exactly one log entry ++ * ++ * Will set errno to EINVAL if read ++ * buffer is insufficient to hold next entry. ++ */ ++static ssize_t logger_read(struct file *file, char __user *buf, ++ size_t count, loff_t *pos) ++{ ++ struct logger_reader *reader = file->private_data; ++ struct logger_log *log = reader->log; ++ ssize_t ret; ++ DEFINE_WAIT(wait); ++ ++start: ++ while (1) { ++ mutex_lock(&log->mutex); ++ ++ prepare_to_wait(&log->wq, &wait, TASK_INTERRUPTIBLE); ++ ++ ret = (log->w_off == reader->r_off); ++ mutex_unlock(&log->mutex); ++ if (!ret) ++ break; ++ ++ if (file->f_flags & O_NONBLOCK) { ++ ret = -EAGAIN; ++ break; ++ } ++ ++ if (signal_pending(current)) { ++ ret = -EINTR; ++ break; ++ } ++ ++ schedule(); ++ } ++ ++ finish_wait(&log->wq, &wait); ++ if (ret) ++ return ret; ++ ++ mutex_lock(&log->mutex); ++ ++ if (!reader->r_all) ++ reader->r_off = get_next_entry_by_uid(log, ++ reader->r_off, current_euid()); ++ ++ /* is there still something to read or did we race? */ ++ if (unlikely(log->w_off == reader->r_off)) { ++ mutex_unlock(&log->mutex); ++ goto start; ++ } ++ ++ /* get the size of the next entry */ ++ ret = get_user_hdr_len(reader->r_ver) + ++ get_entry_msg_len(log, reader->r_off); ++ if (count < ret) { ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ /* get exactly one entry from the log */ ++ ret = do_read_log_to_user(log, reader, buf, ret); ++ ++out: ++ mutex_unlock(&log->mutex); ++ ++ return ret; ++} ++ ++/* ++ * get_next_entry - return the offset of the first valid entry at least 'len' ++ * bytes after 'off'. ++ * ++ * Caller must hold log->mutex. ++ */ ++static size_t get_next_entry(struct logger_log *log, size_t off, size_t len) ++{ ++ size_t count = 0; ++ ++ do { ++ size_t nr = sizeof(struct logger_entry) + ++ get_entry_msg_len(log, off); ++ off = logger_offset(log, off + nr); ++ count += nr; ++ } while (count < len); ++ ++ return off; ++} ++ ++/* ++ * is_between - is a < c < b, accounting for wrapping of a, b, and c ++ * positions in the buffer ++ * ++ * That is, if ab, check for c outside (not between) a and b ++ * ++ * |------- a xxxxxxxx b --------| ++ * c^ ++ * ++ * |xxxxx b --------- a xxxxxxxxx| ++ * c^ ++ * or c^ ++ */ ++static inline int is_between(size_t a, size_t b, size_t c) ++{ ++ if (a < b) { ++ /* is c between a and b? */ ++ if (a < c && c <= b) ++ return 1; ++ } else { ++ /* is c outside of b through a? */ ++ if (c <= b || a < c) ++ return 1; ++ } ++ ++ return 0; ++} ++ ++/* ++ * fix_up_readers - walk the list of all readers and "fix up" any who were ++ * lapped by the writer; also do the same for the default "start head". ++ * We do this by "pulling forward" the readers and start head to the first ++ * entry after the new write head. ++ * ++ * The caller needs to hold log->mutex. ++ */ ++static void fix_up_readers(struct logger_log *log, size_t len) ++{ ++ size_t old = log->w_off; ++ size_t new = logger_offset(log, old + len); ++ struct logger_reader *reader; ++ ++ if (is_between(old, new, log->head)) ++ log->head = get_next_entry(log, log->head, len); ++ ++ list_for_each_entry(reader, &log->readers, list) ++ if (is_between(old, new, reader->r_off)) ++ reader->r_off = get_next_entry(log, reader->r_off, len); ++} ++ ++/* ++ * do_write_log - writes 'len' bytes from 'buf' to 'log' ++ * ++ * The caller needs to hold log->mutex. ++ */ ++static void do_write_log(struct logger_log *log, const void *buf, size_t count) ++{ ++ size_t len; ++ ++ len = min(count, log->size - log->w_off); ++ memcpy(log->buffer + log->w_off, buf, len); ++ ++ if (count != len) ++ memcpy(log->buffer, buf + len, count - len); ++ ++ log->w_off = logger_offset(log, log->w_off + count); ++ ++} ++ ++/* ++ * do_write_log_user - writes 'len' bytes from the user-space buffer 'buf' to ++ * the log 'log' ++ * ++ * The caller needs to hold log->mutex. ++ * ++ * Returns 'count' on success, negative error code on failure. ++ */ ++static ssize_t do_write_log_from_user(struct logger_log *log, ++ const void __user *buf, size_t count) ++{ ++ size_t len; ++ ++ len = min(count, log->size - log->w_off); ++ if (len && copy_from_user(log->buffer + log->w_off, buf, len)) ++ return -EFAULT; ++ ++ if (count != len) ++ if (copy_from_user(log->buffer, buf + len, count - len)) ++ /* ++ * Note that by not updating w_off, this abandons the ++ * portion of the new entry that *was* successfully ++ * copied, just above. This is intentional to avoid ++ * message corruption from missing fragments. ++ */ ++ return -EFAULT; ++ ++ log->w_off = logger_offset(log, log->w_off + count); ++ ++ return count; ++} ++ ++/* ++ * logger_aio_write - our write method, implementing support for write(), ++ * writev(), and aio_write(). Writes are our fast path, and we try to optimize ++ * them above all else. ++ */ ++static ssize_t logger_aio_write(struct kiocb *iocb, struct iov_iter *iter) ++{ ++ struct logger_log *log = file_get_log(iocb->ki_filp); ++ size_t orig; ++ struct logger_entry header; ++ struct timespec now; ++ ssize_t ret = 0; ++ ++ now = current_kernel_time(); ++ ++ header.pid = current->tgid; ++ header.tid = current->pid; ++ header.sec = now.tv_sec; ++ header.nsec = now.tv_nsec; ++ header.euid = current_euid(); ++ header.len = min_t(size_t, iter->count, LOGGER_ENTRY_MAX_PAYLOAD); ++ header.hdr_size = sizeof(struct logger_entry); ++ ++ /* null writes succeed, return zero */ ++ if (unlikely(!header.len)) ++ return 0; ++ ++ mutex_lock(&log->mutex); ++ ++ orig = log->w_off; ++ ++ /* ++ * Fix up any readers, pulling them forward to the first readable ++ * entry after (what will be) the new write offset. We do this now ++ * because if we partially fail, we can end up with clobbered log ++ * entries that encroach on readable buffer. ++ */ ++ fix_up_readers(log, sizeof(struct logger_entry) + header.len); ++ ++ do_write_log(log, &header, sizeof(struct logger_entry)); ++ ++ while (iter->nr_segs-- > 0) { ++ size_t len; ++ ssize_t nr; ++ ++ /* figure out how much of this vector we can keep */ ++ len = min_t(size_t, iter->iov->iov_len, header.len - ret); ++ ++ /* write out this segment's payload */ ++ nr = do_write_log_from_user(log, iter->iov->iov_base, len); ++ if (unlikely(nr < 0)) { ++ log->w_off = orig; ++ mutex_unlock(&log->mutex); ++ return nr; ++ } ++ ++ iter->iov++; ++ ret += nr; ++ } ++ ++ mutex_unlock(&log->mutex); ++ ++ /* wake up any blocked readers */ ++ wake_up_interruptible(&log->wq); ++ ++ return ret; ++} ++ ++static struct logger_log *get_log_from_minor(int minor) ++{ ++ struct logger_log *log; ++ ++ list_for_each_entry(log, &log_list, logs) ++ if (log->misc.minor == minor) ++ return log; ++ return NULL; ++} ++ ++/* ++ * logger_open - the log's open() file operation ++ * ++ * Note how near a no-op this is in the write-only case. Keep it that way! ++ */ ++static int logger_open(struct inode *inode, struct file *file) ++{ ++ struct logger_log *log; ++ int ret; ++ ++ ret = nonseekable_open(inode, file); ++ if (ret) ++ return ret; ++ ++ log = get_log_from_minor(MINOR(inode->i_rdev)); ++ if (!log) ++ return -ENODEV; ++ ++ if (file->f_mode & FMODE_READ) { ++ struct logger_reader *reader; ++ ++ reader = kmalloc(sizeof(struct logger_reader), GFP_KERNEL); ++ if (!reader) ++ return -ENOMEM; ++ ++ reader->log = log; ++ reader->r_ver = 1; ++ reader->r_all = in_egroup_p(inode->i_gid) || ++ capable(CAP_SYSLOG); ++ ++ INIT_LIST_HEAD(&reader->list); ++ ++ mutex_lock(&log->mutex); ++ reader->r_off = log->head; ++ list_add_tail(&reader->list, &log->readers); ++ mutex_unlock(&log->mutex); ++ ++ file->private_data = reader; ++ } else ++ file->private_data = log; ++ ++ return 0; ++} ++ ++/* ++ * logger_release - the log's release file operation ++ * ++ * Note this is a total no-op in the write-only case. Keep it that way! ++ */ ++static int logger_release(struct inode *ignored, struct file *file) ++{ ++ if (file->f_mode & FMODE_READ) { ++ struct logger_reader *reader = file->private_data; ++ struct logger_log *log = reader->log; ++ ++ mutex_lock(&log->mutex); ++ list_del(&reader->list); ++ mutex_unlock(&log->mutex); ++ ++ kfree(reader); ++ } ++ ++ return 0; ++} ++ ++/* ++ * logger_poll - the log's poll file operation, for poll/select/epoll ++ * ++ * Note we always return POLLOUT, because you can always write() to the log. ++ * Note also that, strictly speaking, a return value of POLLIN does not ++ * guarantee that the log is readable without blocking, as there is a small ++ * chance that the writer can lap the reader in the interim between poll() ++ * returning and the read() request. ++ */ ++static unsigned int logger_poll(struct file *file, poll_table *wait) ++{ ++ struct logger_reader *reader; ++ struct logger_log *log; ++ unsigned int ret = POLLOUT | POLLWRNORM; ++ ++ if (!(file->f_mode & FMODE_READ)) ++ return ret; ++ ++ reader = file->private_data; ++ log = reader->log; ++ ++ poll_wait(file, &log->wq, wait); ++ ++ mutex_lock(&log->mutex); ++ if (!reader->r_all) ++ reader->r_off = get_next_entry_by_uid(log, ++ reader->r_off, current_euid()); ++ ++ if (log->w_off != reader->r_off) ++ ret |= POLLIN | POLLRDNORM; ++ mutex_unlock(&log->mutex); ++ ++ return ret; ++} ++ ++static long logger_set_version(struct logger_reader *reader, void __user *arg) ++{ ++ int version; ++ if (copy_from_user(&version, arg, sizeof(int))) ++ return -EFAULT; ++ ++ if ((version < 1) || (version > 2)) ++ return -EINVAL; ++ ++ reader->r_ver = version; ++ return 0; ++} ++ ++static long logger_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ struct logger_log *log = file_get_log(file); ++ struct logger_reader *reader; ++ long ret = -EINVAL; ++ void __user *argp = (void __user *) arg; ++ ++ mutex_lock(&log->mutex); ++ ++ switch (cmd) { ++ case LOGGER_GET_LOG_BUF_SIZE: ++ ret = log->size; ++ break; ++ case LOGGER_GET_LOG_LEN: ++ if (!(file->f_mode & FMODE_READ)) { ++ ret = -EBADF; ++ break; ++ } ++ reader = file->private_data; ++ if (log->w_off >= reader->r_off) ++ ret = log->w_off - reader->r_off; ++ else ++ ret = (log->size - reader->r_off) + log->w_off; ++ break; ++ case LOGGER_GET_NEXT_ENTRY_LEN: ++ if (!(file->f_mode & FMODE_READ)) { ++ ret = -EBADF; ++ break; ++ } ++ reader = file->private_data; ++ ++ if (!reader->r_all) ++ reader->r_off = get_next_entry_by_uid(log, ++ reader->r_off, current_euid()); ++ ++ if (log->w_off != reader->r_off) ++ ret = get_user_hdr_len(reader->r_ver) + ++ get_entry_msg_len(log, reader->r_off); ++ else ++ ret = 0; ++ break; ++ case LOGGER_FLUSH_LOG: ++ if (!(file->f_mode & FMODE_WRITE)) { ++ ret = -EBADF; ++ break; ++ } ++ if (!(in_egroup_p(file_inode(file)->i_gid) || ++ capable(CAP_SYSLOG))) { ++ ret = -EPERM; ++ break; ++ } ++ list_for_each_entry(reader, &log->readers, list) ++ reader->r_off = log->w_off; ++ log->head = log->w_off; ++ ret = 0; ++ break; ++ case LOGGER_GET_VERSION: ++ if (!(file->f_mode & FMODE_READ)) { ++ ret = -EBADF; ++ break; ++ } ++ reader = file->private_data; ++ ret = reader->r_ver; ++ break; ++ case LOGGER_SET_VERSION: ++ if (!(file->f_mode & FMODE_READ)) { ++ ret = -EBADF; ++ break; ++ } ++ reader = file->private_data; ++ ret = logger_set_version(reader, argp); ++ break; ++ } ++ ++ mutex_unlock(&log->mutex); ++ ++ return ret; ++} ++ ++static const struct file_operations logger_fops = { ++ .owner = THIS_MODULE, ++ .read = logger_read, ++ .write_iter = logger_aio_write, ++ .poll = logger_poll, ++ .unlocked_ioctl = logger_ioctl, ++ .compat_ioctl = logger_ioctl, ++ .open = logger_open, ++ .release = logger_release, ++}; ++ ++/* ++ * Log size must must be a power of two, and greater than ++ * (LOGGER_ENTRY_MAX_PAYLOAD + sizeof(struct logger_entry)). ++ */ ++static int __init create_log(char *log_name, int size) ++{ ++ int ret = 0; ++ struct logger_log *log; ++ unsigned char *buffer; ++ ++ buffer = vmalloc(size); ++ if (buffer == NULL) ++ return -ENOMEM; ++ ++ log = kzalloc(sizeof(struct logger_log), GFP_KERNEL); ++ if (log == NULL) { ++ ret = -ENOMEM; ++ goto out_free_buffer; ++ } ++ log->buffer = buffer; ++ ++ log->misc.minor = MISC_DYNAMIC_MINOR; ++ log->misc.name = kstrdup(log_name, GFP_KERNEL); ++ if (log->misc.name == NULL) { ++ ret = -ENOMEM; ++ goto out_free_log; ++ } ++ ++ log->misc.fops = &logger_fops; ++ log->misc.parent = NULL; ++ ++ init_waitqueue_head(&log->wq); ++ INIT_LIST_HEAD(&log->readers); ++ mutex_init(&log->mutex); ++ log->w_off = 0; ++ log->head = 0; ++ log->size = size; ++ ++ INIT_LIST_HEAD(&log->logs); ++ list_add_tail(&log->logs, &log_list); ++ ++ /* finally, initialize the misc device for this log */ ++ ret = misc_register(&log->misc); ++ if (unlikely(ret)) { ++ pr_err("failed to register misc device for log '%s'!\n", ++ log->misc.name); ++ goto out_free_log; ++ } ++ ++ //pr_info("created %luK log '%s'\n", ++ // (unsigned long) log->size >> 10, log->misc.name); ++ ++ return 0; ++ ++out_free_log: ++ kfree(log); ++ ++out_free_buffer: ++ vfree(buffer); ++ return ret; ++} ++ ++static int __init logger_init(void) ++{ ++ int ret; ++ ++ ret = create_log(LOGGER_LOG_MAIN, 256*1024); ++ if (unlikely(ret)) ++ goto out; ++ ++ ret = create_log(LOGGER_LOG_EVENTS, 256*1024); ++ if (unlikely(ret)) ++ goto out; ++ ++ ret = create_log(LOGGER_LOG_RADIO, 256*1024); ++ if (unlikely(ret)) ++ goto out; ++ ++ ret = create_log(LOGGER_LOG_SYSTEM, 256*1024); ++ if (unlikely(ret)) ++ goto out; ++ ++out: ++ return ret; ++} ++ ++static void __exit logger_exit(void) ++{ ++ struct logger_log *current_log, *next_log; ++ ++ list_for_each_entry_safe(current_log, next_log, &log_list, logs) { ++ /* we have to delete all the entry inside log_list */ ++ misc_deregister(¤t_log->misc); ++ vfree(current_log->buffer); ++ kfree(current_log->misc.name); ++ list_del(¤t_log->logs); ++ kfree(current_log); ++ } ++} ++ ++ ++device_initcall(logger_init); ++module_exit(logger_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Robert Love, "); ++MODULE_DESCRIPTION("Android Logger"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_misc_logger.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_misc_logger.h.patch new file mode 100644 index 00000000..c643f9ef --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_misc_logger.h.patch @@ -0,0 +1,93 @@ +diff -drupN a/drivers/misc/logger.h b/drivers/misc/logger.h +--- a/drivers/misc/logger.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/misc/logger.h 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,89 @@ ++/* include/linux/logger.h ++ * ++ * Copyright (C) 2007-2008 Google, Inc. ++ * Author: Robert Love ++ * ++ * This software is licensed under the terms of the GNU General Public ++ * License version 2, as published by the Free Software Foundation, and ++ * may be copied, distributed, and modified under those terms. ++ * ++ * 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. ++ * ++ */ ++ ++#ifndef _LINUX_LOGGER_H ++#define _LINUX_LOGGER_H ++ ++#include ++#include ++ ++/** ++ * struct user_logger_entry_compat - defines a single entry that is given to a logger ++ * @len: The length of the payload ++ * @__pad: Two bytes of padding that appear to be required ++ * @pid: The generating process' process ID ++ * @tid: The generating process' thread ID ++ * @sec: The number of seconds that have elapsed since the Epoch ++ * @nsec: The number of nanoseconds that have elapsed since @sec ++ * @msg: The message that is to be logged ++ * ++ * The userspace structure for version 1 of the logger_entry ABI. ++ * This structure is returned to userspace unless the caller requests ++ * an upgrade to a newer ABI version. ++ */ ++struct user_logger_entry_compat { ++ __u16 len; ++ __u16 __pad; ++ __s32 pid; ++ __s32 tid; ++ __s32 sec; ++ __s32 nsec; ++ char msg[0]; ++}; ++ ++/** ++ * struct logger_entry - defines a single entry that is given to a logger ++ * @len: The length of the payload ++ * @hdr_size: sizeof(struct logger_entry_v2) ++ * @pid: The generating process' process ID ++ * @tid: The generating process' thread ID ++ * @sec: The number of seconds that have elapsed since the Epoch ++ * @nsec: The number of nanoseconds that have elapsed since @sec ++ * @euid: Effective UID of logger ++ * @msg: The message that is to be logged ++ * ++ * The structure for version 2 of the logger_entry ABI. ++ * This structure is returned to userspace if ioctl(LOGGER_SET_VERSION) ++ * is called with version >= 2 ++ */ ++struct logger_entry { ++ __u16 len; ++ __u16 hdr_size; ++ __s32 pid; ++ __s32 tid; ++ __s32 sec; ++ __s32 nsec; ++ kuid_t euid; ++ char msg[0]; ++}; ++ ++#define LOGGER_LOG_RADIO "log_radio" /* radio-related messages */ ++#define LOGGER_LOG_EVENTS "log_events" /* system/hardware events */ ++#define LOGGER_LOG_SYSTEM "log_system" /* system/framework messages */ ++#define LOGGER_LOG_MAIN "log_main" /* everything else */ ++ ++#define LOGGER_ENTRY_MAX_PAYLOAD 4076 ++ ++#define __LOGGERIO 0xAE ++ ++#define LOGGER_GET_LOG_BUF_SIZE _IO(__LOGGERIO, 1) /* size of log */ ++#define LOGGER_GET_LOG_LEN _IO(__LOGGERIO, 2) /* used log len */ ++#define LOGGER_GET_NEXT_ENTRY_LEN _IO(__LOGGERIO, 3) /* next entry len */ ++#define LOGGER_FLUSH_LOG _IO(__LOGGERIO, 4) /* flush log */ ++#define LOGGER_GET_VERSION _IO(__LOGGERIO, 5) /* abi version */ ++#define LOGGER_SET_VERSION _IO(__LOGGERIO, 6) /* abi version */ ++ ++#endif /* _LINUX_LOGGER_H */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_misc_rmem.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_misc_rmem.c.patch new file mode 100644 index 00000000..28e34e5b --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_misc_rmem.c.patch @@ -0,0 +1,169 @@ +diff -drupN a/drivers/misc/rmem.c b/drivers/misc/rmem.c +--- a/drivers/misc/rmem.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/misc/rmem.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,165 @@ ++/* ++ * rmem.c - Reserved memory driver for libimp. ++ * ++ * Copyright (C) 2012 Ingenic Semiconductor Co., Ltd. ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define RMEM_MAGIC 'r' ++#define RMEM_CMD_FLUSH_CACHE _IOWR(RMEM_MAGIC, 0, struct rmem_flush_cache_info) ++#define RMEM_CMD_RMEM_INFO _IOWR(RMEM_MAGIC, 1, struct rmem_info) ++ ++struct rmem_info { ++ unsigned int vaddr; ++ unsigned int paddr; ++}; ++static struct rmem_info rmem_addr; ++ ++ ++static struct miscdevice mdev; ++ ++struct rmem_flush_cache_info { ++ unsigned int addr; ++ unsigned int len; ++ unsigned int dir; ++}; ++ ++static int rmem_open(struct inode *inode, struct file *filp) ++{ ++ pr_debug("[%d:%d] %s\n", current->tgid, current->pid, __func__); ++ return 0; ++} ++ ++static int rmem_release(struct inode *inode, struct file *filp) ++{ ++ pr_debug("[%d:%d] %s\n", current->tgid, current->pid, __func__); ++ return 0; ++} ++ ++static long rmem_cmd_flush_cache(long arg) ++{ ++ struct rmem_flush_cache_info info; ++ long ret = 0; ++ if (copy_from_user(&info, (void *)arg, sizeof(info))) { ++ return -EFAULT; ++ } ++ ++ dma_cache_sync(NULL, (void *)info.addr, info.len, info.dir); ++ ++ return ret; ++} ++ ++static long rmem_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ switch (cmd) { ++ case RMEM_CMD_FLUSH_CACHE: ++ return rmem_cmd_flush_cache(arg); ++ case RMEM_CMD_RMEM_INFO: ++ if (copy_to_user((void *)arg, &rmem_addr, sizeof(struct rmem_info))) { ++ return -EFAULT; ++ } ++ break; ++ default: ++ pr_err("Unknown ioctl: 0x%.8X\n", cmd); ++ return -EINVAL; ++ } ++} ++ ++static int rmem_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ vma->vm_flags |= VM_IO; ++ ++ pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK; ++ pgprot_val(vma->vm_page_prot) |= _CACHE_CACHABLE_NONCOHERENT; ++ ++ if (io_remap_pfn_range(vma,vma->vm_start, ++ vma->vm_pgoff, ++ vma->vm_end - vma->vm_start, ++ vma->vm_page_prot)) ++ return -EAGAIN; ++ rmem_addr.vaddr = vma->vm_start; ++ rmem_addr.paddr = vma->vm_pgoff * PAGE_SIZE; ++ ++ ++ return 0; ++} ++ ++static struct file_operations rmem_misc_fops = { ++ .open = rmem_open, ++ .release = rmem_release, ++ .unlocked_ioctl = rmem_ioctl, ++ .mmap = rmem_mmap, ++}; ++ ++static int rmem_probe(struct platform_device *pdev) ++{ ++ int ret; ++ ++ ++ mdev.minor = MISC_DYNAMIC_MINOR; ++ mdev.name = "rmem"; ++ mdev.fops = &rmem_misc_fops; ++ ++ ret = misc_register(&mdev); ++ if (ret < 0) { ++ pr_err("rmem register failed\n"); ++ return -1; ++ } ++ ++ rmem_addr.vaddr = 0; ++ rmem_addr.paddr = 0; ++ ++ return 0; ++} ++ ++static int rmem_remove(struct platform_device *dev) ++{ ++ return 0; ++} ++ ++static struct platform_driver rmem_driver = { ++ .probe = rmem_probe, ++ .remove = rmem_remove, ++ .driver = { ++ .name = "rmem", ++ }, ++}; ++ ++struct platform_device rmem_device = { ++ .name = "rmem", ++ .id = -1, ++ .resource = NULL, ++ .num_resources = 0, ++}; ++ ++static int __init rmem_init(void) ++{ ++ platform_device_register(&rmem_device); ++ return platform_driver_register(&rmem_driver); ++} ++ ++static void __exit rmem_exit(void) ++{ ++ platform_device_unregister(&rmem_device); ++ platform_driver_unregister(&rmem_driver); ++} ++ ++module_init(rmem_init); ++module_exit(rmem_exit); ++ ++MODULE_LICENSE("GPL v2"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_core_core.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_core_core.c.patch new file mode 100644 index 00000000..83920387 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_core_core.c.patch @@ -0,0 +1,30 @@ +diff -drupN a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c +--- a/drivers/mmc/core/core.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/mmc/core/core.c 2022-06-09 05:02:30.000000000 +0300 +@@ -1485,7 +1485,7 @@ int mmc_regulator_get_supply(struct mmc_ + if (IS_ERR(mmc->supply.vmmc)) { + if (PTR_ERR(mmc->supply.vmmc) == -EPROBE_DEFER) + return -EPROBE_DEFER; +- dev_info(dev, "No vmmc regulator found\n"); ++ //dev_info(dev, "No vmmc regulator found\n"); + } else { + ret = mmc_regulator_get_ocrmask(mmc->supply.vmmc); + if (ret > 0) +@@ -1497,7 +1497,7 @@ int mmc_regulator_get_supply(struct mmc_ + if (IS_ERR(mmc->supply.vqmmc)) { + if (PTR_ERR(mmc->supply.vqmmc) == -EPROBE_DEFER) + return -EPROBE_DEFER; +- dev_info(dev, "No vqmmc regulator found\n"); ++ //dev_info(dev, "No vqmmc regulator found\n"); + } + + return 0; +@@ -2578,7 +2578,7 @@ void mmc_rescan(struct work_struct *work + /* If there is a non-removable card registered, only scan once */ + if ((host->caps & MMC_CAP_NONREMOVABLE) && host->rescan_entered) + return; +- host->rescan_entered = 1; ++// host->rescan_entered = 1; + + mmc_bus_get(host); + diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_core_pwrseq_simple.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_core_pwrseq_simple.c.patch new file mode 100644 index 00000000..2e206cbd --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_core_pwrseq_simple.c.patch @@ -0,0 +1,42 @@ +diff -drupN a/drivers/mmc/core/pwrseq_simple.c b/drivers/mmc/core/pwrseq_simple.c +--- a/drivers/mmc/core/pwrseq_simple.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/mmc/core/pwrseq_simple.c 2022-06-09 05:02:30.000000000 +0300 +@@ -15,6 +15,8 @@ + #include + #include + ++#include ++ + #include + + #include "pwrseq.h" +@@ -50,7 +52,7 @@ static void mmc_pwrseq_simple_pre_power_ + pwrseq->clk_enabled = true; + } + +- mmc_pwrseq_simple_set_gpios_value(pwrseq, 1); ++ mmc_pwrseq_simple_set_gpios_value(pwrseq, 0); + } + + static void mmc_pwrseq_simple_post_power_on(struct mmc_host *host) +@@ -58,7 +60,9 @@ static void mmc_pwrseq_simple_post_power + struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq, + struct mmc_pwrseq_simple, pwrseq); + +- mmc_pwrseq_simple_set_gpios_value(pwrseq, 0); ++ mmc_pwrseq_simple_set_gpios_value(pwrseq, 1); ++ ++ jzgpio_set_func(GPIO_PORT_B, GPIO_FUNC_0, 0x3f); + } + + static void mmc_pwrseq_simple_power_off(struct mmc_host *host) +@@ -66,7 +70,8 @@ static void mmc_pwrseq_simple_power_off( + struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq, + struct mmc_pwrseq_simple, pwrseq); + +- mmc_pwrseq_simple_set_gpios_value(pwrseq, 1); ++ jzgpio_set_func(GPIO_PORT_B, GPIO_OUTPUT0, 0x3f); ++ mmc_pwrseq_simple_set_gpios_value(pwrseq, 0); + + if (!IS_ERR(pwrseq->ext_clk) && pwrseq->clk_enabled) { + clk_disable_unprepare(pwrseq->ext_clk); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_host_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_host_Kconfig.patch new file mode 100644 index 00000000..a5635bd6 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_host_Kconfig.patch @@ -0,0 +1,45 @@ +diff -drupN a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig +--- a/drivers/mmc/host/Kconfig 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/mmc/host/Kconfig 2022-06-09 05:02:30.000000000 +0300 +@@ -4,6 +4,17 @@ + + comment "MMC/SD/SDIO Host Controller Drivers" + ++config MMC_SDHCI_INGENIC ++ tristate "Ingenic(XBurst2) MMC/SD Card Controller(MSC) support" ++ depends on SOC_T40 ++ select MMC_SDHCI ++ help ++ This selects the Ingenic XBurst2 SD/MMC Card Controller MSC. ++ If you have platform with a SD/Multimedia Card slot and compact ++ with this version, say Y or M here. ++ If unsure, say N. ++ ++ + config MMC_ARMMMCI + tristate "ARM AMBA Multimedia Card Interface support" + depends on ARM_AMBA +@@ -689,6 +700,23 @@ config MMC_JZ4740 + If you have a board based on such a SoC and with a SD/MMC slot, + say Y or M here. + ++config INGENIC_MMC ++ tristate "Ingenic(XBurst) MMC/SD Card Controller(MSC) support" ++ depends on MACH_XBURST ++ help ++ This selects the Ingenic XBurst SD/MMC Card Controller. ++ If you have platform with a SD/Multimedia Card slot and compact ++ with this version, say Y or M here. ++ If unsure, say N. ++ ++config INGENIC_MMC_MMC0 ++ bool "INGENIC_MMC MMC0" ++ depends on INGENIC_MMC ++ ++config INGENIC_MMC_MMC1 ++ bool "INGENIC_MMC MMC1" ++ depends on INGENIC_MMC ++ + config MMC_VUB300 + tristate "VUB300 USB to SDIO/SD/MMC Host Controller support" + depends on USB diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_host_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_host_Makefile.patch new file mode 100644 index 00000000..4acd8e12 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_host_Makefile.patch @@ -0,0 +1,26 @@ +diff -drupN a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile +--- a/drivers/mmc/host/Makefile 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/mmc/host/Makefile 2022-06-09 05:02:30.000000000 +0300 +@@ -50,6 +50,8 @@ obj-$(CONFIG_MMC_DW_PCI) += dw_mmc-pci.o + obj-$(CONFIG_MMC_DW_ROCKCHIP) += dw_mmc-rockchip.o + obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o + obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o ++obj-$(CONFIG_INGENIC_MMC_MMC0) += ingenic_mmc.o ingenic_sdio.o ++obj-$(CONFIG_INGENIC_MMC_MMC1) += ingenic_mmc.o ingenic_sdio.o + obj-$(CONFIG_MMC_VUB300) += vub300.o + obj-$(CONFIG_MMC_USHC) += ushc.o + obj-$(CONFIG_MMC_WMT) += wmt-sdmmc.o +@@ -76,6 +78,13 @@ obj-$(CONFIG_MMC_SDHCI_IPROC) += sdhci- + obj-$(CONFIG_MMC_SDHCI_MSM) += sdhci-msm.o + obj-$(CONFIG_MMC_SDHCI_ST) += sdhci-st.o + ++ifeq ($(CONFIG_MMC_SDHCI_INGENIC),m) ++ obj-m += ingenic_sdhci_sdio.o ++ ingenic_sdhci_sdio-objs := sdhci-ingenic.o ingenic_sdio.o ++else ++ obj-$(CONFIG_MMC_SDHCI_INGENIC) += sdhci-ingenic.o ingenic_sdio.o ++endif ++ + ifeq ($(CONFIG_CB710_DEBUG),y) + CFLAGS-cb710-mmc += -DDEBUG + endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_host_ingenic_mmc.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_host_ingenic_mmc.c.patch new file mode 100644 index 00000000..6f3d5a97 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_host_ingenic_mmc.c.patch @@ -0,0 +1,1779 @@ +diff -drupN a/drivers/mmc/host/ingenic_mmc.c b/drivers/mmc/host/ingenic_mmc.c +--- a/drivers/mmc/host/ingenic_mmc.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mmc/host/ingenic_mmc.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,1775 @@ ++/* ++ * Ingenic MMC/SD Controller driver ++ * ++ * Copyright (C) 2012 Ingenic Semiconductor Co., Ltd. ++ * Written by Large Dipper . ++ * ++ * Modified by qipengzhen 2016-04-21 ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ingenic_mmc.h" ++ ++/** ++ * MMC driver parameters ++ */ ++#define TIMEOUT_PERIOD 3000 /* msc operation timeout detect period */ ++#define PIO_THRESHOLD 64 /* use pio mode if data length < PIO_THRESHOLD */ ++#define CLK_RATE (CONFIG_EXTAL_CLOCK * 1000000) ++#define CLK_CTRL ++ ++#define ERROR_IFLG ( \ ++ IFLG_CRC_RES_ERR | \ ++ IFLG_CRC_READ_ERR | \ ++ IFLG_CRC_WRITE_ERR | \ ++ IFLG_TIMEOUT_RES | \ ++ IFLG_TIMEOUT_READ) ++ ++/* ++ * Error status including CRC_READ_ERROR, CRC_WRITE_ERROR, ++ * CRC_RES_ERR, TIME_OUT_RES, TIME_OUT_READ ++ */ ++#define ERROR_STAT 0x3f ++ ++#define ingenic_mmc_check_pending(host, event) \ ++ test_and_clear_bit(event, &host->pending_events) ++#define ingenic_mmc_set_pending(host, event) \ ++ set_bit(event, &host->pending_events) ++#define is_pio_mode(host) \ ++ (host->flags & (1 << INGENIC_MMC_USE_PIO)) ++#define enable_pio_mode(host) \ ++ (host->flags |= (1 << INGENIC_MMC_USE_PIO)) ++#define disable_pio_mode(host) \ ++ (host->flags &= ~(1 << INGENIC_MMC_USE_PIO)) ++ ++static LIST_HEAD(manual_list); ++ ++/*-------------------End structure and macro define------------------------*/ ++ ++#ifndef IT_IS_USED_FOR_DEBUG ++static void ingenic_mmc_dump_reg(struct ingenic_mmc_host *host) ++{ ++ dev_info(host->dev,"\nREG dump:\n" ++ "\tCTRL2\t= 0x%08X\n" ++ "\tSTAT\t= 0x%08X\n" ++ "\tCLKRT\t= 0x%08X\n" ++ "\tCMDAT\t= 0x%08X\n" ++ "\tRESTO\t= 0x%08X\n" ++ "\tRDTO\t= 0x%08X\n" ++ "\tBLKLEN\t= 0x%08X\n" ++ "\tNOB\t= 0x%08X\n" ++ "\tSNOB\t= 0x%08X\n" ++ "\tIMASK\t= 0x%08X\n" ++ "\tIFLG\t= 0x%08X\n" ++ "\tCMD\t= 0x%08X\n" ++ "\tARG\t= 0x%08X\n" ++ "\tRES\t= 0x%08X\n" ++ "\tLPM\t= 0x%08X\n" ++ "\tDMAC\t= 0x%08X\n" ++ "\tDMANDA\t= 0x%08X\n" ++ "\tDMADA\t= 0x%08X\n" ++ "\tDMALEN\t= 0x%08X\n" ++ "\tDMACMD\t= 0x%08X\n" ++ "\tRTCNT\t= 0x%08X\n" ++ "\tDEBUG\t= 0x%08X\n", ++ ++ msc_readl(host, CTRL2), ++ msc_readl(host, STAT), ++ msc_readl(host, CLKRT), ++ msc_readl(host, CMDAT), ++ msc_readl(host, RESTO), ++ msc_readl(host, RDTO), ++ msc_readl(host, BLKLEN), ++ msc_readl(host, NOB), ++ msc_readl(host, SNOB), ++ msc_readl(host, IMASK), ++ msc_readl(host, IFLG), ++ msc_readl(host, CMD), ++ msc_readl(host, ARG), ++ msc_readl(host, RES), ++ msc_readl(host, LPM), ++ msc_readl(host, DMAC), ++ msc_readl(host, DMANDA), ++ msc_readl(host, DMADA), ++ msc_readl(host, DMALEN), ++ msc_readl(host, DMACMD), ++ msc_readl(host, RTCNT), ++ msc_readl(host, DEBUG)); ++} ++#endif ++ ++/* ++ * Functional functions. ++ * ++ * These small function will be called frequently. ++ */ ++static inline void enable_msc_irq(struct ingenic_mmc_host *host, unsigned long bits) ++{ ++ unsigned long imsk; ++ ++ spin_lock_bh(&host->lock); ++ imsk = msc_readl(host, IMASK); ++ imsk &= ~bits; ++ msc_writel(host, IMASK, imsk); ++ spin_unlock_bh(&host->lock); ++} ++ ++static inline void clear_msc_irq(struct ingenic_mmc_host *host, unsigned long bits) ++{ ++ msc_writel(host, IFLG, bits); ++} ++ ++static inline void disable_msc_irq(struct ingenic_mmc_host *host, unsigned long bits) ++{ ++ unsigned long imsk; ++ ++ spin_lock_bh(&host->lock); ++ imsk = msc_readl(host, IMASK); ++ imsk |= bits; ++ msc_writel(host, IMASK, imsk); ++ spin_unlock_bh(&host->lock); ++} ++ ++static inline void ingenic_mmc_reset(struct ingenic_mmc_host *host) ++{ ++ unsigned int clkrt = msc_readl(host, CLKRT); ++ unsigned int cnt = 100 * 1000 * 1000; ++ int vl; ++ ++ msc_writel(host, CTRL, CTRL_RESET); ++ vl = msc_readl(host,CTRL); ++ vl &= ~CTRL_RESET; ++ msc_writel(host, CTRL, vl); ++ ++ while ((msc_readl(host, STAT) & STAT_IS_RESETTING) && (--cnt)); ++ WARN_ON(!cnt); ++ ++ if(host->pdata->sdio_clk) ++ msc_writel(host, CTRL, CTRL_CLOCK_START); ++ else ++ msc_writel(host, LPM, LPM_LPM); ++ ++ msc_writel(host, IMASK, 0xffffffff); ++ msc_writel(host, IFLG, 0xffffffff); ++ ++ msc_writel(host, CLKRT, clkrt); ++} ++ ++static inline void ingenic_mmc_stop_dma(struct ingenic_mmc_host *host) ++{ ++ dev_warn(host->dev, "%s\n", __func__); ++ ++ /* ++ * Theoretically, DMA can't be stopped when transfering, so we can only ++ * diable it when it is out of DMA request. ++ */ ++ msc_writel(host, DMAC, 0); ++} ++ ++static inline int request_need_stop(struct mmc_request *mrq) ++{ ++ return mrq->stop ? 1 : 0; ++} ++static inline void ingenic_mmc_clk_onoff(struct ingenic_mmc_host *host, unsigned int on) ++{ ++ if(on) { ++ clk_prepare_enable(host->clk_cgu); ++ clk_prepare_enable(host->clk_gate); ++ } else { ++ clk_disable_unprepare(host->clk_cgu); ++ clk_disable_unprepare(host->clk_gate); ++ } ++} ++static inline int check_error_status(struct ingenic_mmc_host *host, unsigned int status) ++{ ++ if (status & ERROR_STAT) { ++ dev_err(host->dev, "Error status->0x%08X: cmd=%d, state=%d\n", ++ status, host->cmd->opcode, host->state); ++ return -1; ++ } ++ return 0; ++} ++ ++static int ingenic_mmc_polling_status(struct ingenic_mmc_host *host, unsigned int status) ++{ ++ unsigned int cnt = 100 * 1000 * 1000; ++ while(!(msc_readl(host, STAT) & (status | ERROR_STAT)) \ ++ && test_bit(INGENIC_MMC_CARD_PRESENT, &host->flags) && (--cnt)); ++ ++ if (unlikely(!cnt)) { ++ dev_err(host->dev, "polling status(0x%08X) time out, " ++ "op=%d, status=0x%08X\n", status, ++ host->cmd->opcode, msc_readl(host, STAT)); ++ return -1; ++ } ++ if (unlikely(!test_bit(INGENIC_MMC_CARD_PRESENT, &host->flags))) { ++ dev_err(host->dev, "card remove while polling" ++ "status(0x%08X), op=%d\n", status, host->cmd->opcode); ++ return -1; ++ } ++ if (msc_readl(host, STAT) & ERROR_STAT) { ++ dev_err(host->dev, "polling status(0x%08X) error, " ++ "op=%d, status=0x%08X\n", status, ++ host->cmd->opcode, msc_readl(host, STAT)); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static void send_stop_command(struct ingenic_mmc_host *host) ++{ ++ struct mmc_command *stop_cmd = host->mrq->stop; ++ ++ msc_writel(host, CMD, stop_cmd->opcode); ++ msc_writel(host, ARG, stop_cmd->arg); ++ msc_writel(host, CMDAT, CMDAT_BUSY | CMDAT_RESPONSE_R1); ++ msc_writel(host, RESTO, 0xff); ++ msc_writel(host, CTRL, CTRL_START_OP); ++ ++ if (ingenic_mmc_polling_status(host, STAT_END_CMD_RES)) ++ stop_cmd->error = -EIO; ++} ++static void ingenic_mmc_command_done(struct ingenic_mmc_host *host, struct mmc_command *cmd) ++{ ++ unsigned long res; ++ ++ if ((host->cmdat & CMDAT_RESPONSE_MASK) == CMDAT_RESPONSE_R2) { ++ int i; ++ res = msc_readl(host, RES); ++ for (i = 0 ; i < 4 ; i++) { ++ cmd->resp[i] = res << 24; ++ res = msc_readl(host, RES); ++ cmd->resp[i] |= res << 8; ++ res = msc_readl(host, RES); ++ cmd->resp[i] |= res >> 8; ++ } ++ } else { ++ res = msc_readl(host, RES); ++ cmd->resp[0] = res << 24; ++ res = msc_readl(host, RES); ++ cmd->resp[0] |= res << 8; ++ res = msc_readl(host, RES); ++ cmd->resp[0] |= res & 0xff; ++ } ++ ++ clear_msc_irq(host, IFLG_END_CMD_RES); ++} ++ ++static void ingenic_mmc_data_done(struct ingenic_mmc_host *host) ++{ ++ struct mmc_data *data = host->data; ++ ++ if (data->error == 0) ++ data->bytes_xfered = (data->blocks * data->blksz); ++ else { ++ ingenic_mmc_stop_dma(host); ++ data->bytes_xfered = 0; ++ dev_err(host->dev, "error when request done\n"); ++ } ++ ++ del_timer_sync(&host->request_timer); ++ mmc_request_done(host->mmc, host->mrq); ++} ++ ++/*------------------------End functional functions-------------------------*/ ++ ++/* ++ * State machine. ++ * ++ * The state machine is the manager of the mmc_request. It's triggered by ++ * MSC interrupt and work in interrupt context. ++ */ ++static void ingenic_mmc_state_machine(struct ingenic_mmc_host *host, unsigned int status) ++{ ++ struct mmc_request *mrq = host->mrq; ++ struct mmc_data *data = host->data; ++ ++ WARN_ON(host->double_enter++); ++start: ++ dev_dbg(host->dev, "enter state: %d\n", host->state); ++ ++ switch (host->state) { ++ case STATE_IDLE: ++ dev_warn(host->dev, "WARN: enter state machine with IDLE\n"); ++ break; ++ ++ case STATE_WAITING_RESP: ++ if (!ingenic_mmc_check_pending(host, EVENT_CMD_COMPLETE)) ++ break; ++ if (unlikely(check_error_status(host, status) != 0)) { ++ host->state = STATE_ERROR; ++ clear_msc_irq(host, IFLG_CRC_RES_ERR ++ | IFLG_TIMEOUT_RES ++ | IFLG_END_CMD_RES); ++ goto start; ++ } ++ ingenic_mmc_command_done(host, mrq->cmd); ++ if (!data) { ++ host->state = STATE_IDLE; ++ del_timer_sync(&host->request_timer); ++ mmc_request_done(host->mmc, host->mrq); ++ break; ++ } ++ host->state = STATE_WAITING_DATA; ++ break; ++ ++ case STATE_WAITING_DATA: ++ if (!ingenic_mmc_check_pending(host, EVENT_DATA_COMPLETE)) ++ break; ++ if (unlikely(check_error_status(host, status) != 0)) { ++ clear_msc_irq(host, IFLG_DATA_TRAN_DONE ++ | IFLG_CRC_READ_ERR ++ | IFLG_CRC_WRITE_ERR ++ | IFLG_TIMEOUT_READ); ++ if (request_need_stop(host->mrq)) ++ send_stop_command(host); ++ host->state = STATE_ERROR; ++ goto start; ++ } ++ ++ if (request_need_stop(host->mrq)) { ++ if (likely(msc_readl(host, STAT) & STAT_AUTO_CMD12_DONE)) { ++ disable_msc_irq(host, IMASK_AUTO_CMD12_DONE); ++ clear_msc_irq(host, IFLG_AUTO_CMD12_DONE); ++ host->state = STATE_IDLE; ++ ingenic_mmc_data_done(host); ++ } else { ++ enable_msc_irq(host, IMASK_AUTO_CMD12_DONE); ++ if (msc_readl(host, STAT) & STAT_AUTO_CMD12_DONE) { ++ disable_msc_irq(host, IMASK_AUTO_CMD12_DONE); ++ clear_msc_irq(host, IFLG_AUTO_CMD12_DONE); ++ host->state = STATE_IDLE; ++ ingenic_mmc_data_done(host); ++ } else ++ host->state = STATE_SENDING_STOP; ++ } ++ } else { ++ host->state = STATE_IDLE; ++ ingenic_mmc_data_done(host); ++ } ++ break; ++ ++ case STATE_SENDING_STOP: ++ if (!ingenic_mmc_check_pending(host, EVENT_STOP_COMPLETE)) ++ break; ++ host->state = STATE_IDLE; ++ ingenic_mmc_data_done(host); ++ break; ++ ++ case STATE_ERROR: ++ if (host->state == STATE_WAITING_DATA) ++ host->data->error = -1; ++ host->cmd->error = -1; ++ ++ if (data) { ++ data->bytes_xfered = 0; ++ /* Whether should we stop DMA here? */ ++ } ++ del_timer_sync(&host->request_timer); ++ host->state = STATE_IDLE; ++ mmc_request_done(host->mmc, host->mrq); ++ break; ++ } ++ ++ dev_dbg(host->dev, "exit state: %d\n", host->state); ++ host->double_enter--; ++} ++ ++static irqreturn_t ingenic_mmc_thread_handle(int irq, void *dev_id) ++{ ++ struct ingenic_mmc_host *host = (struct ingenic_mmc_host *)dev_id; ++ unsigned int iflg, imask, pending, status; ++ ++start: ++ iflg = msc_readl(host, IFLG); ++ imask = msc_readl(host, IMASK); ++ pending = iflg & ~imask; ++ status = msc_readl(host, STAT); ++ dev_dbg(host->dev, "%s: iflg-0x%08X imask-0x%08X status-0x%08X\n", ++ __func__, iflg, imask, status); ++ ++ if (!pending) { ++ goto out; ++ } else if (pending & IFLG_SDIO) { ++ mmc_signal_sdio_irq(host->mmc); ++ goto out; ++ } else if (pending & ERROR_IFLG) { ++ unsigned int mask = ERROR_IFLG; ++ ++ dev_dbg(host->dev, "%s: iflg-0x%08X imask-0x%08X status-0x%08X\n", ++ __func__, iflg, imask, status); ++ ++ dev_dbg(host->dev, "err%d cmd%d iflg%08X status%08X\n", ++ host->state, host->cmd ? host->cmd->opcode : -1, iflg, status); ++ ++ if (host->state == STATE_WAITING_RESP) ++ mask |= IMASK_END_CMD_RES; ++ else if (host->state == STATE_WAITING_DATA) ++ mask |= IMASK_WR_ALL_DONE | IMASK_DMA_DATA_DONE; ++ ++ clear_msc_irq(host, mask); ++ disable_msc_irq(host, mask); ++ ++ /* ++ * It seems that cmd53 CRC error occurs frequently ++ * at 50mHz clk, but it disappear at 40mHz. In case of ++ * it happens, we add retry here to try to fix the error. ++ */ ++ if ((host->cmd->opcode == 53) ++ && (status & STAT_CRC_READ_ERROR)) { ++ dev_err(host->dev, "cmd53 crc error, retry.\n"); ++ host->cmd->error = -1; ++ host->cmd->retries = 1; ++ host->data->bytes_xfered = 0; ++ del_timer_sync(&host->request_timer); ++ host->state = STATE_IDLE; ++ mmc_request_done(host->mmc, host->mrq); ++ goto out; ++ } ++ host->state = STATE_ERROR; ++ ingenic_mmc_state_machine(host, status); ++ goto out; ++ ++ } else if (pending & IFLG_END_CMD_RES) { ++ ingenic_mmc_set_pending(host, EVENT_CMD_COMPLETE); ++ disable_msc_irq(host, IMASK_END_CMD_RES | \ ++ IMASK_CRC_RES_ERR | IMASK_TIME_OUT_RES); ++ ingenic_mmc_state_machine(host, status); ++ } else if (pending & IFLG_WR_ALL_DONE) { ++ ingenic_mmc_set_pending(host, EVENT_DATA_COMPLETE); ++ clear_msc_irq(host, IFLG_WR_ALL_DONE ++ | IFLG_DMAEND ++ | IFLG_DATA_TRAN_DONE ++ | IFLG_PRG_DONE); ++ disable_msc_irq(host, IMASK_WR_ALL_DONE | IMASK_CRC_WRITE_ERR); ++ ingenic_mmc_state_machine(host, status); ++ ++ } else if (pending & IFLG_DMA_DATA_DONE) { ++ ingenic_mmc_set_pending(host, EVENT_DATA_COMPLETE); ++ clear_msc_irq(host, IFLG_DATA_TRAN_DONE | IFLG_DMAEND | ++ IFLG_DMA_DATA_DONE); ++ disable_msc_irq(host, IMASK_DMA_DATA_DONE | IMASK_CRC_READ_ERR); ++ ingenic_mmc_state_machine(host, status); ++ } else if (pending & IFLG_AUTO_CMD12_DONE) { ++ ingenic_mmc_set_pending(host, EVENT_STOP_COMPLETE); ++ clear_msc_irq(host, IFLG_AUTO_CMD12_DONE); ++ disable_msc_irq(host, IMASK_AUTO_CMD12_DONE); ++ ingenic_mmc_state_machine(host, status); ++ ++ } else ++ dev_warn(host->dev, "state-%d: Nothing happens?!\n", host->state); ++ ++ /* ++ * Check if the status has already changed. If so, goto start so that ++ * we can avoid an interrupt. ++ */ ++ if (status != msc_readl(host, STAT)) { ++ goto start; ++ } ++ ++out: ++ return IRQ_HANDLED; ++} ++/*--------------------------End state machine------------------------------*/ ++ ++/* ++ * DMA handler. ++ * ++ * Descriptor DMA transfer that can handle scatter gather list directly ++ * without bounce buffer which may cause a big deal of memcpy. ++ */ ++static inline void sg_to_desc(struct scatterlist *sgentry, struct desc_hd *dhd) ++{ ++ dhd->dma_desc->da = sg_phys(sgentry); ++ dhd->dma_desc->len = sg_dma_len(sgentry); ++ dhd->dma_desc->dcmd = DMACMD_LINK; ++} ++ ++static void ingenic_mmc_submit_dma(struct ingenic_mmc_host *host, struct mmc_data *data) ++{ ++ int i = 0; ++ struct scatterlist *sgentry; ++ struct desc_hd *dhd = &(host->decshds[0]); ++ ++ dma_map_sg(host->dev, data->sg, data->sg_len, ++ data->flags & MMC_DATA_WRITE ++ ? DMA_TO_DEVICE : DMA_FROM_DEVICE); ++ ++ for_each_sg(data->sg, sgentry, data->sg_len, i) { ++ sg_to_desc(sgentry, dhd); ++ if ((data->sg_len - i) > 1) { ++ if (unlikely(dhd->next == NULL)) ++ dev_err(host->dev, "dhd->next == NULL\n"); ++ else { ++ dhd->dma_desc->nda = dhd->next->dma_desc_phys_addr; ++ dhd = dhd->next; ++ } ++ } ++ } ++ ++ dma_unmap_sg(host->dev, data->sg, data->sg_len, ++ data->flags & MMC_DATA_WRITE ++ ? DMA_TO_DEVICE : DMA_FROM_DEVICE); ++ ++ dhd->dma_desc->dcmd |= DMACMD_ENDI; ++ dhd->dma_desc->dcmd &= ~DMACMD_LINK; ++} ++ ++static inline unsigned int get_incr(unsigned int dma_len) ++{ ++ unsigned int incr = 0; ++ ++ BUG_ON(!dma_len); ++#if 0 ++ /* ++ * BUG here! ++ */ ++ switch (dma_len) { ++#define _CASE(S,D) case S: incr = D; break ++ _CASE(1 ... 31, 0); ++ _CASE(32 ... 63, 1); ++ default: ++ incr = 2; ++ break; ++#undef _CASE ++ } ++#else ++ incr = 2; ++#endif ++ return incr; ++} ++ ++/* #define PERFORMANCE_DMA */ ++static inline void ingenic_mmc_dma_start(struct ingenic_mmc_host *host, struct mmc_data *data) ++{ ++ dma_addr_t dma_addr = sg_phys(data->sg); ++ unsigned int dma_len = sg_dma_len(data->sg); ++ unsigned int dmac; ++ ++#ifdef PERFORMANCE_DMA ++ dmac = (get_incr(dma_len) << DMAC_INCR_SHF) | DMAC_DMAEN | DMAC_MODE_SEL; ++#else ++ dmac = (get_incr(dma_len) << DMAC_INCR_SHF) | DMAC_DMAEN; ++#endif ++ ++ if ((dma_addr & 0x3) || (dma_len & 0x3)) { ++ dmac |= DMAC_ALIGNEN; ++ if (dma_addr & 0x3) ++ dmac |= (dma_addr % 4) << DMAC_AOFST_SHF; ++ } ++ msc_writel(host, DMANDA, host->decshds[0].dma_desc_phys_addr); ++ msc_writel(host, DMAC, dmac); ++} ++ ++/*----------------------------End DMA handler------------------------------*/ ++ ++/* ++ * PIO transfer mode. ++ * ++ * Functions of PIO read/write mode that can handle 1, 2 or 3 bytes transfer ++ * even though the FIFO register is 32-bits width. ++ * It's better just used for test. ++ */ ++static int wait_cmd_response(struct ingenic_mmc_host *host) ++{ ++ if (ingenic_mmc_polling_status(host, STAT_END_CMD_RES) < 0) { ++ dev_err(host->dev, "PIO mode: command response error\n"); ++ return -1; ++ } ++ msc_writel(host, IFLG, IFLG_END_CMD_RES); ++ return 0; ++} ++ ++static void do_pio_read(struct ingenic_mmc_host *host, ++ unsigned int *addr, unsigned int cnt) ++{ ++ int i = 0; ++ unsigned int status = 0; ++ ++ for (i = 0; i < cnt / 4; i++) { ++ while (((status = msc_readl(host, STAT)) ++ & STAT_DATA_FIFO_EMPTY) ++ && test_bit(INGENIC_MMC_CARD_PRESENT, &host->flags)); ++ ++ if (!test_bit(INGENIC_MMC_CARD_PRESENT, &host->flags)) { ++ host->data->error = -ENOMEDIUM; ++ dev_err(host->dev, ++ "PIO mode: card remove while reading\n"); ++ return; ++ } ++ if (check_error_status(host, status)) { ++ host->data->error = -1; ++ return; ++ } ++ *addr++ = msc_readl(host, RXFIFO); ++ } ++ ++ /* ++ * These codes handle the last 1, 2 or 3 bytes transfer. ++ */ ++ if (cnt & 3) { ++ u32 n = cnt & 3; ++ u32 data = msc_readl(host, RXFIFO); ++ u8 *p = (u8 *)addr; ++ ++ while (n--) { ++ *p++ = data; ++ data >>= 8; ++ } ++ } ++} ++ ++static void do_pio_write(struct ingenic_mmc_host *host, ++ unsigned int *addr, unsigned int cnt) ++{ ++ int i = 0; ++ unsigned int status = 0; ++ ++ for (i = 0; i < (cnt / 4); i++) { ++ while (((status = msc_readl(host, STAT)) ++ & STAT_DATA_FIFO_FULL) ++ && test_bit(INGENIC_MMC_CARD_PRESENT, &host->flags)); ++ ++ if(!test_bit(INGENIC_MMC_CARD_PRESENT, &host->flags)) { ++ host->data->error = -ENOMEDIUM; ++ dev_err(host->dev, ++ "PIO mode: card remove while writing\n"); ++ break; ++ } ++ if (check_error_status(host, status)) { ++ host->data->error = -1; ++ return; ++ } ++ msc_writel(host, TXFIFO, *addr++); ++ } ++ ++ /* ++ * These codes handle the last 1, 2 or 3 bytes transfer. ++ */ ++ if (cnt & 3) { ++ u32 data = 0; ++ u8 *p = (u8 *)addr; ++ ++ for (i = 0; i < (cnt & 3); i++) ++ data |= *p++ << (8 * i); ++ ++ msc_writel(host, TXFIFO, data); ++ } ++} ++ ++static inline void pio_trans_start(struct ingenic_mmc_host *host, struct mmc_data *data) ++{ ++ unsigned int *addr = sg_virt(data->sg); ++ unsigned int cnt = sg_dma_len(data->sg); ++ ++ if (data->flags & MMC_DATA_WRITE) ++ do_pio_write(host, addr, cnt); ++ else ++ do_pio_read(host, addr, cnt); ++} ++ ++static void pio_trans_done(struct ingenic_mmc_host *host, struct mmc_data *data) ++{ ++ if (data->error == 0) ++ data->bytes_xfered = data->blocks * data->blksz; ++ else ++ data->bytes_xfered = 0; ++ ++ if (host->mrq->stop) { ++ if (ingenic_mmc_polling_status(host, STAT_AUTO_CMD12_DONE) < 0) ++ data->error = -EIO; ++ } ++ ++ if (data->flags & MMC_DATA_WRITE) { ++ if (ingenic_mmc_polling_status(host, STAT_PRG_DONE) < 0) { ++ data->error = -EIO; ++ } ++ clear_msc_irq(host, IFLG_PRG_DONE); ++ } else { ++ if (ingenic_mmc_polling_status(host, STAT_DATA_TRAN_DONE) < 0) { ++ data->error = -EIO; ++ } ++ clear_msc_irq(host, IFLG_DATA_TRAN_DONE); ++ } ++} ++ ++/*-------------------------End PIO transfer mode---------------------------*/ ++ ++/* ++ * Achieve mmc_request here. ++ */ ++static void ingenic_mmc_data_pre(struct ingenic_mmc_host *host, struct mmc_data *data) ++{ ++ unsigned int nob = data->blocks; ++ unsigned long cmdat,imsk; ++ ++ msc_writel(host, RDTO, 0xffffff); ++ msc_writel(host, NOB, nob); ++ msc_writel(host, BLKLEN, data->blksz); ++ cmdat = CMDAT_DATA_EN; ++ ++ msc_writel(host, CMDAT, CMDAT_DATA_EN); ++ ++ ++ if (data->flags & MMC_DATA_WRITE) { ++ cmdat |= CMDAT_WRITE_READ; ++ imsk = IMASK_WR_ALL_DONE | IMASK_CRC_WRITE_ERR; ++ } else if (data->flags & MMC_DATA_READ) { ++ cmdat &= ~CMDAT_WRITE_READ; ++ imsk = IMASK_DMA_DATA_DONE ++ | IMASK_TIME_OUT_READ ++ | IMASK_CRC_READ_ERR; ++ } else { ++ dev_err(host->dev, "data direction confused\n"); ++ BUG_ON(1); ++ } ++ host->cmdat |= cmdat; ++ ++ if (!is_pio_mode(host)) { ++ ingenic_mmc_submit_dma(host, data); ++ clear_msc_irq(host, IFLG_PRG_DONE); ++ enable_msc_irq(host, imsk); ++ } ++} ++ ++static void ingenic_mmc_data_start(struct ingenic_mmc_host *host, struct mmc_data *data) ++{ ++ if (is_pio_mode(host)) { ++ pio_trans_start(host, data); ++ pio_trans_done(host, data); ++ del_timer_sync(&host->request_timer); ++ if (!(host->pdata->pio_mode)) ++ disable_pio_mode(host); ++ mmc_request_done(host->mmc, host->mrq); ++ } else { ++ ingenic_mmc_dma_start(host, data); ++ } ++} ++ ++static void ingenic_mmc_command_start(struct ingenic_mmc_host *host, struct mmc_command *cmd) ++{ ++ unsigned long cmdat = 0; ++ unsigned long imsk; ++ ++ if (cmd->flags & MMC_RSP_BUSY) ++ cmdat |= CMDAT_BUSY; ++ if (request_need_stop(host->mrq)) ++ cmdat |= CMDAT_AUTO_CMD12; ++ ++ ++ switch (mmc_resp_type(cmd)) { ++#define _CASE(S,D) case MMC_RSP_##S: cmdat |= CMDAT_RESPONSE_##D; break ++ _CASE(R1, R1); /* r1 = r5,r6,r7 */ ++ _CASE(R1B, R1); ++ _CASE(R2, R2); ++ _CASE(R3, R3); /* r3 = r4 */ ++ default: ++ break; ++#undef _CASE ++ } ++ host->cmdat |= cmdat; ++ if (!is_pio_mode(host)) { ++ imsk = IMASK_TIME_OUT_RES | IMASK_END_CMD_RES; ++ enable_msc_irq(host, imsk); ++ host->state = STATE_WAITING_RESP; ++ } ++ msc_writel(host, CMD, cmd->opcode); ++ msc_writel(host, ARG, cmd->arg); ++ msc_writel(host, CMDAT, host->cmdat); ++ msc_writel(host, CTRL, CTRL_START_OP); ++ if (is_pio_mode(host)) { ++ if (wait_cmd_response(host) < 0) { ++ cmd->error = -ETIMEDOUT; ++ del_timer_sync(&host->request_timer); ++ mmc_request_done(host->mmc, host->mrq); ++ return; ++ } ++ ingenic_mmc_command_done(host, host->cmd); ++ if (!host->data) { ++ del_timer_sync(&host->request_timer); ++ mmc_request_done(host->mmc, host->mrq); ++ } ++ } ++} ++ ++static void ingenic_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) ++{ ++ struct ingenic_mmc_host *host = mmc_priv(mmc); ++ if (!test_bit(INGENIC_MMC_CARD_PRESENT, &host->flags)) { ++ dev_vdbg(host->dev, "No card present\n"); ++ mrq->cmd->error = -ENOMEDIUM; ++ mmc_request_done(mmc, mrq); ++ return; ++ } ++ ++ /* ++ * It means that this request may flush cache in interrupt context. ++ * It never happens in design, but we add BUG_ON here to prevent it. ++ */ ++ if ((host->state != STATE_IDLE) && (mrq->data != NULL)) { ++ dev_warn(host->dev, "operate in non-idle state\n"); ++ WARN_ON(1); ++ } ++ ++ host->mrq = mrq; ++ host->data = mrq->data; ++ host->cmd = mrq->cmd; ++ if (host->data) ++ dev_dbg(host->dev, "op:%d arg:0x%08X sz:%uk\n", ++ host->cmd->opcode, host->cmd->arg, ++ host->data->blocks >> 1); ++ else ++ dev_dbg(host->dev, "op:%d\n", host->cmd->opcode); ++ ++ host->cmdat = host->cmdat_def; ++ if(host->data) { ++ if ((host->data->sg_len == 1) ++ && (sg_dma_len(host->data->sg)) < PIO_THRESHOLD) { ++ enable_pio_mode(host); ++ } ++ ++ ingenic_mmc_data_pre(host, host->data); ++ } ++ /* ++ * We would get mmc_request_done at last, unless some terrible error ++ * occurs such as intensity rebounding of VDD, that maybe result in ++ * no action to complete the request. ++ */ ++ host->timeout_cnt = 0; ++ mod_timer(&host->request_timer, jiffies + ++ msecs_to_jiffies(TIMEOUT_PERIOD)); ++ ingenic_mmc_command_start(host, host->cmd); ++ if (host->data) { ++ ingenic_mmc_data_start(host, host->data); ++ ++ } ++ if (unlikely(test_and_clear_bit(INGENIC_MMC_CARD_NEED_INIT, &host->flags))) ++ host->cmdat_def &= ~CMDAT_INIT; ++} ++ ++static void ingenic_mmc_request_timeout(unsigned long data) ++{ ++ struct ingenic_mmc_host *host = (struct ingenic_mmc_host *)data; ++ unsigned int status = msc_readl(host, STAT); ++ if (host->timeout_cnt++ < (3000 / TIMEOUT_PERIOD)) { ++ dev_warn(host->dev, "timeout %dms op:%d %s sz:%d state:%d " ++ "STAT:0x%08X DMALEN:0x%08X blks:%d/%d clk:%s\n", ++ host->timeout_cnt * TIMEOUT_PERIOD, ++ host->cmd->opcode, ++ host->data ++ ? (host->data->flags & MMC_DATA_WRITE ? "w" : "r") ++ : "", ++ host->data ? host->data->blocks << 9 : 0, ++ host->state, ++ status, ++ msc_readl(host, DMALEN), ++ msc_readl(host, SNOB), ++ msc_readl(host, NOB), ++ __clk_is_enabled(host->clk_cgu) ? "enable" : "disable"); ++ mod_timer(&host->request_timer, jiffies + ++ msecs_to_jiffies(TIMEOUT_PERIOD)); ++ return; ++ ++ } else if (host->timeout_cnt++ < (60000 / TIMEOUT_PERIOD)) { ++ mod_timer(&host->request_timer, jiffies + ++ msecs_to_jiffies(TIMEOUT_PERIOD)); ++ return; ++ } ++ ++ dev_err(host->dev, "request time out, op=%d arg=0x%08X, " ++ "sz:%dB state=%d, status=0x%08X, pending=0x%08X, nr_desc=%d\n", ++ host->cmd->opcode, host->cmd->arg, ++ host->data ? host->data->blocks << 9 : -1, ++ host->state, status, (u32)host->pending_events, ++ host->data ? host->data->sg_len : 0); ++ ingenic_mmc_dump_reg(host); ++ ++ if (host->data) { ++ int i; ++ dev_err(host->dev, "Descriptor dump:\n"); ++ for (i = 0; i < MAX_SEGS; i++) { ++ unsigned int *desc = (unsigned int *)host->decshds[i].dma_desc; ++ dev_err(host->dev, "\t%03d\t nda=%08X da=%08X len=%08X dcmd=%08X\n", ++ i, *desc, *(desc+1), *(desc+2), *(desc+3)); ++ } ++ dev_err(host->dev, "\n"); ++ } ++ ++ if (host->mrq) { ++ if (request_need_stop(host->mrq)) { ++ send_stop_command(host); ++ } ++ host->cmd->error = -ENOMEDIUM; ++ host->state = STATE_IDLE; ++ mmc_request_done(host->mmc, host->mrq); ++ } ++} ++ ++/*---------------------------End mmc_request-------------------------------*/ ++ ++/* ++ * Card insert and remove handler. ++ */ ++static irqreturn_t ingenic_mmc_detect_handler(int irq, void *dev_id) ++{ ++ struct ingenic_mmc_host *host = (struct ingenic_mmc_host *)dev_id; ++ ++ disable_irq_nosync(irq); ++ mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(200)); ++ ++ return IRQ_HANDLED; ++} ++ ++static int get_pin_status(struct ingenic_mmc_pin *pin) ++{ ++ int val; ++ ++ if(!gpio_is_valid(pin->num)) { ++ return -1; ++ } ++ val = gpio_get_value(pin->num); ++ ++ if (pin->enable_level == LOW_ENABLE) ++ return !val; ++ return val; ++} ++ ++static void set_pin_status(struct ingenic_mmc_pin *pin, int enable) ++{ ++ if(gpio_is_valid(pin->num)) { ++ return; ++ } ++ ++ if (pin->enable_level == LOW_ENABLE) ++ enable = !enable; ++ gpio_set_value(pin->num, enable); ++} ++ ++static void ingenic_mmc_detect(unsigned long data) ++{ ++ struct ingenic_mmc_host *host = (struct ingenic_mmc_host *)data; ++ bool present; ++ bool present_old; ++ static int irq_disable_count; ++ ++ present = get_pin_status(&host->pdata->gpio->cd); ++ present_old = test_bit(INGENIC_MMC_CARD_PRESENT, &host->flags); ++ ++ if ((present != present_old) || (present_old && host->mmc->card)) { ++ if (present && present_old) ++ dev_warn(host->dev, "rapidly remove\n"); ++ else ++ dev_notice(host->dev, "card %s, state=%d\n", ++ present ? "inserted" : "removed", host->state); ++ ++ if (!present || present_old) { ++ clear_bit(INGENIC_MMC_CARD_PRESENT, &host->flags); ++ if(!irq_disable_count) { ++ disable_irq_nosync(host->irq); ++ irq_disable_count = 1; ++ } ++ ingenic_mmc_reset(host); ++ ++ if (host->mrq && (host->state > STATE_IDLE)) { ++ host->cmd->error = -ENOMEDIUM; ++ if (host->data) { ++ host->data->bytes_xfered = 0; ++ ingenic_mmc_stop_dma(host); ++ } ++ del_timer_sync(&host->request_timer); ++ mmc_request_done(host->mmc, host->mrq); ++ host->state = STATE_IDLE; ++ } ++ mmc_detect_change(host->mmc, 0); ++ } else { ++ if(irq_disable_count) { ++ enable_irq(host->irq); ++ irq_disable_count = 0; ++ } ++ set_bit(INGENIC_MMC_CARD_PRESENT, &host->flags); ++ /* ++ * spin_lock() here may case recursion, ++ * so discard the clk operation. ++ */ ++ ingenic_mmc_clk_onoff(host, 1); ++ mmc_detect_change(host->mmc, msecs_to_jiffies(1000)); ++ } ++ ++ if (!test_bit(INGENIC_MMC_CARD_PRESENT, &host->flags)) { ++ ingenic_mmc_clk_onoff(host, 0); ++ } ++ } ++ ++ enable_irq(gpio_to_irq(host->pdata->gpio->cd.num)); ++} ++ ++/** ++ * ingenic_mmc_manual_detect - insert or remove card manually ++ * @index: host->index, namely the index of the controller. ++ * @on: 1 means insert card, 0 means remove card. ++ * ++ * This functions will be called by manually card-detect driver such as ++ * wifi. To enable this mode you can set value pdata.removal = MANUAL. ++ */ ++int ingenic_mmc_manual_detect(int index, int on) ++{ ++ struct ingenic_mmc_host *host; ++ struct list_head *pos; ++ ++ list_for_each(pos, &manual_list) { ++ host = list_entry(pos, struct ingenic_mmc_host, list); ++ if (host->index == index) ++ break; ++ else ++ host = NULL; ++ } ++ ++ if(!host) { ++ printk("no manual card detect\n"); ++ return -1; ++ } ++ ++ if (on) { ++ dev_vdbg(host->dev, "card insert manually\n"); ++ set_bit(INGENIC_MMC_CARD_PRESENT, &host->flags); ++#ifdef CLK_CTRL ++ ingenic_mmc_clk_onoff(host, 1); ++#endif ++ mmc_detect_change(host->mmc, 0); ++ } else { ++ dev_vdbg(host->dev, "card remove manually\n"); ++ clear_bit(INGENIC_MMC_CARD_PRESENT, &host->flags); ++ mmc_detect_change(host->mmc, 0); ++#ifdef CLK_CTRL ++ ingenic_mmc_clk_onoff(host, 0); ++#endif ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(ingenic_mmc_manual_detect); ++ ++/** ++ * ingenic_mmc_clk_ctrl - enable or disable msc clock gate ++ * @index: host->index, namely the index of the controller. ++ * @on: 1-enable msc clock gate, 0-disable msc clock gate. ++ */ ++int ingenic_mmc_clk_ctrl(int index, int on) ++{ ++ struct ingenic_mmc_host *host; ++ struct list_head *pos; ++ ++#ifdef CLK_CTRL ++ list_for_each(pos, &manual_list) { ++ host = list_entry(pos, struct ingenic_mmc_host, list); ++ if (host->index == index) ++ break; ++ else ++ host = NULL; ++ } ++ ++ if (!host) { ++ printk("no manual card detect\n"); ++ return -1; ++ } ++ ingenic_mmc_clk_onoff(host, on); ++#endif ++ return 0; ++} ++EXPORT_SYMBOL(ingenic_mmc_clk_ctrl); ++ ++/*-------------------End card insert and remove handler--------------------*/ ++ ++/* ++ * Other mmc_ops except request. ++ */ ++static inline void ingenic_mmc_power_on(struct ingenic_mmc_host *host) ++{ ++ dev_vdbg(host->dev, "power_on\n"); ++ ++ if (!IS_ERR(host->power)) { ++ /* if(!regulator_is_enabled(host->power)) */ ++ /* regulator_enable(host->power); */ ++ ++ } else if (host->pdata->gpio) { ++ set_pin_status(&host->pdata->gpio->pwr, 1); ++ } ++} ++ ++static inline void ingenic_mmc_power_off(struct ingenic_mmc_host *host) ++{ ++ dev_vdbg(host->dev, "power_off\n"); ++ ++ if (!IS_ERR(host->power)) { ++ /* if(regulator_is_enabled(host->power)) */ ++ /* regulator_disable(host->power); */ ++ ++ } else if (host->pdata->gpio) { ++ set_pin_status(&host->pdata->gpio->pwr, 0); ++ } ++} ++ ++static int ingenic_mmc_get_read_only(struct mmc_host *mmc) ++{ ++ struct ingenic_mmc_host *host = mmc_priv(mmc); ++ int ret = 0; ++ ++ dev_vdbg(host->dev, "get card ro\n"); ++ if (host->pdata->gpio != NULL) ++ ret = get_pin_status(&host->pdata->gpio->wp); ++ ++ return ret < 0? 0 : ret; ++} ++ ++static int ingenic_mmc_get_card_detect(struct mmc_host *mmc) ++{ ++ struct ingenic_mmc_host *host = mmc_priv(mmc); ++ int ret = -1; ++ ++ dev_vdbg(host->dev, "get card present\n"); ++ if ((host->pdata->removal == NONREMOVABLE) ++ || (host->pdata->removal == MANUAL)) { ++ return test_bit(INGENIC_MMC_CARD_PRESENT, &host->flags); ++ } ++ ++ if (host->pdata->gpio != NULL) ++ ret = get_pin_status(&host->pdata->gpio->cd); ++ ++ return ret < 0? 1 : ret; ++} ++ ++static void ingenic_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ++{ ++ struct ingenic_mmc_host *host = mmc_priv(mmc); ++ ++ /* ++ * The max bus width is set in the platformdata->capacity, ++ * MMC_CAP_4_BIT_DATA: Can the host do 4 bit transfers ++ * MMC_CAP_8_BIT_DATA: Can the host do 8 bit transfers ++ */ ++ ++ switch (ios->bus_width) { ++ case MMC_BUS_WIDTH_1: ++ host->cmdat_def &= ~CMDAT_BUS_WIDTH_MASK; ++ host->cmdat_def |= CMDAT_BUS_WIDTH_1BIT; ++ break; ++ case MMC_BUS_WIDTH_4: ++ host->cmdat_def &= ~CMDAT_BUS_WIDTH_MASK; ++ host->cmdat_def |= CMDAT_BUS_WIDTH_4BIT; ++ break; ++ case MMC_BUS_WIDTH_8: ++ host->cmdat_def &= ~CMDAT_BUS_WIDTH_MASK; ++ host->cmdat_def |= CMDAT_BUS_WIDTH_8BIT; ++ break; ++ } ++ ++ if (ios->clock) { ++ unsigned int clk_set = 0, clkrt = 0; ++ unsigned int clk_want = ios->clock; ++ unsigned int lpm = 0; ++ ++ ingenic_mmc_clk_onoff(host, 0); ++ if (clk_want > 3000000) { ++ clk_set_rate(host->clk_cgu, ios->clock); ++ } else { ++ clk_set_rate(host->clk_cgu, CLK_RATE); ++ } ++ /*clk_get_rate is permanently 24000000 on board_4785_fpga*/ ++ clk_set = clk_get_rate(host->clk_cgu); ++ ++ while (clk_want < clk_set) { ++ clkrt++; ++ clk_set >>= 1; ++ } ++ /* discard this warning on board 4785 fpga */ ++ if ((clk_want > 3000000) && clkrt) { ++ dev_err(host->dev, "CLKRT must be set to 0 " ++ "when MSC works during normal r/w: " ++ "ios->clock=%d clk_want=%d " ++ "clk_set=%d clkrt=%X,\n", ++ ios->clock, clk_want, clk_set, clkrt); ++ WARN_ON(1); ++ } ++ ++ if (clkrt > 7) { ++ dev_err(host->dev, "invalid value of CLKRT: " ++ "ios->clock=%d clk_want=%d " ++ "clk_set=%d clkrt=%X,\n", ++ ios->clock, clk_want, clk_set, clkrt); ++ WARN_ON(1); ++ return; ++ } ++ if (!clkrt) ++ dev_vdbg(host->dev, "clk_want: %u, clk_set: %luHz\n", ++ ios->clock, clk_get_rate(host->clk_cgu)); ++ ++ ingenic_mmc_clk_onoff(host, 1); ++ msc_writel(host, CLKRT, clkrt); ++ ++ if (clk_set > 25000000) ++ lpm = (0x2 << LPM_DRV_SEL_SHF) | LPM_SMP_SEL; ++ ++ if(host->pdata->sdio_clk) { ++ msc_writel(host, LPM, lpm); ++ msc_writel(host, CTRL, CTRL_CLOCK_START); ++ } else { ++ lpm |= LPM_LPM; ++ msc_writel(host, LPM, lpm); ++ } ++ } ++ ++ switch (ios->power_mode) { ++ case MMC_POWER_ON: ++ case MMC_POWER_UP: ++ host->cmdat_def |= CMDAT_INIT; ++ set_bit(INGENIC_MMC_CARD_NEED_INIT, &host->flags); ++ ingenic_mmc_power_on(host); ++ break; ++ case MMC_POWER_OFF: ++ ingenic_mmc_power_off(host); ++ break; ++ default: ++ break; ++ } ++} ++ ++static void ingenic_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) ++{ ++ struct ingenic_mmc_host *host = mmc_priv(mmc); ++ ++ if (enable) { ++ enable_msc_irq(host, IMASK_SDIO); ++ } else { ++ clear_msc_irq(host, IFLG_SDIO); ++ disable_msc_irq(host, IMASK_SDIO); ++ } ++} ++ ++static const struct mmc_host_ops ingenic_mmc_ops = { ++ .request = ingenic_mmc_request, ++ .set_ios = ingenic_mmc_set_ios, ++ .get_ro = ingenic_mmc_get_read_only, ++ .get_cd = ingenic_mmc_get_card_detect, ++ .enable_sdio_irq = ingenic_mmc_enable_sdio_irq, ++}; ++ ++/*--------------------------End other mmc_ops------------------------------*/ ++static ssize_t ingenic_mmc_present_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct ingenic_mmc_host *host = dev_get_drvdata(dev); ++ ssize_t count = 0; ++ ++ if (test_bit(INGENIC_MMC_CARD_PRESENT, &host->flags)) ++ count = sprintf(buf, "Y\n"); ++ else ++ count = sprintf(buf, "N\n"); ++ ++ return count; ++} ++ ++static ssize_t ingenic_mmc_present_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct ingenic_mmc_pdata *pdata = dev->platform_data; ++ struct ingenic_mmc_host *host = dev_get_drvdata(dev); ++ ++ if ((buf == NULL) || (pdata->removal != NONREMOVABLE)) { ++ dev_err(host->dev, "can't set present\n"); ++ return count; ++ } ++ ++ if (strncmp(buf, "INSERT", 6) == 0) { ++ dev_info(host->dev, "card insert via sysfs\n"); ++ set_bit(INGENIC_MMC_CARD_PRESENT, &host->flags); ++ mmc_detect_change(host->mmc, 0); ++ ++ } else if (strncmp(buf, "REMOVE", 6) == 0) { ++ dev_info(host->dev, "card remove via sysfs\n"); ++ clear_bit(INGENIC_MMC_CARD_PRESENT, &host->flags); ++ mmc_detect_change(host->mmc, 0); ++ ingenic_mmc_reset(host); ++ ++ } else { ++ dev_err(host->dev, "set present error, " ++ "the argument can't be recognised\n"); ++ } ++ ++ return count; ++} ++ ++static DEVICE_ATTR(present, S_IWUSR | S_IRUSR, ++ ingenic_mmc_present_show, ingenic_mmc_present_store); ++ ++static struct attribute *ingenic_mmc_attributes[] = { ++ &dev_attr_present.attr, ++ NULL ++}; ++ ++static const struct attribute_group ingenic_mmc_attr_group = { ++ .attrs = ingenic_mmc_attributes, ++}; ++ ++/*-------------------------End Sysfs interface-----------------------------*/ ++ ++/* ++ * Platform driver and initialization. ++ */ ++static void __init ingenic_mmc_host_init(struct ingenic_mmc_host *host, struct mmc_host *mmc) ++{ ++ struct ingenic_mmc_pdata *pdata = host->pdata; ++ ++ mmc->ops = &ingenic_mmc_ops; ++ mmc->f_min = 200000; ++ mmc->ocr_avail = pdata->ocr_avail; ++ mmc->pm_flags |= pdata->pm_flags; ++#ifdef CONFIG_MMC_BLOCK_BOUNCE ++ mmc->max_blk_count = 65535; ++ mmc->max_req_size = PAGE_SIZE * 16; ++#else ++ mmc->max_segs = MAX_SEGS; ++ mmc->max_blk_count = 4096; ++ mmc->max_req_size = 4096 * 512; ++#endif ++ mmc->max_blk_size = 512; ++ mmc->max_seg_size = mmc->max_req_size; ++ ++ host->mmc = mmc; ++ setup_timer(&host->request_timer, ingenic_mmc_request_timeout, ++ (unsigned long)host); ++ ++ mmc_of_parse(mmc); ++ ++ mmc_add_host(mmc); ++} ++ ++static int __init ingenic_mmc_dma_init(struct ingenic_mmc_host *host) ++{ ++ struct sdma_desc *next_desc; ++ unsigned char i = 0; ++ void *desc_mem; ++ void __iomem *desc; ++ ++ desc_mem = (struct sdma_desc *)get_zeroed_page(GFP_KERNEL); ++ if (desc_mem == NULL) { ++ dev_err(host->dev, "get DMA descriptor memory error\n"); ++ return -ENODEV; ++ } ++ ++ desc = devm_ioremap_nocache(host->dev, virt_to_phys(desc_mem), PAGE_SIZE); ++ if (desc == NULL) { ++ dev_err(host->dev, "remap descriptor memory error\n"); ++ kfree(desc_mem); ++ return -ENODEV; ++ } ++ ++ host->decshds[0].dma_desc = (struct sdma_desc*)desc; ++ next_desc = host->decshds[0].dma_desc; ++ ++ for (i = 0; i < MAX_SEGS; ++i) { ++ struct desc_hd *dhd = &host->decshds[i]; ++ dhd->dma_desc = next_desc; ++ dhd->dma_desc_phys_addr = CPHYSADDR((unsigned long)dhd->dma_desc); ++ next_desc += 1; ++ dhd->next = dhd + 1; ++ } ++ host->decshds[MAX_SEGS - 1].next = NULL; ++ return 0; ++} ++ ++static int __init ingenic_mmc_msc_init(struct ingenic_mmc_host *host) ++{ ++ ingenic_mmc_reset(host); ++ host->cmdat_def = CMDAT_RTRG_EQUALT_16 | CMDAT_TTRG_LESS_16 | \ ++ CMDAT_BUS_WIDTH_1BIT; ++ ++ return devm_request_threaded_irq(host->dev, host->irq, NULL, ++ ingenic_mmc_thread_handle, IRQF_ONESHOT, dev_name(host->dev), host); ++} ++static void ingenic_mmc_get_gpio(struct device_node *np, ++ struct ingenic_mmc_pin *pin, char *gpioname) ++{ ++ int gpio; ++ enum of_gpio_flags flags; ++ ++ pin->num = -EBUSY; ++ gpio = of_get_named_gpio_flags(np, gpioname, 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ pin->num = gpio; ++ pin->enable_level = ++ (flags == OF_GPIO_ACTIVE_LOW ? LOW_ENABLE : HIGH_ENABLE); ++ } ++ printk("mmc gpio %s num:%d en-level: %d\n", ++ gpioname, pin->num, pin->enable_level); ++} ++static void ingenic_mmc_init_gpio(struct ingenic_mmc_pin *pin, char *gpioname, int dir) ++{ ++ if(gpio_is_valid(pin->num)) { ++ if (gpio_request_one(pin->num, dir, gpioname)) { ++ pr_info("%s no detect pin available\n", gpioname); ++ pin->num = -EBUSY; ++ } ++ } ++} ++ ++static int __init ingenic_mmc_gpio_init(struct ingenic_mmc_host *host) ++{ ++ struct card_gpio *card_gpio = host->pdata->gpio; ++ int ret = 0, dir; ++ ++ ingenic_mmc_init_gpio(&card_gpio->cd, "mmc_detect", GPIOF_DIR_IN); ++ ingenic_mmc_init_gpio(&card_gpio->wp, "mmc_wp", GPIOF_DIR_IN); ++ ingenic_mmc_init_gpio(&card_gpio->rst, "mmc_rst", GPIOF_DIR_OUT); ++ dir = card_gpio->pwr.enable_level ? GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH; ++ ingenic_mmc_init_gpio(&card_gpio->pwr, "mmc_pwr", dir); ++ ++ switch (host->pdata->removal) { ++ case NONREMOVABLE: ++ break; ++ case REMOVABLE: ++ if (gpio_is_valid(card_gpio->cd.num)) { ++ setup_timer(&host->detect_timer, ingenic_mmc_detect, ++ (unsigned long)host); ++ ret = devm_request_irq(host->dev, gpio_to_irq(card_gpio->cd.num), ++ ingenic_mmc_detect_handler, ++ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, ++ "mmc-insert-detect", host); ++ if (ret) { ++ dev_err(host->dev, "request detect irq-%d fail\n", ++ gpio_to_irq(card_gpio->cd.num)); ++ break; ++ } ++ ++ if(!timer_pending(&host->detect_timer)){ ++ disable_irq_nosync(gpio_to_irq(card_gpio->cd.num)); ++ mod_timer(&host->detect_timer, jiffies); ++ } ++ } else { ++ dev_err(host->dev, "card-detect pin must be valid " ++ "when host->pdata->removal = 1, errno=%d\n", ++ card_gpio->cd.num); ++ } ++ ++ break; ++ case MANUAL: ++ list_add(&(host->list), &manual_list); ++ break; ++ default: ++ set_bit(INGENIC_MMC_CARD_PRESENT, &host->flags); ++ break; ++ } ++ ++ return ret; ++} ++ ++static void ingenic_mmc_gpio_deinit(struct ingenic_mmc_host *host) ++{ ++ struct card_gpio *card_gpio = host->pdata->gpio; ++ ++ if (card_gpio) { ++ if(gpio_is_valid(card_gpio->cd.num)) { ++ gpio_free(card_gpio->cd.num); ++ } ++ if(gpio_is_valid(card_gpio->wp.num)) { ++ gpio_free(card_gpio->wp.num); ++ } ++ if(gpio_is_valid(card_gpio->pwr.num)) { ++ gpio_free(card_gpio->pwr.num); ++ } ++ if(gpio_is_valid(card_gpio->rst.num)) { ++ gpio_free(card_gpio->rst.num); ++ } ++ } ++} ++ ++static const struct of_device_id mmc_ingenic_of_match[] = { ++ {.compatible = "ingenic,mmc",}, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, mmc_ingenic_of_match); ++ ++static struct ingenic_mmc_pdata *of_get_mmc_ingenic_pdata(struct device *dev) ++{ ++ struct ingenic_mmc_pdata *pdata; ++ struct device_node *np = dev->of_node; ++ struct card_gpio *card_gpio; ++ ++ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); ++ if (!pdata) ++ return NULL; /* out of memory */ ++ ++ card_gpio = devm_kzalloc(dev, sizeof(struct card_gpio), GFP_KERNEL); ++ if(!card_gpio) ++ return NULL; ++ ingenic_mmc_get_gpio(np, &card_gpio->rst, "ingneic,rst-gpios"); ++ ingenic_mmc_get_gpio(np, &card_gpio->wp, "ingneic,wp-gpios"); ++ ingenic_mmc_get_gpio(np, &card_gpio->pwr, "ingneic,pwr-gpios"); ++ ingenic_mmc_get_gpio(np, &card_gpio->cd, "ingneic,cd-gpios"); ++ pdata->gpio = card_gpio; ++ ++ if(of_property_read_bool(np, "pio-mode")) { ++ pdata->pio_mode = 1; ++ } ++ ++ { ++ unsigned int val; ++ if(!(of_property_read_u32(np, "ingenic,sdio_clk", &val))) ++ pdata->sdio_clk = val; ++ } ++ ++ if(of_property_read_bool(np, "ingenic,removal-dontcare")) { ++ pdata->removal = DONTCARE; ++ } else if(of_property_read_bool(np, "ingenic,removal-nonremovable")) { ++ pdata->removal = NONREMOVABLE; ++ } else if(of_property_read_bool(np, "ingenic,removal-removable")) { ++ pdata->removal = REMOVABLE; ++ } else if(of_property_read_bool(np, "ingenic,removal-manual")) { ++ pdata->removal = MANUAL; ++ }; ++ ++ mmc_of_parse_voltage(np, &pdata->ocr_avail); ++ ++ return pdata; ++} ++ ++static int mmc_ingenic_probe(struct platform_device *pdev) ++{ ++ struct ingenic_mmc_pdata *pdata; ++ struct resource *regs; ++ struct ingenic_mmc_host *host = NULL; ++ struct mmc_host *mmc; ++ int ret = 0; ++ char clkname[16]; ++ ++ pdata = of_get_mmc_ingenic_pdata(&pdev->dev); ++ if(IS_ERR(pdata)) { ++ dev_err(&pdev->dev, "Platform Data is missing!\n"); ++ return PTR_ERR(pdata); ++ } ++ mmc = mmc_alloc_host(sizeof(struct ingenic_mmc_host), &pdev->dev); ++ if (!mmc) ++ return -ENOMEM; ++ ++ host = mmc_priv(mmc); ++ ++ pdev->id = of_alias_get_id(pdev->dev.of_node, "msc"); ++ sprintf(clkname, "cgu_msc%d", pdev->id); ++ host->clk_cgu = devm_clk_get(&pdev->dev, clkname); ++ if(!host->clk_cgu) { ++ dev_err(&pdev->dev, "Failed to Get MSC clk!\n"); ++ return PTR_ERR(host->clk_cgu); ++ } ++ sprintf(clkname, "gate_msc%d", pdev->id); ++ host->clk_gate = devm_clk_get(&pdev->dev, clkname); ++ if(!host->clk_gate) { ++ dev_err(&pdev->dev, "Failed to Get PWC MSC clk!\n"); ++ return PTR_ERR(host->clk_gate); ++ } ++ ++ clk_set_rate(host->clk_cgu, CLK_RATE); ++ if(clk_get_rate(host->clk_cgu) > CLK_RATE) { ++ dev_err(&pdev->dev, "Failed to Set MSC clk %ld!\n", clk_get_rate(host->clk_cgu)); ++ goto err_clk_get_rate; ++ } ++ ingenic_mmc_clk_onoff(host, 1); ++ ++ host->dev = &pdev->dev; ++ host->index = pdev->id; ++ host->pdata = pdata; ++ ++ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!regs) { ++ dev_err(&pdev->dev, "No iomem resource\n"); ++ return -ENXIO; ++ } ++ host->iomem = devm_ioremap_resource(&pdev->dev, regs); ++ if (!host->iomem) ++ goto err_ioremap; ++ ++ host->irq = platform_get_irq(pdev, 0); ++ if (host->irq < 0) { ++ dev_err(&pdev->dev, "No irq resource\n"); ++ return host->irq; ++ } ++ ++ /* host->power = regulator_get(host->dev, "cpu_mem12"); */ ++ /* if (IS_ERR(host->power)) { */ ++ /* dev_warn(host->dev, "vmmc regulator missing\n"); */ ++ /* } */ ++ if (host->pdata->pio_mode) ++ set_bit(INGENIC_MMC_USE_PIO, &host->flags); ++ ++ if (!test_bit(INGENIC_MMC_USE_PIO, &host->flags)) { ++ ret = ingenic_mmc_dma_init(host); ++ if (ret < 0) ++ goto err_dma_init; ++ } ++ ++ spin_lock_init(&host->lock); ++ if (pdata->sdio_clk) { ++ ingenic_sdio_wlan_init(&pdev->dev, host->index); ++ } ++ ++ ret = ingenic_mmc_msc_init(host); ++ if (ret < 0) ++ goto err_msc_init; ++ ++ ingenic_mmc_host_init(host, mmc); ++ ++ ret = ingenic_mmc_gpio_init(host); ++ if (ret < 0) ++ goto err_gpio_init; ++ ++ ret = sysfs_create_group(&pdev->dev.kobj, &ingenic_mmc_attr_group); ++ if (ret < 0) ++ goto err_sysfs_create; ++ ++ platform_set_drvdata(pdev, host); ++ ++ dev_info(host->dev, "register success!\n"); ++ return 0; ++ ++err_sysfs_create: ++ ingenic_mmc_gpio_deinit(host); ++err_gpio_init: ++ free_irq(host->irq, host); ++err_msc_init: ++ devm_iounmap(&pdev->dev, (void __iomem *)host->decshds[0].dma_desc); ++err_dma_init: ++ devm_iounmap(&pdev->dev, host->iomem); ++err_ioremap: ++ mmc_free_host(mmc); ++ clk_disable_unprepare(host->clk_cgu); ++err_clk_get_rate: ++ clk_put(host->clk_cgu); ++ clk_put(host->clk_gate); ++ dev_err(host->dev, "mmc probe error\n"); ++ return ret; ++} ++ ++static int __exit mmc_ingenic_remove(struct platform_device *pdev) ++{ ++ struct ingenic_mmc_host *host = platform_get_drvdata(pdev); ++ ++ platform_set_drvdata(pdev, NULL); ++ mmc_remove_host(host->mmc); ++ mmc_free_host(host->mmc); ++ sysfs_remove_group(&pdev->dev.kobj, &ingenic_mmc_attr_group); ++ ++ ingenic_mmc_power_off(host); ++ if (host->pdata->removal == REMOVABLE) ++ free_irq(gpio_to_irq(host->pdata->gpio->cd.num), host); ++ ++ free_irq(host->irq, host); ++ ingenic_mmc_gpio_deinit(host); ++ devm_iounmap(&pdev->dev, (void __iomem *)host->decshds[0].dma_desc); ++ /* regulator_put(host->power); */ ++ ingenic_mmc_clk_onoff(host, 0); ++ ++ clk_put(host->clk_cgu); ++ clk_put(host->clk_gate); ++ iounmap(host->iomem); ++ kfree(host); ++ ++ return 0; ++} ++ ++static void mmc_ingenic_shutdown(struct platform_device *pdev) ++{ ++ struct ingenic_mmc_host *host = platform_get_drvdata(pdev); ++ struct card_gpio *card_gpio = host->pdata->gpio; ++ ++ /* ++ * Remove host when shutdown to avoid illegal request, ++ * but don't remove sdio_host in case of the SDIO device driver ++ * can't handle bus remove correctly. ++ */ ++ dev_vdbg(host->dev, "shutdown\n"); ++ if(host->mmc->card && !mmc_card_sdio(host->mmc->card)) { ++ if(gpio_is_valid(card_gpio->rst.num)) { ++ gpio_direction_output(card_gpio->rst.num, 0); ++ } else { ++ mmc_remove_host(host->mmc); ++ } ++ } ++ ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int mmc_ingenic_suspend(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct ingenic_mmc_host *host = platform_get_drvdata(pdev); ++ int ret = 0; ++ ++ ingenic_mmc_clk_onoff(host, 0); ++ /* if (host->mmc->card && host->mmc->card->type != MMC_TYPE_SDIO) { */ ++ /* ret = mmc_suspend_host(host->mmc); */ ++ /* } */ ++ return ret; ++} ++ ++static int mmc_ingenic_resume(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct ingenic_mmc_host *host = platform_get_drvdata(pdev); ++ int ret = 0; ++ ingenic_mmc_clk_onoff(host, 1); ++ /* if (host->mmc->card && host->mmc->card->type != MMC_TYPE_SDIO) { */ ++ /* ret = mmc_resume_host(host->mmc); */ ++ /* } */ ++ return ret; ++} ++#else ++#define mmc_ingenic_suspend NULL ++#define mmc_ingenic_resume NULL ++#endif ++static SIMPLE_DEV_PM_OPS(mmc_ingenic_pm_ops, mmc_ingenic_suspend, ++ mmc_ingenic_resume); ++ ++static struct platform_driver mmc_ingenic_driver = { ++ .driver = { ++ .name = "ingenic,mmc", ++ .owner = THIS_MODULE, ++ .pm = &mmc_ingenic_pm_ops, ++ .of_match_table = of_match_ptr(mmc_ingenic_of_match), ++ }, ++ .probe = mmc_ingenic_probe, ++ .remove = mmc_ingenic_remove, ++ .shutdown = mmc_ingenic_shutdown, ++}; ++ ++module_platform_driver(mmc_ingenic_driver); ++ ++MODULE_DESCRIPTION("Multimedia Card Interface driver, MMC version 1.2"); ++MODULE_AUTHOR("bo.liu "); ++MODULE_LICENSE("GPL v2"); ++MODULE_VERSION("20170222"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_host_ingenic_mmc.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_host_ingenic_mmc.h.patch new file mode 100644 index 00000000..dab12aa4 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_host_ingenic_mmc.h.patch @@ -0,0 +1,157 @@ +diff -drupN a/drivers/mmc/host/ingenic_mmc.h b/drivers/mmc/host/ingenic_mmc.h +--- a/drivers/mmc/host/ingenic_mmc.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mmc/host/ingenic_mmc.h 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,153 @@ ++#ifndef __INGENIC_MMC_H__ ++#define __INGENIC_MMC_H__ ++ ++#include "ingenic_mmc_reg.h" ++enum { ++ DONTCARE = 0, ++ NONREMOVABLE, ++ REMOVABLE, ++ MANUAL, ++}; ++ ++enum { ++ EVENT_CMD_COMPLETE = 0, ++ EVENT_TRANS_COMPLETE, ++ EVENT_DMA_COMPLETE, ++ EVENT_DATA_COMPLETE, ++ EVENT_STOP_COMPLETE, ++ EVENT_ERROR, ++}; ++ ++enum ingenic_mmc_state { ++ STATE_IDLE = 0, ++ STATE_WAITING_RESP, ++ STATE_WAITING_DATA, ++ STATE_SENDING_STOP, ++ STATE_ERROR, ++}; ++ ++struct sdma_desc { ++ volatile u32 nda; ++ volatile u32 da; ++ volatile u32 len; ++ volatile u32 dcmd; ++}; ++ ++struct desc_hd { ++ struct sdma_desc *dma_desc; ++ dma_addr_t dma_desc_phys_addr; ++ struct desc_hd *next; ++}; ++ ++#define LOW_ENABLE 0 ++#define HIGH_ENABLE 1 ++struct ingenic_mmc_pin { ++ short num; ++ short enable_level; ++}; ++ ++struct card_gpio { ++ struct ingenic_mmc_pin wp; ++ struct ingenic_mmc_pin cd; ++ struct ingenic_mmc_pin pwr; ++ struct ingenic_mmc_pin rst; ++}; ++ ++/** ++ * struct ingenic_mmc_platform_data is a struct which defines board MSC informations ++ * @removal: This shows the card slot's type: ++ * REMOVABLE/IRREMOVABLE/MANUAL (Tablet card/Phone card/build-in SDIO). ++ * @sdio_clk: SDIO device's clock can't use Low-Power-Mode. ++ * @ocr_mask: This one shows the voltage that host provide. ++ * @capacity: Shows the host's speed capacity and bus width. ++ * @max_freq: The max freqency of mmc host. ++ * ++ * @recovery_info: Informations that Android recovery mode uses. ++ * @gpio: Slot's gpio information including pins of write-protect, card-detect and power. ++ * @pio_mode: Indicate that whether the MSC host use PIO mode. ++ * @private_init: Board private initial function, mostly for SDIO devices. ++ */ ++struct ingenic_mmc_pdata { ++ unsigned short removal; ++ unsigned short sdio_clk; ++ unsigned int ocr_avail; ++ unsigned int capacity; ++ unsigned int pm_flags; ++ struct card_gpio *gpio; ++ unsigned int pio_mode; ++ int (*private_init)(void); ++}; ++ ++/** ++ * struct ingenic_mmc_host - Ingenic MMC/SD Controller host structure ++ * @pdata: The platform data. ++ * @dev: The mmc device pointer. ++ * @irq: Interrupt of MSC. ++ * @clk: Main Clk of MSC, including cgu and clk gate. ++ * @pwc_clk: Power of MSC module, MSC register can be access when pwc_clk on. ++ * @power: Power regulator of SD/MMC attached to SD slot. ++ * @mrq: mmc_request pointer which includes all the information ++ * of the current request, or NULL when the host is idle. ++ * @cmd: Command information of mmc_request. ++ * @data: Data information of mmc_request, or NULL when mrq without ++ * data request. ++ * @mmc: The mmc_host representing this slot. ++ * @pending_events: Bitmask of events flagged by the interrupt handler ++ * to be processed by the state machine. ++ * @iomem: Pointer to MSC registers. ++ * @detect_timer: Timer used for debouncing card insert interrupts. ++ * @request_timer: Timer used for preventing request time out. ++ * @flags: Random state bits associated with the slot. ++ * @cmdat: Variable for MSC_CMDAT register. ++ * @cmdat_def: Defalt CMDAT register value for every request. ++ * @gpio: Information of gpio including cd, wp and pwr. ++ * @index: Number of each MSC host. ++ * @decshds[]: Descriptor DMA information structure. ++ * @state: It's the state for request. ++ * @list: List head for manually detect card such as wifi. ++ * @lock: Lock the registers operation. ++ * @double_enter: Prevent state machine reenter. ++ * @timeout_cnt: The count of timeout second. ++ */ ++#define MAX_SEGS 128 /* max count of sg */ ++#define INGENIC_MMC_CARD_PRESENT 0 ++#define INGENIC_MMC_CARD_NEED_INIT 1 ++#define INGENIC_MMC_USE_PIO 2 ++ ++struct ingenic_mmc_host { ++ void __iomem *iomem; ++ struct device *dev; ++ struct clk *clk_cgu; ++ struct clk *clk_gate; ++ struct regulator *power; ++ struct mmc_request *mrq; ++ struct mmc_command *cmd; ++ struct mmc_data *data; ++ struct mmc_host *mmc; ++ struct timer_list detect_timer; ++ struct timer_list request_timer; ++ struct tasklet_struct tasklet; ++ struct list_head list; ++ struct ingenic_mmc_pdata *pdata; ++ struct desc_hd decshds[MAX_SEGS]; ++ enum ingenic_mmc_state state; ++ spinlock_t lock; ++ unsigned long pending_events; ++ unsigned long flags; ++ unsigned int cmdat; ++ unsigned int cmdat_def; ++ unsigned int index; ++ unsigned int double_enter; ++ int timeout_cnt; ++ int irq; ++}; ++ ++/* Register access macros */ ++#define msc_readl(port,reg) \ ++ __raw_readl((port)->iomem + MSC_##reg) ++#define msc_writel(port,reg,value) \ ++ __raw_writel((value), (port)->iomem + MSC_##reg) ++int ingenic_sdio_wlan_init(struct device *dev, int index); ++int ingenic_mmc_clk_ctrl(int index, int on); ++int ingenic_mmc_manual_detect(int index, int on); ++#endif /* __INGENIC_MMC_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_host_ingenic_mmc_reg.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_host_ingenic_mmc_reg.h.patch new file mode 100644 index 00000000..431e1c87 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_host_ingenic_mmc_reg.h.patch @@ -0,0 +1,236 @@ +diff -drupN a/drivers/mmc/host/ingenic_mmc_reg.h b/drivers/mmc/host/ingenic_mmc_reg.h +--- a/drivers/mmc/host/ingenic_mmc_reg.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mmc/host/ingenic_mmc_reg.h 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,232 @@ ++#ifndef __INGENIC_MMC_REG_H__ ++#define __INGENIC_MMC_REG_H__ ++#define MMC_BOOT_AREA_PROTECTED (0x1234) /* Can not modified the area protected */ ++#define MMC_BOOT_AREA_OPENED (0x4321) /* Can modified the area protected */ ++ ++#define MSC_CTRL 0x000 ++#define MSC_STAT 0x004 ++#define MSC_CLKRT 0x008 ++#define MSC_CMDAT 0x00C ++#define MSC_RESTO 0x010 ++#define MSC_RDTO 0x014 ++#define MSC_BLKLEN 0x018 ++#define MSC_NOB 0x01C ++#define MSC_SNOB 0x020 ++#define MSC_IMASK 0x024 ++#define MSC_IFLG 0x028 ++#define MSC_CMD 0x02C ++#define MSC_ARG 0x030 ++#define MSC_RES 0x034 ++#define MSC_RXFIFO 0x038 ++#define MSC_TXFIFO 0x03C ++#define MSC_LPM 0x040 ++#define MSC_DMAC 0x044 ++#define MSC_DMANDA 0x048 ++#define MSC_DMADA 0x04C ++#define MSC_DMALEN 0x050 ++#define MSC_DMACMD 0x054 ++#define MSC_CTRL2 0x058 ++#define MSC_RTCNT 0x05C ++#define MSC_DEBUG 0x0FC ++ ++/* MSC Clock and Control Register (MSC_CTRL) */ ++#define CTRL_SEND_CCSD (1 << 15) /*send command completion signal disable to ceata */ ++#define CTRL_SEND_AS_CCSD (1 << 14) /*send internally generated stop after sending ccsd */ ++#define CTRL_EXIT_MULTIPLE (1 << 7) ++#define CTRL_EXIT_TRANSFER (1 << 6) ++#define CTRL_START_READWAIT (1 << 5) ++#define CTRL_STOP_READWAIT (1 << 4) ++#define CTRL_RESET (1 << 3) ++#define CTRL_START_OP (1 << 2) ++#define CTRL_CLOCK_SHF 0 ++#define CTRL_CLOCK_MASK (0x3 << CTRL_CLOCK_SHF) ++#define CTRL_CLOCK_STOP (0x1 << CTRL_CLOCK_SHF) /* Stop MMC/SD clock */ ++#define CTRL_CLOCK_START (0x2 << CTRL_CLOCK_SHF) /* Start MMC/SD clock */ ++ ++/* MSC Control 2 Register (MSC_CTRL2) */ ++#define CTRL2_PIP_SHF 24 ++#define CTRL2_PIP_MASK (0x1f << CTRL2_PIP_SHF) ++#define CTRL2_RST_EN (1 << 23) ++#define CTRL2_STPRM (1 << 4) ++#define CTRL2_SVC (1 << 3) ++#define CTRL2_SMS_SHF 0 ++#define CTRL2_SMS_MASK (0x7 << CTRL2_SMS_SHF) ++#define CTRL2_SMS_DEFSPD (0x0 << CTRL2_SMS_SHF) ++#define CTRL2_SMS_HISPD (0x1 << CTRL2_SMS_SHF) ++#define CTRL2_SMS_SDR12 (0x2 << CTRL2_SMS_SHF) ++#define CTRL2_SMS_SDR25 (0x3 << CTRL2_SMS_SHF) ++#define CTRL2_SMS_SDR50 (0x4 << CTRL2_SMS_SHF) ++ ++/* MSC Status Register (MSC_STAT) */ ++#define STAT_AUTO_CMD12_DONE (1 << 31) ++#define STAT_AUTO_CMD23_DONE (1 << 30) ++#define STAT_SVS (1 << 29) ++#define STAT_PIN_LEVEL_SHF 24 ++#define STAT_PIN_LEVEL_MASK (0x1f << STAT_PIN_LEVEL_SHF) ++#define STAT_BCE (1 << 20) ++#define STAT_BDE (1 << 19) ++#define STAT_BAE (1 << 18) ++#define STAT_BAR (1 << 17) ++#define STAT_IS_RESETTING (1 << 15) ++#define STAT_SDIO_INT_ACTIVE (1 << 14) ++#define STAT_PRG_DONE (1 << 13) ++#define STAT_DATA_TRAN_DONE (1 << 12) ++#define STAT_END_CMD_RES (1 << 11) ++#define STAT_DATA_FIFO_AFULL (1 << 10) ++#define STAT_IS_READWAIT (1 << 9) ++#define STAT_CLK_EN (1 << 8) ++#define STAT_DATA_FIFO_FULL (1 << 7) ++#define STAT_DATA_FIFO_EMPTY (1 << 6) ++#define STAT_CRC_RES_ERR (1 << 5) ++#define STAT_CRC_READ_ERROR (1 << 4) ++#define STAT_CRC_WRITE_ERROR_SHF 2 ++#define STAT_CRC_WRITE_ERROR_MASK (0x3 << STAT_CRC_WRITE_ERROR_SHF) ++#define STAT_CRC_WRITE_ERROR_NO (0 << STAT_CRC_WRITE_ERROR_SHF) ++#define STAT_CRC_WRITE_ERROR (1 << STAT_CRC_WRITE_ERROR_SHF) ++#define STAT_CRC_WRITE_ERROR_NOSTS (2 << STAT_CRC_WRITE_ERROR_SHF) ++#define STAT_TIME_OUT_RES (1 << 1) ++#define STAT_TIME_OUT_READ (1 << 0) ++ ++/* MSC Bus Clock Control Register (MSC_CLKRT) */ ++#define CLKRT_CLK_RATE_SHF 0 ++#define CLKRT_CLK_RATE_MASK (0x7 << CLKRT_CLK_RATE_SHF) ++#define CLKRT_CLK_RATE_DIV_1 (0x0 << CLKRT_CLK_RATE_SHF) /* CLK_SRC */ ++#define CLKRT_CLK_RATE_DIV_2 (0x1 << CLKRT_CLK_RATE_SHF) /* 1/2 of CLK_SRC */ ++#define CLKRT_CLK_RATE_DIV_4 (0x2 << CLKRT_CLK_RATE_SHF) /* 1/4 of CLK_SRC */ ++#define CLKRT_CLK_RATE_DIV_8 (0x3 << CLKRT_CLK_RATE_SHF) /* 1/8 of CLK_SRC */ ++#define CLKRT_CLK_RATE_DIV_16 (0x4 << CLKRT_CLK_RATE_SHF) /* 1/16 of CLK_SRC */ ++#define CLKRT_CLK_RATE_DIV_32 (0x5 << CLKRT_CLK_RATE_SHF) /* 1/32 of CLK_SRC */ ++#define CLKRT_CLK_RATE_DIV_64 (0x6 << CLKRT_CLK_RATE_SHF) /* 1/64 of CLK_SRC */ ++#define CLKRT_CLK_RATE_DIV_128 (0x7 << CLKRT_CLK_RATE_SHF) /* 1/128 of CLK_SRC */ ++ ++/* MSC Command Sequence Control Register (MSC_CMDAT) */ ++#define CMDAT_CCS_EXPECTED (1 << 31) /* interrupts are enabled in ce-ata */ ++#define CMDAT_READ_CEATA (1 << 30) ++#define CMDAT_DIS_BOOT (1 << 27) ++#define CMDAT_ENB_BOOT (1 << 26) ++#define CMDAT_EXP_BOOT_ACK (1 << 25) ++#define CMDAT_BOOT_MODE (1 << 24) ++#define CMDAT_AUTO_CMD23 (1 << 18) ++#define CMDAT_SDIO_PRDT (1 << 17) /* exact 2 cycle */ ++#define CMDAT_AUTO_CMD12 (1 << 16) ++#define CMDAT_RTRG_SHF 14 ++#define CMDAT_RTRG_EQUALT_16 (0x0 << CMDAT_RTRG_SHF) /*reset value*/ ++#define CMDAT_RTRG_EQUALT_32 (0x1 << CMDAT_RTRG_SHF) ++#define CMDAT_RTRG_EQUALT_64 (0x2 << CMDAT_RTRG_SHF) ++#define CMDAT_RTRG_EQUALT_96 (0x3 << CMDAT_RTRG_SHF) ++#define CMDAT_TTRG_SHF 12 ++#define CMDAT_TTRG_LESS_16 (0x0 << CMDAT_TTRG_SHF) /*reset value*/ ++#define CMDAT_TTRG_LESS_32 (0x1 << CMDAT_TTRG_SHF) ++#define CMDAT_TTRG_LESS_64 (0x2 << CMDAT_TTRG_SHF) ++#define CMDAT_TTRG_LESS_96 (0x3 << CMDAT_TTRG_SHF) ++#define CMDAT_IO_ABORT (1 << 11) ++#define CMDAT_BUS_WIDTH_SHF 9 ++#define CMDAT_BUS_WIDTH_MASK (0x3 << CMDAT_BUS_WIDTH_SHF) ++#define CMDAT_BUS_WIDTH_1BIT (0x0 << CMDAT_BUS_WIDTH_SHF) /* 1-bit data bus */ ++#define CMDAT_BUS_WIDTH_4BIT (0x2 << CMDAT_BUS_WIDTH_SHF) /* 4-bit data bus */ ++#define CMDAT_BUS_WIDTH_8BIT (0x3 << CMDAT_BUS_WIDTH_SHF) /* 8-bit data bus */ ++#define CMDAT_INIT (1 << 7) ++#define CMDAT_BUSY (1 << 6) ++#define CMDAT_STREAM_BLOCK (1 << 5) ++#define CMDAT_WRITE_READ (1 << 4) ++#define CMDAT_DATA_EN (1 << 3) ++#define CMDAT_RESPONSE_SHF 0 ++#define CMDAT_RESPONSE_MASK (0x7 << CMDAT_RESPONSE_SHF) ++#define CMDAT_RESPONSE_NONE (0x0 << CMDAT_RESPONSE_SHF) /* No response */ ++#define CMDAT_RESPONSE_R1 (0x1 << CMDAT_RESPONSE_SHF) /* Format R1 and R1b */ ++#define CMDAT_RESPONSE_R2 (0x2 << CMDAT_RESPONSE_SHF) /* Format R2 */ ++#define CMDAT_RESPONSE_R3 (0x3 << CMDAT_RESPONSE_SHF) /* Format R3 */ ++#define CMDAT_RESPONSE_R4 (0x4 << CMDAT_RESPONSE_SHF) /* Format R4 */ ++#define CMDAT_RESPONSE_R5 (0x5 << CMDAT_RESPONSE_SHF) /* Format R5 */ ++#define CMDAT_RESPONSE_R6 (0x6 << CMDAT_RESPONSE_SHF) /* Format R6 */ ++#define CMDAT_RESRONSE_R7 (0x7 << CMDAT_RESPONSE_SHF) /* Format R7 */ ++ ++/* MSC Interrupts Mask Register (MSC_IMASK) */ ++#define IMASK_DMA_DATA_DONE (1 << 31) ++#define IMASK_WR_ALL_DONE (1 << 23) ++#define IMASK_AUTO_CMD23_DONE (1 << 30) ++#define IMASK_SVS (1 << 29) ++#define IMASK_PIN_LEVEL_SHF 24 ++#define IMASK_PIN_LEVEL_MASK (0x1f << IMASK_PIN_LEVEL_SHF) ++#define IMASK_BCE (1 << 20) ++#define IMASK_BDE (1 << 19) ++#define IMASK_BAE (1 << 18) ++#define IMASK_BAR (1 << 17) ++#define IMASK_DMAEND (1 << 16) ++#define IMASK_AUTO_CMD12_DONE (1 << 15) ++#define IMASK_DATA_FIFO_FULL (1 << 14) ++#define IMASK_DATA_FIFO_EMP (1 << 13) ++#define IMASK_CRC_RES_ERR (1 << 12) ++#define IMASK_CRC_READ_ERR (1 << 11) ++#define IMASK_CRC_WRITE_ERR (1 << 10) ++#define IMASK_TIME_OUT_RES (1 << 9) ++#define IMASK_TIME_OUT_READ (1 << 8) ++#define IMASK_SDIO (1 << 7) ++#define IMASK_TXFIFO_WR_REQ (1 << 6) ++#define IMASK_RXFIFO_RD_REQ (1 << 5) ++#define IMASK_END_CMD_RES (1 << 2) ++#define IMASK_PRG_DONE (1 << 1) ++#define IMASK_DATA_TRAN_DONE (1 << 0) ++ ++/* MSC Interrupts Status Register (MSC_IREG) */ ++#define IFLG_DMA_DATA_DONE (1 << 31) ++#define IFLG_WR_ALL_DONE (1 << 23) ++#define IFLG_AUTO_CMD23_DONE (1 << 30) ++#define IFLG_SVS (1 << 29) ++#define IFLG_PIN_LEVEL_SHF 24 ++#define IFLG_PIN_LEVEL_MASK (0x1f << IFLG_PIN_LEVEL_SHF) ++#define IFLG_BCE (1 << 20) ++#define IFLG_BDE (1 << 19) ++#define IFLG_BAE (1 << 18) ++#define IFLG_BAR (1 << 17) ++#define IFLG_DMAEND (1 << 16) ++#define IFLG_AUTO_CMD12_DONE (1 << 15) ++#define IFLG_DATA_FIFO_FULL (1 << 14) ++#define IFLG_DATA_FIFO_EMP (1 << 13) ++#define IFLG_CRC_RES_ERR (1 << 12) ++#define IFLG_CRC_READ_ERR (1 << 11) ++#define IFLG_CRC_WRITE_ERR (1 << 10) ++#define IFLG_TIMEOUT_RES (1 << 9) ++#define IFLG_TIMEOUT_READ (1 << 8) ++#define IFLG_SDIO (1 << 7) ++#define IFLG_TXFIFO_WR_REQ (1 << 6) ++#define IFLG_RXFIFO_RD_REQ (1 << 5) ++#define IFLG_END_CMD_RES (1 << 2) ++#define IFLG_PRG_DONE (1 << 1) ++#define IFLG_DATA_TRAN_DONE (1 << 0) ++ ++/* MSC Low Power Mode Register (MSC_LPM) */ ++#define LPM_DRV_SEL_SHF 30 ++#define LPM_DRV_SEL_MASK (0x3 << LPM_DRV_SEL_SHF) ++#define LPM_SMP_SEL (1 << 29) ++#define LPM_LPM (1 << 0) ++ ++/* MSC DMA Control Register (MSC_DMAC) */ ++#define DMAC_MODE_SEL (1 << 7) ++#define DMAC_AOFST_SHF 5 ++#define DMAC_AOFST_MASK (0x3 << DMAC_AOFST_SHF) ++#define DMAC_AOFST_0 (0 << DMAC_AOFST_SHF) ++#define DMAC_AOFST_1 (1 << DMAC_AOFST_SHF) ++#define DMAC_AOFST_2 (2 << DMAC_AOFST_SHF) ++#define DMAC_AOFST_3 (3 << DMAC_AOFST_SHF) ++#define DMAC_ALIGNEN (1 << 4) ++#define DMAC_INCR_SHF 2 ++#define DMAC_INCR_MASK (0x3 << DMAC_INCR_SHF) ++#define DMAC_INCR_16 (0 << DMAC_INCR_SHF) ++#define DMAC_INCR_32 (1 << DMAC_INCR_SHF) ++#define DMAC_INCR_64 (2 << DMAC_INCR_SHF) ++#define DMAC_DMASEL (1 << 1) ++#define DMAC_DMAEN (1 << 0) ++ ++/* MSC DMA Command Register (MSC_DMACMD) */ ++#define DMACMD_IDI_SHF 24 ++#define DMACMD_IDI_MASK (0xff << DMACMD_IDI_SHF) ++#define DMACMD_ID_SHF 16 ++#define DMACMD_ID_MASK (0xff << DMACMD_ID_SHF) ++#define DMACMD_OFFSET_SHF 9 ++#define DMACMD_OFFSET_MASK (0x3 << DMACMD_OFFSET_SHF) ++#define DMACMD_ALIGN_EN (1 << 8) ++#define DMACMD_ENDI (1 << 1) ++#define DMACMD_LINK (1 << 0) ++ ++#endif /* __INGENIC_MMC_REG_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_host_ingenic_sdio.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_host_ingenic_sdio.c.patch new file mode 100644 index 00000000..e5f87c5f --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_host_ingenic_sdio.c.patch @@ -0,0 +1,216 @@ +diff -drupN a/drivers/mmc/host/ingenic_sdio.c b/drivers/mmc/host/ingenic_sdio.c +--- a/drivers/mmc/host/ingenic_sdio.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mmc/host/ingenic_sdio.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,212 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#if defined CONFIG_KP_AXP ++#include ++#endif ++#ifdef CONFIG_SOC_T40 ++#include "sdhci-ingenic.h" ++#else ++#include "ingenic_mmc.h" ++#endif ++ ++struct wifi_data { ++ int sdio_index; ++ /* struct wake_lock wifi_wake_lock; */ ++ /* struct regulator *wifi_vbat; */ ++ /* struct regulator *wifi_vddio; */ ++ uint wifi_reset; ++ uint wifi_irq; ++ uint wifi_irq_flags; ++ struct pinctrl *pctrl; ++ atomic_t rtc32k_ref; ++#if defined CONFIG_KP_AXP ++ struct regulator *wifi_regulator; ++#endif ++ ++}; ++ ++#define RESET 0 ++#define NORMAL 1 ++ ++struct wifi_data wifi_data; ++static void rtc32k_init(struct device *dev, struct wifi_data *wdata) ++{ ++ atomic_set(&wdata->rtc32k_ref, 0); ++ wdata->pctrl = devm_pinctrl_get(dev); ++} ++void rtc32k_enable(void) ++{ ++ struct pinctrl_state *state = NULL; ++ struct pinctrl *p = wifi_data.pctrl; ++ ++ if (atomic_inc_return(&wifi_data.rtc32k_ref) == 1) { ++ state = pinctrl_lookup_state(p, "enable"); ++ if (!IS_ERR_OR_NULL(state)) { ++ pinctrl_select_state(p, state); ++ } ++ } ++} ++EXPORT_SYMBOL(rtc32k_enable); ++void rtc32k_disable(void) ++{ ++ struct pinctrl_state *state = NULL; ++ struct pinctrl *p = wifi_data.pctrl; ++ ++ if (atomic_inc_return(&wifi_data.rtc32k_ref) == 0) { ++ state = pinctrl_lookup_state(p, "disable"); ++ if (!IS_ERR_OR_NULL(state)) { ++ pinctrl_select_state(p, state); ++ } ++ } ++} ++EXPORT_SYMBOL(rtc32k_disable); ++ ++static const struct of_device_id wlan_ingenic_of_match[] = { ++ {.compatible = "android,bcmdhd_wlan"}, ++ {.compatible = "rtk,rtl8723ds_wlan"}, ++ {}, ++}; ++ ++ ++ ++#ifdef CONFIG_RTL8723DS ++extern int rtk_wlan_init(void); ++#else ++static int rtk_wlan_init(void) ++{ ++ return 0; ++} ++#endif ++static int rtl8723ds_wlan_init(void) ++{ ++ rtk_wlan_init(); ++ return 0; ++} ++ ++ ++int ingenic_sdio_wlan_init(struct device *dev, int index) ++{ ++ struct device_node *np = dev->of_node, *cnp; ++ unsigned int flags, gpio; ++ ++ for_each_child_of_node(np, cnp) { ++ if(of_device_is_compatible(cnp, "android,bcmdhd_wlan")) { ++ printk("----android,bcmdhd_wlan!\n"); ++ wifi_data.wifi_reset = of_get_named_gpio_flags(cnp, "ingenic,sdio-reset", 0, &flags); ++ wifi_data.wifi_irq = of_get_named_gpio_flags(cnp, "ingenic,sdio-irq", 0, &flags); ++ wifi_data.wifi_irq_flags = flags; ++ } ++ if(of_device_is_compatible(cnp, "rtk,rtl8723ds_wlan")) { ++ printk("----rtk,rtl8723ds_wlan\n"); ++ rtl8723ds_wlan_init(); ++ return 0; ++ } ++ } ++#if defined CONFIG_KP_AXP ++ wifi_data.wifi_regulator = regulator_get(NULL, "wlreg_on"); ++ if (wifi_data.wifi_regulator == NULL) { ++ printk(("%s regulator is null\n", __FUNCTION__)); ++ return -1; ++ } ++ ++ if(regulator_enable(wifi_data.wifi_regulator) < 0){ ++ printk(("%s: regulator enable/disable failed", __FUNCTION__)); ++ return -1; ++ } ++#endif ++ ++ rtc32k_init(dev, &wifi_data); ++ rtc32k_enable(); ++ ++ gpio = wifi_data.wifi_reset; ++ if (devm_gpio_request(dev, gpio, "wifi_reset")) { ++ printk("ERROR: no wifi_reset pin available !!\n"); ++ return -EINVAL; ++ } else { ++ gpio_direction_output(gpio, 1); ++ } ++ wifi_data.wifi_reset = gpio; ++ wifi_data.sdio_index = index; ++ ++ return 0; ++} ++EXPORT_SYMBOL(ingenic_sdio_wlan_init); ++int ingenic_sdio_wlan_get_irq(unsigned long *flag) ++{ ++ *flag = wifi_data.wifi_irq_flags; ++ return wifi_data.wifi_irq; ++} ++EXPORT_SYMBOL(ingenic_sdio_wlan_get_irq); ++int ingenic_sdio_wlan_power_onoff(int onoff, int flag) ++{ ++#if defined CONFIG_KP_AXP ++ int err = 0; ++#endif ++ int reset = wifi_data.wifi_reset; ++ if(!reset) ++ return -EINVAL; ++ if(onoff) { ++ printk("reset %d wlan power on:%d\n", reset, flag); ++#if defined CONFIG_KP_AXP ++ err = regulator_enable(wifi_data.wifi_regulator); ++#endif ++ rtc32k_enable(); ++ switch(flag) { ++ case RESET: ++ ingenic_mmc_clk_ctrl(wifi_data.sdio_index, 1); ++ gpio_set_value(reset, 0); ++ msleep(10); ++ gpio_set_value(reset, 1); ++ break; ++ case NORMAL: ++ gpio_set_value(reset, 1); ++ jzmmc_manual_detect(wifi_data.sdio_index, 1); ++ break; ++ } ++ } else { ++ printk("wlan power off:%d\n", flag); ++ switch(flag) { ++ case RESET: ++ gpio_set_value(reset, 0); ++ break; ++ case NORMAL: ++ gpio_set_value(reset, 0); ++ break; ++ } ++ rtc32k_disable(); ++#if defined CONFIG_KP_AXP ++ err = regulator_disable(wifi_data.wifi_regulator); ++#endif ++ } ++#if defined CONFIG_KP_AXP ++ if (err < 0) { ++ printk(("%s: regulator enable/disable failed", __FUNCTION__)); ++ return -1; ++ } ++#endif ++ return 0; ++ ++} ++EXPORT_SYMBOL(ingenic_sdio_wlan_power_onoff); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_host_sdhci-ingenic.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_host_sdhci-ingenic.c.patch new file mode 100644 index 00000000..58a4b9e1 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_host_sdhci-ingenic.c.patch @@ -0,0 +1,804 @@ +diff -drupN a/drivers/mmc/host/sdhci-ingenic.c b/drivers/mmc/host/sdhci-ingenic.c +--- a/drivers/mmc/host/sdhci-ingenic.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mmc/host/sdhci-ingenic.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,800 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include "sdhci.h" ++#include "sdhci-ingenic.h" ++ ++#define CLK_CTRL ++/* Software redefinition caps */ ++#define CAPABILITIES1_SW 0x276dc898 ++#define CAPABILITIES2_SW 0 ++ ++static LIST_HEAD(manual_list); ++#define CPM_MSC0_CLK_R (0xB0000068) ++#define CPM_MSC1_CLK_R (0xB000006C) ++#ifdef CONFIG_FPGA_TEST ++#define MSC_CLK_H_FREQ (0x1 << 20) ++ ++static void sdhci_ingenic_fpga_clk(unsigned int clock) ++{ ++#define CPM_MSC_CLK_R CPM_MSC0_CLK_R ++//#define CPM_MSC_CLK_R CPM_MSC1_CLK_R ++ unsigned int val; ++ ++ if(500000 <= clock){ ++ val = readl((const volatile void*)CPM_MSC_CLK_R); ++ val |= MSC_CLK_H_FREQ; ++ writel(val, (void*)CPM_MSC_CLK_R); ++ } else { ++ val = readl((const volatile void*)CPM_MSC_CLK_R); ++ val &= ~MSC_CLK_H_FREQ; ++ writel(val, (void*)CPM_MSC_CLK_R); ++ } ++ //printk("\tclk=%d, CPM_MSC0_CLK_R: %08x\n\n", clock, readl((const volatile void*)CPM_MSC0_CLK_R)); ++} ++#endif ++ ++static unsigned int sdhci_ingenic_get_cpm_msc(struct sdhci_host *host) ++{ ++ char msc_ioaddr[16]; ++ unsigned int cpm_msc; ++ sprintf(msc_ioaddr, "0x%x", (unsigned int)host->ioaddr); ++ ++ if (!strcmp(msc_ioaddr ,"0xb3060000")) ++ cpm_msc = CPM_MSC0_CLK_R; ++ if (!strcmp(msc_ioaddr ,"0xb3070000")) ++ cpm_msc = CPM_MSC1_CLK_R; ++ return cpm_msc; ++} ++ ++/** ++ * sdhci_ingenic_msc_tuning Enable msc controller tuning ++ * ++ * Tuning rx phase ++ * */ ++static void sdhci_ingenic_en_msc_tuning(struct sdhci_host *host, unsigned int cpm_msc) ++{ ++ if (host->flags & SDHCI_SDR50_NEEDS_TUNING || ++ host->flags & SDHCI_SDR104_NEEDS_TUNING || ++ host->flags & SDHCI_HS400_TUNING) { ++ *(volatile unsigned int*)cpm_msc &= ~(0x1 << 20); ++ } ++} ++ ++static void sdhci_ingenic_sel_rx_phase(unsigned int cpm_msc) ++{ ++ *(volatile unsigned int*)cpm_msc |= (0x1 << 20); // default ++ ++ *(volatile unsigned int*)cpm_msc &= ~(0x7 << 17); ++ *(volatile unsigned int*)cpm_msc |= (0x7 << 17); // OK RX 90 TX 270 ++} ++ ++static void sdhci_ingenic_sel_tx_phase(unsigned int cpm_msc) ++{ ++ *(volatile unsigned int*)cpm_msc &= ~(0x3 << 15); ++/* *(volatile unsigned int*)cpm_msc |= (0x2 << 15); // 180 100M OK*/ ++ *(volatile unsigned int*)cpm_msc |= (0x3 << 15); ++} ++ ++/** ++ * sdhci_ingenic_set_clock - callback on clock change ++ * @host: The SDHCI host being changed ++ * @clock: The clock rate being requested. ++ * ++ * When the card's clock is going to be changed, look at the new frequency ++ * and find the best clock source to go with it. ++*/ ++static void sdhci_ingenic_set_clock(struct sdhci_host *host, unsigned int clock) ++{ ++#ifndef CONFIG_FPGA_TEST ++ struct sdhci_ingenic *sdhci_ing = sdhci_priv(host); ++ unsigned int cpm_msc = sdhci_ingenic_get_cpm_msc(host); ++ char clkname[16]; ++ ++ ++ if (clock == 0) ++ return; ++ ++ sdhci_set_clock(host, clock); ++ ++ spin_unlock_irq(&host->lock); ++ sprintf(clkname, "mux_msc%d", sdhci_ing->pdev->id); ++ sdhci_ing->clk_mux = clk_get(NULL, clkname); ++ ++ if (clock > 400000) { ++ clk_set_parent(sdhci_ing->clk_mux, sdhci_ing->clk_mpll); ++ } else { ++ clk_set_parent(sdhci_ing->clk_mux, sdhci_ing->clk_ext); ++ *(volatile unsigned int *)0xB0000068 |= 1 << 21; ++ } ++ ++ clk_set_rate(sdhci_ing->clk_cgu, clock); ++ ++ spin_lock_irq(&host->lock); ++ //printk("%s, set clk: %d, get_clk_rate=%ld\n", __func__, clock, clk_get_rate(sdhci_ing->clk_cgu)); ++ ++ if (host->mmc->ios.timing == MMC_TIMING_MMC_HS200 || ++ host->mmc->ios.timing == MMC_TIMING_UHS_SDR104) { ++ ++ /* RX phase selecte */ ++ if (sdhci_ing->pdata->enable_cpm_rx_tuning == 1) ++ sdhci_ingenic_sel_rx_phase(cpm_msc); ++ else ++ sdhci_ingenic_en_msc_tuning(host, cpm_msc); ++ /* TX phase selecte */ ++ if (sdhci_ing->pdata->enable_cpm_tx_tuning == 1) ++ sdhci_ingenic_sel_tx_phase(cpm_msc); ++ } ++#else //CONFIG_FPGA_TEST ++ sdhci_ingenic_fpga_clk(clock); ++#endif ++} ++ ++#ifdef VOLTAGE_SWITCH ++static void sdhci_ingenic_set_cpm_poc(int power_v18) ++{ ++ if (power_v18) { ++ cpm_outl(0x8, CPM_POC); ++ } else { ++ cpm_outl(0x0, CPM_POC); ++ } ++ ++ return; ++} ++#endif ++ ++/* I/O Driver Strength Types */ ++#define INGENIC_TYPE_0 0x0 //30 ++#define INGENIC_TYPE_1 0x1 //50 ++#define INGENIC_TYPE_2 0x2 //66 ++#define INGENIC_TYPE_3 0x3 //100 ++ ++static int sdhci_ingenic_select_drive_strength(struct sdhci_host *host, ++ struct mmc_card *card, ++ unsigned int max_dtr, ++ int host_drv, int card_drv, int *drv_type) ++{ ++ int drive_strength, type; ++ ++ type = INGENIC_TYPE_1; ++ ++ switch (type) { ++ case INGENIC_TYPE_0: ++ /* Type 0: 50 */ ++ *(volatile unsigned int*)(0xb0010500 + 0xb8) |= 0xfff; ++ *(volatile unsigned int*)(0xb0010500 + 0xb4) |= 0x555; ++ drive_strength = 0; ++ break; ++ case INGENIC_TYPE_1: ++ /* Type 1: 33 */ ++ *(volatile unsigned int*)(0xb0010500 + 0xb8) |= 0xfff; ++ *drv_type = MMC_CAP_DRIVER_TYPE_A; // GPIO DRV_STR ++ drive_strength = 1; ++ break; ++ case INGENIC_TYPE_2: ++ /* Type 2: 66 */ ++ *(volatile unsigned int*)(0xb0010500 + 0xb8) |= 0xfff; ++ *(volatile unsigned int*)(0xb0010500 + 0xb4) |= 0xaaa; ++ *drv_type = MMC_CAP_DRIVER_TYPE_C; // GPIO DRV_STR ++ drive_strength = 2; ++ break; ++ case INGENIC_TYPE_3: ++ /* Type 3: 100 */ ++ *(volatile unsigned int*)(0xb0010500 + 0xb8) |= 0xfff; ++ *(volatile unsigned int*)(0xb0010500 + 0xb4) |= 0xfff; ++ *drv_type = MMC_CAP_DRIVER_TYPE_D; // GPIO DRV_STR ++ drive_strength = 3; ++ break; ++ } ++ ++ return drive_strength; ++} ++ ++#ifdef VOLTAGE_SWITCH ++void sdhci_ingenic_voltage_switch(struct sdhci_host *host) ++{ ++ struct sdhci_ingenic *sdhci_ing = sdhci_priv(host); ++ struct sdhci_ingenic_pdata *pdata = sdhci_ing->pdata; ++ unsigned int val; ++ ++ if (pdata->sdr_v18 < 0) ++ return; ++ ++ /*controlled SD voltage to 1.8V*/ ++ val = cpm_inl(CPM_EXCLK_DS) | (1 << 31); ++ cpm_outl(val, CPM_EXCLK_DS); ++ ++ /*Set up hardware circuit 1.8V*/ ++ val = pdata->sdr_v18; ++ ++ gpio_direction_output(val, 1); ++} ++#endif ++ ++static struct sdhci_ops sdhci_ingenic_ops = { ++ .set_clock = sdhci_ingenic_set_clock, ++ .set_bus_width = sdhci_set_bus_width, ++ .reset = sdhci_reset, ++ .set_uhs_signaling = sdhci_set_uhs_signaling, ++ .select_drive_strength = sdhci_ingenic_select_drive_strength, ++#ifdef VOLTAGE_SWITCH ++ .voltage_switch = sdhci_ingenic_voltage_switch, ++#endif ++}; ++ ++static void sdhci_ingenic_notify_change(struct platform_device *dev, int state) ++{ ++ struct sdhci_host *host = platform_get_drvdata(dev); ++ struct sdhci_ingenic *sdhci_ing = sdhci_priv(host); ++ struct sdhci_ingenic_pdata *pdata = sdhci_ing->pdata; ++ unsigned long flags, val; ++ ++ if (host) { ++ spin_lock_irqsave(&host->lock, flags); ++ if (state) { ++ printk("%s: card inserted\n", mmc_hostname(host->mmc)); ++ host->flags &= ~SDHCI_DEVICE_DEAD; ++ host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION; ++ ++ mmc_detect_change(host->mmc, 0); ++ } else { ++ printk("%s: card removed\n", mmc_hostname(host->mmc)); ++ host->flags |= SDHCI_DEVICE_DEAD; ++ host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; ++#ifdef VOLTAGE_SWITCH ++ if (pdata->sdr_v18 > 0) { ++ gpio_direction_output(pdata->sdr_v18, 0); ++ ++ val = cpm_inl(CPM_EXCLK_DS) & ~(1 << 31); ++ cpm_outl(val, CPM_EXCLK_DS); ++ } ++#endif ++ mmc_detect_change(host->mmc, 0); ++ } ++ tasklet_schedule(&host->finish_tasklet); ++ spin_unlock_irqrestore(&host->lock, flags); ++ } ++} ++ ++static irqreturn_t sdhci_ingenic_gpio_card_detect_thread(int irq, void *dev_id) ++{ ++ struct sdhci_ingenic *sdhci_ing = (struct sdhci_ingenic *)dev_id; ++ int status = gpio_get_value(sdhci_ing->ext_cd_gpio); ++ ++ if (!(sdhci_ing->pdata->gpio->cd.enable_level)) ++ status = !status; ++ sdhci_ingenic_notify_change(sdhci_ing->pdev, status); ++ return IRQ_HANDLED; ++} ++ ++static void sdhci_ingenic_setup_card_detect_gpio(struct sdhci_ingenic *sdhci_ing) ++{ ++ struct sdhci_ingenic_pdata *pdata = sdhci_ing->pdata; ++ struct device *dev = &sdhci_ing->pdev->dev; ++ ++ if (devm_gpio_request(dev, pdata->gpio->cd.num, "SDHCI EXT CD") == 0) { ++ sdhci_ing->ext_cd_gpio = pdata->gpio->cd.num; ++ sdhci_ing->ext_cd_irq = gpio_to_irq(pdata->gpio->cd.num); ++ if (sdhci_ing->ext_cd_irq && ++ request_threaded_irq(sdhci_ing->ext_cd_irq, NULL, ++ sdhci_ingenic_gpio_card_detect_thread, ++ IRQF_TRIGGER_RISING | ++ IRQF_TRIGGER_FALLING | ++ IRQF_ONESHOT, ++ dev_name(dev), sdhci_ing) == 0) { ++ int status = gpio_get_value(sdhci_ing->ext_cd_gpio); ++ if (!(pdata->gpio->cd.enable_level)) ++ status = !status; ++ sdhci_ingenic_notify_change(sdhci_ing->pdev, status); ++ } else { ++ dev_warn(dev, "cannot request irq for card detect\n"); ++ sdhci_ing->ext_cd_irq = 0; ++ } ++ } else { ++ dev_err(dev, "cannot request gpio for card detect\n"); ++ } ++} ++ ++#ifdef CONFIG_OF ++static void ingenic_mmc_get_gpio(struct device_node *np, ++ struct ingenic_mmc_pin *pin, char *gpioname) ++{ ++ int gpio; ++ enum of_gpio_flags flags; ++ ++ pin->num = -EBUSY; ++ gpio = of_get_named_gpio_flags(np, gpioname, 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ pin->num = gpio; ++ pin->enable_level = ++ (flags == OF_GPIO_ACTIVE_LOW ? LOW_ENABLE : HIGH_ENABLE); ++ //printk("mmc gpio %s num:%d en-level: %d\n", gpioname, pin->num, pin->enable_level); ++ } ++} ++ ++static inline void ingenic_mmc_clk_onoff(struct sdhci_ingenic *ingenic_ing, unsigned int on) ++{ ++ if(on) { ++ clk_prepare_enable(ingenic_ing->clk_cgu); ++ clk_prepare_enable(ingenic_ing->clk_gate); ++ } else { ++ clk_disable_unprepare(ingenic_ing->clk_cgu); ++ clk_disable_unprepare(ingenic_ing->clk_gate); ++ } ++} ++ ++/** ++ * jzmmc_manual_detect - insert or remove card manually ++ * @index: host->index, namely the index of the controller. ++ * @on: 1 means insert card, 0 means remove card. ++ * ++ * This functions will be called by manually card-detect driver such as ++ * wifi. To enable this mode you can set value pdata.removal = MANUAL. ++ */ ++int jzmmc_manual_detect(int index, int on) ++{ ++ struct sdhci_ingenic *sdhci_ing; ++ struct sdhci_host *host; ++ struct list_head *pos; ++ ++ list_for_each(pos, &manual_list) { ++ sdhci_ing = list_entry(pos, struct sdhci_ingenic, list); ++ if (sdhci_ing->pdev->id == index) { ++ break; ++ } else ++ sdhci_ing = NULL; ++ } ++ ++ if(!sdhci_ing) { ++ printk("no manual card detect\n"); ++ return -1; ++ } ++ ++ host = sdhci_ing->host; ++ ++ if (on) { ++ dev_err(&sdhci_ing->pdev->dev, "card insert manually\n"); ++ set_bit(INGENIC_MMC_CARD_PRESENT, &sdhci_ing->flags); ++#ifdef CLK_CTRL ++ ingenic_mmc_clk_onoff(sdhci_ing, 1); ++#endif ++ host->flags &= ~SDHCI_DEVICE_DEAD; ++ host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION; ++ mmc_detect_change(sdhci_ing->host->mmc, 0); ++ } else { ++ dev_err(&sdhci_ing->pdev->dev, "card remove manually\n"); ++ clear_bit(INGENIC_MMC_CARD_PRESENT, &sdhci_ing->flags); ++ ++ host->flags |= SDHCI_DEVICE_DEAD; ++ host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; ++ mmc_detect_change(sdhci_ing->host->mmc, 0); ++#ifdef CLK_CTRL ++ ingenic_mmc_clk_onoff(sdhci_ing, 0); ++#endif ++ } ++ ++ tasklet_schedule(&host->finish_tasklet); ++ ++ return 0; ++} ++EXPORT_SYMBOL(jzmmc_manual_detect); ++ ++/** ++ * ingenic_mmc_clk_ctrl - enable or disable msc clock gate ++ * @index: host->index, namely the index of the controller. ++ * @on: 1-enable msc clock gate, 0-disable msc clock gate. ++ */ ++int ingenic_mmc_clk_ctrl(int index, int on) ++{ ++ struct sdhci_ingenic *sdhci_ing; ++ struct list_head *pos; ++ ++#ifdef CLK_CTRL ++ list_for_each(pos, &manual_list) { ++ sdhci_ing = list_entry(pos, struct sdhci_ingenic, list); ++ if (sdhci_ing->pdev->id == index) ++ break; ++ else ++ sdhci_ing = NULL; ++ } ++ ++ if (!sdhci_ing) { ++ printk("no manual card detect\n"); ++ return -1; ++ } ++ ingenic_mmc_clk_onoff(sdhci_ing, on); ++#endif ++ return 0; ++} ++EXPORT_SYMBOL(ingenic_mmc_clk_ctrl); ++ ++static int sdhci_ingenic_parse_dt(struct device *dev, ++ struct sdhci_host *host, ++ struct sdhci_ingenic_pdata *pdata) ++{ ++ struct device_node *np = dev->of_node; ++ struct card_gpio *card_gpio; ++ unsigned int val; ++ ++ card_gpio = devm_kzalloc(dev, sizeof(struct card_gpio), GFP_KERNEL); ++ if(!card_gpio) ++ return 0; ++ ++ ingenic_mmc_get_gpio(np, &card_gpio->rst, "ingenic,rst-gpios"); ++ ingenic_mmc_get_gpio(np, &card_gpio->wp, "ingenic,wp-gpios"); ++ ingenic_mmc_get_gpio(np, &card_gpio->pwr, "ingenic,pwr-gpios"); ++ ingenic_mmc_get_gpio(np, &card_gpio->cd, "ingenic,cd-gpios"); ++ pdata->gpio = card_gpio; ++ ++ ++ pdata->sdr_v18 = of_get_named_gpio(np, "ingenic,sdr-gpios", 0); ++ ++ /* assuming internal card detect that will be configured by pinctrl */ ++ pdata->cd_type = SDHCI_INGENIC_CD_INTERNAL; ++ ++ if(of_property_read_bool(np, "pio-mode")) { ++ pdata->pio_mode = 1; ++ } ++ if(of_property_read_bool(np, "enable_autocmd12")) { ++ pdata->enable_autocmd12 = 1; ++ } ++ if(of_property_read_bool(np, "enable_cpm_rx_tuning")) { ++ pdata->enable_cpm_rx_tuning = 1; ++ } ++ if(of_property_read_bool(np, "enable_cpm_tx_tuning")) { ++ pdata->enable_cpm_tx_tuning = 1; ++ } ++ ++ /* get the card detection method */ ++ if (of_get_property(np, "broken-cd", NULL)) { ++ pdata->cd_type = SDHCI_INGENIC_CD_NONE; ++ } ++ ++ if (of_get_property(np, "non-removable", NULL)) { ++ pdata->cd_type = SDHCI_INGENIC_CD_PERMANENT; ++ } ++ ++ if (of_get_property(np, "cd-inverted", NULL)) { ++ pdata->cd_type = SDHCI_INGENIC_CD_GPIO; ++ } ++ ++ if(!(of_property_read_u32(np, "ingenic,sdio_clk", &val))) ++ pdata->sdio_clk = val; ++ ++ /*set Power-On-Control Select of GPIO PE group*/ ++ if(of_property_read_bool(np, "ingenic,poc-v1.8")) { ++ pdata->poc_v18 = 1; ++ } ++ ++ /* if(of_property_read_bool(np, "ingenic,removal-dontcare")) { */ ++ /* pdata->removal = DONTCARE; */ ++ /* } else if(of_property_read_bool(np, "ingenic,removal-nonremovable")) { */ ++ /* pdata->removal = NONREMOVABLE; */ ++ /* } else if(of_property_read_bool(np, "ingenic,removal-removable")) { */ ++ /* pdata->removal = REMOVABLE; */ ++ /* } else if(of_property_read_bool(np, "ingenic,removal-manual")) { */ ++ /* pdata->removal = MANUAL; */ ++ /* }; */ ++ ++ /* mmc_of_parse_voltage(np, &pdata->ocr_avail); */ ++ ++ return 0; ++} ++#else ++static int sdhci_ingenic_parse_dt(struct device *dev, ++ struct sdhci_host *host, ++ struct sdhci_ingenic_pdata *pdata) ++{ ++ return -EINVAL; ++} ++#endif ++ ++static int sdhci_ingenic_probe(struct platform_device *pdev) ++{ ++ struct sdhci_ingenic_pdata *pdata; ++ struct device *dev = &pdev->dev; ++ struct sdhci_host *host; ++ struct sdhci_ingenic *sdhci_ing; ++ char clkname[16]; ++ int ret, irq; ++ ++ if (!pdev->dev.platform_data && !pdev->dev.of_node) { ++ dev_err(dev, "no device data specified\n"); ++ return -ENOENT; ++ } ++ ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) { ++ dev_err(dev, "no irq specified\n"); ++ return irq; ++ } ++ ++ host = sdhci_alloc_host(dev, sizeof(struct sdhci_ingenic)); ++ if (IS_ERR(host)) { ++ dev_err(dev, "sdhci_alloc_host() failed\n"); ++ return PTR_ERR(host); ++ } ++ sdhci_ing = sdhci_priv(host); ++ ++ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); ++ if (!pdata) { ++ ret = -ENOMEM; ++ return ret; ++ } ++ ++ if (pdev->dev.of_node) { ++ ret = sdhci_ingenic_parse_dt(&pdev->dev, host, pdata); ++ if (ret) ++ return ret; ++ } else { ++ memcpy(pdata, pdev->dev.platform_data, sizeof(*pdata)); ++ } ++ ++ pdev->id = of_alias_get_id(pdev->dev.of_node, "msc"); ++ ++ sprintf(clkname, "div_msc%d", pdev->id); ++ sdhci_ing->clk_cgu = devm_clk_get(&pdev->dev, clkname); ++ if(!sdhci_ing->clk_cgu) { ++ dev_err(&pdev->dev, "Failed to Get MSC clk!\n"); ++ return PTR_ERR(sdhci_ing->clk_cgu); ++ } ++ sprintf(clkname, "gate_msc%d", pdev->id); ++ sdhci_ing->clk_gate = devm_clk_get(&pdev->dev, clkname); ++ if(!sdhci_ing->clk_gate) { ++ dev_err(&pdev->dev, "Failed to Get PWC MSC clk!\n"); ++ return PTR_ERR(sdhci_ing->clk_gate); ++ } ++ sdhci_ing->clk_ext = clk_get(NULL, "ext"); ++ sdhci_ing->clk_mpll = clk_get(NULL, "mpll"); ++ ++ ingenic_mmc_clk_onoff(sdhci_ing, 1); ++ ++ sdhci_ing->host = host; ++ sdhci_ing->dev = &pdev->dev; ++ sdhci_ing->pdev = pdev; ++ sdhci_ing->pdata = pdata; ++ ++ host->ioaddr= of_iomap(pdev->dev.of_node, 0); ++ if (IS_ERR(host->ioaddr)) { ++ return PTR_ERR(host->ioaddr); ++ } ++ ++ platform_set_drvdata(pdev, host); ++ ++#ifdef VOLTAGE_SWITCH ++ if (pdata->poc_v18){ ++ sdhci_ingenic_set_cpm_poc(1); ++ } else { ++ sdhci_ingenic_set_cpm_poc(0); ++ } ++#endif ++ ++ /* sdio for WIFI init*/ ++ if (pdata->sdio_clk) { ++ ingenic_sdio_wlan_init(&pdev->dev, pdev->id); ++ list_add(&(sdhci_ing->list), &manual_list); ++ } ++ ++ if (pdata->sdr_v18 > 0 && \ ++ devm_gpio_request(dev, pdata->sdr_v18, "sdr-v18")) { ++ printk("ERROR: no sdr-v18 pin available !!\n"); ++ } ++ ++ host->hw_name = "ingenic-sdhci"; ++ host->ops = &sdhci_ingenic_ops; ++ host->quirks = 0; ++ host->irq = irq; ++ ++ /* Software redefinition caps */ ++ host->quirks |= SDHCI_QUIRK_MISSING_CAPS; ++ host->caps = CAPABILITIES1_SW; ++ host->caps1 = CAPABILITIES2_SW; ++ ++ /* not check wp */ ++ host->quirks |= SDHCI_QUIRK_INVERTED_WRITE_PROTECT; ++ ++ /* Setup quirks for the controller */ ++ host->quirks |= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC; ++ host->quirks |= SDHCI_QUIRK_NO_HISPD_BIT; ++ ++ /* Data Timeout Counter Value */ ++ //host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; ++ host->timeout_clk = 24000; //TMCLK = 24MHz ++ ++ /* This host supports the Auto CMD12 */ ++ if(pdata->enable_autocmd12) ++ host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12; ++ ++ /* PIO transfer mode */ ++ if(pdata->pio_mode){ ++ host->quirks |= SDHCI_QUIRK_BROKEN_DMA; ++ host->quirks |= SDHCI_QUIRK_BROKEN_ADMA; ++ } ++ /* TODO:SoCs need BROKEN_ADMA_ZEROLEN_DESC */ ++/* host->quirks |= SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC;*/ ++ ++ if (pdata->cd_type == SDHCI_INGENIC_CD_NONE || ++ pdata->cd_type == SDHCI_INGENIC_CD_PERMANENT) ++ host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION; ++ ++ if (pdata->cd_type == SDHCI_INGENIC_CD_PERMANENT) ++ host->mmc->caps = MMC_CAP_NONREMOVABLE; ++ ++ if (pdata->pm_caps) ++ host->mmc->pm_caps |= pdata->pm_caps; ++ ++ host->quirks |= (SDHCI_QUIRK_32BIT_DMA_ADDR | ++ SDHCI_QUIRK_32BIT_DMA_SIZE); ++ ++ /* It supports additional host capabilities if needed */ ++ if (pdata->host_caps) ++ host->mmc->caps |= pdata->host_caps; ++ ++ if (pdata->host_caps2) ++ host->mmc->caps2 |= pdata->host_caps2; ++ ++#ifdef CONFIG_PM_RUNTIME ++ pm_runtime_enable(&pdev->dev); ++ pm_runtime_set_autosuspend_delay(&pdev->dev, 50); ++ pm_runtime_use_autosuspend(&pdev->dev); ++ pm_suspend_ignore_children(&pdev->dev, 1); ++#endif ++ ++ ret = mmc_of_parse(host->mmc); ++ if (ret) { ++ dev_err(dev, "mmc_of_parse() failed\n"); ++ pm_runtime_forbid(&pdev->dev); ++ pm_runtime_get_noresume(&pdev->dev); ++ return ret; ++ } ++ ++ ret = sdhci_add_host(host); ++ if (ret) { ++ dev_err(dev, "sdhci_add_host() failed\n"); ++ pm_runtime_forbid(&pdev->dev); ++ pm_runtime_get_noresume(&pdev->dev); ++ return ret; ++ } ++ ++ if (pdata->cd_type == SDHCI_INGENIC_CD_GPIO && ++ gpio_is_valid(pdata->gpio->cd.num)) ++ sdhci_ingenic_setup_card_detect_gpio(sdhci_ing); ++ ++#ifdef CONFIG_PM_RUNTIME ++ if (pdata->cd_type != SDHCI_INGENIC_CD_INTERNAL) { ++ clk_disable_unprepare(sdhci_ing->clk_cgu); ++ /* clk_disable_unprepare(sdhci_ing->clk_gate); */ ++ } ++#endif ++ ++ return 0; ++} ++ ++static int sdhci_ingenic_remove(struct platform_device *pdev) ++{ ++ struct sdhci_host *host = platform_get_drvdata(pdev); ++ struct sdhci_ingenic *sdhci_ing = sdhci_priv(host); ++ ++ if (sdhci_ing->ext_cd_irq) ++ free_irq(sdhci_ing->ext_cd_irq, sdhci_ing); ++ ++#ifdef CONFIG_PM_RUNTIME ++ if (pdata->cd_type != SDHCI_INGENIC_CD_INTERNAL){ ++ /* clk_prepare_enable(sdhci_ing->clk_gate); */ ++ clk_prepare_enable(sdhci_ing->clk_cgu); ++ } ++#endif ++ sdhci_remove_host(host, 1); ++ ++ pm_runtime_dont_use_autosuspend(&pdev->dev); ++ pm_runtime_disable(&pdev->dev); ++ ++ clk_disable_unprepare(sdhci_ing->clk_cgu); ++ /* clk_disable_unprepare(sdhci_ing->clk_gate); */ ++ ++ sdhci_free_host(host); ++ platform_set_drvdata(pdev, NULL); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int sdhci_ingenic_suspend(struct device *dev) ++{ ++ struct sdhci_host *host = dev_get_drvdata(dev); ++ struct sdhci_ingenic *sdhci_ing = sdhci_priv(host) ; ++ ++ ingenic_mmc_clk_onoff(sdhci_ing, 0); ++ ++ return sdhci_suspend_host(host); ++} ++ ++static int sdhci_ingenic_resume(struct device *dev) ++{ ++ struct sdhci_host *host = dev_get_drvdata(dev); ++ struct sdhci_ingenic *sdhci_ing = sdhci_priv(host) ; ++ ++ ingenic_mmc_clk_onoff(sdhci_ing, 1); ++ ++ return sdhci_resume_host(host); ++} ++#endif ++ ++#ifdef CONFIG_PM ++static int sdhci_ingenic_runtime_suspend(struct device *dev) ++{ ++ return 0; ++} ++ ++ ++static int sdhci_ingenic_runtime_resume(struct device *dev) ++{ ++ return 0; ++} ++#endif ++ ++#ifdef CONFIG_PM ++static const struct dev_pm_ops sdhci_ingenic_pmops = { ++ SET_SYSTEM_SLEEP_PM_OPS(sdhci_ingenic_suspend, sdhci_ingenic_resume) ++ SET_RUNTIME_PM_OPS(sdhci_ingenic_runtime_suspend, sdhci_ingenic_runtime_resume, ++ NULL) ++}; ++ ++#define SDHCI_INGENIC_PMOPS (&sdhci_ingenic_pmops) ++ ++#else ++#define SDHCI_INGENIC_PMOPS NULL ++#endif ++ ++ ++static struct platform_device_id sdhci_ingenic_driver_ids[] = { ++ { ++ .name = "ingenic,sdhci", ++ .driver_data = (kernel_ulong_t)NULL, ++ }, ++ { } ++}; ++MODULE_DEVICE_TABLE(platform, sdhci_ingenic_driver_ids); ++ ++#ifdef CONFIG_OF ++static const struct of_device_id sdhci_ingenic_dt_match[] = { ++ {.compatible = "ingenic,sdhci",}, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, sdhci_ingenic_dt_match); ++#endif ++ ++static struct platform_driver sdhci_ingenic_driver = { ++ .probe = sdhci_ingenic_probe, ++ .remove = sdhci_ingenic_remove, ++ .id_table = sdhci_ingenic_driver_ids, ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = "ingenic,sdhci", ++ .pm = SDHCI_INGENIC_PMOPS, ++ .of_match_table = of_match_ptr(sdhci_ingenic_dt_match), ++ }, ++}; ++ ++module_platform_driver(sdhci_ingenic_driver); ++ ++ ++MODULE_DESCRIPTION("Ingenic SDHCI (MSC) driver"); ++MODULE_AUTHOR("Large Dipper "); ++MODULE_LICENSE("GPL v2"); ++MODULE_VERSION("20160808"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_host_sdhci-ingenic.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_host_sdhci-ingenic.h.patch new file mode 100644 index 00000000..01237acd --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_host_sdhci-ingenic.h.patch @@ -0,0 +1,101 @@ +diff -drupN a/drivers/mmc/host/sdhci-ingenic.h b/drivers/mmc/host/sdhci-ingenic.h +--- a/drivers/mmc/host/sdhci-ingenic.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mmc/host/sdhci-ingenic.h 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,97 @@ ++#ifndef __SDHCI_INGENIC_H__ ++#define __SDHCI_INGENIC_H__ ++ ++#include ++#include "ingenic_mmc_reg.h" ++enum cd_types { ++ SDHCI_INGENIC_CD_INTERNAL, /* use mmc internal CD line */ ++ SDHCI_INGENIC_CD_GPIO, /* use external gpio pin for CD line */ ++ SDHCI_INGENIC_CD_NONE, /* no CD line, use polling to detect card */ ++ SDHCI_INGENIC_CD_PERMANENT, /* no CD line, card permanently wired to host */ ++}; ++ ++ ++#define LOW_ENABLE 0 ++#define HIGH_ENABLE 1 ++struct ingenic_mmc_pin { ++ short num; ++ short enable_level; ++}; ++ ++struct card_gpio { ++ struct ingenic_mmc_pin wp; ++ struct ingenic_mmc_pin cd; ++ struct ingenic_mmc_pin pwr; ++ struct ingenic_mmc_pin rst; ++}; ++ ++/** ++ * struct sdhci_ingenic_platdata() - Platform device data for ingenic SDHCI ++ * @max_width: The maximum number of data bits supported. ++ * @host_caps: Standard MMC host capabilities bit field. ++ * @host_caps2: The second standard MMC host capabilities bit field. ++ * @sdr_v18: External gpio pin switch voltage from 3.3V to 1.8V ++ * @cd_type: Type of Card Detection method (see cd_types enum above) ++ * @enable_cpm_rx_tunning: Manual adjustment cpm rx tunting ++ * @enable_cpm_tx_tunning: Manual adjustment cpm tx tunting ++ * @ext_cd_gpio_invert: invert values for external CD gpio line ++ * @cfg_gpio: Configure the GPIO for a specific card bit-width ++ * ++ * Initialisation data specific to either the machine or the platform ++ * for the device driver to use or call-back when configuring gpio or ++ * card speed information. ++ */ ++struct sdhci_ingenic_pdata { ++ unsigned int host_caps; ++ unsigned int host_caps2; ++ unsigned short sdio_clk; ++ int sdr_v18; ++ unsigned int poc_v18; ++ unsigned int pm_caps; ++ enum cd_types cd_type; ++ ++ unsigned int pio_mode; ++ unsigned int enable_autocmd12; ++ ++ struct card_gpio *gpio; ++ int enable_cpm_rx_tuning; ++ int enable_cpm_tx_tuning; ++ bool ext_cd_gpio_invert; ++ ++ void (*cfg_gpio)(struct platform_device *dev, int width); ++ int (*private_init)(void); ++}; ++ ++ ++#define INGENIC_MMC_CARD_PRESENT 0 ++#define INGENIC_MMC_CARD_NEED_INIT 1 ++#define INGENIC_MMC_USE_PIO 2 ++/** ++ * struct sdhci_ingenic - INGENIC SDHCI instance ++ * @host: The SDHCI host created ++ * @pdev: The platform device we where created from. ++ * @ioarea: The resource created when we claimed the IO area. ++ * @pdata: The platform data for this controller. ++ */ ++struct sdhci_ingenic { ++ struct device *dev; ++ struct sdhci_host *host; ++ struct platform_device *pdev; ++ struct device_node *node; ++ struct sdhci_ingenic_pdata *pdata; ++ struct list_head list; ++ struct clk *clk_cgu; ++ struct clk *clk_gate; ++ struct clk *clk_ext; ++ struct clk *clk_mux; ++ struct clk *clk_mpll; ++ int cur_clk; ++ int ext_cd_irq; ++ int ext_cd_gpio; ++ unsigned long clk_rates; ++ unsigned long flags; ++}; ++ ++int ingenic_sdio_wlan_init(struct device *dev, int index); ++int ingenic_mmc_clk_ctrl(int index, int on); ++#endif /* __SDHCI_INGENIC_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_host_sdhci.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_host_sdhci.c.patch new file mode 100644 index 00000000..d28c9cb4 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mmc_host_sdhci.c.patch @@ -0,0 +1,16 @@ +diff -drupN a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c +--- a/drivers/mmc/host/sdhci.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/mmc/host/sdhci.c 2022-06-09 05:02:30.000000000 +0300 +@@ -2937,9 +2937,9 @@ int sdhci_add_host(struct sdhci_host *ho + host->version = (host->version & SDHCI_SPEC_VER_MASK) + >> SDHCI_SPEC_VER_SHIFT; + if (host->version > SDHCI_SPEC_300) { +- pr_err("%s: Unknown controller version (%d). " +- "You may experience problems.\n", mmc_hostname(mmc), +- host->version); ++ /*pr_err("%s: Unknown controller version (%d). " \ ++ "You may experience problems.\n", mmc_hostname(mmc), \ ++ host->version);*/ + } + + caps[0] = (host->quirks & SDHCI_QUIRK_MISSING_CAPS) ? host->caps : diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_Kconfig.patch new file mode 100644 index 00000000..9fb6e153 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_Kconfig.patch @@ -0,0 +1,13 @@ +diff -drupN a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig +--- a/drivers/mtd/devices/Kconfig 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/mtd/devices/Kconfig 2022-06-09 05:02:30.000000000 +0300 +@@ -233,4 +233,9 @@ config BCH_CONST_T + default 4 + endif + ++ ++source "drivers/mtd/devices/ingenic_sfc_v1/Kconfig" ++source "drivers/mtd/devices/ingenic_sfc_v2/Kconfig" ++ ++ + endmenu diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_Makefile.patch new file mode 100644 index 00000000..43f7759d --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_Makefile.patch @@ -0,0 +1,11 @@ +diff -drupN a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile +--- a/drivers/mtd/devices/Makefile 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/mtd/devices/Makefile 2022-06-09 05:02:30.000000000 +0300 +@@ -18,5 +18,7 @@ obj-$(CONFIG_MTD_BCM47XXSFLASH) += bcm47 + obj-$(CONFIG_MTD_ST_SPI_FSM) += st_spi_fsm.o + obj-$(CONFIG_MTD_POWERNV_FLASH) += powernv_flash.o + ++obj-y += ingenic_sfc_v1/ ++obj-y += ingenic_sfc_v2/ + + CFLAGS_docg3.o += -I$(src) diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_Kconfig.patch new file mode 100644 index 00000000..fb58c793 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_Kconfig.patch @@ -0,0 +1,48 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v1/Kconfig b/drivers/mtd/devices/ingenic_sfc_v1/Kconfig +--- a/drivers/mtd/devices/ingenic_sfc_v1/Kconfig 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v1/Kconfig 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,44 @@ ++config INGENIC_SFC_V1 ++ tristate "Ingenic series SFC driver v1" ++ depends on MACH_XBURST || MACH_XBURST2 ++ help ++ SFC driver version v1.0 for Ingenic series SoCs ++ ++if INGENIC_SFC_V1 ++ ++choice ++ prompt "the SFC external memory (nor or nand)" ++ help ++ Select the SFC external memory ++ ++config MTD_INGENIC_SFC_V1_NORFLASH ++ bool "Support ingenic sfc-nor" ++ depends on INGENIC_SFC_V1 ++ ++config MTD_INGENIC_SFC_V1_NANDFLASH ++ bool "Support ingenic sfc-nand" ++ depends on INGENIC_SFC_V1 ++ select MTD_NAND ++ ++endchoice ++ ++choice ++ prompt "sfc Mode" ++ help ++ Select sfc Mode ++ ++config SPI_STANDARD ++ bool "standard spi mode" ++ depends on INGENIC_SFC_V1 ++ help ++ Say Y here to enable spi STANDARD MODE ++ ++config SPI_QUAD ++ bool "quad spi mode" ++ depends on INGENIC_SFC_V1 ++ help ++ Say Y Here to enable spi QUAD MODE ++endchoice ++ ++endif ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_Makefile.patch new file mode 100644 index 00000000..a9051a6f --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_Makefile.patch @@ -0,0 +1,11 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v1/Makefile b/drivers/mtd/devices/ingenic_sfc_v1/Makefile +--- a/drivers/mtd/devices/ingenic_sfc_v1/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v1/Makefile 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,7 @@ ++# ++# linux/drivers/mtd/devices/ingenic_sfc_v1/Makefile ++# ++ ++obj-$(CONFIG_MTD_INGENIC_SFC_V1_NORFLASH) += ingenic_sfc_common.o ingenic_sfc_nor.o ingenic_sfc_ops.o ++obj-$(CONFIG_MTD_INGENIC_SFC_V1_NANDFLASH) += ingenic_sfc_common.o ingenic_sfc_nand.o nand_device/ ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_ingenic_sfc_common.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_ingenic_sfc_common.c.patch new file mode 100644 index 00000000..7a3483d4 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_ingenic_sfc_common.c.patch @@ -0,0 +1,750 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v1/ingenic_sfc_common.c b/drivers/mtd/devices/ingenic_sfc_v1/ingenic_sfc_common.c +--- a/drivers/mtd/devices/ingenic_sfc_v1/ingenic_sfc_common.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v1/ingenic_sfc_common.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,746 @@ ++/* ++ * SFC controller for SPI protocol, use FIFO and DMA; ++ * ++ * Copyright (c) 2015 Ingenic ++ * Author: ++ * 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. ++ * ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include "ingenic_sfc_common.h" ++ ++ ++//#define SFC_DEBUG ++ ++ ++#define GET_PHYADDR(a) \ ++({ \ ++ unsigned int v; \ ++ if (unlikely((unsigned int)(a) & 0x40000000)) { \ ++ v = page_to_phys(vmalloc_to_page((const void *)(a))) | ((unsigned int)(a) & ~PAGE_MASK); \ ++ } else \ ++ v = ((unsigned int)(a) & 0x1fffffff); \ ++ v; \ ++ }) ++static inline void sfc_writel(struct sfc *sfc, unsigned short offset, u32 value) ++{ ++ writel(value, sfc->iomem + offset); ++} ++ ++static inline unsigned int sfc_readl(struct sfc *sfc, unsigned short offset) ++{ ++ return readl(sfc->iomem + offset); ++} ++ ++#ifdef SFC_DEBUG ++void dump_sfc_reg(struct sfc *sfc) ++{ ++ int i = 0; ++ printk("SFC_GLB :%08x\n", sfc_readl(sfc, SFC_GLB )); ++ printk("SFC_DEV_CONF :%08x\n", sfc_readl(sfc, SFC_DEV_CONF )); ++ printk("SFC_DEV_STA_EXP :%08x\n", sfc_readl(sfc, SFC_DEV_STA_EXP)); ++ printk("SFC_DEV_STA_RT :%08x\n", sfc_readl(sfc, SFC_DEV_STA_RT )); ++ printk("SFC_DEV_STA_MSK :%08x\n", sfc_readl(sfc, SFC_DEV_STA_MSK )); ++ printk("SFC_TRAN_LEN :%08x\n", sfc_readl(sfc, SFC_TRAN_LEN )); ++ ++ for(i = 0; i < 6; i++) ++ printk("SFC_TRAN_CONF(%d) :%08x\n", i,sfc_readl(sfc, SFC_TRAN_CONF(i))); ++ ++ for(i = 0; i < 6; i++) ++ printk("SFC_DEV_ADDR(%d) :%08x\n", i,sfc_readl(sfc, SFC_DEV_ADDR(i))); ++ ++ printk("SFC_MEM_ADDR :%08x\n", sfc_readl(sfc, SFC_MEM_ADDR )); ++ printk("SFC_TRIG :%08x\n", sfc_readl(sfc, SFC_TRIG)); ++ printk("SFC_SR :%08x\n", sfc_readl(sfc, SFC_SR)); ++ printk("SFC_SCR :%08x\n", sfc_readl(sfc, SFC_SCR)); ++ printk("SFC_INTC :%08x\n", sfc_readl(sfc, SFC_INTC)); ++ printk("SFC_FSM :%08x\n", sfc_readl(sfc, SFC_FSM )); ++ printk("SFC_CGE :%08x\n", sfc_readl(sfc, SFC_CGE )); ++// printk("SFC_RM_DR :%08x\n", sfc_readl(spi, SFC_RM_DR)); ++} ++static void dump_reg(struct sfc *sfc) ++{ ++ printk("SFC_GLB = %08x\n",sfc_readl(sfc,0x0000)); ++ printk("SFC_DEV_CONF = %08x\n",sfc_readl(sfc,0x0004)); ++ printk("SFC_DEV_STA_EXP = %08x\n",sfc_readl(sfc,0x0008)); ++ printk("SFC_DEV_STA_RT = %08x\n",sfc_readl(sfc,0x000c)); ++ printk("SFC_DEV_STA_MASK = %08x\n",sfc_readl(sfc,0x0010)); ++ printk("SFC_TRAN_CONF0 = %08x\n",sfc_readl(sfc,0x0014)); ++ printk("SFC_TRAN_LEN = %08x\n",sfc_readl(sfc,0x002c)); ++ printk("SFC_DEV_ADDR0 = %08x\n",sfc_readl(sfc,0x0030)); ++ printk("SFC_DEV_ADDR_PLUS0 = %08x\n",sfc_readl(sfc,0x0048)); ++ printk("SFC_MEM_ADDR = %08x\n",sfc_readl(sfc,0x0060)); ++ printk("SFC_TRIG = %08x\n",sfc_readl(sfc,0x0064)); ++ printk("SFC_SR = %08x\n",sfc_readl(sfc,0x0068)); ++ printk("SFC_SCR = %08x\n",sfc_readl(sfc,0x006c)); ++ printk("SFC_INTC = %08x\n",sfc_readl(sfc,0x0070)); ++ printk("SFC_FSM = %08x\n",sfc_readl(sfc,0x0074)); ++ printk("SFC_CGE = %08x\n",sfc_readl(sfc,0x0078)); ++// printk("SFC_DR = %08x\n",sfc_readl(sfc,0x1000)); ++} ++#endif ++ ++static inline void sfc_init(struct sfc *sfc) ++{ ++ sfc_writel(sfc, SFC_TRIG, TRIG_STOP); ++ sfc_writel(sfc, SFC_DEV_CONF, 0); ++ ++ /* X1000 need set to 0,but X2000 can be set to 1*/ ++ sfc_writel(sfc, SFC_CGE, 0); ++ ++} ++ ++static inline void sfc_start(struct sfc *sfc) ++{ ++ uint32_t tmp; ++ tmp = sfc_readl(sfc, SFC_TRIG); ++ tmp |= TRIG_START; ++ sfc_writel(sfc, SFC_TRIG, tmp); ++} ++ ++static inline void sfc_flush_fifo(struct sfc *sfc) ++{ ++ unsigned int tmp; ++ tmp = sfc_readl(sfc, SFC_TRIG); ++ tmp |= TRIG_FLUSH; ++ sfc_writel(sfc, SFC_TRIG, tmp); ++} ++static inline void sfc_clear_end_intc(struct sfc *sfc) ++{ ++ sfc_writel(sfc, SFC_SCR, CLR_END); ++} ++ ++static inline void sfc_clear_treq_intc(struct sfc *sfc) ++{ ++ sfc_writel(sfc, SFC_SCR, CLR_TREQ); ++} ++ ++static inline void sfc_clear_rreq_intc(struct sfc *sfc) ++{ ++ sfc_writel(sfc, SFC_SCR, CLR_RREQ); ++} ++ ++static inline void sfc_clear_over_intc(struct sfc *sfc) ++{ ++ sfc_writel(sfc, SFC_SCR, CLR_OVER); ++} ++ ++static inline void sfc_clear_under_intc(struct sfc *sfc) ++{ ++ sfc_writel(sfc, SFC_SCR, CLR_UNDER); ++} ++ ++static inline void sfc_clear_all_intc(struct sfc *sfc) ++{ ++ sfc_writel(sfc, SFC_SCR, 0x1f); ++} ++ ++static inline void sfc_mask_all_intc(struct sfc *sfc) ++{ ++ sfc_writel(sfc, SFC_INTC, 0x1f); ++} ++ ++static void sfc_set_phase_num(struct sfc *sfc, int32_t num) ++{ ++ uint32_t tmp; ++ ++ tmp = sfc_readl(sfc, SFC_GLB); ++ tmp &= ~GLB_PHASE_NUM_MSK; ++ tmp |= num << GLB_PHASE_NUM_OFFSET; ++ sfc_writel(sfc, SFC_GLB, tmp); ++} ++ ++static void sfc_dev_hw_init(struct sfc *sfc) ++{ ++ uint32_t tmp; ++ tmp = sfc_readl(sfc, SFC_DEV_CONF); ++ ++ /*cpha bit:0 , cpol bit:0 */ ++ tmp &= ~(DEV_CONF_CPHA | DEV_CONF_CPOL); ++ /*ce_dl bit:1, hold bit:1,wp bit:1*/ ++ tmp |= (DEV_CONF_CEDL | DEV_CONF_HOLDDL | DEV_CONF_WPDL); ++ sfc_writel(sfc, SFC_DEV_CONF, tmp); ++ ++} ++ ++static void sfc_threshold(struct sfc *sfc, uint32_t value) ++{ ++ uint32_t tmp = sfc_readl(sfc, SFC_GLB); ++ tmp &= ~GLB_THRESHOLD_MSK; ++ tmp |= value << GLB_THRESHOLD_OFFSET; ++ sfc_writel(sfc, SFC_GLB, tmp); ++} ++ ++static void sfc_smp_delay(struct sfc *sfc, uint8_t value) ++{ ++ uint32_t tmp; ++ tmp = sfc_readl(sfc, SFC_DEV_CONF); ++ tmp &= ~DEV_CONF_SMP_DELAY_MSK; ++ tmp |= value << DEV_CONF_SMP_DELAY_OFFSET; ++ sfc_writel(sfc, SFC_DEV_CONF, tmp); ++} ++ ++int32_t set_flash_timing(struct sfc *sfc, uint32_t t_hold, uint32_t t_setup, uint32_t t_shslrd, uint32_t t_shslwr) ++{ ++ uint32_t c_hold = 0; ++ uint32_t c_setup = 0; ++ uint32_t t_in = 0, c_in = 0; ++ uint32_t tmp; ++ unsigned long cycle; ++ unsigned long long ns; ++ ++ ns = 1000000000ULL; ++ cycle = do_div(ns, sfc->src_clk); ++ cycle = ns; ++ ++ tmp = sfc_readl(sfc, SFC_DEV_CONF); ++ tmp &= ~(DEV_CONF_THOLD_MSK | DEV_CONF_TSETUP_MSK | DEV_CONF_TSH_MSK); ++ ++ c_hold = t_hold / cycle; ++ if(c_hold > 0) ++ c_hold -= 1; ++ ++ c_setup = t_setup / cycle; ++ if(c_setup > 0) ++ c_setup -= 1; ++ ++ t_in = max(t_shslrd, t_shslwr); ++ c_in = t_in / cycle; ++ if(c_in > 0) ++ c_in -= 1; ++ ++ tmp |= (c_hold << DEV_CONF_THOLD_OFFSET) | \ ++ (c_setup << DEV_CONF_TSETUP_OFFSET) | \ ++ (c_in << DEV_CONF_TSH_OFFSET); ++ ++ sfc_writel(sfc, SFC_DEV_CONF, tmp); ++ return 0; ++} ++ ++static void sfc_set_length(struct sfc *sfc, uint32_t value) ++{ ++ sfc_writel(sfc, SFC_TRAN_LEN, value); ++} ++ ++static inline void sfc_transfer_mode(struct sfc *sfc, uint8_t value) ++{ ++ uint32_t tmp; ++ tmp = sfc_readl(sfc, SFC_GLB); ++ if(value == 0) ++ tmp &= ~GLB_OP_MODE; ++ else ++ tmp |= GLB_OP_MODE; ++ sfc_writel(sfc, SFC_GLB, tmp); ++} ++ ++static void sfc_read_data(struct sfc *sfc, uint32_t *value) ++{ ++ *value = sfc_readl(sfc, SFC_RM_DR); ++} ++ ++static void sfc_write_data(struct sfc *sfc, uint32_t value) ++{ ++ sfc_writel(sfc, SFC_RM_DR, value); ++} ++ ++static void cpu_read_rxfifo(struct sfc *sfc) ++{ ++ int32_t i = 0; ++ uint32_t align_len = 0; ++ uint32_t fifo_num = 0; ++ uint32_t last_word = 0; ++ uint32_t unalign_data; ++ uint8_t *c; ++ ++ align_len = ALIGN(sfc->transfer->len, 4); ++ ++ if(((align_len - sfc->transfer->cur_len) / 4) > sfc->threshold) { ++ fifo_num = sfc->threshold; ++ last_word = 0; ++ } else { ++ /* last aligned THRESHOLD data*/ ++ if(sfc->transfer->len % 4) { ++ fifo_num = (align_len - sfc->transfer->cur_len) / 4 - 1; ++ last_word = 1; ++ } else { ++ fifo_num = (align_len - sfc->transfer->cur_len) / 4; ++ last_word = 0; ++ } ++ } ++ ++ if ((uint32_t)sfc->transfer->data & 0x3) { ++ /* addr not align */ ++ for (i = 0; i < fifo_num; i++) { ++ sfc_read_data(sfc, &unalign_data); ++ c = sfc->transfer->data; ++ c[0] = (unalign_data >> 0) & 0xff; ++ c[1] = (unalign_data >> 8) & 0xff; ++ c[2] = (unalign_data >> 16) & 0xff; ++ c[3] = (unalign_data >> 24) & 0xff; ++ ++ sfc->transfer->data += 4; ++ sfc->transfer->cur_len += 4; ++ } ++ } else { ++ /* addr align */ ++ for (i = 0; i < fifo_num; i++) { ++ sfc_read_data(sfc, (uint32_t *)sfc->transfer->data); ++ sfc->transfer->data += 4; ++ sfc->transfer->cur_len += 4; ++ } ++ } ++ ++ /* last word */ ++ if(last_word == 1) { ++ sfc_read_data(sfc, &unalign_data); ++ c = sfc->transfer->data; ++ ++ for(i = 0; i < sfc->transfer->len % 4; i++) { ++ c[i] = (unalign_data >> (i * 8)) & 0xff; ++ } ++ ++ sfc->transfer->data += sfc->transfer->len % 4; ++ sfc->transfer->cur_len += sfc->transfer->len % 4; ++ } ++ ++} ++ ++static void cpu_write_txfifo(struct sfc *sfc) ++{ ++ uint32_t align_len = 0; ++ uint32_t fifo_num = 0; ++ uint32_t data = 0; ++ uint32_t i; ++ uint32_t nbytes = sfc->transfer->len % 4; ++ ++ align_len = sfc->transfer->len / 4 * 4; ++ ++ if (((align_len - sfc->transfer->cur_len) / 4) >= sfc->threshold) { ++ fifo_num = sfc->threshold; ++ nbytes = 0; ++ } else { ++ fifo_num = (align_len - sfc->transfer->cur_len) / 4; ++ } ++ ++ if ((uint32_t)sfc->transfer->data & 3) { ++ /* addr not align */ ++ for(i = 0; i < fifo_num; i++) { ++ data = sfc->transfer->data[3] << 24 | sfc->transfer->data[2] << 16 | sfc->transfer->data[1] << 8 | sfc->transfer->data[0]; ++ sfc_write_data(sfc, data); ++ sfc->transfer->data += 4; ++ sfc->transfer->cur_len += 4; ++ } ++ } else { ++ /* addr align */ ++ for(i = 0; i < fifo_num; i++) { ++ sfc_write_data(sfc, *(uint32_t *)sfc->transfer->data); ++ sfc->transfer->data += 4; ++ sfc->transfer->cur_len += 4; ++ } ++ } ++ ++ if(nbytes) { ++ data = 0; ++ for(i = 0; i < nbytes; i++) ++ data |= sfc->transfer->data[i] << i * 8; ++ sfc_write_data(sfc, data); ++ sfc->transfer->cur_len += nbytes; ++ } ++ ++} ++ ++uint32_t sfc_get_sta_rt(struct sfc *sfc) ++{ ++ return sfc_readl(sfc, SFC_DEV0_STA_RT); ++} ++ ++static void sfc_dev_sta_exp(struct sfc *sfc, uint32_t value) ++{ ++ sfc_writel(sfc, SFC_DEV_STA_EXP, value); ++} ++ ++static void sfc_dev_sta_msk(struct sfc *sfc, uint32_t value) ++{ ++ sfc_writel(sfc, SFC_DEV_STA_MSK, value); ++} ++ ++static void sfc_enable_all_intc(struct sfc *sfc) ++{ ++ sfc_writel(sfc, SFC_INTC, 0); ++} ++ ++static void sfc_set_mem_addr(struct sfc *sfc, unsigned int addr) ++{ ++ sfc_writel(sfc, SFC_MEM_ADDR, addr); ++} ++ ++#define SFC_TRANSFER_TIMEOUT 3000 //3000ms for timeout ++static int32_t sfc_start_transfer(struct sfc *sfc) ++{ ++ int32_t err; ++ sfc_clear_all_intc(sfc); ++ sfc_enable_all_intc(sfc); ++ sfc_start(sfc); ++ err = wait_for_completion_timeout(&sfc->done, msecs_to_jiffies(SFC_TRANSFER_TIMEOUT)); ++ if (!err) { ++ sfc_mask_all_intc(sfc); ++ sfc_clear_all_intc(sfc); ++ printk("line:%d Timeout for ACK from SFC device\n",__LINE__); ++ return -ETIMEDOUT; ++ } ++ return 0; ++} ++ ++static void sfc_set_tran_config(struct sfc *sfc, struct sfc_transfer *transfer, int channel) ++{ ++ uint32_t tmp = 0; ++ ++ tmp = (transfer->sfc_mode << TRAN_CONF_TRAN_MODE_OFFSET) \ ++ | (transfer->addr_len << ADDR_WIDTH_OFFSET) \ ++ | (transfer->cmd_info.pollen << TRAN_CONF_POLL_OFFSET) \ ++ | (TRAN_CONF_CMDEN) \ ++ | (0 << TRAN_CONF_FMAT_OFFSET) \ ++ | (transfer->data_dummy_bits << DMYBITS_OFFSET) \ ++ | (transfer->cmd_info.dataen << TRAN_CONF_DATEEN_OFFSET) \ ++ | transfer->cmd_info.cmd; ++ ++ sfc_writel(sfc, SFC_TRAN_CONF(channel), tmp); ++} ++ ++static void sfc_phase_transfer(struct sfc *sfc, struct sfc_transfer * ++ transfer, int channel) ++{ ++ sfc_writel(sfc, SFC_DEV_ADDR(channel), transfer->addr); //set addr ++ sfc_writel(sfc, SFC_DEV_ADDR_PLUS(channel), transfer->addr_plus); //set plus addr ++ sfc_set_tran_config(sfc, transfer, channel); ++} ++ ++static void sfc_set_glb_config(struct sfc *sfc, struct sfc_transfer *transfer) ++{ ++ uint32_t tmp = 0; ++ ++ tmp = sfc_readl(sfc, SFC_GLB); ++ ++ if (transfer->direction == GLB_TRAN_DIR_READ) ++ tmp &= ~GLB_TRAN_DIR; ++ else ++ tmp |= GLB_TRAN_DIR; ++ ++ if (transfer->ops_mode == DMA_OPS) ++ tmp |= GLB_OP_MODE; ++ else ++ tmp &= ~GLB_OP_MODE; ++ ++ sfc_writel(sfc, SFC_GLB, tmp); ++} ++ ++static void sfc_glb_info_config(struct sfc *sfc, struct sfc_transfer *transfer) ++{ ++ sfc_set_length(sfc, transfer->len); ++ if((transfer->ops_mode == DMA_OPS)){ ++ if(transfer->direction == GLB_TRAN_DIR_READ) ++ dma_cache_sync(NULL, (void *)transfer->data, transfer->len, DMA_FROM_DEVICE); ++ else ++ dma_cache_sync(NULL, (void *)transfer->data, transfer->len, DMA_TO_DEVICE); ++ sfc_set_mem_addr(sfc, GET_PHYADDR(transfer->data)); ++ }else{ ++ sfc_set_mem_addr(sfc, 0); ++ } ++ sfc_set_glb_config(sfc, transfer); ++} ++#ifdef SFC_DEBUG ++static void dump_transfer(struct sfc_transfer *xfer,int num) ++{ ++ printk("\n"); ++ printk("cmd[%d].cmd = 0x%02x\n",num,xfer->cmd_info->cmd); ++ printk("cmd[%d].addr_len = %d\n",num,xfer->addr_len); ++ printk("cmd[%d].dummy_byte = %d\n",num,xfer->data_dummy_bits); ++ printk("cmd[%d].dataen = %d\n",num,xfer->cmd_info->dataen); ++ printk("cmd[%d].sta_exp = %d\n",num,xfer->cmd_info->sta_exp); ++ printk("cmd[%d].sta_msk = %d\n",num,xfer->cmd_info->sta_msk); ++ ++ ++ printk("transfer[%d].addr = 0x%08x\n",num,xfer->addr); ++ printk("transfer[%d].len = %d\n",num,xfer->len); ++ printk("transfer[%d].data = 0x%p\n",num,xfer->data); ++ printk("transfer[%d].direction = %d\n",num,xfer->direction); ++ printk("transfer[%d].sfc_mode = %d\n",num,xfer->sfc_mode); ++ printk("transfer[%d].ops_mode = %d\n",num,xfer->ops_mode); ++} ++#endif ++ ++int sfc_sync(struct sfc *sfc, struct sfc_transfer *head) ++{ ++ int phase_num = 0; ++ struct sfc_transfer *xfer = head; ++ ++ sfc_flush_fifo(sfc); ++ sfc_set_length(sfc, 0); ++ do { ++ ++ sfc_phase_transfer(sfc, xfer, phase_num); //set phase ++ if(xfer->cmd_info.pollen) { //set polling ++ sfc_dev_sta_exp(sfc, xfer->cmd_info.sta_exp); ++ sfc_dev_sta_msk(sfc, xfer->cmd_info.sta_msk); ++ } ++ ++ if(xfer->cmd_info.dataen && xfer->len) { //set mem ++ sfc_glb_info_config(sfc, xfer); ++ if(xfer->ops_mode == CPU_OPS) ++ sfc->transfer = xfer; ++ if(xfer->ops_mode == DMA_OPS) ++ xfer->cur_len = xfer->len; ++ } ++ ++ phase_num++; ++ } while (&xfer->list != head->list.prev && ++ (xfer = list_entry(xfer->list.next, typeof(*xfer), list))); ++ ++ sfc_set_phase_num(sfc, phase_num); ++ return sfc_start_transfer(sfc); ++} ++ ++int sfc_sync_poll(struct sfc *sfc, struct sfc_transfer *head) ++{ ++ uint32_t timeout = 4000, val; ++ int phase_num = 0; ++ struct sfc_transfer *xfer = head; ++ ++ sfc_flush_fifo(sfc); ++ sfc_set_length(sfc, 0); ++ do { ++ ++ sfc_phase_transfer(sfc, xfer, phase_num); //set phase ++ if(xfer->cmd_info.pollen) { //set polling ++ sfc_dev_sta_exp(sfc, xfer->cmd_info.sta_exp); ++ sfc_dev_sta_msk(sfc, xfer->cmd_info.sta_msk); ++ } ++ ++ if(xfer->cmd_info.dataen && xfer->len) { //set mem ++ sfc_glb_info_config(sfc, xfer); ++ if(xfer->ops_mode == CPU_OPS) ++ sfc->transfer = xfer; ++ if(xfer->ops_mode == DMA_OPS) ++ xfer->cur_len = xfer->len; ++ } ++ ++ phase_num++; ++ } while (&xfer->list != head->list.prev && ++ (xfer = list_entry(xfer->list.next, typeof(*xfer), list))); ++ ++ sfc_set_phase_num(sfc, phase_num); ++ ++ sfc_mask_all_intc(sfc); ++ sfc_clear_all_intc(sfc); ++ sfc_start(sfc); ++ ++ while(timeout --) { ++ ++ val = sfc_readl(sfc, SFC_SR) & 0x1f; ++ ++ if(val & CLR_RREQ) { ++ cpu_read_rxfifo(sfc); ++ sfc_clear_rreq_intc(sfc); ++ } else if(val & CLR_TREQ) { ++ cpu_write_txfifo(sfc); ++ sfc_clear_treq_intc(sfc); ++ } else if(val & CLR_OVER) { ++ sfc_clear_over_intc(sfc); ++ pr_err("sfc poll OVER !\n"); ++ } else if(val & CLR_UNDER) { ++ sfc_clear_under_intc(sfc); ++ pr_err("sfc poll UNDR !\n"); ++ } else if(val & CLR_END) { ++ sfc_mask_all_intc(sfc); ++ sfc_clear_end_intc(sfc); ++ return 0; ++ } else { ++ udelay(1); ++ } ++ } ++ ++ pr_err("sfc transfer timeout --! %d\n", timeout); ++ ++ return -ETIMEDOUT; ++} ++ ++void sfc_transfer_del(struct sfc_transfer *entry) ++{ ++ list_del(&entry->list); ++} ++ ++void sfc_list_add_tail(struct sfc_transfer *new, struct sfc_transfer *head) ++{ ++ list_add_tail(&new->list, &head->list); ++} ++ ++void sfc_list_init(struct sfc_transfer *head) ++{ ++ INIT_LIST_HEAD(&head->list); ++} ++ ++static irqreturn_t ingenic_sfc_pio_irq_callback(int32_t irq, void *dev) ++{ ++ struct sfc *sfc = dev; ++ uint32_t val; ++ ++ val = sfc_readl(sfc, SFC_SR) & 0x1f; ++ ++ if(val & CLR_RREQ) { ++ sfc_clear_rreq_intc(sfc); ++ cpu_read_rxfifo(sfc); ++ } else if(val & CLR_TREQ) { ++ sfc_clear_treq_intc(sfc); ++ cpu_write_txfifo(sfc); ++ } else if(val & CLR_OVER) { ++ sfc_clear_over_intc(sfc); ++ pr_err("sfc OVER !\n"); ++ complete(&sfc->done); ++ } else if(val & CLR_UNDER) { ++ sfc_clear_under_intc(sfc); ++ pr_err("sfc UNDR !\n"); ++ complete(&sfc->done); ++ } else if(val & CLR_END) { ++ sfc_mask_all_intc(sfc); ++ sfc_clear_end_intc(sfc); ++ complete(&sfc->done); ++ } ++ return IRQ_HANDLED; ++} ++ ++static void ingenic_sfc_init_setup(struct sfc *sfc) ++{ ++ sfc_init(sfc); ++ sfc_threshold(sfc, sfc->threshold); ++ sfc_dev_hw_init(sfc); ++ ++ sfc_transfer_mode(sfc, SLAVE_MODE); ++ if(sfc->src_clk >= 100000000){ ++ sfc_smp_delay(sfc, DEV_CONF_HALF_CYCLE_DELAY); ++ } ++} ++ ++struct sfc *sfc_res_init(struct platform_device *pdev) ++{ ++ struct device_node* np = pdev->dev.of_node; ++ struct ingenic_sfc_info *board_info; ++ struct sfc *sfc; ++ struct resource *res; ++ int32_t err = 0; ++ ++ board_info = devm_kzalloc(&pdev->dev, sizeof(struct ingenic_sfc_info), GFP_KERNEL); ++ if(!board_info){ ++ printk("ERROR: %s %d devm_kzalloc() error !\n",__func__,__LINE__); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ sfc = devm_kzalloc(&pdev->dev, sizeof(struct sfc), GFP_KERNEL); ++ if (!sfc) { ++ printk("ERROR: %s %d devm_kzalloc() error !\n",__func__,__LINE__); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ err = of_property_read_u32(np, "ingenic,sfc-max-frequency", (unsigned int *)&sfc->src_clk); ++ if (err < 0) { ++ dev_err(&pdev->dev, "Cannot get sfc max frequency\n"); ++ return ERR_PTR(-ENOENT); ++ } ++ ++ err = of_property_read_u32(np, "ingenic,spiflash_param_offset", (unsigned int *)&board_info->param_offset); ++ if (err < 0) { ++ dev_err(&pdev->dev, "No dts param_offset, use default.\n"); ++ board_info->param_offset = -EINVAL; ++ } ++ ++ err = of_property_read_u8(np, "ingenic,use_board_info", &board_info->use_board_info); ++ if (err < 0) { ++ dev_err(&pdev->dev, "Cannot get sfc use_board_info\n"); ++ return ERR_PTR(-ENOENT); ++ } ++ ++ err = platform_device_add_data(pdev, board_info, sizeof(struct ingenic_sfc_info)); ++ if(err){ ++ printk("ERROR: %s %d error !\n",__func__,__LINE__); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ /* find and map our resources */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (res == NULL) { ++ dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n"); ++ return ERR_PTR(-ENOENT); ++ } ++ ++ sfc->iomem = devm_ioremap_resource(&pdev->dev, res); ++ if (sfc->iomem == NULL) { ++ dev_err(&pdev->dev, "Cannot map IO\n"); ++ return ERR_PTR(-ENXIO); ++ } ++ ++ sfc->clk = devm_clk_get(&pdev->dev, "cgu_sfc"); ++ if (IS_ERR(sfc->clk)) { ++ dev_err(&pdev->dev, "Cannot get cgu_sfc clock\n"); ++ return ERR_PTR(-ENOENT); ++ } ++ ++ sfc->clk_gate = devm_clk_get(&pdev->dev, "gate_sfc"); ++ if (IS_ERR(sfc->clk_gate)) { ++ dev_err(&pdev->dev, "Cannot get sfc clock\n"); ++ return ERR_PTR(-ENOENT); ++ } ++ ++ clk_set_rate(sfc->clk, sfc->src_clk); ++ if(clk_prepare_enable(sfc->clk)) { ++ dev_err(&pdev->dev, "cgu clk error\n"); ++ return ERR_PTR(-ENOENT); ++ } ++ if(clk_prepare_enable(sfc->clk_gate)) { ++ dev_err(&pdev->dev, "gate clk error\n"); ++ return ERR_PTR(-ENOENT); ++ } ++ ++ sfc->threshold = THRESHOLD; ++ ++ /* request SFC irq */ ++ sfc->irq = platform_get_irq(pdev, 0); ++ if (sfc->irq < 0) { ++ dev_err(&pdev->dev, "No IRQ specified\n"); ++ return ERR_PTR(-ENOENT); ++ } ++ ++ err = devm_request_irq(&pdev->dev, sfc->irq, ingenic_sfc_pio_irq_callback, 0, pdev->name, sfc); ++ if (err) { ++ dev_err(&pdev->dev, "Cannot claim IRQ\n"); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ /* SFC controller initializations for SFC */ ++ ingenic_sfc_init_setup(sfc); ++ init_completion(&sfc->done); ++ return sfc; ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_ingenic_sfc_common.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_ingenic_sfc_common.h.patch new file mode 100644 index 00000000..4f81ab9b --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_ingenic_sfc_common.h.patch @@ -0,0 +1,32 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v1/ingenic_sfc_common.h b/drivers/mtd/devices/ingenic_sfc_v1/ingenic_sfc_common.h +--- a/drivers/mtd/devices/ingenic_sfc_v1/ingenic_sfc_common.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v1/ingenic_sfc_common.h 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,28 @@ ++#ifndef ingenic_SFC_COMMON_H ++#define ingenic_SFC_COMMON_H ++#include ++#include ++#include ++#include ++#include ++#include "sfc.h" ++#include "sfc_flash.h" ++ ++ ++void dump_sfc_reg(struct sfc *sfc); ++ ++void sfc_list_init(struct sfc_transfer *); ++void sfc_list_add_tail(struct sfc_transfer *, struct sfc_transfer *); ++int32_t sfc_sync(struct sfc *, struct sfc_transfer *); ++int32_t sfc_sync_poll(struct sfc *, struct sfc_transfer *); ++struct sfc *sfc_res_init(struct platform_device *); ++void sfc_res_deinit(struct sfc *sfc); ++uint32_t sfc_get_sta_rt(struct sfc *); ++ ++int32_t set_flash_timing(struct sfc *, uint32_t, uint32_t, uint32_t, uint32_t); ++ ++int32_t sfc_nor_get_special_ops(struct sfc_flash *); ++ ++#endif ++ ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_ingenic_sfc_nand.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_ingenic_sfc_nand.c.patch new file mode 100644 index 00000000..26f03a6f --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_ingenic_sfc_nand.c.patch @@ -0,0 +1,1037 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v1/ingenic_sfc_nand.c b/drivers/mtd/devices/ingenic_sfc_v1/ingenic_sfc_nand.c +--- a/drivers/mtd/devices/ingenic_sfc_v1/ingenic_sfc_nand.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v1/ingenic_sfc_nand.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,1033 @@ ++/* ++ * SFC controller for SPI protocol, use FIFO and DMA; ++ * ++ * Copyright (c) 2015 Ingenic ++ * Author: ++ * 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. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "sfc_flash.h" ++#include "spinand.h" ++#include "ingenic_sfc_common.h" ++#include "./nand_device/nand_common.h" ++ ++ ++#define STATUS_SUSPND (1<<0) ++#define to_ingenic_spi_nand(mtd_info) container_of(mtd_info, struct sfc_flash, mtd) ++ ++/* ++ * below is the informtion about nand ++ * that user should modify according to nand spec ++ * */ ++ ++static LIST_HEAD(nand_list); ++ ++void dump_flash_info(struct sfc_flash *flash) ++{ ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ struct ingenic_sfcnand_base_param *param = &nand_info->param; ++ struct mtd_partition *partition = nand_info->partition.partition; ++ uint8_t num_partition = nand_info->partition.num_partition; ++ ++ printk("id_manufactory = 0x%02x\n", nand_info->id_manufactory); ++ printk("id_device = 0x%02x\n", nand_info->id_device); ++ ++ printk("pagesize = %d\n", param->pagesize); ++ printk("blocksize = %d\n", param->blocksize); ++ printk("oobsize = %d\n", param->oobsize); ++ printk("flashsize = %d\n", param->flashsize); ++ ++ printk("tHOLD = %d\n", param->tHOLD); ++ printk("tSETUP = %d\n", param->tSETUP); ++ printk("tSHSL_R = %d\n", param->tSHSL_R); ++ printk("tSHSL_W = %d\n", param->tSHSL_W); ++ ++ printk("ecc_max = %d\n", param->ecc_max); ++ printk("need_quad = %d\n", param->need_quad); ++ ++ while(num_partition--) { ++ printk("partition(%d) name=%s\n", num_partition, partition[num_partition].name); ++ printk("partition(%d) size = 0x%llx\n", num_partition, partition[num_partition].size); ++ printk("partition(%d) offset = 0x%llx\n", num_partition, partition[num_partition].offset); ++ printk("partition(%d) mask_flags = 0x%x\n", num_partition, partition[num_partition].mask_flags); ++ } ++ return; ++} ++ ++static int32_t ingenic_sfc_nand_read(struct sfc_flash *flash, int32_t pageaddr, int32_t columnaddr, u_char *buffer, size_t len) ++{ ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ struct ingenic_sfcnand_read *nand_read_ops = &nand_info->ops.nand_read_ops; ++ struct sfc_transfer transfer; ++ struct flash_operation_message op_info = { .flash = flash, ++ .pageaddr = pageaddr, ++ .columnaddr = columnaddr, ++ .buffer = buffer, ++ .len = len, ++ }; ++ ++ int32_t ret = 0; ++ ++ memset(&transfer, 0, sizeof(transfer)); ++ sfc_list_init(&transfer); ++ /*1. pageread_to_cache*/ ++ nand_read_ops->pageread_to_cache(&transfer, &op_info); ++ if(sfc_sync_poll(flash->sfc, &transfer)) { ++ dev_err(flash->dev,"sfc_sync error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ /*2. read delay*/ ++ udelay(nand_info->param.tRD); ++ ++ /*3. read feature*/ ++ ret = nand_read_ops->get_feature(&op_info); ++ if(ret == -EIO) ++ return ret; ++ ++ memset(&transfer, 0, sizeof(transfer)); ++ sfc_list_init(&transfer); ++ ++ /*4. read data to mem*/ ++ if(nand_info->param.need_quad) { ++ nand_read_ops->quad_read(&transfer, &op_info); ++ } else { ++ nand_read_ops->single_read(&transfer, &op_info); ++ } ++ ++ if((len / 4) < THRESHOLD) { ++ if(sfc_sync_poll(flash->sfc, &transfer)) { ++ dev_err(flash->dev,"sfc_sync error ! %s %s %d\n", __FILE__, __func__, __LINE__); ++ ret = -EIO; ++ } ++ } else { ++ if(sfc_sync(flash->sfc, &transfer)) { ++ dev_err(flash->dev,"sfc_sync error ! %s %s %d\n", __FILE__, __func__, __LINE__); ++ ret = -EIO; ++ } ++ } ++ ++ if(transfer.ops_mode == DMA_OPS) ++ dma_cache_sync(NULL, (void *)transfer.data, transfer.len, DMA_FROM_DEVICE); ++ ++ return ret; ++} ++ ++ ++static int badblk_check(int len, unsigned char *buf) ++{ ++ int j; ++ unsigned char *check_buf = buf; ++ ++ for(j = 0; j < len; j++){ ++ if(check_buf[j] != 0xff){ ++ return 1; ++ } ++ } ++ return 0; ++} ++ ++ ++static int32_t ingenic_sfc_nand_write(struct sfc_flash *flash, u_char *buffer, uint32_t pageaddr, uint32_t columnaddr, size_t len) ++{ ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ struct ingenic_sfcnand_write *nand_write_ops = &nand_info->ops.nand_write_ops; ++ struct sfc_transfer transfer[3]; ++ struct flash_operation_message op_info = { .flash = flash, ++ .pageaddr = pageaddr, ++ .columnaddr = columnaddr, ++ .buffer = buffer, ++ .len = len, ++ }; ++ int32_t ret = 0; ++ ++ memset(transfer, 0, sizeof(transfer)); ++ sfc_list_init(transfer); ++ ++ /*1. write enable*/ ++ nand_write_ops->write_enable(transfer, &op_info); ++ ++ /*2. write to cache*/ ++ if(nand_info->param.need_quad) { ++ nand_write_ops->quad_load(&transfer[1], &op_info); ++ } else { ++ nand_write_ops->single_load(&transfer[1], &op_info); ++ } ++ sfc_list_add_tail(&transfer[1], transfer); ++ ++ /*3. program exec*/ ++ nand_write_ops->program_exec(&transfer[2], &op_info); ++ sfc_list_add_tail(&transfer[2], transfer); ++ ++ if(sfc_sync(flash->sfc, transfer)) { ++ dev_err(flash->dev, "sfc_sync error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ udelay(nand_info->param.tPP); ++ ++ /*4. get status to be sure nand wirte completed*/ ++ ret = nand_write_ops->get_feature(&op_info); ++ ++ return ret; ++} ++ ++static int32_t is_split_page(void * buf, uint32_t len) { ++ ++ uint32_t start, end; ++ if(is_vmalloc_addr(buf)) { ++ start = page_to_phys(vmalloc_to_page((const void *)(buf))) | ((unsigned int)(buf) & ~PAGE_MASK); ++ end = page_to_phys(vmalloc_to_page((const void *)(buf + len - 1))) | ((unsigned int)(buf + len -1) & ~PAGE_MASK); ++ ++ if((start & PAGE_MASK) != (end & PAGE_MASK)) ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static int ingenic_sfcnand_write_oob(struct mtd_info *mtd, loff_t addr, struct mtd_oob_ops *ops) ++{ ++ struct sfc_flash *flash = to_ingenic_spi_nand(mtd); ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ void *pbuf = nand_info->swapbuf; ++ uint32_t oob_addr = (uint32_t)addr; ++ int32_t ret; ++ ++ mutex_lock(&flash->lock); ++ if(is_split_page(ops->oobbuf, ops->ooblen)) ++ memcpy(pbuf, ops->oobbuf, ops->ooblen); ++ else ++ pbuf = ops->oobbuf; ++ ++ if((ret = ingenic_sfc_nand_write(flash, pbuf, oob_addr / mtd->writesize, mtd->writesize, ops->ooblen))) { ++ dev_err(flash->dev, "spi nand write oob error %s %s %d \n",__FILE__,__func__,__LINE__); ++ goto write_oob_exit; ++ } ++ ops->retlen = ops->ooblen; ++write_oob_exit: ++ mutex_unlock(&flash->lock); ++ return ret; ++} ++ ++static int ingenic_sfcnand_chip_block_markbad(struct mtd_info *mtd, loff_t ofs) ++{ ++ struct nand_chip *chip = mtd->priv; ++ uint8_t buf[2] = { 0, 0 }; ++ int ret = 0, i = 0; ++ int write_oob = !(chip->bbt_options & NAND_BBT_NO_OOB_BBM); ++ ++ /* Write bad block marker to OOB */ ++ if (write_oob) { ++ struct mtd_oob_ops ops; ++ loff_t wr_ofs = ofs; ++ ops.datbuf = NULL; ++ ops.oobbuf = buf; ++ ops.ooboffs = chip->badblockpos; ++ if (chip->options & NAND_BUSWIDTH_16) { ++ ops.ooboffs &= ~0x01; ++ ops.len = ops.ooblen = 2; ++ } else { ++ ops.len = ops.ooblen = 1; ++ } ++ ops.mode = MTD_OPS_PLACE_OOB; ++ ++ /* Write to first/last page(s) if necessary */ ++ if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) ++ wr_ofs += mtd->erasesize - mtd->writesize; ++ do { ++ ret = ingenic_sfcnand_write_oob(mtd, wr_ofs, &ops); ++ if (ret) ++ return ret; ++ wr_ofs += mtd->writesize; ++ i++; ++ } while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2); ++ } ++ /* Update flash-based bad block table */ ++ if (chip->bbt_options & NAND_BBT_USE_FLASH) { ++ ret = nand_markbad_bbt(mtd, ofs); ++ } ++ ++ return ret; ++} ++ ++static int32_t ingenic_sfc_nand_erase_blk(struct sfc_flash *flash, uint32_t pageaddr) ++{ ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ struct ingenic_sfcnand_erase *nand_erase_ops = &nand_info->ops.nand_erase_ops; ++ struct sfc_transfer transfer[2]; ++ struct flash_operation_message op_info = { .flash = flash, ++ .pageaddr = pageaddr, ++ .columnaddr = 0, ++ .buffer = NULL, ++ .len = 0, ++ }; ++ ++ int32_t ret; ++ ++ memset(transfer, 0, sizeof(transfer)); ++ sfc_list_init(transfer); ++ ++ /*1. write enable */ ++ nand_erase_ops->write_enable(transfer, &op_info); ++ ++ /*2. block erase*/ ++ nand_erase_ops->block_erase(&transfer[1], &op_info); ++ sfc_list_add_tail(&transfer[1], transfer); ++ ++ if(sfc_sync(flash->sfc, transfer)) { ++ dev_err(flash->dev, "sfc_sync error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ mdelay(nand_info->param.tBE); ++ ++ /*3. get feature*/ ++ ret = nand_erase_ops->get_feature(&op_info); ++ ++ if(ret) ++ dev_err(flash->dev, "Erase error,get state error ! %s %s %d \n",__FILE__,__func__,__LINE__); ++ ++ return ret; ++} ++ ++static int ingenic_sfcnand_erase(struct mtd_info *mtd, struct erase_info *instr) ++{ ++ struct sfc_flash *flash = to_ingenic_spi_nand(mtd); ++ uint32_t addr = (uint32_t)instr->addr; ++ uint32_t end; ++ int32_t ret; ++ ++ if(addr % mtd->erasesize) { ++ dev_err(flash->dev, "ERROR:%s line %d eraseaddr no align\n", __func__,__LINE__); ++ return -EINVAL; ++ } ++ end = addr + instr->len; ++ instr->state = MTD_ERASING; ++ mutex_lock(&flash->lock); ++ while (addr < end) { ++ if((ret = ingenic_sfc_nand_erase_blk(flash, addr / mtd->writesize))) { ++ dev_err(flash->dev, "spi nand erase error blk id %d !\n",addr / mtd->erasesize); ++ instr->state = MTD_ERASE_FAILED; ++ goto erase_exit; ++ } ++ addr += mtd->erasesize; ++ } ++ ++ instr->state = MTD_ERASE_DONE; ++erase_exit: ++ mutex_unlock(&flash->lock); ++ return ret; ++} ++ ++static int ingenic_sfcnand_block_isbab(struct mtd_info *mtd, loff_t ofs) ++{ ++ struct nand_chip *chip = mtd->priv; ++ if(!chip->bbt) ++ return chip->block_bad(mtd, ofs, 1); ++ return nand_isbad_bbt(mtd, ofs, 0); ++} ++ ++static int ingenic_sfcnand_block_markbad(struct mtd_info *mtd, loff_t ofs) ++{ ++ struct nand_chip *chip = mtd->priv; ++ int ret = ingenic_sfcnand_block_isbab(mtd, ofs); ++ if(ret > 0) { ++ /* If it was bad already, return success and do nothing */ ++ return 0; ++ } ++ return chip->block_markbad(mtd, ofs); ++} ++ ++static int ingenic_sfcnand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) ++{ ++ struct sfc_flash *flash = to_ingenic_spi_nand(mtd); ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ uint8_t *pbuf = nand_info->swapbuf; ++ uint32_t pagesize = mtd->writesize; ++ uint32_t pageaddr; ++ uint32_t columnaddr; ++ uint32_t rlen; ++ int32_t ret = 0, reterr = 0, ret_eccvalue = 0; ++ int32_t split; ++ ++ mutex_lock(&flash->lock); ++ while(len) { ++ pageaddr = (uint32_t)from / pagesize; ++ columnaddr = (uint32_t)from % pagesize; ++ rlen = min_t(uint32_t, len, pagesize - columnaddr); ++ ++ split = is_split_page((void *)buf, rlen); ++ if(!split) { ++ pbuf = buf; ++ } else { ++ pbuf = nand_info->swapbuf; ++ } ++ ret = ingenic_sfc_nand_read(flash, pageaddr, columnaddr, pbuf, rlen); ++ if(split) ++ memcpy(buf, pbuf, rlen); ++ if(ret < 0) { ++ dev_err(flash->dev, "%s %s %d: ingenic_sfc_nand_read error, ret = %d, \ ++ pageaddr = %u, columnaddr = %u, rlen = %u\n", ++ __FILE__, __func__, __LINE__, ++ ret, pageaddr, columnaddr, rlen); ++ reterr = ret; ++ if(ret == -EIO) ++ break; ++ } else if (ret > 0) { ++ dev_dbg(flash->dev, "%s %s %d: ingenic_sfc_nand_read, ecc value = %d, \ ++ pageaddr = %u, columnaddr = %u, rlen = %u\n", ++ __FILE__, __func__, __LINE__, ++ ret, pageaddr, columnaddr, rlen); ++ ret_eccvalue = ret; ++ } ++ ++ len -= rlen; ++ from += rlen; ++ buf += rlen; ++ *retlen += rlen; ++ } ++ mutex_unlock(&flash->lock); ++ return reterr ? reterr : (ret_eccvalue ? ret_eccvalue : ret); ++} ++ ++static int ingenic_sfcnand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) ++{ ++ struct sfc_flash *flash = to_ingenic_spi_nand(mtd); ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ void *pbuf = nand_info->swapbuf; ++ uint32_t pagesize = mtd->writesize; ++ uint32_t pageaddr; ++ uint32_t columnaddr; ++ uint32_t wlen; ++ int32_t ret; ++ int32_t split; ++ ++ mutex_lock(&flash->lock); ++ while(len) { ++ pageaddr = (uint32_t)to / pagesize; ++ columnaddr = (uint32_t)to % pagesize; ++ wlen = min_t(uint32_t, pagesize - columnaddr, len); ++ ++ split = is_split_page((void *)buf, wlen); ++ if(split) { ++ pbuf = nand_info->swapbuf; ++ memcpy(pbuf, buf, wlen); ++ } else { ++ pbuf = (void *)buf; ++ } ++ if((ret = ingenic_sfc_nand_write(flash, (u_char *)pbuf, pageaddr, columnaddr, wlen))) { ++ dev_err(flash->dev, "%s %s %d : spi nand write fail, ret = %d, \ ++ pageaddr = %u, columnaddr = %u, wlen = %u\n", ++ __FILE__, __func__, __LINE__, ret, ++ pageaddr, columnaddr, wlen); ++ break; ++ } ++ *retlen += wlen; ++ len -= wlen; ++ to += wlen; ++ buf += wlen; ++ } ++ mutex_unlock(&flash->lock); ++ return ret; ++} ++ ++static int32_t ingenic_sfcnand_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) ++{ ++ struct sfc_flash *flash = to_ingenic_spi_nand(mtd); ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ uint8_t *pbuf = nand_info->swapbuf; ++ uint32_t addr = (uint32_t)from; ++ uint32_t pageaddr = addr / mtd->writesize; ++ int32_t ret = 0, ret_eccvalue = 0; ++ ++ mutex_lock(&flash->lock); ++ if(ops->datbuf) { ++ ret = ingenic_sfcnand_read(mtd, from, ops->len, &ops->retlen, ops->datbuf); ++ if(ret < 0) { ++ dev_err(flash->dev, "%s %s %d : spi nand read data error, ret = %d\n",__FILE__,__func__,__LINE__, ret); ++ if(ret == -EIO) { ++ mutex_unlock(&flash->lock); ++ return ret; ++ } else { ++ ret_eccvalue = ret; ++ } ++ } ++ } ++ ++ if(ops->oobbuf) { ++ int32_t split = is_split_page(ops->oobbuf, ops->ooblen); ++ if(!split) ++ pbuf = ops->oobbuf; ++ ret = ingenic_sfc_nand_read(flash, pageaddr, mtd->writesize + ops->ooboffs, pbuf, ops->ooblen); ++ if(split) ++ memcpy(ops->oobbuf, pbuf, ops->ooblen); ++ if(ret < 0) ++ dev_err(flash->dev, "%s %s %d : spi nand read oob error ,ret= %d\n", __FILE__, __func__, __LINE__, ret); ++ ++ if(ret != -EIO) ++ ops->oobretlen = ops->ooblen; ++ ++ } ++ mutex_unlock(&flash->lock); ++ ++ return ret ? ret : ret_eccvalue; ++} ++ ++static int ingenic_sfcnand_block_bad_check(struct mtd_info *mtd, loff_t ofs, int getchip) ++{ ++ int check_len = 1; ++ unsigned char check_buf[2] = {0x0}; ++ struct nand_chip *chip = (struct nand_chip *)mtd->priv; ++ struct mtd_oob_ops ops; ++ ++ memset(&ops, 0, sizeof(ops)); ++ if (chip->options & NAND_BUSWIDTH_16) ++ check_len = 2; ++ ++ ops.oobbuf = check_buf; ++ ops.ooblen = check_len; ++ ingenic_sfcnand_read_oob(mtd, ofs, &ops); ++ if(badblk_check(check_len, check_buf)) ++ return 1; ++ return 0; ++} ++ ++static int ingenic_sfc_nand_set_feature(struct sfc_flash *flash, uint8_t addr, uint32_t val) ++{ ++ struct sfc_transfer transfer; ++ ++ memset(&transfer, 0, sizeof(transfer)); ++ sfc_list_init(&transfer); ++ nand_set_feature(&transfer, addr, &val); ++ if(sfc_sync(flash->sfc, &transfer)) { ++ dev_err(flash->dev, "sfc_sync error ! %s %s %d\n", __FILE__, __func__, __LINE__); ++ return -EIO; ++ } ++ return 0; ++} ++ ++static int ingenic_sfc_nand_get_feature(struct sfc_flash *flash, uint8_t addr, uint8_t *val) ++{ ++ struct sfc_transfer transfer; ++ ++ memset(&transfer, 0, sizeof(transfer)); ++ sfc_list_init(&transfer); ++ nand_get_feature(&transfer, addr, val); ++ if(sfc_sync(flash->sfc, &transfer)) { ++ dev_err(flash->dev, "sfc_sync error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ return 0; ++} ++ ++static int32_t __init ingenic_sfc_nand_dev_init(struct sfc_flash *flash) ++{ ++ int32_t ret; ++ /*release protect*/ ++ uint8_t feature = 0, status = 0; ++ if((ret = ingenic_sfc_nand_set_feature(flash, SPINAND_ADDR_PROTECT, feature))) ++ goto exit; ++ ++ if((ret = ingenic_sfc_nand_get_feature(flash, SPINAND_ADDR_FEATURE, &feature))) ++ goto exit; ++ ++ feature |= (1 << 4) | (1 << 3) | (1 << 0); ++ if((ret = ingenic_sfc_nand_set_feature(flash, SPINAND_ADDR_FEATURE, feature))) ++ goto exit; ++ ++ if((ret = ingenic_sfc_nand_get_feature(flash, SPINAND_ADDR_FEATURE, &status))); ++ goto exit; ++ if(status != feature) { ++ dev_err(flash->dev, "set feature != get feature, set feature failed!\n"); ++ ret = -EIO; ++ goto exit; ++ } ++ return 0; ++exit: ++ return ret; ++} ++ ++static int32_t __init ingenic_sfcnand_fill_ops(struct sfc_flash *flash, struct ingenic_sfcnand_ops *slave_ops) { ++ ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ /*master ops:sfcnand driver ops*/ ++ struct ingenic_sfcnand_ops *master_ops = &nand_info->ops; ++ struct ingenic_sfcnand_read *master_read_ops = &master_ops->nand_read_ops; ++ struct ingenic_sfcnand_write *master_write_ops = &master_ops->nand_write_ops; ++ struct ingenic_sfcnand_erase *master_erase_ops = &master_ops->nand_erase_ops; ++ ++ *master_ops = *slave_ops; ++ ++ /*read ops*/ ++ master_read_ops->pageread_to_cache ? : (master_read_ops->pageread_to_cache = nand_pageread_to_cache); ++ ++ if(!master_read_ops->get_feature) { ++ dev_err(flash->dev, "ERROR: nand device must have get_read_feature function,id_manufactory= %02x, id_device=%02x\n", nand_info->id_manufactory, nand_info->id_device); ++ return -EIO; ++ } ++ ++ master_read_ops->single_read ? : (master_read_ops->single_read = nand_single_read); ++ ++ master_read_ops->quad_read ? : (master_read_ops->quad_read = nand_quad_read); ++ ++ /*write ops*/ ++ master_write_ops->write_enable ? : (master_write_ops->write_enable = nand_write_enable); ++ ++ master_write_ops->single_load ? : (master_write_ops->single_load = nand_single_load); ++ ++ master_write_ops->quad_load ? : (master_write_ops->quad_load = nand_quad_load); ++ ++ master_write_ops->program_exec ? : (master_write_ops->program_exec = nand_program_exec); ++ ++ master_write_ops->get_feature ? : (master_write_ops->get_feature = nand_get_program_feature); ++ ++ /*erase ops*/ ++ master_erase_ops->write_enable ? : (master_erase_ops->write_enable = nand_write_enable); ++ ++ master_erase_ops->block_erase ? : (master_erase_ops->block_erase = nand_block_erase); ++ ++ master_erase_ops->get_feature ? : (master_erase_ops->get_feature = nand_get_erase_feature); ++ ++ return 0; ++} ++ ++static int32_t __init ingenic_sfc_nand_try_id(struct sfc_flash *flash) ++{ ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ struct ingenic_sfcnand_device *nand_device; ++ struct sfc_transfer transfer; ++ uint8_t addr_len[] = {0, 1}; ++ uint8_t id_buf[2] = {0}; ++ uint8_t i = 0; ++ ++ for(i = 0; i < sizeof(addr_len); i++) { ++ memset(&transfer, 0, sizeof(transfer)); ++ sfc_list_init(&transfer); ++ transfer.sfc_mode = TM_STD_SPI; ++ transfer.cmd_info.cmd = SPINAND_CMD_RDID; ++ ++ transfer.addr = 0; ++ transfer.addr_len = addr_len[i]; ++ ++ transfer.cmd_info.dataen = ENABLE; ++ transfer.data = id_buf; ++ transfer.len = sizeof(id_buf); ++ transfer.direction = GLB_TRAN_DIR_READ; ++ transfer.data_dummy_bits = 0; ++ ++ transfer.ops_mode = CPU_OPS; ++ if(sfc_sync(flash->sfc, &transfer)){ ++ dev_err(flash->dev,"sfc_sync error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ list_for_each_entry(nand_device, &nand_list, list) { ++ if(nand_device->id_manufactory == id_buf[0]) { ++ nand_info->id_manufactory = id_buf[0]; ++ nand_info->id_device = id_buf[1]; ++ break; ++ } ++ } ++ ++ if(nand_info->id_manufactory && nand_info->id_device) ++ break; ++ } ++ ++ if(!nand_info->id_manufactory && !nand_info->id_device) { ++ dev_err(flash->dev, " ERROR!: don`t support this nand manufactory, please add nand driver\n"); ++ return -ENODEV; ++ } else { ++ struct device_id_struct *device_id = nand_device->id_device_list; ++ int32_t id_count = nand_device->id_device_count; ++ while(id_count--) { ++ if(device_id->id_device == nand_info->id_device) { ++ /*notice :base_param and partition param should read from nand*/ ++ nand_info->param = *device_id->param; ++ break; ++ } ++ device_id++; ++ } ++ if(id_count < 0) { ++ dev_err(flash->dev, "ERROR: do support this device, id_manufactory = 0x%02x, id_device = 0x%02x\n", nand_info->id_manufactory, nand_info->id_device); ++ return -ENODEV; ++ } ++ } ++ dev_info(flash->dev, "Found Supported device, id_manufactory = 0x%02x, id_device = 0x%02x\n", nand_info->id_manufactory, nand_info->id_device); ++ ++ return ingenic_sfcnand_fill_ops(flash, &nand_device->ops); ++} ++ ++static int32_t __init nand_partition_param_copy(struct sfc_flash *flash, struct ingenic_sfcnand_burner_param *burn_param) { ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ int i = 0, count = 5, ret; ++ size_t retlen = 0; ++ ++ /*partition param copy*/ ++ nand_info->partition.num_partition = burn_param->partition_num; ++ ++ burn_param->partition = kzalloc(nand_info->partition.num_partition * sizeof(struct ingenic_sfcnand_partition), GFP_KERNEL); ++ if (IS_ERR_OR_NULL(burn_param->partition)) { ++ dev_err(flash->dev, "alloc partition space failed!\n"); ++ return -ENOMEM; ++ } ++ ++ nand_info->partition.partition = kzalloc(nand_info->partition.num_partition * sizeof(struct mtd_partition), GFP_KERNEL); ++ if (IS_ERR_OR_NULL(nand_info->partition.partition)) { ++ dev_err(flash->dev, "alloc partition space failed!\n"); ++ kfree(burn_param->partition); ++ return -ENOMEM; ++ } ++ ++partition_retry_read: ++ ret = ingenic_sfcnand_read(&flash->mtd, flash->param_offset + sizeof(*burn_param) - sizeof(burn_param->partition), ++ nand_info->partition.num_partition * sizeof(struct ingenic_sfcnand_partition), ++ &retlen, (u_char *)burn_param->partition); ++ ++ if((ret < 0) && count--) ++ goto partition_retry_read; ++ if(count < 0) { ++ dev_err(flash->dev, "read nand partition failed!\n"); ++ kfree(burn_param->partition); ++ kfree(nand_info->partition.partition); ++ return -EIO; ++ } ++ ++ for(i = 0; i < burn_param->partition_num; i++) { ++ nand_info->partition.partition[i].name = burn_param->partition[i].name; ++ nand_info->partition.partition[i].size = burn_param->partition[i].size; ++ nand_info->partition.partition[i].offset = burn_param->partition[i].offset; ++ nand_info->partition.partition[i].mask_flags = burn_param->partition[i].mask_flags; ++ } ++ return 0; ++} ++ ++static struct ingenic_sfcnand_burner_param *burn_param; ++static int32_t __init flash_part_from_chip(struct sfc_flash *flash) { ++ ++ int32_t ret = 0, retlen = 0, count = 5; ++ ++ burn_param = kzalloc(sizeof(struct ingenic_sfcnand_burner_param), GFP_KERNEL); ++ if(IS_ERR_OR_NULL(burn_param)) { ++ dev_err(flash->dev, "alloc burn_param space error!\n"); ++ return -ENOMEM; ++ } ++ ++ count = 5; ++param_retry_read: ++ ret = ingenic_sfcnand_read(&flash->mtd, flash->param_offset, ++ sizeof(struct ingenic_sfcnand_burner_param), &retlen, (u_char *)burn_param); ++ if((ret < 0) && count--) ++ goto param_retry_read; ++ if(count < 0) { ++ dev_err(flash->dev, "read nand base param failed!\n"); ++ ret = -EIO; ++ goto failed; ++ } ++ ++ if(burn_param->magic_num != SPINAND_MAGIC_NUM) { ++ dev_info(flash->dev, "NOTICE: this flash haven`t param, magic_num:%x\n", burn_param->magic_num); ++ ret = -EINVAL; ++ goto failed; ++ } ++ ++ if(nand_partition_param_copy(flash, burn_param)) { ++ ret = -ENOMEM; ++ goto failed; ++ } ++ ++ return 0; ++failed: ++ kfree(burn_param); ++ return ret; ++ ++} ++ ++static int32_t __init flash_part_from_board(struct sfc_flash *flash, struct ingenic_sfc_info *board_info) { ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ struct ingenic_sfcnand_partition *flash_partition = board_info->flash_partition; ++ int8_t i = 0; ++ ++ nand_info->partition.num_partition = board_info->num_partition; ++ nand_info->partition.partition = kzalloc(nand_info->partition.num_partition * sizeof(struct mtd_partition), GFP_KERNEL); ++ if (IS_ERR_OR_NULL(nand_info->partition.partition)) { ++ dev_err(flash->dev, "alloc partition space failed!\n"); ++ nand_info->partition.num_partition = 0; ++ return -ENOMEM; ++ } ++ ++ for(i = 0; i < board_info->num_partition; i++) { ++ nand_info->partition.partition[i].name = flash_partition[i].name; ++ nand_info->partition.partition[i].size = flash_partition[i].size; ++ nand_info->partition.partition[i].offset = flash_partition[i].offset; ++ nand_info->partition.partition[i].mask_flags = flash_partition[i].mask_flags; ++ } ++ return 0; ++} ++ ++static int32_t __init ingenic_sfcnand_partition(struct sfc_flash *flash, struct ingenic_sfc_info *board_info) { ++ int32_t ret = 0; ++ if(!board_info || !board_info->use_board_info) { ++ if((ret = flash_part_from_chip(flash))) ++ dev_err(flash->dev, "read partition from flash failed!\n"); ++ } else { ++ if((ret = flash_part_from_board(flash, board_info))) ++ dev_err(flash->dev, "copy partition from board failed!\n"); ++ } ++ return ret; ++} ++ ++int ingenic_sfcnand_register(struct ingenic_sfcnand_device *flash) { ++ list_add_tail(&flash->list, &nand_list); ++ return 0; ++} ++EXPORT_SYMBOL_GPL(ingenic_sfcnand_register); ++ ++static int __init ingenic_sfcnand_probe(struct platform_device *pdev) ++{ ++ const char *ingenic_probe_types[] = {"cmdlinepart",NULL}; ++ struct ingenic_sfc_info *board_info = NULL; ++ struct sfc_flash *flash; ++ struct nand_chip *chip; ++ struct ingenic_sfcnand_flashinfo *nand_info; ++ int32_t ret; ++ ++ flash = kzalloc(sizeof(struct sfc_flash), GFP_KERNEL); ++ if (IS_ERR_OR_NULL(flash)) ++ return -ENOMEM; ++ chip = kzalloc(sizeof(struct nand_chip), GFP_KERNEL); ++ if (IS_ERR_OR_NULL(chip)) { ++ kfree(flash); ++ return -ENOMEM; ++ } ++ nand_info = kzalloc(sizeof(struct ingenic_sfcnand_flashinfo), GFP_KERNEL); ++ if(IS_ERR_OR_NULL(nand_info)) { ++ kfree(flash); ++ kfree(chip); ++ return -ENOMEM; ++ } ++ ++ platform_set_drvdata(pdev, flash); ++ mutex_init(&flash->lock); ++ flash->dev = &pdev->dev; ++ flash->flash_info = nand_info; ++ flash->sfc = sfc_res_init(pdev); ++ if(IS_ERR(flash->sfc)) { ++ dev_err(flash->dev, "sfc control init error!\n"); ++ ret = PTR_ERR(flash->sfc); ++ goto free_base; ++ } ++ board_info = pdev->dev.platform_data; ++ if(board_info->param_offset > 0) { ++ flash->param_offset = board_info->param_offset; ++ } else { ++ flash->param_offset = SPIFLASH_PARAMER_OFFSET; ++ } ++ ++#define THOLD 5 ++#define TSETUP 5 ++#define TSHSL_R 20 ++#define TSHSL_W 50 ++ ++ set_flash_timing(flash->sfc, THOLD, TSETUP, TSHSL_R, TSHSL_W); ++ ++ if((ret = ingenic_sfc_nand_dev_init(flash))) { ++ dev_err(flash->dev, "nand device init failed!\n"); ++ goto free_base; ++ } ++ ++ if((ret = ingenic_sfc_nand_try_id(flash))) { ++ dev_err(flash->dev, "try device id failed\n"); ++ goto free_base; ++ } ++ ++ set_flash_timing(flash->sfc, nand_info->param.tHOLD, ++ nand_info->param.tSETUP, nand_info->param.tSHSL_R, nand_info->param.tSHSL_W); ++ flash->mtd.name = "sfc_nand"; ++ flash->mtd.owner = THIS_MODULE; ++ flash->mtd.type = MTD_NANDFLASH; ++ flash->mtd.flags |= MTD_CAP_NANDFLASH; ++ flash->mtd.erasesize = nand_info->param.blocksize; ++ flash->mtd.writesize = nand_info->param.pagesize; ++ flash->mtd.size = nand_info->param.flashsize; ++ flash->mtd.oobsize = nand_info->param.oobsize; ++ flash->mtd.writebufsize = flash->mtd.writesize; ++ flash->mtd.bitflip_threshold = flash->mtd.ecc_strength = nand_info->param.ecc_max - 1; ++ ++ chip->select_chip = NULL; ++ chip->badblockbits = 8; ++ chip->scan_bbt = nand_default_bbt; ++ chip->block_bad = ingenic_sfcnand_block_bad_check; ++ chip->block_markbad = ingenic_sfcnand_chip_block_markbad; ++ //chip->ecc.layout= &gd5f_ecc_layout_128; // for erase ops ++ chip->bbt_erase_shift = chip->phys_erase_shift = ffs(flash->mtd.erasesize) - 1; ++ chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL); ++ if(IS_ERR_OR_NULL(chip->buffers)) { ++ dev_err(flash->dev, "alloc nand buffer failed\n"); ++ ret = -ENOMEM; ++ goto free_base; ++ } ++ chip->buffers->databuf = kzalloc(nand_info->param.pagesize + nand_info->param.oobsize, GFP_KERNEL); ++ if(IS_ERR_OR_NULL(chip->buffers->databuf)) { ++ dev_err(flash->dev, "alloc nand buffer->databuf failed\n"); ++ ret = -ENOMEM; ++ kfree(chip->buffers); ++ goto free_base; ++ } ++ ++ /* Set the bad block position */ ++ if (flash->mtd.writesize > 512 || (chip->options & NAND_BUSWIDTH_16)) ++ chip->badblockpos = NAND_LARGE_BADBLOCK_POS; ++ else ++ chip->badblockpos = NAND_SMALL_BADBLOCK_POS; ++ ++ flash->mtd.priv = chip; ++ flash->mtd._erase = ingenic_sfcnand_erase; ++ flash->mtd._read = ingenic_sfcnand_read; ++ flash->mtd._write = ingenic_sfcnand_write; ++ flash->mtd._read_oob = ingenic_sfcnand_read_oob; ++ flash->mtd._write_oob = ingenic_sfcnand_write_oob; ++ flash->mtd._block_isbad = ingenic_sfcnand_block_isbab; ++ flash->mtd._block_markbad = ingenic_sfcnand_block_markbad; ++ ++ nand_info->swapbuf = kmalloc(nand_info->param.pagesize, GFP_KERNEL); ++ if(IS_ERR_OR_NULL(nand_info->swapbuf)) { ++ ret = -ENOMEM; ++ kfree(chip->buffers->databuf); ++ kfree(chip->buffers); ++ goto free_base; ++ } ++ ++ if((ret = chip->scan_bbt(&flash->mtd))) { ++ dev_err(flash->dev, "creat and scan bbt failed\n"); ++ goto free_all; ++ } ++ ++ if((ret = ingenic_sfcnand_partition(flash, board_info))) { ++ if(ret == -EINVAL) ++ return 0; ++ dev_err(flash->dev, "read flash partition failed!\n"); ++ goto free_all; ++ } ++ ++/* dump_flash_info(flash);*/ ++ ret = mtd_device_parse_register(&flash->mtd, ingenic_probe_types, NULL, nand_info->partition.partition, nand_info->partition.num_partition); ++ if (ret) { ++ kfree(nand_info->partition.partition); ++ if(!board_info->use_board_info) { ++ kfree(burn_param->partition); ++ kfree(burn_param); ++ } ++ ret = -ENODEV; ++ goto free_all; ++ } ++ ++ return 0; ++ ++free_all: ++ kfree(chip->buffers->databuf); ++ kfree(chip->buffers); ++ kfree(nand_info->swapbuf); ++ ++free_base: ++ kfree(flash); ++ kfree(chip); ++ kfree(nand_info); ++ return ret; ++} ++ ++static int __exit ingenic_sfc_remove(struct platform_device *pdev) ++{ ++ struct sfc_flash *flash = platform_get_drvdata(pdev); ++ struct sfc *sfc = flash->sfc; ++ clk_disable_unprepare(sfc->clk_gate); ++ clk_put(sfc->clk_gate); ++ clk_disable_unprepare(sfc->clk); ++ clk_put(sfc->clk); ++ free_irq(sfc->irq, flash); ++ iounmap(sfc->iomem); ++ release_mem_region(sfc->ioarea->start, resource_size(sfc->ioarea)); ++ platform_set_drvdata(pdev, NULL); ++ return 0; ++} ++ ++static int ingenic_sfc_suspend(struct platform_device *pdev, pm_message_t msg) ++{ ++ struct sfc_flash *flash = platform_get_drvdata(pdev); ++ struct sfc *sfc = flash->sfc; ++ disable_irq(sfc->irq); ++ clk_disable_unprepare(sfc->clk_gate); ++ clk_disable_unprepare(sfc->clk); ++ return 0; ++} ++ ++static int ingenic_sfc_resume(struct platform_device *pdev) ++{ ++ struct sfc_flash *flash = platform_get_drvdata(pdev); ++ struct sfc *sfc = flash->sfc; ++ clk_prepare_enable(sfc->clk); ++ clk_prepare_enable(sfc->clk_gate); ++ enable_irq(sfc->irq); ++ return 0; ++} ++ ++void ingenic_sfc_shutdown(struct platform_device *pdev) ++{ ++ struct sfc_flash *flash = platform_get_drvdata(pdev); ++ struct sfc *sfc = flash->sfc; ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ ++ if(nand_info->id_manufactory == 0xEF && ++ nand_info->id_device == 0xAB) ++ winbond_reset(flash); ++ ++ disable_irq(sfc->irq); ++ clk_disable_unprepare(sfc->clk_gate); ++ clk_disable_unprepare(sfc->clk); ++ return ; ++} ++ ++static const struct of_device_id ingenicsfc_match[] = { ++ { .compatible = "ingenic,sfc", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ingenicsfc_match); ++ ++static struct platform_driver ingenic_sfcnand_drv = { ++ .driver = { ++ .name = "ingenic-sfc", ++ .owner = THIS_MODULE, ++ .of_match_table = ingenicsfc_match, ++ }, ++ .remove = __exit_p(ingenic_sfc_remove), ++ .suspend = ingenic_sfc_suspend, ++ .resume = ingenic_sfc_resume, ++ .shutdown = ingenic_sfc_shutdown, ++}; ++module_platform_driver_probe(ingenic_sfcnand_drv, ingenic_sfcnand_probe); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("INGENIC SFC Driver"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_ingenic_sfc_nor.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_ingenic_sfc_nor.c.patch new file mode 100644 index 00000000..85b6eef1 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_ingenic_sfc_nor.c.patch @@ -0,0 +1,980 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v1/ingenic_sfc_nor.c b/drivers/mtd/devices/ingenic_sfc_v1/ingenic_sfc_nor.c +--- a/drivers/mtd/devices/ingenic_sfc_v1/ingenic_sfc_nor.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v1/ingenic_sfc_nor.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,976 @@ ++/* ++ * SFC controller for SPI protocol, use FIFO and DMA; ++ * ++ * Copyright (c) 2015 Ingenic ++ * Author: ++ * 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. ++ * ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "sfc_flash.h" ++#include "spinor.h" ++#include "ingenic_sfc_common.h" ++ ++extern int get_status(struct sfc_flash *flash, int command, int len); ++//#define DEBUG_CLONER_PARAMS ++ ++static int L2CACHE_ALIGN_SIZE; ++ ++#define STATUS_SUSPND (1<<0) ++ ++ ++struct sfc_flash *to_ingenic_spi_norflash(struct mtd_info *mtd_info) ++{ ++ return container_of(mtd_info, struct sfc_flash, mtd); ++} ++ ++int32_t sfc_nor_reset(struct sfc_flash *flash) ++{ ++ struct sfc_transfer transfer; ++ ++ memset(&transfer, 0, sizeof(transfer)); ++ sfc_list_init(&transfer); ++ ++ transfer.cmd_info.cmd = SPINOR_OP_RSTEN; ++ transfer.cmd_info.dataen = DISABLE; ++ transfer.sfc_mode = TM_STD_SPI; ++ ++ if(sfc_sync(flash->sfc, &transfer)) { ++ dev_err(flash->dev,"sfc_sync error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ memset(&transfer, 0, sizeof(transfer)); ++ sfc_list_init(&transfer); ++ ++ transfer.cmd_info.cmd = SPINOR_OP_RST; ++ transfer.cmd_info.dataen = DISABLE; ++ transfer.sfc_mode = TM_STD_SPI; ++ ++ if(sfc_sync(flash->sfc, &transfer)) { ++ dev_err(flash->dev,"sfc_sync error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ udelay(100); ++ return 0; ++} ++ ++int sfc_nor_read_id(struct sfc_flash *flash, u8 command, unsigned int addr, int addr_len, size_t len, int dummy_byte) ++{ ++ ++ struct sfc_transfer transfer; ++ int ret; ++ unsigned int chip_id = 0; ++ ++ memset(&transfer, 0, sizeof(transfer)); ++ sfc_list_init(&transfer); ++ ++ transfer.sfc_mode = TM_STD_SPI; ++ transfer.cmd_info.cmd = command; ++ ++ transfer.addr_len = addr_len; ++ transfer.addr = addr; ++ ++ transfer.cmd_info.dataen = ENABLE; ++ transfer.data =(uint8_t *)&chip_id; ++ transfer.len = len; ++ transfer.direction = GLB_TRAN_DIR_READ; ++ ++ transfer.data_dummy_bits = dummy_byte; ++ transfer.ops_mode = CPU_OPS; ++ ++ ret = sfc_sync(flash->sfc, &transfer); ++ if(ret) { ++ dev_err(flash->dev,"sfc_sync error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ ret=-EIO; ++ } ++ ++ chip_id = chip_id & 0x00ffffff; ++ chip_id = ((chip_id & 0xff) << 16) | (((chip_id >> 8) & 0xff) << 8) | ((chip_id >> 16) & 0xff); ++ return chip_id; ++} ++ ++static unsigned int sfc_do_read(struct sfc_flash *flash, unsigned int addr, unsigned char *buf, size_t len) ++{ ++ struct spinor_flashinfo *nor_info = flash->flash_info; ++ unsigned char command = nor_info->cur_r_cmd->cmd; ++ int dummy_byte = nor_info->cur_r_cmd->dummy_byte; ++ int addr_size = nor_info->cur_r_cmd->addr_nbyte; ++ int transfer_mode = nor_info->cur_r_cmd->transfer_mode; ++ struct sfc_transfer transfer; ++ int ret; ++ ++ memset(&transfer, 0, sizeof(transfer)); ++ sfc_list_init(&transfer); ++ ++ transfer.sfc_mode = transfer_mode; ++ transfer.cmd_info.cmd = command; ++ ++ transfer.addr_len = addr_size; ++ transfer.addr = addr; ++ ++ transfer.cmd_info.dataen = ENABLE; ++ transfer.len = len; ++ transfer.data = buf; ++ transfer.cur_len = 0; ++ ++ transfer.data_dummy_bits = dummy_byte; ++ transfer.direction = GLB_TRAN_DIR_READ; ++ if (len >= L2CACHE_ALIGN_SIZE) ++ transfer.ops_mode = DMA_OPS; ++ else ++ transfer.ops_mode = CPU_OPS; ++ ++ ret = sfc_sync(flash->sfc, &transfer); ++ if(ret) { ++ dev_err(flash->dev,"sfc_sync error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ ret=-EIO; ++ } ++ /*fix the cache line problem,when use jffs2 filesystem must be flush cache twice*/ ++ if(transfer.ops_mode == DMA_OPS) ++ dma_cache_sync(NULL, (void *)buf, len, DMA_FROM_DEVICE); ++ ++ return transfer.cur_len; ++} ++static unsigned int sfc_do_write(struct sfc_flash *flash, unsigned int addr, const unsigned char *buf, size_t len) ++{ ++ struct spinor_flashinfo *nor_info = flash->flash_info; ++ struct spi_nor_info *spi_nor_info = nor_info->nor_flash_info; ++ struct spi_nor_cmd_info *wr_en = &spi_nor_info->wr_en; ++ struct spi_nor_st_info *busy = &spi_nor_info->busy; ++ unsigned char command = nor_info->cur_w_cmd->cmd; ++ int dummy_byte = nor_info->cur_w_cmd->dummy_byte; ++ int transfer_mode = nor_info->cur_w_cmd->transfer_mode; ++ int addr_size = nor_info->cur_w_cmd->addr_nbyte; ++ struct sfc_transfer transfer[3]; ++ int ret; ++ uint32_t sta_reg = 0; ++ ++ memset(transfer, 0, sizeof(transfer)); ++ sfc_list_init(transfer); ++ ++ /* write enable */ ++ transfer[0].sfc_mode = transfer_mode; ++ transfer[0].cmd_info.cmd = wr_en->cmd; ++ ++ transfer[0].addr_len = wr_en->addr_nbyte; ++ ++ transfer[0].cmd_info.dataen = DISABLE; ++ ++ transfer[0].data_dummy_bits = wr_en->dummy_byte; ++ ++ /* write ops */ ++ transfer[1].sfc_mode = transfer_mode; ++ transfer[1].cmd_info.cmd = command; ++ ++ transfer[1].addr_len = addr_size; ++ transfer[1].addr = addr; ++ ++ transfer[1].cmd_info.dataen = ENABLE; ++ transfer[1].data = (uint8_t *)buf; ++ transfer[1].len = len; ++ transfer[1].cur_len = 0; ++ transfer[1].direction = GLB_TRAN_DIR_WRITE; ++ ++ transfer[1].data_dummy_bits = dummy_byte; ++ if(len >= L2CACHE_ALIGN_SIZE) ++ transfer[1].ops_mode = DMA_OPS; ++ else ++ transfer[1].ops_mode = CPU_OPS; ++ sfc_list_add_tail(&transfer[1], transfer); ++ ++ ret = sfc_sync(flash->sfc, transfer); ++ if(ret) { ++ dev_err(flash->dev,"sfc_sync error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ ret=-EIO; ++ } ++ ++ do { ++ sta_reg = get_status(flash, busy->cmd, busy->len); ++ sta_reg = (sta_reg >> busy->bit_shift) & busy->mask; ++ } while (sta_reg != busy->val); ++ ++ return transfer[1].cur_len; ++} ++ ++static int sfc_do_erase(struct sfc_flash *flash, uint32_t addr) ++{ ++ struct spinor_flashinfo *nor_info = flash->flash_info; ++ struct spi_nor_info *spi_nor_info = nor_info->nor_flash_info; ++ struct spi_nor_cmd_info *sector_erase = &spi_nor_info->sector_erase; ++ struct spi_nor_cmd_info *wr_en = &spi_nor_info->wr_en; ++ struct spi_nor_st_info *busy = &spi_nor_info->busy; ++ struct sfc_transfer transfer[3]; ++ int addr_size = sector_erase->addr_nbyte; ++ int ret; ++ uint32_t sta_reg = 0; ++ ++ memset(transfer, 0, sizeof(transfer)); ++ sfc_list_init(transfer); ++ ++ /* write enable */ ++ transfer[0].sfc_mode = wr_en->transfer_mode; ++ transfer[0].cmd_info.cmd = wr_en->cmd; ++ ++ transfer[0].addr_len = wr_en->addr_nbyte; ++ ++ transfer[0].cmd_info.dataen = DISABLE; ++ ++ transfer[0].data_dummy_bits = wr_en->dummy_byte; ++ ++ /* erase ops */ ++ transfer[1].sfc_mode = TM_STD_SPI; ++ transfer[1].cmd_info.cmd = sector_erase->cmd; ++ ++ transfer[1].addr_len = addr_size; ++ transfer[1].addr = addr; ++ ++ transfer[1].cmd_info.dataen = DISABLE; ++ ++ transfer[1].data_dummy_bits = sector_erase->dummy_byte; ++ transfer[1].direction = GLB_TRAN_DIR_WRITE; ++ sfc_list_add_tail(&transfer[1], transfer); ++ ++ /*polling :have problem*/ ++ ++ ret = sfc_sync(flash->sfc, transfer); ++ if(ret) { ++ dev_err(flash->dev,"sfc_sync error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ ret=-EIO; ++ } ++ ++ do { ++ sta_reg = get_status(flash, busy->cmd, busy->len); ++ sta_reg = (sta_reg >> busy->bit_shift) & busy->mask; ++ } while (sta_reg != busy->val); ++ ++ return ret; ++} ++ ++static int sfc_write(struct sfc_flash *flash, loff_t to, size_t len, const unsigned char *buf) ++{ ++ unsigned int s_len = 0, f_len = 0, a_len = 0; ++ ++ if (len > L2CACHE_ALIGN_SIZE) { ++ s_len = ALIGN((unsigned int )buf, L2CACHE_ALIGN_SIZE) - (unsigned int)buf; ++ if (s_len) { ++ sfc_do_write(flash, (unsigned int)to, buf, s_len); ++ } ++ ++ a_len = (len - s_len) - (len - s_len) % L2CACHE_ALIGN_SIZE; ++ if (a_len) { ++ sfc_do_write(flash, (unsigned int)to + s_len , &buf[s_len], a_len); ++ } ++ ++ f_len = len - s_len - a_len; ++ if (f_len) { ++ sfc_do_write(flash, (unsigned int)to + s_len + a_len , &buf[s_len + a_len], f_len); ++ } ++ } else { ++ sfc_do_write(flash, (unsigned int)to, buf, len); ++ } ++ ++ return len; ++} ++ ++ ++static int sfc_read_cacheline_align(struct sfc_flash *flash, unsigned int addr, unsigned char *buf, size_t len) ++{ ++ unsigned int ret = 0; ++ unsigned int s_len = 0, f_len = 0, a_len = 0; ++ ++ /** ++ * s_len : start not align length ++ * a_len : middle align length ++ * f_len : end not align length ++ */ ++ if (len > L2CACHE_ALIGN_SIZE) { ++ s_len = ALIGN((unsigned int )buf, L2CACHE_ALIGN_SIZE) - (unsigned int)buf; ++ if (s_len) { ++ ret += sfc_do_read(flash, (unsigned int)addr, buf, s_len); ++ } ++ ++ a_len = (len - s_len) - (len - s_len) % L2CACHE_ALIGN_SIZE; ++ if (a_len) { ++ ret += sfc_do_read(flash, (unsigned int)addr + s_len , &buf[s_len], a_len); ++ } ++ ++ f_len = len - s_len - a_len; ++ if (f_len) { ++ ret += sfc_do_read(flash, (unsigned int)addr + s_len + a_len , &buf[s_len + a_len], f_len); ++ } ++ } else { ++ ret = sfc_do_read(flash, (unsigned int)addr, buf, len); ++ } ++ ++ return ret; ++} ++ ++ ++static unsigned int sfc_read_continue(struct sfc_flash *flash, unsigned int addr, unsigned char *buf, size_t len) ++{ ++ unsigned char *vaddr_start = NULL; ++ unsigned char *vaddr_next = NULL; ++ int pfn = 0, pfn_next = 0; ++ int off_len = 0, transfer_len = 0; ++ int page_num = 0, page_offset = 0; ++ int continue_times = 0; ++ int ret = 0; ++ ++ if (is_vmalloc_addr(buf)) { ++ vaddr_start = buf; ++ pfn = vmalloc_to_pfn(vaddr_start); ++ page_offset = (unsigned int)vaddr_start & 0xfff; ++ ++ off_len = PAGE_SIZE - page_offset; ++ ++ if (off_len >= len) { //all in one page ++ ret = sfc_read_cacheline_align(flash, addr, buf, len); ++ return len; ++ } else { ++ page_num = (len - off_len) / PAGE_SIZE; //more than one page ++ } ++ ++ vaddr_next = vaddr_start + off_len; ++ while (page_num) { //find continue page ++ pfn_next = vmalloc_to_pfn((unsigned char *)((unsigned int)vaddr_next)); ++ if (pfn + 1 == pfn_next) { ++ page_num --; ++ continue_times++; ++ pfn++; ++ vaddr_next += PAGE_SIZE; ++ } else { ++ break; ++ } ++ } ++ ++ transfer_len = PAGE_SIZE * continue_times + off_len; ++ ret += sfc_read_cacheline_align(flash, addr, buf, transfer_len); //transfer continue page ++ ++ if (page_num == 0) { //last not continue page ++ if(transfer_len < len) { ++ ret += sfc_read_cacheline_align(flash, addr + transfer_len, &buf[transfer_len], len - transfer_len); ++ } ++ } ++ } else { ++ ret = sfc_read_cacheline_align(flash, addr, buf, len); ++ } ++ ++ return ret; ++ ++} ++ ++static int sfc_read(struct sfc_flash *flash, loff_t from, size_t len, unsigned char *buf) ++{ ++ int tmp_len = 0, current_len = 0; ++ ++ while (len) { ++ tmp_len = sfc_read_continue(flash, (unsigned int)from + current_len, &buf[current_len], len); ++ current_len += tmp_len; ++ len -= tmp_len; ++ } ++ ++ return current_len; ++} ++ ++static int ingenic_spi_norflash_read(struct mtd_info *mtd, loff_t from, size_t len,size_t *retlen, unsigned char *buf) ++{ ++ struct sfc_flash *flash = to_ingenic_spi_norflash(mtd); ++ ++ mutex_lock(&flash->lock); ++ *retlen = sfc_read(flash, from, len, buf); ++ mutex_unlock(&flash->lock); ++ ++ return 0; ++} ++ ++static int ingenic_spi_norflash_write(struct mtd_info *mtd, loff_t to, size_t len, ++ size_t *retlen, const unsigned char *buf) ++{ ++ u32 page_offset, actual_len; ++ struct sfc_flash *flash = to_ingenic_spi_norflash(mtd); ++ struct spinor_flashinfo *nor_info = flash->flash_info; ++ struct spi_nor_info *spi_nor_info = nor_info->nor_flash_info; ++ int ret; ++ ++ mutex_lock(&flash->lock); ++ ++ page_offset = to & (spi_nor_info->page_size - 1); ++ /* do all the bytes fit onto one page? */ ++ if (page_offset + len <= spi_nor_info->page_size) { ++ ret = sfc_write(flash, to, len, buf); ++ *retlen = ret; ++ } else { ++ u32 i; ++ ++ /* the size of data remaining on the first page */ ++ actual_len = spi_nor_info->page_size - page_offset; ++ ret = sfc_write(flash, to, actual_len, buf); ++ *retlen += ret; ++ ++ /* write everything in flash->page_size chunks */ ++ for (i = actual_len; i < len; i += mtd->writesize) { ++ actual_len = len - i; ++ if (actual_len >= mtd->writesize) ++ actual_len = mtd->writesize; ++ ++ ret = sfc_write(flash, to + i, actual_len, buf + i); ++ *retlen += ret; ++ } ++ } ++ mutex_unlock(&flash->lock); ++ return 0; ++} ++ ++static int ingenic_spi_norflash_erase(struct mtd_info *mtd, struct erase_info *instr) ++{ ++ struct sfc_flash *flash = to_ingenic_spi_norflash(mtd); ++ struct spinor_flashinfo *nor_info = flash->flash_info; ++ struct spi_nor_info *spi_nor_info = nor_info->nor_flash_info; ++ uint32_t addr, end; ++ int ret; ++ ++ mutex_lock(&flash->lock); ++ ++ addr = (instr->addr & (mtd->erasesize - 1)); ++ if (addr) { ++ dev_err(flash->dev, "%s eraseaddr no align\n", __func__); ++ mutex_unlock(&flash->lock); ++ return -EINVAL; ++ } ++ end = (instr->len & (mtd->erasesize - 1)); ++ if (end) { ++ dev_err(flash->dev,"%s erasesize no align\n", __func__); ++ mutex_unlock(&flash->lock); ++ return -EINVAL; ++ } ++ addr = (uint32_t)instr->addr; ++ end = addr + (uint32_t)instr->len; ++ ++ while (addr < end) { ++ ret = sfc_do_erase(flash, addr); ++ if (ret) { ++ dev_err(flash->dev,"erase error !\n"); ++ mutex_unlock(&flash->lock); ++ instr->state = MTD_ERASE_FAILED; ++ return ret; ++ } ++ addr += spi_nor_info->erase_size; ++ } ++ mutex_unlock(&flash->lock); ++ instr->state = MTD_ERASE_DONE; ++ ++ mtd_erase_callback(instr); ++ return 0; ++} ++ ++static int get_current_operate_cmd(struct sfc_flash *flash) ++{ ++ struct spinor_flashinfo *nor_info = flash->flash_info; ++ struct spi_nor_info *spi_nor_info = nor_info->nor_flash_info; ++ ++ if (nor_info->quad_succeed) { ++ nor_info->cur_r_cmd = &spi_nor_info->read_quad; ++ nor_info->cur_w_cmd = &spi_nor_info->write_quad; ++ } else { ++ nor_info->cur_r_cmd = &spi_nor_info->read_standard; ++ nor_info->cur_w_cmd = &spi_nor_info->write_standard; ++ } ++ ++ return 0; ++} ++ ++static int32_t ingenic_spi_norflash_read_params(struct sfc_flash *flash, loff_t from, size_t len, uint8_t *buf) ++{ ++ struct sfc_transfer transfer; ++ ++ memset(&transfer, 0, sizeof(transfer)); ++ sfc_list_init(&transfer); ++ ++ transfer.sfc_mode = TM_STD_SPI; ++ transfer.cmd_info.cmd = SPINOR_OP_READ; ++ ++ transfer.addr_len = DEFAULT_ADDRSIZE; ++ transfer.addr = (uint32_t)from; ++ ++ transfer.cmd_info.dataen = ENABLE; ++ transfer.len = len; ++ transfer.data = buf; ++ transfer.direction = GLB_TRAN_DIR_READ; ++ ++ transfer.data_dummy_bits = 0; ++ transfer.ops_mode = CPU_OPS; ++ ++ if(sfc_sync(flash->sfc, &transfer)) { ++ dev_err(flash->dev,"sfc_sync error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++#ifdef DEBUG_CLONER_PARAMS ++static void dump_cloner_params(struct burner_params *params) ++{ ++ struct spi_nor_info *spi_nor_info; ++ ++ spi_nor_info = ¶ms->spi_nor_info; ++ ++ printk("name=%s\n", spi_nor_info->name); ++ printk("id=0x%x\n", spi_nor_info->id); ++ ++ printk("read_standard->cmd=0x%x\n", spi_nor_info->read_standard.cmd); ++ printk("read_standard->dummy=0x%x\n", spi_nor_info->read_standard.dummy_byte); ++ printk("read_standard->addr_nbyte=0x%x\n", spi_nor_info->read_standard.addr_nbyte); ++ printk("read_standard->transfer_mode=0x%x\n", spi_nor_info->read_standard.transfer_mode); ++ ++ printk("read_quad->cmd=0x%x\n", spi_nor_info->read_quad.cmd); ++ printk("read_quad->dummy=0x%x\n", spi_nor_info->read_quad.dummy_byte); ++ printk("read_quad->addr_nbyte=0x%x\n", spi_nor_info->read_quad.addr_nbyte); ++ printk("read_quad->transfer_mode=0x%x\n", spi_nor_info->read_quad.transfer_mode); ++ ++ printk("write_standard->cmd=0x%x\n", spi_nor_info->write_standard.cmd); ++ printk("write_standard->dummy=0x%x\n", spi_nor_info->write_standard.dummy_byte); ++ printk("write_standard->addr_nbyte=0x%x\n", spi_nor_info->write_standard.addr_nbyte); ++ printk("write_standard->transfer_mode=0x%x\n", spi_nor_info->write_standard.transfer_mode); ++ ++ printk("write_quad->cmd=0x%x\n", spi_nor_info->write_quad.cmd); ++ printk("write_quad->dummy=0x%x\n", spi_nor_info->write_quad.dummy_byte); ++ printk("write_quad->addr_nbyte=0x%x\n", spi_nor_info->write_quad.addr_nbyte); ++ printk("write_quad->transfer_mode=0x%x\n", spi_nor_info->write_quad.transfer_mode); ++ ++ printk("sector_erase->cmd=0x%x\n", spi_nor_info->sector_erase.cmd); ++ printk("sector_erase->dummy=0x%x\n", spi_nor_info->sector_erase.dummy_byte); ++ printk("sector_erase->addr_nbyte=0x%x\n", spi_nor_info->sector_erase.addr_nbyte); ++ printk("sector_erase->transfer_mode=0x%x\n", spi_nor_info->sector_erase.transfer_mode); ++ ++ printk("wr_en->cmd=0x%x\n", spi_nor_info->wr_en.cmd); ++ printk("wr_en->dummy=0x%x\n", spi_nor_info->wr_en.dummy_byte); ++ printk("wr_en->addr_nbyte=0x%x\n", spi_nor_info->wr_en.addr_nbyte); ++ printk("wr_en->transfer_mode=0x%x\n", spi_nor_info->wr_en.transfer_mode); ++ ++ printk("en4byte->cmd=0x%x\n", spi_nor_info->en4byte.cmd); ++ printk("en4byte->dummy=0x%x\n", spi_nor_info->en4byte.dummy_byte); ++ printk("en4byte->addr_nbyte=0x%x\n", spi_nor_info->en4byte.addr_nbyte); ++ printk("en4byte->transfer_mode=0x%x\n", spi_nor_info->en4byte.transfer_mode); ++ ++ printk("quad_set->cmd=0x%x\n", spi_nor_info->quad_set.cmd); ++ printk("quad_set->bit_shift=0x%x\n", spi_nor_info->quad_set.bit_shift); ++ printk("quad_set->mask=0x%x\n", spi_nor_info->quad_set.mask); ++ printk("quad_set->val=0x%x\n", spi_nor_info->quad_set.val); ++ printk("quad_set->len=0x%x\n", spi_nor_info->quad_set.len); ++ printk("quad_set->dummy=0x%x\n", spi_nor_info->quad_set.dummy); ++ ++ printk("quad_get->cmd=0x%x\n", spi_nor_info->quad_get.cmd); ++ printk("quad_get->bit_shift=0x%x\n", spi_nor_info->quad_get.bit_shift); ++ printk("quad_get->mask=0x%x\n", spi_nor_info->quad_get.mask); ++ printk("quad_get->val=0x%x\n", spi_nor_info->quad_get.val); ++ printk("quad_get->len=0x%x\n", spi_nor_info->quad_get.len); ++ printk("quad_get->dummy=0x%x\n", spi_nor_info->quad_get.dummy); ++ ++ printk("busy->cmd=0x%x\n", spi_nor_info->busy.cmd); ++ printk("busy->bit_shift=0x%x\n", spi_nor_info->busy.bit_shift); ++ printk("busy->mask=0x%x\n", spi_nor_info->busy.mask); ++ printk("busy->val=0x%x\n", spi_nor_info->busy.val); ++ printk("busy->len=0x%x\n", spi_nor_info->busy.len); ++ printk("busy->dummy=0x%x\n", spi_nor_info->busy.dummy); ++ ++ printk("quad_ops_mode=%d\n", spi_nor_info->quad_ops_mode); ++ printk("addr_ops_mode=%d\n", spi_nor_info->addr_ops_mode); ++ ++ printk("tCHSH=%d\n", spi_nor_info->tCHSH); ++ printk("tSLCH=%d\n", spi_nor_info->tSLCH); ++ printk("tSHSL_RD=%d\n", spi_nor_info->tSHSL_RD); ++ printk("tSHSL_WR=%d\n", spi_nor_info->tSHSL_WR); ++ ++ printk("chip_size=%d\n", spi_nor_info->chip_size); ++ printk("page_size=%d\n", spi_nor_info->page_size); ++ printk("erase_size=%d\n", spi_nor_info->erase_size); ++ ++ printk("chip_erase_cmd=0x%x\n", spi_nor_info->chip_erase_cmd); ++} ++#endif ++ ++static struct burner_params *burner_params = NULL; ++static int ingenic_spi_norflash_get_params(struct sfc_flash *flash, struct ingenic_sfc_info *pdata) ++{ ++ int32_t ret, err = 0; ++ struct spinor_flashinfo *nor_info = flash->flash_info; ++ struct ingenic_sfc_info *ingenic_sfc_info = pdata; ++ ++ burner_params = kzalloc(sizeof(struct burner_params), GFP_KERNEL); ++ if (!burner_params) { ++ dev_err(flash->dev, "Failed to alloc mem for params\n"); ++ err = -ENOMEM; ++ goto err_params; ++ } ++ ++ ret = ingenic_spi_norflash_read_params(flash, SPIFLASH_PARAMER_OFFSET, sizeof(struct burner_params), (uint8_t *)burner_params); ++ if (ret) { ++ dev_err(flash->dev, "Failed to read params (burned by Burner)\n"); ++ err = -EINVAL; ++ goto err_read_params; ++ } ++ dev_info(flash->dev, "magic is 0x%x version is 0x%x\n", burner_params->magic, burner_params->version); ++ nor_info->nor_flash_info = NULL; ++ if (burner_params->magic == NOR_MAGIC) { ++ if (burner_params->version == NOR_VERSION) { ++ nor_info->nor_flash_info = &burner_params->spi_nor_info; ++ nor_info->norflash_partitions = &burner_params->norflash_partitions; ++ nor_info->nor_pri_data = &burner_params->nor_pri_data; ++ } ++ } ++ ++ if (ingenic_sfc_info && ingenic_sfc_info->use_board_info) { ++ if (ingenic_sfc_info->flash_param) ++ nor_info->nor_flash_info = ingenic_sfc_info->flash_param; ++ if (ingenic_sfc_info->flash_partition) { ++ nor_info->norflash_partitions->num_partition_info = ingenic_sfc_info->num_partition; ++ memcpy(nor_info->norflash_partitions->nor_partition, ingenic_sfc_info->flash_partition, sizeof(struct nor_partition) * ingenic_sfc_info->num_partition); ++ } ++ if (ingenic_sfc_info->other_args) { ++ if (((struct nor_private_data *)(ingenic_sfc_info->other_args))->fs_erase_size != nor_info->nor_pri_data->fs_erase_size) ++ nor_info->nor_pri_data->fs_erase_size = ((struct nor_private_data *)(ingenic_sfc_info->other_args))->fs_erase_size; ++// if (((struct nor_private_data *)(ingenic_sfc_info->other_args))->uk_quad != nor_info->nor_pri_data->uk_quad) ++ nor_info->nor_pri_data->uk_quad = ((struct nor_private_data *)(ingenic_sfc_info->other_args))->uk_quad; ++ } ++ } ++ ++ if ((!nor_info->nor_flash_info) || (!nor_info->norflash_partitions)) { ++ printk("WARNING : cannot get nor flash params or partitions !!!\n"); ++ err = -EINVAL; ++ goto err_read_params; ++ } ++ ++#ifdef DEBUG_CLONER_PARAMS ++ dump_cloner_params(burner_params); ++#endif ++ return 0; ++err_read_params: ++ kfree(burner_params); ++err_params: ++ return err; ++} ++static ssize_t sfc_nor_partition_offset_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ return sprintf(buf,"0x%x\n", SPIFLASH_PARAMER_OFFSET + sizeof(int) * 2 + sizeof(struct spi_nor_info)); ++} ++ ++static DEVICE_ATTR(sfc_nor_partition_offset, S_IRUGO | S_IWUSR, ++ sfc_nor_partition_offset_show, ++ NULL); ++ ++static ssize_t sfc_nor_params_offset_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ return sprintf(buf,"0x%x\n",SPIFLASH_PARAMER_OFFSET); ++} ++ ++static DEVICE_ATTR(sfc_nor_params_offset, S_IRUGO | S_IWUSR, ++ sfc_nor_params_offset_show, ++ NULL); ++ ++/*add your attr in here*/ ++static struct attribute *sfc_norflash_info_attributes[] = { ++ &dev_attr_sfc_nor_partition_offset.attr, ++ &dev_attr_sfc_nor_params_offset.attr, ++ NULL ++}; ++ ++static const struct attribute_group sfc_norflash_info_attr_group = { ++ .attrs = sfc_norflash_info_attributes ++}; ++ ++ ++static int __init ingenic_sfc_probe(struct platform_device *pdev) ++{ ++ struct sfc_flash *flash; ++ struct mtd_partition *ingenic_mtd_partition; ++ const char *ingenic_probe_types[] = {"cmdlinepart",NULL}; ++ int num_partition_info = 0; ++ int err = 0,ret = 0; ++ struct spinor_flashinfo *nor_info; ++ struct ingenic_sfc_info *pdata_params; ++ int i; ++ int tchsh; ++ int tslch; ++ int tshsl_rd; ++ int tshsl_wr; ++ ++ L2CACHE_ALIGN_SIZE = 128; ++ ++ flash = kzalloc(sizeof(struct sfc_flash), GFP_KERNEL); ++ if (flash == NULL) { ++ dev_err(&pdev->dev, "Failed to alloc mem for flash\n"); ++ return -ENOMEM; ++ } ++ ++ nor_info = kzalloc(sizeof(*nor_info), GFP_KERNEL); ++ if(!nor_info) { ++ dev_err(&pdev->dev, "alloc nor_info failed!\n"); ++ kfree(flash); ++ return -ENOMEM; ++ } ++ flash->flash_info = nor_info; ++ ++ flash->dev = &pdev->dev; ++ ++ flash->sfc = sfc_res_init(pdev); ++ if(IS_ERR_OR_NULL(flash->sfc)) { ++ ret = -ENOMEM; ++ goto err_sfc_res_init; ++ } ++ ++ platform_set_drvdata(pdev, flash); ++ mutex_init(&flash->lock); ++ ++ set_flash_timing(flash->sfc, DEF_TCHSH, DEF_TSLCH, DEF_TSHSL_R, DEF_TSHSL_W); ++ ret = sfc_nor_reset(flash); ++ if(ret) { ++ dev_warn(flash->dev, "Failed to reset nor flash, Try to go on\n"); ++ } ++ ++ pdata_params = pdev->dev.platform_data; ++ ret = ingenic_spi_norflash_get_params(flash, pdata_params); ++ if (ret) { ++ ret = -ENODEV; ++ dev_err(flash->dev, "Failed to match correct nor flash device!\n"); ++ goto err_match_device; ++ } ++ ++ num_partition_info = nor_info->norflash_partitions->num_partition_info; ++ ingenic_mtd_partition = (struct mtd_partition*)kzalloc(sizeof(struct mtd_partition) * num_partition_info, GFP_KERNEL); ++ if (!ingenic_mtd_partition) { ++ ret = -ENOMEM; ++ dev_err(flash->dev, "Failed to alloc mem for ingenic_mtd_partition\n"); ++ goto err_alloc_partition; ++ } ++ ++ for (i = 0; i < num_partition_info; i++) { ++ ingenic_mtd_partition[i].ecclayout = NULL; ++ ingenic_mtd_partition[i].name = nor_info->norflash_partitions->nor_partition[i].name; ++ ingenic_mtd_partition[i].offset = nor_info->norflash_partitions->nor_partition[i].offset; ++ ++ if (nor_info->norflash_partitions->nor_partition[i].size == -1) { ++ ingenic_mtd_partition[i].size = MTDPART_SIZ_FULL; ++ } else { ++ ingenic_mtd_partition[i].size = nor_info->norflash_partitions->nor_partition[i].size; ++ } ++ ++ if (nor_info->norflash_partitions->nor_partition[i].mask_flags & NORFLASH_PART_RO) { //have problem!!! ++ ingenic_mtd_partition[i].mask_flags = MTD_CAP_RAM; ++ } else { ++ ingenic_mtd_partition[i].mask_flags = MTD_CAP_ROM; ++ } ++ ++ } ++ ++ flash->mtd.name = "sfc_mtd"; ++ flash->mtd.owner = THIS_MODULE; ++ flash->mtd.type = MTD_NORFLASH; ++ flash->mtd.flags = MTD_CAP_NORFLASH; ++ flash->mtd.erasesize = nor_info->nor_pri_data->fs_erase_size; ++ flash->mtd.writesize = nor_info->nor_flash_info->page_size; ++ flash->mtd.size = nor_info->nor_flash_info->chip_size; ++ flash->mtd._erase = ingenic_spi_norflash_erase; ++ flash->mtd._read = ingenic_spi_norflash_read; ++ flash->mtd._write = ingenic_spi_norflash_write; ++ ++ tchsh = nor_info->nor_flash_info->tCHSH; ++ tslch = nor_info->nor_flash_info->tSLCH; ++ tshsl_rd = nor_info->nor_flash_info->tSHSL_RD; ++ tshsl_wr = nor_info->nor_flash_info->tSHSL_WR; ++ set_flash_timing(flash->sfc, tchsh, tslch, tshsl_rd, tshsl_wr); ++ ++ sfc_nor_get_special_ops(flash); ++ ++ if (nor_info->nor_pri_data->uk_quad) { ++ if (nor_info->nor_flash_ops->set_quad_mode) { ++ ret = nor_info->nor_flash_ops->set_quad_mode(flash); ++ if (ret < 0) { ++ nor_info->quad_succeed = 0; ++ dev_info(&pdev->dev, "set quad mode error !\n"); ++ } else { ++ nor_info->quad_succeed = 1; ++ dev_info(&pdev->dev, "nor flash quad mode is set, now use quad mode!\n"); ++ } ++ } ++ } ++ ++ /* if nor flash size is greater than 16M, use 4byte mode */ ++ if(flash->mtd.size > NOR_SIZE_16M) { ++ if (nor_info->nor_flash_ops->set_4byte_mode) { ++ nor_info->nor_flash_ops->set_4byte_mode(flash); ++ } ++ } ++ ++ get_current_operate_cmd(flash); ++ ++ ret = mtd_device_parse_register(&flash->mtd, ingenic_probe_types, NULL, ingenic_mtd_partition, num_partition_info); ++ if (ret) { ++ ret = -ENODEV; ++ dev_err(flash->dev, "Failed to parse register!\n"); ++ goto err_parse_register; ++ } ++ ++ ret = sysfs_create_group(&pdev->dev.kobj, &sfc_norflash_info_attr_group); ++ if (err) { ++ dev_err(&pdev->dev, "failed to register sysfs\n"); ++ ret = -EIO; ++ goto err_create_group; ++ } ++ ++ dev_info(&pdev->dev,"SPI NOR MTD LOAD OK\n"); ++ return 0; ++ ++err_create_group: ++ mtd_device_unregister(&flash->mtd); ++err_parse_register: ++ kfree(ingenic_mtd_partition); ++err_alloc_partition: ++ kfree(burner_params); ++err_match_device: ++err_sfc_res_init: ++ kfree(nor_info); ++ kfree(flash); ++ return ret; ++ ++} ++ ++static int __exit ingenic_sfc_remove(struct platform_device *pdev) ++{ ++ struct sfc_flash *flash = platform_get_drvdata(pdev); ++ struct sfc *sfc = flash->sfc; ++ ++ clk_disable_unprepare(sfc->clk_gate); ++ clk_put(sfc->clk_gate); ++ ++ clk_disable_unprepare(sfc->clk); ++ clk_put(sfc->clk); ++ ++ free_irq(sfc->irq, flash); ++ iounmap(sfc->iomem); ++ release_mem_region(sfc->ioarea->start, resource_size(sfc->ioarea)); ++ ++ platform_set_drvdata(pdev, NULL); ++ sysfs_remove_group(&pdev->dev.kobj, &sfc_norflash_info_attr_group); ++ return 0; ++} ++ ++static int ingenic_sfc_suspend(struct platform_device *pdev, pm_message_t msg) ++{ ++ struct sfc_flash *flash = platform_get_drvdata(pdev); ++ struct sfc *sfc = flash->sfc; ++#ifdef CONFIG_ENABLE_DEEP_POWER_DOWN ++ { ++ struct sfc_transfer transfer; ++ int ret; ++ ++ memset(&transfer, 0, sizeof(transfer)); ++ sfc_list_init(&transfer); ++ ++ transfer.cmd_info.cmd = CMD_DP; ++ transfer.cmd_info.dataen = DISABLE; ++ ret = sfc_sync(sfc, &transfer); ++ if(ret) { ++ dev_err(flash->dev,"sfc_sync error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ } ++ udelay(10); ++ } ++#endif ++ ++ disable_irq(sfc->irq); ++ clk_disable_unprepare(sfc->clk_gate); ++ clk_disable_unprepare(sfc->clk); ++ ++ return 0; ++} ++ ++static int ingenic_sfc_resume(struct platform_device *pdev) ++{ ++ struct sfc_flash *flash = platform_get_drvdata(pdev); ++ struct sfc *sfc = flash->sfc; ++ ++ clk_prepare_enable(sfc->clk); ++ clk_prepare_enable(sfc->clk_gate); ++ ++ enable_irq(sfc->irq); ++#ifdef CONFIG_ENABLE_DEEP_POWER_DOWN ++ { ++ struct sfc_transfer transfer; ++ int ret; ++ ++ memset(&transfer, 0, sizeof(transfer)); ++ sfc_list_init(&transfer); ++ ++ transfer.cmd_info.cmd = CMD_RDP; ++ transfer.cmd_info.dataen = DISABLE; ++ ret = sfc_sync(sfc, &transfer); ++ if(ret) { ++ dev_err(flash->dev,"sfc_sync error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ } ++ udelay(60); ++ } ++#endif ++ return 0; ++} ++ ++void ingenic_sfc_shutdown(struct platform_device *pdev) ++{ ++ struct sfc_flash *flash = platform_get_drvdata(pdev); ++ struct sfc *sfc = flash->sfc; ++ ++ disable_irq(sfc->irq); ++ clk_disable_unprepare(sfc->clk_gate); ++ clk_disable_unprepare(sfc->clk); ++ return ; ++} ++ ++static const struct of_device_id ingenicsfc_match[] = { ++ { .compatible = "ingenic,sfc", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ingenicsfc_match); ++ ++static struct platform_driver ingenic_sfcdrv = { ++ .driver = { ++ .name = "ingenic-sfc", ++ .owner = THIS_MODULE, ++ .of_match_table = ingenicsfc_match, ++ }, ++ .remove = __exit_p(ingenic_sfc_remove), ++ .suspend = ingenic_sfc_suspend, ++ .resume = ingenic_sfc_resume, ++// .shutdown = ingenic_sfc_shutdown, ++}; ++module_platform_driver_probe(ingenic_sfcdrv, ingenic_sfc_probe); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("INGENIC SFC Driver"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_ingenic_sfc_ops.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_ingenic_sfc_ops.c.patch new file mode 100644 index 00000000..5736e09d --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_ingenic_sfc_ops.c.patch @@ -0,0 +1,255 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v1/ingenic_sfc_ops.c b/drivers/mtd/devices/ingenic_sfc_v1/ingenic_sfc_ops.c +--- a/drivers/mtd/devices/ingenic_sfc_v1/ingenic_sfc_ops.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v1/ingenic_sfc_ops.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,251 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "spinor.h" ++#include "ingenic_sfc_common.h" ++ ++int get_status(struct sfc_flash *flash, int command, int len) ++{ ++ struct sfc_transfer transfer; ++ int ret; ++ static unsigned char buf[32]; ++ int i = 0; ++ int val = 0; ++ ++ memset(buf, 0, sizeof(buf)); ++ memset(&transfer, 0, sizeof(transfer)); ++ sfc_list_init(&transfer); ++ ++ transfer.sfc_mode = TM_STD_SPI; ++ transfer.cmd_info.cmd = command; ++ ++ transfer.addr_len = 0; ++ transfer.addr = 0; ++ ++ transfer.cmd_info.dataen = ENABLE; ++ transfer.len = len; ++ transfer.data = (uint8_t *)buf; ++ transfer.cur_len = 0; ++ transfer.direction = GLB_TRAN_DIR_READ; ++ ++ transfer.data_dummy_bits = 0; ++ transfer.ops_mode = CPU_OPS; ++ ++ ret = sfc_sync(flash->sfc, &transfer); ++ if(ret) { ++ dev_err(flash->dev,"sfc_sync error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ ret=-EIO; ++ } ++ ++ for(i = 0; i < len; i++) { ++ val |= buf[i] << (i * 8); ++ } ++ ++ return val; ++ ++} ++ ++/* do nothing to set quad mode, use cmd directly */ ++static int set_quad_mode_cmd(struct sfc_flash *flash) ++{ ++ return 0; ++} ++ ++/* write nor flash status register QE bit to set quad mode */ ++static int set_quad_mode_reg(struct sfc_flash *flash) ++{ ++ unsigned int data; ++ int ret; ++ struct sfc_transfer transfer[2]; ++ struct spinor_flashinfo *nor_info = flash->flash_info; ++ struct spi_nor_info *spi_nor_info = nor_info->nor_flash_info; ++ struct spi_nor_cmd_info *wr_en; ++ struct spi_nor_st_info *quad_set; ++ struct spi_nor_st_info *quad_get; ++ struct spi_nor_st_info *busy; ++ uint32_t sta_reg = 0; ++ ++ wr_en = &spi_nor_info->wr_en; ++ busy = &spi_nor_info->busy; ++ quad_set = &spi_nor_info->quad_set; ++ quad_get = &spi_nor_info->quad_get; ++ data = (quad_set->val & quad_set->mask) << quad_set->bit_shift; ++ ++ memset(transfer, 0, sizeof(transfer)); ++ sfc_list_init(transfer); ++ ++ /* write enable */ ++ transfer[0].sfc_mode = wr_en->transfer_mode; ++ transfer[0].cmd_info.cmd = wr_en->cmd; ++ ++ transfer[0].addr_len = wr_en->addr_nbyte; ++ ++ transfer[0].cmd_info.dataen = DISABLE; ++ ++ transfer[0].data_dummy_bits = wr_en->dummy_byte; ++ ++ /* write ops */ ++ transfer[1].sfc_mode = TM_STD_SPI; ++ transfer[1].cmd_info.cmd = quad_set->cmd; ++ ++ transfer[1].cmd_info.dataen = ENABLE; ++ transfer[1].len = quad_set->len; ++ transfer[1].data = (uint8_t *)&data; ++ transfer[1].direction = GLB_TRAN_DIR_WRITE; ++ ++ transfer[1].data_dummy_bits = quad_set->dummy; ++ transfer[1].ops_mode = CPU_OPS; ++ sfc_list_add_tail(&transfer[1], transfer); ++ ++ ret = sfc_sync(flash->sfc, transfer); ++ if(ret) { ++ dev_err(flash->dev,"sfc_sync error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ ret=-EIO; ++ } ++ ++ do { ++ sta_reg = get_status(flash, busy->cmd, busy->len); ++ sta_reg = (sta_reg >> busy->bit_shift) & busy->mask; ++ } while (sta_reg != busy->val); ++ ++ do { ++ sta_reg = get_status(flash, quad_get->cmd, quad_get->len); ++ sta_reg = (sta_reg >> quad_get->bit_shift) & quad_get->mask; ++ } while (sta_reg != quad_get->val); ++ ++ return ret; ++} ++ ++static int write_enable(struct sfc_flash *flash) ++{ ++ struct spinor_flashinfo *nor_info = flash->flash_info; ++ struct spi_nor_info *spi_nor_info = nor_info->nor_flash_info; ++ struct spi_nor_cmd_info *wr_en = &spi_nor_info->wr_en; ++ struct sfc_transfer transfer; ++ int ret; ++ ++ memset(&transfer, 0, sizeof(transfer)); ++ sfc_list_init(&transfer); ++ ++ transfer.sfc_mode = wr_en->transfer_mode; ++ transfer.cmd_info.cmd = wr_en->cmd; ++ ++ transfer.addr_len = wr_en->addr_nbyte; ++ ++ transfer.cmd_info.dataen = DISABLE; ++ ++ transfer.data_dummy_bits = wr_en->dummy_byte; ++ ++ ret = sfc_sync(flash->sfc, &transfer); ++ if(ret) { ++ dev_err(flash->dev,"sfc_sync error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ ret=-EIO; ++ } ++ return ret; ++} ++ ++static int enter_4byte(struct sfc_flash *flash) ++{ ++ struct spinor_flashinfo *nor_info = flash->flash_info; ++ struct spi_nor_info *spi_nor_info = nor_info->nor_flash_info; ++ struct spi_nor_cmd_info *en4byte = &spi_nor_info->en4byte; ++ struct sfc_transfer transfer; ++ int ret; ++ ++ memset(&transfer, 0, sizeof(transfer)); ++ sfc_list_init(&transfer); ++ ++ transfer.sfc_mode = en4byte->transfer_mode; ++ transfer.cmd_info.cmd = en4byte->cmd; ++ ++ transfer.addr_len = en4byte->addr_nbyte; ++ ++ transfer.cmd_info.dataen = DISABLE; ++ ++ transfer.data_dummy_bits = en4byte->dummy_byte; ++ ++ ret = sfc_sync(flash->sfc, &transfer); ++ if(ret) { ++ dev_err(flash->dev,"sfc_sync error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ ret=-EIO; ++ } ++ return ret; ++} ++ ++/* send 4byte command to enter 4byte mode */ ++static int set_4byte_mode_normal(struct sfc_flash *flash) ++{ ++ int ret; ++ ret = enter_4byte(flash); ++ if (ret) { ++ dev_err(flash->dev, "enter 4byte mode failed\n"); ++ } ++ return ret; ++} ++ ++/** ++ * 1.send write enable command ++ * 2.send 4byte command to enter 4byte mode ++ **/ ++static int set_4byte_mode_wren(struct sfc_flash *flash) ++{ ++ int ret; ++ ret = write_enable(flash); ++ if (ret) { ++ dev_err(flash->dev, "enter 4byte mode failed\n"); ++ return ret; ++ } ++ ++ ret = enter_4byte(flash); ++ if (ret) { ++ dev_err(flash->dev, "enter 4byte mode failed\n"); ++ } ++ return ret; ++} ++ ++ ++static struct spi_nor_flash_ops nor_flash_ops; ++ ++static int noop(struct sfc_flash *flash) ++{ ++ return 0; ++} ++ ++int sfc_nor_get_special_ops(struct sfc_flash *flash) ++{ ++ struct spinor_flashinfo *nor_info = flash->flash_info; ++ struct spi_nor_info *spi_nor_info = nor_info->nor_flash_info; ++ ++ switch (spi_nor_info->quad_ops_mode) { ++ case 0: ++ nor_flash_ops.set_quad_mode = set_quad_mode_cmd; ++ break; ++ case 1: ++ nor_flash_ops.set_quad_mode = set_quad_mode_reg; ++ break; ++ default: ++ nor_flash_ops.set_quad_mode = noop; ++ break; ++ } ++ ++ switch (spi_nor_info->addr_ops_mode) { ++ case 0: ++ nor_flash_ops.set_4byte_mode = set_4byte_mode_normal; ++ break; ++ case 1: ++ nor_flash_ops.set_4byte_mode = set_4byte_mode_wren; ++ break; ++ default: ++ nor_flash_ops.set_4byte_mode = noop; ++ break; ++ } ++ ++ nor_info->nor_flash_ops = &nor_flash_ops; ++ ++ return 0; ++} ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_nand_device_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_nand_device_Makefile.patch new file mode 100644 index 00000000..27bdbc32 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_nand_device_Makefile.patch @@ -0,0 +1,6 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v1/nand_device/Makefile b/drivers/mtd/devices/ingenic_sfc_v1/nand_device/Makefile +--- a/drivers/mtd/devices/ingenic_sfc_v1/nand_device/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v1/nand_device/Makefile 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,2 @@ ++obj-y += ato_nand.o gd_nand.o mxic_nand.o winbond_nand.o xtx_nand.o ++obj-y += nand_common.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_nand_device_ato_nand.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_nand_device_ato_nand.c.patch new file mode 100644 index 00000000..ae8cdcf1 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_nand_device_ato_nand.c.patch @@ -0,0 +1,124 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v1/nand_device/ato_nand.c b/drivers/mtd/devices/ingenic_sfc_v1/nand_device/ato_nand.c +--- a/drivers/mtd/devices/ingenic_sfc_v1/nand_device/ato_nand.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v1/nand_device/ato_nand.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,120 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../spinand.h" ++#include "../ingenic_sfc_common.h" ++#include "nand_common.h" ++ ++#define ATO_DEVICES_NUM 1 ++#define TSETUP 5 ++#define THOLD 5 ++#define TSHSL_R 30 ++#define TSHSL_W 30 ++ ++#define TRD 25 ++#define TPP 500 ++#define TBE 3 ++ ++static struct ingenic_sfcnand_base_param ato25d1ga_param = { ++ ++ .pagesize = 2 * 1024, ++ .oobsize = 64, ++ .blocksize = 2 * 1024 * 64, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .ecc_max = 0,//0x3, ++ .need_quad = 1, ++ ++}; ++ ++static struct device_id_struct device_id[ATO_DEVICES_NUM] = { ++ DEVICE_ID_STRUCT(0x12, "ATO25D1GA", &ato25d1ga_param), ++}; ++ ++ ++#if 0 ++static int32_t ato_get_read_feature(struct sfc_flash *flash, uint8_t device_id) { ++ switch(device_id) { ++ case 0x12: ++ return 0; ++ default: ++ dev_err(flash->dev, "device_id err, it maybe don`t support this device, check your device id: device_id = 0x%02x\n", device_id); ++ return -EIO;//notice!!! ++ } ++} ++#else ++static int32_t ato_get_read_feature(struct flash_operation_message *op_info) { ++ ++ struct sfc_flash *flash = op_info->flash; ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ struct sfc_transfer transfer; ++ uint8_t device_id = nand_info->id_device; ++ uint32_t ecc_status; ++ ++retry: ++ ecc_status = 0; ++ memset(&transfer, 0, sizeof(transfer)); ++ sfc_list_init(&transfer); ++ ++ transfer.cmd_info.cmd = SPINAND_CMD_GET_FEATURE; ++ transfer.sfc_mode = TM_STD_SPI; ++ ++ transfer.addr = SPINAND_ADDR_STATUS; ++ transfer.addr_len = 1; ++ ++ transfer.cmd_info.dataen = ENABLE; ++ transfer.data = (uint8_t *)&ecc_status; ++ transfer.len = 1; ++ transfer.direction = GLB_TRAN_DIR_READ; ++ ++ transfer.data_dummy_bits = 0; ++ transfer.ops_mode = CPU_OPS; ++ ++ /*wait poll time*/ ++ if(sfc_sync_poll(flash->sfc, &transfer)) { ++ dev_err(flash->dev,"sfc_sync error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ if(ecc_status & SPINAND_IS_BUSY) ++ goto retry; ++ ++ switch(device_id) { ++ case 0x12: ++ return 0; ++ default: ++ pr_err("device_id err,it maybe don`t support this device, please check your device id: device_id = 0x%02x\n", device_id); ++ return -EIO; //notice!!! ++ } ++} ++ ++#endif ++ ++static int __init ato_nand_init(void) { ++ struct ingenic_sfcnand_device *ato_nand; ++ ato_nand = kzalloc(sizeof(*ato_nand), GFP_KERNEL); ++ if(!ato_nand) { ++ pr_err("alloc ato_nand struct fail\n"); ++ return -ENOMEM; ++ } ++ ++ ato_nand->id_manufactory = 0x9B; ++ ato_nand->id_device_list = device_id; ++ ato_nand->id_device_count = ATO_DEVICES_NUM; ++ ++ ato_nand->ops.nand_read_ops.get_feature = ato_get_read_feature; ++ return ingenic_sfcnand_register(ato_nand); ++} ++fs_initcall(ato_nand_init); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_nand_device_gd_nand.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_nand_device_gd_nand.c.patch new file mode 100644 index 00000000..84ed8a97 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_nand_device_gd_nand.c.patch @@ -0,0 +1,352 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v1/nand_device/gd_nand.c b/drivers/mtd/devices/ingenic_sfc_v1/nand_device/gd_nand.c +--- a/drivers/mtd/devices/ingenic_sfc_v1/nand_device/gd_nand.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v1/nand_device/gd_nand.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,348 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../spinand.h" ++#include "../ingenic_sfc_common.h" ++#include "nand_common.h" ++ ++#define GD_DEVICES_NUM 6 ++#define TSETUP 5 ++#define THOLD 5 ++#define TSHSL_R 20 ++#define TSHSL_W 20 ++ ++#define TRD 80 ++#define TRD_4G 120 ++#define TPP 700 ++#define TBE 5 ++ ++static struct ingenic_sfcnand_base_param gd_param[GD_DEVICES_NUM] = { ++ ++ [0] = { ++ /*GD5F1GQ4UB*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 128, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .ecc_max = 0x8, ++ .need_quad = 1, ++ }, ++ [1] = { ++ /*GD5F2GQ4UB*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 128, ++ .flashsize = 2 * 1024 * 64 * 2048, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .ecc_max = 0x8, ++ .need_quad = 1, ++ }, ++ [2] = { ++ /*GD5F4GQ4UB*/ ++ .pagesize = 4 * 1024, ++ .blocksize = 4 * 1024 * 64, ++ .oobsize = 256, ++ .flashsize = 4 * 1024 * 64 * 2048, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD_4G, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .ecc_max = 0x8, ++ .need_quad = 1, ++ }, ++ [3] = { ++ /*GD5F1GQ4UC*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 128, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .ecc_max = 0x8, ++ .need_quad = 1, ++ ++ }, ++ [4] = { ++ /*GD5F2GQ4UC*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 128, ++ .flashsize = 2 * 1024 * 64 * 2048, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .ecc_max = 0x8, ++ .need_quad = 1, ++ }, ++ [5] = { ++ /*GD5F4GQ4UC*/ ++ .pagesize = 4 * 1024, ++ .blocksize = 4 * 1024 * 64, ++ .oobsize = 256, ++ .flashsize = 4 * 1024 * 64 * 2048, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD_4G, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .ecc_max = 0x3, ++ .need_quad = 1, ++ }, ++ ++}; ++ ++static struct device_id_struct device_id[GD_DEVICES_NUM] = { ++ DEVICE_ID_STRUCT(0xD1, "GD5F1GQ4UB",&gd_param[0]), ++ DEVICE_ID_STRUCT(0xD2, "GD5F2GQ4UB",&gd_param[1]), ++ DEVICE_ID_STRUCT(0xD4, "GD5F4GQ4UB",&gd_param[2]), ++ DEVICE_ID_STRUCT(0xB1, "GD5F1GQ4UC",&gd_param[3]), ++ DEVICE_ID_STRUCT(0xB2, "GD5F2GQ4UC",&gd_param[4]), ++ DEVICE_ID_STRUCT(0xB4, "GD5F4GQ4UC",&gd_param[5]), ++}; ++ ++static void gd_single_read(struct sfc_transfer *transfer, struct flash_operation_message *op_info) { ++ ++ struct sfc_flash *flash = op_info->flash; ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ uint8_t device_id = nand_info->id_device; ++ uint8_t addr_len = 0; ++ switch(device_id) { ++ case 0xB1 ... 0xB4: ++ addr_len = 3; ++ break; ++ case 0xD1 ... 0xD4: ++ addr_len = 2; ++ break; ++ default: ++ dev_err(flash->dev, "device_id err, please check your device id: device_id = 0x%02x\n", device_id); ++ addr_len = 2; ++ break; ++ } ++ ++ transfer->cmd_info.cmd = SPINAND_CMD_FRCH; ++ transfer->sfc_mode = TM_STD_SPI; ++ ++ transfer->addr = op_info->columnaddr; ++ transfer->addr_len = addr_len; ++ ++ transfer->cmd_info.dataen = ENABLE; ++ transfer->data = op_info->buffer; ++ transfer->len = op_info->len; ++ transfer->direction = GLB_TRAN_DIR_READ; ++ ++ transfer->data_dummy_bits = 8; ++ transfer->ops_mode = DMA_OPS; ++ ++ return; ++} ++ ++static void gd_quad_read(struct sfc_transfer *transfer, struct flash_operation_message *op_info) { ++ ++ struct sfc_flash *flash = op_info->flash; ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ uint8_t device_id = nand_info->id_device; ++ uint8_t addr_len = 0; ++ switch(device_id) { ++ case 0xB1 ... 0xB4: ++ addr_len = 3; ++ break; ++ case 0xD1 ... 0xD4: ++ addr_len = 2; ++ break; ++ default: ++ dev_err(flash->dev, "device_id err, please check your device id: device_id = 0x%02x\n", device_id); ++ addr_len = 2; ++ break; ++ } ++ transfer->cmd_info.cmd = SPINAND_CMD_RDCH_X4; ++ transfer->sfc_mode = TM_QI_QO_SPI; ++ ++ transfer->addr = op_info->columnaddr; ++ transfer->addr_len = addr_len; ++ ++ transfer->cmd_info.dataen = ENABLE; ++ transfer->data = op_info->buffer; ++ transfer->len = op_info->len; ++ transfer->direction = GLB_TRAN_DIR_READ; ++ ++ transfer->data_dummy_bits = 8; ++ transfer->ops_mode = DMA_OPS; ++ ++ return; ++} ++ ++static int32_t gd_get_f0_register_value(struct sfc_flash *flash) { ++ ++ struct sfc_transfer transfer; ++ uint32_t buf = 0; ++ ++ memset(&transfer, 0, sizeof(transfer)); ++ sfc_list_init(&transfer); ++ ++ transfer.cmd_info.cmd = SPINAND_CMD_GET_FEATURE; ++ transfer.sfc_mode = TM_STD_SPI; ++ ++ transfer.addr = 0xf0; ++ transfer.addr_len = 1; ++ ++ transfer.cmd_info.dataen = ENABLE; ++ transfer.len = 1; ++ transfer.data = (uint8_t *)&buf; ++ transfer.direction = GLB_TRAN_DIR_READ; ++ ++ transfer.data_dummy_bits = 0; ++ transfer.ops_mode = CPU_OPS; ++ ++ if(sfc_sync_poll(flash->sfc, &transfer)) { ++ dev_err(flash->dev,"sfc_sync error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ return buf; ++} ++ ++static int32_t gd_get_read_feature(struct flash_operation_message *op_info) { ++ ++ struct sfc_flash *flash = op_info->flash; ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ struct sfc_transfer transfer; ++ uint8_t device_id = nand_info->id_device; ++ uint8_t ecc_status = 0; ++ int32_t ret = 0; ++ ++retry: ++ ecc_status = 0; ++ memset(&transfer, 0, sizeof(transfer)); ++ sfc_list_init(&transfer); ++ ++ transfer.cmd_info.cmd = SPINAND_CMD_GET_FEATURE; ++ transfer.sfc_mode = TM_STD_SPI; ++ ++ transfer.addr = SPINAND_ADDR_STATUS; ++ transfer.addr_len = 1; ++ ++ transfer.cmd_info.dataen = ENABLE; ++ transfer.data = &ecc_status; ++ transfer.len = 1; ++ transfer.direction = GLB_TRAN_DIR_READ; ++ ++ transfer.data_dummy_bits = 0; ++ transfer.ops_mode = CPU_OPS; ++ ++ if(sfc_sync_poll(flash->sfc, &transfer)) { ++ dev_err(flash->dev,"sfc_sync error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ if(ecc_status & SPINAND_IS_BUSY) ++ goto retry; ++ ++ switch(device_id) { ++ case 0xB1 ... 0xB4: ++ switch((ecc_status >> 4) & 0x7) { ++ case 0x7: ++ ret = -EBADMSG; ++ break; ++ case 0x6: ++ ret = 0x8; ++ break; ++ case 0x5: ++ ret = 0x7; ++ break; ++ default: ++ ret = 0; ++ break; ++ } ++ break; ++ case 0xD1 ... 0xD4: ++ switch((ecc_status >> 4) & 0x3) { ++ case 0x3: ++ ret = 0x8; ++ break; ++ case 0x2: ++ ret = -EBADMSG; ++ break; ++ case 0x1: ++ if((ret = gd_get_f0_register_value(flash)) < 0) ++ return ret; ++ if(((ret >> 4) & 0x3) == 0x3) ++ ret = 0x7; ++ default: ++ ret = 0; ++ break; ++ } ++ break; ++ default: ++ dev_err(flash->dev, "device_id err,it maybe don`t support this device, please check your device id: device_id = 0x%02x\n", device_id); ++ ret = -EIO; //notice!!! ++ } ++ ++ return ret; ++} ++ ++static int __init gd_nand_init(void) { ++ struct ingenic_sfcnand_device *gd_nand; ++ gd_nand = kzalloc(sizeof(*gd_nand), GFP_KERNEL); ++ if(!gd_nand) { ++ pr_err("alloc gd_nand struct fail\n"); ++ return -ENOMEM; ++ } ++ ++ gd_nand->id_manufactory = 0xC8; ++ gd_nand->id_device_list = device_id; ++ gd_nand->id_device_count = GD_DEVICES_NUM; ++ ++ gd_nand->ops.nand_read_ops.get_feature = gd_get_read_feature; ++ gd_nand->ops.nand_read_ops.single_read = gd_single_read; ++ gd_nand->ops.nand_read_ops.quad_read = gd_quad_read; ++ ++ return ingenic_sfcnand_register(gd_nand); ++} ++fs_initcall(gd_nand_init); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_nand_device_mxic_nand.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_nand_device_mxic_nand.c.patch new file mode 100644 index 00000000..c5cbed97 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_nand_device_mxic_nand.c.patch @@ -0,0 +1,389 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v1/nand_device/mxic_nand.c b/drivers/mtd/devices/ingenic_sfc_v1/nand_device/mxic_nand.c +--- a/drivers/mtd/devices/ingenic_sfc_v1/nand_device/mxic_nand.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v1/nand_device/mxic_nand.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,385 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../spinand.h" ++#include "../ingenic_sfc_common.h" ++#include "nand_common.h" ++ ++#define MXIC_DEVICES_NUM 3 ++#define MXIC_CMD_GET_ECC 0x7c ++#define THOLD 4 ++#define TSETUP 4 ++#define TSHSL_R 100 ++#define TSHSL_W 100 ++ ++#define TRD 70 ++#define TRD_14AC 25 ++#define TPP 600 ++#define TBE 4 ++ ++static struct ingenic_sfcnand_base_param mxic_param[MXIC_DEVICES_NUM] = { ++ [0] = { ++ /*MX35LF1GE4AB*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ ++ .tHOLD = THOLD, ++ .tSETUP = TSETUP, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .ecc_max = 0x4, ++ .need_quad = 1, ++ }, ++ [1] = { ++ /*MX35LF2GE4AB*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 2048, ++ ++ .tHOLD = THOLD, ++ .tSETUP = TSETUP, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .ecc_max = 0x4, ++ .need_quad = 1, ++ }, ++ [2] = { ++ /*MX35LF2G14AC*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 2048, ++ ++ .tHOLD = THOLD, ++ .tSETUP = TSETUP, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD_14AC, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .ecc_max = 0, ++ .need_quad = 1, ++ }, ++ ++}; ++ ++static struct device_id_struct device_id[MXIC_DEVICES_NUM] = { ++ DEVICE_ID_STRUCT(0x12, "MX35LF1GE4AB", &mxic_param[0]), ++ DEVICE_ID_STRUCT(0x22, "MX35LF2GE4AB", &mxic_param[1]), ++ DEVICE_ID_STRUCT(0x20, "MX35LF2G14AC", &mxic_param[2]), ++}; ++ ++static void mxic_pageread_to_cache(struct sfc_transfer *transfer, struct flash_operation_message *op_info) { ++ ++ transfer->cmd_info.cmd = SPINAND_CMD_PARD; ++ transfer->sfc_mode = TM_STD_SPI; ++ ++ transfer->addr = op_info->pageaddr; ++ transfer->addr_len = 3; ++ ++ transfer->cmd_info.dataen = DISABLE; ++ transfer->len = 0; ++ ++ transfer->data_dummy_bits = 0; ++ transfer->ops_mode = CPU_OPS; ++ return; ++} ++ ++static int32_t get_ecc_value(struct sfc_flash *flash) { ++ struct sfc_transfer transfer; ++ uint32_t buf = 0; ++ int8_t count = 5; ++ ++try_read_again: ++ memset(&transfer, 0, sizeof(transfer)); ++ sfc_list_init(&transfer); ++ transfer.cmd_info.cmd = MXIC_CMD_GET_ECC; ++ transfer.sfc_mode = TM_STD_SPI; ++ ++ transfer.addr = 0; ++ transfer.addr_len = 0; ++ ++ transfer.cmd_info.dataen = ENABLE; ++ transfer.len = 1; ++ transfer.data = (uint8_t *)&buf; ++ transfer.direction = GLB_TRAN_DIR_READ; ++ ++ transfer.data_dummy_bits = 8; ++ transfer.ops_mode = CPU_OPS; ++ ++ if(sfc_sync_poll(flash->sfc, &transfer) && count--) ++ goto try_read_again; ++ if(count < 0) ++ return -EIO; ++ return buf & 0xf; ++} ++ ++static int32_t mxic_get_read_feature(struct flash_operation_message *op_info) { ++ ++ struct sfc_flash *flash = op_info->flash; ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ struct sfc_transfer transfer; ++ uint8_t device_id = nand_info->id_device; ++ uint8_t ecc_status = 0; ++ int32_t ret = 0; ++ ++retry: ++ ecc_status = 0; ++ memset(&transfer, 0, sizeof(transfer)); ++ sfc_list_init(&transfer); ++ ++ transfer.cmd_info.cmd = SPINAND_CMD_GET_FEATURE; ++ transfer.sfc_mode = TM_STD_SPI; ++ ++ transfer.addr = SPINAND_ADDR_STATUS; ++ transfer.addr_len = 1; ++ ++ transfer.cmd_info.dataen = ENABLE; ++ transfer.data = &ecc_status; ++ transfer.len = 1; ++ transfer.direction = GLB_TRAN_DIR_READ; ++ ++ transfer.data_dummy_bits = 0; ++ transfer.ops_mode = CPU_OPS; ++ ++ if(sfc_sync_poll(flash->sfc, &transfer)) { ++ dev_err(flash->dev, "sfc_sync error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ if(ecc_status & SPINAND_IS_BUSY) ++ goto retry; ++ ++ switch(device_id) { ++ case 0x12: ++ case 0x22: ++ switch((ecc_status >> 0x4) & 0x3) { ++ case 0x0: ++ ret = 0; ++ break; ++ case 0x1: ++ if((ret = get_ecc_value(flash)) > 0x4) ++ ret = -EBADMSG; ++ break; ++ case 0x2: ++ ret = -EBADMSG; ++ break; ++ default: ++ dev_err(flash->dev, "it is flash Unknown state, device_id: 0x%02x\n", device_id); ++ ret = -EIO; ++ } ++ break; ++ case 0x20: ++ ret = 0; ++ break; ++ default: ++ dev_warn(flash->dev, "device_id err, it maybe don`t support this device, check your device id: device_id = 0x%02x\n", device_id); ++ ret = -EIO; ++ } ++ return ret; ++} ++ ++static void mxic_single_read(struct sfc_transfer *transfer, struct flash_operation_message *op_info) { ++ ++ struct sfc_flash *flash = op_info->flash; ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ uint8_t device_id = nand_info->id_device; ++ uint32_t columnaddr = op_info->columnaddr; ++ int plane_flag = 0; ++ ++ switch(device_id) { ++ case 0x20: ++ case 0x22: ++ plane_flag = (op_info->pageaddr >> 6) & 1; ++ columnaddr |= (plane_flag << 12); ++ break; ++ case 0x12: ++ break; ++ default: ++ dev_err(flash->dev, "device_id err,it maybe don`t support this device, please check your device id: device_id = 0x%02x\n", device_id); ++ break; ++ } ++ ++ transfer->cmd_info.cmd = SPINAND_CMD_FRCH; ++ transfer->sfc_mode = TM_STD_SPI; ++ ++ transfer->addr = columnaddr; ++ transfer->addr_len = 2; ++ ++ transfer->cmd_info.dataen = ENABLE; ++ transfer->data = op_info->buffer; ++ transfer->len = op_info->len; ++ transfer->direction = GLB_TRAN_DIR_READ; ++ ++ transfer->data_dummy_bits = 8; ++ transfer->ops_mode = DMA_OPS; ++ return; ++} ++ ++static void mxic_quad_read(struct sfc_transfer *transfer, struct flash_operation_message *op_info) { ++ ++ struct sfc_flash *flash = op_info->flash; ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ uint8_t device_id = nand_info->id_device; ++ uint32_t columnaddr = op_info->columnaddr; ++ int plane_flag = 0; ++ ++ switch(device_id) { ++ case 0x20: ++ case 0x22: ++ plane_flag = (op_info->pageaddr >> 6) & 1; ++ columnaddr |= (plane_flag << 12); ++ break; ++ case 0x12: ++ break; ++ default: ++ dev_err(flash->dev, "device_id err,it maybe don`t support this device, please check your device id: device_id = 0x%02x\n", device_id); ++ break; ++ } ++ ++ transfer->cmd_info.cmd = SPINAND_CMD_RDCH_X4; ++ transfer->sfc_mode = TM_QI_QO_SPI; ++ ++ transfer->addr = columnaddr; ++ transfer->addr_len = 2; ++ ++ transfer->cmd_info.dataen = ENABLE; ++ transfer->data = op_info->buffer; ++ transfer->len = op_info->len; ++ transfer->direction = GLB_TRAN_DIR_READ; ++ ++ transfer->data_dummy_bits = 8; ++ transfer->ops_mode = DMA_OPS; ++ return; ++} ++ ++static void mxic_single_load(struct sfc_transfer *transfer, struct flash_operation_message *op_info) { ++ ++ struct sfc_flash *flash = op_info->flash; ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ uint8_t device_id = nand_info->id_device; ++ uint32_t columnaddr = op_info->columnaddr; ++ int plane_flag = 0; ++ ++ switch(device_id) { ++ case 0x20: ++ case 0x22: ++ plane_flag = (op_info->pageaddr >> 6) & 1; ++ columnaddr |= (plane_flag << 12); ++ break; ++ case 0x12: ++ break; ++ default: ++ dev_err(flash->dev, "device_id err,it maybe don`t support this device, please check your device id: device_id = 0x%02x\n", device_id); ++ break; ++ } ++ ++ transfer->cmd_info.cmd = SPINAND_CMD_PRO_LOAD; ++ transfer->sfc_mode = TM_STD_SPI; ++ ++ transfer->addr = columnaddr; ++ transfer->addr_len = 2; ++ ++ transfer->cmd_info.dataen = ENABLE; ++ transfer->data = op_info->buffer; ++ transfer->len = op_info->len; ++ transfer->direction = GLB_TRAN_DIR_WRITE; ++ ++ transfer->data_dummy_bits = 0; ++ transfer->ops_mode = DMA_OPS; ++} ++ ++static void mxic_quad_load(struct sfc_transfer *transfer, struct flash_operation_message *op_info) { ++ ++ struct sfc_flash *flash = op_info->flash; ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ uint8_t device_id = nand_info->id_device; ++ uint32_t columnaddr = op_info->columnaddr; ++ int plane_flag = 0; ++ ++ switch(device_id) { ++ case 0x20: ++ case 0x22: ++ plane_flag = (op_info->pageaddr >> 6) & 1; ++ columnaddr |= (plane_flag << 12); ++ break; ++ case 0x12: ++ break; ++ default: ++ dev_err(flash->dev, "device_id err,it maybe don`t support this device, please check your device id: device_id = 0x%02x\n", device_id); ++ break; ++ } ++ ++ transfer->cmd_info.cmd = SPINAND_CMD_PRO_LOAD_X4; ++ transfer->sfc_mode = TM_QI_QO_SPI; ++ ++ transfer->addr = columnaddr; ++ transfer->addr_len = 2; ++ ++ transfer->cmd_info.dataen = ENABLE; ++ transfer->data = op_info->buffer; ++ transfer->len = op_info->len; ++ transfer->direction = GLB_TRAN_DIR_WRITE; ++ ++ transfer->data_dummy_bits = 0; ++ transfer->ops_mode = DMA_OPS; ++ ++} ++ ++static void mxic_program_exec(struct sfc_transfer *transfer, struct flash_operation_message *op_info) { ++ ++ transfer->cmd_info.cmd = SPINAND_CMD_PRO_EN; ++ transfer->sfc_mode = TM_STD_SPI; ++ ++ transfer->addr = op_info->pageaddr; ++ transfer->addr_len = 3; ++ ++ transfer->cmd_info.dataen = DISABLE; ++ transfer->len = 0; ++ ++ transfer->data_dummy_bits = 0; ++ transfer->ops_mode = CPU_OPS; ++} ++ ++static int __init mxic_nand_init(void) { ++ struct ingenic_sfcnand_device *mxic_nand; ++ mxic_nand = kzalloc(sizeof(*mxic_nand), GFP_KERNEL); ++ if(!mxic_nand) { ++ pr_err("alloc mxic_nand struct fail\n"); ++ return -ENOMEM; ++ } ++ ++ mxic_nand->id_manufactory = 0xC2; ++ mxic_nand->id_device_list = device_id; ++ mxic_nand->id_device_count = MXIC_DEVICES_NUM; ++ ++ mxic_nand->ops.nand_read_ops.pageread_to_cache = mxic_pageread_to_cache; ++ mxic_nand->ops.nand_read_ops.get_feature = mxic_get_read_feature; ++ mxic_nand->ops.nand_read_ops.single_read = mxic_single_read; ++ mxic_nand->ops.nand_read_ops.quad_read = mxic_quad_read; ++ ++ mxic_nand->ops.nand_write_ops.single_load = mxic_single_load; ++ mxic_nand->ops.nand_write_ops.quad_load = mxic_quad_load; ++ mxic_nand->ops.nand_write_ops.program_exec = mxic_program_exec; ++ ++ return ingenic_sfcnand_register(mxic_nand); ++} ++fs_initcall(mxic_nand_init); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_nand_device_nand_common.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_nand_device_nand_common.c.patch new file mode 100644 index 00000000..d0a1c2f7 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_nand_device_nand_common.c.patch @@ -0,0 +1,359 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v1/nand_device/nand_common.c b/drivers/mtd/devices/ingenic_sfc_v1/nand_device/nand_common.c +--- a/drivers/mtd/devices/ingenic_sfc_v1/nand_device/nand_common.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v1/nand_device/nand_common.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,355 @@ ++#include ++#include ++#include "../sfc.h" ++#include "../spinand.h" ++#include "../spinand_cmd.h" ++#include "../ingenic_sfc_common.h" ++ ++/* ++ * pageread_to_cache default: ++ * cmd = SPINAND_CMD_PARD ++ * addr_len = 3 ++ * data_dummy_bits = 0 ++ * dataen = disable ++ * ++ */ ++void nand_pageread_to_cache(struct sfc_transfer *transfer, struct flash_operation_message *op_info) { ++ ++ transfer->cmd_info.cmd = SPINAND_CMD_PARD; ++ transfer->sfc_mode = TM_STD_SPI; ++ ++ transfer->addr = op_info->pageaddr; ++ transfer->addr_len = 3; ++ ++ transfer->cmd_info.dataen = DISABLE; ++ transfer->len = 0; ++ ++ transfer->data_dummy_bits = 0; ++ transfer->ops_mode = CPU_OPS; ++ return; ++} ++EXPORT_SYMBOL_GPL(nand_pageread_to_cache); ++ ++/* ++ * single read default format: ++ * cmd = SPINAND_CMD_FRCH ++ * addr_len = 2; ++ * data_dummy_bits = 8 ++ * dataen = enable ++ */ ++void nand_single_read(struct sfc_transfer *transfer, struct flash_operation_message *op_info) { ++ ++ transfer->cmd_info.cmd = SPINAND_CMD_FRCH; ++ transfer->sfc_mode = TM_STD_SPI; ++ ++ transfer->addr = op_info->columnaddr; ++ transfer->addr_len = 2; ++ ++ transfer->cmd_info.dataen = ENABLE; ++ transfer->data = op_info->buffer; ++ transfer->len = op_info->len; ++ transfer->direction = GLB_TRAN_DIR_READ; ++ ++ transfer->data_dummy_bits = 8; ++ transfer->ops_mode = DMA_OPS; ++ return; ++} ++EXPORT_SYMBOL_GPL(nand_single_read); ++ ++/* ++ * quad read default format: ++ * cmd = SPINAND_CMD_RDCH_X4 ++ * addr_len = 2; ++ * data_dummy_bits = 8; ++ * dataen = enable ++ */ ++void nand_quad_read(struct sfc_transfer *transfer, struct flash_operation_message *op_info) { ++ ++ transfer->cmd_info.cmd = SPINAND_CMD_RDCH_X4; ++ transfer->sfc_mode = TM_QI_QO_SPI; ++ ++ transfer->addr = op_info->columnaddr; ++ transfer->addr_len = 2; ++ ++ transfer->cmd_info.dataen = ENABLE; ++ transfer->data = op_info->buffer; ++ transfer->len = op_info->len; ++ transfer->direction = GLB_TRAN_DIR_READ; ++ ++ transfer->data_dummy_bits = 8; ++ transfer->ops_mode = DMA_OPS; ++ return; ++} ++EXPORT_SYMBOL_GPL(nand_quad_read); ++ ++/* ++ * write_enable default: ++ * cmd = SPINAND_CMD_WREN ++ * addr = 0 ++ * dummy = 0 ++ * dataen = 0 ++ */ ++void nand_write_enable(struct sfc_transfer *transfer, struct flash_operation_message *op_info) { ++ ++ transfer->cmd_info.cmd = SPINAND_CMD_WREN; ++ transfer->sfc_mode = TM_STD_SPI; ++ ++ transfer->addr = 0; ++ transfer->addr_len = 0; ++ ++ transfer->cmd_info.dataen = DISABLE; ++ transfer->len = 0; ++ ++ transfer->data_dummy_bits = 0; ++ transfer->ops_mode = CPU_OPS; ++ return; ++} ++EXPORT_SYMBOL_GPL(nand_write_enable); ++ ++/* ++ * single_load default: ++ * cmd = SPINAND_CMD_PRO_LOAD ++ * addr_len = 2 ++ * data_dummy_bits = 0 ++ * dataen = enable ++ * ++ */ ++void nand_single_load(struct sfc_transfer *transfer, struct flash_operation_message *op_info) { ++ ++ transfer->cmd_info.cmd = SPINAND_CMD_PRO_LOAD; ++ transfer->sfc_mode = TM_STD_SPI; ++ ++ transfer->addr = op_info->columnaddr; ++ transfer->addr_len = 2; ++ ++ transfer->cmd_info.dataen = ENABLE; ++ transfer->data = op_info->buffer; ++ transfer->len = op_info->len; ++ transfer->direction = GLB_TRAN_DIR_WRITE; ++ ++ transfer->data_dummy_bits = 0; ++ transfer->ops_mode = DMA_OPS; ++ return; ++} ++EXPORT_SYMBOL_GPL(nand_single_load); ++ ++/* ++ * quad_load default: ++ * cmd = SPINAND_CMD_PRO_LOAD_X4 ++ * addr_len = 2 ++ * data_dummy_bits = 0 ++ * dataen = enable ++ */ ++void nand_quad_load(struct sfc_transfer *transfer, struct flash_operation_message *op_info) { ++ ++ transfer->cmd_info.cmd = SPINAND_CMD_PRO_LOAD_X4; ++ transfer->sfc_mode = TM_QI_QO_SPI; ++ ++ transfer->addr = op_info->columnaddr; ++ transfer->addr_len = 2; ++ ++ transfer->cmd_info.dataen = ENABLE; ++ transfer->data = op_info->buffer; ++ transfer->len = op_info->len; ++ transfer->direction = GLB_TRAN_DIR_WRITE; ++ ++ transfer->data_dummy_bits = 0; ++ transfer->ops_mode = DMA_OPS; ++ return; ++} ++EXPORT_SYMBOL_GPL(nand_quad_load); ++ ++/* ++ * program_exec default: ++ * cmd = SPINAND_CMD_PRO_EN ++ * addr_len = 3 ++ * data_dummy_bits = 0 ++ * dataen = disable ++ */ ++void nand_program_exec(struct sfc_transfer *transfer, struct flash_operation_message *op_info) { ++ ++ transfer->cmd_info.cmd = SPINAND_CMD_PRO_EN; ++ transfer->sfc_mode = TM_STD_SPI; ++ ++ transfer->addr = op_info->pageaddr; ++ transfer->addr_len = 3; ++ ++ transfer->cmd_info.dataen = DISABLE; ++ transfer->len = 0; ++ ++ transfer->data_dummy_bits = 0; ++ transfer->ops_mode = CPU_OPS; ++} ++EXPORT_SYMBOL_GPL(nand_program_exec); ++ ++/* ++ * get_program_feature default: ++ * cmd = SPINAND_CMD_GET_FEATURE ++ * addr = SPINAND_ADDR_STATUS ++ * data_dummy_bits = 0 ++ * dataen = enable ++ */ ++int32_t nand_get_program_feature(struct flash_operation_message *op_info) { ++ ++ struct sfc_flash *flash = op_info->flash; ++ struct sfc_transfer transfer; ++ uint32_t ecc_status; ++ ++retry: ++ ecc_status = 0; ++ memset(&transfer, 0, sizeof(transfer)); ++ sfc_list_init(&transfer); ++ ++ transfer.cmd_info.cmd = SPINAND_CMD_GET_FEATURE; ++ transfer.sfc_mode = TM_STD_SPI; ++ ++ transfer.addr = SPINAND_ADDR_STATUS; ++ transfer.addr_len = 1; ++ ++ transfer.cmd_info.dataen = ENABLE; ++ transfer.data = (uint8_t *)&ecc_status; ++ transfer.len = 1; ++ transfer.direction = GLB_TRAN_DIR_READ; ++ ++ transfer.data_dummy_bits = 0; ++ transfer.ops_mode = CPU_OPS; ++ ++ if(sfc_sync_poll(flash->sfc, &transfer)) { ++ dev_err(flash->dev,"sfc_sync error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ if(ecc_status & SPINAND_IS_BUSY) ++ goto retry; ++ if(ecc_status & (1 << 3)) ++ return -EIO; ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(nand_get_program_feature); ++ ++/* ++ * block_erase default: ++ * cmd = SPINAND_CMD_ERASE_128K ++ * addr_len = 3 ++ * data_dummy_bits = 0 ++ * dataen = disable ++ */ ++void nand_block_erase(struct sfc_transfer *transfer, struct flash_operation_message *op_info) { ++ ++ transfer->cmd_info.cmd = SPINAND_CMD_ERASE_128K; ++ transfer->sfc_mode = TM_STD_SPI; ++ ++ transfer->addr = op_info->pageaddr; ++ transfer->addr_len = 3; ++ ++ transfer->cmd_info.dataen = DISABLE; ++ transfer->len = 0; ++ ++ transfer->data_dummy_bits = 0; ++ transfer->ops_mode = CPU_OPS; ++ return; ++} ++EXPORT_SYMBOL_GPL(nand_block_erase); ++ ++/* ++ * get_erase_feature default: ++ * cmd = SPINAND_CMD_GET_FEATURE ++ * addr_len = 1 ++ * data_dummy_bits = 0 ++ * dataen = disable ++ * polling = SPINAND_IS_BUSY ++ */ ++int32_t nand_get_erase_feature(struct flash_operation_message *op_info) { ++ ++ struct sfc_flash *flash = op_info->flash; ++ struct sfc_transfer transfer; ++ uint32_t ecc_status; ++ ++retry: ++ ecc_status = 0; ++ memset(&transfer, 0, sizeof(transfer)); ++ sfc_list_init(&transfer); ++ ++ transfer.cmd_info.cmd = SPINAND_CMD_GET_FEATURE; ++ transfer.sfc_mode = TM_STD_SPI; ++ ++ transfer.addr = SPINAND_ADDR_STATUS; ++ transfer.addr_len = 1; ++ ++ transfer.cmd_info.dataen = ENABLE; ++ transfer.data = (uint8_t *)&ecc_status; ++ transfer.len = 1; ++ transfer.direction = GLB_TRAN_DIR_READ; ++ ++ transfer.data_dummy_bits = 0; ++ transfer.ops_mode = CPU_OPS; ++ ++ if(sfc_sync_poll(flash->sfc, &transfer)) { ++ dev_err(flash->dev, "sfc_sync error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ if(ecc_status & SPINAND_IS_BUSY) ++ goto retry; ++ ++ if(ecc_status & (1 << 2)) ++ return -EIO; ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(nand_get_erase_feature); ++ ++/* ++ * nand_set_feature default: ++ * cmd = SPINAND_CMD_SET_FEATURE ++ * addr_len = 1 ++ * data_dummy_bits = 0 ++ * dataen = enable ++ * ++ */ ++void nand_set_feature(struct sfc_transfer *transfer, uint8_t addr, uint32_t *val) { ++ ++ transfer->cmd_info.cmd = SPINAND_CMD_SET_FEATURE; ++ transfer->sfc_mode = TM_STD_SPI; ++ ++ transfer->addr = addr; ++ transfer->addr_len = 1; ++ ++ transfer->cmd_info.dataen = ENABLE; ++ transfer->data = (uint8_t *)val; ++ transfer->len = 1; ++ transfer->direction = GLB_TRAN_DIR_WRITE; ++ ++ transfer->data_dummy_bits = 0; ++ transfer->ops_mode = CPU_OPS; ++ return; ++} ++EXPORT_SYMBOL_GPL(nand_set_feature); ++ ++/* ++ * nand_get_feature default: ++ * cmd = SPINAND_CMD_GET_FEATURE ++ * addr_len = 1 ++ * data_dummy_bits = 0 ++ * dataen = enable ++ * ++ */ ++void nand_get_feature(struct sfc_transfer *transfer, uint8_t addr, uint8_t *val) { ++ ++ transfer->cmd_info.cmd = SPINAND_CMD_GET_FEATURE; ++ transfer->sfc_mode = TM_STD_SPI; ++ ++ transfer->addr = addr; ++ transfer->addr_len = 1; ++ ++ transfer->cmd_info.dataen = ENABLE; ++ transfer->data = val; ++ transfer->len = 1; ++ transfer->direction = GLB_TRAN_DIR_READ; ++ ++ transfer->data_dummy_bits = 0; ++ transfer->ops_mode = CPU_OPS; ++ return; ++} ++EXPORT_SYMBOL_GPL(nand_get_feature); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_nand_device_nand_common.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_nand_device_nand_common.h.patch new file mode 100644 index 00000000..f4e5f24c --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_nand_device_nand_common.h.patch @@ -0,0 +1,44 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v1/nand_device/nand_common.h b/drivers/mtd/devices/ingenic_sfc_v1/nand_device/nand_common.h +--- a/drivers/mtd/devices/ingenic_sfc_v1/nand_device/nand_common.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v1/nand_device/nand_common.h 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,40 @@ ++#ifndef __NAND_COMMON_H ++#define __NAND_COMMON_H ++#include ++#include "../sfc.h" ++#include "../sfc_flash.h" ++#include "../spinand.h" ++ ++#define DEVICE_ID_STRUCT(id, name_string, parameter) { \ ++ .id_device = id, \ ++ .name = name_string, \ ++ .param = parameter, \ ++} ++ ++void nand_pageread_to_cache(struct sfc_transfer *transfer, struct flash_operation_message *op_info); ++ ++void nand_single_read(struct sfc_transfer *transfer, struct flash_operation_message *op_info); ++ ++void nand_quad_read(struct sfc_transfer *transfer, struct flash_operation_message *op_info); ++ ++void nand_write_enable(struct sfc_transfer *transfer, struct flash_operation_message *op_info); ++ ++ ++void nand_single_load(struct sfc_transfer *transfer, struct flash_operation_message *op_info); ++ ++void nand_quad_load(struct sfc_transfer *transfer, struct flash_operation_message *op_info); ++ ++void nand_program_exec(struct sfc_transfer *transfer, struct flash_operation_message *op_info); ++ ++int32_t nand_get_program_feature(struct flash_operation_message *op_info); ++ ++void nand_block_erase(struct sfc_transfer *transfer, struct flash_operation_message *op_info); ++ ++int32_t nand_get_erase_feature(struct flash_operation_message *op_info); ++ ++void nand_set_feature(struct sfc_transfer *transfer, uint8_t addr, uint32_t *val); ++ ++void nand_get_feature(struct sfc_transfer *transfer, uint8_t addr, uint8_t *val); ++ ++void winbond_reset(struct sfc_flash *flash); ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_nand_device_winbond_nand.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_nand_device_winbond_nand.c.patch new file mode 100644 index 00000000..0c80ff88 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_nand_device_winbond_nand.c.patch @@ -0,0 +1,420 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v1/nand_device/winbond_nand.c b/drivers/mtd/devices/ingenic_sfc_v1/nand_device/winbond_nand.c +--- a/drivers/mtd/devices/ingenic_sfc_v1/nand_device/winbond_nand.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v1/nand_device/winbond_nand.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,416 @@ ++/*#define WINBOND_DEBUG*/ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../spinand.h" ++#include "../ingenic_sfc_common.h" ++#include "nand_common.h" ++ ++#define WINBOND_DEVICES_NUM 2 ++ ++#define WINDOND_DIE_SELECT 0xC2 ++#define WINDOND_RESET 0xFF ++#define TSETUP 5 ++#define THOLD 3 ++#define TSHSL_R 10 ++#define TSHSL_W 50 ++ ++#define TRD 60 ++#define TPP 700 ++#define TBE 10 ++ ++static struct ingenic_sfcnand_base_param winbond_param[WINBOND_DEVICES_NUM] = { ++ [0] = { ++ /*W25N01GV*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ ++ .tSETUP =TSETUP, ++ .tHOLD =THOLD, ++ .tSHSL_R =TSHSL_R, ++ .tSHSL_W =TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .ecc_max = 0x4, ++ .need_quad = 1, ++ }, ++ ++ [1] = { ++ /*W25M02GV */ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 2048, ++ ++ .tSETUP =TSETUP, ++ .tHOLD =THOLD, ++ .tSHSL_R =TSHSL_R, ++ .tSHSL_W =TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .ecc_max = 0x4, ++ .need_quad = 1, ++ ++ } ++}; ++ ++static struct device_id_struct device_id[WINBOND_DEVICES_NUM] = { ++ DEVICE_ID_STRUCT(0xAA, "W25N01GV", &winbond_param[0]), ++ DEVICE_ID_STRUCT(0xAB, "W25M02GV", &winbond_param[1]), ++}; ++ ++static void active_die(struct sfc_flash *flash, uint8_t die_id) { ++ ++ struct sfc_transfer transfer; ++ ++ memset(&transfer, 0, sizeof(transfer)); ++ sfc_list_init(&transfer); ++ ++ transfer.cmd_info.cmd = WINDOND_DIE_SELECT; ++ transfer.sfc_mode = TM_STD_SPI; ++ ++ transfer.addr = die_id; ++ transfer.addr_len = 1; ++ ++ transfer.cmd_info.dataen = DISABLE; ++ transfer.len = 0; ++ ++ transfer.data_dummy_bits = 0; ++ transfer.ops_mode = CPU_OPS; ++ ++ if(sfc_sync_poll(flash->sfc, &transfer)) { ++ dev_err(flash->dev, "sfc_sync_poll error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return; ++ } ++} ++ ++void winbond_reset(struct sfc_flash *flash) { ++ ++ struct sfc_transfer transfer; ++ ++ memset(&transfer, 0, sizeof(transfer)); ++ sfc_list_init(&transfer); ++ ++ transfer.cmd_info.cmd = WINDOND_RESET; ++ transfer.sfc_mode = TM_STD_SPI; ++ ++ transfer.addr = 0; ++ transfer.addr_len = 0; ++ ++ transfer.cmd_info.dataen = DISABLE; ++ transfer.len = 0; ++ ++ transfer.data_dummy_bits = 0; ++ transfer.ops_mode = CPU_OPS; ++ ++ if(sfc_sync_poll(flash->sfc, &transfer)) { ++ dev_err(flash->dev, "sfc_sync_poll error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return; ++ } ++} ++ ++#ifdef WINBOND_DEBUG ++static void winbond_print_register(struct sfc_flash *flash, uint8_t register_addr) { ++ ++ struct sfc_transfer transfer; ++ uint8_t ret = 0; ++ ++ memset(&transfer, 0, sizeof(transfer)); ++ ++ sfc_list_init(&transfer); ++ nand_get_feature(&transfer, register_addr, &ret); ++ ++ if(sfc_sync_poll(flash->sfc, &transfer)) { ++ dev_err(flash->dev, "sfc_sync_poll error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return; ++ } ++ ++ printk("printk register (%x) = %x\n", register_addr, ret); ++ ++} ++ ++#endif ++ ++static void winbond_pageread_to_cache(struct sfc_transfer *transfer, struct flash_operation_message *op_info) { ++ ++ struct sfc_flash *flash = op_info->flash; ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ uint8_t device_id = nand_info->id_device; ++ uint32_t pageaddr = op_info->pageaddr; ++ ++ switch(device_id) { ++ case 0xAB: ++ if(pageaddr > 65535) { ++ active_die(flash, 1); ++ pageaddr -= 65536; ++ } else { ++ active_die(flash, 0); ++ } ++ case 0xAA: ++ break; ++ default: ++ dev_err(flash->dev, "device_id err,it maybe don`t support this device, please check your device id: device_id = 0x%02x\n", device_id); ++ } ++ ++ transfer->cmd_info.cmd = SPINAND_CMD_PARD; ++ transfer->sfc_mode = TM_STD_SPI; ++ ++ transfer->addr = pageaddr; ++ transfer->addr_len = 3; ++ ++ transfer->cmd_info.dataen = DISABLE; ++ transfer->len = 0; ++ ++ transfer->data_dummy_bits = 0; ++ transfer->ops_mode = CPU_OPS; ++ return; ++} ++ ++static void winbond_single_read(struct sfc_transfer *transfer, struct flash_operation_message *op_info) { ++ ++ transfer->cmd_info.cmd = SPINAND_CMD_FRCH; ++ transfer->sfc_mode = TM_STD_SPI; ++ ++ transfer->addr = op_info->columnaddr; ++ transfer->addr_len = 2; ++ ++ transfer->cmd_info.dataen = ENABLE; ++ transfer->data = op_info->buffer; ++ transfer->len = op_info->len; ++ transfer->direction = GLB_TRAN_DIR_READ; ++ ++ transfer->data_dummy_bits = 8; ++ transfer->ops_mode = DMA_OPS; ++ return; ++} ++ ++static void winbond_quad_read(struct sfc_transfer *transfer, struct flash_operation_message *op_info) { ++ ++ transfer->cmd_info.cmd = SPINAND_CMD_RDCH_X4; ++ transfer->sfc_mode = TM_QI_QO_SPI; ++ ++ transfer->addr = op_info->columnaddr; ++ transfer->addr_len = 2; ++ ++ transfer->cmd_info.dataen = ENABLE; ++ transfer->data = op_info->buffer; ++ transfer->len = op_info->len; ++ transfer->direction = GLB_TRAN_DIR_READ; ++ ++ transfer->data_dummy_bits = 8; ++ transfer->ops_mode = DMA_OPS; ++ return; ++} ++ ++static int32_t winbond_get_read_feature(struct flash_operation_message *op_info) { ++ ++ struct sfc_flash *flash = op_info->flash; ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ struct sfc_transfer transfer; ++ uint8_t device_id = nand_info->id_device; ++ uint8_t ecc_status = 0; ++ int32_t ret = 0; ++ ++retry: ++ ecc_status = 0; ++ memset(&transfer, 0, sizeof(transfer)); ++ sfc_list_init(&transfer); ++ ++ transfer.cmd_info.cmd = SPINAND_CMD_GET_FEATURE; ++ transfer.sfc_mode = TM_STD_SPI; ++ ++ transfer.addr = SPINAND_ADDR_STATUS; ++ transfer.addr_len = 1; ++ ++ transfer.cmd_info.dataen = ENABLE; ++ transfer.data = &ecc_status; ++ transfer.len = 1; ++ transfer.direction = GLB_TRAN_DIR_READ; ++ ++ transfer.data_dummy_bits = 0; ++ transfer.ops_mode = CPU_OPS; ++ ++ if(sfc_sync_poll(flash->sfc, &transfer)) { ++ dev_err(flash->dev,"sfc_sync_poll error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ if(ecc_status & SPINAND_IS_BUSY) ++ goto retry; ++ ++ switch(device_id) { ++ case 0xAA ... 0xAB: ++ switch((ecc_status >> 4) & 0x3) { ++ case 0x0: ++ ret = 0; ++ break; ++ case 0x01: ++ ret = 0x4; ++ break; ++ default: ++ ret = -EBADMSG; ++ } ++ break; ++ default: ++ dev_err(flash->dev, "device_id err, it maybe don`t support this device, check your device id: device_id = 0x%02x\n", device_id); ++ ret = -EIO; //notice!!! ++ ++ } ++ ++ if(ret < 0) ++ dev_err(flash->dev, "%s %s %d, ecc_status = %d, ret = %d\n", ++ __FILE__, __func__, __LINE__, ecc_status, ret); ++ return ret; ++} ++ ++static void winbond_set_register(struct sfc_flash *flash, uint8_t register_addr, uint32_t val) { ++ ++ struct sfc_transfer transfer; ++ ++ memset(&transfer, 0, sizeof(transfer)); ++ ++ sfc_list_init(&transfer); ++ nand_set_feature(&transfer, register_addr, &val); ++ ++ if(sfc_sync_poll(flash->sfc, &transfer)) { ++ dev_err(flash->dev, "sfc_sync_poll error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return; ++ } ++ ++} ++ ++static void winbond_write_enable(struct sfc_transfer *transfer, struct flash_operation_message *op_info) { ++ ++ struct sfc_flash *flash = op_info->flash; ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ uint8_t device_id = nand_info->id_device; ++ ++ switch(device_id) { ++ case 0xAB: ++ if(op_info->pageaddr > 65535) { ++ active_die(flash, 1); ++ /*clear protect bits, because each die ++ * has a set of state registers. */ ++ winbond_set_register(flash, SPINAND_ADDR_PROTECT, 0); ++ winbond_set_register(flash, SPINAND_ADDR_FEATURE, (1 << 4) | (1 << 3)); ++ } else { ++ active_die(flash, 0); ++ } ++ case 0xAA: ++ break; ++ default: ++ dev_err(flash->dev, "device_id err,it maybe don`t support this device, please check your device id: device_id = 0x%02x\n", device_id); ++ } ++ ++ transfer->cmd_info.cmd = SPINAND_CMD_WREN; ++ transfer->sfc_mode = TM_STD_SPI; ++ ++ transfer->addr = 0; ++ transfer->addr_len = 0; ++ ++ transfer->cmd_info.dataen = DISABLE; ++ transfer->len = 0; ++ ++ transfer->data_dummy_bits = 0; ++ transfer->ops_mode = CPU_OPS; ++ return; ++} ++ ++static void winbond_program_exec(struct sfc_transfer *transfer, struct flash_operation_message *op_info) { ++ ++ struct sfc_flash *flash = op_info->flash; ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ uint8_t device_id = nand_info->id_device; ++ uint32_t pageaddr = op_info->pageaddr; ++ ++ switch(device_id) { ++ case 0xAB: ++ if(pageaddr > 65535) ++ pageaddr -= 65536; ++ case 0xAA: ++ break; ++ default: ++ dev_err(flash->dev, "device_id err,it maybe don`t support this device, please check your device id: device_id = 0x%02x\n", device_id); ++ } ++ ++ transfer->cmd_info.cmd = SPINAND_CMD_PRO_EN; ++ transfer->sfc_mode = TM_STD_SPI; ++ ++ transfer->addr = pageaddr; ++ transfer->addr_len = 3; ++ ++ transfer->cmd_info.dataen = DISABLE; ++ transfer->len = 0; ++ ++ transfer->data_dummy_bits = 0; ++ transfer->ops_mode = CPU_OPS; ++} ++ ++static void winbond_block_erase(struct sfc_transfer *transfer, struct flash_operation_message *op_info) { ++ ++ struct sfc_flash *flash = op_info->flash; ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ uint8_t device_id = nand_info->id_device; ++ uint32_t pageaddr = op_info->pageaddr; ++ ++ switch(device_id) { ++ case 0xAB: ++ if(pageaddr > 65535) ++ pageaddr -= 65536; ++ case 0xAA: ++ break; ++ default: ++ dev_err(flash->dev, "device_id err,it maybe don`t support this device, please check your device id: device_id = 0x%02x\n", device_id); ++ } ++ ++ transfer->cmd_info.cmd = SPINAND_CMD_ERASE_128K; ++ transfer->sfc_mode = TM_STD_SPI; ++ ++ transfer->addr = pageaddr; ++ transfer->addr_len = 3; ++ ++ transfer->cmd_info.dataen = DISABLE; ++ transfer->len = 0; ++ ++ transfer->data_dummy_bits = 0; ++ transfer->ops_mode = CPU_OPS; ++ ++} ++ ++static int __init winbond_nand_init(void) { ++ struct ingenic_sfcnand_device *winbond_nand; ++ winbond_nand = kzalloc(sizeof(*winbond_nand), GFP_KERNEL); ++ if(!winbond_nand) { ++ pr_err("alloc winbond_nand struct fail\n"); ++ return -ENOMEM; ++ } ++ ++ winbond_nand->id_manufactory = 0xEF; ++ winbond_nand->id_device_list = device_id; ++ winbond_nand->id_device_count = WINBOND_DEVICES_NUM; ++ ++ winbond_nand->ops.nand_read_ops.pageread_to_cache = winbond_pageread_to_cache; ++ winbond_nand->ops.nand_read_ops.single_read = winbond_single_read; ++ winbond_nand->ops.nand_read_ops.quad_read = winbond_quad_read; ++ winbond_nand->ops.nand_read_ops.get_feature = winbond_get_read_feature; ++ ++ winbond_nand->ops.nand_write_ops.write_enable = winbond_write_enable; ++ winbond_nand->ops.nand_write_ops.program_exec = winbond_program_exec; ++ ++ winbond_nand->ops.nand_erase_ops.write_enable = winbond_write_enable; ++ winbond_nand->ops.nand_erase_ops.block_erase = winbond_block_erase; ++ ++ return ingenic_sfcnand_register(winbond_nand); ++} ++fs_initcall(winbond_nand_init); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_nand_device_xtx_nand.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_nand_device_xtx_nand.c.patch new file mode 100644 index 00000000..1934c1da --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_nand_device_xtx_nand.c.patch @@ -0,0 +1,145 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v1/nand_device/xtx_nand.c b/drivers/mtd/devices/ingenic_sfc_v1/nand_device/xtx_nand.c +--- a/drivers/mtd/devices/ingenic_sfc_v1/nand_device/xtx_nand.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v1/nand_device/xtx_nand.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,141 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../spinand.h" ++#include "../ingenic_sfc_common.h" ++#include "nand_common.h" ++ ++#define XTX_DEVICES_NUM 2 ++#define TSETUP 5 ++#define THOLD 5 ++#define TSHSL_R 20 ++#define TSHSL_W 20 ++ ++#define TRD 240 ++#define TPP 1400 ++#define TBE 10 ++ ++static struct ingenic_sfcnand_base_param xtx_param[XTX_DEVICES_NUM] = { ++ ++ [0] = { ++ /*PN26G01AW*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 128, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .ecc_max = 0x8, ++ .need_quad = 1, ++ }, ++ [1] = { ++ /*PN26G02AW */ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 128, ++ .flashsize = 2 * 1024 * 64 * 2048, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .ecc_max = 0x8, ++ .need_quad = 1, ++ } ++ ++}; ++ ++static struct device_id_struct device_id[XTX_DEVICES_NUM] = { ++ DEVICE_ID_STRUCT(0xE1, "PN26G01AW", &xtx_param[0]), ++ DEVICE_ID_STRUCT(0xE2, "PN26G02AW", &xtx_param[1]), ++}; ++ ++static int32_t xtx_get_read_feature(struct flash_operation_message *op_info) { ++ ++ struct sfc_flash *flash = op_info->flash; ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ struct sfc_transfer transfer; ++ uint8_t device_id = nand_info->id_device; ++ uint8_t ecc_status = 0; ++ int32_t ret = 0; ++ ++retry: ++ ecc_status = 0; ++ memset(&transfer, 0, sizeof(transfer)); ++ sfc_list_init(&transfer); ++ ++ transfer.cmd_info.cmd = SPINAND_CMD_GET_FEATURE; ++ transfer.sfc_mode = TM_STD_SPI; ++ ++ transfer.addr = SPINAND_ADDR_STATUS; ++ transfer.addr_len = 1; ++ ++ transfer.cmd_info.dataen = ENABLE; ++ transfer.data = &ecc_status; ++ transfer.len = 1; ++ transfer.direction = GLB_TRAN_DIR_READ; ++ ++ transfer.data_dummy_bits = 0; ++ transfer.ops_mode = CPU_OPS; ++ ++ if(sfc_sync_poll(flash->sfc, &transfer)) { ++ dev_err(flash->dev, "sfc_sync error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ if(ecc_status & SPINAND_IS_BUSY) ++ goto retry; ++ ++ switch(device_id) { ++ case 0xE1 ... 0xE2: ++ switch((ecc_status >> 4) & 0x3) { ++ case 0x02: ++ ret = -EBADMSG; ++ break; ++ case 0x03: ++ ret = 0x8; ++ break; ++ default: ++ ret = 0; ++ } ++ break; ++ default: ++ dev_err(flash->dev, "device_id err, it maybe don`t support this device, check your device id: device_id = 0x%02x\n", device_id); ++ ret = -EIO; //notice!!! ++ ++ } ++ return ret; ++} ++ ++static int __init xtx_nand_init(void) { ++ struct ingenic_sfcnand_device *xtx_nand; ++ xtx_nand = kzalloc(sizeof(*xtx_nand), GFP_KERNEL); ++ if(!xtx_nand) { ++ pr_err("alloc xtx_nand struct fail\n"); ++ return -ENOMEM; ++ } ++ ++ xtx_nand->id_manufactory = 0xA1; ++ xtx_nand->id_device_list = device_id; ++ xtx_nand->id_device_count = XTX_DEVICES_NUM; ++ ++ xtx_nand->ops.nand_read_ops.get_feature = xtx_get_read_feature; ++ return ingenic_sfcnand_register(xtx_nand); ++} ++fs_initcall(xtx_nand_init); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_sfc.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_sfc.h.patch new file mode 100644 index 00000000..c6ce736a --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_sfc.h.patch @@ -0,0 +1,62 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v1/sfc.h b/drivers/mtd/devices/ingenic_sfc_v1/sfc.h +--- a/drivers/mtd/devices/ingenic_sfc_v1/sfc.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v1/sfc.h 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,58 @@ ++#ifndef __SFC_H ++#define __SFC_H ++ ++#include ++#include ++#include ++#include ++ ++struct cmd_info{ ++ uint8_t cmd; ++ uint8_t dataen; ++ uint8_t pollen; ++ uint8_t sta_exp; ++ uint8_t sta_msk; ++}; ++ ++struct sfc_transfer { ++ uint8_t direction; ++ ++ struct cmd_info cmd_info; ++ ++ uint8_t addr_len; ++ uint32_t addr; ++ uint32_t addr_plus; ++ uint8_t *data; ++ uint8_t data_dummy_bits;/*addr + data_dummy_bits + data*/ ++ ++ uint32_t len; ++ uint32_t cur_len; ++ ++ uint8_t sfc_mode; ++ uint8_t ops_mode; ++ uint8_t phase_format;/*we just use default value;phase1:cmd+dummy+addr... phase0:cmd+addr+dummy...*/ ++ ++ struct list_head list; ++}; ++ ++struct sfc{ ++ ++ void __iomem *iomem; ++ struct resource *ioarea; ++ int irq; ++ struct clk *clk; ++ struct clk *clk_gate; ++ unsigned long src_clk; ++ struct completion done; ++ uint32_t threshold; ++ irqreturn_t (*irq_callback)(struct sfc *); ++ unsigned long phys; ++ ++ struct sfc_transfer *transfer; ++}; ++ ++ ++ ++#endif ++ ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_sfc_flash.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_sfc_flash.h.patch new file mode 100644 index 00000000..342647f7 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_sfc_flash.h.patch @@ -0,0 +1,33 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v1/sfc_flash.h b/drivers/mtd/devices/ingenic_sfc_v1/sfc_flash.h +--- a/drivers/mtd/devices/ingenic_sfc_v1/sfc_flash.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v1/sfc_flash.h 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,29 @@ ++#ifndef __SFC_FLASH_H ++#define __SFC_FLASH_H ++#include ++#include ++#include ++#include "sfc.h" ++ ++struct sfc_flash { ++ ++ struct sfc *sfc; ++ void *flash_info; ++ struct device* dev; ++ struct mtd_info mtd; ++ struct mutex lock; ++ int param_offset; //param_offset. ++ ++}; ++ ++struct ingenic_sfc_info { ++ ++ uint8_t num_partition; //flash partiton len ++ uint8_t use_board_info; //use board flag ++ void *flash_param; //flash param ++ void *flash_partition; //flash partiton ++ void *other_args; //other args ++ int param_offset; //param_offset. ++}; ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_spinand.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_spinand.h.patch new file mode 100644 index 00000000..8be3021c --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_spinand.h.patch @@ -0,0 +1,116 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v1/spinand.h b/drivers/mtd/devices/ingenic_sfc_v1/spinand.h +--- a/drivers/mtd/devices/ingenic_sfc_v1/spinand.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v1/spinand.h 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,112 @@ ++#ifndef __SPINAND_H ++#define __SPINAND_H ++#include ++#include "sfc_flash.h" ++#include "spinand_cmd.h" ++ ++#define SPIFLASH_PARAMER_OFFSET 0x3c00 ++#define SPINAND_MAGIC_NUM 0x646e616e ++struct ingenic_sfcnand_base_param { ++ uint32_t pagesize; ++ uint32_t blocksize; ++ uint32_t oobsize; ++ uint32_t flashsize; ++ ++ uint16_t tHOLD; ++ uint16_t tSETUP; ++ uint16_t tSHSL_R; ++ uint16_t tSHSL_W; ++ ++ uint16_t tRD; ++ uint16_t tPP; ++ uint16_t tBE; ++ ++ uint8_t ecc_max; ++ uint8_t need_quad; ++}; ++ ++struct ingenic_sfcnand_partition_param { ++ struct mtd_partition *partition; ++ uint8_t num_partition; ++}; ++ ++struct device_id_struct { ++ uint8_t id_device; ++ char *name; ++ struct ingenic_sfcnand_base_param *param; ++}; ++ ++ ++/*this informtion is used by nand devices*/ ++struct flash_operation_message { ++ struct sfc_flash *flash; ++ uint32_t pageaddr; ++ uint32_t columnaddr; ++ u_char *buffer; ++ size_t len; ++}; ++struct ingenic_sfcnand_read { ++ void (*pageread_to_cache)(struct sfc_transfer *, struct flash_operation_message *); ++ int32_t (*get_feature)(struct flash_operation_message *); ++ void (*single_read)(struct sfc_transfer *, struct flash_operation_message *); ++ void (*quad_read)(struct sfc_transfer *, struct flash_operation_message *); ++}; ++ ++struct ingenic_sfcnand_write { ++ void (*write_enable)(struct sfc_transfer *, struct flash_operation_message *); ++ void (*single_load)(struct sfc_transfer *, struct flash_operation_message *); ++ void (*quad_load)(struct sfc_transfer *, struct flash_operation_message *); ++ void (*program_exec)(struct sfc_transfer *, struct flash_operation_message *); ++ int32_t (*get_feature)(struct flash_operation_message *); ++}; ++ ++struct ingenic_sfcnand_erase { ++ void (*write_enable)(struct sfc_transfer *, struct flash_operation_message *); ++ void (*block_erase)(struct sfc_transfer *, struct flash_operation_message *); ++ int32_t (*get_feature)(struct flash_operation_message *); ++}; ++ ++struct ingenic_sfcnand_ops { ++ struct ingenic_sfcnand_read nand_read_ops; ++ struct ingenic_sfcnand_write nand_write_ops; ++ struct ingenic_sfcnand_erase nand_erase_ops; ++}; ++ ++struct ingenic_sfcnand_device { ++ uint8_t id_manufactory; ++ struct device_id_struct *id_device_list; ++ uint8_t id_device_count; ++ ++ struct ingenic_sfcnand_ops ops; ++ struct list_head list; ++}; ++ ++struct ingenic_sfcnand_flashinfo { ++ uint8_t id_manufactory; ++ uint8_t id_device; ++ ++ struct ingenic_sfcnand_base_param param; ++ struct ingenic_sfcnand_partition_param partition; ++ struct ingenic_sfcnand_ops ops; ++ ++ void *swapbuf; ++}; ++ ++struct ingenic_sfcnand_partition { ++ char name[32]; /* identifier string */ ++ uint32_t size; /* partition size */ ++ uint32_t offset; /* offset within the master MTD space */ ++ uint32_t mask_flags; /* master MTD flags to mask out for this partition */ ++ uint32_t manager_mode; /* manager_mode mtd or ubi */ ++}; ++ ++struct ingenic_sfcnand_burner_param { ++ uint32_t magic_num; ++ int32_t partition_num; ++ struct ingenic_sfcnand_partition *partition; ++}; ++ ++int32_t ingenic_sfcnand_register(struct ingenic_sfcnand_device *flash); ++ ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_spinand_cmd.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_spinand_cmd.h.patch new file mode 100644 index 00000000..c0124b86 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_spinand_cmd.h.patch @@ -0,0 +1,33 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v1/spinand_cmd.h b/drivers/mtd/devices/ingenic_sfc_v1/spinand_cmd.h +--- a/drivers/mtd/devices/ingenic_sfc_v1/spinand_cmd.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v1/spinand_cmd.h 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,29 @@ ++#ifndef __SPINAND_CMD_H ++#define __SPINAND_CMD_H ++ ++#define SPINAND_CMD_RDID 0x9f /* read spi nand id */ ++#define SPINAND_CMD_WREN 0x06 /* spi nand write enable */ ++#define SPINAND_CMD_PRO_LOAD 0x02 /* program load */ ++#define SPINAND_CMD_PRO_LOAD_X4 0x32 /* program load fast*/ ++#define SPINAND_CMD_PRO_EN 0x10 /* program load execute */ ++#define SPINAND_CMD_PARD 0x13 /* read page data to spi nand cache */ ++#define SPINAND_CMD_PLRd 0x84 /* program load random data */ ++#define SPINAND_CMD_PLRd_X4 0xc4 /* program load random data x4*/ ++#define SPINAND_CMD_RDCH 0x03 /* read from spi nand cache */ ++#define SPINAND_CMD_RDCH_X4 0x6b /* read from spi nand cache */ ++#define SPINAND_CMD_FRCH 0x0b /* fast read from spi nand cache */ ++#define SPINAND_CMD_FRCH_IO 0xeb /* for Quad I/O SPI mode */ ++#define SPINAND_CMD_ERASE_128K 0xd8 /* erase spi nand block 128K */ ++#define SPINAND_CMD_GET_FEATURE 0x0f /* get spi nand feature */ ++#define SPINAND_CMD_SET_FEATURE 0x1f /* set spi nand feature */ ++ ++ ++#define SPINAND_ADDR_PROTECT 0xa0 /* protect addr */ ++#define SPINAND_ADDR_STATUS 0xc0 /* get feature status addr */ ++#define SPINAND_ADDR_FEATURE 0xb0 /* set feature addr */ ++ ++#define SPINAND_IS_BUSY (1 << 0) /* PROGRAM EXECUTE, PAGE READ, BLOCK ERASE, or RESET command executing */ ++#define SPINAND_OP_BL_128K (128 * 1024) ++ ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_spinor.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_spinor.h.patch new file mode 100644 index 00000000..18add2b4 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_spinor.h.patch @@ -0,0 +1,121 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v1/spinor.h b/drivers/mtd/devices/ingenic_sfc_v1/spinor.h +--- a/drivers/mtd/devices/ingenic_sfc_v1/spinor.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v1/spinor.h 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,117 @@ ++#ifndef __SPINOR_H ++#define __SPINOR_H ++#include "sfc_flash.h" ++#include "spinor_cmd.h" ++ ++#define SPIFLASH_PARAMER_OFFSET 0x3c00 ++#define NOR_MAJOR_VERSION_NUMBER 2 ++#define NOR_MINOR_VERSION_NUMBER 0 ++#define NOR_REVERSION_NUMBER 0 ++#define NOR_VERSION (NOR_MAJOR_VERSION_NUMBER | (NOR_MINOR_VERSION_NUMBER << 8) | (NOR_REVERSION_NUMBER << 16)) ++ ++ ++#define SIZEOF_NAME 32 ++ ++#define NOR_MAGIC 0x726f6e //ascii "nor" ++#define NOR_PART_NUM 10 ++#define NORFLASH_PART_RW 0 ++#define NORFLASH_PART_WO 1 ++#define NORFLASH_PART_RO 2 ++ ++ ++struct spi_nor_cmd_info { ++ unsigned short cmd; ++ unsigned char dummy_byte; ++ unsigned char addr_nbyte; ++ unsigned char transfer_mode; ++ ++}; ++ ++struct spi_nor_st_info { ++ unsigned short cmd; ++ unsigned char bit_shift; ++ unsigned char mask; ++ unsigned char val; ++ unsigned char len; //length of byte to operate from register ++ unsigned char dummy; ++}; ++ ++struct spi_nor_info { ++ unsigned char name[32]; ++ unsigned int id; ++ ++ struct spi_nor_cmd_info read_standard; ++ struct spi_nor_cmd_info read_quad; ++ ++ struct spi_nor_cmd_info write_standard; ++ struct spi_nor_cmd_info write_quad; ++ ++ struct spi_nor_cmd_info sector_erase; ++ ++ struct spi_nor_cmd_info wr_en; ++ struct spi_nor_cmd_info en4byte; ++ struct spi_nor_st_info quad_set; ++ struct spi_nor_st_info quad_get; ++ struct spi_nor_st_info busy; ++ ++ unsigned short quad_ops_mode; ++ unsigned short addr_ops_mode; ++ ++ unsigned int tCHSH; //hold ++ unsigned int tSLCH; //setup ++ unsigned int tSHSL_RD; //interval ++ unsigned int tSHSL_WR; ++ ++ unsigned int chip_size; ++ unsigned int page_size; ++ unsigned int erase_size; ++ ++ unsigned char chip_erase_cmd; ++}; ++ ++struct nor_partition { ++ char name[32]; ++ uint32_t size; ++ uint32_t offset; ++ uint32_t mask_flags;//bit 0-1 mask the partiton RW mode, 0:RW 1:W 2:R ++ uint32_t manager_mode; ++}; ++ ++struct norflash_partitions { ++ struct nor_partition nor_partition[NOR_PART_NUM]; ++ uint32_t num_partition_info; ++}; ++ ++struct nor_private_data { ++ unsigned int fs_erase_size; ++ unsigned char uk_quad; ++}; ++ ++ ++struct burner_params { ++ uint32_t magic; ++ uint32_t version; ++ struct spi_nor_info spi_nor_info; ++ struct norflash_partitions norflash_partitions; ++ struct nor_private_data nor_pri_data; ++}; ++ ++struct spi_nor_flash_ops { ++ int (*set_4byte_mode)(struct sfc_flash *flash); ++ int (*set_quad_mode)(struct sfc_flash *flash); ++}; ++ ++struct spinor_flashinfo { ++ ++ int quad_succeed; ++ struct spi_nor_flash_ops *nor_flash_ops; ++ struct spi_nor_info *nor_flash_info; ++ struct spi_nor_cmd_info *cur_r_cmd; ++ struct spi_nor_cmd_info *cur_w_cmd; ++ struct norflash_partitions *norflash_partitions; ++ struct nor_private_data *nor_pri_data; ++ ++}; ++ ++#endif ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_spinor_cmd.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_spinor_cmd.h.patch new file mode 100644 index 00000000..9d1c11a9 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v1_spinor_cmd.h.patch @@ -0,0 +1,84 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v1/spinor_cmd.h b/drivers/mtd/devices/ingenic_sfc_v1/spinor_cmd.h +--- a/drivers/mtd/devices/ingenic_sfc_v1/spinor_cmd.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v1/spinor_cmd.h 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,80 @@ ++#ifndef __SPINOR_CMD_H ++#define __SPINOR_CMD_H ++ ++/* Flash opcodes. */ ++#define SPINOR_OP_RSTEN 0x66 /* reset enable */ ++#define SPINOR_OP_RST 0x99 /* reset */ ++#define SPINOR_OP_WREN 0x06 /* Write enable */ ++#define SPINOR_OP_RDSR 0x05 /* Read status register */ ++#define SPINOR_OP_RDSR_1 0x35 /* Read status1 register */ ++#define SPINOR_OP_RDSR_2 0x15 /* Read status2 register */ ++#define SPINOR_OP_WRSR 0x01 /* Write status register 1 byte */ ++#define SPINOR_OP_WRSR_1 0x31 /* Write status1 register 1 byte */ ++#define SPINOR_OP_WRSR_2 0x11 /* Write status2 register 1 byte */ ++#define SPINOR_OP_READ 0x03 /* Read data bytes (low frequency) */ ++#define SPINOR_OP_READ_FAST 0x0b /* Read data bytes (high frequency) */ ++#define SPINOR_OP_READ_1_1_2 0x3b /* Read data bytes (Dual SPI) */ ++#define SPINOR_OP_READ_1_1_4 0x6b /* Read data bytes (Quad SPI) */ ++#define SPINOR_OP_PP 0x02 /* Page program (up to 256 bytes) */ ++#define SPINOR_OP_QPP 0x32 /* Page program (up to 256 bytes) */ ++#define SPINOR_OP_BE_4K 0x20 /* Erase 4KiB block */ ++#define SPINOR_OP_BE_4K_PMC 0xd7 /* Erase 4KiB block on PMC chips */ ++#define SPINOR_OP_BE_32K 0x52 /* Erase 32KiB block */ ++#define SPINOR_OP_CHIP_ERASE 0xc7 /* Erase whole flash chip */ ++#define SPINOR_OP_SE 0xd8 /* Sector erase (usually 64KiB) */ ++#define SPINOR_OP_RDID 0x9f /* Read JEDEC ID */ ++#define SPINOR_OP_RDCR 0x35 /* Read configuration register */ ++#define SPINOR_OP_RDFSR 0x70 /* Read flag status register */ ++ ++/* 4-byte address opcodes - used on Spansion and some Macronix flashes. */ ++#define SPINOR_OP_READ4 0x13 /* Read data bytes (low frequency) */ ++#define SPINOR_OP_READ4_FAST 0x0c /* Read data bytes (high frequency) */ ++#define SPINOR_OP_READ4_1_1_2 0x3c /* Read data bytes (Dual SPI) */ ++#define SPINOR_OP_READ4_1_1_4 0x6c /* Read data bytes (Quad SPI) */ ++#define SPINOR_OP_PP_4B 0x12 /* Page program (up to 256 bytes) */ ++#define SPINOR_OP_SE_4B 0xdc /* Sector erase (usually 64KiB) */ ++ ++/* Used for SST flashes only. */ ++#define SPINOR_OP_BP 0x02 /* Byte program */ ++#define SPINOR_OP_WRDI 0x04 /* Write disable */ ++#define SPINOR_OP_AAI_WP 0xad /* Auto address increment word program */ ++ ++/* Used for Macronix and Winbond flashes. */ ++#define SPINOR_OP_EN4B 0xb7 /* Enter 4-byte mode */ ++#define SPINOR_OP_EX4B 0xe9 /* Exit 4-byte mode */ ++ ++/* Used for Spansion flashes only. */ ++#define SPINOR_OP_BRWR 0x17 /* Bank register write */ ++ ++/* Status Register bits. */ ++#define SR_WIP 1 /* Write in progress */ ++#define SR_WEL 2 /* Write enable latch */ ++#define SR_SQE (1 << 1) /* QUAD MODE enable */ ++/* meaning of other SR_* bits may differ between vendors */ ++#define SR_BP0 4 /* Block protect 0 */ ++#define SR_BP1 8 /* Block protect 1 */ ++#define SR_BP2 0x10 /* Block protect 2 */ ++#define SR_SRWD 0x80 /* SR write protect */ ++ ++#define SR_QUAD_EN_MX 0x40 /* Macronix Quad I/O */ ++ ++/* Flag Status Register bits */ ++#define FSR_READY 0x80 ++ ++/* Configuration Register bits. */ ++#define CR_QUAD_EN_SPAN 0x2 /* Spansion Quad I/O */ ++ ++ ++#define CMD_WREN 0x06 /* Write Enable */ ++#define CMD_EN4B 0xB7 ++#define CMD_EX4B 0xE9 ++/* nor cmd entry deep power down and Release from Deep Power-Down and Read Device ID */ ++#define CMD_DP (0xB9) ++#define CMD_RDP (0xAB) ++ ++ ++#define BUFFER_SIZE PAGE_SIZE ++ ++#define NOR_SIZE_16M 0x1000000 ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_Kconfig.patch new file mode 100644 index 00000000..67eda5c1 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_Kconfig.patch @@ -0,0 +1,48 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v2/Kconfig b/drivers/mtd/devices/ingenic_sfc_v2/Kconfig +--- a/drivers/mtd/devices/ingenic_sfc_v2/Kconfig 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v2/Kconfig 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,44 @@ ++config INGENIC_SFC_V2 ++ tristate "Ingenic series SFC driver v2" ++ depends on MACH_XBURST || MACH_XBURST2 ++ help ++ SFC driver version v2.0 for Ingenic series SoCs ++ ++if INGENIC_SFC_V2 ++ ++choice ++ prompt "the SFC external memory (nor or nand)" ++ help ++ Select the SFC external memory ++ ++config MTD_INGENIC_SFC_V2_NORFLASH ++ bool "Support ingenic sfc-nor" ++ depends on INGENIC_SFC_V2 ++ ++config MTD_INGENIC_SFC_V2_NANDFLASH ++ bool "Support ingenic sfc-nand" ++ depends on INGENIC_SFC_V2 ++ select MTD_NAND ++ ++endchoice ++ ++choice ++ prompt "sfc Mode" ++ help ++ Select sfc Mode ++ ++config SPI_STANDARD_MODE ++ bool "standard spi mode" ++ depends on INGENIC_SFC_V2 ++ help ++ Say Y here to enable spi standard mode ++ ++config SPI_QUAD_MODE ++ bool "quad spi mode" ++ depends on INGENIC_SFC_V2 ++ help ++ Say Y Here to enable spi QUAD MODE ++endchoice ++ ++endif ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_Makefile.patch new file mode 100644 index 00000000..ef7b4ebe --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_Makefile.patch @@ -0,0 +1,10 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v2/Makefile b/drivers/mtd/devices/ingenic_sfc_v2/Makefile +--- a/drivers/mtd/devices/ingenic_sfc_v2/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v2/Makefile 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,6 @@ ++# ++# linux/drivers/mtd/devices/ingenic_sfc_v2/Makefile ++# ++ ++obj-$(CONFIG_MTD_INGENIC_SFC_V2_NORFLASH) += ingenic_sfc_common.o ingenic_sfc_nor.o ingenic_sfc_ops.o ++obj-$(CONFIG_MTD_INGENIC_SFC_V2_NANDFLASH) += ingenic_sfc_common.o ingenic_sfc_nand.o nand_device/ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_ingenic_sfc_common.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_ingenic_sfc_common.c.patch new file mode 100644 index 00000000..66ce0f02 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_ingenic_sfc_common.c.patch @@ -0,0 +1,795 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_common.c b/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_common.c +--- a/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_common.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_common.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,791 @@ ++/* ++ * SFC controller for SPI protocol, use FIFO and DMA; ++ * ++ * Copyright (c) 2015 Ingenic ++ * Author: ++ * 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. ++ * ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include "ingenic_sfc_common.h" ++ ++ ++//#define SFC_DEBUG ++ ++#define GET_PHYADDR(a) \ ++({ \ ++ unsigned int v; \ ++ if (unlikely((unsigned int)(a) & 0x40000000)) { \ ++ v = page_to_phys(vmalloc_to_page((const void *)(a))) | ((unsigned int)(a) & ~PAGE_MASK); \ ++ } else \ ++ v = ((unsigned int)(a) & 0x1fffffff); \ ++ v; \ ++ }) ++static inline void sfc_writel(struct sfc *sfc, unsigned short offset, u32 value) ++{ ++ writel(value, sfc->iomem + offset); ++} ++ ++static inline unsigned int sfc_readl(struct sfc *sfc, unsigned short offset) ++{ ++ return readl(sfc->iomem + offset); ++} ++ ++#ifdef SFC_DEBUG ++void dump_sfc_reg(struct sfc *sfc) ++{ ++ int i = 0; ++ printk("SFC_GLB0 :%08x\n", sfc_readl(sfc, SFC_GLB0 )); ++ printk("SFC_DEV_CONF :%08x\n", sfc_readl(sfc, SFC_DEV_CONF )); ++ printk("SFC_DEV_STA_EXP :%08x\n", sfc_readl(sfc, SFC_DEV_STA_EXP)); ++ printk("SFC_DEV0_STA_RT :%08x\n", sfc_readl(sfc, SFC_DEV0_STA_RT )); ++ printk("SFC_DEV_STA_MSK :%08x\n", sfc_readl(sfc, SFC_DEV_STA_MSK )); ++ printk("SFC_TRAN_LEN :%08x\n", sfc_readl(sfc, SFC_TRAN_LEN )); ++ ++ for(i = 0; i < 6; i++) ++ printk("SFC_TRAN_CONF0(%d) :%08x\n", i,sfc_readl(sfc, SFC_TRAN_CONF0(i))); ++ for(i = 0; i < 6; i++) ++ printk("SFC_TRAN_CONF1(%d) :%08x\n", i,sfc_readl(sfc, SFC_TRAN_CONF1(i))); ++ ++ for(i = 0; i < 6; i++) ++ printk("SFC_DEV_ADDR(%d) :%08x\n", i,sfc_readl(sfc, SFC_DEV_ADDR(i))); ++ ++ printk("SFC_MEM_ADDR :%08x\n", sfc_readl(sfc, SFC_MEM_ADDR )); ++ printk("SFC_TRIG :%08x\n", sfc_readl(sfc, SFC_TRIG)); ++ printk("SFC_SR :%08x\n", sfc_readl(sfc, SFC_SR)); ++ printk("SFC_SCR :%08x\n", sfc_readl(sfc, SFC_SCR)); ++ printk("SFC_INTC :%08x\n", sfc_readl(sfc, SFC_INTC)); ++ printk("SFC_FSM :%08x\n", sfc_readl(sfc, SFC_FSM )); ++ printk("SFC_CGE :%08x\n", sfc_readl(sfc, SFC_CGE )); ++// printk("SFC_RM_DR :%08x\n", sfc_readl(spi, SFC_RM_DR)); ++} ++static void dump_reg(struct sfc *sfc) ++{ ++ printk("SFC_GLB0 = %08x\n",sfc_readl(sfc,0x0000)); ++ printk("SFC_DEV_CONF = %08x\n",sfc_readl(sfc,0x0004)); ++ printk("SFC_DEV_STA_EXP = %08x\n",sfc_readl(sfc,0x0008)); ++ printk("SFC_DEV0_STA_RT = %08x\n",sfc_readl(sfc,0x000c)); ++ printk("SFC_DEV_STA_MASK = %08x\n",sfc_readl(sfc,0x0010)); ++ printk("SFC_TRAN_CONF0 = %08x\n",sfc_readl(sfc,0x0014)); ++ printk("SFC_TRAN_LEN = %08x\n",sfc_readl(sfc,0x002c)); ++ printk("SFC_DEV_ADDR0 = %08x\n",sfc_readl(sfc,0x0030)); ++ printk("SFC_DEV_ADDR_PLUS0 = %08x\n",sfc_readl(sfc,0x0048)); ++ printk("SFC_MEM_ADDR = %08x\n",sfc_readl(sfc,0x0060)); ++ printk("SFC_TRIG = %08x\n",sfc_readl(sfc,0x0064)); ++ printk("SFC_SR = %08x\n",sfc_readl(sfc,0x0068)); ++ printk("SFC_SCR = %08x\n",sfc_readl(sfc,0x006c)); ++ printk("SFC_INTC = %08x\n",sfc_readl(sfc,0x0070)); ++ printk("SFC_FSM = %08x\n",sfc_readl(sfc,0x0074)); ++ printk("SFC_CGE = %08x\n",sfc_readl(sfc,0x0078)); ++ printk("SFC_CMD_IDX = %08x\n",sfc_readl(sfc,0x007c)); ++ printk("SFC_COL_ADDR = %08x\n", sfc_readl(sfc, 0x80)); ++ printk("SFC_ROW_ADDR = %08x\n", sfc_readl(sfc, 0x84)); ++ printk("SFC_STA_ADDR0 = %08x\n", sfc_readl(sfc, 0x88)); ++ printk("SFC_DES_ADDR = %08x\n", sfc_readl(sfc, 0x90)); ++ printk("SFC_GLB1 = %08x\n", sfc_readl(sfc, 0x94)); ++ printk("SFC_DEV1_STA_RT = %08x\n", sfc_readl(sfc, 0x98)); ++ printk("SFC_TRAN_CONF1 = %08x\n", sfc_readl(sfc, 0x9c)); ++ printk("SFC_CDT = %08x\n", sfc_readl(sfc, 0x800)); ++// printk("SFC_DR = %08x\n",sfc_readl(sfc,0x1000)); ++} ++ ++void dump_cdt(struct sfc *sfc) ++{ ++ struct sfc_cdt *cdt; ++ int i; ++ ++ if(sfc->iomem == NULL){ ++ printk("%s error: sfc res not init !\n", __func__); ++ return; ++ } ++ ++ cdt = sfc->iomem + 0x800; ++ ++ for(i = 0; i < 32; i++){ ++ printk("\nnum------->%d\n", i); ++ printk("link:%02x, ENDIAN:%02x, WORD_UINT:%02x, TRAN_MODE:%02x, ADDR_KIND:%02x\n", ++ (cdt[i].link >> 31) & 0x1, (cdt[i].link >> 18) & 0x1, ++ (cdt[i].link >> 16) & 0x3, (cdt[i].link >> 4) & 0xf, ++ (cdt[i].link >> 0) & 0x3 ++ ); ++ printk("CLK_MODE:%02x, ADDR_WIDTH:%02x, POLL_EN:%02x, CMD_EN:%02x,PHASE_FORMAT:%02x, DMY_BITS:%02x, DATA_EN:%02x, TRAN_CMD:%04x\n", ++ (cdt[i].xfer >> 29) & 0x7, (cdt[i].xfer >> 26) & 0x7, ++ (cdt[i].xfer >> 25) & 0x1, (cdt[i].xfer >> 24) & 0x1, ++ (cdt[i].xfer >> 23) & 0x1, (cdt[i].xfer >> 17) & 0x3f, ++ (cdt[i].xfer >> 16) & 0x1, (cdt[i].xfer >> 0) & 0xffff ++ ); ++ printk("DEV_STA_EXP:%08x\n", cdt[i].staExp); ++ printk("DEV_STA_MSK:%08x\n", cdt[i].staMsk); ++ } ++} ++ ++void dump_desc(struct sfc *sfc, uint32_t desc_num) ++{ ++ struct sfc_desc *desc = sfc->desc; ++ int i = 0; ++ ++ for(; i <= desc_num; i++){ ++ printk("\nDMA Descriptor ---->num: %d, addr: 0x%08x\n", i, (unsigned int)virt_to_phys(&desc[i])); ++ printk("next_desc_addr: 0x%08x\n", desc[i].next_des_addr); ++ printk("mem_addr: 0x%08x\n", desc[i].mem_addr); ++ printk("tran_len: %d\n", desc[i].tran_len); ++ printk("link: %d\n\n", desc[i].link); ++ } ++} ++ ++#endif ++ ++static int32_t sfc_stop(struct sfc *sfc) ++{ ++ int32_t timeout = 0xffff; ++ sfc_writel(sfc, SFC_TRIG, TRIG_STOP); ++ ++ while((sfc_readl(sfc, SFC_SR) & SFC_BUSY) && timeout--); ++ if(timeout < 0) ++ return -EIO; ++ return 0; ++} ++ ++static inline void sfc_init(struct sfc *sfc) ++{ ++ sfc_writel(sfc, SFC_TRIG, TRIG_STOP); ++ sfc_writel(sfc, SFC_DEV_CONF, 0); ++ ++ /* X1000 need set to 0,but X2000 can be set to 1*/ ++ sfc_writel(sfc, SFC_CGE, 0); ++ ++} ++ ++static inline void sfc_start(struct sfc *sfc) ++{ ++ uint32_t tmp; ++ tmp = sfc_readl(sfc, SFC_TRIG); ++ tmp |= TRIG_START; ++ sfc_writel(sfc, SFC_TRIG, tmp); ++} ++ ++static inline void sfc_flush_fifo(struct sfc *sfc) ++{ ++ unsigned int tmp; ++ tmp = sfc_readl(sfc, SFC_TRIG); ++ tmp |= TRIG_FLUSH; ++ sfc_writel(sfc, SFC_TRIG, tmp); ++} ++static inline void sfc_clear_end_intc(struct sfc *sfc) ++{ ++ sfc_writel(sfc, SFC_SCR, CLR_END); ++} ++ ++static inline void sfc_clear_treq_intc(struct sfc *sfc) ++{ ++ sfc_writel(sfc, SFC_SCR, CLR_TREQ); ++} ++ ++static inline void sfc_clear_rreq_intc(struct sfc *sfc) ++{ ++ sfc_writel(sfc, SFC_SCR, CLR_RREQ); ++} ++ ++static inline void sfc_clear_over_intc(struct sfc *sfc) ++{ ++ sfc_writel(sfc, SFC_SCR, CLR_OVER); ++} ++ ++static inline void sfc_clear_under_intc(struct sfc *sfc) ++{ ++ sfc_writel(sfc, SFC_SCR, CLR_UNDER); ++} ++ ++static inline void sfc_clear_all_intc(struct sfc *sfc) ++{ ++ sfc_writel(sfc, SFC_SCR, 0x1f); ++} ++ ++static inline void sfc_mask_all_intc(struct sfc *sfc) ++{ ++ sfc_writel(sfc, SFC_INTC, 0x1f); ++} ++ ++static void sfc_dev_hw_init(struct sfc *sfc) ++{ ++ uint32_t tmp; ++ tmp = sfc_readl(sfc, SFC_DEV_CONF); ++ ++ /*cpha bit:0 , cpol bit:0 */ ++ tmp &= ~(DEV_CONF_CPHA | DEV_CONF_CPOL); ++ /*ce_dl bit:1, hold bit:1,wp bit:1*/ ++ tmp |= (DEV_CONF_CEDL | DEV_CONF_HOLDDL | DEV_CONF_WPDL); ++ sfc_writel(sfc, SFC_DEV_CONF, tmp); ++ ++ /* use CDT mode */ ++ printk("Enter 'CDT' mode.\n"); ++ tmp = sfc_readl(sfc, SFC_GLB0); ++ tmp |= GLB0_CDT_EN; ++ sfc_writel(sfc, SFC_GLB0, tmp); ++ ++ /* use DMA Descriptor chain mode */ ++ printk("Enter 'DMA Descriptor chain' mode.\n"); ++ tmp = sfc_readl(sfc, SFC_GLB0); ++ tmp |= GLB0_DES_EN; ++ sfc_writel(sfc, SFC_GLB0, tmp); ++} ++ ++static void sfc_threshold(struct sfc *sfc, uint32_t value) ++{ ++ uint32_t tmp = sfc_readl(sfc, SFC_GLB0); ++ tmp &= ~GLB0_THRESHOLD_MSK; ++ tmp |= value << GLB0_THRESHOLD_OFFSET; ++ sfc_writel(sfc, SFC_GLB0, tmp); ++} ++ ++static void sfc_smp_delay(struct sfc *sfc, uint32_t value) ++{ ++ uint32_t tmp; ++ tmp = sfc_readl(sfc, SFC_DEV_CONF); ++ tmp &= ~DEV_CONF_SMP_DELAY_MSK; ++ tmp |= value << DEV_CONF_SMP_DELAY_OFFSET; ++ sfc_writel(sfc, SFC_DEV_CONF, tmp); ++} ++ ++int32_t set_flash_timing(struct sfc *sfc, uint32_t t_hold, uint32_t t_setup, uint32_t t_shslrd, uint32_t t_shslwr) ++{ ++ uint32_t c_hold = 0; ++ uint32_t c_setup = 0; ++ uint32_t t_in = 0, c_in = 0; ++ uint32_t tmp; ++ unsigned long cycle; ++ unsigned long long ns; ++ ++ ns = 1000000000ULL; ++ cycle = do_div(ns, sfc->src_clk); ++ cycle = ns; ++ ++ tmp = sfc_readl(sfc, SFC_DEV_CONF); ++ tmp &= ~(DEV_CONF_THOLD_MSK | DEV_CONF_TSETUP_MSK | DEV_CONF_TSH_MSK); ++ ++ c_hold = t_hold / cycle; ++ if(c_hold > 0) ++ c_hold -= 1; ++ ++ c_setup = t_setup / cycle; ++ if(c_setup > 0) ++ c_setup -= 1; ++ ++ t_in = max(t_shslrd, t_shslwr); ++ c_in = t_in / cycle; ++ if(c_in > 0) ++ c_in -= 1; ++ ++ tmp |= (c_hold << DEV_CONF_THOLD_OFFSET) | \ ++ (c_setup << DEV_CONF_TSETUP_OFFSET) | \ ++ (c_in << DEV_CONF_TSH_OFFSET); ++ ++ sfc_writel(sfc, SFC_DEV_CONF, tmp); ++ return 0; ++} ++ ++static void sfc_set_length(struct sfc *sfc, uint32_t value) ++{ ++ sfc_writel(sfc, SFC_TRAN_LEN, value); ++} ++ ++static inline void sfc_transfer_mode(struct sfc *sfc, uint32_t value) ++{ ++ uint32_t tmp; ++ tmp = sfc_readl(sfc, SFC_GLB0); ++ if(value == 0) ++ tmp &= ~GLB0_OP_MODE; ++ else ++ tmp |= GLB0_OP_MODE; ++ sfc_writel(sfc, SFC_GLB0, tmp); ++} ++ ++static void sfc_read_data(struct sfc *sfc, uint32_t *value) ++{ ++ *value = sfc_readl(sfc, SFC_RM_DR); ++} ++ ++static void sfc_write_data(struct sfc *sfc, uint32_t value) ++{ ++ sfc_writel(sfc, SFC_RM_DR, value); ++} ++ ++static void cpu_read_rxfifo(struct sfc *sfc, struct sfc_cdt_xfer *xfer) ++{ ++ int32_t i = 0; ++ uint32_t align_len = 0; ++ uint32_t fifo_num = 0; ++ uint32_t last_word = 0; ++ uint32_t unalign_data; ++ uint8_t *c; ++ ++ align_len = ALIGN(xfer->config.datalen, 4); ++ ++ if(((align_len - xfer->config.cur_len) / 4) > sfc->threshold) { ++ fifo_num = sfc->threshold; ++ last_word = 0; ++ } else { ++ /* last aligned THRESHOLD data*/ ++ if(xfer->config.datalen % 4) { ++ fifo_num = (align_len - xfer->config.cur_len) / 4 - 1; ++ last_word = 1; ++ } else { ++ fifo_num = (align_len - xfer->config.cur_len) / 4; ++ last_word = 0; ++ } ++ } ++ ++ if ((uint32_t)xfer->config.buf & 0x3) { ++ /* addr not align */ ++ for (i = 0; i < fifo_num; i++) { ++ sfc_read_data(sfc, &unalign_data); ++ c = xfer->config.buf; ++ c[0] = (unalign_data >> 0) & 0xff; ++ c[1] = (unalign_data >> 8) & 0xff; ++ c[2] = (unalign_data >> 16) & 0xff; ++ c[3] = (unalign_data >> 24) & 0xff; ++ ++ xfer->config.buf += 4; ++ xfer->config.cur_len += 4; ++ } ++ } else { ++ /* addr align */ ++ for (i = 0; i < fifo_num; i++) { ++ sfc_read_data(sfc, (uint32_t *)xfer->config.buf); ++ xfer->config.buf += 4; ++ xfer->config.cur_len += 4; ++ } ++ } ++ ++ /* last word */ ++ if(last_word == 1) { ++ sfc_read_data(sfc, &unalign_data); ++ c = (uint8_t *)xfer->config.buf; ++ ++ for(i = 0; i < xfer->config.datalen % 4; i++) { ++ c[i] = (unalign_data >> (i * 8)) & 0xff; ++ } ++ ++ xfer->config.buf += xfer->config.datalen % 4; ++ xfer->config.cur_len += xfer->config.datalen % 4; ++ } ++ ++} ++ ++static void cpu_write_txfifo(struct sfc *sfc, struct sfc_cdt_xfer *xfer) ++{ ++ uint32_t align_len = 0; ++ uint32_t fifo_num = 0; ++ uint32_t data = 0; ++ uint32_t i; ++ uint32_t nbytes = xfer->config.datalen % 4; ++ ++ align_len = xfer->config.datalen / 4 * 4; ++ ++ if (((align_len - xfer->config.cur_len) / 4) >= sfc->threshold) { ++ fifo_num = sfc->threshold; ++ nbytes = 0; ++ } else { ++ fifo_num = (align_len - xfer->config.cur_len) / 4; ++ } ++ ++ if ((uint32_t)xfer->config.buf & 0x3) { ++ /* addr not align */ ++ for(i = 0; i < fifo_num; i++) { ++ data = xfer->config.buf[3] << 24 | xfer->config.buf[2] << 16 | xfer->config.buf[1] << 8 | xfer->config.buf[0]; ++ sfc_write_data(sfc, data); ++ xfer->config.buf += 4; ++ xfer->config.cur_len += 4; ++ } ++ } else { ++ /* addr align */ ++ for(i = 0; i < fifo_num; i++) { ++ sfc_write_data(sfc, *(uint32_t *)xfer->config.buf); ++ xfer->config.buf += 4; ++ xfer->config.cur_len += 4; ++ } ++ } ++ ++ if(nbytes) { ++ data = 0; ++ for(i = 0; i < nbytes; i++) ++ data |= xfer->config.buf[i] << i * 8; ++ sfc_write_data(sfc, data); ++ xfer->config.cur_len += nbytes; ++ } ++ ++} ++ ++uint32_t sfc_get_sta_rt0(struct sfc *sfc) ++{ ++ return sfc_readl(sfc, SFC_DEV0_STA_RT); ++} ++ ++ ++static void sfc_enable_all_intc(struct sfc *sfc) ++{ ++ sfc_writel(sfc, SFC_INTC, 0); ++} ++ ++static void sfc_set_mem_addr(struct sfc *sfc, unsigned int addr) ++{ ++ sfc_writel(sfc, SFC_MEM_ADDR, addr); ++} ++ ++static void sfc_set_desc_addr(struct sfc *sfc, unsigned int addr) ++{ ++ sfc_writel(sfc, SFC_DES_ADDR, addr); ++} ++ ++void *sfc_get_paddr(void *vaddr) ++{ ++ unsigned long paddr; ++ unsigned int pfn = 0; ++ unsigned int page_offset = 0; ++ ++ if (is_vmalloc_addr(vaddr)) { ++ pfn = vmalloc_to_pfn(vaddr); ++ page_offset = (unsigned int)vaddr & (PAGE_SIZE - 1); ++ paddr = (pfn << 12) + page_offset; ++ } else { ++ paddr = virt_to_phys(vaddr); ++ } ++ ++ return (void *)paddr; ++} ++ ++int32_t create_sfc_desc(struct sfc_flash *flash, unsigned char *vaddr, size_t len) ++{ ++ struct sfc *sfc = flash->sfc; ++ struct sfc_desc *desc = sfc->desc; ++ uint32_t ualign_size, off_len, last_len, step_len, page_num; ++ int current_pfn = 0, next_pfn = 0; ++ uint32_t i = 0; ++ ++ ualign_size = (unsigned int)vaddr & (PAGE_SIZE - 1); ++ off_len = PAGE_SIZE - ualign_size; ++ ++ if(is_vmalloc_addr(vaddr) && (len > off_len)){ ++ page_num = (len - off_len) >> (ffs(PAGE_SIZE) - 1); ++ last_len = (len - off_len) & (PAGE_SIZE - 1); ++ current_pfn = vmalloc_to_pfn(vaddr); ++ ++ desc[i].next_des_addr = 0; ++ desc[i].mem_addr = (unsigned int)sfc_get_paddr((void *)vaddr); ++ desc[i].tran_len = off_len; ++ desc[i].link = 1; ++ ++ vaddr += off_len; ++ step_len = PAGE_SIZE; ++ ++ /* case 1. Handle physical address discontinuity */ ++ do{ ++ if(!page_num){ ++ if(last_len) ++ step_len = last_len; ++ else{ ++ break; ++ } ++ } ++ ++ next_pfn = vmalloc_to_pfn(vaddr); ++ if((current_pfn + 1) != next_pfn){ ++ if(++i > (sfc->desc_max_num - 1)){ ++ dev_err(flash->dev, "%s The number of descriptors exceeds the maximum limit.\n", __func__); ++ return -ENOMEM; ++ } ++ ++ desc[i-1].next_des_addr = (unsigned int)sfc_get_paddr((void *)&desc[i]); ++ ++ desc[i].next_des_addr = 0; ++ desc[i].mem_addr = (unsigned int)sfc_get_paddr((void *)vaddr); ++ desc[i].tran_len = step_len; ++ desc[i].link = 1; ++ }else{ ++ desc[i].tran_len += step_len; ++ } ++ ++ ++ if(page_num){ ++ current_pfn = next_pfn; ++ vaddr += step_len; ++ } ++ }while(page_num--); ++ }else{ ++ /* case 2. Physical Address Continuity and only need one descriptor */ ++ desc[i].next_des_addr = 0; ++ desc[i].mem_addr = (unsigned int)sfc_get_paddr((void *)vaddr); ++ desc[i].tran_len = len; ++ } ++ ++ /* last descriptor is not link */ ++ desc[i].link = 0; ++ ++ return i; ++} ++ ++#define SFC_TRANSFER_TIMEOUT 3000 //3000ms for timeout ++static int32_t sfc_start_transfer(struct sfc *sfc) ++{ ++ int32_t err; ++ sfc_clear_all_intc(sfc); ++ sfc_enable_all_intc(sfc); ++ sfc_start(sfc); ++ err = wait_for_completion_timeout(&sfc->done, msecs_to_jiffies(SFC_TRANSFER_TIMEOUT)); ++ if (!err) { ++ sfc_mask_all_intc(sfc); ++ sfc_clear_all_intc(sfc); ++ sfc_stop(sfc); ++ sfc_flush_fifo(sfc); ++ printk("line:%d Timeout for ACK from SFC device\n",__LINE__); ++ return -ETIMEDOUT; ++ } ++ return 0; ++} ++ ++void write_cdt(struct sfc *sfc, struct sfc_cdt *cdt, uint16_t start_index, uint16_t end_index) ++{ ++ uint32_t cdt_num, cdt_size; ++ ++ cdt_num = end_index - start_index + 1; ++ cdt_size = sizeof(struct sfc_cdt); ++ ++ memcpy((void *)sfc->iomem + SFC_CDT + (start_index * cdt_size), (void *)cdt + (start_index * cdt_size), cdt_num * cdt_size); ++ //printk("create CDT index: %d ~ %d, index number:%d.\n", start_index, end_index, cdt_num); ++} ++ ++static void sfc_set_index(struct sfc *sfc, unsigned short index) ++{ ++ ++ uint32_t tmp = sfc_readl(sfc, SFC_CMD_IDX); ++ tmp &= ~CMD_IDX_MSK; ++ tmp |= index; ++ sfc_writel(sfc, SFC_CMD_IDX, tmp); ++} ++ ++static void sfc_set_dataen(struct sfc *sfc, uint8_t dataen) ++{ ++ ++ uint32_t tmp = sfc_readl(sfc, SFC_CMD_IDX); ++ tmp &= ~CDT_DATAEN_MSK; ++ tmp |= (dataen << CDT_DATAEN_OFF); ++ sfc_writel(sfc, SFC_CMD_IDX, tmp); ++} ++ ++static void sfc_set_datadir(struct sfc *sfc, uint8_t datadir) ++{ ++ ++ uint32_t tmp = sfc_readl(sfc, SFC_CMD_IDX); ++ tmp &= ~CDT_DIR_MSK; ++ tmp |= (datadir << CDT_DIR_OFF); ++ sfc_writel(sfc, SFC_CMD_IDX, tmp); ++} ++ ++ ++int sfc_sync_cdt(struct sfc *sfc, struct sfc_cdt_xfer *xfer) ++{ ++ /*0.reset transfer length*/ ++ sfc_set_length(sfc, 0); ++ ++ /*1. set index*/ ++ sfc_set_index(sfc, xfer->cmd_index); ++ ++ /*2. set addr*/ ++ sfc_writel(sfc, SFC_COL_ADDR, xfer->columnaddr); ++ sfc_writel(sfc, SFC_ROW_ADDR, xfer->rowaddr); ++ sfc_writel(sfc, SFC_STA_ADDR0, xfer->staaddr0); ++ sfc_writel(sfc, SFC_STA_ADDR1, xfer->staaddr1); ++ ++ /*3. config data*/ ++ sfc_set_dataen(sfc, xfer->dataen); ++ if(xfer->dataen){ ++ sfc_set_datadir(sfc, xfer->config.data_dir); ++ sfc_transfer_mode(sfc, xfer->config.ops_mode); ++ sfc_set_length(sfc, xfer->config.datalen); ++ ++ /* Memory address for DMA when do not use DMA descriptor */ ++ sfc_set_mem_addr(sfc, 0); ++ ++ if(xfer->config.ops_mode == DMA_OPS){ ++ if(xfer->config.data_dir == GLB0_TRAN_DIR_READ){ ++ dma_cache_sync(NULL, (void *)xfer->config.buf, xfer->config.datalen, DMA_FROM_DEVICE); ++ }else{ ++ dma_cache_sync(NULL, (void *)xfer->config.buf, xfer->config.datalen, DMA_TO_DEVICE); ++ } ++ /* Set Descriptor address for DMA */ ++ sfc_set_desc_addr(sfc, virt_to_phys(sfc->desc)); ++ } ++ sfc->xfer = xfer; ++ } ++ ++ return sfc_start_transfer(sfc); ++ ++} ++ ++static irqreturn_t ingenic_sfc_pio_irq_callback(int32_t irq, void *dev) ++{ ++ struct sfc *sfc = dev; ++ uint32_t val; ++ ++ val = sfc_readl(sfc, SFC_SR) & 0x1f; ++ ++ if(val & CLR_RREQ) { ++ sfc_clear_rreq_intc(sfc); ++ cpu_read_rxfifo(sfc, sfc->xfer); ++ } else if(val & CLR_TREQ) { ++ sfc_clear_treq_intc(sfc); ++ cpu_write_txfifo(sfc, sfc->xfer); ++ } else if(val & CLR_OVER) { ++ sfc_clear_over_intc(sfc); ++ pr_err("sfc OVER !\n"); ++ complete(&sfc->done); ++ } else if(val & CLR_UNDER) { ++ sfc_clear_under_intc(sfc); ++ pr_err("sfc UNDR !\n"); ++ complete(&sfc->done); ++ } else if(val & CLR_END) { ++ sfc_mask_all_intc(sfc); ++ sfc_clear_end_intc(sfc); ++ complete(&sfc->done); ++ } ++ return IRQ_HANDLED; ++} ++ ++static void ingenic_sfc_init_setup(struct sfc *sfc) ++{ ++ sfc_init(sfc); ++ sfc_threshold(sfc, sfc->threshold); ++ sfc_dev_hw_init(sfc); ++ ++ sfc_transfer_mode(sfc, SLAVE_MODE); ++ if(sfc->src_clk >= 100000000){ ++ sfc_smp_delay(sfc, DEV_CONF_SMP_DELAY_180); ++ } ++} ++ ++struct sfc *sfc_res_init(struct platform_device *pdev) ++{ ++ struct device_node* np = pdev->dev.of_node; ++ struct ingenic_sfc_info *board_info; ++ struct sfc *sfc; ++ struct resource *res; ++ int32_t err = 0; ++ ++ board_info = devm_kzalloc(&pdev->dev, sizeof(struct ingenic_sfc_info), GFP_KERNEL); ++ if(!board_info){ ++ printk("ERROR: %s %d devm_kzalloc() error !\n",__func__,__LINE__); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ sfc = devm_kzalloc(&pdev->dev, sizeof(struct sfc), GFP_KERNEL); ++ if (!sfc) { ++ printk("ERROR: %s %d devm_kzalloc() error !\n",__func__,__LINE__); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ err = of_property_read_u32(np, "ingenic,sfc-max-frequency", (unsigned int *)&sfc->src_clk); ++ if (err < 0) { ++ dev_err(&pdev->dev, "Cannot get sfc max frequency\n"); ++ return ERR_PTR(-ENOENT); ++ } ++ ++ err = of_property_read_u32(np, "ingenic,spiflash_param_offset", (unsigned int *)&board_info->param_offset); ++ if (err < 0) { ++ dev_err(&pdev->dev, "No dts param_offset, use default.\n"); ++ board_info->param_offset = -EINVAL; ++ } ++ ++ err = of_property_read_u8(np, "ingenic,use_board_info", &board_info->use_board_info); ++ if (err < 0) { ++ dev_err(&pdev->dev, "Cannot get sfc use_board_info\n"); ++ return ERR_PTR(-ENOENT); ++ } ++ ++ err = platform_device_add_data(pdev, board_info, sizeof(struct ingenic_sfc_info)); ++ if(err){ ++ printk("ERROR: %s %d error !\n",__func__,__LINE__); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ /* find and map our resources */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (res == NULL) { ++ dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n"); ++ return ERR_PTR(-ENOENT); ++ } ++ ++ sfc->iomem = devm_ioremap_resource(&pdev->dev, res); ++ if (sfc->iomem == NULL) { ++ dev_err(&pdev->dev, "Cannot map IO\n"); ++ return ERR_PTR(-ENXIO); ++ } ++ ++#ifndef FPGA_TEST ++ sfc->clk = devm_clk_get(&pdev->dev, "div_sfc"); ++ if (IS_ERR(sfc->clk)) { ++ dev_err(&pdev->dev, "Cannot get div_sfc clock\n"); ++ return ERR_PTR(-ENOENT); ++ } ++ ++ sfc->clk_gate = devm_clk_get(&pdev->dev, "gate_sfc"); ++ if (IS_ERR(sfc->clk_gate)) { ++ dev_err(&pdev->dev, "Cannot get sfc clock\n"); ++ return ERR_PTR(-ENOENT); ++ } ++ ++ clk_set_rate(sfc->clk, sfc->src_clk); ++ if(clk_prepare_enable(sfc->clk)) { ++ dev_err(&pdev->dev, "cgu clk error\n"); ++ return ERR_PTR(-ENOENT); ++ } ++ if(clk_prepare_enable(sfc->clk_gate)) { ++ dev_err(&pdev->dev, "gate clk error\n"); ++ return ERR_PTR(-ENOENT); ++ } ++#endif ++ ++ sfc->threshold = THRESHOLD; ++ ++ /* request SFC irq */ ++ sfc->irq = platform_get_irq(pdev, 0); ++ if (sfc->irq < 0) { ++ dev_err(&pdev->dev, "No IRQ specified\n"); ++ return ERR_PTR(-ENOENT); ++ } ++ ++ err = devm_request_irq(&pdev->dev, sfc->irq, ingenic_sfc_pio_irq_callback, 0, pdev->name, sfc); ++ if (err) { ++ dev_err(&pdev->dev, "Cannot claim IRQ\n"); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ /* SFC controller initializations for SFC */ ++ ingenic_sfc_init_setup(sfc); ++ init_completion(&sfc->done); ++ return sfc; ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_ingenic_sfc_common.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_ingenic_sfc_common.h.patch new file mode 100644 index 00000000..f13b5f37 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_ingenic_sfc_common.h.patch @@ -0,0 +1,33 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_common.h b/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_common.h +--- a/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_common.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_common.h 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,29 @@ ++#ifndef ingenic_SFC_COMMON_H ++#define ingenic_SFC_COMMON_H ++#include ++#include ++#include ++#include ++#include ++#include "sfc.h" ++#include "sfc_flash.h" ++ ++ ++void dump_sfc_reg(struct sfc *sfc); ++void dump_cdt(struct sfc *sfc); ++void dump_desc(struct sfc *sfc, uint32_t desc_num); ++ ++void *sfc_get_paddr(void *); ++int32_t create_sfc_desc(struct sfc_flash *, unsigned char *, size_t); ++int sfc_sync_cdt(struct sfc *sfc, struct sfc_cdt_xfer *xfer); ++struct sfc *sfc_res_init(struct platform_device *); ++void sfc_res_deinit(struct sfc *sfc); ++uint32_t sfc_get_sta_rt(struct sfc *); ++void write_cdt(struct sfc *sfc, struct sfc_cdt *cdt, uint16_t start_index, uint16_t end_index); ++ ++int32_t set_flash_timing(struct sfc *, uint32_t, uint32_t, uint32_t, uint32_t); ++ ++int32_t sfc_nor_get_special_ops(struct sfc_flash *); ++ ++#endif ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_ingenic_sfc_nand.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_ingenic_sfc_nand.c.patch new file mode 100644 index 00000000..95571372 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_ingenic_sfc_nand.c.patch @@ -0,0 +1,1136 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_nand.c b/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_nand.c +--- a/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_nand.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_nand.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,1132 @@ ++/* ++ * SFC controller for SPI protocol, use FIFO and DMA; ++ * ++ * Copyright (c) 2015 Ingenic ++ * Author: ++ * 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. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "sfc_flash.h" ++#include "spinand.h" ++#include "ingenic_sfc_common.h" ++#include "./nand_device/nand_common.h" ++ ++ ++#define STATUS_SUSPND (1<<0) ++#define to_ingenic_spi_nand(mtd_info) container_of(mtd_info, struct sfc_flash, mtd) ++ ++/* ++ * below is the informtion about nand ++ * that user should modify according to nand spec ++ * */ ++ ++static LIST_HEAD(nand_list); ++ ++void dump_flash_info(struct sfc_flash *flash) ++{ ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ struct ingenic_sfcnand_base_param *param = &nand_info->param; ++ struct mtd_partition *partition = nand_info->partition.partition; ++ uint8_t num_partition = nand_info->partition.num_partition; ++ ++ printk("id_manufactory = 0x%02x\n", nand_info->id_manufactory); ++ printk("id_device = 0x%02x\n", nand_info->id_device); ++ ++ printk("pagesize = %d\n", param->pagesize); ++ printk("blocksize = %d\n", param->blocksize); ++ printk("oobsize = %d\n", param->oobsize); ++ printk("flashsize = %d\n", param->flashsize); ++ ++ printk("tHOLD = %d\n", param->tHOLD); ++ printk("tSETUP = %d\n", param->tSETUP); ++ printk("tSHSL_R = %d\n", param->tSHSL_R); ++ printk("tSHSL_W = %d\n", param->tSHSL_W); ++ ++ printk("ecc_max = %d\n", param->ecc_max); ++ printk("need_quad = %d\n", param->need_quad); ++ ++ while(num_partition--) { ++ printk("partition(%d) name=%s\n", num_partition, partition[num_partition].name); ++ printk("partition(%d) size = 0x%llx\n", num_partition, partition[num_partition].size); ++ printk("partition(%d) offset = 0x%llx\n", num_partition, partition[num_partition].offset); ++ printk("partition(%d) mask_flags = 0x%x\n", num_partition, partition[num_partition].mask_flags); ++ } ++ return; ++} ++ ++static int32_t ingenic_sfc_nand_read(struct sfc_flash *flash, int32_t pageaddr, int32_t columnaddr, u_char *buffer, size_t len) ++{ ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ struct ingenic_sfcnand_ops *ops = nand_info->ops; ++ struct sfc_cdt_xfer xfer; ++ int32_t ret = 0; ++ ++ memset(&xfer, 0, sizeof(xfer)); ++ ++ /* set Index */ ++ if(nand_info->param.need_quad){ ++ xfer.cmd_index = NAND_QUAD_READ_TO_CACHE; ++ }else{ ++ xfer.cmd_index = NAND_STANDARD_READ_TO_CACHE; ++ } ++ ++ /* set addr */ ++ xfer.rowaddr = pageaddr; ++ ++ if(nand_info->param.plane_select){ ++ xfer.columnaddr = CONVERT_COL_ADDR(pageaddr, columnaddr); ++ }else{ ++ xfer.columnaddr = columnaddr; ++ } ++ ++ xfer.staaddr0 = SPINAND_ADDR_STATUS; ++ ++ /* set transfer config */ ++ xfer.dataen = ENABLE; ++ xfer.config.datalen = len; ++ xfer.config.data_dir = GLB0_TRAN_DIR_READ; ++ xfer.config.ops_mode = DMA_OPS; ++ xfer.config.buf = buffer; ++ ++ if(sfc_sync_cdt(flash->sfc, &xfer)) { ++ dev_err(flash->dev,"sfc_sync_cdt error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ /* get status to check nand ecc status */ ++ ret = ops->get_feature(flash, GET_ECC_STATUS); ++ ++ if(xfer.config.ops_mode == DMA_OPS) ++ dma_cache_sync(NULL, (void *)xfer.config.buf, xfer.config.datalen, DMA_FROM_DEVICE); ++ ++ return ret; ++} ++ ++static int badblk_check(int len, unsigned char *buf) ++{ ++ int j; ++ unsigned char *check_buf = buf; ++ ++ for(j = 0; j < len; j++){ ++ if(check_buf[j] != 0xff){ ++ return 1; ++ } ++ } ++ return 0; ++} ++ ++static int32_t ingenic_sfc_nand_write(struct sfc_flash *flash, u_char *buffer, uint32_t pageaddr, uint32_t columnaddr, size_t len) ++{ ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ struct ingenic_sfcnand_ops *ops = nand_info->ops; ++ struct sfc_cdt_xfer xfer; ++ int32_t ret = 0; ++ ++ memset(&xfer, 0, sizeof(xfer)); ++ ++ /* set Index */ ++ if(nand_info->param.need_quad){ ++ xfer.cmd_index = NAND_QUAD_WRITE_ENABLE; ++ }else{ ++ xfer.cmd_index = NAND_STANDARD_WRITE_ENABLE; ++ } ++ ++ /* set addr */ ++ xfer.rowaddr = pageaddr; ++ ++ if(nand_info->param.plane_select){ ++ xfer.columnaddr = CONVERT_COL_ADDR(pageaddr, columnaddr); ++ }else{ ++ xfer.columnaddr = columnaddr; ++ } ++ ++ xfer.staaddr0 = SPINAND_ADDR_STATUS; ++ ++ /* set transfer config */ ++ xfer.dataen = ENABLE; ++ xfer.config.datalen = len; ++ xfer.config.data_dir = GLB0_TRAN_DIR_WRITE; ++ xfer.config.ops_mode = DMA_OPS; ++ xfer.config.buf = buffer; ++ ++ if(sfc_sync_cdt(flash->sfc, &xfer)) { ++ dev_err(flash->dev,"sfc_sync_cdt error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ /* get status to be sure nand write completed */ ++ ret = ops->get_feature(flash, GET_WRITE_STATUS); ++ ++ return ret; ++} ++ ++static int ingenic_sfcnand_write_oob(struct mtd_info *mtd, loff_t addr, struct mtd_oob_ops *ops) ++{ ++ struct sfc_flash *flash = to_ingenic_spi_nand(mtd); ++ uint32_t oob_addr = (uint32_t)addr; ++ int32_t ret; ++ ++ mutex_lock(&flash->lock); ++ if(ops->datbuf && ops->len) ++ { ++ /* create DMA Descriptors */ ++ ret = create_sfc_desc(flash, ops->datbuf, ops->len); ++ if(ret < 0){ ++ dev_err(flash->dev, "%s create descriptors error. -%d\n", __func__, ret); ++ goto write_oob_exit; ++ } ++ ++ if((ret = ingenic_sfc_nand_write(flash, ops->datbuf, oob_addr / mtd->writesize, oob_addr % mtd->writesize, ops->len))) { ++ dev_err(flash->dev, "spi nand write oob error %s %s %d \n",__FILE__,__func__,__LINE__); ++ goto write_oob_exit; ++ } ++ } ++ ++ if(ops->oobbuf && ops->ooblen) ++ { ++ /* create DMA Descriptors */ ++ ret = create_sfc_desc(flash, ops->oobbuf, ops->ooblen); ++ if(ret < 0){ ++ dev_err(flash->dev, "%s create descriptors error. -%d\n", __func__, ret); ++ goto write_oob_exit; ++ } ++ ++ if((ret = ingenic_sfc_nand_write(flash, ops->oobbuf, oob_addr / mtd->writesize, mtd->writesize, ops->ooblen))) { ++ dev_err(flash->dev, "spi nand write oob error %s %s %d \n",__FILE__,__func__,__LINE__); ++ goto write_oob_exit; ++ } ++ } ++ ops->retlen = ops->len; ++ ops->oobretlen = ops->ooblen; ++write_oob_exit: ++ mutex_unlock(&flash->lock); ++ return ret; ++} ++ ++static int ingenic_sfcnand_chip_block_markbad(struct mtd_info *mtd, loff_t ofs) ++{ ++ struct nand_chip *chip = mtd->priv; ++ uint8_t buf[2] = { 0, 0 }; ++ int ret = 0, i = 0; ++ int write_oob = !(chip->bbt_options & NAND_BBT_NO_OOB_BBM); ++ ++ /* Write bad block marker to OOB */ ++ if (write_oob) { ++ struct mtd_oob_ops ops; ++ loff_t wr_ofs = ofs; ++ ops.datbuf = NULL; ++ ops.oobbuf = buf; ++ ops.ooboffs = chip->badblockpos; ++ if (chip->options & NAND_BUSWIDTH_16) { ++ ops.ooboffs &= ~0x01; ++ ops.len = ops.ooblen = 2; ++ } else { ++ ops.len = ops.ooblen = 1; ++ } ++ ops.mode = MTD_OPS_PLACE_OOB; ++ ++ /* Write to first/last page(s) if necessary */ ++ if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) ++ wr_ofs += mtd->erasesize - mtd->writesize; ++ do { ++ ret = ingenic_sfcnand_write_oob(mtd, wr_ofs, &ops); ++ if (ret) ++ return ret; ++ wr_ofs += mtd->writesize; ++ i++; ++ } while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2); ++ } ++ /* Update flash-based bad block table */ ++ if (chip->bbt_options & NAND_BBT_USE_FLASH) { ++ ret = nand_markbad_bbt(mtd, ofs); ++ } ++ ++ return ret; ++} ++ ++static int32_t ingenic_sfc_nand_erase_blk(struct sfc_flash *flash, uint32_t pageaddr) ++{ ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ struct ingenic_sfcnand_ops *ops = nand_info->ops; ++ struct sfc_cdt_xfer xfer; ++ int32_t ret = 0; ++ ++ memset(&xfer, 0, sizeof(xfer)); ++ ++ /* set index */ ++ xfer.cmd_index = NAND_ERASE_WRITE_ENABLE; ++ ++ /* set addr */ ++ xfer.rowaddr = pageaddr; ++ xfer.staaddr0 = SPINAND_ADDR_STATUS; ++ ++ /* set transfer config */ ++ xfer.dataen = DISABLE; ++ ++ if(sfc_sync_cdt(flash->sfc, &xfer)) { ++ dev_err(flash->dev,"sfc_sync_cdt error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ /* get status to be sure nand write completed */ ++ ret = ops->get_feature(flash, GET_ERASE_STATUS); ++ if(ret){ ++ dev_err(flash->dev, "Erase error, get state error ! %s %s %d \n",__FILE__,__func__,__LINE__); ++ } ++ ++ return ret; ++} ++ ++static int ingenic_sfcnand_erase(struct mtd_info *mtd, struct erase_info *instr) ++{ ++ struct sfc_flash *flash = to_ingenic_spi_nand(mtd); ++ uint32_t addr = (uint32_t)instr->addr; ++ uint32_t end; ++ int32_t ret; ++ ++ if(addr % mtd->erasesize) { ++ dev_err(flash->dev, "ERROR:%s line %d eraseaddr no align\n", __func__,__LINE__); ++ return -EINVAL; ++ } ++ end = addr + instr->len; ++ instr->state = MTD_ERASING; ++ mutex_lock(&flash->lock); ++ while (addr < end) { ++ if((ret = ingenic_sfc_nand_erase_blk(flash, addr / mtd->writesize))) { ++ dev_err(flash->dev, "spi nand erase error blk id %d !\n",addr / mtd->erasesize); ++ instr->state = MTD_ERASE_FAILED; ++ goto erase_exit; ++ } ++ addr += mtd->erasesize; ++ } ++ ++ instr->state = MTD_ERASE_DONE; ++erase_exit: ++ mutex_unlock(&flash->lock); ++ return ret; ++} ++ ++static int ingenic_sfcnand_block_isbab(struct mtd_info *mtd, loff_t ofs) ++{ ++ struct nand_chip *chip = mtd->priv; ++ if(!chip->bbt) ++ return chip->block_bad(mtd, ofs, 1); ++ return nand_isbad_bbt(mtd, ofs, 0); ++} ++ ++static int ingenic_sfcnand_block_markbad(struct mtd_info *mtd, loff_t ofs) ++{ ++ struct nand_chip *chip = mtd->priv; ++ int ret = ingenic_sfcnand_block_isbab(mtd, ofs); ++ if(ret > 0) { ++ /* If it was bad already, return success and do nothing */ ++ return 0; ++ } ++ return chip->block_markbad(mtd, ofs); ++} ++ ++static int ingenic_sfcnand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) ++{ ++ struct sfc_flash *flash = to_ingenic_spi_nand(mtd); ++ uint32_t pagesize = mtd->writesize; ++ uint32_t pageaddr; ++ uint32_t columnaddr; ++ uint32_t rlen; ++ int32_t ret = 0, reterr = 0, ret_eccvalue = 0; ++ ++ mutex_lock(&flash->lock); ++ while(len) { ++ pageaddr = (uint32_t)from / pagesize; ++ columnaddr = (uint32_t)from % pagesize; ++ rlen = min_t(uint32_t, len, pagesize - columnaddr); ++ ++ /* create DMA Descriptors */ ++ ret = create_sfc_desc(flash, buf, rlen); ++ if(ret < 0){ ++ dev_err(flash->dev, "%s create descriptors error. -%d\n", __func__, ret); ++ return ret; ++ } ++ ++ /* DMA Descriptors read */ ++ ret = ingenic_sfc_nand_read(flash, pageaddr, columnaddr, buf, rlen); ++ if(ret < 0) { ++ dev_err(flash->dev, "%s %s %d: ingenic_sfc_nand_read error, ret = %d, \ ++ pageaddr = %u, columnaddr = %u, rlen = %u\n", ++ __FILE__, __func__, __LINE__, ++ ret, pageaddr, columnaddr, rlen); ++ reterr = ret; ++ if(ret == -EIO) ++ break; ++ } else if (ret > 0) { ++ dev_dbg(flash->dev, "%s %s %d: ingenic_sfc_nand_read, ecc value = %d, \ ++ pageaddr = %u, columnaddr = %u, rlen = %u\n", ++ __FILE__, __func__, __LINE__, ++ ret, pageaddr, columnaddr, rlen); ++ ret_eccvalue = ret; ++ } ++ ++ len -= rlen; ++ from += rlen; ++ buf += rlen; ++ *retlen += rlen; ++ } ++ mutex_unlock(&flash->lock); ++ return reterr ? reterr : (ret_eccvalue ? ret_eccvalue : ret); ++} ++ ++static int ingenic_sfcnand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) ++{ ++ struct sfc_flash *flash = to_ingenic_spi_nand(mtd); ++ uint32_t pagesize = mtd->writesize; ++ uint32_t pageaddr; ++ uint32_t columnaddr; ++ uint32_t wlen; ++ int32_t ret; ++ ++ mutex_lock(&flash->lock); ++ while(len) { ++ pageaddr = (uint32_t)to / pagesize; ++ columnaddr = (uint32_t)to % pagesize; ++ wlen = min_t(uint32_t, pagesize - columnaddr, len); ++ /* create DMA Descriptors */ ++ ret = create_sfc_desc(flash, (unsigned char *)buf, wlen); ++ if(ret < 0){ ++ dev_err(flash->dev, "%s create descriptors error. -%d\n", __func__, ret); ++ return ret; ++ } ++ ++ /* DMA Descriptors write */ ++ if((ret = ingenic_sfc_nand_write(flash, (u_char *)buf, pageaddr, columnaddr, wlen))) { ++ dev_err(flash->dev, "%s %s %d : spi nand write fail, ret = %d, \ ++ pageaddr = %u, columnaddr = %u, wlen = %u\n", ++ __FILE__, __func__, __LINE__, ret, ++ pageaddr, columnaddr, wlen); ++ break; ++ } ++ *retlen += wlen; ++ len -= wlen; ++ to += wlen; ++ buf += wlen; ++ } ++ mutex_unlock(&flash->lock); ++ return ret; ++} ++ ++static int32_t ingenic_sfcnand_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) ++{ ++ struct sfc_flash *flash = to_ingenic_spi_nand(mtd); ++ uint32_t addr = (uint32_t)from; ++ uint32_t pageaddr = addr / mtd->writesize; ++ uint32_t columnaddr = addr % mtd->writesize; ++ int32_t ret = 0, ret_eccvalue = 0; ++ ++ mutex_lock(&flash->lock); ++ if(ops->datbuf) { ++ /* create DMA Descriptors */ ++ ret = create_sfc_desc(flash, ops->datbuf, ops->len); ++ if(ret < 0){ ++ dev_err(flash->dev, "%s create descriptors error. -%d\n", __func__, ret); ++ goto read_oob_exit; ++ } ++ /* DMA Descriptors read */ ++ ret = ingenic_sfc_nand_read(flash, pageaddr, columnaddr, ops->datbuf, ops->len); ++ if(ret < 0) { ++ dev_err(flash->dev, "%s %s %d : spi nand read data error, ret = %d\n",__FILE__,__func__,__LINE__, ret); ++ if(ret == -EIO) { ++ goto read_oob_exit; ++ } else { ++ ret_eccvalue = ret; ++ } ++ } ++ } ++ if(ops->oobbuf) { ++ /* create DMA Descriptors */ ++ ret = create_sfc_desc(flash, ops->oobbuf, ops->ooblen); ++ if(ret < 0){ ++ dev_err(flash->dev, "%s create descriptors error. -%d\n", __func__, ret); ++ goto read_oob_exit; ++ } ++ ++ ret = ingenic_sfc_nand_read(flash, pageaddr, mtd->writesize + ops->ooboffs, ops->oobbuf, ops->ooblen); ++ if(ret < 0) ++ dev_err(flash->dev, "%s %s %d : spi nand read oob error ,ret= %d\n", __FILE__, __func__, __LINE__, ret); ++ ++ if(ret != -EIO) ++ ops->oobretlen = ops->ooblen; ++ ++ } ++read_oob_exit: ++ mutex_unlock(&flash->lock); ++ ++ return ret ? ret : ret_eccvalue; ++} ++ ++static int ingenic_sfcnand_block_bad_check(struct mtd_info *mtd, loff_t ofs, int getchip) ++{ ++ int check_len = 1; ++ unsigned char check_buf[2] = {0x0}; ++ struct nand_chip *chip = (struct nand_chip *)mtd->priv; ++ struct mtd_oob_ops ops; ++ ++ memset(&ops, 0, sizeof(ops)); ++ if (chip->options & NAND_BUSWIDTH_16) ++ check_len = 2; ++ ++ ops.oobbuf = check_buf; ++ ops.ooblen = check_len; ++ ingenic_sfcnand_read_oob(mtd, ofs, &ops); ++ if(badblk_check(check_len, check_buf)) ++ return 1; ++ return 0; ++} ++ ++static int ingenic_sfc_nand_set_feature(struct sfc_flash *flash, uint8_t addr, uint32_t val) ++{ ++ struct sfc_cdt_xfer xfer; ++ memset(&xfer, 0, sizeof(xfer)); ++ ++ /* set index */ ++ xfer.cmd_index = NAND_SET_FEATURE; ++ ++ /* set addr */ ++ xfer.staaddr0 = addr; ++ ++ /* set transfer config */ ++ xfer.dataen = ENABLE; ++ xfer.config.datalen = 1; ++ xfer.config.data_dir = GLB0_TRAN_DIR_WRITE; ++ xfer.config.ops_mode = CPU_OPS; ++ xfer.config.buf = (uint8_t *)&val; ++ ++ if(sfc_sync_cdt(flash->sfc, &xfer)) { ++ dev_err(flash->dev,"sfc_sync_cdt error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static int ingenic_sfc_nand_get_feature(struct sfc_flash *flash, uint8_t addr, uint8_t *val) ++{ ++ struct sfc_cdt_xfer xfer; ++ memset(&xfer, 0, sizeof(xfer)); ++ ++ /* set index */ ++ xfer.cmd_index = NAND_GET_FEATURE; ++ ++ /* set addr */ ++ xfer.staaddr0 = addr; ++ ++ /* set transfer config */ ++ xfer.dataen = ENABLE; ++ xfer.config.datalen = 1; ++ xfer.config.data_dir = GLB0_TRAN_DIR_READ; ++ xfer.config.ops_mode = CPU_OPS; ++ xfer.config.buf = (uint8_t *)val; ++ ++ if(sfc_sync_cdt(flash->sfc, &xfer)) { ++ dev_err(flash->dev,"sfc_sync_cdt error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static int32_t __init ingenic_sfc_nand_dev_init(struct sfc_flash *flash) ++{ ++ int32_t ret; ++ /*release protect*/ ++ uint8_t feature = 0; ++ if((ret = ingenic_sfc_nand_set_feature(flash, SPINAND_ADDR_PROTECT, feature))) ++ goto exit; ++ ++ if((ret = ingenic_sfc_nand_get_feature(flash, SPINAND_ADDR_FEATURE, &feature))) ++ goto exit; ++ ++ feature |= (1 << 4) | (1 << 3) | (1 << 0); ++ if((ret = ingenic_sfc_nand_set_feature(flash, SPINAND_ADDR_FEATURE, feature))) ++ goto exit; ++ ++ return 0; ++exit: ++ return ret; ++} ++ ++static int32_t __init ingenic_sfc_nand_try_id(struct sfc_flash *flash) ++{ ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ struct ingenic_sfcnand_device *nand_device; ++ struct sfc_cdt_xfer xfer; ++ uint8_t id_buf[2] = {0}; ++ unsigned short index[2] = {NAND_TRY_ID, NAND_TRY_ID_DMY}; ++ uint8_t i = 0; ++ ++ for(i = 0; i < 2; i++){ ++ memset(&xfer, 0, sizeof(xfer)); ++ ++ /* set index */ ++ xfer.cmd_index = index[i]; ++ ++ /* set addr */ ++ xfer.rowaddr = 0; ++ ++ /* set transfer config */ ++ xfer.dataen = ENABLE; ++ xfer.config.datalen = sizeof(id_buf); ++ xfer.config.data_dir = GLB0_TRAN_DIR_READ; ++ xfer.config.ops_mode = CPU_OPS; ++ xfer.config.buf = id_buf; ++ ++ if(sfc_sync_cdt(flash->sfc, &xfer)) { ++ dev_err(flash->dev,"sfc_sync_cdt error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ list_for_each_entry(nand_device, &nand_list, list) { ++ if(nand_device->id_manufactory == id_buf[0]) { ++ nand_info->id_manufactory = id_buf[0]; ++ nand_info->id_device = id_buf[1]; ++ break; ++ } ++ } ++ ++ if(nand_info->id_manufactory && nand_info->id_device) ++ break; ++ } ++ ++ if(!nand_info->id_manufactory && !nand_info->id_device) { ++ dev_err(flash->dev, " ERROR!: don`t support this nand manufactory, please add nand driver.\n"); ++ return -ENODEV; ++ } else { ++ struct device_id_struct *device_id = nand_device->id_device_list; ++ int32_t id_count = nand_device->id_device_count; ++ while(id_count--) { ++ if(device_id->id_device == nand_info->id_device) { ++ /* notice :base_param and partition param should read from nand */ ++ nand_info->param = *device_id->param; ++ break; ++ } ++ device_id++; ++ } ++ if(id_count < 0) { ++ dev_err(flash->dev, "ERROR: do support this device, id_manufactory = 0x%02x, id_device = 0x%02x\n", nand_info->id_manufactory, nand_info->id_device); ++ return -ENODEV; ++ } ++ } ++ ++ dev_info(flash->dev, "Found Supported device, id_manufactory = 0x%02x, id_device = 0x%02x\n", nand_info->id_manufactory, nand_info->id_device); ++ ++ /* fill manufactory special operation and cdt params */ ++ nand_info->ops = &nand_device->ops; ++ nand_info->cdt_params = nand_info->ops->get_cdt_params(flash, nand_info->id_device); ++ ++ if (!nand_info->ops->get_feature) { ++ if (!nand_info->ops->deal_ecc_status) { ++ dev_err(flash->dev,"ERROR:xxx_nand.c \"get_feature()\" and \"deal_ecc_status()\" not define.\n"); ++ return -ENODEV; ++ } else { ++ nand_info->ops->get_feature = nand_common_get_feature; ++ printk("use nand common get feature interface!\n"); ++ } ++ } else { ++ printk("use nand private get feature interface!\n"); ++ } ++ ++ return 0; ++} ++ ++static int32_t __init nand_partition_param_copy(struct sfc_flash *flash, struct ingenic_sfcnand_burner_param *burn_param) { ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ int i = 0, count = 5, ret; ++ size_t retlen = 0; ++ ++ /* partition param copy */ ++ nand_info->partition.num_partition = burn_param->partition_num; ++ ++ burn_param->partition = kzalloc(nand_info->partition.num_partition * sizeof(struct ingenic_sfcnand_partition), GFP_KERNEL); ++ if (IS_ERR_OR_NULL(burn_param->partition)) { ++ dev_err(flash->dev, "alloc partition space failed!\n"); ++ return -ENOMEM; ++ } ++ ++ nand_info->partition.partition = kzalloc(nand_info->partition.num_partition * sizeof(struct mtd_partition), GFP_KERNEL); ++ if (IS_ERR_OR_NULL(nand_info->partition.partition)) { ++ dev_err(flash->dev, "alloc partition space failed!\n"); ++ kfree(burn_param->partition); ++ return -ENOMEM; ++ } ++ ++partition_retry_read: ++ ret = ingenic_sfcnand_read(&flash->mtd, flash->param_offset + sizeof(*burn_param) - sizeof(burn_param->partition), ++ nand_info->partition.num_partition * sizeof(struct ingenic_sfcnand_partition), ++ &retlen, (u_char *)burn_param->partition); ++ ++ if((ret < 0) && count--) ++ goto partition_retry_read; ++ if(count < 0) { ++ dev_err(flash->dev, "read nand partition failed!\n"); ++ kfree(burn_param->partition); ++ kfree(nand_info->partition.partition); ++ return -EIO; ++ } ++ ++ for(i = 0; i < burn_param->partition_num; i++) { ++ nand_info->partition.partition[i].name = burn_param->partition[i].name; ++ nand_info->partition.partition[i].size = burn_param->partition[i].size; ++ nand_info->partition.partition[i].offset = burn_param->partition[i].offset; ++ nand_info->partition.partition[i].mask_flags = burn_param->partition[i].mask_flags; ++ } ++ return 0; ++} ++ ++static struct ingenic_sfcnand_burner_param *burn_param; ++static int32_t __init flash_part_from_chip(struct sfc_flash *flash) { ++ ++ int32_t ret = 0, retlen = 0, count = 5; ++ ++ burn_param = kzalloc(sizeof(struct ingenic_sfcnand_burner_param), GFP_KERNEL); ++ if(IS_ERR_OR_NULL(burn_param)) { ++ dev_err(flash->dev, "alloc burn_param space error!\n"); ++ return -ENOMEM; ++ } ++ ++ count = 5; ++param_retry_read: ++ ret = ingenic_sfcnand_read(&flash->mtd, flash->param_offset, ++ sizeof(struct ingenic_sfcnand_burner_param), &retlen, (u_char *)burn_param); ++ if((ret < 0) && count--) ++ goto param_retry_read; ++ if(count < 0) { ++ dev_err(flash->dev, "read nand base param failed!\n"); ++ ret = -EIO; ++ goto failed; ++ } ++ ++ if(burn_param->magic_num != SPINAND_MAGIC_NUM) { ++ dev_info(flash->dev, "NOTICE: this flash haven`t param, magic_num:%x\n", burn_param->magic_num); ++ ret = -EINVAL; ++ goto failed; ++ } ++ ++ if(nand_partition_param_copy(flash, burn_param)) { ++ ret = -ENOMEM; ++ goto failed; ++ } ++ ++ return 0; ++failed: ++ kfree(burn_param); ++ return ret; ++ ++} ++ ++static int32_t __init flash_part_from_board(struct sfc_flash *flash, struct ingenic_sfc_info *board_info) { ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ struct ingenic_sfcnand_partition *flash_partition = board_info->flash_partition; ++ int8_t i = 0; ++ ++ nand_info->partition.num_partition = board_info->num_partition; ++ nand_info->partition.partition = kzalloc(nand_info->partition.num_partition * sizeof(struct mtd_partition), GFP_KERNEL); ++ if (IS_ERR_OR_NULL(nand_info->partition.partition)) { ++ dev_err(flash->dev, "alloc partition space failed!\n"); ++ nand_info->partition.num_partition = 0; ++ return -ENOMEM; ++ } ++ ++ for(i = 0; i < board_info->num_partition; i++) { ++ nand_info->partition.partition[i].name = flash_partition[i].name; ++ nand_info->partition.partition[i].size = flash_partition[i].size; ++ nand_info->partition.partition[i].offset = flash_partition[i].offset; ++ nand_info->partition.partition[i].mask_flags = flash_partition[i].mask_flags; ++ } ++ return 0; ++} ++ ++static int32_t __init ingenic_sfcnand_partition(struct sfc_flash *flash, struct ingenic_sfc_info *board_info) { ++ int32_t ret = 0; ++ if(!board_info || !board_info->use_board_info) { ++ if((ret = flash_part_from_chip(flash))) ++ dev_info(flash->dev, "read partition from flash failed!\n"); ++ } else { ++ if((ret = flash_part_from_board(flash, board_info))) ++ dev_err(flash->dev, "copy partition from board failed!\n"); ++ } ++ return ret; ++} ++ ++int ingenic_sfcnand_register(struct ingenic_sfcnand_device *flash) { ++ list_add_tail(&flash->list, &nand_list); ++ return 0; ++} ++EXPORT_SYMBOL_GPL(ingenic_sfcnand_register); ++ ++/* ++ *MK_CMD(cdt, cmd, LINK, ADDRMODE, DATA_EN) ++ *MK_ST(cdt, st, LINK, ADDRMODE, ADDR_WIDTH, POLL_EN, DATA_EN, TRAN_MODE) ++ */ ++static void params_to_cdt(cdt_params_t *params, struct sfc_cdt *cdt) ++{ ++ /* 6. nand standard read */ ++ MK_CMD(cdt[NAND_STANDARD_READ_TO_CACHE], params->r_to_cache, 1, ROW_ADDR, DISABLE); ++ MK_ST(cdt[NAND_STANDARD_READ_GET_FEATURE], params->oip, 1, STA_ADDR0, 1, ENABLE, DISABLE, TM_STD_SPI); ++ MK_CMD(cdt[NAND_STANDARD_READ_FROM_CACHE], params->standard_r, 0, COL_ADDR, ENABLE); ++ ++ /* 7. nand quad read */ ++ MK_CMD(cdt[NAND_QUAD_READ_TO_CACHE], params->r_to_cache, 1, ROW_ADDR, DISABLE); ++ MK_ST(cdt[NAND_QUAD_READ_GET_FEATURE], params->oip, 1, STA_ADDR0, 1, ENABLE, DISABLE, TM_STD_SPI); ++ MK_CMD(cdt[NAND_QUAD_READ_FROM_CACHE], params->quad_r, 0, COL_ADDR, ENABLE); ++ ++ /* 8. nand standard write */ ++ MK_CMD(cdt[NAND_STANDARD_WRITE_ENABLE], params->w_en, 1, DEFAULT_ADDRMODE, DISABLE); ++ MK_CMD(cdt[NAND_STANDARD_WRITE_TO_CACHE], params->standard_w_cache, 1, COL_ADDR, ENABLE); ++ MK_CMD(cdt[NAND_STANDARD_WRITE_EXEC], params->w_exec, 1, ROW_ADDR, DISABLE); ++ MK_ST(cdt[NAND_STANDARD_WRITE_GET_FEATURE], params->oip, 0, STA_ADDR0, 1, ENABLE, DISABLE, TM_STD_SPI); ++ ++ /* 9. nand quad write */ ++ MK_CMD(cdt[NAND_QUAD_WRITE_ENABLE], params->w_en, 1, DEFAULT_ADDRMODE, DISABLE); ++ MK_CMD(cdt[NAND_QUAD_WRITE_TO_CACHE], params->quad_w_cache, 1, COL_ADDR, ENABLE); ++ MK_CMD(cdt[NAND_QUAD_WRITE_EXEC], params->w_exec, 1, ROW_ADDR, DISABLE); ++ MK_ST(cdt[NAND_QUAD_WRITE_GET_FEATURE], params->oip, 0, STA_ADDR0, 1, ENABLE, DISABLE, TM_STD_SPI); ++ ++ /* 10. block erase */ ++ MK_CMD(cdt[NAND_ERASE_WRITE_ENABLE], params->w_en, 1, DEFAULT_ADDRMODE, DISABLE); ++ MK_CMD(cdt[NAND_BLOCK_ERASE], params->b_erase, 1, ROW_ADDR, DISABLE); ++ MK_ST(cdt[NAND_ERASE_GET_FEATURE], params->oip, 0, STA_ADDR0, 1, ENABLE, DISABLE, TM_STD_SPI); ++ ++ /* 11. ecc status read */ ++ MK_CMD(cdt[NAND_ECC_STATUS_READ], params->ecc_r, 0, DEFAULT_ADDRMODE, ENABLE); ++ ++} ++ ++static void create_cdt_table(struct sfc_flash *flash, uint32_t flag) ++{ ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ cdt_params_t *cdt_params; ++ struct sfc_cdt sfc_cdt[INDEX_MAX_NUM]; ++ ++ memset(sfc_cdt, 0, sizeof(sfc_cdt)); ++ if(flag == DEFAULT_CDT) ++ { ++ /* 1. reset */ ++ sfc_cdt[NAND_RESET].link = CMD_LINK(0, DEFAULT_ADDRMODE, TM_STD_SPI); ++ sfc_cdt[NAND_RESET].xfer = CMD_XFER(0, DISABLE, 0, DISABLE, SPINAND_CMD_RESET); ++ sfc_cdt[NAND_RESET].staExp = 0; ++ sfc_cdt[NAND_RESET].staMsk = 0; ++ ++ /* 2. try id */ ++ sfc_cdt[NAND_TRY_ID].link = CMD_LINK(0, DEFAULT_ADDRMODE, TM_STD_SPI); ++ sfc_cdt[NAND_TRY_ID].xfer = CMD_XFER(0, DISABLE, 0, ENABLE, SPINAND_CMD_RDID); ++ sfc_cdt[NAND_TRY_ID].staExp = 0; ++ sfc_cdt[NAND_TRY_ID].staMsk = 0; ++ ++ /* 3. try id with dummy */ ++ /* ++ * There are some NAND flash, try ID operation requires 8-bit dummy value to be all 0, ++ * so use 1 byte address instead of dummy here. ++ */ ++ sfc_cdt[NAND_TRY_ID_DMY].link = CMD_LINK(0, ROW_ADDR, TM_STD_SPI); ++ sfc_cdt[NAND_TRY_ID_DMY].xfer = CMD_XFER(1, DISABLE, 0, ENABLE, SPINAND_CMD_RDID); ++ sfc_cdt[NAND_TRY_ID_DMY].staExp = 0; ++ sfc_cdt[NAND_TRY_ID_DMY].staMsk = 0; ++ ++ /* 4. set feature */ ++ sfc_cdt[NAND_SET_FEATURE].link = CMD_LINK(0, STA_ADDR0, TM_STD_SPI); ++ sfc_cdt[NAND_SET_FEATURE].xfer = CMD_XFER(1, DISABLE, 0, ENABLE, SPINAND_CMD_SET_FEATURE); ++ sfc_cdt[NAND_SET_FEATURE].staExp = 0; ++ sfc_cdt[NAND_SET_FEATURE].staMsk = 0; ++ ++ /* 5. get feature */ ++ sfc_cdt[NAND_GET_FEATURE].link = CMD_LINK(0, STA_ADDR0, TM_STD_SPI); ++ sfc_cdt[NAND_GET_FEATURE].xfer = CMD_XFER(1, DISABLE, 0, ENABLE, SPINAND_CMD_GET_FEATURE); ++ sfc_cdt[NAND_GET_FEATURE].staExp = 0; ++ sfc_cdt[NAND_GET_FEATURE].staMsk = 0; ++ ++ /* first create cdt table */ ++ write_cdt(flash->sfc, sfc_cdt, NAND_RESET, NAND_GET_FEATURE); ++ } ++ ++ if(flag == UPDATE_CDT){ ++ cdt_params = nand_info->cdt_params; ++ params_to_cdt(cdt_params, sfc_cdt); ++ ++ /* second create cdt table */ ++ write_cdt(flash->sfc, sfc_cdt, NAND_STANDARD_READ_TO_CACHE, NAND_ECC_STATUS_READ); ++ } ++ //dump_cdt(flash->sfc); ++} ++ ++static int request_sfc_desc(struct sfc_flash *flash) ++{ ++ struct sfc *sfc = flash->sfc; ++ sfc->desc = (struct sfc_desc *)dma_alloc_coherent(flash->dev, sizeof(struct sfc_desc) * DESC_MAX_NUM, &sfc->desc_pyaddr, GFP_KERNEL); ++ if(flash->sfc->desc == NULL){ ++ return -ENOMEM; ++ } ++ sfc->desc_max_num = DESC_MAX_NUM; ++ ++ return 0; ++} ++ ++static int __init ingenic_sfcnand_probe(struct platform_device *pdev) ++{ ++ const char *ingenic_probe_types[] = {"cmdlinepart",NULL}; ++ struct ingenic_sfc_info *board_info = NULL; ++ struct sfc_flash *flash; ++ struct nand_chip *chip; ++ struct ingenic_sfcnand_flashinfo *nand_info; ++ int32_t ret; ++ int chip_param = 1; ++ ++ flash = kzalloc(sizeof(struct sfc_flash), GFP_KERNEL); ++ if (IS_ERR_OR_NULL(flash)) ++ return -ENOMEM; ++ chip = kzalloc(sizeof(struct nand_chip), GFP_KERNEL); ++ if (IS_ERR_OR_NULL(chip)) { ++ kfree(flash); ++ return -ENOMEM; ++ } ++ nand_info = kzalloc(sizeof(struct ingenic_sfcnand_flashinfo), GFP_KERNEL); ++ if(IS_ERR_OR_NULL(nand_info)) { ++ kfree(flash); ++ kfree(chip); ++ return -ENOMEM; ++ } ++ ++ platform_set_drvdata(pdev, flash); ++ mutex_init(&flash->lock); ++ flash->dev = &pdev->dev; ++ flash->flash_info = nand_info; ++ flash->sfc = sfc_res_init(pdev); ++ if(IS_ERR(flash->sfc)) { ++ dev_err(flash->dev, "sfc control init error!\n"); ++ ret = PTR_ERR(flash->sfc); ++ goto free_base; ++ } ++ board_info = pdev->dev.platform_data; ++ if(board_info->param_offset > 0) { ++ flash->param_offset = board_info->param_offset; ++ } else { ++ flash->param_offset = SPIFLASH_PARAMER_OFFSET; ++ } ++ ++#define THOLD 5 ++#define TSETUP 5 ++#define TSHSL_R 20 ++#define TSHSL_W 50 ++ ++ set_flash_timing(flash->sfc, THOLD, TSETUP, TSHSL_R, TSHSL_W); ++ ++ /* request DMA Descriptor space */ ++ ret = request_sfc_desc(flash); ++ if(ret){ ++ dev_err(flash->dev, "Failure to request DMA descriptor space!\n"); ++ ret = -ENOMEM; ++ dma_free_coherent(flash->dev, sizeof(struct sfc_desc) * DESC_MAX_NUM, flash->sfc->desc, flash->sfc->desc_pyaddr); ++ goto free_base; ++ } ++ ++ /* Try creating default CDT table */ ++ create_cdt_table(flash, DEFAULT_CDT); ++ ++ if((ret = ingenic_sfc_nand_dev_init(flash))) { ++ dev_err(flash->dev, "nand device init failed!\n"); ++ goto free_base; ++ } ++ ++ if((ret = ingenic_sfc_nand_try_id(flash))) { ++ dev_err(flash->dev, "try device id failed\n"); ++ goto free_base; ++ } ++ ++ /* Update to private CDT table */ ++ create_cdt_table(flash, UPDATE_CDT); ++ ++ set_flash_timing(flash->sfc, nand_info->param.tHOLD, ++ nand_info->param.tSETUP, nand_info->param.tSHSL_R, nand_info->param.tSHSL_W); ++ flash->mtd.name = "sfc_nand"; ++ flash->mtd.owner = THIS_MODULE; ++ flash->mtd.type = MTD_NANDFLASH; ++ flash->mtd.flags |= MTD_CAP_NANDFLASH; ++ flash->mtd.erasesize = nand_info->param.blocksize; ++ flash->mtd.writesize = nand_info->param.pagesize; ++ flash->mtd.size = nand_info->param.flashsize; ++ flash->mtd.oobsize = nand_info->param.oobsize; ++ flash->mtd.writebufsize = flash->mtd.writesize; ++ flash->mtd.bitflip_threshold = flash->mtd.ecc_strength = nand_info->param.ecc_max - 1; ++ ++ chip->select_chip = NULL; ++ chip->badblockbits = 8; ++ chip->scan_bbt = nand_default_bbt; ++ chip->block_bad = ingenic_sfcnand_block_bad_check; ++ chip->block_markbad = ingenic_sfcnand_chip_block_markbad; ++ //chip->ecc.layout= &gd5f_ecc_layout_128; // for erase ops ++ chip->bbt_erase_shift = chip->phys_erase_shift = ffs(flash->mtd.erasesize) - 1; ++ chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL); ++ if(IS_ERR_OR_NULL(chip->buffers)) { ++ dev_err(flash->dev, "alloc nand buffer failed\n"); ++ ret = -ENOMEM; ++ goto free_base; ++ } ++ chip->buffers->databuf = kzalloc(nand_info->param.pagesize + nand_info->param.oobsize, GFP_KERNEL); ++ if(IS_ERR_OR_NULL(chip->buffers->databuf)) { ++ dev_err(flash->dev, "alloc nand buffer->databuf failed\n"); ++ ret = -ENOMEM; ++ kfree(chip->buffers); ++ goto free_base; ++ } ++ ++ /* Set the bad block position */ ++ if (flash->mtd.writesize > 512 || (chip->options & NAND_BUSWIDTH_16)) ++ chip->badblockpos = NAND_LARGE_BADBLOCK_POS; ++ else ++ chip->badblockpos = NAND_SMALL_BADBLOCK_POS; ++ ++ flash->mtd.priv = chip; ++ flash->mtd._erase = ingenic_sfcnand_erase; ++ flash->mtd._read = ingenic_sfcnand_read; ++ flash->mtd._write = ingenic_sfcnand_write; ++ flash->mtd._read_oob = ingenic_sfcnand_read_oob; ++ flash->mtd._write_oob = ingenic_sfcnand_write_oob; ++ flash->mtd._block_isbad = ingenic_sfcnand_block_isbab; ++ flash->mtd._block_markbad = ingenic_sfcnand_block_markbad; ++ if((ret = chip->scan_bbt(&flash->mtd))) { ++ dev_err(flash->dev, "creat and scan bbt failed\n"); ++ goto free_all; ++ } ++ ++ if((ret = ingenic_sfcnand_partition(flash, board_info))) { ++ if(ret == -EINVAL) ++ { ++ chip_param = 0; ++ dev_info(flash->dev, "read mtdparts!\n"); ++ }else{ ++ dev_err(flash->dev, "read flash partition failed!\n"); ++ goto free_all; ++ } ++ }else{ ++ flash->mtd.name = "chip_param"; ++ } ++ ++ /* dump_flash_info(flash);*/ ++ if(chip_param) ++ ret = mtd_device_parse_register(&flash->mtd, ingenic_probe_types, NULL, nand_info->partition.partition, nand_info->partition.num_partition); ++ else ++ ret = mtd_device_parse_register(&flash->mtd, NULL, NULL, NULL, 0); ++ if (ret) { ++ kfree(nand_info->partition.partition); ++ if(!board_info->use_board_info) { ++ kfree(burn_param->partition); ++ kfree(burn_param); ++ } ++ ret = -ENODEV; ++ goto free_all; ++ } ++ ++ return 0; ++ ++free_all: ++ kfree(chip->buffers->databuf); ++ kfree(chip->buffers); ++ ++free_base: ++ kfree(flash); ++ kfree(chip); ++ kfree(nand_info); ++ return ret; ++} ++ ++static int __exit ingenic_sfc_remove(struct platform_device *pdev) ++{ ++ struct sfc_flash *flash = platform_get_drvdata(pdev); ++ struct sfc *sfc = flash->sfc; ++ clk_disable_unprepare(sfc->clk_gate); ++ clk_put(sfc->clk_gate); ++ clk_disable_unprepare(sfc->clk); ++ clk_put(sfc->clk); ++ free_irq(sfc->irq, flash); ++ iounmap(sfc->iomem); ++ release_mem_region(sfc->ioarea->start, resource_size(sfc->ioarea)); ++ platform_set_drvdata(pdev, NULL); ++ return 0; ++} ++ ++static int ingenic_sfc_suspend(struct platform_device *pdev, pm_message_t msg) ++{ ++ struct sfc_flash *flash = platform_get_drvdata(pdev); ++ struct sfc *sfc = flash->sfc; ++ disable_irq(sfc->irq); ++ clk_disable_unprepare(sfc->clk_gate); ++ clk_disable_unprepare(sfc->clk); ++ return 0; ++} ++ ++static int ingenic_sfc_resume(struct platform_device *pdev) ++{ ++ struct sfc_flash *flash = platform_get_drvdata(pdev); ++ struct sfc *sfc = flash->sfc; ++ clk_prepare_enable(sfc->clk); ++ clk_prepare_enable(sfc->clk_gate); ++ enable_irq(sfc->irq); ++ return 0; ++} ++ ++void ingenic_sfc_shutdown(struct platform_device *pdev) ++{ ++ struct sfc_flash *flash = platform_get_drvdata(pdev); ++ struct sfc *sfc = flash->sfc; ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ ++ if(nand_info->id_manufactory == 0xEF && ++ nand_info->id_device == 0xAB) ++ //winbond_reset(flash); ++ ++ disable_irq(sfc->irq); ++ clk_disable_unprepare(sfc->clk_gate); ++ clk_disable_unprepare(sfc->clk); ++ return ; ++} ++ ++static const struct of_device_id ingenicsfc_match[] = { ++ { .compatible = "ingenic,sfc", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ingenicsfc_match); ++ ++static struct platform_driver ingenic_sfcnand_drv = { ++ .driver = { ++ .name = "ingenic-sfc", ++ .owner = THIS_MODULE, ++ .of_match_table = ingenicsfc_match, ++ }, ++ .remove = __exit_p(ingenic_sfc_remove), ++ .suspend = ingenic_sfc_suspend, ++ .resume = ingenic_sfc_resume, ++ .shutdown = ingenic_sfc_shutdown, ++}; ++module_platform_driver_probe(ingenic_sfcnand_drv, ingenic_sfcnand_probe); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("INGENIC SFC Driver"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_ingenic_sfc_nor.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_ingenic_sfc_nor.c.patch new file mode 100644 index 00000000..56259e41 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_ingenic_sfc_nor.c.patch @@ -0,0 +1,1057 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_nor.c b/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_nor.c +--- a/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_nor.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_nor.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,1053 @@ ++/* ++ * SFC controller for SPI protocol, use FIFO and DMA; ++ * ++ * Copyright (c) 2015 Ingenic ++ * Author: ++ * 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. ++ * ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "sfc_flash.h" ++#include "spinor.h" ++#include "ingenic_sfc_common.h" ++ ++//#define DEBUG_CLONER_PARAMS ++ ++#define STATUS_SUSPND (1<<0) ++ ++static struct spi_nor_cmd_info read_standard_table = { ++ .cmd = SPINOR_OP_READ, ++ .dummy_byte = 0, ++ .addr_nbyte = 3, ++ .transfer_mode = 0, ++}; ++static struct spi_nor_cmd_info read_quad_table = { ++ .cmd = SPINOR_OP_READ_1_1_4, ++ .dummy_byte = 8, ++ .addr_nbyte = 3, ++ .transfer_mode = 5, ++}; ++static struct spi_nor_cmd_info write_standard_table = { ++ .cmd = SPINOR_OP_PP, ++ .dummy_byte = 0, ++ .addr_nbyte = 3, ++ .transfer_mode = 0, ++}; ++static struct spi_nor_cmd_info write_quad_table = { ++ .cmd = SPINOR_OP_QPP, ++ .dummy_byte = 0, ++ .addr_nbyte = 3, ++ .transfer_mode = 5, ++}; ++static struct spi_nor_cmd_info sector_erase_table_32k = { ++ .cmd = SPINOR_OP_BE_32K, ++ .dummy_byte = 0, ++ .addr_nbyte = 3, ++ .transfer_mode = 0, ++}; ++ ++static struct spi_nor_cmd_info sector_erase_table_64k = { ++ .cmd = SPINOR_OP_SE, ++ .dummy_byte = 0, ++ .addr_nbyte = 3, ++ .transfer_mode = 0, ++}; ++static struct spi_nor_cmd_info wr_en_table = { ++ .cmd = SPINOR_OP_WREN, ++ .dummy_byte = 0, ++ .addr_nbyte = 0, ++ .transfer_mode = 0, ++}; ++static struct spi_nor_cmd_info en4byte_table = { ++ .cmd = SPINOR_OP_EN4B, ++ .dummy_byte = 0, ++ .addr_nbyte = 0, ++ .transfer_mode = 0, ++}; ++static struct spi_nor_st_info quad_set_table = { ++ .cmd = SPINOR_OP_WRSR_1, ++ .bit_shift = 1, ++ .mask = 1, ++ .val = 1, ++ .len = 1, ++ .dummy = 0, ++}; ++static struct spi_nor_st_info quad_get_table = { ++ .cmd = SPINOR_OP_RDSR_1, ++ .bit_shift = 1, ++ .mask = 1, ++ .val = 1, ++ .len = 1, ++ .dummy = 0, ++}; ++static struct spi_nor_st_info busy_table = { ++ .cmd = SPINOR_OP_RDSR, ++ .bit_shift = 0, ++ .mask = 1, ++ .val = 0, ++ .len = 1, ++ .dummy = 0, ++}; ++static struct spi_nor_cmd_info enotp_table = { ++ .cmd = SPINOR_OP_ENOTP, ++ .dummy_byte = 0, ++ .addr_nbyte = 0, ++ .transfer_mode = 0, ++}; ++static struct spi_nor_cmd_info exotp_table = { ++ .cmd = SPINOR_OP_EXOTP, ++ .dummy_byte = 0, ++ .addr_nbyte = 0, ++ .transfer_mode = 0, ++}; ++ ++static struct burner_params *burner_params; ++struct sfc_flash *to_ingenic_spi_norflash(struct mtd_info *mtd_info) ++{ ++ return container_of(mtd_info, struct sfc_flash, mtd); ++} ++ ++int32_t sfc_nor_reset(struct sfc_flash *flash) ++{ ++ struct sfc_cdt_xfer xfer; ++ memset(&xfer, 0, sizeof(xfer)); ++ ++ /* set Index */ ++ xfer.cmd_index = NOR_RESET_ENABLE; ++ ++ /* set addr */ ++ xfer.rowaddr = 0; ++ xfer.columnaddr = 0; ++ ++ /* set transfer config */ ++ xfer.dataen = DISABLE; ++ ++ if(sfc_sync_cdt(flash->sfc, &xfer)) { ++ dev_err(flash->dev,"sfc_sync_cdt error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ udelay(100); ++ return 0; ++} ++ ++int sfc_nor_read_id(struct sfc_flash *flash) ++{ ++ struct sfc_cdt_xfer xfer; ++ unsigned char buf[3]; ++ unsigned int chip_id = 0; ++ memset(&xfer, 0, sizeof(xfer)); ++ ++ /* set Index */ ++ xfer.cmd_index = NOR_READ_ID; ++ ++ /* set addr */ ++ xfer.rowaddr = 0; ++ xfer.columnaddr = 0; ++ ++ /* set transfer config */ ++ xfer.dataen = ENABLE; ++ xfer.config.datalen = 3; ++ xfer.config.data_dir = GLB0_TRAN_DIR_READ; ++ xfer.config.ops_mode = CPU_OPS; ++ xfer.config.buf = buf; ++ ++ if(sfc_sync_cdt(flash->sfc, &xfer)) { ++ dev_err(flash->dev,"sfc_sync_cdt error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ if(xfer.config.ops_mode == DMA_OPS) ++ dma_cache_sync(NULL, (void *)xfer.config.buf, xfer.config.datalen, DMA_FROM_DEVICE); ++ ++ chip_id = ((buf[0] & 0xff) << 16) | ((buf[1] & 0xff) << 8) | (buf[2] & 0xff); ++ ++ return chip_id; ++} ++ ++static unsigned int sfc_do_read(struct sfc_flash *flash, unsigned int addr, unsigned char *buf, size_t len) ++{ ++ struct spinor_flashinfo *nor_info = flash->flash_info; ++ struct sfc_cdt_xfer xfer; ++ memset(&xfer, 0, sizeof(xfer)); ++ ++ /* set Index */ ++ if (nor_info->quad_succeed) { ++ xfer.cmd_index = NOR_READ_QUAD; ++ } else { ++ xfer.cmd_index = NOR_READ_STANDARD; ++ } ++ ++ /* set addr */ ++ xfer.columnaddr = 0; ++ xfer.rowaddr = addr; ++ ++ /* set transfer config */ ++ xfer.dataen = ENABLE; ++ xfer.config.datalen = len; ++ xfer.config.data_dir = GLB0_TRAN_DIR_READ; ++ xfer.config.ops_mode = DMA_OPS; ++ xfer.config.buf = buf; ++ ++ if(sfc_sync_cdt(flash->sfc, &xfer)) { ++ dev_err(flash->dev,"sfc_sync_cdt error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ if(xfer.config.ops_mode == DMA_OPS) ++ dma_cache_sync(NULL, (void *)buf, len, DMA_FROM_DEVICE); ++ ++ return len; ++} ++ ++static unsigned int sfc_do_write(struct sfc_flash *flash, unsigned int addr, const unsigned char *buf, size_t len) ++{ ++ struct spinor_flashinfo *nor_info = flash->flash_info; ++ struct sfc_cdt_xfer xfer; ++ memset(&xfer, 0, sizeof(xfer)); ++ ++ /* set Index */ ++ if (nor_info->quad_succeed) { ++ xfer.cmd_index = NOR_WRITE_QUAD_ENABLE; ++ } else { ++ xfer.cmd_index = NOR_WRITE_STANDARD_ENABLE; ++ } ++ ++ /* set addr */ ++ xfer.columnaddr = 0; ++ xfer.rowaddr = addr; ++ ++ /* set transfer config */ ++ xfer.dataen = ENABLE; ++ xfer.config.datalen = len; ++ xfer.config.data_dir = GLB0_TRAN_DIR_WRITE; ++ xfer.config.ops_mode = DMA_OPS; ++ xfer.config.buf = (uint8_t *)buf; ++ ++ if(sfc_sync_cdt(flash->sfc, &xfer)) { ++ dev_err(flash->dev,"sfc_sync_cdt error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ return len; ++} ++ ++static int sfc_do_erase(struct sfc_flash *flash, uint32_t addr, uint32_t flash_erase_size) ++{ ++ struct sfc_cdt_xfer xfer; ++ ++ memset(&xfer, 0, sizeof(xfer)); ++ ++ /* set Index */ ++ switch (flash_erase_size) ++ { ++ case 0x8000: ++ xfer.cmd_index = NOR_ERASE_WRITE_ENABLE_32K; ++ break; ++ case 0x10000: ++ xfer.cmd_index = NOR_ERASE_WRITE_ENABLE_64K; ++ break; ++ } ++ ++ /* set addr */ ++ xfer.rowaddr = addr; ++ ++ /* set transfer config */ ++ if(sfc_sync_cdt(flash->sfc, &xfer)) { ++ dev_err(flash->dev,"sfc_sync_cdt error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static int sfc_read(struct sfc_flash *flash, loff_t from, size_t len, unsigned char *buf) ++{ ++ int32_t ret; ++ ++ //memset(flash->sfc->desc, 0, sizeof(struct sfc_desc) * DESC_MAX_NUM); //1024 bytes space ++ ++ /* create DMA Descriptors */ ++ ret = create_sfc_desc(flash, buf, len); ++ if(ret < 0){ ++ dev_err(flash->dev, "%s create descriptors error. -%d\n", __func__, ret); ++ return ret; ++ } ++ ++ //dump_desc(flash->sfc, ret); ++ ++ /* DMA Descriptors read */ ++ ret = sfc_do_read(flash, (unsigned int)from, buf, len); ++ ++ return ret; ++} ++ ++static int sfc_write(struct sfc_flash *flash, loff_t to, size_t len, const unsigned char *buf) ++{ ++ int32_t ret; ++ ++ //memset(flash->sfc->desc, 0, sizeof(struct sfc_desc) * DESC_MAX_NUM); //1024 bytes space ++ ++ /* create DMA Descriptors */ ++ ret = create_sfc_desc(flash, (unsigned char *)buf, len); ++ if(ret < 0){ ++ dev_err(flash->dev, "%s create descriptors error. -%d\n", __func__, ret); ++ return ret; ++ } ++ ++ //dump_desc(flash->sfc, ret); ++ ++ /* DMA Descriptors write */ ++ ret = sfc_do_write(flash, (unsigned int)to, buf, len); ++ ++ return ret; ++} ++ ++static int ingenic_spi_norflash_read(struct mtd_info *mtd, loff_t from, size_t len,size_t *retlen, unsigned char *buf) ++{ ++ struct sfc_flash *flash = to_ingenic_spi_norflash(mtd); ++ ++ mutex_lock(&flash->lock); ++ *retlen = sfc_read(flash, from, len, buf); ++ mutex_unlock(&flash->lock); ++ ++ return 0; ++} ++ ++static int ingenic_spi_norflash_write(struct mtd_info *mtd, loff_t to, size_t len, ++ size_t *retlen, const unsigned char *buf) ++{ ++ u32 page_offset, actual_len; ++ struct sfc_flash *flash = to_ingenic_spi_norflash(mtd); ++ struct spinor_flashinfo *nor_info = flash->flash_info; ++ struct spi_nor_info *spi_nor_info = nor_info->nor_flash_info; ++ int ret; ++ ++ mutex_lock(&flash->lock); ++ ++ page_offset = to & (spi_nor_info->page_size - 1); ++ /* do all the bytes fit onto one page? */ ++ if (page_offset + len <= spi_nor_info->page_size) { ++ ret = sfc_write(flash, (unsigned int)to, len, buf); ++ *retlen = ret; ++ } else { ++ u32 i; ++ ++ /* the size of data remaining on the first page */ ++ actual_len = spi_nor_info->page_size - page_offset; ++ ret = sfc_write(flash, (unsigned int)to, actual_len, buf); ++ *retlen += ret; ++ ++ /* write everything in flash->page_size chunks */ ++ for (i = actual_len; i < len; i += mtd->writesize) { ++ actual_len = len - i; ++ if (actual_len >= mtd->writesize) ++ actual_len = mtd->writesize; ++ ++ ret = sfc_write(flash, (unsigned int)to + i, actual_len, buf + i); ++ *retlen += ret; ++ } ++ } ++ mutex_unlock(&flash->lock); ++ return 0; ++} ++ ++static int ingenic_spi_norflash_erase(struct mtd_info *mtd, struct erase_info *instr) ++{ ++ struct sfc_flash *flash = to_ingenic_spi_norflash(mtd); ++ struct spinor_flashinfo *nor_info = flash->flash_info; ++ struct spi_nor_info *spi_nor_info = nor_info->nor_flash_info; ++ uint32_t addr, end; ++ int ret; ++ ++ mutex_lock(&flash->lock); ++ ++ addr = (instr->addr & (mtd->erasesize - 1)); ++ if (addr) { ++ dev_err(flash->dev, "%s eraseaddr no align\n", __func__); ++ mutex_unlock(&flash->lock); ++ return -EINVAL; ++ } ++ end = (instr->len & (mtd->erasesize - 1)); ++ if (end) { ++ dev_err(flash->dev,"%s erasesize no align\n", __func__); ++ mutex_unlock(&flash->lock); ++ return -EINVAL; ++ } ++ addr = (uint32_t)instr->addr; ++ end = addr + (uint32_t)instr->len; ++ ++ while (addr < end) { ++ ret = sfc_do_erase(flash, addr, spi_nor_info->erase_size); ++ if (ret) { ++ dev_err(flash->dev,"erase error !\n"); ++ mutex_unlock(&flash->lock); ++ instr->state = MTD_ERASE_FAILED; ++ return ret; ++ } ++ addr += spi_nor_info->erase_size; ++ } ++ mutex_unlock(&flash->lock); ++ instr->state = MTD_ERASE_DONE; ++ ++ mtd_erase_callback(instr); ++ return 0; ++} ++#if 0 ++static int32_t ingenic_spi_norflash_read_params(struct sfc_flash *flash, loff_t from, size_t len, uint8_t *buf) ++{ ++ struct sfc_cdt_xfer xfer; ++ memset(&xfer, 0, sizeof(xfer)); ++ ++ xfer.cmd_index = NOR_READ_STANDARD; ++ ++ xfer.columnaddr = 0; ++ xfer.rowaddr = from; ++ ++ xfer.dataen = ENABLE; ++ xfer.config.datalen = len; ++ xfer.config.data_dir = GLB0_TRAN_DIR_READ; ++ xfer.config.ops_mode = CPU_OPS; ++ xfer.config.buf = buf; ++ ++ if(sfc_sync_cdt(flash->sfc, &xfer)) { ++ dev_err(flash->dev,"sfc_sync_cdt error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ return 0; ++} ++#endif ++#ifdef DEBUG_CLONER_PARAMS ++static void dump_cloner_params(struct burner_params *params) ++{ ++ struct spi_nor_info *spi_nor_info; ++ ++ spi_nor_info = ¶ms->spi_nor_info; ++ ++ printk("name=%s\n", spi_nor_info->name); ++ printk("id=0x%x\n", spi_nor_info->id); ++ ++ printk("read_standard->cmd=0x%x\n", spi_nor_info->read_standard.cmd); ++ printk("read_standard->dummy=0x%x\n", spi_nor_info->read_standard.dummy_byte); ++ printk("read_standard->addr_nbyte=0x%x\n", spi_nor_info->read_standard.addr_nbyte); ++ printk("read_standard->transfer_mode=0x%x\n", spi_nor_info->read_standard.transfer_mode); ++ ++ printk("read_quad->cmd=0x%x\n", spi_nor_info->read_quad.cmd); ++ printk("read_quad->dummy=0x%x\n", spi_nor_info->read_quad.dummy_byte); ++ printk("read_quad->addr_nbyte=0x%x\n", spi_nor_info->read_quad.addr_nbyte); ++ printk("read_quad->transfer_mode=0x%x\n", spi_nor_info->read_quad.transfer_mode); ++ ++ printk("write_standard->cmd=0x%x\n", spi_nor_info->write_standard.cmd); ++ printk("write_standard->dummy=0x%x\n", spi_nor_info->write_standard.dummy_byte); ++ printk("write_standard->addr_nbyte=0x%x\n", spi_nor_info->write_standard.addr_nbyte); ++ printk("write_standard->transfer_mode=0x%x\n", spi_nor_info->write_standard.transfer_mode); ++ ++ printk("write_quad->cmd=0x%x\n", spi_nor_info->write_quad.cmd); ++ printk("write_quad->dummy=0x%x\n", spi_nor_info->write_quad.dummy_byte); ++ printk("write_quad->addr_nbyte=0x%x\n", spi_nor_info->write_quad.addr_nbyte); ++ printk("write_quad->transfer_mode=0x%x\n", spi_nor_info->write_quad.transfer_mode); ++ ++ printk("sector_erase->cmd=0x%x\n", spi_nor_info->sector_erase.cmd); ++ printk("sector_erase->dummy=0x%x\n", spi_nor_info->sector_erase.dummy_byte); ++ printk("sector_erase->addr_nbyte=0x%x\n", spi_nor_info->sector_erase.addr_nbyte); ++ printk("sector_erase->transfer_mode=0x%x\n", spi_nor_info->sector_erase.transfer_mode); ++ ++ printk("wr_en->cmd=0x%x\n", spi_nor_info->wr_en.cmd); ++ printk("wr_en->dummy=0x%x\n", spi_nor_info->wr_en.dummy_byte); ++ printk("wr_en->addr_nbyte=0x%x\n", spi_nor_info->wr_en.addr_nbyte); ++ printk("wr_en->transfer_mode=0x%x\n", spi_nor_info->wr_en.transfer_mode); ++ ++ printk("en4byte->cmd=0x%x\n", spi_nor_info->en4byte.cmd); ++ printk("en4byte->dummy=0x%x\n", spi_nor_info->en4byte.dummy_byte); ++ printk("en4byte->addr_nbyte=0x%x\n", spi_nor_info->en4byte.addr_nbyte); ++ printk("en4byte->transfer_mode=0x%x\n", spi_nor_info->en4byte.transfer_mode); ++ ++ printk("quad_set->cmd=0x%x\n", spi_nor_info->quad_set.cmd); ++ printk("quad_set->bit_shift=0x%x\n", spi_nor_info->quad_set.bit_shift); ++ printk("quad_set->mask=0x%x\n", spi_nor_info->quad_set.mask); ++ printk("quad_set->val=0x%x\n", spi_nor_info->quad_set.val); ++ printk("quad_set->len=0x%x\n", spi_nor_info->quad_set.len); ++ printk("quad_set->dummy=0x%x\n", spi_nor_info->quad_set.dummy); ++ ++ printk("quad_get->cmd=0x%x\n", spi_nor_info->quad_get.cmd); ++ printk("quad_get->bit_shift=0x%x\n", spi_nor_info->quad_get.bit_shift); ++ printk("quad_get->mask=0x%x\n", spi_nor_info->quad_get.mask); ++ printk("quad_get->val=0x%x\n", spi_nor_info->quad_get.val); ++ printk("quad_get->len=0x%x\n", spi_nor_info->quad_get.len); ++ printk("quad_get->dummy=0x%x\n", spi_nor_info->quad_get.dummy); ++ ++ printk("busy->cmd=0x%x\n", spi_nor_info->busy.cmd); ++ printk("busy->bit_shift=0x%x\n", spi_nor_info->busy.bit_shift); ++ printk("busy->mask=0x%x\n", spi_nor_info->busy.mask); ++ printk("busy->val=0x%x\n", spi_nor_info->busy.val); ++ printk("busy->len=0x%x\n", spi_nor_info->busy.len); ++ printk("busy->dummy=0x%x\n", spi_nor_info->busy.dummy); ++ ++ printk("quad_ops_mode=%d\n", spi_nor_info->quad_ops_mode); ++ printk("addr_ops_mode=%d\n", spi_nor_info->addr_ops_mode); ++ ++ printk("tCHSH=%d\n", spi_nor_info->tCHSH); ++ printk("tSLCH=%d\n", spi_nor_info->tSLCH); ++ printk("tSHSL_RD=%d\n", spi_nor_info->tSHSL_RD); ++ printk("tSHSL_WR=%d\n", spi_nor_info->tSHSL_WR); ++ ++ printk("chip_size=%d\n", spi_nor_info->chip_size); ++ printk("page_size=%d\n", spi_nor_info->page_size); ++ printk("erase_size=%d\n", spi_nor_info->erase_size); ++ ++ printk("chip_erase_cmd=0x%x\n", spi_nor_info->chip_erase_cmd); ++} ++#endif ++ ++static int ingenic_spi_norflash_get_params(struct sfc_flash *flash, struct ingenic_sfc_info *pdata) ++{ ++ int i = 0; ++ int32_t err = 0; ++ unsigned int chip_id; ++ struct spinor_flashinfo *nor_info = flash->flash_info; ++ struct ingenic_sfc_info *ingenic_sfc_info = pdata; ++ ++ burner_params = kzalloc(sizeof(struct burner_params), GFP_KERNEL); ++ if (!burner_params) { ++ dev_err(flash->dev, "Failed to alloc mem for params\n"); ++ err = -ENOMEM; ++ goto err_params; ++ } ++ ++ chip_id = sfc_nor_read_id(flash); ++ burner_params->spi_nor_info_size = ARRAY_SIZE(spi_nor_info_table); ++ ++ for(i = 0; i < burner_params->spi_nor_info_size; i++) ++ { ++ if(chip_id == spi_nor_info_table[i].id) ++ { ++ if(spi_nor_info_table[i].addr_len == 4) ++ { ++ read_standard_table.addr_nbyte = 4; ++ read_quad_table.addr_nbyte = 4; ++ write_standard_table.addr_nbyte = 4; ++ write_quad_table.addr_nbyte = 4; ++ sector_erase_table_32k.addr_nbyte =4; ++ sector_erase_table_64k.addr_nbyte =4; ++ } ++ quad_set_table.cmd = spi_nor_info_table[i].quad_set.cmd; ++ quad_set_table.bit_shift = spi_nor_info_table[i].quad_set.bit_shift; ++ quad_get_table.cmd = spi_nor_info_table[i].quad_get.cmd; ++ quad_get_table.bit_shift = spi_nor_info_table[i].quad_get.bit_shift; ++ spi_nor_info_table[i].read_standard = read_standard_table; ++ spi_nor_info_table[i].read_quad = read_quad_table; ++ spi_nor_info_table[i].write_standard = write_standard_table; ++ spi_nor_info_table[i].write_quad = write_quad_table; ++ spi_nor_info_table[i].sector_erase_32k = sector_erase_table_32k; ++ spi_nor_info_table[i].sector_erase_64k = sector_erase_table_64k; ++ spi_nor_info_table[i].wr_en = wr_en_table; ++ spi_nor_info_table[i].en4byte = en4byte_table; ++ spi_nor_info_table[i].enotp = enotp_table; ++ spi_nor_info_table[i].exotp = exotp_table; ++ spi_nor_info_table[i].quad_set = quad_set_table; ++ spi_nor_info_table[i].quad_get = quad_get_table; ++ spi_nor_info_table[i].busy = busy_table; ++ burner_params->spi_nor_info = spi_nor_info_table[i]; ++ printk("the id code = %x, the flash name is %s\n", chip_id, spi_nor_info_table[i].name); ++ break; ++ } ++ } ++ ++ if(i == burner_params->spi_nor_info_size) ++ { ++ if((chip_id != 0)&&(chip_id != 0xff)) ++ { ++ printk("ingenic: Unsupported ID %x\n", chip_id); ++ return EINVAL; ++ }else{ ++ printk("read or write error! Unsupported ID %x\n", chip_id); ++ return EINVAL; ++ } ++ } ++ ++#if 0 ++ ret = jz_spi_norflash_read_params(flash, SPIFLASH_PARAMER_OFFSET, sizeof(struct burner_params), (uint8_t *)burner_params); ++ if (ret) { ++ dev_err(flash->dev, "Failed to read params (burned by Burner)\n"); ++ err = -EINVAL; ++ goto err_read_params; ++ } ++#endif ++ ++ //add crc check for params ++ nor_info->nor_flash_info = NULL; ++ nor_info->nor_flash_info = &burner_params->spi_nor_info; ++#if 0 ++ nor_info->norflash_partitions = &burner_params->norflash_partitions; ++ nor_info->nor_pri_data = &burner_params->nor_pri_data; ++#endif ++ if (ingenic_sfc_info && ingenic_sfc_info->use_board_info) { ++ printk("use_board_info is set!!!\n"); ++ if (ingenic_sfc_info->flash_param) ++ nor_info->nor_flash_info = ingenic_sfc_info->flash_param; ++ if (ingenic_sfc_info->flash_partition) { ++ nor_info->norflash_partitions->num_partition_info = ingenic_sfc_info->num_partition; ++ memcpy(nor_info->norflash_partitions->nor_partition, ingenic_sfc_info->flash_partition, sizeof(struct nor_partition) * ingenic_sfc_info->num_partition); ++ } ++ } ++ ++ if ((!nor_info->nor_flash_info)) { ++ printk("WARNING : cannot get nor flash params !!!\n"); ++ err = -EINVAL; ++ goto err_read_params; ++ } ++ ++#ifdef DEBUG_CLONER_PARAMS ++ dump_cloner_params(burner_params); ++#endif ++ return 0; ++err_read_params: ++ kfree(burner_params); ++err_params: ++ return err; ++} ++static ssize_t sfc_nor_partition_offset_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ return sprintf(buf,"0x%x\n", SPIFLASH_PARAMER_OFFSET + sizeof(int) * 2 + sizeof(struct spi_nor_info)); ++} ++ ++static DEVICE_ATTR(sfc_nor_partition_offset, S_IRUGO | S_IWUSR, ++ sfc_nor_partition_offset_show, ++ NULL); ++ ++static ssize_t sfc_nor_params_offset_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ return sprintf(buf,"0x%x\n",SPIFLASH_PARAMER_OFFSET); ++} ++ ++static DEVICE_ATTR(sfc_nor_params_offset, S_IRUGO | S_IWUSR, ++ sfc_nor_params_offset_show, ++ NULL); ++ ++/*add your attr in here*/ ++static struct attribute *sfc_norflash_info_attributes[] = { ++ &dev_attr_sfc_nor_partition_offset.attr, ++ &dev_attr_sfc_nor_params_offset.attr, ++ NULL ++}; ++ ++static const struct attribute_group sfc_norflash_info_attr_group = { ++ .attrs = sfc_norflash_info_attributes ++}; ++ ++/* ++ *MK_CMD(cdt, cmd, LINK, ADDRMODE, DATA_EN) ++ *MK_ST(cdt, st, LINK, ADDRMODE, ADDR_WIDTH, POLL_EN, DATA_EN, TRAN_MODE) ++ */ ++static void params_to_cdt(struct spi_nor_info *params, struct sfc_cdt *cdt) ++{ ++ /* 4.nor singleRead */ ++ MK_CMD(cdt[NOR_READ_STANDARD], params->read_standard, 0, ROW_ADDR, ENABLE); ++ ++ /* 5.nor quadRead */ ++ MK_CMD(cdt[NOR_READ_QUAD], params->read_quad, 0, ROW_ADDR, ENABLE); ++ ++ /* 6. nor writeStandard */ ++ MK_CMD(cdt[NOR_WRITE_STANDARD_ENABLE], params->wr_en, 1, DEFAULT_ADDRMODE, DISABLE); ++ MK_CMD(cdt[NOR_WRITE_STANDARD], params->write_standard, 1, ROW_ADDR, ENABLE); ++ MK_ST(cdt[NOR_WRITE_STANDARD_FINISH], params->busy, 0, DEFAULT_ADDRMODE, 0, ENABLE, DISABLE, TM_STD_SPI); ++ ++ /* 7. nor writeQuad */ ++ MK_CMD(cdt[NOR_WRITE_QUAD_ENABLE], params->wr_en, 1, DEFAULT_ADDRMODE, DISABLE); ++ MK_CMD(cdt[NOR_WRITE_QUAD], params->write_quad, 1, ROW_ADDR, ENABLE); ++ MK_ST(cdt[NOR_WRITE_QUAD_FINISH], params->busy, 0, DEFAULT_ADDRMODE, 0, ENABLE, DISABLE, TM_STD_SPI); ++ ++ /* 8. nor erase */ ++ MK_CMD(cdt[NOR_ERASE_WRITE_ENABLE_32K], params->wr_en, 1, DEFAULT_ADDRMODE, DISABLE); ++ MK_CMD(cdt[NOR_ERASE_32K], params->sector_erase_32k, 1, ROW_ADDR, DISABLE); ++ MK_ST(cdt[NOR_ERASE_FINISH_32K], params->busy, 0, DEFAULT_ADDRMODE, 0, ENABLE, DISABLE, TM_STD_SPI); ++ ++ MK_CMD(cdt[NOR_ERASE_WRITE_ENABLE_64K], params->wr_en, 1, DEFAULT_ADDRMODE, DISABLE); ++ MK_CMD(cdt[NOR_ERASE_64K], params->sector_erase_64k, 1, ROW_ADDR, DISABLE); ++ MK_ST(cdt[NOR_ERASE_FINISH_64K], params->busy, 0, DEFAULT_ADDRMODE, 0, ENABLE, DISABLE, TM_STD_SPI); ++ ++ /* 9. quad mode */ ++ if(params->quad_ops_mode){ ++ printk("params->otp_ops_mode = %d\n",params->otp_ops_mode); ++ if(!params->otp_ops_mode){ ++ MK_CMD(cdt[NOR_QUAD_SET_ENABLE], params->wr_en, 1, DEFAULT_ADDRMODE, DISABLE); ++ MK_ST(cdt[NOR_QUAD_SET], params->quad_set, 1, DEFAULT_ADDRMODE, 0, DISABLE, ENABLE, TM_STD_SPI); //disable poll, enable data ++ ++ MK_ST(cdt[NOR_QUAD_FINISH], params->busy, 1, DEFAULT_ADDRMODE, 0, ENABLE, DISABLE, TM_STD_SPI); ++ ++ MK_ST(cdt[NOR_QUAD_GET], params->quad_get, 0, DEFAULT_ADDRMODE, 0, ENABLE, DISABLE, TM_STD_SPI); ++ ++ } else { ++ MK_CMD(cdt[NOR_ENTER_OTP], params->enotp, 1, DEFAULT_ADDRMODE, DISABLE); ++ ++ MK_CMD(cdt[NOR_OTP_QUAD_SET_ENABLE], params->wr_en, 1, DEFAULT_ADDRMODE, DISABLE); ++ MK_ST(cdt[NOR_OTP_QUAD_SET], params->quad_set, 1, DEFAULT_ADDRMODE, 0, DISABLE, ENABLE, TM_STD_SPI); //disable poll, enable data ++ ++ MK_ST(cdt[NOR_OTP_QUAD_FINISH], params->busy, 1, DEFAULT_ADDRMODE, 0, ENABLE, DISABLE, TM_STD_SPI); ++ ++ MK_ST(cdt[NOR_OTP_QUAD_GET], params->quad_get, 1, DEFAULT_ADDRMODE, 0, ENABLE, DISABLE, TM_STD_SPI); ++ ++ MK_CMD(cdt[NOR_EXIT_OTP], params->exotp, 0, DEFAULT_ADDRMODE, DISABLE); ++ } ++ } ++ ++ /* 10. nor write ENABLE */ ++ MK_CMD(cdt[NOR_WRITE_ENABLE], params->wr_en, 0, DEFAULT_ADDRMODE, DISABLE); ++ ++ /* 11. entry 4byte mode */ ++ MK_CMD(cdt[NOR_EN_4BYTE], params->en4byte, 0, DEFAULT_ADDRMODE, DISABLE); ++ ++} ++ ++static void create_cdt_table(struct sfc_flash *flash, uint32_t flag) ++{ ++ struct spinor_flashinfo *nor_info = flash->flash_info; ++ struct spi_nor_info *nor_flash_info; ++ struct sfc_cdt sfc_cdt[INDEX_MAX_NUM]; ++ ++ memset(sfc_cdt, 0, sizeof(sfc_cdt)); ++ ++ /* 1.nor reset */ ++ sfc_cdt[NOR_RESET_ENABLE].link = CMD_LINK(1, DEFAULT_ADDRMODE, TM_STD_SPI); ++ sfc_cdt[NOR_RESET_ENABLE].xfer = CMD_XFER(0, DISABLE, 0, DISABLE, SPINOR_OP_RSTEN); ++ sfc_cdt[NOR_RESET_ENABLE].staExp = 0; ++ sfc_cdt[NOR_RESET_ENABLE].staMsk = 0; ++ ++ sfc_cdt[NOR_RESET].link = CMD_LINK(0, DEFAULT_ADDRMODE, TM_STD_SPI); ++ sfc_cdt[NOR_RESET].xfer = CMD_XFER(0, DISABLE, 0, DISABLE, SPINOR_OP_RST); ++ sfc_cdt[NOR_RESET].staExp = 0; ++ sfc_cdt[NOR_RESET].staMsk = 0; ++ ++ ++ /* 2.nor read id */ ++ sfc_cdt[NOR_READ_ID].link = CMD_LINK(0, DEFAULT_ADDRMODE, TM_STD_SPI); ++ sfc_cdt[NOR_READ_ID].xfer = CMD_XFER(0, DISABLE, 0, ENABLE, SPINOR_OP_RDID); ++ sfc_cdt[NOR_READ_ID].staExp = 0; ++ sfc_cdt[NOR_READ_ID].staMsk = 0; ++ ++ ++ /* 3. nor get status */ ++ sfc_cdt[NOR_GET_STATUS].link = CMD_LINK(0, DEFAULT_ADDRMODE, TM_STD_SPI); ++ sfc_cdt[NOR_GET_STATUS].xfer = CMD_XFER(0, DISABLE, 0, ENABLE, SPINOR_OP_RDSR); ++ sfc_cdt[NOR_GET_STATUS].staExp = 0; ++ sfc_cdt[NOR_GET_STATUS].staMsk = 0; ++ ++ sfc_cdt[NOR_GET_STATUS_1].link = CMD_LINK(0, DEFAULT_ADDRMODE, TM_STD_SPI); ++ sfc_cdt[NOR_GET_STATUS_1].xfer = CMD_XFER(0, DISABLE, 0, ENABLE, SPINOR_OP_RDSR_1); ++ sfc_cdt[NOR_GET_STATUS_1].staExp = 0; ++ sfc_cdt[NOR_GET_STATUS_1].staMsk = 0; ++ ++ sfc_cdt[NOR_GET_STATUS_2].link = CMD_LINK(0, DEFAULT_ADDRMODE, TM_STD_SPI); ++ sfc_cdt[NOR_GET_STATUS_2].xfer = CMD_XFER(0, DISABLE, 0, ENABLE, SPINOR_OP_RDSR_2); ++ sfc_cdt[NOR_GET_STATUS_2].staExp = 0; ++ sfc_cdt[NOR_GET_STATUS_2].staMsk = 0; ++ ++ if(flag == DEFAULT_CDT){ ++ /* 4.nor singleRead */ ++ sfc_cdt[NOR_READ_STANDARD].link = CMD_LINK(0, ROW_ADDR, TM_STD_SPI); ++ sfc_cdt[NOR_READ_STANDARD].xfer = CMD_XFER(DEFAULT_ADDRSIZE, DISABLE, 0, ENABLE, SPINOR_OP_READ); ++ sfc_cdt[NOR_READ_STANDARD].staExp = 0; ++ sfc_cdt[NOR_READ_STANDARD].staMsk = 0; ++ ++ /* first create cdt table */ ++ write_cdt(flash->sfc, sfc_cdt, NOR_RESET_ENABLE, NOR_READ_STANDARD); ++ } ++ ++ ++ if(flag == UPDATE_CDT){ ++ nor_flash_info = nor_info->nor_flash_info; ++ params_to_cdt(nor_flash_info, sfc_cdt); ++ ++ /* second create cdt table */ ++ write_cdt(flash->sfc, sfc_cdt, NOR_READ_STANDARD, NOR_EN_4BYTE); ++ } ++ //dump_cdt(flash->sfc); ++} ++ ++static int request_sfc_desc(struct sfc_flash *flash) ++{ ++ struct sfc *sfc = flash->sfc; ++ sfc->desc = (struct sfc_desc *)dma_alloc_coherent(flash->dev, sizeof(struct sfc_desc) * DESC_MAX_NUM, &sfc->desc_pyaddr, GFP_KERNEL); ++ if(flash->sfc->desc == NULL){ ++ return -ENOMEM; ++ } ++ sfc->desc_max_num = DESC_MAX_NUM; ++ ++ return 0; ++} ++ ++static int __init ingenic_sfc_probe(struct platform_device *pdev) ++{ ++ struct sfc_flash *flash; ++ int err = 0,ret = 0; ++ struct spinor_flashinfo *nor_info; ++ struct ingenic_sfc_info *pdata_params; ++ int tchsh; ++ int tslch; ++ int tshsl_rd; ++ int tshsl_wr; ++ ++ flash = kzalloc(sizeof(struct sfc_flash), GFP_KERNEL); ++ if (flash == NULL) { ++ dev_err(&pdev->dev, "Failed to alloc mem for flash\n"); ++ return -ENOMEM; ++ } ++ ++ nor_info = kzalloc(sizeof(*nor_info), GFP_KERNEL); ++ if(!nor_info) { ++ dev_err(&pdev->dev, "alloc nor_info failed!\n"); ++ kfree(flash); ++ return -ENOMEM; ++ } ++ flash->flash_info = nor_info; ++ ++ flash->dev = &pdev->dev; ++ ++ flash->sfc = sfc_res_init(pdev); ++ if(IS_ERR_OR_NULL(flash->sfc)) { ++ ret = -ENOMEM; ++ goto err_sfc_res_init; ++ } ++ ++ platform_set_drvdata(pdev, flash); ++ mutex_init(&flash->lock); ++ ++ set_flash_timing(flash->sfc, DEF_TCHSH, DEF_TSLCH, DEF_TSHSL_R, DEF_TSHSL_W); ++ ++ /* request DMA Descriptor space */ ++ ret = request_sfc_desc(flash); ++ if(ret){ ++ dev_err(flash->dev, "Failure to request DMA descriptor space!\n"); ++ ret = -ENOMEM; ++ goto err_sfc_desc_request; ++ } ++ ++ /* try creating default CDT table */ ++ create_cdt_table(flash, DEFAULT_CDT); ++ ++ ret = sfc_nor_reset(flash); ++ if(ret) { ++ dev_warn(flash->dev, "Failed to reset nor flash, Try to go on\n"); ++ } ++ ++ pdata_params = pdev->dev.platform_data; ++ ret = ingenic_spi_norflash_get_params(flash, pdata_params); ++ if (ret) { ++ ret = -ENODEV; ++ dev_err(flash->dev, "Failed to match correct nor flash device!\n"); ++ goto err_match_device; ++ } ++ ++ /* Update to private CDT table */ ++ create_cdt_table(flash, UPDATE_CDT); ++ ++ flash->mtd.name = "jz_sfc"; ++ flash->mtd.owner = THIS_MODULE; ++ flash->mtd.type = MTD_NORFLASH; ++ flash->mtd.flags = MTD_CAP_NORFLASH; ++ flash->mtd.erasesize = nor_info->nor_flash_info->erase_size; ++ flash->mtd.writesize = nor_info->nor_flash_info->page_size; ++ flash->mtd.size = nor_info->nor_flash_info->chip_size; ++ flash->mtd._erase = ingenic_spi_norflash_erase; ++ flash->mtd._read = ingenic_spi_norflash_read; ++ flash->mtd._write = ingenic_spi_norflash_write; ++ ++ tchsh = nor_info->nor_flash_info->tCHSH; ++ tslch = nor_info->nor_flash_info->tSLCH; ++ tshsl_rd = nor_info->nor_flash_info->tSHSL_RD; ++ tshsl_wr = nor_info->nor_flash_info->tSHSL_WR; ++ set_flash_timing(flash->sfc, tchsh, tslch, tshsl_rd, tshsl_wr); ++ ++ sfc_nor_get_special_ops(flash); ++ ++#ifdef CONFIG_SPI_STANDARD_MODE ++ nor_info->quad_succeed = 0; ++ dev_info(&pdev->dev, "nor flash now use standard mode!\n"); ++#else ++ ret = nor_info->nor_flash_ops->set_quad_mode(flash); ++ if (ret < 0) { ++ nor_info->quad_succeed = 0; ++ dev_info(&pdev->dev, "set quad mode error !\n"); ++ } else { ++ nor_info->quad_succeed = 1; ++ dev_info(&pdev->dev, "nor flash quad mode is set, now use quad mode!\n"); ++ } ++#endif ++ ++ /* if nor flash size is greater than 16M, use 4byte mode */ ++ if(flash->mtd.size > NOR_SIZE_16M) { ++ if (nor_info->nor_flash_ops->set_4byte_mode) { ++ nor_info->nor_flash_ops->set_4byte_mode(flash); ++ } ++ } ++ ++ ret = mtd_device_parse_register(&flash->mtd, NULL, NULL, NULL, 0); ++ if (ret) { ++ ret = -ENODEV; ++ dev_err(flash->dev, "Failed to parse register!\n"); ++ goto err_parse_register; ++ } ++ ++ ret = sysfs_create_group(&pdev->dev.kobj, &sfc_norflash_info_attr_group); ++ if (err) { ++ dev_err(&pdev->dev, "failed to register sysfs\n"); ++ ret = -EIO; ++ goto err_create_group; ++ } ++ ++ dev_info(&pdev->dev,"SPI NOR MTD LOAD OK\n"); ++ return 0; ++ ++err_create_group: ++ mtd_device_unregister(&flash->mtd); ++err_parse_register: ++ kfree(burner_params); ++err_match_device: ++err_sfc_desc_request: ++ dma_free_coherent(flash->dev, sizeof(struct sfc_desc) * DESC_MAX_NUM, flash->sfc->desc, flash->sfc->desc_pyaddr); ++err_sfc_res_init: ++ kfree(nor_info); ++ kfree(flash); ++ return ret; ++ ++} ++ ++static int __exit ingenic_sfc_remove(struct platform_device *pdev) ++{ ++ struct sfc_flash *flash = platform_get_drvdata(pdev); ++ struct sfc *sfc = flash->sfc; ++ ++ clk_disable_unprepare(sfc->clk_gate); ++ clk_put(sfc->clk_gate); ++ ++ clk_disable_unprepare(sfc->clk); ++ clk_put(sfc->clk); ++ ++ free_irq(sfc->irq, flash); ++ iounmap(sfc->iomem); ++ release_mem_region(sfc->ioarea->start, resource_size(sfc->ioarea)); ++ ++ platform_set_drvdata(pdev, NULL); ++ sysfs_remove_group(&pdev->dev.kobj, &sfc_norflash_info_attr_group); ++ return 0; ++} ++ ++static int ingenic_sfc_suspend(struct platform_device *pdev, pm_message_t msg) ++{ ++ struct sfc_flash *flash = platform_get_drvdata(pdev); ++ struct sfc *sfc = flash->sfc; ++#ifdef CONFIG_ENABLE_DEEP_POWER_DOWN ++ { ++ struct sfc_transfer transfer; ++ int ret; ++ ++ memset(&transfer, 0, sizeof(transfer)); ++ sfc_list_init(&transfer); ++ ++ transfer.cmd_info.cmd = CMD_DP; ++ transfer.cmd_info.dataen = DISABLE; ++ ret = sfc_sync(sfc, &transfer); ++ if(ret) { ++ dev_err(flash->dev,"sfc_sync error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ } ++ udelay(10); ++ } ++#endif ++ ++ disable_irq(sfc->irq); ++ clk_disable_unprepare(sfc->clk_gate); ++ clk_disable_unprepare(sfc->clk); ++ ++ return 0; ++} ++ ++static int ingenic_sfc_resume(struct platform_device *pdev) ++{ ++ struct sfc_flash *flash = platform_get_drvdata(pdev); ++ struct sfc *sfc = flash->sfc; ++ ++ clk_prepare_enable(sfc->clk); ++ clk_prepare_enable(sfc->clk_gate); ++ ++ enable_irq(sfc->irq); ++#ifdef CONFIG_ENABLE_DEEP_POWER_DOWN ++ { ++ struct sfc_transfer transfer; ++ int ret; ++ ++ memset(&transfer, 0, sizeof(transfer)); ++ sfc_list_init(&transfer); ++ ++ transfer.cmd_info.cmd = CMD_RDP; ++ transfer.cmd_info.dataen = DISABLE; ++ ret = sfc_sync(sfc, &transfer); ++ if(ret) { ++ dev_err(flash->dev,"sfc_sync error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ } ++ udelay(60); ++ } ++#endif ++ return 0; ++} ++ ++void ingenic_sfc_shutdown(struct platform_device *pdev) ++{ ++ struct sfc_flash *flash = platform_get_drvdata(pdev); ++ struct sfc *sfc = flash->sfc; ++ ++ disable_irq(sfc->irq); ++ clk_disable_unprepare(sfc->clk_gate); ++ clk_disable_unprepare(sfc->clk); ++ return ; ++} ++ ++static const struct of_device_id ingenicsfc_match[] = { ++ { .compatible = "ingenic,sfc", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ingenicsfc_match); ++ ++static struct platform_driver ingenic_sfcdrv = { ++ .driver = { ++ .name = "ingenic-sfc", ++ .owner = THIS_MODULE, ++ .of_match_table = ingenicsfc_match, ++ }, ++ .remove = __exit_p(ingenic_sfc_remove), ++ .suspend = ingenic_sfc_suspend, ++ .resume = ingenic_sfc_resume, ++// .shutdown = ingenic_sfc_shutdown, ++}; ++module_platform_driver_probe(ingenic_sfcdrv, ingenic_sfc_probe); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("INGENIC SFC Driver"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_ingenic_sfc_ops.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_ingenic_sfc_ops.c.patch new file mode 100644 index 00000000..b2272198 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_ingenic_sfc_ops.c.patch @@ -0,0 +1,233 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_ops.c b/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_ops.c +--- a/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_ops.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_ops.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,229 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "spinor.h" ++#include "ingenic_sfc_common.h" ++ ++int get_status(struct sfc_flash *flash, int command, int len) ++{ ++ struct spinor_flashinfo *nor_info = flash->flash_info; ++ struct spi_nor_info *spi_nor_info = nor_info->nor_flash_info; ++ struct spi_nor_st_info *quad_get; ++ struct spi_nor_st_info *busy; ++ struct sfc_cdt_xfer xfer; ++ static unsigned char buf[32]; ++ unsigned int val = 0, i = 0, ret = 0; ++ ++ busy = &spi_nor_info->busy; ++ quad_get = &spi_nor_info->quad_get; ++ ++ memset(&xfer, 0, sizeof(xfer)); ++ memset(buf, 0, sizeof(buf)); ++ ++ /* set index */ ++ if(command == busy->cmd) ++ xfer.cmd_index = NOR_GET_STATUS; ++ else if(command == quad_get->cmd) ++ xfer.cmd_index = NOR_GET_STATUS_1; ++ else ++ xfer.cmd_index = NOR_GET_STATUS_2; ++ ++ /* set addr */ ++ xfer.rowaddr = 0; ++ xfer.columnaddr = 0; ++ ++ /* set transfer config */ ++ xfer.dataen = ENABLE; ++ xfer.config.datalen = len; ++ xfer.config.data_dir = GLB0_TRAN_DIR_READ; ++ xfer.config.ops_mode = CPU_OPS; ++ xfer.config.buf = buf; ++ ++ if(sfc_sync_cdt(flash->sfc, &xfer)) { ++ printk("sfc_sync error! %s %s %d\n", __FILE__, __func__, __LINE__); ++ ret = -EIO; ++ } ++ ++ for(i = 0; i < len; i++) { ++ val |= buf[i] << (i * 8); ++ } ++ ++ return val; ++} ++ ++/* do nothing to set quad mode, use cmd directly */ ++static int set_quad_mode_cmd(struct sfc_flash *flash) ++{ ++ return 0; ++} ++ ++/* write nor flash status register QE bit to set quad mode */ ++static int set_quad_mode_reg(struct sfc_flash *flash) ++{ ++ struct spinor_flashinfo *nor_info = flash->flash_info; ++ struct spi_nor_info *spi_nor_info = nor_info->nor_flash_info; ++ struct spi_nor_st_info *quad_set; ++ struct spi_nor_st_info *quad_get; ++ struct spi_nor_st_info *busy; ++ unsigned int data; ++ unsigned short otp_mode; ++ struct sfc_cdt_xfer xfer; ++ int ret = 0; ++ ++ busy = &spi_nor_info->busy; ++ quad_set = &spi_nor_info->quad_set; ++ quad_get = &spi_nor_info->quad_get; ++ data = (quad_set->val & quad_set->mask) << quad_set->bit_shift; ++ otp_mode = spi_nor_info->otp_ops_mode; ++ memset(&xfer, 0, sizeof(xfer)); ++ ++ /* set index */ ++ if(!otp_mode) ++ xfer.cmd_index = NOR_QUAD_SET_ENABLE; ++ else ++ xfer.cmd_index = NOR_OTP_QUAD_SET_ENABLE; ++ ++ /* set addr */ ++ xfer.columnaddr = 0; ++ xfer.rowaddr = 0; ++ ++ /* set transfer config */ ++ xfer.dataen = ENABLE; ++ xfer.config.datalen = quad_set->len; ++ xfer.config.data_dir = GLB0_TRAN_DIR_WRITE; ++ xfer.config.ops_mode = CPU_OPS; ++ xfer.config.buf = (uint8_t *)&data; ++ ++ if(sfc_sync_cdt(flash->sfc, &xfer)) { ++ printk("sfc_sync error! %s %s %d\n", __FILE__, __func__, __LINE__); ++ ret = -EIO; ++ } ++ ++ return ret; ++} ++ ++static int write_enable(struct sfc_flash *flash) ++{ ++ struct sfc_cdt_xfer xfer; ++ int32_t ret = 0; ++ ++ memset(&xfer, 0, sizeof(xfer)); ++ ++ /* set index */ ++ xfer.cmd_index = NOR_WRITE_ENABLE; ++ ++ /* set addr */ ++ xfer.columnaddr = 0; ++ ++ /* set transfer config */ ++ xfer.dataen = DISABLE; ++ ++ if(sfc_sync_cdt(flash->sfc, &xfer)) { ++ printk("sfc_sync error! %s %s %d\n", __FILE__, __func__, __LINE__); ++ ret = -EIO; ++ } ++ ++ return ret; ++} ++ ++static int enter_4byte(struct sfc_flash *flash) ++{ ++ struct sfc_cdt_xfer xfer; ++ int32_t ret = 0; ++ ++ memset(&xfer, 0, sizeof(xfer)); ++ ++ /* set index */ ++ xfer.cmd_index = NOR_EN_4BYTE; ++ ++ /* set addr */ ++ xfer.columnaddr = 0; ++ ++ /* set transfer config */ ++ xfer.dataen = DISABLE; ++ ++ if(sfc_sync_cdt(flash->sfc, &xfer)) { ++ printk("sfc_sync error! %s %s %d\n", __FILE__, __func__, __LINE__); ++ ret = -EIO; ++ } ++ ++ return ret; ++} ++ ++/* send 4byte command to enter 4byte mode */ ++static int set_4byte_mode_normal(struct sfc_flash *flash) ++{ ++ int ret; ++ ret = enter_4byte(flash); ++ if (ret) { ++ dev_err(flash->dev, "enter 4byte mode failed\n"); ++ } ++ return ret; ++} ++ ++/** ++ * 1.send write enable command ++ * 2.send 4byte command to enter 4byte mode ++ **/ ++static int set_4byte_mode_wren(struct sfc_flash *flash) ++{ ++ int ret; ++ ret = write_enable(flash); ++ if (ret) { ++ dev_err(flash->dev, "enter 4byte mode failed\n"); ++ return ret; ++ } ++ ++ ret = enter_4byte(flash); ++ if (ret) { ++ dev_err(flash->dev, "enter 4byte mode failed\n"); ++ } ++ return ret; ++} ++ ++ ++static struct spi_nor_flash_ops nor_flash_ops; ++ ++static int noop(struct sfc_flash *flash) ++{ ++ return 0; ++} ++ ++int sfc_nor_get_special_ops(struct sfc_flash *flash) ++{ ++ struct spinor_flashinfo *nor_info = flash->flash_info; ++ struct spi_nor_info *spi_nor_info = nor_info->nor_flash_info; ++ ++ switch (spi_nor_info->quad_ops_mode) { ++ case 0: ++ nor_flash_ops.set_quad_mode = set_quad_mode_cmd; ++ break; ++ case 1: ++ nor_flash_ops.set_quad_mode = set_quad_mode_reg; ++ break; ++ default: ++ nor_flash_ops.set_quad_mode = noop; ++ break; ++ } ++ ++ switch (spi_nor_info->addr_ops_mode) { ++ case 0: ++ nor_flash_ops.set_4byte_mode = noop; ++ break; ++ case 1: ++ nor_flash_ops.set_4byte_mode = set_4byte_mode_wren; ++ break; ++ default: ++ nor_flash_ops.set_4byte_mode = noop; ++ break; ++ } ++ ++ nor_info->nor_flash_ops = &nor_flash_ops; ++ ++ return 0; ++} ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_Makefile.patch new file mode 100644 index 00000000..e84c6450 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_Makefile.patch @@ -0,0 +1,6 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v2/nand_device/Makefile b/drivers/mtd/devices/ingenic_sfc_v2/nand_device/Makefile +--- a/drivers/mtd/devices/ingenic_sfc_v2/nand_device/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v2/nand_device/Makefile 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,2 @@ ++obj-y += ato_nand.o gd_nand.o mxic_nand.o xtx_nand.o dosilicon_nand.o foresee_nand.o xtx_mid0b_nand.o zetta_nand.o esmt_mid2c_nand.o micron_nand.o winbond_nand.o ++obj-y += nand_common.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_ato_nand.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_ato_nand.c.patch new file mode 100644 index 00000000..a1946e37 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_ato_nand.c.patch @@ -0,0 +1,109 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v2/nand_device/ato_nand.c b/drivers/mtd/devices/ingenic_sfc_v2/nand_device/ato_nand.c +--- a/drivers/mtd/devices/ingenic_sfc_v2/nand_device/ato_nand.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v2/nand_device/ato_nand.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,105 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../spinand.h" ++#include "../ingenic_sfc_common.h" ++#include "nand_common.h" ++ ++#define ATO_DEVICES_NUM 1 ++#define TSETUP 5 ++#define THOLD 5 ++#define TSHSL_R 30 ++#define TSHSL_W 30 ++ ++#define TRD 25 ++#define TPP 500 ++#define TBE 3 ++ ++static struct ingenic_sfcnand_device *ato_nand; ++ ++static struct ingenic_sfcnand_base_param ato25d1ga_param = { ++ ++ .pagesize = 2 * 1024, ++ .oobsize = 64, ++ .blocksize = 2 * 1024 * 64, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0,//0x3, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .need_quad = 0, ++#else ++ .need_quad = 1, ++#endif ++ ++}; ++ ++static struct device_id_struct device_id[ATO_DEVICES_NUM] = { ++ DEVICE_ID_STRUCT(0x12, "ATO25D1GA", &ato25d1ga_param), ++}; ++ ++ ++static cdt_params_t *ato_get_cdt_params(struct sfc_flash *flash, uint8_t device_id) ++{ ++ CDT_PARAMS_INIT(ato_nand->cdt_params); ++ ++ switch(device_id) { ++ case 0x12: ++ break; ++ default: ++ dev_err(flash->dev, "device_id err, please check your device id: device_id = 0x%02x\n", device_id); ++ return NULL; ++ } ++ ++ return &ato_nand->cdt_params; ++} ++ ++ ++static inline int deal_ecc_status(struct sfc_flash *flash, uint8_t device_id, uint8_t ecc_status) ++{ ++ int ret = 0; ++ switch(device_id) { ++ case 0x12: ++ return 0; ++ default: ++ dev_err(flash->dev, "device_id err,it maybe don`t support this device, please check your device id: device_id = 0x%02x\n", device_id); ++ return -EIO; //notice!!! ++ } ++ return ret; ++} ++ ++ ++static int __init ato_nand_init(void) { ++ ++ ato_nand = kzalloc(sizeof(*ato_nand), GFP_KERNEL); ++ if(!ato_nand) { ++ pr_err("alloc ato_nand struct fail\n"); ++ return -ENOMEM; ++ } ++ ++ ato_nand->id_manufactory = 0x9B; ++ ato_nand->id_device_list = device_id; ++ ato_nand->id_device_count = ATO_DEVICES_NUM; ++ ++ ato_nand->ops.get_cdt_params = ato_get_cdt_params; ++ ato_nand->ops.deal_ecc_status = deal_ecc_status; ++ ++ /* use private get feature interface, please define it in this document */ ++ ato_nand->ops.get_feature = NULL; ++ ++ return ingenic_sfcnand_register(ato_nand); ++} ++ ++fs_initcall(ato_nand_init); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_dosilicon_nand.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_dosilicon_nand.c.patch new file mode 100644 index 00000000..689fdbd7 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_dosilicon_nand.c.patch @@ -0,0 +1,171 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v2/nand_device/dosilicon_nand.c b/drivers/mtd/devices/ingenic_sfc_v2/nand_device/dosilicon_nand.c +--- a/drivers/mtd/devices/ingenic_sfc_v2/nand_device/dosilicon_nand.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v2/nand_device/dosilicon_nand.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,167 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../spinand.h" ++#include "../ingenic_sfc_common.h" ++#include "nand_common.h" ++ ++#define DOSILICON_DEVICES_NUM 2 ++#define THOLD 5 ++#define TSETUP 5 ++#define TSHSL_R 100 ++#define TSHSL_W 100 ++ ++#define TRD 90 ++#define TPP 700 ++#define TBE 10 ++ ++struct ingenic_sfcnand_device *dosilicon_nand; ++ ++static struct ingenic_sfcnand_base_param dosilicon_param[DOSILICON_DEVICES_NUM] = { ++ [0] = { ++ /*DS35X1GAXXX*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ ++ .tHOLD = THOLD, ++ .tSETUP = TSETUP, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = 70, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x4, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .need_quad = 0, ++#else ++ .need_quad = 1, ++#endif ++ }, ++ [1] = { ++ /*DS35Q2GAXXX*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 2048, ++ ++ .tHOLD = THOLD, ++ .tSETUP = TSETUP, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = 90, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 1, ++ .ecc_max = 0x4, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .need_quad = 0, ++#else ++ .need_quad = 1, ++#endif ++ }, ++}; ++ ++static struct device_id_struct device_id[DOSILICON_DEVICES_NUM] = { ++ DEVICE_ID_STRUCT(0x71, "DS35X1GAXXX", &dosilicon_param[0]), ++ DEVICE_ID_STRUCT(0x72, "DS35Q2GAXXX", &dosilicon_param[1]), ++}; ++ ++ ++static cdt_params_t *dosilicon_get_cdt_params(struct sfc_flash *flash, uint8_t device_id) ++{ ++ CDT_PARAMS_INIT(dosilicon_nand->cdt_params); ++ ++ switch(device_id) { ++ case 0x71: ++ case 0x72: ++ break; ++ default: ++ dev_err(flash->dev, "device_id err, please check your device id: device_id = 0x%02x\n", device_id); ++ return NULL; ++ } ++ ++ return &dosilicon_nand->cdt_params; ++} ++ ++ ++static inline int deal_ecc_status(struct sfc_flash *flash, uint8_t device_id, uint8_t ecc_status) ++{ ++ int ret = 0; ++ ++ switch(device_id) { ++ case 0x71: ++ switch((ecc_status >> 0x4) & 0x3) { ++ case 0x0: ++ break; ++ case 0x1: ++ dev_err(flash->dev, "SFC ECC:1 ~ 4 bits error and been corrected.\n"); ++ break; ++ case 0x2: ++ dev_err(flash->dev, "SFC ECC:Bit errors greater than 4 bits detected and not corrected.\n"); ++ ret = -EBADMSG; ++ break; ++ default: ++ dev_err(flash->dev, "SFC ECC:Reserved.\n"); ++ } ++ break; ++ case 0x72: ++ switch((ecc_status >> 0x4) & 0x7) { ++ case 0x0: ++ break; ++ case 0x1: ++ dev_err(flash->dev, "SFC ECC:1 ~ 3 bits error and been corrected.\n"); ++ break; ++ case 0x2: ++ dev_err(flash->dev, "SFC ECC:Bit errors greater than 8 bits detected and not corrected.\n"); ++ ret = -EBADMSG; ++ break; ++ case 0x3: ++ dev_err(flash->dev, "SFC ECC:4 ~ 6 bits error and been corrected.\n"); ++ break; ++ case 0x5: ++ dev_err(flash->dev, "SFC ECC:7 ~ 8 bits error and been corrected.\n"); ++ break; ++ default: ++ dev_err(flash->dev, "SFC ECC:Reserved.\n"); ++ } ++ break; ++ default: ++ dev_err(flash->dev, "device_id err,it maybe don`t support this device, please check your device id: device_id = 0x%02x\n", device_id); ++ ret = -EIO; ++ } ++ return ret; ++} ++ ++ ++static int dosilicon_nand_init(void) { ++ ++ dosilicon_nand = kzalloc(sizeof(*dosilicon_nand), GFP_KERNEL); ++ if(!dosilicon_nand) { ++ pr_err("alloc dosilicon_nand struct fail\n"); ++ return -ENOMEM; ++ } ++ ++ dosilicon_nand->id_manufactory = 0xE5; ++ dosilicon_nand->id_device_list = device_id; ++ dosilicon_nand->id_device_count = DOSILICON_DEVICES_NUM; ++ ++ dosilicon_nand->ops.get_cdt_params = dosilicon_get_cdt_params; ++ dosilicon_nand->ops.deal_ecc_status = deal_ecc_status; ++ ++ /* use private get feature interface, please define it in this document */ ++ dosilicon_nand->ops.get_feature = NULL; ++ ++ return ingenic_sfcnand_register(dosilicon_nand); ++} ++ ++fs_initcall(dosilicon_nand_init); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_esmt_mid2c_nand.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_esmt_mid2c_nand.c.patch new file mode 100644 index 00000000..7b66f400 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_esmt_mid2c_nand.c.patch @@ -0,0 +1,120 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v2/nand_device/esmt_mid2c_nand.c b/drivers/mtd/devices/ingenic_sfc_v2/nand_device/esmt_mid2c_nand.c +--- a/drivers/mtd/devices/ingenic_sfc_v2/nand_device/esmt_mid2c_nand.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v2/nand_device/esmt_mid2c_nand.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,116 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../spinand.h" ++#include "../ingenic_sfc_common.h" ++#include "nand_common.h" ++ ++#define ESMT_MID2C_DEVICES_NUM 1 ++#define TSETUP 5 ++#define THOLD 5 ++#define TSHSL_R 20 ++#define TSHSL_W 20 ++ ++#define TRD 50 ++#define TPP 400 ++#define TBE 10 ++ ++static struct ingenic_sfcnand_device *esmt_mid2c_nand; ++ ++static struct ingenic_sfcnand_base_param esmt_mid2c_param[ESMT_MID2C_DEVICES_NUM] = { ++ ++ [0] = { ++ /* F50L2G41XA */ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 128, ++ .flashsize = 2 * 1024 * 64 * 2048, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 1, ++ .ecc_max = 0x8, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .need_quad = 0, ++#else ++ .need_quad = 1, ++#endif ++ }, ++}; ++ ++static struct device_id_struct device_id[ESMT_MID2C_DEVICES_NUM] = { ++ DEVICE_ID_STRUCT(0x24, "F50L2G41XA", &esmt_mid2c_param[0]), ++}; ++ ++ ++static cdt_params_t *esmt_mid2c_get_cdt_params(struct sfc_flash *flash, uint8_t device_id) ++{ ++ CDT_PARAMS_INIT(esmt_mid2c_nand->cdt_params); ++ ++ switch(device_id) { ++ case 0x24: ++ break; ++ default: ++ dev_err(flash->dev, "device_id err, please check your device id: device_id = 0x%02x\n", device_id); ++ return NULL; ++ } ++ ++ return &esmt_mid2c_nand->cdt_params; ++} ++ ++ ++static inline int deal_ecc_status(struct sfc_flash *flash, uint8_t device_id, uint8_t ecc_status) ++{ ++ int ret = 0; ++ ++ switch(device_id) { ++ case 0x24: ++ switch((ecc_status >> 4) & 0x7) { ++ case 0x2: ++ dev_err(flash->dev, "SFC ECC:Bit errors greater than 8 bits detected and not corrected.\n"); ++ ret = -EBADMSG; ++ break; ++ default: ++ ret = 0x0; ++ } ++ break; ++ default: ++ dev_err(flash->dev, "device_id err, it maybe don`t support this device, check your device id: device_id = 0x%02x\n", device_id); ++ ret = -EIO; //notice!!! ++ } ++ return ret; ++} ++ ++ ++static int __init esmt_mid2c_nand_init(void) { ++ ++ esmt_mid2c_nand = kzalloc(sizeof(*esmt_mid2c_nand), GFP_KERNEL); ++ if(!esmt_mid2c_nand) { ++ pr_err("alloc esmt_mid2c_nand struct fail\n"); ++ return -ENOMEM; ++ } ++ ++ esmt_mid2c_nand->id_manufactory = 0x2C; ++ esmt_mid2c_nand->id_device_list = device_id; ++ esmt_mid2c_nand->id_device_count = ESMT_MID2C_DEVICES_NUM; ++ ++ esmt_mid2c_nand->ops.get_cdt_params = esmt_mid2c_get_cdt_params; ++ esmt_mid2c_nand->ops.deal_ecc_status = deal_ecc_status; ++ ++ /* use private get feature interface, please define it in this document */ ++ esmt_mid2c_nand->ops.get_feature = NULL; ++ ++ return ingenic_sfcnand_register(esmt_mid2c_nand); ++} ++ ++fs_initcall(esmt_mid2c_nand_init); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_foresee_nand.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_foresee_nand.c.patch new file mode 100644 index 00000000..feea36bb --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_foresee_nand.c.patch @@ -0,0 +1,159 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v2/nand_device/foresee_nand.c b/drivers/mtd/devices/ingenic_sfc_v2/nand_device/foresee_nand.c +--- a/drivers/mtd/devices/ingenic_sfc_v2/nand_device/foresee_nand.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v2/nand_device/foresee_nand.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,155 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../spinand.h" ++#include "../ingenic_sfc_common.h" ++#include "nand_common.h" ++ ++#define FS_DEVICES_NUM 2 ++#define TSETUP 5 ++#define THOLD 5 ++#define TSHSL_R 20 ++#define TSHSL_W 20 ++ ++#define TRD 180 ++#define TPP 400 ++#define TBE 3 ++ ++static struct ingenic_sfcnand_device *fs_nand; ++ ++static struct ingenic_sfcnand_base_param fs_param[FS_DEVICES_NUM] = { ++ ++ [0] = { ++ /*FS35ND01G*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x4, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .need_quad = 0, ++#else ++ .need_quad = 1, ++#endif ++ }, ++ ++ [1] = { ++ /*F35SQA001G*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x2, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .need_quad = 0, ++#else ++ .need_quad = 1, ++#endif ++ }, ++ ++}; ++ ++static struct device_id_struct device_id[FS_DEVICES_NUM] = { ++ DEVICE_ID_STRUCT(0xA1, "FS35ND01G", &fs_param[0]), ++ DEVICE_ID_STRUCT(0x71, "F35SQA001G", &fs_param[1]), ++}; ++ ++ ++static cdt_params_t *fs_get_cdt_params(struct sfc_flash *flash, uint8_t device_id) ++{ ++ CDT_PARAMS_INIT(fs_nand->cdt_params); ++ ++ switch(device_id) { ++ case 0xA1: ++ break; ++ case 0x71: ++ break; ++ default: ++ dev_err(flash->dev, "device_id err, please check your device id: device_id = 0x%02x\n", device_id); ++ return NULL; ++ } ++ ++ return &fs_nand->cdt_params; ++} ++ ++ ++static inline int deal_ecc_status(struct sfc_flash *flash, uint8_t device_id, uint8_t ecc_status) ++{ ++ int ret = 0; ++ ++ switch(device_id) { ++ case 0xA1: ++ switch((ret = ((ecc_status >> 4) & 0x7))) { ++ case 0x0 ... 0x4: ++ break; ++ default: ++ ret = -EBADMSG; ++ } ++ break; ++ case 0x71: ++ switch((ret = ((ecc_status >> 4) & 0x3))) { ++ case 0x0 ... 0x1: ++ ret = 0; ++ break; ++ default: ++ dev_err(flash->dev, "SFC ECC:Bit errors greater than 1 bits detected and not corrected.\n"); ++ ret = -EBADMSG; ++ } ++ break; ++ default: ++ dev_warn(flash->dev, "device_id err, it maybe don`t support this device, check your device id: device_id = 0x%02x\n", device_id); ++ ret = -EIO; //notice!!! ++ ++ } ++ return ret; ++ ++} ++ ++ ++static int fs_nand_init(void) { ++ ++ fs_nand = kzalloc(sizeof(*fs_nand), GFP_KERNEL); ++ if(!fs_nand) { ++ pr_err("alloc fs_nand struct fail\n"); ++ return -ENOMEM; ++ } ++ ++ fs_nand->id_manufactory = 0xCD; ++ fs_nand->id_device_list = device_id; ++ fs_nand->id_device_count = FS_DEVICES_NUM; ++ ++ fs_nand->ops.get_cdt_params = fs_get_cdt_params; ++ fs_nand->ops.deal_ecc_status = deal_ecc_status; ++ ++ /* use private get feature interface, please define it in this document */ ++ fs_nand->ops.get_feature = NULL; ++ ++ return ingenic_sfcnand_register(fs_nand); ++} ++ ++fs_initcall(fs_nand_init); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_gd_nand.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_gd_nand.c.patch new file mode 100644 index 00000000..0168a94b --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_gd_nand.c.patch @@ -0,0 +1,415 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v2/nand_device/gd_nand.c b/drivers/mtd/devices/ingenic_sfc_v2/nand_device/gd_nand.c +--- a/drivers/mtd/devices/ingenic_sfc_v2/nand_device/gd_nand.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v2/nand_device/gd_nand.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,411 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../spinand.h" ++#include "../ingenic_sfc_common.h" ++#include "nand_common.h" ++ ++#define GD_DEVICES_NUM 10 ++#define TSETUP 5 ++#define THOLD 5 ++#define TSHSL_R 20 ++#define TSHSL_W 20 ++ ++#define TRD 80 ++#define TRD_4G 120 ++#define TPP 700 ++#define TBE 5 ++ ++static struct ingenic_sfcnand_device *gd_nand; ++ ++static struct ingenic_sfcnand_base_param gd_param[GD_DEVICES_NUM] = { ++ ++ [0] = { ++ /*GD5F1GQ4UB*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 128, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x8, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .need_quad = 0, ++#else ++ .need_quad = 1, ++#endif ++ }, ++ [1] = { ++ /*GD5F2GQ4UB*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 128, ++ .flashsize = 2 * 1024 * 64 * 2048, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x8, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .need_quad = 0, ++#else ++ .need_quad = 1, ++#endif ++ ++ }, ++ [2] = { ++ /*GD5F4GQ4UB*/ ++ .pagesize = 4 * 1024, ++ .blocksize = 4 * 1024 * 64, ++ .oobsize = 256, ++ .flashsize = 4 * 1024 * 64 * 2048, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD_4G, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x8, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .need_quad = 0, ++#else ++ .need_quad = 1, ++#endif ++ }, ++ [3] = { ++ /*GD5F1GQ4UC*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 128, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x8, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .need_quad = 0, ++#else ++ .need_quad = 1, ++#endif ++ }, ++ [4] = { ++ /*GD5F2GQ4UC*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 128, ++ .flashsize = 2 * 1024 * 64 * 2048, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x8, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .need_quad = 0, ++#else ++ .need_quad = 1, ++#endif ++ }, ++ [5] = { ++ /*GD5F4GQ4UC*/ ++ .pagesize = 4 * 1024, ++ .blocksize = 4 * 1024 * 64, ++ .oobsize = 256, ++ .flashsize = 4 * 1024 * 64 * 2048, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD_4G, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x8, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .need_quad = 0, ++#else ++ .need_quad = 1, ++#endif ++ }, ++ ++ [6] = { ++ /*GD5F1GQ4RF9IG*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x8, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .need_quad = 0, ++#else ++ .need_quad = 1, ++#endif ++ }, ++ [7] = { ++ /*GD5F1GQ5UE*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .ecc_max = 0x4, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .need_quad = 0, ++#else ++ .need_quad = 1, ++#endif ++ }, ++ [8] = { ++ /*GD5F2GQ5UE*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 2048, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .ecc_max = 0x4, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .need_quad = 0, ++#else ++ .need_quad = 1, ++#endif ++ }, ++ [9] = { ++ /*GD5F2GM7UE*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 2048, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .ecc_max = 0x8, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .need_quad = 0, ++#else ++ .need_quad = 1, ++#endif ++ }, ++ ++}; ++ ++static struct device_id_struct device_id[GD_DEVICES_NUM] = { ++ DEVICE_ID_STRUCT(0xD1, "GD5F1GQ4UB",&gd_param[0]), ++ DEVICE_ID_STRUCT(0xD2, "GD5F2GQ4UB",&gd_param[1]), ++ DEVICE_ID_STRUCT(0xD4, "GD5F4GQ4UB",&gd_param[2]), ++ DEVICE_ID_STRUCT(0xB1, "GD5F1GQ4UC",&gd_param[3]), ++ DEVICE_ID_STRUCT(0xB2, "GD5F2GQ4UC",&gd_param[4]), ++ DEVICE_ID_STRUCT(0xB4, "GD5F4GQ4UC",&gd_param[5]), ++ DEVICE_ID_STRUCT(0xA1, "GD5F1GQ4RF",&gd_param[6]), ++ DEVICE_ID_STRUCT(0x51, "GD5F1GQ5UE",&gd_param[7]), ++ DEVICE_ID_STRUCT(0x52, "GD5F2GQ5UE",&gd_param[8]), ++ DEVICE_ID_STRUCT(0x92, "GD5F2GM7UE",&gd_param[9]), ++}; ++ ++ ++static cdt_params_t *gd_get_cdt_params(struct sfc_flash *flash, uint8_t device_id) ++{ ++ CDT_PARAMS_INIT(gd_nand->cdt_params); ++ ++ switch(device_id) { ++ case 0xB1 ... 0xB4: ++ case 0xA1: ++ gd_nand->cdt_params.standard_r.addr_nbyte = 3; ++ gd_nand->cdt_params.quad_r.addr_nbyte = 3; ++ break; ++ case 0xD1 ... 0xD4: ++ break; ++ case 0x51 ... 0x52: ++ break; ++ case 0x92: ++ break; ++ default: ++ dev_err(flash->dev, "device_id err, please check your device id: device_id = 0x%02x\n", device_id); ++ return NULL; ++ } ++ ++ return &gd_nand->cdt_params; ++} ++ ++ ++static int32_t gd_get_f0_register_value(struct sfc_flash *flash) ++{ ++ struct sfc_cdt_xfer xfer; ++ uint32_t buf = 0; ++ ++ memset(&xfer, 0, sizeof(xfer)); ++ ++ /*set index*/ ++ xfer.cmd_index = NAND_GET_FEATURE; ++ ++ /* set addr */ ++ xfer.staaddr0 = 0xf0; ++ ++ /* set transfer config */ ++ xfer.dataen = ENABLE; ++ xfer.config.datalen = 1; ++ xfer.config.data_dir = GLB0_TRAN_DIR_READ; ++ xfer.config.ops_mode = CPU_OPS; ++ xfer.config.buf = (uint8_t *)&buf; ++ ++ if(sfc_sync_cdt(flash->sfc, &xfer)){ ++ dev_err(flash->dev,"sfc_sync_cdt error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ return buf; ++} ++ ++ ++static inline int deal_ecc_status(struct sfc_flash *flash, uint8_t device_id, uint8_t ecc_status) ++{ ++ int ret = 0; ++ ++ switch(device_id) { ++ case 0xB1 ... 0xB4: ++ switch((ecc_status >> 4) & 0x7) { ++ case 0x7: ++ ret = -EBADMSG; ++ break; ++ case 0x6: ++ ret = 0x8; ++ break; ++ case 0x5: ++ ret = 0x7; ++ break; ++ default: ++ ret = 0; ++ } ++ break; ++ case 0xD1 ... 0xD4: ++ switch((ecc_status >> 4) & 0x3) { ++ case 0x3: ++ ret = 0x8; ++ break; ++ case 0x2: ++ ret = -EBADMSG; ++ break; ++ case 0x1: ++ if((ret = gd_get_f0_register_value(flash)) < 0) ++ return ret; ++ if(((ret >> 4) & 0x3) == 0x3) ++ ret = 0x7; ++ break; ++ default: ++ ret = 0; ++ } ++ break; ++ case 0x51 ... 0x52: ++ switch((ecc_status >> 4) & 0x3) { ++ case 0x2: ++ dev_err(flash->dev, "SFC ECC:Bit errors greater than 4 bits detected and not corrected.\n"); ++ ret = -EBADMSG; ++ break; ++ default: ++ ret = 0x0; ++ break; ++ } ++ break; ++ case 0x92: ++ switch((ecc_status >> 4) & 0x3) { ++ case 0x2: ++ ret = -EBADMSG; ++ break; ++ default: ++ ret = 0; ++ break; ++ } ++ break; ++ default: ++ dev_err(flash->dev, "device_id err,it maybe don`t support this device, please check your device id: device_id = 0x%02x\n", device_id); ++ ret = -EIO; //notice!!! ++ } ++ return ret; ++} ++ ++ ++static int __init gd_nand_init(void) { ++ ++ gd_nand = kzalloc(sizeof(*gd_nand), GFP_KERNEL); ++ if(!gd_nand) { ++ pr_err("alloc gd_nand struct fail\n"); ++ return -ENOMEM; ++ } ++ ++ gd_nand->id_manufactory = 0xC8; ++ gd_nand->id_device_list = device_id; ++ gd_nand->id_device_count = GD_DEVICES_NUM; ++ ++ gd_nand->ops.get_cdt_params = gd_get_cdt_params; ++ gd_nand->ops.deal_ecc_status = deal_ecc_status; ++ ++ /* use private get feature interface, please define it in this document */ ++ gd_nand->ops.get_feature = NULL; ++ ++ return ingenic_sfcnand_register(gd_nand); ++} ++ ++fs_initcall(gd_nand_init); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_micron_nand.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_micron_nand.c.patch new file mode 100644 index 00000000..cdf76050 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_micron_nand.c.patch @@ -0,0 +1,120 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v2/nand_device/micron_nand.c b/drivers/mtd/devices/ingenic_sfc_v2/nand_device/micron_nand.c +--- a/drivers/mtd/devices/ingenic_sfc_v2/nand_device/micron_nand.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v2/nand_device/micron_nand.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,116 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../spinand.h" ++#include "../ingenic_sfc_common.h" ++#include "nand_common.h" ++ ++#define MICRON_DEVICES_NUM 1 ++#define TSETUP 5 ++#define THOLD 5 ++#define TSHSL_R 20 ++#define TSHSL_W 20 ++ ++#define TRD 50 ++#define TPP 400 ++#define TBE 10 ++ ++static struct ingenic_sfcnand_device *micron_nand; ++ ++static struct ingenic_sfcnand_base_param micron_param[MICRON_DEVICES_NUM] = { ++ ++ [0] = { ++ /* MT29F2G01A */ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 128, ++ .flashsize = 2 * 1024 * 64 * 2048, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 1, ++ .ecc_max = 0x8, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .need_quad = 0, ++#else ++ .need_quad = 1, ++#endif ++ }, ++}; ++ ++static struct device_id_struct device_id[MICRON_DEVICES_NUM] = { ++ DEVICE_ID_STRUCT(0x24, "MT29F2G01A", µn_param[0]), ++}; ++ ++ ++static cdt_params_t *micron_get_cdt_params(struct sfc_flash *flash, uint8_t device_id) ++{ ++ CDT_PARAMS_INIT(micron_nand->cdt_params); ++ ++ switch(device_id) { ++ case 0x24: ++ break; ++ default: ++ dev_err(flash->dev, "device_id err, please check your device id: device_id = 0x%02x\n", device_id); ++ return NULL; ++ } ++ ++ return µn_nand->cdt_params; ++} ++ ++ ++static inline int deal_ecc_status(struct sfc_flash *flash, uint8_t device_id, uint8_t ecc_status) ++{ ++ int ret = 0; ++ ++ switch(device_id) { ++ case 0x24: ++ switch((ecc_status >> 4) & 0x7) { ++ case 0x2: ++ dev_err(flash->dev, "SFC ECC:Bit errors greater than 8 bits detected and not corrected.\n"); ++ ret = -EBADMSG; ++ break; ++ default: ++ ret = 0x0; ++ } ++ break; ++ default: ++ dev_err(flash->dev, "device_id err, it maybe don`t support this device, check your device id: device_id = 0x%02x\n", device_id); ++ ret = -EIO; //notice!!! ++ } ++ return ret; ++} ++ ++ ++static int __init micron_nand_init(void) { ++ ++ micron_nand = kzalloc(sizeof(*micron_nand), GFP_KERNEL); ++ if(!micron_nand) { ++ pr_err("alloc micron_nand struct fail\n"); ++ return -ENOMEM; ++ } ++ ++ micron_nand->id_manufactory = 0x2C; ++ micron_nand->id_device_list = device_id; ++ micron_nand->id_device_count = MICRON_DEVICES_NUM; ++ ++ micron_nand->ops.get_cdt_params = micron_get_cdt_params; ++ micron_nand->ops.deal_ecc_status = deal_ecc_status; ++ ++ /* use private get feature interface, please define it in this document */ ++ micron_nand->ops.get_feature = NULL; ++ ++ return ingenic_sfcnand_register(micron_nand); ++} ++ ++fs_initcall(micron_nand_init); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_mxic_nand.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_mxic_nand.c.patch new file mode 100644 index 00000000..86001be0 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_mxic_nand.c.patch @@ -0,0 +1,214 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v2/nand_device/mxic_nand.c b/drivers/mtd/devices/ingenic_sfc_v2/nand_device/mxic_nand.c +--- a/drivers/mtd/devices/ingenic_sfc_v2/nand_device/mxic_nand.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v2/nand_device/mxic_nand.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,210 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../spinand.h" ++#include "../ingenic_sfc_common.h" ++#include "nand_common.h" ++ ++#define MXIC_DEVICES_NUM 3 ++#define MXIC_CMD_GET_ECC 0x7c ++#define THOLD 4 ++#define TSETUP 4 ++#define TSHSL_R 100 ++#define TSHSL_W 100 ++ ++#define TRD 70 ++#define TRD_14AC 25 ++#define TPP 600 ++#define TBE 4 ++ ++static struct ingenic_sfcnand_device *mxic_nand; ++ ++static struct ingenic_sfcnand_base_param mxic_param[MXIC_DEVICES_NUM] = { ++ [0] = { ++ /*MX35LF1GE4AB*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ ++ .tHOLD = THOLD, ++ .tSETUP = TSETUP, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x4, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .need_quad = 0, ++#else ++ .need_quad = 1, ++#endif ++ }, ++ [1] = { ++ /*MX35LF2GE4AB*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 2048, ++ ++ .tHOLD = THOLD, ++ .tSETUP = TSETUP, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 1, ++ .ecc_max = 0x4, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .need_quad = 0, ++#else ++ .need_quad = 1, ++#endif ++ }, ++ [2] = { ++ /*MX35LF2G14AC*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 2048, ++ ++ .tHOLD = THOLD, ++ .tSETUP = TSETUP, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD_14AC, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .need_quad = 0, ++#else ++ .need_quad = 1, ++#endif ++ }, ++ ++}; ++ ++static struct device_id_struct device_id[MXIC_DEVICES_NUM] = { ++ DEVICE_ID_STRUCT(0x12, "MX35LF1GE4AB", &mxic_param[0]), ++ DEVICE_ID_STRUCT(0x22, "MX35LF2GE4AB", &mxic_param[1]), ++ DEVICE_ID_STRUCT(0x20, "MX35LF2G14AC", &mxic_param[2]), ++}; ++ ++ ++static cdt_params_t *mxic_get_cdt_params(struct sfc_flash *flash, uint8_t device_id) ++{ ++ CDT_PARAMS_INIT(mxic_nand->cdt_params); ++ ++ /* ecc status read */ ++ CMD_INFO(mxic_nand->cdt_params.ecc_r, MXIC_CMD_GET_ECC, 8, 0, TM_STD_SPI); ++ ++ switch(device_id) { ++ case 0x12: ++ case 0x22: ++ case 0x20: ++ break; ++ default: ++ dev_err(flash->dev, "device_id err, please check your device id: device_id = 0x%02x\n", device_id); ++ return NULL; ++ } ++ ++ return &mxic_nand->cdt_params; ++} ++ ++ ++static int32_t get_ecc_value(struct sfc_flash *flash) ++{ ++ struct sfc_cdt_xfer xfer; ++ uint32_t buf = 0; ++ int8_t count = 5; ++ ++try_read_again: ++ memset(&xfer, 0, sizeof(xfer)); ++ ++ /*set index*/ ++ xfer.cmd_index = NAND_ECC_STATUS_READ; ++ ++ /* set addr */ ++ xfer.columnaddr = 0; ++ ++ /* set transfer config */ ++ xfer.dataen = ENABLE; ++ xfer.config.datalen = 1; ++ xfer.config.data_dir = GLB0_TRAN_DIR_READ; ++ xfer.config.ops_mode = CPU_OPS; ++ xfer.config.buf = (uint8_t *)&buf; ++ ++ if(sfc_sync_cdt(flash->sfc, &xfer) && count--){ ++ goto try_read_again; ++ } ++ ++ if(count < 0) ++ return -EIO; ++ ++ return buf & 0xf; ++} ++ ++ ++static inline int deal_ecc_status(struct sfc_flash *flash, uint8_t device_id, uint8_t ecc_status) ++{ ++ int ret = 0; ++ ++ switch(device_id) { ++ case 0x12: ++ case 0x22: ++ switch((ecc_status >> 0x4) & 0x3) { ++ case 0x2: ++ dev_err(flash->dev, "SFC ECC:Bit errors greater than 4 bits detected and not corrected.\n"); ++ ret = -EBADMSG; ++ break; ++ default: ++ ret = 0; ++ } ++ break; ++ ++ case 0x20: ++ ret = 0; ++ break; ++ default: ++ dev_warn(flash->dev, "device_id err, it maybe don`t support this device, check your device id: device_id = 0x%02x\n", device_id); ++ ret = -EIO; ++ } ++ return ret; ++} ++ ++static int __init mxic_nand_init(void) { ++ ++ mxic_nand = kzalloc(sizeof(*mxic_nand), GFP_KERNEL); ++ if(!mxic_nand) { ++ pr_err("alloc mxic_nand struct fail\n"); ++ return -ENOMEM; ++ } ++ ++ mxic_nand->id_manufactory = 0xC2; ++ mxic_nand->id_device_list = device_id; ++ mxic_nand->id_device_count = MXIC_DEVICES_NUM; ++ ++ mxic_nand->ops.get_cdt_params = mxic_get_cdt_params; ++ mxic_nand->ops.deal_ecc_status = deal_ecc_status; ++ ++ /* use private get feature interface, please define it in this document */ ++ mxic_nand->ops.get_feature = NULL; ++ ++ return ingenic_sfcnand_register(mxic_nand); ++} ++ ++fs_initcall(mxic_nand_init); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_nand_common.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_nand_common.c.patch new file mode 100644 index 00000000..7b22c543 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_nand_common.c.patch @@ -0,0 +1,70 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v2/nand_device/nand_common.c b/drivers/mtd/devices/ingenic_sfc_v2/nand_device/nand_common.c +--- a/drivers/mtd/devices/ingenic_sfc_v2/nand_device/nand_common.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v2/nand_device/nand_common.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,66 @@ ++#include ++#include ++#include "../sfc.h" ++#include "../spinand.h" ++#include "../spinand_cmd.h" ++#include "../ingenic_sfc_common.h" ++#include "nand_common.h" ++ ++/* ++ * Note: the deal_ecc_status() function needs to be defined in xxx_nand.c ++ */ ++int32_t nand_common_get_feature(struct sfc_flash *flash, uint8_t flag) ++{ ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ struct ingenic_sfcnand_ops *ops = nand_info->ops; ++ uint8_t device_id = nand_info->id_device; ++ struct sfc_cdt_xfer xfer; ++ uint8_t ecc_status = 0; ++ int32_t ret = 0; ++ ++retry: ++ ecc_status = 0; ++ ++ memset(&xfer, 0, sizeof(xfer)); ++ ++ /*set index*/ ++ xfer.cmd_index = NAND_GET_FEATURE; ++ ++ /* set addr */ ++ xfer.staaddr0 = SPINAND_ADDR_STATUS; ++ ++ /* set transfer config */ ++ xfer.dataen = ENABLE; ++ xfer.config.datalen = 1; ++ xfer.config.data_dir = GLB0_TRAN_DIR_READ; ++ xfer.config.ops_mode = CPU_OPS; ++ xfer.config.buf = &ecc_status; ++ ++ if(sfc_sync_cdt(flash->sfc, &xfer)) { ++ dev_err(flash->dev,"sfc_sync_cdt error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ if(ecc_status & SPINAND_IS_BUSY) ++ goto retry; ++ ++ switch(flag) { ++ case GET_WRITE_STATUS: ++ if(ecc_status & (0x1 << 3)) ++ ret = -EIO; ++ break; ++ ++ case GET_ERASE_STATUS: ++ if(ecc_status & (0x1 << 2)) ++ ret = -EIO; ++ break; ++ ++ case GET_ECC_STATUS: ++ ret = ops->deal_ecc_status(flash, device_id, ecc_status); ++ break; ++ default: ++ dev_err(flash->dev,"flag value is error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ } ++ return ret; ++} ++EXPORT_SYMBOL_GPL(nand_common_get_feature); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_nand_common.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_nand_common.h.patch new file mode 100644 index 00000000..ee72e23b --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_nand_common.h.patch @@ -0,0 +1,78 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v2/nand_device/nand_common.h b/drivers/mtd/devices/ingenic_sfc_v2/nand_device/nand_common.h +--- a/drivers/mtd/devices/ingenic_sfc_v2/nand_device/nand_common.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v2/nand_device/nand_common.h 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,74 @@ ++#ifndef __NAND_COMMON_H ++#define __NAND_COMMON_H ++#include ++#include "../sfc.h" ++#include "../sfc_flash.h" ++#include "../spinand.h" ++ ++#define GET_WRITE_STATUS 1 ++#define GET_ECC_STATUS 2 ++#define GET_ERASE_STATUS 3 ++ ++/* page number of convert plane */ ++#define NAND_PLANE_PAGES 64 ++ ++/* select plane to convert columnaddr */ ++#define CONVERT_COL_ADDR(pageaddr, columnaddr) ({ \ ++ uint32_t plane_flag = (pageaddr >> (ffs(NAND_PLANE_PAGES) - 1)) & 0x1; \ ++ if (plane_flag) { \ ++ columnaddr = columnaddr | ( plane_flag << 12); \ ++ } \ ++ columnaddr; \ ++}) ++ ++#define DEVICE_ID_STRUCT(id, name_string, parameter) { \ ++ .id_device = id, \ ++ .name = name_string, \ ++ .param = parameter, \ ++} ++ ++#define CMD_INFO(_CMD, COMMAND, DUMMY_BIT, ADDR_LEN, TRANSFER_MODE) { \ ++ _CMD.cmd = COMMAND; \ ++ _CMD.dummy_byte = DUMMY_BIT; \ ++ _CMD.addr_nbyte = ADDR_LEN; \ ++ _CMD.transfer_mode = TRANSFER_MODE; \ ++} ++ ++#define ST_INFO(_ST, COMMAND, BIT_SHIFT, MASK, VAL, LEN, DUMMY_BIT) { \ ++ _ST.cmd = COMMAND; \ ++ _ST.bit_shift = BIT_SHIFT; \ ++ _ST.mask = MASK; \ ++ _ST.val = VAL; \ ++ _ST.len = LEN; \ ++ _ST.dummy = DUMMY_BIT; \ ++} ++ ++/* ++ * cdt params ++ */ ++#define CDT_PARAMS_INIT(cdt_params) { \ ++ /* read to cache */ \ ++ CMD_INFO(cdt_params.r_to_cache, SPINAND_CMD_PARD, 0, 3, TM_STD_SPI); \ ++ /* standard read from cache */ \ ++ CMD_INFO(cdt_params.standard_r, SPINAND_CMD_FRCH, 8, 2, TM_STD_SPI); \ ++ /* quad read from cache*/ \ ++ CMD_INFO(cdt_params.quad_r, SPINAND_CMD_RDCH_X4, 8, 2, TM_QI_QO_SPI); \ ++ /* standard write to cache*/ \ ++ CMD_INFO(cdt_params.standard_w_cache, SPINAND_CMD_PRO_LOAD, 0, 2, TM_STD_SPI); \ ++ /* quad write to cache*/ \ ++ CMD_INFO(cdt_params.quad_w_cache, SPINAND_CMD_PRO_LOAD_X4, 0, 2, TM_QI_QO_SPI); \ ++ /* write exec */ \ ++ CMD_INFO(cdt_params.w_exec, SPINAND_CMD_PRO_EN, 0, 3, TM_STD_SPI); \ ++ /* block erase */ \ ++ CMD_INFO(cdt_params.b_erase, SPINAND_CMD_ERASE_128K, 0, 3, TM_STD_SPI); \ ++ /* write enable */ \ ++ CMD_INFO(cdt_params.w_en, SPINAND_CMD_WREN, 0, 0, TM_STD_SPI); \ ++ \ ++ /* get frature wait oip not busy */ \ ++ ST_INFO(cdt_params.oip, SPINAND_CMD_GET_FEATURE, 0, 0x1, 0x0, 1, 0); \ ++} ++ ++ ++int32_t nand_common_get_feature(struct sfc_flash *flash, uint8_t flag); ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_winbond_nand.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_winbond_nand.c.patch new file mode 100644 index 00000000..091df8d9 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_winbond_nand.c.patch @@ -0,0 +1,115 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v2/nand_device/winbond_nand.c b/drivers/mtd/devices/ingenic_sfc_v2/nand_device/winbond_nand.c +--- a/drivers/mtd/devices/ingenic_sfc_v2/nand_device/winbond_nand.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v2/nand_device/winbond_nand.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,111 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../spinand.h" ++#include "../ingenic_sfc_common.h" ++#include "nand_common.h" ++ ++#define WB_DEVICES_NUM 1 ++#define TSETUP 5 ++#define THOLD 3 ++#define TSHSL_R 10 ++#define TSHSL_W 50 ++ ++#define TRD 60 ++#define TPP 700 ++#define TBE 10 ++ ++static struct ingenic_sfcnand_device *wb_nand; ++ ++static struct ingenic_sfcnand_base_param wb_param[WB_DEVICES_NUM] = { ++ ++ [0] = { ++ /* W25N01GV */ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ ++ .tSETUP =TSETUP, ++ .tHOLD =THOLD, ++ .tSHSL_R =TSHSL_R, ++ .tSHSL_W =TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .ecc_max = 0x4, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .need_quad = 0, ++#else ++ .need_quad = 1, ++#endif ++ }, ++}; ++ ++static struct device_id_struct device_id[WB_DEVICES_NUM] = { ++ DEVICE_ID_STRUCT(0xAA, "W25N01GV", &wb_param[0]), ++}; ++ ++ ++static cdt_params_t *wb_get_cdt_params(struct sfc_flash *flash, uint8_t device_id) ++{ ++ CDT_PARAMS_INIT(wb_nand->cdt_params); ++ ++ switch(device_id) { ++ case 0xAA: ++ break; ++ default: ++ dev_err(flash->dev, "device_id err, please check your device id: device_id = 0x%x\n", device_id); ++ return NULL; ++ } ++ return &wb_nand->cdt_params; ++} ++ ++ ++static inline int deal_ecc_status(struct sfc_flash *flash, uint8_t device_id, uint8_t ecc_status) ++{ ++ int ret = 0; ++ switch(device_id) { ++ case 0xAA: ++ switch((ret = ((ecc_status >> 4) & 0x3))) { ++ case 0x0 ... 0x1: ++ break; ++ default: ++ ret = -EBADMSG; ++ } ++ break; ++ default: ++ dev_warn(flash->dev, "device_id err, it maybe don`t support this device, check your device id: device_id = 0x%x\n", device_id); ++ ret = -EIO; //notice!!! ++ } ++ return ret; ++} ++ ++ ++static int wb_nand_init(void) { ++ ++ wb_nand = kzalloc(sizeof(*wb_nand), GFP_KERNEL); ++ if(!wb_nand) { ++ pr_err("alloc wb_nand struct fail\n"); ++ return -ENOMEM; ++ } ++ ++ wb_nand->id_manufactory = 0xEF; ++ wb_nand->id_device_list = device_id; ++ wb_nand->id_device_count = WB_DEVICES_NUM; ++ ++ wb_nand->ops.get_cdt_params = wb_get_cdt_params; ++ wb_nand->ops.deal_ecc_status = deal_ecc_status; ++ ++ /* use private get feature interface, please define it in this document */ ++ wb_nand->ops.get_feature = NULL; ++ ++ return ingenic_sfcnand_register(wb_nand); ++} ++ ++fs_initcall(wb_nand_init); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_xtx_mid0b_nand.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_xtx_mid0b_nand.c.patch new file mode 100644 index 00000000..d811f26d --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_xtx_mid0b_nand.c.patch @@ -0,0 +1,200 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v2/nand_device/xtx_mid0b_nand.c b/drivers/mtd/devices/ingenic_sfc_v2/nand_device/xtx_mid0b_nand.c +--- a/drivers/mtd/devices/ingenic_sfc_v2/nand_device/xtx_mid0b_nand.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v2/nand_device/xtx_mid0b_nand.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,196 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../spinand.h" ++#include "../ingenic_sfc_common.h" ++#include "nand_common.h" ++ ++#define XTX_MID0B_DEVICES_NUM 3 ++#define TSETUP 5 ++#define THOLD 5 ++#define TSHSL_R 20 ++#define TSHSL_W 20 ++ ++#define TRD 260 ++#define TPP 350 ++#define TBE 3 ++ ++static struct ingenic_sfcnand_device *xtx_mid0b_nand; ++ ++static struct ingenic_sfcnand_base_param xtx_mid0b_param[XTX_MID0B_DEVICES_NUM] = { ++ ++ [0] = { ++ /*XT26G01A */ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x8, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .need_quad = 0, ++#else ++ .need_quad = 1, ++#endif ++ }, ++ ++ [1] = { ++ /*XT26G02B */ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 2048, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x4, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .need_quad = 0, ++#else ++ .need_quad = 1, ++#endif ++ }, ++ ++ [2] = { ++ /*XT26G01C */ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 128, ++ .flashsize = 1 * 1024 * 64 * 2048, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0xf, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .need_quad = 0, ++#else ++ .need_quad = 1, ++#endif ++ }, ++ ++}; ++ ++static struct device_id_struct device_id[XTX_MID0B_DEVICES_NUM] = { ++ DEVICE_ID_STRUCT(0xE1, "XT26G01A ", &xtx_mid0b_param[0]), ++ DEVICE_ID_STRUCT(0xF2, "XT26G02B ", &xtx_mid0b_param[1]), ++ DEVICE_ID_STRUCT(0x11, "XT26G01C ", &xtx_mid0b_param[2]), ++}; ++ ++ ++static cdt_params_t *xtx_mid0b_get_cdt_params(struct sfc_flash *flash, uint8_t device_id) ++{ ++ CDT_PARAMS_INIT(xtx_mid0b_nand->cdt_params); ++ ++ switch(device_id) { ++ case 0xE1: ++ case 0xF2: ++ case 0x11: ++ break; ++ default: ++ dev_err(flash->dev, "device_id err, please check your device id: device_id = 0x%02x\n", device_id); ++ return NULL; ++ } ++ ++ return &xtx_mid0b_nand->cdt_params; ++} ++ ++ ++static inline int deal_ecc_status(struct sfc_flash *flash, uint8_t device_id, uint8_t ecc_status) ++{ ++ int ret = 0; ++ ++ switch(device_id) { ++ case 0xE1: ++ switch((ecc_status >> 2) & 0xf) { ++ case 0x12: ++ case 0x8: ++ ret = -EBADMSG; ++ break; ++ case 0x0 ... 0x7: ++ default: ++ ret = 0; ++ break; ++ } ++ break; ++ ++ case 0xF2: ++ switch((ecc_status >> 4) & 0x3) { ++ case 0x02: ++ ret = -EBADMSG; ++ break; ++ default: ++ ret = 0; ++ } ++ break; ++ ++ case 0x11: ++ switch((ecc_status >> 4) & 0xf) { ++ case 0x0f: ++ dev_err(flash->dev, "SFC ECC:Bit errors greater than 8 bits detected and not corrected.\n"); ++ ret = -EBADMSG; ++ break; ++ default: ++ ret = 0; ++ } ++ break; ++ ++ default: ++ dev_warn(flash->dev, "device_id err, it maybe don`t support this device, check your device id: device_id = 0x%02x\n", device_id); ++ ret = -EIO; ++ ++ } ++ return ret; ++} ++ ++ ++static int xtx_mid0b_nand_init(void) { ++ ++ xtx_mid0b_nand = kzalloc(sizeof(*xtx_mid0b_nand), GFP_KERNEL); ++ if(!xtx_mid0b_nand) { ++ pr_err("alloc xtx_mid0b_nand struct fail\n"); ++ return -ENOMEM; ++ } ++ ++ xtx_mid0b_nand->id_manufactory = 0x0B; ++ xtx_mid0b_nand->id_device_list = device_id; ++ xtx_mid0b_nand->id_device_count = XTX_MID0B_DEVICES_NUM; ++ ++ xtx_mid0b_nand->ops.get_cdt_params = xtx_mid0b_get_cdt_params; ++ xtx_mid0b_nand->ops.deal_ecc_status = deal_ecc_status; ++ ++ /* use private get feature interface, please define it in this document */ ++ xtx_mid0b_nand->ops.get_feature = NULL; ++ ++ return ingenic_sfcnand_register(xtx_mid0b_nand); ++} ++ ++fs_initcall(xtx_mid0b_nand_init); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_xtx_nand.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_xtx_nand.c.patch new file mode 100644 index 00000000..54c925b1 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_xtx_nand.c.patch @@ -0,0 +1,172 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v2/nand_device/xtx_nand.c b/drivers/mtd/devices/ingenic_sfc_v2/nand_device/xtx_nand.c +--- a/drivers/mtd/devices/ingenic_sfc_v2/nand_device/xtx_nand.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v2/nand_device/xtx_nand.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,168 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../spinand.h" ++#include "../ingenic_sfc_common.h" ++#include "nand_common.h" ++ ++#define XTX_DEVICES_NUM 3 ++#define TSETUP 5 ++#define THOLD 5 ++#define TSHSL_R 20 ++#define TSHSL_W 20 ++ ++#define TRD 240 ++#define TPP 1400 ++#define TBE 10 ++ ++static struct ingenic_sfcnand_device *xtx_nand; ++ ++static struct ingenic_sfcnand_base_param xtx_param[XTX_DEVICES_NUM] = { ++ ++ [0] = { ++ /*PN26G01AW*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 128, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x8, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .need_quad = 0, ++#else ++ .need_quad = 1, ++#endif ++ }, ++ [1] = { ++ /*PN26G02AW */ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 128, ++ .flashsize = 2 * 1024 * 64 * 2048, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x8, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .need_quad = 0, ++#else ++ .need_quad = 1, ++#endif ++ }, ++ [2] = { ++ /*PN26Q01AW */ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 128, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x8, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .need_quad = 0, ++#else ++ .need_quad = 1, ++#endif ++ }, ++ ++}; ++ ++static struct device_id_struct device_id[XTX_DEVICES_NUM] = { ++ DEVICE_ID_STRUCT(0xE1, "PN26G01AW", &xtx_param[0]), ++ DEVICE_ID_STRUCT(0xE2, "PN26G02AW", &xtx_param[1]), ++ DEVICE_ID_STRUCT(0xC1, "PN26Q01AW", &xtx_param[2]), ++}; ++ ++ ++static cdt_params_t *xtx_get_cdt_params(struct sfc_flash *flash, uint8_t device_id) ++{ ++ CDT_PARAMS_INIT(xtx_nand->cdt_params); ++ ++ switch(device_id) { ++ case 0xA1: ++ break; ++ default: ++ dev_err(flash->dev, "device_id err, please check your device id: device_id = 0x%02x\n", device_id); ++ return NULL; ++ } ++ ++ return &xtx_nand->cdt_params; ++} ++ ++ ++static inline int deal_ecc_status(struct sfc_flash *flash, uint8_t device_id, uint8_t ecc_status) ++{ ++ int ret = 0; ++ ++ switch(device_id) { ++ case 0xE1 ... 0xE2: ++ case 0xC1: ++ switch((ecc_status >> 4) & 0x3) { ++ case 0x02: ++ ret = -EBADMSG; ++ break; ++ default: ++ ret = 0; ++ } ++ break; ++ default: ++ dev_err(flash->dev, "device_id err, it maybe don`t support this device, check your device id: device_id = 0x%02x\n", device_id); ++ ret = -EIO; //notice!!! ++ ++ } ++ return ret; ++} ++ ++ ++static int __init xtx_nand_init(void) { ++ ++ xtx_nand = kzalloc(sizeof(*xtx_nand), GFP_KERNEL); ++ if(!xtx_nand) { ++ pr_err("alloc xtx_nand struct fail\n"); ++ return -ENOMEM; ++ } ++ ++ xtx_nand->id_manufactory = 0xA1; ++ xtx_nand->id_device_list = device_id; ++ xtx_nand->id_device_count = XTX_DEVICES_NUM; ++ ++ xtx_nand->ops.get_cdt_params = xtx_get_cdt_params; ++ xtx_nand->ops.deal_ecc_status = deal_ecc_status; ++ ++ /* use private get feature interface, please define it in this document */ ++ xtx_nand->ops.get_feature = NULL; ++ ++ return ingenic_sfcnand_register(xtx_nand); ++} ++ ++fs_initcall(xtx_nand_init); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_zetta_nand.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_zetta_nand.c.patch new file mode 100644 index 00000000..f0bfa269 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_nand_device_zetta_nand.c.patch @@ -0,0 +1,151 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v2/nand_device/zetta_nand.c b/drivers/mtd/devices/ingenic_sfc_v2/nand_device/zetta_nand.c +--- a/drivers/mtd/devices/ingenic_sfc_v2/nand_device/zetta_nand.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v2/nand_device/zetta_nand.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,147 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../spinand.h" ++#include "../ingenic_sfc_common.h" ++#include "nand_common.h" ++ ++#define ZETTA_DEVICES_NUM 2 ++#define TSETUP 5 ++#define THOLD 5 ++#define TSHSL_R 100 ++#define TSHSL_W 100 ++ ++#define TRD 70 ++#define TPP 320 ++#define TBE 2 ++ ++static struct ingenic_sfcnand_device *zetta_nand; ++ ++static struct ingenic_sfcnand_base_param zetta_param[ZETTA_DEVICES_NUM] = { ++ ++ [0] = { ++ /*ZD35Q1GA*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x4, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .need_quad = 0, ++#else ++ .need_quad = 1, ++#endif ++ }, ++ [1] = { ++ /*ZD35Q1GA*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 1, ++ .ecc_max = 0x4, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .need_quad = 0, ++#else ++ .need_quad = 1, ++#endif ++ }, ++ ++}; ++ ++static struct device_id_struct device_id[ZETTA_DEVICES_NUM] = { ++ DEVICE_ID_STRUCT(0x71, "ZD35Q1GA", &zetta_param[0]), ++ DEVICE_ID_STRUCT(0x72, "ZD35Q2GA", &zetta_param[1]), ++}; ++ ++ ++static cdt_params_t *zetta_get_cdt_params(struct sfc_flash *flash, uint8_t device_id) ++{ ++ CDT_PARAMS_INIT(zetta_nand->cdt_params); ++ ++ switch(device_id) { ++ case 0x71: ++ case 0x72: ++ break; ++ default: ++ dev_err(flash->dev, "device_id err, please check your device id: device_id = 0x%02x\n", device_id); ++ return NULL; ++ } ++ ++ return &zetta_nand->cdt_params; ++} ++ ++ ++static inline int deal_ecc_status(struct sfc_flash *flash, uint8_t device_id, uint8_t ecc_status) ++{ ++ int ret = 0; ++ ++ switch(device_id) { ++ case 0x71: ++ case 0x72: ++ switch((ecc_status >> 4) & 0x3) { ++ case 0x01: ++ ret = 0x4; ++ break; ++ case 0x02: ++ ret = -EBADMSG; ++ break; ++ default: ++ ret = 0; ++ } ++ break; ++ ++ default: ++ dev_warn(flash->dev, "device_id err, it maybe don`t support this device, check your device id: device_id = 0x%02x\n", device_id); ++ ret = -EIO; //notice!!! ++ } ++ return ret; ++} ++ ++ ++static int zetta_nand_init(void) ++{ ++ zetta_nand = kzalloc(sizeof(*zetta_nand), GFP_KERNEL); ++ if(!zetta_nand) { ++ pr_err("alloc zetta_nand struct fail\n"); ++ return -ENOMEM; ++ } ++ ++ zetta_nand->id_manufactory = 0xBA; ++ zetta_nand->id_device_list = device_id; ++ zetta_nand->id_device_count = ZETTA_DEVICES_NUM; ++ ++ zetta_nand->ops.get_cdt_params = zetta_get_cdt_params; ++ zetta_nand->ops.deal_ecc_status = deal_ecc_status; ++ ++ /* use private get feature interface, please define it in this document */ ++ zetta_nand->ops.get_feature = NULL; ++ ++ return ingenic_sfcnand_register(zetta_nand); ++} ++ ++fs_initcall(zetta_nand_init); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_sfc.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_sfc.h.patch new file mode 100644 index 00000000..ba3c45c1 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_sfc.h.patch @@ -0,0 +1,114 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v2/sfc.h b/drivers/mtd/devices/ingenic_sfc_v2/sfc.h +--- a/drivers/mtd/devices/ingenic_sfc_v2/sfc.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v2/sfc.h 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,110 @@ ++#ifndef __SFC_H ++#define __SFC_H ++ ++#include ++#include ++#include ++#include ++ ++ ++struct sfc{ ++ ++ void __iomem *iomem; ++ struct resource *ioarea; ++ int irq; ++ struct clk *clk; ++ struct clk *clk_gate; ++ unsigned long src_clk; ++ struct completion done; ++ uint32_t threshold; ++ irqreturn_t (*irq_callback)(struct sfc *); ++ unsigned long phys; ++ ++ struct sfc_cdt_xfer *xfer; ++ ++ struct sfc_desc *desc; ++ dma_addr_t desc_pyaddr; ++ uint32_t desc_max_num; ++}; ++ ++struct data_config { ++ ++ uint32_t datalen; ++ uint32_t cur_len; ++ uint8_t data_dir; ++ uint8_t ops_mode; ++ uint8_t *buf; ++}; ++ ++struct sfc_cdt_xfer { ++ ++ unsigned short cmd_index; ++ uint8_t dataen; ++ struct data_config config; ++ ++ struct { ++ uint32_t columnaddr; ++ uint32_t rowaddr; ++ uint32_t staaddr0; ++ uint32_t staaddr1; ++ }; ++ ++}; ++ ++struct sfc_desc { ++ unsigned int next_des_addr; ++ unsigned int mem_addr; ++ unsigned int tran_len; ++ unsigned int link; ++}; ++ ++enum{ ++ COL_ADDR, ++ ROW_ADDR, ++ STA_ADDR0, ++ STA_ADDR1, ++}; ++ ++ ++/* ++ * create cdt table ++ */ ++struct sfc_cdt{ ++ uint32_t link; ++ uint32_t xfer; ++ uint32_t staExp; ++ uint32_t staMsk; ++}; ++ ++#define CMD_XFER(ADDR_WIDTH, POLL_EN, DMY_BITS, DATA_EN, CMD) ( \ ++ (ADDR_WIDTH << TRAN_CONF0_ADDR_WIDTH_OFFSET) \ ++ | (POLL_EN << TRAN_CONF0_POLL_OFFSET) \ ++ | (TRAN_CONF0_CMDEN) \ ++ | (0 << TRAN_CONF0_FMAT_OFFSET) \ ++ | (DMY_BITS << TRAN_CONF0_DMYBITS_OFFSET) \ ++ | (DATA_EN << TRAN_CONF0_DATEEN_OFFSET) \ ++ | CMD \ ++ ) ++ ++#define CMD_LINK(LINK, ADDRMODE, TRAN_MODE) ( \ ++ (LINK << 31) | (TRAN_MODE << TRAN_CONF1_TRAN_MODE_OFFSET) | (ADDRMODE) \ ++ ) ++ ++#define MK_CMD(cdt, cmd_info, LINK, ADDRMODE, DATA_EN) { \ ++ cdt.link = CMD_LINK(LINK, ADDRMODE, cmd_info.transfer_mode); \ ++ cdt.xfer = CMD_XFER(cmd_info.addr_nbyte, DISABLE, cmd_info.dummy_byte, DATA_EN, cmd_info.cmd); \ ++ cdt.staExp = 0; \ ++ cdt.staMsk = 0; \ ++} ++ ++#define MK_ST(cdt, st_info, LINK, ADDRMODE, ADDR_WIDTH, POLL_EN, DATA_EN, TRAN_MODE) { \ ++ cdt.link = CMD_LINK(LINK, ADDRMODE, TRAN_MODE); \ ++ cdt.xfer = CMD_XFER(ADDR_WIDTH, POLL_EN, st_info.dummy, DATA_EN, st_info.cmd); \ ++ cdt.staExp = (st_info.val << st_info.bit_shift); \ ++ cdt.staMsk = (st_info.mask << st_info.bit_shift); \ ++} ++ ++ ++#endif ++ ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_sfc_flash.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_sfc_flash.h.patch new file mode 100644 index 00000000..95c59ff6 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_sfc_flash.h.patch @@ -0,0 +1,33 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v2/sfc_flash.h b/drivers/mtd/devices/ingenic_sfc_v2/sfc_flash.h +--- a/drivers/mtd/devices/ingenic_sfc_v2/sfc_flash.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v2/sfc_flash.h 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,29 @@ ++#ifndef __SFC_FLASH_H ++#define __SFC_FLASH_H ++#include ++#include ++#include ++#include "sfc.h" ++ ++struct sfc_flash { ++ ++ struct sfc *sfc; ++ void *flash_info; ++ struct device* dev; ++ struct mtd_info mtd; ++ struct mutex lock; ++ int param_offset; //param_offset. ++ ++}; ++ ++struct ingenic_sfc_info { ++ ++ uint8_t num_partition; //flash partiton len ++ uint8_t use_board_info; //use board flag ++ void *flash_param; //flash param ++ void *flash_partition; //flash partiton ++ void *other_args; //other args ++ int param_offset; //param_offset. ++}; ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_spinand.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_spinand.h.patch new file mode 100644 index 00000000..a336f00e --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_spinand.h.patch @@ -0,0 +1,185 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v2/spinand.h b/drivers/mtd/devices/ingenic_sfc_v2/spinand.h +--- a/drivers/mtd/devices/ingenic_sfc_v2/spinand.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v2/spinand.h 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,181 @@ ++#ifndef __SPINAND_H ++#define __SPINAND_H ++#include ++#include "sfc_flash.h" ++#include "spinand_cmd.h" ++ ++#define SPIFLASH_PARAMER_OFFSET 0x6800 ++#define SPINAND_MAGIC_NUM 0x646e616e ++ ++/* the max number of DMA Descriptor */ ++#define DESC_MAX_NUM 2 ++ ++struct ingenic_sfcnand_base_param { ++ uint32_t pagesize; ++ uint32_t blocksize; ++ uint32_t oobsize; ++ uint32_t flashsize; ++ ++ uint16_t tHOLD; ++ uint16_t tSETUP; ++ uint16_t tSHSL_R; ++ uint16_t tSHSL_W; ++ ++ uint16_t tRD; ++ uint16_t tPP; ++ uint16_t tBE; ++ ++ /* ++ * Indicates that NAND flash has a serial plane structure, ++ * needs to convert the plane by changing the column address ++ */ ++ uint8_t plane_select; ++ ++ uint8_t ecc_max; ++ uint8_t need_quad; ++}; ++ ++struct ingenic_sfcnand_partition_param { ++ struct mtd_partition *partition; ++ uint8_t num_partition; ++}; ++ ++struct device_id_struct { ++ uint8_t id_device; ++ char *name; ++ struct ingenic_sfcnand_base_param *param; ++}; ++ ++struct spi_nand_cmd_info { ++ unsigned short cmd; ++ unsigned char dummy_byte; ++ unsigned char addr_nbyte; ++ unsigned char transfer_mode; ++ ++}; ++ ++struct spi_nand_st_info { ++ unsigned short cmd; ++ unsigned char bit_shift; ++ unsigned char mask; ++ unsigned char val; ++ unsigned char len; //length of byte to operate from register ++ unsigned char dummy; ++}; ++ ++struct ingenic_sfcnand_cdt_params { ++ /* general cmd info */ ++ struct spi_nand_cmd_info r_to_cache; ++ struct spi_nand_cmd_info standard_r; ++ struct spi_nand_cmd_info quad_r; ++ struct spi_nand_cmd_info standard_w_cache; ++ struct spi_nand_cmd_info quad_w_cache; ++ struct spi_nand_cmd_info w_exec; ++ struct spi_nand_cmd_info b_erase; ++ struct spi_nand_cmd_info w_en; ++ struct spi_nand_cmd_info ecc_r; ++ ++ /* status polling cmd info */ ++ struct spi_nand_st_info oip; ++}; ++typedef struct ingenic_sfcnand_cdt_params cdt_params_t; ++ ++struct ingenic_sfcnand_ops { ++ cdt_params_t *(*get_cdt_params)(struct sfc_flash *, uint8_t); ++ int (*deal_ecc_status)(struct sfc_flash *, uint8_t, uint8_t); ++ int32_t (*get_feature)(struct sfc_flash *, uint8_t); ++}; ++ ++struct ingenic_sfcnand_device { ++ uint8_t id_manufactory; ++ struct device_id_struct *id_device_list; ++ uint8_t id_device_count; ++ ++ struct ingenic_sfcnand_ops ops; ++ cdt_params_t cdt_params; ++ ++ struct list_head list; ++}; ++ ++struct ingenic_sfcnand_flashinfo { ++ uint8_t id_manufactory; ++ uint8_t id_device; ++ ++ struct ingenic_sfcnand_base_param param; ++ struct ingenic_sfcnand_partition_param partition; ++ struct ingenic_sfcnand_ops *ops; ++ cdt_params_t *cdt_params; ++}; ++ ++struct ingenic_sfcnand_partition { ++ char name[32]; /* identifier string */ ++ uint32_t size; /* partition size */ ++ uint32_t offset; /* offset within the master MTD space */ ++ uint32_t mask_flags; /* master MTD flags to mask out for this partition */ ++ uint32_t manager_mode; /* manager_mode mtd or ubi */ ++}; ++ ++struct ingenic_sfcnand_burner_param { ++ uint32_t magic_num; ++ int32_t partition_num; ++ struct ingenic_sfcnand_partition *partition; ++}; ++ ++int32_t ingenic_sfcnand_register(struct ingenic_sfcnand_device *flash); ++ ++ ++/* SFC CDT Maximum INDEX number */ ++#define INDEX_MAX_NUM 32 ++ ++/* SFC CDT INDEX */ ++enum { ++ /* 1. reset */ ++ NAND_RESET, ++ ++ /* 2. try id */ ++ NAND_TRY_ID, ++ ++ /* 3. try id with dummy */ ++ NAND_TRY_ID_DMY, ++ ++ /* 4. set feature */ ++ NAND_SET_FEATURE, ++ ++ /* 5. get feature */ ++ NAND_GET_FEATURE, ++ ++ /* 6. nand standard read */ ++ NAND_STANDARD_READ_TO_CACHE, ++ NAND_STANDARD_READ_GET_FEATURE, ++ NAND_STANDARD_READ_FROM_CACHE, ++ ++ /* 7. nand quad read */ ++ NAND_QUAD_READ_TO_CACHE, ++ NAND_QUAD_READ_GET_FEATURE, ++ NAND_QUAD_READ_FROM_CACHE, ++ ++ /* 8. nand standard write */ ++ NAND_STANDARD_WRITE_ENABLE, ++ NAND_STANDARD_WRITE_TO_CACHE, ++ NAND_STANDARD_WRITE_EXEC, ++ NAND_STANDARD_WRITE_GET_FEATURE, ++ ++ /* 9. nand quad write */ ++ NAND_QUAD_WRITE_ENABLE, ++ NAND_QUAD_WRITE_TO_CACHE, ++ NAND_QUAD_WRITE_EXEC, ++ NAND_QUAD_WRITE_GET_FEATURE, ++ ++ /* 10. block erase */ ++ NAND_ERASE_WRITE_ENABLE, ++ NAND_BLOCK_ERASE, ++ NAND_ERASE_GET_FEATURE, ++ ++ /* 11. ecc status read */ ++ NAND_ECC_STATUS_READ, ++ ++ /* index count */ ++ NAND_MAX_INDEX, ++}; ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_spinand_cmd.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_spinand_cmd.h.patch new file mode 100644 index 00000000..3edc9c48 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_spinand_cmd.h.patch @@ -0,0 +1,34 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v2/spinand_cmd.h b/drivers/mtd/devices/ingenic_sfc_v2/spinand_cmd.h +--- a/drivers/mtd/devices/ingenic_sfc_v2/spinand_cmd.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v2/spinand_cmd.h 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,30 @@ ++#ifndef __SPINAND_CMD_H ++#define __SPINAND_CMD_H ++ ++#define SPINAND_CMD_RDID 0x9f /* read spi nand id */ ++#define SPINAND_CMD_WREN 0x06 /* spi nand write enable */ ++#define SPINAND_CMD_PRO_LOAD 0x02 /* program load */ ++#define SPINAND_CMD_PRO_LOAD_X4 0x32 /* program load fast*/ ++#define SPINAND_CMD_PRO_EN 0x10 /* program load execute */ ++#define SPINAND_CMD_PARD 0x13 /* read page data to spi nand cache */ ++#define SPINAND_CMD_PLRd 0x84 /* program load random data */ ++#define SPINAND_CMD_PLRd_X4 0xc4 /* program load random data x4*/ ++#define SPINAND_CMD_RDCH 0x03 /* read from spi nand cache */ ++#define SPINAND_CMD_RDCH_X4 0x6b /* read from spi nand cache */ ++#define SPINAND_CMD_FRCH 0x0b /* fast read from spi nand cache */ ++#define SPINAND_CMD_FRCH_IO 0xeb /* for Quad I/O SPI mode */ ++#define SPINAND_CMD_ERASE_128K 0xd8 /* erase spi nand block 128K */ ++#define SPINAND_CMD_GET_FEATURE 0x0f /* get spi nand feature */ ++#define SPINAND_CMD_SET_FEATURE 0x1f /* set spi nand feature */ ++#define SPINAND_CMD_RESET 0xff /* reset nand flash device */ ++ ++ ++#define SPINAND_ADDR_PROTECT 0xa0 /* protect addr */ ++#define SPINAND_ADDR_STATUS 0xc0 /* get feature status addr */ ++#define SPINAND_ADDR_FEATURE 0xb0 /* set feature addr */ ++ ++#define SPINAND_IS_BUSY (1 << 0) /* PROGRAM EXECUTE, PAGE READ, BLOCK ERASE, or RESET command executing */ ++#define SPINAND_OP_BL_128K (128 * 1024) ++ ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_spinor.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_spinor.h.patch new file mode 100644 index 00000000..35929351 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_spinor.h.patch @@ -0,0 +1,1495 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v2/spinor.h b/drivers/mtd/devices/ingenic_sfc_v2/spinor.h +--- a/drivers/mtd/devices/ingenic_sfc_v2/spinor.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v2/spinor.h 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,1491 @@ ++#ifndef __SPINOR_H ++#define __SPINOR_H ++#include "sfc_flash.h" ++#include "spinor_cmd.h" ++ ++#define SPIFLASH_PARAMER_OFFSET 0x3c00 ++#define NOR_MAJOR_VERSION_NUMBER 2 ++#define NOR_MINOR_VERSION_NUMBER 0 ++#define NOR_REVERSION_NUMBER 0 ++#define NOR_VERSION (NOR_MAJOR_VERSION_NUMBER | (NOR_MINOR_VERSION_NUMBER << 8) | (NOR_REVERSION_NUMBER << 16)) ++ ++ ++#define SIZEOF_NAME 32 ++ ++#define NOR_MAGIC 0x726f6e //ascii "nor" ++#define NOR_PART_NUM 10 ++#define NORFLASH_PART_RW 0 ++#define NORFLASH_PART_WO 1 ++#define NORFLASH_PART_RO 2 ++ ++/* the max number of DMA Descriptor */ ++#define DESC_MAX_NUM 64 ++ ++ ++struct spi_nor_cmd_info { ++ unsigned short cmd; ++ unsigned char dummy_byte; ++ unsigned char addr_nbyte; ++ unsigned char transfer_mode; ++ ++}; ++ ++struct spi_nor_st_info { ++ unsigned short cmd; ++ unsigned char bit_shift; ++ unsigned char mask; ++ unsigned char val; ++ unsigned char len; //length of byte to operate from register ++ unsigned char dummy; ++}; ++ ++struct spi_nor_info { ++ unsigned char name[32]; ++ unsigned int id; ++ ++ struct spi_nor_cmd_info read_standard; ++ struct spi_nor_cmd_info read_quad; ++ ++ struct spi_nor_cmd_info write_standard; ++ struct spi_nor_cmd_info write_quad; ++ ++ struct spi_nor_cmd_info sector_erase_32k; ++ struct spi_nor_cmd_info sector_erase_64k; ++ ++ struct spi_nor_cmd_info wr_en; ++ struct spi_nor_cmd_info en4byte; ++ struct spi_nor_cmd_info enotp; ++ struct spi_nor_cmd_info exotp; ++ struct spi_nor_st_info quad_set; ++ struct spi_nor_st_info quad_get; ++ struct spi_nor_st_info busy; ++ ++ unsigned short quad_ops_mode; ++ unsigned short addr_ops_mode; ++ unsigned short otp_ops_mode; ++ ++ unsigned int tCHSH; //hold ++ unsigned int tSLCH; //setup ++ unsigned int tSHSL_RD; //interval ++ unsigned int tSHSL_WR; ++ ++ unsigned int chip_size; ++ unsigned int page_size; ++ unsigned int erase_size; ++ unsigned int addr_len; ++ ++ unsigned char chip_erase_cmd; ++}; ++ ++struct nor_partition { ++ char name[32]; ++ uint32_t size; ++ uint32_t offset; ++ uint32_t mask_flags;//bit 0-1 mask the partiton RW mode, 0:RW 1:W 2:R ++ uint32_t manager_mode; ++}; ++ ++struct norflash_partitions { ++ struct nor_partition nor_partition[NOR_PART_NUM]; ++ uint32_t num_partition_info; ++}; ++ ++struct nor_private_data { ++ unsigned int fs_erase_size; ++ unsigned char uk_quad; ++}; ++ ++ ++struct burner_params { ++ uint32_t magic; ++ uint32_t version; ++ struct spi_nor_info spi_nor_info; ++ struct norflash_partitions norflash_partitions; ++ struct nor_private_data nor_pri_data; ++ unsigned int spi_nor_info_size; ++}; ++ ++struct spi_nor_flash_ops { ++ int (*set_4byte_mode)(struct sfc_flash *flash); ++ int (*set_quad_mode)(struct sfc_flash *flash); ++}; ++ ++struct spinor_flashinfo { ++ ++ int quad_succeed; ++ struct spi_nor_flash_ops *nor_flash_ops; ++ struct spi_nor_info *nor_flash_info; ++ struct spi_nor_cmd_info *cur_r_cmd; ++ struct spi_nor_cmd_info *cur_w_cmd; ++ struct norflash_partitions *norflash_partitions; ++ struct nor_private_data *nor_pri_data; ++ ++}; ++ ++/* SFC CDT Maximum INDEX number */ ++#define INDEX_MAX_NUM 32 ++ ++enum { ++ /* 1. nor reset */ ++ NOR_RESET_ENABLE, ++ NOR_RESET, ++ ++ /* 2. nor read id */ ++ NOR_READ_ID, ++ ++ /* 3. nor get status */ ++ NOR_GET_STATUS, ++ NOR_GET_STATUS_1, ++ NOR_GET_STATUS_2, ++ ++ /* 4. nor singleRead */ ++ NOR_READ_STANDARD, ++ ++ /* 5. nor quadRead */ ++ NOR_READ_QUAD, ++ ++ /* 6. nor writeStandard */ ++ NOR_WRITE_STANDARD_ENABLE, ++ NOR_WRITE_STANDARD, ++ NOR_WRITE_STANDARD_FINISH, ++ ++ /* 7. nor writeQuad */ ++ NOR_WRITE_QUAD_ENABLE, ++ NOR_WRITE_QUAD, ++ NOR_WRITE_QUAD_FINISH, ++ ++ /* 8. nor erase */ ++ NOR_ERASE_WRITE_ENABLE_32K, ++ NOR_ERASE_32K, ++ NOR_ERASE_FINISH_32K, ++ NOR_ERASE_WRITE_ENABLE_64K, ++ NOR_ERASE_64K, ++ NOR_ERASE_FINISH_64K, ++ ++ /* 9. quad mode */ ++ NOR_QUAD_SET_ENABLE, ++ NOR_QUAD_SET, ++ NOR_QUAD_FINISH, ++ NOR_QUAD_GET, ++ ++ /* 10. nor write ENABLE */ ++ NOR_WRITE_ENABLE, ++ ++ /* 11. entry 4byte mode */ ++ NOR_EN_4BYTE, ++ ++ /* index count */ ++ NOR_MAX_INDEX, ++ ++ /*need ecter otp mode to set quad mode*/ ++ NOR_ENTER_OTP, ++ NOR_OTP_QUAD_SET_ENABLE, ++ NOR_OTP_QUAD_SET, ++ NOR_OTP_QUAD_FINISH, ++ NOR_OTP_QUAD_GET, ++ NOR_EXIT_OTP, ++ ++}; ++ ++static struct spi_nor_info spi_nor_info_table[] = { ++ { ++ .name = "GD25LQ128C", ++ .id = 0xc86018, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 0, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 16 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 3, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR_1, ++ .bit_shift = 1, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR_1, ++ .bit_shift = 1, ++ }, ++ }, ++ { ++ .name = "EN25QH64A", ++ .id = 0x1c7017, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 0, ++ /* otp_ops_mode: set quad mode need enter otp, set 1 */ ++ .otp_ops_mode = 1, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 8 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 3, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR, ++ .bit_shift = 6, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR, ++ .bit_shift = 6, ++ }, ++ }, ++ { ++ .name = "EN25QH128A", ++ .id = 0x1c7018, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 0, ++ /* otp_ops_mode: set quad mode need enter otp, set 1 */ ++ .otp_ops_mode = 1, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 16 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 3, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR, ++ .bit_shift = 6, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR, ++ .bit_shift = 6, ++ }, ++ }, ++ { ++ .name = "EN25QH256A", ++ .id = 0x1c7019, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 1, ++ /* otp_ops_mode: set quad mode need enter otp, set 1 */ ++ .otp_ops_mode = 1, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 32 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 4, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR, ++ .bit_shift = 6, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR, ++ .bit_shift = 6, ++ }, ++ }, ++ { ++ .name = "EN25QX128A", ++ .id = 0x1c7118, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 0, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 16 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 3, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR_1, ++ .bit_shift = 1, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR_1, ++ .bit_shift = 1, ++ }, ++ }, ++ { ++ .name = "GD25Q64C", ++ .id = 0xc84017, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 0, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 8 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 3, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR_1, ++ .bit_shift = 1, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR_1, ++ .bit_shift = 1, ++ }, ++ }, ++ { ++ .name = "GD25Q127C", ++ .id = 0xc84018, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 0, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 16 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 3, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR_1, ++ .bit_shift = 1, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR_1, ++ .bit_shift = 1, ++ }, ++ }, ++ { ++ .name = "GD25Q256D/E", ++ .id = 0xc84019, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 1, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 32 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 4, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR_1, ++ .bit_shift = 1, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR_1, ++ .bit_shift = 1, ++ }, ++ }, ++ { ++ .name = "IS25LP064D", ++ .id = 0x9d6017, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 0, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 8 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 3, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR, ++ .bit_shift = 6, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR, ++ .bit_shift = 6, ++ }, ++ }, ++ { ++ .name = "IS25LP128F", ++ .id = 0x9d6018, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 0, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 16 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 3, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR, ++ .bit_shift = 6, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR, ++ .bit_shift = 6, ++ }, ++ }, ++ { ++ .name = "MX25L6406F", ++ .id = 0xc22017, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 0, ++ .tCHSH = 3, ++ .tSLCH = 3, ++ .tSHSL_RD = 7, ++ .tSHSL_WR = 30, ++ .chip_size = 8 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 3, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR, ++ .bit_shift = 6, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR, ++ .bit_shift = 6, ++ }, ++ }, ++ { ++ .name = "MX25L12835F", ++ .id = 0xc22018, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 0, ++ .tCHSH = 3, ++ .tSLCH = 3, ++ .tSHSL_RD = 7, ++ .tSHSL_WR = 30, ++ .chip_size = 16 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 3, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR, ++ .bit_shift = 6, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR, ++ .bit_shift = 6, ++ }, ++ }, ++ { ++ .name = "WIN25Q64", ++ .id = 0xef4017, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 0, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 8 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 3, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR_1, ++ .bit_shift = 1, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR_1, ++ .bit_shift = 1, ++ }, ++ }, ++ { ++ .name = "WIN25Q128", ++ .id = 0xef4018, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 0, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 16 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 3, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR_1, ++ .bit_shift = 1, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR_1, ++ .bit_shift = 1, ++ }, ++ }, ++ { ++ .name = "XM25QH64A", ++ .id = 0x207017, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 0, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 8 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 3, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR_1, ++ .bit_shift = 1, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR_1, ++ .bit_shift = 1, ++ }, ++ }, ++ { ++ .name = "XM25QH128A", ++ .id = 0x207018, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 0, ++ /* otp_ops_mode: set quad mode need enter otp, set 1 */ ++ .otp_ops_mode = 1, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 16 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 3, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR_1, ++ .bit_shift = 1, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR_1, ++ .bit_shift = 1, ++ }, ++ }, ++ { ++ .name = "XM25QH64B", ++ .id = 0x206017, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 0, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 8 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 3, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR, ++ .bit_shift = 6, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR, ++ .bit_shift = 6, ++ }, ++ }, ++ { ++ .name = "XM25QH128B", ++ .id = 0x206018, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 0, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 16 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 3, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR, ++ .bit_shift = 6, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR, ++ .bit_shift = 6, ++ }, ++ }, ++ { ++ .name = "XM25QH64C", ++ .id = 0x204017, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 0, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 8 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 3, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR_1, ++ .bit_shift = 1, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR_1, ++ .bit_shift = 1, ++ }, ++ }, ++ { ++ .name = "XM25QH128C", ++ .id = 0x204018, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 0, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 16 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 3, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR_1, ++ .bit_shift = 1, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR_1, ++ .bit_shift = 1, ++ }, ++ }, ++ { ++ .name = "XM25QH256C", ++ .id = 0x204019, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 1, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 32 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 4, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR_1, ++ .bit_shift = 1, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR_1, ++ .bit_shift = 1, ++ }, ++ }, ++ { ++ .name = "XM25QU128C", ++ .id = 0x204118, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 0, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 16 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 3, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR_1, ++ .bit_shift = 1, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR_1, ++ .bit_shift = 1, ++ }, ++ }, ++ { ++ .name = "XM25QU256C", ++ .id = 0x204119, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 1, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 32 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 4, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR_1, ++ .bit_shift = 1, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR_1, ++ .bit_shift = 1, ++ }, ++ }, ++ { ++ .name = "FM25Q64A", ++ .id = 0xF83217, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 0, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 8 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 3, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR_1, ++ .bit_shift = 1, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR_1, ++ .bit_shift = 1, ++ }, ++ }, ++ { ++ .name = "MX25L25645G/35F", ++ .id = 0xc22019, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 1, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 32 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 4, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR, ++ .bit_shift = 6, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR, ++ .bit_shift = 6, ++ }, ++ }, ++ { ++ .name = "MX25L51245G", ++ .id = 0xc2201A, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 1, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 64 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 4, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR, ++ .bit_shift = 6, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR, ++ .bit_shift = 6, ++ }, ++ }, ++ { ++ .name = "W25Q256JV", ++ .id = 0xef4019, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 1, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 32 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 4, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR_1, ++ .bit_shift = 1, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR_1, ++ .bit_shift = 1, ++ }, ++ }, ++ { ++ .name = "W25Q512JV", ++ .id = 0xef4020, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 1, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 64 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 4, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR_1, ++ .bit_shift = 1, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR_1, ++ .bit_shift = 1, ++ }, ++ }, ++ { ++ .name = "BY25Q64AS", ++ .id = 0x684017, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 0, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 8 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 3, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR_1, ++ .bit_shift = 1, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR_1, ++ .bit_shift = 1, ++ }, ++ }, ++ { ++ .name = "BY25Q128AS", ++ .id = 0x684018, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 0, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 16 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 3, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR_1, ++ .bit_shift = 1, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR_1, ++ .bit_shift = 1, ++ }, ++ }, ++ { ++ .name = "ZB25VQ64", ++ .id = 0x5e4017, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 0, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 8 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 3, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR_1, ++ .bit_shift = 1, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR_1, ++ .bit_shift = 1, ++ }, ++ }, ++ { ++ .name = "ZB25VQ128", ++ .id = 0x5e4018, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 0, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 16 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 3, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR_1, ++ .bit_shift = 1, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR_1, ++ .bit_shift = 1, ++ }, ++ }, ++ { ++ .name = "XT25F64B", ++ .id = 0x0b4017, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 0, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 8 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 3, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR_1, ++ .bit_shift = 1, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR_1, ++ .bit_shift = 1, ++ }, ++ }, ++ { ++ .name = "XT25F128B", ++ .id = 0x0b4018, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 0, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 16 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 3, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR_1, ++ .bit_shift = 1, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR_1, ++ .bit_shift = 1, ++ }, ++ }, ++ { ++ .name = "FM25Q64A", ++ .id = 0xa14017, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 0, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 8 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 3, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR_1, ++ .bit_shift = 1, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR_1, ++ .bit_shift = 1, ++ }, ++ }, ++ { ++ .name = "FM25Q128A", ++ .id = 0xa14018, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 0, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 16 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 3, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR_1, ++ .bit_shift = 1, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR_1, ++ .bit_shift = 1, ++ }, ++ }, ++ { ++ .name = "FM25W128", ++ .id = 0xa12818, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 0, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 16 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 3, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR_1, ++ .bit_shift = 1, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR_1, ++ .bit_shift = 1, ++ }, ++ }, ++ { ++ .name = "P25Q64H", ++ .id = 0x856017, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 0, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 8 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 3, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR_1, ++ .bit_shift = 1, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR_1, ++ .bit_shift = 1, ++ }, ++ }, ++ { ++ .name = "P25Q128H", ++ .id = 0x856018, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 0, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 16 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 3, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR_1, ++ .bit_shift = 1, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR_1, ++ .bit_shift = 1, ++ }, ++ ++ }, ++ { ++ .name = "GM25Q64A", ++ .id = 0x1c4017, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 0, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 8 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 3, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR_1, ++ .bit_shift = 1, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR_1, ++ .bit_shift = 1, ++ }, ++ }, ++ { ++ .name = "GM25Q128A", ++ .id = 0x1c4018, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 0, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 16 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 3, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR_1, ++ .bit_shift = 1, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR_1, ++ .bit_shift = 1, ++ }, ++ }, ++ { ++ .name = "NM25Q64EVB", ++ .id = 0x522217, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 0, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 8 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 3, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR_1, ++ .bit_shift = 2, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR_1, ++ .bit_shift = 2, ++ }, ++ }, ++ { ++ .name = "NM25Q128EVB", ++ .id = 0x522118, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 0, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 16 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 3, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR_1, ++ .bit_shift = 2, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR_1, ++ .bit_shift = 2, ++ }, ++ }, ++ { ++ .name = "ZD25Q64B", ++ .id = 0xba3217, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 0, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 8 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 3, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR_1, ++ .bit_shift = 1, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR_1, ++ .bit_shift = 1, ++ }, ++ }, ++ { ++ .name = "SK25P128", ++ .id = 0x256018, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 0, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 16 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 3, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR, ++ .bit_shift = 6, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR, ++ .bit_shift = 6, ++ }, ++ }, ++ { ++ .name = "PY25Q128HA", ++ .id = 0x852018, ++#ifdef CONFIG_SPI_STANDARD_MODE ++ .quad_ops_mode = 0, ++#else ++ .quad_ops_mode = 1, ++#endif ++ /* addr_ops_mode: en4byte or addr_len > 3, set 1 */ ++ .addr_ops_mode = 0, ++ .tCHSH = 5, ++ .tSLCH = 5, ++ .tSHSL_RD = 20, ++ .tSHSL_WR = 20, ++ .chip_size = 16 * 1024 * 1024, ++ .page_size = 256, ++ .erase_size = 32 * 1024, ++ .addr_len = 3, ++ .chip_erase_cmd = SPINOR_OP_CHIP_ERASE, ++ .quad_set = { ++ .cmd = SPINOR_OP_WRSR_1, ++ .bit_shift = 1, ++ }, ++ .quad_get = { ++ .cmd = SPINOR_OP_RDSR_1, ++ .bit_shift = 1, ++ }, ++ }, ++}; ++ ++#endif ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_spinor_cmd.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_spinor_cmd.h.patch new file mode 100644 index 00000000..651a1dcd --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mtd_devices_ingenic_sfc_v2_spinor_cmd.h.patch @@ -0,0 +1,89 @@ +diff -drupN a/drivers/mtd/devices/ingenic_sfc_v2/spinor_cmd.h b/drivers/mtd/devices/ingenic_sfc_v2/spinor_cmd.h +--- a/drivers/mtd/devices/ingenic_sfc_v2/spinor_cmd.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/mtd/devices/ingenic_sfc_v2/spinor_cmd.h 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,85 @@ ++#ifndef __SPINOR_CMD_H ++#define __SPINOR_CMD_H ++ ++/* Flash opcodes. */ ++#define SPINOR_OP_RSTEN 0x66 /* reset enable */ ++#define SPINOR_OP_RST 0x99 /* reset */ ++#define SPINOR_OP_WREN 0x06 /* Write enable */ ++#define SPINOR_OP_RDSR 0x05 /* Read status register */ ++#define SPINOR_OP_RDSR_1 0x35 /* Read status1 register */ ++#define SPINOR_OP_RDSR_2 0x15 /* Read status2 register */ ++#define SPINOR_OP_WRSR 0x01 /* Write status register 1 byte */ ++#define SPINOR_OP_WRSR_1 0x31 /* Write status1 register 1 byte */ ++#define SPINOR_OP_WRSR_2 0x11 /* Write status2 register 1 byte */ ++#define SPINOR_OP_READ 0x03 /* Read data bytes (low frequency) */ ++#define SPINOR_OP_READ_FAST 0x0b /* Read data bytes (high frequency) */ ++#define SPINOR_OP_READ_1_1_2 0x3b /* Read data bytes (Dual SPI) */ ++#define SPINOR_OP_READ_1_1_4 0x6b /* Read data bytes (Quad SPI) */ ++#define SPINOR_OP_PP 0x02 /* Page program (up to 256 bytes) */ ++#define SPINOR_OP_QPP 0x32 /* Page program (up to 256 bytes) */ ++#define SPINOR_OP_BE_4K 0x20 /* Erase 4KiB block */ ++#define SPINOR_OP_BE_4K_PMC 0xd7 /* Erase 4KiB block on PMC chips */ ++#define SPINOR_OP_BE_32K 0x52 /* Erase 32KiB block */ ++#define SPINOR_OP_CHIP_ERASE 0xc7 /* Erase whole flash chip */ ++#define SPINOR_OP_SE 0xd8 /* Sector erase (usually 64KiB) */ ++#define SPINOR_OP_RDID 0x9f /* Read JEDEC ID */ ++#define SPINOR_OP_RDCR 0x35 /* Read configuration register */ ++#define SPINOR_OP_RDFSR 0x70 /* Read flag status register */ ++ ++/* 4-byte address opcodes - used on Spansion and some Macronix flashes. */ ++#define SPINOR_OP_READ4 0x13 /* Read data bytes (low frequency) */ ++#define SPINOR_OP_READ4_FAST 0x0c /* Read data bytes (high frequency) */ ++#define SPINOR_OP_READ4_1_1_2 0x3c /* Read data bytes (Dual SPI) */ ++#define SPINOR_OP_READ4_1_1_4 0x6c /* Read data bytes (Quad SPI) */ ++#define SPINOR_OP_PP_4B 0x12 /* Page program (up to 256 bytes) */ ++#define SPINOR_OP_SE_4B 0xdc /* Sector erase (usually 64KiB) */ ++ ++/* Used for SST flashes only. */ ++#define SPINOR_OP_BP 0x02 /* Byte program */ ++#define SPINOR_OP_WRDI 0x04 /* Write disable */ ++#define SPINOR_OP_AAI_WP 0xad /* Auto address increment word program */ ++ ++/* Used for Macronix and Winbond flashes. */ ++#define SPINOR_OP_EN4B 0xb7 /* Enter 4-byte mode */ ++#define SPINOR_OP_EX4B 0xe9 /* Exit 4-byte mode */ ++ ++#define SPINOR_OP_ENOTP 0x3a /* Enter otp mode */ ++#define SPINOR_OP_EXOTP 0x04 /* Exit otp mode */ ++ ++/* Used for Spansion flashes only. */ ++#define SPINOR_OP_BRWR 0x17 /* Bank register write */ ++ ++/* Status Register bits. */ ++#define SR_WIP 1 /* Write in progress */ ++#define SR_WEL 2 /* Write enable latch */ ++#define SR_SQE (1 << 1) /* QUAD MODE enable */ ++/* meaning of other SR_* bits may differ between vendors */ ++#define SR_BP0 4 /* Block protect 0 */ ++#define SR_BP1 8 /* Block protect 1 */ ++#define SR_BP2 0x10 /* Block protect 2 */ ++#define SR_SRWD 0x80 /* SR write protect */ ++ ++#define SR_QUAD_EN_MX 0x40 /* Macronix Quad I/O */ ++ ++/* Flag Status Register bits */ ++#define FSR_READY 0x80 ++ ++/* Configuration Register bits. */ ++#define CR_QUAD_EN_SPAN 0x2 /* Spansion Quad I/O */ ++ ++ ++#define CMD_WREN 0x06 /* Write Enable */ ++#define CMD_EN4B 0xB7 ++#define CMD_EX4B 0xE9 ++#define CMD_ENOTP 0x3a ++#define CMD_EXOTP 0x04 ++/* nor cmd entry deep power down and Release from Deep Power-Down and Read Device ID */ ++#define CMD_DP (0xB9) ++#define CMD_RDP (0xAB) ++ ++ ++#define BUFFER_SIZE PAGE_SIZE ++ ++#define NOR_SIZE_16M 0x1000000 ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_Kconfig.patch new file mode 100644 index 00000000..a796285a --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_Kconfig.patch @@ -0,0 +1,35 @@ +diff -drupN a/drivers/net/Kconfig b/drivers/net/Kconfig +--- a/drivers/net/Kconfig 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/net/Kconfig 2022-06-09 05:02:30.000000000 +0300 +@@ -25,9 +25,6 @@ menuconfig NETDEVICES + # that for each of the symbols. + if NETDEVICES + +-config MII +- tristate +- + config NET_CORE + default y + bool "Network core driver support" +@@ -103,6 +100,13 @@ config NET_FC + adaptor below. You also should have said Y to "SCSI support" and + "SCSI generic support". + ++config MII ++ tristate "Generic Media Independent Interface device support" ++ help ++ Most ethernet controllers have MII transceiver either as an external ++ or internal device. It is safe to say Y or M here even if your ++ ethernet card lacks MII. ++ + config IFB + tristate "Intermediate Functional Block support" + depends on NET_CLS_ACT +@@ -423,6 +427,6 @@ config FUJITSU_ES + This driver provides support for Extended Socket network device + on Extended Partitioning of FUJITSU PRIMEQUEST 2000 E2 series. + +-source "drivers/net/hyperv/Kconfig" ++source "drivers/net/ethernet/Kconfig" + + endif # NETDEVICES diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_Kconfig.patch new file mode 100644 index 00000000..92c44f03 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_Kconfig.patch @@ -0,0 +1,11 @@ +diff -drupN a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig +--- a/drivers/net/ethernet/Kconfig 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/net/ethernet/Kconfig 2022-06-09 05:02:30.000000000 +0300 +@@ -17,6 +17,7 @@ config MDIO + config SUNGEM_PHY + tristate + ++source "drivers/net/ethernet/ingenic/Kconfig" + source "drivers/net/ethernet/3com/Kconfig" + source "drivers/net/ethernet/adaptec/Kconfig" + source "drivers/net/ethernet/aeroflex/Kconfig" diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_Makefile.patch new file mode 100644 index 00000000..7671a520 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_Makefile.patch @@ -0,0 +1,8 @@ +diff -drupN a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile +--- a/drivers/net/ethernet/Makefile 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/net/ethernet/Makefile 2022-06-09 05:02:30.000000000 +0300 +@@ -87,3 +87,4 @@ obj-$(CONFIG_NET_VENDOR_VIA) += via/ + obj-$(CONFIG_NET_VENDOR_WIZNET) += wiznet/ + obj-$(CONFIG_NET_VENDOR_XILINX) += xilinx/ + obj-$(CONFIG_NET_VENDOR_XIRCOM) += xircom/ ++obj-$(CONFIG_INGENIC_MAC) += ingenic/ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_ingenic_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_ingenic_Kconfig.patch new file mode 100644 index 00000000..b70d7d32 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_ingenic_Kconfig.patch @@ -0,0 +1,32 @@ +diff -drupN a/drivers/net/ethernet/ingenic/Kconfig b/drivers/net/ethernet/ingenic/Kconfig +--- a/drivers/net/ethernet/ingenic/Kconfig 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/net/ethernet/ingenic/Kconfig 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,28 @@ ++config INGENIC_MAC ++ tristate "ingenic on-chip MAC support" ++ select CRC32 ++ select RMII ++ select MII ++ help ++ This is the driver for INGENIC on-chip mac device. ++ ++config INGENIC_MAC_DMA_INTERFACES ++ bool "Ingenic mac dma interfaces" ++ depends on INGENIC_MAC ++ help ++ This is for MAC Dma interfaces selection ++choice ++ prompt "Ingenic mac dma bus interfaces" ++ depends on INGENIC_MAC_DMA_INTERFACES ++ default CONFIG_INGENIC_MAC_AHB_BUS ++ ++config INGENIC_MAC_AXI_BUS ++ bool "MAC_AXI_BUS" ++ help ++ Select for mac dma AXI bus ++ ++config INGENIC_MAC_AHB_BUS ++ bool "MAC_AHB_BUS" ++ help ++ Select for mac dma AHB bus ++endchoice diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_ingenic_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_ingenic_Makefile.patch new file mode 100644 index 00000000..a61ed3e5 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_ingenic_Makefile.patch @@ -0,0 +1,35 @@ +diff -drupN a/drivers/net/ethernet/ingenic/Makefile b/drivers/net/ethernet/ingenic/Makefile +--- a/drivers/net/ethernet/ingenic/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/net/ethernet/ingenic/Makefile 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,31 @@ ++ ++#################################################### ++# Explanation for EXTRA_FLAGS ++# -DDEBUG => Enable the debug trace for driver ++# -DIPC_OFFLOAD => Enables the IP and TCP checksum offloading feature in HW (IPV4 only) ++# -DENH_DESC => Enables Enhanced Descriptors ++# -DENH_DESC_8W => Enable Enhanced Descriptors of 8words or else Descriptor will be of 4words. ++#################################################### ++ ++ ++#with the below flags enables Debug messages ++ ++#EXTRA_CFLAGS += -DDEBUG ++#EXTRA_CFLAGS +=-DDEBUG -DIPC_OFFLOAD ++#EXTRA_CFLAGS += -DDEBUG -DIPC_OFFLOAD ++#EXTRA_CFLAGS += -DIPC_OFFLOAD ++ ++ ++#Enhanced Descriptor ++#EXTRA_CFLAGS += -DENH_DESC ++#EXTRA_CFLAGS += -DENH_DESC -DIPC_OFFLOAD ++EXTRA_CFLAGS += -DENH_DESC -DENH_DESC_8W ++#EXTRA_CFLAGS += -DDEBUG -DENH_DESC -DENH_DESC_8W ++#EXTRA_CFLAGS += -DDEBUG -DENH_DESC -DENH_DESC_8W -DIPC_OFFLOAD ++#EXTRA_CFLAGS += -DENH_DESC -DENH_DESC_8W -DIPC_OFFLOAD ++#EXTRA_CFLAGS += -DENH_DESC -DENH_DESC_8W -DAVB_SUPPORT -DDEBUG ++#EXTRA_CFLAGS += -DENH_DESC -DENH_DESC_8W -DAVB_SUPPORT ++#EXTRA_CFLAGS += -DENH_DESC -DENH_DESC_8W ++ ++obj-$(CONFIG_INGENIC_MAC) += synopGMAC_plat.o synopGMAC_Dev.o ++obj-$(CONFIG_INGENIC_MAC) += ingenic_mac.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_ingenic_ingenic_mac.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_ingenic_ingenic_mac.c.patch new file mode 100644 index 00000000..efa5259d --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_ingenic_ingenic_mac.c.patch @@ -0,0 +1,2447 @@ +diff -drupN a/drivers/net/ethernet/ingenic/ingenic_mac.c b/drivers/net/ethernet/ingenic/ingenic_mac.c +--- a/drivers/net/ethernet/ingenic/ingenic_mac.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/net/ethernet/ingenic/ingenic_mac.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,2443 @@ ++/* ++ * ingenic On-Chip MAC Driver ++ * ++ * Copyright (C) 2010 - 2011 Ingenic Semiconductor Inc. ++ * ++ * Licensed under the GPL-2 or later. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "ingenic_mac.h" ++#include ++ ++DEFINE_SEMAPHORE(mutex_mdio); ++int debug_enable = 0; ++#define INGENIC_MAC_DRV_NAME "dwc-mac" ++#define INGENIC_MAC_DRV_VERSION "1.0" ++#define INGENIC_MAC_DRV_DESC "Ingenic on-chip Ethernet MAC driver" ++module_param(debug_enable, int, 0644); ++MODULE_AUTHOR("Lutts Wolf "); ++MODULE_VERSION(INGENIC_MAC_DRV_VERSION); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION(INGENIC_MAC_DRV_DESC); ++MODULE_ALIAS("platform:"INGENIC_MAC_DRV_NAME); ++#define COPYBREAK_DEFAULT 256 ++static unsigned int copybreak __read_mostly = COPYBREAK_DEFAULT; ++module_param(copybreak, uint, 0644); ++MODULE_PARM_DESC(copybreak, ++ "Maximum size of packet that is copied to a new buffer on receive"); ++ ++#define INGENIC_MAC_RX_BUFFER_WRITE 16 /* Must be power of 2 */ ++ ++static synopGMACdevice *g_gmacdev; ++/* Generate the bit field mask from msb to lsb */ ++#define BITS_H2L(msb, lsb) ((0xFFFFFFFF >> (32-((msb)-(lsb)+1))) << (lsb)) ++ ++static const struct of_device_id ingenic_mac_dt_match[]; ++ ++static int ingenic_mac_phy_hwrst(struct platform_device *pdev, bool init) ++{ ++ struct net_device *ndev = platform_get_drvdata(pdev); ++ struct ingenic_mac_local *lp = netdev_priv(ndev); ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ enum of_gpio_flags flags; ++ int ret = 0; ++ struct pinctrl *p = pinctrl_get(dev); ++ struct pinctrl_state *state = NULL; ++ ++ if (IS_ERR_OR_NULL(p)) { ++ dev_warn(&pdev->dev, "can not get pinctrl\n"); ++ return 0; ++ } ++ ++ if (init) ++ lp->reset_gpio = -ENODEV; ++ ++ if (!(lp->reset_gpio < 0)) ++ goto hw_reset; ++ ++ lp->reset_gpio = of_get_named_gpio_flags(np, "ingenic,rst-gpio", 0, &flags); ++ if (lp->reset_gpio < 0) ++ goto out; ++ ret = devm_gpio_request(dev, lp->reset_gpio, "mac-hw-rst"); ++ if (ret) { ++ lp->reset_gpio = ret; ++ dev_err(dev, "ingenic mac-hw-rst gpio request failed errno(%d)\n", ret); ++ goto out; ++ } ++ lp->reset_lvl = flags & OF_GPIO_ACTIVE_LOW ? 0 : 1; ++ ++#define DEFAULT_RESET_MS 10 ++ ret = of_property_read_u32(np, "ingenic,rst-ms", &lp->reset_ms); ++ if (ret < 0) ++ lp->reset_ms = DEFAULT_RESET_MS; ++#undef DEFAULT_RESET_MS ++ ++hw_reset: ++ state = pinctrl_lookup_state(p, "reset"); ++ if (!IS_ERR_OR_NULL(state)) ++ pinctrl_select_state(p, state); ++ ++ gpio_direction_output(lp->reset_gpio, lp->reset_lvl); ++ if (in_atomic()) ++ mdelay(lp->reset_ms); ++ else ++ msleep(lp->reset_ms); ++ gpio_direction_output(lp->reset_gpio, !lp->reset_lvl); ++ ++ state = pinctrl_lookup_state(p, PINCTRL_STATE_DEFAULT); ++ if (!IS_ERR_OR_NULL(state)) ++ pinctrl_select_state(p, state); ++ ++out: ++ pinctrl_put(p); ++ return ret; ++} ++ ++static inline unsigned char str2hexnum(unsigned char c) ++{ ++ if (c >= '0' && c <= '9') ++ return c - '0'; ++ if (c >= 'a' && c <= 'f') ++ return c - 'a' + 10; ++ if (c >= 'A' && c <= 'F') ++ return c - 'A' + 10; ++ ++ return 0; /* foo */ ++} ++ ++static inline void str2eaddr(unsigned char *ea, unsigned char *str) ++{ ++ int i; ++ ++ for (i = 0; i < 6; i++) { ++ unsigned char num; ++ ++ if ((*str == '.') || (*str == ':')) ++ str++; ++ num = str2hexnum(*str++) << 4; ++ num |= str2hexnum(*str++); ++ ea[i] = num; ++ } ++} ++ ++static int bootargs_ethaddr = 0; ++static unsigned char ethaddr_hex[6]; ++ ++static int __init ethernet_addr_setup(char *str) ++{ ++ if (!str) { ++ printk("ethaddr not set in command line\n"); ++ return -1; ++ } ++ bootargs_ethaddr = 1; ++ str2eaddr(ethaddr_hex, str); ++ ++ return 0; ++} ++ ++__setup("ethaddr=", ethernet_addr_setup); ++ ++/* debug routines */ ++__attribute__((__unused__)) static void ingenic_mac_dump_pkt_data(unsigned char *data, int len) { ++ int i = 0; ++ printk("\t0x0000: "); ++ for (i = 0; i < len; i++) { ++ printk("%02x", data[i]); ++ ++ if (i % 2) ++ printk(" "); ++ ++ if ( (i != 0) && ((i % 16) == 15) ) ++ printk("\n\t0x%04x: ", i+1); ++ } ++ printk("\n"); ++} ++ ++__attribute__((__unused__)) static void ingenic_mac_dump_skb_data(struct sk_buff *skb) { ++ printk("\n\n===================================\n"); ++ printk("head = 0x%08x, data = 0x%08x, tail = 0x%08x, end = 0x%08x\n", ++ (unsigned int)(skb->head), (unsigned int)(skb->data), ++ (unsigned int)(skb->tail), (unsigned int)(skb->end)); ++ printk("len = %d\n", skb->len); ++ ingenic_mac_dump_pkt_data(skb->data, skb->len); ++ printk("\n=====================================\n"); ++} ++ ++struct ingenic_mac_reg ++{ ++ u32 addr; ++ char * name; ++}; ++ ++static struct ingenic_mac_reg mac[] = ++{ ++ { 0x0000, " Config" }, ++ { 0x0004, " Frame Filter" }, ++ { 0x0008, " MAC HT High" }, ++ { 0x000C, " MAC HT Low" }, ++ { 0x0010, " GMII Addr" }, ++ { 0x0014, " GMII Data" }, ++ { 0x0018, " Flow Control" }, ++ { 0x001C, " VLAN Tag" }, ++ { 0x0020, " GMAC Version" }, ++ { 0x0024, " GMAC Debug " }, ++ { 0x0028, "Remote Wake-Up Frame Filter" }, ++ { 0x002C, " PMT Control and Status" }, ++ { 0x0030, " LPI Control and status" }, ++ { 0x0034, " LPI Timers Control" }, ++ { 0x0038, " Interrupt Status" }, ++ { 0x003c, " Interrupt Mask" }, ++ { 0x0040, " MAC Addr0 High" }, ++ { 0x0044, " MAC Addr0 Low" }, ++ { 0x0048, " MAC Addr1 High" }, ++ { 0x004c, " MAC Addr1 Low" }, ++ { 0x0100, " MMC Ctrl Reg " }, ++ { 0x010c, " MMC Intr Msk(rx)" }, ++ { 0x0110, " MMC Intr Msk(tx)" }, ++ { 0x0200, " MMC Intr Msk(rx ipc)" }, ++ { 0x0738, " AVMAC Ctrl Reg" }, ++ { 0x00D8, " RGMII C/S Reg" }, ++ { 0, 0 } ++}; ++static struct ingenic_mac_reg dma0[] = ++{ ++ { 0x0000, "[CH0] CSR0 Bus Mode" }, ++ { 0x0004, "[CH0] CSR1 TxPlDmnd" }, ++ { 0x0008, "[CH0] CSR2 RxPlDmnd" }, ++ { 0x000C, "[CH0] CSR3 Rx Base" }, ++ { 0x0010, "[CH0] CSR4 Tx Base" }, ++ { 0x0014, "[CH0] CSR5 Status" }, ++ { 0x0018, "[CH0] CSR6 Control" }, ++ { 0x001C, "[CH0] CSR7 Int Enable" }, ++ { 0x0020, "[CH0] CSR8 Missed Fr." }, ++ { 0x0024, "[CH0] Recv Intr Wd.Tm." }, ++ { 0x0028, "[CH0] AXI Bus Mode " }, ++ { 0x002c, "[CH0] AHB or AXI Status" }, ++ { 0x0048, "[CH0] CSR18 Tx Desc " }, ++ { 0x004C, "[CH0] CSR19 Rx Desc " }, ++ { 0x0050, "[CH0] CSR20 Tx Buffer" }, ++ { 0x0054, "[CH0] CSR21 Rx Buffer" }, ++ { 0x0058, "CSR22 HWCFG " }, ++ { 0, 0 } ++}; ++ ++__attribute__((__unused__)) static void ingenic_mac_dump_dma_regs(synopGMACdevice *gmacdev, const char *func, int line) ++{ ++ struct ingenic_mac_reg *reg = dma0; ++ ++ printk("======================DMA Regs start===================\n"); ++ printk("func = %s line = %d\n", func, line); ++ while(reg->name) { ++ printk("===>%s:\t0x%08x\n", reg->name, synopGMACReadReg((u32 *)gmacdev->DmaBase,reg->addr)); ++ reg++; ++ } ++ printk("======================DMA Regs end===================\n"); ++} ++ ++__attribute__((__unused__)) static void ingenic_mac_dump_mac_regs(synopGMACdevice *gmacdev, const char *func, int line) ++{ ++ struct ingenic_mac_reg *reg = mac; ++ ++ printk("======================MAC Regs start===================\n"); ++ printk("func = %s line = %d\n", func, line); ++ while(reg->name) { ++ printk("===>%s:\t0x%08x\n", reg->name, synopGMACReadReg((u32 *)gmacdev->MacBase,reg->addr)); ++ reg++; ++ } ++ printk("======================MAC Regs end===================\n"); ++} ++ ++__attribute__((__unused__)) static void ingenic_mac_dump_all_regs(synopGMACdevice *gmacdev, const char *func, int line) { ++ ingenic_mac_dump_dma_regs(gmacdev, func, line); ++ ingenic_mac_dump_mac_regs(gmacdev, func, line); ++} ++ ++__attribute__((__unused__)) static void ingenic_mac_dump_dma_buffer_info(struct ingenic_mac_buffer *buffer_info) { ++ printk("\tbuffer_info(%p):\n", buffer_info); ++ printk("\t\tskb = %p\n", buffer_info->skb); ++ printk("\t\tdma = 0x%08x\n", buffer_info->dma); ++ printk("\t\tlen = %u\n", buffer_info->length); ++ printk("\t\ttrans = %d\n", buffer_info->transfering); ++ printk("\t\tinvalid = %d\n", buffer_info->invalid); ++} ++ ++__attribute__((__unused__)) static void ingenic_mac_dump_dma_desc(DmaDesc *desc) { ++ printk("\tdma desc(%p):\n", desc); ++ printk("\t\tstatus = 0x%08x\n", desc->status); ++ printk("\t\tbuffer1 = 0x%08x\n", desc->buffer1); ++ printk("\t\tlength = %u\n", desc->length); ++} ++ ++__attribute__((__unused__)) static void ingenic_mac_dump_dma_desc2(DmaDesc *desc, struct ingenic_mac_buffer *buffer_info) { ++ printk("desc: %p, status: 0x%08x buf1: 0x%08x dma: 0x%08x len: %u bi: %p skb: %p trans: %d inv: %d\n", ++ desc, desc->status, desc->buffer1, buffer_info->dma, desc->length, ++ buffer_info, buffer_info->skb, buffer_info->transfering, buffer_info->invalid); ++} ++ ++__attribute__((__unused__)) static void ingenic_mac_dump_rx_desc(struct ingenic_mac_local *lp) { ++ int i = 0; ++ printk("\n===================rx====================\n"); ++ printk("count = %d, next_to_use = %d next_to_clean = %d\n", ++ lp->rx_ring.count, lp->rx_ring.next_to_use, lp->rx_ring.next_to_clean); ++ for (i = 0; i < INGENIC_MAC_RX_DESC_COUNT; i++) { ++ DmaDesc *desc = lp->rx_ring.desc + i; ++ struct ingenic_mac_buffer *b = lp->rx_ring.buffer_info + i; ++ ++#if 0 ++ printk("desc %d:\n", i); ++ ingenic_mac_dump_dma_desc(desc); ++ ingenic_mac_dump_dma_buffer_info(b); ++#endif ++ ingenic_mac_dump_dma_desc2(desc, b); ++ } ++ printk("\n=========================================\n"); ++} ++ ++__attribute__((__unused__)) static void ingenic_mac_dump_tx_desc(struct ingenic_mac_local *lp) { ++ int i = 0; ++ printk("\n===================tx====================\n"); ++ printk("count = %d, next_to_use = %d next_to_clean = %d\n", ++ lp->tx_ring.count, lp->tx_ring.next_to_use, lp->tx_ring.next_to_clean); ++ for (i = 0; i < INGENIC_MAC_TX_DESC_COUNT; i++) { ++ DmaDesc *desc = lp->tx_ring.desc + i; ++ struct ingenic_mac_buffer *b = lp->tx_ring.buffer_info + i; ++ ++#if 0 ++ printk("desc %d:\n", i); ++ ingenic_mac_dump_dma_desc(desc); ++ ingenic_mac_dump_dma_buffer_info(b); ++#endif ++ ingenic_mac_dump_dma_desc2(desc, b); ++ } ++ printk("\n=========================================\n"); ++} ++ ++__attribute__((__unused__)) static void ingenic_mac_dump_all_desc(struct ingenic_mac_local *lp) { ++ ingenic_mac_dump_rx_desc(lp); ++ ingenic_mac_dump_tx_desc(lp); ++} ++ ++__attribute__((__unused__)) static int get_rx_index_by_desc(struct ingenic_mac_local *lp, DmaDesc *desc) { ++ int i = 0; ++ ++ for (i = 0; i < INGENIC_MAC_RX_DESC_COUNT; i++) { ++ if ( (lp->rx_ring.desc + i) == desc) ++ return i; ++ } ++ ++ BUG_ON(i == INGENIC_MAC_RX_DESC_COUNT); ++ return -1; ++} ++ ++__attribute__((__unused__)) static void ingenic_mac_phy_dump(struct ingenic_mac_local *lp) { ++ u16 phy[] = {0, 1, 4, 5, 6, 9, 16, 17, 18, 20, 21, 24, 0x1c}; ++ ++ u16 data[sizeof(phy) / sizeof(u16)]; ++ int i; ++ ++ printk("\n-------->PHY dump: %08X\n", lp->phydev->phy_id); ++ for (i = 0; i < sizeof(phy) / sizeof(u16); i++) ++ data[i] = lp->mii_bus->read(lp->mii_bus, lp->phydev->addr, phy[i]); ++ ++ for (i = 0; i < sizeof(phy) / sizeof(u16); i++) ++ printk("PHY reg%d, value %04X\n", phy[i], data[i]); ++} ++ ++ ++static void ingenic_mac_restart_rx_dma(struct ingenic_mac_local *lp) { ++ synopGMAC_enable_dma_rx(lp->gmacdev); ++} ++ ++static void ingenic_mac_alloc_rx_buffers(struct ingenic_mac_local *lp, int cleaned_count, ++ int restart_dma) { ++ int i = 0; ++ struct ingenic_mac_buffer *buffer_info; ++ struct sk_buff *skb; ++ struct ingenic_mac_rx_ring *rx_ring = &lp->rx_ring; ++ DmaDesc *rx_desc; ++ DmaDesc *first_desc; ++ int first; ++ ++ first = rx_ring->next_to_use; ++ i = rx_ring->next_to_use; ++ rx_desc = INGENIC_MAC_RX_DESC(*rx_ring, i); ++ first_desc = rx_desc; ++ buffer_info = &rx_ring->buffer_info[i]; ++ ++ while (cleaned_count--) { ++ skb = buffer_info->skb; ++ if (skb) { ++ skb_trim(skb, 0); ++ goto map_skb; ++ } ++ ++ skb = netdev_alloc_skb_ip_align(lp->netdev, lp->netdev->mtu + ETHERNET_HEADER + ETHERNET_CRC); ++ if (unlikely(!skb)) { ++ /* Better luck next round */ ++ lp->alloc_rx_buff_failed++; ++ break; ++ } ++ ++ buffer_info->skb = skb; ++ buffer_info->length = skb_tailroom(skb); ++map_skb: ++ buffer_info->dma = dma_map_single(&lp->netdev->dev, ++ skb->data, skb_tailroom(skb), ++ DMA_FROM_DEVICE); ++ if (dma_mapping_error(&lp->netdev->dev, buffer_info->dma)) { ++ dev_err(&lp->netdev->dev, "Rx DMA map failed\n"); ++ lp->alloc_rx_buff_failed++; ++ break; ++ } ++ ++ rx_desc->length |= ((skb_tailroom(skb) <buffer1 = cpu_to_le32(buffer_info->dma); ++ ++ rx_desc->extstatus = 0; ++ rx_desc->reserved1 = 0; ++ rx_desc->timestamplow = 0; ++ rx_desc->timestamphigh = 0; ++ ++ ++ /* clr invalid first, then start transfer */ ++ buffer_info->invalid = 0; ++ ++ /* start transfer */ ++ rx_desc->status = DescOwnByDma; ++ ++ /* next */ ++ if (unlikely(++i == rx_ring->count)) ++ i = 0; ++ ++ wmb(); ++ ++ rx_desc = INGENIC_MAC_RX_DESC(*rx_ring, i); ++ buffer_info = &rx_ring->buffer_info[i]; ++ } ++ ++ if (likely(rx_ring->next_to_use != i)) { ++ rx_ring->next_to_use = i; ++ /* sanity check: ensure next_to_use is not used */ ++ rx_desc->buffer1 = cpu_to_le32(0); ++ rx_desc->status &= ~DescOwnByDma; ++ buffer_info->invalid = 1; ++ wmb(); ++ ++ /* assure that if there's any buffer space, dma is enabled */ ++ if (likely(restart_dma)) ++ ingenic_mac_restart_rx_dma(lp); ++ } ++} ++ ++static int desc_list_init_rx(struct ingenic_mac_local *lp) { ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ int i; ++ int size; ++ ++ /* rx init */ ++ lp->rx_ring.count = INGENIC_MAC_RX_DESC_COUNT; ++ ++ size = lp->rx_ring.count * sizeof(struct ingenic_mac_buffer); ++ lp->rx_ring.buffer_info = vmalloc(size); ++ if (!lp->rx_ring.buffer_info) { ++ printk(KERN_ERR "Unable to allocate memory for the receive descriptor ring\n"); ++ return -ENOMEM; ++ } ++ memset(lp->rx_ring.buffer_info, 0, size); ++ ++ lp->rx_ring.desc = dma_alloc_noncoherent(&lp->netdev->dev, ++ lp->rx_ring.count * sizeof(DmaDesc), ++ &lp->rx_ring.dma, GFP_KERNEL); ++ ++ if (lp->rx_ring.desc == NULL) { ++ vfree(lp->rx_ring.buffer_info); ++ lp->rx_ring.buffer_info = NULL; ++ return -ENOMEM; ++ } ++ ++ dma_cache_wback_inv((unsigned long)lp->rx_ring.desc, ++ lp->rx_ring.count * sizeof(DmaDesc)); ++ ++ /* we always use uncached address for descriptors */ ++ lp->rx_ring.desc = (DmaDesc *)CKSEG1ADDR(lp->rx_ring.desc); ++ ++ for (i = 0; i < INGENIC_MAC_RX_DESC_COUNT; i++) { ++ DmaDesc *desc = lp->rx_ring.desc + i; ++ ++ synopGMAC_rx_desc_init_ring(desc, i == (INGENIC_MAC_RX_DESC_COUNT - 1)); ++ } ++ ++ lp->rx_ring.next_to_use = lp->rx_ring.next_to_clean = 0; ++ ingenic_mac_alloc_rx_buffers(lp, INGENIC_MAC_DESC_UNUSED(&lp->rx_ring), 0); ++ ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase,DmaRxBaseAddr, lp->rx_ring.dma); ++ ++ return 0; ++} ++ ++static void desc_list_free_rx(struct ingenic_mac_local *lp) { ++ struct ingenic_mac_buffer *b; ++ int i = 0; ++ ++ if (lp->rx_ring.desc) ++ dma_free_noncoherent(&lp->netdev->dev, ++ lp->rx_ring.count * sizeof(DmaDesc), ++ (void *)CKSEG0ADDR(lp->rx_ring.desc), ++ lp->rx_ring.dma); ++ ++ if (lp->rx_ring.buffer_info) { ++ b = lp->rx_ring.buffer_info; ++ ++ for(i = 0; i < INGENIC_MAC_RX_DESC_COUNT; i++) { ++ if (b[i].skb) { ++ if (b[i].dma) { ++ dma_unmap_single(&lp->netdev->dev, b[i].dma, ++ b[i].length, DMA_FROM_DEVICE); ++ b[i].dma = 0; ++ } ++ ++ dev_kfree_skb_any(b[i].skb); ++ b[i].skb = NULL; ++ b[i].time_stamp = 0; ++ } ++ } ++ } ++ vfree(lp->rx_ring.buffer_info); ++ lp->rx_ring.buffer_info = NULL; ++ lp->rx_ring.next_to_use = lp->rx_ring.next_to_clean = 0; ++} ++ ++/* must be called from interrupt handler */ ++static void ingenic_mac_take_desc_ownership_rx(struct ingenic_mac_local *lp) { ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ int i = 0; ++ ++ /* must called with interrupts disabled */ ++ BUG_ON(synopGMAC_get_interrupt_mask(gmacdev)); ++ ++ for (i = 0; i < INGENIC_MAC_RX_DESC_COUNT; i++) { ++ DmaDesc *desc = lp->rx_ring.desc + i; ++ struct ingenic_mac_buffer *b = lp->rx_ring.buffer_info + i; ++ ++ if (!b->invalid) { ++ synopGMAC_take_desc_ownership(desc); ++ } ++ } ++ ++ //synopGMACWriteReg((u32 *)gmacdev->DmaBase,DmaRxBaseAddr, lp->rx_ring.dma);//new add for t40 ++} ++ ++/* MUST ensure that rx is stopped ans rx_dma is disabled */ ++static void desc_list_reinit_rx(struct ingenic_mac_local *lp) { ++ DmaDesc *desc; ++ int i = 0; ++ ++ //TODO: BUG_ON(!ingenic_mac_rx_dma_stopped()); ++ ++ for (i = 0; i < INGENIC_MAC_RX_DESC_COUNT; i++) { ++ desc = lp->rx_ring.desc + i; ++ ++ /* owned by DMA, can fill data */ ++ synopGMAC_rx_desc_init_ring(desc, i == (INGENIC_MAC_RX_DESC_COUNT - 1)); ++ } ++ ++ lp->rx_ring.next_to_use = lp->rx_ring.next_to_clean = 0; ++ ingenic_mac_alloc_rx_buffers(lp, INGENIC_MAC_DESC_UNUSED(&lp->rx_ring), 0); ++ ++ synopGMACWriteReg((u32 *)lp->gmacdev->DmaBase,DmaRxBaseAddr, lp->rx_ring.dma);//new add for t40 ++} ++ ++static int desc_list_init_tx(struct ingenic_mac_local *lp) { ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ int i; ++ int size; ++ ++ /* tx init */ ++ lp->tx_ring.count = INGENIC_MAC_TX_DESC_COUNT; ++ ++ size = lp->tx_ring.count * sizeof(struct ingenic_mac_buffer); ++ lp->tx_ring.buffer_info = vmalloc(size); ++ if (!lp->tx_ring.buffer_info) { ++ printk(KERN_ERR"Unable to allocate memory for the receive descriptor ring\n"); ++ return -ENOMEM; ++ } ++ memset(lp->tx_ring.buffer_info, 0, size); ++ ++ lp->tx_ring.desc = dma_alloc_noncoherent(&lp->netdev->dev, ++ lp->tx_ring.count * sizeof(DmaDesc), ++ &lp->tx_ring.dma, GFP_KERNEL); ++ ++ if (lp->tx_ring.desc == NULL) { ++ vfree(lp->tx_ring.buffer_info); ++ lp->tx_ring.buffer_info = NULL; ++ return -ENOMEM; ++ } ++ ++ dma_cache_wback_inv((unsigned long)lp->tx_ring.desc, ++ lp->tx_ring.count * sizeof(DmaDesc)); ++ ++ /* we always use uncached address for descriptors */ ++ lp->tx_ring.desc = (DmaDesc *)CKSEG1ADDR(lp->tx_ring.desc); ++ ++ for (i = 0; i < INGENIC_MAC_TX_DESC_COUNT; i++) { ++ DmaDesc *desc = lp->tx_ring.desc + i; ++ ++ synopGMAC_tx_desc_init_ring(desc, i == (INGENIC_MAC_TX_DESC_COUNT - 1)); ++ } ++ ++ lp->tx_ring.next_to_use = lp->tx_ring.next_to_clean = 0; ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase,DmaTxBaseAddr,(u32)lp->tx_ring.dma); ++ return 0; ++} ++ ++__attribute__((__unused__)) static int get_tx_index_by_desc(struct ingenic_mac_local *lp, DmaDesc *desc) { ++ int i = 0; ++ ++ for (i = 0; i < INGENIC_MAC_TX_DESC_COUNT; i++) { ++ if ( (lp->tx_ring.desc + i) == desc) ++ return i; ++ } ++ ++ BUG_ON(i == INGENIC_MAC_TX_DESC_COUNT); ++ return -1; ++} ++ ++static void ingenic_mac_unmap_and_free_tx_resource(struct ingenic_mac_local *lp, ++ struct ingenic_mac_buffer *buffer_info) ++{ ++ buffer_info->transfering = 0; ++ ++ if (buffer_info->skb) { ++ if (buffer_info->dma) { ++ if (buffer_info->mapped_as_page) ++ dma_unmap_page(&lp->netdev->dev, buffer_info->dma, ++ buffer_info->length, DMA_TO_DEVICE); ++ else ++ dma_unmap_single(&lp->netdev->dev, buffer_info->dma, ++ buffer_info->length, DMA_TO_DEVICE); ++ buffer_info->dma = 0; ++ } ++ dev_kfree_skb_any(buffer_info->skb); ++ buffer_info->skb = NULL; ++ } ++ buffer_info->time_stamp = 0; ++} ++ ++static void desc_list_free_tx(struct ingenic_mac_local *lp) { ++ struct ingenic_mac_buffer *b; ++ int i = 0; ++ ++ if (lp->tx_ring.desc) ++ dma_free_noncoherent(&lp->netdev->dev, ++ lp->tx_ring.count * sizeof(DmaDesc), ++ (void *)CKSEG0ADDR(lp->tx_ring.desc), ++ lp->tx_ring.dma); ++ ++ if (lp->tx_ring.buffer_info) { ++ b = lp->tx_ring.buffer_info; ++ ++ for (i = 0; i < INGENIC_MAC_TX_DESC_COUNT; i++) { ++ // panic("===>ahha, testing! please do not goes here(%s:%d)!!!\n", __func__, __LINE__); ++ ingenic_mac_unmap_and_free_tx_resource(lp, b + i); ++ } ++ ++ } ++ vfree(lp->tx_ring.buffer_info); ++ lp->tx_ring.buffer_info = NULL; ++ lp->tx_ring.next_to_use = lp->tx_ring.next_to_clean = 0; ++} ++ ++/* must called in interrupt handler */ ++static void ingenic_mac_take_desc_ownership_tx(struct ingenic_mac_local *lp) { ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ int i = 0; ++ ++ /* must called with interrupts disabled */ ++ BUG_ON(synopGMAC_get_interrupt_mask(gmacdev)); ++ ++ for (i = 0; i < INGENIC_MAC_TX_DESC_COUNT; i++) { ++ DmaDesc *desc = lp->tx_ring.desc + i; ++ struct ingenic_mac_buffer *b = lp->tx_ring.buffer_info + i; ++ ++ if (!b->invalid) { ++ synopGMAC_take_desc_ownership(desc); ++ } ++ } ++} ++ ++/* must assure that tx transfer are stopped and tx_dma is disabled */ ++static void desc_list_reinit_tx(struct ingenic_mac_local *lp) { ++ int i = 0; ++ DmaDesc *desc; ++ struct ingenic_mac_buffer *b; ++ ++ //TODO: BUG_ON(!ingenic_mac_tx_dma_stopped()); ++ ++ for (i = 0; i < INGENIC_MAC_TX_DESC_COUNT; i++) { ++ desc = lp->tx_ring.desc + i; ++ b = lp->tx_ring.buffer_info + i; ++ ++ /* owned by CPU, no valid data */ ++ synopGMAC_tx_desc_init_ring(desc, i == (INGENIC_MAC_TX_DESC_COUNT - 1)); ++ ++ ingenic_mac_unmap_and_free_tx_resource(lp, b); ++ } ++ ++ lp->tx_ring.next_to_use = lp->tx_ring.next_to_clean = 0; ++} ++ ++static void desc_list_free(struct ingenic_mac_local *lp) ++{ ++ desc_list_free_rx(lp); ++ desc_list_free_tx(lp); ++} ++ ++static void desc_list_reinit(struct ingenic_mac_local *lp) { ++ desc_list_reinit_rx(lp); ++ desc_list_reinit_tx(lp); ++ //ingenic_mac_dump_all_desc(lp); ++} ++ ++static int desc_list_init(struct ingenic_mac_local *lp) ++{ ++ if (desc_list_init_rx(lp) < 0) ++ goto init_error; ++ ++ if (desc_list_init_tx(lp) < 0) ++ goto init_error; ++ ++ //ingenic_mac_dump_all_desc(lp); ++ return 0; ++ ++init_error: ++ desc_list_free(lp); ++ printk(KERN_ERR INGENIC_MAC_DRV_NAME ": kmalloc failed\n"); ++ return -ENOMEM; ++} ++ ++ ++/*---PHY CONTROL AND CONFIGURATION-----------------------------------------*/ ++static void ingenic_mac_adjust_link(struct net_device *dev) ++{ ++ struct ingenic_mac_local *lp = netdev_priv(dev); ++ struct phy_device *phydev = lp->phydev; ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ unsigned long flags; ++ int new_state = 0; ++ ++ //printk("===>ajust link, old_duplex = %d, old_speed = %d, old_link = %d\n", ++ // lp->old_duplex, lp->old_speed, lp->old_link); ++ ++ spin_lock_irqsave(&lp->link_lock, flags); ++ if (phydev->link) { ++ /* Now we make sure that we can be in full duplex mode. ++ * If not, we operate in half-duplex mode. */ ++ if (phydev->duplex != lp->old_duplex) { ++ new_state = 1; ++ ++ if (phydev->duplex) { ++ synopGMAC_set_full_duplex(gmacdev); ++ //synopGMAC_rx_own_enable(gmacdev); ++ //synopGMAC_set_Inter_Frame_Gap(gmacdev, GmacInterFrameGap7); ++ } else { ++ synopGMAC_set_half_duplex(gmacdev); ++ //synopGMAC_rx_own_disable(gmacdev); ++ //synopGMAC_set_Inter_Frame_Gap(gmacdev, GmacInterFrameGap4); ++ } ++ ++ lp->old_duplex = phydev->duplex; ++ } ++ ++ if (phydev->speed != lp->old_speed) { ++ switch (phydev->speed) { ++ case 1000: ++ synopGMAC_select_speed1000(gmacdev); ++ break; ++ case 100: ++ synopGMAC_select_speed100(gmacdev); ++ break; ++ case 10: ++ synopGMAC_select_speed10(gmacdev); ++ break; ++ default: ++ printk(KERN_ERR "GMAC PHY speed NOT match!\n"); ++ synopGMAC_select_speed100(gmacdev); ++ } ++ ++ new_state = 1; ++ lp->old_speed = phydev->speed; ++ } ++ ++ if (!lp->old_link) { ++ new_state = 1; ++ lp->old_link = 1; ++ netif_carrier_on(dev); ++ } ++ } else if (lp->old_link) { ++ new_state = 1; ++ lp->old_link = 0; ++ lp->old_speed = 0; ++ lp->old_duplex = -1; ++ netif_carrier_off(dev); ++ } ++ ++ if (new_state) ++ phy_print_status(phydev); ++ ++ //printk("===>ajust link, new_duplex = %d, new_speed = %d, new_link = %d\n", ++ // lp->old_duplex, lp->old_speed, lp->old_link); ++ ++ spin_unlock_irqrestore(&lp->link_lock, flags); ++ ++} ++ ++static int mii_probe(struct net_device *dev) ++{ ++ struct ingenic_mac_local *lp = netdev_priv(dev); ++ struct phy_device *phydev = NULL; ++ int phy_interface; ++ int i; ++ ++ /* search for connect PHY device */ ++ for (i = 0; i < PHY_MAX_ADDR; i++) { ++ struct phy_device *const tmp_phydev = lp->mii_bus->phy_map[i]; ++ ++ if (!tmp_phydev) ++ continue; /* no PHY here... */ ++ ++ phydev = tmp_phydev; ++ break; /* found it */ ++ } ++ ++ /* now we are supposed to have a proper phydev, to attach to... */ ++ if (!phydev) { ++ printk(KERN_INFO "%s: Don't found any phy device at all\n", ++ dev->name); ++ return -ENODEV; ++ } ++ ++ if(lp->interface == RMII) ++ phy_interface = PHY_INTERFACE_MODE_RMII; ++ else if(lp->interface == RGMII) ++ phy_interface = PHY_INTERFACE_MODE_RGMII; ++ else if(lp->interface == GMII) ++ phy_interface = PHY_INTERFACE_MODE_GMII; ++ else ++ phy_interface = PHY_INTERFACE_MODE_MII; ++ ++ phydev = phy_connect(dev, dev_name(&phydev->dev), &ingenic_mac_adjust_link, ++ phy_interface); ++ if (IS_ERR(phydev)) { ++ printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); ++ return PTR_ERR(phydev); ++ } ++ ++ /* mask with MAC supported features */ ++ phydev->supported &= (SUPPORTED_10baseT_Half ++ | SUPPORTED_10baseT_Full ++ | SUPPORTED_100baseT_Half ++ | SUPPORTED_100baseT_Full ++ | SUPPORTED_1000baseT_Half ++ | SUPPORTED_1000baseT_Full ++ | SUPPORTED_Autoneg ++ | SUPPORTED_Pause | SUPPORTED_Asym_Pause ++ | SUPPORTED_MII ++ | SUPPORTED_TP); ++ ++ phydev->advertising = phydev->supported; ++ ++ lp->old_link = 0; ++ lp->old_speed = 0; ++ lp->old_duplex = -1; ++ lp->phydev = phydev; ++#ifdef DUMP_DEBUG ++ ingenic_mac_phy_dump(lp); ++#endif ++ ++ return 0; ++} ++ ++/** ++ * ingenic_mac_update_stats - Update the board statistics counters ++ * @lp: board private structure ++ **/ ++ ++void ingenic_mac_update_stats(struct ingenic_mac_local *lp) ++{ ++ if ((lp->old_link == 0) || (lp->old_speed == 0) || (lp->old_duplex == -1)) ++ return; ++ ++#if 0 ++ //spin_lock_irqsave(&lp->stats_lock, flags); ++ //spin_lock(&lp->stats_lock); ++ ++ /* Fill out the OS statistics structure */ ++ lp->net_stats.multicast = REG32(MAC_STAT_RMCA); ++ lp->net_stats.collisions = REG32(MAC_STAT_RBCA); ++ ++ /* Rx Errors */ ++ ++ /* RLEC on some newer hardware can be incorrect so build ++ * our own version based on RUC and ROC */ ++ lp->net_stats.rx_errors = lp->stats.rxerrc + ++ lp->stats.crcerrs + lp->stats.algnerrc + ++ lp->stats.ruc + lp->stats.roc + ++ lp->stats.cexterr; ++ lp->net_stats.rx_length_errors = REG32(MAC_STAT_RFLR); ++ lp->net_stats.rx_crc_errors = REG32(MAC_STAT_RFCS); ++ lp->net_stats.rx_frame_errors = REG32(MAC_STAT_RALN); ++ lp->net_stats.rx_missed_errors = lp->stats.mpc; ++ ++ /* Tx Errors */ ++ lp->stats.txerrc = lp->stats.ecol + lp->stats.latecol; ++ lp->net_stats.tx_errors = lp->stats.txerrc; ++ lp->net_stats.tx_aborted_errors = lp->stats.ecol; ++ lp->net_stats.tx_window_errors = lp->stats.latecol; ++ lp->net_stats.tx_carrier_errors = lp->stats.tncrs; ++ if (hw->bad_tx_carr_stats_fd && ++ lp->link_duplex == FULL_DUPLEX) { ++ lp->net_stats.tx_carrier_errors = 0; ++ lp->stats.tncrs = 0; ++ } ++ ++ /* Tx Dropped needs to be maintained elsewhere */ ++ ++ /* Phy Stats */ ++ if (hw->media_type == e1000_media_type_copper) { ++ if ((lp->link_speed == SPEED_1000) && ++ (!e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_tmp))) { ++ phy_tmp &= PHY_IDLE_ERROR_COUNT_MASK; ++ lp->phy_stats.idle_errors += phy_tmp; ++ } ++ ++ if ((hw->mac_type <= e1000_82546) && ++ (hw->phy_type == e1000_phy_m88) && ++ !e1000_read_phy_reg(hw, M88E1000_RX_ERR_CNTR, &phy_tmp)) ++ lp->phy_stats.receive_errors += phy_tmp; ++ } ++ ++ /* Management Stats */ ++ if (hw->has_smbus) { ++ lp->stats.mgptc += er32(MGTPTC); ++ lp->stats.mgprc += er32(MGTPRC); ++ lp->stats.mgpdc += er32(MGTPDC); ++ } ++ ++ //spin_unlock_irqrestore(&lp->stats_lock, flags); ++ //spin_unlock(&lp->stats_lock); ++#endif ++} ++ ++/** ++ * ingenic_mac_watchdog - Timer Call-back ++ * @data: pointer to lp cast into an unsigned long ++ **/ ++static void ingenic_mac_watchdog(unsigned long data) { ++ struct ingenic_mac_local *lp = (struct ingenic_mac_local *)data; ++ ++ ingenic_mac_update_stats(lp); ++ ++ mod_timer(&lp->watchdog_timer, round_jiffies(jiffies + 5 * HZ)); ++} ++ ++static int __ingenic_mac_maybe_stop_tx(struct net_device *netdev, int size) ++{ ++ struct ingenic_mac_local *lp = netdev_priv(netdev); ++ struct ingenic_mac_tx_ring *tx_ring = &lp->tx_ring; ++ ++ netif_stop_queue(netdev); ++ smp_mb(); ++ ++ /* We need to check again in a case another CPU has just ++ * made room available. */ ++ if (likely(INGENIC_MAC_DESC_UNUSED(tx_ring) < size)) ++ return -EBUSY; ++ ++ /* A reprieve! */ ++ netif_start_queue(netdev); ++ ++lp->restart_queue; ++ return 0; ++} ++ ++static int ingenic_mac_maybe_stop_tx(struct net_device *netdev, ++ struct ingenic_mac_tx_ring *tx_ring, int size) ++{ ++ if (likely(INGENIC_MAC_DESC_UNUSED(tx_ring) >= size)) ++ return 0; ++ return __ingenic_mac_maybe_stop_tx(netdev, size); ++} ++ ++static int ingenic_mac_tx_map(struct ingenic_mac_local *lp, ++ struct ingenic_mac_tx_ring *tx_ring, ++ struct sk_buff *skb) ++{ ++ struct net_device *pdev = lp->netdev; ++ struct ingenic_mac_buffer *buffer_info; ++ unsigned int len = skb_headlen(skb); ++ unsigned int offset = 0, count = 0, i; ++ unsigned int f, segs; ++ unsigned int nr_frags = skb_shinfo(skb)->nr_frags; ++ ++ i = tx_ring->next_to_use; ++ ++ buffer_info = &tx_ring->buffer_info[i]; ++ buffer_info->length = len; ++ buffer_info->time_stamp = jiffies; ++ buffer_info->dma = dma_map_single(&pdev->dev, ++ skb->data + offset, ++ len, DMA_TO_DEVICE); ++ buffer_info->mapped_as_page = false; ++ if (dma_mapping_error(&pdev->dev, buffer_info->dma)) ++ goto dma_error; ++ segs = skb_shinfo(skb)->gso_segs ? : 1; ++ tx_ring->buffer_info[i].skb = skb; ++ tx_ring->buffer_info[i].segs = segs; ++ //tx_ring->buffer_info[i].transfering = 1;//x2000 not have ++ count++; ++ ++ for (f = 0; f < nr_frags; f++) { ++ struct skb_frag_struct *frag; ++ ++// struct page *p; ++ frag = &skb_shinfo(skb)->frags[f]; ++ len = frag->size; ++ offset = frag->page_offset; ++ i++; ++ if (i == tx_ring->count) ++ i = 0; ++ buffer_info = &tx_ring->buffer_info[i]; ++ buffer_info->length = len; ++ buffer_info->time_stamp = jiffies; ++ buffer_info->dma = dma_map_page(&pdev->dev, (struct page *)frag, offset, len, DMA_TO_DEVICE); ++ ++ buffer_info->mapped_as_page = true; ++ if (dma_mapping_error(&pdev->dev, buffer_info->dma)) ++ goto dma_unwind; ++ segs = skb_shinfo(skb)->gso_segs ? : 1; ++ tx_ring->buffer_info[i].skb = skb; ++ tx_ring->buffer_info[i].segs = segs; ++ tx_ring->buffer_info[i].transfering = 1; ++ ++ count++; ++ } ++ ++ ++ return count; ++dma_unwind: ++ dev_err(&pdev->dev, "Tx DMA map failed at dma_unwind\n"); ++ while(count-- > 0) { ++ i--; ++ if (i == 0) { ++ i = tx_ring->count; ++ } ++ buffer_info = &tx_ring->buffer_info[i]; ++ if (buffer_info->dma) { ++ if (buffer_info->mapped_as_page) ++ dma_unmap_page(&pdev->dev, buffer_info->dma, ++ buffer_info->length, DMA_TO_DEVICE); ++ else ++ dma_unmap_single(&pdev->dev, buffer_info->dma, ++ buffer_info->length, DMA_TO_DEVICE); ++ buffer_info->dma = 0; ++ } ++ if (buffer_info->skb) { ++ dev_kfree_skb_any(buffer_info->skb); ++ buffer_info->skb = NULL; ++ } ++ buffer_info->time_stamp = 0; ++ } ++ ++dma_error: ++ dev_err(&pdev->dev, "Tx DMA map failed at dma_error\n"); ++ buffer_info->dma = 0; ++ return -ENOMEM; ++} ++ ++static void ingenic_mac_restart_tx_dma(struct ingenic_mac_local *lp) { ++ /* TODO: clear error status bits if any */ ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ u32 data; ++ ++ data = synopGMACReadReg((u32 *)gmacdev->DmaBase, DmaControl); ++ if (data & DmaTxStart) { ++ synopGMAC_resume_dma_tx(gmacdev); ++ } else { ++ synopGMAC_enable_dma_tx(gmacdev); ++ } ++ ++ /* ensure irq is enabled */ ++ synopGMAC_enable_interrupt(gmacdev,DmaIntEnable); ++} ++ ++static void ingenic_mac_tx_queue(struct ingenic_mac_local *lp, ++ struct ingenic_mac_tx_ring *tx_ring) ++{ ++ DmaDesc *tx_desc = NULL; ++ struct ingenic_mac_buffer *buffer_info; ++ unsigned int i; ++ ++ i = tx_ring->next_to_use; ++ ++ buffer_info = &tx_ring->buffer_info[i]; ++ tx_desc = INGENIC_MAC_TX_DESC(*tx_ring, i); ++ ++ tx_desc->length |= (((cpu_to_le32(buffer_info->length) <buffer1 = cpu_to_le32(buffer_info->dma); ++ tx_desc->buffer2 = 0; ++ tx_desc->status |= (DescTxFirst | DescTxLast | DescTxIntEnable); //ENH_DESC ++ tx_desc->status |= DescOwnByDma;//ENH_DESC ++ ++ wmb(); ++ ++ buffer_info->transfering = 1; ++ ++ if (unlikely(++i == tx_ring->count)) i = 0; ++ tx_ring->next_to_use = i; ++ ++ wmb(); ++ ingenic_mac_restart_tx_dma(lp); ++} ++ ++static int ingenic_mac_hard_start_xmit(struct sk_buff *skb, ++ struct net_device *netdev) ++{ ++ struct ingenic_mac_local *lp = netdev_priv(netdev); ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ struct ingenic_mac_tx_ring *tx_ring; ++ unsigned int first; ++ int count = 1; ++ ++ tx_ring = &lp->tx_ring; ++ ++#if 0 ++ /* this can be cacelled for we should support it */ ++ if (unlikely(skb->len <= 0)) { ++ printk(JZMAC_DRV_NAME ": WARNING: skb->len < 0\n"); ++ dev_kfree_skb_any(skb); ++ return NETDEV_TX_OK; ++ } ++#endif ++ ++ /* this can be cacelled for we should support it*/ ++ /* ++ if (skb_shinfo(skb)->nr_frags) { ++ printk(JZMAC_DRV_NAME ": WARNING: fragment packet do not handled!!!\n"); ++ dev_kfree_skb_any(skb); ++ return NETDEV_TX_OK; ++ } ++ */ ++ ++ /* need: count + 2 desc gap to keep tail from touching ++ * head, otherwise try next time */ ++ if (unlikely(ingenic_mac_maybe_stop_tx(netdev, tx_ring, count + 2))) ++ return NETDEV_TX_BUSY; ++ ++ first = tx_ring->next_to_use; ++ count = ingenic_mac_tx_map(lp, tx_ring, skb); ++ ++ if (likely(count)) { ++ ingenic_mac_tx_queue(lp, tx_ring); ++ /* Make sure there is space in the ring for the next send.*/ ++ ingenic_mac_maybe_stop_tx(netdev, tx_ring, MAX_SKB_FRAGS + 2); ++#ifdef DUMP_DEBUG ++ ingenic_mac_dump_all_regs(gmacdev, __func__, __LINE__); ++#endif ++ } else { ++ dev_kfree_skb_any(skb); ++ tx_ring->buffer_info[first].time_stamp = 0; ++ tx_ring->next_to_use = first; ++ } ++ ++#ifdef DUMP_DEBUG ++ ingenic_mac_dump_all_regs(gmacdev, __func__, __LINE__); ++ ingenic_mac_phy_dump(lp); ++ //ingenic_mac_dump_all_desc(lp); ++#endif ++ ++ return NETDEV_TX_OK; ++} ++ ++static bool ingenic_mac_clean_tx_irq(struct ingenic_mac_local *lp) { ++ struct net_device *netdev = lp->netdev; ++ struct ingenic_mac_buffer *buffer_info; ++ struct ingenic_mac_tx_ring *tx_ring = &lp->tx_ring; ++ DmaDesc *desc; ++ unsigned int i; ++ unsigned int count = 0; ++ unsigned int total_tx_bytes=0, total_tx_packets=0; ++ ++ i = tx_ring->next_to_clean; ++ desc = INGENIC_MAC_TX_DESC(*tx_ring, i); ++ buffer_info = &tx_ring->buffer_info[i]; ++ ++ while (buffer_info->transfering && ++ !synopGMAC_is_desc_owned_by_dma(desc) && ++ (count < tx_ring->count)) { ++ ++ buffer_info->transfering = 0; ++ count++; ++ ++ if(synopGMAC_is_desc_valid(desc->status)){ ++ total_tx_packets ++; ++ total_tx_bytes += buffer_info->length; ++ } ++ ++ ingenic_mac_unmap_and_free_tx_resource(lp, buffer_info); ++ synopGMAC_tx_desc_init_ring(desc, i == (tx_ring->count - 1)); ++ ++ i++; ++ if (unlikely(i == tx_ring->count)) i = 0; ++ ++ desc = INGENIC_MAC_TX_DESC(*tx_ring, i); ++ buffer_info = &tx_ring->buffer_info[i]; ++ } ++ ++ tx_ring->next_to_clean = i; ++ ++#define TX_WAKE_THRESHOLD 16 ++ if (unlikely(count && netif_carrier_ok(netdev) && ++ INGENIC_MAC_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD)) { ++ /* Make sure that anybody stopping the queue after this ++ * sees the new next_to_clean. ++ */ ++ smp_mb(); ++ if (netif_queue_stopped(netdev)) { ++ netif_wake_queue(netdev); ++ ++lp->restart_queue; ++ } ++ } ++ ++ lp->total_tx_bytes += total_tx_bytes; ++ lp->total_tx_packets += total_tx_packets; ++ lp->net_stats.tx_bytes += total_tx_bytes; ++ lp->net_stats.tx_packets += total_tx_packets; ++ ++ return (count < tx_ring->count); ++} ++ ++static bool ingenic_mac_clean_rx_irq(struct ingenic_mac_local *lp, ++ int *work_done, int work_to_do) { ++ ++ struct net_device *netdev = lp->netdev; ++ struct ingenic_mac_rx_ring *rx_ring = &lp->rx_ring; ++ DmaDesc *rx_desc, *next_rxd; ++ struct ingenic_mac_buffer *buffer_info, *next_buffer; ++ u32 length; ++ unsigned int i; ++ unsigned int rx_desc_i; ++ int cleaned_count = 0; ++ bool cleaned = false; ++ unsigned int total_rx_bytes=0, total_rx_packets=0; ++ ++ i = rx_ring->next_to_clean; ++ rx_desc = INGENIC_MAC_RX_DESC(*rx_ring, i); ++ buffer_info = &rx_ring->buffer_info[i]; ++ ++ /* except the slot not used, if transfer done, buffer_info->invalid is always 0 */ ++ while ((!synopGMAC_is_desc_owned_by_dma(rx_desc)) && (!buffer_info->invalid)) { ++ struct sk_buff *skb; ++ ++ if (*work_done >= work_to_do) ++ break; ++ (*work_done)++; ++ rmb(); /* read descriptor and rx_buffer_info after status DD */ ++ ++ buffer_info->invalid = 1; ++ skb = buffer_info->skb; ++ buffer_info->skb = NULL; /* cleaned */ ++ ++ if(synopGMAC_is_rx_desc_valid(rx_desc->status)) ++ prefetch(skb->data - NET_IP_ALIGN); ++ ++ rx_desc_i = i; ++ if (++i == rx_ring->count) i = 0; ++ ++ next_rxd = INGENIC_MAC_RX_DESC(*rx_ring, i); ++ prefetch(next_rxd); ++ ++ next_buffer = &rx_ring->buffer_info[i]; ++ ++ cleaned = true; ++ cleaned_count++; ++ ++ if(!synopGMAC_is_rx_desc_valid(rx_desc->status)) { ++ /* save the skb in buffer_info as good */ ++ buffer_info->skb = skb; ++ //printk("====>invalid pkt\n"); ++ goto invalid_pkt; ++ } ++ ++ length = synopGMAC_get_rx_desc_frame_length(rx_desc->status); ++ synopGMAC_rx_desc_init_ring(rx_desc, rx_desc_i == (rx_ring->count - 1)); ++#if 0 ++ printk("============================================\n"); ++ ingenic_mac_dump_pkt_data((unsigned char *)CKSEG1ADDR(buffer_info->dma), ++ length - 4); ++ printk("============================================\n"); ++#endif ++ dma_unmap_single(&lp->netdev->dev, ++ buffer_info->dma, buffer_info->length, ++ DMA_FROM_DEVICE); ++ buffer_info->dma = 0; ++ ++ ++ /* adjust length to remove Ethernet CRC, this must be ++ * done after the TBI_ACCEPT workaround above */ ++ length -= 4; ++ ++ /* probably a little skewed due to removing CRC */ ++ total_rx_bytes += length; ++ total_rx_packets++; ++ ++ /* code added for copybreak, this should improve ++ * performance for small packets with large amounts ++ * of reassembly being done in the stack */ ++ if (length < copybreak) { ++ struct sk_buff *new_skb = ++ netdev_alloc_skb_ip_align(netdev, length); ++ ++ if (new_skb) { ++ skb_copy_to_linear_data_offset(new_skb, ++ -NET_IP_ALIGN, ++ (skb->data - ++ NET_IP_ALIGN), ++ (length + ++ NET_IP_ALIGN)); ++ /* save the skb in buffer_info as good */ ++ buffer_info->skb = skb; ++ skb = new_skb; ++ } ++ /* else just continue with the old one */ ++ } ++ ++ /* end copybreak code */ ++ skb_put(skb, length); ++ skb->protocol = eth_type_trans(skb, netdev); ++ ++ //ingenic_mac_dump_skb_data(skb); ++ netif_receive_skb(skb); //x2000 delete ++// napi_gro_receive(&lp->napi, skb); //x2000 add ++ //netdev->last_rx = jiffies; ++ ++invalid_pkt: ++ rx_desc->status = 0; ++ /* return some buffers to hardware, one at a time is too slow */ ++ if (unlikely(cleaned_count >= INGENIC_MAC_RX_BUFFER_WRITE)) { ++ ingenic_mac_alloc_rx_buffers(lp, cleaned_count, 1); ++ cleaned_count = 0; ++ } ++ ++ /* use prefetched values */ ++ rx_desc = next_rxd; ++ buffer_info = next_buffer; ++ } ++ ++ rx_ring->next_to_clean = i; ++ ++ cleaned_count = INGENIC_MAC_DESC_UNUSED(rx_ring); ++ if (cleaned_count) ++ ingenic_mac_alloc_rx_buffers(lp, cleaned_count, 1); ++ ++ lp->total_rx_packets += total_rx_packets; ++ lp->total_rx_bytes += total_rx_bytes; ++ lp->net_stats.rx_bytes += total_rx_bytes; ++ lp->net_stats.rx_packets += total_rx_packets; ++ ++ return cleaned; ++} ++ ++/** ++ * ingenic_mac_clean - NAPI Rx polling callback ++ **/ ++static int ingenic_mac_clean(struct napi_struct *napi, int budget) { ++ struct ingenic_mac_local *lp = container_of(napi, struct ingenic_mac_local, napi); ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ int tx_cleaned = 0; ++ int work_done = 0; ++ ++ spin_lock(&lp->napi_poll_lock); ++ ++ tx_cleaned = ingenic_mac_clean_tx_irq(lp); ++ ++ ingenic_mac_clean_rx_irq(lp, &work_done, budget); ++ ++ if (!tx_cleaned) ++ work_done = budget; ++ ++ //printk("===>workdone = %d, budget = %d\n", work_done, budget); ++ //ingenic_mac_dump_all_regs(gmacdev, __func__, __LINE__); ++ ++ /* If budget not fully consumed, exit the polling mode */ ++ if (work_done < budget) { ++ napi_complete(napi); ++ synopGMAC_enable_interrupt(gmacdev,DmaIntEnable); ++ } ++ ++ spin_unlock(&lp->napi_poll_lock); ++ return work_done; ++} ++ ++/* interrupt routine to handle rx and error signal */ ++static irqreturn_t ingenic_mac_interrupt(int irq, void *data) ++{ ++ struct net_device *netdev = data; ++ struct ingenic_mac_local *lp = netdev_priv(netdev); ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ u32 interrupt,dma_status_reg; ++ u32 mac_interrupt_status; ++ u32 rgmii_interrupt_status; ++ ++ /* Read the Dma interrupt status to know whether the interrupt got generated by our device or not*/ ++ dma_status_reg = synopGMACReadReg((u32 *)gmacdev->DmaBase, DmaStatus); ++ mac_interrupt_status = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacInterruptStatus); ++ ++ //printk("===>enter %s:%d DmaStatus = 0x%08x\n", __func__, __LINE__, dma_status_reg); ++ if(dma_status_reg == 0) ++ return IRQ_NONE; ++ ++ synopGMAC_disable_interrupt_all(gmacdev); ++ ++ ++ if(dma_status_reg & GmacPmtIntr){ ++ dev_err(&netdev->dev, "%s:: Interrupt due to PMT module\n",__FUNCTION__); ++ //synopGMAC_linux_powerup_mac(gmacdev); ++ } ++ ++ if(dma_status_reg & GmacMmcIntr){ ++ dev_err(&netdev->dev, "%s:: Interrupt due to MMC module\n",__FUNCTION__); ++ dev_err(&netdev->dev, "%s:: synopGMAC_rx_int_status = %08x\n", ++ __FUNCTION__,synopGMAC_read_mmc_rx_int_status(gmacdev)); ++ dev_err(&netdev->dev, "%s:: synopGMAC_tx_int_status = %08x\n", ++ __FUNCTION__,synopGMAC_read_mmc_tx_int_status(gmacdev)); ++ } ++ ++ if(dma_status_reg & GmacLineIntfIntr){ ++ if (mac_interrupt_status & GmacRgmiiIntSts) { ++ rgmii_interrupt_status = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacRGMIIControl); ++ dev_dbg(&netdev->dev, "%s:Interrupts to RGMII/SGMII: 0x%08x\n",__FUNCTION__,rgmii_interrupt_status); ++ } else ++ dev_err(&netdev->dev, "%s:: Interrupt due to GMAC LINE module\n",__FUNCTION__); ++ } ++ ++ /* Now lets handle the DMA interrupts*/ ++ interrupt = synopGMAC_get_interrupt_type(gmacdev); ++ dev_dbg(&netdev->dev, "%s:Interrupts to be handled: 0x%08x\n",__FUNCTION__,interrupt); ++ ++ ++ if(interrupt & synopGMACDmaError){ ++ dev_err(&netdev->dev, "%s::Fatal Bus Error Inetrrupt Seen\n",__FUNCTION__); ++ /* do nothing here, let tx_timeout to handle it */ ++ } ++ ++ if(interrupt & synopGMACDmaRxAbnormal){ ++ dev_dbg(&netdev->dev, "%s::Abnormal Rx Interrupt Seen\n",__FUNCTION__); ++ synopGMAC_resume_dma_rx(gmacdev); ++ } ++ ++ if(interrupt & synopGMACDmaRxStopped){ ++ // Receiver gone in to stopped state ++ // why Rx Stopped? no enough descriptor? but why no enough descriptor need cause an interrupt? ++ // we have no enough descriptor because we can't handle packets that fast, isn't it? ++ // So I think if DmaRxStopped Interrupt can disabled ++ dev_info(&netdev->dev, "%s::Receiver stopped seeing Rx interrupts\n",__FUNCTION__); ++ ++ synopGMAC_enable_dma_rx(gmacdev); ++ } ++ ++ if(interrupt & synopGMACDmaTxAbnormal){ ++ dev_dbg(&netdev->dev, "%s::Abnormal Tx Interrupt Seen\n",__FUNCTION__); ++ } ++ ++ if(interrupt & synopGMACDmaTxStopped){ ++ dev_err(&netdev->dev, "%s::Transmitter stopped sending the packets\n",__FUNCTION__); ++ synopGMAC_disable_dma_tx(gmacdev); ++ ingenic_mac_dump_all_desc(lp); ++ ingenic_mac_take_desc_ownership_tx(lp); ++ synopGMAC_enable_dma_tx(gmacdev); ++ } ++ ++ if (likely(napi_schedule_prep(&lp->napi))) { ++ lp->total_tx_bytes = 0; ++ lp->total_tx_packets = 0; ++ lp->total_rx_bytes = 0; ++ lp->total_rx_packets = 0; ++ dev_dbg(&netdev->dev, "enter %s:%d, call __napi_schedule\n", __func__, __LINE__); ++ __napi_schedule(&lp->napi); ++ } else { ++ /* this really should not happen! if it does it is basically a ++ * bug, but not a hard error, so enable ints and continue */ ++ synopGMAC_enable_interrupt(gmacdev,DmaIntEnable); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++/* MAC control and configuration */ ++ ++static void ingenic_mac_stop_activity(struct ingenic_mac_local *lp) { ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ synopGMAC_disable_interrupt_all(gmacdev); ++ ++ // Disable the Dma in rx path ++ synopGMAC_disable_dma_rx(gmacdev); ++ ingenic_mac_take_desc_ownership_rx(lp); ++ //msleep(100); // Allow any pending buffer to be read by host ++ //synopGMAC_rx_disable(gmacdev); ++ ++ synopGMAC_disable_dma_tx(gmacdev); ++ ingenic_mac_take_desc_ownership_tx(lp); ++ //msleep(100); // allow any pending transmission to complete ++ // Disable the Mac for both tx and rx ++ //synopGMAC_tx_disable(gmacdev); ++} ++ ++static void ingenic_mac_disable(struct ingenic_mac_local *lp) { ++ /* First ensure that the upper network stack is stopped */ ++ /* can be netif_tx_disable when NETIF_F_LLTX is removed */ ++ netif_stop_queue(lp->netdev); /* tx */ ++ napi_disable(&lp->napi); /* rx */ ++ ++ ingenic_mac_stop_activity(lp); ++ ++ del_timer_sync(&lp->watchdog_timer); //x2000 delete ++ ++#if 0 // t40 0 x2000 open ++ spin_lock(&lp->napi_poll_lock); ++ desc_list_reinit(lp); ++ spin_unlock(&lp->napi_poll_lock); ++#endif ++} ++ ++static void ingenic_mac_init(struct ingenic_mac_local *lp) { ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ /* ++ * disable the watchdog and gab to receive frames up to 16384 bytes ++ * to adjust IP protocol ++ */ ++ synopGMAC_wd_disable(gmacdev); ++ synopGMAC_jab_disable(gmacdev); ++ ++ /* cancel to set Frame Burst Enable for now we use duplex mode */ ++ //synopGMAC_frame_burst_enable(gmacdev); ++ ++ /* set jumbo to allow to receive Jumbo frames of 9,018 bytes */ ++ //synopGMAC_jumbo_frame_disable(gmacdev); ++ synopGMAC_jumbo_frame_enable(gmacdev); ++ ++ /* for we try to use duplex */ ++ synopGMAC_rx_own_disable(gmacdev); ++ synopGMAC_loopback_off(gmacdev); ++ /* default to full duplex, I think this will be the common case */ ++ synopGMAC_set_full_duplex(gmacdev); ++ /* here retry enabe may useless */ ++ synopGMAC_retry_enable(gmacdev); ++ synopGMAC_pad_crc_strip_disable(gmacdev); ++ synopGMAC_back_off_limit(gmacdev,GmacBackoffLimit0); ++ synopGMAC_deferral_check_disable(gmacdev); ++ synopGMAC_tx_enable(gmacdev); ++ synopGMAC_rx_enable(gmacdev); ++ ++ /* default to 100M, I think this will be the common case */ ++ synopGMAC_select_mii(gmacdev); ++ synopGMAC_select_speed100(gmacdev); ++ ++ /* Frame Filter Configuration */ ++ synopGMAC_frame_filter_enable(gmacdev); ++ synopGMAC_set_pass_control(gmacdev,GmacPassControl0); ++ synopGMAC_broadcast_enable(gmacdev); ++ synopGMAC_src_addr_filter_disable(gmacdev); ++ synopGMAC_multicast_disable(gmacdev); ++ synopGMAC_dst_addr_filter_normal(gmacdev); ++ synopGMAC_multicast_hash_filter_disable(gmacdev); ++ synopGMAC_promisc_disable(gmacdev); ++ synopGMAC_unicast_hash_filter_disable(gmacdev); ++ ++ /*Flow Control Configuration*/ ++#if 1 /* t40 old */ ++ synopGMAC_unicast_pause_frame_detect_enable(gmacdev); ++ synopGMAC_rx_flow_control_enable(gmacdev); ++ synopGMAC_tx_flow_control_enable(gmacdev); ++#else /* x2000 code */ ++ synopGMAC_unicast_pause_frame_detect_disable(gmacdev); ++ synopGMAC_rx_flow_control_disable(gmacdev); ++ synopGMAC_tx_flow_control_disable(gmacdev); ++#endif ++} ++ ++static void ingenic_mac_configure(struct ingenic_mac_local *lp) { ++ synopGMACdevice *gmacdev = lp->gmacdev; ++#ifdef ENH_DESC_8W ++#if 1 /* t40 before */ ++ /* pbl32 incr with rxthreshold 128 and Desc is 8 Words */ ++ synopGMAC_dma_bus_mode_init(gmacdev, DmaBurstLength32 | DmaDescriptorSkip2 | DmaDescriptor8Words | DmaFixedBurstEnable | 0x02000000); ++ /* pbl32 incr with rxthreshold 128 and Desc is 8 Words */ ++ //synopGMAC_dma_bus_mode_init(gmacdev, DmaBurstLength32 | DmaDescriptorSkip2 | DmaDescriptor8Words | DmaFixedBurstEnable); ++#else /* x2000 change */ ++#ifndef CONFIG_INGENIC_MAC_AXI_BUS //x2000 add ++ synopGMAC_dma_bus_mode_init(gmacdev, DmaBurstLength32 | DmaDescriptorSkip2 | DmaDescriptor8Words | DmaFixedBurstEnable | 0x02000000); //pbl32 incr with rxthreshold 128 and Desc is 8 Words ++#else ++ synopGMAC_dma_bus_mode_init(gmacdev, DmaBurstLength32 | DmaDescriptorSkip1 | DmaDescriptor8Words); ++#endif ++#endif ++#else ++ /* pbl32 incr with rxthreshold 128 */ ++ synopGMAC_dma_bus_mode_init(gmacdev, DmaBurstLength32 | DmaDescriptorSkip2); ++#endif ++ /* DmaRxThreshCtrl128 is ok for the RX FIFO is configured to 256 Bytes */ ++ synopGMAC_dma_control_init(gmacdev,DmaStoreAndForward |DmaTxSecondFrame|DmaRxThreshCtrl128); ++ ++ /*Initialize the mac interface*/ ++ ++ ingenic_mac_init(lp); ++ //synopGMAC_pause_control(gmacdev); // This enables the pause control in Full duplex mode of operation ++ ++#ifdef IPC_OFFLOAD ++ /*IPC Checksum offloading is enabled for this driver. Should only be used if Full Ip checksumm offload engine is configured in the hardware*/ ++ synopGMAC_enable_rx_chksum_offload(gmacdev); //Enable the offload engine in the receive path ++ synopGMAC_rx_tcpip_chksum_drop_enable(gmacdev); // This is default configuration, DMA drops the packets if error in encapsulated ethernet payload ++ // The FEF bit in DMA control register is configured to 0 indicating DMA to drop the errored frames. ++ /*Inform the Linux Networking stack about the hardware capability of checksum offloading*/ ++ netdev->features = NETIF_F_HW_CSUM; ++#endif ++ ++ synopGMAC_clear_interrupt(gmacdev); ++ /* ++ Disable the interrupts generated by MMC and IPC counters. ++ If these are not disabled ISR should be modified accordingly to handle these interrupts. ++ */ ++ synopGMAC_disable_mmc_tx_interrupt(gmacdev, 0xFFFFFFFF); ++ synopGMAC_disable_mmc_rx_interrupt(gmacdev, 0xFFFFFFFF); ++ synopGMAC_disable_mmc_ipc_rx_interrupt(gmacdev, 0xFFFFFFFF); ++} ++ ++/* ++ * Enable Interrupts, Receive, and Transmit(The same sequence as ingenic_mac_open, only a bit different) ++ */ ++static void ingenic_mac_enable(struct ingenic_mac_local *lp) { ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ desc_list_init(lp); //x2000 delete ++ ingenic_mac_configure(lp); ++ ++ napi_enable(&lp->napi); ++ synopGMAC_enable_interrupt(gmacdev,DmaIntEnable); ++ /* we only enable rx here */ ++ synopGMAC_enable_dma_rx(gmacdev); ++ /* We can accept TX packets again */ ++ lp->netdev->trans_start = jiffies; ++ netif_wake_queue(lp->netdev); ++} ++ ++static void ingenic_mac_reinit_locked(struct ingenic_mac_local *lp) ++{ ++ WARN_ON(in_interrupt()); ++ ingenic_mac_disable(lp); ++ ingenic_mac_enable(lp); ++} ++ ++/* Our watchdog timed out. Called by the networking layer */ ++static void ingenic_mac_tx_timeout(struct net_device *dev) ++{ ++ struct ingenic_mac_local *lp = netdev_priv(dev); ++ printk("%s,%d: \n", __func__, __LINE__); ++ /* Do the reset outside of interrupt context */ ++ lp->tx_timeout_count++; ++ schedule_work(&lp->reset_task); ++} ++ ++static void ingenic_mac_reset_task(struct work_struct *work) ++{ ++ struct ingenic_mac_local *lp = ++ container_of(work, struct ingenic_mac_local, reset_task); ++ ++ ingenic_mac_reinit_locked(lp); ++} ++ ++static void setup_mac_addr(synopGMACdevice *gmacdev, u8 *mac_addr) { ++ synopGMAC_set_mac_addr(gmacdev, ++ GmacAddr0High,GmacAddr0Low, ++ mac_addr); ++} ++ ++static int ingenic_mac_set_mac_address(struct net_device *dev, void *p) { ++ struct ingenic_mac_local *lp = netdev_priv(dev); ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ ++ struct sockaddr *addr = p; ++ if (netif_running(dev)) ++ return -EBUSY; ++ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); ++ setup_mac_addr(gmacdev, dev->dev_addr); ++ return 0; ++} ++ ++/* ++ * Open and Initialize the interface ++ * ++ * Set up everything, reset the card, etc.. ++ */ ++static int ingenic_mac_open(struct net_device *dev) ++{ ++ struct ingenic_mac_local *lp = netdev_priv(dev); ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ int retval; ++ ++ pr_debug("%s: %s\n", dev->name, __func__); ++ ++ retval = phy_read(lp->phydev, MII_BMCR); ++ retval &= ~(1 << 11); ++ phy_write(lp->phydev, MII_BMCR, retval); ++ ++ /* ++ * Check that the address is valid. If its not, refuse ++ * to bring the device up. The user must specify an ++ * address using ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx ++ */ ++ if (!is_valid_ether_addr(dev->dev_addr)) { ++ printk(KERN_WARNING INGENIC_MAC_DRV_NAME ": no valid ethernet hw addr\n"); ++ return -EINVAL; ++ } ++ ++ phy_write(lp->phydev, MII_BMCR, BMCR_RESET); ++ while(phy_read(lp->phydev, MII_BMCR) & BMCR_RESET); ++ phy_start(lp->phydev); ++ ++ if (synopGMAC_reset(gmacdev) < 0) { ++ printk("func:%s, synopGMAC_reset failed\n", __func__); ++ phy_stop(lp->phydev); ++ return -1; ++ } ++ ++ /* init MDC CLK */ ++ synopGMAC_set_mdc_clk_div(gmacdev,GmiiCsrClk4); ++ gmacdev->ClockDivMdc = synopGMAC_get_mdc_clk_div(gmacdev); ++ ++ /* initial rx and tx list */ ++ retval = desc_list_init(lp); ++ ++ if (retval) ++ return retval; ++ ++ setup_mac_addr(gmacdev, dev->dev_addr); ++ ingenic_mac_configure(lp); ++#ifdef DUMP_DEBUG ++ ingenic_mac_dump_all_regs(gmacdev, __func__, __LINE__); ++ ingenic_mac_phy_dump(lp); ++#endif ++ napi_enable(&lp->napi); ++ ++ /* we are ready, reset GMAC and enable interrupts */ ++ synopGMAC_enable_interrupt(gmacdev,DmaIntEnable); ++ /* we only enable rx here */ ++ synopGMAC_enable_dma_rx(gmacdev); ++ ++ /* We can accept TX packets again */ ++ lp->netdev->trans_start = jiffies; ++ netif_start_queue(dev); ++ ++ return 0; ++} ++ ++/* ++ * this makes the board clean up everything that it can ++ * and not talk to the outside world. Caused by ++ * an 'ifconfig ethX down' ++ */ ++static int ingenic_mac_close(struct net_device *dev) ++{ ++ struct ingenic_mac_local *lp = netdev_priv(dev); ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ int data = 0; ++ ++ synopGMAC_clear_interrupt(gmacdev); ++ synopGMAC_disable_interrupt_all(gmacdev); ++ ingenic_mac_disable(lp); ++ ++ netif_carrier_off(dev); ++ ++ phy_stop(lp->phydev); ++ data = phy_read(lp->phydev, MII_BMCR); ++ phy_write(lp->phydev, MII_BMCR, (data | BMCR_PDOWN)); ++ ++ /* free the rx/tx buffers */ ++ desc_list_free(lp); ++ return 0; ++} ++ ++static void ingenic_mac_change_rx_flags(struct net_device *dev, int flags) ++{ ++ struct ingenic_mac_local *lp = netdev_priv(dev); ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ if (dev->flags & IFF_PROMISC) { ++ /* Accept any kinds of packets */ ++ synopGMAC_promisc_enable(gmacdev); ++ // synopGMAC_frame_filter_disable(gmacdev); ++ printk("%s: Enter promisc mode!\n",dev->name); ++ }else{ ++ synopGMAC_promisc_disable(gmacdev); ++ } ++} ++ ++static struct net_device_stats *ingenic_mac_get_stats(struct net_device *netdev) ++{ ++ struct ingenic_mac_local *lp = netdev_priv(netdev); ++ ++ /* only return the current stats */ ++ return &lp->net_stats; ++} ++ ++static int ingenic_mac_change_mtu(struct net_device *netdev, int new_mtu) { ++ printk("===>new_mtu = %d\n", new_mtu); ++#if 1 ++ return eth_change_mtu(netdev, new_mtu); ++#else ++ netdev->mtu = new_mtu; ++ return 0; ++#endif ++} ++ ++static int ingenic_mac_do_ioctl(struct net_device *netdev, struct ifreq *ifr, s32 cmd) { ++ struct ingenic_mac_local *lp = netdev_priv(netdev); ++ ++ if (!netif_running(netdev)) { ++ printk("error : it is not in netif_running\n"); ++ return -EINVAL; ++ } ++ ++ if(!(lp->phydev->link)) ++ return 0; ++ ++ return phy_mii_ioctl(lp->phydev, ifr, cmd); ++} ++ ++/* ++ * Multicast filter and config multicast hash table ++ */ ++#define MULTICAST_FILTER_LIMIT 64 ++static void ingenic_mac_multicast_hash(struct net_device *dev) ++{ ++ struct netdev_hw_addr *ha; ++ u32 mc_filter[2]; ++ u32 crc; ++ ++ mc_filter[1] = mc_filter[0] = 0; ++ netdev_for_each_mc_addr(ha, dev) { ++ /* make sure this is a multicast address - ++ shouldn't this be a given if we have it here ? */ ++ if (!(*ha->addr & 1)) ++ continue; ++ crc = ether_crc(ETH_ALEN, ha->addr); ++ /* Take upper 6bits HASH value after bitwise reversal Ether CRC */ ++ set_bit(~crc >> 26, (unsigned long *)mc_filter); ++ } ++ /* TODO: set multicast hash filter here */ ++ synopGMAC_write_hash_table_high(g_gmacdev, mc_filter[1]); ++ synopGMAC_write_hash_table_low(g_gmacdev, mc_filter[0]); ++ ++} ++static void ingenic_set_multicast_list(struct net_device *dev) ++{ ++ if (dev->flags & IFF_PROMISC) { ++ /* Accept any kinds of packets */ ++ synopGMAC_promisc_enable(g_gmacdev); ++ printk("%s: Enter promisc mode!\n",dev->name); ++ }else if ((dev->flags & IFF_ALLMULTI) || (dev->mc.count > MULTICAST_FILTER_LIMIT)) { ++ /* Accept all multicast packets */ ++ synopGMAC_multicast_enable(g_gmacdev); ++ ++ /* TODO: accept broadcast and enable multicast here */ ++ printk("%s: Enter allmulticast mode! %d \n",dev->name,dev->mc.count); ++ }else if (dev->mc.count) { ++ /* Update multicast hash table */ ++ ingenic_mac_multicast_hash(dev); ++ ++ /* TODO: enable multicast here */ ++ synopGMAC_promisc_disable(g_gmacdev); ++ synopGMAC_multicast_disable(g_gmacdev); ++ synopGMAC_multicast_hash_filter_enable(g_gmacdev); ++ } else { ++ /* FIXME: clear promisc or multicast mode */ ++ synopGMAC_promisc_disable(g_gmacdev); ++ synopGMAC_multicast_disable(g_gmacdev); ++ synopGMAC_multicast_hash_filter_disable(g_gmacdev); ++ } ++} ++ ++static const struct net_device_ops ingenic_mac_netdev_ops = { ++ .ndo_open = ingenic_mac_open, ++ .ndo_stop = ingenic_mac_close, ++ .ndo_start_xmit = ingenic_mac_hard_start_xmit, ++ .ndo_change_rx_flags = ingenic_mac_change_rx_flags, ++ .ndo_get_stats = ingenic_mac_get_stats, ++ .ndo_set_mac_address = ingenic_mac_set_mac_address, ++ .ndo_tx_timeout = ingenic_mac_tx_timeout, ++ .ndo_validate_addr = eth_validate_addr, ++ .ndo_change_mtu = ingenic_mac_change_mtu, ++ .ndo_do_ioctl = ingenic_mac_do_ioctl, ++ .ndo_set_rx_mode = ingenic_set_multicast_list, ++}; ++ ++ ++/* Read an off-chip register in a PHY through the MDC/MDIO port */ ++static int ingenic_mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum) ++{ ++ struct ingenic_mac_local *lp = bus->priv; ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ u16 data = 0; ++ s32 status; ++ ++ status = synopGMAC_read_phy_reg(gmacdev, phy_addr, regnum, &data); ++ ++ if (status) ++ data = 0; ++ return (int)data; ++} ++ ++/* Write an off-chip register in a PHY through the MDC/MDIO port */ ++static int ingenic_mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum, ++ u16 value) ++{ ++ struct ingenic_mac_local *lp = bus->priv; ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ ++ return synopGMAC_write_phy_reg(gmacdev, phy_addr, regnum, value); ++} ++ ++static int ingenic_mdiobus_reset(struct mii_bus *bus) ++{ ++ return 0; ++} ++ ++static int ingenic_mdio_phy_read(struct net_device *dev, int phy_id, int location) ++{ ++ struct ingenic_mac_local *lp = netdev_priv(dev); ++ return ingenic_mdiobus_read(lp->mii_bus, phy_id, location); ++} ++ ++static void ingenic_mdio_phy_write(struct net_device *dev, int phy_id, int location, int value) ++{ ++ struct ingenic_mac_local *lp = netdev_priv(dev); ++ ++ ingenic_mdiobus_write(lp->mii_bus, phy_id, location, value); ++} ++ ++static void ingenic_mac_interface_set(struct ingenic_mac_local *lp) ++{ ++ struct platform_device *pdev = lp->pdev; ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ unsigned int cpm_mphyc; ++ unsigned int mode; ++ unsigned int data; ++ unsigned int val; ++ int err; ++ ++ err = of_property_read_u32(np, "ingenic,mac-mode", &mode); ++ if (err < 0) ++ return; ++ lp->interface = mode; ++ ++ err = of_property_read_u32(np, "ingenic,mode-reg", &cpm_mphyc); ++ if (err < 0) ++ return; ++ ++ if(mode==RMII || mode==RGMII) ++ val = mode; ++ else ++ val = 0; ++ ++ data = *(volatile unsigned int *)cpm_mphyc; ++ *(volatile unsigned int *)cpm_mphyc = (data & ~0x7) | val; ++} ++#if 1 ++/** ++ * ingenic_mac_get_settings - Exported for Ethtool to query PHY setting ++ * @ndev: pointer of net DEVICE structure ++ * @cmd: ++ */ ++static int ingenic_mac_get_settings(struct net_device *ndev, struct ethtool_cmd *cmd) ++{ ++ struct ingenic_mac_local *ingenic_local = netdev_priv(ndev); ++ return mii_ethtool_gset(&ingenic_local->mii, cmd); ++} ++ ++/** ++ * ingenic_mac_set_settings - Exported for Ethtool to set PHY setting ++ * @ndev: pointer of net DEVICE structure ++ * @cmd: ++ */ ++static int ingenic_mac_set_settings(struct net_device *ndev, struct ethtool_cmd *cmd) ++{ ++ struct ingenic_mac_local *ingenic_local = netdev_priv(ndev); ++ return mii_ethtool_sset(&ingenic_local->mii, cmd); ++} ++ ++/** ++ * ingenic_mac_get_drvinfo - Exported for Ethtool to query the driver version ++ * @ndev: pointer of net DEVICE structure ++ * @info: ++ */ ++static void ingenic_mac_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info) ++{ ++ /* Inherit standard device info */ ++ strncpy (info->driver, INGENIC_MAC_DRV_NAME, sizeof info->driver); ++ strncpy (info->version, INGENIC_MAC_DRV_VERSION, sizeof info->version); ++} ++ ++/** ++ * ingenic_mac_nway_reset - Exported for Ethtool to restart PHY autonegotiation ++ * @ndev: pointer of net DEVICE structure ++ */ ++static int ingenic_mac_nway_reset(struct net_device *ndev) ++{ ++ struct ingenic_mac_local *ingenic_local = netdev_priv(ndev); ++ return mii_nway_restart(&ingenic_local->mii); ++} ++ ++ ++static struct ethtool_ops ingenic_mac_ethtool_ops = { ++ .get_settings = ingenic_mac_get_settings, ++ .set_settings = ingenic_mac_set_settings, ++ .get_drvinfo = ingenic_mac_get_drvinfo, ++ .nway_reset = ingenic_mac_nway_reset, ++ .get_link = ethtool_op_get_link, ++}; ++ ++#endif ++static ssize_t mdio_cmd_set(struct file *file, const char __user *buffer, size_t count, loff_t *f_pos); ++static int mdio_cmd_open(struct inode *inode, struct file *file); ++static const struct file_operations mdio_cmd_fops ={ ++ .read = seq_read, ++ .open = mdio_cmd_open, ++ .llseek = seq_lseek, ++ .release = single_release, ++ .write = mdio_cmd_set, ++}; ++ ++static int ingenic_mac_probe(struct platform_device *pdev) ++{ ++ synopGMACdevice *gmacdev; ++ struct resource *r_mem = NULL; ++ struct net_device *ndev = NULL; ++ struct device_node *child = NULL; ++ struct ingenic_mac_local *lp; ++ const struct of_device_id *match; ++ struct mii_bus *miibus; ++ char clk_name[16]; ++ unsigned int mode; ++ int rc = 0, i; ++ struct proc_dir_entry *proc; ++ unsigned int phy_clk_freq; ++ ++ r_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!r_mem) { ++ dev_err(&pdev->dev, "no IO resource defined.\n"); ++ return -ENXIO; ++ } ++ ++ gmacdev = devm_kzalloc(&pdev->dev, sizeof (synopGMACdevice), GFP_KERNEL); ++ if(!gmacdev) ++ return -ENOMEM; ++ ++ ndev = alloc_etherdev(sizeof(struct ingenic_mac_local)); ++ if (!ndev) { ++ dev_err(&pdev->dev, "Cannot allocate net device!\n"); ++ return -ENOMEM; ++ } ++ ++ pdev->id = of_alias_get_id(pdev->dev.of_node, "mac"); ++ SET_NETDEV_DEV(ndev, &pdev->dev); ++ platform_set_drvdata(pdev, ndev); ++ lp = netdev_priv(ndev); ++ lp->netdev = ndev; ++ lp->pdev = pdev; ++ lp->gmacdev = gmacdev; ++ lp->id = pdev->id; ++ lp->interface = RMII; ++ ++ match = of_match_node(ingenic_mac_dt_match, pdev->dev.of_node); ++ if (!match) { ++ rc = -ENODEV; ++ goto err_out_free_netdev; ++ } ++ ++ lp->baseaddr = devm_ioremap_resource(&pdev->dev, r_mem); ++ if (IS_ERR(lp->baseaddr)) { ++ dev_err(&pdev->dev, "failed to map baseaddress.\n"); ++ rc = PTR_ERR(lp->baseaddr); ++ goto err_out_free_netdev; ++ } ++ ++ gmacdev->DmaBase = (u32)lp->baseaddr + DMABASE; ++ gmacdev->MacBase = (u32)lp->baseaddr + MACBASE; ++ ++ rc = of_property_read_u32(pdev->dev.of_node, "ingenic,mac-mode", &mode); ++ if (rc < 0) { ++ dev_err(&pdev->dev, "Get mac-mode value failed\n"); ++ goto err_out_free_netdev; ++ } ++ lp->interface = mode; ++ ++ sprintf(clk_name, "gate_gmac"); ++ lp->clk_gate = devm_clk_get(&pdev->dev, clk_name); ++ if (IS_ERR(lp->clk_gate)) { ++ rc = PTR_ERR(lp->clk_gate); ++ dev_err(&pdev->dev, "%s:can't get clk %s\n", __func__,clk_name); ++ goto err_out_free_netdev; ++ } ++ sprintf(clk_name, "div_macphy"); ++ lp->clk_cgu = devm_clk_get(&pdev->dev, clk_name); ++ if (IS_ERR(lp->clk_cgu)) { ++ rc = PTR_ERR(lp->clk_cgu); ++ dev_err(&pdev->dev, "%s:can't get clk %s\n", __func__,clk_name); ++ goto err_out_clk_gate_put; ++ } ++ ++ if ((rc = clk_prepare_enable(lp->clk_gate)) < 0) { ++ dev_err(&pdev->dev, "Enable gmac gate clk failed\n"); ++ goto err_out_clk_cgu_disable; ++ } ++ if ((rc = clk_prepare_enable(lp->clk_cgu)) < 0) { ++ dev_err(&pdev->dev, "Enable gmac cgu clk failed\n"); ++ goto err_out_clk_gate_disable; ++ } ++ ++ rc = of_property_read_u32(pdev->dev.of_node, "ingenic,phy-clk-freq", &phy_clk_freq); ++ if (rc < 0) { ++ phy_clk_freq = 50000000; ++ } ++ ++ if (clk_set_rate(lp->clk_cgu, phy_clk_freq) || (clk_prepare_enable(lp->clk_cgu))) { ++ dev_err(&pdev->dev, "Set cgu_mac clk rate faild\n"); ++ rc = -ENODEV; ++ goto err_out_clk_gate_disable; ++ } ++ ++ ingenic_mac_interface_set(lp); ++ ++ if (ingenic_mac_phy_hwrst(pdev, true)) { ++ rc = -ENODEV; ++ goto err_out_clk_cgu_disable; ++ } ++ ++ if (synopGMAC_reset(gmacdev)) { ++ dev_err(&pdev->dev, "PROB:synopGMAC_reset timeout...\n"); ++ rc = -ETIMEDOUT; ++ goto err_out_clk_cgu_disable; ++ } ++ ++ synopGMAC_disable_interrupt_all(gmacdev); ++ ++ if (!!(child = of_get_child_by_name(pdev->dev.of_node, "mdio-gpio")) && ++ of_device_is_available(child)) { ++ if (!(lp->mii_pdev = of_platform_device_create(child, NULL, &pdev->dev))) { ++ rc = -ENODEV; ++ goto err_out_clk_cgu_disable; ++ } ++ lp->use_mdio_goio = true; ++ lp->mii_bus = platform_get_drvdata(lp->mii_pdev); ++ } else { ++ lp->use_mdio_goio = false; ++ if (!(miibus = devm_mdiobus_alloc(&pdev->dev))) { ++ rc = -ENOMEM; ++ goto err_out_clk_cgu_disable; ++ } ++ miibus->priv = lp; ++ miibus->read = ingenic_mdiobus_read; ++ miibus->write = ingenic_mdiobus_write; ++ miibus->reset = ingenic_mdiobus_reset; ++ miibus->parent = &pdev->dev; ++ miibus->name = "ingenic_mii_bus"; ++ snprintf(miibus->id, MII_BUS_ID_SIZE, "%d", lp->id); ++ miibus->irq = devm_kzalloc(&pdev->dev, sizeof(int) * PHY_MAX_ADDR, GFP_ATOMIC); ++ for (i = 0; i < PHY_MAX_ADDR; ++i) ++ miibus->irq[i] = PHY_POLL; ++ ++ /* init MDC CLK */ ++ synopGMAC_set_mdc_clk_div(gmacdev, GmiiCsrClk4); ++ ++ rc = mdiobus_register(miibus); ++ if (rc) { ++ dev_err(&pdev->dev, "Cannot register MDIO bus!\n"); ++ goto err_out_clk_cgu_disable; ++ } ++ lp->mii_bus = miibus; ++ } ++ ++ /*Lets read the version of ip in to device structure*/ ++ synopGMAC_read_version(gmacdev); ++ ++ /* configure MAC address */ ++ if (bootargs_ethaddr) { ++ for (i=0; i<6; i++) { ++ ndev->dev_addr[i] = ethaddr_hex[i]; ++ } ++ } else { ++ random_ether_addr(ndev->dev_addr); ++ } ++ setup_mac_addr(gmacdev, ndev->dev_addr); ++ ++ rc = mii_probe(ndev); ++ if (rc) { ++ dev_err(&pdev->dev, "MII Probe failed!\n"); ++ goto err_out_miibus_unregister; ++ } ++ ++ /* Fill in the fields of the device structure with ethernet values. */ ++ ether_setup(ndev); ++ ++ ndev->netdev_ops = &ingenic_mac_netdev_ops; ++ ndev->ethtool_ops = &ingenic_mac_ethtool_ops; ++ ndev->watchdog_timeo = 2 * HZ; ++ ++ lp->mii.phy_id = lp->phydev->addr; ++ lp->mii.phy_id_mask = 0x1f; ++ lp->mii.reg_num_mask = 0x1f; ++ lp->mii.dev = ndev; ++ lp->mii.mdio_read = ingenic_mdio_phy_read; ++ lp->mii.mdio_write = ingenic_mdio_phy_write; ++ lp->mii.supports_gmii = mii_check_gmii_support(&lp->mii); ++ ++ init_timer(&lp->watchdog_timer); ++ lp->watchdog_timer.data = (unsigned long)lp; ++ lp->watchdog_timer.function = &ingenic_mac_watchdog; ++ ++ netif_napi_add(ndev, &lp->napi, ingenic_mac_clean, 32); ++ ++ spin_lock_init(&lp->link_lock); ++ spin_lock_init(&lp->napi_poll_lock); ++ ++ INIT_WORK(&lp->reset_task, ingenic_mac_reset_task); ++ ++ /* register irq handler */ ++ rc = platform_get_irq(pdev, 0); ++ if (rc < 0) ++ goto err_out_miibus_unregister; ++ ++ rc = devm_request_irq(&pdev->dev, rc, ingenic_mac_interrupt, 0, "ingenic_mac", ndev); ++ if (rc) { ++ dev_err(&pdev->dev, "Cannot request ingenic MAC IRQ!\n"); ++ rc = -EBUSY; ++ goto err_out_miibus_unregister; ++ } ++ ++ strcpy(ndev->name, "eth%d"); ++ rc = register_netdev(ndev); ++ if (rc) { ++ dev_err(&pdev->dev, "Cannot register net device!\n"); ++ goto err_out_miibus_unregister; ++ } ++ ++ dev_info(&pdev->dev, "%s, Version %s\n", INGENIC_MAC_DRV_DESC, INGENIC_MAC_DRV_VERSION); ++ ++ g_gmacdev = gmacdev; ++ /* proc info */ ++ proc = jz_proc_mkdir("mdio"); ++ if (!proc) { ++ printk("create mdio info failed!\n"); ++ } ++ proc_create_data("cmd", S_IRUGO, proc, &mdio_cmd_fops, NULL); ++ ++ return 0; ++ ++err_out_miibus_unregister: ++ if (lp->use_mdio_goio) ++ platform_device_unregister(lp->mii_pdev); ++ else ++ mdiobus_unregister(lp->mii_bus); ++err_out_clk_cgu_disable: ++ clk_disable_unprepare(lp->clk_cgu); ++err_out_clk_gate_disable: ++ clk_disable_unprepare(lp->clk_gate); ++err_out_clk_cgu_put: ++ devm_clk_put(&pdev->dev, lp->clk_cgu); ++err_out_clk_gate_put: ++ devm_clk_put(&pdev->dev, lp->clk_gate); ++err_out_free_netdev: ++ platform_set_drvdata(pdev, NULL); ++ free_netdev(ndev); ++ return rc; ++} ++ ++static int ingenic_mac_remove(struct platform_device *pdev) ++{ ++ struct net_device *ndev = platform_get_drvdata(pdev); ++ struct ingenic_mac_local *lp = netdev_priv(ndev); ++ ++ unregister_netdev(ndev); ++ ++ if (lp->use_mdio_goio) ++ platform_device_unregister(lp->mii_pdev); ++ else ++ mdiobus_unregister(lp->mii_bus); ++ ++ clk_disable_unprepare(lp->clk_cgu); ++ ++ clk_disable_unprepare(lp->clk_gate); ++ ++ platform_set_drvdata(pdev, NULL); ++ ++ free_netdev(ndev); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int ingenic_mac_suspend(struct platform_device *pdev, pm_message_t mesg) ++{ ++ struct net_device *net_dev = platform_get_drvdata(pdev); ++ struct ingenic_mac_local *lp = netdev_priv(net_dev); ++ ++ if (netif_running(net_dev)) ++ ingenic_mac_close(net_dev); ++ ++ clk_disable_unprepare(lp->clk_cgu); ++#ifndef CONFIG_FPGA_TEST ++ clk_disable_unprepare(lp->clk_gate); ++#endif ++ return 0; ++} ++ ++static int ingenic_mac_resume(struct platform_device *pdev) ++{ ++ struct net_device *net_dev = platform_get_drvdata(pdev); ++ struct ingenic_mac_local *lp = netdev_priv(net_dev); ++#ifndef CONFIG_FPGA_TEST ++ clk_prepare_enable(lp->clk_gate); ++#endif ++ clk_prepare_enable(lp->clk_cgu); ++ ++ if(ingenic_mac_phy_hwrst(pdev, false) < 0) ++ return -1; ++ ++ if (netif_running(net_dev)) ++ ingenic_mac_open(net_dev); ++ ++ return 0; ++} ++#else ++#define ingenic_mac_suspend NULL ++#define ingenic_mac_resume NULL ++#endif /* CONFIG_PM */ ++ ++static const struct of_device_id ingenic_mac_dt_match[] = { ++ { .compatible = "ingenic,t40-mac", .data = NULL }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ingenic_mac_dt_match); ++ ++static struct platform_driver ingenic_mac_driver = { ++ .driver = { ++ .name = INGENIC_MAC_DRV_NAME, ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(ingenic_mac_dt_match), ++ }, ++ .probe = ingenic_mac_probe, ++ .remove = ingenic_mac_remove, ++ .resume = ingenic_mac_resume, ++ .suspend = ingenic_mac_suspend, ++}; ++module_platform_driver(ingenic_mac_driver) ++ ++/* cmd */ ++#define MDIO_CMD_BUF_SIZE 100 ++static uint8_t mdio_cmd_buf[100]; ++static int mdio_cmd_show(struct seq_file *m, void *v) ++{ ++ int len = 0; ++ len += seq_printf(m ,"%s\n", mdio_cmd_buf); ++ return len; ++} ++ ++static ssize_t mdio_cmd_set(struct file *file, const char __user *buffer, size_t count, loff_t *f_pos) ++{ ++ int ret = 0; ++ char *buf = kzalloc((count+1), GFP_KERNEL); ++ if(!buf) ++ return -ENOMEM; ++ if(copy_from_user(buf, buffer, count)) ++ { ++ kfree(buf); ++ return EFAULT; ++ } ++ if (!strncmp(buf, "r reg", sizeof("r reg")-1)) { ++ uint32_t phybase; ++ uint32_t regoffset; ++ uint16_t data = 0; ++ ret = sscanf(buf, "r reg:%i-%i", &phybase, ®offset); ++ if (2!=ret) ++ return EFAULT; ++ { ++ ret = down_interruptible(&mutex_mdio); ++ if (0 != ret) { ++ printk("err(%s): ret = %d\n", __func__, ret); ++ } ++ ret = synopGMAC_read_phy_reg(g_gmacdev, phybase, regoffset, &data); ++ up(&mutex_mdio); ++ } ++ if (ret) ++ printk("##### err %s.%d\n", __func__, __LINE__); ++ printk("mdio: reg read 0x%x-0x%x:0x%x\n", phybase, regoffset, data); ++ sprintf(mdio_cmd_buf, "mdio: reg read 0x%x-0x%x:0x%x\n", phybase, regoffset, data); ++ } else if (!strncmp(buf, "w reg", sizeof("w reg")-1)) { ++ uint32_t phybase; ++ uint32_t regoffset; ++ uint32_t data = 0; ++ ret = sscanf(buf, "w reg:%i-%i-%i", &phybase, ®offset, &data); ++ if (3!=ret) ++ return EFAULT; ++ printk("mdio: reg write 0x%x-0x%x-0x%x\n", phybase, regoffset, data); ++ { ++ ++ ret = down_interruptible(&mutex_mdio); ++ if (0 != ret) { ++ printk("err(%s): ret = %d\n", __func__, ret); ++ } ++ ret = synopGMAC_write_phy_reg(g_gmacdev, phybase, regoffset, data); ++ up(&mutex_mdio); ++ } ++ if (!ret) ++ sprintf(mdio_cmd_buf, "%s\n", "ok"); ++ else ++ sprintf(mdio_cmd_buf, "%s\n", "nok"); ++ } else { ++ sprintf(mdio_cmd_buf, "null"); ++ } ++ kfree(buf); ++ return count; ++} ++static int mdio_cmd_open(struct inode *inode, struct file *file) ++{ ++ return single_open_size(file, mdio_cmd_show, PDE_DATA(inode),8192); ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_ingenic_ingenic_mac.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_ingenic_ingenic_mac.h.patch new file mode 100644 index 00000000..cb73d12f --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_ingenic_ingenic_mac.h.patch @@ -0,0 +1,136 @@ +diff -drupN a/drivers/net/ethernet/ingenic/ingenic_mac.h b/drivers/net/ethernet/ingenic/ingenic_mac.h +--- a/drivers/net/ethernet/ingenic/ingenic_mac.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/net/ethernet/ingenic/ingenic_mac.h 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,132 @@ ++#ifndef __INGENIC_MAC_H__ ++#define __INGENIC_MAC_H__ ++ ++ ++#include "synopGMAC_Dev.h" ++ ++/* wrapper around a pointer to a socket buffer, ++ * so a DMA handle can be stored along with the buffer */ ++struct ingenic_mac_buffer { ++ struct sk_buff *skb; ++ dma_addr_t dma; ++ unsigned long time_stamp; ++ u16 length; ++ volatile u8 transfering; /* used by tx */ ++ volatile u8 invalid; /* used by rx */ ++ u16 mapped_as_page; ++ unsigned int segs; ++}; ++ ++/* TX/RX descriptor defines */ ++#define INGENIC_MAC_TX_DESC_COUNT 128 ++#define INGENIC_MAC_MAX_TXD 256 ++#define INGENIC_MAC_MIN_TXD 80 ++ ++#define INGENIC_MAC_RX_DESC_COUNT 128 ++#define INGENIC_MAC_MAX_RXD 256 ++#define INGENIC_MAC_MIN_RXD 80 ++ ++struct ingenic_mac_tx_ring { ++ /* pointer to the descriptor ring memory */ ++ DmaDesc *desc; ++ /* physical address of the descriptor ring */ ++ dma_addr_t dma; ++ /* number of descriptors in the ring */ ++ unsigned int count; ++ /* next descriptor to associate a buffer with */ ++ unsigned int next_to_use; ++ /* next descriptor to check for trans done status */ ++ unsigned int next_to_clean; ++ /* array of buffer information structs */ ++ struct ingenic_mac_buffer *buffer_info; ++}; ++ ++struct ingenic_mac_rx_ring { ++ /* pointer to the descriptor ring memory */ ++ DmaDesc *desc; ++ /* physical address of the descriptor ring */ ++ dma_addr_t dma; ++ /* number of descriptors in the ring */ ++ unsigned int count; ++ /* next descriptor to associate a buffer with */ ++ unsigned int next_to_use; ++ /* next descriptor to check for DD status bit */ ++ unsigned int next_to_clean; ++ /* array of buffer information structs */ ++ struct ingenic_mac_buffer *buffer_info; ++}; ++ ++#define INGENIC_MAC_DESC_UNUSED(R) \ ++ ((((R)->next_to_clean > (R)->next_to_use) \ ++ ? 0 : (R)->count) + (R)->next_to_clean - (R)->next_to_use - 1) ++ ++#define INGENIC_MAC_DESC_USED(R) (((R)->count - 1) - INGENIC_MAC_DESC_UNUSED(R)) ++ ++#define INGENIC_MAC_GET_DESC(R, i) (&(((DmaDesc *)((R).desc))[i])) ++#define INGENIC_MAC_RX_DESC(R, i) INGENIC_MAC_GET_DESC(R, i) ++#define INGENIC_MAC_TX_DESC(R, i) INGENIC_MAC_GET_DESC(R, i) ++ ++struct ingenic_mac_local { ++ struct clk *clk_gate; ++ struct clk *clk_cgu; ++ void __iomem *baseaddr; ++ ++ struct ingenic_mac_tx_ring tx_ring; ++ unsigned int restart_queue; ++ u32 tx_timeout_count; ++ ++ struct timer_list watchdog_timer; ++ struct ingenic_mac_rx_ring rx_ring; ++ ++ struct napi_struct napi; ++ spinlock_t napi_poll_lock; ++ ++ struct net_device *netdev; ++ struct platform_device *pdev; ++ struct net_device_stats net_stats; ++ ++ spinlock_t stats_lock; ++ unsigned int total_tx_bytes; ++ unsigned int total_tx_packets; ++ unsigned int total_rx_bytes; ++ unsigned int total_rx_packets; ++ ++ atomic_t tx_fifo_used; ++ ++ unsigned char Mac[6]; /* MAC address of the board */ ++ spinlock_t link_lock; ++ ++ /* MII and PHY stuffs */ ++ int old_link; ++ int old_speed; ++ int old_duplex; ++ ++ struct phy_device *phydev; ++ struct mii_bus *mii_bus; ++ bool use_mdio_goio; ++ struct platform_device *mii_pdev; ++ ++ u32 alloc_rx_buff_failed; ++ ++ struct work_struct reset_task; ++ struct mii_if_info mii; ++ ++ /*hw reset*/ ++ u32 reset_ms; ++ int reset_gpio; ++ u32 reset_lvl; ++ int id; ++ ++ synopGMACdevice *gmacdev; ++ unsigned int interface; ++}; ++ ++ ++extern struct proc_dir_entry *proc_create_data(const char *name, umode_t mode, ++ struct proc_dir_entry *parent, ++ const struct file_operations *proc_fops, ++ void *data); ++extern int jz_clk_set_rate(struct clk *clk, unsigned long rate); ++extern void *PDE_DATA(const struct inode *inode); ++ ++#endif /* __INGENIC_MAC_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_ingenic_readme.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_ingenic_readme.patch new file mode 100644 index 00000000..8db3e784 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_ingenic_readme.patch @@ -0,0 +1,30 @@ +diff -drupN a/drivers/net/ethernet/ingenic/readme b/drivers/net/ethernet/ingenic/readme +--- a/drivers/net/ethernet/ingenic/readme 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/net/ethernet/ingenic/readme 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,26 @@ ++*************************************README*************************************** ++ ++ ++********************************************************************************** ++ ++This is a README file for the sample device driver software for Synopsys Universal ++GMAC IP. The files listed below are available in this directory. ++ ++./README (this file) ++./synopGMAC_banner.h ++./synopGMAC_plat.c ++./synopGMAC_plat.h ++./synopGMAC_Dev.c ++./synopGMAC_Dev.h ++./synopGMAC_network_interface.c ++./synopGMAC_network_interface.h ++./synopGMAC_Host.c ++./synopGMAC_Host.h ++./Makefile ++./synopGMAC_Debug.c ++./synopGMAC_driver_ug.pdf ++ ++The User Guide (synopGMAC_driver_ug.pdf) provides details about driver architecture, flow ++diagrams and driver APIs. Please refer to compilation subsection of chapter 1 to compile ++the driver and the debug utility. The same section explains how to use the kernel module ++in Linux platform. diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_ingenic_synopGMAC_Dev.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_ingenic_synopGMAC_Dev.c.patch new file mode 100644 index 00000000..8f369524 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_ingenic_synopGMAC_Dev.c.patch @@ -0,0 +1,3842 @@ +diff -drupN a/drivers/net/ethernet/ingenic/synopGMAC_Dev.c b/drivers/net/ethernet/ingenic/synopGMAC_Dev.c +--- a/drivers/net/ethernet/ingenic/synopGMAC_Dev.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/net/ethernet/ingenic/synopGMAC_Dev.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,3838 @@ ++/* =================================================================================== ++ * Copyright (c) <2009> Synopsys, Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy of ++ * this software annotated with this license and associated documentation files ++ * (the "Software"), to deal in the Software without restriction, including without ++ * limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in all ++ * copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, ++ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A ++ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT ++ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE ++ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * =================================================================================== */ ++ ++/** \file ++ * This file defines the synopsys GMAC device dependent functions. ++ * Most of the operations on the GMAC device are available in this file. ++ * Functions for initiliasing and accessing MAC/DMA/PHY registers and the DMA descriptors ++ * are encapsulated in this file. The functions are platform/host/OS independent. ++ * These functions in turn use the low level device dependent (HAL) functions to ++ * access the register space. ++ * \internal ++ * ------------------------REVISION HISTORY--------------------------------- ++ * Synopsys 01/Aug/2007 Created ++ */ ++#include "synopGMAC_Dev.h" ++ ++/** ++ * Function to set the MDC clock for mdio transactiona ++ * ++ * @param[in] pointer to device structure. ++ * @param[in] clk divider value. ++ * \return Reuturns 0 on success else return the error value. ++ */ ++s32 synopGMAC_set_mdc_clk_div(synopGMACdevice *gmacdev,u32 clk_div_val) ++{ ++ u32 orig_data; ++ int times = 100; ++ while(((orig_data = synopGMACReadReg((u32 *)gmacdev->MacBase,GmacGmiiAddr)) & GmiiBusy) && (times-- > 0)) { ++ printk("===>PHY busy!\n"); ++ } ++ orig_data &= (~ GmiiCsrClkMask); ++ orig_data |= clk_div_val; ++ synopGMACWriteReg((u32 *)gmacdev->MacBase, GmacGmiiAddr ,orig_data); ++ return 0; ++} ++ ++/** ++ * Returns the current MDC divider value programmed in the ip. ++ * ++ * @param[in] pointer to device structure. ++ * @param[in] clk divider value. ++ * \return Returns the MDC divider value read. ++ */ ++u32 synopGMAC_get_mdc_clk_div(synopGMACdevice *gmacdev) ++{ ++ u32 data; ++ data = synopGMACReadReg((u32 *)gmacdev->MacBase,GmacGmiiAddr); ++ data &= GmiiCsrClkMask; ++ return data; ++} ++ ++/** ++ * struct GmiiCsrDiv ++ */ ++typedef struct GmiiCisrDivStruct { ++ u32 CsrClkDiv; ++ u32 CsrRegValue; ++} GmiiCsrDiv; ++ ++/** ++ * GmacCsrDivArray ++ * ++ * Note: ++ * GmacCsrDivArray is descending order baseed on ++ * GmacCsrDivArray.CsrClkDiv. ++ */ ++static GmiiCsrDiv GmacCsrDivArray[] = { ++ { 124, GmiiCsrClk5 }, /* sysclk is 250-300 MHz */ ++ { 102, GmiiCsrClk4 }, /* sysclk is 150-250 MHz */ ++ { 62, GmiiCsrClk1 }, /* sysclk is 100-150 MHz */ ++ { 42, GmiiCsrClk0 }, /* sysclk is 60-100 MHz */ ++ { 26, GmiiCsrClk3 }, /* sysclk is 35-60 MHz */ ++ { 16, GmiiCsrClk2 }, /* sysclk is 20-35 MHz */ ++ { 14, 0x00000034 }, ++ { 12, 0x00000030 }, ++ { 10, 0x0000002C }, ++ { 8, 0x00000028 }, ++ { 6, 0x00000024 }, ++ { 4, 0x00000020 }, ++}; ++ ++/** ++ * Function to Calculate the GMIIAddressRegister.CR[5:2] right value ++ * @sysclk[in] ++ * @max_mdcclk[in] ++ * \return Returns 0xFFFFFFFF on out of band else return a rigth value. ++ */ ++u32 synopGMAC_calculate_mdc_clk_csr(u32 sysclk, u32 max_mdcclk) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(GmacCsrDivArray); i++) { ++ if (sysclk > max_mdcclk * GmacCsrDivArray[i].CsrClkDiv) ++ return i ? GmacCsrDivArray[i - 1].CsrRegValue : ~(u32)0; ++ } ++ ++ return GmacCsrDivArray[i - 1].CsrRegValue; ++} ++ ++ ++/** ++ * Function to read the Phy register. The access to phy register ++ * is a slow process as the data is moved accross MDI/MDO interface ++ * @param[in] pointer to Register Base (It is the mac base in our case) . ++ * @param[in] PhyBase register is the index of one of supported 32 PHY devices. ++ * @param[in] Register offset is the index of one of the 32 phy register. ++ * @param[out] u16 data read from the respective phy register (only valid iff return value is 0). ++ * \return Returns 0 on success else return the error status. ++ */ ++s32 synopGMAC_read_phy_reg(synopGMACdevice *gmacdev, u32 PhyBase, u32 RegOffset, u16 * data) ++{ ++ u32 addr = 0; ++ u32 loop_variable = 0; ++ u32 *RegBase = (u32 *)gmacdev->MacBase; ++ int times = 100; ++ ++ while((synopGMACReadReg(RegBase,GmacGmiiAddr) & GmiiBusy) && (times-- > 0)) { ++ printk("===>PHY busy!\n"); ++ } ++ ++ addr = ((PhyBase << GmiiDevShift) & GmiiDevMask) | ((RegOffset << GmiiRegShift) & GmiiRegMask); ++ addr = addr | (gmacdev->ClockDivMdc) | GmiiBusy; //Gmii busy bit ++ ++ // printk("====>PHY: addr = 0x%08x\n", addr); ++ ++ synopGMACWriteReg(RegBase,GmacGmiiAddr,addr); //write the address from where the data to be read in GmiiGmiiAddr register of synopGMAC ip ++ ++ for(loop_variable = 0; loop_variable < DEFAULT_LOOP_VARIABLE; loop_variable++){ //Wait till the busy bit gets cleared with in a certain amount of time ++ if (!(synopGMACReadReg(RegBase,GmacGmiiAddr) & GmiiBusy)){ ++ break; ++ } ++ plat_delay(DEFAULT_DELAY_VARIABLE); ++ } ++ if(loop_variable < DEFAULT_LOOP_VARIABLE) { ++ *data = (u16)(synopGMACReadReg(RegBase,GmacGmiiData) & 0xFFFF); ++ // printk("======>PHY: data = 0x%04x\n", *data); ++ } else{ ++ printk("====>Error::: PHY not responding Busy bit didnot get cleared !!!!!!\n"); ++ return -ESYNOPGMACPHYERR; ++ } ++ return -ESYNOPGMACNOERR; ++} ++ ++/** ++ * Function to write to the Phy register. The access to phy register ++ * is a slow process as the data is moved accross MDI/MDO interface ++ * @param[in] pointer to Register Base (It is the mac base in our case) . ++ * @param[in] PhyBase register is the index of one of supported 32 PHY devices. ++ * @param[in] Register offset is the index of one of the 32 phy register. ++ * @param[in] data to be written to the respective phy register. ++ * \return Returns 0 on success else return the error status. ++ */ ++s32 synopGMAC_write_phy_reg(synopGMACdevice *gmacdev, u32 PhyBase, u32 RegOffset, u16 data) ++{ ++ u32 addr; ++ u32 loop_variable; ++ u32 *RegBase = (u32 *)gmacdev->MacBase; ++ int times = 100; ++ ++ while((synopGMACReadReg(RegBase,GmacGmiiAddr) & GmiiBusy) && (times-- > 0)) { ++ printk("===>PHY busy!\n"); ++ } ++ synopGMACWriteReg(RegBase,GmacGmiiData,data); // write the data in to GmacGmiiData register of synopGMAC ip ++ addr = ((PhyBase << GmiiDevShift) & GmiiDevMask) | ((RegOffset << GmiiRegShift) & GmiiRegMask) | GmiiWrite; ++ ++ addr = addr | (gmacdev->ClockDivMdc) | GmiiBusy ; //set Gmii clk to 20-35 Mhz and Gmii busy bit ++ ++ times = 100; ++ while((synopGMACReadReg(RegBase,GmacGmiiAddr) & GmiiBusy) && (times-- > 0)) { ++ printk("===>PHY busy!\n"); ++ } ++ synopGMACWriteReg(RegBase,GmacGmiiAddr,addr); ++ for(loop_variable = 0; loop_variable < DEFAULT_LOOP_VARIABLE; loop_variable++){ ++ if (!(synopGMACReadReg(RegBase,GmacGmiiAddr) & GmiiBusy)){ ++ break; ++ } ++ plat_delay(DEFAULT_DELAY_VARIABLE); ++ } ++ ++ if(loop_variable < DEFAULT_LOOP_VARIABLE){ ++ return -ESYNOPGMACNOERR; ++ } ++ else{ ++ TR("Error::: PHY not responding Busy bit didnot get cleared !!!!!!\n"); ++ return -ESYNOPGMACPHYERR; ++ } ++} ++ ++/** ++ * Function to configure the phy in loopback mode. ++ * ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] enable or disable the loopback. ++ * \return 0 on success else return the error status. ++ * \note Don't get confused with mac loop-back synopGMAC_loopback_on(synopGMACdevice *) ++ * and synopGMAC_loopback_off(synopGMACdevice *) functions. ++ */ ++s32 synopGMAC_phy_loopback(synopGMACdevice *gmacdev, bool loopback) ++{ ++ s32 status = -ESYNOPGMACNOERR; ++ if(loopback) ++ status = synopGMAC_write_phy_reg(gmacdev, gmacdev->PhyBase, PHY_CONTROL_REG, Mii_Loopback); ++ else ++ status = synopGMAC_write_phy_reg(gmacdev, gmacdev->PhyBase, PHY_CONTROL_REG, Mii_NoLoopback); ++ ++ return status; ++} ++ ++ ++ ++/** ++ * Function to read the GMAC IP Version and populates the same in device data structure. ++ * @param[in] pointer to synopGMACdevice. ++ * \return Always return 0. ++ */ ++ ++s32 synopGMAC_read_version (synopGMACdevice * gmacdev) ++{ ++ u32 data = 0; ++ data = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacVersion ); ++ gmacdev->Version = data; ++ TR("The data read from %08x is %08x\n",(gmacdev->MacBase+GmacVersion),data); ++ return 0; ++} ++ ++#include ++ ++/** ++ * Function to reset the GMAC core. ++ * This reests the DMA and GMAC core. After reset all the registers holds their respective reset value ++ * @param[in] pointer to synopGMACdevice. ++ * \return 0 on success else return the error status. ++ */ ++s32 synopGMAC_reset (synopGMACdevice * gmacdev) ++{ ++ u32 data = 0; ++ int cnt = 0; ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaBusMode ,DmaResetOn); ++ plat_delay(DEFAULT_LOOP_VARIABLE); ++ ++ while (1) { ++ data = synopGMACReadReg((u32 *)gmacdev->DmaBase, DmaBusMode); ++ TR("DATA after Reset = %08x\n",data); ++ if (data & DmaResetOn) { ++ if (cnt < 10) { ++ printk("Bus Mode Reg after reset: 0x%08x, cnt=%d\n", data, cnt); ++ } else { ++ return -1; ++ } ++ ++ mdelay(1); ++ cnt ++; ++ } else { ++ break; ++ } ++ } ++ ++ return 0; ++} ++ ++ ++/** ++ * Function to program DMA bus mode register. ++ * ++ * The Bus Mode register is programmed with the value given. The bits to be set are ++ * bit wise or'ed and sent as the second argument to this function. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] the data to be programmed. ++ * \return 0 on success else return the error status. ++ */ ++s32 synopGMAC_dma_bus_mode_init(synopGMACdevice * gmacdev, u32 init_value ) ++{ ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaBusMode ,init_value); ++ TR("bus_mode after init: 0x%08x\n", synopGMACReadReg((u32 *)gmacdev->DmaBase, DmaBusMode)); ++ return 0; ++ ++} ++ ++/** ++ * Function to program DMA Control register. ++ * ++ * The Dma Control register is programmed with the value given. The bits to be set are ++ * bit wise or'ed and sent as the second argument to this function. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] the data to be programmed. ++ * \return 0 on success else return the error status. ++ */ ++s32 synopGMAC_dma_control_init(synopGMACdevice * gmacdev, u32 init_value) ++{ ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaControl, init_value); ++ return 0; ++} ++ ++ ++/*Gmac configuration functions*/ ++ ++/** ++ * Enable the watchdog timer on the receiver. ++ * When enabled, Gmac enables Watchdog timer, and GMAC allows no more than ++ * 2048 bytes of data (10,240 if Jumbo frame enabled). ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_wd_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacWatchdog); ++ return; ++} ++/** ++ * Disable the watchdog timer on the receiver. ++ * When disabled, Gmac disabled watchdog timer, and can receive frames up to ++ * 16,384 bytes. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_wd_disable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacWatchdog); ++ return; ++} ++ ++/** ++ * Enables the Jabber frame support. ++ * When cleared, GMAC enables jabber timer. It cuts of transmitter if application ++ * sends more than 2048 bytes of data (10240 if Jumbo frame enabled). ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_jab_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacJabber); ++ return; ++} ++/* ++ * Disables the Jabber frame support. ++ * When set, GMAC disabled the jabber timer, and can transfer 16,384 byte frames. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_jab_disable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacJabber); ++ return; ++} ++ ++/** ++ * Enables Frame bursting (Only in Half Duplex Mode). ++ * When enabled, GMAC allows frame bursting in GMII Half Duplex mode. ++ * Reserved in 10/100 and Full-Duplex configurations. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_frame_burst_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacFrameBurst); ++ return; ++} ++/** ++ * Disables Frame bursting. ++ * When Disabled, frame bursting is not supported. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_frame_burst_disable(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacFrameBurst); ++ return; ++} ++ ++/** ++ * Enable Jumbo frame support. ++ * When Enabled GMAC supports jumbo frames of 9018/9022(VLAN tagged). ++ * Giant frame error is not reported in receive frame status. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_jumbo_frame_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacJumboFrame); ++ return; ++} ++ ++/** ++ * Disable Jumbo frame support. ++ * When Disabled GMAC does not supports jumbo frames. ++ * Giant frame error is reported in receive frame status. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_jumbo_frame_disable(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacJumboFrame); ++ return; ++} ++ ++/** ++ * ++ */ ++void synopGMAC_set_Inter_Frame_Gap(synopGMACdevice * gmacdev, u32 value) ++{ ++ u32 data; ++ data = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacConfig); ++ data &= (~GmacInterFrameGap); ++ data |= value; ++ synopGMACWriteReg((u32 *)gmacdev->MacBase, GmacConfig, data); ++ return; ++} ++ ++/** ++ * Disable Carrier sense. ++ * When Disabled GMAC ignores CRS signal during frame transmission ++ * in half duplex mode. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++ ++void synopGMAC_disable_crs(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacDisableCrs); ++ return; ++} ++ ++ ++ ++/** ++ * Selects the GMII port. ++ * When called GMII (1000Mbps) port is selected (programmable only in 10/100/1000 Mbps configuration). ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_select_gmii(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacMiiGmii); ++ return; ++} ++/** ++ * Selects the MII port. ++ * When called MII (10/100Mbps) port is selected (programmable only in 10/100/1000 Mbps configuration). ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_select_mii(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacSelectMii); ++ return; ++} ++ ++/** ++ * Select the Speed 1000 Mbps ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_select_speed1000(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacMiiGmii); ++ return; ++} ++ ++ ++/** ++ * Select the Speed 100 Mbps ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_select_speed100(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacFESpeed100 | GmacSelectMii); ++ return; ++} ++ ++/** ++ * Select the Speed 10 Mbps ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_select_speed10(synopGMACdevice * gmacdev) ++{ ++ u32 regVal; ++ regVal = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacConfig); ++ regVal |= GmacSelectMii; ++ regVal &= (~GmacFESpeed100); ++ synopGMACWriteReg((u32 *)gmacdev->MacBase, GmacConfig, regVal); ++ return; ++} ++ ++/** ++ * Enables Receive Own bit (Only in Half Duplex Mode). ++ * When enaled GMAC receives all the packets given by phy while transmitting. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_rx_own_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacRxOwn); ++ return; ++} ++/** ++ * Disables Receive Own bit (Only in Half Duplex Mode). ++ * When enaled GMAC disables the reception of frames when gmii_txen_o is asserted. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_rx_own_disable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacRxOwn); ++ return; ++} ++ ++/** ++ * Sets the GMAC in loopback mode. ++ * When on GMAC operates in loop-back mode at GMII/MII. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ * \note (G)MII Receive clock is required for loopback to work properly, as transmit clock is ++ * not looped back internally. ++ */ ++void synopGMAC_loopback_on(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacLoopback); ++ return; ++} ++/** ++ * Sets the GMAC in Normal mode. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_loopback_off(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacLoopback); ++ return; ++} ++ ++/** ++ * Sets the GMAC core in Full-Duplex mode. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_set_full_duplex(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacDuplex); ++ return; ++} ++/** ++ * Sets the GMAC core in Half-Duplex mode. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_set_half_duplex(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacDuplex); ++ return; ++} ++ ++/** ++ * GMAC tries retransmission (Only in Half Duplex mode). ++ * If collision occurs on the GMII/MII, GMAC attempt retries based on the ++ * back off limit configured. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ * \note This function is tightly coupled with synopGMAC_back_off_limit(synopGMACdev *, u32). ++ */ ++void synopGMAC_retry_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacRetry); ++ return; ++} ++/** ++ * GMAC tries only one transmission (Only in Half Duplex mode). ++ * If collision occurs on the GMII/MII, GMAC will ignore the current frami ++ * transmission and report a frame abort with excessive collision in tranmit frame status. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_retry_disable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacRetry); ++ return; ++} ++ ++/** ++ * GMAC strips the Pad/FCS field of incoming frames. ++ * This is true only if the length field value is less than or equal to ++ * 1500 bytes. All received frames with length field greater than or equal to ++ * 1501 bytes are passed to the application without stripping the Pad/FCS field. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_pad_crc_strip_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacPadCrcStrip); ++ return; ++} ++/** ++ * GMAC doesnot strips the Pad/FCS field of incoming frames. ++ * GMAC will pass all the incoming frames to Host unmodified. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_pad_crc_strip_disable(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacPadCrcStrip); ++ return; ++} ++/** ++ * GMAC programmed with the back off limit value. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ * \note This function is tightly coupled with synopGMAC_retry_enable(synopGMACdevice * gmacdev) ++ */ ++void synopGMAC_back_off_limit(synopGMACdevice * gmacdev, u32 value) ++{ ++ u32 data; ++ data = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacConfig); ++ data &= (~GmacBackoffLimit); ++ data |= value; ++ synopGMACWriteReg((u32 *)gmacdev->MacBase, GmacConfig,data); ++ return; ++} ++ ++/** ++ * Enables the Deferral check in GMAC (Only in Half Duplex mode) ++ * GMAC issues a Frame Abort Status, along with the excessive deferral error bit set in the ++ * transmit frame status when transmit state machine is deferred for more than ++ * - 24,288 bit times in 10/100Mbps mode ++ * - 155,680 bit times in 1000Mbps mode or Jumbo frame mode in 10/100Mbps operation. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ * \note Deferral begins when transmitter is ready to transmit, but is prevented because of ++ * an active CRS (carrier sense) ++ */ ++void synopGMAC_deferral_check_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacDeferralCheck); ++ return; ++} ++/** ++ * Disables the Deferral check in GMAC (Only in Half Duplex mode). ++ * GMAC defers until the CRS signal goes inactive. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_deferral_check_disable(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacDeferralCheck); ++ return; ++} ++/** ++ * Enable the reception of frames on GMII/MII. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_rx_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacRx); ++ return; ++} ++/** ++ * Disable the reception of frames on GMII/MII. ++ * GMAC receive state machine is disabled after completion of reception of current frame. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_rx_disable(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacRx); ++ return; ++} ++/** ++ * Enable the transmission of frames on GMII/MII. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_tx_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacTx); ++ return; ++} ++/** ++ * Disable the transmission of frames on GMII/MII. ++ * GMAC transmit state machine is disabled after completion of transmission of current frame. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_tx_disable(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacTx); ++ return; ++} ++ ++ ++/*Receive frame filter configuration functions*/ ++ ++/** ++ * Enables reception of all the frames to application. ++ * GMAC passes all the frames received to application irrespective of whether they ++ * pass SA/DA address filtering or not. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_frame_filter_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacFilter); ++ return; ++} ++/** ++ * Disables reception of all the frames to application. ++ * GMAC passes only those received frames to application which ++ * pass SA/DA address filtering. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_frame_filter_disable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacFilter); ++ return; ++} ++ ++/** ++ * Populates the Hash High register with the data supplied. ++ * This function is called when the Hash filtering is to be enabled. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] data to be written to hash table high register. ++ * \return void. ++ */ ++void synopGMAC_write_hash_table_high(synopGMACdevice * gmacdev, u32 data) ++{ ++ synopGMACWriteReg((u32 *)gmacdev->MacBase,GmacHashHigh,data); ++ return; ++} ++ ++/** ++ * Populates the Hash Low register with the data supplied. ++ * This function is called when the Hash filtering is to be enabled. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] data to be written to hash table low register. ++ * \return void. ++ */ ++void synopGMAC_write_hash_table_low(synopGMACdevice * gmacdev, u32 data) ++{ ++ synopGMACWriteReg((u32 *)gmacdev->MacBase,GmacHashLow,data); ++ return; ++} ++ ++/** ++ * Enables Hash or Perfect filter (only if Hash filter is enabled in H/W). ++ * Only frames matching either perfect filtering or Hash Filtering as per HMC and HUC ++ * configuration are sent to application. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_hash_perfect_filter_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacHashPerfectFilter); ++ return; ++} ++ ++/** ++ * Enables only Hash(only if Hash filter is enabled in H/W). ++ * Only frames matching Hash Filtering as per HMC and HUC ++ * configuration are sent to application. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_Hash_filter_only_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacHashPerfectFilter); ++ return; ++} ++ ++/** ++ * Enables Source address filtering. ++ * When enabled source address filtering is performed. Only frames matching SA filtering are passed to application with ++ * SAMatch bit of RxStatus is set. GMAC drops failed frames. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ * \note This function is overriden by synopGMAC_frame_filter_disable(synopGMACdevice *) ++ */ ++void synopGMAC_src_addr_filter_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacSrcAddrFilter); ++ return; ++} ++/** ++ * Disables Source address filtering. ++ * When disabled GMAC forwards the received frames with updated SAMatch bit in RxStatus. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_src_addr_filter_disable(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacSrcAddrFilter); ++ return; ++} ++/** ++ * Enables Inverse Destination address filtering. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_dst_addr_filter_inverse(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacDestAddrFilterNor); ++ return; ++} ++/** ++ * Enables the normal Destination address filtering. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_dst_addr_filter_normal(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacDestAddrFilterNor); ++ return; ++} ++ ++/** ++ * Enables forwarding of control frames. ++ * When set forwards all the control frames (incl. unicast and multicast PAUSE frames). ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ * \note Depends on RFE of FlowControlRegister[2] ++ */ ++void synopGMAC_set_pass_control(synopGMACdevice * gmacdev,u32 passcontrol) ++{ ++ u32 data; ++ data = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacFrameFilter); ++ data &= (~GmacPassControl); ++ data |= passcontrol; ++ synopGMACWriteReg((u32 *)gmacdev->MacBase,GmacFrameFilter,data); ++ return; ++} ++ ++/** ++ * Enables Broadcast frames. ++ * When enabled Address filtering module passes all incoming broadcast frames. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_broadcast_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacBroadcast); ++ return; ++} ++/** ++ * Disable Broadcast frames. ++ * When disabled Address filtering module filters all incoming broadcast frames. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_broadcast_disable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacBroadcast); ++ return; ++} ++ ++/** ++ * Enables Multicast frames. ++ * When enabled all multicast frames are passed. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_multicast_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacMulticastFilter); ++ return; ++} ++/** ++ * Disable Multicast frames. ++ * When disabled multicast frame filtering depends on HMC bit. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_multicast_disable(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacMulticastFilter); ++ return; ++} ++ ++/** ++ * Enables multicast hash filtering. ++ * When enabled GMAC performs teh destination address filtering according to the hash table. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_multicast_hash_filter_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacMcastHashFilter); ++ return; ++} ++/** ++ * Disables multicast hash filtering. ++ * When disabled GMAC performs perfect destination address filtering for multicast frames, it compares ++ * DA field with the value programmed in DA register. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_multicast_hash_filter_disable(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacMcastHashFilter); ++ return; ++} ++ ++/** ++ * Enables promiscous mode. ++ * When enabled Address filter modules pass all incoming frames regardless of their Destination ++ * and source addresses. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_promisc_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacPromiscuousMode); ++ return; ++} ++/** ++ * Clears promiscous mode. ++ * When called the GMAC falls back to normal operation from promiscous mode. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_promisc_disable(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacPromiscuousMode); ++ return; ++} ++ ++ ++/** ++ * Enables unicast hash filtering. ++ * When enabled GMAC performs the destination address filtering of unicast frames according to the hash table. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_unicast_hash_filter_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacUcastHashFilter); ++ return; ++} ++/** ++ * Disables multicast hash filtering. ++ * When disabled GMAC performs perfect destination address filtering for unicast frames, it compares ++ * DA field with the value programmed in DA register. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_unicast_hash_filter_disable(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacUcastHashFilter); ++ return; ++} ++ ++/*Flow control configuration functions*/ ++ ++/** ++ * Enables detection of pause frames with stations unicast address. ++ * When enabled GMAC detects the pause frames with stations unicast address in addition to the ++ * detection of pause frames with unique multicast address. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_unicast_pause_frame_detect_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacFlowControl, GmacUnicastPauseFrame); ++ return; ++} ++/** ++ * Disables detection of pause frames with stations unicast address. ++ * When disabled GMAC only detects with the unique multicast address (802.3x). ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_unicast_pause_frame_detect_disable(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacFlowControl, GmacUnicastPauseFrame); ++ return; ++} ++/** ++ * Rx flow control enable. ++ * When Enabled GMAC will decode the rx pause frame and disable the tx for a specified time. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_rx_flow_control_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacFlowControl, GmacRxFlowControl); ++ return; ++} ++/** ++ * Rx flow control disable. ++ * When disabled GMAC will not decode pause frame. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_rx_flow_control_disable(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacFlowControl, GmacRxFlowControl); ++ return; ++} ++/** ++ * Tx flow control enable. ++ * When Enabled ++ * - In full duplex GMAC enables flow control operation to transmit pause frames. ++ * - In Half duplex GMAC enables the back pressure operation ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_tx_flow_control_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacFlowControl, GmacTxFlowControl); ++ return; ++} ++ ++/** ++ * Tx flow control disable. ++ * When Disabled ++ * - In full duplex GMAC will not transmit any pause frames. ++ * - In Half duplex GMAC disables the back pressure feature. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_tx_flow_control_disable(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacFlowControl, GmacTxFlowControl); ++ return; ++} ++ ++/** ++ * Initiate Flowcontrol operation. ++ * When Set ++ * - In full duplex GMAC initiates pause control frame. ++ * - In Half duplex GMAC initiates back pressure function. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_tx_activate_flow_control(synopGMACdevice * gmacdev) ++{ ++ //In case of full duplex check for this bit to b'0. if it is read as b'1 indicates that ++ //control frame transmission is in progress. ++ if(gmacdev->Speed == FULLDUPLEX){ ++ if(!synopGMACCheckBits((u32 *)gmacdev->MacBase, GmacFlowControl, GmacFlowControlBackPressure)) ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacFlowControl, GmacFlowControlBackPressure); ++ } ++ else{ //if half duplex mode ++ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacFlowControl, GmacFlowControlBackPressure); ++ } ++ ++ return; ++} ++ ++/** ++ * stops Flowcontrol operation. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_tx_deactivate_flow_control(synopGMACdevice * gmacdev) ++{ ++ //In full duplex this bit is automatically cleared after transmitting a pause control frame. ++ if(gmacdev->Speed == HALFDUPLEX){ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacFlowControl, GmacFlowControlBackPressure); ++ } ++ return; ++} ++ ++/** ++ * This enables the pause frame generation after programming the appropriate registers. ++ * presently activation is set at 3k and deactivation set at 4k. These may have to tweaked ++ * if found any issues ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_pause_control(synopGMACdevice *gmacdev) ++{ ++ u32 omr_reg; ++ u32 mac_flow_control_reg; ++ omr_reg = synopGMACReadReg((u32 *)gmacdev->DmaBase,DmaControl); ++ omr_reg |= DmaRxFlowCtrlAct4K | DmaRxFlowCtrlDeact5K |DmaEnHwFlowCtrl; ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaControl, omr_reg); ++ ++ mac_flow_control_reg = synopGMACReadReg((u32 *)gmacdev->MacBase,GmacFlowControl); ++ mac_flow_control_reg |= GmacRxFlowControl | GmacTxFlowControl | 0xFFFF0000; ++ synopGMACWriteReg((u32 *)gmacdev->MacBase,GmacFlowControl,mac_flow_control_reg); ++ ++ return; ++ ++} ++ ++/** ++ * Example mac initialization sequence. ++ * This function calls the initialization routines to initialize the GMAC register. ++ * One can change the functions invoked here to have different configuration as per the requirement ++ * @param[in] pointer to synopGMACdevice. ++ * \return Returns 0 on success. ++ */ ++s32 synopGMAC_mac_init(synopGMACdevice * gmacdev) ++{ ++ u32 PHYreg; ++ ++ printk("=====>enter %s:%d\n", __func__, __LINE__); ++ ++ if(gmacdev->DuplexMode == FULLDUPLEX){ ++ printk("=====>full duplex\n"); ++ ++ synopGMAC_wd_enable(gmacdev); ++ //synopGMAC_jab_enable(gmacdev); ++ synopGMAC_frame_burst_enable(gmacdev); ++ synopGMAC_jumbo_frame_disable(gmacdev); ++ synopGMAC_rx_own_enable(gmacdev); ++ synopGMAC_loopback_off(gmacdev); ++ synopGMAC_set_full_duplex(gmacdev); ++ synopGMAC_retry_enable(gmacdev); ++ synopGMAC_pad_crc_strip_disable(gmacdev); ++ synopGMAC_back_off_limit(gmacdev,GmacBackoffLimit0); ++ synopGMAC_deferral_check_disable(gmacdev); ++ synopGMAC_tx_enable(gmacdev); ++ synopGMAC_rx_enable(gmacdev); ++ ++ if(gmacdev->Speed == SPEED1000) { ++ printk("=====>1000M\n"); ++ synopGMAC_select_gmii(gmacdev); ++ } else { ++ printk("=====>100M\n"); ++ synopGMAC_select_mii(gmacdev); ++ } ++ ++ /*Frame Filter Configuration*/ ++ synopGMAC_frame_filter_enable(gmacdev); ++ synopGMAC_set_pass_control(gmacdev,GmacPassControl0); ++ synopGMAC_broadcast_enable(gmacdev); ++ synopGMAC_src_addr_filter_disable(gmacdev); ++ synopGMAC_multicast_disable(gmacdev); ++ synopGMAC_dst_addr_filter_normal(gmacdev); ++ synopGMAC_multicast_hash_filter_disable(gmacdev); ++ synopGMAC_promisc_disable(gmacdev); ++ synopGMAC_unicast_hash_filter_disable(gmacdev); ++ ++ /*Flow Control Configuration*/ ++ synopGMAC_unicast_pause_frame_detect_disable(gmacdev); ++#if 0 ++ synopGMAC_rx_flow_control_enable(gmacdev); ++ synopGMAC_tx_flow_control_enable(gmacdev); ++#else ++ synopGMAC_rx_flow_control_disable(gmacdev); ++ synopGMAC_tx_flow_control_disable(gmacdev); ++#endif ++ } ++ else{//for Half Duplex configuration ++ printk("====>half duplex\n"); ++ ++ synopGMAC_wd_enable(gmacdev); ++ synopGMAC_jab_enable(gmacdev); ++ synopGMAC_frame_burst_enable(gmacdev); ++ synopGMAC_jumbo_frame_disable(gmacdev); ++ synopGMAC_rx_own_enable(gmacdev); ++ synopGMAC_loopback_off(gmacdev); ++ synopGMAC_set_half_duplex(gmacdev); ++ synopGMAC_retry_enable(gmacdev); ++ synopGMAC_pad_crc_strip_disable(gmacdev); ++ synopGMAC_back_off_limit(gmacdev,GmacBackoffLimit0); ++ synopGMAC_deferral_check_disable(gmacdev); ++ synopGMAC_tx_enable(gmacdev); ++ synopGMAC_rx_enable(gmacdev); ++ ++ if(gmacdev->Speed == SPEED1000) ++ synopGMAC_select_gmii(gmacdev); ++ else ++ synopGMAC_select_mii(gmacdev); ++ ++ /*Frame Filter Configuration*/ ++ synopGMAC_frame_filter_enable(gmacdev); ++ synopGMAC_set_pass_control(gmacdev,GmacPassControl0); ++ synopGMAC_broadcast_enable(gmacdev); ++ synopGMAC_src_addr_filter_disable(gmacdev); ++ synopGMAC_multicast_disable(gmacdev); ++ synopGMAC_dst_addr_filter_normal(gmacdev); ++ synopGMAC_multicast_hash_filter_disable(gmacdev); ++ synopGMAC_promisc_disable(gmacdev); ++ synopGMAC_unicast_hash_filter_disable(gmacdev); ++ ++ /*Flow Control Configuration*/ ++ synopGMAC_unicast_pause_frame_detect_disable(gmacdev); ++ synopGMAC_rx_flow_control_disable(gmacdev); ++ synopGMAC_tx_flow_control_disable(gmacdev); ++ ++ /*To set PHY register to enable CRS on Transmit*/ ++ synopGMACWriteReg((u32 *)gmacdev->MacBase, GmacGmiiAddr, GmiiBusy | 0x00000408); ++ PHYreg = synopGMACReadReg((u32 *)gmacdev->MacBase,GmacGmiiData); ++ synopGMACWriteReg((u32 *)gmacdev->MacBase, GmacGmiiData, PHYreg | 0x00000800); ++ synopGMACWriteReg((u32 *)gmacdev->MacBase, GmacGmiiAddr, GmiiBusy | 0x0000040a); ++ } ++ return 0; ++} ++ ++s32 synopGMAC_search_phy (synopGMACdevice * gmacdev) { ++ int phy_id = 0; ++ u16 data; ++ s32 status = -ESYNOPGMACNOERR; ++ ++ for (phy_id = 0; phy_id < 32; phy_id++) { ++ status = synopGMAC_read_phy_reg(gmacdev, phy_id, PHY_STATUS_REG, &data); ++ if ( (!status) && (data != 0xffff)) { ++ if((data & Mii_AutoNegCmplt) != 0){ ++ printk("====>phy %d Autonegotiation Complete\n", phy_id); ++ break; ++ } ++ } ++ } ++ ++ return (phy_id < 32) ? phy_id : -ESYNOPGMACPHYERR; ++} ++ ++/** ++ * Checks and initialze phy. ++ * This function checks whether the phy initialization is complete. ++ * @param[in] pointer to synopGMACdevice. ++ * \return 0 if success else returns the error number. ++ */ ++#if 0 ++s32 synopGMAC_check_phy_init (synopGMACdevice * gmacdev) ++{ ++ //u32 addr; ++ u16 data; ++ s32 status = -ESYNOPGMACNOERR; ++ s32 loop_count; ++ ++ loop_count = DEFAULT_LOOP_VARIABLE; ++ while(loop_count-- > 0) ++ { ++ ++ status = synopGMAC_read_phy_reg((u32 *)gmacdev->MacBase,gmacdev->PhyBase,PHY_STATUS_REG, &data); ++ if(status) ++ return status; ++ ++ if((data & Mii_AutoNegCmplt) != 0){ ++ TR("Autonegotiation Complete\n"); ++ break; ++ } ++ } ++ ++ status = synopGMAC_read_phy_reg((u32 *)gmacdev->MacBase,gmacdev->PhyBase,PHY_SPECIFIC_STATUS_REG, &data); ++ if(status) ++ return status; ++ ++ if((data & Mii_phy_status_link_up) == 0){ ++ TR("No Link\n"); ++ gmacdev->LinkState = LINKDOWN; ++ return -ESYNOPGMACPHYERR; ++ } ++ else{ ++ gmacdev->LinkState = LINKUP; ++ TR("Link UP\n"); ++ } ++ ++ status = synopGMAC_read_phy_reg((u32 *)gmacdev->MacBase,gmacdev->PhyBase,PHY_SPECIFIC_STATUS_REG, &data); ++ if(status) ++ return status; ++ ++ ++ ++ gmacdev->DuplexMode = (data & Mii_phy_status_full_duplex) ? FULLDUPLEX: HALFDUPLEX ; ++ TR("Link is up in %s mode\n",(gmacdev->DuplexMode == FULLDUPLEX) ? "FULL DUPLEX": "HALF DUPLEX"); ++ ++ /*if not set to Master configuration in case of Half duplex mode set it manually as Master*/ ++ if(gmacdev->DuplexMode == HALFDUPLEX){ ++ printk("=========>enter %s:%d\n", __func__, __LINE__); ++ status = synopGMAC_read_phy_reg((u32 *)gmacdev->MacBase,gmacdev->PhyBase,PHY_CONTROL_REG, &data); ++ if(status) ++ return status; ++ ++ status = synopGMAC_write_phy_reg((u32 *)gmacdev->MacBase,gmacdev->PhyBase,PHY_CONTROL_REG, data | Mii_Manual_Master_Config ); ++ if(status) ++ return status; ++ } ++ ++ status = synopGMAC_read_phy_reg((u32 *)gmacdev->MacBase,gmacdev->PhyBase,PHY_SPECIFIC_STATUS_REG, &data); ++ if(status) ++ return status; ++ if(data & Mii_phy_status_speed_1000) ++ gmacdev->Speed = SPEED1000; ++ else if(data & Mii_phy_status_speed_100) ++ gmacdev->Speed = SPEED100; ++ else ++ gmacdev->Speed = SPEED10; ++ ++ if(gmacdev->Speed == SPEED1000) ++ TR("Link is with 1000M Speed \n"); ++ if(gmacdev->Speed == SPEED100) ++ TR("Link is with 100M Speed \n"); ++ if(gmacdev->Speed == SPEED10) ++ TR("Link is with 10M Speed \n"); ++ ++ return -ESYNOPGMACNOERR; ++} ++#else ++s32 synopGMAC_check_phy_init (synopGMACdevice * gmacdev) { ++ gmacdev->LinkState = LINKUP; ++ gmacdev->DuplexMode = FULLDUPLEX; ++ gmacdev->Speed = SPEED100; ++ ++ return -ESYNOPGMACNOERR; ++} ++#endif ++ ++/** ++ * Sets the Mac address in to GMAC register. ++ * This function sets the MAC address to the MAC register in question. ++ * @param[in] pointer to synopGMACdevice to populate mac dma and phy addresses. ++ * @param[in] Register offset for Mac address high ++ * @param[in] Register offset for Mac address low ++ * @param[in] buffer containing mac address to be programmed. ++ * \return 0 upon success. Error code upon failure. ++ */ ++s32 synopGMAC_set_mac_addr(synopGMACdevice *gmacdev, u32 MacHigh, u32 MacLow, u8 *MacAddr) ++{ ++ u32 data; ++ ++ data = (MacAddr[5] << 8) | MacAddr[4]; ++ synopGMACWriteReg((u32 *)gmacdev->MacBase,MacHigh,data); ++ data = (MacAddr[3] << 24) | (MacAddr[2] << 16) | (MacAddr[1] << 8) | MacAddr[0] ; ++ synopGMACWriteReg((u32 *)gmacdev->MacBase,MacLow,data); ++ return 0; ++} ++ ++ ++/** ++ * Get the Mac address in to the address specified. ++ * The mac register contents are read and written to buffer passed. ++ * @param[in] pointer to synopGMACdevice to populate mac dma and phy addresses. ++ * @param[in] Register offset for Mac address high ++ * @param[in] Register offset for Mac address low ++ * @param[out] buffer containing the device mac address. ++ * \return 0 upon success. Error code upon failure. ++ */ ++s32 synopGMAC_get_mac_addr(synopGMACdevice *gmacdev, u32 MacHigh, u32 MacLow, u8 *MacAddr) ++{ ++ u32 data; ++ ++ data = synopGMACReadReg((u32 *)gmacdev->MacBase,MacHigh); ++ MacAddr[5] = (data >> 8) & 0xff; ++ MacAddr[4] = (data) & 0xff; ++ ++ data = synopGMACReadReg((u32 *)gmacdev->MacBase,MacLow); ++ MacAddr[3] = (data >> 24) & 0xff; ++ MacAddr[2] = (data >> 16) & 0xff; ++ MacAddr[1] = (data >> 8 ) & 0xff; ++ MacAddr[0] = (data ) & 0xff; ++ ++ return 0; ++} ++ ++ ++/** ++ * Attaches the synopGMAC device structure to the hardware. ++ * Device structure is populated with MAC/DMA and PHY base addresses. ++ * @param[in] pointer to synopGMACdevice to populate mac dma and phy addresses. ++ * @param[in] GMAC IP mac base address. ++ * @param[in] GMAC IP dma base address. ++ * @param[in] GMAC IP phy base address. ++ * \return 0 upon success. Error code upon failure. ++ * \note This is important function. No kernel api provided by Synopsys ++ */ ++ ++s32 synopGMAC_attach (synopGMACdevice * gmacdev, u32 macBase, u32 dmaBase, u32 phyBase) ++{ ++ u8 mac_addr0[6] = DEFAULT_MAC_ADDRESS; ++ /*Make sure the Device data strucure is cleared before we proceed further*/ ++ memset((void *) gmacdev,0,sizeof(synopGMACdevice)); ++ /*Populate the mac and dma base addresses*/ ++ gmacdev->MacBase = macBase; ++ gmacdev->DmaBase = dmaBase; ++ gmacdev->PhyBase = phyBase; ++ ++ printk("=======>MacBase = 0x%08x, DmaBase = 0x%08x PhyBase = 0x%08x\n", ++ gmacdev->MacBase, gmacdev->DmaBase, gmacdev->PhyBase); ++ ++ /* Program/flash in the station/IP's Mac address */ ++ synopGMAC_set_mac_addr(gmacdev,GmacAddr0High,GmacAddr0Low, mac_addr0); ++ ++ return 0; ++} ++ ++ ++ ++/** ++ * Initialize the rx descriptors for ring or chain mode operation. ++ * - Status field is initialized to 0. ++ * - EndOfRing set for the last descriptor. ++ * - buffer1 and buffer2 set to 0 for ring mode of operation. (note) ++ * - data1 and data2 set to 0. (note) ++ * @param[in] pointer to DmaDesc structure. ++ * @param[in] whether end of ring ++ * \return void. ++ * \note Initialization of the buffer1, buffer2, data1,data2 and status are not done here. This only initializes whether one wants to use this descriptor ++ * in chain mode or ring mode. For chain mode of operation the buffer2 and data2 are programmed before calling this function. ++ */ ++void synopGMAC_rx_desc_init_ring(DmaDesc *desc, bool last_ring_desc) ++{ ++ desc->status = 0; ++ desc->length = last_ring_desc ? RxDescEndOfRing : 0; ++ desc->buffer1 = 0; ++ desc->buffer2 = 0; ++ desc->data1 = 0; ++ desc->data2 = 0; ++ return; ++} ++/** ++ * Initialize the tx descriptors for ring or chain mode operation. ++ * - Status field is initialized to 0. ++ * - EndOfRing set for the last descriptor. ++ * - buffer1 and buffer2 set to 0 for ring mode of operation. (note) ++ * - data1 and data2 set to 0. (note) ++ * @param[in] pointer to DmaDesc structure. ++ * @param[in] whether end of ring ++ * \return void. ++ * \note Initialization of the buffer1, buffer2, data1,data2 and status are not done here. This only initializes whether one wants to use this descriptor ++ * in chain mode or ring mode. For chain mode of operation the buffer2 and data2 are programmed before calling this function. ++ */ ++void synopGMAC_tx_desc_init_ring(DmaDesc *desc, bool last_ring_desc) ++{ ++#ifdef ENH_DESC ++ desc->status = last_ring_desc? TxDescEndOfRing : 0; ++ desc->length = 0; ++#else ++ desc->length = last_ring_desc? TxDescEndOfRing : 0; ++#endif ++ desc->buffer1 = 0; ++ desc->buffer2 = 0; ++ desc->data1 = 0; ++ desc->data2 = 0; ++ return; ++} ++ ++ ++ ++/** ++ * Initialize the rx descriptors for chain mode of operation. ++ * - Status field is initialized to 0. ++ * - EndOfRing set for the last descriptor. ++ * - buffer1 and buffer2 set to 0. ++ * - data1 and data2 set to 0. ++ * @param[in] pointer to DmaDesc structure. ++ * @param[in] whether end of ring ++ * \return void. ++ */ ++ ++void synopGMAC_rx_desc_init_chain(DmaDesc * desc) ++{ ++ desc->status = 0; ++ desc->length = RxDescChain; ++ desc->buffer1 = 0; ++ desc->data1 = 0; ++ return; ++} ++/** ++ * Initialize the rx descriptors for chain mode of operation. ++ * - Status field is initialized to 0. ++ * - EndOfRing set for the last descriptor. ++ * - buffer1 and buffer2 set to 0. ++ * - data1 and data2 set to 0. ++ * @param[in] pointer to DmaDesc structure. ++ * @param[in] whether end of ring ++ * \return void. ++ */ ++void synopGMAC_tx_desc_init_chain(DmaDesc * desc) ++{ ++#ifdef ENH_DESC ++ desc->status = TxDescChain; ++ desc->length = 0; ++#else ++ desc->length = TxDescChain; ++#endif ++ desc->buffer1 = 0; ++ desc->data1 = 0; ++ return; ++} ++ ++ ++s32 synopGMAC_init_tx_rx_desc_queue(synopGMACdevice *gmacdev) ++{ ++ s32 i; ++ for(i =0; i < gmacdev -> TxDescCount; i++){ ++ synopGMAC_tx_desc_init_ring(gmacdev->TxDesc + i, i == gmacdev->TxDescCount-1); ++ } ++ TR("At line %d\n",__LINE__); ++ for(i =0; i < gmacdev -> RxDescCount; i++){ ++ synopGMAC_rx_desc_init_ring(gmacdev->RxDesc + i, i == gmacdev->RxDescCount-1); ++ } ++ ++ gmacdev->TxNext = 0; ++ gmacdev->TxBusy = 0; ++ gmacdev->RxNext = 0; ++ gmacdev->RxBusy = 0; ++ ++ return -ESYNOPGMACNOERR; ++} ++/** ++ * Programs the DmaRxBaseAddress with the Rx descriptor base address. ++ * Rx Descriptor's base address is available in the gmacdev structure. This function progrms the ++ * Dma Rx Base address with the starting address of the descriptor ring or chain. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_init_rx_desc_base(synopGMACdevice *gmacdev) ++{ ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase,DmaRxBaseAddr,(u32)gmacdev->RxDescDma); ++ return; ++} ++ ++/** ++ * Programs the DmaTxBaseAddress with the Tx descriptor base address. ++ * Tx Descriptor's base address is available in the gmacdev structure. This function progrms the ++ * Dma Tx Base address with the starting address of the descriptor ring or chain. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_init_tx_desc_base(synopGMACdevice *gmacdev) ++{ ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase,DmaTxBaseAddr,(u32)gmacdev->TxDescDma); ++ return; ++} ++ ++ ++/** ++ * Makes the Dma as owner for this descriptor. ++ * This function sets the own bit of status field of the DMA descriptor, ++ * indicating the DMA is the owner for this descriptor. ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns void. ++ */ ++void synopGMAC_set_owner_dma(DmaDesc *desc) ++{ ++ desc->status |= DescOwnByDma; ++} ++ ++/** ++ * set tx descriptor to indicate SOF. ++ * This Descriptor contains the start of ethernet frame. ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns void. ++ */ ++void synopGMAC_set_desc_sof(DmaDesc *desc) ++{ ++#ifdef ENH_DESC ++ desc->status |= DescTxFirst;//ENH_DESC ++#else ++ desc->length |= DescTxFirst; ++#endif ++ ++} ++ ++/** ++ * set tx descriptor to indicate EOF. ++ * This descriptor contains the End of ethernet frame. ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns void. ++ */ ++void synopGMAC_set_desc_eof(DmaDesc *desc) ++{ ++#ifdef ENH_DESC ++ desc->status |= DescTxLast;//ENH_DESC ++#else ++ desc->length |= DescTxLast; ++#endif ++} ++ ++ ++/** ++ * checks whether this descriptor contains start of frame. ++ * This function is to check whether the descriptor's data buffer ++ * contains a fresh ethernet frame? ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns true if SOF in current descriptor, else returns fail. ++ */ ++bool synopGMAC_is_sof_in_rx_desc(DmaDesc *desc) ++{ ++ return ((desc->status & DescRxFirst) == DescRxFirst); ++} ++ ++/** ++ * checks whether this descriptor contains end of frame. ++ * This function is to check whether the descriptor's data buffer ++ * contains end of ethernet frame? ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns true if SOF in current descriptor, else returns fail. ++ */ ++bool synopGMAC_is_eof_in_rx_desc(DmaDesc *desc) ++{ ++ return ((desc->status & DescRxLast) == DescRxLast); ++} ++ ++/** ++ * checks whether destination address filter failed in the rx frame. ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns true if Failed, false if not. ++ */ ++bool synopGMAC_is_da_filter_failed(DmaDesc *desc) ++{ ++ return ((desc->status & DescDAFilterFail) == DescDAFilterFail); ++} ++ ++/** ++ * checks whether source address filter failed in the rx frame. ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns true if Failed, false if not. ++ */ ++bool synopGMAC_is_sa_filter_failed(DmaDesc *desc) ++{ ++ return ((desc->status & DescSAFilterFail) == DescSAFilterFail); ++} ++ ++/** ++ * Checks whether the descriptor is owned by DMA. ++ * If descriptor is owned by DMA then the OWN bit is set to 1. This API is same for both ring and chain mode. ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns true if Dma owns descriptor and false if not. ++ */ ++bool synopGMAC_is_desc_owned_by_dma(DmaDesc *desc) ++{ ++ return ((desc->status & DescOwnByDma) == DescOwnByDma ); ++} ++ ++/** ++ * returns the byte length of received frame including CRC. ++ * This returns the no of bytes received in the received ethernet frame including CRC(FCS). ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns the length of received frame lengths in bytes. ++ */ ++u32 synopGMAC_get_rx_desc_frame_length(u32 status) ++{ ++ return ((status & DescFrameLengthMask) >> DescFrameLengthShift); ++} ++ ++/** ++ * Checks whether the descriptor is valid ++ * if no errors such as CRC/Receive Error/Watchdog Timeout/Late collision/Giant Frame/Overflow/Descriptor ++ * error the descritpor is said to be a valid descriptor. ++ * @param[in] pointer to DmaDesc structure. ++ * \return True if desc valid. false if error. ++ */ ++bool synopGMAC_is_desc_valid(u32 status) ++{ ++ return ((status & DescError) == 0); ++} ++ ++/** ++ * Checks whether the descriptor is empty. ++ * If the buffer1 and buffer2 lengths are zero in ring mode descriptor is empty. ++ * In chain mode buffer2 length is 0 but buffer2 itself contains the next descriptor address. ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns true if descriptor is empty, false if not empty. ++ */ ++bool synopGMAC_is_desc_empty(DmaDesc *desc) ++{ ++ //if both the buffer1 length and buffer2 length are zero desc is empty ++ return(((desc->length & DescSize1Mask) == 0) && ((desc->length & DescSize2Mask) == 0) ); ++} ++ ++ ++/** ++ * Checks whether the rx descriptor is valid. ++ * if rx descripor is not in error and complete frame is available in the same descriptor ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns true if no error and first and last desc bits are set, otherwise it returns false. ++ */ ++bool synopGMAC_is_rx_desc_valid(u32 status) ++{ ++ return ((status & DescError) == 0) && ((status & DescRxFirst) == DescRxFirst) && ((status & DescRxLast) == DescRxLast); ++} ++ ++/** ++ * Checks whether the tx is aborted due to collisions. ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns true if collisions, else returns false. ++ */ ++bool synopGMAC_is_tx_aborted(u32 status) ++{ ++ return (((status & DescTxLateCollision) == DescTxLateCollision) | ((status & DescTxExcCollisions) == DescTxExcCollisions)); ++ ++} ++ ++/** ++ * Checks whether the tx carrier error. ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns true if carrier error occured, else returns falser. ++ */ ++bool synopGMAC_is_tx_carrier_error(u32 status) ++{ ++ return (((status & DescTxLostCarrier) == DescTxLostCarrier) | ((status & DescTxNoCarrier) == DescTxNoCarrier)); ++} ++ ++ ++/** ++ * Gives the transmission collision count. ++ * returns the transmission collision count indicating number of collisions occured before the frame was transmitted. ++ * Make sure to check excessive collision didnot happen to ensure the count is valid. ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns the count value of collision. ++ */ ++u32 synopGMAC_get_tx_collision_count(u32 status) ++{ ++ return ((status & DescTxCollMask) >> DescTxCollShift); ++} ++u32 synopGMAC_is_exc_tx_collisions(u32 status) ++{ ++ return ((status & DescTxExcCollisions) == DescTxExcCollisions); ++} ++ ++ ++/** ++ * Check for damaged frame due to overflow or collision. ++ * Retruns true if rx frame was damaged due to buffer overflow in MTL or late collision in half duplex mode. ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns true if error else returns false. ++ */ ++bool synopGMAC_is_rx_frame_damaged(u32 status) ++{ ++ //bool synopGMAC_dma_rx_collisions(u32 status) ++ return (((status & DescRxDamaged) == DescRxDamaged) | ((status & DescRxCollision) == DescRxCollision)); ++} ++ ++/** ++ * Check for damaged frame due to collision. ++ * Retruns true if rx frame was damaged due to late collision in half duplex mode. ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns true if error else returns false. ++ */ ++bool synopGMAC_is_rx_frame_collision(u32 status) ++{ ++ //bool synopGMAC_dma_rx_collisions(u32 status) ++ return ((status & DescRxCollision) == DescRxCollision); ++} ++ ++/** ++ * Check for receive CRC error. ++ * Retruns true if rx frame CRC error occured. ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns true if error else returns false. ++ */ ++bool synopGMAC_is_rx_crc(u32 status) ++{ ++ //u32 synopGMAC_dma_rx_crc(u32 status) ++ return ((status & DescRxCrc) == DescRxCrc); ++} ++ ++/** ++ * Indicates rx frame has non integer multiple of bytes. (odd nibbles). ++ * Retruns true if dribbling error in rx frame. ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns true if error else returns false. ++ */ ++bool synopGMAC_is_frame_dribbling_errors(u32 status) ++{ ++ //u32 synopGMAC_dma_rx_frame_errors(u32 status) ++ return ((status & DescRxDribbling) == DescRxDribbling); ++} ++ ++/** ++ * Indicates error in rx frame length. ++ * Retruns true if received frame length doesnot match with the length field ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns true if error else returns false. ++ */ ++bool synopGMAC_is_rx_frame_length_errors(u32 status) ++{ ++ //u32 synopGMAC_dma_rx_length_errors(u32 status) ++ return((status & DescRxLengthError) == DescRxLengthError); ++} ++ ++/** ++ * Checks whether this rx descriptor is last rx descriptor. ++ * This returns true if it is last descriptor either in ring mode or in chain mode. ++ * @param[in] pointer to devic structure. ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns true if it is last descriptor, false if not. ++ * \note This function should not be called before initializing the descriptor using synopGMAC_desc_init(). ++ */ ++bool synopGMAC_is_last_rx_desc(synopGMACdevice * gmacdev,DmaDesc *desc) ++{ ++ //bool synopGMAC_is_last_desc(DmaDesc *desc) ++ return (((desc->length & RxDescEndOfRing) == RxDescEndOfRing) || ((u32)gmacdev->RxDesc == desc->data2)); ++} ++ ++/** ++ * Checks whether this tx descriptor is last tx descriptor. ++ * This returns true if it is last descriptor either in ring mode or in chain mode. ++ * @param[in] pointer to devic structure. ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns true if it is last descriptor, false if not. ++ * \note This function should not be called before initializing the descriptor using synopGMAC_desc_init(). ++ */ ++bool synopGMAC_is_last_tx_desc(synopGMACdevice * gmacdev,DmaDesc *desc) ++{ ++ //bool synopGMAC_is_last_desc(DmaDesc *desc) ++#ifdef ENH_DESC ++ return (((desc->status & TxDescEndOfRing) == TxDescEndOfRing) || ((u32)gmacdev->TxDesc == desc->data2)); ++#else ++ return (((desc->length & TxDescEndOfRing) == TxDescEndOfRing) || ((u32)gmacdev->TxDesc == desc->data2)); ++#endif ++} ++ ++/** ++ * Checks whether this rx descriptor is in chain mode. ++ * This returns true if it is this descriptor is in chain mode. ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns true if chain mode is set, false if not. ++ */ ++bool synopGMAC_is_rx_desc_chained(DmaDesc * desc) ++{ ++ return((desc->length & RxDescChain) == RxDescChain); ++} ++ ++/** ++ * Checks whether this tx descriptor is in chain mode. ++ * This returns true if it is this descriptor is in chain mode. ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns true if chain mode is set, false if not. ++ */ ++bool synopGMAC_is_tx_desc_chained(DmaDesc * desc) ++{ ++#ifdef ENH_DESC ++ return((desc->status & TxDescChain) == TxDescChain); ++#else ++ return((desc->length & TxDescChain) == TxDescChain); ++#endif ++} ++ ++/** ++ * Driver Api to get the descriptor field information. ++ * This returns the status, dma-able address of buffer1, the length of buffer1, virtual address of buffer1 ++ * dma-able address of buffer2, length of buffer2, virtural adddress of buffer2. ++ * @param[in] pointer to DmaDesc structure. ++ * @param[out] pointer to status field fo descriptor. ++ * @param[out] dma-able address of buffer1. ++ * @param[out] length of buffer1. ++ * @param[out] virtual address of buffer1. ++ * @param[out] dma-able address of buffer2. ++ * @param[out] length of buffer2. ++ * @param[out] virtual address of buffer2. ++ * \return returns void. ++ */ ++void synopGMAC_get_desc_data(DmaDesc * desc, u32 * Status, u32 * Buffer1, u32 * Length1, u32 * Data1, u32 * Buffer2, u32 * Length2, u32 * Data2) ++{ ++ ++ if(Status != 0) ++ *Status = desc->status; ++ ++ if(Buffer1 != 0) ++ *Buffer1 = desc->buffer1; ++ if(Length1 != 0) ++ *Length1 = (desc->length & DescSize1Mask) >> DescSize1Shift; ++ if(Data1 != 0) ++ *Data1 = desc->data1; ++ ++ if(Buffer2 != 0) ++ *Buffer2 = desc->buffer2; ++ if(Length2 != 0) ++ *Length2 = (desc->length & DescSize2Mask) >> DescSize2Shift; ++ if(Data1 != 0) ++ *Data2 = desc->data2; ++ ++ return; ++ ++} ++#ifdef AVB_SUPPORT ++void synopGMAC_set_desc_data(DmaDesc *txdesc, u32 Status, u32 Buffer1, u32 Length1, u32 Data1, u32 Buffer2, u32 Length2, u32 Data2) ++{ ++ TR("s:%08x B1:%08x L1:%08x D1: %08x B2: %08x L2: %08x D2: %08x\n",Status,Buffer1,Length1,Data1,Buffer2,Length2,Data2); ++ ++ txdesc->length = (((Length1 <status |= (DescTxFirst | DescTxLast | DescTxIntEnable | Status ); //ENH_DESC ++#else ++ txdesc->length |= (DescTxFirst | DescTxLast | DescTxIntEnable ); //Its always assumed that complete data will fit in to one descriptor ++#endif ++ ++ txdesc->buffer1 = Buffer1; ++ txdesc->data1 = Data1; ++ ++ txdesc->buffer2 = Buffer2; ++ txdesc->data2 = Data2; ++ ++#ifdef ENH_DESC ++ txdesc->status |= DescOwnByDma;//ENH_DESC ++#else ++ txdesc->status = DescOwnByDma; ++#endif ++} ++#endif ++ ++#ifdef ENH_DESC_8W ++/** ++ * This function is defined two times. Once when the code is compiled for ENHANCED DESCRIPTOR SUPPORT and Once for Normal descriptor ++ * Get the index and address of Tx desc. ++ * This api is same for both ring mode and chain mode. ++ * This function tracks the tx descriptor the DMA just closed after the transmission of data from this descriptor is ++ * over. This returns the descriptor fields to the caller. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[out] status field of the descriptor. ++ * @param[out] Dma-able buffer1 pointer. ++ * @param[out] length of buffer1 (Max is 2048). ++ * @param[out] virtual pointer for buffer1. ++ * @param[out] Dma-able buffer2 pointer. ++ * @param[out] length of buffer2 (Max is 2048). ++ * @param[out] virtual pointer for buffer2. ++ * @param[out] u32 data indicating whether the descriptor is in ring mode or chain mode. ++ * \return returns present tx descriptor index on success. Negative value if error. ++ */ ++s32 synopGMAC_get_tx_qptr(synopGMACdevice * gmacdev, u32 * Status, u32 * Buffer1, u32 * Length1, u32 * Data1, u32 * Buffer2, u32 * Length2, u32 * Data2, ++ u32 * Ext_Status, u32 * Time_Stamp_High, u32 * Time_Stamp_Low) ++{ ++ u32 txover = gmacdev->TxBusy; ++ DmaDesc * txdesc = gmacdev->TxBusyDesc; ++ ++ if(synopGMAC_is_desc_owned_by_dma(txdesc)) ++ return -1; ++ if(synopGMAC_is_desc_empty(txdesc)) ++ return -1; ++ ++ (gmacdev->BusyTxDesc)--; //busy tx descriptor is reduced by one as it will be handed over to Processor now ++ ++ if(Status != 0) ++ *Status = txdesc->status; ++ ++ if(Ext_Status != 0) ++ *Ext_Status = txdesc->extstatus; ++ if(Time_Stamp_High != 0) ++ *Time_Stamp_High = txdesc->timestamphigh; ++ if(Time_Stamp_Low != 0) ++ *Time_Stamp_High = txdesc->timestamplow; ++ ++ if(Buffer1 != 0) ++ *Buffer1 = txdesc->buffer1; ++ if(Length1 != 0) ++ *Length1 = (txdesc->length & DescSize1Mask) >> DescSize1Shift; ++ if(Data1 != 0) ++ *Data1 = txdesc->data1; ++ ++ if(Buffer2 != 0) ++ *Buffer2 = txdesc->buffer2; ++ if(Length2 != 0) ++ *Length2 = (txdesc->length & DescSize2Mask) >> DescSize2Shift; ++ if(Data1 != 0) ++ *Data2 = txdesc->data2; ++ ++ gmacdev->TxBusy = synopGMAC_is_last_tx_desc(gmacdev,txdesc) ? 0 : txover + 1; ++ ++ if(synopGMAC_is_tx_desc_chained(txdesc)){ ++ gmacdev->TxBusyDesc = (DmaDesc *)txdesc->data2; ++ synopGMAC_tx_desc_init_chain(txdesc); ++ } ++ else{ ++ gmacdev->TxBusyDesc = synopGMAC_is_last_tx_desc(gmacdev,txdesc) ? gmacdev->TxDesc : (txdesc + 1); ++ synopGMAC_tx_desc_init_ring(txdesc, synopGMAC_is_last_tx_desc(gmacdev,txdesc)); ++ } ++ TR("(get)%02d %08x %08x %08x %08x %08x %08x %08x\n",txover,(u32)txdesc,txdesc->status,txdesc->length,txdesc->buffer1,txdesc->buffer2,txdesc->data1,txdesc->data2); ++ ++ return txover; ++} ++#else ++ ++/** ++ * Get the index and address of Tx desc. ++ * This api is same for both ring mode and chain mode. ++ * This function tracks the tx descriptor the DMA just closed after the transmission of data from this descriptor is ++ * over. This returns the descriptor fields to the caller. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[out] status field of the descriptor. ++ * @param[out] Dma-able buffer1 pointer. ++ * @param[out] length of buffer1 (Max is 2048). ++ * @param[out] virtual pointer for buffer1. ++ * @param[out] Dma-able buffer2 pointer. ++ * @param[out] length of buffer2 (Max is 2048). ++ * @param[out] virtual pointer for buffer2. ++ * @param[out] u32 data indicating whether the descriptor is in ring mode or chain mode. ++ * \return returns present tx descriptor index on success. Negative value if error. ++ */ ++s32 synopGMAC_get_tx_qptr(synopGMACdevice * gmacdev, u32 * Status, u32 * Buffer1, u32 * Length1, u32 * Data1, u32 * Buffer2, u32 * Length2, u32 * Data2 ) ++{ ++ u32 txover = gmacdev->TxBusy; ++ DmaDesc * txdesc = gmacdev->TxBusyDesc; ++ ++ if(synopGMAC_is_desc_owned_by_dma(txdesc)) ++ return -1; ++ if(synopGMAC_is_desc_empty(txdesc)) ++ return -1; ++ ++ (gmacdev->BusyTxDesc)--; //busy tx descriptor is reduced by one as it will be handed over to Processor now ++ ++ if(Status != 0) ++ *Status = txdesc->status; ++ ++ if(Buffer1 != 0) ++ *Buffer1 = txdesc->buffer1; ++ if(Length1 != 0) ++ *Length1 = (txdesc->length & DescSize1Mask) >> DescSize1Shift; ++ if(Data1 != 0) ++ *Data1 = txdesc->data1; ++ ++ if(Buffer2 != 0) ++ *Buffer2 = txdesc->buffer2; ++ if(Length2 != 0) ++ *Length2 = (txdesc->length & DescSize2Mask) >> DescSize2Shift; ++ if(Data1 != 0) ++ *Data2 = txdesc->data2; ++ ++ gmacdev->TxBusy = synopGMAC_is_last_tx_desc(gmacdev,txdesc) ? 0 : txover + 1; ++ ++ if(synopGMAC_is_tx_desc_chained(txdesc)){ ++ gmacdev->TxBusyDesc = (DmaDesc *)txdesc->data2; ++ synopGMAC_tx_desc_init_chain(txdesc); ++ } ++ else{ ++ gmacdev->TxBusyDesc = synopGMAC_is_last_tx_desc(gmacdev,txdesc) ? gmacdev->TxDesc : (txdesc + 1); ++ synopGMAC_tx_desc_init_ring(txdesc, synopGMAC_is_last_tx_desc(gmacdev,txdesc)); ++ } ++ TR("(get)%02d %08x %08x %08x %08x %08x %08x %08x\n",txover,(u32)txdesc,txdesc->status,txdesc->length,txdesc->buffer1,txdesc->buffer2,txdesc->data1,txdesc->data2); ++ ++ return txover; ++} ++ ++#endif ++/** ++ * Populate the tx desc structure with the buffer address. ++ * Once the driver has a packet ready to be transmitted, this function is called with the ++ * valid dma-able buffer addresses and their lengths. This function populates the descriptor ++ * and make the DMA the owner for the descriptor. This function also controls whetther Checksum ++ * offloading to be done in hardware or not. ++ * This api is same for both ring mode and chain mode. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] Dma-able buffer1 pointer. ++ * @param[in] length of buffer1 (Max is 2048). ++ * @param[in] virtual pointer for buffer1. ++ * @param[in] Dma-able buffer2 pointer. ++ * @param[in] length of buffer2 (Max is 2048). ++ * @param[in] virtual pointer for buffer2. ++ * @param[in] u32 data indicating whether the descriptor is in ring mode or chain mode. ++ * @param[in] u32 indicating whether the checksum offloading in HW/SW. ++ * \return returns present tx descriptor index on success. Negative value if error. ++ */ ++s32 synopGMAC_set_tx_qptr(synopGMACdevice * gmacdev, u32 Buffer1, u32 Length1, u32 Data1, u32 Buffer2, u32 Length2, u32 Data2,u32 offload_needed) ++{ ++ u32 txnext = gmacdev->TxNext; ++ DmaDesc * txdesc = gmacdev->TxNextDesc; ++ if(!synopGMAC_is_desc_empty(txdesc)) ++ return -1; ++ ++ (gmacdev->BusyTxDesc)++; //busy tx descriptor is incremented by one as it will be handed over to DMA ++ ++ if(synopGMAC_is_tx_desc_chained(txdesc)){ ++ txdesc->length |= ((Length1 <status |= (DescTxFirst | DescTxLast | DescTxIntEnable); //ENH_DESC ++#else ++ txdesc->length |= (DescTxFirst | DescTxLast | DescTxIntEnable); //Its always assumed that complete data will fit in to one descriptor ++#endif ++ ++ txdesc->buffer1 = Buffer1; ++ txdesc->data1 = Data1; ++ ++ if(offload_needed){ ++ /* ++ Make sure that the OS you are running supports the IP and TCP checkusm offloaidng, ++ before calling any of the functions given below. ++ */ ++ synopGMAC_tx_checksum_offload_ipv4hdr(gmacdev, txdesc); ++ synopGMAC_tx_checksum_offload_tcponly(gmacdev, txdesc); ++ // synopGMAC_tx_checksum_offload_tcp_pseudo(gmacdev, txdesc); ++ } ++#ifdef ENH_DESC ++ txdesc->status |= DescOwnByDma;//ENH_DESC ++#else ++ txdesc->status = DescOwnByDma; ++#endif ++ ++ gmacdev->TxNext = synopGMAC_is_last_tx_desc(gmacdev,txdesc) ? 0 : txnext + 1; ++ gmacdev->TxNextDesc = (DmaDesc *)txdesc->data2; ++ } ++ else{ ++ txdesc->length |= (((Length1 <status |= (DescTxFirst | DescTxLast | DescTxIntEnable); //ENH_DESC ++#else ++ txdesc->length |= (DescTxFirst | DescTxLast | DescTxIntEnable); //Its always assumed that complete data will fit in to one descriptor ++#endif ++ ++ txdesc->buffer1 = Buffer1; ++ txdesc->data1 = Data1; ++ ++ txdesc->buffer2 = Buffer2; ++ txdesc->data2 = Data2; ++ ++ if(offload_needed){ ++ /* ++ Make sure that the OS you are running supports the IP and TCP checkusm offloaidng, ++ before calling any of the functions given below. ++ */ ++ synopGMAC_tx_checksum_offload_ipv4hdr(gmacdev, txdesc); ++ synopGMAC_tx_checksum_offload_tcponly(gmacdev, txdesc); ++ // synopGMAC_tx_checksum_offload_tcp_pseudo(gmacdev, txdesc); ++ } ++#ifdef ENH_DESC ++ txdesc->status |= DescOwnByDma;//ENH_DESC ++#else ++ txdesc->status = DescOwnByDma; ++#endif ++ ++ gmacdev->TxNext = synopGMAC_is_last_tx_desc(gmacdev,txdesc) ? 0 : txnext + 1; ++ gmacdev->TxNextDesc = synopGMAC_is_last_tx_desc(gmacdev,txdesc) ? gmacdev->TxDesc : (txdesc + 1); ++ } ++ ++ ++ TR("(set)%02d %08x %08x %08x %08x %08x %08x %08x\n",txnext,(u32)txdesc,txdesc->status,txdesc->length,txdesc->buffer1,txdesc->buffer2,txdesc->data1,txdesc->data2); ++ return txnext; ++} ++#ifdef ENH_DESC_8W ++/** ++ * Prepares the descriptor to receive packets. ++ * The descriptor is allocated with the valid buffer addresses (sk_buff address) and the length fields ++ * and handed over to DMA by setting the ownership. After successful return from this function the ++ * descriptor is added to the receive descriptor pool/queue. ++ * This api is same for both ring mode and chain mode. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] Dma-able buffer1 pointer. ++ * @param[in] length of buffer1 (Max is 2048). ++ * @param[in] Dma-able buffer2 pointer. ++ * @param[in] length of buffer2 (Max is 2048). ++ * @param[in] u32 data indicating whether the descriptor is in ring mode or chain mode. ++ * \return returns present rx descriptor index on success. Negative value if error. ++ */ ++s32 synopGMAC_set_rx_qptr(synopGMACdevice * gmacdev, u32 Buffer1, u32 Length1, u32 Data1, u32 Buffer2, u32 Length2, u32 Data2) ++{ ++ u32 rxnext = gmacdev->RxNext; ++ DmaDesc * rxdesc = gmacdev->RxNextDesc; ++ ++ if(!synopGMAC_is_desc_empty(rxdesc)) ++ return -1; ++ ++ ++ if(synopGMAC_is_rx_desc_chained(rxdesc)){ ++ rxdesc->length |= ((Length1 <buffer1 = Buffer1; ++ rxdesc->data1 = Data1; ++ ++ rxdesc->extstatus = 0; ++ rxdesc->reserved1 = 0; ++ rxdesc->timestamplow = 0; ++ rxdesc->timestamphigh = 0; ++ ++ if((rxnext % MODULO_INTERRUPT) !=0) ++ rxdesc->length |= RxDisIntCompl; ++ ++ rxdesc->status = DescOwnByDma; ++ ++ gmacdev->RxNext = synopGMAC_is_last_rx_desc(gmacdev,rxdesc) ? 0 : rxnext + 1; ++ gmacdev->RxNextDesc = (DmaDesc *)rxdesc->data2; ++ } ++ else{ ++ rxdesc->length |= (((Length1 <buffer1 = Buffer1; ++ rxdesc->data1 = Data1; ++ ++ rxdesc->extstatus = 0; ++ rxdesc->reserved1 = 0; ++ rxdesc->timestamplow = 0; ++ rxdesc->timestamphigh = 0; ++ ++ rxdesc->buffer2 = Buffer2; ++ rxdesc->data2 = Data2; ++ ++ if((rxnext % MODULO_INTERRUPT) !=0) ++ rxdesc->length |= RxDisIntCompl; ++ ++ rxdesc->status = DescOwnByDma; ++ ++ gmacdev->RxNext = synopGMAC_is_last_rx_desc(gmacdev,rxdesc) ? 0 : rxnext + 1; ++ gmacdev->RxNextDesc = synopGMAC_is_last_rx_desc(gmacdev,rxdesc) ? gmacdev->RxDesc : (rxdesc + 1); ++ } ++ TR("%02d %08x %08x %08x %08x %08x %08x %08x\n",rxnext,(u32)rxdesc,rxdesc->status,rxdesc->length,rxdesc->buffer1,rxdesc->buffer2,rxdesc->data1,rxdesc->data2); ++ ++ (gmacdev->BusyRxDesc)++; //One descriptor will be given to Hardware. So busy count incremented by one ++ return rxnext; ++} ++ ++#else ++/** ++ * Prepares the descriptor to receive packets. ++ * The descriptor is allocated with the valid buffer addresses (sk_buff address) and the length fields ++ * and handed over to DMA by setting the ownership. After successful return from this function the ++ * descriptor is added to the receive descriptor pool/queue. ++ * This api is same for both ring mode and chain mode. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] Dma-able buffer1 pointer. ++ * @param[in] length of buffer1 (Max is 2048). ++ * @param[in] Dma-able buffer2 pointer. ++ * @param[in] length of buffer2 (Max is 2048). ++ * @param[in] u32 data indicating whether the descriptor is in ring mode or chain mode. ++ * \return returns present rx descriptor index on success. Negative value if error. ++ */ ++s32 synopGMAC_set_rx_qptr(synopGMACdevice * gmacdev, u32 Buffer1, u32 Length1, u32 Data1, u32 Buffer2, u32 Length2, u32 Data2) ++{ ++ u32 rxnext = gmacdev->RxNext; ++ DmaDesc * rxdesc = gmacdev->RxNextDesc; ++ ++ if(!synopGMAC_is_desc_empty(rxdesc)) ++ return -1; ++ ++ if(synopGMAC_is_rx_desc_chained(rxdesc)){ ++ rxdesc->length |= ((Length1 <buffer1 = Buffer1; ++ rxdesc->data1 = Data1; ++ ++ if((rxnext % MODULO_INTERRUPT) !=0) ++ rxdesc->length |= RxDisIntCompl; ++ ++ rxdesc->status = DescOwnByDma; ++ ++ gmacdev->RxNext = synopGMAC_is_last_rx_desc(gmacdev,rxdesc) ? 0 : rxnext + 1; ++ gmacdev->RxNextDesc = (DmaDesc *)rxdesc->data2; ++ } ++ else{ ++ rxdesc->length |= (((Length1 <buffer1 = Buffer1; ++ rxdesc->data1 = Data1; ++ ++ rxdesc->buffer2 = Buffer2; ++ rxdesc->data2 = Data2; ++ ++ if((rxnext % MODULO_INTERRUPT) !=0) ++ rxdesc->length |= RxDisIntCompl; ++ ++ rxdesc->status = DescOwnByDma; ++ ++ gmacdev->RxNext = synopGMAC_is_last_rx_desc(gmacdev,rxdesc) ? 0 : rxnext + 1; ++ gmacdev->RxNextDesc = synopGMAC_is_last_rx_desc(gmacdev,rxdesc) ? gmacdev->RxDesc : (rxdesc + 1); ++ } ++ TR("%s: %02d %08x %08x %08x %08x %08x %08x %08x\n", ++ __func__, rxnext,(u32)rxdesc,rxdesc->status,rxdesc->length,rxdesc->buffer1,rxdesc->buffer2,rxdesc->data1,rxdesc->data2); ++ (gmacdev->BusyRxDesc)++; //One descriptor will be given to Hardware. So busy count incremented by one ++ return rxnext; ++} ++ ++#endif ++#ifdef ENH_DESC_8W ++/** ++ * This function is defined two times. Once when the code is compiled for ENHANCED DESCRIPTOR SUPPORT and Once for Normal descriptor ++ * Get back the descriptor from DMA after data has been received. ++ * When the DMA indicates that the data is received (interrupt is generated), this function should be ++ * called to get the descriptor and hence the data buffers received. With successful return from this ++ * function caller gets the descriptor fields for processing. check the parameters to understand the ++ * fields returned.` ++ * @param[in] pointer to synopGMACdevice. ++ * @param[out] pointer to hold the status of DMA. ++ * @param[out] Dma-able buffer1 pointer. ++ * @param[out] pointer to hold length of buffer1 (Max is 2048). ++ * @param[out] virtual pointer for buffer1. ++ * @param[out] Dma-able buffer2 pointer. ++ * @param[out] pointer to hold length of buffer2 (Max is 2048). ++ * @param[out] virtual pointer for buffer2. ++ * \return returns present rx descriptor index on success. Negative value if error. ++ */ ++s32 synopGMAC_get_rx_qptr(synopGMACdevice * gmacdev, u32 * Status, u32 * Buffer1, u32 * Length1, u32 * Data1, u32 * Buffer2, u32 * Length2, u32 * Data2, ++ u32 * Ext_Status, u32 * Time_Stamp_High, u32 * Time_Stamp_Low) ++{ ++ u32 rxnext = gmacdev->RxBusy; // index of descriptor the DMA just completed. May be useful when data ++ //is spread over multiple buffers/descriptors ++ DmaDesc * rxdesc = gmacdev->RxBusyDesc; ++ if(synopGMAC_is_desc_owned_by_dma(rxdesc)) ++ return -1; ++ if(synopGMAC_is_desc_empty(rxdesc)) ++ return -1; ++ ++ ++ if(Status != 0) ++ *Status = rxdesc->status;// send the status of this descriptor ++ ++ if(Ext_Status != 0) ++ *Ext_Status = rxdesc->extstatus; ++ if(Time_Stamp_High != 0) ++ *Time_Stamp_High = rxdesc->timestamphigh; ++ if(Time_Stamp_Low != 0) ++ *Time_Stamp_Low = rxdesc->timestamplow; ++ ++ if(Length1 != 0) ++ *Length1 = (rxdesc->length & DescSize1Mask) >> DescSize1Shift; ++ if(Buffer1 != 0) ++ *Buffer1 = rxdesc->buffer1; ++ if(Data1 != 0) ++ *Data1 = rxdesc->data1; ++ ++ if(Length2 != 0) ++ *Length2 = (rxdesc->length & DescSize2Mask) >> DescSize2Shift; ++ if(Buffer2 != 0) ++ *Buffer2 = rxdesc->buffer2; ++ if(Data1 != 0) ++ *Data2 = rxdesc->data2; ++ ++ gmacdev->RxBusy = synopGMAC_is_last_rx_desc(gmacdev,rxdesc) ? 0 : rxnext + 1; ++ ++ if(synopGMAC_is_rx_desc_chained(rxdesc)){ ++ gmacdev->RxBusyDesc = (DmaDesc *)rxdesc->data2; ++ synopGMAC_rx_desc_init_chain(rxdesc); ++ //synopGMAC_desc_init_chain(rxdesc, synopGMAC_is_last_rx_desc(gmacdev,rxdesc),0,0); ++ } ++ else{ ++ gmacdev->RxBusyDesc = synopGMAC_is_last_rx_desc(gmacdev,rxdesc) ? gmacdev->RxDesc : (rxdesc + 1); ++ synopGMAC_rx_desc_init_ring(rxdesc, synopGMAC_is_last_rx_desc(gmacdev,rxdesc)); ++ } ++ TR("%02d %08x %08x %08x %08x %08x %08x %08x\n",rxnext,(u32)rxdesc,rxdesc->status,rxdesc->length,rxdesc->buffer1,rxdesc->buffer2,rxdesc->data1,rxdesc->data2); ++ (gmacdev->BusyRxDesc)--; //busy tx descriptor is reduced by one as it will be handed over to Processor now ++ return(rxnext); ++ ++} ++#else ++ ++/** ++ * Get back the descriptor from DMA after data has been received. ++ * When the DMA indicates that the data is received (interrupt is generated), this function should be ++ * called to get the descriptor and hence the data buffers received. With successful return from this ++ * function caller gets the descriptor fields for processing. check the parameters to understand the ++ * fields returned.` ++ * @param[in] pointer to synopGMACdevice. ++ * @param[out] pointer to hold the status of DMA. ++ * @param[out] Dma-able buffer1 pointer. ++ * @param[out] pointer to hold length of buffer1 (Max is 2048). ++ * @param[out] virtual pointer for buffer1. ++ * @param[out] Dma-able buffer2 pointer. ++ * @param[out] pointer to hold length of buffer2 (Max is 2048). ++ * @param[out] virtual pointer for buffer2. ++ * \return returns present rx descriptor index on success. Negative value if error. ++ */ ++s32 synopGMAC_get_rx_qptr(synopGMACdevice * gmacdev, u32 * Status, u32 * Buffer1, u32 * Length1, u32 * Data1, u32 * Buffer2, u32 * Length2, u32 * Data2) ++{ ++ u32 rxnext = gmacdev->RxBusy; // index of descriptor the DMA just completed. May be useful when data ++ //is spread over multiple buffers/descriptors ++ DmaDesc * rxdesc = gmacdev->RxBusyDesc; ++ if(synopGMAC_is_desc_owned_by_dma(rxdesc)) ++ return -1; ++ if(synopGMAC_is_desc_empty(rxdesc)) ++ return -1; ++ ++ ++ if(Status != 0) ++ *Status = rxdesc->status;// send the status of this descriptor ++ ++ if(Length1 != 0) ++ *Length1 = (rxdesc->length & DescSize1Mask) >> DescSize1Shift; ++ if(Buffer1 != 0) ++ *Buffer1 = rxdesc->buffer1; ++ if(Data1 != 0) ++ *Data1 = rxdesc->data1; ++ ++ if(Length2 != 0) ++ *Length2 = (rxdesc->length & DescSize2Mask) >> DescSize2Shift; ++ if(Buffer2 != 0) ++ *Buffer2 = rxdesc->buffer2; ++ if(Data1 != 0) ++ *Data2 = rxdesc->data2; ++ ++ gmacdev->RxBusy = synopGMAC_is_last_rx_desc(gmacdev,rxdesc) ? 0 : rxnext + 1; ++ ++ if(synopGMAC_is_rx_desc_chained(rxdesc)){ ++ gmacdev->RxBusyDesc = (DmaDesc *)rxdesc->data2; ++ synopGMAC_rx_desc_init_chain(rxdesc); ++ //synopGMAC_desc_init_chain(rxdesc, synopGMAC_is_last_rx_desc(gmacdev,rxdesc),0,0); ++ } ++ else{ ++ gmacdev->RxBusyDesc = synopGMAC_is_last_rx_desc(gmacdev,rxdesc) ? gmacdev->RxDesc : (rxdesc + 1); ++ synopGMAC_rx_desc_init_ring(rxdesc, synopGMAC_is_last_rx_desc(gmacdev,rxdesc)); ++ } ++ TR("%02d %08x %08x %08x %08x %08x %08x %08x\n",rxnext,(u32)rxdesc,rxdesc->status,rxdesc->length,rxdesc->buffer1,rxdesc->buffer2,rxdesc->data1,rxdesc->data2); ++ (gmacdev->BusyRxDesc)--; //This returns one descriptor to processor. So busy count will be decremented by one ++ ++ return(rxnext); ++ ++} ++ ++#endif ++ ++/** ++ * Clears all the pending interrupts. ++ * If the Dma status register is read then all the interrupts gets cleared ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_clear_interrupt(synopGMACdevice *gmacdev) ++{ ++ u32 data; ++ data = synopGMACReadReg((u32 *)gmacdev->DmaBase, DmaStatus); ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaStatus ,data); ++} ++ ++/** ++ * Returns the all unmasked interrupt status after reading the DmaStatus register. ++ * @param[in] pointer to synopGMACdevice. ++ * \return 0 upon success. Error code upon failure. ++ */ ++u32 synopGMAC_get_interrupt_type(synopGMACdevice *gmacdev) ++{ ++ u32 data; ++ u32 interrupts = 0; ++ data = synopGMACReadReg((u32 *)gmacdev->DmaBase, DmaStatus); ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaStatus ,data); //This is the appropriate location to clear the interrupts ++ TR("DMA status reg is %08x\n",data); ++ if(data & DmaIntErrorMask) interrupts |= synopGMACDmaError; ++ if(data & DmaIntRxNormMask) interrupts |= synopGMACDmaRxNormal; ++ if(data & DmaIntRxAbnMask) interrupts |= synopGMACDmaRxAbnormal; ++ if(data & DmaIntRxStoppedMask) interrupts |= synopGMACDmaRxStopped; ++ if(data & DmaIntTxNormMask) interrupts |= synopGMACDmaTxNormal; ++ if(data & DmaIntTxAbnMask) interrupts |= synopGMACDmaTxAbnormal; ++ if(data & DmaIntTxStoppedMask) interrupts |= synopGMACDmaTxStopped; ++#ifdef AVB_SUPPORT ++ if(data & DmaSlotCounterIntr) interrupts |= synopGMADmaSlotCounter; ++#endif ++ ++ return interrupts; ++} ++ ++/** ++ * Returns the interrupt mask. ++ * @param[in] pointer to synopGMACdevice. ++ * \return 0 upon success. Error code upon failure. ++ */ ++u32 synopGMAC_get_interrupt_mask(synopGMACdevice *gmacdev) ++{ ++ return(synopGMACReadReg((u32 *)gmacdev->DmaBase, DmaInterrupt)); ++} ++ ++/** ++ * Enable all the interrupts. ++ * Enables the DMA interrupt as specified by the bit mask. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] bit mask of interrupts to be enabled. ++ * \return returns void. ++ */ ++void synopGMAC_enable_interrupt(synopGMACdevice *gmacdev, u32 interrupts) ++{ ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaInterrupt, interrupts); ++ return; ++} ++ ++ ++/** ++ * Disable all the interrupts. ++ * Disables all DMA interrupts. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ * \note This function disabled all the interrupts, if you want to disable a particular interrupt then ++ * use synopGMAC_disable_interrupt(). ++ */ ++void synopGMAC_disable_interrupt_all(synopGMACdevice *gmacdev) ++{ ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaInterrupt, DmaIntDisable); ++ return; ++} ++ ++/** ++ * Disable interrupt according to the bitfield supplied. ++ * Disables only those interrupts specified in the bit mask in second argument. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] bit mask for interrupts to be disabled. ++ * \return returns void. ++ */ ++void synopGMAC_disable_interrupt(synopGMACdevice *gmacdev, u32 interrupts) ++{ ++ synopGMACClearBits((u32 *)gmacdev->DmaBase, DmaInterrupt, interrupts); ++ return; ++} ++/** ++ * Enable the DMA Reception. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_enable_dma_rx(synopGMACdevice * gmacdev) ++{ ++ // synopGMACSetBits((u32 *)gmacdev->DmaBase, DmaControl, DmaRxStart); ++ u32 data; ++ data = synopGMACReadReg((u32 *)gmacdev->DmaBase, DmaControl); ++ data |= DmaRxStart; ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaControl ,data); ++ ++} ++ ++/** ++ * Enable the DMA Transmission. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_enable_dma_tx(synopGMACdevice * gmacdev) ++{ ++ // synopGMACSetBits((u32 *)gmacdev->DmaBase, DmaControl, DmaTxStart); ++ u32 data; ++ data = synopGMACReadReg((u32 *)gmacdev->DmaBase, DmaControl); ++ data |= DmaTxStart; ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaControl ,data); ++ ++} ++ ++/** ++ * Resumes the DMA Transmission. ++ * the DmaTxPollDemand is written. (the data writeen could be anything). ++ * This forces the DMA to resume transmission. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_resume_dma_tx(synopGMACdevice * gmacdev) ++{ ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaTxPollDemand, 0); ++ ++} ++/** ++ * Resumes the DMA Reception. ++ * the DmaRxPollDemand is written. (the data writeen could be anything). ++ * This forces the DMA to resume reception. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_resume_dma_rx(synopGMACdevice * gmacdev) ++{ ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaRxPollDemand, 0); ++ ++} ++/** ++ * Take ownership of this Descriptor. ++ * The function is same for both the ring mode and the chain mode DMA structures. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_take_desc_ownership(DmaDesc * desc) ++{ ++ if(desc){ ++ desc->status &= ~DescOwnByDma; //Clear the DMA own bit ++ // desc->status |= DescError; // Set the error to indicate this descriptor is bad ++ } ++} ++ ++/** ++ * Take ownership of all the rx Descriptors. ++ * This function is called when there is fatal error in DMA transmission. ++ * When called it takes the ownership of all the rx descriptor in rx descriptor pool/queue from DMA. ++ * The function is same for both the ring mode and the chain mode DMA structures. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ * \note Make sure to disable the transmission before calling this function, otherwise may result in racing situation. ++ */ ++void synopGMAC_take_desc_ownership_rx(synopGMACdevice * gmacdev) ++{ ++ s32 i; ++ DmaDesc *desc; ++ desc = gmacdev->RxDesc; ++ for(i = 0; i < gmacdev->RxDescCount; i++){ ++ if(synopGMAC_is_rx_desc_chained(desc)){ //This descriptor is in chain mode ++ ++ synopGMAC_take_desc_ownership(desc); ++ desc = (DmaDesc *)desc->data2; ++ } ++ else{ ++ synopGMAC_take_desc_ownership(desc + i); ++ } ++ } ++} ++ ++/** ++ * Take ownership of all the rx Descriptors. ++ * This function is called when there is fatal error in DMA transmission. ++ * When called it takes the ownership of all the tx descriptor in tx descriptor pool/queue from DMA. ++ * The function is same for both the ring mode and the chain mode DMA structures. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ * \note Make sure to disable the transmission before calling this function, otherwise may result in racing situation. ++ */ ++void synopGMAC_take_desc_ownership_tx(synopGMACdevice * gmacdev) ++{ ++ s32 i; ++ DmaDesc *desc; ++ desc = gmacdev->TxDesc; ++ for(i = 0; i < gmacdev->TxDescCount; i++){ ++ if(synopGMAC_is_tx_desc_chained(desc)){ //This descriptor is in chain mode ++ synopGMAC_take_desc_ownership(desc); ++ desc = (DmaDesc *)desc->data2; ++ } ++ else{ ++ synopGMAC_take_desc_ownership(desc + i); ++ } ++ } ++ ++} ++ ++/** ++ * Disable the DMA for Transmission. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++ ++void synopGMAC_disable_dma_tx(synopGMACdevice * gmacdev) ++{ ++ // synopGMACClearBits((u32 *)gmacdev->DmaBase, DmaControl, DmaTxStart); ++ u32 data; ++ data = synopGMACReadReg((u32 *)gmacdev->DmaBase, DmaControl); ++ data &= (~DmaTxStart); ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaControl ,data); ++} ++/** ++ * Disable the DMA for Reception. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_disable_dma_rx(synopGMACdevice * gmacdev) ++{ ++ // synopGMACClearBits((u32 *)gmacdev->DmaBase, DmaControl, DmaRxStart); ++ u32 data; ++ data = synopGMACReadReg((u32 *)gmacdev->DmaBase, DmaControl); ++ data &= (~DmaRxStart); ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaControl ,data); ++} ++ ++ ++ ++/*******************PMT APIs***************************************/ ++ ++ ++ ++ ++/** ++ * Enables the assertion of PMT interrupt. ++ * This enables the assertion of PMT interrupt due to Magic Pkt or Wakeup frame ++ * reception. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_pmt_int_enable(synopGMACdevice *gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacInterruptMask,GmacPmtIntMask); ++ return; ++} ++/** ++ * Disables the assertion of PMT interrupt. ++ * This disables the assertion of PMT interrupt due to Magic Pkt or Wakeup frame ++ * reception. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_pmt_int_disable(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacInterruptMask,GmacPmtIntMask); ++ return; ++} ++/** ++ * Enables the power down mode of GMAC. ++ * This function puts the Gmac in power down mode. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_power_down_enable(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacPmtCtrlStatus,GmacPmtPowerDown); ++ return; ++} ++/** ++ * Disables the powerd down setting of GMAC. ++ * If the driver wants to bring up the GMAC from powerdown mode, even though the magic packet or the ++ * wake up frames received from the network, this function should be called. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_power_down_disable(synopGMACdevice *gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacPmtCtrlStatus,GmacPmtPowerDown); ++ return; ++} ++/** ++ * Enables the pmt interrupt generation in powerdown mode. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_enable_pmt_interrupt(synopGMACdevice *gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacInterruptMask,GmacPmtIntMask); ++} ++/** ++ * Disables the pmt interrupt generation in powerdown mode. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_disable_pmt_interrupt(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacInterruptMask,GmacPmtIntMask); ++} ++/** ++ * Enables GMAC to look for Magic packet. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_magic_packet_enable(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacPmtCtrlStatus,GmacPmtMagicPktEnable); ++ return; ++} ++ ++/** ++ * Enables GMAC to look for wake up frame. ++ * Wake up frame is defined by the user. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_wakeup_frame_enable(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacPmtCtrlStatus,GmacPmtWakeupFrameEnable); ++ return; ++} ++ ++/** ++ * Enables wake-up frame filter to handle unicast packets. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_pmt_unicast_enable(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacPmtCtrlStatus,GmacPmtGlobalUnicast); ++ return; ++} ++/** ++ * Checks whether the packet received is a magic packet?. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns True if magic packet received else returns false. ++ */ ++bool synopGMAC_is_magic_packet_received(synopGMACdevice *gmacdev) ++{ ++ u32 data; ++ data = synopGMACReadReg((u32 *)gmacdev->MacBase,GmacPmtCtrlStatus); ++ return((data & GmacPmtMagicPktReceived) == GmacPmtMagicPktReceived); ++} ++/** ++ * Checks whether the packet received is a wakeup frame?. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns true if wakeup frame received else returns false. ++ */ ++bool synopGMAC_is_wakeup_frame_received(synopGMACdevice *gmacdev) ++{ ++ u32 data; ++ data = synopGMACReadReg((u32 *)gmacdev->MacBase,GmacPmtCtrlStatus); ++ return((data & GmacPmtWakeupFrameReceived) == GmacPmtWakeupFrameReceived); ++} ++ ++/** ++ * Populates the remote wakeup frame registers. ++ * Consecutive 8 writes to GmacWakeupAddr writes the wakeup frame filter registers. ++ * Before commensing a new write, frame filter pointer is reset to 0x0000. ++ * A small delay is introduced to allow frame filter pointer reset operation. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] pointer to frame filter contents array. ++ * \return returns void. ++ */ ++void synopGMAC_write_wakeup_frame_register(synopGMACdevice *gmacdev, u32 * filter_contents) ++{ ++ s32 i; ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacPmtCtrlStatus,GmacPmtFrmFilterPtrReset); ++ plat_delay(10); ++ for(i =0; iMacBase, GmacWakeupAddr, *(filter_contents + i)); ++ return; ++ ++} ++/*******************PMT APIs***************************************/ ++/*******************MMC APIs***************************************/ ++ ++/** ++ * Freezes the MMC counters. ++ * This function call freezes the MMC counters. None of the MMC counters are updated ++ * due to any tx or rx frames until synopGMAC_mmc_counters_resume is called. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_mmc_counters_stop(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacMmcCntrl,GmacMmcCounterFreeze); ++ return; ++} ++/** ++ * Resumes the MMC counter updation. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_mmc_counters_resume(synopGMACdevice *gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacMmcCntrl,GmacMmcCounterFreeze); ++ return; ++} ++/** ++ * Configures the MMC in Self clearing mode. ++ * Programs MMC interface so that counters are cleared when the counters are read. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_mmc_counters_set_selfclear(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacMmcCntrl,GmacMmcCounterResetOnRead); ++ return; ++} ++/** ++ * Configures the MMC in non-Self clearing mode. ++ * Programs MMC interface so that counters are cleared when the counters are read. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_mmc_counters_reset_selfclear(synopGMACdevice *gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacMmcCntrl,GmacMmcCounterResetOnRead); ++ return; ++} ++/** ++ * Configures the MMC to stop rollover. ++ * Programs MMC interface so that counters will not rollover after reaching maximum value. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_mmc_counters_disable_rollover(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacMmcCntrl,GmacMmcCounterStopRollover); ++ return; ++} ++/** ++ * Configures the MMC to rollover. ++ * Programs MMC interface so that counters will rollover after reaching maximum value. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_mmc_counters_enable_rollover(synopGMACdevice *gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacMmcCntrl,GmacMmcCounterStopRollover); ++ return; ++} ++ ++/** ++ * Read the MMC Counter. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] the counter to be read. ++ * \return returns the read count value. ++ */ ++u32 synopGMAC_read_mmc_counter(synopGMACdevice *gmacdev, u32 counter) ++{ ++ return( synopGMACReadReg((u32 *)gmacdev->MacBase,counter)); ++} ++/** ++ * Read the MMC Rx interrupt status. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns the Rx interrupt status. ++ */ ++u32 synopGMAC_read_mmc_rx_int_status(synopGMACdevice *gmacdev) ++{ ++ return( synopGMACReadReg((u32 *)gmacdev->MacBase,GmacMmcIntrRx)); ++} ++/** ++ * Read the MMC Tx interrupt status. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns the Tx interrupt status. ++ */ ++u32 synopGMAC_read_mmc_tx_int_status(synopGMACdevice *gmacdev) ++{ ++ return( synopGMACReadReg((u32 *)gmacdev->MacBase,GmacMmcIntrTx)); ++} ++/** ++ * Disable the MMC Tx interrupt. ++ * The MMC tx interrupts are masked out as per the mask specified. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] tx interrupt bit mask for which interrupts needs to be disabled. ++ * \return returns void. ++ */ ++void synopGMAC_disable_mmc_tx_interrupt(synopGMACdevice *gmacdev, u32 mask) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacMmcIntrMaskTx,mask); ++ return; ++} ++/** ++ * Enable the MMC Tx interrupt. ++ * The MMC tx interrupts are enabled as per the mask specified. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] tx interrupt bit mask for which interrupts needs to be enabled. ++ * \return returns void. ++ */ ++void synopGMAC_enable_mmc_tx_interrupt(synopGMACdevice *gmacdev, u32 mask) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacMmcIntrMaskTx,mask); ++} ++/** ++ * Disable the MMC Rx interrupt. ++ * The MMC rx interrupts are masked out as per the mask specified. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] rx interrupt bit mask for which interrupts needs to be disabled. ++ * \return returns void. ++ */ ++void synopGMAC_disable_mmc_rx_interrupt(synopGMACdevice *gmacdev, u32 mask) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacMmcIntrMaskRx,mask); ++ return; ++} ++/** ++ * Enable the MMC Rx interrupt. ++ * The MMC rx interrupts are enabled as per the mask specified. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] rx interrupt bit mask for which interrupts needs to be enabled. ++ * \return returns void. ++ */ ++void synopGMAC_enable_mmc_rx_interrupt(synopGMACdevice *gmacdev, u32 mask) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacMmcIntrMaskRx,mask); ++ return; ++} ++/** ++ * Disable the MMC ipc rx checksum offload interrupt. ++ * The MMC ipc rx checksum offload interrupts are masked out as per the mask specified. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] rx interrupt bit mask for which interrupts needs to be disabled. ++ * \return returns void. ++ */ ++void synopGMAC_disable_mmc_ipc_rx_interrupt(synopGMACdevice *gmacdev, u32 mask) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacMmcRxIpcIntrMask,mask); ++ return; ++} ++/** ++ * Enable the MMC ipc rx checksum offload interrupt. ++ * The MMC ipc rx checksum offload interrupts are enabled as per the mask specified. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] rx interrupt bit mask for which interrupts needs to be enabled. ++ * \return returns void. ++ */ ++void synopGMAC_enable_mmc_ipc_rx_interrupt(synopGMACdevice *gmacdev, u32 mask) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacMmcRxIpcIntrMask,mask); ++ return; ++} ++/*******************MMC APIs***************************************/ ++/*******************Ip checksum offloading APIs***************************************/ ++ ++/** ++ * Enables the ip checksum offloading in receive path. ++ * When set GMAC calculates 16 bit 1's complement of all received ethernet frame payload. ++ * It also checks IPv4 Header checksum is correct. GMAC core appends the 16 bit checksum calculated ++ * for payload of IP datagram and appends it to Ethernet frame transferred to the application. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_enable_rx_chksum_offload(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacConfig,GmacRxIpcOffload); ++ return; ++} ++/** ++ * Disable the ip checksum offloading in receive path. ++ * Ip checksum offloading is disabled in the receive path. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_disable_rx_Ipchecksum_offload(synopGMACdevice *gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacConfig,GmacRxIpcOffload); ++} ++/** ++ * Instruct the DMA to drop the packets fails tcp ip checksum. ++ * This is to instruct the receive DMA engine to drop the recevied packet if they ++ * fails the tcp/ip checksum in hardware. Valid only when full checksum offloading is enabled(type-2). ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_rx_tcpip_chksum_drop_enable(synopGMACdevice *gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->DmaBase,DmaControl,DmaDisableDropTcpCs); ++ return; ++} ++/** ++ * Instruct the DMA not to drop the packets even if it fails tcp ip checksum. ++ * This is to instruct the receive DMA engine to allow the packets even if recevied packet ++ * fails the tcp/ip checksum in hardware. Valid only when full checksum offloading is enabled(type-2). ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_rx_tcpip_chksum_drop_disable(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->DmaBase,DmaControl,DmaDisableDropTcpCs); ++ return; ++} ++ ++/** ++ * When the Enhanced Descriptor is enabled then the bit 0 of RDES0 indicates whether the ++ * Extended Status is available (RDES4). Time Stamp feature and the Checksum Offload Engine2 ++ * makes use of this extended status to provide the status of the received packet. ++ * @param[in] pointer to synopGMACdevice ++ * \return returns TRUE or FALSE ++ */ ++#ifdef ENH_DESC_8W ++ ++/** ++ * This function indicates whether extended status is available in the RDES0. ++ * Any function which accesses the fields of extended status register must ensure a check on this has been made ++ * This is valid only for Enhanced Descriptor. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] u32 status field of the corresponding descriptor. ++ * \return returns TRUE or FALSE. ++ */ ++bool synopGMAC_is_ext_status(synopGMACdevice *gmacdev,u32 status) // extended status present indicates that the RDES4 need to be probed ++{ ++ return((status & DescRxEXTsts ) != 0 ); // if extstatus set then it returns 1 ++} ++/** ++ * This function returns true if the IP header checksum bit is set in the extended status. ++ * Valid only when enhaced status available is set in RDES0 bit 0. ++ * This is valid only for Enhanced Descriptor. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] u32 status field of the corresponding descriptor. ++ * \return returns TRUE or FALSE. ++ */ ++bool synopGMAC_ES_is_IP_header_error(synopGMACdevice *gmacdev,u32 ext_status) // IP header (IPV4) checksum error ++{ ++ return((ext_status & DescRxIpHeaderError) != 0 ); // if IPV4 header error return 1 ++} ++/** ++ * This function returns true if the Checksum is bypassed in the hardware. ++ * Valid only when enhaced status available is set in RDES0 bit 0. ++ * This is valid only for Enhanced Descriptor. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] u32 status field of the corresponding descriptor. ++ * \return returns TRUE or FALSE. ++ */ ++bool synopGMAC_ES_is_rx_checksum_bypassed(synopGMACdevice *gmacdev,u32 ext_status) // Hardware engine bypassed the checksum computation/checking ++{ ++ return((ext_status & DescRxChkSumBypass ) != 0 ); // if checksum offloading bypassed return 1 ++} ++/** ++ * This function returns true if payload checksum error is set in the extended status. ++ * Valid only when enhaced status available is set in RDES0 bit 0. ++ * This is valid only for Enhanced Descriptor. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] u32 status field of the corresponding descriptor. ++ * \return returns TRUE or FALSE. ++ */ ++bool synopGMAC_ES_is_IP_payload_error(synopGMACdevice *gmacdev,u32 ext_status) // IP payload checksum is in error (UDP/TCP/ICMP checksum error) ++{ ++ return((ext_status & DescRxIpPayloadError) != 0 ); // if IP payload error return 1 ++} ++#endif ++ ++ ++ ++/** ++ * Decodes the Rx Descriptor status to various checksum error conditions. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] u32 status field of the corresponding descriptor. ++ * \return returns decoded enum (u32) indicating the status. ++ */ ++u32 synopGMAC_is_rx_checksum_error(synopGMACdevice *gmacdev, u32 status) ++{ ++ if (((status & DescRxChkBit5) == 0) && ((status & DescRxChkBit7) == 0) && ((status & DescRxChkBit0) == 0)) ++ return RxLenLT600; ++ else if(((status & DescRxChkBit5) == 0) && ((status & DescRxChkBit7) == 0) && ((status & DescRxChkBit0) != 0)) ++ return RxIpHdrPayLoadChkBypass; ++ else if(((status & DescRxChkBit5) == 0) && ((status & DescRxChkBit7) != 0) && ((status & DescRxChkBit0) != 0)) ++ return RxChkBypass; ++ else if(((status & DescRxChkBit5) != 0) && ((status & DescRxChkBit7) == 0) && ((status & DescRxChkBit0) == 0)) ++ return RxNoChkError; ++ else if(((status & DescRxChkBit5) != 0) && ((status & DescRxChkBit7) == 0) && ((status & DescRxChkBit0) != 0)) ++ return RxPayLoadChkError; ++ else if(((status & DescRxChkBit5) != 0) && ((status & DescRxChkBit7) != 0) && ((status & DescRxChkBit0) == 0)) ++ return RxIpHdrChkError; ++ else if(((status & DescRxChkBit5) != 0) && ((status & DescRxChkBit7) != 0) && ((status & DescRxChkBit0) != 0)) ++ return RxIpHdrPayLoadChkError; ++ else ++ return RxIpHdrPayLoadRes; ++} ++/** ++ * Checks if any Ipv4 header checksum error in the frame just transmitted. ++ * This serves as indication that error occureed in the IPv4 header checksum insertion. ++ * The sent out frame doesnot carry any ipv4 header checksum inserted by the hardware. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] u32 status field of the corresponding descriptor. ++ * \return returns true if error in ipv4 header checksum, else returns false. ++ */ ++bool synopGMAC_is_tx_ipv4header_checksum_error(synopGMACdevice *gmacdev, u32 status) ++{ ++ return((status & DescTxIpv4ChkError) == DescTxIpv4ChkError); ++} ++ ++ ++/** ++ * Checks if any payload checksum error in the frame just transmitted. ++ * This serves as indication that error occureed in the payload checksum insertion. ++ * The sent out frame doesnot carry any payload checksum inserted by the hardware. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] u32 status field of the corresponding descriptor. ++ * \return returns true if error in ipv4 header checksum, else returns false. ++ */ ++bool synopGMAC_is_tx_payload_checksum_error(synopGMACdevice *gmacdev, u32 status) ++{ ++ return((status & DescTxPayChkError) == DescTxPayChkError); ++} ++/** ++ * The check summ offload engine is bypassed in the tx path. ++ * Checksum is not computed in the Hardware. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] Pointer to tx descriptor for which ointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_tx_checksum_offload_bypass(synopGMACdevice *gmacdev, DmaDesc *desc) ++{ ++#ifdef ENH_DESC ++ desc->status = (desc->length & (~DescTxCisMask));//ENH_DESC ++#else ++ desc->length = (desc->length & (~DescTxCisMask)); ++#endif ++ ++} ++/** ++ * The check summ offload engine is enabled to do only IPV4 header checksum. ++ * IPV4 header Checksum is computed in the Hardware. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] Pointer to tx descriptor for which ointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_tx_checksum_offload_ipv4hdr(synopGMACdevice *gmacdev, DmaDesc *desc) ++{ ++#ifdef ENH_DESC ++ desc->status = ((desc->status & (~DescTxCisMask)) | DescTxCisIpv4HdrCs);//ENH_DESC ++#else ++ desc->length = ((desc->length & (~DescTxCisMask)) | DescTxCisIpv4HdrCs); ++#endif ++ ++} ++ ++/** ++ * The check summ offload engine is enabled to do TCPIP checsum assuming Pseudo header is available. ++ * Hardware computes the tcp ip checksum assuming pseudo header checksum is computed in software. ++ * Ipv4 header checksum is also inserted. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] Pointer to tx descriptor for which ointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_tx_checksum_offload_tcponly(synopGMACdevice *gmacdev, DmaDesc *desc) ++{ ++#ifdef ENH_DESC ++ desc->status = ((desc->status & (~DescTxCisMask)) | DescTxCisTcpOnlyCs);//ENH_DESC ++#else ++ desc->length = ((desc->length & (~DescTxCisMask)) | DescTxCisTcpOnlyCs); ++#endif ++ ++} ++/** ++ * The check summ offload engine is enabled to do complete checksum computation. ++ * Hardware computes the tcp ip checksum including the pseudo header checksum. ++ * Here the tcp payload checksum field should be set to 0000. ++ * Ipv4 header checksum is also inserted. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] Pointer to tx descriptor for which ointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_tx_checksum_offload_tcp_pseudo(synopGMACdevice *gmacdev, DmaDesc *desc) ++{ ++#ifdef ENH_DESC ++ desc->status = ((desc->length & (~DescTxCisMask)) | DescTxCisTcpPseudoCs); ++#else ++ desc->length = ((desc->length & (~DescTxCisMask)) | DescTxCisTcpPseudoCs); ++#endif ++ ++} ++/*******************Ip checksum offloading APIs***************************************/ ++ ++ ++ ++ ++ ++/*******************IEEE 1588 Timestamping API***************************************/ ++ ++ ++/* ++ * At this time the driver supports the IEEE time stamping feature when the Enhanced Descriptors are enabled. ++ * For normal descriptor and the IEEE time stamp (version 1), driver support is not proviced ++ * Please make sure you have enabled the Advanced timestamp feature in the hardware and the driver should ++ * be compiled with the ADV_TME_STAMP feature. ++ * Some of the APIs provided here may not be valid for all configurations. Please make sure you call the ++ * API with due care. ++ */ ++ ++/** ++ * This function enables the timestamping. This enables the timestamping for transmit and receive frames. ++ * When disabled timestamp is not added to tx and receive frames and timestamp generator is suspended. ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_enable(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSENA); ++ return; ++} ++/** ++ * This function disables the timestamping. ++ * When disabled timestamp is not added to tx and receive frames and timestamp generator is suspended. ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_disable(synopGMACdevice *gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacTSControl, GmacTSENA); ++ return; ++} ++ ++ ++/** ++ * Enable the interrupt to get timestamping interrupt. ++ * This enables the host to get the interrupt when (1) system time is greater or equal to the ++ * target time high and low register or (2) there is a overflow in th esecond register. ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_int_enable(synopGMACdevice *gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacInterruptMask,GmacPmtIntMask); ++ return; ++} ++ ++/** ++ * Disable the interrupt to get timestamping interrupt. ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_int_disable(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacInterruptMask,GmacPmtIntMask); ++ return; ++} ++ ++/** ++ * Enable MAC address for PTP frame filtering. ++ * When enabled, uses MAC address (apart from MAC address 0) to filter the PTP frames when ++ * PTP is sent directly over Ethernet. ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_mac_addr_filt_enable(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSENMACADDR); ++ return; ++} ++ ++/** ++ * Disables MAC address for PTP frame filtering. ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_mac_addr_filt_disable(synopGMACdevice *gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSENMACADDR); ++ return; ++} ++ ++ ++/** ++ * Selet the type of clock mode for PTP. ++ * Please note to use one of the follwoing as the clk_type argument. ++ * GmacTSOrdClk = 0x00000000, 00=> Ordinary clock ++ * GmacTSBouClk = 0x00010000, 01=> Boundary clock ++ * GmacTSEtoEClk = 0x00020000, 10=> End-to-End transparent clock ++ * GmacTSPtoPClk = 0x00030000, 11=> P-to-P transparent clock ++ * @param[in] pointer to synopGMACdevice ++ * @param[in] u32 value representing one of the above clk value ++ * \return returns void ++ */ ++void synopGMAC_TS_set_clk_type(synopGMACdevice *gmacdev, u32 clk_type) ++{ ++ u32 clkval; ++ clkval = synopGMACReadReg((u32 *)gmacdev->MacBase,GmacTSControl); //set the mdc clock to the user defined value ++ clkval = clkval | clk_type; ++ synopGMACWriteReg((u32 *)gmacdev->MacBase,GmacTSControl,clkval); ++ return; ++} ++ ++/** ++ * Enable Snapshot for messages relevant to Master. ++ * When enabled, snapshot is taken for messages relevant to master mode only, else snapshot is taken for messages relevant ++ * to slave node. ++ * Valid only for Ordinary clock and Boundary clock ++ * Reserved when "Advanced Time Stamp" is not selected ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_master_enable(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSMSTRENA); ++ return; ++} ++/** ++ * Disable Snapshot for messages relevant to Master. ++ * When disabled, snapshot is taken for messages relevant ++ * to slave node. ++ * Valid only for Ordinary clock and Boundary clock ++ * Reserved when "Advanced Time Stamp" is not selected ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_master_disable(synopGMACdevice *gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSMSTRENA); ++ return; ++} ++/** ++ * Enable Snapshot for Event messages. ++ * When enabled, snapshot is taken for event messages only (SYNC, Delay_Req, Pdelay_Req or Pdelay_Resp) ++ * When disabled, snapshot is taken for all messages except Announce, Management and Signaling. ++ * Reserved when "Advanced Time Stamp" is not selected ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_event_enable(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSEVNTENA); ++ return; ++} ++/** ++ * Disable Snapshot for Event messages. ++ * When disabled, snapshot is taken for all messages except Announce, Management and Signaling. ++ * Reserved when "Advanced Time Stamp" is not selected ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_event_disable(synopGMACdevice *gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSEVNTENA); ++ return; ++} ++ ++/** ++ * Enable time stamp snapshot for IPV4 frames. ++ * When enabled, time stamp snapshot is taken for IPV4 frames ++ * Reserved when "Advanced Time Stamp" is not selected ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_IPV4_enable(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSIPV4ENA); ++ return; ++} ++/** ++ * Disable time stamp snapshot for IPV4 frames. ++ * When disabled, time stamp snapshot is not taken for IPV4 frames ++ * Reserved when "Advanced Time Stamp" is not selected ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_IPV4_disable(synopGMACdevice *gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSIPV4ENA); ++ return; ++} // Only for "Advanced Time Stamp" ++/** ++ * Enable time stamp snapshot for IPV6 frames. ++ * When enabled, time stamp snapshot is taken for IPV6 frames ++ * Reserved when "Advanced Time Stamp" is not selected ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_IPV6_enable(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSIPV6ENA); ++ return; ++} ++/** ++ * Disable time stamp snapshot for IPV6 frames. ++ * When disabled, time stamp snapshot is not taken for IPV6 frames ++ * Reserved when "Advanced Time Stamp" is not selected ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_IPV6_disable(synopGMACdevice *gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSIPV6ENA); ++ return; ++} ++ ++/** ++ * Enable time stamp snapshot for PTP over Ethernet frames. ++ * When enabled, time stamp snapshot is taken for PTP over Ethernet frames ++ * Reserved when "Advanced Time Stamp" is not selected ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_ptp_over_ethernet_enable(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSIPENA); ++ return; ++} ++/** ++ * Disable time stamp snapshot for PTP over Ethernet frames. ++ * When disabled, time stamp snapshot is not taken for PTP over Ethernet frames ++ * Reserved when "Advanced Time Stamp" is not selected ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_ptp_over_ethernet_disable(synopGMACdevice *gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSIPENA); ++ return; ++} ++ ++ ++/** ++ * Snoop PTP packet for version 2 format ++ * When set the PTP packets are snooped using the version 2 format. ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_pkt_snoop_ver2(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSVER2ENA); ++ return; ++} ++/** ++ * Snoop PTP packet for version 2 format ++ * When set the PTP packets are snooped using the version 2 format. ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_pkt_snoop_ver1(synopGMACdevice *gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSVER2ENA); ++ return; ++} ++ ++/** ++ * Timestamp digital rollover ++ * When set the timestamp low register rolls over after 0x3B9A_C9FF value. ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_digital_rollover_enable(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSCTRLSSR); ++ return; ++} ++/** ++ * Timestamp binary rollover ++ * When set the timestamp low register rolls over after 0x7FFF_FFFF value. ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_binary_rollover_enable(synopGMACdevice *gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSCTRLSSR); ++ return; ++} ++/** ++ * Enable Time Stamp for All frames ++ * When set the timestamp snap shot is enabled for all frames received by the core. ++ * Reserved when "Advanced Time Stamp" is not selected ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_all_frames_enable(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSENALL); ++ return; ++} ++/** ++ * Disable Time Stamp for All frames ++ * When reset the timestamp snap shot is not enabled for all frames received by the core. ++ * Reserved when "Advanced Time Stamp" is not selected ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_all_frames_disable(synopGMACdevice *gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSENALL); ++ return; ++} ++/** ++ * Addend Register Update ++ * This function loads the contents of Time stamp addend register with the supplied 32 value. ++ * This is reserved function when only coarse correction option is selected ++ * @param[in] pointer to synopGMACdevice ++ * @param[in] 32 bit addend value ++ * \return returns 0 for Success or else Failure ++ */ ++s32 synopGMAC_TS_addend_update(synopGMACdevice *gmacdev, u32 addend_value) ++{ ++ u32 loop_variable; ++ synopGMACWriteReg((u32 *)gmacdev->MacBase,GmacTSAddend,addend_value);// Load the addend_value in to Addend register ++ for(loop_variable = 0; loop_variable < DEFAULT_LOOP_VARIABLE; loop_variable++){ //Wait till the busy bit gets cleared with in a certain amount of time ++ if(!((synopGMACReadReg((u32 *)gmacdev->MacBase,GmacTSControl)) & GmacTSADDREG)){ // if it is cleared then break ++ break; ++ } ++ plat_delay(DEFAULT_DELAY_VARIABLE); ++ } ++ if(loop_variable < DEFAULT_LOOP_VARIABLE) ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSADDREG); ++ else{ ++ TR("Error::: The TSADDREG bit is not getting cleared !!!!!!\n"); ++ return -ESYNOPGMACPHYERR; ++ } ++ return -ESYNOPGMACNOERR; ++ ++} ++/** ++ * time stamp Update ++ * This function updates (adds/subtracts) with the value specified in the Timestamp High Update and ++ * Timestamp Low Update register. ++ * @param[in] pointer to synopGMACdevice ++ * @param[in] Timestamp High Update value ++ * @param[in] Timestamp Low Update value ++ * \return returns 0 for Success or else Failure ++ */ ++s32 synopGMAC_TS_timestamp_update(synopGMACdevice *gmacdev, u32 high_value, u32 low_value) ++{ ++ u32 loop_variable; ++ synopGMACWriteReg((u32 *)gmacdev->MacBase,GmacTSHighUpdate,high_value);// Load the high value to Timestamp High register ++ synopGMACWriteReg((u32 *)gmacdev->MacBase,GmacTSLowUpdate,low_value);// Load the high value to Timestamp High register ++ for(loop_variable = 0; loop_variable < DEFAULT_LOOP_VARIABLE; loop_variable++){ //Wait till the busy bit gets cleared with in a certain amount of time ++ if(!((synopGMACReadReg((u32 *)gmacdev->MacBase,GmacTSControl)) & GmacTSUPDT)){ // if it is cleared then break ++ break; ++ } ++ plat_delay(DEFAULT_DELAY_VARIABLE); ++ } ++ if(loop_variable < DEFAULT_LOOP_VARIABLE) ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSUPDT); ++ else{ ++ TR("Error::: The TSADDREG bit is not getting cleared !!!!!!\n"); ++ return -ESYNOPGMACPHYERR; ++ } ++ return -ESYNOPGMACNOERR; ++} ++ ++/** ++ * time stamp Initialize ++ * This function Loads/Initializes h the value specified in the Timestamp High Update and ++ * Timestamp Low Update register. ++ * @param[in] pointer to synopGMACdevice ++ * @param[in] Timestamp High Load value ++ * @param[in] Timestamp Low Load value ++ * \return returns 0 for Success or else Failure ++ */ ++s32 synopGMAC_TS_timestamp_init(synopGMACdevice *gmacdev, u32 high_value, u32 low_value) ++{ ++ u32 loop_variable; ++ synopGMACWriteReg((u32 *)gmacdev->MacBase,GmacTSHighUpdate,high_value);// Load the high value to Timestamp High register ++ synopGMACWriteReg((u32 *)gmacdev->MacBase,GmacTSLowUpdate,low_value);// Load the high value to Timestamp High register ++ for(loop_variable = 0; loop_variable < DEFAULT_LOOP_VARIABLE; loop_variable++){ //Wait till the busy bit gets cleared with in a certain amount of time ++ if(!((synopGMACReadReg((u32 *)gmacdev->MacBase,GmacTSControl)) & GmacTSINT)){ // if it is cleared then break ++ break; ++ } ++ plat_delay(DEFAULT_DELAY_VARIABLE); ++ } ++ if(loop_variable < DEFAULT_LOOP_VARIABLE) ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSINT); ++ else{ ++ TR("Error::: The TSADDREG bit is not getting cleared !!!!!!\n"); ++ return -ESYNOPGMACPHYERR; ++ } ++ return -ESYNOPGMACNOERR; ++} ++ ++/** ++ * Time Stamp Update Coarse ++ * When reset the timestamp update is done using coarse method. ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_coarse_update(synopGMACdevice *gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSCFUPDT); ++ return; ++} ++/** ++ * Time Stamp Update Fine ++ * When reset the timestamp update is done using Fine method. ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_fine_update(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSCFUPDT); ++ return; ++} ++ ++/** ++ * Load the Sub Second Increment value in to Sub Second increment register ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_subsecond_init(synopGMACdevice *gmacdev, u32 sub_sec_inc_value) ++{ ++ synopGMACWriteReg((u32 *)gmacdev->MacBase,GmacTSSubSecIncr,(sub_sec_inc_value & GmacSSINCMsk)); ++ return; ++} ++/** ++ * Reads the time stamp contents in to the respective pointers ++ * These registers are readonly. ++ * This function returns the 48 bit time stamp assuming Version 2 timestamp with higher word is selected. ++ * @param[in] pointer to synopGMACdevice ++ * @param[in] pointer to hold 16 higher bit second register contents ++ * @param[in] pointer to hold 32 bit second register contents ++ * @param[in] pointer to hold 32 bit subnanosecond register contents ++ * \return returns void ++ * \note Please note that since the atomic access to the timestamp registers is not possible, ++ * the contents read may be different from the actual time stamp. ++ */ ++void synopGMAC_TS_read_timestamp(synopGMACdevice *gmacdev, u16 * higher_sec_val, u32 * sec_val, u32 * sub_sec_val) ++{ ++ * higher_sec_val = (u16)(synopGMACReadReg((u32 *)gmacdev->MacBase,GmacTSHighWord) & GmacTSHighWordMask); ++ * sec_val = synopGMACReadReg((u32 *)gmacdev->MacBase,GmacTSHigh); ++ * sub_sec_val = synopGMACReadReg((u32 *)gmacdev->MacBase,GmacTSLow); ++ return; ++} ++/** ++ * Loads the time stamp higher sec value from the value supplied ++ * @param[in] pointer to synopGMACdevice ++ * @param[in] 16 higher bit second register contents passed as 32 bit value ++ * \return returns void ++ */ ++void synopGMAC_TS_load_timestamp_higher_val(synopGMACdevice *gmacdev, u32 higher_sec_val) ++{ ++ synopGMACWriteReg((u32 *)gmacdev->MacBase,GmacTSHighWord, (higher_sec_val & GmacTSHighWordMask)); ++ return; ++} ++/** ++ * Reads the time stamp higher sec value to respective pointers ++ * @param[in] pointer to synopGMACdevice ++ * @param[in] pointer to hold 16 higher bit second register contents ++ * \return returns void ++ */ ++void synopGMAC_TS_read_timestamp_higher_val(synopGMACdevice *gmacdev, u16 * higher_sec_val) ++{ ++ * higher_sec_val = (u16)(synopGMACReadReg((u32 *)gmacdev->MacBase,GmacTSHighWord) & GmacTSHighWordMask); ++ return; ++} ++/** ++ * Load the Target time stamp registers ++ * This function Loads the target time stamp registers with the values proviced ++ * @param[in] pointer to synopGMACdevice ++ * @param[in] target Timestamp High value ++ * @param[in] target Timestamp Low value ++ * \return returns 0 for Success or else Failure ++ */ ++void synopGMAC_TS_load_target_timestamp(synopGMACdevice *gmacdev, u32 sec_val, u32 sub_sec_val) ++{ ++ synopGMACWriteReg((u32 *)gmacdev->MacBase,GmacTSTargetTimeHigh,sec_val); ++ synopGMACWriteReg((u32 *)gmacdev->MacBase,GmacTSTargetTimeLow,sub_sec_val); ++ return; ++} ++/** ++ * Reads the Target time stamp registers ++ * This function Loads the target time stamp registers with the values proviced ++ * @param[in] pointer to synopGMACdevice ++ * @param[in] pointer to hold target Timestamp High value ++ * @param[in] pointer to hold target Timestamp Low value ++ * \return returns 0 for Success or else Failure ++ */ ++void synopGMAC_TS_read_target_timestamp(synopGMACdevice *gmacdev, u32 * sec_val, u32 * sub_sec_val) ++{ ++ * sec_val = synopGMACReadReg((u32 *)gmacdev->MacBase,GmacTSTargetTimeHigh); ++ * sub_sec_val = synopGMACReadReg((u32 *)gmacdev->MacBase,GmacTSTargetTimeLow); ++ return; ++} ++ ++#ifdef AVB_SUPPORT ++void synopGMACsetAvType(synopGMACdevice *gmacdev, u32 avtype) ++{ ++ u32 orig_data; ++ orig_data = synopGMACReadReg((u32 *)gmacdev->MacBase,GmacAvMacCtrl); ++ orig_data &= (~ GmacAvTypeMask); ++ orig_data |= avtype; ++ synopGMACWriteReg((u32 *)gmacdev->MacBase, GmacAvMacCtrl ,orig_data); ++} ++ ++void synopGMACsetAvPrio(synopGMACdevice * gmacdev,u8 priority){ //set the Avpriority tag ++ u32 orig_data; ++ orig_data = synopGMACReadReg((u32 *)gmacdev->MacBase,GmacAvMacCtrl); ++ orig_data &= (~ GmacAvPrio); ++ orig_data |= (priority << 16); ++ synopGMACWriteReg((u32 *)gmacdev->MacBase, GmacAvMacCtrl ,orig_data); ++ ++} ++void synopGMACsetAvCtrlCh(synopGMACdevice * gmacdev,u8 channel) ++{//set the Av control Channel ++ u32 orig_data; ++ orig_data = synopGMACReadReg((u32 *)gmacdev->MacBase,GmacAvMacCtrl); ++ orig_data &= (~ GmacAvCtrlCh); ++ orig_data |= (channel << 24); ++ synopGMACWriteReg((u32 *)gmacdev->MacBase, GmacAvMacCtrl ,orig_data); ++ ++} ++void synopGMACsetAvPTPCh (synopGMACdevice * gmacdev,u8 channel) ++{//set the Av control Channel ++ u32 orig_data; ++ orig_data = synopGMACReadReg((u32 *)gmacdev->MacBase,GmacAvMacCtrl); ++ orig_data &= (~ GmacPtpCh); ++ orig_data |= (channel << 24); ++ synopGMACWriteReg((u32 *)gmacdev->MacBase, GmacAvMacCtrl ,orig_data); ++ ++} ++ ++void synopGMACsetTxRxPrioPolicy(synopGMACdevice * gmacdev,u8 policy) ++{ //0=>RR 1=>Strict priority ++ if(policy) ++ synopGMACSetBits((u32 *)gmacdev->DmaBase, DmaBusMode , DmaArbitrationStrict); ++ else ++ synopGMACClearBits((u32 *)gmacdev->DmaBase, DmaBusMode , DmaArbitrationStrict); ++} ++void synopGMACsetTxRxPrio(synopGMACdevice * gmacdev,u8 tx_has_high_prio) ++{ //0=>RR 1=>Strict priority ++ if(tx_has_high_prio) ++ synopGMACSetBits((u32 *)gmacdev->DmaBase, DmaBusMode , DmaTxRxPrio ); ++ else ++ synopGMACClearBits((u32 *)gmacdev->DmaBase, DmaBusMode , DmaTxRxPrio ); ++} ++void synopGMACsetTxRxPrioRatio(synopGMACdevice * gmacdev,u8 tx_rx_prio_ratio) ++{ //0=>RR 1=>Strict prioriyt ++ ++ synopGMACClearBits((u32 *)gmacdev->DmaBase, DmaBusMode , DmaPriorityRatio41); ++ if(tx_rx_prio_ratio == 0) ++ synopGMACSetBits((u32 *)gmacdev->DmaBase, DmaBusMode , DmaPriorityRatio11); ++ if(tx_rx_prio_ratio == 1) ++ synopGMACSetBits((u32 *)gmacdev->DmaBase, DmaBusMode , DmaPriorityRatio21); ++ if(tx_rx_prio_ratio == 2) ++ synopGMACSetBits((u32 *)gmacdev->DmaBase, DmaBusMode , DmaPriorityRatio31); ++ if(tx_rx_prio_ratio == 3) ++ synopGMACSetBits((u32 *)gmacdev->DmaBase, DmaBusMode , DmaPriorityRatio41); ++} ++void synopGMACsetChPrioWts(synopGMACdevice * gmacdev,u8 weights) ++{ ++ synopGMACClearBits((u32 *)gmacdev->DmaBase, DmaBusMode , DmaChannelPrioWt); ++ if(weights == 1) ++ synopGMACSetBits((u32 *)gmacdev->DmaBase, DmaBusMode, DmaChannelPrio1); ++ if(weights == 2) ++ synopGMACSetBits((u32 *)gmacdev->DmaBase, DmaBusMode, DmaChannelPrio2); ++ if(weights == 3) ++ synopGMACSetBits((u32 *)gmacdev->DmaBase, DmaBusMode, DmaChannelPrio3); ++ if(weights == 4) ++ synopGMACSetBits((u32 *)gmacdev->DmaBase, DmaBusMode, DmaChannelPrio4); ++} ++ ++void synopGMACAvbEnSlot(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->DmaBase, DmaSlotFnCtrlSts , EnaSlot); ++} ++void synopGMACAvbDisSlot (synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->DmaBase, DmaSlotFnCtrlSts , EnaSlot); ++} ++void synopGMACAvbEnAdvSlotInt(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->DmaBase, DmaSlotFnCtrlSts , AdvSlotInt ); ++} ++void synopGMACAvbDisAdvSlotInt(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->DmaBase, DmaSlotFnCtrlSts , AdvSlotInt ); ++} ++void synopGMACAvbSetSlotCount(synopGMACdevice * gmacdev, u8 slotcount) ++{ ++ u32 orig_data; ++ orig_data = synopGMACReadReg((u32 *)gmacdev->DmaBase,DmaChannelCtrl); ++ orig_data &= (~ ChannelSlotCount); ++ if(slotcount == 1 ) ++ orig_data |= 0x00000000; ++ if(slotcount == 2 ) ++ orig_data |= 0x00000010; ++ if(slotcount == 4 ) ++ orig_data |= 0x00000020; ++ if(slotcount == 8 ) ++ orig_data |= 0x00000030; ++ if(slotcount == 16 ) ++ orig_data |= 0x00000040; ++ ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaChannelCtrl,orig_data); ++ ++ TR("CH1 SLOT COUNT = %08x\n",synopGMACReadReg((u32 *)gmacdev->DmaBase,DmaChannelCtrl)); ++ ++} ++ ++void synopGMACAvbEnSlotInterrupt(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->DmaBase, DmaChannelCtrl, ChannelSlotIntEn); ++} ++void synopGMACAvbDisSlotInterrupt(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->DmaBase, DmaChannelCtrl, ChannelSlotIntEn); ++} ++void synopGMACAvbEnableCrSh(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->DmaBase, DmaChannelCtrl, ChannelCreditShDis); ++} ++void synopGMACAvbDisableCrSh(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->DmaBase, DmaChannelCtrl, ChannelCreditShDis); ++} ++void synopGMACAvbEnableCrControl(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->DmaBase, DmaChannelCtrl, ChannelCreditCtrl); ++} ++void synopGMACAvbDisableCrControl(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->DmaBase, DmaChannelCtrl, ChannelCreditCtrl); ++} ++ ++void synopGMACsetAvbSendSlope(synopGMACdevice * gmacdev,u32 sendslope_val) ++{ ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase, SendSlopeCredit,(ChannelSendSlCr & sendslope_val )); ++} ++void synopGMACsetAvbIdleSlope(synopGMACdevice * gmacdev,u32 idleslope_val) ++{ ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase, IdleSlopeCredit,(ChannelIdleSlCr & idleslope_val )); ++} ++void synopGMACsetAvbHiCredit(synopGMACdevice * gmacdev,u32 hicredit_val) ++{ ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase, HighCredit ,(ChannelHiCr & hicredit_val)); ++} ++void synopGMACsetAvbLoCredit(synopGMACdevice * gmacdev,u32 locredit_val) ++{ ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase, LoCredit ,(ChannelLoCr & locredit_val)); ++} ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_ingenic_synopGMAC_Dev.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_ingenic_synopGMAC_Dev.h.patch new file mode 100644 index 00000000..bb6a4eb6 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_ingenic_synopGMAC_Dev.h.patch @@ -0,0 +1,2019 @@ +diff -drupN a/drivers/net/ethernet/ingenic/synopGMAC_Dev.h b/drivers/net/ethernet/ingenic/synopGMAC_Dev.h +--- a/drivers/net/ethernet/ingenic/synopGMAC_Dev.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/net/ethernet/ingenic/synopGMAC_Dev.h 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,2015 @@ ++/* =================================================================================== ++ * Copyright (c) <2009> Synopsys, Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy of ++ * this software annotated with this license and associated documentation files ++ * (the "Software"), to deal in the Software without restriction, including without ++ * limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in all ++ * copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, ++ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A ++ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT ++ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE ++ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * =================================================================================== */ ++ ++/**\file ++ * This file defines the function prototypes for the Synopsys GMAC device and the ++ * Marvell 88E1011/88E1011S integrated 10/100/1000 Gigabit Ethernet Transceiver. ++ * Since the phy register mapping are standardised, the phy register map and the ++ * bit definitions remain the same for other phy as well. ++ * This also defines some of the Ethernet related parmeters. ++ * \internal ++ * -----------------------------REVISION HISTORY------------------------------------ ++ * Synopsys 01/Aug/2007 Created ++ */ ++ ++ ++#ifndef SYNOP_GMAC_DEV_H ++#define SYNOP_GMAC_DEV_H 1 ++ ++#include "synopGMAC_plat.h" ++ ++/*SynopGMAC can support up to 32 phys*/ ++ ++enum GMACPhyBase ++{ ++ PHY0 = 0, //The device can support 32 phys, but we use first phy only ++ PHY31 = 31, ++}; ++ ++#define DEFAULT_PHY_BASE (PHY0 + 16) //We use First Phy ++#define MACBASE 0x0000 // The Mac Base address offset is 0x0000 ++#define DMABASE 0x1000 // Dma base address starts with an offset 0x1000 ++ ++#ifdef AVB_SUPPORT ++#define DMABASE_CH0 DMABASE // DMA base address for Channel 0 ++#define DMABASE_CH1 0x1100 // DMA base address for Channel 1 ++#define DMABASE_CH2 0x1200 // DMA base address for Channel 2 ++ ++#define ETHERNET_HEADER_AVB 18 //6 byte Dest addr, 6 byte Src addr, 2 byte length/type ++ ++#endif ++ ++ ++//#define TRANSMIT_DESC_SIZE 256 //Tx Descriptors needed in the Descriptor pool/queue ++//#define RECEIVE_DESC_SIZE 256 //Rx Descriptors needed in the Descriptor pool/queue ++#define TRANSMIT_DESC_SIZE 12//256 //Tx Descriptors needed in the Descriptor pool/queue ++#define RECEIVE_DESC_SIZE 12//256 //Rx Descriptors needed in the Descriptor pool/queue ++ ++#define ETHERNET_HEADER 14 //6 byte Dest addr, 6 byte Src addr, 2 byte length/type ++#define ETHERNET_CRC 4 //Ethernet CRC ++#define ETHERNET_EXTRA 2 //Only God knows about this????? ++#define ETHERNET_PACKET_COPY 250 // Maximum length when received data is copied on to a new skb ++#define ETHERNET_PACKET_EXTRA 18 // Preallocated length for the rx packets is MTU + ETHERNET_PACKET_EXTRA ++#define VLAN_TAG 4 //optional 802.1q VLAN Tag ++#define MIN_ETHERNET_PAYLOAD 46 //Minimum Ethernet payload size ++#define MAX_ETHERNET_PAYLOAD 1500 //Maximum Ethernet payload size ++#define JUMBO_FRAME_PAYLOAD 9000 //Jumbo frame payload size ++ ++#define TX_BUF_SIZE ETHERNET_HEADER + ETHERNET_CRC + MAX_ETHERNET_PAYLOAD + VLAN_TAG ++ ++ ++// This is the IP's phy address. This is unique address for every MAC in the universe ++#define DEFAULT_MAC_ADDRESS {0x00, 0x55, 0x7B, 0xB5, 0x7D, 0xF7} ++ ++/* ++ DMA Descriptor Structure ++ The structure is common for both receive and transmit descriptors ++ The descriptor is of 4 words, but our structrue contains 6 words where ++ last two words are to hold the virtual address of the network buffer pointers ++ for driver's use ++ From the GMAC core release 3.50a onwards, the Enhanced Descriptor structure got changed. ++ The descriptor (both transmit and receive) are of 8 words each rather the 4 words of normal ++ descriptor structure. ++ Whenever IEEE 1588 Timestamping is enabled TX/RX DESC6 provides the lower 32 bits of Timestamp value and ++ TX/RX DESC7 provides the upper 32 bits of Timestamp value ++ In addition to this whenever extended status bit is set (RX DESC0 bit 0), RX DESC4 contains the extended status information ++ */ ++ ++#define MODULO_INTERRUPT 1 // if it is set to 1, interrupt is available for all the descriptors or else interrupt is available only for ++// descriptor whose index%MODULO_INTERRUPT is zero ++#ifdef ENH_DESC_8W ++typedef struct DmaDescStruct ++{ ++ u32 status; /* Status */ ++ u32 length; /* Buffer 1 and Buffer 2 length */ ++ u32 buffer1; /* Network Buffer 1 pointer (Dma-able) */ ++ u32 buffer2; /* Network Buffer 2 pointer or next descriptor pointer (Dma-able)in chain structure */ ++ /* This data below is used only by driver */ ++ u32 extstatus; /* Extended status of a Rx Descriptor */ ++ u32 reserved1; /* Reserved word */ ++ u32 timestamplow; /* Lower 32 bits of the 64 bit timestamp value */ ++ u32 timestamphigh; /* Higher 32 bits of the 64 bit timestamp value */ ++ u32 data1; /* This holds virtual address of buffer1, not used by DMA */ ++ u32 data2; /* This holds virtual address of buffer2, not used by DMA */ ++#ifndef CONFIG_INGENIC_MAC_AXI_BUS ++}DmaDesc; ++#else ++}__packed __aligned(8) DmaDesc; ++#endif ++#else ++typedef struct DmaDescStruct ++{ ++ u32 status; /* Status */ ++ u32 length; /* Buffer 1 and Buffer 2 length */ ++ u32 buffer1; /* Network Buffer 1 pointer (Dma-able) */ ++ u32 buffer2; /* Network Buffer 2 pointer or next descriptor pointer (Dma-able)in chain structure */ ++ /* This data below is used only by driver */ ++ u32 data1; /* This holds virtual address of buffer1, not used by DMA */ ++ u32 data2; /* This holds virtual address of buffer2, not used by DMA */ ++#ifndef CONFIG_INGENIC_MAC_AXI_BUS ++}DmaDesc; ++#else ++}__packed __aligned(8) DmaDesc; ++#endif ++#endif ++ ++enum DescMode ++{ ++ RINGMODE = 0x00000001, ++ CHAINMODE = 0x00000002, ++}; ++ ++enum BufferMode ++{ ++ SINGLEBUF = 0x00000001, ++ DUALBUF = 0x00000002, ++}; ++ ++/* synopGMAC device data */ ++ ++typedef struct synopGMACDeviceStruct ++{ ++ u32 MacBase; /* base address of MAC registers */ ++ u32 DmaBase; /* base address of DMA registers */ ++ u32 PhyBase; /* PHY device address on MII interface */ ++ u32 Version; /* Gmac Revision version */ ++ ++ ++ dma_addr_t TxDescDma; /* Dma-able address of first tx descriptor either in ring or chain mode, this is used by the GMAC device*/ ++ dma_addr_t RxDescDma; /* Dma-albe address of first rx descriptor either in ring or chain mode, this is used by the GMAC device*/ ++ DmaDesc *TxDesc; /* start address of TX descriptors ring or chain, this is used by the driver */ ++ DmaDesc *RxDesc; /* start address of RX descriptors ring or chain, this is used by the driver */ ++ ++ u32 BusyTxDesc; /* Number of Tx Descriptors owned by DMA at any given time*/ ++ u32 BusyRxDesc; /* Number of Rx Descriptors owned by DMA at any given time*/ ++ ++ u32 RxDescCount; /* number of rx descriptors in the tx descriptor queue/pool */ ++ u32 TxDescCount; /* number of tx descriptors in the rx descriptor queue/pool */ ++ ++ u32 TxBusy; /* index of the tx descriptor owned by DMA, is obtained by synopGMAC_get_tx_qptr() */ ++ u32 TxNext; /* index of the tx descriptor next available with driver, given to DMA by synopGMAC_set_tx_qptr() */ ++ u32 RxBusy; /* index of the rx descriptor owned by DMA, obtained by synopGMAC_get_rx_qptr() */ ++ u32 RxNext; /* index of the rx descriptor next available with driver, given to DMA by synopGMAC_set_rx_qptr() */ ++ ++ DmaDesc * TxBusyDesc; /* Tx Descriptor address corresponding to the index TxBusy */ ++ DmaDesc * TxNextDesc; /* Tx Descriptor address corresponding to the index TxNext */ ++ DmaDesc * RxBusyDesc; /* Rx Descriptor address corresponding to the index TxBusy */ ++ DmaDesc * RxNextDesc; /* Rx Descriptor address corresponding to the index RxNext */ ++ ++ ++ /*Phy related stuff*/ ++ u32 ClockDivMdc; /* Clock divider value programmed in the hardware */ ++ /* The status of the link */ ++ u32 LinkState; /* Link status as reported by the Marvel Phy */ ++ u32 DuplexMode; /* Duplex mode of the Phy */ ++ u32 Speed; /* Speed of the Phy */ ++ u32 LoopBackMode; /* Loopback status of the Phy */ ++ ++} synopGMACdevice; ++ ++#ifdef AVB_SUPPORT ++typedef struct AVBStruct ++{ ++ u8 ChSelMask; /* This gives which DMA channel is enabled and which is disabled ++ Bit0 for Ch0 ++ Bit1 for Ch1 ++ Bit2 for Ch2 ++ */ ++ u8 DurationOfExp; /* Duration for which experiment should be conducted in minutes - Default 2 Minutes */ ++ ++ u8 AvControlCh; /* channel on which AV control channel must be received (Not used)*/ ++ u8 PTPCh; /* Channel on which PTP packets must be received (Not Used)*/ ++ u8 PrioTagForAV; /* Used when more than One channel enabled in Rx path (Not Used) ++ for only CH1 Enabled: ++ Frames sith Priority > Value programmed, frames sent to CH1 ++ Frames with priority < Value programmed are sent to CH0 ++ For both CH1 and CH2 Enabled: ++ Frames sith Priority > Value programmed, frames sent to CH2 ++ Frames with priority < Value programmed are sent to CH1 ++ */ ++ ++ u16 AvType; /* AV Ethernet Type to be programmed for Core to identify AV type */ ++ ++ u8 Ch1PrioWts; ++ u8 Ch1Bw; ++ u32 Ch1_frame_size; ++ u8 Ch1_EnableSlotCheck; /* Enable checking of slot numbers programmed in the Tx Desc*/ ++ u8 Ch1_AdvSlotInterval; /* When Set Data fetched for current slot and for next 2 slots in advance ++ When reset data fetched for current slot and in advance for next slot*/ ++ ++ u8 Ch1CrSh; /* When set Enables the credit based traffic shaping. Now works with Strict priority style*/ ++ u8 Ch1SlotCount; /* Over which transmiteed bits per slot needs to be computed (Only for Credit based shaping) */ ++ u32 Ch1AvgBitsPerSlot; /* Average bits per slot reported by core once in Ch1SlotCount * 125 micro seconds */ ++ u32 Ch1AvgBitsPerSlotAccL; /* No of Avg Bits per slot on Channel1*/ ++ u32 Ch1AvgBitsPerSlotAccH; /* No of Avg Bits per slot on Channel1*/ ++ u32 Ch1AvgBitsNoOfInterrupts; /* Total Number of interrupts over which AvbBits are accumulated*/ ++ ++ u8 Ch1CreditControl; /* Will be zero (Not used) */ ++ ++ u8 Ch1_tx_rx_prio_policy; // Should Ch1 use Strict or RR policy ++ u8 Ch1_use_tx_high_prio; // Should Ch1 Tx have High priority over Rx ++ u8 Ch1_tx_rx_prio_ratio; // For Round Robin what is the ratio between tx-rx or rx-tx ++ ++ u8 Ch1_tx_desc_slot_no_start; ++ u8 Ch1_tx_desc_slot_no_skip; ++ ++ u32 Ch1SendSlope; ++ u32 Ch1IdleSlope; ++ u32 Ch1HiCredit; ++ u32 Ch1LoCredit; ++ ++ u32 Ch1FramecountTx; /* No of Frames Transmitted on Channel 1 */ ++ u32 Ch1FramecountRx; /* No of Frames Received on Channel 1 */ ++ ++ u8 Ch2PrioWts; ++ u8 Ch2Bw; ++ u32 Ch2_frame_size; ++ u8 Ch2_EnableSlotCheck; /* Enable checking of slot numbers programmed in the Tx Desc*/ ++ u8 Ch2_AdvSlotInterval; /* When Set Data fetched for current slot and for next 2 slots in advance ++ When reset data fetched for current slot and in advance for next slot*/ ++ u8 Ch2CrSh; /* When set Enables the credit based traffic shaping. Now works with Strict priority style*/ ++ u8 Ch2SlotCount; /* Over which transmiteed bits per slot needs to be computed (Only for Credit based shaping) */ ++ u32 Ch2AvgBitsPerSlot; /* Average bits per slot reported by core once in Ch2SlotCount * 125 micro seconds */ ++ u32 Ch2AvgBitsPerSlotAccL; /* No of Avg Bits per slot on Channel2*/ ++ u32 Ch2AvgBitsPerSlotAccH; /* No of Avg Bits per slot on Channel2*/ ++ u32 Ch2AvgBitsNoOfInterrupts; /* Total Number of interrupts over which AvbBits are accumulated*/ ++ ++ u8 Ch2CreditControl; /* Will be zero at present*/ ++ ++ u8 Ch2_tx_rx_prio_policy; // Should Ch1 use Strict or RR policy ++ u8 Ch2_use_tx_high_prio; // Should Ch1 Tx have High priority over Rx ++ u8 Ch2_tx_rx_prio_ratio; // For Round Robin what is the ratio between tx-rx or rx-tx ++ ++ ++ u8 Ch2_tx_desc_slot_no_start; ++ u8 Ch2_tx_desc_slot_no_skip; ++ ++ u32 Ch2SendSlope; ++ u32 Ch2IdleSlope; ++ u32 Ch2HiCredit; ++ u32 Ch2LoCredit; ++ ++ u32 Ch2FramecountTx; /* No of Frames Transmitted on Channel 2 */ ++ u32 Ch2FramecountRx; /* No of Frames Received on Channel 2 */ ++ ++ u8 Ch0PrioWts; ++ u8 Ch0_tx_rx_prio_policy; // Should Ch1 use Strict or RR policy ++ u8 Ch0_use_tx_high_prio; // Should Ch1 Tx have High priority over Rx ++ u8 Ch0_tx_rx_prio_ratio; // For Round Robin what is the ratio between tx-rx or rx-tx ++ ++ u32 Ch0_frame_size; ++ u32 Ch0FramecountTx; /* No of Frames Transmitted on Channel 0 */ ++ u32 Ch0FramecountRx; /* No of Frames Received on Channel 0 */ ++ ++} synopGMACavbStruct; ++#endif ++ ++/* Below is "88E1011/88E1011S Integrated 10/100/1000 Gigabit Ethernet Transceiver" ++ * Register and their layouts. This Phy has been used in the Dot Aster GMAC Phy daughter. ++ * Since the Phy register map is standard, this map hardly changes to a different Ppy ++ */ ++ ++enum MiiRegisters ++{ ++ PHY_CONTROL_REG = 0x0000, /*Control Register*/ ++ PHY_STATUS_REG = 0x0001, /*Status Register */ ++ PHY_ID_HI_REG = 0x0002, /*PHY Identifier High Register*/ ++ PHY_ID_LOW_REG = 0x0003, /*PHY Identifier High Register*/ ++ PHY_AN_ADV_REG = 0x0004, /*Auto-Negotiation Advertisement Register*/ ++ PHY_LNK_PART_ABl_REG = 0x0005, /*Link Partner Ability Register (Base Page)*/ ++ PHY_AN_EXP_REG = 0x0006, /*Auto-Negotiation Expansion Register*/ ++ PHY_AN_NXT_PAGE_TX_REG = 0x0007, /*Next Page Transmit Register*/ ++ PHY_LNK_PART_NXT_PAGE_REG = 0x0008, /*Link Partner Next Page Register*/ ++ PHY_1000BT_CTRL_REG = 0x0009, /*1000BASE-T Control Register*/ ++ PHY_1000BT_STATUS_REG = 0x000a, /*1000BASE-T Status Register*/ ++ PHY_SPECIFIC_CTRL_REG = 0x0010, /*Phy specific control register*/ ++ PHY_SPECIFIC_STATUS_REG = 0x0011, /*Phy specific status register*/ ++ PHY_INTERRUPT_ENABLE_REG = 0x0012, /*Phy interrupt enable register*/ ++ PHY_INTERRUPT_STATUS_REG = 0x0013, /*Phy interrupt status register*/ ++ PHY_EXT_PHY_SPC_CTRL = 0x0014, /*Extended Phy specific control*/ ++ PHY_RX_ERR_COUNTER = 0x0015, /*Receive Error Counter*/ ++ PHY_EXT_ADDR_CBL_DIAG = 0x0016, /*Extended address for cable diagnostic register*/ ++ PHY_LED_CONTROL = 0x0018, /*LED Control*/ ++ PHY_MAN_LED_OVERIDE = 0x0019, /*Manual LED override register*/ ++ PHY_EXT_PHY_SPC_CTRL2 = 0x001a, /*Extended Phy specific control 2*/ ++ PHY_EXT_PHY_SPC_STATUS = 0x001b, /*Extended Phy specific status*/ ++ PHY_CBL_DIAG_REG = 0x001c, /*Cable diagnostic registers*/ ++}; ++ ++ ++/* This is Control register layout. Control register is of 16 bit wide. ++*/ ++ ++enum Mii_GEN_CTRL ++{ /* Description bits R/W default value */ ++ Mii_reset = 0x8000, ++ Mii_Speed_10 = 0x0000, /* 10 Mbps 6:13 RW */ ++ Mii_Speed_100 = 0x2000, /* 100 Mbps 6:13 RW */ ++ Mii_Speed_1000 = 0x0040, /* 1000 Mbit/s 6:13 RW */ ++ ++ Mii_Duplex = 0x0100, /* Full Duplex mode 8 RW */ ++ ++ Mii_Manual_Master_Config = 0x0800, /* Manual Master Config 11 RW */ ++ ++ Mii_Loopback = 0x4000, /* Enable Loop back 14 RW */ ++ Mii_NoLoopback = 0x0000, /* Enable Loop back 14 RW */ ++}; ++ ++enum Mii_Phy_Status ++{ ++ Mii_phy_status_speed_10 = 0x0000, ++ Mii_phy_status_speed_100 = 0x4000, ++ Mii_phy_status_speed_1000 = 0x8000, ++ ++ Mii_phy_status_full_duplex = 0x2000, ++ Mii_phy_status_half_duplex = 0x0000, ++ ++ Mii_phy_status_link_up = 0x0400, ++}; ++/* This is Status register layout. Status register is of 16 bit wide. ++*/ ++enum Mii_GEN_STATUS ++{ ++ Mii_AutoNegCmplt = 0x0020, /* Autonegotiation completed 5 RW */ ++ Mii_Link = 0x0004, /* Link status 2 RW */ ++}; ++ ++enum Mii_Link_Status ++{ ++ LINKDOWN = 0, ++ LINKUP = 1, ++}; ++ ++enum Mii_Duplex_Mode ++{ ++ HALFDUPLEX = 1, ++ FULLDUPLEX = 2, ++}; ++enum Mii_Link_Speed ++{ ++ SPEED10 = 1, ++ SPEED100 = 2, ++ SPEED1000 = 3, ++}; ++ ++enum Mii_Loop_Back ++{ ++ NOLOOPBACK = 0, ++ LOOPBACK = 1, ++}; ++ ++ ++ ++/********************************************************** ++ * GMAC registers Map ++ * For Pci based system address is BARx + GmacRegisterBase ++ * For any other system translation is done accordingly ++ **********************************************************/ ++enum GmacRegisters ++{ ++ GmacConfig = 0x0000, /* Mac config Register */ ++ GmacFrameFilter = 0x0004, /* Mac frame filtering controls */ ++ GmacHashHigh = 0x0008, /* Multi-cast hash table high */ ++ GmacHashLow = 0x000C, /* Multi-cast hash table low */ ++ GmacGmiiAddr = 0x0010, /* GMII address Register(ext. Phy) */ ++ GmacGmiiData = 0x0014, /* GMII data Register(ext. Phy) */ ++ GmacFlowControl = 0x0018, /* Flow control Register */ ++ GmacVlan = 0x001C, /* VLAN tag Register (IEEE 802.1Q) */ ++ ++ GmacVersion = 0x0020, /* GMAC Core Version Register */ ++ GmacWakeupAddr = 0x0028, /* GMAC wake-up frame filter adrress reg */ ++ GmacPmtCtrlStatus = 0x002C, /* PMT control and status register */ ++ ++#ifdef LPI_SUPPORT ++ GmacLPICtrlSts = 0x0030, /* LPI (low power idle) Control and Status Register */ ++ GmacLPITimerCtrl = 0x0034, /* LPI timer control register */ ++#endif ++ ++ GmacInterruptStatus = 0x0038, /* Mac Interrupt ststus register */ ++ GmacInterruptMask = 0x003C, /* Mac Interrupt Mask register */ ++ ++ GmacAddr0High = 0x0040, /* Mac address0 high Register */ ++ GmacAddr0Low = 0x0044, /* Mac address0 low Register */ ++ GmacAddr1High = 0x0048, /* Mac address1 high Register */ ++ GmacAddr1Low = 0x004C, /* Mac address1 low Register */ ++ GmacAddr2High = 0x0050, /* Mac address2 high Register */ ++ GmacAddr2Low = 0x0054, /* Mac address2 low Register */ ++ GmacAddr3High = 0x0058, /* Mac address3 high Register */ ++ GmacAddr3Low = 0x005C, /* Mac address3 low Register */ ++ GmacAddr4High = 0x0060, /* Mac address4 high Register */ ++ GmacAddr4Low = 0x0064, /* Mac address4 low Register */ ++ GmacAddr5High = 0x0068, /* Mac address5 high Register */ ++ GmacAddr5Low = 0x006C, /* Mac address5 low Register */ ++ GmacAddr6High = 0x0070, /* Mac address6 high Register */ ++ GmacAddr6Low = 0x0074, /* Mac address6 low Register */ ++ GmacAddr7High = 0x0078, /* Mac address7 high Register */ ++ GmacAddr7Low = 0x007C, /* Mac address7 low Register */ ++ GmacAddr8High = 0x0080, /* Mac address8 high Register */ ++ GmacAddr8Low = 0x0084, /* Mac address8 low Register */ ++ GmacAddr9High = 0x0088, /* Mac address9 high Register */ ++ GmacAddr9Low = 0x008C, /* Mac address9 low Register */ ++ GmacAddr10High = 0x0090, /* Mac address10 high Register */ ++ GmacAddr10Low = 0x0094, /* Mac address10 low Register */ ++ GmacAddr11High = 0x0098, /* Mac address11 high Register */ ++ GmacAddr11Low = 0x009C, /* Mac address11 low Register */ ++ GmacAddr12High = 0x00A0, /* Mac address12 high Register */ ++ GmacAddr12Low = 0x00A4, /* Mac address12 low Register */ ++ GmacAddr13High = 0x00A8, /* Mac address13 high Register */ ++ GmacAddr13Low = 0x00AC, /* Mac address13 low Register */ ++ GmacAddr14High = 0x00B0, /* Mac address14 high Register */ ++ GmacAddr14Low = 0x00B4, /* Mac address14 low Register */ ++ GmacAddr15High = 0x00B8, /* Mac address15 high Register */ ++ GmacAddr15Low = 0x00BC, /* Mac address15 low Register */ ++ ++ GmacRGMIIControl = 0x00D8, /* SGMII/RGMII/SMII Control and Status Register */ ++ ++ /*Time Stamp Register Map*/ ++ GmacTSControl = 0x0700, /* Controls the Timestamp update logic : only when IEEE 1588 time stamping is enabled in corekit */ ++ ++ GmacTSSubSecIncr = 0x0704, /* 8 bit value by which sub second register is incremented : only when IEEE 1588 time stamping without external timestamp input */ ++ ++ GmacTSHigh = 0x0708, /* 32 bit seconds(MS) : only when IEEE 1588 time stamping without external timestamp input */ ++ GmacTSLow = 0x070C, /* 32 bit nano seconds(MS) : only when IEEE 1588 time stamping without external timestamp input */ ++ ++ GmacTSHighUpdate = 0x0710, /* 32 bit seconds(MS) to be written/added/subtracted : only when IEEE 1588 time stamping without external timestamp input */ ++ GmacTSLowUpdate = 0x0714, /* 32 bit nano seconds(MS) to be writeen/added/subtracted : only when IEEE 1588 time stamping without external timestamp input */ ++ ++ GmacTSAddend = 0x0718, /* Used by Software to readjust the clock frequency linearly : only when IEEE 1588 time stamping without external timestamp input */ ++ ++ GmacTSTargetTimeHigh = 0x071C, /* 32 bit seconds(MS) to be compared with system time : only when IEEE 1588 time stamping without external timestamp input */ ++ GmacTSTargetTimeLow = 0x0720, /* 32 bit nano seconds(MS) to be compared with system time : only when IEEE 1588 time stamping without external timestamp input */ ++ ++ GmacTSHighWord = 0x0724, /* Time Stamp Higher Word Register (Version 2 only); only lower 16 bits are valid */ ++ //GmacTSHighWordUpdate = 0x072C, /* Time Stamp Higher Word Update Register (Version 2 only); only lower 16 bits are valid */ ++ ++ GmacTSStatus = 0x0728, /* Time Stamp Status Register */ ++#ifdef AVB_SUPPORT ++ GmacAvMacCtrl = 0x0738, /* AV mac control Register */ ++#endif ++ ++}; ++ ++/********************************************************** ++ * GMAC Network interface registers ++ * This explains the Register's Layout ++ ++ * FES is Read only by default and is enabled only when Tx ++ * Config Parameter is enabled for RGMII/SGMII interface ++ * during CoreKit Config. ++ ++ * DM is Read only with value 1'b1 in Full duplex only Config ++ **********************************************************/ ++ ++/* GmacConfig = 0x0000, Mac config Register Layout */ ++enum GmacConfigReg ++{ ++ /* Bit description Bits R/W Reset value */ ++ GmacWatchdog = 0x00800000, ++ GmacWatchdogDisable = 0x00800000, /* (WD)Disable watchdog timer on Rx 23 RW */ ++ GmacWatchdogEnable = 0x00000000, /* Enable watchdog timer 0 */ ++ ++ GmacJabber = 0x00400000, ++ GmacJabberDisable = 0x00400000, /* (JD)Disable jabber timer on Tx 22 RW */ ++ GmacJabberEnable = 0x00000000, /* Enable jabber timer 0 */ ++ ++ GmacFrameBurst = 0x00200000, ++ GmacFrameBurstEnable = 0x00200000, /* (BE)Enable frame bursting during Tx 21 RW */ ++ GmacFrameBurstDisable = 0x00000000, /* Disable frame bursting 0 */ ++ ++ GmacJumboFrame = 0x00100000, ++ GmacJumboFrameEnable = 0x00100000, /* (JE)Enable jumbo frame for Tx 20 RW */ ++ GmacJumboFrameDisable = 0x00000000, /* Disable jumbo frame 0 */ ++ ++ GmacInterFrameGap = 0x000E0000, ++ GmacInterFrameGap7 = 0x000E0000, /* (IFG) Config7 - 40 bit times 19:17 RW */ ++ GmacInterFrameGap6 = 0x000C0000, /* (IFG) Config6 - 48 bit times */ ++ GmacInterFrameGap5 = 0x000A0000, /* (IFG) Config5 - 56 bit times */ ++ GmacInterFrameGap4 = 0x00080000, /* (IFG) Config4 - 64 bit times */ ++ GmacInterFrameGap3 = 0x00040000, /* (IFG) Config3 - 72 bit times */ ++ GmacInterFrameGap2 = 0x00020000, /* (IFG) Config2 - 80 bit times */ ++ GmacInterFrameGap1 = 0x00010000, /* (IFG) Config1 - 88 bit times */ ++ GmacInterFrameGap0 = 0x00000000, /* (IFG) Config0 - 96 bit times 000 */ ++ ++ GmacDisableCrs = 0x00010000, ++ GmacMiiGmii = 0x00008000, ++ GmacSelectMii = 0x00008000, /* (PS)Port Select-MII mode 15 RW */ ++ GmacSelectGmii = 0x00000000, /* GMII mode 0 */ ++ ++ GmacFESpeed100 = 0x00004000, /*(FES)Fast Ethernet speed 100Mbps 14 RW */ ++ GmacFESpeed10 = 0x00000000, /* 10Mbps 0 */ ++ ++ GmacRxOwn = 0x00002000, ++ GmacDisableRxOwn = 0x00002000, /* (DO)Disable receive own packets 13 RW */ ++ GmacEnableRxOwn = 0x00000000, /* Enable receive own packets 0 */ ++ ++ GmacLoopback = 0x00001000, ++ GmacLoopbackOn = 0x00001000, /* (LM)Loopback mode for GMII/MII 12 RW */ ++ GmacLoopbackOff = 0x00000000, /* Normal mode 0 */ ++ ++ GmacDuplex = 0x00000800, ++ GmacFullDuplex = 0x00000800, /* (DM)Full duplex mode 11 RW */ ++ GmacHalfDuplex = 0x00000000, /* Half duplex mode 0 */ ++ ++ GmacRxIpcOffload = 0x00000400, /*IPC checksum offload 10 RW 0 */ ++ ++ GmacRetry = 0x00000200, ++ GmacRetryDisable = 0x00000200, /* (DR)Disable Retry 9 RW */ ++ GmacRetryEnable = 0x00000000, /* Enable retransmission as per BL 0 */ ++ ++ GmacLinkUp = 0x00000100, /* (LUD)Link UP 8 RW */ ++ GmacLinkDown = 0x00000100, /* Link Down 0 */ ++ ++ GmacPadCrcStrip = 0x00000080, ++ GmacPadCrcStripEnable = 0x00000080, /* (ACS) Automatic Pad/Crc strip enable 7 RW */ ++ GmacPadCrcStripDisable = 0x00000000, /* Automatic Pad/Crc stripping disable 0 */ ++ ++ GmacBackoffLimit = 0x00000060, ++ GmacBackoffLimit3 = 0x00000060, /* (BL)Back-off limit in HD mode 6:5 RW */ ++ GmacBackoffLimit2 = 0x00000040, /* */ ++ GmacBackoffLimit1 = 0x00000020, /* */ ++ GmacBackoffLimit0 = 0x00000000, /* 00 */ ++ ++ GmacDeferralCheck = 0x00000010, ++ GmacDeferralCheckEnable = 0x00000010, /* (DC)Deferral check enable in HD mode 4 RW */ ++ GmacDeferralCheckDisable = 0x00000000, /* Deferral check disable 0 */ ++ ++ GmacTx = 0x00000008, ++ GmacTxEnable = 0x00000008, /* (TE)Transmitter enable 3 RW */ ++ GmacTxDisable = 0x00000000, /* Transmitter disable 0 */ ++ ++ GmacRx = 0x00000004, ++ GmacRxEnable = 0x00000004, /* (RE)Receiver enable 2 RW */ ++ GmacRxDisable = 0x00000000, /* Receiver disable 0 */ ++}; ++ ++/* GmacFrameFilter = 0x0004, Mac frame filtering controls Register Layout*/ ++enum GmacFrameFilterReg ++{ ++ GmacFilter = 0x80000000, ++ GmacFilterOff = 0x80000000, /* (RA)Receive all incoming packets 31 RW */ ++ GmacFilterOn = 0x00000000, /* Receive filtered packets only 0 */ ++ ++ GmacHashPerfectFilter = 0x00000400, /*Hash or Perfect Filter enable 10 RW 0 */ ++ ++ GmacSrcAddrFilter = 0x00000200, ++ GmacSrcAddrFilterEnable = 0x00000200, /* (SAF)Source Address Filter enable 9 RW */ ++ GmacSrcAddrFilterDisable = 0x00000000, /* 0 */ ++ ++ GmacSrcInvaAddrFilter = 0x00000100, ++ GmacSrcInvAddrFilterEn = 0x00000100, /* (SAIF)Inv Src Addr Filter enable 8 RW */ ++ GmacSrcInvAddrFilterDis = 0x00000000, /* 0 */ ++ ++ GmacPassControl = 0x000000C0, ++ GmacPassControl3 = 0x000000C0, /* (PCS)Forwards ctrl frms that pass AF 7:6 RW */ ++ GmacPassControl2 = 0x00000080, /* Forwards all control frames */ ++ GmacPassControl1 = 0x00000040, /* Does not pass control frames */ ++ GmacPassControl0 = 0x00000000, /* Does not pass control frames 00 */ ++ ++ GmacBroadcast = 0x00000020, ++ GmacBroadcastDisable = 0x00000020, /* (DBF)Disable Rx of broadcast frames 5 RW */ ++ GmacBroadcastEnable = 0x00000000, /* Enable broadcast frames 0 */ ++ ++ GmacMulticastFilter = 0x00000010, ++ GmacMulticastFilterOff = 0x00000010, /* (PM) Pass all multicast packets 4 RW */ ++ GmacMulticastFilterOn = 0x00000000, /* Pass filtered multicast packets 0 */ ++ ++ GmacDestAddrFilter = 0x00000008, ++ GmacDestAddrFilterInv = 0x00000008, /* (DAIF)Inverse filtering for DA 3 RW */ ++ GmacDestAddrFilterNor = 0x00000000, /* Normal filtering for DA 0 */ ++ ++ GmacMcastHashFilter = 0x00000004, ++ GmacMcastHashFilterOn = 0x00000004, /* (HMC)perfom multicast hash filtering 2 RW */ ++ GmacMcastHashFilterOff = 0x00000000, /* perfect filtering only 0 */ ++ ++ GmacUcastHashFilter = 0x00000002, ++ GmacUcastHashFilterOn = 0x00000002, /* (HUC)Unicast Hash filtering only 1 RW */ ++ GmacUcastHashFilterOff = 0x00000000, /* perfect filtering only 0 */ ++ ++ GmacPromiscuousMode = 0x00000001, ++ GmacPromiscuousModeOn = 0x00000001, /* Receive all frames 0 RW */ ++ GmacPromiscuousModeOff = 0x00000000, /* Receive filtered packets only 0 */ ++}; ++ ++ ++/*GmacGmiiAddr = 0x0010, GMII address Register(ext. Phy) Layout */ ++enum GmacGmiiAddrReg ++{ ++ GmiiDevMask = 0x0000F800, /* (PA)GMII device address 15:11 RW 0x00 */ ++ GmiiDevShift = 11, ++ ++ GmiiRegMask = 0x000007C0, /* (GR)GMII register in selected Phy 10:6 RW 0x00 */ ++ GmiiRegShift = 6, ++ ++ GmiiCsrClkMask = 0x0000001C, /*CSR Clock bit Mask 4:2 */ ++ GmiiCsrClk5 = 0x00000014, /* (CR)CSR Clock Range 250-300 MHz 4:2 RW 000 */ ++ GmiiCsrClk4 = 0x00000010, /* 150-250 MHz */ ++ GmiiCsrClk3 = 0x0000000C, /* 35-60 MHz */ ++ GmiiCsrClk2 = 0x00000008, /* 20-35 MHz */ ++ GmiiCsrClk1 = 0x00000004, /* 100-150 MHz */ ++ GmiiCsrClk0 = 0x00000000, /* 60-100 MHz */ ++ ++ GmiiWrite = 0x00000002, /* (GW)Write to register 1 RW */ ++ GmiiRead = 0x00000000, /* Read from register 0 */ ++ ++ GmiiBusy = 0x00000001, /* (GB)GMII interface is busy 0 RW 0 */ ++}; ++ ++/* GmacGmiiData = 0x0014, GMII data Register(ext. Phy) Layout */ ++enum GmacGmiiDataReg ++{ ++ GmiiDataMask = 0x0000FFFF, /* (GD)GMII Data 15:0 RW 0x0000 */ ++}; ++ ++ ++/*GmacFlowControl = 0x0018, Flow control Register Layout */ ++enum GmacFlowControlReg ++{ ++ GmacPauseTimeMask = 0xFFFF0000, /* (PT) PAUSE TIME field in the control frame 31:16 RW 0x0000 */ ++ GmacPauseTimeShift = 16, ++ ++ GmacPauseLowThresh = 0x00000030, ++ GmacPauseLowThresh3 = 0x00000030, /* (PLT)thresh for pause tmr 256 slot time 5:4 RW */ ++ GmacPauseLowThresh2 = 0x00000020, /* 144 slot time */ ++ GmacPauseLowThresh1 = 0x00000010, /* 28 slot time */ ++ GmacPauseLowThresh0 = 0x00000000, /* 4 slot time 000 */ ++ ++ GmacUnicastPauseFrame = 0x00000008, ++ GmacUnicastPauseFrameOn = 0x00000008, /* (UP)Detect pause frame with unicast addr. 3 RW */ ++ GmacUnicastPauseFrameOff = 0x00000000, /* Detect only pause frame with multicast addr. 0 */ ++ ++ GmacRxFlowControl = 0x00000004, ++ GmacRxFlowControlEnable = 0x00000004, /* (RFE)Enable Rx flow control 2 RW */ ++ GmacRxFlowControlDisable = 0x00000000, /* Disable Rx flow control 0 */ ++ ++ GmacTxFlowControl = 0x00000002, ++ GmacTxFlowControlEnable = 0x00000002, /* (TFE)Enable Tx flow control 1 RW */ ++ GmacTxFlowControlDisable = 0x00000000, /* Disable flow control 0 */ ++ ++ GmacFlowControlBackPressure= 0x00000001, ++ GmacSendPauseFrame = 0x00000001, /* (FCB/PBA)send pause frm/Apply back pressure 0 RW 0 */ ++}; ++ ++/* GmacInterruptStatus = 0x0038, Mac Interrupt ststus register */ ++enum GmacInterruptStatusBitDefinition ++{ ++ GmacTSIntSts = 0x00000200, /* set if int generated due to TS (Read Time Stamp Status Register to know details)*/ ++ GmacMmcRxChksumOffload = 0x00000080, /* set if int generated in MMC RX CHECKSUM OFFLOAD int register */ ++ GmacMmcTxIntSts = 0x00000040, /* set if int generated in MMC TX Int register */ ++ GmacMmcRxIntSts = 0x00000020, /* set if int generated in MMC RX Int register */ ++ GmacMmcIntSts = 0x00000010, /* set if any of the above bit [7:5] is set */ ++ GmacPmtIntSts = 0x00000008, /* set whenver magic pkt/wake-on-lan frame is received */ ++ GmacPcsAnComplete = 0x00000004, /* set when AN is complete in TBI/RTBI/SGMIII phy interface */ ++ GmacPcsLnkStsChange = 0x00000002, /* set if any lnk status change in TBI/RTBI/SGMII interface */ ++ GmacRgmiiIntSts = 0x00000001, /* set if any change in lnk status of RGMII interface */ ++ ++}; ++ ++/* GmacInterruptMask = 0x003C, Mac Interrupt Mask register */ ++enum GmacInterruptMaskBitDefinition ++{ ++ GmacTSIntMask = 0x00000200, /* when set disables the time stamp interrupt generation */ ++ GmacPmtIntMask = 0x00000008, /* when set Disables the assertion of PMT interrupt */ ++ GmacPcsAnIntMask = 0x00000004, /* When set disables the assertion of PCS AN complete interrupt */ ++ GmacPcsLnkStsIntMask = 0x00000002, /* when set disables the assertion of PCS lnk status change interrupt */ ++ GmacRgmiiIntMask = 0x00000001, /* when set disables the assertion of RGMII int */ ++}; ++ ++/********************************************************** ++ * GMAC DMA registers ++ * For Pci based system address is BARx + GmaDmaBase ++ * For any other system translation is done accordingly ++ **********************************************************/ ++ ++enum DmaRegisters ++{ ++ DmaBusMode = 0x0000, /* CSR0 - Bus Mode Register */ ++ DmaTxPollDemand = 0x0004, /* CSR1 - Transmit Poll Demand Register */ ++ DmaRxPollDemand = 0x0008, /* CSR2 - Receive Poll Demand Register */ ++ DmaRxBaseAddr = 0x000C, /* CSR3 - Receive Descriptor list base address */ ++ DmaTxBaseAddr = 0x0010, /* CSR4 - Transmit Descriptor list base address */ ++ DmaStatus = 0x0014, /* CSR5 - Dma status Register */ ++ DmaControl = 0x0018, /* CSR6 - Dma Operation Mode Register */ ++ DmaInterrupt = 0x001C, /* CSR7 - Interrupt enable */ ++ DmaMissedFr = 0x0020, /* CSR8 - Missed Frame & Buffer overflow Counter */ ++ DmaTxCurrDesc = 0x0048, /* - Current host Tx Desc Register */ ++ DmaRxCurrDesc = 0x004C, /* - Current host Rx Desc Register */ ++ DmaTxCurrAddr = 0x0050, /* CSR20 - Current host transmit buffer address */ ++ DmaRxCurrAddr = 0x0054, /* CSR21 - Current host receive buffer address */ ++ ++#ifdef AVB_SUPPORT ++ HwFeature = 0x0058, /* Hardware Feature Register */ ++ ++ DmaSlotFnCtrlSts = 0x0030, /* Slot function control and status register */ ++ ++ DmaChannelCtrl = 0x0060, /* Channel Control register only for Channel1 and Channel2 */ ++ DmaChannelAvSts = 0x0064, /* Channel Status register only for Channel1 and Channel2 */ ++ IdleSlopeCredit = 0x0068, /* Idle slope credit register */ ++ SendSlopeCredit = 0x006C, /* Send slope credit register */ ++ HighCredit = 0x0070, /* High Credit register */ ++ LoCredit = 0x0074, /* Lo Credit Register */ ++#endif ++ ++}; ++ ++/********************************************************** ++ * DMA Engine registers Layout ++ **********************************************************/ ++ ++/*DmaBusMode = 0x0000, CSR0 - Bus Mode */ ++enum DmaBusModeReg ++{ ++ /* Bit description Bits R/W Reset value */ ++#ifdef AVB_SUPPORT ++ DmaChannelPrioWt = 0x30000000, /* Channel priority weight mask 29:28 RW 0 */ ++ DmaChannelPrio1 = 0x00000000, /* Channel priority weight 1 29:28 RW 0 */ ++ DmaChannelPrio2 = 0x10000000, /* Channel priority weight 2 29:28 RW 0 */ ++ DmaChannelPrio3 = 0x20000000, /* Channel priority weight 3 29:28 RW 0 */ ++ DmaChannelPrio4 = 0x30000000, /* Channel priority weight 4 29:28 RW 0 */ ++ ++ DmaTxRxPrio = 0x08000000, /* When set indicates Tx Dma has more priority 27 RW 0 */ ++ ++ DmaPriorityRatio11 = 0x00000000, /* (PR)TX:RX DMA priority ratio 1:1 15:14 RW 00 */ ++ DmaPriorityRatio21 = 0x00004000, /* (PR)TX:RX DMA priority ratio 2:1 */ ++ DmaPriorityRatio31 = 0x00008000, /* (PR)TX:RX DMA priority ratio 3:1 */ ++ DmaPriorityRatio41 = 0x0000C000, /* (PR)TX:RX DMA priority ratio 4:1 */ ++ ++ DmaArbitration = 0x00000002, /* Dma Arbitration decides whether strict prio or RR 1 RW 0 */ ++ DmaArbitrationStrict = 0x00000002, /* Dma Arbitration decides whether strict prio or RR 1 RW 0 */ ++ DmaArbitrationRR = 0x00000000, /* Dma Arbitration decides whether strict prio or RR 0 RW 0 */ ++#endif ++ ++ ++ DmaFixedBurstEnable = 0x00010000, /* (FB)Fixed Burst SINGLE, INCR4, INCR8 or INCR16 16 RW */ ++ DmaFixedBurstDisable = 0x00000000, /* SINGLE, INCR 0 */ ++ ++ DmaTxPriorityRatio11 = 0x00000000, /* (PR)TX:RX DMA priority ratio 1:1 15:14 RW 00 */ ++ DmaTxPriorityRatio21 = 0x00004000, /* (PR)TX:RX DMA priority ratio 2:1 */ ++ DmaTxPriorityRatio31 = 0x00008000, /* (PR)TX:RX DMA priority ratio 3:1 */ ++ DmaTxPriorityRatio41 = 0x0000C000, /* (PR)TX:RX DMA priority ratio 4:1 */ ++ ++ DmaBurstLengthx8 = 0x01000000, /* When set mutiplies the PBL by 8 24 RW 0 */ ++ ++ DmaBurstLength256 = 0x01002000, /*(DmaBurstLengthx8 | DmaBurstLength32) = 256 [24]:13:8 */ ++ DmaBurstLength128 = 0x01001000, /*(DmaBurstLengthx8 | DmaBurstLength16) = 128 [24]:13:8 */ ++ DmaBurstLength64 = 0x01000800, /*(DmaBurstLengthx8 | DmaBurstLength8) = 64 [24]:13:8 */ ++ DmaBurstLength32 = 0x00002000, /* (PBL) programmable Dma burst length = 32 13:8 RW */ ++ DmaBurstLength16 = 0x00001000, /* Dma burst length = 16 */ ++ DmaBurstLength8 = 0x00000800, /* Dma burst length = 8 */ ++ DmaBurstLength4 = 0x00000400, /* Dma burst length = 4 */ ++ DmaBurstLength2 = 0x00000200, /* Dma burst length = 2 */ ++ DmaBurstLength1 = 0x00000100, /* Dma burst length = 1 */ ++ DmaBurstLength0 = 0x00000000, /* Dma burst length = 0 0x00 */ ++ ++ DmaDescriptor8Words = 0x00000080, /* Enh Descriptor works 1=> 8 word descriptor 7 0 */ ++ DmaDescriptor4Words = 0x00000000, /* Enh Descriptor works 0=> 4 word descriptor 7 0 */ ++ ++ DmaDescriptorSkip16 = 0x00000040, /* (DSL)Descriptor skip length (no.of dwords) 6:2 RW */ ++ DmaDescriptorSkip8 = 0x00000020, /* between two unchained descriptors */ ++ DmaDescriptorSkip4 = 0x00000010, /* */ ++ DmaDescriptorSkip2 = 0x00000008, /* */ ++ DmaDescriptorSkip1 = 0x00000004, /* */ ++ DmaDescriptorSkip0 = 0x00000000, /* 0x00 */ ++ ++ DmaArbitRr = 0x00000000, /* (DA) DMA RR arbitration 1 RW 0 */ ++ DmaArbitPr = 0x00000002, /* Rx has priority over Tx */ ++ ++ DmaResetOn = 0x00000001, /* (SWR)Software Reset DMA engine 0 RW */ ++ DmaResetOff = 0x00000000, /* 0 */ ++}; ++ ++ ++/*DmaStatus = 0x0014, CSR5 - Dma status Register */ ++enum DmaStatusReg ++{ ++ /*Bit 28 27 and 26 indicate whether the interrupt due to PMT GMACMMC or GMAC LINE Remaining bits are DMA interrupts*/ ++ ++#ifdef AVB_SUPPORT ++ DmaSlotCounterIntr = 0x40000000, /* For Ch1 and Ch2 AVB slot interrupt status 31 RW 0 */ ++#endif ++#ifdef LPI_SUPPORT ++ GmacLPIIntr = 0x40000000, /* GMC LPI interrupt 31 RO 0 */ ++#endif ++ ++ GmacPmtIntr = 0x10000000, /* (GPI)Gmac subsystem interrupt 28 RO 0 */ ++ GmacMmcIntr = 0x08000000, /* (GMI)Gmac MMC subsystem interrupt 27 RO 0 */ ++ GmacLineIntfIntr = 0x04000000, /* Line interface interrupt 26 RO 0 */ ++ ++ DmaErrorBit2 = 0x02000000, /* (EB)Error bits 0-data buffer, 1-desc. access 25 RO 0 */ ++ DmaErrorBit1 = 0x01000000, /* (EB)Error bits 0-write trnsf, 1-read transfr 24 RO 0 */ ++ DmaErrorBit0 = 0x00800000, /* (EB)Error bits 0-Rx DMA, 1-Tx DMA 23 RO 0 */ ++ ++ DmaTxState = 0x00700000, /* (TS)Transmit process state 22:20 RO */ ++ DmaTxStopped = 0x00000000, /* Stopped - Reset or Stop Tx Command issued 000 */ ++ DmaTxFetching = 0x00100000, /* Running - fetching the Tx descriptor */ ++ DmaTxWaiting = 0x00200000, /* Running - waiting for status */ ++ DmaTxReading = 0x00300000, /* Running - reading the data from host memory */ ++ DmaTxSuspended = 0x00600000, /* Suspended - Tx Descriptor unavailabe */ ++ DmaTxClosing = 0x00700000, /* Running - closing Rx descriptor */ ++ ++ DmaRxState = 0x000E0000, /* (RS)Receive process state 19:17 RO */ ++ DmaRxStopped = 0x00000000, /* Stopped - Reset or Stop Rx Command issued 000 */ ++ DmaRxFetching = 0x00020000, /* Running - fetching the Rx descriptor */ ++ DmaRxWaiting = 0x00060000, /* Running - waiting for packet */ ++ DmaRxSuspended = 0x00080000, /* Suspended - Rx Descriptor unavailable */ ++ DmaRxClosing = 0x000A0000, /* Running - closing descriptor */ ++ DmaRxQueuing = 0x000E0000, /* Running - queuing the recieve frame into host memory */ ++ ++ DmaIntNormal = 0x00010000, /* (NIS)Normal interrupt summary 16 RW 0 */ ++ DmaIntAbnormal = 0x00008000, /* (AIS)Abnormal interrupt summary 15 RW 0 */ ++ ++ DmaIntEarlyRx = 0x00004000, /* Early receive interrupt (Normal) RW 0 */ ++ DmaIntBusError = 0x00002000, /* Fatal bus error (Abnormal) RW 0 */ ++ DmaIntEarlyTx = 0x00000400, /* Early transmit interrupt (Abnormal) RW 0 */ ++ DmaIntRxWdogTO = 0x00000200, /* Receive Watchdog Timeout (Abnormal) RW 0 */ ++ DmaIntRxStopped = 0x00000100, /* Receive process stopped (Abnormal) RW 0 */ ++ DmaIntRxNoBuffer = 0x00000080, /* Receive buffer unavailable (Abnormal) RW 0 */ ++ DmaIntRxCompleted = 0x00000040, /* Completion of frame reception (Normal) RW 0 */ ++ DmaIntTxUnderflow = 0x00000020, /* Transmit underflow (Abnormal) RW 0 */ ++ DmaIntRcvOverflow = 0x00000010, /* Receive Buffer overflow interrupt RW 0 */ ++ DmaIntTxJabberTO = 0x00000008, /* Transmit Jabber Timeout (Abnormal) RW 0 */ ++ DmaIntTxNoBuffer = 0x00000004, /* Transmit buffer unavailable (Normal) RW 0 */ ++ DmaIntTxStopped = 0x00000002, /* Transmit process stopped (Abnormal) RW 0 */ ++ DmaIntTxCompleted = 0x00000001, /* Transmit completed (Normal) RW 0 */ ++}; ++ ++/*DmaControl = 0x0018, CSR6 - Dma Operation Mode Register */ ++enum DmaControlReg ++{ ++ DmaDisableDropTcpCs = 0x04000000, /* (DT) Dis. drop. of tcp/ip CS error frames 26 RW 0 */ ++ ++ DmaStoreAndForward = 0x00200000, /* (SF)Store and forward 21 RW 0 */ ++ DmaFlushTxFifo = 0x00100000, /* (FTF)Tx FIFO controller is reset to default 20 RW 0 */ ++ ++ DmaTxThreshCtrl = 0x0001C000, /* (TTC)Controls thre Threh of MTL tx Fifo 16:14 RW */ ++ DmaTxThreshCtrl16 = 0x0001C000, /* (TTC)Controls thre Threh of MTL tx Fifo 16 16:14 RW */ ++ DmaTxThreshCtrl24 = 0x00018000, /* (TTC)Controls thre Threh of MTL tx Fifo 24 16:14 RW */ ++ DmaTxThreshCtrl32 = 0x00014000, /* (TTC)Controls thre Threh of MTL tx Fifo 32 16:14 RW */ ++ DmaTxThreshCtrl40 = 0x00010000, /* (TTC)Controls thre Threh of MTL tx Fifo 40 16:14 RW */ ++ DmaTxThreshCtrl256 = 0x0000c000, /* (TTC)Controls thre Threh of MTL tx Fifo 256 16:14 RW */ ++ DmaTxThreshCtrl192 = 0x00008000, /* (TTC)Controls thre Threh of MTL tx Fifo 192 16:14 RW */ ++ DmaTxThreshCtrl128 = 0x00004000, /* (TTC)Controls thre Threh of MTL tx Fifo 128 16:14 RW */ ++ DmaTxThreshCtrl64 = 0x00000000, /* (TTC)Controls thre Threh of MTL tx Fifo 64 16:14 RW 000 */ ++ ++ DmaTxStart = 0x00002000, /* (ST)Start/Stop transmission 13 RW 0 */ ++ ++ DmaRxFlowCtrlDeact = 0x00401800, /* (RFD)Rx flow control deact. threhold [22]:12:11 RW */ ++ DmaRxFlowCtrlDeact1K = 0x00000000, /* (RFD)Rx flow control deact. threhold (1kbytes) [22]:12:11 RW 00 */ ++ DmaRxFlowCtrlDeact2K = 0x00000800, /* (RFD)Rx flow control deact. threhold (2kbytes) [22]:12:11 RW */ ++ DmaRxFlowCtrlDeact3K = 0x00001000, /* (RFD)Rx flow control deact. threhold (3kbytes) [22]:12:11 RW */ ++ DmaRxFlowCtrlDeact4K = 0x00001800, /* (RFD)Rx flow control deact. threhold (4kbytes) [22]:12:11 RW */ ++ DmaRxFlowCtrlDeact5K = 0x00400000, /* (RFD)Rx flow control deact. threhold (4kbytes) [22]:12:11 RW */ ++ DmaRxFlowCtrlDeact6K = 0x00400800, /* (RFD)Rx flow control deact. threhold (4kbytes) [22]:12:11 RW */ ++ DmaRxFlowCtrlDeact7K = 0x00401000, /* (RFD)Rx flow control deact. threhold (4kbytes) [22]:12:11 RW */ ++ ++ DmaRxFlowCtrlAct = 0x00800600, /* (RFA)Rx flow control Act. threhold [23]:10:09 RW */ ++ DmaRxFlowCtrlAct1K = 0x00000000, /* (RFA)Rx flow control Act. threhold (1kbytes) [23]:10:09 RW 00 */ ++ DmaRxFlowCtrlAct2K = 0x00000200, /* (RFA)Rx flow control Act. threhold (2kbytes) [23]:10:09 RW */ ++ DmaRxFlowCtrlAct3K = 0x00000400, /* (RFA)Rx flow control Act. threhold (3kbytes) [23]:10:09 RW */ ++ DmaRxFlowCtrlAct4K = 0x00000300, /* (RFA)Rx flow control Act. threhold (4kbytes) [23]:10:09 RW */ ++ DmaRxFlowCtrlAct5K = 0x00800000, /* (RFA)Rx flow control Act. threhold (5kbytes) [23]:10:09 RW */ ++ DmaRxFlowCtrlAct6K = 0x00800200, /* (RFA)Rx flow control Act. threhold (6kbytes) [23]:10:09 RW */ ++ DmaRxFlowCtrlAct7K = 0x00800400, /* (RFA)Rx flow control Act. threhold (7kbytes) [23]:10:09 RW */ ++ ++ DmaRxThreshCtrl = 0x00000018, /* (RTC)Controls thre Threh of MTL rx Fifo 4:3 RW */ ++ DmaRxThreshCtrl64 = 0x00000000, /* (RTC)Controls thre Threh of MTL tx Fifo 64 4:3 RW */ ++ DmaRxThreshCtrl32 = 0x00000008, /* (RTC)Controls thre Threh of MTL tx Fifo 32 4:3 RW */ ++ DmaRxThreshCtrl96 = 0x00000010, /* (RTC)Controls thre Threh of MTL tx Fifo 96 4:3 RW */ ++ DmaRxThreshCtrl128 = 0x00000018, /* (RTC)Controls thre Threh of MTL tx Fifo 128 4:3 RW */ ++ ++ DmaEnHwFlowCtrl = 0x00000100, /* (EFC)Enable HW flow control 8 RW */ ++ DmaDisHwFlowCtrl = 0x00000000, /* Disable HW flow control 0 */ ++ ++ DmaFwdErrorFrames = 0x00000080, /* (FEF)Forward error frames 7 RW 0 */ ++ DmaFwdUnderSzFrames = 0x00000040, /* (FUF)Forward undersize frames 6 RW 0 */ ++ DmaTxSecondFrame = 0x00000004, /* (OSF)Operate on second frame 4 RW 0 */ ++ DmaRxStart = 0x00000002, /* (SR)Start/Stop reception 1 RW 0 */ ++}; ++ ++ ++/*DmaInterrupt = 0x001C, CSR7 - Interrupt enable Register Layout */ ++enum DmaInterruptReg ++{ ++ DmaIeNormal = DmaIntNormal , /* Normal interrupt enable RW 0 */ ++ DmaIeAbnormal = DmaIntAbnormal , /* Abnormal interrupt enable RW 0 */ ++ ++ DmaIeEarlyRx = DmaIntEarlyRx , /* Early receive interrupt enable RW 0 */ ++ DmaIeBusError = DmaIntBusError , /* Fatal bus error enable RW 0 */ ++ DmaIeEarlyTx = DmaIntEarlyTx , /* Early transmit interrupt enable RW 0 */ ++ DmaIeRxWdogTO = DmaIntRxWdogTO , /* Receive Watchdog Timeout enable RW 0 */ ++ DmaIeRxStopped = DmaIntRxStopped , /* Receive process stopped enable RW 0 */ ++ DmaIeRxNoBuffer = DmaIntRxNoBuffer , /* Receive buffer unavailable enable RW 0 */ ++ DmaIeRxCompleted = DmaIntRxCompleted, /* Completion of frame reception enable RW 0 */ ++ DmaIeTxUnderflow = DmaIntTxUnderflow, /* Transmit underflow enable RW 0 */ ++ ++ DmaIeRxOverflow = DmaIntRcvOverflow, /* Receive Buffer overflow interrupt RW 0 */ ++ DmaIeTxJabberTO = DmaIntTxJabberTO , /* Transmit Jabber Timeout enable RW 0 */ ++ DmaIeTxNoBuffer = DmaIntTxNoBuffer , /* Transmit buffer unavailable enable RW 0 */ ++ DmaIeTxStopped = DmaIntTxStopped , /* Transmit process stopped enable RW 0 */ ++ DmaIeTxCompleted = DmaIntTxCompleted, /* Transmit completed enable RW 0 */ ++}; ++ ++#ifdef AVB_SUPPORT ++/*DmaSlotFnCtrlSts = 0x0030, Slot function control and status register */ ++enum DmaSlotFnCtrlStsReg ++{ ++ SlotNum = 0x000F0000, /* Current Slot Number 19:16 R0 0 */ ++ AdvSlotInt = 0x00000002, /* Advance the slot interval for data fetch 1 RW 0 */ ++ EnaSlot = 0x00000001, /* Enable checking of Slot number 0 RW 0 */ ++}; ++ ++/* DmaChannelCtrl = 0x0060, Channel Control register only for Channel1 and Channel2 */ ++enum DmaChannelCtrlReg ++{ ++ ChannelSlotIntEn = 0x00020000, /* Channel Slot Interrupt Enable 16 RW 0 */ ++ ChannelSlotCount = 0x00000070, /* Channel Slot Count 6:4 RW 0 */ ++ ChannelCreditCtrl = 0x00000002, /* Channel Credit Control 1 RW 0 */ ++ ChannelCreditShDis = 0x00000001, /* Channel Credit based shaping disable 0 RW 0 */ ++}; ++ ++/* DmaChannelSts = 0x0064, Channel Status register only for Channel1 and Channel2 */ ++enum DmaChannelStsReg ++{ ++ ChannelAvBitsPerSlot = 0x0000FFFF, /* Channel Average Bits per slot 16:0 RO 0 */ ++}; ++ ++/* IdleSlopeCredit = 0x0068, Idle slope credit register */ ++enum IdleSlopeCreditReg ++{ ++ ChannelIdleSlCr = 0x00003FFF, /*Channel Idle Slope Credit 13:0 RW 0 */ ++}; ++ ++/*SendSlopeCredit = 0x006C, Send slope credit register */ ++enum SendSlopeCreditReg ++{ ++ ChannelSendSlCr = 0x00003FFF, /*Channel Send Slope Credit 13:0 RW 0 */ ++}; ++ ++/* HighCredit = 0x0070, High Credit register */ ++enum HighCreditReg ++{ ++ ChannelHiCr = 0x1FFFFFFF, /*Channel Hi Credit 28:0 RW 0 */ ++}; ++ ++/* LoCredit = 0x0074, Lo Credit Register */ ++enum LoCreditReg ++{ ++ ChannelLoCr = 0x1FFFFFFF, /* Channel Lo Credit 28:0 RW 0 */ ++}; ++/*DmaChannelAvSts */ ++enum DmaChannelAvStsReg ++{ ++ ChannelAvgBitsPerSlotMsk = 0x0001FFFF, ++}; ++#endif ++ ++/********************************************************** ++ * DMA Engine descriptors ++ **********************************************************/ ++#ifdef ENH_DESC ++/* ++ **********Enhanced Descritpor structure to support 8K buffer per buffer **************************** ++ ++ DmaRxBaseAddr = 0x000C, CSR3 - Receive Descriptor list base address ++ DmaRxBaseAddr is the pointer to the first Rx Descriptors. the Descriptor format in Little endian with a ++ 32 bit Data bus is as shown below ++ ++ Similarly ++ DmaTxBaseAddr = 0x0010, CSR4 - Transmit Descriptor list base address ++ DmaTxBaseAddr is the pointer to the first Rx Descriptors. the Descriptor format in Little endian with a ++ 32 bit Data bus is as shown below ++ -------------------------------------------------------------------------- ++ RDES0 |OWN (31)| Status | ++ -------------------------------------------------------------------------- ++ RDES1 | Ctrl | Res | Byte Count Buffer 2 | Ctrl | Res | Byte Count Buffer 1 | ++ -------------------------------------------------------------------------- ++ RDES2 | Buffer 1 Address | ++ -------------------------------------------------------------------------- ++ RDES3 | Buffer 2 Address / Next Descriptor Address | ++ -------------------------------------------------------------------------- ++ ++ -------------------------------------------------------------------------- ++ TDES0 |OWN (31)| Ctrl | Res | Ctrl | Res | Status | ++ -------------------------------------------------------------------------- ++ TDES1 | Res | Byte Count Buffer 2 | Res | Byte Count Buffer 1 | ++ -------------------------------------------------------------------------- ++ TDES2 | Buffer 1 Address | ++ -------------------------------------------------------------------------- ++ TDES3 | Buffer 2 Address / Next Descriptor Address | ++ -------------------------------------------------------------------------- ++ ++*/ ++ ++enum DmaDescriptorStatus /* status word of DMA descriptor */ ++{ ++ ++ DescOwnByDma = 0x80000000, /* (OWN)Descriptor is owned by DMA engine 31 RW */ ++ ++ DescDAFilterFail = 0x40000000, /* (AFM)Rx - DA Filter Fail for the rx frame 30 */ ++ ++ DescFrameLengthMask = 0x3FFF0000, /* (FL)Receive descriptor frame length 29:16 */ ++ DescFrameLengthShift = 16, ++ ++ DescError = 0x00008000, /* (ES)Error summary bit - OR of the follo. bits: 15 */ ++ /* DE || OE || IPC || LC || RWT || RE || CE */ ++ DescRxTruncated = 0x00004000, /* (DE)Rx - no more descriptors for receive frame 14 */ ++ DescSAFilterFail = 0x00002000, /* (SAF)Rx - SA Filter Fail for the received frame 13 */ ++ DescRxLengthError = 0x00001000, /* (LE)Rx - frm size not matching with len field 12 */ ++ DescRxDamaged = 0x00000800, /* (OE)Rx - frm was damaged due to buffer overflow 11 */ ++ DescRxVLANTag = 0x00000400, /* (VLAN)Rx - received frame is a VLAN frame 10 */ ++ DescRxFirst = 0x00000200, /* (FS)Rx - first descriptor of the frame 9 */ ++ DescRxLast = 0x00000100, /* (LS)Rx - last descriptor of the frame 8 */ ++ DescRxLongFrame = 0x00000080, /* (Giant Frame)Rx - frame is longer than 1518/1522 7 */ ++ DescRxCollision = 0x00000040, /* (LC)Rx - late collision occurred during reception 6 */ ++ DescRxFrameEther = 0x00000020, /* (FT)Rx - Frame type - Ethernet, otherwise 802.3 5 */ ++ DescRxWatchdog = 0x00000010, /* (RWT)Rx - watchdog timer expired during reception 4 */ ++ DescRxMiiError = 0x00000008, /* (RE)Rx - error reported by MII interface 3 */ ++ DescRxDribbling = 0x00000004, /* (DE)Rx - frame contains non int multiple of 8 bits 2 */ ++ DescRxCrc = 0x00000002, /* (CE)Rx - CRC error 1 */ ++ // DescRxMacMatch = 0x00000001, /* (RX MAC Address) Rx mac address reg(1 to 15)match 0 */ ++ ++ DescRxEXTsts = 0x00000001, /* Extended Status Available (RDES4) 0 */ ++ ++ DescTxIntEnable = 0x40000000, /* (IC)Tx - interrupt on completion 30 */ ++ DescTxLast = 0x20000000, /* (LS)Tx - Last segment of the frame 29 */ ++ DescTxFirst = 0x10000000, /* (FS)Tx - First segment of the frame 28 */ ++ DescTxDisableCrc = 0x08000000, /* (DC)Tx - Add CRC disabled (first segment only) 27 */ ++ DescTxDisablePadd = 0x04000000, /* (DP)disable padding, added by - reyaz 26 */ ++ ++ DescTxCisMask = 0x00c00000, /* Tx checksum offloading control mask 23:22 */ ++ DescTxCisBypass = 0x00000000, /* Checksum bypass */ ++ DescTxCisIpv4HdrCs = 0x00400000, /* IPv4 header checksum */ ++ DescTxCisTcpOnlyCs = 0x00800000, /* TCP/UDP/ICMP checksum. Pseudo header checksum is assumed to be present */ ++ DescTxCisTcpPseudoCs = 0x00c00000, /* TCP/UDP/ICMP checksum fully in hardware including pseudo header */ ++ ++ TxDescEndOfRing = 0x00200000, /* (TER)End of descriptors ring 21 */ ++ TxDescChain = 0x00100000, /* (TCH)Second buffer address is chain address 20 */ ++ ++ DescRxChkBit0 = 0x00000001, /*() Rx - Rx Payload Checksum Error 0 */ ++ DescRxChkBit7 = 0x00000080, /* (IPC CS ERROR)Rx - Ipv4 header checksum error 7 */ ++ DescRxChkBit5 = 0x00000020, /* (FT)Rx - Frame type - Ethernet, otherwise 802.3 5 */ ++ ++ DescRxTSavail = 0x00000080, /* Time stamp available 7 */ ++ DescRxFrameType = 0x00000020, /* (FT)Rx - Frame type - Ethernet, otherwise 802.3 5 */ ++ ++ DescTxIpv4ChkError = 0x00010000, /* (IHE) Tx Ip header error 16 */ ++ DescTxTimeout = 0x00004000, /* (JT)Tx - Transmit jabber timeout 14 */ ++ DescTxFrameFlushed = 0x00002000, /* (FF)Tx - DMA/MTL flushed the frame due to SW flush 13 */ ++ DescTxPayChkError = 0x00001000, /* (PCE) Tx Payload checksum Error 12 */ ++ DescTxLostCarrier = 0x00000800, /* (LC)Tx - carrier lost during tramsmission 11 */ ++ DescTxNoCarrier = 0x00000400, /* (NC)Tx - no carrier signal from the tranceiver 10 */ ++ DescTxLateCollision = 0x00000200, /* (LC)Tx - transmission aborted due to collision 9 */ ++ DescTxExcCollisions = 0x00000100, /* (EC)Tx - transmission aborted after 16 collisions 8 */ ++ DescTxVLANFrame = 0x00000080, /* (VF)Tx - VLAN-type frame 7 */ ++ ++ DescTxCollMask = 0x00000078, /* (CC)Tx - Collision count 6:3 */ ++ DescTxCollShift = 3, ++ ++ DescTxExcDeferral = 0x00000004, /* (ED)Tx - excessive deferral 2 */ ++ DescTxUnderflow = 0x00000002, /* (UF)Tx - late data arrival from the memory 1 */ ++ DescTxDeferred = 0x00000001, /* (DB)Tx - frame transmision deferred 0 */ ++ ++ /* ++ This explains the RDES1/TDES1 bits layout ++ -------------------------------------------------------------------- ++ RDES1/TDES1 | Control Bits | Byte Count Buffer 2 | Byte Count Buffer 1 | ++ -------------------------------------------------------------------- ++ ++*/ ++ // DmaDescriptorLength length word of DMA descriptor ++ ++ ++ RxDisIntCompl = 0x80000000, /* (Disable Rx int on completion) 31 */ ++ RxDescEndOfRing = 0x00008000, /* (TER)End of descriptors ring 15 */ ++ RxDescChain = 0x00004000, /* (TCH)Second buffer address is chain address 14 */ ++ ++ ++ DescSize2Mask = 0x1FFF0000, /* (TBS2) Buffer 2 size 28:16 */ ++ DescSize2Shift = 16, ++ DescSize1Mask = 0x00001FFF, /* (TBS1) Buffer 1 size 12:0 */ ++ DescSize1Shift = 0, ++ ++ ++ /* ++ This explains the RDES4 Extended Status bits layout ++ -------------------------------------------------------------------- ++ RDES4 | Extended Status | ++ -------------------------------------------------------------------- ++ */ ++ ++#ifdef AVB_SUPPORT ++ DescRxVlanPrioVal = 0x001C0000, /* Gives the VLAN Priority Value 20:18 */ ++ DescRxVlanPrioShVal = 18, /* Gives the shift value to get priority value in LS bits */ ++ ++ DescRxAvTagPktRx = 0x00020000, /* Indicates AV tagged Packet is received 17 */ ++ DescRxAvPktRx = 0x00010000, /* Indicates AV Packet received 16 */ ++ ++#endif ++ ++ DescRxPtpAvail = 0x00004000, /* PTP snapshot available 14 */ ++ DescRxPtpVer = 0x00002000, /* When set indicates IEEE1584 Version 2 (else Ver1) 13 */ ++ DescRxPtpFrameType = 0x00001000, /* PTP frame type Indicates PTP sent over ethernet 12 */ ++ DescRxPtpMessageType = 0x00000F00, /* Message Type 11:8 */ ++ DescRxPtpNo = 0x00000000, /* 0000 => No PTP message received */ ++ DescRxPtpSync = 0x00000100, /* 0001 => Sync (all clock types) received */ ++ DescRxPtpFollowUp = 0x00000200, /* 0010 => Follow_Up (all clock types) received */ ++ DescRxPtpDelayReq = 0x00000300, /* 0011 => Delay_Req (all clock types) received */ ++ DescRxPtpDelayResp = 0x00000400, /* 0100 => Delay_Resp (all clock types) received */ ++ DescRxPtpPdelayReq = 0x00000500, /* 0101 => Pdelay_Req (in P to P tras clk) or Announce in Ord and Bound clk */ ++ DescRxPtpPdelayResp = 0x00000600, /* 0110 => Pdealy_Resp(in P to P trans clk) or Management in Ord and Bound clk */ ++ DescRxPtpPdelayRespFP = 0x00000700, /* 0111 => Pdealy_Resp_Follow_Up (in P to P trans clk) or Signaling in Ord and Bound clk */ ++ DescRxPtpIPV6 = 0x00000080, /* Received Packet is in IPV6 Packet 7 */ ++ DescRxPtpIPV4 = 0x00000040, /* Received Packet is in IPV4 Packet 6 */ ++ ++ DescRxChkSumBypass = 0x00000020, /* When set indicates checksum offload engine 5 ++ is bypassed */ ++ DescRxIpPayloadError = 0x00000010, /* When set indicates 16bit IP payload CS is in error 4 */ ++ DescRxIpHeaderError = 0x00000008, /* When set indicates 16bit IPV4 header CS is in 3 ++ error or IP datagram version is not consistent ++ with Ethernet type value */ ++ DescRxIpPayloadType = 0x00000007, /* Indicate the type of payload encapsulated 2:0 ++ in IPdatagram processed by COE (Rx) */ ++ DescRxIpPayloadUnknown= 0x00000000, /* Unknown or didnot process IP payload */ ++ DescRxIpPayloadUDP = 0x00000001, /* UDP */ ++ DescRxIpPayloadTCP = 0x00000002, /* TCP */ ++ DescRxIpPayloadICMP = 0x00000003, /* ICMP */ ++ ++}; ++ ++#else ++/* ++ ++ ********** Default Descritpor structure **************************** ++ DmaRxBaseAddr = 0x000C, CSR3 - Receive Descriptor list base address ++ DmaRxBaseAddr is the pointer to the first Rx Descriptors. the Descriptor format in Little endian with a ++ 32 bit Data bus is as shown below ++ ++ Similarly ++ DmaTxBaseAddr = 0x0010, CSR4 - Transmit Descriptor list base address ++ DmaTxBaseAddr is the pointer to the first Rx Descriptors. the Descriptor format in Little endian with a ++ 32 bit Data bus is as shown below ++ -------------------------------------------------------------------- ++ RDES0/TDES0 |OWN (31)| Status | ++ -------------------------------------------------------------------- ++ RDES1/TDES1 | Control Bits | Byte Count Buffer 2 | Byte Count Buffer 1 | ++ -------------------------------------------------------------------- ++ RDES2/TDES2 | Buffer 1 Address | ++ -------------------------------------------------------------------- ++ RDES3/TDES3 | Buffer 2 Address / Next Descriptor Address | ++ -------------------------------------------------------------------- ++ */ ++enum DmaDescriptorStatus /* status word of DMA descriptor */ ++{ ++ DescOwnByDma = 0x80000000, /* (OWN)Descriptor is owned by DMA engine 31 RW */ ++ ++ DescDAFilterFail = 0x40000000, /* (AFM)Rx - DA Filter Fail for the rx frame 30 */ ++ ++ DescFrameLengthMask = 0x3FFF0000, /* (FL)Receive descriptor frame length 29:16 */ ++ DescFrameLengthShift = 16, ++ ++ DescError = 0x00008000, /* (ES)Error summary bit - OR of the follo. bits: 15 */ ++ /* DE || OE || IPC || LC || RWT || RE || CE */ ++ DescRxTruncated = 0x00004000, /* (DE)Rx - no more descriptors for receive frame 14 */ ++ DescSAFilterFail = 0x00002000, /* (SAF)Rx - SA Filter Fail for the received frame 13 */ ++ DescRxLengthError = 0x00001000, /* (LE)Rx - frm size not matching with len field 12 */ ++ DescRxDamaged = 0x00000800, /* (OE)Rx - frm was damaged due to buffer overflow 11 */ ++ DescRxVLANTag = 0x00000400, /* (VLAN)Rx - received frame is a VLAN frame 10 */ ++ DescRxFirst = 0x00000200, /* (FS)Rx - first descriptor of the frame 9 */ ++ DescRxLast = 0x00000100, /* (LS)Rx - last descriptor of the frame 8 */ ++ DescRxLongFrame = 0x00000080, /* (Giant Frame)Rx - frame is longer than 1518/1522 7 */ ++ DescRxCollision = 0x00000040, /* (LC)Rx - late collision occurred during reception 6 */ ++ DescRxFrameEther = 0x00000020, /* (FT)Rx - Frame type - Ethernet, otherwise 802.3 5 */ ++ DescRxWatchdog = 0x00000010, /* (RWT)Rx - watchdog timer expired during reception 4 */ ++ DescRxMiiError = 0x00000008, /* (RE)Rx - error reported by MII interface 3 */ ++ DescRxDribbling = 0x00000004, /* (DE)Rx - frame contains non int multiple of 8 bits 2 */ ++ DescRxCrc = 0x00000002, /* (CE)Rx - CRC error 1 */ ++ DescRxMacMatch = 0x00000001, /* (RX MAC Address) Rx mac address reg(1 to 15)match 0 */ ++ ++ //Rx Descriptor Checksum Offload engine (type 2) encoding ++ //DescRxPayChkError = 0x00000001, /* () Rx - Rx Payload Checksum Error 0 */ ++ //DescRxIpv4ChkError = 0x00000080, /* (IPC CS ERROR)Rx - Ipv4 header checksum error 7 */ ++ ++ DescRxChkBit0 = 0x00000001, /*() Rx - Rx Payload Checksum Error 0 */ ++ DescRxChkBit7 = 0x00000080, /* (IPC CS ERROR)Rx - Ipv4 header checksum error 7 */ ++ DescRxChkBit5 = 0x00000020, /* (FT)Rx - Frame type - Ethernet, otherwise 802.3 5 */ ++ ++ DescTxIpv4ChkError = 0x00010000, /* (IHE) Tx Ip header error 16 */ ++ DescTxTimeout = 0x00004000, /* (JT)Tx - Transmit jabber timeout 14 */ ++ DescTxFrameFlushed = 0x00002000, /* (FF)Tx - DMA/MTL flushed the frame due to SW flush 13 */ ++ DescTxPayChkError = 0x00001000, /* (PCE) Tx Payload checksum Error 12 */ ++ DescTxLostCarrier = 0x00000800, /* (LC)Tx - carrier lost during tramsmission 11 */ ++ DescTxNoCarrier = 0x00000400, /* (NC)Tx - no carrier signal from the tranceiver 10 */ ++ DescTxLateCollision = 0x00000200, /* (LC)Tx - transmission aborted due to collision 9 */ ++ DescTxExcCollisions = 0x00000100, /* (EC)Tx - transmission aborted after 16 collisions 8 */ ++ DescTxVLANFrame = 0x00000080, /* (VF)Tx - VLAN-type frame 7 */ ++ ++ DescTxCollMask = 0x00000078, /* (CC)Tx - Collision count 6:3 */ ++ DescTxCollShift = 3, ++ ++ DescTxExcDeferral = 0x00000004, /* (ED)Tx - excessive deferral 2 */ ++ DescTxUnderflow = 0x00000002, /* (UF)Tx - late data arrival from the memory 1 */ ++ DescTxDeferred = 0x00000001, /* (DB)Tx - frame transmision deferred 0 */ ++ ++ /* ++ This explains the RDES1/TDES1 bits layout ++ -------------------------------------------------------------------- ++ RDES1/TDES1 | Control Bits | Byte Count Buffer 2 | Byte Count Buffer 1 | ++ -------------------------------------------------------------------- ++ ++*/ ++ //DmaDescriptorLength length word of DMA descriptor ++ ++ DescTxIntEnable = 0x80000000, /* (IC)Tx - interrupt on completion 31 */ ++ DescTxLast = 0x40000000, /* (LS)Tx - Last segment of the frame 30 */ ++ DescTxFirst = 0x20000000, /* (FS)Tx - First segment of the frame 29 */ ++ DescTxDisableCrc = 0x04000000, /* (DC)Tx - Add CRC disabled (first segment only) 26 */ ++ ++ RxDisIntCompl = 0x80000000, /* (Disable Rx int on completion) 31 */ ++ RxDescEndOfRing = 0x02000000, /* (TER)End of descriptors ring */ ++ RxDescChain = 0x01000000, /* (TCH)Second buffer address is chain address 24 */ ++ ++ DescTxDisablePadd = 0x00800000, /* (DP)disable padding, added by - reyaz 23 */ ++ ++ TxDescEndOfRing = 0x02000000, /* (TER)End of descriptors ring */ ++ TxDescChain = 0x01000000, /* (TCH)Second buffer address is chain address 24 */ ++ ++ DescSize2Mask = 0x003FF800, /* (TBS2) Buffer 2 size 21:11 */ ++ DescSize2Shift = 11, ++ DescSize1Mask = 0x000007FF, /* (TBS1) Buffer 1 size 10:0 */ ++ DescSize1Shift = 0, ++ ++ ++ DescTxCisMask = 0x18000000, /* Tx checksum offloading control mask 28:27 */ ++ DescTxCisBypass = 0x00000000, /* Checksum bypass */ ++ DescTxCisIpv4HdrCs = 0x08000000, /* IPv4 header checksum */ ++ DescTxCisTcpOnlyCs = 0x10000000, /* TCP/UDP/ICMP checksum. Pseudo header checksum is assumed to be present */ ++ DescTxCisTcpPseudoCs = 0x18000000, /* TCP/UDP/ICMP checksum fully in hardware including pseudo header */ ++}; ++#endif ++ ++// Rx Descriptor COE type2 encoding ++enum RxDescCOEEncode ++{ ++ RxLenLT600 = 0, /* Bit(5:7:0)=>0 IEEE 802.3 type frame Length field is Lessthan 0x0600 */ ++ RxIpHdrPayLoadChkBypass = 1, /* Bit(5:7:0)=>1 Payload & Ip header checksum bypassed (unsuppported payload) */ ++ RxIpHdrPayLoadRes = 2, /* Bit(5:7:0)=>2 Reserved */ ++ RxChkBypass = 3, /* Bit(5:7:0)=>3 Neither IPv4 nor IPV6. So checksum bypassed */ ++ RxNoChkError = 4, /* Bit(5:7:0)=>4 No IPv4/IPv6 Checksum error detected */ ++ RxPayLoadChkError = 5, /* Bit(5:7:0)=>5 Payload checksum error detected for Ipv4/Ipv6 frames */ ++ RxIpHdrChkError = 6, /* Bit(5:7:0)=>6 Ip header checksum error detected for Ipv4 frames */ ++ RxIpHdrPayLoadChkError = 7, /* Bit(5:7:0)=>7 Payload & Ip header checksum error detected for Ipv4/Ipv6 frames */ ++}; ++ ++/********************************************************** ++ * DMA engine interrupt handling functions ++ **********************************************************/ ++ ++enum synopGMACDmaIntEnum /* Intrerrupt types */ ++{ ++ synopGMACDmaRxNormal = 0x01, /* normal receiver interrupt */ ++ synopGMACDmaRxAbnormal = 0x02, /* abnormal receiver interrupt */ ++ synopGMACDmaRxStopped = 0x04, /* receiver stopped */ ++ synopGMACDmaTxNormal = 0x08, /* normal transmitter interrupt */ ++ synopGMACDmaTxAbnormal = 0x10, /* abnormal transmitter interrupt */ ++ synopGMACDmaTxStopped = 0x20, /* transmitter stopped */ ++ synopGMACDmaError = 0x80, /* Dma engine error */ ++ ++#ifdef AVB_SUPPORT ++ synopGMADmaSlotCounter = 0x40, /* Dma SlotCounter interrupt mask for Channel1 and Channel2*/ ++#endif ++}; ++ ++ ++/********************************************************** ++ * Initial register values ++ **********************************************************/ ++enum InitialRegisters ++{ ++ /* Full-duplex mode with perfect filter on */ ++ GmacConfigInitFdx1000 = GmacWatchdogEnable | GmacJabberEnable | GmacFrameBurstEnable | GmacJumboFrameDisable ++ | GmacSelectGmii | GmacEnableRxOwn | GmacLoopbackOff ++ | GmacFullDuplex | GmacRetryEnable | GmacPadCrcStripDisable ++ | GmacBackoffLimit0 | GmacDeferralCheckDisable | GmacTxEnable | GmacRxEnable, ++ ++ /* Full-duplex mode with perfect filter on */ ++ GmacConfigInitFdx110 = GmacWatchdogEnable | GmacJabberEnable | GmacFrameBurstEnable | GmacJumboFrameDisable ++ | GmacSelectMii | GmacEnableRxOwn | GmacLoopbackOff ++ | GmacFullDuplex | GmacRetryEnable | GmacPadCrcStripDisable ++ | GmacBackoffLimit0 | GmacDeferralCheckDisable | GmacTxEnable | GmacRxEnable, ++ ++ /* Full-duplex mode */ ++ // CHANGED: Pass control config, dest addr filter normal, added source address filter, multicast & unicast ++ // Hash filter. ++ /* = GmacFilterOff | GmacPassControlOff | GmacBroadcastEnable */ ++ GmacFrameFilterInitFdx = GmacFilterOn | GmacPassControl0 | GmacBroadcastEnable | GmacSrcAddrFilterDisable ++ | GmacMulticastFilterOn | GmacDestAddrFilterNor | GmacMcastHashFilterOff ++ | GmacPromiscuousModeOff | GmacUcastHashFilterOff, ++ ++ /* Full-duplex mode */ ++ GmacFlowControlInitFdx = GmacUnicastPauseFrameOff | GmacRxFlowControlEnable | GmacTxFlowControlEnable, ++ ++ /* Full-duplex mode */ ++ GmacGmiiAddrInitFdx = GmiiCsrClk2, ++ ++ ++ /* Half-duplex mode with perfect filter on */ ++ // CHANGED: Removed Endian configuration, added single bit config for PAD/CRC strip, ++ /*| GmacSelectMii | GmacLittleEndian | GmacDisableRxOwn | GmacLoopbackOff*/ ++ GmacConfigInitHdx1000 = GmacWatchdogEnable | GmacJabberEnable | GmacFrameBurstEnable | GmacJumboFrameDisable ++ | GmacSelectGmii | GmacDisableRxOwn | GmacLoopbackOff ++ | GmacHalfDuplex | GmacRetryEnable | GmacPadCrcStripDisable ++ | GmacBackoffLimit0 | GmacDeferralCheckDisable | GmacTxEnable | GmacRxEnable, ++ ++ /* Half-duplex mode with perfect filter on */ ++ GmacConfigInitHdx110 = GmacWatchdogEnable | GmacJabberEnable | GmacFrameBurstEnable | GmacJumboFrameDisable ++ | GmacSelectMii | GmacDisableRxOwn | GmacLoopbackOff ++ | GmacHalfDuplex | GmacRetryEnable | GmacPadCrcStripDisable ++ | GmacBackoffLimit0 | GmacDeferralCheckDisable | GmacTxEnable | GmacRxEnable, ++ ++ /* Half-duplex mode */ ++ GmacFrameFilterInitHdx = GmacFilterOn | GmacPassControl0 | GmacBroadcastEnable | GmacSrcAddrFilterDisable ++ | GmacMulticastFilterOn | GmacDestAddrFilterNor | GmacMcastHashFilterOff ++ | GmacUcastHashFilterOff| GmacPromiscuousModeOff, ++ ++ /* Half-duplex mode */ ++ GmacFlowControlInitHdx = GmacUnicastPauseFrameOff | GmacRxFlowControlDisable | GmacTxFlowControlDisable, ++ ++ /* Half-duplex mode */ ++ GmacGmiiAddrInitHdx = GmiiCsrClk2, ++ ++ ++ ++ /********************************************** ++ *DMA configurations ++ **********************************************/ ++ ++ DmaBusModeInit = DmaFixedBurstEnable | DmaBurstLength8 | DmaDescriptorSkip2 | DmaResetOff | 0x02000000, ++ // DmaBusModeInit = DmaFixedBurstEnable | DmaBurstLength8 | DmaDescriptorSkip4 | DmaResetOff, ++ ++ /* 1000 Mb/s mode */ ++ DmaControlInit1000 = DmaStoreAndForward,// | DmaTxSecondFrame , ++ ++ /* 100 Mb/s mode */ ++ DmaControlInit100 = DmaStoreAndForward, ++ ++ /* 10 Mb/s mode */ ++ DmaControlInit10 = DmaStoreAndForward, ++ ++ /* Interrupt groups */ ++ DmaIntErrorMask = DmaIntBusError, /* Error */ ++ DmaIntRxAbnMask = DmaIntRxNoBuffer, /* receiver abnormal interrupt */ ++ DmaIntRxNormMask = DmaIntRxCompleted, /* receiver normal interrupt */ ++ DmaIntRxStoppedMask = DmaIntRxStopped, /* receiver stopped */ ++ DmaIntTxAbnMask = DmaIntTxUnderflow, /* transmitter abnormal interrupt */ ++ DmaIntTxNormMask = DmaIntTxCompleted, /* transmitter normal interrupt */ ++ DmaIntTxStoppedMask = DmaIntTxStopped, /* transmitter stopped */ ++ ++#if 0 ++ DmaIntEnable = DmaIeNormal | DmaIeAbnormal | DmaIntErrorMask ++ | DmaIntRxAbnMask | DmaIntRxNormMask | DmaIntRxStoppedMask ++ | DmaIntTxAbnMask | DmaIntTxNormMask | DmaIntTxStoppedMask, ++#else ++ DmaIntEnable = DmaIeNormal | DmaIntErrorMask ++ | DmaIntRxNormMask | DmaIntRxStoppedMask ++ | DmaIntTxNormMask | DmaIntTxStoppedMask, ++#endif ++ DmaIntDisable = 0, ++}; ++ ++ ++/********************************************************** ++ * Mac Management Counters (MMC) ++ **********************************************************/ ++ ++enum MMC_ENABLE ++{ ++ GmacMmcCntrl = 0x0100, /* mmc control for operating mode of MMC */ ++ GmacMmcIntrRx = 0x0104, /* maintains interrupts generated by rx counters */ ++ GmacMmcIntrTx = 0x0108, /* maintains interrupts generated by tx counters */ ++ GmacMmcIntrMaskRx = 0x010C, /* mask for interrupts generated from rx counters */ ++ GmacMmcIntrMaskTx = 0x0110, /* mask for interrupts generated from tx counters */ ++}; ++enum MMC_TX ++{ ++ GmacMmcTxOctetCountGb = 0x0114, /*Bytes Tx excl. of preamble and retried bytes (Good or Bad) */ ++ GmacMmcTxFrameCountGb = 0x0118, /*Frames Tx excl. of retried frames (Good or Bad) */ ++ GmacMmcTxBcFramesG = 0x011C, /*Broadcast Frames Tx (Good) */ ++ GmacMmcTxMcFramesG = 0x0120, /*Multicast Frames Tx (Good) */ ++ ++ GmacMmcTx64OctetsGb = 0x0124, /*Tx with len 64 bytes excl. of pre and retried (Good or Bad) */ ++ GmacMmcTx65To127OctetsGb = 0x0128, /*Tx with len >64 bytes <=127 excl. of pre and retried (Good or Bad) */ ++ GmacMmcTx128To255OctetsGb = 0x012C, /*Tx with len >128 bytes <=255 excl. of pre and retried (Good or Bad) */ ++ GmacMmcTx256To511OctetsGb = 0x0130, /*Tx with len >256 bytes <=511 excl. of pre and retried (Good or Bad) */ ++ GmacMmcTx512To1023OctetsGb = 0x0134, /*Tx with len >512 bytes <=1023 excl. of pre and retried (Good or Bad) */ ++ GmacMmcTx1024ToMaxOctetsGb = 0x0138, /*Tx with len >1024 bytes <=MaxSize excl. of pre and retried (Good or Bad) */ ++ ++ GmacMmcTxUcFramesGb = 0x013C, /*Unicast Frames Tx (Good or Bad) */ ++ GmacMmcTxMcFramesGb = 0x0140, /*Multicast Frames Tx (Good and Bad) */ ++ GmacMmcTxBcFramesGb = 0x0144, /*Broadcast Frames Tx (Good and Bad) */ ++ GmacMmcTxUnderFlowError = 0x0148, /*Frames aborted due to Underflow error */ ++ GmacMmcTxSingleColG = 0x014C, /*Successfully Tx Frames after singel collision in Half duplex mode */ ++ GmacMmcTxMultiColG = 0x0150, /*Successfully Tx Frames after more than singel collision in Half duplex mode */ ++ GmacMmcTxDeferred = 0x0154, /*Successfully Tx Frames after a deferral in Half duplex mode */ ++ GmacMmcTxLateCol = 0x0158, /*Frames aborted due to late collision error */ ++ GmacMmcTxExessCol = 0x015C, /*Frames aborted due to excessive (16) collision errors */ ++ GmacMmcTxCarrierError = 0x0160, /*Frames aborted due to carrier sense error (No carrier or Loss of carrier) */ ++ GmacMmcTxOctetCountG = 0x0164, /*Bytes Tx excl. of preamble and retried bytes (Good) */ ++ GmacMmcTxFrameCountG = 0x0168, /*Frames Tx (Good) */ ++ GmacMmcTxExessDef = 0x016C, /*Frames aborted due to excessive deferral errors (deferred for more than 2 max-sized frame times)*/ ++ ++ GmacMmcTxPauseFrames = 0x0170, /*Number of good pause frames Tx. */ ++ GmacMmcTxVlanFramesG = 0x0174, /*Number of good Vlan frames Tx excl. retried frames */ ++}; ++enum MMC_RX ++{ ++ GmacMmcRxFrameCountGb = 0x0180, /*Frames Rx (Good or Bad) */ ++ GmacMmcRxOctetCountGb = 0x0184, /*Bytes Rx excl. of preamble and retried bytes (Good or Bad) */ ++ GmacMmcRxOctetCountG = 0x0188, /*Bytes Rx excl. of preamble and retried bytes (Good) */ ++ GmacMmcRxBcFramesG = 0x018C, /*Broadcast Frames Rx (Good) */ ++ GmacMmcRxMcFramesG = 0x0190, /*Multicast Frames Rx (Good) */ ++ ++ GmacMmcRxCrcError = 0x0194, /*Number of frames received with CRC error */ ++ GmacMmcRxAlignError = 0x0198, /*Number of frames received with alignment (dribble) error. Only in 10/100mode */ ++ GmacMmcRxRuntError = 0x019C, /*Number of frames received with runt (<64 bytes and CRC error) error */ ++ GmacMmcRxJabberError = 0x01A0, /*Number of frames rx with jabber (>1518/1522 or >9018/9022 and CRC) */ ++ GmacMmcRxUnderSizeG = 0x01A4, /*Number of frames received with <64 bytes without any error */ ++ GmacMmcRxOverSizeG = 0x01A8, /*Number of frames received with >1518/1522 bytes without any error */ ++ ++ GmacMmcRx64OctetsGb = 0x01AC, /*Rx with len 64 bytes excl. of pre and retried (Good or Bad) */ ++ GmacMmcRx65To127OctetsGb = 0x01B0, /*Rx with len >64 bytes <=127 excl. of pre and retried (Good or Bad) */ ++ GmacMmcRx128To255OctetsGb = 0x01B4, /*Rx with len >128 bytes <=255 excl. of pre and retried (Good or Bad) */ ++ GmacMmcRx256To511OctetsGb = 0x01B8, /*Rx with len >256 bytes <=511 excl. of pre and retried (Good or Bad) */ ++ GmacMmcRx512To1023OctetsGb = 0x01BC, /*Rx with len >512 bytes <=1023 excl. of pre and retried (Good or Bad) */ ++ GmacMmcRx1024ToMaxOctetsGb = 0x01C0, /*Rx with len >1024 bytes <=MaxSize excl. of pre and retried (Good or Bad) */ ++ ++ GmacMmcRxUcFramesG = 0x01C4, /*Unicast Frames Rx (Good) */ ++ GmacMmcRxLengthError = 0x01C8, /*Number of frames received with Length type field != frame size */ ++ GmacMmcRxOutOfRangeType = 0x01CC, /*Number of frames received with length field != valid frame size */ ++ ++ GmacMmcRxPauseFrames = 0x01D0, /*Number of good pause frames Rx. */ ++ GmacMmcRxFifoOverFlow = 0x01D4, /*Number of missed rx frames due to FIFO overflow */ ++ GmacMmcRxVlanFramesGb = 0x01D8, /*Number of good Vlan frames Rx */ ++ ++ GmacMmcRxWatchdobError = 0x01DC, /*Number of frames rx with error due to watchdog timeout error */ ++}; ++enum MMC_IP_RELATED ++{ ++ GmacMmcRxIpcIntrMask = 0x0200, /*Maintains the mask for interrupt generated from rx IPC statistic counters */ ++ GmacMmcRxIpcIntr = 0x0208, /*Maintains the interrupt that rx IPC statistic counters generate */ ++ ++ GmacMmcRxIpV4FramesG = 0x0210, /*Good IPV4 datagrams received */ ++ GmacMmcRxIpV4HdrErrFrames = 0x0214, /*Number of IPV4 datagrams received with header errors */ ++ GmacMmcRxIpV4NoPayFrames = 0x0218, /*Number of IPV4 datagrams received which didnot have TCP/UDP/ICMP payload */ ++ GmacMmcRxIpV4FragFrames = 0x021C, /*Number of IPV4 datagrams received with fragmentation */ ++ GmacMmcRxIpV4UdpChkDsblFrames = 0x0220, /*Number of IPV4 datagrams received that had a UDP payload checksum disabled */ ++ ++ GmacMmcRxIpV6FramesG = 0x0224, /*Good IPV6 datagrams received */ ++ GmacMmcRxIpV6HdrErrFrames = 0x0228, /*Number of IPV6 datagrams received with header errors */ ++ GmacMmcRxIpV6NoPayFrames = 0x022C, /*Number of IPV6 datagrams received which didnot have TCP/UDP/ICMP payload */ ++ ++ GmacMmcRxUdpFramesG = 0x0230, /*Number of good IP datagrams with good UDP payload */ ++ GmacMmcRxUdpErrorFrames = 0x0234, /*Number of good IP datagrams with UDP payload having checksum error */ ++ ++ GmacMmcRxTcpFramesG = 0x0238, /*Number of good IP datagrams with good TDP payload */ ++ GmacMmcRxTcpErrorFrames = 0x023C, /*Number of good IP datagrams with TCP payload having checksum error */ ++ ++ GmacMmcRxIcmpFramesG = 0x0240, /*Number of good IP datagrams with good Icmp payload */ ++ GmacMmcRxIcmpErrorFrames = 0x0244, /*Number of good IP datagrams with Icmp payload having checksum error */ ++ ++ GmacMmcRxIpV4OctetsG = 0x0250, /*Good IPV4 datagrams received excl. Ethernet hdr,FCS,Pad,Ip Pad bytes */ ++ GmacMmcRxIpV4HdrErrorOctets = 0x0254, /*Number of bytes in IPV4 datagram with header errors */ ++ GmacMmcRxIpV4NoPayOctets = 0x0258, /*Number of bytes in IPV4 datagram with no TCP/UDP/ICMP payload */ ++ GmacMmcRxIpV4FragOctets = 0x025C, /*Number of bytes received in fragmented IPV4 datagrams */ ++ GmacMmcRxIpV4UdpChkDsblOctets = 0x0260, /*Number of bytes received in UDP segment that had UDP checksum disabled */ ++ ++ GmacMmcRxIpV6OctetsG = 0x0264, /*Good IPV6 datagrams received excl. Ethernet hdr,FCS,Pad,Ip Pad bytes */ ++ GmacMmcRxIpV6HdrErrorOctets = 0x0268, /*Number of bytes in IPV6 datagram with header errors */ ++ GmacMmcRxIpV6NoPayOctets = 0x026C, /*Number of bytes in IPV6 datagram with no TCP/UDP/ICMP payload */ ++ ++ GmacMmcRxUdpOctetsG = 0x0270, /*Number of bytes in IP datagrams with good UDP payload */ ++ GmacMmcRxUdpErrorOctets = 0x0274, /*Number of bytes in IP datagrams with UDP payload having checksum error */ ++ ++ GmacMmcRxTcpOctetsG = 0x0278, /*Number of bytes in IP datagrams with good TDP payload */ ++ GmacMmcRxTcpErrorOctets = 0x027C, /*Number of bytes in IP datagrams with TCP payload having checksum error */ ++ ++ GmacMmcRxIcmpOctetsG = 0x0280, /*Number of bytes in IP datagrams with good Icmp payload */ ++ GmacMmcRxIcmpErrorOctets = 0x0284, /*Number of bytes in IP datagrams with Icmp payload having checksum error */ ++}; ++ ++ ++enum MMC_CNTRL_REG_BIT_DESCRIPTIONS ++{ ++ GmacMmcCounterFreeze = 0x00000008, /* when set MMC counters freeze to current value */ ++ GmacMmcCounterResetOnRead = 0x00000004, /* when set MMC counters will be reset to 0 after read */ ++ GmacMmcCounterStopRollover = 0x00000002, /* when set counters will not rollover after max value */ ++ GmacMmcCounterReset = 0x00000001, /* when set all counters wil be reset (automatically cleared after 1 clk) */ ++ ++}; ++ ++enum MMC_RX_INTR_MASK_AND_STATUS_BIT_DESCRIPTIONS ++{ ++ GmacMmcRxWDInt = 0x00800000, /* set when rxwatchdog error reaches half of max value */ ++ GmacMmcRxVlanInt = 0x00400000, /* set when GmacMmcRxVlanFramesGb counter reaches half of max value */ ++ GmacMmcRxFifoOverFlowInt = 0x00200000, /* set when GmacMmcRxFifoOverFlow counter reaches half of max value */ ++ GmacMmcRxPauseFrameInt = 0x00100000, /* set when GmacMmcRxPauseFrames counter reaches half of max value */ ++ GmacMmcRxOutOfRangeInt = 0x00080000, /* set when GmacMmcRxOutOfRangeType counter reaches half of max value */ ++ GmacMmcRxLengthErrorInt = 0x00040000, /* set when GmacMmcRxLengthError counter reaches half of max value */ ++ GmacMmcRxUcFramesInt = 0x00020000, /* set when GmacMmcRxUcFramesG counter reaches half of max value */ ++ GmacMmcRx1024OctInt = 0x00010000, /* set when GmacMmcRx1024ToMaxOctetsGb counter reaches half of max value */ ++ GmacMmcRx512OctInt = 0x00008000, /* set when GmacMmcRx512To1023OctetsGb counter reaches half of max value */ ++ GmacMmcRx256OctInt = 0x00004000, /* set when GmacMmcRx256To511OctetsGb counter reaches half of max value */ ++ GmacMmcRx128OctInt = 0x00002000, /* set when GmacMmcRx128To255OctetsGb counter reaches half of max value */ ++ GmacMmcRx65OctInt = 0x00001000, /* set when GmacMmcRx65To127OctetsG counter reaches half of max value */ ++ GmacMmcRx64OctInt = 0x00000800, /* set when GmacMmcRx64OctetsGb counter reaches half of max value */ ++ GmacMmcRxOverSizeInt = 0x00000400, /* set when GmacMmcRxOverSizeG counter reaches half of max value */ ++ GmacMmcRxUnderSizeInt = 0x00000200, /* set when GmacMmcRxUnderSizeG counter reaches half of max value */ ++ GmacMmcRxJabberErrorInt = 0x00000100, /* set when GmacMmcRxJabberError counter reaches half of max value */ ++ GmacMmcRxRuntErrorInt = 0x00000080, /* set when GmacMmcRxRuntError counter reaches half of max value */ ++ GmacMmcRxAlignErrorInt = 0x00000040, /* set when GmacMmcRxAlignError counter reaches half of max value */ ++ GmacMmcRxCrcErrorInt = 0x00000020, /* set when GmacMmcRxCrcError counter reaches half of max value */ ++ GmacMmcRxMcFramesInt = 0x00000010, /* set when GmacMmcRxMcFramesG counter reaches half of max value */ ++ GmacMmcRxBcFramesInt = 0x00000008, /* set when GmacMmcRxBcFramesG counter reaches half of max value */ ++ GmacMmcRxOctetGInt = 0x00000004, /* set when GmacMmcRxOctetCountG counter reaches half of max value */ ++ GmacMmcRxOctetGbInt = 0x00000002, /* set when GmacMmcRxOctetCountGb counter reaches half of max value */ ++ GmacMmcRxFrameInt = 0x00000001, /* set when GmacMmcRxFrameCountGb counter reaches half of max value */ ++}; ++ ++enum MMC_TX_INTR_MASK_AND_STATUS_BIT_DESCRIPTIONS ++{ ++ ++ GmacMmcTxVlanInt = 0x01000000, /* set when GmacMmcTxVlanFramesG counter reaches half of max value */ ++ GmacMmcTxPauseFrameInt = 0x00800000, /* set when GmacMmcTxPauseFrames counter reaches half of max value */ ++ GmacMmcTxExessDefInt = 0x00400000, /* set when GmacMmcTxExessDef counter reaches half of max value */ ++ GmacMmcTxFrameInt = 0x00200000, /* set when GmacMmcTxFrameCount counter reaches half of max value */ ++ GmacMmcTxOctetInt = 0x00100000, /* set when GmacMmcTxOctetCountG counter reaches half of max value */ ++ GmacMmcTxCarrierErrorInt = 0x00080000, /* set when GmacMmcTxCarrierError counter reaches half of max value */ ++ GmacMmcTxExessColInt = 0x00040000, /* set when GmacMmcTxExessCol counter reaches half of max value */ ++ GmacMmcTxLateColInt = 0x00020000, /* set when GmacMmcTxLateCol counter reaches half of max value */ ++ GmacMmcTxDeferredInt = 0x00010000, /* set when GmacMmcTxDeferred counter reaches half of max value */ ++ GmacMmcTxMultiColInt = 0x00008000, /* set when GmacMmcTxMultiColG counter reaches half of max value */ ++ GmacMmcTxSingleCol = 0x00004000, /* set when GmacMmcTxSingleColG counter reaches half of max value */ ++ GmacMmcTxUnderFlowErrorInt = 0x00002000, /* set when GmacMmcTxUnderFlowError counter reaches half of max value */ ++ GmacMmcTxBcFramesGbInt = 0x00001000, /* set when GmacMmcTxBcFramesGb counter reaches half of max value */ ++ GmacMmcTxMcFramesGbInt = 0x00000800, /* set when GmacMmcTxMcFramesGb counter reaches half of max value */ ++ GmacMmcTxUcFramesInt = 0x00000400, /* set when GmacMmcTxUcFramesGb counter reaches half of max value */ ++ GmacMmcTx1024OctInt = 0x00000200, /* set when GmacMmcTx1024ToMaxOctetsGb counter reaches half of max value */ ++ GmacMmcTx512OctInt = 0x00000100, /* set when GmacMmcTx512To1023OctetsGb counter reaches half of max value */ ++ GmacMmcTx256OctInt = 0x00000080, /* set when GmacMmcTx256To511OctetsGb counter reaches half of max value */ ++ GmacMmcTx128OctInt = 0x00000040, /* set when GmacMmcTx128To255OctetsGb counter reaches half of max value */ ++ GmacMmcTx65OctInt = 0x00000020, /* set when GmacMmcTx65To127OctetsGb counter reaches half of max value */ ++ GmacMmcTx64OctInt = 0x00000010, /* set when GmacMmcTx64OctetsGb counter reaches half of max value */ ++ GmacMmcTxMcFramesInt = 0x00000008, /* set when GmacMmcTxMcFramesG counter reaches half of max value */ ++ GmacMmcTxBcFramesInt = 0x00000004, /* set when GmacMmcTxBcFramesG counter reaches half of max value */ ++ GmacMmcTxFrameGbInt = 0x00000002, /* set when GmacMmcTxFrameCountGb counter reaches half of max value */ ++ GmacMmcTxOctetGbInt = 0x00000001, /* set when GmacMmcTxOctetCountGb counter reaches half of max value */ ++ ++}; ++ ++ ++/********************************************************** ++ * Power Management (PMT) Block ++ **********************************************************/ ++ ++/** ++ * PMT supports the reception of network (remote) wake-up frames and Magic packet frames. ++ * It generates interrupts for wake-up frames and Magic packets received by GMAC. ++ * PMT sits in Rx path and is enabled with remote wake-up frame enable and Magic packet enable. ++ * These enable are in PMT control and Status register and are programmed by apllication. ++ * ++ * When power down mode is enabled in PMT, all rx frames are dropped by the core. Core comes ++ * out of power down mode only when either Magic packe tor a Remote wake-up frame is received ++ * and the corresponding detection is enabled. ++ * ++ * Driver need not be modified to support this feature. Only Api to put the device in to power ++ * down mode is sufficient ++ */ ++ ++#define WAKEUP_REG_LENGTH 8 /*This is the reg length for wake up register configuration*/ ++ ++enum GmacPmtCtrlStatusBitDefinition ++{ ++ GmacPmtFrmFilterPtrReset = 0x80000000, /* when set remote wake-up frame filter register pointer to 3'b000 */ ++ GmacPmtGlobalUnicast = 0x00000200, /* When set enables any unicast packet to be a wake-up frame */ ++ GmacPmtWakeupFrameReceived = 0x00000040, /* Wake up frame received */ ++ GmacPmtMagicPktReceived = 0x00000020, /* Magic Packet received */ ++ GmacPmtWakeupFrameEnable = 0x00000004, /* Wake-up frame enable */ ++ GmacPmtMagicPktEnable = 0x00000002, /* Magic packet enable */ ++ GmacPmtPowerDown = 0x00000001, /* Power Down */ ++}; ++ ++ ++ ++ ++/********************************************************** ++ * IEEE 1588-2008 Precision Time Protocol (PTP) Support ++ **********************************************************/ ++enum PTPMessageType ++{ ++ SYNC = 0x0, ++ Delay_Req = 0x1, ++ Pdelay_Req = 0x2, ++ Pdelay_Resp = 0x3, ++ Follow_up = 0x8, ++ Delay_Resp = 0x9, ++ Pdelay_Resp_Follow_Up = 0xA, ++ Announce = 0xB, ++ Signaling = 0xC, ++ Management = 0xD, ++}; ++ ++ ++ ++typedef struct TimeStampStruct ++{ ++ u32 TSversion; /* PTP Version 1 or PTP version2 */ ++ u32 TSmessagetype; /* Message type associated with this time stamp */ ++ ++ u16 TShighest16; /* Highest 16 bit time stamp value, Valid onley when ADV_TIME_HIGH_WORD configured in corekit */ ++ u32 TSupper32; /* Most significant 32 bit time stamp value */ ++ u32 TSlower32; /* Least Significat 32 bit time stamp value */ ++ ++} TimeStamp; ++ ++ ++/** ++ * IEEE 1588-2008 is the optional module to support Ethernet frame time stamping. ++ * Sixty four (+16) bit time stamps are given in each frames transmit and receive status. ++ * The driver assumes the following ++ * 1. "IEEE 1588 Time Stamping" "TIME_STAMPING"is ENABLED in corekit ++ * 2. "IEEE 1588 External Time Stamp Input Enable" "EXT_TIME_STAMPING" is DISABLED in corekit ++ * 3. "IEEE 1588 Advanced Time Stamp support" "ADV_TIME_STAMPING" is ENABLED in corekit ++ * 4. "IEEE 1588 Higher Word Register Enable" "ADV_TIME_HIGH_WORD" is ENABLED in corekit ++ */ ++ ++/* GmacTSControl = 0x0700, Controls the Timestamp update logic : only when IEEE 1588 time stamping is enabled in corekit */ ++enum GmacTSControlReg ++{ ++ GmacTSENMACADDR = 0x00040000, /* Enable Mac Addr for PTP filtering 18 RW 0 */ ++ ++ GmacTSCLKTYPE = 0x00030000, /* Select the type of clock node 17:16 RW 00 */ ++ /* ++ TSCLKTYPE TSMSTRENA TSEVNTENA Messages for wihich TS snapshot is taken ++ 00/01 X 0 SYNC, FOLLOW_UP, DELAY_REQ, DELAY_RESP ++ 00/01 1 0 DELAY_REQ ++ 00/01 0 1 SYNC ++ 10 NA 0 SYNC, FOLLOW_UP, DELAY_REQ, DELAY_RESP ++ 10 NA 1 SYNC, FOLLOW_UP ++ 11 NA 0 SYNC, FOLLOW_UP, DELAY_REQ, DELAY_RESP, PDELAY_REQ, PDELAY_RESP ++ 11 NA 1 SYNC, PDELAY_REQ, PDELAY_RESP ++ */ ++ GmacTSOrdClk = 0x00000000, /* 00=> Ordinary clock*/ ++ GmacTSBouClk = 0x00010000, /* 01=> Boundary clock*/ ++ GmacTSEtoEClk = 0x00020000, /* 10=> End-to-End transparent clock*/ ++ GmacTSPtoPClk = 0x00030000, /* 11=> P-to-P transparent clock*/ ++ ++ GmacTSMSTRENA = 0x00008000, /* Ena TS Snapshot for Master Messages 15 RW 0 */ ++ GmacTSEVNTENA = 0x00004000, /* Ena TS Snapshot for Event Messages 14 RW 0 */ ++ GmacTSIPV4ENA = 0x00002000, /* Ena TS snapshot for IPv4 13 RW 1 */ ++ GmacTSIPV6ENA = 0x00001000, /* Ena TS snapshot for IPv6 12 RW 0 */ ++ GmacTSIPENA = 0x00000800, /* Ena TS snapshot for PTP over E'net 11 RW 0 */ ++ GmacTSVER2ENA = 0x00000400, /* Ena PTP snooping for version 2 10 RW 0 */ ++ ++ GmacTSCTRLSSR = 0x00000200, /* Digital or Binary Rollover 9 RW 0 */ ++ ++ GmacTSENALL = 0x00000100, /* Enable TS fro all frames (Ver2 only) 8 RW 0 */ ++ ++ GmacTSADDREG = 0x00000020, /* Addend Register Update 5 RW_SC 0 */ ++ GmacTSUPDT = 0x00000008, /* Time Stamp Update 3 RW_SC 0 */ ++ GmacTSINT = 0x00000004, /* Time Atamp Initialize 2 RW_SC 0 */ ++ ++ GmacTSTRIG = 0x00000010, /* Time stamp interrupt Trigger Enable 4 RW_SC 0 */ ++ ++ GmacTSCFUPDT = 0x00000002, /* Time Stamp Fine/Coarse 1 RW 0 */ ++ GmacTSCUPDTCoarse = 0x00000000, /* 0=> Time Stamp update method is coarse */ ++ GmacTSCUPDTFine = 0x00000002, /* 1=> Time Stamp update method is fine */ ++ ++ GmacTSENA = 0x00000001, /* Time Stamp Enable 0 RW 0 */ ++}; ++ ++ ++/* GmacTSSubSecIncr = 0x0704, 8 bit value by which sub second register is incremented : only when IEEE 1588 time stamping without external timestamp input */ ++enum GmacTSSubSecIncrReg ++{ ++ GmacSSINCMsk = 0x000000FF, /* Only Lower 8 bits are valid bits 7:0 RW 00 */ ++}; ++ ++/* GmacTSLow = 0x070C, Indicates whether the timestamp low count is positive or negative; for Adv timestamp it is always zero */ ++enum GmacTSSign ++{ ++ GmacTSSign = 0x80000000, /* PSNT 31 RW 0 */ ++ GmacTSPositive = 0x00000000, ++ GmacTSNegative = 0x80000000, ++}; ++ ++/*GmacTargetTimeLow = 0x0718, 32 bit nano seconds(MS) to be compared with system time : only when IEEE 1588 time stamping without external timestamp input */ ++enum GmacTSLowReg ++{ ++ GmacTSDecThr = 0x3B9AC9FF, /*when TSCTRLSSR is set the max value for GmacTargetTimeLowReg and GmacTimeStampLow register is 0x3B9AC9FF at 1ns precision */ ++}; ++ ++/* GmacTSHighWord = 0x0724, Time Stamp Higher Word Register (Version 2 only); only lower 16 bits are valid */ ++enum GmacTSHighWordReg ++{ ++ GmacTSHighWordMask = 0x0000FFFF, /* Time Stamp Higher work register has only lower 16 bits valid */ ++}; ++/*GmacTSStatus = 0x0728, Time Stamp Status Register */ ++enum GmacTSStatusReg ++{ ++ GmacTSTargTimeReached = 0x00000002, /* Time Stamp Target Time Reached 1 RO 0 */ ++ GmacTSSecondsOverflow = 0x00000001, /* Time Stamp Seconds Overflow 0 RO 0 */ ++}; ++ ++/* GmacAvMacCtrl = 0x0738, AV mac control Register */ ++#ifdef AVB_SUPPORT ++enum GmacAvMacCtrlReg ++{ ++ GmacAvCtrlCh = 0x03000000, /* Channel on which AV control packets to be received 25:24 RW 0 */ ++ GmacPtpCh = 0x00180000, /* Channel on which PTP packets to be received 20:19 RW 0 */ ++ GmacAvPrio = 0x00070000, /* Priority tag value for AV Packets 18:16 RW 4 */ ++ GmacAvTypeMask = 0x0000FFFF, /* Ethernet Type value to be used for comparing and detecting AV packet 15:0 RW 0 */ ++}; ++#endif ++ ++/********************************************************** ++ * Time stamp related functions ++ **********************************************************/ ++void synopGMAC_TS_enable(synopGMACdevice *gmacdev); ++void synopGMAC_TS_disable(synopGMACdevice *gmacdev); ++ ++void synopGMAC_TS_int_enable(synopGMACdevice *gmacdev); ++void synopGMAC_TS_int_disable(synopGMACdevice *gmacdev); ++ ++void synopGMAC_TS_mac_addr_filt_enable(synopGMACdevice *gmacdev); ++void synopGMAC_TS_mac_addr_filt_disable(synopGMACdevice *gmacdev); ++void synopGMAC_TS_set_clk_type(synopGMACdevice *gmacdev, u32 clk_type); ++void synopGMAC_TS_master_enable(synopGMACdevice *gmacdev); // Only for Ordinary clock and Boundary clock and "Advanced Time Stamp" ++void synopGMAC_TS_master_disable(synopGMACdevice *gmacdev); // Only for Ordinary clock and Boundary clock and "Advanced Time Stamp" ++void synopGMAC_TS_event_enable(synopGMACdevice *gmacdev); // Only for "Advanced Time Stamp" ++void synopGMAC_TS_event_disable(synopGMACdevice *gmacdev); // Only for "Advanced Time Stamp" ++void synopGMAC_TS_IPV4_enable(synopGMACdevice *gmacdev); // Only for "Advanced Time Stamp" ++void synopGMAC_TS_IPV4_disable(synopGMACdevice *gmacdev); // Only for "Advanced Time Stamp" ++void synopGMAC_TS_IPV6_enable(synopGMACdevice *gmacdev); // Only for "Advanced Time Stamp" ++void synopGMAC_TS_IPV6_disable(synopGMACdevice *gmacdev); // Only for "Advanced Time Stamp" ++void synopGMAC_TS_ptp_over_ethernet_enable(synopGMACdevice *gmacdev); // Only for "Advanced Time Stamp" ++void synopGMAC_TS_ptp_over_ethernet_disable(synopGMACdevice *gmacdev); // Only for "Advanced Time Stamp" ++void synopGMAC_TS_pkt_snoop_ver2(synopGMACdevice *gmacdev); // Only for "Advanced Time Stamp" ++void synopGMAC_TS_pkt_snoop_ver1(synopGMACdevice *gmacdev); // Only for "Advanced Time Stamp" ++ ++void synopGMAC_TS_digital_rollover_enable(synopGMACdevice *gmacdev); ++void synopGMAC_TS_binary_rollover_enable(synopGMACdevice *gmacdev); ++void synopGMAC_TS_all_frames_enable(synopGMACdevice *gmacdev); // Only for "Advanced Time Stamp" ++void synopGMAC_TS_all_frames_disable(synopGMACdevice *gmacdev); // Only for "Advanced Time Stamp" ++ ++s32 synopGMAC_TS_addend_update(synopGMACdevice *gmacdev, u32 addend_value); ++s32 synopGMAC_TS_timestamp_update(synopGMACdevice *gmacdev, u32 high_value, u32 low_value); ++s32 synopGMAC_TS_timestamp_init(synopGMACdevice *gmacdev, u32 high_value, u32 low_value); ++ ++void synopGMAC_TS_coarse_update(synopGMACdevice *gmacdev); // Only if "fine correction" enabled ++void synopGMAC_TS_fine_update(synopGMACdevice *gmacdev); // Only if "fine correction" enabled ++ ++void synopGMAC_TS_subsecond_init(synopGMACdevice *gmacdev, u32 sub_sec_inc_val); // Update should happen making use of subsecond mask ++void synopGMAC_TS_read_timestamp(synopGMACdevice *gmacdev, u16 * higher_sec_val, ++ u32 * sec_val, u32 * sub_sec_val); // Reads the timestamp low,high and higher(Ver2) registers in the the struct pointer; readonly contents ++void synopGMAC_TS_load_target_timestamp(synopGMACdevice *gmacdev, u32 sec_val, u32 sub_sec_val); //Loads the timestamp target register with the values provided ++ ++void synopGMAC_TS_load_timestamp_higher_val(synopGMACdevice *gmacdev, u32 higher_sec_val); ++void synopGMAC_TS_read_timestamp_higher_val(synopGMACdevice *gmacdev, u16 * higher_sec_val); ++void synopGMAC_TS_read_target_timestamp(synopGMACdevice *gmacdev, u32 * sec_val, u32 * sub_sec_val); //Read the target time stamp register contents ++ ++ ++/********************************************************** ++ * Common functions ++ **********************************************************/ ++s32 synopGMAC_set_mdc_clk_div(synopGMACdevice *gmacdev,u32 clk_div_val); ++u32 synopGMAC_get_mdc_clk_div(synopGMACdevice *gmacdev); ++u32 synopGMAC_calculate_mdc_clk_csr(u32 sysclk, u32 max_mdcclk); ++s32 synopGMAC_read_phy_reg(synopGMACdevice *gmacdev, u32 PhyBase, u32 RegOffset, u16 * data); ++s32 synopGMAC_write_phy_reg(synopGMACdevice *gmacdev, u32 PhyBase, u32 RegOffset, u16 data); ++s32 synopGMAC_phy_loopback(synopGMACdevice *gmacdev, bool loopback); ++s32 synopGMAC_read_version (synopGMACdevice * gmacdev) ; ++s32 synopGMAC_reset (synopGMACdevice * gmacdev ); ++s32 synopGMAC_dma_bus_mode_init(synopGMACdevice * gmacdev, u32 init_value ); ++s32 synopGMAC_dma_control_init(synopGMACdevice * gmacdev, u32 init_value); ++void synopGMAC_wd_enable(synopGMACdevice * gmacdev); ++void synopGMAC_wd_disable(synopGMACdevice * gmacdev); ++void synopGMAC_jab_enable(synopGMACdevice * gmacdev); ++void synopGMAC_jab_disable(synopGMACdevice * gmacdev); ++void synopGMAC_frame_burst_enable(synopGMACdevice * gmacdev); ++void synopGMAC_frame_burst_disable(synopGMACdevice * gmacdev); ++void synopGMAC_jumbo_frame_enable(synopGMACdevice * gmacdev); ++void synopGMAC_jumbo_frame_disable(synopGMACdevice * gmacdev); ++void synopGMAC_set_Inter_Frame_Gap(synopGMACdevice * gmacdev, u32 value); ++void synopGMAC_select_gmii(synopGMACdevice * gmacdev); ++void synopGMAC_select_mii(synopGMACdevice * gmacdev); ++void synopGMAC_select_speed1000(synopGMACdevice * gmacdev); ++void synopGMAC_select_speed100(synopGMACdevice * gmacdev); ++void synopGMAC_select_speed10(synopGMACdevice * gmacdev); ++void synopGMAC_rx_own_enable(synopGMACdevice * gmacdev); ++void synopGMAC_rx_own_disable(synopGMACdevice * gmacdev); ++void synopGMAC_loopback_on(synopGMACdevice * gmacdev); ++void synopGMAC_loopback_off(synopGMACdevice * gmacdev); ++void synopGMAC_set_full_duplex(synopGMACdevice * gmacdev); ++void synopGMAC_set_half_duplex(synopGMACdevice * gmacdev); ++void synopGMAC_retry_enable(synopGMACdevice * gmacdev); ++void synopGMAC_retry_disable(synopGMACdevice * gmacdev); ++void synopGMAC_pad_crc_strip_enable(synopGMACdevice * gmacdev); ++void synopGMAC_pad_crc_strip_disable(synopGMACdevice * gmacdev); ++void synopGMAC_back_off_limit(synopGMACdevice * gmacdev, u32 value); ++void synopGMAC_deferral_check_enable(synopGMACdevice * gmacdev); ++void synopGMAC_deferral_check_disable(synopGMACdevice * gmacdev); ++void synopGMAC_rx_enable(synopGMACdevice * gmacdev); ++void synopGMAC_rx_disable(synopGMACdevice * gmacdev); ++void synopGMAC_tx_enable(synopGMACdevice * gmacdev); ++void synopGMAC_tx_disable(synopGMACdevice * gmacdev); ++void synopGMAC_frame_filter_enable(synopGMACdevice * gmacdev); ++void synopGMAC_frame_filter_disable(synopGMACdevice * gmacdev); ++void synopGMAC_write_hash_table_high(synopGMACdevice * gmacdev, u32 data); ++void synopGMAC_write_hash_table_low(synopGMACdevice * gmacdev, u32 data); ++void synopGMAC_hash_perfect_filter_enable(synopGMACdevice * gmacdev); ++void synopGMAC_Hash_filter_only_enable(synopGMACdevice * gmacdev); ++void synopGMAC_src_addr_filter_enable(synopGMACdevice * gmacdev); ++void synopGMAC_src_addr_filter_disable(synopGMACdevice * gmacdev); ++void synopGMAC_dst_addr_filter_inverse(synopGMACdevice * gmacdev); ++void synopGMAC_dst_addr_filter_normal(synopGMACdevice * gmacdev); ++void synopGMAC_set_pass_control(synopGMACdevice * gmacdev,u32 passcontrol); ++void synopGMAC_broadcast_enable(synopGMACdevice * gmacdev); ++void synopGMAC_broadcast_disable(synopGMACdevice * gmacdev); ++void synopGMAC_multicast_enable(synopGMACdevice * gmacdev); ++void synopGMAC_multicast_disable(synopGMACdevice * gmacdev); ++void synopGMAC_multicast_hash_filter_enable(synopGMACdevice * gmacdev); ++void synopGMAC_multicast_hash_filter_disable(synopGMACdevice * gmacdev); ++void synopGMAC_promisc_enable(synopGMACdevice * gmacdev); ++void synopGMAC_promisc_disable(synopGMACdevice * gmacdev); ++void synopGMAC_unicast_hash_filter_enable(synopGMACdevice * gmacdev); ++void synopGMAC_unicast_hash_filter_disable(synopGMACdevice * gmacdev); ++void synopGMAC_unicast_pause_frame_detect_enable(synopGMACdevice * gmacdev); ++void synopGMAC_unicast_pause_frame_detect_disable(synopGMACdevice * gmacdev); ++void synopGMAC_rx_flow_control_enable(synopGMACdevice * gmacdev); ++void synopGMAC_rx_flow_control_disable(synopGMACdevice * gmacdev); ++void synopGMAC_tx_flow_control_enable(synopGMACdevice * gmacdev); ++void synopGMAC_tx_flow_control_disable(synopGMACdevice * gmacdev); ++void synopGMAC_tx_activate_flow_control(synopGMACdevice * gmacdev); ++void synopGMAC_tx_deactivate_flow_control(synopGMACdevice * gmacdev); ++void synopGMAC_pause_control(synopGMACdevice *gmacdev); ++s32 synopGMAC_mac_init(synopGMACdevice * gmacdev); ++s32 synopGMAC_search_phy (synopGMACdevice * gmacdev); ++s32 synopGMAC_check_phy_init (synopGMACdevice * gmacdev); ++s32 synopGMAC_set_mac_addr(synopGMACdevice *gmacdev, u32 MacHigh, u32 MacLow, u8 *MacAddr); ++s32 synopGMAC_get_mac_addr(synopGMACdevice *gmacdev, u32 MacHigh, u32 MacLow, u8 *MacAddr); ++s32 synopGMAC_attach (synopGMACdevice * gmacdev, u32 macBase, u32 dmaBase, u32 phyBase); ++void synopGMAC_rx_desc_init_ring(DmaDesc *desc, bool last_ring_desc); ++void synopGMAC_tx_desc_init_ring(DmaDesc *desc, bool last_ring_desc); ++void synopGMAC_rx_desc_init_chain(DmaDesc * desc); ++void synopGMAC_tx_desc_init_chain(DmaDesc * desc); ++s32 synopGMAC_init_tx_rx_desc_queue(synopGMACdevice *gmacdev); ++void synopGMAC_init_rx_desc_base(synopGMACdevice *gmacdev); ++void synopGMAC_init_tx_desc_base(synopGMACdevice *gmacdev); ++void synopGMAC_set_owner_dma(DmaDesc *desc); ++void synopGMAC_set_desc_sof(DmaDesc *desc); ++void synopGMAC_set_desc_eof(DmaDesc *desc); ++bool synopGMAC_is_sof_in_rx_desc(DmaDesc *desc); ++bool synopGMAC_is_eof_in_rx_desc(DmaDesc *desc); ++bool synopGMAC_is_da_filter_failed(DmaDesc *desc); ++bool synopGMAC_is_sa_filter_failed(DmaDesc *desc); ++bool synopGMAC_is_desc_owned_by_dma(DmaDesc *desc); ++u32 synopGMAC_get_rx_desc_frame_length(u32 status); ++bool synopGMAC_is_desc_valid(u32 status); ++bool synopGMAC_is_desc_empty(DmaDesc *desc); ++bool synopGMAC_is_rx_desc_valid(u32 status); ++bool synopGMAC_is_tx_aborted(u32 status); ++bool synopGMAC_is_tx_carrier_error(u32 status); ++u32 synopGMAC_get_tx_collision_count(u32 status); ++u32 synopGMAC_is_exc_tx_collisions(u32 status); ++bool synopGMAC_is_rx_frame_damaged(u32 status); ++bool synopGMAC_is_rx_frame_collision(u32 status); ++bool synopGMAC_is_rx_crc(u32 status); ++bool synopGMAC_is_frame_dribbling_errors(u32 status); ++bool synopGMAC_is_rx_frame_length_errors(u32 status); ++bool synopGMAC_is_last_rx_desc(synopGMACdevice * gmacdev,DmaDesc *desc); ++bool synopGMAC_is_last_tx_desc(synopGMACdevice * gmacdev,DmaDesc *desc); ++bool synopGMAC_is_rx_desc_chained(DmaDesc * desc); ++bool synopGMAC_is_tx_desc_chained(DmaDesc * desc); ++void synopGMAC_get_desc_data(DmaDesc * desc, u32 * Status, u32 * Buffer1, u32 * Length1, u32 * Data1, u32 * Buffer2, u32 * Length2, u32 * Data2); ++#ifdef ENH_DESC_8W ++s32 synopGMAC_get_tx_qptr(synopGMACdevice * gmacdev, u32 * Status, u32 * Buffer1, u32 * Length1, u32 * Data1, u32 * Buffer2, u32 * Length2, u32 * Data2, ++ u32 * Ext_Status, u32 * Time_Stamp_High, u32 * Time_Stamp_low); ++#else ++s32 synopGMAC_get_tx_qptr(synopGMACdevice * gmacdev, u32 * Status, u32 * Buffer1, u32 * Length1, u32 * Data1, u32 * Buffer2, u32 * Length2, u32 * Data2 ); ++#endif ++s32 synopGMAC_set_tx_qptr(synopGMACdevice * gmacdev, u32 Buffer1, u32 Length1, u32 Data1, u32 Buffer2, u32 Length2, u32 Data2,u32 offload_needed); ++s32 synopGMAC_set_rx_qptr(synopGMACdevice * gmacdev, u32 Buffer1, u32 Length1, u32 Data1, u32 Buffer2, u32 Length2, u32 Data2); ++#ifdef ENH_DESC_8W ++s32 synopGMAC_get_rx_qptr(synopGMACdevice * gmacdev, u32 * Status, u32 * Buffer1, u32 * Length1, u32 * Data1, u32 * Buffer2, u32 * Length2, u32 * Data2, ++ u32 * Ext_Status, u32 * Time_Stamp_High, u32 * Time_Stamp_low); ++#else ++s32 synopGMAC_get_rx_qptr(synopGMACdevice * gmacdev, u32 * Status, u32 * Buffer1, u32 * Length1, u32 * Data1, u32 * Buffer2, u32 * Length2, u32 * Data2); ++#endif ++void synopGMAC_clear_interrupt(synopGMACdevice *gmacdev); ++u32 synopGMAC_get_interrupt_type(synopGMACdevice *gmacdev); ++u32 synopGMAC_get_interrupt_mask(synopGMACdevice *gmacdev); ++void synopGMAC_enable_interrupt(synopGMACdevice *gmacdev, u32 interrupts); ++void synopGMAC_disable_interrupt_all(synopGMACdevice *gmacdev); ++void synopGMAC_disable_interrupt(synopGMACdevice *gmacdev, u32 interrupts); ++void synopGMAC_enable_dma_rx(synopGMACdevice * gmacdev); ++void synopGMAC_enable_dma_tx(synopGMACdevice * gmacdev); ++void synopGMAC_resume_dma_tx(synopGMACdevice * gmacdev); ++void synopGMAC_resume_dma_rx(synopGMACdevice * gmacdev); ++void synopGMAC_take_desc_ownership(DmaDesc * desc); ++void synopGMAC_take_desc_ownership_rx(synopGMACdevice * gmacdev); ++void synopGMAC_take_desc_ownership_tx(synopGMACdevice * gmacdev); ++void synopGMAC_disable_dma_tx(synopGMACdevice * gmacdev); ++void synopGMAC_disable_dma_rx(synopGMACdevice * gmacdev); ++/******Following APIs are valid only for Enhanced Descriptor from 3.50a release onwards*******/ ++bool synopGMAC_is_ext_status(synopGMACdevice *gmacdev,u32 status); ++bool synopGMAC_ES_is_IP_header_error(synopGMACdevice *gmacdev,u32 ext_status); ++bool synopGMAC_ES_is_rx_checksum_bypassed(synopGMACdevice *gmacdev,u32 ext_status); ++bool synopGMAC_ES_is_IP_payload_error(synopGMACdevice *gmacdev,u32 ext_status); ++/*******************PMT APIs***************************************/ ++void synopGMAC_pmt_int_enable(synopGMACdevice *gmacdev); ++void synopGMAC_pmt_int_disable(synopGMACdevice *gmacdev); ++void synopGMAC_power_down_enable(synopGMACdevice *gmacdev); ++void synopGMAC_power_down_disable(synopGMACdevice *gmacdev); ++void synopGMAC_enable_pmt_interrupt(synopGMACdevice *gmacdev); ++void synopGMAC_disable_pmt_interrupt(synopGMACdevice *gmacdev); ++void synopGMAC_magic_packet_enable(synopGMACdevice *gmacdev); ++void synopGMAC_wakeup_frame_enable(synopGMACdevice *gmacdev); ++void synopGMAC_pmt_unicast_enable(synopGMACdevice *gmacdev); ++bool synopGMAC_is_magic_packet_received(synopGMACdevice *gmacdev); ++bool synopGMAC_is_wakeup_frame_received(synopGMACdevice *gmacdev); ++void synopGMAC_write_wakeup_frame_register(synopGMACdevice *gmacdev, u32 * filter_contents); ++/*******************MMC APIs***************************************/ ++void synopGMAC_mmc_counters_stop(synopGMACdevice *gmacdev); ++void synopGMAC_mmc_counters_resume(synopGMACdevice *gmacdev); ++void synopGMAC_mmc_counters_set_selfclear(synopGMACdevice *gmacdev); ++void synopGMAC_mmc_counters_reset_selfclear(synopGMACdevice *gmacdev); ++void synopGMAC_mmc_counters_disable_rollover(synopGMACdevice *gmacdev); ++void synopGMAC_mmc_counters_enable_rollover(synopGMACdevice *gmacdev); ++u32 synopGMAC_read_mmc_counter(synopGMACdevice *gmacdev, u32 counter); ++u32 synopGMAC_read_mmc_rx_int_status(synopGMACdevice *gmacdev); ++u32 synopGMAC_read_mmc_tx_int_status(synopGMACdevice *gmacdev); ++void synopGMAC_disable_mmc_tx_interrupt(synopGMACdevice *gmacdev, u32 mask); ++void synopGMAC_enable_mmc_tx_interrupt(synopGMACdevice *gmacdev, u32 mask); ++void synopGMAC_disable_mmc_rx_interrupt(synopGMACdevice *gmacdev, u32 mask); ++void synopGMAC_enable_mmc_rx_interrupt(synopGMACdevice *gmacdev, u32 mask); ++void synopGMAC_enable_mmc_ipc_rx_interrupt(synopGMACdevice *gmacdev, u32 mask); ++void synopGMAC_disable_mmc_ipc_rx_interrupt(synopGMACdevice *gmacdev, u32 mask); ++/*******************Ip checksum offloading APIs***************************************/ ++void synopGMAC_enable_rx_chksum_offload(synopGMACdevice *gmacdev); ++void synopGMAC_disable_rx_Ipchecksum_offload(synopGMACdevice *gmacdev); ++void synopGMAC_rx_tcpip_chksum_drop_enable(synopGMACdevice *gmacdev); ++void synopGMAC_rx_tcpip_chksum_drop_disable(synopGMACdevice *gmacdev); ++u32 synopGMAC_is_rx_checksum_error(synopGMACdevice *gmacdev, u32 status); ++bool synopGMAC_is_tx_ipv4header_checksum_error(synopGMACdevice *gmacdev, u32 status); ++bool synopGMAC_is_tx_payload_checksum_error(synopGMACdevice *gmacdev, u32 status); ++void synopGMAC_tx_checksum_offload_bypass(synopGMACdevice *gmacdev, DmaDesc *desc); ++void synopGMAC_tx_checksum_offload_ipv4hdr(synopGMACdevice *gmacdev, DmaDesc *desc); ++void synopGMAC_tx_checksum_offload_tcponly(synopGMACdevice *gmacdev, DmaDesc *desc); ++void synopGMAC_tx_checksum_offload_tcp_pseudo(synopGMACdevice *gmacdev, DmaDesc *desc); ++#ifdef AVB_SUPPORT ++void synopGMACsetAvType(synopGMACdevice *gmacdev, u32 avtype); ++void synopGMACsetAvPrio(synopGMACdevice * gmacdev,u8 priority); ++void synopGMACsetAvCtrlCh(synopGMACdevice * gmacdev,u8 channel); ++void synopGMACsetAvPTPCh (synopGMACdevice * gmacdev,u8 channel); ++void synopGMACsetTxRxPrioPolicy(synopGMACdevice * gmacdev,u8 policy); ++void synopGMACsetTxRxPrio(synopGMACdevice * gmacdev,u8 tx_has_high_prio); ++void synopGMACsetTxRxPrioRatio(synopGMACdevice * gmacdev,u8 tx_rx_prio_ratio); ++void synopGMACsetChPrioWts(synopGMACdevice * gmacdev,u8 weights); ++void synopGMACAvbEnSlot(synopGMACdevice * gmacdev); ++void synopGMACAvbDisSlot (synopGMACdevice * gmacdev); ++void synopGMACAvbEnAdvSlotInt(synopGMACdevice * gmacdev); ++void synopGMACAvbDisAdvSlotInt(synopGMACdevice * gmacdev); ++void synopGMACAvbSetSlotCount(synopGMACdevice * gmacdev, u8 slotcount); ++void synopGMACAvbEnSlotInterrupt(synopGMACdevice * gmacdev); ++void synopGMACAvbDisSlotInterrupt(synopGMACdevice * gmacdev); ++void synopGMACAvbEnableCrSh(synopGMACdevice * gmacdev); ++void synopGMACAvbDisableCrSh(synopGMACdevice * gmacdev); ++void synopGMACAvbEnableCrControl(synopGMACdevice * gmacdev); ++void synopGMACAvbDisableCrControl(synopGMACdevice * gmacdev); ++void synopGMACsetAvbSendSlope(synopGMACdevice * gmacdev,u32 sendslope_val); ++void synopGMACsetAvbIdleSlope(synopGMACdevice * gmacdev,u32 idleslope_val); ++void synopGMACsetAvbHiCredit(synopGMACdevice * gmacdev,u32 hicredit_val); ++void synopGMACsetAvbLoCredit(synopGMACdevice * gmacdev,u32 locredit_val); ++ ++void synopGMAC_set_desc_data(DmaDesc *txdesc, u32 Status, u32 Buffer1, u32 Length1, u32 Data1, u32 Buffer2, u32 Length2, u32 Data2); ++#endif ++ ++ ++#endif /* End of file */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_ingenic_synopGMAC_plat.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_ingenic_synopGMAC_plat.c.patch new file mode 100644 index 00000000..5b27af06 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_ingenic_synopGMAC_plat.c.patch @@ -0,0 +1,98 @@ +diff -drupN a/drivers/net/ethernet/ingenic/synopGMAC_plat.c b/drivers/net/ethernet/ingenic/synopGMAC_plat.c +--- a/drivers/net/ethernet/ingenic/synopGMAC_plat.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/net/ethernet/ingenic/synopGMAC_plat.c 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,94 @@ ++/* =================================================================================== ++ * Copyright (c) <2009> Synopsys, Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy of ++ * this software annotated with this license and associated documentation files ++ * (the "Software"), to deal in the Software without restriction, including without ++ * limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in all ++ * copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, ++ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A ++ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT ++ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE ++ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * =================================================================================== */ ++ ++/**\file ++ * This file defines the wrapper for the platform/OS related functions ++ * The function definitions needs to be modified according to the platform ++ * and the Operating system used. ++ * This file should be handled with greatest care while porting the driver ++ * to a different platform running different operating system other than ++ * Linux 2.6.xx. ++ * \internal ++ * ----------------------------REVISION HISTORY----------------------------- ++ * Synopsys 01/Aug/2007 Created ++ */ ++ ++#include "synopGMAC_plat.h" ++ ++/** ++ * This is a wrapper function for Memory allocation routine. In linux Kernel ++ * it it kmalloc function ++ * @param[in] bytes in bytes to allocate ++ */ ++ ++void *plat_alloc_memory(u32 bytes) ++{ ++ return kmalloc((size_t)bytes, GFP_KERNEL); ++} ++ ++/** ++ * This is a wrapper function for consistent dma-able Memory allocation routine. ++ * @param[in] bytes in bytes to allocate ++ */ ++ ++void *plat_alloc_consistent_dmaable_memory(struct device *dev, u32 size, u32 *addr) ++{ ++ return dma_alloc_coherent(dev, size, addr, GFP_ATOMIC); ++} ++ ++/** ++ * This is a wrapper function for freeing consistent dma-able Memory. ++ * @param[in] bytes in bytes to allocate ++ */ ++ ++void plat_free_consistent_dmaable_memory(struct device *dev, u32 size, void * addr,u32 dma_addr) ++{ ++ dma_free_coherent(dev, size, addr, dma_addr); ++} ++ ++ ++ ++/** ++ * This is a wrapper function for Memory free routine. In linux Kernel ++ * it it kfree function ++ * @param[in] buffer pointer to be freed ++ */ ++void plat_free_memory(void *buffer) ++{ ++ kfree(buffer); ++ return ; ++} ++ ++ ++/** ++ * This is a wrapper function for platform dependent delay ++ * Take care while passing the argument to this function ++ * @param[in] buffer pointer to be freed ++ */ ++void plat_delay(u32 delay) ++{ ++ while (delay--); ++ return; ++} ++ ++ ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_ingenic_synopGMAC_plat.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_ingenic_synopGMAC_plat.h.patch new file mode 100644 index 00000000..0a66e89d --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_ethernet_ingenic_synopGMAC_plat.h.patch @@ -0,0 +1,211 @@ +diff -drupN a/drivers/net/ethernet/ingenic/synopGMAC_plat.h b/drivers/net/ethernet/ingenic/synopGMAC_plat.h +--- a/drivers/net/ethernet/ingenic/synopGMAC_plat.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/net/ethernet/ingenic/synopGMAC_plat.h 2022-06-09 05:02:30.000000000 +0300 +@@ -0,0 +1,207 @@ ++/* =================================================================================== ++ * Copyright (c) <2009> Synopsys, Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy of ++ * this software annotated with this license and associated documentation files ++ * (the "Software"), to deal in the Software without restriction, including without ++ * limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in all ++ * copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, ++ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A ++ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT ++ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE ++ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * =================================================================================== */ ++ ++/**\file ++ * This file serves as the wrapper for the platform/OS dependent functions ++ * It is needed to modify these functions accordingly based on the platform and the ++ * OS. Whenever the synopsys GMAC driver ported on to different platform, this file ++ * should be handled at most care. ++ * The corresponding function definitions for non-inline functions are available in ++ * synopGMAC_plat.c file. ++ * \internal ++ * -------------------------------------REVISION HISTORY--------------------------- ++ * Synopsys 01/Aug/2007 Created ++ */ ++ ++ ++#ifndef SYNOP_GMAC_PLAT_H ++#define SYNOP_GMAC_PLAT_H 1 ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define TR0(fmt, args...) printk(KERN_CRIT "SynopGMAC: " fmt, ##args) ++ ++extern int debug_enable; ++ ++#if 0 ++#ifdef DEBUG ++#undef TR ++# define TR(fmt, args...) printk(KERN_CRIT "SynopGMAC: " fmt, ##args) ++#else ++# define TR(fmt, args...) /* not debugging: nothing */ ++#endif ++#endif ++ ++#define TR(fmt, args...) \ ++ do { \ ++ if (debug_enable) { \ ++ printk(KERN_CRIT "SynopGMAC: " fmt, ##args); \ ++ } \ ++ } while(0) ++ ++#if 0 ++typedef int bool; ++enum synopGMAC_boolean ++ { ++ false = 0, ++ true = 1 ++ }; ++#endif ++ ++#define DEFAULT_DELAY_VARIABLE 10 ++#define DEFAULT_LOOP_VARIABLE 10000 ++ ++/* There are platform related endian conversions ++ * ++ */ ++ ++#define LE32_TO_CPU __le32_to_cpu ++#define BE32_TO_CPU __be32_to_cpu ++#define CPU_TO_LE32 __cpu_to_le32 ++ ++/* Error Codes */ ++#define ESYNOPGMACNOERR 0 ++#define ESYNOPGMACNOMEM 1 ++#define ESYNOPGMACPHYERR 2 ++#define ESYNOPGMACBUSY 3 ++ ++struct Network_interface_data ++{ ++ u32 unit; ++ u32 addr; ++ u32 data; ++}; ++ ++ ++/** ++ * These are the wrapper function prototypes for OS/platform related routines ++ */ ++ ++void * plat_alloc_memory(u32 ); ++void plat_free_memory(void *); ++ ++void * plat_alloc_consistent_dmaable_memory(struct device *, u32, u32 *); ++void plat_free_consistent_dmaable_memory (struct device *, u32, void *, u32); ++ ++void plat_delay(u32); ++ ++ ++/** ++ * The Low level function to read register contents from Hardware. ++ * ++ * @param[in] pointer to the base of register map ++ * @param[in] Offset from the base ++ * \return Returns the register contents ++ */ ++static u32 __inline__ synopGMACReadReg(u32 *RegBase, u32 RegOffset) ++{ ++ ++ u32 addr = (u32)RegBase + RegOffset; ++ u32 data = readl((void *)addr); ++ //printk("=====>%s: RegBase = 0x%08x RegOffset = 0x%08x RegData = 0x%08x\n", __FUNCTION__, (u32)RegBase, RegOffset, data ); ++ return data; ++} ++ ++/** ++ * The Low level function to write to a register in Hardware. ++ * ++ * @param[in] pointer to the base of register map ++ * @param[in] Offset from the base ++ * @param[in] Data to be written ++ * \return void ++ */ ++static void __inline__ synopGMACWriteReg(u32 *RegBase, u32 RegOffset, u32 RegData) ++{ ++ ++ u32 addr = (u32)RegBase + RegOffset; ++ //printk("=====>%s RegBase = 0x%08x RegOffset = 0x%08x RegData = 0x%08x\n", __FUNCTION__,(u32) RegBase, RegOffset, RegData ); ++ writel(RegData,(void *)addr); ++ //*((volatile unsigned int *)addr) = RegData; ++ return; ++} ++ ++/** ++ * The Low level function to set bits of a register in Hardware. ++ * ++ * @param[in] pointer to the base of register map ++ * @param[in] Offset from the base ++ * @param[in] Bit mask to set bits to logical 1 ++ * \return void ++ */ ++static void __inline__ synopGMACSetBits(u32 *RegBase, u32 RegOffset, u32 BitPos) ++{ ++ u32 addr = (u32)RegBase + RegOffset; ++ u32 data = readl((void *)addr); ++ data |= BitPos; ++// TR("%s !!!!!!!!!!!!! RegOffset = 0x%08x RegData = 0x%08x\n", __FUNCTION__, RegOffset, data ); ++ writel(data,(void *)addr); ++// TR("%s !!!!!!!!!!!!! RegOffset = 0x%08x RegData = 0x%08x\n", __FUNCTION__, RegOffset, data ); ++ return; ++} ++ ++ ++/** ++ * The Low level function to clear bits of a register in Hardware. ++ * ++ * @param[in] pointer to the base of register map ++ * @param[in] Offset from the base ++ * @param[in] Bit mask to clear bits to logical 0 ++ * \return void ++ */ ++static void __inline__ synopGMACClearBits(u32 *RegBase, u32 RegOffset, u32 BitPos) ++{ ++ u32 addr = (u32)RegBase + RegOffset; ++ u32 data = readl((void *)addr); ++ data &= (~BitPos); ++// TR("%s !!!!!!!!!!!!!! RegOffset = 0x%08x RegData = 0x%08x\n", __FUNCTION__, RegOffset, data ); ++ writel(data,(void *)addr); ++// TR("%s !!!!!!!!!!!!! RegOffset = 0x%08x RegData = 0x%08x\n", __FUNCTION__, RegOffset, data ); ++ return; ++} ++ ++/** ++ * The Low level function to Check the setting of the bits. ++ * ++ * @param[in] pointer to the base of register map ++ * @param[in] Offset from the base ++ * @param[in] Bit mask to set bits to logical 1 ++ * \return returns TRUE if set to '1' returns FALSE if set to '0'. Result undefined there are no bit set in the BitPos argument. ++ * ++ */ ++static bool __inline__ synopGMACCheckBits(u32 *RegBase, u32 RegOffset, u32 BitPos) ++{ ++ u32 addr = (u32)RegBase + RegOffset; ++ u32 data = readl((void *)addr); ++ data &= BitPos; ++ if(data) return true; ++ else return false; ++ ++} ++ ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_mii.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_mii.c.patch new file mode 100644 index 00000000..9a0fb23e --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_net_mii.c.patch @@ -0,0 +1,78 @@ +diff -drupN a/drivers/net/mii.c b/drivers/net/mii.c +--- a/drivers/net/mii.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/net/mii.c 2022-06-09 05:02:30.000000000 +0300 +@@ -133,6 +133,7 @@ int mii_ethtool_gset(struct mii_if_info + + return 0; + } ++EXPORT_SYMBOL(mii_ethtool_gset); + + /** + * mii_ethtool_sset - set settings that are specified in @ecmd +@@ -225,6 +226,7 @@ int mii_ethtool_sset(struct mii_if_info + } + return 0; + } ++EXPORT_SYMBOL(mii_ethtool_sset); + + /** + * mii_check_gmii_support - check if the MII supports Gb interfaces +@@ -243,6 +245,7 @@ int mii_check_gmii_support(struct mii_if + + return 0; + } ++EXPORT_SYMBOL(mii_check_gmii_support); + + /** + * mii_link_ok - is link status up/ok +@@ -258,6 +261,7 @@ int mii_link_ok (struct mii_if_info *mii + return 1; + return 0; + } ++EXPORT_SYMBOL(mii_link_ok); + + /** + * mii_nway_restart - restart NWay (autonegotiation) for this interface +@@ -281,6 +285,7 @@ int mii_nway_restart (struct mii_if_info + + return r; + } ++EXPORT_SYMBOL(mii_nway_restart); + + /** + * mii_check_link - check MII link status +@@ -300,6 +305,7 @@ void mii_check_link (struct mii_if_info + else if (prev_link && !cur_link) + netif_carrier_off(mii->dev); + } ++EXPORT_SYMBOL(mii_check_link); + + /** + * mii_check_media - check the MII interface for a carrier/speed/duplex change +@@ -379,6 +385,7 @@ unsigned int mii_check_media (struct mii + + return 0; /* duplex did not change */ + } ++EXPORT_SYMBOL(mii_check_media); + + /** + * generic_mii_ioctl - main MII ioctl interface +@@ -458,17 +465,8 @@ int generic_mii_ioctl(struct mii_if_info + + return rc; + } ++EXPORT_SYMBOL(generic_mii_ioctl); + + MODULE_AUTHOR ("Jeff Garzik "); + MODULE_DESCRIPTION ("MII hardware support library"); + MODULE_LICENSE("GPL"); +- +-EXPORT_SYMBOL(mii_link_ok); +-EXPORT_SYMBOL(mii_nway_restart); +-EXPORT_SYMBOL(mii_ethtool_gset); +-EXPORT_SYMBOL(mii_ethtool_sset); +-EXPORT_SYMBOL(mii_check_link); +-EXPORT_SYMBOL(mii_check_media); +-EXPORT_SYMBOL(mii_check_gmii_support); +-EXPORT_SYMBOL(generic_mii_ioctl); +- diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_pinctrl_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_pinctrl_Kconfig.patch new file mode 100644 index 00000000..8ec7a971 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_pinctrl_Kconfig.patch @@ -0,0 +1,16 @@ +diff -drupN a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig +--- a/drivers/pinctrl/Kconfig 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/pinctrl/Kconfig 2022-06-09 05:02:32.000000000 +0300 +@@ -246,6 +246,12 @@ config PINCTRL_ZYNQ + help + This selectes the pinctrl driver for Xilinx Zynq. + ++config PINCTRL_INGENIC ++ bool ++ select PINMUX ++ select PINCONF ++ select GENERIC_PINCONF ++ + source "drivers/pinctrl/bcm/Kconfig" + source "drivers/pinctrl/berlin/Kconfig" + source "drivers/pinctrl/freescale/Kconfig" diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_pinctrl_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_pinctrl_Makefile.patch new file mode 100644 index 00000000..ab2f9d8d --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_pinctrl_Makefile.patch @@ -0,0 +1,12 @@ +diff -drupN a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile +--- a/drivers/pinctrl/Makefile 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/pinctrl/Makefile 2022-06-09 05:02:32.000000000 +0300 +@@ -39,7 +39,7 @@ obj-$(CONFIG_PINCTRL_LPC18XX) += pinctrl + obj-$(CONFIG_PINCTRL_TB10X) += pinctrl-tb10x.o + obj-$(CONFIG_PINCTRL_ST) += pinctrl-st.o + obj-$(CONFIG_PINCTRL_ZYNQ) += pinctrl-zynq.o +- ++obj-$(CONFIG_PINCTRL_INGENIC) += pinctrl-ingenic.o + obj-$(CONFIG_ARCH_BCM) += bcm/ + obj-$(CONFIG_ARCH_BERLIN) += berlin/ + obj-y += freescale/ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_pinctrl_pinctrl-ingenic.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_pinctrl_pinctrl-ingenic.c.patch new file mode 100644 index 00000000..d696ebb0 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_pinctrl_pinctrl-ingenic.c.patch @@ -0,0 +1,1794 @@ +diff -drupN a/drivers/pinctrl/pinctrl-ingenic.c b/drivers/pinctrl/pinctrl-ingenic.c +--- a/drivers/pinctrl/pinctrl-ingenic.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/pinctrl/pinctrl-ingenic.c 2022-06-09 05:02:33.000000000 +0300 +@@ -0,0 +1,1790 @@ ++/* ++ * pinctrl/ingenic/pinctrl-ingenic.c ++ * ++ * Copyright 2015 Ingenic Semiconductor Co.,Ltd ++ * ++ * Author: cli ++ * ++ * redistribute from drivers/pinctrl/pinctrl-samsung.c ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "pinctrl-ingenic.h" ++ ++static struct ingenic_pinctrl *gpctl = NULL; ++static const struct ingenic_priv common_priv_data[]; ++static const struct of_device_id ingenic_pinctrl_dt_match[]; ++ ++static void ingenic_gpio_set_func_normal(struct ingenic_gpio_chip *chip, ++ enum gpio_function func, u32 pins) ++{ ++ unsigned long flags, func_tmp = func; ++ spin_lock_irqsave(&chip->lock, flags); ++ ++ if(func_tmp & 0x10){ ++ func = GPIO_INT_FE; ++ } ++ if (func & 0x8) ++ ingenic_gpio_writel(chip, PxINTS, pins); ++ else ++ ingenic_gpio_writel(chip, PxINTC, pins); ++ if (func & 0x4) ++ ingenic_gpio_writel(chip, PxMSKS, pins); ++ else ++ ingenic_gpio_writel(chip, PxMSKC, pins); ++ ++ if (func & 0x2) ++ ingenic_gpio_writel(chip, PxPAT1S, pins); ++ else ++ ingenic_gpio_writel(chip, PxPAT1C, pins); ++ ++ if(func_tmp & 0x10){ ++ int old, new, timeout = 10; ++ do { ++ old = ingenic_gpio_readl(chip, PxPIN) & pins; ++ if (old) ++ func = GPIO_INT_FE; ++ else ++ func = GPIO_INT_RE; ++ if (func & 0x1) ++ ingenic_gpio_writel(chip, PxPAT0S, pins); ++ else ++ ingenic_gpio_writel(chip, PxPAT0C, pins); ++ new = ingenic_gpio_readl(chip, PxPIN) & pins; ++ timeout --; ++ }while(old != new && timeout); ++ if(!timeout) ++ pr_err("pins %x function %d failed\n", pins, func); ++ } else { ++ if (func & 0x1) ++ ingenic_gpio_writel(chip, PxPAT0S, pins); ++ else ++ ingenic_gpio_writel(chip, PxPAT0C, pins); ++ } ++ ingenic_gpio_writel(chip, PxFLGC, pins); ++ spin_unlock_irqrestore(&chip->lock, flags); ++} ++ ++static void ingenic_gpio_fill_func_shadow(struct ingenic_gpio_chip *chip, ++ enum gpio_function func, u32 pins) ++{ ++ if (func & 0x8) ++ ingenic_gpio_shadow_fill(chip, PxINTS, pins); ++ else ++ ingenic_gpio_shadow_fill(chip, PxINTC, pins); ++ if (func & 0x4) ++ ingenic_gpio_shadow_fill(chip, PxMSKS, pins); ++ else ++ ingenic_gpio_shadow_fill(chip, PxMSKC, pins); ++ if (func & 0x2) ++ ingenic_gpio_shadow_fill(chip, PxPAT1S, pins); ++ else ++ ingenic_gpio_shadow_fill(chip, PxPAT1C, pins); ++ if (func & 0x1) ++ ingenic_gpio_shadow_fill(chip, PxPAT0S, pins); ++ else ++ ingenic_gpio_shadow_fill(chip, PxPAT0C, pins); ++} ++ ++static void ingenic_gpio_set_func_shadow(struct ingenic_gpio_chip *chip, ++ enum gpio_function func, u32 pins) ++{ ++ struct ingenic_pinctrl *pctl = chip->pctl; ++ unsigned long flags; ++ unsigned long func_tmp = func; ++ ++ spin_lock_irqsave(&pctl->shadow_lock, flags); ++ if(func_tmp & 0x10){ ++ int old, new, timeout = 10; ++ do { ++ old = ingenic_gpio_readl(chip, PxPIN) & pins; ++ if (old) ++ func = GPIO_INT_FE; ++ else ++ func = GPIO_INT_RE; ++ ingenic_gpio_fill_func_shadow(chip, func, pins); ++ ingenic_gpio_shadow_writel(chip); ++ new = ingenic_gpio_readl(chip, PxPIN) & pins; ++ timeout --; ++ }while(old != new && timeout); ++ if(!timeout) ++ pr_err("pins %x function %d failed\n",pins, func); ++ } else { ++ ingenic_gpio_fill_func_shadow(chip, func, pins); ++ ingenic_gpio_shadow_writel(chip); ++ } ++ spin_unlock_irqrestore(&pctl->shadow_lock, flags); ++} ++ ++/************************************************************** ++ * Set GPIO Function ++ * chip: gpio chip ++ * have_shadow: soc support shadow register ot not ++ * func: function select ++ * pins: pins bitmap ++ **************************************************************/ ++static void ingenic_gpio_set_func(struct ingenic_gpio_chip *chip, ++ bool have_shadow, enum gpio_function func, ++ u32 pins) ++{ ++ if (have_shadow) ++ ingenic_gpio_set_func_shadow(chip, func, pins); ++ else ++ ingenic_gpio_set_func_normal(chip, func, pins); ++} ++ ++static void ingenic_gpio_set_pull(struct ingenic_gpio_chip *chip, ++ u32 pins, unsigned int state) ++{ ++ const struct ingenic_priv *priv = chip->pctl->priv; ++ ++ if(priv->pull_tristate) { ++ if(state == INGENIC_GPIO_PULLUP) { ++ ingenic_gpio_writel(chip, PxPDENC, pins); ++ ingenic_gpio_writel(chip, PxPUENS, pins); ++ } else if(state == INGENIC_GPIO_PULLDOWN) { ++ ingenic_gpio_writel(chip, PxPUENC, pins); ++ ingenic_gpio_writel(chip, PxPDENS, pins); ++ } else if(state == INGENIC_GPIO_HIZ) { ++ ingenic_gpio_writel(chip, PxPUENC, pins); ++ ingenic_gpio_writel(chip, PxPDENC, pins); ++ } ++ } else { ++ printk("error: this gpio func not support\n"); ++ return; ++ } ++} ++ ++static int ingenic_gpio_get_pull_state(struct ingenic_gpio_chip *chip, u32 pins) ++{ ++ unsigned int pull_down = 0; ++ unsigned int pull_up = 0; ++ int state = 0; ++ ++ pull_down = (ingenic_gpio_readl(chip, PxPDEN) & BIT(pins)) >> pins; ++ pull_up = (ingenic_gpio_readl(chip, PxPUEN) & BIT(pins)) >> pins; ++ ++ if(pull_down && pull_up) { ++ dev_warn(chip->gc.dev, "Set both pull_up and pull_down on %s %d\n", chip->name, pins); ++ } ++ ++ if(pull_down) { ++ state = INGENIC_GPIO_PULLDOWN; ++ } else if(pull_up) { ++ state = INGENIC_GPIO_PULLUP; ++ } else { ++ state = INGENIC_GPIO_HIZ; ++ } ++ ++ return state; ++ ++} ++ ++/************************************************************* ++ * Set GPIO Input&Interrupt HW filter ++ * chip: gpio chip ++ * pin: pin num (one pin) ++ * pinflt: filter to set ++ *************************************************************/ ++static void ingenic_gpio_set_filter(struct ingenic_gpio_chip *chip, ++ u32 pin, u16 pinflt) ++{ ++ const struct ingenic_priv *priv = chip->pctl->priv; ++ if (chip->filter_bitmap & BIT(pin)) ++ priv->set_filter(chip, pin, pinflt); ++} ++ ++static void ingenic_gpio_set_schmitt_enable(struct ingenic_gpio_chip *chip, ++ u32 pin, int enable) ++{ ++ if(enable) { ++ ingenic_gpio_writel(chip, PxPSMTS, BIT(pin)); ++ } else { ++ ingenic_gpio_writel(chip, PxPSMTC, BIT(pin)); ++ } ++} ++ ++static void ingenic_gpio_set_slew_rate(struct ingenic_gpio_chip *chip, ++ u32 pin, int enable) ++{ ++ if(enable) { ++ ingenic_gpio_writel(chip, PxPSLWS, BIT(pin)); ++ } else { ++ ingenic_gpio_writel(chip, PxPSLWC, BIT(pin)); ++ } ++} ++ ++static void ingenic_gpio_set_drive_strength(struct ingenic_gpio_chip *chip, ++ u32 pin, u16 strength) ++{ ++ if(strength > 7) ++ strength = 7; ++ ++ if(strength & BIT(0)) ++ ingenic_gpio_writel(chip, PxPDS0S, BIT(pin)); ++ else ++ ingenic_gpio_writel(chip, PxPDS0C, BIT(pin)); ++ ++ if(strength & BIT(1)) ++ ingenic_gpio_writel(chip, PxPDS1S, BIT(pin)); ++ else ++ ingenic_gpio_writel(chip, PxPDS1C, BIT(pin)); ++ ++ if(strength & BIT(2)) ++ ingenic_gpio_writel(chip, PxPDS2S, BIT(pin)); ++ else ++ ingenic_gpio_writel(chip, PxPDS2C, BIT(pin)); ++} ++ ++static unsigned short ingenic_gpio_get_drive_strength(struct ingenic_gpio_chip *chip, ++ u32 pin) ++{ ++ unsigned short strength = 0; ++ ++ strength |= (ingenic_gpio_readl(chip, PxPDS0) & BIT(pin)) ? (1 << 0) : 0; ++ strength |= (ingenic_gpio_readl(chip, PxPDS1) & BIT(pin)) ? (1 << 1) : 0; ++ strength |= (ingenic_gpio_readl(chip, PxPDS2) & BIT(pin)) ? (1 << 2) : 0; ++ ++ return strength; ++} ++ ++static void ingenic_gpio_irq_mask(struct irq_data *irqd) ++{ ++ struct ingenic_gpio_chip *jzgc = irq_data_get_irq_chip_data(irqd); ++ ingenic_gpio_writel(jzgc, PxMSKS, BIT(irqd->hwirq)); ++} ++ ++static void ingenic_gpio_irq_unmask(struct irq_data *irqd) ++{ ++ struct ingenic_gpio_chip *jzgc = irq_data_get_irq_chip_data(irqd); ++ ingenic_gpio_writel(jzgc, PxMSKC, BIT(irqd->hwirq)); ++} ++ ++static void ingenic_gpio_irq_ack(struct irq_data *irqd) ++{ ++ struct ingenic_gpio_chip *jzgc = irq_data_get_irq_chip_data(irqd); ++ unsigned pins, pins_before, pending; ++ ++ ingenic_gpio_writel(jzgc, PxFLGC, BIT(irqd->hwirq)); ++ /* ++ * The controller not support BOTH EDGE trigger ++ * So we set the right trigger edge after irq ack ++ * Note: To make sure our edge interrupt will be tigger and handle at next time ++ * 0, clear pending ++ * 1, read the pin level ++ * 2, set edge according the pin level ++ * 3, read the pin level ++ * 4, read the pending ++ * 5, if pin level is change and irq not pending the irq may miss, goto 2 retry ++ */ ++ if (irqd_get_trigger_type(irqd) == IRQ_TYPE_EDGE_BOTH) { ++ pins = ingenic_gpio_readl(jzgc, PxPIN); ++ do { ++ ingenic_gpio_writel(jzgc, pins & BIT(irqd->hwirq) ? ++ PxPAT0C : PxPAT0S, BIT(irqd->hwirq)); ++ pins_before = pins; ++ pins = ingenic_gpio_readl(jzgc, PxPIN); ++ pending = ingenic_gpio_readl(jzgc, PxFLG); ++ } while(( (pins & BIT(irqd->hwirq)) != ++ (pins_before & BIT(irqd->hwirq)) ) && ++ !(pending & BIT(irqd->hwirq))); ++ } ++} ++ ++static int ingenic_gpio_irq_set_type(struct irq_data *irqd, unsigned int flow_type) ++{ ++ struct ingenic_gpio_chip *jzgc = irq_data_get_irq_chip_data(irqd); ++ const struct ingenic_priv *priv = jzgc->pctl->priv; ++ enum gpio_function func; ++ ++ if (!(flow_type & IRQ_TYPE_SENSE_MASK)) ++ return 0; ++ ++ if (flow_type & IRQ_TYPE_EDGE_BOTH) ++ irq_set_handler_locked(irqd, handle_edge_irq); ++ else ++ irq_set_handler_locked(irqd, handle_level_irq); ++ ++ switch (flow_type & IRQD_TRIGGER_MASK) { ++ case IRQ_TYPE_LEVEL_HIGH: func = GPIO_INT_HI; break; ++ case IRQ_TYPE_LEVEL_LOW: func = GPIO_INT_LO; break; ++ case IRQ_TYPE_EDGE_RISING: func = GPIO_INT_RE; break; ++ case IRQ_TYPE_EDGE_FALLING: func = GPIO_INT_FE; break; ++ case IRQ_TYPE_EDGE_BOTH: func = GPIO_INT_RE_FE; break; ++ default: ++ pr_err("unsupported external interrupt type\n"); ++ return -EINVAL; ++ } ++ ++ ingenic_gpio_set_func(jzgc, priv->have_shadow, func, BIT(irqd->hwirq)); ++ return 0; ++} ++ ++static int ingenic_gpio_irq_set_wake(struct irq_data *irqd, unsigned int on) ++{ ++ struct ingenic_gpio_chip *jzgc = irq_data_get_irq_chip_data(irqd); ++ ++ if (on) ++ jzgc->wakeup_bitmap |= BIT(irqd->hwirq); ++ else ++ jzgc->wakeup_bitmap &= ~BIT(irqd->hwirq); ++ ++ return irq_set_irq_wake(jzgc->irq, on); ++} ++ ++static void ingenic_gpio_irq_suspend(struct irq_data *irqd) ++{ ++ struct ingenic_gpio_chip *jzgc = irq_data_get_irq_chip_data(irqd); ++ ++ if ((!(jzgc->wakeup_bitmap & BIT(irqd->hwirq))) && ++ (!(ingenic_gpio_readl(jzgc, PxMSK) & BIT(irqd->hwirq)))) { ++ jzgc->pm_irq_bitmap |= BIT(irqd->hwirq); ++ ingenic_gpio_writel(jzgc, PxMSKS, BIT(irqd->hwirq)); ++ } ++} ++ ++static void ingenic_gpio_irq_resume(struct irq_data *irqd) ++{ ++ struct ingenic_gpio_chip *jzgc = irq_data_get_irq_chip_data(irqd); ++ ++ if (jzgc->pm_irq_bitmap & BIT(irqd->hwirq)) { ++ ingenic_gpio_writel(jzgc, PxMSKC, BIT(irqd->hwirq)); ++ jzgc->pm_irq_bitmap &= ~BIT(irqd->hwirq); ++ } ++} ++ ++static int ingenic_irq_request_resources(struct irq_data *irqd) ++{ ++ struct gpio_chip *chip = irq_data_get_irq_chip_data(irqd); ++ ++ if (!try_module_get(chip->owner)) ++ return -ENODEV; ++ ++ if (gpiochip_lock_as_irq(chip, irqd->hwirq)) { ++ pr_err("GPIO chip %s: unable to lock HW IRQ %lu for IRQ\n", ++ chip->label, ++ irqd->hwirq); ++ module_put(chip->owner); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static void ingenic_irq_release_resources(struct irq_data *irqd) ++{ ++ struct gpio_chip *chip = irq_data_get_irq_chip_data(irqd); ++ ++ gpiochip_unlock_as_irq(chip, irqd->hwirq); ++ module_put(chip->owner); ++} ++ ++static struct irq_chip ingenic_gpio_irq_chip = { ++ .name = "GPIO", ++ .irq_unmask = ingenic_gpio_irq_unmask, ++ .irq_mask = ingenic_gpio_irq_mask, ++ .irq_ack = ingenic_gpio_irq_ack, ++ .irq_set_type = ingenic_gpio_irq_set_type, ++ .irq_set_wake = ingenic_gpio_irq_set_wake, ++ .irq_suspend = ingenic_gpio_irq_suspend, ++ .irq_resume = ingenic_gpio_irq_resume, ++ .irq_request_resources = ingenic_irq_request_resources, ++ .irq_release_resources = ingenic_irq_release_resources, ++}; ++ ++static void ingenic_gpio_irq_handler(struct irq_desc *desc) ++{ ++ struct ingenic_gpio_chip *jzgc = irq_desc_get_handler_data(desc); ++ unsigned long pend, mask; ++ unsigned long i; ++ ++ if (IS_ERR_OR_NULL(jzgc->mcu_gpio_reg)) { ++ mask = ingenic_gpio_readl(jzgc, PxMSK); ++ pend = ingenic_gpio_readl(jzgc, PxFLG); ++ pend = pend & ~mask; ++ } else { ++ pend = *(jzgc->mcu_gpio_reg); ++ } ++ ++ for_each_set_bit(i, &pend, jzgc->gc.ngpio) ++ generic_handle_irq(irq_find_mapping(jzgc->irq_domain, i)); ++ ++ if (!IS_ERR_OR_NULL(jzgc->mcu_gpio_reg)) ++ *(jzgc->mcu_gpio_reg) = 0; ++ return; ++} ++ ++static void ingenic_gpio_set(struct gpio_chip *chip, ++ unsigned pin, int value) ++{ ++ struct ingenic_gpio_chip *jzgc = gc_to_ingenic_gc(chip); ++ ++ BUG_ON(pin > jzgc->gc.ngpio); ++ if (value) ++ ingenic_gpio_writel(jzgc, PxPAT0S, BIT(pin)); ++ else ++ ingenic_gpio_writel(jzgc, PxPAT0C, BIT(pin)); ++} ++ ++static int ingenic_gpio_get(struct gpio_chip *chip, unsigned pin) ++{ ++ struct ingenic_gpio_chip *jzgc = gc_to_ingenic_gc(chip); ++ ++ BUG_ON(pin > chip->ngpio); ++ if (jzgc->resume_pending & BIT(pin)) { ++ jzgc->resume_pending &= ~BIT(pin); ++ return !!(jzgc->sleep_level & BIT(pin)); ++ } ++ return !!(ingenic_gpio_readl(jzgc, PxPIN) & BIT(pin)); ++} ++ ++static int ingenic_gpio_direction_input(struct gpio_chip *chip, ++ unsigned pin) ++{ ++ BUG_ON(pin > chip->ngpio); ++ return pinctrl_gpio_direction_input(chip->base + pin); ++} ++ ++static int ingenic_gpio_direction_output(struct gpio_chip *chip, ++ unsigned pin, int value) ++{ ++ struct ingenic_gpio_chip *jzgc = gc_to_ingenic_gc(chip); ++ struct ingenic_pinctrl *pctl = jzgc->pctl; ++ const struct ingenic_priv *priv = pctl->priv; ++ enum gpio_function func; ++ unsigned long flags; ++ BUG_ON(pin > jzgc->gc.ngpio); ++ if(value) ++ func = GPIO_OUTPUT1; ++ else ++ func = GPIO_OUTPUT0; ++ if(priv->have_shadow){ ++ spin_lock_irqsave(&pctl->shadow_lock, flags); ++ ingenic_gpio_fill_func_shadow(jzgc, func, BIT(pin)); ++ ingenic_gpio_shadow_writel(jzgc); ++ spin_unlock_irqrestore(&pctl->shadow_lock, flags); ++ }else{ ++ ingenic_gpio_set_func_normal(jzgc, func, BIT(pin)); ++ } ++ return pinctrl_gpio_direction_output(chip->base + pin); ++} ++ ++static int ingenic_gpio_to_irq(struct gpio_chip *chip, ++ unsigned pin) ++{ ++ struct ingenic_gpio_chip *jzgc = gc_to_ingenic_gc(chip); ++ unsigned int virq; ++ ++ ++ BUG_ON(pin > chip->ngpio); ++ if (NULL == jzgc->irq_domain) return -ENXIO; ++ virq = irq_create_mapping(jzgc->irq_domain, pin); ++ ++ return (virq) ?: -ENXIO; ++} ++static int ingenic_gpio_request(struct gpio_chip *chip, unsigned offset) ++{ ++ struct ingenic_gpio_chip *jzgc = gc_to_ingenic_gc(chip); ++ unsigned gpio = chip->base + offset; ++ ++ if(jzgc->used_pins_bitmap & (1 << offset)) { ++ printk("%s: GP:%s used_pins_bitmap: 0X%08X\n", __func__, jzgc->name, jzgc->used_pins_bitmap); ++ printk("current gpio request pin: chip->name %s, gpio: 0X%08X\n", chip->of_node->name, 1 << offset); ++ dump_stack(); ++ printk("%s:gpio functions has redefinition\n", __FILE__); ++ } ++ ++ jzgc->used_pins_bitmap |= 1 << offset; ++ ++ return pinctrl_request_gpio(gpio); ++} ++static void ingenic_gpio_free(struct gpio_chip *chip, unsigned offset) ++{ ++ struct ingenic_gpio_chip *jzgc = gc_to_ingenic_gc(chip); ++ unsigned gpio = chip->base + offset; ++ pinctrl_free_gpio(gpio); ++ jzgc->used_pins_bitmap &= ~(1 << offset); ++} ++ ++static const struct gpio_chip ingenic_gpiolib_chip = { ++ .owner = THIS_MODULE, ++ .set = ingenic_gpio_set, ++ .get = ingenic_gpio_get, ++ .direction_input = ingenic_gpio_direction_input, ++ .direction_output = ingenic_gpio_direction_output, ++ .to_irq = ingenic_gpio_to_irq, ++ .request = ingenic_gpio_request, ++ .free = ingenic_gpio_free, ++}; ++ ++static int ingenic_of_gpio_xlate(struct gpio_chip *gc, ++ const struct of_phandle_args *gpiospec, u32 *flags) ++{ ++ struct ingenic_gpio_chip *jzgc = gc_to_ingenic_gc(gc); ++ u32 pin; ++ u32 pull; ++#if defined(INGENIC_GPIO_FILTER) ++ u32 filter; ++#endif ++ u32 drive_strength = 0; ++ u32 schmit_enable = 0; ++ u32 slewrate_enable = 0; ++ ++ if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells)) ++ return -EINVAL; ++ ++ if (gpiospec->args[0] >= gc->ngpio) ++ return -EINVAL; ++ ++ if (flags) ++ *flags = gpiospec->args[1]; ++ ++ pin = gpiospec->args[0]; ++ ++ pull = INGENIC_GPIO_PULL(gpiospec->args[2]); ++ ingenic_gpio_set_pull(jzgc, BIT(pin), pull); ++ ++ drive_strength = INGENIC_GPIO_DRIVE_STRENGTH(gpiospec->args[2]); ++ schmit_enable = INGENIC_GPIO_SCHMITT_ENABLE(gpiospec->args[2]); ++ slewrate_enable = INGENIC_GPIO_SLEW_RATE_ENABLE(gpiospec->args[2]); ++ ++ ingenic_gpio_set_drive_strength(jzgc, pin, drive_strength); ++ ingenic_gpio_set_schmitt_enable(jzgc, pin, schmit_enable); ++ ingenic_gpio_set_slew_rate(jzgc, pin, slewrate_enable); ++ ++#if defined(INGENIC_GPIO_FILTER) ++ filter = INGENIC_GPIO_FILTER(gpiospec->args[2]); ++ if (jzgc->filter_bitmap & BIT(pin)) ++ ingenic_gpio_set_filter(jzgc, pin, filter); ++#endif ++ return pin; ++} ++ ++static int ingenic_gpio_chip_add(struct ingenic_pinctrl *pctl, ++ struct device_node *np, int base, int idx) ++{ ++ struct ingenic_gpio_chip *jzgc = &pctl->gpio_chips[idx]; ++ struct gpio_chip *gc = &jzgc->gc; ++ u32 ngpio; ++ ++ jzgc->gc = ingenic_gpiolib_chip; ++ snprintf(jzgc->name, sizeof(jzgc->name), "GP%c", 'A' + idx); ++ ++ if (of_property_read_u32(np, "ingenic,num-gpios", &ngpio)) ++ ngpio = MAX_GPIOS_ON_CHIP; ++ if (of_property_read_u32(np, "ingenic,filter-gpios", &jzgc->filter_bitmap)) ++ jzgc->filter_bitmap = 0; ++ if (of_property_read_u32(np, "ingenic,pull-gpios", &jzgc->pull_bitmap)) ++ jzgc->pull_bitmap = 0; ++ if (of_property_read_u32(np, "#gpio-cells", &gc->of_gpio_n_cells)) ++ gc->of_gpio_n_cells = 3; ++ jzgc->used_pins_bitmap = 0; ++ pr_debug("%s (%d) config:\nfilter %08x\npull %08x\ncells=%d\nbase%d\n", ++ jzgc->name, ++ ngpio, ++ jzgc->filter_bitmap, ++ jzgc->pull_bitmap, ++ gc->of_gpio_n_cells, ++ base); ++ jzgc->of_node = np; ++ jzgc->idx = idx; ++ jzgc->pctl = pctl; ++ gc->ngpio = (u16)ngpio; ++ gc->of_node = np; ++ gc->base = base; ++ gc->dev = pctl->dev; ++ gc->label = jzgc->name; ++ gc->of_xlate = ingenic_of_gpio_xlate; ++ ++ return gpiochip_add(gc); ++} ++ ++static void ingenic_gpio_sleep_init(struct device_node *np, ++ const char *list_name, u32 *pm_pin) ++{ ++ int size, i, array[32], pin_bitmap = 0; ++ ++ if (!of_find_property(np, list_name, &size)) ++ return; ++ ++ if (of_property_read_u32_array(np, list_name, ++ array, size/sizeof(u32))) ++ return; ++ ++ for (i = 0; i < size/sizeof(u32); i++) { ++ BUG_ON(array[i] > 31); ++ pin_bitmap |= BIT(array[i]); ++ } ++ ++ *pm_pin = pin_bitmap; ++} ++ ++static void ingenic_gpio_pm_init(struct ingenic_pinctrl *pctl, ++ struct device_node *np, int idx) ++{ ++ struct ingenic_gpio_chip *jzgc = &pctl->gpio_chips[idx]; ++ ++ ingenic_gpio_sleep_init(np, "ingenic,gpio-sleep-low", ++ &jzgc->pm_bitmap[PM_SLEEP_LOW]); ++ ingenic_gpio_sleep_init(np, "ingenic,gpio-sleep-high", ++ &jzgc->pm_bitmap[PM_SLEEP_HIGH]); ++ ingenic_gpio_sleep_init(np, "ingenic,gpio-sleep-pull", ++ &jzgc->pm_bitmap[PM_SLEEP_PULL]); ++ ingenic_gpio_sleep_init(np, "ingenic,gpio-sleep-npul", ++ &jzgc->pm_bitmap[PM_SLEEP_NOPULL]); ++ ingenic_gpio_sleep_init(np, "ingenic,gpio-sleep-pullup", ++ &jzgc->pm_bitmap[PM_SLEEP_PULL_UP]); ++ ingenic_gpio_sleep_init(np, "ingenic,gpio-sleep-pulldown", ++ &jzgc->pm_bitmap[PM_SLEEP_PULL_DOWN]); ++ ingenic_gpio_sleep_init(np, "ingenic,gpio-sleep-hiz", ++ &jzgc->pm_bitmap[PM_SLEEP_HIZ]); ++ ++ jzgc->wakeup_bitmap = 0; ++ ++ /*pr_info("%s pm sleep:\nlow %08x\nhigh %08x\npull %08x\nnpull %08x\n", ++ jzgc->name, jzgc->pm_bitmap[PM_SLEEP_LOW], ++ jzgc->pm_bitmap[PM_SLEEP_HIGH], ++ jzgc->pm_bitmap[PM_SLEEP_PULL], ++ jzgc->pm_bitmap[PM_SLEEP_NOPULL]); ++ */ ++} ++ ++static int ingenic_irq_domain_xlate(struct irq_domain *d, ++ struct device_node *ctrlr, ++ const u32 *intspec, unsigned int intsize, ++ unsigned long *out_hwirq, unsigned int *out_type) ++{ ++ struct ingenic_gpio_chip *jzgc = d->host_data; ++ u32 pin; ++#if defined(INGENIC_GPIO_PULL) ++ u32 pull; ++#endif ++#if defined(INGENIC_GPIO_FILTER) ++ u32 filter; ++#endif ++ ++ if (WARN_ON(intsize < 3)) ++ return -EINVAL; ++ pin = *out_hwirq = intspec[0]; ++ *out_type = (intsize > 1) ? intspec[1] : IRQ_TYPE_NONE; ++ ++#if defined(INGENIC_GPIO_PULL) ++ pull = INGENIC_GPIO_PULL(intspec[2]); ++ ingenic_gpio_set_pull(jzgc, BIT(pin), pull); ++#endif ++ ++#if defined(INGENIC_GPIO_FILTER) ++ filter = INGENIC_GPIO_FILTER(intspec[2]); ++ if (jzgc->filter_bitmap & BIT(pin)) ++ ingenic_gpio_set_filter(jzgc, pin, filter); ++#endif ++ return 0; ++} ++ ++static int ingenic_irq_domain_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw) ++{ ++ struct ingenic_gpio_chip *jzgc = d->host_data; ++ irq_set_chip_data(virq, jzgc); ++ irq_set_chip_and_handler(virq, &ingenic_gpio_irq_chip, ++ handle_level_irq); ++ return 0; ++} ++ ++static const struct irq_domain_ops ingenic_irq_domain_ops = { ++ .map = ingenic_irq_domain_map, ++ .xlate = ingenic_irq_domain_xlate, ++}; ++ ++static int ingenic_gpio_irq_init(struct ingenic_pinctrl *pctl, ++ struct device_node *np, int idx) ++{ ++ struct ingenic_gpio_chip *jzgc = &pctl->gpio_chips[idx]; ++ ++ jzgc->irq = irq_of_parse_and_map(np, 0); ++ if (!jzgc->irq) ++ return -EINVAL; ++ ++ jzgc->irq_domain = irq_domain_add_linear(np, jzgc->gc.ngpio, ++ &ingenic_irq_domain_ops, (void *)jzgc); ++ if (!jzgc->irq_domain) ++ return -ENOMEM; ++ irq_set_handler_data(jzgc->irq, jzgc); ++ irq_set_chained_handler(jzgc->irq, ingenic_gpio_irq_handler); ++ return 0; ++} ++ ++static int ingenic_gpiolib_register(struct ingenic_pinctrl *pctl) ++{ ++ struct ingenic_gpio_chip *gpio_chips; ++ struct device_node *np; ++ int idx = 0, ret; ++ ++ if (of_property_read_u32(pctl->of_node,"ingenic,num-chips", &pctl->num_chips)) ++ return -EINVAL; ++ ++ pctl->bitmap_priv = devm_kzalloc(pctl->dev, sizeof(u32) * pctl->num_chips, ++ GFP_KERNEL); ++ if (!pctl->bitmap_priv) ++ return -ENOMEM; ++ ++ gpio_chips = devm_kzalloc(pctl->dev, ++ pctl->num_chips * sizeof(struct ingenic_gpio_chip), ++ GFP_KERNEL); ++ pctl->gpio_chips = gpio_chips; ++ pctl->total_pins = 0; ++ spin_lock_init(&pctl->shadow_lock); ++ ++ for_each_child_of_node(pctl->of_node, np) { ++ if (!of_find_property(np, "gpio-controller", NULL)) ++ continue; ++ ++ if (WARN_ON(idx >= pctl->num_chips)) ++ break; ++ ++ ret = ingenic_gpio_chip_add(pctl, np, pctl->total_pins, idx); ++ if (ret) { ++ dev_err(pctl->dev, "%s gpio add failed\n", gpio_chips[idx].name); ++ return ret; ++ } ++ pctl->total_pins += gpio_chips[idx].gc.ngpio; ++ spin_lock_init(&gpio_chips[idx].lock); ++ ++ ingenic_gpio_pm_init(pctl, np, idx); ++ ++ if (!of_find_property(np, "interrupt-controller", NULL)) ++ goto next_chip; ++ ++ ret = ingenic_gpio_irq_init(pctl, np, idx); ++ if (ret) ++ dev_err(pctl->dev, "%s irq init failed\n", ++ gpio_chips[idx].gc.label); ++ ++next_chip: ++ of_node_get(np); ++ idx++; ++ } ++ ++ dev_info(pctl->dev, "%d gpio chip add success, pins %d\n", ++ idx, pctl->total_pins); ++ return 0; ++} ++ ++static int ingenic_get_group_count(struct pinctrl_dev *pctldev) ++{ ++ struct ingenic_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); ++ return pctl->num_groups; ++} ++ ++static const char* ingenic_get_group_name(struct pinctrl_dev *pctldev, ++ unsigned selector) ++{ ++ struct ingenic_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); ++ ++ BUG_ON(selector >= pctl->num_groups); ++ return pctl->groups[selector].name; ++} ++ ++static int ingenic_get_group_pins(struct pinctrl_dev *pctldev, ++ unsigned selector, ++ const unsigned **pins, ++ unsigned *num_pins) ++{ ++ struct ingenic_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); ++ ++ BUG_ON(selector >= pctl->num_groups); ++ *pins = pctl->groups[selector].pins; ++ *num_pins = pctl->groups[selector].num_pins; ++ return 0; ++} ++ ++static int ingenic_gc_match(struct gpio_chip *chip, void *data) ++{ ++ return chip->of_node == data; ++} ++ ++static int ingenic_packed_config(int cfgval, int *config) ++{ ++ int value; ++ ++ value = PINCFG_UNPACK_VALUE(cfgval); ++ switch (cfgval & PINCTL_CFG_TYPE_MSK ) { ++ case PINCTL_CFG_FILTER: ++ *config = pinconf_to_config_packed(PIN_CONFIG_INPUT_DEBOUNCE, value & 0xffff); ++ case PINCTL_CFG_DRIVE_STRENGTH: ++ *config = pinconf_to_config_packed(PIN_CONFIG_DRIVE_STRENGTH, value & 0xffff); ++ break; ++ case PINCTL_CFG_BIAS_PULL_PIN_DEFAULT: ++ *config = pinconf_to_config_packed(PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, 1); ++ break; ++ case PINCTL_CFG_BIAS_DISABLE: ++ *config = pinconf_to_config_packed(PIN_CONFIG_BIAS_DISABLE, 1); ++ break; ++ case PINCTL_CFG_BIAS_HIGH_IMPEDANCE: ++ *config = pinconf_to_config_packed(PIN_CONFIG_BIAS_HIGH_IMPEDANCE, 1); ++ break; ++ case PINCTL_CFG_INPUT_SCHMITT_ENABLE: ++ *config = pinconf_to_config_packed(PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1); ++ break; ++ case PINCTL_CFG_SLEW_RATE: ++ *config = pinconf_to_config_packed(PIN_CONFIG_SLEW_RATE, 1); ++ break; ++ default: ++ *config = 0; ++ } ++ return 0; ++} ++ ++#if defined(PINCTL_CFG_TYPES) ++static int of_prase_pincfg_to_map(struct device_node *np, ++ struct pinctrl_map *map, int num_maps) ++{ ++ struct of_phandle_args out_args; ++ struct ingenic_gpio_chip *jzgc; ++ struct gpio_chip *gc; ++ u32 idx = 0, config = 0, index = 0; ++ unsigned long pin, bitmap; ++ char *pin_names; ++ ++ while (!of_parse_phandle_with_args(np, "ingenic,pincfg", ++ "#ingenic,pincfg-cells", index++, ++ &out_args)) { ++ gc = gpiochip_find(out_args.np, ingenic_gc_match); ++ if (!gc) return -EINVAL; ++ jzgc = gc_to_ingenic_gc(gc); ++ ++ bitmap = pin_bitmap(out_args.args[PIN_ARGS_FROM_INDEX], ++ out_args.args[PIN_ARGS_TO_INDEX]); ++ ++ ingenic_packed_config(out_args.args[PIN_ARGS_CFG_INDEX], &config); ++ for_each_set_bit(pin, &bitmap, jzgc->gc.ngpio) { ++ pin_names = kzalloc(sizeof(char) * PIN_NAMES_LEN, GFP_KERNEL); ++ if (!pin_names) return -ENOMEM; ++ sprintf(pin_names, "%s-%d", jzgc->name, (unsigned)pin); ++ for (idx = 0; idx < num_maps && ++ map[idx].data.configs.group_or_pin && ++ strcmp(pin_names, map[idx].data.configs.group_or_pin); ++ idx++); ++ BUG_ON(num_maps == idx); ++ if (map[idx].data.configs.num_configs == PINCTL_CFG_TYPES) { ++ __WARN(); ++ continue; ++ } ++ kfree(map[idx].data.configs.group_or_pin); ++ map[idx].data.configs.group_or_pin = pin_names; ++ map[idx].data.configs.configs[map[idx].data.configs.num_configs] = config; ++ map[idx].data.configs.num_configs++; ++ map[idx].type = PIN_MAP_TYPE_CONFIGS_PIN; ++ } ++ } ++ return 0; ++} ++#endif ++ ++static int ingenic_dt_node_to_map(struct pinctrl_dev *pctldev, ++ struct device_node *np_config, ++ struct pinctrl_map **maps, unsigned *num_maps) ++{ ++ struct ingenic_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); ++ struct gpio_chip *gc; ++ struct ingenic_gpio_chip *jzgc; ++ struct device_node *node; ++ struct ingenic_pinctrl_group *grp; ++ struct ingenic_pinctrl_func *func; ++ struct pinctrl_map *new_map; ++ unsigned long *cfgs; ++ int index = 0, ret = 0; ++ unsigned map_cnt = 0, cfg_map_cnt = 0, idx; ++ struct of_phandle_args out_args; ++ u32 *pincfg_bitmap = pctl->bitmap_priv; ++ ++ grp = find_group_by_of_node(pctl, np_config); ++ if (!grp) ++ return -EINVAL; ++ ++ if ((node = of_get_parent(np_config)) == pctl->of_node) ++ func = find_func_by_of_node(pctl, np_config); ++ else ++ func = find_func_by_of_node(pctl, node); ++ of_node_put(node); ++ if (!func) ++ return -EINVAL; ++ ++ ++#if defined(PINCTL_CFG_TYPES) ++ for (idx = 0; idx < pctl->num_chips; idx++) ++ pincfg_bitmap[idx] = 0; ++ while (!of_parse_phandle_with_args(np_config, "ingenic,pincfg", ++ "#ingenic,pincfg-cells", index++, &out_args)) { ++ gc = gpiochip_find(out_args.np, ingenic_gc_match); ++ if (!gc) return -ENOMEM; ++ jzgc = gc_to_ingenic_gc(gc); ++ pincfg_bitmap[jzgc->idx] |= pin_bitmap(out_args.args[PIN_ARGS_FROM_INDEX], ++ out_args.args[PIN_ARGS_TO_INDEX]); ++ }; ++ for (idx = 0; idx < pctl->num_chips; idx++) ++ cfg_map_cnt += bit_count(pincfg_bitmap[idx]); ++ map_cnt = cfg_map_cnt; ++#endif ++ ++ if (of_find_property(np_config, "ingenic,pinmux", NULL) && ++ of_find_property(np_config, "ingenic,pinmux-funcsel", NULL)) ++ map_cnt++; ++ if (!map_cnt) return -EINVAL; ++ ++ *maps = new_map = kzalloc(sizeof(*new_map) * map_cnt, GFP_KERNEL); ++ if (!new_map) ++ return -ENOMEM; ++ ++#if defined(PINCTL_CFG_TYPES) ++ if (!cfg_map_cnt) ++ goto skip_config; ++ ++ cfgs = kzalloc(sizeof(*cfgs) * PINCTL_CFG_TYPES * cfg_map_cnt, GFP_KERNEL); ++ if (!cfgs) ++ return -ENOMEM; ++ ++ for (idx = 0; idx < cfg_map_cnt; idx++, cfgs += PINCTL_CFG_TYPES) { ++ new_map[idx].data.configs.configs = cfgs; ++ } ++ ++ ret = of_prase_pincfg_to_map(np_config, new_map, cfg_map_cnt); ++ if (ret) ++ return ret; ++#endif ++skip_config: ++ *num_maps = cfg_map_cnt; ++ if (!of_find_property(np_config, "ingenic,pinmux", NULL)) ++ return 0; ++ ++ jzgc = gc_to_ingenic_gc(grp->gc); ++ /* if(jzgc->used_pins_bitmap & grp->pinmux_bitmap) { */ ++ /* printk("%s: GP:%s used_pins_bitmap: 0X%08X\n", __func__, jzgc->name, jzgc->used_pins_bitmap); */ ++ /* printk("current set function pin: chip->name %s, gpio: 0X%08X\n", grp->name, grp->pinmux_bitmap); */ ++ /* dump_stack(); */ ++ /* printk("%s:gpio functions has redefinition\n", __FILE__); */ ++ /* } */ ++ jzgc->used_pins_bitmap |= grp->pinmux_bitmap; ++ new_map[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP; ++ new_map[*num_maps].data.mux.function = func->name; ++ new_map[*num_maps].data.mux.group = grp->name; ++ (*num_maps)++; ++ return 0; ++} ++ ++static void ingenic_dt_free_map(struct pinctrl_dev *pctldev, ++ struct pinctrl_map *maps, unsigned num_maps) ++{ ++ unsigned long *configs = NULL; ++ int idx; ++ for (idx = 0; idx < num_maps; idx++) { ++ if (maps[idx].type == PIN_MAP_TYPE_CONFIGS_GROUP) { ++ if (NULL == configs) ++ configs = maps[idx].data.configs.configs; ++ kfree(maps[idx].data.configs.group_or_pin); ++ } ++ } ++ kfree(configs); ++ kfree(maps); ++} ++ ++static const struct pinctrl_ops ingenic_pctl_ops = { ++ .get_groups_count = ingenic_get_group_count, ++ .get_group_name = ingenic_get_group_name, ++ .get_group_pins = ingenic_get_group_pins, ++ .dt_node_to_map = ingenic_dt_node_to_map, /* TODO: use generic map*/ ++ .dt_free_map = ingenic_dt_free_map, ++}; ++ ++static int ingenic_pinmux_get_functions_count(struct pinctrl_dev *pctldev) ++{ ++ struct ingenic_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); ++ return pctl->num_funs; ++} ++ ++static const char *ingenic_pinmux_get_function_name(struct pinctrl_dev *pctldev, ++ unsigned selector) ++{ ++ struct ingenic_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); ++ return pctl->functions[selector].name; ++} ++ ++static int ingenic_pinmux_get_groups(struct pinctrl_dev *pctldev, ++ unsigned selector, ++ const char * const **groups, ++ unsigned * const num_groups) ++{ ++ struct ingenic_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); ++ ++ BUG_ON(selector > pctl->num_funs); ++ *groups = pctl->functions[selector].groups; ++ *num_groups = pctl->functions[selector].num_groups; ++ return 0; ++} ++ ++static int ingenic_pinmux_enable(struct pinctrl_dev *pctldev, ++ unsigned func_selector, ++ unsigned group_selector) ++{ ++ struct ingenic_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); ++ struct ingenic_pinctrl_group *grp = NULL; ++ const struct ingenic_priv *priv = pctl->priv; ++ struct ingenic_gpio_chip *jzgc; ++ ++ if (func_selector > pctl->num_funs || ++ group_selector > pctl->num_groups) ++ return -EINVAL; ++ ++ grp = &pctl->groups[group_selector]; ++ jzgc = gc_to_ingenic_gc(grp->gc); ++ ++ ingenic_gpio_set_func(jzgc, priv->have_shadow, ++ grp->pinmux_func, grp->pinmux_bitmap); ++ return 0; ++} ++ ++static int ingenic_pinmux_gpio_set_dir(struct pinctrl_dev *pctldev, ++ struct pinctrl_gpio_range *range, unsigned gpio, ++ bool input) ++{ ++ struct ingenic_gpio_chip *jzgc = gc_to_ingenic_gc(range->gc); ++ const struct ingenic_priv *priv = jzgc->pctl->priv; ++ unsigned pin = gpio - range->gc->base; ++ unsigned pxpat0, pxint; ++ enum gpio_function func = GPIO_INPUT; ++ if (!input) { ++ pxpat0 = ingenic_gpio_readl(jzgc, PxPAT0); ++ if (pxpat0 & BIT(pin)) ++ func = GPIO_OUTPUT1; ++ else ++ func = GPIO_OUTPUT0; ++ } else { ++ pxint = ingenic_gpio_readl(jzgc, PxINT); ++ if (pxint & BIT(pin)) ++ return 0; ++ } ++ ingenic_gpio_set_func(jzgc, priv->have_shadow, func, BIT(pin)); ++ return 0; ++} ++ ++static const struct pinmux_ops ingenic_pinmux_ops = { ++ .get_functions_count = ingenic_pinmux_get_functions_count, ++ .get_function_name = ingenic_pinmux_get_function_name, ++ .get_function_groups = ingenic_pinmux_get_groups, ++ .set_mux = ingenic_pinmux_enable, ++ .gpio_set_direction = ingenic_pinmux_gpio_set_dir, ++}; ++ ++static int ingenic_pinconf_get(struct pinctrl_dev *pctldev, ++ unsigned gpio, ++ unsigned long *config) ++{ ++ struct gpio_chip *gc = gpio_to_chip(gpio); ++ struct ingenic_gpio_chip *jzgc = gc_to_ingenic_gc(gc); ++ enum pin_config_param param; ++ unsigned pin; ++ unsigned arg; ++ bool pull; ++ ++ if (!jzgc) return -EINVAL; ++ ++ pin = gpio - jzgc->gc.base; ++ ++ param = pinconf_to_config_param(*config); ++ ++ switch (param) { ++ case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: ++ case PIN_CONFIG_BIAS_DISABLE: ++ pull = ingenic_gpio_readl(jzgc, PxPUEN)&BIT(pin); ++ if ((jzgc->pull_bitmap & BIT(pin)) && pull) ++ *config = pinconf_to_config_packed(PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, 1); ++ else ++ *config = pinconf_to_config_packed(PIN_CONFIG_BIAS_DISABLE, 1); ++ break; ++ case PIN_CONFIG_DRIVE_STRENGTH: ++ arg = ingenic_gpio_get_drive_strength(jzgc, pin); ++ *config = pinconf_to_config_packed(param, arg); ++ break; ++ case PIN_CONFIG_BIAS_PULL_UP: ++ case PIN_CONFIG_BIAS_PULL_DOWN: ++ case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: ++ arg = ingenic_gpio_get_pull_state(jzgc, pin); ++ *config = pinconf_to_config_packed(param, arg); ++ break; ++ case PIN_CONFIG_SLEW_RATE: ++ arg = !!(ingenic_gpio_readl(jzgc, PxPSLW) & BIT(pin)); ++ *config = pinconf_to_config_packed(param, arg); ++ break; ++ case PIN_CONFIG_INPUT_SCHMITT_ENABLE: ++ arg = !!(ingenic_gpio_readl(jzgc, PxPSMT) & BIT(pin)); ++ *config = pinconf_to_config_packed(param, arg); ++ break; ++ default: ++ return -ENOTSUPP; ++ break; ++ } ++ return 0; ++} ++ ++static int ingenic_pinconf_set(struct pinctrl_dev *pctldev, ++ unsigned gpio, ++ unsigned long *configs, ++ unsigned num_configs) ++{ ++ struct gpio_chip *gc = gpio_to_chip(gpio); ++ struct ingenic_gpio_chip *jzgc = gc_to_ingenic_gc(gc); ++ enum pin_config_param param; ++ u16 value; ++ unsigned pin; ++ int i; ++ ++ ++ if (!jzgc) { ++ return -EINVAL; ++ } ++ ++ pin = gpio - jzgc->gc.base; ++ ++ dev_dbg(pctldev->dev, "%s %s %u %lx\n", __func__, jzgc->gc.label, pin, *configs); ++ ++ for(i = 0; i < num_configs; i++) { ++ param = pinconf_to_config_param(configs[i]); ++ switch (param) { ++ case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: ++ if (!(jzgc->pull_bitmap & BIT(pin))) ++ return -EINVAL; ++ ingenic_gpio_set_pull(jzgc, BIT(pin), INGENIC_GPIO_PULLUP); ++ break; ++ case PIN_CONFIG_BIAS_DISABLE: ++ if ((!(jzgc->pull_bitmap & BIT(pin)))) ++ return -EINVAL; ++ ingenic_gpio_set_pull(jzgc, BIT(pin), INGENIC_GPIO_HIZ); ++ break; ++ case PIN_CONFIG_INPUT_DEBOUNCE: ++ value = pinconf_to_config_argument(configs[i]); ++ ingenic_gpio_set_filter(jzgc, pin, value); ++ break; ++ case PIN_CONFIG_DRIVE_STRENGTH: ++ value = pinconf_to_config_argument(configs[i]); ++ ingenic_gpio_set_drive_strength(jzgc, pin, value); ++ break; ++ case PIN_CONFIG_INPUT_SCHMITT_ENABLE: ++ ingenic_gpio_set_schmitt_enable(jzgc, pin, 1); ++ break; ++ case PIN_CONFIG_SLEW_RATE: ++ ingenic_gpio_set_slew_rate(jzgc, pin, 1); ++ break; ++ case PIN_CONFIG_BIAS_PULL_UP: ++ ingenic_gpio_set_pull(jzgc, BIT(pin), INGENIC_GPIO_PULLUP); ++ break; ++ case PIN_CONFIG_BIAS_PULL_DOWN: ++ ingenic_gpio_set_pull(jzgc, BIT(pin), INGENIC_GPIO_PULLDOWN); ++ break; ++ case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: ++ ingenic_gpio_set_pull(jzgc, BIT(pin), INGENIC_GPIO_HIZ); ++ break; ++ default: ++ return -ENOTSUPP; ++ } ++ } ++ return 0; ++} ++ ++/* set the pin config settings for a specified pin group */ ++static int ingenic_pinconf_group_set(struct pinctrl_dev *pctldev, ++ unsigned group, unsigned long *configs, ++ unsigned num_configs) ++{ ++ struct ingenic_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); ++ struct ingenic_pinctrl_group *grp = NULL; ++ const unsigned int *pins; ++ unsigned int cnt; ++ ++ grp = &pctl->groups[group]; ++ pins = grp->pins; ++ ++ for (cnt = 0; cnt < grp->num_pins; cnt++) ++ ingenic_pinconf_set(pctldev, pins[cnt], configs, num_configs); ++ ++ return 0; ++} ++ ++/* get the pin config settings for a specified pin group */ ++static int ingenic_pinconf_group_get(struct pinctrl_dev *pctldev, ++ unsigned int group, unsigned long *config) ++{ ++ struct ingenic_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); ++ const unsigned int *pins; ++ ++ pins = pctl->groups[group].pins; ++ ingenic_pinconf_get(pctldev, pins[0], config); ++ return 0; ++} ++ ++ ++static const struct pinconf_ops ingenic_pinconf_ops = { ++ .pin_config_get = ingenic_pinconf_get, ++ .pin_config_set = ingenic_pinconf_set, ++ .pin_config_group_get = ingenic_pinconf_group_get, ++ .pin_config_group_set = ingenic_pinconf_group_set, ++}; ++ ++static int ingenic_init_group(struct device *dev, struct device_node *np, ++ struct ingenic_pinctrl_group *grp) ++{ ++ struct device_node *gpio_np = NULL; ++ struct of_phandle_args out_args; ++ u32 func; ++ int pin, idx = 0, index = 0; ++ ++ grp->name = np->name; ++ grp->of_node = np; ++ ++ while(!of_parse_phandle_with_args(np, "ingenic,pinmux", ++ "#ingenic,pinmux-cells", index++, &out_args)) { ++ if (gpio_np != NULL && out_args.np != gpio_np) ++ return -EINVAL; ++ if (of_property_read_u32(np, "ingenic,pinmux-funcsel", &func)) ++ return -EINVAL; ++ gpio_np = out_args.np; ++ grp->pinmux_bitmap |= pin_bitmap(out_args.args[PIN_ARGS_FROM_INDEX], ++ out_args.args[PIN_ARGS_TO_INDEX]); ++ } ++ if (!gpio_np) ++ return 0; ++ grp->gc = gpiochip_find(gpio_np, ingenic_gc_match); ++ if (!grp->gc) return -EINVAL; ++ grp->num_pins = bit_count(grp->pinmux_bitmap); ++ grp->pins = devm_kzalloc(dev, sizeof(unsigned) * grp->num_pins, ++ GFP_KERNEL); ++ if (!grp->pins) ++ return -ENOMEM; ++ ++ switch (func) { ++ case PINCTL_FUNCTION0: grp->pinmux_func = GPIO_FUNC_0; break; ++ case PINCTL_FUNCTION1: grp->pinmux_func = GPIO_FUNC_1; break; ++ case PINCTL_FUNCTION2: grp->pinmux_func = GPIO_FUNC_2; break; ++ case PINCTL_FUNCTION3: grp->pinmux_func = GPIO_FUNC_3; break; ++ case PINCTL_FUNCLOLVL: grp->pinmux_func = GPIO_OUTPUT0; break; ++ case PINCTL_FUNCHILVL: grp->pinmux_func = GPIO_OUTPUT1; break; ++ case PINCTL_FUNCINPUT: grp->pinmux_func = GPIO_INPUT; break; ++ default: ++ return -EINVAL; ++ } ++ for_each_set_bit(pin, (unsigned long *)&grp->pinmux_bitmap, grp->gc->ngpio) ++ grp->pins[idx++] = grp->gc->base + pin; ++ return 0; ++} ++ ++static struct ingenic_pinctrl_group* ingenic_pinctrl_create_groups( ++ struct device *dev, unsigned *cnt) ++{ ++ struct device_node *np, *subnp; ++ struct ingenic_pinctrl_group *grp; ++ unsigned int i = 0; ++ ++ *cnt = 0; ++ for_each_child_of_node(dev->of_node, np) { ++ unsigned count = 0; ++ if (!!of_find_property(np, "gpio-controller", NULL)) ++ continue; ++ if (!!(count = of_get_child_count(np))) ++ *cnt += count; ++ else ++ (*cnt)++; ++ } ++ ++ grp = devm_kzalloc(dev, sizeof(*grp) * (*cnt), GFP_KERNEL); ++ if (!grp) ++ return ERR_PTR(-ENOMEM); ++ ++ for_each_child_of_node(dev->of_node, np) { ++ if (!!of_find_property(np, "gpio-controller", NULL)) ++ continue; ++ ++ if (!of_get_child_count(np)) { ++ ingenic_init_group(dev, np, &grp[i++]); ++ continue; ++ } ++ ++ for_each_child_of_node(np, subnp) { ++ ingenic_init_group(dev, subnp, &grp[i++]); ++ } ++ } ++ return grp; ++} ++ ++static struct ingenic_pinctrl_func* ingenic_pinctrl_create_functions( ++ struct device *dev, unsigned int *cnt) ++{ ++ struct device_node *np, *subnp; ++ struct ingenic_pinctrl_func *func; ++ int i = 0; ++ ++ *cnt = 0; ++ for_each_child_of_node(dev->of_node, np) { ++ if (!!of_find_property(np, "gpio-controller", NULL)) ++ continue; ++ (*cnt)++; ++ } ++ ++ func = devm_kzalloc(dev, sizeof(*func) * (*cnt), GFP_KERNEL); ++ if (!func) ++ return ERR_PTR(-ENOMEM); ++ ++ for_each_child_of_node(dev->of_node, np) { ++ u8 num_child, j = 0; ++ if (!!of_find_property(np, "gpio-controller", NULL)) ++ continue; ++ func[i].name = np->name; ++ func[i].of_node = np; ++ num_child = of_get_child_count(np); ++ func[i].num_groups = num_child ?:1; ++ func[i].groups = devm_kzalloc(dev, sizeof(char *) * func[i].num_groups, ++ GFP_KERNEL); ++ if (!func[i].groups) ++ return ERR_PTR(-ENOMEM); ++ if (num_child) { ++ for_each_child_of_node(np, subnp) ++ func[i].groups[j++] = subnp->name; ++ } else ++ func[i].groups[0] = func[i].name; ++ i++; ++ } ++ return func; ++} ++ ++static int ingenic_pinctrl_parse_dt(struct ingenic_pinctrl *pctl) ++{ ++ struct ingenic_pinctrl_group *groups; ++ struct ingenic_pinctrl_func *functions; ++ unsigned int grp_cnt = 0, func_cnt = 0; ++ ++ groups = ingenic_pinctrl_create_groups(pctl->dev, &grp_cnt); ++ if (IS_ERR(groups)) { ++ dev_err(pctl->dev, "failed to parse pin groups\n"); ++ return PTR_ERR(groups); ++ } ++ ++ functions = ingenic_pinctrl_create_functions(pctl->dev, &func_cnt); ++ if (IS_ERR(functions)) { ++ dev_err(pctl->dev, "failed to parse pin functions\n"); ++ return PTR_ERR(groups); ++ } ++ ++ pctl->groups = groups; ++ pctl->num_groups = grp_cnt; ++ pctl->functions = functions; ++ pctl->num_funs = func_cnt; ++ return 0; ++} ++ ++static int ingenic_pinctrl_register(struct ingenic_pinctrl *pctl) ++{ ++ struct pinctrl_desc *pctl_desc = &pctl->pctl_desc; ++ struct pinctrl_pin_desc *pindesc, *pdesc; ++ char *pin_names; ++ unsigned chip, pin; ++ int ret; ++ ++ pctl_desc->name = "ingenic pinctrl"; ++ pctl_desc->owner = THIS_MODULE; ++ pctl_desc->pctlops = &ingenic_pctl_ops; ++ pctl_desc->pmxops = &ingenic_pinmux_ops; ++ pctl_desc->confops = &ingenic_pinconf_ops; ++ pctl_desc->npins = pctl->total_pins; ++ pindesc = devm_kzalloc(pctl->dev, ++ sizeof(*pindesc) * pctl_desc->npins, GFP_KERNEL); ++ if (!pindesc) ++ return -ENOMEM; ++ pctl_desc->pins = pindesc; ++ ++ for (pin = 0, pdesc = pindesc; pin < pctl_desc->npins; pin++, pdesc++) ++ pdesc->number = pin; ++ ++ pin_names = devm_kzalloc(pctl->dev, ++ sizeof(char) * PIN_NAMES_LEN * pctl_desc->npins, ++ GFP_KERNEL); ++ if (!pin_names) ++ return -ENOMEM; ++ ++ for (chip = 0; chip < pctl->num_chips; chip++) { ++ struct ingenic_gpio_chip *jzgc = &pctl->gpio_chips[chip]; ++ for (pin = 0; pin < jzgc->gc.ngpio; pin++) { ++ sprintf(pin_names, "%s-%d", jzgc->name, pin); ++ pdesc = pindesc++; ++ pdesc->name = pin_names; ++ pin_names += PIN_NAMES_LEN; ++ } ++ } ++ ++ ret = ingenic_pinctrl_parse_dt(pctl); ++ if (ret) ++ return ret; ++ ++ pctl->pctl_dev = pinctrl_register(pctl_desc, pctl->dev, pctl); ++ if (!pctl->pctl_dev) ++ return -EINVAL; ++ ++ for (chip = 0; chip < pctl->num_chips; chip++) { ++ struct ingenic_gpio_chip *jzgc = &pctl->gpio_chips[chip]; ++ ++ jzgc->grange.name = jzgc->name; ++ jzgc->grange.id = jzgc->idx; ++ jzgc->grange.pin_base = jzgc->gc.base; ++ jzgc->grange.base = jzgc->gc.base; ++ jzgc->grange.npins = jzgc->gc.ngpio; ++ jzgc->grange.gc = &jzgc->gc; ++ pinctrl_add_gpio_range(pctl->pctl_dev, &jzgc->grange); ++ } ++ ++ return 0; ++} ++ ++static ssize_t dump_gpio(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct ingenic_pinctrl *pctl = dev_get_drvdata(dev); ++ struct ingenic_gpio_chip *gpio_chips = pctl->gpio_chips; ++ const struct ingenic_priv *priv = pctl->priv; ++ int idx; ++ ssize_t len = 0; ++ ++ for (idx = 0; idx < pctl->num_chips; idx++) ++ len += snprintf(buf + len, PAGE_SIZE - len, "REG :|+++GP%c++|", ++ 'A' + idx); ++ len += snprintf(buf+len, PAGE_SIZE - len, "\n"); ++ for (idx = 0; idx < pctl->num_chips; idx++) ++ len += snprintf(buf + len, PAGE_SIZE - len, "INT :|%08x|", ++ ingenic_gpio_readl(&gpio_chips[idx], PxINT)); ++ len += snprintf(buf+len, PAGE_SIZE - len, "\n"); ++ for (idx = 0; idx < pctl->num_chips; idx++) ++ len += snprintf(buf + len, PAGE_SIZE - len, "MSK :|%08x|", ++ ingenic_gpio_readl(&gpio_chips[idx], PxMSK)); ++ len += snprintf(buf+len, PAGE_SIZE - len, "\n"); ++ for (idx = 0; idx < pctl->num_chips; idx++) ++ len += snprintf(buf + len, PAGE_SIZE - len, "PAT1:|%08x|", ++ ingenic_gpio_readl(&gpio_chips[idx], PxPAT1)); ++ len += snprintf(buf+len, PAGE_SIZE - len, "\n"); ++ for (idx = 0; idx < pctl->num_chips; idx++) ++ len += snprintf(buf + len, PAGE_SIZE - len, "PAT0:|%08x|", ++ ingenic_gpio_readl(&gpio_chips[idx], PxPAT0)); ++ len += snprintf(buf+len, PAGE_SIZE - len, "\n"); ++ for (idx = 0; idx < pctl->num_chips; idx++) ++ len += snprintf(buf + len, PAGE_SIZE - len, "PULL_UP:|%08x|", ++ ingenic_gpio_readl(&gpio_chips[idx], PxPUEN)); ++ len += snprintf(buf+len, PAGE_SIZE - len, "\n"); ++ for (idx = 0; idx < pctl->num_chips; idx++) ++ len += snprintf(buf + len, PAGE_SIZE - len, "PULL_DOWN:|%08x|", ++ ingenic_gpio_readl(&gpio_chips[idx], PxPDEN)); ++ len += snprintf(buf+len, PAGE_SIZE - len, "\n"); ++ for (idx = 0; idx < pctl->num_chips; idx++) ++ len += snprintf(buf + len, PAGE_SIZE - len, "FLAG:|%08x|", ++ ingenic_gpio_readl(&gpio_chips[idx], PxFLG)); ++ len += snprintf(buf+len, PAGE_SIZE - len, "\n"); ++ ++ if (priv->dump_filter) ++ len += priv->dump_filter(pctl, buf+len, PAGE_SIZE - len); ++ return len; ++} ++static DEVICE_ATTR(dump_gpio, 0444, dump_gpio, NULL); ++ ++static struct attribute *ingenic_pinctrl_attrs[] = { ++ &dev_attr_dump_gpio.attr, ++ NULL, ++}; ++ ++static const struct attribute_group ingenic_pinctrl_attr_group = { ++ .attrs = (struct attribute **)ingenic_pinctrl_attrs, ++}; ++ ++ ++static int ingenic_pinctrl_probe(struct platform_device *pdev) ++{ ++ struct ingenic_pinctrl *pctl; ++ const struct of_device_id *match; ++ struct resource *res; ++ int ret; ++ ++ pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL); ++ if (!pctl) ++ return -ENOMEM; ++ match = of_match_node(ingenic_pinctrl_dt_match, pdev->dev.of_node); ++ if (!match) ++ return -ENODEV; ++ ++ pctl->priv = !match->data ? common_priv_data : (struct ingenic_priv *)match->data; ++ pctl->dev = &pdev->dev; ++ pctl->of_node = pdev->dev.of_node; ++ ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) ++ return -ENOMEM; ++ ++ pctl->io_base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(pctl->io_base)) ++ return PTR_ERR(pctl->io_base); ++ ++ platform_set_drvdata(pdev, pctl); ++ ++ ret = ingenic_gpiolib_register(pctl); ++ if (ret) ++ return ret; ++ ++ ret = ingenic_pinctrl_register(pctl); ++ if (ret) ++ return ret; ++ ++ ret = sysfs_create_group(&pdev->dev.kobj, &ingenic_pinctrl_attr_group); ++ if (ret) ++ dev_info(&pdev->dev, "ingenic pinctrl attr create failed\n"); ++ ++ gpctl = pctl; ++ ++ dev_info(&pdev->dev, "ingenic pinctrl probe success\n"); ++ return 0; ++} ++ ++unsigned long ingenic_pinctrl_lock(int port) ++{ ++ unsigned long flags; ++ struct ingenic_gpio_chip *chip; ++ struct ingenic_pinctrl *pctl = NULL; ++ const struct ingenic_priv *priv = NULL; ++ ++ if (port < 0 || port >= gpctl->num_chips) ++ return 0; ++ ++ chip = &gpctl->gpio_chips[port]; ++ pctl = chip->pctl; ++ priv = pctl->priv; ++ ++ if(priv->have_shadow) ++ spin_lock_irqsave(&pctl->shadow_lock, flags); ++ else ++ spin_lock_irqsave(&chip->lock, flags); ++ ++ return flags; ++} ++ ++unsigned long ingenic_pinctrl_unlock(int port, unsigned long flags) ++{ ++ struct ingenic_gpio_chip *chip; ++ struct ingenic_pinctrl *pctl = NULL; ++ const struct ingenic_priv *priv = NULL; ++ ++ if (port < 0 || port >= gpctl->num_chips) ++ return 0; ++ ++ chip = &gpctl->gpio_chips[port]; ++ pctl = chip->pctl; ++ priv = pctl->priv; ++ ++ if(priv->have_shadow) ++ spin_unlock_irqrestore(&pctl->shadow_lock, flags); ++ else ++ spin_unlock_irqrestore(&chip->lock, flags); ++ ++ return flags; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++#ifdef PINCTL_DEBUG ++static char dump_buf[PAGE_SIZE]; ++static void dump_pinctl(void) ++{ ++ struct ingenic_pinctrl *pctl = gpctl; ++ char *buf = dump_buf; ++ dump_gpio(pctl->dev, NULL, buf); ++ printk("%s\n", buf); ++} ++#else ++static void dump_pinctl(void) {} ++#endif ++ ++static int ingenic_gpio_suspend_set(struct ingenic_gpio_chip *jzgc) ++{ ++ const struct ingenic_priv *priv = jzgc->pctl->priv; ++ u32 pm_high = 0, pm_low = 0, pm_pullup = 0, pm_pulldown = 0, pm_hiz = 0; ++ ++ jzgc->pm_bitmap[PM_RESUME_INT] = ingenic_gpio_readl(jzgc, PxINT); ++ jzgc->pm_bitmap[PM_RESUME_MSK] = ingenic_gpio_readl(jzgc, PxMSK); ++ jzgc->pm_bitmap[PM_RESUME_PAT0] = ingenic_gpio_readl(jzgc, PxPAT0); ++ jzgc->pm_bitmap[PM_RESUME_PAT1] = ingenic_gpio_readl(jzgc, PxPAT1); ++ jzgc->pm_bitmap[PM_RESUME_PULL_UP] = ingenic_gpio_readl(jzgc, PxPUEN); ++ jzgc->pm_bitmap[PM_RESUME_PULL_DOWN] = ingenic_gpio_readl(jzgc, PxPDEN); ++ ++ pm_pullup = jzgc->pm_bitmap[PM_SLEEP_PULL_UP] & (~(jzgc->wakeup_bitmap)); ++ pm_pulldown = jzgc->pm_bitmap[PM_SLEEP_PULL_DOWN] & (~(jzgc->wakeup_bitmap)); ++ ++ pm_high = jzgc->pm_bitmap[PM_SLEEP_HIGH] & (~(jzgc->wakeup_bitmap)); ++ pm_low = jzgc->pm_bitmap[PM_SLEEP_LOW] & (~(jzgc->wakeup_bitmap)); ++ pm_hiz = jzgc->pm_bitmap[PM_SLEEP_HIZ] & (~(jzgc->wakeup_bitmap)); ++ ++ if (pm_pullup) { ++ ingenic_gpio_set_func(jzgc, priv->have_shadow, GPIO_INPUT, pm_pullup); ++ ingenic_gpio_set_pull(jzgc, pm_pullup, INGENIC_GPIO_PULLUP); ++ } ++ if (pm_pulldown) { ++ ingenic_gpio_set_func(jzgc, priv->have_shadow, GPIO_INPUT, pm_pulldown); ++ ingenic_gpio_set_pull(jzgc, pm_pulldown, INGENIC_GPIO_PULLDOWN); ++ } ++ if(pm_hiz) { ++ ingenic_gpio_set_func(jzgc, priv->have_shadow, GPIO_INPUT, pm_hiz); ++ ingenic_gpio_set_pull(jzgc, pm_hiz, INGENIC_GPIO_HIZ); ++ } ++ ++ if (pm_high) ++ ingenic_gpio_set_func(jzgc, priv->have_shadow, GPIO_OUTPUT1, pm_high); ++ if (pm_low) ++ ingenic_gpio_set_func(jzgc, priv->have_shadow, GPIO_OUTPUT0, pm_low); ++ ++ return 0; ++} ++ ++static int ingenic_pinctrl_suspend(void) ++{ ++ struct ingenic_pinctrl *pctl = gpctl; ++ int idx; ++ ++ if (!gpctl) ++ return 0; ++ dump_pinctl(); ++ for (idx = 0; idx < pctl->num_chips; idx++) { ++ struct ingenic_gpio_chip *chip = &pctl->gpio_chips[idx]; ++ ingenic_gpio_suspend_set(chip); ++ chip->resume_pending = 0; ++ } ++ ++ dump_pinctl(); ++ return 0; ++} ++ ++static void ingenic_check_wakeup_gpio(struct ingenic_gpio_chip *jzgc) ++{ ++ u32 pend, mask; ++ ++ pend = ingenic_gpio_readl(jzgc, PxFLG); ++ mask = ingenic_gpio_readl(jzgc, PxMSK); ++ pend = pend & ~mask; ++ pend = pend & jzgc->wakeup_bitmap; ++ if(pend) { ++ jzgc->resume_pending = pend; ++ jzgc->sleep_level = ingenic_gpio_readl(jzgc, PxPAT0) & pend; ++ } ++} ++ ++static void ingenic_pinctrl_resume(void) ++{ ++ struct ingenic_pinctrl *pctl = gpctl; ++ int idx; ++ ++ if (!gpctl) ++ return; ++ for (idx = 0; idx < pctl->num_chips; idx++) { ++ struct ingenic_gpio_chip *jzgc = &pctl->gpio_chips[idx]; ++ /*const struct ingenic_priv *priv = jzgc->pctl->priv;*/ ++ ingenic_check_wakeup_gpio(jzgc); ++ ingenic_gpio_writel(jzgc, PxINT, jzgc->pm_bitmap[PM_RESUME_INT]); ++ ingenic_gpio_writel(jzgc, PxMSK, jzgc->pm_bitmap[PM_RESUME_MSK]); ++ ingenic_gpio_writel(jzgc, PxPAT0, jzgc->pm_bitmap[PM_RESUME_PAT0]); ++ ingenic_gpio_writel(jzgc, PxPAT1, jzgc->pm_bitmap[PM_RESUME_PAT1]); ++ ingenic_gpio_writel(jzgc, PxPUEN, jzgc->pm_bitmap[PM_RESUME_PULL_UP]); ++ ingenic_gpio_writel(jzgc, PxPDEN, jzgc->pm_bitmap[PM_RESUME_PULL_DOWN]); ++ } ++} ++#else ++#define ingenic_pinctrl_suspend NULL ++#define ingenic_pinctrl_resume NULL ++#endif ++ ++static struct syscore_ops ingenic_pinctrl_syscore_ops = { ++ .suspend = ingenic_pinctrl_suspend, ++ .resume = ingenic_pinctrl_resume, ++}; ++ ++static const struct ingenic_priv common_priv_data[] = { ++ { ++ .have_shadow = true, ++ .pull_tristate = true, ++ }, ++}; ++ ++static const struct of_device_id ingenic_pinctrl_dt_match[] = { ++ { .compatible = "ingenic,t40-pinctrl", .data = (void *)common_priv_data}, ++ { .compatible = "ingenic,x2000-v12-pinctrl", .data = (void *)common_priv_data}, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ingenic_pinctrl_dt_match); ++ ++static struct platform_driver ingenic_pinctrl_drv = { ++ .probe = ingenic_pinctrl_probe, ++ .driver = { ++ .name = "ingenic pinctrl", ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(ingenic_pinctrl_dt_match), ++ }, ++}; ++ ++static int __init ingenic_pinctrl_drv_init(void) ++{ ++ register_syscore_ops(&ingenic_pinctrl_syscore_ops); ++ return platform_driver_register(&ingenic_pinctrl_drv); ++} ++postcore_initcall(ingenic_pinctrl_drv_init); ++ ++static void __exit ingenic_pinctrl_drv_exit(void) ++{ ++ unregister_syscore_ops(&ingenic_pinctrl_syscore_ops); ++ platform_driver_unregister(&ingenic_pinctrl_drv); ++ return; ++} ++module_exit(ingenic_pinctrl_drv_exit); ++ ++ ++int mcu_gpio_register(unsigned int ggpio, unsigned int reg) ++{ ++ struct ingenic_pinctrl *pctl = gpctl; ++ struct ingenic_gpio_chip *jzgc = NULL; ++ if (!gpctl) ++ return -ENODEV; ++ jzgc = &pctl->gpio_chips[ggpio]; ++ jzgc->mcu_gpio_reg = (unsigned int *)reg; ++ return 0; ++} ++EXPORT_SYMBOL_GPL(mcu_gpio_register); ++ ++void mcu_gpio_unregister(unsigned int ggpio) ++{ ++ struct ingenic_pinctrl *pctl = gpctl; ++ struct ingenic_gpio_chip *jzgc = NULL; ++ ++ if (!gpctl) ++ return; ++ jzgc = &pctl->gpio_chips[ggpio]; ++ jzgc->mcu_gpio_reg = NULL; ++} ++EXPORT_SYMBOL_GPL(mcu_gpio_unregister); ++ ++MODULE_AUTHOR("cli "); ++MODULE_DESCRIPTION("Ingenic pinctrl driver"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:pinctrl"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_pinctrl_pinctrl-ingenic.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_pinctrl_pinctrl-ingenic.h.patch new file mode 100644 index 00000000..8a129b22 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_pinctrl_pinctrl-ingenic.h.patch @@ -0,0 +1,281 @@ +diff -drupN a/drivers/pinctrl/pinctrl-ingenic.h b/drivers/pinctrl/pinctrl-ingenic.h +--- a/drivers/pinctrl/pinctrl-ingenic.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/pinctrl/pinctrl-ingenic.h 2022-06-09 05:02:33.000000000 +0300 +@@ -0,0 +1,277 @@ ++/* ++ * pinctrl/ingenic/pinctrl-ingenic.c ++ * ++ * Copyright 2015 Ingenic Semiconductor Co.,Ltd ++ * ++ * Author: cli ++ * ++ * 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. ++ */ ++ ++#ifndef __PINCTRL_INGENIC_H__ ++#define __PINCTRL_INGENIC_H__ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "core.h" ++ ++enum gpio_function { ++ GPIO_FUNC_0 = 0x00, //0000, GPIO as function 0 / device 0 ++ GPIO_FUNC_1 = 0x01, //0001, GPIO as function 1 / device 1 ++ GPIO_FUNC_2 = 0x02, //0010, GPIO as function 2 / device 2 ++ GPIO_FUNC_3 = 0x03, //0011, GPIO as function 3 / device 3 ++ GPIO_OUTPUT0 = 0x04, //0100, GPIO output low level ++ GPIO_OUTPUT1 = 0x05, //0101, GPIO output high level ++ GPIO_INPUT = 0x06, //0110, GPIO as input ++ GPIO_INT_LO = 0x0c, //1100, Low Level trigger interrupt ++ GPIO_INT_HI = 0x0d, //1101, High Level trigger interrupt ++ GPIO_INT_FE = 0x0e, //1110, Fall Edge trigger interrupt ++ GPIO_INT_RE = 0x0f, //1111, Rise Edge trigger interrupt ++ GPIO_INT_RE_FE = 0x10, //Fall&Rise Edge trigger interrupt ++}; ++ ++#define PxOFFSET 0x1000 ++#define PxPIN 0x00 /* PIN Level Register */ ++#define PxINT 0x10 /* Port Interrupt Register */ ++#define PxINTS 0x14 /* Port Interrupt Set Register */ ++#define PxINTC 0x18 /* Port Interrupt Clear Register */ ++#define PxMSK 0x20 /* Port Interrupt Mask Reg */ ++#define PxMSKS 0x24 /* Port Interrupt Mask Set Reg */ ++#define PxMSKC 0x28 /* Port Interrupt Mask Clear Reg */ ++#define PxPAT1 0x30 /* Port Pattern 1 Set Reg. */ ++#define PxPAT1S 0x34 /* Port Pattern 1 Set Reg. */ ++#define PxPAT1C 0x38 /* Port Pattern 1 Clear Reg. */ ++#define PxPAT0 0x40 /* Port Pattern 0 Register */ ++#define PxPAT0S 0x44 /* Port Pattern 0 Set Register */ ++#define PxPAT0C 0x48 /* Port Pattern 0 Clear Register */ ++#define PxFLG 0x50 /* Port Flag Register */ ++#define PxFLGC 0x58 /* Port Flag clear Register */ ++//#define PxPEN 0x60 /* Port Pull Disable Register */ ++//#define PxPENS 0x64 /* Port Pull Disable Set Register */ ++//#define PxPENC 0x68 /* Port Pull Disable Clear Register */ ++ ++ ++#define PxGFCFG0 0x70 /* Port Glitch Filter Configure 0 Register */ ++#define PxGFCFG0S 0x74 /* Port Glitch Filter Configure 0 Set Register */ ++#define PxGFCFG0C 0x78 /* Port Glitch Filter Configure 0 Clear Register */ ++#define PxGFCFG1 0x80 /* Port Glitch Filter Configure 1 Register */ ++#define PxGFCFG1S 0x84 /* Port Glitch Filter Configure 1 Set Register */ ++#define PxGFCFG1C 0x88 /* Port Glitch Filter Configure 1 Clear Register */ ++#define PxGFCFG2 0x90 /* Port Glitch Filter Configure 2 Register */ ++#define PxGFCFG2S 0x94 /* Port Glitch Filter Configure 2 Set Register */ ++#define PxGFCFG2C 0x98 /* Port Glitch Filter Configure 2 Clear Register */ ++#define PxGFCFG3 0xa0 /* Port Glitch Filter Configure 3 Register */ ++#define PxGFCFG3S 0xa4 /* Port Glitch Filter Configure 3 Set Register */ ++#define PxGFCFG3C 0xa8 /* Port Glitch Filter Configure 3 Clear Register */ ++ ++ ++#define PxGPDCR 0x100 /* Port IO Power Domain control Register */ ++#define PxGPDCRS 0x104 /* Port IO Power Domain control Set Register */ ++#define PxGPDCRC 0x108 /* Port IO Power Domain control Clear Register */ ++#define PxPUEN 0x110 /* Port Pull-up status Register */ ++#define PxPUENS 0x114 /* Port Pull-up status Set Register */ ++#define PxPUENC 0x118 /* Port Pull-up status Clear Register */ ++#define PxPDEN 0x120 /* Port Pull-down status Register */ ++#define PxPDENS 0x124 /* Port Pull-down status Set Register */ ++#define PxPDENC 0x128 /* Port Pull-down status Clear Register */ ++#define PxPDS0 0x130 /* Port Driver-strength 0 Register */ ++#define PxPDS0S 0x134 /* Port Driver-strength 0 Set Register */ ++#define PxPDS0C 0x138 /* Port Driver-strength 0 Clear Register */ ++#define PxPDS1 0x140 /* Port Driver-strength 1 Register */ ++#define PxPDS1S 0x144 /* Port Driver-strength 1 Set Register */ ++#define PxPDS1C 0x148 /* Port Driver-strength 1 Clear Register */ ++#define PxPDS2 0x150 /* Port Driver-strength 2 Register */ ++#define PxPDS2S 0x154 /* Port Driver-strength 2 Set Register */ ++#define PxPDS2C 0x158 /* Port Driver-strength 2 Clear Register */ ++#define PxPSLW 0x160 /* Port Slew Rate Register */ ++#define PxPSLWS 0x164 /* Port Slew Rate Set Register */ ++#define PxPSLWC 0x168 /* Port Slew Rate Clear Register */ ++#define PxPSMT 0x170 /* Port Schmitt Trigger Register */ ++#define PxPSMTS 0x174 /* Port Schmitt Trigger Set Register */ ++#define PxPSMTC 0x178 /* Port Schmitt Trigger Clear Register */ ++ ++/* Only PC use */ ++#define PxPSMT1 0x180 /* Port Schmitt 1 Trigger Register */ ++#define PxPSMT1S 0x184 /* Port Schmitt 1 Trigger Set Register */ ++#define PxPSMT1C 0x188 /* Port Schmitt 1 Trigger Clear Register */ ++#define PxPHE 0x190 /* Port Hold Enable Register */ ++#define PxPHES 0x194 /* Port Hold Enable Set Register */ ++#define PxPHEC 0x198 /* Port Hold Enable Clear Register */ ++ ++#define PSHADOW_OFF 0x7000 ++#define PZGIDLD 0xF0 /* GPIOZ Group ID to load */ ++ ++#define PIN_NAMES_LEN 10 ++#define MAX_GPIOS_ON_CHIP 32 ++#define MAX_FUNCTIONS_ON_GPIO 4 ++#define PIN_ARGS_FROM_INDEX 0 ++#define PIN_ARGS_TO_INDEX 1 ++#define PIN_ARGS_CFG_INDEX 2 ++ ++static inline u32 pin_bitmap(u32 from, u32 to) ++{ ++ if (to == 31) ++ return ~((1<<(from))-1); ++ return ((~((1<<(from))-1))&((1 << ((to)+1))-1)); ++} ++ ++static inline unsigned bit_count(unsigned v) ++{ ++ unsigned int c; ++ for (c = 0; v; c++) ++ v &= v - 1; ++ return c; ++} ++ ++typedef enum ingenic_gpio_pm_arr { ++ PM_SLEEP_PULL = 0, /*sleep state*/ /*input pull*/ ++ PM_SLEEP_NOPULL, /*input no pull*/ ++ PM_SLEEP_PULL_UP, /*input pull*/ ++ PM_SLEEP_PULL_DOWN, /*input pull*/ ++ PM_SLEEP_HIZ, /*input hiz*/ ++ PM_SLEEP_HIGH, /*output high*/ ++ PM_SLEEP_LOW, /*output low*/ ++ PM_RESUME_INT, /*keep register for resume*/ ++ PM_RESUME_MSK, ++ PM_RESUME_PAT0, ++ PM_RESUME_PAT1, ++ PM_RESUME_PULL_UP, ++ PM_RESUME_PULL_DOWN, ++ PM_STATE_CNT, ++} ingenic_gpio_pm_arr_t; ++ ++/*ingenic gpio chip*/ ++struct ingenic_gpio_chip { ++ struct gpio_chip gc; ++ char name[4]; /*name format "GPX"(X = 'A' + idx)*/ ++ u8 idx; /*gpio index of this chip*/ ++ const struct device_node *of_node; /*gpio chip device node*/ ++ int irq; /*gpio chip irq*/ ++ struct irq_domain *irq_domain; ++ struct pinctrl_gpio_range grange; ++ struct ingenic_pinctrl *pctl; ++ spinlock_t lock; /*gpio func write lock*/ ++ u32 *mcu_gpio_reg; /*used for gpio irq to mcu ++ mcu's pending register*/ ++ u32 used_pins_bitmap; /*bitmap of pins for been had requested*/ ++ u32 resume_pending; /*bitmap of pins wakeup pending when sleep*/ ++ u32 sleep_level; /*bitmap of pins level when sleep*/ ++ u32 filter_bitmap; /*bitmap of pins filter support*/ ++ u32 pull_bitmap; /*bitmap of pins pill support*/ ++ u32 wakeup_bitmap; /*bitmap of pins wakeup pins*/ ++ u32 pm_irq_bitmap; /*bitmap of pins used for irq sleep&resume*/ ++ u32 pm_bitmap[PM_STATE_CNT]; /*bitmap of pins used for sleep&resume*/ ++}; ++ ++#define gc_to_ingenic_gc(gpiochip) container_of(gpiochip, struct ingenic_gpio_chip, gc) ++ ++/*function information*/ ++struct ingenic_pinctrl_func { ++ const char *name; ++ struct device_node *of_node; /* function device node */ ++ const char **groups; /* all sub groups name*/ ++ u8 num_groups; /* num groups of this function */ ++}; ++ ++/*group information*/ ++struct ingenic_pinctrl_group { ++ const char *name; ++ struct device_node *of_node; /* group device node */ ++ struct gpio_chip *gc; /* corresponding gpio chip*/ ++ unsigned *pins; /* Contained pins software gpio num*/ ++ u8 num_pins; /* num gpios of the set group*/ ++ u32 pinmux_bitmap; /* pins bitmap of this group*/ ++ enum gpio_function pinmux_func; /* pins function select of this group*/ ++}; ++ ++/*soc private data*/ ++struct ingenic_priv { ++ bool have_shadow; /*support shadow register or not*/ ++ bool have_filter; /*support input pin filter of nor*/ ++ bool pull_tristate; /*support pullup/pulldown/hiz settable.*/ ++ int (*set_filter)(struct ingenic_gpio_chip *jzgc, /*set input pin filter function*/ ++ unsigned pin, ++ u16 filter); ++ ssize_t (*dump_filter)(struct ingenic_pinctrl *pctl, ++ char *buf, ++ ssize_t size); ++}; ++ ++struct ingenic_pinctrl { ++ void __iomem *io_base; ++ struct device_node *of_node; /*pinctrl device_node*/ ++ struct device *dev; ++ ++ spinlock_t shadow_lock; /*shadow register access lock*/ ++ struct ingenic_gpio_chip *gpio_chips; /*gpio chips of this pinctrl*/ ++ unsigned num_chips; /*num gpio chips*/ ++ unsigned total_pins; /*total pins of this pinctrl*/ ++ u32 *bitmap_priv; /*******private*******/ ++ ++ struct pinctrl_desc pctl_desc; ++ struct pinctrl_dev *pctl_dev; ++ ++ struct ingenic_pinctrl_group *groups; ++ unsigned num_groups; ++ ++ struct ingenic_pinctrl_func *functions; ++ unsigned num_funs; ++ ++ const struct ingenic_priv *priv; /*soc data*/ ++}; ++ ++static inline struct ingenic_pinctrl_group *find_group_by_of_node( ++ struct ingenic_pinctrl *pctl, struct device_node *np) ++{ ++ int i; ++ for (i = 0; i < pctl->num_groups; i++) { ++ if (pctl->groups[i].of_node == np) ++ return &pctl->groups[i]; ++ } ++ return NULL; ++} ++ ++static inline struct ingenic_pinctrl_func *find_func_by_of_node( ++ struct ingenic_pinctrl *pctl, struct device_node *np) ++{ ++ int i; ++ for (i = 0; i < pctl->num_funs; i++) { ++ if (pctl->functions[i].of_node == np) ++ return &pctl->functions[i]; ++ } ++ return NULL; ++} ++ ++static inline u32 ingenic_gpio_readl(struct ingenic_gpio_chip *chip, int offset) ++{ ++ struct ingenic_pinctrl *pctl = chip->pctl; ++ return readl(pctl->io_base + (chip->idx * PxOFFSET) + offset); ++} ++ ++static inline void ingenic_gpio_writel(struct ingenic_gpio_chip *chip, int offset, int value) ++{ ++ struct ingenic_pinctrl *pctl = chip->pctl; ++ writel(value , pctl->io_base + (chip->idx * PxOFFSET) + offset); ++} ++ ++static inline void ingenic_gpio_shadow_fill(struct ingenic_gpio_chip *chip, int offset, int value) ++{ ++ struct ingenic_pinctrl *pctl = chip->pctl; ++ writel(value, pctl->io_base + PSHADOW_OFF + offset); ++} ++ ++static inline void ingenic_gpio_shadow_writel(struct ingenic_gpio_chip *chip) ++{ ++ struct ingenic_pinctrl *pctl = chip->pctl; ++ writel(chip->idx, pctl->io_base + PSHADOW_OFF + PZGIDLD); ++} ++#endif /*__PINCTRL_INGENIC_H__*/ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_pwm_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_pwm_Kconfig.patch new file mode 100644 index 00000000..a1b9b73d --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_pwm_Kconfig.patch @@ -0,0 +1,31 @@ +diff -drupN a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig +--- a/drivers/pwm/Kconfig 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/pwm/Kconfig 2022-06-09 05:02:33.000000000 +0300 +@@ -189,6 +189,27 @@ config PWM_JZ4740 + To compile this driver as a module, choose M here: the module + will be called pwm-jz4740. + ++config PWM_INGENIC ++ tristate "Ingenic PWM support" ++ depends on MACH_XBURST ++ help ++ Generic PWM framework driver for Ingenic soc based ++ machines. ++ ++ To compile this driver as a module, choose M here: the module ++ will be called pwm-ingenic. ++ ++config PWM_INGENIC_V2 ++ tristate "Ingenic PWM V2 support" ++ depends on MACH_XBURST2 ++ help ++ Generic PWM framework driver for Ingenic soc based ++ machines. ++ Support SOCs: X2000, ++ ++ To compile this driver as a module, choose M here: the module ++ will be called pwm-ingenic. ++ + config PWM_LP3943 + tristate "TI/National Semiconductor LP3943 PWM support" + depends on MFD_LP3943 diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_pwm_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_pwm_Makefile.patch new file mode 100644 index 00000000..78466098 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_pwm_Makefile.patch @@ -0,0 +1,12 @@ +diff -drupN a/drivers/pwm/Makefile b/drivers/pwm/Makefile +--- a/drivers/pwm/Makefile 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/pwm/Makefile 2022-06-09 05:02:33.000000000 +0300 +@@ -16,6 +16,8 @@ obj-$(CONFIG_PWM_FSL_FTM) += pwm-fsl-ftm + obj-$(CONFIG_PWM_IMG) += pwm-img.o + obj-$(CONFIG_PWM_IMX) += pwm-imx.o + obj-$(CONFIG_PWM_JZ4740) += pwm-jz4740.o ++obj-$(CONFIG_PWM_INGENIC) += pwm-ingenic.o ++obj-$(CONFIG_PWM_INGENIC_V2) += pwm-ingenic-v2.o + obj-$(CONFIG_PWM_LP3943) += pwm-lp3943.o + obj-$(CONFIG_PWM_LPC18XX_SCT) += pwm-lpc18xx-sct.o + obj-$(CONFIG_PWM_LPC32XX) += pwm-lpc32xx.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_pwm_core.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_pwm_core.c.patch new file mode 100644 index 00000000..469b1cfc --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_pwm_core.c.patch @@ -0,0 +1,11 @@ +diff -drupN a/drivers/pwm/core.c b/drivers/pwm/core.c +--- a/drivers/pwm/core.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/pwm/core.c 2022-06-09 05:02:33.000000000 +0300 +@@ -645,6 +645,7 @@ void pwm_add_table(struct pwm_lookup *ta + + mutex_unlock(&pwm_lookup_lock); + } ++EXPORT_SYMBOL_GPL(pwm_add_table); + + /** + * pwm_remove_table() - unregister PWM device consumers diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_pwm_pwm-ingenic-v2.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_pwm_pwm-ingenic-v2.c.patch new file mode 100644 index 00000000..11700c52 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_pwm_pwm-ingenic-v2.c.patch @@ -0,0 +1,925 @@ +diff -drupN a/drivers/pwm/pwm-ingenic-v2.c b/drivers/pwm/pwm-ingenic-v2.c +--- a/drivers/pwm/pwm-ingenic-v2.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/pwm/pwm-ingenic-v2.c 2022-06-09 05:02:33.000000000 +0300 +@@ -0,0 +1,921 @@ ++/* drivers/pwm/pwm-ingenic-x2000.c ++ * PWM driver of Ingenic's SoC X2000 ++ * ++ * Copyright (C) 2015 Ingenic Semiconductor Co., Ltd. ++ * http://www.ingenic.com ++ * Author: sihui.liu ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define INGENIC_PWM_NUM (16) ++#define NS_IN_HZ (1000000000UL) ++#define DEFAULT_PWM_CLK_RATE (50000000) ++ ++struct ingenic_pwm_channel { ++ u32 period_ns; ++ u32 duty_ns; ++}; ++ ++enum pwm_mode_sel{ ++ COMMON_MODE, ++ DMA_MODE ++}; ++#define PWM_INIT_HIGH (1) ++#define PWM_INIT_LOW (0) ++ ++ ++struct ingenic_pwm_chip { ++ struct pwm_chip chip; ++ struct clk *clk_pwm; ++ struct clk *clk_gate; ++ void __iomem *iomem; ++ int init_level; ++ struct mutex mutex; ++ unsigned int output_mask; ++ ++ struct pwm_device *debug_pwm[INGENIC_PWM_NUM]; ++ unsigned int vir_addr[INGENIC_PWM_NUM]; ++ unsigned int phy_addr[INGENIC_PWM_NUM]; ++ int debug_current_id; ++ int mode_sel[INGENIC_PWM_NUM]; ++ int irq; ++}; ++ ++ ++ ++ ++ ++/**----------------------------------------------------------------------------- ++ ** reg offset ++ **-----------------------------------------------------------------------------*/ ++ ++ ++#define PWM_CCFG0 (0x0) ++#define PWM_CCFG1 (0x4) ++#define PWM_ENS (0x10) ++#define PWM_ENC (0x14) ++#define PWM_EN (0x18) ++#define PWM_UP (0x20) ++#define PWM_BUSY (0x24) ++#define PWM_INITR (0x30) ++#define PWM_WCFG (0xb0) ++#define PWM_DES (0x100) ++#define PWM_DEC (0x104) ++#define PWM_DE (0x108) ++#define PWM_DCR0 (0x110) ++#define PWM_DCR1 (0x114) ++#define PWM_DTRIG (0x120) ++#define PWM_DFER (0x124) ++#define PWM_DFSM (0x128) ++#define PWM_DSR (0x130) ++#define PWM_DSCR (0x134) ++#define PWM_DINTC (0x138) ++#define PWM_DMADDR (0x140) ++#define PWM_DTLR (0x190) ++#define PWM_OEN (0x300) ++ ++ ++#define PRESCALE_MSK (0xf) ++#define PRESCALE (0x2) ++#define TRANS_LEN (32) ++#define PWM_PER (0x30) ++ ++ ++/**----------------------------------------------------------------------------- ++ ** reg bit field ++ **-----------------------------------------------------------------------------*/ ++ ++/** ++ ** PWM Waveform Configuration Register (PWMWCFG) ++ **/ ++#define PWM_WCFG_HIGH (16) ++#define PWM_WCFG_LOW (0) ++ ++static void pwm_writel(struct ingenic_pwm_chip *chip, unsigned int value, unsigned int offset) ++{ ++ writel(value, chip->iomem + offset); ++} ++ ++static unsigned int pwm_readl(struct ingenic_pwm_chip *chip, unsigned int offset) ++{ ++ return readl(chip->iomem + offset); ++} ++ ++static void pwm_clk_config(struct ingenic_pwm_chip *chip, unsigned int channel, unsigned int prescale) ++{ ++ int tmp = 0; ++ if(channel < 8) { ++ tmp = pwm_readl(chip, PWM_CCFG0) & ~(PRESCALE_MSK << (channel *4)); ++ tmp |= prescale << (channel * 4); ++ pwm_writel(chip, tmp, PWM_CCFG0); ++ } else { ++ tmp = pwm_readl(chip, PWM_CCFG1) & ~(PRESCALE_MSK << ((channel - 8) * 4)); ++ tmp |= prescale << ((channel - 8) * 4); ++ pwm_writel(chip, tmp, PWM_CCFG1); ++ } ++} ++ ++static unsigned int pwm_get_prescale(struct ingenic_pwm_chip *chip, unsigned int channel) ++{ ++ int tmp = 0; ++ int prescale = 0; ++ if(channel < 8) { ++ tmp = pwm_readl(chip, PWM_CCFG0); ++ prescale = tmp & (0xf << channel * 4); ++ } else { ++ tmp = pwm_readl(chip, PWM_CCFG1); ++ prescale = tmp & (0xf << (channel - 8) * 4); ++ } ++ return prescale; ++} ++ ++static void pwm_enable_hw(struct ingenic_pwm_chip *chip, unsigned int channel) ++{ ++ int tmp = 0; ++ tmp = pwm_readl(chip, PWM_EN); ++ tmp |= (1 << channel); ++ pwm_writel(chip, tmp, PWM_ENS); ++} ++ ++static void pwm_disable_hw(struct ingenic_pwm_chip *chip, unsigned int channel) ++{ ++ pwm_writel(chip, 1 << channel, PWM_ENC); ++} ++ ++static int pwm_enable_status(struct ingenic_pwm_chip *chip) ++{ ++ return pwm_readl(chip, PWM_EN); ++} ++ ++static void pwm_update(struct ingenic_pwm_chip *chip, unsigned int channel) ++{ ++ pwm_writel(chip, 1 << channel, PWM_UP); ++} ++ ++static int pwm_busy(struct ingenic_pwm_chip *chip, unsigned int channel) ++{ ++ int tmp = 0; ++ tmp = pwm_readl(chip, PWM_BUSY); ++ return tmp & (1 << channel); ++} ++ ++static void pwm_set_period_hw(struct ingenic_pwm_chip *chip, unsigned int channel, unsigned int period) ++{ ++ pwm_writel(chip, period, PWM_PER + channel * 4); ++} ++ ++static void pwm_set_init_level(struct ingenic_pwm_chip *ingenic_pwm, unsigned int channel, unsigned int level) ++{ ++ int tmp; ++ tmp = pwm_readl(ingenic_pwm,PWM_INITR); ++ if(level) ++ tmp |= 1 << channel; ++ else ++ tmp &= ~(1 << channel); ++ pwm_writel(ingenic_pwm,tmp,PWM_INITR); ++} ++ ++static void pwm_set_finish_level(struct ingenic_pwm_chip *ingenic_pwm, unsigned int channel, unsigned int level) ++{ ++ int tmp; ++ tmp = pwm_readl(ingenic_pwm,PWM_INITR); ++ if(level) ++ tmp |= 1 << (channel + 16); ++ else ++ tmp &= ~(1 << (channel + 16)); ++ pwm_writel(ingenic_pwm,tmp,PWM_INITR); ++} ++ ++static void pwm_waveform_high(struct ingenic_pwm_chip *ingenic_pwm, unsigned int channel, unsigned int high_num) ++{ ++ int tmp = 0; ++ tmp = pwm_readl(ingenic_pwm, PWM_WCFG + channel * 4); ++ tmp &= ~(0xffff << PWM_WCFG_HIGH); ++ tmp |= high_num << PWM_WCFG_HIGH; ++ pwm_writel(ingenic_pwm, tmp, PWM_WCFG + channel * 4); ++} ++ ++static void pwm_waveform_low(struct ingenic_pwm_chip *ingenic_pwm, unsigned int channel, unsigned int low_num) ++{ ++ int tmp = 0; ++ tmp = pwm_readl(ingenic_pwm, PWM_WCFG + channel * 4); ++ tmp &= ~(0xffff); ++ tmp |= low_num << PWM_WCFG_LOW; ++ pwm_writel(ingenic_pwm, tmp, PWM_WCFG + channel * 4); ++} ++ ++/*pwm DMA mode control register operation*/ ++static void pwm_dma_enable_hw(struct ingenic_pwm_chip *ingenic_pwm, unsigned int channel) ++{ ++ int tmp = 0; ++ tmp = pwm_readl(ingenic_pwm, PWM_DES); ++ tmp |= (1 << channel); ++ pwm_writel(ingenic_pwm, tmp, PWM_DES); ++} ++ ++static void pwm_dma_disable_hw(struct ingenic_pwm_chip *ingenic_pwm, unsigned int channel) ++{ ++ pwm_writel(ingenic_pwm, 1 << channel, PWM_DEC); ++} ++ ++static int pwm_dma_enable_status(struct ingenic_pwm_chip *ingenic_pwm) ++{ ++ return pwm_readl(ingenic_pwm, PWM_DE); ++} ++ ++static void pwm_set_update_mode(struct ingenic_pwm_chip *ingenic_pwm, unsigned int channel, int mode_sel) ++{ ++ int tmp; ++ tmp = pwm_readl(ingenic_pwm,PWM_DCR0); ++ if(mode_sel == DMA_MODE) ++ tmp |= 1 << channel; ++ if(mode_sel == COMMON_MODE) ++ tmp &= ~(1 << channel); ++ pwm_writel(ingenic_pwm,tmp,PWM_DCR0); ++} ++ ++static void pwm_dma_set_loop(struct ingenic_pwm_chip *ingenic_pwm, unsigned int channel) ++{ ++ int tmp; ++ tmp = pwm_readl(ingenic_pwm,PWM_DCR1); ++ tmp |= 1 << channel; ++ pwm_writel(ingenic_pwm,tmp,PWM_DCR1); ++} ++ ++static void pwm_dma_clear_loop(struct ingenic_pwm_chip *ingenic_pwm, unsigned int channel) ++{ ++ int tmp; ++ tmp = pwm_readl(ingenic_pwm,PWM_DCR1); ++ tmp &= ~(1 << channel); ++ pwm_writel(ingenic_pwm,tmp,PWM_DCR1); ++} ++ ++static unsigned int pwm_dma_get_loop_status(struct ingenic_pwm_chip *ingenic_pwm,unsigned int channel) ++{ ++ return pwm_readl(ingenic_pwm,PWM_DCR1) & (1 << channel); ++} ++ ++static void pwm_dma_trans_trigger(struct ingenic_pwm_chip *ingenic_pwm, unsigned int channel) ++{ ++ int tmp; ++ tmp = pwm_readl(ingenic_pwm,PWM_DTRIG); ++ tmp |= 1 << channel; ++ pwm_writel(ingenic_pwm,tmp,PWM_DTRIG); ++} ++ ++static unsigned int pwm_dma_fifo_empty(struct ingenic_pwm_chip *ingenic_pwm,unsigned int channel) ++{ ++ return pwm_readl(ingenic_pwm,PWM_DFER) & (1 << channel); ++} ++ ++static unsigned int pwm_dma_get_dfsm(struct ingenic_pwm_chip *ingenic_pwm, unsigned int channel) ++{ ++ int tmp; ++ tmp = pwm_readl(ingenic_pwm,PWM_DFSM); ++ tmp &= 1 << channel; ++ return tmp; ++} ++ ++static int pwm_dma_get_status(struct ingenic_pwm_chip *ingenic_pwm) ++{ ++ return pwm_readl(ingenic_pwm,PWM_DSR); ++} ++ ++static void pwm_dma_clear_status(struct ingenic_pwm_chip *ingenic_pwm, unsigned int channel) ++{ ++ int tmp; ++ tmp = pwm_readl(ingenic_pwm,PWM_DSCR); ++ tmp |= 1 << channel; ++ pwm_writel(ingenic_pwm,tmp,PWM_DSCR); ++} ++ ++static void pwm_dma_interrupt_mask(struct ingenic_pwm_chip *ingenic_pwm, unsigned int channel) ++{ ++ int tmp; ++ tmp = pwm_readl(ingenic_pwm,PWM_DINTC); ++ tmp |= 1 << channel; ++ pwm_writel(ingenic_pwm,tmp,PWM_DINTC); ++} ++ ++static void pwm_dma_interrupt_unmask(struct ingenic_pwm_chip *ingenic_pwm, unsigned int channel) ++{ ++ int tmp; ++ tmp = pwm_readl(ingenic_pwm,PWM_DINTC); ++ tmp &= ~(1 << channel); ++ pwm_writel(ingenic_pwm,tmp,PWM_DINTC); ++} ++ ++static void pwm_dma_set_mem_addr(struct ingenic_pwm_chip *ingenic_pwm, unsigned int channel, unsigned int mem_addr) ++{ ++ pwm_writel(ingenic_pwm,mem_addr,PWM_DMADDR + channel * 4); ++} ++ ++/*DMA transfer length must 4 word align*/ ++static void pwm_dma_set_trans_length(struct ingenic_pwm_chip *ingenic_pwm, unsigned int channel, int tran_len) ++{ ++ pwm_writel(ingenic_pwm,tran_len,PWM_DTLR + channel * 4); ++} ++ ++static void pwm_set_io_output_enable(struct ingenic_pwm_chip *ingenic_pwm, unsigned int channel, int enable) ++{ ++ int tmp; ++ tmp = pwm_readl(ingenic_pwm, PWM_OEN); ++ if(enable) ++ tmp |= 1 << channel; ++ else ++ tmp &= ~(1 << channel); ++ pwm_writel(ingenic_pwm, tmp, PWM_OEN); ++} ++ ++static void dump_pwm_reg(struct ingenic_pwm_chip *ingenic_pwm) ++{ ++ int i; ++ printk("PWM_CCFG0 addr %08x = %08x\n", ingenic_pwm->iomem + PWM_CCFG0,pwm_readl(ingenic_pwm, PWM_CCFG0)); ++ printk("PWM_CCFG1 addr %08x = %08x\n", ingenic_pwm->iomem + PWM_CCFG1,pwm_readl(ingenic_pwm, PWM_CCFG1)); ++ printk("PWM_ENS addr %08x = %08x\n", ingenic_pwm->iomem + PWM_ENS, pwm_readl(ingenic_pwm, PWM_ENS)); ++ printk("PWM_ENC addr %08x = %08x\n", ingenic_pwm->iomem + PWM_ENC,pwm_readl(ingenic_pwm, PWM_ENC)); ++ printk("PWM_EN addr %08x = %08x\n", ingenic_pwm->iomem + PWM_EN,pwm_readl(ingenic_pwm, PWM_EN)); ++ printk("PWM_UP addr %08x = %08x\n", ingenic_pwm->iomem + PWM_UP,pwm_readl(ingenic_pwm, PWM_UP)); ++ printk("PWM_LOOP addr %08x = %08x\n", ingenic_pwm->iomem + PWM_DCR1,pwm_readl(ingenic_pwm, PWM_DCR1)); ++ printk("PWM_MASK addr %08x = %08x\n", ingenic_pwm->iomem + PWM_DINTC,pwm_readl(ingenic_pwm, PWM_DINTC)); ++ printk("PWM_BUSY addr %08x = %08x\n", ingenic_pwm->iomem + PWM_BUSY,pwm_readl(ingenic_pwm, PWM_BUSY)); ++ printk("----------------------------------------------------------------------\n"); ++ for(i = 0; i < 16; i++) { ++ printk("PWM_DAR %d addr %08x = %08x\n", i,ingenic_pwm->iomem + i * 4, pwm_readl(ingenic_pwm, PWM_DMADDR + i * 4)); ++ } ++ printk("----------------------------------------------------------------------\n"); ++ for(i = 0; i < 16; i++) { ++ printk("PWM_WCFG%d addr %08x = %08x\n", i,ingenic_pwm->iomem + i * 4, pwm_readl(ingenic_pwm, PWM_WCFG + i * 4)); ++ } ++ printk("----------------------------------------------------------------------\n"); ++ for(i = 0; i < 16; i++) { ++ printk("PWM_DTLR%d addr %08x = %08x\n", i, ingenic_pwm->iomem + i * 4,pwm_readl(ingenic_pwm, PWM_DTLR + i * 4)); ++ } ++} ++ ++ ++static irqreturn_t ingenic_pwm_interrupt(int irq, void *dev_id) ++{ ++ int tmp; ++ struct ingenic_pwm_chip *ingenic_pwm = (struct ingenic_pwm_chip *)(dev_id); ++ tmp = pwm_dma_get_status(ingenic_pwm); ++ /*clear end flag*/ ++ pwm_writel(ingenic_pwm,tmp,PWM_DSCR); ++ ++ /*restart DMA transfer*/ ++ // pwm_writel(ingenic_pwm,tmp,PWM_DTRIG); ++ ++ return IRQ_HANDLED; ++} ++ ++ ++//--------------------------add end---------------------- ++ ++ ++static inline struct ingenic_pwm_chip *to_ingenic_chip(struct pwm_chip *chip) ++{ ++ return container_of(chip, struct ingenic_pwm_chip, chip); ++} ++ ++static int ingenic_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, ++ int duty_ns, int period_ns) ++{ ++ struct ingenic_pwm_chip *ingenic_pwm = to_ingenic_chip(chip); ++ int channel = pwm->hwpwm; ++ unsigned int period = 0; ++ unsigned int duty = 0; ++ unsigned short start = 0; ++ unsigned short end = 0; ++ unsigned int pwm_freq = 0; ++ unsigned int clk_in = 0; ++ unsigned int prescale = 0; ++ unsigned int tmp = 1; ++ int i = 0; ++ int update_flag = 1; ++ int mode = 0; ++ unsigned int dma_coherent; ++ dma_addr_t dma_coherent_handle; ++ unsigned long long clk_ns = 1000000000ULL; ++ ++ mutex_lock(&ingenic_pwm->mutex); ++ printk("duty_ns=%d period_ns=%d\n", duty_ns, period_ns); ++ ++ if (duty_ns < 0 || duty_ns > period_ns) { ++ pr_err("%s, duty_ns(%d)< 0 or duty_ns > period_ns(%d)\n", __func__, duty_ns, period_ns); ++ return -EINVAL; ++ } ++ ++ if(period_ns > NS_IN_HZ || duty_ns > NS_IN_HZ) ++ return -ERANGE; ++ ++ /*select mode */ ++ mode = ingenic_pwm->mode_sel[channel]; ++ ++ /*set prescale*/ ++ pwm_clk_config(ingenic_pwm, channel, PRESCALE); ++ clk_in = clk_get_rate(ingenic_pwm->clk_pwm); ++ prescale = pwm_get_prescale(ingenic_pwm, channel); ++ printk("prescale=%08x\n", prescale); ++ ++ for (i = 0; i < prescale; i++) { ++ tmp = 2 * tmp; ++ } ++ ++ pwm_freq = clk_in / tmp; ++ printk("pwm_freq=%d tmp=%d\n", pwm_freq, tmp); ++ do_div(clk_ns, pwm_freq); ++ printk("clk_ns=%lld\n", clk_ns); ++ ++ period = (period_ns / (unsigned int)clk_ns) - 1; ++ printk("period=%d\n", period); ++ // pwm_set_period_hw(ingenic_pwm, channel, period); ++ duty = duty_ns / (unsigned int)clk_ns; ++ ++ /*set init level*/ ++ if (ingenic_pwm->init_level == PWM_INIT_HIGH) ++ pwm_set_init_level(ingenic_pwm,channel,1); ++ else if (ingenic_pwm->init_level == PWM_INIT_LOW) ++ pwm_set_init_level(ingenic_pwm,channel,0); ++ else ++ pr_err("%s, pwm init level error\n", __func__); ++ ++ printk("duty=%d level_init=%d low=%d\n", duty, ingenic_pwm->init_level, period - duty); ++ ++ /*set waveform high_num and low_num*/ ++ if(COMMON_MODE == mode){ ++ //*****************************test**(duty**period)********** ++ pwm_waveform_high(ingenic_pwm, channel, duty_ns); ++ pwm_waveform_low(ingenic_pwm, channel, period_ns - duty_ns); ++ } ++ ++ /*Set the level state at the end of the waveform*/ ++ pwm_set_finish_level(ingenic_pwm,channel,0); ++ ++ /*pwm output enable*/ ++ pwm_set_io_output_enable(ingenic_pwm, channel, 1); ++ ++ /*Update bit according to mode setting*/ ++ pwm_set_update_mode(ingenic_pwm, channel, mode); ++ ++ /*Whether to update*/ ++ if(ingenic_pwm->chip.pwms[channel].flags & (1 << PWMF_ENABLED)) { ++ if(COMMON_MODE == mode){ ++ pwm_update(ingenic_pwm, channel); ++ while(pwm_busy(ingenic_pwm, channel)); ++ } ++ if(DMA_MODE == mode){ ++ update_flag = 0; ++ if(!pwm_dma_get_loop_status(ingenic_pwm, channel)){ ++ while(!pwm_dma_fifo_empty(ingenic_pwm, channel)); ++ if(pwm_dma_fifo_empty(ingenic_pwm, channel)) ++ update_flag = 1; ++ } ++ } ++ } ++ /*DMA mode related configuration*/ ++ if(DMA_MODE == mode && update_flag){ ++ ++ dma_coherent = dma_alloc_coherent(ingenic_pwm->chip.dev, sizeof(int) * TRANS_LEN, &dma_coherent_handle, GFP_KERNEL); ++ printk("--%s-------%d-dma_coherent = %x--dma_coherent_handle = %x---write value = %x----\n",__func__,__LINE__,dma_coherent,dma_coherent_handle,(0x1111ffff)); ++ dma_cache_wback_inv(dma_coherent,sizeof(int) * TRANS_LEN); ++ for(i = 0; i < TRANS_LEN; i++ ){ ++ printk("-----------befor-addr = %x--value ----%x --- \n",dma_coherent + i * 4,*(volatile unsigned int *)(dma_coherent + i * 4)); ++ *(volatile unsigned int *)(dma_coherent + i * 4) = (0x1111ffff + i * 5); ++ printk("-----------after-addr = %x--value ----%x --- \n",dma_coherent + i * 4,*(volatile unsigned int *)(dma_coherent + i * 4)); ++ } ++ ingenic_pwm->vir_addr[channel] = dma_coherent; ++ ingenic_pwm->phy_addr[channel] = dma_coherent_handle; ++ ++ /*set addr and trans_len*/ ++ pwm_dma_set_mem_addr(ingenic_pwm, channel, dma_coherent_handle); ++ pwm_dma_set_trans_length(ingenic_pwm, channel, TRANS_LEN); ++ ++ /*set interrupt */ ++ pwm_dma_clear_loop(ingenic_pwm, channel); ++ pwm_dma_interrupt_unmask(ingenic_pwm, channel); ++ } ++ mutex_unlock(&ingenic_pwm->mutex); ++ return 0; ++} ++ ++ ++static int ingenic_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) ++{ ++ struct ingenic_pwm_chip *ingenic_pwm = to_ingenic_chip(chip); ++ int channel = pwm->hwpwm; ++ int count = 0; ++ mutex_lock(&ingenic_pwm->mutex); ++ ++ if(ingenic_pwm->mode_sel[channel] == DMA_MODE){ ++ /*enable DMA mode*/ ++ while(pwm_dma_get_dfsm(ingenic_pwm,channel)){ ++ count ++; ++ if(count == 0x10000000){ ++ printk("pwm %d channel is working\n",channel); ++ return 0; ++ } ++ } ++ pwm_dma_enable_hw(ingenic_pwm, channel); ++ pwm_dma_trans_trigger(ingenic_pwm, channel); ++ } ++ pwm_enable_hw(ingenic_pwm, channel); ++ mutex_unlock(&ingenic_pwm->mutex); ++ ++ return 0; ++} ++ ++static void ingenic_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) ++{ ++ struct ingenic_pwm_chip *ingenic_pwm = to_ingenic_chip(chip); ++ int channel = pwm->hwpwm; ++ ++ mutex_lock(&ingenic_pwm->mutex); ++ if(ingenic_pwm->mode_sel[channel] == DMA_MODE){ ++ pwm_dma_disable_hw(ingenic_pwm,channel); ++ dma_free_coherent(ingenic_pwm->chip.dev,sizeof(int) * TRANS_LEN, ingenic_pwm->vir_addr[channel], ingenic_pwm->phy_addr[channel]); ++ } ++ ++ pwm_disable_hw(ingenic_pwm, channel); ++ mutex_unlock(&ingenic_pwm->mutex); ++} ++ ++ ++ ++static const struct pwm_ops ingenic_pwm_ops = { ++ .config = ingenic_pwm_config, ++ .enable = ingenic_pwm_enable, ++ .disable = ingenic_pwm_disable, ++ .owner = THIS_MODULE, ++}; ++ ++ ++static ssize_t pwm_show_enable(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct ingenic_pwm_chip *ingenic_pwm = dev_get_drvdata(dev); ++ return sprintf(buf, "%x", pwm_enable_status(ingenic_pwm)); ++} ++ ++static ssize_t pwm_store_enable(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct ingenic_pwm_chip *ingenic_pwm = dev_get_drvdata(dev); ++ int enable; ++ const char *str = buf; ++ int ret_count = 0; ++ ++ while (!isxdigit(*str)) { ++ str++; ++ if(++ret_count >= count) ++ return count; ++ } ++ enable = simple_strtoul(str, (char **)&str, 10); ++ ++ printk("input enable value %d,current_id %d\n",enable,ingenic_pwm->debug_current_id); ++ if (enable == 1) { ++ pwm_enable(ingenic_pwm->debug_pwm[ingenic_pwm->debug_current_id]); ++ } else if (enable == 0) { ++ pwm_disable(ingenic_pwm->debug_pwm[ingenic_pwm->debug_current_id]); ++ } else { ++ printk("enable or disable error!\n"); ++ } ++ return count; ++} ++ ++ ++static ssize_t pwm_show_config(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct ingenic_pwm_chip *ingenic_pwm = dev_get_drvdata(dev); ++ dump_pwm_reg(ingenic_pwm); ++ printk("\n"); ++ return 0; ++} ++ ++static ssize_t pwm_store_config(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct ingenic_pwm_chip *ingenic_pwm = dev_get_drvdata(dev); ++ const char *str = buf; ++ unsigned int period_ns, duty_ns; ++ int mode = 0; ++ int ret_count = 0; ++ ++ while (!isxdigit(*str)) { ++ str++; ++ if(++ret_count >= count) ++ return count; ++ } ++ mode = simple_strtoul(str, (char **)&str, 10); ++ if(DMA_MODE == mode) ++ ingenic_pwm->mode_sel[ingenic_pwm->debug_current_id] = DMA_MODE; ++ ++ while (!isxdigit(*str)) { ++ str++; ++ if(++ret_count >= count) ++ return count; ++ } ++ duty_ns = simple_strtoul(str, (char **)&str, 10); ++ ++ while (!isxdigit(*str)) { ++ str++; ++ if(++ret_count >= count) ++ return count; ++ } ++ period_ns = simple_strtoul(str, (char **)&str, 10); ++ ++ printk("debug_current_id = %d \n", ingenic_pwm->debug_current_id); ++ printk("period_ns = %d , duty_ns = %d mode = %s\n", period_ns,duty_ns,mode? "DMA_MODE":"COMMON_MODE"); ++ pwm_config(ingenic_pwm->debug_pwm[ingenic_pwm->debug_current_id], duty_ns, period_ns); ++ printk("pwm_config finish\n"); ++ ++ printk("\n"); ++ return count; ++} ++ ++static ssize_t pwm_show_channel(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct ingenic_pwm_chip *ingenic_pwm = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "channel = %x", ingenic_pwm->debug_current_id); ++ ++} ++ ++static ssize_t pwm_store_channel(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct ingenic_pwm_chip *ingenic_pwm = dev_get_drvdata(dev); ++ const char *str = buf; ++ int ret_count = 0; ++ int pwm_id = 0; ++ struct pwm_device *pwm = NULL; ++ ++ while (!isxdigit(*str)) { ++ str++; ++ if(++ret_count >= count) ++ return count; ++ } ++ pwm_id = simple_strtoul(str, (char **)&str, 10); ++ pwm = pwm_request(pwm_id, "pwm_request_test"); ++ if (IS_ERR(pwm)) { ++ printk("unable to request pwm\n"); ++ return -1; ++ } ++ ingenic_pwm->debug_pwm[pwm_id] = pwm; ++ ingenic_pwm->debug_current_id = pwm_id; ++ printk("channel = %d\n", ingenic_pwm->debug_current_id); ++ printk("\n"); ++ return count; ++} ++ ++static ssize_t pwm_store_free(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct ingenic_pwm_chip *ingenic_pwm = dev_get_drvdata(dev); ++ const char *str = buf; ++ int ret_count = 0; ++ int pwm_id = 0; ++ ++ while (!isxdigit(*str)) { ++ str++; ++ if(++ret_count >= count) ++ return count; ++ } ++ pwm_id = simple_strtoul(str, (char **)&str, 10); ++ ++ pwm_put(ingenic_pwm->debug_pwm[pwm_id]); ++ ingenic_pwm->debug_pwm[pwm_id] = NULL; ++ return count; ++} ++ ++static ssize_t pwm_show_requested_channel(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct ingenic_pwm_chip *ingenic_pwm = dev_get_drvdata(dev); ++ int i = 0; ++ int ret = 0; ++ ++ for (i = 0; i debug_pwm[i] == &(ingenic_pwm->chip.pwms[i])) ++ ret += sprintf(buf + ret, "ch: %d requested\n", i); ++ else ++ ret += sprintf(buf + ret, "ch: %d unrequested\n", i); ++ } ++ return ret; ++} ++ ++static struct device_attribute pwm_device_attributes[] = { ++ __ATTR(enable, S_IRUGO|S_IWUSR, pwm_show_enable, pwm_store_enable), ++ __ATTR(config, S_IRUGO|S_IWUSR, pwm_show_config, pwm_store_config), ++ __ATTR(request, S_IRUGO|S_IWUSR, pwm_show_channel, pwm_store_channel), ++ __ATTR(free, S_IWUSR, NULL, pwm_store_free), ++ __ATTR(channels, S_IRUGO, pwm_show_requested_channel, NULL), ++}; ++ ++static int ingenic_pwm_probe(struct platform_device *pdev) ++{ ++ struct ingenic_pwm_chip *chip; ++ struct resource *res; ++ int err = 0; ++ int ret = 0; ++ int i = 0; ++ ++ chip = devm_kzalloc(&pdev->dev, ++ sizeof(struct ingenic_pwm_chip), GFP_KERNEL); ++ if (!chip) { ++ pr_err("%s %d,malloc ingenic_pwm_chip error\n", ++ __func__, __LINE__); ++ return -ENOMEM; ++ } ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (res == NULL) { ++ dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n"); ++ return -ENOENT; ++ } ++ ++ chip->irq = platform_get_irq(pdev, 0); ++ if(chip->irq < 0){ ++ dev_err(&pdev->dev, "Cannot get %d IORESOURCE_IRQ\n",chip->irq); ++ return -ENOENT; ++ } ++ ++ chip->iomem = ioremap(res->start, (res->end - res->start) + 1); ++ if (chip->iomem == NULL) { ++ dev_err(&pdev->dev, "Cannot map IO\n"); ++ err = -ENXIO; ++ goto err_no_iomap; ++ } ++ ++ chip->clk_gate = devm_clk_get(&pdev->dev, "gate_pwm"); ++ if (IS_ERR(chip->clk_gate)) { ++ dev_err(&pdev->dev, "get pwm clk gate failed %ld\n", PTR_ERR(chip->clk_gate)); ++ return PTR_ERR(chip->clk_gate); ++ } ++ ++ chip->clk_pwm = devm_clk_get(&pdev->dev, "cgu_pwm"); ++ if(IS_ERR(chip->clk_pwm)){ ++ dev_err(&pdev->dev, "get pwm clk failed %ld\n", PTR_ERR(chip->clk_pwm)); ++ return PTR_ERR(chip->clk_pwm); ++ } ++ ++ if(chip->clk_gate) { ++ ret = clk_prepare_enable(chip->clk_gate); ++ if(ret) { ++ dev_err(&pdev->dev, "enable pwm clock gate failed!\n"); ++ } ++ } ++ ++ if(chip->clk_pwm) { ++ ret = clk_set_rate(chip->clk_pwm, DEFAULT_PWM_CLK_RATE); ++ if(ret) { ++ dev_err(&pdev->dev, "set pwm clock rate failed!\n"); ++ } ++ ret = clk_prepare_enable(chip->clk_pwm); ++ if(ret) { ++ dev_err(&pdev->dev, "enable pwm clock failed!\n"); ++ } ++ } ++ ++ chip->chip.dev = &pdev->dev; ++ chip->chip.ops = &ingenic_pwm_ops; ++ chip->chip.base = 0; ++ chip->chip.npwm = INGENIC_PWM_NUM; ++ chip->init_level = PWM_INIT_HIGH; ++ ++ ret = pwmchip_add(&chip->chip); ++ if (ret < 0) { ++ devm_kfree(&pdev->dev, chip); ++ return ret; ++ } ++ ++ ret = request_irq(chip->irq,ingenic_pwm_interrupt, ++ IRQF_SHARED | IRQF_TRIGGER_LOW,"ingenic-interrupt",chip); ++ if (ret) { ++ dev_err(&pdev->dev, "request_irq failed !! %d-\n",chip->irq); ++ goto err_no_iomap; ++ } ++ ++ platform_set_drvdata(pdev, chip); ++ mutex_init(&chip->mutex); ++ ++ for (i = 0; i < ARRAY_SIZE(pwm_device_attributes); i++) { ++ ret = device_create_file(&pdev->dev, &pwm_device_attributes[i]); ++ if (ret) ++ dev_warn(&pdev->dev, "attribute %d create failed", i); ++ } ++ ++ dev_info(&pdev->dev, "ingenic-x2000 Probe of pwm success!\n"); ++ return 0; ++ ++err_no_iomap: ++ iounmap(chip->iomem); ++ ++ return err; ++} ++ ++static int ingenic_pwm_remove(struct platform_device *pdev) ++{ ++ struct ingenic_pwm_chip *chip; ++ chip =platform_get_drvdata(pdev); ++ if (!chip) ++ return -ENODEV; ++ ++ free_irq(chip->irq,chip); ++ pwmchip_remove(&chip->chip); ++ devm_clk_put(&pdev->dev,chip->clk_pwm); ++ devm_clk_put(&pdev->dev,chip->clk_gate); ++ devm_kfree(&pdev->dev, chip); ++ return 0; ++} ++ ++static const struct of_device_id ingenic_pwm_matches[] = { ++ { .compatible = "ingenic,x2000-pwm", .data = NULL }, ++ {}, ++}; ++ ++#ifdef CONFIG_PM_SLEEP ++static int ingenic_pwm_suspend(struct device *dev) ++{ ++ struct ingenic_pwm_chip *chip = dev_get_drvdata(dev); ++ unsigned int i; ++ ++ /* ++ * No one preserves these values during suspend so reset them. ++ * Otherwise driver leaves PWM unconfigured if same values are ++ * passed to pwm_config() next time. ++ */ ++ for (i = 0; i < INGENIC_PWM_NUM; ++i) { ++ struct pwm_device *pwm = &chip->chip.pwms[i]; ++ struct ingenic_pwm_channel *chan = pwm_get_chip_data(pwm); ++ ++ if (!chan) ++ continue; ++ chan->period_ns = 0; ++ chan->duty_ns = 0; ++ } ++ ++ return 0; ++} ++ ++static int ingenic_pwm_resume(struct device *dev) ++{ ++ struct ingenic_pwm_chip *chip = dev_get_drvdata(dev); ++ unsigned int chan; ++ ++ /* ++ * Inverter setting must be preserved across suspend/resume ++ * as nobody really seems to configure it more than once. ++ */ ++ for (chan = 0; chan < INGENIC_PWM_NUM; ++chan) { ++ if (chip->output_mask & BIT(chan)) { ++ /*TODO: ??*/ ++ } ++ } ++ return 0; ++} ++#endif ++ ++static SIMPLE_DEV_PM_OPS(ingenic_pwm_pm_ops, ingenic_pwm_suspend, ingenic_pwm_resume); ++ ++static struct platform_driver ingenic_pwm_driver = { ++ .driver = { ++ .name = "ingenic-pwm", ++ .pm = &ingenic_pwm_pm_ops, ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(ingenic_pwm_matches), ++ }, ++ .probe = ingenic_pwm_probe, ++ .remove = ingenic_pwm_remove, ++}; ++module_platform_driver(ingenic_pwm_driver); ++ ++MODULE_DESCRIPTION("Ingenic SoC PWM driver"); ++MODULE_ALIAS("platform:ingenic-pwm"); ++MODULE_LICENSE("GPL"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_pwm_pwm-ingenic.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_pwm_pwm-ingenic.c.patch new file mode 100644 index 00000000..aee78d3b --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_pwm_pwm-ingenic.c.patch @@ -0,0 +1,491 @@ +diff -drupN a/drivers/pwm/pwm-ingenic.c b/drivers/pwm/pwm-ingenic.c +--- a/drivers/pwm/pwm-ingenic.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/pwm/pwm-ingenic.c 2022-06-09 05:02:33.000000000 +0300 +@@ -0,0 +1,487 @@ ++/* ++ * Copyright (c) 2007 Ben Dooks ++ * Copyright (c) 2008 Simtec Electronics ++ * Ben Dooks , ++ * Copyright (c) 2013 Tomasz Figa ++ * ++ * PWM driver for Samsung SoCs ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++/** ++ * struct ingenic_pwm_channel - private data of PWM channel ++ * @period_ns: current period in nanoseconds programmed to the hardware ++ * @duty_ns: current duty time in nanoseconds programmed to the hardware ++ */ ++struct ingenic_pwm_channel { ++ struct ingenic_tcu_chn *chan; ++ u32 period_ns; ++ u32 duty_ns; ++}; ++ ++/** ++ * struct ingenic_pwm_chip - private data of PWM chip ++ * @chip: generic PWM chip ++ * @rtc_clk: external RTC clock(can be ERR_PTR if not present) ++ * @ext_clk: external EXT clock(can be ERR_PTR if not present) ++ * @output_mask: output status for all channels - one bit per channel ++ */ ++struct ingenic_pwm_chip { ++ struct pwm_chip chip; ++ struct clk *rtc_clk; ++ struct clk *ext_clk; ++ u32 output_mask; ++}; ++ ++static inline ++struct ingenic_pwm_chip *to_ingenic_pwm_chip(struct pwm_chip *chip) ++{ ++ return container_of(chip, struct ingenic_pwm_chip, chip); ++} ++static inline ++struct ingenic_tcu_chn *to_ingenic_tcu_channel(struct pwm_device *pwm) ++{ ++ return ((struct ingenic_pwm_channel *)pwm_get_chip_data(pwm))->chan; ++} ++ ++static int pwm_get_period_num(struct ingenic_pwm_chip *chip, ++ struct ingenic_tcu_chn *tcu_chan, int period_ns) ++{ ++ unsigned long long rate; ++ unsigned long long tmp; ++ int div = 0; ++ int period = 0; ++ ++ if(tcu_chan->clk_src == TCU_CLKSRC_EXT) { ++ rate = (unsigned long long)clk_get_rate(chip->ext_clk); ++ } else if(tcu_chan->clk_src == TCU_CLKSRC_RTC) { ++ rate = (unsigned long long)clk_get_rate(chip->ext_clk); ++ } else { ++ printk("not support clk soruce\n"); ++ return -EINVAL; ++ } ++ ++ tmp = rate * period_ns; ++ do_div(tmp, 1000000000); ++ period = tmp; ++ ++ while (period > 0xffff && div < 6) { ++ period >>= 2; ++ ++div; ++ } ++ ++ if (div == 6) ++ return -EINVAL; ++ ++ tcu_chan->full_num = period; ++ tcu_chan->clk_div = div; ++ return period; ++} ++static int pwm_ingenic_get_period(struct ingenic_pwm_chip *chip, ++ struct pwm_device *pwm, int period_ns) ++{ ++ struct ingenic_tcu_chn *tcu_chan; ++ int period; ++ ++ tcu_chan = to_ingenic_tcu_channel(pwm); ++ /* ++ * Compare minimum PWM frequency that can be achieved with possible ++ * divider settings and choose the lowest divisor that can generate ++ * frequencies lower than requested. ++ */ ++ tcu_chan->clk_src = TCU_CLKSRC_EXT; ++ period = pwm_get_period_num(chip, tcu_chan, period_ns); ++ if(period < 0) { ++ tcu_chan->clk_src = TCU_CLKSRC_RTC; ++ period = pwm_get_period_num(chip, tcu_chan, period_ns); ++ if(period < 0) { ++ dev_err(chip->chip.dev,"can not find right div\n"); ++ } ++ } ++ ++ return period; ++} ++ ++static int pwm_ingenic_request(struct pwm_chip *chip, struct pwm_device *pwm) ++{ ++ struct ingenic_pwm_chip *our_chip = to_ingenic_pwm_chip(chip); ++ struct ingenic_pwm_channel *our_chan; ++ struct mfd_cell *cell; ++ ++ if (!(our_chip->output_mask & BIT(pwm->hwpwm))) { ++ dev_warn(chip->dev, ++ "tried to request PWM channel %d without output\n", ++ pwm->hwpwm); ++ return -EINVAL; ++ } ++ ++ cell = request_cell(pwm->hwpwm); ++ if(!cell){ ++ dev_err(chip->dev, "tried to request tcu channel %d busy\n", ++ pwm->hwpwm); ++ return -EINVAL; ++ } ++ ++ our_chan = devm_kzalloc(chip->dev, sizeof(*our_chan), GFP_KERNEL); ++ if (!our_chan) ++ return -ENOMEM; ++ ++ our_chan->chan = cell->platform_data; ++ our_chan->chan->enable(cell->id); ++ ++ pwm_set_chip_data(pwm, our_chan); ++ ++ return 0; ++} ++ ++static void pwm_ingenic_free(struct pwm_chip *chip, struct pwm_device *pwm) ++{ ++ struct ingenic_pwm_channel *our_chan; ++ int id; ++ ++ our_chan = pwm_get_chip_data(pwm); ++ ++ id = pwm->hwpwm; ++ our_chan->chan->disable(id); ++ free_cell(id); ++ devm_kfree(chip->dev, our_chan); ++ pwm_set_chip_data(pwm, NULL); ++} ++ ++static int pwm_ingenic_enable(struct pwm_chip *chip, struct pwm_device *pwm) ++{ ++ struct ingenic_tcu_chn *tcu_chan; ++ tcu_chan = to_ingenic_tcu_channel(pwm); ++ ingenic_tcu_counter_begin(tcu_chan); ++ ++ return 0; ++} ++ ++static void pwm_ingenic_disable(struct pwm_chip *chip, struct pwm_device *pwm) ++{ ++ struct ingenic_tcu_chn *tcu_chan; ++ tcu_chan = to_ingenic_tcu_channel(pwm); ++ ingenic_tcu_counter_stop(tcu_chan); ++} ++ ++static int pwm_ingenic_config(struct pwm_chip *chip, struct pwm_device *pwm, ++ int duty_ns, int period_ns) ++{ ++ struct ingenic_pwm_chip *our_chip = to_ingenic_pwm_chip(chip); ++ struct ingenic_pwm_channel *our_chan = pwm_get_chip_data(pwm); ++ struct ingenic_tcu_chn *tcu_chan = our_chan->chan; ++ u16 tfull = tcu_chan->full_num, thalf; ++ ++ /* ++ * We currently avoid using 64bit arithmetic by using the ++ * fact that anything faster than 1Hz is easily representable ++ * by 32bits. ++ */ ++ if (period_ns > NSEC_PER_SEC) ++ return -ERANGE; ++ ++ if (period_ns == our_chan->period_ns && duty_ns == our_chan->duty_ns) ++ return 0; ++ ++ /* Check to see if we are changing the clock rate of the PWM. */ ++ if (our_chan->period_ns != period_ns) { ++ int period; ++ ++ period = pwm_ingenic_get_period(our_chip, pwm, period_ns); ++ dev_dbg(our_chip->chip.dev, "duty_ns=%d, period_ns=%d (%u)\n", ++ duty_ns, period_ns, period); ++ if(period < 0) ++ return -ERANGE; ++ tfull = period; ++ } ++ /* Period is too short. */ ++ if (tfull <= 1) ++ return -ERANGE; ++ ++ /* Note that counters count down. */ ++ { ++ unsigned long long tmp; ++ tmp = (unsigned long long)tfull * duty_ns; ++ do_div(tmp, period_ns); ++ thalf = tmp; ++ } ++ ++ /* 0% duty is not available */ ++ if (!thalf) ++ ++thalf; ++ ++ thalf = tfull - thalf; ++ if(!thalf){ ++ /* set pwm output 1 */ ++ } ++ ++ dev_info(our_chip->chip.dev, ++ "thalf=%u/%u\n", thalf, tfull); ++ ++ tcu_chan->irq_type = NULL_IRQ_MODE; ++ tcu_chan->is_pwm = 1; ++ tcu_chan->full_num = tfull; ++ tcu_chan->half_num = thalf; ++ tcu_chan->shutdown_mode = 0; ++ ++ ingenic_tcu_config(tcu_chan); ++ ++ our_chan->period_ns = period_ns; ++ our_chan->duty_ns = duty_ns; ++ ++ return 0; ++} ++ ++static int pwm_ingenic_set_polarity(struct pwm_chip *chip, ++ struct pwm_device *pwm, ++ enum pwm_polarity polarity) ++{ ++ struct ingenic_tcu_chn *tcu_chan; ++ bool invert = (polarity == PWM_POLARITY_NORMAL); ++ ++ tcu_chan = to_ingenic_tcu_channel(pwm); ++ if (invert) { ++ tcu_chan->init_level = 1; ++ } else { ++ tcu_chan->init_level = 0; ++ } ++ ++ return 0; ++} ++ ++static const struct pwm_ops pwm_ingenic_ops = { ++ .request = pwm_ingenic_request, ++ .free = pwm_ingenic_free, ++ .enable = pwm_ingenic_enable, ++ .disable = pwm_ingenic_disable, ++ .config = pwm_ingenic_config, ++ .set_polarity = pwm_ingenic_set_polarity, ++ .owner = THIS_MODULE, ++}; ++ ++#ifdef CONFIG_OF ++/** ++ * of_irq_find_parent - Given a device node, find its interrupt parent node ++ * @child: pointer to device node ++ * ++ * Returns a pointer to the interrupt parent node, or NULL if the interrupt ++ * parent could not be determined. ++ */ ++struct device_node *of_pwm_find_parent(struct device_node *child) ++{ ++ struct device_node *p; ++ const __be32 *parp; ++ ++ if (!of_node_get(child)) ++ return NULL; ++ ++ do { ++ parp = of_get_property(child, "ingenic,timer-parent", NULL); ++ if (parp == NULL) ++ p = of_get_parent(child); ++ else { ++ p = of_find_node_by_phandle(be32_to_cpup(parp)); ++ } ++ of_node_put(child); ++ } while (!p); ++ ++ return p; ++} ++ ++static void pwm_ingenic_parse_dt(struct ingenic_pwm_chip *chip) ++{ ++ struct device_node *np = chip->chip.dev->of_node; ++ struct device_node *child, *parent; ++ int enable_pwm_num = 0; ++ ++ for_each_child_of_node(np, child) { ++ const char *status; ++ parent = of_pwm_find_parent(child); ++ of_property_read_string(child, "status", &status); ++ ++ if(!strcmp(status, "okay") ){ ++ unsigned int info, id; ++ of_property_read_u32(parent, "ingenic,channel-info", &info); ++ id = info & (CHANNEL_BASE_OFF*2 - 1); ++ chip->output_mask |= BIT(id); ++ enable_pwm_num ++; ++ } ++ } ++ chip->chip.of_pwm_n_cells = enable_pwm_num; ++} ++static const struct of_device_id ingenic_pwm_matches[] = { ++ { .compatible = "ingenic,pwm", .data = NULL }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ingenic_pwm_matches); ++#else ++static int pwm_ingenic_parse_dt(struct ingenic_pwm_chip *chip) ++{ ++ return -ENODEV; ++} ++#endif ++ ++static int pwm_ingenic_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct ingenic_pwm_chip *chip; ++ struct device_node *np; ++ unsigned int pwmnum; ++ int ret = 0; ++ ++ chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); ++ if (chip == NULL) ++ return -ENOMEM; ++ ++ np = pdev->dev.of_node; ++ pwmnum = of_get_child_count(np); ++ chip->chip.dev = &pdev->dev; ++ chip->chip.dev->of_node = np; ++ chip->chip.ops = &pwm_ingenic_ops; ++ chip->chip.base = -1; ++ chip->chip.npwm = pwmnum; ++ ++ if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) { ++ pwm_ingenic_parse_dt(chip); ++ /* chip->chip.of_xlate = of_pwm_xlate_with_flags; */ ++ } else { ++ if (!pdev->dev.platform_data) { ++ dev_err(&pdev->dev, "no platform data specified\n"); ++ return -EINVAL; ++ } ++ } ++ ++ chip->ext_clk = devm_clk_get(&pdev->dev, "ext"); ++ chip->rtc_clk = devm_clk_get(&pdev->dev, "rtc"); ++ if (IS_ERR(chip->ext_clk) || IS_ERR(chip->rtc_clk)) { ++ dev_err(dev, "failed to get timer base clk\n"); ++ return -EINVAL; ++ } ++ ++ platform_set_drvdata(pdev, chip); ++ ++ ret = pwmchip_add(&chip->chip); ++ if (ret < 0) { ++ dev_err(dev, "failed to register PWM chip\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int pwm_ingenic_remove(struct platform_device *pdev) ++{ ++ struct ingenic_pwm_chip *chip = platform_get_drvdata(pdev); ++ int ret; ++ ++ ret = pwmchip_remove(&chip->chip); ++ if (ret < 0) ++ return ret; ++ ++ clk_disable_unprepare(chip->ext_clk); ++ clk_disable_unprepare(chip->rtc_clk); ++ ++ return 0; ++} ++ ++ ++#ifdef CONFIG_PM_SLEEP ++static int pwm_ingenic_suspend(struct device *dev) ++{ ++ struct ingenic_pwm_chip *chip = dev_get_drvdata(dev); ++ unsigned int i; ++ ++ /* ++ * No one preserves these values during suspend so reset them. ++ * Otherwise driver leaves PWM unconfigured if same values are ++ * passed to pwm_config() next time. ++ */ ++ for (i = 0; i < chip->chip.npwm; ++i) { ++ struct pwm_device *pwm = &chip->chip.pwms[i]; ++ struct ingenic_pwm_channel *chan = pwm_get_chip_data(pwm); ++ int id; ++ if (!chan) ++ continue; ++ ++ id = pwm->hwpwm; ++ chan->chan->disable(id); ++ } ++ ++ return 0; ++} ++ ++static int pwm_ingenic_resume(struct device *dev) ++{ ++ struct ingenic_pwm_chip *chip = dev_get_drvdata(dev); ++ unsigned int chan; ++ ++ /* ++ * Inverter setting must be preserved across suspend/resume ++ * as nobody really seems to configure it more than once. ++ */ ++ for (chan = 0; chan < chip->chip.npwm; ++chan) { ++ if (chip->output_mask & BIT(chan)) { ++ struct pwm_device *pwm = &chip->chip.pwms[chan]; ++ struct ingenic_pwm_channel *chan = pwm_get_chip_data(pwm); ++ int id; ++ if (!chan) ++ continue; ++ ++ id = pwm->hwpwm; ++ chan->chan->enable(id); ++ } ++ } ++ ++ return 0; ++} ++#endif ++ ++static SIMPLE_DEV_PM_OPS(pwm_ingenic_pm_ops, pwm_ingenic_suspend, ++ pwm_ingenic_resume); ++ ++static struct platform_driver pwm_ingenic_driver = { ++ .driver = { ++ .name = "ingenic,pwm", ++ .pm = &pwm_ingenic_pm_ops, ++ .of_match_table = of_match_ptr(ingenic_pwm_matches), ++ }, ++ .probe = pwm_ingenic_probe, ++ .remove = pwm_ingenic_remove, ++}; ++ ++static int __init ingenic_pwm_init(void) ++{ ++ return platform_driver_register(&pwm_ingenic_driver); ++} ++ ++static void __exit ingenic_pwm_exit(void) ++{ ++ platform_driver_unregister(&pwm_ingenic_driver); ++} ++ ++device_initcall_sync(ingenic_pwm_init); ++module_exit(ingenic_pwm_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("bo.liu "); ++MODULE_ALIAS("platform:ingenic-pwm"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_regulator_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_regulator_Kconfig.patch new file mode 100644 index 00000000..46d17e7d --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_regulator_Kconfig.patch @@ -0,0 +1,20 @@ +diff -drupN a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig +--- a/drivers/regulator/Kconfig 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/regulator/Kconfig 2022-06-09 05:02:33.000000000 +0300 +@@ -557,6 +557,16 @@ config REGULATOR_RC5T583 + through regulator interface. The device supports multiple DCDC/LDO + outputs which can be controlled by i2c communication. + ++config REGULATOR_RN5T567 ++ tristate "RICOH RN5T567 Power regulators" ++ depends on MFD_RN5T567 ++ help ++ Select this option to enable the power regulator of RICOH ++ PMIC RN5T567. ++ This driver supports the control of different power rails of device ++ through regulator interface. The device supports multiple DCDC/LDO ++ outputs which can be controlled by i2c communication. ++ + config REGULATOR_RK808 + tristate "Rockchip RK808 Power regulators" + depends on MFD_RK808 diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_regulator_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_regulator_Makefile.patch new file mode 100644 index 00000000..56534efb --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_regulator_Makefile.patch @@ -0,0 +1,11 @@ +diff -drupN a/drivers/regulator/Makefile b/drivers/regulator/Makefile +--- a/drivers/regulator/Makefile 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/regulator/Makefile 2022-06-09 05:02:33.000000000 +0300 +@@ -72,6 +72,7 @@ obj-$(CONFIG_REGULATOR_PBIAS) += pbias-r + obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o + obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o + obj-$(CONFIG_REGULATOR_RC5T583) += rc5t583-regulator.o ++obj-$(CONFIG_REGULATOR_RN5T567) += rn5t567-regulator.o + obj-$(CONFIG_REGULATOR_RK808) += rk808-regulator.o + obj-$(CONFIG_REGULATOR_RN5T618) += rn5t618-regulator.o + obj-$(CONFIG_REGULATOR_RT5033) += rt5033-regulator.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_regulator_rn5t567-regulator.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_regulator_rn5t567-regulator.c.patch new file mode 100644 index 00000000..8abb599f --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_regulator_rn5t567-regulator.c.patch @@ -0,0 +1,232 @@ +diff -drupN a/drivers/regulator/rn5t567-regulator.c b/drivers/regulator/rn5t567-regulator.c +--- a/drivers/regulator/rn5t567-regulator.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/regulator/rn5t567-regulator.c 2022-06-09 05:02:33.000000000 +0300 +@@ -0,0 +1,228 @@ ++/* ++ * ++ * Regulator driver for RICOH RN5T567 power management chip. ++ * ++ * Copyright (C) 2016 Ingenic Semiconductor Co., Ltd. ++ * cli ++ * ++ * Based on code ++ * ricoh619-regulator.c ++ * Copyright (C) 2011 NVIDIA Corporation ++ * rn5t618-regulator.c ++ * Copyright (C) 2014 Beniamino Galvani ++ * ++ * 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, see . ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static const struct regulator_ops rn5t567_regulator_ops = { ++ .enable = regulator_enable_regmap, ++ .disable = regulator_disable_regmap, ++ .is_enabled = regulator_is_enabled_regmap, ++ .set_voltage_sel = regulator_set_voltage_sel_regmap, ++ .get_voltage_sel = regulator_get_voltage_sel_regmap, ++ .list_voltage = regulator_list_voltage_linear, ++ .set_voltage_time_sel = regulator_set_voltage_time_sel, ++}; ++ ++static int of_parse_rn5t567_cb(struct device_node *nd, ++ const struct regulator_desc * desc, ++ struct regulator_config *config) { ++ uint32_t pval; ++ int sel, ret = 0, us; ++ int svsel_reg[RN5T567_REGLATOR_NUM] = { ++ [RN5T567_DCDC1] = RN5T567_DC1DAC_SLP, ++ [RN5T567_DCDC2] = RN5T567_DC2DAC_SLP, ++ [RN5T567_DCDC3] = RN5T567_DC3DAC_SLP, ++ [RN5T567_DCDC4] = RN5T567_DC4DAC_SLP, ++ [RN5T567_LDO1] = RN5T567_LDO1DAC_SLP, ++ [RN5T567_LDO2] = RN5T567_LDO2DAC_SLP, ++ [RN5T567_LDO3] = RN5T567_LDO3DAC_SLP, ++ [RN5T567_LDO4] = RN5T567_LDO4DAC_SLP, ++ [RN5T567_LDO5] = RN5T567_LDO5DAC_SLP, ++ [RN5T567_LDORTC1] = -1, ++// [RN5T567_LDORTC2] = -1, ++ }; ++ ++ ++ if (!of_property_read_u32(nd, "init_uV" , &pval)) { ++ sel = (pval - desc->min_uV) / desc->uV_step; ++ if (desc->id < RN5T567_LDO1) ++ sel <<= ffs(desc->vsel_mask) - 1; ++ else ++ sel <<= ffs(desc->vsel_mask) - 1; ++ ret = regmap_update_bits(config->regmap, desc->vsel_reg, ++ desc->vsel_mask, sel); ++ if (ret) ++ goto out; ++ us = (sel - 1) * desc->uV_step / desc->ramp_delay; ++ udelay(us); ++ } ++ ++ if (!of_property_read_u32(nd, "sleep_uV", &pval) && svsel_reg[desc->id] != -1) { ++ sel = (pval - desc->min_uV) / desc->uV_step; ++ sel <<= ffs(desc->vsel_mask) - 1; ++ ret = regmap_update_bits(config->regmap, svsel_reg[desc->id], ++ desc->vsel_mask, sel); ++ if (ret) ++ goto out; ++ } ++ ++out: ++ return ret; ++} ++ ++#define REGULATOR_NODE_NAME "regulators" ++#define DESC(_rid, _ereg, _emsk, _min_uv, _max_uv, _uV_step, _vsreg, _vsmsk, _ramp_delay, _enable_time) \ ++ [RN5T567_##_rid] = { \ ++ .name = #_rid, \ ++ .of_match = of_match_ptr(#_rid), \ ++ .regulators_node = of_match_ptr(REGULATOR_NODE_NAME), \ ++ .of_parse_cb = of_parse_rn5t567_cb, \ ++ .id = RN5T567_##_rid, \ ++ .n_voltages = ((_max_uv) - (_min_uv)) / (_uV_step) + 1, \ ++ .ops = &rn5t567_regulator_ops, \ ++ .type = REGULATOR_VOLTAGE, \ ++ .owner = THIS_MODULE, \ ++ .min_uV = _min_uv, \ ++ .uV_step = _uV_step, \ ++ .linear_min_sel = 0, \ ++ .ramp_delay = _ramp_delay, \ ++ .vsel_reg = _vsreg, \ ++ .vsel_mask = _vsmsk, \ ++ .enable_reg = _ereg, \ ++ .enable_mask = _emsk, \ ++ .enable_time = _enable_time, \ ++ } ++ ++#define LDO_DESC(_rid, _ereg, _emsk, _min_uv, _max_uv, _uV_step, _vsreg, _vsmsk, _enable_time) \ ++ DESC(_rid, _ereg, _emsk, _min_uv, _max_uv, _uV_step, _vsreg, _vsmsk, 0, _enable_time) ++ ++static const struct regulator_desc rn5t567_regulator_descs[RN5T567_REGLATOR_NUM] = { ++ DESC(DCDC1, RN5T567_DC1CTL, BIT(0), 600000, 3500000, 12500, RN5T567_DC1DAC, 0xff, 14000, 500), ++ DESC(DCDC2, RN5T567_DC2CTL, BIT(0), 600000, 3500000, 12500, RN5T567_DC2DAC, 0xff, 14000, 500), ++ DESC(DCDC3, RN5T567_DC3CTL, BIT(0), 600000, 3500000, 12500, RN5T567_DC3DAC, 0xff, 14000, 500), ++ DESC(DCDC4, RN5T567_DC4CTL, BIT(0), 600000, 3500000, 12500, RN5T567_DC4DAC, 0xff, 14000, 500), ++ ++ LDO_DESC(LDO1, RN5T567_LDOEN1, BIT(0), 900000, 3500000, 50000, RN5T567_LDO1DAC, 0xfe, 500), ++ LDO_DESC(LDO2, RN5T567_LDOEN1, BIT(1), 900000, 3500000, 50000, RN5T567_LDO2DAC, 0xfe, 500), ++ LDO_DESC(LDO3, RN5T567_LDOEN1, BIT(2), 600000, 3500000, 50000, RN5T567_LDO3DAC, 0xfe, 500), ++ LDO_DESC(LDO4, RN5T567_LDOEN1, BIT(3), 900000, 3500000, 50000, RN5T567_LDO4DAC, 0xfe, 500), ++ LDO_DESC(LDO5, RN5T567_LDOEN1, BIT(4), 900000, 3500000, 50000, RN5T567_LDO5DAC, 0xfe, 500), ++ ++ LDO_DESC(LDORTC1, RN5T567_LDOEN2, BIT(4), 1200000, 3500000, 50000, RN5T567_LDORTCDAC, 0xfe, 500), ++// LDO_DESC(LDORTC2, RN5T567_LDOEN2, BIT(5), 900000, 3500000, 50000, RN5T567_LDORTC2DAC, 0xfe, 500), ++}; ++ ++#ifdef CONFIG_REGULATOR_USERSPACE_CONSUMER ++static void of_populate_userspace_consumers(struct device *dev) ++{ ++ struct device_node *child = NULL; ++ struct device_node *parent = NULL; ++ struct platform_device *pdev = NULL; ++ struct regulator_userspace_consumer_data pdata; ++ static int id = 0; ++ ++ parent = of_get_child_by_name(dev->parent->of_node, REGULATOR_NODE_NAME); ++ ++ for_each_child_of_node(parent, child) { ++ int supplies = 0, index = 0; ++ if (!child->type || of_node_cmp(child->type, "reg-userspace-consumer")) ++ continue; ++ ++ supplies = of_property_count_strings(child, "supplies-name"); ++ if (supplies <= 0) ++ continue; ++ ++ pdata.num_supplies = supplies; ++ pdata.supplies = devm_kzalloc(dev, supplies * sizeof(struct regulator_bulk_data), ++ GFP_KERNEL); ++ if (!pdata.supplies) ++ continue; ++ ++ if (of_property_read_string(child, "bulk-name", &(pdata.name))) ++ continue; ++ ++ for (index = 0; index < supplies; index++) ++ of_property_read_string_index(child, "supplies-name", index, ++ &(pdata.supplies[index].supply)); ++ ++ pdata.init_on = of_property_read_bool(child, "init_on"); ++ ++ pdev = platform_device_register_data(dev, "reg-userspace-consumer", id++, &pdata, ++ sizeof(struct regulator_userspace_consumer_data)); ++ WARN(IS_ERR(pdev), "%s(%s) register failed: %ld\n", pdata.name, ++ pdata.supplies[0].supply, PTR_ERR(pdev)); ++ } ++} ++#endif ++ ++static int rn5t567_regulator_probe(struct platform_device *pdev) ++{ ++ struct regmap *regmap = dev_get_drvdata(pdev->dev.parent); ++ struct regulator_config config = { }; ++ struct regulator_dev *rdev = NULL; ++ int i; ++ ++ for (i = 0; i < RN5T567_REGLATOR_NUM; i++) { ++ config.dev = pdev->dev.parent; ++ config.regmap = regmap; ++ ++ rdev = devm_regulator_register(&pdev->dev, &rn5t567_regulator_descs[i], &config); ++ if (IS_ERR(rdev)) { ++ dev_err(&pdev->dev, "failed to register %s regulator (errno %ld\n)\n", ++ rn5t567_regulator_descs[i].name, PTR_ERR(rdev)); ++ return PTR_ERR(rdev); ++ } ++ } ++ ++#ifdef CONFIG_REGULATOR_USERSPACE_CONSUMER ++ of_populate_userspace_consumers(&pdev->dev); ++#endif ++ return 0; ++} ++ ++static struct platform_driver rn5t567_regulator_driver = { ++ .probe = rn5t567_regulator_probe, ++ .driver = { ++ .name = "rn5t567-regulator", ++ }, ++}; ++ ++static int __init rn5t567_regulator_init(void) ++{ ++ return platform_driver_register(&rn5t567_regulator_driver); ++} ++subsys_initcall(rn5t567_regulator_init); ++ ++static void __exit rn5t567_regulator_exit(void) ++{ ++ platform_driver_unregister(&rn5t567_regulator_driver); ++} ++module_exit(rn5t567_regulator_exit); ++ ++MODULE_DESCRIPTION("rn5t567 regulator driver"); ++MODULE_ALIAS("platform:rn5t567-regulator"); ++MODULE_LICENSE("GPL"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_rtc_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_rtc_Kconfig.patch new file mode 100644 index 00000000..42f3eb77 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_rtc_Kconfig.patch @@ -0,0 +1,35 @@ +diff -drupN a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig +--- a/drivers/rtc/Kconfig 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/rtc/Kconfig 2022-06-09 05:02:33.000000000 +0300 +@@ -139,6 +139,15 @@ config RTC_DRV_TEST + This driver can also be built as a module. If so, the module + will be called rtc-test. + ++config RTC_DRV_INGENIC ++ tristate "INGENIC RTC" ++ help ++ If you say Y here you will get access to the real time clock ++ built into your INGENIC CPU. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called rtc-ingenic. ++ + comment "I2C RTC drivers" + depends on I2C + +@@ -419,6 +428,15 @@ config RTC_DRV_PCF8523 + This driver can also be built as a module. If so, the module + will be called rtc-pcf8523. + ++config RTC_DRV_BM8563 ++ tristate "BM8563 " ++ help ++ If you say yes here you get support for the NXP BM8563 RTC ++ chips. ++ ++ This driver can also be built as a module. If so, the module ++ will be called rtc-bm8563. ++ + config RTC_DRV_PCF8563 + tristate "Philips PCF8563/Epson RTC8564" + help diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_rtc_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_rtc_Makefile.patch new file mode 100644 index 00000000..6ed72181 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_rtc_Makefile.patch @@ -0,0 +1,16 @@ +diff -drupN a/drivers/rtc/Makefile b/drivers/rtc/Makefile +--- a/drivers/rtc/Makefile 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/rtc/Makefile 2022-06-09 05:02:33.000000000 +0300 +@@ -105,6 +105,7 @@ obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o + obj-$(CONFIG_RTC_DRV_OPAL) += rtc-opal.o + obj-$(CONFIG_RTC_DRV_PALMAS) += rtc-palmas.o + obj-$(CONFIG_RTC_DRV_PCAP) += rtc-pcap.o ++obj-$(CONFIG_RTC_DRV_BM8563) += rtc-bm8563.o + obj-$(CONFIG_RTC_DRV_PCF2123) += rtc-pcf2123.o + obj-$(CONFIG_RTC_DRV_PCF2127) += rtc-pcf2127.o + obj-$(CONFIG_RTC_DRV_PCF50633) += rtc-pcf50633.o +@@ -161,3 +162,4 @@ obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm83 + obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o + obj-$(CONFIG_RTC_DRV_XGENE) += rtc-xgene.o + obj-$(CONFIG_RTC_DRV_ZYNQMP) += rtc-zynqmp.o ++obj-$(CONFIG_RTC_DRV_INGENIC) += rtc-ingenic.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_rtc_rtc-bm8563.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_rtc_rtc-bm8563.c.patch new file mode 100644 index 00000000..f76e7da4 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_rtc_rtc-bm8563.c.patch @@ -0,0 +1,190 @@ +diff -drupN a/drivers/rtc/rtc-bm8563.c b/drivers/rtc/rtc-bm8563.c +--- a/drivers/rtc/rtc-bm8563.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/rtc/rtc-bm8563.c 2022-06-09 05:02:33.000000000 +0300 +@@ -0,0 +1,186 @@ ++//驱动代码 ++/* ++* An rtc/i2c driver for the BM8563 ++* ++* Based on rtc-bm8563.c ++* ++* 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. ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Registers */ ++#define REG_CTRL_1 0x00 ++#define REG_CTRL_2 0x01 ++#define REG_WATCH_SEC 0x02 ++#define REG_WATCH_MIN 0x03 ++#define REG_WATCH_HOUR 0x04 ++#define REG_WATCH_DATE 0x05 ++#define REG_WATCH_DAY 0x06 ++#define REG_WATCH_MON 0x07 ++#define REG_WATCH_YEAR 0x08 ++#define RTC_I2C_NUM 1 ++#define RTC_ADDR 0x51 ++ ++#define I2C_WRITE 0 ++#define I2C_READ 1 ++ ++static struct i2c_board_info bm8563_info = { ++ I2C_BOARD_INFO("bm8563", RTC_ADDR), ++}; ++ ++static struct i2c_client *bm8563_client; ++ ++static int bm8563_get_time(struct device *dev, struct rtc_time *tm) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ unsigned char addr = REG_WATCH_SEC; ++ unsigned char buf[7] = {0}; ++ ++ struct i2c_msg msgs[2] = { ++ [0] = { ++ .addr = client->addr, ++ .flags = I2C_WRITE, ++ .len = 1, ++ .buf = &addr, ++ }, /* setup read addr */ ++ [1] = { ++ .addr = client->addr, ++ .flags = I2C_READ, ++ .len = 7, ++ .buf = buf, ++ }, /* read time/date */ ++ }; ++ ++ /* read time/date registers */ ++ if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { ++ dev_err(&client->dev, "%s: read error\n", __func__); ++ return -EIO; ++ } ++ ++ //printk("kernel get time\n"); ++ tm->tm_sec = bcd2bin(buf[0]&0x7f) ; ++ tm->tm_min = bcd2bin(buf[1]); ++ tm->tm_hour = bcd2bin(buf[2]); ++ tm->tm_mday = bcd2bin(buf[3]); ++ tm->tm_wday = bcd2bin(buf[4]); ++ tm->tm_mon = bcd2bin(buf[5])-1; ++ tm->tm_year = bcd2bin(buf[6]) + 100; ++ if((tm->tm_sec == 0) && (tm->tm_min == 0) && (tm->tm_hour == 0) ) ++ rtc_time_to_tm(0, tm); ++ return 0; ++} ++ ++static int bm8563_set_time(struct device *dev, struct rtc_time *tm) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ unsigned char buf[8] = {0}; ++ unsigned char data[2] = {0}; ++ ++ struct i2c_msg msg[2] = { ++ [0] = { ++ .addr = client->addr, ++ .flags = I2C_WRITE, ++ .len = 8, ++ .buf = buf, ++ }, /* setup rtc time */ ++ [1] = { ++ .addr = client->addr, ++ .flags = I2C_READ, ++ .len = 1, ++ .buf = data, ++ }, /* read time/date */ ++ }; ++ ++ //printk("kernel set time\n"); ++ buf[0] = REG_WATCH_SEC; ++ buf[1] = bin2bcd(tm->tm_sec); ++ buf[2] = bin2bcd(tm->tm_min); ++ buf[3] = bin2bcd(tm->tm_hour); ++ buf[4] = bin2bcd(tm->tm_mday); ++ buf[5] = bin2bcd(tm->tm_wday); ++ buf[6] = bin2bcd(tm->tm_mon)+1; ++ buf[7] = bin2bcd(tm->tm_year % 100); ++ ++ /* write time/date registers */ ++ if ((i2c_transfer(client->adapter, msg, 2)) != 1) { ++ dev_err(&client->dev, "%s: write error\n", __func__); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static const struct rtc_class_ops bm8563_rtc_ops = { ++ .read_time = bm8563_get_time, ++ .set_time = bm8563_set_time, ++}; ++ ++static int bm8563_dev_init(void) ++{ ++ struct rtc_device *rtc; ++ struct i2c_adapter *i2c_adap; ++ struct i2c_client *client; ++ unsigned char buf[2]; ++ struct i2c_msg msg = { ++ RTC_ADDR, I2C_WRITE, 2, buf, /* write time/date */ ++ }; ++ ++ i2c_adap = i2c_get_adapter(RTC_I2C_NUM); ++ bm8563_client = i2c_new_device(i2c_adap, &bm8563_info); ++ i2c_put_adapter(i2c_adap); ++ client = bm8563_client; ++ ++ ++ buf[0] = REG_CTRL_1; ++ buf[1] = 0; ++ if ((i2c_transfer(client->adapter, &msg, 1)) != 1) { ++ dev_err(&client->dev, "%s: write error\n", __func__); ++ return -EIO; ++ } ++ rtc = rtc_device_register("bm8563", &client->dev, ++ &bm8563_rtc_ops, THIS_MODULE); ++ if (IS_ERR(rtc)) ++ return PTR_ERR(rtc); ++ ++ i2c_set_clientdata(client, rtc); ++ ++ return 0; ++} ++static void bm8563_dev_exit(void) ++{ ++ struct rtc_device *rtc = i2c_get_clientdata(bm8563_client); ++ ++ if (rtc) ++ rtc_device_unregister(rtc); ++ i2c_unregister_device(bm8563_client); ++} ++module_init(bm8563_dev_init); ++module_exit(bm8563_dev_exit); ++ ++MODULE_AUTHOR("damon.jszhang@ingenic.com"); ++MODULE_DESCRIPTION("rtc driver"); ++MODULE_LICENSE("GPL"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_rtc_rtc-ingenic.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_rtc_rtc-ingenic.c.patch new file mode 100644 index 00000000..7d34c70c --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_rtc_rtc-ingenic.c.patch @@ -0,0 +1,599 @@ +diff -drupN a/drivers/rtc/rtc-ingenic.c b/drivers/rtc/rtc-ingenic.c +--- a/drivers/rtc/rtc-ingenic.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/rtc/rtc-ingenic.c 2022-06-09 05:02:33.000000000 +0300 +@@ -0,0 +1,595 @@ ++/* ++ * Copyright (C) 2015 Ingenic Semiconductor Co., Ltd. ++ * Author: cli ++ * ++ * Real Time Clock interface for Ingenic's SOC, such as X1000, ++ * and so on. (kernel.4.4) ++ * ++ * Base on:rtc-generic: RTC driver using the generic RTC abstraction ++ * ++ * 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. ++ */ ++ ++/*#define DEBUG*/ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "rtc-ingenic.h" ++ ++#if defined(CONFIG_DEBUG_FS) && defined(DEBUG) ++#include ++#include ++#endif ++ ++struct ingenic_rtc_device { ++ struct rtc_device *rtc; ++ struct device *dev; ++ struct mutex reg_mutex; ++ bool pmic_vailed; /*power manage ic is vailed*/ ++ void __iomem *reg_base; ++ int irq; ++ uint32_t lprs_pwon_ms; /*long press power ms time on Wakeup pin*/ ++ uint32_t hr_assert_ms; /*HIBERNATE Reset assert time n*125ms*/ ++ struct clk *rtc_gate; ++ int rtc_clk_rate; ++ unsigned int hwrsr; ++ struct notifier_block restart_handler; ++#if defined(CONFIG_DEBUG_FS) && defined(DEBUG) ++ struct dentry *debugfs; ++#endif ++#ifdef CONFIG_SUSPEND_TEST ++ unsigned int sleep_count; ++ unsigned int os_alarm_time; ++ unsigned int save_rtccr; ++#endif ++}; ++ ++static struct ingenic_rtc_device *m_rtc; ++ ++static bool ingenic_rtc_clk_disconnect = false; ++ ++static int ingenic_rtc_read(struct ingenic_rtc_device* rtc, int reg) ++{ ++ return readl(rtc->reg_base + reg); ++} ++ ++static int ingenic_rtc_write(struct ingenic_rtc_device* rtc, int reg, int val) ++{ ++ int timeout = 1000000; ++ ++ mutex_lock(&rtc->reg_mutex); ++ ++ writel(WENR_WENPAT_WRITABLE, rtc->reg_base + RTC_WENR); ++ ++ while (!(readl(rtc->reg_base + RTC_WENR) & WENR_WEN) && ++ --timeout); ++ if (!timeout) { ++ dev_warn(rtc->dev, "wait rtc wenr timeout\n"); ++ mutex_unlock(&rtc->reg_mutex); ++ return -EIO; ++ } ++ timeout = 1000000; ++ while(!(readl(rtc->reg_base + RTC_RTCCR) & RTCCR_WRDY) && ++ --timeout); ++ if (!timeout) { ++ dev_warn(rtc->dev, "wait rtc write ready timeout 1 %x:%x (rtccr:%x)\n", ++ reg, val, ++ readl(rtc->reg_base + RTC_RTCCR)); ++ mutex_unlock(&rtc->reg_mutex); ++ return -EIO; ++ } ++ ++ writel(val, rtc->reg_base + reg); ++ ++ timeout = 1000000; ++ while(!(readl(rtc->reg_base + RTC_RTCCR) & RTCCR_WRDY) && ++ --timeout); ++ if (!timeout) { ++ dev_warn(rtc->dev, "wait rtc write ready timeout 2 %x:%x (rtccr:%x)\n", ++ reg, val, ++ readl(rtc->reg_base + RTC_RTCCR)); ++ mutex_unlock(&rtc->reg_mutex); ++ return -EIO; ++ } ++ ++ mutex_unlock(&rtc->reg_mutex); ++ return 0; ++} ++ ++static int ingenic_rtc_prepare_enable(struct ingenic_rtc_device *rtc) ++{ ++ if (ingenic_rtc_read(rtc, RTC_HSPR) != HSPR_RTCV) { /*rtc power on*/ ++ unsigned int rtccr, tmp; ++ int ret; ++ dev_info(rtc->dev, "usb rtc clk, system power on first time\n"); ++ ++ /*Try use rtc clk*/ ++ rtccr = RTCCR_RTCE; ++ //writel(rtccr, rtc->reg_base + RTC_RTCCR); ++ ingenic_rtc_clk_disconnect = false; ++ ret = ingenic_rtc_write(rtc, RTC_RTCGR, (rtc->rtc_clk_rate - 1) & RTCGR_NC1HZ_MASK); ++ if (!ret && (ingenic_rtc_read(rtc, RTC_RTCGR) & RTCGR_NC1HZ_MASK) == ++ (rtc->rtc_clk_rate - 1)) ++ goto rtc_power_on; ++ ++ /*Try use ext clk / 512*/ ++ dev_info(rtc->dev, "use (extern clk)/512\n"); ++ rtccr = RTCCR_SELEXC | RTCCR_RTCE; ++ writel(rtccr, rtc->reg_base + RTC_RTCCR); ++ rtc->rtc_clk_rate = 24000000/512; ++ ingenic_rtc_clk_disconnect = true; ++ ret = ingenic_rtc_write(rtc, RTC_RTCGR, (rtc->rtc_clk_rate - 1) & RTCGR_NC1HZ_MASK); ++ if (ret || (ingenic_rtc_read(rtc, RTC_RTCGR) & RTCGR_NC1HZ_MASK) != ++ (rtc->rtc_clk_rate - 1)) ++ return -ENODEV; ++rtc_power_on: ++ ingenic_rtc_write(rtc, RTC_HWFCR, HWFCR_WAIT_TIME(rtc->lprs_pwon_ms, rtc->rtc_clk_rate)); ++ ingenic_rtc_write(rtc, RTC_HRCR, HRCR_WAIT_TIME(rtc->hr_assert_ms, rtc->rtc_clk_rate)); ++ ingenic_rtc_write(rtc, RTC_RTCSR, 0); ++ ingenic_rtc_write(rtc, RTC_RTCSAR, 0); ++ tmp = ingenic_rtc_read(rtc, RTC_WKUPPINCR); ++ tmp &= ~(WKUPPINCR_P_JUD_EN); ++ ingenic_rtc_write(rtc, RTC_WKUPPINCR, tmp); ++ ingenic_rtc_write(rtc, RTC_RTCCR, rtccr); ++ ingenic_rtc_write(rtc, RTC_HSPR, HSPR_RTCV); ++ } else { ++ int temp, temp_new; ++ ++ temp = HWFCR_WAIT_TIME(rtc->lprs_pwon_ms, rtc->rtc_clk_rate); ++ if (temp != (ingenic_rtc_read(rtc, RTC_HWFCR) & HWFCR_MASK)) ++ ingenic_rtc_write(rtc, RTC_HWFCR, temp); ++ ++ temp = HRCR_WAIT_TIME(rtc->hr_assert_ms, rtc->rtc_clk_rate); ++ if (temp != (ingenic_rtc_read(rtc, RTC_HRCR) & HRCR_MASK)) ++ ingenic_rtc_write(rtc, RTC_HRCR, temp); ++ ++ temp = ingenic_rtc_read(rtc, RTC_WKUPPINCR); ++ temp_new = temp & (~WKUPPINCR_P_JUD_EN); ++ if (temp_new != temp) ++ ingenic_rtc_write(rtc, RTC_WKUPPINCR, temp_new); ++ ++ rtc->hwrsr = ingenic_rtc_read(rtc, RTC_HWRSR); ++ } ++ ingenic_rtc_write(rtc, RTC_HWRSR, 0x0); ++ ingenic_rtc_write(rtc, RTC_RTCGR, RTCGR_LOCK | ingenic_rtc_read(rtc, RTC_RTCGR)); ++ ingenic_rtc_write(rtc, RTC_HWCR, HWCR_EALM | EPDET_ENABLE); ++ ++ return 0; ++} ++ ++static irqreturn_t ingenic_rtc_interrupt_thread_handler(int irq, void *dev_id) ++{ ++ struct ingenic_rtc_device *rtc = dev_id; ++ unsigned int rtccr; ++ ++ mutex_lock(&rtc->rtc->ops_lock); ++ rtccr = ingenic_rtc_read(rtc, RTC_RTCCR); ++ rtccr &= ~(RTCCR_1HZ | RTCCR_AF); ++ ingenic_rtc_write(rtc, RTC_RTCCR, rtccr); ++ mutex_unlock(&rtc->rtc->ops_lock); ++ ++ rtc_update_irq(rtc->rtc, 0/*uncare*/, 0/*uncare*/); ++ ++ return IRQ_HANDLED; ++} ++ ++static int ingenic_rtc_get_time(struct device *dev, struct rtc_time *tm) ++{ ++ struct ingenic_rtc_device *rtc = dev_get_drvdata(dev); ++ uint32_t secs, secs2; ++ int timeout = 10; ++ ++ /* If the seconds register is read while it is updated, it can contain a ++ * bogus value. This can be avoided by making sure that two consecutive ++ * reads have the same value. ++ */ ++ secs = readl(rtc->reg_base + RTC_RTCSR); ++ secs = readl(rtc->reg_base + RTC_RTCSR); ++ ++ while (secs != secs2 && --timeout) { ++ secs = secs2; ++ secs2 = readl(rtc->reg_base + RTC_RTCSR); ++ } ++ ++ if (timeout == 0) ++ return -EIO; ++ ++ rtc_time_to_tm(secs, tm); ++ ++ return rtc_valid_tm(tm); ++} ++ ++static int ingenic_rtc_set_mmss(struct device *dev, unsigned long secs) ++{ ++ struct ingenic_rtc_device *rtc = dev_get_drvdata(dev); ++ return ingenic_rtc_write(rtc, RTC_RTCSR, secs); ++} ++ ++static int ingenic_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) ++{ ++ struct ingenic_rtc_device *rtc = dev_get_drvdata(dev); ++ unsigned int rtccr_new, rtccr; ++ ++ rtccr = ingenic_rtc_read(rtc, RTC_RTCCR); ++ /*WARN_ON(!(enabled && (rtccr & (RTCCR_1HZIE|RTCCR_AIE))));*/ ++ ++ if (!enabled) { ++ rtccr_new = rtccr; ++ if (!rtc->rtc->uie_rtctimer.enabled) ++ rtccr_new &= ~(RTCCR_1HZIE); ++ rtccr_new &= ~(RTCCR_AIE | RTCCR_AE); ++ if (rtccr_new != rtccr) ++ ingenic_rtc_write(rtc, RTC_RTCCR, rtccr_new); ++ } ++ pr_debug("=====> %s %d enabled %d, %x\n", __func__, __LINE__, ++ enabled, ++ ingenic_rtc_read(rtc, RTC_RTCCR)); ++ return 0; ++} ++ ++static int ingenic_rtc_read_alarm(struct device * dev, struct rtc_wkalrm *alrm) ++{ ++ struct ingenic_rtc_device *rtc = dev_get_drvdata(dev); ++ uint32_t secs; ++ uint32_t ctrl; ++ ++ secs = ingenic_rtc_read(rtc, RTC_RTCSAR); ++ ctrl = ingenic_rtc_read(rtc, RTC_RTCCR); ++ ++ alrm->enabled = !!(ctrl & RTCCR_AIE); ++ alrm->pending = !!(ctrl & RTCCR_AF); ++ ++ rtc_time_to_tm(secs, &alrm->time); ++ ++ return rtc_valid_tm(&alrm->time); ++} ++ ++static int ingenic_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) ++{ ++ struct ingenic_rtc_device *rtc = dev_get_drvdata(dev); ++ struct timerqueue_node *next = timerqueue_getnext(&rtc->rtc->timerqueue); ++ struct rtc_timer *timer; ++ unsigned long secs; ++ unsigned int rtccr_new, rtccr; ++ int ret = 0; ++ ++ BUG_ON(!next); ++ timer = container_of(next, struct rtc_timer, node); ++ rtc_tm_to_time(&alrm->time, &secs); ++ ++ if (&rtc->rtc->uie_rtctimer == timer) { ++ /*1HZ peroid interrupt*/ ++ rtccr = rtccr_new = ingenic_rtc_read(rtc, RTC_RTCCR); ++ rtccr_new &= ~(RTCCR_AIE | RTCCR_AE); ++ rtccr_new |= RTCCR_1HZIE; ++ if (rtccr_new != rtccr) ++ ret = ingenic_rtc_write(rtc, RTC_RTCCR, rtccr_new); ++ } else { ++ /*alarm interrupt*/ ++ ret = ingenic_rtc_write(rtc, RTC_RTCSAR, secs); ++ if (!ret) { ++ rtccr = rtccr_new = ingenic_rtc_read(rtc, RTC_RTCCR); ++ rtccr_new &= ~(RTCCR_1HZIE); ++ rtccr_new |= RTCCR_AIE | RTCCR_AE; ++ if (rtccr_new != rtccr) { ++ ret = ingenic_rtc_write(rtc, RTC_RTCCR, rtccr_new); ++ } ++ } ++ } ++ pr_debug("=====> %s %d %x:%x:%x\n", __func__, __LINE__, ++ ingenic_rtc_read(rtc, RTC_RTCSR), ++ ingenic_rtc_read(rtc, RTC_RTCSAR), ++ ingenic_rtc_read(rtc, RTC_RTCCR)); ++ return ret; ++} ++ ++static int ingenic_rtc_rtc_proc(struct device *dev, struct seq_file *seq) ++{ ++ struct ingenic_rtc_device *rtc = dev_get_drvdata(dev); ++ ++ seq_printf(seq, "RTC regulator\t: 0x%08x\n", ++ ingenic_rtc_read(rtc, RTC_RTCGR)); ++ seq_printf(seq, "update_IRQ\t: %s\n", ++ (ingenic_rtc_read(rtc, RTC_RTCCR) & RTCCR_1HZIE) ? "yes" : "no"); ++ ++ if (rtc->hwrsr & HWRSR_APD) ++ seq_printf(seq, "Accident power down\n"); ++ if (rtc->hwrsr & HWRSR_HR) ++ seq_printf(seq, "Hibernate Reset: \n"); ++ if (rtc->hwrsr & HWRSR_PIN) ++ seq_printf(seq, "\tWakeup Pin wakeup system\n"); ++ if (rtc->hwrsr & HWRSR_ALM) ++ seq_printf(seq, "\tAlarm wakeup system\n"); ++ if (rtc->hwrsr & HWRSR_PPR) ++ seq_printf(seq, "PAD PIN Reset\n"); ++ return 0; ++} ++ ++static const struct rtc_class_ops ingenic_rtc_ops = { ++ .read_time = ingenic_rtc_get_time, ++ .set_mmss = ingenic_rtc_set_mmss, ++ .alarm_irq_enable = ingenic_rtc_alarm_irq_enable, ++ .read_alarm = ingenic_rtc_read_alarm, ++ .set_alarm = ingenic_rtc_set_alarm, ++ .proc = ingenic_rtc_rtc_proc, ++}; ++ ++#define INGENIC_RTC_DEFUALT_PWON_PRESS_MS (2000) ++#define INGENIC_RTC_DEFUALT_HIBERNATE_RESET_ASSERT_MS (60) /*copy from old rtc driver*/ ++ ++static void ingenic_rtc_hibernate(void) ++{ ++ struct ingenic_rtc_device *rtc = m_rtc; ++ ++ mutex_lock(&rtc->rtc->ops_lock); ++ ingenic_rtc_write(rtc, RTC_HCR, HCR_PD); ++ mdelay(2000); ++ mutex_unlock(&rtc->rtc->ops_lock); ++ pr_err("RTC hibernate has been run, but extern power not down RTC_HCR(%x)\n", ++ ingenic_rtc_read(rtc, RTC_HCR)); ++ while(1); ++} ++ ++static int ingenic_rtc_reset_handler(struct notifier_block *this, unsigned long mode, ++ void *cmd) ++{ ++ struct ingenic_rtc_device *rtc = m_rtc; ++ uint32_t rtc_rtcsr,rtc_rtccr; ++ ++ /* ++ * Use setup params "reboot=h" (mode == REBOOT_HARD) , ++ * enable the hibernate reset function ++ */ ++ if (mode != REBOOT_HARD || (cmd && (!strcmp(cmd, REBOOT_CMD_RECOVERY) || ++ !strcmp(cmd, REBOOT_CMD_SOFTBURN)))) { ++ pr_debug("%s %d mode %lu cmd %s\n", __func__, __LINE__, mode, cmd ? (char*)cmd : "null"); ++ return NOTIFY_DONE; ++ } ++ pr_info("hibernate reset"); ++ mutex_lock(&rtc->rtc->ops_lock); ++ rtc_rtcsr = ingenic_rtc_read(rtc, RTC_RTCSR); ++ ingenic_rtc_write(rtc, RTC_RTCSAR, rtc_rtcsr + 5); /*5s delay*/ ++ rtc_rtccr = ingenic_rtc_read(rtc, RTC_RTCCR); ++ rtc_rtccr &= ~RTCCR_AF; ++ rtc_rtccr |= RTCCR_AIE | RTCCR_AE; ++ ingenic_rtc_write(rtc, RTC_RTCCR, rtc_rtccr); ++ ingenic_rtc_write(rtc, RTC_HWRSR, 0x0); ++ ingenic_rtc_write(rtc, RTC_HWCR, HWCR_EALM|EPDET_ENABLE); ++ ingenic_rtc_write(rtc, RTC_HCR, HCR_PD); ++ while(1) { ++ mdelay(200); ++ printk("%s:We should NOT come here.%08x\n", ++ __func__, ingenic_rtc_read(rtc, RTC_HCR)); ++ } ++ mutex_unlock(&rtc->rtc->ops_lock); ++ return NOTIFY_STOP; ++} ++ ++#if defined(CONFIG_DEBUG_FS) && defined(DEBUG) ++static ssize_t ingenic_rtc_show_regs(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ingenic_rtc_device *rtc = file->private_data; ++ char *buf; ++ int len = 0; ++ ssize_t ret; ++ ++#define REGS_BUFSIZE 1024 ++ buf = kzalloc(REGS_BUFSIZE, GFP_KERNEL); ++ if (!buf) ++ return 0; ++ len += snprintf(buf + len, REGS_BUFSIZE - len, "rtc register: %p\n", rtc->reg_base); ++ len += snprintf(buf + len, REGS_BUFSIZE - len, "RTC_RTCCR : 0x%08x\n", ingenic_rtc_read(rtc, RTC_RTCCR)); ++ len += snprintf(buf + len, REGS_BUFSIZE - len, "RTC_RTCSR : 0x%08x\n", ingenic_rtc_read(rtc, RTC_RTCSR)); ++ len += snprintf(buf + len, REGS_BUFSIZE - len, "RTC_RTCSAR : 0x%08x\n", ingenic_rtc_read(rtc, RTC_RTCSAR)); ++ len += snprintf(buf + len, REGS_BUFSIZE - len, "RTC_RTCGR : 0x%08x\n", ingenic_rtc_read(rtc, RTC_RTCGR)); ++ len += snprintf(buf + len, REGS_BUFSIZE - len, "RTC_HCR : 0x%08x\n", ingenic_rtc_read(rtc, RTC_HCR)); ++ len += snprintf(buf + len, REGS_BUFSIZE - len, "RTC_HWFCR : 0x%08x\n", ingenic_rtc_read(rtc, RTC_HWFCR)); ++ len += snprintf(buf + len, REGS_BUFSIZE - len, "RTC_HRCR : 0x%08x\n", ingenic_rtc_read(rtc, RTC_HRCR)); ++ len += snprintf(buf + len, REGS_BUFSIZE - len, "RTC_HWCR : 0x%08x\n", ingenic_rtc_read(rtc, RTC_HWCR)); ++ len += snprintf(buf + len, REGS_BUFSIZE - len, "RTC_HWRSR : 0x%08x\n", ingenic_rtc_read(rtc, RTC_HWRSR)); ++ len += snprintf(buf + len, REGS_BUFSIZE - len, "RTC_HSPR : 0x%08x\n", ingenic_rtc_read(rtc, RTC_HSPR)); ++ len += snprintf(buf + len, REGS_BUFSIZE - len, "RTC_WENR : 0x%08x\n", ingenic_rtc_read(rtc, RTC_WENR)); ++ len += snprintf(buf + len, REGS_BUFSIZE - len, "RTC_WKUPPINCR: 0x%08x\n", ingenic_rtc_read(rtc, RTC_WKUPPINCR)); ++ ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); ++ kfree(buf); ++#undef REGS_BUFSIZE ++ return ret; ++} ++ ++static struct file_operations ingenic_rtc_reg_ops = { ++ .owner = THIS_MODULE, ++ .open = simple_open, ++ .read = ingenic_rtc_show_regs, ++ .llseek = default_llseek, ++}; ++#endif ++ ++static int __init ingenic_rtc_probe(struct platform_device *pdev) ++{ ++ struct ingenic_rtc_device *ingenic_rtc; ++ struct resource *res; ++ struct clk *rtc_clk; ++ struct clk *rtc_gate; ++ int ret; ++ ++ ingenic_rtc = devm_kzalloc(&pdev->dev, sizeof(struct ingenic_rtc_device), GFP_KERNEL); ++ if (!ingenic_rtc) ++ return -ENOMEM; ++ ++ ingenic_rtc->pmic_vailed = of_property_read_bool(pdev->dev.of_node, ++ "system-power-controller"); ++ if (ingenic_rtc->pmic_vailed) { ++ ret = of_property_read_u32(pdev->dev.of_node, ++ "power-on-press-ms", ++ &ingenic_rtc->lprs_pwon_ms); ++ if (ret) ++ ingenic_rtc->lprs_pwon_ms = INGENIC_RTC_DEFUALT_PWON_PRESS_MS; ++ ingenic_rtc->hr_assert_ms = INGENIC_RTC_DEFUALT_HIBERNATE_RESET_ASSERT_MS; ++ if (!pm_power_off) { ++ m_rtc = ingenic_rtc; ++ pm_power_off = ingenic_rtc_hibernate; ++ } ++ } ++ ingenic_rtc->dev = &pdev->dev; ++ mutex_init(&ingenic_rtc->reg_mutex); ++ ++ rtc_gate = clk_get(&pdev->dev, "gate_rtc"); ++ if (IS_ERR(rtc_gate)) ++ return PTR_ERR(rtc_gate); ++ clk_prepare_enable(rtc_gate); ++ clk_put(rtc_gate); ++ ++ rtc_clk = clk_get(&pdev->dev, "rtc"); ++ if (IS_ERR_OR_NULL(rtc_clk) || ++ (ingenic_rtc->rtc_clk_rate = clk_get_rate(rtc_clk)) <= 0) { ++ dev_warn(&pdev->dev, "Impossible: can not find fin_rtc(use 32768)\n"); ++ ingenic_rtc->rtc_clk_rate = 32768; ++ } ++ if (!IS_ERR_OR_NULL(rtc_clk)) ++ clk_put(rtc_clk); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) ++ return -ENOMEM; ++ ++ ingenic_rtc->reg_base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(ingenic_rtc->reg_base)) ++ return PTR_ERR(ingenic_rtc->reg_base); ++ ++ ingenic_rtc->irq = platform_get_irq(pdev, 0); ++ if (ingenic_rtc->irq < 0) ++ return ingenic_rtc->irq; ++ ++ ret = ingenic_rtc_prepare_enable(ingenic_rtc); ++ if (ret) ++ return ret; ++ ++ device_init_wakeup(&pdev->dev, true); ++ platform_set_drvdata(pdev, ingenic_rtc); ++ ++ ingenic_rtc->rtc = devm_rtc_device_register(&pdev->dev, "rtc-ingenic", ++ &ingenic_rtc_ops, THIS_MODULE); ++ if (IS_ERR(ingenic_rtc->rtc)) ++ return PTR_ERR(ingenic_rtc->rtc); ++ ++ ret = devm_request_threaded_irq(&pdev->dev, ingenic_rtc->irq, NULL, ++ ingenic_rtc_interrupt_thread_handler, ++ IRQF_TRIGGER_LOW | IRQF_ONESHOT, ++ "rtc 1HZ and alarm", ++ (void *)ingenic_rtc); ++ if (ret) ++ return ret; ++ ++ ingenic_rtc->restart_handler.notifier_call = ingenic_rtc_reset_handler; ++ ingenic_rtc->restart_handler.priority = RTC_HIBERNATE_RESET_PROR; ++ ret = register_restart_handler(&ingenic_rtc->restart_handler); ++ if (ret) ++ dev_warn(&pdev->dev, ++ "cannot register rtc restart\ ++ handler (err=%d)\n", ret); ++ ++ ++#if defined(CONFIG_DEBUG_FS) && defined(DEBUG) ++ ingenic_rtc->debugfs = debugfs_create_file("rtc_reg", 0x444, NULL, ++ ingenic_rtc, &ingenic_rtc_reg_ops); ++#endif ++ return 0; ++} ++ ++static void __exit ingenic_rtc_remove(struct platform_device *pdev) ++{ ++#if defined(CONFIG_DEBUG_FS) && defined(DEBUG) ++ struct ingenic_rtc_device *ingenic_rtc = platform_get_drvdata(pdev); ++ if (ingenic_rtc->debugfs) ++ debugfs_remove(ingenic_rtc->debugfs); ++#endif ++} ++ ++static const struct of_device_id ingenic_rtc_of_match[] = { ++ { .compatible = "ingenic,rtc", .data = NULL, }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ingenic_rtc_of_match); ++ ++#ifdef CONFIG_PM ++static int ingenic_rtc_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ struct ingenic_rtc_device *rtc = platform_get_drvdata(pdev); ++#ifdef CONFIG_SUSPEND_TEST ++ unsigned int val; ++ unsigned int test_alarm_time, sr_time; ++ ++ val = ingenic_rtc_read(rtc, RTC_RTCCR); ++ if(val & RTCCR_AE) { ++ rtc->save_rtccr = val; ++ rtc->os_alarm_time = ingenic_rtc_read(rtc, RTC_RTCSAR); ++ } ++ val |= RTCCR_AIE | RTCCR_AE; ++ ingenic_rtc_write(rtc, RTC_RTCCR, val); ++ ++ sr_time = ingenic_rtc_read(rtc, RTC_RTCSR); ++ test_alarm_time = sr_time + CONFIG_SUSPEND_ALARM_TIME; ++ if(rtc->os_alarm_time && rtc->os_alarm_time > sr_time \ ++ && rtc->os_alarm_time < test_alarm_time) ++ test_alarm_time = rtc->os_alarm_time; ++ ingenic_rtc_write(rtc, RTC_RTCSAR, test_alarm_time); ++ ++ printk("-------suspend count = %d\n", rtc->sleep_count++); ++#endif ++ if (device_may_wakeup(&pdev->dev)) ++ enable_irq_wake(rtc->irq); ++ return 0; ++} ++ ++static int ingenic_rtc_resume(struct platform_device *pdev) ++{ ++ struct ingenic_rtc_device *rtc = platform_get_drvdata(pdev); ++#ifdef CONFIG_SUSPEND_TEST ++ if(rtc->save_rtccr & RTCCR_AE) { ++ ingenic_rtc_write(rtc, RTC_RTCSAR, rtc->os_alarm_time); ++ ingenic_rtc_write(rtc, RTC_RTCCR, rtc->save_rtccr); ++ rtc->os_alarm_time = 0; ++ rtc->save_rtccr = 0; ++ } else { ++ unsigned int val; ++ val = ingenic_rtc_read(rtc, RTC_RTCCR); ++ val &= ~ (RTCCR_AF |RTCCR_AIE | RTCCR_AE); ++ ingenic_rtc_write(rtc, RTC_RTCCR, val); ++ } ++#endif ++ if (device_may_wakeup(&pdev->dev)) ++ disable_irq_wake(rtc->irq); ++ return 0; ++} ++ ++#else ++#define ingenic_rtc_suspend NULL ++#define ingenic_rtc_resume NULL ++#endif ++ ++static struct platform_driver ingenic_rtc_driver = { ++ .driver = { ++ .name = "rtc-ingenic", ++ .of_match_table = ingenic_rtc_of_match, ++ }, ++ .remove = __exit_p(ingenic_rtc_remove), ++ .suspend = ingenic_rtc_suspend, ++ .resume = ingenic_rtc_resume, ++}; ++module_platform_driver_probe(ingenic_rtc_driver, ingenic_rtc_probe); ++ ++MODULE_AUTHOR("Cli "); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("Ingenic RTC driver"); ++MODULE_ALIAS("platform:rtc-ingenic"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_rtc_rtc-ingenic.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_rtc_rtc-ingenic.h.patch new file mode 100644 index 00000000..6d19cb07 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_rtc_rtc-ingenic.h.patch @@ -0,0 +1,135 @@ +diff -drupN a/drivers/rtc/rtc-ingenic.h b/drivers/rtc/rtc-ingenic.h +--- a/drivers/rtc/rtc-ingenic.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/rtc/rtc-ingenic.h 2022-06-09 05:02:33.000000000 +0300 +@@ -0,0 +1,131 @@ ++/* ++ * Copyright (C) 2015 Ingenic Semiconductor Co., Ltd. ++ * Author: cli ++ * ++ * Real Time Clock register definition for Ingenic's SOC, such as X1000, ++ * and so on. (kernel.4.4) ++ * ++ * 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. ++ */ ++ ++#ifndef __RTC_INGENIC_H__ ++#define __RTC_INGENIC_H__ ++ ++/* ++ * RTC registers offset address definition ++ */ ++#define RTC_RTCCR (0x00) /* rw, 32, 0x00000081 */ ++#define RTC_RTCSR (0x04) /* rw, 32, 0x???????? */ ++#define RTC_RTCSAR (0x08) /* rw, 32, 0x???????? */ ++#define RTC_RTCGR (0x0c) /* rw, 32, 0x0??????? */ ++ ++#define RTC_HCR (0x20) /* rw, 32, 0x00000000 */ ++#define RTC_HWFCR (0x24) /* rw, 32, 0x0000???0 */ ++#define RTC_HRCR (0x28) /* rw, 32, 0x00000??0 */ ++#define RTC_HWCR (0x2c) /* rw, 32, 0x00000008 */ ++#define RTC_HWRSR (0x30) /* rw, 32, 0x00000000 */ ++#define RTC_HSPR (0x34) /* rw, 32, 0x???????? */ ++#define RTC_WENR (0x3c) /* rw, 32, 0x00000000 */ ++#define RTC_WKUPPINCR (0x48) /* rw, 32, 0x00050064*/ ++ ++/* ++ * RTC registers common define ++ */ ++ ++/* RTC control register(RTCCR) */ ++#define RTCCR_WRDY BIT(7) ++#define RTCCR_1HZ BIT(6) ++#define RTCCR_1HZIE BIT(5) ++#define RTCCR_AF BIT(4) ++#define RTCCR_AIE BIT(3) ++#define RTCCR_AE BIT(2) ++#define RTCCR_SELEXC BIT(1) ++#define RTCCR_RTCE BIT(0) ++ ++ ++/* Generate the bit field mask from msb to lsb */ ++#define BITS_H2L(msb, lsb) ((0xFFFFFFFF >> (32-((msb)-(lsb)+1))) << (lsb)) ++ ++/* RTC regulator register(RTCGR) */ ++#define RTCGR_LOCK BIT(31) ++#define RTCGR_ADJC_LSB 16 ++#define RTCGR_ADJC_MASK BITS_H2L(25, RTCGR_ADJC_LSB) ++#define RTCGR_NC1HZ_LSB 0 ++#define RTCGR_NC1HZ_MASK BITS_H2L(15, RTCGR_NC1HZ_LSB) ++ ++/* Hibernate control register(HCR) */ ++#define HCR_PD BIT(0) ++ ++/* Hibernate wakeup filter counter register(HWFCR) */ ++#define HWFCR_LSB 5 ++#define HWFCR_MASK BITS_H2L(15, HWFCR_LSB) ++#define HWFCR_WAIT_TIME(ms, clk) (((ms)*(clk)/1000+0xf) > HWFCR_MASK ? HWFCR_MASK : ((ms)*(clk)/1000+0xf) & HWFCR_MASK) ++ ++/* Hibernate reset counter register(HRCR) */ ++#define HRCR_LSB 11 ++#define HRCR_MASK BITS_H2L(14, HRCR_LSB) ++#define HRCR_WAIT_TIME(ms, clk) (((ms)*(clk)/1000 + 0x3ff - 0x800) > HRCR_MASK ? HRCR_MASK : \ ++ ((ms)*(clk)/1000 + 0x3ff - 0x800) & HRCR_MASK) ++ ++ ++/* Hibernate wakeup control register(HWCR) */ ++/* Power detect default value; this value means enable */ ++#define EPDET_LSB 3 ++#define EPDET_DEFAULT (0x5aa5a5a << EPDET_LSB) ++#define EPDET_ENABLE (0x5aa5a5a << EPDET_LSB) ++#define EPDET_DISABLE (0x1a55a5a5 << EPDET_LSB) ++#define HWCR_EALM BIT(0) ++ ++ ++/* Hibernate wakeup status register(HWRSR) */ ++#define HWRSR_APD BIT(8) ++#define HWRSR_HR BIT(5) ++#define HWRSR_PPR BIT(4) ++#define HWRSR_PIN BIT(1) ++#define HWRSR_ALM BIT(0) ++ ++/* write enable pattern register(WENR) */ ++#define WENR_WEN BIT(31) ++#define WENR_WENPAT_LSB 0 ++#define WENR_WENPAT_MASK BITS_H2L(15, WENR_WENPAT_LSB) ++#define WENR_WENPAT_WRITABLE (0xa55a) ++ ++/* Hibernate scratch pattern register(HSPR) */ ++#define HSPR_RTCV 0x52544356 /* The value is 'RTCV', means rtc is valid */ ++ ++/*WKUP_PIN_RST control register (WKUPPINCR)*/ ++#define WKUPPINCR_BIAS_CTRL (0x1 << 16) /* fix value*/ ++#define WKUPPINCR_OSC_EN BIT(18) ++#define WKUPPINCR_P_JUD_LEN_LSB 4 ++#define WKUPPINCR_P_JUD_LEN_MASK BITS_H2L(7, WKUPPINCR_P_JUD_LEN_LSB) ++#define WKUPPINCR_P_JUD_LEN(s) ((s) << WKUPPINCR_P_JUD_LEN_LSB) > WKUPPINCR_P_JUD_LEN_MASK ? \ ++ WKUPPINCR_P_JUD_LEN_MASK : (s) << WKUPPINCR_P_JUD_LEN_LSB ++#define WKUPPINCR_P_JUD_EN (0x4) ++/* The divider is decided by the RTC clock frequency. */ ++#define RTC_FREQ_DIVIDER (32768 - 1) ++ ++/*ingenic rtc device struct*/ ++struct ingenic_rtc { ++ int irq; ++ struct clk *clk; ++ spinlock_t lock; ++ spinlock_t rd_lock; ++ spinlock_t wr_lock; ++ void __iomem *iomem; ++ struct mutex mutexlock; ++ struct mutex mutex_wr_lock; ++ struct resource *res; ++ struct work_struct work; ++ struct rtc_device *rtc; ++ struct rtc_time rtc_alarm; ++#ifdef CONFIG_SUSPEND_TEST ++ unsigned int sleep_count; ++ unsigned int os_alarm_time; ++ unsigned int save_rtccr; ++#endif ++ struct dentry *debugfs; ++}; ++#endif /* __RTC_INGENIC_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_spi_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_spi_Kconfig.patch new file mode 100644 index 00000000..881212d9 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_spi_Kconfig.patch @@ -0,0 +1,21 @@ +diff -drupN a/drivers/spi/Kconfig b/drivers/spi/Kconfig +--- a/drivers/spi/Kconfig 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/spi/Kconfig 2022-06-09 05:02:33.000000000 +0300 +@@ -53,6 +53,17 @@ if SPI_MASTER + + comment "SPI Master Controller Drivers" + ++config INGENIC_SPI ++ tristate "Ingenic SPI Controller" ++ depends on MACH_XBURST2 ++ select SPI_BITBANG ++ help ++ SPI driver for Ingenic series SoCs ++ ++config INGENIC_SPI0 ++ bool "Ingenic SoC SSI controller 0 for SPI Host driver" ++ depends on INGENIC_SPI ++ + config SPI_ALTERA + tristate "Altera SPI Controller" + select SPI_BITBANG diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_spi_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_spi_Makefile.patch new file mode 100644 index 00000000..bb495ac9 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_spi_Makefile.patch @@ -0,0 +1,8 @@ +diff -drupN a/drivers/spi/Makefile b/drivers/spi/Makefile +--- a/drivers/spi/Makefile 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/spi/Makefile 2022-06-09 05:02:33.000000000 +0300 +@@ -93,3 +93,4 @@ obj-$(CONFIG_SPI_XILINX) += spi-xilinx. + obj-$(CONFIG_SPI_XLP) += spi-xlp.o + obj-$(CONFIG_SPI_XTENSA_XTFPGA) += spi-xtensa-xtfpga.o + obj-$(CONFIG_SPI_ZYNQMP_GQSPI) += spi-zynqmp-gqspi.o ++obj-$(CONFIG_INGENIC_SPI) += ingenic_spi.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_spi_ingenic_spi.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_spi_ingenic_spi.c.patch new file mode 100644 index 00000000..aa6ae018 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_spi_ingenic_spi.c.patch @@ -0,0 +1,1490 @@ +diff -drupN a/drivers/spi/ingenic_spi.c b/drivers/spi/ingenic_spi.c +--- a/drivers/spi/ingenic_spi.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/spi/ingenic_spi.c 2022-06-09 05:02:33.000000000 +0300 +@@ -0,0 +1,1486 @@ ++/* linux/drivers/spi/ingenic_spi.c ++ * ++ * SSI controller for SPI protocol,use FIFO and DMA; ++ * base-to: linux/drivers/spi/spi_bitbang.c ++ * ++ * Copyright (c) 2010 Ingenic ++ * Author:Shumb ++ * ++ * 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. ++ * ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ingenic_spi.h" ++ ++/* #define SSI_DEGUG */ ++#ifdef SSI_DEGUG ++#define print_dbg(format,arg...) \ ++ printk(format,## arg) ++#else ++#define print_dbg(format,arg...) ++#endif ++ ++#define INGENIC_SPI_RX_BUF(type) \ ++ u32 ingenic_spi_rx_buf_##type(struct ingenic_spi *ingspi) \ ++ { \ ++ u32 data = spi_readl(ingspi, SSI_DR); \ ++ type * rx = (type *)ingspi->rx; \ ++ *rx++ = (type)(data); \ ++ ingspi->rx = (u8 *)rx; \ ++ return (u32)data; \ ++ } ++ ++#define INGENIC_SPI_TX_BUF(type) \ ++ u32 ingenic_spi_tx_buf_##type(struct ingenic_spi *ingspi) \ ++ { \ ++ u32 data; \ ++ const type * tx = (type *)ingspi->tx; \ ++ data = *tx++; \ ++ ingspi->tx = (u8 *)tx; \ ++ transmit_data(ingspi, data); \ ++ return (u32)data; \ ++ } ++ ++INGENIC_SPI_RX_BUF(u8) ++INGENIC_SPI_TX_BUF(u8) ++ ++INGENIC_SPI_RX_BUF(u16) ++INGENIC_SPI_TX_BUF(u16) ++ ++INGENIC_SPI_RX_BUF(u32) ++INGENIC_SPI_TX_BUF(u32) ++ ++/* the spi->mode bits understood by this driver: */ ++#define MODEBITS (SPI_3WIRE | SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST | SPI_LOOP) ++#define SPI_BITS_SUPPORT (SPI_BITS_8 | SPI_BITS_16 | SPI_BITS_32) ++ ++static void ingenic_spi_cs(struct ingenic_spi_info *spi, u8 cs, unsigned int pol) ++{ ++#ifdef CONFIG_INGENIC_SPI_PIO_CE ++ u32 pin_value = *(spi->chipselect + cs); ++ gpio_direction_output(pin_value, !pol ? 0 : 1); ++#endif ++} ++ ++static void ingenic_spi_chipsel(struct spi_device *spi, int value) ++{ ++ struct ingenic_spi *ingspi = spi_master_get_devdata(spi->master); ++ unsigned int cspol = spi->mode & SPI_CS_HIGH ? 1 : 0; ++ ++ /*printk("%s[%d]: value = %d\n",__func__,__LINE__, value);*/ ++ switch (value) { ++ case BITBANG_CS_INACTIVE: ++ /* chip disable selected */ ++ if (ingspi->set_cs && ingspi->pdata) ++ ingspi->set_cs(ingspi->pdata, spi->chip_select, cspol^1); ++ break; ++ case BITBANG_CS_ACTIVE: ++ if (spi->mode & SPI_CPHA) ++ set_spi_clock_phase(ingspi, 1); ++ else ++ set_spi_clock_phase(ingspi, 0); ++ ++ if (spi->mode & SPI_CPOL) ++ set_spi_clock_polarity(ingspi, 1); ++ else ++ set_spi_clock_polarity(ingspi, 0); ++ ++ if (!(spi->mode & SPI_LSB_FIRST)) { ++ set_tx_msb(ingspi); ++ set_rx_msb(ingspi); ++ } else { ++ set_tx_lsb(ingspi); ++ set_rx_lsb(ingspi); ++ } ++ ++ if (spi->mode & SPI_LOOP) ++ enable_loopback(ingspi); ++ else ++ disable_loopback(ingspi); ++ ++ /* chip enable selected */ ++ if (ingspi->set_cs && ingspi->pdata) ++ ingspi->set_cs(ingspi->pdata, spi->chip_select, cspol); ++ break; ++ default: ++ break; ++ } ++} ++ ++static void ingenic_spi_clk_enable(struct ingenic_spi *ingspi) { ++ if(ingspi->clk_flag == 0) ++ return; ++ ++ clk_set_rate(ingspi->clk_cgu, ingspi->max_clk); ++ clk_prepare_enable(ingspi->clk_cgu); ++ clk_prepare_enable(ingspi->clk_gate); ++ ingspi->clk_flag = 0; ++} ++ ++static void ingenic_spi_clk_disable(struct ingenic_spi *ingspi) { ++ if(ingspi->clk_flag) ++ return; ++ ++ clk_disable_unprepare(ingspi->clk_cgu); ++ clk_disable_unprepare(ingspi->clk_gate); ++ ingspi->clk_flag = 1; ++} ++ ++static unsigned long ingenic_spi_clk_get_rate(struct spi_device *spi) ++{ ++ struct ingenic_spi *ingspi = spi_master_get_devdata(spi->master); ++ unsigned long rate; ++ u16 cgv; ++ ++ spin_lock(&ingspi->lock); ++ rate = clk_get_rate(ingspi->clk_cgu); ++ cgv = spi_readl(ingspi, SSI_GR); ++ spin_unlock(&ingspi->lock); ++ return (rate / (2 * (cgv + 1))); ++} ++static int ingenic_spi_clk_set_rate(struct spi_device *spi, unsigned long rate) ++{ ++ struct ingenic_spi *ingspi = spi_master_get_devdata(spi->master); ++ unsigned long cur_rate; ++ unsigned long src_rate; ++ int cgv; ++ ++ cur_rate = ingenic_spi_clk_get_rate(spi); ++ if(cur_rate == rate) ++ return 0; ++ spin_lock(&ingspi->lock); ++ src_rate = clk_get_rate(ingspi->clk_cgu); ++ cgv = (src_rate / (rate * 2)) - 1; ++ if(cgv < 0) { ++ printk("spi clk set %ld not support, src_rate = %ld\n", rate, src_rate); ++ return -1; ++ } ++ /*printk("%s[%d]: clk_cgu = %ld, cur_rate = %d, rate = %ld, cgv = %d\n",__func__,__LINE__,src_rate, cur_rate, rate, cgv);*/ ++ spi_writel(ingspi, SSI_GR, cgv); ++ spin_unlock(&ingspi->lock); ++ return 0; ++} ++ ++static void dma_tx_callback(void *data) ++{ ++ struct ingenic_spi *ingspi = data; ++ ++ dma_unmap_sg(ingspi->txchan->device->dev, ingspi->sg_tx, 1, DMA_TO_DEVICE); ++ complete(&ingspi->done_tx_dma); ++} ++ ++static void dma_rx_callback(void *data) ++{ ++ struct ingenic_spi *ingspi = data; ++ ++ dma_unmap_sg(ingspi->txchan->device->dev, ingspi->sg_tx, 1, DMA_TO_DEVICE); ++ dma_unmap_sg(ingspi->rxchan->device->dev, ingspi->sg_rx, 1, DMA_FROM_DEVICE); ++ complete(&ingspi->done_rx_dma); ++} ++ ++/*extern void jzdma_dump(struct dma_chan *chan);*/ ++static int ingenic_spi_dma_txrx(struct spi_device *spi, struct spi_transfer *t) ++{ ++ int ret; ++ struct ingenic_spi *ingspi = spi_master_get_devdata(spi->master); ++ struct dma_slave_config rx_config, tx_config; ++ struct dma_async_tx_descriptor *rxdesc; ++ struct dma_async_tx_descriptor *txdesc; ++ struct dma_chan *rxchan = ingspi->rxchan; ++ struct dma_chan *txchan = ingspi->txchan; ++ struct ingenic_intr_cnt *g_ingenic_intr; ++ int dma_ds[] = {64, 32, 16, 4, 2, 1}; ++ int i; ++ ++// printk("%s[%d]: \n",__func__,__LINE__); ++ /* Check that the channels are available */ ++ if (!txchan || !rxchan) { ++ dev_err(&spi->dev, "no dma channel\n"); ++ return -ENODEV; ++ } ++ ++ if (t->len % ingspi->transfer_unit_size) { ++ pr_err("The length of tranfer data is error\n"); ++ return -EFAULT; ++ } ++ ++ ingspi->rw_mode = 0; ++ if(t->tx_buf) ++ ingspi->rw_mode |= W_MODE; ++ if(t->rx_buf) ++ ingspi->rw_mode |= R_MODE; ++ ++ /* all transfer starts with tx, ends with rx. */ ++ if (ingspi->rw_mode & W_MODE) ++ ingspi->tx = t->tx_buf; ++ else ++ ingspi->tx = ingspi->buffer; ++ ++ if (ingspi->rw_mode & R_MODE) ++ ingspi->rx = t->rx_buf; ++ else ++ ingspi->rx = ingspi->buffer; ++ ++ memset(ingspi->buffer, 0, BUFFER_SIZE); ++ ++ switch (ingspi->transfer_unit_size) { ++ case SPI_8BITS: ++ tx_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; ++ tx_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; ++ rx_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; ++ rx_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; ++ tx_config.dst_maxburst = 1; ++ tx_config.src_maxburst = 1; ++ rx_config.src_maxburst = 1; ++ rx_config.dst_maxburst = 1; ++ break; ++ case SPI_16BITS: ++ tx_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; ++ tx_config.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; ++ rx_config.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; ++ rx_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; ++ tx_config.dst_maxburst = 2; ++ tx_config.src_maxburst = 2; ++ rx_config.src_maxburst = 2; ++ rx_config.dst_maxburst = 2; ++ break; ++ case SPI_32BITS: ++ tx_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; ++ tx_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; ++ rx_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; ++ rx_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; ++ tx_config.dst_maxburst = 4; ++ tx_config.src_maxburst = 4; ++ rx_config.src_maxburst = 4; ++ rx_config.dst_maxburst = 4; ++ break; ++ } ++ ++ tx_config.dst_addr = (dma_addr_t)(ingspi->phys + SSI_DR); ++ rx_config.src_addr = (dma_addr_t)(ingspi->phys + SSI_DR); ++ ++ tx_config.direction = DMA_MEM_TO_DEV; ++ rx_config.direction = DMA_DEV_TO_MEM; ++ ++ dmaengine_slave_config(txchan, &tx_config); ++ dmaengine_slave_config(rxchan, &rx_config); ++ ++ /* set tx dma trigger */ ++ for (i = 0; i < ARRAY_SIZE(dma_ds); i++) { ++ if (t->len / dma_ds[i]) ++ break; ++ } ++ ++ if (i < ARRAY_SIZE(dma_ds)) { ++ ingspi->dma_tx_unit = dma_ds[i]; ++ } else { ++ print_dbg("DMA tx block_size force to defaut set!!!"); ++ ingspi->dma_tx_unit = INGENIC_SSI_DMA_BURST_LENGTH; ++ } ++ ++ ingspi->tx_trigger = ingspi->dma_tx_unit / (ingspi->txfifo_width >> 3); ++ //set_tx_trigger(ingspi, ingspi->tx_trigger); ++ set_tx_trigger(ingspi, 8); //The transfer is steady if the trigger number is used ++ print_dbg("t->len: %d, tx fifo width: %d, set tx trigger value to %d\n", t->len, ingspi->txfifo_width, ingspi->tx_trigger); ++ ++ sg_init_one(ingspi->sg_tx, ingspi->tx, t->len); ++ if (dma_map_sg(ingspi->txchan->device->dev, ++ ingspi->sg_tx, 1, DMA_TO_DEVICE) != 1) { ++ dev_err(&spi->dev, "dma_map_sg tx error\n"); ++ printk("%s LINE %d: %s\n", __func__, __LINE__, __FILE__); ++ goto err_tx_sgmap; ++ } ++ ++ txdesc = txchan->device->device_prep_slave_sg(txchan, ++ ingspi->sg_tx, ++ 1, ++ DMA_TO_DEVICE, ++ DMA_PREP_INTERRUPT | DMA_CTRL_ACK,NULL); ++ if (!txdesc) { ++ dev_err(&spi->dev, "device_prep_slave_sg error\n"); ++ printk("%s LINE %d: %s\n", __func__, __LINE__, __FILE__); ++ goto err_txdesc; ++ } ++ ++ // config controller ++ disable_tx_intr(ingspi); ++ disable_rx_intr(ingspi); ++ ++ //revisit ++ disable_tx_error_intr(ingspi); ++ disable_rx_error_intr(ingspi); ++ ++ start_transmit(ingspi); ++ //finish_transmit(ingspi); ++ ++ flush_fifo(ingspi); ++ ++// enable_receive(ingspi); ++ clear_errors(ingspi); ++ ++ g_ingenic_intr = ingspi->g_ingenic_intr; ++ memset(g_ingenic_intr, 0, sizeof *g_ingenic_intr); ++ ++ if (!(ingspi->rw_mode & R_MODE)) { ++ txdesc->callback = dma_tx_callback; ++ txdesc->callback_param = ingspi; ++ enable_tx_error_intr(ingspi); ++ ++ dmaengine_submit(txdesc); ++ dma_async_issue_pending(txchan); ++ ++ enable_receive(ingspi); ++ ret = wait_for_completion_interruptible_timeout(&ingspi->done_tx_dma, 60 * HZ); ++ if (ret <= 0) { ++ printk("The tx_dma umap wait timeout\n"); ++ goto err_txdesc; ++ } ++ ret = wait_for_completion_interruptible_timeout(&ingspi->done, 60 * HZ); ++ if (ret <= 0) { ++ printk("The spi transfer wait timeout\n"); ++ goto err_txdesc; ++ } ++ ++ if(t->cs_change) ++ finish_transmit(ingspi); ++ flush_rxfifo(ingspi); ++ clear_errors(ingspi); ++ ++ return t->len; ++ } ++ /* prepare spi dma rx */ ++ for (i = 0; i < ARRAY_SIZE(dma_ds); i++) { ++ if (!(t->len % dma_ds[i])) ++ break; ++ } ++ ++ if (i < ARRAY_SIZE(dma_ds)) { ++ ingspi->dma_rx_unit = dma_ds[i]; ++ } else { ++ print_dbg("DMA rx block_size force to defaut set!!!"); ++ ingspi->dma_rx_unit = INGENIC_SSI_DMA_BURST_LENGTH; ++ } ++ ++ ingspi->rx_trigger = ingspi->dma_rx_unit/(ingspi->rxfifo_width >> 3); ++ //set_rx_trigger(ingspi, ingspi->rx_trigger); ++ set_rx_trigger(ingspi, 1); //the rx trigger is steady for tranfer ++ print_dbg("t->len: %d, rx fifo width: %d, set rx trigger value to %d\n", t->len, ingspi->rxfifo_width, ingspi->rx_trigger); ++ ++ sg_init_one(ingspi->sg_rx, ingspi->rx, t->len); ++ ++ if (dma_map_sg(ingspi->rxchan->device->dev, ++ ingspi->sg_rx, 1, DMA_FROM_DEVICE) != 1) { ++ dev_err(&spi->dev, "dma_map_sg rx error\n"); ++ goto err_rx_sgmap; ++ } ++ ++ rxdesc = rxchan->device->device_prep_slave_sg(rxchan, ++ ingspi->sg_rx, ++ 1, ++ DMA_FROM_DEVICE, ++ DMA_PREP_INTERRUPT | DMA_CTRL_ACK,NULL); ++ if (!rxdesc) { ++ dev_err(&spi->dev, "device_prep_slave_sg error\n"); ++ goto err_rxdesc; ++ } ++ ++ txdesc->callback = NULL; ++ txdesc->callback_param = NULL; ++ ++ rxdesc->callback = dma_rx_callback; ++ rxdesc->callback_param = ingspi; ++ enable_rx_error_intr(ingspi); ++ enable_tx_error_intr(ingspi); ++ ++ dmaengine_submit(txdesc); ++ dmaengine_submit(rxdesc); ++ ++ dma_async_issue_pending(rxchan); ++ dma_async_issue_pending(txchan); ++ ++ enable_receive(ingspi); ++// dump_spi_reg(ingspi); ++ ret = wait_for_completion_interruptible_timeout(&ingspi->done_rx, 60 * HZ); ++ if (ret <= 0) { ++ dump_spi_reg(ingspi); ++ printk("The spi receiver wait timeout\n"); ++ goto err_rxdesc; ++ } ++ /*jzdma_dump(rxchan);*/ ++ /*printk("%s[%d]: wait dma\n",__func__,__LINE__);*/ ++ ret = wait_for_completion_interruptible_timeout(&ingspi->done_rx_dma, 60 * HZ); ++ if (ret <= 0) { ++ dump_spi_reg(ingspi); ++ printk("The spi dam_callback wait timeout\n"); ++ goto err_rxdesc; ++ } ++ finish_transmit(ingspi); ++ //flush_rxfifo(ingspi); ++ clear_errors(ingspi); ++ ++ return t->len; ++ ++err_rxdesc: ++ dma_unmap_sg(rxchan->device->dev, ingspi->sg_rx, 1, DMA_FROM_DEVICE); ++err_rx_sgmap: ++err_txdesc: ++ dma_unmap_sg(txchan->device->dev, ingspi->sg_tx, 1, DMA_TO_DEVICE); ++err_tx_sgmap: ++ printk("<< dma_txrx error. out of memory >>\n"); ++ return -ENOMEM; ++} ++ ++static irqreturn_t ingenic_spi_dma_irq_callback(struct ingenic_spi *ingspi) ++{ ++ struct ingenic_intr_cnt *g_ingenic_intr = ingspi->g_ingenic_intr; ++ print_dbg("%s: status register: %08x\n", __func__, spi_readl(ingspi, SSI_SR)); ++ ++ if (ssi_underrun(ingspi) && tx_error_intr(ingspi)) { ++ print_dbg("UNDR:\n"); ++ ++ g_ingenic_intr->ssi_eti++; ++ disable_tx_error_intr(ingspi); ++ ++ clear_errors(ingspi); ++ complete(&ingspi->done); ++ complete(&ingspi->done_rx); ++ ++ goto irq_done; ++ } ++ ++ if (ssi_overrun(ingspi) && rx_error_intr(ingspi)) { ++ print_dbg(" overrun:\n"); ++ g_ingenic_intr->ssi_eri++; ++ ++ clear_errors(ingspi); ++ complete(&ingspi->done); ++ complete(&ingspi->done_rx); ++ } ++ ++irq_done: ++ return IRQ_HANDLED; ++} ++ ++static inline u32 cpu_read_rxfifo(struct ingenic_spi *ingspi) ++{ ++ u8 unit_size = ingspi->transfer_unit_size; ++ u32 cnt, dat; ++ int dummy_read = 0; ++ ++ print_dbg("The count of RxFIFO is %d \n", get_rxfifo_count(ingspi)); ++ if (get_rxfifo_count(ingspi) < 1) ++ return 0; ++ ++ cnt = ingspi->rlen; ++ if ((ingspi->rw_mode & RW_MODE) == W_MODE) { ++ print_dbg("W_MODE\n"); ++ dummy_read = 1; ++ } ++ ++ spin_lock(&ingspi->lock); ++ ++ while (!rxfifo_empty(ingspi)) { ++ ingspi->rlen += unit_size; ++ if (dummy_read) ++ dat = spi_readl(ingspi, SSI_DR); ++ else ++ dat = ingspi->get_rx(ingspi); ++ } ++ ++ spin_unlock(&ingspi->lock); ++ ++ return (ingspi->rlen - cnt); ++} ++ ++static inline u32 cpu_write_txfifo(struct ingenic_spi *ingspi, u32 entries) ++{ ++ u8 unit_size = ingspi->transfer_unit_size; ++ u32 i, cnt, count; ++ u32 dat; ++ ++ if ((!entries ) || (!(ingspi->rw_mode & RW_MODE))) ++ return 0; ++ ++ cnt = entries; ++ count = cnt * unit_size; ++ ++ spin_lock(&ingspi->lock); ++ if (ingspi->rw_mode & W_MODE) { ++ for (i = 0; i < cnt; i++) { ++ ingspi->count += unit_size; ++ dat = (u32)(ingspi->get_tx(ingspi)); ++ } ++ } else { /* read, fill txfifo with 0 */ ++ for (i = 0; i < cnt; i++) { ++ ingspi->count += unit_size; ++ transmit_data(ingspi, 0); ++ } ++ } ++ spin_unlock(&ingspi->lock); ++ ++ print_dbg("ingspi->count:%d. %s LINE %d: %s\n", ingspi->count, __func__, __LINE__, __FILE__); ++ return count; ++} ++ ++static int ingenic_spi_cpu_transfer(struct ingenic_spi *ingspi, long length) ++{ ++ unsigned char int_flag = 0, last_flag = 0; ++ u32 entries = 0, send_entries = 0; ++ u32 unit_size, trigger; ++ long leave_len_bytes; ++ u32 retlen; ++ ++ print_dbg("%s LINE %d: %s\n", __func__, __LINE__, __FILE__); ++ ++ /* calculate the left entries */ ++ leave_len_bytes = ingspi->len - ingspi->count; ++ ++ if (ingspi->len < ingspi->count) { ++ dev_err(ingspi->dev, ++ "Fill data len error!!!(len : count > %d : %d)\n", ++ ingspi->len, ingspi->count); ++ return -1; ++ } ++ ++ if (leave_len_bytes == 0) { ++ print_dbg("leave_len_bytes = 0\n"); ++ printk("leave_len_bytes = 0\n"); ++ return 0; ++ } ++ ++ if (ingspi->len % ingspi->transfer_unit_size) { ++ pr_err("The length of tranfer data is error\n"); ++ return -EFAULT; ++ } ++ ++ unit_size = ingspi->transfer_unit_size; ++ if (unit_size == SPI_8BITS) ++ entries = leave_len_bytes; ++ else if (unit_size == SPI_16BITS ) ++ entries = leave_len_bytes >> 1; ++ else if (unit_size == SPI_32BITS ) ++ entries = leave_len_bytes >> 2; ++ else { ++ dev_err(ingspi->dev,"transfer_unit_size error!\n"); ++ return -1; ++ } ++ print_dbg("%s unit_size:%d, entries:%d\n", __func__, unit_size, entries); ++ ++ /* calculate the entries which will be sent currently ++ * distinguish between the first and interrupt */ ++ if (ingspi->is_first) { ++ /* CPU Mode should reset SSI triggers at first */ ++ ingspi->tx_trigger = SSI_TX_FIFO_THRESHOLD * 8; ++ ingspi->rx_trigger = (SSI_RX_FIFO_THRESHOLD - SSI_SAFE_THRESHOLD) * 8; ++ ++ set_tx_trigger(ingspi, ingspi->tx_trigger); ++ set_rx_trigger(ingspi, ingspi->rx_trigger); ++ ++ if(entries <= INGENIC_SSI_MAX_FIFO_ENTRIES) { ++ send_entries = entries; ++ } else { ++ /* need enable half_intr, left entries will be sent ++ in SSI interrupt and receive the datas */ ++ send_entries = INGENIC_SSI_MAX_FIFO_ENTRIES; ++ int_flag = 1; ++ } ++ start_transmit(ingspi); ++ ++ ingspi->is_first = 0; ++ } else { /* happen in interrupts */ ++ trigger = INGENIC_SSI_MAX_FIFO_ENTRIES - ingspi->tx_trigger; ++ if (entries <= trigger) { ++ send_entries = entries; ++ /* the last part of data shouldn't disable RXI_intr ++ at once !!! */ ++ last_flag = 1; ++ } else { ++ /* need enable half_intr, left entries will be sent ++ in SSI interrupt and receive the datas */ ++ send_entries = CPU_ONCE_BLOCK_ENTRIES; ++ int_flag = 1; ++ } ++ } ++ ++ if (length > 0) { ++ length = length/ingspi->transfer_unit_size; ++ if (length < send_entries) ++ send_entries = length; ++ } ++ ++ /* fill the txfifo with CPU Mode */ ++ retlen = cpu_write_txfifo(ingspi, send_entries); ++ if (!retlen) { ++ dev_info(ingspi->dev,"cpu_write_txfifo error!\n"); ++ return -1; ++ } ++ print_dbg("+:(%d)\n", retlen); ++ ++ enable_tx_error_intr(ingspi); ++ enable_rx_error_intr(ingspi); ++ ++ /* every time should control the SSI half_intrs */ ++ if (int_flag) { ++ enable_txfifo_half_empty_intr(ingspi); ++ enable_rxfifo_half_full_intr(ingspi); ++ } else { ++ disable_txfifo_half_empty_intr(ingspi); ++ disable_rxfifo_half_full_intr(ingspi); ++ } ++ ++ /* to avoid RxFIFO overflow when CPU Mode at last time to fill */ ++ if (last_flag) { ++ last_flag = 0; ++ enable_rxfifo_half_full_intr(ingspi); ++ } ++ ++#ifdef SSI_DEGUG ++ dump_spi_reg(ingspi); ++#endif ++ ++ return 0; ++} ++ ++static int ingenic_spi_pio_txrx(struct spi_device *spi, struct spi_transfer *t) ++{ ++ struct ingenic_spi *ingspi = spi_master_get_devdata(spi->master); ++ struct ingenic_intr_cnt *g_ingenic_intr = ingspi->g_ingenic_intr; ++ u32 entries; ++ int status; ++ unsigned long flags; ++ ++ ingspi->tx = t->tx_buf; ++ ingspi->rx = t->rx_buf; ++ ingspi->len = t->len; ++ ingspi->count = 0; ++ ingspi->rlen = 0; ++ ingspi->dma_flag &= ~SPI_DMA_ACK; ++ ++ ingspi->rw_mode = 0; ++ if(ingspi->tx) ++ ingspi->rw_mode |= W_MODE; ++ if(ingspi->rx) ++ ingspi->rw_mode |= R_MODE; ++ ++ disable_tx_intr(ingspi); ++ disable_rx_intr(ingspi); ++ ++ start_transmit(ingspi); ++ flush_fifo(ingspi); ++ ++ enable_receive(ingspi); ++ clear_errors(ingspi); ++ ++ memset(g_ingenic_intr, 0, sizeof(struct ingenic_intr_cnt)); ++ /* Calculate Max IRQ numbers for SSI error out */ ++ entries = ingspi->len * 8 / ingspi->bits_per_word; ++ g_ingenic_intr->max_ssi_intr = (entries + INGENIC_SSI_MAX_FIFO_ENTRIES - 1) / ++ INGENIC_SSI_MAX_FIFO_ENTRIES * 2 + 2; ++ ++#ifdef SSI_DEGUG ++ dump_spi_reg(ingspi); ++#endif ++ ++ /* This start SSI transfer, write data or 0 to txFIFO. ++ * irq is locked to protect SSI config registers */ ++ spin_lock_irqsave(&ingspi->txrx_lock, flags); ++ ingspi->is_first = 1; ++ status = ingenic_spi_cpu_transfer(ingspi, 0); ++ if (status < 0) { ++ dev_err(ingspi->dev,"ERROR:spi_transfer error(%d)!\n", status); ++ disable_tx_intr(ingspi); ++ disable_rx_intr(ingspi); ++ spin_unlock_irqrestore(&ingspi->txrx_lock, flags); ++ ++ return status; ++ } ++ spin_unlock_irqrestore(&ingspi->txrx_lock, flags); ++ ++ /* wait the interrupt finish the transfer( one spi_transfer be sent ) */ ++ wait_for_completion_interruptible(&ingspi->done); ++ ++ if(t->cs_change) ++ finish_transmit(ingspi); ++ clear_errors(ingspi); ++ ++ if (ingspi->rlen != t->len) { ++ dev_info(ingspi->dev, "Length error:ingspi->rlen=%d t->len=%d\n", ingspi->rlen,t->len); ++ ++ if(ingspi->rlen > ingspi->len) ++ ingspi->rlen = ingspi->len; ++ } ++ ++ return ingspi->rlen; ++} ++ ++static irqreturn_t ingenic_spi_pio_irq_callback(struct ingenic_spi *ingspi) ++{ ++ struct ingenic_intr_cnt *g_ingenic_intr = ingspi->g_ingenic_intr; ++ long left_count = ingspi->len - ingspi->count; ++ u8 flag = 0; ++ u32 cnt; ++ int status; ++ ++ g_ingenic_intr->ssi_intr_cnt++; ++ /* to avoid die in interrupt if some error occur */ ++ if (g_ingenic_intr->ssi_intr_cnt > g_ingenic_intr->max_ssi_intr) { ++ disable_tx_intr(ingspi); ++ disable_rx_intr(ingspi); ++ dev_err(ingspi->dev,"ssi interrupts too many count(%d)!\n", ++ g_ingenic_intr->ssi_intr_cnt); ++ ++ complete(&ingspi->done); ++ goto irq_done; ++ } ++ ++ if ( ssi_underrun(ingspi) && tx_error_intr(ingspi) ) { ++ print_dbg("UNDR:"); ++ g_ingenic_intr->ssi_eti++; ++ disable_tx_error_intr(ingspi); ++ ++ if(left_count == 0){ ++ cnt = cpu_read_rxfifo(ingspi); ++ print_dbg("-:(%d)\n",cnt); ++ ++ disable_tx_intr(ingspi); ++ disable_rx_intr(ingspi); ++ ++ complete(&ingspi->done); ++ } else { ++ clear_errors(ingspi); ++ enable_tx_error_intr(ingspi); ++ } ++ ++ flag++; ++ } ++ ++ if ( ssi_overrun(ingspi) && rx_error_intr(ingspi) ) { ++ print_dbg(" overrun:"); ++ g_ingenic_intr->ssi_eri++; ++ ++ cnt = cpu_read_rxfifo(ingspi); ++ print_dbg("-:(%d)\n",cnt); ++ ++ flag++; ++ } ++ ++ if ( rxfifo_half_full(ingspi) && ++ rxfifo_half_full_intr(ingspi)) { ++ ++ print_dbg("RXI:"); ++ g_ingenic_intr->ssi_rxi++; ++ ++ cnt = cpu_read_rxfifo(ingspi); ++ print_dbg("-:(%d)\n",cnt); ++ ++ flag++; ++ } ++ ++ if ( txfifo_half_empty_intr(ingspi) && ++ txfifo_half_empty(ingspi)) { ++ ++ print_dbg("TXI:"); ++ g_ingenic_intr->ssi_txi++; ++ ++ status = ingenic_spi_cpu_transfer(ingspi, 0); ++ if (status < 0) { ++ dev_err(ingspi->dev,"ingenic_spi_cpu_transfer error!!!!!\n"); ++ disable_tx_intr(ingspi); ++ disable_rx_intr(ingspi); ++ complete(&ingspi->done); ++ ++ goto irq_done; ++ } ++ flag++; ++ } ++ ++ if (!flag) { ++ dev_info(ingspi->dev, "\nERROR:SSI interrupt Type error\n"); ++ complete(&ingspi->done); ++ } ++ ++irq_done: ++ clear_errors(ingspi); ++ return IRQ_HANDLED; ++} ++ ++/* every spi_transfer could call this routine to setup itself */ ++static int ingenic_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t) ++{ ++ struct ingenic_spi *ingspi = spi_master_get_devdata(spi->master); ++ u8 bpw, fifo_width; ++ u32 hz; ++ int ret; ++ ++ /*printk("%s[%d]: \n",__func__,__LINE__);*/ ++ bpw = spi->bits_per_word; ++ hz = spi->max_speed_hz; ++ ++ if (t) { ++ if(t->bits_per_word) ++ bpw = t->bits_per_word; ++ if(t->speed_hz) ++ hz = t->speed_hz; ++ } ++ ++ if (bpw < 2 || bpw > 32) { ++ dev_err(&spi->dev, "invalid bits-per-word (%d)\n", bpw); ++ return -EINVAL; ++ } ++ ++ if (ingspi->use_dma) { ++ ingspi->txrx_bufs = &ingenic_spi_dma_txrx; ++ ingspi->irq_callback = &ingenic_spi_dma_irq_callback; ++ } else { ++ ingspi->txrx_bufs = &ingenic_spi_pio_txrx; ++ ingspi->irq_callback = &ingenic_spi_pio_irq_callback; ++ } ++ ++ ingspi->bits_per_word = bpw; ++ if (bpw <= 8) { ++ ingspi->transfer_unit_size = SPI_8BITS; ++ ingspi->get_rx = ingenic_spi_rx_buf_u8; ++ ingspi->get_tx = ingenic_spi_tx_buf_u8; ++ fifo_width = FIFO_W8; ++ } else if (bpw <= 16) { ++ ingspi->transfer_unit_size = SPI_16BITS; ++ ingspi->get_rx = ingenic_spi_rx_buf_u16; ++ ingspi->get_tx = ingenic_spi_tx_buf_u16; ++ fifo_width = FIFO_W16; ++ } else { ++ ingspi->transfer_unit_size = SPI_32BITS; ++ ingspi->get_rx = ingenic_spi_rx_buf_u32; ++ ingspi->get_tx = ingenic_spi_tx_buf_u32; ++ fifo_width = FIFO_W32; ++ } ++ ++ ingspi->txfifo_width = fifo_width; ++ ingspi->rxfifo_width = fifo_width; ++ set_frame_length(ingspi, fifo_width); ++ ++ if (spi->mode & SPI_LSB_FIRST) { ++ set_tx_lsb(ingspi); ++ set_rx_lsb(ingspi); ++ } else { ++ set_tx_msb(ingspi); ++ set_rx_msb(ingspi); ++ } ++ ++ if((ret = ingenic_spi_clk_set_rate(spi, hz))) ++ return ret; ++ ++ dev_dbg(&spi->dev, "The real SPI CLK is %ld Hz\n", ingenic_spi_clk_get_rate(spi)); ++ ++ mutex_lock(&ingspi->bitbang.lock); ++ if (!ingspi->bitbang.busy) { ++ ingspi->bitbang.chipselect(spi, BITBANG_CS_INACTIVE); ++ /* need to ndelay for 0.5 clocktick ? */ ++ } ++ mutex_unlock(&ingspi->bitbang.lock); ++ ++ return 0; ++} ++ ++static int ingenic_spi_setup(struct spi_device *spi) ++{ ++ struct ingenic_spi *ingspi = spi_master_get_devdata(spi->master); ++ unsigned long flags; ++ unsigned int frmhl = 0; ++ ++ spin_lock_irqsave(&ingspi->lock, flags); ++ if (ingspi->state & SUSPND) { ++ spin_unlock_irqrestore(&ingspi->lock, flags); ++ dev_err(&spi->dev, ++ "setup: SPI-%d not active!\n", spi->master->bus_num); ++ return -ESHUTDOWN; ++ } ++ spin_unlock_irqrestore(&ingspi->lock, flags); ++ ++ if (spi->chip_select >= spi->master->num_chipselect) { ++ dev_err(&spi->dev, "cs%d >= max %d\n", ++ spi->chip_select, ++ spi->master->num_chipselect); ++ return -EINVAL; ++ } ++ ++ if (spi->chip_select == 0) { ++ select_ce(ingspi); ++ frmhl = spi_readl(ingspi, SSI_CR1); ++ frmhl &= ~(1<<30); ++ frmhl |= (spi->mode & SPI_CS_HIGH ? 1 : 0) << 30; ++ spi_writel(ingspi, SSI_CR1, frmhl); ++ } else if (spi->chip_select == 1) { ++ select_ce2(ingspi); ++ frmhl = spi_readl(ingspi, SSI_CR1); ++ frmhl &= ~(1<<31); ++ frmhl |= (spi->mode & SPI_CS_HIGH ? 1 : 0) << 31; ++ spi_writel(ingspi, SSI_CR1, frmhl); ++ } else ++ return -EINVAL; ++ ++ if (!spi->bits_per_word) ++ spi->bits_per_word = 8; ++ ++ if (spi->mode & ~MODEBITS) { ++ dev_info(&spi->dev, "Warning: unsupported mode bits %x\n", ++ spi->mode & ~MODEBITS); ++ return -EINVAL; ++ } ++ ingspi->spi_mode = spi->mode; ++ ++ if (spi->mode & SPI_LSB_FIRST) { ++ set_tx_lsb(ingspi); ++ set_rx_lsb(ingspi); ++ } else { ++ set_tx_msb(ingspi); ++ set_rx_msb(ingspi); ++ } ++ ++ if (spi->bits_per_word & ~SPI_BITS_SUPPORT) { ++ dev_info(&spi->dev, "Warning: unsupported bits_per_word: %d\n", ++ spi->bits_per_word); ++ return -EINVAL; ++ } ++ ++ if (!spi->max_speed_hz) { ++ return -EINVAL; ++ } ++ ++ /*printk("%s[%d]: ingspi->max_clk = %ld, spi->max_speed_hz = %ld\n",__func__,__LINE__,ingspi->max_clk, spi->max_speed_hz);*/ ++ if (ingspi->max_clk < spi->max_speed_hz) { ++ dev_info(&spi->dev, "Warning:invalid clock(%d Hz) be set to source clk(%d Hz)!\n", ++ spi->max_speed_hz,(uint)ingspi->max_clk); ++ spi->max_speed_hz = ingspi->max_clk; ++ } ++ ++ mutex_lock(&ingspi->bitbang.lock); ++ if (!ingspi->bitbang.busy) { ++ ingspi->bitbang.chipselect(spi, BITBANG_CS_INACTIVE); ++ /* need to ndelay for 0.5 clocktick ? */ ++ } ++ mutex_unlock(&ingspi->bitbang.lock); ++ ++ return 0; ++} ++ ++/** ++ * ingenic_spi_txrx - functions which will handle transfer data ++ * @spi: spi device on which data transfer to be done ++ * @t: spi transfer in which transfer info is filled ++ * ++ * This function will put data to be transferred into data register ++ * of SPI controller and then wait until the completion will be marked ++ * by the IRQ Handler. ++ */ ++static int ingenic_spi_txrx(struct spi_device * spi, struct spi_transfer *t) ++{ ++ struct ingenic_spi *ingspi = spi_master_get_devdata(spi->master); ++ unsigned int ret; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ingspi->lock, flags); ++ if (ingspi->state & SUSPND) { ++ ingspi->state &= ~SPIBUSY; ++ spin_unlock_irqrestore(&ingspi->lock, flags); ++ printk("Now enter suspend, so cann't tranfer data\n"); ++ return -ESHUTDOWN; ++ } ++ ingspi->state |= SPIBUSY; ++ spin_unlock_irqrestore(&ingspi->lock, flags); ++ ++ ret = ingspi->txrx_bufs(spi, t); ++ ++ spin_lock_irqsave(&ingspi->lock, flags); ++ ingspi->state &= ~SPIBUSY; ++ spin_unlock_irqrestore(&ingspi->lock, flags); ++ return ret; ++} ++ ++static irqreturn_t ingenic_spi_irq(int irq, void *dev) ++{ ++ struct ingenic_spi *ingspi = dev; ++ ++ return ingspi->irq_callback(ingspi); ++} ++ ++static int ingenic_spi_init_setup(struct ingenic_spi *ingspi) ++{ ++ ingspi->clk_flag = 1; ++ ingenic_spi_clk_enable(ingspi); ++ ++ /* disable the SSI controller */ ++ ssi_disable(ingspi); ++ ++ /* set default half_intr trigger */ ++ ingspi->tx_trigger = SSI_TX_FIFO_THRESHOLD * 8; ++ ingspi->rx_trigger = SSI_RX_FIFO_THRESHOLD * 8; ++ set_tx_trigger(ingspi, ingspi->tx_trigger); ++ set_rx_trigger(ingspi, ingspi->rx_trigger); ++ ++ /* First,mask the interrupt, while verify the status ? */ ++ disable_tx_intr(ingspi); ++ disable_rx_intr(ingspi); ++ ++ disable_receive(ingspi); ++ ++ set_spi_clock_phase(ingspi, 0); ++ set_spi_clock_polarity(ingspi, 0); ++ set_tx_msb(ingspi); ++ set_rx_msb(ingspi); ++ ++ set_spi_format(ingspi); ++ set_frame_length(ingspi, 8); ++ disable_loopback(ingspi); ++ flush_fifo(ingspi); ++ ++ underrun_auto_clear(ingspi); ++ clear_errors(ingspi); ++ ssi_enable(ingspi); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_OF ++static struct ingenic_spi_info *ingenic_spi_parse_dt(struct ingenic_spi *ingspi) ++{ ++ struct ingenic_spi_info *isi; ++ struct device *dev = ingspi->dev; ++ unsigned int value; ++ int i; ++ isi = devm_kzalloc(dev, sizeof(*isi), GFP_KERNEL); ++ if (!isi) ++ return ERR_PTR(-ENOMEM); ++ ++ if(of_property_read_u32(dev->of_node, "spi-max-frequency", &value)) { ++ dev_warn(dev, "spi-max-frequency not specified\n"); ++ isi->max_clk = 0; ++ } else { ++ isi->max_clk = value; ++ } ++ ++ /*printk("%s[%d]: isi->max_clk = %ld\n",__func__,__LINE__, isi->max_clk);*/ ++ if(of_property_read_u32(dev->of_node, "ingenic,has_dma_support", &value)) { ++ dev_warn(dev, "spi-max-frequency not specified\n"); ++ ingspi->use_dma = 0; ++ } else { ++ ingspi->use_dma = value; ++ } ++ ++ if (of_property_read_u32(dev->of_node, "ingenic,chnl", &value)) { ++ dev_warn(dev, "ingenic,channel not specified\n"); ++ isi->chnl = 0; ++ } else { ++ isi->chnl = value; ++ } ++ ++ /*printk("%s[%d]: isi->chnl = %d\n",__func__,__LINE__, isi->chnl);*/ ++ if (of_property_read_u32(dev->of_node, "num-cs", &value)) { ++ dev_warn(dev, "num_cs not specified\n"); ++ isi->num_chipselect = 0; ++ } else { ++ isi->num_chipselect = value; ++ } ++ ++ /*printk("%s[%d]: isi->num_chipselect = %d\n",__func__,__LINE__, isi->num_chipselect);*/ ++ if (of_property_read_u32(dev->of_node, "ingenic,allow_cs_same", &value)) { ++ dev_warn(dev, "ingenic,allow_cs_same not specified\n"); ++ isi->allow_cs_same = 0; ++ } else { ++ isi->allow_cs_same = value; ++ } ++ ++ /*printk("%s[%d]: isi->allow_cs_same = %d\n",__func__,__LINE__, isi->allow_cs_same);*/ ++ if (of_property_read_u32(dev->of_node, "ingenic,bus_num", &value)) { ++ dev_warn(dev, "ingenic,bus_num not specified\n"); ++ isi->bus_num = 0; ++ } else { ++ isi->bus_num = value; ++ } ++ ++ /*printk("%s[%d]: isi->bus_num = %d\n",__func__,__LINE__, isi->bus_num);*/ ++ for (i = 0; i < isi->num_chipselect; i++) { ++ int cs_gpio = of_get_named_gpio(dev->of_node, "cs-gpios", i); ++ if (cs_gpio == -EPROBE_DEFER) { ++ break; ++ } ++ isi->chipselects[i] = cs_gpio; ++ /*printk("%s[%d]: cs%d is gpio = %d\n",__func__,__LINE__, i ,cs_gpio);*/ ++ if (gpio_is_valid(cs_gpio)) { ++ if (devm_gpio_request(dev, cs_gpio, "INGENIC_SPI_CS")) { ++ if(!isi->allow_cs_same) ++ dev_err(dev, "could not request %d gpio\n", cs_gpio); ++ } else if (gpio_direction_output(cs_gpio, 1)) ++ dev_err(dev, "could not set gpio %d as output\n", cs_gpio); ++ } ++ } ++ ++ return isi; ++} ++#else ++static struct ingenic_spi_info *ingenic_spi_parse_dt(struct device *dev) ++{ ++ return dev_get_platdata(dev); ++} ++#endif ++ ++static int ingenic_spi_clk_init(struct platform_device *pdev, struct ingenic_spi *ingspi) ++{ ++ struct clk *clk; ++ char clkname[16]; ++ int err = 0; ++ ++ pdev->id = of_alias_get_id(pdev->dev.of_node, "spi"); ++ sprintf(clkname, "gate_ssi%d", pdev->id); ++ ingspi->clk_gate = devm_clk_get(&pdev->dev, clkname); ++ ingspi->clk_cgu = devm_clk_get(&pdev->dev, "div_ssi"); ++ ++ if (IS_ERR(ingspi->clk_cgu) || IS_ERR(ingspi->clk_gate)) { ++ dev_err(&pdev->dev, "Cannot get spi clock\n"); ++ err = PTR_ERR(ingspi->clk_cgu); ++ return err; ++ } ++ return 0; ++} ++ ++static int ingenic_spi_configure_dma(struct ingenic_spi *ingspi) ++{ ++ struct device *dev = ingspi->dev; ++ dma_cap_mask_t mask; ++ int err = 0; ++ ++ dma_cap_zero(mask); ++ dma_cap_set(DMA_SLAVE, mask); ++ ++ ingspi->txchan = dma_request_slave_channel_reason(dev, "tx"); ++ if (IS_ERR(ingspi->txchan)) { ++ err = PTR_ERR(ingspi->txchan); ++ if (err == -EPROBE_DEFER) { ++ dev_warn(dev, "no DMA channel available at the moment\n"); ++ return err; ++ } ++ dev_err(dev, "DMA TX channel not available, SPI unable to use DMA\n"); ++ err = -EBUSY; ++ goto error; ++ } ++ ++ /* ++ * No reason to check EPROBE_DEFER here since we have already requested ++ * tx channel. If it fails here, it's for another reason. ++ */ ++ ingspi->rxchan = dma_request_slave_channel(dev, "rx"); ++ ++ if (!ingspi->rxchan) { ++ dev_err(dev, "DMA RX channel not available, SPI unable to use DMA\n"); ++ err = -EBUSY; ++ goto error; ++ } ++ ++ //alloc temp buffer for dma ++ ingspi->buffer = dma_alloc_coherent(dev, BUFFER_SIZE, ++ &ingspi->buffer_dma, GFP_KERNEL); ++ if (!ingspi->buffer) { ++ dev_err(dev, "SPI request temp dma buffer failed"); ++ goto error; ++ } ++ ++#if 0 ++ ingspi->buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL); ++ if (!ingspi->buffer) { ++ dev_err(dev, "SPI request temp dma buffer failed"); ++ goto error; ++ } ++ print_dbg("<< ingspi->buffer addr:%p >>\n", ingspi->buffer); ++#endif ++ ++ ingspi->sg_tx = devm_kmalloc(dev, sizeof(struct scatterlist), GFP_KERNEL); ++ if (!ingspi->sg_tx) { ++ dev_err(dev, "Failed to alloc tx scatterlist\n"); ++ goto error; ++ } ++ ++ ingspi->sg_rx = devm_kmalloc(dev, sizeof(struct scatterlist), GFP_KERNEL); ++ if(!ingspi->sg_rx) { ++ dev_err(dev, "Failed to alloc rx scatterlist\n"); ++ goto error; ++ } ++ ++ ++ dev_info(dev, "Using %s (tx) and %s (rx) for DMA transfers\n", ++ dma_chan_name(ingspi->txchan), ++ dma_chan_name(ingspi->rxchan)); ++ return 0; ++error: ++ if (ingspi->rxchan) ++ dma_release_channel(ingspi->rxchan); ++ if (!IS_ERR(ingspi->txchan)) ++ dma_release_channel(ingspi->txchan); ++ return err; ++} ++ ++static int ingenic_spi_probe(struct platform_device *pdev) ++{ ++ struct ingenic_spi *ingspi; ++ struct spi_master *master; ++ struct device_node *np = pdev->dev.of_node; ++ struct ingenic_spi_info *pdata = dev_get_platdata(&pdev->dev); ++ struct resource *res; ++ int err = 0; ++ ++ master = spi_alloc_master(&pdev->dev, sizeof(struct ingenic_spi)); ++ if (!master) { ++ dev_err(&pdev->dev, "Unable to allocate SPI Master\n"); ++ return -ENOMEM; ++ } ++ ++ /* the spi->mode bits understood by this drivers: */ ++ master->mode_bits = MODEBITS; ++ ++ ingspi = spi_master_get_devdata(master); ++ ingspi->g_ingenic_intr = devm_kzalloc(&pdev->dev, ++ sizeof(struct ingenic_intr_cnt),GFP_KERNEL); ++ if(!ingspi->g_ingenic_intr) { ++ dev_err(&pdev->dev, "No memory for ingenic_intr_cnt\n"); ++ return -ENOMEM; ++ } ++ ++ ingspi->master = spi_master_get(master); ++ ingspi->dev = &pdev->dev; ++ ++ if (!pdata && np) { ++ pdata = ingenic_spi_parse_dt(ingspi); ++ if (IS_ERR(pdata)) ++ return PTR_ERR(pdata); ++ } ++ ++ if (!pdata) { ++ dev_err(&pdev->dev, "platform_data missing!\n"); ++ return -ENODEV; ++ } ++ ++ ++ ingspi->pdata = pdata; ++ ingspi->chnl= ingspi->pdata->chnl; ++ master->bus_num = (s16)ingspi->pdata->bus_num; ++ if(master->bus_num != 0 && master->bus_num != 1){ ++ dev_err(&pdev->dev, "No this channel, bus_num= %d.\n", master->bus_num); ++ err = -ENOENT; ++ goto err_no_pdata; ++ } ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) { ++ dev_err(&pdev->dev, "Unable to get SPI MEM resource\n"); ++ return -ENXIO; ++ } ++ ingspi->phys = res->start; ++ ingspi->iomem = devm_ioremap_resource(&pdev->dev, res); ++ if (!ingspi->iomem) { ++ dev_err(&pdev->dev, "Cannot map IO\n"); ++ err = -ENXIO; ++ goto err_no_iomap; ++ } ++ ++ ingspi->irq = platform_get_irq(pdev, 0); ++ if (ingspi->irq <= 0) { ++ dev_err(&pdev->dev, "No IRQ specified\n"); ++ err = -ENOENT; ++ goto err_no_irq; ++ } ++ ++ ingenic_spi_clk_init(pdev, ingspi); ++ ++ ingspi->spi_clk = ingspi->pdata->src_clk; ++ ingspi->max_clk = ingspi->pdata->max_clk; ++ ++ platform_set_drvdata(pdev, ingspi); ++ init_completion(&ingspi->done); ++ init_completion(&ingspi->done_rx); ++ init_completion(&ingspi->done_tx_dma); ++ init_completion(&ingspi->done_rx_dma); ++ spin_lock_init(&ingspi->lock); ++ spin_lock_init(&ingspi->txrx_lock); ++ ++ master->bus_num = ingspi->pdata->bus_num; ++ master->num_chipselect = ingspi->pdata->num_chipselect; ++ master->dev.of_node = pdev->dev.of_node; ++ /* setup the state for the bitbang driver */ ++ ingspi->bitbang.master = ingspi->master; ++ ingspi->bitbang.setup_transfer = ingenic_spi_setupxfer; ++ ingspi->bitbang.chipselect = ingenic_spi_chipsel; ++ ingspi->bitbang.txrx_bufs = ingenic_spi_txrx; ++ ingspi->bitbang.master->setup = ingenic_spi_setup; ++ ingspi->fifodepth = INGENIC_SSI_MAX_FIFO_ENTRIES; ++ ingspi->set_cs = &ingenic_spi_cs; ++ ++ ingenic_spi_init_setup(ingspi); ++ ++ if (ingspi->use_dma) { ++ ingenic_spi_configure_dma(ingspi); ++ } ++ ++ /* request SSI irq */ ++ err = devm_request_irq(&pdev->dev, ingspi->irq, ingenic_spi_irq, 0, pdev->name, ingspi); ++ if (err) { ++ dev_err(&pdev->dev, "Cannot claim IRQ\n"); ++ goto err_register; ++ } ++ ++ dev_dbg(ingspi->dev, "bitbang at %p\n", &ingspi->bitbang); ++ ++ err = spi_bitbang_start(&ingspi->bitbang); ++ if (err) { ++ dev_err(&pdev->dev, "Failed to register SPI master ERR_NO:%d\n",err); ++ goto err_register; ++ } ++ ++ printk(KERN_INFO "INGENIC SSI Controller for SPI channel %d driver register\n",ingspi->chnl); ++ return 0; ++ ++err_register: ++ free_irq(ingspi->irq, ingspi); ++err_no_irq: ++ if(ingspi->clk_gate) ++ clk_put(ingspi->clk_gate); ++ if(ingspi->clk_cgu) ++ clk_put(ingspi->clk_cgu); ++ iounmap(ingspi->iomem); ++err_no_iomap: ++ release_resource(ingspi->ioarea); ++ kfree(ingspi->ioarea); ++#ifdef CONFIG_INGENIC_SPI_PIO_CE ++err_cs_gpio: ++ for (i = 0; i < num_cs_got; i++) ++ gpio_free(ingspi->pdata->chipselect[i]); ++#endif ++err_no_pdata: ++ spi_master_put(ingspi->master); ++ ++ return err; ++} ++ ++static int ingenic_spi_remove(struct platform_device *dev) ++{ ++ struct ingenic_spi *ingspi = platform_get_drvdata(dev); ++ ++ spi_master_put(ingspi->master); ++ spi_bitbang_stop(&ingspi->bitbang); ++ ++ platform_set_drvdata(dev, NULL); ++ ++ free_irq(ingspi->irq, ingspi); ++ iounmap(ingspi->iomem); ++ ++ ingenic_spi_clk_disable(ingspi); ++ clk_put(ingspi->clk_gate); ++ clk_put(ingspi->clk_cgu); ++ ++ release_resource(ingspi->ioarea); ++ kfree(ingspi->ioarea); ++ ++ /* release DMA channel */ ++ if (ingspi->rxchan) { ++ dma_release_channel(ingspi->rxchan); ++ } ++ if (ingspi->txchan) { ++ dma_release_channel(ingspi->txchan); ++ } ++ ++#ifdef CONFIG_INGENIC_SPI_PIO_CE ++ /* release chipselect gpio */ ++ { ++ int i; ++ for (i = 0; i < ingspi->pdata->num_chipselect; i++) ++ gpio_free(ingspi->pdata->chipselect[i]); ++ } ++#endif ++ ++ kfree(ingspi->g_ingenic_intr); ++ kfree(ingspi); ++ printk(KERN_INFO "INGENIC SSI Controller for SPI channel %d driver removed\n",ingspi->chnl); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int ingenic_spi_suspend(struct platform_device *pdev, pm_message_t msg) ++{ ++ struct ingenic_spi *ingspi = platform_get_drvdata(pdev); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ingspi->lock, flags); ++ ingspi->state |= SUSPND; ++ spin_unlock_irqrestore(&ingspi->lock, flags); ++ ++ while (ingspi->state & SPIBUSY) ++ printk("Now spi is busy, waitting!\n"); ++ ++ ingenic_spi_clk_disable(ingspi); ++ ++ return 0; ++} ++ ++static int ingenic_spi_resume(struct platform_device *pdev) ++{ ++ struct ingenic_spi *ingspi = platform_get_drvdata(pdev); ++ unsigned long flags; ++ ++ ingenic_spi_clk_enable(ingspi); ++ ++ spin_lock_irqsave(&ingspi->lock, flags); ++ ingspi->state &= ~SUSPND; ++ spin_unlock_irqrestore(&ingspi->lock, flags); ++ ++ return 0; ++} ++ ++#else ++#define ingenic_spi_suspend NULL ++#define ingenic_spi_resume NULL ++#endif ++ ++static const struct of_device_id ingenic_spi_match[] = { ++ { .compatible = "ingenic,spi", }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, ingenic_spi_match); ++ ++static struct platform_driver ingenic_spidrv = { ++ .probe = ingenic_spi_probe, ++ .remove = ingenic_spi_remove, ++ .suspend = ingenic_spi_suspend, ++ .resume = ingenic_spi_resume, ++ .driver = { ++ .name = "ingenic-spi", ++ .of_match_table = ingenic_spi_match, ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++module_platform_driver(ingenic_spidrv); ++ ++MODULE_ALIAS("ingenic_spi"); ++MODULE_AUTHOR("Bo Liu "); ++MODULE_DESCRIPTION("INGENIC SPI controller driver"); ++MODULE_LICENSE("GPL"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_spi_ingenic_spi.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_spi_ingenic_spi.h.patch new file mode 100644 index 00000000..73d80d52 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_spi_ingenic_spi.h.patch @@ -0,0 +1,682 @@ +diff -drupN a/drivers/spi/ingenic_spi.h b/drivers/spi/ingenic_spi.h +--- a/drivers/spi/ingenic_spi.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/spi/ingenic_spi.h 2022-06-09 05:02:33.000000000 +0300 +@@ -0,0 +1,678 @@ ++#ifndef __LINUX_SPI_JZ_H ++#define __LINUX_SPI_JZ_H ++ ++#include ++#include ++ ++struct ingenic_spi_info { ++ u8 chnl; /* the chanel of SSI controller */ ++ u16 bus_num; /* spi_master.bus_num */ ++ u8 src_clk; /* source clock: 1---sfcclk;0---exclk */ ++ unsigned long max_clk; ++ unsigned long board_size; /* spi_master.num_chipselect */ ++ struct spi_board_info *board_info; /* link to spi devices info */ ++ u32 num_chipselect; ++ u32 allow_cs_same; ++ unsigned int chipselects[2]; ++ ++ void (*set_cs)(struct ingenic_spi_info *spi, u8 cs,unsigned int pol); /* be defined by spi devices driver user */ ++ void (*pins_config)(void); /* configure spi function pins (CLK,DR,RT) by user if need. */ ++}; ++ ++/************************************************************************* ++ * SSI (Synchronous Serial Interface) ++ *************************************************************************/ ++/* n = 0, 1 (SSI0, SSI1) */ ++#define SSI_DR 0x000 ++#define SSI_CR0 0x004 ++#define SSI_CR1 0x008 ++#define SSI_SR 0x00C ++#define SSI_ITR 0x010 ++#define SSI_ICR 0x014 ++#define SSI_GR 0x018 ++#define SSI_RCNT 0x01C ++ ++/* SSI Data Register (SSI_DR) */ ++#define DR_GPC_BIT 0 ++#define DR_GPC_MASK (0x1ff << SSI_DR_GPC_BIT) ++ ++/* SSI Control Register 0 (SSI_CR0) */ ++#define CR0_TENDIAN_BIT 18 ++#define CR0_TENDIAN_MASK (3 << CR0_TENDIAN_BIT) ++#define CR0_RENDIAN_BIT 16 ++#define CR0_RENDIAN_MASK (3 << CR0_RENDIAN_BIT) ++#define CR0_SSIE (1 << 15) ++#define CR0_TIE (1 << 14) ++#define CR0_RIE (1 << 13) ++#define CR0_TEIE (1 << 12) ++#define CR0_REIE (1 << 11) ++#define CR0_LOOP (1 << 10) ++#define CR0_RFINE (1 << 9) ++#define CR0_RFINC (1 << 8) ++#define CR0_EACLRUN (1 << 7) /* hardware auto clear underrun when TxFifo no empty */ ++#define CR0_FSEL (1 << 6) ++#define CR0_VRCNT (1 << 4) ++#define CR0_TFMODE (1 << 3) ++#define CR0_TFLUSH (1 << 2) ++#define CR0_RFLUSH (1 << 1) ++#define CR0_DISREV (1 << 0) ++ ++/* SSI Control Register 1 (SSI_CR1) */ ++#define CR1_FRMHL_BIT 30 ++#define CR1_FRMHL_MASK (0x3 << CR1_FRMHL_BIT) ++#define CR1_FRMHL_CELOW_CE2LOW (0 << CR1_FRMHL_BIT) /* SSI_CE_ is low valid and SSI_CE2_ is low valid */ ++#define CR1_FRMHL_CEHIGH_CE2LOW (1 << CR1_FRMHL_BIT) /* SSI_CE_ is high valid and SSI_CE2_ is low valid */ ++#define CR1_FRMHL_CELOW_CE2HIGH (2 << CR1_FRMHL_BIT) /* SSI_CE_ is low valid and SSI_CE2_ is high valid */ ++#define CR1_FRMHL_CEHIGH_CE2HIGH (3 << CR1_FRMHL_BIT) /* SSI_CE_ is high valid and SSI_CE2_ is high valid */ ++#define CR1_TFVCK_BIT 28 ++#define CR1_TFVCK_MASK (0x3 << CR1_TFVCK_BIT) ++ #define CR1_TFVCK_0 (0 << CR1_TFVCK_BIT) ++ #define CR1_TFVCK_1 (1 << CR1_TFVCK_BIT) ++ #define CR1_TFVCK_2 (2 << CR1_TFVCK_BIT) ++ #define CR1_TFVCK_3 (3 << CR1_TFVCK_BIT) ++#define CR1_TCKFI_BIT 26 ++#define CR1_TCKFI_MASK (0x3 << CR1_TCKFI_BIT) ++ #define CR1_TCKFI_0 (0 << CR1_TCKFI_BIT) ++ #define CR1_TCKFI_1 (1 << CR1_TCKFI_BIT) ++ #define CR1_TCKFI_2 (2 << CR1_TCKFI_BIT) ++ #define CR1_TCKFI_3 (3 << CR1_TCKFI_BIT) ++#define CR1_ITFRM (1 << 24) ++#define CR1_UNFIN (1 << 23) ++#define CR1_FMAT_BIT 20 ++#define CR1_FMAT_MASK (0x3 << CR1_FMAT_BIT) ++ #define CR1_FMAT_SPI (0 << CR1_FMAT_BIT) /* Motorola¡¯s SPI format */ ++ #define CR1_FMAT_SSP (1 << CR1_FMAT_BIT) /* TI's SSP format */ ++ #define CR1_FMAT_MW1 (2 << CR1_FMAT_BIT) /* National Microwire 1 format */ ++ #define CR1_FMAT_MW2 (3 << CR1_FMAT_BIT) /* National Microwire 2 format */ ++#define CR1_TTRG_BIT 16 /* SSI1 TX trigger */ ++#define CR1_TTRG_MASK (0xf << CR1_TTRG_BIT) ++#define CR1_MCOM_BIT 12 ++#define CR1_MCOM_MASK (0xf << CR1_MCOM_BIT) ++// #define CR1_MCOM_BIT(NO) (##NO## << CR1_MCOM_BIT) /* N-bit command selected */ ++#define CR1_RTRG_BIT 8 /* SSI RX trigger */ ++#define CR1_RTRG_MASK (0xf << CR1_RTRG_BIT) ++#define CR1_FLEN_BIT 3 ++#define CR1_FLEN_MASK (0x1f << CR1_FLEN_BIT) ++ #define CR1_FLEN_2BIT (0x0 << CR1_FLEN_BIT) ++#define CR1_PHA (1 << 1) ++#define CR1_POL (1 << 0) ++ ++/* SSI Status Register (SSI_SR) */ ++#define SR_TFIFONUM_BIT 16 ++#define SR_TFIFONUM_MASK (0xff << SR_TFIFONUM_BIT) ++#define SR_RFIFONUM_BIT 8 ++#define SR_RFIFONUM_MASK (0xff << SR_RFIFONUM_BIT) ++#define SR_END (1 << 7) ++#define SR_BUSY (1 << 6) ++#define SR_TFF (1 << 5) ++#define SR_RFE (1 << 4) ++#define SR_TFHE (1 << 3) ++#define SR_RFHF (1 << 2) ++#define SR_UNDR (1 << 1) ++#define SR_OVER (1 << 0) ++ ++/* SSI Interval Time Control Register (SSI_ITR) */ ++#define ITR_CNTCLK (1 << 15) ++#define ITR_IVLTM_BIT 0 ++#define ITR_IVLTM_MASK (0x7fff << ITR_IVLTM_BIT) ++ ++ ++ ++#define R_MODE 0x1 ++#define W_MODE 0x2 ++#define RW_MODE (R_MODE | W_MODE) ++ ++#define R_DMA 0x4 ++#define W_DMA 0x8 ++#define RW_DMA (R_DMA |W_DMA) ++ ++#define SPI_DMA_ACK 0x1 ++ ++#define SPI_DMA_ERROR -3 ++#define SPI_CPU_ERROR -4 ++ ++#define SPI_COMPLETE 5 ++ ++#define INGENIC_SSI_MAX_FIFO_ENTRIES 128 ++#define INGENIC_SSI_DMA_BURST_LENGTH 16 ++ ++#define FIFO_W8 8 ++#define FIFO_W16 16 ++#define FIFO_W32 32 ++ ++#define SPI_BITS_8 8 ++#define SPI_BITS_16 16 ++#define SPI_BITS_32 32 ++ ++#define SPI_8BITS 1 ++#define SPI_16BITS 2 ++#define SPI_32BITS 4 ++ ++ ++/* tx rx threshold from 0x0 to 0xF */ ++#define SSI_FULL_THRESHOLD 0xF ++#define SSI_TX_FIFO_THRESHOLD 0x1 ++#define SSI_RX_FIFO_THRESHOLD (SSI_FULL_THRESHOLD - SSI_TX_FIFO_THRESHOLD) ++#define SSI_SAFE_THRESHOLD 0x1 ++ ++#define CPU_ONCE_BLOCK_ENTRIES ((SSI_FULL_THRESHOLD-SSI_TX_FIFO_THRESHOLD)*8) ++ ++#define MAX_SSI_INTR 10000 ++ ++#define MAX_SSICDR 63 ++#define MAX_CGV 255 ++ ++#define SSI_DMA_FASTNESS_CHNL 0 // SSI controller [n] FASTNESS when probe(); ++ ++#define JZ_NEW_CODE_TYPE ++ ++#define BUFFER_SIZE PAGE_SIZE ++ ++#define CONFIG_DMA_ENGINE 1 ++ ++#define SUSPND (1<<0) ++#define SPIBUSY (1<<1) ++#define RXBUSY (1<<2) ++#define TXBUSY (1<<3) ++ ++struct ingenic_spi { ++ /* bitbang has to be first */ ++ struct spi_bitbang bitbang; ++ struct clk *clk_gate; ++ struct clk *clk_cgu; ++ unsigned int clk_flag; ++ unsigned int set_clk_flag; ++ struct completion done; ++ struct completion done_rx; ++ struct completion done_tx_dma; ++ struct completion done_rx_dma; ++ ++ spinlock_t lock; ++ spinlock_t txrx_lock; ++ ++ unsigned int state; ++ ++ u8 chnl; ++ u8 rw_mode; ++ u8 spi_mode; ++ u8 use_dma; ++ u8 is_first; ++ ++ u8 bits_per_word; /*8 or 16 (or 32)*/ ++ u8 transfer_unit_size; /* 1 or 2 (or 4) */ ++ u8 tx_trigger; /* 0-128 */ ++ u8 rx_trigger; /* 0-128 */ ++ u8 dma_tx_unit; /* 1 or 2 or 4 or 16 or 32*/ ++ u8 dma_rx_unit; /* 1 or 2 or 4 or 16 or 32*/ ++ u8 txfifo_width; ++ u8 rxfifo_width; ++ u32 fifodepth; ++ ++ /* data buffers */ ++ const u8 *tx; ++ u8 *rx; ++ ++ /* temp buffers */ ++ void *buffer; ++ dma_addr_t buffer_dma; ++ ++ void __iomem *iomem; ++ unsigned long phys; ++ int irq; ++ u32 len; ++ u32 rlen; /* receive len */ ++ u32 count; /* sent count */ ++ u32 dma_flag; ++ ++ void (*set_cs)(struct ingenic_spi_info *spi, u8 cs, unsigned int pol); ++ ++ /* functions to deal with different size buffers */ ++ u32 (*get_rx) (struct ingenic_spi *); ++ u32 (*get_tx) (struct ingenic_spi *); ++ int (*txrx_bufs)(struct spi_device *spi, struct spi_transfer *t); ++ irqreturn_t (*irq_callback)(struct ingenic_spi *); ++ ++#ifdef CONFIG_DMA_ENGINE ++ struct dma_chan *txchan; ++ struct dma_chan *rxchan; ++ struct scatterlist *sg_rx; /* I/O scatter list */ ++ struct scatterlist *sg_tx; /* I/O scatter list */ ++#endif ++ ++ unsigned long max_clk; ++ unsigned long spi_clk; ++ ++ struct ingenic_intr_cnt *g_ingenic_intr; ++ ++ struct resource *ioarea; ++ struct spi_master *master; ++ struct device *dev; ++ struct ingenic_spi_info *pdata; ++// struct spi_board_info *pdata; ++}; ++ ++ ++struct ingenic_intr_cnt{ ++ int dma_tx_cnt; ++ int dma_rx_cnt; ++ int ssi_intr_cnt; ++ int max_ssi_intr; ++ int ssi_txi; ++ int ssi_rxi; ++ int ssi_eti; ++ int ssi_eri; ++ int ssi_rlen; ++ int dma_tx_err; ++ int dma_tx_end; ++ int dma_rx_err; ++ int dma_rx_end; ++}; ++/* the max number of spi devices */ ++#define MAX_SPI_DEVICES 10 ++#define MAX_SPI_HOST 2 ++ ++#define INGENIC_SPI_ID_INVALID(ssi_id) ( ((ssi_id) < 0) || ((ssi_id) > (MAX_SPI_HOST - 1)) ) ++ ++#define MAX_SPI_CHIPSELECT_NUM MAX_GPIO_NUM ++ ++ ++static inline void spi_writel(struct ingenic_spi *spi, unsigned short offset, u32 value) ++{ ++ writel(value, spi->iomem + offset); ++} ++ ++static inline u32 spi_readl(struct ingenic_spi *spi, ++ unsigned short offset) ++{ ++ return readl(spi->iomem + offset); ++} ++ ++static inline void set_frmhl(struct ingenic_spi *spi, unsigned int frmhl) ++{ ++ u32 tmp; ++ tmp = spi_readl(spi, SSI_CR1); ++ tmp = (tmp & ~CR1_FRMHL_MASK) | frmhl; ++ spi_writel(spi, SSI_CR1, tmp); ++} ++ ++static inline void set_spi_clock_phase(struct ingenic_spi *spi, unsigned int cpha) ++{ ++ u32 tmp; ++ tmp = spi_readl(spi, SSI_CR1); ++ tmp = (tmp & ~CR1_PHA) | (cpha ? CR1_PHA : 0); ++ spi_writel(spi, SSI_CR1, tmp); ++} ++ ++static inline void set_spi_clock_polarity(struct ingenic_spi *spi, ++ unsigned int cpol) ++{ ++ u32 tmp; ++ tmp = spi_readl(spi, SSI_CR1); ++ tmp = (tmp & ~CR1_POL) | (cpol ? CR1_POL : 0); ++ spi_writel(spi, SSI_CR1, tmp); ++} ++ ++static inline void set_tx_msb(struct ingenic_spi *spi) ++{ ++ u32 tmp; ++ tmp = spi_readl(spi, SSI_CR0); ++ tmp &= ~CR0_TENDIAN_MASK; ++ spi_writel(spi, SSI_CR0, tmp); ++} ++ ++static inline void set_tx_lsb(struct ingenic_spi *spi) ++{ ++ u32 tmp; ++ tmp = spi_readl(spi, SSI_CR0); ++ tmp |= (tmp & ~CR0_TENDIAN_MASK) | (0x2 << CR0_TENDIAN_BIT); ++ spi_writel(spi, SSI_CR0, tmp); ++} ++ ++static inline void set_rx_msb(struct ingenic_spi *spi) ++{ ++ u32 tmp; ++ tmp = spi_readl(spi, SSI_CR0); ++ tmp &= ~CR0_RENDIAN_MASK; ++ spi_writel(spi, SSI_CR0, tmp); ++} ++ ++static inline void set_rx_lsb(struct ingenic_spi *spi) ++{ ++ u32 tmp; ++ tmp = spi_readl(spi, SSI_CR0); ++ tmp |= (tmp & ~CR0_RENDIAN_MASK) | (0x2 << CR0_RENDIAN_BIT); ++ spi_writel(spi, SSI_CR0, tmp); ++} ++ ++static inline void enable_loopback(struct ingenic_spi *spi) ++{ ++ u32 tmp; ++ tmp = spi_readl(spi, SSI_CR0); ++ tmp |= CR0_LOOP; ++ spi_writel(spi, SSI_CR0, tmp); ++} ++ ++static inline void disable_loopback(struct ingenic_spi *spi) ++{ ++ u32 tmp; ++ tmp = spi_readl(spi, SSI_CR0); ++ tmp &= ~CR0_LOOP; ++ spi_writel(spi, SSI_CR0, tmp); ++} ++ ++static inline void transmit_data(struct ingenic_spi *spi, u32 value) ++{ ++ spi_writel(spi, SSI_DR, value); ++} ++ ++static inline void set_frame_length(struct ingenic_spi *spi, u32 len) ++{ ++ u32 tmp; ++ tmp = spi_readl(spi, SSI_CR1); ++ tmp = (tmp & ~CR1_FLEN_MASK) | (((len) - 2) << CR1_FLEN_BIT); ++ spi_writel(spi, SSI_CR1, tmp); ++} ++ ++static inline void set_tx_trigger(struct ingenic_spi *spi, u32 val) ++{ ++ u32 tmp; ++ tmp = spi_readl(spi, SSI_CR1); ++ tmp = (tmp & ~CR1_TTRG_MASK) | ((val)/8) << CR1_TTRG_BIT; ++ spi_writel(spi, SSI_CR1, tmp); ++} ++ ++static inline void set_rx_trigger(struct ingenic_spi *spi, u32 val) ++{ ++ u32 tmp; ++ tmp = spi_readl(spi, SSI_CR1); ++ tmp = (tmp & ~CR1_RTRG_MASK) | ((val)/8) << CR1_RTRG_BIT; ++ spi_writel(spi, SSI_CR1, tmp); ++} ++ ++static inline void enable_txfifo_half_empty_intr(struct ingenic_spi *spi) ++{ ++ u32 tmp; ++ tmp = spi_readl(spi, SSI_CR0); ++ tmp |= CR0_TIE; ++ spi_writel(spi, SSI_CR0, tmp); ++} ++ ++static inline void disable_txfifo_half_empty_intr(struct ingenic_spi *spi) ++{ ++ u32 tmp; ++ tmp = spi_readl(spi, SSI_CR0); ++ tmp &= ~CR0_TIE; ++ spi_writel(spi, SSI_CR0, tmp); ++} ++ ++static inline void enable_rxfifo_half_full_intr(struct ingenic_spi *spi) ++{ ++ u32 tmp; ++ tmp = spi_readl(spi, SSI_CR0); ++ tmp |= CR0_RIE; ++ spi_writel(spi, SSI_CR0, tmp); ++} ++ ++static inline void disable_rxfifo_half_full_intr(struct ingenic_spi *spi) ++{ ++ u32 tmp; ++ tmp = spi_readl(spi, SSI_CR0); ++ tmp &= ~CR0_RIE; ++ spi_writel(spi, SSI_CR0, tmp); ++} ++ ++static inline void enable_tx_intr(struct ingenic_spi *spi) ++{ ++ u32 tmp; ++ tmp = spi_readl(spi, SSI_CR0); ++ tmp |= CR0_TIE | CR0_TEIE; ++ spi_writel(spi, SSI_CR0, tmp); ++} ++ ++static inline void disable_tx_intr(struct ingenic_spi *spi) ++{ ++ u32 tmp; ++ tmp = spi_readl(spi, SSI_CR0); ++ tmp &= ~(CR0_TIE | CR0_TEIE); ++ spi_writel(spi, SSI_CR0, tmp); ++} ++ ++static inline void enable_rx_intr(struct ingenic_spi *spi) ++{ ++ u32 tmp; ++ tmp = spi_readl(spi, SSI_CR0); ++ tmp |= CR0_RIE | CR0_REIE; ++ spi_writel(spi, SSI_CR0, tmp); ++} ++ ++static inline void disable_rx_intr(struct ingenic_spi *spi) ++{ ++ u32 tmp; ++ tmp = spi_readl(spi, SSI_CR0); ++ tmp &= ~(CR0_RIE | CR0_REIE); ++ spi_writel(spi, SSI_CR0, tmp); ++} ++ ++static inline void enable_tx_error_intr(struct ingenic_spi *spi) ++{ ++ u32 tmp; ++ tmp = spi_readl(spi, SSI_CR0); ++ tmp |= CR0_TEIE; ++ spi_writel(spi, SSI_CR0, tmp); ++} ++ ++static inline void disable_tx_error_intr(struct ingenic_spi *spi) ++{ ++ u32 tmp; ++ tmp = spi_readl(spi, SSI_CR0); ++ tmp &= ~CR0_TEIE; ++ spi_writel(spi, SSI_CR0, tmp); ++} ++ ++static inline void enable_rx_error_intr(struct ingenic_spi *spi) ++{ ++ u32 tmp; ++ tmp = spi_readl(spi, SSI_CR0); ++ tmp |= CR0_REIE; ++ spi_writel(spi, SSI_CR0, tmp); ++} ++ ++static inline void disable_rx_error_intr(struct ingenic_spi *spi) ++{ ++ u32 tmp; ++ tmp = spi_readl(spi, SSI_CR0); ++ tmp &= ~CR0_REIE; ++ spi_writel(spi, SSI_CR0, tmp); ++} ++ ++static inline void underrun_auto_clear(struct ingenic_spi *spi) ++{ ++ u32 tmp; ++ tmp = spi_readl(spi, SSI_CR0); ++ tmp |= CR0_EACLRUN; ++ spi_writel(spi, SSI_CR0, tmp); ++} ++ ++static inline void clear_errors(struct ingenic_spi *spi) ++{ ++ u32 tmp; ++ tmp = spi_readl(spi, SSI_SR); ++ tmp &= ~(SR_UNDR | SR_OVER); ++ spi_writel(spi, SSI_SR, tmp); ++} ++ ++static inline void set_spi_format(struct ingenic_spi *spi) ++{ ++ u32 tmp; ++ tmp = spi_readl(spi, SSI_CR1); ++ tmp &= ~CR1_FMAT_MASK; ++ tmp |= CR1_FMAT_SPI; ++ tmp &= ~(CR1_TFVCK_MASK | CR1_TCKFI_MASK); ++ tmp |= (CR1_TFVCK_0 | CR1_TCKFI_0); ++// tmp |= (CR1_TFVCK_1 | CR1_TCKFI_1); ++// tmp |= (CR1_TFVCK_2 | CR1_TCKFI_2); ++// tmp |= (CR1_TFVCK_3 | CR1_TCKFI_3); ++ spi_writel(spi, SSI_CR1, tmp); ++} ++ ++static inline void enable_receive(struct ingenic_spi *spi) ++{ ++ u32 tmp; ++ tmp = spi_readl(spi, SSI_CR0); ++ tmp &= ~CR0_DISREV; ++ spi_writel(spi, SSI_CR0, tmp); ++} ++ ++static inline void disable_receive(struct ingenic_spi *spi) ++{ ++ u32 tmp; ++ tmp = spi_readl(spi, SSI_CR0); ++ tmp |= CR0_DISREV; ++ spi_writel(spi, SSI_CR0, tmp); ++} ++ ++static inline void flush_fifo(struct ingenic_spi *spi) ++{ ++ u32 tmp; ++ tmp = spi_readl(spi, SSI_CR0); ++ tmp |= CR0_TFLUSH | CR0_RFLUSH; ++ spi_writel(spi, SSI_CR0, tmp); ++} ++ ++static inline void finish_transmit(struct ingenic_spi *spi) ++{ ++ u32 tmp; ++ tmp = spi_readl(spi, SSI_CR1); ++ tmp &= ~CR1_UNFIN; ++ spi_writel(spi, SSI_CR1, tmp); ++} ++ ++static inline void start_transmit(struct ingenic_spi *spi) ++{ ++ u32 tmp; ++ tmp = spi_readl(spi, SSI_CR1); ++ tmp |= CR1_UNFIN; ++ spi_writel(spi, SSI_CR1, tmp); ++} ++ ++static inline int rxfifo_empty(struct ingenic_spi *spi) ++{ ++ return spi_readl(spi, SSI_SR) & SR_RFE; ++} ++ ++static inline int ssi_busy(struct ingenic_spi *spi) ++{ ++ return spi_readl(spi, SSI_SR) & SR_BUSY; ++} ++ ++static inline void ssi_disable(struct ingenic_spi *spi) ++{ ++ u32 tmp; ++ tmp = spi_readl(spi, SSI_CR0); ++ tmp &= ~CR0_SSIE; ++ spi_writel(spi, SSI_CR0, tmp); ++} ++ ++static inline void ssi_enable(struct ingenic_spi *spi) ++{ ++ u32 tmp; ++ tmp = spi_readl(spi, SSI_CR0); ++ tmp |= CR0_SSIE; ++ spi_writel(spi, SSI_CR0, tmp); ++} ++ ++static inline u32 get_rxfifo_count(struct ingenic_spi *spi) ++{ ++ return (spi_readl(spi, SSI_SR) & SR_RFIFONUM_MASK) >> SR_RFIFONUM_BIT; ++} ++ ++static inline void flush_txfifo(struct ingenic_spi *spi) ++{ ++ u32 tmp; ++ tmp = spi_readl(spi, SSI_CR0); ++ tmp |= CR0_TFLUSH; ++ spi_writel(spi, SSI_CR0, tmp); ++} ++ ++static inline void flush_rxfifo(struct ingenic_spi *spi) ++{ ++ u32 tmp; ++ tmp = spi_readl(spi, SSI_CR0); ++ tmp |= CR0_RFLUSH; ++ spi_writel(spi, SSI_CR0, tmp); ++} ++ ++static inline int ssi_underrun(struct ingenic_spi *spi) ++{ ++ return spi_readl(spi, SSI_SR) & SR_UNDR; ++} ++ ++static inline int ssi_overrun(struct ingenic_spi *spi) ++{ ++ return spi_readl(spi, SSI_SR) & SR_OVER; ++} ++ ++static inline int ssi_transfer_end(struct ingenic_spi *spi) ++{ ++ return spi_readl(spi, SSI_SR) & SR_END; ++} ++ ++static inline int tx_error_intr(struct ingenic_spi *spi) ++{ ++ return spi_readl(spi, SSI_CR0) & CR0_TEIE; ++} ++ ++static inline int rx_error_intr(struct ingenic_spi *spi) ++{ ++ return spi_readl(spi, SSI_CR0) & CR0_REIE; ++} ++ ++static inline int rxfifo_half_full(struct ingenic_spi *spi) ++{ ++ return spi_readl(spi, SSI_SR) & SR_RFHF; ++} ++ ++static inline int txfifo_half_empty(struct ingenic_spi *spi) ++{ ++ return spi_readl(spi, SSI_SR) & SR_TFHE; ++} ++ ++static inline int txfifo_half_empty_intr(struct ingenic_spi *spi) ++{ ++ return spi_readl(spi, SSI_CR0) & CR0_TIE; ++} ++ ++static inline int rxfifo_half_full_intr(struct ingenic_spi *spi) ++{ ++ return spi_readl(spi, SSI_CR0) & CR0_RIE; ++} ++ ++static inline void select_ce(struct ingenic_spi *spi) ++{ ++ u32 tmp; ++ tmp = spi_readl(spi, SSI_CR0); ++ tmp &= ~CR0_FSEL; ++ spi_writel(spi, SSI_CR0, tmp); ++} ++ ++static inline void select_ce2(struct ingenic_spi *spi) ++{ ++ u32 tmp; ++ tmp = spi_readl(spi, SSI_CR0); ++ tmp |= CR0_FSEL; ++ spi_writel(spi, SSI_CR0, tmp); ++} ++ ++static inline void dump_spi_reg(struct ingenic_spi *spi) ++{ ++// printk("SSI_DR :%08x\n", spi_readl(spi, SSI_DR )); ++ printk("SSI_CR0 :%08x\n", spi_readl(spi, SSI_CR0 )); ++ printk("SSI_CR1 :%08x\n", spi_readl(spi, SSI_CR1 )); ++ printk("SSI_SR :%08x\n", spi_readl(spi, SSI_SR )); ++ printk("SSI_ITR :%08x\n", spi_readl(spi, SSI_ITR )); ++ printk("SSI_ICR :%08x\n", spi_readl(spi, SSI_ICR )); ++ printk("SSI_GR :%08x\n", spi_readl(spi, SSI_GR )); ++ printk("SSI_RCNT:%08x\n", spi_readl(spi, SSI_RCNT)); ++} ++ ++#endif /* __LINUX_SPI_JZ_H */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_tty_serial_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_tty_serial_Kconfig.patch new file mode 100644 index 00000000..c198c1ac --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_tty_serial_Kconfig.patch @@ -0,0 +1,80 @@ +diff -drupN a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig +--- a/drivers/tty/serial/Kconfig 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/tty/serial/Kconfig 2022-06-09 05:02:34.000000000 +0300 +@@ -262,7 +262,7 @@ config SERIAL_SAMSUNG_UARTS + help + Select the number of available UART ports for the Samsung S3C + serial driver +- ++ + config SERIAL_SAMSUNG_DEBUG + bool "Samsung SoC serial debug" + depends on SERIAL_SAMSUNG && DEBUG_LL +@@ -680,8 +680,8 @@ config PDC_CONSOLE + depends on PARISC && !SERIAL_MUX && VT + default n + help +- Saying Y here will enable the software based PDC console to be +- used as the system console. This is useful for machines in ++ Saying Y here will enable the software based PDC console to be ++ used as the system console. This is useful for machines in + which the hardware based console has not been written yet. The + following steps must be completed to use the PDC console: + +@@ -872,7 +872,7 @@ config SERIAL_CPM + depends on CPM2 || CPM1 + select SERIAL_CORE + help +- This driver supports the SCC and SMC serial ports on Motorola ++ This driver supports the SCC and SMC serial ports on Motorola + embedded PowerPC that contain a CPM1 (8xx) or CPM2 (8xxx) + + config SERIAL_CPM_CONSOLE +@@ -1629,6 +1629,47 @@ config SERIAL_STM32_CONSOLE + depends on SERIAL_STM32=y + select SERIAL_CORE_CONSOLE + ++config SERIAL_INGENIC_UART ++ tristate "ingenic serial port support" ++ select SERIAL_CORE ++ help ++ If you have a machine based on a xbrust mips soc you can ++ enable its onboard serial port by enabling this option. ++ ++config SERIAL_INGENIC_CONSOLE ++ bool "Console on ingenic soc and compatible serial port" ++ depends on SERIAL_INGENIC_UART=y ++ select SERIAL_CORE_CONSOLE ++ ---help--- ++ If you say Y here, it will be possible to use a serial port as the ++ system console (the system console is the device which receives all ++ kernel messages and warnings and which allows logins in single user ++ mode). This could be useful if some terminal or printer is connected ++ to that serial port. ++ ++ Even if you say Y here, the currently visible virtual console ++ (/dev/tty0) will still be used as the system console by default, but ++ you can alter that using a kernel command line option such as ++ "console=ttyS1". (Try "man bootparam" or see the documentation of ++ your boot loader (grub or lilo or loadlin) about how to pass options ++ to the kernel at boot time.) ++ ++ If you don't have a VGA card installed and you say Y here, the ++ kernel will automatically use the first serial line, /dev/ttyS0, as ++ system console. ++ ++ If unsure, say N. ++ ++config SERIAL_INGENIC_LARGE_BAUDRATE ++ bool "ingenic baudrate add support greater than 1M" ++ depends on SERIAL_INGENIC_UART=y ++ default y ++ ++config SERIAL_INGENIC_MAGIC_SYSRQ ++ bool "ingenic uart enable Magic SysRq key" ++ depends on MAGIC_SYSRQ=y && SERIAL_INGENIC_UART=y ++ default n ++ + endmenu + + config SERIAL_MCTRL_GPIO diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_tty_serial_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_tty_serial_Makefile.patch new file mode 100644 index 00000000..b922a393 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_tty_serial_Makefile.patch @@ -0,0 +1,11 @@ +diff -drupN a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile +--- a/drivers/tty/serial/Makefile 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/tty/serial/Makefile 2022-06-09 05:02:34.000000000 +0300 +@@ -4,6 +4,7 @@ + + obj-$(CONFIG_SERIAL_CORE) += serial_core.o + obj-$(CONFIG_SERIAL_21285) += 21285.o ++obj-$(CONFIG_SERIAL_INGENIC_UART) += ingenic_uart.o + + obj-$(CONFIG_SERIAL_EARLYCON) += earlycon.o + obj-$(CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST) += earlycon-arm-semihost.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_tty_serial_ingenic_uart.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_tty_serial_ingenic_uart.c.patch new file mode 100644 index 00000000..871dc1ed --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_tty_serial_ingenic_uart.c.patch @@ -0,0 +1,1222 @@ +diff -drupN a/drivers/tty/serial/ingenic_uart.c b/drivers/tty/serial/ingenic_uart.c +--- a/drivers/tty/serial/ingenic_uart.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/tty/serial/ingenic_uart.c 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,1218 @@ ++/* ++ * Based on drivers/serial/8250.c by Russell King. ++ * ++ * Author: Nicolas Pitre ++ * Created: Feb 20, 2003 ++ * Copyright: (C) 2003 Monta Vista Software, Inc. ++ * ++ * 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. ++ * ++ * Note 1: This driver is made separate from the already too overloaded ++ * 8250.c because it needs some kirks of its own and that'll make it ++ * easier to add DMA support. ++ * ++ * Note 2: I'm too sick of device allocation policies for serial ports. ++ * If someone else wants to request an "official" allocation of major/minor ++ * for this driver please be my guest. And don't forget that new hardware ++ * to come from Intel might have more than 3 or 4 of those UARTs. Let's ++ * hope for a better port registration and dynamic device allocation scheme ++ * with the serial core maintainer satisfaction to appear soon. ++ */ ++ ++ ++#if defined(CONFIG_SERIAL_INGENIC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) ++#define SUPPORT_SYSRQ ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ingenic_uart.h" ++ ++#define PORT_NR 10 ++#define DMA_BUFFER 1024 ++#define COUNT_DMA_BUFFER 2048 ++static unsigned short quot1[3] = {0}; /* quot[0]:baud_div, quot[1]:umr, quot[2]:uacr */ ++struct uart_ingenic_port { ++ struct uart_port port; ++ unsigned char ier; ++ unsigned char lcr; ++ unsigned char mcr;/* just store bit status of MDCE and FCM in UART_MCR */ ++ unsigned char old_mcr; /* store the old value of UART_MCR */ ++ unsigned int lsr_break_flag; ++ struct clk *clk; ++ char name[16]; ++ ++#ifdef CONFIG_DEBUG_FS ++ struct dentry *debugfs; ++#endif ++}; ++static inline void check_modem_status(struct uart_ingenic_port *up); ++static unsigned short *serial47xx_get_divisor(struct uart_port *port, unsigned int baud); ++static inline void serial_dl_write(struct uart_port *up, int value); ++ ++static struct baudtoregs_t ++{ ++ unsigned int baud; ++ unsigned short div; ++ unsigned int umr:5; ++ unsigned int uacr:12; ++} baudtoregs[] = { ++ /* ++ The data is generated by a python, ++ the script is tools/tty/get_divisor.py ++ */ ++ #if (CONFIG_EXTAL_CLOCK == 24) ++ {50,0x7530,0x10,0x0}, ++ {75,0x4e20,0x10,0x0}, ++ {110,0x3521,0x10,0x0}, ++ {134,0x2b9d,0x10,0x0}, ++ {150,0x2710,0x10,0x0}, ++ {200,0x1d4c,0x10,0x0}, ++ {300,0x1388,0x10,0x0}, ++ {600,0x9c4,0x10,0x0}, ++ {1200,0x4e2,0x10,0x0}, ++ {1800,0x340,0x10,0x0}, ++ {2400,0x271,0x10,0x0}, ++ {4800,0x138,0x10,0x0}, ++ {9600,0x9c,0x10,0x0}, ++ {19200,0x4e,0x10,0x0}, ++ {38400,0x27,0x10,0x0}, ++ {57600,0x1a,0x10,0x0}, ++ {115200,0xd,0x10,0x0}, ++ {230400,0x6,0x11,0x252}, ++ {460800,0x3,0x11,0x252}, ++ {500000,0x3,0x10,0x0}, ++ {576000,0x3,0xd,0xfef}, ++ {921600,0x2,0xd,0x0}, ++ {1000000,0x2,0xc,0x0}, ++ {1152000,0x1,0x14,0xefb}, ++ {1500000,0x1,0x10,0x0}, ++ {2000000,0x1,0xc,0x0}, ++ {2500000,0x1,0x9,0x6b5}, ++ {3000000,0x1,0x8,0x0}, ++ {3500000,0x1,0x6,0xbf7}, ++ {4000000,0x1,0x6,0x0}, ++#elif (CONFIG_EXTAL_CLOCK == 26) ++ {50,0x7ef4,0x10,0x0}, ++ {75,0x546b,0x10,0x0}, ++ {110,0x398f,0x10,0x0}, ++ {134,0x2f40,0x10,0x0}, ++ {150,0x2a36,0x10,0x0}, ++ {200,0x1fbd,0x10,0x0}, ++ {300,0x151b,0x10,0x0}, ++ {600,0xa8e,0x10,0x0}, ++ {1200,0x547,0x10,0x0}, ++ {1800,0x385,0x10,0x0}, ++ {2400,0x2a4,0x10,0x0}, ++ {4800,0x152,0x10,0x0}, ++ {9600,0xa9,0x10,0x0}, ++ {19200,0x54,0x10,0x2}, ++ {38400,0x2a,0x10,0x2}, ++ {57600,0x1c,0x10,0x2}, ++ {115200,0xe,0x10,0x2}, ++ {230400,0x7,0x10,0x2}, ++ {460800,0x4,0xe,0x2}, ++ {500000,0x3,0x11,0x550}, ++ {576000,0x3,0xf,0x2}, ++ {921600,0x2,0xe,0x2}, ++ {1000000,0x2,0xd,0x0}, ++ {1152000,0x2,0xb,0x248}, ++ {1500000,0x1,0x11,0x550}, ++ {2000000,0x1,0xd,0x0}, ++ {2500000,0x1,0xa,0x2a0}, ++ {3000000,0x1,0x8,0x700}, ++ {3500000,0x1,0x7,0x2a0}, ++ {4000000,0x1,0x6,0x7c0}, ++#elif (CONFIG_EXTAL_CLOCK == 48) ++ {50,0xea60,0x10,0x0}, ++ {75,0x9c40,0x10,0x0}, ++ {110,0x6a42,0x10,0x0}, ++ {134,0x573a,0x10,0x0}, ++ {150,0x4e20,0x10,0x0}, ++ {200,0x3a98,0x10,0x0}, ++ {300,0x2710,0x10,0x0}, ++ {600,0x1388,0x10,0x0}, ++ {1200,0x9c4,0x10,0x0}, ++ {1800,0x67f,0x10,0x0}, ++ {2400,0x4e2,0x10,0x0}, ++ {4800,0x271,0x10,0x0}, ++ {9600,0x138,0x10,0x0}, ++ {19200,0x9c,0x10,0x0}, ++ {38400,0x4e,0x10,0x0}, ++ {57600,0x34,0x10,0x0}, ++ {115200,0x1a,0x10,0x0}, ++ {230400,0xd,0x10,0x0}, ++ {460800,0x6,0x11,0x550}, ++ {500000,0x6,0x10,0x0}, ++ {576000,0x5,0x10,0x700}, ++ {921600,0x3,0x11,0x550}, ++ {1000000,0x3,0x10,0x0}, ++ {1152000,0x3,0xd,0x0}, ++ {1500000,0x2,0x10,0x0}, ++ {2000000,0x2,0xc,0x0}, ++ {2500000,0x1,0x13,0x84}, ++ {3000000,0x1,0x10,0x0}, ++ {3500000,0x1,0xd,0x600}, ++ {4000000,0x1,0xc,0x0}, ++#endif ++}; ++ ++/* ++*Function:read register ++*Parameter:struct uart_ingenic_port *up, int offset ++*Return:unsigned int:Register address ++*/ ++static inline unsigned int serial_in(struct uart_ingenic_port *up, int offset) ++{ ++ offset <<= 2; ++ return readl(up->port.membase + offset); ++} ++ ++/* ++*Function:write register ++*Parameter:struct uart_ingenic_port *up, int offset,int value:write value ++*Return:void ++*/ ++static inline void serial_out(struct uart_ingenic_port *up, int offset, int value) ++{ ++ offset <<= 2; ++ writel(value, up->port.membase + offset); ++} ++ ++/* ++*Function: Enable Modem status interrupt ++*Parameter:struct uart_ingenic_port ++*Return:void ++*/ ++static void serial_ingenic_enable_ms(struct uart_port *port) ++{ ++ struct uart_ingenic_port *up = (struct uart_ingenic_port *)port; ++ ++ up->ier |= UART_IER_MSI;// Enable Modem status interrupt ++ serial_out(up, UART_IER, up->ier); ++} ++ ++/* ++*Function:stop transmitting ++*Parameter:struct uart_ingenic_port ++*Return:void ++*/ ++static void serial_ingenic_stop_tx(struct uart_port *port) ++{ ++ struct uart_ingenic_port *up = (struct uart_ingenic_port *)port; ++ ++ if (up->ier & UART_IER_THRI) { ++ up->ier &= ~UART_IER_THRI;// Disable the transmit data request interrupt ++ serial_out(up, UART_IER, up->ier); ++ } ++} ++ ++/* ++*Function:stop receiving ++*Parameter:struct uart_ingenic_port *up ++*Return:void ++*/ ++static void serial_ingenic_stop_rx(struct uart_port *port) ++{ ++ struct uart_ingenic_port *up = (struct uart_ingenic_port *)port; ++ ++ up->ier &= ~UART_IER_RLSI; ++ up->port.read_status_mask &= ~UART_LSR_DR; ++ serial_out(up, UART_IER, up->ier); ++} ++ ++/* ++*Function:receive char ++*Parameter:unsigned long data,unsigned int status ++*Return:void ++*/ ++static inline void receive_chars(unsigned long data) ++{ ++ struct uart_ingenic_port *up = (struct uart_ingenic_port *)data; ++ struct tty_struct *tty = up->port.state->port.tty; ++ unsigned int ch, flag; ++ int max_count = 256; ++ unsigned int status= serial_in(up, UART_LSR); ++ while ((status & UART_LSR_DR) && (max_count-- > 0)) ++ //ready to receive data and max_count>0 ++ { ++ ch = serial_in(up, UART_RX);//read RX_Register ++ flag = TTY_NORMAL;// TTY_NORMAL=0 ++ up->port.icount.rx++; ++ ++#ifdef CONFIG_SERIAL_INGENIC_MAGIC_SYSRQ ++ /* Test SYSRQ */ ++ if((status == 0xe1) && ch == 0x00) { ++ if (uart_handle_break(&up->port)) ++ goto ignore_char; ++ } ++#endif ++ /* Break interrupt error | prrity error | Frame error | overun error */ ++ if (unlikely(status & (UART_LSR_BI | UART_LSR_PE | ++ UART_LSR_FE | UART_LSR_OE))) { ++ if (status & UART_LSR_BI) { ++ status &= ~(UART_LSR_FE | UART_LSR_PE); ++ up->port.icount.brk++; ++ /* ++ * We do the SysRQ and SAK checking ++ * here because otherwise the break ++ * may get masked by ignore_status_mask ++ * or read_status_mask. ++ */ ++ if (uart_handle_break(&up->port)) ++ goto ignore_char; ++ } else if (status & UART_LSR_PE) ++ up->port.icount.parity++; ++ else if (status & UART_LSR_FE) ++ up->port.icount.frame++; ++ if (status & UART_LSR_OE) ++ up->port.icount.overrun++; ++ /* ++ * Mask off conditions which should be ignored. ++ */ ++ status &= up->port.read_status_mask; ++ ++#ifdef CONFIG_SERIAL_INGENIC_CONSOLE ++ if (up->port.line == up->port.cons->index) { ++ /* Recover the break flag from console xmit */ ++ status |= up->lsr_break_flag; ++ up->lsr_break_flag = 0; ++ } ++#endif ++#ifdef CONFIG_SERIAL_INGENIC_MAGIC_SYSRQ ++ if (status == 0xe1) { ++ printk("handling break ....!\n"); ++#else ++ if (status & UART_LSR_BI) { ++#endif ++ flag = TTY_BREAK; ++ } else if (status & UART_LSR_PE) ++ flag = TTY_PARITY; ++ else if (status & UART_LSR_FE) ++ flag = TTY_FRAME; ++ } ++#ifdef CONFIG_SERIAL_INGENIC_MAGIC_SYSRQ ++ if (uart_handle_sysrq_char(&up->port, ch)) ++ goto ignore_char; ++#endif ++ uart_insert_char(&up->port, status, UART_LSR_OE, ch, flag); ++ ++ignore_char: ++ status = serial_in(up, UART_LSR); ++ } ++ tty_flip_buffer_push(tty->port); ++} ++/* transmit one char*/ ++static void transmit_chars(struct uart_ingenic_port *up) ++{ ++ struct circ_buf *xmit = &up->port.state->xmit; ++ int count; ++ if (up->port.x_char) { ++ serial_out(up, UART_TX, up->port.x_char);//transmit char=port.x_char ++ up->port.icount.tx++; ++ up->port.x_char = 0;//transmit finish x_char=0 ++ return; ++ } ++ if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {//xmit is empty or stop tx ++ serial_ingenic_stop_tx(&up->port); ++ return; ++ } ++ ++ /* try to tx char until xmit is empty or count=0*/ ++ count = up->port.fifosize / 2; ++ do { ++ serial_out(up, UART_TX, xmit->buf[xmit->tail]); ++ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); ++ up->port.icount.tx++; ++ if (uart_circ_empty(xmit)) ++ break; ++ } while (--count > 0); ++ ++ /*if circ_chars is less than WARKUP_CHARS,then warkup */ ++ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)//get the renainder of circ_chars ++ uart_write_wakeup(&up->port); ++ ++ if (uart_circ_empty(xmit)) ++ serial_ingenic_stop_tx(&up->port); ++} ++ ++static void serial_ingenic_start_tx(struct uart_port *port) ++{ ++ struct uart_ingenic_port *up = (struct uart_ingenic_port *)port; ++ ++ if (!(up->ier & UART_IER_THRI)) { ++ up->ier |= UART_IER_THRI; ++ serial_out(up, UART_IER, up->ier); ++ } ++} ++ ++static inline void check_modem_status(struct uart_ingenic_port *up) ++{ ++ int status; ++ status = serial_in(up, UART_MSR); ++ ++ if ((status & UART_MSR_ANY_DELTA) == 0) ++ return; ++ ++ if (status & UART_MSR_DCTS) ++ uart_handle_cts_change(&up->port, status & UART_MSR_CTS); ++ ++ wake_up_interruptible(&up->port.state->port.delta_msr_wait); ++} ++/* ++ * This handles the interrupt from one port. ++ */ ++static inline irqreturn_t serial_ingenic_irq(int irq, void *dev_id) ++{ ++ struct uart_ingenic_port *up = dev_id; ++ unsigned int iir, lsr; ++ iir = serial_in(up, UART_IIR); ++ lsr = serial_in(up, UART_LSR); ++ if (iir & UART_IIR_NO_INT) ++ return IRQ_NONE; ++ ++ if (lsr & UART_LSR_DR) ++ receive_chars((unsigned long)up); ++ check_modem_status(up); ++ if (lsr & UART_LSR_THRE) ++ transmit_chars(up); ++ return IRQ_HANDLED; ++} ++ ++static unsigned int serial_ingenic_tx_empty(struct uart_port *port) ++{ ++ struct uart_ingenic_port *up = (struct uart_ingenic_port *)port; ++ unsigned long flags; ++ unsigned int ret; ++ ++ spin_lock_irqsave(&up->port.lock, flags); ++ ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0; ++ spin_unlock_irqrestore(&up->port.lock, flags); ++ ++ return ret; ++} ++ ++/*get modem control*/ ++static unsigned int serial_ingenic_get_mctrl(struct uart_port *port) ++{ ++ struct uart_ingenic_port *up = (struct uart_ingenic_port *)port; ++ unsigned char status; ++ unsigned int ret; ++ ++ status = serial_in(up, UART_MSR); ++ ++ ret = 0; ++ if (status & UART_MSR_CTS) ++ ret |= TIOCM_CTS; ++ return ret; ++} ++ ++static void serial_ingenic_set_mctrl(struct uart_port *port, unsigned int mctrl) ++{ ++ struct uart_ingenic_port *up = (struct uart_ingenic_port *)port; ++ unsigned char mcr = 0; ++ int is_auto_rts = up->mcr & UART_MCR_FCM; ++ int is_mctrl_enabled = up->mcr & UART_MCR_MDCE; ++ ++ if (!is_mctrl_enabled) { ++ mcr = up->mcr; ++ up->old_mcr = mcr; ++ ++ serial_out(up, UART_MCR, mcr); ++ return; ++ } ++ ++ mcr |= UART_MCR_MDCE; ++ ++ /* ++ * If bit ITIOCM_RTS is cleared, force RTS to high whether auto RTS ++ * is enabled or not, which is: in UMCR, MDCE bit set to 1, bit FCM ++ * set to 0, and bit RTS set to 0. ++ */ ++ if (mctrl & TIOCM_RTS) { ++ if (is_auto_rts) ++ mcr |= UART_MCR_FCM; ++ else ++ mcr |= UART_MCR_RTS; ++ } ++ if (mctrl & TIOCM_LOOP) ++ mcr |= UART_MCR_LOOP; ++ ++ if (mcr == up->old_mcr) ++ return; ++ ++ up->old_mcr = mcr; ++ serial_out(up, UART_MCR, mcr); ++} ++ ++static void serial_ingenic_break_ctl(struct uart_port *port, int break_state) ++{ ++ struct uart_ingenic_port *up = (struct uart_ingenic_port *)port; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&up->port.lock, flags); ++ if (break_state == -1) ++ up->lcr |= UART_LCR_SBC; ++ else ++ up->lcr &= ~UART_LCR_SBC; ++ serial_out(up, UART_LCR, up->lcr); ++ spin_unlock_irqrestore(&up->port.lock, flags); ++} ++ ++static int serial_ingenic_startup(struct uart_port *port) ++{ ++ struct uart_ingenic_port *up = (struct uart_ingenic_port *)port; ++ unsigned long flags; ++ int retval; ++ ++ /* ++ * Allocate the IRQ ++ */ ++ retval = request_irq(port->irq, serial_ingenic_irq, 0, up->name, up); ++ if (retval) ++ return retval; ++ ++ /* ++ * Clear the FIFO buffers and disable them. ++ * (they will be reenabled in set_termios()) ++ */ ++ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); ++ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO ++ | UART_FCR_CLEAR_RCVR ++ | UART_FCR_CLEAR_XMIT ++ | UART_FCR_UME); ++ serial_out(up, UART_FCR, 0); ++ ++ /* ++ * Clear the interrupt registers. ++ */ ++ (void) serial_in(up, UART_LSR); ++ (void) serial_in(up, UART_RX); ++ (void) serial_in(up, UART_IIR); ++ (void) serial_in(up, UART_MSR); ++ ++ /* ++ * Now, initialize the UART ++ */ ++ serial_out(up, UART_LCR, UART_LCR_WLEN8); ++ serial_out(up, UART_ISR, 0); ++ ++ spin_lock_irqsave(&up->port.lock, flags); ++ spin_unlock_irqrestore(&up->port.lock, flags); ++ ++ /* ++ * Finally, enable interrupts. Note: Modem status interrupts ++ * are set via set_termos(), which will be occurring imminently ++ * anyway, so we don't enable them here. ++ */ ++ up->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE; ++ serial_out(up, UART_IER, up->ier); ++ ++ /* ++ * And clear the interrupt registers again for luck. ++ */ ++ (void) serial_in(up, UART_LSR); ++ (void) serial_in(up, UART_RX); ++ (void) serial_in(up, UART_IIR); ++ (void) serial_in(up, UART_MSR); ++ ++ return 0; ++} ++ ++static void serial_ingenic_shutdown(struct uart_port *port) ++{ ++ struct uart_ingenic_port *up = (struct uart_ingenic_port *)port; ++ unsigned long flags; ++ int tries; ++ ++ /* ++ * Disable interrupts from this port ++ */ ++ spin_lock_irqsave(&port->lock, flags); ++ up->ier = 0; ++ serial_out(up, UART_IER, 0); ++ ++ spin_unlock_irqrestore(&port->lock, flags); ++ ++ /* ++ * Wait the RX FIFO to be read. ++ */ ++ for (tries = 3; (serial_in(up, UART_RCR) != 0) && tries; tries--) { ++ printk(KERN_WARNING "%s: waiting RX FIFO to be read\n", up->name); ++ msleep(10); ++ } ++ if (!tries) ++ printk(KERN_ERR "%s: RX FIFO hasn't been read before clearing\n", ++ up->name); ++ ++ /* ++ * Disable break condition and FIFOs ++ */ ++ serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC); ++ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO ++ | UART_FCR_CLEAR_RCVR ++ | UART_FCR_CLEAR_XMIT ++ | UART_FCR_UME); ++ ++ free_irq(port->irq, up); ++} ++ ++static void init_hw_stopped_status(struct uart_port *uport) ++{ ++ struct tty_port tport = uport->state->port; ++ struct tty_struct *tty = tport.tty; ++ ++ if (tport.flags & ASYNC_CTS_FLOW) { ++ unsigned int mctrl; ++ spin_lock_irq(&uport->lock); ++ if (!((mctrl = uport->ops->get_mctrl(uport)) & TIOCM_CTS)) ++ tty->hw_stopped = 1; ++ else ++ tty->hw_stopped = 0; ++ spin_unlock_irq(&uport->lock); ++ } ++} ++ ++static void serial_ingenic_set_termios(struct uart_port *port, struct ktermios *termios,struct ktermios *old) ++{ ++ struct uart_ingenic_port *up = (struct uart_ingenic_port *)port; ++ unsigned char cval=0; ++ unsigned long flags; ++ unsigned int baud; ++ unsigned short *quot1; ++ ++ switch (termios->c_cflag & CSIZE) { ++ case CS5: ++ cval = UART_LCR_WLEN5; ++ break; ++ case CS6: ++ cval = UART_LCR_WLEN6; ++ break; ++ case CS7: ++ cval = UART_LCR_WLEN7; ++ break; ++ default: ++ case CS8: ++ cval = UART_LCR_WLEN8; ++ break; ++ } ++ ++ if (termios->c_cflag & CSTOPB){ ++ cval |= UART_LCR_STOP; ++ } ++ if (termios->c_cflag & PARENB){ ++ cval |= UART_LCR_PARITY; ++ } ++ if (!(termios->c_cflag & PARODD)){ ++ cval |= UART_LCR_EPAR; ++ } ++ serial_out(up, UART_LCR, cval);//write cval to UART_LCR ++ /* ++ * Ask the core to calculate the divisor for us. ++ */ ++ baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk);//get BaudRate ++ quot1 = serial47xx_get_divisor(port, baud); ++ /* ++ * Ok, we're now changing the port state. Do it with ++ * interrupts disabled. ++ */ ++ spin_lock_irqsave(&up->port.lock, flags); ++ /* ++ * Update the per-port timeout. ++ */ ++ uart_update_timeout(port, termios->c_cflag, baud); ++ up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; ++ if (termios->c_iflag & INPCK) ++ up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; ++ if (termios->c_iflag & (BRKINT | PARMRK)) ++ up->port.read_status_mask |= UART_LSR_BI; ++ ++ /* ++ * Characters to ignore ++ */ ++ up->port.ignore_status_mask = 0; ++ if (termios->c_iflag & IGNPAR) ++ up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; ++ if (termios->c_iflag & IGNBRK) { ++ up->port.ignore_status_mask |= UART_LSR_BI; ++ /* ++ * If we're ignoring parity and break indicators, ++ * ignore overruns too (for real raw support). ++ */ ++ if (termios->c_iflag & IGNPAR) ++ up->port.ignore_status_mask |= UART_LSR_OE; ++ } ++ ++ /* ++ * ignore all characters if CREAD is not set ++ */ ++ if ((termios->c_cflag & CREAD) == 0) ++ up->port.ignore_status_mask |= UART_LSR_DR; ++ ++ /* ++ * CTS flow control flag and modem status interrupts ++ */ ++ up->ier &= ~UART_IER_MSI; ++ /* ++ *enable modem status interrupts and enable modem function and control by hardware ++ */ ++ if (UART_ENABLE_MS(&up->port, termios->c_cflag)) { ++ up->ier |= UART_IER_MSI; ++ serial_out(up, UART_IER, up->ier); ++ up->mcr |= UART_MCR_MDCE | UART_MCR_FCM; ++ } ++ /* ++ *disable modem status interrupts and clear MCR bits of modem function and control by hardware ++ */ ++ else { ++ up->ier &= ~UART_IER_MSI; ++ serial_out(up, UART_IER, up->ier); ++ up->mcr &= ~(UART_MCR_MDCE | UART_MCR_FCM); ++ } ++ ++ serial_dl_write(port, quot1[0]); ++ serial_out(up,UART_UMR, quot1[1]);//UART send or receive one bit takes quot1[1] cycles ++ serial_out(up,UART_UACR, quot1[2]); ++ ++ up->lcr = cval; /* Save LCR */ ++ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_11 | UART_FCR_UME); ++ ++ serial_ingenic_set_mctrl(port, up->port.mctrl); ++ spin_unlock_irqrestore(&up->port.lock, flags); ++ ++ init_hw_stopped_status(port); ++} ++ ++static inline void serial_dl_write(struct uart_port *up, int value) ++{ ++ struct uart_ingenic_port *port = (struct uart_ingenic_port*)up; ++ int lcr = serial_in(port,UART_LCR); ++ serial_out(port,UART_LCR, UART_LCR_DLAB); ++ serial_out(port,UART_DLL, value & 0xff); ++ serial_out(port,UART_DLM, (value >> 8 )& 0xff); ++ serial_out(port,UART_LCR, lcr); ++} ++ ++ ++static int uart_setting_baud(const void *key,const void *elt) ++{ ++ unsigned long *d = (unsigned long*)key; ++ struct baudtoregs_t *b = (struct baudtoregs_t *)elt; ++ if(*d > b->baud) ++ return 1; ++ else if(*d < b->baud) ++ return -1; ++ return 0; ++} ++ ++static struct baudtoregs_t *search_divisor(unsigned int baud) ++{ ++ struct baudtoregs_t *b = NULL; ++ ++ if(baud <= baudtoregs[ARRAY_SIZE(baudtoregs) - 1].baud) ++ b = (struct baudtoregs_t *)bsearch((const void*)&baud,(const void*)baudtoregs,ARRAY_SIZE(baudtoregs), ++ sizeof(struct baudtoregs_t),uart_setting_baud); ++ ++ return b; ++} ++ ++static unsigned short *get_divisor(struct uart_port *port, unsigned int baud) ++{ ++ int err, sum, i, j; ++ int a[12], b[12]; ++ unsigned short div, umr, uacr; ++ unsigned short umr_best, div_best, uacr_best; ++ unsigned long long t0, t1, t2, t3; ++ ++ sum = 0; ++ umr_best = div_best = uacr_best = 0; ++ div = 1; ++ ++ if ((port->uartclk % (16 * baud)) == 0) { ++ quot1[0] = port->uartclk / (16 * baud); ++ quot1[1] = 16; ++ quot1[2] = 0; ++ return quot1; ++ } ++ ++ while (1) { ++ umr = port->uartclk / (baud * div); ++ if (umr > 32) { ++ div++; ++ continue; ++ } ++ if (umr < 4) { ++ break; ++ } ++ for (i = 0; i < 12; i++) { ++ a[i] = umr; ++ b[i] = 0; ++ sum = 0; ++ for (j = 0; j <= i; j++) { ++ sum += a[j]; ++ } ++ ++ /* the precision could be 1/2^(36) due to the value of t0 */ ++ t0 = 0x1000000000LL; ++ t1 = (i + 1) * t0; ++ t2 = (sum * div) * t0; ++ t3 = div * t0; ++ do_div(t1, baud); ++ do_div(t2, port->uartclk); ++ do_div(t3, (2 * port->uartclk)); ++ err = t1 - t2 - t3; ++ ++ if (err > 0) { ++ a[i] += 1; ++ b[i] = 1; ++ } ++ } ++ ++ uacr = 0; ++ for (i = 0; i < 12; i++) { ++ if (b[i] == 1) { ++ uacr |= 1 << i; ++ } ++ } ++ if (div_best ==0){ ++ div_best = div; ++ umr_best = umr; ++ uacr_best = uacr; ++ } ++ ++ /* the best value of umr should be near 16, and the value of uacr should better be smaller */ ++ if (abs(umr - 16) < abs(umr_best - 16) || (abs(umr - 16) == abs(umr_best - 16) && uacr_best > uacr)) ++ { ++ div_best = div; ++ umr_best = umr; ++ uacr_best = uacr; ++ } ++ div++; ++ } ++ ++ quot1[0] = div_best; ++ quot1[1] = umr_best; ++ quot1[2] = uacr_best; ++ ++ return quot1; ++} ++static unsigned short *serial47xx_get_divisor(struct uart_port *port, unsigned int baud) ++{ ++ struct baudtoregs_t *bt; ++ ++ bt = search_divisor(baud); ++ if(bt) { ++ quot1[0] = bt->div; ++ quot1[1] = bt->umr; ++ quot1[2] = bt->uacr; ++ return quot1; ++ } ++ ++ return get_divisor(port, baud); ++} ++ ++static void serial_ingenic_release_port(struct uart_port *port) ++{ ++} ++ ++static int serial_ingenic_request_port(struct uart_port *port) ++{ ++ return 0; ++} ++ ++static void serial_ingenic_config_port(struct uart_port *port, int flags) ++{ ++ struct uart_ingenic_port *up = (struct uart_ingenic_port *)port; ++ up->port.type = PORT_8250; ++} ++ ++static int serial_ingenic_verify_port(struct uart_port *port, struct serial_struct *ser) ++{ ++ /* we don't want the core code to modify any port params */ ++ return -EINVAL; ++} ++ ++static const char *serial_ingenic_type(struct uart_port *port) ++{ ++ struct uart_ingenic_port *up = (struct uart_ingenic_port *)port; ++ return up->name; ++} ++static struct uart_ingenic_port *serial_ingenic_ports[PORT_NR]; ++static struct uart_driver serial_ingenic_reg; ++ ++#ifdef CONFIG_SERIAL_INGENIC_CONSOLE ++ ++#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) ++ ++/* ++ * Wait for transmitter & holding register to empty ++ */ ++static inline void wait_for_xmitr(struct uart_ingenic_port *up) ++{ ++ unsigned int status, tmout = 10000; ++ ++ /* Wait up to 10ms for the character(s) to be sent. */ ++ do { ++ status = serial_in(up, UART_LSR); ++ ++ if (status & UART_LSR_BI) ++ up->lsr_break_flag = UART_LSR_BI; ++ ++ if (--tmout == 0) ++ break; ++ udelay(1); ++ } while ((status & BOTH_EMPTY) != BOTH_EMPTY); ++ ++ /* Wait up to 1s for flow control if necessary */ ++ if (up->port.flags & UPF_CONS_FLOW) { ++ tmout = 1000000; ++ while (--tmout && ++ ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0))//no CTS ++ udelay(1); ++ } ++} ++ ++static void serial_ingenic_console_putchar(struct uart_port *port, int ch) ++{ ++ struct uart_ingenic_port *up = (struct uart_ingenic_port *)port; ++ ++ wait_for_xmitr(up); ++ serial_out(up, UART_TX, ch); ++} ++ ++/* ++ * Print a string to the serial port trying not to disturb ++ * any possible real use of the port... ++ * ++ * The console_lock must be held when we get here. ++ */ ++static void serial_ingenic_console_write(struct console *co, const char *s, unsigned int count) ++{ ++ struct uart_ingenic_port *up = serial_ingenic_ports[co->index]; ++ unsigned int ier; ++ ++ /* ++ * First save the IER then disable the interrupts ++ */ ++ spin_lock(&up->port.lock); ++ ier = up->ier; ++ up->ier &= ~UART_IER_THRI; ++ serial_out(up, UART_IER, up->ier); ++ ++ uart_console_write(&up->port, s, count, serial_ingenic_console_putchar); ++ ++ /* ++ * Finally, wait for transmitter to become empty ++ * and restore the IER ++ */ ++ wait_for_xmitr(up); ++ up->ier = ier; ++ serial_out(up, UART_IER, ier); ++ spin_unlock(&up->port.lock); ++} ++ ++static int __init serial_ingenic_console_setup(struct console *co, char *options) ++{ ++ struct uart_ingenic_port *up; ++ int baud = 57600; ++ int bits = 8; ++ int parity = 'n'; ++ int flow = 'n'; ++ ++ if (co->index == -1 || co->index >= serial_ingenic_reg.nr) ++ co->index = 0; ++ up = serial_ingenic_ports[co->index]; ++ if (!up) ++ return -ENODEV; ++ ++ if (options) ++ uart_parse_options(options, &baud, &parity, &bits, &flow); ++ ++ return uart_set_options(&up->port, co, baud, parity, bits, flow); ++} ++ ++static struct console serial_ingenic_console = { ++ .name = "ttyS", ++ .write = serial_ingenic_console_write, ++ .device = uart_console_device, ++ .setup = serial_ingenic_console_setup, ++ .flags = CON_PRINTBUFFER, ++ .index = -1, ++ .data = &serial_ingenic_reg, ++}; ++ ++#define INGENIC_CONSOLE &serial_ingenic_console ++#else ++#define INGENIC_CONSOLE NULL ++#endif ++ ++struct uart_ops serial_ingenic_pops = { ++ .tx_empty = serial_ingenic_tx_empty,//TX Buffer empty ++ .set_mctrl = serial_ingenic_set_mctrl,//set Modem control ++ .get_mctrl = serial_ingenic_get_mctrl,//get Modem control ++ .stop_tx = serial_ingenic_stop_tx,//stop TX ++ .start_tx = serial_ingenic_start_tx,//start tx ++ .stop_rx = serial_ingenic_stop_rx,//stop rx ++ .enable_ms = serial_ingenic_enable_ms,//modem status enable ++ .break_ctl = serial_ingenic_break_ctl,// ++ .startup = serial_ingenic_startup,//start endport ++ .shutdown = serial_ingenic_shutdown,//shutdown endport ++ .set_termios = serial_ingenic_set_termios,//change para of endport ++ .type = serial_ingenic_type,// ++ .release_port = serial_ingenic_release_port,//release port I/O ++ .request_port = serial_ingenic_request_port,// ++ .config_port = serial_ingenic_config_port,// ++ .verify_port = serial_ingenic_verify_port,// ++}; ++ ++static struct uart_driver serial_ingenic_reg = { ++ .owner = THIS_MODULE, ++ .driver_name = "INGENIC serial", ++ .dev_name = "ttyS", ++ .major = TTY_MAJOR, ++ .minor = 64, ++ .nr = PORT_NR, ++ .cons = INGENIC_CONSOLE, ++}; ++ ++#ifdef CONFIG_PM ++static int serial_ingenic_suspend(struct device *dev) ++{ ++ struct uart_ingenic_port *up = dev_get_drvdata(dev); ++ ++ if (up) ++ uart_suspend_port(&serial_ingenic_reg, &up->port); ++ ++ return 0; ++} ++ ++static int serial_ingenic_resume(struct device *dev) ++{ ++ struct uart_ingenic_port *up = dev_get_drvdata(dev); ++ ++ if (up) ++ uart_resume_port(&serial_ingenic_reg, &up->port); ++ ++ return 0; ++} ++ ++static const struct dev_pm_ops serial_ingenic_pm_ops = { ++ .suspend = serial_ingenic_suspend, ++ .resume = serial_ingenic_resume, ++}; ++#endif ++ ++#ifdef CONFIG_DEBUG_FS ++ ++ ++static ssize_t port_show_regs(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct uart_ingenic_port *up = file->private_data; ++ char *buf; ++ int len = 0; ++ unsigned int lcr; ++ unsigned long flags; ++ ssize_t ret; ++ ++#define REGS_BUFSIZE 1024 ++ buf = kzalloc(REGS_BUFSIZE, GFP_KERNEL); ++ if (!buf) ++ return 0; ++ ++ spin_lock_irqsave(&up->port.lock, flags); ++ ++ lcr = serial_in(up, UART_LCR); ++ serial_out(up, UART_LCR, lcr | UART_LCR_DLAB); ++ len += snprintf(buf + len, REGS_BUFSIZE - len, "%s:\n", up->name); ++ len += snprintf(buf + len, REGS_BUFSIZE - len, "UDLLR: 0x%02x\n", serial_in(up, UART_DLL)); ++ len += snprintf(buf + len, REGS_BUFSIZE - len, "UDLHR: 0x%02x\n", serial_in(up, UART_DLM)); ++ serial_out(up, UART_LCR, lcr & (~UART_LCR_DLAB)); ++ len += snprintf(buf + len, REGS_BUFSIZE - len, "UIER: 0x%02x\n", serial_in(up, UART_IER)); ++ serial_out(up, UART_LCR, lcr); ++ len += snprintf(buf + len, REGS_BUFSIZE - len, "UIIR: 0x%02x\n", serial_in(up, UART_IIR)); ++ len += snprintf(buf + len, REGS_BUFSIZE - len, "UFCR: 0x%02x\n", serial_in(up, UART_FCR)); ++ len += snprintf(buf + len, REGS_BUFSIZE - len, "ULCR: 0x%02x\n", lcr); ++ len += snprintf(buf + len, REGS_BUFSIZE - len, "UMCR: 0x%02x\n", serial_in(up, UART_MCR)); ++ len += snprintf(buf + len, REGS_BUFSIZE - len, "ULSR: 0x%02x\n", serial_in(up, UART_LSR)); ++ len += snprintf(buf + len, REGS_BUFSIZE - len, "UMSR: 0x%02x\n", serial_in(up, UART_MSR)); ++ len += snprintf(buf + len, REGS_BUFSIZE - len, "USPR: 0x%02x\n", serial_in(up, UART_SCR)); ++ len += snprintf(buf + len, REGS_BUFSIZE - len, "UISR: 0x%02x\n", serial_in(up, UART_ISR)); ++ len += snprintf(buf + len, REGS_BUFSIZE - len, "UMR: 0x%02x\n", serial_in(up, UART_UMR)); ++ len += snprintf(buf + len, REGS_BUFSIZE - len, "UACR: 0x%03x\n", serial_in(up, UART_UACR)); ++ len += snprintf(buf + len, REGS_BUFSIZE - len, "URCR: 0x%03x\n", serial_in(up, UART_RCR)); ++ len += snprintf(buf + len, REGS_BUFSIZE - len, "UTCR: 0x%03x\n", serial_in(up, UART_TCR)); ++ ++ spin_unlock_irqrestore(&up->port.lock, flags); ++ ++ ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); ++ kfree(buf); ++#undef REGS_BUFSIZE ++ return ret; ++} ++ ++static const struct file_operations port_regs_ops = { ++ .owner = THIS_MODULE, ++ .open = simple_open, ++ .read = port_show_regs, ++ .llseek = default_llseek, ++}; ++#endif ++ ++static const struct of_device_id serial_ingenic_of_match[] = { ++ {.compatible = "ingenic,8250-uart", .data = NULL}, ++}; ++ ++MODULE_DEVICE_TABLE(of, serial_ingenic_of_match); ++ ++static int serial_ingenic_probe(struct platform_device *pdev) ++{ ++ struct uart_ingenic_port *up; ++ struct resource *mmres; ++ int irq; ++ char clk_name[20]; ++ unsigned long uartclk; ++ ++ mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ irq = platform_get_irq(pdev, 0); ++ if (!mmres || irq < 0) ++ return -ENODEV; ++ ++ up = devm_kzalloc(&pdev->dev, sizeof(struct uart_ingenic_port), GFP_KERNEL); ++ if (!up) ++ return -ENOMEM; ++ ++ pdev->id = of_alias_get_id(pdev->dev.of_node, "uart"); ++ ++ sprintf(up->name,"uart%d",pdev->id); ++ ++ sprintf(clk_name, "gate_uart%d",pdev->id); ++ up->clk = devm_clk_get(&pdev->dev, clk_name); ++ if (IS_ERR_OR_NULL(up->clk)) { ++ printk(KERN_WARNING "%s: Failed to get uart clk. Using Default clk rate(24MHz)\n", up->name); ++ uartclk = 24000000; ++ up->clk = NULL; ++ } else { ++ uartclk = clk_get_rate(up->clk); ++ } ++ ++ up->port.type = PORT_8250; ++ up->port.iotype = UPIO_MEM; ++ up->port.mapbase = mmres->start; ++ up->port.mapsize = resource_size(mmres); ++ up->port.irq = irq; ++ up->port.fifosize = 64; ++ up->port.ops = &serial_ingenic_pops; ++ up->port.line = pdev->id; ++ up->port.dev = &pdev->dev; ++ up->port.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF; ++ up->port.uartclk = uartclk; ++ up->port.membase = devm_ioremap_resource(&pdev->dev, mmres); ++ if (!up->port.membase) ++ return -ENOMEM; ++ ++ if(up->clk) ++ clk_prepare_enable(up->clk); ++ ++ serial_ingenic_ports[pdev->id] = up; ++ uart_add_one_port(&serial_ingenic_reg, &up->port); ++ ++ platform_set_drvdata(pdev, up); ++ ++#ifdef CONFIG_DEBUG_FS ++ { ++ char name[20]; ++ snprintf(name, sizeof(name), "uart%d_regs", up->port.line); ++ up->debugfs = debugfs_create_file(name, S_IFREG | S_IRUGO, ++ NULL, up, &port_regs_ops); ++ } ++#endif ++ return 0; ++} ++ ++static int serial_ingenic_remove(struct platform_device *pdev) ++{ ++ struct uart_ingenic_port *up = platform_get_drvdata(pdev); ++ ++#ifdef CONFIG_DEBUG_FS ++ if (up->debugfs) ++ debugfs_remove(up->debugfs); ++#endif ++ platform_set_drvdata(pdev, NULL); ++ ++ uart_remove_one_port(&serial_ingenic_reg, &up->port); ++ ++ if(up->clk) ++ clk_disable_unprepare(up->clk); ++ ++ return 0; ++} ++ ++static struct platform_driver serial_ingenic_driver = { ++ .probe = serial_ingenic_probe, ++ .remove = serial_ingenic_remove, ++ ++ .driver = { ++ .name = "ingenic-uart", ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(serial_ingenic_of_match), ++#ifdef CONFIG_PM ++ .pm = &serial_ingenic_pm_ops, ++#endif ++ }, ++}; ++ ++int __init serial_ingenic_init(void) ++{ ++ int ret; ++ ret = uart_register_driver(&serial_ingenic_reg); ++ if (ret != 0) ++ return ret; ++ ++ ret = platform_driver_register(&serial_ingenic_driver); ++ if (ret != 0) ++ uart_unregister_driver(&serial_ingenic_reg); ++ ++ return ret; ++} ++ ++void __exit serial_ingenic_exit(void) ++{ ++ platform_driver_unregister(&serial_ingenic_driver); ++ uart_unregister_driver(&serial_ingenic_reg); ++} ++ ++#ifdef CONFIG_EARLY_INIT_RUN ++rootfs_initcall(serial_ingenic_init); ++ ++#else ++module_init(serial_ingenic_init); ++ ++#endif ++ ++module_exit(serial_ingenic_exit); ++ ++MODULE_DESCRIPTION("Ingenic Compatible UART driver"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:ingenic-uart"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_tty_serial_ingenic_uart.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_tty_serial_ingenic_uart.h.patch new file mode 100644 index 00000000..5aadc84e --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_tty_serial_ingenic_uart.h.patch @@ -0,0 +1,121 @@ +diff -drupN a/drivers/tty/serial/ingenic_uart.h b/drivers/tty/serial/ingenic_uart.h +--- a/drivers/tty/serial/ingenic_uart.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/tty/serial/ingenic_uart.h 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,117 @@ ++/* ++ * ++ * Copyright (C) 1992, 1994 by Theodore Ts'o. ++ * ++ * Redistribution of this file is permitted under the terms of the GNU ++ * Public License (GPL) ++ * ++ * These are the UART port assignments, expressed as offsets from the base ++ * register. These assignments should hold for any serial port based on ++ * a 8250, 16450, or 16550(A). ++ */ ++ ++#ifndef __INGENIC_UART_H__ ++#define __INGENIC_UART_H__ ++ ++/* ++ * DLAB=0 ++ */ ++#define UART_RX 0 /* In: Receive buffer */ ++#define UART_TX 0 /* Out: Transmit buffer */ ++ ++#define UART_IER 1 /* Out: Interrupt Enable Register */ ++#define UART_IER_RTOIE 0x10 /* Receiver Time Out Interrupt Enable */ ++#define UART_IER_MSI 0x08 /* Enable Modem status interrupt */ ++#define UART_IER_RLSI 0x04 /* Enable receiver line status interrupt */ ++#define UART_IER_THRI 0x02 /* Enable Transmitter holding register int. */ ++#define UART_IER_RDI 0x01 /* Enable receiver data interrupt */ ++ ++#define UART_IIR 2 /* In: Interrupt ID Register */ ++#define UART_IIR_NO_INT 0x01 /* No interrupts pending */ ++#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */ ++#define UART_IIR_MSI 0x00 /* Modem status interrupt */ ++#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */ ++#define UART_IIR_RDI 0x04 /* Receiver data interrupt */ ++#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */ ++ ++#define UART_IIR_BUSY 0x07 /* DesignWare APB Busy Detect */ ++ ++#define UART_FCR 2 /* Out: FIFO Control Register */ ++#define UART_FCR_ENABLE_FIFO 0x01 /* Enable the FIFO */ ++#define UART_FCR_CLEAR_RCVR 0x02 /* Clear the RCVR FIFO */ ++#define UART_FCR_CLEAR_XMIT 0x04 /* Clear the XMIT FIFO */ ++#define UART_FCR_DMA_SELECT 0x08 /* For DMA applications */ ++#define UART_FCR_UME 0x10 /* UME */ ++ ++#define UART_FCR_R_TRIG_00 0x00 ++#define UART_FCR_R_TRIG_01 0x40 ++#define UART_FCR_R_TRIG_10 0x80 ++#define UART_FCR_R_TRIG_11 0xc0 ++#define UART_FCR_TRIGGER_MASK 0xC0 /* Mask for the FIFO trigger range */ ++ ++#define UART_LCR 3 /* Out: Line Control Register */ ++/* ++ * Note: if the word length is 5 bits (UART_LCR_WLEN5), then setting ++ * UART_LCR_STOP will select 1.5 stop bits, not 2 stop bits. ++ */ ++#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */ ++#define UART_LCR_SBC 0x40 /* Set break control */ ++#define UART_LCR_SPAR 0x20 /* Stick parity (?) */ ++#define UART_LCR_EPAR 0x10 /* Even parity select */ ++#define UART_LCR_PARITY 0x08 /* Parity Enable */ ++#define UART_LCR_STOP 0x04 /* Stop bits: 0=1 bit, 1=2 bits */ ++#define UART_LCR_WLEN5 0x00 /* Wordlength: 5 bits */ ++#define UART_LCR_WLEN6 0x01 /* Wordlength: 6 bits */ ++#define UART_LCR_WLEN7 0x02 /* Wordlength: 7 bits */ ++#define UART_LCR_WLEN8 0x03 /* Wordlength: 8 bits */ ++ ++/* ++ * Access to some registers depends on register access / configuration ++ * mode. ++ */ ++#define UART_LCR_CONF_MODE_A UART_LCR_DLAB /* Configutation mode A */ ++#define UART_LCR_CONF_MODE_B 0xBF /* Configutation mode B */ ++ ++#define UART_MCR 4 /* Out: Modem Control Register */ ++#define UART_MCR_MDCE 0x80 /* Enable modem function */ ++#define UART_MCR_FCM 0x40 /* flow control by hardware */ ++#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */ ++#define UART_MCR_RTS 0x02 /* RTS complement */ ++ ++#define UART_LSR 5 /* In: Line Status Register */ ++#define UART_LSR_FIFOE 0x80 /* Fifo error */ ++#define UART_LSR_TEMT 0x40 /* Transmitter empty */ ++#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */ ++#define UART_LSR_BI 0x10 /* Break interrupt indicator */ ++#define UART_LSR_FE 0x08 /* Frame error indicator */ ++#define UART_LSR_PE 0x04 /* Parity error indicator */ ++#define UART_LSR_OE 0x02 /* Overrun error indicator */ ++#define UART_LSR_DR 0x01 /* Receiver data ready */ ++#define UART_LSR_BRK_ERROR_BITS 0x1E /* BI, FE, PE, OE bits */ ++ ++#define UART_MSR 6 /* In: Modem Status Register */ ++#define UART_MSR_CTS 0x10 /* Clear to Send */ ++#define UART_MSR_DCTS 0x01 /* Delta CTS */ ++#define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */ ++#define UART_RCR 16 ++#define UART_TCR 17 ++ ++#define UART_SCR 7 /* I/O: Scratch Register */ ++ ++/* ++ * The Ingenic xburst on-chip UARTs define these bits ++ */ ++ ++#define UART_ISR 8 ++#define UART_UMR 9 ++#define UART_UACR 10 ++#define UART_RCR 16 /* RX FIFO Counter Register */ ++#define UART_TCR 17 /* TX FIFO Counter Register */ ++ ++/* ++ * DLAB=1 ++ */ ++#define UART_DLL 0 /* Out: Divisor Latch Low */ ++#define UART_DLM 1 /* Out: Divisor Latch High */ ++ ++#endif /* __INGENIC_UART_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_tty_serial_serial_core.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_tty_serial_serial_core.c.patch new file mode 100644 index 00000000..2b0fd7c2 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_tty_serial_serial_core.c.patch @@ -0,0 +1,55 @@ +diff -drupN a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c +--- a/drivers/tty/serial/serial_core.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/tty/serial/serial_core.c 2022-06-09 05:02:34.000000000 +0300 +@@ -1892,26 +1892,6 @@ uart_parse_options(char *options, int *b + } + EXPORT_SYMBOL_GPL(uart_parse_options); + +-struct baud_rates { +- unsigned int rate; +- unsigned int cflag; +-}; +- +-static const struct baud_rates baud_rates[] = { +- { 921600, B921600 }, +- { 460800, B460800 }, +- { 230400, B230400 }, +- { 115200, B115200 }, +- { 57600, B57600 }, +- { 38400, B38400 }, +- { 19200, B19200 }, +- { 9600, B9600 }, +- { 4800, B4800 }, +- { 2400, B2400 }, +- { 1200, B1200 }, +- { 0, B38400 } +-}; +- + /** + * uart_set_options - setup the serial console parameters + * @port: pointer to the serial ports uart_port structure +@@ -1927,7 +1907,6 @@ uart_set_options(struct uart_port *port, + { + struct ktermios termios; + static struct ktermios dummy; +- int i; + + /* + * Ensure that the serial console lock is initialised +@@ -1943,15 +1922,7 @@ uart_set_options(struct uart_port *port, + memset(&termios, 0, sizeof(struct ktermios)); + + termios.c_cflag = CREAD | HUPCL | CLOCAL; +- +- /* +- * Construct a cflag setting. +- */ +- for (i = 0; baud_rates[i].rate; i++) +- if (baud_rates[i].rate <= baud) +- break; +- +- termios.c_cflag |= baud_rates[i].cflag; ++ tty_termios_encode_baud_rate(&termios, baud, baud); + + if (bits == 7) + termios.c_cflag |= CS7; diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_core_hub.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_core_hub.c.patch new file mode 100644 index 00000000..faa33eea --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_core_hub.c.patch @@ -0,0 +1,12 @@ +diff -drupN a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c +--- a/drivers/usb/core/hub.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/usb/core/hub.c 2022-06-09 05:02:34.000000000 +0300 +@@ -2414,7 +2414,7 @@ int usb_new_device(struct usb_device *ud + (((udev->bus->busnum-1) * 128) + (udev->devnum-1))); + + /* Tell the world! */ +- announce_device(udev); ++ /*announce_device(udev);*/ + + if (udev->serial) + add_device_randomness(udev->serial, strlen(udev->serial)); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_dwc2_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_dwc2_Kconfig.patch new file mode 100644 index 00000000..b1f19e15 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_dwc2_Kconfig.patch @@ -0,0 +1,26 @@ +diff -drupN a/drivers/usb/dwc2/Kconfig b/drivers/usb/dwc2/Kconfig +--- a/drivers/usb/dwc2/Kconfig 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/usb/dwc2/Kconfig 2022-06-09 05:02:34.000000000 +0300 +@@ -50,6 +50,22 @@ config USB_DWC2_DUAL_ROLE + option requires USB_GADGET to be enabled. + endchoice + ++ ++choice ++ bool "DWC2 DMA Mode Selection" ++ default USB_DWC2_DMA_BUFFER_MODE ++config USB_DWC2_DMA_BUFFER_MODE ++ bool "dma buffer mode" ++ ++config USB_DWC2_DMA_DESCRIPTOR_MODE ++ bool "dma descriptor mode" ++endchoice ++ ++config USB_DWC2_HIGHWIDTH_FIFO ++ bool "Enable usb dwc2 highwidth fifo" ++ help ++ Say Y here to enable debugging messages in the DWC2 Driver. ++ + config USB_DWC2_PCI + tristate "DWC2 PCI" + depends on PCI diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_dwc2_core.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_dwc2_core.c.patch new file mode 100644 index 00000000..55af11cf --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_dwc2_core.c.patch @@ -0,0 +1,213 @@ +diff -drupN a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c +--- a/drivers/usb/dwc2/core.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/usb/dwc2/core.c 2022-06-09 05:02:34.000000000 +0300 +@@ -485,13 +485,18 @@ static int dwc2_core_reset(struct dwc2_h + { + u32 greset; + int count = 0; +- u32 gusbcfg; +- ++ bool wait_for_host_mode = false; ++ u32 gotgctl = dwc2_readl(hsotg->regs + GOTGCTL); ++ u32 gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG); + dev_vdbg(hsotg->dev, "%s()\n", __func__); + ++ if (!(gotgctl & GOTGCTL_CONID_B) ||(gusbcfg & GUSBCFG_FORCEHOSTMODE)) { ++ wait_for_host_mode = true; ++ } ++ + /* Wait for AHB master IDLE state */ + do { +- usleep_range(20000, 40000); ++ udelay(1); + greset = dwc2_readl(hsotg->regs + GRSTCTL); + if (++count > 50) { + dev_warn(hsotg->dev, +@@ -506,7 +511,7 @@ static int dwc2_core_reset(struct dwc2_h + greset |= GRSTCTL_CSFTRST; + dwc2_writel(greset, hsotg->regs + GRSTCTL); + do { +- usleep_range(20000, 40000); ++ udelay(1); + greset = dwc2_readl(hsotg->regs + GRSTCTL); + if (++count > 50) { + dev_warn(hsotg->dev, +@@ -537,8 +542,17 @@ static int dwc2_core_reset(struct dwc2_h + * NOTE: This long sleep is _very_ important, otherwise the core will + * not stay in host mode after a connector ID change! + */ +- usleep_range(150000, 200000); +- ++ count = 0; ++ if(wait_for_host_mode){ ++ do{ ++ if (++count > 110) { ++ dev_warn(hsotg->dev, "%s: Couldn't set host mode\n", ++ __func__); ++ break; ++ } ++ usleep_range(1000, 2000); ++ }while(!dwc2_is_host_mode(hsotg)); ++ } + return 0; + } + +@@ -769,7 +783,7 @@ static void dwc2_gusbcfg_init(struct dwc + * @select_phy: If true then also set the Phy type + * @irq: If >= 0, the irq to register + */ +-int dwc2_core_init(struct dwc2_hsotg *hsotg, bool select_phy, int irq) ++int dwc2_core_init(struct dwc2_hsotg *hsotg, bool select_phy, int irq, bool initial_setup) + { + u32 usbcfg, otgctl; + int retval; +@@ -792,13 +806,14 @@ int dwc2_core_init(struct dwc2_hsotg *hs + dwc2_writel(usbcfg, hsotg->regs + GUSBCFG); + + /* Reset the Controller */ +- retval = dwc2_core_reset(hsotg); +- if (retval) { +- dev_err(hsotg->dev, "%s(): Reset failed, aborting\n", +- __func__); +- return retval; ++ if(!initial_setup){ ++ retval = dwc2_core_reset(hsotg); ++ if (retval) { ++ dev_err(hsotg->dev, "%s(): Reset failed, aborting\n", ++ __func__); ++ return retval; ++ } + } +- + /* + * This needs to happen in FS mode before any other programming occurs + */ +@@ -835,6 +850,8 @@ int dwc2_core_init(struct dwc2_hsotg *hs + if (dwc2_is_host_mode(hsotg)) { + dev_dbg(hsotg->dev, "Host Mode\n"); + hsotg->op_state = OTG_STATE_A_HOST; ++ otgctl |= GOTGCTL_VBVALIDOVEN | GOTGCTL_VBVALIDOVVAL; ++ dwc2_writel(otgctl, hsotg->regs + GOTGCTL); + } else { + dev_dbg(hsotg->dev, "Device Mode\n"); + hsotg->op_state = OTG_STATE_B_PERIPHERAL; +@@ -1029,6 +1046,7 @@ void dwc2_core_host_init(struct dwc2_hso + + /* Initialize Host Configuration Register */ + dwc2_init_fs_ls_pclk_sel(hsotg); ++ + if (hsotg->core_params->speed == DWC2_SPEED_PARAM_FULL) { + hcfg = dwc2_readl(hsotg->regs + HCFG); + hcfg |= HCFG_FSLSSUPP; +@@ -1131,6 +1149,7 @@ void dwc2_core_host_init(struct dwc2_hso + hprt0 |= HPRT0_PWR; + dwc2_writel(hprt0, hsotg->regs + HPRT0); + } ++ usb_phy_vbus_on(hsotg->uphy); + } + + dwc2_enable_host_interrupts(hsotg); +@@ -2172,6 +2191,10 @@ void dwc2_dump_host_registers(struct dwc + u32 __iomem *addr; + int i; + ++ if (!(dwc2_readl(hsotg->regs + GINTSTS) & GINTSTS_CURMODE_HOST)) { ++ dev_dbg(hsotg->dev, "%s but current mode is device\n", __func__); ++ return; ++ } + dev_dbg(hsotg->dev, "Host Global Registers\n"); + addr = hsotg->regs + HCFG; + dev_dbg(hsotg->dev, "HCFG @0x%08lX : 0x%08X\n", +@@ -3052,6 +3075,51 @@ void dwc2_set_parameters(struct dwc2_hso + dwc2_set_param_hibernation(hsotg, params->hibernation); + } + ++/* ++ * Gets host hardware parameters. Forces host mode to get parameters ++ */ ++static void dwc2_get_host_hwparams(struct dwc2_hsotg *hsotg) ++{ ++ struct dwc2_hw_params *hw = &hsotg->hw_params; ++ u32 gnptxfsiz; ++ u32 hptxfsiz; ++ u32 gusbcfg; ++ bool forced; ++ int count = 0; ++ ++/*when device mode, return */ ++ if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) ++ return; ++ ++/*set force host mode , and wait for host mode*/ ++ gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG); ++ gusbcfg |= GUSBCFG_FORCEHOSTMODE; ++ dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG); ++ ++ do{ ++ if (++count > 110) { ++ dev_warn(hsotg->dev, "%s: Couldn't set host mode\n", ++ __func__); ++ break; ++ } ++ usleep_range(1000, 2000); ++ }while(!dwc2_is_host_mode(hsotg)); ++ ++ gnptxfsiz = dwc2_readl(hsotg->regs + GNPTXFSIZ); ++ hptxfsiz = dwc2_readl(hsotg->regs + HPTXFSIZ); ++ ++/*clear force host mode , don't wait*/ ++ gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG); ++ gusbcfg &= ~GUSBCFG_FORCEHOSTMODE; ++ dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG); ++ ++ hw->host_nperio_tx_fifo_size = (gnptxfsiz & FIFOSIZE_DEPTH_MASK) >> ++ FIFOSIZE_DEPTH_SHIFT; ++ hw->host_perio_tx_fifo_size = (hptxfsiz & FIFOSIZE_DEPTH_MASK) >> ++ FIFOSIZE_DEPTH_SHIFT; ++} ++ ++ + /** + * During device initialization, read various hardware configuration + * registers and interpret the contents. +@@ -3061,7 +3129,7 @@ int dwc2_get_hwparams(struct dwc2_hsotg + struct dwc2_hw_params *hw = &hsotg->hw_params; + unsigned width; + u32 hwcfg1, hwcfg2, hwcfg3, hwcfg4; +- u32 hptxfsiz, grxfsiz, gnptxfsiz; ++ u32 grxfsiz; + u32 gusbcfg; + + /* +@@ -3095,19 +3163,7 @@ int dwc2_get_hwparams(struct dwc2_hsotg + dev_dbg(hsotg->dev, "grxfsiz=%08x\n", grxfsiz); + + /* Force host mode to get HPTXFSIZ / GNPTXFSIZ exact power on value */ +- gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG); +- gusbcfg |= GUSBCFG_FORCEHOSTMODE; +- dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG); +- usleep_range(100000, 150000); +- +- gnptxfsiz = dwc2_readl(hsotg->regs + GNPTXFSIZ); +- hptxfsiz = dwc2_readl(hsotg->regs + HPTXFSIZ); +- dev_dbg(hsotg->dev, "gnptxfsiz=%08x\n", gnptxfsiz); +- dev_dbg(hsotg->dev, "hptxfsiz=%08x\n", hptxfsiz); +- gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG); +- gusbcfg &= ~GUSBCFG_FORCEHOSTMODE; +- dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG); +- usleep_range(100000, 150000); ++ dwc2_get_host_hwparams(hsotg); + + /* hwcfg2 */ + hw->op_mode = (hwcfg2 & GHWCFG2_OP_MODE_MASK) >> +@@ -3163,10 +3219,6 @@ int dwc2_get_hwparams(struct dwc2_hsotg + /* fifo sizes */ + hw->host_rx_fifo_size = (grxfsiz & GRXFSIZ_DEPTH_MASK) >> + GRXFSIZ_DEPTH_SHIFT; +- hw->host_nperio_tx_fifo_size = (gnptxfsiz & FIFOSIZE_DEPTH_MASK) >> +- FIFOSIZE_DEPTH_SHIFT; +- hw->host_perio_tx_fifo_size = (hptxfsiz & FIFOSIZE_DEPTH_MASK) >> +- FIFOSIZE_DEPTH_SHIFT; + + dev_dbg(hsotg->dev, "Detected values from hardware:\n"); + dev_dbg(hsotg->dev, " op_mode=%d\n", diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_dwc2_core.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_dwc2_core.h.patch new file mode 100644 index 00000000..98864e3c --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_dwc2_core.h.patch @@ -0,0 +1,37 @@ +diff -drupN a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h +--- a/drivers/usb/dwc2/core.h 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/usb/dwc2/core.h 2022-06-09 05:02:34.000000000 +0300 +@@ -239,9 +239,14 @@ enum dwc2_lx_state { + * Gadget periodic tx fifo sizes as used by legacy driver + * EP0 is not included + */ +-#define DWC2_G_P_LEGACY_TX_FIFO_SIZE {256, 256, 256, 256, 768, 768, 768, \ +- 768, 0, 0, 0, 0, 0, 0, 0} + ++#ifdef CONFIG_USB_DWC2_HIGHWIDTH_FIFO ++#define DWC2_G_P_LEGACY_TX_FIFO_SIZE {128 ,128, 128, 128, 128, 128, 256, \ ++ 768, 0, 0 , 0, 0, 0, 0, 0} ++#else ++#define DWC2_G_P_LEGACY_TX_FIFO_SIZE {256, 256, 256, 256, 256, 256, 256, \ ++ 512, 0, 0, 0, 0, 0, 0, 0} ++#endif + /* Gadget ep0 states */ + enum dwc2_ep0_state { + DWC2_EP0_SETUP, +@@ -848,6 +853,7 @@ struct dwc2_hsotg { + int fifo_mem; + unsigned int dedicated_fifos:1; + unsigned char num_of_eps; ++ unsigned char num_of_ineps; + u32 fifo_map; + + struct usb_request *ep0_reply; +@@ -928,7 +934,7 @@ extern void dwc2_read_packet(struct dwc2 + extern void dwc2_flush_tx_fifo(struct dwc2_hsotg *hsotg, const int num); + extern void dwc2_flush_rx_fifo(struct dwc2_hsotg *hsotg); + +-extern int dwc2_core_init(struct dwc2_hsotg *hsotg, bool select_phy, int irq); ++extern int dwc2_core_init(struct dwc2_hsotg *hsotg, bool select_phy, int irq, bool initial_setup); + extern void dwc2_enable_global_interrupts(struct dwc2_hsotg *hcd); + extern void dwc2_disable_global_interrupts(struct dwc2_hsotg *hcd); + diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_dwc2_gadget.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_dwc2_gadget.c.patch new file mode 100644 index 00000000..47dc30f1 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_dwc2_gadget.c.patch @@ -0,0 +1,118 @@ +diff -drupN a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c +--- a/drivers/usb/dwc2/gadget.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/usb/dwc2/gadget.c 2022-06-09 05:02:34.000000000 +0300 +@@ -197,7 +197,7 @@ static void dwc2_hsotg_init_fifo(struct + * them to endpoints dynamically according to maxpacket size value of + * given endpoint. + */ +- for (ep = 1; ep < MAX_EPS_CHANNELS; ep++) { ++ for (ep = 1; ep < hsotg->num_of_ineps; ep++) { + if (!hsotg->g_tx_fifo_sz[ep]) + continue; + val = addr; +@@ -209,6 +209,9 @@ static void dwc2_hsotg_init_fifo(struct + dwc2_writel(val, hsotg->regs + DPTXFSIZN(ep)); + } + ++ val = (addr << GDFIFOCFG_EPINFOBASE_SHIFT) | hsotg->fifo_mem; ++ dwc2_writel(val, hsotg->regs + GDFIFOCFG); ++ + /* + * according to p428 of the design guide, we need to ensure that + * all fifos are flushed before continuing +@@ -1742,7 +1745,7 @@ static void dwc2_hsotg_set_ep_maxpacket( + struct dwc2_hsotg_ep *hs_ep; + void __iomem *regs = hsotg->regs; + u32 mpsval; +- u32 mcval; ++ u32 mcval = 1; + u32 reg; + + hs_ep = index_to_ep(hsotg, ep, dir_in); +@@ -2095,7 +2098,7 @@ static void dwc2_hsotg_irq_enumdone(stru + */ + + /* catch both EnumSpd_FS and EnumSpd_FS48 */ +- switch (dsts & DSTS_ENUMSPD_MASK) { ++ switch ((dsts & DSTS_ENUMSPD_MASK) >> DSTS_ENUMSPD_SHIFT) { + case DSTS_ENUMSPD_FS: + case DSTS_ENUMSPD_FS48: + hsotg->gadget.speed = USB_SPEED_FULL; +@@ -2163,6 +2166,7 @@ static void kill_all_requests(struct dwc + { + struct dwc2_hsotg_req *req, *treq; + unsigned size; ++ int index = ep->index; + + ep->req = NULL; + +@@ -2325,7 +2329,10 @@ void dwc2_hsotg_core_init_disconnected(s + if (!is_usb_reset) + __orr32(hsotg->regs + DCTL, DCTL_SFTDISCON); + +- dwc2_writel(DCFG_EPMISCNT(1) | DCFG_DEVSPD_HS, hsotg->regs + DCFG); ++ if (hsotg->gadget.max_speed == USB_SPEED_FULL) ++ dwc2_writel(DCFG_DEVSPD_FS, hsotg->regs + DCFG); ++ else ++ dwc2_writel(DCFG_DEVSPD_HS, hsotg->regs + DCFG); + + /* Clear any pending OTG interrupts */ + dwc2_writel(0xffffffff, hsotg->regs + GOTGINT); +@@ -3439,6 +3446,8 @@ static int dwc2_hsotg_hw_cfg(struct dwc2 + + cfg = dwc2_readl(hsotg->regs + GHWCFG4); + hsotg->dedicated_fifos = (cfg >> GHWCFG4_DED_FIFO_SHIFT) & 1; ++ hsotg->num_of_ineps = (cfg & GHWCFG4_NUM_IN_EPS_MASK) >> GHWCFG4_NUM_IN_EPS_SHIFT; ++ hsotg->num_of_ineps++; + + dev_info(hsotg->dev, "EPs: %d, %s fifos, %d entries in SPRAM\n", + hsotg->num_of_eps, +@@ -3459,6 +3468,11 @@ static void dwc2_hsotg_dump(struct dwc2_ + u32 val; + int idx; + ++ if ((dwc2_readl(hsotg->regs + GINTSTS) & GINTSTS_CURMODE_HOST)) { ++ dev_dbg(hsotg->dev, "%s but current mode is host\n", __func__); ++ return; ++ } ++ + dev_info(dev, "DCFG=0x%08x, DCTL=0x%08x, DIEPMSK=%08x\n", + dwc2_readl(regs + DCFG), dwc2_readl(regs + DCTL), + dwc2_readl(regs + DIEPMSK)); +@@ -3558,8 +3572,8 @@ int dwc2_gadget_init(struct dwc2_hsotg * + u32 p_tx_fifo[] = DWC2_G_P_LEGACY_TX_FIFO_SIZE; + + /* Initialize to legacy fifo configuration values */ +- hsotg->g_rx_fifo_sz = 2048; +- hsotg->g_np_g_tx_fifo_sz = 1024; ++ hsotg->g_rx_fifo_sz = 768; ++ hsotg->g_np_g_tx_fifo_sz = 256; + memcpy(&hsotg->g_tx_fifo_sz[1], p_tx_fifo, sizeof(p_tx_fifo)); + /* Device tree specific probe */ + dwc2_hsotg_of_probe(hsotg); +@@ -3567,11 +3581,15 @@ int dwc2_gadget_init(struct dwc2_hsotg * + dev_dbg(dev, "NonPeriodic TXFIFO size: %d\n", + hsotg->g_np_g_tx_fifo_sz); + dev_dbg(dev, "RXFIFO size: %d\n", hsotg->g_rx_fifo_sz); +- for (i = 0; i < MAX_EPS_CHANNELS; i++) ++ for (i = 1; i < MAX_EPS_CHANNELS; i++) + dev_dbg(dev, "Periodic TXFIFO%2d size: %d\n", i, + hsotg->g_tx_fifo_sz[i]); + +- hsotg->gadget.max_speed = USB_SPEED_HIGH; ++ if (hsotg->core_params->speed == DWC2_SPEED_PARAM_FULL) ++ hsotg->gadget.max_speed = USB_SPEED_FULL; ++ else ++ hsotg->gadget.max_speed = USB_SPEED_HIGH; ++ + hsotg->gadget.ops = &dwc2_hsotg_gadget_ops; + hsotg->gadget.name = dev_name(dev); + if (hsotg->dr_mode == USB_DR_MODE_OTG) +@@ -3714,6 +3732,7 @@ int dwc2_hsotg_resume(struct dwc2_hsotg + if (hsotg->lx_state == DWC2_L2) + return 0; + ++ udelay(20); + if (hsotg->driver) { + dev_info(hsotg->dev, "resuming usb gadget %s\n", + hsotg->driver->driver.name); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_dwc2_hcd.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_dwc2_hcd.c.patch new file mode 100644 index 00000000..98f56db0 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_dwc2_hcd.c.patch @@ -0,0 +1,132 @@ +diff -drupN a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c +--- a/drivers/usb/dwc2/hcd.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/usb/dwc2/hcd.c 2022-06-09 05:02:34.000000000 +0300 +@@ -302,6 +302,7 @@ void dwc2_hcd_disconnect(struct dwc2_hso + if (hsotg->op_state != OTG_STATE_A_SUSPEND) { + dev_dbg(hsotg->dev, "Disconnect: PortPower off\n"); + dwc2_writel(0, hsotg->regs + HPRT0); ++ usb_phy_vbus_off(hsotg->uphy); + } + + dwc2_disable_host_interrupts(hsotg); +@@ -356,6 +357,7 @@ void dwc2_hcd_stop(struct dwc2_hsotg *hs + /* Turn off the vbus power */ + dev_dbg(hsotg->dev, "PortPower off\n"); + dwc2_writel(0, hsotg->regs + HPRT0); ++ usb_phy_vbus_off(hsotg->uphy); + } + + /* Caller must hold driver lock */ +@@ -1367,6 +1369,7 @@ static void dwc2_conn_id_status_change(s + + /* B-Device connector (Device Mode) */ + if (gotgctl & GOTGCTL_CONID_B) { ++ usb_phy_vbus_off(hsotg->uphy); + /* Wait for switch to device mode */ + dev_dbg(hsotg->dev, "connId B\n"); + while (!dwc2_is_device_mode(hsotg)) { +@@ -1382,12 +1385,18 @@ static void dwc2_conn_id_status_change(s + dev_err(hsotg->dev, + "Connection id status change timed out\n"); + hsotg->op_state = OTG_STATE_B_PERIPHERAL; +- dwc2_core_init(hsotg, false, -1); ++ dwc2_core_init(hsotg, false, -1, false); + dwc2_enable_global_interrupts(hsotg); + spin_lock_irqsave(&hsotg->lock, flags); +- dwc2_hsotg_core_init_disconnected(hsotg, false); +- spin_unlock_irqrestore(&hsotg->lock, flags); +- dwc2_hsotg_core_connect(hsotg); ++#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) ++ if(hsotg->enabled){ ++ dwc2_hsotg_core_init_disconnected(hsotg, false); ++ spin_unlock_irqrestore(&hsotg->lock, flags); ++ dwc2_hsotg_core_connect(hsotg); ++ }else{ ++ spin_unlock_irqrestore(&hsotg->lock, flags); ++ } ++#endif + } else { + /* A-Device connector (Host Mode) */ + dev_dbg(hsotg->dev, "connId A\n"); +@@ -1405,7 +1414,7 @@ static void dwc2_conn_id_status_change(s + hsotg->op_state = OTG_STATE_A_HOST; + + /* Initialize the Core for Host mode */ +- dwc2_core_init(hsotg, false, -1); ++ dwc2_core_init(hsotg, false, -1, false); + dwc2_enable_global_interrupts(hsotg); + dwc2_hcd_start(hsotg); + } +@@ -2378,11 +2387,14 @@ static void _dwc2_hcd_stop(struct usb_hc + + static int _dwc2_hcd_suspend(struct usb_hcd *hcd) + { ++ int ret = 0; + struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); + unsigned long flags; +- int ret = 0; + u32 hprt0; + ++ if(!dwc2_is_host_mode(hsotg)) ++ return ret; ++ + spin_lock_irqsave(&hsotg->lock, flags); + + if (hsotg->lx_state != DWC2_L0) +@@ -2403,6 +2415,7 @@ static int _dwc2_hcd_suspend(struct usb_ + hprt0 |= HPRT0_SUSP; + hprt0 &= ~HPRT0_PWR; + dwc2_writel(hprt0, hsotg->regs + HPRT0); ++ usb_phy_vbus_off(hsotg->uphy); + } + + /* Enter hibernation */ +@@ -2428,18 +2441,20 @@ skip_power_saving: + hsotg->lx_state = DWC2_L2; + unlock: + spin_unlock_irqrestore(&hsotg->lock, flags); +- + return ret; + } + + static int _dwc2_hcd_resume(struct usb_hcd *hcd) + { ++ ++ int ret = 0; + struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); + unsigned long flags; +- int ret = 0; + +- spin_lock_irqsave(&hsotg->lock, flags); ++ if(!dwc2_is_host_mode(hsotg)) ++ return ret; + ++ spin_lock_irqsave(&hsotg->lock, flags); + if (hsotg->lx_state != DWC2_L2) + goto unlock; + +@@ -2487,6 +2502,7 @@ static int _dwc2_hcd_resume(struct usb_h + * Clear Port Enable and Port Status changes. + * Enable Port Power. + */ ++ usb_phy_vbus_on(hsotg->uphy); + dwc2_writel(HPRT0_PWR | HPRT0_CONNDET | + HPRT0_ENACHG, hsotg->regs + HPRT0); + /* Wait for controller to detect Port Connect */ +@@ -2496,7 +2512,6 @@ static int _dwc2_hcd_resume(struct usb_h + return ret; + unlock: + spin_unlock_irqrestore(&hsotg->lock, flags); +- + return ret; + } + +@@ -3054,7 +3069,7 @@ int dwc2_hcd_init(struct dwc2_hsotg *hso + dwc2_disable_global_interrupts(hsotg); + + /* Initialize the DWC_otg core, and select the Phy type */ +- retval = dwc2_core_init(hsotg, true, irq); ++ retval = dwc2_core_init(hsotg, true, irq, true); + if (retval) + goto error2; + diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_dwc2_hcd_ddma.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_dwc2_hcd_ddma.c.patch new file mode 100644 index 00000000..4197c846 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_dwc2_hcd_ddma.c.patch @@ -0,0 +1,46 @@ +diff -drupN a/drivers/usb/dwc2/hcd_ddma.c b/drivers/usb/dwc2/hcd_ddma.c +--- a/drivers/usb/dwc2/hcd_ddma.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/usb/dwc2/hcd_ddma.c 2022-06-09 05:02:34.000000000 +0300 +@@ -524,12 +524,13 @@ static void dwc2_fill_host_isoc_dma_desc + dma_desc->status = qh->n_bytes[idx] << HOST_DMA_ISOC_NBYTES_SHIFT & + HOST_DMA_ISOC_NBYTES_MASK; + ++ dma_desc->status |= HOST_DMA_A; + #ifdef ISOC_URB_GIVEBACK_ASAP + /* Set IOC for each descriptor corresponding to last frame of URB */ +- if (qtd->isoc_frame_index_last == qtd->urb->packet_count) ++ if (qtd->isoc_frame_index_last == qtd->urb->packet_count-1){ + dma_desc->status |= HOST_DMA_IOC; ++ } + #endif +- + qh->ntd++; + qtd->isoc_frame_index_last++; + } +@@ -558,8 +559,6 @@ static void dwc2_init_isoc_dma_desc(stru + list_for_each_entry(qtd, &qh->qtd_list, qtd_list_entry) { + while (qh->ntd < ntd_max && qtd->isoc_frame_index_last < + qtd->urb->packet_count) { +- if (n_desc > 1) +- qh->desc_list[n_desc - 1].status |= HOST_DMA_A; + dwc2_fill_host_isoc_dma_desc(hsotg, qtd, qh, + max_xfer_size, idx); + idx = dwc2_desclist_idx_inc(idx, inc, qh->dev_speed); +@@ -808,7 +807,8 @@ static int dwc2_cmpl_host_isoc_dma_desc( + if (!qtd->urb) + return -EINVAL; + +- frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index_last]; ++ frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index]; ++ + dma_desc->buf = (u32)(qtd->urb->dma + frame_desc->offset); + if (chan->ep_is_in) + remain = (dma_desc->status & HOST_DMA_ISOC_NBYTES_MASK) >> +@@ -854,6 +854,7 @@ static int dwc2_cmpl_host_isoc_dma_desc( + if (dma_desc->status & HOST_DMA_IOC) + rc = DWC2_CMPL_STOP; + ++ dma_desc->status = 0; + return rc; + } + diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_dwc2_hcd_intr.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_dwc2_hcd_intr.c.patch new file mode 100644 index 00000000..d5e39529 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_dwc2_hcd_intr.c.patch @@ -0,0 +1,15 @@ +diff -drupN a/drivers/usb/dwc2/hcd_intr.c b/drivers/usb/dwc2/hcd_intr.c +--- a/drivers/usb/dwc2/hcd_intr.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/usb/dwc2/hcd_intr.c 2022-06-09 05:02:34.000000000 +0300 +@@ -102,6 +102,11 @@ static void dwc2_hc_handle_tt_clear(stru + if (!usb_urb || !usb_urb->dev || !usb_urb->dev->tt) + return; + ++ WARN_ON(!usb_urb->dev->tt->hub); ++ if (usb_urb->dev->tt->hub == ++ dwc2_hsotg_to_hcd(hsotg)->self.root_hub) ++ return; ++ + if (qtd->urb->status != -EPIPE && qtd->urb->status != -EREMOTEIO) { + chan->qh->tt_buffer_dirty = 1; + if (usb_hub_clear_tt_buffer(usb_urb)) diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_dwc2_hcd_queue.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_dwc2_hcd_queue.c.patch new file mode 100644 index 00000000..cd74dd08 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_dwc2_hcd_queue.c.patch @@ -0,0 +1,20 @@ +diff -drupN a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c +--- a/drivers/usb/dwc2/hcd_queue.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/usb/dwc2/hcd_queue.c 2022-06-09 05:02:34.000000000 +0300 +@@ -578,7 +578,6 @@ int dwc2_hcd_qh_add(struct dwc2_hsotg *h + { + int status; + u32 intr_mask; +- + if (dbg_qh(qh)) + dev_vdbg(hsotg->dev, "%s()\n", __func__); + +@@ -605,7 +604,7 @@ int dwc2_hcd_qh_add(struct dwc2_hsotg *h + status = dwc2_schedule_periodic(hsotg, qh); + if (status) + return status; +- if (!hsotg->periodic_qh_count) { ++ if ((!hsotg->periodic_qh_count)&&(!hsotg->core_params->dma_desc_enable)) { + intr_mask = dwc2_readl(hsotg->regs + GINTMSK); + intr_mask |= GINTSTS_SOF; + dwc2_writel(intr_mask, hsotg->regs + GINTMSK); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_dwc2_hw.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_dwc2_hw.h.patch new file mode 100644 index 00000000..83ab9a12 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_dwc2_hw.h.patch @@ -0,0 +1,12 @@ +diff -drupN a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h +--- a/drivers/usb/dwc2/hw.h 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/usb/dwc2/hw.h 2022-06-09 05:02:34.000000000 +0300 +@@ -52,6 +52,8 @@ + #define GOTGCTL_HSTSETHNPEN (1 << 10) + #define GOTGCTL_HNPREQ (1 << 9) + #define GOTGCTL_HSTNEGSCS (1 << 8) ++#define GOTGCTL_VBVALIDOVVAL (1 << 3) ++#define GOTGCTL_VBVALIDOVEN (1 << 2) + #define GOTGCTL_SESREQ (1 << 1) + #define GOTGCTL_SESREQSCS (1 << 0) + diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_dwc2_platform.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_dwc2_platform.c.patch new file mode 100644 index 00000000..f57f9cc7 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_dwc2_platform.c.patch @@ -0,0 +1,260 @@ +diff -drupN a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c +--- a/drivers/usb/dwc2/platform.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/usb/dwc2/platform.c 2022-06-09 05:02:34.000000000 +0300 +@@ -54,52 +54,28 @@ + + static const char dwc2_driver_name[] = "dwc2"; + +-static const struct dwc2_core_params params_bcm2835 = { +- .otg_cap = 0, /* HNP/SRP capable */ +- .otg_ver = 0, /* 1.3 */ +- .dma_enable = 1, +- .dma_desc_enable = 0, +- .speed = 0, /* High Speed */ +- .enable_dynamic_fifo = 1, +- .en_multiple_tx_fifo = 1, +- .host_rx_fifo_size = 774, /* 774 DWORDs */ +- .host_nperio_tx_fifo_size = 256, /* 256 DWORDs */ +- .host_perio_tx_fifo_size = 512, /* 512 DWORDs */ +- .max_transfer_size = 65535, +- .max_packet_count = 511, +- .host_channels = 8, +- .phy_type = 1, /* UTMI */ +- .phy_utmi_width = 8, /* 8 bits */ +- .phy_ulpi_ddr = 0, /* Single */ +- .phy_ulpi_ext_vbus = 0, +- .i2c_enable = 0, +- .ulpi_fs_ls = 0, +- .host_support_fs_ls_low_power = 0, +- .host_ls_low_power_phy_clk = 0, /* 48 MHz */ +- .ts_dline = 0, +- .reload_ctl = 0, +- .ahbcfg = 0x10, +- .uframe_sched = 0, +- .external_id_pin_ctl = -1, +- .hibernation = -1, +-}; ++static const struct dwc2_core_params params_jz4780 = { ++ .otg_cap = 2, ++ .otg_ver = 1, ++ .dma_enable = 1, /* DMA Enabled */ ++#ifdef CONFIG_USB_DWC2_DMA_BUFFER_MODE ++ .dma_desc_enable = 0, ++#endif ++#ifdef CONFIG_USB_DWC2_DMA_DESCRIPTOR_MODE ++ .dma_desc_enable = 1, ++#endif + +-static const struct dwc2_core_params params_rk3066 = { +- .otg_cap = 2, /* non-HNP/non-SRP */ +- .otg_ver = -1, +- .dma_enable = -1, +- .dma_desc_enable = 0, + .speed = -1, +- .enable_dynamic_fifo = 1, ++ .enable_dynamic_fifo = -1, + .en_multiple_tx_fifo = -1, +- .host_rx_fifo_size = 520, /* 520 DWORDs */ +- .host_nperio_tx_fifo_size = 128, /* 128 DWORDs */ +- .host_perio_tx_fifo_size = 256, /* 256 DWORDs */ +- .max_transfer_size = 65535, ++ .host_rx_fifo_size = 1024, /* 1024 DWORDs */ ++ .host_nperio_tx_fifo_size = 1024, /* 1024 DWORDs */ ++ .host_perio_tx_fifo_size = 1024, /* 1024 DWORDs */ ++ .max_transfer_size = -1, + .max_packet_count = -1, + .host_channels = -1, + .phy_type = -1, +- .phy_utmi_width = -1, ++ .phy_utmi_width = 16, + .phy_ulpi_ddr = -1, + .phy_ulpi_ext_vbus = -1, + .i2c_enable = -1, +@@ -108,39 +84,26 @@ static const struct dwc2_core_params par + .host_ls_low_power_phy_clk = -1, + .ts_dline = -1, + .reload_ctl = -1, +- .ahbcfg = GAHBCFG_HBSTLEN_INCR16 << +- GAHBCFG_HBSTLEN_SHIFT, ++ .ahbcfg = -1, + .uframe_sched = -1, + .external_id_pin_ctl = -1, +- .hibernation = -1, ++ .hibernation = 0, + }; + + static int __dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg) + { +- struct platform_device *pdev = to_platform_device(hsotg->dev); + int ret; + +- ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies), +- hsotg->supplies); +- if (ret) +- return ret; +- + if (hsotg->clk) { + ret = clk_prepare_enable(hsotg->clk); + if (ret) + return ret; ++ printk("OTG CLK %x\n", *(volatile unsigned int *)(0xb0000020)); + } + + if (hsotg->uphy) + ret = usb_phy_init(hsotg->uphy); +- else if (hsotg->plat && hsotg->plat->phy_init) +- ret = hsotg->plat->phy_init(pdev, hsotg->plat->phy_type); +- else { +- ret = phy_power_on(hsotg->phy); +- if (ret == 0) +- ret = phy_init(hsotg->phy); +- } +- ++ printk("CPCCR CLK %x\n", *(volatile unsigned int *)(0xb0000024)); + return ret; + } + +@@ -162,27 +125,14 @@ int dwc2_lowlevel_hw_enable(struct dwc2_ + + static int __dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg) + { +- struct platform_device *pdev = to_platform_device(hsotg->dev); + int ret = 0; + + if (hsotg->uphy) + usb_phy_shutdown(hsotg->uphy); +- else if (hsotg->plat && hsotg->plat->phy_exit) +- ret = hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type); +- else { +- ret = phy_exit(hsotg->phy); +- if (ret == 0) +- ret = phy_power_off(hsotg->phy); +- } +- if (ret) +- return ret; + + if (hsotg->clk) + clk_disable_unprepare(hsotg->clk); + +- ret = regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), +- hsotg->supplies); +- + return ret; + } + +@@ -204,78 +154,35 @@ int dwc2_lowlevel_hw_disable(struct dwc2 + + static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg) + { +- int i, ret; ++ int ret; + + /* Set default UTMI width */ + hsotg->phyif = GUSBCFG_PHYIF16; + +- /* +- * Attempt to find a generic PHY, then look for an old style +- * USB PHY and then fall back to pdata +- */ +- hsotg->phy = devm_phy_get(hsotg->dev, "usb2-phy"); +- if (IS_ERR(hsotg->phy)) { +- ret = PTR_ERR(hsotg->phy); ++ hsotg->uphy = devm_usb_get_phy_by_phandle(hsotg->dev, "ingenic,usbphy", 0); ++ if (IS_ERR(hsotg->uphy)) { ++ ret = PTR_ERR(hsotg->uphy); + switch (ret) { + case -ENODEV: +- case -ENOSYS: +- hsotg->phy = NULL; ++ case -ENXIO: ++ hsotg->uphy = NULL; + break; + case -EPROBE_DEFER: + return ret; + default: +- dev_err(hsotg->dev, "error getting phy %d\n", ret); +- return ret; +- } +- } +- +- if (!hsotg->phy) { +- hsotg->uphy = devm_usb_get_phy(hsotg->dev, USB_PHY_TYPE_USB2); +- if (IS_ERR(hsotg->uphy)) { +- ret = PTR_ERR(hsotg->uphy); +- switch (ret) { +- case -ENODEV: +- case -ENXIO: +- hsotg->uphy = NULL; +- break; +- case -EPROBE_DEFER: +- return ret; +- default: +- dev_err(hsotg->dev, "error getting usb phy %d\n", ++ dev_err(hsotg->dev, "error getting usb phy %d\n", + ret); +- return ret; +- } ++ return ret; + } + } + + hsotg->plat = dev_get_platdata(hsotg->dev); + +- if (hsotg->phy) { +- /* +- * If using the generic PHY framework, check if the PHY bus +- * width is 8-bit and set the phyif appropriately. +- */ +- if (phy_get_bus_width(hsotg->phy) == 8) +- hsotg->phyif = GUSBCFG_PHYIF8; +- } +- +- /* Clock */ +- hsotg->clk = devm_clk_get(hsotg->dev, "otg"); ++ hsotg->clk = devm_clk_get(hsotg->dev, "gate_otg"); + if (IS_ERR(hsotg->clk)) { + hsotg->clk = NULL; + dev_dbg(hsotg->dev, "cannot get otg clock\n"); + } +- +- /* Regulators */ +- for (i = 0; i < ARRAY_SIZE(hsotg->supplies); i++) +- hsotg->supplies[i].supply = dwc2_hsotg_supply_names[i]; +- +- ret = devm_regulator_bulk_get(hsotg->dev, ARRAY_SIZE(hsotg->supplies), +- hsotg->supplies); +- if (ret) { +- dev_err(hsotg->dev, "failed to request supplies: %d\n", ret); +- return ret; +- } + return 0; + } + +@@ -299,7 +206,6 @@ static int dwc2_driver_remove(struct pla + dwc2_hcd_remove(hsotg); + if (hsotg->gadget_enabled) + dwc2_hsotg_remove(hsotg); +- + if (hsotg->ll_hw_enabled) + dwc2_lowlevel_hw_disable(hsotg); + +@@ -307,10 +213,7 @@ static int dwc2_driver_remove(struct pla + } + + static const struct of_device_id dwc2_of_match_table[] = { +- { .compatible = "brcm,bcm2835-usb", .data = ¶ms_bcm2835 }, +- { .compatible = "rockchip,rk3066-usb", .data = ¶ms_rk3066 }, +- { .compatible = "snps,dwc2", .data = NULL }, +- { .compatible = "samsung,s3c6400-hsotg", .data = NULL}, ++ { .compatible = "ingenic,dwc2-hsotg", .data = (void *)¶ms_jz4780}, + {}, + }; + MODULE_DEVICE_TABLE(of, dwc2_of_match_table); +@@ -444,6 +347,7 @@ static int dwc2_driver_probe(struct plat + hsotg->hcd_enabled = 1; + } + ++ + platform_set_drvdata(dev, hsotg); + + dwc2_debugfs_init(hsotg); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_gadget_function_uvc_configfs.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_gadget_function_uvc_configfs.c.patch new file mode 100644 index 00000000..8a966b20 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_gadget_function_uvc_configfs.c.patch @@ -0,0 +1,31 @@ +diff -drupN a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c +--- a/drivers/usb/gadget/function/uvc_configfs.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/usb/gadget/function/uvc_configfs.c 2022-06-09 05:02:34.000000000 +0300 +@@ -2202,7 +2202,7 @@ static struct configfs_item_operations u + .release = uvc_attr_release, + }; + +-#define UVCG_OPTS_ATTR(cname, conv, str2u, uxx, vnoc, limit) \ ++#define UVCG_OPTS_ATTR(cname, aname, conv, str2u, uxx, vnoc, limit) \ + static ssize_t f_uvc_opts_##cname##_show( \ + struct config_item *item, char *page) \ + { \ +@@ -2249,12 +2249,12 @@ UVC_ATTR(f_uvc_opts_, cname, aname) + + #define identity_conv(x) (x) + +-UVCG_OPTS_ATTR(streaming_interval, identity_conv, kstrtou8, u8, identity_conv, +- 16); +-UVCG_OPTS_ATTR(streaming_maxpacket, le16_to_cpu, kstrtou16, u16, le16_to_cpu, +- 3072); +-UVCG_OPTS_ATTR(streaming_maxburst, identity_conv, kstrtou8, u8, identity_conv, +- 15); ++UVCG_OPTS_ATTR(streaming_interval, streaming_interval, identity_conv, ++ kstrtou8, u8, identity_conv, 16); ++UVCG_OPTS_ATTR(streaming_maxpacket, streaming_maxpacket, le16_to_cpu, ++ kstrtou16, u16, le16_to_cpu, 3072); ++UVCG_OPTS_ATTR(streaming_maxburst, streaming_maxburst, identity_conv, ++ kstrtou8, u8, identity_conv, 15); + + #undef identity_conv + diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_phy_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_phy_Kconfig.patch new file mode 100644 index 00000000..d4b59256 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_phy_Kconfig.patch @@ -0,0 +1,37 @@ +diff -drupN a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig +--- a/drivers/usb/phy/Kconfig 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/usb/phy/Kconfig 2022-06-09 05:02:34.000000000 +0300 +@@ -77,6 +77,33 @@ config SAMSUNG_USBPHY + This driver provides common interface to interact, for Samsung USB 2.0 PHY + driver and later for Samsung USB 3.0 PHY driver. + ++choice ++ prompt "Ingenic usb Phy selects" ++ ++config INGENIC_USBPHY ++ tristate "Ingenic usb phy" ++ select USB_PHY ++ help ++ Enable this to support Ingenic USB phy helper driver for ingenic SoCs. ++ This driver provides common interface to interact, for ingenic USB 2.0 PHY ++ ++config INGENIC_USBPHY_X1800 ++ tristate "Ingenic usb phy for x1800" ++ select USB_PHY ++ help ++ Enable this to support Ingenic USB phy helper driver for ingenic SoCs. ++ This driver provides common interface to interact, for ingenic USB 2.0 PHY ++ ++config INGENIC_INNOPHY ++ tristate "Ingenic usb phy(INNO) implemented." ++ select USB_PHY ++ help ++ Enable this to support Ingenic USB phy helper driver for ingenic SoCs. ++ This driver provides common interface to interact, for ingenic Inno PHY, ++ typically used for X2000 SOCs. ++ ++endchoice ++ + config TWL6030_USB + tristate "TWL6030 USB Transceiver Driver" + depends on TWL4030_CORE && OMAP_USB2 && USB_MUSB_OMAP2PLUS diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_phy_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_phy_Makefile.patch new file mode 100644 index 00000000..608f928f --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_phy_Makefile.patch @@ -0,0 +1,10 @@ +diff -drupN a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile +--- a/drivers/usb/phy/Makefile 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/usb/phy/Makefile 2022-06-09 05:02:34.000000000 +0300 +@@ -27,3 +27,6 @@ obj-$(CONFIG_USB_RCAR_PHY) += phy-rcar- + obj-$(CONFIG_USB_ULPI) += phy-ulpi.o + obj-$(CONFIG_USB_ULPI_VIEWPORT) += phy-ulpi-viewport.o + obj-$(CONFIG_KEYSTONE_USB_PHY) += phy-keystone.o ++obj-$(CONFIG_INGENIC_USBPHY) += phy-ingenic-usb.o ++obj-$(CONFIG_INGENIC_USBPHY_X1800) += phy-ingenic-x1800.o ++obj-$(CONFIG_INGENIC_INNOPHY) += phy-ingenic-inno.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_phy_phy-ingenic-inno.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_phy_phy-ingenic-inno.c.patch new file mode 100644 index 00000000..0d7d1018 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_phy_phy-ingenic-inno.c.patch @@ -0,0 +1,552 @@ +diff -drupN a/drivers/usb/phy/phy-ingenic-inno.c b/drivers/usb/phy/phy-ingenic-inno.c +--- a/drivers/usb/phy/phy-ingenic-inno.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/usb/phy/phy-ingenic-inno.c 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,548 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define usb_phy_readb(addr) readb((addr)) ++#define usb_phy_writeb(val, addr) writeb(val,(addr)) ++ ++#define PHY_TX_HS_STRENGTH_CONF (0x40) ++#define PHY_EYES_MAP_ADJ_CONF (0x60) ++#define PHY_SUSPEND_LPM (0x108) ++ ++#define PHY_RX_SQU_TRI (0x64) ++#define PHY_RX_SQU_TRI_112MV (0x0) ++#define PHY_RX_SQU_TRI_125MV (0x8) ++ ++#define PHY_DETECT (0x70) ++#define PHY_OTG_SESSION (0x78) ++ ++struct ingenic_usb_phy { ++ struct usb_phy phy; ++ struct device *dev; ++ struct clk *gate_clk; ++ struct regmap *regmap; ++ void __iomem *base; ++ ++ /*otg phy*/ ++ spinlock_t phy_lock; ++ struct gpio_desc *gpiod_drvvbus; ++ struct gpio_desc *gpiod_id; ++ struct gpio_desc *gpiod_vbus; ++#define USB_DETE_VBUS 0x1 ++#define USB_DETE_ID 0x2 ++ unsigned int usb_dete_state; ++ struct delayed_work work; ++ ++ enum usb_device_speed roothub_port_speed; ++}; ++ ++static inline int inno_usbphy_read(struct usb_phy *x, u32 reg) ++{ ++ struct ingenic_usb_phy *iphy = container_of(x, struct ingenic_usb_phy, phy); ++ u32 val = 0; ++ regmap_read(iphy->regmap, reg, &val); ++ return val; ++} ++ ++static inline int inno_usbphy_write(struct usb_phy *x, u32 val, u32 reg) ++{ ++ struct ingenic_usb_phy *iphy = container_of(x, struct ingenic_usb_phy, phy); ++ ++ return regmap_write(iphy->regmap, reg, val); ++} ++ ++static inline int inno_usbphy_update_bits(struct usb_phy *x, u32 reg, u32 mask, u32 bits) ++{ ++ struct ingenic_usb_phy *iphy = container_of(x, struct ingenic_usb_phy, phy); ++ ++ return regmap_update_bits_check(iphy->regmap, reg, mask, bits, NULL); ++} ++ ++static irqreturn_t usb_dete_irq_handler(int irq, void *data) ++{ ++ struct ingenic_usb_phy *iphy = (struct ingenic_usb_phy *)data; ++ ++ schedule_delayed_work(&iphy->work, msecs_to_jiffies(100)); ++ return IRQ_HANDLED; ++} ++ ++static void usb_dete_work(struct work_struct *work) ++{ ++ struct ingenic_usb_phy *iphy = ++ container_of(work, struct ingenic_usb_phy, work.work); ++ struct usb_otg *otg = iphy->phy.otg; ++ int vbus = 0, id_level = 1, usb_state = 0; ++ ++ if (iphy->gpiod_vbus) ++ vbus = gpiod_get_value_cansleep(iphy->gpiod_vbus); ++ ++ if (iphy->gpiod_id) ++ id_level = gpiod_get_value_cansleep(iphy->gpiod_id); ++ ++ if (vbus && id_level) ++ usb_state |= USB_DETE_VBUS; ++ else ++ usb_state &= ~USB_DETE_VBUS; ++ ++ if (id_level) ++ usb_state |= USB_DETE_ID; ++ else ++ usb_state &= ~USB_DETE_ID; ++ ++ if (usb_state != iphy->usb_dete_state) { ++ enum usb_phy_events status; ++ if (!(usb_state & USB_DETE_VBUS)) { ++ status = USB_EVENT_NONE; ++ otg->state = OTG_STATE_B_IDLE; ++ iphy->phy.last_event = status; ++ if (otg->gadget){ ++ usb_gadget_vbus_disconnect(otg->gadget); ++ atomic_notifier_call_chain(&iphy->phy.notifier, status, ++ otg->gadget); ++ } ++ } ++ ++ if (!(usb_state & USB_DETE_ID)) { ++ status = USB_EVENT_ID; ++ otg->state = OTG_STATE_A_IDLE; ++ iphy->phy.last_event = status; ++ if (otg->host) ++ atomic_notifier_call_chain(&iphy->phy.notifier, status, ++ otg->host); ++ } ++ ++ if (usb_state & USB_DETE_VBUS) { ++ status = USB_EVENT_VBUS; ++ otg->state = OTG_STATE_B_PERIPHERAL; ++ iphy->phy.last_event = status; ++ if (otg->gadget){ ++ usb_gadget_vbus_connect(otg->gadget); ++ atomic_notifier_call_chain(&iphy->phy.notifier, status, ++ otg->gadget); ++ } ++ } ++ iphy->usb_dete_state = usb_state; ++ } ++ return; ++} ++ ++static int iphy_init(struct usb_phy *x) ++{ ++ struct ingenic_usb_phy *iphy = container_of(x, struct ingenic_usb_phy, phy); ++ u32 usbpcr, usbpcr1; ++ unsigned long flags; ++ u8 reg; ++ ++ if (!IS_ERR_OR_NULL(iphy->gate_clk)) ++ clk_prepare_enable(iphy->gate_clk); ++ ++ spin_lock_irqsave(&iphy->phy_lock, flags); ++ ++ usbpcr1 = inno_usbphy_read(x, CPM_USBPCR1); ++ usbpcr1 |= USBPCR1_DPPULLDOWN | USBPCR1_DMPULLDOWN; ++ inno_usbphy_write(x, usbpcr1, CPM_USBPCR1); ++ ++ usbpcr = inno_usbphy_read(x, CPM_USBPCR); ++ usbpcr &= ~USBPCR_IDPULLUP_MASK; ++#if IS_ENABLED(CONFIG_USB_DWC2_HOST) ++ usbpcr |= USBPCR_USB_MODE | USBPCR_IDPULLUP_OTG; ++#elif IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) ++ usbpcr &= ~USBPCR_USB_MODE; ++#endif ++ inno_usbphy_write(x, usbpcr, CPM_USBPCR); ++ ++ inno_usbphy_update_bits(x, CPM_USBPCR1, USBPCR1_PORT_RST, USBPCR1_PORT_RST); ++ ++ inno_usbphy_update_bits(x, CPM_USBRDT, USBRDT_UTMI_RST, 0); ++ inno_usbphy_update_bits(x, CPM_USBPCR, USBPCR_POR, USBPCR_POR); ++ inno_usbphy_update_bits(x, CPM_SRBC, SRBC_USB_SR, SRBC_USB_SR); ++ udelay(5); ++ inno_usbphy_update_bits(x, CPM_USBPCR, USBPCR_POR, 0); ++ udelay(10); ++ inno_usbphy_update_bits(x, CPM_OPCR, OPCR_USB_SPENDN, OPCR_USB_SPENDN); ++ udelay(550); ++ inno_usbphy_update_bits(x, CPM_USBRDT, USBRDT_UTMI_RST, USBRDT_UTMI_RST); ++ udelay(10); ++ inno_usbphy_update_bits(x, CPM_SRBC, SRBC_USB_SR, 0); ++ ++ reg = usb_phy_readb(iphy->base + PHY_RX_SQU_TRI); ++ reg &= ~(0xf << 3); ++ reg |= PHY_RX_SQU_TRI_125MV << 3; ++ usb_phy_writeb(reg,iphy->base + PHY_RX_SQU_TRI); ++ ++ reg = usb_phy_readb(iphy->base + PHY_OTG_SESSION); ++ reg |=0x20; ++ usb_phy_writeb(reg,iphy->base + PHY_OTG_SESSION); ++ reg = usb_phy_readb(iphy->base + PHY_DETECT); ++ reg &= ~0x8; ++ usb_phy_writeb(reg,iphy->base + PHY_DETECT); ++ ++ spin_unlock_irqrestore(&iphy->phy_lock, flags); ++ return 0; ++} ++ ++static int iphy_set_suspend(struct usb_phy *x, int suspend); ++static void iphy_shutdown(struct usb_phy *x) ++{ ++ struct ingenic_usb_phy *iphy = container_of(x, struct ingenic_usb_phy, phy); ++ iphy_set_suspend(x, 1); ++ ++ if (!IS_ERR_OR_NULL(iphy->gate_clk)) ++ clk_disable_unprepare(iphy->gate_clk); ++} ++ ++static int iphy_set_vbus(struct usb_phy *x, int on) ++{ ++ struct ingenic_usb_phy *iphy = container_of(x, struct ingenic_usb_phy, phy); ++ ++ if (!(IS_ERR_OR_NULL(iphy->gpiod_drvvbus))) { ++ printk("OTG VBUS %s\n", on ? "ON" : "OFF"); ++ gpiod_set_value(iphy->gpiod_drvvbus, on); ++ } ++ return 0; ++} ++ ++static int iphy_set_wakeup(struct usb_phy *x, bool enabled); ++static int iphy_set_suspend(struct usb_phy *x, int suspend) ++{ ++ struct ingenic_usb_phy *iphy = container_of(x, struct ingenic_usb_phy, phy); ++ unsigned long flags; ++#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) ++ struct usb_otg *otg = iphy->phy.otg; ++ enum usb_device_speed speed; ++ unsigned int usbrdt; ++ unsigned int cpm_opcr; ++ unsigned int cpm_clkgr; ++ unsigned int cpm_usbpcr1; ++#endif ++ ++ spin_lock_irqsave(&iphy->phy_lock, flags); ++#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) ++ if(suspend){ ++ cpm_usbpcr1 = inno_usbphy_read(x, CPM_USBPCR1); ++ cpm_usbpcr1 &= ~(1 << 30); ++ inno_usbphy_write(x, cpm_usbpcr1, CPM_USBPCR1); ++ ++ usbrdt = inno_usbphy_read(x, CPM_USBRDT); ++ usbrdt &= ~USBRDT_RESUME_SPEED_MSK; ++ speed = (otg && otg->gadget) ? otg->gadget->speed : USB_SPEED_FULL; ++ if(speed == USB_SPEED_FULL) ++ usbrdt |= USBRDT_RESUME_SPEED_FULL; ++ if(speed == USB_SPEED_LOW) ++ usbrdt |= USBRDT_RESUME_SPEED_LOW; ++ //TODO: the function be in suspend. ++ //usbrdt |= USBRDT_RESUME_INTEEN; ++ inno_usbphy_write(x, usbrdt, CPM_USBRDT); ++ ++ usb_phy_writeb(0x8,iphy->base + PHY_SUSPEND_LPM); ++ ++ cpm_opcr =inno_usbphy_read(x,CPM_OPCR); ++ cpm_opcr &= ~OPCR_USB_SPENDN; ++ inno_usbphy_write(x,cpm_opcr,CPM_OPCR); ++ ++ udelay(10); ++ ++ cpm_opcr =inno_usbphy_read(x,CPM_OPCR); ++ cpm_opcr |= OPCR_USB_PHY_GATE; ++ inno_usbphy_write(x,cpm_opcr,CPM_OPCR); ++ ++ cpm_clkgr =inno_usbphy_read(x,CPM_CLKGR); ++ cpm_clkgr |= (1 << 3); ++ inno_usbphy_write(x,cpm_clkgr,CPM_CLKGR); ++ } ++ ++ if(!suspend) ++ iphy_set_wakeup(x, true); ++#else ++ if (suspend) ++ inno_usbphy_update_bits(x, CPM_OPCR, USBPCR1_PORT_RST, 0); ++ ++ inno_usbphy_update_bits(x, CPM_OPCR, OPCR_USB_SPENDN, ++ suspend ? 0 : OPCR_USB_SPENDN); ++ if (!suspend) { ++ udelay(501); /*500us and 10 utmi clock*/ ++ inno_usbphy_update_bits(x, CPM_OPCR, USBPCR1_PORT_RST, USBPCR1_PORT_RST); ++ udelay(1); /*1 us*/ ++ inno_usbphy_update_bits(x, CPM_OPCR, USBPCR1_PORT_RST, 0); ++ } ++ udelay(1); /*1us*/ ++#endif ++ spin_unlock_irqrestore(&iphy->phy_lock, flags); ++ ++ return 0; ++} ++ ++static int iphy_set_wakeup(struct usb_phy *x, bool enabled) ++{ ++ struct ingenic_usb_phy *iphy = container_of(x, struct ingenic_usb_phy, phy); ++ struct usb_otg *otg = iphy->phy.otg; ++ enum usb_device_speed speed; ++ unsigned long flags; ++#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) ++ int timeout; ++ unsigned int usbrdt; ++ unsigned int cpm_opcr; ++ unsigned int cpm_clkgr; ++ unsigned int cpm_usbpcr1; ++#endif ++ spin_lock_irqsave(&iphy->phy_lock, flags); ++ ++#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) ++ if (enabled) { ++ /*enable usb resume interrupt*/ ++ if (otg && otg->state >= OTG_STATE_A_IDLE) ++ speed = iphy->roothub_port_speed; ++ else ++ speed = (otg && otg->gadget) ? otg->gadget->speed : USB_SPEED_FULL; ++ ++ usbrdt = inno_usbphy_read(x, CPM_USBRDT); ++ if(usbrdt & (USBRDT_RESUME_STATUS)){ ++ usbrdt |= USBRDT_RESUME_INTERCLR; ++ inno_usbphy_write(x, usbrdt, CPM_USBRDT); ++ timeout = 100; ++ while(1){ ++ if(timeout-- < 0){ ++ printk("%s:%d resume interrupt clear failed\n", __func__, __LINE__); ++ return -EAGAIN; ++ } ++ usbrdt = inno_usbphy_read(x, CPM_USBRDT); ++ if(!(usbrdt & (USBRDT_RESUME_STATUS))) ++ break; ++ } ++ } ++ ++ cpm_opcr = inno_usbphy_read(x, CPM_OPCR); ++ cpm_opcr &= ~OPCR_USB_PHY_GATE; ++ inno_usbphy_write(x,cpm_opcr, CPM_OPCR); ++ ++ cpm_opcr = inno_usbphy_read(x, CPM_OPCR); ++ cpm_opcr |= OPCR_USB_SPENDN; ++ inno_usbphy_write(x,cpm_opcr, CPM_OPCR); ++ ++ udelay(501); ++ ++ cpm_usbpcr1 = inno_usbphy_read(x, CPM_USBPCR1); ++ cpm_usbpcr1 |= USBPCR1_PORT_RST; ++ inno_usbphy_write(x,cpm_usbpcr1, CPM_USBPCR1); ++ ++ udelay(2); ++ ++ cpm_usbpcr1 = inno_usbphy_read(x, CPM_USBPCR1); ++ cpm_usbpcr1 &= ~USBPCR1_PORT_RST; ++ inno_usbphy_write(x,cpm_usbpcr1, CPM_USBPCR1); ++ ++ udelay(1); ++ ++ cpm_clkgr = inno_usbphy_read(x, CPM_CLKGR); ++ cpm_clkgr &= ~(1 << 3); ++ inno_usbphy_write(x,cpm_clkgr, CPM_CLKGR); ++ ++ usb_phy_writeb(0x0,iphy->base + PHY_SUSPEND_LPM); ++ ++ } else { ++ /*disable usb resume interrupt*/ ++ inno_usbphy_update_bits(x, CPM_USBRDT, USBRDT_RESUME_INTEEN|USBRDT_RESUME_INTERCLR, ++ USBRDT_RESUME_INTERCLR); ++ } ++#else ++ if (enabled) { ++ /*enable usb resume interrupt*/ ++ if (otg && otg->state >= OTG_STATE_A_IDLE) ++ speed = iphy->roothub_port_speed; ++ else ++ speed = (otg && otg->gadget) ? otg->gadget->speed : USB_SPEED_FULL; ++ inno_usbphy_update_bits(x, CPM_USBRDT, USBRDT_RESUME_INTEEN, USBRDT_RESUME_INTEEN); ++ } else { ++ /*disable usb resume interrupt*/ ++ inno_usbphy_update_bits(x, CPM_USBRDT, USBRDT_RESUME_INTEEN|USBRDT_RESUME_INTERCLR, ++ USBRDT_RESUME_INTERCLR); ++ } ++#endif ++ spin_unlock_irqrestore(&iphy->phy_lock, flags); ++ return 0; ++} ++ ++static int iphy_set_host(struct usb_otg *otg, struct usb_bus *host) ++{ ++ if (!otg) ++ return -ENODEV; ++ otg->host = host; ++ return 0; ++} ++ ++static int iphy_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget) ++{ ++ if (!otg) ++ return -ENODEV; ++ ++ otg->gadget = gadget; ++#ifdef CONFIG_USB_DWC2_DETECT_CONNECT ++ if(gadget){ ++ struct ingenic_usb_phy *iphy = container_of(otg->usb_phy, struct ingenic_usb_phy, phy); ++ iphy->usb_dete_state = ~iphy->usb_dete_state; ++ schedule_delayed_work(&iphy->work, msecs_to_jiffies(100)); ++} ++#endif ++ return 0; ++} ++ ++static int iphy_notify_connect(struct usb_phy *x, ++ enum usb_device_speed speed) ++{ ++ struct ingenic_usb_phy *iphy = container_of(x, struct ingenic_usb_phy, phy); ++ ++ iphy->roothub_port_speed = speed; ++ ++ return 0; ++} ++ ++static int usb_phy_ingenic_probe(struct platform_device *pdev) ++{ ++ struct ingenic_usb_phy *iphy; ++ struct resource *res; ++ int ret; ++ int vbus; ++ ++ iphy = (struct ingenic_usb_phy *) ++ devm_kzalloc(&pdev->dev, sizeof(*iphy), GFP_KERNEL); ++ if (!iphy) ++ return -ENOMEM; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 1); ++ iphy->base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(iphy->base)) ++ return PTR_ERR(iphy->base); ++ ++ iphy->phy.init = iphy_init; ++ iphy->phy.shutdown = iphy_shutdown; ++ iphy->phy.dev = &pdev->dev; ++ iphy->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, NULL); ++ if (IS_ERR(iphy->regmap)) { ++ dev_err(&pdev->dev, "failed to find regmap for usb phy %ld\n", PTR_ERR(iphy->regmap)); ++ return PTR_ERR(iphy->regmap); ++ } ++ ++ spin_lock_init(&iphy->phy_lock); ++ ++ iphy->gpiod_id = devm_gpiod_get_optional(&pdev->dev,"ingenic,id-dete", GPIOD_IN); ++ iphy->gpiod_vbus = devm_gpiod_get_optional(&pdev->dev,"ingenic,vbus-dete", GPIOD_ASIS); ++ if (iphy->gpiod_id || iphy->gpiod_vbus) ++ INIT_DELAYED_WORK(&iphy->work, usb_dete_work); ++ ++ if (!IS_ERR_OR_NULL(iphy->gpiod_id)) { ++ ret = devm_request_irq(&pdev->dev, ++ gpiod_to_irq(iphy->gpiod_id), ++ usb_dete_irq_handler, ++ IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING|IRQF_ONESHOT, ++ "id_dete", ++ (void *)iphy); ++ if (ret) ++ return ret; ++ } else { ++ iphy->usb_dete_state |= USB_DETE_ID; ++ iphy->gpiod_id = NULL; ++ } ++ ++ if (!IS_ERR_OR_NULL(iphy->gpiod_vbus)) { ++ ret = devm_request_irq(&pdev->dev, ++ gpiod_to_irq(iphy->gpiod_vbus), ++ usb_dete_irq_handler, ++ IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING|IRQF_ONESHOT, ++ "vbus_dete", ++ (void *)iphy); ++ if (ret) ++ return ret; ++ vbus = gpiod_get_value_cansleep(iphy->gpiod_vbus); ++ if(vbus) ++ iphy->usb_dete_state |= USB_DETE_VBUS; ++ else ++ iphy->usb_dete_state &= ~USB_DETE_VBUS; ++ } else { ++ iphy->usb_dete_state &= ~USB_DETE_VBUS; ++ iphy->gpiod_vbus = NULL; ++ } ++ ++ iphy->gpiod_drvvbus = devm_gpiod_get_optional(&pdev->dev,"ingenic,drvvbus", GPIOD_OUT_LOW); ++ if (IS_ERR_OR_NULL(iphy->gpiod_drvvbus)) ++ iphy->gpiod_drvvbus = NULL; ++ iphy->phy.set_vbus = iphy_set_vbus; ++ iphy->phy.set_suspend = iphy_set_suspend; ++ iphy->phy.set_wakeup = iphy_set_wakeup; ++ iphy->phy.notify_connect = iphy_notify_connect; ++ iphy->phy.otg = devm_kzalloc(&pdev->dev, sizeof(*iphy->phy.otg), ++ GFP_KERNEL); ++ ++ if (!iphy->phy.otg) ++ return -ENOMEM; ++ ++ iphy->phy.otg->state = OTG_STATE_UNDEFINED; ++ iphy->phy.otg->usb_phy = &iphy->phy; ++ iphy->phy.otg->set_host = iphy_set_host; ++ iphy->phy.otg->set_peripheral = iphy_set_peripheral; ++ ++ iphy->gate_clk = devm_clk_get(&pdev->dev, "gate_usbphy"); ++ if (IS_ERR_OR_NULL(iphy->gate_clk)){ ++ iphy->gate_clk = NULL; ++ dev_err(&pdev->dev, "cannot get usbphy clock !\n"); ++ return -ENODEV; ++ } ++ ++ ret = usb_add_phy_dev(&iphy->phy); ++ if (ret) { ++ dev_err(&pdev->dev, "can't register transceiver, err: %d\n", ++ ret); ++ return ret; ++ } ++ platform_set_drvdata(pdev, iphy); ++ pr_info("inno phy probe success\n"); ++ return 0; ++} ++ ++static int usb_phy_ingenic_remove(struct platform_device *pdev) ++{ ++ struct ingenic_usb_phy *iphy = platform_get_drvdata(pdev); ++ ++ usb_remove_phy(&iphy->phy); ++ return 0; ++} ++ ++static const struct of_device_id of_matchs[] = { ++ { .compatible = "ingenic,innophy"}, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, ingenic_xceiv_dt_ids); ++ ++static struct platform_driver usb_phy_ingenic_driver = { ++ .probe = usb_phy_ingenic_probe, ++ .remove = usb_phy_ingenic_remove, ++ .driver = { ++ .name = "usb_phy", ++ .of_match_table = of_matchs, ++ }, ++}; ++ ++static int __init usb_phy_ingenic_init(void) ++{ ++ return platform_driver_register(&usb_phy_ingenic_driver); ++} ++subsys_initcall(usb_phy_ingenic_init); ++ ++static void __exit usb_phy_ingenic_exit(void) ++{ ++ platform_driver_unregister(&usb_phy_ingenic_driver); ++} ++module_exit(usb_phy_ingenic_exit); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_phy_phy-ingenic-usb.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_phy_phy-ingenic-usb.c.patch new file mode 100644 index 00000000..9465cb15 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_phy_phy-ingenic-usb.c.patch @@ -0,0 +1,434 @@ +diff -drupN a/drivers/usb/phy/phy-ingenic-usb.c b/drivers/usb/phy/phy-ingenic-usb.c +--- a/drivers/usb/phy/phy-ingenic-usb.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/usb/phy/phy-ingenic-usb.c 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,430 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++enum { ++ OTG_PHY = 0, ++ HOST_PHY ++}; ++ ++struct ingenic_usb_phy { ++ struct usb_phy phy; ++ struct device *dev; ++ unsigned long ext_rate; ++ struct clk *clk; ++ struct clk *gate_clk; ++ struct regmap *regmap; ++ ++ bool is_otg_phy; ++ ++ /*otg phy*/ ++ enum usb_dr_mode dr_mode; ++ struct gpio_desc *gpiod_drvvbus; ++ struct gpio_desc *gpiod_id; ++ struct gpio_desc *gpiod_vbus; ++#define USB_DETE_VBUS 0x1 ++#define USB_DETE_ID 0x2 ++ unsigned int usb_dete_state; ++ struct delayed_work work; ++ u32 usbpcr; ++ ++ /*uhc phy*/ ++ unsigned int has_inited; ++ u32 usbpcr1; ++}; ++ ++static inline int dwc_usbphy_read(struct usb_phy *x, u32 reg) ++{ ++ struct ingenic_usb_phy *jzphy = container_of(x, struct ingenic_usb_phy, phy); ++ u32 val = 0; ++ regmap_read(jzphy->regmap, reg, &val); ++ return val; ++} ++ ++static inline int dwc_usbphy_write(struct usb_phy *x, u32 val, u32 reg) ++{ ++ struct ingenic_usb_phy *jzphy = container_of(x, struct ingenic_usb_phy, phy); ++ ++ return regmap_write(jzphy->regmap, reg, val); ++} ++ ++static inline int dwc_usbphy_update_bits(struct usb_phy *x, u32 reg, u32 mask, u32 bits) ++{ ++ struct ingenic_usb_phy *jzphy = container_of(x, struct ingenic_usb_phy, phy); ++ ++ return regmap_update_bits_check(jzphy->regmap, reg, mask, bits, NULL); ++} ++ ++static irqreturn_t usb_dete_irq_handler(int irq, void *data) ++{ ++ struct ingenic_usb_phy *jzphy = (struct ingenic_usb_phy *)data; ++ ++ schedule_delayed_work(&jzphy->work, msecs_to_jiffies(100)); ++ return IRQ_HANDLED; ++} ++ ++static void usb_dete_work(struct work_struct *work) ++{ ++ struct ingenic_usb_phy *jzphy = ++ container_of(work, struct ingenic_usb_phy, work.work); ++ struct usb_otg *otg = jzphy->phy.otg; ++ int vbus = 0, id_level = 1, usb_state = 0; ++ ++ if (jzphy->gpiod_vbus) ++ vbus = gpiod_get_value_cansleep(jzphy->gpiod_vbus); ++ ++ if (jzphy->gpiod_id) ++ id_level = gpiod_get_value_cansleep(jzphy->gpiod_id); ++ ++ if (vbus && id_level) ++ usb_state |= USB_DETE_VBUS; ++ else ++ usb_state &= ~USB_DETE_VBUS; ++ ++ if (id_level) ++ usb_state |= USB_DETE_ID; ++ else ++ usb_state &= ~USB_DETE_ID; ++ ++ if (usb_state != jzphy->usb_dete_state) { ++ enum usb_phy_events status; ++ if (!(usb_state & USB_DETE_VBUS)) { ++ usb_gadget_vbus_disconnect(otg->gadget); ++ status = USB_EVENT_NONE; ++ otg->state = OTG_STATE_B_IDLE; ++ jzphy->phy.last_event = status; ++ if (otg->gadget) ++ atomic_notifier_call_chain(&jzphy->phy.notifier, status, ++ otg->gadget); ++ } ++ ++ if (!(usb_state & USB_DETE_ID)) { ++ status = USB_EVENT_ID; ++ otg->state = OTG_STATE_A_IDLE; ++ jzphy->phy.last_event = status; ++ if (otg->host) ++ atomic_notifier_call_chain(&jzphy->phy.notifier, status, ++ otg->host); ++ } ++ ++ if (usb_state & USB_DETE_VBUS) { ++ status = USB_EVENT_VBUS; ++ otg->state = OTG_STATE_B_PERIPHERAL; ++ jzphy->phy.last_event = status; ++ usb_gadget_vbus_connect(otg->gadget); ++ if (otg->gadget) ++ atomic_notifier_call_chain(&jzphy->phy.notifier, status, ++ otg->gadget); ++ } ++ jzphy->usb_dete_state = usb_state; ++ } ++ return; ++} ++ ++static int jzphy_set_suspend(struct usb_phy *x, int suspend); ++static int jzphy_init(struct usb_phy *x) ++{ ++ struct ingenic_usb_phy *jzphy = container_of(x, struct ingenic_usb_phy, phy); ++ unsigned long rate, usb_clk_sel = USBPCR1_REFCLKDIV_24M; ++ u32 usbpcr, usbpcr1; ++ ++ if (!IS_ERR_OR_NULL(jzphy->clk)) { ++ switch (jzphy->ext_rate/1000000) { ++ case 12: ++ usb_clk_sel = USBPCR1_REFCLKDIV_12M; ++ break; ++ case 48: ++ rate = jzphy->ext_rate; ++ usb_clk_sel = USBPCR1_REFCLKDIV_48M; ++ break; ++ default: ++ case 24: ++ rate = 24000000; ++ usb_clk_sel = USBPCR1_REFCLKDIV_24M; ++ } ++ if (rate != clk_get_rate(jzphy->clk)) ++ clk_set_rate(jzphy->clk, rate); ++ clk_prepare_enable(jzphy->clk); ++ } ++ ++ if (!IS_ERR_OR_NULL(jzphy->gate_clk)) ++ clk_prepare_enable(jzphy->gate_clk); ++ ++ jzphy_set_suspend(x, 0); ++ ++ /* fil */ ++ dwc_usbphy_write(x, 0, CPM_USBVBFIL); ++ ++ /* rdt */ ++ dwc_usbphy_write(x, USBRDT_USBRDT(0x96) | USBRDT_VBFIL_LD_EN, CPM_USBRDT); ++ ++ if (jzphy->is_otg_phy) { ++ usbpcr = USBPCR_COMMONONN | USBPCR_VBUSVLDEXT | USBPCR_VBUSVLDEXTSEL | ++ USBPCR_SQRXTUNE(7) | USBPCR_TXPREEMPHTUNE | USBPCR_TXHSXVTUNE(1) | ++ USBPCR_TXVREFTUNE(7); ++ usbpcr1 = dwc_usbphy_read(x, CPM_USBPCR1); ++ usbpcr1 &= ~(USBPCR1_REFCLKDIV_MSK); ++ usbpcr1 = USBPCR1_REFCLKSEL | USBPCR1_REFCLKDIV(usb_clk_sel) | USBPCR1_WORD_IF_16BIT; ++ if (jzphy->dr_mode == USB_DR_MODE_PERIPHERAL) { ++ pr_info("DWC PHY IN DEVICE ONLY MODE\n"); ++ usbpcr1 |= USBPCR1_BVLD_REG; ++ usbpcr |= USBPCR_OTG_DISABLE; ++ } else { ++ pr_info("DWC PHY IN OTG MODE\n"); ++ usbpcr |= USBPCR_USB_MODE; ++ } ++ dwc_usbphy_write(x, usbpcr1, CPM_USBPCR1); ++ } else { ++ } ++ /** ++ * Power-On Reset(POR) ++ * Function:This customer-specific signal resets all test registers and state machines ++ * in the USB 2.0 nanoPHY. ++ * The POR signal must be asserted for a minimum of 10 μs. ++ * For POR timing information: ++ * ++ * T0: Power-on reset (POR) is initiated. 0 (reference) ++ * T1: T1 indicates when POR can be set to 1’b0. (To provide examples, values for T2 and T3 are also shown ++ * where T1 = T0 + 30 μs.); In general, T1 must be ≥ T0 + 10 μs. T0 + 10 μs ≤ T1 ++ * T2: T2 indicates when PHYCLOCK, CLK48MOHCI, and CLK12MOHCI are available at the macro output, based on ++ * the USB 2.0 nanoPHY reference clock source. ++ * Crystal: ++ • When T1 = T0 + 10 μs: ++ T2 < T1 + 805 μs = T0 + 815 μs ++ • When T1 = T0 + 30 μs: ++ T2 < T1 + 805 μs = T0 + 835 μs ++ * see "Reset and Power-Saving Signals" on page 60 an “Powering Up and Powering Down the USB 2.0 ++ * nanoPHY” on page 73. ++ */ ++ usbpcr |= USBPCR_POR; ++ dwc_usbphy_write(x, usbpcr, CPM_USBPCR); ++ mdelay(1); ++ usbpcr &= ~USBPCR_POR; ++ dwc_usbphy_write(x, usbpcr, CPM_USBPCR); ++ mdelay(1); ++ return 0; ++} ++ ++static void jzphy_shutdown(struct usb_phy *x) ++{ ++ ++ struct ingenic_usb_phy *jzphy = container_of(x, struct ingenic_usb_phy, phy); ++ ++ jzphy_set_suspend(x, 1); ++ ++ if (jzphy->is_otg_phy) ++ dwc_usbphy_update_bits(x, CPM_USBPCR, ++ USBPCR_OTG_DISABLE|USBPCR_SIDDQ, ++ USBPCR_OTG_DISABLE|USBPCR_SIDDQ); ++ if (!IS_ERR_OR_NULL(jzphy->clk)) ++ clk_disable_unprepare(jzphy->clk); ++ if (!IS_ERR_OR_NULL(jzphy->gate_clk)) ++ clk_disable_unprepare(jzphy->gate_clk); ++} ++ ++static int jzphy_set_vbus(struct usb_phy *x, int on) ++{ ++ struct ingenic_usb_phy *jzphy = container_of(x, struct ingenic_usb_phy, phy); ++ ++ printk("OTG VBUS %s\n", on ? "ON" : "OFF"); ++ gpiod_set_value(jzphy->gpiod_drvvbus, on); ++ return 0; ++} ++ ++static int jzphy_set_suspend(struct usb_phy *x, int suspend) ++{ ++ struct ingenic_usb_phy *jzphy = container_of(x, struct ingenic_usb_phy, phy); ++ int suspend_bit = jzphy->is_otg_phy ? OPCR_USB_SPENDN : OPCR_USB_SPENDN1; ++ ++ pr_debug("usb phy suspend %d suspend bit %x\n", suspend, suspend_bit); ++ dwc_usbphy_update_bits(x, CPM_OPCR, ++ suspend_bit, ++ suspend ? ~suspend_bit : suspend_bit); ++ udelay(suspend ? 5 : 45); ++ return 0; ++} ++ ++static int jzphy_set_wakeup(struct usb_phy *x, bool enabled) ++{ ++ return 0; ++} ++ ++static int jzphy_set_host(struct usb_otg *otg, struct usb_bus *host) ++{ ++ if (!otg) ++ return -ENODEV; ++ otg->host = host; ++ return 0; ++} ++ ++static int jzphy_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget) ++{ ++ if (!otg) ++ return -ENODEV; ++ otg->gadget = gadget; ++ return 0; ++} ++ ++static const struct of_device_id of_matchs[]; ++static int usb_phy_ingenic_probe(struct platform_device *pdev) ++{ ++ const struct of_device_id *match; ++ struct ingenic_usb_phy *jzphy; ++ bool is_otg_phy = false; ++ struct clk *clk; ++ int ret; ++ ++ match = of_match_device(of_matchs, &pdev->dev); ++ if (!match) ++ return -ENODEV; ++ ++ if ((int)match->data == OTG_PHY) ++ is_otg_phy = true; ++ ++ jzphy = (struct ingenic_usb_phy *) ++ devm_kzalloc(&pdev->dev, sizeof(*jzphy), GFP_KERNEL); ++ if (!jzphy) ++ return -ENOMEM; ++ ++ jzphy->phy.init = jzphy_init; ++ jzphy->phy.shutdown = jzphy_shutdown; ++ jzphy->phy.dev = &pdev->dev; ++ jzphy->is_otg_phy = is_otg_phy; ++ jzphy->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "ingenic,syscon"); ++ if (IS_ERR(jzphy->regmap)) { ++ dev_err(&pdev->dev, "failed to find regmap for usb phy\n"); ++ return PTR_ERR(jzphy->regmap); ++ } ++ ++ if (is_otg_phy) { ++ if (of_find_property(pdev->dev.of_node, "dr_mode", NULL)) ++ jzphy->dr_mode = usb_get_dr_mode(&pdev->dev); ++ else ++ jzphy->dr_mode = USB_DR_MODE_HOST; ++ ++ jzphy->gpiod_id = devm_gpiod_get_optional(&pdev->dev,"ingenic,id-dete", GPIOD_IN); ++ jzphy->gpiod_vbus = devm_gpiod_get_optional(&pdev->dev,"ingenic,vbus-dete", GPIOD_ASIS); ++ if (jzphy->gpiod_id || jzphy->gpiod_vbus) ++ INIT_DELAYED_WORK(&jzphy->work, usb_dete_work); ++ ++ if (!IS_ERR_OR_NULL(jzphy->gpiod_id)) { ++ ret = devm_request_irq(&pdev->dev, ++ gpiod_to_irq(jzphy->gpiod_id), ++ usb_dete_irq_handler, ++ IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING|IRQF_ONESHOT, ++ "id_dete", ++ (void *)jzphy); ++ if (ret) ++ return ret; ++ } else { ++ jzphy->usb_dete_state |= USB_DETE_ID; ++ jzphy->gpiod_id = NULL; ++ } ++ ++ if (!IS_ERR_OR_NULL(jzphy->gpiod_vbus)) { ++ ret = devm_request_irq(&pdev->dev, ++ gpiod_to_irq(jzphy->gpiod_vbus), ++ usb_dete_irq_handler, ++ IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING|IRQF_ONESHOT, ++ "vbus_dete", ++ (void *)jzphy); ++ if (ret) ++ return ret; ++ } else { ++ jzphy->usb_dete_state &= ~USB_DETE_VBUS; ++ jzphy->gpiod_vbus = NULL; ++ } ++ ++ jzphy->gpiod_drvvbus = devm_gpiod_get_optional(&pdev->dev,"ingenic,drvvbus", GPIOD_OUT_LOW); ++ if (IS_ERR_OR_NULL(jzphy->gpiod_drvvbus)) ++ jzphy->gpiod_drvvbus = NULL; ++ jzphy->phy.set_vbus = jzphy_set_vbus; ++ jzphy->phy.set_suspend = jzphy_set_suspend; ++ jzphy->phy.set_wakeup = jzphy_set_wakeup; ++ jzphy->phy.otg = devm_kzalloc(&pdev->dev, sizeof(*jzphy->phy.otg), ++ GFP_KERNEL); ++ if (!jzphy->phy.otg) ++ return -ENOMEM; ++ ++ jzphy->phy.otg->state = OTG_STATE_UNDEFINED; ++ jzphy->phy.otg->usb_phy = &jzphy->phy; ++ jzphy->phy.otg->set_host = jzphy_set_host; ++ jzphy->phy.otg->set_peripheral = jzphy_set_peripheral; ++ } ++ ++ jzphy->clk = devm_clk_get(&pdev->dev, "cgu_usb"); ++ if (IS_ERR_OR_NULL(jzphy->clk)) ++ return -ENODEV; ++ ++ jzphy->gate_clk = devm_clk_get(&pdev->dev, "gate_usbphy"); ++ if (IS_ERR_OR_NULL(jzphy->gate_clk)) ++ return -ENODEV; ++ ++ clk = clk_get(NULL, "ext"); ++ if (!IS_ERR_OR_NULL(clk)) { ++ jzphy->ext_rate = clk_get_rate(clk); ++ clk_put(clk); ++ } ++ ++ ret = usb_add_phy_dev(&jzphy->phy); ++ if (ret) { ++ dev_err(&pdev->dev, "can't register transceiver, err: %d\n", ++ ret); ++ return ret; ++ } ++ platform_set_drvdata(pdev, jzphy); ++ ++ return 0; ++} ++ ++static int usb_phy_ingenic_remove(struct platform_device *pdev) ++{ ++ struct ingenic_usb_phy *jzphy = platform_get_drvdata(pdev); ++ ++ usb_remove_phy(&jzphy->phy); ++ ++ clk_disable_unprepare(jzphy->clk); ++ return 0; ++} ++ ++static const struct of_device_id of_matchs[] = { ++ { .compatible = "ingenic,otgphy", .data = (void *)OTG_PHY}, ++ { .compatible = "ingenic,usbphy", .data = (void *)HOST_PHY}, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, ingenic_xceiv_dt_ids); ++ ++static struct platform_driver usb_phy_ingenic_driver = { ++ .probe = usb_phy_ingenic_probe, ++ .remove = usb_phy_ingenic_remove, ++ .driver = { ++ .name = "usb_phy", ++ .of_match_table = of_matchs, ++ }, ++}; ++ ++static int __init usb_phy_ingenic_init(void) ++{ ++ return platform_driver_register(&usb_phy_ingenic_driver); ++} ++subsys_initcall(usb_phy_ingenic_init); ++ ++static void __exit usb_phy_ingenic_exit(void) ++{ ++ platform_driver_unregister(&usb_phy_ingenic_driver); ++} ++module_exit(usb_phy_ingenic_exit); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_phy_phy-ingenic-x1800.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_phy_phy-ingenic-x1800.c.patch new file mode 100644 index 00000000..75d1b852 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_usb_phy_phy-ingenic-x1800.c.patch @@ -0,0 +1,511 @@ +diff -drupN a/drivers/usb/phy/phy-ingenic-x1800.c b/drivers/usb/phy/phy-ingenic-x1800.c +--- a/drivers/usb/phy/phy-ingenic-x1800.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/usb/phy/phy-ingenic-x1800.c 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,507 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#ifndef BIT ++#define BIT(nr) (1UL << nr) ++#endif ++ ++/*USB Parameter Control Register*/ ++#define USBPCR_USB_MODE BIT(31) ++#define USBPCR_AVLD_REG BIT(30) ++#define USBPCR_IDPULLUP_MASK_BIT 28 ++#define USBPCR_IDPULLUP_MASK_MSK (0x3 << USBPCR_IDPULLUP_MASK_BIT) ++#define USBPCR_IDPULLUP_OTG (0x0 << USBPCR_IDPULLUP_MASK_BIT) ++#define USBPCR_IDPULLUP_ALWAYS_SUSPEND (0x1 << USBPCR_IDPULLUP_MASK_BIT) ++#define USBPCR_IDPULLUP_ALWAYS (0x2 << USBPCR_IDPULLUP_MASK_BIT) ++#define USBPCR_INCR_MASK BIT(27) ++#define USBPCR_TXRISETUNE BIT(26) /*0*/ ++#define USBPCR_COMMONONN BIT(25) ++#define USBPCR_VBUSVLDEXT BIT(24) ++#define USBPCR_VBUSVLDEXTSEL BIT(23) ++#define USBPCR_POR_BIT 22 ++#define USBPCR_POR BIT(USBPCR_POR_BIT) ++#define USBPCR_SIDDQ BIT(21) ++#define USBPCR_OTG_DISABLE BIT(20) ++#define USBPCR_COMPDISTUNE_BIT 17 ++#define USBPCR_COMPDISTUNE_MSK (0x7 << USBPCR_COMPDISTUNE_BIT) ++#define USBPCR_COMPDISTUNE(x) (((x) << USBPCR_COMPDISTUNE_BIT) & USBPCR_COMPDISTUNE_MSK) /*4*/ ++#define USBPCR_OTGTUNE_BIT 14 ++#define USBPCR_OTGTUNE_MSK (0x7 << USBPCR_OTGTUNE_BIT) ++#define USBPCR_OTGTUNE(x) (((x) << USBPCR_OTGTUNE_BIT) & USBPCR_OTGTUNE_MSK) /*4*/ ++#define USBPCR_SQRXTUNE_BIT 11 ++#define USBPCR_SQRXTUNE_MSK (0x7 << USBPCR_SQRXTUNE_BIT) ++#define USBPCR_SQRXTUNE(x) (((x) << USBPCR_SQRXTUNE_BIT) & USBPCR_SQRXTUNE_MSK) /*3*/ ++#define USBPCR_TXFSLSTUNE_BIT 7 ++#define USBPCR_TXFSLSTUNE_MSK (0xf << USBPCR_TXFSLSTUNE_BIT) ++#define USBPCR_TXFSLSTUNE(x) (((x) << USBPCR_TXFSLSTUNE_BIT) & USBPCR_TXFSLSTUNE_MSK) /*2*/ ++#define USBPCR_TXPREEMPHTUNE BIT(6) /*0*/ ++#define USBPCR_TXHSXVTUNE_BIT 4 ++#define USBPCR_TXHSXVTUNE_MSK (0x3 << USBPCR_TXHSXVTUNE_BIT) ++#define USBPCR_TXHSXVTUNE(x) (((x) << USBPCR_TXHSXVTUNE_BIT) & USBPCR_TXHSXVTUNE_MSK) /*3*/ ++#define USBPCR_TXVREFTUNE_BIT 0 ++#define USBPCR_TXVREFTUNE_MSK (0xf << USBPCR_TXVREFTUNE_BIT) ++#define USBPCR_TXVREFTUNE(x) (((x) << USBPCR_TXVREFTUNE_BIT) & USBPCR_TXVREFTUNE_MSK) /*4*/ ++ ++/*USB Reset Detect Timer Register*/ ++#define USBRDT_HB_MASK BIT(26) ++#define USBRDT_VBFIL_LD_EN BIT(25) ++#define USBRDT_IDDIG_EN 24 ++#define USBRDT_IDDIG_REG 23 ++#define USBRDT_USBRDT_MSK (0x7fffff) ++#define USBRDT_USBRDT(x) ((x) & USBRDT_USBRDT_MSK) ++ ++/*USB VBUS Jitter Filter Register*/ ++#define USBVBFIL_USBVBFIL(x) ((x) & 0xffff) ++#define USBVBFIL_IDDIGFIL(x) ((x) & (0xffff << 16)) ++ ++/*USB Parameter Control Register1*/ ++#define USBPCR1_BVLD_REG BIT(31) ++#define USBPCR1_REFCLKSEL (0x2 << 26) ++#define USBPCR1_REFCLKDIV_MSK (0x7 << 23) ++#define USBPCR1_REFCLKDIV(x) (((x) & 0x7) << 23) ++#define USBPCR1_PORT_RST BIT(21) ++#define USBPCR1_WORD_IF_16BIT BIT(19) ++ ++#define OPCR_SPENDN_BIT 7 ++#define OPCR_GATE_USBPHY_CLK_BIT 23 ++ ++#define SRBC_USB_SR 12 ++ ++enum { ++ OTG_PHY = 0, ++ HOST_PHY ++}; ++ ++struct ingenic_usb_phy { ++ struct usb_phy phy; ++ struct device *dev; ++ unsigned long ext_rate; ++ struct clk *clk; ++ struct clk *gate_clk; ++ struct regmap *regmap; ++ ++ bool is_otg_phy; ++ ++ /*otg phy*/ ++ enum usb_dr_mode dr_mode; ++ struct gpio_desc *gpiod_drvvbus; ++ struct gpio_desc *gpiod_id; ++ struct gpio_desc *gpiod_vbus; ++#define USB_DETE_VBUS 0x1 ++#define USB_DETE_ID 0x2 ++ unsigned int usb_dete_state; ++ struct delayed_work work; ++ u32 usbpcr; ++ ++ /*uhc phy*/ ++ unsigned int has_inited; ++ u32 usbpcr1; ++}; ++ ++static inline int dwc_usbphy_read(struct usb_phy *x, u32 reg) ++{ ++ struct ingenic_usb_phy *jzphy = container_of(x, struct ingenic_usb_phy, phy); ++ u32 val = 0; ++ regmap_read(jzphy->regmap, reg, &val); ++ return val; ++} ++ ++static inline int dwc_usbphy_write(struct usb_phy *x, u32 val, u32 reg) ++{ ++ struct ingenic_usb_phy *jzphy = container_of(x, struct ingenic_usb_phy, phy); ++ ++ return regmap_write(jzphy->regmap, reg, val); ++} ++ ++static inline int dwc_usbphy_update_bits(struct usb_phy *x, u32 reg, u32 mask, u32 bits) ++{ ++ struct ingenic_usb_phy *jzphy = container_of(x, struct ingenic_usb_phy, phy); ++ ++ return regmap_update_bits_check(jzphy->regmap, reg, mask, bits, NULL); ++} ++ ++static irqreturn_t usb_dete_irq_handler(int irq, void *data) ++{ ++ struct ingenic_usb_phy *jzphy = (struct ingenic_usb_phy *)data; ++ ++ schedule_delayed_work(&jzphy->work, msecs_to_jiffies(100)); ++ return IRQ_HANDLED; ++} ++ ++static void usb_dete_work(struct work_struct *work) ++{ ++ struct ingenic_usb_phy *jzphy = ++ container_of(work, struct ingenic_usb_phy, work.work); ++ struct usb_otg *otg = jzphy->phy.otg; ++ int vbus = 0, id_level = 1, usb_state = 0; ++ ++ if (jzphy->gpiod_vbus) ++ vbus = gpiod_get_value_cansleep(jzphy->gpiod_vbus); ++ ++ if (jzphy->gpiod_id) ++ id_level = gpiod_get_value_cansleep(jzphy->gpiod_id); ++ ++ if (vbus && id_level) ++ usb_state |= USB_DETE_VBUS; ++ else ++ usb_state &= ~USB_DETE_VBUS; ++ ++ if (id_level) ++ usb_state |= USB_DETE_ID; ++ else ++ usb_state &= ~USB_DETE_ID; ++ ++ if (usb_state != jzphy->usb_dete_state) { ++ enum usb_phy_events status; ++ if (!(usb_state & USB_DETE_VBUS)) { ++ usb_gadget_vbus_disconnect(otg->gadget); ++ status = USB_EVENT_NONE; ++ otg->state = OTG_STATE_B_IDLE; ++ jzphy->phy.last_event = status; ++ if (otg->gadget) ++ atomic_notifier_call_chain(&jzphy->phy.notifier, status, ++ otg->gadget); ++ } ++ ++ if (!(usb_state & USB_DETE_ID)) { ++ status = USB_EVENT_ID; ++ otg->state = OTG_STATE_A_IDLE; ++ jzphy->phy.last_event = status; ++ if (otg->host) ++ atomic_notifier_call_chain(&jzphy->phy.notifier, status, ++ otg->host); ++ } ++ ++ if (usb_state & USB_DETE_VBUS) { ++ status = USB_EVENT_VBUS; ++ otg->state = OTG_STATE_B_PERIPHERAL; ++ jzphy->phy.last_event = status; ++ usb_gadget_vbus_connect(otg->gadget); ++ if (otg->gadget) ++ atomic_notifier_call_chain(&jzphy->phy.notifier, status, ++ otg->gadget); ++ } ++ jzphy->usb_dete_state = usb_state; ++ } ++ return; ++} ++ ++static int jzphy_set_suspend(struct usb_phy *x, int suspend); ++static int jzphy_init(struct usb_phy *x) ++{ ++ struct ingenic_usb_phy *jzphy = container_of(x, struct ingenic_usb_phy, phy); ++ unsigned long rate; ++ u32 usbpcr, usbpcr1; ++ unsigned long usbclk_sel = 0; ++ ++ if (!IS_ERR_OR_NULL(jzphy->clk)) { ++ switch (jzphy->ext_rate/1000000) { ++ case 50: ++ usbclk_sel += 2; ++ case 24: ++ usbclk_sel++; ++ case 20: ++ usbclk_sel++; ++ case 19: ++ usbclk_sel++; ++ case 12: ++ usbclk_sel++; ++ case 10: ++ usbclk_sel++; ++ case 9: ++ break; ++ default: ++ return; ++ } ++ if (rate != clk_get_rate(jzphy->clk)) ++ clk_set_rate(jzphy->clk, rate); ++ clk_prepare_enable(jzphy->clk); ++ } ++ ++ unsigned int aaa = *(volatile unsigned int *)0xb0000024; ++ aaa &= ~(1 << 23); ++ *(volatile unsigned int *)0xb0000024 = aaa; ++ ++ if (!IS_ERR_OR_NULL(jzphy->gate_clk)) ++ clk_prepare_enable(jzphy->gate_clk); ++ ++ jzphy_set_suspend(x, 0); ++ ++ /* fil */ ++ dwc_usbphy_write(x, 0, CPM_USBVBFIL); ++ ++ /* rdt */ ++ dwc_usbphy_write(x, USBRDT_USBRDT(0x96) | USBRDT_VBFIL_LD_EN, CPM_USBRDT); ++ ++ if (jzphy->is_otg_phy) { ++ usbpcr = USBPCR_COMMONONN | USBPCR_VBUSVLDEXT | USBPCR_VBUSVLDEXTSEL | ++ USBPCR_SQRXTUNE(7) | USBPCR_TXPREEMPHTUNE | USBPCR_TXHSXVTUNE(1) | ++ USBPCR_TXVREFTUNE(7); ++ usbpcr1 = dwc_usbphy_read(x, CPM_USBPCR1); ++ usbpcr1 &= ~(USBPCR1_REFCLKDIV_MSK); ++ usbpcr1 = USBPCR1_REFCLKSEL | USBPCR1_REFCLKDIV(usbclk_sel) | USBPCR1_WORD_IF_16BIT; ++ if (jzphy->dr_mode == USB_DR_MODE_PERIPHERAL) { ++ pr_info("DWC PHY IN DEVICE ONLY MODE\n"); ++ usbpcr1 |= USBPCR1_BVLD_REG; ++ usbpcr |= USBPCR_OTG_DISABLE; ++ } else { ++ pr_info("DWC PHY IN OTG MODE\n"); ++ usbpcr |= USBPCR_USB_MODE; ++ } ++ dwc_usbphy_write(x, usbpcr1, CPM_USBPCR1); ++ } else { ++ } ++ /** ++ * Power-On Reset(POR) ++ * Function:This customer-specific signal resets all test registers and state machines ++ * in the USB 2.0 nanoPHY. ++ * The POR signal must be asserted for a minimum of 10 μs. ++ * For POR timing information: ++ * ++ * T0: Power-on reset (POR) is initiated. 0 (reference) ++ * T1: T1 indicates when POR can be set to 1’b0. (To provide examples, values for T2 and T3 are also shown ++ * where T1 = T0 + 30 μs.); In general, T1 must be ≥ T0 + 10 μs. T0 + 10 μs ≤ T1 ++ * T2: T2 indicates when PHYCLOCK, CLK48MOHCI, and CLK12MOHCI are available at the macro output, based on ++ * the USB 2.0 nanoPHY reference clock source. ++ * Crystal: ++ • When T1 = T0 + 10 μs: ++ T2 < T1 + 805 μs = T0 + 815 μs ++ • When T1 = T0 + 30 μs: ++ T2 < T1 + 805 μs = T0 + 835 μs ++ * see "Reset and Power-Saving Signals" on page 60 an “Powering Up and Powering Down the USB 2.0 ++ * nanoPHY” on page 73. ++ */ ++ usbpcr |= USBPCR_POR; ++ dwc_usbphy_write(x, usbpcr, CPM_USBPCR); ++ mdelay(1); ++ usbpcr &= ~USBPCR_POR; ++ dwc_usbphy_write(x, usbpcr, CPM_USBPCR); ++ mdelay(1); ++ return 0; ++} ++ ++static void jzphy_shutdown(struct usb_phy *x) ++{ ++ ++ struct ingenic_usb_phy *jzphy = container_of(x, struct ingenic_usb_phy, phy); ++ ++ jzphy_set_suspend(x, 1); ++ ++ if (jzphy->is_otg_phy) ++ dwc_usbphy_update_bits(x, CPM_USBPCR, ++ USBPCR_OTG_DISABLE|USBPCR_SIDDQ, ++ USBPCR_OTG_DISABLE|USBPCR_SIDDQ); ++ if (!IS_ERR_OR_NULL(jzphy->clk)) ++ clk_disable_unprepare(jzphy->clk); ++ if (!IS_ERR_OR_NULL(jzphy->gate_clk)) ++ clk_disable_unprepare(jzphy->gate_clk); ++} ++ ++static int jzphy_set_vbus(struct usb_phy *x, int on) ++{ ++ struct ingenic_usb_phy *jzphy = container_of(x, struct ingenic_usb_phy, phy); ++ ++ printk("OTG VBUS %s\n", on ? "ON" : "OFF"); ++ gpiod_set_value(jzphy->gpiod_drvvbus, on); ++ return 0; ++} ++ ++static int jzphy_set_suspend(struct usb_phy *x, int suspend) ++{ ++ struct ingenic_usb_phy *jzphy = container_of(x, struct ingenic_usb_phy, phy); ++ int suspend_bit = jzphy->is_otg_phy ? OPCR_USB_SPENDN : OPCR_USB_SPENDN1; ++ ++ pr_debug("usb phy suspend %d suspend bit %x\n", suspend, suspend_bit); ++ dwc_usbphy_update_bits(x, CPM_OPCR, ++ suspend_bit, ++ suspend ? ~suspend_bit : suspend_bit); ++ udelay(suspend ? 5 : 45); ++ return 0; ++} ++ ++static int jzphy_set_wakeup(struct usb_phy *x, bool enabled) ++{ ++ return 0; ++} ++ ++static int jzphy_set_host(struct usb_otg *otg, struct usb_bus *host) ++{ ++ if (!otg) ++ return -ENODEV; ++ otg->host = host; ++ return 0; ++} ++ ++static int jzphy_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget) ++{ ++ if (!otg) ++ return -ENODEV; ++ otg->gadget = gadget; ++ return 0; ++} ++ ++static const struct of_device_id of_matchs[]; ++static int usb_phy_ingenic_probe(struct platform_device *pdev) ++{ ++ const struct of_device_id *match; ++ struct ingenic_usb_phy *jzphy; ++ bool is_otg_phy = false; ++ struct clk *clk; ++ int ret; ++ ++ match = of_match_device(of_matchs, &pdev->dev); ++ if (!match) ++ return -ENODEV; ++ ++ if ((int)match->data == OTG_PHY) ++ is_otg_phy = true; ++ ++ jzphy = (struct ingenic_usb_phy *) ++ devm_kzalloc(&pdev->dev, sizeof(*jzphy), GFP_KERNEL); ++ if (!jzphy) ++ return -ENOMEM; ++ ++ jzphy->phy.init = jzphy_init; ++ jzphy->phy.shutdown = jzphy_shutdown; ++ jzphy->phy.dev = &pdev->dev; ++ jzphy->is_otg_phy = is_otg_phy; ++ jzphy->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "ingenic,syscon"); ++ if (IS_ERR(jzphy->regmap)) { ++ dev_err(&pdev->dev, "failed to find regmap for usb phy\n"); ++ return PTR_ERR(jzphy->regmap); ++ } ++ ++ if (is_otg_phy) { ++ if (of_find_property(pdev->dev.of_node, "dr_mode", NULL)) ++ jzphy->dr_mode = usb_get_dr_mode(&pdev->dev); ++ else ++ jzphy->dr_mode = USB_DR_MODE_HOST; ++ ++ jzphy->gpiod_id = devm_gpiod_get_optional(&pdev->dev,"ingenic,id-dete", GPIOD_IN); ++ jzphy->gpiod_vbus = devm_gpiod_get_optional(&pdev->dev,"ingenic,vbus-dete", GPIOD_ASIS); ++ if (jzphy->gpiod_id || jzphy->gpiod_vbus) ++ INIT_DELAYED_WORK(&jzphy->work, usb_dete_work); ++ ++ if (!IS_ERR_OR_NULL(jzphy->gpiod_id)) { ++ ret = devm_request_irq(&pdev->dev, ++ gpiod_to_irq(jzphy->gpiod_id), ++ usb_dete_irq_handler, ++ IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING|IRQF_ONESHOT, ++ "id_dete", ++ (void *)jzphy); ++ if (ret) ++ return ret; ++ } else { ++ jzphy->usb_dete_state |= USB_DETE_ID; ++ jzphy->gpiod_id = NULL; ++ } ++ ++ if (!IS_ERR_OR_NULL(jzphy->gpiod_vbus)) { ++ ret = devm_request_irq(&pdev->dev, ++ gpiod_to_irq(jzphy->gpiod_vbus), ++ usb_dete_irq_handler, ++ IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING|IRQF_ONESHOT, ++ "vbus_dete", ++ (void *)jzphy); ++ if (ret) ++ return ret; ++ } else { ++ jzphy->usb_dete_state &= ~USB_DETE_VBUS; ++ jzphy->gpiod_vbus = NULL; ++ } ++ ++ jzphy->gpiod_drvvbus = devm_gpiod_get_optional(&pdev->dev,"ingenic,drvvbus", GPIOD_OUT_LOW); ++ if (IS_ERR_OR_NULL(jzphy->gpiod_drvvbus)) ++ jzphy->gpiod_drvvbus = NULL; ++ jzphy->phy.set_vbus = jzphy_set_vbus; ++ jzphy->phy.set_suspend = jzphy_set_suspend; ++ jzphy->phy.set_wakeup = jzphy_set_wakeup; ++ jzphy->phy.otg = devm_kzalloc(&pdev->dev, sizeof(*jzphy->phy.otg), ++ GFP_KERNEL); ++ if (!jzphy->phy.otg) ++ return -ENOMEM; ++ ++ jzphy->phy.otg->state = OTG_STATE_UNDEFINED; ++ jzphy->phy.otg->usb_phy = &jzphy->phy; ++ jzphy->phy.otg->set_host = jzphy_set_host; ++ jzphy->phy.otg->set_peripheral = jzphy_set_peripheral; ++ } ++ ++ jzphy->clk = devm_clk_get(&pdev->dev, "cgu_usb"); ++ if (IS_ERR_OR_NULL(jzphy->clk)) ++ return -ENODEV; ++ ++ jzphy->gate_clk = devm_clk_get(&pdev->dev, "gate_usbphy"); ++ if (IS_ERR_OR_NULL(jzphy->gate_clk)) ++ return -ENODEV; ++ ++ clk = clk_get(NULL, "ext"); ++ if (!IS_ERR_OR_NULL(clk)) { ++ jzphy->ext_rate = clk_get_rate(clk); ++ clk_put(clk); ++ } ++ ++ ret = usb_add_phy_dev(&jzphy->phy); ++ if (ret) { ++ dev_err(&pdev->dev, "can't register transceiver, err: %d\n", ++ ret); ++ return ret; ++ } ++ platform_set_drvdata(pdev, jzphy); ++ ++ return 0; ++} ++ ++static int usb_phy_ingenic_remove(struct platform_device *pdev) ++{ ++ struct ingenic_usb_phy *jzphy = platform_get_drvdata(pdev); ++ ++ usb_remove_phy(&jzphy->phy); ++ ++ clk_disable_unprepare(jzphy->clk); ++ return 0; ++} ++ ++static const struct of_device_id of_matchs[] = { ++ { .compatible = "ingenic,otgphy", .data = (void *)OTG_PHY}, ++ { .compatible = "ingenic,usbphy", .data = (void *)HOST_PHY}, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, ingenic_xceiv_dt_ids); ++ ++static struct platform_driver usb_phy_ingenic_driver = { ++ .probe = usb_phy_ingenic_probe, ++ .remove = usb_phy_ingenic_remove, ++ .driver = { ++ .name = "usb_phy", ++ .of_match_table = of_matchs, ++ }, ++}; ++ ++static int __init usb_phy_ingenic_init(void) ++{ ++ return platform_driver_register(&usb_phy_ingenic_driver); ++} ++subsys_initcall(usb_phy_ingenic_init); ++ ++static void __exit usb_phy_ingenic_exit(void) ++{ ++ platform_driver_unregister(&usb_phy_ingenic_driver); ++} ++module_exit(usb_phy_ingenic_exit); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_Kconfig.patch new file mode 100644 index 00000000..b6a780ad --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_Kconfig.patch @@ -0,0 +1,13 @@ +diff -drupN a/drivers/video/Kconfig b/drivers/video/Kconfig +--- a/drivers/video/Kconfig 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/video/Kconfig 2022-06-09 05:02:34.000000000 +0300 +@@ -29,6 +29,9 @@ source "drivers/video/fbdev/Kconfig" + endmenu + + source "drivers/video/backlight/Kconfig" ++source "drivers/video/ingenic_i2d/Kconfig" ++source "drivers/video/ingenic_ipu/Kconfig" ++source "drivers/video/ingenic_bscaler/Kconfig" + + config VGASTATE + tristate diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_Makefile.patch new file mode 100644 index 00000000..f794170d --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_Makefile.patch @@ -0,0 +1,24 @@ +diff -drupN a/drivers/video/Makefile b/drivers/video/Makefile +--- a/drivers/video/Makefile 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/video/Makefile 2022-06-09 05:02:34.000000000 +0300 +@@ -1,11 +1,14 @@ +-obj-$(CONFIG_VGASTATE) += vgastate.o +-obj-$(CONFIG_HDMI) += hdmi.o ++obj-$(CONFIG_VGASTATE) += vgastate.o ++obj-$(CONFIG_HDMI) += hdmi.o + +-obj-$(CONFIG_VT) += console/ +-obj-$(CONFIG_LOGO) += logo/ +-obj-y += backlight/ ++obj-$(CONFIG_VT) += console/ ++obj-$(CONFIG_LOGO) += logo/ ++obj-y += backlight/ ++obj-y += fbdev/ + +-obj-y += fbdev/ ++obj-$(CONFIG_JZ_I2D) += ingenic_i2d/ ++obj-$(CONFIG_JZ_IPU) += ingenic_ipu/ ++obj-$(CONFIG_JZ_BSCALER) += ingenic_bscaler/ + + obj-$(CONFIG_VIDEOMODE_HELPERS) += display_timing.o videomode.o + ifeq ($(CONFIG_OF),y) diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_Kconfig.patch new file mode 100644 index 00000000..c74fe6e5 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_Kconfig.patch @@ -0,0 +1,110 @@ +diff -drupN a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig +--- a/drivers/video/fbdev/Kconfig 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/video/fbdev/Kconfig 2022-06-09 05:02:34.000000000 +0300 +@@ -681,7 +681,7 @@ config FB_STI + BIOS routines contained in a ROM chip in HP PA-RISC based machines. + Enabling this option will implement the linux framebuffer device + using calls to the STI BIOS routines for initialisation. +- ++ + If you enable this option, you will get a planar framebuffer device + /dev/fb which will work on the most common HP graphic cards of the + NGLE family, including the artist chips (in the 7xx and Bxxx series), +@@ -1115,36 +1115,36 @@ config FB_I810 + select FB_CFB_IMAGEBLIT + select VGASTATE + help +- This driver supports the on-board graphics built in to the Intel 810 ++ This driver supports the on-board graphics built in to the Intel 810 + and 815 chipsets. Say Y if you have and plan to use such a board. + + To compile this driver as a module, choose M here: the + module will be called i810fb. + +- For more information, please read ++ For more information, please read + + + config FB_I810_GTF + bool "use VESA Generalized Timing Formula" + depends on FB_I810 + help +- If you say Y, then the VESA standard, Generalized Timing Formula ++ If you say Y, then the VESA standard, Generalized Timing Formula + or GTF, will be used to calculate the required video timing values +- per video mode. Since the GTF allows nondiscrete timings ++ per video mode. Since the GTF allows nondiscrete timings + (nondiscrete being a range of values as opposed to discrete being a +- set of values), you'll be able to use any combination of horizontal ++ set of values), you'll be able to use any combination of horizontal + and vertical resolutions, and vertical refresh rates without having + to specify your own timing parameters. This is especially useful +- to maximize the performance of an aging display, or if you just +- have a display with nonstandard dimensions. A VESA compliant ++ to maximize the performance of an aging display, or if you just ++ have a display with nonstandard dimensions. A VESA compliant + monitor is recommended, but can still work with non-compliant ones. +- If you need or want this, then select this option. The timings may +- not be compliant with Intel's recommended values. Use at your own ++ If you need or want this, then select this option. The timings may ++ not be compliant with Intel's recommended values. Use at your own + risk. + +- If you say N, the driver will revert to discrete video timings ++ If you say N, the driver will revert to discrete video timings + using a set recommended by Intel in their documentation. +- ++ + If unsure, say N. + + config FB_I810_I2C +@@ -1262,10 +1262,10 @@ config FB_MATROX_G + G450/G550 secondary head and digital output are supported without + additional modules. + +- The driver starts in monitor mode. You must use the matroxset tool +- (available at ) to +- swap primary and secondary head outputs, or to change output mode. +- Secondary head driver always start in 640x480 resolution and you ++ The driver starts in monitor mode. You must use the matroxset tool ++ (available at ) to ++ swap primary and secondary head outputs, or to change output mode. ++ Secondary head driver always start in 640x480 resolution and you + must use fbset to change it. + + Do not forget that second head supports only 16 and 32 bpp +@@ -1348,7 +1348,7 @@ config FB_RADEON_I2C + select FB_DDC + default y + help +- Say Y here if you want DDC/I2C support for your Radeon board. ++ Say Y here if you want DDC/I2C support for your Radeon board. + + config FB_RADEON_BACKLIGHT + bool "Support for backlight control" +@@ -1580,7 +1580,7 @@ config FB_NEOMAGIC + select VGASTATE + help + This driver supports notebooks with NeoMagic PCI chips. +- Say Y if you have such a graphics card. ++ Say Y if you have such a graphics card. + + To compile this driver as a module, choose M here: the + module will be called neofb. +@@ -1635,7 +1635,7 @@ config FB_VOODOO1 + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + ---help--- +- Say Y here if you have a 3Dfx Voodoo Graphics (Voodoo1/sst1) or ++ Say Y here if you have a 3Dfx Voodoo Graphics (Voodoo1/sst1) or + Voodoo2 (cvg) based graphics card. + + To compile this driver as a module, choose M here: the +@@ -2449,6 +2449,7 @@ source "drivers/video/fbdev/omap/Kconfig + source "drivers/video/fbdev/omap2/Kconfig" + source "drivers/video/fbdev/exynos/Kconfig" + source "drivers/video/fbdev/mmp/Kconfig" ++source "drivers/video/fbdev/ingenic/Kconfig" + + config FB_SH_MOBILE_MERAM + tristate "SuperH Mobile MERAM read ahead support" diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_Makefile.patch new file mode 100644 index 00000000..7f9a2f6a --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_Makefile.patch @@ -0,0 +1,11 @@ +diff -drupN a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile +--- a/drivers/video/fbdev/Makefile 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/video/fbdev/Makefile 2022-06-09 05:02:34.000000000 +0300 +@@ -149,6 +149,7 @@ obj-$(CONFIG_FB_DA8XX) += da8xx-fb.o + obj-$(CONFIG_FB_MXS) += mxsfb.o + obj-$(CONFIG_FB_SSD1307) += ssd1307fb.o + obj-$(CONFIG_FB_SIMPLE) += simplefb.o ++obj-$(CONFIG_FB_INGENIC) += ingenic/ + + # the test framebuffer is last + obj-$(CONFIG_FB_VIRTUAL) += vfb.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_Kconfig.patch new file mode 100644 index 00000000..c85ae0f9 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_Kconfig.patch @@ -0,0 +1,84 @@ +diff -drupN a/drivers/video/fbdev/ingenic/Kconfig b/drivers/video/fbdev/ingenic/Kconfig +--- a/drivers/video/fbdev/ingenic/Kconfig 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/Kconfig 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,80 @@ ++menuconfig FB_INGENIC ++ tristate "Ingenic Framebuffer Driver" ++ depends on FB ++ select FB_CFB_FILLRECT ++ select FB_CFB_COPYAREA ++ select FB_CFB_IMAGEBLIT ++ default n ++ help ++ LCD Driver for INGENIC ++ ++config FB_VSYNC_SKIP_DISABLE ++ bool "Disable Vsync skip" ++ depends on FB_INGENIC ++ help ++ Disable Vsync skip ++ ++config FB_VSYNC_SKIP ++ int "Vsync skip ratio[0..9]" ++ depends on FB_INGENIC ++ default 9 ++ help ++ Vsync skip ratio ++ ++config FB_INGENIC_NR_FRAMES ++ int "how many frames support(max=3)" ++ depends on FB_INGENIC ++ default 2 ++ ++config FB_INGENIC_NR_LAYERS ++ int "how many layers support(max=4)" ++ depends on FB_INGENIC ++ default 1 ++ ++config FB_INGENIC_DEBUG ++ bool "fb test for displaying color bar" ++ depends on FB_INGENIC ++ default n ++ help ++ fb test for displaying color bar in your board. ++ ++config SLCDC_CONTINUA ++ tristate "SLCDC CONTINUA TRANFER" ++ depends on FB_INGENIC ++ default n ++ ++config SLCDC_USE_TE ++ tristate "SLCDC USE TE SIGNAL" ++ depends on FB_INGENIC ++ default n ++ ++config FB_INGENIC_MIPI_DSI ++ tristate "Ingenic MIPI DSI Interface" ++ depends on FB_INGENIC ++ default n ++ ++config MIPI_TX_LANE ++ tristate "MIPI_TX_LANES" ++ depends on FB_INGENIC_MIPI_DSI ++ choice ++ prompt "2 LANE or 4 LANE" ++ depends on MIPI_TX_LANE ++ config MIPI_4LANE ++ bool "4LANE" ++ config MIPI_2LANE ++ bool "2LANE" ++ endchoice ++ ++config INGENIC_FB_BOOT_PATTERN ++ tristate "Ingenic Janus boot image" ++ depends on FB_INGENIC ++ default n ++ help ++ display the boot image of Janus in your board ++ ++if FB_INGENIC ++source "drivers/video/fbdev/ingenic/fb_v10/Kconfig" ++source "drivers/video/fbdev/ingenic/fb_v11/Kconfig" ++source "drivers/video/fbdev/ingenic/fb_v12/Kconfig" ++endif ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_Makefile.patch new file mode 100644 index 00000000..197bf51b --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_Makefile.patch @@ -0,0 +1,7 @@ +diff -drupN a/drivers/video/fbdev/ingenic/Makefile b/drivers/video/fbdev/ingenic/Makefile +--- a/drivers/video/fbdev/ingenic/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/Makefile 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,3 @@ ++obj-$(CONFIG_FB_INGENIC_X1000) += fb_v10/ ++obj-$(CONFIG_FB_INGENIC_X2000) += fb_v11/ ++obj-$(CONFIG_FB_INGENIC_V12) += fb_v12/ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v10_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v10_Kconfig.patch new file mode 100644 index 00000000..65c24727 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v10_Kconfig.patch @@ -0,0 +1,31 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v10/Kconfig b/drivers/video/fbdev/ingenic/fb_v10/Kconfig +--- a/drivers/video/fbdev/ingenic/fb_v10/Kconfig 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v10/Kconfig 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,27 @@ ++menuconfig FB_INGENIC_X1000 ++ tristate "Ingenic Framebuffer Driver for Version 10" ++ depends on FB_INGENIC ++ select FB_INGENIC_DISPLAYS_X1000 ++ help ++ LCD Driver for X1000 ++choice ++ depends on FB_INGENIC_X1000 ++ prompt "Framebuffer format" ++ default LCD_FB_FORMAT_16BIT ++config LCD_FB_FORMAT_16BIT ++ bool "Support 16bpp framebuffer" ++config LCD_FB_FORMAT_24BIT ++ bool "Support 24bpp framebuffer" ++endchoice ++ ++config SLCDC_LOW_POWER_CONSUMPTION ++ bool "Low power consumption mode (experimental)" ++ depends on FB_INGENIC_X1000 ++ default n ++ help ++ In this mode, will startup the LCD clk and pixel clk only at user operate the frame buffer device. ++ This will save 6mW at sigal frame mode, or 24mW at contiune frame mode. ++ notice: ++ Because of the clk has been shutdown, the sys node will invalid like read register draw color bar ... ++ ++source "drivers/video/fbdev/ingenic/fb_v10/displays/Kconfig" diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v10_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v10_Makefile.patch new file mode 100644 index 00000000..813d9f39 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v10_Makefile.patch @@ -0,0 +1,6 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v10/Makefile b/drivers/video/fbdev/ingenic/fb_v10/Makefile +--- a/drivers/video/fbdev/ingenic/fb_v10/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v10/Makefile 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,2 @@ ++obj-y += ingenicfb.o ++obj-y += displays/ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v10_displays_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v10_displays_Kconfig.patch new file mode 100644 index 00000000..4cf2d613 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v10_displays_Kconfig.patch @@ -0,0 +1,17 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v10/displays/Kconfig b/drivers/video/fbdev/ingenic/fb_v10/displays/Kconfig +--- a/drivers/video/fbdev/ingenic/fb_v10/displays/Kconfig 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v10/displays/Kconfig 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,13 @@ ++menuconfig FB_INGENIC_DISPLAYS_X1000 ++ tristate "Supported lcd panels" ++ depends on FB_INGENIC_X1000 ++ select BACKLIGHT_LCD_SUPPORT ++ select LCD_CLASS_DEVICE ++ select BACKLIGHT_CLASS_DEVICE ++ ++ ++config PANEL_X1000_TRULY_TFT240240_2_E ++ tristate "lcd panel truly tft240240" ++ depends on FB_INGENIC_DISPLAYS_X1000 ++ help ++ lcd panel truly tft240240, for ingenicfb drivers. diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v10_displays_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v10_displays_Makefile.patch new file mode 100644 index 00000000..cbee6df4 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v10_displays_Makefile.patch @@ -0,0 +1,5 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v10/displays/Makefile b/drivers/video/fbdev/ingenic/fb_v10/displays/Makefile +--- a/drivers/video/fbdev/ingenic/fb_v10/displays/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v10/displays/Makefile 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1 @@ ++obj-$(CONFIG_PANEL_X1000_TRULY_TFT240240_2_E) += panel_truly_tft240240_2_e.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v10_displays_panel_truly_tft240240_2_e.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v10_displays_panel_truly_tft240240_2_e.c.patch new file mode 100644 index 00000000..2e13e1c1 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v10_displays_panel_truly_tft240240_2_e.c.patch @@ -0,0 +1,411 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v10/displays/panel_truly_tft240240_2_e.c b/drivers/video/fbdev/ingenic/fb_v10/displays/panel_truly_tft240240_2_e.c +--- a/drivers/video/fbdev/ingenic/fb_v10/displays/panel_truly_tft240240_2_e.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v10/displays/panel_truly_tft240240_2_e.c 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,407 @@ ++/* ++ * LCD panel support for ingenicfb ++ * ++ * Copyright (C) 2016 Ingenic Semiconductor Inc. ++ * ++ * Author:clwang ++ * qipengzhen ++ * ++ * 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 ++#include ++#include ++#include "../ingenicfb.h" ++#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL) ++struct board_gpio { ++ short gpio; ++ short active_level; ++}; ++ ++struct truly_device { ++ /* ingenic frame buffer */ ++ struct device *dev; ++ struct ingenicfb_platform_data *panel; ++ /* common lcd framework */ ++ struct lcd_device *lcd; ++ struct backlight_device *backlight; ++ int power; ++ struct regulator *vcc; ++ struct board_gpio cs; ++ struct board_gpio rst; ++ /*struct board_gpio pwmen;*/ ++ struct board_gpio blken; ++}; ++struct fb_videomode ingenicfb0_videomode = { ++ .name = "240x240", ++ .refresh = 60, ++ .xres = 240, ++ .yres = 240, ++ .pixclock = KHZ2PICOS(30000), ++ .left_margin = 0, ++ .right_margin = 0, ++ .upper_margin = 0, ++ .lower_margin = 0, ++ .hsync_len = 0, ++ .vsync_len = 0, ++ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, ++ .vmode = FB_VMODE_NONINTERLACED, ++ .flag = 0, ++}; ++static struct smart_lcd_data_table truly_tft240240_data_table[] = { ++ /* LCD init code */ ++ {SMART_CONFIG_CMD, 0x01}, //soft reset, 120 ms = 120 000 us ++ {SMART_CONFIG_UDELAY, 1000}, ++ {SMART_CONFIG_CMD, 0x11}, ++ {SMART_CONFIG_UDELAY, 5000}, /* sleep out 5 ms */ ++ {SMART_CONFIG_CMD, 0x36}, ++#ifdef CONFIG_TRULY_240X240_ROTATE_180 ++ /*{0x36, 0xc0, 2, 0}, //40*/ ++ {SMART_CONFIG_DATA, 0xd0}, //40 ++#else ++ {SMART_CONFIG_DATA, 0x00}, //40 ++#endif ++ {SMART_CONFIG_CMD, 0x2a}, ++ {SMART_CONFIG_DATA, 0x00}, ++ {SMART_CONFIG_DATA, 0x00}, ++ {SMART_CONFIG_DATA, 0x00}, ++ {SMART_CONFIG_DATA, 0xef}, ++ {SMART_CONFIG_CMD, 0x2b}, ++ {SMART_CONFIG_DATA, 0x00}, ++ {SMART_CONFIG_DATA, 0x00}, ++ {SMART_CONFIG_DATA, 0x00}, ++ {SMART_CONFIG_DATA, 0xef}, ++ {SMART_CONFIG_CMD, 0x3a}, ++#if defined(CONFIG_SLCD_TRULY_18BIT) //if 18bit/pixel unusual. try to use 16bit/pixel ++ {SMART_CONFIG_DATA, 0x06}, //6-6-6 ++#else ++ {SMART_CONFIG_DATA, 0x05}, //5-6-5 ++#endif ++ // {SMART_CONFIG_DATA, 0x55}, ++ {SMART_CONFIG_CMD, 0xb2}, ++ {SMART_CONFIG_DATA, 0x7f}, ++ {SMART_CONFIG_DATA, 0x7f}, ++ {SMART_CONFIG_DATA, 0x01}, ++ {SMART_CONFIG_DATA, 0xde}, ++ {SMART_CONFIG_DATA, 0x33}, ++ {SMART_CONFIG_CMD, 0xb3}, ++ {SMART_CONFIG_DATA, 0x10}, ++ {SMART_CONFIG_DATA, 0x05}, ++ {SMART_CONFIG_DATA, 0x0f}, ++ {SMART_CONFIG_CMD, 0xb4}, ++ {SMART_CONFIG_DATA, 0x0b}, ++ {SMART_CONFIG_CMD, 0xb7}, ++ {SMART_CONFIG_DATA, 0x35}, ++ {SMART_CONFIG_CMD, 0xbb}, ++ {SMART_CONFIG_DATA, 0x28}, //23 ++ {SMART_CONFIG_CMD, 0xbc}, ++ {SMART_CONFIG_DATA, 0xec}, ++ {SMART_CONFIG_CMD, 0xc0}, ++ {SMART_CONFIG_DATA, 0x2c}, ++ {SMART_CONFIG_CMD, 0xc2}, ++ {SMART_CONFIG_DATA, 0x01}, ++ {SMART_CONFIG_CMD, 0xc3}, ++ {SMART_CONFIG_DATA, 0x1e}, //14 ++ {SMART_CONFIG_CMD, 0xc4}, ++ {SMART_CONFIG_DATA, 0x20}, ++ {SMART_CONFIG_CMD, 0xc6}, ++ {SMART_CONFIG_DATA, 0x14}, ++ {SMART_CONFIG_CMD, 0xd0}, ++ {SMART_CONFIG_DATA, 0xa4}, ++ {SMART_CONFIG_DATA, 0xa1}, ++ {SMART_CONFIG_CMD, 0xe0}, ++ {SMART_CONFIG_DATA, 0xd0}, ++ {SMART_CONFIG_DATA, 0x00}, ++ {SMART_CONFIG_DATA, 0x00}, ++ {SMART_CONFIG_DATA, 0x08}, ++ {SMART_CONFIG_DATA, 0x07}, ++ {SMART_CONFIG_DATA, 0x05}, ++ {SMART_CONFIG_DATA, 0x29}, ++ {SMART_CONFIG_DATA, 0x54}, ++ {SMART_CONFIG_DATA, 0x41}, ++ {SMART_CONFIG_DATA, 0x3c}, ++ {SMART_CONFIG_DATA, 0x17}, ++ {SMART_CONFIG_DATA, 0x15}, ++ {SMART_CONFIG_DATA, 0x1a}, ++ {SMART_CONFIG_DATA, 0x20}, ++ {SMART_CONFIG_CMD, 0xe1}, ++ {SMART_CONFIG_DATA, 0xd0}, ++ {SMART_CONFIG_DATA, 0x00}, ++ {SMART_CONFIG_DATA, 0x00}, ++ {SMART_CONFIG_DATA, 0x08}, ++ {SMART_CONFIG_DATA, 0x07}, ++ {SMART_CONFIG_DATA, 0x04}, ++ {SMART_CONFIG_DATA, 0x29}, ++ {SMART_CONFIG_DATA, 0x44}, ++ {SMART_CONFIG_DATA, 0x42}, ++ {SMART_CONFIG_DATA, 0x3b}, ++ {SMART_CONFIG_DATA, 0x16}, ++ {SMART_CONFIG_DATA, 0x15}, ++ {SMART_CONFIG_DATA, 0x1b}, ++ {SMART_CONFIG_DATA, 0x1f}, ++ {SMART_CONFIG_CMD, 0x35}, // TE on ++ {SMART_CONFIG_DATA, 0x00}, // TE mode: 0, mode1; 1, mode2 ++ // {SMART_CONFIG_CMD, 0x34}, // TE off ++ {SMART_CONFIG_CMD, 0x21}, ++ {SMART_CONFIG_CMD, 0x29}, //Display ON ++ /* set window size*/ ++ // {SMART_CONFIG_CMD, 0xcd}, ++ {SMART_CONFIG_CMD, 0x2a}, ++ {SMART_CONFIG_DATA, 0}, ++ {SMART_CONFIG_DATA, 0}, ++ {SMART_CONFIG_DATA, (239>> 8) & 0xff}, ++ {SMART_CONFIG_DATA, 239 & 0xff}, ++#ifdef CONFIG_TRULY_240X240_ROTATE_180 ++ {SMART_CONFIG_CMD, 0x2b}, ++ {SMART_CONFIG_DATA, ((320-240)>>8)&0xff}, ++ {SMART_CONFIG_DATA, ((320-240)>>0)&0xff}, ++ {SMART_CONFIG_DATA, ((320-1)>>8) & 0xff}, ++ {SMART_CONFIG_DATA, ((320-1)>>0) & 0xff}, ++#else ++ {SMART_CONFIG_CMD, 0x2b}, ++ {SMART_CONFIG_DATA, 0}, ++ {SMART_CONFIG_DATA, 0}, ++ {SMART_CONFIG_DATA, (239>> 8) & 0xff}, ++ {SMART_CONFIG_DATA, 239 & 0xff}, ++#endif ++ {SMART_CONFIG_CMD, 0x2C}, ++ {SMART_CONFIG_CMD, 0x2C}, ++ {SMART_CONFIG_CMD, 0x2C}, ++ {SMART_CONFIG_CMD, 0x2C}, ++}; ++ ++unsigned long truly_cmd_buf[]= { ++ 0x2C2C2C2C, ++}; ++ ++static struct ingenicfb_platform_data ingenicfb_pdata = { ++ .num_modes = 1, ++ .modes = &ingenicfb0_videomode, ++ .lcd_type = LCD_TYPE_SLCD, ++ .bpp = 16, ++ .width = 31, ++ .height = 31, ++ .pinmd = 0, ++ .smart_config.rsply_cmd_high = 0, ++ .smart_config.csply_active_high = 0, ++ .smart_config.newcfg_fmt_conv = 1, ++ .smart_config.write_gram_cmd = truly_cmd_buf, ++ .smart_config.length_cmd = ARRAY_SIZE(truly_cmd_buf), ++ .smart_config.bus_width = 8, ++ .smart_config.data_table_width = 8, ++ .smart_config.length_data_table = ARRAY_SIZE(truly_tft240240_data_table), ++ .smart_config.data_table = truly_tft240240_data_table, ++ .dither_enable = 0, ++}; ++ ++static void truly_power_reset(struct board_gpio *rst) ++{ ++ gpio_direction_output(rst->gpio, rst->active_level); ++ mdelay(20); ++ gpio_direction_output(rst->gpio, !rst->active_level); ++ mdelay(10); ++} ++ ++static int truly_set_power(struct lcd_device *lcd, int power) ++{ ++ struct truly_device *truly = lcd_get_data(lcd); ++ struct board_gpio *cs = &truly->cs; ++ struct board_gpio *rst = &truly->rst; ++ if(POWER_IS_ON(power) && !POWER_IS_ON(truly->power)) { ++ gpio_direction_output(cs->gpio, !cs->active_level); ++ truly_power_reset(rst); ++ mdelay(5); ++ gpio_direction_output(cs->gpio, cs->active_level); ++ } ++ if(!POWER_IS_ON(power) && POWER_IS_ON(truly->power)) { ++ gpio_direction_output(cs->gpio, cs->active_level); ++ gpio_direction_output(rst->gpio, cs->active_level); ++ } ++/* gpio_direction_output(truly->pwmen.gpio, 1);*/ ++ gpio_direction_output(truly->blken.gpio, 1); ++ truly->power = power; ++ return 0; ++} ++ ++static int truly_get_power(struct lcd_device *lcd) ++{ ++ struct truly_device *truly = lcd_get_data(lcd); ++ return truly->power; ++} ++ ++static struct lcd_ops truly_lcd_ops = { ++ .set_power = truly_set_power, ++ .get_power = truly_get_power, ++}; ++ ++ ++static int of_truly_parse(struct device *dev) ++{ ++ struct truly_device *truly = dev_get_drvdata(dev); ++ struct device_node *np = dev->of_node; ++ enum of_gpio_flags flags; ++ int ret = 0; ++ ++ truly->cs.gpio = of_get_named_gpio_flags(np, "ingenic,cs-gpio", 0, &flags); ++ if(gpio_is_valid(truly->cs.gpio)) { ++ truly->cs.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ ret = gpio_request(truly->cs.gpio, "cs"); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request cs pin!\n"); ++ return -1; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio cs.gpio: %d\n", truly->cs.gpio); ++ return -1; ++ } ++ ++ truly->rst.gpio = of_get_named_gpio_flags(np, "ingenic,rst-gpio", 0, &flags); ++ if(gpio_is_valid(truly->rst.gpio)) { ++ truly->rst.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ ret = gpio_request(truly->rst.gpio, "rst"); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request rst pin!\n"); ++ goto err_request_rst; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio rst.gpio: %d\n", truly->cs.gpio); ++ goto err_request_rst; ++ } ++ ++ truly->blken.gpio = of_get_named_gpio_flags(np, "ingenic,blken-gpio", 0, &flags); ++ if(gpio_is_valid(truly->blken.gpio)) { ++ truly->blken.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ ret = gpio_request(truly->blken.gpio, "blken"); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request blken pin!\n"); ++ goto err_request_blken; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio blken.gpio: %d\n", truly->blken.gpio); ++ goto err_request_blken; ++ } ++ ++ return 0; ++err_request_blken: ++ gpio_free(truly->blken.gpio); ++err_request_rst: ++ gpio_free(truly->cs.gpio); ++ return -1; ++} ++ ++static int lcd_inited_by_uboot( void ) ++{ ++ if (*(unsigned int*)(0xb3050000 + 0x30) & (1 << 3)) ++ return 1; ++ else ++ return 0; ++} ++ ++static int truly_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ struct truly_device *truly; ++ ++ truly = kzalloc(sizeof(struct truly_device), GFP_KERNEL); ++ if(truly == NULL) { ++ dev_err(&pdev->dev, "Faile to alloc memory!"); ++ return -ENOMEM; ++ } ++ truly->dev = &pdev->dev; ++ dev_set_drvdata(&pdev->dev, truly); ++ ++ ret = of_truly_parse(&pdev->dev); ++ if(ret < 0) { ++ goto err_of_parse; ++ } ++ ++ ret = ingenicfb_register_panel(&ingenicfb_pdata); ++ if(ret < 0) { ++ dev_err(&pdev->dev, "Failed to register lcd panel!\n"); ++ } ++ ++ truly->lcd = lcd_device_register("truly_tft240240_lcd", &pdev->dev, truly, &truly_lcd_ops); ++ if(IS_ERR_OR_NULL(truly->lcd)) { ++ dev_err(&pdev->dev, "Error register lcd!\n"); ++ ret = -EINVAL; ++ goto err_lcd_register; ++ } ++ ++ /* TODO: should this power status sync from uboot */ ++ truly->power = FB_BLANK_POWERDOWN; ++ if(!lcd_inited_by_uboot()) ++ truly_set_power(truly->lcd, FB_BLANK_UNBLANK); ++ truly->power = FB_BLANK_UNBLANK; ++ ++ return 0; ++ ++err_lcd_register: ++err_of_parse: ++ kfree(truly); ++ return ret; ++} ++ ++static int truly_remove(struct platform_device *pdev) ++{ ++ struct truly_device *truly = dev_get_drvdata(&pdev->dev); ++ ++ truly_set_power(truly->lcd, FB_BLANK_POWERDOWN); ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int truly_suspend(struct device *dev) ++{ ++ struct truly_device *truly = dev_get_drvdata(dev); ++ truly_set_power(truly->lcd, FB_BLANK_POWERDOWN); ++ return 0; ++} ++ ++static int truly_resume(struct device *dev) ++{ ++ struct truly_device *truly = dev_get_drvdata(dev); ++ truly_set_power(truly->lcd, FB_BLANK_UNBLANK); ++ return 0; ++} ++ ++static const struct dev_pm_ops truly_pm_ops = { ++ .suspend = truly_suspend, ++ .resume = truly_resume, ++}; ++#endif ++static const struct of_device_id truly_of_match[] = { ++ { .compatible = "ingenic,truly_tft240240_2_e", }, ++ {}, ++}; ++static struct platform_driver truly_driver = { ++ .probe = truly_probe, ++ .remove = truly_remove, ++ .driver = { ++ .name = "truly_tft240240_2_e", ++ .of_match_table = truly_of_match, ++#ifdef CONFIG_PM ++ .pm = &truly_pm_ops, ++#endif ++ }, ++}; ++module_platform_driver(truly_driver); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v10_ingenicfb.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v10_ingenicfb.c.patch new file mode 100644 index 00000000..cca08d60 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v10_ingenicfb.c.patch @@ -0,0 +1,2671 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v10/ingenicfb.c b/drivers/video/fbdev/ingenic/fb_v10/ingenicfb.c +--- a/drivers/video/fbdev/ingenic/fb_v10/ingenicfb.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v10/ingenicfb.c 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,2667 @@ ++/* ++ * kernel/drivers/video/ingenic_fb_v1_2/ingenic_fb.c ++ * ++ * Copyright (c) 2012 Ingenic Semiconductor Co., Ltd. ++ * http://www.ingenic.com/ ++ * ++ * Core file for Ingenic Display Controller driver ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++//#include ++//#include ++//#include ++ ++#include "ingenicfb.h" ++#include "lcd_regs.h" ++struct ingenicfb_platform_data *fbdev_panel = NULL; ++struct platform_device *fbdev_pdev = NULL; ++static void dump_lcdc_registers(struct ingenicfb *ingenicfb); ++static void ingenicfb_enable(struct fb_info *info); ++static void ingenicfb_disable(struct fb_info *info); ++static int ingenicfb_set_par(struct fb_info *info); ++ ++static int uboot_inited; ++static int showFPS = 0; ++static struct ingenicfb *ingenicfb; ++ ++static const struct fb_fix_screeninfo ingenicfb_fix = { ++ .id = "ingenicfb", ++ .type = FB_TYPE_PACKED_PIXELS, ++ .visual = FB_VISUAL_TRUECOLOR, ++ .xpanstep = 0, ++ .ypanstep = 1, ++ .ywrapstep = 0, ++ .accel = FB_ACCEL_NONE, ++}; ++ ++void ingenicfb_clk_enable(struct ingenicfb *ingenicfb); ++void ingenicfb_clk_disable(struct ingenicfb *ingenicfb); ++void ingenicfb_pclk_enable(struct ingenicfb *ingenicfb); ++void ingenicfb_pclk_disable(struct ingenicfb *ingenicfb); ++static int ingenicfb_open(struct fb_info *info, int user) ++{ ++ struct ingenicfb *ingenicfb = info->par; ++ ++ dev_dbg(info->dev, "open count : %d\n", ++ingenicfb->open_cnt); ++ ++ if (!ingenicfb->is_lcd_en && ingenicfb->vidmem_phys) { ++#ifdef CONFIG_SLCDC_LOW_POWER_CONSUMPTION ++ ingenicfb_clk_enable(ingenicfb); ++ ingenicfb_pclk_enable(ingenicfb); ++#endif ++ if (ingenicfb->is_inited == 0) ++ ingenicfb_set_par(info); ++ ++ ingenicfb_enable(info); ++ } ++ ++ return 0; ++} ++ ++static int ingenicfb_release(struct fb_info *info, int user) ++{ ++ unsigned int tmp = 0; ++ ++ tmp = reg_read(ingenicfb, SLCDC_CTRL); ++#ifdef CONFIG_SLCDC_CONTINUA ++ tmp &= ~(SLCDC_CTRL_DMA_START | SLCDC_CTRL_DMA_MODE); ++#else ++ tmp |= SLCDC_CTRL_DMA_MODE | SLCDC_CTRL_DMA_START; ++#endif ++ reg_write(ingenicfb, SLCDC_CTRL, tmp); ++ ++#ifdef CONFIG_SLCDC_LOW_POWER_CONSUMPTION ++ msleep(100); ++ ingenicfb_disable(ingenicfb->fb); ++ ingenicfb_pclk_disable(ingenicfb); ++ ingenicfb_clk_disable(ingenicfb); ++#endif ++ return 0; ++} ++ ++ static void ++ingenicfb_videomode_to_var(struct fb_var_screeninfo *var, ++ const struct fb_videomode *mode, int lcd_type) ++{ ++ var->xres = mode->xres; ++ var->yres = mode->yres; ++ var->xres_virtual = mode->xres; ++ var->yres_virtual = mode->yres * NUM_FRAME_BUFFERS; ++ var->xoffset = 0; ++ var->yoffset = 0; ++ var->left_margin = mode->left_margin; ++ var->right_margin = mode->right_margin; ++ var->upper_margin = mode->upper_margin; ++ var->lower_margin = mode->lower_margin; ++ var->hsync_len = mode->hsync_len; ++ var->vsync_len = mode->vsync_len; ++ var->sync = mode->sync; ++ var->vmode = mode->vmode & FB_VMODE_MASK; ++ if (lcd_type == LCD_TYPE_SLCD) { ++ uint64_t pixclk = ++ KHZ2PICOS((var->xres + var->left_margin + ++ var->hsync_len) * (var->yres + ++ var->upper_margin + ++ var->lower_margin + ++ var->vsync_len) * 60 / 1000); ++ var->pixclock = ++ (mode->pixclock < pixclk) ? pixclk : mode->pixclock; ++ } else { ++ var->pixclock = mode->pixclock; ++ } ++} ++ ++static int ingenicfb_get_controller_bpp(struct ingenicfb *ingenicfb) ++{ ++ switch (ingenicfb->fb_bpp) { ++ case 18: ++ case 24: ++ return 32; ++ case 15: ++ return 16; ++ default: ++ return ingenicfb->fb_bpp; ++ } ++} ++ ++static struct fb_videomode *ingenicfb_get_mode(struct fb_var_screeninfo *var, ++ struct fb_info *info) ++{ ++ size_t i; ++ struct ingenicfb *ingenicfb = info->par; ++ struct fb_videomode *mode = ingenicfb->pdata->modes; ++ ++ for (i = 0; i < ingenicfb->pdata->num_modes; ++i, ++mode) { ++ if (mode->flag & FB_MODE_IS_VGA) { ++ if (mode->xres == var->xres && ++ mode->yres == var->yres ++ && mode->pixclock == var->pixclock) ++ return mode; ++ } else { ++ if (mode->xres == var->xres && mode->yres == var->yres ++ && mode->vmode == var->vmode ++ && mode->right_margin == var->right_margin) { ++ if (ingenicfb->pdata->lcd_type != LCD_TYPE_SLCD) { ++ if (mode->pixclock == var->pixclock) ++ return mode; ++ } else { ++ return mode; ++ } ++ } ++ } ++ } ++ ++ return NULL; ++} ++ ++static struct fb_videomode *ingenicfb_checkout_max_vga_videomode(struct fb_info ++ *info) ++{ ++ struct ingenicfb *ingenicfb = info->par; ++ struct ingenicfb_platform_data *pdata = ingenicfb->pdata; ++ int i, flag; ++ int pix_size = 0; ++ flag = 0; ++ for (i = 0; i < pdata->num_modes; i++) { ++ if ((pdata->modes[i].xres * pdata->modes[i].yres) > pix_size) { ++ flag = pdata->modes[i].flag; ++ pix_size = pdata->modes[i].xres * pdata->modes[i].yres; ++ } ++ } ++ ++ for (i = 0; i < pdata->num_modes; i++) { ++ if (pdata->modes[i].flag != flag) ++ continue; ++ return &pdata->modes[i]; ++ } ++ ++ if (i > pdata->num_modes) { ++ dev_err(ingenicfb->dev, "Find video mode fail\n"); ++ return NULL; ++ } ++ ++ return NULL; ++} ++ ++static void ingenicfb_config_fg0(struct fb_info *info) ++{ ++ unsigned int rgb_ctrl, cfg; ++ struct ingenicfb *ingenicfb = info->par; ++ struct ingenicfb_osd_t *osd = &ingenicfb->osd; ++ struct fb_videomode *mode = info->mode; ++ ++ if (!mode) { ++ dev_err(ingenicfb->dev, "%s, video mode is NULL\n", __func__); ++ return; ++ } ++ osd->fg0.fg = 0; ++ osd->fg0.bpp = ingenicfb_get_controller_bpp(ingenicfb) == 32 ? 32 : 16; ++ osd->fg0.x = osd->fg0.y = 0; ++ osd->fg0.w = mode->xres; ++ osd->fg0.h = mode->yres; ++ ++ /* OSD mode enable and alpha blending is enabled */ ++ cfg = LCDC_OSDC_OSDEN | LCDC_OSDC_ALPHAEN; ++ cfg |= 1 << 16; /* once transfer two pixels */ ++ ++ if (ingenicfb->fmt_order == FORMAT_X8B8G8R8) { ++ rgb_ctrl = ++ LCDC_RGBC_RGBFMT | LCDC_RGBC_ODD_BGR | LCDC_RGBC_EVEN_BGR; ++ } else { ++ /* default: FORMAT_X8R8G8B8 */ ++ rgb_ctrl = ++ LCDC_RGBC_RGBFMT | LCDC_RGBC_ODD_RGB | LCDC_RGBC_EVEN_RGB; ++ } ++ ++ // reg_write(ingenicfb, LCDC_OSDC, cfg); ++ // reg_write(ingenicfb, LCDC_OSDCTRL, ctrl); ++ reg_write(ingenicfb, LCDC_RGBC, rgb_ctrl); ++} ++ ++ static int ++ingenicfb_calculate_size(struct fb_info *info, struct ingenicfb_display_size *size) ++{ ++ struct ingenicfb *ingenicfb = info->par; ++ struct fb_videomode *mode = info->mode; ++ ++ if (!mode) { ++ dev_err(ingenicfb->dev, "%s, video mode is NULL\n", __func__); ++ return -EINVAL; ++ } ++ /* ++ * The rules of f0, f1's position: ++ * f0.x + f0.w <= panel.w; ++ * f0.y + f0.h <= panel.h; ++ */ ++ if ((ingenicfb->osd.fg0.x + ingenicfb->osd.fg0.w > mode->xres) | ++ (ingenicfb->osd.fg0.y + ingenicfb->osd.fg0.h > mode->yres) | ++ (ingenicfb->osd.fg0.x >= mode->xres) | (ingenicfb->osd.fg0.y >= mode->yres)) { ++ dev_info(info->dev, "Invalid foreground size or position"); ++ return -EINVAL; ++ } ++ ++ /* lcd display area */ ++ size->fg0_line_size = ingenicfb->osd.fg0.w * ingenicfb->osd.fg0.bpp >> 3; ++ /* word aligned and in word */ ++ size->fg0_line_size = ALIGN(size->fg0_line_size, 4) >> 2; ++ size->fg0_frm_size = size->fg0_line_size * ingenicfb->osd.fg0.h; ++ ++ /* panel PIXEL_ALIGN stride buffer area */ ++ size->panel_line_size = ALIGN(mode->xres, PIXEL_ALIGN) * ++ (ingenicfb->osd.fg0.bpp >> 3); ++ /* word aligned and in word */ ++ size->panel_line_size = ALIGN(size->panel_line_size, 4) >> 2; ++ ingenicfb->frm_size = size->panel_line_size * mode->yres << 2; ++ ++ size->height_width = (ingenicfb->osd.fg0.h - 1) << LCDC_DESSIZE_HEIGHT_BIT ++ & LCDC_DESSIZE_HEIGHT_MASK; ++ size->height_width |= ((ingenicfb->osd.fg0.w - 1) << LCDC_DESSIZE_WIDTH_BIT ++ & LCDC_DESSIZE_WIDTH_MASK); ++ ++ return 0; ++} ++ ++ static void ++ingenicfb_config_tft_lcd_dma(struct fb_info *info, ++ struct ingenicfb_display_size *size, ++ struct ingenicfb_framedesc *framedesc) ++{ ++ struct ingenicfb *ingenicfb = info->par; ++ ++ framedesc->next = ingenicfb->framedesc_phys; ++ framedesc->databuf = ingenicfb->vidmem_phys; ++ framedesc->id = 0xda0; ++ ++ framedesc->cmd = LCDC_CMD_EOFINT | LCDC_CMD_FRM_EN; ++ if (!ingenicfb->osd.block) { ++ framedesc->cmd |= size->fg0_frm_size; ++ framedesc->offsize = ++ (size->panel_line_size - size->fg0_line_size); ++ } else { ++ framedesc->cmd |= LCDC_CMD_16X16BLOCK; ++ framedesc->cmd |= (ingenicfb->osd.fg0.h & LCDC_CMD_LEN_MASK); ++ /* block size */ ++ /* framedesc->offsize = size->fg0_frm_size; */ ++ } ++ ++ if (framedesc->offsize == 0) { ++ framedesc->page_width = 0; ++ } else { ++ framedesc->page_width = size->fg0_line_size; ++ } ++ ++ if (ingenicfb->framedesc[0]->cpos & LCDC_CPOS_ALPHAMD1) ++ /* per pixel alpha mode */ ++ framedesc->cpos = LCDC_CPOS_ALPHAMD1; ++ else ++ framedesc->cpos = 0; ++ ++ switch (ingenicfb->osd.fg0.bpp) { ++ case 16: ++ framedesc->cpos |= LCDC_CPOS_RGB_RGB565 | LCDC_CPOS_BPP_16; ++ break; ++ case 30: ++ framedesc->cpos |= LCDC_CPOS_BPP_30; ++ break; ++ default: ++ framedesc->cpos |= LCDC_CPOS_BPP_18_24; ++ break; ++ } ++ ++ /* data has not been premultied */ ++ framedesc->cpos |= LCDC_CPOS_PREMULTI; ++ /* coef_sle 0 use 1 */ ++ framedesc->cpos |= LCDC_CPOS_COEF_SLE_1; ++ framedesc->cpos |= (ingenicfb->osd.fg0.y << LCDC_CPOS_YPOS_BIT ++ & LCDC_CPOS_YPOS_MASK); ++ framedesc->cpos |= (ingenicfb->osd.fg0.x << LCDC_CPOS_XPOS_BIT ++ & LCDC_CPOS_XPOS_MASK); ++ ++ /* fg0 alpha value */ ++ framedesc->desc_size = 0xff << LCDC_DESSIZE_ALPHA_BIT; ++ framedesc->desc_size |= size->height_width; ++} ++ ++ static void ++ingenicfb_config_smart_lcd_dma(struct fb_info *info, ++ struct ingenicfb_display_size *size, ++ struct ingenicfb_framedesc *framedesc) ++{ ++ struct ingenicfb *ingenicfb = info->par; ++ ++ framedesc->next = ++ ingenicfb->framedesc_phys + ++ sizeof(struct ingenicfb_framedesc) * (ingenicfb->desc_num - 2); ++ framedesc->databuf = ingenicfb->vidmem_phys; ++ framedesc->id = 0xda0da0; ++ ++ framedesc->cmd = LCDC_CMD_EOFINT | LCDC_CMD_FRM_EN; ++ framedesc->cmd |= size->fg0_frm_size; ++ ++ if (ingenicfb->framedesc[0]->cpos & LCDC_CPOS_ALPHAMD1) ++ /* per pixel alpha mode */ ++ framedesc->cpos = LCDC_CPOS_ALPHAMD1; ++ else ++ framedesc->cpos = 0; ++ framedesc->offsize = (size->panel_line_size - size->fg0_line_size); ++ if (framedesc->offsize == 0) { ++ framedesc->page_width = 0; ++ } else { ++ framedesc->page_width = size->fg0_line_size; ++ } ++ ++ switch (ingenicfb->osd.fg0.bpp) { ++ case 16: ++ framedesc->cpos |= LCDC_CPOS_RGB_RGB565 | LCDC_CPOS_BPP_16; ++ break; ++ case 30: ++ framedesc->cpos |= LCDC_CPOS_BPP_30; ++ break; ++ default: ++ framedesc->cpos |= LCDC_CPOS_BPP_18_24; ++ break; ++ } ++ /* data has not been premultied */ ++ framedesc->cpos |= LCDC_CPOS_PREMULTI; ++ /* coef_sle 0 use 1 */ ++ framedesc->cpos |= LCDC_CPOS_COEF_SLE_1; ++ framedesc->cpos |= (ingenicfb->osd.fg0.y << LCDC_CPOS_YPOS_BIT ++ & LCDC_CPOS_YPOS_MASK); ++ framedesc->cpos |= (ingenicfb->osd.fg0.x << LCDC_CPOS_XPOS_BIT ++ & LCDC_CPOS_XPOS_MASK); ++ ++ /* fg0 alpha value */ ++ framedesc->desc_size = 0xff << LCDC_DESSIZE_ALPHA_BIT; ++ framedesc->desc_size |= size->height_width; ++ ++ framedesc[1].next = ingenicfb->framedesc_phys; ++ framedesc[1].databuf = 0; ++ framedesc[1].id = 0xda0da1; ++ framedesc[1].cmd = LCDC_CMD_CMD | LCDC_CMD_FRM_EN | 0; ++ framedesc[1].offsize = 0; ++ framedesc[1].page_width = 0; ++ framedesc[1].cpos = 0; ++ framedesc[1].desc_size = 0; ++ ++ framedesc[2].next = ingenicfb->framedesc_phys; ++ framedesc[2].databuf = ingenicfb->desc_cmd_phys; ++ framedesc[2].id = 0xda0da2; ++ framedesc[2].offsize = 0; ++ framedesc[2].page_width = 0; ++ framedesc[2].desc_size = 0; ++ ++ /*must to optimize*/ ++ switch (ingenicfb->pdata->smart_config.bus_width) { ++ case 8: ++ framedesc[2].cmd = LCDC_CMD_CMD | LCDC_CMD_FRM_EN | 1; ++ framedesc[2].cpos = 4; ++ break; ++ case 9: ++ case 16: ++ framedesc[2].cmd = LCDC_CMD_CMD | LCDC_CMD_FRM_EN | 1; ++ framedesc[2].cpos = 2; ++ break; ++ default: ++ framedesc[2].cmd = LCDC_CMD_CMD | LCDC_CMD_FRM_EN | 1; ++ framedesc[2].cpos = 1; ++ break; ++ } ++} ++#if 0 ++ static void ++ingenicfb_config_fg1_dma(struct fb_info *info, struct ingenicfb_display_size *size) ++{ ++ struct ingenicfb *ingenicfb = info->par; ++ ++ /* ++ * the descriptor of DMA 1 just init once ++ * and generally no need to use it ++ */ ++ if (ingenicfb->fg1_framedesc){ ++ reg_write(ingenicfb, LCDC_DA1, ingenicfb->fg1_framedesc->next); ++ return; ++ } ++ ++ ingenicfb->fg1_framedesc = ingenicfb->framedesc[0] + (ingenicfb->desc_num - 1); ++ ingenicfb->fg1_framedesc->next = ++ ingenicfb->framedesc_phys + ++ sizeof(struct ingenicfb_framedesc) * (ingenicfb->desc_num - 1); ++ ++ ingenicfb->fg1_framedesc->databuf = 0; ++ ingenicfb->fg1_framedesc->id = 0xda1; ++ ingenicfb->fg1_framedesc->cmd = (LCDC_CMD_EOFINT & ~LCDC_CMD_FRM_EN) ++ | size->fg0_frm_size; ++ ingenicfb->fg1_framedesc->offsize = 0; ++ ingenicfb->fg1_framedesc->page_width = 0; ++ ++ /* global alpha mode, data has not been premultied, COEF_SLE is 11 */ ++ ingenicfb->fg1_framedesc->cpos = LCDC_CPOS_BPP_18_24 | ingenicfb->osd.fg0.y << ++ LCDC_CPOS_YPOS_BIT | ingenicfb->osd.fg0.x | LCDC_CPOS_PREMULTI ++ | LCDC_CPOS_COEF_SLE_3; ++ ++ ingenicfb->fg1_framedesc->desc_size = size->height_width | 0xff << ++ LCDC_DESSIZE_ALPHA_BIT; ++ ++ reg_write(ingenicfb, LCDC_DA1, ingenicfb->fg1_framedesc->next); ++} ++#endif ++static int ingenicfb_prepare_dma_desc(struct fb_info *info) ++{ ++ int i; ++ struct ingenicfb *ingenicfb = info->par; ++ struct ingenicfb_display_size *display_size; ++ struct ingenicfb_framedesc *framedesc[MAX_DESC_NUM]; ++ unsigned int val; ++ display_size = kmalloc(sizeof(struct ingenicfb_display_size), GFP_KERNEL); ++ framedesc[0] = kmalloc(sizeof(struct ingenicfb_framedesc) * ++ (ingenicfb->desc_num - 1), GFP_KERNEL); ++ for (i = 1; i < ingenicfb->desc_num - 1; i++) ++ framedesc[i] = framedesc[0] + i; ++ ++ ingenicfb_calculate_size(info, display_size); ++ ++ if (ingenicfb->pdata->lcd_type != LCD_TYPE_SLCD) { ++ ingenicfb_config_tft_lcd_dma(info, display_size, framedesc[0]); ++ } else { ++ ingenicfb_config_smart_lcd_dma(info, display_size, framedesc[0]); ++ } ++ ++ for (i = 0; i < ingenicfb->desc_num - 1; i++) { ++ ingenicfb->framedesc[i]->next = framedesc[i]->next; ++ ingenicfb->framedesc[i]->databuf = framedesc[i]->databuf; ++ ingenicfb->framedesc[i]->id = framedesc[i]->id; ++ ingenicfb->framedesc[i]->cmd = framedesc[i]->cmd; ++ ingenicfb->framedesc[i]->offsize = framedesc[i]->offsize; ++ ingenicfb->framedesc[i]->page_width = framedesc[i]->page_width; ++ ingenicfb->framedesc[i]->cpos = framedesc[i]->cpos; ++ ingenicfb->framedesc[i]->desc_size = framedesc[i]->desc_size; ++ } ++ ++ if (ingenicfb->pdata->lcd_type != LCD_TYPE_SLCD) { ++ reg_write(ingenicfb, LCDC_DA0, ingenicfb->framedesc[0]->next); ++ } else { ++ //reg_write(ingenicfb, LCDC_DA0, (unsigned int)virt_to_phys((void *) ++ // reg_write(ingenicfb, LCDC_DA0, 0x20006666); ++ //reg_write(ingenicfb, LCDC_DA0, (unsigned int)virt_to_phys((void *)ingenicfb->framedesc[2])); ++ val = (unsigned int)ingenicfb->framedesc[2] - 0xa0000000; ++ ++ reg_write(ingenicfb, LCDC_DA0, val); ++ } ++ // ingenicfb_config_fg1_dma(info, display_size); ++ kzfree(framedesc[0]); ++ kzfree(display_size); ++ ++ return 0; ++} ++ ++static int ingenicfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) ++{ ++ struct ingenicfb *ingenicfb = info->par; ++ struct fb_videomode *mode; ++ ++ if (var->bits_per_pixel != ingenicfb_get_controller_bpp(ingenicfb) && ++ var->bits_per_pixel != ingenicfb->pdata->bpp) ++ return -EINVAL; ++ mode = ingenicfb_get_mode(var, info); ++ if (mode == NULL) { ++ dev_err(info->dev, "%s get video mode failed\n", __func__); ++ return -EINVAL; ++ } ++ ++ ingenicfb_videomode_to_var(var, mode, ingenicfb->pdata->lcd_type); ++ ++ switch (ingenicfb->fb_bpp) { ++ case 16: ++ var->red.offset = 11; ++ var->red.length = 5; ++ var->green.offset = 5; ++ var->green.length = 6; ++ var->blue.offset = 0; ++ var->blue.length = 5; ++ break; ++ case 17 ... 32: ++ if (ingenicfb->fmt_order == FORMAT_X8B8G8R8) { ++ var->red.offset = 0; ++ var->green.offset = 8; ++ var->blue.offset = 16; ++ } else { ++ /* default: FORMAT_X8R8G8B8 */ ++ var->red.offset = 16; ++ var->green.offset = 8; ++ var->blue.offset = 0; ++ } ++ ++ var->transp.offset = 24; ++ var->transp.length = 8; ++ var->red.length = 8; ++ var->green.length = 8; ++ var->blue.length = 8; ++ var->bits_per_pixel = 32; ++ break; ++ default: ++ dev_err(ingenicfb->dev, "Not support for %d bpp\n", ++ ingenicfb->pdata->bpp); ++ break; ++ } ++ ++ return 0; ++} ++ ++/* Sent a command without data (18-bit bus, 16-bit index) */ ++static void slcd_send_mcu_command(struct ingenicfb *ingenicfb, unsigned long cmd) ++{ ++ int count = 10000; ++ while ((reg_read(ingenicfb, SLCDC_STATE) & SLCDC_STATE_BUSY) && count--) { ++ udelay(10); ++ } ++ if (count < 0) { ++ dev_err(ingenicfb->dev, "SLCDC wait busy state wrong"); ++ } ++ reg_write(ingenicfb, SLCDC_DATA, SLCDC_DATA_RS_COMMAND | cmd); ++} ++ ++static void slcd_send_mcu_data(struct ingenicfb *ingenicfb, unsigned long data) ++{ ++ int count = 10000; ++ ++ while ((reg_read(ingenicfb, SLCDC_STATE) & SLCDC_STATE_BUSY) && count--) { ++ udelay(10); ++ } ++ if (count < 0) { ++ dev_err(ingenicfb->dev, "SLCDC wait busy state wrong"); ++ } ++ ++ reg_write(ingenicfb, SLCDC_DATA, SLCDC_DATA_RS_DATA | data); ++} ++ ++static void ingenicfb_slcd_mcu_init(struct fb_info *info) ++{ ++ unsigned int is_lcd_en, i, j; ++ struct ingenicfb *ingenicfb = info->par; ++ struct ingenicfb_platform_data *pdata = ingenicfb->pdata; ++ unsigned int data_table_width = pdata->smart_config.data_table_width; ++ unsigned int bus_width = pdata->smart_config.bus_width; ++ ++ data_table_width = (data_table_width > bus_width) ? data_table_width : bus_width; ++ ++ if (pdata->lcd_type != LCD_TYPE_SLCD) ++ return; ++ ++ is_lcd_en = ingenicfb->is_lcd_en; ++ ingenicfb_enable(info); ++ ++#ifndef CONFIG_GPIO_SIMULATE ++ if (pdata->smart_config.gpio_for_slcd) { ++ pdata->smart_config.gpio_for_slcd(); ++ } ++#endif ++ /* ++ *set cmd_width and data_width ++ * */ ++ if (pdata->smart_config.length_data_table ++ && pdata->smart_config.data_table) { ++ for (i = 0; i < pdata->smart_config.length_data_table; i++) { ++ unsigned int value = pdata->smart_config.data_table[i].value; ++ switch (pdata->smart_config.data_table[i].type) { ++ case SMART_CONFIG_DATA: ++ for (j = data_table_width/bus_width; j>0; j--) ++ slcd_send_mcu_data(ingenicfb, ++ ((value << (32 - bus_width * j)) >> (32 - bus_width))); ++ break; ++ case SMART_CONFIG_CMD: ++ for (j = data_table_width/bus_width; j>0; j--) ++ slcd_send_mcu_command(ingenicfb, ++ ((value << (32 - bus_width * j)) >> (32 - bus_width))); ++ break; ++ case SMART_CONFIG_UDELAY: ++ udelay(value); ++ break; ++ default: ++ dev_err(ingenicfb->dev, "Unknow SLCD data type\n"); ++ break; ++ } ++ } ++ { ++ int count = 10000; ++ while ((reg_read(ingenicfb, SLCDC_STATE) & SLCDC_STATE_BUSY) ++ && count--) { ++ udelay(10); ++ } ++ if (count < 0) { ++ dev_err(ingenicfb->dev, ++ "SLCDC wait busy state wrong"); ++ } ++ ++ } ++ ++ } ++ ++ if(pdata->bpp / pdata->smart_config.bus_width != 1 ) { ++ int tmp = reg_read(ingenicfb, SLCDC_CFG_NEW); ++ tmp &= ~(SMART_LCD_NEW_DTIMES_MASK); //mask the 8~9bit ++ tmp |= (pdata->bpp / pdata->smart_config.bus_width) == 2 ? SMART_LCD_NEW_DTIMES_TWICE : SMART_LCD_NEW_DTIMES_THICE; ++ reg_write(ingenicfb, SLCDC_CFG_NEW, tmp); ++ dev_dbg(ingenicfb->dev, "the slcd slcd_cfg_new is %08x\n", tmp); ++ } ++#ifdef CONFIG_LCD_TRULY_TFT240240_2_2E ++ reg_write(ingenicfb,SLCDC_CFG,reg_read(ingenicfb, SLCDC_CFG) & ~(0x01<<8)); ++ reg_write(ingenicfb,SLCDC_CFG_NEW,reg_read(ingenicfb,SLCDC_CFG_NEW) | (0x01<<13)); ++#endif ++#ifdef CONFIG_FB_INGENIC_DEBUG ++ /*for register mode test, ++ * you can write test code according to the lcd panel ++ **/ ++#endif ++ ++ /*recovery ori status*/ ++ if (!is_lcd_en) { ++ ingenicfb_disable(info); ++ } ++ ++} ++ ++void ingenicfb_clk_enable(struct ingenicfb *ingenicfb) ++{ ++ /* if(!__clk_is_enabled(ingenicfb->clk)) */ ++ if(ingenicfb->is_clk_en) ++ return ; ++ clk_prepare_enable(ingenicfb->clk); ++ ingenicfb->is_clk_en = 1; ++} ++void ingenicfb_clk_disable(struct ingenicfb *ingenicfb) ++{ ++ /* if(__clk_is_enabled(ingenicfb->clk)) */ ++ if(!ingenicfb->is_clk_en) ++ return ; ++ ingenicfb->is_clk_en = 0; ++ clk_disable_unprepare(ingenicfb->clk); ++} ++ ++void ingenicfb_pclk_enable(struct ingenicfb *ingenicfb) ++{ ++// if(!__clk_is_enabled(ingenicfb->pclk)) ++ if(ingenicfb->is_pclk_en) ++ return ; ++ clk_prepare_enable(ingenicfb->pclk); ++ ingenicfb->is_pclk_en = 1; ++} ++ ++void ingenicfb_pclk_disable(struct ingenicfb *ingenicfb) ++{ ++// if(__clk_is_enabled(ingenicfb->pclk)) ++ if(!ingenicfb->is_pclk_en) ++ return ; ++ ingenicfb->is_pclk_en = 0; ++ clk_disable_unprepare(ingenicfb->pclk); ++} ++ ++static void ingenicfb_enable(struct fb_info *info) ++{ ++ uint32_t ctrl; ++ struct ingenicfb *ingenicfb = info->par; ++ int count = 2000; ++ ++ if (ingenicfb->is_lcd_en) { ++ while ((reg_read(ingenicfb, SLCDC_STATE) & SLCDC_STATE_BUSY) && count) { ++ count--; ++ udelay(10); ++ } ++ } ++/* ++ if (!count) ++ dump_stack(); ++*/ ++ mutex_lock(&ingenicfb->lock); ++ if (ingenicfb->is_lcd_en) { ++ mutex_unlock(&ingenicfb->lock); ++ return; ++ } ++ ++ reg_write(ingenicfb, LCDC_STATE, 0); ++ ctrl = reg_read(ingenicfb, LCDC_CTRL); ++ ctrl |= LCDC_CTRL_ENA; ++ reg_write(ingenicfb, LCDC_CTRL, ctrl); ++ ++ ingenicfb->is_lcd_en = 1; ++ mutex_unlock(&ingenicfb->lock); ++} ++ ++static void ingenicfb_disable(struct fb_info *info) ++{ ++ uint32_t ctrl; ++ struct ingenicfb *ingenicfb = info->par; ++ ++ mutex_lock(&ingenicfb->lock); ++ if (!ingenicfb->is_lcd_en) { ++ mutex_unlock(&ingenicfb->lock); ++ return; ++ } ++ ++ /* SLCD and TVE only support quick disable */ ++ ctrl = reg_read(ingenicfb, LCDC_CTRL); ++ ctrl &= ~LCDC_CTRL_ENA; ++ reg_write(ingenicfb, LCDC_CTRL, ctrl); ++ ingenicfb->is_lcd_en = 0; ++ udelay(10); ++ mutex_unlock(&ingenicfb->lock); ++ ++} ++ ++static int ingenicfb_set_par(struct fb_info *info) ++{ ++ struct ingenicfb *ingenicfb = info->par; ++ struct ingenicfb_platform_data *pdata = ingenicfb->pdata; ++ struct fb_var_screeninfo *var = &info->var; ++ struct fb_videomode *mode; ++ int is_lcd_en; ++ uint16_t hds, vds; ++ uint16_t hde, vde; ++ uint16_t ht, vt; ++ uint32_t cfg, ctrl; ++ uint32_t smart_cfg = 0, smart_ctrl = 0; ++ uint32_t smart_new_cfg = 0; ++ uint32_t smart_wtime = 0, smart_tas = 0; ++ uint32_t pcfg; ++ unsigned long rate; ++ ++ mode = ingenicfb_get_mode(var, info); ++ if (mode == NULL) { ++ dev_err(info->dev, "%s get video mode failed\n", __func__); ++ return -EINVAL; ++ } ++#if 0 ++ if (mode == info->mode){ ++ printk("+++++mode=%d info->mode=%d\n",mode,info->mode); ++ return 0; ++ } ++#endif ++ info->mode = mode; ++ ++ hds = mode->hsync_len + mode->left_margin; ++ hde = hds + mode->xres; ++ ht = hde + mode->right_margin; ++ ++ vds = mode->vsync_len + mode->upper_margin; ++ vde = vds + mode->yres; ++ vt = vde + mode->lower_margin; ++ ++ /* ++ * configure LCDC config register ++ * use 8words descriptor, not use palette ++ * ! M200 NOT SUPPORT PALETTE FUNCTION, DO NOT SET LCDC_CFG_PALBP(BIT27), IT CAUGHT BPP16 COLOR ERROR. ++ */ ++ /*SET PALBP TO AVOID FORMAT TRANSFER */ ++ ++ cfg = LCDC_CFG_NEWDES | LCDC_CFG_RECOVER; ++ cfg |= pdata->lcd_type; ++ ++ if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT)) ++ cfg |= LCDC_CFG_HSP; ++ ++ if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT)) ++ cfg |= LCDC_CFG_VSP; ++ ++ if (pdata->pixclk_falling_edge) ++ cfg |= LCDC_CFG_PCP; ++ ++ if (pdata->data_enable_active_low) ++ cfg |= LCDC_CFG_DEP; ++ ++ /* configure LCDC control register */ ++ ctrl = LCDC_CTRL_BST_64 | LCDC_CTRL_OFUM; ++ if (pdata->pinmd) ++ ctrl |= LCDC_CTRL_PINMD; ++ ++ pcfg = 0xC0000000 | (511 << 18) | (400 << 9) | (256 << 0); ++ ++ /* configure smart LCDC registers */ ++ if (pdata->lcd_type == LCD_TYPE_SLCD) { ++ switch(pdata->smart_config.bus_width){ ++ case 8: ++ smart_cfg |= SMART_LCD_CWIDTH_8_BIT_ONCE; ++ smart_new_cfg |= SMART_LCD_NEW_DWIDTH_8_BIT; ++ break; ++ case 9: ++#ifdef CONFIG_LCD_TRULY_TFT240240_2_2E ++ smart_cfg |= SMART_LCD_CWIDTH_8_BIT_ONCE; ++ smart_new_cfg |= SMART_LCD_NEW_DWIDTH_8_BIT; ++#else ++ smart_cfg |= SMART_LCD_CWIDTH_9_BIT_ONCE; ++ smart_new_cfg |= SMART_LCD_NEW_DWIDTH_16_BIT; ++#endif ++ break; ++ case 16: ++ smart_cfg |= SMART_LCD_CWIDTH_16_BIT_ONCE; ++ smart_new_cfg |= SMART_LCD_NEW_DWIDTH_16_BIT; ++ break; ++ case 18: ++ smart_cfg |= SMART_LCD_CWIDTH_18_BIT_ONCE; ++ smart_new_cfg |= SMART_LCD_NEW_DWIDTH_18_BIT; ++ break; ++ case 24: ++ smart_cfg |= SMART_LCD_CWIDTH_24_BIT_ONCE; ++ smart_new_cfg |= SMART_LCD_NEW_DWIDTH_24_BIT; ++ break; ++ default: ++ printk("ERR: please check out your bus width config\n"); ++ break; ++ } ++ ++ if (pdata->smart_config.clkply_active_rising) ++ smart_cfg |= SLCDC_CFG_CLK_ACTIVE_RISING; ++ if (pdata->smart_config.rsply_cmd_high) ++ smart_cfg |= SLCDC_CFG_RS_CMD_HIGH; ++ if (pdata->smart_config.csply_active_high) ++ smart_cfg |= SLCDC_CFG_CS_ACTIVE_HIGH; ++ ++ smart_ctrl = SLCDC_CTRL_DMA_MODE; ++ //smart_ctrl |= SLCDC_CTRL_GATE_MASK; //for saving power ++ smart_ctrl &= ~SLCDC_CTRL_GATE_MASK; ++ ++ smart_ctrl |= (SLCDC_CTRL_NEW_MODE | SLCDC_CTRL_NOT_USE_TE | SLCDC_CTRL_FAST_MODE); //new slcd mode ++ smart_ctrl &= ~SLCDC_CTRL_MIPI_MODE; ++ smart_new_cfg |= SMART_LCD_NEW_DTIMES_ONCE; ++ ++ if (pdata->smart_config.newcfg_6800_md) ++ smart_new_cfg |= SLCDC_NEW_CFG_6800_MD; ++ if (pdata->smart_config.datatx_type_serial ++ && pdata->smart_config.cmdtx_type_serial) ++ smart_new_cfg |= ++ SLCDC_NEW_CFG_DTYPE_SERIAL | ++ SLCDC_NEW_CFG_CTYPE_SERIAL; ++ if (pdata->smart_config.newcfg_cmd_9bit) ++ smart_new_cfg |= SLCDC_NEW_CFG_CMD_9BIT; ++ ++ smart_wtime = 0; ++ smart_tas = 0; ++ } ++ ++ if (mode->pixclock) { ++ rate = PICOS2KHZ(mode->pixclock) * 1000; ++ mode->refresh = rate / vt / ht; ++ } else { ++ if (pdata->lcd_type == LCD_TYPE_8BIT_SERIAL) { ++ rate = mode->refresh * (vt + 2 * mode->xres) * ht; ++ } else { ++ rate = mode->refresh * vt * ht; ++ } ++ mode->pixclock = KHZ2PICOS(rate / 1000); ++ ++ var->pixclock = mode->pixclock; ++ } ++ // printk("lcd pixel rate is :::::::::::::::::::::::::::::::::::::::%d\n",rate); ++ /*set reg,and enable lcd after set all reg*/ ++ is_lcd_en = ingenicfb->is_lcd_en; ++ ingenicfb_disable(info); ++ ++ mutex_lock(&ingenicfb->lock); ++ ++ switch (pdata->lcd_type) { ++ case LCD_TYPE_SPECIAL_TFT_1: ++ case LCD_TYPE_SPECIAL_TFT_2: ++ case LCD_TYPE_SPECIAL_TFT_3: ++ reg_write(ingenicfb, LCDC_SPL, pdata->special_tft_config.spl); ++ reg_write(ingenicfb, LCDC_CLS, pdata->special_tft_config.cls); ++ reg_write(ingenicfb, LCDC_PS, pdata->special_tft_config.ps); ++ reg_write(ingenicfb, LCDC_REV, pdata->special_tft_config.ps); ++ break; ++ default: ++ cfg |= LCDC_CFG_PSM; ++ cfg |= LCDC_CFG_CLSM; ++ cfg |= LCDC_CFG_SPLM; ++ cfg |= LCDC_CFG_REVM; ++ break; ++ } ++ ++ if (pdata->lcd_type != LCD_TYPE_SLCD) { ++ reg_write(ingenicfb, LCDC_VAT, (ht << 16) | vt); ++ ++ /* ++ * If you are using a VGA output, ++ * then you need to last a pix of the value is set to 0, ++ * you can add the background size widened, that is, ++ * the increase in the value of the VDE, plus at least 1, ++ * the maximum can not exceed the value of VT. ++ * Example: ++ * LCD monitor manufacturers: ViewSonic ++ * Model: VA926. ++ * Set the resolution: 1280 * 1024 ++ * To set the parameters in xxx_lcd.c need to pay attention to: ++ * 1. The timing need to use the standard timing ++ * 2. If you will be using a VGA display, .flag = FB_MODE_IS_VGA ++ * 3. sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, ++ * The sync trigger for the high level active ++ * 4. pixclk_falling_edge = 1, PIX clock trigger high level ++ * 5. data_enable_active_low = 1, DATA enable is high level ++ */ ++ ++ if (mode->flag & FB_MODE_IS_VGA) { ++ if ((hde + 8) <= ht) ++ hde += 8; ++ else if ((hde + 1) <= ht) ++ hde += 1; ++ /* ++ if(vds > 2 && (vde + 2) <= vt){ ++ vds -= 2; ++ vde += 2; ++ } ++ */ ++ info->fix.line_length = info->var.bits_per_pixel * ++ ALIGN(mode->xres, PIXEL_ALIGN) >> 3; ++ } ++ ++ reg_write(ingenicfb, LCDC_DAH, (hds << 16) | hde); ++ reg_write(ingenicfb, LCDC_DAV, (vds << 16) | vde); ++ ++ reg_write(ingenicfb, LCDC_HSYNC, mode->hsync_len); ++ reg_write(ingenicfb, LCDC_VSYNC, mode->vsync_len); ++ } else { ++ reg_write(ingenicfb, LCDC_VAT, (mode->xres << 16) | mode->yres); ++ reg_write(ingenicfb, LCDC_DAH, mode->xres); ++ reg_write(ingenicfb, LCDC_DAV, mode->yres); ++ ++ reg_write(ingenicfb, LCDC_HSYNC, 0); ++ reg_write(ingenicfb, LCDC_VSYNC, 0); ++ ++ reg_write(ingenicfb, SLCDC_CFG, smart_cfg); ++ reg_write(ingenicfb, SLCDC_CTRL, smart_ctrl); ++ ++ reg_write(ingenicfb, SLCDC_CFG_NEW, smart_new_cfg); ++ reg_write(ingenicfb, SLCDC_WTIME, smart_wtime); ++ reg_write(ingenicfb, SLCDC_TAS, smart_tas); ++ ++ } ++ ++ reg_write(ingenicfb, LCDC_CFG, cfg); ++ ctrl |= reg_read(ingenicfb, LCDC_CTRL); ++ reg_write(ingenicfb, LCDC_CTRL, ctrl); ++ reg_write(ingenicfb, LCDC_PCFG, pcfg); ++ ++ ingenicfb_config_fg0(info); ++ // printk("this once called ingenicfb_prepare_dma_desc() in this function::%s00000000000000\n",__func__); ++ ingenicfb_prepare_dma_desc(info); ++ mutex_unlock(&ingenicfb->lock); ++ ++ ingenicfb_pclk_disable(ingenicfb); ++ clk_set_rate(ingenicfb->pclk, rate); ++ ingenicfb_pclk_enable(ingenicfb); ++ ++ if (!ingenicfb->is_suspend) { ++ /*avoid printk after every wake up */ ++ dev_dbg(ingenicfb->dev, "LCDC: PixClock:%lu\n", rate); ++ dev_dbg(ingenicfb->dev, "LCDC: PixClock:%lu(real)\n", clk_get_rate(ingenicfb->pclk)); ++ } ++ ++ // ingenicfb_config_image_enh(info); ++ if (pdata->lcd_type == LCD_TYPE_SLCD) { ++ ingenicfb_slcd_mcu_init(info); ++ ++#ifdef CONFIG_SLCDC_CONTINUA ++ smart_ctrl &= ~SLCDC_CTRL_DMA_MODE; ++#else ++ smart_ctrl |= SLCDC_CTRL_DMA_START; ++#endif ++ smart_ctrl |= SLCDC_CTRL_DMA_EN; ++ ++#ifdef CONFIG_SLCDC_USE_TE ++ smart_ctrl &= ~SLCDC_CTRL_NOT_USE_TE; ++#endif ++ ++ if (pdata->smart_config.newcfg_fmt_conv) { ++ smart_new_cfg = reg_read(ingenicfb, SLCDC_CFG_NEW); ++ smart_new_cfg |= SLCDC_NEW_CFG_FMT_CONV_EN; ++ reg_write(ingenicfb, SLCDC_CFG_NEW, smart_new_cfg); ++ } ++ if (pdata->smart_config.bus_width == 9) { ++ smart_new_cfg = reg_read(ingenicfb, SLCDC_CFG_NEW); ++ smart_new_cfg &= ~(SMART_LCD_NEW_DWIDTH_MASK); ++ smart_new_cfg |= SMART_LCD_NEW_DWIDTH_9_BIT; ++ reg_write(ingenicfb, SLCDC_CFG_NEW, smart_new_cfg); ++ } ++ reg_write(ingenicfb, SLCDC_CTRL, smart_ctrl); ++ } ++ ++ if (is_lcd_en) { ++ ingenicfb_enable(info); ++ } ++ ++ ingenicfb->is_inited = 1; ++ return 0; ++} ++ ++static int ingenicfb_blank(int blank_mode, struct fb_info *info) ++{ ++ int count = 10000; ++ unsigned long ctrl; ++ struct ingenicfb *ingenicfb = info->par; ++ ++ switch (blank_mode) { ++ case FB_BLANK_UNBLANK: ++ reg_write(ingenicfb, LCDC_STATE, 0); ++ reg_write(ingenicfb, LCDC_OSDS, 0); ++ ctrl = reg_read(ingenicfb, LCDC_CTRL); ++ ctrl |= LCDC_CTRL_ENA; ++ ctrl &= ~LCDC_CTRL_DIS; ++ reg_write(ingenicfb, LCDC_CTRL, ctrl); ++ ++ mutex_lock(&ingenicfb->suspend_lock); ++ if (ingenicfb->is_suspend) { ++ ingenicfb->is_suspend = 0; ++ mutex_unlock(&ingenicfb->suspend_lock); ++ } else { ++ mutex_unlock(&ingenicfb->suspend_lock); ++ } ++ ingenicfb->is_lcd_en = 1; ++ break; ++ default: ++ if (ingenicfb->pdata->lcd_type != LCD_TYPE_SLCD) { ++ ctrl = reg_read(ingenicfb, LCDC_CTRL); ++ ctrl |= LCDC_CTRL_DIS; ++ reg_write(ingenicfb, LCDC_CTRL, ctrl); ++ while (!(reg_read(ingenicfb, LCDC_STATE) & LCDC_STATE_LDD) ++ && count--) { ++ udelay(10); ++ } ++ if (count >= 0) { ++ ctrl = reg_read(ingenicfb, LCDC_STATE); ++ ctrl &= ~LCDC_STATE_LDD; ++ reg_write(ingenicfb, LCDC_STATE, ctrl); ++ } else { ++ dev_err(ingenicfb->dev, "LCDC disable state wrong\n"); ++ } ++ } else { ++ ctrl = reg_read(ingenicfb, LCDC_CTRL); ++ ctrl &= ~LCDC_CTRL_ENA; ++ reg_write(ingenicfb, LCDC_CTRL, ctrl); ++ ++ ctrl = reg_read(ingenicfb, SLCDC_CTRL); ++ ctrl &= ~SLCDC_CTRL_DMA_EN; ++ reg_write(ingenicfb, SLCDC_CTRL, ctrl); ++ } ++ ingenicfb->is_lcd_en = 0; ++ } ++ ++ return 0; ++} ++ ++static int ingenicfb_alloc_devmem(struct ingenicfb *ingenicfb) ++{ ++ int i; ++ unsigned int videosize = 0; ++ struct fb_videomode *mode; ++ void *page; ++ ++ ingenicfb->framedesc[0] = ++ dma_alloc_coherent(ingenicfb->dev, ++ sizeof(struct ingenicfb_framedesc) * ingenicfb->desc_num, ++ &ingenicfb->framedesc_phys, GFP_KERNEL); ++ if (!ingenicfb->framedesc[0]) ++ return -ENOMEM; ++ for (i = 1; i < ingenicfb->desc_num; i++){ ++ ingenicfb->framedesc[i] = ingenicfb->framedesc[0] + i; ++ } ++ ++ mode = ingenicfb->pdata->modes; ++ if (!mode) { ++ dev_err(ingenicfb->dev, "Checkout video mode fail\n"); ++ return -EINVAL; ++ } ++ ++ if (mode->flag & FB_MODE_IS_VGA) { ++ mode = ingenicfb_checkout_max_vga_videomode(ingenicfb->fb); ++ if (!mode) { ++ dev_err(ingenicfb->dev, ++ "Checkout VGA max pix video mode fail\n"); ++ return -EINVAL; ++ } ++ } ++ ++ videosize = ALIGN(mode->xres, PIXEL_ALIGN) * mode->yres; ++ videosize *= ingenicfb_get_controller_bpp(ingenicfb) >> 3; ++ videosize *= NUM_FRAME_BUFFERS; ++ ++ ingenicfb->vidmem_size = PAGE_ALIGN(videosize); ++ ++ /** ++ * Use the dma alloc coherent has waste some space, ++ * If you need to alloc buffer for dma, open it, ++ * else close it and use the Kmalloc. ++ * And in ingenicfb_free_devmem() function is also set. ++ */ ++ ingenicfb->vidmem = dma_alloc_coherent(ingenicfb->dev, ++ ingenicfb->vidmem_size, ++ &ingenicfb->vidmem_phys, GFP_KERNEL); ++ if (!ingenicfb->vidmem) ++ return -ENOMEM; ++ for (page = ingenicfb->vidmem; ++ page < ingenicfb->vidmem + PAGE_ALIGN(ingenicfb->vidmem_size); ++ page += PAGE_SIZE) { ++ SetPageReserved(virt_to_page(page)); ++ } ++ ++ if (ingenicfb->pdata->lcd_type == LCD_TYPE_SLCD) { ++ int i; ++ unsigned long *ptr; ++ ingenicfb->desc_cmd_vidmem = dma_alloc_coherent(ingenicfb->dev, PAGE_SIZE, ++ &ingenicfb->desc_cmd_phys, ++ GFP_KERNEL); ++ ptr = (unsigned long *)ingenicfb->desc_cmd_vidmem; ++ for (i = 0; i < ingenicfb->pdata->smart_config.length_cmd; i++) { ++ ptr[i] = ingenicfb->pdata->smart_config.write_gram_cmd[i]; ++ } ++ } ++ ++ dev_dbg(ingenicfb->dev, "Frame buffer size: %d bytes\n", ingenicfb->vidmem_size); ++ ++ return 0; ++} ++ ++static void ingenicfb_free_devmem(struct ingenicfb *ingenicfb) ++{ ++ dma_free_coherent(ingenicfb->dev, ingenicfb->vidmem_size, ++ ingenicfb->vidmem, ingenicfb->vidmem_phys); ++ dma_free_coherent(ingenicfb->dev, ++ sizeof(struct ingenicfb_framedesc) * ingenicfb->desc_num, ++ ingenicfb->framedesc, ingenicfb->framedesc_phys); ++ if (ingenicfb->pdata->lcd_type == LCD_TYPE_SLCD) { ++ dma_free_coherent(ingenicfb->dev, PAGE_SIZE, ++ ingenicfb->desc_cmd_vidmem, ingenicfb->desc_cmd_phys); ++ } ++} ++ ++#define SPEC_TIME_IN_NS (1000*1000000) /* 1s */ ++static int ingenicfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) ++{ ++ int next_frm; ++ unsigned int tmp = 0; ++ struct ingenicfb *ingenicfb = info->par; ++ ++ {/*debug*/ ++ static struct timespec time_now, time_last; ++ struct timespec time_interval; ++ long long interval_in_ns; ++ unsigned int interval_in_ms; ++ static unsigned int fpsCount = 0; ++ ++ ingenicfb->pan_display_count++; ++ if(showFPS){ ++ switch(showFPS){ ++ case 1: ++ fpsCount++; ++ time_now = current_kernel_time(); ++ time_interval = timespec_sub(time_now, time_last); ++ interval_in_ns = timespec_to_ns(&time_interval); ++ if ( interval_in_ns > SPEC_TIME_IN_NS ) { ++ printk(KERN_DEBUG " Pan display FPS: %d\n",fpsCount); ++ fpsCount = 0; ++ time_last = time_now; ++ } ++ break; ++ case 2: ++ time_now = current_kernel_time(); ++ time_interval = timespec_sub(time_now, time_last); ++ interval_in_ns = timespec_to_ns(&time_interval); ++ interval_in_ms = (unsigned long)interval_in_ns/1000000; ++ printk(KERN_DEBUG " Pan display interval: %d\n",interval_in_ms); ++ time_last = time_now; ++ break; ++ default: ++ break; ++ } ++ } ++ }/*end debug*/ ++ if (var->xoffset - info->var.xoffset) { ++ dev_err(info->dev, "No support for X panning for now\n"); ++ return -EINVAL; ++ } ++ ++ if (var->yres == 720 || var->yres == 1080) { /* work around for HDMI device */ ++ switch (var->yoffset) { ++ case 1440: ++ case (1080 * 2): ++ next_frm = 2; ++ break; ++ case 720: ++ case (1080 * 1): ++ next_frm = 1; ++ break; ++ default: ++ next_frm = 0; ++ break; ++ } ++ } else ++ next_frm = var->yoffset / var->yres; ++ ++ ingenicfb->current_buffer = next_frm; ++ ++ if (ingenicfb->pdata->lcd_type != LCD_TYPE_INTERLACED_TV && ++ ingenicfb->pdata->lcd_type != LCD_TYPE_SLCD) { ++ if (!ingenicfb->osd.block) { ++ ingenicfb->framedesc[0]->databuf = ingenicfb->vidmem_phys ++ + ingenicfb->frm_size * next_frm; ++ } else { ++ /* 16x16 block mode */ ++ } ++ } else if (ingenicfb->pdata->lcd_type == LCD_TYPE_SLCD) { ++ /* smart tft spec code here */ ++ ingenicfb->framedesc[0]->databuf = ingenicfb->vidmem_phys ++ + ingenicfb->frm_size * next_frm; ++ if (!ingenicfb->is_lcd_en) ++ return -EINVAL;; ++ ++ if (ingenicfb->pdata->lcd_callback_ops.dma_transfer_begin){ ++ ingenicfb->pdata->lcd_callback_ops.dma_transfer_begin(ingenicfb); ++ tmp = reg_read(ingenicfb, SLCDC_CTRL); ++ tmp |= SLCDC_CTRL_DMA_START | SLCDC_CTRL_DMA_MODE; ++ reg_write(ingenicfb, SLCDC_CTRL, tmp); ++ }else{ ++ tmp = reg_read(ingenicfb, SLCDC_CTRL); ++ tmp |= SLCDC_CTRL_DMA_START | SLCDC_CTRL_DMA_MODE; ++ reg_write(ingenicfb, SLCDC_CTRL, tmp); ++ } ++ } else { ++ /* LCD_TYPE_INTERLACED_TV */ ++ } ++ ++ return 0; ++} ++ ++static void ingenicfb_set_alpha(struct fb_info *info, struct ingenicfb_fg_alpha *fg_alpha) ++{ ++ int i; ++ int desc_num; ++ uint32_t cfg; ++ struct ingenicfb *ingenicfb = info->par; ++ struct ingenicfb_framedesc *framedesc; ++ ++ if (!fg_alpha->fg) { ++ desc_num = ingenicfb->desc_num - 1; ++ framedesc = ingenicfb->framedesc[0]; ++ } else { ++ desc_num = 1; ++ framedesc = ingenicfb->fg1_framedesc; ++ } ++ ++ cfg = reg_read(ingenicfb, LCDC_OSDC); ++ if (fg_alpha->enable) { ++ cfg |= LCDC_OSDC_ALPHAEN; ++ for (i = 0; i < desc_num; i++) { ++ if (!fg_alpha->mode) { ++ (framedesc + i)->cpos &= ~LCDC_CPOS_ALPHAMD1; ++ } else { ++ (framedesc + i)->cpos |= LCDC_CPOS_ALPHAMD1; ++ } ++ (framedesc + i)->desc_size &= ~LCDC_DESSIZE_ALPHA_MASK; ++ (framedesc + i)->desc_size |= (fg_alpha->value << ++ LCDC_DESSIZE_ALPHA_BIT ++ & ++ LCDC_DESSIZE_ALPHA_MASK); ++ } ++ } else { ++ dev_info(info->dev, "Failed to set alpha\n"); ++ } ++ // reg_write(ingenicfb, LCDC_OSDC, cfg); ++} ++ ++ static void ++ingenicfb_set_background(struct fb_info *info, struct ingenicfb_bg *background) ++{ ++ struct ingenicfb *ingenicfb = info->par; ++ uint32_t bg_value; ++ ++ bg_value = background->red << LCDC_BGC_RED_OFFSET & LCDC_BGC_RED_MASK; ++ bg_value |= (background->green << LCDC_BGC_GREEN_OFFSET ++ & LCDC_BGC_GREEN_MASK); ++ bg_value |= ++ (background->blue << LCDC_BGC_BLUE_OFFSET & LCDC_BGC_BLUE_MASK); ++ ++ if (!background->fg) ++ reg_write(ingenicfb, LCDC_BGC0, bg_value); ++ else ++ reg_write(ingenicfb, LCDC_BGC1, bg_value); ++} ++ ++ static void ++ingenicfb_set_colorkey(struct fb_info *info, struct ingenicfb_color_key *color_key) ++{ ++ struct ingenicfb *ingenicfb = info->par; ++ uint32_t tmp = 0; ++ ++ if (color_key->mode == 1) { ++ tmp |= LCDC_KEY_KEYMD; ++ } else { ++ tmp &= ~LCDC_KEY_KEYMD; ++ } ++ ++ tmp |= (color_key->red << LCDC_KEY_RED_OFFSET & LCDC_KEY_RED_MASK); ++ tmp |= ++ (color_key->green << LCDC_KEY_GREEN_OFFSET & LCDC_KEY_GREEN_MASK); ++ tmp |= (color_key->blue << LCDC_KEY_BLUE_OFFSET & LCDC_KEY_BLUE_MASK); ++ tmp |= LCDC_KEY_KEYEN; ++ ++ if (!color_key->fg) { ++ reg_write(ingenicfb, LCDC_KEY0, tmp); ++ tmp = reg_read(ingenicfb, LCDC_KEY0); ++ } else { ++ reg_write(ingenicfb, LCDC_KEY1, tmp); ++ tmp = reg_read(ingenicfb, LCDC_KEY1); ++ } ++ ++ if (color_key->enable == 1) { ++ tmp |= LCDC_KEY_KEYEN; ++ } else { ++ tmp &= ~LCDC_KEY_KEYEN; ++ } ++ if (!color_key->fg) { ++ reg_write(ingenicfb, LCDC_KEY0, tmp); ++ } else { ++ reg_write(ingenicfb, LCDC_KEY1, tmp); ++ } ++} ++ ++ static int ++ingenicfb_set_foreground_position(struct fb_info *info, struct ingenicfb_fg_pos *fg_pos) ++{ ++ int i; ++ int desc_num; ++ struct ingenicfb *ingenicfb = info->par; ++ struct ingenicfb_framedesc *framedesc; ++ struct fb_videomode *mode = info->mode; ++ ++ if (!mode) { ++ dev_err(ingenicfb->dev, "%s, video mode is NULL\n", __func__); ++ return -EINVAL; ++ } ++ /* ++ * The rules of f0, f1's position: ++ * f0.x + f0.w <= panel.w; ++ * f0.y + f0.h <= panel.h; ++ */ ++ if ((fg_pos->x + ingenicfb->osd.fg0.w > mode->xres) | ++ (fg_pos->y + ingenicfb->osd.fg0.h > mode->yres) | ++ (fg_pos->x >= mode->xres) | (fg_pos->y >= mode->yres)) { ++ dev_info(info->dev, "Invalid foreground position"); ++ return -EINVAL; ++ } ++ ingenicfb->osd.fg0.x = fg_pos->x; ++ ingenicfb->osd.fg0.y = fg_pos->y; ++ ++ if (!fg_pos->fg) { ++ desc_num = ingenicfb->desc_num - 1; ++ framedesc = ingenicfb->framedesc[0]; ++ } else { ++ desc_num = 1; ++ framedesc = ingenicfb->fg1_framedesc; ++ } ++ ++ for (i = 0; i < desc_num; i++) { ++ (framedesc + i)->cpos |= (((fg_pos->y << LCDC_CPOS_YPOS_BIT) & ++ LCDC_CPOS_YPOS_MASK) | ++ (fg_pos->x & LCDC_CPOS_XPOS_MASK)); ++ } ++ ++ return 0; ++} ++ ++static int ingenicfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) ++{ ++ int i; ++ unsigned int value; ++ unsigned int tmp; ++ void __user *argp = (void __user *)arg; ++ struct ingenicfb *ingenicfb = info->par; ++ struct ingenicfb_platform_data *pdata = ingenicfb->pdata; ++ struct fb_videomode *mode = info->mode; ++ int *buf; ++ unsigned long flags; ++ ++ union { ++ struct ingenicfb_fg_pos fg_pos; ++ struct ingenicfb_fg_size fg_size; ++ struct ingenicfb_fg_alpha fg_alpha; ++ struct ingenicfb_bg background; ++ struct ingenicfb_color_key color_key; ++ struct ingenicfb_mode_res res; ++ } osd; ++ ++ switch (cmd) { ++ case INGENICFB_GET_MODENUM: ++ copy_to_user(argp, &pdata->num_modes, sizeof(int)); ++ break; ++ case INGENICFB_GET_MODELIST: ++ buf = kzalloc(sizeof(int) * pdata->num_modes, GFP_KERNEL); ++ for (i = 0; i < pdata->num_modes; i++) { ++ if (!pdata->modes[i].flag) ++ continue; ++ buf[i] = pdata->modes[i].flag; ++ } ++ copy_to_user(argp, buf, sizeof(int) * pdata->num_modes); ++ kzfree(buf); ++ break; ++ case INGENICFB_SET_VIDMEM: ++ if (copy_from_user ++ (&ingenicfb->vidmem_phys, argp, sizeof(unsigned int))) ++ return -EFAULT; ++ break; ++ case INGENICFB_SET_MODE: ++ if (copy_from_user(&value, argp, sizeof(int))) ++ return -EFAULT; ++ ++ for (i = 0; i < pdata->num_modes; i++) { ++ if (pdata->modes[i].flag == value) { ++ ingenicfb_videomode_to_var(&info->var, ++ &pdata->modes[i], ++ ingenicfb->pdata->lcd_type); ++ return ingenicfb_set_par(info); ++ } ++ } ++ dev_info(info->dev, "Not find equal video mode at pdata"); ++ return -EFAULT; ++ break; ++ case INGENICFB_ENABLE: ++ if (copy_from_user(&value, argp, sizeof(int))) { ++ dev_info(info->dev, "copy FB enable value failed\n"); ++ return -EFAULT; ++ } ++ ++ if (value) { ++ ingenicfb_enable(info); ++ } else { ++ ingenicfb_disable(info); ++ } ++ break; ++ case INGENICFB_SET_FG_SIZE: ++ if (copy_from_user ++ (&osd.fg_size, argp, sizeof(struct ingenicfb_fg_size))) { ++ dev_info(info->dev, "copy FG size from user failed\n"); ++ return -EFAULT; ++ } else { ++ if (!mode) { ++ dev_err(ingenicfb->dev, "Video mode is NULL\n"); ++ return -EINVAL; ++ } ++ if ((ingenicfb->osd.fg0.x + osd.fg_size.w > mode->xres) | ++ (ingenicfb->osd.fg0.y + osd.fg_size.h > mode->yres)) { ++ dev_info(info->dev, "Invalid foreground size"); ++ return -EINVAL; ++ } ++ if (!osd.fg_size.fg) { ++ ingenicfb->osd.fg0.w = osd.fg_size.w; ++ ingenicfb->osd.fg0.h = osd.fg_size.h; ++ printk("this once called ingenicfb_prepare_dma_desc() in this function::%s00000000000000\n",__func__); ++ return ingenicfb_prepare_dma_desc(info); ++ } else { ++ /* LCDC DMA 1 is not used for now */ ++ } ++ } ++ break; ++ case INGENICFB_GET_FG_SIZE: ++ if (copy_from_user ++ (&osd.fg_size, argp, sizeof(struct ingenicfb_fg_size))) { ++ dev_info(info->dev, "copy FG size from user failed\n"); ++ return -EFAULT; ++ } ++ ++ if (!osd.fg_size.fg) { ++ value = reg_read(ingenicfb, LCDC_SIZE0); ++ } else { ++ value = reg_read(ingenicfb, LCDC_SIZE1); ++ } ++ osd.fg_size.w = value & LCDC_SIZE_WIDTH_MASK; ++ osd.fg_size.h = ++ (value & LCDC_SIZE_HEIGHT_MASK) >> LCDC_SIZE_HEIGHT_BIT; ++ if (copy_to_user ++ (argp, &osd.fg_size, sizeof(struct ingenicfb_fg_size))) { ++ dev_info(info->dev, "copy FG size to user failed\n"); ++ return -EFAULT; ++ } ++ break; ++ case INGENICFB_SET_FG_POS: ++ if (copy_from_user ++ (&osd.fg_pos, argp, sizeof(struct ingenicfb_fg_pos))) { ++ dev_info(info->dev, "copy FG pos from user failed\n"); ++ return -EFAULT; ++ } else { ++ return ingenicfb_set_foreground_position(info, &osd.fg_pos); ++ } ++ break; ++ case INGENICFB_GET_FG_POS: ++ if (copy_from_user ++ (&osd.fg_pos, argp, sizeof(struct ingenicfb_fg_pos))) { ++ dev_info(info->dev, "copy FG pos from user failed\n"); ++ return -EFAULT; ++ } ++ if (!osd.fg_size.fg) { ++ value = reg_read(ingenicfb, LCDC_XYP0); ++ } else { ++ value = reg_read(ingenicfb, LCDC_XYP1); ++ } ++ osd.fg_pos.x = value & LCDC_XYP_XPOS_MASK; ++ osd.fg_pos.y = ++ (value & LCDC_XYP_YPOS_MASK) >> LCDC_XYP_YPOS_BIT; ++ if (copy_to_user(argp, &osd.fg_pos, sizeof(struct ingenicfb_fg_pos))) { ++ dev_info(info->dev, "copy FG pos to user failed\n"); ++ return -EFAULT; ++ } ++ break; ++ case INGENICFB_GET_BUFFER: ++ if (copy_to_user(argp, &ingenicfb->current_buffer, sizeof(int))) { ++ dev_info(info->dev, "user get current buffer failed\n"); ++ return -EFAULT; ++ } ++ break; ++ case INGENICFB_SET_ALPHA: ++ if (copy_from_user ++ (&osd.fg_alpha, argp, sizeof(struct ingenicfb_fg_alpha))) { ++ dev_info(info->dev, "copy alpha from user failed\n"); ++ return -EFAULT; ++ } else { ++ ingenicfb_set_alpha(info, &osd.fg_alpha); ++ } ++ break; ++ case INGENICFB_SET_VSYNCINT: ++ if (copy_from_user(&value, argp, sizeof(int))) ++ return -EFAULT; ++ spin_lock_irqsave(&ingenicfb->vsync_lock, flags); ++ if (value && (ingenicfb->is_vsync == 0)) { ++ /* clear previous EOF flag */ ++ tmp = reg_read(ingenicfb, LCDC_STATE); ++ reg_write(ingenicfb, LCDC_STATE, tmp & ~LCDC_STATE_EOF); ++ /* enable end of frame interrupt */ ++ tmp = reg_read(ingenicfb, LCDC_CTRL); ++ reg_write(ingenicfb, LCDC_CTRL, tmp | LCDC_CTRL_EOFM); ++ } ++ ingenicfb->is_vsync = value ? 1 : 2; ++ spin_unlock_irqrestore(&ingenicfb->vsync_lock, flags); ++ break; ++ case INGENICFB_SET_BACKGROUND: ++ if (copy_from_user ++ (&osd.background, argp, sizeof(struct ingenicfb_bg))) { ++ dev_info(info->dev, "copy colorkey from user failed\n"); ++ return -EFAULT; ++ } else { ++ ingenicfb_set_background(info, &osd.background); ++ } ++ break; ++ case INGENICFB_SET_COLORKEY: ++ if (copy_from_user ++ (&osd.color_key, argp, sizeof(struct ingenicfb_color_key))) { ++ dev_info(info->dev, "copy colorkey from user failed\n"); ++ return -EFAULT; ++ } ++ ingenicfb_set_colorkey(info, &osd.color_key); ++ break; ++ case INGENICFB_16X16_BLOCK_EN: ++ if (copy_from_user(&value, argp, sizeof(int))) ++ return -EFAULT; ++ ++ if (value) { ++ dev_dbg(info->dev, "LCDC DMA enable block mode"); ++ ingenicfb->osd.block = 1; ++ printk("this once called ingenicfb_prepare_dma_desc() in this function::%s00000000000000\n",__func__); ++ ingenicfb_prepare_dma_desc(info); ++ } else { ++ dev_dbg(info->dev, "LCDC DMA disable block mode"); ++ ingenicfb->osd.block = 0; ++ printk("this once called ingenicfb_prepare_dma_desc() in this function::%s00000000000000\n",__func__); ++ ingenicfb_prepare_dma_desc(info); ++ } ++ break; ++ case INGENICFB_ENABLE_FG0: ++ if (copy_from_user(&value, argp, sizeof(int))) ++ return -EFAULT; ++ for (i = 0; i < ingenicfb->desc_num - 1; i++) { ++ if (value) { ++ ingenicfb->framedesc[i]->cmd |= LCDC_CMD_FRM_EN; ++ } else { ++ ingenicfb->framedesc[i]->cmd &= ~LCDC_CMD_FRM_EN; ++ } ++ } ++ break; ++ case INGENICFB_ENABLE_FG1: ++ if (copy_from_user(&value, argp, sizeof(int))) ++ return -EFAULT; ++ if (value) { ++ ingenicfb->fg1_framedesc->cmd |= LCDC_CMD_FRM_EN; ++ } else { ++ ingenicfb->fg1_framedesc->cmd &= ~LCDC_CMD_FRM_EN; ++ } ++ break; ++ default: ++ // ingenicfb_image_enh_ioctl(info, cmd, arg); ++ break; ++ } ++ ++ return 0; ++} ++ ++static int ingenicfb_mmap(struct fb_info *info, struct vm_area_struct *vma) ++{ ++ struct ingenicfb *ingenicfb = info->par; ++ unsigned long start; ++ unsigned long off; ++ u32 len; ++ ++ off = vma->vm_pgoff << PAGE_SHIFT; ++ ++ /* frame buffer memory */ ++ start = ingenicfb->fb->fix.smem_start; ++ len = PAGE_ALIGN((start & ~PAGE_MASK) + ingenicfb->fb->fix.smem_len); ++ start &= PAGE_MASK; ++ ++ if ((vma->vm_end - vma->vm_start + off) > len) ++ return -EINVAL; ++ off += start; ++ ++ vma->vm_pgoff = off >> PAGE_SHIFT; ++ vma->vm_flags |= VM_IO; ++ ++ pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK; ++ /* Write-Acceleration */ ++ pgprot_val(vma->vm_page_prot) |= _CACHE_CACHABLE_WA; ++ ++ if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, ++ vma->vm_end - vma->vm_start, vma->vm_page_prot)) ++ { ++ return -EAGAIN; ++ } ++ ++ return 0; ++} ++/* ++static int ingenicfb_wait_for_vsync_thread(void *data) ++{ ++ struct ingenicfb *ingenicfb = (struct ingenicfb *)data; ++ unsigned long flags; ++ unsigned int tmp; ++ char *envp[2]; ++ ktime_t timestamp; ++ ++ while (!kthread_should_stop()) { ++ wait_for_completion(&ingenicfb->vsync_wq); ++ mutex_lock(&ingenicfb->lock); ++// rotate right ++ ingenicfb->vsync_skip_map = (ingenicfb->vsync_skip_map >> 1 | ++ ingenicfb->vsync_skip_map << 9) & ++ 0x3ff; ++ mutex_unlock(&ingenicfb->lock); ++ if (!(ingenicfb->vsync_skip_map & 0x1)) ++ continue; ++ ++ spin_lock_irqsave(&ingenicfb->vsync_lock, flags); ++ timestamp = ingenicfb->timestamp_array[ingenicfb->timestamp_thread_pos&(0xf)]; ++ spin_unlock_irqrestore(&ingenicfb->vsync_lock, flags); ++ ++ snprintf(ingenicfb->eventbuf, sizeof(ingenicfb->eventbuf), "VSYNC=%llu", ktime_to_ns(timestamp)); ++ ingenicfb->timestamp_thread_pos++; ++ envp[0] = ingenicfb->eventbuf; ++ envp[1] = NULL; ++ kobject_uevent_env(&ingenicfb->dev->kobj, KOBJ_CHANGE, envp); ++ ++ spin_lock_irqsave(&ingenicfb->vsync_lock, flags); ++ if(ingenicfb->is_vsync == 2) { ++ tmp = reg_read(ingenicfb, LCDC_CTRL); ++ reg_write(ingenicfb, LCDC_CTRL, tmp & ~LCDC_CTRL_EOFM); ++ ingenicfb->is_vsync = 0; ++ } ++ if(ingenicfb->timestamp_irq_pos == ingenicfb->timestamp_thread_pos) ++ ingenicfb->timestamp_irq_pos = ingenicfb->timestamp_thread_pos = 0; ++ spin_unlock_irqrestore(&ingenicfb->vsync_lock, flags); ++ } ++ ++ return 0; ++} ++*/ ++static irqreturn_t ingenicfb_irq_handler(int irq, void *data) ++{ ++ unsigned int state; ++ struct ingenicfb *ingenicfb = (struct ingenicfb *)data; ++ ++ state = reg_read(ingenicfb, LCDC_STATE); ++ ++ if (state & LCDC_STATE_EOF) { ++ reg_write(ingenicfb, LCDC_STATE, state & ~LCDC_STATE_EOF); ++ wmb(); ++ ingenicfb->timestamp_array[ingenicfb->timestamp_irq_pos&(0xf)] = ktime_get(); ++ ingenicfb->timestamp_irq_pos++; ++ complete(&ingenicfb->vsync_wq); ++ } ++ ++ if (state & LCDC_STATE_OFU) { ++ reg_write(ingenicfb, LCDC_STATE, state & ~LCDC_STATE_OFU); ++ if (ingenicfb->irq_cnt++ > 100) { ++ unsigned int tmp; ++ ingenicfb->irq_cnt = 0; ++ tmp = reg_read(ingenicfb, LCDC_CTRL); ++ reg_write(ingenicfb, LCDC_CTRL, tmp & ~LCDC_CTRL_OFUM); ++ dev_err(ingenicfb->dev, "disable OFU irq\n"); ++ } ++ /* dev_err(ingenicfb->dev, "%s, Out FiFo underrun\n", __func__); */ ++ } ++ return IRQ_HANDLED; ++} ++ ++static struct fb_ops ingenicfb_ops = { ++ .owner = THIS_MODULE, ++ .fb_open = ingenicfb_open, ++ .fb_release = ingenicfb_release, ++ .fb_check_var = ingenicfb_check_var, ++ .fb_set_par = ingenicfb_set_par, ++ .fb_blank = ingenicfb_blank, ++ .fb_pan_display = ingenicfb_pan_display, ++ .fb_fillrect = cfb_fillrect, ++ .fb_copyarea = cfb_copyarea, ++ .fb_imageblit = cfb_imageblit, ++ .fb_ioctl = ingenicfb_ioctl, ++ .fb_mmap = ingenicfb_mmap, ++}; ++ ++static void ingenicfb_change_dma_desc(struct fb_info *info) ++{ ++ struct ingenicfb *ingenicfb = info->par; ++ struct fb_videomode *mode; ++#if 0 ++ if (!ingenicfb->is_lcd_en) { ++ dev_err(ingenicfb->dev, "LCDC isn't enabled\n"); ++ return; ++ } ++#endif ++ ++ mode = ingenicfb->pdata->modes; ++ if (!mode) ++ return; ++ ingenicfb->osd.fg0.fg = 0; ++ ingenicfb->osd.fg0.bpp = ingenicfb_get_controller_bpp(ingenicfb) == 32 ? 32 : 16; ++ ingenicfb->osd.fg0.x = ingenicfb->osd.fg0.y = 0; ++ ingenicfb->osd.fg0.w = mode->xres; ++ ingenicfb->osd.fg0.h = mode->yres; ++ ++ info->mode = mode; ++ printk("this once called ingenicfb_prepare_dma_desc() in this function::%s00000000000000\n",__func__); ++ ingenicfb_prepare_dma_desc(info); ++ ++ if (mode->pixclock) { ++ unsigned long rate = PICOS2KHZ(mode->pixclock) * 1000; ++ ingenicfb_pclk_disable(ingenicfb); ++ clk_set_rate(ingenicfb->pclk, rate); ++ ingenicfb_pclk_enable(ingenicfb); ++ dev_dbg(ingenicfb->dev, "LCDC: PixClock = %lu\n", rate); ++ dev_dbg(ingenicfb->dev, "LCDC: PixClock = %lu(real)\n", ++ clk_get_rate(ingenicfb->pclk)); ++ } else { ++ dev_err(ingenicfb->dev, "Video mode pixclock invalid\n"); ++ } ++ ++ // ingenicfb_config_image_enh(info); ++ ++#ifndef CONFIG_SLCDC_CONTINUA ++ if (ingenicfb->pdata->lcd_type == LCD_TYPE_SLCD) { ++ /* update display */ ++ unsigned long tmp; ++ tmp = reg_read(ingenicfb, SLCDC_CTRL); ++ tmp |= SLCDC_CTRL_DMA_MODE | SLCDC_CTRL_DMA_START; ++ reg_write(ingenicfb, SLCDC_CTRL, tmp); ++ } ++#else ++ reg_write(ingenicfb, SLCDC_CTRL, reg_read(ingenicfb, SLCDC_CTRL) & ~SLCDC_CTRL_DMA_MODE); ++#endif ++} ++ ++static int ingenicfb_copy_logo(struct fb_info *info) ++{ ++ unsigned long src_addr = 0; /* u-boot logo buffer address */ ++ unsigned long dst_addr = 0; /* kernel frame buffer address */ ++ unsigned long size; ++ unsigned long offsize; ++ int i = 0, j = 0; ++ struct ingenicfb *ingenicfb = info->par; ++ ++ /* get buffer physical address */ ++ src_addr = (unsigned long)reg_read(ingenicfb, LCDC_SA0); ++ if (!(reg_read(ingenicfb, LCDC_CTRL) & LCDC_CTRL_ENA)) { ++ /* u-boot is not display logo */ ++ printk("uboot lcd is not enabled!!!\n"); ++ return -ENOMEM; ++ } ++ ++ printk("uboot lcd is enabled!!\n"); ++ ingenicfb->is_lcd_en = 1; ++ ++ if (src_addr) { ++ src_addr = (unsigned long)phys_to_virt(src_addr); ++ if (ALIGN(info->var.xres, PIXEL_ALIGN) == info->var.xres) { ++ size = info->fix.line_length * info->var.yres; ++ ++ for (i = 0; i < NUM_FRAME_BUFFERS; i++) { ++ dst_addr = (unsigned long)info->screen_base + i * size; ++ memcpy((void *)dst_addr, (void *)src_addr, size); ++ } ++ } else { ++ size = info->var.bits_per_pixel * info->var.xres >> 3; ++ offsize = info->var.bits_per_pixel * (ALIGN(info->var.xres, PIXEL_ALIGN) - info->var.xres) >> 3; ++ ++ dst_addr = (unsigned long)info->screen_base; ++ for (i = 0; i < NUM_FRAME_BUFFERS; i++) { ++ unsigned long temp_src_addr = src_addr; ++ for (j = 0; j < info->var.yres; j++) { ++ memcpy((void *)dst_addr, (void *)temp_src_addr, size); ++ dst_addr += (size + offsize); ++ temp_src_addr += size; ++ } ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++static void ingenicfb_display_v_color_bar(struct fb_info *info) ++{ ++ int i, j; ++ int w, h; ++ int bpp; ++ unsigned short *p16; ++ unsigned int *p32; ++ struct ingenicfb *ingenicfb = info->par; ++ struct fb_videomode *mode = ingenicfb->pdata->modes; ++ ++ if (!mode) { ++ dev_err(ingenicfb->dev, "%s, video mode is NULL\n", __func__); ++ return; ++ } ++ if (!ingenicfb->vidmem_phys) { ++ dev_err(ingenicfb->dev, "Not allocate frame buffer yet\n"); ++ return; ++ } ++ if (!ingenicfb->vidmem) ++ ingenicfb->vidmem = (void *)(ingenicfb->vidmem_phys+0x80000000); ++ p16 = (unsigned short *)ingenicfb->vidmem; ++ p32 = (unsigned int *)ingenicfb->vidmem; ++ w = ingenicfb->osd.fg0.w; ++ h = ingenicfb->osd.fg0.h; ++ bpp = ingenicfb->osd.fg0.bpp; ++ ++ dev_info(info->dev, ++ "LCD V COLOR BAR w,h,bpp(%d,%d,%d) ingenicfb->vidmem=%p\n", w, h, ++ bpp, ingenicfb->vidmem); ++ ++ for (i = 0; i < h; i++) { ++ for (j = 0; j < w; j++) { ++ short c16; ++ int c32 = 0; ++ switch ((j / 10) % 4) { ++ case 0: ++ c16 = 0xF800; ++ c32 = 0xFFFF0000; ++ break; ++ case 1: ++ c16 = 0x07C0; ++ c32 = 0xFF00FF00; ++ break; ++ case 2: ++ c16 = 0x001F; ++ c32 = 0xFF0000FF; ++ break; ++ default: ++ c16 = 0xFFFF; ++ c32 = 0xFFFFFFFF; ++ break; ++ } ++ switch (bpp) { ++ case 18: ++ case 24: ++ case 32: ++ *p32++ = c32; ++ break; ++ default: ++ *p16++ = c16; ++ } ++ } ++ if (w % PIXEL_ALIGN) { ++ switch (bpp) { ++ case 18: ++ case 24: ++ case 32: ++ p32 += (ALIGN(mode->xres, PIXEL_ALIGN) - w); ++ break; ++ default: ++ p16 += (ALIGN(mode->xres, PIXEL_ALIGN) - w); ++ break; ++ } ++ } ++ } ++} ++ ++static void ingenicfb_display_h_color_bar(struct fb_info *info) ++{ ++ int i, j; ++ int w, h; ++ int bpp; ++ unsigned short *p16; ++ unsigned int *p32; ++ struct ingenicfb *ingenicfb = info->par; ++ struct fb_videomode *mode = ingenicfb->pdata->modes; ++ ++ if (!mode) { ++ dev_err(ingenicfb->dev, "%s, video mode is NULL\n", __func__); ++ return; ++ } ++ if (!ingenicfb->vidmem_phys) { ++ dev_err(ingenicfb->dev, "Not allocate frame buffer yet\n"); ++ return; ++ } ++ if (!ingenicfb->vidmem) ++ ingenicfb->vidmem = (void *)(ingenicfb->vidmem_phys + 0x80000000); ++ p16 = (unsigned short *)ingenicfb->vidmem; ++ p32 = (unsigned int *)ingenicfb->vidmem; ++ w = ingenicfb->osd.fg0.w; ++ h = ingenicfb->osd.fg0.h; ++ bpp = ingenicfb->osd.fg0.bpp; ++ ++ dev_info(info->dev, ++ "LCD H COLOR BAR w,h,bpp(%d,%d,%d), ingenicfb->vidmem=%p\n", w, h, ++ bpp, ingenicfb->vidmem); ++ ++ for (i = 0; i < h; i++) { ++ for (j = 0; j < w; j++) { ++ short c16; ++ int c32; ++ switch ((i / 10) % 4) { ++ case 0: ++ c16 = 0xF800; ++ c32 = 0x00FF0000; ++ break; ++ case 1: ++ c16 = 0x07C0; ++ c32 = 0x0000FF00; ++ break; ++ case 2: ++ c16 = 0x001F; ++ c32 = 0x000000FF; ++ break; ++ default: ++ c16 = 0xFFFF; ++ c32 = 0xFFFFFFFF; ++ break; ++ } ++ switch (bpp) { ++ case 18: ++ case 24: ++ case 32: ++ *p32++ = c32; ++ break; ++ default: ++ *p16++ = c16; ++ } ++ } ++ if (w % PIXEL_ALIGN) { ++ switch (bpp) { ++ case 18: ++ case 24: ++ case 32: ++ p32 += (ALIGN(mode->xres, PIXEL_ALIGN) - w); ++ break; ++ default: ++ p16 += (ALIGN(mode->xres, PIXEL_ALIGN) - w); ++ break; ++ } ++ } ++ } ++} ++static void dump_lcdc_registers(struct ingenicfb *ingenicfb) ++{ ++ int i; ++ long unsigned int tmp; ++ struct device *dev = ingenicfb->dev; ++ ++ // is_clk_en = ingenicfb->is_clk_en; ++ // ingenicfb_clk_enable(ingenicfb); ++ ++ /* LCD Controller Resgisters */ ++ dev_info(dev, "ingenicfb->base:\t0x%08x\n", (unsigned int)(ingenicfb->base)); ++ ++ dev_info(dev, "LCDC_CFG:(0x%08x)\t0x%08lx\n",LCDC_CFG, reg_read(ingenicfb, LCDC_CFG)); ++ dev_info(dev, "LCDC_CTRL:(0x%08x)\t0x%08lx\n", LCDC_CTRL,reg_read(ingenicfb, LCDC_CTRL)); ++ dev_info(dev, "LCDC_STATE:(0x%08x)\t0x%08lx\n",LCDC_STATE, reg_read(ingenicfb, LCDC_STATE)); ++ dev_info(dev, "LCDC_OSDC:(0x%08x)\t0x%08lx\n",LCDC_OSDC, reg_read(ingenicfb, LCDC_OSDC)); ++ dev_info(dev, "LCDC_OSDCTRL:(0x%08x)\t0x%08lx\n",LCDC_OSDCTRL, reg_read(ingenicfb, LCDC_OSDCTRL)); ++ dev_info(dev, "LCDC_OSDS:(0x%08x)\t0x%08lx\n",LCDC_OSDS, reg_read(ingenicfb, LCDC_OSDS)); ++ dev_info(dev, "LCDC_BGC0:(0x%08x)\t0x%08lx\n",LCDC_BGC0, reg_read(ingenicfb, LCDC_BGC0)); ++ dev_info(dev, "LCDC_KEY0:(0x%08x)\t0x%08lx\n",LCDC_KEY0, reg_read(ingenicfb, LCDC_KEY0)); ++ dev_info(dev, "LCDC_ALPHA:(0x%08x)\t0x%08lx\n",LCDC_ALPHA, reg_read(ingenicfb, LCDC_ALPHA)); ++ dev_info(dev, "LCDC_IPUR:(0x%08x)\t0x%08lx\n",LCDC_IPUR, reg_read(ingenicfb, LCDC_IPUR)); ++ dev_info(dev, "==================================\n"); ++ tmp = reg_read(ingenicfb, LCDC_VAT); ++ dev_info(dev, "LCDC_VAT:(0x%08x)\t0x%08lx, HT = %ld, VT = %ld\n",LCDC_VAT, tmp, ++ (tmp & LCDC_VAT_HT_MASK) >> LCDC_VAT_HT_BIT, ++ (tmp & LCDC_VAT_VT_MASK) >> LCDC_VAT_VT_BIT); ++ tmp = reg_read(ingenicfb, LCDC_DAH); ++ dev_info(dev, "LCDC_DAH:(0x%08x)\t0x%08lx, HDS = %ld, HDE = %ld\n", LCDC_DAH,tmp, ++ (tmp & LCDC_DAH_HDS_MASK) >> LCDC_DAH_HDS_BIT, ++ (tmp & LCDC_DAH_HDE_MASK) >> LCDC_DAH_HDE_BIT); ++ tmp = reg_read(ingenicfb, LCDC_DAV); ++ dev_info(dev, "LCDC_DAV:(0x%08x)\t0x%08lx, VDS = %ld, VDE = %ld\n", LCDC_DAV,tmp, ++ (tmp & LCDC_DAV_VDS_MASK) >> LCDC_DAV_VDS_BIT, ++ (tmp & LCDC_DAV_VDE_MASK) >> LCDC_DAV_VDE_BIT); ++ tmp = reg_read(ingenicfb, LCDC_HSYNC); ++ dev_info(dev, "LCDC_HSYNC:(0x%08x)\t0x%08lx, HPS = %ld, HPE = %ld\n", LCDC_HSYNC,tmp, ++ (tmp & LCDC_HSYNC_HPS_MASK) >> LCDC_HSYNC_HPS_BIT, ++ (tmp & LCDC_HSYNC_HPE_MASK) >> LCDC_HSYNC_HPE_BIT); ++ tmp = reg_read(ingenicfb, LCDC_VSYNC); ++ dev_info(dev, "LCDC_VSYNC:(0x%08x)\t0x%08lx, VPS = %ld, VPE = %ld\n", LCDC_VSYNC,tmp, ++ (tmp & LCDC_VSYNC_VPS_MASK) >> LCDC_VSYNC_VPS_BIT, ++ (tmp & LCDC_VSYNC_VPE_MASK) >> LCDC_VSYNC_VPE_BIT); ++ dev_info(dev, "==================================\n"); ++ dev_info(dev, "LCDC_XYP0:(0x%08x)\t0x%08lx\n",LCDC_XYP0, reg_read(ingenicfb, LCDC_XYP0)); ++ dev_info(dev, "LCDC_SIZE0:(0x%08x)\t0x%08lx\n",LCDC_SIZE0, reg_read(ingenicfb, LCDC_SIZE0)); ++ dev_info(dev, "LCDC_RGBC:(0x%08x) \t0x%08lx\n",LCDC_RGBC, reg_read(ingenicfb, LCDC_RGBC)); ++ dev_info(dev, "LCDC_PS:(0x%08x)\t0x%08lx\n",LCDC_PS, reg_read(ingenicfb, LCDC_PS)); ++ dev_info(dev, "LCDC_CLS:(0x%08x)\t0x%08lx\n",LCDC_CLS, reg_read(ingenicfb, LCDC_CLS)); ++ dev_info(dev, "LCDC_SPL:(0x%08x)\t0x%08lx\n",LCDC_SPL, reg_read(ingenicfb, LCDC_SPL)); ++ dev_info(dev, "LCDC_REV:(0x%08x)\t0x%08lx\n",LCDC_REV, reg_read(ingenicfb, LCDC_REV)); ++ dev_info(dev, "LCDC_IID:(0x%08x)\t0x%08lx\n",LCDC_IID, reg_read(ingenicfb, LCDC_IID)); ++ dev_info(dev, "==================================\n"); ++ dev_info(dev, "LCDC_DA0:(0x%08x)\t0x%08lx\n",LCDC_DA0, reg_read(ingenicfb, LCDC_DA0)); ++ dev_info(dev, "LCDC_SA0:(0x%08x)\t0x%08lx\n",LCDC_SA0, reg_read(ingenicfb, LCDC_SA0)); ++ dev_info(dev, "LCDC_FID0:(0x%08x)\t0x%08lx\n",LCDC_FID0, reg_read(ingenicfb, LCDC_FID0)); ++ dev_info(dev, "LCDC_CMD0:(0x%08x)\t0x%08lx\n",LCDC_CMD0, reg_read(ingenicfb, LCDC_CMD0)); ++ dev_info(dev, "LCDC_OFFS0:(0x%08x)\t0x%08lx\n",LCDC_OFFS0, reg_read(ingenicfb, LCDC_OFFS0)); ++ dev_info(dev, "LCDC_PW0:(0x%08x)\t0x%08lx\n", LCDC_PW0,reg_read(ingenicfb, LCDC_PW0)); ++ dev_info(dev, "LCDC_CNUM0:(0x%08x)\t0x%08lx\n",LCDC_CNUM0, reg_read(ingenicfb, LCDC_CNUM0)); ++ dev_info(dev, "LCDC_DESSIZE0:(0x%08x)\t0x%08lx\n",LCDC_DESSIZE0, ++ reg_read(ingenicfb, LCDC_DESSIZE0)); ++ dev_info(dev, "==================================\n"); ++ dev_info(dev, "LCDC_PCFG:(0x%08x)\t0x%08lx\n",LCDC_PCFG, reg_read(ingenicfb, LCDC_PCFG)); ++ dev_info(dev, "==================================\n"); ++ dev_info(dev, "SLCDC_CFG:(0x%08x) \t0x%08lx\n",SLCDC_CFG, reg_read(ingenicfb, SLCDC_CFG)); ++ dev_info(dev, "SLCDC_CTRL:(0x%08x) \t0x%08lx\n",SLCDC_CTRL, reg_read(ingenicfb, SLCDC_CTRL)); ++ dev_info(dev, "SLCDC_STATE:(0x%08x) \t0x%08lx\n",SLCDC_STATE, reg_read(ingenicfb, SLCDC_STATE)); ++ dev_info(dev, "SLCDC_DATA:(0x%08x) \t0x%08lx\n",SLCDC_DATA, reg_read(ingenicfb, SLCDC_DATA)); ++ dev_info(dev, "SLCDC_CFG_NEW:(0x%08x) \t0x%08lx\n",SLCDC_CFG_NEW, ++ reg_read(ingenicfb, SLCDC_CFG_NEW)); ++ dev_info(dev, "SLCDC_WTIME:(0x%08x) \t0x%08lx\n",SLCDC_WTIME, reg_read(ingenicfb, SLCDC_WTIME)); ++ dev_info(dev, "SLCDC_TAS:(0x%08x) \t0x%08lx\n",SLCDC_TAS, reg_read(ingenicfb, SLCDC_TAS)); ++ dev_info(dev, "==================================\n"); ++ printk("reg:0x10000020 value=0x%08x (24bit) Clock Gate Register0\n", ++ *(unsigned int *)0xb0000020); ++ printk("reg:0x100000e4 value=0x%08x (5bit_lcdc 21bit_lcdcs) Power Gate Register: \n", ++ *(unsigned int *)0xb00000e4); ++ printk("reg:0x100000b8 value=0x%08x (10bit) SRAM Power Control Register0 \n", ++ *(unsigned int *)0xb00000b8); ++ printk("reg:0x10000064 value=0x%08x Lcd pixclock \n", ++ *(unsigned int *)0xb0000064); ++ printk("==================================\n"); ++ printk("PAINT:\t0x%08x\n", *(unsigned int *)0xb0010010); ++ printk("PAMASK:\t0x%08x\n",*(unsigned int *)0xb0010020); ++ printk("PAPAT1:\t0x%08x\n",*(unsigned int *)0xb0010030); ++ printk("PAPAT0:\t0x%08x\n",*(unsigned int *)0xb0010040); ++ printk("PBINT:\t0x%08x\n", *(unsigned int *)0xb0010110); ++ printk("PBMASK:\t0x%08x\n",*(unsigned int *)0xb0010120); ++ printk("PBPAT1:\t0x%08x\n",*(unsigned int *)0xb0010130); ++ printk("PBPAT0:\t0x%08x\n",*(unsigned int *)0xb0010140); ++ for (i = 0; i < ingenicfb->desc_num + 1; i++) { ++ if (!ingenicfb->framedesc[i]) ++ break; ++ dev_info(dev, "==================================\n"); ++ dev_info(dev, "ingenicfb->framedesc[%d]: 0x%p\n" , i, ingenicfb->framedesc[i]); ++ dev_info(dev, "framedesc[%d]->next: 0x%08x\n", i, ingenicfb->framedesc[i]->next); ++ dev_info(dev, "framedesc[%d]->databuf: 0x%08x\n", i, ingenicfb->framedesc[i]->databuf); ++ dev_info(dev, "framedesc[%d]->id: 0x%08x\n", i, ingenicfb->framedesc[i]->id); ++ dev_info(dev, "framedesc[%d]->cmd: 0x%08x\n", i, ingenicfb->framedesc[i]->cmd); ++ dev_info(dev, "framedesc[%d]->offsize: 0x%08x\n", i, ingenicfb->framedesc[i]->offsize); ++ dev_info(dev, "framedesc[%d]->page_width: 0x%08x\n", i, ingenicfb->framedesc[i]->page_width); ++ dev_info(dev, "framedesc[%d]->cpos: 0x%08x\n", i, ingenicfb->framedesc[i]->cpos); ++ dev_info(dev, "framedesc[%d]->desc_size: 0x%08x\n", i, ingenicfb->framedesc[i]->desc_size); ++ } ++ // if (!is_clk_en) ++ // ingenicfb_clk_disable(ingenicfb); ++ ++ return; ++} ++ ++ static ssize_t ++dump_lcd(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct ingenicfb *ingenicfb = dev_get_drvdata(dev); ++ dump_lcdc_registers(ingenicfb); ++ ++ return 0; ++} ++ ++ static ssize_t ++dump_h_color_bar(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct ingenicfb *ingenicfb = dev_get_drvdata(dev); ++ ingenicfb_display_h_color_bar(ingenicfb->fb); ++ return 0; ++} ++ ++ static ssize_t ++dump_v_color_bar(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct ingenicfb *ingenicfb = dev_get_drvdata(dev); ++ ingenicfb_display_v_color_bar(ingenicfb->fb); ++ return 0; ++} ++ ++ static ssize_t ++vsync_skip_r(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct ingenicfb *ingenicfb = dev_get_drvdata(dev); ++ mutex_lock(&ingenicfb->lock); ++ snprintf(buf, 3, "%d\n", ingenicfb->vsync_skip_ratio); ++ dev_dbg(dev, "vsync_skip_map = 0x%08x\n", ingenicfb->vsync_skip_map); ++ mutex_unlock(&ingenicfb->lock); ++ return 3; /* sizeof ("%d\n") */ ++} ++ ++static int vsync_skip_set(struct ingenicfb *ingenicfb, int vsync_skip) ++{ ++ unsigned int map_wide10 = 0; ++ int rate, i, p, n; ++ int fake_float_1k; ++ ++ if (vsync_skip < 0 || vsync_skip > 9) ++ return -EINVAL; ++ ++ rate = vsync_skip + 1; ++ fake_float_1k = 10000 / rate; /* 10.0 / rate */ ++ ++ p = 1; ++ n = (fake_float_1k * p + 500) / 1000; /* +0.5 to int */ ++ ++ for (i = 1; i <= 10; i++) { ++ map_wide10 = map_wide10 << 1; ++ if (i == n) { ++ map_wide10++; ++ p++; ++ n = (fake_float_1k * p + 500) / 1000; ++ } ++ } ++ mutex_lock(&ingenicfb->lock); ++ ingenicfb->vsync_skip_map = map_wide10; ++ ingenicfb->vsync_skip_ratio = rate - 1; /* 0 ~ 9 */ ++ mutex_unlock(&ingenicfb->lock); ++ ++ return 0; ++} ++ ++ static ssize_t ++vsync_skip_w(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct ingenicfb *ingenicfb = dev_get_drvdata(dev); ++ ++ if ((count != 1) && (count != 2)) ++ return -EINVAL; ++ if ((*buf < '0') && (*buf > '9')) ++ return -EINVAL; ++ ++ vsync_skip_set(ingenicfb, *buf - '0'); ++ ++ return count; ++} ++ ++static ssize_t fps_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ printk("\n-----you can choice print way:\n"); ++ printk("Example: echo NUM > show_fps\n"); ++ printk("NUM = 0: close fps statistics\n"); ++ printk("NUM = 1: print recently fps\n"); ++ printk("NUM = 2: print interval between last and this pan_display\n"); ++ printk("NUM = 3: print pan_display count\n\n"); ++ return 0; ++} ++ ++static ssize_t fps_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++ int num = 0; ++ num = simple_strtoul(buf, NULL, 0); ++ if(num < 0 || num > 3){ ++ printk("\n--please 'cat show_fps' to view using the method\n\n"); ++ return n; ++ } ++ showFPS = num; ++ if(showFPS == 3) ++ printk(KERN_DEBUG " Pand display count=%d\n",ingenicfb->pan_display_count); ++ return n; ++} ++/**********************lcd_debug***************************/ ++// #include "foreground_width_test.c" /* for foreground width test */ ++ ++static DEVICE_ATTR(dump_lcd, S_IRUGO|S_IWUSR, dump_lcd, NULL); ++static DEVICE_ATTR(dump_h_color_bar, S_IRUGO|S_IWUSR, dump_h_color_bar, NULL); ++static DEVICE_ATTR(dump_v_color_bar, S_IRUGO|S_IWUSR, dump_v_color_bar, NULL); ++static DEVICE_ATTR(vsync_skip, S_IRUGO|S_IWUSR, vsync_skip_r, vsync_skip_w); ++static DEVICE_ATTR(show_fps, S_IRUGO|S_IWUSR, fps_show, fps_store); ++#ifdef FOREGROUND_WIDTH_TEST ++static DEVICE_ATTR(partial_test, S_IRUGO|S_IWUSR, NULL, test_partial_refresh); ++#endif ++ ++static struct attribute *lcd_debug_attrs[] = { ++ &dev_attr_dump_lcd.attr, ++ &dev_attr_dump_h_color_bar.attr, ++ &dev_attr_dump_v_color_bar.attr, ++ &dev_attr_vsync_skip.attr, ++ &dev_attr_show_fps.attr, ++#ifdef FOREGROUND_WIDTH_TEST ++ &dev_attr_partial_test.attr, ++#endif ++ NULL, ++}; ++ ++const char lcd_group_name[] = "debug"; ++static struct attribute_group lcd_debug_attr_group = { ++ .name = lcd_group_name, ++ .attrs = lcd_debug_attrs, ++}; ++ ++ ++void test_pattern(struct ingenicfb *ingenicfb) ++{ ++ int count = 5; ++ int next_frm = 0; ++ // dump_lcdc_registers(ingenicfb); ++ ingenicfb_set_par(ingenicfb->fb); ++ // dump_lcdc_registers(ingenicfb); ++ ingenicfb_display_h_color_bar(ingenicfb->fb); ++ ++ ingenicfb_enable(ingenicfb->fb); ++ ++ //dump_lcdc_registers(ingenicfb); ++ while(count--){ ++ if(next_frm){ ++ next_frm = 0; ++ ingenicfb_display_v_color_bar(ingenicfb->fb); ++ } ++ else{ ++ next_frm = 1; ++ ingenicfb_display_h_color_bar(ingenicfb->fb); ++ } ++ if (ingenicfb->pdata->lcd_type == LCD_TYPE_SLCD) { ++#ifndef CONFIG_SLCDC_CONTINUA ++ int smart_ctrl = 0; ++ smart_ctrl = reg_read(ingenicfb, SLCDC_CTRL); ++ smart_ctrl |= SLCDC_CTRL_DMA_START; //trigger a new frame ++ reg_write(ingenicfb, SLCDC_CTRL, smart_ctrl); ++#endif ++ } ++ mdelay(2000); ++ } ++} ++int lcd_display_inited_by_uboot( void ) ++{ ++ if (*(unsigned int*)(0xb3050000 + LCDC_CTRL) & LCDC_CTRL_ENA) ++ uboot_inited = 1; ++ else ++ uboot_inited = 0; ++ /* screen init will set this function first */ ++ return uboot_inited; ++} ++ ++static int ingenicfb_do_probe(struct platform_device *pdev, struct ingenicfb_platform_data *pdata) ++{ ++ int ret = 0; ++ struct fb_info *fb; ++ struct fb_videomode *video_mode; ++ struct resource *mem; ++ ++ if (!pdata) { ++ dev_err(&pdev->dev, "Missing platform data\n"); ++ return -ENXIO; ++ } ++ ++ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!mem) { ++ dev_err(&pdev->dev, "Failed to get register memory resource\n"); ++ return -ENXIO; ++ } ++ mem = request_mem_region(mem->start, resource_size(mem), pdev->name); ++ if (!mem) { ++ dev_err(&pdev->dev, ++ "Failed to request register memory region\n"); ++ return -EBUSY; ++ } ++ ++ ++ fb = framebuffer_alloc(sizeof(struct ingenicfb), &pdev->dev); ++ if (!fb) { ++ dev_err(&pdev->dev, "Failed to allocate framebuffer device\n"); ++ ret = -ENOMEM; ++ goto err_release_mem_region; ++ } ++ ++ fb->fbops = &ingenicfb_ops; ++ fb->flags = FBINFO_DEFAULT; ++ ++ ingenicfb = fb->par; ++ ++#if defined (CONFIG_LCD_FB_FORMAT_16BIT) ++ ingenicfb->fb_bpp = 16; ++#elif defined(CONFIG_LCD_FB_FORMAT_24BIT) ++ ingenicfb->fb_bpp = 24; ++#endif ++ ++ ingenicfb->fb = fb; ++ ingenicfb->dev = &pdev->dev; ++ ingenicfb->pdata = pdata; ++ ingenicfb->mem = mem; ++ ingenicfb->is_lcd_en = 0; ++ if (pdata->lcd_type != LCD_TYPE_INTERLACED_TV && ++ pdata->lcd_type != LCD_TYPE_SLCD) { ++ ingenicfb->desc_num = MAX_DESC_NUM - 2; ++ } else { ++ ingenicfb->desc_num = MAX_DESC_NUM; ++ } ++ ++ mutex_init(&ingenicfb->lock); ++ mutex_init(&ingenicfb->suspend_lock); ++ ++ sprintf(ingenicfb->clk_name, "gate_lcd"); ++ sprintf(ingenicfb->pclk_name, "cgu_lcd"); ++ ingenicfb->clk = devm_clk_get(&pdev->dev, ingenicfb->clk_name); ++ ingenicfb->pclk = devm_clk_get(&pdev->dev, ingenicfb->pclk_name); ++ if (IS_ERR(ingenicfb->clk) || IS_ERR(ingenicfb->pclk) ) { ++ ret = PTR_ERR(ingenicfb->clk); ++ dev_err(&pdev->dev, "Failed to get lcdc clock: %d\n", ret); ++ goto err_framebuffer_release; ++ } ++ /* Don't read or write lcdc registers until here. */ ++ ingenicfb_clk_enable(ingenicfb); ++ ingenicfb_pclk_enable(ingenicfb); ++ /**(volatile unsigned int*)0xb0000064 = (1<<31) | (1<<28) | (0x13); ++ *(volatile unsigned int*)0xb0000020 &= ~(1 << 23);*/ ++ ingenicfb->base = ioremap(mem->start, resource_size(mem)); ++ if (!ingenicfb->base) { ++ dev_err(&pdev->dev, ++ "Failed to ioremap register memory region\n"); ++ ret = -EBUSY; ++ goto err_put_clk; ++ } ++ ++ platform_set_drvdata(pdev, ingenicfb); ++ ++ fb_videomode_to_modelist(pdata->modes, pdata->num_modes, &fb->modelist); ++ video_mode = ingenicfb->pdata->modes; ++ if (!video_mode) ++ goto err_iounmap; ++ ingenicfb_videomode_to_var(&fb->var, video_mode, ingenicfb->pdata->lcd_type); ++ fb->var.width = pdata->width; ++ fb->var.height = pdata->height; ++ fb->var.bits_per_pixel = ingenicfb->fb_bpp; ++ ++ /* Android generic FrameBuffer format is A8B8G8R8(B3B2B1B0), so we set A8B8G8R8 as default. ++ * ++ * If set rgb order as A8B8G8R8, both SLCD cmd_buffer and data_buffer bytes sequence changed. ++ * so remain slcd format X8R8G8B8, until fix this problem.(, 2014-06-20) ++ */ ++#ifdef CONFIG_ANDROID ++ if (pdata->lcd_type == LCD_TYPE_SLCD) { ++ ingenicfb->fmt_order = FORMAT_X8R8G8B8; ++ } ++ else { ++ ingenicfb->fmt_order = FORMAT_X8B8G8R8; ++ } ++#else ++ ingenicfb->fmt_order = FORMAT_X8R8G8B8; ++#endif ++ ++ ingenicfb_check_var(&fb->var, fb); ++ ++ ret = ingenicfb_alloc_devmem(ingenicfb); ++ if (ret) { ++ dev_err(&pdev->dev, "Failed to allocate video memory\n"); ++ goto err_iounmap; ++ } ++ fb->fix = ingenicfb_fix; ++ fb->fix.line_length = fb->var.bits_per_pixel * ALIGN(fb->var.xres, ++ PIXEL_ALIGN) >> 3; ++ fb->fix.mmio_start = mem->start; ++ fb->fix.mmio_len = resource_size(mem); ++ fb->fix.smem_start = ingenicfb->vidmem_phys; ++ fb->fix.smem_len = ingenicfb->vidmem_size; ++ fb->screen_base = ingenicfb->vidmem; ++ fb->pseudo_palette = (void *)(fb + 1); ++ ingenicfb->irq = platform_get_irq(pdev, 0); ++ sprintf(ingenicfb->irq_name, "lcdc%d", pdev->id); ++ if (request_irq(ingenicfb->irq, ingenicfb_irq_handler, 0, ++ ingenicfb->irq_name, ingenicfb)) { ++ dev_err(&pdev->dev, "request irq failed\n"); ++ ret = -EINVAL; ++ goto err_free_devmem; ++ } ++ ++ ret = sysfs_create_group(&ingenicfb->dev->kobj, &lcd_debug_attr_group); ++ if (ret) { ++ dev_err(&pdev->dev, "device create sysfs group failed\n"); ++ ++ ret = -EINVAL; ++ goto err_free_irq; ++ } ++ ++ vsync_skip_set(ingenicfb, 0/*CONFIG_FB_VSYNC_SKIP*/); ++ ++ init_completion(&ingenicfb->vsync_wq); ++ ingenicfb->timestamp_irq_pos = 0; ++ ingenicfb->timestamp_thread_pos = 0; ++ spin_lock_init(&ingenicfb->vsync_lock); ++/* ingenicfb->vsync_thread = kthread_run(ingenicfb_wait_for_vsync_thread, ingenicfb, "ingenicfb-vsync"); ++ if (ingenicfb->vsync_thread == ERR_PTR(-ENOMEM)) { ++ dev_err(&pdev->dev, "Failed to run vsync thread"); ++ goto err_free_file; ++ } ++*/ ++ ret = register_framebuffer(fb); ++ if (ret) { ++ dev_err(&pdev->dev, "Failed to register framebuffer: %d\n", ++ ret); ++ goto err_kthread_stop; ++ } ++ ++ if (ingenicfb->vidmem_phys) { ++ if (!ingenicfb_copy_logo(ingenicfb->fb)) { ++ ingenicfb_change_dma_desc(ingenicfb->fb); ++ ingenicfb->is_inited = 1; ++ } else { ++ ingenicfb->is_inited = 0; ++ } ++#ifdef CONFIG_FB_INGENIC_DEBUG ++ test_pattern(ingenicfb); ++#endif ++ ++#ifdef CONFIG_SLCDC_LOW_POWER_CONSUMPTION ++ ingenicfb_disable(ingenicfb->fb); ++ ingenicfb_pclk_disable(ingenicfb); ++ ingenicfb_clk_disable(ingenicfb); ++#endif ++ } ++ return 0; ++ ++err_kthread_stop: ++ kthread_stop(ingenicfb->vsync_thread); ++/*err_free_file:*/ ++ sysfs_remove_group(&ingenicfb->dev->kobj, &lcd_debug_attr_group); ++err_free_irq: ++ free_irq(ingenicfb->irq, ingenicfb); ++err_free_devmem: ++ ingenicfb_free_devmem(ingenicfb); ++err_iounmap: ++ iounmap(ingenicfb->base); ++err_put_clk: ++err_framebuffer_release: ++ framebuffer_release(fb); ++err_release_mem_region: ++ release_mem_region(mem->start, resource_size(mem)); ++ return ret; ++} ++ ++static int ingenicfb_remove(struct platform_device *pdev) ++{ ++ struct ingenicfb *ingenicfb = platform_get_drvdata(pdev); ++ ++ kthread_stop(ingenicfb->vsync_thread); ++ ingenicfb_free_devmem(ingenicfb); ++ platform_set_drvdata(pdev, NULL); ++ sysfs_remove_group(&ingenicfb->dev->kobj, &lcd_debug_attr_group); ++ ++ iounmap(ingenicfb->base); ++ release_mem_region(ingenicfb->mem->start, resource_size(ingenicfb->mem)); ++ ++ framebuffer_release(ingenicfb->fb); ++ ++ return 0; ++} ++ ++static void ingenicfb_shutdown(struct platform_device *pdev) ++{ ++ struct ingenicfb *ingenicfb = platform_get_drvdata(pdev); ++ int is_fb_blank; ++ mutex_lock(&ingenicfb->suspend_lock); ++ is_fb_blank = (ingenicfb->is_suspend != 1); ++ ingenicfb->is_suspend = 1; ++ mutex_unlock(&ingenicfb->suspend_lock); ++ if (is_fb_blank) ++ fb_blank(ingenicfb->fb, FB_BLANK_POWERDOWN); ++}; ++ ++#ifdef CONFIG_PM ++ ++static int ingenicfb_suspend(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct ingenicfb *ingenicfb = platform_get_drvdata(pdev); ++ mutex_lock(&ingenicfb->lock); ++ /* set suspend state and notify panel, backlight client */ ++ fb_blank(ingenicfb->fb, FB_BLANK_POWERDOWN); ++ mutex_lock(&ingenicfb->suspend_lock); ++ ingenicfb->is_suspend = 1; ++ mutex_unlock(&ingenicfb->suspend_lock); ++ mutex_unlock(&ingenicfb->lock); ++ ++ /*disable clock*/ ++ ingenicfb_clk_disable(ingenicfb); ++ ingenicfb_pclk_disable(ingenicfb); ++ ++ return 0; ++} ++ ++static int ingenicfb_resume(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct ingenicfb *ingenicfb = platform_get_drvdata(pdev); ++ ++ fb_blank(ingenicfb->fb, FB_BLANK_UNBLANK); ++ ++ /*enable clock*/ ++ ingenicfb_clk_enable(ingenicfb); ++ ingenicfb_pclk_enable(ingenicfb); ++ ingenicfb_set_par(ingenicfb->fb); ++ ++ ++ mutex_lock(&ingenicfb->suspend_lock); ++ ingenicfb->is_suspend = 0; ++ mutex_unlock(&ingenicfb->suspend_lock); ++ ++ ingenicfb_display_v_color_bar(ingenicfb->fb); ++ return 0; ++} ++ ++static const struct dev_pm_ops ingenicfb_pm_ops = { ++ .suspend = ingenicfb_suspend, ++ .resume = ingenicfb_resume, ++}; ++#endif ++int ingenicfb_register_panel(struct ingenicfb_platform_data *panel) ++{ ++ WARN_ON(fbdev_panel != NULL); ++ ++ fbdev_panel = panel; ++ if(fbdev_pdev != NULL) { ++ return ingenicfb_do_probe(fbdev_pdev, fbdev_panel); ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(ingenicfb_register_panel); ++ ++static int ingenicfb_probe(struct platform_device *pdev) ++{ ++ WARN_ON(fbdev_pdev != NULL); ++ ++ fbdev_pdev = pdev; ++ ++ if(fbdev_panel != NULL) ++ return ingenicfb_do_probe(fbdev_pdev, fbdev_panel); ++ ++ return 0; ++} ++static const struct of_device_id ingenicfb_of_match[] = { ++ { .compatible = "ingenic,lcd"}, ++ {}, ++}; ++static struct platform_driver ingenicfb_driver = { ++ .probe = ingenicfb_probe, ++ .remove = ingenicfb_remove, ++ .shutdown = ingenicfb_shutdown, ++ .driver = { ++ .name = "ingenic-fb", ++ .of_match_table = ingenicfb_of_match, ++#ifdef CONFIG_PM ++ .pm = &ingenicfb_pm_ops, ++#endif ++ ++ }, ++}; ++ ++static int __init ingenicfb_init(void) ++{ ++ platform_driver_register(&ingenicfb_driver); ++ return 0; ++} ++ ++static void __exit ingenicfb_cleanup(void) ++{ ++ platform_driver_unregister(&ingenicfb_driver); ++} ++ ++#ifdef CONFIG_EARLY_INIT_RUN ++rootfs_initcall(ingenicfb_init); ++#else ++module_init(ingenicfb_init); ++#endif ++ ++module_exit(ingenicfb_cleanup); ++ ++MODULE_DESCRIPTION("ingenic LCD Controller driver"); ++MODULE_AUTHOR("Sean Tang "); ++MODULE_LICENSE("GPL"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v10_ingenicfb.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v10_ingenicfb.h.patch new file mode 100644 index 00000000..fea7dd5f --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v10_ingenicfb.h.patch @@ -0,0 +1,383 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v10/ingenicfb.h b/drivers/video/fbdev/ingenic/fb_v10/ingenicfb.h +--- a/drivers/video/fbdev/ingenic/fb_v10/ingenicfb.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v10/ingenicfb.h 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,379 @@ ++#include ++//#include ++ ++//#ifdef CONFIG_ONE_FRAME_BUFFERS ++#define NUM_FRAME_BUFFERS CONFIG_FB_INGENIC_NR_FRAMES ++//#endif ++ ++//#ifdef CONFIG_TWO_FRAME_BUFFERS ++//#define NUM_FRAME_BUFFERS 2 ++//#endif ++ ++//#ifdef CONFIG_THREE_FRAME_BUFFERS ++//#define NUM_FRAME_BUFFERS 3 ++//#endif ++ ++#define PIXEL_ALIGN 4 ++#define MAX_DESC_NUM 4 ++ ++/** ++ * @next: physical address of next frame descriptor ++ * @databuf: physical address of buffer ++ * @id: frame ID ++ * @cmd: DMA command and buffer length(in word) ++ * @offsize: DMA off size, in word ++ * @page_width: DMA page width, in word ++ * @cpos: smart LCD mode is commands' number, other is bpp, ++ * premulti and position of foreground 0, 1 ++ * @desc_size: alpha and size of foreground 0, 1 ++ */ ++struct ingenicfb_framedesc { ++ uint32_t next; ++ uint32_t databuf; ++ uint32_t id; ++ uint32_t cmd; ++ uint32_t offsize; ++ uint32_t page_width; ++ uint32_t cpos; ++ uint32_t desc_size; ++}; ++ ++struct ingenicfb_display_size { ++ u32 fg0_line_size; ++ u32 fg0_frm_size; ++ u32 panel_line_size; ++ u32 height_width; ++}; ++ ++enum ingenicfb_format_order { ++ FORMAT_X8R8G8B8 = 1, ++ FORMAT_X8B8G8R8, ++}; ++ ++/** ++ * @fg: foreground 0 or foreground 1 ++ * @bpp: foreground bpp ++ * @x: foreground start position x ++ * @y: foreground start position y ++ * @w: foreground width ++ * @h: foreground height ++ */ ++struct ingenicfb_fg_t { ++ u32 fg; ++ u32 bpp; ++ u32 x; ++ u32 y; ++ u32 w; ++ u32 h; ++}; ++ ++/** ++ *@decompress: enable decompress function, used by FG0 ++ *@block: enable 16x16 block function ++ *@fg0: fg0 info ++ *@fg1: fg1 info ++ */ ++struct ingenicfb_osd_t { ++ int block; ++ struct ingenicfb_fg_t fg0; ++ struct ingenicfb_fg_t fg1; ++}; ++ ++struct ingenicfb { ++ int fb_bpp; /* bpp of frame buffer */ ++ int is_lcd_en; /* 0, disable 1, enable */ ++ int is_clk_en; /* 0, disable 1, enable */ ++ int is_pclk_en; /* 0, disable 1, enable */ ++ int irq; /* lcdc interrupt num */ ++ int open_cnt; ++ int irq_cnt; ++ int desc_num; ++ char clk_name[16]; ++ char pclk_name[16]; ++ char pwcl_name[16]; ++ char irq_name[16]; ++ ++ struct fb_info *fb; ++ struct device *dev; ++ struct ingenicfb_platform_data *pdata; ++ void __iomem *base; ++ struct resource *mem; ++ ++ size_t vidmem_size; ++ void *vidmem; ++ dma_addr_t vidmem_phys; ++ void *desc_cmd_vidmem; ++ dma_addr_t desc_cmd_phys; ++ ++ int frm_size; ++ int current_buffer; ++ /* dma 0 descriptor base address */ ++ struct ingenicfb_framedesc *framedesc[MAX_DESC_NUM]; ++ struct ingenicfb_framedesc *fg1_framedesc; /* FG 1 dma descriptor */ ++ dma_addr_t framedesc_phys; ++ ++ struct completion vsync_wq; ++ struct task_struct *vsync_thread; ++ unsigned int vsync_skip_map; /* 10 bits width */ ++ int vsync_skip_ratio; ++ ++ struct mutex lock; ++ struct mutex suspend_lock; ++ ++ enum ingenicfb_format_order fmt_order; /* frame buffer pixel format order */ ++ struct ingenicfb_osd_t osd; /* osd's config information */ ++ ++ struct clk *clk; ++ struct clk *pclk; ++ struct clk *pwcl; ++ ++ int is_suspend; ++ unsigned int pan_display_count; ++ ++ char eventbuf[64]; ++ int is_vsync; ++ int is_inited; ++ ++ /* long long timestamp_array[16]; */ ++ ktime_t timestamp_array[16]; ++ int timestamp_irq_pos; ++ int timestamp_thread_pos; ++ spinlock_t vsync_lock; ++}; ++ ++void ingenicfb_clk_enable(struct ingenicfb *ingenicfb); ++void ingenicfb_clk_disable(struct ingenicfb *ingenicfb); ++static inline unsigned long reg_read(struct ingenicfb *ingenicfb, int offset) ++{ ++ return readl(ingenicfb->base + offset); ++} ++ ++static inline void reg_write(struct ingenicfb *ingenicfb, int offset, unsigned long val) ++{ ++ writel(val, ingenicfb->base + offset); ++} ++ ++/* structures for frame buffer ioctl */ ++struct ingenicfb_fg_pos { ++ __u32 fg; /* 0:fg0, 1:fg1 */ ++ __u32 x; ++ __u32 y; ++}; ++ ++struct ingenicfb_fg_size { ++ __u32 fg; ++ __u32 w; ++ __u32 h; ++}; ++ ++struct ingenicfb_fg_alpha { ++ __u32 fg; /* 0:fg0, 1:fg1 */ ++ __u32 enable; ++ __u32 mode; /* 0:global alpha, 1:pixel alpha */ ++ __u32 value; /* 0x00-0xFF */ ++}; ++ ++struct ingenicfb_bg { ++ __u32 fg; /* 0:fg0, 1:fg1 */ ++ __u32 red; ++ __u32 green; ++ __u32 blue; ++}; ++ ++struct ingenicfb_color_key { ++ __u32 fg; /* 0:fg0, 1:fg1 */ ++ __u32 enable; ++ __u32 mode; /* 0:color key, 1:mask color key */ ++ __u32 red; ++ __u32 green; ++ __u32 blue; ++}; ++ ++struct ingenicfb_mode_res { ++ __u32 index; /* 1-64 */ ++ __u32 w; ++ __u32 h; ++}; ++ ++/* ioctl commands base fb.h FBIO_XXX */ ++/* image_enh.h: 0x142 -- 0x162 */ ++#define INGENICFB_GET_MODENUM _IOR('F', 0x100, int) ++#define INGENICFB_GET_MODELIST _IOR('F', 0x101, int) ++#define INGENICFB_SET_VIDMEM _IOW('F', 0x102, unsigned int *) ++#define INGENICFB_SET_MODE _IOW('F', 0x103, int) ++#define INGENICFB_ENABLE _IOW('F', 0x104, int) ++#define INGENICFB_GET_RESOLUTION _IOWR('F', 0x105, struct ingenicfb_mode_res) ++ ++/* Reserved for future extend */ ++#define INGENICFB_SET_FG_SIZE _IOW('F', 0x116, struct ingenicfb_fg_size) ++#define INGENICFB_GET_FG_SIZE _IOWR('F', 0x117, struct ingenicfb_fg_size) ++#define INGENICFB_SET_FG_POS _IOW('F', 0x118, struct ingenicfb_fg_pos) ++#define INGENICFB_GET_FG_POS _IOWR('F', 0x119, struct ingenicfb_fg_pos) ++#define INGENICFB_GET_BUFFER _IOR('F', 0x120, int) ++/* Reserved for future extend */ ++#define INGENICFB_SET_ALPHA _IOW('F', 0x123, struct ingenicfb_fg_alpha) ++#define INGENICFB_SET_BACKGROUND _IOW('F', 0x124, struct ingenicfb_bg) ++#define INGENICFB_SET_COLORKEY _IOW('F', 0x125, struct ingenicfb_color_key) ++#define INGENICFB_16X16_BLOCK_EN _IOW('F', 0x127, int) ++#define INGENICFB_ENABLE_LCDC_CLK _IOW('F', 0x130, int) ++/* Reserved for future extend */ ++#define INGENICFB_ENABLE_FG0 _IOW('F', 0x139, int) ++#define INGENICFB_ENABLE_FG1 _IOW('F', 0x140, int) ++ ++/* Reserved for future extend */ ++#define INGENICFB_SET_VSYNCINT _IOW('F', 0x210, int) ++/* define in image_enh.c */ ++extern int ingenicfb_config_image_enh(struct fb_info *info); ++extern int ingenicfb_image_enh_ioctl(struct fb_info *info, unsigned int cmd, ++ unsigned long arg); ++extern int update_slcd_frame_buffer(void); ++extern int lcd_display_inited_by_uboot(void); ++extern int ingenicfb_register_panel(struct ingenicfb_platform_data *panel); ++ ++#define FB_MODE_IS_VGA (1 << 30) ++enum ingenicfb_lcd_type { ++ LCD_TYPE_GENERIC_16_BIT = 0, ++ LCD_TYPE_GENERIC_18_BIT = 0 | (1 << 7), ++ LCD_TYPE_GENERIC_24_BIT = 0 | (1 << 6), ++ LCD_TYPE_SPECIAL_TFT_1 = 1, ++ LCD_TYPE_SPECIAL_TFT_2 = 2, ++ LCD_TYPE_SPECIAL_TFT_3 = 3, ++ LCD_TYPE_NON_INTERLACED_TV = 4 | (1 << 26), ++ LCD_TYPE_INTERLACED_TV = 6 | (1 << 26) | (1 << 30), ++ LCD_TYPE_8BIT_SERIAL = 0xc, ++ LCD_TYPE_SLCD = 0xd | (1 << 31), ++}; ++ ++/* smart lcd command width */ ++enum smart_lcd_cwidth { ++ SMART_LCD_CWIDTH_16_BIT_ONCE = (0 << 8), ++ SMART_LCD_CWIDTH_9_BIT_ONCE = SMART_LCD_CWIDTH_16_BIT_ONCE, ++ SMART_LCD_CWIDTH_8_BIT_ONCE = (0x1 << 8), ++ SMART_LCD_CWIDTH_18_BIT_ONCE = (0x2 << 8), ++ SMART_LCD_CWIDTH_24_BIT_ONCE = (0x3 << 8), ++}; ++ ++/* smart lcd data width */ ++enum smart_lcd_dwidth { ++ SMART_LCD_DWIDTH_18_BIT_ONCE_PARALLEL_SERIAL = (0 << 10), ++ SMART_LCD_DWIDTH_16_BIT_ONCE_PARALLEL_SERIAL = (0x1 << 10), ++ SMART_LCD_DWIDTH_8_BIT_THIRD_TIME_PARALLEL = (0x2 << 10), ++ SMART_LCD_DWIDTH_8_BIT_TWICE_TIME_PARALLEL = (0x3 << 10), ++ SMART_LCD_DWIDTH_8_BIT_ONCE_PARALLEL_SERIAL = (0x4 << 10), ++ SMART_LCD_DWIDTH_24_BIT_ONCE_PARALLEL = (0x5 << 10), ++ SMART_LCD_DWIDTH_9_BIT_TWICE_TIME_PARALLEL = (0x7 << 10), ++ SMART_LCD_DWIDTH_MASK = (0x7 << 10) ++}; ++ ++/* smart lcd new data width */ ++enum smart_lcd_new_dwidth { ++ SMART_LCD_NEW_DWIDTH_24_BIT = (4 << 13), ++ SMART_LCD_NEW_DWIDTH_18_BIT = (3 << 13), ++ SMART_LCD_NEW_DWIDTH_16_BIT = (2 << 13), ++ SMART_LCD_NEW_DWIDTH_9_BIT = (1 << 13), ++ SMART_LCD_NEW_DWIDTH_8_BIT = (0 << 13), ++ SMART_LCD_NEW_DWIDTH_MASK = (0x7 << 13), ++}; ++ ++/* smart lcd data times */ ++enum smart_lcd_new_dtimes { ++ SMART_LCD_NEW_DTIMES_ONCE = (0 << 8), ++ SMART_LCD_NEW_DTIMES_TWICE = (1 << 8), ++ SMART_LCD_NEW_DTIMES_THICE = (2 << 8), ++ SMART_LCD_NEW_DTIMES_MASK = (3 << 8), ++}; ++ ++enum smart_config_type { ++ SMART_CONFIG_CMD = 0, ++ SMART_CONFIG_DATA = 1, ++ SMART_CONFIG_UDELAY = 2, ++}; ++ ++struct smart_lcd_data_table { ++ enum smart_config_type type; ++ uint32_t value; ++}; ++ ++enum smart_lcd_type { ++ SMART_LCD_TYPE_PARALLEL, ++ SMART_LCD_TYPE_SERIAL, ++}; ++ ++struct ingenicfb_platform_data { ++ size_t num_modes; ++ struct fb_videomode *modes; ++ struct ingenicdsi_data *dsi_pdata; ++ ++ enum ingenicfb_lcd_type lcd_type; ++ unsigned int bpp; ++ unsigned int width; ++ unsigned int height; ++ unsigned pinmd:1; ++ ++ unsigned pixclk_falling_edge:1; ++ unsigned data_enable_active_low:1; ++ ++ struct { ++ enum smart_lcd_type smart_type; ++ unsigned clkply_active_rising:1; ++ unsigned rsply_cmd_high:1; ++ unsigned csply_active_high:1; ++ ++ unsigned newcfg_6800_md:1; ++ unsigned newcfg_fmt_conv:1; ++ unsigned datatx_type_serial:1; ++ unsigned cmdtx_type_serial:1; ++ unsigned newcfg_cmd_9bit:1; ++ ++ size_t length_cmd; ++ unsigned long *write_gram_cmd; ++ unsigned int bus_width; ++ unsigned int data_table_width; ++ /* ++ * ++ * data_table_width: ++ * The width of the (struct)smart_lcd_data_table.value, ++ * which provided by panel manufacturers. ++ * e.g. ++ * truly_tft240240_2_e is 8bit, ++ * kfm701a21_1a is 16bit. ++ * ++ * */ ++ size_t length_data_table; ++ struct smart_lcd_data_table *data_table; ++ int (*init) (void); ++ int (*gpio_for_slcd) (void); ++ int te_gpio; ++ int te_irq_level; ++ ++ } smart_config; ++ ++ unsigned dither_enable:1; ++ struct { ++ unsigned dither_red; ++ unsigned dither_green; ++ unsigned dither_blue; ++ } dither; ++ ++ struct { ++ uint32_t spl; ++ uint32_t cls; ++ uint32_t ps; ++ uint32_t rev; ++ } special_tft_config; ++ ++ struct { ++ int (*lcd_initialize_begin)(void*); ++ int (*lcd_initialize_end)(void*); ++ ++ int (*lcd_power_on_begin)(void*); ++ int (*lcd_power_on_end)(void*); ++ ++ int (*lcd_power_off_begin)(void*); ++ int (*lcd_power_off_end)(void*); ++ ++ int (*dma_transfer_begin)(void*); ++ int (*dma_transfer_end)(void*); ++ } lcd_callback_ops; ++ ++}; diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v10_lcd_regs.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v10_lcd_regs.h.patch new file mode 100644 index 00000000..bca4363a --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v10_lcd_regs.h.patch @@ -0,0 +1,645 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v10/lcd_regs.h b/drivers/video/fbdev/ingenic/fb_v10/lcd_regs.h +--- a/drivers/video/fbdev/ingenic/fb_v10/lcd_regs.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v10/lcd_regs.h 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,641 @@ ++/* drivers/video/jz4780/regs.h ++ * ++ * Copyright (c) 2012 Ingenic Semiconductor Co., Ltd. ++ * http://www.ingenic.com/ ++ * ++ * Register definition file for ingenic jz4780 Display Controller driver ++ * ++ * 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. ++*/ ++ ++#ifndef _REGS_LCDC_H_ ++#define _REGS_LCDC_H_ ++ ++/* Register Map Of LCDC */ ++#define LCDC_CFG (0x00) /* Configure Register */ ++#define LCDC_CTRL (0x30) /* Control Register */ ++#define LCDC_STATE (0x34) /* Status Register */ ++ ++#define LCDC_OSDC (0x100) /* OSD Configure Register */ ++#define LCDC_OSDCTRL (0x104) /* OSD Control Register */ ++#define LCDC_OSDS (0x108) /* OSD Status Register */ ++#define LCDC_BGC0 (0x10c) /* Background 0 Color Register */ ++#define LCDC_BGC1 (0x2c4) /* Background 1 Color Register */ ++//#define LCDC_BGC1 (0x24c) /* Background 1 Color Register */ ++#define LCDC_KEY0 (0x110) /* Foreground Color Key Register 0 */ ++#define LCDC_KEY1 (0x114) /* Foreground Color Key Register 1 */ ++#define LCDC_ALPHA (0x118) /* ALPHA Register */ ++#define LCDC_IPUR (0x11c) /* IPU Restart Register */ ++#define LCDC_RGBC (0x90) /* RGB Controll Register */ ++ ++#define LCDC_VAT (0x0c) /* Virtual Area Setting Register */ ++#define LCDC_DAH (0x10) /* Display Area Horizontal Start/End Point */ ++#define LCDC_DAV (0x14) /* Display Area Vertical Start/End Point */ ++ ++#define LCDC_XYP0 (0x120) /* Foreground 0 XY Position Register */ ++#define LCDC_XYP1 (0x124) /* Foreground 1 XY Position Register */ ++#define LCDC_SIZE0 (0x128) /* Foreground 0 Size Register */ ++#define LCDC_SIZE1 (0x12c) /* Foreground 1 Size Register */ ++ ++#define LCDC_VSYNC (0x04) /* Vertical Synchronize Register */ ++#define LCDC_HSYNC (0x08) /* Horizontal Synchronize Register */ ++#define LCDC_PS (0x18) /* PS Signal Setting */ ++#define LCDC_CLS (0x1c) /* CLS Signal Setting */ ++#define LCDC_SPL (0x20) /* SPL Signal Setting */ ++#define LCDC_REV (0x24) /* REV Signal Setting */ ++#define LCDC_IID (0x38) /* Interrupt ID Register */ ++#define LCDC_DA0 (0x40) /* Descriptor Address Register 0 */ ++#define LCDC_SA0 (0x44) /* Source Address Register 0 */ ++#define LCDC_FID0 (0x48) /* Frame ID Register 0 */ ++#define LCDC_CMD0 (0x4c) /* DMA Command Register 0 */ ++ ++#define LCDC_OFFS0 (0x60) /* DMA Offsize Register 0 */ ++#define LCDC_PW0 (0x64) /* DMA Page Width Register 0 */ ++#define LCDC_CNUM0 (0x68) /* ++ * DMA Command Counter Register 0 ++ * only used in smart LCD mode ++ */ ++#define LCDC_CPOS0 (0x68) /* DMA Command and position Register 0 */ ++#define LCDC_DESSIZE0 (0x6c) /* Foreground Size in Descriptor 0 Register */ ++ ++#define LCDC_DA1 (0x50) /* Descriptor Address Register 1 */ ++#define LCDC_SA1 (0x54) /* Source Address Register 1 */ ++#define LCDC_FID1 (0x58) /* Frame ID Register 1 */ ++#define LCDC_CMD1 (0x5c) /* DMA Command Register 1 */ ++#define LCDC_OFFS1 (0x70) /* DMA Offsize Register 1 */ ++#define LCDC_PW1 (0x74) /* DMA Page Width Register 1 */ ++#define LCDC_CNUM1 (0x78) /* ++ * DMA Command Counter Register 1 ++ * only used in smart LCD mode ++ */ ++#define LCDC_CPOS1 (0x78) /* DMA Command and position Register 1 */ ++#define LCDC_DESSIZE1 (0x7c) /* Foreground Size in Descriptor 1 Register */ ++ ++#define LCDC_PCFG (0x2c0) /* Priority level threshold configure Register */ ++#define LCDC_DUAL_CTRL (0x2c8) /* Dual LCDC Channel Control register */ ++ ++#define LCDC_ENH_CFG (0x400) /* Image inhancement CFG Register */ ++#define LCDC_ENH_CSCCFG (0x404) /* Color space conversion CFG Register */ ++#define LCDC_ENH_LUMACFG (0x408) /* LUMA CFG Register */ ++#define LCDC_ENH_CHROCFG0 (0x40c) /* CHROMA0 CFG Register */ ++#define LCDC_ENH_CHROCFG1 (0x410) /* CHROMA1 CFG Register */ ++#define LCDC_ENH_DITHERCFG (0x414) /* DITHER CFG Register */ ++#define LCDC_ENH_STATUS (0x418) /* Enhance status Register */ ++#define LCDC_ENH_GAMMA (0x800) /* GAMMA CFG Register */ ++#define LCDC_ENH_VEE (0x1000) /* VEE CFG Register */ ++ ++/* LCD Configure Register */ ++#define LCDC_CFG_LCDPIN_BIT 31 /* LCD pins selection */ ++#define LCDC_CFG_LCDPIN_MASK (0x1 << LCDC_CFG_LCDPIN_BIT) ++#define LCDC_CFG_LCDPIN_LCD (0x0 << LCDC_CFG_LCDPIN_BIT) ++#define LCDC_CFG_LCDPIN_SLCD (0x1 << LCDC_CFG_LCDPIN_BIT) ++#define LCDC_CFG_TVEPEH (1 << 30) /* TVE PAL enable extra halfline signal */ ++ /* Keep this bit to 0 */ ++#define LCDC_CFG_NEWDES (1 << 28) /* use new descripter. old: 4words, new:8words */ ++#define LCDC_CFG_PALBP (1 << 27) /* bypass data format and alpha blending */ ++#define LCDC_CFG_TVEN (1 << 26) /* indicate the terminal is lcd or tv */ ++#define LCDC_CFG_RECOVER (1 << 25) /* Auto recover when output fifo underrun */ ++/* Dither function has been move to DITHER CFG Register*/ ++#define LCDC_CFG_PSM (1 << 23) /* PS signal mode */ ++#define LCDC_CFG_CLSM (1 << 22) /* CLS signal mode */ ++#define LCDC_CFG_SPLM (1 << 21) /* SPL signal mode */ ++#define LCDC_CFG_REVM (1 << 20) /* REV signal mode */ ++#define LCDC_CFG_HSYNM (1 << 19) /* HSYNC signal mode */ ++#define LCDC_CFG_PCLKM (1 << 18) /* PCLK signal mode */ ++#define LCDC_CFG_INVDAT (1 << 17) /* Inverse output data */ ++#define LCDC_CFG_SYNDIR_IN (1 << 16) /* VSYNC&HSYNC direction */ ++#define LCDC_CFG_PSP (1 << 15) /* PS pin reset state */ ++#define LCDC_CFG_CLSP (1 << 14) /* CLS pin reset state */ ++#define LCDC_CFG_SPLP (1 << 13) /* SPL pin reset state */ ++#define LCDC_CFG_REVP (1 << 12) /* REV pin reset state */ ++#define LCDC_CFG_HSP (1 << 11) /* HSYNC polarity:0-active high,1-active low */ ++#define LCDC_CFG_PCP (1 << 10) /* PCLK polarity:0-rising,1-falling */ ++#define LCDC_CFG_DEP (1 << 9) /* DE polarity:0-active high,1-active low */ ++#define LCDC_CFG_VSP (1 << 8) /* VSYNC polarity:0-rising,1-falling */ ++#define LCDC_CFG_MODE_TFT_18BIT (1 << 7) /* 18bit TFT */ ++#define LCDC_CFG_MODE_TFT_16BIT (0 << 7) /* 16bit TFT */ ++#define LCDC_CFG_MODE_TFT_24BIT (1 << 6) /* 24bit TFT */ ++ ++#define LCDC_CFG_MODE_BIT 0 /* Display Device Mode Select */ ++#define LCDC_CFG_MODE_MASK (0x0f << LCDC_CFG_MODE_BIT) ++#define LCDC_CFG_MODE_GENERIC_TFT (0 << LCDC_CFG_MODE_BIT) /* 16,18 bit TFT */ ++#define LCDC_CFG_MODE_SPECIAL_TFT_1 (1 << LCDC_CFG_MODE_BIT) ++#define LCDC_CFG_MODE_SPECIAL_TFT_2 (2 << LCDC_CFG_MODE_BIT) ++#define LCDC_CFG_MODE_SPECIAL_TFT_3 (3 << LCDC_CFG_MODE_BIT) ++#define LCDC_CFG_MODE_NONINTER_CCIR656 (4 << LCDC_CFG_MODE_BIT) ++#define LCDC_CFG_MODE_INTER_CCIR656 (6 << LCDC_CFG_MODE_BIT) ++#define LCDC_CFG_MODE_SERIAL_TFT (12 << LCDC_CFG_MODE_BIT) ++#define LCDC_CFG_MODE_LCM (13 << LCDC_CFG_MODE_BIT) ++ ++/* LCD Control Register */ ++#define LCDC_CTRL_PINMD (1 << 31) /* This register set Pin distribution in 16-bit parallel mode ++ 0: 16-bit data correspond with LCDC_D[15:0] ++ 1: 16-bit data correspond with LCDC_D[17:10], LCDC_D[8:1] */ ++#define LCDC_CTRL_BST_BIT 28 /* Burst Length Selection */ ++#define LCDC_CTRL_BST_MASK (0x7 << LCDC_CTRL_BST_BIT) ++#define LCDC_CTRL_BST_4 (0 << LCDC_CTRL_BST_BIT) /* 4-word */ ++#define LCDC_CTRL_BST_8 (1 << LCDC_CTRL_BST_BIT) /* 8-word */ ++#define LCDC_CTRL_BST_16 (2 << LCDC_CTRL_BST_BIT) /* 16-word */ ++#define LCDC_CTRL_BST_32 (3 << LCDC_CTRL_BST_BIT) /* 32-word */ ++#define LCDC_CTRL_BST_64 (4 << LCDC_CTRL_BST_BIT) /* 64-word */ ++#define LCDC_CTRL_RGB565 (0 << 27) /* RGB565 mode(foreground 0 in OSD mode) */ ++#define LCDC_CTRL_RGB555 (1 << 27) /* RGB555 mode(foreground 0 in OSD mode) */ ++#define LCDC_CTRL_OFUP (1 << 26) /* Output FIFO underrun protection enable */ ++#define LCDC_CTRL_PDD_BIT 16 /* Load Palette Delay Counter */ ++#define LCDC_CTRL_PDD_MASK (0xff << LCDC_CTRL_PDD_BIT) ++ /* Keep this bit to 0 */ ++#define LCDC_CTRL_DACTE (1 << 14) /* DAC loop back test */ ++#define LCDC_CTRL_EOFM (1 << 13) /* EOF interrupt mask */ ++#define LCDC_CTRL_SOFM (1 << 12) /* SOF interrupt mask */ ++#define LCDC_CTRL_OFUM (1 << 11) /* Output FIFO underrun interrupt mask */ ++#define LCDC_CTRL_IFUM0 (1 << 10) /* Input FIFO 0 underrun interrupt mask */ ++#define LCDC_CTRL_IFUM1 (1 << 9) /* Input FIFO 1 underrun interrupt mask */ ++#define LCDC_CTRL_LDDM (1 << 8) /* LCD disable done interrupt mask */ ++#define LCDC_CTRL_QDM (1 << 7) /* LCD quick disable done interrupt mask */ ++#define LCDC_CTRL_BEDN (1 << 6) /* Endian selection */ ++#define LCDC_CTRL_PEDN (1 << 5) /* Endian in byte:0-msb first, 1-lsb first */ ++#define LCDC_CTRL_DIS (1 << 4) /* Disable indicate bit */ ++#define LCDC_CTRL_ENA (1 << 3) /* LCDC enable bit */ ++#define LCDC_CTRL_BPP_BIT 0 /* Bits Per Pixel */ ++#define LCDC_CTRL_BPP_MASK (0x07 << LCDC_CTRL_BPP_BIT) ++#define LCDC_CTRL_BPP_1 (0 << LCDC_CTRL_BPP_BIT) /* 1 bpp */ ++#define LCDC_CTRL_BPP_2 (1 << LCDC_CTRL_BPP_BIT) /* 2 bpp */ ++#define LCDC_CTRL_BPP_4 (2 << LCDC_CTRL_BPP_BIT) /* 4 bpp */ ++#define LCDC_CTRL_BPP_8 (3 << LCDC_CTRL_BPP_BIT) /* 8 bpp */ ++#define LCDC_CTRL_BPP_16 (4 << LCDC_CTRL_BPP_BIT) /* 15/16 bpp */ ++#define LCDC_CTRL_BPP_18_24 (5 << LCDC_CTRL_BPP_BIT) /* 18/24/32 bpp */ ++#define LCDC_CTRL_BPP_CMPS_24 (6 << LCDC_CTRL_BPP_BIT) /* 24 compress bpp */ ++#define LCDC_CTRL_BPP_30 (7 << LCDC_CTRL_BPP_BIT) /* 30 bpp */ ++ ++/* LCD Status Register */ ++#define LCDC_STATE_QD (1 << 7) /* Quick Disable Done */ ++#define LCDC_STATE_EOF (1 << 5) /* EOF Flag */ ++#define LCDC_STATE_SOF (1 << 4) /* SOF Flag */ ++#define LCDC_STATE_OFU (1 << 3) /* Output FIFO Underrun */ ++#define LCDC_STATE_IFU0 (1 << 2) /* Input FIFO 0 Underrun */ ++#define LCDC_STATE_IFU1 (1 << 1) /* Input FIFO 1 Underrun */ ++#define LCDC_STATE_LDD (1 << 0) /* LCD Disabled */ ++ ++/* OSD Configure Register */ ++#define LCDC_OSDC_PREMULTI1 (1 << 23) /* ++ * Premulti enable of foreground 1 ++ * 0:data has been premultied and don't need premulti ++ * 1:data should be premultied by lcd ++ */ ++#define LCDC_OSDC_COEF_SLE1_BIT 21 /* Select coefficient for foreground 1 */ ++#define LCDC_OSDC_COEF_SLE1_MASK (0x03 << LCDC_OSDC_COEF_SLE1_BIT) ++#define LCDC_OSDC_COEF_SLE1_0 (0 << LCDC_OSDC_COEF_SLE1_BIT) /* 00:0 */ ++#define LCDC_OSDC_COEF_SLE1_1 (1 << LCDC_OSDC_COEF_SLE1_BIT) /* 01:1 */ ++#define LCDC_OSDC_COEF_SLE1_2 (2 << LCDC_OSDC_COEF_SLE1_BIT) /* 10:alpha0 */ ++#define LCDC_OSDC_COEF_SLE1_3 (3 << LCDC_OSDC_COEF_SLE1_BIT) /* 11:1-alpha0 */ ++ ++#define LCDC_OSDC_PREMULTI0 (1 << 20) /* ++ * Premulti enable of foreground 0 ++ * 0:data has been premultied and don't need premulti ++ * 1:data should be premultied by lcd ++ */ ++#define LCDC_OSDC_COEF_SLE0_BIT 18 /* Select coefficient for foreground 0 */ ++#define LCDC_OSDC_COEF_SLE0_MASK (0x03 << LCDC_OSDC_COEF_SLE0_BIT) ++#define LCDC_OSDC_COEF_SLE0_0 (0 << LCDC_OSDC_COEF_SLE0_BIT) /* 00:0 */ ++#define LCDC_OSDC_COEF_SLE0_1 (1 << LCDC_OSDC_COEF_SLE0_BIT) /* 01:1 */ ++#define LCDC_OSDC_COEF_SLE0_2 (2 << LCDC_OSDC_COEF_SLE0_BIT) /* 10:alpha1 */ ++#define LCDC_OSDC_COEF_SLE0_3 (3 << LCDC_OSDC_COEF_SLE0_BIT) /* 11:1-alpha1 */ ++#define LCDC_OSDC_ALPHAMD1 (1 << 17) /* Alpha blending mode for foreground 1 */ ++ ++#define LCDC_OSDC_SOFM1 (1 << 15) /* Start of frame interrupt mask for foreground 1 */ ++#define LCDC_OSDC_EOFM1 (1 << 14) /* End of frame interrupt mask for foreground 1 */ ++#define LCDC_OSDC_SOFM0 (1 << 11) /* Start of frame interrupt mask for foreground 0 */ ++#define LCDC_OSDC_EOFM0 (1 << 10) /* End of frame interrupt mask for foreground 0 */ ++#define LCDC_OSDC_DENDM (1 << 9) /* Display end interrupt mask */ ++#define LCDC_OSDC_F1EN (1 << 4) /* enable foreground 1 */ ++#define LCDC_OSDC_F0EN (1 << 3) /* enable foreground 0 */ ++#define LCDC_OSDC_ALPHAEN (1 << 2) /* enable alpha blending */ ++#define LCDC_OSDC_ALPHAMD0 (1 << 1) /* alpha blending mode */ ++#define LCDC_OSDC_OSDEN (1 << 0) /* OSD mode enable */ ++ ++/* OSD Controll Register */ ++#define LCDC_OSDCTRL_IPU_CLKEN (1 << 15) /* IPU clock enable: 1: enable; 0:disable */ ++#define LCDC_OSDCTRL_RGB0_RGB565 (0 << 5) /* foreground 0, 16bpp, 0-RGB565, 1-RGB555 */ ++#define LCDC_OSDCTRL_RGB0_RGB555 (1 << 5) /* foreground 0, 16bpp, 0-RGB565, 1-RGB555 */ ++#define LCDC_OSDCTRL_RGB1_RGB565 (0 << 4) /* foreground 1, 16bpp, 0-RGB565, 1-RGB555 */ ++#define LCDC_OSDCTRL_RGB1_RGB555 (1 << 4) /* foreground 1, 16bpp, 0-RGB565, 1-RGB555 */ ++ ++#define LCDC_OSDCTRL_BPP_BIT 0 /* Bits Per Pixel of OSD Channel 1 */ ++#define LCDC_OSDCTRL_BPP_MASK (0x7< ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../ingenicfb.h" ++ ++struct board_gpio { ++ short gpio; ++ short active_level; ++}; ++ ++struct panel_dev { ++ /* ingenic frame buffer */ ++ struct device *dev; ++ struct lcd_panel *panel; ++ ++ /* common lcd framework */ ++ struct lcd_device *lcd; ++ struct backlight_device *backlight; ++ int power; ++ ++ struct regulator *vcc; ++ struct board_gpio cs; ++ struct board_gpio rst; ++ struct board_gpio vdd_en; ++ struct board_gpio pwm; ++}; ++ ++static struct smart_lcd_data_table kd035hvfbd037_data_table[] = { ++/* LCD init code */ ++ {SMART_CONFIG_UDELAY, 12000}, ++ {SMART_CONFIG_CMD , 0xff}, //Command 2 Enable ++ {SMART_CONFIG_PRM , 0x48}, ++ {SMART_CONFIG_PRM , 0x02}, ++ {SMART_CONFIG_PRM , 0x01}, ++ ++ {SMART_CONFIG_CMD , 0x00}, ++ {SMART_CONFIG_PRM , 0x80}, ++ {SMART_CONFIG_CMD , 0xff}, //ORISE Command Enable ++ {SMART_CONFIG_PRM , 0x48}, ++ {SMART_CONFIG_PRM , 0x02}, ++ ++ {SMART_CONFIG_CMD , 0x00}, ++ {SMART_CONFIG_PRM , 0x90}, ++ {SMART_CONFIG_CMD , 0xFF}, //MPU 16bit setting ++ {SMART_CONFIG_PRM , 0x01}, //02-16BIT MCU,01-8BIT MCU ++ ++ {SMART_CONFIG_CMD , 0x00}, ++ {SMART_CONFIG_PRM , 0x93}, ++ {SMART_CONFIG_CMD , 0xFF}, //SW MPU enable ++ {SMART_CONFIG_PRM , 0x20}, ++ ++ {SMART_CONFIG_CMD , 0x00}, ++ {SMART_CONFIG_PRM , 0x00}, ++ {SMART_CONFIG_CMD , 0x51}, //Wright Display brightness ++ {SMART_CONFIG_PRM , 0xf0}, ++ ++ {SMART_CONFIG_CMD , 0x00}, ++ {SMART_CONFIG_PRM , 0x00}, ++ {SMART_CONFIG_CMD , 0x53}, // Wright CTRL Display ++ {SMART_CONFIG_PRM , 0x24}, ++ ++ {SMART_CONFIG_CMD , 0x00}, ++ {SMART_CONFIG_PRM , 0xb1}, ++ {SMART_CONFIG_CMD , 0xc5}, //VSEL setting ++ {SMART_CONFIG_PRM , 0x00}, ++ ++ {SMART_CONFIG_CMD , 0x00}, ++ {SMART_CONFIG_PRM , 0xB0}, ++ {SMART_CONFIG_CMD , 0xc4}, //Gate Timing control ++ {SMART_CONFIG_PRM , 0x02}, ++ {SMART_CONFIG_PRM , 0x08}, ++ {SMART_CONFIG_PRM , 0x05}, ++ {SMART_CONFIG_PRM , 0x00}, ++ ++ {SMART_CONFIG_CMD , 0x00}, ++ {SMART_CONFIG_PRM , 0x90}, ++ {SMART_CONFIG_CMD , 0xc0}, //TCON MCLK Shift Control ++ {SMART_CONFIG_PRM , 0x00}, ++ {SMART_CONFIG_PRM , 0x0f}, ++ {SMART_CONFIG_PRM , 0x00}, ++ {SMART_CONFIG_PRM , 0x15}, ++ {SMART_CONFIG_PRM , 0x00}, ++ {SMART_CONFIG_PRM , 0x17}, ++ ++ {SMART_CONFIG_CMD , 0x00}, ++ {SMART_CONFIG_PRM , 0x82}, ++ {SMART_CONFIG_CMD , 0xc5}, //Adjust pump phase ++ {SMART_CONFIG_PRM , 0x01}, ++ ++ {SMART_CONFIG_CMD , 0x00}, ++ {SMART_CONFIG_PRM , 0x90}, ++ {SMART_CONFIG_CMD , 0xc5}, //Adjust pump phase ++ {SMART_CONFIG_PRM , 0x47}, ++ ++ {SMART_CONFIG_CMD , 0x00}, ++ {SMART_CONFIG_PRM , 0x00}, ++ {SMART_CONFIG_CMD , 0xd8}, //GVDD/NGVDD Setting ++ {SMART_CONFIG_PRM , 0x58}, //58,17V ++ {SMART_CONFIG_PRM , 0x58}, //58 ++ ++ {SMART_CONFIG_CMD , 0x00}, ++ {SMART_CONFIG_PRM , 0x00}, ++ {SMART_CONFIG_CMD , 0xd9}, //VCOM Setting ++ {SMART_CONFIG_PRM , 0xb0}, // ++ ++ {SMART_CONFIG_CMD , 0x00}, ++ {SMART_CONFIG_PRM , 0x91}, ++ {SMART_CONFIG_CMD , 0xb3}, //Display setting ++ {SMART_CONFIG_PRM , 0xC0}, ++ {SMART_CONFIG_PRM , 0x25}, ++ ++ {SMART_CONFIG_CMD , 0x00}, ++ {SMART_CONFIG_PRM , 0x81}, ++ {SMART_CONFIG_CMD , 0xC1}, //Osillator Adjustment:70Hz ++ {SMART_CONFIG_PRM , 0x77}, ++ ++ {SMART_CONFIG_CMD , 0x00}, ++ {SMART_CONFIG_PRM , 0x00}, ++ {SMART_CONFIG_CMD , 0xe1}, //Gamma setting ( positive) ++ {SMART_CONFIG_PRM , 0x00}, ++ {SMART_CONFIG_PRM , 0x05}, ++ {SMART_CONFIG_PRM , 0x09}, ++ {SMART_CONFIG_PRM , 0x04}, ++ {SMART_CONFIG_PRM , 0x02}, ++ {SMART_CONFIG_PRM , 0x0b}, ++ {SMART_CONFIG_PRM , 0x0a}, ++ {SMART_CONFIG_PRM , 0x09}, ++ {SMART_CONFIG_PRM , 0x05}, ++ {SMART_CONFIG_PRM , 0x08}, ++ {SMART_CONFIG_PRM , 0x10}, ++ {SMART_CONFIG_PRM , 0x05}, ++ {SMART_CONFIG_PRM , 0x06}, ++ {SMART_CONFIG_PRM , 0x11}, ++ {SMART_CONFIG_PRM , 0x09}, ++ {SMART_CONFIG_PRM , 0x01}, ++ ++ {SMART_CONFIG_CMD , 0x00}, ++ {SMART_CONFIG_PRM , 0x00}, ++ {SMART_CONFIG_CMD , 0xe2}, //Gamma setting ( negative) ++ {SMART_CONFIG_PRM , 0x00}, ++ {SMART_CONFIG_PRM , 0x05}, ++ {SMART_CONFIG_PRM , 0x09}, ++ {SMART_CONFIG_PRM , 0x04}, ++ {SMART_CONFIG_PRM , 0x02}, ++ {SMART_CONFIG_PRM , 0x0b}, ++ {SMART_CONFIG_PRM , 0x0a}, ++ {SMART_CONFIG_PRM , 0x09}, ++ {SMART_CONFIG_PRM , 0x05}, ++ {SMART_CONFIG_PRM , 0x08}, ++ {SMART_CONFIG_PRM , 0x10}, ++ {SMART_CONFIG_PRM , 0x05}, ++ {SMART_CONFIG_PRM , 0x06}, ++ {SMART_CONFIG_PRM , 0x11}, ++ {SMART_CONFIG_PRM , 0x09}, ++ {SMART_CONFIG_PRM , 0x01}, ++ ++ {SMART_CONFIG_CMD , 0x00}, ++ {SMART_CONFIG_PRM , 0x00}, ++ {SMART_CONFIG_CMD , 0x00}, //End Gamma setting ++ {SMART_CONFIG_PRM , 0x00}, ++ ++ {SMART_CONFIG_CMD , 0x00}, ++ {SMART_CONFIG_PRM , 0x80}, ++ {SMART_CONFIG_CMD , 0xff}, //Orise mode command Disable ++ {SMART_CONFIG_PRM , 0x00}, ++ {SMART_CONFIG_PRM , 0x00}, ++ ++ {SMART_CONFIG_CMD , 0x00}, ++ {SMART_CONFIG_PRM , 0x00}, ++ ++ {SMART_CONFIG_CMD , 0xff}, //Command 2 Disable ++ {SMART_CONFIG_PRM , 0xff}, ++ {SMART_CONFIG_PRM , 0xff}, ++ {SMART_CONFIG_PRM , 0xff}, ++ ++ //{SMART_CONFIG_CMD , 0x35}, //TE ON ++ //{SMART_CONFIG_DATA , 0x00}, ++ ++ {SMART_CONFIG_CMD , 0x36}, //set X Y refresh direction ++ {SMART_CONFIG_PRM , 0x00}, ++ ++ {SMART_CONFIG_CMD , 0x3A}, //16-bit/pixe 565 ++ {SMART_CONFIG_PRM , 0x05}, ++ ++ {SMART_CONFIG_CMD , 0x2A}, //Frame rate control 320 ++ {SMART_CONFIG_PRM , 0x00}, ++ {SMART_CONFIG_PRM , 0x00}, ++ {SMART_CONFIG_PRM , 0x01}, ++ {SMART_CONFIG_PRM , 0x3F}, ++ ++ {SMART_CONFIG_CMD , 0x2B}, //Display function control 480 ++ {SMART_CONFIG_PRM , 0x00}, ++ {SMART_CONFIG_PRM , 0x00}, ++ {SMART_CONFIG_PRM , 0x01}, ++ {SMART_CONFIG_PRM , 0xDF}, ++ ++ {SMART_CONFIG_CMD , 0x11}, ++ {SMART_CONFIG_UDELAY , 12000}, ++ {SMART_CONFIG_CMD , 0x29}, //display on ++ ++ {SMART_CONFIG_CMD , 0x2c}, ++ ++}; ++ ++static struct fb_videomode panel_modes[] = { ++ [0] = { ++ .name = "320x480", ++ .refresh = 60, ++ .xres = 320, ++ .yres = 480, ++ .pixclock = KHZ2PICOS(18432), ++ .left_margin = 0, ++ .right_margin = 0, ++ .upper_margin = 0, ++ .lower_margin = 0, ++ .hsync_len = 0, ++ .vsync_len = 0, ++ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, ++ .vmode = FB_VMODE_NONINTERLACED, ++ .flag = 0, ++ }, ++}; ++ ++struct smart_config kd035hvfbd037_cfg = { ++ .rdy_anti_jit = 0, ++ .te_anti_jit = 1, ++ .te_md = 0, ++ .te_switch = 0, ++ .rdy_switch = 0, ++ .cs_en = 0, ++ .cs_dp = 0, ++ .rdy_dp = 1, ++ .dc_md = 0, ++ .wr_md = 1, ++ .te_dp = 1, ++ .smart_type = SMART_LCD_TYPE_8080, ++ .pix_fmt = SMART_LCD_FORMAT_565, ++ .dwidth = SMART_LCD_DWIDTH_8_BIT, ++ .cwidth = SMART_LCD_CWIDTH_8_BIT, ++ .bus_width = 8, ++ ++ .write_gram_cmd = 0x2c, ++ .data_table = kd035hvfbd037_data_table, ++ .length_data_table = ARRAY_SIZE(kd035hvfbd037_data_table), ++}; ++ ++struct lcd_panel lcd_panel = { ++ .name = "kd035hvfbd037", ++ .num_modes = ARRAY_SIZE(panel_modes), ++ .modes = panel_modes, ++ .lcd_type = LCD_TYPE_SLCD, ++ .bpp = 32, ++ .width = 320, ++ .height = 480, ++ ++ .smart_config = &kd035hvfbd037_cfg, ++ ++ .dither_enable = 0, ++ .dither.dither_red = 0, ++ .dither.dither_green = 0, ++ .dither.dither_blue = 0, ++}; ++ ++/* SGM3146 supports 16 brightness step */ ++#define MAX_BRIGHTNESS_STEP 16 ++/* System support 256 brightness step */ ++#define CONVERT_FACTOR (256/MAX_BRIGHTNESS_STEP) ++ ++static int panel_update_status(struct backlight_device *bd) ++{ ++ struct panel_dev *panel = dev_get_drvdata(&bd->dev); ++ int brightness = bd->props.brightness; ++ unsigned int i; ++ int pulse_num = MAX_BRIGHTNESS_STEP - brightness / CONVERT_FACTOR - 1; ++ ++ if (bd->props.fb_blank == FB_BLANK_POWERDOWN) { ++ return 0; ++ } ++ ++ if (bd->props.state & BL_CORE_SUSPENDED) ++ brightness = 0; ++ ++ if (brightness) { ++ gpio_direction_output(panel->pwm.gpio,0); ++ udelay(5000); ++ gpio_direction_output(panel->pwm.gpio,1); ++ udelay(100); ++ ++ for (i = pulse_num; i > 0; i--) { ++ gpio_direction_output(panel->pwm.gpio,0); ++ udelay(1); ++ gpio_direction_output(panel->pwm.gpio,1); ++ udelay(3); ++ } ++ } else ++ gpio_direction_output(panel->pwm.gpio, 0); ++ ++ return 0; ++} ++ ++static struct backlight_ops panel_backlight_ops = { ++ .options = BL_CORE_SUSPENDRESUME, ++ .update_status = panel_update_status, ++}; ++ ++static void panel_power_reset(struct board_gpio *rst) ++{ ++ gpio_direction_output(rst->gpio, 0); ++ mdelay(20); ++ gpio_direction_output(rst->gpio, 1); ++ mdelay(10); ++} ++ ++#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL) ++static int panel_set_power(struct lcd_device *lcd, int power) ++{ ++ struct panel_dev *panel = lcd_get_data(lcd); ++ struct board_gpio *cs = &panel->cs; ++ struct board_gpio *rst = &panel->rst; ++ struct board_gpio *vdd_en = &panel->vdd_en; ++ if(POWER_IS_ON(power) && !POWER_IS_ON(panel->power)) { ++ gpio_direction_output(vdd_en->gpio, 1); ++ gpio_direction_output(rst->gpio, 1); ++ gpio_direction_output(cs->gpio, 1); ++ mdelay(5); ++ panel_power_reset(rst); ++ gpio_direction_output(cs->gpio, 0); ++ } ++ if(!POWER_IS_ON(power) && POWER_IS_ON(panel->power)) { ++ gpio_direction_output(cs->gpio, 0); ++ gpio_direction_output(rst->gpio, 0); ++ gpio_direction_output(vdd_en->gpio, 0); ++ } ++ ++ panel->power = power; ++ return 0; ++} ++ ++static int panel_get_power(struct lcd_device *lcd) ++{ ++ struct panel_dev *panel = lcd_get_data(lcd); ++ ++ return panel->power; ++} ++ ++static struct lcd_ops panel_lcd_ops = { ++ .early_set_power = panel_set_power, ++ .set_power = panel_set_power, ++ .get_power = panel_get_power, ++}; ++ ++static int of_panel_parse(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ struct device_node *np = dev->of_node; ++ enum of_gpio_flags flags; ++ int ret = 0; ++ ++ panel->cs.gpio = of_get_named_gpio_flags(np, "ingenic,cs-gpio", 0, &flags); ++ if(gpio_is_valid(panel->cs.gpio)) { ++ panel->cs.active_level = OF_GPIO_ACTIVE_LOW ? 0 : 1; ++ ret = gpio_request_one(panel->cs.gpio, GPIOF_DIR_OUT, "cs"); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request cs pin!\n"); ++ return ret; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio cs.gpio: %d\n", panel->cs.gpio); ++ } ++ ++ panel->rst.gpio = of_get_named_gpio_flags(np, "ingenic,rst-gpio", 0, &flags); ++ if(gpio_is_valid(panel->rst.gpio)) { ++ panel->rst.active_level = OF_GPIO_ACTIVE_LOW ? 0 : 1; ++ ret = gpio_request_one(panel->rst.gpio, GPIOF_DIR_OUT, "rst"); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request rst pin!\n"); ++ goto err_request_rst; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio rst.gpio: %d\n", panel->rst.gpio); ++ } ++ ++ panel->vdd_en.gpio = of_get_named_gpio_flags(np, "ingenic,vdd-en-gpio", 0, &flags); ++ if(gpio_is_valid(panel->vdd_en.gpio)) { ++ panel->vdd_en.active_level = OF_GPIO_ACTIVE_LOW ? 0 : 1; ++ ret = gpio_request_one(panel->vdd_en.gpio, GPIOF_DIR_OUT, "vdd_en"); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request vdd_en pin!\n"); ++ goto err_request_rst; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio vdd_en.gpio: %d\n", panel->vdd_en.gpio); ++ } ++ panel->pwm.gpio = of_get_named_gpio_flags(np, "ingenic,pwm-gpio", 0, &flags); ++ if(gpio_is_valid(panel->pwm.gpio)) { ++ panel->pwm.active_level = OF_GPIO_ACTIVE_LOW ? 0 : 1; ++ ret = gpio_request_one(panel->pwm.gpio, GPIOF_DIR_OUT, "pwm"); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request pwm pin!\n"); ++ goto err_request_rst; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio pwm.gpio: %d\n", panel->pwm.gpio); ++ } ++ ++ return 0; ++err_request_rst: ++ gpio_free(panel->cs.gpio); ++ return ret; ++} ++/** ++* @panel_probe ++* ++* 1. Register to ingenicfb. ++* 2. Register to lcd. ++* 3. Register to backlight if possible. ++* ++* @pdev ++* ++* @Return - ++*/ ++static int panel_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ struct panel_dev *panel; ++ struct backlight_properties props; ++ ++ memset(&props, 0, sizeof(props)); ++ panel = kzalloc(sizeof(struct panel_dev), GFP_KERNEL); ++ if(panel == NULL) { ++ dev_err(&pdev->dev, "Faile to alloc memory!"); ++ return -ENOMEM; ++ } ++ panel->dev = &pdev->dev; ++ dev_set_drvdata(&pdev->dev, panel); ++ ++ ret = of_panel_parse(&pdev->dev); ++ if(ret < 0) { ++ goto err_of_parse; ++ } ++ ++ panel->lcd = lcd_device_register("panel_lcd", &pdev->dev, panel, &panel_lcd_ops); ++ if(IS_ERR_OR_NULL(panel->lcd)) { ++ dev_err(&pdev->dev, "Error register lcd!\n"); ++ ret = -EINVAL; ++ goto err_of_parse; ++ } ++ ++ /* TODO: should this power status sync from uboot */ ++ panel->power = FB_BLANK_POWERDOWN; ++ panel_set_power(panel->lcd, FB_BLANK_UNBLANK); ++ ++ props.type = BACKLIGHT_RAW; ++ props.max_brightness = 255; ++ panel->backlight = backlight_device_register("pwm-backlight.0", ++ &pdev->dev, panel, ++ &panel_backlight_ops, ++ &props); ++ if (IS_ERR_OR_NULL(panel->backlight)) { ++ dev_err(panel->dev, "failed to register 'pwm-backlight.0'.\n"); ++ goto err_lcd_register; ++ } ++ panel->backlight->props.brightness = props.max_brightness; ++ backlight_update_status(panel->backlight); ++ ++ ret = ingenicfb_register_panel(&lcd_panel); ++ if(ret < 0) { ++ dev_err(&pdev->dev, "Failed to register lcd panel!\n"); ++ goto err_lcd_register; ++ } ++ ++ return 0; ++ ++err_lcd_register: ++ lcd_device_unregister(panel->lcd); ++err_of_parse: ++ kfree(panel); ++ return ret; ++} ++ ++static int panel_remove(struct platform_device *pdev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(&pdev->dev); ++ ++ panel_set_power(panel->lcd, FB_BLANK_POWERDOWN); ++ return 0; ++} ++ ++ ++#ifdef CONFIG_PM ++static int panel_suspend(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ ++ panel_set_power(panel->lcd, FB_BLANK_POWERDOWN); ++ return 0; ++} ++ ++static int panel_resume(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ ++ panel_set_power(panel->lcd, FB_BLANK_UNBLANK); ++ return 0; ++} ++ ++static const struct dev_pm_ops panel_pm_ops = { ++ .suspend = panel_suspend, ++ .resume = panel_resume, ++}; ++#endif ++static const struct of_device_id panel_of_match[] = { ++ { .compatible = "ingenic,kd035hvfbd037", }, ++ {}, ++}; ++ ++static struct platform_driver panel_driver = { ++ .probe = panel_probe, ++ .remove = panel_remove, ++ .driver = { ++ .name = "kd035hvfbd037", ++ .of_match_table = panel_of_match, ++#ifdef CONFIG_PM ++ .pm = &panel_pm_ops, ++#endif ++ }, ++}; ++ ++module_platform_driver(panel_driver); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v11_displays_panel-kd035hvfmd057.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v11_displays_panel-kd035hvfmd057.c.patch new file mode 100644 index 00000000..87395e56 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v11_displays_panel-kd035hvfmd057.c.patch @@ -0,0 +1,530 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v11/displays/panel-kd035hvfmd057.c b/drivers/video/fbdev/ingenic/fb_v11/displays/panel-kd035hvfmd057.c +--- a/drivers/video/fbdev/ingenic/fb_v11/displays/panel-kd035hvfmd057.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v11/displays/panel-kd035hvfmd057.c 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,526 @@ ++/* ++ * driver/video/fbdev/ingenic/x2000/displays/kd035hvfmd057.c ++ * ++ * Copyright (C) 2016 Ingenic Semiconductor Inc. ++ * ++ * Author:clwang ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../ingenicfb.h" ++ ++struct board_gpio { ++ short gpio; ++ short active_level; ++}; ++ ++struct panel_dev { ++ /* ingenic frame buffer */ ++ struct device *dev; ++ struct lcd_panel *panel; ++ ++ /* common lcd framework */ ++ struct lcd_device *lcd; ++ struct backlight_device *backlight; ++ int power; ++ ++ struct regulator *vcc; ++ struct board_gpio cs; ++ struct board_gpio rst; ++ struct board_gpio ssi_clk; ++ struct board_gpio ssi_dt; ++ struct board_gpio pwm; ++}; ++ ++#define SSI_CS(panel, n) gpio_direction_output(panel->cs.gpio, n) ++#define SSI_CLK(panel, n) gpio_direction_output(panel->ssi_clk.gpio, n) ++#define SSI_DT(panel, n) gpio_direction_output(panel->ssi_dt.gpio, n) ++ ++static void lcd_send_cmd(struct panel_dev *panel, uint8_t cmd) { ++ ++ int i = 8; ++ SSI_CS(panel, 0); ++ SSI_CLK(panel, 0); ++ SSI_DT(panel, 0); ++ SSI_CLK(panel, 1); ++ while(i--) { ++ SSI_CLK(panel, 0); ++ SSI_DT(panel, !!(cmd & 0x80)); ++ SSI_CLK(panel, 1); ++ cmd = cmd << 1; ++ } ++ SSI_CLK(panel, 0); ++ SSI_CS(panel, 1); ++} ++ ++static void lcd_send_param(struct panel_dev *panel, uint8_t param) { ++ ++ int i = 8; ++ SSI_CS(panel, 0); ++ SSI_CLK(panel, 0); ++ SSI_DT(panel, 1); ++ SSI_CLK(panel,1); ++ while(i--) { ++ SSI_CLK(panel, 0); ++ SSI_DT(panel, !!(param & 0x80)); ++ SSI_CLK(panel, 1); ++ param = param << 1; ++ } ++ SSI_CLK(panel, 0); ++ SSI_CS(panel, 1); ++ ++} ++ ++static void panel_init(struct panel_dev *panel) { ++#define LCD_SEND_CMD(n) lcd_send_cmd(panel, n) ++#define LCD_SEND_PARAM(n) lcd_send_param(panel, n) ++ LCD_SEND_CMD(0xC0); ++ LCD_SEND_PARAM(0x17); ++ LCD_SEND_PARAM(0x17); ++ ++ LCD_SEND_CMD(0xC1); ++ LCD_SEND_PARAM(0x44); ++ ++ LCD_SEND_CMD(0xC5); ++ LCD_SEND_PARAM(0x00); ++ LCD_SEND_PARAM(0x3A); ++ LCD_SEND_PARAM(0x80); ++ ++ LCD_SEND_CMD(0x36); ++ LCD_SEND_PARAM(0x48); ++ ++ LCD_SEND_CMD(0x3A); //Interface Mode Control ++ LCD_SEND_PARAM(0x60); ++ ++ LCD_SEND_CMD(0xB1); //Frame rate 70HZ ++ LCD_SEND_PARAM(0xA0); ++ ++ LCD_SEND_CMD(0xB4); ++ LCD_SEND_PARAM(0x02); ++ ++ LCD_SEND_CMD(0xB7); ++ LCD_SEND_PARAM(0xC6); ++ ++ LCD_SEND_CMD(0xE9); ++ LCD_SEND_PARAM(0x00); ++ ++ LCD_SEND_CMD(0XF7); ++ LCD_SEND_PARAM(0xA9); ++ LCD_SEND_PARAM(0x51); ++ LCD_SEND_PARAM(0x2C); ++ LCD_SEND_PARAM(0x82); ++ ++ LCD_SEND_CMD(0xE0); ++ LCD_SEND_PARAM(0x01); ++ LCD_SEND_PARAM(0x13); ++ LCD_SEND_PARAM(0x1E); ++ LCD_SEND_PARAM(0x00); ++ LCD_SEND_PARAM(0x0D); ++ LCD_SEND_PARAM(0x03); ++ LCD_SEND_PARAM(0x3D); ++ LCD_SEND_PARAM(0x55); ++ LCD_SEND_PARAM(0x4F); ++ LCD_SEND_PARAM(0x06); ++ LCD_SEND_PARAM(0x10); ++ LCD_SEND_PARAM(0x0B); ++ LCD_SEND_PARAM(0x2C); ++ LCD_SEND_PARAM(0x32); ++ LCD_SEND_PARAM(0x0F); ++ ++ LCD_SEND_CMD(0xE1); ++ LCD_SEND_PARAM(0x08); ++ LCD_SEND_PARAM(0x10); ++ LCD_SEND_PARAM(0x15); ++ LCD_SEND_PARAM(0x03); ++ LCD_SEND_PARAM(0x0E); ++ LCD_SEND_PARAM(0x03); ++ LCD_SEND_PARAM(0x32); ++ LCD_SEND_PARAM(0x34); ++ LCD_SEND_PARAM(0x44); ++ LCD_SEND_PARAM(0x07); ++ LCD_SEND_PARAM(0x10); ++ LCD_SEND_PARAM(0x0E); ++ LCD_SEND_PARAM(0x23); ++ LCD_SEND_PARAM(0x2E); ++ LCD_SEND_PARAM(0x0F); ++ ++ LCD_SEND_CMD(0xB6); ++ LCD_SEND_PARAM(0xB0); //set rgb bypass mode ++ LCD_SEND_PARAM(0x02); //GS,SS ++ LCD_SEND_PARAM(0x3B); ++ ++ /****************************************/ ++ LCD_SEND_CMD(0XB0); //Interface Mode Control ++ LCD_SEND_PARAM(0x02); ++ /**************************************************/ ++ LCD_SEND_CMD(0x2A); //Frame rate control ++ LCD_SEND_PARAM(0x00); ++ LCD_SEND_PARAM(0x00); ++ LCD_SEND_PARAM(0x01); ++ LCD_SEND_PARAM(0x3F); ++ ++ LCD_SEND_CMD(0x2B); //Display function control ++ LCD_SEND_PARAM(0x00); ++ LCD_SEND_PARAM(0x00); ++ LCD_SEND_PARAM(0x01); ++ LCD_SEND_PARAM(0xDF); ++ ++ LCD_SEND_CMD(0x21); ++ ++ LCD_SEND_CMD(0x11); ++ mdelay(20); ++ LCD_SEND_CMD(0x29); //display on ++ LCD_SEND_CMD(0x2c); ++} ++ ++static void panel_enable(struct lcd_panel *panel) ++{ ++} ++ ++static void panel_disable(struct lcd_panel *panel) ++{ ++} ++ ++static struct lcd_panel_ops panel_ops = { ++ .enable = (void*)panel_enable, ++ .disable = (void*)panel_disable, ++}; ++ ++static struct fb_videomode panel_modes[] = { ++ [0] = { ++ .name = "320x480", ++ .refresh = 60, ++ .xres = 320, ++ .yres = 480, ++ .pixclock = KHZ2PICOS(33264), ++ .left_margin = 3, ++ .right_margin = 60, ++ .upper_margin = 2, ++ .lower_margin = 2, ++ .hsync_len = 20, ++ .vsync_len = 2, ++ .sync = ~FB_SYNC_HOR_HIGH_ACT & ~FB_SYNC_VERT_HIGH_ACT, ++ .vmode = FB_VMODE_NONINTERLACED, ++ .flag = 0, ++ }, ++}; ++ ++static struct tft_config kd035hvfmd057_cfg = { ++ .pix_clk_inv = 0, ++ .de_dl = 0, ++ .sync_dl = 0, ++ .color_even = TFT_LCD_COLOR_EVEN_RGB, ++ .color_odd = TFT_LCD_COLOR_ODD_RGB, ++ .mode = TFT_LCD_MODE_PARALLEL_666, ++}; ++ ++struct lcd_panel lcd_panel = { ++ .name = "kd035hvfmd057", ++ .num_modes = ARRAY_SIZE(panel_modes), ++ .modes = panel_modes, ++ .bpp = 24, ++ .width = 320, ++ .height = 480, ++ ++ .lcd_type = LCD_TYPE_TFT, ++ ++ .tft_config = &kd035hvfmd057_cfg, ++ ++ .dither_enable = 0, ++ .dither.dither_red = 0, ++ .dither.dither_green = 0, ++ .dither.dither_blue = 0, ++ ++ .ops = &panel_ops, ++}; ++ ++ ++/* SGM3146 supports 16 brightness step */ ++#define MAX_BRIGHTNESS_STEP 16 ++/* System support 256 brightness step */ ++#define CONVERT_FACTOR (256/MAX_BRIGHTNESS_STEP) ++ ++static int panel_update_status(struct backlight_device *bd) ++{ ++ struct panel_dev *panel = dev_get_drvdata(&bd->dev); ++ int brightness = bd->props.brightness; ++ unsigned int i; ++ int pulse_num = MAX_BRIGHTNESS_STEP - brightness / CONVERT_FACTOR - 1; ++ ++ if (bd->props.fb_blank == FB_BLANK_POWERDOWN) { ++ return 0; ++ } ++ ++ if (bd->props.state & BL_CORE_SUSPENDED) ++ brightness = 0; ++ ++ if (brightness) { ++ gpio_direction_output(panel->pwm.gpio,0); ++ udelay(5000); ++ gpio_direction_output(panel->pwm.gpio,1); ++ udelay(100); ++ ++ for (i = pulse_num; i > 0; i--) { ++ gpio_direction_output(panel->pwm.gpio,0); ++ udelay(1); ++ gpio_direction_output(panel->pwm.gpio,1); ++ udelay(3); ++ } ++ } else ++ gpio_direction_output(panel->pwm.gpio, 0); ++ ++ return 0; ++} ++ ++static struct backlight_ops panel_backlight_ops = { ++ .options = BL_CORE_SUSPENDRESUME, ++ .update_status = panel_update_status, ++}; ++ ++static void panel_power_reset(struct board_gpio *rst) ++{ ++ gpio_direction_output(rst->gpio, 0); ++ mdelay(10); ++ gpio_direction_output(rst->gpio, 1); ++ mdelay(20); ++} ++ ++#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL) ++static int panel_set_power(struct lcd_device *lcd, int power) ++{ ++ struct panel_dev *panel = lcd_get_data(lcd); ++ struct board_gpio *cs = &panel->cs; ++ struct board_gpio *rst = &panel->rst; ++ if(POWER_IS_ON(power) && !POWER_IS_ON(panel->power)) { ++ gpio_direction_output(rst->gpio, 1); ++ gpio_direction_output(cs->gpio, 1); ++ panel_power_reset(rst); ++ gpio_direction_output(cs->gpio, 0); ++ panel_init(panel); ++ } ++ if(!POWER_IS_ON(power) && POWER_IS_ON(panel->power)) { ++ gpio_direction_output(cs->gpio, 1); ++ gpio_direction_output(rst->gpio, 0); ++ } ++ ++ panel->power = power; ++ return 0; ++} ++ ++static int panel_get_power(struct lcd_device *lcd) ++{ ++ struct panel_dev *panel = lcd_get_data(lcd); ++ ++ return panel->power; ++} ++ ++/** ++* @ pannel_kd035hvfmd057_lcd_ops, register to kernel common backlight/lcd.c framworks. ++*/ ++static struct lcd_ops panel_lcd_ops = { ++ .early_set_power = panel_set_power, ++ .set_power = panel_set_power, ++ .get_power = panel_get_power, ++}; ++ ++static int of_panel_parse(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ struct device_node *np = dev->of_node; ++ enum of_gpio_flags flags; ++ int ret = 0; ++ ++ panel->cs.gpio = of_get_named_gpio_flags(np, "ingenic,cs-gpio", 0, &flags); ++ if(gpio_is_valid(panel->cs.gpio)) { ++ panel->cs.active_level = OF_GPIO_ACTIVE_LOW ? 0 : 1; ++ ret = gpio_request_one(panel->cs.gpio, GPIOF_DIR_OUT, "cs"); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request cs pin!\n"); ++ return ret; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio cs.gpio: %d\n", panel->cs.gpio); ++ } ++ ++ panel->rst.gpio = of_get_named_gpio_flags(np, "ingenic,rst-gpio", 0, &flags); ++ if(gpio_is_valid(panel->rst.gpio)) { ++ panel->rst.active_level = OF_GPIO_ACTIVE_LOW ? 0 : 1; ++ ret = gpio_request_one(panel->rst.gpio, GPIOF_DIR_OUT, "rst"); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request rst pin!\n"); ++ goto err_request_rst; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio rst.gpio: %d\n", panel->rst.gpio); ++ } ++ panel->ssi_clk.gpio = of_get_named_gpio_flags(np, "ingenic,ssi-clk-gpio", 0, &flags); ++ if(gpio_is_valid(panel->ssi_clk.gpio)) { ++ panel->ssi_clk.active_level = OF_GPIO_ACTIVE_LOW ? 0 : 1; ++ ret = gpio_request_one(panel->ssi_clk.gpio, GPIOF_DIR_OUT, "ssi_clk"); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request ssi_clk pin!\n"); ++ goto err_request_rst; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio ssi_clk.gpio: %d\n", panel->ssi_clk.gpio); ++ } ++ panel->ssi_dt.gpio = of_get_named_gpio_flags(np, "ingenic,ssi-dt-gpio", 0, &flags); ++ if(gpio_is_valid(panel->ssi_dt.gpio)) { ++ panel->ssi_dt.active_level = OF_GPIO_ACTIVE_LOW ? 0 : 1; ++ ret = gpio_request_one(panel->ssi_dt.gpio, GPIOF_DIR_OUT, "ssi_dt"); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request ssi_dt pin!\n"); ++ goto err_request_rst; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio ssi_dt.gpio: %d\n", panel->ssi_dt.gpio); ++ } ++ panel->pwm.gpio = of_get_named_gpio_flags(np, "ingenic,pwm-gpio", 0, &flags); ++ if(gpio_is_valid(panel->pwm.gpio)) { ++ panel->pwm.active_level = OF_GPIO_ACTIVE_LOW ? 0 : 1; ++ ret = gpio_request_one(panel->pwm.gpio, GPIOF_DIR_OUT, "pwm"); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request pwm pin!\n"); ++ goto err_request_rst; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio pwm.gpio: %d\n", panel->pwm.gpio); ++ } ++ ++ return 0; ++err_request_rst: ++ gpio_free(panel->cs.gpio); ++ return ret; ++} ++/** ++* @panel_probe ++* ++* 1. Register to ingenicfb. ++* 2. Register to lcd. ++* 3. Register to backlight if possible. ++* ++* @pdev ++* ++* @Return - ++*/ ++static int panel_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ struct panel_dev *panel; ++ struct backlight_properties props; ++ ++ memset(&props, 0, sizeof(props)); ++ panel = kzalloc(sizeof(struct panel_dev), GFP_KERNEL); ++ if(panel == NULL) { ++ dev_err(&pdev->dev, "Faile to alloc memory!"); ++ return -ENOMEM; ++ } ++ panel->dev = &pdev->dev; ++ dev_set_drvdata(&pdev->dev, panel); ++ ++ ret = of_panel_parse(&pdev->dev); ++ if(ret < 0) { ++ goto err_of_parse; ++ } ++ ++ panel->lcd = lcd_device_register("panel_lcd", &pdev->dev, panel, &panel_lcd_ops); ++ if(IS_ERR_OR_NULL(panel->lcd)) { ++ dev_err(&pdev->dev, "Error register lcd!\n"); ++ ret = -EINVAL; ++ goto err_of_parse; ++ } ++ ++ /* TODO: should this power status sync from uboot */ ++ panel->power = FB_BLANK_POWERDOWN; ++ panel_set_power(panel->lcd, FB_BLANK_UNBLANK); ++ ++ props.type = BACKLIGHT_RAW; ++ props.max_brightness = 255; ++ panel->backlight = backlight_device_register("pwm-backlight.0", ++ &pdev->dev, panel, ++ &panel_backlight_ops, ++ &props); ++ if (IS_ERR_OR_NULL(panel->backlight)) { ++ dev_err(panel->dev, "failed to register 'pwm-backlight.0'.\n"); ++ goto err_lcd_register; ++ } ++ panel->backlight->props.brightness = props.max_brightness; ++ backlight_update_status(panel->backlight); ++ ++ ret = ingenicfb_register_panel(&lcd_panel); ++ if(ret < 0) { ++ dev_err(&pdev->dev, "Failed to register lcd panel!\n"); ++ goto err_lcd_register; ++ } ++ ++ return 0; ++ ++err_lcd_register: ++ lcd_device_unregister(panel->lcd); ++err_of_parse: ++ kfree(panel); ++ return ret; ++} ++ ++static int panel_remove(struct platform_device *pdev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(&pdev->dev); ++ ++ panel_set_power(panel->lcd, FB_BLANK_POWERDOWN); ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int panel_suspend(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ ++ panel_set_power(panel->lcd, FB_BLANK_POWERDOWN); ++ return 0; ++} ++ ++static int panel_resume(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ ++ panel_set_power(panel->lcd, FB_BLANK_UNBLANK); ++ return 0; ++} ++ ++static const struct dev_pm_ops panel_pm_ops = { ++ .suspend = panel_suspend, ++ .resume = panel_resume, ++}; ++#endif ++static const struct of_device_id panel_of_match[] = { ++ { .compatible = "ingenic,kd035hvfmd057", }, ++ {}, ++}; ++ ++static struct platform_driver panel_driver = { ++ .probe = panel_probe, ++ .remove = panel_remove, ++ .driver = { ++ .name = "kd035hvfmd057", ++ .of_match_table = panel_of_match, ++#ifdef CONFIG_PM ++ .pm = &panel_pm_ops, ++#endif ++ }, ++}; ++ ++module_platform_driver(panel_driver); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v11_dpu_reg.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v11_dpu_reg.h.patch new file mode 100644 index 00000000..0a7da261 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v11_dpu_reg.h.patch @@ -0,0 +1,819 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v11/dpu_reg.h b/drivers/video/fbdev/ingenic/fb_v11/dpu_reg.h +--- a/drivers/video/fbdev/ingenic/fb_v11/dpu_reg.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v11/dpu_reg.h 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,815 @@ ++/* ++ * drivers/video/jz_fb_v14/dpu_reg.h ++ * ++ * Copyright (C) 2016 Ingenic Semiconductor Inc. ++ * ++ * Author:clwang ++ * ++ * 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. ++ */ ++ ++#ifndef _DPU_REG_H_ ++#define _DPU_REG_H_ ++ ++#define DPU_BASE 0xb3050000 ++ ++/*------------------------------------------------------------------------------- ++ * DPU Register Offset ++ * -----------------------------------------------------------------------------*/ ++ ++ ++/* RW 32 0x0000_0000 frame descriptor's address*/ ++#define DC_FRM_CFG_ADDR (0x0000) ++/* -W 32 0x0000_0000 frame descriptor's control*/ ++#define DC_FRM_CFG_CTRL (0x0004) ++/* RW 32 0x0000_0000 DC control*/ ++#define DC_CTRL (0x2000) ++/* RW 32 0x0000_0000 DC status*/ ++#define DC_ST (0x2004) ++/* -W 32 0x0000_0000 DC clear status*/ ++#define DC_CLR_ST (0x2008) ++/* RW 32 0x0000_0000 DC interrupt mask*/ ++#define DC_INTC (0x200c) ++/* R- 32 0x0000_0000 For debug*/ ++#define DC_INT_FLAG (0x2010) ++/* RW 32 0x0000_0000 Common configure register*/ ++#define DC_COM_CONFIG (0x2014) ++/* RW 32 0x0181-4060 Priority config*/ ++#define DC_PCFG_RD_CTRL (0x2018) ++/* RW 32 0x0181-4060 OFIFO Priority level threshold config*/ ++#define DC_OFIFO_PCFG (0x2020) ++/* R- 32 0x0000_0000 For debug*/ ++#define DC_FRM_DES (0x2100) ++/* R- 32 0x0000_0000 For debug*/ ++#define DC_LAY0_DES (0x2104) ++/* R- 32 0x0000_0000 For debug*/ ++#define DC_LAY1_DES (0x2108) ++/* R- 32 0x0000_0000 For debug*/ ++#define DC_LAY2_DES (0x210c) ++/* R- 32 0x0000_0000 For debug*/ ++#define DC_LAY3_DES (0x2110) ++/* R- 32 0x0000_0000 For debug*/ ++#define DC_RDMA_DES (0x2114) ++/* R- 32 0x0000_0000 frame descriptor's current site*/ ++#define DC_FRM_CHAIN_SITE (0x2200) ++/* R- 32 0x0000_0000 rdma descriptor's current site*/ ++#define DC_RDMA_CHAIN_SITE (0x2204) ++/* R- 32 0x0000_0000 layer0's current site*/ ++#define DC_LAY0_SITE (0x3100) ++/* R- 32 0x0000_0000 layer1's current site*/ ++#define DC_LAY1_SITE (0x3104) ++/* R- 32 0x0000_0000 layer2's current site*/ ++#define DC_LAY2_SITE (0x3108) ++/* R- 32 0x0000_0000 layer3's current site*/ ++#define DC_LAY3_SITE (0x310c) ++/* R- 32 0x0000_0000 rdma's current site*/ ++#define DC_RDMA_SITE (0x3110) ++/* R- 32 0x0000_0000 wdma's current site*/ ++#define DC_WDMA_SITE (0x221c) ++/* RW 32 0x0000_0000 TLB Global Control*/ ++#define DC_TLB_GLBC (0x3000) ++/* RW 32 0x0000_0000 TLB table entry address*/ ++#define DC_TLB_TLBA (0x3010) ++/* RW 32 0x0000_0000 TLB trigger control*/ ++#define DC_TLB_TLBC (0x3020) ++/* R- 32 0x0000_0000 VPN probe 0*/ ++#define DC_TLB0_VPN (0x3030) ++/* R- 32 0x0000_0000 VPN probe 1*/ ++#define DC_TLB1_VPN (0x3034) ++/* R- 32 0x0000_0000 VPN probe 2*/ ++#define DC_TLB2_VPN (0x3038) ++/* R- 32 0x0000_0000 VPN probe 3*/ ++#define DC_TLB3_VPN (0x303c) ++/* RW 32 0x0000_0000 TLB table entry verification*/ ++#define DC_TLB_TLBV (0x3040) ++/* R- 32 0x0000_0000 TLB status*/ ++#define DC_TLB_STAT (0x3050) ++/* RW 32 0x066204a8 CscMultYRv*/ ++#define DC_CSC_MULT_YRV (0x3200) ++/* RW 32 0x03410190 CscMultGuGv*/ ++#define DC_CSC_MULT_GUGV (0x3204) ++/* RW 32 0x00000812 CscMultBu*/ ++#define DC_CSC_MULT_BU (0x3208) ++/* RW 32 0x00800000 CscSubYUV*/ ++#define DC_CSC_SUB_YUV (0x320c) ++/* RW 32 0x0000_0000 display common configure*/ ++#define DC_DISP_COM (0x8000) ++/* RW 32 0x0000_0000 TFT HSYNC*/ ++#define DC_TFT_HSYNC (0x9000) ++/* RW 32 0x0000_0000 TFT VSYNC*/ ++#define DC_TFT_VSYNC (0x9004) ++/* RW 32 0x0000_0000 TFT HDE*/ ++#define DC_TFT_HDE (0x9008) ++/* RW 32 0x0000_0000 TFT VDE*/ ++#define DC_TFT_VDE (0x900C) ++/* RW 32 0x0000_0000 TFT configure*/ ++#define DC_TFT_CFG (0x9010) ++/* RW 32 0x0000_0000 TFT status*/ ++#define DC_TFT_ST (0x9014) ++/* RW 32 0x0000_0000 SLCD configure*/ ++#define DC_SLCD_CFG (0xA000) ++/* RW 32 0x0000_0000 SLCD WR's duty*/ ++#define DC_SLCD_WR_DUTY (0xA004) ++/* RW 32 0x0000_0000 SLCD timing*/ ++#define DC_SLCD_TIMING (0xA008) ++/* RW 32 0x0000_0000 frame size*/ ++#define DC_SLCD_FRM_SIZE (0xA00C) ++/* RW 32 0x0000_0000 slow time*/ ++#define DC_SLCD_SLOW_TIME (0xA010) ++/* RW 32 0x0000_0000 SLCD command*/ ++#define DC_SLCD_CMD (0xA014) ++/* RW 32 0x0000_0000 SLCD status*/ ++#define DC_SLCD_ST (0xA018) ++ ++ ++/*------------------------------------------------------------------------------- ++ * DPU Registers Bits Field Define ++ * -----------------------------------------------------------------------------*/ ++ ++ ++/* Frame descriptor control(DC_FRM_CFG_CTRL) bit field define */ ++ ++/* Frame descriptor DMA start */ ++#define DC_FRM_START BIT(0) ++ ++/* Control configure(DC_CTRL) bit field define */ ++ ++/* Write 1 to start TFT transfer. */ ++#define DC_TFT_START BIT(6) ++/* Write 1 to start SLCD transfer. */ ++#define DC_SLCD_START BIT(5) ++/* General stop the composer channel. Assure integrity of the current frame */ ++#define DC_GEN_STP_CMP BIT(3) ++/* Reset the counter of FRM_DES, LAYx_DES and RDMA_DES */ ++#define DC_DES_CNT_RST BIT(2) ++/* Quick stop the composer channel. */ ++#define DC_QCK_STP_CMP BIT(0) ++ ++/* Status Register(DC_ST) bit field define */ ++ ++/* Composer cannot meet the writeback frame rate*/ ++#define DC_CMP_W_SLOW BIT(31) ++/* composer end of each frame. */ ++#define DC_CMP_END BIT(23) ++/* One frame display end */ ++#define DC_DISP_END BIT(17) ++/* layer1's block DMA end. */ ++#define DC_BDMA1_END BIT(11) ++/* layer0's block DMA end. */ ++#define DC_BDMA0_END BIT(10) ++/* all layer's block DMA end. */ ++#define DC_BDMA_END BIT(9) ++/* TFT jump into under-run mode. */ ++#define DC_TFT_UNDR BIT(8) ++/* Display channel general stop */ ++#define DC_STOP_DISP_ACK BIT(6) ++/* composer direct output channel is working. */ ++#define DC_FRM_WORKING BIT(4) ++/* one frame start reading. */ ++#define DC_ST_FRM_START BIT(2) ++/* one frame read end. */ ++#define DC_FRM_END BIT(1) ++/* display controller is working. */ ++#define DC_WORKING BIT(0) ++ ++/* Clear status Register(DC_CSR) bit field define */ ++ ++/* Clear CMP_W_SLOW*/ ++#define DC_CLR_CMP_W_SLOW BIT(31) ++/* clear CMP_END */ ++#define DC_CLR_CMP_END BIT(23) ++/* clear DISP_END */ ++#define DC_CLR_DISP_END BIT(17) ++/* clear BDMA1_END */ ++#define DC_CLR_BDMA1_END BIT(11) ++/* clear BDMA0_END */ ++#define DC_CLR_BDMA0_END BIT(10) ++/* clear BDMA_END */ ++#define DC_CLR_BDMA_END BIT(9) ++/* clear TFT_UNDR */ ++#define DC_CLR_TFT_UNDR BIT(8) ++/* clear STOP_DISP_ACK */ ++#define DC_CLR_STOP_DISP_ACK BIT(6) ++/* clear FRM_START. */ ++#define DC_CLR_FRM_START BIT(2) ++/* clear FRM_END */ ++#define DC_CLR_FRM_END BIT(1) ++ ++/* INTC register(DC_INTC) bit field define */ ++ ++/* Mask of CMP_W_SLOW*/ ++#define DC_CWS_MSK BIT(31) ++/* mask of CMP_END */ ++#define DC_EOC_MSK BIT(23) ++/* mask of DISP_END */ ++#define DC_EOD_MSK BIT(17) ++/* mask of BDMA1_END */ ++#define DC_EOB1_MSK BIT(11) ++/* mask of BDMA0_END */ ++#define DC_EOB0_MSK BIT(10) ++/* mask of BDMA_END */ ++#define DC_EOB_MSK BIT(9) ++/* mask of TFT_UNDR */ ++#define DC_UOT_MSK BIT(8) ++/* mask of STOP_DISP_ACK */ ++#define DC_SDA_MSK BIT(6) ++/* mask of FRM_START. */ ++#define DC_SOF_MSK BIT(2) ++/* mask of FRM_END */ ++#define DC_EOF_MSK BIT(1) ++ ++/* DC interrupt flag(DC_INT_FLAG) */ ++ ++/* Interrupt of CMP_W_SLOW*/ ++#define DC_INT_CWS BIT(31) ++/* Interrupt of CMP_END */ ++#define DC_INT_EOC BIT(23) ++/* Interrupt of DISP_END */ ++#define DC_INT_EOD BIT(17) ++/* Interrupt of BDMA1_END */ ++#define DC_INT_EOB1 BIT(11) ++/* Interrupt of BDMA0_END */ ++#define DC_INT_EOB0 BIT(10) ++/* Interrupt of BDMA_END */ ++#define DC_INT_EOB BIT(9) ++/* Interrupt of TFT_UNDR */ ++#define DC_INT_UOT BIT(8) ++/* Interrupt of STOP_DISP_ACK */ ++#define DC_INT_SDA BIT(6) ++/* Interrupt of FRM_START. */ ++#define DC_INT_SOF BIT(2) ++/* Interrupt of FRM_END */ ++#define DC_INT_EOF BIT(1) ++ ++/* Common configure register(DC_COM_CONFIG) bit field define */ ++ ++/* The max length of the block DMA's burst. */ ++#define LAYER1_CLKGATE_EN BIT(17) ++#define LAYER0_CLKGATE_EN BIT(16) ++#define DC_BURST_LEN_BDMA_LBIT (2) ++#define DC_BURST_LEN_BDMA_HBIT (3) ++#define DC_BURST_LEN_BDMA_MASK \ ++ GENMASK(DC_BURST_LEN_BDMA_HBIT, DC_BURST_LEN_BDMA_LBIT) ++#define DC_BURST_LEN_BDMA_4 (0) << DC_BURST_LEN_BDMA_LBIT ++#define DC_BURST_LEN_BDMA_8 (1) << DC_BURST_LEN_BDMA_LBIT ++#define DC_BURST_LEN_BDMA_16 (2) << DC_BURST_LEN_BDMA_LBIT ++#define DC_BURST_LEN_BDMA_32 (3) << DC_BURST_LEN_BDMA_LBIT ++ ++/* keep default value */ ++#define DC_OUT_SEL BIT(1) ++ ++/* PCFG_RD_CTRL register */ ++ ++/* QoS value */ ++#define DC_ARQOS_VAL_LBIT (1) ++#define DC_ARQOS_VAL_HBIT (2) ++#define DC_ARQOS_VAL_MASK \ ++ GENMASK(DC_ARQOS_VAL_HBIT, DC_ARQOS_VAL_LBIT) ++#define DC_ARQOS_VAL_0 (0) << DC_ARQOS_VAL_LBIT ++#define DC_ARQOS_VAL_1 (1) << DC_ARQOS_VAL_LBIT ++#define DC_ARQOS_VAL_2 (2) << DC_ARQOS_VAL_LBIT ++#define DC_ARQOS_VAL_3 (3) << DC_ARQOS_VAL_LBIT ++/* QoS ctrl */ ++#define DC_ARQOS_CTRL BIT(0) ++ ++/* PCFG register(OFIFO's PCFG Register) bit field define */ ++#define DC_PCFG0_LBIT (0) ++#define DC_PCFG0_HBIT (8) ++#define DC_PCFG0_MASK \ ++ GENMASK(DC_PCFG0_HBIT, DC_PCFG0_LBIT) ++ ++#define DC_PCFG1_LBIT (9) ++#define DC_PCFG1_HBIT (17) ++#define DC_PCFG1_MASK \ ++ GENMASK(DC_PCFG1_HBIT, DC_PCFG1_LBIT) ++ ++#define DC_PCFG2_LBIT (18) ++#define DC_PCFG2_HBIT (26) ++#define DC_PCFG2_MASK \ ++ GENMASK(DC_PCFG2_HBIT, DC_PCFG2_LBIT) ++ ++/* CscMultYRv */ ++ ++#define DC_CSC_MULT_Y_LBIT (0) ++#define DC_CSC_MULT_Y_HBIT (10) ++#define DC_CSC_MULT_Y_MASK \ ++ GENMASK(DC_CSC_MULT_Y_HBIT, DC_CSC_MULT_Y_LBIT) ++#define DC_CSC_MULT_Y_MD0 (0x400) << DC_CSC_MULT_Y_LBIT ++#define DC_CSC_MULT_Y_MD1 (0x4a8) << DC_CSC_MULT_Y_LBIT ++#define DC_CSC_MULT_Y_MD2 (0x400) << DC_CSC_MULT_Y_LBIT ++#define DC_CSC_MULT_Y_MD3 (0x47c) << DC_CSC_MULT_Y_LBIT ++ ++#define DC_CSC_MULT_RV_LBIT (16) ++#define DC_CSC_MULT_RV_HBIT (26) ++#define DC_CSC_MULT_RV_MASK \ ++ GENMASK(DC_CSC_MULT_RV_HBIT, DC_CSC_MULT_RV_LBIT) ++#define DC_CSC_MULT_RV_MD0 (0x48f) << DC_CSC_MULT_RV_LBIT ++#define DC_CSC_MULT_RV_MD1 (0x662) << DC_CSC_MULT_RV_LBIT ++#define DC_CSC_MULT_RV_MD2 (0x59c) << DC_CSC_MULT_RV_LBIT ++#define DC_CSC_MULT_RV_MD3 (0x57c) << DC_CSC_MULT_RV_LBIT ++ ++/* CscMultGuGv */ ++ ++#define DC_CSC_MULT_GU_LBIT (0) ++#define DC_CSC_MULT_GU_HBIT (8) ++#define DC_CSC_MULT_GU_MASK \ ++ GENMASK(DC_CSC_MULT_GU_HBIT, DC_CSC_MULT_GU_LBIT) ++#define DC_CSC_MULT_GU_MD0 (0x193) << DC_CSC_MULT_GU_LBIT ++#define DC_CSC_MULT_GU_MD1 (0x190) << DC_CSC_MULT_GU_LBIT ++#define DC_CSC_MULT_GU_MD2 (0x160) << DC_CSC_MULT_GU_LBIT ++#define DC_CSC_MULT_GU_MD3 (0x15a) << DC_CSC_MULT_GU_LBIT ++ ++#define DC_CSC_MULT_GV_LBIT (16) ++#define DC_CSC_MULT_GV_HBIT (25) ++#define DC_CSC_MULT_GV_MASK \ ++ GENMASK(DC_CSC_MULT_GV_HBIT, DC_CSC_MULT_GV_LBIT) ++#define DC_CSC_MULT_GV_MD0 (0x253) << DC_CSC_MULT_GV_LBIT ++#define DC_CSC_MULT_GV_MD1 (0x341) << DC_CSC_MULT_GV_LBIT ++#define DC_CSC_MULT_GV_MD2 (0x2db) << DC_CSC_MULT_GV_LBIT ++#define DC_CSC_MULT_GV_MD3 (0x2cb) << DC_CSC_MULT_GV_LBIT ++ ++/* CscMultBu */ ++ ++#define DC_CSC_MULT_BU_LBIT (0) ++#define DC_CSC_MULT_BU_HBIT (11) ++#define DC_CSC_MULT_BU_MASK \ ++ GENMASK(DC_CSC_MULT_BU_HBIT, DC_CSC_MULT_BU_LBIT) ++#define DC_CSC_MULT_BU_MD0 (0x820) << DC_CSC_MULT_BU_LBIT ++#define DC_CSC_MULT_BU_MD1 (0x812) << DC_CSC_MULT_BU_LBIT ++#define DC_CSC_MULT_BU_MD2 (0x717) << DC_CSC_MULT_BU_LBIT ++#define DC_CSC_MULT_BU_MD3 (0x6ee) << DC_CSC_MULT_BU_LBIT ++ ++/* CscSubYUV */ ++ ++#define DC_CSC_SUB_Y_LBIT (0) ++#define DC_CSC_SUB_Y_HBIT (4) ++#define DC_CSC_SUB_Y_MASK \ ++ GENMASK(DC_CSC_SUB_Y_HBIT, DC_CSC_SUB_Y_LBIT) ++#define DC_CSC_SUB_Y_MD0 (0x00) << DC_CSC_SUB_Y_LBIT ++#define DC_CSC_SUB_Y_MD1 (0x10) << DC_CSC_SUB_Y_LBIT ++#define DC_CSC_SUB_Y_MD2 (0x00) << DC_CSC_SUB_Y_LBIT ++#define DC_CSC_SUB_Y_MD3 (0x10) << DC_CSC_SUB_Y_LBIT ++ ++#define DC_CSC_SUB_UV_LBIT (16) ++#define DC_CSC_SUB_UV_HBIT (23) ++#define DC_CSC_SUB_UV_MASK \ ++ GENMASK(DC_CSC_SUB_UV_HBIT, DC_CSC_SUB_UV_LBIT) ++#define DC_CSC_SUB_UV_MD0 (0x00) << DC_CSC_SUB_UV_LBIT ++#define DC_CSC_SUB_UV_MD1 (0x80) << DC_CSC_SUB_UV_LBIT ++#define DC_CSC_SUB_UV_MD2 (0x80) << DC_CSC_SUB_UV_LBIT ++#define DC_CSC_SUB_UV_MD3 (0x80) << DC_CSC_SUB_UV_LBIT ++ ++/* Common(DISP_COM) bit field define */ ++ ++/* Dither drop bit. */ ++#define DC_DP_DITHER_DW_LBIT (16) ++#define DC_DP_DITHER_DW_HBIT (21) ++#define DC_DP_DITHER_DW_MASK \ ++ GENMASK(DC_DP_DITHER_DW_HBIT, DC_DP_DITHER_DW_LBIT) ++#define DC_DP_DITHER_DW_BLUE_LBIT (16) ++#define DC_DP_DITHER_DW_GREEN_LBIT (18) ++#define DC_DP_DITHER_DW_RED_LBIT (20) ++#define DC_DP_DITHER_DROP_0_BITS (0) ++#define DC_DP_DITHER_DROP_2_BITS (1) ++#define DC_DP_DITHER_DROP_3_BITS (2) ++#define DC_DP_DITHER_DROP_4_BITS (3) ++#define DC_RGB888_TO_RGB565_DITHER (0b100110) << DC_DP_DITHER_DW_LBIT ++#define DC_RGB888_TO_RGB666_DITHER (0b010101) << DC_DP_DITHER_DW_LBIT ++/* Dither Clk gate enable */ ++#define DC_DITHER_CLKGATE_EN BIT(4) ++/* SLCD Clk gate enable */ ++#define DC_SLCD_CLKGATE_EN BIT(3) ++/* TFT Clk gate enable */ ++#define DC_TFT_CLKGATE_EN BIT(2) ++/* Dither enable. 1:dither enable 0:dither disable */ ++#define DC_DP_DITHER_EN BIT(1) ++/* Display interfaces select. 0:TFT 1:SLCD */ ++#define DC_DP_IF_SEL GENMASK(1, 0) ++#define DC_DISP_COM_SLCD BIT(1) ++#define DC_DISP_COM_TFT BIT(0) ++ ++/* TIMING_HSYNC(TFT_TIMING_HSYNC) bit field define */ ++ ++/* HSYNC pulse start point(base on dot clock cycle) */ ++#define DC_HPS_LBIT (16) ++#define DC_HPS_HBIT (27) ++#define DC_HPS_MASK \ ++ GENMASK(DC_HPS_HBIT, DC_HPS_LBIT) ++/* HSYNC pulse end point(base on dot clock cycle) */ ++#define DC_HPE_LBIT (0) ++#define DC_HPE_HBIT (11) ++#define DC_HPE_MASK \ ++ GENMASK(DC_HPE_HBIT, DC_HPE_LBIT) ++ ++/* TIMING_VSYNC(TFT_TIMING_VSYNC) bit field define */ ++ ++/* VSYNC pulse start point(base on dot clock cycle) */ ++#define DC_VPS_LBIT (16) ++#define DC_VPS_HBIT (27) ++#define DC_VPS_MASK \ ++ GENMASK(DC_VPS_HBIT, DC_VPS_LBIT) ++/* VSYNC pulse end point(base on dot clock cycle) */ ++#define DC_VPE_LBIT (0) ++#define DC_VPE_HBIT (11) ++#define DC_VPE_MASK \ ++ GENMASK(DC_VPE_HBIT, DC_VPE_LBIT) ++ ++/* TIMING_HDE(TFT_TIMING_HDE) bit field define */ ++ ++/* Horizontal display area start point (base on dot clock cycle). ++ * And it is also the DE pulse start point in horizontal. ++ * It indicate the end point of vertical back porch.*/ ++#define DC_HDS_LBIT (16) ++#define DC_HDS_HBIT (27) ++#define DC_HDS_MASK \ ++ GENMASK(HDE_HDS_HBIT, DC_HDS_LBIT) ++/* Horizontal display area end point (base on dot clock cycle). ++ * And it is also the DE pulse end point in horizontal. ++ * It indicate the end point of horizontal front porch.*/ ++#define DC_HDE_LBIT (0) ++#define DC_HDE_HBIT (11) ++#define DC_HDE_MASK \ ++ GENMASK(DC_HDE_HBIT, DC_HDE_LBIT) ++ ++/* TIMING_VDE(TFT_TIMING_VDE) bit field define */ ++ ++/* Vertical display area start point(base on dot clock cycle). ++ * And it is also the DE pulse start point in vertical. ++ * It indicate the end point of vertical back porch. */ ++#define DC_VDS_LBIT (16) ++#define DC_VDS_HBIT (27) ++#define DC_VDS_MASK \ ++ GENMASK(VDE_VDS_HBIT, DC_VDS_LBIT) ++/* Vertical display area end point(base on dot clock cycle). ++ * And it is also the DE pulse end point in vertical. ++ * It indicate the start point of vertical front porch. */ ++#define DC_VDE_LBIT (0) ++#define DC_VDE_HBIT (11) ++#define DC_VDE_MASK \ ++ GENMASK(DC_VDE_HBIT, DC_VDE_LBIT) ++ ++/* TRANS_CONFIG(TFT_TRAN_CFG) bit field define */ ++ ++/* Inverse the polarity of the DOT_CLK */ ++#define DC_PIX_CLK_INV BIT(10) ++/* Default level of DE(invalid level) */ ++#define DC_DE_DL BIT(9) ++/* Default level of HSYNC and VSYNC(invalid level) */ ++#define DC_SYNC_DL BIT(8) ++/* Output color mode of even lines(2,4,6...) */ ++#define DC_COLOR_EVEN_LBIT (19) ++#define DC_COLOR_EVEN_HBIT (21) ++#define DC_COLOR_EVEN_MASK \ ++ GENMASK(DC_COLOR_EVEN_HBIT, DC_COLOR_EVEN_LBIT) ++#define DC_EVEN_RGB (0b000) << DC_COLOR_EVEN_LBIT ++#define DC_EVEN_RBG (0b001) << DC_COLOR_EVEN_LBIT ++#define DC_EVEN_BGR (0b010) << DC_COLOR_EVEN_LBIT ++#define DC_EVEN_BRG (0b011) << DC_COLOR_EVEN_LBIT ++#define DC_EVEN_GBR (0b100) << DC_COLOR_EVEN_LBIT ++#define DC_EVEN_GRB (0b101) << DC_COLOR_EVEN_LBIT ++/* Output color mode of odd lines(1, 3, 5...) */ ++#define DC_COLOR_ODD_LBIT (16) ++#define DC_COLOR_ODD_HBIT (18) ++#define DC_COLOR_ODD_MASK \ ++ GENMASK(DC_COLOR_ODD_HBIT, DC_COLOR_ODD_LBIT) ++#define DC_ODD_RGB (0b000) << DC_COLOR_ODD_LBIT ++#define DC_ODD_RBG (0b001) << DC_COLOR_ODD_LBIT ++#define DC_ODD_BGR (0b010) << DC_COLOR_ODD_LBIT ++#define DC_ODD_BRG (0b011) << DC_COLOR_ODD_LBIT ++#define DC_ODD_GBR (0b100) << DC_COLOR_ODD_LBIT ++#define DC_ODD_GRB (0b101) << DC_COLOR_ODD_LBIT ++/* 0x:0x: 24bits parallel mode ++ * 10: 8bits serial mode without dummy(RGB) ++ * 11: 8bits serial mode with dummy(RGBD)*/ ++#define DC_MODE_LBIT (0) ++#define DC_MODE_HBIT (2) ++#define DC_MODE_MASK \ ++ GENMASK(DC_MODE_HBIT, DC_MODE_LBIT) ++#define DC_MODE_PARALLEL_888 (0b000) << DC_MODE_LBIT ++#define DC_MODE_PARALLEL_666 (0b001) << DC_MODE_LBIT ++#define DC_MODE_PARALLEL_565 (0b010) << DC_MODE_LBIT ++#define DC_MODE_SERIAL_8BIT_RGB (0b100) << DC_MODE_LBIT ++#define DC_MODE_SERIAL_8BIT_RGBD (0b101) << DC_MODE_LBIT ++ ++/* STATUS(TFT_ST) bit field define */ ++ ++/* 0: TFT is not working 1: TFT is working */ ++#define DC_TFT_WORKING BIT(1) ++/* Indicate the controller jump into recovery state, ++ * and starting trans one frame 0 to panel. ++ * 0: TFT is working order 1: TFT is in UNDER mode.*/ ++#define DC_TFT_UNDER BIT(0) ++ ++/* SLCD_CONFIG(SLCD_PANEL_CFG) bit field define */ ++ ++/* Frame refresh mode ++ * 0: single frame mode(default) 1: continuous frame mode */ ++#define DC_FRM_MD BIT(31) ++/* Anti-jitter for RDY. ++ * 0: sample RDY with 1 pixclk cycle(default) ++ * 1: sample RDY with 3 pixclk cycles for anti-jitter.*/ ++#define DC_RDY_ANTI_JIT BIT(27) ++/* Whether the pixel data or command need conversion ++ * 0: no use conversion, such as parameter of command(default) ++ * 1: need conversion, such as pixel data*/ ++#define DC_FMT_EN BIT(26) ++/* 001: typeA(6800) 010: typeB(8080)(default) 100: typeC(SPI) */ ++#define DC_DBI_TYPE_LBIT (23) ++#define DC_DBI_TYPE_HBIT (25) ++#define DC_DBI_TYPE_MASK \ ++ GENMASK(DC_DBI_TYPE_HBIT, DC_DBI_TYPE_LBIT) ++#define DC_DBI_TYPE_A_6800 (0b001) << DC_DBI_TYPE_LBIT ++#define DC_DBI_TYPE_B_8080 (0b010) << DC_DBI_TYPE_LBIT ++#define DC_DBI_TYPE_C_SPI_3 (0b100) << DC_DBI_TYPE_LBIT ++#define DC_DBI_TYPE_C_SPI_4 (0b101) << DC_DBI_TYPE_LBIT ++/* Color format. ++ * 00: 565 01: 666 10: 888(default) */ ++#define DC_DATA_FMT_LBIT (21) ++#define DC_DATA_FMT_HBIT (22) ++#define DC_DATA_FMT_MASK \ ++ GENMASK(DC_DATA_FMT_HBIT, DC_DATA_FMT_LBIT) ++#define DC_DATA_FMT_565 (0b00) << DC_DATA_FMT_LBIT ++#define DC_DATA_FMT_444 (0b01) << DC_DATA_FMT_LBIT ++#define DC_DATA_FMT_666 (0b01) << DC_DATA_FMT_LBIT ++#define DC_DATA_FMT_888 (0b10) << DC_DATA_FMT_LBIT ++/* Anti-jitter for TE. ++ * 0: sample TE with 1 pixclk cycle; ++ * 1: sample TE with 3 pixclk cycles for anti-jitter(default).*/ ++#define DC_TE_ANTI_JIT BIT(20) ++/* The active edge of TE. ++ * 0: the front edge(default) 1: the back edge*/ ++#define DC_TE_MD BIT(19) ++/* 0: do not wait TE, send pix_data after SLCD_START; ++ * 1: wait TE, and then send pix_data.(default)*/ ++#define DC_TE_SWITCH BIT(18) ++/* 0: do not wait RDY, send command or data immediately;(default) ++ * 1: wait RDY, and then send command or data. */ ++#define DC_RDY_SWITCH BIT(17) ++/* CS control enable. ++ * 0: The CS pin is controlled by GPIO.(default) ++ * 1: The CS pin is controlled by Display Controller. */ ++#define DC_CS_EN BIT(16) ++/* The CS's default polarity ++ * 0: the default(invalid) level is low; ++ * 1: the default(invalid) level is high;(default) */ ++#define DC_CS_DP BIT(11) ++/* The RDY's default polarity ++ * 0: the default(invalid) level is low; ++ * 1: the default(invalid) level is high;(default) */ ++#define DC_RDY_DP BIT(10) ++/* DC's definition. ++ * 0: Command DC = low, Data DC = high(default) ++ * 1: Command DC = high, Data DC = low */ ++#define DC_DC_MD BIT(9) ++/* WR's default polarity. ++ * 0: drive at posedge, and sample at negedge; ++ * 1: drive at negedge, and sample at posedge.(default) */ ++#define DC_WR_DP BIT(8) ++/* SPI_CLK Polarity. ++ * 0: Active edge is Falling(default) ++ * 1: Active edge is Rising Used for serial transfer mode. */ ++#define DC_CLKPLY BIT(7) ++/* The TE' default polarity ++ * 0: the default(invalid) level is low;(default) ++ * 1: the default(invalid) level is high; */ ++#define DC_TE_DP BIT(6) ++/* Panel's data width. It's also used in MIPI DSI command mod ++ * 000: 8bits 001: 9bits 010: 16bits 011: 18bits 100: 24bits(default) */ ++#define DC_DWIDTH_LBIT (3) ++#define DC_DWIDTH_HBIT (5) ++#define DC_DWIDTH_MASK \ ++ GENMASK(DC_DWIDTH_HBIT, DC_DWIDTH_LBIT) ++#define DC_DWIDTH_8BITS (0b000) << DC_DWIDTH_LBIT ++#define DC_DWIDTH_9BITS (0b001) << DC_DWIDTH_LBIT ++#define DC_DWIDTH_16BITS (0b010) << DC_DWIDTH_LBIT ++#define DC_DWIDTH_18BITS (0b011) << DC_DWIDTH_LBIT ++#define DC_DWIDTH_24BITS (0b100) << DC_DWIDTH_LBIT ++/* The width of panel's command and it's parameters ++ * 000: 8bits(default) 001: 9bits 010: 16bits 011: 18bits 100: 24bits */ ++#define DC_CWIDTH_LBIT (0) ++#define DC_CWIDTH_HBIT (2) ++#define DC_CWIDTH_MASK \ ++ GENMASK(DC_CWIDTH_HBIT, DC_CWIDTH_LBIT) ++#define DC_CWIDTH_8BITS (0b000) << DC_CWIDTH_LBIT ++#define DC_CWIDTH_9BITS (0b001) << DC_CWIDTH_LBIT ++#define DC_CWIDTH_16BITS (0b010) << DC_CWIDTH_LBIT ++#define DC_CWIDTH_18BITS (0b011) << DC_CWIDTH_LBIT ++#define DC_CWIDTH_24BITS (0b100) << DC_CWIDTH_LBIT ++ ++/* SLCD_WR_DUTY(SLCD_WR_DUTY) bit field define */ ++ ++/* WR's high time period when transmitting data ++ * (base on MIPI DBI Type B, and this is low time at Type A) */ ++#define DC_DSTIME_LBIT (24) ++#define DC_DSTIME_HBIT (31) ++#define DC_DSTIME_MASK \ ++ GENMASK(DC_DSTIME_HBIT, DC_DSTIME_LBIT) ++/* WR's low time period when transmitting data ++ * (base on MIPI DBI Type B, and this is high time at Type A) */ ++#define DC_DDTIME_LBIT (16) ++#define DC_DDTIME_HBIT (23) ++#define DC_DDTIME_MASK \ ++ GENMASK(DC_DDTIME_HBIT, DC_DDTIME_LBIT) ++/* WR's high time period when transmitting command ++ * (base on MIPI DBI Type B, and this is low time at Type A) */ ++#define DC_CSTIME_LBIT (8) ++#define DC_CSTIME_HBIT (15) ++#define DC_CSTIME_MASK \ ++ GENMASK(DC_CSTIME_HBIT, DC_CSTIME_LBIT) ++/* WR's low time period when transmitting command ++ * (base on MIPI DBI Type B, and this is high time at Type A) */ ++#define DC_CDTIME_LBIT (0) ++#define DC_CDTIME_HBIT (7) ++#define DC_CDTIME_MASK \ ++ GENMASK(DC_CDTIME_HBIT, DC_CDTIME_LBIT) ++ ++/* SLCD_TIMING(SLCD_TIMING) bit field define */ ++#define DC_TCH_LBIT (24) ++#define DC_TCH_HBIT (31) ++#define DC_TCH_MASK \ ++ GENMASK(DC_TCH_HBIT, DC_TCH_LBIT) ++#define DC_TCS_LBIT (16) ++#define DC_TCS_HBIT (23) ++#define DC_TCS_MASK \ ++ GENMASK(DC_TCS_HBIT, DC_TCS_LBIT) ++#define DC_TAH_LBIT (8) ++#define DC_TAH_HBIT (15) ++#define DC_TAH_MASK \ ++ GENMASK(DC_TAH_HBIT, DC_TAH_LBIT) ++#define DC_TAS_LBIT (0) ++#define DC_TAS_HBIT (7) ++#define DC_TAS_MASK \ ++ GENMASK(DC_TAS_HBIT, DC_TAS_LBIT) ++ ++/* SLCD_FRM_SIZE(SLCD_FRM_SIZE) bit field define */ ++ ++/* Line number of each frame. */ ++#define DC_SLCD_FRM_V_SIZE_LBIT (16) ++#define DC_SLCD_FRM_V_SIZE_HBIT (31) ++#define DC_SLCD_FRM_V_SIZE_MASK \ ++ GENMASK(DC_SLCD_FRM_V_SIZE_HBIT, DC_SLCD_FRM_V_SIZE_LBIT) ++/* Pixel number of each line. */ ++#define DC_SLCD_FRM_H_SIZE_LBIT (0) ++#define DC_SLCD_FRM_H_SIZE_HBIT (15) ++#define DC_SLCD_FRM_H_SIZE_MASK \ ++ GENMASK(DC_SLCD_FRM_H_SIZE_HBIT, DC_SLCD_FRM_H_SIZE_LBIT) ++ ++/* SLCD_SLOW_TIME(SLCD_SLOW_TIME) bit field define */ ++ ++/* SLCD will delay some period of pixclk before transmitting data, ++ * after TE鈥檚 relative edge. */ ++#define DC_SLOW_TIME_LBIT (0) ++#define DC_SLOW_TIME_HBIT (15) ++#define DC_SLOW_TIME_MASK \ ++ GENMASK(DC_SLOW_TIME_HBIT, DC_SLOW_TIME_LBIT) ++ ++/* SLCD_REG_IF(SLCD_REG_IF) bit field define */ ++ ++/* It is used to decide the meanings of the DATA/CMD/PARAMETER. ++ * 00: pix_data; 01: parameter; 1x: command(default). */ ++#define DC_SLCD_CMD_FLAG_LBIT (30) ++#define DC_SLCD_CMD_FLAG_HBIT (31) ++#define DC_SLCD_CMD_FLAG_MASK \ ++ GENMASK(DC_SLCD_CMD_FLAG_HBIT, DC_SLCD_CMD_FLAG_LBIT) ++#define DC_SLCD_CMD_FLAG_DATA (0b00) << DC_SLCD_CMD_FLAG_LBIT ++#define DC_SLCD_CMD_FLAG_PRM (0b01) << DC_SLCD_CMD_FLAG_LBIT ++#define DC_SLCD_CMD_FLAG_CMD (0b10) << DC_SLCD_CMD_FLAG_LBIT ++/* Indicate this is the last content, the hardware will disable the CS */ ++#define DC_SLCD_CMD_END BIT(29) ++/* content */ ++#define DC_SLCD_CMD_CONTENT_LBIT (0) ++#define DC_SLCD_CMD_CONTENT_HBIT (23) ++#define DC_SLCD_CMD_CONTENT_MASK \ ++ GENMASK(DC_SLCD_CMD_CONTENT_HBIT, DC_SLCD_CMD_CONTENT_LBIT) ++ ++/* SLCD_STATUS(SLCD_ST) bit field define */ ++ ++/* Indicate whether the SLCD DBI interface controller is working or not. ++ * 0: idle 1: busy */ ++#define DC_SLCD_ST_BUSY BIT(0) ++ ++typedef union frm_size { ++ uint32_t d32; ++ struct { ++ uint32_t width:12; ++ uint32_t reserve12_15:4; ++ uint32_t height:12; ++ uint32_t reserve28_31:4; ++ }b; ++} frm_size_t; ++ ++typedef union frm_ctrl { ++ uint32_t d32; ++ struct { ++ uint32_t stop:1; ++ uint32_t bit1_keep0:1; ++ uint32_t bit2_keep1:1; ++ uint32_t bit3_4_keep0:2; ++ uint32_t reserve5_31:27; ++ }b; ++} frm_ctrl_t; ++ ++typedef union lay_cfg_en { ++ uint32_t d32; ++ struct { ++ uint32_t bit0_3_keep0:4; ++ uint32_t lay0_en:1; ++ uint32_t lay1_en:1; ++ uint32_t bit6_7_keep0:2; ++ uint32_t lay0_z_order:2; ++ uint32_t lay1_z_order:2; ++ uint32_t bit12_15_keep0:4; ++ uint32_t reserve16_31:16; ++ }b; ++} lay_cfg_en_t; ++ ++typedef union cmp_irq_ctrl { ++ uint32_t d32; ++ struct { ++ uint32_t reserve_0:1; ++ uint32_t eof_msk:1; ++ uint32_t sof_msk:1; ++ uint32_t reserve3_14:12; ++ uint32_t bit15_keep0:1; ++ uint32_t reserve_16:1; ++ uint32_t eod_msk:1; ++ uint32_t reserve16_31:14; ++ }b; ++} cmp_irq_ctrl_t; ++ ++typedef union lay_size { ++ uint32_t d32; ++ struct { ++ uint32_t width:12; ++ uint32_t reserve12_15:4; ++ uint32_t height:12; ++ uint32_t reserve28_31:4; ++ }b; ++} lay_size_t; ++ ++typedef union lay_cfg { ++ uint32_t d32; ++ struct { ++ uint32_t g_alpha:8; ++ uint32_t reserve8_9:2; ++ uint32_t color:3; ++ uint32_t g_alpha_en:1; ++ uint32_t domain_multi:1; ++ uint32_t reserve14_15:1; ++ uint32_t format:4; ++ uint32_t reserve22_31:12; ++ }b; ++} lay_cfg_t; ++ ++typedef union lay_scale { ++ uint32_t d32; ++ struct { ++ uint32_t target_width:12; ++ uint32_t reserve12_15:4; ++ uint32_t target_height:12; ++ uint32_t reserve28_31:4; ++ }b; ++} lay_scale_t; ++ ++typedef union lay_pos { ++ uint32_t d32; ++ struct { ++ uint32_t x_pos:12; ++ uint32_t reserve12_15:4; ++ uint32_t y_pos:12; ++ uint32_t reserve28_31:4; ++ }b; ++} lay_pos_t; ++ ++struct ingenicfb_framedesc { ++ uint32_t FrameNextCfgAddr; ++ frm_size_t FrameSize; ++ frm_ctrl_t FrameCtrl; ++ uint32_t WritebackAddr; ++ uint32_t WritebackStride; ++ uint32_t Layer0CfgAddr; ++ uint32_t Layer1CfgAddr; ++ uint32_t Layer2CfgAddr; ++ uint32_t Layer3CfgAddr; ++ lay_cfg_en_t LayCfgEn; ++ cmp_irq_ctrl_t InterruptControl; ++}; ++ ++struct ingenicfb_layerdesc { ++ lay_size_t LayerSize; ++ lay_cfg_t LayerCfg; ++ uint32_t LayerBufferAddr; ++ lay_scale_t LayerScale; ++ uint32_t layer_reserve0; ++ uint32_t LayerScratch; ++ lay_pos_t LayerPos; ++ uint32_t layer_reserve1; ++ uint32_t layer_reserve2; ++ uint32_t LayerStride; ++}; ++ ++#endif /* _DPU_REG_H_ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v11_ingenicfb.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v11_ingenicfb.c.patch new file mode 100644 index 00000000..70a66269 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v11_ingenicfb.c.patch @@ -0,0 +1,2951 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v11/ingenicfb.c b/drivers/video/fbdev/ingenic/fb_v11/ingenicfb.c +--- a/drivers/video/fbdev/ingenic/fb_v11/ingenicfb.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v11/ingenicfb.c 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,2947 @@ ++/* ++ * File: drivers/video/ingenic/x2000/ingenicfb.c ++ * ++ * ++ * Copyright (C) 2016 Ingenic Semiconductor Inc. ++ * ++ * Author:clwang ++ * qipengzhen ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "dpu_reg.h" ++#include "ingenicfb.h" ++ ++#define CONFIG_FB_JZ_DEBUG ++ ++struct lcd_panel *fbdev_panel = NULL; ++struct platform_device *fbdev_pdev = NULL; ++ ++static int uboot_inited; ++static int showFPS = 0; ++static struct ingenicfb_device *fbdev; ++ ++static const struct fb_fix_screeninfo ingenicfb_fix = { ++ .id = "ingenicfb", ++ .type = FB_TYPE_PACKED_PIXELS, ++ .visual = FB_VISUAL_TRUECOLOR, ++ .xpanstep = 0, ++ .ypanstep = 1, ++ .ywrapstep = 0, ++ .accel = FB_ACCEL_NONE, ++}; ++ ++struct ingenicfb_colormode { ++ uint32_t mode; ++ uint32_t color; ++ uint32_t bits_per_pixel; ++ uint32_t nonstd; ++ struct fb_bitfield red; ++ struct fb_bitfield green; ++ struct fb_bitfield blue; ++ struct fb_bitfield transp; ++}; ++ ++static struct ingenicfb_colormode ingenicfb_colormodes[] = { ++ { ++ .mode = LAYER_CFG_FORMAT_RGB888, ++ .color = LAYER_CFG_COLOR_RGB, ++ .bits_per_pixel = 32, ++ .nonstd = 0, ++#ifdef CONFIG_ANDROID ++ .color = LAYER_CFG_COLOR_BGR, ++ .red = { .length = 8, .offset = 0, .msb_right = 0 }, ++ .green = { .length = 8, .offset = 8, .msb_right = 0 }, ++ .blue = { .length = 8, .offset = 16, .msb_right = 0 }, ++#else ++ .color = LAYER_CFG_COLOR_RGB, ++ .red = { .length = 8, .offset = 16, .msb_right = 0 }, ++ .green = { .length = 8, .offset = 8, .msb_right = 0 }, ++ .blue = { .length = 8, .offset = 0, .msb_right = 0 }, ++#endif ++ .transp = { .length = 0, .offset = 0, .msb_right = 0 }, ++ }, { ++ .mode = LAYER_CFG_FORMAT_ARGB8888, ++ .bits_per_pixel = 32, ++ .nonstd = 0, ++#ifdef CONFIG_ANDROID ++ .color = LAYER_CFG_COLOR_BGR, ++ .red = { .length = 8, .offset = 0, .msb_right = 0 }, ++ .green = { .length = 8, .offset = 8, .msb_right = 0 }, ++ .blue = { .length = 8, .offset = 16, .msb_right = 0 }, ++#else ++ .color = LAYER_CFG_COLOR_RGB, ++ .red = { .length = 8, .offset = 16, .msb_right = 0 }, ++ .green = { .length = 8, .offset = 8, .msb_right = 0 }, ++ .blue = { .length = 8, .offset = 0, .msb_right = 0 }, ++#endif ++ .transp = { .length = 8, .offset = 24, .msb_right = 0 }, ++ }, { ++ .mode = LAYER_CFG_FORMAT_RGB555, ++ .color = LAYER_CFG_COLOR_RGB, ++ .bits_per_pixel = 16, ++ .nonstd = 0, ++ .red = { .length = 5, .offset = 10, .msb_right = 0 }, ++ .green = { .length = 5, .offset = 5, .msb_right = 0 }, ++ .blue = { .length = 5, .offset = 0, .msb_right = 0 }, ++ .transp = { .length = 0, .offset = 0, .msb_right = 0 }, ++ }, { ++ .mode = LAYER_CFG_FORMAT_ARGB1555, ++ .color = LAYER_CFG_COLOR_RGB, ++ .bits_per_pixel = 16, ++ .nonstd = 0, ++ .red = { .length = 5, .offset = 10, .msb_right = 0 }, ++ .green = { .length = 5, .offset = 5, .msb_right = 0 }, ++ .blue = { .length = 5, .offset = 0, .msb_right = 0 }, ++ .transp = { .length = 1, .offset = 15, .msb_right = 0 }, ++ }, { ++ .mode = LAYER_CFG_FORMAT_RGB565, ++ .color = LAYER_CFG_COLOR_RGB, ++ .bits_per_pixel = 16, ++ .nonstd = 0, ++ .red = { .length = 5, .offset = 11, .msb_right = 0 }, ++ .green = { .length = 6, .offset = 5, .msb_right = 0 }, ++ .blue = { .length = 5, .offset = 0, .msb_right = 0 }, ++ .transp = { .length = 0, .offset = 0, .msb_right = 0 }, ++ }, { ++ .mode = LAYER_CFG_FORMAT_YUV422, ++ .bits_per_pixel = 16, ++ .nonstd = LAYER_CFG_FORMAT_YUV422, ++ }, ++}; ++ ++static void dump_dc_reg(void) ++{ ++ printk("-----------------dc_reg------------------\n"); ++ printk("DC_FRM_CFG_ADDR: %lx\n",reg_read(fbdev, DC_FRM_CFG_ADDR)); ++ printk("DC_FRM_CFG_CTRL: %lx\n",reg_read(fbdev, DC_FRM_CFG_CTRL)); ++ printk("DC_CTRL: %lx\n",reg_read(fbdev, DC_CTRL)); ++ printk("DC_CSC_MULT_YRV: %lx\n",reg_read(fbdev, DC_CSC_MULT_YRV)); ++ printk("DC_CSC_MULT_GUGV: %lx\n",reg_read(fbdev, DC_CSC_MULT_GUGV)); ++ printk("DC_CSC_MULT_BU: %lx\n",reg_read(fbdev, DC_CSC_MULT_BU)); ++ printk("DC_CSC_SUB_YUV: %lx\n",reg_read(fbdev, DC_CSC_SUB_YUV)); ++ printk("DC_ST: %lx\n",reg_read(fbdev, DC_ST)); ++ printk("DC_INTC: %lx\n",reg_read(fbdev, DC_INTC)); ++ printk("DC_INT_FLAG: %lx\n",reg_read(fbdev, DC_INT_FLAG)); ++ printk("DC_COM_CONFIG: %lx\n",reg_read(fbdev, DC_COM_CONFIG)); ++ printk("DC_PCFG_RD_CTRL: %lx\n",reg_read(fbdev, DC_PCFG_RD_CTRL)); ++ printk("DC_OFIFO_PCFG: %lx\n",reg_read(fbdev, DC_OFIFO_PCFG)); ++ printk("DC_DISP_COM: %lx\n",reg_read(fbdev, DC_DISP_COM)); ++ printk("-----------------dc_reg------------------\n"); ++} ++ ++static void dump_tft_reg(void) ++{ ++ printk("----------------tft_reg------------------\n"); ++ printk("TFT_TIMING_HSYNC: %lx\n",reg_read(fbdev, DC_TFT_HSYNC)); ++ printk("TFT_TIMING_VSYNC: %lx\n",reg_read(fbdev, DC_TFT_VSYNC)); ++ printk("TFT_TIMING_HDE: %lx\n",reg_read(fbdev, DC_TFT_HDE)); ++ printk("TFT_TIMING_VDE: %lx\n",reg_read(fbdev, DC_TFT_VDE)); ++ printk("TFT_TRAN_CFG: %lx\n",reg_read(fbdev, DC_TFT_CFG)); ++ printk("TFT_ST: %lx\n",reg_read(fbdev, DC_TFT_ST)); ++ printk("----------------tft_reg------------------\n"); ++} ++ ++static void dump_slcd_reg(void) ++{ ++ printk("---------------slcd_reg------------------\n"); ++ printk("SLCD_CFG: %lx\n",reg_read(fbdev, DC_SLCD_CFG)); ++ printk("SLCD_WR_DUTY: %lx\n",reg_read(fbdev, DC_SLCD_WR_DUTY)); ++ printk("SLCD_TIMING: %lx\n",reg_read(fbdev, DC_SLCD_TIMING)); ++ printk("SLCD_FRM_SIZE: %lx\n",reg_read(fbdev, DC_SLCD_FRM_SIZE)); ++ printk("SLCD_SLOW_TIME: %lx\n",reg_read(fbdev, DC_SLCD_SLOW_TIME)); ++ printk("SLCD_CMD: %lx\n",reg_read(fbdev, DC_SLCD_CMD)); ++ printk("SLCD_ST: %lx\n",reg_read(fbdev, DC_SLCD_ST)); ++ printk("---------------slcd_reg------------------\n"); ++} ++ ++static void dump_frm_desc_reg(void) ++{ ++ unsigned int ctrl; ++ ctrl = reg_read(fbdev, DC_CTRL); ++ ctrl |= DC_DES_CNT_RST; ++ reg_write(fbdev, DC_CTRL, ctrl); ++ ++ printk("--------Frame Descriptor register--------\n"); ++ printk("FrameNextCfgAddr: %lx\n",reg_read(fbdev, DC_FRM_DES)); ++ printk("FrameSize: %lx\n",reg_read(fbdev, DC_FRM_DES)); ++ printk("FrameCtrl: %lx\n",reg_read(fbdev, DC_FRM_DES)); ++ printk("WritebackAddr: %lx\n",reg_read(fbdev, DC_FRM_DES)); ++ printk("WritebackStride: %lx\n",reg_read(fbdev, DC_FRM_DES)); ++ printk("Layer0CfgAddr: %lx\n",reg_read(fbdev, DC_FRM_DES)); ++ printk("Layer1CfgAddr: %lx\n",reg_read(fbdev, DC_FRM_DES)); ++ printk("Layer2CfgAddr: %lx\n",reg_read(fbdev, DC_FRM_DES)); ++ printk("Layer3CfgAddr: %lx\n",reg_read(fbdev, DC_FRM_DES)); ++ printk("LayCfgEn: %lx\n",reg_read(fbdev, DC_FRM_DES)); ++ printk("InterruptControl: %lx\n",reg_read(fbdev, DC_FRM_DES)); ++ printk("--------Frame Descriptor register--------\n"); ++} ++ ++static void dump_layer_desc_reg(void) ++{ ++ unsigned int ctrl; ++ ctrl = reg_read(fbdev, DC_CTRL); ++ ctrl |= DC_DES_CNT_RST; ++ reg_write(fbdev, DC_CTRL, ctrl); ++ ++ printk("--------layer0 Descriptor register-------\n"); ++ printk("LayerSize: %lx\n",reg_read(fbdev, DC_LAY0_DES)); ++ printk("LayerCfg: %lx\n",reg_read(fbdev, DC_LAY0_DES)); ++ printk("LayerBufferAddr: %lx\n",reg_read(fbdev, DC_LAY0_DES)); ++ printk("LayerScale: %lx\n",reg_read(fbdev, DC_LAY0_DES)); ++ printk("LayerRotation: %lx\n",reg_read(fbdev, DC_LAY0_DES)); ++ printk("LayerScratch: %lx\n",reg_read(fbdev, DC_LAY0_DES)); ++ printk("LayerPos: %lx\n",reg_read(fbdev, DC_LAY0_DES)); ++ printk("LayerResizeCoef_X: %lx\n",reg_read(fbdev, DC_LAY0_DES)); ++ printk("LayerResizeCoef_Y: %lx\n",reg_read(fbdev, DC_LAY0_DES)); ++ printk("LayerStride: %lx\n",reg_read(fbdev, DC_LAY0_DES)); ++ printk("--------layer0 Descriptor register-------\n"); ++ ++ printk("--------layer1 Descriptor register-------\n"); ++ printk("LayerSize: %lx\n",reg_read(fbdev, DC_LAY1_DES)); ++ printk("LayerCfg: %lx\n",reg_read(fbdev, DC_LAY1_DES)); ++ printk("LayerBufferAddr: %lx\n",reg_read(fbdev, DC_LAY1_DES)); ++ printk("LayerScale: %lx\n",reg_read(fbdev, DC_LAY1_DES)); ++ printk("LayerRotation: %lx\n",reg_read(fbdev, DC_LAY1_DES)); ++ printk("LayerScratch: %lx\n",reg_read(fbdev, DC_LAY1_DES)); ++ printk("LayerPos: %lx\n",reg_read(fbdev, DC_LAY1_DES)); ++ printk("LayerResizeCoef_X: %lx\n",reg_read(fbdev, DC_LAY1_DES)); ++ printk("LayerResizeCoef_Y: %lx\n",reg_read(fbdev, DC_LAY1_DES)); ++ printk("LayerStride: %lx\n",reg_read(fbdev, DC_LAY1_DES)); ++ printk("--------layer1 Descriptor register-------\n"); ++} ++ ++static void dump_frm_desc(struct ingenicfb_framedesc *framedesc, int index) ++{ ++ printk("-------User Frame Descriptor index[%d]-----\n", index); ++ printk("FramedescAddr: 0x%x\n",(uint32_t)framedesc); ++ printk("FrameNextCfgAddr: 0x%x\n",framedesc->FrameNextCfgAddr); ++ printk("FrameSize: 0x%x\n",framedesc->FrameSize.d32); ++ printk("FrameCtrl: 0x%x\n",framedesc->FrameCtrl.d32); ++ printk("Layer0CfgAddr: 0x%x\n",framedesc->Layer0CfgAddr); ++ printk("Layer1CfgAddr: 0x%x\n",framedesc->Layer1CfgAddr); ++ printk("LayerCfgEn: 0x%x\n",framedesc->LayCfgEn.d32); ++ printk("InterruptControl: 0x%x\n",framedesc->InterruptControl.d32); ++ printk("-------User Frame Descriptor index[%d]-----\n", index); ++} ++ ++static void dump_layer_desc(struct ingenicfb_layerdesc *layerdesc, int row, int col) ++{ ++ printk("------User layer Descriptor index[%d][%d]------\n", row, col); ++ printk("LayerdescAddr: 0x%x\n",(uint32_t)layerdesc); ++ printk("LayerSize: 0x%x\n",layerdesc->LayerSize.d32); ++ printk("LayerCfg: 0x%x\n",layerdesc->LayerCfg.d32); ++ printk("LayerBufferAddr: 0x%x\n",layerdesc->LayerBufferAddr); ++ printk("LayerScale: 0x%x\n",layerdesc->LayerScale.d32); ++ printk("LayerPos: 0x%x\n",layerdesc->LayerPos.d32); ++ printk("LayerStride: 0x%x\n",layerdesc->LayerStride); ++ printk("------User layer Descriptor index[%d][%d]------\n", row, col); ++} ++ ++void dump_lay_cfg(struct ingenicfb_lay_cfg * lay_cfg, int index) ++{ ++ printk("------User disp set index[%d]------\n", index); ++ printk("lay_en: 0x%x\n",lay_cfg->lay_en); ++ printk("lay_z_order: 0x%x\n",lay_cfg->lay_z_order); ++ printk("pic_witdh: 0x%x\n",lay_cfg->pic_width); ++ printk("pic_heght: 0x%x\n",lay_cfg->pic_height); ++ printk("disp_pos_x: 0x%x\n",lay_cfg->disp_pos_x); ++ printk("disp_pos_y: 0x%x\n",lay_cfg->disp_pos_y); ++ printk("g_alpha_en: 0x%x\n",lay_cfg->g_alpha_en); ++ printk("g_alpha_val: 0x%x\n",lay_cfg->g_alpha_val); ++ printk("color: 0x%x\n",lay_cfg->color); ++ printk("format: 0x%x\n",lay_cfg->format); ++ printk("stride: 0x%x\n",lay_cfg->stride); ++ printk("------User disp set index[%d]------\n", index); ++} ++ ++static void dump_lcdc_registers(void) ++{ ++ dump_dc_reg(); ++ dump_tft_reg(); ++ dump_slcd_reg(); ++ dump_frm_desc_reg(); ++ dump_layer_desc_reg(); ++} ++ ++static void dump_desc(struct ingenicfb_device *fbdev) ++{ ++ int i, j; ++ for(i = 0; i < MAX_DESC_NUM; i++) { ++ for(j = 0; j < MAX_LAYER_NUM; j++) { ++ dump_layer_desc(fbdev->layerdesc[i][j], i, j); ++ } ++ dump_frm_desc(fbdev->framedesc[i], i); ++ } ++} ++ ++ static ssize_t ++dump_lcd(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct ingenicfb_device *fbdev = dev_get_drvdata(dev); ++ printk("\nDisp_end_num = %d\n\n", fbdev->irq_cnt); ++ printk("\nTFT_UNDR_num = %d\n\n", fbdev->tft_undr_cnt); ++ printk("\nFrm_start_num = %d\n\n", fbdev->frm_start); ++ printk(" Pand display count=%d\n",fbdev->pan_display_count); ++ printk("timestamp.wp = %d , timestamp.rp = %d\n\n", fbdev->timestamp.wp, fbdev->timestamp.rp); ++ dump_lcdc_registers(); ++ dump_desc(fbdev); ++ return 0; ++} ++ ++static void dump_all(struct ingenicfb_device *fbdev) ++{ ++ printk("\ndisp_end_num = %d\n\n", fbdev->irq_cnt); ++ printk("\nTFT_UNDR_num = %d\n\n", fbdev->tft_undr_cnt); ++ printk("\nFrm_start_num = %d\n\n", fbdev->frm_start); ++ dump_lcdc_registers(); ++ dump_desc(fbdev); ++} ++ ++void ingenicfb_clk_enable(struct ingenicfb_device *fbdev) ++{ ++ if(fbdev->is_clk_en){ ++ return; ++ } ++ clk_prepare_enable(fbdev->pclk); ++ clk_prepare_enable(fbdev->clk); ++ fbdev->is_clk_en = 1; ++} ++ ++void ingenicfb_clk_disable(struct ingenicfb_device *fbdev) ++{ ++ if(!fbdev->is_clk_en){ ++ return; ++ } ++ fbdev->is_clk_en = 0; ++ clk_disable_unprepare(fbdev->clk); ++ clk_disable_unprepare(fbdev->pclk); ++} ++ ++ static void ++ingenicfb_videomode_to_var(struct fb_var_screeninfo *var, ++ const struct fb_videomode *mode, int lcd_type) ++{ ++ var->xres = mode->xres; ++ var->yres = mode->yres; ++ var->xres_virtual = mode->xres; ++ var->yres_virtual = mode->yres * MAX_DESC_NUM * MAX_LAYER_NUM; ++ var->xoffset = 0; ++ var->yoffset = 0; ++ var->left_margin = mode->left_margin; ++ var->right_margin = mode->right_margin; ++ var->upper_margin = mode->upper_margin; ++ var->lower_margin = mode->lower_margin; ++ var->hsync_len = mode->hsync_len; ++ var->vsync_len = mode->vsync_len; ++ var->sync = mode->sync; ++ var->vmode = mode->vmode & FB_VMODE_MASK; ++ var->pixclock = mode->pixclock; ++} ++ ++static struct fb_videomode *ingenicfb_get_mode(struct fb_var_screeninfo *var, ++ struct fb_info *info) ++{ ++ size_t i; ++ struct ingenicfb_device *fbdev = info->par; ++ struct fb_videomode *mode = fbdev->panel->modes; ++ ++ for (i = 0; i < fbdev->panel->num_modes; ++i, ++mode) { ++ if (mode->xres == var->xres && mode->yres == var->yres ++ && mode->vmode == var->vmode ++ && mode->right_margin == var->right_margin) { ++ if (fbdev->panel->lcd_type != LCD_TYPE_SLCD) { ++ if (mode->pixclock == var->pixclock) ++ return mode; ++ } else { ++ return mode; ++ } ++ } ++ } ++ ++ return NULL; ++} ++ ++static int ingenicfb_check_frm_cfg(struct fb_info *info, struct ingenicfb_frm_cfg *frm_cfg) ++{ ++ struct fb_var_screeninfo *var = &info->var; ++ struct ingenicfb_lay_cfg *lay_cfg; ++ struct fb_videomode *mode; ++ ++ mode = ingenicfb_get_mode(var, info); ++ if (mode == NULL) { ++ dev_err(info->dev, "%s get video mode failed\n", __func__); ++ return -EINVAL; ++ } ++ ++ lay_cfg = frm_cfg->lay_cfg; ++ ++ if((!lay_cfg[0].lay_en) || ++ (lay_cfg[0].lay_z_order != 1) || ++ (lay_cfg[0].lay_z_order == lay_cfg[1].lay_z_order) || ++ (lay_cfg[0].pic_width > mode->xres) || ++ (lay_cfg[0].pic_width == 0) || ++ (lay_cfg[0].pic_height > mode->yres) || ++ (lay_cfg[0].pic_height == 0) || ++ (lay_cfg[0].disp_pos_x > mode->xres) || ++ (lay_cfg[0].disp_pos_y > mode->yres) || ++ (lay_cfg[0].color > LAYER_CFG_COLOR_BGR) || ++ (lay_cfg[0].stride > 4096)) { ++ dev_err(info->dev,"%s frame[0] cfg value is err!\n",__func__); ++ return -EINVAL; ++ } ++ ++ switch (lay_cfg[0].format) { ++ case LAYER_CFG_FORMAT_RGB555: ++ case LAYER_CFG_FORMAT_ARGB1555: ++ case LAYER_CFG_FORMAT_RGB565: ++ case LAYER_CFG_FORMAT_RGB888: ++ case LAYER_CFG_FORMAT_ARGB8888: ++ case LAYER_CFG_FORMAT_YUV422: ++ break; ++ default: ++ dev_err(info->dev,"%s frame[0] cfg value is err!\n",__func__); ++ return -EINVAL; ++ } ++ ++ if(lay_cfg[1].lay_en) { ++ if((lay_cfg[1].lay_z_order != 0) || ++ (lay_cfg[1].pic_width > mode->xres) || ++ (lay_cfg[1].pic_width == 0) || ++ (lay_cfg[1].pic_height > mode->yres) || ++ (lay_cfg[1].pic_height == 0) || ++ (lay_cfg[1].disp_pos_x > mode->xres) || ++ (lay_cfg[1].disp_pos_y > mode->yres) || ++ (lay_cfg[1].color > LAYER_CFG_COLOR_BGR) || ++ (lay_cfg[1].stride > 4096)) { ++ dev_err(info->dev,"%s frame[1] cfg value is err!\n",__func__); ++ return -EINVAL; ++ } ++ switch (lay_cfg[1].format) { ++ case LAYER_CFG_FORMAT_RGB555: ++ case LAYER_CFG_FORMAT_ARGB1555: ++ case LAYER_CFG_FORMAT_RGB565: ++ case LAYER_CFG_FORMAT_RGB888: ++ case LAYER_CFG_FORMAT_ARGB8888: ++ break; ++ default: ++ dev_err(info->dev,"%s frame[0] cfg value is err!\n",__func__); ++ return -EINVAL; ++ } ++ } ++ ++ return 0; ++} ++ ++static void ingenicfb_colormode_to_var(struct fb_var_screeninfo *var, ++ struct ingenicfb_colormode *color) ++{ ++ var->bits_per_pixel = color->bits_per_pixel; ++ var->nonstd = color->nonstd; ++ var->red = color->red; ++ var->green = color->green; ++ var->blue = color->blue; ++ var->transp = color->transp; ++} ++ ++static bool cmp_var_to_colormode(struct fb_var_screeninfo *var, ++ struct ingenicfb_colormode *color) ++{ ++ bool cmp_component(struct fb_bitfield *f1, struct fb_bitfield *f2) ++ { ++ return f1->length == f2->length && ++ f1->offset == f2->offset && ++ f1->msb_right == f2->msb_right; ++ } ++ ++ if (var->bits_per_pixel == 0 || ++ var->red.length == 0 || ++ var->blue.length == 0 || ++ var->green.length == 0) ++ return 0; ++ ++ return var->bits_per_pixel == color->bits_per_pixel && ++ cmp_component(&var->red, &color->red) && ++ cmp_component(&var->green, &color->green) && ++ cmp_component(&var->blue, &color->blue) && ++ cmp_component(&var->transp, &color->transp); ++} ++ ++static int ingenicfb_check_colormode(struct fb_var_screeninfo *var, uint32_t *mode) ++{ ++ int i; ++ ++ if (var->nonstd) { ++ for (i = 0; i < ARRAY_SIZE(ingenicfb_colormodes); ++i) { ++ struct ingenicfb_colormode *m = &ingenicfb_colormodes[i]; ++ if (var->nonstd == m->nonstd) { ++ ingenicfb_colormode_to_var(var, m); ++ *mode = m->mode; ++ return 0; ++ } ++ } ++ ++ return -EINVAL; ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(ingenicfb_colormodes); ++i) { ++ struct ingenicfb_colormode *m = &ingenicfb_colormodes[i]; ++ if (cmp_var_to_colormode(var, m)) { ++ ingenicfb_colormode_to_var(var, m); ++ *mode = m->mode; ++ return 0; ++ } ++ } ++ ++ return -EINVAL; ++} ++ ++static int ingenicfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ struct fb_videomode *mode; ++ uint32_t colormode; ++ int ret; ++ ++ mode = ingenicfb_get_mode(var, info); ++ if (mode == NULL) { ++ dev_err(info->dev, "%s get video mode failed\n", __func__); ++ return -EINVAL; ++ } ++ ++ ingenicfb_videomode_to_var(var, mode, fbdev->panel->lcd_type); ++ ++ ret = ingenicfb_check_colormode(var, &colormode); ++ if(ret) { ++ dev_err(info->dev,"Check colormode failed!\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void slcd_send_mcu_command(struct ingenicfb_device *fbdev, unsigned long cmd) ++{ ++ int count = 10000; ++ uint32_t slcd_cfg; ++ ++ while ((reg_read(fbdev, DC_SLCD_ST) & DC_SLCD_ST_BUSY) && count--) { ++ udelay(10); ++ } ++ if (count < 0) { ++ dev_err(fbdev->dev, "SLCDC wait busy state wrong"); ++ } ++ ++ slcd_cfg = reg_read(fbdev, DC_SLCD_CFG); ++/* reg_write(fbdev, DC_SLCD_CFG, (slcd_cfg & ~DC_FMT_EN));*/ //notice ++ reg_write(fbdev, DC_SLCD_CMD, DC_SLCD_CMD_FLAG_CMD | (cmd & ~DC_SLCD_CMD_FLAG_MASK)); ++} ++ ++static void slcd_send_mcu_data(struct ingenicfb_device *fbdev, unsigned long data) ++{ ++ int count = 10000; ++ uint32_t slcd_cfg; ++ ++ while ((reg_read(fbdev, DC_SLCD_ST) & DC_SLCD_ST_BUSY) && count--) { ++ udelay(10); ++ } ++ if (count < 0) { ++ dev_err(fbdev->dev, "SLCDC wait busy state wrong"); ++ } ++ ++ slcd_cfg = reg_read(fbdev, DC_SLCD_CFG); ++ reg_write(fbdev, DC_SLCD_CFG, (slcd_cfg | DC_FMT_EN)); ++ reg_write(fbdev, DC_SLCD_CMD, DC_SLCD_CMD_FLAG_DATA | (data & ~DC_SLCD_CMD_FLAG_MASK)); ++} ++ ++static void slcd_send_mcu_prm(struct ingenicfb_device *fbdev, unsigned long data) ++{ ++ int count = 10000; ++ uint32_t slcd_cfg; ++ ++ while ((reg_read(fbdev, DC_SLCD_ST) & DC_SLCD_ST_BUSY) && count--) { ++ udelay(10); ++ } ++ if (count < 0) { ++ dev_err(fbdev->dev, "SLCDC wait busy state wrong"); ++ } ++ ++ slcd_cfg = reg_read(fbdev, DC_SLCD_CFG); ++/* reg_write(fbdev, DC_SLCD_CFG, (slcd_cfg & ~DC_FMT_EN));*/ //notice ++ reg_write(fbdev, DC_SLCD_CMD, DC_SLCD_CMD_FLAG_PRM | (data & ~DC_SLCD_CMD_FLAG_MASK)); ++} ++ ++static void wait_slcd_busy(void) ++{ ++ int count = 100000; ++ while ((reg_read(fbdev, DC_SLCD_ST) & DC_SLCD_ST_BUSY) ++ && count--) { ++ udelay(10); ++ } ++ if (count < 0) { ++ dev_err(fbdev->dev,"SLCDC wait busy state wrong"); ++ } ++} ++ ++static int wait_dc_state(uint32_t state, uint32_t flag) ++{ ++ unsigned long timeout = 20000; ++ while(((!(reg_read(fbdev, DC_ST) & state)) == flag) && timeout) { ++ timeout--; ++ udelay(10); ++ } ++ if(timeout <= 0) { ++ printk("LCD wait state timeout! state = %d, DC_ST = 0x%x\n", state, DC_ST); ++ return -1; ++ } ++ return 0; ++} ++ ++static void ingenicfb_slcd_mcu_init(struct fb_info *info) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ struct lcd_panel *panel = fbdev->panel; ++ struct smart_config *smart_config; ++ struct smart_lcd_data_table *data_table; ++ uint32_t length_data_table; ++ uint32_t i; ++ ++ smart_config = panel->smart_config; ++ data_table = smart_config->data_table; ++ length_data_table = smart_config->length_data_table; ++ if (panel->lcd_type != LCD_TYPE_SLCD) ++ return; ++ ++ if(length_data_table && data_table) { ++ for(i = 0; i < length_data_table; i++) { ++ switch (data_table[i].type) { ++ case SMART_CONFIG_DATA: ++ slcd_send_mcu_data(fbdev, data_table[i].value); ++ break; ++ case SMART_CONFIG_PRM: ++ slcd_send_mcu_prm(fbdev, data_table[i].value); ++ break; ++ case SMART_CONFIG_CMD: ++ slcd_send_mcu_command(fbdev, data_table[i].value); ++ break; ++ case SMART_CONFIG_UDELAY: ++ udelay(data_table[i].value); ++ break; ++ default: ++ printk("Unknow SLCD data type\n"); ++ break; ++ } ++ } ++ } ++} ++ ++static void ingenicfb_cmp_start(struct fb_info *info) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ ++ if(!(reg_read(fbdev, DC_ST) & DC_FRM_WORKING)) { ++ reg_write(fbdev, DC_FRM_CFG_CTRL, DC_FRM_START); ++ } else { ++ //dev_err(fbdev->dev, "Composer has enabled.\n"); ++ } ++} ++ ++static void ingenicfb_tft_start(struct fb_info *info) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ ++ if(!(reg_read(fbdev, DC_TFT_ST) & DC_TFT_WORKING)) { ++ reg_write(fbdev, DC_CTRL, DC_TFT_START); ++ } else { ++ dev_err(fbdev->dev, "TFT has enabled.\n"); ++ } ++} ++ ++static void ingenicfb_slcd_start(struct fb_info *info) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ ++ if(!(reg_read(fbdev, DC_SLCD_ST) & DC_SLCD_ST_BUSY)) { ++ reg_write(fbdev, DC_CTRL, DC_SLCD_START); ++ } else { ++ dev_err(fbdev->dev, "Slcd has enabled.\n"); ++ } ++} ++ ++static void ingenicfb_gen_stp_cmp(struct fb_info *info) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ ++ reg_write(fbdev, DC_CTRL, DC_GEN_STP_CMP); ++} ++ ++static void ingenicfb_qck_stp_cmp(struct fb_info *info) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ ++ reg_write(fbdev, DC_CTRL, DC_QCK_STP_CMP); ++} ++ ++static void tft_timing_init(struct fb_videomode *modes) { ++ uint32_t hps; ++ uint32_t hpe; ++ uint32_t vps; ++ uint32_t vpe; ++ uint32_t hds; ++ uint32_t hde; ++ uint32_t vds; ++ uint32_t vde; ++ ++ hps = modes->hsync_len; ++ hpe = hps + modes->left_margin + modes->xres + modes->right_margin; ++ vps = modes->vsync_len; ++ vpe = vps + modes->upper_margin + modes->yres + modes->lower_margin; ++ ++ hds = modes->hsync_len + modes->left_margin; ++ hde = hds + modes->xres; ++ vds = modes->vsync_len + modes->upper_margin; ++ vde = vds + modes->yres; ++ ++ reg_write(fbdev, DC_TFT_HSYNC, ++ (hps << DC_HPS_LBIT) | ++ (hpe << DC_HPE_LBIT)); ++ reg_write(fbdev, DC_TFT_VSYNC, ++ (vps << DC_VPS_LBIT) | ++ (vpe << DC_VPE_LBIT)); ++ reg_write(fbdev, DC_TFT_HDE, ++ (hds << DC_HDS_LBIT) | ++ (hde << DC_HDE_LBIT)); ++ reg_write(fbdev, DC_TFT_VDE, ++ (vds << DC_VDS_LBIT) | ++ (vde << DC_VDE_LBIT)); ++} ++ ++void tft_cfg_init(struct tft_config *tft_config) { ++ uint32_t tft_cfg; ++ ++ tft_cfg = reg_read(fbdev, DC_TFT_CFG); ++ if(tft_config->pix_clk_inv) { ++ tft_cfg |= DC_PIX_CLK_INV; ++ } else { ++ tft_cfg &= ~DC_PIX_CLK_INV; ++ } ++ ++ if(tft_config->de_dl) { ++ tft_cfg |= DC_DE_DL; ++ } else { ++ tft_cfg &= ~DC_DE_DL; ++ } ++ ++ if(tft_config->sync_dl) { ++ tft_cfg |= DC_SYNC_DL; ++ } else { ++ tft_cfg &= ~DC_SYNC_DL; ++ } ++ ++ tft_cfg &= ~DC_COLOR_EVEN_MASK; ++ switch(tft_config->color_even) { ++ case TFT_LCD_COLOR_EVEN_RGB: ++ tft_cfg |= DC_EVEN_RGB; ++ break; ++ case TFT_LCD_COLOR_EVEN_RBG: ++ tft_cfg |= DC_EVEN_RBG; ++ break; ++ case TFT_LCD_COLOR_EVEN_BGR: ++ tft_cfg |= DC_EVEN_BGR; ++ break; ++ case TFT_LCD_COLOR_EVEN_BRG: ++ tft_cfg |= DC_EVEN_BRG; ++ break; ++ case TFT_LCD_COLOR_EVEN_GBR: ++ tft_cfg |= DC_EVEN_GBR; ++ break; ++ case TFT_LCD_COLOR_EVEN_GRB: ++ tft_cfg |= DC_EVEN_GRB; ++ break; ++ default: ++ printk("err!\n"); ++ break; ++ } ++ ++ tft_cfg &= ~DC_COLOR_ODD_MASK; ++ switch(tft_config->color_odd) { ++ case TFT_LCD_COLOR_ODD_RGB: ++ tft_cfg |= DC_ODD_RGB; ++ break; ++ case TFT_LCD_COLOR_ODD_RBG: ++ tft_cfg |= DC_ODD_RBG; ++ break; ++ case TFT_LCD_COLOR_ODD_BGR: ++ tft_cfg |= DC_ODD_BGR; ++ break; ++ case TFT_LCD_COLOR_ODD_BRG: ++ tft_cfg |= DC_ODD_BRG; ++ break; ++ case TFT_LCD_COLOR_ODD_GBR: ++ tft_cfg |= DC_ODD_GBR; ++ break; ++ case TFT_LCD_COLOR_ODD_GRB: ++ tft_cfg |= DC_ODD_GRB; ++ break; ++ default: ++ printk("err!\n"); ++ break; ++ } ++ ++ tft_cfg &= ~DC_MODE_MASK; ++ switch(tft_config->mode) { ++ case TFT_LCD_MODE_PARALLEL_888: ++ tft_cfg |= DC_MODE_PARALLEL_888; ++ break; ++ case TFT_LCD_MODE_PARALLEL_666: ++ tft_cfg |= DC_MODE_PARALLEL_666; ++ break; ++ case TFT_LCD_MODE_PARALLEL_565: ++ tft_cfg |= DC_MODE_PARALLEL_565; ++ break; ++ case TFT_LCD_MODE_SERIAL_RGB: ++ tft_cfg |= DC_MODE_SERIAL_8BIT_RGB; ++ break; ++ case TFT_LCD_MODE_SERIAL_RGBD: ++ tft_cfg |= DC_MODE_SERIAL_8BIT_RGBD; ++ break; ++ default: ++ printk("err!\n"); ++ break; ++ } ++ reg_write(fbdev, DC_TFT_CFG, tft_cfg); ++} ++ ++static int ingenicfb_tft_set_par(struct fb_info *info) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ struct lcd_panel *panel = fbdev->panel; ++ struct lcd_panel_ops *panel_ops; ++ struct fb_videomode *mode; ++ ++ panel_ops = panel->ops; ++ ++ mode = ingenicfb_get_mode(&info->var, info); ++ if (mode == NULL) { ++ dev_err(info->dev, "%s get video mode failed\n", __func__); ++ return -EINVAL; ++ } ++ ++ tft_timing_init(mode); ++ tft_cfg_init(panel->tft_config); ++ if(panel_ops && panel_ops->enable) ++ panel_ops->enable(panel); ++ ++ return 0; ++} ++ ++static void slcd_cfg_init(struct smart_config *smart_config) { ++ uint32_t slcd_cfg; ++ ++ slcd_cfg = reg_read(fbdev, DC_SLCD_CFG); ++ ++ slcd_cfg |= DC_FRM_MD; ++ ++ if(smart_config->rdy_switch) { ++ slcd_cfg |= DC_RDY_SWITCH; ++ ++ if(smart_config->rdy_dp) { ++ slcd_cfg |= DC_RDY_DP; ++ } else { ++ slcd_cfg &= ~DC_RDY_DP; ++ } ++ if(smart_config->rdy_anti_jit) { ++ slcd_cfg |= DC_RDY_ANTI_JIT; ++ } else { ++ slcd_cfg &= ~DC_RDY_ANTI_JIT; ++ } ++ } else { ++ slcd_cfg &= ~DC_RDY_SWITCH; ++ } ++ ++ if(smart_config->te_switch) { ++ slcd_cfg |= DC_TE_SWITCH; ++ ++ if(smart_config->te_dp) { ++ slcd_cfg |= DC_TE_DP; ++ } else { ++ slcd_cfg &= ~DC_TE_DP; ++ } ++ if(smart_config->te_md) { ++ slcd_cfg |= DC_TE_MD; ++ } else { ++ slcd_cfg &= ~DC_TE_MD; ++ } ++ if(smart_config->te_anti_jit) { ++ slcd_cfg |= DC_TE_ANTI_JIT; ++ } else { ++ slcd_cfg &= ~DC_TE_ANTI_JIT; ++ } ++ } else { ++ slcd_cfg &= ~DC_TE_SWITCH; ++ } ++ ++ if(smart_config->cs_en) { ++ slcd_cfg |= DC_CS_EN; ++ ++ if(smart_config->cs_dp) { ++ slcd_cfg |= DC_CS_DP; ++ } else { ++ slcd_cfg &= ~DC_CS_DP; ++ } ++ } else { ++ slcd_cfg &= ~DC_CS_EN; ++ } ++ ++ if(smart_config->dc_md) { ++ slcd_cfg |= DC_DC_MD; ++ } else { ++ slcd_cfg &= ~DC_DC_MD; ++ } ++ ++ if(smart_config->wr_md) { ++ slcd_cfg |= DC_WR_DP; ++ } else { ++ slcd_cfg &= ~DC_WR_DP; ++ } ++ ++ slcd_cfg &= ~DC_DBI_TYPE_MASK; ++ switch(smart_config->smart_type){ ++ case SMART_LCD_TYPE_8080: ++ slcd_cfg |= DC_DBI_TYPE_B_8080; ++ break; ++ case SMART_LCD_TYPE_6800: ++ slcd_cfg |= DC_DBI_TYPE_A_6800; ++ break; ++ case SMART_LCD_TYPE_SPI_3: ++ slcd_cfg |= DC_DBI_TYPE_C_SPI_3; ++ break; ++ case SMART_LCD_TYPE_SPI_4: ++ slcd_cfg |= DC_DBI_TYPE_C_SPI_4; ++ break; ++ default: ++ printk("err!\n"); ++ break; ++ } ++ ++ slcd_cfg &= ~DC_DATA_FMT_MASK; ++ switch(smart_config->pix_fmt) { ++ case SMART_LCD_FORMAT_888: ++ slcd_cfg |= DC_DATA_FMT_888; ++ break; ++ case SMART_LCD_FORMAT_666: ++ slcd_cfg |= DC_DATA_FMT_666; ++ break; ++ case SMART_LCD_FORMAT_565: ++ slcd_cfg |= DC_DATA_FMT_565; ++ break; ++ default: ++ printk("err!\n"); ++ break; ++ } ++ ++ slcd_cfg &= ~DC_DWIDTH_MASK; ++ switch(smart_config->dwidth) { ++ case SMART_LCD_DWIDTH_8_BIT: ++ slcd_cfg |= DC_DWIDTH_8BITS; ++ break; ++ case SMART_LCD_DWIDTH_9_BIT: ++ slcd_cfg |= DC_DWIDTH_9BITS; ++ break; ++ case SMART_LCD_DWIDTH_16_BIT: ++ slcd_cfg |= DC_DWIDTH_16BITS; ++ break; ++ case SMART_LCD_DWIDTH_18_BIT: ++ slcd_cfg |= DC_DWIDTH_18BITS; ++ break; ++ case SMART_LCD_DWIDTH_24_BIT: ++ slcd_cfg |= DC_DWIDTH_24BITS; ++ break; ++ default: ++ printk("err!\n"); ++ break; ++ } ++ ++ slcd_cfg &= ~DC_CWIDTH_MASK; ++ switch(smart_config->cwidth) { ++ case SMART_LCD_CWIDTH_8_BIT: ++ slcd_cfg |= DC_CWIDTH_8BITS; ++ break; ++ case SMART_LCD_CWIDTH_9_BIT: ++ slcd_cfg |= DC_CWIDTH_9BITS; ++ break; ++ case SMART_LCD_CWIDTH_16_BIT: ++ slcd_cfg |= DC_CWIDTH_16BITS; ++ break; ++ case SMART_LCD_CWIDTH_18_BIT: ++ slcd_cfg |= DC_CWIDTH_18BITS; ++ break; ++ case SMART_LCD_CWIDTH_24_BIT: ++ slcd_cfg |= DC_CWIDTH_24BITS; ++ break; ++ default: ++ printk("err!\n"); ++ break; ++ } ++ ++ reg_write(fbdev, DC_SLCD_CFG, slcd_cfg); ++ ++ return; ++} ++ ++static int slcd_timing_init(struct lcd_panel *ingenicfb_panel) ++{ ++ uint32_t width = ingenicfb_panel->width; ++ uint32_t height = ingenicfb_panel->height; ++ uint32_t dhtime = 0; ++ uint32_t dltime = 0; ++ uint32_t chtime = 0; ++ uint32_t cltime = 0; ++ uint32_t tah = 0; ++ uint32_t tas = 0; ++ uint32_t slowtime = 0; ++ ++ /*frm_size*/ ++ reg_write(fbdev, DC_SLCD_FRM_SIZE, ++ ((width << DC_SLCD_FRM_H_SIZE_LBIT) | ++ (height << DC_SLCD_FRM_V_SIZE_LBIT))); ++ ++ /* wr duty */ ++ reg_write(fbdev, DC_SLCD_WR_DUTY, ++ ((dhtime << DC_DSTIME_LBIT) | ++ (dltime << DC_DDTIME_LBIT) | ++ (chtime << DC_CSTIME_LBIT) | ++ (cltime << DC_CDTIME_LBIT))); ++ ++ /* slcd timing */ ++ reg_write(fbdev, DC_SLCD_TIMING, ++ ((tah << DC_TAH_LBIT) | ++ (tas << DC_TAS_LBIT))); ++ ++ /* slow time */ ++ reg_write(fbdev, DC_SLCD_SLOW_TIME, slowtime); ++ ++ return 0; ++} ++ ++static int ingenicfb_slcd_set_par(struct fb_info *info) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ struct lcd_panel *panel = fbdev->panel; ++ struct lcd_panel_ops *panel_ops; ++ ++ panel_ops = panel->ops; ++ ++ slcd_cfg_init(panel->smart_config); ++ slcd_timing_init(panel); ++ ++ if(panel_ops && panel_ops->enable) ++ panel_ops->enable(panel); ++ ++ ingenicfb_slcd_mcu_init(info); ++ ++ return 0; ++} ++ ++static void csc_mode_set(struct ingenicfb_device *fbdev, csc_mode_t mode) { ++ switch(mode) { ++ case CSC_MODE_0: ++ reg_write(fbdev, DC_CSC_MULT_YRV, DC_CSC_MULT_Y_MD0 | DC_CSC_MULT_RV_MD0); ++ reg_write(fbdev, DC_CSC_MULT_GUGV, DC_CSC_MULT_GU_MD0 | DC_CSC_MULT_GV_MD0); ++ reg_write(fbdev, DC_CSC_MULT_BU, DC_CSC_MULT_BU_MD0); ++ reg_write(fbdev, DC_CSC_SUB_YUV, DC_CSC_SUB_Y_MD0 | DC_CSC_SUB_UV_MD0); ++ break; ++ case CSC_MODE_1: ++ reg_write(fbdev, DC_CSC_MULT_YRV, DC_CSC_MULT_Y_MD1 | DC_CSC_MULT_RV_MD1); ++ reg_write(fbdev, DC_CSC_MULT_GUGV, DC_CSC_MULT_GU_MD1 | DC_CSC_MULT_GV_MD1); ++ reg_write(fbdev, DC_CSC_MULT_BU, DC_CSC_MULT_BU_MD1); ++ reg_write(fbdev, DC_CSC_SUB_YUV, DC_CSC_SUB_Y_MD1 | DC_CSC_SUB_UV_MD1); ++ break; ++ case CSC_MODE_2: ++ reg_write(fbdev, DC_CSC_MULT_YRV, DC_CSC_MULT_Y_MD2 | DC_CSC_MULT_RV_MD2); ++ reg_write(fbdev, DC_CSC_MULT_GUGV, DC_CSC_MULT_GU_MD2 | DC_CSC_MULT_GV_MD2); ++ reg_write(fbdev, DC_CSC_MULT_BU, DC_CSC_MULT_BU_MD2); ++ reg_write(fbdev, DC_CSC_SUB_YUV, DC_CSC_SUB_Y_MD2 | DC_CSC_SUB_UV_MD2); ++ break; ++ case CSC_MODE_3: ++ reg_write(fbdev, DC_CSC_MULT_YRV, DC_CSC_MULT_Y_MD3 | DC_CSC_MULT_RV_MD3); ++ reg_write(fbdev, DC_CSC_MULT_GUGV, DC_CSC_MULT_GU_MD3 | DC_CSC_MULT_GV_MD3); ++ reg_write(fbdev, DC_CSC_MULT_BU, DC_CSC_MULT_BU_MD3); ++ reg_write(fbdev, DC_CSC_SUB_YUV, DC_CSC_SUB_Y_MD3 | DC_CSC_SUB_UV_MD3); ++ break; ++ default: ++ dev_err(fbdev->dev, "Set csc mode err!\n"); ++ break; ++ } ++} ++ ++static int ingenicfb_alloc_devmem(struct ingenicfb_device *fbdev) ++{ ++ struct fb_videomode *mode; ++ struct fb_info *fb = fbdev->fb; ++ uint32_t buff_size; ++ void *page; ++ uint8_t *addr; ++ dma_addr_t addr_phy; ++ int i, j; ++ ++ mode = fbdev->panel->modes; ++ if (!mode) { ++ dev_err(fbdev->dev, "Checkout video mode fail\n"); ++ return -EINVAL; ++ } ++ ++ buff_size = sizeof(struct ingenicfb_framedesc); ++ buff_size = ALIGN(buff_size, DESC_ALIGN); ++ addr = dma_alloc_coherent(fbdev->dev, buff_size * MAX_DESC_NUM, ++ &addr_phy, GFP_KERNEL); ++ if(addr == NULL) { ++ return -ENOMEM; ++ } ++ for(i = 0; i < MAX_DESC_NUM; i++) { ++ fbdev->framedesc[i] = ++ (struct ingenicfb_framedesc *)(addr + i * buff_size); ++ fbdev->framedesc_phys[i] = addr_phy + i * buff_size; ++ } ++ ++ buff_size = sizeof(struct ingenicfb_layerdesc); ++ buff_size = ALIGN(buff_size, DESC_ALIGN); ++ addr = dma_alloc_coherent(fbdev->dev, buff_size * MAX_DESC_NUM * MAX_LAYER_NUM, ++ &addr_phy, GFP_KERNEL); ++ if(addr == NULL) { ++ return -ENOMEM; ++ } ++ for(j = 0; j < MAX_DESC_NUM; j++) { ++ for(i = 0; i < MAX_LAYER_NUM; i++) { ++ fbdev->layerdesc[j][i] = (struct ingenicfb_layerdesc *) ++ (addr + i * buff_size + j * buff_size * MAX_LAYER_NUM); ++ fbdev->layerdesc_phys[j][i] = ++ addr_phy + i * buff_size + j * buff_size * MAX_LAYER_NUM; ++ } ++ } ++ ++ buff_size = mode->xres * mode->yres; ++ fbdev->frm_size = buff_size * fb->var.bits_per_pixel >> 3; ++ buff_size *= MAX_BITS_PER_PIX >> 3; ++ ++ buff_size = buff_size * MAX_DESC_NUM * MAX_LAYER_NUM; ++ fbdev->vidmem_size = PAGE_ALIGN(buff_size); ++ ++ fbdev->vidmem[0][0] = dma_alloc_coherent(fbdev->dev, fbdev->vidmem_size, ++ &fbdev->vidmem_phys[0][0], GFP_KERNEL); ++ if(fbdev->vidmem[0][0] == NULL) { ++ return -ENOMEM; ++ } ++ for (page = fbdev->vidmem[0][0]; ++ page < fbdev->vidmem[0][0] + PAGE_ALIGN(fbdev->vidmem_size); ++ page += PAGE_SIZE) { ++ SetPageReserved(virt_to_page(page)); ++ } ++ ++ return 0; ++} ++ ++#define DPU_WAIT_IRQ_TIME 2000 ++static int ingenicfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) ++{ ++ void __user *argp = (void __user *)arg; ++ struct ingenicfb_device *fbdev = info->par; ++ int ret; ++ csc_mode_t csc_mode; ++ int value; ++ int tmp; ++ int i; ++ ++ switch (cmd) { ++ case JZFB_CMP_START: ++ ingenicfb_cmp_start(info); ++ break; ++ case JZFB_TFT_START: ++ ingenicfb_tft_start(info); ++ break; ++ case JZFB_SLCD_START: ++ slcd_send_mcu_command(fbdev, fbdev->panel->smart_config->write_gram_cmd); ++ wait_slcd_busy(); ++ ingenicfb_slcd_start(info); ++ break; ++ case JZFB_GEN_STP_CMP: ++ ingenicfb_gen_stp_cmp(info); ++ wait_dc_state(DC_WORKING, 0); ++ break; ++ case JZFB_QCK_STP_CMP: ++ ingenicfb_qck_stp_cmp(info); ++ wait_dc_state(DC_WORKING, 0); ++ break; ++ case JZFB_DUMP_LCDC_REG: ++ dump_all(info->par); ++ break; ++ case JZFB_SET_VSYNCINT: ++ if (unlikely(copy_from_user(&value, argp, sizeof(int)))) ++ return -EFAULT; ++ tmp = reg_read(fbdev, DC_INTC); ++ if (value) { ++ if(fbdev->panel->lcd_type == LCD_TYPE_SLCD && ++ !fbdev->slcd_continua) { ++ reg_write(fbdev, DC_CLR_ST, DC_CLR_DISP_END); ++ reg_write(fbdev, DC_INTC, tmp | DC_EOD_MSK); ++ } else { ++ reg_write(fbdev, DC_CLR_ST, DC_CLR_FRM_START); ++ reg_write(fbdev, DC_INTC, tmp | DC_SOF_MSK); ++ } ++ } else { ++ if(fbdev->panel->lcd_type == LCD_TYPE_SLCD && ++ !fbdev->slcd_continua) { ++ reg_write(fbdev, DC_INTC, tmp & ~DC_EOD_MSK); ++ } else { ++ reg_write(fbdev, DC_INTC, tmp & ~DC_SOF_MSK); ++ } ++ } ++ break; ++ case FBIO_WAITFORVSYNC: ++ unlock_fb_info(info); ++ ret = wait_event_interruptible_timeout(fbdev->vsync_wq, ++ fbdev->timestamp.wp != fbdev->timestamp.rp, ++ msecs_to_jiffies(DPU_WAIT_IRQ_TIME)); ++ lock_fb_info(info); ++ if(ret == 0) { ++ dev_err(info->dev, "DPU wait vsync timeout!\n"); ++ return -EFAULT; ++ } ++ ++ ret = copy_to_user(argp, fbdev->timestamp.value + fbdev->timestamp.rp, ++ sizeof(u64)); ++ fbdev->timestamp.rp = (fbdev->timestamp.rp + 1) % TIMESTAMP_CAP; ++ ++ if (unlikely(ret)) ++ return -EFAULT; ++ break; ++ case JZFB_PUT_FRM_CFG: ++ ret = ingenicfb_check_frm_cfg(info, (struct ingenicfb_frm_cfg *)argp); ++ if(ret) { ++ return ret; ++ } ++ copy_from_user(&fbdev->current_frm_mode.frm_cfg, ++ (void *)argp, ++ sizeof(struct ingenicfb_frm_cfg)); ++ ++ for (i = 0; i < ARRAY_SIZE(ingenicfb_colormodes); ++i) { ++ struct ingenicfb_colormode *m = &ingenicfb_colormodes[i]; ++ if (m->mode == fbdev->current_frm_mode.frm_cfg.lay_cfg[0].format) { ++ ingenicfb_colormode_to_var(&info->var, m); ++ break; ++ } ++ } ++ ++ for(i = 0; i < MAX_DESC_NUM; i++) { ++ fbdev->current_frm_mode.update_st[i] = FRAME_CFG_NO_UPDATE; ++ } ++ break; ++ case JZFB_GET_FRM_CFG: ++ copy_to_user((void *)argp, ++ &fbdev->current_frm_mode.frm_cfg, ++ sizeof(struct ingenicfb_frm_cfg)); ++ break; ++ case JZFB_SET_CSC_MODE: ++ if (unlikely(copy_from_user(&csc_mode, argp, sizeof(csc_mode_t)))) ++ return -EFAULT; ++ csc_mode_set(fbdev, csc_mode); ++ break; ++ default: ++ printk("Command:%x Error!\n",cmd); ++ break; ++ } ++ return 0; ++} ++ ++static int ingenicfb_mmap(struct fb_info *info, struct vm_area_struct *vma) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ unsigned long start; ++ unsigned long off; ++ u32 len; ++ ++ off = vma->vm_pgoff << PAGE_SHIFT; ++ ++ /* frame buffer memory */ ++ start = fbdev->fb->fix.smem_start; ++ len = PAGE_ALIGN((start & ~PAGE_MASK) + fbdev->fb->fix.smem_len); ++ start &= PAGE_MASK; ++ ++ if ((vma->vm_end - vma->vm_start + off) > len) ++ return -EINVAL; ++ off += start; ++ ++ vma->vm_pgoff = off >> PAGE_SHIFT; ++ vma->vm_flags |= VM_IO; ++ ++ pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK; ++ /* Write-Acceleration */ ++ pgprot_val(vma->vm_page_prot) |= _CACHE_CACHABLE_WA; ++ ++ if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, ++ vma->vm_end - vma->vm_start, vma->vm_page_prot)) ++ { ++ return -EAGAIN; ++ } ++ ++ return 0; ++} ++ ++static void ingenicfb_set_vsync_value(struct ingenicfb_device *ingenicfb) ++{ ++ fbdev->vsync_skip_map = (fbdev->vsync_skip_map >> 1 | ++ fbdev->vsync_skip_map << 9) & 0x3ff; ++ if(likely(fbdev->vsync_skip_map & 0x1)) { ++ fbdev->timestamp.value[fbdev->timestamp.wp] = ++ ktime_to_ns(ktime_get()); ++ fbdev->timestamp.wp = (fbdev->timestamp.wp + 1) % TIMESTAMP_CAP; ++ wake_up_interruptible(&fbdev->vsync_wq); ++ } ++} ++ ++static int ingenicfb_update_frm_msg(struct fb_info *info) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ struct ingenicfb_frmdesc_msg *desc_msg_done; ++ struct ingenicfb_frmdesc_msg *desc_msg_reday; ++ ++ if(list_empty(&fbdev->desc_run_list)) { ++ printk(KERN_DEBUG "%s %d dpu irq run list empty\n", __func__, __LINE__); ++ return 0; ++ } ++ desc_msg_done = list_first_entry(&fbdev->desc_run_list, ++ struct ingenicfb_frmdesc_msg, list); ++ if(desc_msg_done->state != DESC_ST_RUNING) { ++ dev_err(info->dev, "%s Desc state is err!!\n", __func__); ++ } ++ ++ list_del(&desc_msg_done->list); ++ ++ fbdev->frmdesc_msg[desc_msg_done->index].state = DESC_ST_AVAILABLE; ++ fbdev->vsync_skip_map = (fbdev->vsync_skip_map >> 1 | ++ fbdev->vsync_skip_map << 9) & 0x3ff; ++ if(likely(fbdev->vsync_skip_map & 0x1)) { ++ fbdev->timestamp.value[fbdev->timestamp.wp] = ++ ktime_to_ns(ktime_get()); ++ fbdev->timestamp.wp = (fbdev->timestamp.wp + 1) % TIMESTAMP_CAP; ++ wake_up_interruptible(&fbdev->vsync_wq); ++ } ++ ++ if(!(reg_read(fbdev, DC_ST) & DC_WORKING) ++ && !(list_empty(&fbdev->desc_run_list))) { ++ desc_msg_reday = list_first_entry(&fbdev->desc_run_list, ++ struct ingenicfb_frmdesc_msg, list); ++ reg_write(fbdev, DC_FRM_CFG_ADDR, desc_msg_reday->addr_phy); ++ ingenicfb_cmp_start(info); ++ ingenicfb_slcd_start(info); ++ } ++ ++ return 0; ++} ++ ++static irqreturn_t ingenicfb_irq_handler(int irq, void *data) ++{ ++ unsigned int irq_flag; ++ struct ingenicfb_device *fbdev = (struct ingenicfb_device *)data; ++ ++ spin_lock(&fbdev->irq_lock); ++ irq_flag = reg_read(fbdev, DC_INT_FLAG); ++ if(likely(irq_flag & DC_ST_FRM_START)) { ++ reg_write(fbdev, DC_CLR_ST, DC_CLR_FRM_START); ++ fbdev->frm_start++; ++ if((fbdev->panel->lcd_type == LCD_TYPE_SLCD && fbdev->slcd_continua) || ++ fbdev->panel->lcd_type == LCD_TYPE_TFT) { ++ ingenicfb_set_vsync_value(fbdev); ++ } ++ spin_unlock(&fbdev->irq_lock); ++ return IRQ_HANDLED; ++ } ++ ++ if(likely(irq_flag & DC_DISP_END)) { ++ reg_write(fbdev, DC_CLR_ST, DC_CLR_DISP_END); ++ fbdev->irq_cnt++; ++ if(fbdev->panel->lcd_type == LCD_TYPE_SLCD && !fbdev->slcd_continua) { ++ ingenicfb_update_frm_msg(fbdev->fb); ++ } ++ spin_unlock(&fbdev->irq_lock); ++ return IRQ_HANDLED; ++ } ++ ++ if(unlikely(irq_flag & DC_STOP_DISP_ACK)) { ++ reg_write(fbdev, DC_CLR_ST, DC_CLR_STOP_DISP_ACK); ++ wake_up_interruptible(&fbdev->gen_stop_wq); ++ spin_unlock(&fbdev->irq_lock); ++ return IRQ_HANDLED; ++ } ++ ++ if(unlikely(irq_flag & DC_TFT_UNDR)) { ++ reg_write(fbdev, DC_CLR_ST, DC_CLR_TFT_UNDR); ++ fbdev->tft_undr_cnt++; ++#ifdef CONFIG_FPGA_TEST ++ if (!(fbdev->tft_undr_cnt % 100000)) //FIXME: ++#endif ++ printk("\nTFT_UNDR_num = %d\n\n", fbdev->tft_undr_cnt); ++ spin_unlock(&fbdev->irq_lock); ++ return IRQ_HANDLED; ++ } ++ ++ dev_err(fbdev->dev, "DPU irq nothing do, please check!!!\n"); ++ spin_unlock(&fbdev->irq_lock); ++ return IRQ_HANDLED; ++} ++ ++static inline uint32_t convert_color_to_hw(unsigned val, struct fb_bitfield *bf) ++{ ++ return (((val << bf->length) + 0x7FFF - val) >> 16) << bf->offset; ++} ++ ++static int ingenicfb_setcolreg(unsigned regno, unsigned red, unsigned green, ++ unsigned blue, unsigned transp, struct fb_info *fb) ++{ ++ if (regno >= 16) ++ return -EINVAL; ++ ++ ((uint32_t *)(fb->pseudo_palette))[regno] = ++ convert_color_to_hw(red, &fb->var.red) | ++ convert_color_to_hw(green, &fb->var.green) | ++ convert_color_to_hw(blue, &fb->var.blue) | ++ convert_color_to_hw(transp, &fb->var.transp); ++ ++ return 0; ++} ++ ++static void ingenicfb_display_v_color_bar(struct fb_info *info) ++{ ++ int i, j; ++ int w, h; ++ int bpp; ++ unsigned short *p16; ++ unsigned int *p32; ++ struct ingenicfb_device *fbdev = info->par; ++ struct fb_videomode *mode = fbdev->panel->modes; ++ ++ if (!mode) { ++ dev_err(fbdev->dev, "%s, video mode is NULL\n", __func__); ++ return; ++ } ++ if (!fbdev->vidmem_phys[fbdev->current_frm_desc][0]) { ++ dev_err(fbdev->dev, "Not allocate frame buffer yet\n"); ++ return; ++ } ++ if (!fbdev->vidmem[fbdev->current_frm_desc][0]) ++ fbdev->vidmem[fbdev->current_frm_desc][0] = ++ (void *)phys_to_virt(fbdev->vidmem_phys[fbdev->current_frm_desc][0]); ++ p16 = (unsigned short *)fbdev->vidmem[fbdev->current_frm_desc][0]; ++ p32 = (unsigned int *)fbdev->vidmem[fbdev->current_frm_desc][0]; ++ w = mode->xres; ++ h = mode->yres; ++ bpp = info->var.bits_per_pixel; ++ ++ dev_info(info->dev, ++ "LCD V COLOR BAR w,h,bpp(%d,%d,%d) fbdev->vidmem[0]=%p\n", w, h, ++ bpp, fbdev->vidmem[fbdev->current_frm_desc][0]); ++ ++ for (i = 0; i < h; i++) { ++ for (j = 0; j < w; j++) { ++ short c16; ++ int c32 = 0; ++ switch ((j / 10) % 4) { ++ case 0: ++ c16 = 0xF800; ++ c32 = 0xFFFF0000; ++ break; ++ case 1: ++ c16 = 0x07C0; ++ c32 = 0xFF00FF00; ++ break; ++ case 2: ++ c16 = 0x001F; ++ c32 = 0xFF0000FF; ++ break; ++ default: ++ c16 = 0xFFFF; ++ c32 = 0xFFFFFFFF; ++ break; ++ } ++ switch (bpp) { ++ case 18: ++ case 24: ++ case 32: ++ *p32++ = c32; ++ break; ++ default: ++ *p16++ = c16; ++ } ++ } ++ if (w % PIXEL_ALIGN) { ++ switch (bpp) { ++ case 18: ++ case 24: ++ case 32: ++ p32 += (ALIGN(mode->xres, PIXEL_ALIGN) - w); ++ break; ++ default: ++ p16 += (ALIGN(mode->xres, PIXEL_ALIGN) - w); ++ break; ++ } ++ } ++ } ++} ++ ++static void ingenicfb_display_h_color_bar(struct fb_info *info) ++{ ++ int i, j; ++ int w, h; ++ int bpp; ++ unsigned short *p16; ++ unsigned int *p32; ++ struct ingenicfb_device *fbdev = info->par; ++ struct fb_videomode *mode = fbdev->panel->modes; ++ ++ if (!mode) { ++ dev_err(fbdev->dev, "%s, video mode is NULL\n", __func__); ++ return; ++ } ++ if (!fbdev->vidmem_phys[fbdev->current_frm_desc][0]) { ++ dev_err(fbdev->dev, "Not allocate frame buffer yet\n"); ++ return; ++ } ++ if (!fbdev->vidmem[fbdev->current_frm_desc][0]) ++ fbdev->vidmem[fbdev->current_frm_desc][0] = ++ (void *)phys_to_virt(fbdev->vidmem_phys[fbdev->current_frm_desc][0]); ++ p16 = (unsigned short *)fbdev->vidmem[fbdev->current_frm_desc][0]; ++ p32 = (unsigned int *)fbdev->vidmem[fbdev->current_frm_desc][0]; ++ w = mode->xres; ++ h = mode->yres; ++ bpp = info->var.bits_per_pixel; ++ ++ dev_info(info->dev, ++ "LCD H COLOR BAR w,h,bpp(%d,%d,%d), fbdev->vidmem[0]=%p\n", w, h, ++ bpp, fbdev->vidmem[fbdev->current_frm_desc][0]); ++ ++ for (i = 0; i < h; i++) { ++ for (j = 0; j < w; j++) { ++ short c16; ++ int c32; ++ switch ((i / 10) % 4) { ++ case 0: ++ c16 = 0xF800; ++ c32 = 0x00FF0000; ++ break; ++ case 1: ++ c16 = 0x07C0; ++ c32 = 0x0000FF00; ++ break; ++ case 2: ++ c16 = 0x001F; ++ c32 = 0x000000FF; ++ break; ++ default: ++ c16 = 0xFFFF; ++ c32 = 0xFFFFFFFF; ++ break; ++ } ++ switch (bpp) { ++ case 18: ++ case 24: ++ case 32: ++ *p32++ = c32; ++ break; ++ default: ++ *p16++ = c16; ++ } ++ } ++ if (w % PIXEL_ALIGN) { ++ switch (bpp) { ++ case 18: ++ case 24: ++ case 32: ++ p32 += (ALIGN(mode->xres, PIXEL_ALIGN) - w); ++ break; ++ default: ++ p16 += (ALIGN(mode->xres, PIXEL_ALIGN) - w); ++ break; ++ } ++ } ++ } ++} ++ ++int lcd_display_inited_by_uboot( void ) ++{ ++ if (*(unsigned int*)(0xb3050000 + DC_ST) & DC_WORKING) ++ uboot_inited = 1; ++ else ++ uboot_inited = 0; ++ return uboot_inited; ++} ++ ++static int slcd_pixel_refresh_times(struct fb_info *info) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ struct lcd_panel *panel = fbdev->panel; ++ struct smart_config *smart_config = panel->smart_config; ++ ++ switch(smart_config->smart_type){ ++ case SMART_LCD_TYPE_8080: ++ case SMART_LCD_TYPE_6800: ++ break; ++ case SMART_LCD_TYPE_SPI_3: ++ return 9; ++ case SMART_LCD_TYPE_SPI_4: ++ return 8; ++ default: ++ printk("%s %d err!\n",__func__,__LINE__); ++ break; ++ } ++ ++ switch(smart_config->pix_fmt) { ++ case SMART_LCD_FORMAT_888: ++ return 3; ++ case SMART_LCD_FORMAT_565: ++ return 2; ++ default: ++ printk("%s %d err!\n",__func__,__LINE__); ++ break; ++ } ++ ++ return 1; ++} ++ ++static int refresh_pixclock_auto_adapt(struct fb_info *info) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ struct lcd_panel *panel = fbdev->panel; ++ struct fb_var_screeninfo *var = &info->var; ++ struct fb_videomode *mode; ++ uint16_t hds, vds; ++ uint16_t hde, vde; ++ uint16_t ht, vt; ++ unsigned long rate; ++ ++ mode = panel->modes; ++ if (mode == NULL) { ++ dev_err(fbdev->dev, "%s get video mode failed\n", __func__); ++ return -EINVAL; ++ } ++ ++ hds = mode->hsync_len + mode->left_margin; ++ hde = hds + mode->xres; ++ ht = hde + mode->right_margin; ++ ++ vds = mode->vsync_len + mode->upper_margin; ++ vde = vds + mode->yres; ++ vt = vde + mode->lower_margin; ++ ++ if(mode->refresh){ ++ rate = mode->refresh * vt * ht; ++ if(fbdev->panel->lcd_type == LCD_TYPE_SLCD) { ++ /* pixclock frequency is wr 2.5 times */ ++ rate = rate * 5 / 2; ++ rate *= slcd_pixel_refresh_times(info); ++ } ++ mode->pixclock = KHZ2PICOS(rate / 1000); ++ ++ var->pixclock = mode->pixclock; ++ }else if(mode->pixclock){ ++ rate = PICOS2KHZ(mode->pixclock) * 1000; ++ mode->refresh = rate / vt / ht; ++ }else{ ++ dev_err(fbdev->dev,"%s error:lcd important config info is absenced\n",__func__); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static void ingenicfb_enable(struct fb_info *info) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ struct lcd_panel *panel = fbdev->panel; ++ ++ mutex_lock(&fbdev->lock); ++ if (fbdev->is_lcd_en) { ++ mutex_unlock(&fbdev->lock); ++ return; ++ } ++ ++ ingenicfb_cmp_start(info); ++ ++ if(panel->lcd_type == LCD_TYPE_SLCD) { ++ slcd_send_mcu_command(fbdev, panel->smart_config->write_gram_cmd); ++ wait_slcd_busy(); ++ ingenicfb_slcd_start(info); ++ } else { ++ ingenicfb_tft_start(info); ++ } ++ ++ fbdev->is_lcd_en = 1; ++ mutex_unlock(&fbdev->lock); ++ return; ++} ++ ++static void ingenicfb_disable(struct fb_info *info, stop_mode_t stop_md) ++{ ++ mutex_lock(&fbdev->lock); ++ if (!fbdev->is_lcd_en) { ++ mutex_unlock(&fbdev->lock); ++ return; ++ } ++ ++ if(stop_md == QCK_STOP) { ++ reg_write(fbdev, DC_CTRL, DC_QCK_STP_CMP); ++ wait_dc_state(DC_WORKING, 0); ++ } else { ++ reg_write(fbdev, DC_CTRL, DC_GEN_STP_CMP); ++ wait_event_interruptible(fbdev->gen_stop_wq, ++ !(reg_read(fbdev, DC_ST) & DC_WORKING)); ++ } ++ ++ fbdev->is_lcd_en = 0; ++ mutex_unlock(&fbdev->lock); ++} ++ ++static int ingenicfb_desc_init(struct fb_info *info, int frm_num) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ struct fb_videomode *mode; ++ struct ingenicfb_frm_mode *frm_mode; ++ struct ingenicfb_frm_cfg *frm_cfg; ++ struct ingenicfb_lay_cfg *lay_cfg; ++ struct fb_var_screeninfo *var = &info->var; ++ struct ingenicfb_framedesc **framedesc; ++ int frm_num_mi, frm_num_ma; ++ int frm_size; ++ int i, j; ++ int ret = 0; ++ ++ mode = ingenicfb_get_mode(var, info); ++ if (mode == NULL) { ++ dev_err(info->dev, "%s get video mode failed\n", __func__); ++ return -EINVAL; ++ } ++ ++ framedesc = fbdev->framedesc; ++ frm_mode = &fbdev->current_frm_mode; ++ frm_cfg = &frm_mode->frm_cfg; ++ lay_cfg = frm_cfg->lay_cfg; ++ ++ ret = ingenicfb_check_frm_cfg(info, frm_cfg); ++ if(ret) { ++ dev_err(info->dev, "%s configure framedesc[%d] error!\n", __func__, frm_num); ++ return ret; ++ } ++ ++ if(frm_num == FRAME_CFG_ALL_UPDATE) { ++ frm_num_mi = 0; ++ frm_num_ma = MAX_DESC_NUM; ++ } else { ++ if(frm_num < 0 || frm_num > MAX_DESC_NUM) { ++ dev_err(info->dev, "framedesc num err!\n"); ++ return -EINVAL; ++ } ++ frm_num_mi = frm_num; ++ frm_num_ma = frm_num + 1; ++ } ++ ++ for(i = frm_num_mi; i < frm_num_ma; i++) { ++ framedesc[i]->FrameNextCfgAddr = fbdev->framedesc_phys[i]; ++ framedesc[i]->FrameSize.b.width = mode->xres; ++ framedesc[i]->FrameSize.b.height = mode->yres; ++ framedesc[i]->FrameCtrl.d32 = FRAME_CTRL_DEFAULT_SET; ++ framedesc[i]->Layer0CfgAddr = fbdev->layerdesc_phys[i][0]; ++ framedesc[i]->Layer1CfgAddr = fbdev->layerdesc_phys[i][1]; ++ framedesc[i]->LayCfgEn.b.lay0_en = lay_cfg[0].lay_en; ++ framedesc[i]->LayCfgEn.b.lay1_en = lay_cfg[1].lay_en; ++ framedesc[i]->LayCfgEn.b.lay0_z_order = lay_cfg[0].lay_z_order; ++ framedesc[i]->LayCfgEn.b.lay1_z_order = lay_cfg[1].lay_z_order; ++ if(fbdev->panel->lcd_type == LCD_TYPE_SLCD && !fbdev->slcd_continua) { ++ framedesc[i]->FrameCtrl.b.stop = 1; ++ framedesc[i]->InterruptControl.d32 = DC_EOD_MSK; ++ } else { ++ framedesc[i]->FrameCtrl.b.stop = 0; ++ framedesc[i]->InterruptControl.d32 = DC_SOF_MSK; ++ } ++ } ++ ++ frm_size = mode->xres * mode->yres; ++ fbdev->frm_size = frm_size * info->var.bits_per_pixel >> 3; ++ info->screen_size = fbdev->frm_size; ++ ++ for(i = frm_num_mi; i < frm_num_ma; i++) { ++ for(j =0; j < MAX_LAYER_NUM; j++) { ++ if(!lay_cfg[j].lay_en) ++ continue; ++ fbdev->layerdesc[i][j]->LayerSize.b.width = lay_cfg[j].pic_width; ++ fbdev->layerdesc[i][j]->LayerSize.b.height = lay_cfg[j].pic_height; ++ fbdev->layerdesc[i][j]->LayerPos.b.x_pos = lay_cfg[j].disp_pos_x; ++ fbdev->layerdesc[i][j]->LayerPos.b.y_pos = lay_cfg[j].disp_pos_y; ++ fbdev->layerdesc[i][j]->LayerCfg.b.g_alpha_en = lay_cfg[j].g_alpha_en; ++ fbdev->layerdesc[i][j]->LayerCfg.b.g_alpha = lay_cfg[j].g_alpha_val; ++ fbdev->layerdesc[i][j]->LayerCfg.b.color = lay_cfg[j].color; ++ fbdev->layerdesc[i][j]->LayerCfg.b.domain_multi = lay_cfg[j].domain_multi; ++ fbdev->layerdesc[i][j]->LayerCfg.b.format = lay_cfg[j].format; ++ fbdev->layerdesc[i][j]->LayerStride = lay_cfg[j].stride; ++ fbdev->vidmem_phys[i][j] = fbdev->vidmem_phys[0][0] + ++ i * fbdev->frm_size + ++ j * fbdev->frm_size * MAX_DESC_NUM; ++ fbdev->vidmem[i][j] = fbdev->vidmem[0][0] + ++ i * fbdev->frm_size + ++ j * fbdev->frm_size * MAX_DESC_NUM; ++ fbdev->layerdesc[i][j]->LayerBufferAddr = fbdev->vidmem_phys[i][j]; ++ } ++ } ++ ++ for(i = frm_num_mi; i < frm_num_ma; i++) { ++ frm_mode->update_st[i] = FRAME_CFG_UPDATE; ++ } ++ ++ return 0; ++} ++ ++static int ingenicfb_update_frm_mode(struct fb_info *info) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ struct fb_videomode *mode; ++ struct ingenicfb_frm_mode *frm_mode; ++ struct ingenicfb_frm_cfg *frm_cfg; ++ struct ingenicfb_lay_cfg *lay_cfg; ++ struct fb_var_screeninfo *var = &info->var; ++ int i; ++ ++ mode = ingenicfb_get_mode(var, info); ++ if (mode == NULL) { ++ dev_err(info->dev, "%s get video mode failed\n", __func__); ++ return -EINVAL; ++ } ++ ++ frm_mode = &fbdev->current_frm_mode; ++ frm_cfg = &frm_mode->frm_cfg; ++ lay_cfg = frm_cfg->lay_cfg; ++ ++ /*Only set layer0 work*/ ++ lay_cfg[0].lay_en = 1; ++ lay_cfg[0].lay_z_order = 1; ++ lay_cfg[1].lay_en = 0; ++ lay_cfg[1].lay_z_order = 0; ++ ++ for(i = 0; i < MAX_LAYER_NUM; i++) { ++ lay_cfg[i].pic_width = mode->xres; ++ lay_cfg[i].pic_height = mode->yres; ++ lay_cfg[i].disp_pos_x = 0; ++ lay_cfg[i].disp_pos_y = 0; ++ lay_cfg[i].g_alpha_en = 0; ++ lay_cfg[i].g_alpha_val = 0xff; ++ lay_cfg[i].color = ingenicfb_colormodes[0].color; ++ lay_cfg[i].format = ingenicfb_colormodes[0].mode; ++ lay_cfg[i].domain_multi = 1; ++ lay_cfg[i].stride = mode->xres; ++ } ++ ++ fbdev->current_frm_desc = 0; ++ ++ return 0; ++} ++ ++static void disp_common_init(struct lcd_panel *ingenicfb_panel) { ++ uint32_t disp_com; ++ ++ disp_com = reg_read(fbdev, DC_DISP_COM); ++ disp_com &= ~DC_DP_IF_SEL; ++ if(ingenicfb_panel->lcd_type == LCD_TYPE_SLCD) { ++ disp_com |= DC_DISP_COM_SLCD; ++ } else { ++ disp_com |= DC_DISP_COM_TFT; ++ } ++ if(ingenicfb_panel->dither_enable) { ++ disp_com |= DC_DP_DITHER_EN; ++ disp_com &= ~DC_DP_DITHER_DW_MASK; ++ disp_com |= ingenicfb_panel->dither.dither_red ++ << DC_DP_DITHER_DW_RED_LBIT; ++ disp_com |= ingenicfb_panel->dither.dither_green ++ << DC_DP_DITHER_DW_GREEN_LBIT; ++ disp_com |= ingenicfb_panel->dither.dither_blue ++ << DC_DP_DITHER_DW_BLUE_LBIT; ++ } else { ++ disp_com &= ~DC_DP_DITHER_EN; ++ } ++ reg_write(fbdev, DC_DISP_COM, disp_com); ++} ++ ++static void common_cfg_init(void) ++{ ++ unsigned com_cfg = 0; ++ ++ com_cfg = reg_read(fbdev, DC_COM_CONFIG); ++ /*Keep COM_CONFIG reg first bit 0 */ ++ com_cfg &= ~DC_OUT_SEL; ++ ++ /* set burst length 32*/ ++ com_cfg &= ~DC_BURST_LEN_BDMA_MASK; ++ com_cfg |= DC_BURST_LEN_BDMA_32; ++ ++ reg_write(fbdev, DC_COM_CONFIG, com_cfg); ++} ++ ++static int ingenicfb_set_fix_par(struct fb_info *info) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ struct lcd_panel *panel = fbdev->panel; ++ unsigned int intc; ++ unsigned int disp_com; ++ unsigned int is_lcd_en; ++ ++ mutex_lock(&fbdev->lock); ++ is_lcd_en = fbdev->is_lcd_en; ++ mutex_unlock(&fbdev->lock); ++ ++ ingenicfb_disable(info, GEN_STOP); ++ ++ disp_common_init(panel); ++ ++ common_cfg_init(); ++ ++ reg_write(fbdev, DC_CLR_ST, 0x01FFFFFE); ++ ++ disp_com = reg_read(fbdev, DC_DISP_COM); ++ if (panel->lcd_type == LCD_TYPE_SLCD) { ++ reg_write(fbdev, DC_DISP_COM, disp_com | DC_DISP_COM_SLCD); ++ ingenicfb_slcd_set_par(info); ++ } else { ++ reg_write(fbdev, DC_DISP_COM, disp_com | DC_DISP_COM_TFT); ++ ingenicfb_tft_set_par(info); ++ } ++ /* disp end gen_stop tft_under frm_start frm_end */ ++// intc = DC_EOD_MSK | DC_SDA_MSK | DC_UOT_MSK | DC_SOF_MSK | DC_EOF_MSK; ++ intc = DC_EOD_MSK | DC_SDA_MSK | DC_UOT_MSK | DC_SOF_MSK; ++ if (panel->lcd_type == LCD_TYPE_SLCD && !fbdev->slcd_continua) { ++ intc = DC_EOD_MSK | DC_SDA_MSK | DC_UOT_MSK; ++ } else { ++ intc = DC_SDA_MSK | DC_UOT_MSK | DC_SOF_MSK; ++ } ++ reg_write(fbdev, DC_INTC, intc); ++ ++ if(is_lcd_en) { ++ ingenicfb_enable(info); ++ } ++ ++ return 0; ++} ++ ++static int ingenicfb_set_par(struct fb_info *info) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ struct fb_var_screeninfo *var = &info->var; ++ struct fb_videomode *mode; ++ struct ingenicfb_frmdesc_msg *desc_msg; ++ unsigned long flags; ++ uint32_t colormode; ++ int ret; ++ int i; ++ ++ mode = ingenicfb_get_mode(var, info); ++ if (mode == NULL) { ++ dev_err(info->dev, "%s get video mode failed\n", __func__); ++ return -EINVAL; ++ } ++ info->mode = mode; ++ ++ ret = ingenicfb_check_colormode(var, &colormode); ++ if(ret) { ++ dev_err(info->dev,"Check colormode failed!\n"); ++ return ret; ++ } ++ if(colormode != LAYER_CFG_FORMAT_YUV422) { ++ for(i = 0; i < MAX_LAYER_NUM; i++) { ++ fbdev->current_frm_mode.frm_cfg.lay_cfg[i].format = colormode; ++ } ++ } else { ++ fbdev->current_frm_mode.frm_cfg.lay_cfg[0].format = colormode; ++ } ++ ++ ret = ingenicfb_desc_init(info, FRAME_CFG_ALL_UPDATE); ++ if(ret) { ++ dev_err(fbdev->dev, "Desc init err!\n"); ++ return ret; ++ } ++ ++ spin_lock_irqsave(&fbdev->irq_lock, flags); ++ if(fbdev->panel->lcd_type == LCD_TYPE_SLCD && !fbdev->slcd_continua) { ++ if(!list_empty(&fbdev->desc_run_list)) { ++ desc_msg = list_first_entry(&fbdev->desc_run_list, ++ struct ingenicfb_frmdesc_msg, list); ++ } else { ++ desc_msg = &fbdev->frmdesc_msg[fbdev->current_frm_desc]; ++ desc_msg->addr_virt->FrameCtrl.b.stop = 1; ++ desc_msg->state = DESC_ST_RUNING; ++ list_add_tail(&desc_msg->list, &fbdev->desc_run_list); ++ } ++ reg_write(fbdev, DC_FRM_CFG_ADDR, desc_msg->addr_phy); ++ } else { ++ reg_write(fbdev, DC_FRM_CFG_ADDR, fbdev->framedesc_phys[fbdev->current_frm_desc]); ++ } ++ spin_unlock_irqrestore(&fbdev->irq_lock, flags); ++ ++ return 0; ++} ++ ++int test_pattern(struct ingenicfb_device *fbdev) ++{ ++ int ret; ++ ++ ingenicfb_disable(fbdev->fb, QCK_STOP); ++ ingenicfb_display_h_color_bar(fbdev->fb); ++ fbdev->current_frm_desc = 0; ++ ingenicfb_set_fix_par(fbdev->fb); ++ ret = ingenicfb_set_par(fbdev->fb); ++ if(ret) { ++ dev_err(fbdev->dev, "Set par failed!\n"); ++ return ret; ++ } ++ ingenicfb_enable(fbdev->fb); ++ ++ return 0; ++} ++ ++static inline int timeval_sub_to_us(struct timeval lhs, ++ struct timeval rhs) ++{ ++ int sec, usec; ++ sec = lhs.tv_sec - rhs.tv_sec; ++ usec = lhs.tv_usec - rhs.tv_usec; ++ ++ return (sec*1000000 + usec); ++} ++ ++static inline int time_us2ms(int us) ++{ ++ return (us/1000); ++} ++ ++static void calculate_frame_rate(void) ++{ ++ static struct timeval time_now, time_last; ++ unsigned int interval_in_us; ++ unsigned int interval_in_ms; ++ static unsigned int fpsCount = 0; ++ ++ switch(showFPS){ ++ case 1: ++ fpsCount++; ++ do_gettimeofday(&time_now); ++ interval_in_us = timeval_sub_to_us(time_now, time_last); ++ if ( interval_in_us > (USEC_PER_SEC) ) { /* 1 second = 1000000 us. */ ++ printk(" Pan display FPS: %d\n",fpsCount); ++ fpsCount = 0; ++ time_last = time_now; ++ } ++ break; ++ case 2: ++ do_gettimeofday(&time_now); ++ interval_in_us = timeval_sub_to_us(time_now, time_last); ++ interval_in_ms = time_us2ms(interval_in_us); ++ printk(" Pan display interval ms: %d\n",interval_in_ms); ++ time_last = time_now; ++ break; ++ default: ++ if (showFPS > 3) { ++ int d, f; ++ fpsCount++; ++ do_gettimeofday(&time_now); ++ interval_in_us = timeval_sub_to_us(time_now, time_last); ++ if (interval_in_us > USEC_PER_SEC * showFPS ) { /* 1 second = 1000000 us. */ ++ d = fpsCount / showFPS; ++ f = (fpsCount * 10) / showFPS - d * 10; ++ printk(" Pan display FPS: %d.%01d\n", d, f); ++ fpsCount = 0; ++ time_last = time_now; ++ } ++ } ++ break; ++ } ++} ++ ++static int ingenicfb_set_desc_msg(struct fb_info *info, int num) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ struct ingenicfb_frmdesc_msg *desc_msg_curr; ++ struct ingenicfb_frmdesc_msg *desc_msg; ++ int i; ++ ++ desc_msg_curr = &fbdev->frmdesc_msg[num]; ++ if((desc_msg_curr->state != DESC_ST_AVAILABLE) ++ && (desc_msg_curr->state != DESC_ST_FREE)) { ++ printk(KERN_DEBUG "%s Desc state is err!\n" ++ "Now there are %d bufs, hoping to use polling to improve efficiency\n" ++ , __func__, MAX_DESC_NUM); ++ return 0; ++ } ++ ++ /* Whether the controller in the work */ ++ if(!(reg_read(fbdev, DC_ST) & DC_WORKING) && (list_empty(&fbdev->desc_run_list))) { ++ desc_msg_curr->state = DESC_ST_RUNING; ++ list_add_tail(&desc_msg_curr->list, &fbdev->desc_run_list); ++ desc_msg_curr->addr_virt->FrameCtrl.b.stop = 1; ++ reg_write(fbdev, DC_FRM_CFG_ADDR, desc_msg_curr->addr_phy); ++ ingenicfb_cmp_start(info); ++ ingenicfb_slcd_start(info); ++ } else { ++ if(list_empty(&fbdev->desc_run_list)) { ++ dev_err(fbdev->dev, "desc_run_list is empty!!!!\n"); ++ return -EINVAL; ++ } ++ desc_msg = list_entry(fbdev->desc_run_list.prev, ++ struct ingenicfb_frmdesc_msg, list); ++ if(reg_read(fbdev, DC_FRM_DES) != desc_msg->addr_phy) { ++ desc_msg->addr_virt->FrameNextCfgAddr = desc_msg_curr->addr_phy; ++ desc_msg->addr_virt->FrameCtrl.b.stop = 0; ++ } ++ desc_msg_curr->addr_virt->FrameCtrl.b.stop = 1; ++ desc_msg_curr->state = DESC_ST_RUNING; ++ list_add_tail(&desc_msg_curr->list, &fbdev->desc_run_list); ++ } ++ ++ for(i = 0; i < MAX_DESC_NUM; i++) { ++ if(fbdev->frmdesc_msg[i].state == DESC_ST_FREE) { ++ fbdev->frmdesc_msg[i].state = DESC_ST_AVAILABLE; ++ fbdev->vsync_skip_map = (fbdev->vsync_skip_map >> 1 | ++ fbdev->vsync_skip_map << 9) & 0x3ff; ++ if(likely(fbdev->vsync_skip_map & 0x1)) { ++ fbdev->timestamp.value[fbdev->timestamp.wp] = ++ ktime_to_ns(ktime_get()); ++ fbdev->timestamp.wp = (fbdev->timestamp.wp + 1) % TIMESTAMP_CAP; ++ wake_up_interruptible(&fbdev->vsync_wq); ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++static int ingenicfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ unsigned long flags; ++ int next_frm; ++ int ret = 0; ++ ++ if (var->xoffset - info->var.xoffset) { ++ dev_err(info->dev, "No support for X panning for now\n"); ++ return -EINVAL; ++ } ++ ++ fbdev->pan_display_count++; ++ if(showFPS){ ++ calculate_frame_rate(); ++ } ++ ++ next_frm = var->yoffset / var->yres; ++ ++// if(fbdev->current_frm_desc == next_frm && fbdev->is_lcd_en) { ++// ingenicfb_disable(fbdev->fb, GEN_STOP); ++// } ++ if(fbdev->current_frm_mode.update_st[next_frm] == FRAME_CFG_NO_UPDATE) { ++ if((ret = ingenicfb_desc_init(info, next_frm))) { ++ dev_err(info->dev, "%s: desc init err!\n", __func__); ++ dump_lcdc_registers(); ++ return ret; ++ } ++ } ++ ++ if(fbdev->panel->lcd_type == LCD_TYPE_SLCD && !fbdev->slcd_continua) { ++ spin_lock_irqsave(&fbdev->irq_lock, flags); ++ ret = ingenicfb_set_desc_msg(info, next_frm); ++ spin_unlock_irqrestore(&fbdev->irq_lock, flags); ++ if(ret) { ++ dev_err(info->dev, "%s: Set desc_msg err!\n", __func__); ++ return ret; ++ } ++ } else { ++ reg_write(fbdev, DC_FRM_CFG_ADDR, fbdev->framedesc_phys[next_frm]); ++ } ++ ++ if(!fbdev->is_lcd_en) ++ ingenicfb_enable(info); ++ fbdev->current_frm_desc = next_frm; ++ ++ return 0; ++} ++ ++static void ingenicfb_do_resume(struct ingenicfb_device *fbdev) ++{ ++ int ret; ++ ++ mutex_lock(&fbdev->suspend_lock); ++ if(fbdev->is_suspend) { ++ ingenicfb_clk_enable(fbdev); ++ ingenicfb_set_fix_par(fbdev->fb); ++ ret = ingenicfb_set_par(fbdev->fb); ++ if(ret) { ++ dev_err(fbdev->dev, "Set par failed!\n"); ++ } ++ ingenicfb_enable(fbdev->fb); ++ fbdev->is_suspend = 0; ++ } ++ mutex_unlock(&fbdev->suspend_lock); ++} ++ ++static void ingenicfb_do_suspend(struct ingenicfb_device *fbdev) ++{ ++ struct lcd_panel *panel = fbdev->panel; ++ struct lcd_panel_ops *panel_ops; ++ ++ panel_ops = panel->ops; ++ ++ mutex_lock(&fbdev->suspend_lock); ++ if (!fbdev->is_suspend){ ++ ingenicfb_disable(fbdev->fb, QCK_STOP); ++ ingenicfb_clk_disable(fbdev); ++ if(panel_ops && panel_ops->disable) ++ panel_ops->disable(panel); ++ ++ fbdev->is_suspend = 1; ++ } ++ mutex_unlock(&fbdev->suspend_lock); ++} ++ ++static int ingenicfb_blank(int blank_mode, struct fb_info *info) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ ++ if (blank_mode == FB_BLANK_UNBLANK) { ++ ingenicfb_do_resume(fbdev); ++ } else { ++ ingenicfb_do_suspend(fbdev); ++ } ++ ++ return 0; ++} ++ ++static int ingenicfb_open(struct fb_info *info, int user) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ int ret; ++ int i; ++ ++ if (!fbdev->is_lcd_en && fbdev->vidmem_phys) { ++ for(i = 0; i < MAX_DESC_NUM; i++) { ++ fbdev->frmdesc_msg[i].state = DESC_ST_FREE; ++ } ++ INIT_LIST_HEAD(&fbdev->desc_run_list); ++ fbdev->timestamp.rp = 0; ++ fbdev->timestamp.wp = 0; ++ ingenicfb_set_fix_par(info); ++ ret = ingenicfb_set_par(info); ++ if(ret) { ++ dev_err(info->dev, "Set par failed!\n"); ++ return ret; ++ } ++ memset(fbdev->vidmem[fbdev->current_frm_desc][0], 0, fbdev->frm_size); ++ ingenicfb_enable(info); ++ } ++ ++ dev_dbg(info->dev, "####open count : %d\n", ++fbdev->open_cnt); ++ ++ return 0; ++} ++ ++static int ingenicfb_release(struct fb_info *info, int user) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ int i; ++ ++ dev_dbg(info->dev, "####close count : %d\n", fbdev->open_cnt--); ++ if(!fbdev->open_cnt) { ++ for(i = 0; i < MAX_DESC_NUM; i++) { ++ fbdev->frmdesc_msg[i].state = DESC_ST_FREE; ++ } ++ INIT_LIST_HEAD(&fbdev->desc_run_list); ++ fbdev->timestamp.rp = 0; ++ fbdev->timestamp.wp = 0; ++ } ++ return 0; ++} ++ ++static ssize_t ingenicfb_write(struct fb_info *info, const char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ u8 *buffer, *src; ++ u8 __iomem *dst; ++ int c, cnt = 0, err = 0; ++ unsigned long total_size; ++ unsigned long p = *ppos; ++ unsigned long flags; ++ int next_frm = 0; ++ int ret; ++ ++ total_size = info->screen_size; ++ ++ if (total_size == 0) ++ total_size = info->fix.smem_len; ++ ++ if (p > total_size) ++ return -EFBIG; ++ ++ if (count > total_size) { ++ err = -EFBIG; ++ count = total_size; ++ } ++ ++ if (count + p > total_size) { ++ if (!err) ++ err = -ENOSPC; ++ ++ count = total_size - p; ++ } ++ ++ buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, ++ GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ dst = (u8 __iomem *) (info->screen_base + p); ++ ++ while (count) { ++ c = (count > PAGE_SIZE) ? PAGE_SIZE : count; ++ src = buffer; ++ ++ if (copy_from_user(src, buf, c)) { ++ err = -EFAULT; ++ break; ++ } ++ ++ fb_memcpy_tofb(dst, src, c); ++ dst += c; ++ src += c; ++ *ppos += c; ++ buf += c; ++ cnt += c; ++ count -= c; ++ } ++ ++ kfree(buffer); ++ ++ if(fbdev->panel->lcd_type == LCD_TYPE_SLCD && !fbdev->slcd_continua) { ++ spin_lock_irqsave(&fbdev->irq_lock, flags); ++ ret = ingenicfb_set_desc_msg(info, next_frm); ++ spin_unlock_irqrestore(&fbdev->irq_lock, flags); ++ if(ret) { ++ dev_err(info->dev, "%s: Set desc_msg err!\n", __func__); ++ return ret; ++ } ++ } else { ++ reg_write(fbdev, DC_FRM_CFG_ADDR, fbdev->framedesc_phys[next_frm]); ++ } ++ ++ if(!fbdev->is_lcd_en) ++ ingenicfb_enable(info); ++ fbdev->current_frm_desc = next_frm; ++ ++ return (cnt) ? cnt : err; ++} ++ ++static struct fb_ops ingenicfb_ops = { ++ .owner = THIS_MODULE, ++ .fb_open = ingenicfb_open, ++ .fb_release = ingenicfb_release, ++ .fb_write = ingenicfb_write, ++ .fb_check_var = ingenicfb_check_var, ++ .fb_set_par = ingenicfb_set_par, ++ .fb_setcolreg = ingenicfb_setcolreg, ++ .fb_blank = ingenicfb_blank, ++ .fb_pan_display = ingenicfb_pan_display, ++ .fb_fillrect = cfb_fillrect, ++ .fb_copyarea = cfb_copyarea, ++ .fb_imageblit = cfb_imageblit, ++ .fb_ioctl = ingenicfb_ioctl, ++ .fb_mmap = ingenicfb_mmap, ++}; ++ ++ static ssize_t ++dump_h_color_bar(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct ingenicfb_device *fbdev = dev_get_drvdata(dev); ++ ingenicfb_display_h_color_bar(fbdev->fb); ++ if (fbdev->panel->lcd_type == LCD_TYPE_SLCD && !fbdev->slcd_continua) { ++ ingenicfb_cmp_start(fbdev->fb); ++ ingenicfb_slcd_start(fbdev->fb); ++ } ++ return 0; ++} ++ ++ static ssize_t ++dump_v_color_bar(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct ingenicfb_device *fbdev = dev_get_drvdata(dev); ++ ingenicfb_display_v_color_bar(fbdev->fb); ++ if (fbdev->panel->lcd_type == LCD_TYPE_SLCD && !fbdev->slcd_continua) { ++ ingenicfb_cmp_start(fbdev->fb); ++ ingenicfb_slcd_start(fbdev->fb); ++ } ++ return 0; ++} ++ ++ static ssize_t ++vsync_skip_r(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct ingenicfb_device *fbdev = dev_get_drvdata(dev); ++ mutex_lock(&fbdev->lock); ++ snprintf(buf, 3, "%d\n", fbdev->vsync_skip_ratio); ++ printk("vsync_skip_map = 0x%08x\n", fbdev->vsync_skip_map); ++ mutex_unlock(&fbdev->lock); ++ return 3; /* sizeof ("%d\n") */ ++} ++ ++static int vsync_skip_set(struct ingenicfb_device *fbdev, int vsync_skip) ++{ ++ unsigned int map_wide10 = 0; ++ int rate, i, p, n; ++ int fake_float_1k; ++ ++ if (vsync_skip < 0 || vsync_skip > 9) ++ return -EINVAL; ++ ++ rate = vsync_skip + 1; ++ fake_float_1k = 10000 / rate; /* 10.0 / rate */ ++ ++ p = 1; ++ n = (fake_float_1k * p + 500) / 1000; /* +0.5 to int */ ++ ++ for (i = 1; i <= 10; i++) { ++ map_wide10 = map_wide10 << 1; ++ if (i == n) { ++ map_wide10++; ++ p++; ++ n = (fake_float_1k * p + 500) / 1000; ++ } ++ } ++ mutex_lock(&fbdev->lock); ++ fbdev->vsync_skip_map = map_wide10; ++ fbdev->vsync_skip_ratio = rate - 1; /* 0 ~ 9 */ ++ mutex_unlock(&fbdev->lock); ++ ++ printk("vsync_skip_ratio = %d\n", fbdev->vsync_skip_ratio); ++ printk("vsync_skip_map = 0x%08x\n", fbdev->vsync_skip_map); ++ ++ return 0; ++} ++ ++ static ssize_t ++vsync_skip_w(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct ingenicfb_device *fbdev = dev_get_drvdata(dev); ++ ++ if ((count != 1) && (count != 2)) ++ return -EINVAL; ++ if ((*buf < '0') && (*buf > '9')) ++ return -EINVAL; ++ ++ vsync_skip_set(fbdev, *buf - '0'); ++ ++ return count; ++} ++ ++static ssize_t fps_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ printk("\n-----you can choice print way:\n"); ++ printk("Example: echo NUM > show_fps\n"); ++ printk("NUM = 0: close fps statistics\n"); ++ printk("NUM = 1: print recently fps\n"); ++ printk("NUM = 2: print interval between last and this pan_display\n"); ++ printk("NUM = 3: print pan_display count\n\n"); ++ return 0; ++} ++ ++static ssize_t fps_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++ int num = 0; ++ num = simple_strtoul(buf, NULL, 0); ++ if(num < 0){ ++ printk("\n--please 'cat show_fps' to view using the method\n\n"); ++ return n; ++ } ++ showFPS = num; ++ if(showFPS == 3) ++ printk(KERN_DEBUG " Pand display count=%d\n",fbdev->pan_display_count); ++ return n; ++} ++ ++ ++ static ssize_t ++debug_clr_st(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct ingenicfb_device *fbdev = dev_get_drvdata(dev); ++ reg_write(fbdev, DC_CLR_ST, 0xffffffff); ++ return 0; ++} ++ ++static ssize_t test_suspend(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++ int num = 0; ++ num = simple_strtoul(buf, NULL, 0); ++ printk("0 --> resume | 1 --> suspend\nnow input %d\n", num); ++ if (num == 0) { ++ ingenicfb_do_resume(fbdev); ++ } else { ++ ingenicfb_do_suspend(fbdev); ++ } ++ return n; ++} ++ ++/**********************lcd_debug***************************/ ++static DEVICE_ATTR(dump_lcd, S_IRUGO|S_IWUSR, dump_lcd, NULL); ++static DEVICE_ATTR(dump_h_color_bar, S_IRUGO|S_IWUSR, dump_h_color_bar, NULL); ++static DEVICE_ATTR(dump_v_color_bar, S_IRUGO|S_IWUSR, dump_v_color_bar, NULL); ++static DEVICE_ATTR(vsync_skip, S_IRUGO|S_IWUSR, vsync_skip_r, vsync_skip_w); ++static DEVICE_ATTR(show_fps, S_IRUGO|S_IWUSR, fps_show, fps_store); ++static DEVICE_ATTR(debug_clr_st, S_IRUGO|S_IWUSR, debug_clr_st, NULL); ++static DEVICE_ATTR(test_suspend, S_IRUGO|S_IWUSR, NULL, test_suspend); ++ ++static struct attribute *lcd_debug_attrs[] = { ++ &dev_attr_dump_lcd.attr, ++ &dev_attr_dump_h_color_bar.attr, ++ &dev_attr_dump_v_color_bar.attr, ++ &dev_attr_vsync_skip.attr, ++ &dev_attr_show_fps.attr, ++ &dev_attr_debug_clr_st.attr, ++ &dev_attr_test_suspend.attr, ++ NULL, ++}; ++ ++const char lcd_group_name[] = "debug"; ++static struct attribute_group lcd_debug_attr_group = { ++ .name = lcd_group_name, ++ .attrs = lcd_debug_attrs, ++}; ++ ++static void ingenicfb_free_devmem(struct ingenicfb_device *fbdev) ++{ ++ size_t buff_size; ++ ++ dma_free_coherent(fbdev->dev, ++ fbdev->vidmem_size, ++ fbdev->vidmem[0][0], ++ fbdev->vidmem_phys[0][0]); ++ ++ buff_size = sizeof(struct ingenicfb_layerdesc); ++ buff_size = ALIGN(buff_size, DESC_ALIGN); ++ dma_free_coherent(fbdev->dev, ++ buff_size * MAX_DESC_NUM * MAX_LAYER_NUM, ++ fbdev->layerdesc[0], ++ fbdev->layerdesc_phys[0][0]); ++ ++ buff_size = sizeof(struct ingenicfb_framedesc); ++ buff_size = ALIGN(buff_size, DESC_ALIGN); ++ dma_free_coherent(fbdev->dev, ++ buff_size * MAX_DESC_NUM, ++ fbdev->framedesc[0], ++ fbdev->framedesc_phys[0]); ++} ++ ++static int ingenicfb_copy_logo(struct fb_info *info) ++{ ++ unsigned long src_addr = 0; /* u-boot logo buffer address */ ++ unsigned long dst_addr = 0; /* kernel frame buffer address */ ++ struct ingenicfb_device *fbdev = info->par; ++ unsigned long size; ++ unsigned int ctrl; ++ unsigned read_times; ++ lay_cfg_en_t lay_cfg_en; ++ ++ /* Sure the uboot SLCD using the continuous mode, Close irq */ ++ if (!(reg_read(fbdev, DC_ST) & DC_WORKING)) { ++ dev_err(fbdev->dev, "uboot is not display logo!\n"); ++ return -ENOEXEC; ++ } ++ ++ /*fbdev->is_lcd_en = 1;*/ ++ ++ /* Reading Desc from regisger need reset */ ++ ctrl = reg_read(fbdev, DC_CTRL); ++ ctrl |= DC_DES_CNT_RST; ++ reg_write(fbdev, DC_CTRL, ctrl); ++ ++ /* For geting LayCfgEn need read DC_FRM_DES 10 times */ ++ read_times = 10 - 1; ++ while(read_times--) { ++ reg_read(fbdev, DC_FRM_DES); ++ } ++ lay_cfg_en.d32 = reg_read(fbdev, DC_FRM_DES); ++ if(!lay_cfg_en.b.lay0_en) { ++ dev_err(fbdev->dev, "Uboot initialization is not using layer0!\n"); ++ return -ENOEXEC; ++ } ++ ++ /* For geting LayerBufferAddr need read DC_LAY0_DES 3 times */ ++ read_times = 3 - 1; ++ /* get buffer physical address */ ++ while(read_times--) { ++ reg_read(fbdev, DC_LAY0_DES); ++ } ++ src_addr = (unsigned long)reg_read(fbdev, DC_LAY0_DES); ++ ++ if (src_addr) { ++ size = info->fix.line_length * info->var.yres; ++ src_addr = (unsigned long)phys_to_virt(src_addr); ++ dst_addr = (unsigned long)fbdev->vidmem[0][0]; ++ memcpy((void *)dst_addr, (void *)src_addr, size); ++ } ++ ++ return 0; ++} ++ ++static int ingenicfb_do_probe(struct platform_device *pdev, struct lcd_panel *panel) ++{ ++ struct fb_videomode *video_mode; ++ struct fb_info *fb; ++ unsigned long rate; ++ int ret = 0; ++ int i; ++ ++ fb = framebuffer_alloc(sizeof(struct ingenicfb_device), &pdev->dev); ++ if (!fb) { ++ dev_err(&pdev->dev, "Failed to allocate framebuffer device\n"); ++ return -ENOMEM; ++ } ++ ++ fbdev = fb->par; ++ fbdev->fb = fb; ++ fbdev->dev = &pdev->dev; ++ fbdev->panel = panel; ++#ifdef CONFIG_SLCDC_CONTINUA ++ if(fbdev->panel->lcd_type == LCD_TYPE_SLCD) ++ fbdev->slcd_continua = 1; ++#endif ++ ++ spin_lock_init(&fbdev->irq_lock); ++ mutex_init(&fbdev->lock); ++ mutex_init(&fbdev->suspend_lock); ++ sprintf(fbdev->clk_name, "gate_lcd"); ++ sprintf(fbdev->pclk_name, "cgu_lcd"); ++ ++ fbdev->clk = devm_clk_get(&pdev->dev, fbdev->clk_name); ++ fbdev->pclk = devm_clk_get(&pdev->dev, fbdev->pclk_name); ++ ++ if (IS_ERR(fbdev->clk) || IS_ERR(fbdev->pclk)) { ++ ret = PTR_ERR(fbdev->clk); ++ dev_err(&pdev->dev, "Failed to get lcdc clock: %d\n", ret); ++ goto err_framebuffer_release; ++ } ++ ++ fbdev->base = of_iomap(pdev->dev.of_node, 0); ++ if (!fbdev->base) { ++ dev_err(&pdev->dev, ++ "Failed to ioremap register memory region\n"); ++ ret = -EBUSY; ++ goto err_put_clk; ++ } ++ ++ ret = refresh_pixclock_auto_adapt(fb); ++ if(ret){ ++ goto err_iounmap; ++ } ++ ++ video_mode = fbdev->panel->modes; ++ if (!video_mode) { ++ ret = -ENXIO; ++ goto err_iounmap; ++ } ++ ++ fb_videomode_to_modelist(panel->modes, panel->num_modes, &fb->modelist); ++ ++ ingenicfb_videomode_to_var(&fb->var, video_mode, fbdev->panel->lcd_type); ++ fb->fbops = &ingenicfb_ops; ++ fb->flags = FBINFO_DEFAULT; ++ fb->var.width = panel->width; ++ fb->var.height = panel->height; ++ ++ ingenicfb_colormode_to_var(&fb->var, &ingenicfb_colormodes[0]); ++ ++ ret = ingenicfb_check_var(&fb->var, fb); ++ if (ret) { ++ goto err_iounmap; ++ } ++ ++ rate = PICOS2KHZ(fb->var.pixclock) * 1000; ++ clk_set_rate(fbdev->pclk, rate); ++ ++ if(rate != clk_get_rate(fbdev->pclk)) { ++ dev_err(&pdev->dev, "expect rate = %ld, actual rate = %ld\n", rate, clk_get_rate(fbdev->pclk)); ++ ++ } ++ ++ clk_prepare_enable(fbdev->clk); ++ clk_prepare_enable(fbdev->pclk); ++ fbdev->is_clk_en = 1; ++ ++ ret = ingenicfb_alloc_devmem(fbdev); ++ if (ret) { ++ dev_err(&pdev->dev, "Failed to allocate video memory\n"); ++ goto err_iounmap; ++ } ++ ++ fb->fix = ingenicfb_fix; ++ fb->fix.line_length = (fb->var.bits_per_pixel * fb->var.xres) >> 3; ++ fb->fix.smem_start = fbdev->vidmem_phys[0][0]; ++ fb->fix.smem_len = fbdev->vidmem_size; ++ fb->screen_size = fbdev->frm_size; ++ fb->screen_base = fbdev->vidmem[0][0]; ++ fb->pseudo_palette = fbdev->pseudo_palette; ++ ++ vsync_skip_set(fbdev, CONFIG_FB_VSYNC_SKIP); ++ init_waitqueue_head(&fbdev->vsync_wq); ++ init_waitqueue_head(&fbdev->gen_stop_wq); ++ fbdev->open_cnt = 0; ++ fbdev->is_lcd_en = 0; ++ fbdev->timestamp.rp = 0; ++ fbdev->timestamp.wp = 0; ++ ++ INIT_LIST_HEAD(&fbdev->desc_run_list); ++ for(i = 0; i < MAX_DESC_NUM; i++) { ++ fbdev->frmdesc_msg[i].state = DESC_ST_FREE; ++ fbdev->frmdesc_msg[i].addr_virt = fbdev->framedesc[i]; ++ fbdev->frmdesc_msg[i].addr_phy = fbdev->framedesc_phys[i]; ++ fbdev->frmdesc_msg[i].index = i; ++ } ++ ++ ingenicfb_update_frm_mode(fbdev->fb); ++ ++ fbdev->irq = platform_get_irq(pdev, 0); ++ if(fbdev->irq < 0) { ++ dev_err(fbdev->dev, "Failed to get irq resource!\n"); ++ goto err_free_devmem; ++ } ++ ret = devm_request_irq(fbdev->dev, fbdev->irq, ingenicfb_irq_handler, 0, "lcdc", fbdev); ++ if(ret < 0) { ++ dev_err(fbdev->dev, "Failed to request irq handler!\n"); ++ goto err_free_devmem; ++ } ++ ++ platform_set_drvdata(pdev, fbdev); ++ ++ ret = sysfs_create_group(&fbdev->dev->kobj, &lcd_debug_attr_group); ++ if (ret) { ++ dev_err(&pdev->dev, "device create sysfs group failed\n"); ++ ++ ret = -EINVAL; ++ goto err_free_irq; ++ } ++ ++ ret = register_framebuffer(fb); ++ if (ret) { ++ dev_err(&pdev->dev, "Failed to register framebuffer: %d\n", ++ ret); ++ goto err_free_file; ++ } ++ ++ if (fbdev->vidmem_phys) { ++ if (!ingenicfb_copy_logo(fbdev->fb)) { ++ fbdev->is_lcd_en = 1; ++ ret = ingenicfb_desc_init(fb, 0); ++ if(ret) { ++ dev_err(fbdev->dev, "Desc init err!\n"); ++ goto err_free_file; ++ } ++ reg_write(fbdev, DC_FRM_CFG_ADDR, fbdev->framedesc_phys[fbdev->current_frm_desc]); ++ } ++#ifdef CONFIG_FB_JZ_DEBUG ++ test_pattern(fbdev); ++#endif ++ }else{ ++ ++ ingenicfb_clk_disable(fbdev); ++ ret = -ENOMEM; ++ goto err_free_file; ++ } ++ ++ return 0; ++ ++err_free_file: ++ sysfs_remove_group(&fbdev->dev->kobj, &lcd_debug_attr_group); ++err_free_irq: ++ free_irq(fbdev->irq, fbdev); ++err_free_devmem: ++ ingenicfb_free_devmem(fbdev); ++err_iounmap: ++ iounmap(fbdev->base); ++err_put_clk: ++ ++ if (fbdev->clk) ++ devm_clk_put(fbdev->dev, fbdev->clk); ++ if (fbdev->pclk) ++ devm_clk_put(fbdev->dev, fbdev->pclk); ++ ++err_framebuffer_release: ++ framebuffer_release(fb); ++ return ret; ++} ++ ++int ingenicfb_register_panel(struct lcd_panel *panel) ++{ ++ WARN_ON(fbdev_panel != NULL); ++ ++ fbdev_panel = panel; ++ if(fbdev_pdev != NULL) { ++ return ingenicfb_do_probe(fbdev_pdev, fbdev_panel); ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(ingenicfb_register_panel); ++ ++static int ingenicfb_probe(struct platform_device *pdev) ++{ ++ WARN_ON(fbdev_pdev != NULL); ++ ++ fbdev_pdev = pdev; ++ ++ if(fbdev_panel != NULL) { ++ return ingenicfb_do_probe(fbdev_pdev, fbdev_panel); ++ } ++ ++ return 0; ++} ++ ++static int ingenicfb_remove(struct platform_device *pdev) ++{ ++ struct ingenicfb_device *fbdev = platform_get_drvdata(pdev); ++ ++ ingenicfb_free_devmem(fbdev); ++ platform_set_drvdata(pdev, NULL); ++ ++ devm_clk_put(fbdev->dev, fbdev->pclk); ++ devm_clk_put(fbdev->dev, fbdev->clk); ++ ++ sysfs_remove_group(&fbdev->dev->kobj, &lcd_debug_attr_group); ++ ++ iounmap(fbdev->base); ++ ++ framebuffer_release(fbdev->fb); ++ ++ return 0; ++} ++ ++static void ingenicfb_shutdown(struct platform_device *pdev) ++{ ++ struct ingenicfb_device *fbdev = platform_get_drvdata(pdev); ++ int is_fb_blank; ++ mutex_lock(&fbdev->suspend_lock); ++ is_fb_blank = (fbdev->is_suspend != 1); ++ fbdev->is_suspend = 1; ++ mutex_unlock(&fbdev->suspend_lock); ++ if (is_fb_blank) ++ fb_blank(fbdev->fb, FB_BLANK_POWERDOWN); ++}; ++ ++#ifdef CONFIG_PM ++ ++static int ingenicfb_suspend(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct ingenicfb_device *fbdev = platform_get_drvdata(pdev); ++ ++ fb_blank(fbdev->fb, FB_BLANK_POWERDOWN); ++ ++ return 0; ++} ++ ++static int ingenicfb_resume(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct ingenicfb_device *fbdev = platform_get_drvdata(pdev); ++ ++ fb_blank(fbdev->fb, FB_BLANK_UNBLANK); ++ ++ return 0; ++} ++ ++static const struct dev_pm_ops ingenicfb_pm_ops = { ++ .suspend = ingenicfb_suspend, ++ .resume = ingenicfb_resume, ++}; ++#endif ++ ++static const struct of_device_id ingenicfb_of_match[] = { ++ { .compatible = "ingenic,x2000-dpu"}, ++ {}, ++}; ++ ++static struct platform_driver ingenicfb_driver = { ++ .probe = ingenicfb_probe, ++ .remove = ingenicfb_remove, ++ .shutdown = ingenicfb_shutdown, ++ .driver = { ++ .name = "ingenic-fb", ++ .of_match_table = ingenicfb_of_match, ++#ifdef CONFIG_PM ++ .pm = &ingenicfb_pm_ops, ++#endif ++ ++ }, ++}; ++ ++static int __init ingenicfb_init(void) ++{ ++ platform_driver_register(&ingenicfb_driver); ++ return 0; ++} ++ ++static void __exit ingenicfb_cleanup(void) ++{ ++ platform_driver_unregister(&ingenicfb_driver); ++} ++ ++ ++#ifdef CONFIG_EARLY_INIT_RUN ++rootfs_initcall(ingenicfb_init); ++#else ++module_init(ingenicfb_init); ++#endif ++ ++module_exit(ingenicfb_cleanup); ++ ++MODULE_DESCRIPTION("JZ LCD Controller driver"); ++MODULE_AUTHOR("Sean Tang "); ++MODULE_LICENSE("GPL"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v11_ingenicfb.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v11_ingenicfb.h.patch new file mode 100644 index 00000000..e7a88a3d --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v11_ingenicfb.h.patch @@ -0,0 +1,298 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v11/ingenicfb.h b/drivers/video/fbdev/ingenic/fb_v11/ingenicfb.h +--- a/drivers/video/fbdev/ingenic/fb_v11/ingenicfb.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v11/ingenicfb.h 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,294 @@ ++/* drivers/video/jz_fb_v14/jz_fb.h ++ * ++ * Copyright (C) 2016 Ingenic Semiconductor Inc. ++ * ++ * Author:clwang ++ * ++ * 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. ++ */ ++ ++#include ++#include "uapi_ingenicfb.h" ++ ++#ifdef CONFIG_ONE_FRAME_BUFFERS ++#define MAX_DESC_NUM 1 ++#endif ++ ++#ifdef CONFIG_TWO_FRAME_BUFFERS ++#define MAX_DESC_NUM 2 ++#endif ++ ++#ifdef CONFIG_THREE_FRAME_BUFFERS ++#define MAX_DESC_NUM 3 ++#endif ++ ++#define DESC_ALIGN 8 ++#define MAX_DESC_NUM 3 ++#define MAX_BITS_PER_PIX (32) ++#define MAX_STRIDE_VALUE (4096) ++#define FRAME_CTRL_DEFAULT_SET (0x04) ++#define FRAME_CFG_ALL_UPDATE (0xFF) ++ ++enum ingenic_lcd_type { ++ LCD_TYPE_TFT = 0, ++ LCD_TYPE_SLCD =1, ++}; ++ ++/* smart lcd interface_type */ ++enum smart_lcd_type { ++ SMART_LCD_TYPE_6800, ++ SMART_LCD_TYPE_8080, ++ SMART_LCD_TYPE_SPI_3, ++ SMART_LCD_TYPE_SPI_4, ++}; ++ ++/* smart lcd format */ ++enum smart_lcd_format { ++ SMART_LCD_FORMAT_565, ++ SMART_LCD_FORMAT_666, ++ SMART_LCD_FORMAT_888, ++}; ++ ++/* smart lcd command width */ ++enum smart_lcd_cwidth { ++ SMART_LCD_CWIDTH_8_BIT, ++ SMART_LCD_CWIDTH_9_BIT, ++ SMART_LCD_CWIDTH_16_BIT, ++ SMART_LCD_CWIDTH_18_BIT, ++ SMART_LCD_CWIDTH_24_BIT, ++}; ++ ++/* smart lcd data width */ ++enum smart_lcd_dwidth { ++ SMART_LCD_DWIDTH_8_BIT, ++ SMART_LCD_DWIDTH_9_BIT, ++ SMART_LCD_DWIDTH_16_BIT, ++ SMART_LCD_DWIDTH_18_BIT, ++ SMART_LCD_DWIDTH_24_BIT, ++}; ++ ++enum smart_config_type { ++ SMART_CONFIG_DATA, ++ SMART_CONFIG_PRM, ++ SMART_CONFIG_CMD, ++ SMART_CONFIG_UDELAY, ++}; ++ ++struct smart_lcd_data_table { ++ enum smart_config_type type; ++ unsigned int value; ++}; ++ ++enum tft_lcd_color_even { ++ TFT_LCD_COLOR_EVEN_RGB, ++ TFT_LCD_COLOR_EVEN_RBG, ++ TFT_LCD_COLOR_EVEN_BGR, ++ TFT_LCD_COLOR_EVEN_BRG, ++ TFT_LCD_COLOR_EVEN_GBR, ++ TFT_LCD_COLOR_EVEN_GRB, ++}; ++ ++enum tft_lcd_color_odd { ++ TFT_LCD_COLOR_ODD_RGB, ++ TFT_LCD_COLOR_ODD_RBG, ++ TFT_LCD_COLOR_ODD_BGR, ++ TFT_LCD_COLOR_ODD_BRG, ++ TFT_LCD_COLOR_ODD_GBR, ++ TFT_LCD_COLOR_ODD_GRB, ++}; ++ ++enum tft_lcd_mode { ++ TFT_LCD_MODE_PARALLEL_888, ++ TFT_LCD_MODE_PARALLEL_666, ++ TFT_LCD_MODE_PARALLEL_565, ++ TFT_LCD_MODE_SERIAL_RGB, ++ TFT_LCD_MODE_SERIAL_RGBD, ++}; ++ ++struct tft_config { ++ unsigned int pix_clk_inv:1; ++ unsigned int de_dl:1; ++ unsigned int sync_dl:1; ++ enum tft_lcd_color_even color_even; ++ enum tft_lcd_color_odd color_odd; ++ enum tft_lcd_mode mode; ++}; ++ ++struct smart_config { ++ unsigned int frm_md:1; ++ unsigned int rdy_switch:1; ++ unsigned int rdy_dp:1; ++ unsigned int rdy_anti_jit:1; ++ unsigned int te_switch:1; ++ unsigned int te_md:1; ++ unsigned int te_dp:1; ++ unsigned int te_anti_jit:1; ++ unsigned int cs_en:1; ++ unsigned int cs_dp:1; ++ unsigned int dc_md:1; ++ unsigned int wr_md:1; ++ enum smart_lcd_type smart_type; ++ enum smart_lcd_format pix_fmt; ++ enum smart_lcd_dwidth dwidth; ++ enum smart_lcd_cwidth cwidth; ++ unsigned int bus_width; ++ ++ unsigned long write_gram_cmd; ++ unsigned int length_cmd; ++ struct smart_lcd_data_table *data_table; ++ unsigned int length_data_table; ++ int (*init) (void); ++ int (*gpio_for_slcd) (void); ++}; ++ ++struct lcd_panel_ops { ++ void (*init)(void *panel); ++ void (*enable)(void *panel); ++ void (*disable)(void *panel); ++}; ++ ++struct lcd_panel { ++ const char *name; ++ unsigned int num_modes; ++ struct fb_videomode *modes; ++ ++ enum ingenic_lcd_type lcd_type; ++ unsigned int bpp; ++ unsigned int width; ++ unsigned int height; ++ ++ struct smart_config *smart_config; ++ struct tft_config *tft_config; ++ ++ unsigned dither_enable:1; ++ struct { ++ unsigned dither_red; ++ unsigned dither_green; ++ unsigned dither_blue; ++ } dither; ++ ++ struct lcd_panel_ops *ops; ++}; ++ ++typedef enum stop_mode { ++ QCK_STOP, ++ GEN_STOP, ++} stop_mode_t; ++ ++typedef enum framedesc_st { ++ FRAME_DESC_AVAILABLE = 1, ++ FRAME_DESC_SET_OVER = 2, ++ FRAME_DESC_USING = 3, ++}framedesc_st_t; ++ ++typedef enum frm_cfg_st { ++ FRAME_CFG_NO_UPDATE, ++ FRAME_CFG_UPDATE, ++}frm_cfg_st_t; ++ ++struct ingenicfb_frm_mode { ++ struct ingenicfb_frm_cfg frm_cfg; ++ frm_cfg_st_t update_st[MAX_DESC_NUM]; ++}; ++ ++typedef enum { ++ DESC_ST_FREE, ++ DESC_ST_AVAILABLE, ++ DESC_ST_RUNING, ++} frm_st_t; ++ ++struct ingenicfb_frmdesc_msg { ++ struct ingenicfb_framedesc *addr_virt; ++ dma_addr_t addr_phy; ++ struct list_head list; ++ int state; ++ int index; ++}; ++ ++struct ingenicfb_device { ++ int is_lcd_en; /* 0, disable 1, enable */ ++ int is_clk_en; /* 0, disable 1, enable */ ++ int irq; /* lcdc interrupt num */ ++ int open_cnt; ++ int irq_cnt; ++ int tft_undr_cnt; ++ int frm_start; ++ ++ char clk_name[16]; ++ char pclk_name[16]; ++ char irq_name[16]; ++ struct clk *clk; ++ struct clk *pclk; ++ ++ ++ struct fb_info *fb; ++ struct device *dev; ++ struct lcd_panel *panel; ++ ++ void __iomem *base; ++ struct resource *mem; ++ ++ size_t vidmem_size; ++ void *vidmem[MAX_DESC_NUM][MAX_LAYER_NUM]; ++ dma_addr_t vidmem_phys[MAX_DESC_NUM][MAX_LAYER_NUM]; ++ ++ int current_frm_desc; ++ struct ingenicfb_frm_mode current_frm_mode; ++ ++ size_t frm_size; ++ struct ingenicfb_framedesc *framedesc[MAX_DESC_NUM]; ++ dma_addr_t framedesc_phys[MAX_DESC_NUM]; ++ struct ingenicfb_layerdesc *layerdesc[MAX_DESC_NUM][MAX_LAYER_NUM]; ++ dma_addr_t layerdesc_phys[MAX_DESC_NUM][MAX_LAYER_NUM]; ++ ++ wait_queue_head_t gen_stop_wq; ++ wait_queue_head_t vsync_wq; ++ unsigned int vsync_skip_map; /* 10 bits width */ ++ int vsync_skip_ratio; ++ ++ struct ingenicfb_frmdesc_msg frmdesc_msg[MAX_DESC_NUM]; ++ struct list_head desc_run_list; ++ ++ struct ingenicfb_timestamp timestamp; ++ ++ struct mutex lock; ++ struct mutex suspend_lock; ++ spinlock_t irq_lock; ++ ++#ifdef CONFIG_HAS_EARLYSUSPEND ++ struct early_suspend early_suspend; ++#endif ++ int is_suspend; ++ unsigned int pan_display_count; ++ int blank; ++ unsigned int pseudo_palette[16]; ++ int slcd_continua; ++ ++#ifdef CONFIG_FB_INGENIC_MIPI_DSI ++ struct dsi_device *dsi; ++#endif ++}; ++ ++void ingenicfb_clk_enable(struct ingenicfb_device *ingenicfb); ++void ingenicfb_clk_disable(struct ingenicfb_device *fbdev); ++static inline unsigned long reg_read(struct ingenicfb_device *fbdev, int offset) ++{ ++ return readl(fbdev->base + offset); ++} ++ ++static inline void reg_write(struct ingenicfb_device *fbdev, int offset, unsigned long val) ++{ ++ writel(val, fbdev->base + offset); ++} ++ ++/* define in image_enh.c */ ++extern int ingenicfb_config_image_enh(struct fb_info *info); ++extern int ingenicfb_image_enh_ioctl(struct fb_info *info, unsigned int cmd, ++ unsigned long arg); ++extern int update_slcd_frame_buffer(void); ++extern int lcd_display_inited_by_uboot(void); ++extern int ingenicfb_register_panel(struct lcd_panel *panel); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v11_uapi_ingenicfb.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v11_uapi_ingenicfb.h.patch new file mode 100644 index 00000000..5d2ba4f9 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v11_uapi_ingenicfb.h.patch @@ -0,0 +1,124 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v11/uapi_ingenicfb.h b/drivers/video/fbdev/ingenic/fb_v11/uapi_ingenicfb.h +--- a/drivers/video/fbdev/ingenic/fb_v11/uapi_ingenicfb.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v11/uapi_ingenicfb.h 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,120 @@ ++/* ++ * File: drivers/video/ingenic/uapi_ingenicfb.h ++ * ++ * ++ * Copyright (C) 2017 Ingenic Semiconductor Inc. ++ * ++ * Author:clwang ++ * qipengzhen ++ * ++ * 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 __UAPI_LINUX_INGENICFB_H__ ++#define __UAPI_LINUX_INGENICFB_H__ ++ ++#define MAX_LAYER_NUM 2 ++#define PIXEL_ALIGN 4 ++ ++enum { ++ LAYER_CFG_FORMAT_RGB555 = 0, ++ LAYER_CFG_FORMAT_ARGB1555 = 1, ++ LAYER_CFG_FORMAT_RGB565 = 2, ++ LAYER_CFG_FORMAT_RGB888 = 4, ++ LAYER_CFG_FORMAT_ARGB8888 = 5, ++ LAYER_CFG_FORMAT_NV12 = 8, ++ LAYER_CFG_FORMAT_NV21 = 9, ++ LAYER_CFG_FORMAT_YUV422 = 10, ++ LAYER_CFG_FORMAT_TILE_H264 = 12, ++}; ++ ++enum { ++ LAYER_CFG_COLOR_RGB = 0, ++ LAYER_CFG_COLOR_RBG = 1, ++ LAYER_CFG_COLOR_GRB = 2, ++ LAYER_CFG_COLOR_GBR = 3, ++ LAYER_CFG_COLOR_BRG = 4, ++ LAYER_CFG_COLOR_BGR = 5, ++}; ++/** ++* @ingenicfb_layer_cfg layer cfg for frames. userspace use this struct. ++* ++* @layer_en layer enable. ++* @layer_z_order ++* @pic_width width of this layer ++* @pic_height height of this layer ++* @disp_pos_x start x ++* @disp_pos_y start y. ++* @g_alpha_en global alpha enable. ++* @g_alpha_val global alpha value. ++* @color color of source data in memory. if format is not RGB kind. ++* color is useless. ++* @format format of source data in memory. ++* @stride width stride. ++*/ ++struct ingenicfb_lay_cfg { ++ unsigned int lay_en; ++ unsigned int lay_z_order; ++ unsigned int pic_width; ++ unsigned int pic_height; ++ unsigned int disp_pos_x; ++ unsigned int disp_pos_y; ++ unsigned int g_alpha_en; ++ unsigned int g_alpha_val; ++ unsigned int color; ++ unsigned int domain_multi; ++ unsigned int format; ++ unsigned int stride; ++}; ++struct ingenicfb_frm_cfg { ++ struct ingenicfb_lay_cfg lay_cfg[MAX_LAYER_NUM]; ++}; ++ ++typedef enum csc_mode { ++ CSC_MODE_0, ++ CSC_MODE_1, ++ CSC_MODE_2, ++ CSC_MODE_3, ++} csc_mode_t; ++ ++struct ingenicfb_timestamp { ++#define TIMESTAMP_CAP (16) ++ int wp; /* Write position, after lcd write a frame to lcd. update wp*/ ++ int rp; /* Read position, after wait vsync, update rp*/ ++ unsigned long long value[TIMESTAMP_CAP]; ++}; ++ ++#define JZFB_PUT_FRM_CFG _IOWR('F', 0x101, struct ingenicfb_frm_cfg *) ++#define JZFB_GET_FRM_CFG _IOWR('F', 0x102, struct ingenicfb_frm_cfg *) ++#define JZFB_SET_LAYER_POS _IOWR('F', 0x105, struct ingenicfb_layer_pos *) ++#define JZFB_SET_LAYER_SIZE _IOWR('F', 0x106, struct ingenicfb_layer_size *) ++#define JZFB_SET_LAYER_FORMAT _IOWR('F', 0x109, struct ingenicfb_layer_format *) ++#define JZFB_SET_LAYER_ALPHA _IOWR('F', 0x151, struct ingenicfb_layer_alpha *) ++ ++#define JZFB_GET_LAYER_POS _IOR('F', 0x115, struct ingenicfb_layer_pos *) ++#define JZFB_GET_LAYER_SIZE _IOR('F', 0x116, struct ingenicfb_layer_size *) ++ ++#define JZFB_SET_CSC_MODE _IOW('F', 0x120, csc_mode_t) ++#define JZFB_CMP_START _IOW('F', 0X141, int) ++#define JZFB_TFT_START _IOW('F', 0X143, int) ++#define JZFB_SLCD_START _IOW('F', 0X144, int) ++#define JZFB_GEN_STP_CMP _IOW('F', 0x145, int) ++#define JZFB_QCK_STP_CMP _IOW('F', 0x147, int) ++#define JZFB_DUMP_LCDC_REG _IOW('F', 0x150, int) ++ ++#define JZFB_SET_VSYNCINT _IOW('F', 0x210, int) ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_Kconfig.patch new file mode 100644 index 00000000..bfe12b71 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_Kconfig.patch @@ -0,0 +1,48 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v12/Kconfig b/drivers/video/fbdev/ingenic/fb_v12/Kconfig +--- a/drivers/video/fbdev/ingenic/fb_v12/Kconfig 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v12/Kconfig 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,44 @@ ++menuconfig FB_INGENIC_V12 ++ tristate "Ingenic Framebuffer Driver for Version 12" ++ depends on FB_INGENIC ++ select FB_INGENIC_DISPLAYS_V12 ++ select FB_CFB_FILLRECT ++ select FB_CFB_COPYAREA ++ select FB_CFB_IMAGEBLIT ++ help ++ Framebuffer support for the Version 12 DPU SoC. ++ ++config INGENIC_FB_SIMPLE_RDMA ++ tristate "Use SIMPLE RDMA in dpu driver" ++ depends on FB_INGENIC_V12 ++ default n ++ help ++ use simple rdma in dpu driver. for advacned usage. ++ this will cause more memory allocated. ++ ++config INGENIC_FB_COLOR_MODE ++ tristate "INGENIC_FB_COLOR_MODE" ++ depends on FB_INGENIC_V12 ++ choice ++ prompt "Current Color Mode" ++ depends on INGENIC_FB_COLOR_MODE ++ config RGB888 ++ bool "RGB888" ++ config ARGB888 ++ bool "ARGB888" ++ config RGB555 ++ bool "RGB555" ++ config ARGB1555 ++ bool "ARGB1555" ++ config RGB565 ++ bool "RGB565" ++ config YUV422 ++ bool "YUV422" ++ config NV12 ++ bool "NV12" ++ config NV21 ++ bool "NV21" ++ endchoice ++ ++ ++source "drivers/video/fbdev/ingenic/fb_v12/displays/Kconfig" diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_Makefile.patch new file mode 100644 index 00000000..276a31c4 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_Makefile.patch @@ -0,0 +1,7 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v12/Makefile b/drivers/video/fbdev/ingenic/fb_v12/Makefile +--- a/drivers/video/fbdev/ingenic/fb_v12/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v12/Makefile 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,3 @@ ++obj-y += ingenicfb.o ++obj-y += displays/ ++obj-$(CONFIG_FB_INGENIC_MIPI_DSI) += jz_mipi_dsi/ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_Kconfig.patch new file mode 100644 index 00000000..cba0e2c5 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_Kconfig.patch @@ -0,0 +1,114 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v12/displays/Kconfig b/drivers/video/fbdev/ingenic/fb_v12/displays/Kconfig +--- a/drivers/video/fbdev/ingenic/fb_v12/displays/Kconfig 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v12/displays/Kconfig 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,110 @@ ++menuconfig FB_INGENIC_DISPLAYS_V12 ++ tristate "Supported lcd panels" ++ depends on FB_INGENIC_V12 ++ select BACKLIGHT_LCD_SUPPORT ++ select LCD_CLASS_DEVICE ++ select BACKLIGHT_CLASS_DEVICE ++ ++ ++config PANEL_V12_Y88249 ++ tristate "lcd panel y88249" ++ depends on FB_INGENIC_DISPLAYS_V12 ++ help ++ lcd panel y88249, for ingenicfb drivers. ++ ++config PANEL_V12_KD050HDFIA019 ++ tristate "lcd panel kd050hdfia019" ++ depends on FB_INGENIC_DISPLAYS_V12 ++ help ++ lcd panel kd050hdfia019, for ingenicfb drivers. ++ ++config PANEL_V12_MA0060 ++ tristate "lcd panel MA0060" ++ depends on FB_INGENIC_DISPLAYS_V12 ++ help ++ lcd panel MA0060, for ingenicfb drivers. ++ ++config PANEL_V12_TL040WVS03CT ++ tristate "lcd panel tl040wvs03ct" ++ depends on FB_INGENIC_DISPLAYS_V12 ++ help ++ lcd panel tl040wvs03ct, for ingenicfb drivers. ++ ++config PANEL_V12_TL040HDS01CT ++ tristate "lcd panel tl040hds01ct" ++ depends on FB_INGENIC_DISPLAYS_V12 ++ help ++ lcd panel tl040hds01ct, for ingenicfb drivers. ++ ++config PANEL_V12_JD9161Z ++ tristate "lcd panel JD9161Z" ++ depends on FB_INGENIC_DISPLAYS_V12 ++ help ++ lcd panel JD9161Z, for ingenicfb drivers. ++ ++config PANEL_V12_ST7701S ++ tristate "lcd panel ST7701S" ++ depends on FB_INGENIC_DISPLAYS_V12 ++ help ++ lcd panel ST7701S, for ingenicfb drivers. ++ ++config PANEL_V12_YTS500XLAI ++ tristate "lcd panel YTS500XLAI" ++ depends on FB_INGENIC_DISPLAYS_V12 ++ help ++ lcd panel YTS500XLAI, for ingenicfb drivers. ++ ++config PANEL_V12_YLYM286A ++ tristate "lcd panel ylym286a" ++ depends on FB_INGENIC_DISPLAYS_V12 ++ help ++ lcd panel ylym286a with bridge lt9211, for ingenicfb drivers. ++ ++config PANEL_X2000_KD035HVFBD037 ++ tristate "SLCD KD035HVFBD037 with control IC otm4802a (320x480)" ++ depends on FB_INGENIC_DISPLAYS_V12 ++ help ++ lcd panel KD035HVFBD037, for ingenicfb drivers. ++ ++config PANEL_BM8766 ++ tristate "TFT BM8766 (800x480)" ++ depends on FB_INGENIC_DISPLAYS_V12 ++ help ++ lcd panel BM8766, for ingenicfb drivers. ++ ++config PANEL_TRULY240240 ++ tristate "SLCD TRULY240240 (240x240)" ++ depends on FB_INGENIC_DISPLAYS_V12 ++ help ++ lcd panel TRULY240240, for ingenicfb drivers. ++ ++config PANEL_ST7789V240320 ++ tristate "SLCD ST7789V240320 (240x320)" ++ depends on FB_INGENIC_DISPLAYS_V12 ++ help ++ lcd panel TRULY240240, for ingenicfb drivers. ++ ++config PANEL_EK79007 ++ tristate "TFT EK79007 (1024x600)" ++ depends on FB_INGENIC_DISPLAYS_V12 ++ help ++ lcd panel EK79007, for ingenicfb drivers. ++ ++config PANEL_ST7703 ++ tristate "TFT ST7703 (1280*720)" ++ depends on FB_INGENIC_DISPLAYS_V12 ++ help ++ lcd panel ST7703, for ingenicfb drivers. ++ ++config PANEL_PX070 ++ tristate "TFT PX070 (1024x600)" ++ depends on FB_INGENIC_DISPLAYS_V12 ++ help ++ lcd panel px070, for ingenicfb drivers. ++ ++config PANEL_MTF070 ++ tristate "TFT MTF070 (800x1280)" ++ depends on FB_INGENIC_DISPLAYS_V12 ++ help ++ lcd panel mtf070, for ingenicfb drivers. ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_Makefile.patch new file mode 100644 index 00000000..b70478b4 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_Makefile.patch @@ -0,0 +1,21 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v12/displays/Makefile b/drivers/video/fbdev/ingenic/fb_v12/displays/Makefile +--- a/drivers/video/fbdev/ingenic/fb_v12/displays/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v12/displays/Makefile 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,17 @@ ++obj-$(CONFIG_PANEL_V12_Y88249) += panel-y88249.o ++obj-$(CONFIG_PANEL_V12_KD050HDFIA019) += panel-kd050hdfia019.o ++obj-$(CONFIG_PANEL_V12_MA0060) += panel-ma0060.o ++obj-$(CONFIG_PANEL_V12_TL040WVS03CT) += panel-tl040wvs03ct.o ++obj-$(CONFIG_PANEL_V12_TL040HDS01CT) += panel-tl040hds01ct.o ++obj-$(CONFIG_PANEL_V12_JD9161Z) += panel-jd9161z.o ++obj-$(CONFIG_PANEL_V12_ST7701S) += panel-st7701s.o ++obj-$(CONFIG_PANEL_V12_YTS500XLAI) += panel-yts500xlai.o ++obj-$(CONFIG_PANEL_V12_YLYM286A) += panel-ylym286a.o ++obj-$(CONFIG_PANEL_X2000_KD035HVFBD037) += panel-kd035hvfbd037.o ++obj-$(CONFIG_PANEL_BM8766) += panel-bm8766.o ++obj-$(CONFIG_PANEL_TRULY240240) += panel-truly_240_240.o ++obj-$(CONFIG_PANEL_ST7789V240320) += panel-st7789v_240_320.o ++obj-$(CONFIG_PANEL_EK79007) += panel-ek79007.o ++obj-$(CONFIG_PANEL_ST7703) += panel-st7703.o ++obj-$(CONFIG_PANEL_PX070) += panel-px070.o ++obj-$(CONFIG_PANEL_MTF070) += panel-mtf070.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_lt9211.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_lt9211.c.patch new file mode 100644 index 00000000..87bd0a55 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_lt9211.c.patch @@ -0,0 +1,571 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v12/displays/lt9211.c b/drivers/video/fbdev/ingenic/fb_v12/displays/lt9211.c +--- a/drivers/video/fbdev/ingenic/fb_v12/displays/lt9211.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v12/displays/lt9211.c 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,567 @@ ++#include "lt9211.h" ++ ++static unsigned char mipi_fmt = 0; ++ ++struct video_timing *pVideo_Format; ++ ++#ifdef DEBUG ++#define debug(info, ...) printk(info, ##__VA_ARGS__) ++#else ++#define debug(info, ...) ++#endif ++ ++#define HTOTAL (HFP + HACT + HBP + HS) ++#define VTOTAL (VFP + VACT + VBP + VS) ++ ++#define PIXCLK (HTOTAL * VTOTAL * FPS / 1000) ++ ++//hfp, hs, hbp, hact, htotal, vfp, vs, vbp, vact, vtotal, pixclk ++struct video_timing video_640x480_60Hz ={ 8, 96, 40, 640, 800, 33, 2, 10, 480, 525, 25000}; ++struct video_timing video_720x480_60Hz ={16, 62, 60, 720, 858, 9, 6, 30, 480, 525, 27000}; ++struct video_timing video_1280x720_60Hz ={110,40, 220,1280, 1650, 5, 5, 20, 720, 750, 74250}; ++struct video_timing video_1280x720_30Hz ={110,40, 220,1280, 1650, 5, 5, 20, 720, 750, 37125}; ++struct video_timing video_1366x768_60Hz ={26, 110,110,1366, 1592, 13, 6, 13, 768, 800, 81000}; ++struct video_timing video_1920x720_60Hz ={148,44, 88, 1920, 2200, 28, 5, 12, 720, 765, 88000}; ++struct video_timing video_1920x1080_30Hz ={88, 44, 148,1920, 2200, 4, 5, 36, 1080, 1125, 74250}; ++struct video_timing video_1920x1080_60Hz ={HFP, HS, HBP, HACT, HTOTAL, VFP, VS, VBP, VACT, VTOTAL, PIXCLK}; ++struct video_timing video_1920x1200_60Hz ={48, 32, 80,1920, 2080, 3, 6, 26, 1200, 1235, 154000}; ++struct video_timing video_3840x2160_30Hz ={176,88, 296,3840, 4400, 8, 10, 72, 2160, 2250, 297000}; ++ ++static unsigned int i2c_write(struct i2c_client *client,unsigned char addr,unsigned char value); ++static unsigned char i2c_read(struct i2c_client *client, u8 addr); ++ ++#ifdef DEBUG ++static void LT9211_ChipID(struct i2c_client *client) ++{ ++ i2c_write(client, 0xff,0x81);//register bank ++ printk("LT9211 Chip ID:%x,",i2c_read(client, 0x00)); ++ printk("%02x, ",i2c_read(client, 0x01)); ++ printk("%02x\n",i2c_read(client, 0x02)); ++} ++#endif ++ ++/** video chk soft rst **/ ++#if 0 ++static void lt9211_vid_chk_rst(struct i2c_client *client) ++{ ++ i2c_write(client, 0xff,0x81); ++ i2c_write(client, 0x10,0xbe); ++ mdelay(10); ++ i2c_write(client, 0x10,0xfe); ++} ++#endif ++ ++/** lvds rx logic rst **/ ++static void lt9211_mipirx_logic_rst(struct i2c_client *client) ++{ ++ i2c_write(client, 0xff,0x81); ++ i2c_write(client, 0x0a,0xc0); ++ i2c_write(client, 0x20,0xbf); //mipi rx div logic reset,for portb input ++ mdelay(10); ++ i2c_write(client, 0x0a,0xc1); ++ i2c_write(client, 0x20,0xff); ++} ++ ++static void LT9211_SystemInt(struct i2c_client *client) ++{ ++ /* system clock init */ ++ i2c_write(client, 0xff,0x82); ++ i2c_write(client, 0x01,0x18); ++ ++ i2c_write(client, 0xff,0x86); ++ i2c_write(client, 0x06,0x61); ++ i2c_write(client, 0x07,0xa8); //fm for sys_clk ++ ++ i2c_write(client, 0xff,0x87); ++ i2c_write(client, 0x14,0x08); //default value ++ i2c_write(client, 0x15,0x00); //default value ++ i2c_write(client, 0x18,0x0f); ++ i2c_write(client, 0x22,0x08); //default value ++ i2c_write(client, 0x23,0x00); //default value ++ i2c_write(client, 0x26,0x0f); ++ ++ i2c_write(client, 0xff,0x81); ++ i2c_write(client, 0x0B,0xFE); //rpt reset ++} ++ ++#if 0 ++static void LT9211_ClkDetDebug(struct i2c_client *client) ++{ ++ unsigned int fm_value; ++ ++ i2c_write(client, 0xff,0x86); ++ i2c_write(client, 0x00,0x14); ++ mdelay(100); ++ fm_value = 0; ++ fm_value = (i2c_read(client, 0x08) &(0x0f)); ++ fm_value = (fm_value<<8) ; ++ fm_value = fm_value + i2c_read(client, 0x09); ++ fm_value = (fm_value<<8) ; ++ fm_value = fm_value + i2c_read(client, 0x0a); ++ ++ printk("input ttlclk: \n"); ++ printk("\033[33m fm_value = %x |\033[0m\n", fm_value); ++} ++#endif ++ ++static void LT9211_MipiRxPhy(struct i2c_client *client) ++{ ++#ifdef INPUT_PORTA ++ debug("Port A PHY Config\n"); ++ i2c_write(client, 0xff,0x82); ++ i2c_write(client, 0x02,0x44); //Port A MIPI mode enable ++ i2c_write(client, 0x04,0xa0); //select port A clk as byteclk ++ i2c_write(client, 0x05,0x22); //port A CLK lane swap ++ i2c_write(client, 0x07,0x9f); //port A clk enable ++ i2c_write(client, 0x08,0xfc); //port A clk enable ++ i2c_write(client, 0x09,0x01); //port A P/N swap ++ i2c_write(client, 0x17,0x0c); ++ ++ i2c_write(client, 0xff,0x86); ++ i2c_write(client, 0x33,0x1b); //port a lane swap 1b:no swap ++#endif ++ ++#ifdef INPUT_PORTB ++ debug("Port B PHY Config\n"); ++ i2c_write(client, 0xff,0x82); ++ i2c_write(client, 0x02,0x44); //Port A/B MIPI mode enable ++ i2c_write(client, 0x04,0xa1); //select port A clk as byteclk ++ i2c_write(client, 0x05,0x26); //port A CLK lane swap ++ i2c_write(client, 0x0d,0x26); //port B CLK lane swap ++ i2c_write(client, 0x07,0x9f); //port A clk enable (??Portb?,porta?lane0 clk???) ++ i2c_write(client, 0x0f,0x9f); //port B clk enable ++ i2c_write(client, 0x10,0xfc); //select port B clk as byteclk ++ i2c_write(client, 0x11,0x01); //port B P/N swap ++ i2c_write(client, 0x17,0x0c); ++ i2c_write(client, 0x1d,0x0c); ++ ++ i2c_write(client, 0xff,0x86); ++ i2c_write(client, 0x34,0x1b); //Port B Lane swap ++#endif ++ ++ i2c_write(client, 0xff,0x81); ++ i2c_write(client, 0x20,0x7f); ++ i2c_write(client, 0x20,0xff); //mlrx calib reset ++} ++ ++static void LT9211_MipiRxDigital(struct i2c_client *client) ++{ ++ i2c_write(client, 0xff,0x86); ++#ifdef INPUT_PORTA ++ i2c_write(client, 0x30,0x85); //mipirx input port sel ++#endif ++ ++#ifdef INPUT_PORTB ++ i2c_write(client, 0x30,0x8f); //mipirx input port sel ++#endif ++ ++ i2c_write(client, 0xff,0x85); ++ i2c_write(client, 0x88,0x40); //select mipi in lvds out ++ ++#ifdef MIPI_CSI ++ debug("Set to CSI Mode\n"); ++ i2c_write(client, 0xff,0xd0); //CSI_EN ++ i2c_write(client, 0x04,0x10); ++ i2c_write(client, 0x21,0xc6); //CSI_SEL ++#else ++ debug("Set to DSI Mode\n"); ++#endif ++ ++ i2c_write(client, 0xff,0xd0); ++ i2c_write(client, 0x00,0x02); //4Lane:0x00, 2Lane:0x02, 1Lane:0x01 ++ i2c_write(client, 0x02,0x05); //settle ++} ++ ++static void LT9211_SetVideoTiming(struct i2c_client *client, struct video_timing *video_format) ++{ ++ mdelay(100); ++ i2c_write(client, 0xff,0xd0); ++ i2c_write(client, 0x0d,(unsigned char)(video_format->vtotal>>8)); //vtotal[15:8] ++ i2c_write(client, 0x0e,(unsigned char)(video_format->vtotal)); //vtotal[7:0] ++ i2c_write(client, 0x0f,(unsigned char)(video_format->vact>>8)); //vactive[15:8] ++ i2c_write(client, 0x10,(unsigned char)(video_format->vact)); //vactive[7:0] ++ i2c_write(client, 0x15,(unsigned char)(video_format->vs)); //vs[7:0] ++ i2c_write(client, 0x17,(unsigned char)(video_format->vfp>>8)); //vfp[15:8] ++ i2c_write(client, 0x18,(unsigned char)(video_format->vfp)); //vfp[7:0] ++ ++ i2c_write(client, 0x11,(unsigned char)(video_format->htotal>>8)); //htotal[15:8] ++ i2c_write(client, 0x12,(unsigned char)(video_format->htotal)); //htotal[7:0] ++ i2c_write(client, 0x13,(unsigned char)(video_format->hact>>8)); //hactive[15:8] ++ i2c_write(client, 0x14,(unsigned char)(video_format->hact)); //hactive[7:0] ++ i2c_write(client, 0x16,(unsigned char)(video_format->hs)); //hs[7:0] ++ i2c_write(client, 0x19,(unsigned char)(video_format->hfp>>8)); //hfp[15:8] ++ i2c_write(client, 0x1a,(unsigned char)(video_format->hfp)); //hfp[7:0] ++} ++ ++#ifdef DEBUG ++static void LT9211_debug(struct i2c_client *client) ++{ ++ int i; ++ unsigned char start = 0x80; ++ i2c_write(client, 0xff,0xd0); ++ for(i=0;i<30;i++) ++ printk("read 0x%02x = 0x%02x\n", start+i, i2c_read(client, start+i)); ++} ++#endif ++ ++static int LT9211_TimingSet(struct i2c_client *client) ++{ ++ unsigned short hact ; ++ unsigned short vact ; ++ unsigned char pa_lpn = 0; ++ ++ lt9211_mipirx_logic_rst(client); ++ mdelay(100); ++ ++ i2c_write(client, 0xff,0xd0); ++ hact = (i2c_read(client, 0x82)<<8) + i2c_read(client, 0x83) ; ++ mipi_fmt = (i2c_read(client, 0x84) & 0x0f); ++ vact = (i2c_read(client, 0x85)<<8) +i2c_read(client, 0x86); ++ pa_lpn = i2c_read(client, 0x9c); ++#ifdef DEBUG ++ LT9211_debug(client); ++#endif ++ ++ if(mipi_fmt == 0x03) { ++ debug("Input MIPI FMT: CSI_YUV422_16\n"); ++ hact = hact / 2; ++ } else if(mipi_fmt == 0x0a) { ++ debug("Input MIPI FMT: RGB888\n"); ++ hact = hact / 3; ++ } ++ ++ debug("\033[33m hact = %d |\033[0m\n", hact); ++ debug("\033[33m vact = %d |\033[0m\n", vact); ++ ++ debug("fmt = %x\n", mipi_fmt); ++ debug("pa_lpn = %x\n", pa_lpn); ++ ++ mdelay(100); ++ if ((hact == video_1280x720_60Hz.hact ) &&( vact == video_1280x720_60Hz.vact )) { ++ pVideo_Format = &video_1280x720_60Hz; ++ LT9211_SetVideoTiming(client, &video_1280x720_60Hz); ++ } else if ((hact == video_1366x768_60Hz.hact ) &&( vact == video_1366x768_60Hz.vact )) { ++ pVideo_Format = &video_1366x768_60Hz; ++ LT9211_SetVideoTiming(client, &video_1366x768_60Hz); ++ } else if ((hact == video_1920x1080_60Hz.hact ) &&( vact == video_1920x1080_60Hz.vact )) { ++ pVideo_Format = &video_1920x1080_60Hz; ++ LT9211_SetVideoTiming(client, &video_1920x1080_60Hz); ++ } else if ((hact == video_1920x1200_60Hz.hact ) &&( vact == video_1920x1200_60Hz.vact )) { ++ pVideo_Format = &video_1920x1200_60Hz; ++ LT9211_SetVideoTiming(client, &video_1920x1200_60Hz); ++ } else { ++ pVideo_Format = NULL; ++ printk("video_none\n"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static void LT9211_DesscPll(struct i2c_client *client) ++{ ++ i2c_write(client, 0xff,0x82); ++ i2c_write(client, 0x2d,0x48); ++ ++ if(pVideo_Format->pclk_khz < 44000) { ++ i2c_write(client, 0x35,0x83); ++ } else if(pVideo_Format->pclk_khz < 88000) { ++ i2c_write(client, 0x35,0x82); ++ } else if(pVideo_Format->pclk_khz < 176000) { ++ i2c_write(client, 0x35,0x81); ++ } ++} ++ ++static int LT9211_MipiPcr(struct i2c_client *client) ++{ ++ unsigned char loopx; ++ i2c_write(client, 0xff,0xd0); ++ i2c_write(client, 0x26,0x17); ++ i2c_write(client, 0x27,0xC3); ++ i2c_write(client, 0x2d,0x30); //PCR M overflow limit setting. ++ i2c_write(client, 0x31,0x10); //PCR M underflow limit setting. ++ i2c_write(client, 0x23,0x20); ++ ++ i2c_write(client, 0x38,0x02); ++ i2c_write(client, 0x39,0x10); ++ i2c_write(client, 0x3a,0x20); ++ i2c_write(client, 0x3b,0x60); ++ i2c_write(client, 0x3f,0x04); ++ i2c_write(client, 0x40,0x08); ++ i2c_write(client, 0x41,0x10); ++ ++ i2c_write(client, 0xff,0x81); ++ i2c_write(client, 0x0B,0xEE); ++ i2c_write(client, 0x0B,0xFE); ++ ++ for(loopx = 0; loopx < 5; loopx++) //Check pcr_stable ++ { ++ mdelay(200); ++ i2c_write(client, 0xff,0xd0); ++ if(i2c_read(client, 0x87)&0x08) { ++ debug("\033[32mLT9211 pcr stable\033[0m\n"); ++ return 0; ++ } ++ } ++ printk("LT9211 pcr unstable!!!!\n"); ++ return -1; ++} ++ ++static void LT9211_CSC(struct i2c_client *client) ++{ ++ //yuv422 to rgb888 ++ if(mipi_fmt == 0x03) { ++ debug("csc:yuv422 to rgb888\n"); ++ i2c_write(client, 0xff,0xf9); ++ i2c_write(client, 0x90,0x03); ++ i2c_write(client, 0x91,0x03); ++ } ++} ++ ++static void LT9211_TxPhy(struct i2c_client *client) ++{ ++ i2c_write(client, 0xff,0x82); ++ i2c_write(client, 0x62,0x00); //ttl output disable ++ if( LVDS_PORTNUM == LVDS_2PORT ) { ++ i2c_write(client, 0x3b,0xb8); ++ } else { ++ i2c_write(client, 0x3b,0x38); //dual-port lvds tx phy ++ } ++ i2c_write(client, 0x3e,0x92); ++ i2c_write(client, 0x3f,0x48); ++ i2c_write(client, 0x40,0x31); ++ i2c_write(client, 0x43,0x80); ++ i2c_write(client, 0x44,0x00); ++ i2c_write(client, 0x45,0x00); ++ i2c_write(client, 0x49,0x00); ++ i2c_write(client, 0x4a,0x01); ++ i2c_write(client, 0x4e,0x00); ++ i2c_write(client, 0x4f,0x00); ++ i2c_write(client, 0x50,0x00); ++ i2c_write(client, 0x53,0x00); ++ i2c_write(client, 0x54,0x01); ++ ++ i2c_write(client, 0xff,0x86); ++ i2c_write(client, 0x46,0x10); ++#ifdef LVDS_2PORT_SWAP ++ debug("LVDS Output Port Swap!\n"); ++ i2c_write(client, 0x46,0x40); ++#endif ++ ++ i2c_write(client, 0xff,0x81); ++ i2c_write(client, 0x20,0x7b); ++ i2c_write(client, 0x20,0xff); //mlrx mltx calib reset ++} ++ ++static void LT9211_TxDigital(struct i2c_client *client) ++{ ++ debug("LT9211 LVDS_OUTPUT_MODE: \n"); ++ i2c_write(client, 0xff,0x85); /* lvds tx controller */ ++ i2c_write(client, 0x59,0x40); ++ if( LVDS_DATAFORMAT == VESA ) { ++ debug("Data Format: VESA\n"); ++ i2c_write(client, 0x59, (i2c_read(client, 0x59) & 0x7f)); ++ } else if( LVDS_DATAFORMAT == JEIDA ) { ++ debug("Data Format: JEIDA\n"); ++ i2c_write(client, 0x59, (i2c_read(client, 0x59) | 0x80)); ++ } ++ if( LVDS_COLORDEPTH == DEPTH_6BIT ) { ++ debug("ColorDepth: 6Bit\n"); ++ i2c_write(client, 0x59, (i2c_read(client, 0x59) & 0xef)); ++ } else if( LVDS_COLORDEPTH == DEPTH_8BIT ) { ++ debug("ColorDepth: 8Bit\n"); ++ i2c_write(client, 0x59, (i2c_read(client, 0x59) | 0x10)); ++ } ++ if( LVDS_MODE == SYNC_MODE ) { ++ debug("LVDS_MODE: Sync Mode\n"); ++ i2c_write(client, 0x59, (i2c_read(client, 0x59) & 0xdf)); ++ } else if( LVDS_MODE == DE_MODE ) { ++ debug("LVDS_MODE: De Mode\n"); ++ i2c_write(client, 0x59, (i2c_read(client, 0x59) | 0x20)); ++ } ++ ++ i2c_write(client, 0x5a,0xaa); ++ i2c_write(client, 0x5b,0xaa); ++ if( LVDS_PORTNUM == LVDS_2PORT ) { ++ debug("LVDS Output Port Num: 2Port\n"); ++ i2c_write(client, 0x5c,0x01); //lvdstx port sel 01:dual;00:single ++ } else { ++ debug("LVDS Output Port Num: 1Port\n"); ++ i2c_write(client, 0x5c,0x00); ++ } ++ i2c_write(client, 0xa1,0x77); ++ i2c_write(client, 0xff,0x86); ++ i2c_write(client, 0x40,0x40); //tx_src_sel ++ /*port src sel*/ ++ i2c_write(client, 0x41,0x34); ++ i2c_write(client, 0x42,0x10); ++ i2c_write(client, 0x43,0x23); //pt0_tx_src_sel ++ i2c_write(client, 0x44,0x41); ++ i2c_write(client, 0x45,0x02); //pt1_tx_src_scl ++} ++ ++static void LT9211_Txpll(struct i2c_client *client) ++{ ++ unsigned char loopx; ++ ++ i2c_write(client, 0xff,0x82); ++ i2c_write(client, 0x36,0x01); //b7:txpll_pd ++ if( LVDS_PORTNUM == LVDS_1PORT ) { ++ i2c_write(client, 0x37,0x29); ++ } else { ++ i2c_write(client, 0x37,0x2a); ++ } ++ i2c_write(client, 0x38,0x06); ++ i2c_write(client, 0x39,0x30); ++ i2c_write(client, 0x3a,0x8e); ++ i2c_write(client, 0xff,0x87); ++ i2c_write(client, 0x37,0x14); ++ i2c_write(client, 0x13,0x00); ++ i2c_write(client, 0x13,0x80); ++ mdelay(100); ++ for(loopx = 0; loopx < 10; loopx++) //Check Tx PLL cal ++ { ++ i2c_write(client, 0xff,0x87); ++ if(i2c_read(client, 0x1f)& 0x80) { ++ if(i2c_read(client, 0x20)& 0x80) { ++ debug("LT9211 tx pll lock\n"); ++ } else { ++ printk("LT9211 tx pll unlocked\n"); ++ } ++ debug("LT9211 tx pll cal done\n"); ++ break; ++ } else { ++ printk("LT9211 tx pll unlocked\n"); ++ } ++ } ++} ++ ++#ifdef DEBUG ++static void LT9211_LvdsClkDebug(struct i2c_client *client) ++{ ++ unsigned int fm_value; ++ ++ i2c_write(client, 0xff,0x86); ++ i2c_write(client, 0x00,0x12); ++ mdelay(100); ++ fm_value = 0; ++ fm_value = (i2c_read(client, 0x08) &(0x0f)); ++ fm_value = (fm_value<<8) ; ++ fm_value = fm_value + i2c_read(client, 0x09); ++ fm_value = (fm_value<<8) ; ++ fm_value = fm_value + i2c_read(client, 0x0a); ++ ++ printk("\033[33m lvds pixclk = %d |\033[0m\n", fm_value); ++} ++ ++static void LT9211_MipiByteClkDebug(struct i2c_client *client) ++{ ++ unsigned int fm_value; ++ ++ i2c_write(client, 0xff,0x86); ++#ifdef INPUT_PORTA ++ i2c_write(client, 0x00,0x01); ++#endif ++#ifdef INPUT_PORTB ++ i2c_write(client, 0x00,0x02); ++#endif ++ mdelay(100); ++ fm_value = 0; ++ fm_value = (i2c_read(client, 0x08) &(0x0f)); ++ fm_value = (fm_value<<8) ; ++ fm_value = fm_value + i2c_read(client, 0x09); ++ fm_value = (fm_value<<8) ; ++ fm_value = fm_value + i2c_read(client, 0x0a); ++ printk("\033[33m mipi byteclk = %d |\033[0m\n", fm_value); ++} ++ ++static void LT9211_VideoCheckDebug(struct i2c_client *client) ++{ ++ unsigned char sync_polarity; ++ unsigned short hact, vact; ++ unsigned short hs, vs; ++ unsigned short hbp, vbp; ++ unsigned short htotal, vtotal; ++ unsigned short hfp, vfp; ++ ++ i2c_write(client, 0xff,0x86); ++ i2c_write(client, 0x20,0x00); ++ ++ sync_polarity = i2c_read(client, 0x70); ++ vs = i2c_read(client, 0x71); ++ ++ hs = i2c_read(client, 0x72); ++ hs = (hs<<8) + i2c_read(client, 0x73); ++ ++ vbp = i2c_read(client, 0x74); ++ vfp = i2c_read(client, 0x75); ++ ++ hbp = i2c_read(client, 0x76); ++ hbp = (hbp<<8) + i2c_read(client, 0x77); ++ ++ hfp = i2c_read(client, 0x78); ++ hfp = (hfp<<8) + i2c_read(client, 0x79); ++ ++ vtotal = i2c_read(client, 0x7A); ++ vtotal = (vtotal<<8) + i2c_read(client, 0x7B); ++ ++ htotal = i2c_read(client, 0x7C); ++ htotal = (htotal<<8) + i2c_read(client, 0x7D); ++ ++ vact = i2c_read(client, 0x7E); ++ vact = (vact<<8)+ i2c_read(client, 0x7F); ++ ++ hact = i2c_read(client, 0x80); ++ hact = (hact<<8) + i2c_read(client, 0x81); ++ ++ printk("sync_polarity = %x\n", sync_polarity); ++ ++ printk("\033[33m hfp = %d , hs = %d , hbp = %d , hact = %d , htotal = %d\033[0m\n", hfp, hs, hbp, hact, htotal); ++ ++ printk("\033[33m vfp = %d , vs = %d , vbp = %d , vact = %d , vtotal = %d\033[0m\n", vfp, vs, vbp, vact, vtotal); ++} ++#endif ++ ++int LT9211_MIPI2LVDS_Config(struct i2c_client *client) ++{ ++ int retry = 5; ++ int ret = 0; ++ debug("*************LT9211 MIPI2LVDS Config*************\n"); ++#ifdef DEBUG ++ LT9211_ChipID(client); ++#endif ++ LT9211_SystemInt(client); ++ LT9211_MipiRxPhy(client); ++ LT9211_MipiRxDigital(client); ++ ++ while(retry--) ++ if ((ret = LT9211_TimingSet(client)) == 0) break; ++ ++ if( pVideo_Format != NULL ) ++ { ++#ifdef DEBUG ++ LT9211_MipiByteClkDebug(client); ++#endif ++ LT9211_DesscPll(client); ++ ++ retry = 5; ++ while(retry--) ++ if ((ret = LT9211_MipiPcr(client)) == 0) break; ++ ++ LT9211_CSC(client); ++ /********LVDS OUTPUT CONFIG********/ ++ LT9211_TxPhy(client); ++ LT9211_TxDigital(client); ++ LT9211_Txpll(client); ++ ++#ifdef DEBUG ++ /* i2c_write(client, 0xff,0x85); */ ++ /* i2c_write(client, 0x88,0xC0); // debug: colorbar */ ++ /* i2c_write(client, 0xA1,0x04); // single color 0x1: blue, 0x2: green, 0x4: red. */ ++ ++ LT9211_LvdsClkDebug(client); ++ LT9211_VideoCheckDebug(client); ++#endif ++ } ++ return ret; ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_lt9211.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_lt9211.h.patch new file mode 100644 index 00000000..28a6bcec --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_lt9211.h.patch @@ -0,0 +1,66 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v12/displays/lt9211.h b/drivers/video/fbdev/ingenic/fb_v12/displays/lt9211.h +--- a/drivers/video/fbdev/ingenic/fb_v12/displays/lt9211.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v12/displays/lt9211.h 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,62 @@ ++#ifndef _LT9211_H ++#define _LT9211_H ++ ++/* #define DEBUG */ ++ ++/******************* MIPI Input Config ********************/ ++/* #define MIPI_CSI */ ++ ++#define INPUT_PORTA ++//#define INPUT_PORTB ++ ++#define Lane_Num 2 ++/******************* MIPI Input Config ********************/ ++ ++/******************* Lvds Output Config ********************/ ++enum LT9211_LVDSPORT_ENUM ++{ ++ LVDS_1PORT = 0, ++ LVDS_2PORT = 1 ++}; ++#define LVDS_PORTNUM LVDS_2PORT ++ ++enum LT9211_LVDSMODE_ENUM ++{ ++ DE_MODE = 0, ++ SYNC_MODE = 1 ++}; ++#define LVDS_MODE DE_MODE ++ ++enum LT9211_LVDSDATAFORMAT_ENUM ++{ ++ VESA = 0, ++ JEIDA = 1 ++}; ++#define LVDS_DATAFORMAT VESA ++ ++enum LT9211_LVDSCOLORDEPTH_ENUM ++{ ++ DEPTH_6BIT = 0, ++ DEPTH_8BIT = 1 ++}; ++#define LVDS_COLORDEPTH DEPTH_8BIT ++ ++//#define LVDS_2PORT_SWAP ++ ++/******************* Lvds Output Config ********************/ ++ ++struct video_timing { ++unsigned short hfp; ++unsigned short hs; ++unsigned short hbp; ++unsigned short hact; ++unsigned short htotal; ++unsigned short vfp; ++unsigned short vs; ++unsigned short vbp; ++unsigned short vact; ++unsigned short vtotal; ++unsigned int pclk_khz; ++}; ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-bm8766.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-bm8766.c.patch new file mode 100644 index 00000000..fde31dc6 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-bm8766.c.patch @@ -0,0 +1,315 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v12/displays/panel-bm8766.c b/drivers/video/fbdev/ingenic/fb_v12/displays/panel-bm8766.c +--- a/drivers/video/fbdev/ingenic/fb_v12/displays/panel-bm8766.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v12/displays/panel-bm8766.c 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,311 @@ ++/* ++ * ingenic_bsp/chip-x2000/fpga/dpu/bm8766.c ++ * ++ * Copyright (C) 2016 Ingenic Semiconductor Inc. ++ * ++ * Author:clwang ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../ingenicfb.h" ++ ++struct board_gpio { ++ short gpio; ++ short active_level; ++}; ++ ++struct panel_dev { ++ /* ingenic frame buffer */ ++ struct device *dev; ++ struct lcd_panel *panel; ++ ++ /* common lcd framework */ ++ struct lcd_device *lcd; ++ struct backlight_device *backlight; ++ int power; ++ ++ struct regulator *vcc; ++ struct board_gpio vdd_en; ++ struct board_gpio bl; ++ struct board_gpio rst; ++ struct board_gpio pwm; ++}; ++ ++static struct panel_dev *panel; ++ ++static void bm8766_power_on(struct lcd_panel *ppanel) ++{ ++ struct panel_dev *panel_bm8766 = dev_get_drvdata(panel->dev); ++ ++ gpio_direction_output(panel_bm8766->bl.gpio, panel_bm8766->bl.active_level); ++} ++ ++static void bm8766_power_off(struct lcd_panel *ppanel) ++{ ++ struct panel_dev *panel_bm8766 = dev_get_drvdata(panel->dev); ++ ++ gpio_direction_output(panel_bm8766->bl.gpio, !panel_bm8766->bl.active_level); ++ return; ++} ++ ++static struct lcd_panel_ops bm8766_ops = { ++ .enable = (void*)bm8766_power_on, ++ .disable = (void*)bm8766_power_off, ++}; ++ ++static struct fb_videomode jzfb_bm8766_videomode[] = { ++ [0] = { ++ .name = "800x480", ++ /* .refresh = 30, */ ++ .refresh = 60, ++ .xres = 800, ++ .yres = 480, ++ /* .pixclock = KHZ2PICOS(16632), */ ++ .pixclock = KHZ2PICOS(33264), ++ .left_margin = 88, ++ .right_margin = 40, ++ .upper_margin = 8, ++ .lower_margin = 35, ++ .hsync_len = 128, ++ .vsync_len = 2, ++ .sync = ~FB_SYNC_HOR_HIGH_ACT & ~FB_SYNC_VERT_HIGH_ACT, ++ .vmode = FB_VMODE_NONINTERLACED, ++ .flag = 0, ++ }, ++}; ++ ++static struct tft_config bm8766_cfg = { ++ .pix_clk_inv = 0, ++ .de_dl = 0, ++ .sync_dl = 0, ++ .color_even = TFT_LCD_COLOR_EVEN_BGR, ++ .color_odd = TFT_LCD_COLOR_ODD_BGR, ++ .mode = TFT_LCD_MODE_PARALLEL_666, ++}; ++ ++struct lcd_panel lcd_panel = { ++ .name = "bm8766", ++ .num_modes = ARRAY_SIZE(jzfb_bm8766_videomode), ++ .modes = jzfb_bm8766_videomode, ++ .lcd_type = LCD_TYPE_TFT, ++ .bpp = 24, ++ .width = 800, ++ .height = 480, ++ ++ .tft_config = &bm8766_cfg, ++ ++ /*T40 RGB real line is 666, so, for RGB888, we discard low 2 bytes, config as follows:*/ ++ .dither_enable = 1, ++ .dither.dither_red = 1, ++ .dither.dither_green = 1, ++ .dither.dither_blue = 1, ++ ++ .ops = &bm8766_ops, ++}; ++ ++#if 0 ++static int panel_update_status(struct backlight_device *bd) ++{ ++ struct panel_dev *panel = dev_get_drvdata(&bd->dev); ++ int brightness = bd->props.brightness; ++ unsigned int i; ++ int pulse_num = MAX_BRIGHTNESS_STEP - brightness / CONVERT_FACTOR - 1; ++ ++ if (FB_BLANK_POWERDOWN == bd->pros.fb_blank) ++ return 0; ++ ++ if (bd->props.state & BL_CORE_SUSPEND) ++ brightness = 0; ++ ++ if (brightness) { ++ gpio_direction_output(panel->pwm.gpio, 0); ++ udelay(5000); ++ gpio_direction_output(panel->pwm.gpio, 1); ++ udelay(100); ++ ++ for (i = pulse_num; i > 0 ; i--) { ++ gpio_direction_output(panel->pwm.gpio, 0); ++ udelay(1); ++ gpio_direction_output(panel->pwm.gpio, 1); ++ udelay(3); ++ } ++ } else ++ gpio_direction_output(panel->pwm.gpio, 0); ++ ++ return 0; ++} ++ ++static struct backlight_ops panel_backlight_ops = { ++ .options = BL_CORE_SUSPENDRESUME, ++ .update_status = panel_update_status, ++}; ++#endif ++ ++#define RESET(n)\ ++ gpio_direction_output(panel->rst.gpio, n) ++#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL) ++static int panel_set_power(struct lcd_device *lcd, int power) ++{ ++ return 0; ++} ++ ++static int panel_get_power(struct lcd_device *lcd) ++{ ++ struct panel_dev *panel = lcd_get_data(lcd); ++ ++ return panel->power; ++} ++ ++/** ++ * @ panel_bm8766_lcd_ops, register to kernel common backlight/lcd.c frameworks. ++ */ ++static struct lcd_ops panel_lcd_ops = { ++ .early_set_power = panel_set_power, ++ .set_power = panel_set_power, ++ .get_power = panel_get_power, ++}; ++ ++static int of_panel_parse(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ struct device_node *np = dev->of_node; ++ enum of_gpio_flags flags; ++ int ret = 0; ++ ++ panel->bl.gpio = of_get_named_gpio_flags(np, "ingenic,bl-gpio", 0, &flags); ++ if (gpio_is_valid(panel->bl.gpio)) { ++ panel->bl.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ ret = devm_gpio_request(dev, panel->bl.gpio, "backlight"); ++ if (ret < 0) { ++ dev_err(dev, "Failed to request backlight pin!\n"); ++ return ret; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio backlight.gpio: %d\n", panel->bl.gpio); ++ } ++ ++ return 0; ++} ++ ++/** ++ * @panel_probe ++ * ++ * 1. register to ingenicfb. ++ * 2. register to lcd. ++ * 3. register to backlight if possible. ++ * ++ * @pdev ++ * ++ * @return - ++ * */ ++static int panel_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ struct backlight_properties props; //backlight properties ++ ++ memset(&props, 0, sizeof(props)); ++ panel = kzalloc(sizeof(struct panel_dev), GFP_KERNEL); ++ if (NULL == panel) { ++ dev_err(&pdev->dev, "Failed to alloc memory!"); ++ return -ENOMEM; ++ } ++ panel->dev = &pdev->dev; ++ dev_set_drvdata(&pdev->dev, panel); ++ ++ /* panel pinctrl parse */ ++ ret = of_panel_parse(&pdev->dev); ++ if (ret < 0) { ++ goto err_of_parse; ++ } ++ ++ panel->lcd = lcd_device_register("panel_lcd", &pdev->dev, panel, &panel_lcd_ops); ++ if (IS_ERR_OR_NULL(panel->lcd)) { ++ dev_err(&pdev->dev, "Error register lcd!"); ++ ret = -EINVAL; ++ goto err_of_parse; ++ } ++ ++ /* TODO: should this power status sync from uboot */ ++ panel->power = FB_BLANK_POWERDOWN; ++ panel_set_power(panel->lcd, FB_BLANK_UNBLANK); ++ ++ ret = ingenicfb_register_panel(&lcd_panel); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "Failed to register lcd panel!\n"); ++ goto err_lcd_register; ++ } ++ ++ return 0; ++ ++err_lcd_register: ++ lcd_device_unregister(panel->lcd); ++err_of_parse: ++ kfree(panel); ++ return ret; ++} ++ ++static int panel_remove(struct platform_device *pdev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(&pdev->dev); ++ ++ panel_set_power(panel->lcd, FB_BLANK_POWERDOWN); ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int panel_suspend(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ ++ panel_set_power(panel->lcd, FB_BLANK_POWERDOWN); ++ return 0; ++} ++ ++static int panel_resume(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ ++ panel_set_power(panel->lcd, FB_BLANK_UNBLANK); ++ return 0; ++} ++ ++static const struct dev_pm_ops panel_pm_ops = { ++ .suspend = panel_suspend, ++ .resume = panel_resume, ++}; ++#endif ++ ++static const struct of_device_id panel_of_match[] = { ++ { .compatible = "ingenic,bm8766", }, ++ { .compatible = "bm8766", }, ++ {}, ++}; ++ ++static struct platform_driver panel_driver = { ++ .probe = panel_probe, ++ .remove = panel_remove, ++ .driver = { ++ .name = "bm8766", ++ .of_match_table = panel_of_match, ++#ifdef CONFIG_PM ++ .pm = &panel_pm_ops, ++#endif ++ }, ++}; ++ ++module_platform_driver(panel_driver); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-ek79007.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-ek79007.c.patch new file mode 100644 index 00000000..31912ab1 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-ek79007.c.patch @@ -0,0 +1,528 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v12/displays/panel-ek79007.c b/drivers/video/fbdev/ingenic/fb_v12/displays/panel-ek79007.c +--- a/drivers/video/fbdev/ingenic/fb_v12/displays/panel-ek79007.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v12/displays/panel-ek79007.c 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,524 @@ ++/* ++ * Copyright (c) 2012 Ingenic Semiconductor Co., Ltd. ++ * http://www.ingenic.com/ ++ * ++ * dorado board lcd setup routines. ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../ingenicfb.h" ++#include "../jz_dsim.h" ++ ++#define EK79007_SUPPORT_LANE_4_FPS_60 0 ++#define EK79007_SUPPORT_LANE_4_FPS_30 1 ++#define EK79007_SUPPORT_LANE_4_FPS_20 2 ++#define EK79007_SUPPORT_LANE_2_FPS_30 3 ++ ++#define EK79007_SUPPORT_LANE_4_FPS_90 4 ++ ++#define JZ_LCD_FPS_MAX EK79007_SUPPORT_LANE_4_FPS_60 ++ ++static struct dsi_cmd_packet ek79007_cmd_list[] = { ++ {0x15, 0x80, 0xAC, {0x00}}, ++ {0x15, 0x81, 0xB8, {0x00}}, ++ {0x15, 0x82, 0x09, {0x00}}, ++ {0x15, 0x83, 0x78, {0x00}}, ++ {0x15, 0x84, 0x7F, {0x00}}, ++ {0x15, 0x85, 0xBB, {0x00}}, ++ {0x15, 0x86, 0x70, {0x00}}, ++ //{0x15, 0xB0, 0x80, 0x00}, /* pwm on */ ++ //{0x15, 0x87, 0x5A, 0x00}, /* test color bar */ ++ //{0x15, 0xB1, 0x08, 0x00}, /* test color bar */ ++#ifdef CONFIG_MIPI_2LANE ++ {0x15, 0xB2, 0x10, {0x00}}, /*00:4 lane; 10:2 lane*/ ++#endif ++#ifdef CONFIG_MIPI_4LANE ++ {0x15, 0xB2, 0x00, {0x00}}, /*00:4 lane; 10:2 lane*/ ++#endif ++}; ++ ++struct board_gpio { ++ short gpio; ++ short active_level; ++}; ++ ++struct panel_dev { ++ /* ingenic frame buffer */ ++ struct device *dev; ++ struct lcd_panel *panel; ++ ++ /* common lcd framework */ ++ struct lcd_device *lcd; ++ struct backlight_device *backlight; ++ int power; ++ ++ struct regulator *vcc; ++ struct board_gpio vdd_en; ++ struct board_gpio bl; ++ struct board_gpio rst; ++ struct board_gpio oled; ++ struct board_gpio lcd_pwm; ++ ++ struct mipi_dsim_lcd_device *dsim_dev; ++}; ++ ++struct panel_dev *panel; ++ ++#define lcd_to_master(a) (a->dsim_dev->master) ++#define lcd_to_master_ops(a) ((lcd_to_master(a))->master_ops) ++ ++struct ek79007 { ++ struct device *dev; ++ unsigned int power; ++ unsigned int id; ++ ++ struct lcd_device *ld; ++ struct backlight_device *bd; ++ ++ struct mipi_dsim_lcd_device *dsim_dev; ++}; ++ ++struct fb_videomode jzfb_ek79007_videomode[] = { ++ //[0] 4lane 60fps ++ { ++ .name = "ek79007", ++ .refresh = 60, ++ .xres = 1024, ++ .yres = 600, ++ .pixclock = KHZ2PICOS(51700), ++ .left_margin = 160, ++ .right_margin = 160, ++ .upper_margin = 12, ++ .lower_margin = 23, ++ .hsync_len = 10, ++ .vsync_len = 1, ++ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, ++ .vmode = FB_VMODE_NONINTERLACED, ++ .flag = 0, ++ }, ++ //[1] 4lane 30fps ++ { ++ .name = "ek79007", ++ .refresh = 30, ++ .xres = 1024, ++ .yres = 600, ++ .pixclock = KHZ2PICOS(25900), ++ .left_margin = 160, ++ .right_margin = 160, ++ .upper_margin = 12, ++ .lower_margin = 23, ++ .hsync_len = 10, ++ .vsync_len = 1, ++ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, ++ .vmode = FB_VMODE_NONINTERLACED, ++ .flag = 0, ++ }, ++ //[2] 4lane 20fps ++ { ++ .name = "ek79007", ++ .refresh = 20, ++ .xres = 1024, ++ .yres = 600, ++ .pixclock = KHZ2PICOS(17300), ++ .left_margin = 160, ++ .right_margin = 160, ++ .upper_margin = 12, ++ .lower_margin = 23, ++ .hsync_len = 10, ++ .vsync_len = 1, ++ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, ++ .vmode = FB_VMODE_NONINTERLACED, ++ .flag = 0, ++ }, ++ //[3] 2lane 30fps ++ { ++ .name = "ek79007", ++ .refresh = 30, ++ .xres = 1024, ++ .yres = 600, ++ .pixclock = KHZ2PICOS(25900), ++ .left_margin = 60, ++ .right_margin = 60, ++ .upper_margin = 5, ++ .lower_margin = 10, ++ .hsync_len = 10, ++ .vsync_len = 2, ++ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, ++ .vmode = FB_VMODE_NONINTERLACED, ++ .flag = 0, ++ }, ++ //[4] 4lane 120fps ++ { ++ .name = "ek79007", ++ .refresh = 90, ++ .xres = 1024, ++ .yres = 600, ++ .pixclock = KHZ2PICOS(77700), ++ .left_margin = 160, ++ .right_margin = 160, ++ .upper_margin = 12, ++ .lower_margin = 23, ++ .hsync_len = 10, ++ .vsync_len = 1, ++ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, ++ .vmode = FB_VMODE_NONINTERLACED, ++ .flag = 0, ++ }, ++ ++ {} ++}; ++ ++struct jzdsi_data jzdsi_pdata = { ++ .modes = &jzfb_ek79007_videomode[JZ_LCD_FPS_MAX], ++#ifdef CONFIG_MIPI_2LANE ++ .video_config.no_of_lanes = 2, ++#endif ++#ifdef CONFIG_MIPI_4LANE ++ .video_config.no_of_lanes = 4, ++#endif ++ .video_config.virtual_channel = 0, ++ .video_config.color_coding = COLOR_CODE_24BIT, ++#if 0 ++ .video_config.video_mode = VIDEO_NON_BURST_WITH_SYNC_PULSES, ++#else ++ .video_config.video_mode = VIDEO_BURST_WITH_SYNC_PULSES, ++#endif ++ .video_config.receive_ack_packets = 0, /* enable receiving of ack packets */ ++ /*loosely: R0R1R2R3R4R5__G0G1G2G3G4G5G6__B0B1B2B3B4B5B6, ++ * not loosely: R0R1R2R3R4R5G0G1G2G3G4G5B0B1B2B3B4B5*/ ++ .video_config.is_18_loosely = 0, ++ .video_config.data_en_polarity = 1, ++ ++ .dsi_config.max_lanes = 4, ++ .dsi_config.max_hs_to_lp_cycles = 100, ++ .dsi_config.max_lp_to_hs_cycles = 40, ++ .dsi_config.max_bta_cycles = 4095, ++ .dsi_config.color_mode_polarity = 1, ++ .dsi_config.shut_down_polarity = 1, ++ .dsi_config.max_bps = 460, ++ // .max_bps = 650, // 650 Mbps ++ .bpp_info = 24, ++ ++}; ++ ++struct tft_config ek79007_cfg = { ++ .pix_clk_inv = 0, ++ .de_dl = 0, ++ .sync_dl = 0, ++ .color_even = TFT_LCD_COLOR_EVEN_RGB, ++ .color_odd = TFT_LCD_COLOR_ODD_RGB, ++ .mode = TFT_LCD_MODE_PARALLEL_888, ++}; ++ ++struct lcd_panel lcd_panel = { ++ .num_modes = 1, ++ .modes = &jzfb_ek79007_videomode[JZ_LCD_FPS_MAX], ++ .dsi_pdata = &jzdsi_pdata, ++ //.smart_config = &smart_cfg, ++ .tft_config = &ek79007_cfg, ++ ++ .lcd_type = LCD_TYPE_TFT , ++ .width = 1024, ++ .height = 600, ++ //.bpp = 24, ++ ++ //.pixclk_falling_edge = 0, ++ //.data_enable_active_low = 0, ++ ++}; ++ ++/**************************************************************************************************/ ++#ifdef CONFIG_BACKLIGHT_PWM ++ ++static struct platform_pwm_backlight_data backlight_data = { ++ .pwm_id = 0, ++ .max_brightness = 255, ++ .dft_brightness = 100, ++ .pwm_period_ns = 30000, ++}; ++ ++struct platform_device backlight_device = { ++ .name = "pwm-backlight", ++ .dev = { ++ .platform_data = &backlight_data, ++ }, ++}; ++ ++#endif ++ ++#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL) ++static int panel_set_power(struct lcd_device *lcd, int power) ++{ ++ return 0; ++} ++ ++static int panel_get_power(struct lcd_device *lcd) ++{ ++ struct panel_dev *panel = lcd_get_data(lcd); ++ ++ return panel->power; ++} ++ ++static struct lcd_ops panel_lcd_ops = { ++ .early_set_power = panel_set_power, ++ .set_power = panel_set_power, ++ .get_power = panel_get_power, ++}; ++ ++static int of_panel_parse(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ struct device_node *np = dev->of_node; ++ enum of_gpio_flags flags; ++ int ret = 0; ++ ++ panel->bl.gpio = of_get_named_gpio_flags(np, "ingenic,bl-gpio", 0, &flags); ++ if (gpio_is_valid(panel->bl.gpio)) { ++ panel->bl.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ ret = devm_gpio_request(dev, panel->bl.gpio, "backlight"); ++ if (ret < 0) { ++ dev_err(dev, "Failed to request backlight pin!\n"); ++ return ret; ++ } ++ } else ++ dev_warn(dev, "invalid gpio backlight.gpio: %d\n", panel->bl.gpio); ++ ++ panel->rst.gpio = of_get_named_gpio_flags(np, "ingenic,rst-gpio", 0, &flags); ++ if (gpio_is_valid(panel->rst.gpio)) { ++ panel->rst.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ ret = devm_gpio_request(dev, panel->rst.gpio, "reset"); ++ if (ret < 0) { ++ dev_err(dev, "Failed to request rst pin!\n"); ++ return ret; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio rst.gpio: %d\n", panel->rst.gpio); ++ } ++ ++ return 0; ++} ++ ++static void panel_dev_panel_init(struct panel_dev *lcd) ++{ ++ int i; ++ struct dsi_master_ops *ops = lcd_to_master_ops(lcd); ++ struct dsi_device *dsi = lcd_to_master(lcd); ++ ++ for (i = 0; i < ARRAY_SIZE(ek79007_cmd_list); i++) ++ ops->cmd_write(dsi, ek79007_cmd_list[i]); ++ msleep(20); ++} ++ ++static int panel_dev_ioctl(struct mipi_dsim_lcd_device *dsim_dev, int cmd) ++{ ++ return 0; ++} ++ ++static void panel_dev_set_sequence(struct mipi_dsim_lcd_device *dsim_dev) ++{ ++ struct ek79007 *lcd = dev_get_drvdata(&dsim_dev->dev); ++ ++ panel_dev_panel_init(panel); ++ msleep(120); ++ ++ lcd->power = FB_BLANK_UNBLANK; ++} ++ ++static void panel_dev_power_on(struct mipi_dsim_lcd_device *dsim_dev, int power) ++{ ++ struct panel_dev *panel_ek79007 = dev_get_drvdata(panel->dev); ++ ++ if (power == 1) { ++ //reset ++ if (gpio_is_valid(panel_ek79007->rst.gpio)) { ++ gpio_direction_output(panel_ek79007->rst.gpio, !panel_ek79007->rst.active_level); ++ mdelay(120); ++ gpio_direction_output(panel_ek79007->rst.gpio, panel_ek79007->rst.active_level); ++ mdelay(50); ++ gpio_direction_output(panel_ek79007->rst.gpio, !panel_ek79007->rst.active_level); ++ mdelay(120); ++ } ++ //open backlight ++ if (gpio_is_valid(panel_ek79007->bl.gpio)) ++ gpio_direction_output(panel_ek79007->bl.gpio, panel_ek79007->bl.active_level); ++ } else { ++ if (gpio_is_valid(panel_ek79007->bl.gpio)) ++ gpio_direction_output(panel_ek79007->bl.gpio, !panel_ek79007->bl.active_level); ++ } ++} ++ ++static int panel_dev_probe(struct mipi_dsim_lcd_device *dsim_dev) ++{ ++ struct ek79007 *lcd; ++ ++ lcd = devm_kzalloc(&dsim_dev->dev, sizeof(struct ek79007), GFP_KERNEL); ++ if (IS_ERR_OR_NULL(lcd)) { ++ dev_err(&dsim_dev->dev, "Failed to allocate ek79007 structure!\n"); ++ return -ENOMEM; ++ } ++ ++ lcd->dsim_dev = dsim_dev; ++ lcd->dev = &dsim_dev->dev; ++ ++ lcd->ld = lcd_device_register("ek79007", lcd->dev, lcd, ++ &panel_lcd_ops); ++ if (IS_ERR(lcd->ld)) { ++ dev_err(lcd->dev, "Failed to register lcd ops."); ++ return PTR_ERR(lcd->ld); ++ } ++ ++ //panel_dev_power_on(dsi); ++ ++ dev_set_drvdata(&dsim_dev->dev, lcd); ++ ++ dev_dbg(lcd->dev, "Now probed ek79007 panel.\n"); ++ ++ panel->dsim_dev = dsim_dev; ++ ++ return 0; ++} ++ ++static int panel_dev_suspend(struct mipi_dsim_lcd_device *dsim_dev) ++{ ++ struct board_gpio *vdd_en = &panel->bl; ++ ++ gpio_direction_output(vdd_en->gpio, !vdd_en->active_level); ++ ++ return 0; ++} ++ ++static int panel_dev_resume(struct mipi_dsim_lcd_device *dsim_dev) ++{ ++ struct board_gpio *vdd_en = &panel->bl; ++ ++ gpio_direction_output(vdd_en->gpio, vdd_en->active_level); ++ ++ return 0; ++} ++ ++static struct mipi_dsim_lcd_driver panel_dev_dsim_ddi_driver = { ++ .name = "ek79007", ++ .id = -1, ++ ++ .power_on = panel_dev_power_on, ++ .set_sequence = panel_dev_set_sequence, ++ .probe = panel_dev_probe, ++ .suspend = panel_dev_suspend, ++ .resume = panel_dev_resume, ++ .ioctl = panel_dev_ioctl, ++}; ++ ++static struct mipi_dsim_lcd_device panel_dev_device = { ++ .name = "ek79007", ++ .id = 0, ++}; ++ ++/** ++ * @panel_probe ++ * ++ * 1. register to ingenicfb ++ * 2. register to lcd ++ * 3. register to backlight if possible ++ * ++ * @pdev ++ * ++ * @return - ++ */ ++static int panel_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ ++ panel = kzalloc(sizeof(struct panel_dev), GFP_KERNEL); ++ if (IS_ERR_OR_NULL(panel)) { ++ dev_err(&pdev->dev, "Failed to alloc memory!\n"); ++ return -ENOMEM; ++ } ++ panel->dev = &pdev->dev; ++ dev_set_drvdata(&pdev->dev, panel); ++ ++ ret = of_panel_parse(&pdev->dev); ++ if (ret < 0) ++ goto err_of_parse; ++ ++ /* register to mipi-dsi devicelist*/ ++ mipi_dsi_register_lcd_device(&panel_dev_device); ++ mipi_dsi_register_lcd_driver(&panel_dev_dsim_ddi_driver); ++ ++ ret = ingenicfb_register_panel(&lcd_panel); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "Failed to register lcd panel!\n"); ++ goto err_of_parse; ++ } ++ ++ return 0; ++err_of_parse: ++ kfree(panel); ++ return ret; ++} ++ ++static int panel_remove(struct platform_device *dev) ++{ ++ if (NULL != panel) ++ kfree(panel); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int panel_suspend(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ ++ panel_set_power(panel->lcd, FB_BLANK_POWERDOWN); ++ return 0; ++} ++ ++static int panel_resume(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ ++ panel_set_power(panel->lcd, FB_BLANK_UNBLANK); ++ return 0; ++} ++ ++static const struct dev_pm_ops panel_pm_ops = { ++ .suspend = panel_suspend, ++ .resume = panel_resume, ++}; ++#endif ++static const struct of_device_id panel_of_match[] = { ++ { .compatible = "ingenic,ek79007", }, ++ { .compatible = "ek79007", }, ++ {}, ++}; ++ ++static struct platform_driver panel_driver = { ++ .probe = panel_probe, ++ .remove = panel_remove, ++ .driver = { ++ .name = "ek79007", ++ .of_match_table = panel_of_match, ++#ifdef CONFIG_PM ++ .pm = &panel_pm_ops, ++#endif ++ }, ++}; ++ ++module_platform_driver(panel_driver); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-jd9161z.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-jd9161z.c.patch new file mode 100644 index 00000000..c26e6f4c --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-jd9161z.c.patch @@ -0,0 +1,521 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v12/displays/panel-jd9161z.c b/drivers/video/fbdev/ingenic/fb_v12/displays/panel-jd9161z.c +--- a/drivers/video/fbdev/ingenic/fb_v12/displays/panel-jd9161z.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v12/displays/panel-jd9161z.c 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,517 @@ ++/* ++ * driver/video/fbdev/ingenic/x2000_v12/displays/panel-jd9161z.c ++ * ++ * Copyright (C) 2016 Ingenic Semiconductor Inc. ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#include "../ingenicfb.h" ++#include "../jz_dsim.h" ++ ++static int test = 0; ++ ++struct board_gpio { ++ short gpio; ++ short active_level; ++}; ++ ++struct panel_dev { ++ /* ingenic frame buffer */ ++ struct device *dev; ++ struct lcd_panel *panel; ++ ++ /* common lcd framework */ ++ struct lcd_device *lcd; ++ struct backlight_device *backlight; ++ int power; ++ ++ struct regulator *vcc; ++ struct board_gpio vdd_en; ++ struct board_gpio rst; ++ struct board_gpio lcd_te; ++ struct board_gpio lcd_pwm; ++ ++ struct mipi_dsim_lcd_device *dsim_dev; ++}; ++ ++struct panel_dev *panel; ++ ++#define lcd_to_master(a) (a->dsim_dev->master) ++#define lcd_to_master_ops(a) ((lcd_to_master(a))->master_ops) ++ ++struct jd9161z { ++ struct device *dev; ++ unsigned int power; ++ unsigned int id; ++ ++ struct lcd_device *ld; ++ struct backlight_device *bd; ++ ++ struct mipi_dsim_lcd_device *dsim_dev; ++ ++}; ++ ++static struct dsi_cmd_packet fitipower_jd9161z_480_800_cmd_list1[] = ++{ ++ {0x39, 0x04, 0x00, {0xDF, 0x91, 0x62, 0xF3}},//Delayms(1) ++ {0x39, 0x03, 0x00, {0xB2, 0x00, 0x92}}, //Set VCOM, Delayms(1); ++ {0x39, 0x03, 0x00, {0xB3, 0x00, 0x92}}, //Set VCOM_R, Delayms(1); ++ {0x39, 0x07, 0x00, {0xB7, 0x10, 0x1A, 0x49, 0x00, 0x50, 0x53}}, //Set Gamma Power, VGMP,VGMN,VGSP,VGSN, Delayms(1);(0x1A); //VGMP = 5V;(0x49); //VGSP = 0V,R(0x50); //VGMN = -5V,(0x53); //VGSN = -0V 33 ++ {0x39, 0x07, 0x00, {0xB7, 0x10, 0x04, 0x33, 0x00, 0x3C, 0x67}}, //(0x04); VGMP = 5V,(0x33); //VGSP = 0V,(0x3C); //VGMN = -5V,(0x67); //VGSN = -0V 33 ++ {0x39, 0x07, 0x00, {0xB7, 0x00, 0xF3, 0x22, 0x00, 0x17, 0x8C}},//Delayms(1);(0x00); //VGMP = 5V,(0x22); //VGSP = 0V,(0x17); //VGMN = -5V,(0x8C); //VGSN = -0V 33 ++ {0x39, 0x0C, 0x00, {0xBB, 0x69, 0x1E, 0xB2, 0xB2, 0xB2, 0xC0, 0xC0, 0x20, 0x30, 0x50, 0x50}},//DCDC_CTRL RBBh,Delayms(1);(0x69);//68,C0 20200511,(0xC0);//E0 20200511,(0x20); //30 20200511,(0x30);//F0,(0x50);//F0,(0x50);//F0 ++ {0x39, 0x0F, 0x00, {0xC3, 0x34, 0x0C, 0x0C, 0x1C, 0x00, 0x1C, 0x04, 0x1C, 0x1C, 0x00, 0x1C, 0x7F, 0x04, 0x7C}}, ++ {0x39, 0x07, 0x00, {0xC4, 0x10, 0x90, 0x92, 0x0E, 0x12, 0x16}},//12:0e ++ {0x39, 0x27, 0x00, {0xC8, 0x7F, 0x73, 0x6A, 0x62, 0x64, 0x57, 0x60, 0x4B, 0x65, 0x63, 0x60, 0x79, 0x63, 0x63, 0x55, 0x40, 0x30, 0x1E, 0x00, 0x7F, 0x73, 0x6A, 0x62, 0x64, 0x57, 0x60, 0x4B, 0x65, 0x63, 0x60, 0x79, 0x63, 0x63, 0x55, 0x40, 0x30, 0x1E, 0x00}},//--- Gamma ----// ++ {0x39, 0x11, 0x00, {0xD0, 0x15, 0x10, 0x35, 0x03, 0x1E, 0x1F, 0x01, 0x1F, 0x05, 0x07, 0x09, 0x0B, 0x1F, 0x1F, 0x1F, 0x1F}},//SET GIP_R,Delayms(1); ++ {0x39, 0x11, 0x00, {0xD1, 0x15, 0x10, 0x35, 0x02, 0x1E, 0x1F, 0x00, 0x1F, 0x04, 0x06, 0x08, 0x0A, 0x1F, 0x1F, 0x1F, 0x1F}},//SET GIP_L,Delayms(1); ++ {0x39, 0x11, 0x00, {0xD2, 0x1F, 0x02, 0x35, 0x10, 0x15, 0x1E, 0x00, 0x1F, 0x04, 0x0A, 0x08, 0x06, 0x1F, 0x1F, 0x1F, 0x1F}},//SET GIP_GS_L,Delayms(1); ++ {0x39, 0x11, 0x00, {0xD3, 0x1F, 0x03, 0x35, 0x10, 0x15, 0x1E, 0x01, 0x1F, 0x05, 0x0B, 0x09, 0x07, 0x1F, 0x1F, 0x1F, 0x1F}},//SET GIP_GS_R,Delayms(1); ++ {0x39, 0x1e, 0x00, {0xD4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x08, 0x30, 0x00, 0x0A, 0x04, 0x6F, 0x04, 0x6F, 0x04, 0x30, 0x80, 0x00, 0x04, 0x6F, 0x73, 0x0C, 0x04, 0x6F, 0x0F, 0x25, 0x00, 0x63, 0x03, 0x00}},//Gip timing,Delayms(1); ++ {0x39, 0x21, 0x00, {0xD5, 0x01, 0x08, 0x80, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x06, 0x60, 0x00, 0x87, 0x50, 0x00, 0x83, 0xC0, 0x00, 0x60, 0x03, 0x00, 0x00, 0x00, 0x04, 0x6F, 0x06, 0x10, 0x00, 0x00, 0x0F, 0x4F, 0x00, 0x10, 0x1F, 0x3F}},//GIP Timing , ++#if 0 ++ {0x39, 0x02, 0x00, {0xDE, 0x02}},//Page2 ++ {0x39, 0x02, 0x00, {0xC1, 0x71}},//Delayms(1); ++ {0x39, 0x02, 0x00, {0xDE, 0x00}},//Page0 ++#else ++ {0x15, 0xDE, 0x02}, ++ {0x15, 0xC1, 0x71}, ++ {0x15, 0xDE, 0x00}, ++// {0x15, 0xc2, 0x28},// color bar ++ ++#endif ++ ++}; ++ ++static struct dsi_cmd_packet fitipower_jd9161z_480_800_cmd_list2[] = ++{ ++ {0x15, 0xDE, 0x02}, ++ {0x15, 0xC1, 0x71}, ++ {0x15, 0xDE, 0x00}, ++// {0x15, 0xc2, 0x28},// color bar ++}; ++ ++ ++static void panel_dev_sleep_in(struct panel_dev *lcd) ++{ ++ struct dsi_master_ops *ops = lcd_to_master_ops(lcd); ++ struct dsi_cmd_packet data_to_send = {0x05, 0x10, 0x00}; ++ ++ ops->cmd_write(lcd_to_master(lcd), data_to_send); ++} ++ ++static void panel_dev_sleep_out(struct panel_dev *lcd) ++{ ++ struct dsi_master_ops *ops = lcd_to_master_ops(lcd); ++ struct dsi_cmd_packet data_to_send = {0x05, 0x11, 0x00}; ++// struct dsi_cmd_packet data_to_send1 = {0x15, 0xc2, 0x20};//color bar test mode. ++// while (1) { ++ ops->cmd_write(lcd_to_master(lcd), data_to_send); ++// ops->cmd_write(lcd_to_master(lcd), data_to_send1); ++// } ++} ++ ++static void panel_dev_display_on(struct panel_dev *lcd) ++{ ++ struct dsi_master_ops *ops = lcd_to_master_ops(lcd);//color bar turn off 0x29 command. ++ struct dsi_cmd_packet data_to_send = {0x05, 0x29, 0x00}; ++ /* struct dsi_cmd_packet data_to_send1 = {0x15, 0x51, 250}; */ ++ ++ ops->cmd_write(lcd_to_master(lcd), data_to_send); ++ /* ops->cmd_write(lcd_to_master(lcd), data_to_send1); */ ++} ++ ++static void panel_dev_display_off(struct panel_dev *lcd) ++{ ++ struct dsi_master_ops *ops = lcd_to_master_ops(lcd); ++ struct dsi_cmd_packet data_to_send = {0x05, 0x28, 0x00}; ++ ++ ops->cmd_write(lcd_to_master(lcd), data_to_send); ++} ++ ++ ++static void panel_dev_panel_init(struct panel_dev *lcd) ++{ ++ int i; ++ struct dsi_master_ops *ops = lcd_to_master_ops(lcd); ++ struct dsi_device *dsi = lcd_to_master(lcd); ++ ++ for (i = 0; i < ARRAY_SIZE(fitipower_jd9161z_480_800_cmd_list1); i++) ++ { ++ ops->cmd_write(dsi, fitipower_jd9161z_480_800_cmd_list1[i]); ++ } ++// msleep(20); ++// for (i = 0; i < ARRAY_SIZE(fitipower_jd9161z_480_800_cmd_list2); i++) ++// { ++// ops->cmd_write(dsi, fitipower_jd9161z_480_800_cmd_list2[i]); ++// } ++} ++ ++static int panel_dev_ioctl(struct mipi_dsim_lcd_device *dsim_dev, int cmd) ++{ ++ return 0; ++} ++static void panel_dev_set_sequence(struct mipi_dsim_lcd_device *dsim_dev) ++{ ++ struct jd9161z *lcd = dev_get_drvdata(&dsim_dev->dev); ++ ++ printk(">>>>>>>>>>>>>>>>>>>>%s %d\n",__func__,__LINE__); ++ if(test != 0) ++ return; ++ test++; ++ ++ panel_dev_panel_init(panel); ++ panel_dev_sleep_out(panel); ++ msleep(120); ++ panel_dev_display_on(panel); ++ msleep(5); ++ /* dump_dsi_reg(dsi); */ ++ lcd->power = FB_BLANK_UNBLANK; ++} ++static void panel_dev_power_on(struct mipi_dsim_lcd_device *dsim_dev, int power) ++{ ++ struct board_gpio *vdd_en = &panel->vdd_en; ++ struct board_gpio *rst = &panel->rst; ++ struct board_gpio *lcd_te = &panel->lcd_te; ++ printk(">>>>>>>>>>>>>>>>>>>>%s %d\n",__func__,__LINE__); ++ ++ if(test != 0) ++ return; ++ ++ gpio_direction_output(vdd_en->gpio, vdd_en->active_level); ++ ++ if (gpio_is_valid(lcd_te->gpio)) { ++ gpio_direction_input(lcd_te->gpio); ++ } ++ msleep(50); ++ gpio_direction_output(rst->gpio, 0); ++ msleep(50); ++ gpio_direction_output(rst->gpio, 1); ++ msleep(120); ++ ++ panel->power = power; ++} ++ ++static struct fb_videomode panel_modes = { ++ .name = "fitipower_jd9161z-lcd", ++ .xres = 480, ++ .yres = 800, ++// .xres = 268, ++// .yres = 800, ++ ++// .refresh = 10, ++ .refresh = 60, ++ ++ .left_margin = 20,//hbp ++ .right_margin = 20,//hfp ++ .hsync_len = 20, //hsync ++ ++ .upper_margin = 16,//vbp ++ .lower_margin = 16,//vfp ++ .vsync_len = 4, //vsync ++ ++ .sync = FB_SYNC_HOR_HIGH_ACT & FB_SYNC_VERT_HIGH_ACT, ++ .vmode = FB_VMODE_NONINTERLACED, ++ .flag = 0, ++}; ++ ++struct jzdsi_data jzdsi_pdata = { ++ .modes = &panel_modes, ++ .video_config.no_of_lanes = 2, ++ .video_config.virtual_channel = 0, ++ .video_config.color_coding = COLOR_CODE_24BIT, ++ .video_config.video_mode = VIDEO_BURST_WITH_SYNC_PULSES, ++ .video_config.receive_ack_packets = 0, /* enable receiving of ack packets */ ++ .video_config.is_18_loosely = 0, ++ .video_config.data_en_polarity = 1, ++ .video_config.byte_clock = 0, // driver will auto calculate byte_clock. ++ .video_config.byte_clock_coef = MIPI_PHY_BYTE_CLK_COEF_MUL3_DIV2, // byte_clock *3/2. ++ ++ .dsi_config.max_lanes = 2, ++ .dsi_config.max_hs_to_lp_cycles = 100, ++ .dsi_config.max_lp_to_hs_cycles = 40, ++// .dsi_config.max_hs_to_lp_cycles = 200, ++// .dsi_config.max_lp_to_hs_cycles = 80, ++ .dsi_config.max_bta_cycles = 4095, ++ .dsi_config.color_mode_polarity = 1, ++ .dsi_config.shut_down_polarity = 1, ++ .dsi_config.max_bps = 2750, ++// .max_bps = 650, // 650 Mbps ++ .bpp_info = 24, ++}; ++static struct tft_config kd050hdfia019_cfg = { ++ .pix_clk_inv = 0, ++ .de_dl = 0, ++ .sync_dl = 0, ++ .color_even = TFT_LCD_COLOR_EVEN_RGB, ++ .color_odd = TFT_LCD_COLOR_ODD_RGB, ++ .mode = TFT_LCD_MODE_PARALLEL_888, ++}; ++ ++ ++struct lcd_panel lcd_panel = { ++ .num_modes = 1, ++ .modes = &panel_modes, ++ .dsi_pdata = &jzdsi_pdata, ++ ++ .lcd_type = LCD_TYPE_TFT, ++ .tft_config = &kd050hdfia019_cfg, ++ .bpp = 24, ++// .width = 700, ++// .height = 1230, ++ .width = 68, ++ .height = 121, ++ .dither_enable = 0, ++ .dither.dither_red = 0, ++ .dither.dither_green = 0, ++ .dither.dither_blue = 0, ++ ++ ++}; ++ ++#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL) ++static int panel_set_power(struct lcd_device *lcd, int power) ++{ ++ return 0; ++} ++ ++static int panel_get_power(struct lcd_device *lcd) ++{ ++ struct panel_dev *panel = lcd_get_data(lcd); ++ ++ return panel->power; ++} ++ ++/** ++* @ pannel_jd9161z_lcd_ops, register to kernel common backlight/lcd.c framworks. ++*/ ++static struct lcd_ops panel_lcd_ops = { ++ .early_set_power = panel_set_power, ++ .set_power = panel_set_power, ++ .get_power = panel_get_power, ++}; ++ ++static int of_panel_parse(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ struct device_node *np = dev->of_node; ++ enum of_gpio_flags flags; ++ int ret = 0; ++ ++ panel->vdd_en.gpio = of_get_named_gpio_flags(np, "ingenic,vdd-en-gpio", 0, &flags); ++ if(gpio_is_valid(panel->vdd_en.gpio)) { ++ panel->vdd_en.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ ret = gpio_request_one(panel->vdd_en.gpio, GPIOF_DIR_OUT, "vdd_en"); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request vdd_en pin!\n"); ++ return ret; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio vdd_en.gpio: %d\n", panel->vdd_en.gpio); ++ } ++ ++ panel->rst.gpio = of_get_named_gpio_flags(np, "ingenic,rst-gpio", 0, &flags); ++ if(gpio_is_valid(panel->rst.gpio)) { ++ panel->rst.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ ret = gpio_request_one(panel->rst.gpio, GPIOF_DIR_OUT, "rst"); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request rst pin!\n"); ++ goto err_request_rst; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio rst.gpio: %d\n", panel->rst.gpio); ++ } ++ ++ *(volatile unsigned int * )0xb0010188 = (0x1 << 27); //lcd_te high impedance config. ++ *(volatile unsigned int * )0xb0010198 = (0x1 << 27); ++ ++ panel->lcd_te.gpio = of_get_named_gpio_flags(np, "ingenic,lcd-te-gpio", 0, &flags); ++ if(gpio_is_valid(panel->lcd_te.gpio)) { ++ panel->lcd_te.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ ret = gpio_request_one(panel->lcd_te.gpio, GPIOF_DIR_IN, "lcd_te"); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request lcd_te pin!\n"); ++ goto err_request_lcd_te; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio lcd_te.gpio: %d\n", panel->lcd_te.gpio); ++ } ++ ++ panel->lcd_pwm.gpio = of_get_named_gpio_flags(np, "ingenic,lcd-pwm-gpio", 0, &flags); ++ if(gpio_is_valid(panel->lcd_pwm.gpio)) { ++ panel->lcd_pwm.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++// ret = gpio_request_one(panel->lcd_pwm.gpio, GPIOF_DIR_OUT, "lcd-pwm"); ++ ret = gpio_direction_output(panel->lcd_pwm.gpio,1); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request lcd-pwm pin!\n"); ++ return ret; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio lcd-pwm.gpio: %d\n", panel->lcd_pwm.gpio); ++ } ++ ++ ++ return 0; ++err_request_lcd_te: ++ if(gpio_is_valid(panel->rst.gpio)) ++ gpio_free(panel->rst.gpio); ++err_request_rst: ++ if(gpio_is_valid(panel->vdd_en.gpio)) ++ gpio_free(panel->vdd_en.gpio); ++ return ret; ++} ++ ++static int panel_dev_probe(struct mipi_dsim_lcd_device *dsim_dev) ++{ ++ struct jd9161z *lcd; ++ lcd = devm_kzalloc(&dsim_dev->dev, sizeof(struct jd9161z), GFP_KERNEL); ++ if (!lcd) ++ { ++ dev_err(&dsim_dev->dev, "failed to allocate fitipower_jd9161z structure.\n"); ++ return -ENOMEM; ++ } ++ ++ lcd->dsim_dev = dsim_dev; ++ lcd->dev = &dsim_dev->dev; ++ ++ lcd->ld = lcd_device_register("fitipower_jd9161z", lcd->dev, lcd, ++ &panel_lcd_ops); ++ if (IS_ERR(lcd->ld)) ++ { ++ dev_err(lcd->dev, "failed to register lcd ops.\n"); ++ return PTR_ERR(lcd->ld); ++ } ++ ++ dev_set_drvdata(&dsim_dev->dev, lcd); ++ ++ ++ dev_dbg(lcd->dev, "probed fitipower_jd9161z panel driver.\n"); ++ ++ ++ panel->dsim_dev = dsim_dev; ++ ++ ++ return 0; ++ ++} ++ ++static int panel_suspend(struct mipi_dsim_lcd_device *dsim_dev) ++{ ++ struct board_gpio *vdd_en = &panel->vdd_en; ++ ++ printk(">>>>>>>>>>>>>>>>>>>>%s %d\n",__func__,__LINE__); ++ panel_dev_display_off(panel); ++ panel_dev_sleep_in(panel); ++ gpio_direction_output(vdd_en->gpio, !vdd_en->active_level); ++ ++ return 0; ++} ++ ++static int panel_resume(struct mipi_dsim_lcd_device *dsim_dev) ++{ ++ struct board_gpio *vdd_en = &panel->vdd_en; ++ printk(">>>>>>>>>>>>>>>>>>>>%s %d\n",__func__,__LINE__); ++ ++ gpio_direction_output(vdd_en->gpio, vdd_en->active_level); ++ ++ return 0; ++} ++ ++static struct mipi_dsim_lcd_driver panel_dev_dsim_ddi_driver = { ++ .name = "fitipower_jd9161z-lcd", ++ .id = -1, ++ ++ .power_on = panel_dev_power_on, ++ .set_sequence = panel_dev_set_sequence, ++ .probe = panel_dev_probe, ++// .suspend = panel_suspend, ++ .resume = panel_resume, ++}; ++ ++ ++struct mipi_dsim_lcd_device panel_dev_device={ ++ .name = "fitipower_jd9161z-lcd", ++ .id = 0, ++}; ++ ++/** ++* @panel_probe ++* ++* 1. Register to ingenicfb. ++* 2. Register to lcd. ++* 3. Register to backlight if possible. ++* ++* @pdev ++* ++* @Return - ++*/ ++static int panel_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ ++ panel = kzalloc(sizeof(struct panel_dev), GFP_KERNEL); ++ if(panel == NULL) { ++ dev_err(&pdev->dev, "Faile to alloc memory!"); ++ return -ENOMEM; ++ } ++ panel->dev = &pdev->dev; ++ dev_set_drvdata(&pdev->dev, panel); ++ ++ ret = of_panel_parse(&pdev->dev); ++ if(ret < 0) { ++ goto err_of_parse; ++ } ++ ++ mipi_dsi_register_lcd_device(&panel_dev_device); ++ mipi_dsi_register_lcd_driver(&panel_dev_dsim_ddi_driver); ++ ++ ret = ingenicfb_register_panel(&lcd_panel); ++ if(ret < 0) { ++ dev_err(&pdev->dev, "Failed to register lcd panel!\n"); ++ goto err_of_parse; ++ } ++ ++ return 0; ++ ++err_of_parse: ++ kfree(panel); ++ return ret; ++} ++ ++static int panel_remove(struct platform_device *pdev) ++{ ++ return 0; ++} ++ ++static const struct of_device_id panel_of_match[] = { ++ { .compatible = "ingenic,jd9161z", }, ++ {}, ++}; ++ ++static struct platform_driver panel_driver = { ++ .probe = panel_probe, ++ .remove = panel_remove, ++ .driver = { ++ .name = "jd9161z", ++ .of_match_table = panel_of_match, ++ }, ++}; ++ ++module_platform_driver(panel_driver); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-kd035hvfbd037.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-kd035hvfbd037.c.patch new file mode 100644 index 00000000..4bf917a3 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-kd035hvfbd037.c.patch @@ -0,0 +1,547 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v12/displays/panel-kd035hvfbd037.c b/drivers/video/fbdev/ingenic/fb_v12/displays/panel-kd035hvfbd037.c +--- a/drivers/video/fbdev/ingenic/fb_v12/displays/panel-kd035hvfbd037.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v12/displays/panel-kd035hvfbd037.c 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,543 @@ ++/* ++ * driver/video/fbdev/ingenic/fb_v12/displays/kd035hvfbd037.c ++ * ++ * Copyright (C) 2016 Ingenic Semiconductor Inc. ++ * ++ * Author:clwang ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../ingenicfb.h" ++ ++struct board_gpio { ++ short gpio; ++ short active_level; ++}; ++ ++struct panel_dev { ++ /* ingenic frame buffer */ ++ struct device *dev; ++ struct lcd_panel *panel; ++ ++ /* common lcd framework */ ++ struct lcd_device *lcd; ++ struct backlight_device *backlight; ++ int power; ++ ++ struct regulator *vcc; ++ struct board_gpio cs; ++ struct board_gpio rst; ++ struct board_gpio vdd_en; ++ struct board_gpio pwm; ++}; ++ ++static struct smart_lcd_data_table kd035hvfbd037_data_table[] = { ++/* LCD init code */ ++ {SMART_CONFIG_UDELAY, 12000}, ++ {SMART_CONFIG_CMD , 0xff}, //Command 2 Enable ++ {SMART_CONFIG_PRM , 0x48}, ++ {SMART_CONFIG_PRM , 0x02}, ++ {SMART_CONFIG_PRM , 0x01}, ++ ++ {SMART_CONFIG_CMD , 0x00}, ++ {SMART_CONFIG_PRM , 0x80}, ++ {SMART_CONFIG_CMD , 0xff}, //ORISE Command Enable ++ {SMART_CONFIG_PRM , 0x48}, ++ {SMART_CONFIG_PRM , 0x02}, ++ ++ {SMART_CONFIG_CMD , 0x00}, ++ {SMART_CONFIG_PRM , 0x90}, ++ {SMART_CONFIG_CMD , 0xFF}, //MPU 16bit setting ++ {SMART_CONFIG_PRM , 0x01}, //02-16BIT MCU,01-8BIT MCU ++ ++ {SMART_CONFIG_CMD , 0x00}, ++ {SMART_CONFIG_PRM , 0x93}, ++ {SMART_CONFIG_CMD , 0xFF}, //SW MPU enable ++ {SMART_CONFIG_PRM , 0x20}, ++ ++ {SMART_CONFIG_CMD , 0x00}, ++ {SMART_CONFIG_PRM , 0x00}, ++ {SMART_CONFIG_CMD , 0x51}, //Wright Display brightness ++ {SMART_CONFIG_PRM , 0xf0}, ++ ++ {SMART_CONFIG_CMD , 0x00}, ++ {SMART_CONFIG_PRM , 0x00}, ++ {SMART_CONFIG_CMD , 0x53}, // Wright CTRL Display ++ {SMART_CONFIG_PRM , 0x24}, ++ ++ {SMART_CONFIG_CMD , 0x00}, ++ {SMART_CONFIG_PRM , 0xb1}, ++ {SMART_CONFIG_CMD , 0xc5}, //VSEL setting ++ {SMART_CONFIG_PRM , 0x00}, ++ ++ {SMART_CONFIG_CMD , 0x00}, ++ {SMART_CONFIG_PRM , 0xB0}, ++ {SMART_CONFIG_CMD , 0xc4}, //Gate Timing control ++ {SMART_CONFIG_PRM , 0x02}, ++ {SMART_CONFIG_PRM , 0x08}, ++ {SMART_CONFIG_PRM , 0x05}, ++ {SMART_CONFIG_PRM , 0x00}, ++ ++ {SMART_CONFIG_CMD , 0x00}, ++ {SMART_CONFIG_PRM , 0x90}, ++ {SMART_CONFIG_CMD , 0xc0}, //TCON MCLK Shift Control ++ {SMART_CONFIG_PRM , 0x00}, ++ {SMART_CONFIG_PRM , 0x0f}, ++ {SMART_CONFIG_PRM , 0x00}, ++ {SMART_CONFIG_PRM , 0x15}, ++ {SMART_CONFIG_PRM , 0x00}, ++ {SMART_CONFIG_PRM , 0x17}, ++ ++ {SMART_CONFIG_CMD , 0x00}, ++ {SMART_CONFIG_PRM , 0x82}, ++ {SMART_CONFIG_CMD , 0xc5}, //Adjust pump phase ++ {SMART_CONFIG_PRM , 0x01}, ++ ++ {SMART_CONFIG_CMD , 0x00}, ++ {SMART_CONFIG_PRM , 0x90}, ++ {SMART_CONFIG_CMD , 0xc5}, //Adjust pump phase ++ {SMART_CONFIG_PRM , 0x47}, ++ ++ {SMART_CONFIG_CMD , 0x00}, ++ {SMART_CONFIG_PRM , 0x00}, ++ {SMART_CONFIG_CMD , 0xd8}, //GVDD/NGVDD Setting ++ {SMART_CONFIG_PRM , 0x58}, //58,17V ++ {SMART_CONFIG_PRM , 0x58}, //58 ++ ++ {SMART_CONFIG_CMD , 0x00}, ++ {SMART_CONFIG_PRM , 0x00}, ++ {SMART_CONFIG_CMD , 0xd9}, //VCOM Setting ++ {SMART_CONFIG_PRM , 0xb0}, // ++ ++ {SMART_CONFIG_CMD , 0x00}, ++ {SMART_CONFIG_PRM , 0x91}, ++ {SMART_CONFIG_CMD , 0xb3}, //Display setting ++ {SMART_CONFIG_PRM , 0xC0}, ++ {SMART_CONFIG_PRM , 0x25}, ++ ++ {SMART_CONFIG_CMD , 0x00}, ++ {SMART_CONFIG_PRM , 0x81}, ++ {SMART_CONFIG_CMD , 0xC1}, //Osillator Adjustment:70Hz ++ {SMART_CONFIG_PRM , 0x77}, ++ ++ {SMART_CONFIG_CMD , 0x00}, ++ {SMART_CONFIG_PRM , 0x00}, ++ {SMART_CONFIG_CMD , 0xe1}, //Gamma setting ( positive) ++ {SMART_CONFIG_PRM , 0x00}, ++ {SMART_CONFIG_PRM , 0x05}, ++ {SMART_CONFIG_PRM , 0x09}, ++ {SMART_CONFIG_PRM , 0x04}, ++ {SMART_CONFIG_PRM , 0x02}, ++ {SMART_CONFIG_PRM , 0x0b}, ++ {SMART_CONFIG_PRM , 0x0a}, ++ {SMART_CONFIG_PRM , 0x09}, ++ {SMART_CONFIG_PRM , 0x05}, ++ {SMART_CONFIG_PRM , 0x08}, ++ {SMART_CONFIG_PRM , 0x10}, ++ {SMART_CONFIG_PRM , 0x05}, ++ {SMART_CONFIG_PRM , 0x06}, ++ {SMART_CONFIG_PRM , 0x11}, ++ {SMART_CONFIG_PRM , 0x09}, ++ {SMART_CONFIG_PRM , 0x01}, ++ ++ {SMART_CONFIG_CMD , 0x00}, ++ {SMART_CONFIG_PRM , 0x00}, ++ {SMART_CONFIG_CMD , 0xe2}, //Gamma setting ( negative) ++ {SMART_CONFIG_PRM , 0x00}, ++ {SMART_CONFIG_PRM , 0x05}, ++ {SMART_CONFIG_PRM , 0x09}, ++ {SMART_CONFIG_PRM , 0x04}, ++ {SMART_CONFIG_PRM , 0x02}, ++ {SMART_CONFIG_PRM , 0x0b}, ++ {SMART_CONFIG_PRM , 0x0a}, ++ {SMART_CONFIG_PRM , 0x09}, ++ {SMART_CONFIG_PRM , 0x05}, ++ {SMART_CONFIG_PRM , 0x08}, ++ {SMART_CONFIG_PRM , 0x10}, ++ {SMART_CONFIG_PRM , 0x05}, ++ {SMART_CONFIG_PRM , 0x06}, ++ {SMART_CONFIG_PRM , 0x11}, ++ {SMART_CONFIG_PRM , 0x09}, ++ {SMART_CONFIG_PRM , 0x01}, ++ ++ {SMART_CONFIG_CMD , 0x00}, ++ {SMART_CONFIG_PRM , 0x00}, ++ {SMART_CONFIG_CMD , 0x00}, //End Gamma setting ++ {SMART_CONFIG_PRM , 0x00}, ++ ++ {SMART_CONFIG_CMD , 0x00}, ++ {SMART_CONFIG_PRM , 0x80}, ++ {SMART_CONFIG_CMD , 0xff}, //Orise mode command Disable ++ {SMART_CONFIG_PRM , 0x00}, ++ {SMART_CONFIG_PRM , 0x00}, ++ ++ {SMART_CONFIG_CMD , 0x00}, ++ {SMART_CONFIG_PRM , 0x00}, ++ ++ {SMART_CONFIG_CMD , 0xff}, //Command 2 Disable ++ {SMART_CONFIG_PRM , 0xff}, ++ {SMART_CONFIG_PRM , 0xff}, ++ {SMART_CONFIG_PRM , 0xff}, ++ ++ //{SMART_CONFIG_CMD , 0x35}, //TE ON ++ //{SMART_CONFIG_DATA , 0x00}, ++ ++ {SMART_CONFIG_CMD , 0x36}, //set X Y refresh direction ++ {SMART_CONFIG_PRM , 0x00}, ++ ++ {SMART_CONFIG_CMD , 0x3A}, //16-bit/pixe 565 ++ {SMART_CONFIG_PRM , 0x05}, ++ ++ {SMART_CONFIG_CMD , 0x2A}, //Frame rate control 320 ++ {SMART_CONFIG_PRM , 0x00}, ++ {SMART_CONFIG_PRM , 0x00}, ++ {SMART_CONFIG_PRM , 0x01}, ++ {SMART_CONFIG_PRM , 0x3F}, ++ ++ {SMART_CONFIG_CMD , 0x2B}, //Display function control 480 ++ {SMART_CONFIG_PRM , 0x00}, ++ {SMART_CONFIG_PRM , 0x00}, ++ {SMART_CONFIG_PRM , 0x01}, ++ {SMART_CONFIG_PRM , 0xDF}, ++ ++ {SMART_CONFIG_CMD , 0x11}, ++ {SMART_CONFIG_UDELAY , 12000}, ++ {SMART_CONFIG_CMD , 0x29}, //display on ++ ++ {SMART_CONFIG_CMD , 0x2c}, ++ ++}; ++ ++static struct fb_videomode panel_modes[] = { ++ [0] = { ++ .name = "320x480", ++ .refresh = 60, ++ .xres = 320, ++ .yres = 480, ++ .pixclock = KHZ2PICOS(18432), ++ .left_margin = 0, ++ .right_margin = 0, ++ .upper_margin = 0, ++ .lower_margin = 0, ++ .hsync_len = 0, ++ .vsync_len = 0, ++ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, ++ .vmode = FB_VMODE_NONINTERLACED, ++ .flag = 0, ++ }, ++}; ++ ++struct smart_config kd035hvfbd037_cfg = { ++ .te_anti_jit = 1, ++ .te_md = 0, ++ .te_switch = 0, ++ .dc_md = 0, ++ .wr_md = 1, ++ .te_dp = 1, ++ .smart_type = SMART_LCD_TYPE_8080, ++ .pix_fmt = SMART_LCD_FORMAT_565, ++ .dwidth = SMART_LCD_DWIDTH_8_BIT, ++ .cwidth = SMART_LCD_CWIDTH_8_BIT, ++ .bus_width = 8, ++ ++ .write_gram_cmd = 0x2c, ++ .data_table = kd035hvfbd037_data_table, ++ .length_data_table = ARRAY_SIZE(kd035hvfbd037_data_table), ++}; ++ ++struct lcd_panel lcd_panel = { ++ .name = "kd035hvfbd037", ++ .num_modes = ARRAY_SIZE(panel_modes), ++ .modes = panel_modes, ++ .lcd_type = LCD_TYPE_SLCD, ++ .width = 320, ++ .height = 480, ++ ++ .smart_config = &kd035hvfbd037_cfg, ++ ++ .dither_enable = 0, ++ .dither.dither_red = 0, ++ .dither.dither_green = 0, ++ .dither.dither_blue = 0, ++}; ++ ++/* SGM3146 supports 16 brightness step */ ++#define MAX_BRIGHTNESS_STEP 16 ++/* System support 256 brightness step */ ++#define CONVERT_FACTOR (256/MAX_BRIGHTNESS_STEP) ++ ++static int panel_update_status(struct backlight_device *bd) ++{ ++ struct panel_dev *panel = dev_get_drvdata(&bd->dev); ++ int brightness = bd->props.brightness; ++ unsigned int i; ++ int pulse_num = MAX_BRIGHTNESS_STEP - brightness / CONVERT_FACTOR - 1; ++ ++ if (bd->props.fb_blank == FB_BLANK_POWERDOWN) { ++ return 0; ++ } ++ ++ if (bd->props.state & BL_CORE_SUSPENDED) ++ brightness = 0; ++ ++ if (brightness) { ++ gpio_direction_output(panel->pwm.gpio,0); ++ udelay(5000); ++ gpio_direction_output(panel->pwm.gpio,1); ++ udelay(100); ++ ++ for (i = pulse_num; i > 0; i--) { ++ gpio_direction_output(panel->pwm.gpio,0); ++ udelay(1); ++ gpio_direction_output(panel->pwm.gpio,1); ++ udelay(3); ++ } ++ } else ++ gpio_direction_output(panel->pwm.gpio, 0); ++ ++ return 0; ++} ++ ++static struct backlight_ops panel_backlight_ops = { ++ .options = BL_CORE_SUSPENDRESUME, ++ .update_status = panel_update_status, ++}; ++ ++static void panel_power_reset(struct board_gpio *rst) ++{ ++ gpio_direction_output(rst->gpio, 0); ++ mdelay(20); ++ gpio_direction_output(rst->gpio, 1); ++ mdelay(10); ++} ++ ++#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL) ++static int panel_set_power(struct lcd_device *lcd, int power) ++{ ++ struct panel_dev *panel = lcd_get_data(lcd); ++ struct board_gpio *cs = &panel->cs; ++ struct board_gpio *rst = &panel->rst; ++ struct board_gpio *vdd_en = &panel->vdd_en; ++ if(POWER_IS_ON(power) && !POWER_IS_ON(panel->power)) { ++ gpio_direction_output(vdd_en->gpio, 1); ++ gpio_direction_output(rst->gpio, 1); ++ gpio_direction_output(cs->gpio, 1); ++ mdelay(5); ++ panel_power_reset(rst); ++ gpio_direction_output(cs->gpio, 0); ++ } ++ if(!POWER_IS_ON(power) && POWER_IS_ON(panel->power)) { ++ gpio_direction_output(cs->gpio, 0); ++ gpio_direction_output(rst->gpio, 0); ++ gpio_direction_output(vdd_en->gpio, 0); ++ } ++ ++ panel->power = power; ++ return 0; ++} ++ ++static int panel_get_power(struct lcd_device *lcd) ++{ ++ struct panel_dev *panel = lcd_get_data(lcd); ++ ++ return panel->power; ++} ++ ++static struct lcd_ops panel_lcd_ops = { ++ .early_set_power = panel_set_power, ++ .set_power = panel_set_power, ++ .get_power = panel_get_power, ++}; ++ ++static int of_panel_parse(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ struct device_node *np = dev->of_node; ++ enum of_gpio_flags flags; ++ int ret = 0; ++ ++ panel->cs.gpio = of_get_named_gpio_flags(np, "ingenic,cs-gpio", 0, &flags); ++ if(gpio_is_valid(panel->cs.gpio)) { ++ panel->cs.active_level = OF_GPIO_ACTIVE_LOW ? 0 : 1; ++ ret = gpio_request_one(panel->cs.gpio, GPIOF_DIR_OUT, "cs"); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request cs pin!\n"); ++ return ret; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio cs.gpio: %d\n", panel->cs.gpio); ++ } ++ ++ panel->rst.gpio = of_get_named_gpio_flags(np, "ingenic,rst-gpio", 0, &flags); ++ if(gpio_is_valid(panel->rst.gpio)) { ++ panel->rst.active_level = OF_GPIO_ACTIVE_LOW ? 0 : 1; ++ ret = gpio_request_one(panel->rst.gpio, GPIOF_DIR_OUT, "rst"); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request rst pin!\n"); ++ goto err_request_rst; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio rst.gpio: %d\n", panel->rst.gpio); ++ } ++ ++ panel->vdd_en.gpio = of_get_named_gpio_flags(np, "ingenic,vdd-en-gpio", 0, &flags); ++ if(gpio_is_valid(panel->vdd_en.gpio)) { ++ panel->vdd_en.active_level = OF_GPIO_ACTIVE_LOW ? 0 : 1; ++ ret = gpio_request_one(panel->vdd_en.gpio, GPIOF_DIR_OUT, "vdd_en"); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request vdd_en pin!\n"); ++ goto err_request_rst; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio vdd_en.gpio: %d\n", panel->vdd_en.gpio); ++ } ++ panel->pwm.gpio = of_get_named_gpio_flags(np, "ingenic,pwm-gpio", 0, &flags); ++ if(gpio_is_valid(panel->pwm.gpio)) { ++ panel->pwm.active_level = OF_GPIO_ACTIVE_LOW ? 0 : 1; ++ ret = gpio_request_one(panel->pwm.gpio, GPIOF_DIR_OUT, "pwm"); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request pwm pin!\n"); ++ goto err_request_rst; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio pwm.gpio: %d\n", panel->pwm.gpio); ++ } ++ ++ return 0; ++err_request_rst: ++ gpio_free(panel->cs.gpio); ++ return ret; ++} ++/** ++* @panel_probe ++* ++* 1. Register to ingenicfb. ++* 2. Register to lcd. ++* 3. Register to backlight if possible. ++* ++* @pdev ++* ++* @Return - ++*/ ++static int panel_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ struct panel_dev *panel; ++ struct backlight_properties props; ++ ++ memset(&props, 0, sizeof(props)); ++ panel = kzalloc(sizeof(struct panel_dev), GFP_KERNEL); ++ if(panel == NULL) { ++ dev_err(&pdev->dev, "Faile to alloc memory!"); ++ return -ENOMEM; ++ } ++ panel->dev = &pdev->dev; ++ dev_set_drvdata(&pdev->dev, panel); ++ ++ ret = of_panel_parse(&pdev->dev); ++ if(ret < 0) { ++ goto err_of_parse; ++ } ++ ++ panel->lcd = lcd_device_register("panel_lcd", &pdev->dev, panel, &panel_lcd_ops); ++ if(IS_ERR_OR_NULL(panel->lcd)) { ++ dev_err(&pdev->dev, "Error register lcd!\n"); ++ ret = -EINVAL; ++ goto err_of_parse; ++ } ++ ++ /* TODO: should this power status sync from uboot */ ++ panel->power = FB_BLANK_POWERDOWN; ++ panel_set_power(panel->lcd, FB_BLANK_UNBLANK); ++ ++ props.type = BACKLIGHT_RAW; ++ props.max_brightness = 255; ++ panel->backlight = backlight_device_register("pwm-backlight.0", ++ &pdev->dev, panel, ++ &panel_backlight_ops, ++ &props); ++ if (IS_ERR_OR_NULL(panel->backlight)) { ++ dev_err(panel->dev, "failed to register 'pwm-backlight.0'.\n"); ++ goto err_lcd_register; ++ } ++ panel->backlight->props.brightness = props.max_brightness; ++ backlight_update_status(panel->backlight); ++ ++ ret = ingenicfb_register_panel(&lcd_panel); ++ if(ret < 0) { ++ dev_err(&pdev->dev, "Failed to register lcd panel!\n"); ++ goto err_lcd_register; ++ } ++ ++ return 0; ++ ++err_lcd_register: ++ lcd_device_unregister(panel->lcd); ++err_of_parse: ++ kfree(panel); ++ return ret; ++} ++ ++static int panel_remove(struct platform_device *pdev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(&pdev->dev); ++ ++ panel_set_power(panel->lcd, FB_BLANK_POWERDOWN); ++ return 0; ++} ++ ++ ++#ifdef CONFIG_PM ++static int panel_suspend(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ ++ panel_set_power(panel->lcd, FB_BLANK_POWERDOWN); ++ return 0; ++} ++ ++static int panel_resume(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ ++ panel_set_power(panel->lcd, FB_BLANK_UNBLANK); ++ return 0; ++} ++ ++static const struct dev_pm_ops panel_pm_ops = { ++ .suspend = panel_suspend, ++ .resume = panel_resume, ++}; ++#endif ++static const struct of_device_id panel_of_match[] = { ++ { .compatible = "ingenic,kd035hvfbd037", }, ++ {}, ++}; ++ ++static struct platform_driver panel_driver = { ++ .probe = panel_probe, ++ .remove = panel_remove, ++ .driver = { ++ .name = "kd035hvfbd037", ++ .of_match_table = panel_of_match, ++#ifdef CONFIG_PM ++ .pm = &panel_pm_ops, ++#endif ++ }, ++}; ++ ++module_platform_driver(panel_driver); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-kd050hdfia019.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-kd050hdfia019.c.patch new file mode 100644 index 00000000..b6c97510 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-kd050hdfia019.c.patch @@ -0,0 +1,478 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v12/displays/panel-kd050hdfia019.c b/drivers/video/fbdev/ingenic/fb_v12/displays/panel-kd050hdfia019.c +--- a/drivers/video/fbdev/ingenic/fb_v12/displays/panel-kd050hdfia019.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v12/displays/panel-kd050hdfia019.c 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,474 @@ ++/* ++ * driver/video/fbdev/ingenic/x2000_v12/displays/panel-kd050hdfia019.c ++ * ++ * Copyright (C) 2016 Ingenic Semiconductor Inc. ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../ingenicfb.h" ++#include "../jz_dsim.h" ++ ++struct board_gpio { ++ short gpio; ++ short active_level; ++}; ++ ++struct panel_dev { ++ /* ingenic frame buffer */ ++ struct device *dev; ++ struct lcd_panel *panel; ++ ++ /* common lcd framework */ ++ struct lcd_device *lcd; ++ struct backlight_device *backlight; ++ int power; ++ ++ struct regulator *vcc; ++ struct board_gpio vdd_en; ++ struct board_gpio rst; ++ struct board_gpio pwm; ++ ++ struct mipi_dsim_lcd_device *dsim_dev; ++}; ++ ++struct panel_dev *panel; ++ ++ struct dsi_cmd_packet kd050hdfia019_cmd_list[] = { ++ /* for KD050FWFIA019-C019A */ ++ {0x39, 0x06, 0x00, {0xFF, 0xFF, 0x98, 0x06, 0x04, 0x01}}, ++ {0x15, 0x08, 0x10}, ++ {0x15, 0x20, 0x00}, ++ {0x15, 0x21, 0x01}, ++ {0x15, 0x30, 0x01}, ++ {0x15, 0x31, 0x00}, ++ {0x15, 0x40, 0x16}, ++ {0x15, 0x41, 0x33}, ++ {0x15, 0x42, 0x03}, ++ {0x15, 0x43, 0x09}, ++ {0x15, 0x44, 0x06}, ++ {0x15, 0x50, 0x88}, ++ {0x15, 0x51, 0x88}, ++ {0x15, 0x52, 0x00}, ++ {0x15, 0x53, 0x49}, ++ {0x15, 0x55, 0x49}, ++ {0x15, 0x60, 0x07}, ++ {0x15, 0x61, 0x00}, ++ {0x15, 0x62, 0x07}, ++ {0x15, 0x63, 0x00}, ++ {0x15, 0xA0, 0x00}, ++ {0x15, 0xA1, 0x09}, ++ {0x15, 0xA2, 0x11}, ++ {0x15, 0xA3, 0x0B}, ++ {0x15, 0xA4, 0x05}, ++ {0x15, 0xA5, 0x08}, ++ {0x15, 0xA6, 0x06}, ++ {0x15, 0xA7, 0x04}, ++ {0x15, 0xA8, 0x09}, ++ {0x15, 0xA9, 0x0C}, ++ {0x15, 0xAA, 0x15}, ++ {0x15, 0xAB, 0x08}, ++ {0x15, 0xAC, 0x0F}, ++ {0x15, 0xAD, 0x12}, ++ {0x15, 0xAE, 0x09}, ++ {0x15, 0xAF, 0x00}, ++ {0x15, 0xC0, 0x00}, ++ {0x15, 0xC1, 0x09}, ++ {0x15, 0xC2, 0x10}, ++ {0x15, 0xC3, 0x0C}, ++ {0x15, 0xC4, 0x05}, ++ {0x15, 0xC5, 0x08}, ++ {0x15, 0xC6, 0x06}, ++ {0x15, 0xC7, 0x04}, ++ {0x15, 0xC8, 0x08}, ++ {0x15, 0xC9, 0x0C}, ++ {0x15, 0xCA, 0x14}, ++ {0x15, 0xCB, 0x08}, ++ {0x15, 0xCC, 0x0F}, ++ {0x15, 0xCD, 0x11}, ++ {0x15, 0xCE, 0x09}, ++ {0x15, 0xCF, 0x00}, ++ {0x39, 0x06, 0x00,{0xFF, 0xFF, 0x98, 0x06, 0x04, 0x06}}, ++ {0x15, 0x00, 0x20}, ++ {0x15, 0x01, 0x0A}, ++ {0x15, 0x02, 0x00}, ++ {0x15, 0x03, 0x00}, ++ {0x15, 0x04, 0x01}, ++ {0x15, 0x05, 0x01}, ++ {0x15, 0x06, 0x98}, ++ {0x15, 0x07, 0x06}, ++ {0x15, 0x08, 0x01}, ++ {0x15, 0x09, 0x80}, ++ {0x15, 0x0A, 0x00}, ++ {0x15, 0x0B, 0x00}, ++ {0x15, 0x0C, 0x01}, ++ {0x15, 0x0D, 0x01}, ++ {0x15, 0x0E, 0x05}, ++ {0x15, 0x0F, 0x00}, ++ {0x15, 0x10, 0xF0}, ++ {0x15, 0x11, 0xF4}, ++ {0x15, 0x12, 0x01}, ++ {0x15, 0x13, 0x00}, ++ {0x15, 0x14, 0x00}, ++ {0x15, 0x15, 0xC0}, ++ {0x15, 0x16, 0x08}, ++ {0x15, 0x17, 0x00}, ++ {0x15, 0x18, 0x00}, ++ {0x15, 0x19, 0x00}, ++ {0x15, 0x1A, 0x00}, ++ {0x15, 0x1B, 0x00}, ++ {0x15, 0x1C, 0x00}, ++ {0x15, 0x1D, 0x00}, ++ {0x15, 0x20, 0x01}, ++ {0x15, 0x21, 0x23}, ++ {0x15, 0x22, 0x45}, ++ {0x15, 0x23, 0x67}, ++ {0x15, 0x24, 0x01}, ++ {0x15, 0x25, 0x23}, ++ {0x15, 0x26, 0x45}, ++ {0x15, 0x27, 0x67}, ++ {0x15, 0x30, 0x11}, ++ {0x15, 0x31, 0x11}, ++ {0x15, 0x32, 0x00}, ++ {0x15, 0x33, 0xEE}, ++ {0x15, 0x34, 0xFF}, ++ {0x15, 0x35, 0xBB}, ++ {0x15, 0x36, 0xAA}, ++ {0x15, 0x37, 0xDD}, ++ {0x15, 0x38, 0xCC}, ++ {0x15, 0x39, 0x66}, ++ {0x15, 0x3A, 0x77}, ++ {0x15, 0x3B, 0x22}, ++ {0x15, 0x3C, 0x22}, ++ {0x15, 0x3D, 0x22}, ++ {0x15, 0x3E, 0x22}, ++ {0x15, 0x3F, 0x22}, ++ {0x15, 0x40, 0x22}, ++ {0x39, 0x06, 0x00,{0xFF, 0xFF, 0x98, 0x06, 0x04, 0x07}}, ++ {0x15, 0x17, 0x22}, ++ {0x15, 0x02, 0x77}, ++ {0x15, 0x26, 0xB2}, ++ {0x39, 0x06, 0x00,{0xFF, 0xFF, 0x98, 0x06, 0x04, 0x00}}, ++ {0x15, 0x3A, 0x70}, ++ {0x05, 0x11, 0x00}, ++// {0x05, 0x29, 0x00}, display on ++ }; ++ ++struct kd050hdfia019 { ++ struct device *dev; ++ unsigned int power; ++ unsigned int id; ++ ++ struct lcd_device *ld; ++ struct backlight_device *bd; ++ ++ struct mipi_dsim_lcd_device *dsim_dev; ++ struct kd050hdfia019_platform_data *ddi_pd; ++ ++}; ++ ++#define lcd_to_master(a) (a->dsim_dev->master) ++#define lcd_to_master_ops(a) ((lcd_to_master(a))->master_ops) ++ ++static void panel_dev_sleep_out(struct panel_dev *lcd) ++{ ++ struct dsi_master_ops *ops = lcd_to_master_ops(lcd); ++ struct dsi_cmd_packet data_to_send = {0x05, 0x11, 0x00}; ++ ++ ops->cmd_write(lcd_to_master(lcd), data_to_send); ++} ++ ++static void panel_dev_display_on(struct panel_dev *lcd) ++{ ++ struct dsi_master_ops *ops = lcd_to_master_ops(lcd); ++ struct dsi_cmd_packet data_to_send = {0x05, 0x29, 0x00}; ++ ++ ops->cmd_write(lcd_to_master(lcd), data_to_send); ++} ++ ++static void panel_dev_panel_condition_setting(struct panel_dev *lcd) ++{ ++ int i; ++ struct dsi_master_ops *ops = lcd_to_master_ops(lcd); ++ struct dsi_device *dsi = lcd_to_master(lcd); ++ for(i = 0; i < ARRAY_SIZE(kd050hdfia019_cmd_list); i++) { ++ ops->cmd_write(dsi, kd050hdfia019_cmd_list[i]); ++ } ++ ++} ++ ++static int panel_dev_ioctl(struct mipi_dsim_lcd_device *dsim_dev, int cmd) ++{ ++ return 0; ++} ++static void panel_dev_set_sequence(struct mipi_dsim_lcd_device *dsim_dev) ++{ ++ struct panel_dev *lcd = dev_get_drvdata(&dsim_dev->dev); ++ ++ /* panel reset ... */ ++ ++ panel_dev_panel_condition_setting(lcd); ++ ++ panel_dev_sleep_out(lcd); ++ ++ msleep(120); ++ panel_dev_display_on(lcd); ++ ++ lcd->power = FB_BLANK_UNBLANK; ++} ++static int panel_dev_probe(struct mipi_dsim_lcd_device *dsim_dev) ++{ ++ panel->dsim_dev = dsim_dev; ++ dev_set_drvdata(&dsim_dev->dev, panel); ++ return 0; ++} ++static struct mipi_dsim_lcd_driver panel_dev_dsim_ddi_driver = { ++ .name = "kd050hdfia019-lcd", ++ .id = 0, ++ ++// .power_on = panel_dev_power_on, ++ .set_sequence = panel_dev_set_sequence, ++ .ioctl = panel_dev_ioctl, ++ .probe = panel_dev_probe, ++}; ++ ++struct mipi_dsim_lcd_device panel_dev_device={ ++ .name = "kd050hdfia019-lcd", ++ .id = 0, ++ .platform_data = NULL, ++}; ++ ++static void panel_enable(struct lcd_panel *panel) ++{ ++} ++ ++static void panel_disable(struct lcd_panel *panel) ++{ ++} ++ ++static struct lcd_panel_ops panel_ops = { ++ .enable = (void*)panel_enable, ++ .disable = (void*)panel_disable, ++}; ++ ++static struct fb_videomode panel_modes = { ++ .name = "kd050hdfia019-lcd", ++ .refresh = 0, ++ .xres = 480, ++ .yres = 854, ++ .pixclock = KHZ2PICOS(30000), ++ .left_margin = 40, ++ .right_margin = 50, ++ .upper_margin = 16, ++ .lower_margin = 4, ++ ++ .hsync_len = 8, ++ .vsync_len = 10, ++ .sync = FB_SYNC_HOR_HIGH_ACT & FB_SYNC_VERT_HIGH_ACT, ++ .vmode = FB_VMODE_NONINTERLACED, ++ .flag = 0, ++}; ++ ++struct jzdsi_data jzdsi_pdata = { ++ .modes = &panel_modes, ++ .video_config.no_of_lanes = 2, ++ .video_config.virtual_channel = 0, ++ .video_config.color_coding = COLOR_CODE_24BIT, ++ .video_config.video_mode = VIDEO_BURST_WITH_SYNC_PULSES, ++ .video_config.receive_ack_packets = 0, ++ .video_config.is_18_loosely = 0, ++ .video_config.data_en_polarity = 1, ++ .video_config.byte_clock = 0, // driver will auto calculate byte_clock. ++ .video_config.byte_clock_coef = MIPI_PHY_BYTE_CLK_COEF_MUL3_DIV2, //for auto calculate byte clock ++ ++ .dsi_config.max_lanes = 4, ++ .dsi_config.max_hs_to_lp_cycles = 100, ++ .dsi_config.max_lp_to_hs_cycles = 40, ++ .dsi_config.max_bta_cycles = 4095, ++ .dsi_config.color_mode_polarity = 1, ++ .dsi_config.shut_down_polarity = 1, ++ .dsi_config.max_bps = 650, ++ .bpp_info = 24, ++}; ++ ++static struct tft_config kd050hdfia019_cfg = { ++ .de_dl = 0, ++ .sync_dl = 0, ++ .color_even = TFT_LCD_COLOR_EVEN_RGB, ++ .color_odd = TFT_LCD_COLOR_ODD_RGB, ++ .mode = TFT_LCD_MODE_PARALLEL_888, ++}; ++ ++struct lcd_panel lcd_panel = { ++ .name = "kd050hdfia019", ++ .num_modes = 1, ++ .modes = &panel_modes, ++ .bpp = 24, ++ .width = 62, ++ .height = 110, ++ ++ .lcd_type = LCD_TYPE_TFT, ++ ++ .tft_config = &kd050hdfia019_cfg, ++ .dsi_pdata = &jzdsi_pdata, ++ ++ .dither_enable = 0, ++ .dither.dither_red = 0, ++ .dither.dither_green = 0, ++ .dither.dither_blue = 0, ++ ++ .ops = &panel_ops, ++}; ++ ++#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL) ++static int panel_set_power(struct lcd_device *lcd, int power) ++{ ++ struct panel_dev *panel = lcd_get_data(lcd); ++ ++ if(POWER_IS_ON(power) && !POWER_IS_ON(panel->power)) { ++ } ++ if(!POWER_IS_ON(power) && POWER_IS_ON(panel->power)) { ++ } ++ ++ panel->power = power; ++ return 0; ++} ++ ++static int panel_get_power(struct lcd_device *lcd) ++{ ++ struct panel_dev *panel = lcd_get_data(lcd); ++ ++ return panel->power; ++} ++ ++/** ++* @ pannel_kd050hdfia019_lcd_ops, register to kernel common backlight/lcd.c framworks. ++*/ ++static struct lcd_ops panel_lcd_ops = { ++ .early_set_power = panel_set_power, ++ .set_power = panel_set_power, ++ .get_power = panel_get_power, ++}; ++ ++static int of_panel_parse(struct device *dev) ++{ ++ return 0; ++} ++/** ++* @panel_probe ++* ++* 1. Register to ingenicfb. ++* 2. Register to lcd. ++* 3. Register to backlight if possible. ++* ++* @pdev ++* ++* @Return - ++*/ ++static int panel_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ ++ panel = kzalloc(sizeof(struct panel_dev), GFP_KERNEL); ++ if(panel == NULL) { ++ dev_err(&pdev->dev, "Faile to alloc memory!"); ++ return -ENOMEM; ++ } ++ panel->dev = &pdev->dev; ++ dev_set_drvdata(&pdev->dev, panel); ++ ++ ret = of_panel_parse(&pdev->dev); ++ if(ret < 0) { ++ goto err_of_parse; ++ } ++ ++ panel->lcd = lcd_device_register("panel_lcd", &pdev->dev, panel, &panel_lcd_ops); ++ if(IS_ERR_OR_NULL(panel->lcd)) { ++ dev_err(&pdev->dev, "Error register lcd!\n"); ++ ret = -EINVAL; ++ goto err_of_parse; ++ } ++ ++ /* TODO: should this power status sync from uboot */ ++ panel->power = FB_BLANK_POWERDOWN; ++ panel_set_power(panel->lcd, FB_BLANK_UNBLANK); ++ ++ mipi_dsi_register_lcd_device(&panel_dev_device); ++ mipi_dsi_register_lcd_driver(&panel_dev_dsim_ddi_driver); ++ ++ ret = ingenicfb_register_panel(&lcd_panel); ++ if(ret < 0) { ++ dev_err(&pdev->dev, "Failed to register lcd panel!\n"); ++ goto err_lcd_register; ++ } ++ ++ return 0; ++ ++err_lcd_register: ++ lcd_device_unregister(panel->lcd); ++err_of_parse: ++ kfree(panel); ++ return ret; ++} ++ ++static int panel_remove(struct platform_device *pdev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(&pdev->dev); ++ ++ panel_set_power(panel->lcd, FB_BLANK_POWERDOWN); ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int panel_suspend(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ ++ panel_set_power(panel->lcd, FB_BLANK_POWERDOWN); ++ return 0; ++} ++ ++static int panel_resume(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ ++ panel_set_power(panel->lcd, FB_BLANK_UNBLANK); ++ return 0; ++} ++ ++static const struct dev_pm_ops panel_pm_ops = { ++ .suspend = panel_suspend, ++ .resume = panel_resume, ++}; ++#endif ++static const struct of_device_id panel_of_match[] = { ++ { .compatible = "ingenic,kd050hdfia019", }, ++ {}, ++}; ++ ++static struct platform_driver panel_driver = { ++ .probe = panel_probe, ++ .remove = panel_remove, ++ .driver = { ++ .name = "kd050hdfia019", ++ .of_match_table = panel_of_match, ++#ifdef CONFIG_PM ++ .pm = &panel_pm_ops, ++#endif ++ }, ++}; ++ ++module_platform_driver(panel_driver); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-ma0060.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-ma0060.c.patch new file mode 100644 index 00000000..76d44d0a --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-ma0060.c.patch @@ -0,0 +1,849 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v12/displays/panel-ma0060.c b/drivers/video/fbdev/ingenic/fb_v12/displays/panel-ma0060.c +--- a/drivers/video/fbdev/ingenic/fb_v12/displays/panel-ma0060.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v12/displays/panel-ma0060.c 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,845 @@ ++/* ++ * driver/video/fbdev/ingenic/x2000_v12/displays/panel-ma0060.c ++ * ++ * Copyright (C) 2016 Ingenic Semiconductor Inc. ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#include "../ingenicfb.h" ++#include "../jz_dsim.h" ++ ++/* #define _1080P */ ++ ++struct board_gpio { ++ short gpio; ++ short active_level; ++}; ++ ++struct panel_dev { ++ /* ingenic frame buffer */ ++ struct device *dev; ++ struct lcd_panel *panel; ++ ++ /* common lcd framework */ ++ struct lcd_device *lcd; ++ struct backlight_device *backlight; ++ int power; ++ ++ struct regulator *vcc; ++ struct board_gpio vdd_en; ++ struct board_gpio rst; ++ struct board_gpio oled; ++ struct board_gpio lcd_pwm; ++ struct board_gpio swire; ++ ++ struct mipi_dsim_lcd_device *dsim_dev; ++}; ++ ++struct panel_dev *panel; ++ ++#define lcd_to_master(a) (a->dsim_dev->master) ++#define lcd_to_master_ops(a) ((lcd_to_master(a))->master_ops) ++ ++struct ma0060 { ++ struct device *dev; ++ unsigned int power; ++ unsigned int id; ++ ++ struct lcd_device *ld; ++ struct backlight_device *bd; ++ ++ struct mipi_dsim_lcd_device *dsim_dev; ++ ++}; ++ ++static struct dsi_cmd_packet visionox_ma0060_720p_cmd_list[] = ++{ ++ {0X39, 0X02, 0X00, {0XFE, 0XD0}}, ++ {0X39, 0X02, 0X00, {0X07, 0X84}}, ++ {0X39, 0X02, 0X00, {0X40, 0X02}}, ++ {0X39, 0X02, 0X00, {0X4B, 0X4C}}, ++ {0X39, 0X02, 0X00, {0X49, 0X01}}, ++ {0X39, 0X02, 0X00, {0XFE, 0X40}}, ++ {0X39, 0X02, 0X00, {0XC7, 0X85}}, ++ {0X39, 0X02, 0X00, {0XC8, 0X32}}, ++ {0X39, 0X02, 0X00, {0XC9, 0X18}}, ++ {0X39, 0X02, 0X00, {0XCA, 0X09}}, ++ {0X39, 0X02, 0X00, {0XCB, 0X22}}, ++ {0X39, 0X02, 0X00, {0XCC, 0X44}}, ++ {0X39, 0X02, 0X00, {0XCD, 0X11}}, ++ {0X39, 0X02, 0X00, {0X05, 0X0F}}, ++ {0X39, 0X02, 0X00, {0X06, 0X09}}, ++ {0X39, 0X02, 0X00, {0X08, 0X0F}}, ++ {0X39, 0X02, 0X00, {0X09, 0X09}}, ++ {0X39, 0X02, 0X00, {0X0A, 0XE6}}, ++ {0X39, 0X02, 0X00, {0X0B, 0X88}}, ++ {0X39, 0X02, 0X00, {0X0D, 0X90}}, ++ {0X39, 0X02, 0X00, {0X0E, 0X10}}, ++ {0X39, 0X02, 0X00, {0X20, 0X93}}, ++ {0X39, 0X02, 0X00, {0X21, 0X93}}, ++ {0X39, 0X02, 0X00, {0X24, 0X02}}, ++ {0X39, 0X02, 0X00, {0X26, 0X02}}, ++ {0X39, 0X02, 0X00, {0X28, 0X05}}, ++ {0X39, 0X02, 0X00, {0X2A, 0X05}}, ++ {0X39, 0X02, 0X00, {0X2D, 0X23}}, ++ {0X39, 0X02, 0X00, {0X2F, 0X23}}, ++ {0X39, 0X02, 0X00, {0X30, 0X23}}, ++ {0X39, 0X02, 0X00, {0X31, 0X23}}, ++ {0X39, 0X02, 0X00, {0X36, 0X55}}, ++ {0X39, 0X02, 0X00, {0X37, 0X80}}, ++ {0X39, 0X02, 0X00, {0X38, 0X50}}, ++ {0X39, 0X02, 0X00, {0X39, 0X00}}, ++ {0X39, 0X02, 0X00, {0X46, 0X27}}, ++ {0X39, 0X02, 0X00, {0X6F, 0X00}}, ++ {0X39, 0X02, 0X00, {0X74, 0X2F}}, ++ {0X39, 0X02, 0X00, {0X75, 0X19}}, ++ {0X39, 0X02, 0X00, {0X79, 0X00}}, ++ {0X39, 0X02, 0X00, {0XAD, 0X00}}, ++ {0X39, 0X02, 0X00, {0XFE, 0X60}}, ++ {0X39, 0X02, 0X00, {0X00, 0XC4}}, ++ {0X39, 0X02, 0X00, {0X01, 0X00}}, ++ {0X39, 0X02, 0X00, {0X02, 0X02}}, ++ {0X39, 0X02, 0X00, {0X03, 0X00}}, ++ {0X39, 0X02, 0X00, {0X04, 0X00}}, ++ {0X39, 0X02, 0X00, {0X05, 0X07}}, ++ {0X39, 0X02, 0X00, {0X06, 0X00}}, ++ {0X39, 0X02, 0X00, {0X07, 0X83}}, ++ {0X39, 0X02, 0X00, {0X09, 0XC4}}, ++ {0X39, 0X02, 0X00, {0X0A, 0X00}}, ++ {0X39, 0X02, 0X00, {0X0B, 0X02}}, ++ {0X39, 0X02, 0X00, {0X0C, 0X00}}, ++ {0X39, 0X02, 0X00, {0X0D, 0X00}}, ++ {0X39, 0X02, 0X00, {0X0E, 0X08}}, ++ {0X39, 0X02, 0X00, {0X0F, 0X00}}, ++ {0X39, 0X02, 0X00, {0X10, 0X83}}, ++ {0X39, 0X02, 0X00, {0X12, 0XCC}}, ++ {0X39, 0X02, 0X00, {0X13, 0X0F}}, ++ {0X39, 0X02, 0X00, {0X14, 0XFF}}, ++ {0X39, 0X02, 0X00, {0X15, 0X01}}, ++ {0X39, 0X02, 0X00, {0X16, 0X00}}, ++ {0X39, 0X02, 0X00, {0X17, 0X02}}, ++ {0X39, 0X02, 0X00, {0X18, 0X00}}, ++ {0X39, 0X02, 0X00, {0X19, 0X00}}, ++ {0X39, 0X02, 0X00, {0X1B, 0XC4}}, ++ {0X39, 0X02, 0X00, {0X1C, 0X00}}, ++ {0X39, 0X02, 0X00, {0X1D, 0X02}}, ++ {0X39, 0X02, 0X00, {0X1E, 0X00}}, ++ {0X39, 0X02, 0X00, {0X1F, 0X00}}, ++ {0X39, 0X02, 0X00, {0X20, 0X08}}, ++ {0X39, 0X02, 0X00, {0X21, 0X00}}, ++ {0X39, 0X02, 0X00, {0X22, 0X89}}, ++ {0X39, 0X02, 0X00, {0X24, 0XC4}}, ++ {0X39, 0X02, 0X00, {0X25, 0X00}}, ++ {0X39, 0X02, 0X00, {0X26, 0X02}}, ++ {0X39, 0X02, 0X00, {0X27, 0X00}}, ++ {0X39, 0X02, 0X00, {0X28, 0X00}}, ++ {0X39, 0X02, 0X00, {0X29, 0X07}}, ++ {0X39, 0X02, 0X00, {0X2A, 0X00}}, ++ {0X39, 0X02, 0X00, {0X2B, 0X89}}, ++ {0X39, 0X02, 0X00, {0X2F, 0XC4}}, ++ {0X39, 0X02, 0X00, {0X30, 0X00}}, ++ {0X39, 0X02, 0X00, {0X31, 0X02}}, ++ {0X39, 0X02, 0X00, {0X32, 0X00}}, ++ {0X39, 0X02, 0X00, {0X33, 0X00}}, ++ {0X39, 0X02, 0X00, {0X34, 0X06}}, ++ {0X39, 0X02, 0X00, {0X35, 0X00}}, ++ {0X39, 0X02, 0X00, {0X36, 0X89}}, ++ {0X39, 0X02, 0X00, {0X38, 0XC4}}, ++ {0X39, 0X02, 0X00, {0X39, 0X00}}, ++ {0X39, 0X02, 0X00, {0X3A, 0X02}}, ++ {0X39, 0X02, 0X00, {0X3B, 0X00}}, ++ {0X39, 0X02, 0X00, {0X3D, 0X00}}, ++ {0X39, 0X02, 0X00, {0X3F, 0X07}}, ++ {0X39, 0X02, 0X00, {0X40, 0X00}}, ++ {0X39, 0X02, 0X00, {0X41, 0X89}}, ++ {0X39, 0X02, 0X00, {0X4C, 0XC4}}, ++ {0X39, 0X02, 0X00, {0X4D, 0X00}}, ++ {0X39, 0X02, 0X00, {0X4E, 0X04}}, ++ {0X39, 0X02, 0X00, {0X4F, 0X01}}, ++ {0X39, 0X02, 0X00, {0X50, 0X00}}, ++ {0X39, 0X02, 0X00, {0X51, 0X08}}, ++ {0X39, 0X02, 0X00, {0X52, 0X00}}, ++ {0X39, 0X02, 0X00, {0X53, 0X61}}, ++ {0X39, 0X02, 0X00, {0X55, 0XC4}}, ++ {0X39, 0X02, 0X00, {0X56, 0X00}}, ++ {0X39, 0X02, 0X00, {0X58, 0X04}}, ++ {0X39, 0X02, 0X00, {0X59, 0X01}}, ++ {0X39, 0X02, 0X00, {0X5A, 0X00}}, ++ {0X39, 0X02, 0X00, {0X5B, 0X06}}, ++ {0X39, 0X02, 0X00, {0X5C, 0X00}}, ++ {0X39, 0X02, 0X00, {0X5D, 0X61}}, ++ {0X39, 0X02, 0X00, {0X5F, 0XCE}}, ++ {0X39, 0X02, 0X00, {0X60, 0X00}}, ++ {0X39, 0X02, 0X00, {0X61, 0X07}}, ++ {0X39, 0X02, 0X00, {0X62, 0X05}}, ++ {0X39, 0X02, 0X00, {0X63, 0X00}}, ++ {0X39, 0X02, 0X00, {0X64, 0X04}}, ++ {0X39, 0X02, 0X00, {0X65, 0X00}}, ++ {0X39, 0X02, 0X00, {0X66, 0X60}}, ++ {0X39, 0X02, 0X00, {0X67, 0X80}}, ++ {0X39, 0X02, 0X00, {0X9B, 0X03}}, ++ {0X39, 0X02, 0X00, {0XA9, 0X10}}, ++ {0X39, 0X02, 0X00, {0XAA, 0X10}}, ++ {0X39, 0X02, 0X00, {0XAB, 0X02}}, ++ {0X39, 0X02, 0X00, {0XAC, 0X04}}, ++ {0X39, 0X02, 0X00, {0XAD, 0X03}}, ++ {0X39, 0X02, 0X00, {0XAE, 0X10}}, ++ {0X39, 0X02, 0X00, {0XAF, 0X10}}, ++ {0X39, 0X02, 0X00, {0XB0, 0X10}}, ++ {0X39, 0X02, 0X00, {0XB1, 0X10}}, ++ {0X39, 0X02, 0X00, {0XB2, 0X10}}, ++ {0X39, 0X02, 0X00, {0XB3, 0X10}}, ++ {0X39, 0X02, 0X00, {0XB4, 0X10}}, ++ {0X39, 0X02, 0X00, {0XB5, 0X10}}, ++ {0X39, 0X02, 0X00, {0XB6, 0X10}}, ++ {0X39, 0X02, 0X00, {0XB7, 0X10}}, ++ {0X39, 0X02, 0X00, {0XB8, 0X10}}, ++ {0X39, 0X02, 0X00, {0XB9, 0X08}}, ++ {0X39, 0X02, 0X00, {0XBA, 0X09}}, ++ {0X39, 0X02, 0X00, {0XBB, 0X0A}}, ++ {0X39, 0X02, 0X00, {0XBC, 0X05}}, ++ {0X39, 0X02, 0X00, {0XBD, 0X06}}, ++ {0X39, 0X02, 0X00, {0XBE, 0X02}}, ++ {0X39, 0X02, 0X00, {0XBF, 0X10}}, ++ {0X39, 0X02, 0X00, {0XC0, 0X10}}, ++ {0X39, 0X02, 0X00, {0XC1, 0X03}}, ++ {0X39, 0X02, 0X00, {0XC4, 0X80}}, ++ {0X39, 0X02, 0X00, {0XFE, 0X70}}, ++ {0X39, 0X02, 0X00, {0X48, 0X05}}, ++ {0X39, 0X02, 0X00, {0X52, 0X00}}, ++ {0X39, 0X02, 0X00, {0X5A, 0XFF}}, ++ {0X39, 0X02, 0X00, {0X5C, 0XF6}}, ++ {0X39, 0X02, 0X00, {0X5D, 0X07}}, ++ {0X39, 0X02, 0X00, {0X7D, 0X75}}, ++ {0X39, 0X02, 0X00, {0X86, 0X07}}, ++ {0X39, 0X02, 0X00, {0XA7, 0X02}}, ++ {0X39, 0X02, 0X00, {0XA9, 0X2C}}, ++ {0X39, 0X02, 0X00, {0XFE, 0XA0}}, ++ {0X39, 0X02, 0X00, {0X2B, 0X18}}, ++ ++ {0x39, 0x02, 0x00, {0xFE, 0xD0}}, /* 【2 lane 设置】 */ ++ {0x39, 0x02, 0x00, {0x1E, 0x05}}, ++ ++ {0x39, 0x02, 0x00, {0xFE, 0x00}}, ++ {0x39, 0x05, 0x00, {0x2A, 0x00, 0x00, 0x02, 0xCF}}, ++ {0x39, 0x05, 0x00, {0x2B, 0x00, 0x00, 0x04, 0xFF}}, ++ ++ {0x39, 0x02, 0x00, {0x11, 0x00}}, ++ {0x99, 120, 0x00, {0x00}}, ++ ++ {0x39, 0x02, 0x00, {0x29, 0x00}}, ++ {0x99, 50, 0x00, {0x00}}, ++ ++}; ++ ++static struct dsi_cmd_packet visionox_ma0060_1080p_cmd_list[] = ++{ ++#if 1 ++ {0x99, 120, 0x00, {0x00}}, //delay 250ms ++ {0x39, 0x02, 0x00, {0xFE, 0x04}}, ++ {0x39, 0x02, 0x00, {0x01, 0x08}}, ++ {0x39, 0x02, 0x00, {0x0D, 0x80}}, ++ {0x39, 0x02, 0x00, {0x05, 0x07}}, ++ {0x39, 0x02, 0x00, {0x06, 0x09}}, ++ {0x39, 0x02, 0x00, {0x0A, 0xDB}}, ++ {0x39, 0x02, 0x00, {0x0B, 0x8C}}, ++ {0x39, 0x02, 0x00, {0x0E, 0x10}}, ++ {0x39, 0x02, 0x00, {0x0F, 0xE0}}, ++ {0x39, 0x02, 0x00, {0x1A, 0x11}}, ++ {0x39, 0x02, 0x00, {0x29, 0x93}}, ++ {0x39, 0x02, 0x00, {0x2A, 0x93}}, ++ {0x39, 0x02, 0x00, {0x2F, 0x02}}, ++ {0x39, 0x02, 0x00, {0x31, 0x02}}, ++ {0x39, 0x02, 0x00, {0x33, 0x05}}, ++ {0x39, 0x02, 0x00, {0x37, 0x23}}, ++ {0x39, 0x02, 0x00, {0x38, 0x23}}, ++ {0x39, 0x02, 0x00, {0x3A, 0x23}}, ++ {0x39, 0x02, 0x00, {0x3B, 0x23}}, ++ {0x39, 0x02, 0x00, {0x3D, 0x2C}}, ++ {0x39, 0x02, 0x00, {0x3F, 0x80}}, ++ {0x39, 0x02, 0x00, {0x40, 0x50}}, ++ {0x39, 0x02, 0x00, {0x41, 0x8E}}, ++ {0x39, 0x02, 0x00, {0x4F, 0x2F}}, ++ {0x39, 0x02, 0x00, {0x50, 0x19}}, ++ {0x39, 0x02, 0x00, {0x51, 0x0A}}, ++ ++ {0x39, 0x02, 0x00, {0xFE, 0x07}}, ++ {0x39, 0x02, 0x00, {0x03, 0x40}}, ++ {0x39, 0x02, 0x00, {0x05, 0x00}}, ++ {0x39, 0x02, 0x00, {0x07, 0x0A}}, ++ ++ {0x39, 0x02, 0x00, {0xFE, 0x06}}, ++ {0x39, 0x02, 0x00, {0xB0, 0x11}}, ++ {0x39, 0x02, 0x00, {0x00, 0xE4}}, ++ {0x39, 0x02, 0x00, {0x01, 0x0F}}, ++ {0x39, 0x02, 0x00, {0x02, 0xFF}}, ++ {0x39, 0x02, 0x00, {0x03, 0x00}}, ++ {0x39, 0x02, 0x00, {0x04, 0x00}}, ++ {0x39, 0x02, 0x00, {0x05, 0x02}}, ++ {0x39, 0x02, 0x00, {0x06, 0x00}}, ++ {0x39, 0x02, 0x00, {0x07, 0xC0}}, ++ {0x39, 0x02, 0x00, {0x08, 0xE4}}, ++ {0x39, 0x02, 0x00, {0x09, 0x00}}, ++ {0x39, 0x02, 0x00, {0x0A, 0x02}}, ++ {0x39, 0x02, 0x00, {0x0B, 0x00}}, ++ {0x39, 0x02, 0x00, {0x0C, 0x00}}, ++ {0x39, 0x02, 0x00, {0x0D, 0x08}}, ++ {0x39, 0x02, 0x00, {0x0E, 0x00}}, ++ {0x39, 0x02, 0x00, {0x0F, 0x83}}, ++ {0x39, 0x02, 0x00, {0x10, 0xE4}}, ++ {0x39, 0x02, 0x00, {0x11, 0x00}}, ++ {0x39, 0x02, 0x00, {0x12, 0x02}}, ++ {0x39, 0x02, 0x00, {0x13, 0x00}}, ++ {0x39, 0x02, 0x00, {0x14, 0x00}}, ++ {0x39, 0x02, 0x00, {0x15, 0x07}}, ++ {0x39, 0x02, 0x00, {0x16, 0x00}}, ++ {0x39, 0x02, 0x00, {0x17, 0x67}}, ++ {0x39, 0x02, 0x00, {0x18, 0xE4}}, ++ {0x39, 0x02, 0x00, {0x19, 0x00}}, ++ {0x39, 0x02, 0x00, {0x1A, 0x02}}, ++ {0x39, 0x02, 0x00, {0x1B, 0x00}}, ++ {0x39, 0x02, 0x00, {0x1C, 0x00}}, ++ {0x39, 0x02, 0x00, {0x1D, 0x07}}, ++ {0x39, 0x02, 0x00, {0x1E, 0x00}}, ++ {0x39, 0x02, 0x00, {0x1F, 0x67}}, ++ {0x39, 0x02, 0x00, {0x20, 0xE4}}, ++ {0x39, 0x02, 0x00, {0x21, 0x00}}, ++ {0x39, 0x02, 0x00, {0x22, 0x02}}, ++ {0x39, 0x02, 0x00, {0x23, 0x00}}, ++ {0x39, 0x02, 0x00, {0x24, 0x00}}, ++ {0x39, 0x02, 0x00, {0x25, 0x08}}, ++ {0x39, 0x02, 0x00, {0x26, 0x00}}, ++ {0x39, 0x02, 0x00, {0x27, 0x83}}, ++ {0x39, 0x02, 0x00, {0x28, 0xE4}}, ++ {0x39, 0x02, 0x00, {0x29, 0x00}}, ++ {0x39, 0x02, 0x00, {0x2A, 0x02}}, ++ {0x39, 0x02, 0x00, {0x2B, 0x00}}, ++ {0x39, 0x02, 0x00, {0x2D, 0x00}}, ++ {0x39, 0x02, 0x00, {0x2F, 0x07}}, ++ {0x39, 0x02, 0x00, {0x30, 0x00}}, ++ {0x39, 0x02, 0x00, {0x31, 0x67}}, ++ {0x39, 0x02, 0x00, {0x32, 0xE4}}, ++ {0x39, 0x02, 0x00, {0x33, 0x00}}, ++ {0x39, 0x02, 0x00, {0x34, 0x02}}, ++ {0x39, 0x02, 0x00, {0x35, 0x00}}, ++ {0x39, 0x02, 0x00, {0x36, 0x00}}, ++ {0x39, 0x02, 0x00, {0x37, 0x08}}, ++ {0x39, 0x02, 0x00, {0x38, 0x00}}, ++ {0x39, 0x02, 0x00, {0x39, 0x67}}, ++ {0x39, 0x02, 0x00, {0x44, 0xE4}}, ++ {0x39, 0x02, 0x00, {0x45, 0x00}}, ++ {0x39, 0x02, 0x00, {0x46, 0x04}}, ++ {0x39, 0x02, 0x00, {0x47, 0x01}}, ++ {0x39, 0x02, 0x00, {0x48, 0x00}}, ++ {0x39, 0x02, 0x00, {0x49, 0x08}}, ++ {0x39, 0x02, 0x00, {0x4A, 0x00}}, ++ {0x39, 0x02, 0x00, {0x4B, 0x64}}, ++ {0x39, 0x02, 0x00, {0x4C, 0xE4}}, ++ {0x39, 0x02, 0x00, {0x4D, 0x00}}, ++ {0x39, 0x02, 0x00, {0x4E, 0x04}}, ++ {0x39, 0x02, 0x00, {0x4F, 0x01}}, ++ {0x39, 0x02, 0x00, {0x50, 0x00}}, ++ {0x39, 0x02, 0x00, {0x51, 0x06}}, ++ {0x39, 0x02, 0x00, {0x52, 0x00}}, ++ {0x39, 0x02, 0x00, {0x53, 0x64}}, ++ {0x39, 0x02, 0x00, {0x8D, 0xEA}}, ++ {0x39, 0x02, 0x00, {0x8E, 0x0F}}, ++ {0x39, 0x02, 0x00, {0x8F, 0xFF}}, ++ {0x39, 0x02, 0x00, {0x90, 0x05}}, ++ {0x39, 0x02, 0x00, {0x91, 0x00}}, ++ {0x39, 0x02, 0x00, {0x92, 0x04}}, ++ {0x39, 0x02, 0x00, {0x93, 0x00}}, ++ {0x39, 0x02, 0x00, {0x94, 0xAB}}, ++ {0x39, 0x02, 0x00, {0xAC, 0x00}}, ++ {0x39, 0x02, 0x00, {0xA6, 0x20}}, ++ {0x39, 0x02, 0x00, {0xA7, 0x04}}, ++ {0x39, 0x02, 0x00, {0xA9, 0x58}}, ++ {0x39, 0x02, 0x00, {0xB1, 0x17}}, ++ {0x39, 0x02, 0x00, {0xB2, 0x17}}, ++ {0x39, 0x02, 0x00, {0xB3, 0x00}}, ++ {0x39, 0x02, 0x00, {0xB4, 0x03}}, ++ {0x39, 0x02, 0x00, {0xB5, 0x04}}, ++ {0x39, 0x02, 0x00, {0xB6, 0x17}}, ++ {0x39, 0x02, 0x00, {0xB7, 0x17}}, ++ {0x39, 0x02, 0x00, {0xB8, 0x17}}, ++ {0x39, 0x02, 0x00, {0xB9, 0x17}}, ++ {0x39, 0x02, 0x00, {0xBA, 0x17}}, ++ {0x39, 0x02, 0x00, {0xBB, 0x17}}, ++ {0x39, 0x02, 0x00, {0xBC, 0x17}}, ++ {0x39, 0x02, 0x00, {0xBD, 0x17}}, ++ {0x39, 0x02, 0x00, {0xBE, 0x17}}, ++ {0x39, 0x02, 0x00, {0xBF, 0x17}}, ++ {0x39, 0x02, 0x00, {0xC0, 0x17}}, ++ {0x39, 0x02, 0x00, {0xC1, 0x08}}, ++ {0x39, 0x02, 0x00, {0xC2, 0x09}}, ++ {0x39, 0x02, 0x00, {0xC3, 0x11}}, ++ {0x39, 0x02, 0x00, {0xC4, 0x06}}, ++ {0x39, 0x02, 0x00, {0xC5, 0x05}}, ++ {0x39, 0x02, 0x00, {0xC6, 0x00}}, ++ {0x39, 0x02, 0x00, {0xC7, 0x17}}, ++ {0x39, 0x02, 0x00, {0xC8, 0x17}}, ++ ++ {0x39, 0x02, 0x00, {0xFE, 0x09}}, ++ {0x39, 0x02, 0x00, {0x15, 0x92}}, ++ {0x39, 0x02, 0x00, {0x16, 0x24}}, ++ {0x39, 0x02, 0x00, {0x17, 0x49}}, ++ {0x39, 0x02, 0x00, {0x1B, 0x92}}, ++ {0x39, 0x02, 0x00, {0x1C, 0x24}}, ++ {0x39, 0x02, 0x00, {0x1D, 0x49}}, ++ {0x39, 0x02, 0x00, {0x21, 0x92}}, ++ {0x39, 0x02, 0x00, {0x22, 0x24}}, ++ {0x39, 0x02, 0x00, {0x23, 0x49}}, ++ {0x39, 0x02, 0x00, {0x9B, 0x47}}, ++ {0x39, 0x02, 0x00, {0x9C, 0x81}}, ++ {0x39, 0x02, 0x00, {0xA3, 0x18}}, ++ ++ {0x39, 0x02, 0x00, {0xFE, 0x0A}}, ++ {0x39, 0x02, 0x00, {0x25, 0x66}}, ++ {0x39, 0x02, 0x00, {0xFE, 0x0E}}, ++ {0x39, 0x02, 0x00, {0x12, 0x33}}, ++ {0x99, 20, 0x00, {0x00}}, //delay 20ms ++ ++ {0x39, 0x02, 0x00, {0xFE, 0x00}}, ++ {0x39, 0x02, 0x00, {0xc2, 0x08}}, ++ {0x39, 0x02, 0x00, {0x35, 0x00}}, ++ ++ {0x39, 0x02, 0x00, {0x11, 0x00}}, ++ {0x99, 120, 0x00, {0x00}}, //delay 120ms ++ ++ {0x39, 0x02, 0x00, {0x29, 0x00}}, ++ {0x99, 50, 0x00, {0x00}}, //delay 120ms ++#endif ++}; ++ ++static void panel_dev_sleep_in(struct panel_dev *lcd) ++{ ++ struct dsi_master_ops *ops = lcd_to_master_ops(lcd); ++ struct dsi_cmd_packet data_to_send = {0x05, 0x10, 0x00}; ++ ++ ops->cmd_write(lcd_to_master(lcd), data_to_send); ++} ++ ++static void panel_dev_sleep_out(struct panel_dev *lcd) ++{ ++ struct dsi_master_ops *ops = lcd_to_master_ops(lcd); ++ struct dsi_cmd_packet data_to_send = {0x05, 0x11, 0x00}; ++ ++ ops->cmd_write(lcd_to_master(lcd), data_to_send); ++} ++ ++static void panel_dev_display_on(struct panel_dev *lcd) ++{ ++ struct dsi_master_ops *ops = lcd_to_master_ops(lcd); ++ struct dsi_cmd_packet data_to_send = {0x05, 0x29, 0x00}; ++ /* struct dsi_cmd_packet data_to_send1 = {0x15, 0x51, 250}; */ ++ ++ ops->cmd_write(lcd_to_master(lcd), data_to_send); ++ /* ops->cmd_write(lcd_to_master(lcd), data_to_send1); */ ++} ++ ++static void panel_dev_display_off(struct panel_dev *lcd) ++{ ++ struct dsi_master_ops *ops = lcd_to_master_ops(lcd); ++ struct dsi_cmd_packet data_to_send = {0x05, 0x28, 0x00}; ++ ++ ops->cmd_write(lcd_to_master(lcd), data_to_send); ++} ++ ++ ++static void panel_dev_panel_init(struct panel_dev *lcd) ++{ ++ int i; ++ struct dsi_master_ops *ops = lcd_to_master_ops(lcd); ++ struct dsi_device *dsi = lcd_to_master(lcd); ++ ++ ++#ifdef _1080P ++ for (i = 0; i < ARRAY_SIZE(visionox_ma0060_1080p_cmd_list); i++) ++ { ++ if (visionox_ma0060_1080p_cmd_list[i].packet_type == 0x99) { ++ msleep(visionox_ma0060_1080p_cmd_list[i].cmd0_or_wc_lsb + visionox_ma0060_1080p_cmd_list[i].cmd1_or_wc_msb); ++ continue; ++ } ++ ops->cmd_write(dsi, visionox_ma0060_1080p_cmd_list[i]); ++ } ++#else ++ for (i = 0; i < ARRAY_SIZE(visionox_ma0060_720p_cmd_list); i++) ++ { ++ if (visionox_ma0060_720p_cmd_list[i].packet_type == 0x99) { ++ msleep(visionox_ma0060_720p_cmd_list[i].cmd0_or_wc_lsb + visionox_ma0060_720p_cmd_list[i].cmd1_or_wc_msb); ++ continue; ++ } ++ ops->cmd_write(dsi, visionox_ma0060_720p_cmd_list[i]); ++ } ++#endif ++} ++ ++static int panel_dev_ioctl(struct mipi_dsim_lcd_device *dsim_dev, int cmd) ++{ ++ return 0; ++} ++static void panel_dev_set_sequence(struct mipi_dsim_lcd_device *dsim_dev) ++{ ++ struct ma0060 *lcd = dev_get_drvdata(&dsim_dev->dev); ++ ++ panel_dev_panel_init(panel); ++ lcd->power = FB_BLANK_UNBLANK; ++} ++static void panel_dev_power_on(struct mipi_dsim_lcd_device *dsim_dev, int power) ++{ ++ struct board_gpio *vdd_en = &panel->vdd_en; ++ struct board_gpio *rst = &panel->rst; ++ struct board_gpio *oled = &panel->oled; ++ struct board_gpio *swire = &panel->swire; ++ ++ ++ gpio_direction_output(vdd_en->gpio, vdd_en->active_level); ++ ++ if (gpio_is_valid(swire->gpio)) { ++ gpio_direction_input(swire->gpio); ++ } ++ ++ if (gpio_is_valid(oled->gpio)) { ++ gpio_direction_input(oled->gpio); ++ } ++ msleep(100); ++ ++ gpio_direction_output(rst->gpio, 1); ++ msleep(100); ++ gpio_direction_output(rst->gpio, 0); ++ msleep(150); ++ gpio_direction_output(rst->gpio, 1); ++ msleep(100); ++ ++ panel->power = power; ++} ++ ++static struct fb_videomode panel_modes = { ++ .name = "visionox_ma0060-lcd", ++#ifdef _1080P ++ .refresh = 45, ++ .xres = 1080, ++ .yres = 1920, ++#else ++ .refresh = 60, ++ .xres = 720, ++ .yres = 1280, ++#endif ++ .left_margin = 36, ++ .right_margin = 26, ++ .upper_margin = 4, ++ .lower_margin = 8, ++ ++ .hsync_len = 2, ++ .vsync_len = 4, ++ .vmode = FB_VMODE_NONINTERLACED, ++ .flag = 0, ++}; ++ ++struct jzdsi_data jzdsi_pdata = { ++ .modes = &panel_modes, ++ ++#ifdef _1080P ++ .video_config.no_of_lanes = 4, ++#else ++ .video_config.no_of_lanes = 2, ++#endif ++ .video_config.virtual_channel = 0, ++ .video_config.color_coding = COLOR_CODE_24BIT, ++ .video_config.video_mode = VIDEO_BURST_WITH_SYNC_PULSES, ++ .video_config.receive_ack_packets = 0, /* enable receiving of ack packets */ ++ .video_config.is_18_loosely = 0, ++ .video_config.data_en_polarity = 1, ++ .video_config.byte_clock = 0, // driver will auto calculate byte_clock. ++ .video_config.byte_clock_coef = MIPI_PHY_BYTE_CLK_COEF_MUL6_DIV5, //for auto calculate byte clock ++ ++ .dsi_config.max_lanes = 4, ++ .dsi_config.max_hs_to_lp_cycles = 100, ++ .dsi_config.max_lp_to_hs_cycles = 40, ++ .dsi_config.max_bta_cycles = 4095, ++ .dsi_config.color_mode_polarity = 1, ++ .dsi_config.shut_down_polarity = 1, ++ .dsi_config.max_bps = 2750, ++ .bpp_info = 24, ++}; ++ ++struct smart_config smart_cfg = { ++ .smart_type = SMART_LCD_TYPE_8080, ++ .pix_fmt = SMART_LCD_FORMAT_888, ++ .dwidth = SMART_LCD_DWIDTH_24_BIT, ++}; ++ ++struct lcd_panel lcd_panel = { ++ .num_modes = 1, ++ .modes = &panel_modes, ++ .dsi_pdata = &jzdsi_pdata, ++ .smart_config = &smart_cfg, ++ .lcd_type = LCD_TYPE_MIPI_SLCD, ++ ++ .bpp = 24, ++#ifdef _1080P ++ .width = 1080, ++ .height = 1920, ++#else ++ .width = 720, ++ .height = 1280, ++#endif ++}; ++ ++#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL) ++static int panel_set_power(struct lcd_device *lcd, int power) ++{ ++ return 0; ++} ++ ++static int panel_get_power(struct lcd_device *lcd) ++{ ++ struct panel_dev *panel = lcd_get_data(lcd); ++ ++ return panel->power; ++} ++ ++/** ++* @ pannel_ma0060_lcd_ops, register to kernel common backlight/lcd.c framworks. ++*/ ++static struct lcd_ops panel_lcd_ops = { ++ .early_set_power = panel_set_power, ++ .set_power = panel_set_power, ++ .get_power = panel_get_power, ++}; ++ ++static int of_panel_parse(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ struct device_node *np = dev->of_node; ++ enum of_gpio_flags flags; ++ int ret = 0; ++ ++ panel->vdd_en.gpio = of_get_named_gpio_flags(np, "ingenic,vdd-en-gpio", 0, &flags); ++ if(gpio_is_valid(panel->vdd_en.gpio)) { ++ panel->vdd_en.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ ret = gpio_request_one(panel->vdd_en.gpio, GPIOF_DIR_OUT, "vdd_en"); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request vdd_en pin!\n"); ++ return ret; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio vdd_en.gpio: %d\n", panel->vdd_en.gpio); ++ } ++ ++ panel->rst.gpio = of_get_named_gpio_flags(np, "ingenic,rst-gpio", 0, &flags); ++ if(gpio_is_valid(panel->rst.gpio)) { ++ panel->rst.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ ret = gpio_request_one(panel->rst.gpio, GPIOF_DIR_OUT, "rst"); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request rst pin!\n"); ++ goto err_request_rst; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio rst.gpio: %d\n", panel->rst.gpio); ++ } ++ ++ /* panel->oled.gpio = of_get_named_gpio_flags(np, "ingenic,oled-gpio", 0, &flags); ++ if(gpio_is_valid(panel->oled.gpio)) { ++ panel->oled.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ ret = gpio_request_one(panel->oled.gpio, GPIOF_DIR_OUT, "oled"); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request oled pin!\n"); ++ goto err_request_oled; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio oled.gpio: %d\n", panel->oled.gpio); ++ } */ ++ ++ panel->lcd_pwm.gpio = of_get_named_gpio_flags(np, "ingenic,lcd-pwm-gpio", 0, &flags); ++ if(gpio_is_valid(panel->lcd_pwm.gpio)) { ++ panel->lcd_pwm.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ ret = gpio_request_one(panel->lcd_pwm.gpio, GPIOF_DIR_OUT, "lcd-pwm"); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request lcd-pwm pin!\n"); ++ goto err_request_pwm; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio lcd-pwm.gpio: %d\n", panel->lcd_pwm.gpio); ++ } ++ ++ /* panel->swire.gpio = of_get_named_gpio_flags(np, "ingenic,swire-gpio", 0, &flags); ++ if(gpio_is_valid(panel->swire.gpio)) { ++ panel->swire.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ ret = gpio_request_one(panel->swire.gpio, GPIOF_DIR_OUT, "swire"); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request swire pin!\n"); ++ goto err_request_swire; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio swire.gpio: %d\n", panel->swire.gpio); ++ } */ ++ ++ return 0; ++/* err_request_swire: ++ if(gpio_is_valid(panel->lcd_pwm.gpio)) ++ gpio_free(panel->lcd_pwm.gpio); */ ++err_request_pwm: ++ /* if(gpio_is_valid(panel->oled.gpio)) */ ++ /* gpio_free(panel->oled.gpio); */ ++/* err_request_oled: */ ++ if(gpio_is_valid(panel->rst.gpio)) ++ gpio_free(panel->rst.gpio); ++err_request_rst: ++ if(gpio_is_valid(panel->vdd_en.gpio)) ++ gpio_free(panel->vdd_en.gpio); ++ return ret; ++} ++ ++static int panel_dev_probe(struct mipi_dsim_lcd_device *dsim_dev) ++{ ++ struct ma0060 *lcd; ++ lcd = devm_kzalloc(&dsim_dev->dev, sizeof(struct ma0060), GFP_KERNEL); ++ if (!lcd) ++ { ++ dev_err(&dsim_dev->dev, "failed to allocate visionox_ma0060 structure.\n"); ++ return -ENOMEM; ++ } ++ ++ lcd->dsim_dev = dsim_dev; ++ lcd->dev = &dsim_dev->dev; ++ ++ lcd->ld = lcd_device_register("visionox_ma0060", lcd->dev, lcd, ++ &panel_lcd_ops); ++ if (IS_ERR(lcd->ld)) ++ { ++ dev_err(lcd->dev, "failed to register lcd ops.\n"); ++ return PTR_ERR(lcd->ld); ++ } ++ ++ dev_set_drvdata(&dsim_dev->dev, lcd); ++ ++ ++ dev_dbg(lcd->dev, "probed visionox_ma0060 panel driver.\n"); ++ ++ ++ panel->dsim_dev = dsim_dev; ++ ++ ++ return 0; ++ ++} ++ ++static int panel_suspend(struct mipi_dsim_lcd_device *dsim_dev) ++{ ++ struct board_gpio *vdd_en = &panel->vdd_en; ++ ++ panel_dev_display_off(panel); ++ panel_dev_sleep_in(panel); ++ gpio_direction_output(vdd_en->gpio, !vdd_en->active_level); ++ ++ return 0; ++} ++ ++static int panel_resume(struct mipi_dsim_lcd_device *dsim_dev) ++{ ++ struct board_gpio *vdd_en = &panel->vdd_en; ++ ++ gpio_direction_output(vdd_en->gpio, vdd_en->active_level); ++ ++ return 0; ++} ++ ++static struct mipi_dsim_lcd_driver panel_dev_dsim_ddi_driver = { ++ .name = "visionox_ma0060-lcd", ++ .id = -1, ++ ++ .power_on = panel_dev_power_on, ++ .set_sequence = panel_dev_set_sequence, ++ .probe = panel_dev_probe, ++ .suspend = panel_suspend, ++ .resume = panel_resume, ++}; ++ ++ ++struct mipi_dsim_lcd_device panel_dev_device={ ++ .name = "visionox_ma0060-lcd", ++ .id = 0, ++}; ++ ++/** ++* @panel_probe ++* ++* 1. Register to ingenicfb. ++* 2. Register to lcd. ++* 3. Register to backlight if possible. ++* ++* @pdev ++* ++* @Return - ++*/ ++static int panel_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ ++ panel = kzalloc(sizeof(struct panel_dev), GFP_KERNEL); ++ if(panel == NULL) { ++ dev_err(&pdev->dev, "Faile to alloc memory!"); ++ return -ENOMEM; ++ } ++ panel->dev = &pdev->dev; ++ dev_set_drvdata(&pdev->dev, panel); ++ ++ ret = of_panel_parse(&pdev->dev); ++ if(ret < 0) { ++ goto err_of_parse; ++ } ++ ++ mipi_dsi_register_lcd_device(&panel_dev_device); ++ mipi_dsi_register_lcd_driver(&panel_dev_dsim_ddi_driver); ++ ++ ret = ingenicfb_register_panel(&lcd_panel); ++ if(ret < 0) { ++ dev_err(&pdev->dev, "Failed to register lcd panel!\n"); ++ goto err_of_parse; ++ } ++ ++ return 0; ++ ++err_of_parse: ++ kfree(panel); ++ return ret; ++} ++ ++static int panel_remove(struct platform_device *pdev) ++{ ++ return 0; ++} ++ ++static const struct of_device_id panel_of_match[] = { ++ { .compatible = "ingenic,ma0060", }, ++ {}, ++}; ++ ++static struct platform_driver panel_driver = { ++ .probe = panel_probe, ++ .remove = panel_remove, ++ .driver = { ++ .name = "ma0060", ++ .of_match_table = panel_of_match, ++ }, ++}; ++ ++module_platform_driver(panel_driver); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-mtf070.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-mtf070.c.patch new file mode 100644 index 00000000..ab35f0d7 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-mtf070.c.patch @@ -0,0 +1,624 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v12/displays/panel-mtf070.c b/drivers/video/fbdev/ingenic/fb_v12/displays/panel-mtf070.c +--- a/drivers/video/fbdev/ingenic/fb_v12/displays/panel-mtf070.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v12/displays/panel-mtf070.c 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,620 @@ ++/* ++ * Copyright (c) 2012 Ingenic Semiconductor Co., Ltd. ++ * http://www.ingenic.com/ ++ * ++ * dorado board lcd setup routines. ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../ingenicfb.h" ++#include "../jz_dsim.h" ++ ++#define JZ_LCD_FPS_MAX 0 ++ ++#define LCD_WIDTH 800 ++#define LCD_HEIGHT 1280 ++ ++static struct dsi_cmd_packet mtf070_cmd_list[] = { ++#ifdef CONFIG_MIPI_2LANE ++ /*{0x15, 0xDE, 0x01, {0x00}}, [>11:4 lane; 01:2 lane<]*/ ++#endif ++#ifdef CONFIG_MIPI_4LANE ++ /*{0x15, 0xDE, 0x03, {0x00}}, [>11:4 lane; 01:2 lane<]*/ ++#endif ++ {0x39, 0x05, 0x00, { 0xFF, 0xAA, 0x55, 0xA5, 0x80} }, ++ {0x39, 0x03, 0x00, { 0x6F,0x11,0x00} }, ++ {0x39, 0x03, 0x00, { 0xF7,0x20,0x00} }, ++ {0x15, 0x6F, 0x06, { 0x00}}, ++ {0x15, 0xF7, 0xA0, { 0x00}}, ++ {0x15, 0x6F, 0x19, { 0x00}}, ++ {0x15, 0xF7, 0x12, { 0x00}}, ++ {0x15, 0xF4, 0x03, { 0x00}}, ++ {0x15, 0x6F, 0x08, { 0x00}}, ++ {0x15, 0xFA, 0x40, { 0x00}}, ++ {0x15, 0x6F, 0x11, { 0x00}}, ++ {0x15, 0xF3, 0x01, { 0x00}}, ++ {0x39, 0x06, 0x00, { 0xF0,0x55,0xAA,0x52,0x08,0x00} }, ++ {0x15, 0xC8, 0x80, { 0x00}}, ++ {0x39, 0x03, 0x00, { 0xB1,0x6C,0x01} }, ++ {0x15, 0xB6, 0x08, { 0x00}}, ++ {0x15, 0x6F, 0x02, { 0x00}}, ++ {0x15, 0xB8, 0x08, { 0x00}}, ++ {0x39, 0x03, 0x00, { 0xBB,0x54,0x54} }, ++ {0x39, 0x03, 0x00, { 0xBC,0x05,0x05} }, ++ {0x15, 0xC7, 0x01, { 0x00}}, ++ {0x39, 0x06, 0x00, { 0xBD,0x02,0xB0,0x0C,0x0A,0x00} }, ++ {0x39, 0x06, 0x00, { 0xF0,0x55,0xAA,0x52,0x08,0x01} }, ++ {0x39, 0x03, 0x00, { 0xB0,0x05,0x05} }, ++ {0x39, 0x03, 0x00, { 0xB1,0x05,0x05} }, ++ {0x39, 0x03, 0x00, { 0xBC,0x3A,0x01} }, ++ {0x39, 0x03, 0x00, { 0xBD,0x3E,0x01} }, ++ {0x15, 0xCA, 0x00, { 0x00}}, ++ {0x15, 0xC0, 0x04, { 0x00}}, ++ {0x15, 0xB2, 0x00, { 0x00}}, ++ {0x15, 0xBE, 0x80, { 0x00}}, ++ {0x39, 0x03, 0x00, { 0xB3,0x19,0x19} }, ++ {0x39, 0x03, 0x00, { 0xB4,0x12,0x12} }, ++ {0x39, 0x03, 0x00, { 0xB9,0x24,0x24} }, ++ {0x39, 0x03, 0x00, { 0xBA,0x14,0x14} }, ++ {0x39, 0x06, 0x00, { 0xF0,0x55,0xAA,0x52,0x08,0x02} }, ++ {0x15, 0xEE, 0x01, { 0x00}}, ++ {0x39, 0x05, 0x00, { 0xEF,0x09,0x06,0x15,0x18} }, ++ {0x39, 0x07, 0x00, { 0xB0,0x00,0x00,0x00,0x08,0x00,0x17} }, ++ {0x15, 0x6F, 0x06, { 0x00 }}, ++ {0x39, 0x07, 0x00, { 0xB0,0x00,0x25,0x00,0x30,0x00,0x45} }, ++ {0x15, 0x6F, 0x0C, { 0x00 }}, ++ {0x39, 0x05, 0x00, { 0xB0,0x00,0x56,0x00,0x7a} }, ++ {0x39, 0x07, 0x00, { 0xB1,0x00,0xa3,0x00,0xe7,0x01,0x20} }, ++ {0x15, 0x6F, 0x06, { 0x00 }}, ++ {0x39, 0x07, 0x00, { 0xB1,0x01,0x7a,0x01,0xc2,0x01,0xc5} }, ++ {0x15, 0x6F, 0x0C, { 0x00 }}, ++ {0x39, 0x05, 0x00, { 0xB1,0x02,0x06,0x02,0x5f} }, ++ {0x39, 0x07, 0x00, { 0xB2,0x02,0x92,0x02,0xD0,0x02,0xfc} }, ++ {0x15, 0x6F, 0x06, { 0x00 }}, ++ {0x39, 0x07, 0x00, { 0xB2,0x03,0x35,0x03,0x5d,0x03,0x8b} }, ++ {0x15, 0x6F, 0x0C, { 0x00 }}, ++ {0x39, 0x05, 0x00, { 0xB2,0x03,0xA2,0x03,0xBF} }, ++ {0x39, 0x05, 0x00, { 0xB3,0x03,0xD2,0x03,0xFF} }, ++ ++ {0x39, 0x06, 0x00, { 0xF0,0x55,0xAA,0x52,0x08,0x06} }, ++ {0x39, 0x03, 0x00, { 0xB0,0x00,0x17} }, ++ {0x39, 0x03, 0x00, { 0xB1,0x16,0x15} }, ++ {0x39, 0x03, 0x00, { 0xB2,0x14,0x13} }, ++ {0x39, 0x03, 0x00, { 0xB3,0x12,0x11} }, ++ {0x39, 0x03, 0x00, { 0xB4,0x10,0x2D} }, ++ {0x39, 0x03, 0x00, { 0xB5,0x01,0x08} }, ++ {0x39, 0x03, 0x00, { 0xB6,0x09,0x31} }, ++ {0x39, 0x03, 0x00, { 0xB7,0x31,0x31} }, ++ {0x39, 0x03, 0x00, { 0xB8,0x31,0x31} }, ++ {0x39, 0x03, 0x00, { 0xB9,0x31,0x31} }, ++ {0x39, 0x03, 0x00, { 0xBA,0x31,0x31} }, ++ {0x39, 0x03, 0x00, { 0xBB,0x31,0x31} }, ++ {0x39, 0x03, 0x00, { 0xBC,0x31,0x31} }, ++ {0x39, 0x03, 0x00, { 0xBD,0x31,0x09} }, ++ {0x39, 0x03, 0x00, { 0xBE,0x08,0x01} }, ++ {0x39, 0x03, 0x00, { 0xBF,0x2D,0x10} }, ++ {0x39, 0x03, 0x00, { 0xC0,0x11,0x12} }, ++ {0x39, 0x03, 0x00, { 0xC1,0x13,0x14} }, ++ {0x39, 0x03, 0x00, { 0xC2,0x15,0x16} }, ++ {0x39, 0x03, 0x00, { 0xC3,0x17,0x00} }, ++ {0x39, 0x03, 0x00, { 0xE5,0x31,0x31} }, ++ {0x39, 0x03, 0x00, { 0xC4,0x00,0x17} }, ++ {0x39, 0x03, 0x00, { 0xC5,0x16,0x15} }, ++ {0x39, 0x03, 0x00, { 0xC6,0x14,0x13} }, ++ {0x39, 0x03, 0x00, { 0xC7,0x12,0x11} }, ++ {0x39, 0x03, 0x00, { 0xC8,0x10,0x2D} }, ++ {0x39, 0x03, 0x00, { 0xC9,0x01,0x08} }, ++ {0x39, 0x03, 0x00, { 0xCA,0x09,0x31} }, ++ {0x39, 0x03, 0x00, { 0xCB,0x31,0x31} }, ++ {0x39, 0x03, 0x00, { 0xCC,0x31,0x31} }, ++ {0x39, 0x03, 0x00, { 0xCD,0x31,0x31} }, ++ {0x39, 0x03, 0x00, { 0xCE,0x31,0x31} }, ++ {0x39, 0x03, 0x00, { 0xCF,0x31,0x31} }, ++ {0x39, 0x03, 0x00, { 0xD0,0x31,0x31} }, ++ {0x39, 0x03, 0x00, { 0xD1,0x31,0x09} }, ++ {0x39, 0x03, 0x00, { 0xD2,0x08,0x01} }, ++ {0x39, 0x03, 0x00, { 0xD3,0x2D,0x10} }, ++ {0x39, 0x03, 0x00, { 0xD4,0x11,0x12} }, ++ {0x39, 0x03, 0x00, { 0xD5,0x13,0x14} }, ++ {0x39, 0x03, 0x00, { 0xD6,0x15,0x16} }, ++ {0x39, 0x03, 0x00, { 0xD7,0x17,0x00} }, ++ {0x39, 0x03, 0x00, { 0xE6,0x31,0x31} }, ++ {0x39, 0x06, 0x00, { 0xD8,0x00,0x00,0x00,0x00,0x00} }, ++ {0x39, 0x06, 0x00, { 0xD9,0x00,0x00,0x00,0x00,0x00} }, ++ {0x15, 0xE7, 0x00, { 0x00 } }, ++ ++ {0x39, 0x06, 0x00, { 0xF0,0x55,0xAA,0x52,0x08,0x03} }, ++ {0x39, 0x03, 0x00, { 0xB0,0x20,0x00} }, ++ {0x39, 0x03, 0x00, { 0xB1,0x20,0x00} }, ++ {0x39, 0x06, 0x00, { 0xB2,0x05,0x00,0x42,0x00,0x00} }, ++ {0x39, 0x06, 0x00, { 0xB6,0x05,0x00,0x42,0x00,0x00} }, ++ {0x39, 0x06, 0x00, { 0xBA,0x53,0x00,0x42,0x00,0x00} }, ++ {0x39, 0x06, 0x00, { 0xBB,0x53,0x00,0x42,0x00,0x00} }, ++ {0x15, 0xC4, 0x40, { 0x00 } }, ++ ++ {0x39, 0x06, 0x00, { 0xF0,0x55,0xAA,0x52,0x08,0x05} }, ++ {0x39, 0x03, 0x00, { 0xB0,0x17,0x06} }, ++ {0x15, 0xB8, 0x00, { 0x00 } }, ++ {0x39, 0x06, 0x00, { 0xBD,0x03,0x01,0x01,0x00,0x01} }, ++ {0x39, 0x03, 0x00, { 0xB1,0x17,0x06} }, ++ {0x39, 0x03, 0x00, { 0xB9,0x00,0x01} }, ++ {0x39, 0x03, 0x00, { 0xB2,0x17,0x06} }, ++ {0x39, 0x03, 0x00, { 0xBA,0x00,0x01} }, ++ {0x39, 0x03, 0x00, { 0xB3,0x17,0x06} }, ++ {0x39, 0x03, 0x00, { 0xBB,0x0A,0x00} }, ++ {0x39, 0x03, 0x00, { 0xB4,0x17,0x06} }, ++ {0x39, 0x03, 0x00, { 0xB5,0x17,0x06} }, ++ {0x39, 0x03, 0x00, { 0xB6,0x14,0x03} }, ++ {0x39, 0x03, 0x00, { 0xB7,0x00,0x00} }, ++ {0x39, 0x03, 0x00, { 0xBC,0x02,0x01} }, ++ {0x15, 0xC0, 0x05, { 0x00 } }, ++ {0x15, 0xC4, 0xA5, { 0x00 } }, ++ {0x39, 0x03, 0x00, { 0xC8,0x03,0x30} }, ++ {0x39, 0x03, 0x00, { 0xC9,0x03,0x51} }, ++ {0x39, 0x06, 0x00, { 0xD1,0x00,0x05,0x03,0x00,0x00} }, ++ {0x39, 0x06, 0x00, { 0xD2,0x00,0x05,0x09,0x00,0x00} }, ++ {0x15, 0xE5, 0x02, { 0x00 } }, ++ {0x15, 0xE6, 0x02, { 0x00 } }, ++ {0x15, 0xE7, 0x02, { 0x00 } }, ++ {0x15, 0xE9, 0x02, { 0x00 } }, ++ {0x15, 0xED, 0x33, { 0x00 } }, ++ ++ {0x15, 0x11, 0x00, { 0x00 }}, //Sleep out ++ {0x99, 500, 0x00, {0x00}}, //delay 500ms ++ {0x15, 0x29, 0x00, { 0x00}}, // Display On ++ {0x99, 200, 0x00, {0x00}}, //delay 200ms ++}; ++ ++struct board_gpio { ++ short gpio; ++ short active_level; ++}; ++ ++struct panel_dev { ++ /* ingenic frame buffer */ ++ struct device *dev; ++ struct lcd_panel *panel; ++ ++ /* common lcd framework */ ++ struct lcd_device *lcd; ++ struct backlight_device *backlight; ++ int power; ++ ++ struct regulator *vcc; ++ struct board_gpio vdd_en; ++ struct board_gpio bl; ++ struct board_gpio rst; ++ struct board_gpio pw; ++ struct board_gpio oled; ++ struct board_gpio lcd_pwm; ++ ++ struct mipi_dsim_lcd_device *dsim_dev; ++}; ++ ++struct panel_dev *panel; ++ ++#define lcd_to_master(a) (a->dsim_dev->master) ++#define lcd_to_master_ops(a) ((lcd_to_master(a))->master_ops) ++ ++struct mtf070 { ++ struct device *dev; ++ unsigned int power; ++ unsigned int id; ++ ++ struct lcd_device *ld; ++ struct backlight_device *bd; ++ ++ struct mipi_dsim_lcd_device *dsim_dev; ++}; ++ ++struct fb_videomode jzfb_mtf070_videomode[] = { ++ { ++ .name = "mtf070", ++ .refresh = 30, ++ .xres = LCD_WIDTH, ++ .yres = LCD_HEIGHT, ++ .pixclock = KHZ2PICOS(20000), ++ .left_margin = 44, ++ .right_margin = 48, ++ .upper_margin = 112, ++ .lower_margin = 120, ++ .hsync_len = 10, ++ .vsync_len = 4, ++ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, ++ .vmode = FB_VMODE_NONINTERLACED, ++ .flag = 0, ++ }, ++}; ++struct jzdsi_data jzdsi_pdata = { ++ .modes = &jzfb_mtf070_videomode[JZ_LCD_FPS_MAX], ++#ifdef CONFIG_MIPI_2LANE ++ .video_config.no_of_lanes = 2, ++#endif ++#ifdef CONFIG_MIPI_4LANE ++ .video_config.no_of_lanes = 4, ++#endif ++ .video_config.virtual_channel = 0, ++ .video_config.color_coding = COLOR_CODE_24BIT, ++#if 1 ++ .video_config.video_mode = VIDEO_NON_BURST_WITH_SYNC_PULSES, ++#else ++ .video_config.video_mode = VIDEO_BURST_WITH_SYNC_PULSES, ++#endif ++ .video_config.receive_ack_packets = 0, /* enable receiving of ack packets */ ++ /*loosely: R0R1R2R3R4R5__G0G1G2G3G4G5G6__B0B1B2B3B4B5B6, ++ * not loosely: R0R1R2R3R4R5G0G1G2G3G4G5B0B1B2B3B4B5*/ ++ .video_config.is_18_loosely = 0, ++ .video_config.data_en_polarity = 1, ++ ++ .dsi_config.max_lanes = 4, ++ .dsi_config.max_hs_to_lp_cycles = 100, ++ .dsi_config.max_lp_to_hs_cycles = 40, ++ .dsi_config.max_bta_cycles = 4095, ++ .dsi_config.color_mode_polarity = 1, ++ .dsi_config.shut_down_polarity = 1, ++ .dsi_config.max_bps = 1361, ++ /*.max_bps = 650, // 650 Mbps*/ ++ .bpp_info = 24, ++ ++}; ++ ++struct tft_config mtf070_cfg = { ++ .pix_clk_inv = 0, ++ .de_dl = 0, ++ .sync_dl = 0, ++ .color_even = TFT_LCD_COLOR_EVEN_RGB, ++ .color_odd = TFT_LCD_COLOR_ODD_RGB, ++ .mode = TFT_LCD_MODE_PARALLEL_888, ++}; ++ ++struct lcd_panel lcd_panel = { ++ .num_modes = 1, ++ .modes = &jzfb_mtf070_videomode[JZ_LCD_FPS_MAX], ++ .dsi_pdata = &jzdsi_pdata, ++ //.smart_config = &smart_cfg, ++ .tft_config = &mtf070_cfg, ++ ++ .lcd_type = LCD_TYPE_TFT , ++ .width = LCD_WIDTH, ++ .height = LCD_HEIGHT, ++ //.bpp = 24, ++ ++ //.pixclk_falling_edge = 0, ++ //.data_enable_active_low = 0, ++ ++}; ++ ++/**************************************************************************************************/ ++#ifdef CONFIG_BACKLIGHT_PWM ++ ++static struct platform_pwm_backlight_data backlight_data = { ++ .pwm_id = 0, ++ .max_brightness = 255, ++ .dft_brightness = 100, ++ .pwm_period_ns = 30000, ++}; ++ ++struct platform_device backlight_device = { ++ .name = "pwm-backlight", ++ .dev = { ++ .platform_data = &backlight_data, ++ }, ++}; ++ ++#endif ++ ++#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL) ++static int panel_set_power(struct lcd_device *lcd, int power) ++{ ++ return 0; ++} ++ ++static int panel_get_power(struct lcd_device *lcd) ++{ ++ struct panel_dev *panel = lcd_get_data(lcd); ++ ++ return panel->power; ++} ++ ++static struct lcd_ops panel_lcd_ops = { ++ .early_set_power = panel_set_power, ++ .set_power = panel_set_power, ++ .get_power = panel_get_power, ++}; ++ ++static int of_panel_parse(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ struct device_node *np = dev->of_node; ++ enum of_gpio_flags flags; ++ int ret = 0; ++ ++ panel->bl.gpio = of_get_named_gpio_flags(np, "ingenic,bl-gpio", 0, &flags); ++ if (gpio_is_valid(panel->bl.gpio)) { ++ panel->bl.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ ret = devm_gpio_request(dev, panel->bl.gpio, "backlight"); ++ if (ret < 0) { ++ dev_err(dev, "Failed to request backlight pin!\n"); ++ return ret; ++ } ++ } else ++ dev_warn(dev, "invalid gpio backlight.gpio: %d\n", panel->bl.gpio); ++ ++ panel->rst.gpio = of_get_named_gpio_flags(np, "ingenic,rst-gpio", 0, &flags); ++ if (gpio_is_valid(panel->rst.gpio)) { ++ panel->rst.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ ret = devm_gpio_request(dev, panel->rst.gpio, "reset"); ++ if (ret < 0) { ++ dev_err(dev, "Failed to request rst pin!\n"); ++ return ret; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio rst.gpio: %d\n", panel->rst.gpio); ++ } ++ ++ panel->pw.gpio = of_get_named_gpio_flags(np, "ingenic,pw-gpio", 0, &flags); ++ if (gpio_is_valid(panel->pw.gpio)) { ++ panel->pw.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ ret = devm_gpio_request(dev, panel->pw.gpio, "power_on"); ++ if (ret < 0) { ++ dev_err(dev, "Failed to request power_on pin!\n"); ++ return ret; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio pw.gpio: %d\n", panel->pw.gpio); ++ } ++ ++ return 0; ++} ++ ++static void panel_dev_panel_init(struct panel_dev *lcd) ++{ ++#if 0 ++ int i; ++ struct dsi_master_ops *ops = lcd_to_master_ops(lcd); ++ struct dsi_device *dsi = lcd_to_master(lcd); ++ ++ for (i = 0; i < ARRAY_SIZE(mtf070_cmd_list); i++) ++ ops->cmd_write(dsi, mtf070_cmd_list[i]); ++ msleep(20); ++#endif ++ int i, j; ++ struct dsi_master_ops *ops = lcd_to_master_ops(lcd); ++ struct dsi_device *dsi = lcd_to_master(lcd); ++ unsigned char dsi_command_param[MAX_WORD_COUNT] = {0}; ++ ++ for (i = 0; i < ARRAY_SIZE(mtf070_cmd_list); i++) { ++ if (mtf070_cmd_list[i].packet_type == 0x99) { ++ /* printk("\nsleep now. time: %dms\n", mtf070_cmd_list[i].cmd0_or_wc_lsb+mtf070_cmd_list[i].cmd1_or_wc_msb); */ ++ if (mtf070_cmd_list[i].cmd0_or_wc_lsb + mtf070_cmd_list[i].cmd1_or_wc_msb == 510) ++ msleep(600); ++ else ++ msleep(mtf070_cmd_list[i].cmd0_or_wc_lsb + mtf070_cmd_list[i].cmd1_or_wc_msb); ++ continue; ++ } ++ ++ ops->cmd_write(dsi, mtf070_cmd_list[i]); ++ } ++} ++ ++static int panel_dev_ioctl(struct mipi_dsim_lcd_device *dsim_dev, int cmd) ++{ ++ return 0; ++} ++ ++static void panel_dev_set_sequence(struct mipi_dsim_lcd_device *dsim_dev) ++{ ++ struct mtf070 *lcd = dev_get_drvdata(&dsim_dev->dev); ++ ++ panel_dev_panel_init(panel); ++ msleep(120); ++ ++ lcd->power = FB_BLANK_UNBLANK; ++} ++ ++static void panel_dev_power_on(struct mipi_dsim_lcd_device *dsim_dev, int power) ++{ ++ struct panel_dev *panel_mtf070 = dev_get_drvdata(panel->dev); ++ ++ if (power == 1) { ++ /* power on */ ++ if (gpio_is_valid(panel_mtf070->pw.gpio)){ ++ printk(">>>>>panel power on\n"); ++ gpio_direction_output(panel_mtf070->pw.gpio, panel_mtf070->pw.active_level); ++ mdelay(150); ++ } ++ ++ //reset ++ if (gpio_is_valid(panel_mtf070->rst.gpio)) { ++ gpio_direction_output(panel_mtf070->rst.gpio, !panel_mtf070->rst.active_level); ++ mdelay(120); ++ gpio_direction_output(panel_mtf070->rst.gpio, panel_mtf070->rst.active_level); ++ mdelay(50); ++ gpio_direction_output(panel_mtf070->rst.gpio, !panel_mtf070->rst.active_level); ++ mdelay(120); ++ } ++ //open backlight ++ if (gpio_is_valid(panel_mtf070->bl.gpio)) ++ gpio_direction_output(panel_mtf070->bl.gpio, panel_mtf070->bl.active_level); ++ ++ } else { ++ if (gpio_is_valid(panel_mtf070->bl.gpio)) ++ gpio_direction_output(panel_mtf070->bl.gpio, !panel_mtf070->bl.active_level); ++ } ++} ++ ++static int panel_dev_probe(struct mipi_dsim_lcd_device *dsim_dev) ++{ ++ struct mtf070 *lcd; ++ ++ lcd = devm_kzalloc(&dsim_dev->dev, sizeof(struct mtf070), GFP_KERNEL); ++ if (IS_ERR_OR_NULL(lcd)) { ++ dev_err(&dsim_dev->dev, "Failed to allocate mtf070 structure!\n"); ++ return -ENOMEM; ++ } ++ ++ lcd->dsim_dev = dsim_dev; ++ lcd->dev = &dsim_dev->dev; ++ ++ lcd->ld = lcd_device_register("mtf070", lcd->dev, lcd, ++ &panel_lcd_ops); ++ if (IS_ERR(lcd->ld)) { ++ dev_err(lcd->dev, "Failed to register lcd ops."); ++ return PTR_ERR(lcd->ld); ++ } ++ ++ //panel_dev_power_on(dsi); ++ ++ dev_set_drvdata(&dsim_dev->dev, lcd); ++ ++ dev_dbg(lcd->dev, "Now probed mtf070 panel.\n"); ++ ++ panel->dsim_dev = dsim_dev; ++ ++ return 0; ++} ++ ++static int panel_dev_suspend(struct mipi_dsim_lcd_device *dsim_dev) ++{ ++ struct board_gpio *vdd_en = &panel->bl; ++ ++ gpio_direction_output(vdd_en->gpio, !vdd_en->active_level); ++ ++ return 0; ++} ++ ++static int panel_dev_resume(struct mipi_dsim_lcd_device *dsim_dev) ++{ ++ struct board_gpio *vdd_en = &panel->bl; ++ ++ gpio_direction_output(vdd_en->gpio, vdd_en->active_level); ++ ++ return 0; ++} ++ ++static struct mipi_dsim_lcd_driver panel_dev_dsim_ddi_driver = { ++ .name = "mtf070", ++ .id = -1, ++ ++ .power_on = panel_dev_power_on, ++ .set_sequence = panel_dev_set_sequence, ++ .probe = panel_dev_probe, ++ .suspend = panel_dev_suspend, ++ .resume = panel_dev_resume, ++ .ioctl = panel_dev_ioctl, ++}; ++ ++static struct mipi_dsim_lcd_device panel_dev_device = { ++ .name = "mtf070", ++ .id = 0, ++}; ++ ++/** ++ * @panel_probe ++ * ++ * 1. register to ingenicfb ++ * 2. register to lcd ++ * 3. register to backlight if possible ++ * ++ * @pdev ++ * ++ * @return - ++ */ ++static int panel_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ ++ panel = kzalloc(sizeof(struct panel_dev), GFP_KERNEL); ++ if (IS_ERR_OR_NULL(panel)) { ++ dev_err(&pdev->dev, "Failed to alloc memory!\n"); ++ return -ENOMEM; ++ } ++ panel->dev = &pdev->dev; ++ dev_set_drvdata(&pdev->dev, panel); ++ ++ ret = of_panel_parse(&pdev->dev); ++ if (ret < 0) ++ goto err_of_parse; ++ ++ /* register to mipi-dsi devicelist*/ ++ mipi_dsi_register_lcd_device(&panel_dev_device); ++ mipi_dsi_register_lcd_driver(&panel_dev_dsim_ddi_driver); ++ ++ ret = ingenicfb_register_panel(&lcd_panel); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "Failed to register lcd panel!\n"); ++ goto err_of_parse; ++ } ++ ++ return 0; ++err_of_parse: ++ kfree(panel); ++ return ret; ++} ++ ++static int panel_remove(struct platform_device *dev) ++{ ++ if (NULL != panel) ++ kfree(panel); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int panel_suspend(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ ++ panel_set_power(panel->lcd, FB_BLANK_POWERDOWN); ++ return 0; ++} ++ ++static int panel_resume(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ ++ panel_set_power(panel->lcd, FB_BLANK_UNBLANK); ++ return 0; ++} ++ ++static const struct dev_pm_ops panel_pm_ops = { ++ .suspend = panel_suspend, ++ .resume = panel_resume, ++}; ++#endif ++static const struct of_device_id panel_of_match[] = { ++ { .compatible = "ingenic,mtf070", }, ++ { .compatible = "mtf070", }, ++ {}, ++}; ++ ++static struct platform_driver panel_driver = { ++ .probe = panel_probe, ++ .remove = panel_remove, ++ .driver = { ++ .name = "mtf070", ++ .of_match_table = panel_of_match, ++#ifdef CONFIG_PM ++ .pm = &panel_pm_ops, ++#endif ++ }, ++}; ++ ++module_platform_driver(panel_driver); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-px070.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-px070.c.patch new file mode 100644 index 00000000..fc84d5d6 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-px070.c.patch @@ -0,0 +1,323 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v12/displays/panel-px070.c b/drivers/video/fbdev/ingenic/fb_v12/displays/panel-px070.c +--- a/drivers/video/fbdev/ingenic/fb_v12/displays/panel-px070.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v12/displays/panel-px070.c 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,319 @@ ++/* ++ * Copyright (C) 2016 Ingenic Semiconductor Inc. ++ * ++ * Author : Tania Xiang ++ * ++ * Mail : xiuhui.xiang@ingenic.com ++ * ++ * under the terms of the GNU General Public License version 2 as published by ++ * ++ * the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../ingenicfb.h" ++ ++#define LCD_WIDTH 1024 ++#define LCD_HEIGHT 608 ++ ++struct board_gpio { ++ short gpio; ++ short active_level; ++}; ++ ++struct panel_dev { ++ /* ingenic frame buffer */ ++ struct device *dev; ++ struct lcd_panel *panel; ++ ++ /* common lcd framework */ ++ struct lcd_device *lcd; ++ struct backlight_device *backlight; ++ int power; ++ ++ struct regulator *vcc; ++ struct board_gpio vdd_en; ++ struct board_gpio bl; ++ struct board_gpio rst; ++ struct board_gpio pwm; ++}; ++ ++static struct panel_dev *panel; ++ ++static void px070_power_on(struct lcd_panel *ppanel) ++{ ++ struct panel_dev *panel_px070 = dev_get_drvdata(panel->dev); ++ ++ gpio_direction_output(panel_px070->bl.gpio, panel_px070->bl.active_level); ++} ++ ++static void px070_power_off(struct lcd_panel *ppanel) ++{ ++ struct panel_dev *panel_px070 = dev_get_drvdata(panel->dev); ++ ++ gpio_direction_output(panel_px070->bl.gpio, !panel_px070->bl.active_level); ++ return; ++} ++ ++static struct lcd_panel_ops px070_ops = { ++ .enable = (void*)px070_power_on, ++ .disable = (void*)px070_power_off, ++}; ++ ++static struct fb_videomode jzfb_px070_videomode[] = { ++ [0] = { ++ .name = "1024x600", ++ .refresh = 30, ++ .xres = LCD_WIDTH, ++ .yres = LCD_HEIGHT, ++ .pixclock = KHZ2PICOS(51200), ++ .left_margin = 160, ++ .right_margin = 140, ++ .upper_margin = 4, ++ .lower_margin = 20, ++ .hsync_len = 20, ++ .vsync_len = 3, ++ .sync = ~FB_SYNC_HOR_HIGH_ACT & ~FB_SYNC_VERT_HIGH_ACT, ++ .vmode = FB_VMODE_NONINTERLACED, ++ /*.pixclock = KHZ2PICOS(33264),*/ ++ /*.left_margin = 32,*/ ++ /*.right_margin = 40,*/ ++ /*.upper_margin = 4,*/ ++ /*.lower_margin = 20,*/ ++ /*.hsync_len = 128,*/ ++ /*.vsync_len = 2,*/ ++ /*.sync = ~FB_SYNC_HOR_HIGH_ACT & ~FB_SYNC_VERT_HIGH_ACT,*/ ++ /*.vmode = FB_VMODE_NONINTERLACED,*/ ++ .flag = 0, ++ }, ++}; ++ ++static struct tft_config px070_cfg = { ++ .pix_clk_inv = 0, ++ .de_dl = 0, ++ .sync_dl = 0, ++ .color_even = TFT_LCD_COLOR_EVEN_BGR, ++ .color_odd = TFT_LCD_COLOR_ODD_BGR, ++ .mode = TFT_LCD_MODE_PARALLEL_666, ++}; ++ ++struct lcd_panel lcd_panel = { ++ .name = "px070", ++ .num_modes = ARRAY_SIZE(jzfb_px070_videomode), ++ .modes = jzfb_px070_videomode, ++ .lcd_type = LCD_TYPE_TFT, ++ .bpp = 24, ++ .width = LCD_WIDTH, ++ .height = LCD_HEIGHT, ++ ++ .tft_config = &px070_cfg, ++ ++ /*T40 RGB real line is 666, so, for RGB888, we discard low 2 bytes, config as follows:*/ ++ .dither_enable = 1, ++ .dither.dither_red = 1, ++ .dither.dither_green = 1, ++ .dither.dither_blue = 1, ++ ++ .ops = &px070_ops, ++}; ++ ++#if 0 ++static int panel_update_status(struct backlight_device *bd) ++{ ++ struct panel_dev *panel = dev_get_drvdata(&bd->dev); ++ int brightness = bd->props.brightness; ++ unsigned int i; ++ int pulse_num = MAX_BRIGHTNESS_STEP - brightness / CONVERT_FACTOR - 1; ++ ++ if (FB_BLANK_POWERDOWN == bd->pros.fb_blank) ++ return 0; ++ ++ if (bd->props.state & BL_CORE_SUSPEND) ++ brightness = 0; ++ ++ if (brightness) { ++ gpio_direction_output(panel->pwm.gpio, 0); ++ udelay(5000); ++ gpio_direction_output(panel->pwm.gpio, 1); ++ udelay(100); ++ ++ for (i = pulse_num; i > 0 ; i--) { ++ gpio_direction_output(panel->pwm.gpio, 0); ++ udelay(1); ++ gpio_direction_output(panel->pwm.gpio, 1); ++ udelay(3); ++ } ++ } else ++ gpio_direction_output(panel->pwm.gpio, 0); ++ ++ return 0; ++} ++ ++static struct backlight_ops panel_backlight_ops = { ++ .options = BL_CORE_SUSPENDRESUME, ++ .update_status = panel_update_status, ++}; ++#endif ++ ++#define RESET(n)\ ++ gpio_direction_output(panel->rst.gpio, n) ++#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL) ++static int panel_set_power(struct lcd_device *lcd, int power) ++{ ++ return 0; ++} ++ ++static int panel_get_power(struct lcd_device *lcd) ++{ ++ struct panel_dev *panel = lcd_get_data(lcd); ++ ++ return panel->power; ++} ++ ++/** ++ * @ panel_px070_lcd_ops, register to kernel common backlight/lcd.c frameworks. ++ */ ++static struct lcd_ops panel_lcd_ops = { ++ .early_set_power = panel_set_power, ++ .set_power = panel_set_power, ++ .get_power = panel_get_power, ++}; ++ ++static int of_panel_parse(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ struct device_node *np = dev->of_node; ++ enum of_gpio_flags flags; ++ int ret = 0; ++ ++ panel->bl.gpio = of_get_named_gpio_flags(np, "ingenic,bl-gpio", 0, &flags); ++ if (gpio_is_valid(panel->bl.gpio)) { ++ panel->bl.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ ret = devm_gpio_request(dev, panel->bl.gpio, "backlight"); ++ if (ret < 0) { ++ dev_err(dev, "Failed to request backlight pin!\n"); ++ return ret; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio backlight.gpio: %d\n", panel->bl.gpio); ++ } ++ ++ return 0; ++} ++ ++/** ++ * @panel_probe ++ * ++ * 1. register to ingenicfb. ++ * 2. register to lcd. ++ * 3. register to backlight if possible. ++ * ++ * @pdev ++ * ++ * @return - ++ * */ ++static int panel_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ struct backlight_properties props; //backlight properties ++ ++ memset(&props, 0, sizeof(props)); ++ panel = kzalloc(sizeof(struct panel_dev), GFP_KERNEL); ++ if (NULL == panel) { ++ dev_err(&pdev->dev, "Failed to alloc memory!"); ++ return -ENOMEM; ++ } ++ panel->dev = &pdev->dev; ++ dev_set_drvdata(&pdev->dev, panel); ++ ++ /* panel pinctrl parse */ ++ ret = of_panel_parse(&pdev->dev); ++ if (ret < 0) { ++ goto err_of_parse; ++ } ++ ++ panel->lcd = lcd_device_register("panel_lcd", &pdev->dev, panel, &panel_lcd_ops); ++ if (IS_ERR_OR_NULL(panel->lcd)) { ++ dev_err(&pdev->dev, "Error register lcd!"); ++ ret = -EINVAL; ++ goto err_of_parse; ++ } ++ ++ /* TODO: should this power status sync from uboot */ ++ panel->power = FB_BLANK_POWERDOWN; ++ panel_set_power(panel->lcd, FB_BLANK_UNBLANK); ++ ++ ret = ingenicfb_register_panel(&lcd_panel); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "Failed to register lcd panel!\n"); ++ goto err_lcd_register; ++ } ++ ++ return 0; ++ ++err_lcd_register: ++ lcd_device_unregister(panel->lcd); ++err_of_parse: ++ kfree(panel); ++ return ret; ++} ++ ++static int panel_remove(struct platform_device *pdev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(&pdev->dev); ++ ++ panel_set_power(panel->lcd, FB_BLANK_POWERDOWN); ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int panel_suspend(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ ++ panel_set_power(panel->lcd, FB_BLANK_POWERDOWN); ++ return 0; ++} ++ ++static int panel_resume(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ ++ panel_set_power(panel->lcd, FB_BLANK_UNBLANK); ++ return 0; ++} ++ ++static const struct dev_pm_ops panel_pm_ops = { ++ .suspend = panel_suspend, ++ .resume = panel_resume, ++}; ++#endif ++ ++static const struct of_device_id panel_of_match[] = { ++ { .compatible = "ingenic,px070", }, ++ { .compatible = "px070", }, ++ {}, ++}; ++ ++static struct platform_driver panel_driver = { ++ .probe = panel_probe, ++ .remove = panel_remove, ++ .driver = { ++ .name = "px070", ++ .of_match_table = panel_of_match, ++#ifdef CONFIG_PM ++ .pm = &panel_pm_ops, ++#endif ++ }, ++}; ++ ++module_platform_driver(panel_driver); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-st7701s.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-st7701s.c.patch new file mode 100644 index 00000000..bcdb999f --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-st7701s.c.patch @@ -0,0 +1,547 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v12/displays/panel-st7701s.c b/drivers/video/fbdev/ingenic/fb_v12/displays/panel-st7701s.c +--- a/drivers/video/fbdev/ingenic/fb_v12/displays/panel-st7701s.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v12/displays/panel-st7701s.c 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,543 @@ ++/* ++ * driver/video/fbdev/ingenic/x2000_v12/displays/panel-st7701s.c ++ * ++ * Copyright (C) 2016 Ingenic Semiconductor Inc. ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#include "../ingenicfb.h" ++#include "../jz_dsim.h" ++ ++static int test = 0; ++ ++struct board_gpio { ++ short gpio; ++ short active_level; ++}; ++ ++struct panel_dev { ++ /* ingenic frame buffer */ ++ struct device *dev; ++ struct lcd_panel *panel; ++ ++ /* common lcd framework */ ++ struct lcd_device *lcd; ++ struct backlight_device *backlight; ++ int power; ++ ++ struct regulator *vcc; ++ struct board_gpio vdd_en; ++ struct board_gpio rst; ++ struct board_gpio lcd_te; ++ struct board_gpio lcd_pwm; ++ ++ struct mipi_dsim_lcd_device *dsim_dev; ++}; ++ ++struct panel_dev *panel; ++ ++#define lcd_to_master(a) (a->dsim_dev->master) ++#define lcd_to_master_ops(a) ((lcd_to_master(a))->master_ops) ++ ++struct st7701s { ++ struct device *dev; ++ unsigned int power; ++ unsigned int id; ++ ++ struct lcd_device *ld; ++ struct backlight_device *bd; ++ ++ struct mipi_dsim_lcd_device *dsim_dev; ++ ++}; ++ ++static struct dsi_cmd_packet fitipower_st7701s_480_800_cmd_list1[] = ++{ ++ ++/**st7701s***/ ++ {0x39, 0x06, 0x00, {0xFF, 0x77, 0x01, 0x00, 0x00, 0x13}}, ++ {0x15, 0xEF, 0x08}, ++ {0x39, 0x06, 0x00, {0xFF, 0x77, 0x01, 0x00, 0x00, 0x10}}, ++ {0x39, 0x03, 0x00, {0xC0, 0x63, 0x00}}, ++ {0x39, 0x03, 0x00, {0xC1, 0x11, 0x0C}}, ++ {0x39, 0x03, 0x00, {0xC2, 0x07, 0x08}}, ++ {0x15, 0xCC, 0x10}, ++ {0x39, 0x11, 0x00, {0xB0, 0x00, 0x08, 0x0E, 0x0C, 0x10, 0x06, 0x01,0x07,0x07, 0x1E, 0x05, 0x13, 0x10, 0x2C, 0x34, 0x1E}}, ++ {0x39, 0x11, 0x00, {0xB1, 0x00, 0x0F, 0x16, 0x0D, 0x10, 0x05, 0x01,0x08,0x07, 0x1E, 0x04, 0x12, 0x11, 0x28, 0x30, 0x1E}}, ++ {0x39, 0x06, 0x00, {0xFF, 0x77, 0x01, 0x00, 0x00, 0x11}}, ++ {0x15, 0xB0, 0x72}, ++ {0x15, 0xB1, 0x8E}, ++ {0x15, 0xB2, 0x87}, ++ {0x15, 0xB3, 0x80}, ++ {0x15, 0xB5, 0x4C}, ++ {0x15, 0xB7, 0x85}, ++ {0x15, 0xB8, 0x20}, ++ {0x15, 0xC1, 0x78}, ++ {0x15, 0xC2, 0x78}, ++ {0x15, 0xD0, 0x88}, ++ {0x39, 0x07, 0x00, {0xE0, 0x00, 0x00, 0x02, 0x00, 0x00, 0x0C}}, ++ {0x39, 0x0C, 0x00, {0xE1, 0x06, 0x8C, 0x08, 0x8C, 0x07, 0x8C, 0x09, 0x8C, 0x00, 0x44, 0x44}}, ++ {0x39, 0x0D, 0x00, {0xE2, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x03, 0xA0, 0x00, 0x00, 0x03, 0xA0}}, ++ {0x39, 0x05, 0x00, {0xE3, 0x00, 0x00, 0x33, 0x33}}, ++ {0x39, 0x03, 0x00, {0xE4, 0x44, 0x44}}, ++ {0x39, 0x11, 0x00, {0xE5, 0x0D, 0x31, 0x0C, 0xA0, 0x0F, 0x33, 0x0C, 0xA0, 0x09, 0x2D, 0x0C, 0xA0, 0x0B, 0x2F, 0x0C, 0xA0}}, ++ {0x39, 0x05, 0x00, {0xE6, 0x00, 0x00, 0x33, 0x33}}, ++ {0x39, 0x03, 0x00, {0xE7, 0x44, 0x44}}, ++ {0x39, 0x11, 0x00, {0xE8, 0x0E, 0x32, 0x0C, 0xA0, 0x10, 0x34, 0x0C, 0xA0, 0x0A, 0x2E, 0x0C, 0xA0, 0x0C, 0x30, 0x0C, 0xA0}}, ++ {0x39, 0x07, 0x00, {0xEB, 0x00, 0x01, 0xE4, 0xE4, 0x44, 0x00}}, ++ {0x39, 0x11, 0x00, {0xED, 0xF3, 0xC1, 0xAB, 0x0F, 0x67, 0x45, 0xFF, 0xFF, 0xFF, 0xFF, 0x54, 0x76, 0xF0, 0xBA, 0x1C, 0x3F}}, ++ {0x39, 0x07, 0x00, {0xEF, 0x10, 0x0D, 0x04, 0x08, 0x3F, 0x1F}}, ++ {0x39, 0x06, 0x00, {0xFF, 0x77, 0x01, 0x00, 0x00, 0x13}}, ++ {0x39, 0x03, 0x00, {0xE8, 0x00, 0x0E}}, ++ /**/ ++ {0x05, 0x11, 0x00},//delay 120ms ++ /***/ ++// {0x39, 0x03, 0x00, {0xE8, 0x00, 0x0C}},//delay 20ms ++// {0x39, 0x03, 0x00, {0xE8, 0x00, 0x00}}, ++// {0x39, 0x06, 0x00, {0xFF, 0x77, 0x01, 0x00, 0x00,0x00}}, ++// {0x39, 0x03, 0x00, {0x29, 0x36, 0x00}}, ++/**st7701s***/ ++ ++}; ++ ++static struct dsi_cmd_packet fitipower_st7701s_480_800_cmd_list2[] = ++{ ++ {0x39, 0x03, 0x00, {0xE8, 0x00, 0x0C}},//delay 20ms ++}; ++ ++static struct dsi_cmd_packet fitipower_st7701s_480_800_cmd_list3[] = ++{ ++ {0x39, 0x03, 0x00, {0xE8, 0x00, 0x00}}, ++ {0x39, 0x06, 0x00, {0xFF, 0x77, 0x01, 0x00, 0x00,0x00}}, ++ {0x39, 0x03, 0x00, {0x29, 0x36, 0x00}}, ++}; ++ ++ ++static void panel_dev_sleep_in(struct panel_dev *lcd) ++{ ++ struct dsi_master_ops *ops = lcd_to_master_ops(lcd); ++ struct dsi_cmd_packet data_to_send = {0x05, 0x10, 0x00}; ++ ++ ops->cmd_write(lcd_to_master(lcd), data_to_send); ++} ++ ++static void panel_dev_sleep_out(struct panel_dev *lcd) ++{ ++ struct dsi_master_ops *ops = lcd_to_master_ops(lcd); ++ struct dsi_cmd_packet data_to_send = {0x05, 0x11, 0x00}; ++// struct dsi_cmd_packet data_to_send1 = {0x15, 0xc2, 0x20};//color bar test mode. ++// while (1) { ++ ops->cmd_write(lcd_to_master(lcd), data_to_send); ++// ops->cmd_write(lcd_to_master(lcd), data_to_send1); ++// } ++} ++ ++static void panel_dev_display_on(struct panel_dev *lcd) ++{ ++ struct dsi_master_ops *ops = lcd_to_master_ops(lcd);//color bar turn off 0x29 command. ++ struct dsi_cmd_packet data_to_send = {0x05, 0x29, 0x00}; ++ /* struct dsi_cmd_packet data_to_send1 = {0x15, 0x51, 250}; */ ++ ++ ops->cmd_write(lcd_to_master(lcd), data_to_send); ++ /* ops->cmd_write(lcd_to_master(lcd), data_to_send1); */ ++} ++ ++static void panel_dev_display_off(struct panel_dev *lcd) ++{ ++ struct dsi_master_ops *ops = lcd_to_master_ops(lcd); ++ struct dsi_cmd_packet data_to_send = {0x05, 0x28, 0x00}; ++ ++ ops->cmd_write(lcd_to_master(lcd), data_to_send); ++} ++ ++ ++static void panel_dev_panel_init(struct panel_dev *lcd) ++{ ++ int i; ++ struct dsi_master_ops *ops = lcd_to_master_ops(lcd); ++ struct dsi_device *dsi = lcd_to_master(lcd); ++ ++ for (i = 0; i < ARRAY_SIZE(fitipower_st7701s_480_800_cmd_list1); i++) ++ { ++ ops->cmd_write(dsi, fitipower_st7701s_480_800_cmd_list1[i]); ++ } ++ msleep(120); ++ for (i = 0; i < ARRAY_SIZE(fitipower_st7701s_480_800_cmd_list2); i++) ++ { ++ ops->cmd_write(dsi, fitipower_st7701s_480_800_cmd_list2[i]); ++ } ++ msleep(20); ++ for (i = 0; i < ARRAY_SIZE(fitipower_st7701s_480_800_cmd_list3); i++) ++ { ++ ops->cmd_write(dsi, fitipower_st7701s_480_800_cmd_list3[i]); ++ } ++} ++ ++static int panel_dev_ioctl(struct mipi_dsim_lcd_device *dsim_dev, int cmd) ++{ ++ return 0; ++} ++static void panel_dev_set_sequence(struct mipi_dsim_lcd_device *dsim_dev) ++{ ++ struct st7701s *lcd = dev_get_drvdata(&dsim_dev->dev); ++ ++ printk(">>>>>>>>>>>>>>>>>>>>%s %d\n",__func__,__LINE__); ++ if(test != 0) ++ return; ++ test++; ++ ++ panel_dev_panel_init(panel); ++ panel_dev_sleep_out(panel); ++ msleep(120); ++ panel_dev_display_on(panel); ++ msleep(5); ++ /* dump_dsi_reg(dsi); */ ++ lcd->power = FB_BLANK_UNBLANK; ++} ++static void panel_dev_power_on(struct mipi_dsim_lcd_device *dsim_dev, int power) ++{ ++ struct board_gpio *vdd_en = &panel->vdd_en; ++ struct board_gpio *rst = &panel->rst; ++ struct board_gpio *lcd_te = &panel->lcd_te; ++ printk(">>>>>>>>>>>>>>>>>>>>%s %d\n",__func__,__LINE__); ++ ++ if(test != 0) ++ return; ++ ++ gpio_direction_output(vdd_en->gpio, vdd_en->active_level); ++ ++ if (gpio_is_valid(lcd_te->gpio)) { ++ gpio_direction_input(lcd_te->gpio); ++ } ++ msleep(50); ++ gpio_direction_output(rst->gpio, 0); ++ msleep(50); ++ gpio_direction_output(rst->gpio, 1); ++ msleep(120); ++ ++ panel->power = power; ++} ++ ++static struct fb_videomode panel_modes = { ++ .name = "fitipower_st7701s-lcd", ++ .xres = 480, ++ .yres = 800, ++// .xres = 268, ++// .yres = 800, ++ ++// .refresh = 10, ++ .refresh = 60, ++ ++ .left_margin = 20,//hbp ++ .right_margin = 20,//hfp ++ .hsync_len = 20, //hsync ++ ++// .upper_margin = 16,//vbp ++ .upper_margin = 18,//vbp ++ .lower_margin = 16,//vfp ++ .vsync_len = 4, //vsync ++ ++ .sync = FB_SYNC_HOR_HIGH_ACT & FB_SYNC_VERT_HIGH_ACT, ++ .vmode = FB_VMODE_NONINTERLACED, ++ .flag = 0, ++}; ++ ++struct jzdsi_data jzdsi_pdata = { ++ .modes = &panel_modes, ++ .video_config.no_of_lanes = 2, ++ .video_config.virtual_channel = 0, ++ .video_config.color_coding = COLOR_CODE_24BIT, ++ .video_config.video_mode = VIDEO_BURST_WITH_SYNC_PULSES, ++ .video_config.receive_ack_packets = 0, /* enable receiving of ack packets */ ++ .video_config.is_18_loosely = 0, ++ .video_config.data_en_polarity = 1, ++ .video_config.byte_clock = 0, // driver will auto calculate byte_clock. ++ .video_config.byte_clock_coef = MIPI_PHY_BYTE_CLK_COEF_MUL3_DIV2, // byte_clock *3/2. ++ ++ .dsi_config.max_lanes = 2, ++ .dsi_config.max_hs_to_lp_cycles = 100, ++ .dsi_config.max_lp_to_hs_cycles = 40, ++// .dsi_config.max_hs_to_lp_cycles = 200, ++// .dsi_config.max_lp_to_hs_cycles = 80, ++ .dsi_config.max_bta_cycles = 4095, ++ .dsi_config.color_mode_polarity = 1, ++ .dsi_config.shut_down_polarity = 1, ++ .dsi_config.max_bps = 2750, ++// .max_bps = 650, // 650 Mbps ++ .bpp_info = 24, ++}; ++static struct tft_config kd050hdfia019_cfg = { ++ .pix_clk_inv = 0, ++ .de_dl = 0, ++ .sync_dl = 0, ++ .color_even = TFT_LCD_COLOR_EVEN_RGB, ++ .color_odd = TFT_LCD_COLOR_ODD_RGB, ++ .mode = TFT_LCD_MODE_PARALLEL_888, ++}; ++ ++ ++struct lcd_panel lcd_panel = { ++ .num_modes = 1, ++ .modes = &panel_modes, ++ .dsi_pdata = &jzdsi_pdata, ++ ++ .lcd_type = LCD_TYPE_TFT, ++ .tft_config = &kd050hdfia019_cfg, ++ .bpp = 24, ++// .width = 700, ++// .height = 1230, ++ .width = 68, ++ .height = 121, ++ .dither_enable = 0, ++ .dither.dither_red = 0, ++ .dither.dither_green = 0, ++ .dither.dither_blue = 0, ++ ++ ++}; ++ ++#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL) ++static int panel_set_power(struct lcd_device *lcd, int power) ++{ ++ return 0; ++} ++ ++static int panel_get_power(struct lcd_device *lcd) ++{ ++ struct panel_dev *panel = lcd_get_data(lcd); ++ ++ return panel->power; ++} ++ ++/** ++* @ pannel_st7701s_lcd_ops, register to kernel common backlight/lcd.c framworks. ++*/ ++static struct lcd_ops panel_lcd_ops = { ++ .early_set_power = panel_set_power, ++ .set_power = panel_set_power, ++ .get_power = panel_get_power, ++}; ++ ++static int of_panel_parse(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ struct device_node *np = dev->of_node; ++ enum of_gpio_flags flags; ++ int ret = 0; ++ ++ panel->vdd_en.gpio = of_get_named_gpio_flags(np, "ingenic,vdd-en-gpio", 0, &flags); ++ if(gpio_is_valid(panel->vdd_en.gpio)) { ++ panel->vdd_en.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ ret = gpio_request_one(panel->vdd_en.gpio, GPIOF_DIR_OUT, "vdd_en"); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request vdd_en pin!\n"); ++ return ret; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio vdd_en.gpio: %d\n", panel->vdd_en.gpio); ++ } ++ ++ panel->rst.gpio = of_get_named_gpio_flags(np, "ingenic,rst-gpio", 0, &flags); ++ if(gpio_is_valid(panel->rst.gpio)) { ++ panel->rst.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ ret = gpio_request_one(panel->rst.gpio, GPIOF_DIR_OUT, "rst"); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request rst pin!\n"); ++ goto err_request_rst; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio rst.gpio: %d\n", panel->rst.gpio); ++ } ++ ++ *(volatile unsigned int * )0xb0010188 = (0x1 << 27); //lcd_te high impedance config. ++ *(volatile unsigned int * )0xb0010198 = (0x1 << 27); ++ ++ panel->lcd_te.gpio = of_get_named_gpio_flags(np, "ingenic,lcd-te-gpio", 0, &flags); ++ if(gpio_is_valid(panel->lcd_te.gpio)) { ++ panel->lcd_te.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ ret = gpio_request_one(panel->lcd_te.gpio, GPIOF_DIR_IN, "lcd_te"); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request lcd_te pin!\n"); ++ goto err_request_lcd_te; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio lcd_te.gpio: %d\n", panel->lcd_te.gpio); ++ } ++/**lcd_bl_pwm pin as normal io pin config pull up***/ ++// panel->lcd_pwm.gpio = of_get_named_gpio_flags(np, "ingenic,lcd-pwm-gpio", 0, &flags); ++// if(gpio_is_valid(panel->lcd_pwm.gpio)) { ++// panel->lcd_pwm.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++// ret = gpio_direction_output(panel->lcd_pwm.gpio,1); ++// if(ret < 0) { ++// dev_err(dev, "Failed to request lcd-pwm pin!\n"); ++// return ret; ++// } ++// } else { ++// dev_warn(dev, "invalid gpio lcd-pwm.gpio: %d\n", panel->lcd_pwm.gpio); ++// } ++// ++ ++ return 0; ++err_request_lcd_te: ++ if(gpio_is_valid(panel->rst.gpio)) ++ gpio_free(panel->rst.gpio); ++err_request_rst: ++ if(gpio_is_valid(panel->vdd_en.gpio)) ++ gpio_free(panel->vdd_en.gpio); ++ return ret; ++} ++ ++static int panel_dev_probe(struct mipi_dsim_lcd_device *dsim_dev) ++{ ++ struct st7701s *lcd; ++ lcd = devm_kzalloc(&dsim_dev->dev, sizeof(struct st7701s), GFP_KERNEL); ++ if (!lcd) ++ { ++ dev_err(&dsim_dev->dev, "failed to allocate fitipower_st7701s structure.\n"); ++ return -ENOMEM; ++ } ++ ++ lcd->dsim_dev = dsim_dev; ++ lcd->dev = &dsim_dev->dev; ++ ++ lcd->ld = lcd_device_register("fitipower_st7701s", lcd->dev, lcd, ++ &panel_lcd_ops); ++ if (IS_ERR(lcd->ld)) ++ { ++ dev_err(lcd->dev, "failed to register lcd ops.\n"); ++ return PTR_ERR(lcd->ld); ++ } ++ ++ dev_set_drvdata(&dsim_dev->dev, lcd); ++ ++ ++ dev_dbg(lcd->dev, "probed fitipower_st7701s panel driver.\n"); ++ ++ ++ panel->dsim_dev = dsim_dev; ++ ++ ++ return 0; ++ ++} ++ ++static int panel_suspend(struct mipi_dsim_lcd_device *dsim_dev) ++{ ++ struct board_gpio *vdd_en = &panel->vdd_en; ++ ++ printk(">>>>>>>>>>>>>>>>>>>>%s %d\n",__func__,__LINE__); ++ panel_dev_display_off(panel); ++ panel_dev_sleep_in(panel); ++ gpio_direction_output(vdd_en->gpio, !vdd_en->active_level); ++ ++ return 0; ++} ++ ++static int panel_resume(struct mipi_dsim_lcd_device *dsim_dev) ++{ ++ struct board_gpio *vdd_en = &panel->vdd_en; ++ printk(">>>>>>>>>>>>>>>>>>>>%s %d\n",__func__,__LINE__); ++ ++ gpio_direction_output(vdd_en->gpio, vdd_en->active_level); ++ ++ return 0; ++} ++ ++static struct mipi_dsim_lcd_driver panel_dev_dsim_ddi_driver = { ++ .name = "fitipower_st7701s-lcd", ++ .id = -1, ++ ++ .power_on = panel_dev_power_on, ++ .set_sequence = panel_dev_set_sequence, ++ .probe = panel_dev_probe, ++// .suspend = panel_suspend, ++ .resume = panel_resume, ++}; ++ ++ ++struct mipi_dsim_lcd_device panel_dev_device={ ++ .name = "fitipower_st7701s-lcd", ++ .id = 0, ++}; ++ ++/** ++* @panel_probe ++* ++* 1. Register to ingenicfb. ++* 2. Register to lcd. ++* 3. Register to backlight if possible. ++* ++* @pdev ++* ++* @Return - ++*/ ++static int panel_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ ++ panel = kzalloc(sizeof(struct panel_dev), GFP_KERNEL); ++ if(panel == NULL) { ++ dev_err(&pdev->dev, "Faile to alloc memory!"); ++ return -ENOMEM; ++ } ++ panel->dev = &pdev->dev; ++ dev_set_drvdata(&pdev->dev, panel); ++ ++ ret = of_panel_parse(&pdev->dev); ++ if(ret < 0) { ++ goto err_of_parse; ++ } ++ ++ mipi_dsi_register_lcd_device(&panel_dev_device); ++ mipi_dsi_register_lcd_driver(&panel_dev_dsim_ddi_driver); ++ ++ ret = ingenicfb_register_panel(&lcd_panel); ++ if(ret < 0) { ++ dev_err(&pdev->dev, "Failed to register lcd panel!\n"); ++ goto err_of_parse; ++ } ++ ++ return 0; ++ ++err_of_parse: ++ kfree(panel); ++ return ret; ++} ++ ++static int panel_remove(struct platform_device *pdev) ++{ ++ return 0; ++} ++ ++static const struct of_device_id panel_of_match[] = { ++ { .compatible = "ingenic,st7701s", }, ++ {}, ++}; ++ ++static struct platform_driver panel_driver = { ++ .probe = panel_probe, ++ .remove = panel_remove, ++ .driver = { ++ .name = "st7701s", ++ .of_match_table = panel_of_match, ++ }, ++}; ++ ++module_platform_driver(panel_driver); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-st7703.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-st7703.c.patch new file mode 100644 index 00000000..59c899f0 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-st7703.c.patch @@ -0,0 +1,566 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v12/displays/panel-st7703.c b/drivers/video/fbdev/ingenic/fb_v12/displays/panel-st7703.c +--- a/drivers/video/fbdev/ingenic/fb_v12/displays/panel-st7703.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v12/displays/panel-st7703.c 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,562 @@ ++/* ++ * Copyright (c) 2012 Ingenic Semiconductor Co., Ltd. ++ * http://www.ingenic.com/ ++ * ++ * dorado board lcd setup routines. ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../ingenicfb.h" ++#include "../jz_dsim.h" ++#include "../jz_mipi_dsi/jz_mipi_dsih_hal.h" ++ ++#define ST7703_SUPPORT_LANE_4_FPS_60 0 ++#define ST7703_SUPPORT_LANE_4_FPS_30 1 ++#define ST7703_SUPPORT_LANE_4_FPS_20 2 ++#define ST7703_SUPPORT_LANE_2_FPS_30 3 ++ ++#define JZ_LCD_FPS_MAX ST7703_SUPPORT_LANE_4_FPS_60 ++ ++static struct dsi_cmd_packet st7703_cmd_list[] = { ++ {0x99, 50, 0x00, {0x00}}, //sleep 5ms ++ {0x39, 0x04, 0x00, { 0xB9, 0xF1, 0x12, 0x83, } }, ++#ifdef CONFIG_MIPI_4LANE ++ {0x39, 0x1C, 0x00, { 0xBA, 0x33, 0x81, 0x05, 0xF9, 0x0E, 0x0E, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x25, 0x00, 0x91, 0x0A, 0x00, 0x00, 0x02, 0x4F, 0xD1, 0x00, 0x00, 0x37, } }, ++#endif ++#ifdef CONFIG_MIPI_2LANE ++ {0x39, 0x1C, 0x00, { 0xBA, 0x31, 0x81, 0x05, 0xF9, 0x0E, 0x0E, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x25, 0x00, 0x91, 0x0A, 0x00, 0x00, 0x02, 0x4F, 0xD1, 0x00, 0x00, 0x37, } }, ++#endif ++ {0x39, 0x02, 0x00, { 0xB8, 0x26, } }, ++ {0x39, 0x04, 0x00, { 0xBF, 0x02, 0x11, 0x00, } }, ++ {0x39, 0x0B, 0x00, { 0xB3, 0x0C, 0x10, 0x0A, 0x50, 0x03, 0xFF, 0x00, 0x00, 0x00, 0x00, } }, ++ {0x39, 0x0A, 0x00, { 0xC0, 0x73, 0x73, 0x50, 0x50, 0x00, 0x00, 0x08, 0x70, 0x00, } }, ++ {0x39, 0x02, 0x00, { 0xBC, 0x46, } }, ++ {0x39, 0x02, 0x00, { 0xCC, 0x0B, } }, ++ {0x39, 0x02, 0x00, { 0xB4, 0x80, } }, ++ {0x39, 0x04, 0x00, { 0xB2, 0xC8, 0x12, 0x30,}}, ++ {0x39, 0x0F, 0x00, { 0xE3, 0x07, 0x07, 0x0B, 0x0B, 0x03, 0x0B, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0xC0, 0x10, }}, ++ {0x39, 0x0D, 0x00, { 0xC1, 0x25, 0x00, 0x32, 0x32, 0x77, 0xE1, 0xFF, 0xFF, 0xCC, 0xCC, 0x77,0x77, }}, ++ {0x39, 0x03, 0x00, { 0xB5, 0x0A, 0x0A, }}, ++ {0x39, 0x03, 0x00, { 0xB6, 0x50, 0x50,}}, ++ {0x29, 0x40, 0x00, { 0xE9, 0xC2,0x10,0x0F,0x00,0x00,0xB2,0xB8,0x12,0x31,0x23,0x48,0x8B, 0xB2, 0xB8, 0x47, 0x20, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xF8, 0x13, 0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }}, ++ {0x29, 0x3E, 0x00, { 0xEA, 0x00,0x1A,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x75,0x31,0x31,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x8F,0x64,0x20,0x20,0x88, 0x88,0x88,0x88,0x88,0x88,0x88,0x8F,0x23,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, }}, ++ {0x39, 0x23, 0x00, { 0xe0, 0x03, 0x13,0x17,0x26,0x2F,0x38,0x47,0x3A,0x07,0x0C,0x0E,0x12,0x14,0x12,0x14,0x12,0x1A,0x03,0x13, 0x17,0x26,0x2F,0x38,0x47,0x3A,0x07,0x0C,0x0E,0x12,0x14,0x12,0x14,0x12,0x1A, }}, ++ {0x15, 0x11, 0x00, { 0x00 }}, //Sleep out ++ {0x99, 250, 0x00, {0x00}}, //delay 250ms ++ {0x15, 0x29, 0x00, { 0x00}}, // Display On ++ {0x99, 50, 0x00, {0x00}}, //delay 50ms ++}; ++ ++struct board_gpio { ++ short gpio; ++ short active_level; ++}; ++ ++struct panel_dev { ++ /* ingenic frame buffer */ ++ struct device *dev; ++ struct lcd_panel *panel; ++ ++ /* common lcd framework */ ++ struct lcd_device *lcd; ++ struct backlight_device *backlight; ++ int power; ++ ++ struct regulator *vcc; ++ struct board_gpio vdd_en; ++ struct board_gpio bl; ++ struct board_gpio rst; ++ struct board_gpio oled; ++ struct board_gpio lcd_pwm; ++ ++ struct mipi_dsim_lcd_device *dsim_dev; ++}; ++ ++struct panel_dev *panel; ++ ++#define lcd_to_master(a) (a->dsim_dev->master) ++#define lcd_to_master_ops(a) ((lcd_to_master(a))->master_ops) ++ ++struct st7703 { ++ struct device *dev; ++ unsigned int power; ++ unsigned int id; ++ ++ struct lcd_device *ld; ++ struct backlight_device *bd; ++ ++ struct mipi_dsim_lcd_device *dsim_dev; ++}; ++ ++struct fb_videomode jzfb_st7703_videomode[] = { ++ //[0] 4lane 60fps ++ { ++ .name = "st7703", ++ .refresh = 60, ++ .xres = 720, ++ .yres = 1280, ++ .pixclock = KHZ2PICOS(56000), //60 ++ .left_margin = 40, ++ .right_margin = 40, ++ .upper_margin = 16, ++ .lower_margin = 14, ++ .hsync_len = 20, ++ .vsync_len = 4, ++ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, ++ .vmode = FB_VMODE_NONINTERLACED, ++ .flag = 0 ++ }, ++ ++ //[1] 4lane 30fps ++ { ++ .name = "st7703", ++ .refresh = 30, ++ .xres = 720, ++ .yres = 1280, ++ .pixclock = KHZ2PICOS(28000), ++ /* .left_margin = 40+20, */ ++ /* .right_margin = 40+80, */ ++ .left_margin = 40, ++ .right_margin = 40, ++ .upper_margin = 16, ++ .lower_margin = 14, ++ .hsync_len = 20, ++ .vsync_len = 4, ++ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, ++ .vmode = FB_VMODE_NONINTERLACED, ++ .flag = 0 ++ }, ++ //[2] 4lane 20fps ++ { ++ .name = "st7703", ++ .refresh = 20, ++ .xres = 720, ++ .yres = 1280, ++ .pixclock = KHZ2PICOS(18800), ++ .left_margin = 40, ++ .right_margin = 40, ++ .upper_margin = 16, ++ .lower_margin = 14, ++ .hsync_len = 20, ++ .vsync_len = 4, ++ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, ++ .vmode = FB_VMODE_NONINTERLACED, ++ .flag = 0 ++ }, ++ //[3] 2lane 30fps ++ { ++ .name = "st7703", ++ .refresh = 10, ++ .xres = 720, ++ .yres = 1280, ++ .pixclock = KHZ2PICOS(28000), ++ .left_margin = 40, ++ .right_margin = 40, ++ .upper_margin = 16, ++ .lower_margin = 14, ++ .hsync_len = 20, ++ .vsync_len = 4, ++ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, ++ .vmode = FB_VMODE_NONINTERLACED, ++ .flag = 0 ++ }, ++ ++}; ++ ++struct jzdsi_data jzdsi_pdata = { ++ .modes = &jzfb_st7703_videomode[JZ_LCD_FPS_MAX], ++#ifdef CONFIG_MIPI_2LANE ++ .video_config.no_of_lanes = 2, ++#endif ++#ifdef CONFIG_MIPI_4LANE ++ .video_config.no_of_lanes = 4, ++#endif ++ .video_config.virtual_channel = 0, ++ .video_config.color_coding = COLOR_CODE_24BIT, ++#if 0 ++ .video_config.video_mode = VIDEO_NON_BURST_WITH_SYNC_PULSES, ++#else ++ .video_config.video_mode = VIDEO_BURST_WITH_SYNC_PULSES, ++#endif ++ .video_config.receive_ack_packets = 0, /* enable receiving of ack packets */ ++ /*loosely: R0R1R2R3R4R5__G0G1G2G3G4G5G6__B0B1B2B3B4B5B6, ++ * not loosely: R0R1R2R3R4R5G0G1G2G3G4G5B0B1B2B3B4B5*/ ++ .video_config.is_18_loosely = 0, ++ .video_config.data_en_polarity = 1, ++ ++ .dsi_config.max_lanes = 4, ++ .dsi_config.max_hs_to_lp_cycles = 100, ++ .dsi_config.max_lp_to_hs_cycles = 40, ++ .dsi_config.max_bta_cycles = 4095, ++ .dsi_config.color_mode_polarity = 1, ++ .dsi_config.shut_down_polarity = 1, ++ .dsi_config.max_bps = 460, ++ // .max_bps = 650, // 650 Mbps ++ .bpp_info = 24, ++ ++}; ++ ++struct tft_config st7703_cfg = { ++ .pix_clk_inv = 0, ++ .de_dl = 0, ++ .sync_dl = 0, ++ .color_even = TFT_LCD_COLOR_EVEN_RGB, ++ .color_odd = TFT_LCD_COLOR_ODD_RGB, ++ .mode = TFT_LCD_MODE_PARALLEL_888, ++}; ++ ++struct lcd_panel lcd_panel = { ++ .num_modes = 1, ++ .modes = &jzfb_st7703_videomode[JZ_LCD_FPS_MAX], ++ .dsi_pdata = &jzdsi_pdata, ++ //.smart_config = &smart_cfg, ++ .tft_config = &st7703_cfg, ++ ++ .lcd_type = LCD_TYPE_TFT , ++ .width = 720, ++ .height = 1280, ++ //.bpp = 24, ++ ++ //.pixclk_falling_edge = 0, ++ //.data_enable_active_low = 0, ++ ++}; ++ ++/**************************************************************************************************/ ++#ifdef CONFIG_BACKLIGHT_PWM ++ ++static struct platform_pwm_backlight_data backlight_data = { ++ .pwm_id = 0, ++ .max_brightness = 255, ++ .dft_brightness = 100, ++ .pwm_period_ns = 30000, ++}; ++ ++struct platform_device backlight_device = { ++ .name = "pwm-backlight", ++ .dev = { ++ .platform_data = &backlight_data, ++ }, ++}; ++ ++#endif ++ ++#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL) ++static int panel_set_power(struct lcd_device *lcd, int power) ++{ ++ return 0; ++} ++ ++static int panel_get_power(struct lcd_device *lcd) ++{ ++ struct panel_dev *panel = lcd_get_data(lcd); ++ ++ return panel->power; ++} ++ ++static struct lcd_ops panel_lcd_ops = { ++ .early_set_power = panel_set_power, ++ .set_power = panel_set_power, ++ .get_power = panel_get_power, ++}; ++ ++static int of_panel_parse(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ struct device_node *np = dev->of_node; ++ enum of_gpio_flags flags; ++ int ret = 0; ++ ++ panel->bl.gpio = of_get_named_gpio_flags(np, "ingenic,bl-gpio", 0, &flags); ++ if (gpio_is_valid(panel->bl.gpio)) { ++ panel->bl.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ ret = devm_gpio_request(dev, panel->bl.gpio, "backlight"); ++ if (ret < 0) { ++ dev_err(dev, "Failed to request backlight pin!\n"); ++ return ret; ++ } ++ } else ++ dev_warn(dev, "invalid gpio backlight.gpio: %d\n", panel->bl.gpio); ++ ++ panel->rst.gpio = of_get_named_gpio_flags(np, "ingenic,rst-gpio", 0, &flags); ++ if (gpio_is_valid(panel->rst.gpio)) { ++ panel->rst.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ ret = devm_gpio_request(dev, panel->rst.gpio, "reset"); ++ if (ret < 0) { ++ dev_err(dev, "Failed to request rst pin!\n"); ++ return ret; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio rst.gpio: %d\n", panel->rst.gpio); ++ } ++ ++ return 0; ++} ++ ++static void panel_dev_panel_init(struct panel_dev *lcd) ++{ ++ int i, j; ++ struct dsi_master_ops *ops = lcd_to_master_ops(lcd); ++ struct dsi_device *dsi = lcd_to_master(lcd); ++ unsigned char buf[MAX_WORD_COUNT]; ++ unsigned char dsi_command_param[MAX_WORD_COUNT] = {0}; ++ ++ memset(buf, 0, sizeof(buf)); ++#if 0 ++ //set maximum transfer datasize ++ dsi_command_param[0] = 4; //lsb ++ dsi_command_param[1] = 0; //msb ++ mipi_dsih_gen_wr_packet(dsi, 0, 0x37, dsi_command_param, 2); ++ printk("set maximum return packet size ok now...\n"); ++ ++ //read display ID ++ mipi_dsih_gen_rd_packet(dsi, 0, 0x14, 0, 0x04, 4, buf); ++ printk("read buffer: \ncmd: 0x04, parameter:0x%x,0x%x,0x%x,0x%x\n", buf[0], buf[1], buf[2], buf[3]); ++ ++#endif ++ ++ for (i = 0; i < ARRAY_SIZE(st7703_cmd_list); i++) { ++ if (st7703_cmd_list[i].packet_type == 0x99) { ++ /* printk("\nsleep now. time: %dms\n", st7703_cmd_list[i].cmd0_or_wc_lsb+st7703_cmd_list[i].cmd1_or_wc_msb); */ ++ if (st7703_cmd_list[i].cmd0_or_wc_lsb+st7703_cmd_list[i].cmd1_or_wc_msb == 510) ++ msleep(600); ++ else ++ msleep(st7703_cmd_list[i].cmd0_or_wc_lsb+st7703_cmd_list[i].cmd1_or_wc_msb); ++ continue; ++ } ++ ++ ops->cmd_write(dsi, st7703_cmd_list[i]); ++ ++#if 0 ++ //short packet read here ++ if (st7703_cmd_list[i].packet_type == 0x15) { ++ //we read command here, see whether we send command configure ok. ++ mipi_dsih_gen_rd_packet(dsi, 0, 0x14, 0, st7703_cmd_list[i].cmd0_or_wc_lsb, 4, buf); ++ printk("read buffer: \ncmd: 0x%x, parameter:0x%x,0x%x,0x%x,0x%x\n", st7703_cmd_list[i].cmd0_or_wc_lsb, buf[0], buf[1], buf[2], buf[3]); ++ } ++ //long packet read here ++ if (st7703_cmd_list[i].packet_type == 0x39 || st7703_cmd_list[i].packet_type == 0x29) { ++ //we read command here, see whether we send command configure ok. ++ printk("return value : %d\t", mipi_dsih_gen_rd_packet(dsi, 0, 0x14, 0, st7703_cmd_list[i].cmd_data[0], 110, buf)); ++ printk("read buffer(data_type: 0x%x, cmd: 0x%x)\n", st7703_cmd_list[i].packet_type, st7703_cmd_list[i].cmd_data[0]); ++ for (j = 0 ; j < 110; j++) ++ printk("paramter list[%d]:0x%x\t", j, buf[j]); ++ printk("\n"); ++ } ++#endif ++ memset(buf, 0, sizeof(buf)); ++ } ++ ++} ++ ++static int panel_dev_ioctl(struct mipi_dsim_lcd_device *dsim_dev, int cmd) ++{ ++ return 0; ++} ++ ++static void panel_dev_set_sequence(struct mipi_dsim_lcd_device *dsim_dev) ++{ ++ struct st7703 *lcd = dev_get_drvdata(&dsim_dev->dev); ++ ++ panel_dev_panel_init(panel); ++ msleep(120); ++ ++ lcd->power = FB_BLANK_UNBLANK; ++} ++ ++static void panel_dev_power_on(struct mipi_dsim_lcd_device *dsim_dev, int power) ++{ ++ struct panel_dev *panel_st7703 = dev_get_drvdata(panel->dev); ++ ++ if (power == 1) { ++ //reset ++ if (gpio_is_valid(panel_st7703->rst.gpio)) { ++ gpio_direction_output(panel_st7703->rst.gpio, !panel_st7703->rst.active_level); ++ mdelay(120); ++ gpio_direction_output(panel_st7703->rst.gpio, panel_st7703->rst.active_level); ++ mdelay(50); ++ gpio_direction_output(panel_st7703->rst.gpio, !panel_st7703->rst.active_level); ++ mdelay(120); ++ } ++ //open backlight ++ if (gpio_is_valid(panel_st7703->bl.gpio)) ++ gpio_direction_output(panel_st7703->bl.gpio, panel_st7703->bl.active_level); ++ } else { ++ if (gpio_is_valid(panel_st7703->bl.gpio)) ++ gpio_direction_output(panel_st7703->bl.gpio, !panel_st7703->bl.active_level); ++ } ++} ++ ++static int panel_dev_probe(struct mipi_dsim_lcd_device *dsim_dev) ++{ ++ struct st7703 *lcd; ++ ++ lcd = devm_kzalloc(&dsim_dev->dev, sizeof(struct st7703), GFP_KERNEL); ++ if (IS_ERR_OR_NULL(lcd)) { ++ dev_err(&dsim_dev->dev, "Failed to allocate st7703 structure!\n"); ++ return -ENOMEM; ++ } ++ ++ lcd->dsim_dev = dsim_dev; ++ lcd->dev = &dsim_dev->dev; ++ ++ lcd->ld = lcd_device_register("st7703", lcd->dev, lcd, ++ &panel_lcd_ops); ++ if (IS_ERR(lcd->ld)) { ++ dev_err(lcd->dev, "Failed to register lcd ops."); ++ return PTR_ERR(lcd->ld); ++ } ++ ++ dev_set_drvdata(&dsim_dev->dev, lcd); ++ ++ dev_dbg(lcd->dev, "Now probed st7703 panel.\n"); ++ ++ panel->dsim_dev = dsim_dev; ++ ++ return 0; ++} ++ ++static int panel_dev_suspend(struct mipi_dsim_lcd_device *dsim_dev) ++{ ++ struct board_gpio *vdd_en = &panel->bl; ++ ++ gpio_direction_output(vdd_en->gpio, !vdd_en->active_level); ++ ++ return 0; ++} ++ ++static int panel_dev_resume(struct mipi_dsim_lcd_device *dsim_dev) ++{ ++ struct board_gpio *vdd_en = &panel->bl; ++ ++ gpio_direction_output(vdd_en->gpio, vdd_en->active_level); ++ ++ return 0; ++} ++ ++static struct mipi_dsim_lcd_driver panel_dev_dsim_ddi_driver = { ++ .name = "st7703", ++ .id = -1, ++ ++ .power_on = panel_dev_power_on, ++ .set_sequence = panel_dev_set_sequence, ++ .probe = panel_dev_probe, ++ .suspend = panel_dev_suspend, ++ .resume = panel_dev_resume, ++ .ioctl = panel_dev_ioctl, ++}; ++ ++static struct mipi_dsim_lcd_device panel_dev_device = { ++ .name = "st7703", ++ .id = 0, ++}; ++ ++/** ++ * @panel_probe ++ * ++ * 1. register to ingenicfb ++ * 2. register to lcd ++ * 3. register to backlight if possible ++ * ++ * @pdev ++ * ++ * @return - ++ */ ++static int panel_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ ++ panel = kzalloc(sizeof(struct panel_dev), GFP_KERNEL); ++ if (IS_ERR_OR_NULL(panel)) { ++ dev_err(&pdev->dev, "Failed to alloc memory!\n"); ++ return -ENOMEM; ++ } ++ panel->dev = &pdev->dev; ++ dev_set_drvdata(&pdev->dev, panel); ++ ++ ret = of_panel_parse(&pdev->dev); ++ if (ret < 0) ++ goto err_of_parse; ++ ++ /* register to mipi-dsi devicelist*/ ++ mipi_dsi_register_lcd_device(&panel_dev_device); ++ mipi_dsi_register_lcd_driver(&panel_dev_dsim_ddi_driver); ++ ++ ret = ingenicfb_register_panel(&lcd_panel); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "Failed to register lcd panel!\n"); ++ goto err_of_parse; ++ } ++ ++ return 0; ++err_of_parse: ++ kfree(panel); ++ return ret; ++} ++ ++static int panel_remove(struct platform_device *dev) ++{ ++ if (NULL != panel) ++ kfree(panel); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int panel_suspend(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ ++ panel_set_power(panel->lcd, FB_BLANK_POWERDOWN); ++ return 0; ++} ++ ++static int panel_resume(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ ++ panel_set_power(panel->lcd, FB_BLANK_UNBLANK); ++ return 0; ++} ++ ++static const struct dev_pm_ops panel_pm_ops = { ++ .suspend = panel_suspend, ++ .resume = panel_resume, ++}; ++#endif ++static const struct of_device_id panel_of_match[] = { ++ { .compatible = "ingenic,st7703", }, ++ { .compatible = "st7703", }, ++ {}, ++}; ++ ++static struct platform_driver panel_driver = { ++ .probe = panel_probe, ++ .remove = panel_remove, ++ .driver = { ++ .name = "st7703", ++ .of_match_table = panel_of_match, ++#ifdef CONFIG_PM ++ .pm = &panel_pm_ops, ++#endif ++ }, ++}; ++ ++module_platform_driver(panel_driver); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-st7789v_240_320.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-st7789v_240_320.c.patch new file mode 100644 index 00000000..9b58f38c --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-st7789v_240_320.c.patch @@ -0,0 +1,524 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v12/displays/panel-st7789v_240_320.c b/drivers/video/fbdev/ingenic/fb_v12/displays/panel-st7789v_240_320.c +--- a/drivers/video/fbdev/ingenic/fb_v12/displays/panel-st7789v_240_320.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v12/displays/panel-st7789v_240_320.c 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,520 @@ ++/* ++ * ingenic_bsp/chip-x2000/fpga/dpu/st7789v_240_320.c ++ * ++ * Copyright (C) 2016 Ingenic Semiconductor Inc. ++ * ++ * Author:clwang ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../ingenicfb.h" ++ ++struct board_gpio { ++ short gpio; ++ short active_level; ++}; ++ ++struct panel_dev { ++ /* ingenic frame buffer */ ++ struct device *dev; ++ struct lcd_panel *panel; ++ ++ /* common lcd framework */ ++ struct lcd_device *lcd; ++ struct backlight_device *backlight; ++ int power; ++ ++ struct regulator *vcc; ++ struct board_gpio cs; ++ struct board_gpio bl; ++ struct board_gpio rst; ++ struct board_gpio vdd_en; ++ struct board_gpio rd; ++ struct board_gpio pwm; ++}; ++ ++struct lcdc_gpio_struct { ++ unsigned long cs; ++ unsigned long rd; ++ unsigned long rst; ++ unsigned long func_pins; ++ enum gpio_port func_port; ++ enum gpio_function func_num; ++ unsigned long backlight; ++}; ++ ++static void st7789v240320_power_on(struct lcd_panel *panel) ++{ ++ ++} ++ ++static void st7789v240320_power_off(struct lcd_panel *panel) ++{ ++ ++} ++ ++struct lcd_panel_ops st7789v240320_ops = { ++ .enable = (void*)st7789v240320_power_on, ++ .disable = (void*)st7789v240320_power_off, ++}; ++ ++static struct smart_lcd_data_table st7789v240320_data_table[] = { ++ {SMART_CONFIG_CMD, 0x36}, ++ {SMART_CONFIG_PRM, 0x00}, ++ ++ {SMART_CONFIG_CMD, 0x3a}, //rgb format ++ {SMART_CONFIG_PRM, 0x05}, //5-6-5 ++ ++ {SMART_CONFIG_CMD, 0xb2}, //row ++ {SMART_CONFIG_PRM, 0x0c}, ++ {SMART_CONFIG_PRM, 0x0c}, ++ {SMART_CONFIG_PRM, 0x00}, ++ {SMART_CONFIG_PRM, 0x33}, ++ {SMART_CONFIG_PRM, 0x33}, ++ ++ {SMART_CONFIG_CMD, 0xb7}, ++ {SMART_CONFIG_PRM, 0x70}, ++ ++ {SMART_CONFIG_CMD, 0xbb}, ++ {SMART_CONFIG_PRM, 0x21}, ++ ++ {SMART_CONFIG_CMD, 0xc0}, ++ {SMART_CONFIG_PRM, 0x2c}, ++ ++ {SMART_CONFIG_CMD, 0xc2}, ++ {SMART_CONFIG_PRM, 0x01}, ++ ++ {SMART_CONFIG_CMD, 0xc3}, ++ {SMART_CONFIG_PRM, 0x0b}, ++ ++ {SMART_CONFIG_CMD, 0xc4}, ++ {SMART_CONFIG_PRM, 0x27}, ++ ++ {SMART_CONFIG_CMD, 0xc6}, ++ {SMART_CONFIG_PRM, 0x0f}, ++ ++ {SMART_CONFIG_CMD, 0xd0}, ++ {SMART_CONFIG_PRM, 0xa4}, ++ {SMART_CONFIG_PRM, 0xa1}, ++ ++ {SMART_CONFIG_CMD, 0xe0}, ++ {SMART_CONFIG_PRM, 0xd0}, ++ {SMART_CONFIG_PRM, 0x06}, ++ {SMART_CONFIG_PRM, 0x0b}, ++ {SMART_CONFIG_PRM, 0x09}, ++ {SMART_CONFIG_PRM, 0x08}, ++ {SMART_CONFIG_PRM, 0x30}, ++ {SMART_CONFIG_PRM, 0x30}, ++ {SMART_CONFIG_PRM, 0x5b}, ++ {SMART_CONFIG_PRM, 0x4b}, ++ {SMART_CONFIG_PRM, 0x18}, ++ {SMART_CONFIG_PRM, 0x14}, ++ {SMART_CONFIG_PRM, 0x14}, ++ {SMART_CONFIG_PRM, 0x2c}, ++ {SMART_CONFIG_PRM, 0x32}, ++ ++ {SMART_CONFIG_CMD, 0xe1}, ++ {SMART_CONFIG_PRM, 0xd0}, ++ {SMART_CONFIG_PRM, 0x05}, ++ {SMART_CONFIG_PRM, 0x0a}, ++ {SMART_CONFIG_PRM, 0x0a}, ++ {SMART_CONFIG_PRM, 0x07}, ++ {SMART_CONFIG_PRM, 0x28}, ++ {SMART_CONFIG_PRM, 0x32}, ++ {SMART_CONFIG_PRM, 0x2c}, ++ {SMART_CONFIG_PRM, 0x49}, ++ {SMART_CONFIG_PRM, 0x18}, ++ {SMART_CONFIG_PRM, 0x13}, ++ {SMART_CONFIG_PRM, 0x14}, ++ {SMART_CONFIG_PRM, 0x2c}, ++ {SMART_CONFIG_PRM, 0x33}, ++ ++ {SMART_CONFIG_CMD, 0x21}, ++ {SMART_CONFIG_CMD, 0x2a}, ++ {SMART_CONFIG_PRM, 0x00}, ++ {SMART_CONFIG_PRM, 0x00}, ++ {SMART_CONFIG_PRM, 0x00}, ++ {SMART_CONFIG_PRM, 0xef}, ++ {SMART_CONFIG_CMD, 0x2b}, ++ {SMART_CONFIG_PRM, 0x00}, ++ {SMART_CONFIG_PRM, 0x00}, ++ {SMART_CONFIG_PRM, 0x01}, ++ {SMART_CONFIG_PRM, 0x3f}, ++ ++ {SMART_CONFIG_CMD, 0x11}, ++ {SMART_CONFIG_UDELAY, 120000}, ++ ++ {SMART_CONFIG_CMD, 0x29}, ++ {SMART_CONFIG_CMD, 0x2c}, ++}; ++ ++struct fb_videomode jzfb_st7789v_240_320_videomode[] = { ++ [0] = { ++ .name = "240x320", ++ .refresh = 60, ++ .xres = 240, ++ .yres = 320, ++ .pixclock = KHZ2PICOS(30000), ++ .left_margin = 0, ++ .right_margin = 0, ++ .upper_margin = 0, ++ .lower_margin = 0, ++ .hsync_len = 0, ++ .vsync_len = 0, ++ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, ++ .vmode = FB_VMODE_NONINTERLACED, ++ .flag = 0, ++ }, ++}; ++ ++struct smart_config st7789v_240_320_cfg = { ++ .te_anti_jit = 1, ++ .te_md = 0, ++ //.te_switch = 1, ++ .te_switch = 0, ++ .dc_md = 0, ++ .wr_md = 1, ++ .te_dp = 1, ++ .smart_type = SMART_LCD_TYPE_8080, ++ .pix_fmt = SMART_LCD_FORMAT_565, ++ .dwidth = SMART_LCD_DWIDTH_8_BIT, ++ .cwidth = SMART_LCD_CWIDTH_8_BIT, ++ .bus_width = 8, ++ ++ .write_gram_cmd = 0x2c, ++ .data_table = st7789v240320_data_table, ++ .length_data_table = ARRAY_SIZE(st7789v240320_data_table), ++}; ++ ++struct lcd_panel lcd_panel = { ++ .num_modes = ARRAY_SIZE(jzfb_st7789v_240_320_videomode), ++ .modes = jzfb_st7789v_240_320_videomode, ++ .lcd_type = LCD_TYPE_SLCD, ++ .bpp = 16, ++ .width = 240, ++ .height = 320, ++ ++ .smart_config = &st7789v_240_320_cfg, ++ ++ .dither_enable = 0, ++ .dither.dither_red = 0, ++ .dither.dither_green = 0, ++ .dither.dither_blue = 0, ++ .ops = &st7789v240320_ops, ++}; ++ ++/* panel support 16 brightness step, really? */ ++#define MAX_BRIGHTNESS_STEP 16 ++/* System support 256 brightness step, really? */ ++#define CONVERT_FACTOR (256/MAX_BRIGHTNESS_STEP) ++ ++static int panel_update_status(struct backlight_device *bd) ++{ ++#if 0 ++ struct panel_dev *panel = dev_get_drvdata(&bd->dev); ++ int brightness = bd->props.brightness; ++ unsigned int i; ++ int pulse_num = MAX_BRIGHTNESS_STEP - brightness / CONVERT_FACTOR - 1;; ++ ++ if (bd->props.fb_blank == FB_BLANK_POWERDOWN) ++ return 0; ++ ++ if (bd->props.state & BL_CORE_SUSPENDED) ++ brightness = 0; ++ ++ if (brightness) { ++ gpio_direction_output(panel->pwm.gpio, 0); ++ udelay(5000); ++ gpio_direction_output(panel->pwm.gpio, 1); ++ udelay(100); ++ ++ for (i = pulse_num ; i > 0 ; i--) { ++ gpio_direction_output(panel->pwm.gpio, 0); ++ udelay(1); ++ gpio_direction_output(panel->pwm.gpio, 1); ++ udelay(3); ++ } ++ } else ++ gpio_direction_output(panel->pwm.gpio, 0); ++#endif ++ return 0; ++} ++ ++static struct backlight_ops panel_backlight_ops = { ++ .options = BL_CORE_SUSPENDRESUME, ++ .update_status = panel_update_status, ++}; ++ ++static void panel_power_reset(struct board_gpio *rst) ++{ ++ gpio_direction_output(rst->gpio, 1); ++ mdelay(1); ++ gpio_direction_output(rst->gpio, 0); ++ mdelay(10); ++ gpio_direction_output(rst->gpio, 1); ++ mdelay(120); ++} ++ ++ ++#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL) ++static int panel_set_power(struct lcd_device *lcd, int power) ++{ ++ struct panel_dev *panel = lcd_get_data(lcd); ++ struct board_gpio *cs = &panel->cs; ++ struct board_gpio *rst = &panel->rst; ++ struct board_gpio *bl = &panel->bl; ++ ++ if (POWER_IS_ON(power) && !POWER_IS_ON(panel->power)) { ++ gpio_direction_output(bl->gpio, bl->active_level); ++ gpio_direction_output(cs->gpio, 1); ++ mdelay(5); ++ panel_power_reset(rst); ++ gpio_direction_output(cs->gpio, 0); ++ } ++ ++ if (!POWER_IS_ON(power) && POWER_IS_ON(panel->power)) { ++ gpio_direction_output(cs->gpio, 0); ++ gpio_direction_output(rst->gpio, 0); ++ gpio_direction_output(bl->gpio, !bl->active_level); ++ } ++ ++ panel->power = power; ++ return 0; ++} ++ ++static int panel_get_power(struct lcd_device *lcd) ++{ ++ struct panel_dev *panel = lcd_get_data(lcd); ++ ++ return panel->power; ++} ++ ++static struct lcd_ops panel_lcd_ops = { ++ .early_set_power = panel_set_power, ++ .set_power = panel_set_power, ++ .get_power = panel_get_power, ++}; ++ ++static int of_panel_parse(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ struct device_node *np = dev->of_node; ++ enum of_gpio_flags flags; ++ int ret = 0; ++ ++ panel->cs.gpio = of_get_named_gpio_flags(np, "ingenic,cs-gpio", 0, &flags); ++ if (gpio_is_valid(panel->cs.gpio)) { ++ panel->cs.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ ret = gpio_request_one(panel->cs.gpio, GPIOF_DIR_OUT, "cs"); ++ if (ret < 0) { ++ dev_err(dev, "Failed to request cs pin!\n"); ++ return ret; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio cs.gpio: %d\n", panel->cs.gpio); ++ } ++ ++ panel->rst.gpio = of_get_named_gpio_flags(np, "ingenic,rst-gpio", 0, &flags); ++ if (gpio_is_valid(panel->rst.gpio)) { ++ panel->rst.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ ret = gpio_request_one(panel->rst.gpio, GPIOF_DIR_OUT, "rst"); ++ if (ret < 0) { ++ dev_err(dev, "Failed to request rst pin!\n"); ++ goto err_request_rst; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio rst.gpio: %d\n", panel->rst.gpio); ++ } ++ ++#if 0 ++ panel->rd.gpio = of_get_named_gpio_flags(np, "ingenic,rd-gpio", 0, &flags); ++ if (gpio_is_valid(panel->rd.gpio)) { ++ panel->rd.active_level = (flags &OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ ret = gpio_request_one(panel->rd.gpio, GPIOF_DIR_OUT, "rd"); ++ if (ret < 0) { ++ dev_err(dev, "Failed to request rd pin!\n"); ++ goto err_request_rd; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio rd.gpio: %d\n", panel->rd.gpio); ++ } ++#endif ++ panel->bl.gpio = of_get_named_gpio_flags(np, "ingenic,bl-gpio", 0, &flags); ++ if (gpio_is_valid(panel->bl.gpio)) { ++ panel->bl.active_level = (flags &OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ ret = gpio_request_one(panel->bl.gpio, GPIOF_DIR_OUT, "backlight"); ++ if (ret < 0) { ++ dev_err(dev, "Failed to request backlight pin!\n"); ++ goto err_request_rd; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio bl.gpio: %d\n", panel->bl.gpio); ++ } ++#if 0 ++ panel->vdd_en.gpio = of_get_named_gpio_flags(np, "ingenic,vdd-en-gpio", 0, &flags); ++ if (gpio_is_valid(panel->vdd_en.gpio)) { ++ panel->vdd_en.active_level = OF_GPIO_ACTIVE_LOW ? 0 : 1; ++ ret = gpio_request_one(panel->vdd_en.gpio, GPIOF_DIR_OUT, "vdd_en"); ++ if (ret < 0) { ++ dev_err(dev, "Failed to request vdd_en pin!\n"); ++ goto err_request_rst; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio vdd_en.gpio: %d\n", panel->vdd_en.gpio); ++ } ++ ++ panel->pwm.gpio = of_get_named_gpio_flags(np, "ingenic,pwm-gpio", 0, &flags); ++ if (gpio_is_valid(panel->pwm.gpio)) { ++ panel->pwm.active_level = OF_GPIO_ACTIVE_LOW ? 0 : 1; ++ ret = gpio_request_one(panel->pwm.gpio, GPIOF_DIR_OUT, "pwm"); ++ if (ret < 0) { ++ dev_err(dev, "Failed to request pwm pin!\n"); ++ goto err_request_rst; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio pwm.gpio: %d\n", panel->pwm.gpio); ++ } ++#endif ++ ++ return 0; ++err_request_rd: ++ gpio_free(panel->rst.gpio); ++err_request_rst: ++ gpio_free(panel->cs.gpio); ++ return ret; ++} ++ ++/** ++ * @panel_probe ++ * ++ * 1. register to ingenicfb. ++ * 2. register to lcd. ++ * 3. register to backlight if possible ++ * ++ * @pdev ++ * ++ * @return - ++ */ ++static int panel_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ struct panel_dev *panel; ++ struct backlight_properties props; ++ ++ memset(&props, 0, sizeof(props)); ++ panel = kzalloc(sizeof(struct panel_dev), GFP_KERNEL); ++ if (IS_ERR_OR_NULL(panel)) { ++ dev_err(&pdev->dev, "Failed to alloc memory!\n"); ++ return -ENOMEM; ++ } ++ panel->dev = &pdev->dev; ++ dev_set_drvdata(&pdev->dev, panel); ++ ++ ret = of_panel_parse(&pdev->dev); ++ if (ret < 0) ++ goto err_of_parse; ++ ++ panel->lcd = lcd_device_register("panel_lcd", &pdev->dev, panel, &panel_lcd_ops); ++ if (IS_ERR_OR_NULL(panel->lcd)) { ++ dev_err(&pdev->dev, "Error register st7789v240320 lcd\n"); ++ ret = -EINVAL; ++ goto err_of_parse; ++ } ++ ++ /* TODO: should this power status sync from uboot */ ++ panel->power = FB_BLANK_POWERDOWN; ++ panel_set_power(panel->lcd, FB_BLANK_UNBLANK); ++ ++ props.type = BACKLIGHT_RAW; ++ props.max_brightness = 255; ++ panel->backlight = backlight_device_register("pwm-backlight.0", ++ &pdev->dev, panel, ++ &panel_backlight_ops, ++ &props); ++ if (IS_ERR_OR_NULL(panel->backlight)) { ++ dev_err(panel->dev, "Failed to register 'pwm-backlight.0'\n"); ++ goto err_lcd_register; ++ } ++ panel->backlight->props.brightness = props.max_brightness; ++ backlight_update_status(panel->backlight); ++ ++ ret = ingenicfb_register_panel(&lcd_panel); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "Failed to register lcd panel!\n"); ++ goto err_lcd_register; ++ } ++ ++ return 0; ++ ++err_lcd_register: ++ lcd_device_unregister(panel->lcd); ++err_of_parse: ++ kfree(panel); ++ return ret; ++} ++ ++static int panel_remove(struct platform_device *pdev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(&pdev->dev); ++ ++ panel_set_power(panel->lcd, FB_BLANK_POWERDOWN); ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int panel_suspend(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ ++ panel_set_power(panel->lcd, FB_BLANK_POWERDOWN); ++ return 0; ++} ++ ++static int panel_resume(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ ++ panel_set_power(panel->lcd, FB_BLANK_UNBLANK); ++ return 0; ++} ++ ++static const struct dev_pm_ops panel_pm_ops = { ++ .suspend = panel_suspend, ++ .resume = panel_resume, ++}; ++#endif ++ ++static const struct of_device_id panel_of_match[] = { ++ { .compatible = "ingenic,st7789v240320", }, ++ { .compatible = "st7789v_240_320", }, ++ {}, ++}; ++ ++static struct platform_driver panel_driver = { ++ .probe = panel_probe, ++ .remove = panel_remove, ++ .driver = { ++ .name = "st7789v_240_320", ++ .of_match_table = panel_of_match, ++#ifdef CONFIG_PM ++ .pm = &panel_pm_ops, ++#endif ++ }, ++}; ++ ++module_platform_driver(panel_driver); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-tl040hds01ct.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-tl040hds01ct.c.patch new file mode 100644 index 00000000..013757b4 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-tl040hds01ct.c.patch @@ -0,0 +1,377 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v12/displays/panel-tl040hds01ct.c b/drivers/video/fbdev/ingenic/fb_v12/displays/panel-tl040hds01ct.c +--- a/drivers/video/fbdev/ingenic/fb_v12/displays/panel-tl040hds01ct.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v12/displays/panel-tl040hds01ct.c 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,373 @@ ++/* ++ * driver/video/fbdev/ingenic/x2000_v12/displays/panel-tl040hds01ct.c ++ * ++ * Copyright (C) 2020 Ingenic Semiconductor Inc. ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../ingenicfb.h" ++ ++struct board_gpio { ++ short gpio; ++ short active_level; ++}; ++ ++struct panel_dev { ++ /* ingenic frame buffer */ ++ struct device *dev; ++ struct lcd_panel *panel; ++ ++ /* common lcd framework */ ++ struct lcd_device *lcd; ++ struct backlight_device *backlight; ++ int power; ++ ++ struct regulator *vcc; ++ struct board_gpio vdd_en; ++ struct board_gpio rst; ++ struct board_gpio pwm; ++}; ++ ++static struct panel_dev *panel; ++ ++#define RESET(n)\ ++ gpio_direction_output(panel->rst.gpio, n) ++ ++static void panel_enable(struct lcd_panel *panel) ++{ ++} ++ ++static void panel_disable(struct lcd_panel *panel) ++{ ++} ++ ++static struct lcd_panel_ops panel_ops = { ++ .enable = (void*)panel_enable, ++ .disable = (void*)panel_disable, ++}; ++ ++static struct fb_videomode panel_modes[] = { ++ [0] = { ++ .name = "720x720", ++ .refresh = 60, ++ .xres = 720, ++ .yres = 720, ++ /* .pixclock = KHZ2PICOS(35000), */ ++ .left_margin = 10, ++ .right_margin = 20, ++ .upper_margin = 10, ++ .lower_margin = 10, ++ ++ .hsync_len = 20, ++ .vsync_len = 10, ++ .sync = ~FB_SYNC_HOR_HIGH_ACT & ~FB_SYNC_VERT_HIGH_ACT, ++ .vmode = FB_VMODE_NONINTERLACED, ++ .flag = 0, ++ }, ++}; ++ ++static struct tft_config tl040hds01ct_cfg = { ++ .pix_clk_inv = 0, ++ .de_dl = 0, ++ .sync_dl = 0, ++ .color_even = TFT_LCD_COLOR_EVEN_RGB, ++ .color_odd = TFT_LCD_COLOR_ODD_RGB, ++ .mode = TFT_LCD_MODE_PARALLEL_666, ++}; ++ ++struct lcd_panel lcd_panel = { ++ .name = "tl040hds01ct", ++ .num_modes = ARRAY_SIZE(panel_modes), ++ .modes = panel_modes, ++ .bpp = 24, ++ .width = 72, ++ .height = 72, ++ ++ .lcd_type = LCD_TYPE_TFT, ++ ++ .tft_config = &tl040hds01ct_cfg, ++ ++ .dither_enable = 1, ++ .dither.dither_red = 1, ++ .dither.dither_green = 1, ++ .dither.dither_blue = 1, ++ ++ .ops = &panel_ops, ++}; ++ ++#if 0 ++static int panel_update_status(struct backlight_device *bd) ++{ ++ struct panel_dev *panel = dev_get_drvdata(&bd->dev); ++ int brightness = bd->props.brightness; ++ unsigned int i; ++ int pulse_num = MAX_BRIGHTNESS_STEP - brightness / CONVERT_FACTOR - 1; ++ ++ if (bd->props.fb_blank == FB_BLANK_POWERDOWN) { ++ return 0; ++ } ++ ++ if (bd->props.state & BL_CORE_SUSPENDED) ++ brightness = 0; ++ ++ if (brightness) { ++ gpio_direction_output(panel->pwm.gpio,0); ++ udelay(5000); ++ gpio_direction_output(panel->pwm.gpio,1); ++ udelay(100); ++ ++ for (i = pulse_num; i > 0; i--) { ++ gpio_direction_output(panel->pwm.gpio,0); ++ udelay(1); ++ gpio_direction_output(panel->pwm.gpio,1); ++ udelay(3); ++ } ++ } else ++ gpio_direction_output(panel->pwm.gpio, 0); ++ ++ return 0; ++} ++ ++static struct backlight_ops panel_backlight_ops = { ++ .options = BL_CORE_SUSPENDRESUME, ++ .update_status = panel_update_status, ++}; ++#endif ++ ++#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL) ++static int panel_set_power(struct lcd_device *lcd, int power) ++{ ++ struct panel_dev *panel = lcd_get_data(lcd); ++ struct board_gpio *vdd_en = &panel->vdd_en; ++ struct board_gpio *rst = &panel->rst; ++ ++ if(POWER_IS_ON(power) && !POWER_IS_ON(panel->power)) { ++ /* *(unsigned int*)(0xb00101a4) = 0xf000000; */ ++ /* *(unsigned int*)(0xb00101b8) = 0xf000000; */ ++ /* *(unsigned int*)(0xb00101c4) = 0xf000000; */ ++ ++ gpio_direction_output(vdd_en->gpio, 0); ++ ++ RESET(1); ++ udelay(50000); ++ RESET(0); ++ udelay(120000); ++ RESET(1); ++ udelay(20000); ++ ++ } ++ if(!POWER_IS_ON(power) && POWER_IS_ON(panel->power)) { ++ gpio_direction_output(vdd_en->gpio, 1); ++ } ++ ++ panel->power = power; ++ return 0; ++} ++ ++static int panel_get_power(struct lcd_device *lcd) ++{ ++ struct panel_dev *panel = lcd_get_data(lcd); ++ ++ return panel->power; ++} ++ ++/** ++* @ pannel_tl040hds01ct_lcd_ops, register to kernel common backlight/lcd.c framworks. ++*/ ++static struct lcd_ops panel_lcd_ops = { ++ .early_set_power = panel_set_power, ++ .set_power = panel_set_power, ++ .get_power = panel_get_power, ++}; ++ ++static int of_panel_parse(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ struct device_node *np = dev->of_node; ++ enum of_gpio_flags flags; ++ int ret = 0; ++ ++ panel->vdd_en.gpio = of_get_named_gpio_flags(np, "ingenic,vdd-en-gpio", 0, &flags); ++ if(gpio_is_valid(panel->vdd_en.gpio)) { ++ panel->vdd_en.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ ret = gpio_request_one(panel->vdd_en.gpio, GPIOF_DIR_OUT, "vdd_en"); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request vdd_en pin!\n"); ++ return ret; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio vdd_en.gpio: %d\n", panel->vdd_en.gpio); ++ } ++ ++ panel->rst.gpio = of_get_named_gpio_flags(np, "ingenic,rst-gpio", 0, &flags); ++ if(gpio_is_valid(panel->rst.gpio)) { ++ panel->rst.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ ret = gpio_request_one(panel->rst.gpio, GPIOF_DIR_OUT, "rst"); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request rst pin!\n"); ++ goto err_request_rst; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio rst.gpio: %d\n", panel->rst.gpio); ++ } ++ ++#if 0 ++ panel->pwm.gpio = of_get_named_gpio_flags(np, "ingenic,lcd-pwm-gpio", 0, &flags); ++ if(gpio_is_valid(panel->pwm.gpio)) { ++ panel->pwm.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ ret = gpio_request_one(panel->pwm.gpio, GPIOF_DIR_OUT, "pwm"); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request pwm pin!\n"); ++ goto err_request_pwm; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio pwm.gpio: %d\n", panel->pwm.gpio); ++ } ++#endif ++ ++ return 0; ++err_request_sdo: ++ if(gpio_is_valid(panel->pwm.gpio)) ++ gpio_free(panel->pwm.gpio); ++err_request_pwm: ++ if(gpio_is_valid(panel->rst.gpio)) ++ gpio_free(panel->rst.gpio); ++err_request_rst: ++ if(gpio_is_valid(panel->vdd_en.gpio)) ++ gpio_free(panel->vdd_en.gpio); ++ return ret; ++} ++/** ++* @panel_probe ++* ++* 1. Register to ingenicfb. ++* 2. Register to lcd. ++* 3. Register to backlight if possible. ++* ++* @pdev ++* ++* @Return - ++*/ ++static int panel_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ /* struct panel_dev *panel; */ ++ struct backlight_properties props; ++ ++ memset(&props, 0, sizeof(props)); ++ panel = kzalloc(sizeof(struct panel_dev), GFP_KERNEL); ++ if(panel == NULL) { ++ dev_err(&pdev->dev, "Failed to alloc memory!"); ++ return -ENOMEM; ++ } ++ panel->dev = &pdev->dev; ++ dev_set_drvdata(&pdev->dev, panel); ++ ++ ret = of_panel_parse(&pdev->dev); ++ if(ret < 0) { ++ goto err_of_parse; ++ } ++ ++ panel->lcd = lcd_device_register("panel_lcd", &pdev->dev, panel, &panel_lcd_ops); ++ if(IS_ERR_OR_NULL(panel->lcd)) { ++ dev_err(&pdev->dev, "Error register lcd!\n"); ++ ret = -EINVAL; ++ goto err_of_parse; ++ } ++ ++ /* TODO: should this power status sync from uboot */ ++ panel->power = FB_BLANK_POWERDOWN; ++ panel_set_power(panel->lcd, FB_BLANK_UNBLANK); ++ ++#if 0 ++ props.type = BACKLIGHT_RAW; ++ props.max_brightness = 255; ++ panel->backlight = backlight_device_register("pwm-backlight.0", ++ &pdev->dev, panel, ++ &panel_backlight_ops, ++ &props); ++ if (IS_ERR_OR_NULL(panel->backlight)) { ++ dev_err(panel->dev, "failed to register 'pwm-backlight.0'.\n"); ++ goto err_lcd_register; ++ } ++ panel->backlight->props.brightness = props.max_brightness; ++ backlight_update_status(panel->backlight); ++#endif ++ ++ ret = ingenicfb_register_panel(&lcd_panel); ++ if(ret < 0) { ++ dev_err(&pdev->dev, "Failed to register lcd panel!\n"); ++ goto err_lcd_register; ++ } ++ ++ return 0; ++ ++err_lcd_register: ++ lcd_device_unregister(panel->lcd); ++err_of_parse: ++ kfree(panel); ++ return ret; ++} ++ ++static int panel_remove(struct platform_device *pdev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(&pdev->dev); ++ ++ panel_set_power(panel->lcd, FB_BLANK_POWERDOWN); ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int panel_suspend(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ ++ panel_set_power(panel->lcd, FB_BLANK_POWERDOWN); ++ return 0; ++} ++ ++static int panel_resume(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ ++ panel_set_power(panel->lcd, FB_BLANK_UNBLANK); ++ return 0; ++} ++ ++static const struct dev_pm_ops panel_pm_ops = { ++ .suspend = panel_suspend, ++ .resume = panel_resume, ++}; ++#endif ++static const struct of_device_id panel_of_match[] = { ++ { .compatible = "ingenic,tl040hds01ct", }, ++ {}, ++}; ++ ++static struct platform_driver panel_driver = { ++ .probe = panel_probe, ++ .remove = panel_remove, ++ .driver = { ++ .name = "tl040hds01ct", ++ .of_match_table = panel_of_match, ++#ifdef CONFIG_PM ++ .pm = &panel_pm_ops, ++#endif ++ }, ++}; ++ ++module_platform_driver(panel_driver); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-tl040wvs03ct.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-tl040wvs03ct.c.patch new file mode 100644 index 00000000..8863b86e --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-tl040wvs03ct.c.patch @@ -0,0 +1,740 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v12/displays/panel-tl040wvs03ct.c b/drivers/video/fbdev/ingenic/fb_v12/displays/panel-tl040wvs03ct.c +--- a/drivers/video/fbdev/ingenic/fb_v12/displays/panel-tl040wvs03ct.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v12/displays/panel-tl040wvs03ct.c 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,736 @@ ++/* ++ * driver/video/fbdev/ingenic/x2000_v12/displays/panel-88249.c ++ * ++ * Copyright (C) 2016 Ingenic Semiconductor Inc. ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../ingenicfb.h" ++ ++struct board_gpio { ++ short gpio; ++ short active_level; ++}; ++ ++struct gpio_spi { ++ short sdo; ++ short sdi; ++ short sck; ++ short cs; ++}; ++ ++struct panel_dev { ++ /* ingenic frame buffer */ ++ struct device *dev; ++ struct lcd_panel *panel; ++ ++ /* common lcd framework */ ++ struct lcd_device *lcd; ++ struct backlight_device *backlight; ++ int power; ++ ++ struct regulator *vcc; ++ struct board_gpio vdd_en; ++ struct board_gpio rst; ++ struct board_gpio pwm; ++ struct gpio_spi spi; ++}; ++ ++static struct panel_dev *panel; ++ ++#define RESET(n)\ ++ gpio_direction_output(panel->rst.gpio, n) ++ ++#define CS(n)\ ++ gpio_direction_output(panel->spi.cs, n) ++ ++#define SCK(n)\ ++ gpio_direction_output(panel->spi.sck, n) ++ ++#define SDO(n)\ ++ gpio_direction_output(panel->spi.sdo, n) ++ ++#if 0 ++#define SDI()\ ++ gpio_get_value(panel->spi.sdi) ++#endif ++ ++void SPI_SendData(unsigned char i) ++{ ++ unsigned char n; ++ ++ for(n=0; n<8; n++) { ++ if(i&0x80) ++ SDO(1); ++ else ++ SDO(0); ++ i = i << 1; ++ ++ SCK(0); ++ udelay(10); ++ SCK(1); ++ udelay(10); ++ } ++} ++ ++void SPI_WriteComm(unsigned char c) ++{ ++ CS(0); ++ ++ SDO(0); ++ ++ SCK(0); ++ udelay(10); ++ SCK(1); ++ udelay(10); ++ ++ SPI_SendData(c); ++ ++ CS(1); ++} ++ ++void SPI_WriteData(unsigned char d) ++{ ++ CS(0); ++ ++ SDO(1); ++ ++ SCK(0); ++ udelay(10); ++ SCK(1); ++ udelay(10); ++ ++ SPI_SendData(d); ++ ++ CS(1); ++} ++ ++void Initial_IC(void) ++{ ++ RESET(1); ++ udelay(10000); ++ RESET(0); ++ udelay(10); ++ RESET(1); ++ udelay(120000); // Delay 120ms // This delay time is necessary ++ SPI_WriteComm(0x11); ++ /* udelay(120000); // Delay 120ms // This delay time is necessary */ ++ //PAGE1 ++ SPI_WriteComm(0xFF); ++ SPI_WriteData(0x77); ++ SPI_WriteData(0x01); ++ SPI_WriteData(0x00); ++ SPI_WriteData(0x00); ++ SPI_WriteData(0x10); ++ ++ SPI_WriteComm(0xC0); ++ SPI_WriteData(0x3B); ++ SPI_WriteData(0x00); ++ ++ SPI_WriteComm(0xC1); ++ SPI_WriteData(0x0D); ++ SPI_WriteData(0x02); ++ ++ SPI_WriteComm(0xC2); ++ SPI_WriteData(0x31); ++ SPI_WriteData(0x05); ++ ++ SPI_WriteComm(0xCd); ++ SPI_WriteData(0x08); ++ ++ SPI_WriteComm(0xB0); ++ SPI_WriteData(0x00); //Positive Voltage Gamma Control ++ SPI_WriteData(0x11); ++ SPI_WriteData(0x18); ++ SPI_WriteData(0x0E); ++ SPI_WriteData(0x11); ++ SPI_WriteData(0x06); ++ SPI_WriteData(0x07); ++ SPI_WriteData(0x08); ++ SPI_WriteData(0x07); ++ SPI_WriteData(0x22); ++ SPI_WriteData(0x04); ++ SPI_WriteData(0x12); ++ SPI_WriteData(0x0F); ++ SPI_WriteData(0xAA); ++ SPI_WriteData(0x31); ++ SPI_WriteData(0x18); ++ ++ ++ SPI_WriteComm(0xB1); ++ SPI_WriteData(0x00); //Negative Voltage Gamma Control ++ SPI_WriteData(0x11); ++ SPI_WriteData(0x19); ++ SPI_WriteData(0x0E); ++ SPI_WriteData(0x12); ++ SPI_WriteData(0x07); ++ SPI_WriteData(0x08); ++ SPI_WriteData(0x08); ++ SPI_WriteData(0x08); ++ SPI_WriteData(0x22); ++ SPI_WriteData(0x04); ++ SPI_WriteData(0x11); ++ SPI_WriteData(0x11); ++ SPI_WriteData(0xA9); ++ SPI_WriteData(0x32); ++ SPI_WriteData(0x18); ++ ++ //PAGE1 ++ SPI_WriteComm(0xFF); ++ SPI_WriteData(0x77); ++ SPI_WriteData(0x01); ++ SPI_WriteData(0x00); ++ SPI_WriteData(0x00); ++ SPI_WriteData(0x11); ++ ++ ++ SPI_WriteComm(0xB0); SPI_WriteData(0x60); //Vop=4.7375v ++ ++ SPI_WriteComm(0xB1); SPI_WriteData(0x32); //VCOM=32 ++ ++ SPI_WriteComm(0xB2); SPI_WriteData(0x07); //VGH=15v ++ ++ SPI_WriteComm(0xB3); SPI_WriteData(0x80); ++ ++ SPI_WriteComm(0xB5); SPI_WriteData(0x49); //VGL=-10.17v ++ ++ SPI_WriteComm(0xB7); SPI_WriteData(0x85); ++ ++ SPI_WriteComm(0xB8); SPI_WriteData(0x21); //AVDD=6.6 & AVCL=-4.6 ++ ++ SPI_WriteComm(0xC1); SPI_WriteData(0x78); ++ ++ SPI_WriteComm(0xC2); SPI_WriteData(0x78); ++ ++ SPI_WriteComm(0xE0); ++ SPI_WriteData(0x00); ++ SPI_WriteData(0x1B); ++ SPI_WriteData(0x02); ++ ++ SPI_WriteComm(0xE1); ++ SPI_WriteData(0x08); ++ SPI_WriteData(0xA0); ++ SPI_WriteData(0x00); ++ SPI_WriteData(0x00); ++ SPI_WriteData(0x07); ++ SPI_WriteData(0xA0); ++ SPI_WriteData(0x00); ++ SPI_WriteData(0x00); ++ SPI_WriteData(0x00); ++ SPI_WriteData(0x44); ++ SPI_WriteData(0x44); ++ ++ ++ ++ SPI_WriteComm(0xE2); ++ SPI_WriteData(0x11); ++ SPI_WriteData(0x11); ++ SPI_WriteData(0x44); ++ SPI_WriteData(0x44); ++ SPI_WriteData(0xED); ++ SPI_WriteData(0xA0); ++ SPI_WriteData(0x00); ++ SPI_WriteData(0x00); ++ SPI_WriteData(0xEC); ++ SPI_WriteData(0xA0); ++ SPI_WriteData(0x00); ++ SPI_WriteData(0x00); ++ ++ ++ SPI_WriteComm(0xE3); ++ SPI_WriteData(0x00); ++ SPI_WriteData(0x00); ++ SPI_WriteData(0x11); ++ SPI_WriteData(0x11); ++ ++ ++ SPI_WriteComm(0xE4); ++ SPI_WriteData(0x44); ++ SPI_WriteData(0x44); ++ ++ SPI_WriteComm(0xE5); ++ SPI_WriteData(0x0A); ++ SPI_WriteData(0xE9); ++ SPI_WriteData(0xD8); ++ SPI_WriteData(0xA0); ++ SPI_WriteData(0x0C); ++ SPI_WriteData(0xEB); ++ SPI_WriteData(0xD8); ++ SPI_WriteData(0xA0); ++ SPI_WriteData(0x0E); ++ SPI_WriteData(0xED); ++ SPI_WriteData(0xD8); ++ SPI_WriteData(0xA0); ++ SPI_WriteData(0x10); ++ SPI_WriteData(0xEF); ++ SPI_WriteData(0xD8); ++ SPI_WriteData(0xA0); ++ ++ ++ ++ ++ SPI_WriteComm(0xE6); ++ SPI_WriteData(0x00); ++ SPI_WriteData(0x00); ++ SPI_WriteData(0x11); ++ SPI_WriteData(0x11); ++ ++ SPI_WriteComm(0xE7); ++ SPI_WriteData(0x44); ++ SPI_WriteData(0x44); ++ ++ ++ SPI_WriteComm(0xE8); ++ SPI_WriteData(0x09); ++ SPI_WriteData(0xE8); ++ SPI_WriteData(0xD8); ++ SPI_WriteData(0xA0); ++ SPI_WriteData(0x0B); ++ SPI_WriteData(0xEA); ++ SPI_WriteData(0xD8); ++ SPI_WriteData(0xA0); ++ SPI_WriteData(0x0D); ++ SPI_WriteData(0xEC); ++ SPI_WriteData(0xD8); ++ SPI_WriteData(0xA0); ++ SPI_WriteData(0x0F); ++ SPI_WriteData(0xEE); ++ SPI_WriteData(0xD8); ++ SPI_WriteData(0xA0); ++ ++ ++ SPI_WriteComm(0xEB); ++ SPI_WriteData(0x02); ++ SPI_WriteData(0x00); ++ SPI_WriteData(0xE4); ++ SPI_WriteData(0xE4); ++ SPI_WriteData(0x88); ++ SPI_WriteData(0x00); ++ SPI_WriteData(0x40); ++ ++ ++ SPI_WriteComm(0xEC); ++ SPI_WriteData(0x3C); ++ SPI_WriteData(0x00); ++ ++ ++ SPI_WriteComm(0xED); ++ SPI_WriteData(0xAB); ++ SPI_WriteData(0x89); ++ SPI_WriteData(0x76); ++ SPI_WriteData(0x54); ++ SPI_WriteData(0x02); ++ SPI_WriteData(0xFF); ++ SPI_WriteData(0xFF); ++ SPI_WriteData(0xFF); ++ SPI_WriteData(0xFF); ++ SPI_WriteData(0xFF); ++ SPI_WriteData(0xFF); ++ SPI_WriteData(0x20); ++ SPI_WriteData(0x45); ++ SPI_WriteData(0x67); ++ SPI_WriteData(0x98); ++ SPI_WriteData(0xBA); ++ ++ SPI_WriteComm(0x36); ++ SPI_WriteData(0x00); ++ ++ ++ //-----------VAP & VAN--------------- ++ SPI_WriteComm(0xFF); ++ SPI_WriteData(0x77); ++ SPI_WriteData(0x01); ++ SPI_WriteData(0x00); ++ SPI_WriteData(0x00); ++ SPI_WriteData(0x13); ++ ++ SPI_WriteComm(0xE5); ++ SPI_WriteData(0xE4); ++ ++ SPI_WriteComm(0xFF); ++ SPI_WriteData(0x77); ++ SPI_WriteData(0x01); ++ SPI_WriteData(0x00); ++ SPI_WriteData(0x00); ++ SPI_WriteData(0x00); ++ ++ SPI_WriteComm(0x3a); ++ SPI_WriteData(0x66); ++ SPI_WriteComm(0x21); ++ udelay(1000); // Delay 1ms ++ SPI_WriteComm(0x11); ++ udelay(120000); // Delay 120ms // This delay time is necessary ++ SPI_WriteComm(0x29); ++} ++ ++ ++static void panel_enable(struct lcd_panel *panel) ++{ ++} ++ ++static void panel_disable(struct lcd_panel *panel) ++{ ++} ++ ++static struct lcd_panel_ops panel_ops = { ++ .enable = (void*)panel_enable, ++ .disable = (void*)panel_disable, ++}; ++ ++static struct fb_videomode panel_modes[] = { ++ [0] = { ++ .name = "480X480", ++ .refresh = 60, ++ .xres = 480, ++ .yres = 480, ++ .pixclock = KHZ2PICOS(14000), ++ .left_margin = 160, ++ .right_margin = 10, ++ .upper_margin = 2, ++ .lower_margin = 1, ++ ++ .hsync_len = 16, ++ .vsync_len = 13, ++ /* .sync = ~FB_SYNC_HOR_HIGH_ACT & ~FB_SYNC_VERT_HIGH_ACT, */ ++ .vmode = FB_VMODE_NONINTERLACED, ++ .flag = 0, ++ }, ++}; ++ ++static struct tft_config tl040wvs03ct_cfg = { ++ .pix_clk_inv = 0, ++ .de_dl = 0, ++ .sync_dl = 0, ++ .color_even = TFT_LCD_COLOR_EVEN_RGB, ++ .color_odd = TFT_LCD_COLOR_ODD_RGB, ++ .mode = TFT_LCD_MODE_PARALLEL_666, ++}; ++ ++struct lcd_panel lcd_panel = { ++ .name = "tl040wvs03ct", ++ .num_modes = ARRAY_SIZE(panel_modes), ++ .modes = panel_modes, ++ .bpp = 32, ++ .width = 71, ++ .height = 70, ++ ++ .lcd_type = LCD_TYPE_TFT, ++ ++ .tft_config = &tl040wvs03ct_cfg, ++ ++ .dither_enable = 1, ++ .dither.dither_red = 1, ++ .dither.dither_green = 1, ++ .dither.dither_blue = 1, ++ ++ .ops = &panel_ops, ++}; ++ ++#if 0 ++static int panel_update_status(struct backlight_device *bd) ++{ ++ struct panel_dev *panel = dev_get_drvdata(&bd->dev); ++ int brightness = bd->props.brightness; ++ unsigned int i; ++ int pulse_num = MAX_BRIGHTNESS_STEP - brightness / CONVERT_FACTOR - 1; ++ ++ if (bd->props.fb_blank == FB_BLANK_POWERDOWN) { ++ return 0; ++ } ++ ++ if (bd->props.state & BL_CORE_SUSPENDED) ++ brightness = 0; ++ ++ if (brightness) { ++ gpio_direction_output(panel->pwm.gpio,0); ++ udelay(5000); ++ gpio_direction_output(panel->pwm.gpio,1); ++ udelay(100); ++ ++ for (i = pulse_num; i > 0; i--) { ++ gpio_direction_output(panel->pwm.gpio,0); ++ udelay(1); ++ gpio_direction_output(panel->pwm.gpio,1); ++ udelay(3); ++ } ++ } else ++ gpio_direction_output(panel->pwm.gpio, 0); ++ ++ return 0; ++} ++ ++static struct backlight_ops panel_backlight_ops = { ++ .options = BL_CORE_SUSPENDRESUME, ++ .update_status = panel_update_status, ++}; ++#endif ++ ++#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL) ++static int panel_set_power(struct lcd_device *lcd, int power) ++{ ++ struct panel_dev *panel = lcd_get_data(lcd); ++ struct board_gpio *vdd_en = &panel->vdd_en; ++ struct board_gpio *rst = &panel->rst; ++ ++ if(POWER_IS_ON(power) && !POWER_IS_ON(panel->power)) { ++ /* *(unsigned int*)(0xb00101a4) = 0xf000000; */ ++ /* *(unsigned int*)(0xb00101b4) = 0xf000000; */ ++ /* *(unsigned int*)(0xb00101c4) = 0xf000000; */ ++ gpio_direction_output(vdd_en->gpio, 0); ++ gpio_direction_output(rst->gpio, 1); ++ ++ Initial_IC(); ++ } ++ if(!POWER_IS_ON(power) && POWER_IS_ON(panel->power)) { ++ gpio_direction_output(vdd_en->gpio, 1); ++ } ++ ++ panel->power = power; ++ return 0; ++} ++ ++static int panel_get_power(struct lcd_device *lcd) ++{ ++ struct panel_dev *panel = lcd_get_data(lcd); ++ ++ return panel->power; ++} ++ ++/** ++* @ pannel_tl040wvs03ct_lcd_ops, register to kernel common backlight/lcd.c framworks. ++*/ ++static struct lcd_ops panel_lcd_ops = { ++ .early_set_power = panel_set_power, ++ .set_power = panel_set_power, ++ .get_power = panel_get_power, ++}; ++ ++static int of_panel_parse(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ struct device_node *np = dev->of_node; ++ enum of_gpio_flags flags; ++ int ret = 0; ++ ++ panel->vdd_en.gpio = of_get_named_gpio_flags(np, "ingenic,vdd-en-gpio", 0, &flags); ++ if(gpio_is_valid(panel->vdd_en.gpio)) { ++ panel->vdd_en.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ ret = gpio_request_one(panel->vdd_en.gpio, GPIOF_DIR_OUT, "vdd_en"); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request vdd_en pin!\n"); ++ return ret; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio vdd_en.gpio: %d\n", panel->vdd_en.gpio); ++ } ++ ++ panel->rst.gpio = of_get_named_gpio_flags(np, "ingenic,rst-gpio", 0, &flags); ++ if(gpio_is_valid(panel->rst.gpio)) { ++ panel->rst.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ ret = gpio_request_one(panel->rst.gpio, GPIOF_DIR_OUT, "rst"); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request rst pin!\n"); ++ goto err_request_rst; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio rst.gpio: %d\n", panel->rst.gpio); ++ } ++#if 0 ++ panel->pwm.gpio = of_get_named_gpio_flags(np, "ingenic,lcd-pwm-gpio", 0, &flags); ++ if(gpio_is_valid(panel->pwm.gpio)) { ++ panel->pwm.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ ret = gpio_request_one(panel->pwm.gpio, GPIOF_DIR_OUT, "pwm"); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request pwm pin!\n"); ++ goto err_request_pwm; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio pwm.gpio: %d\n", panel->pwm.gpio); ++ } ++#endif ++ ++ panel->spi.sdo = of_get_named_gpio_flags(np, "ingenic,lcd-sdo-gpio", 0, &flags); ++ if(gpio_is_valid(panel->spi.sdo)) { ++ ret = gpio_request_one(panel->spi.sdo, GPIOF_DIR_OUT, "sdo"); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request sdo pin!\n"); ++ goto err_request_sdo; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio spi.sdo: %d\n", panel->spi.sdo); ++ } ++ ++ panel->spi.sck = of_get_named_gpio_flags(np, "ingenic,lcd-sck-gpio", 0, &flags); ++ if(gpio_is_valid(panel->spi.sck)) { ++ ret = gpio_request_one(panel->spi.sck, GPIOF_DIR_OUT, "sck"); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request sck pin!\n"); ++ goto err_request_sck; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio spi.sck: %d\n", panel->spi.sck); ++ } ++ ++ panel->spi.cs = of_get_named_gpio_flags(np, "ingenic,lcd-cs-gpio", 0, &flags); ++ if(gpio_is_valid(panel->spi.cs)) { ++ ret = gpio_request_one(panel->spi.cs, GPIOF_DIR_OUT, "cs"); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request cs pin!\n"); ++ goto err_request_cs; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio spi.cs: %d\n", panel->spi.cs); ++ } ++ ++ return 0; ++err_request_cs: ++ if(gpio_is_valid(panel->spi.sck)) ++ gpio_free(panel->spi.sck); ++err_request_sck: ++ if(gpio_is_valid(panel->spi.sdo)) ++ gpio_free(panel->spi.sdo); ++err_request_sdo: ++ if(gpio_is_valid(panel->pwm.gpio)) ++ gpio_free(panel->pwm.gpio); ++err_request_pwm: ++ if(gpio_is_valid(panel->rst.gpio)) ++ gpio_free(panel->rst.gpio); ++err_request_rst: ++ if(gpio_is_valid(panel->vdd_en.gpio)) ++ gpio_free(panel->vdd_en.gpio); ++ return ret; ++} ++/** ++* @panel_probe ++* ++* 1. Register to ingenicfb. ++* 2. Register to lcd. ++* 3. Register to backlight if possible. ++* ++* @pdev ++* ++* @Return - ++*/ ++static int panel_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ /* struct panel_dev *panel; */ ++ struct backlight_properties props; ++ ++ memset(&props, 0, sizeof(props)); ++ panel = kzalloc(sizeof(struct panel_dev), GFP_KERNEL); ++ if(panel == NULL) { ++ dev_err(&pdev->dev, "Failed to alloc memory!"); ++ return -ENOMEM; ++ } ++ panel->dev = &pdev->dev; ++ dev_set_drvdata(&pdev->dev, panel); ++ ++ ret = of_panel_parse(&pdev->dev); ++ if(ret < 0) { ++ goto err_of_parse; ++ } ++ ++ panel->lcd = lcd_device_register("panel_lcd", &pdev->dev, panel, &panel_lcd_ops); ++ if(IS_ERR_OR_NULL(panel->lcd)) { ++ dev_err(&pdev->dev, "Error register lcd!\n"); ++ ret = -EINVAL; ++ goto err_of_parse; ++ } ++ ++ /* TODO: should this power status sync from uboot */ ++ panel->power = FB_BLANK_POWERDOWN; ++ panel_set_power(panel->lcd, FB_BLANK_UNBLANK); ++ ++#if 0 ++ props.type = BACKLIGHT_RAW; ++ props.max_brightness = 255; ++ panel->backlight = backlight_device_register("pwm-backlight.0", ++ &pdev->dev, panel, ++ &panel_backlight_ops, ++ &props); ++ if (IS_ERR_OR_NULL(panel->backlight)) { ++ dev_err(panel->dev, "failed to register 'pwm-backlight.0'.\n"); ++ goto err_lcd_register; ++ } ++ panel->backlight->props.brightness = props.max_brightness; ++ backlight_update_status(panel->backlight); ++#endif ++ ++ ret = ingenicfb_register_panel(&lcd_panel); ++ if(ret < 0) { ++ dev_err(&pdev->dev, "Failed to register lcd panel!\n"); ++ goto err_lcd_register; ++ } ++ ++ return 0; ++ ++err_lcd_register: ++ lcd_device_unregister(panel->lcd); ++err_of_parse: ++ kfree(panel); ++ return ret; ++} ++ ++static int panel_remove(struct platform_device *pdev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(&pdev->dev); ++ ++ panel_set_power(panel->lcd, FB_BLANK_POWERDOWN); ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int panel_suspend(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ ++ panel_set_power(panel->lcd, FB_BLANK_POWERDOWN); ++ return 0; ++} ++ ++static int panel_resume(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ ++ panel_set_power(panel->lcd, FB_BLANK_UNBLANK); ++ return 0; ++} ++ ++static const struct dev_pm_ops panel_pm_ops = { ++ .suspend = panel_suspend, ++ .resume = panel_resume, ++}; ++#endif ++static const struct of_device_id panel_of_match[] = { ++ { .compatible = "ingenic,tl040wvs03ct", }, ++ {}, ++}; ++ ++static struct platform_driver panel_driver = { ++ .probe = panel_probe, ++ .remove = panel_remove, ++ .driver = { ++ .name = "tl040wvs03ct", ++ .of_match_table = panel_of_match, ++#ifdef CONFIG_PM ++ .pm = &panel_pm_ops, ++#endif ++ }, ++}; ++ ++module_platform_driver(panel_driver); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-y88249.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-y88249.c.patch new file mode 100644 index 00000000..1f48f7e9 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-y88249.c.patch @@ -0,0 +1,301 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v12/displays/panel-y88249.c b/drivers/video/fbdev/ingenic/fb_v12/displays/panel-y88249.c +--- a/drivers/video/fbdev/ingenic/fb_v12/displays/panel-y88249.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v12/displays/panel-y88249.c 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,297 @@ ++/* ++ * driver/video/fbdev/ingenic/x2000_v12/displays/panel-y88249.c ++ * ++ * Copyright (C) 2016 Ingenic Semiconductor Inc. ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../ingenicfb.h" ++ ++struct board_gpio { ++ short gpio; ++ short active_level; ++}; ++ ++struct panel_dev { ++ /* ingenic frame buffer */ ++ struct device *dev; ++ struct lcd_panel *panel; ++ ++ /* common lcd framework */ ++ struct lcd_device *lcd; ++ struct backlight_device *backlight; ++ int power; ++ ++ struct regulator *vcc; ++ struct board_gpio vdd_en; ++ struct board_gpio rst; ++ struct board_gpio pwm; ++}; ++ ++static void panel_enable(struct lcd_panel *panel) ++{ ++} ++ ++static void panel_disable(struct lcd_panel *panel) ++{ ++} ++ ++static struct lcd_panel_ops panel_ops = { ++ .enable = (void*)panel_enable, ++ .disable = (void*)panel_disable, ++}; ++ ++static struct fb_videomode panel_modes[] = { ++ [0] = { ++ .name = "640X480", ++ .refresh = 65, ++ .xres = 640, ++ .yres = 480, ++ .pixclock = KHZ2PICOS(33264), ++ .left_margin = 20, ++ .right_margin = 20, ++ .upper_margin = 6, ++ .lower_margin = 12, ++ ++ .hsync_len = 2, ++ .vsync_len = 2, ++ .sync = ~FB_SYNC_HOR_HIGH_ACT & ~FB_SYNC_VERT_HIGH_ACT, ++ .vmode = FB_VMODE_NONINTERLACED, ++ .flag = 0, ++ }, ++}; ++ ++static struct tft_config y88249_cfg = { ++ .pix_clk_inv = 0, ++ .de_dl = 0, ++ .sync_dl = 0, ++ .color_even = TFT_LCD_COLOR_EVEN_RGB, ++ .color_odd = TFT_LCD_COLOR_ODD_RGB, ++ .mode = TFT_LCD_MODE_PARALLEL_888, ++}; ++ ++struct lcd_panel lcd_panel = { ++ .name = "y88249", ++ .num_modes = ARRAY_SIZE(panel_modes), ++ .modes = panel_modes, ++ .bpp = 24, ++ .width = 640, ++ .height = 480, ++ ++ .lcd_type = LCD_TYPE_TFT, ++ ++ .tft_config = &y88249_cfg, ++ ++ .dither_enable = 1, ++ .dither.dither_red = 1, ++ .dither.dither_green = 1, ++ .dither.dither_blue = 1, ++ ++ .ops = &panel_ops, ++}; ++ ++#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL) ++static int panel_set_power(struct lcd_device *lcd, int power) ++{ ++ struct panel_dev *panel = lcd_get_data(lcd); ++ struct board_gpio *vdd_en = &panel->vdd_en; ++ struct board_gpio *rst = &panel->rst; ++ struct board_gpio *pwm = &panel->pwm; ++ ++ if(POWER_IS_ON(power) && !POWER_IS_ON(panel->power)) { ++ gpio_direction_output(vdd_en->gpio, 1); ++ gpio_direction_output(rst->gpio, 1); ++ gpio_direction_output(pwm->gpio, 1); ++ } ++ if(!POWER_IS_ON(power) && POWER_IS_ON(panel->power)) { ++ gpio_direction_output(vdd_en->gpio, 0); ++ } ++ ++ panel->power = power; ++ return 0; ++} ++ ++static int panel_get_power(struct lcd_device *lcd) ++{ ++ struct panel_dev *panel = lcd_get_data(lcd); ++ ++ return panel->power; ++} ++ ++/** ++* @ pannel_y88249_lcd_ops, register to kernel common backlight/lcd.c framworks. ++*/ ++static struct lcd_ops panel_lcd_ops = { ++ .early_set_power = panel_set_power, ++ .set_power = panel_set_power, ++ .get_power = panel_get_power, ++}; ++ ++static int of_panel_parse(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ struct device_node *np = dev->of_node; ++ enum of_gpio_flags flags; ++ int ret = 0; ++ ++ panel->vdd_en.gpio = of_get_named_gpio_flags(np, "ingenic,vdd-en-gpio", 0, &flags); ++ if(gpio_is_valid(panel->vdd_en.gpio)) { ++ panel->vdd_en.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ ret = gpio_request_one(panel->vdd_en.gpio, GPIOF_DIR_OUT, "vdd_en"); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request vdd_en pin!\n"); ++ return ret; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio vdd_en.gpio: %d\n", panel->vdd_en.gpio); ++ } ++ ++ panel->rst.gpio = of_get_named_gpio_flags(np, "ingenic,rst-gpio", 0, &flags); ++ if(gpio_is_valid(panel->rst.gpio)) { ++ panel->rst.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ ret = gpio_request_one(panel->rst.gpio, GPIOF_DIR_OUT, "rst"); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request rst pin!\n"); ++ goto err_request_rst; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio rst.gpio: %d\n", panel->rst.gpio); ++ } ++ panel->pwm.gpio = of_get_named_gpio_flags(np, "ingenic,pwm-gpio", 0, &flags); ++ if(gpio_is_valid(panel->pwm.gpio)) { ++ panel->pwm.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ ret = gpio_request_one(panel->pwm.gpio, GPIOF_DIR_OUT, "pwm"); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request pwm pin!\n"); ++ goto err_request_pwm; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio pwm.gpio: %d\n", panel->pwm.gpio); ++ } ++ ++ return 0; ++err_request_pwm: ++ if(gpio_is_valid(panel->rst.gpio)) ++ gpio_free(panel->rst.gpio); ++err_request_rst: ++ if(gpio_is_valid(panel->vdd_en.gpio)) ++ gpio_free(panel->vdd_en.gpio); ++ return ret; ++} ++/** ++* @panel_probe ++* ++* 1. Register to ingenicfb. ++* 2. Register to lcd. ++* 3. Register to backlight if possible. ++* ++* @pdev ++* ++* @Return - ++*/ ++static int panel_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ struct panel_dev *panel; ++ ++ panel = kzalloc(sizeof(struct panel_dev), GFP_KERNEL); ++ if(panel == NULL) { ++ dev_err(&pdev->dev, "Faile to alloc memory!"); ++ return -ENOMEM; ++ } ++ panel->dev = &pdev->dev; ++ dev_set_drvdata(&pdev->dev, panel); ++ ++ ret = of_panel_parse(&pdev->dev); ++ if(ret < 0) { ++ goto err_of_parse; ++ } ++ ++ panel->lcd = lcd_device_register("panel_lcd", &pdev->dev, panel, &panel_lcd_ops); ++ if(IS_ERR_OR_NULL(panel->lcd)) { ++ dev_err(&pdev->dev, "Error register lcd!\n"); ++ ret = -EINVAL; ++ goto err_of_parse; ++ } ++ ++ /* TODO: should this power status sync from uboot */ ++ panel->power = FB_BLANK_POWERDOWN; ++ panel_set_power(panel->lcd, FB_BLANK_UNBLANK); ++ ++ ret = ingenicfb_register_panel(&lcd_panel); ++ if(ret < 0) { ++ dev_err(&pdev->dev, "Failed to register lcd panel!\n"); ++ goto err_lcd_register; ++ } ++ ++ return 0; ++ ++err_lcd_register: ++ lcd_device_unregister(panel->lcd); ++err_of_parse: ++ kfree(panel); ++ return ret; ++} ++ ++static int panel_remove(struct platform_device *pdev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(&pdev->dev); ++ ++ panel_set_power(panel->lcd, FB_BLANK_POWERDOWN); ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int panel_suspend(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ ++ panel_set_power(panel->lcd, FB_BLANK_POWERDOWN); ++ return 0; ++} ++ ++static int panel_resume(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ ++ panel_set_power(panel->lcd, FB_BLANK_UNBLANK); ++ return 0; ++} ++ ++static const struct dev_pm_ops panel_pm_ops = { ++ .suspend = panel_suspend, ++ .resume = panel_resume, ++}; ++#endif ++static const struct of_device_id panel_of_match[] = { ++ { .compatible = "ingenic,y88249", }, ++ {}, ++}; ++ ++static struct platform_driver panel_driver = { ++ .probe = panel_probe, ++ .remove = panel_remove, ++ .driver = { ++ .name = "y88249", ++ .of_match_table = panel_of_match, ++#ifdef CONFIG_PM ++ .pm = &panel_pm_ops, ++#endif ++ }, ++}; ++ ++module_platform_driver(panel_driver); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-ylym286a.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-ylym286a.c.patch new file mode 100644 index 00000000..15a26b2e --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-ylym286a.c.patch @@ -0,0 +1,464 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v12/displays/panel-ylym286a.c b/drivers/video/fbdev/ingenic/fb_v12/displays/panel-ylym286a.c +--- a/drivers/video/fbdev/ingenic/fb_v12/displays/panel-ylym286a.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v12/displays/panel-ylym286a.c 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,460 @@ ++/* ++ * driver/video/fbdev/ingenic/x2000_v12/displays/panel-ylym286a.c ++ * ++ * Copyright (C) 2016 Ingenic Semiconductor Inc. ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../ingenicfb.h" ++ ++struct board_gpio { ++ short gpio; ++ short active_level; ++}; ++ ++struct panel_dev { ++ /* ingenic frame buffer */ ++ struct i2c_client *client; ++ struct device *dev; ++ struct lcd_panel *panel; ++ ++ /* common lcd framework */ ++ struct lcd_device *lcd; ++ int power; ++ ++ struct board_gpio reset; ++ struct board_gpio lcd_en; ++ char *panel_name; ++}; ++ ++#define FPS 60 ++#define HACT 1920 ++#define VACT 1080 ++ ++#define HFP 88 ++#define HBP 148 ++#define HS 44 ++ ++#define VFP 4 ++#define VBP 36 ++#define VS 5 ++ ++#include "lt9211.c" ++ ++static struct panel_dev *lt9211_info; ++ ++static void panel_enable(struct lcd_panel *panel) ++{ ++} ++ ++static void panel_disable(struct lcd_panel *panel) ++{ ++} ++ ++static struct lcd_panel_ops panel_ops = { ++ .enable = (void*)panel_enable, ++ .disable = (void*)panel_disable, ++}; ++ ++static struct fb_videomode panel_modes = { ++ .name = "lt9211-ylym286a", ++ .refresh = FPS, ++ .xres = HACT, ++ .yres = VACT, ++ .left_margin = HFP, ++ .right_margin = HBP, ++ .upper_margin = VFP, ++ .lower_margin = VBP, ++ ++ .hsync_len = HS, ++ .vsync_len = VS, ++ .sync = FB_SYNC_HOR_HIGH_ACT & FB_SYNC_VERT_HIGH_ACT, ++ .vmode = FB_VMODE_NONINTERLACED, ++ .flag = 0, ++}; ++ ++struct jzdsi_data jzdsi_pdata = { ++ .modes = &panel_modes, ++ .video_config.no_of_lanes = 2, ++ .video_config.virtual_channel = 0, ++ .video_config.color_coding = COLOR_CODE_24BIT, ++ .video_config.video_mode = VIDEO_BURST_WITH_SYNC_PULSES, ++ .video_config.receive_ack_packets = 0, /* enable receiving of ack packets */ ++ .video_config.is_18_loosely = 0, ++ .video_config.data_en_polarity = 1, ++ .video_config.byte_clock = 0, // driver will auto calculate byte_clock. ++ .video_config.byte_clock_coef = MIPI_PHY_BYTE_CLK_COEF_MUL1, ++ ++ .dsi_config.max_lanes = 2, ++ .dsi_config.max_hs_to_lp_cycles = 100, ++ .dsi_config.max_lp_to_hs_cycles = 40, ++ .dsi_config.max_bta_cycles = 4095, ++ .dsi_config.color_mode_polarity = 1, ++ .dsi_config.shut_down_polarity = 1, ++ .dsi_config.max_bps = 2750, ++ .bpp_info = 24, ++}; ++ ++static struct tft_config kd050hdfia019_cfg = { ++ .pix_clk_inv = 0, ++ .de_dl = 0, ++ .sync_dl = 0, ++ .color_even = TFT_LCD_COLOR_EVEN_RGB, ++ .color_odd = TFT_LCD_COLOR_ODD_RGB, ++ .mode = TFT_LCD_MODE_PARALLEL_888, ++}; ++ ++struct lcd_panel lcd_panel[] = { ++ [0] = { ++ .name = "ylym286a", ++ .modes = &panel_modes, ++ .num_modes = 1, ++ .dsi_pdata = &jzdsi_pdata, ++ ++ .bpp = 24, ++ .width = 699, ++ .height = 197, ++ ++ .lcd_type = LCD_TYPE_TFT, ++ ++ .tft_config = &kd050hdfia019_cfg, ++ .dsi_pdata = &jzdsi_pdata, ++ ++ .dither_enable = 0, ++ .dither.dither_red = 0, ++ .dither.dither_green = 0, ++ .dither.dither_blue = 0, ++ ++ .ops = &panel_ops, ++ }, ++}; ++ ++static unsigned char i2c_read(struct i2c_client *client, unsigned char addr) ++{ ++ return i2c_smbus_read_byte_data(client, addr); ++} ++ ++static unsigned int i2c_write(struct i2c_client *client,unsigned char addr,unsigned char value) ++{ ++ return i2c_smbus_write_byte_data(client, addr, value); ++} ++ ++void lt9211_reset(struct panel_dev *lt9211_info) ++{ ++ struct board_gpio *rst = <9211_info->reset; ++ ++ gpio_direction_output(rst->gpio, 1); ++ mdelay(1); ++ gpio_direction_output(rst->gpio, 0); ++ mdelay(100); ++ gpio_direction_output(rst->gpio, 1); ++ mdelay(100); ++} ++ ++#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL) ++static int panel_set_power(struct lcd_device *lcd, int power) ++{ ++ struct panel_dev *lt9211_info = lcd_get_data(lcd); ++ struct i2c_client *client = lt9211_info->client; ++ ++ struct board_gpio *lcd_en = <9211_info->lcd_en; ++ struct board_gpio *rst = <9211_info->reset; ++ ++ if(POWER_IS_ON(power) && !POWER_IS_ON(lt9211_info->power)) { ++ gpio_direction_output(rst->gpio, 0); ++ gpio_direction_output(lcd_en->gpio, 1); ++ mdelay(15); ++ ++ lt9211_reset(lt9211_info); ++ if (LT9211_MIPI2LVDS_Config(client)) ++ return -1; ++ } ++ if(!POWER_IS_ON(power) && POWER_IS_ON(lt9211_info->power)) { ++ gpio_direction_output(lcd_en->gpio, 0); ++ } ++ ++ lt9211_info->power = power; ++ return 0; ++} ++ ++static int panel_get_power(struct lcd_device *lcd) ++{ ++ struct panel_dev *lt9211_info = lcd_get_data(lcd); ++ ++ return lt9211_info->power; ++} ++ ++static struct lcd_ops panel_lcd_ops = { ++ .early_set_power = panel_set_power, ++ .set_power = panel_set_power, ++ .get_power = panel_get_power, ++}; ++ ++ ++int _of_get_named_gpio_lvl(struct device *dev, short *gpio, short *lvl, char *of_name) ++{ ++ int ret = 0; ++ enum of_gpio_flags flags; ++ ++ /* devm_gpio_request_one */ ++ *gpio = of_get_named_gpio_flags(dev->of_node, of_name, 0, &flags); ++ if(gpio_is_valid(*gpio)) { ++ *lvl = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ ret = gpio_request_one(*gpio, GPIOF_DIR_OUT, of_name); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request reset pin!\n"); ++ return ret; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio: %s\n", of_name); ++ return -1; ++ } ++ return 0; ++} ++ ++static int of_panel_parse(struct device *dev) ++{ ++ struct panel_dev *lt9211_info = dev_get_drvdata(dev); ++ int ret = 0; ++ ++ if ((ret = _of_get_named_gpio_lvl(dev, ++ <9211_info->reset.gpio, ++ <9211_info->reset.active_level, ++ "lt9211,reset-gpio"))) ++ return ret; ++ ++ if ((ret = _of_get_named_gpio_lvl(dev, ++ <9211_info->lcd_en.gpio, ++ <9211_info->lcd_en.active_level, ++ "lt9211,lcd_en-gpio"))) ++ goto err_request_reset; ++ ++ /* devm_ */ ++ ++ return 0; ++err_request_reset: ++ if(gpio_is_valid(lt9211_info->reset.gpio)) ++ gpio_free(lt9211_info->reset.gpio); ++ return ret; ++} ++#if 0 ++/** ++* @panel_probe ++* ++* 1. Register to ingenicfb. ++* 2. Register to lcd. ++* 3. Register to backlight if possible. ++* ++* @pdev ++* ++* @Return - ++*/ ++static int panel_remove(struct platform_device *pdev) ++{ ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int panel_suspend(struct device *dev) ++{ ++ struct panel_dev *lt9211_info = dev_get_drvdata(dev); ++ ++ panel_set_power(lt9211_info->lcd, FB_BLANK_POWERDOWN); ++ return 0; ++} ++ ++static int panel_resume(struct device *dev) ++{ ++ struct panel_dev *lt9211_info = dev_get_drvdata(dev); ++ ++ panel_set_power(lt9211_info->lcd, FB_BLANK_UNBLANK); ++ return 0; ++} ++ ++static const struct dev_pm_ops panel_pm_ops = { ++ .suspend = panel_suspend, ++ .resume = panel_resume, ++}; ++#endif ++ ++static const struct of_device_id panel_of_match[] = { ++ { .compatible = "ingenic,ylym286a", }, ++ {}, ++}; ++ ++static struct platform_driver panel_driver = { ++ .probe = panel_probe, ++ .remove = panel_remove, ++ .driver = { ++ .name = "ylym286a", ++ .of_match_table = panel_of_match, ++#ifdef CONFIG_PM ++ .pm = &panel_pm_ops, ++#endif ++ }, ++}; ++#endif ++ ++static struct mipi_dsim_lcd_driver panel_dev_dsim_ddi_driver = { ++ .name = "lt9211-ylym286a", ++ .id = -1, ++ ++ /* .power_on = panel_dev_power_on, */ ++ /* .set_sequence = panel_dev_set_sequence, */ ++ /* .probe = panel_dev_probe, */ ++ /* .suspend = panel_suspend, */ ++ /* .resume = panel_resume, */ ++}; ++ ++ ++struct mipi_dsim_lcd_device panel_dev_device={ ++ .name = "lt9211-ylym286a", ++ .id = 0, ++}; ++ ++static int lt9211_probe(struct i2c_client *client, const struct i2c_device_id *id) ++{ ++ int ret = 0, i; ++ struct device *dev = &client->dev; ++ struct device_node *np = dev->of_node; ++ ++ lt9211_info = kzalloc(sizeof(struct panel_dev), GFP_KERNEL); ++ if(lt9211_info == NULL) { ++ dev_err(dev, "Failed to alloc memory!"); ++ return -ENOMEM; ++ } ++ lt9211_info->dev = dev; ++ lt9211_info->client = client; ++ dev_set_drvdata(dev, lt9211_info); ++ ++ // set dev_info. ++ ret = of_panel_parse(dev); ++ if(ret < 0) { ++ goto err_of_parse; ++ } ++ ++ // register lcd device. ++ lt9211_info->lcd = lcd_device_register("panel_lcd", dev, lt9211_info, &panel_lcd_ops); ++ if(IS_ERR_OR_NULL(lt9211_info->lcd)) { ++ dev_err(dev, "Error register lcd!\n"); ++ ret = -EINVAL; ++ goto err_of_parse; ++ } ++ ++ of_property_read_string(np, "lt9211,panel_name", (const char**)<9211_info->panel_name); ++ ++ if (lt9211_info->panel_name) { ++ for (i = 0; i < ARRAY_SIZE(lcd_panel); ++i) { ++ if (strcmp(lcd_panel[i].name, lt9211_info->panel_name) == 0) ++ break; ++ } ++ if (i == ARRAY_SIZE(lcd_panel)) { ++ printk("\033[31munsupport panel!\033[0m\n"); ++ goto err_lcd_register; ++ } ++ } else { ++ printk("\033[31mno found specid lcd panel!\033[0m\n"); ++ goto err_lcd_register; ++ } ++ ++ mipi_dsi_register_lcd_device(&panel_dev_device); ++ mipi_dsi_register_lcd_driver(&panel_dev_dsim_ddi_driver); ++ ++ ret = ingenicfb_register_panel(&lcd_panel[i]); ++ if(ret < 0) { ++ dev_err(dev, "Failed to register lcd panel!\n"); ++ goto err_lcd_register; ++ } ++ ++ // register ingenicfb device. ++ /* TODO: should this power status sync from uboot */ ++ lt9211_info->power = FB_BLANK_POWERDOWN; ++ if (panel_set_power(lt9211_info->lcd, FB_BLANK_UNBLANK)) ++ goto err_lcd_register; ++ ++ printk("\033[32mregister %s sucess.\033[0m\n", lt9211_info->panel_name); ++ ++ return 0; ++ ++err_lcd_register: ++ lcd_device_unregister(lt9211_info->lcd); ++err_of_parse: ++ kfree(lt9211_info); ++ printk("\033[31mregister %s dailed.\033[0m\n", lt9211_info->panel_name); ++ return ret; ++} ++ ++static int lt9211_remove(struct i2c_client *client) ++{ ++ struct panel_dev *lt9211_info = dev_get_drvdata(&client->dev); ++ ++ panel_set_power(lt9211_info->lcd, FB_BLANK_POWERDOWN); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_OF ++static const struct of_device_id lt9211_match_table[] = { ++ {.compatible = "mipi2lvds,lt9211",}, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, lt9211_match_table); ++#endif ++ ++static const struct i2c_device_id lt9211_id[] = { ++ { "lt9211", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, lt9211_id); ++ ++static struct i2c_driver lt9211_driver = { ++ .probe = lt9211_probe, ++ .remove = lt9211_remove, ++ .driver = { ++ .name = "lt9211", ++ .owner = THIS_MODULE, ++#ifdef CONFIG_OF ++ .of_match_table = of_match_ptr(lt9211_match_table), ++#endif ++ }, ++ .id_table = lt9211_id, ++}; ++ ++static int __init lt9211_init(void) ++{ ++ int ret; ++ printk("\033[33m%s\033[0m\n", "lt9211 driver installing..."); ++ ret = i2c_add_driver(<9211_driver); ++ if ( ret != 0 ) { ++ printk("lt9211 driver init failed!\n"); ++ } ++ ++ return ret; ++} ++ ++static void __exit lt9211_exit(void) ++{ ++ printk("lt9211 driver exited.\n"); ++ i2c_del_driver(<9211_driver); ++} ++ ++/* module_i2c_driver(lt9211_driver); */ ++module_init(lt9211_init); ++module_exit(lt9211_exit); ++ ++MODULE_DESCRIPTION("LT9211 Driver"); ++MODULE_LICENSE("GPL"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-yts500xlai.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-yts500xlai.c.patch new file mode 100644 index 00000000..94709957 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_displays_panel-yts500xlai.c.patch @@ -0,0 +1,478 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v12/displays/panel-yts500xlai.c b/drivers/video/fbdev/ingenic/fb_v12/displays/panel-yts500xlai.c +--- a/drivers/video/fbdev/ingenic/fb_v12/displays/panel-yts500xlai.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v12/displays/panel-yts500xlai.c 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,474 @@ ++/* ++ * driver/video/fbdev/ingenic/x2000_v12/displays/panel-yts500xlai.c ++ * ++ * Copyright (C) 2016 Ingenic Semiconductor Inc. ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#include "../ingenicfb.h" ++#include "../jz_dsim.h" ++#include "../jz_mipi_dsi/jz_mipi_dsih_hal.h" ++#include "../jz_mipi_dsi/jz_mipi_dsi_regs.h" ++ ++extern void dump_dsi_reg(struct dsi_device *dsi); ++ ++struct board_gpio { ++ short gpio; ++ short active_level; ++}; ++ ++struct panel_dev { ++ /* ingenic frame buffer */ ++ struct device *dev; ++ struct lcd_panel *panel; ++ ++ /* common lcd framework */ ++ struct lcd_device *lcd; ++ struct backlight_device *backlight; ++ int power; ++ ++ struct regulator *vcc; ++ struct board_gpio vdd_en; ++ struct board_gpio rst; ++ struct board_gpio lcd_te; ++ struct board_gpio lcd_pwm; ++ ++ struct mipi_dsim_lcd_device *dsim_dev; ++}; ++ ++struct panel_dev *panel; ++ ++#define lcd_to_master(a) (a->dsim_dev->master) ++#define lcd_to_master_ops(a) ((lcd_to_master(a))->master_ops) ++ ++struct yts500xlai { ++ struct device *dev; ++ unsigned int power; ++ unsigned int id; ++ ++ struct lcd_device *ld; ++ struct backlight_device *bd; ++ ++ struct mipi_dsim_lcd_device *dsim_dev; ++ ++}; ++ ++static struct dsi_cmd_packet fitipower_yts500xlai_480_800_cmd_list1[] = ++{ ++ ++/**yts500xlai***/ ++ {0x39, 0x04, 0x00, {0xB9, 0xFF, 0x83, 0x89}}, //set extc. ++ {0x39, 0x04, 0x00, {0xB9, 0xFF, 0x83, 0x94}}, //pdf->p21. ++ {0x39, 0x0B, 0x00, {0xB1, 0x48, 0x12, 0x72, 0x09, 0x33, 0x54, 0x51, 0x51, 0x30, 0x43}}, //set power. ++// {0x39, 0x07, 0x00, {0xBA, 0x63, 0x03, 0x68, 0x6B, 0xB2, 0xC0}}, //set mipi 4lane. ++ {0x39, 0x07, 0x00, {0xBA, 0x61, 0x03, 0x68, 0x6B, 0xB2, 0xC0}}, //set mipi 2lane. ++ {0x39, 0x07, 0x00, {0xB2, 0x00, 0x80, 0x64, 0x0C, 0x06, 0x2F}}, //set display. ++// test color ++// {0x39, 0x0C, 0x00, {0xB2, 0x00, 0x80, 0x64, 0x0C, 0x06, 0x2F, 0x00, 0x00, 0x00, 0x00, 0xC8}}, //set display to color test. ++// test color ++ {0x39, 0x1F, 0x00, {0xB4, 0x76, 0x74, 0x76, 0x74, 0x76, 0x74, 0x01, 0x05, 0x84, 0x35, 0x00, 0x3f, 0x76, 0x74, 0x76, 0x74, 0x76, 0x74, 0x01, 0x05, 0x84, 0x3F, 0x00, 0xFF, 0x81, 0x81, 0x81, 0x81, 0x08, 0x01}}, //set cyc. ++ {0x39, 0x22, 0x00, {0xD3, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x12, 0x10, 0x32, 0x10, 0x00, 0x00, 0x00, 0x32, 0x13, 0xC0, 0x00, 0x00, 0x32, 0x10, 0x08, 0x00, 0x00, 0x47, 0x04, 0x02, 0x02, 0x47, 0x04, 0x00, 0x47, 0x0C, 0x40}}, //set w_d(0xD3). ++ {0x39, 0x2D, 0x00, {0xD5, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x20, 0x21, 0x22, 0x23, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x18, 0x18}}, //set GIP. ++ {0x39, 0x2D, 0x00, {0xD6, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x23, 0x22, 0x21, 0x20, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19}}, //set. ++ {0x39, 0x03, 0x00, {0xB6, 0x34, 0x34}}, //set VCOM. ++ {0x39, 0x3B, 0x00, {0xE0, 0x00, 0x06, 0x13, 0x18, 0x1C, 0x20, 0x23, 0x22, 0x48, 0x58, 0x6A, 0x6B, 0x74, 0x88, 0x8E, 0x94, 0xA2, 0xA6, 0xA3, 0xB2, 0xC5, 0x63, 0x61, 0x66, 0x6C, 0x6C, 0x73, 0x7F, 0x7F, 0x00, 0x06, 0x13, 0x18, 0x1C, 0x20, 0x23, 0x22, 0x48, 0x58, 0x6A, 0x6B, 0x75, 0x89, 0x8F, 0x95, 0xA3, 0xA6, 0xA3, 0xB3, 0xC5, 0x63, 0x62, 0x67, 0x6C, 0x71, 0x78, 0x7F, 0x7F}}, //set GAMMA. ++ {0x15, 0xCC, 0x03}, //set pannal. ++ {0x39, 0x03, 0x00, {0xC0, 0x1F, 0x31}}, //set. ++ {0x15, 0xD4, 0x02}, //set. ++ {0x15, 0xBD, 0x01}, //set. ++ {0x15, 0xB1, 0x60}, //set GAS. ++ {0x15, 0xBD, 0x00}, //set . ++ {0x39, 0x08, 0x00, {0xBF, 0x40, 0x81, 0x50, 0x00, 0x1A, 0xFC, 0x01}}, //set power option HX5186 Mode. ++ {0x15, 0x36, 0x02}, // . ++/**yts500xlai***/ ++}; ++ ++ ++static void panel_dev_sleep_in(struct panel_dev *lcd) ++{ ++ struct dsi_master_ops *ops = lcd_to_master_ops(lcd); ++ struct dsi_cmd_packet data_to_send = {0x05, 0x10, 0x00}; ++ ++ ops->cmd_write(lcd_to_master(lcd), data_to_send); ++} ++ ++static void panel_dev_sleep_out(struct panel_dev *lcd) ++{ ++ struct dsi_master_ops *ops = lcd_to_master_ops(lcd); ++ struct dsi_cmd_packet data_to_send = {0x05, 0x11, 0x00}; ++// struct dsi_cmd_packet data_to_send = {0x15, 0x11, 0x00}; ++// while (1) { ++ ops->cmd_write(lcd_to_master(lcd), data_to_send); ++// } ++} ++ ++static void panel_dev_display_on(struct panel_dev *lcd) ++{ ++ struct dsi_master_ops *ops = lcd_to_master_ops(lcd);//color bar turn off 0x29 command. ++ struct dsi_cmd_packet data_to_send = {0x05, 0x29, 0x00}; ++// struct dsi_cmd_packet data_to_send = {0x15, 0x29, 0x00}; ++ ++ ops->cmd_write(lcd_to_master(lcd), data_to_send); ++} ++ ++static void panel_dev_display_off(struct panel_dev *lcd) ++{ ++ struct dsi_master_ops *ops = lcd_to_master_ops(lcd); ++ struct dsi_cmd_packet data_to_send = {0x05, 0x28, 0x00}; ++ ++ ops->cmd_write(lcd_to_master(lcd), data_to_send); ++} ++ ++ ++static void panel_dev_panel_init(struct panel_dev *lcd) ++{ ++ int i; ++ unsigned int value; ++ struct dsi_master_ops *ops = lcd_to_master_ops(lcd); ++ struct dsi_device *dsi = lcd_to_master(lcd); ++ ++ for (i = 0; i < ARRAY_SIZE(fitipower_yts500xlai_480_800_cmd_list1); i++) ++ { ++ ops->cmd_write(dsi, fitipower_yts500xlai_480_800_cmd_list1[i]); ++ value=mipi_dsih_read_word(dsi, R_DSI_HOST_INT_ST0); ++ if(value & 0x180000) ++ { ++ printk("-----2--->i=%d\n",i); ++ } ++ } ++// dump_dsi_reg(dsi); ++} ++ ++static int panel_dev_ioctl(struct mipi_dsim_lcd_device *dsim_dev, int cmd) ++{ ++ return 0; ++} ++static void panel_dev_set_sequence(struct mipi_dsim_lcd_device *dsim_dev) ++{ ++ struct yts500xlai *lcd = dev_get_drvdata(&dsim_dev->dev); ++ ++ printk(">>>>>>>>>>>>>>>>>>>>%s %d\n",__func__,__LINE__); ++ ++ panel_dev_panel_init(panel); ++ panel_dev_sleep_out(panel); ++ msleep(150); ++ panel_dev_display_on(panel); ++ msleep(20); ++ /* dump_dsi_reg(dsi); */ ++ lcd->power = FB_BLANK_UNBLANK; ++} ++static void panel_dev_power_on(struct mipi_dsim_lcd_device *dsim_dev, int power) ++{ ++ struct board_gpio *vdd_en = &panel->vdd_en; ++ struct board_gpio *rst = &panel->rst; ++ struct board_gpio *lcd_te = &panel->lcd_te; ++ printk(">>>>>>>>>>>>>>>>>>>>%s %d\n",__func__,__LINE__); ++ ++ gpio_direction_output(vdd_en->gpio, vdd_en->active_level); ++ ++ if (gpio_is_valid(lcd_te->gpio)) { ++ gpio_direction_input(lcd_te->gpio); ++ } ++ msleep(50); ++ gpio_direction_output(rst->gpio, 0); ++ msleep(50); ++ gpio_direction_output(rst->gpio, 1); ++ msleep(120); ++ ++ panel->power = power; ++} ++ ++static struct fb_videomode panel_modes = { ++ .name = "fitipower_yts500xlai-lcd", ++ .xres = 720, ++ .yres = 1280, ++ ++// .refresh = 10, ++// .refresh = 30, ++ .refresh = 35, ++// .refresh = 60, /*no display*/ ++//debug1 ++ .left_margin = 88,//hbp ++ .right_margin = 35,//hfp ++ .hsync_len = 10, //hsync ++ ++ .upper_margin = 37,//vbp ++ .lower_margin = 13,//vfp ++ .vsync_len = 10, //vsync ++//debug2 ++// .left_margin = 48,//hbp ++// .right_margin = 16,//hfp ++// .hsync_len = 8, //hsync ++// ++// .upper_margin = 3,//vbp ++// .lower_margin = 5,//vfp ++// .vsync_len = 8, //vsync ++ ++ .sync = FB_SYNC_HOR_HIGH_ACT & FB_SYNC_VERT_HIGH_ACT, ++ .vmode = FB_VMODE_NONINTERLACED, ++ .flag = 0, ++}; ++ ++struct jzdsi_data jzdsi_pdata = { ++ .modes = &panel_modes, ++ .video_config.no_of_lanes = 2, ++ .video_config.virtual_channel = 0, ++ .video_config.color_coding = COLOR_CODE_16BIT_CONFIG1, ++ .video_config.video_mode = VIDEO_BURST_WITH_SYNC_PULSES, ++ .video_config.receive_ack_packets = 0, /* enable receiving of ack packets */ ++ .video_config.is_18_loosely = 0, ++ .video_config.data_en_polarity = 1, ++ .video_config.byte_clock = 0, // driver will auto calculate byte_clock. ++// .video_config.byte_clock_coef = MIPI_PHY_BYTE_CLK_COEF_MUL3_DIV2, //1: byte_clock *3/2. ++// .video_config.byte_clock_coef = 2, // byte_clock *4/3 . ++ .video_config.byte_clock_coef = 3, // byte_clock *5/4 35fps. ++ ++ .dsi_config.max_lanes = 2, ++ .dsi_config.max_hs_to_lp_cycles = 100, ++ .dsi_config.max_lp_to_hs_cycles = 40, ++// .dsi_config.max_hs_to_lp_cycles = 200, ++// .dsi_config.max_lp_to_hs_cycles = 80, ++ .dsi_config.max_bta_cycles = 4095, ++ .dsi_config.color_mode_polarity = 1, ++ .dsi_config.shut_down_polarity = 1, ++ .dsi_config.max_bps = 2750, ++// .max_bps = 650, // 650 Mbps ++// .bpp_info = 24, ++ .bpp_info = 16, ++}; ++static struct tft_config kd050hdfia019_cfg = { ++ .pix_clk_inv = 0, ++ .de_dl = 0, ++ .sync_dl = 0, ++ .color_even = TFT_LCD_COLOR_EVEN_RGB, ++ .color_odd = TFT_LCD_COLOR_ODD_RGB, ++ .mode = TFT_LCD_MODE_PARALLEL_565, ++}; ++ ++ ++struct lcd_panel lcd_panel = { ++ .num_modes = 1, ++ .modes = &panel_modes, ++ .dsi_pdata = &jzdsi_pdata, ++ ++ .lcd_type = LCD_TYPE_TFT, ++ .tft_config = &kd050hdfia019_cfg, ++// .bpp = 24, ++ .bpp = 16, ++// .width = 700, ++// .height = 1230, ++ .width = 68, ++ .height = 121, ++ .dither_enable = 0, ++ .dither.dither_red = 0, ++ .dither.dither_green = 0, ++ .dither.dither_blue = 0, ++ ++ ++}; ++ ++#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL) ++static int panel_set_power(struct lcd_device *lcd, int power) ++{ ++ return 0; ++} ++ ++static int panel_get_power(struct lcd_device *lcd) ++{ ++ struct panel_dev *panel = lcd_get_data(lcd); ++ ++ return panel->power; ++} ++ ++/** ++* @ pannel_yts500xlai_lcd_ops, register to kernel common backlight/lcd.c framworks. ++*/ ++static struct lcd_ops panel_lcd_ops = { ++ .early_set_power = panel_set_power, ++ .set_power = panel_set_power, ++ .get_power = panel_get_power, ++}; ++ ++static int of_panel_parse(struct device *dev) ++{ ++ struct panel_dev *panel = dev_get_drvdata(dev); ++ struct device_node *np = dev->of_node; ++ enum of_gpio_flags flags; ++ int ret = 0; ++ ++ panel->rst.gpio = of_get_named_gpio_flags(np, "ingenic,rst-gpio", 0, &flags); ++ if(gpio_is_valid(panel->rst.gpio)) { ++ panel->rst.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ ret = gpio_request_one(panel->rst.gpio, GPIOF_DIR_OUT, "rst"); ++ if(ret < 0) { ++ dev_err(dev, "Failed to request rst pin!\n"); ++ goto err_request_rst; ++ } ++ } else { ++ dev_warn(dev, "invalid gpio rst.gpio: %d\n", panel->rst.gpio); ++ } ++ ++ ++ return 0; ++err_request_lcd_te: ++ if(gpio_is_valid(panel->rst.gpio)) ++ gpio_free(panel->rst.gpio); ++err_request_rst: ++ if(gpio_is_valid(panel->vdd_en.gpio)) ++ gpio_free(panel->vdd_en.gpio); ++ return ret; ++} ++ ++static int panel_dev_probe(struct mipi_dsim_lcd_device *dsim_dev) ++{ ++ struct yts500xlai *lcd; ++ lcd = devm_kzalloc(&dsim_dev->dev, sizeof(struct yts500xlai), GFP_KERNEL); ++ if (!lcd) ++ { ++ dev_err(&dsim_dev->dev, "failed to allocate fitipower_yts500xlai structure.\n"); ++ return -ENOMEM; ++ } ++ ++ lcd->dsim_dev = dsim_dev; ++ lcd->dev = &dsim_dev->dev; ++ ++ lcd->ld = lcd_device_register("fitipower_yts500xlai", lcd->dev, lcd, ++ &panel_lcd_ops); ++ if (IS_ERR(lcd->ld)) ++ { ++ dev_err(lcd->dev, "failed to register lcd ops.\n"); ++ return PTR_ERR(lcd->ld); ++ } ++ ++ dev_set_drvdata(&dsim_dev->dev, lcd); ++ ++ ++ dev_dbg(lcd->dev, "probed fitipower_yts500xlai panel driver.\n"); ++ ++ ++ panel->dsim_dev = dsim_dev; ++ ++ ++ return 0; ++ ++} ++ ++static int panel_suspend(struct mipi_dsim_lcd_device *dsim_dev) ++{ ++ struct board_gpio *vdd_en = &panel->vdd_en; ++ ++ printk(">>>>>>>>>>>>>>>>>>>>%s %d\n",__func__,__LINE__); ++ panel_dev_display_off(panel); ++ panel_dev_sleep_in(panel); ++ gpio_direction_output(vdd_en->gpio, !vdd_en->active_level); ++ ++ return 0; ++} ++ ++static int panel_resume(struct mipi_dsim_lcd_device *dsim_dev) ++{ ++ struct board_gpio *vdd_en = &panel->vdd_en; ++ printk(">>>>>>>>>>>>>>>>>>>>%s %d\n",__func__,__LINE__); ++ ++ gpio_direction_output(vdd_en->gpio, vdd_en->active_level); ++ ++ return 0; ++} ++ ++static struct mipi_dsim_lcd_driver panel_dev_dsim_ddi_driver = { ++ .name = "fitipower_yts500xlai-lcd", ++ .id = -1, ++ ++ .power_on = panel_dev_power_on, ++ .set_sequence = panel_dev_set_sequence, ++ .probe = panel_dev_probe, ++// .suspend = panel_suspend, ++ .resume = panel_resume, ++}; ++ ++ ++struct mipi_dsim_lcd_device panel_dev_device={ ++ .name = "fitipower_yts500xlai-lcd", ++ .id = 0, ++}; ++ ++/** ++* @panel_probe ++* ++* 1. Register to ingenicfb. ++* 2. Register to lcd. ++* 3. Register to backlight if possible. ++* ++* @pdev ++* ++* @Return - ++*/ ++static int panel_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ panel = kzalloc(sizeof(struct panel_dev), GFP_KERNEL); ++ if(panel == NULL) { ++ dev_err(&pdev->dev, "Faile to alloc memory!"); ++ return -ENOMEM; ++ } ++ panel->dev = &pdev->dev; ++ dev_set_drvdata(&pdev->dev, panel); ++ ++ ret = of_panel_parse(&pdev->dev); ++ if(ret < 0) { ++ goto err_of_parse; ++ } ++ ++ mipi_dsi_register_lcd_device(&panel_dev_device); ++ mipi_dsi_register_lcd_driver(&panel_dev_dsim_ddi_driver); ++ ++ ret = ingenicfb_register_panel(&lcd_panel); ++ if(ret < 0) { ++ dev_err(&pdev->dev, "Failed to register lcd panel!\n"); ++ goto err_of_parse; ++ } ++ ++ return 0; ++ ++err_of_parse: ++ kfree(panel); ++ return ret; ++} ++ ++static int panel_remove(struct platform_device *pdev) ++{ ++ return 0; ++} ++ ++static const struct of_device_id panel_of_match[] = { ++ { .compatible = "ingenic,yts500xlai", }, ++ {}, ++}; ++ ++static struct platform_driver panel_driver = { ++ .probe = panel_probe, ++ .remove = panel_remove, ++ .driver = { ++ .name = "yts500xlai", ++ .of_match_table = panel_of_match, ++ }, ++}; ++ ++module_platform_driver(panel_driver); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_dpu_reg.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_dpu_reg.h.patch new file mode 100644 index 00000000..f446b8c2 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_dpu_reg.h.patch @@ -0,0 +1,890 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v12/dpu_reg.h b/drivers/video/fbdev/ingenic/fb_v12/dpu_reg.h +--- a/drivers/video/fbdev/ingenic/fb_v12/dpu_reg.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v12/dpu_reg.h 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,886 @@ ++/* ++ * drivers/video/fbdev/ingenic/x2000_v12/dpu_reg.h ++ * ++ * Copyright (C) 2016 Ingenic Semiconductor Inc. ++ * ++ * Author:clwang ++ * ++ * 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. ++ */ ++ ++#ifndef _DPU_REG_H_ ++#define _DPU_REG_H_ ++ ++#define DPU_BASE 0xb3050000 ++ ++/*------------------------------------------------------------------------------- ++ * DPU Register Offset ++ * -----------------------------------------------------------------------------*/ ++ ++ ++/* RW 32 0x0000_0000 frame descriptor's address*/ ++#define DC_FRM_CFG_ADDR (0x0000) ++/* -W 32 0x0000_0000 frame descriptor's control*/ ++#define DC_FRM_CFG_CTRL (0x0004) ++/* RW 32 0x0000_0000 RDMA descriptor's address*/ ++#define DC_RDMA_CHAIN_ADDR (0x1000) ++/* -W 32 0x0000_0000 RDMA descriptor's control*/ ++#define DC_RDMA_CHAIN_CTRL (0x1004) ++/* RW 32 0x0000_0000 DC control*/ ++#define DC_CTRL (0x2000) ++/* RW 32 0x0000_0000 DC status*/ ++#define DC_ST (0x2004) ++/* -W 32 0x0000_0000 DC clear status*/ ++#define DC_CLR_ST (0x2008) ++/* RW 32 0x0000_0000 DC interrupt mask*/ ++#define DC_INTC (0x200c) ++/* R- 32 0x0000_0000 For debug*/ ++#define DC_INT_FLAG (0x2010) ++/* RW 32 0x0000_0000 Common configure register*/ ++#define DC_COM_CONFIG (0x2014) ++ ++/* RW 32 0x0000-0006 RDMA Priority level soft config*/ ++#define DC_PCFG_RD_CTRL (0x2018) ++/* RW 32 0x0000-0006 writeback Priority level soft config*/ ++#define DC_PCFG_WR_CTRL (0x201c) ++/* RW 32 0x0066-4422 OFIFO Priority level threshold config*/ ++#define DC_OFIFO_PCFG (0x2020) ++/* RW 32 0x0018-1008 WDMA Priority level threshold config*/ ++#define DC_WDMA_PCFG (0x2024) ++/* RW 32 0x0000-0006 CMP_W Priority level soft config*/ ++#define DC_CMPW_PCFG_CTRL (0x2028) ++/* RW 32 0x0000-0006 CMPW PCFG0 soft config*/ ++#define DC_CMPW_PCFG0 (0x202c) ++/* RW 32 0x0000-0006 CMPW PCFG1 soft config*/ ++#define DC_CMPW_PCFG1 (0x2030) ++/* RW 32 0x0000-0006 CMPW PCFG2 soft config*/ ++#define DC_CMPW_PCFG2 (0x2034) ++ ++/* R- 32 0x0000_0000 For debug*/ ++#define DC_FRM_DES (0x2100) ++/* R- 32 0x0000_0000 For debug*/ ++#define DC_LAY0_DES (0x2104) ++/* R- 32 0x0000_0000 For debug*/ ++#define DC_LAY1_DES (0x2108) ++/* R- 32 0x0000_0000 For debug*/ ++#define DC_LAY2_DES (0x210c) ++/* R- 32 0x0000_0000 For debug*/ ++#define DC_LAY3_DES (0x2110) ++/* R- 32 0x0000_0000 For debug*/ ++#define DC_RDMA_DES (0x2114) ++/* R- 32 0x0000_0000 frame descriptor's current site*/ ++#define DC_FRM_CHAIN_SITE (0x2200) ++/* R- 32 0x0000_0000 rdma descriptor's current site*/ ++#define DC_RDMA_CHAIN_SITE (0x2204) ++/* R- 32 0x0000_0000 layer0's current site*/ ++#define DC_LAY0_SITE (0x3100) ++/* R- 32 0x0000_0000 layer1's current site*/ ++#define DC_LAY1_SITE (0x3104) ++/* R- 32 0x0000_0000 layer2's current site*/ ++#define DC_LAY2_SITE (0x3108) ++/* R- 32 0x0000_0000 layer3's current site*/ ++#define DC_LAY3_SITE (0x310c) ++/* R- 32 0x0000_0000 rdma's current site*/ ++#define DC_RDMA_SITE (0x3110) ++/* R- 32 0x0000_0000 wdma's current site*/ ++#define DC_WDMA_SITE (0x221c) ++/* RW 32 0x0000_0000 TLB Global Control*/ ++#define DC_TLB_GLBC (0x3000) ++/* RW 32 0x0000_0000 TLB table entry address*/ ++#define DC_TLB_TLBA (0x3010) ++/* RW 32 0x0000_0000 TLB trigger control*/ ++#define DC_TLB_TLBC (0x3020) ++/* R- 32 0x0000_0000 VPN probe 0*/ ++#define DC_TLB0_VPN (0x3030) ++/* R- 32 0x0000_0000 VPN probe 1*/ ++#define DC_TLB1_VPN (0x3034) ++/* R- 32 0x0000_0000 VPN probe 2*/ ++#define DC_TLB2_VPN (0x3038) ++/* R- 32 0x0000_0000 VPN probe 3*/ ++#define DC_TLB3_VPN (0x303c) ++/* RW 32 0x0000_0000 TLB table entry verification*/ ++#define DC_TLB_TLBV (0x3040) ++/* R- 32 0x0000_0000 TLB status*/ ++#define DC_TLB_STAT (0x3050) ++/* RW 32 0x066204a8 CscMultYRv*/ ++#define DC_CSC_MULT_YRV (0x3200) ++/* RW 32 0x03410190 CscMultGuGv*/ ++#define DC_CSC_MULT_GUGV (0x3204) ++/* RW 32 0x00000812 CscMultBu*/ ++#define DC_CSC_MULT_BU (0x3208) ++/* RW 32 0x00800000 CscSubYUV*/ ++#define DC_CSC_SUB_YUV (0x320c) ++/* RW 32 0x0000_0000 display common configure*/ ++#define DC_DISP_COM (0x8000) ++/* RW 32 0x0000_0000 TFT HSYNC*/ ++#define DC_TFT_HSYNC (0x9000) ++/* RW 32 0x0000_0000 TFT VSYNC*/ ++#define DC_TFT_VSYNC (0x9004) ++/* RW 32 0x0000_0000 TFT HDE*/ ++#define DC_TFT_HDE (0x9008) ++/* RW 32 0x0000_0000 TFT VDE*/ ++#define DC_TFT_VDE (0x900C) ++/* RW 32 0x0000_0000 TFT configure*/ ++#define DC_TFT_CFG (0x9010) ++/* RW 32 0x0000_0000 TFT status*/ ++#define DC_TFT_ST (0x9014) ++/* RW 32 0x0000_0000 SLCD configure*/ ++#define DC_SLCD_CFG (0xA000) ++/* RW 32 0x0000_0000 SLCD WR's duty*/ ++#define DC_SLCD_WR_DUTY (0xA004) ++/* RW 32 0x0000_0000 SLCD timing*/ ++#define DC_SLCD_TIMING (0xA008) ++/* RW 32 0x0000_0000 frame size*/ ++#define DC_SLCD_FRM_SIZE (0xA00C) ++/* RW 32 0x0000_0000 slow time*/ ++#define DC_SLCD_SLOW_TIME (0xA010) ++/* RW 32 0x0000_0000 SLCD command*/ ++#define DC_SLCD_REG_IF (0xA014) ++/* RW 32 0x0000_0000 SLCD status*/ ++#define DC_SLCD_ST (0xA018) ++#define DC_SLCD_REG_CTRL (0xA01c) ++ ++ ++/*------------------------------------------------------------------------------- ++ * DPU Registers Bits Field Define ++ * -----------------------------------------------------------------------------*/ ++ ++ ++/* Frame descriptor control(DC_FRM_CFG_CTRL) bit field define */ ++ ++/* 1:change to single read channel after the current frame ; 0:no effect */ ++#define DC_CHANGE_2_RDMA BIT(1) ++/* Frame descriptor DMA start */ ++#define DC_FRM_START BIT(0) ++ ++/* RDMA descriptor control(DC_RDMA_CHAIN_CTRL) bit field define */ ++ ++/* 1:change to composer channel after the current frame ; 0:no effect */ ++#define DC_CHANGE_2_CMP BIT(1) ++/* RDMA descriptor DMA start */ ++#define DC_RDMA_START BIT(0) ++ ++/* Control configure(DC_CTRL) bit field define */ ++ ++/* General stop the simple read channel.Assure integrity of the current frame */ ++#define DC_GEN_STP_RDMA BIT(4) ++/* General stop the composer channel. Assure integrity of the current frame */ ++#define DC_GEN_STP_CMP BIT(3) ++/* Reset the counter of FRM_DES, LAYx_DES and RDMA_DES */ ++#define DC_DES_CNT_RST BIT(2) ++/* Quick stop the simple read channel. */ ++#define DC_QCK_STP_RDMA BIT(1) ++/* Quick stop the composer channel. */ ++#define DC_QCK_STP_CMP BIT(0) ++ ++/* Status Register(DC_ST) bit field define */ ++ ++/* Composer cannot meet the writeback frame rate*/ ++#define DC_CMP_W_SLOW BIT(31) ++/* One frame display end */ ++#define DC_DISP_END BIT(17) ++/* write back DMA is over-run. */ ++#define DC_WDMA_OVER BIT(16) ++/* write back DMA end. */ ++#define DC_WDMA_END BIT(15) ++/* simple read DMA end. */ ++#define DC_CMP_START BIT(14) ++/* layer3's block DMA end. */ ++#define DC_LAY3_END BIT(13) ++/* layer2's block DMA end. */ ++#define DC_LAY2_END BIT(12) ++/* layer1's block DMA end. */ ++#define DC_LAY1_END BIT(11) ++/* layer0's block DMA end. */ ++#define DC_LAY0_END BIT(10) ++/* composer end of each frame. */ ++#define DC_CMP_END BIT(9) ++/* TFT jump into under-run mode. */ ++#define DC_TFT_UNDR BIT(8) ++/* writeback channel is general stop */ ++#define DC_STOP_WRBK_ACK BIT(7) ++/* Display channel general stop */ ++#define DC_STOP_DISP_ACK BIT(6) ++/* writeback channel is working */ ++#define DC_WRBK_WORKING BIT(5) ++/* composer direct output channel is working. */ ++#define DC_DIRECT_WORKING BIT(4) ++#define DC_SRD_WORKING BIT(3) ++#define DC_SRD_START BIT(2) ++#define DC_SRD_END BIT(1) ++/* display controller is working. */ ++#define DC_WORKING BIT(0) ++ ++/* Clear status Register(DC_CSR) bit field define */ ++ ++/* Clear CMP_W_SLOW*/ ++#define DC_CLR_CMP_W_SLOW BIT(31) ++#define DC_CLR_DISP_END BIT(17) ++/* clear WDMA_OVER */ ++#define DC_CLR_WDMA_OVER BIT(16) ++/* clear WDMA_END */ ++#define DC_CLR_WDMA_END BIT(15) ++#define DC_CLR_CMP_START BIT(14) ++/* clear BDMA3_END */ ++#define DC_CLR_LAY3_END BIT(13) ++/* clear BDMA2_END */ ++#define DC_CLR_LAY2_END BIT(12) ++/* clear BDMA1_END */ ++#define DC_CLR_LAY1_END BIT(11) ++/* clear BDMA0_END */ ++#define DC_CLR_LAY0_END BIT(10) ++/* clear BDMA_END */ ++#define DC_CLR_CMP_END BIT(9) ++/* clear TFT_UNDR */ ++#define DC_CLR_TFT_UNDR BIT(8) ++/* clear STOP_WRBK_ACK */ ++#define DC_CLR_STOP_WRBK_ACK BIT(7) ++/* clear STOP_DISP_ACK */ ++#define DC_CLR_STOP_DISP_ACK BIT(6) ++#define DC_CLR_SRD_START BIT(2) ++#define DC_CLR_SRD_END BIT(1) ++ ++/* INTC register(DC_INTC) bit field define */ ++ ++/* Mask of CMP_W_SLOW*/ ++#define DC_CWS_MSK BIT(31) ++/* mask of DISP_END */ ++#define DC_EOD_MSK BIT(17) ++/* mask of WDMA_OVER */ ++#define DC_OOW_MSK BIT(16) ++/* mask of WDMA_END */ ++#define DC_EOW_MSK BIT(15) ++#define DC_SOC_MSK BIT(14) ++/* mask of BDMA3_END */ ++#define DC_EOL3_MSK BIT(13) ++/* mask of BDMA2_END */ ++#define DC_EOL2_MSK BIT(12) ++/* mask of BDMA1_END */ ++#define DC_EOL1_MSK BIT(11) ++/* mask of BDMA0_END */ ++#define DC_EOL0_MSK BIT(10) ++#define DC_EOC_MSK BIT(9) ++/* mask of TFT_UNDR */ ++#define DC_UOT_MSK BIT(8) ++/* mask of STOP_WRBK_ACK */ ++#define DC_SWA_MSK BIT(7) ++/* mask of STOP_DISP_ACK */ ++#define DC_SDA_MSK BIT(6) ++#define DC_SOS_MSK BIT(2) ++#define DC_EOS_MSK BIT(1) ++ ++/* DC interrupt flag(DC_INT_FLAG) */ ++ ++/* Interrupt of CMP_W_SLOW*/ ++#define DC_INT_CWS BIT(31) ++/* Interrupt of DISP_END */ ++#define DC_INT_EOD BIT(17) ++#define DC_INT_OOW BIT(16) ++#define DC_INT_EOW BIT(15) ++#define DC_INT_SOC BIT(14) ++#define DC_INT_EOL3 BIT(13) ++#define DC_INT_EOL2 BIT(12) ++/* Interrupt of BDMA1_END */ ++#define DC_INT_EOL1 BIT(11) ++/* Interrupt of BDMA0_END */ ++#define DC_INT_EOL0 BIT(10) ++/* Interrupt of BDMA_END */ ++#define DC_INT_EOC BIT(9) ++/* Interrupt of TFT_UNDR */ ++#define DC_INT_UOT BIT(8) ++#define DC_INT_SWA BIT(7) ++/* Interrupt of STOP_DISP_ACK */ ++#define DC_INT_SDA BIT(6) ++#define DC_INT_SOS BIT(2) ++#define DC_INT_EOS BIT(1) ++ ++ ++ ++/* Common configure register(DC_COM_CONFIG) bit field define */ ++ ++ ++/***add reg clk_gate_en***/ ++#define DC_BURST_LEN_WDMA_LBIT (6) ++#define DC_BURST_LEN_WDMA_HBIT (7) ++#define DC_BURST_LEN_WDMA_MASK \ ++ GENMASK(DC_BURST_LEN_WDMA_HBIT, DC_BURST_LEN_WDMA_LBIT) ++#define DC_BURST_LEN_WDMA_4 (0) << DC_BURST_LEN_WDMA_LBIT ++#define DC_BURST_LEN_WDMA_8 (1) << DC_BURST_LEN_WDMA_LBIT ++#define DC_BURST_LEN_WDMA_16 (2) << DC_BURST_LEN_WDMA_LBIT ++#define DC_BURST_LEN_WDMA_32 (3) << DC_BURST_LEN_WDMA_LBIT ++ ++#define DC_BURST_LEN_RDMA_LBIT (4) ++#define DC_BURST_LEN_RDMA_HBIT (5) ++#define DC_BURST_LEN_RDMA_MASK \ ++ GENMASK(DC_BURST_LEN_RDMA_HBIT, DC_BURST_LEN_RDMA_LBIT) ++#define DC_BURST_LEN_RDMA_4 (0) << DC_BURST_LEN_RDMA_LBIT ++#define DC_BURST_LEN_RDMA_8 (1) << DC_BURST_LEN_RDMA_LBIT ++#define DC_BURST_LEN_RDMA_16 (2) << DC_BURST_LEN_RDMA_LBIT ++#define DC_BURST_LEN_RDMA_32 (3) << DC_BURST_LEN_RDMA_LBIT ++ ++#define DC_BURST_LEN_BDMA_LBIT (2) ++#define DC_BURST_LEN_BDMA_HBIT (3) ++#define DC_BURST_LEN_BDMA_MASK \ ++ GENMASK(DC_BURST_LEN_BDMA_HBIT, DC_BURST_LEN_BDMA_LBIT) ++#define DC_BURST_LEN_BDMA_4 (0) << DC_BURST_LEN_BDMA_LBIT ++#define DC_BURST_LEN_BDMA_8 (1) << DC_BURST_LEN_BDMA_LBIT ++#define DC_BURST_LEN_BDMA_16 (2) << DC_BURST_LEN_BDMA_LBIT ++#define DC_BURST_LEN_BDMA_32 (3) << DC_BURST_LEN_BDMA_LBIT ++ ++/* keep default value */ ++#define DC_OUT_SEL BIT(1) ++#define DC_OUT_SEL_RDMA BIT(1) ++#define DC_OUT_SEL_CMP ~BIT(1) ++ ++/* PCFG_RD_CTRL register */ ++ ++/* QoS value */ ++#define DC_ARQOS_VAL_LBIT (1) ++#define DC_ARQOS_VAL_HBIT (2) ++#define DC_ARQOS_VAL_MASK \ ++ GENMASK(DC_ARQOS_VAL_HBIT, DC_ARQOS_VAL_LBIT) ++#define DC_ARQOS_VAL_0 (0) << DC_ARQOS_VAL_LBIT ++#define DC_ARQOS_VAL_1 (1) << DC_ARQOS_VAL_LBIT ++#define DC_ARQOS_VAL_2 (2) << DC_ARQOS_VAL_LBIT ++#define DC_ARQOS_VAL_3 (3) << DC_ARQOS_VAL_LBIT ++/* QoS ctrl */ ++#define DC_ARQOS_CTRL BIT(0) ++ ++/* PCFG register(OFIFO's PCFG Register) bit field define */ ++#define DC_PCFG0_LBIT (0) ++#define DC_PCFG0_HBIT (8) ++#define DC_PCFG0_MASK \ ++ GENMASK(DC_PCFG0_HBIT, DC_PCFG0_LBIT) ++ ++#define DC_PCFG1_LBIT (9) ++#define DC_PCFG1_HBIT (17) ++#define DC_PCFG1_MASK \ ++ GENMASK(DC_PCFG1_HBIT, DC_PCFG1_LBIT) ++ ++#define DC_PCFG2_LBIT (18) ++#define DC_PCFG2_HBIT (26) ++#define DC_PCFG2_MASK \ ++ GENMASK(DC_PCFG2_HBIT, DC_PCFG2_LBIT) ++ ++/* Global control(GLBC) bit field define */ ++ ++/* TLB enable */ ++#define DC_TLBE_LBIT (0) ++#define DC_TLBE_HBIT (3) ++#define DC_TLBE_MASK \ ++ GENMASK(DC_TLBE_HBIT, DC_TLBE_LBIT) ++/* TLB channel 0 enable */ ++#define DC_CH0_TLBE BIT(0) ++/* TLB channel 1 enable */ ++#define DC_CH1_TLBE BIT(1) ++/* TLB channel 2 enable */ ++#define DC_CH2_TLBE BIT(2) ++/* TLB channel 3 enable */ ++#define DC_CH3_TLBE BIT(3) ++ ++/* Interrupt enable */ ++#define DC_INTE_LBIT (4) ++#define DC_INTE_HBIT (7) ++#define DC_INTE_MASK \ ++ GENMASK(DC_INTE_HBIT, DC_INTE_LBIT) ++/* TLB channel 0 interrupt enable */ ++#define DC_CH0_INTE BIT(4) ++/* TLB channel 1 interrupt enable */ ++#define DC_CH1_INTE BIT(5) ++/* TLB channel 2 interrupt enable */ ++#define DC_CH2_INTE BIT(6) ++/* TLB channel 3 interrupt enable */ ++#define DC_CH3_INTE BIT(7) ++ ++/* TLB fetch mode, for STB miss */ ++#define DC_FMODE_LBIT (8) ++#define DC_FMODE_HBIT (11) ++#define DC_FMODE_MASK \ ++ GENMASK(DC_FMODE_HBIT, DC_FMODE_LBIT) ++#define DC_CH0_FMODE BIT(8) ++#define DC_CH1_FMODE BIT(9) ++#define DC_CH2_FMODE BIT(10) ++#define DC_CH3_FMODE BIT(11) ++ ++/* TLB table address(GLBA) bit field define */ ++ ++/* TLB table address,Its only used and must \ ++ * be initialized when GLBC.TLBEn was set */ ++#define DC_TLBA_LBIT (12) ++#define DC_TLBA_HBIT (31) ++#define DC_TLBA_MASK \ ++ GENMASK(DC_TLBA_HBIT, DC_TLBA_LBIT) ++ ++/* TLB control Trigger(TLBC) bit field define */ ++ ++/* When TLB table entry un-usable case occurs, SW set this bit to \ ++ * inform to retry reading the TLB table entry again.*/ ++#define DC_RETRY_LBIT (4) ++#define DC_RETRY_HBIT (7) ++#define DC_RETRY_MASK \ ++ GENMASK(DC_RETRY_HBIT, DC_RETRY_LBIT) ++#define DC_CH0_RETRY BIT(4) ++#define DC_CH1_RETRY BIT(5) ++#define DC_CH2_RETRY BIT(6) ++#define DC_CH3_RETRY BIT(7) ++ ++/* Write 1 to invalidate all TLB caches. */ ++#define DC_INVLD_LBIT (0) ++#define DC_INVLD_HBIT (3) ++#define DC_INVLD_MASK \ ++ GENMASK(DC_INVLD_HBIT, DC_INVLD_LBIT) ++#define DC_CH0_INVLD BIT(0) ++#define DC_CH1_INVLD BIT(1) ++#define DC_CH2_INVLD BIT(2) ++#define DC_CH3_INVLD BIT(3) ++ ++/* TLB VPNX Status(VPNX) bit field define */ ++ ++/* When working in TLB enable case, if the relative TLB table ++ * entry in the external DDR is un-useable, VPU will record its ++ * virtual address bit31:12 into VPN. SW can read-out VPN for ++ * TLB table entry,s rebuilding.*/ ++#define DC_VPNX_LBIT (12) ++#define DC_VPNX_HBIT (31) ++#define DC_VPNX_MASK \ ++ GENMASK(DC_VPNX_HBIT, DC_VPNX_LBIT) ++ ++/* TLB table entry verification(TLBV) bit field define */ ++ ++/* Check bit ignored(ignore the vld bit for PEntry, SEntry in memory*/ ++#define DC_RCI BIT(31) ++/* Check number mask */ ++#define DC_CNM_LBIT (16) ++#define DC_CNM_HBIT (27) ++#define DC_CNM_MASK \ ++ GENMASK(DC_CNM_HBIT, DC_CNM_LBIT) ++/* Golden Check number, ++ * VPU will check its secondary table entry to judge whether it is valid. ++ * If (GCN & CNM) == (TLB entry data readed by TLB [11:0] &CNM) ++ * indicates current entry is valid, otherwise it is unusable.*/ ++#define DC_GCN_LBIT (0) ++#define DC_GCN_HBIT (11) ++#define DC_GCN_MASK \ ++ GENMASK(DC_GCN_HBIT, DC_GCN_LBIT) ++ ++/* SCH status(STAT) bit field define */ ++ ++/* CH3 TLB error occurs. Write 0 to cleared */ ++#define DC_CH3_TLB_ERR BIT(3) ++/* CH2 TLB error occurs. Write 0 to cleared */ ++#define DC_CH2_TLB_ERR BIT(2) ++/* CH1 TLB error occurs. Write 0 to cleared */ ++#define DC_CH1_TLB_ERR BIT(1) ++/* CH0 TLB error occurs. Write 0 to cleared */ ++#define DC_CH0_TLB_ERR BIT(0) ++ ++/* CscMultYRv */ ++ ++#define DC_CSC_MULT_Y_LBIT (0) ++#define DC_CSC_MULT_Y_HBIT (10) ++#define DC_CSC_MULT_Y_MASK \ ++ GENMASK(DC_CSC_MULT_Y_HBIT, DC_CSC_MULT_Y_LBIT) ++#define DC_CSC_MULT_Y_MD0 (0x400) << DC_CSC_MULT_Y_LBIT ++#define DC_CSC_MULT_Y_MD1 (0x4a8) << DC_CSC_MULT_Y_LBIT ++#define DC_CSC_MULT_Y_MD2 (0x400) << DC_CSC_MULT_Y_LBIT ++#define DC_CSC_MULT_Y_MD3 (0x47c) << DC_CSC_MULT_Y_LBIT ++ ++#define DC_CSC_MULT_RV_LBIT (16) ++#define DC_CSC_MULT_RV_HBIT (26) ++#define DC_CSC_MULT_RV_MASK \ ++ GENMASK(DC_CSC_MULT_RV_HBIT, DC_CSC_MULT_RV_LBIT) ++#define DC_CSC_MULT_RV_MD0 (0x48f) << DC_CSC_MULT_RV_LBIT ++#define DC_CSC_MULT_RV_MD1 (0x662) << DC_CSC_MULT_RV_LBIT ++#define DC_CSC_MULT_RV_MD2 (0x59c) << DC_CSC_MULT_RV_LBIT ++#define DC_CSC_MULT_RV_MD3 (0x57c) << DC_CSC_MULT_RV_LBIT ++ ++/* CscMultGuGv */ ++ ++#define DC_CSC_MULT_GU_LBIT (0) ++#define DC_CSC_MULT_GU_HBIT (8) ++#define DC_CSC_MULT_GU_MASK \ ++ GENMASK(DC_CSC_MULT_GU_HBIT, DC_CSC_MULT_GU_LBIT) ++#define DC_CSC_MULT_GU_MD0 (0x193) << DC_CSC_MULT_GU_LBIT ++#define DC_CSC_MULT_GU_MD1 (0x190) << DC_CSC_MULT_GU_LBIT ++#define DC_CSC_MULT_GU_MD2 (0x160) << DC_CSC_MULT_GU_LBIT ++#define DC_CSC_MULT_GU_MD3 (0x15a) << DC_CSC_MULT_GU_LBIT ++ ++#define DC_CSC_MULT_GV_LBIT (16) ++#define DC_CSC_MULT_GV_HBIT (25) ++#define DC_CSC_MULT_GV_MASK \ ++ GENMASK(DC_CSC_MULT_GV_HBIT, DC_CSC_MULT_GV_LBIT) ++#define DC_CSC_MULT_GV_MD0 (0x253) << DC_CSC_MULT_GV_LBIT ++#define DC_CSC_MULT_GV_MD1 (0x341) << DC_CSC_MULT_GV_LBIT ++#define DC_CSC_MULT_GV_MD2 (0x2db) << DC_CSC_MULT_GV_LBIT ++#define DC_CSC_MULT_GV_MD3 (0x2cb) << DC_CSC_MULT_GV_LBIT ++ ++/* CscMultBu */ ++ ++#define DC_CSC_MULT_BU_LBIT (0) ++#define DC_CSC_MULT_BU_HBIT (11) ++#define DC_CSC_MULT_BU_MASK \ ++ GENMASK(DC_CSC_MULT_BU_HBIT, DC_CSC_MULT_BU_LBIT) ++#define DC_CSC_MULT_BU_MD0 (0x820) << DC_CSC_MULT_BU_LBIT ++#define DC_CSC_MULT_BU_MD1 (0x812) << DC_CSC_MULT_BU_LBIT ++#define DC_CSC_MULT_BU_MD2 (0x717) << DC_CSC_MULT_BU_LBIT ++#define DC_CSC_MULT_BU_MD3 (0x6ee) << DC_CSC_MULT_BU_LBIT ++ ++/* CscSubYUV */ ++ ++#define DC_CSC_SUB_Y_LBIT (0) ++#define DC_CSC_SUB_Y_HBIT (4) ++#define DC_CSC_SUB_Y_MASK \ ++ GENMASK(DC_CSC_SUB_Y_HBIT, DC_CSC_SUB_Y_LBIT) ++#define DC_CSC_SUB_Y_MD0 (0x00) << DC_CSC_SUB_Y_LBIT ++#define DC_CSC_SUB_Y_MD1 (0x00) << DC_CSC_SUB_Y_LBIT ++#define DC_CSC_SUB_Y_MD2 (0x00) << DC_CSC_SUB_Y_LBIT ++#define DC_CSC_SUB_Y_MD3 (0x00) << DC_CSC_SUB_Y_LBIT ++ ++#define DC_CSC_SUB_UV_LBIT (16) ++#define DC_CSC_SUB_UV_HBIT (23) ++#define DC_CSC_SUB_UV_MASK \ ++ GENMASK(DC_CSC_SUB_UV_HBIT, DC_CSC_SUB_UV_LBIT) ++#define DC_CSC_SUB_UV_MD0 (0x00) << DC_CSC_SUB_UV_LBIT ++#define DC_CSC_SUB_UV_MD1 (0x80) << DC_CSC_SUB_UV_LBIT ++#define DC_CSC_SUB_UV_MD2 (0x80) << DC_CSC_SUB_UV_LBIT ++#define DC_CSC_SUB_UV_MD3 (0x80) << DC_CSC_SUB_UV_LBIT ++ ++/* Common(DISP_COM) bit field define */ ++ ++/* Dither drop bit. */ ++#define DC_DP_DITHER_DW_LBIT (16) ++#define DC_DP_DITHER_DW_HBIT (21) ++#define DC_DP_DITHER_DW_MASK \ ++ GENMASK(DC_DP_DITHER_DW_HBIT, DC_DP_DITHER_DW_LBIT) ++#define DC_DP_DITHER_DW_BLUE_LBIT (16) ++#define DC_DP_DITHER_DW_GREEN_LBIT (18) ++#define DC_DP_DITHER_DW_RED_LBIT (20) ++#define DC_DP_DITHER_DROP_0_BITS (0) ++#define DC_DP_DITHER_DROP_2_BITS (1) ++#define DC_DP_DITHER_DROP_3_BITS (2) ++#define DC_DP_DITHER_DROP_4_BITS (3) ++#define DC_RGB888_TO_RGB565_DITHER (0b100110) << DC_DP_DITHER_DW_LBIT ++#define DC_RGB888_TO_RGB666_DITHER (0b010101) << DC_DP_DITHER_DW_LBIT ++/* Dither Clk gate enable */ ++#define DC_DITHER_CLKGATE_EN BIT(4) ++/* SLCD Clk gate enable */ ++#define DC_SLCD_CLKGATE_EN BIT(3) ++/* TFT Clk gate enable */ ++#define DC_TFT_CLKGATE_EN BIT(2) ++/* Dither enable. 1:dither enable 0:dither disable */ ++#define DC_DP_DITHER_EN BIT(4) ++/* Display interfaces select. 1:TFT 2:SLCD */ ++ ++#define DC_DP_IF_SEL_LBIT (0) ++#define DC_DP_IF_SEL_HBIT (1) ++#define DC_DP_IF_SEL_MASK GENMASK(DC_DP_IF_SEL_HBIT, DC_DP_IF_SEL_LBIT) ++#define DC_DISP_COM_NO_DISP (0b00) << DC_DP_IF_SEL_LBIT ++#define DC_DISP_COM_TFT (0b01) << DC_DP_IF_SEL_LBIT ++#define DC_DISP_COM_SLCD (0b10) << DC_DP_IF_SEL_LBIT ++#define DC_DISP_COM_MIPI_SLCD (0b11) << DC_DP_IF_SEL_LBIT ++ ++/* TIMING_HSYNC(TFT_TIMING_HSYNC) bit field define */ ++ ++/* HSYNC pulse start point(base on dot clock cycle) */ ++#define DC_HPS_LBIT (16) ++#define DC_HPS_HBIT (27) ++#define DC_HPS_MASK \ ++ GENMASK(DC_HPS_HBIT, DC_HPS_LBIT) ++/* HSYNC pulse end point(base on dot clock cycle) */ ++#define DC_HPE_LBIT (0) ++#define DC_HPE_HBIT (11) ++#define DC_HPE_MASK \ ++ GENMASK(DC_HPE_HBIT, DC_HPE_LBIT) ++ ++/* TIMING_VSYNC(TFT_TIMING_VSYNC) bit field define */ ++ ++/* VSYNC pulse start point(base on dot clock cycle) */ ++#define DC_VPS_LBIT (16) ++#define DC_VPS_HBIT (27) ++#define DC_VPS_MASK \ ++ GENMASK(DC_VPS_HBIT, DC_VPS_LBIT) ++/* VSYNC pulse end point(base on dot clock cycle) */ ++#define DC_VPE_LBIT (0) ++#define DC_VPE_HBIT (11) ++#define DC_VPE_MASK \ ++ GENMASK(DC_VPE_HBIT, DC_VPE_LBIT) ++ ++/* TIMING_HDE(TFT_TIMING_HDE) bit field define */ ++ ++/* Horizontal display area start point (base on dot clock cycle). ++ * And it is also the DE pulse start point in horizontal. ++ * It indicate the end point of vertical back porch.*/ ++#define DC_HDS_LBIT (16) ++#define DC_HDS_HBIT (27) ++#define DC_HDS_MASK \ ++ GENMASK(HDE_HDS_HBIT, DC_HDS_LBIT) ++/* Horizontal display area end point (base on dot clock cycle). ++ * And it is also the DE pulse end point in horizontal. ++ * It indicate the end point of horizontal front porch.*/ ++#define DC_HDE_LBIT (0) ++#define DC_HDE_HBIT (11) ++#define DC_HDE_MASK \ ++ GENMASK(DC_HDE_HBIT, DC_HDE_LBIT) ++ ++/* TIMING_VDE(TFT_TIMING_VDE) bit field define */ ++ ++/* Vertical display area start point(base on dot clock cycle). ++ * And it is also the DE pulse start point in vertical. ++ * It indicate the end point of vertical back porch. */ ++#define DC_VDS_LBIT (16) ++#define DC_VDS_HBIT (27) ++#define DC_VDS_MASK \ ++ GENMASK(VDE_VDS_HBIT, DC_VDS_LBIT) ++/* Vertical display area end point(base on dot clock cycle). ++ * And it is also the DE pulse end point in vertical. ++ * It indicate the start point of vertical front porch. */ ++#define DC_VDE_LBIT (0) ++#define DC_VDE_HBIT (11) ++#define DC_VDE_MASK \ ++ GENMASK(DC_VDE_HBIT, DC_VDE_LBIT) ++ ++/* TRANS_CONFIG(TFT_TRAN_CFG) bit field define */ ++ ++/* Inverse the polarity of the DOT_CLK */ ++#define DC_PIX_CLK_INV BIT(10) ++/* Default level of DE(invalid level) */ ++#define DC_DE_DL BIT(9) ++/* Default level of HSYNC and VSYNC(invalid level) */ ++#define DC_SYNC_DL BIT(8) ++/* Output color mode of even lines(2,4,6...) */ ++#define DC_COLOR_EVEN_LBIT (19) ++#define DC_COLOR_EVEN_HBIT (21) ++#define DC_COLOR_EVEN_MASK \ ++ GENMASK(DC_COLOR_EVEN_HBIT, DC_COLOR_EVEN_LBIT) ++#define DC_EVEN_RGB (0b000) << DC_COLOR_EVEN_LBIT ++#define DC_EVEN_RBG (0b001) << DC_COLOR_EVEN_LBIT ++#define DC_EVEN_BGR (0b010) << DC_COLOR_EVEN_LBIT ++#define DC_EVEN_BRG (0b011) << DC_COLOR_EVEN_LBIT ++#define DC_EVEN_GBR (0b100) << DC_COLOR_EVEN_LBIT ++#define DC_EVEN_GRB (0b101) << DC_COLOR_EVEN_LBIT ++/* Output color mode of odd lines(1, 3, 5...) */ ++#define DC_COLOR_ODD_LBIT (16) ++#define DC_COLOR_ODD_HBIT (18) ++#define DC_COLOR_ODD_MASK \ ++ GENMASK(DC_COLOR_ODD_HBIT, DC_COLOR_ODD_LBIT) ++#define DC_ODD_RGB (0b000) << DC_COLOR_ODD_LBIT ++#define DC_ODD_RBG (0b001) << DC_COLOR_ODD_LBIT ++#define DC_ODD_BGR (0b010) << DC_COLOR_ODD_LBIT ++#define DC_ODD_BRG (0b011) << DC_COLOR_ODD_LBIT ++#define DC_ODD_GBR (0b100) << DC_COLOR_ODD_LBIT ++#define DC_ODD_GRB (0b101) << DC_COLOR_ODD_LBIT ++/* 0x:0x: 24bits parallel mode ++ * 10: 8bits serial mode without dummy(RGB) ++ * 11: 8bits serial mode with dummy(RGBD)*/ ++#define DC_MODE_LBIT (0) ++#define DC_MODE_HBIT (2) ++#define DC_MODE_MASK \ ++ GENMASK(DC_MODE_HBIT, DC_MODE_LBIT) ++#define DC_MODE_PARALLEL_888 (0b000) << DC_MODE_LBIT ++#define DC_MODE_PARALLEL_666 (0b001) << DC_MODE_LBIT ++#define DC_MODE_PARALLEL_565 (0b010) << DC_MODE_LBIT ++#define DC_MODE_SERIAL_8BIT_RGB (0b100) << DC_MODE_LBIT ++#define DC_MODE_SERIAL_8BIT_RGBD (0b101) << DC_MODE_LBIT ++ ++/* STATUS(TFT_ST) bit field define */ ++ ++/* 0: TFT is not working 1: TFT is working */ ++#define DC_TFT_WORKING BIT(1) ++/* Indicate the controller jump into recovery state, ++ * and starting trans one frame 0 to panel. ++ * 0: TFT is working order 1: TFT is in UNDER mode.*/ ++#define DC_TFT_UNDER BIT(0) ++ ++/* SLCD_CONFIG(SLCD_PANEL_CFG) bit field define */ ++ ++/* Anti-jitter for RDY. ++ * 0: sample RDY with 1 pixclk cycle(default) ++ * 1: sample RDY with 3 pixclk cycles for anti-jitter.*/ ++#define DC_RDY_ANTI_JIT BIT(27) ++/* Whether the pixel data or command need conversion ++ * 0: no use conversion, such as parameter of command(default) ++ * 1: need conversion, such as pixel data*/ ++#define DC_FMT_EN BIT(26) ++/* 001: typeA(6800) 010: typeB(8080)(default) 100: typeC(SPI) */ ++#define DC_DBI_TYPE_LBIT (23) ++#define DC_DBI_TYPE_HBIT (25) ++#define DC_DBI_TYPE_MASK \ ++ GENMASK(DC_DBI_TYPE_HBIT, DC_DBI_TYPE_LBIT) ++#define DC_DBI_TYPE_A_6800 (0b001) << DC_DBI_TYPE_LBIT ++#define DC_DBI_TYPE_B_8080 (0b010) << DC_DBI_TYPE_LBIT ++#define DC_DBI_TYPE_C_SPI_3 (0b100) << DC_DBI_TYPE_LBIT ++#define DC_DBI_TYPE_C_SPI_4 (0b101) << DC_DBI_TYPE_LBIT ++/* Color format. ++ * 00: 565 01: 666 10: 888(default) */ ++#define DC_DATA_FMT_LBIT (21) ++#define DC_DATA_FMT_HBIT (22) ++#define DC_DATA_FMT_MASK \ ++ GENMASK(DC_DATA_FMT_HBIT, DC_DATA_FMT_LBIT) ++#define DC_DATA_FMT_565 (0b00) << DC_DATA_FMT_LBIT ++#define DC_DATA_FMT_444 (0b01) << DC_DATA_FMT_LBIT ++#define DC_DATA_FMT_666 (0b01) << DC_DATA_FMT_LBIT ++#define DC_DATA_FMT_888 (0b10) << DC_DATA_FMT_LBIT ++/* Anti-jitter for TE. ++ * 0: sample TE with 1 pixclk cycle; ++ * 1: sample TE with 3 pixclk cycles for anti-jitter(default).*/ ++#define DC_TE_ANTI_JIT BIT(20) ++/* The active edge of TE. ++ * 0: the front edge(default) 1: the back edge*/ ++#define DC_TE_MD BIT(19) ++/* 0: do not wait TE, send pix_data after SLCD_START; ++ * 1: wait TE, and then send pix_data.(default)*/ ++#define DC_TE_SWITCH BIT(18) ++/* 0: do not wait RDY, send command or data immediately;(default) ++ * 1: wait RDY, and then send command or data. */ ++#define DC_RDY_SWITCH BIT(17) ++/* CS control enable. ++ * 0: The CS pin is controlled by GPIO.(default) ++ * 1: The CS pin is controlled by Display Controller. */ ++#define DC_CS_EN BIT(16) ++/* The CS's default polarity ++ * 0: the default(invalid) level is low; ++ * 1: the default(invalid) level is high;(default) */ ++#define DC_CS_DP BIT(11) ++/* The RDY's default polarity ++ * 0: the default(invalid) level is low; ++ * 1: the default(invalid) level is high;(default) */ ++#define DC_RDY_DP BIT(10) ++/* DC's definition. ++ * 0: Command DC = low, Data DC = high(default) ++ * 1: Command DC = high, Data DC = low */ ++#define DC_DC_MD BIT(9) ++/* WR's default polarity. ++ * 0: drive at posedge, and sample at negedge; ++ * 1: drive at negedge, and sample at posedge.(default) */ ++#define DC_WR_DP BIT(8) ++///* SPI_CLK Polarity. ++// * 0: Active edge is Falling(default) ++// * 1: Active edge is Rising Used for serial transfer mode. */ ++//#define DC_CLKPLY BIT(7) ++ ++#define DC_TE_MIPI_SWITCH BIT(7) ++ ++/* The TE' default polarity ++ * 0: the default(invalid) level is low;(default) ++ * 1: the default(invalid) level is high; */ ++#define DC_TE_DP BIT(6) ++/* Panel's data width. It's also used in MIPI DSI command mod ++ * 000: 8bits 001: 9bits 010: 16bits 011: 18bits 100: 24bits(default) */ ++#define DC_DWIDTH_LBIT (3) ++#define DC_DWIDTH_HBIT (5) ++#define DC_DWIDTH_MASK \ ++ GENMASK(DC_DWIDTH_HBIT, DC_DWIDTH_LBIT) ++#define DC_DWIDTH_8BITS (0b000) << DC_DWIDTH_LBIT ++#define DC_DWIDTH_9BITS (0b001) << DC_DWIDTH_LBIT ++#define DC_DWIDTH_16BITS (0b010) << DC_DWIDTH_LBIT ++#define DC_DWIDTH_18BITS (0b011) << DC_DWIDTH_LBIT ++#define DC_DWIDTH_24BITS (0b100) << DC_DWIDTH_LBIT ++/* The width of panel's command and it's parameters ++ * 000: 8bits(default) 001: 9bits 010: 16bits 011: 18bits 100: 24bits */ ++#define DC_CWIDTH_LBIT (0) ++#define DC_CWIDTH_HBIT (2) ++#define DC_CWIDTH_MASK \ ++ GENMASK(DC_CWIDTH_HBIT, DC_CWIDTH_LBIT) ++#define DC_CWIDTH_8BITS (0b000) << DC_CWIDTH_LBIT ++#define DC_CWIDTH_9BITS (0b001) << DC_CWIDTH_LBIT ++#define DC_CWIDTH_16BITS (0b010) << DC_CWIDTH_LBIT ++#define DC_CWIDTH_18BITS (0b011) << DC_CWIDTH_LBIT ++#define DC_CWIDTH_24BITS (0b100) << DC_CWIDTH_LBIT ++ ++/* SLCD_WR_DUTY(SLCD_WR_DUTY) bit field define */ ++ ++/* WR's high time period when transmitting data ++ * (base on MIPI DBI Type B, and this is low time at Type A) */ ++#define DC_DSTIME_LBIT (24) ++#define DC_DSTIME_HBIT (31) ++#define DC_DSTIME_MASK \ ++ GENMASK(DC_DSTIME_HBIT, DC_DSTIME_LBIT) ++/* WR's low time period when transmitting data ++ * (base on MIPI DBI Type B, and this is high time at Type A) */ ++#define DC_DDTIME_LBIT (16) ++#define DC_DDTIME_HBIT (23) ++#define DC_DDTIME_MASK \ ++ GENMASK(DC_DDTIME_HBIT, DC_DDTIME_LBIT) ++/* WR's high time period when transmitting command ++ * (base on MIPI DBI Type B, and this is low time at Type A) */ ++#define DC_CSTIME_LBIT (8) ++#define DC_CSTIME_HBIT (15) ++#define DC_CSTIME_MASK \ ++ GENMASK(DC_CSTIME_HBIT, DC_CSTIME_LBIT) ++/* WR's low time period when transmitting command ++ * (base on MIPI DBI Type B, and this is high time at Type A) */ ++#define DC_CDTIME_LBIT (0) ++#define DC_CDTIME_HBIT (7) ++#define DC_CDTIME_MASK \ ++ GENMASK(DC_CDTIME_HBIT, DC_CDTIME_LBIT) ++ ++/* SLCD_TIMING(SLCD_TIMING) bit field define */ ++#define DC_TCH_LBIT (24) ++#define DC_TCH_HBIT (31) ++#define DC_TCH_MASK \ ++ GENMASK(DC_TCH_HBIT, DC_TCH_LBIT) ++#define DC_TCS_LBIT (16) ++#define DC_TCS_HBIT (23) ++#define DC_TCS_MASK \ ++ GENMASK(DC_TCS_HBIT, DC_TCS_LBIT) ++#define DC_TAH_LBIT (8) ++#define DC_TAH_HBIT (15) ++#define DC_TAH_MASK \ ++ GENMASK(DC_TAH_HBIT, DC_TAH_LBIT) ++#define DC_TAS_LBIT (0) ++#define DC_TAS_HBIT (7) ++#define DC_TAS_MASK \ ++ GENMASK(DC_TAS_HBIT, DC_TAS_LBIT) ++ ++/* SLCD_FRM_SIZE(SLCD_FRM_SIZE) bit field define */ ++ ++/* Line number of each frame. */ ++#define DC_SLCD_FRM_V_SIZE_LBIT (16) ++#define DC_SLCD_FRM_V_SIZE_HBIT (31) ++#define DC_SLCD_FRM_V_SIZE_MASK \ ++ GENMASK(DC_SLCD_FRM_V_SIZE_HBIT, DC_SLCD_FRM_V_SIZE_LBIT) ++/* Pixel number of each line. */ ++#define DC_SLCD_FRM_H_SIZE_LBIT (0) ++#define DC_SLCD_FRM_H_SIZE_HBIT (15) ++#define DC_SLCD_FRM_H_SIZE_MASK \ ++ GENMASK(DC_SLCD_FRM_H_SIZE_HBIT, DC_SLCD_FRM_H_SIZE_LBIT) ++ ++/* SLCD_SLOW_TIME(SLCD_SLOW_TIME) bit field define */ ++ ++/* SLCD will delay some period of pixclk before transmitting data, ++ * after TE鈥檚 relative edge. */ ++#define DC_SLOW_TIME_LBIT (0) ++#define DC_SLOW_TIME_HBIT (15) ++#define DC_SLOW_TIME_MASK \ ++ GENMASK(DC_SLOW_TIME_HBIT, DC_SLOW_TIME_LBIT) ++ ++/* SLCD_REG_IF(SLCD_REG_IF) bit field define */ ++ ++/* It is used to decide the meanings of the DATA/CMD/PARAMETER. ++ * 00: pix_data; 01: parameter; 1x: command(default). */ ++#define DC_SLCD_REG_IF_FLAG_LBIT (30) ++#define DC_SLCD_REG_IF_FLAG_HBIT (31) ++#define DC_SLCD_REG_IF_FLAG_MASK \ ++ GENMASK(DC_SLCD_REG_IF_FLAG_HBIT, DC_SLCD_REG_IF_FLAG_LBIT) ++#define DC_SLCD_REG_IF_FLAG_DATA (0b00) << DC_SLCD_REG_IF_FLAG_LBIT ++#define DC_SLCD_REG_IF_FLAG_PRM (0b01) << DC_SLCD_REG_IF_FLAG_LBIT ++#define DC_SLCD_REG_IF_FLAG_CMD (0b10) << DC_SLCD_REG_IF_FLAG_LBIT ++/* Indicate this is the last content, the hardware will disable the CS */ ++#define DC_SLCD_REG_IF_END BIT(29) ++/* content */ ++#define DC_SLCD_REG_IF_CONTENT_LBIT (0) ++#define DC_SLCD_REG_IF_CONTENT_HBIT (23) ++#define DC_SLCD_REG_IF_CONTENT_MASK \ ++ GENMASK(DC_SLCD_REG_IF_CONTENT_HBIT, DC_SLCD_REG_IF_CONTENT_LBIT) ++ ++/* SLCD_STATUS(SLCD_ST) bit field define */ ++ ++/* Indicate whether the SLCD DBI interface controller is working or not. ++ * 0: idle 1: busy */ ++#define DC_SLCD_ST_BUSY BIT(0) ++ ++#endif /* _DPU_REG_H_ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_ingenicfb.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_ingenicfb.c.patch new file mode 100644 index 00000000..8fe93857 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_ingenicfb.c.patch @@ -0,0 +1,4387 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v12/ingenicfb.c b/drivers/video/fbdev/ingenic/fb_v12/ingenicfb.c +--- a/drivers/video/fbdev/ingenic/fb_v12/ingenicfb.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v12/ingenicfb.c 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,4383 @@ ++/* ++ * drivers/video/fbdev/ingenic/x2000_v12/ingenicfb.c ++ * ++ * Copyright (c) 2012 Ingenic Semiconductor Co., Ltd. ++ * http://www.ingenic.com/ ++ * ++ * Core file for Ingenic Display Controller driver ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "dpu_reg.h" ++#include "ingenicfb.h" ++#include ++ ++ ++#ifdef CONFIG_INGENIC_FB_BOOT_PATTERN ++#include "../../../logo/MTF070_800x1280_nv12.h" ++#endif ++ ++#define dpu_debug 1 ++#define print_dbg(f, arg...) if(dpu_debug) printk(KERN_INFO "dpu: %s, %d: " f "\n", __func__, __LINE__, ## arg) ++ ++#define COMPOSER_DIRECT_OUT_EN ++ ++#ifdef CONFIG_FB_INGENIC_MIPI_DSI ++#include "./jz_mipi_dsi/jz_mipi_dsih_hal.h" ++#include "./jz_mipi_dsi/jz_mipi_dsi_regs.h" ++#include "./jz_mipi_dsi/jz_mipi_dsi_lowlevel.h" ++extern struct dsi_device * jzdsi_init(struct jzdsi_data *pdata); ++extern void jzdsi_remove(struct dsi_device *dsi); ++extern void dump_dsi_reg(struct dsi_device *dsi); ++int jz_mipi_dsi_set_client(struct dsi_device *dsi, int power); ++#endif ++ ++#ifdef CONFIG_TRUE_COLOR_LOGO ++extern void show_logo(struct fb_info *info); ++#endif ++ ++struct lcd_panel *fbdev_panel = NULL; ++struct platform_device *fbdev_pdev = NULL; ++static unsigned int cmp_gen_sop = 0; ++static int uboot_inited; ++static int showFPS = 0; ++static int over_cnt = 0; ++static struct ingenicfb_device *fbdev; ++ ++#ifdef CONFIG_FB_VSYNC_SKIP_DISABLE ++static unsigned int old_desc_addr = 0; ++#endif ++ ++/* #define TEST_IRQ */ ++ ++static const struct fb_fix_screeninfo ingenicfb_fix = { ++ .id = "ingenicfb", ++ .type = FB_TYPE_PACKED_PIXELS, ++ .visual = FB_VISUAL_TRUECOLOR, ++ .xpanstep = 0, ++ .ypanstep = 1, ++ .ywrapstep = 0, ++ .accel = FB_ACCEL_NONE, ++}; ++ ++struct ingenicfb_colormode { ++ uint32_t mode; ++ const char *name; ++ uint32_t color; ++ uint32_t bits_per_pixel; ++ uint32_t nonstd; ++ struct fb_bitfield red; ++ struct fb_bitfield green; ++ struct fb_bitfield blue; ++ struct fb_bitfield transp; ++}; ++ ++static struct ingenicfb_colormode ingenicfb_colormodes[] = { ++ { ++ .mode = LAYER_CFG_FORMAT_RGB888, ++ .name = "rgb888", ++ .color = LAYER_CFG_COLOR_RGB, ++ .bits_per_pixel = 32, ++ .nonstd = 0, ++#ifdef CONFIG_ANDROID ++ .color = LAYER_CFG_COLOR_BGR, ++ .red = { .length = 8, .offset = 0, .msb_right = 0 }, ++ .green = { .length = 8, .offset = 8, .msb_right = 0 }, ++ .blue = { .length = 8, .offset = 16, .msb_right = 0 }, ++#else ++ .color = LAYER_CFG_COLOR_RGB, ++ .red = { .length = 8, .offset = 16, .msb_right = 0 }, ++ .green = { .length = 8, .offset = 8, .msb_right = 0 }, ++ .blue = { .length = 8, .offset = 0, .msb_right = 0 }, ++#endif ++ .transp = { .length = 0, .offset = 0, .msb_right = 0 }, ++ }, { ++ .mode = LAYER_CFG_FORMAT_ARGB8888, ++ .name = "argb888", ++ .bits_per_pixel = 32, ++ .nonstd = 0, ++#ifdef CONFIG_ANDROID ++ .color = LAYER_CFG_COLOR_BGR, ++ .red = { .length = 8, .offset = 0, .msb_right = 0 }, ++ .green = { .length = 8, .offset = 8, .msb_right = 0 }, ++ .blue = { .length = 8, .offset = 16, .msb_right = 0 }, ++#else ++ .color = LAYER_CFG_COLOR_RGB, ++ .red = { .length = 8, .offset = 16, .msb_right = 0 }, ++ .green = { .length = 8, .offset = 8, .msb_right = 0 }, ++ .blue = { .length = 8, .offset = 0, .msb_right = 0 }, ++#endif ++ .transp = { .length = 8, .offset = 24, .msb_right = 0 }, ++ }, { ++ .mode = LAYER_CFG_FORMAT_RGB555, ++ .name = "rgb555", ++ .color = LAYER_CFG_COLOR_RGB, ++ .bits_per_pixel = 16, ++ .nonstd = 0, ++ .red = { .length = 5, .offset = 10, .msb_right = 0 }, ++ .green = { .length = 5, .offset = 5, .msb_right = 0 }, ++ .blue = { .length = 5, .offset = 0, .msb_right = 0 }, ++ .transp = { .length = 0, .offset = 0, .msb_right = 0 }, ++ }, { ++ .mode = LAYER_CFG_FORMAT_ARGB1555, ++ .name = "argb1555", ++ .color = LAYER_CFG_COLOR_RGB, ++ .bits_per_pixel = 16, ++ .nonstd = 0, ++ .red = { .length = 5, .offset = 10, .msb_right = 0 }, ++ .green = { .length = 5, .offset = 5, .msb_right = 0 }, ++ .blue = { .length = 5, .offset = 0, .msb_right = 0 }, ++ .transp = { .length = 1, .offset = 15, .msb_right = 0 }, ++ }, { ++ .mode = LAYER_CFG_FORMAT_RGB565, ++ .name = "rgb565", ++ .color = LAYER_CFG_COLOR_RGB, ++ .bits_per_pixel = 16, ++ .nonstd = 0, ++ .red = { .length = 5, .offset = 11, .msb_right = 0 }, ++ .green = { .length = 6, .offset = 5, .msb_right = 0 }, ++ .blue = { .length = 5, .offset = 0, .msb_right = 0 }, ++ .transp = { .length = 0, .offset = 0, .msb_right = 0 }, ++ }, { ++ .mode = LAYER_CFG_FORMAT_YUV422, ++ .name = "yuv422", ++ .bits_per_pixel = 16, ++ .nonstd = LAYER_CFG_FORMAT_YUV422, ++ }, { ++ .mode = LAYER_CFG_FORMAT_NV12, ++ .name = "nv12", ++ .bits_per_pixel = 16, ++ .nonstd = LAYER_CFG_FORMAT_NV12, ++ }, { ++ .mode = LAYER_CFG_FORMAT_NV21, ++ .name = "nv21", ++ .bits_per_pixel = 16, ++ .nonstd = LAYER_CFG_FORMAT_NV21, ++ }, ++}; ++ ++static void dump_dc_reg(void) ++{ ++ printk("-----------------dc_reg------------------\n"); ++ printk("DC_FRM_CFG_ADDR(0x%04x): 0x%08lx\n", DC_FRM_CFG_ADDR,reg_read(fbdev, DC_FRM_CFG_ADDR)); ++ printk("DC_FRM_CFG_CTRL(0x%04x): 0x%08lx\n", DC_FRM_CFG_CTRL,reg_read(fbdev, DC_FRM_CFG_CTRL)); ++ printk("DC_RDMA_CHAIN_ADDR(0x%04x): 0x%08lx\n", DC_RDMA_CHAIN_ADDR,reg_read(fbdev, DC_RDMA_CHAIN_ADDR)); ++ printk("DC_RDMA_CHAIN_CTRL(0x%04x): 0x%08lx\n", DC_RDMA_CHAIN_CTRL,reg_read(fbdev, DC_RDMA_CHAIN_CTRL)); ++ printk("DC_CTRL(0x%04x): 0x%08lx\n", DC_CTRL, reg_read(fbdev, DC_CTRL)); ++ printk("DC_CSC_MULT_YRV(0x%04x): 0x%08lx\n", DC_CSC_MULT_YRV,reg_read(fbdev, DC_CSC_MULT_YRV)); ++ printk("DC_CSC_MULT_GUGV(0x%04x): 0x%08lx\n", DC_CSC_MULT_GUGV,reg_read(fbdev, DC_CSC_MULT_GUGV)); ++ printk("DC_CSC_MULT_BU(0x%04x): 0x%08lx\n", DC_CSC_MULT_BU,reg_read(fbdev, DC_CSC_MULT_BU)); ++ printk("DC_CSC_SUB_YUV(0x%04x): 0x%08lx\n", DC_CSC_SUB_YUV,reg_read(fbdev, DC_CSC_SUB_YUV)); ++ printk("DC_ST(0x%04x): 0x%08lx\n", DC_ST, reg_read(fbdev, DC_ST)); ++ printk("DC_INTC(0x%04x): 0x%08lx\n", DC_INTC, reg_read(fbdev, DC_INTC)); ++ printk("DC_INT_FLAG(0x%04x): 0x%08lx\n", DC_INT_FLAG, reg_read(fbdev, DC_INT_FLAG)); ++ printk("DC_COM_CONFIG(0x%04x): 0x%08lx\n", DC_COM_CONFIG ,reg_read(fbdev, DC_COM_CONFIG)); ++ printk("DC_TLB_GLBC(0x%04x): 0x%08lx\n", DC_TLB_GLBC,reg_read(fbdev, DC_TLB_GLBC)); ++ printk("DC_TLB_TLBA(0x%04x): 0x%08lx\n", DC_TLB_TLBA,reg_read(fbdev, DC_TLB_TLBA)); ++ printk("DC_TLB_TLBC(0x%04x): 0x%08lx\n", DC_TLB_TLBC,reg_read(fbdev, DC_TLB_TLBC)); ++ printk("DC_TLB0_VPN(0x%04x): 0x%08lx\n", DC_TLB0_VPN,reg_read(fbdev, DC_TLB0_VPN)); ++ printk("DC_TLB1_VPN(0x%04x): 0x%08lx\n", DC_TLB1_VPN,reg_read(fbdev, DC_TLB1_VPN)); ++ printk("DC_TLB2_VPN(0x%04x): 0x%08lx\n", DC_TLB2_VPN,reg_read(fbdev, DC_TLB2_VPN)); ++ printk("DC_TLB3_VPN(0x%04x): 0x%08lx\n", DC_TLB3_VPN,reg_read(fbdev, DC_TLB3_VPN)); ++ printk("DC_TLB_TLBV(0x%04x): 0x%08lx\n", DC_TLB_TLBV,reg_read(fbdev, DC_TLB_TLBV)); ++ printk("DC_TLB_STAT(0x%04x): 0x%08lx\n", DC_TLB_STAT,reg_read(fbdev, DC_TLB_STAT)); ++ printk("DC_PCFG_RD_CTRL(0x%04x): 0x%08lx\n", DC_PCFG_RD_CTRL,reg_read(fbdev, DC_PCFG_RD_CTRL)); ++ printk("DC_PCFG_WR_CTRL(0x%04x): 0x%08lx\n", DC_PCFG_WR_CTRL,reg_read(fbdev, DC_PCFG_WR_CTRL)); ++ printk("DC_OFIFO_PCFG(0x%04x): 0x%08lx\n", DC_OFIFO_PCFG,reg_read(fbdev, DC_OFIFO_PCFG)); ++ printk("DC_WDMA_PCFG(0x%04x): 0x%08lx\n", DC_WDMA_PCFG,reg_read(fbdev, DC_WDMA_PCFG)); ++ printk("DC_CMPW_PCFG_CTRL(0x%04x): 0x%08lx\n", DC_CMPW_PCFG_CTRL,reg_read(fbdev, DC_CMPW_PCFG_CTRL)); ++ printk("DC_CMPW_PCFG0(0x%04x): 0x%08lx\n", DC_CMPW_PCFG0,reg_read(fbdev, DC_CMPW_PCFG0)); ++ printk("DC_CMPW_PCFG1(0x%04x): 0x%08lx\n", DC_CMPW_PCFG1,reg_read(fbdev, DC_CMPW_PCFG1)); ++ printk("DC_CMPW_PCFG2(0x%04x): 0x%08lx\n", DC_CMPW_PCFG2,reg_read(fbdev, DC_CMPW_PCFG2)); ++ printk("DC_PCFG_RD_CTRL(0x%04x): 0x%08lx\n", DC_PCFG_RD_CTRL,reg_read(fbdev, DC_PCFG_RD_CTRL)); ++ printk("DC_OFIFO_PCFG(0x%04x): 0x%08lx\n", DC_OFIFO_PCFG,reg_read(fbdev, DC_OFIFO_PCFG)); ++ printk("DC_DISP_COM(0x%04x): 0x%08lx\n", DC_DISP_COM,reg_read(fbdev, DC_DISP_COM)); ++ printk("-----------------dc_reg------------------\n"); ++} ++ ++static void dump_tft_reg(void) ++{ ++ printk("----------------tft_reg------------------\n"); ++ printk("TFT_TIMING_HSYNC(0x%04x): 0x%08lx\n", DC_TFT_HSYNC, reg_read(fbdev, DC_TFT_HSYNC)); ++ printk("TFT_TIMING_VSYNC(0x%04x): 0x%08lx\n", DC_TFT_VSYNC, reg_read(fbdev, DC_TFT_VSYNC)); ++ printk("TFT_TIMING_HDE(0x%04x): 0x%08lx\n", DC_TFT_HDE, reg_read(fbdev, DC_TFT_HDE)); ++ printk("TFT_TIMING_VDE(0x%04x): 0x%08lx\n", DC_TFT_VDE, reg_read(fbdev, DC_TFT_VDE)); ++ printk("TFT_TRAN_CFG(0x%04x): 0x%08lx\n", DC_TFT_CFG, reg_read(fbdev, DC_TFT_CFG)); ++ printk("TFT_ST(0x%04x): 0x%08lx\n", DC_TFT_ST, reg_read(fbdev, DC_TFT_ST)); ++ printk("----------------tft_reg------------------\n"); ++} ++ ++static void dump_slcd_reg(void) ++{ ++ printk("---------------slcd_reg------------------\n"); ++ printk("SLCD_CFG(0x%04x): 0x%08lx\n", DC_SLCD_CFG, reg_read(fbdev, DC_SLCD_CFG)); ++ printk("SLCD_WR_DUTY(0x%04x): 0x%08lx\n", DC_SLCD_WR_DUTY, reg_read(fbdev, DC_SLCD_WR_DUTY)); ++ printk("SLCD_TIMING(0x%04x): 0x%08lx\n", DC_SLCD_TIMING, reg_read(fbdev, DC_SLCD_TIMING)); ++ printk("SLCD_FRM_SIZE(0x%04x): 0x%08lx\n", DC_SLCD_FRM_SIZE, reg_read(fbdev, DC_SLCD_FRM_SIZE)); ++ printk("SLCD_SLOW_TIME(0x%04x): 0x%08lx\n", DC_SLCD_SLOW_TIME, reg_read(fbdev, DC_SLCD_SLOW_TIME)); ++ printk("SLCD_REG_IF(0x%04x): 0x%08lx\n", DC_SLCD_REG_IF, reg_read(fbdev, DC_SLCD_REG_IF)); ++ printk("SLCD_ST(0x%04x): 0x%08lx\n", DC_SLCD_ST, reg_read(fbdev, DC_SLCD_ST)); ++ printk("---------------slcd_reg------------------\n"); ++} ++ ++static void dump_frm_desc_reg(void) ++{ ++ unsigned int ctrl; ++ ctrl = reg_read(fbdev, DC_CTRL); ++ ctrl |= DC_DES_CNT_RST; ++ reg_write(fbdev, DC_CTRL, ctrl); ++ ++ printk("--------Frame Descriptor register--------\n"); ++ printk("FrameNextCfgAddr: %lx\n",reg_read(fbdev, DC_FRM_DES)); ++ printk("FrameSize: %lx\n",reg_read(fbdev, DC_FRM_DES)); ++ printk("FrameCtrl: %lx\n",reg_read(fbdev, DC_FRM_DES)); ++ printk("WritebackAddr: %lx\n",reg_read(fbdev, DC_FRM_DES)); ++ printk("WritebackStride: %lx\n",reg_read(fbdev, DC_FRM_DES)); ++ printk("Layer0CfgAddr: %lx\n",reg_read(fbdev, DC_FRM_DES)); ++ printk("Layer1CfgAddr: %lx\n",reg_read(fbdev, DC_FRM_DES)); ++ printk("Layer2CfgAddr: %lx\n",reg_read(fbdev, DC_FRM_DES)); ++ printk("Layer3CfgAddr: %lx\n",reg_read(fbdev, DC_FRM_DES)); ++ printk("LayCfgEn: %lx\n",reg_read(fbdev, DC_FRM_DES)); ++ printk("InterruptControl: %lx\n",reg_read(fbdev, DC_FRM_DES)); ++ printk("--------Frame Descriptor register--------\n"); ++} ++ ++static void dump_layer_desc_reg(void) ++{ ++ unsigned int ctrl; ++ ctrl = reg_read(fbdev, DC_CTRL); ++ ctrl |= DC_DES_CNT_RST; ++ reg_write(fbdev, DC_CTRL, ctrl); ++ ++ printk("--------layer0 Descriptor register-------\n"); ++ printk("LayerSize: %lx\n",reg_read(fbdev, DC_LAY0_DES)); ++ printk("LayerCfg: %lx\n",reg_read(fbdev, DC_LAY0_DES)); ++ printk("LayerBufferAddr: %lx\n",reg_read(fbdev, DC_LAY0_DES)); ++ printk("LayerScale: %lx\n",reg_read(fbdev, DC_LAY0_DES)); ++ printk("LayerRotation: %lx\n",reg_read(fbdev, DC_LAY0_DES)); ++ printk("LayerScratch: %lx\n",reg_read(fbdev, DC_LAY0_DES)); ++ printk("LayerPos: %lx\n",reg_read(fbdev, DC_LAY0_DES)); ++ printk("LayerResizeCoef_X: %lx\n",reg_read(fbdev, DC_LAY0_DES)); ++ printk("LayerResizeCoef_Y: %lx\n",reg_read(fbdev, DC_LAY0_DES)); ++ printk("LayerStride: %lx\n",reg_read(fbdev, DC_LAY0_DES)); ++// printk("Layer_UV_addr: %lx\n",reg_read(fbdev, DC_LAY0_DES)); ++// printk("Layer_UV_stride: %lx\n",reg_read(fbdev, DC_LAY0_DES)); ++ printk("--------layer0 Descriptor register-------\n"); ++ ++ printk("--------layer1 Descriptor register-------\n"); ++ printk("LayerSize: %lx\n",reg_read(fbdev, DC_LAY1_DES)); ++ printk("LayerCfg: %lx\n",reg_read(fbdev, DC_LAY1_DES)); ++ printk("LayerBufferAddr: %lx\n",reg_read(fbdev, DC_LAY1_DES)); ++ printk("LayerScale: %lx\n",reg_read(fbdev, DC_LAY1_DES)); ++ printk("LayerRotation: %lx\n",reg_read(fbdev, DC_LAY1_DES)); ++ printk("LayerScratch: %lx\n",reg_read(fbdev, DC_LAY1_DES)); ++ printk("LayerPos: %lx\n",reg_read(fbdev, DC_LAY1_DES)); ++ printk("LayerResizeCoef_X: %lx\n",reg_read(fbdev, DC_LAY1_DES)); ++ printk("LayerResizeCoef_Y: %lx\n",reg_read(fbdev, DC_LAY1_DES)); ++ printk("LayerStride: %lx\n",reg_read(fbdev, DC_LAY1_DES)); ++// printk("Layer_UV_addr: %lx\n",reg_read(fbdev, DC_LAY1_DES)); ++// printk("Layer_UV_stride: %lx\n",reg_read(fbdev, DC_LAY1_DES)); ++ printk("--------layer1 Descriptor register-------\n"); ++ ++ printk("--------layer2 Descriptor register-------\n"); ++ printk("LayerSize: %lx\n",reg_read(fbdev, DC_LAY2_DES)); ++ printk("LayerCfg: %lx\n",reg_read(fbdev, DC_LAY2_DES)); ++ printk("LayerBufferAddr: %lx\n",reg_read(fbdev, DC_LAY2_DES)); ++ printk("LayerScale: %lx\n",reg_read(fbdev, DC_LAY2_DES)); ++ printk("LayerRotation: %lx\n",reg_read(fbdev, DC_LAY2_DES)); ++ printk("LayerScratch: %lx\n",reg_read(fbdev, DC_LAY2_DES)); ++ printk("LayerPos: %lx\n",reg_read(fbdev, DC_LAY2_DES)); ++ printk("LayerResizeCoef_X: %lx\n",reg_read(fbdev, DC_LAY2_DES)); ++ printk("LayerResizeCoef_Y: %lx\n",reg_read(fbdev, DC_LAY2_DES)); ++ printk("LayerStride: %lx\n",reg_read(fbdev, DC_LAY2_DES)); ++// printk("Layer_UV_addr: %lx\n",reg_read(fbdev, DC_LAY2_DES)); ++// printk("Layer_UV_stride: %lx\n",reg_read(fbdev, DC_LAY2_DES)); ++ printk("--------layer2 Descriptor register-------\n"); ++ ++ printk("--------layer3 Descriptor register-------\n"); ++ printk("LayerSize: %lx\n",reg_read(fbdev, DC_LAY3_DES)); ++ printk("LayerCfg: %lx\n",reg_read(fbdev, DC_LAY3_DES)); ++ printk("LayerBufferAddr: %lx\n",reg_read(fbdev, DC_LAY3_DES)); ++ printk("LayerScale: %lx\n",reg_read(fbdev, DC_LAY3_DES)); ++ printk("LayerRotation: %lx\n",reg_read(fbdev, DC_LAY3_DES)); ++ printk("LayerScratch: %lx\n",reg_read(fbdev, DC_LAY3_DES)); ++ printk("LayerPos: %lx\n",reg_read(fbdev, DC_LAY3_DES)); ++ printk("LayerResizeCoef_X: %lx\n",reg_read(fbdev, DC_LAY3_DES)); ++ printk("LayerResizeCoef_Y: %lx\n",reg_read(fbdev, DC_LAY3_DES)); ++ printk("LayerStride: %lx\n",reg_read(fbdev, DC_LAY3_DES)); ++// printk("Layer_UV_addr: %lx\n",reg_read(fbdev, DC_LAY3_DES)); ++// printk("Layer_UV_stride: %lx\n",reg_read(fbdev, DC_LAY3_DES)); ++ printk("--------layer3 Descriptor register-------\n"); ++} ++ ++static void dump_rdma_desc_reg(void) ++{ ++ unsigned int ctrl; ++ ctrl = reg_read(fbdev, DC_CTRL); ++ ctrl |= (1 << 2); ++ reg_write(fbdev, DC_CTRL, ctrl); ++ printk("====================rdma Descriptor register======================\n"); ++ printk("RdmaNextCfgAddr: %lx\n",reg_read(fbdev, DC_RDMA_DES)); ++ printk("FrameBufferAddr: %lx\n",reg_read(fbdev, DC_RDMA_DES)); ++ printk("Stride: %lx\n",reg_read(fbdev, DC_RDMA_DES)); ++ printk("ChainCfg: %lx\n",reg_read(fbdev, DC_RDMA_DES)); ++ printk("InterruptControl: %lx\n",reg_read(fbdev, DC_RDMA_DES)); ++ printk("==================rdma Descriptor register end======================\n"); ++} ++ ++ ++static void dump_frm_desc(struct ingenicfb_framedesc *framedesc, int index) ++{ ++ printk("-------User Frame Descriptor index[%d]-----\n", index); ++ printk("FramedescAddr: 0x%x\n",(uint32_t)framedesc); ++ printk("FrameNextCfgAddr: 0x%x\n",framedesc->FrameNextCfgAddr); ++ printk("FrameSize: 0x%x\n",framedesc->FrameSize.d32); ++ printk("FrameCtrl: 0x%x\n",framedesc->FrameCtrl.d32); ++ printk("Layer0CfgAddr: 0x%x\n",framedesc->Layer0CfgAddr); ++ printk("Layer1CfgAddr: 0x%x\n",framedesc->Layer1CfgAddr); ++ printk("LayerCfgEn: 0x%x\n",framedesc->LayCfgEn.d32); ++ printk("InterruptControl: 0x%x\n",framedesc->InterruptControl.d32); ++ printk("-------User Frame Descriptor index[%d]-----\n", index); ++} ++ ++static void dump_layer_desc(struct ingenicfb_layerdesc *layerdesc, int row, int col) ++{ ++ printk("------User layer Descriptor index[%d][%d]------\n", row, col); ++ printk("LayerdescAddr: 0x%x\n",(uint32_t)layerdesc); ++ printk("LayerSize: 0x%x\n",layerdesc->LayerSize.d32); ++ printk("LayerCfg: 0x%x\n",layerdesc->LayerCfg.d32); ++ printk("LayerBufferAddr: 0x%x\n",layerdesc->LayerBufferAddr); ++ printk("LayerScale: 0x%x\n",layerdesc->LayerScale.d32); ++ printk("LayerResizeCoef_X: 0x%x\n",layerdesc->layerresizecoef_x); ++ printk("LayerResizeCoef_Y: 0x%x\n",layerdesc->layerresizecoef_y); ++ printk("LayerPos: 0x%x\n",layerdesc->LayerPos.d32); ++ printk("LayerStride: 0x%x\n",layerdesc->LayerStride); ++// printk("Layer_UV_addr: 0x%x\n",layer_config->BufferAddr_UV); ++// printk("Layer_UV_stride: 0x%x\n",layer_config->stride_UV); ++ printk("------User layer Descriptor index[%d][%d]------\n", row, col); ++} ++ ++void dump_lay_cfg(struct ingenicfb_lay_cfg * lay_cfg, int index) ++{ ++ printk("------User disp set index[%d]------\n", index); ++ printk("lay_en: 0x%x\n",lay_cfg->lay_en); ++ printk("tlb_en: 0x%x\n",lay_cfg->tlb_en); ++ printk("lay_scale_en: 0x%x\n",lay_cfg->lay_scale_en); ++ printk("lay_z_order: 0x%x\n",lay_cfg->lay_z_order); ++ printk("source_w: 0x%x\n",lay_cfg->source_w); ++ printk("source_h: 0x%x\n",lay_cfg->source_h); ++ printk("disp_pos_x: 0x%x\n",lay_cfg->disp_pos_x); ++ printk("disp_pos_y: 0x%x\n",lay_cfg->disp_pos_y); ++ printk("scale_w: 0x%x\n",lay_cfg->scale_w); ++ printk("scale_h: 0x%x\n",lay_cfg->scale_h); ++ printk("g_alpha_en: 0x%x\n",lay_cfg->g_alpha_en); ++ printk("g_alpha_val: 0x%x\n",lay_cfg->g_alpha_val); ++ printk("color: 0x%x\n",lay_cfg->color); ++ printk("format: 0x%x\n",lay_cfg->format); ++ printk("stride: 0x%x\n",lay_cfg->stride); ++ printk("addr[0]: 0x%x\n",lay_cfg->addr[0]); ++ printk("addr[1]: 0x%x\n",lay_cfg->addr[1]); ++ printk("addr[2]: 0x%x\n",lay_cfg->addr[2]); ++ ++ printk("------User disp set index[%d]------\n", index); ++} ++ ++static void dump_lcdc_registers(void) ++{ ++ dump_dc_reg(); ++ dump_tft_reg(); ++ dump_slcd_reg(); ++ dump_frm_desc_reg(); ++ dump_layer_desc_reg(); ++ dump_rdma_desc_reg(); ++} ++ ++static void dump_desc(struct ingenicfb_device *fbdev) ++{ ++ int i, j; ++ for(i = 0; i < CONFIG_FB_INGENIC_NR_FRAMES*2; i++) { ++ for(j = 0; j < DPU_SUPPORT_MAX_LAYERS; j++) { ++ dump_layer_desc(fbdev->layerdesc[i][j], i, j); ++ } ++ dump_frm_desc(fbdev->framedesc[i], i); ++ } ++} ++ ++ static ssize_t ++dump_lcd(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct ingenicfb_device *fbdev = dev_get_drvdata(dev); ++ ++ printk("\nDisp_end_num = %d\n\n",fbdev->irq_cnt); ++ printk("\nTFT_UNDR_num = %d\n\n",fbdev->tft_undr_cnt); ++ printk("\nFrm_start_num = %d\n\n", fbdev->frm_start); ++ printk(" Pand display count=%d\n",fbdev->pan_display_count); ++ printk("timestamp.wp = %d , timestamp.rp = %d\n\n", fbdev->timestamp.wp, fbdev->timestamp.rp); ++ dump_lcdc_registers(); ++ dump_desc(fbdev); ++ return 0; ++} ++ ++static void dump_all(struct ingenicfb_device *fbdev) ++{ ++ printk("\ndisp_end_num = %d\n\n", fbdev->irq_cnt); ++ printk("\nTFT_UNDR_num = %d\n\n", fbdev->tft_undr_cnt); ++ printk("\nFrm_start_num = %d\n\n", fbdev->frm_start); ++ dump_lcdc_registers(); ++ dump_desc(fbdev); ++} ++ ++#ifdef CONFIG_DEBUG_DPU_IRQCNT ++ static ssize_t ++dump_irqcnts(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct dbg_irqcnt *dbg = &fbdev->dbg_irqcnt; ++ char *p = buf; ++ p += sprintf(p, "irqcnt : %lld\n", dbg->irqcnt); ++ p += sprintf(p, "cmp_start : %lld\n", dbg->cmp_start); ++ p += sprintf(p, "stop_disp_ack : %lld\n", dbg->stop_disp_ack); ++ p += sprintf(p, "disp_end : %lld\n", dbg->disp_end); ++ p += sprintf(p, "tft_under : %lld\n", dbg->tft_under); ++ p += sprintf(p, "wdma_over : %lld\n", dbg->wdma_over); ++ p += sprintf(p, "wdma_end : %lld\n", dbg->wdma_end); ++ p += sprintf(p, "layer3_end : %lld\n", dbg->layer3_end); ++ p += sprintf(p, "layer2_end : %lld\n", dbg->layer2_end); ++ p += sprintf(p, "layer1_end : %lld\n", dbg->layer1_end); ++ p += sprintf(p, "layer0_end : %lld\n", dbg->layer0_end); ++ p += sprintf(p, "clr_cmp_end : %lld\n", dbg->clr_cmp_end); ++ p += sprintf(p, "stop_wrbk_ack : %lld\n", dbg->stop_wrbk_ack); ++ p += sprintf(p, "srd_start : %lld\n", dbg->srd_start); ++ p += sprintf(p, "srd_end : %lld\n", dbg->srd_end); ++ p += sprintf(p, "cmp_w_slow : %lld\n", dbg->cmp_w_slow); ++ ++ return p - buf; ++} ++#endif ++ ++void ingenicfb_clk_enable(struct ingenicfb_device *fbdev) ++{ ++ if(fbdev->is_clk_en){ ++ return; ++ } ++ clk_prepare_enable(fbdev->pclk); ++ clk_prepare_enable(fbdev->clk); ++ fbdev->is_clk_en = 1; ++} ++ ++void ingenicfb_clk_disable(struct ingenicfb_device *fbdev) ++{ ++ if(!fbdev->is_clk_en){ ++ return; ++ } ++ fbdev->is_clk_en = 0; ++ clk_disable_unprepare(fbdev->clk); ++ clk_disable_unprepare(fbdev->pclk); ++} ++ ++ static void ++ingenicfb_videomode_to_var(struct fb_var_screeninfo *var, ++ const struct fb_videomode *mode, int lcd_type) ++{ ++ var->xres = mode->xres; ++ var->yres = mode->yres; ++ var->xres_virtual = mode->xres; ++ var->yres_virtual = mode->yres * CONFIG_FB_INGENIC_NR_FRAMES * CONFIG_FB_INGENIC_NR_LAYERS; ++ var->xoffset = 0; ++ var->yoffset = 0; ++ var->left_margin = mode->left_margin; ++ var->right_margin = mode->right_margin; ++ var->upper_margin = mode->upper_margin; ++ var->lower_margin = mode->lower_margin; ++ var->hsync_len = mode->hsync_len; ++ var->vsync_len = mode->vsync_len; ++ var->sync = mode->sync; ++ var->vmode = mode->vmode & FB_VMODE_MASK; ++ var->pixclock = mode->pixclock; ++} ++ ++static struct fb_videomode *ingenicfb_get_mode(struct fb_var_screeninfo *var, ++ struct fb_info *info) ++{ ++ size_t i; ++ struct ingenicfb_device *fbdev = info->par; ++ struct fb_videomode *mode = fbdev->panel->modes; ++ ++ for (i = 0; i < fbdev->panel->num_modes; ++i, ++mode) { ++ if (mode->xres == var->xres && mode->yres == var->yres ++ && mode->vmode == var->vmode ++ && mode->right_margin == var->right_margin) { ++ if (fbdev->panel->lcd_type != LCD_TYPE_SLCD) { ++ if (mode->pixclock == var->pixclock) ++ return mode; ++ } else { ++ return mode; ++ } ++ } ++ } ++ ++ return NULL; ++} ++ ++static int ingenicfb_check_frm_cfg(struct fb_info *info, struct ingenicfb_frm_cfg *frm_cfg) ++{ ++ struct fb_var_screeninfo *var = &info->var; ++ struct ingenicfb_lay_cfg *lay_cfg; ++ struct fb_videomode *mode; ++ int scale_num = 0; ++ int i; ++ ++ mode = ingenicfb_get_mode(var, info); ++ if (mode == NULL) { ++ dev_err(info->dev, "%s get video mode failed\n", __func__); ++ return -EINVAL; ++ } ++ ++ lay_cfg = frm_cfg->lay_cfg; ++ ++ if((!(lay_cfg[0].lay_en || lay_cfg[1].lay_en || lay_cfg[2].lay_en || lay_cfg[3].lay_en)) || ++ (lay_cfg[0].lay_z_order == lay_cfg[1].lay_z_order) || ++ (lay_cfg[1].lay_z_order == lay_cfg[2].lay_z_order) || ++ (lay_cfg[2].lay_z_order == lay_cfg[3].lay_z_order)) { ++ dev_err(info->dev,"%s %d frame[0] cfg value is err!\n",__func__,__LINE__); ++ return -EINVAL; ++ } ++ ++ switch (lay_cfg[0].format) { ++ case LAYER_CFG_FORMAT_RGB555: ++ case LAYER_CFG_FORMAT_ARGB1555: ++ case LAYER_CFG_FORMAT_RGB565: ++ case LAYER_CFG_FORMAT_RGB888: ++ case LAYER_CFG_FORMAT_ARGB8888: ++ case LAYER_CFG_FORMAT_YUV422: ++ case LAYER_CFG_FORMAT_NV12: ++ case LAYER_CFG_FORMAT_NV21: ++ break; ++ default: ++ dev_err(info->dev,"%s %d frame[0] cfg value is err!\n",__func__,__LINE__); ++ return -EINVAL; ++ } ++ ++ for(i = 0; i < DPU_SUPPORT_MAX_LAYERS; i++) { ++ if(lay_cfg[i].lay_en) { ++ if((lay_cfg[i].source_w > DPU_MAX_SIZE) || ++ (lay_cfg[i].source_w < DPU_MIN_SIZE) || ++ (lay_cfg[i].source_h > DPU_MAX_SIZE) || ++ (lay_cfg[i].source_h < DPU_MIN_SIZE) || ++ (lay_cfg[i].disp_pos_x > mode->xres) || ++ (lay_cfg[i].disp_pos_y > mode->yres) || ++ (lay_cfg[i].color > LAYER_CFG_COLOR_BGR) || ++ (lay_cfg[i].stride > DPU_STRIDE_SIZE)) { ++ dev_err(info->dev,"%s %d frame[0] cfg value is err!\n",__func__,__LINE__); ++ return -EINVAL; ++ } ++ switch (lay_cfg[i].format) { ++ case LAYER_CFG_FORMAT_RGB555: ++ case LAYER_CFG_FORMAT_ARGB1555: ++ case LAYER_CFG_FORMAT_RGB565: ++ case LAYER_CFG_FORMAT_RGB888: ++ case LAYER_CFG_FORMAT_ARGB8888: ++ case LAYER_CFG_FORMAT_YUV422: ++ case LAYER_CFG_FORMAT_NV12: ++ case LAYER_CFG_FORMAT_NV21: ++ break; ++ default: ++ dev_err(info->dev,"%s %d frame[%d] cfg value is err!\n",__func__,__LINE__, i); ++ return -EINVAL; ++ } ++ if(lay_cfg[i].lay_scale_en) { ++ scale_num++; ++ if((lay_cfg[i].scale_w > mode->xres) || ++ (lay_cfg[i].scale_w < DPU_SCALE_MIN_SIZE) || ++ (lay_cfg[i].scale_h > mode->yres) || ++ (lay_cfg[i].scale_h < DPU_SCALE_MIN_SIZE) || ++ (lay_cfg[i].scale_w + lay_cfg[i].disp_pos_x > mode->xres) || ++ (lay_cfg[i].scale_h + lay_cfg[i].disp_pos_y > mode->yres) || ++ (scale_num > 2)) { ++ dev_err(info->dev,"%s %d frame[%d] cfg value is err!\n", ++ __func__, __LINE__,i); ++ return -EINVAL; ++ } ++ } else { ++ if((lay_cfg[i].disp_pos_x + lay_cfg[i].source_w > mode->xres) || ++ (lay_cfg[i].disp_pos_y + lay_cfg[i].source_h > mode->yres)) { ++ dev_err(info->dev,"%s %d frame[%d] cfg value is err!\n", ++ __func__, __LINE__,i); ++ return -EINVAL; ++ } ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++static void ingenicfb_colormode_to_var(struct fb_var_screeninfo *var, ++ struct ingenicfb_colormode *color) ++{ ++ var->bits_per_pixel = color->bits_per_pixel; ++ var->nonstd = color->nonstd; ++ var->red = color->red; ++ var->green = color->green; ++ var->blue = color->blue; ++ var->transp = color->transp; ++} ++ ++static bool cmp_var_to_colormode(struct fb_var_screeninfo *var, ++ struct ingenicfb_colormode *color) ++{ ++ bool cmp_component(struct fb_bitfield *f1, struct fb_bitfield *f2) ++ { ++ return f1->length == f2->length && ++ f1->offset == f2->offset && ++ f1->msb_right == f2->msb_right; ++ } ++ ++ if (var->bits_per_pixel == 0 || ++ var->red.length == 0 || ++ var->blue.length == 0 || ++ var->green.length == 0) ++ return 0; ++ ++ return var->bits_per_pixel == color->bits_per_pixel && ++ cmp_component(&var->red, &color->red) && ++ cmp_component(&var->green, &color->green) && ++ cmp_component(&var->blue, &color->blue) && ++ cmp_component(&var->transp, &color->transp); ++} ++ ++static int ingenicfb_check_colormode(struct fb_var_screeninfo *var, uint32_t *mode) ++{ ++ int i; ++ ++ if (var->nonstd) { ++ for (i = 0; i < ARRAY_SIZE(ingenicfb_colormodes); ++i) { ++ struct ingenicfb_colormode *m = &ingenicfb_colormodes[i]; ++ if (var->nonstd == m->nonstd) { ++ ingenicfb_colormode_to_var(var, m); ++ *mode = m->mode; ++ return 0; ++ } ++ } ++ ++ return -EINVAL; ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(ingenicfb_colormodes); ++i) { ++ struct ingenicfb_colormode *m = &ingenicfb_colormodes[i]; ++ if (cmp_var_to_colormode(var, m)) { ++ ingenicfb_colormode_to_var(var, m); ++ *mode = m->mode; ++ return 0; ++ } ++ } ++ /* To support user libraries that only support RGB format */ ++ for (i = 0; i < ARRAY_SIZE(ingenicfb_colormodes); ++i) { ++ struct ingenicfb_colormode *m = &ingenicfb_colormodes[i]; ++ if (var->bits_per_pixel == m->bits_per_pixel) { ++ ingenicfb_colormode_to_var(var, m); ++ *mode = m->mode; ++ return 0; ++ } ++ } ++ ++ return -EINVAL; ++} ++ ++static int ingenicfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ struct fb_videomode *mode; ++ uint32_t colormode; ++ int ret; ++ ++ mode = ingenicfb_get_mode(var, info); ++ if (mode == NULL) { ++ dev_err(info->dev, "%s get video mode failed\n", __func__); ++ return -EINVAL; ++ } ++ ++ ingenicfb_videomode_to_var(var, mode, fbdev->panel->lcd_type); ++ ++ ret = ingenicfb_check_colormode(var, &colormode); ++ if(ret) { ++ dev_err(info->dev,"Check colormode failed!\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void slcd_send_mcu_command(struct ingenicfb_device *fbdev, unsigned long cmd) ++{ ++ int count = 10000; ++ uint32_t slcd_cfg; ++ ++ while ((reg_read(fbdev, DC_SLCD_ST) & DC_SLCD_ST_BUSY) && count--) { ++ udelay(10); ++ } ++ if (count < 0) { ++ dev_err(fbdev->dev, "SLCDC wait busy state wrong"); ++ } ++ ++ slcd_cfg = reg_read(fbdev, DC_SLCD_CFG); ++ reg_write(fbdev, DC_SLCD_CFG, (slcd_cfg & ~DC_FMT_EN)); ++ reg_write(fbdev, DC_SLCD_REG_IF, DC_SLCD_REG_IF_FLAG_CMD | (cmd & ~DC_SLCD_REG_IF_FLAG_MASK)); ++} ++ ++static void slcd_send_mcu_data(struct ingenicfb_device *fbdev, unsigned long data) ++{ ++ int count = 10000; ++ uint32_t slcd_cfg; ++ ++ while ((reg_read(fbdev, DC_SLCD_ST) & DC_SLCD_ST_BUSY) && count--) { ++ udelay(10); ++ } ++ if (count < 0) { ++ dev_err(fbdev->dev, "SLCDC wait busy state wrong"); ++ } ++ ++ slcd_cfg = reg_read(fbdev, DC_SLCD_CFG); ++ reg_write(fbdev, DC_SLCD_CFG, (slcd_cfg | DC_FMT_EN)); ++ reg_write(fbdev, DC_SLCD_REG_IF, DC_SLCD_REG_IF_FLAG_DATA | (data & ~DC_SLCD_REG_IF_FLAG_MASK)); ++} ++ ++static void slcd_send_mcu_prm(struct ingenicfb_device *fbdev, unsigned long data) ++{ ++ int count = 10000; ++ uint32_t slcd_cfg; ++ ++ while ((reg_read(fbdev, DC_SLCD_ST) & DC_SLCD_ST_BUSY) && count--) { ++ udelay(10); ++ } ++ if (count < 0) { ++ dev_err(fbdev->dev, "SLCDC wait busy state wrong"); ++ } ++ ++ slcd_cfg = reg_read(fbdev, DC_SLCD_CFG); ++ reg_write(fbdev, DC_SLCD_CFG, (slcd_cfg & ~DC_FMT_EN)); ++ reg_write(fbdev, DC_SLCD_REG_IF, DC_SLCD_REG_IF_FLAG_PRM | (data & ~DC_SLCD_REG_IF_FLAG_MASK)); ++} ++ ++static void wait_slcd_busy(void) ++{ ++ int count = 100000; ++ while ((reg_read(fbdev, DC_SLCD_ST) & DC_SLCD_ST_BUSY) ++ && count--) { ++ udelay(10); ++ } ++ if (count < 0) { ++ dev_err(fbdev->dev,"SLCDC wait busy state wrong"); ++ } ++} ++ ++static int wait_dc_state(uint32_t state, uint32_t flag) ++{ ++ unsigned long timeout = 20000; ++ while(((!(reg_read(fbdev, DC_ST) & state)) == flag) && timeout) { ++ timeout--; ++ udelay(10); ++ } ++ if(timeout <= 0) { ++ printk("LCD wait state timeout! state = %d, DC_ST = 0x%x\n", state, DC_ST); ++ return -1; ++ } ++ return 0; ++} ++ ++static void ingenicfb_slcd_mcu_init(struct fb_info *info) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ struct lcd_panel *panel = fbdev->panel; ++ struct smart_config *smart_config; ++ struct smart_lcd_data_table *data_table; ++ uint32_t length_data_table; ++ uint32_t i; ++ ++ smart_config = panel->smart_config; ++ if (panel->lcd_type != LCD_TYPE_SLCD || smart_config == NULL) ++ return; ++ ++ data_table = smart_config->data_table; ++ length_data_table = smart_config->length_data_table; ++ if(length_data_table && data_table) { ++ for(i = 0; i < length_data_table; i++) { ++ switch (data_table[i].type) { ++ case SMART_CONFIG_DATA: ++ slcd_send_mcu_data(fbdev, data_table[i].value); ++ break; ++ case SMART_CONFIG_PRM: ++ slcd_send_mcu_prm(fbdev, data_table[i].value); ++ break; ++ case SMART_CONFIG_CMD: ++ slcd_send_mcu_command(fbdev, data_table[i].value); ++ break; ++ case SMART_CONFIG_UDELAY: ++ udelay(data_table[i].value); ++ break; ++ default: ++ printk("Unknow SLCD data type\n"); ++ break; ++ } ++ } ++ } ++} ++ ++static void ingenicfb_cmp_start(struct fb_info *info) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ ++ reg_write(fbdev, DC_FRM_CFG_CTRL, DC_FRM_START); ++} ++ ++static void ingenicfb_rdma_start(struct fb_info *info) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ ++ reg_write(fbdev, DC_RDMA_CHAIN_CTRL, DC_RDMA_START); ++} ++ ++static void tft_timing_init(struct fb_videomode *modes) { ++ uint32_t hps; ++ uint32_t hpe; ++ uint32_t vps; ++ uint32_t vpe; ++ uint32_t hds; ++ uint32_t hde; ++ uint32_t vds; ++ uint32_t vde; ++ ++ hps = modes->hsync_len; ++ hpe = hps + modes->left_margin + modes->xres + modes->right_margin; ++ vps = modes->vsync_len; ++ vpe = vps + modes->upper_margin + modes->yres + modes->lower_margin; ++ ++ hds = modes->hsync_len + modes->left_margin; ++ hde = hds + modes->xres; ++ vds = modes->vsync_len + modes->upper_margin; ++ vde = vds + modes->yres; ++ ++ reg_write(fbdev, DC_TFT_HSYNC, ++ (hps << DC_HPS_LBIT) | ++ (hpe << DC_HPE_LBIT)); ++ reg_write(fbdev, DC_TFT_VSYNC, ++ (vps << DC_VPS_LBIT) | ++ (vpe << DC_VPE_LBIT)); ++ reg_write(fbdev, DC_TFT_HDE, ++ (hds << DC_HDS_LBIT) | ++ (hde << DC_HDE_LBIT)); ++ reg_write(fbdev, DC_TFT_VDE, ++ (vds << DC_VDS_LBIT) | ++ (vde << DC_VDE_LBIT)); ++} ++ ++void tft_cfg_init(struct tft_config *tft_config) { ++ uint32_t tft_cfg; ++ uint32_t lcd_cgu; ++ ++ lcd_cgu = *(volatile unsigned int *)(0xb0000064); ++ if(tft_config->pix_clk_inv) { ++ lcd_cgu |= (0x1 << 26); ++ } else { ++ lcd_cgu &= ~(0x1 << 26); ++ } ++ *(volatile unsigned int *)(0xb0000064) = lcd_cgu; ++ ++ tft_cfg = reg_read(fbdev, DC_TFT_CFG); ++ if(tft_config->de_dl) { ++ tft_cfg |= DC_DE_DL; ++ } else { ++ tft_cfg &= ~DC_DE_DL; ++ } ++ ++ if(tft_config->sync_dl) { ++ tft_cfg |= DC_SYNC_DL; ++ } else { ++ tft_cfg &= ~DC_SYNC_DL; ++ } ++ ++ tft_cfg &= ~DC_COLOR_EVEN_MASK; ++ switch(tft_config->color_even) { ++ case TFT_LCD_COLOR_EVEN_RGB: ++ tft_cfg |= DC_EVEN_RGB; ++ break; ++ case TFT_LCD_COLOR_EVEN_RBG: ++ tft_cfg |= DC_EVEN_RBG; ++ break; ++ case TFT_LCD_COLOR_EVEN_BGR: ++ tft_cfg |= DC_EVEN_BGR; ++ break; ++ case TFT_LCD_COLOR_EVEN_BRG: ++ tft_cfg |= DC_EVEN_BRG; ++ break; ++ case TFT_LCD_COLOR_EVEN_GBR: ++ tft_cfg |= DC_EVEN_GBR; ++ break; ++ case TFT_LCD_COLOR_EVEN_GRB: ++ tft_cfg |= DC_EVEN_GRB; ++ break; ++ default: ++ printk("err!\n"); ++ break; ++ } ++ ++ tft_cfg &= ~DC_COLOR_ODD_MASK; ++ switch(tft_config->color_odd) { ++ case TFT_LCD_COLOR_ODD_RGB: ++ tft_cfg |= DC_ODD_RGB; ++ break; ++ case TFT_LCD_COLOR_ODD_RBG: ++ tft_cfg |= DC_ODD_RBG; ++ break; ++ case TFT_LCD_COLOR_ODD_BGR: ++ tft_cfg |= DC_ODD_BGR; ++ break; ++ case TFT_LCD_COLOR_ODD_BRG: ++ tft_cfg |= DC_ODD_BRG; ++ break; ++ case TFT_LCD_COLOR_ODD_GBR: ++ tft_cfg |= DC_ODD_GBR; ++ break; ++ case TFT_LCD_COLOR_ODD_GRB: ++ tft_cfg |= DC_ODD_GRB; ++ break; ++ default: ++ printk("err!\n"); ++ break; ++ } ++ ++ tft_cfg &= ~DC_MODE_MASK; ++ switch(tft_config->mode) { ++ case TFT_LCD_MODE_PARALLEL_888: ++ tft_cfg |= DC_MODE_PARALLEL_888; ++ break; ++ case TFT_LCD_MODE_PARALLEL_666: ++ tft_cfg |= DC_MODE_PARALLEL_666; ++ break; ++ case TFT_LCD_MODE_PARALLEL_565: ++ tft_cfg |= DC_MODE_PARALLEL_565; ++ break; ++ case TFT_LCD_MODE_SERIAL_RGB: ++ tft_cfg |= DC_MODE_SERIAL_8BIT_RGB; ++ break; ++ case TFT_LCD_MODE_SERIAL_RGBD: ++ tft_cfg |= DC_MODE_SERIAL_8BIT_RGBD; ++ break; ++ default: ++ printk("err!\n"); ++ break; ++ } ++ reg_write(fbdev, DC_TFT_CFG, tft_cfg); ++} ++ ++static int ingenicfb_tft_set_par(struct fb_info *info) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ struct lcd_panel *panel = fbdev->panel; ++ struct lcd_panel_ops *panel_ops; ++ struct fb_videomode *mode; ++ ++ panel_ops = panel->ops; ++ ++ mode = ingenicfb_get_mode(&info->var, info); ++ if (mode == NULL) { ++ dev_err(info->dev, "%s get video mode failed\n", __func__); ++ return -EINVAL; ++ } ++ ++ tft_timing_init(mode); ++ tft_cfg_init(panel->tft_config); ++ if(panel_ops && panel_ops->enable) ++ panel_ops->enable(panel); ++ ++ return 0; ++} ++ ++static void slcd_cfg_init(struct fb_info *info, ++ struct smart_config *smart_config) { ++ uint32_t slcd_cfg; ++ ++ if (smart_config == NULL) { ++ dev_info(info->dev, "SLCD use default config\n"); ++ return; ++ } ++ ++ slcd_cfg = reg_read(fbdev, DC_SLCD_CFG); ++ slcd_cfg &= ~DC_RDY_SWITCH; ++ slcd_cfg &= ~DC_CS_EN; ++ ++ if(smart_config->te_switch) { ++ slcd_cfg |= DC_TE_SWITCH; ++ ++ if(smart_config->te_dp) { ++ slcd_cfg |= DC_TE_DP; ++ } else { ++ slcd_cfg &= ~DC_TE_DP; ++ } ++ if(smart_config->te_md) { ++ slcd_cfg |= DC_TE_MD; ++ } else { ++ slcd_cfg &= ~DC_TE_MD; ++ } ++ if(smart_config->te_anti_jit) { ++ slcd_cfg |= DC_TE_ANTI_JIT; ++ } else { ++ slcd_cfg &= ~DC_TE_ANTI_JIT; ++ } ++ } else { ++ slcd_cfg &= ~DC_TE_SWITCH; ++ } ++ ++ if(smart_config->te_mipi_switch) { ++ slcd_cfg |= DC_TE_MIPI_SWITCH; ++ } else { ++ slcd_cfg &= ~DC_TE_MIPI_SWITCH; ++ } ++ ++ if(smart_config->dc_md) { ++ slcd_cfg |= DC_DC_MD; ++ } else { ++ slcd_cfg &= ~DC_DC_MD; ++ } ++ ++ if(smart_config->wr_md) { ++ slcd_cfg |= DC_WR_DP; ++ } else { ++ slcd_cfg &= ~DC_WR_DP; ++ } ++ ++ slcd_cfg &= ~DC_DBI_TYPE_MASK; ++ switch(smart_config->smart_type){ ++ case SMART_LCD_TYPE_8080: ++ slcd_cfg |= DC_DBI_TYPE_B_8080; ++ break; ++ case SMART_LCD_TYPE_6800: ++ slcd_cfg |= DC_DBI_TYPE_A_6800; ++ break; ++ case SMART_LCD_TYPE_SPI_3: ++ slcd_cfg |= DC_DBI_TYPE_C_SPI_3; ++ break; ++ case SMART_LCD_TYPE_SPI_4: ++ slcd_cfg |= DC_DBI_TYPE_C_SPI_4; ++ break; ++ default: ++ printk("err!\n"); ++ break; ++ } ++ ++ slcd_cfg &= ~DC_DATA_FMT_MASK; ++ switch(smart_config->pix_fmt) { ++ case SMART_LCD_FORMAT_888: ++ slcd_cfg |= DC_DATA_FMT_888; ++ break; ++ case SMART_LCD_FORMAT_666: ++ slcd_cfg |= DC_DATA_FMT_666; ++ break; ++ case SMART_LCD_FORMAT_565: ++ slcd_cfg |= DC_DATA_FMT_565; ++ break; ++ default: ++ printk("err!\n"); ++ break; ++ } ++ ++ slcd_cfg &= ~DC_DWIDTH_MASK; ++ switch(smart_config->dwidth) { ++ case SMART_LCD_DWIDTH_8_BIT: ++ slcd_cfg |= DC_DWIDTH_8BITS; ++ break; ++ case SMART_LCD_DWIDTH_9_BIT: ++ slcd_cfg |= DC_DWIDTH_9BITS; ++ break; ++ case SMART_LCD_DWIDTH_16_BIT: ++ slcd_cfg |= DC_DWIDTH_16BITS; ++ break; ++ case SMART_LCD_DWIDTH_18_BIT: ++ slcd_cfg |= DC_DWIDTH_18BITS; ++ break; ++ case SMART_LCD_DWIDTH_24_BIT: ++ slcd_cfg |= DC_DWIDTH_24BITS; ++ break; ++ default: ++ printk("err!\n"); ++ break; ++ } ++ ++ slcd_cfg &= ~DC_CWIDTH_MASK; ++ switch(smart_config->cwidth) { ++ case SMART_LCD_CWIDTH_8_BIT: ++ slcd_cfg |= DC_CWIDTH_8BITS; ++ break; ++ case SMART_LCD_CWIDTH_9_BIT: ++ slcd_cfg |= DC_CWIDTH_9BITS; ++ break; ++ case SMART_LCD_CWIDTH_16_BIT: ++ slcd_cfg |= DC_CWIDTH_16BITS; ++ break; ++ case SMART_LCD_CWIDTH_18_BIT: ++ slcd_cfg |= DC_CWIDTH_18BITS; ++ break; ++ case SMART_LCD_CWIDTH_24_BIT: ++ slcd_cfg |= DC_CWIDTH_24BITS; ++ break; ++ default: ++ printk("err!\n"); ++ break; ++ } ++ ++ reg_write(fbdev, DC_SLCD_CFG, slcd_cfg); ++ ++ return; ++} ++ ++static int slcd_timing_init(struct lcd_panel *ingenicfb_panel, ++ struct fb_videomode *mode) ++{ ++ uint32_t width = mode->xres; ++ uint32_t height = mode->yres; ++ uint32_t dhtime = 0; ++ uint32_t dltime = 0; ++ uint32_t chtime = 0; ++ uint32_t cltime = 0; ++ uint32_t tah = 0; ++ uint32_t tas = 0; ++ uint32_t slowtime = 0; ++ ++ /*frm_size*/ ++ reg_write(fbdev, DC_SLCD_FRM_SIZE, ++ ((width << DC_SLCD_FRM_H_SIZE_LBIT) | ++ (height << DC_SLCD_FRM_V_SIZE_LBIT))); ++ ++ /* wr duty */ ++ reg_write(fbdev, DC_SLCD_WR_DUTY, ++ ((dhtime << DC_DSTIME_LBIT) | ++ (dltime << DC_DDTIME_LBIT) | ++ (chtime << DC_CSTIME_LBIT) | ++ (cltime << DC_CDTIME_LBIT))); ++ ++ /* slcd timing */ ++ reg_write(fbdev, DC_SLCD_TIMING, ++ ((tah << DC_TAH_LBIT) | ++ (tas << DC_TAS_LBIT))); ++ ++ /* slow time */ ++ reg_write(fbdev, DC_SLCD_SLOW_TIME, slowtime); ++ ++ return 0; ++} ++ ++static int ingenicfb_slcd_set_par(struct fb_info *info) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ struct lcd_panel *panel = fbdev->panel; ++ struct lcd_panel_ops *panel_ops; ++ struct fb_videomode *mode; ++ ++ mode = ingenicfb_get_mode(&info->var, info); ++ panel_ops = panel->ops; ++ ++ slcd_cfg_init(info, panel->smart_config); ++ slcd_timing_init(panel, mode); ++ ++ if(panel_ops && panel_ops->enable) ++ panel_ops->enable(panel); ++ ++ ingenicfb_slcd_mcu_init(info); ++ ++ return 0; ++} ++ ++static void csc_mode_set(struct ingenicfb_device *fbdev, csc_mode_t mode) { ++ switch(mode) { ++ case CSC_MODE_0: ++ reg_write(fbdev, DC_CSC_MULT_YRV, DC_CSC_MULT_Y_MD0 | DC_CSC_MULT_RV_MD0); ++ reg_write(fbdev, DC_CSC_MULT_GUGV, DC_CSC_MULT_GU_MD0 | DC_CSC_MULT_GV_MD0); ++ reg_write(fbdev, DC_CSC_MULT_BU, DC_CSC_MULT_BU_MD0); ++ reg_write(fbdev, DC_CSC_SUB_YUV, DC_CSC_SUB_Y_MD0 | DC_CSC_SUB_UV_MD0); ++ break; ++ case CSC_MODE_1: ++ reg_write(fbdev, DC_CSC_MULT_YRV, DC_CSC_MULT_Y_MD1 | DC_CSC_MULT_RV_MD1); ++ reg_write(fbdev, DC_CSC_MULT_GUGV, DC_CSC_MULT_GU_MD1 | DC_CSC_MULT_GV_MD1); ++ reg_write(fbdev, DC_CSC_MULT_BU, DC_CSC_MULT_BU_MD1); ++ reg_write(fbdev, DC_CSC_SUB_YUV, DC_CSC_SUB_Y_MD1 | DC_CSC_SUB_UV_MD1); ++ break; ++ case CSC_MODE_2: ++ reg_write(fbdev, DC_CSC_MULT_YRV, DC_CSC_MULT_Y_MD2 | DC_CSC_MULT_RV_MD2); ++ reg_write(fbdev, DC_CSC_MULT_GUGV, DC_CSC_MULT_GU_MD2 | DC_CSC_MULT_GV_MD2); ++ reg_write(fbdev, DC_CSC_MULT_BU, DC_CSC_MULT_BU_MD2); ++ reg_write(fbdev, DC_CSC_SUB_YUV, DC_CSC_SUB_Y_MD2 | DC_CSC_SUB_UV_MD2); ++ break; ++ case CSC_MODE_3: ++ reg_write(fbdev, DC_CSC_MULT_YRV, DC_CSC_MULT_Y_MD3 | DC_CSC_MULT_RV_MD3); ++ reg_write(fbdev, DC_CSC_MULT_GUGV, DC_CSC_MULT_GU_MD3 | DC_CSC_MULT_GV_MD3); ++ reg_write(fbdev, DC_CSC_MULT_BU, DC_CSC_MULT_BU_MD3); ++ reg_write(fbdev, DC_CSC_SUB_YUV, DC_CSC_SUB_Y_MD3 | DC_CSC_SUB_UV_MD3); ++ break; ++ default: ++ dev_err(fbdev->dev, "Set csc mode err!\n"); ++ break; ++ } ++} ++ ++static int ingenicfb_alloc_devmem(struct ingenicfb_device *fbdev) ++{ ++ struct fb_videomode *mode; ++ struct fb_info *fb = fbdev->fb; ++ uint32_t buff_size; ++ void *page; ++ uint8_t *addr; ++ dma_addr_t addr_phy; ++ int i, j; ++ ++ mode = fbdev->panel->modes; ++ if (!mode) { ++ dev_err(fbdev->dev, "Checkout video mode fail\n"); ++ return -EINVAL; ++ } ++ ++ ++ /* 1. Alloc Framedesc Memory */ ++ buff_size = sizeof(struct ingenicfb_framedesc); ++ buff_size = ALIGN(buff_size, DESC_ALIGN); ++ addr = dma_alloc_coherent(fbdev->dev, buff_size * CONFIG_FB_INGENIC_NR_FRAMES * 2, ++ &addr_phy, GFP_KERNEL); ++ if(addr == NULL) { ++ return -ENOMEM; ++ } ++ for(i = 0; i < CONFIG_FB_INGENIC_NR_FRAMES * 2; i++) { ++ fbdev->framedesc[i] = ++ (struct ingenicfb_framedesc *)(addr + i * buff_size); ++ fbdev->framedesc_phys[i] = addr_phy + i * buff_size; ++ } ++ ++ /* 2. Alloc Simple Read Dma Desc Memory. */ ++ buff_size = sizeof(struct ingenicfb_sreadesc); ++ buff_size = ALIGN(buff_size, DESC_ALIGN); ++ addr = dma_alloc_coherent(fbdev->dev, buff_size * CONFIG_FB_INGENIC_NR_FRAMES, ++ &addr_phy, GFP_KERNEL); ++ if(addr == NULL) { ++ return -ENOMEM; ++ } ++ for(i = 0; i < CONFIG_FB_INGENIC_NR_FRAMES; i++) { ++ fbdev->sreadesc[i] = ++ (struct ingenicfb_sreadesc *)(addr + i * buff_size); ++ fbdev->sreadesc_phys[i] = addr_phy + i * buff_size; ++ } ++ ++ ++ /* 3. Alloc Frame Buffer.*/ ++ buff_size = mode->xres * mode->yres; ++ fbdev->frm_size = buff_size * fb->var.bits_per_pixel >> 3; ++ buff_size *= MAX_BITS_PER_PIX >> 3; ++ ++ fbdev->vidmem_size = buff_size * CONFIG_FB_INGENIC_NR_FRAMES * CONFIG_FB_INGENIC_NR_LAYERS; ++#ifdef CONFIG_INGENIC_FB_SIMPLE_RDMA ++ fbdev->sread_vidmem_size = buff_size * CONFIG_FB_INGENIC_NR_FRAMES; ++#else ++ fbdev->sread_vidmem_size = 0; ++ ++#endif ++ buff_size = fbdev->vidmem_size + fbdev->sread_vidmem_size; ++ buff_size = PAGE_ALIGN(buff_size); ++ fbdev->vidmem[0][0] = dma_alloc_coherent(fbdev->dev, buff_size, ++ &fbdev->vidmem_phys[0][0], GFP_KERNEL); ++ if(fbdev->vidmem[0][0] == NULL) { ++ return -ENOMEM; ++ } ++ for (page = fbdev->vidmem[0][0]; ++ page < fbdev->vidmem[0][0] + PAGE_ALIGN(fbdev->vidmem_size); ++ page += PAGE_SIZE) { ++ SetPageReserved(virt_to_page(page)); ++ } ++ ++ if(!fbdev->sread_vidmem_size) { ++ fbdev->sread_vidmem[0] = fbdev->vidmem[0][0] + fbdev->vidmem_size; ++ fbdev->sread_vidmem_phys[0] = fbdev->vidmem_phys[0][0] + fbdev->vidmem_size; ++ for (page = fbdev->sread_vidmem[0]; ++ page < fbdev->sread_vidmem[0] + PAGE_ALIGN(fbdev->sread_vidmem_size); ++ page += PAGE_SIZE) { ++ SetPageReserved(virt_to_page(page)); ++ } ++ } ++ ++ /*4. ALloc Layerdesc Memory.*/ ++ buff_size = sizeof(struct ingenicfb_layerdesc); ++ buff_size = ALIGN(buff_size, DESC_ALIGN); ++ addr = dma_alloc_coherent(fbdev->dev, buff_size * CONFIG_FB_INGENIC_NR_FRAMES * DPU_SUPPORT_MAX_LAYERS * 2, ++ &addr_phy, GFP_KERNEL); ++ if(addr == NULL) { ++ return -ENOMEM; ++ } ++ for(i = 0; i < CONFIG_FB_INGENIC_NR_FRAMES * 2; i++) { ++ for(j = 0; j < DPU_SUPPORT_MAX_LAYERS; j++) { ++ fbdev->layerdesc[i][j] = (struct ingenicfb_layerdesc *) ++ (addr + j * buff_size + i * buff_size * DPU_SUPPORT_MAX_LAYERS); ++ fbdev->layerdesc_phys[i][j] = ++ addr_phy + j * buff_size + i * buff_size * DPU_SUPPORT_MAX_LAYERS; ++ } ++ } ++ for(i = 0; i < CONFIG_FB_INGENIC_NR_FRAMES; i++) { ++ for(j = 0; j < CONFIG_FB_INGENIC_NR_LAYERS; j++) { ++ /* ++ Memory plane: ++ Frame[0] = { Layer[0], Layer[1], Layer[2], Layer[3] } ++ Frame[1] = { Layer[0], Layer[1], Layer[2], Layer[3] } ++ Frame[2] = { Layer[0], Layer[1], Layer[2], Layer[3] } ++ */ ++ fbdev->vidmem_phys[i][j] = fbdev->vidmem_phys[0][0] + ++ j * fbdev->frm_size + ++ i * fbdev->frm_size * CONFIG_FB_INGENIC_NR_LAYERS; ++ fbdev->vidmem[i][j] = fbdev->vidmem[0][0] + ++ j * fbdev->frm_size + ++ i * fbdev->frm_size * CONFIG_FB_INGENIC_NR_LAYERS; ++ } ++ } ++ ++ return 0; ++} ++ ++static void ingenicfb_tlb_enable(struct ingenicfb_device *fbdev) ++{ ++ struct ingenicfb_frm_cfg *frm_cfg; ++ struct ingenicfb_lay_cfg *lay_cfg; ++ unsigned int glbc, val; ++ int i; ++ ++ frm_cfg = &fbdev->current_frm_mode.frm_cfg; ++ lay_cfg = frm_cfg->lay_cfg; ++ val = reg_read(fbdev, DC_TLB_GLBC); ++ glbc = val; ++ ++ for(i = 0; i < DPU_SUPPORT_MAX_LAYERS; i++) { ++ if(lay_cfg[i].lay_en) { ++ if(lay_cfg[i].tlb_en != (glbc>>i & 0x1)) { ++ glbc = lay_cfg[i].tlb_en ? ++ (glbc | (0x1 << i)) : (glbc & ~(0x1 << i)); ++ } ++ } else { ++ glbc &= ~(0x1 << i); ++ } ++ } ++ if(val != glbc) { ++ reg_write(fbdev, DC_CTRL, DC_GEN_STP_CMP); ++ wait_dc_state(DC_WORKING, 0); ++ reg_write(fbdev, DC_TLB_GLBC, glbc); ++ } ++} ++ ++static void ingenicfb_tlb_configure(struct ingenicfb_device *fbdev) ++{ ++ unsigned int tlbv = 0; ++ ++ tlbv |= (1 << DC_CNM_LBIT); ++ tlbv |= (1 << DC_GCN_LBIT); ++ ++ /*mutex_lock(fbdev->lock);*/ ++ reg_write(fbdev, DC_TLB_TLBV, tlbv); ++ reg_write(fbdev, DC_TLB_TLBA, fbdev->tlba); ++ reg_write(fbdev, DC_TLB_TLBC, DC_CH0_INVLD | DC_CH1_INVLD | ++ DC_CH2_INVLD | DC_CH3_INVLD); ++ /*mutex_unlock(fbdev->lock);*/ ++} ++ ++#define DPU_WAIT_IRQ_TIME 8000 ++static int ingenicfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) ++{ ++ void __user *argp = (void __user *)arg; ++ struct ingenicfb_device *fbdev = info->par; ++ int ret; ++ csc_mode_t csc_mode; ++ int value; ++ int tmp; ++ int i; ++ ++ switch (cmd) { ++ case JZFB_SET_VSYNCINT: ++ if (unlikely(copy_from_user(&value, argp, sizeof(int)))) ++ return -EFAULT; ++ tmp = reg_read(fbdev, DC_INTC); ++ if (value) { ++ reg_write(fbdev, DC_CLR_ST, DC_CLR_CMP_START); ++ reg_write(fbdev, DC_INTC, tmp | DC_SOC_MSK); ++ } else { ++ reg_write(fbdev, DC_INTC, tmp & ~DC_SOC_MSK); ++ } ++ break; ++ case FBIO_WAITFORVSYNC: ++#ifndef CONFIG_FB_VSYNC_SKIP_DISABLE ++ unlock_fb_info(info); ++ ret = wait_event_interruptible_timeout(fbdev->vsync_wq, ++ fbdev->timestamp.wp != fbdev->timestamp.rp, ++ msecs_to_jiffies(DPU_WAIT_IRQ_TIME)); ++ lock_fb_info(info); ++ if(ret == 0) { ++ dev_err(info->dev, "DPU wait vsync timeout!\n"); ++ return -EFAULT; ++ } ++ ++ ret = copy_to_user(argp, fbdev->timestamp.value + fbdev->timestamp.rp, ++ sizeof(u64)); ++ fbdev->timestamp.rp = (fbdev->timestamp.rp + 1) % TIMESTAMP_CAP; ++ ++ if (unlikely(ret)) ++ return -EFAULT; ++#else ++ { ++ int retry = 3; ++ while(retry--) { ++ unlock_fb_info(info); ++ fbdev->timestamp.rp = fbdev->timestamp.wp; ++ ret = wait_event_interruptible_timeout(fbdev->vsync_wq, ++ fbdev->timestamp.wp != fbdev->timestamp.rp, ++ msecs_to_jiffies(DPU_WAIT_IRQ_TIME)); ++ lock_fb_info(info); ++ if(ret == 0) { ++ dev_err(info->dev, "DPU wait vsync timeout!\n"); ++ return -EFAULT; ++ } ++ if (old_desc_addr != reg_read(fbdev, DC_FRM_DES)) break; ++ } ++ } ++#endif ++ break; ++ case JZFB_PUT_FRM_CFG: ++ ret = ingenicfb_check_frm_cfg(info, (struct ingenicfb_frm_cfg *)argp); ++ if(ret) { ++ return ret; ++ } ++ copy_from_user(&fbdev->current_frm_mode.frm_cfg, ++ (void *)argp, ++ sizeof(struct ingenicfb_frm_cfg)); ++ ++ for (i = 0; i < ARRAY_SIZE(ingenicfb_colormodes); ++i) { ++ struct ingenicfb_colormode *m = &ingenicfb_colormodes[i]; ++ if (m->mode == fbdev->current_frm_mode.frm_cfg.lay_cfg[0].format) { ++ ingenicfb_colormode_to_var(&info->var, m); ++ break; ++ } ++ } ++ ++ for(i = 0; i < CONFIG_FB_INGENIC_NR_FRAMES; i++) { ++ fbdev->current_frm_mode.update_st[i] = FRAME_CFG_NO_UPDATE; ++ } ++ break; ++ case JZFB_GET_FRM_CFG: ++ copy_to_user((void *)argp, ++ &fbdev->current_frm_mode.frm_cfg, ++ sizeof(struct ingenicfb_frm_cfg)); ++ break; ++ case JZFB_GET_LAYERS_NUM: ++ { ++ unsigned int layers_num = CONFIG_FB_INGENIC_NR_LAYERS; ++ copy_to_user((void *)argp, ++ &layers_num, ++ sizeof(unsigned int)); ++ } ++ break; ++ case JZFB_SET_CSC_MODE: ++ if (unlikely(copy_from_user(&csc_mode, argp, sizeof(csc_mode_t)))) ++ return -EFAULT; ++ csc_mode_set(fbdev, csc_mode); ++ break; ++ case JZFB_USE_TLB: ++ if((unsigned int)arg != 0){ ++ fbdev->tlba = (unsigned int)arg; ++ ingenicfb_tlb_configure(fbdev); ++ } else ++ printk("tlb err!!!\n"); ++ break; ++ case JZFB_DMMU_MEM_SMASH: ++ { ++ struct smash_mode sm; ++ if (copy_from_user(&sm, (void *)arg, sizeof(sm))) { ++ ret = -EFAULT; ++ break; ++ } ++ return dmmu_memory_smash(sm.vaddr, sm.mode); ++ break; ++ } ++ case JZFB_DMMU_DUMP_MAP: ++ { ++ unsigned long vaddr; ++ if (copy_from_user(&vaddr, (void *)arg, sizeof(unsigned long))) { ++ ret = -EFAULT; ++ break; ++ } ++ return dmmu_dump_map(vaddr); ++ break; ++ } ++ case JZFB_DMMU_MAP: ++ { ++ struct dpu_dmmu_map_info di; ++ if (copy_from_user(&di, (void *)arg, sizeof(di))) { ++ ret = -EFAULT; ++ break; ++ } ++ fbdev->user_addr = di.addr; ++ return dmmu_map(info->dev,di.addr,di.len); ++ break; ++ } ++ case JZFB_DMMU_UNMAP: ++ { ++ struct dpu_dmmu_map_info di; ++ if (copy_from_user(&di, (void *)arg, sizeof(di))) { ++ ret = -EFAULT; ++ break; ++ } ++ return dmmu_unmap(info->dev,di.addr,di.len); ++ break; ++ } ++ case JZFB_DMMU_UNMAP_ALL: ++ dmmu_unmap_all(info->dev); ++ break; ++ case JZFB_DMMU_FLUSH_CACHE: ++ { ++ struct dpu_dmmu_map_info di; ++ if (copy_from_user(&di, (void *)arg, sizeof(di))) { ++ ret = -EFAULT; ++ break; ++ } ++ return dmmu_flush_cache(di.addr,di.len); ++ break; ++ } ++ default: ++ printk("Command:%x Error!\n",cmd); ++ break; ++ } ++ return 0; ++} ++ ++static int ingenicfb_mmap(struct fb_info *info, struct vm_area_struct *vma) ++{ ++ unsigned long start; ++ unsigned long off; ++ u32 len; ++ ++ off = vma->vm_pgoff << PAGE_SHIFT; ++ ++ start = info->fix.smem_start; ++ len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len); ++ start &= PAGE_MASK; ++ ++ if ((vma->vm_end - vma->vm_start + off) > len) ++ return -EINVAL; ++ off += start; ++ ++ vma->vm_pgoff = off >> PAGE_SHIFT; ++ vma->vm_flags |= VM_IO; ++ ++ pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK; ++ /* Write-Acceleration */ ++ /*pgprot_val(vma->vm_page_prot) |= _CACHE_CACHABLE_WA;*/ ++ ++ pgprot_val(vma->vm_page_prot) |= _CACHE_CACHABLE_WT_WA_S; ++ ++ if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, ++ vma->vm_end - vma->vm_start, vma->vm_page_prot)) ++ { ++ return -EAGAIN; ++ } ++ ++ return 0; ++} ++ ++static void ingenicfb_set_vsync_value(struct ingenicfb_device *fbdev) ++{ ++ fbdev->vsync_skip_map = (fbdev->vsync_skip_map >> 1 | ++ fbdev->vsync_skip_map << 9) & 0x3ff; ++ if(likely(fbdev->vsync_skip_map & 0x1)) { ++ fbdev->timestamp.value[fbdev->timestamp.wp] = ++ ktime_to_ns(ktime_get()); ++ fbdev->timestamp.wp = (fbdev->timestamp.wp + 1) % TIMESTAMP_CAP; ++ wake_up_interruptible(&fbdev->vsync_wq); ++#ifdef CONFIG_FB_VSYNC_SKIP_DISABLE ++ } else { ++ fbdev->timestamp.wp = fbdev->timestamp.rp + 1; ++ wake_up_interruptible(&fbdev->vsync_wq); ++#endif ++ } ++} ++ ++static irqreturn_t ingenicfb_irq_handler(int irq, void *data) ++{ ++ unsigned int irq_flag; ++ struct ingenicfb_device *fbdev = (struct ingenicfb_device *)data; ++ ++ spin_lock(&fbdev->irq_lock); ++ ++ dbg_irqcnt_inc(fbdev->dbg_irqcnt, irqcnt); ++ ++ irq_flag = reg_read(fbdev, DC_INT_FLAG); ++ if(likely(irq_flag & DC_CMP_START)) { ++ reg_write(fbdev, DC_CLR_ST, DC_CLR_CMP_START); ++ dbg_irqcnt_inc(fbdev->dbg_irqcnt, cmp_start); ++ ++ fbdev->frm_start++; ++ ingenicfb_set_vsync_value(fbdev); ++ spin_unlock(&fbdev->irq_lock); ++ return IRQ_HANDLED; ++ } ++#define IRQ_P_N 50 ++ ++ if(unlikely(irq_flag & DC_STOP_DISP_ACK)) { ++ reg_write(fbdev, DC_CLR_ST, DC_CLR_STOP_DISP_ACK); ++ dbg_irqcnt_inc(fbdev->dbg_irqcnt, stop_disp_ack); ++ cmp_gen_sop = 1; ++ wake_up_interruptible(&fbdev->gen_stop_wq); ++ spin_unlock(&fbdev->irq_lock); ++ return IRQ_HANDLED; ++ } ++ ++ if(unlikely(irq_flag & DC_DISP_END)) { ++ reg_write(fbdev, DC_CLR_ST, DC_CLR_DISP_END); ++ dbg_irqcnt_inc(fbdev->dbg_irqcnt, disp_end); ++ //print_dbg("DC_DISP_END"); ++ //fbdev->dsi->master_ops->query_te(fbdev->dsi); ++ spin_unlock(&fbdev->irq_lock); ++ return IRQ_HANDLED; ++ } ++ ++ ++ if(unlikely(irq_flag & DC_TFT_UNDR)) { ++ reg_write(fbdev, DC_CLR_ST, DC_CLR_TFT_UNDR); ++ dbg_irqcnt_inc(fbdev->dbg_irqcnt, tft_under); ++ fbdev->tft_undr_cnt++; ++#ifdef CONFIG_FPGA_TEST ++ if (!(fbdev->tft_undr_cnt % 100000)) //FIXME: ++#endif ++ if (!(fbdev->tft_undr_cnt % 10000)) //FIXME: ++ printk("\nTFT_UNDR_num = %d\n\n", fbdev->tft_undr_cnt); ++ ++ spin_unlock(&fbdev->irq_lock); ++ return IRQ_HANDLED; ++ } ++ ++#if 1 ++ if(likely(irq_flag & DC_WDMA_OVER)) { ++ over_cnt++; ++ dbg_irqcnt_inc(fbdev->dbg_irqcnt, wdma_over); ++ reg_write(fbdev, DC_CLR_ST, DC_CLR_WDMA_OVER); ++#ifdef CONFIG_FPGA_TEST ++ if (!(over_cnt % 1000)) //FIXME: ++#endif ++ print_dbg("\nDC_WDMA_OVER irq came here!!!!!!!!!!!!!!over_cnt = %d\n",over_cnt); ++ spin_unlock(&fbdev->irq_lock); ++ return IRQ_HANDLED; ++ } ++ if(likely(irq_flag & DC_WDMA_END)) { ++ static int cnt = 0; ++ cnt++; ++ dbg_irqcnt_inc(fbdev->dbg_irqcnt, wdma_end); ++ reg_write(fbdev, DC_CLR_ST, DC_CLR_WDMA_END); ++ if(cnt < IRQ_P_N) ++ print_dbg("DC_WDMA_END irq came here!!!!!!!!!!!!!!"); ++ spin_unlock(&fbdev->irq_lock); ++ return IRQ_HANDLED; ++ } ++ if(likely(irq_flag & DC_LAY3_END)) { ++ static int cnt = 0; ++ cnt++; ++ dbg_irqcnt_inc(fbdev->dbg_irqcnt, layer3_end); ++ reg_write(fbdev, DC_CLR_ST, DC_CLR_LAY3_END); ++ if(cnt < IRQ_P_N) ++ print_dbg("DC_LAY3_END irq came here!!!!!!!!!!!!!!"); ++ spin_unlock(&fbdev->irq_lock); ++ return IRQ_HANDLED; ++ } ++ if(likely(irq_flag & DC_LAY2_END)) { ++ static int cnt = 0; ++ cnt++; ++ dbg_irqcnt_inc(fbdev->dbg_irqcnt, layer2_end); ++ reg_write(fbdev, DC_CLR_ST, DC_CLR_LAY2_END); ++ if(cnt < IRQ_P_N) ++ print_dbg("DC_LAY2_END irq came here!!!!!!!!!!!!!!"); ++ spin_unlock(&fbdev->irq_lock); ++ return IRQ_HANDLED; ++ } ++ if(likely(irq_flag & DC_LAY1_END)) { ++ static int cnt = 0; ++ cnt++; ++ dbg_irqcnt_inc(fbdev->dbg_irqcnt, layer1_end); ++ reg_write(fbdev, DC_CLR_ST, DC_CLR_LAY1_END); ++ if(cnt < IRQ_P_N) ++ print_dbg("DC_LAY1_END irq came here!!!!!!!!!!!!!!"); ++ spin_unlock(&fbdev->irq_lock); ++ return IRQ_HANDLED; ++ } ++ if(likely(irq_flag & DC_LAY0_END)) { ++ static int cnt = 0; ++ cnt++; ++ dbg_irqcnt_inc(fbdev->dbg_irqcnt, layer0_end); ++ reg_write(fbdev, DC_CLR_ST, DC_CLR_LAY0_END); ++ if(cnt < IRQ_P_N) ++ print_dbg("DC_LAY0_END irq came here!!!!!!!!!!!!!!"); ++ spin_unlock(&fbdev->irq_lock); ++ return IRQ_HANDLED; ++ } ++ if(likely(irq_flag & DC_CMP_END)) { ++ static int cnt = 0; ++ cnt++; ++ dbg_irqcnt_inc(fbdev->dbg_irqcnt, clr_cmp_end); ++ reg_write(fbdev, DC_CLR_ST, DC_CLR_CMP_END); ++ if(cnt < IRQ_P_N) ++ print_dbg("DC_CMP_END irq came here!!!!!!!!!!!!!!"); ++ spin_unlock(&fbdev->irq_lock); ++ return IRQ_HANDLED; ++ } ++ if(likely(irq_flag & DC_STOP_WRBK_ACK)) { ++ static int cnt = 0; ++ cnt++; ++ dbg_irqcnt_inc(fbdev->dbg_irqcnt, stop_wrbk_ack); ++ reg_write(fbdev, DC_CLR_ST, DC_CLR_STOP_WRBK_ACK); ++ if(cnt < IRQ_P_N) ++ print_dbg("DC_STOP_SRD irq came here!!!!!!!!!!!!!!"); ++ spin_unlock(&fbdev->irq_lock); ++ return IRQ_HANDLED; ++ } ++ if(likely(irq_flag & DC_SRD_START)) { ++ static int cnt = 0; ++ cnt++; ++ dbg_irqcnt_inc(fbdev->dbg_irqcnt, srd_start); ++ reg_write(fbdev, DC_CLR_ST, DC_CLR_SRD_START); ++ if(cnt < IRQ_P_N) ++ print_dbg("DC_SRD_START irq came here!!!!!!!!!!!!!!"); ++ spin_unlock(&fbdev->irq_lock); ++ return IRQ_HANDLED; ++ } ++ if(likely(irq_flag & DC_SRD_END)) { ++ static int cnt = 0; ++ cnt++; ++ dbg_irqcnt_inc(fbdev->dbg_irqcnt, srd_end); ++ reg_write(fbdev, DC_CLR_ST, DC_CLR_SRD_END); ++ if(cnt < IRQ_P_N) ++ print_dbg("DC_SRD_END irq came here!!!!!!!!!!!!!!"); ++ spin_unlock(&fbdev->irq_lock); ++ return IRQ_HANDLED; ++ } ++ if(likely(irq_flag & DC_CMP_W_SLOW)) { ++ static int cnt = 0; ++ cnt++; ++ dbg_irqcnt_inc(fbdev->dbg_irqcnt, cmp_w_slow); ++ reg_write(fbdev, DC_CLR_ST, DC_CLR_CMP_W_SLOW); ++ if(cnt < IRQ_P_N) ++ print_dbg("DC_CMP_W_SLOW came here!!!!!!!!!!!!!! DC_ST = 0x%lx cnt = %d",reg_read(fbdev,DC_ST),cnt); ++ if(cnt > 10) ++ reg_write(fbdev, DC_CMPW_PCFG_CTRL, 0 << 10 | 30); ++ spin_unlock(&fbdev->irq_lock); ++ return IRQ_HANDLED; ++ } ++#endif ++ ++ dev_err(fbdev->dev, "DPU irq nothing do, please check!!! DC_ST = 0x%lx\n",reg_read(fbdev,DC_ST)); ++ spin_unlock(&fbdev->irq_lock); ++ return IRQ_HANDLED; ++} ++ ++static inline uint32_t convert_color_to_hw(unsigned val, struct fb_bitfield *bf) ++{ ++ return (((val << bf->length) + 0x7FFF - val) >> 16) << bf->offset; ++} ++ ++static int ingenicfb_setcolreg(unsigned regno, unsigned red, unsigned green, ++ unsigned blue, unsigned transp, struct fb_info *fb) ++{ ++ if (regno >= 16) ++ return -EINVAL; ++ ++ ((uint32_t *)(fb->pseudo_palette))[regno] = ++ convert_color_to_hw(red, &fb->var.red) | ++ convert_color_to_hw(green, &fb->var.green) | ++ convert_color_to_hw(blue, &fb->var.blue) | ++ convert_color_to_hw(transp, &fb->var.transp); ++ ++ return 0; ++} ++ ++static void __maybe_unused ingenicfb_display_sread_v_color_bar(struct fb_info *info) ++{ ++ int i, j; ++ int w, h; ++ int bpp; ++ unsigned short *p16; ++ unsigned int *p32; ++ struct ingenicfb_device *fbdev = info->par; ++ struct fb_videomode *mode = fbdev->panel->modes; ++ ++ ++ if (!mode) { ++ dev_err(fbdev->dev, "%s, video mode is NULL\n", __func__); ++ return; ++ } ++ ++ p16 = (unsigned short *)fbdev->sread_vidmem[0]; ++ p32 = (unsigned int *)fbdev->sread_vidmem[0]; ++ w = mode->xres; ++ h = mode->yres; ++ bpp = info->var.bits_per_pixel; ++ ++ ++ for (i = 0; i < h; i++) { ++ for (j = 0; j < w; j++) { ++ short c16; ++ int c32 = 0; ++ switch ((j / 10) % 4) { ++ case 0: ++ c16 = 0xF800; ++ c32 = 0xFFFF0000; ++ break; ++ case 1: ++ c16 = 0x07C0; ++ c32 = 0xFF00FF00; ++ break; ++ case 2: ++ c16 = 0x001F; ++ c32 = 0xFF0000FF; ++ break; ++ default: ++ c16 = 0xFFFF; ++ c32 = 0xFFFFFFFF; ++ break; ++ } ++ switch (bpp) { ++ case 18: ++ case 24: ++ case 32: ++ *p32++ = c32; ++ break; ++ default: ++ *p16++ = c16; ++ } ++ } ++ if (w % PIXEL_ALIGN) { ++ switch (bpp) { ++ case 18: ++ case 24: ++ case 32: ++ p32 += (ALIGN(mode->xres, PIXEL_ALIGN) - w); ++ break; ++ default: ++ p16 += (ALIGN(mode->xres, PIXEL_ALIGN) - w); ++ break; ++ } ++ } ++ } ++} ++ ++static void ingenicfb_display_v_color_bar(struct fb_info *info) ++{ ++ int i, j; ++ int w, h; ++ int bpp; ++ unsigned short *p16; ++ unsigned int *p32; ++ struct ingenicfb_device *fbdev = info->par; ++ struct fb_videomode *mode = fbdev->panel->modes; ++ ++ if (!mode) { ++ dev_err(fbdev->dev, "%s, video mode is NULL\n", __func__); ++ return; ++ } ++ if (!fbdev->vidmem_phys[fbdev->current_frm_desc][0]) { ++ dev_err(fbdev->dev, "Not allocate frame buffer yet\n"); ++ return; ++ } ++ if (!fbdev->vidmem[fbdev->current_frm_desc][0]) ++ fbdev->vidmem[fbdev->current_frm_desc][0] = ++ (void *)phys_to_virt(fbdev->vidmem_phys[fbdev->current_frm_desc][0]); ++ p16 = (unsigned short *)fbdev->vidmem[fbdev->current_frm_desc][0]; ++ p32 = (unsigned int *)fbdev->vidmem[fbdev->current_frm_desc][0]; ++ w = mode->xres; ++ h = mode->yres; ++ bpp = info->var.bits_per_pixel; ++ ++ dev_info(info->dev, ++ "LCD V COLOR BAR w,h,bpp(%d,%d,%d) fbdev->vidmem[0]=%p\n", w, h, ++ bpp, fbdev->vidmem[fbdev->current_frm_desc][0]); ++ ++ ++ for (i = 0; i < h; i++) { ++ for (j = 0; j < w; j++) { ++ short c16; ++ int c32 = 0; ++ switch ((j / 10) % 4) { ++ case 0: ++ c16 = 0xF800; ++ c32 = 0xFFFF0000; ++ break; ++ case 1: ++ c16 = 0x07C0; ++ c32 = 0xFF00FF00; ++ break; ++ case 2: ++ c16 = 0x001F; ++ c32 = 0xFF0000FF; ++ break; ++ default: ++ c16 = 0xFFFF; ++ c32 = 0xFFFFFFFF; ++ break; ++ } ++ switch (bpp) { ++ case 18: ++ case 24: ++ case 32: ++ *p32++ = c32; ++ break; ++ default: ++ *p16++ = c16; ++ } ++ } ++ if (w % PIXEL_ALIGN) { ++ switch (bpp) { ++ case 18: ++ case 24: ++ case 32: ++ p32 += (ALIGN(mode->xres, PIXEL_ALIGN) - w); ++ break; ++ default: ++ p16 += (ALIGN(mode->xres, PIXEL_ALIGN) - w); ++ break; ++ } ++ } ++ } ++} ++ ++static void ingenicfb_display_h_color_bar(struct fb_info *info) ++{ ++ int i, j; ++ int w, h; ++ int bpp; ++ unsigned short *p16; ++ unsigned int *p32; ++ struct ingenicfb_device *fbdev = info->par; ++ struct fb_videomode *mode = fbdev->panel->modes; ++ ++ if (!mode) { ++ dev_err(fbdev->dev, "%s, video mode is NULL\n", __func__); ++ return; ++ } ++ if (!fbdev->vidmem_phys[fbdev->current_frm_desc][0]) { ++ dev_err(fbdev->dev, "Not allocate frame buffer yet\n"); ++ return; ++ } ++ if (!fbdev->vidmem[fbdev->current_frm_desc][0]) ++ fbdev->vidmem[fbdev->current_frm_desc][0] = ++ (void *)phys_to_virt(fbdev->vidmem_phys[fbdev->current_frm_desc][0]); ++ p16 = (unsigned short *)fbdev->vidmem[fbdev->current_frm_desc][0]; ++ p32 = (unsigned int *)fbdev->vidmem[fbdev->current_frm_desc][0]; ++ w = mode->xres; ++ h = mode->yres; ++ bpp = info->var.bits_per_pixel; ++ ++ dev_info(info->dev, ++ "LCD H COLOR BAR w,h,bpp(%d,%d,%d), fbdev->vidmem[0]=%p\n", w, h, ++ bpp, fbdev->vidmem[fbdev->current_frm_desc][0]); ++ ++ for (i = 0; i < h; i++) { ++ for (j = 0; j < w; j++) { ++ short c16; ++ int c32; ++ switch ((i / 10) % 4) { ++ case 0: ++ c16 = 0xF800; ++ c32 = 0x00FF0000; ++ break; ++ case 1: ++ c16 = 0x07C0; ++ c32 = 0x0000FF00; ++ break; ++ case 2: ++ c16 = 0x001F; ++ c32 = 0x000000FF; ++ break; ++ default: ++ c16 = 0xFFFF; ++ c32 = 0xFFFFFFFF; ++ break; ++ } ++ switch (bpp) { ++ case 18: ++ case 24: ++ case 32: ++ *p32++ = c32; ++ break; ++ default: ++ *p16++ = c16; ++ } ++ } ++ if (w % PIXEL_ALIGN) { ++ switch (bpp) { ++ case 18: ++ case 24: ++ case 32: ++ p32 += (ALIGN(mode->xres, PIXEL_ALIGN) - w); ++ break; ++ default: ++ p16 += (ALIGN(mode->xres, PIXEL_ALIGN) - w); ++ break; ++ } ++ } ++ } ++} ++ ++int lcd_display_inited_by_uboot( void ) ++{ ++ if (*(unsigned int*)(0xb3050000 + DC_ST) & DC_WORKING) ++ uboot_inited = 1; ++ else ++ uboot_inited = 0; ++ return uboot_inited; ++} ++ ++static int slcd_pixel_refresh_times(struct fb_info *info) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ struct lcd_panel *panel = fbdev->panel; ++ struct smart_config *smart_config = panel->smart_config; ++ ++ switch(smart_config->smart_type){ ++ case SMART_LCD_TYPE_8080: ++ case SMART_LCD_TYPE_6800: ++ break; ++ case SMART_LCD_TYPE_SPI_3: ++ return 9; ++ case SMART_LCD_TYPE_SPI_4: ++ return 8; ++ default: ++ printk("%s %d err!\n",__func__,__LINE__); ++ break; ++ } ++ ++ switch(smart_config->pix_fmt) { ++ case SMART_LCD_FORMAT_888: ++ if(smart_config->dwidth == SMART_LCD_DWIDTH_8_BIT) ++ return 3; ++ if(smart_config->dwidth == SMART_LCD_DWIDTH_24_BIT) ++ return 1; ++ case SMART_LCD_FORMAT_565: ++ if(smart_config->dwidth == SMART_LCD_DWIDTH_8_BIT) ++ return 2; ++ if(smart_config->dwidth == SMART_LCD_DWIDTH_16_BIT) ++ return 1; ++ default: ++ printk("%s %d err!\n",__func__,__LINE__); ++ break; ++ } ++ ++ return 1; ++} ++ ++static void ingenic_set_pixclk(struct fb_info *info) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ unsigned long rate, prate; ++ struct clk *clk; ++ ++ rate = PICOS2KHZ(info->var.pixclock) * 1000; ++ clk = clk_get_parent(fbdev->pclk); ++ prate = clk_get_rate(clk); ++ ++ if(prate % rate) ++ rate = prate / (prate / rate) + 1; ++ clk_set_rate(fbdev->pclk, rate); ++} ++ ++ ++static int refresh_pixclock_auto_adapt(struct fb_info *info) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ struct lcd_panel *panel = fbdev->panel; ++ struct fb_var_screeninfo *var = &info->var; ++ struct fb_videomode *mode; ++ uint16_t hds, vds; ++ uint16_t hde, vde; ++ uint16_t ht, vt; ++ unsigned long rate; ++ ++ mode = panel->modes; ++ if (mode == NULL) { ++ dev_err(fbdev->dev, "%s get video mode failed\n", __func__); ++ return -EINVAL; ++ } ++ ++ hds = mode->hsync_len + mode->left_margin; ++ hde = hds + mode->xres; ++ ht = hde + mode->right_margin; ++ ++ vds = mode->vsync_len + mode->upper_margin; ++ vde = vds + mode->yres; ++ vt = vde + mode->lower_margin; ++ ++ if(mode->refresh){ ++ rate = mode->refresh * vt * ht; ++ if(fbdev->panel->lcd_type == LCD_TYPE_SLCD) { ++ rate *= slcd_pixel_refresh_times(info); ++ } ++ ++ mode->pixclock = KHZ2PICOS(round_up(rate, 1000)/1000); ++ var->pixclock = mode->pixclock; ++ }else if(mode->pixclock){ ++ rate = PICOS2KHZ(mode->pixclock) * 1000; ++ mode->refresh = rate / vt / ht; ++ if(fbdev->panel->lcd_type == LCD_TYPE_SLCD) ++ mode->refresh /= slcd_pixel_refresh_times(info); ++ }else{ ++ dev_err(fbdev->dev,"%s error:lcd important config info is absenced\n",__func__); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static void ingenicfb_enable(struct fb_info *info) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ struct lcd_panel *panel = fbdev->panel; ++ ++ mutex_lock(&fbdev->lock); ++ if (fbdev->is_lcd_en) { ++ mutex_unlock(&fbdev->lock); ++ return; ++ } ++ ++ ++ if(panel->lcd_type == LCD_TYPE_SLCD) { ++ slcd_send_mcu_command(fbdev, panel->smart_config->write_gram_cmd); ++ wait_slcd_busy(); ++ } ++#ifdef CONFIG_INGENIC_FB_SIMPLE_RDMA ++ ingenicfb_rdma_start(info); ++#else ++ ingenicfb_cmp_start(info); ++#endif ++ ++ fbdev->is_lcd_en = 1; ++ mutex_unlock(&fbdev->lock); ++ return; ++} ++ ++static void ingenicfb_disable(struct fb_info *info, stop_mode_t stop_md) ++{ ++ mutex_lock(&fbdev->lock); ++ if (!fbdev->is_lcd_en) { ++ mutex_unlock(&fbdev->lock); ++ return; ++ } ++ ++ if(stop_md == QCK_STOP) { ++ reg_write(fbdev, DC_CTRL, DC_QCK_STP_CMP); ++ udelay(20); ++ reg_write(fbdev, DC_CTRL, DC_QCK_STP_RDMA); ++ wait_dc_state(DC_WORKING, 0); ++ } else { ++ int ret; ++ reg_write(fbdev, DC_CTRL, DC_GEN_STP_CMP); ++ reg_write(fbdev, DC_CTRL, DC_GEN_STP_RDMA); ++ ret = wait_event_interruptible_timeout(fbdev->gen_stop_wq, ++ !(reg_read(fbdev, DC_ST) & DC_WORKING),msecs_to_jiffies(30000)); ++ if(ret == 0) { ++ dev_err(info->dev, "DPU wait gen stop timeout!!!\n"); ++ } ++ print_dbg("spend time = %d\n",30000-jiffies_to_msecs(ret)); ++ } ++ ++ fbdev->is_lcd_en = 0; ++ mutex_unlock(&fbdev->lock); ++} ++ ++static int ingenicfb_desc_init(struct fb_info *info, int frm_num) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ struct lcd_panel *panel = fbdev->panel; ++ struct fb_videomode *mode; ++ struct ingenicfb_frm_mode *frm_mode; ++ struct ingenicfb_frm_cfg *frm_cfg; ++ struct ingenicfb_lay_cfg *lay_cfg; ++ struct fb_var_screeninfo *var = &info->var; ++ struct ingenicfb_framedesc **framedesc; ++ struct ingenicfb_sreadesc **sreadesc; ++ int frm_num_mi, frm_num_ma; ++ int frm_size; ++ int i, j; ++ int ret = 0; ++ ++ mode = ingenicfb_get_mode(var, info); ++ if (mode == NULL) { ++ dev_err(info->dev, "%s get video mode failed\n", __func__); ++ return -EINVAL; ++ } ++ ++ framedesc = fbdev->framedesc; ++ sreadesc = fbdev->sreadesc; ++ frm_mode = &fbdev->current_frm_mode; ++ frm_cfg = &frm_mode->frm_cfg; ++ lay_cfg = frm_cfg->lay_cfg; ++ ++ ret = ingenicfb_check_frm_cfg(info, frm_cfg); ++ if(ret) { ++ dev_err(info->dev, "%s configure framedesc[%d] error!\n", __func__, frm_num); ++ return ret; ++ } ++ ++ if(frm_num == FRAME_CFG_ALL_UPDATE) { ++ frm_num_mi = 0; ++ frm_num_ma = CONFIG_FB_INGENIC_NR_FRAMES * 2; ++ } else { ++ if(frm_num < 0 || frm_num > (CONFIG_FB_INGENIC_NR_FRAMES * 2 - 1)) { ++ dev_err(info->dev, "framedesc num err!\n"); ++ return -EINVAL; ++ } ++ frm_num_mi = frm_num; ++ frm_num_ma = frm_num_mi + 1; ++ } ++ ++ ++ frm_size = mode->xres * mode->yres; ++ fbdev->frm_size = frm_size * MAX_BITS_PER_PIX >> 3; ++ info->screen_size = fbdev->frm_size; ++ ++ for(i = frm_num_mi; i < frm_num_ma; i++) { ++ framedesc[i]->FrameNextCfgAddr = fbdev->framedesc_phys[i]; ++ framedesc[i]->FrameSize.d32 = 0; ++ framedesc[i]->FrameSize.b.width = mode->xres; ++ framedesc[i]->FrameSize.b.height = mode->yres; ++ framedesc[i]->FrameCtrl.d32 = 0; ++ framedesc[i]->FrameCtrl.b.stop = 1; ++ framedesc[i]->FrameCtrl.b.wb_en = fbdev->sread_vidmem_size > 0 ? fbdev->wback_en : 0; ++ framedesc[i]->FrameCtrl.b.direct_en = 1; ++ if(fbdev->slcd_continua || ++ (panel->lcd_type == LCD_TYPE_TFT)) ++ framedesc[i]->FrameCtrl.b.change_2_rdma = 1; ++ else ++ framedesc[i]->FrameCtrl.b.change_2_rdma = 0; ++#ifdef COMPOSER_DIRECT_OUT_EN ++ framedesc[i]->FrameCtrl.b.stop = 0; ++ framedesc[i]->FrameCtrl.b.change_2_rdma = 0; ++#endif ++ framedesc[i]->FrameCtrl.b.wb_dither_en = 0; ++ framedesc[i]->FrameCtrl.b.wb_dither_auto = 0; ++ framedesc[i]->FrameCtrl.b.wb_dither_auto = 0; ++ framedesc[i]->FrameCtrl.b.wb_dither_b_dw = 0; ++ framedesc[i]->FrameCtrl.b.wb_dither_g_dw = 0; ++ framedesc[i]->FrameCtrl.b.wb_dither_r_dw = 0; ++// framedesc[i]->WritebackAddr = (uint32_t)fbdev->sread_vidmem_phys[0] + i*fbdev->frm_size; ++ framedesc[i]->WritebackAddr = (uint32_t)fbdev->sread_vidmem_phys[0]; ++ framedesc[i]->WritebackStride = mode->xres; ++ framedesc[i]->FrameCtrl.b.wb_format = DC_WB_FORMAT_888; ++ framedesc[i]->Layer0CfgAddr = fbdev->layerdesc_phys[i][0]; ++ framedesc[i]->Layer1CfgAddr = fbdev->layerdesc_phys[i][1]; ++ framedesc[i]->Layer2CfgAddr = fbdev->layerdesc_phys[i][2]; ++ framedesc[i]->Layer3CfgAddr = fbdev->layerdesc_phys[i][3]; ++ framedesc[i]->LayCfgEn.d32 = 0; ++ framedesc[i]->LayCfgEn.b.lay0_scl_en = lay_cfg[0].lay_scale_en; ++ framedesc[i]->LayCfgEn.b.lay1_scl_en = lay_cfg[1].lay_scale_en; ++ framedesc[i]->LayCfgEn.b.lay2_scl_en = lay_cfg[2].lay_scale_en; ++ framedesc[i]->LayCfgEn.b.lay3_scl_en = lay_cfg[3].lay_scale_en; ++ framedesc[i]->LayCfgEn.b.lay0_en = lay_cfg[0].lay_en; ++ framedesc[i]->LayCfgEn.b.lay1_en = lay_cfg[1].lay_en; ++ framedesc[i]->LayCfgEn.b.lay2_en = lay_cfg[2].lay_en; ++ framedesc[i]->LayCfgEn.b.lay3_en = lay_cfg[3].lay_en; ++ framedesc[i]->LayCfgEn.b.lay0_z_order = lay_cfg[0].lay_z_order; ++ framedesc[i]->LayCfgEn.b.lay1_z_order = lay_cfg[1].lay_z_order; ++ framedesc[i]->LayCfgEn.b.lay2_z_order = lay_cfg[2].lay_z_order; ++ framedesc[i]->LayCfgEn.b.lay3_z_order = lay_cfg[3].lay_z_order; ++#ifndef TEST_IRQ ++ framedesc[i]->InterruptControl.d32 = DC_SOC_MSK; ++#else ++ framedesc[i]->InterruptControl.d32 = DC_SOC_MSK | DC_EOD_MSK | DC_EOW_MSK | DC_EOC_MSK; ++#endif ++ } ++ ++ for(i = frm_num_mi; i < frm_num_ma; i++) { ++ for(j =0; j < DPU_SUPPORT_MAX_LAYERS; j++) { ++ if(!lay_cfg[j].lay_en) ++ continue; ++ ++ fbdev->layerdesc[i][j]->LayerSize.d32 = 0; ++ fbdev->layerdesc[i][j]->LayerSize.b.width = lay_cfg[j].source_w; ++ fbdev->layerdesc[i][j]->LayerSize.b.height = lay_cfg[j].source_h; ++ fbdev->layerdesc[i][j]->LayerPos.d32 = 0; ++ fbdev->layerdesc[i][j]->LayerPos.b.x_pos = lay_cfg[j].disp_pos_x; ++ fbdev->layerdesc[i][j]->LayerPos.b.y_pos = lay_cfg[j].disp_pos_y; ++ fbdev->layerdesc[i][j]->LayerCfg.d32 = 0; ++ fbdev->layerdesc[i][j]->LayerCfg.b.g_alpha_en = lay_cfg[j].g_alpha_en; ++ fbdev->layerdesc[i][j]->LayerCfg.b.g_alpha = lay_cfg[j].g_alpha_val; ++ fbdev->layerdesc[i][j]->LayerCfg.b.color = lay_cfg[j].color; ++ fbdev->layerdesc[i][j]->LayerCfg.b.domain_multi = 1; ++ fbdev->layerdesc[i][j]->LayerCfg.b.format = lay_cfg[j].format; ++ fbdev->layerdesc[i][j]->LayerCfg.b.sharpl = 0; ++ fbdev->layerdesc[i][j]->LayerStride = lay_cfg[j].stride; ++ fbdev->layerdesc[i][j]->LayerScale.d32 = 0; ++ if(lay_cfg[j].lay_scale_en) { ++ fbdev->layerdesc[i][j]->LayerScale.b.target_width = lay_cfg[j].scale_w; ++ fbdev->layerdesc[i][j]->LayerScale.b.target_height = lay_cfg[j].scale_h; ++ fbdev->layerdesc[i][j]->layerresizecoef_x = (512 * lay_cfg[j].source_w) / lay_cfg[j].scale_w; ++ fbdev->layerdesc[i][j]->layerresizecoef_y = (512 * lay_cfg[j].source_h) / lay_cfg[j].scale_h; ++ } else { ++ fbdev->layerdesc[i][j]->LayerScale.b.target_width = 0; ++ fbdev->layerdesc[i][j]->LayerScale.b.target_height = 0; ++ fbdev->layerdesc[i][j]->layerresizecoef_x = 0; ++ fbdev->layerdesc[i][j]->layerresizecoef_y = 0; ++ } ++ if(!lay_cfg[j].tlb_en) { ++ fbdev->layerdesc[i][j]->LayerBufferAddr = ++ fbdev->vidmem_phys[i % CONFIG_FB_INGENIC_NR_FRAMES][j]; ++ } else { ++ fbdev->layerdesc[i][j]->LayerBufferAddr = ++ lay_cfg[j].addr[i % CONFIG_FB_INGENIC_NR_FRAMES]; ++ } ++ if(lay_cfg[j].uv_offset[i % CONFIG_FB_INGENIC_NR_FRAMES]) { ++ fbdev->layerdesc[i][j]->UVBufferAddr = ++ fbdev->layerdesc[i][j]->LayerBufferAddr + ++ lay_cfg[j].uv_offset[i % CONFIG_FB_INGENIC_NR_FRAMES]; ++ } else { ++ fbdev->layerdesc[i][j]->UVBufferAddr = ++ fbdev->layerdesc[i][j]->LayerBufferAddr + ++ lay_cfg[j].stride * lay_cfg[j].source_h; ++ } ++ fbdev->layerdesc[i][j]->UVStride = lay_cfg[j].stride; ++ } ++ } ++ ++#ifdef CONFIG_INGENIC_FB_SIMPLE_RDMA ++ for(i = 0; i < CONFIG_FB_INGENIC_NR_FRAMES; i++) { ++ sreadesc[i]->RdmaNextCfgAddr = fbdev->sreadesc_phys[0] + i*fbdev->frm_size; ++ sreadesc[i]->FrameBufferAddr = fbdev->sread_vidmem_phys[0] + i*fbdev->frm_size; ++ sreadesc[i]->Stride = mode->xres; ++ sreadesc[i]->ChainCfg.d32 = 0; ++ sreadesc[i]->ChainCfg.b.format = RDMA_CHAIN_CFG_FORMA_888; ++ sreadesc[i]->ChainCfg.b.color = RDMA_CHAIN_CFG_COLOR_RGB; ++ sreadesc[i]->ChainCfg.b.change_2_cmp = 0; ++ if(fbdev->slcd_continua || ++ (panel->lcd_type == LCD_TYPE_TFT)) ++ sreadesc[i]->ChainCfg.b.chain_end = 0; ++ else ++ sreadesc[i]->ChainCfg.b.chain_end = 1; ++#ifdef TEST_IRQ ++ sreadesc[i]->InterruptControl.d32 = DC_SOS_MSK | DC_EOS_MSK | DC_EOD_MSK; ++#else ++ sreadesc[i]->InterruptControl.d32 = 0; ++#endif ++ } ++#endif ++ ++ for(i = frm_num_mi; i < frm_num_ma; i++) { ++ frm_mode->update_st[i] = FRAME_CFG_UPDATE; ++ } ++ ++ return 0; ++} ++ ++static int ingenicfb_update_frm_mode(struct fb_info *info) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ struct fb_videomode *mode; ++ struct ingenicfb_frm_mode *frm_mode; ++ struct ingenicfb_frm_cfg *frm_cfg; ++ struct ingenicfb_lay_cfg *lay_cfg; ++ struct fb_var_screeninfo *var = &info->var; ++ int i; ++ ++ mode = ingenicfb_get_mode(var, info); ++ if (mode == NULL) { ++ dev_err(info->dev, "%s get video mode failed\n", __func__); ++ return -EINVAL; ++ } ++ ++ frm_mode = &fbdev->current_frm_mode; ++ frm_cfg = &frm_mode->frm_cfg; ++ lay_cfg = frm_cfg->lay_cfg; ++ ++ /*Only set layer0 work*/ ++ lay_cfg[0].lay_en = 1; ++ lay_cfg[0].lay_z_order = LAYER_Z_ORDER_3; /* top */ ++ lay_cfg[1].lay_en = 0; ++ lay_cfg[1].lay_z_order = LAYER_Z_ORDER_2; ++ lay_cfg[2].lay_en = 0; ++ lay_cfg[2].lay_z_order = LAYER_Z_ORDER_1; ++ lay_cfg[3].lay_en = 0; ++ lay_cfg[3].lay_z_order = LAYER_Z_ORDER_0; ++ ++ for(i = 0; i < DPU_SUPPORT_MAX_LAYERS; i++) { ++ lay_cfg[i].source_w = mode->xres; ++ lay_cfg[i].source_h = mode->yres; ++ lay_cfg[i].disp_pos_x = 0; ++ lay_cfg[i].disp_pos_y = 0; ++ lay_cfg[i].g_alpha_en = 0; ++ lay_cfg[i].g_alpha_val = 0xff; ++ lay_cfg[i].color = ingenicfb_colormodes[COLOR_MODE_INDEX].color; ++ lay_cfg[i].format = ingenicfb_colormodes[COLOR_MODE_INDEX].mode; ++ lay_cfg[i].stride = mode->xres; ++ lay_cfg[i].scale_w = 0; ++ lay_cfg[i].scale_h = 0; ++ } ++ ++ for(i = 0; i < CONFIG_FB_INGENIC_NR_FRAMES; i++) { ++ fbdev->framedesc_array_next[i] = i + CONFIG_FB_INGENIC_NR_FRAMES; ++ fbdev->framedesc_array_use[i] = i; ++ } ++ fbdev->current_frm_desc = 0; ++ ++ return 0; ++} ++ ++static void disp_common_init(struct lcd_panel *ingenicfb_panel) { ++ uint32_t disp_com; ++ ++ disp_com = reg_read(fbdev, DC_DISP_COM); ++ disp_com &= ~DC_DP_IF_SEL_MASK; ++ if(ingenicfb_panel->lcd_type == LCD_TYPE_SLCD) { ++ disp_com |= DC_DISP_COM_SLCD; ++ } else if(ingenicfb_panel->lcd_type == LCD_TYPE_MIPI_SLCD) { ++ disp_com |= DC_DISP_COM_MIPI_SLCD; ++ } else { ++ disp_com |= DC_DISP_COM_TFT; ++ } ++ if(ingenicfb_panel->dither_enable) { ++ disp_com |= DC_DP_DITHER_EN; ++ disp_com &= ~DC_DP_DITHER_DW_MASK; ++ disp_com |= ingenicfb_panel->dither.dither_red ++ << DC_DP_DITHER_DW_RED_LBIT; ++ disp_com |= ingenicfb_panel->dither.dither_green ++ << DC_DP_DITHER_DW_GREEN_LBIT; ++ disp_com |= ingenicfb_panel->dither.dither_blue ++ << DC_DP_DITHER_DW_BLUE_LBIT; ++ } else { ++ disp_com &= ~DC_DP_DITHER_EN; ++ } ++ reg_write(fbdev, DC_DISP_COM, disp_com); ++ ++ /* QOS */ ++#if 0 ++ reg_write(fbdev, DC_PCFG_RD_CTRL, 7); ++ reg_write(fbdev, DC_PCFG_WR_CTRL, 1); ++ reg_write(fbdev, DC_WDMA_PCFG, 0x1ff << 18 | 0x1f0 << 9 | 0x1e0 << 0); ++ reg_write(fbdev, DC_OFIFO_PCFG, 0x1ff << 18 | 0x1f0 << 9 | 0x1e0 << 0); ++ reg_write(fbdev, DC_CMPW_PCFG_CTRL, 1 << 10); ++#endif ++} ++ ++static void common_cfg_init(void) ++{ ++ unsigned com_cfg = 0; ++ ++ com_cfg = reg_read(fbdev, DC_COM_CONFIG); ++ /*Keep COM_CONFIG reg first bit 0 */ ++ com_cfg &= ~DC_OUT_SEL; ++ ++ /* set burst length 32*/ ++ com_cfg &= ~DC_BURST_LEN_BDMA_MASK; ++ com_cfg |= DC_BURST_LEN_BDMA_32; ++ com_cfg &= ~DC_BURST_LEN_WDMA_MASK; ++ com_cfg |= DC_BURST_LEN_WDMA_32; ++ com_cfg &= ~DC_BURST_LEN_RDMA_MASK; ++ com_cfg |= DC_BURST_LEN_RDMA_32; ++ ++#ifdef CONFIG_INGENIC_FB_SIMPLE_RDMA ++ com_cfg |= 0x2; ++#else ++ com_cfg &= ~0x2; ++#endif ++ ++ reg_write(fbdev, DC_COM_CONFIG, com_cfg); ++} ++ ++static int ingenicfb_set_fix_par(struct fb_info *info) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ struct lcd_panel *panel = fbdev->panel; ++ unsigned int intc; ++ unsigned int disp_com; ++ unsigned int is_lcd_en; ++ ++ mutex_lock(&fbdev->lock); ++ is_lcd_en = fbdev->is_lcd_en; ++ mutex_unlock(&fbdev->lock); ++ ++ ingenicfb_disable(info, GEN_STOP); ++ ++ disp_common_init(panel); ++ ++ common_cfg_init(); ++ ++ reg_write(fbdev, DC_CLR_ST, 0x01FFFFFE); ++ ++ disp_com = reg_read(fbdev, DC_DISP_COM); ++ ++ switch (panel->lcd_type) { ++ case LCD_TYPE_TFT: ++ ingenicfb_tft_set_par(info); ++#ifdef CONFIG_FB_INGENIC_MIPI_DSI ++ fbdev->dsi->master_ops->mode_cfg(fbdev->dsi, 1); ++#endif ++ break; ++ case LCD_TYPE_SLCD: ++ ingenicfb_slcd_set_par(info); ++ break; ++ case LCD_TYPE_MIPI_SLCD: ++ ingenicfb_slcd_set_par(info); ++#ifdef CONFIG_FB_INGENIC_MIPI_DSI ++ fbdev->dsi->master_ops->mode_cfg(fbdev->dsi, 0); ++#endif ++ break; ++ } ++ ++ /* disp end gen_stop tft_under frm_start frm_end wback over GEN_STOP_SRD*/ ++// intc = DC_EOD_MSK | DC_SDA_MSK | DC_UOT_MSK | DC_SOC_MSK | DC_EOF_MSK | DC_OOW_MSK | DC_SSA_MSK; ++ intc = DC_EOD_MSK | DC_SDA_MSK | DC_UOT_MSK | DC_SOC_MSK | DC_OOW_MSK; ++ reg_write(fbdev, DC_INTC, intc); ++ ++ ingenicfb_tlb_configure(fbdev); ++ ingenicfb_tlb_enable(fbdev); ++ ++ if(is_lcd_en) { ++ ingenicfb_enable(info); ++ } ++ ++ return 0; ++} ++ ++static int ingenicfb_set_par(struct fb_info *info) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ struct fb_var_screeninfo *var = &info->var; ++ struct fb_videomode *mode; ++ uint32_t colormode; ++ unsigned long flags; ++ int ret; ++ ++ mode = ingenicfb_get_mode(var, info); ++ if (mode == NULL) { ++ dev_err(info->dev, "%s get video mode failed\n", __func__); ++ return -EINVAL; ++ } ++ info->mode = mode; ++ ++ ret = ingenicfb_check_colormode(var, &colormode); ++ if(ret) { ++ dev_err(info->dev,"Check colormode failed!\n"); ++ return ret; ++ } ++ ++ fbdev->current_frm_mode.frm_cfg.lay_cfg[0].format = colormode; ++ ++ ret = ingenicfb_desc_init(info, FRAME_CFG_ALL_UPDATE); ++ if(ret) { ++ dev_err(fbdev->dev, "Desc init err!\n"); ++ return ret; ++ } ++ ++ ++ spin_lock_irqsave(&fbdev->irq_lock, flags); ++ ++ reg_write(fbdev, DC_FRM_CFG_ADDR, fbdev->framedesc_phys[fbdev->framedesc_array_use[fbdev->current_frm_desc]]); ++ ++#ifdef CONFIG_INGENIC_FB_SIMPLE_RDMA ++ reg_write(fbdev, DC_RDMA_CHAIN_ADDR, fbdev->sreadesc_phys[0]); ++#endif ++ spin_unlock_irqrestore(&fbdev->irq_lock, flags); ++ ++ return 0; ++} ++ ++int test_pattern(struct ingenicfb_device *fbdev) ++{ ++ int ret; ++ ++ ingenicfb_disable(fbdev->fb, QCK_STOP); ++#ifdef CONFIG_INGENIC_FB_SIMPLE_RDMA ++ ingenicfb_display_sread_v_color_bar(fbdev->fb); ++#else ++ ingenicfb_display_h_color_bar(fbdev->fb); ++#endif ++ fbdev->current_frm_desc = 0; ++ ingenicfb_set_fix_par(fbdev->fb); ++ ret = ingenicfb_set_par(fbdev->fb); ++ if(ret) { ++ dev_err(fbdev->dev, "Set par failed!\n"); ++ return ret; ++ } ++ ingenicfb_enable(fbdev->fb); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_INGENIC_FB_BOOT_PATTERN ++static void ingenicfb_display_boot_pattern(struct fb_info *info) ++{ ++ int w, h; ++ int bpp; ++ ++ unsigned char *p8; ++ struct ingenicfb_device *fbdev = info->par; ++ struct fb_videomode *mode = fbdev->panel->modes; ++ ++ if (!mode) { ++ dev_err(fbdev->dev, "%s, video mode is NULL\n", __func__); ++ return; ++ } ++ if (!fbdev->vidmem_phys[fbdev->current_frm_desc][0]) { ++ dev_err(fbdev->dev, "Not allocate frame buffer yet\n"); ++ return; ++ } ++ if (!fbdev->vidmem[fbdev->current_frm_desc][0]) ++ fbdev->vidmem[fbdev->current_frm_desc][0] = ++ (void *)phys_to_virt(fbdev->vidmem_phys[fbdev->current_frm_desc][0]); ++ ++ p8 = (unsigned char *)fbdev->vidmem[fbdev->current_frm_desc][0]; ++ w = mode->xres; ++ h = mode->yres; ++ bpp = info->var.bits_per_pixel; ++ ++ dev_info(info->dev, ++ "LCD H COLOR BAR w,h,bpp(%d,%d,%d), fbdev->vidmem[0]=%p\n", w, h, ++ bpp, fbdev->vidmem[fbdev->current_frm_desc][0]); ++ ++ memcpy(p8, image_MTF070_800x1280_nv12, w*h*3/2); ++} ++ ++int boot_pattern(struct ingenicfb_device *fbdev) ++{ ++ int ret; ++ ++ ingenicfb_disable(fbdev->fb, QCK_STOP); ++ ingenicfb_display_boot_pattern(fbdev->fb); ++ fbdev->current_frm_desc = 0; ++ ingenicfb_set_fix_par(fbdev->fb); ++ ret = ingenicfb_set_par(fbdev->fb); ++ if(ret) { ++ dev_err(fbdev->dev, "Set par failed!\n"); ++ return ret; ++ } ++ ingenicfb_enable(fbdev->fb); ++ ++ return 0; ++} ++#endif ++ ++static inline int timeval_sub_to_us(struct timeval lhs, ++ struct timeval rhs) ++{ ++ int sec, usec; ++ sec = lhs.tv_sec - rhs.tv_sec; ++ usec = lhs.tv_usec - rhs.tv_usec; ++ ++ return (sec*1000000 + usec); ++} ++ ++static inline int time_us2ms(int us) ++{ ++ return (us/1000); ++} ++ ++static void calculate_frame_rate(void) ++{ ++ static struct timeval time_now, time_last; ++ unsigned int interval_in_us; ++ unsigned int interval_in_ms; ++ static unsigned int fpsCount = 0; ++ ++ switch(showFPS){ ++ case 1: ++ fpsCount++; ++ do_gettimeofday(&time_now); ++ interval_in_us = timeval_sub_to_us(time_now, time_last); ++ if ( interval_in_us > (USEC_PER_SEC) ) { /* 1 second = 1000000 us. */ ++ printk(" Pan display FPS: %d\n",fpsCount); ++ fpsCount = 0; ++ time_last = time_now; ++ } ++ break; ++ case 2: ++ do_gettimeofday(&time_now); ++ interval_in_us = timeval_sub_to_us(time_now, time_last); ++ interval_in_ms = time_us2ms(interval_in_us); ++ printk(" Pan display interval ms: %d\n",interval_in_ms); ++ time_last = time_now; ++ break; ++ default: ++ if (showFPS > 3) { ++ int d, f; ++ fpsCount++; ++ do_gettimeofday(&time_now); ++ interval_in_us = timeval_sub_to_us(time_now, time_last); ++ if (interval_in_us > USEC_PER_SEC * showFPS ) { /* 1 second = 1000000 us. */ ++ d = fpsCount / showFPS; ++ f = (fpsCount * 10) / showFPS - d * 10; ++ printk(" Pan display FPS: %d.%01d\n", d, f); ++ fpsCount = 0; ++ time_last = time_now; ++ } ++ } ++ break; ++ } ++} ++ ++static int ingenicfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ int next_frm; ++ int ret = 0; ++ ++ if (var->xoffset - info->var.xoffset) { ++ dev_err(info->dev, "No support for X panning for now\n"); ++ return -EINVAL; ++ } ++ ++ fbdev->pan_display_count++; ++ if(showFPS){ ++ calculate_frame_rate(); ++ } ++ ++ next_frm = var->yoffset / var->yres; ++ ++ if(fbdev->current_frm_mode.update_st[next_frm] == FRAME_CFG_NO_UPDATE) { ++ if((ret = ingenicfb_desc_init(info, fbdev->framedesc_array_next[next_frm]))) { ++ dev_err(info->dev, "%s: desc init err!\n", __func__); ++ return ret; ++ } ++ fbdev->framedesc_array_use[next_frm] = fbdev->framedesc_array_next[next_frm]; ++ if(fbdev->framedesc_array_next[next_frm] < CONFIG_FB_INGENIC_NR_FRAMES) ++ fbdev->framedesc_array_next[next_frm] = next_frm + CONFIG_FB_INGENIC_NR_FRAMES; ++ else ++ fbdev->framedesc_array_next[next_frm] = next_frm; ++ } ++ ++#ifdef CONFIG_FB_VSYNC_SKIP_DISABLE ++ old_desc_addr = reg_read(fbdev, DC_FRM_DES); ++#endif ++ ++ ingenicfb_tlb_enable(fbdev); ++ reg_write(fbdev, DC_FRM_CFG_ADDR, fbdev->framedesc_phys[fbdev->framedesc_array_use[next_frm]]); ++ ingenicfb_cmp_start(info); ++ ++ if(!fbdev->is_lcd_en) ++ ingenicfb_enable(info); ++ ++ fbdev->current_frm_desc = next_frm; ++ ++ return 0; ++} ++ ++static void ingenicfb_do_resume(struct ingenicfb_device *fbdev) ++{ ++ int ret; ++ ++ mutex_lock(&fbdev->suspend_lock); ++ if(fbdev->is_suspend) { ++ fbdev->timestamp.rp = 0; ++ fbdev->timestamp.wp = 0; ++ ingenicfb_clk_enable(fbdev); ++#ifdef CONFIG_FB_INGENIC_MIPI_DSI ++ fbdev->dsi->master_ops->set_blank_mode(fbdev->dsi, FB_BLANK_UNBLANK); ++#endif ++ ingenicfb_set_fix_par(fbdev->fb); ++ ret = ingenicfb_set_par(fbdev->fb); ++ if(ret) { ++ dev_err(fbdev->dev, "Set par failed!\n"); ++ } ++ ingenicfb_enable(fbdev->fb); ++ fbdev->is_suspend = 0; ++ } ++ mutex_unlock(&fbdev->suspend_lock); ++} ++ ++static void ingenicfb_do_suspend(struct ingenicfb_device *fbdev) ++{ ++ struct lcd_panel *panel = fbdev->panel; ++ struct lcd_panel_ops *panel_ops; ++ ++ panel_ops = panel->ops; ++ ++ mutex_lock(&fbdev->suspend_lock); ++ if (!fbdev->is_suspend){ ++#ifdef CONFIG_FB_INGENIC_MIPI_DSI ++ fbdev->dsi->master_ops->set_blank_mode(fbdev->dsi, FB_BLANK_POWERDOWN); ++#endif ++ ingenicfb_disable(fbdev->fb, QCK_STOP); ++ ingenicfb_clk_disable(fbdev); ++ ++ fbdev->is_suspend = 1; ++ } ++ mutex_unlock(&fbdev->suspend_lock); ++} ++ ++static int ingenicfb_blank(int blank_mode, struct fb_info *info) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ ++ if (blank_mode == FB_BLANK_UNBLANK) { ++ ingenicfb_do_resume(fbdev); ++ } else { ++ ingenicfb_do_suspend(fbdev); ++ } ++ ++ return 0; ++} ++ ++static int ingenicfb_open(struct fb_info *info, int user) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ int ret; ++ ++ if (!fbdev->is_lcd_en && fbdev->vidmem_phys) { ++ fbdev->timestamp.rp = 0; ++ fbdev->timestamp.wp = 0; ++ ingenicfb_set_fix_par(info); ++ ret = ingenicfb_set_par(info); ++ if(ret) { ++ dev_err(info->dev, "Set par failed!\n"); ++ return ret; ++ } ++ memset(fbdev->vidmem[fbdev->current_frm_desc][0], 0, fbdev->frm_size); ++ ingenicfb_enable(info); ++ } ++ ++ dev_dbg(info->dev, "####open count : %d\n", ++fbdev->open_cnt); ++ ++ return 0; ++} ++ ++static int ingenicfb_release(struct fb_info *info, int user) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ ++ dev_dbg(info->dev, "####close count : %d\n", fbdev->open_cnt--); ++ if(!fbdev->open_cnt) { ++// fbdev->timestamp.rp = 0; ++// fbdev->timestamp.wp = 0; ++ } ++ return 0; ++} ++ ++static ssize_t ingenicfb_write(struct fb_info *info, const char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ingenicfb_device *fbdev = info->par; ++ u8 *buffer, *src; ++ u8 __iomem *dst; ++ int c, cnt = 0, err = 0; ++ unsigned long total_size; ++ unsigned long p = *ppos; ++ int next_frm = 0; ++ ++ total_size = info->screen_size; ++ ++ if (total_size == 0) ++ total_size = info->fix.smem_len; ++ ++ if (p > total_size) ++ return -EFBIG; ++ ++ if (count > total_size) { ++ err = -EFBIG; ++ count = total_size; ++ } ++ ++ if (count + p > total_size) { ++ if (!err) ++ err = -ENOSPC; ++ ++ count = total_size - p; ++ } ++ ++ buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, ++ GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ dst = (u8 __iomem *) (info->screen_base + p); ++ ++ while (count) { ++ c = (count > PAGE_SIZE) ? PAGE_SIZE : count; ++ src = buffer; ++ ++ if (copy_from_user(src, buf, c)) { ++ err = -EFAULT; ++ break; ++ } ++ ++ fb_memcpy_tofb(dst, src, c); ++ dst += c; ++ src += c; ++ *ppos += c; ++ buf += c; ++ cnt += c; ++ count -= c; ++ } ++ ++ kfree(buffer); ++ ++ ++ ++ /* TODO: fix this */ ++ if (reg_read(fbdev, DC_ST) & DC_WORKING) { ++ goto end; ++ } else { ++ reg_write(fbdev, DC_FRM_CFG_ADDR, fbdev->framedesc_phys[fbdev->framedesc_array_use[fbdev->current_frm_desc]]); ++ fbdev->current_frm_desc = next_frm; ++ ingenicfb_cmp_start(info); ++ } ++ ++ /* is_lcd_en will always be 1. there is no chance to call ingenicfb_enable ....*/ ++ if(!fbdev->is_lcd_en) ++ ingenicfb_enable(info); ++ ++end: ++ return (cnt) ? cnt : err; ++} ++ ++static struct fb_ops ingenicfb_ops = { ++ .owner = THIS_MODULE, ++ .fb_open = ingenicfb_open, ++ .fb_release = ingenicfb_release, ++ .fb_write = ingenicfb_write, ++ .fb_check_var = ingenicfb_check_var, ++ .fb_set_par = ingenicfb_set_par, ++ .fb_setcolreg = ingenicfb_setcolreg, ++ .fb_blank = ingenicfb_blank, ++ .fb_pan_display = ingenicfb_pan_display, ++ .fb_fillrect = cfb_fillrect, ++ .fb_copyarea = cfb_copyarea, ++ .fb_imageblit = cfb_imageblit, ++ .fb_ioctl = ingenicfb_ioctl, ++ .fb_mmap = ingenicfb_mmap, ++}; ++ ++static int dummy_open(struct fb_info *info, int user) ++{ ++ return 0; ++} ++static int dummy_release(struct fb_info *info, int user) ++{ ++ return 0; ++} ++static int dummy_set_par(struct fb_info *info) ++{ ++ return 0; ++} ++ ++static struct fb_ops ingenicfb_layerx_ops = { ++ .owner = THIS_MODULE, ++ .fb_open = dummy_open, ++ .fb_release = dummy_release, ++ .fb_check_var = ingenicfb_check_var, ++ .fb_set_par = dummy_set_par, ++ .fb_setcolreg = ingenicfb_setcolreg, ++ .fb_fillrect = cfb_fillrect, ++ .fb_copyarea = cfb_copyarea, ++ .fb_imageblit = cfb_imageblit, ++ .fb_mmap = ingenicfb_mmap, ++}; ++ ++ static ssize_t ++dump_h_color_bar(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct ingenicfb_device *fbdev = dev_get_drvdata(dev); ++ ingenicfb_display_h_color_bar(fbdev->fb); ++ ingenicfb_cmp_start(fbdev->fb); ++ return 0; ++} ++ ++ static ssize_t ++dump_v_color_bar(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct ingenicfb_device *fbdev = dev_get_drvdata(dev); ++ ingenicfb_display_v_color_bar(fbdev->fb); ++ ingenicfb_cmp_start(fbdev->fb); ++ return 0; ++} ++ ++ static ssize_t ++vsync_skip_r(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct ingenicfb_device *fbdev = dev_get_drvdata(dev); ++ mutex_lock(&fbdev->lock); ++ snprintf(buf, 3, "%d\n", fbdev->vsync_skip_ratio); ++ printk("vsync_skip_map = 0x%08x\n", fbdev->vsync_skip_map); ++ mutex_unlock(&fbdev->lock); ++ return 3; /* sizeof ("%d\n") */ ++} ++ ++static int vsync_skip_set(struct ingenicfb_device *fbdev, int vsync_skip) ++{ ++ unsigned int map_wide10 = 0; ++ int rate, i, p, n; ++ int fake_float_1k; ++ ++ if (vsync_skip < 0 || vsync_skip > 9) ++ return -EINVAL; ++ ++ rate = vsync_skip + 1; ++ fake_float_1k = 10000 / rate; /* 10.0 / rate */ ++ ++ p = 1; ++ n = (fake_float_1k * p + 500) / 1000; /* +0.5 to int */ ++ ++ for (i = 1; i <= 10; i++) { ++ map_wide10 = map_wide10 << 1; ++ if (i == n) { ++ map_wide10++; ++ p++; ++ n = (fake_float_1k * p + 500) / 1000; ++ } ++ } ++ mutex_lock(&fbdev->lock); ++ fbdev->vsync_skip_map = map_wide10; ++ fbdev->vsync_skip_ratio = rate - 1; /* 0 ~ 9 */ ++ mutex_unlock(&fbdev->lock); ++ ++ printk("vsync_skip_ratio = %d\n", fbdev->vsync_skip_ratio); ++ printk("vsync_skip_map = 0x%08x\n", fbdev->vsync_skip_map); ++ ++ return 0; ++} ++ ++ static ssize_t ++vsync_skip_w(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct ingenicfb_device *fbdev = dev_get_drvdata(dev); ++ ++ if ((count != 1) && (count != 2)) ++ return -EINVAL; ++ if ((*buf < '0') && (*buf > '9')) ++ return -EINVAL; ++ ++ vsync_skip_set(fbdev, *buf - '0'); ++ ++ return count; ++} ++ ++static ssize_t fps_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ printk("\n-----you can choice print way:\n"); ++ printk("Example: echo NUM > show_fps\n"); ++ printk("NUM = 0: close fps statistics\n"); ++ printk("NUM = 1: print recently fps\n"); ++ printk("NUM = 2: print interval between last and this pan_display\n"); ++ printk("NUM = 3: print pan_display count\n\n"); ++ return 0; ++} ++ ++static ssize_t fps_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++ int num = 0; ++ num = simple_strtoul(buf, NULL, 0); ++ if(num < 0){ ++ printk("\n--please 'cat show_fps' to view using the method\n\n"); ++ return n; ++ } ++ showFPS = num; ++ if(showFPS == 3) ++ printk(KERN_DEBUG " Pand display count=%d\n",fbdev->pan_display_count); ++ return n; ++} ++ ++ ++ static ssize_t ++debug_clr_st(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct ingenicfb_device *fbdev = dev_get_drvdata(dev); ++ reg_write(fbdev, DC_CLR_ST, 0xffffffff); ++ return 0; ++} ++ ++static ssize_t test_suspend(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++ int num = 0; ++ num = simple_strtoul(buf, NULL, 0); ++ printk("0 --> resume | 1 --> suspend\nnow input %d\n", num); ++ if (num == 0) { ++ ingenicfb_do_resume(fbdev); ++ } else { ++ ingenicfb_do_suspend(fbdev); ++ } ++ return n; ++} ++ ++/*************************self test******************************/ ++static ssize_t test_slcd_send_value(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++ int num = 0; ++ num = simple_strtoul(buf, NULL, 0); ++ if (num == 0) { ++ slcd_send_mcu_command(fbdev, 0x0); ++ slcd_send_mcu_command(fbdev, 0xffffff); ++ slcd_send_mcu_command(fbdev, 0x0); ++ slcd_send_mcu_command(fbdev, 0xffffff); ++ slcd_send_mcu_command(fbdev, 0x0); ++ slcd_send_mcu_command(fbdev, 0xffffff); ++ slcd_send_mcu_command(fbdev, 0x0); ++ slcd_send_mcu_command(fbdev, 0xffffff); ++ slcd_send_mcu_command(fbdev, 0x0); ++ slcd_send_mcu_command(fbdev, 0xffffff); ++ printk("Send command value 101\n"); ++ } else if(num == 1){ ++ slcd_send_mcu_prm(fbdev, 0x0); ++ slcd_send_mcu_prm(fbdev, 0xffffffff); ++ slcd_send_mcu_prm(fbdev, 0x0); ++ slcd_send_mcu_prm(fbdev, 0xffffffff); ++ slcd_send_mcu_prm(fbdev, 0x0); ++ slcd_send_mcu_prm(fbdev, 0xffffffff); ++ slcd_send_mcu_prm(fbdev, 0x0); ++ slcd_send_mcu_prm(fbdev, 0xffffffff); ++ slcd_send_mcu_prm(fbdev, 0x0); ++ slcd_send_mcu_prm(fbdev, 0xffffffff); ++ slcd_send_mcu_prm(fbdev, 0x0); ++ slcd_send_mcu_prm(fbdev, 0xffffffff); ++ printk("Send prm value 0x101\n"); ++ } else { ++ slcd_send_mcu_data(fbdev, 0x0); ++ slcd_send_mcu_data(fbdev, 0xffffffff); ++ slcd_send_mcu_data(fbdev, 0x0); ++ slcd_send_mcu_data(fbdev, 0xffffffff); ++ slcd_send_mcu_data(fbdev, 0x0); ++ slcd_send_mcu_data(fbdev, 0xffffffff); ++ slcd_send_mcu_data(fbdev, 0x0); ++ slcd_send_mcu_data(fbdev, 0xffffffff); ++ slcd_send_mcu_data(fbdev, 0x0); ++ slcd_send_mcu_data(fbdev, 0xffffffff); ++ slcd_send_mcu_data(fbdev, 0x0); ++ slcd_send_mcu_data(fbdev, 0xffffffff); ++ printk("Send data value 0x101\n"); ++ } ++ return n; ++} ++ ++static ssize_t test_fifo_threshold(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++ int num = 0; ++ unsigned int ctrl; ++ unsigned int cfg = 0; ++ num = simple_strtoul(buf, NULL, 0); ++ if (num == 0) { ++ ctrl = reg_read(fbdev, DC_PCFG_RD_CTRL); ++ ctrl &= ~DC_ARQOS_CTRL; ++ reg_write(fbdev, DC_PCFG_RD_CTRL, ctrl); ++ printk("Close software control %d\n", num); ++ } else { ++ ctrl = reg_read(fbdev, DC_PCFG_RD_CTRL); ++ ctrl |= DC_ARQOS_CTRL; ++ ctrl &= ~DC_ARQOS_VAL_MASK; ++ switch(num) { ++ case 1: ++ ctrl |= DC_ARQOS_VAL_0; ++ break; ++ case 2: ++ ctrl |= DC_ARQOS_VAL_1; ++ break; ++ case 3: ++ ctrl |= DC_ARQOS_VAL_2; ++ break; ++ case 4: ++ ctrl |= DC_ARQOS_VAL_3; ++ break; ++ default: ++ printk("Input err value %d\n", num); ++ return n; ++ } ++ reg_write(fbdev, DC_PCFG_RD_CTRL, ctrl); ++ cfg = (60 << DC_PCFG0_LBIT) | (120 << DC_PCFG1_LBIT) | (180 << DC_PCFG2_LBIT); ++ reg_write(fbdev, DC_OFIFO_PCFG, cfg); ++ printk("DC_OFIFO_PCFG = 0x%x DC_PCFG_RD_CTRL = 0x%x\n", DC_OFIFO_PCFG, DC_PCFG_RD_CTRL); ++ } ++ return n; ++} ++static ssize_t test_slcd_time(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++ unsigned int num = 0; ++ unsigned int type = 0; ++ unsigned int value; ++ num = simple_strtoul(buf, NULL, 0); ++ ++ type = (num >> 8) & 0xff; ++ switch(type) { ++ case 0: ++ printk("\n0: print set ways\n"); ++ printk("1: CDTIME\n"); ++ printk("2: CSTIME\n"); ++ printk("3: DDTIME\n"); ++ printk("4: DSTIME\n"); ++ printk("5: TAS\n"); ++ printk("6: TAH\n"); ++ printk("7: TCS\n"); ++ printk("8: TCH\n"); ++ printk("9: Slow time\n\n"); ++ break; ++ case 1: ++ value = reg_read(fbdev, DC_SLCD_WR_DUTY); ++ reg_write(fbdev, DC_SLCD_WR_DUTY, ((num & 0xff) << DC_CDTIME_LBIT) | (value & ~DC_CDTIME_MASK)); ++ break; ++ case 2: ++ value = reg_read(fbdev, DC_SLCD_WR_DUTY); ++ reg_write(fbdev, DC_SLCD_WR_DUTY, ((num & 0xff) << DC_CSTIME_LBIT) | (value & ~DC_CSTIME_MASK)); ++ break; ++ case 3: ++ value = reg_read(fbdev, DC_SLCD_WR_DUTY); ++ reg_write(fbdev, DC_SLCD_WR_DUTY, ((num & 0xff) << DC_DDTIME_LBIT) | (value & ~DC_DDTIME_MASK)); ++ break; ++ case 4: ++ value = reg_read(fbdev, DC_SLCD_WR_DUTY); ++ reg_write(fbdev, DC_SLCD_WR_DUTY, ((num & 0xff) << DC_DSTIME_LBIT) | (value & ~DC_DSTIME_MASK)); ++ break; ++ case 5: ++ value = reg_read(fbdev, DC_SLCD_TIMING); ++ reg_write(fbdev, DC_SLCD_TIMING, ((num & 0xff) << DC_TAS_LBIT) | (value & ~DC_TAS_MASK)); ++ break; ++ case 6: ++ value = reg_read(fbdev, DC_SLCD_TIMING); ++ reg_write(fbdev, DC_SLCD_TIMING, ((num & 0xff) << DC_TAH_LBIT) | (value & ~DC_TAH_MASK)); ++ break; ++ case 7: ++ value = reg_read(fbdev, DC_SLCD_TIMING); ++ reg_write(fbdev, DC_SLCD_TIMING, ((num & 0xff) << DC_TCS_LBIT) | (value & ~DC_TCS_MASK)); ++ break; ++ case 8: ++ value = reg_read(fbdev, DC_SLCD_TIMING); ++ reg_write(fbdev, DC_SLCD_TIMING, ((num & 0xff) << DC_TCH_LBIT) | (value & ~DC_TCH_MASK)); ++ break; ++ case 9: ++ value = reg_read(fbdev, DC_SLCD_SLOW_TIME); ++ reg_write(fbdev, DC_SLCD_SLOW_TIME, ((num & 0xff) << DC_SLOW_TIME_LBIT) | (value & ~DC_SLOW_TIME_MASK)); ++ break; ++ default: ++ printk("Input err value %d\n", num); ++ return n; ++ } ++ printk("DC_SLCD_WR_DUTY = 0x%lx\n", reg_read(fbdev, DC_SLCD_WR_DUTY)); ++ printk("DC_SLCD_TIMING = 0x%lx\n", reg_read(fbdev, DC_SLCD_TIMING)); ++ printk("DC_SLCD_SLOW_TIME = 0x%lx\n", reg_read(fbdev, DC_SLCD_SLOW_TIME)); ++ return n; ++} ++static ssize_t show_irq_msg(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ char *p = buf; ++ p += printk(p, "0 -> set: all irq\n"); ++ p += printk(p, "1 -> set: DC_CMP_W_SLOW\n"); ++ p += printk(p, "2 -> set: DC_DISP_END\n"); ++ p += printk(p, "3 -> set: DC_WDMA_OVER\n"); ++ p += printk(p, "4 -> set: DC_WDMA_END\n"); ++ p += printk(p, "5 -> set: DC_CMP_START\n"); ++ p += printk(p, "6 -> set: DC_LAY3_END\n"); ++ p += printk(p, "7 -> set: DC_LAY2_END\n"); ++ p += printk(p, "8 -> set: DC_LAY1_END\n"); ++ p += printk(p, "9 -> set: DC_LAY0_END\n"); ++ p += printk(p, "10 -> set: DC_CMP_END\n"); ++ p += printk(p, "11 -> set: DC_TFT_UNDR\n"); ++ p += printk(p, "12 -> set: DC_STOP_WRBK_ACK\n"); ++ p += printk(p, "13 -> set: DC_STOP_DISP_ACK\n"); ++ p += printk(p, "14 -> set: DC_SRD_START\n"); ++ p += printk(p, "15 -> set: DC_SRD_END\n"); ++ ++ return p - buf; ++} ++static ssize_t set_irq_bit(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++ struct ingenicfb_device *fbdev = dev_get_drvdata(dev); ++ int num = 0; ++ unsigned int irq; ++ num = simple_strtoul(buf, NULL, 0); ++ irq = reg_read(fbdev, DC_INTC); ++ switch(num) { ++ case 0: ++ reg_write(fbdev, DC_INTC, 0x820f46); ++ break; ++ case 1: ++ reg_write(fbdev, DC_INTC, DC_CMP_W_SLOW | irq); ++ break; ++ case 2: ++ reg_write(fbdev, DC_INTC, DC_DISP_END | irq); ++ break; ++ case 3: ++ reg_write(fbdev, DC_INTC, DC_WDMA_OVER | irq); ++ break; ++ case 4: ++ reg_write(fbdev, DC_INTC, DC_WDMA_END | irq); ++ break; ++ case 5: ++ reg_write(fbdev, DC_INTC, DC_CMP_START | irq); ++ break; ++ case 6: ++ reg_write(fbdev, DC_INTC, DC_LAY3_END | irq); ++ break; ++ case 7: ++ reg_write(fbdev, DC_INTC, DC_LAY2_END | irq); ++ break; ++ case 8: ++ reg_write(fbdev, DC_INTC, DC_LAY1_END | irq); ++ break; ++ case 9: ++ reg_write(fbdev, DC_INTC, DC_LAY0_END | irq); ++ break; ++ case 10: ++ reg_write(fbdev, DC_INTC, DC_CMP_END | irq); ++ break; ++ case 11: ++ reg_write(fbdev, DC_INTC, DC_TFT_UNDR | irq); ++ break; ++ case 12: ++ reg_write(fbdev, DC_INTC, DC_STOP_WRBK_ACK | irq); ++ break; ++ case 13: ++ reg_write(fbdev, DC_INTC, DC_STOP_DISP_ACK | irq); ++ break; ++ case 14: ++ reg_write(fbdev, DC_INTC, DC_SRD_START | irq); ++ break; ++ case 15: ++ reg_write(fbdev, DC_INTC, DC_SRD_END | irq); ++ break; ++ default: ++ printk("Err: Please check num = %d", num); ++ reg_write(fbdev, DC_INTC, DC_CMP_START); ++ break; ++ } ++ ++ return n; ++} ++ ++#ifdef CONFIG_FB_INGENIC_MIPI_DSI ++static ssize_t ++dump_dsi(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct ingenicfb_device *fbdev = dev_get_drvdata(dev); ++ struct dsi_device *dsi = fbdev->dsi; ++ ++ mutex_lock(&fbdev->lock); ++ dump_dsi_reg(dsi); ++ mutex_unlock(&fbdev->lock); ++ return 0; ++} ++ ++static ssize_t ++dsi_query_te(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct ingenicfb_device *fbdev = dev_get_drvdata(dev); ++ struct dsi_device *dsi = fbdev->dsi; ++ ++ mutex_lock(&fbdev->lock); ++ fbdev->dsi->master_ops->query_te(dsi); ++ mutex_unlock(&fbdev->lock); ++ return 0; ++} ++#endif ++ ++ ++static ssize_t ++test_fb_disable(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct ingenicfb_device *fbdev = dev_get_drvdata(dev); ++ ++ ingenicfb_disable(fbdev->fb, GEN_STOP); ++ return 0; ++} ++ ++static ssize_t ++test_fb_enable(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct ingenicfb_device *fbdev = dev_get_drvdata(dev); ++ ++ ingenicfb_enable(fbdev->fb); ++ return 0; ++} ++ ++static ssize_t show_color_modes(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct ingenicfb_device *fbdev = dev_get_drvdata(dev); ++ struct ingenicfb_colormode *current_mode = NULL; ++ char *p = buf; ++ int i = 0; ++ ++ p += sprintf(p, "supported color modes:\n"); ++ for(i = 0; i < ARRAY_SIZE(ingenicfb_colormodes); i++) { ++ struct ingenicfb_colormode * m = &ingenicfb_colormodes[i]; ++ p += sprintf(p, "[%d]:%s\n", i, m->name); ++ ++ if(m->mode == fbdev->current_frm_mode.frm_cfg.lay_cfg[0].format) { ++ current_mode = m; ++ } ++ } ++ p += sprintf(p, "Current color mode: [%s]\n", current_mode ? current_mode->name:"none"); ++ p += sprintf(p, "Tips: echo [%s] to select one of supported color modes\n", current_mode ? current_mode->name:"none"); ++ ++ return p - buf; ++ ++} ++ ++static ssize_t store_color_modes(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++ struct ingenicfb_device *fbdev = dev_get_drvdata(dev); ++ struct fb_info *fb = fbdev->fb; ++ struct ingenicfb_colormode *m = NULL; ++ int index = 0; ++ int ret = 0; ++ ++ index = simple_strtol(buf, NULL, 10); ++ ++ if(index < 0 && index > ARRAY_SIZE(ingenicfb_colormodes)) ++ return -EINVAL; ++ ++ m = &ingenicfb_colormodes[index]; ++ ++ /* modify fb var. */ ++ ingenicfb_colormode_to_var(&fb->var, m); ++ ++ /* reset params. */ ++ ret = ingenicfb_set_par(fbdev->fb); ++ if(ret < 0) ++ return ret; ++ ++ return n; ++} ++static ssize_t show_wback_en(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct ingenicfb_device *fbdev = dev_get_drvdata(dev); ++ char *p = buf; ++ ++ p += sprintf(p, "help: write [1/0] to [en/dis] wback\n"); ++ p += sprintf(p, "wback_en: %d\n", fbdev->wback_en); ++ ++ return p - buf; ++} ++ ++static ssize_t store_wback_en(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++ struct ingenicfb_device *fbdev = dev_get_drvdata(dev); ++ int en = 0; ++ int ret = 0; ++ ++ en = simple_strtol(buf, NULL, 10); ++ ++ fbdev->wback_en = !!en; ++ ++ /* reset params. */ ++ ret = ingenicfb_set_par(fbdev->fb); ++ if(ret < 0) ++ return ret; ++ ++ return n; ++} ++ ++static ssize_t show_csc_mode(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct ingenicfb_device *fbdev = dev_get_drvdata(dev); ++ char *p = buf; ++ ++ p += sprintf(p, "current csc_mode: %d\n", fbdev->csc_mode); ++ ++ return p - buf; ++} ++ ++static ssize_t store_csc_mode(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++ struct ingenicfb_device *fbdev = dev_get_drvdata(dev); ++ int csc_mode = 0; ++ int ret = 0; ++ ++ csc_mode = simple_strtol(buf, NULL, 10); ++ ++ if(csc_mode < 0 || csc_mode > 3) { ++ return -EINVAL; ++ } ++ ++ csc_mode_set(fbdev, csc_mode); ++ fbdev->csc_mode = csc_mode; ++ ++ /* reset params. */ ++ ret = ingenicfb_set_par(fbdev->fb); ++ if(ret < 0) ++ return ret; ++ ++ return n; ++} ++ ++static ssize_t show_wbackbuf(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct ingenicfb_device *fbdev = dev_get_drvdata(dev); ++ ++ char *wbackbuf = fbdev->sread_vidmem[0]; /* TODO: where should wback addr is?*/ ++ unsigned int wbackbuf_len = fbdev->frm_size; ++ int copy_len = wbackbuf_len < 1024 ? wbackbuf_len : 1024; /* only copy first 1024 bytes for quik debug.*/ ++ ++ if(fbdev->wback_en == 0) { ++ return -EINVAL; ++ } ++ ++ print_hex_dump(KERN_INFO, "wback data: ", DUMP_PREFIX_ADDRESS, 16, 1, wbackbuf, 128, true); ++ ++ memcpy(buf, wbackbuf, copy_len); ++ ++ return copy_len; ++} ++ ++/*************************self test******************************/ ++ ++/**********************lcd_debug***************************/ ++static DEVICE_ATTR(dump_lcd, S_IRUGO|S_IWUSR, dump_lcd, NULL); ++static DEVICE_ATTR(dump_h_color_bar, S_IRUGO|S_IWUSR, dump_h_color_bar, NULL); ++static DEVICE_ATTR(dump_v_color_bar, S_IRUGO|S_IWUSR, dump_v_color_bar, NULL); ++static DEVICE_ATTR(vsync_skip, S_IRUGO|S_IWUSR, vsync_skip_r, vsync_skip_w); ++static DEVICE_ATTR(show_fps, S_IRUGO|S_IWUSR, fps_show, fps_store); ++static DEVICE_ATTR(debug_clr_st, S_IRUGO|S_IWUSR, debug_clr_st, NULL); ++static DEVICE_ATTR(test_suspend, S_IRUGO|S_IWUSR, NULL, test_suspend); ++ ++#ifdef CONFIG_DEBUG_DPU_IRQCNT ++static DEVICE_ATTR(dump_irqcnts, (S_IRUGO|S_IWUGO) & (~S_IWOTH), dump_irqcnts, NULL); ++#endif ++ ++#ifdef CONFIG_FB_INGENIC_MIPI_DSI ++static DEVICE_ATTR(dump_dsi, S_IRUGO|S_IWUSR, dump_dsi, NULL); ++static DEVICE_ATTR(dsi_query_te, S_IRUGO|S_IWUSR, dsi_query_te, NULL); ++#endif ++static DEVICE_ATTR(test_fb_disable, (S_IRUGO|S_IWUGO)&(~S_IWOTH), test_fb_disable, NULL); ++static DEVICE_ATTR(test_fb_enable, (S_IRUGO|S_IWUGO)&(~S_IWOTH) , test_fb_enable, NULL); ++ ++static DEVICE_ATTR(test_irq, S_IRUGO|S_IWUSR, show_irq_msg, set_irq_bit); ++static DEVICE_ATTR(test_fifo_threshold, S_IRUGO|S_IWUSR, NULL, test_fifo_threshold); ++static DEVICE_ATTR(test_slcd_time, S_IRUGO|S_IWUSR, NULL, test_slcd_time); ++static DEVICE_ATTR(test_slcd_send_value, S_IRUGO|S_IWUSR, NULL, test_slcd_send_value); ++static DEVICE_ATTR(color_modes, S_IRUGO|S_IWUSR, show_color_modes, store_color_modes); ++static DEVICE_ATTR(wback_en, S_IRUGO|S_IWUSR, show_wback_en, store_wback_en); ++static DEVICE_ATTR(wbackbuf, S_IRUGO|S_IWUSR, show_wbackbuf, NULL); ++static DEVICE_ATTR(csc_mode, S_IRUGO|S_IWUSR, show_csc_mode, store_csc_mode); ++ ++ ++static struct attribute *lcd_debug_attrs[] = { ++ &dev_attr_dump_lcd.attr, ++ &dev_attr_dump_h_color_bar.attr, ++ &dev_attr_dump_v_color_bar.attr, ++ &dev_attr_vsync_skip.attr, ++ &dev_attr_show_fps.attr, ++ &dev_attr_debug_clr_st.attr, ++ &dev_attr_test_suspend.attr, ++ ++#ifdef CONFIG_DEBUG_DPU_IRQCNT ++ &dev_attr_dump_irqcnts.attr, ++#endif ++ ++#ifdef CONFIG_FB_INGENIC_MIPI_DSI ++ &dev_attr_dump_dsi.attr, ++ &dev_attr_dsi_query_te.attr, ++#endif ++ &dev_attr_test_fb_disable.attr, ++ &dev_attr_test_fb_enable.attr, ++ &dev_attr_test_irq.attr, ++ &dev_attr_test_fifo_threshold.attr, ++ &dev_attr_test_slcd_time.attr, ++ &dev_attr_test_slcd_send_value.attr, ++ &dev_attr_color_modes.attr, ++ &dev_attr_wback_en.attr, ++ &dev_attr_wbackbuf.attr, ++ &dev_attr_csc_mode.attr, ++ NULL, ++}; ++ ++const char lcd_group_name[] = "debug"; ++static struct attribute_group lcd_debug_attr_group = { ++ .name = lcd_group_name, ++ .attrs = lcd_debug_attrs, ++}; ++ ++struct layer_device_attr { ++ struct device_attribute attr; ++ unsigned int id; ++}; ++ ++#define to_layer_attr(attr) \ ++ container_of(attr, struct layer_device_attr, attr) ++ ++ ++static ssize_t show_src_size(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct ingenicfb_device *fbdev = dev_get_drvdata(dev); ++ int layer = to_layer_attr(attr)->id; ++ struct ingenicfb_frm_cfg *frm_cfg = &fbdev->current_frm_mode.frm_cfg; ++ struct ingenicfb_lay_cfg *lay_cfg; ++ char *p = buf; ++ ++ if(layer > CONFIG_FB_INGENIC_NR_LAYERS) { ++ return -EINVAL; ++ } ++ lay_cfg = &frm_cfg->lay_cfg[layer]; ++ ++ p += sprintf(p, "layer: %d, src_w: %d, src_h: %d\n", layer, lay_cfg->source_w, lay_cfg->source_h); ++ ++ return p - buf; ++} ++static ssize_t store_src_size(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++ ++ return n; ++} ++static ssize_t show_src_fmt(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ ++ struct ingenicfb_device *fbdev = dev_get_drvdata(dev); ++ struct ingenicfb_colormode *current_mode = NULL; ++ int layer = to_layer_attr(attr)->id; ++ char *p = buf; ++ int i = 0; ++ ++ p += sprintf(p, "supported color modes:\n"); ++ for(i = 0; i < ARRAY_SIZE(ingenicfb_colormodes); i++) { ++ struct ingenicfb_colormode * m = &ingenicfb_colormodes[i]; ++ p += sprintf(p, "[%d]:%s\n", i, m->name); ++ ++ if(m->mode == fbdev->current_frm_mode.frm_cfg.lay_cfg[layer].format) { ++ current_mode = m; ++ } ++ } ++ p += sprintf(p, "Current color mode: [%s]\n", current_mode ? current_mode->name:"none"); ++ p += sprintf(p, "Tips: echo [%s] to select one of supported color modes\n", current_mode ? current_mode->name:"none"); ++ ++ return p - buf; ++} ++static ssize_t store_src_fmt(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++ struct ingenicfb_device *fbdev = dev_get_drvdata(dev); ++ struct fb_info *fb = fbdev->fb; ++ struct ingenicfb_colormode *m = NULL; ++ int index = 0; ++ int layer = to_layer_attr(attr)->id; ++ struct ingenicfb_frm_cfg *frm_cfg = &fbdev->current_frm_mode.frm_cfg; ++ struct ingenicfb_lay_cfg *lay_cfg; ++ ++ index = simple_strtol(buf, NULL, 10); ++ ++ if(index < 0 && index > ARRAY_SIZE(ingenicfb_colormodes)) ++ return -EINVAL; ++ ++ m = &ingenicfb_colormodes[index]; ++ ++ if(layer > CONFIG_FB_INGENIC_NR_LAYERS) { ++ return -EINVAL; ++ } ++ ++ lay_cfg = &frm_cfg->lay_cfg[layer]; ++ lay_cfg->format = m->mode; ++ ++ /*update fb_info.*/ ++ fb = fbdev->fbs[layer]; ++ ingenicfb_colormode_to_var(&fb->var, m); ++ fb->mode = ingenicfb_get_mode(&fb->var, fb); ++ ++ return n; ++ ++} ++static ssize_t show_target_size(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct ingenicfb_device *fbdev = dev_get_drvdata(dev); ++ int layer = to_layer_attr(attr)->id; ++ struct ingenicfb_frm_cfg *frm_cfg = &fbdev->current_frm_mode.frm_cfg; ++ struct ingenicfb_lay_cfg *lay_cfg; ++ char *p = buf; ++ ++ if(layer > CONFIG_FB_INGENIC_NR_LAYERS) { ++ return -EINVAL; ++ } ++ ++ lay_cfg = &frm_cfg->lay_cfg[layer]; ++ ++ p += sprintf(p, "%dx%d\n", lay_cfg->scale_w, lay_cfg->scale_h); ++ ++ return p - buf; ++} ++static ssize_t store_target_size(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++ struct ingenicfb_device *fbdev = dev_get_drvdata(dev); ++ int layer = to_layer_attr(attr)->id; ++ struct ingenicfb_frm_cfg *frm_cfg = &fbdev->current_frm_mode.frm_cfg; ++ struct ingenicfb_lay_cfg *lay_cfg; ++ char *p; ++ char *s = (char *)buf; ++ ++ if(layer > CONFIG_FB_INGENIC_NR_LAYERS) { ++ return -EINVAL; ++ } ++ ++ lay_cfg = &frm_cfg->lay_cfg[layer]; ++ ++ p = strsep(&s, "x"); ++ if(!s) { ++ return -EINVAL; ++ } ++ ++ lay_cfg->scale_w = simple_strtoul(p, NULL, 0); ++ lay_cfg->scale_h = simple_strtoul(s, NULL, 0); ++ ++ ++ printk("scale_w: %d, scale_h: %d\n", lay_cfg->scale_w, lay_cfg->scale_h); ++ ++ return n; ++} ++static ssize_t show_target_pos(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct ingenicfb_device *fbdev = dev_get_drvdata(dev); ++ int layer = to_layer_attr(attr)->id; ++ struct ingenicfb_frm_cfg *frm_cfg = &fbdev->current_frm_mode.frm_cfg; ++ struct ingenicfb_lay_cfg *lay_cfg; ++ char *p = buf; ++ ++ if(layer > CONFIG_FB_INGENIC_NR_LAYERS) { ++ return -EINVAL; ++ } ++ ++ lay_cfg = &frm_cfg->lay_cfg[layer]; ++ ++ p += sprintf(p, "layer:%d, pos_x: %d, pos_y:%d\n", layer, lay_cfg->disp_pos_x, lay_cfg->disp_pos_y); ++ ++ return p - buf; ++} ++static ssize_t store_target_pos(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++ struct ingenicfb_device *fbdev = dev_get_drvdata(dev); ++ int layer = to_layer_attr(attr)->id; ++ struct ingenicfb_frm_cfg *frm_cfg = &fbdev->current_frm_mode.frm_cfg; ++ struct ingenicfb_lay_cfg *lay_cfg; ++ char *p; ++ char *s = (char *)buf; ++ ++ if(layer > CONFIG_FB_INGENIC_NR_LAYERS) { ++ return -EINVAL; ++ } ++ ++ lay_cfg = &frm_cfg->lay_cfg[layer]; ++ ++ p = strsep(&s, "x"); ++ if(!s) { ++ return -EINVAL; ++ } ++ ++ lay_cfg->disp_pos_x = simple_strtoul(p, NULL, 0); ++ lay_cfg->disp_pos_y = simple_strtoul(s, NULL, 0); ++ ++ ++ printk("-pos_x: %d, pos_y: %d\n", lay_cfg->disp_pos_x, lay_cfg->disp_pos_y); ++ ++ return n; ++} ++ ++static ssize_t show_enable(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct ingenicfb_device *fbdev = dev_get_drvdata(dev); ++ int layer = to_layer_attr(attr)->id; ++ struct ingenicfb_frm_cfg *frm_cfg = &fbdev->current_frm_mode.frm_cfg; ++ struct ingenicfb_lay_cfg *lay_cfg; ++ char *p = buf; ++ ++ if(layer > CONFIG_FB_INGENIC_NR_LAYERS) { ++ return -EINVAL; ++ } ++ ++ lay_cfg = &frm_cfg->lay_cfg[layer]; ++ ++ p += sprintf(p, "layer: %d, enable: %d\n", layer, lay_cfg->lay_en); ++ ++ return p - buf; ++} ++static ssize_t store_enable(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++ struct ingenicfb_device *fbdev = dev_get_drvdata(dev); ++ struct fb_info *fb = fbdev->fb; ++ struct ingenicfb_frm_cfg *frm_cfg = &fbdev->current_frm_mode.frm_cfg; ++ struct ingenicfb_lay_cfg *lay_cfg; ++ int layer = to_layer_attr(attr)->id; ++ int enable = 0; ++ ++ if(layer > CONFIG_FB_INGENIC_NR_LAYERS) { ++ return -EINVAL; ++ } ++ ++ lay_cfg = &frm_cfg->lay_cfg[layer]; ++ ++ if(lay_cfg->scale_w == 0 || lay_cfg->scale_h == 0) { ++ return -EINVAL; ++ } ++ ++ enable = simple_strtoul(buf, NULL, 0); ++ if(enable) { ++ lay_cfg->lay_en = 1; ++ if(lay_cfg->scale_w != lay_cfg->source_w || lay_cfg->scale_h != lay_cfg->source_h) { ++ lay_cfg->lay_scale_en = 1; ++ } else { ++ lay_cfg->lay_scale_en = 0; ++ } ++ } else { ++ lay_cfg->lay_en = 0; ++ lay_cfg->lay_scale_en = 0; ++ } ++ ++ ++ ++#if 0 ++ printk("layer: %d src_w: %d, src_h: %d, scale_w: %d, scale_h: %d, pos_x:%d, pos_y:%d\n", ++ layer, lay_cfg->source_w, lay_cfg->source_h, lay_cfg->scale_w, lay_cfg->scale_h, lay_cfg->disp_pos_x, lay_cfg->disp_pos_y); ++#endif ++ ++ /*update all layers?*/ ++ if(layer == 0) { ++ ingenicfb_disable(fbdev->fb, GEN_STOP); ++ ingenicfb_set_par(fb); ++ ingenicfb_enable(fbdev->fb); ++ } ++ return n; ++} ++ ++ ++#define LAYER_ATTR(layer, _name, _mode, _show, _store) \ ++ { \ ++ .attr = __ATTR(_name, _mode, _show, _store), \ ++ .id = layer, \ ++ } ++ ++ ++#define LAYER_DEVICE_ATTR(_name, _mode, _show, _store) \ ++ static struct layer_device_attr dev_attr_##_name##layer0 = LAYER_ATTR(0, _name, _mode, _show, _store); \ ++ static struct layer_device_attr dev_attr_##_name##layer1 = LAYER_ATTR(1, _name, _mode, _show, _store); \ ++ static struct layer_device_attr dev_attr_##_name##layer2 = LAYER_ATTR(2, _name, _mode, _show, _store); \ ++ static struct layer_device_attr dev_attr_##_name##layer3 = LAYER_ATTR(3, _name, _mode, _show, _store) ++ ++LAYER_DEVICE_ATTR(src_size, S_IRUGO|S_IWUSR, show_src_size, store_src_size); ++LAYER_DEVICE_ATTR(src_fmt, S_IRUGO|S_IWUSR, show_src_fmt, store_src_fmt); ++LAYER_DEVICE_ATTR(target_size, S_IRUGO|S_IWUSR, show_target_size, store_target_size); ++LAYER_DEVICE_ATTR(target_pos, S_IRUGO|S_IWUSR, show_target_pos, store_target_pos); ++LAYER_DEVICE_ATTR(enable, S_IRUGO|S_IWUSR, show_enable, store_enable); ++ ++#define LAYER_ATTRIBUTE_GROUP(name) \ ++ static struct attribute *lcd_##name##_attrs[] = { \ ++ &dev_attr_src_size##name.attr.attr, \ ++ &dev_attr_src_fmt##name.attr.attr, \ ++ &dev_attr_target_size##name.attr.attr, \ ++ &dev_attr_target_pos##name.attr.attr, \ ++ &dev_attr_enable##name.attr.attr, \ ++ NULL, \ ++ }; ++ ++LAYER_ATTRIBUTE_GROUP(layer0); ++LAYER_ATTRIBUTE_GROUP(layer1); ++LAYER_ATTRIBUTE_GROUP(layer2); ++LAYER_ATTRIBUTE_GROUP(layer3); ++ ++static struct attribute_group lcd_layer0_group = { ++ .name = "layer0", ++ .attrs = lcd_layer0_attrs, ++}; ++static struct attribute_group lcd_layer1_group = { ++ .name = "layer1", ++ .attrs = lcd_layer1_attrs, ++}; ++static struct attribute_group lcd_layer2_group = { ++ .name = "layer2", ++ .attrs = lcd_layer2_attrs, ++}; ++static struct attribute_group lcd_layer3_group = { ++ .name = "layer3", ++ .attrs = lcd_layer3_attrs, ++}; ++ ++static const struct attribute_group *lcd_layerx_groups[] = { ++ &lcd_layer0_group, ++ &lcd_layer1_group, ++ &lcd_layer2_group, ++ &lcd_layer3_group, ++ NULL, ++}; ++ ++static void ingenicfb_free_devmem(struct ingenicfb_device *fbdev) ++{ ++ size_t buff_size; ++ ++ dma_free_coherent(fbdev->dev, ++ fbdev->vidmem_size + fbdev->sread_vidmem_size, ++ fbdev->vidmem[0][0], ++ fbdev->vidmem_phys[0][0]); ++ ++ buff_size = sizeof(struct ingenicfb_layerdesc); ++ buff_size = ALIGN(buff_size, DESC_ALIGN); ++ dma_free_coherent(fbdev->dev, ++ buff_size * CONFIG_FB_INGENIC_NR_FRAMES * CONFIG_FB_INGENIC_NR_LAYERS * 2, ++ fbdev->layerdesc[0], ++ fbdev->layerdesc_phys[0][0]); ++ ++ buff_size = sizeof(struct ingenicfb_framedesc); ++ buff_size = ALIGN(buff_size, DESC_ALIGN); ++ dma_free_coherent(fbdev->dev, ++ buff_size * CONFIG_FB_INGENIC_NR_FRAMES * 2, ++ fbdev->framedesc[0], ++ fbdev->framedesc_phys[0]); ++} ++ ++static int ingenicfb_copy_logo(struct fb_info *info) ++{ ++ unsigned long src_addr = 0; /* u-boot logo buffer address */ ++ unsigned long dst_addr = 0; /* kernel frame buffer address */ ++ struct ingenicfb_device *fbdev = info->par; ++ unsigned long size; ++ unsigned int ctrl; ++ unsigned read_times; ++ lay_cfg_en_t lay_cfg_en; ++ ++ /* Sure the uboot SLCD using the continuous mode, Close irq */ ++ if (!(reg_read(fbdev, DC_ST) & DC_WORKING)) { ++ dev_err(fbdev->dev, "uboot is not display logo!\n"); ++#ifdef CONFIG_TRUE_COLOR_LOGO ++ fbdev->current_frm_desc = 0; ++ ingenicfb_set_fix_par(fbdev->fb); ++ ingenicfb_set_par(fbdev->fb); ++ ingenicfb_enable(fbdev->fb); ++ show_logo(fbdev->fb); ++ fb_blank(fbdev->fb, FB_BLANK_UNBLANK); ++#endif ++ return -ENOEXEC; ++ } ++ ++ /*fbdev->is_lcd_en = 1;*/ ++ ++ /* Reading Desc from regisger need reset */ ++ ctrl = reg_read(fbdev, DC_CTRL); ++ ctrl |= DC_DES_CNT_RST; ++ reg_write(fbdev, DC_CTRL, ctrl); ++ ++ /* For geting LayCfgEn need read DC_FRM_DES 10 times */ ++ read_times = 10 - 1; ++ while(read_times--) { ++ reg_read(fbdev, DC_FRM_DES); ++ } ++ lay_cfg_en.d32 = reg_read(fbdev, DC_FRM_DES); ++ if(!lay_cfg_en.b.lay0_en) { ++ dev_err(fbdev->dev, "Uboot initialization is not using layer0!\n"); ++ return -ENOEXEC; ++ } ++ ++ /* For geting LayerBufferAddr need read DC_LAY0_DES 3 times */ ++ read_times = 3 - 1; ++ /* get buffer physical address */ ++ while(read_times--) { ++ reg_read(fbdev, DC_LAY0_DES); ++ } ++ src_addr = (unsigned long)reg_read(fbdev, DC_LAY0_DES); ++ ++ if (src_addr) { ++ size = info->fix.line_length * info->var.yres; ++ src_addr = (unsigned long)phys_to_virt(src_addr); ++ dst_addr = (unsigned long)fbdev->vidmem[0][0]; ++ memcpy((void *)dst_addr, (void *)src_addr, size); ++ } ++ ++ return 0; ++} ++ ++static int ingenicfb_do_probe(struct platform_device *pdev, struct lcd_panel *panel) ++{ ++ struct fb_videomode *video_mode; ++ struct fb_info *fb; ++ struct fb_info *fb_layer; ++ int ret = 0; ++ int i; ++ ++ fb = framebuffer_alloc(sizeof(struct ingenicfb_device), &pdev->dev); ++ if (!fb) { ++ dev_err(&pdev->dev, "Failed to allocate framebuffer device\n"); ++ return -ENOMEM; ++ } ++ ++ fbdev = fb->par; ++ fbdev->fb = fb; ++ fbdev->dev = &pdev->dev; ++ fbdev->panel = panel; ++#ifdef CONFIG_SLCDC_CONTINUA ++ if(fbdev->panel->lcd_type == LCD_TYPE_SLCD) ++ fbdev->slcd_continua = 1; ++#endif ++ ++ ++ spin_lock_init(&fbdev->irq_lock); ++ mutex_init(&fbdev->lock); ++ mutex_init(&fbdev->suspend_lock); ++ sprintf(fbdev->clk_name, "gate_lcd"); ++ sprintf(fbdev->pclk_name, "div_lcd"); ++ ++ fbdev->clk = devm_clk_get(&pdev->dev, fbdev->clk_name); ++ fbdev->pclk = devm_clk_get(&pdev->dev, fbdev->pclk_name); ++ ++ if (IS_ERR(fbdev->clk) || IS_ERR(fbdev->pclk)) { ++ ret = PTR_ERR(fbdev->clk); ++ dev_err(&pdev->dev, "Failed to get lcdc clock: %d\n", ret); ++ goto err_framebuffer_release; ++ } ++ ++ fbdev->base = of_iomap(pdev->dev.of_node, 0); ++ if (!fbdev->base) { ++ dev_err(&pdev->dev, ++ "Failed to ioremap register memory region\n"); ++ ret = -EBUSY; ++ goto err_put_clk; ++ } ++ ++ ret = refresh_pixclock_auto_adapt(fb); ++ if(ret){ ++ goto err_iounmap; ++ } ++ ++ video_mode = fbdev->panel->modes; ++ if (!video_mode) { ++ ret = -ENXIO; ++ goto err_iounmap; ++ } ++ ++ fb_videomode_to_modelist(panel->modes, panel->num_modes, &fb->modelist); ++ ++ ingenicfb_videomode_to_var(&fb->var, video_mode, fbdev->panel->lcd_type); ++ fb->fbops = &ingenicfb_ops; ++ fb->flags = FBINFO_DEFAULT; ++ fb->var.width = panel->width; ++ fb->var.height = panel->height; ++ ++ ingenicfb_colormode_to_var(&fb->var, &ingenicfb_colormodes[COLOR_MODE_INDEX]); ++ ++ ret = ingenicfb_check_var(&fb->var, fb); ++ if (ret) { ++ goto err_iounmap; ++ } ++ ++ /* ++ * #BUG: if uboot pixclock is different from kernel. this may cause problem. ++ * ++ **/ ++ ingenic_set_pixclk(fb); ++ ++ clk_prepare_enable(fbdev->clk); ++ clk_prepare_enable(fbdev->pclk); ++ fbdev->is_clk_en = 1; ++ ++ ret = ingenicfb_alloc_devmem(fbdev); ++ if (ret) { ++ dev_err(&pdev->dev, "Failed to allocate video memory\n"); ++ goto err_iounmap; ++ } ++ ++ fb->fix = ingenicfb_fix; ++ fb->fix.line_length = (fb->var.bits_per_pixel * fb->var.xres) >> 3; ++ fb->fix.smem_start = fbdev->vidmem_phys[0][0]; ++ fb->fix.smem_len = fbdev->vidmem_size + fbdev->sread_vidmem_size; ++ fb->screen_size = fbdev->frm_size; ++ fb->screen_base = fbdev->vidmem[0][0]; ++ fb->pseudo_palette = fbdev->pseudo_palette; ++ ++ vsync_skip_set(fbdev, CONFIG_FB_VSYNC_SKIP); ++ init_waitqueue_head(&fbdev->vsync_wq); ++ init_waitqueue_head(&fbdev->gen_stop_wq); ++ fbdev->open_cnt = 0; ++ fbdev->is_lcd_en = 0; ++ fbdev->timestamp.rp = 0; ++ fbdev->timestamp.wp = 0; ++ ++ fbdev->csc_mode = CSC_MODE_1; ++ csc_mode_set(fbdev, fbdev->csc_mode); ++ ingenicfb_update_frm_mode(fbdev->fb); ++ ++ fbdev->irq = platform_get_irq(pdev, 0); ++ sprintf(fbdev->irq_name, "lcdc%d", pdev->id); ++ if (devm_request_irq(fbdev->dev, fbdev->irq, ingenicfb_irq_handler, 0, ++ fbdev->irq_name, fbdev)) { ++ dev_err(&pdev->dev, "request irq failed\n"); ++ ret = -EINVAL; ++ goto err_free_devmem; ++ } ++ ++#ifdef CONFIG_FB_INGENIC_MIPI_DSI ++ /*BUG**/ ++ fbdev->dsi = jzdsi_init(panel->dsi_pdata); ++ if (!fbdev->dsi) { ++ goto err_iounmap; ++ } ++#endif ++ ++ platform_set_drvdata(pdev, fbdev); ++ ++ ret = sysfs_create_group(&fbdev->dev->kobj, &lcd_debug_attr_group); ++ if (ret) { ++ dev_err(&pdev->dev, "device create sysfs group failed\n"); ++ ++ ret = -EINVAL; ++ goto err_free_irq; ++ } ++ ++ ret = register_framebuffer(fb); ++ if (ret) { ++ dev_err(&pdev->dev, "Failed to register framebuffer: %d\n", ++ ret); ++ goto err_free_file; ++ } ++ ++ if (fbdev->vidmem_phys) { ++ if (!ingenicfb_copy_logo(fbdev->fb)) { ++ fbdev->is_lcd_en = 1; ++ ret = ingenicfb_desc_init(fb, 0); ++ if(ret) { ++ dev_err(fbdev->dev, "Desc init err!\n"); ++ goto err_free_file; ++ } ++ reg_write(fbdev, DC_FRM_CFG_ADDR, fbdev->framedesc_phys[fbdev->framedesc_array_use[fbdev->current_frm_desc]]); ++ } ++#ifdef CONFIG_INGENIC_FB_BOOT_PATTERN ++ boot_pattern(fbdev); ++#endif ++ ++#ifdef CONFIG_FB_INGENIC_DEBUG ++ test_pattern(fbdev); ++#endif ++ }else{ ++ ++ ingenicfb_clk_disable(fbdev); ++ ret = -ENOMEM; ++ goto err_free_file; ++ } ++ ++ /* From Layer1 to NR_LAYERS. */ ++ for(i = 1; i < CONFIG_FB_INGENIC_NR_LAYERS; i++) { ++ ++ fbdev->fbs[i] = framebuffer_alloc(sizeof(struct ingenicfb_device), &pdev->dev); ++ if(fbdev->fbs[i] == NULL) { ++ dev_err(&pdev->dev, "Failed to alloc framebuffer for layer: %d\n", i); ++ return -ENOMEM; ++ } ++ fbdev->fbs[i]->par = fbdev; ++ ++ fb_layer = fbdev->fbs[i]; ++ ++ fb_videomode_to_modelist(panel->modes, panel->num_modes, &fb_layer->modelist); ++ ingenicfb_videomode_to_var(&fb_layer->var, video_mode, fbdev->panel->lcd_type); ++ fb_layer->fbops = &ingenicfb_layerx_ops; ++ fb_layer->flags = FBINFO_DEFAULT; ++ fb_layer->var.width = panel->width; ++ fb_layer->var.height = panel->height; ++ ++ ingenicfb_colormode_to_var(&fb_layer->var, &ingenicfb_colormodes[COLOR_MODE_INDEX]); ++ fb_layer->fix = ingenicfb_fix; ++ fb_layer->fix.line_length = (fb_layer->var.bits_per_pixel * fb_layer->var.xres) >> 3; ++ fb_layer->fix.smem_start = fbdev->vidmem_phys[0][i]; ++ fb_layer->fix.smem_len = fbdev->vidmem_size / CONFIG_FB_INGENIC_NR_FRAMES; ++ fb_layer->screen_size = fbdev->frm_size; ++ fb_layer->screen_base = fbdev->vidmem[0][i]; ++ fb_layer->pseudo_palette = fbdev->pseudo_palette; ++ ret = register_framebuffer(fb_layer); ++ if(ret) { ++ dev_err(&pdev->dev, "Failed to register framebuffer layer : %d\n", i); ++ } ++ } ++ fbdev->fbs[0] = fb; ++ ++ ret = sysfs_create_groups(&fbdev->dev->kobj, lcd_layerx_groups); ++ if(ret) { ++ dev_err(&pdev->dev, "Failed to create sysfs groups\n"); ++ } ++ ++ ++ return 0; ++ ++err_free_file: ++ sysfs_remove_group(&fbdev->dev->kobj, &lcd_debug_attr_group); ++err_free_irq: ++ free_irq(fbdev->irq, fbdev); ++err_free_devmem: ++ ingenicfb_free_devmem(fbdev); ++err_iounmap: ++ iounmap(fbdev->base); ++err_put_clk: ++ ++ if (fbdev->clk) ++ clk_put(fbdev->clk); ++ if (fbdev->pclk) ++ clk_put(fbdev->pclk); ++ ++err_framebuffer_release: ++ framebuffer_release(fb); ++ return ret; ++} ++ ++int ingenicfb_register_panel(struct lcd_panel *panel) ++{ ++ WARN_ON(fbdev_panel != NULL); ++ ++ fbdev_panel = panel; ++ ++ if(fbdev_pdev != NULL) { ++ return ingenicfb_do_probe(fbdev_pdev, fbdev_panel); ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(ingenicfb_register_panel); ++ ++static int ingenicfb_probe(struct platform_device *pdev) ++{ ++ WARN_ON(fbdev_pdev != NULL); ++ ++ fbdev_pdev = pdev; ++ ++ if(fbdev_panel != NULL) { ++ return ingenicfb_do_probe(fbdev_pdev, fbdev_panel); ++ } ++ ++ return 0; ++} ++ ++static int ingenicfb_remove(struct platform_device *pdev) ++{ ++ struct ingenicfb_device *fbdev = platform_get_drvdata(pdev); ++ ++ ingenicfb_free_devmem(fbdev); ++ platform_set_drvdata(pdev, NULL); ++ ++#ifdef CONFIG_FB_INGENIC_MIPI_DSI ++ jzdsi_remove(fbdev->dsi); ++#endif ++ ++ devm_clk_put(fbdev->dev, fbdev->pclk); ++ devm_clk_put(fbdev->dev, fbdev->clk); ++ ++ sysfs_remove_group(&fbdev->dev->kobj, &lcd_debug_attr_group); ++ ++ iounmap(fbdev->base); ++ ++ framebuffer_release(fbdev->fb); ++ ++ return 0; ++} ++ ++static void ingenicfb_shutdown(struct platform_device *pdev) ++{ ++ struct ingenicfb_device *fbdev = platform_get_drvdata(pdev); ++ int is_fb_blank; ++ mutex_lock(&fbdev->suspend_lock); ++ is_fb_blank = (fbdev->is_suspend != 1); ++ fbdev->is_suspend = 1; ++ mutex_unlock(&fbdev->suspend_lock); ++ if (is_fb_blank) ++ fb_blank(fbdev->fb, FB_BLANK_POWERDOWN); ++}; ++ ++#ifdef CONFIG_PM ++ ++static int ingenicfb_suspend(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct ingenicfb_device *fbdev = platform_get_drvdata(pdev); ++ ++ fb_blank(fbdev->fb, FB_BLANK_POWERDOWN); ++ ++ return 0; ++} ++ ++static int ingenicfb_resume(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct ingenicfb_device *fbdev = platform_get_drvdata(pdev); ++ ++ fb_blank(fbdev->fb, FB_BLANK_UNBLANK); ++ ++ return 0; ++} ++ ++static const struct dev_pm_ops ingenicfb_pm_ops = { ++ .suspend = ingenicfb_suspend, ++ .resume = ingenicfb_resume, ++}; ++#endif ++static const struct of_device_id ingenicfb_of_match[] = { ++ { .compatible = "ingenic,x2000-dpu"}, ++ { .compatible = "ingenic,t40-dpu"}, ++ { .compatible = "ingenic,m300-dpu"}, ++ {}, ++}; ++ ++static struct platform_driver ingenicfb_driver = { ++ .probe = ingenicfb_probe, ++ .remove = ingenicfb_remove, ++ .shutdown = ingenicfb_shutdown, ++ .driver = { ++ .name = "ingenic-fb", ++ .of_match_table = ingenicfb_of_match, ++#ifdef CONFIG_PM ++ .pm = &ingenicfb_pm_ops, ++#endif ++ ++ }, ++}; ++ ++static int __init ingenicfb_init(void) ++{ ++ platform_driver_register(&ingenicfb_driver); ++ return 0; ++} ++ ++static void __exit ingenicfb_cleanup(void) ++{ ++ platform_driver_unregister(&ingenicfb_driver); ++} ++ ++ ++#ifdef CONFIG_EARLY_INIT_RUN ++rootfs_initcall(ingenicfb_init); ++#else ++module_init(ingenicfb_init); ++#endif ++ ++module_exit(ingenicfb_cleanup); ++ ++MODULE_DESCRIPTION("JZ LCD Controller driver"); ++MODULE_AUTHOR("Sean Tang "); ++MODULE_LICENSE("GPL"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_ingenicfb.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_ingenicfb.h.patch new file mode 100644 index 00000000..43733a66 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_ingenicfb.h.patch @@ -0,0 +1,675 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v12/ingenicfb.h b/drivers/video/fbdev/ingenic/fb_v12/ingenicfb.h +--- a/drivers/video/fbdev/ingenic/fb_v12/ingenicfb.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v12/ingenicfb.h 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,671 @@ ++/* drivers/video/fbdev/ingenic/x2000_v12/ingenicfb.h ++ * ++ * Copyright (C) 2016 Ingenic Semiconductor Inc. ++ * ++ * Author:clwang ++ * ++ * 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. ++ */ ++#ifndef __JZ_FB_H__ ++#define __JZ_FB_H__ ++#include ++#include "jz_dsim.h" ++ ++/* Maximum layers supported by DPU hardware */ ++#define DPU_SUPPORT_MAX_LAYERS 4 ++/* Maximum frames supported by DPU drivers */ ++#define DPU_SUPPORT_MAX_FRAMES 3 ++ ++#define PIXEL_ALIGN 4 ++#define DESC_ALIGN 8 ++#define MAX_BITS_PER_PIX (32) ++#define DPU_MAX_SIZE (2047) ++#define DPU_MIN_SIZE (4) ++#define DPU_STRIDE_SIZE (4096) ++#define DPU_SCALE_MIN_SIZE (20) ++ ++ ++#define MAX_STRIDE_VALUE (4096) ++ ++#define FRAME_CTRL_DEFAULT_SET (0x04) ++ ++#define FRAME_CFG_ALL_UPDATE (0xFF) ++ ++#ifdef CONFIG_RGB888 ++#define COLOR_MODE_INDEX 0 ++#endif ++#ifdef CONFIG_ARGB8888 ++#define COLOR_MODE_INDEX 1 ++#endif ++#ifdef CONFIG_RGB555 ++#define COLOR_MODE_INDEX 2 ++#endif ++#ifdef CONFIG_ARGB1555 ++#define COLOR_MODE_INDEX 3 ++#endif ++#ifdef CONFIG_RGB565 ++#define COLOR_MODE_INDEX 4 ++#endif ++#ifdef CONFIG_YUV422 ++#define COLOR_MODE_INDEX 5 ++#endif ++#ifdef CONFIG_NV12 ++#define COLOR_MODE_INDEX 6 ++#endif ++#ifdef CONFIG_NV21 ++#define COLOR_MODE_INDEX 7 ++#endif ++ ++enum ingenic_lcd_type { ++ LCD_TYPE_TFT = 0, ++ LCD_TYPE_SLCD =1, ++ LCD_TYPE_MIPI_SLCD = 2, ++}; ++ ++enum { ++ DC_WB_FORMAT_8888 = 0, ++ DC_WB_FORMAT_565 = 1, ++ DC_WB_FORMAT_555 = 2, ++ DC_WB_FORMAT_YUV422 = 3, ++ DC_WB_FORMAT_MONO = 4, ++ DC_WB_FORMAT_888 = 6, ++}; ++ ++enum { ++ LAYER_CFG_FORMAT_RGB555 = 0, ++ LAYER_CFG_FORMAT_ARGB1555 = 1, ++ LAYER_CFG_FORMAT_RGB565 = 2, ++ LAYER_CFG_FORMAT_RGB888 = 4, ++ LAYER_CFG_FORMAT_ARGB8888 = 5, ++ LAYER_CFG_FORMAT_MONO8 = 6, ++ LAYER_CFG_FORMAT_MONO16 = 7, ++ LAYER_CFG_FORMAT_NV12 = 8, ++ LAYER_CFG_FORMAT_NV21 = 9, ++ LAYER_CFG_FORMAT_YUV422 = 10, ++ LAYER_CFG_FORMAT_TILE_H264 = 12, ++}; ++ ++enum { ++ LAYER_CFG_COLOR_RGB = 0, ++ LAYER_CFG_COLOR_RBG = 1, ++ LAYER_CFG_COLOR_GRB = 2, ++ LAYER_CFG_COLOR_GBR = 3, ++ LAYER_CFG_COLOR_BRG = 4, ++ LAYER_CFG_COLOR_BGR = 5, ++}; ++ ++enum { ++ LAYER_Z_ORDER_0 = 0, /* bottom */ ++ LAYER_Z_ORDER_1 = 1, ++ LAYER_Z_ORDER_2 = 2, ++ LAYER_Z_ORDER_3 = 3, /* top */ ++}; ++ ++enum { ++ RDMA_CHAIN_CFG_COLOR_RGB = 0, ++ RDMA_CHAIN_CFG_COLOR_RBG = 1, ++ RDMA_CHAIN_CFG_COLOR_GRB = 2, ++ RDMA_CHAIN_CFG_COLOR_GBR = 3, ++ RDMA_CHAIN_CFG_COLOR_BRG = 4, ++ RDMA_CHAIN_CFG_COLOR_BGR = 5, ++}; ++enum { ++ RDMA_CHAIN_CFG_FORMA_555 = 0, ++ RDMA_CHAIN_CFG_FORMA_565 = 2, ++ RDMA_CHAIN_CFG_FORMA_888 = 4, ++}; ++ ++typedef union frm_size { ++ uint32_t d32; ++ struct { ++ uint32_t width:12; ++ uint32_t reserve12_15:4; ++ uint32_t height:12; ++ uint32_t reserve28_31:4; ++ }b; ++} frm_size_t; ++ ++typedef union frm_ctrl { ++ uint32_t d32; ++ struct { ++ uint32_t stop:1; ++ uint32_t wb_en:1; ++ uint32_t direct_en:1; ++ uint32_t change_2_rdma:1; ++ uint32_t wb_dither_en:1; ++ uint32_t wb_dither_auto:1; ++ uint32_t reserve6_15:10; ++ uint32_t wb_format:3; ++ uint32_t reserve19:1; ++ uint32_t wb_dither_b_dw:2; ++ uint32_t wb_dither_g_dw:2; ++ uint32_t wb_dither_r_dw:2; ++ uint32_t reserve26_31:6; ++ }b; ++} frm_ctrl_t; ++ ++typedef union lay_cfg_en { ++ uint32_t d32; ++ struct { ++ uint32_t lay0_scl_en:1; ++ uint32_t lay1_scl_en:1; ++ uint32_t lay2_scl_en:1; ++ uint32_t lay3_scl_en:1; ++ uint32_t lay0_en:1; ++ uint32_t lay1_en:1; ++ uint32_t lay2_en:1; ++ uint32_t lay3_en:1; ++ uint32_t lay0_z_order:2; ++ uint32_t lay1_z_order:2; ++ uint32_t lay2_z_order:2; ++ uint32_t lay3_z_order:2; ++ uint32_t leserve16_31:16; ++ }b; ++} lay_cfg_en_t; ++ ++typedef union cmp_irq_ctrl { ++ uint32_t d32; ++ struct { ++ uint32_t reserve0_8:9; ++ uint32_t eoc_msk:1; ++ uint32_t reserve10_13:4; ++ uint32_t soc_msk:1; ++ uint32_t eow_msk:1; ++ uint32_t reserve_16:1; ++ uint32_t eod_msk:1; ++ uint32_t reserve18_31:14; ++ }b; ++} cmp_irq_ctrl_t; ++ ++typedef union lay_size { ++ uint32_t d32; ++ struct { ++ uint32_t width:12; ++ uint32_t reserve12_15:4; ++ uint32_t height:12; ++ uint32_t reserve28_31:4; ++ }b; ++} lay_size_t; ++ ++typedef union lay_cfg { ++ uint32_t d32; ++ struct { ++ uint32_t g_alpha:8; ++ uint32_t reserve8_9:2; ++ uint32_t color:3; ++ uint32_t g_alpha_en:1; ++ uint32_t domain_multi:1; ++ uint32_t reserve15:1; ++ uint32_t format:4; ++ uint32_t sharpl:2; ++ uint32_t reserve22_31:10; ++ }b; ++} lay_cfg_t; ++ ++typedef union lay_scale { ++ uint32_t d32; ++ struct { ++ uint32_t target_width:12; ++ uint32_t reserve12_15:4; ++ uint32_t target_height:12; ++ uint32_t reserve28_31:4; ++ }b; ++} lay_scale_t; ++ ++typedef union lay_rotation { ++ uint32_t d32; ++ struct { ++ uint32_t rotation:3; ++ uint32_t reserve3_31:29; ++ }b; ++} lay_rotation_t; ++ ++typedef union lay_pos { ++ uint32_t d32; ++ struct { ++ uint32_t x_pos:12; ++ uint32_t reserve12_15:4; ++ uint32_t y_pos:12; ++ uint32_t reserve28_31:4; ++ }b; ++} lay_pos_t; ++ ++typedef union chain_cfg { ++ uint32_t d32; ++ struct { ++ uint32_t chain_end:1; ++ uint32_t change_2_cmp:1; ++ uint32_t reserve2_15:14; ++ uint32_t color:3; ++ uint32_t format:4; ++ uint32_t reserve23_31:9; ++ }b; ++} chain_cfg_t; ++ ++typedef union rdma_irq_ctrl { ++ uint32_t d32; ++ struct { ++ uint32_t reserve_0:1; ++ uint32_t eos_msk:1; ++ uint32_t sos_msk:1; ++ uint32_t reserve3_16:14; ++ uint32_t eod_msk:1; ++ uint32_t reserve18_31:4; ++ }b; ++} rdma_irq_ctrl_t; ++ ++struct ingenicfb_framedesc { ++ uint32_t FrameNextCfgAddr; ++ frm_size_t FrameSize; ++ frm_ctrl_t FrameCtrl; ++ uint32_t WritebackAddr; ++ uint32_t WritebackStride; ++ uint32_t Layer0CfgAddr; ++ uint32_t Layer1CfgAddr; ++ uint32_t Layer2CfgAddr; ++ uint32_t Layer3CfgAddr; ++ lay_cfg_en_t LayCfgEn; ++ cmp_irq_ctrl_t InterruptControl; ++}; ++ ++struct ingenicfb_layerdesc { ++ lay_size_t LayerSize; ++ lay_cfg_t LayerCfg; ++ uint32_t LayerBufferAddr; ++ lay_scale_t LayerScale; ++ lay_rotation_t LayerRotation; ++ uint32_t LayerScratch; ++ lay_pos_t LayerPos; ++ uint32_t layerresizecoef_x; ++ uint32_t layerresizecoef_y; ++ uint32_t LayerStride; ++ uint32_t UVBufferAddr; ++ uint32_t UVStride; ++ ++}; ++ ++struct ingenicfb_sreadesc { ++ uint32_t RdmaNextCfgAddr; ++ uint32_t FrameBufferAddr; ++ uint32_t Stride; ++ chain_cfg_t ChainCfg; ++ rdma_irq_ctrl_t InterruptControl; ++}; ++ ++struct ingenicfb_lay_cfg { ++ unsigned int lay_en:1; ++ unsigned int tlb_en:1; ++ unsigned int lay_scale_en:1; ++ unsigned int lay_z_order:3; ++ unsigned int format:4; ++ unsigned int color:3; ++ unsigned int g_alpha_en:1; ++ unsigned int g_alpha_val:8; ++ unsigned int source_w; ++ unsigned int source_h; ++ unsigned int stride; ++ unsigned int scale_w; ++ unsigned int scale_h; ++ unsigned int disp_pos_x; ++ unsigned int disp_pos_y; ++ unsigned int addr[3]; ++ unsigned int uv_offset[3]; ++ unsigned int reserve[4]; ++}; ++ ++struct ingenicfb_frm_cfg { ++ struct ingenicfb_lay_cfg lay_cfg[DPU_SUPPORT_MAX_LAYERS]; ++}; ++ ++/* smart lcd interface_type */ ++enum smart_lcd_type { ++ SMART_LCD_TYPE_6800, ++ SMART_LCD_TYPE_8080, ++ SMART_LCD_TYPE_SPI_3, ++ SMART_LCD_TYPE_SPI_4, ++}; ++ ++/* smart lcd format */ ++enum smart_lcd_format { ++ SMART_LCD_FORMAT_565, ++ SMART_LCD_FORMAT_666, ++ SMART_LCD_FORMAT_888, ++}; ++ ++/* smart lcd command width */ ++enum smart_lcd_cwidth { ++ SMART_LCD_CWIDTH_8_BIT, ++ SMART_LCD_CWIDTH_9_BIT, ++ SMART_LCD_CWIDTH_16_BIT, ++ SMART_LCD_CWIDTH_18_BIT, ++ SMART_LCD_CWIDTH_24_BIT, ++}; ++ ++/* smart lcd data width */ ++enum smart_lcd_dwidth { ++ SMART_LCD_DWIDTH_8_BIT, ++ SMART_LCD_DWIDTH_9_BIT, ++ SMART_LCD_DWIDTH_16_BIT, ++ SMART_LCD_DWIDTH_18_BIT, ++ SMART_LCD_DWIDTH_24_BIT, ++}; ++ ++/* smart lcd data width */ ++enum smart_config_type { ++ SMART_CONFIG_DATA, ++ SMART_CONFIG_PRM, ++ SMART_CONFIG_CMD, ++ SMART_CONFIG_UDELAY, ++}; ++struct smart_lcd_data_table { ++ enum smart_config_type type; ++ unsigned int value; ++}; ++enum tft_lcd_color_even { ++ TFT_LCD_COLOR_EVEN_RGB, ++ TFT_LCD_COLOR_EVEN_RBG, ++ TFT_LCD_COLOR_EVEN_BGR, ++ TFT_LCD_COLOR_EVEN_BRG, ++ TFT_LCD_COLOR_EVEN_GBR, ++ TFT_LCD_COLOR_EVEN_GRB, ++}; ++ ++enum tft_lcd_color_odd { ++ TFT_LCD_COLOR_ODD_RGB, ++ TFT_LCD_COLOR_ODD_RBG, ++ TFT_LCD_COLOR_ODD_BGR, ++ TFT_LCD_COLOR_ODD_BRG, ++ TFT_LCD_COLOR_ODD_GBR, ++ TFT_LCD_COLOR_ODD_GRB, ++}; ++ ++enum tft_lcd_mode { ++ TFT_LCD_MODE_PARALLEL_888, ++ TFT_LCD_MODE_PARALLEL_666, ++ TFT_LCD_MODE_PARALLEL_565, ++ TFT_LCD_MODE_SERIAL_RGB, ++ TFT_LCD_MODE_SERIAL_RGBD, ++}; ++ ++struct tft_config { ++ unsigned int pix_clk_inv:1; ++ unsigned int de_dl:1; ++ unsigned int sync_dl:1; ++ enum tft_lcd_color_even color_even; ++ enum tft_lcd_color_odd color_odd; ++ enum tft_lcd_mode mode; ++}; ++ ++struct smart_config { ++ unsigned int te_switch:1; ++ unsigned int te_mipi_switch:1; ++ unsigned int te_md:1; ++ unsigned int te_dp:1; ++ unsigned int te_anti_jit:1; ++ unsigned int dc_md:1; ++ unsigned int wr_md:1; ++ enum smart_lcd_type smart_type; ++ enum smart_lcd_format pix_fmt; ++ enum smart_lcd_dwidth dwidth; ++ enum smart_lcd_cwidth cwidth; ++ unsigned int bus_width; ++ ++ unsigned long write_gram_cmd; ++ unsigned int length_cmd; ++ struct smart_lcd_data_table *data_table; ++ unsigned int length_data_table; ++ int (*init) (void); ++ int (*gpio_for_slcd) (void); ++}; ++ ++ ++struct lcd_panel_ops { ++ void (*init)(void *panel); ++ void (*enable)(void *panel); ++ void (*disable)(void *panel); ++}; ++ ++#ifdef CONFIG_FB_INGENIC_MIPI_DSI ++struct jzdsi_data { ++ struct fb_videomode *modes; ++ struct video_config video_config; ++ struct dsi_config dsi_config; ++ unsigned int bpp_info; ++ unsigned int max_bps; ++}; ++#endif ++ ++struct lcd_panel { ++ const char *name; ++ unsigned int num_modes; ++ struct fb_videomode *modes; ++#ifdef CONFIG_FB_INGENIC_MIPI_DSI ++ struct jzdsi_data *dsi_pdata; ++#endif ++ ++ enum ingenic_lcd_type lcd_type; ++ unsigned int bpp; ++ unsigned int width; ++ unsigned int height; ++ ++ struct smart_config *smart_config; ++ struct tft_config *tft_config; ++ ++ unsigned dither_enable:1; ++ struct { ++ unsigned dither_red; ++ unsigned dither_green; ++ unsigned dither_blue; ++ } dither; ++ ++ struct lcd_panel_ops *ops; ++}; ++ ++ ++typedef enum stop_mode { ++ QCK_STOP, ++ GEN_STOP, ++} stop_mode_t; ++ ++typedef enum csc_mode { ++ CSC_MODE_0, ++ CSC_MODE_1, ++ CSC_MODE_2, ++ CSC_MODE_3, ++} csc_mode_t; ++ ++ ++typedef enum framedesc_st { ++ FRAME_DESC_AVAILABLE = 1, ++ FRAME_DESC_SET_OVER = 2, ++ FRAME_DESC_USING = 3, ++}framedesc_st_t; ++ ++typedef enum frm_cfg_st { ++ FRAME_CFG_NO_UPDATE, ++ FRAME_CFG_UPDATE, ++}frm_cfg_st_t; ++ ++struct ingenicfb_frm_mode { ++ struct ingenicfb_frm_cfg frm_cfg; ++ frm_cfg_st_t update_st[CONFIG_FB_INGENIC_NR_FRAMES*2]; ++}; ++ ++typedef enum { ++ DESC_ST_FREE, ++ DESC_ST_AVAILABLE, ++ DESC_ST_RUNING, ++} frm_st_t; ++ ++ ++#define CONFIG_DEBUG_DPU_IRQCNT ++#ifdef CONFIG_DEBUG_DPU_IRQCNT ++ ++struct dbg_irqcnt { ++ unsigned long long irqcnt; ++ unsigned long long cmp_start; ++ unsigned long long stop_disp_ack; ++ unsigned long long disp_end; ++ unsigned long long tft_under; ++ unsigned long long wdma_over; ++ unsigned long long wdma_end; ++ unsigned long long layer3_end; ++ unsigned long long layer2_end; ++ unsigned long long layer1_end; ++ unsigned long long layer0_end; ++ unsigned long long clr_cmp_end; ++ unsigned long long stop_wrbk_ack; ++ unsigned long long srd_start; ++ unsigned long long srd_end; ++ unsigned long long cmp_w_slow; ++}; ++ ++#define dbg_irqcnt_inc(dbg,x) dbg.x++ ++ ++#else ++struct dbg_irqcnt{ ++}; ++#define dbg_irqcnt_inc(dbg,x) do {} while(0) ++ ++#endif ++ ++struct ingenicfb_timestamp { ++ #define TIMESTAMP_CAP 16 ++ volatile int wp; /* write position */ ++ int rp; /* read position */ ++ u64 value[TIMESTAMP_CAP]; ++}; ++ ++struct ingenicfb_device { ++ int is_lcd_en; /* 0, disable 1, enable */ ++ int is_clk_en; /* 0, disable 1, enable */ ++ int irq; /* lcdc interrupt num */ ++ int open_cnt; ++ int irq_cnt; ++ int tft_undr_cnt; ++ int frm_start; ++ int wback_en; /*writeback enable*/ ++ int csc_mode; /*csc_mode*/ ++ ++ struct dbg_irqcnt dbg_irqcnt; ++ ++ char clk_name[16]; ++ char pclk_name[16]; ++ char irq_name[16]; ++ struct clk *clk; ++ struct clk *pclk; ++ ++ ++ struct fb_info *fb; ++ struct fb_info *fbs[CONFIG_FB_INGENIC_NR_LAYERS]; ++ struct device *dev; ++ struct lcd_panel *panel; ++ void __iomem *base; ++ struct resource *mem; ++ ++ size_t vidmem_size; ++#if 1 ++ void *vidmem[CONFIG_FB_INGENIC_NR_FRAMES][CONFIG_FB_INGENIC_NR_LAYERS]; ++ dma_addr_t vidmem_phys[CONFIG_FB_INGENIC_NR_FRAMES][CONFIG_FB_INGENIC_NR_LAYERS]; ++#else ++ void *vidmem[CONFIG_FB_INGENIC_NR_LAYERS][CONFIG_FB_INGENIC_NR_FRAMES]; ++ dma_addr_t vidmem_phys[CONFIG_FB_INGENIC_NR_LAYERS][CONFIG_FB_INGENIC_NR_FRAMES]; ++ ++#endif ++ size_t sread_vidmem_size; ++ void * sread_vidmem[CONFIG_FB_INGENIC_NR_FRAMES]; ++ dma_addr_t sread_vidmem_phys[CONFIG_FB_INGENIC_NR_FRAMES]; ++ ++ int current_frm_desc; ++ struct ingenicfb_frm_mode current_frm_mode; ++ ++ size_t frm_size; ++ struct ingenicfb_framedesc *framedesc[CONFIG_FB_INGENIC_NR_FRAMES*2]; ++ dma_addr_t framedesc_phys[CONFIG_FB_INGENIC_NR_FRAMES*2]; ++ struct ingenicfb_layerdesc *layerdesc[CONFIG_FB_INGENIC_NR_FRAMES*2][DPU_SUPPORT_MAX_LAYERS]; ++ dma_addr_t layerdesc_phys[CONFIG_FB_INGENIC_NR_FRAMES*2][DPU_SUPPORT_MAX_LAYERS]; ++ struct ingenicfb_sreadesc *sreadesc[CONFIG_FB_INGENIC_NR_FRAMES]; ++ dma_addr_t sreadesc_phys[CONFIG_FB_INGENIC_NR_FRAMES]; ++ int framedesc_array_next[CONFIG_FB_INGENIC_NR_FRAMES]; ++ int framedesc_array_use[CONFIG_FB_INGENIC_NR_FRAMES]; ++ ++ wait_queue_head_t gen_stop_wq; ++ wait_queue_head_t vsync_wq; ++ unsigned int vsync_skip_map; /* 10 bits width */ ++ int vsync_skip_ratio; ++ ++ struct ingenicfb_timestamp timestamp; ++ ++ struct mutex lock; ++ struct mutex suspend_lock; ++ spinlock_t irq_lock; ++ ++#ifdef CONFIG_HAS_EARLYSUSPEND ++ struct early_suspend early_suspend; ++#endif ++ int is_suspend; ++ unsigned int pan_display_count; ++ int blank; ++ unsigned int pseudo_palette[16]; ++ int slcd_continua; ++ ++ unsigned int user_addr; ++ unsigned int tlba; ++ unsigned int tlb_err_cnt; ++ ++#ifdef CONFIG_FB_INGENIC_MIPI_DSI ++ struct dsi_device *dsi; ++#endif ++}; ++ ++struct dpu_dmmu_map_info { ++ unsigned int addr; ++ unsigned int len; ++}; ++ ++struct smash_mode { ++ unsigned long vaddr; ++ int mode; ++}; ++ ++void ingenicfb_clk_enable(struct ingenicfb_device *ingenicfb); ++void ingenicfb_clk_disable(struct ingenicfb_device *fbdev); ++ ++static inline unsigned long reg_read(struct ingenicfb_device *fbdev, int offset) ++{ ++ return readl(fbdev->base + offset); ++} ++ ++static inline void reg_write(struct ingenicfb_device *fbdev, int offset, unsigned long val) ++{ ++ writel(val, fbdev->base + offset); ++} ++ ++#define JZFB_PUT_FRM_CFG _IOWR('F', 0x101, struct ingenicfb_frm_cfg *) ++#define JZFB_GET_FRM_CFG _IOWR('F', 0x102, struct ingenicfb_frm_cfg *) ++ ++#define JZFB_SET_CSC_MODE _IOW('F', 0x120, csc_mode_t) ++#define JZFB_USE_TLB _IOW('F', 0x124, unsigned int) ++#define JZFB_DMMU_MAP _IOWR('F', 0x130, struct dpu_dmmu_map_info) ++#define JZFB_DMMU_UNMAP _IOWR('F', 0x131, struct dpu_dmmu_map_info) ++#define JZFB_DMMU_UNMAP_ALL _IOWR('F', 0x132, struct dpu_dmmu_map_info) ++#define JZFB_DMMU_MEM_SMASH _IOWR('F', 0x133, struct smash_mode) ++#define JZFB_DMMU_DUMP_MAP _IOWR('F', 0x134, unsigned long) ++#define JZFB_DMMU_FLUSH_CACHE _IOWR('F', 0x135, struct dpu_dmmu_map_info) ++#define JZFB_DUMP_LCDC_REG _IOW('F', 0x150, int) ++ ++#define JZFB_SET_VSYNCINT _IOW('F', 0x210, int) ++#define JZFB_GET_LAYERS_NUM _IOWR('F', 0x211, unsigned int) ++ ++/* define in image_enh.c */ ++extern int ingenicfb_config_image_enh(struct fb_info *info); ++extern int ingenicfb_image_enh_ioctl(struct fb_info *info, unsigned int cmd, ++ unsigned long arg); ++extern int update_slcd_frame_buffer(void); ++extern int lcd_display_inited_by_uboot(void); ++extern int ingenicfb_register_panel(struct lcd_panel *panel); ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_jz_dsim.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_jz_dsim.h.patch new file mode 100644 index 00000000..1dadd0ac --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_jz_dsim.h.patch @@ -0,0 +1,297 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v12/jz_dsim.h b/drivers/video/fbdev/ingenic/fb_v12/jz_dsim.h +--- a/drivers/video/fbdev/ingenic/fb_v12/jz_dsim.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v12/jz_dsim.h 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,293 @@ ++/* ++ * 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. ++*/ ++ ++#ifndef _JZ_MIPI_DSIM_H ++#define _JZ_MIPI_DSIM_H ++ ++#include ++#include ++ ++#define REFERENCE_FREQ (24000) //24MHZ, ext ++#define DPHY_DIV_UPPER_LIMIT (40000) ++#define DPHY_DIV_LOWER_LIMIT (1000) ++#define MIN_OUTPUT_FREQ (80) ++ ++#define DSIH_FIFO_ACTIVE_WAIT 500 ++ ++#define PRECISION_FACTOR (1000) ++#define DSIH_PIXEL_TOLERANCE 2 ++ ++#define VIDEO_PACKET_OVERHEAD 6 ++#define NULL_PACKET_OVERHEAD 6 ++#define SHORT_PACKET 4 ++#define BLANKING_PACKET 6 ++#define MAX_NULL_SIZE 1023 ++#define TX_ESC_CLK_DIV 7 ++#define MAX_WORD_COUNT 150 ++#define PANEL_NAME_SIZE (32) ++ ++ ++enum dsi_interface_type { ++ DSIM_COMMAND, ++ DSIM_VIDEO ++}; ++ ++enum dsi_virtual_ch_no { ++ DSIM_VIRTUAL_CH_0, ++ DSIM_VIRTUAL_CH_1, ++ DSIM_VIRTUAL_CH_2, ++ DSIM_VIRTUAL_CH_3 ++}; ++ ++enum dsi_no_of_data_lane { ++ DSIM_DATA_LANE_1, ++ DSIM_DATA_LANE_2, ++ DSIM_DATA_LANE_3, ++ DSIM_DATA_LANE_4 ++}; ++ ++enum dsi_byte_clk_src { ++ DSIM_PLL_OUT_DIV8, ++ DSIM_EXT_CLK_DIV8, ++ DSIM_EXT_CLK_BYPASS ++}; ++ ++struct dsi_config { ++ unsigned char max_lanes; ++ unsigned char max_hs_to_lp_cycles; ++ unsigned char max_lp_to_hs_cycles; ++ unsigned short max_bta_cycles; ++ unsigned int max_bps; ++ int color_mode_polarity; ++ int shut_down_polarity; ++ int te_gpio; ++ int te_irq_level; ++ int te_mipi_en; ++ ++}; ++ ++typedef enum { ++ OK = 0, ++ ERR_DSI_COLOR_CODING, ++ ERR_DSI_OUT_OF_BOUND, ++ ERR_DSI_OVERFLOW, ++ ERR_DSI_INVALID_INSTANCE, ++ ERR_DSI_CORE_INCOMPATIBLE, ++ ERR_DSI_VIDEO_MODE, ++ ERR_DSI_INVALID_COMMAND, ++ ERR_DSI_INVALID_EVENT, ++ ERR_DSI_INVALID_HANDLE, ++ ERR_DSI_PHY_POWERUP, ++ ERR_DSI_PHY_INVALID, ++ ERR_DSI_PHY_FREQ_OUT_OF_BOUND, ++ ERR_DSI_TIMEOUT ++} dsih_error_t; ++ ++enum { ++ DSI_BLANK_UNBLANK, ++ DSI_BLANK_NORMAL, ++ DSI_BLANK_POWERDOWN, ++ DSI_BLANK_POWERUP ++}; ++typedef enum { ++ NOT_INITIALIZED = 0, ++ INITIALIZED, ++ ON, ++ OFF, ++ UBOOT_INITIALIZED ++} dsih_state_t; ++ ++typedef enum { ++ VIDEO_NON_BURST_WITH_SYNC_PULSES = 0, ++ VIDEO_NON_BURST_WITH_SYNC_EVENTS, ++ VIDEO_BURST_WITH_SYNC_PULSES ++} dsih_video_mode_t; ++/** ++ * * Color coding type (depth and pixel configuration) ++ * */ ++typedef enum { ++ COLOR_CODE_16BIT_CONFIG1, ++ COLOR_CODE_16BIT_CONFIG2, ++ COLOR_CODE_16BIT_CONFIG3, ++ COLOR_CODE_18BIT_CONFIG1, ++ COLOR_CODE_18BIT_CONFIG2, ++ COLOR_CODE_24BIT ++} dsih_color_coding_t; ++ ++typedef enum { ++ MIPI_PHY_BYTE_CLK_COEF_MUL1 = 0, ++ MIPI_PHY_BYTE_CLK_COEF_MUL3_DIV2 = 1, ++ MIPI_PHY_BYTE_CLK_COEF_MUL4_DIV3 = 2, ++ MIPI_PHY_BYTE_CLK_COEF_MUL5_DIV4 = 3, ++ MIPI_PHY_BYTE_CLK_COEF_MUL6_DIV5 = 4, ++} byte_clock_coef_t; ++ ++struct video_config { ++ unsigned char no_of_lanes; ++ unsigned char virtual_channel; ++ dsih_video_mode_t video_mode; ++ int receive_ack_packets; ++ unsigned int byte_clock; ++ byte_clock_coef_t byte_clock_coef; ++ unsigned int pixel_clock; ++ dsih_color_coding_t color_coding; ++ int is_18_loosely; ++ int data_en_polarity; ++ int h_polarity; ++ unsigned short h_active_pixels; /* hadr */ ++ unsigned short h_sync_pixels; ++ unsigned short h_back_porch_pixels; /* hbp */ ++ unsigned short h_total_pixels; /* h_total */ ++ int v_polarity; ++ unsigned short v_active_lines; /* vadr */ ++ unsigned short v_sync_lines; ++ unsigned short v_back_porch_lines; /* vbp */ ++ unsigned short v_total_lines; /* v_total */ ++ unsigned int refresh; ++}; ++ ++ ++struct dsi_device { ++ unsigned int __iomem address; ++ unsigned int __iomem phy_address; ++ struct mutex lock; ++ spinlock_t irq_lock; ++ struct clk *clk; ++ struct dsi_config *dsi_config; ++ struct dsi_phy *dsi_phy; ++ struct video_config *video_config; ++ struct dsi_master_ops *master_ops; ++ struct mipi_dsim_lcd_device *dsim_lcd_dev; ++ struct mipi_dsim_lcd_driver *dsim_lcd_drv; ++ ++ ++ struct dsi_cmd_packet *cmd_list; ++ int cmd_packet_len; ++ unsigned int state; ++ unsigned int data_lane; ++ bool suspended; ++ int counter; ++ ++}; ++ ++struct dsi_phy { ++ unsigned int reference_freq; ++ dsih_state_t status; ++ unsigned int address; ++ void (*bsp_pre_config) (struct dsi_device * dsi, void *param); ++ ++}; ++ ++struct mipi_dsim_lcd_device { ++ char *name; ++ struct device dev; ++ int id; ++ int bus_id; ++ int irq; ++ int panel_reverse; ++ ++ struct dsi_device *master; ++ void *platform_data; ++}; ++ ++enum { ++ POWER_ON_LCD = 1, ++ POWER_ON_BL, ++}; ++enum { ++ CMD_MIPI_DISPLAY_ON = 1, ++ CMD_MIPI_END, ++}; ++struct mipi_dsim_lcd_driver { ++ char *name; ++ int id; ++ ++ void (*power_on)(struct mipi_dsim_lcd_device *dsim_dev, int mode); ++ void (*set_sequence)(struct mipi_dsim_lcd_device *dsim_dev); ++ int (*ioctl)(struct mipi_dsim_lcd_device *dsim_dev, int cmd); ++ int (*probe)(struct mipi_dsim_lcd_device *dsim_dev); ++ int (*remove)(struct mipi_dsim_lcd_device *dsim_dev); ++ void (*shutdown)(struct mipi_dsim_lcd_device *dsim_dev); ++ int (*suspend)(struct mipi_dsim_lcd_device *dsim_dev); ++ int (*resume)(struct mipi_dsim_lcd_device *dsim_dev); ++}; ++struct mipi_dsim_platform_data { ++ char lcd_panel_name[PANEL_NAME_SIZE]; ++ ++ struct mipi_dsim_config *dsim_config; ++ unsigned int enabled; ++ void *lcd_panel_info; ++}; ++ ++struct dsi_cmd_packet { ++ unsigned char packet_type; ++ unsigned char cmd0_or_wc_lsb; ++ unsigned char cmd1_or_wc_msb; ++ unsigned char cmd_data[MAX_WORD_COUNT]; ++}; ++ ++typedef struct { ++ /** Register offset */ ++ unsigned int addr; ++ /** Register data [in or out]*/ ++ unsigned int data; ++} register_config_t; ++ ++struct freq_ranges { ++ unsigned int freq; /* upper margin of frequency range */ ++ unsigned char hs_freq; /* hsfreqrange */ ++ unsigned char vco_range; /* vcorange */ ++}; ++ ++struct loop_band { ++ unsigned int loop_div; /* upper limit of loop divider range */ ++ unsigned char cp_current; /* icpctrl */ ++ unsigned char lpf_resistor; /* lpfctrl */ ++}; ++ ++/* ++ * struct dsi_master_ops - callbacks to mipi-dsi operations. ++ * ++ * @cmd_write: transfer command to lcd panel at LP mode. ++ * @cmd_read: read command from rx register. ++ * @get_dsi_frame_done: get the status that all screen data have been ++ * transferred to mipi-dsi. ++ * @clear_dsi_frame_done: clear frame done status. ++ * @get_fb_frame_done: get frame done status of display controller. ++ * @trigger: trigger display controller. ++ * - this one would be used only in case of CPU mode. ++ * @set_early_blank_mode: set framebuffer blank mode. ++ * - this callback should be called prior to fb_blank() by a client driver ++ * only if needing. ++ * @set_blank_mode: set framebuffer blank mode. ++ * - this callback should be called after fb_blank() by a client driver ++ * only if needing. ++ */ ++ ++struct dsi_master_ops { ++ int (*cmd_write) (struct dsi_device * dsi, struct dsi_cmd_packet cmd_data); ++ int (*cmd_read) (struct dsi_device * dsi, u8 * rx_buf); ++ int (*video_cfg) (struct dsi_device * dsi); ++ int (*mode_cfg) (struct dsi_device *dsi, int mode); ++ int (*query_te) (struct dsi_device *dsi); ++ int (*set_early_blank_mode)(struct dsi_device *dsi, int power); ++ int (*set_blank_mode)(struct dsi_device *dsi, int power); ++ int (*set_blank)(struct dsi_device *dsi, int blank_mode); ++ int (*ioctl)(struct dsi_device *dsi, int cmd); ++}; ++ ++extern struct jzdsi_data jzdsi_pdata; ++int mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device ++ *lcd_dev); ++/** ++ * * register mipi_dsim_lcd_driver object defined by lcd panel driver ++ * * to mipi-dsi driver. ++ * */ ++int mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver ++ *lcd_drv); ++ ++ ++#endif /* _JZ_MIPI_DSIM_H */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_jz_mipi_dsi_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_jz_mipi_dsi_Makefile.patch new file mode 100644 index 00000000..fcd7f755 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_jz_mipi_dsi_Makefile.patch @@ -0,0 +1,5 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v12/jz_mipi_dsi/Makefile b/drivers/video/fbdev/ingenic/fb_v12/jz_mipi_dsi/Makefile +--- a/drivers/video/fbdev/ingenic/fb_v12/jz_mipi_dsi/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v12/jz_mipi_dsi/Makefile 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1 @@ ++obj-y += jz_mipi_dsi.o jz_mipi_dsi_lowlevel.o jz_mipi_dsih_hal.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_jz_mipi_dsi_jz_mipi_dsi.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_jz_mipi_dsi_jz_mipi_dsi.c.patch new file mode 100644 index 00000000..9442ea7d --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_jz_mipi_dsi_jz_mipi_dsi.c.patch @@ -0,0 +1,1138 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v12/jz_mipi_dsi/jz_mipi_dsi.c b/drivers/video/fbdev/ingenic/fb_v12/jz_mipi_dsi/jz_mipi_dsi.c +--- a/drivers/video/fbdev/ingenic/fb_v12/jz_mipi_dsi/jz_mipi_dsi.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v12/jz_mipi_dsi/jz_mipi_dsi.c 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,1134 @@ ++/* ++ * Ingenic SoC MIPI-DSI dsim driver. ++ * ++ * 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. ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../ingenicfb.h" ++#include "../jz_dsim.h" ++#include "jz_mipi_dsi_lowlevel.h" ++#include "jz_mipi_dsih_hal.h" ++#include "jz_mipi_dsi_regs.h" ++extern struct jzfb_platform_data jzfb_platform_data; ++#define jzfb_pdata jzfb_platform_data ++ ++ ++#define DSI_IOBASE 0xb0003000 ++ ++#define DSI_PHY_IOBASE 0xb0004000 ++ ++/*64*/ ++ ++struct mipi_dsim_ddi { ++ int bus_id; ++ struct list_head list; ++ struct mipi_dsim_lcd_device *dsim_lcd_dev; ++ struct mipi_dsim_lcd_driver *dsim_lcd_drv; ++}; ++ ++static LIST_HEAD(dsim_ddi_list); ++ ++static DEFINE_MUTEX(mipi_dsim_lock); ++ ++void dump_dsi_reg(struct dsi_device *dsi); ++static DEFINE_MUTEX(dsi_lock); ++ ++int jz_dsi_video_cfg(struct dsi_device *dsi) ++{ ++ dsih_error_t err_code = OK; ++ unsigned short bytes_per_pixel_x100 = 0; /* bpp x 100 because it can be 2.25 */ ++ unsigned short video_size = 0; ++ unsigned int ratio_clock_xPF = 0; /* holds dpi clock/byte clock times precision factor */ ++ unsigned short null_packet_size = 0; ++ unsigned char video_size_step = 1; ++ unsigned int total_bytes = 0; ++ unsigned int bytes_per_chunk = 0; ++ unsigned int no_of_chunks = 0; ++ unsigned int bytes_left = 0; ++ unsigned int chunk_overhead = 0; ++ ++ struct video_config *video_config; ++ video_config = dsi->video_config; ++ ++ /* check DSI controller dsi */ ++ if ((dsi == NULL) || (video_config == NULL)) { ++ return ERR_DSI_INVALID_INSTANCE; ++ } ++#if 1 ++ if(dsi->state == UBOOT_INITIALIZED) { ++ /*no need to reconfig, just return*/ ++ printk("dsi has already been initialized by uboot!!\n"); ++ return OK; ++ } ++#endif ++ if (dsi->state != INITIALIZED) { ++ return ERR_DSI_INVALID_INSTANCE; ++ } ++ ++ ratio_clock_xPF = video_config->byte_clock * PRECISION_FACTOR; ++ ++ if(video_config->refresh <= 10) ++ ratio_clock_xPF *= 15; ++ else if(video_config->refresh <= 15) ++ ratio_clock_xPF *= 11; ++ else if(video_config->refresh <= 20) ++ ratio_clock_xPF *= 8; ++ else if(video_config->refresh <= 25) ++ ratio_clock_xPF *= 6; ++ else if(video_config->refresh <= 30) ++ ratio_clock_xPF *= 5; ++ else if(video_config->refresh <= 50) ++ ratio_clock_xPF *= 4; ++ else if(video_config->refresh <= 60) ++ ratio_clock_xPF *= 3; ++ else if(video_config->refresh <= 120) ++ ratio_clock_xPF *= 2; ++ ++ ratio_clock_xPF /= video_config->pixel_clock; ++ printk("####################### ratio_clock_xPF=%d\n",ratio_clock_xPF); ++ ++ video_size = video_config->h_active_pixels; ++ /* disable set up ACKs and error reporting */ ++ mipi_dsih_hal_dpi_frame_ack_en(dsi, video_config->receive_ack_packets); ++ if (video_config->receive_ack_packets) { /* if ACK is requested, enable BTA, otherwise leave as is */ ++ mipi_dsih_hal_bta_en(dsi, 1); ++ } ++ /*0:switch to high speed transfer, 1 low power mode */ ++ mipi_dsih_write_word(dsi, R_DSI_HOST_CMD_MODE_CFG, 0); ++ /*0:enable video mode, 1:enable cmd mode */ ++ mipi_dsih_hal_gen_set_mode(dsi, 0); ++ ++ err_code = ++ jz_dsi_video_coding(dsi, &bytes_per_pixel_x100, &video_size_step, ++ &video_size); ++ if (err_code) { ++ return err_code; ++ } ++ ++ jz_dsi_dpi_cfg(dsi, &ratio_clock_xPF, &bytes_per_pixel_x100); ++ ++ /* TX_ESC_CLOCK_DIV must be less than 20000KHz */ ++ jz_dsih_hal_tx_escape_division(dsi, TX_ESC_CLK_DIV); ++ ++ /* video packetisation */ ++ if (video_config->video_mode == VIDEO_BURST_WITH_SYNC_PULSES) { /* BURST */ ++ //mipi_dsih_hal_dpi_null_packet_en(dsi, 0); ++ mipi_dsih_hal_dpi_null_packet_size(dsi, 0); ++ //mipi_dsih_hal_dpi_multi_packet_en(dsi, 0); ++ err_code = ++ err_code ? err_code : mipi_dsih_hal_dpi_chunks_no(dsi, 1); ++ err_code = ++ err_code ? err_code : ++ mipi_dsih_hal_dpi_video_packet_size(dsi, video_size); ++ if (err_code != OK) { ++ return err_code; ++ } ++ /* BURST by default, returns to LP during ALL empty periods - energy saving */ ++ mipi_dsih_hal_dpi_lp_during_hfp(dsi, 1); ++ mipi_dsih_hal_dpi_lp_during_hbp(dsi, 1); ++ mipi_dsih_hal_dpi_lp_during_vactive(dsi, 1); ++ mipi_dsih_hal_dpi_lp_during_vfp(dsi, 1); ++ mipi_dsih_hal_dpi_lp_during_vbp(dsi, 1); ++ mipi_dsih_hal_dpi_lp_during_vsync(dsi, 1); ++#ifdef CONFIG_DSI_DPI_DEBUG ++ /* D E B U G */ ++ { ++ pr_info("burst video"); ++ pr_info("h line time %d ,", ++ (unsigned ++ short)((video_config->h_total_pixels * ++ ratio_clock_xPF) / PRECISION_FACTOR)); ++ pr_info("video_size %d ,", video_size); ++ } ++#endif ++ } else { /* non burst transmission */ ++ null_packet_size = 0; ++ /* bytes to be sent - first as one chunk */ ++ bytes_per_chunk = ++ (bytes_per_pixel_x100 * video_config->h_active_pixels) / ++ 100 + VIDEO_PACKET_OVERHEAD; ++ /* bytes being received through the DPI interface per byte clock cycle */ ++ total_bytes = ++ (ratio_clock_xPF * video_config->no_of_lanes * ++ (video_config->h_total_pixels - ++ video_config->h_back_porch_pixels - ++ video_config->h_sync_pixels)) / PRECISION_FACTOR; ++ pr_debug("---->total_bytes:%d, bytes_per_chunk:%d\n", total_bytes, ++ bytes_per_chunk); ++ /* check if the in pixels actually fit on the DSI link */ ++ if (total_bytes >= bytes_per_chunk) { ++ chunk_overhead = total_bytes - bytes_per_chunk; ++ /* overhead higher than 1 -> enable multi packets */ ++ if (chunk_overhead > 1) { ++ for (video_size = video_size_step; video_size < video_config->h_active_pixels; video_size += video_size_step) { /* determine no of chunks */ ++ if ((((video_config->h_active_pixels * ++ PRECISION_FACTOR) / video_size) % ++ PRECISION_FACTOR) == 0) { ++ no_of_chunks = ++ video_config-> ++ h_active_pixels / ++ video_size; ++ bytes_per_chunk = ++ (bytes_per_pixel_x100 * ++ video_size) / 100 + ++ VIDEO_PACKET_OVERHEAD; ++ if (total_bytes >= ++ (bytes_per_chunk * ++ no_of_chunks)) { ++ bytes_left = ++ total_bytes - ++ (bytes_per_chunk * ++ no_of_chunks); ++ break; ++ } ++ } ++ } ++ /* prevent overflow (unsigned - unsigned) */ ++ if (bytes_left > ++ (NULL_PACKET_OVERHEAD * no_of_chunks)) { ++ null_packet_size = ++ (bytes_left - ++ (NULL_PACKET_OVERHEAD * ++ no_of_chunks)) / no_of_chunks; ++ if (null_packet_size > MAX_NULL_SIZE) { /* avoid register overflow */ ++ null_packet_size = ++ MAX_NULL_SIZE; ++ } ++ } ++ } else { /* no multi packets */ ++ no_of_chunks = 1; ++#ifdef CONFIG_DSI_DPI_DEBUG ++ /* D E B U G */ ++ { ++ pr_info("no multi no null video"); ++ pr_info("h line time %d", ++ (unsigned ++ short)((video_config-> ++ h_total_pixels * ++ ratio_clock_xPF) / ++ PRECISION_FACTOR)); ++ pr_info("video_size %d", video_size); ++ } ++#endif ++ /* video size must be a multiple of 4 when not 18 loosely */ ++ for (video_size = video_config->h_active_pixels; ++ (video_size % video_size_step) != 0; ++ video_size++) { ++ ; ++ } ++ } ++ } else { ++ pr_err ++ ("resolution cannot be sent to display through current settings"); ++ err_code = ERR_DSI_OVERFLOW; ++ ++ } ++ } ++ err_code = ++ err_code ? err_code : mipi_dsih_hal_dpi_chunks_no(dsi, ++ no_of_chunks); ++ err_code = ++ err_code ? err_code : mipi_dsih_hal_dpi_video_packet_size(dsi, ++ video_size); ++ err_code = ++ err_code ? err_code : mipi_dsih_hal_dpi_null_packet_size(dsi, ++ null_packet_size); ++ ++ // mipi_dsih_hal_dpi_null_packet_en(dsi, null_packet_size > 0? 1: 0); ++ // mipi_dsih_hal_dpi_multi_packet_en(dsi, (no_of_chunks > 1)? 1: 0); ++#ifdef CONFIG_DSI_DPI_DEBUG ++ /* D E B U G */ ++ { ++ pr_info("total_bytes %d ,", total_bytes); ++ pr_info("bytes_per_chunk %d ,", bytes_per_chunk); ++ pr_info("bytes left %d ,", bytes_left); ++ pr_info("null packets %d ,", null_packet_size); ++ pr_info("chunks %d ,", no_of_chunks); ++ pr_info("video_size %d ", video_size); ++ } ++#endif ++ mipi_dsih_hal_dpi_video_vc(dsi, video_config->virtual_channel); ++ jz_dsih_dphy_no_of_lanes(dsi, video_config->no_of_lanes); ++ /* enable high speed clock */ ++ mipi_dsih_dphy_enable_hs_clk(dsi, 1); ++ pr_debug("video configure is ok!\n"); ++ return err_code; ++ ++} ++ ++/* set all register settings to MIPI DSI controller. */ ++dsih_error_t jz_dsi_phy_cfg(struct dsi_device * dsi) ++{ ++ dsih_error_t err = OK; ++ err = jz_dsi_set_clock(dsi); ++ if (err) { ++ return err; ++ } ++ err = jz_init_dsi(dsi); ++ if (err) { ++ return err; ++ } ++ return OK; ++} ++ ++int jz_dsi_phy_open(struct dsi_device *dsi) ++{ ++ struct video_config *video_config; ++ video_config = dsi->video_config; ++ ++ pr_debug("entry %s()\n", __func__); ++ ++ jz_dsih_dphy_reset(dsi, 0); ++ jz_dsih_dphy_stop_wait_time(dsi, 0x1c); /* 0x1c: */ ++ ++ if (video_config->no_of_lanes > 4 || video_config->no_of_lanes < 1) ++ return ERR_DSI_OUT_OF_BOUND; ++ jz_dsih_dphy_no_of_lanes(dsi, video_config->no_of_lanes); ++ ++ jz_dsih_dphy_clock_en(dsi, 1); ++ jz_dsih_dphy_shutdown(dsi, 1); ++ jz_dsih_dphy_reset(dsi, 1); ++ ++ dsi->dsi_phy->status = INITIALIZED; ++ return OK; ++} ++ ++void dump_dsi_reg(struct dsi_device *dsi) ++{ ++ pr_info("dsi->dev: ===========>dump dsi reg\n"); ++ pr_info("dsi->dev: VERSION------------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_VERSION)); ++ pr_info("dsi->dev: PWR_UP:------------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_PWR_UP)); ++ pr_info("dsi->dev: CLKMGR_CFG---------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_CLKMGR_CFG)); ++ pr_info("dsi->dev: DPI_VCID-----------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_DPI_VCID)); ++ pr_info("dsi->dev: DPI_COLOR_CODING---:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_DPI_COLOR_CODING)); ++ pr_info("dsi->dev: DPI_CFG_POL--------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_DPI_CFG_POL)); ++ pr_info("dsi->dev: DPI_LP_CMD_TIM-----:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_DPI_LP_CMD_TIM)); ++ pr_info("dsi->dev: DBI_VCID-----------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_DBI_VCID)); ++ pr_info("dsi->dev: DBI_CFG------------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_DBI_CFG)); ++ pr_info("dsi->dev: DBI_PARTITIONING_EN:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_DBI_PARTITIONING_EN)); ++ pr_info("dsi->dev: DBI_CMDSIZE--------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_DBI_CMDSIZE)); ++ pr_info("dsi->dev: PCKHDL_CFG---------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_PCKHDL_CFG)); ++ pr_info("dsi->dev: GEN_VCID-----------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_GEN_VCID)); ++ pr_info("dsi->dev: MODE_CFG-----------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_MODE_CFG)); ++ pr_info("dsi->dev: VID_MODE_CFG-------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_VID_MODE_CFG)); ++ pr_info("dsi->dev: VID_PKT_SIZE-------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_VID_PKT_SIZE)); ++ pr_info("dsi->dev: VID_NUM_CHUNKS-----:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_VID_NUM_CHUNKS)); ++ pr_info("dsi->dev: VID_NULL_SIZE------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_VID_NULL_SIZE)); ++ pr_info("dsi->dev: VID_HSA_TIME-------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_VID_HSA_TIME)); ++ pr_info("dsi->dev: VID_HBP_TIME-------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_VID_HBP_TIME)); ++ pr_info("dsi->dev: VID_HLINE_TIME-----:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_VID_HLINE_TIME)); ++ pr_info("dsi->dev: VID_VSA_LINES------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_VID_VSA_LINES)); ++ pr_info("dsi->dev: VID_VBP_LINES------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_VID_VBP_LINES)); ++ pr_info("dsi->dev: VID_VFP_LINES------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_VID_VFP_LINES)); ++ pr_info("dsi->dev: VID_VACTIVE_LINES--:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_VID_VACTIVE_LINES)); ++ pr_info("dsi->dev: EDPI_CMD_SIZE------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_EDPI_CMD_SIZE)); ++ pr_info("dsi->dev: CMD_MODE_CFG-------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_CMD_MODE_CFG)); ++ pr_info("dsi->dev: GEN_HDR------------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_GEN_HDR)); ++ pr_info("dsi->dev: GEN_PLD_DATA-------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_GEN_PLD_DATA)); ++ pr_info("dsi->dev: CMD_PKT_STATUS-----:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_CMD_PKT_STATUS)); ++ pr_info("dsi->dev: TO_CNT_CFG---------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_TO_CNT_CFG)); ++ pr_info("dsi->dev: HS_RD_TO_CNT-------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_HS_RD_TO_CNT)); ++ pr_info("dsi->dev: LP_RD_TO_CNT-------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_LP_RD_TO_CNT)); ++ pr_info("dsi->dev: HS_WR_TO_CNT-------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_HS_WR_TO_CNT)); ++ pr_info("dsi->dev: LP_WR_TO_CNT_CFG---:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_LP_WR_TO_CNT)); ++ pr_info("dsi->dev: BTA_TO_CNT---------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_BTA_TO_CNT)); ++ pr_info("dsi->dev: SDF_3D-------------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_SDF_3D)); ++ pr_info("dsi->dev: LPCLK_CTRL---------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_LPCLK_CTRL)); ++ pr_info("dsi->dev: PHY_TMR_LPCLK_CFG--:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_PHY_TMR_LPCLK_CFG)); ++ pr_info("dsi->dev: PHY_TMR_CFG--------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_PHY_TMR_CFG)); ++ pr_info("dsi->dev: PHY_RSTZ-----------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_PHY_RSTZ)); ++ pr_info("dsi->dev: PHY_IF_CFG---------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_PHY_IF_CFG)); ++ pr_info("dsi->dev: PHY_ULPS_CTRL------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_PHY_ULPS_CTRL)); ++ pr_info("dsi->dev: PHY_TX_TRIGGERS----:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_PHY_TX_TRIGGERS)); ++ pr_info("dsi->dev: PHY_STATUS---------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_PHY_STATUS)); ++ pr_info("dsi->dev: PHY_TST_CTRL0------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_PHY_TST_CTRL0)); ++ pr_info("dsi->dev: PHY_TST_CTRL1------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_PHY_TST_CTRL1)); ++ pr_info("dsi->dev: INT_ST0------------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_INT_ST0)); ++ pr_info("dsi->dev: INT_ST1------------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_INT_ST1)); ++ pr_info("dsi->dev: INT_MSK0-----------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_INT_MSK0)); ++ pr_info("dsi->dev: INT_MSK1-----------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_INT_MSK1)); ++ pr_info("dsi->dev: INT_FORCE0---------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_INT_FORCE0)); ++ pr_info("dsi->dev: INT_FORCE1---------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_INT_FORCE1)); ++ pr_info("dsi->dev: VID_SHADOW_CTRL----:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_VID_SHADOW_CTRL)); ++ pr_info("dsi->dev: DPI_VCID_ACT-------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_DPI_VCID_ACT)); ++ pr_info("dsi->dev: DPI_COLOR_CODING_AC:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_DPI_COLOR_CODING_ACT)); ++ pr_info("dsi->dev: DPI_LP_CMD_TIM_ACT-:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_DPI_LP_CMD_TIM_ACT)); ++ pr_info("dsi->dev: VID_MODE_CFG_ACT---:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_VID_MODE_CFG_ACT)); ++ pr_info("dsi->dev: VID_PKT_SIZE_ACT---:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_VID_PKT_SIZE_ACT)); ++ pr_info("dsi->dev: VID_NUM_CHUNKS_ACT-:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_VID_NUM_CHUNKS_ACT)); ++ pr_info("dsi->dev: VID_HSA_TIME_ACT---:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_VID_HSA_TIME_ACT)); ++ pr_info("dsi->dev: VID_HBP_TIME_ACT---:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_VID_HBP_TIME_ACT)); ++ pr_info("dsi->dev: VID_HLINE_TIME_ACT-:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_VID_HLINE_TIME_ACT)); ++ pr_info("dsi->dev: VID_VSA_LINES_ACT--:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_VID_VSA_LINES_ACT)); ++ pr_info("dsi->dev: VID_VBP_LINES_ACT--:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_VID_VBP_LINES_ACT)); ++ pr_info("dsi->dev: VID_VFP_LINES_ACT--:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_VID_VFP_LINES_ACT)); ++ pr_info("dsi->dev: VID_VACTIVE_LINES_ACT:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_VID_VACTIVE_LINES_ACT)); ++ pr_info("dsi->dev: SDF_3D_ACT---------:%08x\n", ++ mipi_dsih_read_word(dsi, R_DSI_HOST_SDF_3D_ACT)); ++ ++} ++ ++void set_base_dir_tx(struct dsi_device *dsi, void *param) ++{ ++ int i = 0; ++ register_config_t phy_direction[] = { ++ {0xb4, 0x02}, ++ {0xb8, 0xb0}, ++ {0xb8, 0x100b0}, ++ {0xb4, 0x00}, ++ {0xb8, 0x000b0}, ++ {0xb8, 0x0000}, ++ {0xb4, 0x02}, ++ {0xb4, 0x00} ++ }; ++ i = mipi_dsih_write_register_configuration(dsi, phy_direction, ++ (sizeof(phy_direction) / ++ sizeof(register_config_t))); ++ if (i != (sizeof(phy_direction) / sizeof(register_config_t))) { ++ pr_err("ERROR setting up testchip %d", i); ++ } ++} ++ ++static void init_dsi_phy(struct dsi_device *dsi) ++{ ++ unsigned int temp = 0xffffffff; ++ ++ printk("dsi phy address = 0x%x\n", dsi->phy_address); ++ //power on ,reset, set pin_enable_ck/0/1/* of lanes to be used to high level and others to low ++ printk("%s,%d step0 do nothing now.\n", __func__, __LINE__); ++ ++ //step1 ++ temp = *(volatile unsigned int*)(dsi->phy_address+0x0C); ++ temp &= ~0xff; ++ temp |= 0x02; ++ writel(temp, (volatile unsigned int*)(dsi->phy_address+0x0C)); ++ if ((*(volatile unsigned int*)(dsi->phy_address+0x0C) & 0xff) != 0x02) { ++ printk("%s,%d reg write error. Step1\n", __func__, __LINE__); ++ } ++ printk("reg:0x03, value:0x%x\n", *(volatile unsigned int*)(dsi->phy_address+0x0C)); ++ //step2 ++ temp = *(volatile unsigned int*)(dsi->phy_address+0x10); ++ temp &= ~0xff; ++ temp |= 0xff; ++ writel(temp, (volatile unsigned int*)(dsi->phy_address+0x10)); ++ if ((*(volatile unsigned int*)(dsi->phy_address+0x10) & 0xff) != 0x53) { ++ printk("%s,%d reg write error. Step2\n", __func__, __LINE__); ++ } ++ printk("reg:0x04, value:0x%x\n", *(volatile unsigned int*)(dsi->phy_address+0x10)); ++ //step3 ++ temp = *(volatile unsigned int*)(dsi->phy_address+0x04); ++ temp &= ~0xff; ++ temp |= 0xe4; ++ writel(temp, (volatile unsigned int*)(dsi->phy_address+0x04)); ++ if ((*(volatile unsigned int*)(dsi->phy_address+0x04) & 0xff) != 0xe4) { ++ printk("%s,%d reg write error. Step3\n", __func__, __LINE__); ++ } ++ printk("reg:0x01, value:0x%x\n", *(volatile unsigned int*)(dsi->phy_address+0x04)); ++ //step4 ++ if (dsi->video_config->no_of_lanes == 4) { ++ temp = *(volatile unsigned int*)(dsi->phy_address+0x00); ++ temp &= ~0xff; ++ temp |= 0x7d; //4lane ++ writel(temp, (volatile unsigned int*)(dsi->phy_address+0x00)); ++ if ((*(volatile unsigned int*)(dsi->phy_address+0x00) & 0xff) != 0x7d) { ++ printk("%s,%d reg write error. Step4\n", __func__, __LINE__); ++ } ++ } ++ else if (dsi->video_config->no_of_lanes == 2){ ++ temp = *(volatile unsigned int*)(dsi->phy_address+0x00); ++ temp &= ~0xff; ++ temp |= 0x4d; //2lane ++ writel(temp, (volatile unsigned int*)(dsi->phy_address+0x00)); ++ if ((*(volatile unsigned int*)(dsi->phy_address+0x00) & 0xff) != 0x4d) { ++ printk("%s,%d reg write error. Step4\n", __func__, __LINE__); ++ } ++ } ++ printk("reg:0x00, value:0x%x\n", *(volatile unsigned int*)(dsi->phy_address+0x00)); ++ //step5 ++ temp = *(volatile unsigned int*)(dsi->phy_address+0x04); ++ temp &= ~0xff; ++ temp |= 0xe0; ++ writel(temp, (volatile unsigned int*)(dsi->phy_address+0x04)); ++ if ((*(volatile unsigned int*)(dsi->phy_address+0x04) & 0xff) != 0xe0) { ++ printk("%s,%d reg write error. Step5\n", __func__, __LINE__); ++ } ++ printk("reg:0x01, value:0x%x\n", *(volatile unsigned int*)(dsi->phy_address+0x04)); ++ ++ //step6 ++ msleep(20); //at lease 20ms, shortening need validation ++ ++ //step7 ++ temp = *(volatile unsigned int*)(dsi->phy_address+0x80); ++ temp &= ~0xff; ++ temp |= 0x1e; ++ writel(temp, (volatile unsigned int*)(dsi->phy_address+0x80)); ++ if ((*(volatile unsigned int*)(dsi->phy_address+0x80) & 0xff) != 0x1e) { ++ printk("%s,%d reg write error. Step7\n", __func__, __LINE__); ++ } ++ printk("reg:0x20, value:0x%x\n", *(volatile unsigned int*)(dsi->phy_address+0x80)); ++ //step8 ++ temp = *(volatile unsigned int*)(dsi->phy_address+0x80); ++ temp &= ~0xff; ++ temp |= 0x1f; ++ writel(temp, (volatile unsigned int*)(dsi->phy_address+0x80)); ++ if ((*(volatile unsigned int*)(dsi->phy_address+0x80) & 0xff) != 0x1f) { ++ printk("%s,%d reg write error. Step8\n", __func__, __LINE__); ++ } ++ printk("reg:0x20, value:0x%x\n", *(volatile unsigned int*)(dsi->phy_address+0x80)); ++ //step9 ++ msleep(10); ++ ++ printk("%s,%d dsi phy init over now...\n", __func__, __LINE__); ++} ++ ++static int jz_mipi_update_cfg(struct dsi_device *dsi) ++{ ++ int ret; ++ int st_mask = 0; ++ int retry = 5; ++ ret = jz_dsi_phy_open(dsi); ++ if (ret) { ++ pr_err("open the phy failed!\n"); ++ return ret; ++ } ++ ++ mipi_dsih_write_word(dsi, R_DSI_HOST_CMD_MODE_CFG, ++ 0xffffff0); ++ ++ /*set command mode */ ++ mipi_dsih_write_word(dsi, R_DSI_HOST_MODE_CFG, 0x1); ++ /*set this register for cmd size, default 0x6 */ ++ mipi_dsih_write_word(dsi, R_DSI_HOST_EDPI_CMD_SIZE, 0x6); ++ ++ /* ++ * jz_dsi_phy_cfg: ++ * PLL programming, config the output freq to DEFAULT_DATALANE_BPS. ++ * */ ++ init_dsi_phy(dsi); ++ ret = jz_dsi_phy_cfg(dsi); ++ if (ret) { ++ pr_err("phy configigure failed!\n"); ++ return ret; ++ } ++ ++ pr_debug("wait for phy config ready\n"); ++ if (dsi->video_config->no_of_lanes == 2) ++ st_mask = 0x95; ++ else ++ st_mask = 0x15; ++ ++ /*checkout phy clk lock and clklane, datalane stopstate */ ++ udelay(10); ++ while ((mipi_dsih_read_word(dsi, R_DSI_HOST_PHY_STATUS) & st_mask) != ++ st_mask && retry--) { ++ pr_info("phy status = %08x\n", mipi_dsih_read_word(dsi, R_DSI_HOST_PHY_STATUS)); ++ } ++ ++ if (!retry){ ++ pr_err("wait for phy config failed!\n"); ++ return ret; ++ } ++ ++ dsi->state = INITIALIZED; ++ return 0; ++} ++ ++/* for debug lcd power on/off */ ++int jz_mipi_dsi_set_client(struct dsi_device *dsi, int power) ++{ ++ struct mipi_dsim_lcd_driver *client_drv = dsi->dsim_lcd_drv; ++ struct mipi_dsim_lcd_device *client_dev = dsi->dsim_lcd_dev; ++ ++ switch (power) { ++ case FB_BLANK_POWERDOWN: ++ if (client_drv && client_drv->suspend) ++ client_drv->suspend(client_dev); ++ ++ break; ++ case FB_BLANK_UNBLANK: ++ /* lcd panel power on. */ ++ if (client_drv && client_drv->power_on) ++ client_drv->power_on(client_dev, POWER_ON_LCD); ++ ++ /* set lcd panel sequence commands. */ ++ if (client_drv && client_drv->set_sequence) ++ client_drv->set_sequence(client_dev); ++ ++ break; ++ case FB_BLANK_NORMAL: ++ /* TODO. */ ++ break; ++ ++ default: ++ break; ++ } ++ return 0; ++} ++ ++static int jz_mipi_dsi_blank_mode(struct dsi_device *dsi, int power) ++{ ++ struct mipi_dsim_lcd_driver *client_drv = dsi->dsim_lcd_drv; ++ struct mipi_dsim_lcd_device *client_dev = dsi->dsim_lcd_dev; ++ ++ switch (power) { ++ case FB_BLANK_POWERDOWN: ++ if (dsi->suspended) ++ return 0; ++ ++ if (client_drv && client_drv->suspend) ++ client_drv->suspend(client_dev); ++ ++ jz_dsih_dphy_clock_en(dsi, 0); ++ jz_dsih_dphy_shutdown(dsi, 0); ++ clk_disable_unprepare(dsi->clk); ++ mipi_dsih_hal_power(dsi, 0); ++ ++ dsi->state = NOT_INITIALIZED; ++ dsi->suspended = true; ++ ++ break; ++ case FB_BLANK_UNBLANK: ++ if (!dsi->suspended) ++ return 0; ++ ++ clk_prepare_enable(dsi->clk); ++ jz_mipi_update_cfg(dsi); ++ ++ /* lcd panel power on. */ ++ if (client_drv && client_drv->power_on) ++ client_drv->power_on(client_dev, POWER_ON_LCD); ++ ++ /* set lcd panel sequence commands. */ ++ if (client_drv && client_drv->set_sequence) ++ client_drv->set_sequence(client_dev); ++ ++ dsi->suspended = false; ++ ++ break; ++ case FB_BLANK_NORMAL: ++ /* TODO. */ ++ break; ++ ++ ++ default: ++ break; ++ } ++ ++ return 0; ++} ++ ++static int jz_mipi_dsi_ioctl(struct dsi_device *dsi, int cmd) ++{ ++ struct mipi_dsim_lcd_driver *client_drv = dsi->dsim_lcd_drv; ++ struct mipi_dsim_lcd_device *client_dev = dsi->dsim_lcd_dev; ++ ++ if (client_drv && client_drv->ioctl) ++ client_drv->ioctl(client_dev, cmd); ++ ++ return 0; ++} ++ ++int jz_dsi_mode_cfg(struct dsi_device *dsi, int mode) ++{ ++ struct video_config *video_config; ++ struct dsi_config *dsi_config; ++ video_config = dsi->video_config; ++ dsi_config = dsi->dsi_config; ++ ++ if(mode == 1) { ++ /* video mode */ ++ jz_dsih_hal_power(dsi, 0); ++ jz_dsi_video_cfg(dsi); ++ jz_dsih_hal_power(dsi, 1); ++ } else { ++ mipi_dsih_write_word(dsi, R_DSI_HOST_EDPI_CMD_SIZE, 1024); /* 当设置太小时, 对于M31传输数据会有卡死的现象??, 这里设置成1024。*/ ++ mipi_dsih_dphy_enable_hs_clk(dsi, 1); ++ mipi_dsih_dphy_auto_clklane_ctrl(dsi, 1); ++ mipi_dsih_write_word(dsi, R_DSI_HOST_CMD_MODE_CFG, 1); ++ ++ /* cmd mode */ ++ /* color coding fix to 24bit ???? */ ++ mipi_dsih_hal_dpi_frame_ack_en(dsi, video_config->receive_ack_packets); ++ if (video_config->receive_ack_packets) { /* if ACK is requested, enable BTA, otherwise leave as is */ ++ mipi_dsih_hal_bta_en(dsi, 1); ++ } ++ if(dsi_config->te_mipi_en) { ++ mipi_dsih_hal_tear_effect_ack_en(dsi, 1); ++ } else { ++ mipi_dsih_hal_tear_effect_ack_en(dsi, 0); ++ } ++ mipi_dsih_hal_gen_set_mode(dsi, 1); ++ mipi_dsih_hal_dpi_color_coding(dsi, dsi->video_config->color_coding); ++ } ++ ++ return 0; ++} ++ ++static int jz_dsi_query_te(struct dsi_device *dsi) ++{ ++ struct dsi_cmd_packet set_tear_on = {0x15, 0x35, 0x00}; ++ /* unsigned int cmd_mode_cfg; */ ++ ++ if(!dsi->dsi_config->te_mipi_en) ++ return 0; ++ ++ //return 0; ++ ++ /* According to DSI host spec. */ ++ /* ++ Tearing effect request must always be triggered by a set_tear_on ++ command in the DWC_mipi_dsi_host implementation ++ */ ++ write_command(dsi, set_tear_on); ++ ++ return 0; ++ ++} ++ ++/* define MIPI-DSI Master operations. */ ++static struct dsi_master_ops jz_master_ops = { ++ .video_cfg = jz_dsi_video_cfg, ++ .mode_cfg = jz_dsi_mode_cfg, ++ .cmd_write = write_command, /*jz_dsi_wr_data, */ ++ .query_te = jz_dsi_query_te, ++ .cmd_read = NULL, /*jz_dsi_rd_data, */ ++ .ioctl = jz_mipi_dsi_ioctl, ++ .set_blank_mode = jz_mipi_dsi_blank_mode, ++}; ++ ++int mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device *lcd_dev) ++{ ++ struct mipi_dsim_ddi *dsim_ddi; ++ ++ if (!lcd_dev->name) { ++ pr_err("dsim_lcd_device name is NULL.\n"); ++ return -EFAULT; ++ } ++ ++ dsim_ddi = kzalloc(sizeof(struct mipi_dsim_ddi), GFP_KERNEL); ++ if (!dsim_ddi) { ++ pr_err("failed to allocate dsim_ddi object.\n"); ++ return -ENOMEM; ++ } ++ ++ dsim_ddi->dsim_lcd_dev = lcd_dev; ++ ++ mutex_lock(&mipi_dsim_lock); ++ list_add_tail(&dsim_ddi->list, &dsim_ddi_list); ++ mutex_unlock(&mipi_dsim_lock); ++ ++ return 0; ++} ++ ++static struct mipi_dsim_ddi *mipi_dsi_find_lcd_device( ++ struct mipi_dsim_lcd_driver *lcd_drv) ++{ ++ struct mipi_dsim_ddi *dsim_ddi, *next; ++ struct mipi_dsim_lcd_device *lcd_dev; ++ ++ mutex_lock(&mipi_dsim_lock); ++ ++ list_for_each_entry_safe(dsim_ddi, next, &dsim_ddi_list, list) { ++ if (!dsim_ddi) ++ goto out; ++ ++ lcd_dev = dsim_ddi->dsim_lcd_dev; ++ if (!lcd_dev) ++ continue; ++ ++ if ((strcmp(lcd_drv->name, lcd_dev->name)) == 0) { ++ /** ++ * bus_id would be used to identify ++ * connected bus. ++ */ ++ dsim_ddi->bus_id = lcd_dev->bus_id; ++ mutex_unlock(&mipi_dsim_lock); ++ ++ return dsim_ddi; ++ } ++ ++ list_del(&dsim_ddi->list); ++ kfree(dsim_ddi); ++ } ++ ++out: ++ mutex_unlock(&mipi_dsim_lock); ++ ++ return NULL; ++} ++ ++int mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver *lcd_drv) ++{ ++ struct mipi_dsim_ddi *dsim_ddi; ++ ++ if (!lcd_drv->name) { ++ pr_err("dsim_lcd_driver name is NULL.\n"); ++ return -EFAULT; ++ } ++ ++ dsim_ddi = mipi_dsi_find_lcd_device(lcd_drv); ++ if (!dsim_ddi) { ++ pr_err("mipi_dsim_ddi object not found.\n"); ++ return -EFAULT; ++ } ++ ++ dsim_ddi->dsim_lcd_drv = lcd_drv; ++ ++ pr_info("registered panel driver(%s) to mipi-dsi driver.\n", ++ lcd_drv->name); ++ ++ return 0; ++ ++} ++ ++static struct mipi_dsim_ddi *mipi_dsi_bind_lcd_ddi( ++ struct dsi_device *dsim, ++ const char *name) ++{ ++ struct mipi_dsim_ddi *dsim_ddi, *next; ++ struct mipi_dsim_lcd_driver *lcd_drv; ++ struct mipi_dsim_lcd_device *lcd_dev; ++ int ret; ++ ++ mutex_lock(&dsim->lock); ++ ++ list_for_each_entry_safe(dsim_ddi, next, &dsim_ddi_list, list) { ++ lcd_drv = dsim_ddi->dsim_lcd_drv; ++ lcd_dev = dsim_ddi->dsim_lcd_dev; ++ ++ pr_debug("dsi->dev: lcd_drv->name = %s, name = %s\n", ++ lcd_drv->name, name); ++ if ((strcmp(lcd_drv->name, name) == 0)) { ++ lcd_dev->master = dsim; ++ ++ dev_set_name(&lcd_dev->dev, "%s", lcd_drv->name); ++ ++ ret = device_register(&lcd_dev->dev); ++ if (ret < 0) { ++ pr_err("can't register %s, status %d\n", ++ dev_name(&lcd_dev->dev), ret); ++ mutex_unlock(&dsim->lock); ++ return NULL; ++ } ++ ++ dsim->dsim_lcd_dev = lcd_dev; ++ dsim->dsim_lcd_drv = lcd_drv; ++ ++ mutex_unlock(&dsim->lock); ++ ++ return dsim_ddi; ++ }else{ ++ pr_err("dsi->dev: lcd_drv->name is different with fb name\n"); ++ } ++ } ++ ++ mutex_unlock(&dsim->lock); ++ ++ return NULL; ++} ++ ++struct dsi_device * jzdsi_init(struct jzdsi_data *pdata) ++{ ++ struct dsi_device *dsi; ++ struct dsi_phy *dsi_phy; ++ struct mipi_dsim_ddi *dsim_ddi; ++ int ret = -EINVAL; ++ pr_debug("entry %s()\n", __func__); ++ ++ dsi = (struct dsi_device *)kzalloc(sizeof(struct dsi_device), GFP_KERNEL); ++ if (!dsi) { ++ pr_err("dsi->dev: failed to allocate dsi object.\n"); ++ ret = -ENOMEM; ++ goto err_dsi; ++ } ++ ++ dsi_phy = (struct dsi_phy *)kzalloc(sizeof(struct dsi_phy), GFP_KERNEL); ++ if (!dsi_phy) { ++ pr_err("dsi->dev: failed to allocate dsi phy object.\n"); ++ ret = -ENOMEM; ++ goto err_dsi_phy; ++ } ++ dsi->dsi_config = &(pdata->dsi_config); ++ ++ dsi_phy->status = NOT_INITIALIZED; ++ dsi_phy->reference_freq = REFERENCE_FREQ; ++ dsi_phy->bsp_pre_config = set_base_dir_tx; ++ dsi->dsi_phy = dsi_phy; ++ dsi->video_config = &(pdata->video_config); ++ dsi->video_config->refresh = pdata->modes->refresh; ++ dsi->video_config->pixel_clock = PICOS2KHZ(pdata->modes->pixclock); // dpi_clock ++ dsi->video_config->h_polarity = pdata->modes->sync & FB_SYNC_HOR_HIGH_ACT; ++ dsi->video_config->h_active_pixels = pdata->modes->xres; ++ dsi->video_config->h_sync_pixels = pdata->modes->hsync_len; ++ dsi->video_config->h_back_porch_pixels = pdata->modes->left_margin; ++ dsi->video_config->h_total_pixels = pdata->modes->xres + pdata->modes->hsync_len + pdata->modes->left_margin + pdata->modes->right_margin; ++ dsi->video_config->v_active_lines = pdata->modes->yres; ++ dsi->video_config->v_polarity = pdata->modes->sync & FB_SYNC_VERT_HIGH_ACT; ++ dsi->video_config->v_sync_lines = pdata->modes->vsync_len; ++ dsi->video_config->v_back_porch_lines = pdata->modes->upper_margin; ++ dsi->video_config->v_total_lines = pdata->modes->yres + pdata->modes->upper_margin + pdata->modes->lower_margin + pdata->modes->vsync_len; ++ ++ pr_debug("dsi->video_config->h_total_pixels: %d\n", dsi->video_config->h_total_pixels); ++ pr_debug("dsi->video_config->v_total_lines: %d\n", dsi->video_config->v_total_lines); ++ pr_debug("jzfb_pdata.modes->refresh: %d\n", pdata->modes->refresh); ++ pr_debug("jzfb_pdata.bpp: %d\n", pdata->bpp_info); ++ pr_debug("dsi->video_config->no_of_lanes: %d\n", dsi->video_config->no_of_lanes); ++ pr_debug("---dsi->video_config->byte_clock: %d\n", dsi->video_config->byte_clock); ++ ++ printk("dsi->video_config->h_total_pixels: %d\n", dsi->video_config->h_total_pixels); ++ printk("dsi->video_config->v_total_lines: %d\n", dsi->video_config->v_total_lines); ++ printk("jzfb_pdata.modes->refresh: %d\n", pdata->modes->refresh); ++ printk("jzfb_pdata.bpp: %d\n", pdata->bpp_info); ++ printk("dsi->video_config->no_of_lanes: %d\n", dsi->video_config->no_of_lanes); ++ printk("---dsi->video_config->byte_clock: %d\n", dsi->video_config->byte_clock); ++ ++ if(!dsi->video_config->byte_clock) { ++ dsi->video_config->byte_clock = dsi->video_config->h_total_pixels * dsi->video_config->v_total_lines * ++ pdata->modes->refresh * pdata->bpp_info / dsi->video_config->no_of_lanes / 8 / 1000 ; ++#if 0 ++ if (dsi->video_config->no_of_lanes == 2) { ++ if (pdata->modes->refresh == 15) ++ dsi->video_config->byte_clock = dsi->video_config->byte_clock*6 + dsi->video_config->byte_clock / 2; ++ else if (pdata->modes->refresh == 20) ++ dsi->video_config->byte_clock = dsi->video_config->byte_clock*5 + dsi->video_config->byte_clock / 2; ++ else if (pdata->modes->refresh == 25) ++ dsi->video_config->byte_clock = dsi->video_config->byte_clock*4 + dsi->video_config->byte_clock / 2; ++ else if (pdata->modes->refresh == 30) ++ dsi->video_config->byte_clock = dsi->video_config->byte_clock*3 + dsi->video_config->byte_clock / 2; ++ else if (pdata->modes->refresh == 60) ++ dsi->video_config->byte_clock = dsi->video_config->byte_clock + dsi->video_config->byte_clock / 2; ++ } else if (dsi->video_config->no_of_lanes == 4){ ++ if (pdata->modes->refresh == 15) ++ dsi->video_config->byte_clock = dsi->video_config->byte_clock*10; ++ else if (pdata->modes->refresh == 20) ++ dsi->video_config->byte_clock = dsi->video_config->byte_clock*9; ++ else if (pdata->modes->refresh == 25) ++ dsi->video_config->byte_clock = dsi->video_config->byte_clock*7; ++ else if (pdata->modes->refresh == 30) ++ dsi->video_config->byte_clock = dsi->video_config->byte_clock*5; ++ else if (pdata->modes->refresh == 60) ++ dsi->video_config->byte_clock = dsi->video_config->byte_clock*3; ++ } ++#endif ++ /* switch(dsi->video_config->byte_clock_coef) { ++ case MIPI_PHY_BYTE_CLK_COEF_MUL1: ++ break; ++ case MIPI_PHY_BYTE_CLK_COEF_MUL3_DIV2: ++ dsi->video_config->byte_clock = dsi->video_config->byte_clock * 3 / 2; ++ break; ++ case MIPI_PHY_BYTE_CLK_COEF_MUL4_DIV3: ++ dsi->video_config->byte_clock = dsi->video_config->byte_clock * 4 / 3; ++ break; ++ case MIPI_PHY_BYTE_CLK_COEF_MUL5_DIV4: ++ dsi->video_config->byte_clock = dsi->video_config->byte_clock * 5 / 4; ++ break; ++ case MIPI_PHY_BYTE_CLK_COEF_MUL6_DIV5: ++ dsi->video_config->byte_clock = dsi->video_config->byte_clock * 6 / 5; ++ break; ++ default: ++ break; ++ } */ ++ } ++ ++ if (dsi->video_config->byte_clock * 8 > dsi->dsi_config->max_bps * 1000) { ++ pr_err("+++++++++++++warning: DATALANE_BPS is over lcd max_bps allowed ,auto set it lcd max_bps %d\n", dsi->video_config->byte_clock); ++ //dsi->video_config->byte_clock = dsi->dsi_config->max_bps * 1000 / 8; ++ } ++ ++ /*dsi->video_config->byte_clock = dsi->video_config->pixel_clock / 4;*/ ++ ++ pr_debug("%s, %d byte_clock %d KHz, pixel_clock:%d KHz\n", __func__, __LINE__, dsi->video_config->byte_clock, dsi->video_config->pixel_clock); ++ printk("%s, %d byte_clock %d KHz, pixel_clock:%d KHz\n", __func__, __LINE__, dsi->video_config->byte_clock, dsi->video_config->pixel_clock); ++ ++ dsi->master_ops = &jz_master_ops; ++ ++ dsi->clk = clk_get(NULL, "gate_dsi"); ++ if (IS_ERR(dsi->clk)) { ++ pr_err("failed to get dsi clock source\n"); ++ goto err_put_clk; ++ } ++ clk_prepare_enable(dsi->clk); ++ ++ dsi->address = DSI_IOBASE; ++ if (!dsi->address) { ++ pr_err("Failed to ioremap register dsi memory region\n"); ++ goto err_iounmap; ++ } ++ dsi->phy_address = DSI_PHY_IOBASE; ++ if(!dsi->phy_address) { ++ pr_err("Failed to ioremap dsi phy memory region!\n"); ++ goto err_iounmap; ++ } ++ ++ ++ mutex_init(&dsi->lock); ++ ++ dsim_ddi = mipi_dsi_bind_lcd_ddi(dsi, pdata->modes->name); ++ if (!dsim_ddi) { ++ pr_err("dsi->dev: mipi_dsim_ddi object not found.\n"); ++ ret = -EINVAL; ++ goto err_bind_lcd; ++ } ++ ++ if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->probe) ++ dsim_ddi->dsim_lcd_drv->probe(dsim_ddi->dsim_lcd_dev); ++ ++ if (mipi_dsih_read_word(dsi, R_DSI_HOST_PWR_UP) & 0x1) { ++ dsi->state = UBOOT_INITIALIZED; ++ } ++ ++ if(dsi->state == UBOOT_INITIALIZED) { ++ ++ dsi->dsi_phy->status = INITIALIZED; ++ dsi->state = INITIALIZED; /*must be here for set_sequence function*/ ++ } else { ++ ++ dsi->state = NOT_INITIALIZED; /*must be here for set_sequence function*/ ++ ret = jz_mipi_update_cfg(dsi); ++ if (ret) { ++ goto err_dsi_init; ++ } ++ ++ if (dsim_ddi->dsim_lcd_drv) { ++ if (dsim_ddi->dsim_lcd_drv->power_on) ++ dsim_ddi->dsim_lcd_drv->power_on(dsim_ddi->dsim_lcd_dev, 1); ++ if (dsim_ddi->dsim_lcd_drv->set_sequence) ++ dsim_ddi->dsim_lcd_drv->set_sequence(dsim_ddi->dsim_lcd_dev); ++ }else{ ++ pr_err("lcd mipi panel init failed!\n"); ++ goto err_panel_init; ++ } ++ } ++ ++ /* jz_mipi_dsi_init_interrupt(dsi); */ ++ ++ dsi->suspended = false; ++ ++#ifdef CONFIG_DSI_DPI_DEBUG /*test pattern */ ++ unsigned int tmp = 0; ++ jz_dsi_video_cfg(dsi); ++ ++ tmp = mipi_dsih_read_word(dsi, R_DSI_HOST_VID_MODE_CFG); ++ tmp |= 1 << 16 | 0 << 20 | 1 << 24; ++ mipi_dsih_write_word(dsi, R_DSI_HOST_VID_MODE_CFG, tmp); ++#endif ++ ++ return dsi; ++err_panel_init: ++ pr_err("dsi->dev: lcd mipi panel init error\n"); ++err_dsi_init: ++ pr_err("dsi->dev: lcd mipi dsi init error\n"); ++err_bind_lcd: ++ iounmap((void __iomem *)dsi->address); ++err_iounmap: ++ clk_put(dsi->clk); ++err_put_clk: ++ kfree(dsi_phy); ++err_dsi_phy: ++ kfree(dsi); ++err_dsi: ++ return NULL; ++} ++ ++void jzdsi_remove(struct dsi_device *dsi) ++{ ++ struct dsi_phy *dsi_phy; ++ dsi_phy = dsi->dsi_phy; ++ ++ iounmap((void __iomem *)dsi->address); ++ clk_disable(dsi->clk); ++ clk_put(dsi->clk); ++ kfree(dsi_phy); ++ kfree(dsi); ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_jz_mipi_dsi_jz_mipi_dsi_lowlevel.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_jz_mipi_dsi_jz_mipi_dsi_lowlevel.c.patch new file mode 100644 index 00000000..afcd679a --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_jz_mipi_dsi_jz_mipi_dsi_lowlevel.c.patch @@ -0,0 +1,615 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v12/jz_mipi_dsi/jz_mipi_dsi_lowlevel.c b/drivers/video/fbdev/ingenic/fb_v12/jz_mipi_dsi/jz_mipi_dsi_lowlevel.c +--- a/drivers/video/fbdev/ingenic/fb_v12/jz_mipi_dsi/jz_mipi_dsi_lowlevel.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v12/jz_mipi_dsi/jz_mipi_dsi_lowlevel.c 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,611 @@ ++/* ++ * Ingenic SoC MIPI-DSI lowlevel driver. ++ * ++ * 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. ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../jz_dsim.h" ++#include "jz_mipi_dsi_regs.h" ++#include "jz_mipi_dsih_hal.h" ++ ++struct freq_ranges ranges[] = { ++ {90, 0x00, 0x01}, {100, 0x10, 0x01}, {110, 0x20, 0x01}, ++ {125, 0x01, 0x01}, {140, 0x11, 0x01}, {150, 0x21, 0x01}, ++ {160, 0x02, 0x01}, {180, 0x12, 0x03}, {200, 0x22, 0x03}, ++ {210, 0x03, 0x03}, {240, 0x13, 0x03}, {250, 0x23, 0x03}, ++ {270, 0x04, 0x07}, {300, 0x14, 0x07}, {330, 0x24, 0x07}, ++ {360, 0x15, 0x07}, {400, 0x25, 0x07}, {450, 0x06, 0x07}, ++ {500, 0x16, 0x07}, {550, 0x07, 0x0f}, {600, 0x17, 0x0f}, ++ {650, 0x08, 0x0f}, {700, 0x18, 0x0f}, {750, 0x09, 0x0f}, ++ {800, 0x19, 0x0f}, {850, 0x0A, 0x0f}, {900, 0x1A, 0x0f}, ++ {950, 0x2A, 0x0f}, {1000, 0x3A, 0x0f} ++}; ++ ++struct loop_band loop_bandwidth[] = { ++ {32, 0x06, 0x10}, {64, 0x06, 0x10}, {128, 0x0C, 0x08}, ++ {256, 0x04, 0x04}, {512, 0x00, 0x01}, {768, 0x01, 0x01}, ++ {1000, 0x02, 0x01} ++}; ++ ++void jz_dsih_dphy_reset(struct dsi_device *dsi, int reset) ++{ ++ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_PHY_RSTZ, reset, 1, 1); ++} ++ ++void jz_dsih_dphy_stop_wait_time(struct dsi_device *dsi, ++ unsigned char no_of_byte_cycles) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_PHY_IF_CFG, no_of_byte_cycles, 8, ++ 8); ++} ++ ++void jz_dsih_dphy_no_of_lanes(struct dsi_device *dsi, unsigned char no_of_lanes) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_PHY_IF_CFG, no_of_lanes - 1, 0, 2); ++} ++ ++void jz_dsih_dphy_clock_en(struct dsi_device *dsi, int en) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_PHY_RSTZ, en, 2, 1); ++} ++ ++void jz_dsih_dphy_shutdown(struct dsi_device *dsi, int powerup) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_PHY_RSTZ, powerup, 0, 1); ++} ++ ++void jz_dsih_dphy_ulpm_enter(struct dsi_device *dsi) ++{ ++ /* PHY_STATUS[6:1] == 6'h00 */ ++ if (mipi_dsih_read_part(dsi, R_DSI_HOST_PHY_STATUS, 1, 6) == 0x0) { ++ printk("MIPI D-PHY is already in ULPM state now\n"); ++ return; ++ } ++ /* PHY_RSTZ[3:0] = 4'hF */ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_PHY_RSTZ, 0xF, 0, 4); ++ /* PHY_ULPS_CTRL[3:0] = 4'h0 */ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_PHY_ULPS_CTRL, 0x0, 0, 4); ++ /* PHY_TX_TRIGGERS[3:0] = 4'h0 */ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_PHY_TX_TRIGGERS, 0x0, 0, 4); ++ /* PHY_STATUS[6:4] == 3'h3 */ ++ while (mipi_dsih_read_part(dsi, R_DSI_HOST_PHY_STATUS, 4, 3) != 0x3 || ++ mipi_dsih_read_part(dsi, R_DSI_HOST_PHY_STATUS, 0, 2) != 0x1) ++ ; ++ /* PHY_ULPS_CTRL [3:0] = 4'h5 */ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_PHY_ULPS_CTRL, 0x5, 0, 4); ++ /* LPCLK_CTRL[1:0] = 2'h2 */ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_LPCLK_CTRL, 0x2, 0, 2); ++ /* PHY_STATUS[6:0] == 7'h1 */ ++ while (mipi_dsih_read_part(dsi, R_DSI_HOST_PHY_STATUS, 0, 7) != 0x1) ++ ; ++ /* PHY_RSTZ[3] = 1'b0 */ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_PHY_RSTZ, 0x0, 3, 1); ++ /* PHY_STATUS [0] == 1'b0 */ ++ while(mipi_dsih_read_part(dsi, R_DSI_HOST_PHY_STATUS, 0, 1) != 0x0) ++ ; ++ printk("%s ...\n", __func__); ++} ++ ++void jz_dsih_dphy_ulpm_exit(struct dsi_device *dsi) ++{ ++ /* PHY_STATUS[6:1] == 6'h00 */ ++ if (mipi_dsih_read_part(dsi, R_DSI_HOST_PHY_STATUS, 1, 6) != 0x0) { ++ printk("MIPI D-PHY is not in ULPM state now\n"); ++ return; ++ } ++ /* PHY_STATUS[0] == 1'b1 */ ++ if (mipi_dsih_read_part(dsi, R_DSI_HOST_PHY_STATUS, 0, 1) == 0x1) ++ goto step5; ++ ++ /* PHY_RSTZ [3] = 1'b1 */ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_PHY_RSTZ, 0x1, 3, 1); ++ /* PHY_STATUS[0] == 1'b1 */ ++ while (mipi_dsih_read_part(dsi, R_DSI_HOST_PHY_STATUS, 0, 1) != 0x1) ++ ; ++ ++step5: ++ /* PHY_ULPS_CTRL[3:0] = 4'hF */ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_PHY_ULPS_CTRL, 0xF, 0, 4); ++ /* PHY_STATUS [5] == 1'b1 && PHY_STATUS [3] == 1'b1 */ ++ while(mipi_dsih_read_part(dsi, R_DSI_HOST_PHY_STATUS, 5, 1) != 0x1 || ++ mipi_dsih_read_part(dsi, R_DSI_HOST_PHY_STATUS, 3, 1) != 0x1) ++ ; ++ /* Wait for 1 ms */ ++ mdelay(1); ++ /* PHY_ULPS_CTRL [3:0] = 4'h0 */ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_PHY_ULPS_CTRL, 0x0, 0, 4); ++ /* LPCLK_CTRL[1:0] = 2'h1 */ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_LPCLK_CTRL, 0x1, 0, 2); ++ /* PHY_STATUS [6:4] == 3'h3 && PHY_STATUS [1:0] == 2'h1 */ ++ while (mipi_dsih_read_part(dsi, R_DSI_HOST_PHY_STATUS, 4, 3) != 0x3 || ++ mipi_dsih_read_part(dsi, R_DSI_HOST_PHY_STATUS, 0, 2) != 0x1) ++ ; ++ /* PHY_RSTZ [3] = 1'b0 */ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_PHY_RSTZ, 0x0, 3, 1); ++ printk("%s ...\n", __func__); ++} ++ ++void jz_dsih_hal_power(struct dsi_device *dsi, int on) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_PWR_UP, on, 0, 1); ++} ++ ++int jz_dsi_init_config(struct dsi_device *dsi) ++{ ++ struct dsi_config *dsi_config; ++ dsih_error_t err = OK; ++ ++ dsi_config = dsi->dsi_config; ++ ++ mipi_dsih_hal_dpi_color_mode_pol(dsi, !dsi_config->color_mode_polarity); ++ mipi_dsih_hal_dpi_shut_down_pol(dsi, !dsi_config->shut_down_polarity); ++ ++ err = mipi_dsih_phy_hs2lp_config(dsi, dsi_config->max_hs_to_lp_cycles); ++ err |= mipi_dsih_phy_lp2hs_config(dsi, dsi_config->max_lp_to_hs_cycles); ++ err |= mipi_dsih_phy_bta_time(dsi, dsi_config->max_bta_cycles); ++ if (err) { ++ return err; ++ } ++ ++ mipi_dsih_hal_dpi_lp_during_hfp(dsi, 1); ++ mipi_dsih_hal_dpi_lp_during_hbp(dsi, 1); ++ ++ mipi_dsih_hal_dpi_lp_during_vactive(dsi, 1); ++ mipi_dsih_hal_dpi_lp_during_vfp(dsi, 1); ++ mipi_dsih_hal_dpi_lp_during_vbp(dsi, 1); ++ mipi_dsih_hal_dpi_lp_during_vsync(dsi, 1); ++ mipi_dsih_hal_dcs_wr_tx_type(dsi, 0, 1); ++ mipi_dsih_hal_dcs_wr_tx_type(dsi, 1, 1); ++ mipi_dsih_hal_dcs_wr_tx_type(dsi, 3, 1); /* long packet */ ++ mipi_dsih_hal_dcs_rd_tx_type(dsi, 0, 1); ++ ++ mipi_dsih_hal_gen_wr_tx_type(dsi, 0, 1); ++ mipi_dsih_hal_gen_wr_tx_type(dsi, 1, 1); ++ mipi_dsih_hal_gen_wr_tx_type(dsi, 2, 1); ++ mipi_dsih_hal_gen_wr_tx_type(dsi, 3, 1); /* long packet */ ++ mipi_dsih_hal_gen_rd_tx_type(dsi, 0, 1); ++ mipi_dsih_hal_gen_rd_tx_type(dsi, 1, 1); ++ mipi_dsih_hal_gen_rd_tx_type(dsi, 2, 1); ++ mipi_dsih_hal_gen_rd_vc(dsi, 0); ++ mipi_dsih_hal_gen_eotp_rx_en(dsi, 0); ++ mipi_dsih_hal_gen_eotp_tx_en(dsi, 0); ++ mipi_dsih_hal_bta_en(dsi, 0); ++ mipi_dsih_hal_gen_ecc_rx_en(dsi, 0); ++ mipi_dsih_hal_gen_crc_rx_en(dsi, 0); ++ return OK; ++} ++ ++dsih_error_t jz_init_dsi(struct dsi_device * dsi) ++{ ++ ++ dsih_error_t err = OK; ++ if (dsi->state == INITIALIZED) { ++ return ERR_DSI_INVALID_INSTANCE; ++ } else { ++ jz_dsih_hal_power(dsi, 0); ++ jz_dsih_hal_power(dsi, 1); ++ err = jz_dsi_init_config(dsi); ++ if (err) { ++ return err; ++ } ++ jz_dsih_hal_power(dsi, 0); ++ jz_dsih_hal_power(dsi, 1); ++ ++ } ++ ++ return err; ++} ++ ++static irqreturn_t ingenicfb_irq_handler(int irq, void *data) ++{ ++ unsigned int irq_flag; ++ struct dsi_device *dsi = (struct dsi_device *)data; ++ ++ spin_lock(&dsi->irq_lock); ++ ++ irq_flag = mipi_dsih_read_word(dsi, R_DSI_HOST_INT_ST1); ++ ++ if(likely(irq_flag & (1 << 6))) { ++ printk("\033[31m(l:%d, f:%s, F: %s) %d %s\033[0m\n", __LINE__, __func__, __FILE__, 0, ""); ++ } ++ ++ spin_unlock(&dsi->irq_lock); ++ return IRQ_HANDLED; ++} ++ ++void dsi_irq_test(struct dsi_device *dsi) ++{ ++ mipi_dsih_write_word(dsi, R_DSI_HOST_INT_FORCE1, 1 << 6); ++} ++ ++void jz_mipi_dsi_init_interrupt(struct dsi_device *dsi) ++{ ++ /* fiexed */ ++ struct device *dev = &dsi->dsim_lcd_dev->dev; ++ ++ spin_lock_init(&dsi->irq_lock); ++ ++ mipi_dsih_write_word(dsi, R_DSI_HOST_INT_MSK0, 0x3fffff); ++ mipi_dsih_write_word(dsi, R_DSI_HOST_INT_MSK1, 0xfff); ++ ++ if (devm_request_irq(dev, 18, ingenicfb_irq_handler, 0, ++ "mipidsi", dsi)) { ++ dev_err(dev, "request dsi irq failed\n"); ++ } ++} ++ ++int jz_dsi_video_coding(struct dsi_device *dsi, ++ unsigned short *bytes_per_pixel_x100, ++ unsigned char *video_size_step, ++ unsigned short *video_size) ++{ ++ struct video_config *video_config; ++ dsih_error_t err_code = OK; ++ video_config = dsi->video_config; ++ ++ switch (video_config->color_coding) { ++ case COLOR_CODE_16BIT_CONFIG1: ++ case COLOR_CODE_16BIT_CONFIG2: ++ case COLOR_CODE_16BIT_CONFIG3: ++ *bytes_per_pixel_x100 = 200; ++ *video_size_step = 1; ++ break; ++ case COLOR_CODE_18BIT_CONFIG1: ++ case COLOR_CODE_18BIT_CONFIG2: ++ mipi_dsih_hal_dpi_18_loosely_packet_en(dsi, ++ video_config-> ++ is_18_loosely); ++ *bytes_per_pixel_x100 = 225; ++ if (!video_config->is_18_loosely) { // 18bits per pixel and NOT loosely, packets should be multiples of 4 ++ *video_size_step = 4; ++ //round up active H pixels to a multiple of 4 ++ for (; ((*video_size) % 4) != 0; (*video_size)++) { ++ ; ++ } ++ } else { ++ *video_size_step = 1; ++ } ++ break; ++ case COLOR_CODE_24BIT: ++ *bytes_per_pixel_x100 = 300; //burst mode ++ *video_size_step = 1; //no burst mode ++ break; ++ default: ++ printk("invalid color coding\n"); ++ err_code = ERR_DSI_COLOR_CODING; ++ break; ++ } ++ if (err_code == OK) { ++ pr_debug("video_config->color_coding:%d\n", ++ video_config->color_coding); ++ err_code = ++ mipi_dsih_hal_dpi_color_coding(dsi, ++ video_config->color_coding); ++ } ++ if (err_code != OK) { ++ return err_code; ++ } ++ return 0; ++ ++} ++ ++void jz_dsi_dpi_cfg(struct dsi_device *dsi, unsigned int *ratio_clock_xPF, ++ unsigned short *bytes_per_pixel_x100) ++{ ++ struct video_config *video_config; ++ unsigned int hs_timeout = 0; ++ int counter = 0; ++ ++ video_config = dsi->video_config; ++ mipi_dsih_hal_dpi_video_mode_type(dsi, video_config->video_mode); ++ ++ /*HSA+HBP+HACT+HFP * 1 */ ++ mipi_dsih_hal_dpi_hline(dsi, ++ (unsigned ++ short)((video_config->h_total_pixels * ++ (*ratio_clock_xPF)) / ++ PRECISION_FACTOR)); ++ mipi_dsih_hal_dpi_hbp(dsi, ++ ((video_config->h_back_porch_pixels * ++ (*ratio_clock_xPF)) / PRECISION_FACTOR)); ++ mipi_dsih_hal_dpi_hsa(dsi, ++ ((video_config->h_sync_pixels * ++ (*ratio_clock_xPF)) / PRECISION_FACTOR)); ++ mipi_dsih_hal_dpi_vactive(dsi, video_config->v_active_lines); ++ mipi_dsih_hal_dpi_vfp(dsi, ++ video_config->v_total_lines - ++ (video_config->v_back_porch_lines + ++ video_config->v_sync_lines + ++ video_config->v_active_lines)); ++ mipi_dsih_hal_dpi_vbp(dsi, video_config->v_back_porch_lines); ++ mipi_dsih_hal_dpi_vsync(dsi, video_config->v_sync_lines); ++ ++#ifdef CONFIG_DSI_DPI_DEBUG ++ printk("hline:%d\n", ++ (unsigned ++ short)((video_config->h_total_pixels * (*ratio_clock_xPF)) / ++ PRECISION_FACTOR)); ++ printk("hbp:%d\n", ++ ((video_config->h_back_porch_pixels * (*ratio_clock_xPF)) / ++ PRECISION_FACTOR)); ++ printk("hsa:%d\n", ++ ((video_config->h_sync_pixels * (*ratio_clock_xPF)) / ++ PRECISION_FACTOR)); ++ printk("vactive:%d\n", video_config->v_active_lines); ++ printk("vfp:%d\n", ++ video_config->v_total_lines - (video_config->v_back_porch_lines + ++ video_config->v_sync_lines + ++ video_config->v_active_lines)); ++ printk("vbp:%d\n", video_config->v_back_porch_lines); ++ printk("vsync:%d\n", video_config->v_sync_lines); ++#endif ++ ++ mipi_dsih_hal_dpi_hsync_pol(dsi, !video_config->h_polarity); //active low ++ mipi_dsih_hal_dpi_vsync_pol(dsi, !video_config->v_polarity); //active low ++ mipi_dsih_hal_dpi_dataen_pol(dsi, !video_config->data_en_polarity); // active high ++ // HS timeout timing ++ hs_timeout = ++ ((video_config->h_total_pixels * video_config->v_active_lines) + ++ (DSIH_PIXEL_TOLERANCE * (*bytes_per_pixel_x100)) / 100); ++ for (counter = 0x80; (counter < hs_timeout) && (counter > 2); counter--) { ++ if ((hs_timeout % counter) == 0) { ++ mipi_dsih_hal_timeout_clock_division(dsi, counter); ++ mipi_dsih_hal_lp_rx_timeout(dsi, ++ (unsigned short)(hs_timeout ++ / ++ counter)); ++ mipi_dsih_hal_hs_tx_timeout(dsi, ++ (unsigned short)(hs_timeout ++ / ++ counter)); ++ break; ++ } ++ } ++ ++} ++ ++void jz_dsih_hal_tx_escape_division(struct dsi_device *dsi, ++ unsigned char tx_escape_division) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_CLKMGR_CFG, tx_escape_division, 0, ++ 8); ++} ++ ++dsih_error_t jz_dsih_dphy_configure(struct dsi_device *dsi, ++ unsigned char no_of_lanes, ++ unsigned int output_freq) ++{ ++ unsigned int loop_divider = 0; /* (M) */ ++ unsigned int input_divider = 1; /* (N) */ ++ unsigned char data[4]; /* maximum data for now are 4 bytes per test mode */ ++ unsigned char no_of_bytes = 0; ++ unsigned char i = 0; /* iterator */ ++ unsigned char range = 0; /* ranges iterator */ ++ int flag = 0; ++ struct dsi_phy *phy; ++ phy = dsi->dsi_phy; ++ printk("entry function :%s\n", __func__); ++ if (phy == NULL) { ++ return ERR_DSI_INVALID_INSTANCE; ++ } ++ if (phy->status == NOT_INITIALIZED) { ++ return ERR_DSI_INVALID_INSTANCE; ++ } ++ if (output_freq < MIN_OUTPUT_FREQ) { ++ return ERR_DSI_PHY_FREQ_OUT_OF_BOUND; ++ } ++ /* find M and N dividers */ ++ /* M :loop_divider, N: input_divider */ ++ for (input_divider = 1 + (phy->reference_freq / DPHY_DIV_UPPER_LIMIT); ((phy->reference_freq / input_divider) >= DPHY_DIV_LOWER_LIMIT) && (!flag); input_divider++) { /* here the >= DPHY_DIV_LOWER_LIMIT is a phy constraint, formula should be above 1 MHz */ ++ if (((output_freq * input_divider) % (phy->reference_freq)) == 0) { /*found the input_divider we want, but how can we be sure, ++ * for example ,now output_freq is 90000 , that's 90MHZ. ++ * if (90000 * input_divider) % fref == 0, and fref = 27000, ++ * then input_divider = 3; ++ * then loop_divider = 90000 * 3 / 27000 = 10; ++ * if input_divider = 6, then loop_divider is 20; flag = 1 exit loop. ++ */ ++ /* values found */ ++ loop_divider = ++ ((output_freq * input_divider) / ++ (phy->reference_freq)); ++ if (loop_divider >= 12) { ++ flag = 1; ++ } ++ } ++ } ++ ++ if ((!flag) ++ || ((phy->reference_freq / input_divider) < DPHY_DIV_LOWER_LIMIT)) { ++ /* no exact value found in previous for loop */ ++ /* this solution is not favourable as jitter would be maximum */ ++ loop_divider = output_freq / DPHY_DIV_LOWER_LIMIT; ++ input_divider = phy->reference_freq / DPHY_DIV_LOWER_LIMIT; ++ //make sure M is not overflowed,M mask 9 bits ++ if(loop_divider > 511){ ++ loop_divider = output_freq / (DPHY_DIV_LOWER_LIMIT * 2); ++ input_divider = phy->reference_freq / (DPHY_DIV_LOWER_LIMIT * 2); ++ } ++ } else { /* variable was incremented before exiting the loop */ ++ /* ++ * input_divider is 6 now, ++ * */ ++ input_divider--; ++ /* now is 5. ++ * loop_divider is still 20. ++ * */ ++ } ++ for (i = 0; (i < (sizeof(loop_bandwidth) / sizeof(loop_bandwidth[0]))) ++ && (loop_divider > loop_bandwidth[i].loop_div); i++) { ++ ; ++ } ++ /* i = 0; ++ * */ ++ if (i >= (sizeof(loop_bandwidth) / sizeof(loop_bandwidth[0]))) { ++ return ERR_DSI_PHY_FREQ_OUT_OF_BOUND; ++ } ++ /* get the PHY in power down mode (shutdownz=0) and reset it (rstz=0) to ++ avoid transient periods in PHY operation during re-configuration procedures. */ ++ jz_dsih_dphy_reset(dsi, 0); ++ jz_dsih_dphy_clock_en(dsi, 0); ++ jz_dsih_dphy_shutdown(dsi, 0); ++ /* provide an initial active-high test clear pulse in TESTCLR */ ++ //performs vendor-specific interface initialization ++ mipi_dsih_dphy_test_clear(dsi, 1); ++ mipi_dsih_dphy_test_clear(dsi, 0); ++ /* find ranges */ ++ for (range = 0; (range < (sizeof(ranges) / sizeof(ranges[0]))) ++ && ((output_freq / 1000) > ranges[range].freq); range++) { ++ ; ++ } ++ if (range >= (sizeof(ranges) / sizeof(ranges[0]))) { ++ return ERR_DSI_PHY_FREQ_OUT_OF_BOUND; ++ } ++ /* set up board depending on environment if any */ ++ if (phy->bsp_pre_config != 0) { ++ /*set master-phy output direction */ ++ phy->bsp_pre_config(dsi, 0); ++ } ++ /* setup digital part */ ++ /* hs frequency range [7]|[6:1]|[0] */ ++ data[0] = (0 << 7) | (ranges[range].hs_freq << 1) | 0; ++ mipi_dsih_dphy_write(dsi, 0x44, data, 1); ++ /* setup PLL */ ++ /* vco range [7]|[6:3]|[2:1]|[0] */ ++ data[0] = (1 << 7) | (ranges[range].vco_range << 3) | (0 << 1) | 0; ++ mipi_dsih_dphy_write(dsi, 0x10, data, 1); ++ /* PLL reserved|Input divider control|Loop Divider Control|Post Divider Ratio [7:6]|[5]|[4]|[3:0] */ ++ data[0] = (0x00 << 6) | (0x01 << 5) | (0x01 << 4) | (0x03 << 0); /* post divider default = 0x03 - it is only used for clock out 2 */ ++ ++ /* PLL post divider ratio and PLL input and divider ratios control */ ++ mipi_dsih_dphy_write(dsi, 0x19, data, 1); ++ /* PLL Lock bypass|charge pump current [7:4]|[3:0] */ ++ data[0] = (0x00 << 4) | (loop_bandwidth[i].cp_current << 0); ++ ++ /* PLL CP control , PLL lock bypass for initialization and for ULP mode */ ++ mipi_dsih_dphy_write(dsi, 0x11, data, 1); ++ /* bypass CP default|bypass LPF default| LPF resistor [7]|[6]|[5:0] */ ++ data[0] = ++ (0x01 << 7) | (0x01 << 6) | (loop_bandwidth[i].lpf_resistor << 0); ++ mipi_dsih_dphy_write(dsi, 0x12, data, 1); ++ /* PLL input divider ratio [7:0] */ ++ data[0] = input_divider - 1; ++ ++ /*PLL input divider ratio */ ++ mipi_dsih_dphy_write(dsi, 0x17, data, 1); ++ no_of_bytes = 2; /* pll loop divider (code 0x18) takes only 2 bytes (10 bits in data) */ ++ for (i = 0; i < no_of_bytes; i++) { ++ data[i] = ++ ((unsigned char)((((loop_divider - 1) >> (5 * i)) & 0x1F) | ++ (i << 7))); ++ /* 7 is dependent on no_of_bytes ++ make sure 5 bits only of value are written at a time */ ++ } ++ /* *******PLL loop divider ratio - SET no|reserved|feedback divider [7]|[6:5]|[4:0] */ ++ mipi_dsih_dphy_write(dsi, 0x18, data, no_of_bytes); ++ ++ /*now recover the phy state as it before */ ++ jz_dsih_dphy_no_of_lanes(dsi, no_of_lanes); ++ jz_dsih_dphy_stop_wait_time(dsi, 0x1C); ++ jz_dsih_dphy_clock_en(dsi, 1); ++ jz_dsih_dphy_shutdown(dsi, 1); ++ jz_dsih_dphy_reset(dsi, 1); ++ pr_info("configure master-phy is ok\n"); ++ return OK; ++} ++ ++struct dphy_pll_range { ++ unsigned int start_clk_sel; ++ unsigned int output_freq0; /*start freq in same resolution*/ ++ unsigned int output_freq1; /*end freq in same resolution*/ ++ unsigned int resolution; ++}; ++ ++struct dphy_pll_range dphy_pll_table[] = { ++ /* {0, 63750000, 93125000, 312500}, */ ++ /* {95, 93750000, 186250000, 625000}, */ ++ /* {244, 187500000, 372500000, 1250000}, */ ++ /* {393, 375000000, 745000000, 2500000}, */ ++ /* {542, 750000000, 2750000000UL, 5000000}, */ ++ {0x7f, 80000000, 300000000, 0}, ++ {0x7e, 300000000, 400000000, 0}, ++ {0x7c, 400000000, 500000000, 0}, ++ {0x70, 500000000, 600000000, 0}, ++ {0x40, 600000000, 700000000, 0}, ++ {0x02, 700000000, 800000000, 0}, ++ {0x08, 800000000, 1000000000UL, 0}, ++ {0x03, 1000000000UL, 1400000000UL, 0}, ++ {0x42, 1400000000UL, 1600000000UL, 0}, ++ {0x47, 1600000000UL, 1800000000UL, 0}, ++ {0x64, 1800000000UL, 2200000000UL, 0}, ++ {0x33, 2200000000UL, 2400000000UL, 0}, ++ {0x54, 2400000000UL, 2500000000UL, 0}, ++}; ++ ++dsih_error_t jz_dsih_dphy_configure_t40(struct dsi_device *dsi, ++ unsigned char no_of_lanes, ++ unsigned int output_freq) ++{ ++ int i; ++ struct dphy_pll_range *pll; ++ unsigned int pll_clk_sel = 0xffffffff; ++ for(i = 0; i < ARRAY_SIZE(dphy_pll_table); i++) { ++ pll = &dphy_pll_table[i]; ++ if(output_freq >= pll->output_freq0 && output_freq <= pll->output_freq1) { ++ /* pll_clk_sel = pll->start_clk_sel + (output_freq - pll->output_freq0) / pll->resolution; */ ++ pll_clk_sel = pll->start_clk_sel; ++ break; ++ } ++ } ++ if(pll_clk_sel == 0xffffffff) { ++ printk("can not find appropriate pll freq set for dsi phy! output_freq: %d\n", output_freq); ++ return ERR_DSI_PHY_FREQ_OUT_OF_BOUND; ++ } ++ ++ printk("before setting dsi phy: pll_clk_sel: 0x%x, set_pll_clk_sel: 0x%x\n", readl(dsi->phy_address + 0x64), pll_clk_sel); ++ writel(pll_clk_sel, (unsigned int *)(dsi->phy_address + 0x64)); ++ printk("after setting dsi phy: pll_clk_sel: 0x%x, output_freq: %d\n", readl(dsi->phy_address + 0x64), output_freq); ++ ++ return OK; ++} ++ ++dsih_error_t jz_dsi_set_clock(struct dsi_device * dsi) ++{ ++#if 0 ++ dsih_error_t err = OK; ++ /* TODO: configure M31 phy PLL */ ++ err = ++ jz_dsih_dphy_configure(dsi, dsi->video_config->no_of_lanes, ++ dsi->video_config->byte_clock * 8); ++ if (err) { ++ return err; /* ERR_DSI_PHY_POWERUP; */ ++ } ++#endif ++ ++ jz_dsih_dphy_configure_t40(dsi, dsi->video_config->no_of_lanes, ++ dsi->video_config->byte_clock * 1000 * 8); ++ ++ ++ jz_dsih_dphy_stop_wait_time(dsi, 0x1C); ++ jz_dsih_dphy_clock_en(dsi, 1); ++ jz_dsih_dphy_shutdown(dsi, 1); ++ jz_dsih_dphy_reset(dsi, 1); ++ printk("configure master-phy is ok\n"); ++ jz_dsih_hal_tx_escape_division(dsi, TX_ESC_CLK_DIV); ++ return OK; ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_jz_mipi_dsi_jz_mipi_dsi_lowlevel.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_jz_mipi_dsi_jz_mipi_dsi_lowlevel.h.patch new file mode 100644 index 00000000..dd8ab664 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_jz_mipi_dsi_jz_mipi_dsi_lowlevel.h.patch @@ -0,0 +1,33 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v12/jz_mipi_dsi/jz_mipi_dsi_lowlevel.h b/drivers/video/fbdev/ingenic/fb_v12/jz_mipi_dsi/jz_mipi_dsi_lowlevel.h +--- a/drivers/video/fbdev/ingenic/fb_v12/jz_mipi_dsi/jz_mipi_dsi_lowlevel.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v12/jz_mipi_dsi/jz_mipi_dsi_lowlevel.h 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,29 @@ ++/* ++ * 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. ++*/ ++ ++#ifndef _JZ_MIPI_DSI_LOWLEVEL_H ++#define _JZ_MIPI_DSI_LOWLEVEL_H ++ ++ ++void jz_dsih_dphy_reset(struct dsi_device *dsi, int reset); ++ ++void jz_dsih_dphy_stop_wait_time(struct dsi_device *dsi, unsigned char no_of_byte_cycles); ++ ++void jz_dsih_dphy_no_of_lanes(struct dsi_device * dsi, unsigned char no_of_lanes); ++void jz_dsih_dphy_clock_en(struct dsi_device *dsi, int en); ++void jz_dsih_dphy_shutdown(struct dsi_device *dsi, int powerup); ++void jz_dsih_hal_power(struct dsi_device *dsi, int on); ++int jz_dsi_init_config(struct dsi_device *dsi); ++int jz_init_dsi(struct dsi_device *dsi); ++int jz_dsi_set_clock(struct dsi_device *dsi); ++void jz_mipi_dsi_init_interrupt(struct dsi_device *dsi); ++int jz_dsi_video_coding(struct dsi_device *dsi, unsigned short *bytes_per_pixel_x100, unsigned char *video_size_step, unsigned short *video_size); ++void jz_dsi_dpi_cfg(struct dsi_device *dsi, unsigned int *ratio_clock_xPF, unsigned short *bytes_per_pixel_x100); ++void jz_dsih_hal_tx_escape_division(struct dsi_device * dsi, unsigned char tx_escape_division); ++dsih_error_t jz_dsih_dphy_configure(struct dsi_device *dsi, unsigned char no_of_lanes, unsigned int output_freq); ++void jz_dsih_dphy_ulpm_enter(struct dsi_device *dsi); ++void jz_dsih_dphy_ulpm_exit(struct dsi_device *dsi); ++#endif /* _JZ_MIPI_DSI_LOWLEVEL_H */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_jz_mipi_dsi_jz_mipi_dsi_regs.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_jz_mipi_dsi_jz_mipi_dsi_regs.h.patch new file mode 100644 index 00000000..066258aa --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_jz_mipi_dsi_jz_mipi_dsi_regs.h.patch @@ -0,0 +1,83 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v12/jz_mipi_dsi/jz_mipi_dsi_regs.h b/drivers/video/fbdev/ingenic/fb_v12/jz_mipi_dsi/jz_mipi_dsi_regs.h +--- a/drivers/video/fbdev/ingenic/fb_v12/jz_mipi_dsi/jz_mipi_dsi_regs.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v12/jz_mipi_dsi/jz_mipi_dsi_regs.h 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,79 @@ ++/* ++ * 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. ++*/ ++ ++#ifndef _JZ_MIPI_DSI_REGS_H ++#define _JZ_MIPI_DSI_REGS_H ++ ++#define R_DSI_HOST_VERSION 0x000 ++#define R_DSI_HOST_PWR_UP 0x004 ++#define R_DSI_HOST_CLKMGR_CFG 0x008 ++#define R_DSI_HOST_DPI_VCID 0x00c ++#define R_DSI_HOST_DPI_COLOR_CODING 0x010 ++#define R_DSI_HOST_DPI_CFG_POL 0x014 ++#define R_DSI_HOST_DPI_LP_CMD_TIM 0x018 ++#define R_DSI_HOST_DBI_VCID 0x01c ++#define R_DSI_HOST_DBI_CFG 0x020 ++#define R_DSI_HOST_DBI_PARTITIONING_EN 0x024 ++#define R_DSI_HOST_DBI_CMDSIZE 0x028 ++#define R_DSI_HOST_PCKHDL_CFG 0x02c ++#define R_DSI_HOST_GEN_VCID 0x030 ++#define R_DSI_HOST_MODE_CFG 0x034 ++#define R_DSI_HOST_VID_MODE_CFG 0x038 ++#define R_DSI_HOST_VID_PKT_SIZE 0x03c ++#define R_DSI_HOST_VID_NUM_CHUNKS 0x040 ++#define R_DSI_HOST_VID_NULL_SIZE 0x044 ++#define R_DSI_HOST_VID_HSA_TIME 0x048 ++#define R_DSI_HOST_VID_HBP_TIME 0x04c ++#define R_DSI_HOST_VID_HLINE_TIME 0x050 ++#define R_DSI_HOST_VID_VSA_LINES 0x054 ++#define R_DSI_HOST_VID_VBP_LINES 0x058 ++#define R_DSI_HOST_VID_VFP_LINES 0x05c ++#define R_DSI_HOST_VID_VACTIVE_LINES 0x060 ++#define R_DSI_HOST_EDPI_CMD_SIZE 0x064 ++#define R_DSI_HOST_CMD_MODE_CFG 0x068 ++#define R_DSI_HOST_GEN_HDR 0x06c ++#define R_DSI_HOST_GEN_PLD_DATA 0x070 ++#define R_DSI_HOST_CMD_PKT_STATUS 0x074 ++#define R_DSI_HOST_TO_CNT_CFG 0x078 ++#define R_DSI_HOST_HS_RD_TO_CNT 0x07c ++#define R_DSI_HOST_LP_RD_TO_CNT 0x080 ++#define R_DSI_HOST_HS_WR_TO_CNT 0x084 ++#define R_DSI_HOST_LP_WR_TO_CNT 0x088 ++#define R_DSI_HOST_BTA_TO_CNT 0x08c ++#define R_DSI_HOST_SDF_3D 0x090 ++#define R_DSI_HOST_LPCLK_CTRL 0x094 ++#define R_DSI_HOST_PHY_TMR_LPCLK_CFG 0x098 ++#define R_DSI_HOST_PHY_TMR_CFG 0x09c ++#define R_DSI_HOST_PHY_RSTZ 0x0a0 ++#define R_DSI_HOST_PHY_IF_CFG 0x0a4 ++#define R_DSI_HOST_PHY_ULPS_CTRL 0x0a8 ++#define R_DSI_HOST_PHY_TX_TRIGGERS 0x0ac ++#define R_DSI_HOST_PHY_STATUS 0x0b0 ++#define R_DSI_HOST_PHY_TST_CTRL0 0x0b4 ++#define R_DSI_HOST_PHY_TST_CTRL1 0x0b8 ++#define R_DSI_HOST_INT_ST0 0x0bC ++#define R_DSI_HOST_INT_ST1 0x0C0 ++#define R_DSI_HOST_INT_MSK0 0x0C4 ++#define R_DSI_HOST_INT_MSK1 0x0C8 ++#define R_DSI_HOST_INT_FORCE0 0x0D8 ++#define R_DSI_HOST_INT_FORCE1 0x0DC ++#define R_DSI_HOST_VID_SHADOW_CTRL 0x100 ++#define R_DSI_HOST_DPI_VCID_ACT 0x10C ++#define R_DSI_HOST_DPI_COLOR_CODING_ACT 0x110 ++#define R_DSI_HOST_DPI_LP_CMD_TIM_ACT 0x118 ++#define R_DSI_HOST_VID_MODE_CFG_ACT 0x138 ++#define R_DSI_HOST_VID_PKT_SIZE_ACT 0x13C ++#define R_DSI_HOST_VID_NUM_CHUNKS_ACT 0x140 ++#define R_DSI_HOST_VID_NULL_SIZE_ACT 0x144 ++#define R_DSI_HOST_VID_HSA_TIME_ACT 0x148 ++#define R_DSI_HOST_VID_HBP_TIME_ACT 0x14C ++#define R_DSI_HOST_VID_HLINE_TIME_ACT 0x150 ++#define R_DSI_HOST_VID_VSA_LINES_ACT 0x154 ++#define R_DSI_HOST_VID_VBP_LINES_ACT 0x158 ++#define R_DSI_HOST_VID_VFP_LINES_ACT 0x15C ++#define R_DSI_HOST_VID_VACTIVE_LINES_ACT 0x160 ++#define R_DSI_HOST_SDF_3D_ACT 0x190 ++#endif /* _JZ_MIPI_DSI_REGS_H */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_jz_mipi_dsi_jz_mipi_dsih_hal.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_jz_mipi_dsi_jz_mipi_dsih_hal.c.patch new file mode 100644 index 00000000..e0bbf3a5 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_jz_mipi_dsi_jz_mipi_dsih_hal.c.patch @@ -0,0 +1,1287 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v12/jz_mipi_dsi/jz_mipi_dsih_hal.c b/drivers/video/fbdev/ingenic/fb_v12/jz_mipi_dsi/jz_mipi_dsih_hal.c +--- a/drivers/video/fbdev/ingenic/fb_v12/jz_mipi_dsi/jz_mipi_dsih_hal.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v12/jz_mipi_dsi/jz_mipi_dsih_hal.c 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,1283 @@ ++/* ++ * Ingenic SoC MIPI-DSI hal driver. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of thVe GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++*/ ++#include "jz_mipi_dsih_hal.h" ++#include "jz_mipi_dsi_regs.h" ++#include ++/** ++ * Write a 32-bit word to the DSI Host core ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param reg_address register offset in core ++ * @param data 32-bit word to be written to register ++ */ ++void mipi_dsih_write_word(struct dsi_device * dsi, unsigned int reg_address, unsigned int data) ++{ ++ writel(data, (volatile unsigned int *)(dsi->address + reg_address)); ++} ++/** ++ * Write a bit field o a 32-bit word to the DSI Host core ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param reg_address register offset in core ++ * @param data to be written to register ++ * @param shift bit shift from the left (system is BIG ENDIAN) ++ * @param width of bit field ++ */ ++void mipi_dsih_write_part(struct dsi_device * dsi, unsigned int reg_address, unsigned int data, unsigned char shift, unsigned char width) ++{ ++ unsigned int mask = (1 << width) - 1; ++ unsigned int temp = mipi_dsih_read_word(dsi, reg_address); ++ ++ temp &= ~(mask << shift); ++ temp |= (data & mask) << shift; ++ mipi_dsih_write_word(dsi, reg_address, temp); ++} ++/** ++ * Write a 32-bit word to the DSI Host core ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param reg_address offset of register ++ * @return 32-bit word value stored in register ++ */ ++unsigned int mipi_dsih_read_word(struct dsi_device * dsi, unsigned int reg_address) ++{ ++ return readl((volatile unsigned int *)(dsi->address + reg_address)); ++} ++/** ++ * Write a 32-bit word to the DSI Host core ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param reg_address offset of register in core ++ * @param shift bit shift from the left (system is BIG ENDIAN) ++ * @param width of bit field ++ * @return bit field read from register ++ */ ++unsigned int mipi_dsih_read_part(struct dsi_device * dsi, unsigned int reg_address, unsigned char shift, unsigned char width) ++{ ++ return (mipi_dsih_read_word(dsi, reg_address) >> shift) & ((1 << width) - 1); ++} ++/** ++ * Get DSI Host core version ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @return ascii number of the version ++ */ ++unsigned int mipi_dsih_hal_get_version(struct dsi_device * dsi) ++{ ++ return mipi_dsih_read_word(dsi, R_DSI_HOST_VERSION); ++} ++/** ++ * Modify power status of DSI Host core ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param on (1) or off (0) ++ */ ++void mipi_dsih_hal_power(struct dsi_device * dsi, int on) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_PWR_UP, on, 0, 1); ++} ++/** ++ * Get the power status of the DSI Host core ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @return power status ++ */ ++int mipi_dsih_hal_get_power(struct dsi_device * dsi) ++{ ++ return (int)(mipi_dsih_read_word(dsi, R_DSI_HOST_PWR_UP)); ++} ++/** ++ * Write transmission escape timeout ++ * a safe guard so that the state machine would reset if transmission ++ * takes too long ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param tx_escape_division ++ */ ++void mipi_dsih_hal_tx_escape_division(struct dsi_device * dsi, unsigned char tx_escape_division) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_CLKMGR_CFG, tx_escape_division, 0, 8); ++} ++/** ++ * Write the DPI video virtual channel destination ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param vc virtual channel ++ */ ++void mipi_dsih_hal_dpi_video_vc(struct dsi_device * dsi, unsigned char vc) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_DPI_VCID, (unsigned int)(vc), 0, 2); ++} ++/** ++ * Get the DPI video virtual channel destination ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @return virtual channel ++ */ ++unsigned char mipi_dsih_hal_dpi_get_video_vc(struct dsi_device * dsi) ++{ ++ return mipi_dsih_read_part(dsi, R_DSI_HOST_DPI_VCID, 0, 2); ++} ++/** ++ * Set DPI video color coding ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param color_coding enum (configuration and color depth) ++ * @return error code ++ */ ++dsih_error_t mipi_dsih_hal_dpi_color_coding(struct dsi_device * dsi, dsih_color_coding_t color_coding) ++{ ++ dsih_error_t err = OK; ++ if (color_coding > 7) ++ { ++ { ++ printk("invalid colour configuration"); ++ } ++ err = ERR_DSI_COLOR_CODING; ++ } ++ else ++ { ++ mipi_dsih_write_part(dsi, R_DSI_HOST_DPI_COLOR_CODING, color_coding, 0, 4); ++ } ++ return err; ++} ++/** ++ * Get DPI video color coding ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @return color coding enum (configuration and color depth) ++ */ ++dsih_color_coding_t mipi_dsih_hal_dpi_get_color_coding(struct dsi_device * dsi) ++{ ++ return (dsih_color_coding_t)(mipi_dsih_read_part(dsi, R_DSI_HOST_DPI_COLOR_CODING, 0, 4)); ++} ++/** ++ * Get DPI video color depth ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @return number of bits per pixel ++ */ ++unsigned char mipi_dsih_hal_dpi_get_color_depth(struct dsi_device * dsi) ++{ ++ unsigned char color_depth = 0; ++ switch (mipi_dsih_read_part(dsi, R_DSI_HOST_DPI_COLOR_CODING, 0, 4)) ++ { ++ case 0: ++ case 1: ++ case 2: ++ color_depth = 16; ++ break; ++ case 3: ++ case 4: ++ color_depth = 18; ++ break; ++ case 5: ++ color_depth = 24; ++ break; ++ default: ++ printk("###############please make sure your configure!!!################3\n"); ++ break; ++ } ++ return color_depth; ++} ++/** ++ * Get DPI video pixel configuration ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @return pixel configuration ++ */ ++unsigned char mipi_dsih_hal_dpi_get_color_config(struct dsi_device * dsi) ++{ ++ unsigned char color_config = 0; ++ switch (mipi_dsih_read_part(dsi, R_DSI_HOST_DPI_COLOR_CODING, 0, 4)) ++ { ++ case 0: ++ color_config = 1; ++ case 1: ++ color_config = 2; ++ break; ++ case 2: ++ color_config = 3; ++ break; ++ case 3: ++ color_config = 1; ++ break; ++ case 4: ++ color_config = 2; ++ break; ++ case 5: ++ color_config = 0; ++ break; ++ default: ++ printk("@@@@@@@@@@@@please make sure your configure!!!@@@@@@@@@@@@\n"); ++ break; ++ } ++ return color_config; ++} ++/** ++ * Set DPI loosely packetisation video (used only when color depth = 18 ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param enable ++ */ ++void mipi_dsih_hal_dpi_18_loosely_packet_en(struct dsi_device * dsi, int enable) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_DPI_COLOR_CODING, enable, 8, 1); ++} ++/** ++ * Set DPI color mode pin polarity ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param active_low (1) or active high (0) ++ */ ++void mipi_dsih_hal_dpi_color_mode_pol(struct dsi_device * dsi, int active_low) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_DPI_CFG_POL, active_low, 4, 1); ++} ++/** ++ * Set DPI shut down pin polarity ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param active_low (1) or active high (0) ++ */ ++void mipi_dsih_hal_dpi_shut_down_pol(struct dsi_device * dsi, int active_low) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_DPI_CFG_POL, active_low, 3, 1); ++} ++/** ++ * Set DPI horizontal sync pin polarity ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param active_low (1) or active high (0) ++ */ ++void mipi_dsih_hal_dpi_hsync_pol(struct dsi_device * dsi, int active_low) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_DPI_CFG_POL, active_low, 2, 1); ++} ++/** ++ * Set DPI vertical sync pin polarity ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param active_low (1) or active high (0) ++ */ ++void mipi_dsih_hal_dpi_vsync_pol(struct dsi_device * dsi, int active_low) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_DPI_CFG_POL, active_low, 1, 1); ++} ++/** ++ * Set DPI data enable pin polarity ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param active_low (1) or active high (0) ++ */ ++void mipi_dsih_hal_dpi_dataen_pol(struct dsi_device * dsi, int active_low) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_DPI_CFG_POL, active_low, 0, 1); ++} ++/** ++ * Enable FRAME BTA ACK ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param enable (1) - disable (0) ++ */ ++void mipi_dsih_hal_dpi_frame_ack_en(struct dsi_device * dsi, int enable) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_VID_MODE_CFG, enable, 14, 1); ++} ++/** ++ * Enable null packets (value in null packet size will be taken in calculations) ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param enable (1) - disable (0) ++ */ ++//void mipi_dsih_hal_dpi_null_packet_en(struct dsi_device * dsi, int enable) ++//{ ++// mipi_dsih_write_part(dsi, R_DSI_HOST_VID_MODE_CFG, enable, 10, 1); ++//} ++/** ++ * Enable multi packets (value in no of chunks will be taken in calculations) ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param enable (1) - disable (0) ++ */ ++//void mipi_dsih_hal_dpi_multi_packet_en(struct dsi_device * dsi, int enable) ++//{ ++// mipi_dsih_write_part(dsi, R_DSI_HOST_VID_MODE_CFG, enable, 9, 1); ++//} ++/** ++ * Enable return to low power mode inside horizontal front porch periods when ++ * timing allows ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param enable (1) - disable (0) ++ */ ++void mipi_dsih_hal_dpi_lp_during_hfp(struct dsi_device * dsi, int enable) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_VID_MODE_CFG, enable, 13, 1); ++} ++/** ++ * Enable return to low power mode inside horizontal back porch periods when ++ * timing allows ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param enable (1) - disable (0) ++ */ ++void mipi_dsih_hal_dpi_lp_during_hbp(struct dsi_device * dsi, int enable) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_VID_MODE_CFG, enable, 12, 1); ++} ++/** ++ * Enable return to low power mode inside vertical active lines periods when ++ * timing allows ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param enable (1) - disable (0) ++ */ ++void mipi_dsih_hal_dpi_lp_during_vactive(struct dsi_device * dsi, int enable) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_VID_MODE_CFG, enable, 11, 1); ++} ++/** ++ * Enable return to low power mode inside vertical front porch periods when ++ * timing allows ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param enable (1) - disable (0) ++ */ ++void mipi_dsih_hal_dpi_lp_during_vfp(struct dsi_device * dsi, int enable) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_VID_MODE_CFG, enable, 10, 1); ++} ++/** ++ * Enable return to low power mode inside vertical back porch periods when ++ * timing allows ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param enable (1) - disable (0) ++ */ ++void mipi_dsih_hal_dpi_lp_during_vbp(struct dsi_device * dsi, int enable) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_VID_MODE_CFG, enable, 9, 1); ++} ++/** ++ * Enable return to low power mode inside vertical sync periods when ++ * timing allows ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param enable (1) - disable (0) ++ */ ++void mipi_dsih_hal_dpi_lp_during_vsync(struct dsi_device * dsi, int enable) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_VID_MODE_CFG, enable, 8, 1); ++} ++/** ++ * Set DPI video mode type (burst/non-burst - with sync pulses or events) ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param type ++ * @return error code ++ */ ++dsih_error_t mipi_dsih_hal_dpi_video_mode_type(struct dsi_device * dsi, dsih_video_mode_t type) ++{ ++ if (type < 3) ++ { ++ mipi_dsih_write_part(dsi, R_DSI_HOST_VID_MODE_CFG, type, 0, 2); ++ return OK; ++ } ++ else ++ { ++ { ++ printk("undefined type"); ++ } ++ return ERR_DSI_OUT_OF_BOUND; ++ } ++} ++/** ++ * Write the null packet size - will only be taken into account when null ++ * packets are enabled. ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param size of null packet ++ * @return error code ++ */ ++dsih_error_t mipi_dsih_hal_dpi_null_packet_size(struct dsi_device * dsi, unsigned short size) ++{ ++ if (size < 0x3ff) /* 10-bit field */ ++ { ++ mipi_dsih_write_part(dsi, R_DSI_HOST_VID_NULL_SIZE, size, 0, 13); ++ return OK; ++ } ++ else ++ { ++ return ERR_DSI_OUT_OF_BOUND; ++ } ++} ++/** ++ * Write no of chunks to core - taken into consideration only when multi packet ++ * is enabled ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param no of chunks ++ */ ++dsih_error_t mipi_dsih_hal_dpi_chunks_no(struct dsi_device * dsi, unsigned short no) ++{ ++ if (no < 0x3ff) ++ { ++ mipi_dsih_write_part(dsi, R_DSI_HOST_VID_NUM_CHUNKS, no, 0, 13); ++ return OK; ++ } ++ else ++ { ++ return ERR_DSI_OUT_OF_BOUND; ++ } ++} ++/** ++ * Write video packet size. obligatory for sending video ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param size of video packet - containing information ++ * @return error code ++ */ ++dsih_error_t mipi_dsih_hal_dpi_video_packet_size(struct dsi_device * dsi, unsigned short size) ++{ ++ if (size < 0x7ff) /* 11-bit field */ ++ { ++ mipi_dsih_write_part(dsi, R_DSI_HOST_VID_PKT_SIZE, size, 0, 14); ++ return OK; ++ } ++ else ++ { ++ return ERR_DSI_OUT_OF_BOUND; ++ } ++} ++/** ++ * Enable tear effect acknowledge ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param enable (1) - disable (0) ++ */ ++void mipi_dsih_hal_tear_effect_ack_en(struct dsi_device * dsi, int enable) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_CMD_MODE_CFG, enable, 0, 1); ++} ++/** ++ * Enable packets acknowledge request after each packet transmission ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param enable (1) - disable (0) ++ */ ++void mipi_dsih_hal_cmd_ack_en(struct dsi_device * dsi, int enable) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_CMD_MODE_CFG, enable, 1, 1); ++} ++/** ++ * Set DCS command packet transmission to transmission type ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param no_of_param of command ++ * @param lp transmit in low power ++ * @return error code ++ */ ++dsih_error_t mipi_dsih_hal_dcs_wr_tx_type(struct dsi_device * dsi, unsigned no_of_param, int lp) ++{ ++ switch (no_of_param) ++ { ++ case 0: ++ mipi_dsih_write_part(dsi, R_DSI_HOST_CMD_MODE_CFG, lp, 16, 1); ++ break; ++ case 1: ++ mipi_dsih_write_part(dsi, R_DSI_HOST_CMD_MODE_CFG, lp, 17, 1); ++ break; ++ default: ++ mipi_dsih_write_part(dsi, R_DSI_HOST_CMD_MODE_CFG, lp, 19, 1); ++ break; ++ } ++ return OK; ++} ++/** ++ * Set DCS read command packet transmission to transmission type ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param no_of_param of command ++ * @param lp transmit in low power ++ * @return error code ++ */ ++dsih_error_t mipi_dsih_hal_dcs_rd_tx_type(struct dsi_device * dsi, unsigned no_of_param, int lp) ++{ ++ dsih_error_t err = OK; ++ switch (no_of_param) ++ { ++ case 0: ++ mipi_dsih_write_part(dsi, R_DSI_HOST_CMD_MODE_CFG, lp, 18, 1); ++ break; ++ default: ++ printk("undefined DCS Read packet type"); ++ err = ERR_DSI_OUT_OF_BOUND; ++ break; ++ } ++ return err; ++} ++/** ++ * Set generic write command packet transmission to transmission type ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param no_of_param of command ++ * @param lp transmit in low power ++ * @return error code ++ */ ++dsih_error_t mipi_dsih_hal_gen_wr_tx_type(struct dsi_device * dsi, unsigned no_of_param, int lp) ++{ ++ switch (no_of_param) ++ { ++ case 0: ++ mipi_dsih_write_part(dsi, R_DSI_HOST_CMD_MODE_CFG, lp, 8, 1); ++ break; ++ case 1: ++ mipi_dsih_write_part(dsi, R_DSI_HOST_CMD_MODE_CFG, lp, 9, 1); ++ break; ++ case 2: ++ mipi_dsih_write_part(dsi, R_DSI_HOST_CMD_MODE_CFG, lp, 10, 1); ++ break; ++ default: ++ mipi_dsih_write_part(dsi, R_DSI_HOST_CMD_MODE_CFG, lp, 14, 1); ++ break; ++ } ++ return OK; ++} ++/** ++ * Set generic command packet transmission to transmission type ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param no_of_param of command ++ * @param lp transmit in low power ++ * @return error code ++ */ ++dsih_error_t mipi_dsih_hal_gen_rd_tx_type(struct dsi_device * dsi, unsigned no_of_param, int lp) ++{ ++ dsih_error_t err = OK; ++ switch (no_of_param) ++ { ++ case 0: ++ mipi_dsih_write_part(dsi, R_DSI_HOST_CMD_MODE_CFG, lp, 11, 1); ++ break; ++ case 1: ++ mipi_dsih_write_part(dsi, R_DSI_HOST_CMD_MODE_CFG, lp, 12, 1); ++ break; ++ case 2: ++ mipi_dsih_write_part(dsi, R_DSI_HOST_CMD_MODE_CFG, lp, 13, 1); ++ break; ++ default: ++ printk("undefined Generic Read packet type"); ++ err = ERR_DSI_OUT_OF_BOUND; ++ break; ++ } ++ return err; ++} ++/** ++ * Configure maximum read packet size command transmission type ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param lp set to low power ++ */ ++void mipi_dsih_hal_max_rd_size_tx_type(struct dsi_device * dsi, int lp) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_CMD_MODE_CFG, lp, 24, 1); ++} ++/** ++ * Enable command mode (Generic interface) ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param enable 1 ++ */ ++void mipi_dsih_hal_gen_set_mode(struct dsi_device * dsi, int enable) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_MODE_CFG, enable, 0, 1); ++} ++/** ++ * Retrieve the controller's status of whether command mode is ON or not ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @return whether command mode is ON ++ */ ++int mipi_dsih_hal_gen_get_mode(struct dsi_device * dsi) ++{ ++ return mipi_dsih_read_part(dsi, R_DSI_HOST_MODE_CFG, 0, 1); ++} ++/** ++ * Configure the Horizontal Line time ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param time taken to transmit the total of the horizontal line ++ */ ++void mipi_dsih_hal_dpi_hline(struct dsi_device * dsi, unsigned short time) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_VID_HLINE_TIME, time, 0, 15); ++} ++/** ++ * Configure the Horizontal back porch time ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param time taken to transmit the horizontal back porch ++ */ ++void mipi_dsih_hal_dpi_hbp(struct dsi_device * dsi, unsigned short time) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_VID_HBP_TIME, time, 0, 12); ++} ++/** ++ * Configure the Horizontal sync time ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param time taken to transmit the horizontal sync ++ */ ++void mipi_dsih_hal_dpi_hsa(struct dsi_device * dsi, unsigned short time) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_VID_HSA_TIME, time, 0, 12); ++} ++/** ++ * Configure the vertical active lines of the video stream ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param lines ++ */ ++void mipi_dsih_hal_dpi_vactive(struct dsi_device * dsi, unsigned short lines) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_VID_VACTIVE_LINES, lines, 0, 14); ++} ++/** ++ * Configure the vertical front porch lines of the video stream ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param lines ++ */ ++void mipi_dsih_hal_dpi_vfp(struct dsi_device * dsi, unsigned short lines) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_VID_VFP_LINES, lines, 0, 10); ++} ++/** ++ * Configure the vertical back porch lines of the video stream ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param lines ++ */ ++void mipi_dsih_hal_dpi_vbp(struct dsi_device * dsi, unsigned short lines) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_VID_VBP_LINES, lines, 0, 10); ++} ++/** ++ * Configure the vertical sync lines of the video stream ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param lines ++ */ ++void mipi_dsih_hal_dpi_vsync(struct dsi_device * dsi, unsigned short lines) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_VID_VSA_LINES, lines, 0, 10); ++} ++/** ++ * configure timeout divisions (so they would have more clock ticks) ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param byte_clk_division_factor no of hs cycles before transiting back to LP in ++ * (lane_clk / byte_clk_division_factor) ++ */ ++void mipi_dsih_hal_timeout_clock_division(struct dsi_device * dsi, unsigned char byte_clk_division_factor) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_CLKMGR_CFG, byte_clk_division_factor, 8, 8); ++} ++/** ++ * Configure the Low power receive time out ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param count (of byte cycles) ++ */ ++void mipi_dsih_hal_lp_rx_timeout(struct dsi_device * dsi, unsigned short count) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_TO_CNT_CFG, count, 0, 16); ++} ++/** ++ * Configure a high speed transmission time out7 ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param count (byte cycles) ++ */ ++void mipi_dsih_hal_hs_tx_timeout(struct dsi_device * dsi, unsigned short count) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_TO_CNT_CFG, count, 16, 16); ++} ++/** ++ * Get the error 0 interrupt register status ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param mask the mask to be read from the register ++ * @return error status 0 value ++ */ ++unsigned int mipi_dsih_hal_error_status_0(struct dsi_device * dsi, unsigned int mask) ++{ ++ return (mipi_dsih_read_word(dsi, R_DSI_HOST_INT_ST0) & mask); ++} ++/** ++ * Get the error 1 interrupt register status ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param mask the mask to be read from the register ++ * @return error status 1 value ++ */ ++unsigned int mipi_dsih_hal_error_status_1(struct dsi_device * dsi, unsigned int mask) ++{ ++ return (mipi_dsih_read_word(dsi, R_DSI_HOST_INT_ST1) & mask); ++} ++/** ++ * Configure MASK (hiding) of interrupts coming from error 0 source ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param mask to be written to the register ++ */ ++void mipi_dsih_hal_error_mask_0(struct dsi_device * dsi, unsigned int mask) ++{ ++ mipi_dsih_write_word(dsi, R_DSI_HOST_INT_MSK0, mask); ++} ++/** ++ * Get the ERROR MASK 0 register status ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param mask the bits to read from the mask register ++ */ ++unsigned int mipi_dsih_hal_get_error_mask_0(struct dsi_device * dsi, unsigned int mask) ++{ ++ return (mipi_dsih_read_word(dsi, R_DSI_HOST_INT_MSK0) & mask); ++} ++/** ++ * Configure MASK (hiding) of interrupts coming from error 0 source ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param mask the mask to be written to the register ++ */ ++void mipi_dsih_hal_error_mask_1(struct dsi_device * dsi, unsigned int mask) ++{ ++ mipi_dsih_write_word(dsi, R_DSI_HOST_INT_MSK1, mask); ++} ++/** ++ * Get the ERROR MASK 1 register status ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param mask the bits to read from the mask register ++ */ ++unsigned int mipi_dsih_hal_get_error_mask_1(struct dsi_device * dsi, unsigned int mask) ++{ ++ return (mipi_dsih_read_word(dsi, R_DSI_HOST_INT_MSK1) & mask); ++} ++/* DBI NOT IMPLEMENTED */ ++void mipi_dsih_hal_dbi_out_color_coding(struct dsi_device * dsi, unsigned char color_depth, unsigned char option); ++void mipi_dsih_hal_dbi_in_color_coding(struct dsi_device * dsi, unsigned char color_depth, unsigned char option); ++void mipi_dsih_hal_dbi_lut_size(struct dsi_device * dsi, unsigned char size); ++void mipi_dsih_hal_dbi_partitioning_en(struct dsi_device * dsi, int enable); ++void mipi_dsih_hal_dbi_dcs_vc(struct dsi_device * dsi, unsigned char vc); ++void mipi_dsih_hal_dbi_max_cmd_size(struct dsi_device * dsi, unsigned short size); ++void mipi_dsih_hal_dbi_cmd_size(struct dsi_device * dsi, unsigned short size); ++void mipi_dsih_hal_dbi_max_cmd_size(struct dsi_device * dsi, unsigned short size); ++int mipi_dsih_hal_dbi_rd_cmd_busy(struct dsi_device * dsi); ++int mipi_dsih_hal_dbi_read_fifo_full(struct dsi_device * dsi); ++int mipi_dsih_hal_dbi_read_fifo_empty(struct dsi_device * dsi); ++int mipi_dsih_hal_dbi_write_fifo_full(struct dsi_device * dsi); ++int mipi_dsih_hal_dbi_write_fifo_empty(struct dsi_device * dsi); ++int mipi_dsih_hal_dbi_cmd_fifo_full(struct dsi_device * dsi); ++int mipi_dsih_hal_dbi_cmd_fifo_empty(struct dsi_device * dsi); ++ ++/** ++ * Write command header in the generic interface ++ * (which also sends DCS commands) as a subset ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param vc of destination ++ * @param packet_type (or type of DCS command) ++ * @param ls_byte (if DCS, it is the DCS command) ++ * @param ms_byte (only parameter of short DCS packet) ++ * @return error code ++ */ ++dsih_error_t mipi_dsih_hal_gen_packet_header(struct dsi_device * dsi, unsigned char vc, unsigned char packet_type, unsigned char ms_byte, unsigned char ls_byte) ++{ ++ if (vc < 4) ++ { ++ mipi_dsih_write_part(dsi, R_DSI_HOST_GEN_HDR, (ms_byte << 16) | (ls_byte << 8 ) | ((vc << 6) | packet_type), 0, 24); ++ return OK; ++ } ++ return ERR_DSI_OVERFLOW; ++} ++/** ++ * Write the payload of the long packet commands ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param payload array of bytes of payload ++ * @return error code ++ */ ++dsih_error_t mipi_dsih_hal_gen_packet_payload(struct dsi_device * dsi, unsigned int payload) ++{ ++ if (mipi_dsih_hal_gen_write_fifo_full(dsi)) ++ { ++ return ERR_DSI_OVERFLOW; ++ } ++ mipi_dsih_write_word(dsi, R_DSI_HOST_GEN_PLD_DATA, payload); ++ return OK; ++ ++} ++/** ++ * Write the payload of the long packet commands ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param payload pointer to 32-bit array to hold read information ++ * @return error code ++ */ ++dsih_error_t mipi_dsih_hal_gen_read_payload(struct dsi_device * dsi, unsigned int* payload) ++{ ++ *payload = mipi_dsih_read_word(dsi, R_DSI_HOST_GEN_PLD_DATA); ++ return OK; ++} ++ ++/** ++ * Configure the read back virtual channel for the generic interface ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param vc to listen to on the line ++ */ ++void mipi_dsih_hal_gen_rd_vc(struct dsi_device * dsi, unsigned char vc) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_GEN_VCID, vc, 0, 2); ++} ++/** ++ * Enable EOTp reception ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param enable ++ */ ++void mipi_dsih_hal_gen_eotp_rx_en(struct dsi_device * dsi, int enable) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_PCKHDL_CFG, enable, 1, 1); ++} ++/** ++ * Enable EOTp transmission ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param enable ++ */ ++void mipi_dsih_hal_gen_eotp_tx_en(struct dsi_device * dsi, int enable) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_PCKHDL_CFG, enable, 0, 1); ++} ++/** ++ * Enable Bus Turn-around request ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param enable ++ */ ++void mipi_dsih_hal_bta_en(struct dsi_device * dsi, int enable) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_PCKHDL_CFG, enable, 2, 1); ++} ++/** ++ * Enable ECC reception, error correction and reporting ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param enable ++ */ ++void mipi_dsih_hal_gen_ecc_rx_en(struct dsi_device * dsi, int enable) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_PCKHDL_CFG, enable, 3, 1); ++} ++/** ++ * Enable CRC reception, error reporting ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param enable ++ */ ++void mipi_dsih_hal_gen_crc_rx_en(struct dsi_device * dsi, int enable) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_PCKHDL_CFG, enable, 4, 1); ++} ++/** ++ * Get status of read command ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @return 1 if busy ++ */ ++int mipi_dsih_hal_gen_rd_cmd_busy(struct dsi_device * dsi) ++{ ++ return mipi_dsih_read_part(dsi, R_DSI_HOST_CMD_PKT_STATUS, 6, 1); ++} ++/** ++ * Get the FULL status of generic read payload fifo ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @return 1 if fifo full ++ */ ++int mipi_dsih_hal_gen_read_fifo_full(struct dsi_device * dsi) ++{ ++ return mipi_dsih_read_part(dsi, R_DSI_HOST_CMD_PKT_STATUS, 5, 1); ++} ++/** ++ * Get the EMPTY status of generic read payload fifo ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @return 1 if fifo empty ++ */ ++int mipi_dsih_hal_gen_read_fifo_empty(struct dsi_device * dsi) ++{ ++ return mipi_dsih_read_part(dsi, R_DSI_HOST_CMD_PKT_STATUS, 4, 1); ++} ++/** ++ * Get the FULL status of generic write payload fifo ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @return 1 if fifo full ++ */ ++int mipi_dsih_hal_gen_write_fifo_full(struct dsi_device * dsi) ++{ ++ return mipi_dsih_read_part(dsi, R_DSI_HOST_CMD_PKT_STATUS, 3, 1); ++} ++/** ++ * Get the EMPTY status of generic write payload fifo ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @return 1 if fifo empty ++ */ ++int mipi_dsih_hal_gen_write_fifo_empty(struct dsi_device * dsi) ++{ ++ return mipi_dsih_read_part(dsi, R_DSI_HOST_CMD_PKT_STATUS, 2, 1); ++} ++/** ++ * Get the FULL status of generic command fifo ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @return 1 if fifo full ++ */ ++int mipi_dsih_hal_gen_cmd_fifo_full(struct dsi_device * dsi) ++{ ++ return mipi_dsih_read_part(dsi, R_DSI_HOST_CMD_PKT_STATUS, 1, 1); ++} ++/** ++ * Get the EMPTY status of generic command fifo ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @return 1 if fifo empty ++ */ ++int mipi_dsih_hal_gen_cmd_fifo_empty(struct dsi_device * dsi) ++{ ++ return mipi_dsih_read_part(dsi, R_DSI_HOST_CMD_PKT_STATUS, 0, 1); ++} ++/* only if DPI */ ++/** ++ * Configure how many cycles of byte clock would the PHY module take ++ * to switch from high speed to low power ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param no_of_byte_cycles ++ * @return error code ++ */ ++dsih_error_t mipi_dsih_phy_hs2lp_config(struct dsi_device * dsi, unsigned char no_of_byte_cycles) ++{ ++ if (no_of_byte_cycles < 0x100) { ++ mipi_dsih_write_part(dsi, R_DSI_HOST_PHY_TMR_CFG, no_of_byte_cycles, 24, 8); ++ } ++ else { ++ return ERR_DSI_OVERFLOW; ++ } ++ return OK; ++} ++/** ++ * Configure how many cycles of byte clock would the PHY module take ++ * to switch from to low power high speed ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param no_of_byte_cycles ++ * @return error code ++ */ ++dsih_error_t mipi_dsih_phy_lp2hs_config(struct dsi_device * dsi, unsigned char no_of_byte_cycles) ++{ ++ if (no_of_byte_cycles < 0x100) { ++ mipi_dsih_write_part(dsi, R_DSI_HOST_PHY_TMR_CFG, no_of_byte_cycles, 16, 8); ++ } ++ else { ++ return ERR_DSI_OVERFLOW; ++ } ++ return OK; ++} ++/** ++ * Configure how many cycles of byte clock would the PHY module take ++ * to turn the bus around to start receiving ++ * @param dsi pointer to structure holding the DSI Host core information ++ * @param no_of_byte_cycles ++ * @return error code ++ */ ++dsih_error_t mipi_dsih_phy_bta_time(struct dsi_device * dsi, unsigned short no_of_byte_cycles) ++{ ++ if (no_of_byte_cycles < 0x8000) /* 12-bit field */ ++ { ++ mipi_dsih_write_part(dsi, R_DSI_HOST_PHY_TMR_CFG, no_of_byte_cycles, 0, 15); ++ } ++ else ++ { ++ return ERR_DSI_OVERFLOW; ++ } ++ return OK; ++} ++ ++void mipi_dsih_dphy_test_clock(struct dsi_device * dsi, int value) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_PHY_TST_CTRL0, value, 1, 1); ++} ++void mipi_dsih_dphy_test_clear(struct dsi_device * dsi, int value) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_PHY_TST_CTRL0, value, 0, 1); ++} ++void mipi_dsih_dphy_test_en(struct dsi_device * dsi, unsigned char on_falling_edge) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_PHY_TST_CTRL1, on_falling_edge, 16, 1); ++} ++void mipi_dsih_dphy_test_data_in(struct dsi_device *dsi, unsigned char test_data) ++{ ++ mipi_dsih_write_word(dsi, R_DSI_HOST_PHY_TST_CTRL1, test_data); ++} ++ ++ ++void mipi_dsih_dphy_write(struct dsi_device * dsi, unsigned char address, unsigned char * data, unsigned char data_length) ++{ ++ unsigned i = 0; ++ if (data != 0) ++ { ++ /* set the TESTCLK input high in preparation to latch in the desired test mode */ ++ mipi_dsih_dphy_test_clock(dsi, 1); ++ /* set the desired test code in the input 8-bit bus TESTDIN[7:0] */ ++ mipi_dsih_dphy_test_data_in(dsi, address); ++ /* set TESTEN input high */ ++ mipi_dsih_dphy_test_en(dsi, 1); ++ /* drive the TESTCLK input low; the falling edge captures the chosen test code into the transceiver */ ++ mipi_dsih_dphy_test_clock(dsi, 0); ++ /* set TESTEN input low to disable further test mode code latching */ ++ mipi_dsih_dphy_test_en(dsi, 0); ++ /* start writing MSB first */ ++ for (i = data_length; i > 0; i--) ++ { /* set TESTDIN[7:0] to the desired test data appropriate to the chosen test mode */ ++ mipi_dsih_dphy_test_data_in(dsi, data[i - 1]); ++ /* pulse TESTCLK high to capture this test data into the macrocell; repeat these two steps as necessary */ ++ mipi_dsih_dphy_test_clock(dsi, 1); ++ mipi_dsih_dphy_test_clock(dsi, 0); ++ } ++ } ++} ++void mipi_dsih_dphy_enable_hs_clk(struct dsi_device *dsi, int enable) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_LPCLK_CTRL, enable, 0, 1); ++} ++ ++void mipi_dsih_dphy_auto_clklane_ctrl(struct dsi_device *dsi, int enable) ++{ ++ mipi_dsih_write_part(dsi, R_DSI_HOST_LPCLK_CTRL, enable, 1, 1); ++} ++ ++void mipi_dsih_cmd_mode(struct dsi_device * dsi, int en) ++{ ++ if (dsi == NULL || dsi->state != INITIALIZED){ ++ printk("dsi is NULL, or dsi state error\n"); ++ return ; ++ } ++ ++ if ((!mipi_dsih_hal_gen_get_mode(dsi)) && en) ++ { /* disable video mode first */ ++ mipi_dsih_hal_gen_set_mode(dsi, 1); ++ } ++ else if ((mipi_dsih_hal_gen_get_mode(dsi)) && !en) ++ { ++ mipi_dsih_hal_gen_set_mode(dsi, 0); ++ } ++ return; ++} ++ ++unsigned short mipi_dsih_gen_rd_packet(struct dsi_device * dsi, unsigned char vc, unsigned char data_type, unsigned char msb_byte, unsigned char lsb_byte, unsigned char bytes_to_read, unsigned char* read_buffer) ++{ ++ dsih_error_t err_code = OK; ++ int timeout = 0; ++ int counter = 0; ++ int i = 0; ++ int last_count = 0; ++ unsigned int temp[1] = {0}; ++ if (dsi == 0) ++ { ++ return 0; ++ } ++ if (dsi->state != INITIALIZED) ++ { ++ return 0; ++ } ++ if (bytes_to_read < 1) ++ { ++ return 0; ++ } ++ if (read_buffer == 0) ++ { ++ return 0; ++ } ++ /* make sure command mode is on */ ++ mipi_dsih_cmd_mode(dsi, 1); ++ /* make sure receiving is enabled */ ++ mipi_dsih_hal_bta_en(dsi, 1); ++ /* listen to the same virtual channel as the one sent to */ ++ mipi_dsih_hal_gen_rd_vc(dsi, vc); ++ for (timeout = 0; timeout < DSIH_FIFO_ACTIVE_WAIT; timeout++) ++ { /* check if payload Tx fifo is not full */ ++ if (!mipi_dsih_hal_gen_cmd_fifo_full(dsi)) ++ { ++ printk("I am here!\n"); ++ mipi_dsih_hal_gen_packet_header(dsi, vc, data_type, msb_byte, lsb_byte); ++ break; ++ } ++ } ++ if (!(timeout < DSIH_FIFO_ACTIVE_WAIT)) ++ { ++ printk("tx rd command timed out\n"); ++ return 0; ++ } ++ /* loop for the number of words to be read */ ++ for (timeout = 0; timeout < DSIH_FIFO_ACTIVE_WAIT; timeout++) ++ { /* check if command transaction is done */ ++ if (!mipi_dsih_hal_gen_rd_cmd_busy(dsi)) ++ { ++ printk("is not busy\n"); ++ if (!mipi_dsih_hal_gen_read_fifo_empty(dsi)) ++ { ++ for (counter = 0; (!mipi_dsih_hal_gen_read_fifo_empty(dsi)); counter += 4) ++ { ++ err_code = mipi_dsih_hal_gen_read_payload(dsi, temp); ++ if (err_code) ++ { ++ return 0; ++ } ++ if (counter < bytes_to_read) ++ { ++ for (i = 0; i < 4; i++) ++ { ++ if ((counter + i) < bytes_to_read) ++ { ++ /* put 32 bit temp in 4 bytes of buffer passed by user*/ ++ read_buffer[counter + i] = (unsigned char)(temp[0] >> (i * 8)); ++ last_count = i + counter; ++ } ++ else ++ { ++ if ((unsigned char)(temp[0] >> (i * 8)) != 0x00) ++ { ++ last_count = i + counter; ++ } ++ } ++ } ++ } ++ else ++ { ++ last_count = counter; ++ for (i = 0; i < 4; i++) ++ { ++ if ((unsigned char)(temp[0] >> (i * 8)) != 0x00) ++ { ++ last_count = i + counter; ++ } ++ } ++ } ++ } ++ return last_count + 1; ++ } ++ else ++ { ++ printk("rx buffer empty\n"); ++ return 0; ++ } ++ } ++ } ++ printk("rx command timed out\n"); ++ return 0; ++} ++ ++dsih_error_t mipi_dsih_gen_wr_packet(struct dsi_device * dsi, unsigned char vc, unsigned char data_type, unsigned char* params, unsigned short param_length) ++{ ++ dsih_error_t err_code = OK; ++ /* active delay iterator */ ++ int timeout = 0; ++ /* iterators */ ++ int i = 0; ++ int j = 0; ++ /* holds padding bytes needed */ ++ int compliment_counter = 0; ++ unsigned char* payload = 0; ++ /* temporary variable to arrange bytes into words */ ++ unsigned int temp = 0; ++ unsigned short word_count = 0; ++ if (dsi == 0) ++ { ++ return ERR_DSI_INVALID_INSTANCE; ++ } ++ if (dsi->state != INITIALIZED) ++ { ++ return ERR_DSI_INVALID_INSTANCE; ++ } ++ if ((params == 0) && (param_length != 0)) /* pointer NULL */ ++ { ++ return ERR_DSI_OUT_OF_BOUND; ++ } ++ if (param_length > 2) ++ { /* long packet - write word count to header, and the rest to payload */ ++ payload = params + (2 * sizeof(params[0])); ++ word_count = (params[1] << 8) | params[0]; ++ if ((param_length - 2) < word_count) ++ { ++ printk("sent > input payload. complemented with zeroes\n"); ++ compliment_counter = (param_length - 2) - word_count; ++ } ++ else if ((param_length - 2) > word_count) ++ { ++ printk("Overflow - input > sent. payload truncated\n"); ++ } ++ for (i = 0; i < (param_length - 2); i += j) ++ { ++ temp = 0; ++ for (j = 0; (j < 4) && ((j + i) < (param_length - 2)); j++) ++ { /* temp = (payload[i + 3] << 24) | (payload[i + 2] << 16) | (payload[i + 1] << 8) | payload[i]; */ ++ temp |= payload[i + j] << (j * 8); ++ } ++ /* check if payload Tx fifo is not full */ ++ for (timeout = 0; timeout < DSIH_FIFO_ACTIVE_WAIT; timeout++) ++ { ++ /*send data , or parameters*/ ++ if (!mipi_dsih_hal_gen_packet_payload(dsi, temp)) ++ { ++ break; ++ } ++ } ++ if (!(timeout < DSIH_FIFO_ACTIVE_WAIT)) ++ { ++ return ERR_DSI_TIMEOUT; ++ } ++ } ++ /* if word count entered by the user more than actual parameters received ++ * fill with zeroes - a fail safe mechanism, otherwise controller will ++ * want to send data from an empty buffer */ ++ for (i = 0; i < compliment_counter; i++) ++ { ++ /* check if payload Tx fifo is not full */ ++ for (timeout = 0; timeout < DSIH_FIFO_ACTIVE_WAIT; timeout++) ++ { ++ if (!mipi_dsih_hal_gen_packet_payload(dsi, 0x00)) ++ { ++ break; ++ } ++ } ++ if (!(timeout < DSIH_FIFO_ACTIVE_WAIT)) ++ { ++ return ERR_DSI_TIMEOUT; ++ } ++ } ++ } ++ ++ for (timeout = 0; timeout < DSIH_FIFO_ACTIVE_WAIT; timeout++) ++ { ++ /* check if payload Tx fifo is not full */ ++ if (!mipi_dsih_hal_gen_cmd_fifo_full(dsi)) ++ { ++ if (param_length == 0) ++ { ++ err_code |= mipi_dsih_hal_gen_packet_header(dsi, vc, data_type, 0x0, 0x0); ++ } ++ else if (param_length == 1) ++ { ++ err_code |= mipi_dsih_hal_gen_packet_header(dsi, vc, data_type, 0x0, params[0]); ++ } ++ else ++ { ++ /*make the header*/ ++ err_code |= mipi_dsih_hal_gen_packet_header(dsi, vc, data_type, params[1], params[0]); ++ } ++ break; ++ } ++ else{ ++ printk("cmd fifo full error\n"); ++ err_code = ERR_DSI_OVERFLOW; ++ return err_code; ++ } ++ } ++ if (!(timeout < DSIH_FIFO_ACTIVE_WAIT)) ++ { ++ err_code = ERR_DSI_TIMEOUT; ++ } ++ return err_code; ++} ++ ++unsigned int mipi_dsih_write_register_configuration(struct dsi_device * dsi, register_config_t *config, uint16_t config_length) ++{ ++ unsigned short count = 0; ++ if (dsi == 0) ++ { ++ return ERR_DSI_INVALID_INSTANCE; ++ } ++ for (count = 0; count < config_length; count++) ++ { ++ mipi_dsih_write_word(dsi, config[count].addr, config[count].data); ++ } ++ return count; ++} ++ ++int write_command(struct dsi_device * dsi, struct dsi_cmd_packet cmd_data) ++{ ++ unsigned int i, j; ++ unsigned int packet_type; ++ unsigned char dsi_command_param[MAX_WORD_COUNT] = {0}; ++ unsigned short word_count = 0; ++ unsigned int ret; ++ /*word count*/ ++ packet_type = cmd_data.packet_type; ++ dsi_command_param[0] = cmd_data.cmd0_or_wc_lsb; ++ dsi_command_param[1] = cmd_data.cmd1_or_wc_msb; ++ if(packet_type == 0x39 || packet_type == 0x29){ //dcs long packet ++ word_count = ((dsi_command_param[1] << 8 ) | dsi_command_param[0]); ++ j = 2; ++ /*payload: */ ++ for(i = 0; i < word_count; i++) { ++ dsi_command_param[j++] = cmd_data.cmd_data[i]; ++ } ++ ++ }else if (packet_type == 0x05 || packet_type == 0x15){ //dcs short packet ++ word_count = 0; ++ }else{ ++ printk("not support packet type, please checkout!,\n"); ++ } ++ ret = mipi_dsih_gen_wr_packet(dsi, 0, packet_type, dsi_command_param, word_count + 2); ++ if(ret < 0) { ++ printk("gen_wr_packet failed. ret:%d\n", ret); ++ } ++ mdelay(1); ++ return 0; ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_jz_mipi_dsi_jz_mipi_dsih_hal.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_jz_mipi_dsi_jz_mipi_dsih_hal.h.patch new file mode 100644 index 00000000..27aa6b8f --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_fbdev_ingenic_fb_v12_jz_mipi_dsi_jz_mipi_dsih_hal.h.patch @@ -0,0 +1,150 @@ +diff -drupN a/drivers/video/fbdev/ingenic/fb_v12/jz_mipi_dsi/jz_mipi_dsih_hal.h b/drivers/video/fbdev/ingenic/fb_v12/jz_mipi_dsi/jz_mipi_dsih_hal.h +--- a/drivers/video/fbdev/ingenic/fb_v12/jz_mipi_dsi/jz_mipi_dsih_hal.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/fbdev/ingenic/fb_v12/jz_mipi_dsi/jz_mipi_dsih_hal.h 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,146 @@ ++/* ++ * @file mipi_dsih_hal.h ++ * ++ * SG DWC PT02 ++ */ ++#ifndef MIPI_DSIH_HAL_H_ ++#define MIPI_DSIH_HAL_H_ ++ ++#include "../jz_dsim.h" ++ ++ ++/** ++ * @return the dsi host core version ++ */ ++unsigned int mipi_dsih_hal_get_version(struct dsi_device * dsi); ++/*enable dsihost*/ ++void mipi_dsih_hal_power(struct dsi_device * dsi, int on); ++/** ++ * set the virtual channel ID that is indexes to the DPI video mode stream ++ * @param vc virtual channel ID ++ */ ++void mipi_dsih_hal_dpi_video_vc(struct dsi_device * dsi, unsigned char vc); ++/** ++ * @return vc virtual channel ID ++ */ ++unsigned char mipi_dsih_hal_dpi_get_video_vc(struct dsi_device * dsi); ++ ++dsih_error_t mipi_dsih_hal_dpi_color_coding(struct dsi_device * dsi, dsih_color_coding_t color_coding); ++dsih_color_coding_t mipi_dsih_hal_dpi_get_color_coding(struct dsi_device * dsi); ++unsigned char mipi_dsih_hal_dpi_get_color_depth(struct dsi_device * dsi); ++unsigned char mipi_dsih_hal_dpi_get_color_config(struct dsi_device * dsi); ++void mipi_dsih_hal_dpi_18_loosely_packet_en(struct dsi_device * dsi, int enable); ++void mipi_dsih_hal_dpi_color_mode_pol(struct dsi_device * dsi, int active_low); ++void mipi_dsih_hal_dpi_shut_down_pol(struct dsi_device * dsi, int active_low); ++void mipi_dsih_hal_dpi_hsync_pol(struct dsi_device * dsi, int active_low); ++void mipi_dsih_hal_dpi_vsync_pol(struct dsi_device * dsi, int active_low); ++void mipi_dsih_hal_dpi_dataen_pol(struct dsi_device * dsi, int active_low); ++void mipi_dsih_hal_dpi_frame_ack_en(struct dsi_device * dsi, int enable); ++void mipi_dsih_hal_dpi_null_packet_en(struct dsi_device * dsi, int enable); ++void mipi_dsih_hal_dpi_multi_packet_en(struct dsi_device * dsi, int enable); ++void mipi_dsih_hal_dpi_lp_during_hfp(struct dsi_device * dsi, int enable); ++void mipi_dsih_hal_dpi_lp_during_hbp(struct dsi_device * dsi, int enable); ++void mipi_dsih_hal_dpi_lp_during_vactive(struct dsi_device * dsi, int enable); ++void mipi_dsih_hal_dpi_lp_during_vfp(struct dsi_device * dsi, int enable); ++void mipi_dsih_hal_dpi_lp_during_vbp(struct dsi_device * dsi, int enable); ++void mipi_dsih_hal_dpi_lp_during_vsync(struct dsi_device * dsi, int enable); ++ ++dsih_error_t mipi_dsih_hal_dpi_video_mode_type(struct dsi_device * dsi, dsih_video_mode_t type); ++void mipi_dsih_hal_dpi_video_mode_en(struct dsi_device * dsi, int enable); ++int mipi_dsih_hal_dpi_is_video_mode(struct dsi_device * dsi); ++dsih_error_t mipi_dsih_hal_dpi_null_packet_size(struct dsi_device * dsi, unsigned short size); ++dsih_error_t mipi_dsih_hal_dpi_chunks_no(struct dsi_device * dsi, unsigned short no); ++dsih_error_t mipi_dsih_hal_dpi_video_packet_size(struct dsi_device * dsi, unsigned short size); ++ ++void mipi_dsih_hal_tear_effect_ack_en(struct dsi_device * dsi, int enable); ++ ++void mipi_dsih_hal_cmd_ack_en(struct dsi_device * dsi, int enable); ++dsih_error_t mipi_dsih_hal_dcs_wr_tx_type(struct dsi_device * dsi, unsigned no_of_param, int lp); ++dsih_error_t mipi_dsih_hal_dcs_rd_tx_type(struct dsi_device * dsi, unsigned no_of_param, int lp); ++dsih_error_t mipi_dsih_hal_gen_wr_tx_type(struct dsi_device * dsi, unsigned no_of_param, int lp); ++dsih_error_t mipi_dsih_hal_gen_rd_tx_type(struct dsi_device * dsi, unsigned no_of_param, int lp); ++void mipi_dsih_hal_max_rd_size_type(struct dsi_device * dsi, int lp); ++void mipi_dsih_hal_gen_cmd_mode_en(struct dsi_device * dsi, int enable); ++int mipi_dsih_hal_gen_is_cmd_mode(struct dsi_device * dsi); ++ ++void mipi_dsih_hal_dpi_hline(struct dsi_device * dsi, unsigned short time); ++void mipi_dsih_hal_dpi_hbp(struct dsi_device * dsi, unsigned short time); ++void mipi_dsih_hal_dpi_hsa(struct dsi_device * dsi, unsigned short time); ++void mipi_dsih_hal_dpi_vactive(struct dsi_device * dsi, unsigned short lines); ++void mipi_dsih_hal_dpi_vfp(struct dsi_device * dsi, unsigned short lines); ++void mipi_dsih_hal_dpi_vbp(struct dsi_device * dsi, unsigned short lines); ++void mipi_dsih_hal_dpi_vsync(struct dsi_device * dsi, unsigned short lines); ++dsih_error_t mipi_dsih_hal_gen_packet_header(struct dsi_device * dsi, unsigned char vc, unsigned char packet_type, unsigned char ms_byte, unsigned char ls_byte); ++/*dsih_error_t mipi_dsih_hal_gen_packet_payload(struct dsi_device * dsi, unsigned int* payload, unsigned short payload_size);*/ ++dsih_error_t mipi_dsih_hal_gen_packet_payload(struct dsi_device * dsi, unsigned int payload); ++dsih_error_t mipi_dsih_hal_gen_read_payload(struct dsi_device * dsi, unsigned int* payload); ++ ++void mipi_dsih_hal_timeout_clock_division(struct dsi_device * dsi, unsigned char byte_clk_division_factor); ++void mipi_dsih_hal_lp_rx_timeout(struct dsi_device * dsi, unsigned short count); ++void mipi_dsih_hal_hs_tx_timeout(struct dsi_device * dsi, unsigned short count); ++ ++unsigned int mipi_dsih_hal_error_status_0(struct dsi_device * dsi, unsigned int mask); ++unsigned int mipi_dsih_hal_error_status_1(struct dsi_device * dsi, unsigned int mask); ++void mipi_dsih_hal_error_mask_0(struct dsi_device * dsi, unsigned int mask); ++void mipi_dsih_hal_error_mask_1(struct dsi_device * dsi, unsigned int mask); ++unsigned int mipi_dsih_hal_get_error_mask_0(struct dsi_device * dsi, unsigned int mask); ++unsigned int mipi_dsih_hal_get_error_mask_1(struct dsi_device * dsi, unsigned int mask); ++ ++void mipi_dsih_hal_dbi_out_color_coding(struct dsi_device * dsi, unsigned char color_depth, unsigned char option); ++void mipi_dsih_hal_dbi_in_color_coding(struct dsi_device * dsi, unsigned char color_depth, unsigned char option); ++void mipi_dsih_hal_dbi_lut_size(struct dsi_device * dsi, unsigned char size); ++void mipi_dsih_hal_dbi_partitioning_en(struct dsi_device * dsi, int enable); ++void mipi_dsih_hal_dbi_dcs_vc(struct dsi_device * dsi, unsigned char vc); ++ ++void mipi_dsih_hal_dbi_cmd_size(struct dsi_device * dsi, unsigned short size); ++void mipi_dsih_hal_dbi_max_cmd_size(struct dsi_device * dsi, unsigned short size); ++int mipi_dsih_hal_dbi_rd_cmd_busy(struct dsi_device * dsi); ++int mipi_dsih_hal_dbi_read_fifo_full(struct dsi_device * dsi); ++int mipi_dsih_hal_dbi_read_fifo_empty(struct dsi_device * dsi); ++int mipi_dsih_hal_dbi_write_fifo_full(struct dsi_device * dsi); ++int mipi_dsih_hal_dbi_write_fifo_empty(struct dsi_device * dsi); ++int mipi_dsih_hal_dbi_cmd_fifo_full(struct dsi_device * dsi); ++int mipi_dsih_hal_dbi_cmd_fifo_empty(struct dsi_device * dsi); ++ ++void mipi_dsih_hal_gen_rd_vc(struct dsi_device * dsi, unsigned char vc); ++void mipi_dsih_hal_gen_eotp_rx_en(struct dsi_device * dsi, int enable); ++void mipi_dsih_hal_gen_eotp_tx_en(struct dsi_device * dsi, int enable); ++void mipi_dsih_hal_bta_en(struct dsi_device * dsi, int enable); ++void mipi_dsih_hal_gen_ecc_rx_en(struct dsi_device * dsi, int enable); ++void mipi_dsih_hal_gen_crc_rx_en(struct dsi_device * dsi, int enable); ++int mipi_dsih_hal_gen_rd_cmd_busy(struct dsi_device * dsi); ++int mipi_dsih_hal_gen_read_fifo_full(struct dsi_device * dsi); ++int mipi_dsih_hal_gen_read_fifo_empty(struct dsi_device * dsi); ++int mipi_dsih_hal_gen_write_fifo_full(struct dsi_device * dsi); ++int mipi_dsih_hal_gen_write_fifo_empty(struct dsi_device * dsi); ++int mipi_dsih_hal_gen_cmd_fifo_full(struct dsi_device * dsi); ++int mipi_dsih_hal_gen_cmd_fifo_empty(struct dsi_device * dsi); ++ ++/* only if DPI */ ++dsih_error_t mipi_dsih_phy_hs2lp_config(struct dsi_device * dsi, unsigned char no_of_byte_cycles); ++dsih_error_t mipi_dsih_phy_lp2hs_config(struct dsi_device * dsi, unsigned char no_of_byte_cycles); ++dsih_error_t mipi_dsih_phy_bta_time(struct dsi_device * dsi, unsigned short no_of_byte_cycles); ++/* */ ++ ++void mipi_dsih_write_word(struct dsi_device * dsi, unsigned int reg_address, unsigned int data); ++void mipi_dsih_write_part(struct dsi_device * dsi, unsigned int reg_address, unsigned int data, unsigned char shift, unsigned char width); ++unsigned int mipi_dsih_read_word(struct dsi_device * dsi, unsigned int reg_address); ++unsigned int mipi_dsih_read_part(struct dsi_device * dsi, unsigned int reg_address, unsigned char shift, unsigned char width); ++void mipi_dsih_dphy_enable_hs_clk(struct dsi_device *dsi, int enable); ++void mipi_dsih_dphy_auto_clklane_ctrl(struct dsi_device *dsi, int enable); ++void mipi_dsih_dphy_test_clock(struct dsi_device * dsi, int value); ++void mipi_dsih_dphy_test_clear(struct dsi_device * dsi, int value); ++void mipi_dsih_dphy_test_en(struct dsi_device * dsi, unsigned char on_falling_edge); ++void mipi_dsih_dphy_test_data_in(struct dsi_device *dsi, unsigned char test_data); ++void mipi_dsih_dphy_write(struct dsi_device * dsi, unsigned char address, unsigned char * data, unsigned char data_length); ++void mipi_dsih_cmd_mode(struct dsi_device * dsi, int en); ++ ++ ++void mipi_dsih_hal_gen_set_mode(struct dsi_device * dsi, int enable); ++ ++unsigned int mipi_dsih_write_register_configuration(struct dsi_device * dsi, register_config_t *config, uint16_t config_length); ++unsigned short mipi_dsih_gen_rd_packet(struct dsi_device * dsi, unsigned char vc, unsigned char data_type, unsigned char msb_byte, unsigned char lsb_byte, unsigned char bytes_to_read, unsigned char* read_buffer); ++dsih_error_t mipi_dsih_gen_wr_packet(struct dsi_device * dsi, unsigned char vc, unsigned char data_type, unsigned char* params, unsigned short param_length); ++ ++int write_command(struct dsi_device * dsi, struct dsi_cmd_packet cmd_data); ++#endif /* MIPI_DSI_API_H_ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_bscaler_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_bscaler_Kconfig.patch new file mode 100644 index 00000000..f6a50ed7 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_bscaler_Kconfig.patch @@ -0,0 +1,7 @@ +diff -drupN a/drivers/video/ingenic_bscaler/Kconfig b/drivers/video/ingenic_bscaler/Kconfig +--- a/drivers/video/ingenic_bscaler/Kconfig 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/ingenic_bscaler/Kconfig 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,3 @@ ++config JZ_BSCALER ++ bool "jz bscaler driver" ++ default n diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_bscaler_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_bscaler_Makefile.patch new file mode 100644 index 00000000..20adc552 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_bscaler_Makefile.patch @@ -0,0 +1,5 @@ +diff -drupN a/drivers/video/ingenic_bscaler/Makefile b/drivers/video/ingenic_bscaler/Makefile +--- a/drivers/video/ingenic_bscaler/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/ingenic_bscaler/Makefile 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1 @@ ++obj-$(CONFIG_JZ_BSCALER) += ingenic_bscaler.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_bscaler_ingenic_bscaler.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_bscaler_ingenic_bscaler.c.patch new file mode 100644 index 00000000..394dbf07 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_bscaler_ingenic_bscaler.c.patch @@ -0,0 +1,401 @@ +diff -drupN a/drivers/video/ingenic_bscaler/ingenic_bscaler.c b/drivers/video/ingenic_bscaler/ingenic_bscaler.c +--- a/drivers/video/ingenic_bscaler/ingenic_bscaler.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/ingenic_bscaler/ingenic_bscaler.c 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,397 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define JZ_BSCALER_NUM 2 ++ ++#define IOCTL_BSCALER0_IRQ_GET_STAT 0x000 ++#define IOCTL_BSCALER1_IRQ_GET_STAT 0x100 ++ ++#define REG_BSCALER_STAT0 (0x00) ++#define REG_BSCALER_CTRL0 (0xb0) //44*4 FRMT ++#define REG_BSCALER_STAT1 (0x80) ++#define REG_BSCALER_CTRL1 (0x30) //12*4 FRMC ++ ++struct jz_bscaler_context { ++ int irq; ++ struct completion done; ++ spinlock_t slock; ++ unsigned int status; ++}; ++ ++struct jz_bscaler { ++ char name[16]; ++ int idx; ++ void __iomem *iomem; ++ struct clk *clk; ++ struct clk *clk_gate; ++ struct clk *ahb0_gate; ++ pid_t owner_pid; ++ struct jz_bscaler_context ctx[JZ_BSCALER_NUM]; ++ struct miscdevice mdev; ++ struct mutex openmutex; ++ int opencnt; ++}; ++ ++#define jz_bscaler_readl(bscaler, offset) __raw_readl((bscaler)->iomem + offset) ++#define jz_bscaler_writel(bscaler, offset, value) __raw_writel((value), (bscaler)->iomem + offset) ++ ++#define CLEAR_RADIX_BIT(bscaler,offset,bm) \ ++ do { \ ++ unsigned int stat; \ ++ stat = jz_bscaler_readl(bscaler,offset); \ ++ jz_bscaler_writel(bscaler,offset,stat & ~(bm)); \ ++ } while(0) ++ ++static irqreturn_t jz_bscaler_interrupt_t(int irq, void *data) ++{ ++ struct jz_bscaler *bscaler = (struct jz_bscaler *)data; ++ struct jz_bscaler_context *ctx = NULL; ++ unsigned int reg_ctrl = 0, reg_stat = 0; ++ ++ ++ spin_lock(&bscaler->ctx[0].slock); ++ if (irq == bscaler->ctx[0].irq) { ++ ctx = &(bscaler->ctx[0]); ++ reg_ctrl = REG_BSCALER_CTRL0; ++ } else { ++ printk("irq error!\n"); ++ return -1; ++ } ++ ++ if (jz_bscaler_readl(bscaler, 0x80) & 0x100) { ++ jz_bscaler_writel(bscaler, 0x80 ,(jz_bscaler_readl(bscaler, 0x80) & ~0x100)); ++ } ++ ++ if (jz_bscaler_readl(bscaler, 0x84) & 0x4) { ++ jz_bscaler_writel(bscaler, 0x84 ,(jz_bscaler_readl(bscaler, 0x84) & ~0x4)); ++ } ++ if (jz_bscaler_readl(bscaler, 0xb0) & 0x50) { ++ if (jz_bscaler_readl(bscaler, 0xb0) & 0x40) { ++ printk("ERROR: bscaler T irq timeout!!!\n"); ++ } ++ jz_bscaler_writel(bscaler, 0xb0 ,(jz_bscaler_readl(bscaler, 0xb0) & ~0x50)); ++ } ++ ++ ++ ctx->status = jz_bscaler_readl(bscaler, reg_stat); ++ dev_dbg(bscaler->mdev.this_device, "In bscaler0_interrupt : irq=%d, status = 0x%08x\n", irq, ctx->status); ++ complete(&ctx->done); ++ ++ spin_unlock(&bscaler->ctx[0].slock); ++ ++ return IRQ_HANDLED; ++} ++ ++ ++static irqreturn_t jz_bscaler_interrupt_c(int irq, void *data) ++{ ++ struct jz_bscaler *bscaler = (struct jz_bscaler *)data; ++ struct jz_bscaler_context *ctx = NULL; ++ unsigned int reg_ctrl = 0, reg_stat = 0; ++ ++ ++ spin_lock(&bscaler->ctx[1].slock); ++ if (irq == bscaler->ctx[1].irq) { ++ ctx = &(bscaler->ctx[1]); ++ reg_ctrl = REG_BSCALER_CTRL1; ++ } else { ++ printk("irq error!\n"); ++ return -1; ++ } ++ ++ if (jz_bscaler_readl(bscaler, 0x0) & 0x100) { ++ jz_bscaler_writel(bscaler, 0x0 ,(jz_bscaler_readl(bscaler, 0x0) & ~0x100)); ++ } ++ ++ if (jz_bscaler_readl(bscaler, 0x30) & 0x50) { ++ if (jz_bscaler_readl(bscaler, 0x30) & 0x40) { ++ printk("ERROR: bscaler C irq timeout!!!\n"); ++ } ++ jz_bscaler_writel(bscaler, 0x30 ,(jz_bscaler_readl(bscaler, 0x30) & ~0x50)); ++ } ++ ++ ctx->status = jz_bscaler_readl(bscaler, reg_stat); ++ dev_dbg(bscaler->mdev.this_device, "In bscaler0_interrupt : irq=%d, status = 0x%08x\n", irq, ctx->status); ++ complete(&ctx->done); ++ ++ spin_unlock(&bscaler->ctx[1].slock); ++ ++ return IRQ_HANDLED; ++} ++ ++ ++static int jz_bscaler_open(struct inode *inode, struct file *file) ++{ ++ int i = 0; ++ struct miscdevice *mdev = file->private_data; ++ struct jz_bscaler *bscaler = list_entry(mdev, struct jz_bscaler, mdev); ++ ++ clk_prepare_enable(bscaler->clk); ++ clk_prepare_enable(bscaler->ahb0_gate); ++ clk_prepare_enable(bscaler->clk_gate); ++ mutex_lock(&bscaler->openmutex); ++ if (!bscaler->opencnt) { ++ for (i = 0; i < JZ_BSCALER_NUM; i++) { ++ bscaler->ctx[i].done.done = 0; ++ enable_irq(bscaler->ctx[i].irq); ++ } ++ } ++ bscaler->opencnt++; ++ mutex_unlock(&bscaler->openmutex); ++ ++ dev_dbg(mdev->this_device, "%s open successful, opencnt=%d!\n", __func__, bscaler->opencnt); ++ ++ return 0; ++} ++ ++static int jz_bscaler_release(struct inode *inode, struct file *file) ++{ ++ int i = 0; ++ struct miscdevice *mdev = file->private_data; ++ struct jz_bscaler *bscaler = list_entry(mdev, struct jz_bscaler, mdev); ++ ++ mutex_lock(&bscaler->openmutex); ++ if (bscaler->opencnt == 1) { ++ for (i = 0; i < JZ_BSCALER_NUM; i++) { ++ disable_irq(bscaler->ctx[i].irq); ++ bscaler->ctx[i].done.done = 0; ++ } ++ clk_disable(bscaler->clk); ++ clk_disable(bscaler->clk_gate); ++ clk_disable(bscaler->ahb0_gate); ++ bscaler->opencnt--; ++ } ++ mutex_unlock(&bscaler->openmutex); ++ ++ dev_dbg(mdev->this_device, "%s close successful, opencnt=%d!\n", __func__, bscaler->opencnt); ++ ++ return 0; ++} ++ ++static ssize_t jz_bscaler_read(struct file *file, char __user * buffer, size_t count, loff_t * ppos) ++{ ++ return 0; ++} ++ ++static ssize_t jz_bscaler_write(struct file *file, const char __user * buffer, size_t count, loff_t * ppos) ++{ ++ return 0; ++} ++ ++static long jz_bscaler_wait_irq(struct jz_bscaler *bscaler, int bscaler_idx, unsigned long arg) ++{ ++ long ret = 0; ++ dev_dbg(bscaler->mdev.this_device, "%s:bscaler index=%d start\n", __func__, bscaler_idx); ++ ret = wait_for_completion_timeout(&bscaler->ctx[bscaler_idx].done, msecs_to_jiffies(300)); ++ if (ret <= 0) { ++ dev_err(bscaler->mdev.this_device, "copy_to_user bscaler index=%d timeout!\n", bscaler_idx); ++ return -EFAULT; ++ } ++ if (copy_to_user((void *)arg, &bscaler->ctx[bscaler_idx].status, sizeof(unsigned int))) { ++ dev_err(bscaler->mdev.this_device, "copy_to_user bscaler index=%d, stat=0x%x failed!\n", bscaler_idx, bscaler->ctx[bscaler_idx].status); ++ return -EFAULT; ++ } ++ dev_dbg(bscaler->mdev.this_device, "%s:bscaler index=%d end\n", __func__, bscaler_idx); ++ ++ return 0; ++} ++ ++static long jz_bscaler_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ struct miscdevice *mdev = file->private_data; ++ struct jz_bscaler *bscaler = list_entry(mdev, struct jz_bscaler, mdev); ++ ++ switch(cmd) { ++ case IOCTL_BSCALER0_IRQ_GET_STAT: ++ return jz_bscaler_wait_irq(bscaler, 0, arg); ++ case IOCTL_BSCALER1_IRQ_GET_STAT: ++ return jz_bscaler_wait_irq(bscaler, 1, arg); ++ default: ++ dev_err(mdev->this_device, "%s:invalid cmd %u\n", __func__, cmd); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++const struct file_operations jz_bscaler_fops = { ++ .owner = THIS_MODULE, ++ .open = jz_bscaler_open, ++ .release = jz_bscaler_release, ++ .read = jz_bscaler_read, ++ .write = jz_bscaler_write, ++ .unlocked_ioctl = jz_bscaler_ioctl, ++}; ++ ++static int jz_bscaler_probe(struct platform_device *pdev) ++{ ++ int ret = 0, i = 0; ++ struct resource *regs = NULL; ++ struct jz_bscaler *bscaler = NULL; ++ char irq_name[64]; ++ ++ bscaler = devm_kzalloc(&pdev->dev, sizeof(struct jz_bscaler), GFP_KERNEL); ++ if (!bscaler) { ++ dev_err(&pdev->dev, "kzalloc struct jz_bscaler failed\n"); ++ ret = -ENOMEM; ++ goto err_kzalloc_bscaler; ++ } ++ ++ ++ pdev->id = of_alias_get_id(pdev->dev.of_node, "bscaler"); ++ bscaler->idx = pdev->id; ++ sprintf(bscaler->name, "%s%d", "bscaler", pdev->id); ++ ++ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!regs) { ++ dev_err(&pdev->dev, "No iomem resource\n"); ++ ret = -ENXIO; ++ goto err_get_bscaler_resource; ++ } ++ ++ bscaler->iomem = devm_ioremap_resource(&pdev->dev, regs); ++ if (!bscaler->iomem) { ++ dev_err(&pdev->dev, "ioremap failed\n"); ++ ret = -ENXIO; ++ goto err_get_bscaler_iomem; ++ } ++ bscaler->ahb0_gate = devm_clk_get(&pdev->dev, "gate_ahb0"); ++ if (IS_ERR(bscaler->ahb0_gate)) { ++ dev_err(&pdev->dev, "clk_gate get ahb0 failed\n"); ++ ret = PTR_ERR(bscaler->ahb0_gate); ++ goto err_get_bscaler_ahb0_gate; ++ } ++ bscaler->clk_gate = devm_clk_get(&pdev->dev, "gate_bscaler"); ++ if (IS_ERR(bscaler->clk_gate)) { ++ dev_err(&pdev->dev, "clk_gate get bscaler failed\n"); ++ ret = PTR_ERR(bscaler->clk_gate); ++ goto err_get_bscaler_clk_gate; ++ } ++ bscaler->clk = devm_clk_get(&pdev->dev,"div_bscaler"); ++ if (IS_ERR(bscaler->clk)) { ++ dev_err(&pdev->dev, "clk get cgu_bscaler failed\n"); ++ ret = PTR_ERR(bscaler->clk); ++ goto err_get_bscaler_clk_cgu; ++ } ++ ++ clk_set_parent(bscaler->clk, clk_get(NULL, "epll")); ++ clk_set_rate(bscaler->clk,400000000); ++ ++ for (i = 0; i < JZ_BSCALER_NUM; i++) { ++ bscaler->ctx[i].irq = platform_get_irq(pdev, i); ++ if(bscaler->ctx[i].irq < 0) { ++ dev_err(&pdev->dev, "get irq %d failed\n", i); ++ goto err_get_bscaler_irq; ++ } ++ sprintf(irq_name, "%s%d", bscaler->name, bscaler->ctx[i].irq); ++ ret = devm_request_irq(&pdev->dev, bscaler->ctx[i].irq, i == 0 ? jz_bscaler_interrupt_t:jz_bscaler_interrupt_c, IRQF_DISABLED, irq_name, bscaler); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "request_irq i=%d, irq=%d failed\n", i, bscaler->ctx[i].irq); ++ goto err_bscaler_helix_irq; ++ } ++ disable_irq_nosync(bscaler->ctx[i].irq); ++ ++ init_completion(&bscaler->ctx[i].done); ++ spin_lock_init(&bscaler->ctx[i].slock); ++ } ++ mutex_init(&bscaler->openmutex); ++ bscaler->opencnt = 0; ++ ++ ++ bscaler->mdev.minor = MISC_DYNAMIC_MINOR; ++ bscaler->mdev.fops = &jz_bscaler_fops; ++ bscaler->mdev.name = bscaler->name; ++ ret = misc_register(&bscaler->mdev); ++ if(ret < 0) { ++ dev_err(&pdev->dev,"request bscaler misc device failed!\n"); ++ goto err_bscaler_register; ++ } ++ platform_set_drvdata(pdev, bscaler); ++ return 0; ++ ++err_bscaler_register: ++ i = JZ_BSCALER_NUM; ++err_bscaler_helix_irq: ++err_get_bscaler_irq: ++ for (--i; i >= 0; i--) { ++ free_irq(bscaler->ctx[i].irq, bscaler); ++ } ++ clk_put(bscaler->clk); ++err_get_bscaler_clk_cgu: ++ clk_put(bscaler->clk_gate); ++err_get_bscaler_clk_gate: ++ clk_put(bscaler->ahb0_gate); ++err_get_bscaler_ahb0_gate: ++ iounmap(bscaler->iomem); ++err_get_bscaler_iomem: ++err_get_bscaler_resource: ++ kfree(bscaler); ++ bscaler = NULL; ++err_kzalloc_bscaler: ++ return ret; ++} ++ ++static int jz_bscaler_remove(struct platform_device *pdev) ++{ ++ int i; ++ struct jz_bscaler *bscaler = platform_get_drvdata(&pdev->dev); ++ ++ misc_deregister(&bscaler->mdev); ++ ++ for (i = JZ_BSCALER_NUM - 1; i >= 0; i--) { ++ free_irq(bscaler->ctx[i].irq, bscaler); ++ } ++ ++ clk_disable_unprepare(bscaler->clk); ++ clk_disable_unprepare(bscaler->clk_gate); ++ clk_disable_unprepare(bscaler->ahb0_gate); ++ ++ devm_iounmap(&pdev->dev, bscaler->iomem); ++ ++ if (bscaler) { ++ kfree(bscaler); ++ } ++ ++ bscaler = NULL; ++ ++ return 0; ++} ++ ++static const struct of_device_id ingenic_bscaler_dt_match[] = { ++ { .compatible = "ingenic,t40-bscaler", .data = NULL }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ingenic_bscaler_dt_match); ++ ++static struct platform_driver jz_bscaler_driver = { ++ .probe = jz_bscaler_probe, ++ .remove = jz_bscaler_remove, ++ .driver = { ++ .name = "jz-bscaler", ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(ingenic_bscaler_dt_match), ++ }, ++}; ++ ++module_platform_driver(jz_bscaler_driver) ++ ++MODULE_DESCRIPTION("JZ BSCALER driver"); ++MODULE_AUTHOR("Justin "); ++MODULE_LICENSE("GPL v2"); ++MODULE_VERSION("20200820"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_i2d_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_i2d_Kconfig.patch new file mode 100644 index 00000000..c2bdc791 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_i2d_Kconfig.patch @@ -0,0 +1,17 @@ +diff -drupN a/drivers/video/ingenic_i2d/Kconfig b/drivers/video/ingenic_i2d/Kconfig +--- a/drivers/video/ingenic_i2d/Kconfig 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/ingenic_i2d/Kconfig 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,13 @@ ++menuconfig JZ_I2D ++ bool "JZ I2D Driver" ++ default y ++ help ++ Support for Ingenic i2d Driver ++ ++config INGENIC_I2D ++ bool "Ingenic I2D Driver" ++ depends on JZ_I2D ++ default y ++ help ++ Support for Ingenic i2d operations. ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_i2d_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_i2d_Makefile.patch new file mode 100644 index 00000000..cb9da14d --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_i2d_Makefile.patch @@ -0,0 +1,5 @@ +diff -drupN a/drivers/video/ingenic_i2d/Makefile b/drivers/video/ingenic_i2d/Makefile +--- a/drivers/video/ingenic_i2d/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/ingenic_i2d/Makefile 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1 @@ ++obj-$(CONFIG_INGENIC_I2D) += ingenic_i2d.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_i2d_ingenic_i2d.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_i2d_ingenic_i2d.c.patch new file mode 100644 index 00000000..f339d047 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_i2d_ingenic_i2d.c.patch @@ -0,0 +1,747 @@ +diff -drupN a/drivers/video/ingenic_i2d/ingenic_i2d.c b/drivers/video/ingenic_i2d/ingenic_i2d.c +--- a/drivers/video/ingenic_i2d/ingenic_i2d.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/ingenic_i2d/ingenic_i2d.c 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,743 @@ ++/* ++ * Copyright (c) 2015 Ingenic Semiconductor Co., Ltd. ++ * http://www.ingenic.com/ ++ * ++ * Input file for Ingenic I2D driver ++ * ++ * 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. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "ingenic_i2d.h" ++ ++//#define TIMEOUT_TEST ++//#define DEBUG ++#ifdef DEBUG ++static int debug_i2d = 1; ++ ++#define I2D_DEBUG(format, ...) { if (debug_i2d) printk(format, ## __VA_ARGS__);} ++#else ++#define I2D_DEBUG(format, ...) do{ } while(0) ++#endif ++ ++#define I2D_BUF_SIZE (1024 * 1024 * 2) ++#define I2D_ALIGNMENT 16 /*对齐参数*/ ++ ++struct i2d_reg_struct jz_i2d_regs_name[] = { ++ {"I2D_VERSION", I2D_RTL_VERSION}, ++ {"I2D_SHD_CTRL", I2D_SHD_CTRL}, ++ {"I2D_CTRL", I2D_CTRL}, ++ {"I2D_IMG_SIZE", I2D_IMG_SIZE}, ++ {"I2D_IMG_MODE", I2D_IMG_MODE}, ++ {"I2D_SRC_ADDR_Y", I2D_SRC_ADDR_Y}, ++ {"I2D_SRC_ADDR_UV", I2D_SRC_ADDR_UV}, ++ {"I2D_SRC_Y_STRID", I2D_SRC_Y_STRID}, ++ {"I2D_SRC_UV_STRID", I2D_SRC_UV_STRID}, ++ {"I2D_DST_ADDR_Y", I2D_DST_ADDR_Y}, ++ {"I2D_DST_ADDR_UV", I2D_DST_ADDR_UV}, ++ {"I2D_DST_Y_STRID", I2D_DST_Y_STRID}, ++ {"I2D_DST_UV_STRID", I2D_DST_UV_STRID}, ++ {"I2D_IRQ_STATE", I2D_IRQ_STATE}, ++ {"I2D_IRQ_CLEAR", I2D_IRQ_CLEAR}, ++ {"I2D_IRQ_MASK", I2D_IRQ_MASK}, ++ ++ {"I2D_TIMEOUT_VALUE", I2D_TIMEOUT_VALUE}, ++ {"I2D_TIMEOUT_MODE", I2D_TIMEOUT_MODE}, ++ {"I2D_CLK_GATE", I2D_CLK_GATE}, ++ {"I2D_DBG_0", I2D_DBG_0}, ++}; ++ ++ ++static void reg_bit_set(struct jz_i2d *i2d, int offset, unsigned int bit) ++{ ++ unsigned int reg = 0; ++ reg = reg_read(i2d, offset); ++ reg |= bit; ++ reg_write(i2d, offset, reg); ++} ++ ++static void reg_bit_clr(struct jz_i2d *i2d, int offset, unsigned int bit) ++{ ++ unsigned int reg = 0; ++ reg= reg_read(i2d, offset); ++ reg &= ~(bit); ++ reg_write(i2d, offset, reg); ++} ++ ++ ++static int _i2d_dump_regs(struct jz_i2d *i2d) ++{ ++ int i = 0; ++ int num = 0; ++ ++ if (i2d == NULL) { ++ dev_err(i2d->dev, "i2d is NULL!\n"); ++ return -1; ++ } ++ printk("----- dump regs -----\n"); ++ ++ num = sizeof(jz_i2d_regs_name) / sizeof(struct i2d_reg_struct); ++ for (i = 0; i < num; i++) { ++ printk("i2d_reg: %s: \t0x%08x\r\n", jz_i2d_regs_name[i].name, reg_read(i2d, jz_i2d_regs_name[i].addr)); ++ } ++ ++ return 0; ++} ++ ++static void _i2d_dump_param(struct jz_i2d *i2d) ++{ ++ return; ++} ++ ++static int i2d_dump_info(struct jz_i2d *i2d) ++{ ++ int ret = 0; ++ if (i2d == NULL) { ++ dev_err(i2d->dev, "i2d is NULL\n"); ++ return -1; ++ } ++ printk("i2d: i2d->base: %p\n", i2d->iomem); ++ _i2d_dump_param(i2d); ++ ret = _i2d_dump_regs(i2d); ++ ++ return ret; ++} ++ ++static int RoundUp(int iVal, int iRnd) ++{ ++ return (iVal + iRnd - 1) / iRnd * iRnd; ++} ++ ++static int i2d_reg_set(struct jz_i2d *i2d, struct i2d_param *i2d_param) ++{ ++ unsigned int fmt = 0; ++ unsigned int srcw = 0; ++ unsigned int srch = 0; ++ unsigned int flip_enable = 0, mirr_enable = 0, rotate_angle = 0, rotate_enable = 0; ++ unsigned int flip_mode = 0; ++ unsigned int value = 0; ++ ++ unsigned int src_y_pbuf = 0; ++ unsigned int src_uv_pbuf = 0; ++ unsigned int dst_y_pbuf = 0; ++ unsigned int dst_uv_pbuf = 0; ++ ++ unsigned int src_y_strid = 0; ++ unsigned int src_uv_strid = 0; ++ unsigned int dst_y_strid = 0; ++ unsigned int dst_uv_strid = 0; ++ ++ struct i2d_param *ip = i2d_param; ++ if (i2d == NULL) { ++ dev_err(i2d->dev, "i2d: i2d is NULL or i2d_param is NULL\n"); ++ return -1; ++ } ++ ++ fmt = ip->data_type; ++ srcw = ip->src_w; ++ srch = ip->src_h; ++ flip_enable = ip->flip_enable; ++ mirr_enable = ip->mirr_enable; ++ rotate_enable = ip->rotate_enable; ++ rotate_angle = ip->rotate_angle; ++ dst_y_strid = srcw; ++ dst_uv_strid = srcw; ++ switch(fmt) { ++ case PIX_FMT_NV12: ++ src_y_strid = srcw; ++ src_uv_strid = srcw; ++ if ((rotate_angle == 0) || (rotate_angle == 180) || (flip_enable == 1) || (mirr_enable == 1)) { ++ dst_y_strid = srcw; ++ dst_uv_strid = srcw; ++ } else if (((rotate_angle == 90) || (rotate_angle == 270)) && (rotate_enable == 1)) { ++ dst_y_strid = srch; ++ dst_uv_strid = srch; ++ } ++ reg_write(i2d, I2D_IMG_MODE, I2D_DATA_TYPE_NV12); ++ break; ++ case HAL_PIXEL_FORMAT_RAW8: ++ src_y_strid = srcw; ++ src_uv_strid = srcw; ++ if ((rotate_angle == 0) || (rotate_angle == 180) || (flip_enable == 1) || (mirr_enable == 1)) { ++ dst_y_strid = srcw; ++ dst_uv_strid = srcw; ++ } else if (((rotate_angle == 90) || (rotate_angle == 270)) && (rotate_enable == 1)) { ++ dst_y_strid = srch; ++ dst_uv_strid = srch; ++ } ++ reg_write(i2d, I2D_IMG_MODE, I2D_DATA_TYPE_RAW8); ++ break; ++ case HAL_PIXEL_FORMAT_RGB_565: ++ src_y_strid = srcw << 1; ++ src_uv_strid = srcw; ++ if ((rotate_angle == 0) || (rotate_angle == 180) || (flip_enable == 1) || (mirr_enable == 1)) { ++ dst_y_strid = srcw << 1; ++ dst_uv_strid = srcw; ++ } else if (((rotate_angle == 90) || (rotate_angle == 270)) && (rotate_enable == 1)) { ++ dst_y_strid = srch << 1; ++ dst_uv_strid = srch; ++ } ++ reg_write(i2d, I2D_IMG_MODE, I2D_DATA_TYPE_RGB565); ++ break; ++ case HAL_PIXEL_FORMAT_ARGB_8888: ++ src_y_strid = srcw << 2; ++ src_uv_strid = srcw; ++ if ((rotate_angle == 0) || (rotate_angle == 180) || (flip_enable == 1) || (mirr_enable == 1)) { ++ dst_y_strid = srcw << 2; ++ dst_uv_strid = srcw; ++ } else if (((rotate_angle == 90) || (rotate_angle == 270)) && (rotate_enable == 1)) { ++ dst_y_strid = srch << 2; ++ dst_uv_strid = srch; ++ } ++ reg_write(i2d, I2D_IMG_MODE, I2D_DATA_TYPE_ARGB8888); ++ break; ++ default: ++ src_y_strid = srcw; ++ src_uv_strid = srcw; ++ if ((rotate_angle == 0) || (rotate_angle == 180) || (flip_enable == 1) || (mirr_enable == 1)) { ++ dst_y_strid = srcw; ++ dst_uv_strid = srcw; ++ } else if (((rotate_angle == 90) || (rotate_angle == 270)) && (rotate_angle == 1)) { ++ dst_y_strid = srch; ++ dst_uv_strid = srch; ++ } ++ reg_write(i2d, I2D_IMG_MODE, I2D_DATA_TYPE_NV12); ++ break; ++ } ++ ++ ++#ifdef TIMEOUT_TEST ++ reg_write(i2d, I2D_TIMEOUT_MODE, (0 << 0)); //timeout mode 0:not restart 1:auto restart ++ reg_write(i2d, I2D_TIMEOUT_VALUE, (0x64 << 0)); //timeout value ++#endif ++ reg_write(i2d, I2D_IMG_SIZE, (srcw << I2D_WIDTH | srch << I2D_HEIGHT)); ++ // reg_write(i2d, I2D_IMG_MODE, I2D_DATA_TYPE_NV12); ++ reg_write(i2d, I2D_IMG_SIZE, (srcw << I2D_WIDTH | srch << I2D_HEIGHT)); ++ //reg_write(i2d, I2D_IMG_MODE, I2D_FLIP_MODE_90); ++ ++ if(rotate_enable == 1) { ++ unsigned int value = 0, tmp1 = 0; ++ ++ if(rotate_angle == 0) { ++ flip_mode = 0x00; ++ } else if(rotate_angle == 90) { ++ flip_mode = 0x04; ++ } else if(rotate_angle == 180) { ++ flip_mode = 0x08; ++ } else if(rotate_angle == 270) { ++ flip_mode = 0x0c; ++ } else { ++ printk("error: the rotate_angle not suppot!!!\n"); ++ return -1; ++ } ++ ++ value = flip_mode; ++ flip_mode = flip_mode & 0x00000004; ++ switch(flip_mode) { ++ case 0: ++ dst_uv_pbuf = ip->dst_addr_y + dst_y_strid*RoundUp(srch,I2D_ALIGNMENT); ++ tmp1 = reg_read(i2d, I2D_IMG_MODE); ++ value = (((~tmp1) & value) | value); ++ reg_write(i2d, I2D_IMG_MODE, value); ++ break; ++ case 4: ++ dst_uv_pbuf = ip->dst_addr_y + dst_y_strid*srcw; ++ tmp1 = reg_read(i2d, I2D_IMG_MODE); ++ value = (((~tmp1) & value) | value); ++ reg_write(i2d, I2D_IMG_MODE, value); ++ break; ++ default: ++ dst_uv_pbuf = ip->dst_addr_y + dst_y_strid*RoundUp(srch,I2D_ALIGNMENT); ++ tmp1 = reg_read(i2d, I2D_IMG_MODE); ++ value = (((~tmp1) & value) | value); ++ reg_write(i2d, I2D_IMG_MODE, value); ++ break; ++ } ++ } else { ++ dst_uv_pbuf = ip->dst_addr_y + dst_y_strid*RoundUp(srch,I2D_ALIGNMENT); ++ value = reg_read(i2d, I2D_IMG_MODE); ++ reg_write(i2d, I2D_IMG_MODE, value); ++ } ++ ++ ++ if(mirr_enable == 1) { ++ dst_uv_pbuf = ip->dst_addr_y + dst_y_strid*RoundUp(srch,I2D_ALIGNMENT); ++ value = reg_read(i2d, I2D_IMG_MODE); ++ reg_write(i2d, I2D_IMG_MODE, (value | I2D_MIRR)); ++ } ++ ++ if(flip_enable == 1) { ++ dst_uv_pbuf = ip->dst_addr_y + dst_y_strid*RoundUp(srch,I2D_ALIGNMENT); ++ value = reg_read(i2d, I2D_IMG_MODE); ++ reg_write(i2d, I2D_IMG_MODE, (value | I2D_FLIP)); ++ } ++ ++ ++ ++ src_y_pbuf = ip->src_addr_y; ++ //src_uv_pbuf = ip->src_addr_y + src_y_strid*srch; ++ src_uv_pbuf = ip->src_addr_y + src_y_strid*RoundUp(srch,I2D_ALIGNMENT);/*目前SDK的内存都是16对齐,因此这里也需要修改*/ ++ dst_y_pbuf = ip->dst_addr_y; ++ ++ reg_write(i2d, I2D_SRC_ADDR_Y, src_y_pbuf); ++ reg_write(i2d, I2D_SRC_ADDR_UV, src_uv_pbuf); ++ reg_write(i2d, I2D_DST_ADDR_Y, dst_y_pbuf); ++ reg_write(i2d, I2D_DST_ADDR_UV, dst_uv_pbuf); ++ ++ ++ reg_write(i2d, I2D_SRC_Y_STRID, src_y_strid); ++ reg_write(i2d, I2D_SRC_UV_STRID, src_uv_strid); ++ reg_write(i2d, I2D_DST_Y_STRID, dst_y_strid); ++ reg_write(i2d, I2D_DST_UV_STRID, dst_uv_strid); ++ ++ ++ return 0; ++} ++ ++static int i2d_start(struct jz_i2d *i2d, struct i2d_param *i2d_param) ++{ ++ int ret = 0; ++ struct i2d_param *ip = i2d_param; ++ if ((i2d == NULL) || (i2d_param == NULL)) { ++ dev_err(i2d->dev, "i2d: i2d is NULL or i2d_param is NULL\n"); ++ return -1; ++ } ++ I2D_DEBUG("i2d: enter i2d_start %d\n", current->pid); ++#ifndef CONFIG_FPGA_TEST ++ clk_prepare_enable(i2d->clk); ++#ifdef CONFIG_SOC_T40 ++ clk_prepare_enable(i2d->ahb0_gate); ++#endif ++#endif ++ __reset_safe_i2d(); ++ ++ ret = i2d_reg_set(i2d, ip); ++ __i2d_mask_irq();//mask 0 ++ ++ ++ reg_write(i2d, I2D_SHD_CTRL, 0xffffffff); ++ ++ ++ /* start i2d */ ++ __start_i2d(); ++ ++#ifdef DEBUG ++ i2d_dump_info(i2d); ++#endif ++ I2D_DEBUG("i2d_start\n"); ++ mutex_lock(&i2d->irq_mutex); ++ ret = wait_for_completion_interruptible_timeout(&i2d->done_i2d, msecs_to_jiffies(2000)); ++ if (ret < 0) { ++ printk("i2d: done_i2d wait_for_completion_interruptible_timeout err %d\n", ret); ++ mutex_unlock(&i2d->irq_mutex); ++ goto err_i2d_wait_for_done; ++ } else if (ret == 0) { ++ ret = -1; ++ printk("i2d: done_i2d wait_for_completion_interruptible_timeout timeout %d\n", ret); ++ i2d_dump_info(i2d); ++ mutex_unlock(&i2d->irq_mutex); ++ goto err_i2d_wait_for_done; ++ } else { ++ ; ++ } ++ mutex_unlock(&i2d->irq_mutex); ++ I2D_DEBUG("i2d: exit i2d_start %d\n", current->pid); ++ ++#ifndef CONFIG_FPGA_TEST ++#ifdef CONFIG_SOC_T40 ++ clk_disable_unprepare(i2d->ahb0_gate); ++#endif ++#endif ++ return 0; ++ ++err_i2d_wait_for_done: ++#ifndef CONFIG_FPGA_TEST ++#ifdef CONFIG_SOC_T40 ++ clk_disable_unprepare(i2d->ahb0_gate); ++#endif ++#endif ++ ++ return ret; ++ ++} ++ ++static int i2d_listen_buffer(struct jz_i2d *i2d, unsigned long arg) ++{ ++ int ret = 0; ++ int buffers = 0; ++ ++ ret = wait_for_completion_interruptible_timeout(&i2d->done_i2d, msecs_to_jiffies(10*1000)); ++ if (ret < 0) { ++ printk("i2d: done_i2d wait_for_completion_interruptible_timeout err %d\n", ret); ++ return -1; ++ } else if (ret == 0) { ++ ret = -1; ++ printk("i2d: done_i2d wait_for_completion_interruptible_timeout timeout %d\n", ret); ++ i2d_dump_info(i2d); ++ buffers = ret; ++ return -1; ++ } else { ++ buffers = 1; ++ } ++ ++ ret = copy_to_user((void __user *)arg, &buffers,sizeof(buffers)); ++ if (ret){ ++ printk("copy_to_user error!!\n"); ++ return -1; ++ } ++ return ret; ++} ++ ++void i2dgettimee(int64_t *ptime) ++{ ++ struct timeval sttime; ++ do_gettimeofday(&sttime); ++ *ptime = sttime.tv_sec * 1000000 + (sttime.tv_usec); ++ return ; ++} ++ ++ ++static long i2d_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ int ret = 0; ++ struct i2d_param iparam; ++ struct miscdevice *dev = filp->private_data; ++ struct jz_i2d *i2d = container_of(dev, struct jz_i2d, misc_dev); ++ int64_t time0 = 0,time1 = 0,time2 = 0; ++ I2D_DEBUG("i2d: %s pid: %d, tgid: %d file: %p, cmd: 0x%08x\n", ++ __func__, current->pid, current->tgid, filp, cmd); ++ ++ if (_IOC_TYPE(cmd) != JZI2D_IOC_MAGIC) { ++ dev_err(i2d->dev, "invalid cmd!\n"); ++ return -EFAULT; ++ } ++ ++ mutex_lock(&i2d->mutex); ++ switch (cmd) { ++ case IOCTL_I2D_START: ++ i2dgettimee(&time0); ++ if (copy_from_user(&iparam, (void *)arg, sizeof(struct i2d_param))) { ++ dev_err(i2d->dev, "copy_from_user error!!!\n"); ++ ret = -EFAULT; ++ break; ++ } ++ i2dgettimee(&time1); ++ ret = i2d_start(i2d, &iparam); ++ if (ret < 0) { ++ printk("i2d: error i2d start ret = %d\n", ret); ++ } ++ i2dgettimee(&time2); ++#ifdef I2DTIME ++ printk("*****time1-time0=(copyfrom:%lld),time2-time1=(i2dstart:%lld),total:%lld\n",time1-time0,time2-time1,time2-time0); ++#endif ++ break; ++ case IOCTL_I2D_LISTEN: ++ //return i2d_listen_buffer(i2d, arg); ++ break; ++ case IOCTL_I2D_GET_PBUFF: ++ if (i2d->pbuf.vaddr_alloc == 0) { ++ unsigned int size = I2D_BUF_SIZE; ++ i2d->pbuf.vaddr_alloc = (unsigned int)kmalloc(size, GFP_KERNEL); ++ if (!i2d->pbuf.vaddr_alloc) { ++ printk("i2d kmalloc is error\n"); ++ ret = -ENOMEM; ++ } ++ memset((void*)(i2d->pbuf.vaddr_alloc), 0x00, size); ++ i2d->pbuf.size = size; ++ i2d->pbuf.paddr = virt_to_phys((void *)(i2d->pbuf.vaddr_alloc)); ++ i2d->pbuf.paddr_align = ((unsigned long)(i2d->pbuf.paddr)); ++ } ++ I2D_DEBUG("i2d: %s i2d->pbuf.vaddr_alloc = 0x%08x\ni2d->pbuf.vaddr_align = 0x%08x\ni2d->pbuf.size = 0x%x\ni2d->pbuf.paddr = 0x%08x\n" ++ , __func__, i2d->pbuf.vaddr_alloc, i2d->pbuf.paddr_align, i2d->pbuf.size, i2d->pbuf.paddr); ++ if (copy_to_user((void *)arg, &i2d->pbuf, sizeof(struct i2d_buf_info))) { ++ dev_err(i2d->dev, "copy_to_user error!!!\n"); ++ ret = -EFAULT; ++ } ++ break; ++ case IOCTL_I2D_RES_PBUFF: ++ if (i2d->pbuf.vaddr_alloc != 0) { ++ kfree((void *)i2d->pbuf.vaddr_alloc); ++ i2d->pbuf.vaddr_alloc = 0; ++ i2d->pbuf.size = 0; ++ i2d->pbuf.paddr = 0; ++ i2d->pbuf.paddr_align = 0; ++ } else { ++ dev_warn(i2d->dev, "buffer wanted to free is null\n"); ++ } ++ break; ++ case IOCTL_I2D_BUF_FLUSH_CACHE: ++ { ++ struct i2d_flush_cache_para fc; ++ if (copy_from_user(&fc, (void *)arg, sizeof(fc))) { ++ dev_err(i2d->dev, "copy_from_user error!!!\n"); ++ ret = -EFAULT; ++ break; ++ } ++ //dma_sync_single_for_device(NULL, fc.addr, fc.size, DMA_TO_DEVICE); ++ //dma_sync_single_for_device(NULL, fc.addr, fc.size, DMA_FROM_DEVICE); ++ dma_cache_sync(NULL, fc.addr, fc.size, DMA_BIDIRECTIONAL); ++ } ++ break; ++ default: ++ dev_err(i2d->dev, "invalid command: 0x%08x\n", cmd); ++ ret = -EINVAL; ++ } ++ ++ mutex_unlock(&i2d->mutex); ++ return ret; ++} ++ ++static int i2d_open(struct inode *inode, struct file *filp) ++{ ++ int ret = 0; ++ ++ struct miscdevice *dev = filp->private_data; ++ struct jz_i2d *i2d = container_of(dev, struct jz_i2d, misc_dev); ++ ++ I2D_DEBUG("i2d: %s pid: %d, tgid: %d filp: %p\n", ++ __func__, current->pid, current->tgid, filp); ++ mutex_lock(&i2d->mutex); ++ ++ mutex_unlock(&i2d->mutex); ++ return ret; ++} ++ ++static int i2d_release(struct inode *inode, struct file *filp) ++{ ++ int ret = 0; ++ ++ struct miscdevice *dev = filp->private_data; ++ struct jz_i2d *i2d = container_of(dev, struct jz_i2d, misc_dev); ++ ++ I2D_DEBUG("i2d: %s pid: %d, tgid: %d filp: %p\n", ++ __func__, current->pid, current->tgid, filp); ++ mutex_lock(&i2d->mutex); ++ ++ mutex_unlock(&i2d->mutex); ++ return ret; ++} ++ ++static struct file_operations i2d_ops = { ++ .owner = THIS_MODULE, ++ .open = i2d_open, ++ .release = i2d_release, ++ .unlocked_ioctl = i2d_ioctl, ++}; ++ ++int ttt = 0; ++ ++static irqreturn_t i2d_irq_handler(int irq, void *data) ++{ ++ struct jz_i2d *i2d; ++ unsigned int status; ++ ++ I2D_DEBUG("i2d: %s\n", __func__); ++ i2d = (struct jz_i2d *)data; ++ ++ status = reg_read(i2d, I2D_IRQ_STATE); ++ ++ __i2d_irq_clear(status); ++ ++ I2D_DEBUG("----- %s, status= 0x%08x\n", __func__, status); ++ /* this status doesn't do anything including trigger interrupt, ++ * just give a hint */ ++ if (status & 0x1){ ++ complete(&i2d->done_i2d); ++ } ++ ++ /*timeout 10 times,let timeout value 0xffffffff,this can normal run handler*/ ++ // if (status & 0x2){ ++ //if(ttt > 10){ ++ // reg_write(i2d, I2D_TIMEOUT_VALUE, 0xfffffff); //timeout value ++ //}else{ ++ // ttt++; ++ //} ++ //} ++ return IRQ_HANDLED; ++} ++ ++static int i2d_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ struct jz_i2d *i2d; ++ int rc = 0; ++ ++ I2D_DEBUG("%s\n", __func__); ++ i2d = (struct jz_i2d *)devm_kzalloc(&pdev->dev, sizeof(struct jz_i2d), GFP_KERNEL); ++ if (!i2d) { ++ dev_err(&pdev->dev, "alloc jz_i2d failed!\n"); ++ return -ENOMEM; ++ } ++ ++ sprintf(i2d->name, "i2d"); ++ ++ i2d->misc_dev.minor = MISC_DYNAMIC_MINOR; ++ i2d->misc_dev.name = i2d->name; ++ i2d->misc_dev.fops = &i2d_ops; ++ i2d->dev = &pdev->dev; ++ ++ mutex_init(&i2d->mutex); ++ mutex_init(&i2d->irq_mutex); ++ init_completion(&i2d->done_i2d); ++ init_completion(&i2d->done_buf); ++ complete(&i2d->done_buf); ++ ++ i2d->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!i2d->res) { ++ dev_err(&pdev->dev, "failed to get dev resources: %d\n", ret); ++ ret = -EINVAL; ++ } ++ ++ pdev->id = of_alias_get_id(pdev->dev.of_node, "i2d"); ++ ++ i2d->iomem = devm_ioremap_resource(&pdev->dev, i2d->res); ++ if (IS_ERR(i2d->iomem)) { ++ dev_err(&pdev->dev, "failed to map io baseaddress. \n"); ++ ret = -ENODEV; ++ goto err_ioremap; ++ } ++ ++ i2d->irq = platform_get_irq(pdev, 0); ++ if (devm_request_irq(&pdev->dev, i2d->irq, i2d_irq_handler, IRQF_SHARED, i2d->name, i2d)) { ++ dev_err(&pdev->dev, "request irq failed\n"); ++ ret = -EINVAL; ++ goto err_req_irq; ++ } ++ ++#ifndef CONFIG_FPGA_TEST ++ i2d->clk = devm_clk_get(i2d->dev, "gate_i2d"); ++ if (IS_ERR(i2d->clk)) { ++ dev_err(&pdev->dev, "i2d clk get failed!\n"); ++ goto err_get_i2d_clk; ++ } ++ ++#ifdef CONFIG_SOC_T40 ++ i2d->ahb0_gate = devm_clk_get(i2d->dev, "gate_ahb0"); ++ if (IS_ERR(i2d->clk)) { ++ dev_err(&pdev->dev, "i2d clk get failed!\n"); ++ goto err_get_ahb_clk; ++ } ++#endif ++#endif ++ ++ if ((rc = clk_prepare_enable(i2d->clk)) < 0) { ++ dev_err(&pdev->dev, "Enable i2d gate clk failed\n"); ++ goto err_prepare_i2d_clk; ++ } ++ if ((rc = clk_prepare_enable(i2d->ahb0_gate)) < 0) { ++ dev_err(&pdev->dev, "Enable i2d ahb0 clk failed\n"); ++ goto err_prepare_ahb_clk; ++ } ++ ++ dev_set_drvdata(&pdev->dev, i2d); ++ ++ __reset_safe_i2d(); ++ ++ ret = misc_register(&i2d->misc_dev); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "register misc device failed!\n"); ++ goto err_set_drvdata; ++ } ++ ++ return 0; ++ ++err_set_drvdata: ++ devm_free_irq(&pdev->dev, i2d->irq, i2d); ++err_get_i2d_clk: ++ devm_clk_put(&pdev->dev, i2d->clk); ++err_get_ahb_clk: ++ devm_clk_put(&pdev->dev, i2d->ahb0_gate); ++err_prepare_i2d_clk: ++ clk_disable_unprepare(i2d->clk); ++err_prepare_ahb_clk: ++ clk_disable_unprepare(i2d->ahb0_gate); ++err_req_irq: ++ devm_free_irq(&pdev->dev, i2d->irq, i2d); ++err_ioremap: ++ devm_iounmap(&pdev->dev, i2d->iomem); ++ kfree(i2d); ++ ++ return ret; ++} ++ ++static int i2d_remove(struct platform_device *pdev) ++{ ++ int ret = 0; ++ struct jz_i2d *i2d; ++ I2D_DEBUG("%s\n", __func__); ++ ++ i2d = dev_get_drvdata(&pdev->dev); ++ ++ free_irq(i2d->irq, i2d); ++ ++ devm_iounmap(&pdev->dev, i2d->iomem); ++ ++ misc_deregister(&i2d->misc_dev); ++ if (ret < 0) { ++ dev_err(i2d->dev, "misc_deregister error %d\n", ret); ++ return ret; ++ } ++ ++ if (i2d->pbuf.vaddr_alloc) { ++ kfree((void *)(i2d->pbuf.vaddr_alloc)); ++ i2d->pbuf.vaddr_alloc = 0; ++ } ++ ++ clk_disable_unprepare(i2d->clk); ++ ++ clk_disable_unprepare(i2d->ahb0_gate); ++ ++ if (i2d) { ++ kfree(i2d); ++ } ++ ++ return 0; ++} ++ ++static const struct of_device_id ingenic_i2d_dt_match[] = { ++ { .compatible = "ingenic,t40-i2d", .data = NULL }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ingenic_i2d_dt_match); ++ ++static struct platform_driver jz_i2d_driver = { ++ .probe = i2d_probe, ++ .remove = i2d_remove, ++ .driver = { ++ .name = "jz-i2d", ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(ingenic_i2d_dt_match), ++ }, ++}; ++ ++module_platform_driver(jz_i2d_driver) ++ ++MODULE_DESCRIPTION("JZ I2D driver"); ++MODULE_AUTHOR("jiansheng.zhang "); ++MODULE_LICENSE("GPL"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_i2d_ingenic_i2d.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_i2d_ingenic_i2d.h.patch new file mode 100644 index 00000000..17752b52 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_i2d_ingenic_i2d.h.patch @@ -0,0 +1,293 @@ +diff -drupN a/drivers/video/ingenic_i2d/ingenic_i2d.h b/drivers/video/ingenic_i2d/ingenic_i2d.h +--- a/drivers/video/ingenic_i2d/ingenic_i2d.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/ingenic_i2d/ingenic_i2d.h 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,289 @@ ++#ifndef __I2D__H__ ++#define __I2D__H__ ++ ++ ++ ++#define I2D_BASE 0xB30B0000 ++ ++#define I2D_RTL_VERSION 0x00 ++#define I2D_SHD_CTRL 0x08 ++#define I2D_CTRL 0x10 ++#define I2D_IMG_SIZE 0x14 ++#define I2D_IMG_MODE 0x18 ++#define I2D_SRC_ADDR_Y 0x20 ++#define I2D_SRC_ADDR_UV 0x24 ++#define I2D_SRC_Y_STRID 0x28 ++#define I2D_SRC_UV_STRID 0x2C ++#define I2D_DST_ADDR_Y 0x30 ++#define I2D_DST_ADDR_UV 0x34 ++#define I2D_DST_Y_STRID 0x38 ++#define I2D_DST_UV_STRID 0x3C ++#define I2D_IRQ_STATE 0x80 ++#define I2D_IRQ_CLEAR 0x84 ++#define I2D_IRQ_MASK 0x88 ++#define I2D_TIMEOUT_VALUE 0x90 ++#define I2D_TIMEOUT_MODE 0x94 ++#define I2D_CLK_GATE 0x98 ++#define I2D_DBG_0 0xA0 ++ ++#define u32 unsigned int ++ ++struct i2d_reg_struct { ++ char *name; ++ unsigned int addr; ++}; ++ ++struct i2d_buf_info { ++ unsigned int vaddr_alloc; ++ unsigned int paddr; ++ unsigned int paddr_align; ++ unsigned int size; ++}; ++ ++struct jz_i2d { ++ ++ int irq; ++ char name[16]; ++ ++ struct clk *clk; ++ struct clk *ahb0_gate; /* T31 IPU mount at AHB1*/ ++ void __iomem *iomem; ++ struct device *dev; ++ struct resource *res; ++ struct miscdevice misc_dev; ++ ++ struct mutex mutex; ++ struct mutex irq_mutex; ++ struct completion done_i2d; ++ struct completion done_buf; ++ struct i2d_buf_info pbuf; ++}; ++ ++struct i2d_flush_cache_para ++{ ++ void *addr; ++ unsigned int size; ++}; ++ ++struct i2d_param ++{ ++ unsigned int src_w; ++ unsigned int src_h; ++ unsigned int data_type; ++ unsigned int rotate_enable; ++ unsigned int rotate_angle; ++ unsigned int flip_enable; ++ unsigned int mirr_enable; ++ ++ unsigned int src_addr_y; ++ unsigned int src_addr_uv; ++ unsigned int dst_addr_y; ++ unsigned int dst_addr_uv; ++ ++ unsigned int src_y_strid; ++ unsigned int src_uv_strid; ++ unsigned int dst_y_strid; ++ unsigned int dst_uv_strid; ++ ++}; ++ ++enum ++{ ++ FLIP_MODE_0_DEGREE = 1, ++ FLIP_MODE_90_DEGREE = 2, ++ FLIP_MODE_180_DEGREE = 3, ++ FLIP_MODE_270_DEGREE = 4, ++ FLIP_MODE_MIRR = 5, ++ FLIP_MODE_FLIP = 6, ++}; ++ ++/* match HAL_PIXEL_FORMAT_ in system/core/include/system/graphics.h */ ++enum { ++ HAL_PIXEL_FORMAT_RGBA_8888 = 1, ++ HAL_PIXEL_FORMAT_RGBX_8888 = 2, ++ HAL_PIXEL_FORMAT_RGB_888 = 3, ++ HAL_PIXEL_FORMAT_RGB_565 = 4, ++ HAL_PIXEL_FORMAT_BGRA_8888 = 5, ++ //HAL_PIXEL_FORMAT_BGRX_8888 = 0x8000, /* Add BGRX_8888, Wolfgang, 2010-07-24 */ ++ HAL_PIXEL_FORMAT_BGRX_8888 = 0x1ff, /* 2012-10-23 */ ++ HAL_PIXEL_FORMAT_RGBA_5551 = 6, ++ HAL_PIXEL_FORMAT_RGBA_4444 = 7, ++ HAL_PIXEL_FORMAT_ABGR_8888 = 8, ++ HAL_PIXEL_FORMAT_ARGB_8888 = 9, ++ HAL_PIXEL_FORMAT_YCbCr_422_SP = 0x10, ++ HAL_PIXEL_FORMAT_YCbCr_420_SP = 0x11, ++ HAL_PIXEL_FORMAT_YCbCr_422_P = 0x12, ++ HAL_PIXEL_FORMAT_YCbCr_420_P = 0x13, ++ HAL_PIXEL_FORMAT_YCbCr_420_B = 0x24, ++ HAL_PIXEL_FORMAT_YCbCr_422_I = 0x14, ++ HAL_PIXEL_FORMAT_YCbCr_420_I = 0x15, ++ HAL_PIXEL_FORMAT_CbYCrY_422_I = 0x16, ++ HAL_PIXEL_FORMAT_CbYCrY_420_I = 0x17, ++ HAL_PIXEL_FORMAT_NV12 = 0x18, ++ HAL_PIXEL_FORMAT_NV21 = 0x19, ++ HAL_PIXEL_FORMAT_BGRA_5551 = 0x1a, ++ HAL_PIXEL_FORMAT_RAW8 = 0x1b, ++ ++}; ++ ++/** ++ * IMP图像格式定义. ++ */ ++typedef enum { ++ PIX_FMT_YUV420P, /**< planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples) */ ++ PIX_FMT_YUYV422, /**< packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr */ ++ PIX_FMT_UYVY422, /**< packed YUV 4:2:2, 16bpp, Cb Y0 Cr Y1 */ ++ PIX_FMT_YUV422P, /**< planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples) */ ++ PIX_FMT_YUV444P, /**< planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples) */ ++ PIX_FMT_YUV410P, /**< planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples) */ ++ PIX_FMT_YUV411P, /**< planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples) */ ++ PIX_FMT_GRAY8, /**< Y , 8bpp */ ++ PIX_FMT_MONOWHITE, /**< Y , 1bpp, 0 is white, 1 is black, in each byte pixels are ordered from the msb to the lsb */ ++ PIX_FMT_MONOBLACK, /**< Y , 1bpp, 0 is black, 1 is white, in each byte pixels are ordered from the msb to the lsb */ ++ ++ PIX_FMT_NV12, /**< planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (first byte U and the following byte V) */ ++ PIX_FMT_NV21, /**< as above, but U and V bytes are swapped */ ++ ++ PIX_FMT_RGB24, /**< packed RGB 8:8:8, 24bpp, RGBRGB... */ ++ PIX_FMT_BGR24, /**< packed RGB 8:8:8, 24bpp, BGRBGR... */ ++ ++ PIX_FMT_ARGB, /**< packed ARGB 8:8:8:8, 32bpp, ARGBARGB... */ ++ PIX_FMT_RGBA, /**< packed RGBA 8:8:8:8, 32bpp, RGBARGBA... */ ++ PIX_FMT_ABGR, /**< packed ABGR 8:8:8:8, 32bpp, ABGRABGR... */ ++ PIX_FMT_BGRA, /**< packed BGRA 8:8:8:8, 32bpp, BGRABGRA... */ ++ ++ PIX_FMT_RGB565BE, /**< packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), big-endian */ ++ PIX_FMT_RGB565LE, /**< packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), little-endian */ ++ PIX_FMT_RGB555BE, /**< packed RGB 5:5:5, 16bpp, (msb)1A 5R 5G 5B(lsb), big-endian, most significant bit to 0 */ ++ PIX_FMT_RGB555LE, /**< packed RGB 5:5:5, 16bpp, (msb)1A 5R 5G 5B(lsb), little-endian, most significant bit to 0 */ ++ ++ PIX_FMT_BGR565BE, /**< packed BGR 5:6:5, 16bpp, (msb) 5B 6G 5R(lsb), big-endian */ ++ PIX_FMT_BGR565LE, /**< packed BGR 5:6:5, 16bpp, (msb) 5B 6G 5R(lsb), little-endian */ ++ PIX_FMT_BGR555BE, /**< packed BGR 5:5:5, 16bpp, (msb)1A 5B 5G 5R(lsb), big-endian, most significant bit to 1 */ ++ PIX_FMT_BGR555LE, /**< packed BGR 5:5:5, 16bpp, (msb)1A 5B 5G 5R(lsb), little-endian, most significant bit to 1 */ ++ ++ PIX_FMT_0RGB, /**< packed RGB 8:8:8, 32bpp, 0RGB0RGB... */ ++ PIX_FMT_RGB0, /**< packed RGB 8:8:8, 32bpp, RGB0RGB0... */ ++ PIX_FMT_0BGR, /**< packed BGR 8:8:8, 32bpp, 0BGR0BGR... */ ++ PIX_FMT_BGR0, /**< packed BGR 8:8:8, 32bpp, BGR0BGR0... */ ++ ++ PIX_FMT_BAYER_BGGR8, /**< bayer, BGBG..(odd line), GRGR..(even line), 8-bit samples */ ++ PIX_FMT_BAYER_RGGB8, /**< bayer, RGRG..(odd line), GBGB..(even line), 8-bit samples */ ++ PIX_FMT_BAYER_GBRG8, /**< bayer, GBGB..(odd line), RGRG..(even line), 8-bit samples */ ++ PIX_FMT_BAYER_GRBG8, /**< bayer, GRGR..(odd line), BGBG..(even line), 8-bit samples */ ++ ++ PIX_FMT_RAW, ++ ++ PIX_FMT_HSV, ++ ++ PIX_FMT_NB, ++ PIX_FMT_YUV422, ++ PIX_FMT_YVU422, ++ PIX_FMT_UVY422, ++ PIX_FMT_VUY422, ++ PIX_FMT_RAW8, ++ PIX_FMT_RAW16, ++} IMPPixelFormat; ++ ++ ++#define JZI2D_IOC_MAGIC 'D' ++#define IOCTL_I2D_START _IO(JZI2D_IOC_MAGIC, 106) ++#define IOCTL_I2D_LISTEN _IO(JZI2D_IOC_MAGIC, 116) ++#define IOCTL_I2D_RES_PBUFF _IO(JZI2D_IOC_MAGIC, 114) ++#define IOCTL_I2D_GET_PBUFF _IO(JZI2D_IOC_MAGIC, 115) ++#define IOCTL_I2D_BUF_UNLOCK _IO(JZI2D_IOC_MAGIC, 117) ++#define IOCTL_I2D_BUF_FLUSH_CACHE _IO(JZI2D_IOC_MAGIC, 118) ++ ++/* VERSION*/ ++#define I2D_VERSION (1 << 0) ++ ++/* SHD_CTRL */ ++#define I2D_MODE_SHADOW (1 << 1) ++ ++/* SHD_CTRL */ ++#define I2D_MODE_SHADOW (1 << 1) ++#define I2D_ADDR_SHADOW (1 << 0) ++ ++/* CTRL */ ++#define I2D_RESET (1 << 16) ++#define I2D_SAFE_RESET (1 << 4) ++#define I2D_START (1 << 0) ++ ++/* IMG_SIZE */ ++#define I2D_WIDTH (16) ++#define I2D_HEIGHT (0) ++ ++/* I2D_MODE */ ++#define I2D_DATA_TYPE (4) ++#define I2D_DATA_TYPE_NV12 (0 << I2D_DATA_TYPE) ++#define I2D_DATA_TYPE_RAW8 (1 << I2D_DATA_TYPE) ++#define I2D_DATA_TYPE_RGB565 (2 << I2D_DATA_TYPE) ++#define I2D_DATA_TYPE_ARGB8888 (3 << I2D_DATA_TYPE) ++ ++#define I2D_FLIP_MODE (2) ++#define I2D_FLIP_MODE_0 (0 << I2D_FLIP_MODE) ++#define I2D_FLIP_MODE_90 (1 << I2D_FLIP_MODE) ++#define I2D_FLIP_MODE_180 (2 << I2D_FLIP_MODE) ++#define I2D_FLIP_MODE_270 (3 << I2D_FLIP_MODE) ++ ++#define I2D_MIRR (1 << 1) ++#define I2D_FLIP (1 << 0) ++ ++/* SRC_ADDR_Y */ ++#define I2D_SRC_Y (0) ++ ++/* SRC_ADDR_UV */ ++#define I2D_SRC_UV (0) ++ ++/* SRC_Y_STRID */ ++#define I2D_SRC_STRID_Y (0) ++ ++/* SRC_UV_STRID */ ++#define I2D_SRC_STRID_UV (0) ++ ++/* DST_ADDR_Y */ ++#define I2D_DST_Y (0) ++ ++/* DST_ADDR_UV */ ++#define I2D_DST_UV (0) ++ ++/* DST_Y_STRID */ ++#define I2D_DST_STRID_Y (0) ++ ++/* DST_UV_STRID */ ++#define I2D_DST_STRID_UV (0) ++ ++/* IRQ_STATE */ ++#define I2D_IRQ_TIMEOUT (1) ++#define I2D_IRQ_FRAME_DONE (0) ++ ++/* IRQ_CLEAR */ ++#define I2D_IRQ_TIMEOUT_CLR (1 << 1) ++#define I2D_IRQ_FRAME_DONE_CLR (1 << 0) ++ ++/* IRQ_MASK */ ++#define I2D_IRQ_TIMEOUT_MASK (0 << 1) ++#define I2D_IRQ_FRAME_DONE_MASK (0 << 0) ++ ++/* TIMEOUT_MODE */ ++#define I2D_TIMEOUT_RST (0) ++ ++ ++static inline unsigned int reg_read(struct jz_i2d *jzi2d, int offset) ++{ ++ return readl(jzi2d->iomem + offset); ++} ++ ++static inline void reg_write(struct jz_i2d *jzi2d, int offset, unsigned int val) ++{ ++ writel(val, jzi2d->iomem + offset); ++} ++ ++#define __i2d_mask_irq() reg_bit_set(i2d, I2D_IRQ_MASK, (I2D_IRQ_TIMEOUT_MASK | I2D_IRQ_FRAME_DONE_MASK)) ++#define __i2d_irq_clear(value) reg_bit_set(i2d, I2D_IRQ_CLEAR, value) ++ ++#define __start_i2d() reg_bit_set(i2d, I2D_CTRL, I2D_START) ++#define __reset_safe_i2d() reg_bit_set(i2d, I2D_CTRL, I2D_SAFE_RESET) ++#define __reset_i2d() reg_bit_set(i2d, I2D_CTRL, I2D_RESET) ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_ipu_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_ipu_Kconfig.patch new file mode 100644 index 00000000..d22a1195 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_ipu_Kconfig.patch @@ -0,0 +1,16 @@ +diff -drupN a/drivers/video/ingenic_ipu/Kconfig b/drivers/video/ingenic_ipu/Kconfig +--- a/drivers/video/ingenic_ipu/Kconfig 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/ingenic_ipu/Kconfig 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,12 @@ ++menuconfig JZ_IPU ++ bool "JZ IPU Driver" ++ default y ++ help ++ Support for Ingenic dmmu operations. ++ ++config INGENIC_IPU_V13 ++ bool "IPU V13 Driver" ++ depends on JZ_IPU ++ default y ++ help ++ Support for Ingenic ipu v13 operations. diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_ipu_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_ipu_Makefile.patch new file mode 100644 index 00000000..233d5ad5 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_ipu_Makefile.patch @@ -0,0 +1,5 @@ +diff -drupN a/drivers/video/ingenic_ipu/Makefile b/drivers/video/ingenic_ipu/Makefile +--- a/drivers/video/ingenic_ipu/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/ingenic_ipu/Makefile 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1 @@ ++obj-$(CONFIG_INGENIC_IPU_V13) += ingenic_ipu_v13.o ingenic_drawbox.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_ipu_ingenic_drawbox.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_ipu_ingenic_drawbox.c.patch new file mode 100644 index 00000000..d9dce614 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_ipu_ingenic_drawbox.c.patch @@ -0,0 +1,601 @@ +diff -drupN a/drivers/video/ingenic_ipu/ingenic_drawbox.c b/drivers/video/ingenic_ipu/ingenic_drawbox.c +--- a/drivers/video/ingenic_ipu/ingenic_drawbox.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/ingenic_ipu/ingenic_drawbox.c 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,597 @@ ++/* ++ * Copyright (c) 2015 Ingenic Semiconductor Co., Ltd. ++ * http://www.ingenic.com/ ++ * ++ * Input file for Ingenic DBOX driver ++ * ++ * 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. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "ingenic_drawbox.h" ++ ++// #define DEBUG ++#ifdef DEBUG ++static int debug_dbox = 1; ++ ++#define DBOX_DEBUG(format, ...) { if (debug_dbox) printk(format, ## __VA_ARGS__);} ++#else ++#define DBOX_DEBUG(format, ...) do{ } while(0) ++#endif ++ ++#define DBOX_BUF_SIZE (1024 * 1024 * 2) ++ ++#define ALIGN_DOWN(x, a) ( ( (x) / (a)) * (a) ) ++ ++struct dbox_reg_struct jz_dbox_regs_name[] = { ++ {"DBOX_CTRL", DBOX_CTRL}, ++ {"DBOX_YB", DBOX_YB}, ++ {"DBOX_CB", DBOX_CB}, ++ {"DBOX_STRIDE", DBOX_STRIDE}, ++ {"DBOX_IMG_WH", DBOX_IMG_WH}, ++ {"DBOX_COLOR_Y", DBOX_COLOR_Y}, ++ {"DBOX_COLOR_U", DBOX_COLOR_U}, ++ {"DBOX_COLOR_V", DBOX_COLOR_V}, ++ {"DBOX_RAM", DBOX_RAM}, ++ {"DBOX_TIMEOUT", DBOX_TIMEOUT}, ++}; ++ ++ ++static void reg_bit_set(struct jz_dbox *dbox, int offset, unsigned int bit) ++{ ++ unsigned int reg = 0; ++ reg = dbox_reg_read(dbox, offset); ++ reg |= bit; ++ dbox_reg_write(dbox, offset, reg); ++} ++ ++static void reg_bit_clr(struct jz_dbox *dbox, int offset, unsigned int bit) ++{ ++ unsigned int reg = 0; ++ reg= dbox_reg_read(dbox, offset); ++ reg &= ~(bit); ++ dbox_reg_write(dbox, offset, reg); ++} ++ ++ ++static int _dbox_dump_regs(struct jz_dbox *dbox) ++{ ++ int i = 0; ++ int num = 0; ++ ++ if (dbox == NULL) { ++ dev_err(dbox->dev, "dbox is NULL!\n"); ++ return -1; ++ } ++ printk("----- dump regs -----\n"); ++ ++ num = sizeof(jz_dbox_regs_name) / sizeof(struct dbox_reg_struct); ++ for (i = 0; i < num; i++) { ++ printk("dbox_reg: %s: \t0x%08x\r\n", jz_dbox_regs_name[i].name, dbox_reg_read(dbox, jz_dbox_regs_name[i].addr)); ++ } ++ ++ return 0; ++} ++ ++static void _dbox_dump_param(struct jz_dbox *dbox) ++{ ++ return; ++} ++ ++static int dbox_dump_info(struct jz_dbox *dbox) ++{ ++ int ret = 0; ++ if (dbox == NULL) { ++ dev_err(dbox->dev, "dbox is NULL\n"); ++ return -1; ++ } ++ printk("dbox: dbox->base: %p\n", dbox->iomem); ++ _dbox_dump_param(dbox); ++ ret = _dbox_dump_regs(dbox); ++ ++ return ret; ++} ++ ++static int dbox_reg_set(struct jz_dbox *dbox, struct dbox_param *dbox_param) ++{ ++ unsigned int imgw = 0; ++ unsigned int imgh = 0; ++ unsigned int rectw[128]; ++ unsigned int recth[128]; ++ unsigned int rectx[128]; ++ unsigned int recty[128]; ++ unsigned int linew[128]; ++ unsigned int linel[128]; ++ // unsigned int imgstride = 0; ++ unsigned int img_pbuf_y = 0; ++ unsigned int img_pbuf_uv = 0; ++ unsigned int boxs_num = 0; ++ unsigned int is_rgba = 0; ++ unsigned int i = 0; ++ ++ unsigned int dbox_colormode[128]; ++ unsigned int dbox_mode[128]; ++ ++ ++ struct dbox_param *ip = dbox_param; ++ if (dbox == NULL) { ++ dev_err(dbox->dev, "dbox: dbox is NULL or dbox_param is NULL\n"); ++ return -1; ++ } ++ ++ img_pbuf_y = ip->box_pbuf; ++ ++ imgw = ip->img_w; ++ imgh = ip->img_h; ++ boxs_num = ip->boxs_num; ++ is_rgba = ip->is_rgba; ++ ++ if (1 == is_rgba) { ++ reg_bit_set(dbox, DBOX_CTRL, DBOX_IS_BGRA); ++ } else { ++ reg_bit_clr(dbox, DBOX_CTRL, DBOX_IS_BGRA); ++ } ++ ++ img_pbuf_y = ip->box_pbuf; ++ img_pbuf_uv = img_pbuf_y + imgw*imgh; ++ //printk("imgw = %d imgh = %d\n", imgw, imgh); ++ ++ dbox_reg_write(dbox, DBOX_IMG_WH, (imgw << DBOX_WIDTH | imgh << DBOX_HEIGHT)); ++ ++ dbox_reg_write(dbox, DBOX_STRIDE, ((imgw << DBOX_Y_STRIDE) | (imgw << DBOX_C_STRIDE)) ); ++ ++ /* YUV[0] is red ++ * YUV[1] is black ++ * YUV[2] is green ++ * YUV[3] is yellow ++ * rgb2yuv ==> https://www.mikekohn.net/file_formats/yuv_rgb_converter.php */ ++ dbox_reg_write(dbox, DBOX_COLOR_Y, 0xe195004c); ++ dbox_reg_write(dbox, DBOX_COLOR_U, 0x002b8054); ++ dbox_reg_write(dbox, DBOX_COLOR_V, 0x941580ff); ++ ++ dbox_reg_write(dbox, DBOX_YB, (img_pbuf_y << DBOX_LUMA_BASE)); ++ dbox_reg_write(dbox, DBOX_CB, (img_pbuf_uv << DBOX_CONCENTRATION_BASE)); ++ ++ for(i=0; iram_para[i].box_x, 4); ++ recty[i] = ALIGN_DOWN(ip->ram_para[i].box_y, 4); ++ rectw[i] = ALIGN_DOWN(ip->ram_para[i].box_w, 4); ++ recth[i] = ALIGN_DOWN(ip->ram_para[i].box_h, 4); ++ linew[i] = ip->ram_para[i].line_w; ++ linel[i] = ALIGN_DOWN(ip->ram_para[i].line_l, 4); ++ dbox_mode[i] = ip->ram_para[i].box_mode; ++ dbox_colormode[i] = ip->ram_para[i].color_mode; ++ dbox_reg_write(dbox, DBOX_RAM, (rectx[i] << DBOX_BOX_X) | (recty[i] << DBOX_BOX_Y) | (rectw[i] << DBOX_BOX_WIDTH)); ++ dbox_reg_write(dbox, DBOX_RAM, (((rectw[i] >> 8) << 0) | (recth[i] << 4) | (dbox_colormode[i] << 16) | (dbox_mode[i] << 18) | (linew[i] << 20) | (linel[i] << 23))); ++ } ++ ++ return 0; ++} ++ ++static int dbox_start(struct jz_dbox *dbox, struct dbox_param *dbox_param) ++{ ++ int ret = 0; ++ int retry_flag = 0; ++ struct dbox_param *ip = dbox_param; ++ ++ if ((dbox == NULL) || (dbox_param == NULL)) { ++ dev_err(dbox->dev, "dbox: dbox is NULL or dbox_param is NULL\n"); ++ return -1; ++ } ++ DBOX_DEBUG("dbox: enter dbox_start %d\n", current->pid); ++ ++#ifndef CONFIG_FPGA_TEST ++ clk_prepare_enable(dbox->clk); ++#ifdef CONFIG_SOC_T40 ++ clk_prepare_enable(dbox->ahb0_gate); ++#endif ++#endif ++ ++ __reset_dbox(); ++ /* wait reset complete */ ++ while(dbox_reg_read(dbox, DBOX_CTRL) & 0x2) { ++ udelay(10); ++ } ++ ++ ret = dbox_reg_set(dbox, ip); ++ __dbox_mask_irq();//mask 0 ++ ++ ++ DBOX_DEBUG("dbox_start\n"); ++ /* start dbox */ ++ __start_dbox(); ++ ++#ifdef DEBUG ++ //dbox_dump_info(dbox); ++#endif ++ //DBOX_DEBUG("dbox_start\n"); ++retry: ++ ret = wait_for_completion_interruptible_timeout(&dbox->done_dbox, msecs_to_jiffies(5000)); ++ if (ret < 0) { ++ printk("dbox: done_dbox wait_for_completion_interruptible_timeout err %d\n", ret); ++ if(retry_flag == 0) { ++ retry_flag++; ++ printk("dbox_start retry\n"); ++ goto retry; ++ } else { ++ goto err_dbox_wait_for_done; ++ } ++ } else if (ret == 0 ) { ++ ret = -1; ++ printk("dbox: done_dbox wait_for_completion_interruptible_timeout timeout %d\n", ret); ++ dbox_dump_info(dbox); ++ goto err_dbox_wait_for_done; ++ } else { ++ ; ++ } ++ ++ DBOX_DEBUG("dbox: exit dbox_start %d\n", current->pid); ++ ++#ifndef CONFIG_FPGA_TEST ++ clk_disable_unprepare(dbox->clk); ++#ifdef CONFIG_SOC_T40 ++ clk_disable_unprepare(dbox->ahb0_gate); ++#endif ++#endif ++ ++ return 0; ++ ++err_dbox_wait_for_done: ++#ifndef CONFIG_FPGA_TEST ++ clk_disable_unprepare(dbox->clk); ++#ifdef CONFIG_SOC_T40 ++ clk_disable_unprepare(dbox->ahb0_gate); ++#endif ++#endif ++ ++ return ret; ++ ++} ++ ++static long dbox_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ int ret = 0; ++ struct dbox_param iparam; ++ struct miscdevice *dev = filp->private_data; ++ struct jz_dbox *dbox = container_of(dev, struct jz_dbox, misc_dev); ++ ++ DBOX_DEBUG("dbox: %s pid: %d, tgid: %d file: %p, cmd: 0x%08x\n", ++ __func__, current->pid, current->tgid, filp, cmd); ++ ++ if (_IOC_TYPE(cmd) != JZDBOX_IOC_MAGIC) { ++ dev_err(dbox->dev, "invalid cmd!\n"); ++ return -EFAULT; ++ } ++ ++ mutex_lock(&dbox->mutex); ++ ++ switch (cmd) { ++ case IOCTL_DBOX_START: ++ if (copy_from_user(&iparam, (void *)arg, sizeof(struct dbox_param))) { ++ dev_err(dbox->dev, "copy_from_user error!!!\n"); ++ ret = -EFAULT; ++ break; ++ } ++ ret = dbox_start(dbox, &iparam); ++ if (ret) { ++ printk("dbox: error dbox start ret = %d\n", ret); ++ } ++ break; ++ case IOCTL_DBOX_GET_PBUFF: ++ if (dbox->pbuf.vaddr_alloc == 0) { ++ unsigned int size = DBOX_BUF_SIZE; ++ dbox->pbuf.vaddr_alloc = (unsigned int)kmalloc(size, GFP_KERNEL); ++ if (!dbox->pbuf.vaddr_alloc) { ++ printk("dbox kmalloc is error\n"); ++ ret = -ENOMEM; ++ } ++ memset((void*)(dbox->pbuf.vaddr_alloc), 0x00, size); ++ dbox->pbuf.size = size; ++ dbox->pbuf.paddr = virt_to_phys((void *)(dbox->pbuf.vaddr_alloc)); ++ dbox->pbuf.paddr_align = ((unsigned long)(dbox->pbuf.paddr)); ++ } ++ DBOX_DEBUG("dbox: %s dbox->pbuf.vaddr_alloc = 0x%08x\ndbox->pbuf.vaddr_align = 0x%08x\ndbox->pbuf.size = 0x%x\ndbox->pbuf.paddr = 0x%08x\n" ++ , __func__, dbox->pbuf.vaddr_alloc, dbox->pbuf.paddr_align, dbox->pbuf.size, dbox->pbuf.paddr); ++ if (copy_to_user((void *)arg, &dbox->pbuf, sizeof(struct dbox_buf_info))) { ++ dev_err(dbox->dev, "copy_to_user error!!!\n"); ++ ret = -EFAULT; ++ } ++ break; ++ case IOCTL_DBOX_RES_PBUFF: ++ if (dbox->pbuf.vaddr_alloc != 0) { ++ kfree((void *)dbox->pbuf.vaddr_alloc); ++ dbox->pbuf.vaddr_alloc = 0; ++ dbox->pbuf.size = 0; ++ dbox->pbuf.paddr = 0; ++ dbox->pbuf.paddr_align = 0; ++ } else { ++ dev_warn(dbox->dev, "buffer wanted to free is null\n"); ++ } ++ break; ++ case IOCTL_DBOX_BUF_LOCK: ++ ret = wait_for_completion_interruptible_timeout(&dbox->done_buf, msecs_to_jiffies(2000)); ++ if (ret < 0) { ++ printk("dbox: done_buf wait_for_completion_interruptible_timeout err %d\n", ret); ++ } else if (ret == 0 ) { ++ printk("dbox: done_buf wait_for_completion_interruptible_timeout timeout %d\n", ret); ++ ret = -1; ++ dbox_dump_info(dbox); ++ } else { ++ ret = 0; ++ } ++ break; ++ case IOCTL_DBOX_BUF_UNLOCK: ++ complete(&dbox->done_buf); ++ break; ++ case IOCTL_DBOX_BUF_FLUSH_CACHE: ++ { ++ struct dbox_flush_cache_para fc; ++ if (copy_from_user(&fc, (void *)arg, sizeof(fc))) { ++ dev_err(dbox->dev, "copy_from_user error!!!\n"); ++ ret = -EFAULT; ++ break; ++ } ++ //dma_sync_single_for_device(NULL, fc.addr, fc.size, DMA_TO_DEVICE); ++ //dma_sync_single_for_device(NULL, fc.addr, fc.size, DMA_FROM_DEVICE); ++ dma_cache_sync(NULL, fc.addr, fc.size, DMA_BIDIRECTIONAL); ++ } ++ break; ++ default: ++ dev_err(dbox->dev, "invalid command: 0x%08x\n", cmd); ++ ret = -EINVAL; ++ } ++ ++ mutex_unlock(&dbox->mutex); ++ return ret; ++} ++ ++static int dbox_open(struct inode *inode, struct file *filp) ++{ ++ int ret = 0; ++ ++ struct miscdevice *dev = filp->private_data; ++ struct jz_dbox *dbox = container_of(dev, struct jz_dbox, misc_dev); ++ ++ DBOX_DEBUG("dbox: %s pid: %d, tgid: %d filp: %p\n", ++ __func__, current->pid, current->tgid, filp); ++ mutex_lock(&dbox->mutex); ++ ++ mutex_unlock(&dbox->mutex); ++ return ret; ++} ++ ++static int dbox_release(struct inode *inode, struct file *filp) ++{ ++ int ret = 0; ++ ++ struct miscdevice *dev = filp->private_data; ++ struct jz_dbox *dbox = container_of(dev, struct jz_dbox, misc_dev); ++ ++ DBOX_DEBUG("dbox: %s pid: %d, tgid: %d filp: %p\n", ++ __func__, current->pid, current->tgid, filp); ++ mutex_lock(&dbox->mutex); ++ ++ mutex_unlock(&dbox->mutex); ++ return ret; ++} ++ ++static struct file_operations dbox_ops = { ++ .owner = THIS_MODULE, ++ .open = dbox_open, ++ .release = dbox_release, ++ .unlocked_ioctl = dbox_ioctl, ++}; ++ ++static irqreturn_t dbox_irq_handler(int irq, void *data) ++{ ++ struct jz_dbox *dbox; ++ unsigned int status; ++ ++ DBOX_DEBUG("dbox: %s\n", __func__); ++ dbox = (struct jz_dbox *)data; ++ ++ status = dbox_reg_read(dbox, DBOX_CTRL); ++ ++ ++ DBOX_DEBUG("----- %s, status= 0x%08x\n", __func__, status); ++ /* this status doesn't do anything including trigger interrupt, ++ * just give a hint */ ++ if (status & 0x10){ ++ complete(&dbox->done_dbox); ++ } ++ ++ __dbox_irq_clear(); ++ ++ return IRQ_HANDLED; ++} ++ ++static int dbox_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ struct jz_dbox *dbox; ++ ++ DBOX_DEBUG("%s\n", __func__); ++ dbox = (struct jz_dbox *)kzalloc(sizeof(struct jz_dbox), GFP_KERNEL); ++ if (!dbox) { ++ dev_err(&pdev->dev, "alloc jz_dbox failed!\n"); ++ return -ENOMEM; ++ } ++ ++ sprintf(dbox->name, "dbox"); ++ ++ dbox->misc_dev.minor = MISC_DYNAMIC_MINOR; ++ dbox->misc_dev.name = dbox->name; ++ dbox->misc_dev.fops = &dbox_ops; ++ dbox->dev = &pdev->dev; ++ ++ mutex_init(&dbox->mutex); ++ init_completion(&dbox->done_dbox); ++ init_completion(&dbox->done_buf); ++ complete(&dbox->done_buf); ++ ++ dbox->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!dbox->res) { ++ dev_err(&pdev->dev, "failed to get dev resources: %d\n", ret); ++ ret = -EINVAL; ++ goto err_get_platform_res; ++ } ++ ++ dbox->res = request_mem_region(dbox->res->start, ++ dbox->res->end - dbox->res->start + 1, ++ pdev->name); ++ if (!dbox->res) { ++ dev_err(&pdev->dev, "failed to request regs memory region"); ++ ret = -EINVAL; ++ goto err_get_mem_region; ++ } ++ dbox->iomem = ioremap(dbox->res->start, resource_size(dbox->res)); ++ if (!dbox->iomem) { ++ dev_err(&pdev->dev, "failed to remap regs memory region: %d\n",ret); ++ ret = -EINVAL; ++ goto err_ioremap; ++ } ++ ++ dbox->irq = platform_get_irq(pdev, 0); ++ if (request_irq(dbox->irq, dbox_irq_handler, IRQF_SHARED, dbox->name, dbox)) { ++ dev_err(&pdev->dev, "request irq failed\n"); ++ ret = -EINVAL; ++ goto err_req_irq; ++ } ++ ++#ifndef CONFIG_FPGA_TEST ++ dbox->clk = devm_clk_get(dbox->dev, "gate_drawbox"); ++ if (IS_ERR(dbox->clk)) { ++ dev_err(&pdev->dev, "dbox clk get failed!\n"); ++ ret = -EINVAL; ++ goto err_get_dbox_clk; ++ } ++#ifdef CONFIG_SOC_T40 ++ dbox->ahb0_gate = devm_clk_get(dbox->dev, "gate_ahb0"); ++ if (IS_ERR(dbox->clk)) { ++ dev_err(&pdev->dev, "dbox clk get failed!\n"); ++ ret = -EINVAL; ++ goto err_get_ahb0_clk; ++ } ++#endif ++#endif ++ ++ dev_set_drvdata(&pdev->dev, dbox); ++ ++ __reset_dbox(); ++ /* wait reset complete */ ++ while(dbox_reg_read(dbox, DBOX_CTRL) & 0x2) { ++ udelay(10); ++ } ++ ++ ret = misc_register(&dbox->misc_dev); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "register misc device failed!\n"); ++ goto err_misc_register; ++ } ++ ++ printk("JZ DBOX probe ok!!!!\n"); ++ return 0; ++ ++err_misc_register: ++#ifndef CONFIG_FPGA_TEST ++#ifdef CONFIG_SOC_T40 ++ devm_clk_put(dbox->dev, dbox->ahb0_gate); ++err_get_ahb0_clk: ++#endif ++ devm_clk_put(dbox->dev, dbox->clk); ++err_get_dbox_clk: ++#endif ++ free_irq(dbox->irq, dbox); ++err_req_irq: ++ iounmap(dbox->iomem); ++err_ioremap: ++ release_mem_region(dbox->res->start, dbox->res->end - dbox->res->start + 1); ++err_get_platform_res: ++err_get_mem_region: ++ kfree(dbox); ++ ++ return ret; ++} ++ ++static int dbox_remove(struct platform_device *pdev) ++{ ++ struct jz_dbox *dbox; ++ struct resource *res; ++ DBOX_DEBUG("%s\n", __func__); ++ ++ dbox = dev_get_drvdata(&pdev->dev); ++ misc_deregister(&dbox->misc_dev); ++#ifndef CONFIG_FPGA_TEST ++#ifdef CONFIG_SOC_T40 ++ devm_clk_put(dbox->dev, dbox->ahb0_gate); ++#endif ++ devm_clk_put(dbox->dev, dbox->clk); ++#endif ++ res = dbox->res; ++ free_irq(dbox->irq, dbox); ++ iounmap(dbox->iomem); ++ release_mem_region(res->start, res->end - res->start + 1); ++ ++ if (dbox->pbuf.vaddr_alloc) { ++ kfree((void *)(dbox->pbuf.vaddr_alloc)); ++ dbox->pbuf.vaddr_alloc = 0; ++ } ++ if (dbox) { ++ kfree(dbox); ++ } ++ ++ return 0; ++} ++ ++static const struct of_device_id ingenic_dbox_dt_match[] = { ++ { .compatible = "ingenic,t40-drawbox", .data = NULL }, ++ {}, ++}; ++ ++static struct platform_driver jz_dbox_driver = { ++ .probe = dbox_probe, ++ .remove = dbox_remove, ++ .driver = { ++ .name = "jz-drawbox", ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(ingenic_dbox_dt_match), ++ }, ++}; ++ ++void dboxdev_init(void) ++{ ++ DBOX_DEBUG("%s\n", __func__); ++ platform_driver_register(&jz_dbox_driver); ++} ++ ++void dboxdev_exit(void) ++{ ++ DBOX_DEBUG("%s\n", __func__); ++ platform_driver_unregister(&jz_dbox_driver); ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_ipu_ingenic_drawbox.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_ipu_ingenic_drawbox.h.patch new file mode 100644 index 00000000..d478e6e9 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_ipu_ingenic_drawbox.h.patch @@ -0,0 +1,164 @@ +diff -drupN a/drivers/video/ingenic_ipu/ingenic_drawbox.h b/drivers/video/ingenic_ipu/ingenic_drawbox.h +--- a/drivers/video/ingenic_ipu/ingenic_drawbox.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/ingenic_ipu/ingenic_drawbox.h 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,160 @@ ++#ifndef __DBOX__H__ ++#define __DBOX__H__ ++ ++ ++ ++#define DBOX_BASE 0xB30D0000 ++ ++#define DBOX_CTRL 0x00 ++#define DBOX_YB 0x04 ++#define DBOX_CB 0x08 ++#define DBOX_STRIDE 0x0c ++#define DBOX_IMG_WH 0x10 ++#define DBOX_COLOR_Y 0x14 ++#define DBOX_COLOR_U 0x18 ++#define DBOX_COLOR_V 0x1c ++#define DBOX_RAM 0x20 ++#define DBOX_TIMEOUT 0x24 ++ ++#define u32 unsigned int ++ ++struct dbox_reg_struct { ++ char *name; ++ unsigned int addr; ++}; ++ ++struct dbox_buf_info { ++ unsigned int vaddr_alloc; ++ unsigned int paddr; ++ unsigned int paddr_align; ++ unsigned int size; ++}; ++ ++struct jz_dbox { ++ ++ int irq; ++ char name[16]; ++ ++ struct clk *clk; ++ struct clk *ahb0_gate; /* T40 drawbox mount at AHB0*/ ++ void __iomem *iomem; ++ struct device *dev; ++ struct resource *res; ++ struct miscdevice misc_dev; ++ ++ struct mutex mutex; ++ struct completion done_dbox; ++ struct completion done_buf; ++ struct dbox_buf_info pbuf; ++}; ++ ++struct dbox_flush_cache_para ++{ ++ void *addr; ++ unsigned int size; ++}; ++ ++struct dbox_ram ++{ ++ unsigned int box_x; ++ unsigned int box_y; ++ unsigned int box_w; ++ unsigned int box_h; ++ unsigned int line_w; ++ unsigned int line_l; ++ unsigned int box_mode; ++ unsigned int color_mode; ++}; ++ ++struct dbox_param ++{ ++ unsigned int box_pbuf; ++ unsigned int img_w; ++ unsigned int img_h; ++ ++ unsigned int boxs_num; ++ unsigned int is_rgba; ++ struct dbox_ram ram_para[24]; //kernel stack overflow ++}; ++ ++#define JZDBOX_IOC_MAGIC 'X' ++#define IOCTL_DBOX_START _IO(JZDBOX_IOC_MAGIC, 106) ++#define IOCTL_DBOX_RES_PBUFF _IO(JZDBOX_IOC_MAGIC, 114) ++#define IOCTL_DBOX_GET_PBUFF _IO(JZDBOX_IOC_MAGIC, 115) ++#define IOCTL_DBOX_BUF_LOCK _IO(JZDBOX_IOC_MAGIC, 116) ++#define IOCTL_DBOX_BUF_UNLOCK _IO(JZDBOX_IOC_MAGIC, 117) ++#define IOCTL_DBOX_BUF_FLUSH_CACHE _IO(JZDBOX_IOC_MAGIC, 118) ++ ++/* DBOX_CTRL*/ ++#define DBOX_RAM_RP (17) ++#define DBOX_RAM_WP (9) ++#define DBOX_TIMEOUT_MASK (1 << 8) ++#define DBOX_TIMEOUT_IRQ (1 << 7) ++#define DBOX_IS_BGRA (1 << 6) ++#define DBOX_CLOCK_GATE_MASK (1 << 5) ++#define DBOX_IRQ (4) ++#define DBOX_IRQ_OPEN (1 << DBOX_IRQ) ++#define DBOX_IRQ_MASK (1 << 3) ++#define DBOX_COLOR_MASK (1 << 2) ++#define DBOX_RESET (1 << 1) ++#define DBOX_START (1 << 0) ++ ++ ++/* DBOX_YB luma base register */ ++#define DBOX_LUMA_BASE (0) ++ ++/* DBOX_CB */ ++#define DBOX_CONCENTRATION_BASE (0) ++ ++/* DBOX_STRIDE */ ++#define DBOX_C_STRIDE (16) ++#define DBOX_Y_STRIDE (0) ++ ++/* DBOX_IMG_WH */ ++#define DBOX_WIDTH (0) ++#define DBOX_HEIGHT (16) ++ ++/* DBOX_COLOR_Y */ ++#define DBOX_COLOR_ADDR_Y (0) ++ ++/* DBOX_COLOR_U */ ++#define DBOX_COLOR_ADDR_U (0) ++ ++/* DBOX_COLOR_V */ ++#define DBOX_COLOR_ADDR_V (0) ++ ++/* DBOX_RAM */ ++#define DBOX_BOX_LINE_WIDTH (55) ++#define DBOX_BOX_LINE_LENGTH (52) ++#define DBOX_BOX_MODE (50) ++#define DBOX_MODE_RECT (0 << DBOX_BOX_MODE) ++#define DBOX_MODE_HRECT (1 << DBOX_BOX_MODE) ++#define DBOX_MODE_HLINE (2 << DBOX_BOX_MODE) ++#define DBOX_MODE_VLINE (3 << DBOX_BOX_MODE) ++#define DBOX_COLOR_MODE (48) ++#define DBOX_BOX_HEIGHT (36) ++#define DBOX_BOX_WIDTH (24) ++#define DBOX_BOX_Y (12) ++#define DBOX_BOX_X (0) ++ ++extern void dboxdev_init(void); ++extern void dboxdev_exit(void); ++ ++static inline unsigned int dbox_reg_read(struct jz_dbox *jzdbox, int offset) ++{ ++ return readl(jzdbox->iomem + offset); ++} ++ ++static inline void dbox_reg_write(struct jz_dbox *jzdbox, int offset, unsigned int val) ++{ ++ writel(val, jzdbox->iomem + offset); ++} ++ ++#define __dbox_mask_irq() reg_bit_clr(dbox, DBOX_CTRL, DBOX_IRQ_MASK) ++#define __dbox_irq_clear(value) reg_bit_clr(dbox, DBOX_CTRL, DBOX_IRQ_OPEN) ++ ++#define __start_dbox() reg_bit_set(dbox, DBOX_CTRL, DBOX_START) ++#define __reset_dbox() reg_bit_set(dbox, DBOX_CTRL, DBOX_RESET) ++#define __uv_mask_dbox() reg_bit_set(dbox, DBOX_CTRL, DBOX_COLOR_MASK) ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_ipu_ingenic_ipu_v13.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_ipu_ingenic_ipu_v13.c.patch new file mode 100644 index 00000000..bb0073f8 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_ipu_ingenic_ipu_v13.c.patch @@ -0,0 +1,1246 @@ +diff -drupN a/drivers/video/ingenic_ipu/ingenic_ipu_v13.c b/drivers/video/ingenic_ipu/ingenic_ipu_v13.c +--- a/drivers/video/ingenic_ipu/ingenic_ipu_v13.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/ingenic_ipu/ingenic_ipu_v13.c 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,1242 @@ ++/* ++ * Copyright (c) 2015 Ingenic Semiconductor Co., Ltd. ++ * http://www.ingenic.com/ ++ * ++ * Input file for Ingenic IPU driver ++ * ++ * 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. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "ingenic_regs_v13.h" ++#include "ingenic_ipu_v13.h" ++#include "ingenic_drawbox.h" ++ ++// #define DEBUG ++#ifdef DEBUG ++static int debug_ipu = 1; ++ ++#define IPU_DEBUG(format, ...) { if (debug_ipu) printk(format, ## __VA_ARGS__);} ++#else ++#define IPU_DEBUG(format, ...) do{ } while(0) ++#endif ++ ++#define IPU_BUF_SIZE (1024 * 1024 * 2) ++ ++struct ipu_reg_struct jz_ipu_regs_name[] = { ++ {"IPU_FM_CTRL", IPU_FM_CTRL}, ++ {"IPU_STATUS", IPU_STATUS}, ++ {"IPU_D_FMT", IPU_D_FMT}, ++ {"IPU_Y_ADDR", IPU_Y_ADDR}, ++ {"IPU_U_ADDR", IPU_U_ADDR}, ++ {"IPU_IN_FM_GS", IPU_IN_FM_GS}, ++ {"IPU_Y_STRIDE", IPU_Y_STRIDE}, ++ {"IPU_UV_STRIDE", IPU_UV_STRIDE}, ++ {"IPU_OUT_ADDR", IPU_OUT_ADDR}, ++ {"IPU_OUT_STRIDE", IPU_OUT_STRIDE}, ++ {"IPU_OUT_V_ADDR", IPU_OUT_V_ADDR}, ++ {"IPU_OUT_V_STRIDE", IPU_OUT_V_STRIDE}, ++ {"IPU_REG_CTRL", IPU_REG_CTRL}, ++ {"IPU_TRIGGER", IPU_TRIGGER}, ++ {"IPU_GLB_CTRL", IPU_GLB_CTRL}, ++ ++ {"IPU_NV_OUT_ADDR", IPU_NV_OUT_ADDR}, ++ {"IPU_NV_OUT_STRIDE", IPU_NV_OUT_STRIDE}, ++ {"IPU_OSD_IN_CH0_Y_ADDR", IPU_OSD_IN_CH0_Y_ADDR}, ++ {"IPU_OSD_IN_CH0_Y_STRIDE", IPU_OSD_IN_CH0_Y_STRIDE}, ++ {"IPU_OSD_IN_CH0_UV_ADDR", IPU_OSD_IN_CH0_UV_ADDR}, ++ {"IPU_OSD_IN_CH0_UV_STRIDE", IPU_OSD_IN_CH0_UV_STRIDE}, ++ {"IPU_OSD_IN_CH1_Y_ADDR", IPU_OSD_IN_CH1_Y_ADDR}, ++ {"IPU_OSD_IN_CH1_Y_STRIDE", IPU_OSD_IN_CH1_Y_STRIDE}, ++ {"IPU_OSD_IN_CH1_UV_ADDR", IPU_OSD_IN_CH1_UV_ADDR}, ++ {"IPU_OSD_IN_CH1_UV_STRIDE", IPU_OSD_IN_CH1_UV_STRIDE}, ++ {"IPU_OSD_IN_CH2_Y_ADDR", IPU_OSD_IN_CH2_Y_ADDR}, ++ {"IPU_OSD_IN_CH2_Y_STRIDE", IPU_OSD_IN_CH2_Y_STRIDE}, ++ {"IPU_OSD_IN_CH2_UV_ADDR", IPU_OSD_IN_CH2_UV_ADDR}, ++ {"IPU_OSD_IN_CH2_UV_STRIDE", IPU_OSD_IN_CH2_UV_STRIDE}, ++ {"IPU_OSD_IN_CH3_Y_ADDR", IPU_OSD_IN_CH3_Y_ADDR}, ++ {"IPU_OSD_IN_CH3_Y_STRIDE", IPU_OSD_IN_CH3_Y_STRIDE}, ++ {"IPU_OSD_IN_CH3_UV_ADDR", IPU_OSD_IN_CH3_UV_ADDR}, ++ {"IPU_OSD_IN_CH3_UV_STRIDE", IPU_OSD_IN_CH3_UV_STRIDE}, ++ {"IPU_OSD_CH0_GS", IPU_OSD_CH0_GS}, ++ {"IPU_OSD_CH1_GS", IPU_OSD_CH1_GS}, ++ {"IPU_OSD_CH2_GS", IPU_OSD_CH2_GS}, ++ {"IPU_OSD_CH3_GS", IPU_OSD_CH3_GS}, ++ {"IPU_OSD_CH0_POS", IPU_OSD_CH0_POS}, ++ {"IPU_OSD_CH1_POS", IPU_OSD_CH1_POS}, ++ {"IPU_OSD_CH2_POS", IPU_OSD_CH2_POS}, ++ {"IPU_OSD_CH3_POS", IPU_OSD_CH3_POS}, ++ {"IPU_OSD_CH0_PARA", IPU_OSD_CH0_PARA}, ++ {"IPU_OSD_CH1_PARA", IPU_OSD_CH1_PARA}, ++ {"IPU_OSD_CH2_PARA", IPU_OSD_CH2_PARA}, ++ {"IPU_OSD_CH3_PARA", IPU_OSD_CH3_PARA}, ++ {"IPU_OSD_CH_BK_PARA", IPU_OSD_CH_BK_PARA}, ++ {"IPU_OSD_CH0_BAK_ARGB", IPU_OSD_CH0_BAK_ARGB}, ++ {"IPU_OSD_CH1_BAK_ARGB", IPU_OSD_CH1_BAK_ARGB}, ++ {"IPU_OSD_CH2_BAK_ARGB", IPU_OSD_CH2_BAK_ARGB}, ++ {"IPU_OSD_CH3_BAK_ARGB", IPU_OSD_CH3_BAK_ARGB}, ++ {"IPU_OSD_CH_B_BAK_ARGB", IPU_OSD_CH_B_BAK_ARGB}, ++ {"IPU_CH0_CSC_C0_COEF", IPU_CH0_CSC_C0_COEF}, ++ {"IPU_CH0_CSC_C1_COEF", IPU_CH0_CSC_C1_COEF}, ++ {"IPU_CH0_CSC_C2_COEF", IPU_CH0_CSC_C2_COEF}, ++ {"IPU_CH0_CSC_C3_COEF", IPU_CH0_CSC_C3_COEF}, ++ {"IPU_CH0_CSC_C4_COEF", IPU_CH0_CSC_C4_COEF}, ++ {"IPU_CH0_CSC_OFSET_PARA", IPU_CH0_CSC_OFSET_PARA}, ++ {"IPU_CH1_CSC_C0_COEF", IPU_CH1_CSC_C0_COEF}, ++ {"IPU_CH1_CSC_C1_COEF", IPU_CH1_CSC_C1_COEF}, ++ {"IPU_CH1_CSC_C2_COEF", IPU_CH1_CSC_C2_COEF}, ++ {"IPU_CH1_CSC_C3_COEF", IPU_CH1_CSC_C3_COEF}, ++ {"IPU_CH1_CSC_C4_COEF", IPU_CH1_CSC_C4_COEF}, ++ {"IPU_CH1_CSC_OFSET_PARA", IPU_CH1_CSC_OFSET_PARA}, ++ {"IPU_CH2_CSC_C0_COEF", IPU_CH2_CSC_C0_COEF}, ++ {"IPU_CH2_CSC_C1_COEF", IPU_CH2_CSC_C1_COEF}, ++ {"IPU_CH2_CSC_C2_COEF", IPU_CH2_CSC_C2_COEF}, ++ {"IPU_CH2_CSC_C3_COEF", IPU_CH2_CSC_C3_COEF}, ++ {"IPU_CH2_CSC_C4_COEF", IPU_CH2_CSC_C4_COEF}, ++ {"IPU_CH2_CSC_OFSET_PARA", IPU_CH2_CSC_OFSET_PARA}, ++ {"IPU_CH3_CSC_C0_COEF", IPU_CH3_CSC_C0_COEF}, ++ {"IPU_CH3_CSC_C1_COEF", IPU_CH3_CSC_C1_COEF}, ++ {"IPU_CH3_CSC_C2_COEF", IPU_CH3_CSC_C2_COEF}, ++ {"IPU_CH3_CSC_C3_COEF", IPU_CH3_CSC_C3_COEF}, ++ {"IPU_CH3_CSC_C4_COEF", IPU_CH3_CSC_C4_COEF}, ++ {"IPU_CH3_CSC_OFSET_PARA", IPU_CH3_CSC_OFSET_PARA}, ++ {"IPU_RD_ARB_CTL", IPU_RD_ARB_CTL}, ++ {"IPU_CLK_NUM_ONE_FRA", IPU_CLK_NUM_ONE_FRA}, ++ {"IPU_OSD_LAY_PADDING_ARGB", IPU_OSD_LAY_PADDING_ARGB}, ++ {"IPU_TEST_1B4", IPU_TEST_1B4}, ++}; ++ ++ ++static void reg_bit_set(struct jz_ipu *ipu, int offset, unsigned int bit) ++{ ++ unsigned int reg = 0; ++ reg = ipu_reg_read(ipu, offset); ++ reg |= bit; ++ ipu_reg_write(ipu, offset, reg); ++} ++ ++static void reg_bit_clr(struct jz_ipu *ipu, int offset, unsigned int bit) ++{ ++ unsigned int reg = 0; ++ reg= ipu_reg_read(ipu, offset); ++ reg &= ~(bit); ++ ipu_reg_write(ipu, offset, reg); ++} ++ ++static unsigned int _hal_to_ipu_infmt(int hal_fmt, int *isrgb) ++{ ++ unsigned int ipu_fmt = IN_FMT_YUV420; ++ int rgb = 0; ++ ++ switch (hal_fmt) { ++ case HAL_PIXEL_FORMAT_YCbCr_422_SP: ++ ipu_fmt = IN_FMT_YUV422; ++ rgb = 0; ++ break; ++ case HAL_PIXEL_FORMAT_YCbCr_420_SP: ++ ipu_fmt = IN_FMT_YUV420; ++ rgb = 0; ++ break; ++ case HAL_PIXEL_FORMAT_YCbCr_422_P: ++ ipu_fmt = IN_FMT_YUV422; ++ rgb = 0; ++ break; ++ case HAL_PIXEL_FORMAT_YCbCr_422_I: ++ ipu_fmt = IN_FMT_YUV422; ++ rgb = 0; ++ break; ++ case HAL_PIXEL_FORMAT_YCbCr_420_I: ++ ipu_fmt = IN_FMT_YUV420; ++ rgb = 0; ++ break; ++ case HAL_PIXEL_FORMAT_YCbCr_420_B: ++ case HAL_PIXEL_FORMAT_JZ_YUV_420_B: ++ ipu_fmt = IN_FMT_YUV420_B; ++ rgb = 0; ++ break; ++ case HAL_PIXEL_FORMAT_RGBA_5551: //background is not support 5551 format ++ case HAL_PIXEL_FORMAT_BGRA_5551: ++ ipu_fmt = IN_FMT_RGB_555; ++ rgb = 1; ++ break; ++ case HAL_PIXEL_FORMAT_RGBA_8888: ++ case HAL_PIXEL_FORMAT_RGBX_8888: ++ case HAL_PIXEL_FORMAT_RGB_888: ++ case HAL_PIXEL_FORMAT_BGRA_8888: ++ case HAL_PIXEL_FORMAT_ARGB_8888: ++ case HAL_PIXEL_FORMAT_ABGR_8888: ++ case HAL_PIXEL_FORMAT_BGRX_8888: ++ ipu_fmt = IN_FMT_RGB_888; ++ rgb = 1; ++ break; ++ case HAL_PIXEL_FORMAT_RGB_565: //background is not support 565 format ++ ipu_fmt = IN_FMT_RGB_565; ++ rgb = 1; ++ break; ++ case HAL_PIXEL_FORMAT_NV12: ++ case HAL_PIXEL_FORMAT_NV21: ++ case HAL_PIXEL_FORMAT_YCbCr_420_P: ++ case HAL_PIXEL_FORMAT_JZ_YUV_420_P: ++ default: ++ ipu_fmt = IN_FMT_YUV420; ++ rgb = 0; ++ break; ++ } ++ if (isrgb != 0) ++ *isrgb = rgb; ++ return ipu_fmt; ++} ++ ++static unsigned int _hal_to_ipu_outfmt(int hal_fmt) ++{ ++ unsigned int ipu_fmt = OUT_FMT_RGB888; ++ ++ switch (hal_fmt) { ++ case HAL_PIXEL_FORMAT_ARGB_8888: ++ case HAL_PIXEL_FORMAT_ABGR_8888: ++ case HAL_PIXEL_FORMAT_RGBA_8888: ++ case HAL_PIXEL_FORMAT_RGBX_8888: ++ case HAL_PIXEL_FORMAT_RGB_888: ++ case HAL_PIXEL_FORMAT_BGRA_8888: ++ case HAL_PIXEL_FORMAT_BGRX_8888: ++ ipu_fmt = OUT_FMT_RGB888; ++ break; ++ case HAL_PIXEL_FORMAT_RGB_565: //It is not support ++ ipu_fmt = OUT_FMT_RGB565; ++ break; ++ case HAL_PIXEL_FORMAT_RGBA_5551: //It is not support ++ case HAL_PIXEL_FORMAT_BGRA_5551: ++ ipu_fmt = OUT_FMT_RGB555; ++ break; ++ case HAL_PIXEL_FORMAT_YCbCr_422_I: ++ ipu_fmt = OUT_FMT_YUV422; ++ break; ++ case HAL_PIXEL_FORMAT_NV12: ++ ipu_fmt = OUT_FMT_NV12; ++ break; ++ case HAL_PIXEL_FORMAT_HSV:/*Add HSV*/ ++ ipu_fmt = OUT_FMT_HSV; ++ break; ++ case HAL_PIXEL_FORMAT_NV21: ++ ipu_fmt = OUT_FMT_NV21; ++ break; ++ } ++ return ipu_fmt; ++} ++ ++#define IPU_OSD_CH_BK_PARA_GLO_A(p, x) ((p)=(((p)&(~(0xff<<3)))|((x&0xff)<<3))) ++#define IPU_OSD_CH_BK_PARA_ALPHA_SEL(p, x) ((p)=(((p)&(~(0x3<<1)))|((x&0x3)<<1))) ++static int _ipu_set_bg_route(struct jz_ipu *ipu, struct ipu_param *ipu_param) ++{ ++ int ret = 0; ++ unsigned int reg_val = 0; ++ unsigned int bgrgb = 0; ++ unsigned int srcw = 0; ++ unsigned int srch = 0; ++ unsigned int outw = 0; ++ unsigned int outh = 0; ++ unsigned int infmt = 0; ++ unsigned int outfmt = 0; ++ ++ unsigned int outwstride = 0; ++ ++ unsigned int infmt_bits = 0; ++ unsigned int outfmt_bits = 0; ++ unsigned int outrgb_bits = 0; ++ ++ struct ipu_param *ip = ipu_param; ++ ++ srcw = ip->bg_w; ++ srch = ip->bg_h; ++ outw = ip->bg_w; ++ outh = ip->bg_h; ++ ++ IPU_DEBUG("ipu: %s, bgrgb = %d, srcw = %d, srch = %d, outw = %d, outh = %d \n", ++ __func__, bgrgb, srcw, srch, outw, outh); ++ infmt = _hal_to_ipu_infmt(ip->bg_fmt, &bgrgb); ++ outfmt = _hal_to_ipu_outfmt(ip->out_fmt); ++ switch (outfmt) { ++ case OUT_FMT_RGB888: ++ outwstride = outw << 2; ++ break; ++ case OUT_FMT_RGB555: //not used ++ outwstride = outw << 1; ++ break; ++ case OUT_FMT_RGB565: //not used ++ outwstride = outw << 1; ++ break; ++ default: ++ outwstride = outw; ++ break; ++ } ++ ipu_reg_write(ipu, IPU_IN_FM_GS, (IN_FM_W(srcw) | IN_FM_H(srch))); ++ ++ if (ip->cmd & IPU_CMD_OSD) ++ { ++ ipu_reg_write(ipu, IPU_OSD_CH_B_BAK_ARGB, 0xffaa7733); ++ } ++ ++ switch (ip->out_fmt) { ++ case HAL_PIXEL_FORMAT_RGBX_8888: ++ outrgb_bits = RGB_OUT_OFT_BGR; ++ break; ++ case HAL_PIXEL_FORMAT_RGB_888: ++ case HAL_PIXEL_FORMAT_RGB_565: ++ case HAL_PIXEL_FORMAT_BGRA_8888: ++ case HAL_PIXEL_FORMAT_BGRX_8888: ++ case HAL_PIXEL_FORMAT_RGBA_5551: ++ default: ++ outrgb_bits = RGB_OUT_OFT_RGB; //outrgb_bits set 22st bit,this bit in IPU_D_FMT was not used ++ break; ++ } ++ infmt_bits = infmt; ++ outfmt_bits = outfmt; //outfmt_bits set 19st bit,IPU_D_FMT was not used ++ if (infmt == IN_FMT_YUV422) { ++ infmt_bits |= IN_OFT_Y1UY0V; ++ } ++ if (outfmt == OUT_FMT_YUV422) { ++ outfmt_bits |= YUV_PKG_OUT_OFT_Y1UY0V; ++ } ++ ++ /****** Add HSV *******/ ++ if ((outfmt == OUT_FMT_HSV) || (ip->out_fmt == OUT_FMT_HSV)) {/* out format */ ++ reg_val = 0x4; ++ } else if ((outfmt == OUT_FMT_RGB888) || (ip->out_fmt == OUT_FMT_RGB888)) { ++ reg_val = 0x40; ++ } else if ((outfmt == OUT_FMT_NV21) || (ip->out_fmt == OUT_FMT_NV21)) { ++ reg_val = 0x3; ++ } ++ ipu_reg_write(ipu, IPU_D_FMT, reg_val); ++ ++ if (ip->cmd & IPU_CMD_OSD) { ++ if (ip->bg_fmt == HAL_PIXEL_FORMAT_NV12) { ++ reg_val = 0x2; ++ } else if (ip->bg_fmt == HAL_PIXEL_FORMAT_NV21) { ++ reg_val = 0x3; ++ } else { ++ reg_val = infmt_bits | outfmt_bits | outrgb_bits; ++ } ++ ipu_reg_write(ipu, IPU_D_FMT, reg_val); ++ } ++ /* ++ * IPU_D_FMT just use 0~6 bit, if IPU_OSD_CH_BK_PARA set CH_BK_PIC_TYPE , ++ * and the IPU was use to do OSD, this register OUT_FMT bits was valueless, ++ * the OUT_FMT are automatically set equal to CH_BK_PIC_TYPE value; ++ * and if IPU was use to do conversion format, the OUT_FMT bits must be set to the ++ * format that you want to conversion. ++ */ ++ if (infmt == IN_FMT_YUV420_B) { ++ __enable_blk_mode(); ++ } ++ ++ if ((ip->out_fmt == HAL_PIXEL_FORMAT_NV12) || (ip->out_fmt == HAL_PIXEL_FORMAT_NV21)) {/*Add NV12 or NV21*/ ++ ipu_reg_write(ipu, IPU_OUT_STRIDE, srcw); ++ ipu_reg_write(ipu, IPU_NV_OUT_STRIDE, srcw); ++ } else if (ip->out_fmt == HAL_PIXEL_FORMAT_HSV) {/* Add HSV */ ++ ipu_reg_write(ipu, IPU_OUT_STRIDE, srcw); ++ ipu_reg_write(ipu, IPU_NV_OUT_STRIDE, srcw*2); ++ ipu_reg_write(ipu, IPU_OUT_V_STRIDE, srcw); ++ } else if (ip->out_fmt == HAL_PIXEL_FORMAT_BGRA_8888 || ip->out_fmt == HAL_PIXEL_FORMAT_RGBA_8888) {/* Add ARGB */ ++ ipu_reg_write(ipu, IPU_OUT_STRIDE, srcw<<2); ++ } else { ++ ipu_reg_write(ipu, IPU_OUT_STRIDE, outwstride); ++ } ++ ++ if (infmt == IN_FMT_YUV420_B) { ++ ipu_reg_write(ipu, IPU_Y_STRIDE, srcw * 16); ++ } else if (ipu_reg_read(ipu, IPU_FM_CTRL) & (1 << 10)) { ++ ipu_reg_write(ipu, IPU_Y_STRIDE, srcw * 2); ++ } else { ++ ipu_reg_write(ipu, IPU_Y_STRIDE, srcw); ++ } ++ switch (infmt) { ++ case IN_FMT_YUV420: ++ reg_val = U_STRIDE(srcw) | V_STRIDE(srcw); ++ ipu_reg_write(ipu, IPU_UV_STRIDE, reg_val); ++ break; ++ case IN_FMT_YUV422: ++ reg_val = U_STRIDE(srcw / 2) | V_STRIDE(srcw / 2); ++ ipu_reg_write(ipu, IPU_UV_STRIDE, reg_val); ++ break; ++ case IN_FMT_YUV420_B: ++ reg_val = U_STRIDE(8 * srcw) | V_STRIDE(8 * srcw); ++ ipu_reg_write(ipu, IPU_UV_STRIDE, reg_val); ++ break; ++ case IN_FMT_YUV444: ++ reg_val = U_STRIDE(srcw) | V_STRIDE(srcw); ++ ipu_reg_write(ipu, IPU_UV_STRIDE, reg_val); ++ break; ++ case IN_FMT_YUV411: ++ reg_val = U_STRIDE(srcw / 4) | V_STRIDE(srcw / 4); ++ ipu_reg_write(ipu, IPU_UV_STRIDE, reg_val); ++ break; ++ default: ++ dev_err(ipu->dev, "Error: 222 Input data format isn't support\n"); ++ } ++ ++ reg_val = 0; ++ /*select bk ch input fmt*/ ++ if (bgrgb) { ++ switch(ip->bg_fmt) { ++ case HAL_PIXEL_FORMAT_ARGB_8888: ++ reg_val |= CH_BK_ARGB_TYPE_ARGB; ++ break; ++ case HAL_PIXEL_FORMAT_ABGR_8888: ++ reg_val |= CH_BK_ARGB_TYPE_ABGR; ++ break; ++ case HAL_PIXEL_FORMAT_RGBA_8888: ++ reg_val |= CH_BK_ARGB_TYPE_RGBA; ++ break; ++ case HAL_PIXEL_FORMAT_BGRA_8888: ++ reg_val |= CH_BK_ARGB_TYPE_BGRA; ++ break; ++// case HAL_PIXEL_FORMAT_BGRA_5551: //bg_fmt is not support 5551 ++ default: ++ reg_val |= CH_BK_ARGB_TYPE_BGRA; ++ break; ++ } ++ reg_val |= CH_BK_PIC_TYPE_ARGB; ++// reg_val |= CH_BK_ARGB_TYPE_BGRA; //Maybe it's have an other choice, but here I fix it.You can change it. ++ } else { ++ switch(ip->bg_fmt) { ++ case HAL_PIXEL_FORMAT_NV12: ++ reg_val |= CH_BK_PIC_TYPE_NV12; ++ break; ++ case HAL_PIXEL_FORMAT_NV21: ++ reg_val |= CH_BK_PIC_TYPE_NV21; ++ break; ++ default: ++ reg_val |= CH_BK_PIC_TYPE_NV12; ++ break; ++ } ++ } ++ if (ip->cmd & IPU_CMD_OSD) { ++ IPU_DEBUG("ipu: Attention!! Have some OSD CH will ENABLE!!!!\n"); ++ reg_val |= CH_BK_PREM; ++ } ++ ++ IPU_DEBUG("ipu: enable background ch!!! \n"); ++ reg_val |= CH_BK_EN; ++ ++ ipu_reg_write(ipu, IPU_OSD_CH_BK_PARA, reg_val);/* input bk format */ ++ IPU_DEBUG("ipu: Background reg val = 0x%08x\n", ipu_reg_read(ipu, IPU_OSD_CH_BK_PARA)); ++ ++ return ret; ++} ++ ++static int _ipu_osd_isrgb(unsigned int fmt) ++{ ++ int isrgb = 0; ++ switch(fmt) { ++ case HAL_PIXEL_FORMAT_ARGB_8888: ++ case HAL_PIXEL_FORMAT_ABGR_8888: ++ case HAL_PIXEL_FORMAT_RGBA_8888: ++ case HAL_PIXEL_FORMAT_RGBX_8888: ++ case HAL_PIXEL_FORMAT_BGRA_8888: ++ case HAL_PIXEL_FORMAT_BGRX_8888: ++ isrgb = 1; ++ break; ++ case HAL_PIXEL_FORMAT_NV12: ++ isrgb = 0; ++ break; ++ case HAL_PIXEL_FORMAT_HSV:/*Add HSV*/ ++ isrgb = 0; ++ break; ++ case HAL_PIXEL_FORMAT_NV21: ++ isrgb = 0; ++ break; ++ case HAL_PIXEL_FORMAT_BGRA_5551: ++ case HAL_PIXEL_FORMAT_RGBA_5551: ++ isrgb = 2; ++ break; ++ default: ++ isrgb = -1; ++ break; ++ } ++ return isrgb; ++} ++ ++static int _ipu_set_osd_chx_route(struct jz_ipu *ipu, struct ipu_param *ip, int ch) ++{ ++ unsigned int isrgb = 0; ++ unsigned int posx = 0; ++ unsigned int posy = 0; ++ unsigned int srcw = 0; ++ unsigned int srch = 0; ++ unsigned int para = 0; ++ unsigned int fmt = 0; ++ unsigned int bak_argb = 0; ++ unsigned int src_stride = 0; ++ ++ if ((ch < 0) || (ch > 3)) { ++ printk("ipu: osd channel num err ch = %d\n", ch); ++ return -1; ++ } ++ switch(ch) { ++ case 0: ++ fmt = ip->osd_ch0_fmt; ++ posx = ip->osd_ch0_pos_x; ++ posy = ip->osd_ch0_pos_y; ++ srcw = ((ip->bg_w-1) > (ip->osd_ch0_pos_x + ip->osd_ch0_src_w)) ? (ip->osd_ch0_src_w) : (ip->bg_w-1-ip->osd_ch0_pos_x); ++ srch = ((ip->bg_h-1) > (ip->osd_ch0_pos_y + ip->osd_ch0_src_h)) ? (ip->osd_ch0_src_h) : (ip->bg_h-1-ip->osd_ch0_pos_y); ++ para = ip->osd_ch0_para; ++ bak_argb = ip->osd_ch0_bak_argb; ++ src_stride = ip->osd_ch0_src_w; ++ break; ++ case 1: ++ fmt = ip->osd_ch1_fmt; ++ posx = ip->osd_ch1_pos_x; ++ posy = ip->osd_ch1_pos_y; ++ srcw = ((ip->bg_w-1) > (ip->osd_ch1_pos_x + ip->osd_ch1_src_w)) ? (ip->osd_ch1_src_w) : (ip->bg_w-1-ip->osd_ch1_pos_x); ++ srch = ((ip->bg_h-1) > (ip->osd_ch1_pos_y + ip->osd_ch1_src_h)) ? (ip->osd_ch1_src_h) : (ip->bg_h-1-ip->osd_ch1_pos_y); ++ para = ip->osd_ch1_para; ++ bak_argb = ip->osd_ch1_bak_argb; ++ src_stride = ip->osd_ch1_src_w; ++ break; ++ case 2: ++ fmt = ip->osd_ch2_fmt; ++ posx = ip->osd_ch2_pos_x; ++ posy = ip->osd_ch2_pos_y; ++ srcw = ((ip->bg_w-1) > (ip->osd_ch2_pos_x + ip->osd_ch2_src_w)) ? (ip->osd_ch2_src_w) : (ip->bg_w-1-ip->osd_ch2_pos_x); ++ srch = ((ip->bg_h-1) > (ip->osd_ch2_pos_y + ip->osd_ch2_src_h)) ? (ip->osd_ch2_src_h) : (ip->bg_h-1-ip->osd_ch2_pos_y); ++ para = ip->osd_ch2_para; ++ bak_argb = ip->osd_ch2_bak_argb; ++ src_stride = ip->osd_ch2_src_w; ++ break; ++ case 3: ++ fmt = ip->osd_ch3_fmt; ++ posx = ip->osd_ch3_pos_x; ++ posy = ip->osd_ch3_pos_y; ++ srcw = ((ip->bg_w-1) > (ip->osd_ch3_pos_x + ip->osd_ch3_src_w)) ? (ip->osd_ch3_src_w) : (ip->bg_w-1-ip->osd_ch3_pos_x); ++ srch = ((ip->bg_h-1) > (ip->osd_ch3_pos_y + ip->osd_ch3_src_h)) ? (ip->osd_ch3_src_h) : (ip->bg_h-1-ip->osd_ch3_pos_y); ++ para = ip->osd_ch3_para; ++ bak_argb = ip->osd_ch3_bak_argb; ++ src_stride = ip->osd_ch3_src_w; ++ break; ++ default : ++ printk("ipu: osd channel num err ch = %d\n", ch); ++ return -1; ++ break; ++ } ++ ++ isrgb = _ipu_osd_isrgb(fmt); ++ if (isrgb < 0) { ++ printk("ipu: osd fmt err fmt = %d\n", fmt); ++ return -1; ++ } ++ IPU_DEBUG("ipu: ch = %d, isrgb=%d, posx=%d, posy=%d, srcw=%d, srch=%d, para=%d src_stride= %d\n", ++ ch, isrgb, posx, posy, srcw, srch, para, src_stride); ++ if (isrgb == 1) { ++ ipu_reg_write(ipu, IPU_OSD_IN_CH0_Y_STRIDE+0x10*ch, src_stride*4); ++ } else if (isrgb == 2){ //The format is RGBA5551 ++ ipu_reg_write(ipu, IPU_OSD_IN_CH0_Y_STRIDE+0x10*ch, src_stride*2); ++ } else { ++ ipu_reg_write(ipu, IPU_OSD_IN_CH0_Y_STRIDE+0x10*ch, src_stride); ++ ipu_reg_write(ipu, IPU_OSD_IN_CH0_UV_STRIDE+0x10*ch, src_stride); ++ } ++ ++ if((srcw > 0) && (srch > 0)) { ++ if (isrgb == 1) ++ ipu_reg_write(ipu, IPU_OSD_CH0_GS+4*ch, (srcw << 16 << 2) | (srch << 0)); ++ else if (isrgb == 2) //The format is RGBA1555 ++ ipu_reg_write(ipu, IPU_OSD_CH0_GS+4*ch, (srcw << 16 << 1) | (srch << 0)); ++ else ++ ipu_reg_write(ipu, IPU_OSD_CH0_GS+4*ch, (srcw << 16) | (srch << 0)); ++ } ++ else ++ ipu_reg_write(ipu, IPU_OSD_CH0_GS+4*ch, (100 << 16) | (100 << 0)); ++ ++ ipu_reg_write(ipu, IPU_OSD_CH0_POS+4*ch, (posx << 16) | (posy << 0)); ++ ++ if (isrgb > 0) { ++ ipu_reg_write(ipu, IPU_CH0_CSC_C0_COEF+0x18*ch, (0x133 << 0) | (0x25A << 20)); ++ ipu_reg_write(ipu, IPU_CH0_CSC_C1_COEF+0x18*ch, (0x75 << 0) | (0x97 << 20)); ++ ipu_reg_write(ipu, IPU_CH0_CSC_C2_COEF+0x18*ch, (0x128 << 0) | (0x1BF << 20)); ++ ipu_reg_write(ipu, IPU_CH0_CSC_C3_COEF+0x18*ch, (0x276 << 0) | (0x210 << 20)); ++ ipu_reg_write(ipu, IPU_CH0_CSC_C4_COEF+0x18*ch, 0x67 ); ++ ipu_reg_write(ipu, IPU_CH0_CSC_OFSET_PARA+0x18*ch, (0x10 << 0) | (0x80 << 16)); ++ } else { ++ ipu_reg_write(ipu, IPU_CH0_CSC_C0_COEF+0x18*ch, (0x400 << 0) | (0 << 20)); ++ ipu_reg_write(ipu, IPU_CH0_CSC_C1_COEF+0x18*ch, (0x490 << 0) | (0x400 << 20)); ++ ipu_reg_write(ipu, IPU_CH0_CSC_C2_COEF+0x18*ch, (0x190 << 0) | (0x252 << 20)); ++ ipu_reg_write(ipu, IPU_CH0_CSC_C3_COEF+0x18*ch, (0x400 << 0) | (0x81f << 20)); ++ ipu_reg_write(ipu, IPU_CH0_CSC_C4_COEF+0x18*ch, 0 ); ++ ipu_reg_write(ipu, IPU_CH0_CSC_OFSET_PARA+0x18*ch, (0x10 << 0) | (0x80 << 16)); ++ } ++ ipu_reg_write(ipu, IPU_OSD_CH0_BAK_ARGB+4*ch, bak_argb); ++ if (para > 0) ++ ipu_reg_write(ipu, IPU_OSD_CH0_PARA+4*ch, para); ++ else ++ ipu_reg_write(ipu, IPU_OSD_CH0_PARA+4*ch, (0x1 | (0x2 << 11) | (0x01 << 1) | (0x32 << 3) | (0 << 19) | (0 << 18))); ++ ++ return 0; ++} ++ ++static int _ipu_set_bg_buffer(struct jz_ipu *ipu, struct ipu_param *ipu_param) ++{ ++ unsigned int bg_y_pbuf = 0; ++ unsigned int bg_u_pbuf = 0; ++ unsigned int bg_v_pbuf = 0; ++ unsigned int out_y_pbuf = 0; ++ unsigned int out_uv_pbuf = 0; ++ unsigned int out_v_pbuf = 0; ++ unsigned int out_nv21_y = 0; ++ unsigned int out_nv21_uv = 0; ++ ++ struct ipu_param *ip = ipu_param; ++ ++ IPU_DEBUG("ipu: %s:%d \n", __func__, __LINE__); ++ if (ipu == NULL) { ++ dev_err(ipu->dev, "ipu is NULL\n"); ++ return -1; ++ } ++ ++ /* nv12 */ ++ bg_y_pbuf = ((unsigned int)ip->bg_buf_p); ++ bg_u_pbuf = ((unsigned int)ip->bg_buf_p) + ip->bg_w*ip->bg_h; ++ bg_v_pbuf = bg_u_pbuf; ++ ++ if(ip->cmd & IPU_CMD_CSC) { ++ /* OUT HSV */ ++ out_y_pbuf = ((unsigned int)ip->osd_ch0_buf_p) + (ip->bg_w*ip->bg_h)*2; ++ out_uv_pbuf = ((unsigned int)ip->osd_ch0_buf_p); ++ out_v_pbuf = ((unsigned int)ip->osd_ch0_buf_p) + (ip->bg_w*ip->bg_h)*3; ++ ++ /* OUT NV21 */ ++ out_nv21_y = ((unsigned int)ip->osd_ch0_buf_p); ++ out_nv21_uv = ((unsigned int)ip->osd_ch0_buf_p) + (ip->bg_w*ip->bg_h); ++ } ++ ++ IPU_DEBUG("ipu: bg_y_pbuf = 0x%08x, bg_u_pbuf = 0x%08x, bg_v_pbuf = 0x%08x\n", bg_y_pbuf, bg_u_pbuf, bg_v_pbuf); ++ ipu_reg_write(ipu, IPU_Y_ADDR, bg_y_pbuf); ++ ipu_reg_write(ipu, IPU_U_ADDR, bg_u_pbuf); ++ ++ /* set out buff */ ++ if (ip->cmd & IPU_CMD_CSC) {/* out addr */ ++ if (ip->out_fmt == HAL_PIXEL_FORMAT_HSV) { ++ ipu_reg_write(ipu, IPU_OUT_ADDR, out_y_pbuf); ++ ipu_reg_write(ipu, IPU_NV_OUT_ADDR, out_uv_pbuf); ++ ipu_reg_write(ipu, IPU_OUT_V_ADDR, out_v_pbuf); ++ } else if (ip->out_fmt == HAL_PIXEL_FORMAT_NV21) { ++ ipu_reg_write(ipu, IPU_OUT_ADDR, out_nv21_y); ++ ipu_reg_write(ipu, IPU_NV_OUT_ADDR, out_nv21_uv); ++ } else { ++ ipu_reg_write(ipu, IPU_OUT_ADDR, out_uv_pbuf);/* OUT BGRA */ ++ } ++ } else { ++ ipu_reg_write(ipu, IPU_OUT_ADDR, bg_y_pbuf); ++ ipu_reg_write(ipu, IPU_NV_OUT_ADDR, bg_u_pbuf); ++ } ++ ++ return 0; ++} ++ ++static int _ipu_set_osdx_buffer(struct jz_ipu *ipu, struct ipu_param *ipu_param, int ch) ++{ ++ unsigned int osdx_y_pbuf = 0; ++ unsigned int osdx_uv_pbuf = 0; ++ struct ipu_param *ip = ipu_param; ++ ++ IPU_DEBUG("ipu: %s:%d \n", __func__, __LINE__); ++ if (ipu == NULL) { ++ dev_err(ipu->dev, "ipu is NULL\n"); ++ return -1; ++ } ++ if ((ch < 0) || (ch > 3)) { ++ printk("ipu: osd channel num err ch = %d\n", ch); ++ return -1; ++ } ++ switch(ch) { ++ case 0: ++ osdx_y_pbuf = (unsigned int)ip->osd_ch0_buf_p; ++ osdx_uv_pbuf = (unsigned int)ip->osd_ch0_buf_p + ip->osd_ch0_src_w * ip->osd_ch0_src_h; ++ ++ break; ++ case 1: ++ osdx_y_pbuf = (unsigned int)ip->osd_ch1_buf_p; ++ osdx_uv_pbuf = (unsigned int)ip->osd_ch1_buf_p + ip->osd_ch1_src_w * ip->osd_ch1_src_h; ++ break; ++ case 2: ++ osdx_y_pbuf = (unsigned int)ip->osd_ch2_buf_p; ++ osdx_uv_pbuf = (unsigned int)ip->osd_ch2_buf_p + ip->osd_ch2_src_w * ip->osd_ch2_src_h; ++ break; ++ case 3: ++ osdx_y_pbuf = (unsigned int)ip->osd_ch3_buf_p; ++ osdx_uv_pbuf = (unsigned int)ip->osd_ch3_buf_p + ip->osd_ch3_src_w * ip->osd_ch3_src_h; ++ break; ++ default : ++ printk("ipu: osd channel num err ch = %d\n", ch); ++ return -1; ++ break; ++ } ++ ++ /* set osd chx addr */ ++ IPU_DEBUG("ipu: ch = %d, osdx_y_pbuf = 0x%08x, osdx_uv_pbuf = 0x%08x\n", ch, osdx_y_pbuf, osdx_uv_pbuf); ++ ipu_reg_write(ipu, IPU_OSD_IN_CH0_Y_ADDR+0x10*ch, osdx_y_pbuf); ++ ipu_reg_write(ipu, IPU_OSD_IN_CH0_UV_ADDR+0x10*ch, osdx_uv_pbuf); ++ ++ return 0; ++} ++ ++static int _ipu_dump_regs(struct jz_ipu *ipu) ++{ ++ int i = 0; ++ int num = 0; ++ ++ if (ipu == NULL) { ++ dev_err(ipu->dev, "ipu is NULL!\n"); ++ return -1; ++ } ++ printk("----- dump regs -----\n"); ++ ++ num = sizeof(jz_ipu_regs_name) / sizeof(struct ipu_reg_struct); ++ for (i = 0; i < num; i++) { ++ printk("ipu_reg: %s: \t0x%08x\r\n", jz_ipu_regs_name[i].name, ipu_reg_read(ipu, jz_ipu_regs_name[i].addr)); ++ } ++ ++ return 0; ++} ++ ++static void _ipu_dump_param(struct jz_ipu *ipu) ++{ ++ return; ++} ++ ++static int ipu_dump_info(struct jz_ipu *ipu) ++{ ++ int ret = 0; ++ if (ipu == NULL) { ++ dev_err(ipu->dev, "ipu is NULL\n"); ++ return -1; ++ } ++ printk("ipu: ipu->base: %p\n", ipu->iomem); ++ _ipu_dump_param(ipu); ++ ret = _ipu_dump_regs(ipu); ++ ++ return ret; ++} ++ ++static int ipu_start(struct jz_ipu *ipu, struct ipu_param *ipu_param) ++{ ++ int ret = 0; ++ struct ipu_param *ip = ipu_param; ++ ++ if ((ipu == NULL) || (ipu_param == NULL)) { ++ dev_err(ipu->dev, "ipu: ipu is NULL or ipu_param is NULL\n"); ++ return -1; ++ } ++ if ((0 == (ip->cmd & IPU_CMD_OSD))&((0 == (ip->cmd & IPU_CMD_CSC)))) { ++ ++ printk("ipu: error cmd 0x%08x\n", ip->cmd); ++ ret = -1; ++ goto err_cmd; ++ } ++ IPU_DEBUG("ipu: enter ipu_start %d\n", current->pid); ++ ++#ifndef CONFIG_FPGA_TEST ++ clk_prepare_enable(ipu->clk); ++#ifdef CONFIG_SOC_T40 ++ clk_prepare_enable(ipu->ahb0_gate); ++#endif ++#endif ++ ++ __reset_ipu(); ++ ++ ret = _ipu_set_bg_route(ipu, ip); ++ if (ret) { ++ printk("ipu: error _ipu_set_bg_route %d\n", ret); ++ goto err_ipu_set_bg_route; ++ } ++ ret = _ipu_set_bg_buffer(ipu, ip); ++ if (ret) { ++ printk("ipu: error _ipu_set_bg_buffer %d\n", ret); ++ goto err_ipu_set_bg_buffer; ++ } ++ ++ if (ip->cmd & IPU_CMD_CSC) { ++ ipu_reg_write(ipu, IPU_REG_CTRL, 0xffffffff); ++ ipu_reg_write(ipu, IPU_OSD_CH0_PARA, 0x010417fa); ++ ipu_reg_write(ipu, IPU_OSD_CH_BK_PARA, 0x141000); ++ ++ ipu_reg_write(ipu, IPU_CH0_CSC_C0_COEF, (0x4ad << 0) | (0 << 20)); ++ ipu_reg_write(ipu, IPU_CH0_CSC_C1_COEF, (0x669 << 0) | (0x4ad << 20)); ++ ipu_reg_write(ipu, IPU_CH0_CSC_C2_COEF, (0x193 << 0) | (0x344 << 20)); ++ ipu_reg_write(ipu, IPU_CH0_CSC_C3_COEF, (0x4ad << 0) | (0x81a << 20)); ++ ipu_reg_write(ipu, IPU_CH0_CSC_C4_COEF, 0); ++ ipu_reg_write(ipu, IPU_CH0_CSC_OFSET_PARA, (0x10 << 0) | (0x80 << 16)); ++ } ++ ++ if (ip->cmd & IPU_CMD_OSD0) { ++ ret = _ipu_set_osd_chx_route(ipu, ip, 0); ++ if (ret) { ++ printk("ipu: error _ipu_set_osd_ch0_route %d\n", ret); ++ goto err_ipu_set_osd_chx_route; ++ } ++ ret = _ipu_set_osdx_buffer(ipu, ip, 0); ++ if (ret) { ++ printk("ipu: error _ipu_set_osdx_buffer %d\n", ret); ++ goto err_ipu_set_osdx_buffer; ++ } ++ } ++ if (ip->cmd & IPU_CMD_OSD1) { ++ ret = _ipu_set_osd_chx_route(ipu, ip, 1); ++ if (ret) { ++ printk("ipu: error _ipu_set_osd_ch1_route %d\n", ret); ++ goto err_ipu_set_osd_chx_route; ++ } ++ ret = _ipu_set_osdx_buffer(ipu, ip, 1); ++ if (ret) { ++ printk("ipu: error _ipu_set_osdx_buffer %d\n", ret); ++ goto err_ipu_set_osdx_buffer; ++ } ++ } ++ if (ip->cmd & IPU_CMD_OSD2) { ++ ret = _ipu_set_osd_chx_route(ipu, ip, 2); ++ if (ret) { ++ printk("ipu: error _ipu_set_osd_ch2_route %d\n", ret); ++ goto err_ipu_set_osd_chx_route; ++ } ++ ret = _ipu_set_osdx_buffer(ipu, ip, 2); ++ if (ret) { ++ printk("ipu: error _ipu_set_osdx_buffer %d\n", ret); ++ goto err_ipu_set_osdx_buffer; ++ } ++ } ++ if (ip->cmd & IPU_CMD_OSD3) { ++ ret = _ipu_set_osd_chx_route(ipu, ip, 3); ++ if (ret) { ++ printk("ipu: error _ipu_set_osd_ch3_route %d\n", ret); ++ goto err_ipu_set_osd_chx_route; ++ } ++ ret = _ipu_set_osdx_buffer(ipu, ip, 3); ++ if (ret) { ++ printk("ipu: error _ipu_set_osdx_buffer %d\n", ret); ++ goto err_ipu_set_osdx_buffer; ++ } ++ } ++ ++ __clear_ipu_out_end(); ++ __ipu_enable_irq(); ++ ++ ipu_reg_write(ipu, IPU_REG_CTRL, 0xffffffff); ++ ++ /* reg_bit_set(ipu, IPU_TRIGGER, 6<<6); */ ++ /* start ipu */ ++ __start_ipu(); ++ ++#ifdef DEBUG ++ ipu_dump_info(ipu); ++#endif ++ IPU_DEBUG("ipu_start\n"); ++ ++ ret = wait_for_completion_interruptible_timeout(&ipu->done_ipu, msecs_to_jiffies(2000)); ++ if (ret < 0) { ++ printk("ipu: done_ipu wait_for_completion_interruptible_timeout err %d\n", ret); ++ __ipu_disable_irq(); ++ __stop_ipu(); ++ ret = 100; ++ while(((ipu_reg_read(ipu, IPU_STATUS)) & 0x30) && ret) { ++ msleep(10); ++ printk("IPU is running\n"); ++ ret--; ++ } ++ ret = -1; ++ goto err_ipu_wait_for_done; ++ } else if (ret == 0 ) { ++ ret = -1; ++ printk("ipu: done_ipu wait_for_completion_interruptible_timeout timeout %d\n", ret); ++ ipu_dump_info(ipu); ++ ++ __ipu_disable_irq(); ++ __stop_ipu(); ++ ret = 100; ++ while(((ipu_reg_read(ipu, IPU_STATUS)) & 0x30) && ret) { ++ msleep(10); ++ printk("timeout status IPU is running\n"); ++ ret--; ++ } ++ ret = -1; ++ goto err_ipu_wait_for_done; ++ } else { ++ __stop_ipu(); ++ ret = 100; ++ while(((ipu_reg_read(ipu, IPU_STATUS)) & 0x30) && ret) { ++ msleep(10); ++ printk("IPU is running\n"); ++ ret--; ++ } ++ } ++ IPU_DEBUG("ipu: exit ipu_start %d\n", current->pid); ++ ++#ifndef CONFIG_FPGA_TEST ++ clk_disable_unprepare(ipu->clk); ++#ifdef CONFIG_SOC_T40 ++ clk_disable_unprepare(ipu->ahb0_gate); ++#endif ++#endif ++ ++ return 0; ++ ++err_ipu_wait_for_done: ++err_ipu_set_osdx_buffer: ++err_ipu_set_bg_buffer: ++err_ipu_set_osd_chx_route: ++err_ipu_set_bg_route: ++#ifndef CONFIG_FPGA_TEST ++ clk_disable_unprepare(ipu->clk); ++#ifdef CONFIG_SOC_T40 ++ clk_disable_unprepare(ipu->ahb0_gate); ++#endif ++#endif ++err_cmd: ++ return ret; ++} ++ ++static long ipu_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ int ret = 0; ++ struct ipu_param iparam; ++ struct miscdevice *dev = filp->private_data; ++ struct jz_ipu *ipu = container_of(dev, struct jz_ipu, misc_dev); ++ ++ IPU_DEBUG("ipu: %s pid: %d, tgid: %d file: %p, cmd: 0x%08x\n", ++ __func__, current->pid, current->tgid, filp, cmd); ++ ++ if (_IOC_TYPE(cmd) != JZIPU_IOC_MAGIC) { ++ dev_err(ipu->dev, "invalid cmd!\n"); ++ return -EFAULT; ++ } ++ ++ mutex_lock(&ipu->mutex); ++ ++ switch (cmd) { ++ case IOCTL_IPU_START: ++ if (copy_from_user(&iparam, (void *)arg, sizeof(struct ipu_param))) { ++ dev_err(ipu->dev, "copy_from_user error!!!\n"); ++ ret = -EFAULT; ++ break; ++ } ++ ret = ipu_start(ipu, &iparam); ++ if (ret) { ++ printk("ipu: error ipu start ret = %d\n", ret); ++ } ++ break; ++ case IOCTL_IPU_GET_PBUFF: ++ if (ipu->pbuf.vaddr_alloc == 0) { ++ unsigned int size = IPU_BUF_SIZE; ++ ipu->pbuf.vaddr_alloc = (unsigned int)kmalloc(size, GFP_KERNEL); ++ if (!ipu->pbuf.vaddr_alloc) { ++ printk("ipu kmalloc is error\n"); ++ ret = -ENOMEM; ++ } ++ memset((void*)(ipu->pbuf.vaddr_alloc), 0x00, size); ++ ipu->pbuf.size = size; ++ ipu->pbuf.paddr = virt_to_phys((void *)(ipu->pbuf.vaddr_alloc)); ++ ipu->pbuf.paddr_align = ((unsigned long)(ipu->pbuf.paddr)); ++ } ++ IPU_DEBUG("ipu: %s ipu->pbuf.vaddr_alloc = 0x%08x\nipu->pbuf.vaddr_align = 0x%08x\nipu->pbuf.size = 0x%x\nipu->pbuf.paddr = 0x%08x\n" ++ , __func__, ipu->pbuf.vaddr_alloc, ipu->pbuf.paddr_align, ipu->pbuf.size, ipu->pbuf.paddr); ++ if (copy_to_user((void *)arg, &ipu->pbuf, sizeof(struct ipu_buf_info))) { ++ dev_err(ipu->dev, "copy_to_user error!!!\n"); ++ ret = -EFAULT; ++ } ++ break; ++ case IOCTL_IPU_RES_PBUFF: ++ if (ipu->pbuf.vaddr_alloc != 0) { ++ kfree((void *)ipu->pbuf.vaddr_alloc); ++ ipu->pbuf.vaddr_alloc = 0; ++ ipu->pbuf.size = 0; ++ ipu->pbuf.paddr = 0; ++ ipu->pbuf.paddr_align = 0; ++ } else { ++ dev_warn(ipu->dev, "buffer wanted to free is null\n"); ++ } ++ break; ++ case IOCTL_IPU_BUF_LOCK: ++ ret = wait_for_completion_interruptible_timeout(&ipu->done_buf, msecs_to_jiffies(2000)); ++ if (ret < 0) { ++ printk("ipu: done_buf wait_for_completion_interruptible_timeout err %d\n", ret); ++ } else if (ret == 0 ) { ++ printk("ipu: done_buf wait_for_completion_interruptible_timeout timeout %d\n", ret); ++ ret = -1; ++ ipu_dump_info(ipu); ++ } else { ++ ret = 0; ++ } ++ break; ++ case IOCTL_IPU_BUF_UNLOCK: ++ complete(&ipu->done_buf); ++ break; ++ case IOCTL_IPU_BUF_FLUSH_CACHE: ++ { ++ struct ipu_flush_cache_para fc; ++ if (copy_from_user(&fc, (void *)arg, sizeof(fc))) { ++ dev_err(ipu->dev, "copy_from_user error!!!\n"); ++ ret = -EFAULT; ++ break; ++ } ++ //dma_sync_single_for_device(NULL, fc.addr, fc.size, DMA_TO_DEVICE); ++ //dma_sync_single_for_device(NULL, fc.addr, fc.size, DMA_FROM_DEVICE); ++ dma_cache_sync(NULL, fc.addr, fc.size, DMA_BIDIRECTIONAL); ++ } ++ break; ++ default: ++ dev_err(ipu->dev, "invalid command: 0x%08x\n", cmd); ++ ret = -EINVAL; ++ } ++ ++ mutex_unlock(&ipu->mutex); ++ return ret; ++} ++ ++static int ipu_open(struct inode *inode, struct file *filp) ++{ ++ int ret = 0; ++ ++ struct miscdevice *dev = filp->private_data; ++ struct jz_ipu *ipu = container_of(dev, struct jz_ipu, misc_dev); ++ ++ IPU_DEBUG("ipu: %s pid: %d, tgid: %d filp: %p\n", ++ __func__, current->pid, current->tgid, filp); ++ mutex_lock(&ipu->mutex); ++ ++ mutex_unlock(&ipu->mutex); ++ return ret; ++} ++ ++static int ipu_release(struct inode *inode, struct file *filp) ++{ ++ int ret = 0; ++ ++ struct miscdevice *dev = filp->private_data; ++ struct jz_ipu *ipu = container_of(dev, struct jz_ipu, misc_dev); ++ ++ IPU_DEBUG("ipu: %s pid: %d, tgid: %d filp: %p\n", ++ __func__, current->pid, current->tgid, filp); ++ mutex_lock(&ipu->mutex); ++ ++ mutex_unlock(&ipu->mutex); ++ return ret; ++} ++ ++static struct file_operations ipu_ops = { ++ .owner = THIS_MODULE, ++ .open = ipu_open, ++ .release = ipu_release, ++ .unlocked_ioctl = ipu_ioctl, ++}; ++ ++static irqreturn_t ipu_irq_handler(int irq, void *data) ++{ ++ struct jz_ipu *ipu; ++ unsigned int status; ++ ++ IPU_DEBUG("ipu: %s\n", __func__); ++ ipu = (struct jz_ipu *)data; ++ __ipu_disable_irq(); ++ status = ipu_reg_read(ipu, IPU_STATUS); ++ IPU_DEBUG("----- %s, status= 0x%08x\n", __func__, status); ++ /* t10 supports 720P and max width 1280, but t20 supports 1080P and max width ++ * is 1920; the width is limited to 1280 in hardware, so t20 status is 0x4, ++ * and this status doesn't do anything including trigger interrupt, ++ * just give a hint */ ++ if (status & 0x1){ ++ complete(&ipu->done_ipu); ++ } ++ return IRQ_HANDLED; ++} ++ ++static int ipu_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ struct jz_ipu *ipu; ++ ++ IPU_DEBUG("%s\n", __func__); ++ ipu = (struct jz_ipu *)kzalloc(sizeof(struct jz_ipu), GFP_KERNEL); ++ if (!ipu) { ++ dev_err(&pdev->dev, "alloc jz_ipu failed!\n"); ++ return -ENOMEM; ++ } ++ ++ sprintf(ipu->name, "ipu"); ++ ++ ipu->misc_dev.minor = MISC_DYNAMIC_MINOR; ++ ipu->misc_dev.name = ipu->name; ++ ipu->misc_dev.fops = &ipu_ops; ++ ipu->dev = &pdev->dev; ++ ++ mutex_init(&ipu->mutex); ++ init_completion(&ipu->done_ipu); ++ init_completion(&ipu->done_buf); ++ complete(&ipu->done_buf); ++ ++ ipu->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!ipu->res) { ++ dev_err(&pdev->dev, "failed to get dev resources: %d\n", ret); ++ ret = -EINVAL; ++ goto err_get_platform_res; ++ } ++ ipu->res = request_mem_region(ipu->res->start, ++ ipu->res->end - ipu->res->start + 1, ++ pdev->name); ++ if (!ipu->res) { ++ dev_err(&pdev->dev, "failed to request regs memory region"); ++ ret = -EINVAL; ++ goto err_get_mem_region; ++ } ++ ipu->iomem = ioremap(ipu->res->start, resource_size(ipu->res)); ++ if (!ipu->iomem) { ++ dev_err(&pdev->dev, "failed to remap regs memory region: %d\n",ret); ++ ret = -EINVAL; ++ goto err_ioremap; ++ } ++ ++ ipu->irq = platform_get_irq(pdev, 0); ++ if (request_irq(ipu->irq, ipu_irq_handler, IRQF_SHARED, ipu->name, ipu)) { ++ dev_err(&pdev->dev, "request irq failed\n"); ++ ret = -EINVAL; ++ goto err_req_irq; ++ } ++ ++#ifndef CONFIG_FPGA_TEST ++ ipu->clk = devm_clk_get(ipu->dev, "gate_ipu"); ++ if (IS_ERR(ipu->clk)) { ++ dev_err(&pdev->dev, "ipu clk get failed!\n"); ++ ret = -EINVAL; ++ goto err_get_ipu_clk; ++ } ++#ifdef CONFIG_SOC_T40 ++ ipu->ahb0_gate = devm_clk_get(ipu->dev, "gate_ahb0"); ++ if (IS_ERR(ipu->clk)) { ++ dev_err(&pdev->dev, "ipu ahb0 clk get failed!\n"); ++ ret = -EINVAL; ++ goto err_get_ahb0_clk; ++ } ++#endif ++#endif ++ ++ dev_set_drvdata(&pdev->dev, ipu); ++ ++ __reset_ipu(); ++ ret = misc_register(&ipu->misc_dev); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "register misc device failed!\n"); ++ goto err_misc_register; ++ } ++ ++ return 0; ++ ++err_misc_register: ++#ifndef CONFIG_FPGA_TEST ++#ifdef CONFIG_SOC_T40 ++ devm_clk_put(ipu->dev, ipu->ahb0_gate); ++err_get_ahb0_clk: ++#endif ++ devm_clk_put(ipu->dev, ipu->clk); ++err_get_ipu_clk: ++#endif ++ free_irq(ipu->irq, ipu); ++err_req_irq: ++ iounmap(ipu->iomem); ++err_ioremap: ++ release_mem_region(ipu->res->start, ipu->res->end - ipu->res->start + 1); ++err_get_platform_res: ++err_get_mem_region: ++ kfree(ipu); ++ ++ return ret; ++} ++ ++static int ipu_remove(struct platform_device *pdev) ++{ ++ struct jz_ipu *ipu; ++ struct resource *res; ++ IPU_DEBUG("%s\n", __func__); ++ ++ ipu = dev_get_drvdata(&pdev->dev); ++ misc_deregister(&ipu->misc_dev); ++#ifndef CONFIG_FPGA_TEST ++#ifdef CONFIG_SOC_T40 ++ devm_clk_put(ipu->dev, ipu->ahb0_gate); ++#endif ++ devm_clk_put(ipu->dev, ipu->clk); ++#endif ++ res = ipu->res; ++ free_irq(ipu->irq, ipu); ++ iounmap(ipu->iomem); ++ release_mem_region(res->start, res->end - res->start + 1); ++ ++ if (ipu->pbuf.vaddr_alloc) { ++ kfree((void *)(ipu->pbuf.vaddr_alloc)); ++ ipu->pbuf.vaddr_alloc = 0; ++ } ++ if (ipu) { ++ kfree(ipu); ++ } ++ ++ return 0; ++} ++ ++static const struct of_device_id ingenic_ipu_dt_match[] = { ++ { .compatible = "ingenic,t40-ipu", .data = NULL }, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(of, ingenic_ipu_dt_match); ++ ++static struct platform_driver jz_ipu_driver = { ++ .probe = ipu_probe, ++ .remove = ipu_remove, ++ .driver = { ++ .name = "jz-ipu", ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(ingenic_ipu_dt_match), ++ }, ++}; ++ ++static int __init ipudev_init(void) ++{ ++ IPU_DEBUG("%s\n", __func__); ++ platform_driver_register(&jz_ipu_driver); ++ dboxdev_init(); ++ return 0; ++} ++ ++static void __exit ipudev_exit(void) ++{ ++ IPU_DEBUG("%s\n", __func__); ++ platform_driver_unregister(&jz_ipu_driver); ++ dboxdev_exit(); ++} ++ ++module_init(ipudev_init); ++module_exit(ipudev_exit); ++ ++MODULE_DESCRIPTION("JZ IPU driver"); ++MODULE_AUTHOR("Ferdinand Jia "); ++MODULE_LICENSE("GPL"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_ipu_ingenic_ipu_v13.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_ipu_ingenic_ipu_v13.h.patch new file mode 100644 index 00000000..f3559456 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_ipu_ingenic_ipu_v13.h.patch @@ -0,0 +1,212 @@ +diff -drupN a/drivers/video/ingenic_ipu/ingenic_ipu_v13.h b/drivers/video/ingenic_ipu/ingenic_ipu_v13.h +--- a/drivers/video/ingenic_ipu/ingenic_ipu_v13.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/ingenic_ipu/ingenic_ipu_v13.h 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,208 @@ ++#ifndef _JZ_IPU_H_ ++#define _JZ_IPU_H_ ++ ++#define IPU_LUT_LEN 32 ++ ++/* ipu output mode */ ++#define IPU_OUTPUT_TO_LCD_FG1 0x00000002 ++#define IPU_OUTPUT_TO_LCD_FB0 0x00000004 ++#define IPU_OUTPUT_TO_LCD_FB1 0x00000008 ++#define IPU_OUTPUT_TO_FRAMEBUFFER 0x00000010 /* output to user defined buffer */ ++#define IPU_OUTPUT_MODE_MASK 0x000000FF ++#define IPU_DST_USE_COLOR_KEY 0x00000100 ++#define IPU_DST_USE_ALPHA 0x00000200 ++#define IPU_OUTPUT_BLOCK_MODE 0x00000400 ++#define IPU_OUTPUT_MODE_FG0_OFF 0x00000800 ++#define IPU_OUTPUT_MODE_FG1_TVOUT 0x00001000 ++#define IPU_DST_USE_PERPIXEL_ALPHA 0x00010000 ++ ++#ifdef __KERNEL__ ++ ++/* match HAL_PIXEL_FORMAT_ in system/core/include/system/graphics.h */ ++enum { ++ HAL_PIXEL_FORMAT_RGBA_8888 = 1, ++ HAL_PIXEL_FORMAT_RGBX_8888 = 2, ++ HAL_PIXEL_FORMAT_RGB_888 = 3, ++ HAL_PIXEL_FORMAT_RGB_565 = 4, ++ HAL_PIXEL_FORMAT_BGRA_8888 = 5, ++ //HAL_PIXEL_FORMAT_BGRX_8888 = 0x8000, /* Add BGRX_8888, Wolfgang, 2010-07-24 */ ++ HAL_PIXEL_FORMAT_BGRX_8888 = 0x1ff, /* 2012-10-23 */ ++ HAL_PIXEL_FORMAT_RGBA_5551 = 6, ++ HAL_PIXEL_FORMAT_RGBA_4444 = 7, ++ HAL_PIXEL_FORMAT_ABGR_8888 = 8, ++ HAL_PIXEL_FORMAT_ARGB_8888 = 9, ++ HAL_PIXEL_FORMAT_YCbCr_422_SP = 0x10, ++ HAL_PIXEL_FORMAT_YCbCr_420_SP = 0x11, ++ HAL_PIXEL_FORMAT_YCbCr_422_P = 0x12, ++ HAL_PIXEL_FORMAT_YCbCr_420_P = 0x13, ++ HAL_PIXEL_FORMAT_YCbCr_420_B = 0x24, ++ HAL_PIXEL_FORMAT_YCbCr_422_I = 0x14, ++ HAL_PIXEL_FORMAT_YCbCr_420_I = 0x15, ++ HAL_PIXEL_FORMAT_CbYCrY_422_I = 0x16, ++ HAL_PIXEL_FORMAT_CbYCrY_420_I = 0x17, ++ HAL_PIXEL_FORMAT_NV12 = 0x18, ++ HAL_PIXEL_FORMAT_NV21 = 0x19, ++ HAL_PIXEL_FORMAT_BGRA_5551 = 0x1a, ++ HAL_PIXEL_FORMAT_HSV = 0x1b,/*Add HSV*/ ++ ++ /* suport for YUV420 */ ++ HAL_PIXEL_FORMAT_JZ_YUV_420_P = 0x47700001, // YUV_420_P ++ HAL_PIXEL_FORMAT_JZ_YUV_420_B = 0x47700002, // YUV_420_P BLOCK MODE ++}; ++ ++typedef struct { ++ unsigned int coef; ++ unsigned short int in_n; ++ unsigned short int out_n; ++} rsz_lut; ++ ++#endif /* ifdef __KERNEL__ */ ++ ++enum { ++ ZOOM_MODE_BILINEAR = 0, ++ ZOOM_MODE_BICUBE, ++ ZOOM_MODE_BILINEAR_ENHANCE, ++}; ++ ++struct YuvCsc ++{ // YUV(default) or YCbCr ++ unsigned int csc0; // 0x400 0x4A8 ++ unsigned int csc1; // 0x59C 0x662 ++ unsigned int csc2; // 0x161 0x191 ++ unsigned int csc3; // 0x2DC 0x341 ++ unsigned int csc4; // 0x718 0x811 ++ unsigned int chrom; // 128 128 ++ unsigned int luma; // 0 16 ++}; ++ ++struct YuvStride ++{ ++ unsigned int y; ++ unsigned int u; ++ unsigned int v; ++ unsigned int out; ++ unsigned int out_uv; ++}; ++ ++struct ipu_param ++{ ++ unsigned int cmd; /* IPU command */ ++ ++ unsigned int bg_w; /* background weight */ ++ unsigned int bg_h; /* background hight */ ++ unsigned int bg_fmt; /* background format */ ++ unsigned int bg_buf_p; /* background buffer physical addr */ ++ ++ unsigned int out_fmt; /* out format */ ++ ++ unsigned int osd_ch0_fmt; ++ unsigned int osd_ch0_para; ++ unsigned int osd_ch0_bak_argb; ++ unsigned int osd_ch0_pos_x; ++ unsigned int osd_ch0_pos_y; ++ unsigned int osd_ch0_src_w; ++ unsigned int osd_ch0_src_h; ++ unsigned int osd_ch0_buf_p; ++ ++ ++ unsigned int osd_ch1_fmt; ++ unsigned int osd_ch1_para; ++ unsigned int osd_ch1_bak_argb; ++ unsigned int osd_ch1_pos_x; ++ unsigned int osd_ch1_pos_y; ++ unsigned int osd_ch1_src_w; ++ unsigned int osd_ch1_src_h; ++ unsigned int osd_ch1_buf_p; ++ ++ ++ unsigned int osd_ch2_fmt; ++ unsigned int osd_ch2_para; ++ unsigned int osd_ch2_bak_argb; ++ unsigned int osd_ch2_pos_x; ++ unsigned int osd_ch2_pos_y; ++ unsigned int osd_ch2_src_w; ++ unsigned int osd_ch2_src_h; ++ unsigned int osd_ch2_buf_p; ++ ++ unsigned int osd_ch3_fmt; ++ unsigned int osd_ch3_para; ++ unsigned int osd_ch3_bak_argb; ++ unsigned int osd_ch3_pos_x; ++ unsigned int osd_ch3_pos_y; ++ unsigned int osd_ch3_src_w; ++ unsigned int osd_ch3_src_h; ++ unsigned int osd_ch3_buf_p; ++ ++}; ++ ++ ++#define IPU_CMD_OSD0 (1<<0) ++#define IPU_CMD_OSD1 (1<<1) ++#define IPU_CMD_OSD2 (1<<2) ++#define IPU_CMD_OSD3 (1<<3) ++#define IPU_CMD_OSD (0xF<<0) ++#define IPU_CMD_CSC (1<<4) ++ ++#ifdef __KERNEL__ ++ ++/* ++ * IPU driver's native data ++ */ ++ ++struct ipu_reg_struct { ++ char *name; ++ unsigned int addr; ++}; ++ ++struct ipu_buf_info { ++ unsigned int vaddr_alloc; ++ unsigned int paddr; ++ unsigned int paddr_align; ++ unsigned int size; ++}; ++ ++struct jz_ipu { ++ ++ int irq; ++ char name[16]; ++ ++ struct clk *clk; ++ struct clk *ahb0_gate; /* T31 IPU mount at AHB0*/ ++ void __iomem *iomem; ++ struct device *dev; ++ struct resource *res; ++ struct miscdevice misc_dev; ++ ++ struct mutex mutex; ++ struct completion done_ipu; ++ struct completion done_buf; ++ struct ipu_buf_info pbuf; ++}; ++ ++struct ipu_flush_cache_para ++{ ++ void *addr; ++ unsigned int size; ++}; ++ ++#define JZIPU_IOC_MAGIC 'I' ++#define IOCTL_IPU_START _IO(JZIPU_IOC_MAGIC, 106) ++#define IOCTL_IPU_RES_PBUFF _IO(JZIPU_IOC_MAGIC, 114) ++#define IOCTL_IPU_GET_PBUFF _IO(JZIPU_IOC_MAGIC, 115) ++#define IOCTL_IPU_BUF_LOCK _IO(JZIPU_IOC_MAGIC, 116) ++#define IOCTL_IPU_BUF_UNLOCK _IO(JZIPU_IOC_MAGIC, 117) ++#define IOCTL_IPU_BUF_FLUSH_CACHE _IO(JZIPU_IOC_MAGIC, 118) ++ ++static inline unsigned int ipu_reg_read(struct jz_ipu *jzipu, int offset) ++{ ++ return readl(jzipu->iomem + offset); ++} ++ ++static inline void ipu_reg_write(struct jz_ipu *jzipu, int offset, unsigned int val) ++{ ++ writel(val, jzipu->iomem + offset); ++} ++ ++#endif /* #ifdef __KERNEL__ */ ++ ++#endif // _JZ_IPU_H_ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_ipu_ingenic_regs_v13.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_ipu_ingenic_regs_v13.h.patch new file mode 100644 index 00000000..9b2758d2 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_video_ingenic_ipu_ingenic_regs_v13.h.patch @@ -0,0 +1,354 @@ +diff -drupN a/drivers/video/ingenic_ipu/ingenic_regs_v13.h b/drivers/video/ingenic_ipu/ingenic_regs_v13.h +--- a/drivers/video/ingenic_ipu/ingenic_regs_v13.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/video/ingenic_ipu/ingenic_regs_v13.h 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,350 @@ ++#ifndef _REGS_IPU_H_ ++#define _REGS_IPU_H_ ++ ++#ifdef __KERNEL__ ++ ++/* Module for CLKGR */ ++#define IDCT_CLOCK (1 << 27) ++#define DBLK_CLOCK (1 << 26) ++#define ME_CLOCK (1 << 25) ++#define MC_CLOCK (1 << 24) ++#define IPU_CLOCK (1 << 13) ++ ++ ++/* Register offset */ ++#define IPU_FM_CTRL 0x0 ++#define IPU_STATUS 0x4 ++#define IPU_D_FMT 0x8 ++#define IPU_Y_ADDR 0xc ++#define IPU_U_ADDR 0x10 ++#define IPU_IN_FM_GS 0x18 ++#define IPU_Y_STRIDE 0x1c ++#define IPU_UV_STRIDE 0x20 ++ ++#define IPU_OUT_ADDR 0x24 ++#define IPU_OUT_STRIDE 0x2c ++#define IPU_OUT_V_ADDR 0x30 ++#define IPU_OUT_V_STRIDE 0x34 ++ ++#define IPU_REG_CTRL 0x64 ++#define IPU_TRIGGER 0x74 ++#define IPU_GLB_CTRL 0x7C ++ ++#define IPU_NV_OUT_ADDR 0xb4 ++#define IPU_NV_OUT_STRIDE 0xb8 ++#define IPU_OSD_IN_CH0_Y_ADDR 0xbc ++#define IPU_OSD_IN_CH0_Y_STRIDE 0xc0 ++#define IPU_OSD_IN_CH0_UV_ADDR 0xc4 ++#define IPU_OSD_IN_CH0_UV_STRIDE 0xc8 ++#define IPU_OSD_IN_CH1_Y_ADDR 0xcc ++#define IPU_OSD_IN_CH1_Y_STRIDE 0xd0 ++#define IPU_OSD_IN_CH1_UV_ADDR 0xd4 ++#define IPU_OSD_IN_CH1_UV_STRIDE 0xd8 ++#define IPU_OSD_IN_CH2_Y_ADDR 0xdc ++#define IPU_OSD_IN_CH2_Y_STRIDE 0xe0 ++#define IPU_OSD_IN_CH2_UV_ADDR 0xe4 ++#define IPU_OSD_IN_CH2_UV_STRIDE 0xe8 ++#define IPU_OSD_IN_CH3_Y_ADDR 0xec ++#define IPU_OSD_IN_CH3_Y_STRIDE 0xf0 ++#define IPU_OSD_IN_CH3_UV_ADDR 0xf4 ++#define IPU_OSD_IN_CH3_UV_STRIDE 0xf8 ++#define IPU_OSD_CH0_GS 0xfc ++#define IPU_OSD_CH1_GS 0x100 ++#define IPU_OSD_CH2_GS 0x104 ++#define IPU_OSD_CH3_GS 0x108 ++#define IPU_OSD_CH0_POS 0x10c ++#define IPU_OSD_CH1_POS 0x110 ++#define IPU_OSD_CH2_POS 0x114 ++#define IPU_OSD_CH3_POS 0x118 ++#define IPU_OSD_CH0_PARA 0x11c ++#define IPU_OSD_CH1_PARA 0x120 ++#define IPU_OSD_CH2_PARA 0x124 ++#define IPU_OSD_CH3_PARA 0x128 ++#define IPU_OSD_CH_BK_PARA 0x12c ++ ++#define IPU_OSD_CH0_BAK_ARGB 0x130 ++#define IPU_OSD_CH1_BAK_ARGB 0x134 ++#define IPU_OSD_CH2_BAK_ARGB 0x138 ++#define IPU_OSD_CH3_BAK_ARGB 0x13c ++#define IPU_OSD_CH_B_BAK_ARGB 0x140 ++ ++#define IPU_CH0_CSC_C0_COEF 0x148 ++#define IPU_CH0_CSC_C1_COEF 0x14c ++#define IPU_CH0_CSC_C2_COEF 0x150 ++#define IPU_CH0_CSC_C3_COEF 0x154 ++#define IPU_CH0_CSC_C4_COEF 0x158 ++#define IPU_CH0_CSC_OFSET_PARA 0x15c ++ ++#define IPU_CH1_CSC_C0_COEF 0x160 ++#define IPU_CH1_CSC_C1_COEF 0x164 ++#define IPU_CH1_CSC_C2_COEF 0x168 ++#define IPU_CH1_CSC_C3_COEF 0x16c ++#define IPU_CH1_CSC_C4_COEF 0x170 ++#define IPU_CH1_CSC_OFSET_PARA 0x174 ++ ++#define IPU_CH2_CSC_C0_COEF 0x178 ++#define IPU_CH2_CSC_C1_COEF 0x17c ++#define IPU_CH2_CSC_C2_COEF 0x180 ++#define IPU_CH2_CSC_C3_COEF 0x184 ++#define IPU_CH2_CSC_C4_COEF 0x188 ++#define IPU_CH2_CSC_OFSET_PARA 0x18c ++ ++#define IPU_CH3_CSC_C0_COEF 0x190 ++#define IPU_CH3_CSC_C1_COEF 0x194 ++#define IPU_CH3_CSC_C2_COEF 0x198 ++#define IPU_CH3_CSC_C3_COEF 0x19c ++#define IPU_CH3_CSC_C4_COEF 0x1a0 ++#define IPU_CH3_CSC_OFSET_PARA 0x1a4 ++ ++#define IPU_RD_ARB_CTL 0x1a8 ++#define IPU_CLK_NUM_ONE_FRA 0x1ac ++#define IPU_OSD_LAY_PADDING_ARGB 0x1b0 ++#define IPU_TEST_1B4 0x1b4 ++ ++ ++/* SET CH_BK_PARA Register*/ ++#define CH_BK_EN (1 << 0) ++#define CH_BK_PIXEL_ALPHA (0 << 2) //default ++#define CH_BK_GLOBAL_ALPHA (1 << 1) ++#define CH_BK_PALPHA_X_GALPHA (1 << 2) ++#define CH_BKCH_BK_GLO_A(val) ((val) << 3) ++ ++#define CH_BK_PIC_TYPE ( 11 ) ++#define CH_BK_PIC_TYPE_ARGB (0 << CH_BK_PIC_TYPE) ++#define CH_BK_PIC_TYPE_RGB (1 << CH_BK_PIC_TYPE) ++#define CH_BK_PIC_TYPE_NV12 (2 << CH_BK_PIC_TYPE) ++#define CH_BK_PIC_TYPE_NV21 (3 << CH_BK_PIC_TYPE) ++ ++/* ++0000: ARGB 0001: ARBG ++0010: AGRB 0011: AGBR ++0100: ABRG 0101: ABGR ++1000: RGBA 1001: RBGA ++1010: GRBA 1011: GBRA ++1100: BRGA 1101: BGRA ++*/ ++#define CH_BK_ARGB_TYPE ( 14 ) ++#define CH_BK_ARGB_TYPE_ARGB (0 << CH_BK_ARGB_TYPE) ++#define CH_BK_ARGB_TYPE_ARBG (1 << CH_BK_ARGB_TYPE) ++#define CH_BK_ARGB_TYPE_AGRB (2 << CH_BK_ARGB_TYPE) ++#define CH_BK_ARGB_TYPE_AGBR (3 << CH_BK_ARGB_TYPE) ++#define CH_BK_ARGB_TYPE_ABRG (4 << CH_BK_ARGB_TYPE) ++#define CH_BK_ARGB_TYPE_ABGR (5 << CH_BK_ARGB_TYPE) ++#define CH_BK_ARGB_TYPE_RGBA (8 << CH_BK_ARGB_TYPE) ++#define CH_BK_ARGB_TYPE_RBGA (9 << CH_BK_ARGB_TYPE) ++#define CH_BK_ARGB_TYPE_GRBA (0xa << CH_BK_ARGB_TYPE) ++#define CH_BK_ARGB_TYPE_GBRA (0xb << CH_BK_ARGB_TYPE) ++#define CH_BK_ARGB_TYPE_BRGA (0xc << CH_BK_ARGB_TYPE) ++#define CH_BK_ARGB_TYPE_BGRA (0xd << CH_BK_ARGB_TYPE) ++ ++#define CH_BK_PREM (1 << 18) ++#define CH_BK_MASK_EN (1 << 19) ++#define CH_BK_WHOLE_PIC_EN (1 << 20) ++ ++/*OSD_CHN_EN*/ ++#define CHOOSE_OSD_CHN_RESIZE (1 << 5) ++ ++/* IPU_GLB_CTRL Register */ ++#define IRQ_EN (1 << 0) ++ ++/* IPU_OSD_CTRL Register */ ++#define OSD_PM (1 << 2) ++ ++/* IPU_TRIG Register */ ++#define IPU_RUN (1 << 0) ++#define IPU_STOP (1 << 1) ++#define IPU_RESET (1 << 3) ++ ++/* IPU_D_FMT Register */ ++#define BLK_SEL (1 << 4) ++#define RGB_POS (1 << 5) ++#define AL_PIX_EN (1 << 6) ++ ++/* REG_STATUS field define */ ++#define OUT_END (1 << 0) ++#define SIZE_ERR (1 << 2) ++#define ID (1 << 16) ++ ++#define MSTATUS_SFT (4) ++#define MSTATUS_MSK (3) ++#define MSTATUS_IPU_FREE (0 << MSTATUS_SFT) ++#define MSTATUS_IPU_RUNNING (1 << MSTATUS_SFT) ++#define MSTATUS (2 << MSTATUS_SFT) ++ ++/* REG_IPU_ADDR_CTRL */ ++#define Y_RY (1<<0) ++#define U_RY (1<<1) ++#define V_RY (1<<2) ++#define D_RY (1<<3) ++#define PTS_RY (1<<4) ++#define CTRL_RY (1<<6) ++#define DF_RY (1<<7) ++#define NV_D_RY (1 << 17) ++#define NV_STR_RY (1 << 20) ++#define OSD_CH0_RY (1 << 21) ++#define OSD_CH1_RY (1 << 22) ++#define OSD_CH2_RY (1 << 23) ++#define OSD_CH3_RY (1 << 24) ++#define RD_ARB_RY (1 << 26) ++#define OSD_BK_RY (1 << 27) ++ ++/* REG_TLB_MONITOR */ ++#define MIS_CNT_SFT (1) ++#define MIS_CNT_MSK (0x3FF) ++ ++/* REG_TLB_CTRL */ ++#define SRC_PAGE_SFT (0) ++#define SRC_PAGE_MSK (0xF) ++#define SRC_BURST_SFT (4) ++#define SRC_BURST_MSK (0xF) ++#define DEST_PAGE_SFT (16) ++#define DEST_PAGE_MSK (0xF) ++#define DEST_BURST_SFT (20) ++#define DEST_BURST_MSK (0xF) ++ ++/* OSD_CTRL field define */ ++#define GLB_ALPHA(val) ((val) << 8) ++#define MOD_OSD(val) ((val) << 0) ++ ++/* FM_XYOFT field define */ ++#define SCREEN_YOFT(val) ((val) << 16) ++#define SCREEN_XOFT(val) ((val) << 0) ++ ++/* REG_IN_GS field define */ ++#define IN_FM_W(val) ((val) << 16) ++#define IN_FM_H(val) ((val) << 0) ++ ++/* REG_OUT_GS field define */ ++#define OUT_FM_W(val) ((val) << 16) ++#define OUT_FM_H(val) ((val) << 0) ++ ++/* REG_UV_STRIDE field define */ ++#define U_STRIDE(val) ((val) << 16) ++#define V_STRIDE(val) ((val) << 0) ++ ++/* REG_RSZ_COEF field definei */ ++#define HCOEF(val) ((val) << 16) ++#define VCOEF(val) ((val) << 0) ++ ++#if 1 ++#define YUV_CSC_C0 0x4A8 /* 1.164 * 1024 */ ++#define YUV_CSC_C1 0x662 /* 1.596 * 1024 */ ++#define YUV_CSC_C2 0x191 /* 0.392 * 1024 */ ++#define YUV_CSC_C3 0x341 /* 0.813 * 1024 */ ++#define YUV_CSC_C4 0x811 /* 2.017 * 1024 */ ++ ++#define YUV_CSC_OFFSET_PARA 0x800010 /* chroma,luma */ ++#else ++#define YUV_CSC_C0 0x400 ++#define YUV_CSC_C1 0x59C ++#define YUV_CSC_C2 0x161 ++#define YUV_CSC_C3 0x2DC ++#define YUV_CSC_C4 0x718 ++#endif ++ ++/* select ch */ ++#define BK_OSD_PIC_MASK (18) ++#define BK_OSD_PIC_NV21 ( 1 << BK_OSD_PIC_MASK ) ++#define BK_OSD_PIC_NV12 ( 2 << BK_OSD_PIC_MASK ) ++#define BK_OSD_PIC_ARGB ( 3 << BK_OSD_PIC_MASK ) ++#define CH3_OSD_PIC_MASK (15) ++#define CH3_OSD_PIC_NV21 ( 1 << CH3_OSD_PIC_MASK ) ++#define CH3_OSD_PIC_NV12 ( 2 << CH3_OSD_PIC_MASK ) ++#define CH3_OSD_PIC_ARGB ( 3 << CH3_OSD_PIC_MASK ) ++#define CH2_OSD_PIC_MASK (12) ++#define CH2_OSD_PIC_NV21 ( 1 << CH2_OSD_PIC_MASK ) ++#define CH2_OSD_PIC_NV12 ( 2 << CH2_OSD_PIC_MASK ) ++#define CH2_OSD_PIC_ARGB ( 3 << CH2_OSD_PIC_MASK ) ++#define CH1_OSD_PIC_MASK (9) ++#define CH1_OSD_PIC_NV21 ( 1 << CH1_OSD_PIC_MASK ) ++#define CH1_OSD_PIC_NV12 ( 2 << CH1_OSD_PIC_MASK ) ++#define CH1_OSD_PIC_ARGB ( 3 << CH1_OSD_PIC_MASK ) ++#define CH0_OSD_PIC_MASK (6) ++#define CH0_OSD_PIC_NV21 ( 1 << CH0_OSD_PIC_MASK ) ++#define CH0_OSD_PIC_NV12 ( 2 << CH0_OSD_PIC_MASK ) ++#define CH0_OSD_PIC_ARGB ( 3 << CH0_OSD_PIC_MASK ) ++#define OSD_CHN_EN_MASK (0) ++#define OSD_CHN_EN_CH0 ( 1 << OSD_CHN_EN_MASK ) ++#define OSD_CHN_EN_CH1 ( 2 << OSD_CHN_EN_MASK ) ++#define OSD_CHN_EN_CH2 ( 4 << OSD_CHN_EN_MASK ) ++#define OSD_CHN_EN_CH3 ( 8 << OSD_CHN_EN_MASK ) ++#define OSD_CHN_EN_BKG ( 16 << OSD_CHN_EN_MASK ) ++#define OSD_CHN_EN_DST ( 32 << OSD_CHN_EN_MASK ) ++ ++#endif /* #ifdef __KERNEL__ */ ++ ++/////////////////////////////////////////// ++ ++/* Data Format Register, export to libipu */ ++#define RGB_888_OUT_FMT ( 1 << 25 ) ++ ++#define RGB_OUT_OFT_BIT ( 22 ) ++#define RGB_OUT_OFT_MASK ( 7 << RGB_OUT_OFT_BIT ) ++#define RGB_OUT_OFT_RGB ( 0 << RGB_OUT_OFT_BIT ) ++#define RGB_OUT_OFT_RBG ( 1 << RGB_OUT_OFT_BIT ) ++#define RGB_OUT_OFT_GBR ( 2 << RGB_OUT_OFT_BIT ) ++#define RGB_OUT_OFT_GRB ( 3 << RGB_OUT_OFT_BIT ) ++#define RGB_OUT_OFT_BRG ( 4 << RGB_OUT_OFT_BIT ) ++#define RGB_OUT_OFT_BGR ( 5 << RGB_OUT_OFT_BIT ) ++ ++#define OUT_FMT_BIT ( 19 ) ++#define OUT_FMT_MASK ( 3 << OUT_FMT_BIT ) ++#define OUT_FMT_RGB555 ( 0 << OUT_FMT_BIT ) ++#define OUT_FMT_RGB565 ( 1 << OUT_FMT_BIT ) ++#define OUT_FMT_RGB888 ( 2 << OUT_FMT_BIT ) ++#define OUT_FMT_YUV422 ( 3 << OUT_FMT_BIT ) ++#define OUT_FMT_RGBAAA ( 4 << OUT_FMT_BIT ) ++#define OUT_FMT_NV12 ( 6 << OUT_FMT_BIT ) ++#define OUT_FMT_NV21 ( 7 << OUT_FMT_BIT ) ++#define OUT_FMT_HSV ( 1 << 2 ) /*Add HSV*/ ++ ++#define YUV_PKG_OUT_OFT_BIT ( 16 ) ++#define YUV_PKG_OUT_OFT_MASK ( 7 << YUV_PKG_OUT_OFT_BIT ) ++#define YUV_PKG_OUT_OFT_Y1UY0V ( 0 << YUV_PKG_OUT_OFT_BIT ) ++#define YUV_PKG_OUT_OFT_Y1VY0U ( 1 << YUV_PKG_OUT_OFT_BIT ) ++#define YUV_PKG_OUT_OFT_UY1VY0 ( 2 << YUV_PKG_OUT_OFT_BIT ) ++#define YUV_PKG_OUT_OFT_VY1UY0 ( 3 << YUV_PKG_OUT_OFT_BIT ) ++#define YUV_PKG_OUT_OFT_Y0UY1V ( 4 << YUV_PKG_OUT_OFT_BIT ) ++#define YUV_PKG_OUT_OFT_Y0VY1U ( 5 << YUV_PKG_OUT_OFT_BIT ) ++#define YUV_PKG_OUT_OFT_UY0VY1 ( 6 << YUV_PKG_OUT_OFT_BIT ) ++#define YUV_PKG_OUT_OFT_VY0UY1 ( 7 << YUV_PKG_OUT_OFT_BIT ) ++ ++#define IN_OFT_BIT ( 2 ) ++#define IN_OFT_MASK ( 3 << IN_OFT_BIT ) ++#define IN_OFT_Y1UY0V ( 0 << IN_OFT_BIT ) ++#define IN_OFT_Y1VY0U ( 1 << IN_OFT_BIT ) ++#define IN_OFT_UY1VY0 ( 2 << IN_OFT_BIT ) ++#define IN_OFT_VY1UY0 ( 3 << IN_OFT_BIT ) ++ ++#define IN_FMT_BIT ( 0 ) ++#define IN_FMT_MASK ( 7 << IN_FMT_BIT ) ++#define IN_FMT_YUV420 ( 0 << IN_FMT_BIT ) ++#define IN_FMT_YUV420_B ( 4 << IN_FMT_BIT ) ++#define IN_FMT_YUV422 ( 1 << IN_FMT_BIT ) ++#define IN_FMT_YUV444 ( 2 << IN_FMT_BIT ) ++#define IN_FMT_RGB_555 ( 0 << IN_FMT_BIT ) ++#define IN_FMT_RGB_888 ( 2 << IN_FMT_BIT ) ++#define IN_FMT_RGB_565 ( 3 << IN_FMT_BIT ) ++#define IN_FMT_YUV411 ( 3 << IN_FMT_BIT ) ++ ++//hwang add ++#define NV_SEL ( 1 << 7 ) ++#define NV_MODE_NV12 ( 0 << 8 ) ++#define NV_MODE_NV21 ( 1 << 8 ) ++ ++#define __enable_blk_mode() reg_bit_set(ipu, IPU_D_FMT, BLK_SEL) ++#define __disable_blk_mode() reg_bit_clr(ipu, IPU_D_FMT, BLK_SEL) ++#define __clear_ipu_out_end() reg_bit_clr(ipu, IPU_STATUS, OUT_END) ++#define __ipu_enable_irq() \ ++ do {unsigned int val = IRQ_EN ; \ ++ reg_bit_set(ipu, IPU_GLB_CTRL, val); \ ++ }while(0) ++#define __ipu_disable_irq() \ ++ do {unsigned int val = IRQ_EN ; \ ++ reg_bit_clr(ipu, IPU_GLB_CTRL, val); \ ++ }while(0) ++#define __start_ipu() reg_bit_set(ipu, IPU_TRIGGER, IPU_RUN) ++#define __reset_ipu() reg_bit_set(ipu, IPU_TRIGGER, IPU_RESET) ++#define __stop_ipu() reg_bit_set(ipu, IPU_TRIGGER, IPU_STOP) ++ ++#endif // _REGS_IPU_H_ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_watchdog_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_watchdog_Kconfig.patch new file mode 100644 index 00000000..33d0442b --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_watchdog_Kconfig.patch @@ -0,0 +1,17 @@ +diff -drupN a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig +--- a/drivers/watchdog/Kconfig 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/watchdog/Kconfig 2022-06-09 05:02:34.000000000 +0300 +@@ -1209,6 +1209,13 @@ config JZ4740_WDT + help + Hardware driver for the built-in watchdog timer on Ingenic jz4740 SoCs. + ++config INGENIC_WDT ++ tristate "Ingenic ingenic SoC hardware watchdog" ++ depends on MACH_XBURST || MACH_XBURST2 ++ select WATCHDOG_CORE ++ help ++ Hardware driver for the built-in watchdog timer on Ingenic all SoCs. ++ + config WDT_MTX1 + tristate "MTX-1 Hardware Watchdog" + depends on MIPS_MTX1 diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_watchdog_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_watchdog_Makefile.patch new file mode 100644 index 00000000..19e0c44d --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_watchdog_Makefile.patch @@ -0,0 +1,11 @@ +diff -drupN a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile +--- a/drivers/watchdog/Makefile 2017-10-21 18:09:07.000000000 +0300 ++++ b/drivers/watchdog/Makefile 2022-06-09 05:02:34.000000000 +0300 +@@ -139,6 +139,7 @@ obj-$(CONFIG_BCM63XX_WDT) += bcm63xx_wdt + obj-$(CONFIG_RC32434_WDT) += rc32434_wdt.o + obj-$(CONFIG_INDYDOG) += indydog.o + obj-$(CONFIG_JZ4740_WDT) += jz4740_wdt.o ++obj-$(CONFIG_INGENIC_WDT) += ingenic_wdt.o + obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o + obj-$(CONFIG_PNX833X_WDT) += pnx833x_wdt.o + obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_watchdog_ingenic_wdt.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_watchdog_ingenic_wdt.c.patch new file mode 100644 index 00000000..20220c68 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_watchdog_ingenic_wdt.c.patch @@ -0,0 +1,584 @@ +diff -drupN a/drivers/watchdog/ingenic_wdt.c b/drivers/watchdog/ingenic_wdt.c +--- a/drivers/watchdog/ingenic_wdt.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/drivers/watchdog/ingenic_wdt.c 2022-06-09 05:02:34.000000000 +0300 +@@ -0,0 +1,580 @@ ++/* ++ * Copyright (C) 2017, bo.liu ++ * INGENIC Watchdog driver ++ * ++ * 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. ++ * ++ * 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., ++ * 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DEFAULT_HEARTBEAT 5 ++#define MAX_HEARTBEAT 2048 ++ ++ ++static bool nowayout = WATCHDOG_NOWAYOUT; ++module_param(nowayout, bool, 0); ++MODULE_PARM_DESC(nowayout, ++ "Watchdog cannot be stopped once started (default=" ++ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); ++ ++static unsigned int heartbeat = DEFAULT_HEARTBEAT; ++module_param(heartbeat, uint, 0); ++MODULE_PARM_DESC(heartbeat, ++ "Watchdog heartbeat period in seconds from 1 to " ++ __MODULE_STRING(MAX_HEARTBEAT) ", default " ++ __MODULE_STRING(DEFAULT_HEARTBEAT)); ++ ++struct ingenic_wdt_drvdata { ++ struct watchdog_device wdt; ++ struct platform_device *pdev; ++ const struct mfd_cell *cell; ++ ++ struct clk *ext_clk; ++ struct notifier_block restart_handler; ++}; ++ ++static int ingenic_wdt_ping(struct watchdog_device *wdt_dev) ++{ ++ ingenic_watchdog_set_count(0); ++ return 0; ++} ++ ++static inline int get_clk_div(unsigned int *timeout_value) ++{ ++ int clk_div = TCU_PRESCALE_1; ++ ++ while (*timeout_value > 0xffff) { ++ if (clk_div == TCU_PRESCALE_1024) { ++ /* Requested timeout too high; ++ * use highest possible value. */ ++ *timeout_value = 0xffff; ++ clk_div = -1; ++ break; ++ } ++ *timeout_value >>= 2; ++ clk_div += 1; ++ } ++ ++ return clk_div; ++} ++static void wdt_config(struct ingenic_wdt_drvdata *drvdata, ++ unsigned int new_timeout) ++{ ++ unsigned int rtc_clk_rate; ++ //unsigned int ext_clk_rate; ++ unsigned int timeout_value; ++ unsigned int clk_src; ++ int clk_div = 0; ++ ++ rtc_clk_rate = 24000000 / 512; ++ clk_src = TCU_CLKSRC_RTC; ++ //ext_clk_rate = clk_get_rate(drvdata->ext_clk); ++ //timeout_value = ext_clk_rate * new_timeout; ++ timeout_value = rtc_clk_rate * new_timeout; ++ clk_div = get_clk_div(&timeout_value); ++ if(clk_div < 0){ ++ printk("Requested timeout too high, use highest possible value\n"); ++ clk_div = TCU_PRESCALE_1024; ++ timeout_value = 0xffff; ++ } ++ ++ ingenic_watchdog_config((clk_div << 3) | clk_src, timeout_value); ++} ++ ++static int ingenic_wdt_set_timeout(struct watchdog_device *wdt_dev, ++ unsigned int new_timeout) ++{ ++ struct ingenic_wdt_drvdata *drvdata = watchdog_get_drvdata(wdt_dev); ++ ++ wdt_config(drvdata, new_timeout); ++ wdt_dev->timeout = new_timeout; ++ return 0; ++} ++ ++static int ingenic_wdt_start(struct watchdog_device *wdt_dev) ++{ ++ struct ingenic_wdt_drvdata *drvdata = watchdog_get_drvdata(wdt_dev); ++ ++ drvdata->cell->enable(drvdata->pdev); ++ ingenic_wdt_set_timeout(wdt_dev, wdt_dev->timeout); ++ return 0; ++} ++ ++static int ingenic_wdt_stop(struct watchdog_device *wdt_dev) ++{ ++ struct ingenic_wdt_drvdata *drvdata = watchdog_get_drvdata(wdt_dev); ++ drvdata->cell->disable(drvdata->pdev); ++ return 0; ++} ++ ++static const struct watchdog_info ingenic_wdt_info = { ++ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, ++ .identity = "ingenic Watchdog", ++}; ++ ++static const struct watchdog_ops ingenic_wdt_ops = { ++ .owner = THIS_MODULE, ++ .start = ingenic_wdt_start, ++ .stop = ingenic_wdt_stop, ++ .ping = ingenic_wdt_ping, ++ .set_timeout = ingenic_wdt_set_timeout, ++}; ++ ++static int ingenic_reset_handler(struct notifier_block *this, unsigned long mode, ++ void *cmd) ++{ ++ struct ingenic_wdt_drvdata *drvdata = container_of(this, ++ struct ingenic_wdt_drvdata, restart_handler); ++ struct watchdog_device *wdd = &drvdata->wdt; ++ ++ if (cmd && !strcmp(cmd, REBOOT_CMD_RECOVERY)) ++ ingenic_recovery_sign(); ++ else ++ ingenic_reboot_sign(); ++ ++ if (cmd && !strcmp(cmd, REBOOT_CMD_SOFTBURN)) ++ ingenic_softburn_sign(); ++ ++ mutex_lock(&wdd->lock); ++ ++ drvdata->cell->enable(drvdata->pdev); ++ ++ ingenic_watchdog_config((3 << 3)|TCU_CLKSRC_RTC, 4); ++ while (1) { ++ mdelay(500); ++ pr_err("wdt reset failed, Never be here\n"); ++ } ++ mutex_unlock(&wdd->lock); ++ return NOTIFY_DONE; ++} ++ ++#ifdef CONFIG_OF ++static const struct of_device_id ingenic_wdt_of_matches[] = { ++ { .compatible = "ingenic,watchdog", }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, ingenic_wdt_of_matches) ++#endif ++ ++static ssize_t watchdog_cmd_set(struct file *file, const char __user *buffer, size_t count, loff_t *f_pos); ++static int watchdog_cmd_open(struct inode *inode, struct file *file); ++static const struct file_operations watchdog_cmd_fops ={ ++ .read = seq_read, ++ .open = watchdog_cmd_open, ++ .llseek = seq_lseek, ++ .release = single_release, ++ .write = watchdog_cmd_set, ++}; ++ ++ ++static struct watchdog_device *m_wdt; ++static int ingenic_wdt_probe(struct platform_device *pdev) ++{ ++ struct ingenic_wdt_drvdata *drvdata; ++ struct watchdog_device *ingenic_wdt; ++ int ret; ++ struct proc_dir_entry *proc; ++ ++ drvdata = devm_kzalloc(&pdev->dev, sizeof(struct ingenic_wdt_drvdata), ++ GFP_KERNEL); ++ if (!drvdata) { ++ dev_err(&pdev->dev, "Unable to alloacate watchdog device\n"); ++ return -ENOMEM; ++ } ++ ++ drvdata->cell = mfd_get_cell(pdev); ++ if (!drvdata->cell) { ++ dev_err(&pdev->dev, "Failed to get mfd cell\n"); ++ return -ENOMEM; ++ } ++ drvdata->pdev = pdev; ++ if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT) ++ heartbeat = DEFAULT_HEARTBEAT; ++ ++ m_wdt = ingenic_wdt = &drvdata->wdt; ++ ingenic_wdt->info = &ingenic_wdt_info; ++ ingenic_wdt->ops = &ingenic_wdt_ops; ++ ingenic_wdt->timeout = heartbeat; ++ ingenic_wdt->min_timeout = 1; ++ ingenic_wdt->max_timeout = MAX_HEARTBEAT; ++ ingenic_wdt->parent = &pdev->dev; ++ watchdog_set_nowayout(ingenic_wdt, nowayout); ++ watchdog_set_drvdata(ingenic_wdt, drvdata); ++ ++ drvdata->ext_clk = devm_clk_get(&pdev->dev, "ext"); ++ if (IS_ERR(drvdata->ext_clk)) { ++ dev_err(&pdev->dev, "cannot find EXT clock\n"); ++ ret = PTR_ERR(drvdata->ext_clk); ++ goto err_out; ++ } ++ ++ ret = watchdog_register_device(&drvdata->wdt); ++ if (ret < 0) ++ goto err_disable_ext_clk; ++ ++ platform_set_drvdata(pdev, drvdata); ++ ++ drvdata->restart_handler.notifier_call = ingenic_reset_handler; ++ drvdata->restart_handler.priority = WDT_RESET_PROR; ++ ret = register_restart_handler(&drvdata->restart_handler); ++ if (ret) ++ dev_warn(&pdev->dev, ++ "cannot register restart handler (err=%d)\n", ret); ++ ++ /* proc info */ ++ proc = jz_proc_mkdir("watchdog"); ++ if (!proc) { ++ printk("create mdio info failed!\n"); ++ } ++ proc_create_data("reset", S_IRUGO, proc, &watchdog_cmd_fops, NULL); ++ ++ return 0; ++ ++err_disable_ext_clk: ++ clk_put(drvdata->ext_clk); ++err_out: ++ return ret; ++} ++ ++static int ingenic_wdt_remove(struct platform_device *pdev) ++{ ++ struct ingenic_wdt_drvdata *drvdata = platform_get_drvdata(pdev); ++ ++ ingenic_wdt_stop(&drvdata->wdt); ++ watchdog_unregister_device(&drvdata->wdt); ++ clk_put(drvdata->ext_clk); ++ devm_kfree(&pdev->dev, drvdata); ++ return 0; ++} ++ ++static struct platform_driver ingenic_wdt_driver = { ++ .probe = ingenic_wdt_probe, ++ .remove = ingenic_wdt_remove, ++ .driver = { ++ .name = "ingenic,watchdog", ++ .of_match_table = of_match_ptr(ingenic_wdt_of_matches), ++ }, ++}; ++ ++module_platform_driver(ingenic_wdt_driver); ++ ++/**********************ingenic utils(deprecated)*****************************************/ ++struct wdt_utils { ++ struct watchdog_device *wdt; ++ unsigned msecs; ++ ++ unsigned stop; ++ struct task_struct *task; ++ unsigned short count; ++}; ++ ++static __deprecated int reset_task(void *data) { ++ struct wdt_utils *wdt_utils = data; ++ const struct sched_param param = { ++ .sched_priority = MAX_RT_PRIO-1, ++ }; ++ sched_setscheduler(current,SCHED_RR,¶m); ++ ++ if (test_and_set_bit(WDOG_DEV_OPEN, &wdt_utils->wdt->status)) { ++ pr_warn("watchdog conflict\n"); ++ wdt_utils->stop = 1; ++ return 0; ++ } ++ ++ mutex_lock(&wdt_utils->wdt->lock); ++ ++ ingenic_wdt_set_timeout(wdt_utils->wdt, (wdt_utils->msecs + 1000 - 1)/1000); ++ ingenic_wdt_start(wdt_utils->wdt); ++ ++ mutex_unlock(&wdt_utils->wdt->lock); ++ ++ while (1) { ++ if(kthread_should_stop()) { ++ clear_bit(WDOG_DEV_OPEN, &wdt_utils->wdt->status); ++ mutex_lock(&wdt_utils->wdt->lock); ++ ++ ingenic_wdt_stop(wdt_utils->wdt); ++ ++ mutex_unlock(&wdt_utils->wdt->lock); ++ break; ++ } ++ ++ mutex_lock(&wdt_utils->wdt->lock); ++ ++ ingenic_wdt_ping(wdt_utils->wdt); ++ ++ mutex_unlock(&wdt_utils->wdt->lock); ++ msleep(wdt_utils->wdt->timeout / 3); ++ } ++ ++ return 0; ++} ++ ++static __deprecated ssize_t wdt_time_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct wdt_utils *wdt = dev_get_drvdata(dev); ++ return sprintf(buf, "%d msecs\n", wdt->msecs); ++} ++static __deprecated ssize_t wdt_time_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct wdt_utils *wdt = dev_get_drvdata(dev); ++ unsigned int msecs; ++ ++ if(!wdt->stop) ++ return -EBUSY; ++ ++ sscanf(buf,"%d\n",&msecs); ++ ++ if(msecs < 1000) ++ msecs = 1000; ++ if(msecs > 30000) ++ msecs = 30000; ++ ++ wdt->msecs = msecs; ++ return count; ++} ++static __deprecated DEVICE_ATTR_RW(wdt_time); ++ ++static __deprecated ssize_t wdt_control_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct wdt_utils *wdt = dev_get_drvdata(dev); ++ return sprintf(buf, "%s\n", wdt->stop?">offon<\n"); ++} ++ ++static __deprecated ssize_t wdt_control_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct wdt_utils *wdt = dev_get_drvdata(dev); ++ ++ if(!strncmp(buf,"on",2) && (wdt->stop == 1)) { ++ wdt->task = kthread_run(reset_task, wdt, "reset_task%d",wdt->count++); ++ wdt->stop = 0; ++ } else if(!strncmp(buf,"off",3) && (wdt->stop == 0)) { ++ kthread_stop(wdt->task); ++ wdt->stop = 1; ++ } ++ return count; ++} ++static __deprecated DEVICE_ATTR_RW(wdt_control); ++ ++static __deprecated char *reset_command[] = {"wdt", "hibernate","recovery", "burnerboot"}; ++static __deprecated ssize_t reset_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ int len = 0, i; ++ ++ for(i = 0; i < ARRAY_SIZE(reset_command); i++) ++ len += sprintf(buf + len, "%s\t", reset_command[i]); ++ len += sprintf(buf + len, "\n"); ++ ++ return len; ++} ++ ++static __deprecated ssize_t reset_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ int command_size = 0; ++ int i; ++ char *cmd = NULL; ++ ++ if(count == 0) ++ return -EINVAL; ++ ++ command_size = ARRAY_SIZE(reset_command); ++ for(i = 0;i < command_size; i++) { ++ if(!strncmp(buf, reset_command[i], strlen(reset_command[i]))) ++ break; ++ } ++ ++ switch(i) { ++ case 1: ++ reboot_mode = REBOOT_HARD; ++ break; ++ case 2: ++ cmd = "recovery"; ++ break; ++ case 3: ++ cmd = "softburn"; ++ break; ++ default: ++ case 0: ++ break; ++ } ++ kernel_restart(cmd); ++ return count; ++} ++static __deprecated DEVICE_ATTR_RW(reset); ++ ++static __deprecated struct attribute *reset_attrs[] = { ++ &dev_attr_wdt_time.attr, ++ &dev_attr_wdt_control.attr, ++ &dev_attr_reset.attr, ++ NULL ++}; ++ ++static __deprecated const struct attribute_group attr_group = { ++ .attrs = reset_attrs, ++}; ++ ++static __deprecated int wdt_utils_probe(struct platform_device *pdev) ++{ ++ struct wdt_utils *wdt; ++ int ret; ++ ++ wdt = devm_kzalloc(&pdev->dev, sizeof(struct wdt_utils),GFP_KERNEL); ++ if(!wdt) ++ return -ENOMEM; ++ wdt->wdt = m_wdt; ++ wdt->count = 0; ++ wdt->stop = 1; ++ wdt->msecs = heartbeat * 1000; ++ dev_set_drvdata(&pdev->dev, wdt); ++ ret = sysfs_create_group(&pdev->dev.kobj, &attr_group); ++ if (ret) ++ printk("watchdog utils regist failed\n"); ++ return ret; ++} ++ ++static __deprecated void wdt_utils_shutdown(struct platform_device *pdev) ++{ ++ struct wdt_utils *wdt_utils = dev_get_drvdata(&pdev->dev); ++ ingenic_wdt_stop(wdt_utils->wdt); ++} ++ ++static __deprecated int wdt_utils_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ struct wdt_utils *wdt = dev_get_drvdata(&pdev->dev); ++ if (wdt->stop) ++ return 0; ++ kthread_stop(wdt->task); ++ return 0; ++} ++ ++ ++static __deprecated int wdt_utils_resume(struct platform_device *pdev) ++{ ++ struct wdt_utils *wdt = dev_get_drvdata(&pdev->dev); ++ if(wdt->stop) ++ return 0; ++ wdt->task = kthread_run(reset_task, wdt, "reset_task%d",wdt->count++); ++ return 0; ++} ++ ++static __deprecated struct platform_device wdt_utils_pdev = { ++ .name = "wdt_utils", ++}; ++ ++static __deprecated struct platform_driver wdt_utils_pdrv = { ++ .probe = wdt_utils_probe, ++ .shutdown = wdt_utils_shutdown, ++ .suspend = wdt_utils_suspend, ++ .resume = wdt_utils_resume, ++ .driver = { ++ .name = "wdt_utils", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static __deprecated int __init init_reset(void) ++{ ++ platform_driver_register(&wdt_utils_pdrv); ++ platform_device_register(&wdt_utils_pdev); ++ return 0; ++} ++device_initcall_sync(init_reset); ++MODULE_AUTHOR("bo.liu "); ++MODULE_DESCRIPTION("ingenic Watchdog Driver"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:ingenic-wdt"); ++ ++ ++/* cmd */ ++#define WATCHDOG_CMD_BUF_SIZE 100 ++static uint8_t watchdog_cmd_buf[100]; ++static int watchdog_cmd_show(struct seq_file *m, void *v) ++{ ++ int len = 0; ++ len += seq_printf(m ,"%s\n", watchdog_cmd_buf); ++ return len; ++} ++ ++static ssize_t watchdog_cmd_set(struct file *file, const char __user *buffer, size_t count, loff_t *f_pos) ++{ ++ int cmd_value = 0; ++ unsigned int reg04 = 0,reglc = 0; ++ ++ char *buf = kzalloc((count+1), GFP_KERNEL); ++ if(!buf) ++ return -ENOMEM; ++ if(copy_from_user(buf, buffer, count)) ++ { ++ kfree(buf); ++ return EFAULT; ++ } ++ cmd_value = simple_strtoull(buf, NULL, 0); ++ ++ mdelay(1000); ++ if(1 == cmd_value) { ++ reg04 = inl(TCU_IOBASE + 0x04); ++ if(reg04 & 0x1) { ++ outl(0 << 0, TCU_IOBASE + 0x4); ++ } ++ ++ outl(0x1a, TCU_IOBASE + 0xc); ++ ++ reglc = inl(TCU_IOBASE + 0x1c); ++ if(reglc & 0x10000) { ++ outl(1 << 16, TCU_IOBASE + 0x3c); ++ outl(1 << 16, TCU_IOBASE + 0x2c); ++ } ++ outl(0x0000, TCU_IOBASE + 0x0); ++ outl(0x0000, TCU_IOBASE + 0x8); ++ ++ reg04 = inl(TCU_IOBASE + 0x04); ++ if(!(reg04 & 0x1)) { ++ outl(1 << 0, TCU_IOBASE + 0x4); ++ } ++ printk("watchdog reboot system!!!\n"); ++ } ++ ++ kfree(buf); ++ return count; ++} ++static int watchdog_cmd_open(struct inode *inode, struct file *file) ++{ ++ return single_open_size(file, watchdog_cmd_show, PDE_DATA(inode),8192); ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_Kconfig.patch new file mode 100644 index 00000000..ba3a9180 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_Kconfig.patch @@ -0,0 +1,11 @@ +diff -drupN a/fs/Kconfig b/fs/Kconfig +--- a/fs/Kconfig 2017-10-21 18:09:07.000000000 +0300 ++++ b/fs/Kconfig 2022-06-09 05:02:34.000000000 +0300 +@@ -204,6 +204,7 @@ source "fs/hfsplus/Kconfig" + source "fs/befs/Kconfig" + source "fs/bfs/Kconfig" + source "fs/efs/Kconfig" ++source "fs/yaffs2/Kconfig" + source "fs/jffs2/Kconfig" + # UBIFS File system configuration + source "fs/ubifs/Kconfig" diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_Makefile.patch new file mode 100644 index 00000000..89c3a6e4 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_Makefile.patch @@ -0,0 +1,8 @@ +diff -drupN a/fs/Makefile b/fs/Makefile +--- a/fs/Makefile 2017-10-21 18:09:07.000000000 +0300 ++++ b/fs/Makefile 2022-06-09 05:02:34.000000000 +0300 +@@ -126,3 +126,4 @@ obj-y += exofs/ # Multiple modules + obj-$(CONFIG_CEPH_FS) += ceph/ + obj-$(CONFIG_PSTORE) += pstore/ + obj-$(CONFIG_EFIVAR_FS) += efivarfs/ ++obj-$(CONFIG_YAFFS_FS) += yaffs2/ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_seq_file.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_seq_file.c.patch new file mode 100644 index 00000000..0717a91e --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_seq_file.c.patch @@ -0,0 +1,40 @@ +diff -drupN a/fs/seq_file.c b/fs/seq_file.c +--- a/fs/seq_file.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/fs/seq_file.c 2022-06-09 05:02:35.000000000 +0300 +@@ -395,7 +395,7 @@ void seq_escape(struct seq_file *m, cons + } + EXPORT_SYMBOL(seq_escape); + +-void seq_vprintf(struct seq_file *m, const char *f, va_list args) ++int seq_vprintf(struct seq_file *m, const char *f, va_list args) + { + int len; + +@@ -403,20 +403,24 @@ void seq_vprintf(struct seq_file *m, con + len = vsnprintf(m->buf + m->count, m->size - m->count, f, args); + if (m->count + len < m->size) { + m->count += len; +- return; ++ return len; + } + } + seq_set_overflow(m); ++ return 0; + } + EXPORT_SYMBOL(seq_vprintf); + +-void seq_printf(struct seq_file *m, const char *f, ...) ++int seq_printf(struct seq_file *m, const char *f, ...) + { ++ int ret; + va_list args; + + va_start(args, f); +- seq_vprintf(m, f, args); ++ ret = seq_vprintf(m, f, args); + va_end(args); ++ ++ return ret; + } + EXPORT_SYMBOL(seq_printf); + diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_Kconfig.patch new file mode 100644 index 00000000..a3fd0d9b --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_Kconfig.patch @@ -0,0 +1,56 @@ +diff -drupN a/fs/squashfs/Kconfig b/fs/squashfs/Kconfig +--- a/fs/squashfs/Kconfig 2017-10-21 18:09:07.000000000 +0300 ++++ b/fs/squashfs/Kconfig 2022-06-09 05:02:35.000000000 +0300 +@@ -164,6 +164,52 @@ config SQUASHFS_XZ + file systems will be readable without selecting this option. + + If unsure, say N. ++#config SQUASHFS_LZMA ++# bool "Include support for LZMA compressed file systems" ++# depends on SQUASHFS ++# select LZMADEVICE ++# select DECOMPRESS_LZMA ++# select DECOMPRESS_LZMA_NEEDED ++# default y ++# help ++# Saying Y here includes support for reading Squashfs file systems ++# compressed with LZMA compression. LZMA gives better compression than ++# the default zlib compression, at the expense of greater CPU and ++# memory overhead. ++# ++# LZMA is not the standard compression used in Squashfs and so most ++# file systems will be readable without selecting this option. ++# If unsure, say N. ++ ++menuconfig SQUASHFS_LZMA ++ bool " Include support for LZMA compressed file systems" ++ ++ depends on SQUASHFS ++ ++ select LZMADEVICE ++ select DECOMPRESS_LZMA ++ select DECOMPRESS_LZMA_NEEDED ++ default y ++ ++if SQUASHFS_LZMA ++choice ++ prompt "Lzma Decompressor parallelisation options" ++ depends on SQUASHFS ++config S_DECOMPRESS_LZMA ++bool "SOFTWARE support for LZMA file systems" ++ depends on SQUASHFS ++ select DECOMPRESS_LZMA ++ select DECOMPRESS_LZMA_NEEDED ++ ++config H_DECOMPRESS_LZMA ++bool "JZ_HARDWARE support for LZMA file systems" ++ depends on SQUASHFS ++ select DECOMPRESS_LZMA ++ select DECOMPRESS_LZMA_NEEDED ++ select LZMADEVICE ++endchoice ++endif ++ + + config SQUASHFS_4K_DEVBLK_SIZE + bool "Use 4K device block size?" diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_Makefile.patch new file mode 100644 index 00000000..db09339e --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_Makefile.patch @@ -0,0 +1,9 @@ +diff -drupN a/fs/squashfs/Makefile b/fs/squashfs/Makefile +--- a/fs/squashfs/Makefile 2017-10-21 18:09:07.000000000 +0300 ++++ b/fs/squashfs/Makefile 2022-06-09 05:02:35.000000000 +0300 +@@ -14,4 +14,5 @@ squashfs-$(CONFIG_SQUASHFS_XATTR) += xat + squashfs-$(CONFIG_SQUASHFS_LZ4) += lz4_wrapper.o + squashfs-$(CONFIG_SQUASHFS_LZO) += lzo_wrapper.o + squashfs-$(CONFIG_SQUASHFS_XZ) += xz_wrapper.o ++squashfs-$(CONFIG_SQUASHFS_LZMA) += lzma_wrapper.o hardware_lzma.o + squashfs-$(CONFIG_SQUASHFS_ZLIB) += zlib_wrapper.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_decompressor.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_decompressor.c.patch new file mode 100644 index 00000000..df7f4c48 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_decompressor.c.patch @@ -0,0 +1,33 @@ +diff -drupN a/fs/squashfs/decompressor.c b/fs/squashfs/decompressor.c +--- a/fs/squashfs/decompressor.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/fs/squashfs/decompressor.c 2022-06-09 05:02:35.000000000 +0300 +@@ -41,6 +41,12 @@ static const struct squashfs_decompresso + NULL, NULL, NULL, NULL, LZMA_COMPRESSION, "lzma", 0 + }; + ++#ifndef CONFIG_SQUASHFS_LZMA ++ const struct squashfs_decompressor squashfs_lzma_comp_ops = { ++ NULL, NULL, NULL, NULL, LZMA_COMPRESSION, "lzma", 0 ++}; ++#endif ++ + #ifndef CONFIG_SQUASHFS_LZ4 + static const struct squashfs_decompressor squashfs_lz4_comp_ops = { + NULL, NULL, NULL, NULL, LZ4_COMPRESSION, "lz4", 0 +@@ -74,7 +80,7 @@ static const struct squashfs_decompresso + &squashfs_lz4_comp_ops, + &squashfs_lzo_comp_ops, + &squashfs_xz_comp_ops, +- &squashfs_lzma_unsupported_comp_ops, ++ &squashfs_lzma_comp_ops, + &squashfs_unknown_comp_ops + }; + +@@ -139,7 +145,6 @@ void *squashfs_decompressor_setup(struct + + if (IS_ERR(comp_opts)) + return comp_opts; +- + stream = squashfs_decompressor_create(msblk, comp_opts); + if (IS_ERR(stream)) + kfree(comp_opts); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_decompressor.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_decompressor.h.patch new file mode 100644 index 00000000..120683c9 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_decompressor.h.patch @@ -0,0 +1,12 @@ +diff -drupN a/fs/squashfs/decompressor.h b/fs/squashfs/decompressor.h +--- a/fs/squashfs/decompressor.h 2017-10-21 18:09:07.000000000 +0300 ++++ b/fs/squashfs/decompressor.h 2022-06-09 05:02:35.000000000 +0300 +@@ -58,4 +58,8 @@ extern const struct squashfs_decompresso + extern const struct squashfs_decompressor squashfs_zlib_comp_ops; + #endif + ++#ifdef CONFIG_SQUASHFS_LZMA ++extern const struct squashfs_decompressor squashfs_lzma_comp_ops; ++#endif ++ + #endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_decompressor_multi.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_decompressor_multi.c.patch new file mode 100644 index 00000000..5e2a86b4 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_decompressor_multi.c.patch @@ -0,0 +1,15 @@ +diff -drupN a/fs/squashfs/decompressor_multi.c b/fs/squashfs/decompressor_multi.c +--- a/fs/squashfs/decompressor_multi.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/fs/squashfs/decompressor_multi.c 2022-06-09 05:02:35.000000000 +0300 +@@ -188,8 +188,11 @@ int squashfs_decompress(struct squashfs_ + int res; + struct squashfs_stream *stream = msblk->stream; + struct decomp_stream *decomp_stream = get_decomp_stream(msblk, stream); ++ //printk("squashfs multi decompress start: %s : %d time is %d\n",__func__,__LINE__,1000 * *(volatile u32 *)0xb0002078 * 16 / ((24 * 1000 * 1000) / 512) ); ++ //printk("offset = 0x%x length = 0x%x\n",offset,length); + res = msblk->decompressor->decompress(msblk, decomp_stream->stream, + bh, b, offset, length, output); ++ //printk("squashfs multi decompress end: %s : %d time is %d\n",__func__,__LINE__,1000 * *(volatile u32 *)0xb0002078 * 16 / ((24 * 1000 * 1000) / 512) ); + put_decomp_stream(decomp_stream, stream); + if (res < 0) + ERROR("%s decompression failed, data probably corrupt\n", diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_decompressor_single.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_decompressor_single.c.patch new file mode 100644 index 00000000..e5731806 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_decompressor_single.c.patch @@ -0,0 +1,15 @@ +diff -drupN a/fs/squashfs/decompressor_single.c b/fs/squashfs/decompressor_single.c +--- a/fs/squashfs/decompressor_single.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/fs/squashfs/decompressor_single.c 2022-06-09 05:02:35.000000000 +0300 +@@ -68,8 +68,11 @@ int squashfs_decompress(struct squashfs_ + struct squashfs_stream *stream = msblk->stream; + + mutex_lock(&stream->mutex); ++// printk("squashfs single decompress start: %s : %d time is %d\n",__func__,__LINE__,1000 * *(volatile u32 *)0xb0002078 * 16 / ((24 * 1000 * 1000) / 512) ); ++// printk("offset = 0x%x length = 0x%x\n",offset,length); + res = msblk->decompressor->decompress(msblk, stream->stream, bh, b, + offset, length, output); ++// printk("squashfs single decompress end: %s : %d time is %d\n",__func__,__LINE__,1000 * *(volatile u32 *)0xb0002078 * 16 / ((24 * 1000 * 1000) / 512) ); + mutex_unlock(&stream->mutex); + + if (res < 0) diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_hardware_lzma.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_hardware_lzma.c.patch new file mode 100644 index 00000000..a307cb1b --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_hardware_lzma.c.patch @@ -0,0 +1,32 @@ +diff -drupN a/fs/squashfs/hardware_lzma.c b/fs/squashfs/hardware_lzma.c +--- a/fs/squashfs/hardware_lzma.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/squashfs/hardware_lzma.c 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,28 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++extern int jz_lzma_decompress(unsigned char *src, size_t size, unsigned char *dst); ++//extern int jz_lzma_decompress(void); ++ ++int unlzma_hardware(unsigned char *input,size_t in_len,unsigned char *output) ++{ ++ int ret_icl; ++ ++ ret_icl=jz_lzma_decompress(input,in_len,output); ++ if(ret_icl < 0){ ++ printk("lzma_ioctl error\n"); ++ return -1; ++ } ++ ++ return 0; ++ ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_jz-lzma.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_jz-lzma.h.patch new file mode 100644 index 00000000..24ef880b --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_jz-lzma.h.patch @@ -0,0 +1,76 @@ +diff -drupN a/fs/squashfs/jz-lzma.h b/fs/squashfs/jz-lzma.h +--- a/fs/squashfs/jz-lzma.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/squashfs/jz-lzma.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,72 @@ ++#ifndef __JZ_LZMA_MY_H__ ++#define __JZ_LZMA_MY_H__ ++ ++#include ++#define LZMA_IOC_MAGIC 'L' ++#define IOCTL_LZMA_DMA_GET_RANDOM _IO(JZlzma_IOC_MAGIC, 110) ++ ++#define LZMA_CTRL 0x0 ++#define LZMA_BS_BASE 0x4 ++#define LZMA_BS_SIZE 0x8 ++#define LZMA_DST_BASE 0xc ++#define LZMA_ICRC 0x10 ++#define LZMA_CRC 0x14 ++#define LZMA_FINALSIZE 0x1c ++ ++#define IN_FILE_SIZE 11 ++#define OUT_FILE_SIZE 12 ++ ++typedef struct lzma_operation { ++ struct miscdevice lzma_dev; ++ struct resource *res; ++ int state; ++ void __iomem *iomem; ++ struct clk *clk; ++ struct clk *clk_gate; ++ struct clk *ahb0_gate; ++ struct device *dev; ++ int irq; ++ char name[16]; ++ unsigned long in_file; ++ unsigned long out_file; ++ int opencnt; ++ struct mutex openmutex; ++}lzma_operation_t; ++ ++extern int unlzma_hardware(unsigned char *input,int in_len,unsigned char *output); ++ ++extern long lzma_ioctl(struct file *file, unsigned int cmd, unsigned long val); ++ ++#define miscdev_to_lzmaops(mdev) (container_of(mdev, struct lzma_operation, lzma_dev)) ++ ++static inline unsigned int lzma_reg_read(struct lzma_operation *lzma_ope, int offset) ++{ ++// printk("%s, read:0x%08x, val = 0x%08x\n", __func__, lzma_ope->iomem + offset, readl(lzma_ope->iomem + offset)); ++ return readl(lzma_ope->iomem + offset); ++} ++ ++static inline void lzma_reg_write(struct lzma_operation *lzma_ope, int offset, unsigned int val) ++{ ++ writel(val, lzma_ope->iomem + offset); ++// printk("%s, write:0x%08x, val = 0x%08x\n", __func__, lzma_ope->iomem + offset, val); ++} ++ ++static inline void lzma_bit_set(struct lzma_operation *lzma_ope, int offset, unsigned int bit) ++{ ++ unsigned int tmp = 0; ++ ++ tmp = lzma_reg_read(lzma_ope, offset); ++ tmp |= (1 << bit); ++ lzma_reg_write(lzma_ope, offset, tmp); ++} ++ ++static inline void lzma_bit_clr(struct lzma_operation *lzma_ope, int offset, unsigned int bit) ++{ ++ unsigned int tmp = 0; ++ ++ tmp = lzma_reg_read(lzma_ope, offset); ++ tmp &= ~(1 << bit); ++ lzma_reg_write(lzma_ope, offset, tmp); ++} ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_lzma_wrapper.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_lzma_wrapper.c.patch new file mode 100644 index 00000000..0e5c5eaf --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_lzma_wrapper.c.patch @@ -0,0 +1,159 @@ +diff -drupN a/fs/squashfs/lzma_wrapper.c b/fs/squashfs/lzma_wrapper.c +--- a/fs/squashfs/lzma_wrapper.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/squashfs/lzma_wrapper.c 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,155 @@ ++/* ++ * Squashfs - a compressed read only filesystem for Linux ++ * ++ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 ++ * Phillip Lougher ++ * ++ * 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, ++ * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ * ++ * lzma_wrapper.c ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "squashfs_fs.h" ++#include "squashfs_fs_sb.h" ++#include "squashfs_fs_i.h" ++#include "squashfs.h" ++#include "decompressor.h" ++#include ++#include "page_actor.h" ++#include "jz-lzma.h" ++struct squashfs_lzma { ++ void *input; ++ void *output; ++}; ++ ++/* decompress_unlzma.c is currently non re-entrant... */ ++DEFINE_MUTEX(lzma_mutex); ++ ++/* decompress_unlzma.c doesn't provide any context in its callbacks... */ ++static int lzma_error; ++ ++static void error(char *m) ++{ ++ ERROR("unlzma error: %s\n", m); ++ lzma_error = 1; ++} ++ ++ ++static void *lzma_init(struct squashfs_sb_info *msblk,void *buff) ++{ ++ int block_size = max_t(int, msblk->block_size, SQUASHFS_METADATA_SIZE); ++ struct squashfs_lzma *stream = kzalloc(sizeof(*stream), GFP_KERNEL); ++ if (stream == NULL) ++ { ++ goto failed;} ++ stream->input = vmalloc(block_size); ++ if (stream->input == NULL) ++ { ++ goto failed;} ++ stream->output = vmalloc(block_size); ++ if (stream->output == NULL) ++ { ++ goto failed2;} ++ ++ return stream; ++ ++failed2: ++ vfree(stream->input); ++failed: ++ ERROR("failed to allocate lzma workspace\n"); ++ kfree(stream); ++ return NULL; ++} ++ ++ ++static void lzma_free(void *strm) ++{ ++ struct squashfs_lzma *stream = strm; ++ ++ if (stream) { ++ vfree(stream->input); ++ vfree(stream->output); ++ } ++ kfree(stream); ++} ++ ++ ++static int lzma_uncompress(struct squashfs_sb_info *msblk, void *strm, ++ struct buffer_head **bh, int b, int offset, int length, ++ struct squashfs_page_actor *output) ++{ ++ struct squashfs_lzma *stream = strm; ++ void *buff = stream->input, *data; ++ int avail, i, bytes = length, res; ++ size_t out_len = output->length; ++ ++ for (i = 0; i < b; i++) { ++ avail = min(bytes, msblk->devblksize - offset); ++ memcpy(buff, bh[i]->b_data + offset, avail); ++ buff += avail; ++ bytes -= avail; ++ offset = 0; ++ put_bh(bh[i]); ++ } ++#ifdef CONFIG_S_DECOMPRESS_LZMA ++ res = unlzma((unsigned char *)stream->input, length, NULL, NULL, (unsigned char *)stream->output, NULL, error); ++#endif ++ ++#ifdef CONFIG_H_DECOMPRESS_LZMA ++ res = unlzma_hardware((unsigned char *)stream->input,length,(unsigned char *)stream->output); ++#endif ++ if (res || lzma_error) ++ goto failed; ++ ++ res = bytes = (int)out_len; ++ data = squashfs_first_page(output); ++ buff = stream->output; ++ while (data) { ++ if (bytes <= PAGE_CACHE_SIZE) { ++ memcpy(data, buff, bytes); ++ break; ++ } else { ++ memcpy(data, buff, PAGE_CACHE_SIZE); ++ buff += PAGE_CACHE_SIZE; ++ bytes -= PAGE_CACHE_SIZE; ++ data = squashfs_next_page(output); ++ } ++ } ++ squashfs_finish_page(output); ++ ++ return res; ++ ++ ++failed: ++ ERROR("lzma decompression failed, data probably corrupt\n"); ++ return -EIO; ++} ++ ++const struct squashfs_decompressor squashfs_lzma_comp_ops = { ++ .init = lzma_init, ++ .free = lzma_free, ++ .decompress = lzma_uncompress, ++ .id = LZMA_COMPRESSION, ++ .name = "lzma", ++ .supported = 1 ++}; ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_squashfs.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_squashfs.h.patch new file mode 100644 index 00000000..d788ba35 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_squashfs.h.patch @@ -0,0 +1,9 @@ +diff -drupN a/fs/squashfs/squashfs.h b/fs/squashfs/squashfs.h +--- a/fs/squashfs/squashfs.h 2017-10-21 18:09:07.000000000 +0300 ++++ b/fs/squashfs/squashfs.h 2022-06-09 05:02:35.000000000 +0300 +@@ -111,3 +111,5 @@ extern const struct inode_operations squ + + /* xattr.c */ + extern const struct xattr_handler *squashfs_xattr_handlers[]; ++/* lzma wrapper.c */ ++extern const struct squashfs_decompressor squashfs_lzma_comp_ops; diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_super.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_super.c.patch new file mode 100644 index 00000000..226f414e --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_squashfs_super.c.patch @@ -0,0 +1,14 @@ +diff -drupN a/fs/squashfs/super.c b/fs/squashfs/super.c +--- a/fs/squashfs/super.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/fs/squashfs/super.c 2022-06-09 05:02:35.000000000 +0300 +@@ -449,8 +449,8 @@ static int __init init_squashfs_fs(void) + destroy_inodecache(); + return err; + } +- +- pr_info("version 4.0 (2009/01/31) Phillip Lougher\n"); ++printk(KERN_INFO "squashfs: version 4.0 (2021/14/49) " ++ "Phillip Lougher \n"); + + return 0; + } diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_Kconfig.patch new file mode 100644 index 00000000..b48e909b --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_Kconfig.patch @@ -0,0 +1,175 @@ +diff -drupN a/fs/yaffs2/Kconfig b/fs/yaffs2/Kconfig +--- a/fs/yaffs2/Kconfig 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/Kconfig 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,171 @@ ++# ++# yaffs file system configurations ++# ++ ++config YAFFS_FS ++ tristate "yaffs2 file system support" ++ default n ++ depends on MTD_BLOCK ++ select YAFFS_YAFFS1 ++ select YAFFS_YAFFS2 ++ help ++ yaffs2, or Yet Another Flash File System, is a file system ++ optimised for NAND Flash chips. ++ ++ To compile the yaffs2 file system support as a module, choose M ++ here: the module will be called yaffs2. ++ ++ If unsure, say N. ++ ++ Further information on yaffs2 is available at ++ . ++ ++config YAFFS_YAFFS1 ++ bool "512 byte / page devices" ++ depends on YAFFS_FS ++ default y ++ help ++ Enable yaffs1 support -- yaffs for 512 byte / page devices ++ ++ Not needed for 2K-page devices. ++ ++ If unsure, say Y. ++ ++config YAFFS_9BYTE_TAGS ++ bool "Use older-style on-NAND data format with pageStatus byte" ++ depends on YAFFS_YAFFS1 ++ default n ++ help ++ ++ Older-style on-NAND data format has a "pageStatus" byte to record ++ chunk/page state. This byte is zero when the page is discarded. ++ Choose this option if you have existing on-NAND data using this ++ format that you need to continue to support. New data written ++ also uses the older-style format. Note: Use of this option ++ generally requires that MTD's oob layout be adjusted to use the ++ older-style format. See notes on tags formats and MTD versions ++ in yaffs_mtdif1.c. ++ ++ If unsure, say N. ++ ++config YAFFS_DOES_ECC ++ bool "Lets yaffs do its own ECC" ++ depends on YAFFS_FS && YAFFS_YAFFS1 && !YAFFS_9BYTE_TAGS ++ default n ++ help ++ This enables yaffs to use its own ECC functions instead of using ++ the ones from the generic MTD-NAND driver. ++ ++ If unsure, say N. ++ ++config YAFFS_ECC_WRONG_ORDER ++ bool "Use the same ecc byte order as Steven Hill's nand_ecc.c" ++ depends on YAFFS_FS && YAFFS_DOES_ECC && !YAFFS_9BYTE_TAGS ++ default n ++ help ++ This makes yaffs_ecc.c use the same ecc byte order as Steven ++ Hill's nand_ecc.c. If not set, then you get the same ecc byte ++ order as SmartMedia. ++ ++ If unsure, say N. ++ ++config YAFFS_YAFFS2 ++ bool "2048 byte (or larger) / page devices" ++ depends on YAFFS_FS ++ default y ++ help ++ Enable yaffs2 support -- yaffs for >= 2K bytes per page devices ++ ++ If unsure, say Y. ++ ++config YAFFS_AUTO_YAFFS2 ++ bool "Autoselect yaffs2 format" ++ depends on YAFFS_YAFFS2 ++ default y ++ help ++ Without this, you need to explicitely use yaffs2 as the file ++ system type. With this, you can say "yaffs" and yaffs or yaffs2 ++ will be used depending on the device page size (yaffs on ++ 512-byte page devices, yaffs2 on 2K page devices). ++ ++ If unsure, say Y. ++ ++config YAFFS_DISABLE_TAGS_ECC ++ bool "Disable yaffs from doing ECC on tags by default" ++ depends on YAFFS_FS && YAFFS_YAFFS2 ++ default n ++ help ++ This defaults yaffs to using its own ECC calculations on tags instead of ++ just relying on the MTD. ++ This behavior can also be overridden with tags_ecc_on and ++ tags_ecc_off mount options. ++ ++ If unsure, say N. ++ ++config YAFFS_ALWAYS_CHECK_CHUNK_ERASED ++ bool "Force chunk erase check" ++ depends on YAFFS_FS ++ default n ++ help ++ Normally yaffs only checks chunks before writing until an erased ++ chunk is found. This helps to detect any partially written ++ chunks that might have happened due to power loss. ++ ++ Enabling this forces on the test that chunks are erased in flash ++ before writing to them. This takes more time but is potentially ++ a bit more secure. ++ ++ Suggest setting Y during development and ironing out driver ++ issues etc. Suggest setting to N if you want faster writing. ++ ++ If unsure, say Y. ++ ++config YAFFS_EMPTY_LOST_AND_FOUND ++ bool "Empty lost and found on boot" ++ depends on YAFFS_FS ++ default n ++ help ++ If this is enabled then the contents of lost and found is ++ automatically dumped at mount. ++ ++ If unsure, say N. ++ ++config YAFFS_DISABLE_BLOCK_REFRESHING ++ bool "Disable yaffs2 block refreshing" ++ depends on YAFFS_FS ++ default n ++ help ++ If this is set, then block refreshing is disabled. ++ Block refreshing infrequently refreshes the oldest block in ++ a yaffs2 file system. This mechanism helps to refresh flash to ++ mitigate against data loss. This is particularly useful for MLC. ++ ++ If unsure, say N. ++ ++config YAFFS_DISABLE_BACKGROUND ++ bool "Disable yaffs2 background processing" ++ depends on YAFFS_FS ++ default n ++ help ++ If this is set, then background processing is disabled. ++ Background processing makes many foreground activities faster. ++ ++ If unsure, say N. ++ ++config YAFFS_DISABLE_BAD_BLOCK_MARKING ++ bool "Disable yaffs2 bad block marking" ++ depends on YAFFS_FS ++ default n ++ help ++ Useful during early flash bring up to prevent problems causing ++ lots of bad block marking. ++ ++ If unsure, say N. ++ ++config YAFFS_XATTR ++ bool "Enable yaffs2 xattr support" ++ depends on YAFFS_FS ++ default y ++ help ++ If this is set then yaffs2 will provide xattr support. ++ If unsure, say Y. diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_Makefile.patch new file mode 100644 index 00000000..933e71f2 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_Makefile.patch @@ -0,0 +1,23 @@ +diff -drupN a/fs/yaffs2/Makefile b/fs/yaffs2/Makefile +--- a/fs/yaffs2/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/Makefile 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,19 @@ ++# ++# Makefile for the linux YAFFS filesystem routines. ++# ++ ++obj-$(CONFIG_YAFFS_FS) += yaffs.o ++ ++yaffs-y := yaffs_ecc.o yaffs_vfs.o yaffs_guts.o yaffs_checkptrw.o ++yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o ++yaffs-y += yaffs_tagscompat.o yaffs_tagsmarshall.o ++yaffs-y += yaffs_endian.o ++yaffs-y += yaffs_mtdif.o ++yaffs-y += yaffs_nameval.o yaffs_attribs.o ++yaffs-y += yaffs_allocator.o ++yaffs-y += yaffs_yaffs1.o ++yaffs-y += yaffs_yaffs2.o ++yaffs-y += yaffs_bitmap.o ++yaffs-y += yaffs_summary.o ++yaffs-y += yaffs_verify.o ++yaffs-y += yaffs_cache.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_allocator.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_allocator.c.patch new file mode 100644 index 00000000..398bd873 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_allocator.c.patch @@ -0,0 +1,360 @@ +diff -drupN a/fs/yaffs2/yaffs_allocator.c b/fs/yaffs2/yaffs_allocator.c +--- a/fs/yaffs2/yaffs_allocator.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_allocator.c 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,356 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * 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. ++ */ ++ ++#include "yaffs_allocator.h" ++#include "yaffs_guts.h" ++#include "yaffs_trace.h" ++#include "yportenv.h" ++ ++/* ++ * Each entry in yaffs_tnode_list and yaffs_obj_list hold blocks ++ * of approx 100 objects that are themn allocated singly. ++ * This is basically a simplified slab allocator. ++ * ++ * We don't use the Linux slab allocator because slab does not allow ++ * us to dump all the objects in one hit when we do a umount and tear ++ * down all the tnodes and objects. slab requires that we first free ++ * the individual objects. ++ * ++ * Once yaffs has been mainlined I shall try to motivate for a change ++ * to slab to provide the extra features we need here. ++ */ ++ ++struct yaffs_tnode_list { ++ struct yaffs_tnode_list *next; ++ struct yaffs_tnode *tnodes; ++}; ++ ++struct yaffs_obj_list { ++ struct yaffs_obj_list *next; ++ struct yaffs_obj *objects; ++}; ++ ++struct yaffs_allocator { ++ int n_tnodes_created; ++ struct yaffs_tnode *free_tnodes; ++ int n_free_tnodes; ++ struct yaffs_tnode_list *alloc_tnode_list; ++ ++ int n_obj_created; ++ struct list_head free_objs; ++ int n_free_objects; ++ ++ struct yaffs_obj_list *allocated_obj_list; ++}; ++ ++static void yaffs_deinit_raw_tnodes(struct yaffs_dev *dev) ++{ ++ struct yaffs_allocator *allocator = ++ (struct yaffs_allocator *)dev->allocator; ++ struct yaffs_tnode_list *tmp; ++ ++ if (!allocator) { ++ BUG(); ++ return; ++ } ++ ++ while (allocator->alloc_tnode_list) { ++ tmp = allocator->alloc_tnode_list->next; ++ ++ kfree(allocator->alloc_tnode_list->tnodes); ++ kfree(allocator->alloc_tnode_list); ++ allocator->alloc_tnode_list = tmp; ++ } ++ ++ allocator->free_tnodes = NULL; ++ allocator->n_free_tnodes = 0; ++ allocator->n_tnodes_created = 0; ++} ++ ++static void yaffs_init_raw_tnodes(struct yaffs_dev *dev) ++{ ++ struct yaffs_allocator *allocator = dev->allocator; ++ ++ if (!allocator) { ++ BUG(); ++ return; ++ } ++ ++ allocator->alloc_tnode_list = NULL; ++ allocator->free_tnodes = NULL; ++ allocator->n_free_tnodes = 0; ++ allocator->n_tnodes_created = 0; ++} ++ ++static int yaffs_create_tnodes(struct yaffs_dev *dev, int n_tnodes) ++{ ++ struct yaffs_allocator *allocator = ++ (struct yaffs_allocator *)dev->allocator; ++ int i; ++ struct yaffs_tnode *new_tnodes; ++ u8 *mem; ++ struct yaffs_tnode *curr; ++ struct yaffs_tnode *next; ++ struct yaffs_tnode_list *tnl; ++ ++ if (!allocator) { ++ BUG(); ++ return YAFFS_FAIL; ++ } ++ ++ if (n_tnodes < 1) ++ return YAFFS_OK; ++ ++ /* make these things */ ++ new_tnodes = kmalloc(n_tnodes * dev->tnode_size, GFP_NOFS); ++ mem = (u8 *) new_tnodes; ++ ++ if (!new_tnodes) { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "yaffs: Could not allocate Tnodes"); ++ return YAFFS_FAIL; ++ } ++ ++ /* New hookup for wide tnodes */ ++ for (i = 0; i < n_tnodes - 1; i++) { ++ curr = (struct yaffs_tnode *)&mem[i * dev->tnode_size]; ++ next = (struct yaffs_tnode *)&mem[(i + 1) * dev->tnode_size]; ++ curr->internal[0] = next; ++ } ++ ++ curr = (struct yaffs_tnode *)&mem[(n_tnodes - 1) * dev->tnode_size]; ++ curr->internal[0] = allocator->free_tnodes; ++ allocator->free_tnodes = (struct yaffs_tnode *)mem; ++ ++ allocator->n_free_tnodes += n_tnodes; ++ allocator->n_tnodes_created += n_tnodes; ++ ++ /* Now add this bunch of tnodes to a list for freeing up. ++ * NB If we can't add this to the management list it isn't fatal ++ * but it just means we can't free this bunch of tnodes later. ++ */ ++ tnl = kmalloc(sizeof(struct yaffs_tnode_list), GFP_NOFS); ++ if (!tnl) { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "Could not add tnodes to management list"); ++ return YAFFS_FAIL; ++ } else { ++ tnl->tnodes = new_tnodes; ++ tnl->next = allocator->alloc_tnode_list; ++ allocator->alloc_tnode_list = tnl; ++ } ++ ++ yaffs_trace(YAFFS_TRACE_ALLOCATE, "Tnodes added"); ++ ++ return YAFFS_OK; ++} ++ ++struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev) ++{ ++ struct yaffs_allocator *allocator = ++ (struct yaffs_allocator *)dev->allocator; ++ struct yaffs_tnode *tn = NULL; ++ ++ if (!allocator) { ++ BUG(); ++ return NULL; ++ } ++ ++ /* If there are none left make more */ ++ if (!allocator->free_tnodes) ++ yaffs_create_tnodes(dev, YAFFS_ALLOCATION_NTNODES); ++ ++ if (allocator->free_tnodes) { ++ tn = allocator->free_tnodes; ++ allocator->free_tnodes = allocator->free_tnodes->internal[0]; ++ allocator->n_free_tnodes--; ++ } ++ ++ return tn; ++} ++ ++/* FreeTnode frees up a tnode and puts it back on the free list */ ++void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn) ++{ ++ struct yaffs_allocator *allocator = dev->allocator; ++ ++ if (!allocator) { ++ BUG(); ++ return; ++ } ++ ++ if (tn) { ++ tn->internal[0] = allocator->free_tnodes; ++ allocator->free_tnodes = tn; ++ allocator->n_free_tnodes++; ++ } ++ dev->checkpoint_blocks_required = 0; /* force recalculation */ ++} ++ ++/*--------------- yaffs_obj alloaction ------------------------ ++ * ++ * Free yaffs_objs are stored in a list using obj->siblings. ++ * The blocks of allocated objects are stored in a linked list. ++ */ ++ ++static void yaffs_init_raw_objs(struct yaffs_dev *dev) ++{ ++ struct yaffs_allocator *allocator = dev->allocator; ++ ++ if (!allocator) { ++ BUG(); ++ return; ++ } ++ ++ allocator->allocated_obj_list = NULL; ++ INIT_LIST_HEAD(&allocator->free_objs); ++ allocator->n_free_objects = 0; ++} ++ ++static void yaffs_deinit_raw_objs(struct yaffs_dev *dev) ++{ ++ struct yaffs_allocator *allocator = dev->allocator; ++ struct yaffs_obj_list *tmp; ++ ++ if (!allocator) { ++ BUG(); ++ return; ++ } ++ ++ while (allocator->allocated_obj_list) { ++ tmp = allocator->allocated_obj_list->next; ++ kfree(allocator->allocated_obj_list->objects); ++ kfree(allocator->allocated_obj_list); ++ allocator->allocated_obj_list = tmp; ++ } ++ ++ INIT_LIST_HEAD(&allocator->free_objs); ++ allocator->n_free_objects = 0; ++ allocator->n_obj_created = 0; ++} ++ ++static int yaffs_create_free_objs(struct yaffs_dev *dev, int n_obj) ++{ ++ struct yaffs_allocator *allocator = dev->allocator; ++ int i; ++ struct yaffs_obj *new_objs; ++ struct yaffs_obj_list *list; ++ ++ if (!allocator) { ++ BUG(); ++ return YAFFS_FAIL; ++ } ++ ++ if (n_obj < 1) ++ return YAFFS_OK; ++ ++ /* make these things */ ++ new_objs = kmalloc(n_obj * sizeof(struct yaffs_obj), GFP_NOFS); ++ list = kmalloc(sizeof(struct yaffs_obj_list), GFP_NOFS); ++ ++ if (!new_objs || !list) { ++ kfree(new_objs); ++ new_objs = NULL; ++ kfree(list); ++ list = NULL; ++ yaffs_trace(YAFFS_TRACE_ALLOCATE, ++ "Could not allocate more objects"); ++ return YAFFS_FAIL; ++ } ++ ++ /* Hook them into the free list */ ++ for (i = 0; i < n_obj; i++) ++ list_add(&new_objs[i].siblings, &allocator->free_objs); ++ ++ allocator->n_free_objects += n_obj; ++ allocator->n_obj_created += n_obj; ++ ++ /* Now add this bunch of Objects to a list for freeing up. */ ++ ++ list->objects = new_objs; ++ list->next = allocator->allocated_obj_list; ++ allocator->allocated_obj_list = list; ++ ++ return YAFFS_OK; ++} ++ ++struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev) ++{ ++ struct yaffs_obj *obj = NULL; ++ struct list_head *lh; ++ struct yaffs_allocator *allocator = dev->allocator; ++ ++ if (!allocator) { ++ BUG(); ++ return obj; ++ } ++ ++ /* If there are none left make more */ ++ if (list_empty(&allocator->free_objs)) ++ yaffs_create_free_objs(dev, YAFFS_ALLOCATION_NOBJECTS); ++ ++ if (!list_empty(&allocator->free_objs)) { ++ lh = allocator->free_objs.next; ++ obj = list_entry(lh, struct yaffs_obj, siblings); ++ list_del_init(lh); ++ allocator->n_free_objects--; ++ } ++ ++ return obj; ++} ++ ++void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj) ++{ ++ ++ struct yaffs_allocator *allocator = dev->allocator; ++ ++ if (!allocator) { ++ BUG(); ++ return; ++ } ++ ++ /* Link into the free list. */ ++ list_add(&obj->siblings, &allocator->free_objs); ++ allocator->n_free_objects++; ++} ++ ++void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev) ++{ ++ ++ if (!dev->allocator) { ++ BUG(); ++ return; ++ } ++ ++ yaffs_deinit_raw_tnodes(dev); ++ yaffs_deinit_raw_objs(dev); ++ kfree(dev->allocator); ++ dev->allocator = NULL; ++} ++ ++void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev) ++{ ++ struct yaffs_allocator *allocator; ++ ++ if (dev->allocator) { ++ BUG(); ++ return; ++ } ++ ++ allocator = kmalloc(sizeof(struct yaffs_allocator), GFP_NOFS); ++ if (allocator) { ++ dev->allocator = allocator; ++ yaffs_init_raw_tnodes(dev); ++ yaffs_init_raw_objs(dev); ++ } ++} ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_allocator.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_allocator.h.patch new file mode 100644 index 00000000..34831689 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_allocator.h.patch @@ -0,0 +1,33 @@ +diff -drupN a/fs/yaffs2/yaffs_allocator.h b/fs/yaffs2/yaffs_allocator.h +--- a/fs/yaffs2/yaffs_allocator.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_allocator.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,29 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_ALLOCATOR_H__ ++#define __YAFFS_ALLOCATOR_H__ ++ ++#include "yaffs_guts.h" ++ ++void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev); ++void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev); ++ ++struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev); ++void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn); ++ ++struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev); ++void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj); ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_attribs.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_attribs.c.patch new file mode 100644 index 00000000..e4247ad4 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_attribs.c.patch @@ -0,0 +1,139 @@ +diff -drupN a/fs/yaffs2/yaffs_attribs.c b/fs/yaffs2/yaffs_attribs.c +--- a/fs/yaffs2/yaffs_attribs.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_attribs.c 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,135 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * 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. ++ */ ++ ++#include "yaffs_guts.h" ++#include "yaffs_attribs.h" ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) ++#define IATTR_UID ia_uid ++#define IATTR_GID ia_gid ++#else ++#define IATTR_UID ia_uid.val ++#define IATTR_GID ia_gid.val ++#endif ++ ++/* ++ * Loading attibs from/to object header assumes the object header ++ * is in cpu endian. ++ */ ++void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh) ++{ ++ obj->yst_uid = oh->yst_uid; ++ obj->yst_gid = oh->yst_gid; ++ obj->yst_atime = oh->yst_atime; ++ obj->yst_mtime = oh->yst_mtime; ++ obj->yst_ctime = oh->yst_ctime; ++ obj->yst_rdev = oh->yst_rdev; ++} ++ ++void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj) ++{ ++ oh->yst_uid = obj->yst_uid; ++ oh->yst_gid = obj->yst_gid; ++ oh->yst_atime = obj->yst_atime; ++ oh->yst_mtime = obj->yst_mtime; ++ oh->yst_ctime = obj->yst_ctime; ++ oh->yst_rdev = obj->yst_rdev; ++ ++} ++ ++void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c) ++{ ++ obj->yst_mtime = Y_CURRENT_TIME; ++ if (do_a) ++ obj->yst_atime = obj->yst_mtime; ++ if (do_c) ++ obj->yst_ctime = obj->yst_mtime; ++} ++ ++void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev) ++{ ++ yaffs_load_current_time(obj, 1, 1); ++ obj->yst_rdev = rdev; ++ obj->yst_uid = uid; ++ obj->yst_gid = gid; ++} ++ ++static loff_t yaffs_get_file_size(struct yaffs_obj *obj) ++{ ++ YCHAR *alias = NULL; ++ obj = yaffs_get_equivalent_obj(obj); ++ ++ switch (obj->variant_type) { ++ case YAFFS_OBJECT_TYPE_FILE: ++ return obj->variant.file_variant.file_size; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ alias = obj->variant.symlink_variant.alias; ++ if (!alias) ++ return 0; ++ return strnlen(alias, YAFFS_MAX_ALIAS_LENGTH); ++ default: ++ return 0; ++ } ++} ++ ++int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr) ++{ ++ unsigned int valid = attr->ia_valid; ++ ++ if (valid & ATTR_MODE) ++ obj->yst_mode = attr->ia_mode; ++ if (valid & ATTR_UID) ++ obj->yst_uid = attr->IATTR_UID; ++ if (valid & ATTR_GID) ++ obj->yst_gid = attr->IATTR_GID; ++ ++ if (valid & ATTR_ATIME) ++ obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime); ++ if (valid & ATTR_CTIME) ++ obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime); ++ if (valid & ATTR_MTIME) ++ obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime); ++ ++ if (valid & ATTR_SIZE) ++ yaffs_resize_file(obj, attr->ia_size); ++ ++ yaffs_update_oh(obj, NULL, 1, 0, 0, NULL); ++ ++ return YAFFS_OK; ++ ++} ++ ++int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr) ++{ ++ unsigned int valid = 0; ++ ++ attr->ia_mode = obj->yst_mode; ++ valid |= ATTR_MODE; ++ attr->IATTR_UID = obj->yst_uid; ++ valid |= ATTR_UID; ++ attr->IATTR_GID = obj->yst_gid; ++ valid |= ATTR_GID; ++ ++ Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime; ++ valid |= ATTR_ATIME; ++ Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime; ++ valid |= ATTR_CTIME; ++ Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime; ++ valid |= ATTR_MTIME; ++ ++ attr->ia_size = yaffs_get_file_size(obj); ++ valid |= ATTR_SIZE; ++ ++ attr->ia_valid = valid; ++ ++ return YAFFS_OK; ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_attribs.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_attribs.h.patch new file mode 100644 index 00000000..724e9711 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_attribs.h.patch @@ -0,0 +1,31 @@ +diff -drupN a/fs/yaffs2/yaffs_attribs.h b/fs/yaffs2/yaffs_attribs.h +--- a/fs/yaffs2/yaffs_attribs.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_attribs.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,27 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_ATTRIBS_H__ ++#define __YAFFS_ATTRIBS_H__ ++ ++#include "yaffs_guts.h" ++ ++void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh); ++void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj); ++void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev); ++void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c); ++int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr); ++int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr); ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_bitmap.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_bitmap.c.patch new file mode 100644 index 00000000..b5465aed --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_bitmap.c.patch @@ -0,0 +1,102 @@ +diff -drupN a/fs/yaffs2/yaffs_bitmap.c b/fs/yaffs2/yaffs_bitmap.c +--- a/fs/yaffs2/yaffs_bitmap.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_bitmap.c 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,98 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * 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. ++ */ ++ ++#include "yaffs_bitmap.h" ++#include "yaffs_trace.h" ++/* ++ * Chunk bitmap manipulations ++ */ ++ ++static inline u8 *yaffs_block_bits(struct yaffs_dev *dev, int blk) ++{ ++ if (blk < (int)dev->internal_start_block || ++ blk > (int)dev->internal_end_block) { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "BlockBits block %d is not valid", ++ blk); ++ BUG(); ++ } ++ return dev->chunk_bits + ++ (dev->chunk_bit_stride * (blk - dev->internal_start_block)); ++} ++ ++void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk) ++{ ++ if (blk < (int)dev->internal_start_block || ++ blk > (int)dev->internal_end_block || ++ chunk < 0 || chunk >= (int)dev->param.chunks_per_block) { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "Chunk Id (%d:%d) invalid", ++ blk, chunk); ++ BUG(); ++ } ++} ++ ++void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk) ++{ ++ u8 *blk_bits = yaffs_block_bits(dev, blk); ++ ++ memset(blk_bits, 0, dev->chunk_bit_stride); ++} ++ ++void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk) ++{ ++ u8 *blk_bits = yaffs_block_bits(dev, blk); ++ ++ yaffs_verify_chunk_bit_id(dev, blk, chunk); ++ blk_bits[chunk / 8] &= ~(1 << (chunk & 7)); ++} ++ ++void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk) ++{ ++ u8 *blk_bits = yaffs_block_bits(dev, blk); ++ ++ yaffs_verify_chunk_bit_id(dev, blk, chunk); ++ blk_bits[chunk / 8] |= (1 << (chunk & 7)); ++} ++ ++int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk) ++{ ++ u8 *blk_bits = yaffs_block_bits(dev, blk); ++ ++ yaffs_verify_chunk_bit_id(dev, blk, chunk); ++ return (blk_bits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0; ++} ++ ++int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk) ++{ ++ u8 *blk_bits = yaffs_block_bits(dev, blk); ++ int i; ++ ++ for (i = 0; i < dev->chunk_bit_stride; i++) { ++ if (*blk_bits) ++ return 1; ++ blk_bits++; ++ } ++ return 0; ++} ++ ++int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk) ++{ ++ u8 *blk_bits = yaffs_block_bits(dev, blk); ++ int i; ++ int n = 0; ++ ++ for (i = 0; i < dev->chunk_bit_stride; i++, blk_bits++) ++ n += hweight8(*blk_bits); ++ ++ return n; ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_bitmap.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_bitmap.h.patch new file mode 100644 index 00000000..16abd89e --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_bitmap.h.patch @@ -0,0 +1,36 @@ +diff -drupN a/fs/yaffs2/yaffs_bitmap.h b/fs/yaffs2/yaffs_bitmap.h +--- a/fs/yaffs2/yaffs_bitmap.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_bitmap.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,32 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++/* ++ * Chunk bitmap manipulations ++ */ ++ ++#ifndef __YAFFS_BITMAP_H__ ++#define __YAFFS_BITMAP_H__ ++ ++#include "yaffs_guts.h" ++ ++void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk); ++void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk); ++void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk); ++void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk); ++int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk); ++int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk); ++int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk); ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_cache.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_cache.c.patch new file mode 100644 index 00000000..ead36b2a --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_cache.c.patch @@ -0,0 +1,329 @@ +diff -drupN a/fs/yaffs2/yaffs_cache.c b/fs/yaffs2/yaffs_cache.c +--- a/fs/yaffs2/yaffs_cache.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_cache.c 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,325 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * 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. ++ */ ++ ++#include "yaffs_cache.h" ++ ++/*------------------------ Short Operations Cache ------------------------------ ++ * In many situations where there is no high level buffering a lot of ++ * reads might be short sequential reads, and a lot of writes may be short ++ * sequential writes. eg. scanning/writing a jpeg file. ++ * In these cases, a short read/write cache can provide a huge perfomance ++ * benefit with dumb-as-a-rock code. ++ * In Linux, the page cache provides read buffering and the short op cache ++ * provides write buffering. ++ * ++ * There are a small number (~10) of cache chunks per device so that we don't ++ * need a very intelligent search. ++ */ ++ ++int yaffs_obj_cache_dirty(struct yaffs_obj *obj) ++{ ++ struct yaffs_dev *dev = obj->my_dev; ++ int i; ++ struct yaffs_cache_manager *mgr = &dev->cache_mgr; ++ ++ for (i = 0; i < mgr->n_caches; i++) { ++ struct yaffs_cache *cache = &mgr->cache[i]; ++ ++ if (cache->object == obj && cache->dirty) ++ return 1; ++ } ++ ++ return 0; ++} ++ ++void yaffs_flush_single_cache(struct yaffs_cache *cache, int discard) ++{ ++ ++ if (!cache || cache->locked) ++ return; ++ ++ /* Write it out and free it up if need be.*/ ++ if (cache->dirty) { ++ yaffs_wr_data_obj(cache->object, ++ cache->chunk_id, ++ cache->data, ++ cache->n_bytes, ++ 1); ++ ++ cache->dirty = 0; ++ } ++ ++ if (discard) ++ cache->object = NULL; ++} ++ ++void yaffs_flush_file_cache(struct yaffs_obj *obj, int discard) ++{ ++ struct yaffs_dev *dev = obj->my_dev; ++ int i; ++ struct yaffs_cache_manager *mgr = &dev->cache_mgr; ++ ++ if (mgr->n_caches < 1) ++ return; ++ ++ ++ /* Find the chunks for this object and flush them. */ ++ for (i = 0; i < mgr->n_caches; i++) { ++ struct yaffs_cache *cache = &mgr->cache[i]; ++ ++ if (cache->object == obj) ++ yaffs_flush_single_cache(cache, discard); ++ } ++ ++} ++ ++ ++void yaffs_flush_whole_cache(struct yaffs_dev *dev, int discard) ++{ ++ struct yaffs_cache_manager *mgr = &dev->cache_mgr; ++ struct yaffs_obj *obj; ++ int i; ++ ++ /* Find a dirty object in the cache and flush it... ++ * until there are no further dirty objects. ++ */ ++ do { ++ obj = NULL; ++ for (i = 0; i < mgr->n_caches && !obj; i++) { ++ struct yaffs_cache *cache = &mgr->cache[i]; ++ if (cache->object && cache->dirty) ++ obj = cache->object; ++ } ++ if (obj) ++ yaffs_flush_file_cache(obj, discard); ++ } while (obj); ++ ++} ++ ++/* Grab us an unused cache chunk for use. ++ * First look for an empty one. ++ * Then look for the least recently used non-dirty one. ++ * Then look for the least recently used dirty one...., flush and look again. ++ */ ++static struct yaffs_cache *yaffs_grab_chunk_worker(struct yaffs_dev *dev) ++{ ++ struct yaffs_cache_manager *mgr = &dev->cache_mgr; ++ int i; ++ ++ for (i = 0; i < mgr->n_caches; i++) { ++ struct yaffs_cache *cache = &mgr->cache[i]; ++ if (!cache->object) ++ return cache; ++ } ++ ++ return NULL; ++} ++ ++struct yaffs_cache *yaffs_grab_chunk_cache(struct yaffs_dev *dev) ++{ ++ struct yaffs_cache_manager *mgr = &dev->cache_mgr; ++ struct yaffs_cache *cache; ++ int usage; ++ int i; ++ ++ if (mgr->n_caches < 1) ++ return NULL; ++ ++ /* First look for an unused cache */ ++ ++ cache = yaffs_grab_chunk_worker(dev); ++ ++ if (cache) ++ return cache; ++ ++ /* ++ * Thery were all in use. ++ * Find the LRU cache and flush it if it is dirty. ++ */ ++ ++ usage = -1; ++ cache = NULL; ++ ++ for (i = 0; i < mgr->n_caches; i++) { ++ struct yaffs_cache *this_cache = &mgr->cache[i]; ++ ++ if (this_cache->object && ++ !this_cache->locked && ++ (this_cache->last_use < usage || !cache)) { ++ usage = this_cache->last_use; ++ cache = this_cache; ++ } ++ } ++ ++#if 1 ++ yaffs_flush_single_cache(cache, 1); ++#else ++ yaffs_flush_file_cache(cache->object, 1); ++ cache = yaffs_grab_chunk_worker(dev); ++#endif ++ ++ return cache; ++} ++ ++/* Find a cached chunk */ ++struct yaffs_cache *yaffs_find_chunk_cache(const struct yaffs_obj *obj, ++ int chunk_id) ++{ ++ struct yaffs_dev *dev = obj->my_dev; ++ struct yaffs_cache_manager *mgr = &dev->cache_mgr; ++ int i; ++ ++ if (mgr->n_caches < 1) ++ return NULL; ++ ++ for (i = 0; i < mgr->n_caches; i++) { ++ struct yaffs_cache *cache = &mgr->cache[i]; ++ ++ if (cache->object == obj && ++ cache->chunk_id == chunk_id) { ++ dev->cache_hits++; ++ return cache; ++ } ++ } ++ return NULL; ++} ++ ++/* Mark the chunk for the least recently used algorithym */ ++void yaffs_use_cache(struct yaffs_dev *dev, struct yaffs_cache *cache, ++ int is_write) ++{ ++ struct yaffs_cache_manager *mgr = &dev->cache_mgr; ++ int i; ++ ++ if (mgr->n_caches < 1) ++ return; ++ ++ if (mgr->cache_last_use < 0 || ++ mgr->cache_last_use > 100000000) { ++ /* Reset the cache usages */ ++ for (i = 1; i < mgr->n_caches; i++) ++ mgr->cache[i].last_use = 0; ++ ++ mgr->cache_last_use = 0; ++ } ++ mgr->cache_last_use++; ++ cache->last_use = mgr->cache_last_use; ++ ++ if (is_write) ++ cache->dirty = 1; ++} ++ ++/* Invalidate a single cache page. ++ * Do this when a whole page gets written, ++ * ie the short cache for this page is no longer valid. ++ */ ++void yaffs_invalidate_chunk_cache(struct yaffs_obj *object, int chunk_id) ++{ ++ struct yaffs_cache *cache; ++ ++ cache = yaffs_find_chunk_cache(object, chunk_id); ++ if (cache) ++ cache->object = NULL; ++} ++ ++/* Invalidate all the cache pages associated with this object ++ * Do this whenever the file is deleted or resized. ++ */ ++void yaffs_invalidate_file_cache(struct yaffs_obj *in) ++{ ++ int i; ++ struct yaffs_dev *dev = in->my_dev; ++ struct yaffs_cache_manager *mgr = &dev->cache_mgr; ++ ++ /* Invalidate it. */ ++ for (i = 0; i < mgr->n_caches; i++) { ++ struct yaffs_cache *cache = &mgr->cache[i]; ++ ++ if (cache->object == in) ++ cache->object = NULL; ++ } ++} ++ ++int yaffs_count_dirty_caches(struct yaffs_dev *dev) ++{ ++ int n_dirty; ++ int i; ++ struct yaffs_cache_manager *mgr = &dev->cache_mgr; ++ ++ for (n_dirty= 0, i = 0; i < mgr->n_caches; i++) { ++ if (mgr->cache[i].dirty) ++ n_dirty++; ++ } ++ ++ return n_dirty; ++} ++ ++int yaffs_cache_init(struct yaffs_dev *dev) ++{ ++ struct yaffs_cache_manager *mgr = &dev->cache_mgr; ++ int init_failed = 0; ++ ++ if (dev->param.n_caches > YAFFS_MAX_SHORT_OP_CACHES) ++ dev->param.n_caches = YAFFS_MAX_SHORT_OP_CACHES; ++ ++ mgr->n_caches = dev->param.n_caches; ++ if (mgr->n_caches > 0) { ++ int i; ++ void *buf; ++ u32 cache_bytes = ++ mgr->n_caches * sizeof(struct yaffs_cache); ++ ++ ++ ++ mgr->cache = kmalloc(cache_bytes, GFP_NOFS); ++ ++ buf = (u8 *) mgr->cache; ++ ++ if (mgr->cache) ++ memset(mgr->cache, 0, cache_bytes); ++ ++ for (i = 0; i < mgr->n_caches && buf; i++) { ++ struct yaffs_cache *cache = &mgr->cache[i]; ++ ++ cache->object = NULL; ++ cache->last_use = 0; ++ cache->dirty = 0; ++ cache->data = buf = ++ kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS); ++ } ++ if (!buf) ++ init_failed = 1; ++ ++ mgr->cache_last_use = 0; ++ } ++ ++ return init_failed ? -1 : 0; ++} ++ ++void yaffs_cache_deinit(struct yaffs_dev *dev) ++{ ++ struct yaffs_cache_manager *mgr = &dev->cache_mgr; ++ int i; ++ ++ if (mgr->n_caches < 1 || !mgr->cache) ++ return; ++ ++ for (i = 0; i < mgr->n_caches; i++) { ++ ++ struct yaffs_cache *cache = &mgr->cache[i]; ++ kfree(cache->data); ++ cache->data = NULL; ++ } ++ ++ kfree(mgr->cache); ++ mgr->cache = NULL; ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_cache.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_cache.h.patch new file mode 100644 index 00000000..17818328 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_cache.h.patch @@ -0,0 +1,60 @@ +diff -drupN a/fs/yaffs2/yaffs_cache.h b/fs/yaffs2/yaffs_cache.h +--- a/fs/yaffs2/yaffs_cache.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_cache.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,56 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * 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. ++ */ ++ ++#ifndef __YAFFS_CACHE_H__ ++#define __YAFFS_CACHE_H__ ++ ++#include "yaffs_guts.h" ++ ++ ++/* Does the object have a dirty cache ? */ ++int yaffs_obj_cache_dirty(struct yaffs_obj *obj); ++ ++/* Flush the cache associated with a file, either discarding or keeping */ ++void yaffs_flush_file_cache(struct yaffs_obj *obj, int discard); ++ ++/* Flush everything in the cache, either discarding or keeping */ ++void yaffs_flush_whole_cache(struct yaffs_dev *dev, int discard); ++ ++/* Grab a cache item during read or write. */ ++struct yaffs_cache *yaffs_grab_chunk_cache(struct yaffs_dev *dev); ++ ++/* Find a cached chunk */ ++struct yaffs_cache *yaffs_find_chunk_cache(const struct yaffs_obj *obj, ++ int chunk_id); ++ ++/* Mark the chunk for the least recently used algorithym */ ++void yaffs_use_cache(struct yaffs_dev *dev, struct yaffs_cache *cache, ++ int is_write); ++ ++ ++/* Invalidate a single cache page. The cache no longer holds valid data. */ ++void yaffs_invalidate_chunk_cache(struct yaffs_obj *object, ++ int chunk_id); ++ ++/* Invalidate all the cache pages associated with this object ++ * Do this whenever ther file is deleted or resized. ++ */ ++void yaffs_invalidate_file_cache(struct yaffs_obj *in); ++ ++ ++int yaffs_count_dirty_caches(struct yaffs_dev *dev); ++ ++/* Init/deinit. */ ++int yaffs_cache_init(struct yaffs_dev *dev); ++void yaffs_cache_deinit(struct yaffs_dev *dev); ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_checkptrw.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_checkptrw.c.patch new file mode 100644 index 00000000..23f46d8e --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_checkptrw.c.patch @@ -0,0 +1,484 @@ +diff -drupN a/fs/yaffs2/yaffs_checkptrw.c b/fs/yaffs2/yaffs_checkptrw.c +--- a/fs/yaffs2/yaffs_checkptrw.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_checkptrw.c 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,480 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * 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. ++ */ ++ ++#include "yaffs_checkptrw.h" ++#include "yaffs_getblockinfo.h" ++#include "yaffs_endian.h" ++ ++struct yaffs_checkpt_chunk_hdr { ++ int version; ++ int seq; ++ u32 sum; ++ u32 xor; ++} ; ++ ++ ++static int apply_chunk_offset(struct yaffs_dev *dev, int chunk) ++{ ++ return chunk - dev->chunk_offset; ++} ++ ++static int apply_block_offset(struct yaffs_dev *dev, int block) ++{ ++ return block - dev->block_offset; ++} ++ ++ ++static void yaffs2_do_endian_hdr(struct yaffs_dev *dev, ++ struct yaffs_checkpt_chunk_hdr *hdr) ++{ ++ if (!dev->swap_endian) ++ return; ++ hdr->version = swap_s32(hdr->version); ++ hdr->seq = swap_s32(hdr->seq); ++ hdr->sum = swap_u32(hdr->sum); ++ hdr->xor = swap_u32(hdr->xor); ++} ++ ++static void yaffs2_checkpt_init_chunk_hdr(struct yaffs_dev *dev) ++{ ++ struct yaffs_checkpt_chunk_hdr hdr; ++ ++ hdr.version = YAFFS_CHECKPOINT_VERSION; ++ hdr.seq = dev->checkpt_page_seq; ++ hdr.sum = dev->checkpt_sum; ++ hdr.xor = dev->checkpt_xor; ++ ++ dev->checkpt_byte_offs = sizeof(hdr); ++ ++ yaffs2_do_endian_hdr(dev, &hdr); ++ memcpy(dev->checkpt_buffer, &hdr, sizeof(hdr)); ++} ++ ++static int yaffs2_checkpt_check_chunk_hdr(struct yaffs_dev *dev) ++{ ++ struct yaffs_checkpt_chunk_hdr hdr; ++ ++ memcpy(&hdr, dev->checkpt_buffer, sizeof(hdr)); ++ yaffs2_do_endian_hdr(dev, &hdr); ++ ++ dev->checkpt_byte_offs = sizeof(hdr); ++ ++ return hdr.version == YAFFS_CHECKPOINT_VERSION && ++ hdr.seq == dev->checkpt_page_seq && ++ hdr.sum == dev->checkpt_sum && ++ hdr.xor == dev->checkpt_xor; ++} ++ ++static int yaffs2_checkpt_space_ok(struct yaffs_dev *dev) ++{ ++ int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks; ++ ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "checkpt blocks_avail = %d", blocks_avail); ++ ++ return (blocks_avail <= 0) ? 0 : 1; ++} ++ ++static int yaffs_checkpt_erase(struct yaffs_dev *dev) ++{ ++ u32 i; ++ ++ if (!dev->drv.drv_erase_fn) ++ return 0; ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "checking blocks %d to %d", ++ dev->internal_start_block, dev->internal_end_block); ++ ++ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { ++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, i); ++ int offset_i = apply_block_offset(dev, i); ++ int result; ++ ++ if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) { ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "erasing checkpt block %d", i); ++ ++ dev->n_erasures++; ++ ++ result = dev->drv.drv_erase_fn(dev, offset_i); ++ if(result) { ++ bi->block_state = YAFFS_BLOCK_STATE_EMPTY; ++ dev->n_erased_blocks++; ++ dev->n_free_chunks += ++ dev->param.chunks_per_block; ++ } else { ++ dev->drv.drv_mark_bad_fn(dev, offset_i); ++ bi->block_state = YAFFS_BLOCK_STATE_DEAD; ++ } ++ } ++ } ++ ++ dev->blocks_in_checkpt = 0; ++ ++ return 1; ++} ++ ++static void yaffs2_checkpt_find_erased_block(struct yaffs_dev *dev) ++{ ++ u32 i; ++ int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks; ++ ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "allocating checkpt block: erased %d reserved %d avail %d next %d ", ++ dev->n_erased_blocks, dev->param.n_reserved_blocks, ++ blocks_avail, dev->checkpt_next_block); ++ ++ if (dev->checkpt_next_block >= 0 && ++ dev->checkpt_next_block <= (int)dev->internal_end_block && ++ blocks_avail > 0) { ++ ++ for (i = dev->checkpt_next_block; i <= dev->internal_end_block; ++ i++) { ++ struct yaffs_block_info *bi; ++ ++ bi = yaffs_get_block_info(dev, i); ++ if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) { ++ dev->checkpt_next_block = i + 1; ++ dev->checkpt_cur_block = i; ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "allocating checkpt block %d", i); ++ return; ++ } ++ } ++ } ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, "out of checkpt blocks"); ++ ++ dev->checkpt_next_block = -1; ++ dev->checkpt_cur_block = -1; ++} ++ ++static void yaffs2_checkpt_find_block(struct yaffs_dev *dev) ++{ ++ u32 i; ++ struct yaffs_ext_tags tags; ++ ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "find next checkpt block: start: blocks %d next %d", ++ dev->blocks_in_checkpt, dev->checkpt_next_block); ++ ++ if (dev->blocks_in_checkpt < dev->checkpt_max_blocks) ++ for (i = dev->checkpt_next_block; i <= dev->internal_end_block; ++ i++) { ++ int chunk = i * dev->param.chunks_per_block; ++ enum yaffs_block_state state; ++ u32 seq; ++ ++ dev->tagger.read_chunk_tags_fn(dev, ++ apply_chunk_offset(dev, chunk), ++ NULL, &tags); ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "find next checkpt block: search: block %d state %d oid %d seq %d eccr %d", ++ i, (int) state, ++ tags.obj_id, tags.seq_number, ++ tags.ecc_result); ++ ++ if (tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA) ++ continue; ++ ++ dev->tagger.query_block_fn(dev, ++ apply_block_offset(dev, i), ++ &state, &seq); ++ if (state == YAFFS_BLOCK_STATE_DEAD) ++ continue; ++ ++ /* Right kind of block */ ++ dev->checkpt_next_block = tags.obj_id; ++ dev->checkpt_cur_block = i; ++ dev->checkpt_block_list[dev->blocks_in_checkpt] = i; ++ dev->blocks_in_checkpt++; ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "found checkpt block %d", i); ++ return; ++ } ++ ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, "found no more checkpt blocks"); ++ ++ dev->checkpt_next_block = -1; ++ dev->checkpt_cur_block = -1; ++} ++ ++int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing) ++{ ++ u32 i; ++ ++ dev->checkpt_open_write = writing; ++ ++ /* Got the functions we need? */ ++ if (!dev->tagger.write_chunk_tags_fn || ++ !dev->tagger.read_chunk_tags_fn || ++ !dev->drv.drv_erase_fn || ++ !dev->drv.drv_mark_bad_fn) ++ return 0; ++ ++ if (writing && !yaffs2_checkpt_space_ok(dev)) ++ return 0; ++ ++ if (!dev->checkpt_buffer) ++ dev->checkpt_buffer = ++ kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS); ++ if (!dev->checkpt_buffer) ++ return 0; ++ ++ dev->checkpt_page_seq = 0; ++ dev->checkpt_byte_count = 0; ++ dev->checkpt_sum = 0; ++ dev->checkpt_xor = 0; ++ dev->checkpt_cur_block = -1; ++ dev->checkpt_cur_chunk = -1; ++ dev->checkpt_next_block = dev->internal_start_block; ++ ++ if (writing) { ++ memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk); ++ yaffs2_checkpt_init_chunk_hdr(dev); ++ return yaffs_checkpt_erase(dev); ++ } ++ ++ /* Opening for a read */ ++ /* Set to a value that will kick off a read */ ++ dev->checkpt_byte_offs = dev->data_bytes_per_chunk; ++ /* A checkpoint block list of 1 checkpoint block per 16 block is ++ * (hopefully) going to be way more than we need */ ++ dev->blocks_in_checkpt = 0; ++ dev->checkpt_max_blocks = ++ (dev->internal_end_block - dev->internal_start_block) / 16 + 2; ++ if (!dev->checkpt_block_list) ++ dev->checkpt_block_list = ++ kmalloc(sizeof(int) * dev->checkpt_max_blocks, GFP_NOFS); ++ ++ if (!dev->checkpt_block_list) ++ return 0; ++ ++ for (i = 0; i < dev->checkpt_max_blocks; i++) ++ dev->checkpt_block_list[i] = -1; ++ ++ return 1; ++} ++ ++int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum) ++{ ++ u32 composite_sum; ++ ++ composite_sum = (dev->checkpt_sum << 8) | (dev->checkpt_xor & 0xff); ++ *sum = composite_sum; ++ return 1; ++} ++ ++static int yaffs2_checkpt_flush_buffer(struct yaffs_dev *dev) ++{ ++ int chunk; ++ int offset_chunk; ++ struct yaffs_ext_tags tags; ++ ++ if (dev->checkpt_cur_block < 0) { ++ yaffs2_checkpt_find_erased_block(dev); ++ dev->checkpt_cur_chunk = 0; ++ } ++ ++ if (dev->checkpt_cur_block < 0) ++ return 0; ++ ++ tags.is_deleted = 0; ++ tags.obj_id = dev->checkpt_next_block; /* Hint to next place to look */ ++ tags.chunk_id = dev->checkpt_page_seq + 1; ++ tags.seq_number = YAFFS_SEQUENCE_CHECKPOINT_DATA; ++ tags.n_bytes = dev->data_bytes_per_chunk; ++ if (dev->checkpt_cur_chunk == 0) { ++ /* First chunk we write for the block? Set block state to ++ checkpoint */ ++ struct yaffs_block_info *bi = ++ yaffs_get_block_info(dev, dev->checkpt_cur_block); ++ bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT; ++ dev->blocks_in_checkpt++; ++ } ++ ++ chunk = ++ dev->checkpt_cur_block * dev->param.chunks_per_block + ++ dev->checkpt_cur_chunk; ++ ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "checkpoint wite buffer nand %d(%d:%d) objid %d chId %d", ++ chunk, dev->checkpt_cur_block, dev->checkpt_cur_chunk, ++ tags.obj_id, tags.chunk_id); ++ ++ offset_chunk = apply_chunk_offset(dev, chunk); ++ ++ dev->n_page_writes++; ++ ++ dev->tagger.write_chunk_tags_fn(dev, offset_chunk, ++ dev->checkpt_buffer, &tags); ++ dev->checkpt_page_seq++; ++ dev->checkpt_cur_chunk++; ++ if (dev->checkpt_cur_chunk >= (int)dev->param.chunks_per_block) { ++ dev->checkpt_cur_chunk = 0; ++ dev->checkpt_cur_block = -1; ++ } ++ memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk); ++ ++ yaffs2_checkpt_init_chunk_hdr(dev); ++ ++ ++ return 1; ++} ++ ++int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes) ++{ ++ int i = 0; ++ int ok = 1; ++ u8 *data_bytes = (u8 *) data; ++ ++ if (!dev->checkpt_buffer) ++ return 0; ++ ++ if (!dev->checkpt_open_write) ++ return -1; ++ ++ while (i < n_bytes && ok) { ++ dev->checkpt_buffer[dev->checkpt_byte_offs] = *data_bytes; ++ dev->checkpt_sum += *data_bytes; ++ dev->checkpt_xor ^= *data_bytes; ++ ++ dev->checkpt_byte_offs++; ++ i++; ++ data_bytes++; ++ dev->checkpt_byte_count++; ++ ++ if (dev->checkpt_byte_offs < 0 || ++ dev->checkpt_byte_offs >= (int)dev->data_bytes_per_chunk) ++ ok = yaffs2_checkpt_flush_buffer(dev); ++ } ++ ++ return i; ++} ++ ++int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes) ++{ ++ int i = 0; ++ struct yaffs_ext_tags tags; ++ int chunk; ++ int offset_chunk; ++ u8 *data_bytes = (u8 *) data; ++ ++ if (!dev->checkpt_buffer) ++ return 0; ++ ++ if (dev->checkpt_open_write) ++ return -1; ++ ++ while (i < n_bytes) { ++ ++ if (dev->checkpt_byte_offs < 0 || ++ dev->checkpt_byte_offs >= (int)dev->data_bytes_per_chunk) { ++ ++ if (dev->checkpt_cur_block < 0) { ++ yaffs2_checkpt_find_block(dev); ++ dev->checkpt_cur_chunk = 0; ++ } ++ ++ /* Bail out if we can't find a checpoint block */ ++ if (dev->checkpt_cur_block < 0) ++ break; ++ ++ chunk = dev->checkpt_cur_block * ++ dev->param.chunks_per_block + ++ dev->checkpt_cur_chunk; ++ ++ offset_chunk = apply_chunk_offset(dev, chunk); ++ dev->n_page_reads++; ++ ++ /* Read in the next chunk */ ++ dev->tagger.read_chunk_tags_fn(dev, ++ offset_chunk, ++ dev->checkpt_buffer, ++ &tags); ++ ++ /* Bail out if the chunk is corrupted. */ ++ if (tags.chunk_id != (u32)(dev->checkpt_page_seq + 1) || ++ tags.ecc_result > YAFFS_ECC_RESULT_FIXED || ++ tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA) ++ break; ++ ++ /* Bail out if it is not a checkpoint chunk. */ ++ if(!yaffs2_checkpt_check_chunk_hdr(dev)) ++ break; ++ ++ dev->checkpt_page_seq++; ++ dev->checkpt_cur_chunk++; ++ ++ if (dev->checkpt_cur_chunk >= ++ (int)dev->param.chunks_per_block) ++ dev->checkpt_cur_block = -1; ++ ++ } ++ ++ *data_bytes = dev->checkpt_buffer[dev->checkpt_byte_offs]; ++ dev->checkpt_sum += *data_bytes; ++ dev->checkpt_xor ^= *data_bytes; ++ dev->checkpt_byte_offs++; ++ i++; ++ data_bytes++; ++ dev->checkpt_byte_count++; ++ } ++ ++ return i; /* Number of bytes read */ ++} ++ ++int yaffs_checkpt_close(struct yaffs_dev *dev) ++{ ++ u32 i; ++ ++ if (dev->checkpt_open_write) { ++ if (dev->checkpt_byte_offs != ++ sizeof(struct yaffs_checkpt_chunk_hdr)) ++ yaffs2_checkpt_flush_buffer(dev); ++ } else if (dev->checkpt_block_list) { ++ for (i = 0; ++ i < dev->blocks_in_checkpt && ++ dev->checkpt_block_list[i] >= 0; i++) { ++ int blk = dev->checkpt_block_list[i]; ++ struct yaffs_block_info *bi = NULL; ++ ++ if ((int)dev->internal_start_block <= blk && ++ blk <= (int)dev->internal_end_block) ++ bi = yaffs_get_block_info(dev, blk); ++ if (bi && bi->block_state == YAFFS_BLOCK_STATE_EMPTY) ++ bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT; ++ } ++ } ++ ++ dev->n_free_chunks -= ++ dev->blocks_in_checkpt * dev->param.chunks_per_block; ++ dev->n_erased_blocks -= dev->blocks_in_checkpt; ++ ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, "checkpoint byte count %d", ++ dev->checkpt_byte_count); ++ ++ if (dev->checkpt_buffer) ++ return 1; ++ else ++ return 0; ++} ++ ++int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev) ++{ ++ /* Erase the checkpoint data */ ++ ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "checkpoint invalidate of %d blocks", ++ dev->blocks_in_checkpt); ++ ++ return yaffs_checkpt_erase(dev); ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_checkptrw.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_checkptrw.h.patch new file mode 100644 index 00000000..45eaa519 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_checkptrw.h.patch @@ -0,0 +1,36 @@ +diff -drupN a/fs/yaffs2/yaffs_checkptrw.h b/fs/yaffs2/yaffs_checkptrw.h +--- a/fs/yaffs2/yaffs_checkptrw.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_checkptrw.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,32 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_CHECKPTRW_H__ ++#define __YAFFS_CHECKPTRW_H__ ++ ++#include "yaffs_guts.h" ++ ++int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing); ++ ++int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes); ++ ++int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes); ++ ++int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum); ++ ++int yaffs_checkpt_close(struct yaffs_dev *dev); ++ ++int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev); ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_ecc.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_ecc.c.patch new file mode 100644 index 00000000..10ae8144 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_ecc.c.patch @@ -0,0 +1,284 @@ +diff -drupN a/fs/yaffs2/yaffs_ecc.c b/fs/yaffs2/yaffs_ecc.c +--- a/fs/yaffs2/yaffs_ecc.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_ecc.c 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,280 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * 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 code implements the ECC algorithm used in SmartMedia. ++ * ++ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes. ++ * The two unused bit are set to 1. ++ * The ECC can correct single bit errors in a 256-byte page of data. Thus, two ++ * such ECC blocks are used on a 512-byte NAND page. ++ * ++ */ ++ ++#include "yportenv.h" ++ ++#include "yaffs_ecc.h" ++ ++/* Table generated by gen-ecc.c ++ * Using a table means we do not have to calculate p1..p4 and p1'..p4' ++ * for each byte of data. These are instead provided in a table in bits7..2. ++ * Bit 0 of each entry indicates whether the entry has an odd or even parity, ++ * and therefore this bytes influence on the line parity. ++ */ ++ ++static const unsigned char column_parity_table[] = { ++ 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, ++ 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00, ++ 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, ++ 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95, ++ 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, ++ 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99, ++ 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, ++ 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c, ++ 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, ++ 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5, ++ 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, ++ 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30, ++ 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, ++ 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c, ++ 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, ++ 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9, ++ 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, ++ 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9, ++ 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, ++ 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c, ++ 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, ++ 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30, ++ 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, ++ 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5, ++ 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, ++ 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c, ++ 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, ++ 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99, ++ 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, ++ 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95, ++ 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, ++ 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00, ++}; ++ ++ ++/* Calculate the ECC for a 256-byte block of data */ ++void yaffs_ecc_calc(const unsigned char *data, unsigned char *ecc) ++{ ++ unsigned int i; ++ unsigned char col_parity = 0; ++ unsigned char line_parity = 0; ++ unsigned char line_parity_prime = 0; ++ unsigned char t; ++ unsigned char b; ++ ++ for (i = 0; i < 256; i++) { ++ b = column_parity_table[*data++]; ++ col_parity ^= b; ++ ++ if (b & 0x01) { /* odd number of bits in the byte */ ++ line_parity ^= i; ++ line_parity_prime ^= ~i; ++ } ++ } ++ ++ ecc[2] = (~col_parity) | 0x03; ++ ++ t = 0; ++ if (line_parity & 0x80) ++ t |= 0x80; ++ if (line_parity_prime & 0x80) ++ t |= 0x40; ++ if (line_parity & 0x40) ++ t |= 0x20; ++ if (line_parity_prime & 0x40) ++ t |= 0x10; ++ if (line_parity & 0x20) ++ t |= 0x08; ++ if (line_parity_prime & 0x20) ++ t |= 0x04; ++ if (line_parity & 0x10) ++ t |= 0x02; ++ if (line_parity_prime & 0x10) ++ t |= 0x01; ++ ecc[1] = ~t; ++ ++ t = 0; ++ if (line_parity & 0x08) ++ t |= 0x80; ++ if (line_parity_prime & 0x08) ++ t |= 0x40; ++ if (line_parity & 0x04) ++ t |= 0x20; ++ if (line_parity_prime & 0x04) ++ t |= 0x10; ++ if (line_parity & 0x02) ++ t |= 0x08; ++ if (line_parity_prime & 0x02) ++ t |= 0x04; ++ if (line_parity & 0x01) ++ t |= 0x02; ++ if (line_parity_prime & 0x01) ++ t |= 0x01; ++ ecc[0] = ~t; ++ ++} ++ ++/* Correct the ECC on a 256 byte block of data */ ++ ++int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc, ++ const unsigned char *test_ecc) ++{ ++ unsigned char d0, d1, d2; /* deltas */ ++ ++ d0 = read_ecc[0] ^ test_ecc[0]; ++ d1 = read_ecc[1] ^ test_ecc[1]; ++ d2 = read_ecc[2] ^ test_ecc[2]; ++ ++ if ((d0 | d1 | d2) == 0) ++ return 0; /* no error */ ++ ++ if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 && ++ ((d1 ^ (d1 >> 1)) & 0x55) == 0x55 && ++ ((d2 ^ (d2 >> 1)) & 0x54) == 0x54) { ++ /* Single bit (recoverable) error in data */ ++ ++ unsigned byte; ++ unsigned bit; ++ ++ bit = byte = 0; ++ ++ if (d1 & 0x80) ++ byte |= 0x80; ++ if (d1 & 0x20) ++ byte |= 0x40; ++ if (d1 & 0x08) ++ byte |= 0x20; ++ if (d1 & 0x02) ++ byte |= 0x10; ++ if (d0 & 0x80) ++ byte |= 0x08; ++ if (d0 & 0x20) ++ byte |= 0x04; ++ if (d0 & 0x08) ++ byte |= 0x02; ++ if (d0 & 0x02) ++ byte |= 0x01; ++ ++ if (d2 & 0x80) ++ bit |= 0x04; ++ if (d2 & 0x20) ++ bit |= 0x02; ++ if (d2 & 0x08) ++ bit |= 0x01; ++ ++ data[byte] ^= (1 << bit); ++ ++ return 1; /* Corrected the error */ ++ } ++ ++ if ((hweight8(d0) + hweight8(d1) + hweight8(d2)) == 1) { ++ /* Reccoverable error in ecc */ ++ ++ read_ecc[0] = test_ecc[0]; ++ read_ecc[1] = test_ecc[1]; ++ read_ecc[2] = test_ecc[2]; ++ ++ return 1; /* Corrected the error */ ++ } ++ ++ /* Unrecoverable error */ ++ ++ return -1; ++ ++} ++ ++/* ++ * ECCxxxOther does ECC calcs on arbitrary n bytes of data ++ */ ++void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes, ++ struct yaffs_ecc_other *ecc_other) ++{ ++ unsigned int i; ++ unsigned char col_parity = 0; ++ unsigned line_parity = 0; ++ unsigned line_parity_prime = 0; ++ unsigned char b; ++ ++ for (i = 0; i < n_bytes; i++) { ++ b = column_parity_table[*data++]; ++ col_parity ^= b; ++ ++ if (b & 0x01) { ++ /* odd number of bits in the byte */ ++ line_parity ^= i; ++ line_parity_prime ^= ~i; ++ } ++ ++ } ++ ++ ecc_other->col_parity = (col_parity >> 2) & 0x3f; ++ ecc_other->line_parity = line_parity; ++ ecc_other->line_parity_prime = line_parity_prime; ++} ++ ++int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes, ++ struct yaffs_ecc_other *read_ecc, ++ const struct yaffs_ecc_other *test_ecc) ++{ ++ unsigned char delta_col; /* column parity delta */ ++ unsigned delta_line; /* line parity delta */ ++ unsigned delta_line_prime; /* line parity delta */ ++ unsigned bit; ++ ++ delta_col = read_ecc->col_parity ^ test_ecc->col_parity; ++ delta_line = read_ecc->line_parity ^ test_ecc->line_parity; ++ delta_line_prime = ++ read_ecc->line_parity_prime ^ test_ecc->line_parity_prime; ++ ++ if ((delta_col | delta_line | delta_line_prime) == 0) ++ return 0; /* no error */ ++ ++ if (delta_line == ~delta_line_prime && ++ (((delta_col ^ (delta_col >> 1)) & 0x15) == 0x15)) { ++ /* Single bit (recoverable) error in data */ ++ ++ bit = 0; ++ ++ if (delta_col & 0x20) ++ bit |= 0x04; ++ if (delta_col & 0x08) ++ bit |= 0x02; ++ if (delta_col & 0x02) ++ bit |= 0x01; ++ ++ if (delta_line >= n_bytes) ++ return -1; ++ ++ data[delta_line] ^= (1 << bit); ++ ++ return 1; /* corrected */ ++ } ++ ++ if ((hweight32(delta_line) + ++ hweight32(delta_line_prime) + ++ hweight8(delta_col)) == 1) { ++ /* Reccoverable error in ecc */ ++ ++ *read_ecc = *test_ecc; ++ return 1; /* corrected */ ++ } ++ ++ /* Unrecoverable error */ ++ ++ return -1; ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_ecc.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_ecc.h.patch new file mode 100644 index 00000000..d22c2bc7 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_ecc.h.patch @@ -0,0 +1,47 @@ +diff -drupN a/fs/yaffs2/yaffs_ecc.h b/fs/yaffs2/yaffs_ecc.h +--- a/fs/yaffs2/yaffs_ecc.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_ecc.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,43 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++/* ++ * This code implements the ECC algorithm used in SmartMedia. ++ * ++ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes. ++ * The two unused bit are set to 1. ++ * The ECC can correct single bit errors in a 256-byte page of data. ++ * Thus, two such ECC blocks are used on a 512-byte NAND page. ++ * ++ */ ++ ++#ifndef __YAFFS_ECC_H__ ++#define __YAFFS_ECC_H__ ++ ++struct yaffs_ecc_other { ++ unsigned char col_parity; ++ unsigned line_parity; ++ unsigned line_parity_prime; ++}; ++ ++void yaffs_ecc_calc(const unsigned char *data, unsigned char *ecc); ++int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc, ++ const unsigned char *test_ecc); ++ ++void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes, ++ struct yaffs_ecc_other *ecc); ++int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes, ++ struct yaffs_ecc_other *read_ecc, ++ const struct yaffs_ecc_other *test_ecc); ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_endian.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_endian.c.patch new file mode 100644 index 00000000..fc6173c7 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_endian.c.patch @@ -0,0 +1,109 @@ +diff -drupN a/fs/yaffs2/yaffs_endian.c b/fs/yaffs2/yaffs_endian.c +--- a/fs/yaffs2/yaffs_endian.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_endian.c 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,105 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * 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. ++ * ++ * Endian processing functions. ++ */ ++ ++#include "yaffs_endian.h" ++#include "yaffs_guts.h" ++ ++ ++void yaffs_do_endian_u32(struct yaffs_dev *dev, u32 *val) ++{ ++ if (!dev->swap_endian) ++ return; ++ *val = swap_u32(*val); ++} ++ ++void yaffs_do_endian_s32(struct yaffs_dev *dev, s32 *val) ++{ ++ if (!dev->swap_endian) ++ return; ++ *val = swap_s32(*val); ++} ++ ++void yaffs_do_endian_oh(struct yaffs_dev *dev, struct yaffs_obj_hdr *oh) ++{ ++ if (!dev->swap_endian) ++ return; ++ /* Change every field */ ++ oh->type = swap_u32(oh->type); ++ oh->parent_obj_id = swap_u32(oh->parent_obj_id); ++ ++ oh->yst_mode = swap_u32(oh->yst_mode); ++ ++ oh->yst_uid = swap_u32(oh->yst_uid); ++ oh->yst_gid = swap_u32(oh->yst_gid); ++ oh->yst_atime = swap_u32(oh->yst_atime); ++ oh->yst_mtime = swap_u32(oh->yst_mtime); ++ oh->yst_ctime = swap_u32(oh->yst_ctime); ++ ++ oh->file_size_low = swap_u32(oh->file_size_low); ++ ++ oh->equiv_id = swap_u32(oh->equiv_id); ++ ++ oh->yst_rdev = swap_u32(oh->yst_rdev); ++ ++ oh->win_ctime[0] = swap_u32(oh->win_ctime[0]); ++ oh->win_ctime[1] = swap_u32(oh->win_ctime[1]); ++ oh->win_atime[0] = swap_u32(oh->win_atime[0]); ++ oh->win_atime[1] = swap_u32(oh->win_atime[1]); ++ oh->win_mtime[0] = swap_u32(oh->win_mtime[0]); ++ oh->win_mtime[1] = swap_u32(oh->win_mtime[1]); ++ ++ oh->inband_shadowed_obj_id = swap_u32(oh->inband_shadowed_obj_id); ++ oh->inband_is_shrink = swap_u32(oh->inband_is_shrink); ++ ++ oh->file_size_high = swap_u32(oh->file_size_high); ++ oh->reserved[0] = swap_u32(oh->reserved[0]); ++ oh->shadows_obj = swap_s32(oh->shadows_obj); ++ ++ oh->is_shrink = swap_u32(oh->is_shrink); ++} ++ ++ ++void yaffs_do_endian_packed_tags2(struct yaffs_dev *dev, ++ struct yaffs_packed_tags2_tags_only *ptt) ++{ ++ if (!dev->swap_endian) ++ return; ++ ptt->seq_number = swap_u32(ptt->seq_number); ++ ptt->obj_id = swap_u32(ptt->obj_id); ++ ptt->chunk_id = swap_u32(ptt->chunk_id); ++ ptt->n_bytes = swap_u32(ptt->n_bytes); ++} ++ ++void yaffs_endian_config(struct yaffs_dev *dev) ++{ ++ u32 x = 1; ++ ++ if (dev->tnode_size < 1) ++ BUG(); ++ ++ dev->swap_endian = 0; ++ ++ if (((char *)&x)[0] == 1) { ++ /* Little Endian. */ ++ if (dev->param.stored_endian == 2 /* big endian */) ++ dev->swap_endian = 1; ++ } else { ++ /* Big Endian. */ ++ if (dev->param.stored_endian == 1 /* little endian */) ++ dev->swap_endian = 1; ++ } ++ ++ if (dev->swap_endian) ++ dev->tn_swap_buffer = kmalloc(dev->tnode_size, GFP_NOFS); ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_endian.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_endian.h.patch new file mode 100644 index 00000000..19ed3776 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_endian.h.patch @@ -0,0 +1,58 @@ +diff -drupN a/fs/yaffs2/yaffs_endian.h b/fs/yaffs2/yaffs_endian.h +--- a/fs/yaffs2/yaffs_endian.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_endian.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,54 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_ENDIAN_H__ ++#define __YAFFS_ENDIAN_H__ ++#include "yaffs_guts.h" ++#include "yaffs_packedtags2.h" ++ ++static inline u32 swap_u32(u32 val) ++{ ++ return ((val >>24) & 0x000000ff) | ++ ((val >> 8) & 0x0000ff00) | ++ ((val << 8) & 0x00ff0000) | ++ ((val <<24) & 0xff000000); ++} ++ ++#define swap_s32(val) \ ++ (s32)(swap_u32((u32)(val))) ++ ++static inline loff_t swap_loff_t(loff_t lval) ++{ ++ u32 vall = swap_u32(FSIZE_LOW(lval)); ++ u32 valh; ++ ++ if (sizeof(loff_t) == sizeof(u32)) ++ return (loff_t) vall; ++ ++ valh = swap_u32(FSIZE_HIGH(lval)); ++ ++ return FSIZE_COMBINE(vall, valh); /*NB: h and l are swapped. */ ++} ++ ++ ++ ++struct yaffs_dev; ++void yaffs_do_endian_s32(struct yaffs_dev *dev, s32 *val); ++void yaffs_do_endian_u32(struct yaffs_dev *dev, u32 *val); ++void yaffs_do_endian_oh(struct yaffs_dev *dev, struct yaffs_obj_hdr *oh); ++void yaffs_do_endian_packed_tags2(struct yaffs_dev *dev, ++ struct yaffs_packed_tags2_tags_only *ptt); ++void yaffs_endian_config(struct yaffs_dev *dev); ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_getblockinfo.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_getblockinfo.h.patch new file mode 100644 index 00000000..7eb605df --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_getblockinfo.h.patch @@ -0,0 +1,39 @@ +diff -drupN a/fs/yaffs2/yaffs_getblockinfo.h b/fs/yaffs2/yaffs_getblockinfo.h +--- a/fs/yaffs2/yaffs_getblockinfo.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_getblockinfo.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,35 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_GETBLOCKINFO_H__ ++#define __YAFFS_GETBLOCKINFO_H__ ++ ++#include "yaffs_guts.h" ++#include "yaffs_trace.h" ++ ++/* Function to manipulate block info */ ++static inline struct yaffs_block_info *yaffs_get_block_info(struct yaffs_dev ++ *dev, int blk) ++{ ++ if (blk < (int)dev->internal_start_block || ++ blk > (int)dev->internal_end_block) { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "**>> yaffs: get_block_info block %d is not valid", ++ blk); ++ BUG(); ++ } ++ return &dev->block_info[blk - dev->internal_start_block]; ++} ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_guts.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_guts.c.patch new file mode 100644 index 00000000..f21e13ad --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_guts.c.patch @@ -0,0 +1,4954 @@ +diff -drupN a/fs/yaffs2/yaffs_guts.c b/fs/yaffs2/yaffs_guts.c +--- a/fs/yaffs2/yaffs_guts.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_guts.c 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,4950 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * 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. ++ */ ++ ++#include "yportenv.h" ++#include "yaffs_trace.h" ++ ++#include "yaffs_guts.h" ++ ++#include "yaffs_cache.h" ++#include "yaffs_endian.h" ++#include "yaffs_getblockinfo.h" ++#include "yaffs_tagscompat.h" ++#include "yaffs_tagsmarshall.h" ++#include "yaffs_nand.h" ++#include "yaffs_yaffs1.h" ++#include "yaffs_yaffs2.h" ++#include "yaffs_bitmap.h" ++#include "yaffs_verify.h" ++#include "yaffs_nand.h" ++#include "yaffs_packedtags2.h" ++#include "yaffs_nameval.h" ++#include "yaffs_allocator.h" ++#include "yaffs_attribs.h" ++#include "yaffs_summary.h" ++ ++/* Note YAFFS_GC_GOOD_ENOUGH must be <= YAFFS_GC_PASSIVE_THRESHOLD */ ++#define YAFFS_GC_GOOD_ENOUGH 2 ++#define YAFFS_GC_PASSIVE_THRESHOLD 4 ++ ++#include "yaffs_ecc.h" ++ ++/* Forward declarations */ ++ ++static void yaffs_fix_null_name(struct yaffs_obj *obj, YCHAR *name, ++ int buffer_size); ++ ++/* Function to calculate chunk and offset */ ++ ++void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr, ++ int *chunk_out, u32 *offset_out) ++{ ++ int chunk; ++ u32 offset; ++ ++ chunk = (u32) (addr >> dev->chunk_shift); ++ ++ if (dev->chunk_div == 1) { ++ /* easy power of 2 case */ ++ offset = (u32) (addr & dev->chunk_mask); ++ } else { ++ /* Non power-of-2 case */ ++ ++ loff_t chunk_base; ++ ++ chunk /= dev->chunk_div; ++ ++ chunk_base = ((loff_t) chunk) * dev->data_bytes_per_chunk; ++ offset = (u32) (addr - chunk_base); ++ } ++ ++ *chunk_out = chunk; ++ *offset_out = offset; ++} ++ ++/* Function to return the number of shifts for a power of 2 greater than or ++ * equal to the given number ++ * Note we don't try to cater for all possible numbers and this does not have to ++ * be hellishly efficient. ++ */ ++ ++static inline u32 calc_shifts_ceiling(u32 x) ++{ ++ int extra_bits; ++ int shifts; ++ ++ shifts = extra_bits = 0; ++ ++ while (x > 1) { ++ if (x & 1) ++ extra_bits++; ++ x >>= 1; ++ shifts++; ++ } ++ ++ if (extra_bits) ++ shifts++; ++ ++ return shifts; ++} ++ ++/* Function to return the number of shifts to get a 1 in bit 0 ++ */ ++ ++static inline u32 calc_shifts(u32 x) ++{ ++ u32 shifts; ++ ++ shifts = 0; ++ ++ if (!x) ++ return 0; ++ ++ while (!(x & 1)) { ++ x >>= 1; ++ shifts++; ++ } ++ ++ return shifts; ++} ++ ++/* ++ * Temporary buffer manipulations. ++ */ ++ ++static int yaffs_init_tmp_buffers(struct yaffs_dev *dev) ++{ ++ int i; ++ u8 *buf = (u8 *) 1; ++ ++ memset(dev->temp_buffer, 0, sizeof(dev->temp_buffer)); ++ ++ for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) { ++ dev->temp_buffer[i].in_use = 0; ++ buf = kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS); ++ dev->temp_buffer[i].buffer = buf; ++ } ++ ++ return buf ? YAFFS_OK : YAFFS_FAIL; ++} ++ ++u8 *yaffs_get_temp_buffer(struct yaffs_dev * dev) ++{ ++ int i; ++ ++ dev->temp_in_use++; ++ if (dev->temp_in_use > dev->max_temp) ++ dev->max_temp = dev->temp_in_use; ++ ++ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { ++ if (dev->temp_buffer[i].in_use == 0) { ++ dev->temp_buffer[i].in_use = 1; ++ return dev->temp_buffer[i].buffer; ++ } ++ } ++ ++ yaffs_trace(YAFFS_TRACE_BUFFERS, "Out of temp buffers"); ++ /* ++ * If we got here then we have to allocate an unmanaged one ++ * This is not good. ++ */ ++ ++ dev->unmanaged_buffer_allocs++; ++ return kmalloc(dev->data_bytes_per_chunk, GFP_NOFS); ++ ++} ++ ++void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 *buffer) ++{ ++ int i; ++ ++ dev->temp_in_use--; ++ ++ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { ++ if (dev->temp_buffer[i].buffer == buffer) { ++ dev->temp_buffer[i].in_use = 0; ++ return; ++ } ++ } ++ ++ if (buffer) { ++ /* assume it is an unmanaged one. */ ++ yaffs_trace(YAFFS_TRACE_BUFFERS, ++ "Releasing unmanaged temp buffer"); ++ kfree(buffer); ++ dev->unmanaged_buffer_deallocs++; ++ } ++ ++} ++ ++/* ++ * Functions for robustisizing TODO ++ * ++ */ ++ ++static void yaffs_handle_chunk_wr_ok(struct yaffs_dev *dev, int nand_chunk, ++ const u8 *data, ++ const struct yaffs_ext_tags *tags) ++{ ++ (void) dev; ++ (void) nand_chunk; ++ (void) data; ++ (void) tags; ++} ++ ++static void yaffs_handle_chunk_update(struct yaffs_dev *dev, int nand_chunk, ++ const struct yaffs_ext_tags *tags) ++{ ++ (void) dev; ++ (void) nand_chunk; ++ (void) tags; ++} ++ ++void yaffs_handle_chunk_error(struct yaffs_dev *dev, ++ struct yaffs_block_info *bi) ++{ ++ if (!bi->gc_prioritise) { ++ bi->gc_prioritise = 1; ++ dev->has_pending_prioritised_gc = 1; ++ bi->chunk_error_strikes++; ++ ++ if (bi->chunk_error_strikes > 3) { ++ bi->needs_retiring = 1; /* Too many stikes, so retire */ ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "yaffs: Block struck out"); ++ ++ } ++ } ++} ++ ++static void yaffs_handle_chunk_wr_error(struct yaffs_dev *dev, int nand_chunk, ++ int erased_ok) ++{ ++ int flash_block = nand_chunk / dev->param.chunks_per_block; ++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block); ++ ++ yaffs_handle_chunk_error(dev, bi); ++ ++ if (erased_ok) { ++ /* Was an actual write failure, ++ * so mark the block for retirement.*/ ++ bi->needs_retiring = 1; ++ yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, ++ "**>> Block %d needs retiring", flash_block); ++ } ++ ++ /* Delete the chunk */ ++ yaffs_chunk_del(dev, nand_chunk, 1, __LINE__); ++ yaffs_skip_rest_of_block(dev); ++} ++ ++/* ++ * Verification code ++ */ ++ ++/* ++ * Simple hash function. Needs to have a reasonable spread ++ */ ++ ++static inline int yaffs_hash_fn(int n) ++{ ++ if (n < 0) ++ n = -n; ++ return n % YAFFS_NOBJECT_BUCKETS; ++} ++ ++/* ++ * Access functions to useful fake objects. ++ * Note that root might have a presence in NAND if permissions are set. ++ */ ++ ++struct yaffs_obj *yaffs_root(struct yaffs_dev *dev) ++{ ++ return dev->root_dir; ++} ++ ++struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev) ++{ ++ return dev->lost_n_found; ++} ++ ++/* ++ * Erased NAND checking functions ++ */ ++ ++int yaffs_check_ff(u8 *buffer, int n_bytes) ++{ ++ /* Horrible, slow implementation */ ++ while (n_bytes--) { ++ if (*buffer != 0xff) ++ return 0; ++ buffer++; ++ } ++ return 1; ++} ++ ++static int yaffs_check_chunk_erased(struct yaffs_dev *dev, int nand_chunk) ++{ ++ int retval = YAFFS_OK; ++ u8 *data = yaffs_get_temp_buffer(dev); ++ struct yaffs_ext_tags tags; ++ int result; ++ ++ result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, data, &tags); ++ ++ if (result == YAFFS_FAIL || ++ tags.ecc_result > YAFFS_ECC_RESULT_NO_ERROR) ++ retval = YAFFS_FAIL; ++ ++ if (!yaffs_check_ff(data, dev->data_bytes_per_chunk) || ++ tags.chunk_used) { ++ yaffs_trace(YAFFS_TRACE_NANDACCESS, ++ "Chunk %d not erased", nand_chunk); ++ retval = YAFFS_FAIL; ++ } ++ ++ yaffs_release_temp_buffer(dev, data); ++ ++ return retval; ++ ++} ++ ++static int yaffs_verify_chunk_written(struct yaffs_dev *dev, ++ int nand_chunk, ++ const u8 *data, ++ struct yaffs_ext_tags *tags) ++{ ++ int retval = YAFFS_OK; ++ struct yaffs_ext_tags temp_tags; ++ u8 *buffer = yaffs_get_temp_buffer(dev); ++ int result; ++ ++ result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, buffer, &temp_tags); ++ if (result == YAFFS_FAIL || ++ memcmp(buffer, data, dev->data_bytes_per_chunk) || ++ temp_tags.obj_id != tags->obj_id || ++ temp_tags.chunk_id != tags->chunk_id || ++ temp_tags.n_bytes != tags->n_bytes) ++ retval = YAFFS_FAIL; ++ ++ yaffs_release_temp_buffer(dev, buffer); ++ ++ return retval; ++} ++ ++ ++int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks) ++{ ++ int reserved_chunks; ++ int reserved_blocks = dev->param.n_reserved_blocks; ++ int checkpt_blocks; ++ ++ checkpt_blocks = yaffs_calc_checkpt_blocks_required(dev); ++ ++ reserved_chunks = ++ (reserved_blocks + checkpt_blocks) * dev->param.chunks_per_block; ++ ++ return (dev->n_free_chunks > (reserved_chunks + n_chunks)); ++} ++ ++static int yaffs_find_alloc_block(struct yaffs_dev *dev) ++{ ++ u32 i; ++ struct yaffs_block_info *bi; ++ ++ if (dev->n_erased_blocks < 1) { ++ /* Hoosterman we've got a problem. ++ * Can't get space to gc ++ */ ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "yaffs tragedy: no more erased blocks"); ++ ++ return -1; ++ } ++ ++ /* Find an empty block. */ ++ ++ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { ++ dev->alloc_block_finder++; ++ if (dev->alloc_block_finder < (int)dev->internal_start_block ++ || dev->alloc_block_finder > (int)dev->internal_end_block) { ++ dev->alloc_block_finder = dev->internal_start_block; ++ } ++ ++ bi = yaffs_get_block_info(dev, dev->alloc_block_finder); ++ ++ if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) { ++ bi->block_state = YAFFS_BLOCK_STATE_ALLOCATING; ++ dev->seq_number++; ++ bi->seq_number = dev->seq_number; ++ dev->n_erased_blocks--; ++ yaffs_trace(YAFFS_TRACE_ALLOCATE, ++ "Allocated block %d, seq %d, %d left" , ++ dev->alloc_block_finder, dev->seq_number, ++ dev->n_erased_blocks); ++ return dev->alloc_block_finder; ++ } ++ } ++ ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "yaffs tragedy: no more erased blocks, but there should have been %d", ++ dev->n_erased_blocks); ++ ++ return -1; ++} ++ ++static int yaffs_alloc_chunk(struct yaffs_dev *dev, int use_reserver, ++ struct yaffs_block_info **block_ptr) ++{ ++ int ret_val; ++ struct yaffs_block_info *bi; ++ ++ if (dev->alloc_block < 0) { ++ /* Get next block to allocate off */ ++ dev->alloc_block = yaffs_find_alloc_block(dev); ++ dev->alloc_page = 0; ++ } ++ ++ if (!use_reserver && !yaffs_check_alloc_available(dev, 1)) { ++ /* No space unless we're allowed to use the reserve. */ ++ return -1; ++ } ++ ++ if (dev->n_erased_blocks < (int)dev->param.n_reserved_blocks ++ && dev->alloc_page == 0) ++ yaffs_trace(YAFFS_TRACE_ALLOCATE, "Allocating reserve"); ++ ++ /* Next page please.... */ ++ if (dev->alloc_block >= 0) { ++ bi = yaffs_get_block_info(dev, dev->alloc_block); ++ ++ ret_val = (dev->alloc_block * dev->param.chunks_per_block) + ++ dev->alloc_page; ++ bi->pages_in_use++; ++ yaffs_set_chunk_bit(dev, dev->alloc_block, dev->alloc_page); ++ ++ dev->alloc_page++; ++ ++ dev->n_free_chunks--; ++ ++ /* If the block is full set the state to full */ ++ if (dev->alloc_page >= dev->param.chunks_per_block) { ++ bi->block_state = YAFFS_BLOCK_STATE_FULL; ++ dev->alloc_block = -1; ++ } ++ ++ if (block_ptr) ++ *block_ptr = bi; ++ ++ return ret_val; ++ } ++ ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!"); ++ ++ return -1; ++} ++ ++static int yaffs_get_erased_chunks(struct yaffs_dev *dev) ++{ ++ int n; ++ ++ n = dev->n_erased_blocks * dev->param.chunks_per_block; ++ ++ if (dev->alloc_block > 0) ++ n += (dev->param.chunks_per_block - dev->alloc_page); ++ ++ return n; ++ ++} ++ ++/* ++ * yaffs_skip_rest_of_block() skips over the rest of the allocation block ++ * if we don't want to write to it. ++ */ ++void yaffs_skip_rest_of_block(struct yaffs_dev *dev) ++{ ++ struct yaffs_block_info *bi; ++ ++ if (dev->alloc_block > 0) { ++ bi = yaffs_get_block_info(dev, dev->alloc_block); ++ if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING) { ++ bi->block_state = YAFFS_BLOCK_STATE_FULL; ++ dev->alloc_block = -1; ++ } ++ } ++} ++ ++static int yaffs_write_new_chunk(struct yaffs_dev *dev, ++ const u8 *data, ++ struct yaffs_ext_tags *tags, int use_reserver) ++{ ++ u32 attempts = 0; ++ int write_ok = 0; ++ int chunk; ++ ++ yaffs2_checkpt_invalidate(dev); ++ ++ do { ++ struct yaffs_block_info *bi = 0; ++ int erased_ok = 0; ++ ++ chunk = yaffs_alloc_chunk(dev, use_reserver, &bi); ++ if (chunk < 0) { ++ /* no space */ ++ break; ++ } ++ ++ /* First check this chunk is erased, if it needs ++ * checking. The checking policy (unless forced ++ * always on) is as follows: ++ * ++ * Check the first page we try to write in a block. ++ * If the check passes then we don't need to check any ++ * more. If the check fails, we check again... ++ * If the block has been erased, we don't need to check. ++ * ++ * However, if the block has been prioritised for gc, ++ * then we think there might be something odd about ++ * this block and stop using it. ++ * ++ * Rationale: We should only ever see chunks that have ++ * not been erased if there was a partially written ++ * chunk due to power loss. This checking policy should ++ * catch that case with very few checks and thus save a ++ * lot of checks that are most likely not needed. ++ * ++ * Mods to the above ++ * If an erase check fails or the write fails we skip the ++ * rest of the block. ++ */ ++ ++ /* let's give it a try */ ++ attempts++; ++ ++ if (dev->param.always_check_erased) ++ bi->skip_erased_check = 0; ++ ++ if (!bi->skip_erased_check) { ++ erased_ok = yaffs_check_chunk_erased(dev, chunk); ++ if (erased_ok != YAFFS_OK) { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "**>> yaffs chunk %d was not erased", ++ chunk); ++ ++ /* If not erased, delete this one, ++ * skip rest of block and ++ * try another chunk */ ++ yaffs_chunk_del(dev, chunk, 1, __LINE__); ++ yaffs_skip_rest_of_block(dev); ++ continue; ++ } ++ } ++ ++ write_ok = yaffs_wr_chunk_tags_nand(dev, chunk, data, tags); ++ ++ if (!bi->skip_erased_check) ++ write_ok = ++ yaffs_verify_chunk_written(dev, chunk, data, tags); ++ ++ if (write_ok != YAFFS_OK) { ++ /* Clean up aborted write, skip to next block and ++ * try another chunk */ ++ yaffs_handle_chunk_wr_error(dev, chunk, erased_ok); ++ continue; ++ } ++ ++ bi->skip_erased_check = 1; ++ ++ /* Copy the data into the robustification buffer */ ++ yaffs_handle_chunk_wr_ok(dev, chunk, data, tags); ++ ++ } while (write_ok != YAFFS_OK && ++ (yaffs_wr_attempts == 0 || attempts <= yaffs_wr_attempts)); ++ ++ if (!write_ok) ++ chunk = -1; ++ ++ if (attempts > 1) { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "**>> yaffs write required %d attempts", ++ attempts); ++ dev->n_retried_writes += (attempts - 1); ++ } ++ ++ return chunk; ++} ++ ++/* ++ * Block retiring for handling a broken block. ++ */ ++ ++static void yaffs_retire_block(struct yaffs_dev *dev, int flash_block) ++{ ++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block); ++ ++ yaffs2_checkpt_invalidate(dev); ++ ++ yaffs2_clear_oldest_dirty_seq(dev, bi); ++ ++ if (yaffs_mark_bad(dev, flash_block) != YAFFS_OK) { ++ if (yaffs_erase_block(dev, flash_block) != YAFFS_OK) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "yaffs: Failed to mark bad and erase block %d", ++ flash_block); ++ } else { ++ struct yaffs_ext_tags tags; ++ int chunk_id = ++ flash_block * dev->param.chunks_per_block; ++ ++ u8 *buffer = yaffs_get_temp_buffer(dev); ++ ++ memset(buffer, 0xff, dev->data_bytes_per_chunk); ++ memset(&tags, 0, sizeof(tags)); ++ tags.seq_number = YAFFS_SEQUENCE_BAD_BLOCK; ++ if (dev->tagger.write_chunk_tags_fn(dev, chunk_id - ++ dev->chunk_offset, ++ buffer, ++ &tags) != YAFFS_OK) ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "yaffs: Failed to write bad block marker to block %d", ++ flash_block); ++ ++ yaffs_release_temp_buffer(dev, buffer); ++ } ++ } ++ ++ bi->block_state = YAFFS_BLOCK_STATE_DEAD; ++ bi->gc_prioritise = 0; ++ bi->needs_retiring = 0; ++ ++ dev->n_retired_blocks++; ++} ++ ++/*---------------- Name handling functions ------------*/ ++ ++static void yaffs_load_name_from_oh(struct yaffs_dev *dev, YCHAR *name, ++ const YCHAR *oh_name, int buff_size) ++{ ++#ifdef CONFIG_YAFFS_AUTO_UNICODE ++ if (dev->param.auto_unicode) { ++ if (*oh_name) { ++ /* It is an ASCII name, do an ASCII to ++ * unicode conversion */ ++ const char *ascii_oh_name = (const char *)oh_name; ++ int n = buff_size - 1; ++ while (n > 0 && *ascii_oh_name) { ++ *name = *ascii_oh_name; ++ name++; ++ ascii_oh_name++; ++ n--; ++ } ++ } else { ++ strncpy(name, oh_name + 1, buff_size - 1); ++ } ++ } else { ++#else ++ (void) dev; ++ { ++#endif ++ strncpy(name, oh_name, buff_size - 1); ++ } ++} ++ ++static void yaffs_load_oh_from_name(struct yaffs_dev *dev, YCHAR *oh_name, ++ const YCHAR *name) ++{ ++#ifdef CONFIG_YAFFS_AUTO_UNICODE ++ ++ int is_ascii; ++ const YCHAR *w; ++ ++ if (dev->param.auto_unicode) { ++ ++ is_ascii = 1; ++ w = name; ++ ++ /* Figure out if the name will fit in ascii character set */ ++ while (is_ascii && *w) { ++ if ((*w) & 0xff00) ++ is_ascii = 0; ++ w++; ++ } ++ ++ if (is_ascii) { ++ /* It is an ASCII name, so convert unicode to ascii */ ++ char *ascii_oh_name = (char *)oh_name; ++ int n = YAFFS_MAX_NAME_LENGTH - 1; ++ while (n > 0 && *name) { ++ *ascii_oh_name = *name; ++ name++; ++ ascii_oh_name++; ++ n--; ++ } ++ } else { ++ /* Unicode name, so save starting at the second YCHAR */ ++ *oh_name = 0; ++ strncpy(oh_name + 1, name, YAFFS_MAX_NAME_LENGTH - 2); ++ } ++ } else { ++#else ++ dev = dev; ++ { ++#endif ++ strncpy(oh_name, name, YAFFS_MAX_NAME_LENGTH - 1); ++ } ++} ++ ++static u16 yaffs_calc_name_sum(const YCHAR *name) ++{ ++ u16 sum = 0; ++ u16 i = 1; ++ ++ if (!name) ++ return 0; ++ ++ while ((*name) && i < (YAFFS_MAX_NAME_LENGTH / 2)) { ++ ++ /* 0x1f mask is case insensitive */ ++ sum += ((*name) & 0x1f) * i; ++ i++; ++ name++; ++ } ++ return sum; ++} ++ ++ ++void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR * name) ++{ ++ memset(obj->short_name, 0, sizeof(obj->short_name)); ++ ++ if (name && !name[0]) { ++ yaffs_fix_null_name(obj, obj->short_name, ++ YAFFS_SHORT_NAME_LENGTH); ++ name = obj->short_name; ++ } else if (name && ++ strnlen(name, YAFFS_SHORT_NAME_LENGTH + 1) <= ++ YAFFS_SHORT_NAME_LENGTH) { ++ strcpy(obj->short_name, name); ++ } ++ ++ obj->sum = yaffs_calc_name_sum(name); ++} ++ ++void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj, ++ const struct yaffs_obj_hdr *oh) ++{ ++#ifdef CONFIG_YAFFS_AUTO_UNICODE ++ YCHAR tmp_name[YAFFS_MAX_NAME_LENGTH + 1]; ++ memset(tmp_name, 0, sizeof(tmp_name)); ++ yaffs_load_name_from_oh(obj->my_dev, tmp_name, oh->name, ++ YAFFS_MAX_NAME_LENGTH + 1); ++ yaffs_set_obj_name(obj, tmp_name); ++#else ++ yaffs_set_obj_name(obj, oh->name); ++#endif ++} ++ ++loff_t yaffs_max_file_size(struct yaffs_dev *dev) ++{ ++ if (sizeof(loff_t) < 8) ++ return YAFFS_MAX_FILE_SIZE_32; ++ else ++ return ((loff_t) YAFFS_MAX_CHUNK_ID) * dev->data_bytes_per_chunk; ++} ++ ++/*-------------------- TNODES ------------------- ++ ++ * List of spare tnodes ++ * The list is hooked together using the first pointer ++ * in the tnode. ++ */ ++ ++struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev) ++{ ++ struct yaffs_tnode *tn = yaffs_alloc_raw_tnode(dev); ++ ++ if (tn) { ++ memset(tn, 0, dev->tnode_size); ++ dev->n_tnodes++; ++ } ++ ++ dev->checkpoint_blocks_required = 0; /* force recalculation */ ++ ++ return tn; ++} ++ ++/* FreeTnode frees up a tnode and puts it back on the free list */ ++static void yaffs_free_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn) ++{ ++ yaffs_free_raw_tnode(dev, tn); ++ dev->n_tnodes--; ++ dev->checkpoint_blocks_required = 0; /* force recalculation */ ++} ++ ++static void yaffs_deinit_tnodes_and_objs(struct yaffs_dev *dev) ++{ ++ yaffs_deinit_raw_tnodes_and_objs(dev); ++ dev->n_obj = 0; ++ dev->n_tnodes = 0; ++} ++ ++static void yaffs_load_tnode_0(struct yaffs_dev *dev, struct yaffs_tnode *tn, ++ unsigned pos, unsigned val) ++{ ++ u32 *map = (u32 *) tn; ++ u32 bit_in_map; ++ u32 bit_in_word; ++ u32 word_in_map; ++ u32 mask; ++ ++ pos &= YAFFS_TNODES_LEVEL0_MASK; ++ val >>= dev->chunk_grp_bits; ++ ++ bit_in_map = pos * dev->tnode_width; ++ word_in_map = bit_in_map / 32; ++ bit_in_word = bit_in_map & (32 - 1); ++ ++ mask = dev->tnode_mask << bit_in_word; ++ ++ map[word_in_map] &= ~mask; ++ map[word_in_map] |= (mask & (val << bit_in_word)); ++ ++ if (dev->tnode_width > (32 - bit_in_word)) { ++ bit_in_word = (32 - bit_in_word); ++ word_in_map++; ++ mask = ++ dev->tnode_mask >> bit_in_word; ++ map[word_in_map] &= ~mask; ++ map[word_in_map] |= (mask & (val >> bit_in_word)); ++ } ++} ++ ++u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn, ++ unsigned pos) ++{ ++ u32 *map = (u32 *) tn; ++ u32 bit_in_map; ++ u32 bit_in_word; ++ u32 word_in_map; ++ u32 val; ++ ++ pos &= YAFFS_TNODES_LEVEL0_MASK; ++ ++ bit_in_map = pos * dev->tnode_width; ++ word_in_map = bit_in_map / 32; ++ bit_in_word = bit_in_map & (32 - 1); ++ ++ val = map[word_in_map] >> bit_in_word; ++ ++ if (dev->tnode_width > (32 - bit_in_word)) { ++ bit_in_word = (32 - bit_in_word); ++ word_in_map++; ++ val |= (map[word_in_map] << bit_in_word); ++ } ++ ++ val &= dev->tnode_mask; ++ val <<= dev->chunk_grp_bits; ++ ++ return val; ++} ++ ++/* ------------------- End of individual tnode manipulation -----------------*/ ++ ++/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------ ++ * The look up tree is represented by the top tnode and the number of top_level ++ * in the tree. 0 means only the level 0 tnode is in the tree. ++ */ ++ ++/* FindLevel0Tnode finds the level 0 tnode, if one exists. */ ++struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev, ++ struct yaffs_file_var *file_struct, ++ u32 chunk_id) ++{ ++ struct yaffs_tnode *tn = file_struct->top; ++ u32 i; ++ int required_depth; ++ int level = file_struct->top_level; ++ ++ (void) dev; ++ ++ /* Check sane level and chunk Id */ ++ if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL) ++ return NULL; ++ ++ if (chunk_id > YAFFS_MAX_CHUNK_ID) ++ return NULL; ++ ++ /* First check we're tall enough (ie enough top_level) */ ++ ++ i = chunk_id >> YAFFS_TNODES_LEVEL0_BITS; ++ required_depth = 0; ++ while (i) { ++ i >>= YAFFS_TNODES_INTERNAL_BITS; ++ required_depth++; ++ } ++ ++ if (required_depth > file_struct->top_level) ++ return NULL; /* Not tall enough, so we can't find it */ ++ ++ /* Traverse down to level 0 */ ++ while (level > 0 && tn) { ++ tn = tn->internal[(chunk_id >> ++ (YAFFS_TNODES_LEVEL0_BITS + ++ (level - 1) * ++ YAFFS_TNODES_INTERNAL_BITS)) & ++ YAFFS_TNODES_INTERNAL_MASK]; ++ level--; ++ } ++ ++ return tn; ++} ++ ++/* add_find_tnode_0 finds the level 0 tnode if it exists, ++ * otherwise first expands the tree. ++ * This happens in two steps: ++ * 1. If the tree isn't tall enough, then make it taller. ++ * 2. Scan down the tree towards the level 0 tnode adding tnodes if required. ++ * ++ * Used when modifying the tree. ++ * ++ * If the tn argument is NULL, then a fresh tnode will be added otherwise the ++ * specified tn will be plugged into the ttree. ++ */ ++ ++struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev, ++ struct yaffs_file_var *file_struct, ++ u32 chunk_id, ++ struct yaffs_tnode *passed_tn) ++{ ++ int required_depth; ++ int i; ++ int l; ++ struct yaffs_tnode *tn; ++ u32 x; ++ ++ /* Check sane level and page Id */ ++ if (file_struct->top_level < 0 || ++ file_struct->top_level > YAFFS_TNODES_MAX_LEVEL) ++ return NULL; ++ ++ if (chunk_id > YAFFS_MAX_CHUNK_ID) ++ return NULL; ++ ++ /* First check we're tall enough (ie enough top_level) */ ++ ++ x = chunk_id >> YAFFS_TNODES_LEVEL0_BITS; ++ required_depth = 0; ++ while (x) { ++ x >>= YAFFS_TNODES_INTERNAL_BITS; ++ required_depth++; ++ } ++ ++ if (required_depth > file_struct->top_level) { ++ /* Not tall enough, gotta make the tree taller */ ++ for (i = file_struct->top_level; i < required_depth; i++) { ++ ++ tn = yaffs_get_tnode(dev); ++ ++ if (tn) { ++ tn->internal[0] = file_struct->top; ++ file_struct->top = tn; ++ file_struct->top_level++; ++ } else { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "yaffs: no more tnodes"); ++ return NULL; ++ } ++ } ++ } ++ ++ /* Traverse down to level 0, adding anything we need */ ++ ++ l = file_struct->top_level; ++ tn = file_struct->top; ++ ++ if (l > 0) { ++ while (l > 0 && tn) { ++ x = (chunk_id >> ++ (YAFFS_TNODES_LEVEL0_BITS + ++ (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) & ++ YAFFS_TNODES_INTERNAL_MASK; ++ ++ if ((l > 1) && !tn->internal[x]) { ++ /* Add missing non-level-zero tnode */ ++ tn->internal[x] = yaffs_get_tnode(dev); ++ if (!tn->internal[x]) ++ return NULL; ++ } else if (l == 1) { ++ /* Looking from level 1 at level 0 */ ++ if (passed_tn) { ++ /* If we already have one, release it */ ++ if (tn->internal[x]) ++ yaffs_free_tnode(dev, ++ tn->internal[x]); ++ tn->internal[x] = passed_tn; ++ ++ } else if (!tn->internal[x]) { ++ /* Don't have one, none passed in */ ++ tn->internal[x] = yaffs_get_tnode(dev); ++ if (!tn->internal[x]) ++ return NULL; ++ } ++ } ++ ++ tn = tn->internal[x]; ++ l--; ++ } ++ } else { ++ /* top is level 0 */ ++ if (passed_tn) { ++ memcpy(tn, passed_tn, ++ (dev->tnode_width * YAFFS_NTNODES_LEVEL0) / 8); ++ yaffs_free_tnode(dev, passed_tn); ++ } ++ } ++ ++ return tn; ++} ++ ++static int yaffs_tags_match(const struct yaffs_ext_tags *tags, int obj_id, ++ int chunk_obj) ++{ ++ return (tags->chunk_id == (u32)chunk_obj && ++ tags->obj_id == (u32)obj_id && ++ !tags->is_deleted) ? 1 : 0; ++ ++} ++ ++static int yaffs_find_chunk_in_group(struct yaffs_dev *dev, int the_chunk, ++ struct yaffs_ext_tags *tags, int obj_id, ++ int inode_chunk) ++{ ++ int j; ++ ++ for (j = 0; the_chunk && j < dev->chunk_grp_size; j++) { ++ if (yaffs_check_chunk_bit ++ (dev, the_chunk / dev->param.chunks_per_block, ++ the_chunk % dev->param.chunks_per_block)) { ++ ++ if (dev->chunk_grp_size == 1) ++ return the_chunk; ++ else { ++ yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL, ++ tags); ++ if (yaffs_tags_match(tags, ++ obj_id, inode_chunk)) { ++ /* found it; */ ++ return the_chunk; ++ } ++ } ++ } ++ the_chunk++; ++ } ++ return -1; ++} ++ ++int yaffs_find_chunk_in_file(struct yaffs_obj *in, int inode_chunk, ++ struct yaffs_ext_tags *tags) ++{ ++ /*Get the Tnode, then get the level 0 offset chunk offset */ ++ struct yaffs_tnode *tn; ++ int the_chunk = -1; ++ struct yaffs_ext_tags local_tags; ++ int ret_val = -1; ++ struct yaffs_dev *dev = in->my_dev; ++ ++ if (!tags) { ++ /* Passed a NULL, so use our own tags space */ ++ tags = &local_tags; ++ } ++ ++ tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk); ++ ++ if (!tn) ++ return ret_val; ++ ++ the_chunk = yaffs_get_group_base(dev, tn, inode_chunk); ++ ++ ret_val = yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id, ++ inode_chunk); ++ return ret_val; ++} ++ ++static int yaffs_find_del_file_chunk(struct yaffs_obj *in, int inode_chunk, ++ struct yaffs_ext_tags *tags) ++{ ++ /* Get the Tnode, then get the level 0 offset chunk offset */ ++ struct yaffs_tnode *tn; ++ int the_chunk = -1; ++ struct yaffs_ext_tags local_tags; ++ struct yaffs_dev *dev = in->my_dev; ++ int ret_val = -1; ++ ++ if (!tags) { ++ /* Passed a NULL, so use our own tags space */ ++ tags = &local_tags; ++ } ++ ++ tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk); ++ ++ if (!tn) ++ return ret_val; ++ ++ the_chunk = yaffs_get_group_base(dev, tn, inode_chunk); ++ ++ ret_val = yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id, ++ inode_chunk); ++ ++ /* Delete the entry in the filestructure (if found) */ ++ if (ret_val != -1) ++ yaffs_load_tnode_0(dev, tn, inode_chunk, 0); ++ ++ return ret_val; ++} ++ ++int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk, ++ int nand_chunk, int in_scan) ++{ ++ /* NB in_scan is zero unless scanning. ++ * For forward scanning, in_scan is > 0; ++ * for backward scanning in_scan is < 0 ++ * ++ * nand_chunk = 0 is a dummy insert to make sure the tnodes are there. ++ */ ++ ++ struct yaffs_tnode *tn; ++ struct yaffs_dev *dev = in->my_dev; ++ int existing_cunk; ++ struct yaffs_ext_tags existing_tags; ++ struct yaffs_ext_tags new_tags; ++ unsigned existing_serial, new_serial; ++ ++ if (in->variant_type != YAFFS_OBJECT_TYPE_FILE) { ++ /* Just ignore an attempt at putting a chunk into a non-file ++ * during scanning. ++ * If it is not during Scanning then something went wrong! ++ */ ++ if (!in_scan) { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "yaffs tragedy:attempt to put data chunk into a non-file" ++ ); ++ BUG(); ++ } ++ ++ yaffs_chunk_del(dev, nand_chunk, 1, __LINE__); ++ return YAFFS_OK; ++ } ++ ++ tn = yaffs_add_find_tnode_0(dev, ++ &in->variant.file_variant, ++ inode_chunk, NULL); ++ if (!tn) ++ return YAFFS_FAIL; ++ ++ if (!nand_chunk) ++ /* Dummy insert, bail now */ ++ return YAFFS_OK; ++ ++ existing_cunk = yaffs_get_group_base(dev, tn, inode_chunk); ++ ++ if (in_scan != 0) { ++ /* If we're scanning then we need to test for duplicates ++ * NB This does not need to be efficient since it should only ++ * happen when the power fails during a write, then only one ++ * chunk should ever be affected. ++ * ++ * Correction for YAFFS2: This could happen quite a lot and we ++ * need to think about efficiency! TODO ++ * Update: For backward scanning we don't need to re-read tags ++ * so this is quite cheap. ++ */ ++ ++ if (existing_cunk > 0) { ++ /* NB Right now existing chunk will not be real ++ * chunk_id if the chunk group size > 1 ++ * thus we have to do a FindChunkInFile to get the ++ * real chunk id. ++ * ++ * We have a duplicate now we need to decide which ++ * one to use: ++ * ++ * Backwards scanning YAFFS2: The old one is what ++ * we use, dump the new one. ++ * YAFFS1: Get both sets of tags and compare serial ++ * numbers. ++ */ ++ ++ if (in_scan > 0) { ++ /* Only do this for forward scanning */ ++ yaffs_rd_chunk_tags_nand(dev, ++ nand_chunk, ++ NULL, &new_tags); ++ ++ /* Do a proper find */ ++ existing_cunk = ++ yaffs_find_chunk_in_file(in, inode_chunk, ++ &existing_tags); ++ } ++ ++ if (existing_cunk <= 0) { ++ /*Hoosterman - how did this happen? */ ++ ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "yaffs tragedy: existing chunk < 0 in scan" ++ ); ++ ++ } ++ ++ /* NB The deleted flags should be false, otherwise ++ * the chunks will not be loaded during a scan ++ */ ++ ++ if (in_scan > 0) { ++ new_serial = new_tags.serial_number; ++ existing_serial = existing_tags.serial_number; ++ } ++ ++ if ((in_scan > 0) && ++ (existing_cunk <= 0 || ++ ((existing_serial + 1) & 3) == new_serial)) { ++ /* Forward scanning. ++ * Use new ++ * Delete the old one and drop through to ++ * update the tnode ++ */ ++ yaffs_chunk_del(dev, existing_cunk, 1, ++ __LINE__); ++ } else { ++ /* Backward scanning or we want to use the ++ * existing one ++ * Delete the new one and return early so that ++ * the tnode isn't changed ++ */ ++ yaffs_chunk_del(dev, nand_chunk, 1, __LINE__); ++ return YAFFS_OK; ++ } ++ } ++ ++ } ++ ++ if (existing_cunk == 0) ++ in->n_data_chunks++; ++ ++ yaffs_load_tnode_0(dev, tn, inode_chunk, nand_chunk); ++ ++ return YAFFS_OK; ++} ++ ++static void yaffs_soft_del_chunk(struct yaffs_dev *dev, int chunk) ++{ ++ struct yaffs_block_info *the_block; ++ unsigned block_no; ++ ++ yaffs_trace(YAFFS_TRACE_DELETION, "soft delete chunk %d", chunk); ++ ++ block_no = chunk / dev->param.chunks_per_block; ++ the_block = yaffs_get_block_info(dev, block_no); ++ if (the_block) { ++ the_block->soft_del_pages++; ++ dev->n_free_chunks++; ++ yaffs2_update_oldest_dirty_seq(dev, block_no, the_block); ++ } ++} ++ ++/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all ++ * the chunks in the file. ++ * All soft deleting does is increment the block's softdelete count and pulls ++ * the chunk out of the tnode. ++ * Thus, essentially this is the same as DeleteWorker except that the chunks ++ * are soft deleted. ++ */ ++ ++static int yaffs_soft_del_worker(struct yaffs_obj *in, struct yaffs_tnode *tn, ++ u32 level, int chunk_offset) ++{ ++ int i; ++ int the_chunk; ++ int all_done = 1; ++ struct yaffs_dev *dev = in->my_dev; ++ ++ if (!tn) ++ return 1; ++ ++ if (level > 0) { ++ for (i = YAFFS_NTNODES_INTERNAL - 1; ++ all_done && i >= 0; ++ i--) { ++ if (tn->internal[i]) { ++ all_done = ++ yaffs_soft_del_worker(in, ++ tn->internal[i], ++ level - 1, ++ (chunk_offset << ++ YAFFS_TNODES_INTERNAL_BITS) ++ + i); ++ if (all_done) { ++ yaffs_free_tnode(dev, ++ tn->internal[i]); ++ tn->internal[i] = NULL; ++ } else { ++ /* Can this happen? */ ++ } ++ } ++ } ++ return (all_done) ? 1 : 0; ++ } ++ ++ /* level 0 */ ++ for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) { ++ the_chunk = yaffs_get_group_base(dev, tn, i); ++ if (the_chunk) { ++ yaffs_soft_del_chunk(dev, the_chunk); ++ yaffs_load_tnode_0(dev, tn, i, 0); ++ } ++ } ++ return 1; ++} ++ ++static void yaffs_remove_obj_from_dir(struct yaffs_obj *obj) ++{ ++ struct yaffs_dev *dev = obj->my_dev; ++ struct yaffs_obj *parent; ++ ++ yaffs_verify_obj_in_dir(obj); ++ parent = obj->parent; ++ ++ yaffs_verify_dir(parent); ++ ++ if (dev && dev->param.remove_obj_fn) ++ dev->param.remove_obj_fn(obj); ++ ++ list_del_init(&obj->siblings); ++ obj->parent = NULL; ++ ++ yaffs_verify_dir(parent); ++} ++ ++void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj) ++{ ++ if (!directory) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "tragedy: Trying to add an object to a null pointer directory" ++ ); ++ BUG(); ++ return; ++ } ++ if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "tragedy: Trying to add an object to a non-directory" ++ ); ++ BUG(); ++ } ++ ++ if (obj->siblings.prev == NULL) { ++ /* Not initialised */ ++ BUG(); ++ } ++ ++ yaffs_verify_dir(directory); ++ ++ yaffs_remove_obj_from_dir(obj); ++ ++ /* Now add it */ ++ list_add(&obj->siblings, &directory->variant.dir_variant.children); ++ obj->parent = directory; ++ ++ if (directory == obj->my_dev->unlinked_dir ++ || directory == obj->my_dev->del_dir) { ++ obj->unlinked = 1; ++ obj->my_dev->n_unlinked_files++; ++ obj->rename_allowed = 0; ++ } ++ ++ yaffs_verify_dir(directory); ++ yaffs_verify_obj_in_dir(obj); ++} ++ ++static int yaffs_change_obj_name(struct yaffs_obj *obj, ++ struct yaffs_obj *new_dir, ++ const YCHAR *new_name, int force, int shadows) ++{ ++ int unlink_op; ++ int del_op; ++ struct yaffs_obj *existing_target; ++ ++ if (new_dir == NULL) ++ new_dir = obj->parent; /* use the old directory */ ++ ++ if (new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "tragedy: yaffs_change_obj_name: new_dir is not a directory" ++ ); ++ BUG(); ++ } ++ ++ unlink_op = (new_dir == obj->my_dev->unlinked_dir); ++ del_op = (new_dir == obj->my_dev->del_dir); ++ ++ existing_target = yaffs_find_by_name(new_dir, new_name); ++ ++ /* If the object is a file going into the unlinked directory, ++ * then it is OK to just stuff it in since duplicate names are OK. ++ * else only proceed if the new name does not exist and we're putting ++ * it into a directory. ++ */ ++ if (!(unlink_op || del_op || force || ++ shadows > 0 || !existing_target) || ++ new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) ++ return YAFFS_FAIL; ++ ++ yaffs_set_obj_name(obj, new_name); ++ obj->dirty = 1; ++ yaffs_add_obj_to_dir(new_dir, obj); ++ ++ if (unlink_op) ++ obj->unlinked = 1; ++ ++ /* If it is a deletion then we mark it as a shrink for gc */ ++ if (yaffs_update_oh(obj, new_name, 0, del_op, shadows, NULL) >= 0) ++ return YAFFS_OK; ++ ++ return YAFFS_FAIL; ++} ++ ++ ++static void yaffs_unhash_obj(struct yaffs_obj *obj) ++{ ++ int bucket; ++ struct yaffs_dev *dev = obj->my_dev; ++ ++ /* If it is still linked into the bucket list, free from the list */ ++ if (!list_empty(&obj->hash_link)) { ++ list_del_init(&obj->hash_link); ++ bucket = yaffs_hash_fn(obj->obj_id); ++ dev->obj_bucket[bucket].count--; ++ } ++} ++ ++/* FreeObject frees up a Object and puts it back on the free list */ ++static void yaffs_free_obj(struct yaffs_obj *obj) ++{ ++ struct yaffs_dev *dev; ++ ++ if (!obj) { ++ BUG(); ++ return; ++ } ++ dev = obj->my_dev; ++ yaffs_trace(YAFFS_TRACE_OS, "FreeObject %p inode %p", ++ obj, obj->my_inode); ++ if (obj->parent) ++ BUG(); ++ if (!list_empty(&obj->siblings)) ++ BUG(); ++ ++ if (obj->my_inode) { ++ /* We're still hooked up to a cached inode. ++ * Don't delete now, but mark for later deletion ++ */ ++ obj->defered_free = 1; ++ return; ++ } ++ ++ yaffs_unhash_obj(obj); ++ ++ yaffs_free_raw_obj(dev, obj); ++ dev->n_obj--; ++ dev->checkpoint_blocks_required = 0; /* force recalculation */ ++} ++ ++void yaffs_handle_defered_free(struct yaffs_obj *obj) ++{ ++ if (obj->defered_free) ++ yaffs_free_obj(obj); ++} ++ ++static int yaffs_generic_obj_del(struct yaffs_obj *in) ++{ ++ /* Iinvalidate the file's data in the cache, without flushing. */ ++ yaffs_invalidate_file_cache(in); ++ ++ if (in->my_dev->param.is_yaffs2 && in->parent != in->my_dev->del_dir) { ++ /* Move to unlinked directory so we have a deletion record */ ++ yaffs_change_obj_name(in, in->my_dev->del_dir, _Y("deleted"), 0, ++ 0); ++ } ++ ++ yaffs_remove_obj_from_dir(in); ++ yaffs_chunk_del(in->my_dev, in->hdr_chunk, 1, __LINE__); ++ in->hdr_chunk = 0; ++ ++ yaffs_free_obj(in); ++ return YAFFS_OK; ++ ++} ++ ++static void yaffs_soft_del_file(struct yaffs_obj *obj) ++{ ++ if (!obj->deleted || ++ obj->variant_type != YAFFS_OBJECT_TYPE_FILE || ++ obj->soft_del) ++ return; ++ ++ if (obj->n_data_chunks <= 0) { ++ /* Empty file with no duplicate object headers, ++ * just delete it immediately */ ++ yaffs_free_tnode(obj->my_dev, obj->variant.file_variant.top); ++ obj->variant.file_variant.top = NULL; ++ yaffs_trace(YAFFS_TRACE_TRACING, ++ "yaffs: Deleting empty file %d", ++ obj->obj_id); ++ yaffs_generic_obj_del(obj); ++ } else { ++ yaffs_soft_del_worker(obj, ++ obj->variant.file_variant.top, ++ obj->variant. ++ file_variant.top_level, 0); ++ obj->soft_del = 1; ++ } ++} ++ ++/* Pruning removes any part of the file structure tree that is beyond the ++ * bounds of the file (ie that does not point to chunks). ++ * ++ * A file should only get pruned when its size is reduced. ++ * ++ * Before pruning, the chunks must be pulled from the tree and the ++ * level 0 tnode entries must be zeroed out. ++ * Could also use this for file deletion, but that's probably better handled ++ * by a special case. ++ * ++ * This function is recursive. For levels > 0 the function is called again on ++ * any sub-tree. For level == 0 we just check if the sub-tree has data. ++ * If there is no data in a subtree then it is pruned. ++ */ ++ ++static struct yaffs_tnode *yaffs_prune_worker(struct yaffs_dev *dev, ++ struct yaffs_tnode *tn, u32 level, ++ int del0) ++{ ++ int i; ++ int has_data; ++ ++ if (!tn) ++ return tn; ++ ++ has_data = 0; ++ ++ if (level > 0) { ++ for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) { ++ if (tn->internal[i]) { ++ tn->internal[i] = ++ yaffs_prune_worker(dev, ++ tn->internal[i], ++ level - 1, ++ (i == 0) ? del0 : 1); ++ } ++ ++ if (tn->internal[i]) ++ has_data++; ++ } ++ } else { ++ int tnode_size_u32 = dev->tnode_size / sizeof(u32); ++ u32 *map = (u32 *) tn; ++ ++ for (i = 0; !has_data && i < tnode_size_u32; i++) { ++ if (map[i]) ++ has_data++; ++ } ++ } ++ ++ if (has_data == 0 && del0) { ++ /* Free and return NULL */ ++ yaffs_free_tnode(dev, tn); ++ tn = NULL; ++ } ++ return tn; ++} ++ ++static int yaffs_prune_tree(struct yaffs_dev *dev, ++ struct yaffs_file_var *file_struct) ++{ ++ int i; ++ int has_data; ++ int done = 0; ++ struct yaffs_tnode *tn; ++ ++ if (file_struct->top_level < 1) ++ return YAFFS_OK; ++ ++ file_struct->top = ++ yaffs_prune_worker(dev, file_struct->top, file_struct->top_level, 0); ++ ++ /* Now we have a tree with all the non-zero branches NULL but ++ * the height is the same as it was. ++ * Let's see if we can trim internal tnodes to shorten the tree. ++ * We can do this if only the 0th element in the tnode is in use ++ * (ie all the non-zero are NULL) ++ */ ++ ++ while (file_struct->top_level && !done) { ++ tn = file_struct->top; ++ ++ has_data = 0; ++ for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) { ++ if (tn->internal[i]) ++ has_data++; ++ } ++ ++ if (!has_data) { ++ file_struct->top = tn->internal[0]; ++ file_struct->top_level--; ++ yaffs_free_tnode(dev, tn); ++ } else { ++ done = 1; ++ } ++ } ++ ++ return YAFFS_OK; ++} ++ ++/*-------------------- End of File Structure functions.-------------------*/ ++ ++/* alloc_empty_obj gets us a clean Object.*/ ++static struct yaffs_obj *yaffs_alloc_empty_obj(struct yaffs_dev *dev) ++{ ++ struct yaffs_obj *obj = yaffs_alloc_raw_obj(dev); ++ ++ if (!obj) ++ return obj; ++ ++ dev->n_obj++; ++ ++ /* Now sweeten it up... */ ++ ++ memset(obj, 0, sizeof(struct yaffs_obj)); ++ obj->being_created = 1; ++ ++ obj->my_dev = dev; ++ obj->hdr_chunk = 0; ++ obj->variant_type = YAFFS_OBJECT_TYPE_UNKNOWN; ++ INIT_LIST_HEAD(&(obj->hard_links)); ++ INIT_LIST_HEAD(&(obj->hash_link)); ++ INIT_LIST_HEAD(&obj->siblings); ++ ++ /* Now make the directory sane */ ++ if (dev->root_dir) { ++ obj->parent = dev->root_dir; ++ list_add(&(obj->siblings), ++ &dev->root_dir->variant.dir_variant.children); ++ } ++ ++ /* Add it to the lost and found directory. ++ * NB Can't put root or lost-n-found in lost-n-found so ++ * check if lost-n-found exists first ++ */ ++ if (dev->lost_n_found) ++ yaffs_add_obj_to_dir(dev->lost_n_found, obj); ++ ++ obj->being_created = 0; ++ ++ dev->checkpoint_blocks_required = 0; /* force recalculation */ ++ ++ return obj; ++} ++ ++static int yaffs_find_nice_bucket(struct yaffs_dev *dev) ++{ ++ int i; ++ int l = 999; ++ int lowest = 999999; ++ ++ /* Search for the shortest list or one that ++ * isn't too long. ++ */ ++ ++ for (i = 0; i < 10 && lowest > 4; i++) { ++ dev->bucket_finder++; ++ dev->bucket_finder %= YAFFS_NOBJECT_BUCKETS; ++ if (dev->obj_bucket[dev->bucket_finder].count < lowest) { ++ lowest = dev->obj_bucket[dev->bucket_finder].count; ++ l = dev->bucket_finder; ++ } ++ } ++ ++ return l; ++} ++ ++static int yaffs_new_obj_id(struct yaffs_dev *dev) ++{ ++ int bucket = yaffs_find_nice_bucket(dev); ++ int found = 0; ++ struct list_head *i; ++ u32 n = (u32) bucket; ++ ++ /* ++ * Now find an object value that has not already been taken ++ * by scanning the list, incrementing each time by number of buckets. ++ */ ++ while (!found) { ++ found = 1; ++ n += YAFFS_NOBJECT_BUCKETS; ++ list_for_each(i, &dev->obj_bucket[bucket].list) { ++ /* Check if this value is already taken. */ ++ if (i && list_entry(i, struct yaffs_obj, ++ hash_link)->obj_id == n) ++ found = 0; ++ } ++ } ++ return n; ++} ++ ++static void yaffs_hash_obj(struct yaffs_obj *in) ++{ ++ int bucket = yaffs_hash_fn(in->obj_id); ++ struct yaffs_dev *dev = in->my_dev; ++ ++ list_add(&in->hash_link, &dev->obj_bucket[bucket].list); ++ dev->obj_bucket[bucket].count++; ++} ++ ++struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number) ++{ ++ int bucket = yaffs_hash_fn(number); ++ struct list_head *i; ++ struct yaffs_obj *in; ++ ++ list_for_each(i, &dev->obj_bucket[bucket].list) { ++ /* Look if it is in the list */ ++ in = list_entry(i, struct yaffs_obj, hash_link); ++ if (in->obj_id == number) { ++ /* Don't show if it is defered free */ ++ if (in->defered_free) ++ return NULL; ++ return in; ++ } ++ } ++ ++ return NULL; ++} ++ ++static struct yaffs_obj *yaffs_new_obj(struct yaffs_dev *dev, int number, ++ enum yaffs_obj_type type) ++{ ++ struct yaffs_obj *the_obj = NULL; ++ struct yaffs_tnode *tn = NULL; ++ ++ if (number < 0) ++ number = yaffs_new_obj_id(dev); ++ ++ if (type == YAFFS_OBJECT_TYPE_FILE) { ++ tn = yaffs_get_tnode(dev); ++ if (!tn) ++ return NULL; ++ } ++ ++ the_obj = yaffs_alloc_empty_obj(dev); ++ if (!the_obj) { ++ if (tn) ++ yaffs_free_tnode(dev, tn); ++ return NULL; ++ } ++ ++ the_obj->fake = 0; ++ the_obj->rename_allowed = 1; ++ the_obj->unlink_allowed = 1; ++ the_obj->obj_id = number; ++ yaffs_hash_obj(the_obj); ++ the_obj->variant_type = type; ++ yaffs_load_current_time(the_obj, 1, 1); ++ ++ switch (type) { ++ case YAFFS_OBJECT_TYPE_FILE: ++ the_obj->variant.file_variant.file_size = 0; ++ the_obj->variant.file_variant.stored_size = 0; ++ the_obj->variant.file_variant.shrink_size = ++ yaffs_max_file_size(dev); ++ the_obj->variant.file_variant.top_level = 0; ++ the_obj->variant.file_variant.top = tn; ++ break; ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ INIT_LIST_HEAD(&the_obj->variant.dir_variant.children); ++ INIT_LIST_HEAD(&the_obj->variant.dir_variant.dirty); ++ break; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ case YAFFS_OBJECT_TYPE_SPECIAL: ++ /* No action required */ ++ break; ++ case YAFFS_OBJECT_TYPE_UNKNOWN: ++ /* todo this should not happen */ ++ break; ++ } ++ return the_obj; ++} ++ ++static struct yaffs_obj *yaffs_create_fake_dir(struct yaffs_dev *dev, ++ int number, u32 mode) ++{ ++ ++ struct yaffs_obj *obj = ++ yaffs_new_obj(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY); ++ ++ if (!obj) ++ return NULL; ++ ++ obj->fake = 1; /* it is fake so it might not use NAND */ ++ obj->rename_allowed = 0; ++ obj->unlink_allowed = 0; ++ obj->deleted = 0; ++ obj->unlinked = 0; ++ obj->yst_mode = mode; ++ obj->my_dev = dev; ++ obj->hdr_chunk = 0; /* Not a valid chunk. */ ++ return obj; ++ ++} ++ ++ ++static void yaffs_init_tnodes_and_objs(struct yaffs_dev *dev) ++{ ++ int i; ++ ++ dev->n_obj = 0; ++ dev->n_tnodes = 0; ++ yaffs_init_raw_tnodes_and_objs(dev); ++ ++ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) { ++ INIT_LIST_HEAD(&dev->obj_bucket[i].list); ++ dev->obj_bucket[i].count = 0; ++ } ++} ++ ++struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev, ++ int number, ++ enum yaffs_obj_type type) ++{ ++ struct yaffs_obj *the_obj = NULL; ++ ++ if (number > 0) ++ the_obj = yaffs_find_by_number(dev, number); ++ ++ if (!the_obj) ++ the_obj = yaffs_new_obj(dev, number, type); ++ ++ return the_obj; ++ ++} ++ ++YCHAR *yaffs_clone_str(const YCHAR *str) ++{ ++ YCHAR *new_str = NULL; ++ int len; ++ ++ if (!str) ++ str = _Y(""); ++ ++ len = strnlen(str, YAFFS_MAX_ALIAS_LENGTH); ++ new_str = kmalloc((len + 1) * sizeof(YCHAR), GFP_NOFS); ++ if (new_str) { ++ strncpy(new_str, str, len); ++ new_str[len] = 0; ++ } ++ return new_str; ++ ++} ++/* ++ *yaffs_update_parent() handles fixing a directories mtime and ctime when a new ++ * link (ie. name) is created or deleted in the directory. ++ * ++ * ie. ++ * create dir/a : update dir's mtime/ctime ++ * rm dir/a: update dir's mtime/ctime ++ * modify dir/a: don't update dir's mtimme/ctime ++ * ++ * This can be handled immediately or defered. Defering helps reduce the number ++ * of updates when many files in a directory are changed within a brief period. ++ * ++ * If the directory updating is defered then yaffs_update_dirty_dirs must be ++ * called periodically. ++ */ ++ ++static void yaffs_update_parent(struct yaffs_obj *obj) ++{ ++ struct yaffs_dev *dev; ++ ++ if (!obj) ++ return; ++ dev = obj->my_dev; ++ obj->dirty = 1; ++ yaffs_load_current_time(obj, 0, 1); ++ if (dev->param.defered_dir_update) { ++ struct list_head *link = &obj->variant.dir_variant.dirty; ++ ++ if (list_empty(link)) { ++ list_add(link, &dev->dirty_dirs); ++ yaffs_trace(YAFFS_TRACE_BACKGROUND, ++ "Added object %d to dirty directories", ++ obj->obj_id); ++ } ++ ++ } else { ++ yaffs_update_oh(obj, NULL, 0, 0, 0, NULL); ++ } ++} ++ ++void yaffs_update_dirty_dirs(struct yaffs_dev *dev) ++{ ++ struct list_head *link; ++ struct yaffs_obj *obj; ++ struct yaffs_dir_var *d_s; ++ union yaffs_obj_var *o_v; ++ ++ yaffs_trace(YAFFS_TRACE_BACKGROUND, "Update dirty directories"); ++ ++ while (!list_empty(&dev->dirty_dirs)) { ++ link = dev->dirty_dirs.next; ++ list_del_init(link); ++ ++ d_s = list_entry(link, struct yaffs_dir_var, dirty); ++ o_v = list_entry(d_s, union yaffs_obj_var, dir_variant); ++ obj = list_entry(o_v, struct yaffs_obj, variant); ++ ++ yaffs_trace(YAFFS_TRACE_BACKGROUND, "Update directory %d", ++ obj->obj_id); ++ ++ if (obj->dirty) ++ yaffs_update_oh(obj, NULL, 0, 0, 0, NULL); ++ } ++} ++ ++/* ++ * Mknod (create) a new object. ++ * equiv_obj only has meaning for a hard link; ++ * alias_str only has meaning for a symlink. ++ * rdev only has meaning for devices (a subset of special objects) ++ */ ++ ++static struct yaffs_obj *yaffs_create_obj(enum yaffs_obj_type type, ++ struct yaffs_obj *parent, ++ const YCHAR *name, ++ u32 mode, ++ u32 uid, ++ u32 gid, ++ struct yaffs_obj *equiv_obj, ++ const YCHAR *alias_str, u32 rdev) ++{ ++ struct yaffs_obj *in; ++ YCHAR *str = NULL; ++ struct yaffs_dev *dev = parent->my_dev; ++ ++ /* Check if the entry exists. ++ * If it does then fail the call since we don't want a dup. */ ++ if (yaffs_find_by_name(parent, name)) ++ return NULL; ++ ++ if (type == YAFFS_OBJECT_TYPE_SYMLINK) { ++ str = yaffs_clone_str(alias_str); ++ if (!str) ++ return NULL; ++ } ++ ++ in = yaffs_new_obj(dev, -1, type); ++ ++ if (!in) { ++ kfree(str); ++ return NULL; ++ } ++ ++ in->hdr_chunk = 0; ++ in->valid = 1; ++ in->variant_type = type; ++ ++ in->yst_mode = mode; ++ ++ yaffs_attribs_init(in, gid, uid, rdev); ++ ++ in->n_data_chunks = 0; ++ ++ yaffs_set_obj_name(in, name); ++ in->dirty = 1; ++ ++ yaffs_add_obj_to_dir(parent, in); ++ ++ in->my_dev = parent->my_dev; ++ ++ switch (type) { ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ in->variant.symlink_variant.alias = str; ++ break; ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ in->variant.hardlink_variant.equiv_obj = equiv_obj; ++ in->variant.hardlink_variant.equiv_id = equiv_obj->obj_id; ++ list_add(&in->hard_links, &equiv_obj->hard_links); ++ break; ++ case YAFFS_OBJECT_TYPE_FILE: ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ case YAFFS_OBJECT_TYPE_SPECIAL: ++ case YAFFS_OBJECT_TYPE_UNKNOWN: ++ /* do nothing */ ++ break; ++ } ++ ++ if (yaffs_update_oh(in, name, 0, 0, 0, NULL) < 0) { ++ /* Could not create the object header, fail */ ++ yaffs_del_obj(in); ++ in = NULL; ++ } ++ ++ if (in) ++ yaffs_update_parent(parent); ++ ++ return in; ++} ++ ++struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent, ++ const YCHAR *name, u32 mode, u32 uid, ++ u32 gid) ++{ ++ return yaffs_create_obj(YAFFS_OBJECT_TYPE_FILE, parent, name, mode, ++ uid, gid, NULL, NULL, 0); ++} ++ ++struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR *name, ++ u32 mode, u32 uid, u32 gid) ++{ ++ return yaffs_create_obj(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name, ++ mode, uid, gid, NULL, NULL, 0); ++} ++ ++struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent, ++ const YCHAR *name, u32 mode, u32 uid, ++ u32 gid, u32 rdev) ++{ ++ return yaffs_create_obj(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode, ++ uid, gid, NULL, NULL, rdev); ++} ++ ++struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent, ++ const YCHAR *name, u32 mode, u32 uid, ++ u32 gid, const YCHAR *alias) ++{ ++ return yaffs_create_obj(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode, ++ uid, gid, NULL, alias, 0); ++} ++ ++/* yaffs_link_obj returns the object id of the equivalent object.*/ ++struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR * name, ++ struct yaffs_obj *equiv_obj) ++{ ++ /* Get the real object in case we were fed a hard link obj */ ++ equiv_obj = yaffs_get_equivalent_obj(equiv_obj); ++ ++ if (yaffs_create_obj(YAFFS_OBJECT_TYPE_HARDLINK, ++ parent, name, 0, 0, 0, ++ equiv_obj, NULL, 0)) ++ return equiv_obj; ++ ++ return NULL; ++ ++} ++ ++ ++ ++/*---------------------- Block Management and Page Allocation -------------*/ ++ ++static void yaffs_deinit_blocks(struct yaffs_dev *dev) ++{ ++ if (dev->block_info_alt && dev->block_info) ++ vfree(dev->block_info); ++ else ++ kfree(dev->block_info); ++ ++ dev->block_info_alt = 0; ++ ++ dev->block_info = NULL; ++ ++ if (dev->chunk_bits_alt && dev->chunk_bits) ++ vfree(dev->chunk_bits); ++ else ++ kfree(dev->chunk_bits); ++ dev->chunk_bits_alt = 0; ++ dev->chunk_bits = NULL; ++} ++ ++static int yaffs_init_blocks(struct yaffs_dev *dev) ++{ ++ int n_blocks = dev->internal_end_block - dev->internal_start_block + 1; ++ ++ dev->block_info = NULL; ++ dev->chunk_bits = NULL; ++ dev->alloc_block = -1; /* force it to get a new one */ ++ ++ /* If the first allocation strategy fails, thry the alternate one */ ++ dev->block_info = ++ kmalloc(n_blocks * sizeof(struct yaffs_block_info), GFP_NOFS); ++ if (!dev->block_info) { ++ dev->block_info = ++ vmalloc(n_blocks * sizeof(struct yaffs_block_info)); ++ dev->block_info_alt = 1; ++ } else { ++ dev->block_info_alt = 0; ++ } ++ ++ if (!dev->block_info) ++ goto alloc_error; ++ ++ /* Set up dynamic blockinfo stuff. Round up bytes. */ ++ dev->chunk_bit_stride = (dev->param.chunks_per_block + 7) / 8; ++ dev->chunk_bits = ++ kmalloc(dev->chunk_bit_stride * n_blocks, GFP_NOFS); ++ if (!dev->chunk_bits) { ++ dev->chunk_bits = ++ vmalloc(dev->chunk_bit_stride * n_blocks); ++ dev->chunk_bits_alt = 1; ++ } else { ++ dev->chunk_bits_alt = 0; ++ } ++ if (!dev->chunk_bits) ++ goto alloc_error; ++ ++ ++ memset(dev->block_info, 0, n_blocks * sizeof(struct yaffs_block_info)); ++ memset(dev->chunk_bits, 0, dev->chunk_bit_stride * n_blocks); ++ return YAFFS_OK; ++ ++alloc_error: ++ yaffs_deinit_blocks(dev); ++ return YAFFS_FAIL; ++} ++ ++ ++void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no) ++{ ++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, block_no); ++ int erased_ok = 0; ++ u32 i; ++ ++ /* If the block is still healthy erase it and mark as clean. ++ * If the block has had a data failure, then retire it. ++ */ ++ ++ yaffs_trace(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE, ++ "yaffs_block_became_dirty block %d state %d %s", ++ block_no, bi->block_state, ++ (bi->needs_retiring) ? "needs retiring" : ""); ++ ++ yaffs2_clear_oldest_dirty_seq(dev, bi); ++ ++ bi->block_state = YAFFS_BLOCK_STATE_DIRTY; ++ ++ /* If this is the block being garbage collected then stop gc'ing */ ++ if (block_no == (int)dev->gc_block) ++ dev->gc_block = 0; ++ ++ /* If this block is currently the best candidate for gc ++ * then drop as a candidate */ ++ if (block_no == (int)dev->gc_dirtiest) { ++ dev->gc_dirtiest = 0; ++ dev->gc_pages_in_use = 0; ++ } ++ ++ if (!bi->needs_retiring) { ++ yaffs2_checkpt_invalidate(dev); ++ erased_ok = yaffs_erase_block(dev, block_no); ++ if (!erased_ok) { ++ dev->n_erase_failures++; ++ yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, ++ "**>> Erasure failed %d", block_no); ++ } ++ } ++ ++ /* Verify erasure if needed */ ++ if (erased_ok && ++ ((yaffs_trace_mask & YAFFS_TRACE_ERASE) || ++ !yaffs_skip_verification(dev))) { ++ for (i = 0; i < dev->param.chunks_per_block; i++) { ++ if (!yaffs_check_chunk_erased(dev, ++ block_no * dev->param.chunks_per_block + i)) { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ ">>Block %d erasure supposedly OK, but chunk %d not erased", ++ block_no, i); ++ } ++ } ++ } ++ ++ if (!erased_ok) { ++ /* We lost a block of free space */ ++ dev->n_free_chunks -= dev->param.chunks_per_block; ++ yaffs_retire_block(dev, block_no); ++ yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, ++ "**>> Block %d retired", block_no); ++ return; ++ } ++ ++ /* Clean it up... */ ++ bi->block_state = YAFFS_BLOCK_STATE_EMPTY; ++ bi->seq_number = 0; ++ dev->n_erased_blocks++; ++ bi->pages_in_use = 0; ++ bi->soft_del_pages = 0; ++ bi->has_shrink_hdr = 0; ++ bi->skip_erased_check = 1; /* Clean, so no need to check */ ++ bi->gc_prioritise = 0; ++ bi->has_summary = 0; ++ ++ yaffs_clear_chunk_bits(dev, block_no); ++ ++ yaffs_trace(YAFFS_TRACE_ERASE, "Erased block %d", block_no); ++} ++ ++static inline int yaffs_gc_process_chunk(struct yaffs_dev *dev, ++ struct yaffs_block_info *bi, ++ int old_chunk, u8 *buffer) ++{ ++ int new_chunk; ++ int mark_flash = 1; ++ struct yaffs_ext_tags tags; ++ struct yaffs_obj *object; ++ int matching_chunk; ++ int ret_val = YAFFS_OK; ++ ++ memset(&tags, 0, sizeof(tags)); ++ yaffs_rd_chunk_tags_nand(dev, old_chunk, ++ buffer, &tags); ++ object = yaffs_find_by_number(dev, tags.obj_id); ++ ++ yaffs_trace(YAFFS_TRACE_GC_DETAIL, ++ "Collecting chunk in block %d, %d %d %d ", ++ dev->gc_chunk, tags.obj_id, ++ tags.chunk_id, tags.n_bytes); ++ ++ if (object && !yaffs_skip_verification(dev)) { ++ if (tags.chunk_id == 0) ++ matching_chunk = ++ object->hdr_chunk; ++ else if (object->soft_del) ++ /* Defeat the test */ ++ matching_chunk = old_chunk; ++ else ++ matching_chunk = ++ yaffs_find_chunk_in_file ++ (object, tags.chunk_id, ++ NULL); ++ ++ if (old_chunk != matching_chunk) ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "gc: page in gc mismatch: %d %d %d %d", ++ old_chunk, ++ matching_chunk, ++ tags.obj_id, ++ tags.chunk_id); ++ } ++ ++ if (!object) { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "page %d in gc has no object: %d %d %d ", ++ old_chunk, ++ tags.obj_id, tags.chunk_id, ++ tags.n_bytes); ++ } ++ ++ if (object && ++ object->deleted && ++ object->soft_del && tags.chunk_id != 0) { ++ /* Data chunk in a soft deleted file, ++ * throw it away. ++ * It's a soft deleted data chunk, ++ * No need to copy this, just forget ++ * about it and fix up the object. ++ */ ++ ++ /* Free chunks already includes ++ * softdeleted chunks, how ever this ++ * chunk is going to soon be really ++ * deleted which will increment free ++ * chunks. We have to decrement free ++ * chunks so this works out properly. ++ */ ++ dev->n_free_chunks--; ++ bi->soft_del_pages--; ++ ++ object->n_data_chunks--; ++ if (object->n_data_chunks <= 0) { ++ /* remeber to clean up obj */ ++ dev->gc_cleanup_list[dev->n_clean_ups] = tags.obj_id; ++ dev->n_clean_ups++; ++ } ++ mark_flash = 0; ++ } else if (object) { ++ /* It's either a data chunk in a live ++ * file or an ObjectHeader, so we're ++ * interested in it. ++ * NB Need to keep the ObjectHeaders of ++ * deleted files until the whole file ++ * has been deleted off ++ */ ++ tags.serial_number++; ++ dev->n_gc_copies++; ++ ++ if (tags.chunk_id == 0) { ++ /* It is an object Id, ++ * We need to nuke the shrinkheader flags since its ++ * work is done. ++ * Also need to clean up shadowing. ++ * NB We don't want to do all the work of translating ++ * object header endianism back and forth so we leave ++ * the oh endian in its stored order. ++ */ ++ ++ struct yaffs_obj_hdr *oh; ++ oh = (struct yaffs_obj_hdr *) buffer; ++ ++ oh->is_shrink = 0; ++ tags.extra_is_shrink = 0; ++ oh->shadows_obj = 0; ++ oh->inband_shadowed_obj_id = 0; ++ tags.extra_shadows = 0; ++ ++ /* Update file size */ ++ if (object->variant_type == YAFFS_OBJECT_TYPE_FILE) { ++ yaffs_oh_size_load(dev, oh, ++ object->variant.file_variant.stored_size, 1); ++ tags.extra_file_size = ++ object->variant.file_variant.stored_size; ++ } ++ ++ yaffs_verify_oh(object, oh, &tags, 1); ++ new_chunk = ++ yaffs_write_new_chunk(dev, (u8 *) oh, &tags, 1); ++ } else { ++ new_chunk = ++ yaffs_write_new_chunk(dev, buffer, &tags, 1); ++ } ++ ++ if (new_chunk < 0) { ++ ret_val = YAFFS_FAIL; ++ } else { ++ ++ /* Now fix up the Tnodes etc. */ ++ ++ if (tags.chunk_id == 0) { ++ /* It's a header */ ++ object->hdr_chunk = new_chunk; ++ object->serial = tags.serial_number; ++ } else { ++ /* It's a data chunk */ ++ yaffs_put_chunk_in_file(object, tags.chunk_id, ++ new_chunk, 0); ++ } ++ } ++ } ++ if (ret_val == YAFFS_OK) ++ yaffs_chunk_del(dev, old_chunk, mark_flash, __LINE__); ++ return ret_val; ++} ++ ++static int yaffs_gc_block(struct yaffs_dev *dev, int block, int whole_block) ++{ ++ int old_chunk; ++ int ret_val = YAFFS_OK; ++ u32 i; ++ int is_checkpt_block; ++ int max_copies; ++ int chunks_before = yaffs_get_erased_chunks(dev); ++ int chunks_after; ++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, block); ++ ++ is_checkpt_block = (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT); ++ ++ yaffs_trace(YAFFS_TRACE_TRACING, ++ "Collecting block %d, in use %d, shrink %d, whole_block %d", ++ block, bi->pages_in_use, bi->has_shrink_hdr, ++ whole_block); ++ ++ /*yaffs_verify_free_chunks(dev); */ ++ ++ if (bi->block_state == YAFFS_BLOCK_STATE_FULL) ++ bi->block_state = YAFFS_BLOCK_STATE_COLLECTING; ++ ++ bi->has_shrink_hdr = 0; /* clear the flag so that the block can erase */ ++ ++ dev->gc_disable = 1; ++ ++ yaffs_summary_gc(dev, block); ++ ++ if (is_checkpt_block || !yaffs_still_some_chunks(dev, block)) { ++ yaffs_trace(YAFFS_TRACE_TRACING, ++ "Collecting block %d that has no chunks in use", ++ block); ++ yaffs_block_became_dirty(dev, block); ++ } else { ++ ++ u8 *buffer = yaffs_get_temp_buffer(dev); ++ ++ yaffs_verify_blk(dev, bi, block); ++ ++ max_copies = (whole_block) ? dev->param.chunks_per_block : 5; ++ old_chunk = block * dev->param.chunks_per_block + dev->gc_chunk; ++ ++ for (/* init already done */ ; ++ ret_val == YAFFS_OK && ++ dev->gc_chunk < dev->param.chunks_per_block && ++ (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) && ++ max_copies > 0; ++ dev->gc_chunk++, old_chunk++) { ++ if (yaffs_check_chunk_bit(dev, block, dev->gc_chunk)) { ++ /* Page is in use and might need to be copied */ ++ max_copies--; ++ ret_val = yaffs_gc_process_chunk(dev, bi, ++ old_chunk, buffer); ++ } ++ } ++ yaffs_release_temp_buffer(dev, buffer); ++ } ++ ++ yaffs_verify_collected_blk(dev, bi, block); ++ ++ if (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) { ++ /* ++ * The gc did not complete. Set block state back to FULL ++ * because checkpointing does not restore gc. ++ */ ++ bi->block_state = YAFFS_BLOCK_STATE_FULL; ++ } else { ++ /* The gc completed. */ ++ /* Do any required cleanups */ ++ for (i = 0; i < dev->n_clean_ups; i++) { ++ /* Time to delete the file too */ ++ struct yaffs_obj *object = ++ yaffs_find_by_number(dev, dev->gc_cleanup_list[i]); ++ if (object) { ++ yaffs_free_tnode(dev, ++ object->variant.file_variant.top); ++ object->variant.file_variant.top = NULL; ++ yaffs_trace(YAFFS_TRACE_GC, ++ "yaffs: About to finally delete object %d", ++ object->obj_id); ++ yaffs_generic_obj_del(object); ++ object->my_dev->n_deleted_files--; ++ } ++ ++ } ++ chunks_after = yaffs_get_erased_chunks(dev); ++ if (chunks_before >= chunks_after) ++ yaffs_trace(YAFFS_TRACE_GC, ++ "gc did not increase free chunks before %d after %d", ++ chunks_before, chunks_after); ++ dev->gc_block = 0; ++ dev->gc_chunk = 0; ++ dev->n_clean_ups = 0; ++ } ++ ++ dev->gc_disable = 0; ++ ++ return ret_val; ++} ++ ++/* ++ * find_gc_block() selects the dirtiest block (or close enough) ++ * for garbage collection. ++ */ ++ ++static unsigned yaffs_find_gc_block(struct yaffs_dev *dev, ++ int aggressive, int background) ++{ ++ u32 i; ++ u32 iterations; ++ u32 selected = 0; ++ int prioritised = 0; ++ int prioritised_exist = 0; ++ struct yaffs_block_info *bi; ++ u32 threshold = dev->param.chunks_per_block; ++ ++ (void) prioritised; ++ ++ /* First let's see if we need to grab a prioritised block */ ++ if (dev->has_pending_prioritised_gc && !aggressive) { ++ dev->gc_dirtiest = 0; ++ bi = dev->block_info; ++ for (i = dev->internal_start_block; ++ i <= dev->internal_end_block && !selected; i++) { ++ ++ if (bi->gc_prioritise) { ++ prioritised_exist = 1; ++ if (bi->block_state == YAFFS_BLOCK_STATE_FULL && ++ yaffs_block_ok_for_gc(dev, bi)) { ++ selected = i; ++ prioritised = 1; ++ } ++ } ++ bi++; ++ } ++ ++ /* ++ * If there is a prioritised block and none was selected then ++ * this happened because there is at least one old dirty block ++ * gumming up the works. Let's gc the oldest dirty block. ++ */ ++ ++ if (prioritised_exist && ++ !selected && dev->oldest_dirty_block > 0) ++ selected = dev->oldest_dirty_block; ++ ++ if (!prioritised_exist) /* None found, so we can clear this */ ++ dev->has_pending_prioritised_gc = 0; ++ } ++ ++ /* If we're doing aggressive GC then we are happy to take a less-dirty ++ * block, and search harder. ++ * else (leasurely gc), then we only bother to do this if the ++ * block has only a few pages in use. ++ */ ++ ++ if (!selected) { ++ u32 pages_used; ++ int n_blocks = ++ dev->internal_end_block - dev->internal_start_block + 1; ++ if (aggressive) { ++ threshold = dev->param.chunks_per_block; ++ iterations = n_blocks; ++ } else { ++ u32 max_threshold; ++ ++ if (background) ++ max_threshold = dev->param.chunks_per_block / 2; ++ else ++ max_threshold = dev->param.chunks_per_block / 8; ++ ++ if (max_threshold < YAFFS_GC_PASSIVE_THRESHOLD) ++ max_threshold = YAFFS_GC_PASSIVE_THRESHOLD; ++ ++ threshold = background ? (dev->gc_not_done + 2) * 2 : 0; ++ if (threshold < YAFFS_GC_PASSIVE_THRESHOLD) ++ threshold = YAFFS_GC_PASSIVE_THRESHOLD; ++ if (threshold > max_threshold) ++ threshold = max_threshold; ++ ++ iterations = n_blocks / 16 + 1; ++ if (iterations > 100) ++ iterations = 100; ++ } ++ ++ for (i = 0; ++ i < iterations && ++ (dev->gc_dirtiest < 1 || ++ dev->gc_pages_in_use > YAFFS_GC_GOOD_ENOUGH); ++ i++) { ++ dev->gc_block_finder++; ++ if (dev->gc_block_finder < dev->internal_start_block || ++ dev->gc_block_finder > dev->internal_end_block) ++ dev->gc_block_finder = ++ dev->internal_start_block; ++ ++ bi = yaffs_get_block_info(dev, dev->gc_block_finder); ++ ++ pages_used = bi->pages_in_use - bi->soft_del_pages; ++ ++ if (bi->block_state == YAFFS_BLOCK_STATE_FULL && ++ pages_used < dev->param.chunks_per_block && ++ (dev->gc_dirtiest < 1 || ++ pages_used < dev->gc_pages_in_use) && ++ yaffs_block_ok_for_gc(dev, bi)) { ++ dev->gc_dirtiest = dev->gc_block_finder; ++ dev->gc_pages_in_use = pages_used; ++ } ++ } ++ ++ if (dev->gc_dirtiest > 0 && dev->gc_pages_in_use <= threshold) ++ selected = dev->gc_dirtiest; ++ } ++ ++ /* ++ * If nothing has been selected for a while, try the oldest dirty ++ * because that's gumming up the works. ++ */ ++ ++ if (!selected && dev->param.is_yaffs2 && ++ dev->gc_not_done >= (background ? 10 : 20)) { ++ yaffs2_find_oldest_dirty_seq(dev); ++ if (dev->oldest_dirty_block > 0) { ++ selected = dev->oldest_dirty_block; ++ dev->gc_dirtiest = selected; ++ dev->oldest_dirty_gc_count++; ++ bi = yaffs_get_block_info(dev, selected); ++ dev->gc_pages_in_use = ++ bi->pages_in_use - bi->soft_del_pages; ++ } else { ++ dev->gc_not_done = 0; ++ } ++ } ++ ++ if (selected) { ++ yaffs_trace(YAFFS_TRACE_GC, ++ "GC Selected block %d with %d free, prioritised:%d", ++ selected, ++ dev->param.chunks_per_block - dev->gc_pages_in_use, ++ prioritised); ++ ++ dev->n_gc_blocks++; ++ if (background) ++ dev->bg_gcs++; ++ ++ dev->gc_dirtiest = 0; ++ dev->gc_pages_in_use = 0; ++ dev->gc_not_done = 0; ++ if (dev->refresh_skip > 0) ++ dev->refresh_skip--; ++ } else { ++ dev->gc_not_done++; ++ yaffs_trace(YAFFS_TRACE_GC, ++ "GC none: finder %d skip %d threshold %d dirtiest %d using %d oldest %d%s", ++ dev->gc_block_finder, dev->gc_not_done, threshold, ++ dev->gc_dirtiest, dev->gc_pages_in_use, ++ dev->oldest_dirty_block, background ? " bg" : ""); ++ } ++ ++ return selected; ++} ++ ++/* New garbage collector ++ * If we're very low on erased blocks then we do aggressive garbage collection ++ * otherwise we do "leasurely" garbage collection. ++ * Aggressive gc looks further (whole array) and will accept less dirty blocks. ++ * Passive gc only inspects smaller areas and only accepts more dirty blocks. ++ * ++ * The idea is to help clear out space in a more spread-out manner. ++ * Dunno if it really does anything useful. ++ */ ++static int yaffs_check_gc(struct yaffs_dev *dev, int background) ++{ ++ int aggressive = 0; ++ int gc_ok = YAFFS_OK; ++ int max_tries = 0; ++ int min_erased; ++ int erased_chunks; ++ int checkpt_block_adjust; ++ ++ if (dev->param.gc_control_fn && ++ (dev->param.gc_control_fn(dev) & 1) == 0) ++ return YAFFS_OK; ++ ++ if (dev->gc_disable) ++ /* Bail out so we don't get recursive gc */ ++ return YAFFS_OK; ++ ++ /* This loop should pass the first time. ++ * Only loops here if the collection does not increase space. ++ */ ++ ++ do { ++ max_tries++; ++ ++ checkpt_block_adjust = yaffs_calc_checkpt_blocks_required(dev); ++ ++ min_erased = ++ dev->param.n_reserved_blocks + checkpt_block_adjust + 1; ++ erased_chunks = ++ dev->n_erased_blocks * dev->param.chunks_per_block; ++ ++ /* If we need a block soon then do aggressive gc. */ ++ if (dev->n_erased_blocks < min_erased) ++ aggressive = 1; ++ else { ++ if (!background ++ && erased_chunks > (dev->n_free_chunks / 4)) ++ break; ++ ++ if (dev->gc_skip > 20) ++ dev->gc_skip = 20; ++ if (erased_chunks < dev->n_free_chunks / 2 || ++ dev->gc_skip < 1 || background) ++ aggressive = 0; ++ else { ++ dev->gc_skip--; ++ break; ++ } ++ } ++ ++ dev->gc_skip = 5; ++ ++ /* If we don't already have a block being gc'd then see if we ++ * should start another */ ++ ++ if (dev->gc_block < 1 && !aggressive) { ++ dev->gc_block = yaffs2_find_refresh_block(dev); ++ dev->gc_chunk = 0; ++ dev->n_clean_ups = 0; ++ } ++ if (dev->gc_block < 1) { ++ dev->gc_block = ++ yaffs_find_gc_block(dev, aggressive, background); ++ dev->gc_chunk = 0; ++ dev->n_clean_ups = 0; ++ } ++ ++ if (dev->gc_block > 0) { ++ dev->all_gcs++; ++ if (!aggressive) ++ dev->passive_gc_count++; ++ ++ yaffs_trace(YAFFS_TRACE_GC, ++ "yaffs: GC n_erased_blocks %d aggressive %d", ++ dev->n_erased_blocks, aggressive); ++ ++ gc_ok = yaffs_gc_block(dev, dev->gc_block, aggressive); ++ } ++ ++ if (dev->n_erased_blocks < (int)dev->param.n_reserved_blocks && ++ dev->gc_block > 0) { ++ yaffs_trace(YAFFS_TRACE_GC, ++ "yaffs: GC !!!no reclaim!!! n_erased_blocks %d after try %d block %d", ++ dev->n_erased_blocks, max_tries, ++ dev->gc_block); ++ } ++ } while ((dev->n_erased_blocks < (int)dev->param.n_reserved_blocks) && ++ (dev->gc_block > 0) && (max_tries < 2)); ++ ++ return aggressive ? gc_ok : YAFFS_OK; ++} ++ ++/* ++ * yaffs_bg_gc() ++ * Garbage collects. Intended to be called from a background thread. ++ * Returns non-zero if at least half the free chunks are erased. ++ */ ++int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency) ++{ ++ int erased_chunks = dev->n_erased_blocks * dev->param.chunks_per_block; ++ ++ (void) urgency; ++ yaffs_trace(YAFFS_TRACE_BACKGROUND, "Background gc %u", urgency); ++ ++ yaffs_check_gc(dev, 1); ++ return erased_chunks > dev->n_free_chunks / 2; ++} ++ ++/*-------------------- Data file manipulation -----------------*/ ++ ++static int yaffs_rd_data_obj(struct yaffs_obj *in, int inode_chunk, u8 * buffer) ++{ ++ int nand_chunk = yaffs_find_chunk_in_file(in, inode_chunk, NULL); ++ ++ if (nand_chunk >= 0) ++ return yaffs_rd_chunk_tags_nand(in->my_dev, nand_chunk, ++ buffer, NULL); ++ else { ++ yaffs_trace(YAFFS_TRACE_NANDACCESS, ++ "Chunk %d not found zero instead", ++ nand_chunk); ++ /* get sane (zero) data if you read a hole */ ++ memset(buffer, 0, in->my_dev->data_bytes_per_chunk); ++ return 0; ++ } ++ ++} ++ ++void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash, ++ int lyn) ++{ ++ int block; ++ int page; ++ struct yaffs_ext_tags tags; ++ struct yaffs_block_info *bi; ++ ++ (void) lyn; ++ if (chunk_id <= 0) ++ return; ++ ++ dev->n_deletions++; ++ block = chunk_id / dev->param.chunks_per_block; ++ page = chunk_id % dev->param.chunks_per_block; ++ ++ if (!yaffs_check_chunk_bit(dev, block, page)) ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Deleting invalid chunk %d", chunk_id); ++ ++ bi = yaffs_get_block_info(dev, block); ++ ++ yaffs2_update_oldest_dirty_seq(dev, block, bi); ++ ++ yaffs_trace(YAFFS_TRACE_DELETION, ++ "line %d delete of chunk %d", ++ lyn, chunk_id); ++ ++ if (!dev->param.is_yaffs2 && mark_flash && ++ bi->block_state != YAFFS_BLOCK_STATE_COLLECTING) { ++ ++ memset(&tags, 0, sizeof(tags)); ++ tags.is_deleted = 1; ++ yaffs_wr_chunk_tags_nand(dev, chunk_id, NULL, &tags); ++ yaffs_handle_chunk_update(dev, chunk_id, &tags); ++ } else { ++ dev->n_unmarked_deletions++; ++ } ++ ++ /* Pull out of the management area. ++ * If the whole block became dirty, this will kick off an erasure. ++ */ ++ if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING || ++ bi->block_state == YAFFS_BLOCK_STATE_FULL || ++ bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN || ++ bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) { ++ dev->n_free_chunks++; ++ yaffs_clear_chunk_bit(dev, block, page); ++ bi->pages_in_use--; ++ ++ if (bi->pages_in_use == 0 && ++ !bi->has_shrink_hdr && ++ bi->block_state != YAFFS_BLOCK_STATE_ALLOCATING && ++ bi->block_state != YAFFS_BLOCK_STATE_NEEDS_SCAN) { ++ yaffs_block_became_dirty(dev, block); ++ } ++ } ++} ++ ++int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk, ++ const u8 *buffer, int n_bytes, int use_reserve) ++{ ++ /* Find old chunk Need to do this to get serial number ++ * Write new one and patch into tree. ++ * Invalidate old tags. ++ */ ++ ++ int prev_chunk_id; ++ struct yaffs_ext_tags prev_tags; ++ int new_chunk_id; ++ struct yaffs_ext_tags new_tags; ++ struct yaffs_dev *dev = in->my_dev; ++ loff_t endpos; ++ ++ yaffs_check_gc(dev, 0); ++ ++ /* Get the previous chunk at this location in the file if it exists. ++ * If it does not exist then put a zero into the tree. This creates ++ * the tnode now, rather than later when it is harder to clean up. ++ */ ++ prev_chunk_id = yaffs_find_chunk_in_file(in, inode_chunk, &prev_tags); ++ if (prev_chunk_id < 1 && ++ !yaffs_put_chunk_in_file(in, inode_chunk, 0, 0)) ++ return 0; ++ ++ /* Set up new tags */ ++ memset(&new_tags, 0, sizeof(new_tags)); ++ ++ new_tags.chunk_id = inode_chunk; ++ new_tags.obj_id = in->obj_id; ++ new_tags.serial_number = ++ (prev_chunk_id > 0) ? prev_tags.serial_number + 1 : 1; ++ new_tags.n_bytes = n_bytes; ++ ++ if (n_bytes < 1 || n_bytes > (int)dev->data_bytes_per_chunk) { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "Writing %d bytes to chunk!!!!!!!!!", ++ n_bytes); ++ BUG(); ++ } ++ ++ /* ++ * If this is a data chunk and the write goes past the end of the stored ++ * size then update the stored_size. ++ */ ++ if (inode_chunk > 0) { ++ endpos = (inode_chunk - 1) * dev->data_bytes_per_chunk + ++ n_bytes; ++ if (in->variant.file_variant.stored_size < endpos) ++ in->variant.file_variant.stored_size = endpos; ++ } ++ ++ new_chunk_id = ++ yaffs_write_new_chunk(dev, buffer, &new_tags, use_reserve); ++ ++ if (new_chunk_id > 0) { ++ yaffs_put_chunk_in_file(in, inode_chunk, new_chunk_id, 0); ++ ++ if (prev_chunk_id > 0) ++ yaffs_chunk_del(dev, prev_chunk_id, 1, __LINE__); ++ ++ yaffs_verify_file_sane(in); ++ } ++ return new_chunk_id; ++} ++ ++ ++ ++static int yaffs_do_xattrib_mod(struct yaffs_obj *obj, int set, ++ const YCHAR *name, const void *value, int size, ++ int flags) ++{ ++ struct yaffs_xattr_mod xmod; ++ int result; ++ ++ xmod.set = set; ++ xmod.name = name; ++ xmod.data = value; ++ xmod.size = size; ++ xmod.flags = flags; ++ xmod.result = -ENOSPC; ++ ++ result = yaffs_update_oh(obj, NULL, 0, 0, 0, &xmod); ++ ++ if (result > 0) ++ return xmod.result; ++ else ++ return -ENOSPC; ++} ++ ++static int yaffs_apply_xattrib_mod(struct yaffs_obj *obj, char *buffer, ++ struct yaffs_xattr_mod *xmod) ++{ ++ int retval = 0; ++ int x_offs = sizeof(struct yaffs_obj_hdr); ++ struct yaffs_dev *dev = obj->my_dev; ++ int x_size = dev->data_bytes_per_chunk - sizeof(struct yaffs_obj_hdr); ++ char *x_buffer = buffer + x_offs; ++ ++ if (xmod->set) ++ retval = ++ nval_set(dev, x_buffer, x_size, xmod->name, xmod->data, ++ xmod->size, xmod->flags); ++ else ++ retval = nval_del(dev, x_buffer, x_size, xmod->name); ++ ++ obj->has_xattr = nval_hasvalues(dev, x_buffer, x_size); ++ obj->xattr_known = 1; ++ xmod->result = retval; ++ ++ return retval; ++} ++ ++static int yaffs_do_xattrib_fetch(struct yaffs_obj *obj, const YCHAR *name, ++ void *value, int size) ++{ ++ char *buffer = NULL; ++ int result; ++ struct yaffs_ext_tags tags; ++ struct yaffs_dev *dev = obj->my_dev; ++ int x_offs = sizeof(struct yaffs_obj_hdr); ++ int x_size = dev->data_bytes_per_chunk - sizeof(struct yaffs_obj_hdr); ++ char *x_buffer; ++ int retval = 0; ++ ++ if (obj->hdr_chunk < 1) ++ return -ENODATA; ++ ++ /* If we know that the object has no xattribs then don't do all the ++ * reading and parsing. ++ */ ++ if (obj->xattr_known && !obj->has_xattr) { ++ if (name) ++ return -ENODATA; ++ else ++ return 0; ++ } ++ ++ buffer = (char *)yaffs_get_temp_buffer(dev); ++ if (!buffer) ++ return -ENOMEM; ++ ++ result = ++ yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, (u8 *) buffer, &tags); ++ ++ if (result != YAFFS_OK) ++ retval = -ENOENT; ++ else { ++ x_buffer = buffer + x_offs; ++ ++ if (!obj->xattr_known) { ++ obj->has_xattr = nval_hasvalues(dev, x_buffer, x_size); ++ obj->xattr_known = 1; ++ } ++ ++ if (name) ++ retval = nval_get(dev, x_buffer, x_size, ++ name, value, size); ++ else ++ retval = nval_list(dev, x_buffer, x_size, value, size); ++ } ++ yaffs_release_temp_buffer(dev, (u8 *) buffer); ++ return retval; ++} ++ ++int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR * name, ++ const void *value, int size, int flags) ++{ ++ return yaffs_do_xattrib_mod(obj, 1, name, value, size, flags); ++} ++ ++int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR * name) ++{ ++ return yaffs_do_xattrib_mod(obj, 0, name, NULL, 0, 0); ++} ++ ++int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR * name, void *value, ++ int size) ++{ ++ return yaffs_do_xattrib_fetch(obj, name, value, size); ++} ++ ++int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size) ++{ ++ return yaffs_do_xattrib_fetch(obj, NULL, buffer, size); ++} ++ ++static void yaffs_check_obj_details_loaded(struct yaffs_obj *in) ++{ ++ u8 *buf; ++ struct yaffs_obj_hdr *oh; ++ struct yaffs_dev *dev; ++ struct yaffs_ext_tags tags; ++ int result; ++ ++ if (!in || !in->lazy_loaded || in->hdr_chunk < 1) ++ return; ++ ++ dev = in->my_dev; ++ buf = yaffs_get_temp_buffer(dev); ++ ++ result = yaffs_rd_chunk_tags_nand(dev, in->hdr_chunk, buf, &tags); ++ ++ if (result == YAFFS_FAIL) ++ return; ++ ++ oh = (struct yaffs_obj_hdr *)buf; ++ ++ yaffs_do_endian_oh(dev, oh); ++ ++ in->lazy_loaded = 0; ++ in->yst_mode = oh->yst_mode; ++ yaffs_load_attribs(in, oh); ++ yaffs_set_obj_name_from_oh(in, oh); ++ ++ if (in->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) ++ in->variant.symlink_variant.alias = ++ yaffs_clone_str(oh->alias); ++ yaffs_release_temp_buffer(dev, buf); ++} ++ ++/* UpdateObjectHeader updates the header on NAND for an object. ++ * If name is not NULL, then that new name is used. ++ * ++ * We're always creating the obj header from scratch (except reading ++ * the old name) so first set up in cpu endianness then run it through ++ * endian fixing at the end. ++ * ++ * However, a twist: If there are xattribs we leave them as they were. ++ * ++ * Careful! The buffer holds the whole chunk. Part of the chunk holds the ++ * object header and the rest holds the xattribs, therefore we use a buffer ++ * pointer and an oh pointer to point to the same memory. ++ */ ++ ++int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name, int force, ++ int is_shrink, int shadows, struct yaffs_xattr_mod *xmod) ++{ ++ ++ struct yaffs_block_info *bi; ++ struct yaffs_dev *dev = in->my_dev; ++ int prev_chunk_id; ++ int ret_val = 0; ++ int result = 0; ++ int new_chunk_id; ++ struct yaffs_ext_tags new_tags; ++ struct yaffs_ext_tags old_tags; ++ const YCHAR *alias = NULL; ++ u8 *buffer = NULL; ++ YCHAR old_name[YAFFS_MAX_NAME_LENGTH + 1]; ++ struct yaffs_obj_hdr *oh = NULL; ++ loff_t file_size = 0; ++ ++ strcpy(old_name, _Y("silly old name")); ++ ++ if (in->fake && in != dev->root_dir && !force && !xmod) ++ return ret_val; ++ ++ yaffs_check_gc(dev, 0); ++ yaffs_check_obj_details_loaded(in); ++ ++ buffer = yaffs_get_temp_buffer(in->my_dev); ++ oh = (struct yaffs_obj_hdr *)buffer; ++ ++ prev_chunk_id = in->hdr_chunk; ++ ++ if (prev_chunk_id > 0) { ++ /* Access the old obj header just to read the name. */ ++ result = yaffs_rd_chunk_tags_nand(dev, prev_chunk_id, ++ buffer, &old_tags); ++ if (result == YAFFS_OK) { ++ yaffs_verify_oh(in, oh, &old_tags, 0); ++ memcpy(old_name, oh->name, sizeof(oh->name)); ++ ++ /* ++ * NB We only wipe the object header area because the rest of ++ * the buffer might contain xattribs. ++ */ ++ memset(oh, 0xff, sizeof(*oh)); ++ } ++ } else { ++ memset(buffer, 0xff, dev->data_bytes_per_chunk); ++ } ++ ++ oh->type = in->variant_type; ++ oh->yst_mode = in->yst_mode; ++ oh->shadows_obj = oh->inband_shadowed_obj_id = shadows; ++ ++ yaffs_load_attribs_oh(oh, in); ++ ++ if (in->parent) ++ oh->parent_obj_id = in->parent->obj_id; ++ else ++ oh->parent_obj_id = 0; ++ ++ if (name && *name) { ++ memset(oh->name, 0, sizeof(oh->name)); ++ yaffs_load_oh_from_name(dev, oh->name, name); ++ } else if (prev_chunk_id > 0) { ++ memcpy(oh->name, old_name, sizeof(oh->name)); ++ } else { ++ memset(oh->name, 0, sizeof(oh->name)); ++ } ++ ++ oh->is_shrink = is_shrink; ++ ++ switch (in->variant_type) { ++ case YAFFS_OBJECT_TYPE_UNKNOWN: ++ /* Should not happen */ ++ break; ++ case YAFFS_OBJECT_TYPE_FILE: ++ if (oh->parent_obj_id != YAFFS_OBJECTID_DELETED && ++ oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED) ++ file_size = in->variant.file_variant.stored_size; ++ yaffs_oh_size_load(dev, oh, file_size, 0); ++ break; ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ oh->equiv_id = in->variant.hardlink_variant.equiv_id; ++ break; ++ case YAFFS_OBJECT_TYPE_SPECIAL: ++ /* Do nothing */ ++ break; ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ /* Do nothing */ ++ break; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ alias = in->variant.symlink_variant.alias; ++ if (!alias) ++ alias = _Y("no alias"); ++ strncpy(oh->alias, alias, YAFFS_MAX_ALIAS_LENGTH); ++ oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0; ++ break; ++ } ++ ++ /* process any xattrib modifications */ ++ if (xmod) ++ yaffs_apply_xattrib_mod(in, (char *)buffer, xmod); ++ ++ /* Tags */ ++ memset(&new_tags, 0, sizeof(new_tags)); ++ in->serial++; ++ new_tags.chunk_id = 0; ++ new_tags.obj_id = in->obj_id; ++ new_tags.serial_number = in->serial; ++ ++ /* Add extra info for file header */ ++ new_tags.extra_available = 1; ++ new_tags.extra_parent_id = oh->parent_obj_id; ++ new_tags.extra_file_size = file_size; ++ new_tags.extra_is_shrink = oh->is_shrink; ++ new_tags.extra_equiv_id = oh->equiv_id; ++ new_tags.extra_shadows = (oh->shadows_obj > 0) ? 1 : 0; ++ new_tags.extra_obj_type = in->variant_type; ++ ++ /* Now endian swizzle the oh if needed. */ ++ yaffs_do_endian_oh(dev, oh); ++ ++ yaffs_verify_oh(in, oh, &new_tags, 1); ++ ++ /* Create new chunk in NAND */ ++ new_chunk_id = ++ yaffs_write_new_chunk(dev, buffer, &new_tags, ++ (prev_chunk_id > 0) ? 1 : 0); ++ ++ if (buffer) ++ yaffs_release_temp_buffer(dev, buffer); ++ ++ if (new_chunk_id < 0) ++ return new_chunk_id; ++ ++ in->hdr_chunk = new_chunk_id; ++ ++ if (prev_chunk_id > 0) ++ yaffs_chunk_del(dev, prev_chunk_id, 1, __LINE__); ++ ++ if (!yaffs_obj_cache_dirty(in)) ++ in->dirty = 0; ++ ++ /* If this was a shrink, then mark the block ++ * that the chunk lives on */ ++ if (is_shrink) { ++ bi = yaffs_get_block_info(in->my_dev, ++ new_chunk_id / ++ in->my_dev->param.chunks_per_block); ++ bi->has_shrink_hdr = 1; ++ } ++ ++ ++ return new_chunk_id; ++} ++ ++/*--------------------- File read/write ------------------------ ++ * Read and write have very similar structures. ++ * In general the read/write has three parts to it ++ * An incomplete chunk to start with (if the read/write is not chunk-aligned) ++ * Some complete chunks ++ * An incomplete chunk to end off with ++ * ++ * Curve-balls: the first chunk might also be the last chunk. ++ */ ++ ++int yaffs_file_rd(struct yaffs_obj *in, u8 * buffer, loff_t offset, int n_bytes) ++{ ++ int chunk; ++ u32 start; ++ int n_copy; ++ int n = n_bytes; ++ int n_done = 0; ++ struct yaffs_cache *cache; ++ struct yaffs_dev *dev; ++ ++ dev = in->my_dev; ++ ++ while (n > 0) { ++ yaffs_addr_to_chunk(dev, offset, &chunk, &start); ++ chunk++; ++ ++ /* OK now check for the curveball where the start and end are in ++ * the same chunk. ++ */ ++ if ((start + n) < dev->data_bytes_per_chunk) ++ n_copy = n; ++ else ++ n_copy = dev->data_bytes_per_chunk - start; ++ ++ cache = yaffs_find_chunk_cache(in, chunk); ++ ++ /* If the chunk is already in the cache or it is less than ++ * a whole chunk or we're using inband tags then use the cache ++ * (if there is caching) else bypass the cache. ++ */ ++ if (cache || n_copy != (int)dev->data_bytes_per_chunk || ++ dev->param.inband_tags) { ++ if (dev->param.n_caches > 0) { ++ ++ /* If we can't find the data in the cache, ++ * then load it up. */ ++ ++ if (!cache) { ++ cache = ++ yaffs_grab_chunk_cache(in->my_dev); ++ cache->object = in; ++ cache->chunk_id = chunk; ++ cache->dirty = 0; ++ cache->locked = 0; ++ yaffs_rd_data_obj(in, chunk, ++ cache->data); ++ cache->n_bytes = 0; ++ } ++ ++ yaffs_use_cache(dev, cache, 0); ++ ++ cache->locked = 1; ++ ++ memcpy(buffer, &cache->data[start], n_copy); ++ ++ cache->locked = 0; ++ } else { ++ /* Read into the local buffer then copy.. */ ++ ++ u8 *local_buffer = ++ yaffs_get_temp_buffer(dev); ++ yaffs_rd_data_obj(in, chunk, local_buffer); ++ ++ memcpy(buffer, &local_buffer[start], n_copy); ++ ++ yaffs_release_temp_buffer(dev, local_buffer); ++ } ++ } else { ++ /* A full chunk. Read directly into the buffer. */ ++ yaffs_rd_data_obj(in, chunk, buffer); ++ } ++ n -= n_copy; ++ offset += n_copy; ++ buffer += n_copy; ++ n_done += n_copy; ++ } ++ return n_done; ++} ++ ++int yaffs_do_file_wr(struct yaffs_obj *in, const u8 *buffer, loff_t offset, ++ int n_bytes, int write_through) ++{ ++ ++ int chunk; ++ u32 start; ++ int n_copy; ++ int n = n_bytes; ++ int n_done = 0; ++ int n_writeback; ++ loff_t start_write = offset; ++ int chunk_written = 0; ++ u32 n_bytes_read; ++ loff_t chunk_start; ++ struct yaffs_dev *dev; ++ ++ dev = in->my_dev; ++ ++ while (n > 0 && chunk_written >= 0) { ++ yaffs_addr_to_chunk(dev, offset, &chunk, &start); ++ ++ if (((loff_t)chunk) * ++ dev->data_bytes_per_chunk + start != offset || ++ start >= dev->data_bytes_per_chunk) { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "AddrToChunk of offset %lld gives chunk %d start %d", ++ (long long)offset, chunk, start); ++ } ++ chunk++; /* File pos to chunk in file offset */ ++ ++ /* OK now check for the curveball where the start and end are in ++ * the same chunk. ++ */ ++ ++ if ((start + n) < dev->data_bytes_per_chunk) { ++ n_copy = n; ++ ++ /* Now calculate how many bytes to write back.... ++ * If we're overwriting and not writing to then end of ++ * file then we need to write back as much as was there ++ * before. ++ */ ++ ++ chunk_start = (((loff_t)(chunk - 1)) * ++ dev->data_bytes_per_chunk); ++ ++ if (chunk_start > in->variant.file_variant.file_size) ++ n_bytes_read = 0; /* Past end of file */ ++ else ++ n_bytes_read = ++ in->variant.file_variant.file_size - ++ chunk_start; ++ ++ if (n_bytes_read > dev->data_bytes_per_chunk) ++ n_bytes_read = dev->data_bytes_per_chunk; ++ ++ n_writeback = ++ (n_bytes_read > ++ (start + n)) ? n_bytes_read : (start + n); ++ ++ if (n_writeback < 0 || ++ n_writeback > (int)dev->data_bytes_per_chunk) ++ BUG(); ++ ++ } else { ++ n_copy = dev->data_bytes_per_chunk - start; ++ n_writeback = dev->data_bytes_per_chunk; ++ } ++ ++ if (n_copy != (int)dev->data_bytes_per_chunk || ++ !dev->param.cache_bypass_aligned || ++ dev->param.inband_tags) { ++ /* An incomplete start or end chunk (or maybe both ++ * start and end chunk), or we're using inband tags, ++ * or we're forcing writes through the cache, ++ * so we want to use the cache buffers. ++ */ ++ if (dev->param.n_caches > 0) { ++ struct yaffs_cache *cache; ++ ++ /* If we can't find the data in the cache, then ++ * load the cache */ ++ cache = yaffs_find_chunk_cache(in, chunk); ++ ++ if (!cache && ++ yaffs_check_alloc_available(dev, 1)) { ++ cache = yaffs_grab_chunk_cache(dev); ++ cache->object = in; ++ cache->chunk_id = chunk; ++ cache->dirty = 0; ++ cache->locked = 0; ++ yaffs_rd_data_obj(in, chunk, ++ cache->data); ++ } else if (cache && ++ !cache->dirty && ++ !yaffs_check_alloc_available(dev, ++ 1)) { ++ /* Drop the cache if it was a read cache ++ * item and no space check has been made ++ * for it. ++ */ ++ cache = NULL; ++ } ++ ++ if (cache) { ++ yaffs_use_cache(dev, cache, 1); ++ cache->locked = 1; ++ ++ memcpy(&cache->data[start], buffer, ++ n_copy); ++ ++ cache->locked = 0; ++ cache->n_bytes = n_writeback; ++ ++ if (write_through) { ++ chunk_written = ++ yaffs_wr_data_obj ++ (cache->object, ++ cache->chunk_id, ++ cache->data, ++ cache->n_bytes, 1); ++ cache->dirty = 0; ++ } ++ } else { ++ chunk_written = -1; /* fail write */ ++ } ++ } else { ++ /* An incomplete start or end chunk (or maybe ++ * both start and end chunk). Read into the ++ * local buffer then copy over and write back. ++ */ ++ ++ u8 *local_buffer = yaffs_get_temp_buffer(dev); ++ ++ yaffs_rd_data_obj(in, chunk, local_buffer); ++ memcpy(&local_buffer[start], buffer, n_copy); ++ ++ chunk_written = ++ yaffs_wr_data_obj(in, chunk, ++ local_buffer, ++ n_writeback, 0); ++ ++ yaffs_release_temp_buffer(dev, local_buffer); ++ } ++ } else { ++ /* A full chunk. Write directly from the buffer. */ ++ ++ chunk_written = ++ yaffs_wr_data_obj(in, chunk, buffer, ++ dev->data_bytes_per_chunk, 0); ++ ++ /* Since we've overwritten the cached data, ++ * we better invalidate it. */ ++ yaffs_invalidate_chunk_cache(in, chunk); ++ } ++ ++ if (chunk_written >= 0) { ++ n -= n_copy; ++ offset += n_copy; ++ buffer += n_copy; ++ n_done += n_copy; ++ } ++ } ++ ++ /* Update file object */ ++ ++ if ((start_write + n_done) > in->variant.file_variant.file_size) ++ in->variant.file_variant.file_size = (start_write + n_done); ++ ++ in->dirty = 1; ++ return n_done; ++} ++ ++int yaffs_wr_file(struct yaffs_obj *in, const u8 *buffer, loff_t offset, ++ int n_bytes, int write_through) ++{ ++ yaffs2_handle_hole(in, offset); ++ return yaffs_do_file_wr(in, buffer, offset, n_bytes, write_through); ++} ++ ++/* ---------------------- File resizing stuff ------------------ */ ++ ++static void yaffs_prune_chunks(struct yaffs_obj *in, loff_t new_size) ++{ ++ ++ struct yaffs_dev *dev = in->my_dev; ++ loff_t old_size = in->variant.file_variant.file_size; ++ int i; ++ int chunk_id; ++ u32 dummy; ++ int last_del; ++ int start_del; ++ ++ if (old_size > 0) ++ yaffs_addr_to_chunk(dev, old_size - 1, &last_del, &dummy); ++ else ++ last_del = 0; ++ ++ yaffs_addr_to_chunk(dev, new_size + dev->data_bytes_per_chunk - 1, ++ &start_del, &dummy); ++ last_del++; ++ start_del++; ++ ++ /* Delete backwards so that we don't end up with holes if ++ * power is lost part-way through the operation. ++ */ ++ for (i = last_del; i >= start_del; i--) { ++ /* NB this could be optimised somewhat, ++ * eg. could retrieve the tags and write them without ++ * using yaffs_chunk_del ++ */ ++ ++ chunk_id = yaffs_find_del_file_chunk(in, i, NULL); ++ ++ if (chunk_id < 1) ++ continue; ++ ++ if ((u32)chunk_id < ++ (dev->internal_start_block * dev->param.chunks_per_block) || ++ (u32)chunk_id >= ++ ((dev->internal_end_block + 1) * ++ dev->param.chunks_per_block)) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "Found daft chunk_id %d for %d", ++ chunk_id, i); ++ } else { ++ in->n_data_chunks--; ++ yaffs_chunk_del(dev, chunk_id, 1, __LINE__); ++ } ++ } ++} ++ ++void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size) ++{ ++ int new_full; ++ u32 new_partial; ++ struct yaffs_dev *dev = obj->my_dev; ++ ++ yaffs_addr_to_chunk(dev, new_size, &new_full, &new_partial); ++ ++ yaffs_prune_chunks(obj, new_size); ++ ++ if (new_partial != 0) { ++ int last_chunk = 1 + new_full; ++ u8 *local_buffer = yaffs_get_temp_buffer(dev); ++ ++ /* Rewrite the last chunk with its new size and zero pad */ ++ yaffs_rd_data_obj(obj, last_chunk, local_buffer); ++ memset(local_buffer + new_partial, 0, ++ dev->data_bytes_per_chunk - new_partial); ++ ++ yaffs_wr_data_obj(obj, last_chunk, local_buffer, ++ new_partial, 1); ++ ++ yaffs_release_temp_buffer(dev, local_buffer); ++ } ++ ++ obj->variant.file_variant.file_size = new_size; ++ obj->variant.file_variant.stored_size = new_size; ++ ++ yaffs_prune_tree(dev, &obj->variant.file_variant); ++} ++ ++int yaffs_resize_file(struct yaffs_obj *in, loff_t new_size) ++{ ++ struct yaffs_dev *dev = in->my_dev; ++ loff_t old_size = in->variant.file_variant.file_size; ++ ++ yaffs_flush_file_cache(in, 1); ++ yaffs_invalidate_file_cache(in); ++ ++ yaffs_check_gc(dev, 0); ++ ++ if (in->variant_type != YAFFS_OBJECT_TYPE_FILE) ++ return YAFFS_FAIL; ++ ++ if (new_size == old_size) ++ return YAFFS_OK; ++ ++ if (new_size > old_size) { ++ yaffs2_handle_hole(in, new_size); ++ in->variant.file_variant.file_size = new_size; ++ } else { ++ /* new_size < old_size */ ++ yaffs_resize_file_down(in, new_size); ++ } ++ ++ /* Write a new object header to reflect the resize. ++ * show we've shrunk the file, if need be ++ * Do this only if the file is not in the deleted directories ++ * and is not shadowed. ++ */ ++ if (in->parent && ++ !in->is_shadowed && ++ in->parent->obj_id != YAFFS_OBJECTID_UNLINKED && ++ in->parent->obj_id != YAFFS_OBJECTID_DELETED) ++ yaffs_update_oh(in, NULL, 0, 0, 0, NULL); ++ ++ return YAFFS_OK; ++} ++ ++int yaffs_flush_file(struct yaffs_obj *in, ++ int update_time, ++ int data_sync, ++ int discard_cache) ++{ ++ if (!in->dirty) ++ return YAFFS_OK; ++ ++ yaffs_flush_file_cache(in, discard_cache); ++ ++ if (data_sync) ++ return YAFFS_OK; ++ ++ if (update_time) ++ yaffs_load_current_time(in, 0, 0); ++ ++ return (yaffs_update_oh(in, NULL, 0, 0, 0, NULL) >= 0) ? ++ YAFFS_OK : YAFFS_FAIL; ++} ++ ++ ++/* yaffs_del_file deletes the whole file data ++ * and the inode associated with the file. ++ * It does not delete the links associated with the file. ++ */ ++static int yaffs_unlink_file_if_needed(struct yaffs_obj *in) ++{ ++ int ret_val; ++ int del_now = 0; ++ struct yaffs_dev *dev = in->my_dev; ++ ++ if (!in->my_inode) ++ del_now = 1; ++ ++ if (del_now) { ++ ret_val = ++ yaffs_change_obj_name(in, in->my_dev->del_dir, ++ _Y("deleted"), 0, 0); ++ yaffs_trace(YAFFS_TRACE_TRACING, ++ "yaffs: immediate deletion of file %d", ++ in->obj_id); ++ in->deleted = 1; ++ in->my_dev->n_deleted_files++; ++ if (dev->param.disable_soft_del || dev->param.is_yaffs2) ++ yaffs_resize_file(in, 0); ++ yaffs_soft_del_file(in); ++ } else { ++ ret_val = ++ yaffs_change_obj_name(in, in->my_dev->unlinked_dir, ++ _Y("unlinked"), 0, 0); ++ } ++ return ret_val; ++} ++ ++static int yaffs_del_file(struct yaffs_obj *in) ++{ ++ int ret_val = YAFFS_OK; ++ int deleted; /* Need to cache value on stack if in is freed */ ++ struct yaffs_dev *dev = in->my_dev; ++ ++ if (dev->param.disable_soft_del || dev->param.is_yaffs2) ++ yaffs_resize_file(in, 0); ++ ++ if (in->n_data_chunks > 0) { ++ /* Use soft deletion if there is data in the file. ++ * That won't be the case if it has been resized to zero. ++ */ ++ if (!in->unlinked) ++ ret_val = yaffs_unlink_file_if_needed(in); ++ ++ deleted = in->deleted; ++ ++ if (ret_val == YAFFS_OK && in->unlinked && !in->deleted) { ++ in->deleted = 1; ++ deleted = 1; ++ in->my_dev->n_deleted_files++; ++ yaffs_soft_del_file(in); ++ } ++ return deleted ? YAFFS_OK : YAFFS_FAIL; ++ } else { ++ /* The file has no data chunks so we toss it immediately */ ++ yaffs_free_tnode(in->my_dev, in->variant.file_variant.top); ++ in->variant.file_variant.top = NULL; ++ yaffs_generic_obj_del(in); ++ ++ return YAFFS_OK; ++ } ++} ++ ++int yaffs_is_non_empty_dir(struct yaffs_obj *obj) ++{ ++ return (obj && ++ obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) && ++ !(list_empty(&obj->variant.dir_variant.children)); ++} ++ ++static int yaffs_del_dir(struct yaffs_obj *obj) ++{ ++ /* First check that the directory is empty. */ ++ if (yaffs_is_non_empty_dir(obj)) ++ return YAFFS_FAIL; ++ ++ return yaffs_generic_obj_del(obj); ++} ++ ++static int yaffs_del_symlink(struct yaffs_obj *in) ++{ ++ kfree(in->variant.symlink_variant.alias); ++ in->variant.symlink_variant.alias = NULL; ++ ++ return yaffs_generic_obj_del(in); ++} ++ ++static int yaffs_del_link(struct yaffs_obj *in) ++{ ++ /* remove this hardlink from the list associated with the equivalent ++ * object ++ */ ++ list_del_init(&in->hard_links); ++ return yaffs_generic_obj_del(in); ++} ++ ++int yaffs_del_obj(struct yaffs_obj *obj) ++{ ++ int ret_val = -1; ++ ++ switch (obj->variant_type) { ++ case YAFFS_OBJECT_TYPE_FILE: ++ ret_val = yaffs_del_file(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ if (!list_empty(&obj->variant.dir_variant.dirty)) { ++ yaffs_trace(YAFFS_TRACE_BACKGROUND, ++ "Remove object %d from dirty directories", ++ obj->obj_id); ++ list_del_init(&obj->variant.dir_variant.dirty); ++ } ++ return yaffs_del_dir(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ ret_val = yaffs_del_symlink(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ ret_val = yaffs_del_link(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_SPECIAL: ++ ret_val = yaffs_generic_obj_del(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_UNKNOWN: ++ ret_val = 0; ++ break; /* should not happen. */ ++ } ++ return ret_val; ++} ++ ++ ++static void yaffs_empty_dir_to_dir(struct yaffs_obj *from_dir, ++ struct yaffs_obj *to_dir) ++{ ++ struct yaffs_obj *obj; ++ struct list_head *lh; ++ struct list_head *n; ++ ++ list_for_each_safe(lh, n, &from_dir->variant.dir_variant.children) { ++ obj = list_entry(lh, struct yaffs_obj, siblings); ++ yaffs_add_obj_to_dir(to_dir, obj); ++ } ++} ++ ++struct yaffs_obj *yaffs_retype_obj(struct yaffs_obj *obj, ++ enum yaffs_obj_type type) ++{ ++ /* Tear down the old variant */ ++ switch (obj->variant_type) { ++ case YAFFS_OBJECT_TYPE_FILE: ++ /* Nuke file data */ ++ yaffs_resize_file(obj, 0); ++ yaffs_free_tnode(obj->my_dev, obj->variant.file_variant.top); ++ obj->variant.file_variant.top = NULL; ++ break; ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ /* Put the children in lost and found. */ ++ yaffs_empty_dir_to_dir(obj, obj->my_dev->lost_n_found); ++ if (!list_empty(&obj->variant.dir_variant.dirty)) ++ list_del_init(&obj->variant.dir_variant.dirty); ++ break; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ /* Nuke symplink data */ ++ kfree(obj->variant.symlink_variant.alias); ++ obj->variant.symlink_variant.alias = NULL; ++ break; ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ list_del_init(&obj->hard_links); ++ break; ++ default: ++ break; ++ } ++ ++ memset(&obj->variant, 0, sizeof(obj->variant)); ++ ++ /*Set up new variant if the memset is not enough. */ ++ switch (type) { ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ INIT_LIST_HEAD(&obj->variant.dir_variant.children); ++ INIT_LIST_HEAD(&obj->variant.dir_variant.dirty); ++ break; ++ case YAFFS_OBJECT_TYPE_FILE: ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ default: ++ break; ++ } ++ ++ obj->variant_type = type; ++ ++ return obj; ++ ++} ++ ++static int yaffs_unlink_worker(struct yaffs_obj *obj) ++{ ++ int del_now = 0; ++ ++ if (!obj) ++ return YAFFS_FAIL; ++ ++ if (!obj->my_inode) ++ del_now = 1; ++ ++ yaffs_update_parent(obj->parent); ++ ++ if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) { ++ return yaffs_del_link(obj); ++ } else if (!list_empty(&obj->hard_links)) { ++ /* Curve ball: We're unlinking an object that has a hardlink. ++ * ++ * This problem arises because we are not strictly following ++ * The Linux link/inode model. ++ * ++ * We can't really delete the object. ++ * Instead, we do the following: ++ * - Select a hardlink. ++ * - Unhook it from the hard links ++ * - Move it from its parent directory so that the rename works. ++ * - Rename the object to the hardlink's name. ++ * - Delete the hardlink ++ */ ++ ++ struct yaffs_obj *hl; ++ struct yaffs_obj *parent; ++ int ret_val; ++ YCHAR name[YAFFS_MAX_NAME_LENGTH + 1]; ++ ++ hl = list_entry(obj->hard_links.next, struct yaffs_obj, ++ hard_links); ++ ++ yaffs_get_obj_name(hl, name, YAFFS_MAX_NAME_LENGTH + 1); ++ parent = hl->parent; ++ ++ list_del_init(&hl->hard_links); ++ ++ yaffs_add_obj_to_dir(obj->my_dev->unlinked_dir, hl); ++ ++ ret_val = yaffs_change_obj_name(obj, parent, name, 0, 0); ++ ++ if (ret_val == YAFFS_OK) ++ ret_val = yaffs_generic_obj_del(hl); ++ ++ return ret_val; ++ ++ } else if (del_now) { ++ switch (obj->variant_type) { ++ case YAFFS_OBJECT_TYPE_FILE: ++ return yaffs_del_file(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ list_del_init(&obj->variant.dir_variant.dirty); ++ return yaffs_del_dir(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ return yaffs_del_symlink(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_SPECIAL: ++ return yaffs_generic_obj_del(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ case YAFFS_OBJECT_TYPE_UNKNOWN: ++ default: ++ return YAFFS_FAIL; ++ } ++ } else if (yaffs_is_non_empty_dir(obj)) { ++ return YAFFS_FAIL; ++ } else { ++ return yaffs_change_obj_name(obj, obj->my_dev->unlinked_dir, ++ _Y("unlinked"), 0, 0); ++ } ++} ++ ++int yaffs_unlink_obj(struct yaffs_obj *obj) ++{ ++ if (obj && obj->unlink_allowed) ++ return yaffs_unlink_worker(obj); ++ ++ return YAFFS_FAIL; ++} ++ ++int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR *name) ++{ ++ struct yaffs_obj *obj; ++ ++ obj = yaffs_find_by_name(dir, name); ++ return yaffs_unlink_obj(obj); ++} ++ ++/* Note: ++ * If old_name is NULL then we take old_dir as the object to be renamed. ++ */ ++int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR *old_name, ++ struct yaffs_obj *new_dir, const YCHAR *new_name) ++{ ++ struct yaffs_obj *obj = NULL; ++ struct yaffs_obj *existing_target = NULL; ++ int force = 0; ++ int result; ++ struct yaffs_dev *dev; ++ ++ if (!old_dir || old_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { ++ BUG(); ++ return YAFFS_FAIL; ++ } ++ if (!new_dir || new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { ++ BUG(); ++ return YAFFS_FAIL; ++ } ++ ++ dev = old_dir->my_dev; ++ ++#ifdef CONFIG_YAFFS_CASE_INSENSITIVE ++ /* Special case for case insemsitive systems. ++ * While look-up is case insensitive, the name isn't. ++ * Therefore we might want to change x.txt to X.txt ++ */ ++ if (old_dir == new_dir && ++ old_name && new_name && ++ strcmp(old_name, new_name) == 0) ++ force = 1; ++#endif ++ ++ if (strnlen(new_name, YAFFS_MAX_NAME_LENGTH + 1) > ++ YAFFS_MAX_NAME_LENGTH) ++ /* ENAMETOOLONG */ ++ return YAFFS_FAIL; ++ ++ if (old_name) ++ obj = yaffs_find_by_name(old_dir, old_name); ++ else{ ++ obj = old_dir; ++ old_dir = obj->parent; ++ } ++ ++ if (obj && obj->rename_allowed) { ++ /* Now handle an existing target, if there is one */ ++ existing_target = yaffs_find_by_name(new_dir, new_name); ++ if (yaffs_is_non_empty_dir(existing_target)) { ++ return YAFFS_FAIL; /* ENOTEMPTY */ ++ } else if (existing_target && existing_target != obj) { ++ /* Nuke the target first, using shadowing, ++ * but only if it isn't the same object. ++ * ++ * Note we must disable gc here otherwise it can mess ++ * up the shadowing. ++ * ++ */ ++ dev->gc_disable = 1; ++ yaffs_change_obj_name(obj, new_dir, new_name, force, ++ existing_target->obj_id); ++ existing_target->is_shadowed = 1; ++ yaffs_unlink_obj(existing_target); ++ dev->gc_disable = 0; ++ } ++ ++ result = yaffs_change_obj_name(obj, new_dir, new_name, 1, 0); ++ ++ yaffs_update_parent(old_dir); ++ if (new_dir != old_dir) ++ yaffs_update_parent(new_dir); ++ ++ return result; ++ } ++ return YAFFS_FAIL; ++} ++ ++/*----------------------- Initialisation Scanning ---------------------- */ ++ ++void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id, ++ int backward_scanning) ++{ ++ struct yaffs_obj *obj; ++ ++ if (backward_scanning) { ++ /* Handle YAFFS2 case (backward scanning) ++ * If the shadowed object exists then ignore. ++ */ ++ obj = yaffs_find_by_number(dev, obj_id); ++ if (obj) ++ return; ++ } ++ ++ /* Let's create it (if it does not exist) assuming it is a file so that ++ * it can do shrinking etc. ++ * We put it in unlinked dir to be cleaned up after the scanning ++ */ ++ obj = ++ yaffs_find_or_create_by_number(dev, obj_id, YAFFS_OBJECT_TYPE_FILE); ++ if (!obj) ++ return; ++ obj->is_shadowed = 1; ++ yaffs_add_obj_to_dir(dev->unlinked_dir, obj); ++ obj->variant.file_variant.shrink_size = 0; ++ obj->valid = 1; /* So that we don't read any other info. */ ++} ++ ++void yaffs_link_fixup(struct yaffs_dev *dev, struct list_head *hard_list) ++{ ++ struct list_head *lh; ++ struct list_head *save; ++ struct yaffs_obj *hl; ++ struct yaffs_obj *in; ++ ++ list_for_each_safe(lh, save, hard_list) { ++ hl = list_entry(lh, struct yaffs_obj, hard_links); ++ in = yaffs_find_by_number(dev, ++ hl->variant.hardlink_variant.equiv_id); ++ ++ if (in) { ++ /* Add the hardlink pointers */ ++ hl->variant.hardlink_variant.equiv_obj = in; ++ list_add(&hl->hard_links, &in->hard_links); ++ } else { ++ /* Todo Need to report/handle this better. ++ * Got a problem... hardlink to a non-existant object ++ */ ++ hl->variant.hardlink_variant.equiv_obj = NULL; ++ INIT_LIST_HEAD(&hl->hard_links); ++ } ++ } ++} ++ ++static void yaffs_strip_deleted_objs(struct yaffs_dev *dev) ++{ ++ /* ++ * Sort out state of unlinked and deleted objects after scanning. ++ */ ++ struct list_head *i; ++ struct list_head *n; ++ struct yaffs_obj *l; ++ ++ if (dev->read_only) ++ return; ++ ++ /* Soft delete all the unlinked files */ ++ list_for_each_safe(i, n, ++ &dev->unlinked_dir->variant.dir_variant.children) { ++ l = list_entry(i, struct yaffs_obj, siblings); ++ yaffs_del_obj(l); ++ } ++ ++ list_for_each_safe(i, n, &dev->del_dir->variant.dir_variant.children) { ++ l = list_entry(i, struct yaffs_obj, siblings); ++ yaffs_del_obj(l); ++ } ++} ++ ++/* ++ * This code iterates through all the objects making sure that they are rooted. ++ * Any unrooted objects are re-rooted in lost+found. ++ * An object needs to be in one of: ++ * - Directly under deleted, unlinked ++ * - Directly or indirectly under root. ++ * ++ * Note: ++ * This code assumes that we don't ever change the current relationships ++ * between directories: ++ * root_dir->parent == unlinked_dir->parent == del_dir->parent == NULL ++ * lost-n-found->parent == root_dir ++ * ++ * This fixes the problem where directories might have inadvertently been ++ * deleted leaving the object "hanging" without being rooted in the ++ * directory tree. ++ */ ++ ++static int yaffs_has_null_parent(struct yaffs_dev *dev, struct yaffs_obj *obj) ++{ ++ return (obj == dev->del_dir || ++ obj == dev->unlinked_dir || obj == dev->root_dir); ++} ++ ++static void yaffs_fix_hanging_objs(struct yaffs_dev *dev) ++{ ++ struct yaffs_obj *obj; ++ struct yaffs_obj *parent; ++ int i; ++ struct list_head *lh; ++ struct list_head *n; ++ int depth_limit; ++ int hanging; ++ ++ if (dev->read_only) ++ return; ++ ++ /* Iterate through the objects in each hash entry, ++ * looking at each object. ++ * Make sure it is rooted. ++ */ ++ ++ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) { ++ list_for_each_safe(lh, n, &dev->obj_bucket[i].list) { ++ obj = list_entry(lh, struct yaffs_obj, hash_link); ++ parent = obj->parent; ++ ++ if (yaffs_has_null_parent(dev, obj)) { ++ /* These directories are not hanging */ ++ hanging = 0; ++ } else if (!parent || ++ parent->variant_type != ++ YAFFS_OBJECT_TYPE_DIRECTORY) { ++ hanging = 1; ++ } else if (yaffs_has_null_parent(dev, parent)) { ++ hanging = 0; ++ } else { ++ /* ++ * Need to follow the parent chain to ++ * see if it is hanging. ++ */ ++ hanging = 0; ++ depth_limit = 100; ++ ++ while (parent != dev->root_dir && ++ parent->parent && ++ parent->parent->variant_type == ++ YAFFS_OBJECT_TYPE_DIRECTORY && ++ depth_limit > 0) { ++ parent = parent->parent; ++ depth_limit--; ++ } ++ if (parent != dev->root_dir) ++ hanging = 1; ++ } ++ if (hanging) { ++ yaffs_trace(YAFFS_TRACE_SCAN, ++ "Hanging object %d moved to lost and found", ++ obj->obj_id); ++ yaffs_add_obj_to_dir(dev->lost_n_found, obj); ++ } ++ } ++ } ++} ++ ++/* ++ * Delete directory contents for cleaning up lost and found. ++ */ ++static void yaffs_del_dir_contents(struct yaffs_obj *dir) ++{ ++ struct yaffs_obj *obj; ++ struct list_head *lh; ++ struct list_head *n; ++ ++ if (dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) ++ BUG(); ++ ++ list_for_each_safe(lh, n, &dir->variant.dir_variant.children) { ++ obj = list_entry(lh, struct yaffs_obj, siblings); ++ if (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) ++ yaffs_del_dir_contents(obj); ++ yaffs_trace(YAFFS_TRACE_SCAN, ++ "Deleting lost_found object %d", ++ obj->obj_id); ++ yaffs_unlink_obj(obj); ++ } ++} ++ ++static void yaffs_empty_l_n_f(struct yaffs_dev *dev) ++{ ++ yaffs_del_dir_contents(dev->lost_n_found); ++} ++ ++ ++struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *directory, ++ const YCHAR *name) ++{ ++ int sum; ++ struct list_head *i; ++ YCHAR buffer[YAFFS_MAX_NAME_LENGTH + 1]; ++ struct yaffs_obj *l; ++ ++ if (!name) ++ return NULL; ++ ++ if (!directory) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "tragedy: yaffs_find_by_name: null pointer directory" ++ ); ++ BUG(); ++ return NULL; ++ } ++ if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "tragedy: yaffs_find_by_name: non-directory" ++ ); ++ BUG(); ++ } ++ ++ sum = yaffs_calc_name_sum(name); ++ ++ list_for_each(i, &directory->variant.dir_variant.children) { ++ l = list_entry(i, struct yaffs_obj, siblings); ++ ++ if (l->parent != directory) ++ BUG(); ++ ++ yaffs_check_obj_details_loaded(l); ++ ++ /* Special case for lost-n-found */ ++ if (l->obj_id == YAFFS_OBJECTID_LOSTNFOUND) { ++ if (!strcmp(name, YAFFS_LOSTNFOUND_NAME)) ++ return l; ++ } else if (l->sum == sum || l->hdr_chunk <= 0) { ++ /* LostnFound chunk called Objxxx ++ * Do a real check ++ */ ++ yaffs_get_obj_name(l, buffer, ++ YAFFS_MAX_NAME_LENGTH + 1); ++ if (!strncmp(name, buffer, YAFFS_MAX_NAME_LENGTH)) ++ return l; ++ } ++ } ++ return NULL; ++} ++ ++/* GetEquivalentObject dereferences any hard links to get to the ++ * actual object. ++ */ ++ ++struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj) ++{ ++ if (obj && obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) { ++ obj = obj->variant.hardlink_variant.equiv_obj; ++ yaffs_check_obj_details_loaded(obj); ++ } ++ return obj; ++} ++ ++/* ++ * A note or two on object names. ++ * * If the object name is missing, we then make one up in the form objnnn ++ * ++ * * ASCII names are stored in the object header's name field from byte zero ++ * * Unicode names are historically stored starting from byte zero. ++ * ++ * Then there are automatic Unicode names... ++ * The purpose of these is to save names in a way that can be read as ++ * ASCII or Unicode names as appropriate, thus allowing a Unicode and ASCII ++ * system to share files. ++ * ++ * These automatic unicode are stored slightly differently... ++ * - If the name can fit in the ASCII character space then they are saved as ++ * ascii names as per above. ++ * - If the name needs Unicode then the name is saved in Unicode ++ * starting at oh->name[1]. ++ ++ */ ++static void yaffs_fix_null_name(struct yaffs_obj *obj, YCHAR *name, ++ int buffer_size) ++{ ++ /* Create an object name if we could not find one. */ ++ if (strnlen(name, YAFFS_MAX_NAME_LENGTH) == 0) { ++ YCHAR local_name[20]; ++ YCHAR num_string[20]; ++ YCHAR *x = &num_string[19]; ++ unsigned v = obj->obj_id; ++ num_string[19] = 0; ++ while (v > 0) { ++ x--; ++ *x = '0' + (v % 10); ++ v /= 10; ++ } ++ /* make up a name */ ++ strcpy(local_name, YAFFS_LOSTNFOUND_PREFIX); ++ strcat(local_name, x); ++ strncpy(name, local_name, buffer_size - 1); ++ } ++} ++ ++int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR *name, int buffer_size) ++{ ++ memset(name, 0, buffer_size * sizeof(YCHAR)); ++ yaffs_check_obj_details_loaded(obj); ++ if (obj->obj_id == YAFFS_OBJECTID_LOSTNFOUND) { ++ strncpy(name, YAFFS_LOSTNFOUND_NAME, buffer_size - 1); ++ } else if (obj->short_name[0]) { ++ strcpy(name, obj->short_name); ++ } else if (obj->hdr_chunk > 0) { ++ int result; ++ u8 *buffer = yaffs_get_temp_buffer(obj->my_dev); ++ ++ struct yaffs_obj_hdr *oh = (struct yaffs_obj_hdr *)buffer; ++ ++ memset(buffer, 0, obj->my_dev->data_bytes_per_chunk); ++ ++ if (obj->hdr_chunk > 0) { ++ result = yaffs_rd_chunk_tags_nand(obj->my_dev, ++ obj->hdr_chunk, buffer, NULL); ++ if (result == YAFFS_OK) ++ yaffs_load_name_from_oh(obj->my_dev, name, ++ oh->name, buffer_size); ++ } ++ yaffs_release_temp_buffer(obj->my_dev, buffer); ++ } ++ ++ yaffs_fix_null_name(obj, name, buffer_size); ++ ++ return strnlen(name, YAFFS_MAX_NAME_LENGTH); ++} ++ ++loff_t yaffs_get_obj_length(struct yaffs_obj *obj) ++{ ++ /* Dereference any hard linking */ ++ obj = yaffs_get_equivalent_obj(obj); ++ ++ if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) ++ return obj->variant.file_variant.file_size; ++ if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) { ++ if (!obj->variant.symlink_variant.alias) ++ return 0; ++ return strnlen(obj->variant.symlink_variant.alias, ++ YAFFS_MAX_ALIAS_LENGTH); ++ } else { ++ /* Only a directory should drop through to here */ ++ return obj->my_dev->data_bytes_per_chunk; ++ } ++} ++ ++int yaffs_get_obj_link_count(struct yaffs_obj *obj) ++{ ++ int count = 0; ++ struct list_head *i; ++ ++ if (!obj->unlinked) ++ count++; /* the object itself */ ++ ++ list_for_each(i, &obj->hard_links) ++ count++; /* add the hard links; */ ++ ++ return count; ++} ++ ++int yaffs_get_obj_inode(struct yaffs_obj *obj) ++{ ++ obj = yaffs_get_equivalent_obj(obj); ++ ++ return obj->obj_id; ++} ++ ++unsigned yaffs_get_obj_type(struct yaffs_obj *obj) ++{ ++ obj = yaffs_get_equivalent_obj(obj); ++ ++ switch (obj->variant_type) { ++ case YAFFS_OBJECT_TYPE_FILE: ++ return DT_REG; ++ break; ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ return DT_DIR; ++ break; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ return DT_LNK; ++ break; ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ return DT_REG; ++ break; ++ case YAFFS_OBJECT_TYPE_SPECIAL: ++ if (S_ISFIFO(obj->yst_mode)) ++ return DT_FIFO; ++ if (S_ISCHR(obj->yst_mode)) ++ return DT_CHR; ++ if (S_ISBLK(obj->yst_mode)) ++ return DT_BLK; ++ if (S_ISSOCK(obj->yst_mode)) ++ return DT_SOCK; ++ return DT_REG; ++ break; ++ default: ++ return DT_REG; ++ break; ++ } ++} ++ ++YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj) ++{ ++ obj = yaffs_get_equivalent_obj(obj); ++ if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) ++ return yaffs_clone_str(obj->variant.symlink_variant.alias); ++ else ++ return yaffs_clone_str(_Y("")); ++} ++ ++/*--------------------------- Initialisation code -------------------------- */ ++ ++static int yaffs_check_dev_fns(struct yaffs_dev *dev) ++{ ++ struct yaffs_driver *drv = &dev->drv; ++ struct yaffs_tags_handler *tagger = &dev->tagger; ++ ++ /* Common functions, gotta have */ ++ if (!drv->drv_read_chunk_fn || ++ !drv->drv_write_chunk_fn || ++ !drv->drv_erase_fn) ++ return 0; ++ ++ if (dev->param.is_yaffs2 && ++ (!drv->drv_mark_bad_fn || !drv->drv_check_bad_fn)) ++ return 0; ++ ++ /* Install the default tags marshalling functions if needed. */ ++ yaffs_tags_compat_install(dev); ++ yaffs_tags_marshall_install(dev); ++ ++ /* Check we now have the marshalling functions required. */ ++ if (!tagger->write_chunk_tags_fn || ++ !tagger->read_chunk_tags_fn || ++ !tagger->query_block_fn || ++ !tagger->mark_bad_fn) ++ return 0; ++ ++ return 1; ++} ++ ++static int yaffs_create_initial_dir(struct yaffs_dev *dev) ++{ ++ /* Initialise the unlinked, deleted, root and lost+found directories */ ++ dev->lost_n_found = NULL; ++ dev->root_dir = NULL; ++ dev->unlinked_dir = NULL; ++ dev->del_dir = NULL; ++ ++ dev->unlinked_dir = ++ yaffs_create_fake_dir(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR); ++ dev->del_dir = ++ yaffs_create_fake_dir(dev, YAFFS_OBJECTID_DELETED, S_IFDIR); ++ dev->root_dir = ++ yaffs_create_fake_dir(dev, YAFFS_OBJECTID_ROOT, ++ YAFFS_ROOT_MODE | S_IFDIR); ++ dev->lost_n_found = ++ yaffs_create_fake_dir(dev, YAFFS_OBJECTID_LOSTNFOUND, ++ YAFFS_LOSTNFOUND_MODE | S_IFDIR); ++ ++ if (dev->lost_n_found && ++ dev->root_dir && ++ dev->unlinked_dir && ++ dev->del_dir) { ++ /* If lost-n-found is hidden then yank it out of the directory tree. */ ++ if (dev->param.hide_lost_n_found) ++ list_del_init(&dev->lost_n_found->siblings); ++ else ++ yaffs_add_obj_to_dir(dev->root_dir, dev->lost_n_found); ++ return YAFFS_OK; ++ } ++ return YAFFS_FAIL; ++} ++ ++/* Low level init. ++ * Typically only used by yaffs_guts_initialise, but also used by the ++ * Low level yaffs driver tests. ++ */ ++ ++int yaffs_guts_ll_init(struct yaffs_dev *dev) ++{ ++ ++ ++ yaffs_trace(YAFFS_TRACE_TRACING, "yaffs: yaffs_ll_init()"); ++ ++ if (!dev) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "yaffs: Need a device" ++ ); ++ return YAFFS_FAIL; ++ } ++ ++ if (dev->ll_init) ++ return YAFFS_OK; ++ ++ dev->internal_start_block = dev->param.start_block; ++ dev->internal_end_block = dev->param.end_block; ++ dev->block_offset = 0; ++ dev->chunk_offset = 0; ++ dev->n_free_chunks = 0; ++ ++ dev->gc_block = 0; ++ ++ if (dev->param.start_block == 0) { ++ dev->internal_start_block = dev->param.start_block + 1; ++ dev->internal_end_block = dev->param.end_block + 1; ++ dev->block_offset = 1; ++ dev->chunk_offset = dev->param.chunks_per_block; ++ } ++ ++ /* Check geometry parameters. */ ++ ++ if ((!dev->param.inband_tags && dev->param.is_yaffs2 && ++ dev->param.total_bytes_per_chunk < 1024) || ++ (!dev->param.is_yaffs2 && ++ dev->param.total_bytes_per_chunk < 512) || ++ (dev->param.inband_tags && !dev->param.is_yaffs2) || ++ dev->param.chunks_per_block < 2 || ++ dev->param.n_reserved_blocks < 2 || ++ dev->internal_start_block <= 0 || ++ dev->internal_end_block <= 0 || ++ dev->internal_end_block <= ++ (dev->internal_start_block + dev->param.n_reserved_blocks + 2) ++ ) { ++ /* otherwise it is too small */ ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "NAND geometry problems: chunk size %d, type is yaffs%s, inband_tags %d ", ++ dev->param.total_bytes_per_chunk, ++ dev->param.is_yaffs2 ? "2" : "", ++ dev->param.inband_tags); ++ return YAFFS_FAIL; ++ } ++ ++ /* Sort out space for inband tags, if required */ ++ if (dev->param.inband_tags) ++ dev->data_bytes_per_chunk = ++ dev->param.total_bytes_per_chunk - ++ sizeof(struct yaffs_packed_tags2_tags_only); ++ else ++ dev->data_bytes_per_chunk = dev->param.total_bytes_per_chunk; ++ ++ /* Got the right mix of functions? */ ++ if (!yaffs_check_dev_fns(dev)) { ++ /* Function missing */ ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "device function(s) missing or wrong"); ++ ++ return YAFFS_FAIL; ++ } ++ ++ if (yaffs_init_nand(dev) != YAFFS_OK) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, "InitialiseNAND failed"); ++ return YAFFS_FAIL; ++ } ++ ++ return YAFFS_OK; ++} ++ ++ ++int yaffs_guts_format_dev(struct yaffs_dev *dev) ++{ ++ u32 i; ++ enum yaffs_block_state state; ++ u32 dummy; ++ ++ if(yaffs_guts_ll_init(dev) != YAFFS_OK) ++ return YAFFS_FAIL; ++ ++ if(dev->is_mounted) ++ return YAFFS_FAIL; ++ ++ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { ++ yaffs_query_init_block_state(dev, i, &state, &dummy); ++ if (state != YAFFS_BLOCK_STATE_DEAD) ++ yaffs_erase_block(dev, i); ++ } ++ ++ return YAFFS_OK; ++} ++ ++/* ++ * If the dev is mounted r/w then the cleanup will happen during ++ * yaffs_guts_initialise. However if the dev is mounted ro then ++ * the cleanup will be dfered until yaffs is remounted r/w. ++ */ ++void yaffs_guts_cleanup(struct yaffs_dev *dev) ++{ ++ yaffs_strip_deleted_objs(dev); ++ yaffs_fix_hanging_objs(dev); ++ if (dev->param.empty_lost_n_found) ++ yaffs_empty_l_n_f(dev); ++} ++ ++int yaffs_guts_initialise(struct yaffs_dev *dev) ++{ ++ int init_failed = 0; ++ u32 x; ++ u32 bits; ++ ++ if(yaffs_guts_ll_init(dev) != YAFFS_OK) ++ return YAFFS_FAIL; ++ ++ if (dev->is_mounted) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, "device already mounted"); ++ return YAFFS_FAIL; ++ } ++ ++ dev->is_mounted = 1; ++ ++ /* OK now calculate a few things for the device */ ++ ++ /* ++ * Calculate all the chunk size manipulation numbers: ++ */ ++ x = dev->data_bytes_per_chunk; ++ /* We always use dev->chunk_shift and dev->chunk_div */ ++ dev->chunk_shift = calc_shifts(x); ++ x >>= dev->chunk_shift; ++ dev->chunk_div = x; ++ /* We only use chunk mask if chunk_div is 1 */ ++ dev->chunk_mask = (1 << dev->chunk_shift) - 1; ++ ++ /* ++ * Calculate chunk_grp_bits. ++ * We need to find the next power of 2 > than internal_end_block ++ */ ++ ++ x = dev->param.chunks_per_block * (dev->internal_end_block + 1); ++ ++ bits = calc_shifts_ceiling(x); ++ ++ /* Set up tnode width if wide tnodes are enabled. */ ++ if (!dev->param.wide_tnodes_disabled) { ++ /* bits must be even so that we end up with 32-bit words */ ++ if (bits & 1) ++ bits++; ++ if (bits < 16) ++ dev->tnode_width = 16; ++ else ++ dev->tnode_width = bits; ++ } else { ++ dev->tnode_width = 16; ++ } ++ ++ dev->tnode_mask = (1 << dev->tnode_width) - 1; ++ ++ /* Level0 Tnodes are 16 bits or wider (if wide tnodes are enabled), ++ * so if the bitwidth of the ++ * chunk range we're using is greater than 16 we need ++ * to figure out chunk shift and chunk_grp_size ++ */ ++ ++ if (bits <= dev->tnode_width) ++ dev->chunk_grp_bits = 0; ++ else ++ dev->chunk_grp_bits = bits - dev->tnode_width; ++ ++ dev->tnode_size = (dev->tnode_width * YAFFS_NTNODES_LEVEL0) / 8; ++ if (dev->tnode_size < sizeof(struct yaffs_tnode)) ++ dev->tnode_size = sizeof(struct yaffs_tnode); ++ ++ dev->chunk_grp_size = 1 << dev->chunk_grp_bits; ++ ++ if (dev->param.chunks_per_block < dev->chunk_grp_size) { ++ /* We have a problem because the soft delete won't work if ++ * the chunk group size > chunks per block. ++ * This can be remedied by using larger "virtual blocks". ++ */ ++ yaffs_trace(YAFFS_TRACE_ALWAYS, "chunk group too large"); ++ ++ return YAFFS_FAIL; ++ } ++ ++ /* Finished verifying the device, continue with initialisation */ ++ ++ /* More device initialisation */ ++ dev->all_gcs = 0; ++ dev->passive_gc_count = 0; ++ dev->oldest_dirty_gc_count = 0; ++ dev->bg_gcs = 0; ++ dev->gc_block_finder = 0; ++ dev->buffered_block = -1; ++ dev->doing_buffered_block_rewrite = 0; ++ dev->n_deleted_files = 0; ++ dev->n_bg_deletions = 0; ++ dev->n_unlinked_files = 0; ++ dev->n_ecc_fixed = 0; ++ dev->n_ecc_unfixed = 0; ++ dev->n_tags_ecc_fixed = 0; ++ dev->n_tags_ecc_unfixed = 0; ++ dev->n_erase_failures = 0; ++ dev->n_erased_blocks = 0; ++ dev->gc_disable = 0; ++ dev->has_pending_prioritised_gc = 1; /* Assume the worst for now, ++ * will get fixed on first GC */ ++ INIT_LIST_HEAD(&dev->dirty_dirs); ++ dev->oldest_dirty_seq = 0; ++ dev->oldest_dirty_block = 0; ++ ++ yaffs_endian_config(dev); ++ ++ /* Initialise temporary buffers and caches. */ ++ if (!yaffs_init_tmp_buffers(dev)) ++ init_failed = 1; ++ ++ dev->gc_cleanup_list = NULL; ++ ++ if (!init_failed) ++ init_failed = yaffs_cache_init(dev) < 0; ++ ++ dev->cache_hits = 0; ++ ++ if (!init_failed) { ++ dev->gc_cleanup_list = ++ kmalloc(dev->param.chunks_per_block * sizeof(u32), ++ GFP_NOFS); ++ if (!dev->gc_cleanup_list) ++ init_failed = 1; ++ } ++ ++ if (dev->param.is_yaffs2) ++ dev->param.use_header_file_size = 1; ++ ++ if (!init_failed && !yaffs_init_blocks(dev)) ++ init_failed = 1; ++ ++ yaffs_init_tnodes_and_objs(dev); ++ ++ if (!init_failed && !yaffs_create_initial_dir(dev)) ++ init_failed = 1; ++ ++ if (!init_failed && dev->param.is_yaffs2 && ++ !dev->param.disable_summary && ++ !yaffs_summary_init(dev)) ++ init_failed = 1; ++ ++ if (!init_failed) { ++ /* Now scan the flash. */ ++ if (dev->param.is_yaffs2) { ++ if (yaffs2_checkpt_restore(dev)) { ++ yaffs_check_obj_details_loaded(dev->root_dir); ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT | ++ YAFFS_TRACE_MOUNT, ++ "yaffs: restored from checkpoint" ++ ); ++ } else { ++ ++ /* Clean up the mess caused by an aborted ++ * checkpoint load then scan backwards. ++ */ ++ yaffs_deinit_blocks(dev); ++ ++ yaffs_deinit_tnodes_and_objs(dev); ++ ++ dev->n_erased_blocks = 0; ++ dev->n_free_chunks = 0; ++ dev->alloc_block = -1; ++ dev->alloc_page = -1; ++ dev->n_deleted_files = 0; ++ dev->n_unlinked_files = 0; ++ dev->n_bg_deletions = 0; ++ ++ if (!init_failed && !yaffs_init_blocks(dev)) ++ init_failed = 1; ++ ++ yaffs_init_tnodes_and_objs(dev); ++ ++ if (!init_failed ++ && !yaffs_create_initial_dir(dev)) ++ init_failed = 1; ++ ++ if (!init_failed && !yaffs2_scan_backwards(dev)) ++ init_failed = 1; ++ } ++ } else if (!yaffs1_scan(dev)) { ++ init_failed = 1; ++ } ++ ++ yaffs_guts_cleanup(dev); ++ } ++ ++ if (init_failed) { ++ /* Clean up the mess */ ++ yaffs_trace(YAFFS_TRACE_TRACING, ++ "yaffs: yaffs_guts_initialise() aborted."); ++ ++ yaffs_deinitialise(dev); ++ return YAFFS_FAIL; ++ } ++ ++ /* Zero out stats */ ++ dev->n_page_reads = 0; ++ dev->n_page_writes = 0; ++ dev->n_erasures = 0; ++ dev->n_gc_copies = 0; ++ dev->n_retried_writes = 0; ++ ++ dev->n_retired_blocks = 0; ++ ++ yaffs_verify_free_chunks(dev); ++ yaffs_verify_blocks(dev); ++ ++ /* Clean up any aborted checkpoint data */ ++ if (!dev->is_checkpointed && dev->blocks_in_checkpt > 0) ++ yaffs2_checkpt_invalidate(dev); ++ ++ yaffs_trace(YAFFS_TRACE_TRACING, ++ "yaffs: yaffs_guts_initialise() done."); ++ return YAFFS_OK; ++} ++ ++void yaffs_deinitialise(struct yaffs_dev *dev) ++{ ++ if (dev->is_mounted) { ++ u32 i; ++ ++ yaffs_deinit_blocks(dev); ++ yaffs_deinit_tnodes_and_objs(dev); ++ yaffs_summary_deinit(dev); ++ yaffs_cache_deinit(dev); ++ ++ kfree(dev->gc_cleanup_list); ++ ++ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { ++ kfree(dev->temp_buffer[i].buffer); ++ dev->temp_buffer[i].buffer = NULL; ++ } ++ ++ kfree(dev->checkpt_buffer); ++ dev->checkpt_buffer = NULL; ++ kfree(dev->checkpt_block_list); ++ dev->checkpt_block_list = NULL; ++ ++ dev->is_mounted = 0; ++ ++ yaffs_deinit_nand(dev); ++ } ++} ++ ++int yaffs_count_free_chunks(struct yaffs_dev *dev) ++{ ++ int n_free = 0; ++ u32 b; ++ struct yaffs_block_info *blk; ++ ++ blk = dev->block_info; ++ for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) { ++ switch (blk->block_state) { ++ case YAFFS_BLOCK_STATE_EMPTY: ++ case YAFFS_BLOCK_STATE_ALLOCATING: ++ case YAFFS_BLOCK_STATE_COLLECTING: ++ case YAFFS_BLOCK_STATE_FULL: ++ n_free += ++ (dev->param.chunks_per_block - blk->pages_in_use + ++ blk->soft_del_pages); ++ break; ++ default: ++ break; ++ } ++ blk++; ++ } ++ return n_free; ++} ++ ++int yaffs_get_n_free_chunks(struct yaffs_dev *dev) ++{ ++ /* This is what we report to the outside world */ ++ int n_free; ++ int n_dirty_caches; ++ int blocks_for_checkpt; ++ ++ n_free = dev->n_free_chunks; ++ n_free += dev->n_deleted_files; ++ ++ /* Now count and subtract the number of dirty chunks in the cache. */ ++ n_dirty_caches = yaffs_count_dirty_caches(dev); ++ n_free -= n_dirty_caches; ++ ++ n_free -= ++ ((dev->param.n_reserved_blocks + 1) * dev->param.chunks_per_block); ++ ++ /* Now figure checkpoint space and report that... */ ++ blocks_for_checkpt = yaffs_calc_checkpt_blocks_required(dev); ++ ++ n_free -= (blocks_for_checkpt * dev->param.chunks_per_block); ++ ++ if (n_free < 0) ++ n_free = 0; ++ ++ return n_free; ++} ++ ++ ++/* ++ * Marshalling functions to get loff_t file sizes into and out of ++ * object headers. ++ */ ++void yaffs_oh_size_load(struct yaffs_dev *dev, ++ struct yaffs_obj_hdr *oh, ++ loff_t fsize, ++ int do_endian) ++{ ++ oh->file_size_low = FSIZE_LOW(fsize); ++ ++ oh->file_size_high = FSIZE_HIGH(fsize); ++ ++ if (do_endian) { ++ yaffs_do_endian_u32(dev, &oh->file_size_low); ++ yaffs_do_endian_u32(dev, &oh->file_size_high); ++ } ++} ++ ++loff_t yaffs_oh_to_size(struct yaffs_dev *dev, struct yaffs_obj_hdr *oh, ++ int do_endian) ++{ ++ loff_t retval; ++ ++ ++ if (sizeof(loff_t) >= 8 && ~(oh->file_size_high)) { ++ u32 low = oh->file_size_low; ++ u32 high = oh->file_size_high; ++ ++ if (do_endian) { ++ yaffs_do_endian_u32 (dev, &low); ++ yaffs_do_endian_u32 (dev, &high); ++ } ++ retval = FSIZE_COMBINE(high, low); ++ } else { ++ u32 low = oh->file_size_low; ++ ++ if (do_endian) ++ yaffs_do_endian_u32(dev, &low); ++ retval = (loff_t)low; ++ } ++ ++ return retval; ++} ++ ++ ++void yaffs_count_blocks_by_state(struct yaffs_dev *dev, int bs[10]) ++{ ++ u32 i; ++ struct yaffs_block_info *bi; ++ int s; ++ ++ for(i = 0; i < 10; i++) ++ bs[i] = 0; ++ ++ for(i = dev->internal_start_block; i <= dev->internal_end_block; i++) { ++ bi = yaffs_get_block_info(dev, i); ++ s = bi->block_state; ++ if(s > YAFFS_BLOCK_STATE_DEAD || s < YAFFS_BLOCK_STATE_UNKNOWN) ++ bs[0]++; ++ else ++ bs[s]++; ++ } ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_guts.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_guts.h.patch new file mode 100644 index 00000000..c8d5461e --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_guts.h.patch @@ -0,0 +1,1085 @@ +diff -drupN a/fs/yaffs2/yaffs_guts.h b/fs/yaffs2/yaffs_guts.h +--- a/fs/yaffs2/yaffs_guts.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_guts.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,1081 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_GUTS_H__ ++#define __YAFFS_GUTS_H__ ++ ++#include "yportenv.h" ++ ++#define YAFFS_OK 1 ++#define YAFFS_FAIL 0 ++ ++/* Give us a Y=0x59, ++ * Give us an A=0x41, ++ * Give us an FF=0xff ++ * Give us an S=0x53 ++ * And what have we got... ++ */ ++#define YAFFS_MAGIC 0x5941ff53 ++ ++/* ++ * Tnodes form a tree with the tnodes in "levels" ++ * Levels greater than 0 hold 8 slots which point to other tnodes. ++ * Those at level 0 hold 16 slots which point to chunks in NAND. ++ * ++ * A maximum level of 8 thust supports files of size up to: ++ * ++ * 2^(3*MAX_LEVEL+4) ++ * ++ * Thus a max level of 8 supports files with up to 2^^28 chunks which gives ++ * a maximum file size of around 512Gbytees with 2k chunks. ++ */ ++#define YAFFS_NTNODES_LEVEL0 16 ++#define YAFFS_TNODES_LEVEL0_BITS 4 ++#define YAFFS_TNODES_LEVEL0_MASK 0xf ++ ++#define YAFFS_NTNODES_INTERNAL (YAFFS_NTNODES_LEVEL0 / 2) ++#define YAFFS_TNODES_INTERNAL_BITS (YAFFS_TNODES_LEVEL0_BITS - 1) ++#define YAFFS_TNODES_INTERNAL_MASK 0x7 ++#define YAFFS_TNODES_MAX_LEVEL 8 ++#define YAFFS_TNODES_MAX_BITS (YAFFS_TNODES_LEVEL0_BITS + \ ++ YAFFS_TNODES_INTERNAL_BITS * \ ++ YAFFS_TNODES_MAX_LEVEL) ++#define YAFFS_MAX_CHUNK_ID ((1 << YAFFS_TNODES_MAX_BITS) - 1) ++ ++#define YAFFS_MAX_FILE_SIZE_32 0x7fffffff ++ ++/* Constants for YAFFS1 mode */ ++#define YAFFS_BYTES_PER_SPARE 16 ++#define YAFFS_BYTES_PER_CHUNK 512 ++#define YAFFS_CHUNK_SIZE_SHIFT 9 ++#define YAFFS_CHUNKS_PER_BLOCK 32 ++#define YAFFS_BYTES_PER_BLOCK (YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK) ++ ++#define YAFFS_MIN_YAFFS2_CHUNK_SIZE 1024 ++#define YAFFS_MIN_YAFFS2_SPARE_SIZE 32 ++ ++ ++ ++#define YAFFS_ALLOCATION_NOBJECTS 100 ++#define YAFFS_ALLOCATION_NTNODES 100 ++#define YAFFS_ALLOCATION_NLINKS 100 ++ ++#define YAFFS_NOBJECT_BUCKETS 256 ++ ++#define YAFFS_OBJECT_SPACE 0x40000 ++#define YAFFS_MAX_OBJECT_ID (YAFFS_OBJECT_SPACE - 1) ++ ++/* Binary data version stamps */ ++#define YAFFS_SUMMARY_VERSION 1 ++ ++#ifdef CONFIG_YAFFS_UNICODE ++#define YAFFS_MAX_NAME_LENGTH 127 ++#define YAFFS_MAX_ALIAS_LENGTH 79 ++#else ++#define YAFFS_MAX_NAME_LENGTH 255 ++#define YAFFS_MAX_ALIAS_LENGTH 159 ++#endif ++ ++#define YAFFS_SHORT_NAME_LENGTH 15 ++ ++/* Some special object ids for pseudo objects */ ++#define YAFFS_OBJECTID_ROOT 1 ++#define YAFFS_OBJECTID_LOSTNFOUND 2 ++#define YAFFS_OBJECTID_UNLINKED 3 ++#define YAFFS_OBJECTID_DELETED 4 ++ ++/* Fake object Id for summary data */ ++#define YAFFS_OBJECTID_SUMMARY 0x10 ++ ++/* Pseudo object ids for checkpointing */ ++#define YAFFS_OBJECTID_CHECKPOINT_DATA 0x20 ++#define YAFFS_SEQUENCE_CHECKPOINT_DATA 0x21 ++ ++#define YAFFS_MAX_SHORT_OP_CACHES 20 ++ ++#define YAFFS_N_TEMP_BUFFERS 6 ++ ++/* We limit the number attempts at sucessfully saving a chunk of data. ++ * Small-page devices have 32 pages per block; large-page devices have 64. ++ * Default to something in the order of 5 to 10 blocks worth of chunks. ++ */ ++#define YAFFS_WR_ATTEMPTS (5*64) ++ ++/* Sequence numbers are used in YAFFS2 to determine block allocation order. ++ * The range is limited slightly to help distinguish bad numbers from good. ++ * This also allows us to perhaps in the future use special numbers for ++ * special purposes. ++ * EFFFFF00 allows the allocation of 8 blocks/second (~1Mbytes) for 15 years, ++ * and is a larger number than the lifetime of a 2GB device. ++ */ ++#define YAFFS_LOWEST_SEQUENCE_NUMBER 0x00001000 ++#define YAFFS_HIGHEST_SEQUENCE_NUMBER 0xefffff00 ++ ++/* Special sequence number for bad block that failed to be marked bad */ ++#define YAFFS_SEQUENCE_BAD_BLOCK 0xffff0000 ++ ++/* Chunk cache is used for short read/write operations.*/ ++struct yaffs_cache { ++ struct yaffs_obj *object; ++ int chunk_id; ++ int last_use; ++ int dirty; ++ int n_bytes; /* Only valid if the cache is dirty */ ++ int locked; /* Can't push out or flush while locked. */ ++ u8 *data; ++}; ++ ++struct yaffs_cache_manager { ++ struct yaffs_cache *cache; ++ int n_caches; ++ int cache_last_use; ++ int n_temp_buffers; ++}; ++ ++/* yaffs1 tags structures in RAM ++ * NB This uses bitfield. Bitfields should not straddle a u32 boundary ++ * otherwise the structure size will get blown out. ++ */ ++ ++struct yaffs_tags { ++ u32 chunk_id:20; ++ u32 serial_number:2; ++ u32 n_bytes_lsb:10; ++ u32 obj_id:18; ++ u32 ecc:12; ++ u32 n_bytes_msb:2; ++}; ++ ++union yaffs_tags_union { ++ struct yaffs_tags as_tags; ++ u8 as_bytes[8]; ++ u32 as_u32[2]; ++}; ++ ++ ++/* Stuff used for extended tags in YAFFS2 */ ++ ++enum yaffs_ecc_result { ++ YAFFS_ECC_RESULT_UNKNOWN, ++ YAFFS_ECC_RESULT_NO_ERROR, ++ YAFFS_ECC_RESULT_FIXED, ++ YAFFS_ECC_RESULT_UNFIXED ++}; ++ ++/* ++ * Object type enum: ++ * When this is stored in flash we store it as a u32 instead ++ * to prevent any alignment change issues as compiler variants change. ++ */ ++ ++enum yaffs_obj_type { ++ YAFFS_OBJECT_TYPE_UNKNOWN, ++ YAFFS_OBJECT_TYPE_FILE, ++ YAFFS_OBJECT_TYPE_SYMLINK, ++ YAFFS_OBJECT_TYPE_DIRECTORY, ++ YAFFS_OBJECT_TYPE_HARDLINK, ++ YAFFS_OBJECT_TYPE_SPECIAL ++}; ++ ++#define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL ++ ++struct yaffs_ext_tags { ++ unsigned chunk_used; /* Status of the chunk: used or unused */ ++ unsigned obj_id; /* If 0 this is not used */ ++ unsigned chunk_id; /* If 0 this is a header, else a data chunk */ ++ unsigned n_bytes; /* Only valid for data chunks */ ++ ++ /* The following stuff only has meaning when we read */ ++ enum yaffs_ecc_result ecc_result; ++ unsigned block_bad; ++ ++ /* YAFFS 1 stuff */ ++ unsigned is_deleted; /* The chunk is marked deleted */ ++ unsigned serial_number; /* Yaffs1 2-bit serial number */ ++ ++ /* YAFFS2 stuff */ ++ unsigned seq_number; /* The sequence number of this block */ ++ ++ /* Extra info if this is an object header (YAFFS2 only) */ ++ ++ unsigned extra_available; /* Extra info available if not zero */ ++ unsigned extra_parent_id; /* The parent object */ ++ unsigned extra_is_shrink; /* Is it a shrink header? */ ++ unsigned extra_shadows; /* Does this shadow another object? */ ++ ++ enum yaffs_obj_type extra_obj_type; /* What object type? */ ++ ++ loff_t extra_file_size; /* Length if it is a file */ ++ unsigned extra_equiv_id; /* Equivalent object for a hard link */ ++}; ++ ++/* Spare structure for YAFFS1 */ ++struct yaffs_spare { ++ u8 tb0; ++ u8 tb1; ++ u8 tb2; ++ u8 tb3; ++ u8 page_status; /* set to 0 to delete the chunk */ ++ u8 block_status; ++ u8 tb4; ++ u8 tb5; ++ u8 ecc1[3]; ++ u8 tb6; ++ u8 tb7; ++ u8 ecc2[3]; ++}; ++ ++/*Special structure for passing through to mtd */ ++struct yaffs_nand_spare { ++ struct yaffs_spare spare; ++ int eccres1; ++ int eccres2; ++}; ++ ++/* Block data in RAM */ ++ ++enum yaffs_block_state { ++ YAFFS_BLOCK_STATE_UNKNOWN = 0, ++ ++ YAFFS_BLOCK_STATE_SCANNING, ++ /* Being scanned */ ++ ++ YAFFS_BLOCK_STATE_NEEDS_SCAN, ++ /* The block might have something on it (ie it is allocating or full, ++ * perhaps empty) but it needs to be scanned to determine its true ++ * state. ++ * This state is only valid during scanning. ++ * NB We tolerate empty because the pre-scanner might be incapable of ++ * deciding ++ * However, if this state is returned on a YAFFS2 device, ++ * then we expect a sequence number ++ */ ++ ++ YAFFS_BLOCK_STATE_EMPTY, ++ /* This block is empty */ ++ ++ YAFFS_BLOCK_STATE_ALLOCATING, ++ /* This block is partially allocated. ++ * At least one page holds valid data. ++ * This is the one currently being used for page ++ * allocation. Should never be more than one of these. ++ * If a block is only partially allocated at mount it is treated as ++ * full. ++ */ ++ ++ YAFFS_BLOCK_STATE_FULL, ++ /* All the pages in this block have been allocated. ++ * If a block was only partially allocated when mounted we treat ++ * it as fully allocated. ++ */ ++ ++ YAFFS_BLOCK_STATE_DIRTY, ++ /* The block was full and now all chunks have been deleted. ++ * Erase me, reuse me. ++ */ ++ ++ YAFFS_BLOCK_STATE_CHECKPOINT, ++ /* This block is assigned to holding checkpoint data. */ ++ ++ YAFFS_BLOCK_STATE_COLLECTING, ++ /* This block is being garbage collected */ ++ ++ YAFFS_BLOCK_STATE_DEAD ++ /* This block has failed and is not in use */ ++}; ++ ++#define YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1) ++ ++struct yaffs_block_info { ++ ++ s32 soft_del_pages:10; /* number of soft deleted pages */ ++ s32 pages_in_use:10; /* number of pages in use */ ++ u32 block_state:4; /* One of the above block states. */ ++ /* NB use unsigned because enum is sometimes ++ * an int */ ++ u32 needs_retiring:1; /* Data has failed on this block, */ ++ /*need to get valid data off and retire*/ ++ u32 skip_erased_check:1;/* Skip the erased check on this block */ ++ u32 gc_prioritise:1; /* An ECC check or blank check has failed. ++ Block should be prioritised for GC */ ++ u32 chunk_error_strikes:3; /* How many times we've had ecc etc ++ failures on this block and tried to reuse it */ ++ u32 has_summary:1; /* The block has a summary */ ++ ++ u32 has_shrink_hdr:1; /* This block has at least one shrink header */ ++ u32 seq_number; /* block sequence number for yaffs2 */ ++ ++}; ++ ++union yaffs_block_info_union { ++ struct yaffs_block_info bi; ++ u32 as_u32[2]; ++}; ++ ++/* -------------------------- Object structure -------------------------------*/ ++/* This is the object structure as stored on NAND */ ++ ++struct yaffs_obj_hdr { ++ u32 type; /* enum yaffs_obj_type */ ++ ++ /* Apply to everything */ ++ u32 parent_obj_id; ++ u16 sum_no_longer_used; /* checksum of name. No longer used */ ++ YCHAR name[YAFFS_MAX_NAME_LENGTH + 1]; ++ ++ /* The following apply to all object types except for hard links */ ++ u32 yst_mode; /* protection */ ++ ++ u32 yst_uid; ++ u32 yst_gid; ++ u32 yst_atime; ++ u32 yst_mtime; ++ u32 yst_ctime; ++ ++ /* File size applies to files only */ ++ u32 file_size_low; ++ ++ /* Equivalent object id applies to hard links only. */ ++ int equiv_id; ++ ++ /* Alias is for symlinks only. */ ++ YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1]; ++ ++ u32 yst_rdev; /* stuff for block and char devices (major/min) */ ++ ++ u32 win_ctime[2]; ++ u32 win_atime[2]; ++ u32 win_mtime[2]; ++ ++ u32 inband_shadowed_obj_id; ++ u32 inband_is_shrink; ++ ++ u32 file_size_high; ++ u32 reserved[1]; ++ int shadows_obj; /* This object header shadows the ++ specified object if > 0 */ ++ ++ /* is_shrink applies to object headers written when wemake a hole. */ ++ u32 is_shrink; ++ ++}; ++ ++/*--------------------------- Tnode -------------------------- */ ++ ++struct yaffs_tnode { ++ struct yaffs_tnode *internal[YAFFS_NTNODES_INTERNAL]; ++}; ++ ++/*------------------------ Object -----------------------------*/ ++/* An object can be one of: ++ * - a directory (no data, has children links ++ * - a regular file (data.... not prunes :->). ++ * - a symlink [symbolic link] (the alias). ++ * - a hard link ++ */ ++ ++/* The file variant has three file sizes: ++ * - file_size : size of file as written into Yaffs - including data in cache. ++ * - stored_size - size of file as stored on media. ++ * - shrink_size - size of file that has been shrunk back to. ++ * ++ * The stored_size and file_size might be different because the data written ++ * into the cache will increase the file_size but the stored_size will only ++ * change when the data is actually stored. ++ * ++ */ ++struct yaffs_file_var { ++ loff_t file_size; ++ loff_t stored_size; ++ loff_t shrink_size; ++ int top_level; ++ struct yaffs_tnode *top; ++}; ++ ++struct yaffs_dir_var { ++ struct list_head children; /* list of child links */ ++ struct list_head dirty; /* Entry for list of dirty directories */ ++}; ++ ++struct yaffs_symlink_var { ++ YCHAR *alias; ++}; ++ ++struct yaffs_hardlink_var { ++ struct yaffs_obj *equiv_obj; ++ u32 equiv_id; ++}; ++ ++union yaffs_obj_var { ++ struct yaffs_file_var file_variant; ++ struct yaffs_dir_var dir_variant; ++ struct yaffs_symlink_var symlink_variant; ++ struct yaffs_hardlink_var hardlink_variant; ++}; ++ ++struct yaffs_obj { ++ u8 deleted:1; /* This should only apply to unlinked files. */ ++ u8 soft_del:1; /* it has also been soft deleted */ ++ u8 unlinked:1; /* An unlinked file.*/ ++ u8 fake:1; /* A fake object has no presence on NAND. */ ++ u8 rename_allowed:1; /* Some objects cannot be renamed. */ ++ u8 unlink_allowed:1; ++ u8 dirty:1; /* the object needs to be written to flash */ ++ u8 valid:1; /* When the file system is being loaded up, this ++ * object might be created before the data ++ * is available ++ * ie. file data chunks encountered before ++ * the header. ++ */ ++ u8 lazy_loaded:1; /* This object has been lazy loaded and ++ * is missing some detail */ ++ ++ u8 defered_free:1; /* Object is removed from NAND, but is ++ * still in the inode cache. ++ * Free of object is defered. ++ * until the inode is released. ++ */ ++ u8 being_created:1; /* This object is still being created ++ * so skip some verification checks. */ ++ u8 is_shadowed:1; /* This object is shadowed on the way ++ * to being renamed. */ ++ ++ u8 xattr_known:1; /* We know if this has object has xattribs ++ * or not. */ ++ u8 has_xattr:1; /* This object has xattribs. ++ * Only valid if xattr_known. */ ++ ++ u8 serial; /* serial number of chunk in NAND.*/ ++ u16 sum; /* sum of the name to speed searching */ ++ ++ struct yaffs_dev *my_dev; /* The device I'm on */ ++ ++ struct list_head hash_link; /* list of objects in hash bucket */ ++ ++ struct list_head hard_links; /* hard linked object chain*/ ++ ++ /* directory structure stuff */ ++ /* also used for linking up the free list */ ++ struct yaffs_obj *parent; ++ struct list_head siblings; ++ ++ /* Where's my object header in NAND? */ ++ int hdr_chunk; ++ ++ int n_data_chunks; /* Number of data chunks for this file. */ ++ ++ u32 obj_id; /* the object id value */ ++ ++ u32 yst_mode; ++ ++ YCHAR short_name[YAFFS_SHORT_NAME_LENGTH + 1]; ++ ++#ifdef CONFIG_YAFFS_WINCE ++ u32 win_ctime[2]; ++ u32 win_mtime[2]; ++ u32 win_atime[2]; ++#else ++ u32 yst_uid; ++ u32 yst_gid; ++ u32 yst_atime; ++ u32 yst_mtime; ++ u32 yst_ctime; ++#endif ++ ++ u32 yst_rdev; ++ ++ void *my_inode; ++ ++ u32 variant_type; /* enum yaffs_object_type */ ++ ++ union yaffs_obj_var variant; ++ ++}; ++ ++struct yaffs_obj_bucket { ++ struct list_head list; ++ int count; ++}; ++ ++ ++/*--------------------- Temporary buffers ---------------- ++ * ++ * These are chunk-sized working buffers. Each device has a few. ++ */ ++ ++struct yaffs_buffer { ++ u8 *buffer; ++ int in_use; ++}; ++ ++/*----------------- Device ---------------------------------*/ ++ ++struct yaffs_param { ++ const YCHAR *name; ++ ++ /* ++ * Entry parameters set up way early. Yaffs sets up the rest. ++ * The structure should be zeroed out before use so that unused ++ * and default values are zero. ++ */ ++ ++ int inband_tags; /* Use unband tags */ ++ u32 total_bytes_per_chunk; /* Should be >= 512, does not need to ++ be a power of 2 */ ++ u32 chunks_per_block; /* does not need to be a power of 2 */ ++ u32 spare_bytes_per_chunk; /* spare area size */ ++ u32 start_block; /* Start block we're allowed to use */ ++ u32 end_block; /* End block we're allowed to use */ ++ u32 n_reserved_blocks; /* Tuneable so that we can reduce ++ * reserved blocks on NOR and RAM. */ ++ ++ u32 n_caches; /* If == 0, then short op caching is disabled, ++ * else the number of short op caches. ++ */ ++ int cache_bypass_aligned; /* If non-zero then bypass the cache for ++ * aligned writes. ++ */ ++ ++ int use_nand_ecc; /* Flag to decide whether or not to use ++ * NAND driver ECC on data (yaffs1) */ ++ int tags_9bytes; /* Use 9 byte tags */ ++ int no_tags_ecc; /* Flag to decide whether or not to do ECC ++ * on packed tags (yaffs2) */ ++ ++ int is_yaffs2; /* Use yaffs2 mode on this device */ ++ ++ int empty_lost_n_found; /* Auto-empty lost+found directory on mount */ ++ ++ int refresh_period; /* How often to check for a block refresh */ ++ ++ /* Checkpoint control. Can be set before or after initialisation */ ++ u8 skip_checkpt_rd; ++ u8 skip_checkpt_wr; ++ ++ int enable_xattr; /* Enable xattribs */ ++ ++ int max_objects; /* ++ * Set to limit the number of objects created. ++ * 0 = no limit. ++ */ ++ ++ int hide_lost_n_found; /* Set non-zero to hide the lost-n-found dir. */ ++ ++ int stored_endian; /* 0=cpu endian, 1=little endian, 2=big endian */ ++ ++ /* The remove_obj_fn function must be supplied by OS flavours that ++ * need it. ++ * yaffs direct uses it to implement the faster readdir. ++ * Linux uses it to protect the directory during unlocking. ++ */ ++ void (*remove_obj_fn) (struct yaffs_obj *obj); ++ ++ /* Callback to mark the superblock dirty */ ++ void (*sb_dirty_fn) (struct yaffs_dev *dev); ++ ++ /* Callback to control garbage collection. */ ++ unsigned (*gc_control_fn) (struct yaffs_dev *dev); ++ ++ /* Debug control flags. Don't use unless you know what you're doing */ ++ int use_header_file_size; /* Flag to determine if we should use ++ * file sizes from the header */ ++ int disable_lazy_load; /* Disable lazy loading on this device */ ++ int wide_tnodes_disabled; /* Set to disable wide tnodes */ ++ int disable_soft_del; /* yaffs 1 only: Set to disable the use of ++ * softdeletion. */ ++ ++ int defered_dir_update; /* Set to defer directory updates */ ++ ++#ifdef CONFIG_YAFFS_AUTO_UNICODE ++ int auto_unicode; ++#endif ++ int always_check_erased; /* Force chunk erased check always on */ ++ ++ int disable_summary; ++ int disable_bad_block_marking; ++ ++}; ++ ++struct yaffs_driver { ++ int (*drv_write_chunk_fn) (struct yaffs_dev *dev, int nand_chunk, ++ const u8 *data, int data_len, ++ const u8 *oob, int oob_len); ++ int (*drv_read_chunk_fn) (struct yaffs_dev *dev, int nand_chunk, ++ u8 *data, int data_len, ++ u8 *oob, int oob_len, ++ enum yaffs_ecc_result *ecc_result); ++ int (*drv_erase_fn) (struct yaffs_dev *dev, int block_no); ++ int (*drv_mark_bad_fn) (struct yaffs_dev *dev, int block_no); ++ int (*drv_check_bad_fn) (struct yaffs_dev *dev, int block_no); ++ int (*drv_initialise_fn) (struct yaffs_dev *dev); ++ int (*drv_deinitialise_fn) (struct yaffs_dev *dev); ++}; ++ ++struct yaffs_tags_handler { ++ int (*write_chunk_tags_fn) (struct yaffs_dev *dev, ++ int nand_chunk, const u8 *data, ++ const struct yaffs_ext_tags *tags); ++ int (*read_chunk_tags_fn) (struct yaffs_dev *dev, ++ int nand_chunk, u8 *data, ++ struct yaffs_ext_tags *tags); ++ ++ int (*query_block_fn) (struct yaffs_dev *dev, int block_no, ++ enum yaffs_block_state *state, ++ u32 *seq_number); ++ int (*mark_bad_fn) (struct yaffs_dev *dev, int block_no); ++}; ++ ++struct yaffs_dev { ++ struct yaffs_param param; ++ struct yaffs_driver drv; ++ struct yaffs_tags_handler tagger; ++ ++ /* Context storage. Holds extra OS specific data for this device */ ++ ++ void *os_context; ++ void *driver_context; ++ ++ struct list_head dev_list; ++ ++ int ll_init; ++ /* Runtime parameters. Set up by YAFFS. */ ++ u32 data_bytes_per_chunk; ++ ++ /* Non-wide tnode stuff */ ++ u16 chunk_grp_bits; /* Number of bits that need to be resolved if ++ * the tnodes are not wide enough. ++ */ ++ u16 chunk_grp_size; /* == 2^^chunk_grp_bits */ ++ ++ struct yaffs_tnode *tn_swap_buffer; ++ ++ /* Stuff to support wide tnodes */ ++ u32 tnode_width; ++ u32 tnode_mask; ++ u32 tnode_size; ++ ++ /* Stuff for figuring out file offset to chunk conversions */ ++ u32 chunk_shift; /* Shift value */ ++ u32 chunk_div; /* Divisor after shifting: 1 for 2^n sizes */ ++ u32 chunk_mask; /* Mask to use for power-of-2 case */ ++ ++ int is_mounted; ++ int read_only; ++ int is_checkpointed; ++ int swap_endian; /* Stored endian needs endian swap. */ ++ ++ /* Stuff to support block offsetting to support start block zero */ ++ u32 internal_start_block; ++ u32 internal_end_block; ++ int block_offset; ++ int chunk_offset; ++ ++ /* Runtime checkpointing stuff */ ++ int checkpt_page_seq; /* running sequence number of checkpt pages */ ++ int checkpt_byte_count; ++ int checkpt_byte_offs; ++ u8 *checkpt_buffer; ++ int checkpt_open_write; ++ u32 blocks_in_checkpt; ++ int checkpt_cur_chunk; ++ int checkpt_cur_block; ++ int checkpt_next_block; ++ int *checkpt_block_list; ++ u32 checkpt_max_blocks; ++ u32 checkpt_sum; ++ u32 checkpt_xor; ++ ++ int checkpoint_blocks_required; /* Number of blocks needed to store ++ * current checkpoint set */ ++ ++ /* Block Info */ ++ struct yaffs_block_info *block_info; ++ u8 *chunk_bits; /* bitmap of chunks in use */ ++ u8 block_info_alt:1; /* allocated using alternative alloc */ ++ u8 chunk_bits_alt:1; /* allocated using alternative alloc */ ++ int chunk_bit_stride; /* Number of bytes of chunk_bits per block. ++ * Must be consistent with chunks_per_block. ++ */ ++ ++ int n_erased_blocks; ++ int alloc_block; /* Current block being allocated off */ ++ u32 alloc_page; ++ int alloc_block_finder; /* Used to search for next allocation block */ ++ ++ /* Object and Tnode memory management */ ++ void *allocator; ++ int n_obj; ++ int n_tnodes; ++ ++ int n_hardlinks; ++ ++ struct yaffs_obj_bucket obj_bucket[YAFFS_NOBJECT_BUCKETS]; ++ u32 bucket_finder; ++ ++ int n_free_chunks; ++ ++ /* Garbage collection control */ ++ u32 *gc_cleanup_list; /* objects to delete at the end of a GC. */ ++ u32 n_clean_ups; ++ ++ unsigned has_pending_prioritised_gc; /* We think this device might ++ have pending prioritised gcs */ ++ unsigned gc_disable; ++ unsigned gc_block_finder; ++ unsigned gc_dirtiest; ++ unsigned gc_pages_in_use; ++ unsigned gc_not_done; ++ unsigned gc_block; ++ unsigned gc_chunk; ++ unsigned gc_skip; ++ struct yaffs_summary_tags *gc_sum_tags; ++ ++ /* Special directories */ ++ struct yaffs_obj *root_dir; ++ struct yaffs_obj *lost_n_found; ++ ++ int buffered_block; /* Which block is buffered here? */ ++ int doing_buffered_block_rewrite; ++ ++ struct yaffs_cache_manager cache_mgr; ++ ++ /* Stuff for background deletion and unlinked files. */ ++ struct yaffs_obj *unlinked_dir; /* Directory where unlinked and deleted ++ files live. */ ++ struct yaffs_obj *del_dir; /* Directory where deleted objects are ++ sent to disappear. */ ++ struct yaffs_obj *unlinked_deletion; /* Current file being ++ background deleted. */ ++ int n_deleted_files; /* Count of files awaiting deletion; */ ++ int n_unlinked_files; /* Count of unlinked files. */ ++ int n_bg_deletions; /* Count of background deletions. */ ++ ++ /* Temporary buffer management */ ++ struct yaffs_buffer temp_buffer[YAFFS_N_TEMP_BUFFERS]; ++ int max_temp; ++ int temp_in_use; ++ int unmanaged_buffer_allocs; ++ int unmanaged_buffer_deallocs; ++ ++ /* yaffs2 runtime stuff */ ++ unsigned seq_number; /* Sequence number of currently ++ allocating block */ ++ unsigned oldest_dirty_seq; ++ unsigned oldest_dirty_block; ++ ++ /* Block refreshing */ ++ int refresh_skip; /* A skip down counter. ++ * Refresh happens when this gets to zero. */ ++ ++ /* Dirty directory handling */ ++ struct list_head dirty_dirs; /* List of dirty directories */ ++ ++ /* Summary */ ++ int chunks_per_summary; ++ struct yaffs_summary_tags *sum_tags; ++ ++ /* Statistics */ ++ u32 n_page_writes; ++ u32 n_page_reads; ++ u32 n_erasures; ++ u32 n_bad_queries; ++ u32 n_bad_markings; ++ u32 n_erase_failures; ++ u32 n_gc_copies; ++ u32 all_gcs; ++ u32 passive_gc_count; ++ u32 oldest_dirty_gc_count; ++ u32 n_gc_blocks; ++ u32 bg_gcs; ++ u32 n_retried_writes; ++ u32 n_retired_blocks; ++ u32 n_ecc_fixed; ++ u32 n_ecc_unfixed; ++ u32 n_tags_ecc_fixed; ++ u32 n_tags_ecc_unfixed; ++ u32 n_deletions; ++ u32 n_unmarked_deletions; ++ u32 refresh_count; ++ u32 cache_hits; ++ u32 tags_used; ++ u32 summary_used; ++ ++}; ++ ++/* ++ * Checkpointing definitions. ++ */ ++ ++#define YAFFS_CHECKPOINT_VERSION 8 ++ ++/* yaffs_checkpt_obj holds the definition of an object as dumped ++ * by checkpointing. ++ */ ++ ++ ++/* Checkpint object bits in bitfield: offset, length */ ++#define CHECKPOINT_VARIANT_BITS 0, 3 ++#define CHECKPOINT_DELETED_BITS 3, 1 ++#define CHECKPOINT_SOFT_DEL_BITS 4, 1 ++#define CHECKPOINT_UNLINKED_BITS 5, 1 ++#define CHECKPOINT_FAKE_BITS 6, 1 ++#define CHECKPOINT_RENAME_ALLOWED_BITS 7, 1 ++#define CHECKPOINT_UNLINK_ALLOWED_BITS 8, 1 ++#define CHECKPOINT_SERIAL_BITS 9, 8 ++ ++struct yaffs_checkpt_obj { ++ int struct_type; ++ u32 obj_id; ++ u32 parent_id; ++ int hdr_chunk; ++ u32 bit_field; ++ int n_data_chunks; ++ loff_t size_or_equiv_obj; ++}; ++ ++/* The CheckpointDevice structure holds the device information that changes ++ *at runtime and must be preserved over unmount/mount cycles. ++ */ ++struct yaffs_checkpt_dev { ++ int struct_type; ++ int n_erased_blocks; ++ int alloc_block; /* Current block being allocated off */ ++ u32 alloc_page; ++ int n_free_chunks; ++ ++ int n_deleted_files; /* Count of files awaiting deletion; */ ++ int n_unlinked_files; /* Count of unlinked files. */ ++ int n_bg_deletions; /* Count of background deletions. */ ++ ++ /* yaffs2 runtime stuff */ ++ unsigned seq_number; /* Sequence number of currently ++ * allocating block */ ++ ++}; ++ ++struct yaffs_checkpt_validity { ++ int struct_type; ++ u32 magic; ++ u32 version; ++ u32 head; ++}; ++ ++struct yaffs_shadow_fixer { ++ int obj_id; ++ int shadowed_id; ++ struct yaffs_shadow_fixer *next; ++}; ++ ++/* Structure for doing xattr modifications */ ++struct yaffs_xattr_mod { ++ int set; /* If 0 then this is a deletion */ ++ const YCHAR *name; ++ const void *data; ++ int size; ++ int flags; ++ int result; ++}; ++ ++/*----------------------- YAFFS Functions -----------------------*/ ++ ++int yaffs_guts_initialise(struct yaffs_dev *dev); ++void yaffs_deinitialise(struct yaffs_dev *dev); ++void yaffs_guts_cleanup(struct yaffs_dev *dev); ++ ++int yaffs_get_n_free_chunks(struct yaffs_dev *dev); ++ ++int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR * old_name, ++ struct yaffs_obj *new_dir, const YCHAR * new_name); ++ ++int yaffs_unlink_obj(struct yaffs_obj *obj); ++ ++int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR * name); ++int yaffs_del_obj(struct yaffs_obj *obj); ++struct yaffs_obj *yaffs_retype_obj(struct yaffs_obj *obj, ++ enum yaffs_obj_type type); ++ ++ ++int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR * name, int buffer_size); ++loff_t yaffs_get_obj_length(struct yaffs_obj *obj); ++int yaffs_get_obj_inode(struct yaffs_obj *obj); ++unsigned yaffs_get_obj_type(struct yaffs_obj *obj); ++int yaffs_get_obj_link_count(struct yaffs_obj *obj); ++ ++/* File operations */ ++int yaffs_file_rd(struct yaffs_obj *obj, u8 * buffer, loff_t offset, ++ int n_bytes); ++int yaffs_wr_file(struct yaffs_obj *obj, const u8 * buffer, loff_t offset, ++ int n_bytes, int write_trhrough); ++int yaffs_resize_file(struct yaffs_obj *obj, loff_t new_size); ++ ++struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent, ++ const YCHAR *name, u32 mode, u32 uid, ++ u32 gid); ++ ++int yaffs_flush_file(struct yaffs_obj *in, ++ int update_time, ++ int data_sync, ++ int discard_cache); ++ ++/* Flushing and checkpointing */ ++void yaffs_flush_whole_cache(struct yaffs_dev *dev, int discard); ++ ++int yaffs_checkpoint_save(struct yaffs_dev *dev); ++int yaffs_checkpoint_restore(struct yaffs_dev *dev); ++ ++/* Directory operations */ ++struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR *name, ++ u32 mode, u32 uid, u32 gid); ++struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *the_dir, ++ const YCHAR *name); ++struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number); ++ ++/* Link operations */ ++struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR *name, ++ struct yaffs_obj *equiv_obj); ++ ++struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj); ++ ++/* Symlink operations */ ++struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent, ++ const YCHAR *name, u32 mode, u32 uid, ++ u32 gid, const YCHAR *alias); ++YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj); ++ ++/* Special inodes (fifos, sockets and devices) */ ++struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent, ++ const YCHAR *name, u32 mode, u32 uid, ++ u32 gid, u32 rdev); ++ ++int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR *name, ++ const void *value, int size, int flags); ++int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR *name, void *value, ++ int size); ++int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size); ++int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR *name); ++ ++/* Special directories */ ++struct yaffs_obj *yaffs_root(struct yaffs_dev *dev); ++struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev); ++ ++void yaffs_handle_defered_free(struct yaffs_obj *obj); ++ ++void yaffs_update_dirty_dirs(struct yaffs_dev *dev); ++ ++int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency); ++ ++/* Debug dump */ ++int yaffs_dump_obj(struct yaffs_obj *obj); ++ ++void yaffs_guts_test(struct yaffs_dev *dev); ++int yaffs_guts_ll_init(struct yaffs_dev *dev); ++ ++ ++/* A few useful functions to be used within the core files*/ ++void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash, ++ int lyn); ++int yaffs_check_ff(u8 *buffer, int n_bytes); ++void yaffs_handle_chunk_error(struct yaffs_dev *dev, ++ struct yaffs_block_info *bi); ++ ++u8 *yaffs_get_temp_buffer(struct yaffs_dev *dev); ++void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 *buffer); ++ ++struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev, ++ int number, ++ enum yaffs_obj_type type); ++int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk, ++ int nand_chunk, int in_scan); ++void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR *name); ++void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj, ++ const struct yaffs_obj_hdr *oh); ++void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj); ++YCHAR *yaffs_clone_str(const YCHAR *str); ++void yaffs_link_fixup(struct yaffs_dev *dev, struct list_head *hard_list); ++void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no); ++int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name, ++ int force, int is_shrink, int shadows, ++ struct yaffs_xattr_mod *xop); ++void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id, ++ int backward_scanning); ++int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks); ++struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev); ++struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev, ++ struct yaffs_file_var *file_struct, ++ u32 chunk_id, ++ struct yaffs_tnode *passed_tn); ++ ++int yaffs_do_file_wr(struct yaffs_obj *in, const u8 *buffer, loff_t offset, ++ int n_bytes, int write_trhrough); ++void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size); ++void yaffs_skip_rest_of_block(struct yaffs_dev *dev); ++ ++int yaffs_count_free_chunks(struct yaffs_dev *dev); ++ ++struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev, ++ struct yaffs_file_var *file_struct, ++ u32 chunk_id); ++ ++u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn, ++ unsigned pos); ++ ++int yaffs_is_non_empty_dir(struct yaffs_obj *obj); ++ ++int yaffs_guts_format_dev(struct yaffs_dev *dev); ++ ++void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr, ++ int *chunk_out, u32 *offset_out); ++/* ++ * Marshalling functions to get loff_t file sizes into and out of ++ * object headers. ++ */ ++void yaffs_oh_size_load(struct yaffs_dev *dev, struct yaffs_obj_hdr *oh, ++ loff_t fsize, int do_endian); ++loff_t yaffs_oh_to_size(struct yaffs_dev *dev, struct yaffs_obj_hdr *oh, ++ int do_endian); ++loff_t yaffs_max_file_size(struct yaffs_dev *dev); ++ ++ ++/* yaffs_wr_data_obj needs to be exposed to allow the cache to access it. */ ++int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk, ++ const u8 *buffer, int n_bytes, int use_reserve); ++ ++/* ++ * Debug function to count number of blocks in each state ++ * NB Needs to be called with correct number of integers ++ */ ++ ++void yaffs_count_blocks_by_state(struct yaffs_dev *dev, int bs[10]); ++ ++int yaffs_find_chunk_in_file(struct yaffs_obj *in, int inode_chunk, ++ struct yaffs_ext_tags *tags); ++ ++/* ++ * Define LOFF_T_32_BIT if a 32-bit LOFF_T is being used. ++ * Not serious if you get this wrong - you might just get some warnings. ++*/ ++ ++#ifdef LOFF_T_32_BIT ++#define FSIZE_LOW(fsize) (fsize) ++#define FSIZE_HIGH(fsize) 0 ++#define FSIZE_COMBINE(high, low) (low) ++#else ++#define FSIZE_LOW(fsize) ((fsize) & 0xffffffff) ++#define FSIZE_HIGH(fsize)(((fsize) >> 32) & 0xffffffff) ++#define FSIZE_COMBINE(high, low) ((((loff_t) (high)) << 32) | \ ++ (((loff_t) (low)) & 0xFFFFFFFF)) ++#endif ++ ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_linux.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_linux.h.patch new file mode 100644 index 00000000..526810f7 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_linux.h.patch @@ -0,0 +1,51 @@ +diff -drupN a/fs/yaffs2/yaffs_linux.h b/fs/yaffs2/yaffs_linux.h +--- a/fs/yaffs2/yaffs_linux.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_linux.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,47 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_LINUX_H__ ++#define __YAFFS_LINUX_H__ ++ ++#include "yportenv.h" ++ ++struct yaffs_linux_context { ++ struct list_head context_list; /* List of these we have mounted */ ++ struct yaffs_dev *dev; ++ struct super_block *super; ++ struct task_struct *bg_thread; /* Background thread for this device */ ++ int bg_running; ++ struct mutex gross_lock; /* Gross locking mutex*/ ++ u8 *spare_buffer; /* For mtdif2 use. Don't know the buffer size ++ * at compile time so we have to allocate it. ++ */ ++ struct list_head search_contexts; ++ struct task_struct *readdir_process; ++ unsigned mount_id; ++ int dirty; ++}; ++ ++#define yaffs_dev_to_lc(dev) ((struct yaffs_linux_context *)((dev)->os_context)) ++#define yaffs_dev_to_mtd(dev) ((struct mtd_info *)((dev)->driver_context)) ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++#define WRITE_SIZE_STR "writesize" ++#define WRITE_SIZE(mtd) ((mtd)->writesize) ++#else ++#define WRITE_SIZE_STR "oobblock" ++#define WRITE_SIZE(mtd) ((mtd)->oobblock) ++#endif ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_mtdif.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_mtdif.c.patch new file mode 100644 index 00000000..7775b8d3 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_mtdif.c.patch @@ -0,0 +1,319 @@ +diff -drupN a/fs/yaffs2/yaffs_mtdif.c b/fs/yaffs2/yaffs_mtdif.c +--- a/fs/yaffs2/yaffs_mtdif.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_mtdif.c 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,315 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * 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. ++ */ ++ ++#include "yportenv.h" ++ ++#include "yaffs_mtdif.h" ++ ++#include "linux/mtd/mtd.h" ++#include "linux/types.h" ++#include "linux/time.h" ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)) ++#include "linux/mtd/nand.h" ++#else ++#include "linux/mtd/rawnand.h" ++#endif ++#include "linux/kernel.h" ++#include "linux/version.h" ++#include "linux/types.h" ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) ++#include "uapi/linux/major.h" ++#endif ++ ++#include "yaffs_trace.h" ++#include "yaffs_guts.h" ++#include "yaffs_linux.h" ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) ++#define MTD_OPS_AUTO_OOB MTD_OOB_AUTO ++#endif ++ ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) ++#define mtd_erase(m, ei) (m)->erase(m, ei) ++#define mtd_write_oob(m, addr, pops) (m)->write_oob(m, addr, pops) ++#define mtd_read_oob(m, addr, pops) (m)->read_oob(m, addr, pops) ++#define mtd_block_isbad(m, offs) (m)->block_isbad(m, offs) ++#define mtd_block_markbad(m, offs) (m)->block_markbad(m, offs) ++#endif ++ ++int nandmtd_erase_block(struct yaffs_dev *dev, int block_no) ++{ ++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev); ++ u32 addr = ((loff_t) block_no) * dev->param.total_bytes_per_chunk * ++ dev->param.chunks_per_block; ++ struct erase_info ei; ++ int retval = 0; ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 17, 0)) ++ ei.mtd = mtd; ++#endif ++ ei.addr = addr; ++ ei.len = dev->param.total_bytes_per_chunk * dev->param.chunks_per_block; ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 17, 0)) ++ ei.time = 1000; ++ ei.retries = 2; ++ ei.callback = NULL; ++ ei.priv = (u_long) dev; ++#endif ++ ++ retval = mtd_erase(mtd, &ei); ++ ++ if (retval == 0) ++ return YAFFS_OK; ++ ++ return YAFFS_FAIL; ++} ++ ++static int yaffs_mtd_write(struct yaffs_dev *dev, int nand_chunk, ++ const u8 *data, int data_len, ++ const u8 *oob, int oob_len) ++{ ++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev); ++ loff_t addr; ++ struct mtd_oob_ops ops; ++ int retval; ++ ++ yaffs_trace(YAFFS_TRACE_MTD, ++ "yaffs_mtd_write(%p, %d, %p, %d, %p, %d)\n", ++ dev, nand_chunk, data, data_len, oob, oob_len); ++ ++ if (!data || !data_len) { ++ data = NULL; ++ data_len = 0; ++ } ++ ++ if (!oob || !oob_len) { ++ oob = NULL; ++ oob_len = 0; ++ } ++ ++ addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk; ++ //printk("write addr %x, nand_chunk %x, total_bytes_per_chunk %x\n", (unsigned int)addr, (unsigned int)nand_chunk, dev->param.total_bytes_per_chunk); ++ memset(&ops, 0, sizeof(ops)); ++ ops.mode = MTD_OPS_AUTO_OOB; ++ ops.len = (data) ? data_len : 0; ++ ops.ooblen = oob_len; ++ ops.datbuf = (u8 *)data; ++ ops.oobbuf = (u8 *)oob; ++ ++ retval = mtd_write_oob(mtd, addr, &ops); ++ if (retval) { ++ yaffs_trace(YAFFS_TRACE_MTD, ++ "write_oob failed, chunk %d, mtd error %d", ++ nand_chunk, retval); ++ } ++ return retval ? YAFFS_FAIL : YAFFS_OK; ++} ++ ++static int yaffs_mtd_read(struct yaffs_dev *dev, int nand_chunk, ++ u8 *data, int data_len, ++ u8 *oob, int oob_len, ++ enum yaffs_ecc_result *ecc_result) ++{ ++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev); ++ loff_t addr; ++ struct mtd_oob_ops ops; ++ int retval; ++ ++ addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk; ++ //printk("read addr %x, nand_chunk %x, total_bytes_per_chunk %x\n", (unsigned int)addr, (unsigned int)nand_chunk, dev->param.total_bytes_per_chunk); ++ memset(&ops, 0, sizeof(ops)); ++ ops.mode = MTD_OPS_AUTO_OOB; ++ ops.len = (data) ? data_len : 0; ++ ops.ooblen = oob_len; ++ ops.datbuf = data; ++ ops.oobbuf = oob; ++ ++#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 20)) ++ /* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug; ++ * help it out with ops.len = ops.ooblen when ops.datbuf == NULL. ++ */ ++ ops.len = (ops.datbuf) ? ops.len : ops.ooblen; ++#endif ++ /* Read page and oob using MTD. ++ * Check status and determine ECC result. ++ */ ++ retval = mtd_read_oob(mtd, addr, &ops); ++ if (retval) ++ yaffs_trace(YAFFS_TRACE_MTD, ++ "read_oob failed, chunk %d, mtd error %d", ++ nand_chunk, retval); ++ ++ switch (retval) { ++ case 0: ++ /* no error */ ++ if(ecc_result) ++ *ecc_result = YAFFS_ECC_RESULT_NO_ERROR; ++ break; ++ ++ case -EUCLEAN: ++ /* MTD's ECC fixed the data */ ++ if(ecc_result) ++ *ecc_result = YAFFS_ECC_RESULT_FIXED; ++ dev->n_ecc_fixed++; ++ break; ++ ++ case -EBADMSG: ++ default: ++ /* MTD's ECC could not fix the data */ ++ dev->n_ecc_unfixed++; ++ if(ecc_result) ++ *ecc_result = YAFFS_ECC_RESULT_UNFIXED; ++ return YAFFS_FAIL; ++ } ++ ++ return YAFFS_OK; ++} ++ ++static int yaffs_mtd_erase(struct yaffs_dev *dev, int block_no) ++{ ++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev); ++ ++ loff_t addr; ++ struct erase_info ei; ++ int retval = 0; ++ u32 block_size; ++ ++ block_size = dev->param.total_bytes_per_chunk * ++ dev->param.chunks_per_block; ++ addr = ((loff_t) block_no) * block_size; ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 17, 0)) ++ ei.mtd = mtd; ++#endif ++ ei.addr = addr; ++ ei.len = block_size; ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 17, 0)) ++ ei.time = 1000; ++ ei.retries = 2; ++ ei.callback = NULL; ++ ei.priv = (u_long) dev; ++#endif ++ ++ retval = mtd_erase(mtd, &ei); ++ ++ if (retval == 0) ++ return YAFFS_OK; ++ ++ return YAFFS_FAIL; ++} ++ ++static int yaffs_mtd_mark_bad(struct yaffs_dev *dev, int block_no) ++{ ++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev); ++ int blocksize = dev->param.chunks_per_block * dev->param.total_bytes_per_chunk; ++ int retval; ++ ++ yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", block_no); ++ ++ retval = mtd_block_markbad(mtd, (loff_t) blocksize * block_no); ++ return (retval) ? YAFFS_FAIL : YAFFS_OK; ++} ++ ++static int yaffs_mtd_check_bad(struct yaffs_dev *dev, int block_no) ++{ ++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev); ++ int blocksize = dev->param.chunks_per_block * dev->param.total_bytes_per_chunk; ++ int retval; ++ ++ yaffs_trace(YAFFS_TRACE_MTD, "checking block %d bad", block_no); ++ ++ retval = mtd_block_isbad(mtd, (loff_t) blocksize * block_no); ++ return (retval) ? YAFFS_FAIL : YAFFS_OK; ++} ++ ++static int yaffs_mtd_initialise(struct yaffs_dev *dev) ++{ ++ return YAFFS_OK; ++} ++ ++static int yaffs_mtd_deinitialise(struct yaffs_dev *dev) ++{ ++ return YAFFS_OK; ++} ++ ++void yaffs_mtd_drv_install(struct yaffs_dev *dev) ++{ ++ struct yaffs_driver *drv = &dev->drv; ++ ++ drv->drv_write_chunk_fn = yaffs_mtd_write; ++ drv->drv_read_chunk_fn = yaffs_mtd_read; ++ drv->drv_erase_fn = yaffs_mtd_erase; ++ drv->drv_mark_bad_fn = yaffs_mtd_mark_bad; ++ drv->drv_check_bad_fn = yaffs_mtd_check_bad; ++ drv->drv_initialise_fn = yaffs_mtd_initialise; ++ drv->drv_deinitialise_fn = yaffs_mtd_deinitialise; ++} ++ ++struct mtd_info * yaffs_get_mtd_device(dev_t sdev) ++{ ++ struct mtd_info *mtd; ++ ++ mtd = yaffs_get_mtd_device(sdev); ++ ++ /* Check it's an mtd device..... */ ++ if (MAJOR(sdev) != MTD_BLOCK_MAJOR) ++ return NULL; /* This isn't an mtd device */ ++ ++ /* Check it's NAND */ ++ if (mtd->type != MTD_NANDFLASH) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "yaffs: MTD device is not NAND it's type %d", ++ mtd->type); ++ return NULL; ++ } ++ ++ yaffs_trace(YAFFS_TRACE_OS, " %s %d", WRITE_SIZE_STR, WRITE_SIZE(mtd)); ++ yaffs_trace(YAFFS_TRACE_OS, " oobsize %d", mtd->oobsize); ++ yaffs_trace(YAFFS_TRACE_OS, " erasesize %d", mtd->erasesize); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) ++ yaffs_trace(YAFFS_TRACE_OS, " size %u", mtd->size); ++#else ++ yaffs_trace(YAFFS_TRACE_OS, " size %lld", mtd->size); ++#endif ++ ++ return mtd; ++} ++ ++int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags) ++{ ++ if (yaffs_version == 2) { ++ if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE || ++ mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) && ++ !inband_tags) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "MTD device does not have the right page sizes" ++ ); ++ return -1; ++ } ++ } else { ++ if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK || ++ mtd->oobsize != YAFFS_BYTES_PER_SPARE) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "MTD device does not support have the right page sizes" ++ ); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++void yaffs_put_mtd_device(struct mtd_info *mtd) ++{ ++ if (mtd) ++ put_mtd_device(mtd); ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_mtdif.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_mtdif.h.patch new file mode 100644 index 00000000..b7d5b6fb --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_mtdif.h.patch @@ -0,0 +1,28 @@ +diff -drupN a/fs/yaffs2/yaffs_mtdif.h b/fs/yaffs2/yaffs_mtdif.h +--- a/fs/yaffs2/yaffs_mtdif.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_mtdif.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,24 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_MTDIF_H__ ++#define __YAFFS_MTDIF_H__ ++ ++#include "yaffs_guts.h" ++ ++void yaffs_mtd_drv_install(struct yaffs_dev *dev); ++struct mtd_info * yaffs_get_mtd_device(dev_t sdev); ++void yaffs_put_mtd_device(struct mtd_info *mtd); ++int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags); ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_nameval.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_nameval.c.patch new file mode 100644 index 00000000..def23ab1 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_nameval.c.patch @@ -0,0 +1,233 @@ +diff -drupN a/fs/yaffs2/yaffs_nameval.c b/fs/yaffs2/yaffs_nameval.c +--- a/fs/yaffs2/yaffs_nameval.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_nameval.c 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,229 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * 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 simple implementation of a name-value store assumes a small number of ++* values and fits into a small finite buffer. ++ * ++ * Each attribute is stored as a record: ++ * sizeof(size) bytes record size. ++ * strnlen+1 bytes name null terminated. ++ * nbytes value. ++ * ---------- ++ * total size stored in record size ++ * ++ * This code has not been tested with unicode yet. ++ */ ++ ++#include "yaffs_nameval.h" ++#include "yaffs_guts.h" ++#include "yportenv.h" ++#include "yaffs_endian.h" ++ ++static int nval_find(struct yaffs_dev *dev, ++ const char *xb, int xb_size, const YCHAR *name, ++ int *exist_size) ++{ ++ int pos = 0; ++ s32 size; ++ ++ memcpy(&size, xb, sizeof(size)); ++ yaffs_do_endian_s32(dev, &size); ++ ++ while (size > 0 && (size < xb_size) && (pos + size < xb_size)) { ++ if (!strncmp((YCHAR *) (xb + pos + sizeof(size)), ++ name, size)) { ++ if (exist_size) ++ *exist_size = size; ++ return pos; ++ } ++ pos += size; ++ if (pos < (int)(xb_size - sizeof(size))) { ++ memcpy(&size, xb + pos, sizeof(size)); ++ yaffs_do_endian_s32(dev, &size); ++ ++ } else ++ size = 0; ++ } ++ if (exist_size) ++ *exist_size = 0; ++ return -ENODATA; ++} ++ ++static int nval_used(struct yaffs_dev *dev, const char *xb, int xb_size) ++{ ++ int pos = 0; ++ s32 size; ++ ++ memcpy(&size, xb + pos, sizeof(size)); ++ yaffs_do_endian_s32(dev, &size); ++ ++ while (size > 0 && (size < xb_size) && (pos + size < xb_size)) { ++ pos += size; ++ if (pos < (int)(xb_size - sizeof(size))) { ++ memcpy(&size, xb + pos, sizeof(size)); ++ yaffs_do_endian_s32(dev, &size); ++ } else ++ size = 0; ++ } ++ return pos; ++} ++ ++int nval_del(struct yaffs_dev *dev, char *xb, int xb_size, const YCHAR *name) ++{ ++ int pos = nval_find(dev, xb, xb_size, name, NULL); ++ s32 size; ++ ++ if (pos < 0 || pos >= xb_size) ++ return -ENODATA; ++ ++ /* Find size, shift rest over this record, ++ * then zero out the rest of buffer */ ++ memcpy(&size, xb + pos, sizeof(size)); ++ yaffs_do_endian_s32(dev, &size); ++ ++ memcpy(xb + pos, xb + pos + size, xb_size - (pos + size)); ++ memset(xb + (xb_size - size), 0, size); ++ return 0; ++} ++ ++int nval_set(struct yaffs_dev *dev, ++ char *xb, int xb_size, const YCHAR *name, const char *buf, ++ int bsize, int flags) ++{ ++ int pos; ++ int namelen = strnlen(name, xb_size); ++ int size_exist = 0; ++ int space; ++ int start; ++ s32 reclen; ++ s32 reclen_endianised; ++ ++ pos = nval_find(dev, xb, xb_size, name, &size_exist); ++ ++ if (flags & XATTR_CREATE && pos >= 0) ++ return -EEXIST; ++ if (flags & XATTR_REPLACE && pos < 0) ++ return -ENODATA; ++ ++ start = nval_used(dev, xb, xb_size); ++ space = xb_size - start + size_exist; ++ ++ reclen = (sizeof(reclen) + namelen + 1 + bsize); ++ ++ if (reclen > space) ++ return -ENOSPC; ++ ++ if (pos >= 0) { ++ /* Exists, so delete it. */ ++ nval_del(dev, xb, xb_size, name); ++ start = nval_used(dev, xb, xb_size); ++ } ++ ++ pos = start; ++ ++ reclen_endianised = reclen; ++ yaffs_do_endian_s32(dev, &reclen_endianised); ++ memcpy(xb + pos, &reclen_endianised, sizeof(reclen_endianised)); ++ pos += sizeof(reclen_endianised); ++ strncpy((YCHAR *) (xb + pos), name, reclen); ++ pos += (namelen + 1); ++ memcpy(xb + pos, buf, bsize); ++ return 0; ++} ++ ++int nval_get(struct yaffs_dev *dev, ++ const char *xb, int xb_size, const YCHAR * name, char *buf, ++ int bsize) ++{ ++ int pos = nval_find(dev, xb, xb_size, name, NULL); ++ s32 size; ++ ++ if (pos >= 0 && pos < xb_size) { ++ ++ memcpy(&size, xb + pos, sizeof(size)); ++ yaffs_do_endian_s32(dev, &size); ++ pos += sizeof(size); /* advance past record length */ ++ size -= sizeof(size); ++ ++ /* Advance over name string */ ++ while (xb[pos] && size > 0 && pos < xb_size) { ++ pos++; ++ size--; ++ } ++ /*Advance over NUL */ ++ pos++; ++ size--; ++ ++ /* If bsize is zero then this is a size query. ++ * Return the size, but don't copy. ++ */ ++ if (!bsize) ++ return size; ++ ++ if (size <= bsize) { ++ memcpy(buf, xb + pos, size); ++ return size; ++ } ++ } ++ if (pos >= 0) ++ return -ERANGE; ++ ++ return -ENODATA; ++} ++ ++int nval_list(struct yaffs_dev *dev, const char *xb, int xb_size, char *buf, int bsize) ++{ ++ int pos = 0; ++ s32 size; ++ int name_len; ++ int ncopied = 0; ++ int filled = 0; ++ ++ memcpy(&size, xb + pos, sizeof(size)); ++ yaffs_do_endian_s32(dev, &size); ++ ++ while (size > (int)(sizeof(size)) && ++ size <= xb_size && ++ (pos + size) < xb_size && ++ !filled) { ++ pos += sizeof(size); ++ size -= sizeof(size); ++ name_len = strnlen((YCHAR *) (xb + pos), size); ++ if (ncopied + name_len + 1 < bsize) { ++ memcpy(buf, xb + pos, name_len * sizeof(YCHAR)); ++ buf += name_len; ++ *buf = '\0'; ++ buf++; ++ if (sizeof(YCHAR) > 1) { ++ *buf = '\0'; ++ buf++; ++ } ++ ncopied += (name_len + 1); ++ } else { ++ filled = 1; ++ } ++ pos += size; ++ if (pos < (int)(xb_size - sizeof(size))) { ++ memcpy(&size, xb + pos, sizeof(size)); ++ yaffs_do_endian_s32(dev, &size); ++ } ++ else ++ size = 0; ++ } ++ return ncopied; ++} ++ ++int nval_hasvalues(struct yaffs_dev *dev, const char *xb, int xb_size) ++{ ++ return nval_used(dev, xb, xb_size) > 0; ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_nameval.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_nameval.h.patch new file mode 100644 index 00000000..fac4eef9 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_nameval.h.patch @@ -0,0 +1,36 @@ +diff -drupN a/fs/yaffs2/yaffs_nameval.h b/fs/yaffs2/yaffs_nameval.h +--- a/fs/yaffs2/yaffs_nameval.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_nameval.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,32 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __NAMEVAL_H__ ++#define __NAMEVAL_H__ ++ ++#include "yportenv.h" ++ ++struct yaffs_dev; ++ ++int nval_del(struct yaffs_dev *dev, char *xb, int xb_size, const YCHAR * name); ++int nval_set(struct yaffs_dev *dev, ++ char *xb, int xb_size, const YCHAR * name, const char *buf, ++ int bsize, int flags); ++int nval_get(struct yaffs_dev *dev, ++ const char *xb, int xb_size, const YCHAR * name, char *buf, ++ int bsize); ++int nval_list(struct yaffs_dev *dev, ++ const char *xb, int xb_size, char *buf, int bsize); ++int nval_hasvalues(struct yaffs_dev *dev, const char *xb, int xb_size); ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_nand.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_nand.c.patch new file mode 100644 index 00000000..8ed39634 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_nand.c.patch @@ -0,0 +1,125 @@ +diff -drupN a/fs/yaffs2/yaffs_nand.c b/fs/yaffs2/yaffs_nand.c +--- a/fs/yaffs2/yaffs_nand.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_nand.c 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,121 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * 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. ++ */ ++ ++#include "yaffs_nand.h" ++#include "yaffs_tagscompat.h" ++ ++#include "yaffs_getblockinfo.h" ++#include "yaffs_summary.h" ++ ++static int apply_chunk_offset(struct yaffs_dev *dev, int chunk) ++{ ++ return chunk - dev->chunk_offset; ++} ++ ++int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk, ++ u8 *buffer, struct yaffs_ext_tags *tags) ++{ ++ int result; ++ struct yaffs_ext_tags local_tags; ++ int flash_chunk = apply_chunk_offset(dev, nand_chunk); ++ ++ dev->n_page_reads++; ++ ++ /* If there are no tags provided use local tags. */ ++ if (!tags) ++ tags = &local_tags; ++ ++ result = dev->tagger.read_chunk_tags_fn(dev, flash_chunk, buffer, tags); ++ if (tags && tags->ecc_result > YAFFS_ECC_RESULT_NO_ERROR) { ++ ++ struct yaffs_block_info *bi; ++ bi = yaffs_get_block_info(dev, ++ nand_chunk / ++ dev->param.chunks_per_block); ++ yaffs_handle_chunk_error(dev, bi); ++ } ++ return result; ++} ++ ++int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev, ++ int nand_chunk, ++ const u8 *buffer, struct yaffs_ext_tags *tags) ++{ ++ int result; ++ int flash_chunk = apply_chunk_offset(dev, nand_chunk); ++ ++ dev->n_page_writes++; ++ ++ if (!tags) { ++ yaffs_trace(YAFFS_TRACE_ERROR, "Writing with no tags"); ++ BUG(); ++ return YAFFS_FAIL; ++ } ++ ++ tags->seq_number = dev->seq_number; ++ tags->chunk_used = 1; ++ yaffs_trace(YAFFS_TRACE_WRITE, ++ "Writing chunk %d tags %d %d", ++ nand_chunk, tags->obj_id, tags->chunk_id); ++ ++ result = dev->tagger.write_chunk_tags_fn(dev, flash_chunk, ++ buffer, tags); ++ ++ yaffs_summary_add(dev, tags, nand_chunk); ++ ++ return result; ++} ++ ++int yaffs_mark_bad(struct yaffs_dev *dev, int block_no) ++{ ++ block_no -= dev->block_offset; ++ dev->n_bad_markings++; ++ ++ if (dev->param.disable_bad_block_marking) ++ return YAFFS_OK; ++ ++ return dev->tagger.mark_bad_fn(dev, block_no); ++} ++ ++ ++int yaffs_query_init_block_state(struct yaffs_dev *dev, ++ int block_no, ++ enum yaffs_block_state *state, ++ u32 *seq_number) ++{ ++ block_no -= dev->block_offset; ++ return dev->tagger.query_block_fn(dev, block_no, state, seq_number); ++} ++ ++int yaffs_erase_block(struct yaffs_dev *dev, int block_no) ++{ ++ int result; ++ ++ block_no -= dev->block_offset; ++ dev->n_erasures++; ++ result = dev->drv.drv_erase_fn(dev, block_no); ++ return result; ++} ++ ++int yaffs_init_nand(struct yaffs_dev *dev) ++{ ++ if (dev->drv.drv_initialise_fn) ++ return dev->drv.drv_initialise_fn(dev); ++ return YAFFS_OK; ++} ++ ++int yaffs_deinit_nand(struct yaffs_dev *dev) ++{ ++ if (dev->drv.drv_deinitialise_fn) ++ return dev->drv.drv_deinitialise_fn(dev); ++ return YAFFS_OK; ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_nand.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_nand.h.patch new file mode 100644 index 00000000..39b10edd --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_nand.h.patch @@ -0,0 +1,42 @@ +diff -drupN a/fs/yaffs2/yaffs_nand.h b/fs/yaffs2/yaffs_nand.h +--- a/fs/yaffs2/yaffs_nand.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_nand.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,38 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_NAND_H__ ++#define __YAFFS_NAND_H__ ++#include "yaffs_guts.h" ++ ++int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk, ++ u8 *buffer, struct yaffs_ext_tags *tags); ++ ++int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev, ++ int nand_chunk, ++ const u8 *buffer, struct yaffs_ext_tags *tags); ++ ++int yaffs_mark_bad(struct yaffs_dev *dev, int block_no); ++ ++int yaffs_query_init_block_state(struct yaffs_dev *dev, ++ int block_no, ++ enum yaffs_block_state *state, ++ unsigned *seq_number); ++ ++int yaffs_erase_block(struct yaffs_dev *dev, int flash_block); ++ ++int yaffs_init_nand(struct yaffs_dev *dev); ++int yaffs_deinit_nand(struct yaffs_dev *dev); ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_packedtags1.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_packedtags1.c.patch new file mode 100644 index 00000000..8c9abde3 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_packedtags1.c.patch @@ -0,0 +1,58 @@ +diff -drupN a/fs/yaffs2/yaffs_packedtags1.c b/fs/yaffs2/yaffs_packedtags1.c +--- a/fs/yaffs2/yaffs_packedtags1.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_packedtags1.c 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,54 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * 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. ++ */ ++ ++#include "yaffs_packedtags1.h" ++#include "yportenv.h" ++ ++static const u8 all_ff[20] = { ++ 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff ++}; ++ ++void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt, ++ const struct yaffs_ext_tags *t) ++{ ++ pt->chunk_id = t->chunk_id; ++ pt->serial_number = t->serial_number; ++ pt->n_bytes = t->n_bytes; ++ pt->obj_id = t->obj_id; ++ pt->ecc = 0; ++ pt->deleted = (t->is_deleted) ? 0 : 1; ++ pt->unused_stuff = 0; ++ pt->should_be_ff = 0xffffffff; ++} ++ ++void yaffs_unpack_tags1(struct yaffs_ext_tags *t, ++ const struct yaffs_packed_tags1 *pt) ++{ ++ if (memcmp(all_ff, pt, sizeof(struct yaffs_packed_tags1))) { ++ t->block_bad = 0; ++ if (pt->should_be_ff != 0xffffffff) ++ t->block_bad = 1; ++ t->chunk_used = 1; ++ t->obj_id = pt->obj_id; ++ t->chunk_id = pt->chunk_id; ++ t->n_bytes = pt->n_bytes; ++ t->ecc_result = YAFFS_ECC_RESULT_NO_ERROR; ++ t->is_deleted = (pt->deleted) ? 0 : 1; ++ t->serial_number = pt->serial_number; ++ } else { ++ memset(t, 0, sizeof(struct yaffs_ext_tags)); ++ } ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_packedtags1.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_packedtags1.h.patch new file mode 100644 index 00000000..4e03613a --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_packedtags1.h.patch @@ -0,0 +1,42 @@ +diff -drupN a/fs/yaffs2/yaffs_packedtags1.h b/fs/yaffs2/yaffs_packedtags1.h +--- a/fs/yaffs2/yaffs_packedtags1.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_packedtags1.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,38 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++/* This is used to pack YAFFS1 tags, not YAFFS2 tags. */ ++ ++#ifndef __YAFFS_PACKEDTAGS1_H__ ++#define __YAFFS_PACKEDTAGS1_H__ ++ ++#include "yaffs_guts.h" ++ ++struct yaffs_packed_tags1 { ++ u32 chunk_id:20; ++ u32 serial_number:2; ++ u32 n_bytes:10; ++ u32 obj_id:18; ++ u32 ecc:12; ++ u32 deleted:1; ++ u32 unused_stuff:1; ++ unsigned should_be_ff; ++ ++}; ++ ++void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt, ++ const struct yaffs_ext_tags *t); ++void yaffs_unpack_tags1(struct yaffs_ext_tags *t, ++ const struct yaffs_packed_tags1 *pt); ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_packedtags2.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_packedtags2.c.patch new file mode 100644 index 00000000..39a07067 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_packedtags2.c.patch @@ -0,0 +1,215 @@ +diff -drupN a/fs/yaffs2/yaffs_packedtags2.c b/fs/yaffs2/yaffs_packedtags2.c +--- a/fs/yaffs2/yaffs_packedtags2.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_packedtags2.c 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,211 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * 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. ++ */ ++ ++#include "yaffs_packedtags2.h" ++#include "yportenv.h" ++#include "yaffs_trace.h" ++#include "yaffs_endian.h" ++ ++/* This code packs a set of extended tags into a binary structure for ++ * NAND storage ++ */ ++ ++/* Some of the information is "extra" struff which can be packed in to ++ * speed scanning ++ * This is defined by having the EXTRA_HEADER_INFO_FLAG set. ++ */ ++ ++/* Extra flags applied to chunk_id */ ++ ++#define EXTRA_HEADER_INFO_FLAG 0x80000000 ++#define EXTRA_SHRINK_FLAG 0x40000000 ++#define EXTRA_SHADOWS_FLAG 0x20000000 ++#define EXTRA_SPARE_FLAGS 0x10000000 ++ ++#define ALL_EXTRA_FLAGS 0xf0000000 ++ ++/* Also, the top 4 bits of the object Id are set to the object type. */ ++#define EXTRA_OBJECT_TYPE_SHIFT (28) ++#define EXTRA_OBJECT_TYPE_MASK ((0x0f) << EXTRA_OBJECT_TYPE_SHIFT) ++ ++static void yaffs_dump_packed_tags2_tags_only( ++ const struct yaffs_packed_tags2_tags_only *ptt) ++{ ++ (void) ptt; ++ ++ yaffs_trace(YAFFS_TRACE_MTD, ++ "packed tags obj %d chunk %d byte %d seq %d", ++ ptt->obj_id, ptt->chunk_id, ptt->n_bytes, ptt->seq_number); ++} ++ ++static void yaffs_dump_packed_tags2(const struct yaffs_packed_tags2 *pt) ++{ ++ yaffs_dump_packed_tags2_tags_only(&pt->t); ++} ++ ++static void yaffs_dump_tags2(const struct yaffs_ext_tags *t) ++{ ++ ++ (void) t; ++ yaffs_trace(YAFFS_TRACE_MTD, ++ "ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d", ++ t->ecc_result, t->block_bad, t->chunk_used, t->obj_id, ++ t->chunk_id, t->n_bytes, t->is_deleted, t->serial_number, ++ t->seq_number); ++ ++} ++ ++static int yaffs_check_tags_extra_packable(const struct yaffs_ext_tags *t) ++{ ++ if (t->chunk_id != 0 || !t->extra_available) ++ return 0; ++ ++ /* Check if the file size is too long to store */ ++ if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE && ++ (t->extra_file_size >> 31) != 0) ++ return 0; ++ return 1; ++} ++ ++void yaffs_pack_tags2_tags_only(struct yaffs_dev *dev, ++ struct yaffs_packed_tags2_tags_only *ptt, ++ const struct yaffs_ext_tags *t) ++{ ++ ptt->chunk_id = t->chunk_id; ++ ptt->seq_number = t->seq_number; ++ ptt->n_bytes = t->n_bytes; ++ ptt->obj_id = t->obj_id; ++ ++ /* Only store extra tags for object headers. ++ * If it is a file then only store if the file size is short\ ++ * enough to fit. ++ */ ++ if (yaffs_check_tags_extra_packable(t)) { ++ /* Store the extra header info instead */ ++ /* We save the parent object in the chunk_id */ ++ ptt->chunk_id = EXTRA_HEADER_INFO_FLAG | t->extra_parent_id; ++ if (t->extra_is_shrink) ++ ptt->chunk_id |= EXTRA_SHRINK_FLAG; ++ if (t->extra_shadows) ++ ptt->chunk_id |= EXTRA_SHADOWS_FLAG; ++ ++ ptt->obj_id &= ~EXTRA_OBJECT_TYPE_MASK; ++ ptt->obj_id |= (t->extra_obj_type << EXTRA_OBJECT_TYPE_SHIFT); ++ ++ if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK) ++ ptt->n_bytes = t->extra_equiv_id; ++ else if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE) ++ ptt->n_bytes = (unsigned) t->extra_file_size; ++ else ++ ptt->n_bytes = 0; ++ } ++ ++ yaffs_dump_packed_tags2_tags_only(ptt); ++ yaffs_dump_tags2(t); ++ yaffs_do_endian_packed_tags2(dev, ptt); ++} ++ ++void yaffs_pack_tags2(struct yaffs_dev *dev, ++ struct yaffs_packed_tags2 *pt, ++ const struct yaffs_ext_tags *t, int tags_ecc) ++{ ++ yaffs_pack_tags2_tags_only(dev, &pt->t, t); ++ ++ if (tags_ecc) ++ yaffs_ecc_calc_other((unsigned char *)&pt->t, ++ sizeof(struct yaffs_packed_tags2_tags_only), ++ &pt->ecc); ++} ++ ++void yaffs_unpack_tags2_tags_only(struct yaffs_dev *dev, ++ struct yaffs_ext_tags *t, ++ struct yaffs_packed_tags2_tags_only *ptt_ptr) ++{ ++ struct yaffs_packed_tags2_tags_only ptt_copy = *ptt_ptr; ++ ++ memset(t, 0, sizeof(struct yaffs_ext_tags)); ++ ++ if (ptt_copy.seq_number == 0xffffffff) ++ return; ++ ++ yaffs_do_endian_packed_tags2(dev, &ptt_copy); ++ ++ t->block_bad = 0; ++ t->chunk_used = 1; ++ t->obj_id = ptt_copy.obj_id; ++ t->chunk_id = ptt_copy.chunk_id; ++ t->n_bytes = ptt_copy.n_bytes; ++ t->is_deleted = 0; ++ t->serial_number = 0; ++ t->seq_number = ptt_copy.seq_number; ++ ++ /* Do extra header info stuff */ ++ if (ptt_copy.chunk_id & EXTRA_HEADER_INFO_FLAG) { ++ t->chunk_id = 0; ++ t->n_bytes = 0; ++ ++ t->extra_available = 1; ++ t->extra_parent_id = ptt_copy.chunk_id & (~(ALL_EXTRA_FLAGS)); ++ t->extra_is_shrink = ptt_copy.chunk_id & EXTRA_SHRINK_FLAG ? 1 : 0; ++ t->extra_shadows = ptt_copy.chunk_id & EXTRA_SHADOWS_FLAG ? 1 : 0; ++ t->extra_obj_type = ptt_copy.obj_id >> EXTRA_OBJECT_TYPE_SHIFT; ++ t->obj_id &= ~EXTRA_OBJECT_TYPE_MASK; ++ ++ if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK) ++ t->extra_equiv_id = ptt_copy.n_bytes; ++ else ++ t->extra_file_size = ptt_copy.n_bytes; ++ } ++ yaffs_dump_packed_tags2_tags_only(ptt_ptr); ++ yaffs_dump_tags2(t); ++} ++ ++void yaffs_unpack_tags2(struct yaffs_dev *dev, ++ struct yaffs_ext_tags *t, ++ struct yaffs_packed_tags2 *pt, ++ int tags_ecc) ++{ ++ enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_NO_ERROR; ++ ++ if (pt->t.seq_number != 0xffffffff && tags_ecc) { ++ /* Chunk is in use and we need to do ECC */ ++ ++ struct yaffs_ecc_other ecc; ++ int result; ++ yaffs_ecc_calc_other((unsigned char *)&pt->t, ++ sizeof(struct yaffs_packed_tags2_tags_only), ++ &ecc); ++ result = ++ yaffs_ecc_correct_other((unsigned char *)&pt->t, ++ sizeof(struct yaffs_packed_tags2_tags_only), ++ &pt->ecc, &ecc); ++ switch (result) { ++ case 0: ++ ecc_result = YAFFS_ECC_RESULT_NO_ERROR; ++ break; ++ case 1: ++ ecc_result = YAFFS_ECC_RESULT_FIXED; ++ break; ++ case -1: ++ ecc_result = YAFFS_ECC_RESULT_UNFIXED; ++ break; ++ default: ++ ecc_result = YAFFS_ECC_RESULT_UNKNOWN; ++ } ++ } ++ yaffs_unpack_tags2_tags_only(dev, t, &pt->t); ++ ++ t->ecc_result = ecc_result; ++ ++ yaffs_dump_packed_tags2(pt); ++ yaffs_dump_tags2(t); ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_packedtags2.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_packedtags2.h.patch new file mode 100644 index 00000000..24ccc3e9 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_packedtags2.h.patch @@ -0,0 +1,54 @@ +diff -drupN a/fs/yaffs2/yaffs_packedtags2.h b/fs/yaffs2/yaffs_packedtags2.h +--- a/fs/yaffs2/yaffs_packedtags2.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_packedtags2.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,50 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++/* This is used to pack YAFFS2 tags, not YAFFS1tags. */ ++ ++#ifndef __YAFFS_PACKEDTAGS2_H__ ++#define __YAFFS_PACKEDTAGS2_H__ ++ ++#include "yaffs_guts.h" ++#include "yaffs_ecc.h" ++ ++struct yaffs_packed_tags2_tags_only { ++ unsigned seq_number; ++ unsigned obj_id; ++ unsigned chunk_id; ++ unsigned n_bytes; ++}; ++ ++struct yaffs_packed_tags2 { ++ struct yaffs_packed_tags2_tags_only t; ++ struct yaffs_ecc_other ecc; ++}; ++ ++/* Full packed tags with ECC, used for oob tags */ ++void yaffs_pack_tags2(struct yaffs_dev *dev, ++ struct yaffs_packed_tags2 *pt, ++ const struct yaffs_ext_tags *t, int tags_ecc); ++void yaffs_unpack_tags2(struct yaffs_dev *dev, ++ struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt, ++ int tags_ecc); ++ ++/* Only the tags part (no ECC for use with inband tags */ ++void yaffs_pack_tags2_tags_only(struct yaffs_dev *dev, ++ struct yaffs_packed_tags2_tags_only *pt, ++ const struct yaffs_ext_tags *t); ++void yaffs_unpack_tags2_tags_only(struct yaffs_dev *dev, ++ struct yaffs_ext_tags *t, ++ struct yaffs_packed_tags2_tags_only *pt); ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_summary.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_summary.c.patch new file mode 100644 index 00000000..ecf9a4a1 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_summary.c.patch @@ -0,0 +1,313 @@ +diff -drupN a/fs/yaffs2/yaffs_summary.c b/fs/yaffs2/yaffs_summary.c +--- a/fs/yaffs2/yaffs_summary.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_summary.c 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,309 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * 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. ++ */ ++ ++/* Summaries write the useful part of the tags for the chunks in a block into an ++ * an array which is written to the last n chunks of the block. ++ * Reading the summaries gives all the tags for the block in one read. Much ++ * faster. ++ * ++ * Chunks holding summaries are marked with tags making it look like ++ * they are part of a fake file. ++ * ++ * The summary could also be used during gc. ++ * ++ */ ++ ++#include "yaffs_summary.h" ++#include "yaffs_packedtags2.h" ++#include "yaffs_nand.h" ++#include "yaffs_getblockinfo.h" ++#include "yaffs_bitmap.h" ++ ++/* ++ * The summary is built up in an array of summary tags. ++ * This gets written to the last one or two (maybe more) chunks in a block. ++ * A summary header is written as the first part of each chunk of summary data. ++ * The summary header must match or the summary is rejected. ++ */ ++ ++/* Summary tags don't need the sequence number because that is redundant. */ ++struct yaffs_summary_tags { ++ unsigned obj_id; ++ unsigned chunk_id; ++ unsigned n_bytes; ++}; ++ ++/* Summary header */ ++struct yaffs_summary_header { ++ unsigned version; /* Must match current version */ ++ unsigned block; /* Must be this block */ ++ unsigned seq; /* Must be this sequence number */ ++ unsigned sum; /* Just add up all the bytes in the tags */ ++}; ++ ++ ++static void yaffs_summary_clear(struct yaffs_dev *dev) ++{ ++ if (!dev->sum_tags) ++ return; ++ memset(dev->sum_tags, 0, dev->chunks_per_summary * ++ sizeof(struct yaffs_summary_tags)); ++} ++ ++ ++void yaffs_summary_deinit(struct yaffs_dev *dev) ++{ ++ kfree(dev->sum_tags); ++ dev->sum_tags = NULL; ++ kfree(dev->gc_sum_tags); ++ dev->gc_sum_tags = NULL; ++ dev->chunks_per_summary = 0; ++} ++ ++int yaffs_summary_init(struct yaffs_dev *dev) ++{ ++ int sum_bytes; ++ int chunks_used; /* Number of chunks used by summary */ ++ int sum_tags_bytes; ++ ++ sum_bytes = dev->param.chunks_per_block * ++ sizeof(struct yaffs_summary_tags); ++ ++ chunks_used = (sum_bytes + dev->data_bytes_per_chunk - 1)/ ++ (dev->data_bytes_per_chunk - ++ sizeof(struct yaffs_summary_header)); ++ ++ dev->chunks_per_summary = dev->param.chunks_per_block - chunks_used; ++ sum_tags_bytes = sizeof(struct yaffs_summary_tags) * ++ dev->chunks_per_summary; ++ dev->sum_tags = kmalloc(sum_tags_bytes, GFP_NOFS); ++ dev->gc_sum_tags = kmalloc(sum_tags_bytes, GFP_NOFS); ++ if (!dev->sum_tags || !dev->gc_sum_tags) { ++ yaffs_summary_deinit(dev); ++ return YAFFS_FAIL; ++ } ++ ++ yaffs_summary_clear(dev); ++ ++ return YAFFS_OK; ++} ++ ++static unsigned yaffs_summary_sum(struct yaffs_dev *dev) ++{ ++ u8 *sum_buffer = (u8 *)dev->sum_tags; ++ int i; ++ unsigned sum = 0; ++ ++ i = sizeof(struct yaffs_summary_tags) * ++ dev->chunks_per_summary; ++ while (i > 0) { ++ sum += *sum_buffer; ++ sum_buffer++; ++ i--; ++ } ++ ++ return sum; ++} ++ ++static int yaffs_summary_write(struct yaffs_dev *dev, int blk) ++{ ++ struct yaffs_ext_tags tags; ++ u8 *buffer; ++ u8 *sum_buffer = (u8 *)dev->sum_tags; ++ int n_bytes; ++ int chunk_in_nand; ++ int chunk_in_block; ++ int result; ++ int this_tx; ++ struct yaffs_summary_header hdr; ++ int sum_bytes_per_chunk = dev->data_bytes_per_chunk - sizeof(hdr); ++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk); ++ ++ buffer = yaffs_get_temp_buffer(dev); ++ n_bytes = sizeof(struct yaffs_summary_tags) * ++ dev->chunks_per_summary; ++ memset(&tags, 0, sizeof(struct yaffs_ext_tags)); ++ tags.obj_id = YAFFS_OBJECTID_SUMMARY; ++ tags.chunk_id = 1; ++ chunk_in_block = dev->chunks_per_summary; ++ chunk_in_nand = dev->alloc_block * dev->param.chunks_per_block + ++ dev->chunks_per_summary; ++ hdr.version = YAFFS_SUMMARY_VERSION; ++ hdr.block = blk; ++ hdr.seq = bi->seq_number; ++ hdr.sum = yaffs_summary_sum(dev); ++ ++ do { ++ this_tx = n_bytes; ++ if (this_tx > sum_bytes_per_chunk) ++ this_tx = sum_bytes_per_chunk; ++ memcpy(buffer, &hdr, sizeof(hdr)); ++ memcpy(buffer + sizeof(hdr), sum_buffer, this_tx); ++ tags.n_bytes = this_tx + sizeof(hdr); ++ result = yaffs_wr_chunk_tags_nand(dev, chunk_in_nand, ++ buffer, &tags); ++ ++ if (result != YAFFS_OK) ++ break; ++ yaffs_set_chunk_bit(dev, blk, chunk_in_block); ++ bi->pages_in_use++; ++ dev->n_free_chunks--; ++ ++ n_bytes -= this_tx; ++ sum_buffer += this_tx; ++ chunk_in_nand++; ++ chunk_in_block++; ++ tags.chunk_id++; ++ } while (result == YAFFS_OK && n_bytes > 0); ++ yaffs_release_temp_buffer(dev, buffer); ++ ++ ++ if (result == YAFFS_OK) ++ bi->has_summary = 1; ++ ++ ++ return result; ++} ++ ++int yaffs_summary_read(struct yaffs_dev *dev, ++ struct yaffs_summary_tags *st, ++ int blk) ++{ ++ struct yaffs_ext_tags tags; ++ u8 *buffer; ++ u8 *sum_buffer = (u8 *)st; ++ int n_bytes; ++ u32 chunk_id; ++ int chunk_in_nand; ++ int chunk_in_block; ++ int result; ++ int this_tx; ++ struct yaffs_summary_header hdr; ++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk); ++ int sum_bytes_per_chunk = dev->data_bytes_per_chunk - sizeof(hdr); ++ ++ buffer = yaffs_get_temp_buffer(dev); ++ n_bytes = sizeof(struct yaffs_summary_tags) * dev->chunks_per_summary; ++ chunk_in_block = dev->chunks_per_summary; ++ chunk_in_nand = blk * dev->param.chunks_per_block + ++ dev->chunks_per_summary; ++ chunk_id = 1; ++ do { ++ this_tx = n_bytes; ++ if (this_tx > sum_bytes_per_chunk) ++ this_tx = sum_bytes_per_chunk; ++ result = yaffs_rd_chunk_tags_nand(dev, chunk_in_nand, ++ buffer, &tags); ++ ++ if (tags.chunk_id != chunk_id || ++ tags.obj_id != YAFFS_OBJECTID_SUMMARY || ++ tags.chunk_used == 0 || ++ tags.ecc_result > YAFFS_ECC_RESULT_FIXED || ++ tags.n_bytes != (this_tx + sizeof(hdr))) ++ result = YAFFS_FAIL; ++ if (result != YAFFS_OK) ++ break; ++ ++ if (st == dev->sum_tags) { ++ /* If we're scanning then update the block info */ ++ yaffs_set_chunk_bit(dev, blk, chunk_in_block); ++ bi->pages_in_use++; ++ } ++ memcpy(&hdr, buffer, sizeof(hdr)); ++ memcpy(sum_buffer, buffer + sizeof(hdr), this_tx); ++ n_bytes -= this_tx; ++ sum_buffer += this_tx; ++ chunk_in_nand++; ++ chunk_in_block++; ++ chunk_id++; ++ } while (result == YAFFS_OK && n_bytes > 0); ++ yaffs_release_temp_buffer(dev, buffer); ++ ++ if (result == YAFFS_OK) { ++ /* Verify header */ ++ if (hdr.version != YAFFS_SUMMARY_VERSION || ++ hdr.seq != bi->seq_number || ++ hdr.sum != yaffs_summary_sum(dev)) ++ result = YAFFS_FAIL; ++ } ++ ++ if (st == dev->sum_tags && result == YAFFS_OK) ++ bi->has_summary = 1; ++ ++ return result; ++} ++ ++int yaffs_summary_add(struct yaffs_dev *dev, ++ struct yaffs_ext_tags *tags, ++ int chunk_in_nand) ++{ ++ struct yaffs_packed_tags2_tags_only tags_only; ++ struct yaffs_summary_tags *sum_tags; ++ int block_in_nand = chunk_in_nand / dev->param.chunks_per_block; ++ int chunk_in_block = chunk_in_nand % dev->param.chunks_per_block; ++ ++ if (!dev->sum_tags) ++ return YAFFS_OK; ++ ++ if (chunk_in_block >= 0 && chunk_in_block < dev->chunks_per_summary) { ++ yaffs_pack_tags2_tags_only(dev, &tags_only, tags); ++ sum_tags = &dev->sum_tags[chunk_in_block]; ++ ++ sum_tags->chunk_id = tags_only.chunk_id; ++ sum_tags->n_bytes = tags_only.n_bytes; ++ sum_tags->obj_id = tags_only.obj_id; ++ ++ if (chunk_in_block == dev->chunks_per_summary - 1) { ++ /* Time to write out the summary */ ++ yaffs_summary_write(dev, block_in_nand); ++ yaffs_summary_clear(dev); ++ yaffs_skip_rest_of_block(dev); ++ } ++ } ++ return YAFFS_OK; ++} ++ ++int yaffs_summary_fetch(struct yaffs_dev *dev, ++ struct yaffs_ext_tags *tags, ++ int chunk_in_block) ++{ ++ struct yaffs_packed_tags2_tags_only tags_only; ++ struct yaffs_summary_tags *sum_tags; ++ if (chunk_in_block >= 0 && chunk_in_block < dev->chunks_per_summary) { ++ sum_tags = &dev->sum_tags[chunk_in_block]; ++ tags_only.chunk_id = sum_tags->chunk_id; ++ tags_only.n_bytes = sum_tags->n_bytes; ++ tags_only.obj_id = sum_tags->obj_id; ++ yaffs_unpack_tags2_tags_only(dev, tags, &tags_only); ++ return YAFFS_OK; ++ } ++ return YAFFS_FAIL; ++} ++ ++void yaffs_summary_gc(struct yaffs_dev *dev, int blk) ++{ ++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk); ++ u32 i; ++ ++ if (!bi->has_summary) ++ return; ++ ++ for (i = dev->chunks_per_summary; ++ i < dev->param.chunks_per_block; ++ i++) { ++ if (yaffs_check_chunk_bit(dev, blk, i)) { ++ yaffs_clear_chunk_bit(dev, blk, i); ++ bi->pages_in_use--; ++ dev->n_free_chunks++; ++ } ++ } ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_summary.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_summary.h.patch new file mode 100644 index 00000000..2d9b2fe4 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_summary.h.patch @@ -0,0 +1,40 @@ +diff -drupN a/fs/yaffs2/yaffs_summary.h b/fs/yaffs2/yaffs_summary.h +--- a/fs/yaffs2/yaffs_summary.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_summary.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,36 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_SUMMARY_H__ ++#define __YAFFS_SUMMARY_H__ ++ ++#include "yaffs_packedtags2.h" ++ ++ ++int yaffs_summary_init(struct yaffs_dev *dev); ++void yaffs_summary_deinit(struct yaffs_dev *dev); ++ ++int yaffs_summary_add(struct yaffs_dev *dev, ++ struct yaffs_ext_tags *tags, ++ int chunk_in_block); ++int yaffs_summary_fetch(struct yaffs_dev *dev, ++ struct yaffs_ext_tags *tags, ++ int chunk_in_block); ++int yaffs_summary_read(struct yaffs_dev *dev, ++ struct yaffs_summary_tags *st, ++ int blk); ++void yaffs_summary_gc(struct yaffs_dev *dev, int blk); ++ ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_tagscompat.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_tagscompat.c.patch new file mode 100644 index 00000000..edb2059c --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_tagscompat.c.patch @@ -0,0 +1,403 @@ +diff -drupN a/fs/yaffs2/yaffs_tagscompat.c b/fs/yaffs2/yaffs_tagscompat.c +--- a/fs/yaffs2/yaffs_tagscompat.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_tagscompat.c 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,399 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * 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 file handles yaffs1-style tags to allow compatibility with Yaffs1 style ++ * flash layouts. ++ */ ++ ++#include "yaffs_guts.h" ++#include "yaffs_tagscompat.h" ++#include "yaffs_ecc.h" ++#include "yaffs_getblockinfo.h" ++#include "yaffs_trace.h" ++#include "yaffs_endian.h" ++ ++static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk); ++ ++ ++/********** Tags ECC calculations *********/ ++ ++void yaffs_calc_tags_ecc(struct yaffs_tags *tags) ++{ ++ /* Calculate an ecc */ ++ unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes; ++ unsigned i, j; ++ unsigned ecc = 0; ++ unsigned bit = 0; ++ ++ tags->ecc = 0; ++ ++ for (i = 0; i < 8; i++) { ++ for (j = 1; j & 0xff; j <<= 1) { ++ bit++; ++ if (b[i] & j) ++ ecc ^= bit; ++ } ++ } ++ tags->ecc = ecc; ++} ++ ++int yaffs_check_tags_ecc(struct yaffs_tags *tags) ++{ ++ unsigned ecc = tags->ecc; ++ ++ yaffs_calc_tags_ecc(tags); ++ ++ ecc ^= tags->ecc; ++ ++ if (ecc && ecc <= 64) { ++ /* TODO: Handle the failure better. Retire? */ ++ unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes; ++ ++ ecc--; ++ ++ b[ecc / 8] ^= (1 << (ecc & 7)); ++ ++ /* Now recvalc the ecc */ ++ yaffs_calc_tags_ecc(tags); ++ ++ return 1; /* recovered error */ ++ } else if (ecc) { ++ /* Wierd ecc failure value */ ++ /* TODO Need to do somethiong here */ ++ return -1; /* unrecovered error */ ++ } ++ return 0; ++} ++ ++/********** Tags **********/ ++ ++/* ++ * During tags storing/retireval we use a copy of the tags so that ++ * we can modify the endian etc without damaging the previous structure. ++ */ ++static void yaffs_load_tags_to_spare(struct yaffs_dev *dev, ++ struct yaffs_spare *spare_ptr, ++ struct yaffs_tags *tags_ptr) ++{ ++ union yaffs_tags_union *tu_ptr = (union yaffs_tags_union *)tags_ptr; ++ union yaffs_tags_union tags_stored = *tu_ptr; ++ ++ yaffs_calc_tags_ecc(&tags_stored.as_tags); ++ ++ yaffs_do_endian_u32(dev, &tags_stored.as_u32[0]); ++ yaffs_do_endian_u32(dev, &tags_stored.as_u32[1]); ++ ++ spare_ptr->tb0 = tags_stored.as_bytes[0]; ++ spare_ptr->tb1 = tags_stored.as_bytes[1]; ++ spare_ptr->tb2 = tags_stored.as_bytes[2]; ++ spare_ptr->tb3 = tags_stored.as_bytes[3]; ++ spare_ptr->tb4 = tags_stored.as_bytes[4]; ++ spare_ptr->tb5 = tags_stored.as_bytes[5]; ++ spare_ptr->tb6 = tags_stored.as_bytes[6]; ++ spare_ptr->tb7 = tags_stored.as_bytes[7]; ++} ++ ++static void yaffs_get_tags_from_spare(struct yaffs_dev *dev, ++ struct yaffs_spare *spare_ptr, ++ struct yaffs_tags *tags_ptr) ++{ ++ union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr; ++ union yaffs_tags_union tags_stored; ++ int result; ++ ++ tags_stored.as_bytes[0] = spare_ptr->tb0; ++ tags_stored.as_bytes[1] = spare_ptr->tb1; ++ tags_stored.as_bytes[2] = spare_ptr->tb2; ++ tags_stored.as_bytes[3] = spare_ptr->tb3; ++ tags_stored.as_bytes[4] = spare_ptr->tb4; ++ tags_stored.as_bytes[5] = spare_ptr->tb5; ++ tags_stored.as_bytes[6] = spare_ptr->tb6; ++ tags_stored.as_bytes[7] = spare_ptr->tb7; ++ ++ yaffs_do_endian_u32(dev, &tags_stored.as_u32[0]); ++ yaffs_do_endian_u32(dev, &tags_stored.as_u32[1]); ++ ++ *tu = tags_stored; ++ ++ result = yaffs_check_tags_ecc(tags_ptr); ++ if (result > 0) ++ dev->n_tags_ecc_fixed++; ++ else if (result < 0) ++ dev->n_tags_ecc_unfixed++; ++} ++ ++static void yaffs_spare_init(struct yaffs_spare *spare) ++{ ++ memset(spare, 0xff, sizeof(struct yaffs_spare)); ++} ++ ++static int yaffs_wr_nand(struct yaffs_dev *dev, ++ int nand_chunk, const u8 *data, ++ struct yaffs_spare *spare) ++{ ++ int data_size = dev->data_bytes_per_chunk; ++ ++ return dev->drv.drv_write_chunk_fn(dev, nand_chunk, ++ data, data_size, ++ (u8 *) spare, sizeof(*spare)); ++} ++ ++static int yaffs_rd_chunk_nand(struct yaffs_dev *dev, ++ int nand_chunk, ++ u8 *data, ++ struct yaffs_spare *spare, ++ enum yaffs_ecc_result *ecc_result, ++ int correct_errors) ++{ ++ int ret_val; ++ struct yaffs_spare local_spare; ++ int data_size; ++ int spare_size; ++ int ecc_result1, ecc_result2; ++ u8 calc_ecc[3]; ++ ++ if (!spare) { ++ /* If we don't have a real spare, then we use a local one. */ ++ /* Need this for the calculation of the ecc */ ++ spare = &local_spare; ++ } ++ data_size = dev->data_bytes_per_chunk; ++ spare_size = sizeof(struct yaffs_spare); ++ ++ if (dev->param.use_nand_ecc) ++ return dev->drv.drv_read_chunk_fn(dev, nand_chunk, ++ data, data_size, ++ (u8 *) spare, spare_size, ++ ecc_result); ++ ++ ++ /* Handle the ECC at this level. */ ++ ++ ret_val = dev->drv.drv_read_chunk_fn(dev, nand_chunk, ++ data, data_size, ++ (u8 *)spare, spare_size, ++ NULL); ++ if (!data || !correct_errors) ++ return ret_val; ++ ++ /* Do ECC correction if needed. */ ++ yaffs_ecc_calc(data, calc_ecc); ++ ecc_result1 = yaffs_ecc_correct(data, spare->ecc1, calc_ecc); ++ yaffs_ecc_calc(&data[256], calc_ecc); ++ ecc_result2 = yaffs_ecc_correct(&data[256], spare->ecc2, calc_ecc); ++ ++ if (ecc_result1 > 0) { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "**>>yaffs ecc error fix performed on chunk %d:0", ++ nand_chunk); ++ dev->n_ecc_fixed++; ++ } else if (ecc_result1 < 0) { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "**>>yaffs ecc error unfixed on chunk %d:0", ++ nand_chunk); ++ dev->n_ecc_unfixed++; ++ } ++ ++ if (ecc_result2 > 0) { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "**>>yaffs ecc error fix performed on chunk %d:1", ++ nand_chunk); ++ dev->n_ecc_fixed++; ++ } else if (ecc_result2 < 0) { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "**>>yaffs ecc error unfixed on chunk %d:1", ++ nand_chunk); ++ dev->n_ecc_unfixed++; ++ } ++ ++ if (ecc_result1 || ecc_result2) { ++ /* We had a data problem on this page */ ++ yaffs_handle_rd_data_error(dev, nand_chunk); ++ } ++ ++ if (ecc_result1 < 0 || ecc_result2 < 0) ++ *ecc_result = YAFFS_ECC_RESULT_UNFIXED; ++ else if (ecc_result1 > 0 || ecc_result2 > 0) ++ *ecc_result = YAFFS_ECC_RESULT_FIXED; ++ else ++ *ecc_result = YAFFS_ECC_RESULT_NO_ERROR; ++ ++ return ret_val; ++} ++ ++/* ++ * Functions for robustisizing ++ */ ++ ++static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk) ++{ ++ int flash_block = nand_chunk / dev->param.chunks_per_block; ++ ++ /* Mark the block for retirement */ ++ yaffs_get_block_info(dev, flash_block + dev->block_offset)-> ++ needs_retiring = 1; ++ yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, ++ "**>>Block %d marked for retirement", ++ flash_block); ++ ++ /* TODO: ++ * Just do a garbage collection on the affected block ++ * then retire the block ++ * NB recursion ++ */ ++} ++ ++static int yaffs_tags_compat_wr(struct yaffs_dev *dev, ++ int nand_chunk, ++ const u8 *data, const struct yaffs_ext_tags *ext_tags) ++{ ++ struct yaffs_spare spare; ++ struct yaffs_tags tags; ++ ++ yaffs_spare_init(&spare); ++ ++ if (ext_tags->is_deleted) ++ spare.page_status = 0; ++ else { ++ tags.obj_id = ext_tags->obj_id; ++ tags.chunk_id = ext_tags->chunk_id; ++ ++ tags.n_bytes_lsb = ext_tags->n_bytes & (1024 - 1); ++ ++ if (dev->data_bytes_per_chunk >= 1024) ++ tags.n_bytes_msb = (ext_tags->n_bytes >> 10) & 3; ++ else ++ tags.n_bytes_msb = 3; ++ ++ tags.serial_number = ext_tags->serial_number; ++ ++ if (!dev->param.use_nand_ecc && data) { ++ yaffs_ecc_calc(data, spare.ecc1); ++ yaffs_ecc_calc(&data[256], spare.ecc2); ++ } ++ ++ yaffs_load_tags_to_spare(dev, &spare, &tags); ++ } ++ return yaffs_wr_nand(dev, nand_chunk, data, &spare); ++} ++ ++static int yaffs_tags_compat_rd(struct yaffs_dev *dev, ++ int nand_chunk, ++ u8 *data, struct yaffs_ext_tags *ext_tags) ++{ ++ struct yaffs_spare spare; ++ struct yaffs_tags tags; ++ enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_UNKNOWN; ++ static struct yaffs_spare spare_ff; ++ static int init; ++ int deleted; ++ ++ if (!init) { ++ memset(&spare_ff, 0xff, sizeof(spare_ff)); ++ init = 1; ++ } ++ ++ if (!yaffs_rd_chunk_nand(dev, nand_chunk, ++ data, &spare, &ecc_result, 1)) ++ return YAFFS_FAIL; ++ ++ /* ext_tags may be NULL */ ++ if (!ext_tags) ++ return YAFFS_OK; ++ ++ deleted = (hweight8(spare.page_status) < 7) ? 1 : 0; ++ ++ ext_tags->is_deleted = deleted; ++ ext_tags->ecc_result = ecc_result; ++ ext_tags->block_bad = 0; /* We're reading it */ ++ /* therefore it is not a bad block */ ++ ext_tags->chunk_used = ++ memcmp(&spare_ff, &spare, sizeof(spare_ff)) ? 1 : 0; ++ ++ if (ext_tags->chunk_used) { ++ yaffs_get_tags_from_spare(dev, &spare, &tags); ++ ++ ext_tags->obj_id = tags.obj_id; ++ ext_tags->chunk_id = tags.chunk_id; ++ ext_tags->n_bytes = tags.n_bytes_lsb; ++ ++ if (dev->data_bytes_per_chunk >= 1024) ++ ext_tags->n_bytes |= ++ (((unsigned)tags.n_bytes_msb) << 10); ++ ++ ext_tags->serial_number = tags.serial_number; ++ } ++ ++ return YAFFS_OK; ++} ++ ++static int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int flash_block) ++{ ++ struct yaffs_spare spare; ++ ++ memset(&spare, 0xff, sizeof(struct yaffs_spare)); ++ ++ spare.block_status = 'Y'; ++ ++ yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block, NULL, ++ &spare); ++ yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block + 1, ++ NULL, &spare); ++ ++ return YAFFS_OK; ++} ++ ++static int yaffs_tags_compat_query_block(struct yaffs_dev *dev, ++ int block_no, ++ enum yaffs_block_state *state, ++ u32 *seq_number) ++{ ++ struct yaffs_spare spare0, spare1; ++ static struct yaffs_spare spare_ff; ++ static int init; ++ enum yaffs_ecc_result dummy; ++ ++ if (!init) { ++ memset(&spare_ff, 0xff, sizeof(spare_ff)); ++ init = 1; ++ } ++ ++ *seq_number = 0; ++ ++ /* Look for bad block markers in the first two chunks */ ++ yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block, ++ NULL, &spare0, &dummy, 0); ++ yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block + 1, ++ NULL, &spare1, &dummy, 0); ++ ++ if (hweight8(spare0.block_status & spare1.block_status) < 7) ++ *state = YAFFS_BLOCK_STATE_DEAD; ++ else if (memcmp(&spare_ff, &spare0, sizeof(spare_ff)) == 0) ++ *state = YAFFS_BLOCK_STATE_EMPTY; ++ else ++ *state = YAFFS_BLOCK_STATE_NEEDS_SCAN; ++ ++ return YAFFS_OK; ++} ++ ++void yaffs_tags_compat_install(struct yaffs_dev *dev) ++{ ++ if(dev->param.is_yaffs2) ++ return; ++ if(!dev->tagger.write_chunk_tags_fn) ++ dev->tagger.write_chunk_tags_fn = yaffs_tags_compat_wr; ++ if(!dev->tagger.read_chunk_tags_fn) ++ dev->tagger.read_chunk_tags_fn = yaffs_tags_compat_rd; ++ if(!dev->tagger.query_block_fn) ++ dev->tagger.query_block_fn = yaffs_tags_compat_query_block; ++ if(!dev->tagger.mark_bad_fn) ++ dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad; ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_tagscompat.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_tagscompat.h.patch new file mode 100644 index 00000000..58f1eb79 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_tagscompat.h.patch @@ -0,0 +1,47 @@ +diff -drupN a/fs/yaffs2/yaffs_tagscompat.h b/fs/yaffs2/yaffs_tagscompat.h +--- a/fs/yaffs2/yaffs_tagscompat.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_tagscompat.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,43 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_TAGSCOMPAT_H__ ++#define __YAFFS_TAGSCOMPAT_H__ ++ ++ ++#include "yaffs_guts.h" ++ ++#if 0 ++ ++ ++int yaffs_tags_compat_wr(struct yaffs_dev *dev, ++ int nand_chunk, ++ const u8 *data, const struct yaffs_ext_tags *tags); ++int yaffs_tags_compat_rd(struct yaffs_dev *dev, ++ int nand_chunk, ++ u8 *data, struct yaffs_ext_tags *tags); ++int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int block_no); ++int yaffs_tags_compat_query_block(struct yaffs_dev *dev, ++ int block_no, ++ enum yaffs_block_state *state, ++ u32 *seq_number); ++ ++#endif ++ ++ ++void yaffs_tags_compat_install(struct yaffs_dev *dev); ++void yaffs_calc_tags_ecc(struct yaffs_tags *tags); ++int yaffs_check_tags_ecc(struct yaffs_tags *tags); ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_tagsmarshall.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_tagsmarshall.c.patch new file mode 100644 index 00000000..1db9f4c7 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_tagsmarshall.c.patch @@ -0,0 +1,209 @@ +diff -drupN a/fs/yaffs2/yaffs_tagsmarshall.c b/fs/yaffs2/yaffs_tagsmarshall.c +--- a/fs/yaffs2/yaffs_tagsmarshall.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_tagsmarshall.c 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,205 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * 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 file handles the marshalling (ie internal<-->external structure ++ * translation between the internal tags and the stored tags in Yaffs2-style ++ * tags storage. ++ */ ++ ++#include "yaffs_tagsmarshall.h" ++#include "yaffs_trace.h" ++#include "yaffs_packedtags2.h" ++ ++static int yaffs_tags_marshall_write(struct yaffs_dev *dev, ++ int nand_chunk, const u8 *data, ++ const struct yaffs_ext_tags *tags) ++{ ++ struct yaffs_packed_tags2 pt; ++ int retval; ++ ++ int packed_tags_size = ++ dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt); ++ void *packed_tags_ptr = ++ dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt; ++ ++ //printk("write no_tags_ecc is %d, packed_tags_size is %d\n", dev->param.no_tags_ecc, packed_tags_size); ++ yaffs_trace(YAFFS_TRACE_MTD, ++ "yaffs_tags_marshall_write chunk %d data %p tags %p", ++ nand_chunk, data, tags); ++ ++ /* For yaffs2 writing there must be both data and tags. ++ * If we're using inband tags, then the tags are stuffed into ++ * the end of the data buffer. ++ */ ++ if (!data || !tags) ++ BUG(); ++ else if (dev->param.inband_tags) { ++ struct yaffs_packed_tags2_tags_only *pt2tp; ++ pt2tp = ++ (struct yaffs_packed_tags2_tags_only *)(data + ++ dev-> ++ data_bytes_per_chunk); ++ yaffs_pack_tags2_tags_only(dev, pt2tp, tags); ++ } else { ++ yaffs_pack_tags2(dev, &pt, tags, !dev->param.no_tags_ecc); ++ } ++ ++ //printk("inband_tags is %d, packed_tags_ptr is %d, packed_tags_size is %d\n", dev->param.inband_tags, packed_tags_ptr, packed_tags_size); ++ retval = dev->drv.drv_write_chunk_fn(dev, nand_chunk, ++ data, dev->param.total_bytes_per_chunk, ++ (dev->param.inband_tags) ? NULL : packed_tags_ptr, ++ (dev->param.inband_tags) ? 0 : packed_tags_size); ++ ++ return retval; ++} ++ ++static int yaffs_tags_marshall_read(struct yaffs_dev *dev, ++ int nand_chunk, u8 *data, ++ struct yaffs_ext_tags *tags) ++{ ++ int retval = 0; ++ int local_data = 0; ++ u8 spare_buffer[100]; ++ enum yaffs_ecc_result ecc_result; ++ ++ struct yaffs_packed_tags2 pt; ++ ++ int packed_tags_size = ++ dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt); ++ void *packed_tags_ptr = ++ dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt; ++ ++ //printk("read packed_tags_size is %d, no_tags_ecc %d\n", packed_tags_size, dev->param.no_tags_ecc); ++ yaffs_trace(YAFFS_TRACE_MTD, ++ "yaffs_tags_marshall_read chunk %d data %p tags %p", ++ nand_chunk, data, tags); ++ ++ if (dev->param.inband_tags) { ++ if (!data) { ++ local_data = 1; ++ data = yaffs_get_temp_buffer(dev); ++ } ++ } ++ ++ if (dev->param.inband_tags || (data && !tags)) ++ retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk, ++ data, dev->param.total_bytes_per_chunk, ++ NULL, 0, ++ &ecc_result); ++ else if (tags) ++ retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk, ++ data, dev->param.total_bytes_per_chunk, ++ spare_buffer, packed_tags_size, ++ &ecc_result); ++ else ++ BUG(); ++ ++ ++ if (retval == YAFFS_FAIL) ++ return YAFFS_FAIL; ++ ++ if (dev->param.inband_tags) { ++ if (tags) { ++ struct yaffs_packed_tags2_tags_only *pt2tp; ++ pt2tp = ++ (struct yaffs_packed_tags2_tags_only *) ++ &data[dev->data_bytes_per_chunk]; ++ yaffs_unpack_tags2_tags_only(dev, tags, pt2tp); ++ } ++ } else if (tags) { ++ memcpy(packed_tags_ptr, spare_buffer, packed_tags_size); ++ yaffs_unpack_tags2(dev, tags, &pt, !dev->param.no_tags_ecc); ++ } ++ ++ if (local_data) ++ yaffs_release_temp_buffer(dev, data); ++ ++ if (tags && ecc_result == YAFFS_ECC_RESULT_UNFIXED) { ++ tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED; ++ dev->n_ecc_unfixed++; ++ } ++ ++ if (tags && ecc_result == YAFFS_ECC_RESULT_FIXED) { ++ if (tags->ecc_result <= YAFFS_ECC_RESULT_NO_ERROR) ++ tags->ecc_result = YAFFS_ECC_RESULT_FIXED; ++ dev->n_ecc_fixed++; ++ } ++ ++ if (ecc_result < YAFFS_ECC_RESULT_UNFIXED) ++ return YAFFS_OK; ++ else ++ return YAFFS_FAIL; ++} ++ ++static int yaffs_tags_marshall_query_block(struct yaffs_dev *dev, int block_no, ++ enum yaffs_block_state *state, ++ u32 *seq_number) ++{ ++ int retval; ++ ++ yaffs_trace(YAFFS_TRACE_MTD, "yaffs_tags_marshall_query_block %d", ++ block_no); ++ ++ retval = dev->drv.drv_check_bad_fn(dev, block_no); ++ ++ if (retval== YAFFS_FAIL) { ++ yaffs_trace(YAFFS_TRACE_MTD, "block is bad"); ++ ++ *state = YAFFS_BLOCK_STATE_DEAD; ++ *seq_number = 0; ++ } else { ++ struct yaffs_ext_tags t; ++ ++ yaffs_tags_marshall_read(dev, ++ block_no * dev->param.chunks_per_block, ++ NULL, &t); ++ ++ if (t.chunk_used) { ++ *seq_number = t.seq_number; ++ *state = YAFFS_BLOCK_STATE_NEEDS_SCAN; ++ } else { ++ *seq_number = 0; ++ *state = YAFFS_BLOCK_STATE_EMPTY; ++ } ++ } ++ ++ yaffs_trace(YAFFS_TRACE_MTD, ++ "block query returns seq %d state %d", ++ *seq_number, *state); ++ ++ return retval; ++} ++ ++static int yaffs_tags_marshall_mark_bad(struct yaffs_dev *dev, int block_no) ++{ ++ return dev->drv.drv_mark_bad_fn(dev, block_no); ++ ++} ++ ++ ++void yaffs_tags_marshall_install(struct yaffs_dev *dev) ++{ ++ if (!dev->param.is_yaffs2) ++ return; ++ ++ if (!dev->tagger.write_chunk_tags_fn) ++ dev->tagger.write_chunk_tags_fn = yaffs_tags_marshall_write; ++ ++ if (!dev->tagger.read_chunk_tags_fn) ++ dev->tagger.read_chunk_tags_fn = yaffs_tags_marshall_read; ++ ++ if (!dev->tagger.query_block_fn) ++ dev->tagger.query_block_fn = yaffs_tags_marshall_query_block; ++ ++ if (!dev->tagger.mark_bad_fn) ++ dev->tagger.mark_bad_fn = yaffs_tags_marshall_mark_bad; ++ ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_tagsmarshall.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_tagsmarshall.h.patch new file mode 100644 index 00000000..565511ea --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_tagsmarshall.h.patch @@ -0,0 +1,25 @@ +diff -drupN a/fs/yaffs2/yaffs_tagsmarshall.h b/fs/yaffs2/yaffs_tagsmarshall.h +--- a/fs/yaffs2/yaffs_tagsmarshall.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_tagsmarshall.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,21 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_TAGSMARSHALL_H__ ++#define __YAFFS_TAGSMARSHALL_H__ ++ ++#include "yaffs_guts.h" ++void yaffs_tags_marshall_install(struct yaffs_dev *dev); ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_trace.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_trace.h.patch new file mode 100644 index 00000000..71f02b37 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_trace.h.patch @@ -0,0 +1,60 @@ +diff -drupN a/fs/yaffs2/yaffs_trace.h b/fs/yaffs2/yaffs_trace.h +--- a/fs/yaffs2/yaffs_trace.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_trace.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,56 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YTRACE_H__ ++#define __YTRACE_H__ ++ ++extern unsigned int yaffs_trace_mask; ++extern unsigned int yaffs_wr_attempts; ++ ++/* ++ * Tracing flags. ++ * The flags masked in YAFFS_TRACE_ALWAYS are always traced. ++ */ ++ ++#define YAFFS_TRACE_OS 0x00000002 ++#define YAFFS_TRACE_ALLOCATE 0x00000004 ++#define YAFFS_TRACE_SCAN 0x00000008 ++#define YAFFS_TRACE_BAD_BLOCKS 0x00000010 ++#define YAFFS_TRACE_ERASE 0x00000020 ++#define YAFFS_TRACE_GC 0x00000040 ++#define YAFFS_TRACE_WRITE 0x00000080 ++#define YAFFS_TRACE_TRACING 0x00000100 ++#define YAFFS_TRACE_DELETION 0x00000200 ++#define YAFFS_TRACE_BUFFERS 0x00000400 ++#define YAFFS_TRACE_NANDACCESS 0x00000800 ++#define YAFFS_TRACE_GC_DETAIL 0x00001000 ++#define YAFFS_TRACE_SCAN_DEBUG 0x00002000 ++#define YAFFS_TRACE_MTD 0x00004000 ++#define YAFFS_TRACE_CHECKPOINT 0x00008000 ++ ++#define YAFFS_TRACE_VERIFY 0x00010000 ++#define YAFFS_TRACE_VERIFY_NAND 0x00020000 ++#define YAFFS_TRACE_VERIFY_FULL 0x00040000 ++#define YAFFS_TRACE_VERIFY_ALL 0x000f0000 ++ ++#define YAFFS_TRACE_SYNC 0x00100000 ++#define YAFFS_TRACE_BACKGROUND 0x00200000 ++#define YAFFS_TRACE_LOCK 0x00400000 ++#define YAFFS_TRACE_MOUNT 0x00800000 ++ ++#define YAFFS_TRACE_ERROR 0x40000000 ++#define YAFFS_TRACE_BUG 0x80000000 ++#define YAFFS_TRACE_ALWAYS 0xf0000000 ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_verify.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_verify.c.patch new file mode 100644 index 00000000..c04252ad --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_verify.c.patch @@ -0,0 +1,545 @@ +diff -drupN a/fs/yaffs2/yaffs_verify.c b/fs/yaffs2/yaffs_verify.c +--- a/fs/yaffs2/yaffs_verify.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_verify.c 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,541 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * 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. ++ */ ++ ++#include "yaffs_verify.h" ++#include "yaffs_trace.h" ++#include "yaffs_bitmap.h" ++#include "yaffs_getblockinfo.h" ++#include "yaffs_nand.h" ++ ++int yaffs_skip_verification(struct yaffs_dev *dev) ++{ ++ (void) dev; ++ return !(yaffs_trace_mask & ++ (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL)); ++} ++ ++static int yaffs_skip_full_verification(struct yaffs_dev *dev) ++{ ++ (void) dev; ++ return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_FULL)); ++} ++ ++static int yaffs_skip_nand_verification(struct yaffs_dev *dev) ++{ ++ (void) dev; ++ return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_NAND)); ++} ++ ++static const char * const block_state_name[] = { ++ "Unknown", ++ "Needs scan", ++ "Scanning", ++ "Empty", ++ "Allocating", ++ "Full", ++ "Dirty", ++ "Checkpoint", ++ "Collecting", ++ "Dead" ++}; ++ ++void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi, int n) ++{ ++ int actually_used; ++ int in_use; ++ ++ (void) block_state_name; ++ ++ if (yaffs_skip_verification(dev)) ++ return; ++ ++ /* Report illegal runtime states */ ++ if (bi->block_state >= YAFFS_NUMBER_OF_BLOCK_STATES) ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Block %d has undefined state %d", ++ n, bi->block_state); ++ ++ switch (bi->block_state) { ++ case YAFFS_BLOCK_STATE_UNKNOWN: ++ case YAFFS_BLOCK_STATE_SCANNING: ++ case YAFFS_BLOCK_STATE_NEEDS_SCAN: ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Block %d has bad run-state %s", ++ n, block_state_name[bi->block_state]); ++ } ++ ++ /* Check pages in use and soft deletions are legal */ ++ ++ actually_used = bi->pages_in_use - bi->soft_del_pages; ++ ++ if (bi->pages_in_use < 0 || ++ bi->pages_in_use > (int)dev->param.chunks_per_block || ++ bi->soft_del_pages < 0 || ++ bi->soft_del_pages > (int)dev->param.chunks_per_block || ++ actually_used < 0 || actually_used > (int)dev->param.chunks_per_block) ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Block %d has illegal values pages_in_used %d soft_del_pages %d", ++ n, bi->pages_in_use, bi->soft_del_pages); ++ ++ /* Check chunk bitmap legal */ ++ in_use = yaffs_count_chunk_bits(dev, n); ++ if (in_use != bi->pages_in_use) ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Block %d has inconsistent values pages_in_use %d counted chunk bits %d", ++ n, bi->pages_in_use, in_use); ++} ++ ++void yaffs_verify_collected_blk(struct yaffs_dev *dev, ++ struct yaffs_block_info *bi, int n) ++{ ++ yaffs_verify_blk(dev, bi, n); ++ ++ /* After collection the block should be in the erased state */ ++ ++ if (bi->block_state != YAFFS_BLOCK_STATE_COLLECTING && ++ bi->block_state != YAFFS_BLOCK_STATE_EMPTY) { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "Block %d is in state %d after gc, should be erased", ++ n, bi->block_state); ++ } ++} ++ ++void yaffs_verify_blocks(struct yaffs_dev *dev) ++{ ++ u32 i; ++ u32 state_count[YAFFS_NUMBER_OF_BLOCK_STATES]; ++ int illegal_states = 0; ++ ++ if (yaffs_skip_verification(dev)) ++ return; ++ ++ memset(state_count, 0, sizeof(state_count)); ++ ++ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { ++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, i); ++ yaffs_verify_blk(dev, bi, i); ++ ++ if (bi->block_state < YAFFS_NUMBER_OF_BLOCK_STATES) ++ state_count[bi->block_state]++; ++ else ++ illegal_states++; ++ } ++ ++ yaffs_trace(YAFFS_TRACE_VERIFY, "Block summary"); ++ ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "%d blocks have illegal states", ++ illegal_states); ++ if (state_count[YAFFS_BLOCK_STATE_ALLOCATING] > 1) ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Too many allocating blocks"); ++ ++ for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++) ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "%s %d blocks", ++ block_state_name[i], state_count[i]); ++ ++ if (dev->blocks_in_checkpt != state_count[YAFFS_BLOCK_STATE_CHECKPOINT]) ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Checkpoint block count wrong dev %d count %d", ++ dev->blocks_in_checkpt, ++ state_count[YAFFS_BLOCK_STATE_CHECKPOINT]); ++ ++ if (dev->n_erased_blocks != (int)state_count[YAFFS_BLOCK_STATE_EMPTY]) ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Erased block count wrong dev %d count %d", ++ dev->n_erased_blocks, ++ state_count[YAFFS_BLOCK_STATE_EMPTY]); ++ ++ if (state_count[YAFFS_BLOCK_STATE_COLLECTING] > 1) ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Too many collecting blocks %d (max is 1)", ++ state_count[YAFFS_BLOCK_STATE_COLLECTING]); ++} ++ ++/* ++ * Verify the object header. oh must be valid, but obj and tags may be NULL in ++ * which case those tests will not be performed. ++ */ ++void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh, ++ struct yaffs_ext_tags *tags, int parent_check) ++{ ++ if (obj && yaffs_skip_verification(obj->my_dev)) ++ return; ++ ++ if (!(tags && obj && oh)) { ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Verifying object header tags %p obj %p oh %p", ++ tags, obj, oh); ++ return; ++ } ++ ++ if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN || ++ oh->type > YAFFS_OBJECT_TYPE_MAX) ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Obj %d header type is illegal value 0x%x", ++ tags->obj_id, oh->type); ++ ++ if (tags->obj_id != obj->obj_id) ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Obj %d header mismatch obj_id %d", ++ tags->obj_id, obj->obj_id); ++ ++ /* ++ * Check that the object's parent ids match if parent_check requested. ++ * ++ * Tests do not apply to the root object. ++ */ ++ ++ if (parent_check && tags->obj_id > 1 && !obj->parent) ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Obj %d header mismatch parent_id %d obj->parent is NULL", ++ tags->obj_id, oh->parent_obj_id); ++ ++ if (parent_check && obj->parent && ++ oh->parent_obj_id != obj->parent->obj_id && ++ (oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED || ++ obj->parent->obj_id != YAFFS_OBJECTID_DELETED)) ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Obj %d header mismatch parent_id %d parent_obj_id %d", ++ tags->obj_id, oh->parent_obj_id, ++ obj->parent->obj_id); ++ ++ if (tags->obj_id > 1 && oh->name[0] == 0) /* Null name */ ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Obj %d header name is NULL", ++ obj->obj_id); ++ ++ if (tags->obj_id > 1 && ((u8) (oh->name[0])) == 0xff) /* Junk name */ ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Obj %d header name is 0xff", ++ obj->obj_id); ++} ++ ++void yaffs_verify_file(struct yaffs_obj *obj) ++{ ++ u32 x; ++ int required_depth; ++ int last_chunk; ++ u32 offset_in_chunk; ++ u32 the_chunk; ++ ++ int i; ++ struct yaffs_dev *dev; ++ struct yaffs_ext_tags tags; ++ struct yaffs_tnode *tn; ++ u32 obj_id; ++ ++ if (!obj) ++ return; ++ ++ if (yaffs_skip_verification(obj->my_dev)) ++ return; ++ ++ dev = obj->my_dev; ++ obj_id = obj->obj_id; ++ ++ ++ /* Check file size is consistent with tnode depth */ ++ yaffs_addr_to_chunk(dev, obj->variant.file_variant.file_size, ++ &last_chunk, &offset_in_chunk); ++ last_chunk++; ++ x = last_chunk >> YAFFS_TNODES_LEVEL0_BITS; ++ required_depth = 0; ++ while (x > 0) { ++ x >>= YAFFS_TNODES_INTERNAL_BITS; ++ required_depth++; ++ } ++ ++ /* Check that the chunks in the tnode tree are all correct. ++ * We do this by scanning through the tnode tree and ++ * checking the tags for every chunk match. ++ */ ++ ++ if (yaffs_skip_nand_verification(dev)) ++ return; ++ ++ for (i = 1; i <= last_chunk; i++) { ++ tn = yaffs_find_tnode_0(dev, &obj->variant.file_variant, i); ++ ++ if (!tn) ++ continue; ++ ++ the_chunk = yaffs_get_group_base(dev, tn, i); ++ if (the_chunk > 0) { ++ yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL, ++ &tags); ++ if (tags.obj_id != obj_id || tags.chunk_id != (u32)i) ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Object %d chunk_id %d NAND mismatch chunk %d tags (%d:%d)", ++ obj_id, i, the_chunk, ++ tags.obj_id, tags.chunk_id); ++ } ++ } ++} ++ ++void yaffs_verify_link(struct yaffs_obj *obj) ++{ ++ if (obj && yaffs_skip_verification(obj->my_dev)) ++ return; ++ ++ /* Verify sane equivalent object */ ++} ++ ++void yaffs_verify_symlink(struct yaffs_obj *obj) ++{ ++ if (obj && yaffs_skip_verification(obj->my_dev)) ++ return; ++ ++ /* Verify symlink string */ ++} ++ ++void yaffs_verify_special(struct yaffs_obj *obj) ++{ ++ if (obj && yaffs_skip_verification(obj->my_dev)) ++ return; ++} ++ ++void yaffs_verify_obj(struct yaffs_obj *obj) ++{ ++ struct yaffs_dev *dev; ++ u32 chunk_min; ++ u32 chunk_max; ++ u32 chunk_id_ok; ++ u32 chunk_in_range; ++ u32 chunk_wrongly_deleted; ++ u32 chunk_valid; ++ ++ if (!obj) ++ return; ++ ++ if (obj->being_created) ++ return; ++ ++ dev = obj->my_dev; ++ ++ if (yaffs_skip_verification(dev)) ++ return; ++ ++ /* Check sane object header chunk */ ++ ++ chunk_min = dev->internal_start_block * dev->param.chunks_per_block; ++ chunk_max = ++ (dev->internal_end_block + 1) * dev->param.chunks_per_block - 1; ++ ++ chunk_in_range = (((unsigned)(obj->hdr_chunk)) >= chunk_min && ++ ((unsigned)(obj->hdr_chunk)) <= chunk_max); ++ chunk_id_ok = chunk_in_range || (obj->hdr_chunk == 0); ++ chunk_valid = chunk_in_range && ++ yaffs_check_chunk_bit(dev, ++ obj->hdr_chunk / dev->param.chunks_per_block, ++ obj->hdr_chunk % dev->param.chunks_per_block); ++ chunk_wrongly_deleted = chunk_in_range && !chunk_valid; ++ ++ if (!obj->fake && (!chunk_id_ok || chunk_wrongly_deleted)) ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Obj %d has chunk_id %d %s %s", ++ obj->obj_id, obj->hdr_chunk, ++ chunk_id_ok ? "" : ",out of range", ++ chunk_wrongly_deleted ? ",marked as deleted" : ""); ++ ++ if (chunk_valid && !yaffs_skip_nand_verification(dev)) { ++ struct yaffs_ext_tags tags; ++ struct yaffs_obj_hdr *oh; ++ u8 *buffer = yaffs_get_temp_buffer(dev); ++ ++ oh = (struct yaffs_obj_hdr *)buffer; ++ ++ yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, buffer, &tags); ++ ++ yaffs_verify_oh(obj, oh, &tags, 1); ++ ++ yaffs_release_temp_buffer(dev, buffer); ++ } ++ ++ /* Verify it has a parent */ ++ if (obj && !obj->fake && (!obj->parent || obj->parent->my_dev != dev)) { ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Obj %d has parent pointer %p which does not look like an object", ++ obj->obj_id, obj->parent); ++ } ++ ++ /* Verify parent is a directory */ ++ if (obj->parent && ++ obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Obj %d's parent is not a directory (type %d)", ++ obj->obj_id, obj->parent->variant_type); ++ } ++ ++ switch (obj->variant_type) { ++ case YAFFS_OBJECT_TYPE_FILE: ++ yaffs_verify_file(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ yaffs_verify_symlink(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ yaffs_verify_dir(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ yaffs_verify_link(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_SPECIAL: ++ yaffs_verify_special(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_UNKNOWN: ++ default: ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Obj %d has illegaltype %d", ++ obj->obj_id, obj->variant_type); ++ break; ++ } ++} ++ ++void yaffs_verify_objects(struct yaffs_dev *dev) ++{ ++ struct yaffs_obj *obj; ++ int i; ++ struct list_head *lh; ++ ++ if (yaffs_skip_verification(dev)) ++ return; ++ ++ /* Iterate through the objects in each hash entry */ ++ ++ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) { ++ list_for_each(lh, &dev->obj_bucket[i].list) { ++ obj = list_entry(lh, struct yaffs_obj, hash_link); ++ yaffs_verify_obj(obj); ++ } ++ } ++} ++ ++void yaffs_verify_obj_in_dir(struct yaffs_obj *obj) ++{ ++ struct list_head *lh; ++ struct yaffs_obj *list_obj; ++ int count = 0; ++ ++ if (!obj) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, "No object to verify"); ++ BUG(); ++ return; ++ } ++ ++ if (yaffs_skip_verification(obj->my_dev)) ++ return; ++ ++ if (!obj->parent) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, "Object does not have parent"); ++ BUG(); ++ return; ++ } ++ ++ if (obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, "Parent is not directory"); ++ BUG(); ++ } ++ ++ /* Iterate through the objects in each hash entry */ ++ ++ list_for_each(lh, &obj->parent->variant.dir_variant.children) { ++ list_obj = list_entry(lh, struct yaffs_obj, siblings); ++ yaffs_verify_obj(list_obj); ++ if (obj == list_obj) ++ count++; ++ } ++ ++ if (count != 1) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "Object in directory %d times", ++ count); ++ BUG(); ++ } ++} ++ ++void yaffs_verify_dir(struct yaffs_obj *directory) ++{ ++ struct list_head *lh; ++ struct yaffs_obj *list_obj; ++ struct yaffs_dev *dev; ++ ++ if (!directory) { ++ BUG(); ++ return; ++ } ++ ++ dev = directory->my_dev; ++ ++ if (!dev) { ++ BUG(); ++ return; ++ } ++ ++ if (directory == dev->root_dir || ++ directory == dev->lost_n_found || ++ directory == dev->unlinked_dir || ++ directory == dev->del_dir) ++ return; ++ ++ if (yaffs_skip_full_verification(directory->my_dev)) ++ return; ++ ++ if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "Directory has wrong type: %d", ++ directory->variant_type); ++ BUG(); ++ } ++ ++ /* Iterate through the objects in each hash entry */ ++ ++ list_for_each(lh, &directory->variant.dir_variant.children) { ++ list_obj = list_entry(lh, struct yaffs_obj, siblings); ++ if (list_obj->parent != directory) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "Object in directory list has wrong parent %p", ++ list_obj->parent); ++ BUG(); ++ } ++ yaffs_verify_obj_in_dir(list_obj); ++ } ++} ++ ++static int yaffs_free_verification_failures; ++ ++void yaffs_verify_free_chunks(struct yaffs_dev *dev) ++{ ++ int counted; ++ int difference; ++ ++ if (yaffs_skip_verification(dev)) ++ return; ++ ++ counted = yaffs_count_free_chunks(dev); ++ ++ difference = dev->n_free_chunks - counted; ++ ++ if (difference) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "Freechunks verification failure %d %d %d", ++ dev->n_free_chunks, counted, difference); ++ yaffs_free_verification_failures++; ++ } ++} ++ ++int yaffs_verify_file_sane(struct yaffs_obj *in) ++{ ++ (void) in; ++ return YAFFS_OK; ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_verify.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_verify.h.patch new file mode 100644 index 00000000..5d48924d --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_verify.h.patch @@ -0,0 +1,46 @@ +diff -drupN a/fs/yaffs2/yaffs_verify.h b/fs/yaffs2/yaffs_verify.h +--- a/fs/yaffs2/yaffs_verify.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_verify.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,42 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_VERIFY_H__ ++#define __YAFFS_VERIFY_H__ ++ ++#include "yaffs_guts.h" ++ ++void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi, ++ int n); ++void yaffs_verify_collected_blk(struct yaffs_dev *dev, ++ struct yaffs_block_info *bi, int n); ++void yaffs_verify_blocks(struct yaffs_dev *dev); ++ ++void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh, ++ struct yaffs_ext_tags *tags, int parent_check); ++void yaffs_verify_file(struct yaffs_obj *obj); ++void yaffs_verify_link(struct yaffs_obj *obj); ++void yaffs_verify_symlink(struct yaffs_obj *obj); ++void yaffs_verify_special(struct yaffs_obj *obj); ++void yaffs_verify_obj(struct yaffs_obj *obj); ++void yaffs_verify_objects(struct yaffs_dev *dev); ++void yaffs_verify_obj_in_dir(struct yaffs_obj *obj); ++void yaffs_verify_dir(struct yaffs_obj *directory); ++void yaffs_verify_free_chunks(struct yaffs_dev *dev); ++ ++int yaffs_verify_file_sane(struct yaffs_obj *obj); ++ ++int yaffs_skip_verification(struct yaffs_dev *dev); ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_vfs.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_vfs.c.patch new file mode 100644 index 00000000..2bcc8c10 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_vfs.c.patch @@ -0,0 +1,3817 @@ +diff -drupN a/fs/yaffs2/yaffs_vfs.c b/fs/yaffs2/yaffs_vfs.c +--- a/fs/yaffs2/yaffs_vfs.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_vfs.c 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,3813 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * Acknowledgements: ++ * Luc van OostenRyck for numerous patches. ++ * Nick Bane for numerous patches. ++ * Nick Bane for 2.5/2.6 integration. ++ * Andras Toth for mknod rdev issue. ++ * Michael Fischer for finding the problem with inode inconsistency. ++ * Some code bodily lifted from JFFS ++ * ++ * 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 is the file system front-end to YAFFS that hooks it up to ++ * the VFS. ++ * ++ * Special notes: ++ * >> 2.4: sb->u.generic_sbp points to the struct yaffs_dev associated with ++ * this superblock ++ * >> 2.6: sb->s_fs_info points to the struct yaffs_dev associated with this ++ * superblock ++ * >> inode->u.generic_ip points to the associated struct yaffs_obj. ++ */ ++ ++/* ++ * There are two variants of the VFS glue code. This variant should compile ++ * for any version of Linux. ++ */ ++#include ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)) ++#include ++#endif ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)) ++#define YAFFS_COMPILE_BACKGROUND ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)) ++#define YAFFS_COMPILE_FREEZER ++#endif ++#endif ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)) ++#define YAFFS_COMPILE_EXPORTFS ++#endif ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35)) ++#define YAFFS_USE_SETATTR_COPY ++#define YAFFS_USE_TRUNCATE_SETSIZE ++#endif ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35)) ++#define YAFFS_HAS_EVICT_INODE ++#endif ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)) && \ ++ (LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0)) ++#define YAFFS_NEW_FOLLOW_LINK 1 ++#else ++#define YAFFS_NEW_FOLLOW_LINK 0 ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) ++#define YAFFS_HAS_WRITE_SUPER ++#endif ++ ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)) ++#include ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)) ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++ ++#if (YAFFS_NEW_FOLLOW_LINK == 1) ++#include ++#endif ++ ++#ifdef YAFFS_COMPILE_EXPORTFS ++#include ++#endif ++ ++#ifdef YAFFS_COMPILE_BACKGROUND ++#include ++#include ++#endif ++#ifdef YAFFS_COMPILE_FREEZER ++#include ++#endif ++ ++#include ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++ ++#include ++ ++#define UnlockPage(p) unlock_page(p) ++#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags) ++ ++/* FIXME: use sb->s_id instead ? */ ++#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf) ++ ++#else ++ ++#include ++#define BDEVNAME_SIZE 0 ++#define yaffs_devname(sb, buf) kdevname(sb->s_dev) ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)) ++/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */ ++#define __user ++#endif ++ ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)) ++#define YPROC_ROOT (&proc_root) ++#else ++#define YPROC_ROOT NULL ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)) ++#define Y_INIT_TIMER(a) init_timer(a) ++#elif LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) ++#define Y_INIT_TIMER(a) init_timer_on_stack(a) ++#else ++#define Y_INIT_TIMER(a,cb) timer_setup_on_stack(a,cb,0) ++#endif ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27)) ++#define YAFFS_USE_WRITE_BEGIN_END 1 ++#else ++#define YAFFS_USE_WRITE_BEGIN_END 0 ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) ++#define YAFFS_SUPER_HAS_DIRTY ++#endif ++ ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) ++#define set_nlink(inode, count) do { (inode)->i_nlink = (count); } while(0) ++#endif ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28)) ++static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size) ++{ ++ uint64_t result = partition_size; ++ do_div(result, block_size); ++ return (uint32_t) result; ++} ++#else ++#define YCALCBLOCKS(s, b) ((s)/(b)) ++#endif ++ ++#include ++#include ++ ++#include "yportenv.h" ++#include "yaffs_trace.h" ++#include "yaffs_guts.h" ++#include "yaffs_attribs.h" ++#include "yaffs_linux.h" ++#include "yaffs_mtdif.h" ++#include "yaffs_packedtags2.h" ++#include "yaffs_getblockinfo.h" ++ ++unsigned int yaffs_trace_mask = YAFFS_TRACE_BAD_BLOCKS | YAFFS_TRACE_ALWAYS; ++unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS; ++unsigned int yaffs_auto_checkpoint = 1; ++unsigned int yaffs_gc_control = 1; ++unsigned int yaffs_bg_enable = 1; ++unsigned int yaffs_auto_select = 1; ++/* Module Parameters */ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++module_param(yaffs_trace_mask, uint, 0644); ++module_param(yaffs_wr_attempts, uint, 0644); ++module_param(yaffs_auto_checkpoint, uint, 0644); ++module_param(yaffs_gc_control, uint, 0644); ++module_param(yaffs_bg_enable, uint, 0644); ++#else ++MODULE_PARM(yaffs_trace_mask, "i"); ++MODULE_PARM(yaffs_wr_attempts, "i"); ++MODULE_PARM(yaffs_auto_checkpoint, "i"); ++MODULE_PARM(yaffs_gc_control, "i"); ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)) ++/* use iget and read_inode */ ++#define Y_IGET(sb, inum) iget((sb), (inum)) ++ ++#else ++/* Call local equivalent */ ++#define YAFFS_USE_OWN_IGET ++#define Y_IGET(sb, inum) yaffs_iget((sb), (inum)) ++ ++#endif ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)) ++#define yaffs_inode_to_obj_lv(iptr) ((iptr)->i_private) ++#else ++#define yaffs_inode_to_obj_lv(iptr) ((iptr)->u.generic_ip) ++#endif ++ ++#define yaffs_inode_to_obj(iptr) \ ++ ((struct yaffs_obj *)(yaffs_inode_to_obj_lv(iptr))) ++#define yaffs_dentry_to_obj(dptr) yaffs_inode_to_obj((dptr)->d_inode) ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++#define yaffs_super_to_dev(sb) ((struct yaffs_dev *)sb->s_fs_info) ++#else ++#define yaffs_super_to_dev(sb) ((struct yaffs_dev *)sb->u.generic_sbp) ++#endif ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) ++#define Y_CLEAR_INODE(i) clear_inode(i) ++#else ++#define Y_CLEAR_INODE(i) end_writeback(i) ++#endif ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) ++#define YAFFS_USE_DIR_ITERATE ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)) ++#define YAFFS_USE_XATTR ++#endif ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,12,0)) ++#define YAFFS_NEW_PROCFS ++#include ++#endif ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)) ++#define YAFFS_NEW_GET_LINK 1 ++#define YAFFS_NEW_XATTR 1 ++#else ++#define YAFFS_NEW_GET_LINK 0 ++#define YAFFS_NEW_XATTR 0 ++#endif ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) ++#define PAGE_CACHE_SIZE PAGE_SIZE ++#define PAGE_CACHE_SHIFT PAGE_SHIFT ++#define Y_GET_DENTRY(f) ((f)->f_path.dentry) ++#else ++#define Y_GET_DENTRY(f) ((f)->f_dentry) ++#endif ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)) ++#define page_cache_release put_page ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,12,0)) ++#define update_dir_time(dir) do {\ ++ (dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \ ++ } while (0) ++#elif (LINUX_VERSION_CODE < KERNEL_VERSION(4,18,0)) ++#define update_dir_time(dir) do {\ ++ (dir)->i_ctime = (dir)->i_mtime = current_kernel_time(); \ ++ } while (0) ++#else ++#define update_dir_time(dir) do {\ ++ (dir)->i_ctime = (dir)->i_mtime = current_kernel_time64(); \ ++ } while (0) ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)) ++static inline int setattr_prepare(struct dentry *dentry, struct iattr *attr) ++{ ++ return inode_change_ok(dentry->d_inode, attr); ++} ++#endif ++ ++static void yaffs_fill_inode_from_obj(struct inode *inode, ++ struct yaffs_obj *obj); ++ ++ ++static void yaffs_gross_lock(struct yaffs_dev *dev) ++{ ++ yaffs_trace(YAFFS_TRACE_LOCK, "yaffs locking %p", current); ++ mutex_lock(&(yaffs_dev_to_lc(dev)->gross_lock)); ++ yaffs_trace(YAFFS_TRACE_LOCK, "yaffs locked %p", current); ++} ++ ++static void yaffs_gross_unlock(struct yaffs_dev *dev) ++{ ++ yaffs_trace(YAFFS_TRACE_LOCK, "yaffs unlocking %p", current); ++ mutex_unlock(&(yaffs_dev_to_lc(dev)->gross_lock)); ++} ++ ++ ++static int yaffs_readpage_nolock(struct file *f, struct page *pg) ++{ ++ /* Lifted from jffs2 */ ++ ++ struct yaffs_obj *obj; ++ unsigned char *pg_buf; ++ int ret; ++ loff_t pos = ((loff_t) pg->index) << PAGE_SHIFT; ++ struct yaffs_dev *dev; ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_readpage_nolock at %lld, size %08x", ++ (long long)pos, ++ (unsigned)PAGE_SIZE); ++ ++ obj = yaffs_dentry_to_obj(Y_GET_DENTRY(f)); ++ ++ dev = obj->my_dev; ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++ BUG_ON(!PageLocked(pg)); ++#else ++ if (!PageLocked(pg)) ++ PAGE_BUG(pg); ++#endif ++ ++ pg_buf = kmap(pg); ++ /* FIXME: Can kmap fail? */ ++ ++ yaffs_gross_lock(dev); ++ ++ ret = yaffs_file_rd(obj, pg_buf, pos, PAGE_CACHE_SIZE); ++ ++ yaffs_gross_unlock(dev); ++ ++ if (ret >= 0) ++ ret = 0; ++ ++ if (ret) { ++ ClearPageUptodate(pg); ++ SetPageError(pg); ++ } else { ++ SetPageUptodate(pg); ++ ClearPageError(pg); ++ } ++ ++ flush_dcache_page(pg); ++ kunmap(pg); ++ ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage_nolock done"); ++ return ret; ++} ++ ++static int yaffs_readpage_unlock(struct file *f, struct page *pg) ++{ ++ int ret = yaffs_readpage_nolock(f, pg); ++ UnlockPage(pg); ++ return ret; ++} ++ ++static int yaffs_readpage(struct file *f, struct page *pg) ++{ ++ int ret; ++ ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage"); ++ ret = yaffs_readpage_unlock(f, pg); ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage done"); ++ return ret; ++} ++ ++ ++static void yaffs_set_super_dirty_val(struct yaffs_dev *dev, int val) ++{ ++ struct yaffs_linux_context *lc = yaffs_dev_to_lc(dev); ++ ++ if (lc) ++ lc->dirty = val; ++ ++# ifdef YAFFS_SUPER_HAS_DIRTY ++ { ++ struct super_block *sb = lc->super; ++ ++ if (sb) ++ sb->s_dirt = val; ++ } ++#endif ++ ++} ++ ++static void yaffs_set_super_dirty(struct yaffs_dev *dev) ++{ ++ yaffs_set_super_dirty_val(dev, 1); ++} ++ ++static void yaffs_clear_super_dirty(struct yaffs_dev *dev) ++{ ++ yaffs_set_super_dirty_val(dev, 0); ++} ++ ++static int yaffs_check_super_dirty(struct yaffs_dev *dev) ++{ ++ struct yaffs_linux_context *lc = yaffs_dev_to_lc(dev); ++ ++ if (lc && lc->dirty) ++ return 1; ++ ++# ifdef YAFFS_SUPER_HAS_DIRTY ++ { ++ struct super_block *sb = lc->super; ++ ++ if (sb && sb->s_dirt) ++ return 1; ++ } ++#endif ++ return 0; ++ ++} ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++static int yaffs_writepage(struct page *page, struct writeback_control *wbc) ++#else ++static int yaffs_writepage(struct page *page) ++#endif ++{ ++ struct yaffs_dev *dev; ++ struct address_space *mapping = page->mapping; ++ struct inode *inode; ++ unsigned long end_index; ++ char *buffer; ++ struct yaffs_obj *obj; ++ int n_written = 0; ++ unsigned n_bytes; ++ loff_t i_size; ++ ++ if (!mapping) ++ BUG(); ++ inode = mapping->host; ++ if (!inode) ++ BUG(); ++ i_size = i_size_read(inode); ++ ++ end_index = i_size >> PAGE_CACHE_SHIFT; ++ ++ if (page->index < end_index) ++ n_bytes = PAGE_CACHE_SIZE; ++ else { ++ n_bytes = i_size & (PAGE_CACHE_SIZE - 1); ++ ++ if (page->index > end_index || !n_bytes) { ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_writepage at %lld, inode size = %lld!!", ++ ((loff_t)page->index) << PAGE_CACHE_SHIFT, ++ inode->i_size); ++ yaffs_trace(YAFFS_TRACE_OS, ++ " -> don't care!!"); ++ ++ zero_user_segment(page, 0, PAGE_CACHE_SIZE); ++ set_page_writeback(page); ++ unlock_page(page); ++ end_page_writeback(page); ++ return 0; ++ } ++ } ++ ++ if (n_bytes != PAGE_CACHE_SIZE) ++ zero_user_segment(page, n_bytes, PAGE_CACHE_SIZE); ++ ++ get_page(page); ++ ++ buffer = kmap(page); ++ ++ obj = yaffs_inode_to_obj(inode); ++ dev = obj->my_dev; ++ yaffs_gross_lock(dev); ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_writepage at %lld, size %08x", ++ ((loff_t)page->index) << PAGE_CACHE_SHIFT, n_bytes); ++ yaffs_trace(YAFFS_TRACE_OS, ++ "writepag0: obj = %lld, ino = %lld", ++ obj->variant.file_variant.file_size, inode->i_size); ++ ++ n_written = yaffs_wr_file(obj, buffer, ++ ((loff_t)page->index) << PAGE_CACHE_SHIFT, n_bytes, 0); ++ ++ yaffs_set_super_dirty(dev); ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "writepag1: obj = %lld, ino = %lld", ++ obj->variant.file_variant.file_size, inode->i_size); ++ ++ yaffs_gross_unlock(dev); ++ ++ kunmap(page); ++ set_page_writeback(page); ++ unlock_page(page); ++ end_page_writeback(page); ++ put_page(page); ++ ++ return (n_written == n_bytes) ? 0 : -ENOSPC; ++} ++ ++/* Space holding and freeing is done to ensure we have space available for write_begin/end */ ++/* For now we just assume few parallel writes and check against a small number. */ ++/* Todo: need to do this with a counter to handle parallel reads better */ ++ ++static ssize_t yaffs_hold_space(struct file *f) ++{ ++ struct yaffs_obj *obj; ++ struct yaffs_dev *dev; ++ ++ int n_free_chunks; ++ ++ obj = yaffs_dentry_to_obj(Y_GET_DENTRY(f)); ++ ++ dev = obj->my_dev; ++ ++ yaffs_gross_lock(dev); ++ ++ n_free_chunks = yaffs_get_n_free_chunks(dev); ++ ++ yaffs_gross_unlock(dev); ++ ++ return (n_free_chunks > 20) ? 1 : 0; ++} ++ ++static void yaffs_release_space(struct file *f) ++{ ++ struct yaffs_obj *obj; ++ struct yaffs_dev *dev; ++ ++ obj = yaffs_dentry_to_obj(Y_GET_DENTRY(f)); ++ ++ dev = obj->my_dev; ++ ++ yaffs_gross_lock(dev); ++ ++ yaffs_gross_unlock(dev); ++} ++ ++#if (YAFFS_USE_WRITE_BEGIN_END > 0) ++static int yaffs_write_begin(struct file *filp, struct address_space *mapping, ++ loff_t pos, unsigned len, unsigned flags, ++ struct page **pagep, void **fsdata) ++{ ++ struct page *pg = NULL; ++ pgoff_t index = pos >> PAGE_CACHE_SHIFT; ++ ++ int ret = 0; ++ int space_held = 0; ++ ++ /* Get a page */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28) ++ pg = grab_cache_page_write_begin(mapping, index, flags); ++#else ++ pg = __grab_cache_page(mapping, index); ++#endif ++ ++ *pagep = pg; ++ if (!pg) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ yaffs_trace(YAFFS_TRACE_OS, ++ "start yaffs_write_begin index %d(%x) uptodate %d", ++ (int)index, (int)index, Page_Uptodate(pg) ? 1 : 0); ++ ++ /* Get fs space */ ++ space_held = yaffs_hold_space(filp); ++ ++ if (!space_held) { ++ ret = -ENOSPC; ++ goto out; ++ } ++ ++ /* Update page if required */ ++ ++ if (!Page_Uptodate(pg)) ++ ret = yaffs_readpage_nolock(filp, pg); ++ ++ if (ret) ++ goto out; ++ ++ /* Happy path return */ ++ yaffs_trace(YAFFS_TRACE_OS, "end yaffs_write_begin - ok"); ++ ++ return 0; ++ ++out: ++ yaffs_trace(YAFFS_TRACE_OS, ++ "end yaffs_write_begin fail returning %d", ret); ++ if (space_held) ++ yaffs_release_space(filp); ++ if (pg) { ++ unlock_page(pg); ++ page_cache_release(pg); ++ } ++ return ret; ++} ++ ++#else ++ ++static int yaffs_prepare_write(struct file *f, struct page *pg, ++ unsigned offset, unsigned to) ++{ ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_prepair_write"); ++ ++ if (!Page_Uptodate(pg)) ++ return yaffs_readpage_nolock(f, pg); ++ return 0; ++} ++#endif ++ ++ ++static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n, ++ loff_t * pos) ++{ ++ struct yaffs_obj *obj; ++ int n_written; ++ loff_t ipos; ++ struct inode *inode; ++ struct yaffs_dev *dev; ++ ++ obj = yaffs_dentry_to_obj(Y_GET_DENTRY(f)); ++ ++ if (!obj) { ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_file_write: hey obj is null!"); ++ return -EINVAL; ++ } ++ ++ dev = obj->my_dev; ++ ++ yaffs_gross_lock(dev); ++ ++ inode = Y_GET_DENTRY(f)->d_inode; ++ ++ if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND) ++ ipos = inode->i_size; ++ else ++ ipos = *pos; ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_file_write about to write writing %u(%x) bytes to object %d at %lld", ++ (unsigned)n, (unsigned)n, obj->obj_id, ipos); ++ ++ n_written = yaffs_wr_file(obj, buf, ipos, n, 0); ++ ++ yaffs_set_super_dirty(dev); ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_file_write: %d(%x) bytes written", ++ (unsigned)n, (unsigned)n); ++ ++ if (n_written > 0) { ++ ipos += n_written; ++ *pos = ipos; ++ if (ipos > inode->i_size) { ++ inode->i_size = ipos; ++ inode->i_blocks = (ipos + 511) >> 9; ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_file_write size updated to %lld bytes, %d blocks", ++ ipos, (int)(inode->i_blocks)); ++ } ++ ++ } ++ yaffs_gross_unlock(dev); ++ return (n_written == 0) && (n > 0) ? -ENOSPC : n_written; ++} ++ ++ ++#if (YAFFS_USE_WRITE_BEGIN_END > 0) ++static int yaffs_write_end(struct file *filp, struct address_space *mapping, ++ loff_t pos, unsigned len, unsigned copied, ++ struct page *pg, void *fsdadata) ++{ ++ int ret = 0; ++ void *addr, *kva; ++ uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1); ++ ++ kva = kmap(pg); ++ addr = kva + offset_into_page; ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_write_end addr %p pos %lld n_bytes %d", ++ addr, pos, copied); ++ ++ ret = yaffs_file_write(filp, addr, copied, &pos); ++ ++ if (ret != copied) { ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_write_end not same size ret %d copied %d", ++ ret, copied); ++ SetPageError(pg); ++ } ++ ++ kunmap(pg); ++ ++ yaffs_release_space(filp); ++ unlock_page(pg); ++ page_cache_release(pg); ++ return ret; ++} ++#else ++ ++static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset, ++ unsigned to) ++{ ++ void *addr, *kva; ++ ++ loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset; ++ int n_bytes = to - offset; ++ int n_written; ++ ++ kva = kmap(pg); ++ addr = kva + offset; ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_commit_write addr %p pos %lld n_bytes %d", ++ addr, pos, n_bytes); ++ ++ n_written = yaffs_file_write(f, addr, n_bytes, &pos); ++ ++ if (n_written != n_bytes) { ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_commit_write not same size n_written %d n_bytes %d", ++ n_written, n_bytes); ++ SetPageError(pg); ++ } ++ kunmap(pg); ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_commit_write returning %d", ++ n_written == n_bytes ? 0 : n_written); ++ ++ return n_written == n_bytes ? 0 : n_written; ++} ++#endif ++ ++static struct address_space_operations yaffs_file_address_operations = { ++ .readpage = yaffs_readpage, ++ .writepage = yaffs_writepage, ++#if (YAFFS_USE_WRITE_BEGIN_END > 0) ++ .write_begin = yaffs_write_begin, ++ .write_end = yaffs_write_end, ++#else ++ .prepare_write = yaffs_prepare_write, ++ .commit_write = yaffs_commit_write, ++#endif ++}; ++ ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++static int yaffs_file_flush(struct file *file, fl_owner_t id) ++#else ++static int yaffs_file_flush(struct file *file) ++#endif ++{ ++ struct yaffs_obj *obj = yaffs_dentry_to_obj(Y_GET_DENTRY(file)); ++ ++ struct yaffs_dev *dev = obj->my_dev; ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_file_flush object %d (%s)", ++ obj->obj_id, ++ obj->dirty ? "dirty" : "clean"); ++ ++ yaffs_gross_lock(dev); ++ ++ yaffs_flush_file(obj, 1, 0, 0); ++ ++ yaffs_gross_unlock(dev); ++ ++ return 0; ++} ++ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) ++static int yaffs_sync_object(struct file *file, loff_t start, loff_t end, int datasync) ++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34)) ++static int yaffs_sync_object(struct file *file, int datasync) ++#else ++static int yaffs_sync_object(struct file *file, struct dentry *dentry, ++ int datasync) ++#endif ++{ ++ struct yaffs_obj *obj; ++ struct yaffs_dev *dev; ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34)) ++ struct dentry *dentry = file->f_path.dentry; ++#endif ++ ++ obj = yaffs_dentry_to_obj(dentry); ++ ++ dev = obj->my_dev; ++ ++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC, ++ "yaffs_sync_object"); ++ yaffs_gross_lock(dev); ++ yaffs_flush_file(obj, 1, datasync, 0); ++ yaffs_gross_unlock(dev); ++ return 0; ++} ++ ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)) ++static const struct file_operations yaffs_file_operations = { ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0) ++ .read = new_sync_read, ++ .write = new_sync_write, ++#endif ++ .read_iter = generic_file_read_iter, ++ .write_iter = generic_file_write_iter, ++#else ++ .read = do_sync_read, ++ .write = do_sync_write, ++ .aio_read = generic_file_aio_read, ++ .aio_write = generic_file_aio_write, ++#endif ++ .mmap = generic_file_mmap, ++ .flush = yaffs_file_flush, ++ .fsync = yaffs_sync_object, ++ .splice_read = generic_file_splice_read, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) ++ .splice_write = iter_file_splice_write, ++#else ++ .splice_write = generic_file_splice_write, ++#endif ++ .llseek = generic_file_llseek, ++}; ++ ++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)) ++ ++static const struct file_operations yaffs_file_operations = { ++ .read = do_sync_read, ++ .write = do_sync_write, ++ .aio_read = generic_file_aio_read, ++ .aio_write = generic_file_aio_write, ++ .mmap = generic_file_mmap, ++ .flush = yaffs_file_flush, ++ .fsync = yaffs_sync_object, ++ .sendfile = generic_file_sendfile, ++}; ++ ++#else ++ ++static const struct file_operations yaffs_file_operations = { ++ .read = generic_file_read, ++ .write = generic_file_write, ++ .mmap = generic_file_mmap, ++ .flush = yaffs_file_flush, ++ .fsync = yaffs_sync_object, ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++ .sendfile = generic_file_sendfile, ++#endif ++}; ++#endif ++ ++ ++ ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)) ++static void zero_user_segment(struct page *page, unsigned start, unsigned end) ++{ ++ void *kaddr = kmap_atomic(page, KM_USER0); ++ memset(kaddr + start, 0, end - start); ++ kunmap_atomic(kaddr, KM_USER0); ++ flush_dcache_page(page); ++} ++#endif ++ ++ ++static int yaffs_vfs_setsize(struct inode *inode, loff_t newsize) ++{ ++#ifdef YAFFS_USE_TRUNCATE_SETSIZE ++ truncate_setsize(inode, newsize); ++ return 0; ++#else ++ truncate_inode_pages(&inode->i_data, newsize); ++ return 0; ++#endif ++ ++} ++ ++ ++static int yaffs_vfs_setattr(struct inode *inode, struct iattr *attr) ++{ ++#ifdef YAFFS_USE_SETATTR_COPY ++ setattr_copy(inode, attr); ++ return 0; ++#else ++ return inode_setattr(inode, attr); ++#endif ++ ++} ++ ++static int yaffs_setattr(struct dentry *dentry, struct iattr *attr) ++{ ++ struct inode *inode = dentry->d_inode; ++ int error = 0; ++ struct yaffs_dev *dev; ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_setattr of object %d", ++ yaffs_inode_to_obj(inode)->obj_id); ++#if 0 ++ /* Fail if a requested resize >= 2GB */ ++ if (attr->ia_valid & ATTR_SIZE && (attr->ia_size >> 31)) ++ error = -EINVAL; ++#endif ++ ++ if (error == 0) ++ error = setattr_prepare(dentry, attr); ++ if (error == 0) { ++ int result; ++ if (!error) { ++ error = yaffs_vfs_setattr(inode, attr); ++ yaffs_trace(YAFFS_TRACE_OS, "inode_setattr called"); ++ if (attr->ia_valid & ATTR_SIZE) { ++ yaffs_vfs_setsize(inode, attr->ia_size); ++ inode->i_blocks = (inode->i_size + 511) >> 9; ++ } ++ } ++ dev = yaffs_inode_to_obj(inode)->my_dev; ++ if (attr->ia_valid & ATTR_SIZE) { ++ yaffs_trace(YAFFS_TRACE_OS, ++ "resize to %d(%x)", ++ (int)(attr->ia_size), ++ (int)(attr->ia_size)); ++ } ++ yaffs_gross_lock(dev); ++ result = yaffs_set_attribs(yaffs_inode_to_obj(inode), attr); ++ if (result == YAFFS_OK) { ++ error = 0; ++ } else { ++ error = -EPERM; ++ } ++ yaffs_gross_unlock(dev); ++ ++ } ++ ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_setattr done returning %d", error); ++ ++ return error; ++} ++ ++#ifdef YAFFS_USE_XATTR ++#if (YAFFS_NEW_XATTR > 0) ++static int yaffs_setxattr(struct dentry *dentry, struct inode *inode, ++ const char *name, const void *value, size_t size, int flags) ++{ ++#else ++static int yaffs_setxattr(struct dentry *dentry, const char *name, ++ const void *value, size_t size, int flags) ++{ ++ struct inode *inode = dentry->d_inode; ++#endif ++ int error = 0; ++ struct yaffs_dev *dev; ++ struct yaffs_obj *obj = yaffs_inode_to_obj(inode); ++ ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_setxattr of object %d", obj->obj_id); ++ ++ if (error == 0) { ++ int result = YAFFS_FAIL; ++ dev = obj->my_dev; ++ yaffs_gross_lock(dev); ++ result = yaffs_set_xattrib(obj, name, value, size, flags); ++ if (result == YAFFS_OK) ++ error = 0; ++ else if (result < 0) ++ error = result; ++ yaffs_gross_unlock(dev); ++ ++ } ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_setxattr done returning %d", error); ++ ++ return error; ++} ++ ++#if (YAFFS_NEW_XATTR > 0) ++static ssize_t yaffs_getxattr(struct dentry * dentry, struct inode *inode, ++ const char *name, void *buff, size_t size) ++{ ++#else ++static ssize_t yaffs_getxattr(struct dentry * dentry, const char *name, ++ void *buff, size_t size) ++{ ++ struct inode *inode = dentry->d_inode; ++#endif ++ int error = 0; ++ struct yaffs_dev *dev; ++ struct yaffs_obj *obj = yaffs_inode_to_obj(inode); ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_getxattr \"%s\" from object %d", ++ name, obj->obj_id); ++ ++ if (error == 0) { ++ dev = obj->my_dev; ++ yaffs_gross_lock(dev); ++ error = yaffs_get_xattrib(obj, name, buff, size); ++ yaffs_gross_unlock(dev); ++ ++ } ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_getxattr done returning %d", error); ++ ++ return error; ++} ++ ++static int yaffs_removexattr(struct dentry *dentry, const char *name) ++{ ++ struct inode *inode = dentry->d_inode; ++ int error = 0; ++ struct yaffs_dev *dev; ++ struct yaffs_obj *obj = yaffs_inode_to_obj(inode); ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_removexattr of object %d", obj->obj_id); ++ ++ if (error == 0) { ++ int result; ++ dev = obj->my_dev; ++ yaffs_gross_lock(dev); ++ result = yaffs_remove_xattrib(obj, name); ++ if (result == YAFFS_OK) ++ error = 0; ++ else if (result < 0) ++ error = result; ++ yaffs_gross_unlock(dev); ++ ++ } ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_removexattr done returning %d", error); ++ ++ return error; ++} ++#endif ++ ++static ssize_t yaffs_listxattr(struct dentry * dentry, char *buff, size_t size) ++{ ++ struct inode *inode = dentry->d_inode; ++ int error = 0; ++ struct yaffs_dev *dev; ++ struct yaffs_obj *obj = yaffs_inode_to_obj(inode); ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_listxattr of object %d", obj->obj_id); ++ ++ if (error == 0) { ++ dev = obj->my_dev; ++ yaffs_gross_lock(dev); ++ error = yaffs_list_xattrib(obj, buff, size); ++ yaffs_gross_unlock(dev); ++ ++ } ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_listxattr done returning %d", error); ++ ++ return error; ++} ++ ++ ++static const struct inode_operations yaffs_file_inode_operations = { ++ .setattr = yaffs_setattr, ++#ifdef YAFFS_USE_XATTR ++ .setxattr = yaffs_setxattr, ++ .getxattr = yaffs_getxattr, ++ .removexattr = yaffs_removexattr, ++#endif ++ .listxattr = yaffs_listxattr, ++}; ++ ++ ++static int yaffs_readlink(struct dentry *dentry, char __user * buffer, ++ int buflen) ++{ ++ unsigned char *alias; ++ int ret; ++ ++ struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev; ++ ++ yaffs_gross_lock(dev); ++ ++ alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry)); ++ ++ yaffs_gross_unlock(dev); ++ ++ if (!alias) ++ return -ENOMEM; ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0) ++ ret = vfs_readlink(dentry, buffer, buflen, alias); ++#else ++ ret = readlink_copy(buffer, buflen, alias); ++#endif ++ kfree(alias); ++ return ret; ++} ++ ++#if (YAFFS_NEW_GET_LINK == 0) ++#if (YAFFS_NEW_FOLLOW_LINK == 1) ++static void *yaffs_follow_link(struct dentry *dentry, void **data) ++{ ++ void *ret; ++#else ++static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd) ++{ ++ int ret ++#endif ++ unsigned char *alias; ++ int ret_int = 0; ++ struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev; ++ ++ yaffs_gross_lock(dev); ++ ++ alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry)); ++ yaffs_gross_unlock(dev); ++ ++ if (!alias) { ++ ret_int = -ENOMEM; ++ goto out; ++ } ++#if (YAFFS_NEW_FOLLOW_LINK == 1) ++ *data = alias; ++ ret = alias; ++out: ++ if (ret_int) ++ ret = ERR_PTR(ret_int); ++ return ret; ++#else ++ ret = vfs_follow_link(nd, alias); ++ kfree(alias); ++out: ++ if (ret_int) ++ ret = ret_int; ++ return ret; ++#endif ++} ++#else ++static const char *yaffs_get_link(struct dentry *dentry, struct inode *inode, struct delayed_call *done) ++{ ++ unsigned char *alias; ++ struct yaffs_dev *dev; ++ ++ if (!dentry) ++ return ERR_PTR(-ECHILD); ++ ++ dev = yaffs_dentry_to_obj(dentry)->my_dev; ++ ++ yaffs_gross_lock(dev); ++ ++ alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry)); ++ yaffs_gross_unlock(dev); ++ ++ if (!alias) ++ return ERR_PTR(-ENOMEM); ++ set_delayed_call(done, kfree_link, alias); ++ return alias; ++} ++#endif ++ ++#ifdef YAFFS_HAS_PUT_INODE ++ ++/* For now put inode is just for debugging ++ * Put inode is called when the inode **structure** is put. ++ */ ++static void yaffs_put_inode(struct inode *inode) ++{ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_put_inode: ino %d, count %d"), ++ (int)inode->i_ino, atomic_read(&inode->i_count); ++ ++} ++#endif ++ ++#if (YAFFS_NEW_FOLLOW_LINK == 1) ++void yaffs_put_link(struct dentry *dentry, void *alias) ++{ ++ kfree(alias); ++} ++#endif ++ ++static const struct inode_operations yaffs_symlink_inode_operations = { ++ .readlink = yaffs_readlink, ++#if (YAFFS_NEW_GET_LINK == 1) ++ .get_link = yaffs_get_link, ++#else ++ .follow_link = yaffs_follow_link, ++#endif ++#if (YAFFS_NEW_FOLLOW_LINK == 1) ++ .put_link = yaffs_put_link, ++#endif ++ .setattr = yaffs_setattr, ++#ifdef YAFFS_USE_XATTR ++ .setxattr = yaffs_setxattr, ++ .getxattr = yaffs_getxattr, ++ .removexattr = yaffs_removexattr, ++#endif ++ .listxattr = yaffs_listxattr, ++}; ++ ++#ifdef YAFFS_USE_OWN_IGET ++ ++static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino) ++{ ++ struct inode *inode; ++ struct yaffs_obj *obj; ++ struct yaffs_dev *dev = yaffs_super_to_dev(sb); ++ ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_iget for %lu", ino); ++ ++ inode = iget_locked(sb, ino); ++ if (!inode) ++ return ERR_PTR(-ENOMEM); ++ if (!(inode->i_state & I_NEW)) ++ return inode; ++ ++ /* NB This is called as a side effect of other functions, but ++ * we had to release the lock to prevent deadlocks, so ++ * need to lock again. ++ */ ++ ++ yaffs_gross_lock(dev); ++ ++ obj = yaffs_find_by_number(dev, inode->i_ino); ++ ++ yaffs_fill_inode_from_obj(inode, obj); ++ ++ yaffs_gross_unlock(dev); ++ ++ unlock_new_inode(inode); ++ return inode; ++} ++ ++#else ++ ++static void yaffs_read_inode(struct inode *inode) ++{ ++ /* NB This is called as a side effect of other functions, but ++ * we had to release the lock to prevent deadlocks, so ++ * need to lock again. ++ */ ++ ++ struct yaffs_obj *obj; ++ struct yaffs_dev *dev = yaffs_super_to_dev(inode->i_sb); ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_read_inode for %d", (int)inode->i_ino); ++ ++ if (current != yaffs_dev_to_lc(dev)->readdir_process) ++ yaffs_gross_lock(dev); ++ ++ obj = yaffs_find_by_number(dev, inode->i_ino); ++ ++ yaffs_fill_inode_from_obj(inode, obj); ++ ++ if (current != yaffs_dev_to_lc(dev)->readdir_process) ++ yaffs_gross_unlock(dev); ++} ++ ++#endif ++ ++ ++ ++struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev, ++ struct yaffs_obj *obj) ++{ ++ struct inode *inode; ++ ++ if (!sb) { ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_get_inode for NULL super_block!!"); ++ return NULL; ++ ++ } ++ ++ if (!obj) { ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_get_inode for NULL object!!"); ++ return NULL; ++ ++ } ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_get_inode for object %d", obj->obj_id); ++ ++ inode = Y_IGET(sb, obj->obj_id); ++ if (IS_ERR(inode)) ++ return NULL; ++ ++ /* NB Side effect: iget calls back to yaffs_read_inode(). */ ++ /* iget also increments the inode's i_count */ ++ /* NB You can't be holding gross_lock or deadlock will happen! */ ++ ++ return inode; ++} ++ ++ ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) ++#define YCRED(x) x ++#else ++#define YCRED(x) (x->cred) ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0) ++#define YPROC_uid(p) (YCRED(p)->fsuid) ++#define YPROC_gid(p) (YCRED(p)->fsgid) ++#define EXTRACT_gid(x) x ++#define EXTRACT_uid(x) x ++#define MAKE_gid(x) x ++#define MAKE_uid(x) x ++#else ++#define YPROC_uid(p) from_kuid(&init_user_ns, YCRED(p)->fsuid) ++#define YPROC_gid(p) from_kgid(&init_user_ns, YCRED(p)->fsgid) ++#define EXTRACT_gid(x) from_kgid(&init_user_ns, x) ++#define EXTRACT_uid(x) from_kuid(&init_user_ns, x) ++#define MAKE_gid(x) make_kgid(&init_user_ns, x) ++#define MAKE_uid(x) make_kuid(&init_user_ns, x) ++#endif ++ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) ++static int yaffs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, ++ dev_t rdev) ++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, ++ dev_t rdev) ++#else ++static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, ++ int rdev) ++#endif ++{ ++ struct inode *inode; ++ ++ struct yaffs_obj *obj = NULL; ++ struct yaffs_dev *dev; ++ ++ struct yaffs_obj *parent = yaffs_inode_to_obj(dir); ++ ++ int error = -ENOSPC; ++ uid_t uid = YPROC_uid(current); ++ gid_t gid = ++ (dir->i_mode & S_ISGID) ? EXTRACT_gid(dir->i_gid) : YPROC_gid(current); ++ ++ if ((dir->i_mode & S_ISGID) && S_ISDIR(mode)) ++ mode |= S_ISGID; ++ ++ if (parent) { ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_mknod: parent object %d type %d", ++ parent->obj_id, parent->variant_type); ++ } else { ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_mknod: could not get parent object"); ++ return -EPERM; ++ } ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_mknod: making oject for %s, mode %x dev %x", ++ dentry->d_name.name, mode, rdev); ++ ++ dev = parent->my_dev; ++ ++ yaffs_gross_lock(dev); ++ ++ switch (mode & S_IFMT) { ++ default: ++ /* Special (socket, fifo, device...) */ ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making special"); ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++ obj = ++ yaffs_create_special(parent, dentry->d_name.name, mode, uid, ++ gid, old_encode_dev(rdev)); ++#else ++ obj = ++ yaffs_create_special(parent, dentry->d_name.name, mode, uid, ++ gid, rdev); ++#endif ++ break; ++ case S_IFREG: /* file */ ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making file"); ++ obj = yaffs_create_file(parent, dentry->d_name.name, mode, uid, ++ gid); ++ break; ++ case S_IFDIR: /* directory */ ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making directory"); ++ obj = yaffs_create_dir(parent, dentry->d_name.name, mode, ++ uid, gid); ++ break; ++ case S_IFLNK: /* symlink */ ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making symlink"); ++ obj = NULL; /* Do we ever get here? */ ++ break; ++ } ++ ++ /* Can not call yaffs_get_inode() with gross lock held */ ++ yaffs_gross_unlock(dev); ++ ++ if (obj) { ++ inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj); ++ d_instantiate(dentry, inode); ++ update_dir_time(dir); ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_mknod created object %d count = %d", ++ obj->obj_id, atomic_read(&inode->i_count)); ++ error = 0; ++ yaffs_fill_inode_from_obj(dir, parent); ++ } else { ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod failed making object"); ++ error = -ENOMEM; ++ } ++ ++ return error; ++} ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) ++static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) ++#else ++static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode) ++#endif ++{ ++ int ret_val; ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mkdir"); ++ ret_val = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0); ++ return ret_val; ++} ++ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) ++static int yaffs_create(struct inode *dir, struct dentry *dentry, umode_t mode, ++ bool dummy) ++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) ++static int yaffs_create(struct inode *dir, struct dentry *dentry, umode_t mode, ++ struct nameidata *n) ++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode, ++ struct nameidata *n) ++#else ++static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode) ++#endif ++{ ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_create"); ++ return yaffs_mknod(dir, dentry, mode | S_IFREG, 0); ++} ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) ++static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry, ++ unsigned int dummy) ++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry, ++ struct nameidata *n) ++#else ++static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry) ++#endif ++{ ++ struct yaffs_obj *obj; ++ struct inode *inode = NULL; /* NCB 2.5/2.6 needs NULL here */ ++ ++ struct yaffs_dev *dev = yaffs_inode_to_obj(dir)->my_dev; ++ ++ if (current != yaffs_dev_to_lc(dev)->readdir_process) ++ yaffs_gross_lock(dev); ++ ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_lookup for %d:%s", ++ yaffs_inode_to_obj(dir)->obj_id, dentry->d_name.name); ++ ++ obj = yaffs_find_by_name(yaffs_inode_to_obj(dir), dentry->d_name.name); ++ ++ obj = yaffs_get_equivalent_obj(obj); /* in case it was a hardlink */ ++ ++ /* Can't hold gross lock when calling yaffs_get_inode() */ ++ if (current != yaffs_dev_to_lc(dev)->readdir_process) ++ yaffs_gross_unlock(dev); ++ ++ if (obj) { ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_lookup found %d", obj->obj_id); ++ ++ inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj); ++ } else { ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_lookup not found"); ++ ++ } ++ ++/* added NCB for 2.5/6 compatability - forces add even if inode is ++ * NULL which creates dentry hash */ ++ d_add(dentry, inode); ++ ++ return NULL; ++} ++ ++/* ++ * Create a link... ++ */ ++static int yaffs_link(struct dentry *old_dentry, struct inode *dir, ++ struct dentry *dentry) ++{ ++ struct inode *inode = old_dentry->d_inode; ++ struct yaffs_obj *obj = NULL; ++ struct yaffs_obj *link = NULL; ++ struct yaffs_dev *dev; ++ ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_link"); ++ ++ obj = yaffs_inode_to_obj(inode); ++ dev = obj->my_dev; ++ ++ yaffs_gross_lock(dev); ++ ++ if (!S_ISDIR(inode->i_mode)) /* Don't link directories */ ++ link = ++ yaffs_link_obj(yaffs_inode_to_obj(dir), dentry->d_name.name, ++ obj); ++ ++ if (link) { ++ set_nlink(old_dentry->d_inode, yaffs_get_obj_link_count(obj)); ++ d_instantiate(dentry, old_dentry->d_inode); ++ atomic_inc(&old_dentry->d_inode->i_count); ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_link link count %d i_count %d", ++ old_dentry->d_inode->i_nlink, ++ atomic_read(&old_dentry->d_inode->i_count)); ++ } ++ ++ yaffs_gross_unlock(dev); ++ ++ if (link) { ++ update_dir_time(dir); ++ return 0; ++ } ++ ++ return -EPERM; ++} ++ ++static int yaffs_symlink(struct inode *dir, struct dentry *dentry, ++ const char *symname) ++{ ++ struct yaffs_obj *obj; ++ struct yaffs_dev *dev; ++ uid_t uid = YPROC_uid(current); ++ gid_t gid = ++ (dir->i_mode & S_ISGID) ? EXTRACT_gid(dir->i_gid) : YPROC_gid(current); ++ ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_symlink"); ++ ++ if (strnlen(dentry->d_name.name, YAFFS_MAX_NAME_LENGTH + 1) > ++ YAFFS_MAX_NAME_LENGTH) ++ return -ENAMETOOLONG; ++ ++ if (strnlen(symname, YAFFS_MAX_ALIAS_LENGTH + 1) > ++ YAFFS_MAX_ALIAS_LENGTH) ++ return -ENAMETOOLONG; ++ ++ dev = yaffs_inode_to_obj(dir)->my_dev; ++ yaffs_gross_lock(dev); ++ obj = yaffs_create_symlink(yaffs_inode_to_obj(dir), dentry->d_name.name, ++ S_IFLNK | S_IRWXUGO, uid, gid, symname); ++ yaffs_gross_unlock(dev); ++ ++ if (obj) { ++ struct inode *inode; ++ ++ inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj); ++ d_instantiate(dentry, inode); ++ update_dir_time(dir); ++ yaffs_trace(YAFFS_TRACE_OS, "symlink created OK"); ++ return 0; ++ } else { ++ yaffs_trace(YAFFS_TRACE_OS, "symlink not created"); ++ } ++ ++ return -ENOMEM; ++} ++ ++/* ++ * The VFS layer already does all the dentry stuff for rename. ++ * ++ * NB: POSIX says you can rename an object over an old object of the same name ++ */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)) ++static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry, ++ struct inode *new_dir, struct dentry *new_dentry, unsigned int unused) ++#else ++static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry, ++ struct inode *new_dir, struct dentry *new_dentry) ++#endif ++{ ++ struct yaffs_dev *dev; ++ int ret_val = YAFFS_FAIL; ++ struct yaffs_obj *target; ++ ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_rename"); ++ dev = yaffs_inode_to_obj(old_dir)->my_dev; ++ ++ yaffs_gross_lock(dev); ++ ++ /* Check if the target is an existing directory that is not empty. */ ++ target = yaffs_find_by_name(yaffs_inode_to_obj(new_dir), ++ new_dentry->d_name.name); ++ ++ if (target && target->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY && ++ !list_empty(&target->variant.dir_variant.children)) { ++ ++ yaffs_trace(YAFFS_TRACE_OS, "target is non-empty dir"); ++ ++ ret_val = YAFFS_FAIL; ++ } else { ++ /* Now does unlinking internally using shadowing mechanism */ ++ yaffs_trace(YAFFS_TRACE_OS, "calling yaffs_rename_obj"); ++ ++ ret_val = yaffs_rename_obj(yaffs_inode_to_obj(old_dir), ++ old_dentry->d_name.name, ++ yaffs_inode_to_obj(new_dir), ++ new_dentry->d_name.name); ++ } ++ yaffs_gross_unlock(dev); ++ ++ if (ret_val == YAFFS_OK) { ++ if (target) ++ inode_dec_link_count(new_dentry->d_inode); ++ ++ update_dir_time(old_dir); ++ if (old_dir != new_dir) ++ update_dir_time(new_dir); ++ return 0; ++ } else { ++ return -ENOTEMPTY; ++ } ++} ++ ++ ++ ++ ++static int yaffs_unlink(struct inode *dir, struct dentry *dentry) ++{ ++ int ret_val; ++ ++ struct yaffs_dev *dev; ++ struct yaffs_obj *obj; ++ ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_unlink %d:%s", ++ (int)(dir->i_ino), dentry->d_name.name); ++ obj = yaffs_inode_to_obj(dir); ++ dev = obj->my_dev; ++ ++ yaffs_gross_lock(dev); ++ ++ ret_val = yaffs_unlinker(obj, dentry->d_name.name); ++ ++ if (ret_val == YAFFS_OK) { ++ inode_dec_link_count(dentry->d_inode); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)) ++ inode_inc_iversion(dir); ++#else ++ dir->i_version++; ++#endif ++ yaffs_gross_unlock(dev); ++ update_dir_time(dir); ++ return 0; ++ } ++ yaffs_gross_unlock(dev); ++ return -ENOTEMPTY; ++} ++ ++ ++ ++static const struct inode_operations yaffs_dir_inode_operations = { ++ .create = yaffs_create, ++ .lookup = yaffs_lookup, ++ .link = yaffs_link, ++ .unlink = yaffs_unlink, ++ .symlink = yaffs_symlink, ++ .mkdir = yaffs_mkdir, ++ .rmdir = yaffs_unlink, ++ .mknod = yaffs_mknod, ++ .rename = yaffs_rename, ++ .setattr = yaffs_setattr, ++ .listxattr = yaffs_listxattr, ++#ifdef YAFFS_USE_XATTR ++ .setxattr = yaffs_setxattr, ++ .getxattr = yaffs_getxattr, ++ .removexattr = yaffs_removexattr, ++#endif ++}; ++ ++/*-----------------------------------------------------------------*/ ++/* Directory search context allows us to unlock access to yaffs during ++ * filldir without causing problems with the directory being modified. ++ * This is similar to the tried and tested mechanism used in yaffs direct. ++ * ++ * A search context iterates along a doubly linked list of siblings in the ++ * directory. If the iterating object is deleted then this would corrupt ++ * the list iteration, likely causing a crash. The search context avoids ++ * this by using the remove_obj_fn to move the search context to the ++ * next object before the object is deleted. ++ * ++ * Many readdirs (and thus seach conexts) may be alive simulateously so ++ * each struct yaffs_dev has a list of these. ++ * ++ * A seach context lives for the duration of a readdir. ++ * ++ * All these functions must be called while yaffs is locked. ++ */ ++ ++struct yaffs_search_context { ++ struct yaffs_dev *dev; ++ struct yaffs_obj *dir_obj; ++ struct yaffs_obj *next_return; ++ struct list_head others; ++}; ++ ++/* ++ * yaffs_new_search() creates a new search context, initialises it and ++ * adds it to the device's search context list. ++ * ++ * Called at start of readdir. ++ */ ++static struct yaffs_search_context *yaffs_new_search(struct yaffs_obj *dir) ++{ ++ struct yaffs_dev *dev = dir->my_dev; ++ struct yaffs_search_context *sc = ++ kmalloc(sizeof(struct yaffs_search_context), GFP_NOFS); ++ if (sc) { ++ sc->dir_obj = dir; ++ sc->dev = dev; ++ if (list_empty(&sc->dir_obj->variant.dir_variant.children)) ++ sc->next_return = NULL; ++ else ++ sc->next_return = ++ list_entry(dir->variant.dir_variant.children.next, ++ struct yaffs_obj, siblings); ++ INIT_LIST_HEAD(&sc->others); ++ list_add(&sc->others, &(yaffs_dev_to_lc(dev)->search_contexts)); ++ } ++ return sc; ++} ++ ++/* ++ * yaffs_search_end() disposes of a search context and cleans up. ++ */ ++static void yaffs_search_end(struct yaffs_search_context *sc) ++{ ++ if (sc) { ++ list_del(&sc->others); ++ kfree(sc); ++ } ++} ++ ++/* ++ * yaffs_search_advance() moves a search context to the next object. ++ * Called when the search iterates or when an object removal causes ++ * the search context to be moved to the next object. ++ */ ++static void yaffs_search_advance(struct yaffs_search_context *sc) ++{ ++ if (!sc) ++ return; ++ ++ if (sc->next_return == NULL || ++ list_empty(&sc->dir_obj->variant.dir_variant.children)) ++ sc->next_return = NULL; ++ else { ++ struct list_head *next = sc->next_return->siblings.next; ++ ++ if (next == &sc->dir_obj->variant.dir_variant.children) ++ sc->next_return = NULL; /* end of list */ ++ else ++ sc->next_return = ++ list_entry(next, struct yaffs_obj, siblings); ++ } ++} ++ ++/* ++ * yaffs_remove_obj_callback() is called when an object is unlinked. ++ * We check open search contexts and advance any which are currently ++ * on the object being iterated. ++ */ ++static void yaffs_remove_obj_callback(struct yaffs_obj *obj) ++{ ++ ++ struct list_head *i; ++ struct yaffs_search_context *sc; ++ struct list_head *search_contexts = ++ &(yaffs_dev_to_lc(obj->my_dev)->search_contexts); ++ ++ /* Iterate through the directory search contexts. ++ * If any are currently on the object being removed, then advance ++ * the search context to the next object to prevent a hanging pointer. ++ */ ++ list_for_each(i, search_contexts) { ++ sc = list_entry(i, struct yaffs_search_context, others); ++ if (sc->next_return == obj) ++ yaffs_search_advance(sc); ++ } ++ ++} ++ ++ ++/*-----------------------------------------------------------------*/ ++ ++#ifdef YAFFS_USE_DIR_ITERATE ++static int yaffs_iterate(struct file *f, struct dir_context *dc) ++{ ++ struct yaffs_obj *obj; ++ struct yaffs_dev *dev; ++ struct yaffs_search_context *sc; ++ unsigned long curoffs; ++ struct yaffs_obj *l; ++ int ret_val = 0; ++ ++ char name[YAFFS_MAX_NAME_LENGTH + 1]; ++ ++ obj = yaffs_dentry_to_obj(Y_GET_DENTRY(f)); ++ dev = obj->my_dev; ++ ++ yaffs_gross_lock(dev); ++ ++ yaffs_dev_to_lc(dev)->readdir_process = current; ++ ++ sc = yaffs_new_search(obj); ++ if (!sc) { ++ ret_val = -ENOMEM; ++ goto out; ++ } ++ ++ if (!dir_emit_dots(f, dc)) ++ goto out; ++ ++ curoffs = 1; ++ ++ while (sc->next_return) { ++ curoffs++; ++ l = sc->next_return; ++ if (curoffs >= dc->pos) { ++ int this_inode = yaffs_get_obj_inode(l); ++ int this_type = yaffs_get_obj_type(l); ++ ++ yaffs_get_obj_name(l, name, YAFFS_MAX_NAME_LENGTH + 1); ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_readdir: %s inode %d", ++ name, yaffs_get_obj_inode(l)); ++ ++ yaffs_gross_unlock(dev); ++ ++ if (!dir_emit(dc, ++ name, ++ strlen(name), ++ this_inode, ++ this_type)) { ++ yaffs_gross_lock(dev); ++ goto out; ++ } ++ ++ yaffs_gross_lock(dev); ++ ++ dc->pos++; ++ f->f_pos++; ++ } ++ yaffs_search_advance(sc); ++ } ++ ++out: ++ yaffs_search_end(sc); ++ yaffs_dev_to_lc(dev)->readdir_process = NULL; ++ yaffs_gross_unlock(dev); ++ ++ return ret_val; ++} ++ ++#else ++ ++static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir) ++{ ++ struct yaffs_obj *obj; ++ struct yaffs_dev *dev; ++ struct yaffs_search_context *sc; ++ struct inode *inode = Y_GET_DENTRY(f)->d_inode; ++ unsigned long offset, curoffs; ++ struct yaffs_obj *l; ++ int ret_val = 0; ++ ++ char name[YAFFS_MAX_NAME_LENGTH + 1]; ++ ++ obj = yaffs_dentry_to_obj(Y_GET_DENTRY(f)); ++ dev = obj->my_dev; ++ ++ yaffs_gross_lock(dev); ++ ++ yaffs_dev_to_lc(dev)->readdir_process = current; ++ ++ offset = f->f_pos; ++ ++ sc = yaffs_new_search(obj); ++ if (!sc) { ++ ret_val = -ENOMEM; ++ goto out; ++ } ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_readdir: starting at %d", (int)offset); ++ ++ if (offset == 0) { ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_readdir: entry . ino %d", ++ (int)inode->i_ino); ++ yaffs_gross_unlock(dev); ++ if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0) { ++ yaffs_gross_lock(dev); ++ goto out; ++ } ++ yaffs_gross_lock(dev); ++ offset++; ++ f->f_pos++; ++ } ++ if (offset == 1) { ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_readdir: entry .. ino %d", ++ (int)f->f_dentry->d_parent->d_inode->i_ino); ++ yaffs_gross_unlock(dev); ++ if (filldir(dirent, "..", 2, offset, ++ f->f_dentry->d_parent->d_inode->i_ino, ++ DT_DIR) < 0) { ++ yaffs_gross_lock(dev); ++ goto out; ++ } ++ yaffs_gross_lock(dev); ++ offset++; ++ f->f_pos++; ++ } ++ ++ curoffs = 1; ++ ++ /* If the directory has changed since the open or last call to ++ readdir, rewind to after the 2 canned entries. */ ++ if (f->f_version != inode->i_version) { ++ offset = 2; ++ f->f_pos = offset; ++ f->f_version = inode->i_version; ++ } ++ ++ while (sc->next_return) { ++ curoffs++; ++ l = sc->next_return; ++ if (curoffs >= offset) { ++ int this_inode = yaffs_get_obj_inode(l); ++ int this_type = yaffs_get_obj_type(l); ++ ++ yaffs_get_obj_name(l, name, YAFFS_MAX_NAME_LENGTH + 1); ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_readdir: %s inode %d", ++ name, yaffs_get_obj_inode(l)); ++ ++ yaffs_gross_unlock(dev); ++ ++ if (filldir(dirent, ++ name, ++ strlen(name), ++ offset, this_inode, this_type) < 0) { ++ yaffs_gross_lock(dev); ++ goto out; ++ } ++ ++ yaffs_gross_lock(dev); ++ ++ offset++; ++ f->f_pos++; ++ } ++ yaffs_search_advance(sc); ++ } ++ ++out: ++ yaffs_search_end(sc); ++ yaffs_dev_to_lc(dev)->readdir_process = NULL; ++ yaffs_gross_unlock(dev); ++ ++ return ret_val; ++} ++ ++#endif ++ ++static const struct file_operations yaffs_dir_operations = { ++ .read = generic_read_dir, ++#ifdef YAFFS_USE_DIR_ITERATE ++ .iterate = yaffs_iterate, ++#else ++ .readdir = yaffs_readdir, ++#endif ++ .fsync = yaffs_sync_object, ++ .llseek = generic_file_llseek, ++}; ++ ++static void yaffs_fill_inode_from_obj(struct inode *inode, ++ struct yaffs_obj *obj) ++{ ++ if (inode && obj) { ++ ++ /* Check mode against the variant type and attempt to repair if broken. */ ++ u32 mode = obj->yst_mode; ++ switch (obj->variant_type) { ++ case YAFFS_OBJECT_TYPE_FILE: ++ if (!S_ISREG(mode)) { ++ obj->yst_mode &= ~S_IFMT; ++ obj->yst_mode |= S_IFREG; ++ } ++ ++ break; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ if (!S_ISLNK(mode)) { ++ obj->yst_mode &= ~S_IFMT; ++ obj->yst_mode |= S_IFLNK; ++ } ++ ++ break; ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ if (!S_ISDIR(mode)) { ++ obj->yst_mode &= ~S_IFMT; ++ obj->yst_mode |= S_IFDIR; ++ } ++ ++ break; ++ case YAFFS_OBJECT_TYPE_UNKNOWN: ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ case YAFFS_OBJECT_TYPE_SPECIAL: ++ default: ++ /* TODO? */ ++ break; ++ } ++ ++ inode->i_flags |= S_NOATIME; ++ ++ inode->i_ino = obj->obj_id; ++ inode->i_mode = obj->yst_mode; ++ inode->i_uid = MAKE_uid(obj->yst_uid); ++ inode->i_gid = MAKE_gid(obj->yst_gid); ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)) ++ inode->i_blksize = inode->i_sb->s_blocksize; ++#endif ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++ ++ inode->i_rdev = old_decode_dev(obj->yst_rdev); ++ inode->i_atime.tv_sec = (time_t) (obj->yst_atime); ++ inode->i_atime.tv_nsec = 0; ++ inode->i_mtime.tv_sec = (time_t) obj->yst_mtime; ++ inode->i_mtime.tv_nsec = 0; ++ inode->i_ctime.tv_sec = (time_t) obj->yst_ctime; ++ inode->i_ctime.tv_nsec = 0; ++#else ++ inode->i_rdev = obj->yst_rdev; ++ inode->i_atime = obj->yst_atime; ++ inode->i_mtime = obj->yst_mtime; ++ inode->i_ctime = obj->yst_ctime; ++#endif ++ inode->i_size = yaffs_get_obj_length(obj); ++ inode->i_blocks = (inode->i_size + 511) >> 9; ++ ++ set_nlink(inode, yaffs_get_obj_link_count(obj)); ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_fill_inode mode %x uid %d gid %d size %lld count %d", ++ inode->i_mode, obj->yst_uid, obj->yst_gid, ++ inode->i_size, atomic_read(&inode->i_count)); ++ ++ switch (obj->yst_mode & S_IFMT) { ++ default: /* fifo, device or socket */ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++ init_special_inode(inode, obj->yst_mode, ++ old_decode_dev(obj->yst_rdev)); ++#else ++ init_special_inode(inode, obj->yst_mode, ++ (dev_t) (obj->yst_rdev)); ++#endif ++ break; ++ case S_IFREG: /* file */ ++ inode->i_op = &yaffs_file_inode_operations; ++ inode->i_fop = &yaffs_file_operations; ++ inode->i_mapping->a_ops = ++ &yaffs_file_address_operations; ++ break; ++ case S_IFDIR: /* directory */ ++ inode->i_op = &yaffs_dir_inode_operations; ++ inode->i_fop = &yaffs_dir_operations; ++ break; ++ case S_IFLNK: /* symlink */ ++ inode->i_op = &yaffs_symlink_inode_operations; ++ break; ++ } ++ ++ yaffs_inode_to_obj_lv(inode) = obj; ++ ++ obj->my_inode = inode; ++ ++ } else { ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_fill_inode invalid parameters"); ++ } ++ ++} ++ ++ ++ ++/* ++ * yaffs background thread functions . ++ * yaffs_bg_thread_fn() the thread function ++ * yaffs_bg_start() launches the background thread. ++ * yaffs_bg_stop() cleans up the background thread. ++ * ++ * NB: ++ * The thread should only run after the yaffs is initialised ++ * The thread should be stopped before yaffs is unmounted. ++ * The thread should not do any writing while the fs is in read only. ++ */ ++ ++static unsigned yaffs_bg_gc_urgency(struct yaffs_dev *dev) ++{ ++ unsigned erased_chunks = ++ dev->n_erased_blocks * dev->param.chunks_per_block; ++ struct yaffs_linux_context *context = yaffs_dev_to_lc(dev); ++ unsigned scattered = 0; /* Free chunks not in an erased block */ ++ ++ if (erased_chunks < dev->n_free_chunks) ++ scattered = (dev->n_free_chunks - erased_chunks); ++ ++ if (!context->bg_running) ++ return 0; ++ else if (scattered < (dev->param.chunks_per_block * 2)) ++ return 0; ++ else if (erased_chunks > dev->n_free_chunks / 2) ++ return 0; ++ else if (erased_chunks > dev->n_free_chunks / 4) ++ return 1; ++ else ++ return 2; ++} ++ ++#ifdef YAFFS_COMPILE_BACKGROUND ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)) ++struct timer_struct { ++ struct task_struct *task; ++ struct timer_list timer; ++}; ++#endif ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)) ++static void yaffs_background_waker(struct timer_list *t) ++{ ++ struct timer_struct *ts = from_timer(ts, t, timer); ++ ++ wake_up_process(ts->task); ++} ++#else ++void yaffs_background_waker(unsigned long data) ++{ ++ wake_up_process((struct task_struct *)data); ++} ++#endif ++ ++static int yaffs_bg_thread_fn(void *data) ++{ ++ struct yaffs_dev *dev = (struct yaffs_dev *)data; ++ struct yaffs_linux_context *context = yaffs_dev_to_lc(dev); ++ unsigned long now = jiffies; ++ unsigned long next_dir_update = now; ++ unsigned long next_gc = now; ++ unsigned long expires; ++ unsigned int urgency; ++ ++ int gc_result; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)) ++ struct timer_struct timer; ++#else ++ struct timer_list timer; ++#endif ++ ++ yaffs_trace(YAFFS_TRACE_BACKGROUND, ++ "yaffs_background starting for dev %p", (void *)dev); ++ ++#ifdef YAFFS_COMPILE_FREEZER ++ set_freezable(); ++#endif ++ while (context->bg_running) { ++ yaffs_trace(YAFFS_TRACE_BACKGROUND, "yaffs_background"); ++ ++ if (kthread_should_stop()) ++ break; ++ ++#ifdef YAFFS_COMPILE_FREEZER ++ if (try_to_freeze()) ++ continue; ++#endif ++ yaffs_gross_lock(dev); ++ ++ now = jiffies; ++ ++ if (time_after(now, next_dir_update) && yaffs_bg_enable) { ++ yaffs_update_dirty_dirs(dev); ++ next_dir_update = now + HZ; ++ } ++ ++ if (time_after(now, next_gc) && yaffs_bg_enable) { ++ if (!dev->is_checkpointed) { ++ urgency = yaffs_bg_gc_urgency(dev); ++ gc_result = yaffs_bg_gc(dev, urgency); ++ if (urgency > 1) ++ next_gc = now + HZ / 20 + 1; ++ else if (urgency > 0) ++ next_gc = now + HZ / 10 + 1; ++ else ++ next_gc = now + HZ * 2; ++ } else { ++ /* ++ * gc not running so set to next_dir_update ++ * to cut down on wake ups ++ */ ++ next_gc = next_dir_update; ++ } ++ } ++ yaffs_gross_unlock(dev); ++ expires = next_dir_update; ++ if (time_before(next_gc, expires)) ++ expires = next_gc; ++ if (time_before(expires, now)) ++ expires = now + HZ; ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)) ++ Y_INIT_TIMER(&timer.timer, yaffs_background_waker); ++ timer.timer.expires = expires + 1; ++ timer.task = current; ++#else ++ Y_INIT_TIMER(&timer); ++ timer.expires = expires + 1; ++ timer.data = (unsigned long)current; ++ timer.function = yaffs_background_waker; ++#endif ++ ++ set_current_state(TASK_INTERRUPTIBLE); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)) ++ add_timer(&timer.timer); ++ schedule(); ++ del_timer_sync(&timer.timer); ++#else ++ add_timer(&timer); ++ schedule(); ++ del_timer_sync(&timer); ++#endif ++ } ++ ++ return 0; ++} ++ ++static int yaffs_bg_start(struct yaffs_dev *dev) ++{ ++ int retval = 0; ++ struct yaffs_linux_context *context = yaffs_dev_to_lc(dev); ++ ++ if (dev->read_only) ++ return -1; ++ ++ context->bg_running = 1; ++ ++ context->bg_thread = kthread_run(yaffs_bg_thread_fn, ++ (void *)dev, "yaffs-bg-%d", ++ context->mount_id); ++ ++ if (IS_ERR(context->bg_thread)) { ++ retval = PTR_ERR(context->bg_thread); ++ context->bg_thread = NULL; ++ context->bg_running = 0; ++ } ++ return retval; ++} ++ ++static void yaffs_bg_stop(struct yaffs_dev *dev) ++{ ++ struct yaffs_linux_context *ctxt = yaffs_dev_to_lc(dev); ++ ++ ctxt->bg_running = 0; ++ ++ if (ctxt->bg_thread) { ++ kthread_stop(ctxt->bg_thread); ++ ctxt->bg_thread = NULL; ++ } ++} ++#else ++static int yaffs_bg_thread_fn(void *data) ++{ ++ return 0; ++} ++ ++static int yaffs_bg_start(struct yaffs_dev *dev) ++{ ++ return 0; ++} ++ ++static void yaffs_bg_stop(struct yaffs_dev *dev) ++{ ++} ++#endif ++ ++ ++static void yaffs_flush_inodes(struct super_block *sb) ++{ ++ struct inode *iptr; ++ struct yaffs_obj *obj; ++ ++ list_for_each_entry(iptr, &sb->s_inodes, i_sb_list) { ++ obj = yaffs_inode_to_obj(iptr); ++ if (obj) { ++ yaffs_trace(YAFFS_TRACE_OS, ++ "flushing obj %d", ++ obj->obj_id); ++ yaffs_flush_file(obj, 1, 0, 0); ++ } ++ } ++} ++ ++static void yaffs_flush_super(struct super_block *sb, int do_checkpoint) ++{ ++ struct yaffs_dev *dev = yaffs_super_to_dev(sb); ++ if (!dev) ++ return; ++ ++ yaffs_flush_inodes(sb); ++ yaffs_update_dirty_dirs(dev); ++ yaffs_flush_whole_cache(dev, 1); ++ if (do_checkpoint) ++ yaffs_checkpoint_save(dev); ++} ++ ++static LIST_HEAD(yaffs_context_list); ++struct mutex yaffs_context_lock; ++ ++static void yaffs_put_super(struct super_block *sb) ++{ ++ struct yaffs_dev *dev = yaffs_super_to_dev(sb); ++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev); ++ ++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_ALWAYS, ++ "yaffs_put_super"); ++ ++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND, ++ "Shutting down yaffs background thread"); ++ yaffs_bg_stop(dev); ++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND, ++ "yaffs background thread shut down"); ++ ++ yaffs_gross_lock(dev); ++ ++ yaffs_flush_super(sb, 1); ++ ++ yaffs_deinitialise(dev); ++ ++ yaffs_gross_unlock(dev); ++ ++ mutex_lock(&yaffs_context_lock); ++ list_del_init(&(yaffs_dev_to_lc(dev)->context_list)); ++ mutex_unlock(&yaffs_context_lock); ++ ++ if (yaffs_dev_to_lc(dev)->spare_buffer) { ++ kfree(yaffs_dev_to_lc(dev)->spare_buffer); ++ yaffs_dev_to_lc(dev)->spare_buffer = NULL; ++ } ++ ++ kfree(dev); ++ ++ yaffs_put_mtd_device(mtd); ++ ++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_ALWAYS, ++ "yaffs_put_super done"); ++} ++ ++ ++static unsigned yaffs_gc_control_callback(struct yaffs_dev *dev) ++{ ++ return yaffs_gc_control; ++} ++ ++ ++#ifdef YAFFS_COMPILE_EXPORTFS ++ ++static struct inode *yaffs2_nfs_get_inode(struct super_block *sb, uint64_t ino, ++ uint32_t generation) ++{ ++ return Y_IGET(sb, ino); ++} ++ ++static struct dentry *yaffs2_fh_to_dentry(struct super_block *sb, ++ struct fid *fid, int fh_len, ++ int fh_type) ++{ ++ return generic_fh_to_dentry(sb, fid, fh_len, fh_type, ++ yaffs2_nfs_get_inode); ++} ++ ++static struct dentry *yaffs2_fh_to_parent(struct super_block *sb, ++ struct fid *fid, int fh_len, ++ int fh_type) ++{ ++ return generic_fh_to_parent(sb, fid, fh_len, fh_type, ++ yaffs2_nfs_get_inode); ++} ++ ++struct dentry *yaffs2_get_parent(struct dentry *dentry) ++{ ++ ++ struct super_block *sb = dentry->d_inode->i_sb; ++ struct dentry *parent = ERR_PTR(-ENOENT); ++ struct inode *inode; ++ unsigned long parent_ino; ++ struct yaffs_obj *d_obj; ++ struct yaffs_obj *parent_obj; ++ ++ d_obj = yaffs_inode_to_obj(dentry->d_inode); ++ ++ if (d_obj) { ++ parent_obj = d_obj->parent; ++ if (parent_obj) { ++ parent_ino = yaffs_get_obj_inode(parent_obj); ++ inode = Y_IGET(sb, parent_ino); ++ ++ if (IS_ERR(inode)) { ++ parent = ERR_CAST(inode); ++ } else { ++ parent = d_obtain_alias(inode); ++ if (!IS_ERR(parent)) { ++ parent = ERR_PTR(-ENOMEM); ++ iput(inode); ++ } ++ } ++ } ++ } ++ ++ return parent; ++} ++ ++/* Just declare a zero structure as a NULL value implies ++ * using the default functions of exportfs. ++ */ ++ ++static struct export_operations yaffs_export_ops = { ++ .fh_to_dentry = yaffs2_fh_to_dentry, ++ .fh_to_parent = yaffs2_fh_to_parent, ++ .get_parent = yaffs2_get_parent, ++}; ++ ++#endif ++ ++static void yaffs_unstitch_obj(struct inode *inode, struct yaffs_obj *obj) ++{ ++ /* Clear the association between the inode and ++ * the struct yaffs_obj. ++ */ ++ obj->my_inode = NULL; ++ yaffs_inode_to_obj_lv(inode) = NULL; ++ ++ /* If the object freeing was deferred, then the real ++ * free happens now. ++ * This should fix the inode inconsistency problem. ++ */ ++ yaffs_handle_defered_free(obj); ++} ++ ++#ifdef YAFFS_HAS_EVICT_INODE ++/* yaffs_evict_inode combines into one operation what was previously done in ++ * yaffs_clear_inode() and yaffs_delete_inode() ++ * ++ */ ++static void yaffs_evict_inode(struct inode *inode) ++{ ++ struct yaffs_obj *obj; ++ struct yaffs_dev *dev; ++ int deleteme = 0; ++ ++ obj = yaffs_inode_to_obj(inode); ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_evict_inode: ino %d, count %d %s", ++ (int)inode->i_ino, atomic_read(&inode->i_count), ++ obj ? "object exists" : "null object"); ++ ++ if (!inode->i_nlink && !is_bad_inode(inode)) ++ deleteme = 1; ++ truncate_inode_pages(&inode->i_data, 0); ++ Y_CLEAR_INODE(inode); ++ ++ if (deleteme && obj) { ++ dev = obj->my_dev; ++ yaffs_gross_lock(dev); ++ yaffs_del_obj(obj); ++ yaffs_gross_unlock(dev); ++ } ++ if (obj) { ++ dev = obj->my_dev; ++ yaffs_gross_lock(dev); ++ yaffs_unstitch_obj(inode, obj); ++ yaffs_gross_unlock(dev); ++ } ++} ++#else ++ ++/* clear is called to tell the fs to release any per-inode data it holds. ++ * The object might still exist on disk and is just being thrown out of the cache ++ * or else the object has actually been deleted and we're being called via ++ * the chain ++ * yaffs_delete_inode() -> clear_inode()->yaffs_clear_inode() ++ */ ++ ++static void yaffs_clear_inode(struct inode *inode) ++{ ++ struct yaffs_obj *obj; ++ struct yaffs_dev *dev; ++ ++ obj = yaffs_inode_to_obj(inode); ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_clear_inode: ino %d, count %d %s", ++ (int)inode->i_ino, atomic_read(&inode->i_count), ++ obj ? "object exists" : "null object"); ++ ++ if (obj) { ++ dev = obj->my_dev; ++ yaffs_gross_lock(dev); ++ yaffs_unstitch_obj(inode, obj); ++ yaffs_gross_unlock(dev); ++ } ++ ++} ++ ++/* delete is called when the link count is zero and the inode ++ * is put (ie. nobody wants to know about it anymore, time to ++ * delete the file). ++ * NB Must call clear_inode() ++ */ ++static void yaffs_delete_inode(struct inode *inode) ++{ ++ struct yaffs_obj *obj = yaffs_inode_to_obj(inode); ++ struct yaffs_dev *dev; ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_delete_inode: ino %d, count %d %s", ++ (int)inode->i_ino, atomic_read(&inode->i_count), ++ obj ? "object exists" : "null object"); ++ ++ if (obj) { ++ dev = obj->my_dev; ++ yaffs_gross_lock(dev); ++ yaffs_del_obj(obj); ++ yaffs_gross_unlock(dev); ++ } ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)) ++ truncate_inode_pages(&inode->i_data, 0); ++#endif ++ clear_inode(inode); ++} ++#endif ++ ++ ++ ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf) ++{ ++ struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev; ++ struct super_block *sb = dentry->d_sb; ++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf) ++{ ++ struct yaffs_dev *dev = yaffs_super_to_dev(sb); ++#else ++static int yaffs_statfs(struct super_block *sb, struct statfs *buf) ++{ ++ struct yaffs_dev *dev = yaffs_super_to_dev(sb); ++#endif ++ ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_statfs"); ++ ++ yaffs_gross_lock(dev); ++ ++ buf->f_type = YAFFS_MAGIC; ++ buf->f_bsize = sb->s_blocksize; ++ buf->f_namelen = 255; ++ ++ if (dev->data_bytes_per_chunk & (dev->data_bytes_per_chunk - 1)) { ++ /* Do this if chunk size is not a power of 2 */ ++ ++ uint64_t bytes_in_dev; ++ uint64_t bytes_free; ++ ++ bytes_in_dev = ++ ((uint64_t) ++ ((dev->param.end_block - dev->param.start_block + ++ 1))) * ((uint64_t) (dev->param.chunks_per_block * ++ dev->data_bytes_per_chunk)); ++ ++ do_div(bytes_in_dev, sb->s_blocksize); /* bytes_in_dev becomes the number of blocks */ ++ buf->f_blocks = bytes_in_dev; ++ ++ bytes_free = ((uint64_t) (yaffs_get_n_free_chunks(dev))) * ++ ((uint64_t) (dev->data_bytes_per_chunk)); ++ ++ do_div(bytes_free, sb->s_blocksize); ++ ++ buf->f_bfree = bytes_free; ++ ++ } else if (sb->s_blocksize > dev->data_bytes_per_chunk) { ++ ++ buf->f_blocks = ++ (dev->param.end_block - dev->param.start_block + 1) * ++ dev->param.chunks_per_block / ++ (sb->s_blocksize / dev->data_bytes_per_chunk); ++ buf->f_bfree = ++ yaffs_get_n_free_chunks(dev) / ++ (sb->s_blocksize / dev->data_bytes_per_chunk); ++ } else { ++ buf->f_blocks = ++ (dev->param.end_block - dev->param.start_block + 1) * ++ dev->param.chunks_per_block * ++ (dev->data_bytes_per_chunk / sb->s_blocksize); ++ ++ buf->f_bfree = ++ yaffs_get_n_free_chunks(dev) * ++ (dev->data_bytes_per_chunk / sb->s_blocksize); ++ } ++ ++ buf->f_files = 0; ++ buf->f_ffree = 0; ++ buf->f_bavail = buf->f_bfree; ++ ++ yaffs_gross_unlock(dev); ++ return 0; ++} ++ ++ ++ ++static int yaffs_do_sync_fs(struct super_block *sb, int request_checkpoint) ++{ ++ ++ struct yaffs_dev *dev = yaffs_super_to_dev(sb); ++ unsigned int oneshot_checkpoint = (yaffs_auto_checkpoint & 4); ++ unsigned gc_urgent = yaffs_bg_gc_urgency(dev); ++ int do_checkpoint; ++ int dirty = yaffs_check_super_dirty(dev); ++ ++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND, ++ "yaffs_do_sync_fs: gc-urgency %d %s %s%s", ++ gc_urgent, ++ dirty ? "dirty" : "clean", ++ request_checkpoint ? "checkpoint requested" : "no checkpoint", ++ oneshot_checkpoint ? " one-shot" : ""); ++ ++ yaffs_gross_lock(dev); ++ do_checkpoint = ((request_checkpoint && !gc_urgent) || ++ oneshot_checkpoint) && !dev->is_checkpointed; ++ ++ if (dirty || do_checkpoint) { ++ yaffs_flush_super(sb, !dev->is_checkpointed && do_checkpoint); ++ yaffs_clear_super_dirty(dev); ++ if (oneshot_checkpoint) ++ yaffs_auto_checkpoint &= ~4; ++ } ++ yaffs_gross_unlock(dev); ++ ++ return 0; ++} ++ ++ ++#ifdef YAFFS_HAS_WRITE_SUPER ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++static void yaffs_write_super(struct super_block *sb) ++#else ++static int yaffs_write_super(struct super_block *sb) ++#endif ++{ ++ unsigned request_checkpoint = (yaffs_auto_checkpoint >= 2); ++ ++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND, ++ "yaffs_write_super %s", ++ request_checkpoint ? " checkpt" : ""); ++ ++ yaffs_do_sync_fs(sb, request_checkpoint); ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)) ++ return 0; ++#endif ++} ++#endif ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++static int yaffs_sync_fs(struct super_block *sb, int wait) ++#else ++static int yaffs_sync_fs(struct super_block *sb) ++#endif ++{ ++ unsigned request_checkpoint = (yaffs_auto_checkpoint >= 1); ++ ++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC, ++ "yaffs_sync_fs%s", request_checkpoint ? " checkpt" : ""); ++ ++ yaffs_do_sync_fs(sb, request_checkpoint); ++ ++ return 0; ++} ++ ++/* the function only is used to change dev->read_only when this file system ++ * is remounted. ++ */ ++static int yaffs_remount_fs(struct super_block *sb, int *flags, char *data) ++{ ++ int read_only = 0; ++ int was_read_only = 0; ++ struct mtd_info *mtd; ++ struct yaffs_dev *dev = 0; ++ ++ /* Get the device */ ++ mtd = get_mtd_device(NULL, MINOR(sb->s_dev)); ++ if (!mtd) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "MTD device #%u doesn't appear to exist", ++ MINOR(sb->s_dev)); ++ return 1; ++ } ++ ++ /* Check it's NAND */ ++ if (mtd->type != MTD_NANDFLASH) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "MTD device is not NAND it's type %d", ++ mtd->type); ++ return 1; ++ } ++ ++ read_only = ((*flags & MS_RDONLY) != 0); ++ if (!read_only && !(mtd->flags & MTD_WRITEABLE)) { ++ read_only = 1; ++ printk(KERN_INFO ++ "yaffs: mtd is read only, setting superblock read only"); ++ *flags |= MS_RDONLY; ++ } ++ ++ dev = sb->s_fs_info; ++ was_read_only = dev->read_only; ++ dev->read_only = read_only; ++ ++ if (was_read_only && !read_only) { ++ yaffs_gross_lock(dev); ++ yaffs_guts_cleanup(dev); ++ yaffs_gross_unlock(dev); ++ yaffs_bg_start(dev); ++ } else if (!was_read_only && read_only) { ++ yaffs_bg_stop(dev); ++ } ++ ++ return 0; ++} ++ ++static const struct super_operations yaffs_super_ops = { ++ .statfs = yaffs_statfs, ++ ++#ifndef YAFFS_USE_OWN_IGET ++ .read_inode = yaffs_read_inode, ++#endif ++#ifdef YAFFS_HAS_PUT_INODE ++ .put_inode = yaffs_put_inode, ++#endif ++ .put_super = yaffs_put_super, ++#ifdef YAFFS_HAS_EVICT_INODE ++ .evict_inode = yaffs_evict_inode, ++#else ++ .delete_inode = yaffs_delete_inode, ++ .clear_inode = yaffs_clear_inode, ++#endif ++ .sync_fs = yaffs_sync_fs, ++#ifdef YAFFS_HAS_WRITE_SUPER ++ .write_super = yaffs_write_super, ++#endif ++ .remount_fs = yaffs_remount_fs, ++}; ++ ++struct yaffs_options { ++ int inband_tags; ++ int skip_checkpoint_read; ++ int skip_checkpoint_write; ++ int no_cache; ++ int tags_ecc_on; ++ int tags_ecc_overridden; ++ int lazy_loading_enabled; ++ int lazy_loading_overridden; ++ int empty_lost_and_found; ++ int empty_lost_and_found_overridden; ++ int disable_summary; ++}; ++ ++#define MAX_OPT_LEN 30 ++static int yaffs_parse_options(struct yaffs_options *options, ++ const char *options_str) ++{ ++ char cur_opt[MAX_OPT_LEN + 1]; ++ int p; ++ int error = 0; ++ ++ /* Parse through the options which is a comma seperated list */ ++ ++ while (options_str && *options_str && !error) { ++ memset(cur_opt, 0, MAX_OPT_LEN + 1); ++ p = 0; ++ ++ while (*options_str == ',') ++ options_str++; ++ ++ while (*options_str && *options_str != ',') { ++ if (p < MAX_OPT_LEN) { ++ cur_opt[p] = *options_str; ++ p++; ++ } ++ options_str++; ++ } ++ ++ if (!strcmp(cur_opt, "inband-tags")) { ++ options->inband_tags = 1; ++ } else if (!strcmp(cur_opt, "tags-ecc-off")) { ++ options->tags_ecc_on = 0; ++ options->tags_ecc_overridden = 1; ++ } else if (!strcmp(cur_opt, "tags-ecc-on")) { ++ options->tags_ecc_on = 1; ++ options->tags_ecc_overridden = 1; ++ } else if (!strcmp(cur_opt, "lazy-loading-off")) { ++ options->lazy_loading_enabled = 0; ++ options->lazy_loading_overridden = 1; ++ } else if (!strcmp(cur_opt, "lazy-loading-on")) { ++ options->lazy_loading_enabled = 1; ++ options->lazy_loading_overridden = 1; ++ } else if (!strcmp(cur_opt, "disable-summary")) { ++ options->disable_summary = 1; ++ } else if (!strcmp(cur_opt, "empty-lost-and-found-off")) { ++ options->empty_lost_and_found = 0; ++ options->empty_lost_and_found_overridden = 1; ++ } else if (!strcmp(cur_opt, "empty-lost-and-found-on")) { ++ options->empty_lost_and_found = 1; ++ options->empty_lost_and_found_overridden = 1; ++ } else if (!strcmp(cur_opt, "no-cache")) { ++ options->no_cache = 1; ++ } else if (!strcmp(cur_opt, "no-checkpoint-read")) { ++ options->skip_checkpoint_read = 1; ++ } else if (!strcmp(cur_opt, "no-checkpoint-write")) { ++ options->skip_checkpoint_write = 1; ++ } else if (!strcmp(cur_opt, "no-checkpoint")) { ++ options->skip_checkpoint_read = 1; ++ options->skip_checkpoint_write = 1; ++ } else { ++ printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n", ++ cur_opt); ++ error = 1; ++ } ++ } ++ ++ return error; ++} ++ ++ ++static struct dentry *yaffs_make_root(struct inode *inode) ++{ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) ++ struct dentry *root = d_alloc_root(inode); ++ ++ if (!root) ++ iput(inode); ++ ++ return root; ++#else ++ return d_make_root(inode); ++#endif ++} ++ ++ ++ ++ ++static struct super_block *yaffs_internal_read_super(int yaffs_version, ++ struct super_block *sb, ++ void *data, int silent) ++{ ++ int n_blocks; ++ struct inode *inode = NULL; ++ struct dentry *root; ++ struct yaffs_dev *dev = 0; ++ char devname_buf[BDEVNAME_SIZE + 1]; ++ struct mtd_info *mtd; ++ int err; ++ char *data_str = (char *)data; ++ struct yaffs_linux_context *context = NULL; ++ struct yaffs_param *param; ++ ++ int read_only = 0; ++ int inband_tags = 0; ++ ++ struct yaffs_options options; ++ ++ unsigned mount_id; ++ int found; ++ struct yaffs_linux_context *context_iterator; ++ struct list_head *l; ++ ++ if (!sb) { ++ printk(KERN_INFO "yaffs: sb is NULL\n"); ++ return NULL; ++ } ++ ++ sb->s_magic = YAFFS_MAGIC; ++ sb->s_op = &yaffs_super_ops; ++ sb->s_flags |= MS_NOATIME; ++ ++ read_only = ((sb->s_flags & MS_RDONLY) != 0); ++ ++#ifdef YAFFS_COMPILE_EXPORTFS ++ sb->s_export_op = &yaffs_export_ops; ++#endif ++ ++ if (!sb->s_dev) ++ printk(KERN_INFO "yaffs: sb->s_dev is NULL\n"); ++ else if (!yaffs_devname(sb, devname_buf)) ++ printk(KERN_INFO "yaffs: devname is NULL\n"); ++ else ++ printk(KERN_INFO "yaffs: dev is %d name is \"%s\" %s\n", ++ sb->s_dev, ++ yaffs_devname(sb, devname_buf), read_only ? "ro" : "rw"); ++ ++ if (!data_str) ++ data_str = ""; ++ ++ printk(KERN_INFO "yaffs: passed flags \"%s\"\n", data_str); ++ ++ memset(&options, 0, sizeof(options)); ++ ++ if (yaffs_parse_options(&options, data_str)) { ++ /* Option parsing failed */ ++ return NULL; ++ } ++ ++ sb->s_blocksize = PAGE_CACHE_SIZE; ++ sb->s_blocksize_bits = PAGE_CACHE_SHIFT; ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_read_super: Using yaffs%d", yaffs_version); ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_read_super: block size %d", (int)(sb->s_blocksize)); ++ ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "yaffs: Attempting MTD mount of %u.%u,\"%s\"", ++ MAJOR(sb->s_dev), MINOR(sb->s_dev), ++ yaffs_devname(sb, devname_buf)); ++ ++ /* Get the device */ ++ mtd = get_mtd_device(NULL, MINOR(sb->s_dev)); ++ if (IS_ERR(mtd)) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "yaffs: MTD device %u either not valid or unavailable", ++ MINOR(sb->s_dev)); ++ return NULL; ++ } ++ ++ if (yaffs_auto_select && yaffs_version == 1 && WRITE_SIZE(mtd) >= 2048) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs2"); ++ yaffs_version = 2; ++ } ++ ++ /* Added NCB 26/5/2006 for completeness */ ++ if (yaffs_version == 2 && !options.inband_tags ++ && WRITE_SIZE(mtd) == 512) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs1"); ++ yaffs_version = 1; ++ } ++ ++ if (mtd->oobavail < sizeof(struct yaffs_packed_tags2) || ++ options.inband_tags) ++ inband_tags = 1; ++ ++ if(yaffs_verify_mtd(mtd, yaffs_version, inband_tags) < 0) ++ return NULL; ++ ++ /* OK, so if we got here, we have an MTD that's NAND and looks ++ * like it has the right capabilities ++ * Set the struct yaffs_dev up for mtd ++ */ ++ ++ if (!read_only && !(mtd->flags & MTD_WRITEABLE)) { ++ read_only = 1; ++ printk(KERN_INFO ++ "yaffs: mtd is read only, setting superblock read only\n" ++ ); ++ sb->s_flags |= MS_RDONLY; ++ } ++ ++ dev = kmalloc(sizeof(struct yaffs_dev), GFP_KERNEL); ++ context = kmalloc(sizeof(struct yaffs_linux_context), GFP_KERNEL); ++ ++ if (!dev || !context) { ++ kfree(dev); ++ kfree(context); ++ dev = NULL; ++ context = NULL; ++ ++ /* Deep shit could not allocate device structure */ ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "yaffs_read_super: Failed trying to allocate struct yaffs_dev." ++ ); ++ return NULL; ++ } ++ memset(dev, 0, sizeof(struct yaffs_dev)); ++ param = &(dev->param); ++ ++ memset(context, 0, sizeof(struct yaffs_linux_context)); ++ dev->os_context = context; ++ INIT_LIST_HEAD(&(context->context_list)); ++ context->dev = dev; ++ context->super = sb; ++ ++ dev->read_only = read_only; ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++ sb->s_fs_info = dev; ++#else ++ sb->u.generic_sbp = dev; ++#endif ++ ++ ++ dev->driver_context = mtd; ++ param->name = mtd->name; ++ ++ /* Set up the memory size parameters.... */ ++ ++ ++ param->n_reserved_blocks = 5; ++ param->n_caches = (options.no_cache) ? 0 : 10; ++ param->inband_tags = inband_tags; ++ ++ param->enable_xattr = 1; ++ if (options.lazy_loading_overridden) ++ param->disable_lazy_load = !options.lazy_loading_enabled; ++ ++ param->defered_dir_update = 1; ++ ++#ifndef CONFIG_YAFFS_DISABLE_TAGS_ECC ++ if (options.tags_ecc_overridden) ++ param->no_tags_ecc = !options.tags_ecc_on; ++#else ++ param->no_tags_ecc = 1; ++#endif ++ param->empty_lost_n_found = 1; ++ param->refresh_period = 500; ++ param->disable_summary = options.disable_summary; ++ ++ ++#ifdef CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING ++ param->disable_bad_block_marking = 1; ++#endif ++ if (options.empty_lost_and_found_overridden) ++ param->empty_lost_n_found = options.empty_lost_and_found; ++ ++ /* ... and the functions. */ ++ if (yaffs_version == 2) { ++ param->is_yaffs2 = 1; ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++ param->total_bytes_per_chunk = mtd->writesize; ++ param->chunks_per_block = mtd->erasesize / mtd->writesize; ++#else ++ param->total_bytes_per_chunk = mtd->oobblock; ++ param->chunks_per_block = mtd->erasesize / mtd->oobblock; ++#endif ++ n_blocks = YCALCBLOCKS(mtd->size, mtd->erasesize); ++ ++ param->start_block = 0; ++ param->end_block = n_blocks - 1; ++ } else { ++ param->is_yaffs2 = 0; ++ n_blocks = YCALCBLOCKS(mtd->size, ++ YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK); ++ ++ param->chunks_per_block = YAFFS_CHUNKS_PER_BLOCK; ++ param->total_bytes_per_chunk = YAFFS_BYTES_PER_CHUNK; ++ } ++ ++ param->start_block = 0; ++ param->end_block = n_blocks - 1; ++ ++ yaffs_mtd_drv_install(dev); ++ ++ param->sb_dirty_fn = yaffs_set_super_dirty; ++ param->gc_control_fn = yaffs_gc_control_callback; ++ ++ yaffs_dev_to_lc(dev)->super = sb; ++ ++ param->use_nand_ecc = 1; ++ ++ param->skip_checkpt_rd = options.skip_checkpoint_read; ++ param->skip_checkpt_wr = options.skip_checkpoint_write; ++ ++ mutex_lock(&yaffs_context_lock); ++ /* Get a mount id */ ++ found = 0; ++ for (mount_id = 0; !found; mount_id++) { ++ found = 1; ++ list_for_each(l, &yaffs_context_list) { ++ context_iterator = ++ list_entry(l, struct yaffs_linux_context, ++ context_list); ++ if (context_iterator->mount_id == mount_id) ++ found = 0; ++ } ++ } ++ context->mount_id = mount_id; ++ ++ list_add_tail(&(yaffs_dev_to_lc(dev)->context_list), ++ &yaffs_context_list); ++ mutex_unlock(&yaffs_context_lock); ++ ++ /* Directory search handling... */ ++ INIT_LIST_HEAD(&(yaffs_dev_to_lc(dev)->search_contexts)); ++ param->remove_obj_fn = yaffs_remove_obj_callback; ++ ++ mutex_init(&(yaffs_dev_to_lc(dev)->gross_lock)); ++ ++ yaffs_gross_lock(dev); ++ ++ err = yaffs_guts_initialise(dev); ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_read_super: guts initialised %s", ++ (err == YAFFS_OK) ? "OK" : "FAILED"); ++ ++ if (err == YAFFS_OK) ++ yaffs_bg_start(dev); ++ ++ if (!context->bg_thread) ++ param->defered_dir_update = 0; ++ ++ sb->s_maxbytes = yaffs_max_file_size(dev); ++ ++ /* Release lock before yaffs_get_inode() */ ++ yaffs_gross_unlock(dev); ++ ++ /* Create root inode */ ++ if (err == YAFFS_OK) ++ inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0, yaffs_root(dev)); ++ ++ if (!inode) ++ return NULL; ++ ++ inode->i_op = &yaffs_dir_inode_operations; ++ inode->i_fop = &yaffs_dir_operations; ++ ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_read_super: got root inode"); ++ ++ root = yaffs_make_root(inode); ++ ++ if (!root) ++ return NULL; ++ ++ sb->s_root = root; ++ if(!dev->is_checkpointed) ++ yaffs_set_super_dirty(dev); ++ ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "yaffs_read_super: is_checkpointed %d", ++ dev->is_checkpointed); ++ ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_read_super: done"); ++ return sb; ++} ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data, ++ int silent) ++{ ++ return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL; ++} ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) ++static struct dentry *yaffs_mount(struct file_system_type *fs_type, int flags, ++ const char *dev_name, void *data) ++{ ++ return mount_bdev(fs_type, flags, dev_name, data, yaffs_internal_read_super_mtd); ++} ++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++static int yaffs_read_super(struct file_system_type *fs, ++ int flags, const char *dev_name, ++ void *data, struct vfsmount *mnt) ++{ ++ ++ return get_sb_bdev(fs, flags, dev_name, data, ++ yaffs_internal_read_super_mtd, mnt); ++} ++#else ++static struct super_block *yaffs_read_super(struct file_system_type *fs, ++ int flags, const char *dev_name, ++ void *data) ++{ ++ ++ return get_sb_bdev(fs, flags, dev_name, data, ++ yaffs_internal_read_super_mtd); ++} ++#endif ++ ++static struct file_system_type yaffs_fs_type = { ++ .owner = THIS_MODULE, ++ .name = "yaffs", ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) ++ .mount = yaffs_mount, ++#else ++ .get_sb = yaffs_read_super, ++#endif ++ .kill_sb = kill_block_super, ++ .fs_flags = FS_REQUIRES_DEV, ++}; ++#else ++static struct super_block *yaffs_read_super(struct super_block *sb, void *data, ++ int silent) ++{ ++ return yaffs_internal_read_super(1, sb, data, silent); ++} ++ ++static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super, ++ FS_REQUIRES_DEV); ++#endif ++ ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data, ++ int silent) ++{ ++ return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL; ++} ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) ++static struct dentry *yaffs2_mount(struct file_system_type *fs_type, int flags, ++ const char *dev_name, void *data) ++{ ++ return mount_bdev(fs_type, flags, dev_name, data, yaffs2_internal_read_super_mtd); ++} ++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++static int yaffs2_read_super(struct file_system_type *fs, ++ int flags, const char *dev_name, void *data, ++ struct vfsmount *mnt) ++{ ++ return get_sb_bdev(fs, flags, dev_name, data, ++ yaffs2_internal_read_super_mtd, mnt); ++} ++#else ++static struct super_block *yaffs2_read_super(struct file_system_type *fs, ++ int flags, const char *dev_name, ++ void *data) ++{ ++ ++ return get_sb_bdev(fs, flags, dev_name, data, ++ yaffs2_internal_read_super_mtd); ++} ++#endif ++ ++static struct file_system_type yaffs2_fs_type = { ++ .owner = THIS_MODULE, ++ .name = "yaffs2", ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) ++ .mount = yaffs2_mount, ++#else ++ .get_sb = yaffs2_read_super, ++#endif ++ .kill_sb = kill_block_super, ++ .fs_flags = FS_REQUIRES_DEV, ++}; ++#else ++static struct super_block *yaffs2_read_super(struct super_block *sb, ++ void *data, int silent) ++{ ++ return yaffs_internal_read_super(2, sb, data, silent); ++} ++ ++static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super, ++ FS_REQUIRES_DEV); ++#endif ++ ++ ++static struct proc_dir_entry *my_proc_entry; ++ ++static char *yaffs_dump_dev_part0(char *buf, struct yaffs_dev *dev) ++{ ++ struct yaffs_param *param = &dev->param; ++ int bs[10]; ++ ++ yaffs_count_blocks_by_state(dev,bs); ++ ++ buf += sprintf(buf, "start_block.......... %d\n", param->start_block); ++ buf += sprintf(buf, "end_block............ %d\n", param->end_block); ++ buf += sprintf(buf, "total_bytes_per_chunk %d\n", ++ param->total_bytes_per_chunk); ++ buf += sprintf(buf, "use_nand_ecc......... %d\n", param->use_nand_ecc); ++ buf += sprintf(buf, "no_tags_ecc.......... %d\n", param->no_tags_ecc); ++ buf += sprintf(buf, "is_yaffs2............ %d\n", param->is_yaffs2); ++ buf += sprintf(buf, "inband_tags.......... %d\n", param->inband_tags); ++ buf += sprintf(buf, "empty_lost_n_found... %d\n", ++ param->empty_lost_n_found); ++ buf += sprintf(buf, "disable_lazy_load.... %d\n", ++ param->disable_lazy_load); ++ buf += sprintf(buf, "disable_bad_block_mrk %d\n", ++ param->disable_bad_block_marking); ++ buf += sprintf(buf, "refresh_period....... %d\n", ++ param->refresh_period); ++ buf += sprintf(buf, "n_caches............. %d\n", param->n_caches); ++ buf += sprintf(buf, "n_reserved_blocks.... %d\n", ++ param->n_reserved_blocks); ++ buf += sprintf(buf, "always_check_erased.. %d\n", ++ param->always_check_erased); ++ buf += sprintf(buf, "\n"); ++ buf += sprintf(buf, "block count by state\n"); ++ buf += sprintf(buf, "0:%d 1:%d 2:%d 3:%d 4:%d\n", ++ bs[0], bs[1], bs[2], bs[3], bs[4]); ++ buf += sprintf(buf, "5:%d 6:%d 7:%d 8:%d 9:%d\n", ++ bs[5], bs[6], bs[7], bs[8], bs[9]); ++ ++ return buf; ++} ++ ++static char *yaffs_dump_dev_part1(char *buf, struct yaffs_dev *dev) ++{ ++ buf += sprintf(buf, "max file size....... %lld\n", ++ (long long) yaffs_max_file_size(dev)); ++ buf += sprintf(buf, "data_bytes_per_chunk. %d\n", ++ dev->data_bytes_per_chunk); ++ buf += sprintf(buf, "chunk_grp_bits....... %d\n", dev->chunk_grp_bits); ++ buf += sprintf(buf, "chunk_grp_size....... %d\n", dev->chunk_grp_size); ++ buf += sprintf(buf, "n_erased_blocks...... %d\n", dev->n_erased_blocks); ++ buf += sprintf(buf, "blocks_in_checkpt.... %d\n", ++ dev->blocks_in_checkpt); ++ buf += sprintf(buf, "\n"); ++ buf += sprintf(buf, "n_tnodes............. %d\n", dev->n_tnodes); ++ buf += sprintf(buf, "n_obj................ %d\n", dev->n_obj); ++ buf += sprintf(buf, "n_free_chunks........ %d\n", dev->n_free_chunks); ++ buf += sprintf(buf, "\n"); ++ buf += sprintf(buf, "n_page_writes........ %u\n", dev->n_page_writes); ++ buf += sprintf(buf, "n_page_reads......... %u\n", dev->n_page_reads); ++ buf += sprintf(buf, "n_erasures........... %u\n", dev->n_erasures); ++ buf += sprintf(buf, "n_gc_copies.......... %u\n", dev->n_gc_copies); ++ buf += sprintf(buf, "all_gcs.............. %u\n", dev->all_gcs); ++ buf += sprintf(buf, "passive_gc_count..... %u\n", ++ dev->passive_gc_count); ++ buf += sprintf(buf, "oldest_dirty_gc_count %u\n", ++ dev->oldest_dirty_gc_count); ++ buf += sprintf(buf, "n_gc_blocks.......... %u\n", dev->n_gc_blocks); ++ buf += sprintf(buf, "bg_gcs............... %u\n", dev->bg_gcs); ++ buf += sprintf(buf, "n_retried_writes..... %u\n", ++ dev->n_retried_writes); ++ buf += sprintf(buf, "n_retired_blocks..... %u\n", ++ dev->n_retired_blocks); ++ buf += sprintf(buf, "n_ecc_fixed.......... %u\n", dev->n_ecc_fixed); ++ buf += sprintf(buf, "n_ecc_unfixed........ %u\n", dev->n_ecc_unfixed); ++ buf += sprintf(buf, "n_tags_ecc_fixed..... %u\n", ++ dev->n_tags_ecc_fixed); ++ buf += sprintf(buf, "n_tags_ecc_unfixed... %u\n", ++ dev->n_tags_ecc_unfixed); ++ buf += sprintf(buf, "cache_hits........... %u\n", dev->cache_hits); ++ buf += sprintf(buf, "n_deleted_files...... %u\n", dev->n_deleted_files); ++ buf += sprintf(buf, "n_unlinked_files..... %u\n", ++ dev->n_unlinked_files); ++ buf += sprintf(buf, "refresh_count........ %u\n", dev->refresh_count); ++ buf += sprintf(buf, "n_bg_deletions....... %u\n", dev->n_bg_deletions); ++ buf += sprintf(buf, "tags_used............ %u\n", dev->tags_used); ++ buf += sprintf(buf, "summary_used......... %u\n", dev->summary_used); ++ ++ return buf; ++} ++ ++static int yaffs_proc_read(char *page, ++ char **start, ++ off_t offset, int count, int *eof, void *data) ++{ ++ struct list_head *item; ++ char *buf = page; ++ int step = offset; ++ int n = 0; ++ ++ /* Get proc_file_read() to step 'offset' by one on each sucessive call. ++ * We use 'offset' (*ppos) to indicate where we are in dev_list. ++ * This also assumes the user has posted a read buffer large ++ * enough to hold the complete output; but that's life in /proc. ++ */ ++ ++ *(int *)start = 1; ++ ++ /* Print header first */ ++ if (step == 0) ++ buf += ++ sprintf(buf, "Multi-version YAFFS\n"); ++ else if (step == 1) ++ buf += sprintf(buf, "\n"); ++ else { ++ step -= 2; ++ ++ mutex_lock(&yaffs_context_lock); ++ ++ /* Locate and print the Nth entry. Order N-squared but N is small. */ ++ list_for_each(item, &yaffs_context_list) { ++ struct yaffs_linux_context *dc = ++ list_entry(item, struct yaffs_linux_context, ++ context_list); ++ struct yaffs_dev *dev = dc->dev; ++ ++ if (n < (step & ~1)) { ++ n += 2; ++ continue; ++ } ++ if ((step & 1) == 0) { ++ buf += ++ sprintf(buf, "\nDevice %d \"%s\"\n", n, ++ dev->param.name); ++ buf = yaffs_dump_dev_part0(buf, dev); ++ } else { ++ buf = yaffs_dump_dev_part1(buf, dev); ++ } ++ ++ break; ++ } ++ mutex_unlock(&yaffs_context_lock); ++ } ++ ++ return buf - page < count ? buf - page : count; ++} ++ ++/** ++ * Set the verbosity of the warnings and error messages. ++ * ++ * Note that the names can only be a..z or _ with the current code. ++ */ ++ ++static struct { ++ char *mask_name; ++ unsigned mask_bitfield; ++} mask_flags[] = { ++ {"allocate", YAFFS_TRACE_ALLOCATE}, ++ {"always", YAFFS_TRACE_ALWAYS}, ++ {"background", YAFFS_TRACE_BACKGROUND}, ++ {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS}, ++ {"buffers", YAFFS_TRACE_BUFFERS}, ++ {"bug", YAFFS_TRACE_BUG}, ++ {"checkpt", YAFFS_TRACE_CHECKPOINT}, ++ {"deletion", YAFFS_TRACE_DELETION}, ++ {"erase", YAFFS_TRACE_ERASE}, ++ {"error", YAFFS_TRACE_ERROR}, ++ {"gc_detail", YAFFS_TRACE_GC_DETAIL}, ++ {"gc", YAFFS_TRACE_GC}, ++ {"lock", YAFFS_TRACE_LOCK}, ++ {"mtd", YAFFS_TRACE_MTD}, ++ {"nandaccess", YAFFS_TRACE_NANDACCESS}, ++ {"os", YAFFS_TRACE_OS}, ++ {"scan_debug", YAFFS_TRACE_SCAN_DEBUG}, ++ {"scan", YAFFS_TRACE_SCAN}, ++ {"mount", YAFFS_TRACE_MOUNT}, ++ {"tracing", YAFFS_TRACE_TRACING}, ++ {"sync", YAFFS_TRACE_SYNC}, ++ {"write", YAFFS_TRACE_WRITE}, ++ {"verify", YAFFS_TRACE_VERIFY}, ++ {"verify_nand", YAFFS_TRACE_VERIFY_NAND}, ++ {"verify_full", YAFFS_TRACE_VERIFY_FULL}, ++ {"verify_all", YAFFS_TRACE_VERIFY_ALL}, ++ {"all", 0xffffffff}, ++ {"none", 0}, ++ {NULL, 0}, ++}; ++ ++#define MAX_MASK_NAME_LENGTH 40 ++static int yaffs_proc_write_trace_options(struct file *file, const char *buf, ++ unsigned long count) ++{ ++ unsigned rg = 0, mask_bitfield; ++ char *end; ++ char *mask_name; ++ const char *x; ++ char substring[MAX_MASK_NAME_LENGTH + 1]; ++ int i; ++ int done = 0; ++ int add, len = 0; ++ int pos = 0; ++ ++ rg = yaffs_trace_mask; ++ ++ while (!done && (pos < count)) { ++ done = 1; ++ while ((pos < count) && isspace(buf[pos])) ++ pos++; ++ ++ switch (buf[pos]) { ++ case '+': ++ case '-': ++ case '=': ++ add = buf[pos]; ++ pos++; ++ break; ++ ++ default: ++ add = ' '; ++ break; ++ } ++ mask_name = NULL; ++ ++ mask_bitfield = simple_strtoul(buf + pos, &end, 0); ++ ++ if (end > buf + pos) { ++ mask_name = "numeral"; ++ len = end - (buf + pos); ++ pos += len; ++ done = 0; ++ } else { ++ for (x = buf + pos, i = 0; ++ (*x == '_' || (*x >= 'a' && *x <= 'z')) && ++ i < MAX_MASK_NAME_LENGTH; x++, i++, pos++) ++ substring[i] = *x; ++ substring[i] = '\0'; ++ ++ for (i = 0; mask_flags[i].mask_name != NULL; i++) { ++ if (strcmp(substring, mask_flags[i].mask_name) ++ == 0) { ++ mask_name = mask_flags[i].mask_name; ++ mask_bitfield = ++ mask_flags[i].mask_bitfield; ++ done = 0; ++ break; ++ } ++ } ++ } ++ ++ if (mask_name != NULL) { ++ done = 0; ++ switch (add) { ++ case '-': ++ rg &= ~mask_bitfield; ++ break; ++ case '+': ++ rg |= mask_bitfield; ++ break; ++ case '=': ++ rg = mask_bitfield; ++ break; ++ default: ++ rg |= mask_bitfield; ++ break; ++ } ++ } ++ } ++ ++ yaffs_trace_mask = rg | YAFFS_TRACE_ALWAYS; ++ ++ printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_trace_mask); ++ ++ if (rg & YAFFS_TRACE_ALWAYS) { ++ for (i = 0; mask_flags[i].mask_name != NULL; i++) { ++ char flag; ++ flag = ((rg & mask_flags[i].mask_bitfield) == ++ mask_flags[i].mask_bitfield) ? '+' : '-'; ++ printk(KERN_DEBUG "%c%s\n", flag, ++ mask_flags[i].mask_name); ++ } ++ } ++ ++ return count; ++} ++ ++/* Debug strings are of the form: ++ * .bnnn print info on block n ++ * .cobjn,chunkn print nand chunk id for objn:chunkn ++ */ ++ ++static int yaffs_proc_debug_write(struct file *file, const char *buf, ++ unsigned long count) ++{ ++ ++ char str[100]; ++ char *p0; ++ char *p1; ++ long p1_val; ++ long p0_val; ++ char cmd; ++ struct list_head *item; ++ ++ memset(str, 0, sizeof(str)); ++ memcpy(str, buf, min((size_t)count, sizeof(str) -1)); ++ ++ cmd = str[1]; ++ ++ p0 = str + 2; ++ ++ p1 = p0; ++ ++ while (*p1 && *p1 != ',') { ++ p1++; ++ } ++ *p1 = '\0'; ++ p1++; ++ ++ p0_val = simple_strtol(p0, NULL, 0); ++ p1_val = simple_strtol(p1, NULL, 0); ++ ++ ++ mutex_lock(&yaffs_context_lock); ++ ++ /* Locate and print the Nth entry. Order N-squared but N is small. */ ++ list_for_each(item, &yaffs_context_list) { ++ struct yaffs_linux_context *dc = ++ list_entry(item, struct yaffs_linux_context, ++ context_list); ++ struct yaffs_dev *dev = dc->dev; ++ ++ if (cmd == 'b') { ++ struct yaffs_block_info *bi; ++ ++ bi = yaffs_get_block_info(dev,p0_val); ++ ++ if(bi) { ++ printk("Block %d: state %d, retire %d, use %d, seq %d\n", ++ (int)p0_val, bi->block_state, ++ bi->needs_retiring, bi->pages_in_use, ++ bi->seq_number); ++ } ++ } else if (cmd == 'c') { ++ struct yaffs_obj *obj; ++ int nand_chunk; ++ ++ obj = yaffs_find_by_number(dev, p0_val); ++ if (!obj) ++ printk("No obj %d\n", (int)p0_val); ++ else { ++ if(p1_val == 0) ++ nand_chunk = obj->hdr_chunk; ++ else ++ nand_chunk = ++ yaffs_find_chunk_in_file(obj, ++ p1_val, NULL); ++ printk("Nand chunk for %d:%d is %d\n", ++ (int)p0_val, (int)p1_val, nand_chunk); ++ } ++ } ++ } ++ ++ mutex_unlock(&yaffs_context_lock); ++ ++ return count; ++} ++ ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) ++static int yaffs_proc_write(struct file *file, const char *buf, ++ unsigned long count, void *ppos) ++#else ++static ssize_t yaffs_proc_write(struct file *file, const char __user *buf, ++ size_t count, loff_t *ppos) ++#endif ++{ ++ if (buf[0] == '.') ++ return yaffs_proc_debug_write(file, buf, count); ++ return yaffs_proc_write_trace_options(file, buf, count); ++} ++ ++/* Stuff to handle installation of file systems */ ++struct file_system_to_install { ++ struct file_system_type *fst; ++ int installed; ++}; ++ ++static struct file_system_to_install fs_to_install[] = { ++ {&yaffs_fs_type, 0}, ++ {&yaffs2_fs_type, 0}, ++ {NULL, 0} ++}; ++ ++ ++#ifdef YAFFS_NEW_PROCFS ++static int yaffs_proc_show(struct seq_file *m, void *v) ++{ ++ /* FIXME: Unify in a better way? */ ++ char buffer[512]; ++ char *start; ++ int len; ++ ++ len = yaffs_proc_read(buffer, &start, 0, sizeof(buffer), NULL, NULL); ++ seq_puts(m, buffer); ++ return 0; ++} ++ ++static int yaffs_proc_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, yaffs_proc_show, NULL); ++} ++ ++static struct file_operations procfs_ops = { ++ .owner = THIS_MODULE, ++ .open = yaffs_proc_open, ++ .read = seq_read, ++ .write = yaffs_proc_write, ++ .release = single_release, ++}; ++ ++static int yaffs_procfs_init(void) ++{ ++ /* Install the proc_fs entries */ ++ my_proc_entry = proc_create("yaffs", ++ S_IRUGO | S_IFREG, ++ YPROC_ROOT, ++ &procfs_ops); ++ ++ if (my_proc_entry) { ++ return 0; ++ } else { ++ return -ENOMEM; ++ } ++} ++ ++#else ++ ++ ++static int yaffs_procfs_init(void) ++{ ++ /* Install the proc_fs entries */ ++ my_proc_entry = create_proc_entry("yaffs", ++ S_IRUGO | S_IFREG, YPROC_ROOT); ++ ++ if (my_proc_entry) { ++ my_proc_entry->write_proc = yaffs_proc_write; ++ my_proc_entry->read_proc = yaffs_proc_read; ++ my_proc_entry->data = NULL; ++ return 0; ++ } else { ++ return -ENOMEM; ++ } ++} ++ ++#endif ++ ++ ++static int __init init_yaffs_fs(void) ++{ ++ int error = 0; ++ struct file_system_to_install *fsinst; ++ ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "yaffs Installing."); ++ ++ mutex_init(&yaffs_context_lock); ++ ++ error = yaffs_procfs_init(); ++ if (error) ++ return error; ++ ++ /* Now add the file system entries */ ++ ++ fsinst = fs_to_install; ++ ++ while (fsinst->fst && !error) { ++ error = register_filesystem(fsinst->fst); ++ if (!error) ++ fsinst->installed = 1; ++ fsinst++; ++ } ++ ++ /* Any errors? uninstall */ ++ if (error) { ++ fsinst = fs_to_install; ++ ++ while (fsinst->fst) { ++ if (fsinst->installed) { ++ unregister_filesystem(fsinst->fst); ++ fsinst->installed = 0; ++ } ++ fsinst++; ++ } ++ } ++ ++ return error; ++} ++ ++static void __exit exit_yaffs_fs(void) ++{ ++ ++ struct file_system_to_install *fsinst; ++ ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "yaffs removing."); ++ ++ remove_proc_entry("yaffs", YPROC_ROOT); ++ ++ fsinst = fs_to_install; ++ ++ while (fsinst->fst) { ++ if (fsinst->installed) { ++ unregister_filesystem(fsinst->fst); ++ fsinst->installed = 0; ++ } ++ fsinst++; ++ } ++} ++ ++module_init(init_yaffs_fs) ++module_exit(exit_yaffs_fs) ++ ++MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system"); ++MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2011"); ++MODULE_LICENSE("GPL"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_yaffs1.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_yaffs1.c.patch new file mode 100644 index 00000000..9cd59284 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_yaffs1.c.patch @@ -0,0 +1,431 @@ +diff -drupN a/fs/yaffs2/yaffs_yaffs1.c b/fs/yaffs2/yaffs_yaffs1.c +--- a/fs/yaffs2/yaffs_yaffs1.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_yaffs1.c 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,427 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * 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. ++ */ ++ ++#include "yaffs_yaffs1.h" ++#include "yportenv.h" ++#include "yaffs_trace.h" ++#include "yaffs_bitmap.h" ++#include "yaffs_getblockinfo.h" ++#include "yaffs_nand.h" ++#include "yaffs_attribs.h" ++ ++int yaffs1_scan(struct yaffs_dev *dev) ++{ ++#ifdef CONFIG_YAFFS_NO_YAFFS1 ++ return YAFFS_FAIL; ++#else ++ struct yaffs_ext_tags tags; ++ u32 blk; ++ int result; ++ int chunk; ++ u32 c; ++ int deleted; ++ enum yaffs_block_state state; ++ LIST_HEAD(hard_list); ++ struct yaffs_block_info *bi; ++ u32 seq_number; ++ struct yaffs_obj_hdr *oh; ++ struct yaffs_obj *in; ++ struct yaffs_obj *parent; ++ int alloc_failed = 0; ++ struct yaffs_shadow_fixer *shadow_fixers = NULL; ++ u8 *chunk_data; ++ ++ yaffs_trace(YAFFS_TRACE_SCAN, ++ "yaffs1_scan starts intstartblk %d intendblk %d...", ++ dev->internal_start_block, dev->internal_end_block); ++ ++ chunk_data = yaffs_get_temp_buffer(dev); ++ ++ dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER; ++ ++ /* Scan all the blocks to determine their state */ ++ bi = dev->block_info; ++ for (blk = dev->internal_start_block; blk <= dev->internal_end_block; ++ blk++) { ++ yaffs_clear_chunk_bits(dev, blk); ++ bi->pages_in_use = 0; ++ bi->soft_del_pages = 0; ++ ++ yaffs_query_init_block_state(dev, blk, &state, &seq_number); ++ ++ bi->block_state = state; ++ bi->seq_number = seq_number; ++ ++ if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK) ++ bi->block_state = state = YAFFS_BLOCK_STATE_DEAD; ++ ++ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, ++ "Block scanning block %d state %d seq %d", ++ blk, state, seq_number); ++ ++ if (state == YAFFS_BLOCK_STATE_DEAD) { ++ yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, ++ "block %d is bad", blk); ++ } else if (state == YAFFS_BLOCK_STATE_EMPTY) { ++ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty "); ++ dev->n_erased_blocks++; ++ dev->n_free_chunks += dev->param.chunks_per_block; ++ } ++ bi++; ++ } ++ ++ /* For each block.... */ ++ for (blk = dev->internal_start_block; ++ !alloc_failed && blk <= dev->internal_end_block; blk++) { ++ ++ cond_resched(); ++ ++ bi = yaffs_get_block_info(dev, blk); ++ state = bi->block_state; ++ ++ deleted = 0; ++ ++ /* For each chunk in each block that needs scanning.... */ ++ for (c = 0; ++ !alloc_failed && c < dev->param.chunks_per_block && ++ state == YAFFS_BLOCK_STATE_NEEDS_SCAN; c++) { ++ /* Read the tags and decide what to do */ ++ chunk = blk * dev->param.chunks_per_block + c; ++ ++ result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL, ++ &tags); ++ ++ if (result != YAFFS_OK) ++ continue; ++ /* Let's have a good look at this chunk... */ ++ ++ if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED || ++ tags.is_deleted) { ++ /* YAFFS1 only... ++ * A deleted chunk ++ */ ++ deleted++; ++ dev->n_free_chunks++; ++ } else if (!tags.chunk_used) { ++ /* An unassigned chunk in the block ++ * This means that either the block is empty or ++ * this is the one being allocated from ++ */ ++ ++ if (c == 0) { ++ /* We're looking at the first chunk in ++ *the block so the block is unused */ ++ state = YAFFS_BLOCK_STATE_EMPTY; ++ dev->n_erased_blocks++; ++ } else { ++ /* this is the block being allocated */ ++ yaffs_trace(YAFFS_TRACE_SCAN, ++ " Allocating from %d %d", ++ blk, c); ++ state = YAFFS_BLOCK_STATE_ALLOCATING; ++ dev->alloc_block = blk; ++ dev->alloc_page = c; ++ dev->alloc_block_finder = blk; ++ ++ } ++ ++ dev->n_free_chunks += ++ (dev->param.chunks_per_block - c); ++ } else if (tags.chunk_id > 0) { ++ /* chunk_id > 0 so it is a data chunk... */ ++ unsigned int endpos; ++ ++ yaffs_set_chunk_bit(dev, blk, c); ++ bi->pages_in_use++; ++ ++ in = yaffs_find_or_create_by_number(dev, ++ tags.obj_id, ++ YAFFS_OBJECT_TYPE_FILE); ++ /* PutChunkIntoFile checks for a clash ++ * (two data chunks with the same chunk_id). ++ */ ++ ++ if (!in) ++ alloc_failed = 1; ++ ++ if (in) { ++ if (!yaffs_put_chunk_in_file ++ (in, tags.chunk_id, chunk, 1)) ++ alloc_failed = 1; ++ } ++ ++ endpos = ++ (tags.chunk_id - 1) * ++ dev->data_bytes_per_chunk + ++ tags.n_bytes; ++ if (in && ++ in->variant_type == ++ YAFFS_OBJECT_TYPE_FILE && ++ in->variant.file_variant.stored_size < ++ endpos) { ++ in->variant.file_variant.stored_size = ++ endpos; ++ if (!dev->param.use_header_file_size) { ++ in->variant. ++ file_variant.file_size = ++ in->variant. ++ file_variant.stored_size; ++ } ++ ++ } ++ } else { ++ /* chunk_id == 0, so it is an ObjectHeader. ++ * Make the object ++ */ ++ yaffs_set_chunk_bit(dev, blk, c); ++ bi->pages_in_use++; ++ ++ result = yaffs_rd_chunk_tags_nand(dev, chunk, ++ chunk_data, ++ NULL); ++ ++ oh = (struct yaffs_obj_hdr *)chunk_data; ++ ++ in = yaffs_find_by_number(dev, tags.obj_id); ++ if (in && in->variant_type != oh->type) { ++ /* This should not happen, but somehow ++ * Wev'e ended up with an obj_id that ++ * has been reused but not yet deleted, ++ * and worse still it has changed type. ++ * Delete the old object. ++ */ ++ ++ yaffs_del_obj(in); ++ in = NULL; ++ } ++ ++ in = yaffs_find_or_create_by_number(dev, ++ tags.obj_id, ++ oh->type); ++ ++ if (!in) ++ alloc_failed = 1; ++ ++ if (in && oh->shadows_obj > 0) { ++ ++ struct yaffs_shadow_fixer *fixer; ++ fixer = ++ kmalloc(sizeof ++ (struct yaffs_shadow_fixer), ++ GFP_NOFS); ++ if (fixer) { ++ fixer->next = shadow_fixers; ++ shadow_fixers = fixer; ++ fixer->obj_id = tags.obj_id; ++ fixer->shadowed_id = ++ oh->shadows_obj; ++ yaffs_trace(YAFFS_TRACE_SCAN, ++ " Shadow fixer: %d shadows %d", ++ fixer->obj_id, ++ fixer->shadowed_id); ++ ++ } ++ ++ } ++ ++ if (in && in->valid) { ++ /* We have already filled this one. ++ * We have a duplicate and need to ++ * resolve it. */ ++ ++ unsigned existing_serial = in->serial; ++ unsigned new_serial = ++ tags.serial_number; ++ ++ if (((existing_serial + 1) & 3) == ++ new_serial) { ++ /* Use new one - destroy the ++ * exisiting one */ ++ yaffs_chunk_del(dev, ++ in->hdr_chunk, ++ 1, __LINE__); ++ in->valid = 0; ++ } else { ++ /* Use existing - destroy ++ * this one. */ ++ yaffs_chunk_del(dev, chunk, 1, ++ __LINE__); ++ } ++ } ++ ++ if (in && !in->valid && ++ (tags.obj_id == YAFFS_OBJECTID_ROOT || ++ tags.obj_id == ++ YAFFS_OBJECTID_LOSTNFOUND)) { ++ /* We only load some info, don't fiddle ++ * with directory structure */ ++ in->valid = 1; ++ in->variant_type = oh->type; ++ ++ in->yst_mode = oh->yst_mode; ++ yaffs_load_attribs(in, oh); ++ in->hdr_chunk = chunk; ++ in->serial = tags.serial_number; ++ ++ } else if (in && !in->valid) { ++ /* we need to load this info */ ++ ++ in->valid = 1; ++ in->variant_type = oh->type; ++ ++ in->yst_mode = oh->yst_mode; ++ yaffs_load_attribs(in, oh); ++ in->hdr_chunk = chunk; ++ in->serial = tags.serial_number; ++ ++ yaffs_set_obj_name_from_oh(in, oh); ++ in->dirty = 0; ++ ++ /* directory stuff... ++ * hook up to parent ++ */ ++ ++ parent = ++ yaffs_find_or_create_by_number ++ (dev, oh->parent_obj_id, ++ YAFFS_OBJECT_TYPE_DIRECTORY); ++ if (!parent) ++ alloc_failed = 1; ++ if (parent && parent->variant_type == ++ YAFFS_OBJECT_TYPE_UNKNOWN) { ++ /* Set up as a directory */ ++ parent->variant_type = ++ YAFFS_OBJECT_TYPE_DIRECTORY; ++ INIT_LIST_HEAD(&parent-> ++ variant.dir_variant. ++ children); ++ } else if (!parent || ++ parent->variant_type != ++ YAFFS_OBJECT_TYPE_DIRECTORY) { ++ /* Hoosterman, a problem.... ++ * We're trying to use a ++ * non-directory as a directory ++ */ ++ ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." ++ ); ++ parent = dev->lost_n_found; ++ } ++ ++ yaffs_add_obj_to_dir(parent, in); ++ ++ switch (in->variant_type) { ++ case YAFFS_OBJECT_TYPE_UNKNOWN: ++ /* Todo got a problem */ ++ break; ++ case YAFFS_OBJECT_TYPE_FILE: ++ if (dev->param. ++ use_header_file_size) ++ in->variant. ++ file_variant.file_size ++ = yaffs_oh_to_size(dev, oh, 0); ++ break; ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ in->variant. ++ hardlink_variant.equiv_id = ++ oh->equiv_id; ++ list_add(&in->hard_links, ++ &hard_list); ++ break; ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ /* Do nothing */ ++ break; ++ case YAFFS_OBJECT_TYPE_SPECIAL: ++ /* Do nothing */ ++ break; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ in->variant.symlink_variant. ++ alias = ++ yaffs_clone_str(oh->alias); ++ if (!in->variant. ++ symlink_variant.alias) ++ alloc_failed = 1; ++ break; ++ } ++ } ++ } ++ } ++ ++ if (state == YAFFS_BLOCK_STATE_NEEDS_SCAN) { ++ /* If we got this far while scanning, ++ * then the block is fully allocated. */ ++ state = YAFFS_BLOCK_STATE_FULL; ++ } ++ ++ if (state == YAFFS_BLOCK_STATE_ALLOCATING) { ++ /* If the block was partially allocated then ++ * treat it as fully allocated. */ ++ state = YAFFS_BLOCK_STATE_FULL; ++ dev->alloc_block = -1; ++ } ++ ++ bi->block_state = state; ++ ++ /* Now let's see if it was dirty */ ++ if (bi->pages_in_use == 0 && ++ !bi->has_shrink_hdr && ++ bi->block_state == YAFFS_BLOCK_STATE_FULL) ++ yaffs_block_became_dirty(dev, blk); ++ } ++ ++ /* Ok, we've done all the scanning. ++ * Fix up the hard link chains. ++ * We should now have scanned all the objects, now it's time to add ++ * these hardlinks. ++ */ ++ ++ yaffs_link_fixup(dev, &hard_list); ++ ++ /* ++ * Fix up any shadowed objects. ++ * There should not be more than one of these. ++ */ ++ { ++ struct yaffs_shadow_fixer *fixer; ++ struct yaffs_obj *obj; ++ ++ while (shadow_fixers) { ++ fixer = shadow_fixers; ++ shadow_fixers = fixer->next; ++ /* Complete the rename transaction by deleting the ++ * shadowed object then setting the object header ++ to unshadowed. ++ */ ++ obj = yaffs_find_by_number(dev, fixer->shadowed_id); ++ if (obj) ++ yaffs_del_obj(obj); ++ ++ obj = yaffs_find_by_number(dev, fixer->obj_id); ++ ++ if (obj) ++ yaffs_update_oh(obj, NULL, 1, 0, 0, NULL); ++ ++ kfree(fixer); ++ } ++ } ++ ++ yaffs_release_temp_buffer(dev, chunk_data); ++ ++ if (alloc_failed) ++ return YAFFS_FAIL; ++ ++ yaffs_trace(YAFFS_TRACE_SCAN, "yaffs1_scan ends"); ++ ++ return YAFFS_OK; ++#endif ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_yaffs1.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_yaffs1.h.patch new file mode 100644 index 00000000..9dc74015 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_yaffs1.h.patch @@ -0,0 +1,25 @@ +diff -drupN a/fs/yaffs2/yaffs_yaffs1.h b/fs/yaffs2/yaffs_yaffs1.h +--- a/fs/yaffs2/yaffs_yaffs1.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_yaffs1.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,21 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_YAFFS1_H__ ++#define __YAFFS_YAFFS1_H__ ++ ++#include "yaffs_guts.h" ++int yaffs1_scan(struct yaffs_dev *dev); ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_yaffs2.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_yaffs2.c.patch new file mode 100644 index 00000000..9275d54f --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_yaffs2.c.patch @@ -0,0 +1,1717 @@ +diff -drupN a/fs/yaffs2/yaffs_yaffs2.c b/fs/yaffs2/yaffs_yaffs2.c +--- a/fs/yaffs2/yaffs_yaffs2.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_yaffs2.c 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,1713 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * 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. ++ */ ++ ++#include "yaffs_guts.h" ++#include "yaffs_trace.h" ++#include "yaffs_yaffs2.h" ++#include "yaffs_checkptrw.h" ++#include "yaffs_bitmap.h" ++#include "yaffs_nand.h" ++#include "yaffs_getblockinfo.h" ++#include "yaffs_verify.h" ++#include "yaffs_attribs.h" ++#include "yaffs_summary.h" ++#include "yaffs_endian.h" ++ ++/* ++ * Checkpoints are really no benefit on very small partitions. ++ * ++ * To save space on small partitions don't bother with checkpoints unless ++ * the partition is at least this big. ++ */ ++#define YAFFS_CHECKPOINT_MIN_BLOCKS 60 ++#define YAFFS_SMALL_HOLE_THRESHOLD 4 ++ ++/* ++ * Oldest Dirty Sequence Number handling. ++ */ ++ ++/* yaffs_calc_oldest_dirty_seq() ++ * yaffs2_find_oldest_dirty_seq() ++ * Calculate the oldest dirty sequence number if we don't know it. ++ */ ++void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev) ++{ ++ u32 i; ++ unsigned seq; ++ unsigned block_no = 0; ++ struct yaffs_block_info *b; ++ ++ if (!dev->param.is_yaffs2) ++ return; ++ ++ /* Find the oldest dirty sequence number. */ ++ seq = dev->seq_number + 1; ++ b = dev->block_info; ++ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { ++ if (b->block_state == YAFFS_BLOCK_STATE_FULL && ++ (u32)(b->pages_in_use - b->soft_del_pages) < ++ dev->param.chunks_per_block && ++ b->seq_number < seq) { ++ seq = b->seq_number; ++ block_no = i; ++ } ++ b++; ++ } ++ ++ if (block_no) { ++ dev->oldest_dirty_seq = seq; ++ dev->oldest_dirty_block = block_no; ++ } ++} ++ ++void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev) ++{ ++ if (!dev->param.is_yaffs2) ++ return; ++ ++ if (!dev->oldest_dirty_seq) ++ yaffs_calc_oldest_dirty_seq(dev); ++} ++ ++/* ++ * yaffs_clear_oldest_dirty_seq() ++ * Called when a block is erased or marked bad. (ie. when its seq_number ++ * becomes invalid). If the value matches the oldest then we clear ++ * dev->oldest_dirty_seq to force its recomputation. ++ */ ++void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev, ++ struct yaffs_block_info *bi) ++{ ++ ++ if (!dev->param.is_yaffs2) ++ return; ++ ++ if (!bi || bi->seq_number == dev->oldest_dirty_seq) { ++ dev->oldest_dirty_seq = 0; ++ dev->oldest_dirty_block = 0; ++ } ++} ++ ++/* ++ * yaffs2_update_oldest_dirty_seq() ++ * Update the oldest dirty sequence number whenever we dirty a block. ++ * Only do this if the oldest_dirty_seq is actually being tracked. ++ */ ++void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no, ++ struct yaffs_block_info *bi) ++{ ++ if (!dev->param.is_yaffs2) ++ return; ++ ++ if (dev->oldest_dirty_seq) { ++ if (dev->oldest_dirty_seq > bi->seq_number) { ++ dev->oldest_dirty_seq = bi->seq_number; ++ dev->oldest_dirty_block = block_no; ++ } ++ } ++} ++ ++int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi) ++{ ++ ++ if (!dev->param.is_yaffs2) ++ return 1; /* disqualification only applies to yaffs2. */ ++ ++ if (!bi->has_shrink_hdr) ++ return 1; /* can gc */ ++ ++ yaffs2_find_oldest_dirty_seq(dev); ++ ++ /* Can't do gc of this block if there are any blocks older than this ++ * one that have discarded pages. ++ */ ++ return (bi->seq_number <= dev->oldest_dirty_seq); ++} ++ ++/* ++ * yaffs2_find_refresh_block() ++ * periodically finds the oldest full block by sequence number for refreshing. ++ * Only for yaffs2. ++ */ ++u32 yaffs2_find_refresh_block(struct yaffs_dev *dev) ++{ ++ u32 b; ++ u32 oldest = 0; ++ u32 oldest_seq = 0; ++ struct yaffs_block_info *bi; ++ ++ if (!dev->param.is_yaffs2) ++ return oldest; ++ ++ /* ++ * If refresh period < 10 then refreshing is disabled. ++ */ ++ if (dev->param.refresh_period < 10) ++ return oldest; ++ ++ /* ++ * Fix broken values. ++ */ ++ if (dev->refresh_skip > dev->param.refresh_period) ++ dev->refresh_skip = dev->param.refresh_period; ++ ++ if (dev->refresh_skip > 0) ++ return oldest; ++ ++ /* ++ * Refresh skip is now zero. ++ * We'll do a refresh this time around.... ++ * Update the refresh skip and find the oldest block. ++ */ ++ dev->refresh_skip = dev->param.refresh_period; ++ dev->refresh_count++; ++ bi = dev->block_info; ++ for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) { ++ ++ if (bi->block_state == YAFFS_BLOCK_STATE_FULL) { ++ ++ if (oldest < 1 || bi->seq_number < oldest_seq) { ++ oldest = b; ++ oldest_seq = bi->seq_number; ++ } ++ } ++ bi++; ++ } ++ ++ if (oldest > 0) { ++ yaffs_trace(YAFFS_TRACE_GC, ++ "GC refresh count %d selected block %d with seq_number %d", ++ dev->refresh_count, oldest, oldest_seq); ++ } ++ ++ return oldest; ++} ++ ++int yaffs2_checkpt_required(struct yaffs_dev *dev) ++{ ++ int nblocks; ++ ++ if (!dev->param.is_yaffs2) ++ return 0; ++ ++ nblocks = dev->internal_end_block - dev->internal_start_block + 1; ++ ++ return !dev->param.skip_checkpt_wr && ++ !dev->read_only && (nblocks >= YAFFS_CHECKPOINT_MIN_BLOCKS); ++} ++ ++int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev) ++{ ++ int retval; ++ int n_bytes = 0; ++ int n_blocks; ++ int dev_blocks; ++ ++ if (!dev->param.is_yaffs2) ++ return 0; ++ ++ if (!dev->checkpoint_blocks_required && yaffs2_checkpt_required(dev)) { ++ /* Not a valid value so recalculate */ ++ dev_blocks = dev->param.end_block - dev->param.start_block + 1; ++ n_bytes += sizeof(struct yaffs_checkpt_validity); ++ n_bytes += sizeof(struct yaffs_checkpt_dev); ++ n_bytes += dev_blocks * sizeof(struct yaffs_block_info); ++ n_bytes += dev_blocks * dev->chunk_bit_stride; ++ n_bytes += ++ (sizeof(struct yaffs_checkpt_obj) + sizeof(u32)) * ++ dev->n_obj; ++ n_bytes += (dev->tnode_size + sizeof(u32)) * dev->n_tnodes; ++ n_bytes += sizeof(struct yaffs_checkpt_validity); ++ n_bytes += sizeof(u32); /* checksum */ ++ ++ /* Round up and add 2 blocks to allow for some bad blocks, ++ * so add 3 */ ++ ++ n_blocks = ++ (n_bytes / ++ (dev->data_bytes_per_chunk * ++ dev->param.chunks_per_block)) + 3; ++ ++ dev->checkpoint_blocks_required = n_blocks; ++ } ++ ++ retval = dev->checkpoint_blocks_required - dev->blocks_in_checkpt; ++ if (retval < 0) ++ retval = 0; ++ return retval; ++} ++ ++/*--------------------- Checkpointing --------------------*/ ++ ++static void yaffs2_do_endian_validity_marker(struct yaffs_dev *dev, ++ struct yaffs_checkpt_validity *v) ++{ ++ ++ if (!dev->swap_endian) ++ return; ++ v->struct_type = swap_s32(v->struct_type); ++ v->magic = swap_u32(v->magic); ++ v->version = swap_u32(v->version); ++ v->head = swap_u32(v->head); ++} ++ ++static int yaffs2_wr_checkpt_validity_marker(struct yaffs_dev *dev, int head) ++{ ++ struct yaffs_checkpt_validity cp; ++ ++ memset(&cp, 0, sizeof(cp)); ++ ++ cp.struct_type = sizeof(cp); ++ cp.magic = YAFFS_MAGIC; ++ cp.version = YAFFS_CHECKPOINT_VERSION; ++ cp.head = (head) ? 1 : 0; ++ ++ yaffs2_do_endian_validity_marker(dev, &cp); ++ ++ return (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)) ? 1 : 0; ++} ++ ++static int yaffs2_rd_checkpt_validity_marker(struct yaffs_dev *dev, int head) ++{ ++ struct yaffs_checkpt_validity cp; ++ int ok; ++ ++ ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp)); ++ yaffs2_do_endian_validity_marker(dev, &cp); ++ ++ if (ok) ++ ok = (cp.struct_type == sizeof(cp)) && ++ (cp.magic == YAFFS_MAGIC) && ++ (cp.version == YAFFS_CHECKPOINT_VERSION) && ++ (cp.head == ((head) ? 1 : 0)); ++ return ok ? 1 : 0; ++} ++ ++static void yaffs2_dev_to_checkpt_dev(struct yaffs_checkpt_dev *cp, ++ struct yaffs_dev *dev) ++{ ++ cp->struct_type = sizeof(*cp); ++ ++ cp->n_erased_blocks = dev->n_erased_blocks; ++ cp->alloc_block = dev->alloc_block; ++ cp->alloc_page = dev->alloc_page; ++ cp->n_free_chunks = dev->n_free_chunks; ++ ++ cp->n_deleted_files = dev->n_deleted_files; ++ cp->n_unlinked_files = dev->n_unlinked_files; ++ cp->n_bg_deletions = dev->n_bg_deletions; ++ cp->seq_number = dev->seq_number; ++ ++} ++ ++static void yaffs_checkpt_dev_to_dev(struct yaffs_dev *dev, ++ struct yaffs_checkpt_dev *cp) ++{ ++ dev->n_erased_blocks = cp->n_erased_blocks; ++ dev->alloc_block = cp->alloc_block; ++ dev->alloc_page = cp->alloc_page; ++ dev->n_free_chunks = cp->n_free_chunks; ++ ++ dev->n_deleted_files = cp->n_deleted_files; ++ dev->n_unlinked_files = cp->n_unlinked_files; ++ dev->n_bg_deletions = cp->n_bg_deletions; ++ dev->seq_number = cp->seq_number; ++} ++ ++static void yaffs2_do_endian_checkpt_dev(struct yaffs_dev *dev, ++ struct yaffs_checkpt_dev *cp) ++{ ++ if (!dev->swap_endian) ++ return; ++ cp->struct_type = swap_s32(cp->struct_type); ++ cp->n_erased_blocks = swap_s32(cp->n_erased_blocks); ++ cp->alloc_block = swap_s32(cp->alloc_block); ++ cp->alloc_page = swap_u32(cp->alloc_page); ++ cp->n_free_chunks = swap_s32(cp->n_free_chunks); ++ cp->n_deleted_files = swap_s32(cp->n_deleted_files); ++ cp->n_unlinked_files = swap_s32(cp->n_unlinked_files); ++ cp->n_bg_deletions = swap_s32(cp->n_bg_deletions); ++} ++ ++static int yaffs2_wr_checkpt_dev(struct yaffs_dev *dev) ++{ ++ struct yaffs_checkpt_dev cp; ++ u32 n_bytes; ++ u32 n_blocks = dev->internal_end_block - dev->internal_start_block + 1; ++ int ok; ++ u32 i; ++ union yaffs_block_info_union bu; ++ ++ /* Write device runtime values */ ++ yaffs2_dev_to_checkpt_dev(&cp, dev); ++ yaffs2_do_endian_checkpt_dev(dev, &cp); ++ ++ ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)); ++ if (!ok) ++ return 0; ++ ++ /* Write block info. */ ++ if (!dev->swap_endian) { ++ n_bytes = n_blocks * sizeof(struct yaffs_block_info); ++ ok = (yaffs2_checkpt_wr(dev, dev->block_info, n_bytes) == ++ (int)n_bytes); ++ } else { ++ /* ++ * Need to swap the endianisms. We can't do this in place ++ * since that would damage live data, ++ * so write one block info at a time using a copy. ++ */ ++ for (i = 0; i < n_blocks && ok; i++) { ++ bu.bi = dev->block_info[i]; ++ bu.as_u32[0] = swap_u32(bu.as_u32[0]); ++ bu.as_u32[1] = swap_u32(bu.as_u32[1]); ++ ok = (yaffs2_checkpt_wr(dev, &bu, sizeof(bu)) == sizeof(bu)); ++ } ++ } ++ ++ if (!ok) ++ return 0; ++ ++ /* ++ * Write chunk bits. Chunk bits are in bytes so ++ * no endian conversion is needed. ++ */ ++ n_bytes = n_blocks * dev->chunk_bit_stride; ++ ok = (yaffs2_checkpt_wr(dev, dev->chunk_bits, n_bytes) == ++ (int)n_bytes); ++ ++ return ok ? 1 : 0; ++} ++ ++static int yaffs2_rd_checkpt_dev(struct yaffs_dev *dev) ++{ ++ struct yaffs_checkpt_dev cp; ++ u32 n_bytes; ++ u32 n_blocks = ++ (dev->internal_end_block - dev->internal_start_block + 1); ++ int ok; ++ ++ ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp)); ++ if (!ok) ++ return 0; ++ yaffs2_do_endian_checkpt_dev(dev, &cp); ++ ++ if (cp.struct_type != sizeof(cp)) ++ return 0; ++ ++ yaffs_checkpt_dev_to_dev(dev, &cp); ++ ++ n_bytes = n_blocks * sizeof(struct yaffs_block_info); ++ ++ ok = (yaffs2_checkpt_rd(dev, dev->block_info, n_bytes) == ++ (int)n_bytes); ++ ++ if (!ok) ++ return 0; ++ ++ if (dev->swap_endian) { ++ /* The block info can just be handled as a list of u32s. */ ++ u32 *as_u32 = (u32 *) dev->block_info; ++ u32 n_u32s = n_bytes/sizeof(u32); ++ u32 i; ++ ++ for (i=0; i < n_u32s; i++) ++ as_u32[i] = swap_u32(as_u32[i]); ++ } ++ ++ n_bytes = n_blocks * dev->chunk_bit_stride; ++ ++ ok = (yaffs2_checkpt_rd(dev, dev->chunk_bits, n_bytes) == ++ (int)n_bytes); ++ ++ ++ return ok ? 1 : 0; ++} ++ ++ ++static void yaffs2_checkpt_obj_bit_assign(struct yaffs_checkpt_obj *cp, ++ int bit_offset, ++ int bit_width, ++ u32 value) ++{ ++ u32 and_mask; ++ ++ and_mask = ((1<bit_field &= ~and_mask; ++ cp->bit_field |= ((value << bit_offset) & and_mask); ++} ++ ++static u32 yaffs2_checkpt_obj_bit_get(struct yaffs_checkpt_obj *cp, ++ int bit_offset, ++ int bit_width) ++{ ++ u32 and_mask; ++ ++ and_mask = ((1<bit_field >> bit_offset) & and_mask; ++} ++ ++static void yaffs2_obj_checkpt_obj(struct yaffs_checkpt_obj *cp, ++ struct yaffs_obj *obj) ++{ ++ cp->obj_id = obj->obj_id; ++ cp->parent_id = (obj->parent) ? obj->parent->obj_id : 0; ++ cp->hdr_chunk = obj->hdr_chunk; ++ ++ yaffs2_checkpt_obj_bit_assign(cp, CHECKPOINT_VARIANT_BITS, obj->variant_type); ++ yaffs2_checkpt_obj_bit_assign(cp, CHECKPOINT_DELETED_BITS, obj->deleted); ++ yaffs2_checkpt_obj_bit_assign(cp, CHECKPOINT_SOFT_DEL_BITS, obj->soft_del); ++ yaffs2_checkpt_obj_bit_assign(cp, CHECKPOINT_UNLINKED_BITS, obj->unlinked); ++ yaffs2_checkpt_obj_bit_assign(cp, CHECKPOINT_FAKE_BITS, obj->fake); ++ yaffs2_checkpt_obj_bit_assign(cp, CHECKPOINT_RENAME_ALLOWED_BITS, obj->rename_allowed); ++ yaffs2_checkpt_obj_bit_assign(cp, CHECKPOINT_UNLINK_ALLOWED_BITS, obj->unlink_allowed); ++ yaffs2_checkpt_obj_bit_assign(cp, CHECKPOINT_SERIAL_BITS, obj->serial); ++ ++ cp->n_data_chunks = obj->n_data_chunks; ++ ++ if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) ++ cp->size_or_equiv_obj = obj->variant.file_variant.file_size; ++ else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) ++ cp->size_or_equiv_obj = obj->variant.hardlink_variant.equiv_id; ++} ++ ++static int yaffs2_checkpt_obj_to_obj(struct yaffs_obj *obj, ++ struct yaffs_checkpt_obj *cp) ++{ ++ struct yaffs_obj *parent; ++ u32 cp_variant_type = yaffs2_checkpt_obj_bit_get(cp, CHECKPOINT_VARIANT_BITS); ++ ++ if (obj->variant_type != cp_variant_type) { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "Checkpoint read object %d type %d chunk %d does not match existing object type %d", ++ cp->obj_id, cp_variant_type, cp->hdr_chunk, ++ obj->variant_type); ++ return 0; ++ } ++ ++ obj->obj_id = cp->obj_id; ++ ++ if (cp->parent_id) ++ parent = yaffs_find_or_create_by_number(obj->my_dev, ++ cp->parent_id, ++ YAFFS_OBJECT_TYPE_DIRECTORY); ++ else ++ parent = NULL; ++ ++ if (parent) { ++ if (parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "Checkpoint read object %d parent %d type %d chunk %d Parent type, %d, not directory", ++ cp->obj_id, cp->parent_id, ++ cp_variant_type, cp->hdr_chunk, ++ parent->variant_type); ++ return 0; ++ } ++ yaffs_add_obj_to_dir(parent, obj); ++ } ++ ++ obj->hdr_chunk = cp->hdr_chunk; ++ ++ obj->variant_type = yaffs2_checkpt_obj_bit_get(cp, CHECKPOINT_VARIANT_BITS); ++ obj->deleted = yaffs2_checkpt_obj_bit_get(cp, CHECKPOINT_DELETED_BITS); ++ obj->soft_del = yaffs2_checkpt_obj_bit_get(cp, CHECKPOINT_SOFT_DEL_BITS); ++ obj->unlinked = yaffs2_checkpt_obj_bit_get(cp, CHECKPOINT_UNLINKED_BITS); ++ obj->fake = yaffs2_checkpt_obj_bit_get(cp, CHECKPOINT_FAKE_BITS); ++ obj->rename_allowed = yaffs2_checkpt_obj_bit_get(cp, CHECKPOINT_RENAME_ALLOWED_BITS); ++ obj->unlink_allowed = yaffs2_checkpt_obj_bit_get(cp, CHECKPOINT_UNLINK_ALLOWED_BITS); ++ obj->serial = yaffs2_checkpt_obj_bit_get(cp, CHECKPOINT_SERIAL_BITS); ++ ++ obj->n_data_chunks = cp->n_data_chunks; ++ ++ if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) { ++ obj->variant.file_variant.file_size = cp->size_or_equiv_obj; ++ obj->variant.file_variant.stored_size = cp->size_or_equiv_obj; ++ } else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) { ++ obj->variant.hardlink_variant.equiv_id = cp->size_or_equiv_obj; ++ } ++ if (obj->hdr_chunk > 0) ++ obj->lazy_loaded = 1; ++ return 1; ++} ++ ++static void yaffs2_do_endian_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn) ++{ ++ int i; ++ u32 *as_u32 = (u32 *)tn; ++ int tnode_size_u32 = dev->tnode_size / sizeof(u32); ++ ++ if (!dev->swap_endian) ++ return; ++ /* Swap all the tnode data as u32s to fix endianisms. */ ++ for (i = 0; iswap_endian) ++ return tn; ++ ++ memcpy(dev->tn_swap_buffer, tn, dev->tnode_size); ++ tn = dev->tn_swap_buffer; ++ ++ yaffs2_do_endian_tnode(dev, tn); ++ ++ return tn; ++} ++ ++static int yaffs2_checkpt_tnode_worker(struct yaffs_obj *in, ++ struct yaffs_tnode *tn, u32 level, ++ int chunk_offset) ++{ ++ int i; ++ struct yaffs_dev *dev = in->my_dev; ++ int ok = 1; ++ u32 base_offset; ++ ++ if (!tn) ++ return 1; ++ ++ if (level > 0) { ++ for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) { ++ if (!tn->internal[i]) ++ continue; ++ ok = yaffs2_checkpt_tnode_worker(in, ++ tn->internal[i], ++ level - 1, ++ (chunk_offset << ++ YAFFS_TNODES_INTERNAL_BITS) + i); ++ } ++ return ok; ++ } ++ ++ /* Level 0 tnode */ ++ base_offset = chunk_offset << YAFFS_TNODES_LEVEL0_BITS; ++ yaffs_do_endian_u32(dev, &base_offset); ++ ++ ok = (yaffs2_checkpt_wr(dev, &base_offset, sizeof(base_offset)) == ++ sizeof(base_offset)); ++ if (ok) { ++ /* ++ * NB Can't do an in-place endian swizzle since that would ++ * damage current tnode data. ++ * If a tnode endian conversion is required we do a copy. ++ */ ++ tn = yaffs2_do_endian_tnode_copy(dev, tn); ++ ok = (yaffs2_checkpt_wr(dev, tn, dev->tnode_size) == ++ (int)dev->tnode_size); ++ } ++ return ok; ++} ++ ++static int yaffs2_wr_checkpt_tnodes(struct yaffs_obj *obj) ++{ ++ u32 end_marker = ~0; ++ int ok = 1; ++ ++ if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE) ++ return ok; ++ ++ ok = yaffs2_checkpt_tnode_worker(obj, ++ obj->variant.file_variant.top, ++ obj->variant.file_variant. ++ top_level, 0); ++ if (ok) ++ ok = (yaffs2_checkpt_wr(obj->my_dev, &end_marker, ++ sizeof(end_marker)) == sizeof(end_marker)); ++ ++ return ok ? 1 : 0; ++} ++ ++static int yaffs2_rd_checkpt_tnodes(struct yaffs_obj *obj) ++{ ++ u32 base_chunk; ++ int ok = 1; ++ struct yaffs_dev *dev = obj->my_dev; ++ struct yaffs_file_var *file_stuct_ptr = &obj->variant.file_variant; ++ struct yaffs_tnode *tn; ++ int nread = 0; ++ ++ ok = (yaffs2_checkpt_rd(dev, &base_chunk, sizeof(base_chunk)) == ++ sizeof(base_chunk)); ++ ++ yaffs_do_endian_u32(dev, &base_chunk); ++ ++ while (ok && (~base_chunk)) { ++ nread++; ++ /* Read level 0 tnode */ ++ ++ tn = yaffs_get_tnode(dev); ++ if (tn) { ++ ok = (yaffs2_checkpt_rd(dev, tn, dev->tnode_size) == ++ (int)dev->tnode_size); ++ yaffs2_do_endian_tnode(dev, tn); ++ } ++ else ++ ok = 0; ++ ++ if (tn && ok) ++ ok = yaffs_add_find_tnode_0(dev, ++ file_stuct_ptr, ++ base_chunk, tn) ? 1 : 0; ++ ++ if (ok) { ++ ok = (yaffs2_checkpt_rd ++ (dev, &base_chunk, ++ sizeof(base_chunk)) == sizeof(base_chunk)); ++ yaffs_do_endian_u32(dev, &base_chunk); ++ } ++ ++ } ++ ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "Checkpoint read tnodes %d records, last %d. ok %d", ++ nread, base_chunk, ok); ++ ++ return ok ? 1 : 0; ++} ++ ++ ++static void yaffs2_do_endian_checkpt_obj(struct yaffs_dev *dev, ++ struct yaffs_checkpt_obj *cp) ++{ ++ if (!dev->swap_endian) ++ return; ++ cp->struct_type = swap_s32(cp->struct_type); ++ cp->obj_id = swap_u32(cp->obj_id); ++ cp->parent_id = swap_u32(cp->parent_id); ++ cp->hdr_chunk = swap_s32(cp->hdr_chunk); ++ cp->bit_field = swap_u32(cp->bit_field); ++ cp->n_data_chunks = swap_s32(cp->n_data_chunks); ++ cp->size_or_equiv_obj = swap_loff_t(cp->size_or_equiv_obj); ++} ++ ++static int yaffs2_wr_checkpt_objs(struct yaffs_dev *dev) ++{ ++ struct yaffs_obj *obj; ++ struct yaffs_checkpt_obj cp; ++ int i; ++ int ok = 1; ++ struct list_head *lh; ++ u32 cp_variant_type; ++ ++ /* Iterate through the objects in each hash entry, ++ * dumping them to the checkpointing stream. ++ */ ++ ++ (void) cp_variant_type; ++ ++ for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) { ++ list_for_each(lh, &dev->obj_bucket[i].list) { ++ obj = list_entry(lh, struct yaffs_obj, hash_link); ++ if (!obj->defered_free) { ++ yaffs2_obj_checkpt_obj(&cp, obj); ++ cp.struct_type = sizeof(cp); ++ cp_variant_type = yaffs2_checkpt_obj_bit_get( ++ &cp, CHECKPOINT_VARIANT_BITS); ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "Checkpoint write object %d parent %d type %d chunk %d obj addr %p", ++ cp.obj_id, cp.parent_id, ++ cp_variant_type, cp.hdr_chunk, obj); ++ ++ yaffs2_do_endian_checkpt_obj (dev, &cp); ++ ok = (yaffs2_checkpt_wr(dev, &cp, ++ sizeof(cp)) == sizeof(cp)); ++ ++ if (ok && ++ obj->variant_type == ++ YAFFS_OBJECT_TYPE_FILE) ++ ok = yaffs2_wr_checkpt_tnodes(obj); ++ } ++ } ++ } ++ ++ /* Dump end of list */ ++ memset(&cp, 0xff, sizeof(struct yaffs_checkpt_obj)); ++ cp.struct_type = sizeof(cp); ++ yaffs2_do_endian_checkpt_obj (dev, &cp); ++ ++ if (ok) ++ ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)); ++ ++ return ok ? 1 : 0; ++} ++ ++static int yaffs2_rd_checkpt_objs(struct yaffs_dev *dev) ++{ ++ struct yaffs_obj *obj; ++ struct yaffs_checkpt_obj cp; ++ int ok = 1; ++ int done = 0; ++ u32 cp_variant_type; ++ LIST_HEAD(hard_list); ++ ++ ++ while (ok && !done) { ++ ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp)); ++ yaffs2_do_endian_checkpt_obj (dev, &cp); ++ ++ if (cp.struct_type != sizeof(cp)) { ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "struct size %d instead of %d ok %d", ++ cp.struct_type, (int)sizeof(cp), ok); ++ ok = 0; ++ } ++ ++ cp_variant_type = yaffs2_checkpt_obj_bit_get( ++ &cp, CHECKPOINT_VARIANT_BITS); ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "Checkpoint read object %d parent %d type %d chunk %d ", ++ cp.obj_id, cp.parent_id, cp_variant_type, ++ cp.hdr_chunk); ++ ++ if (ok && cp.obj_id == (u32)(~0)) { ++ done = 1; ++ } else if (ok) { ++ obj = ++ yaffs_find_or_create_by_number(dev, cp.obj_id, ++ cp_variant_type); ++ if (obj) { ++ ok = yaffs2_checkpt_obj_to_obj(obj, &cp); ++ if (!ok) ++ break; ++ if (obj->variant_type == ++ YAFFS_OBJECT_TYPE_FILE) { ++ ok = yaffs2_rd_checkpt_tnodes(obj); ++ } else if (obj->variant_type == ++ YAFFS_OBJECT_TYPE_HARDLINK) { ++ list_add(&obj->hard_links, &hard_list); ++ } ++ } else { ++ ok = 0; ++ } ++ } ++ } ++ ++ if (ok) ++ yaffs_link_fixup(dev, &hard_list); ++ ++ return ok ? 1 : 0; ++} ++ ++static int yaffs2_wr_checkpt_sum(struct yaffs_dev *dev) ++{ ++ u32 checkpt_sum; ++ int ok; ++ ++ yaffs2_get_checkpt_sum(dev, &checkpt_sum); ++ ++ yaffs_do_endian_u32(dev, &checkpt_sum); ++ ++ ok = (yaffs2_checkpt_wr(dev, &checkpt_sum, sizeof(checkpt_sum)) == ++ sizeof(checkpt_sum)); ++ ++ if (!ok) ++ return 0; ++ ++ return 1; ++} ++ ++static int yaffs2_rd_checkpt_sum(struct yaffs_dev *dev) ++{ ++ u32 checkpt_sum0; ++ u32 checkpt_sum1; ++ int ok; ++ ++ yaffs2_get_checkpt_sum(dev, &checkpt_sum0); ++ ++ ok = (yaffs2_checkpt_rd(dev, &checkpt_sum1, sizeof(checkpt_sum1)) == ++ sizeof(checkpt_sum1)); ++ ++ if (!ok) ++ return 0; ++ yaffs_do_endian_u32(dev, &checkpt_sum1); ++ ++ if (checkpt_sum0 != checkpt_sum1) ++ return 0; ++ ++ return 1; ++} ++ ++static int yaffs2_wr_checkpt_data(struct yaffs_dev *dev) ++{ ++ int ok = 1; ++ ++ if (!yaffs2_checkpt_required(dev)) { ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "skipping checkpoint write"); ++ ok = 0; ++ } ++ ++ if (ok) ++ ok = yaffs2_checkpt_open(dev, 1); ++ ++ if (ok) { ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "write checkpoint validity"); ++ ok = yaffs2_wr_checkpt_validity_marker(dev, 1); ++ } ++ if (ok) { ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "write checkpoint device"); ++ ok = yaffs2_wr_checkpt_dev(dev); ++ } ++ if (ok) { ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "write checkpoint objects"); ++ ok = yaffs2_wr_checkpt_objs(dev); ++ } ++ if (ok) { ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "write checkpoint validity"); ++ ok = yaffs2_wr_checkpt_validity_marker(dev, 0); ++ } ++ ++ if (ok) ++ ok = yaffs2_wr_checkpt_sum(dev); ++ ++ if (!yaffs_checkpt_close(dev)) ++ ok = 0; ++ ++ if (ok) ++ dev->is_checkpointed = 1; ++ else ++ dev->is_checkpointed = 0; ++ ++ return dev->is_checkpointed; ++} ++ ++static int yaffs2_rd_checkpt_data(struct yaffs_dev *dev) ++{ ++ int ok = 1; ++ ++ if (!dev->param.is_yaffs2) ++ ok = 0; ++ ++ if (ok && dev->param.skip_checkpt_rd) { ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "skipping checkpoint read"); ++ ok = 0; ++ } ++ ++ if (ok) ++ ok = yaffs2_checkpt_open(dev, 0); /* open for read */ ++ ++ if (ok) { ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "read checkpoint validity"); ++ ok = yaffs2_rd_checkpt_validity_marker(dev, 1); ++ } ++ if (ok) { ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "read checkpoint device"); ++ ok = yaffs2_rd_checkpt_dev(dev); ++ } ++ if (ok) { ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "read checkpoint objects"); ++ ok = yaffs2_rd_checkpt_objs(dev); ++ } ++ if (ok) { ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "read checkpoint validity"); ++ ok = yaffs2_rd_checkpt_validity_marker(dev, 0); ++ } ++ ++ if (ok) { ++ ok = yaffs2_rd_checkpt_sum(dev); ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "read checkpoint checksum %d", ok); ++ } ++ ++ if (!yaffs_checkpt_close(dev)) ++ ok = 0; ++ ++ if (ok) ++ dev->is_checkpointed = 1; ++ else ++ dev->is_checkpointed = 0; ++ ++ return ok ? 1 : 0; ++} ++ ++void yaffs2_checkpt_invalidate(struct yaffs_dev *dev) ++{ ++ if (dev->is_checkpointed || dev->blocks_in_checkpt > 0) { ++ dev->is_checkpointed = 0; ++ yaffs2_checkpt_invalidate_stream(dev); ++ } ++ if (dev->param.sb_dirty_fn) ++ dev->param.sb_dirty_fn(dev); ++} ++ ++int yaffs_checkpoint_save(struct yaffs_dev *dev) ++{ ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "save entry: is_checkpointed %d", ++ dev->is_checkpointed); ++ ++ yaffs_verify_objects(dev); ++ yaffs_verify_blocks(dev); ++ yaffs_verify_free_chunks(dev); ++ ++ if (!dev->is_checkpointed) { ++ yaffs2_checkpt_invalidate(dev); ++ yaffs2_wr_checkpt_data(dev); ++ } ++ ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT | YAFFS_TRACE_MOUNT, ++ "save exit: is_checkpointed %d", ++ dev->is_checkpointed); ++ ++ return dev->is_checkpointed; ++} ++ ++int yaffs2_checkpt_restore(struct yaffs_dev *dev) ++{ ++ int retval; ++ ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "restore entry: is_checkpointed %d", ++ dev->is_checkpointed); ++ ++ retval = yaffs2_rd_checkpt_data(dev); ++ ++ if (dev->is_checkpointed) { ++ yaffs_verify_objects(dev); ++ yaffs_verify_blocks(dev); ++ yaffs_verify_free_chunks(dev); ++ } ++ ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "restore exit: is_checkpointed %d", ++ dev->is_checkpointed); ++ ++ return retval; ++} ++ ++/* End of checkpointing */ ++ ++/* Hole handling logic for truncate past end of file */ ++ ++int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size) ++{ ++ /* if new_size > old_file_size. ++ * We're going to be writing a hole. ++ * If the hole is small then write zeros otherwise write a start ++ * of hole marker. ++ */ ++ loff_t old_file_size; ++ loff_t increase; ++ int small_hole; ++ int result = YAFFS_OK; ++ struct yaffs_dev *dev = NULL; ++ u8 *local_buffer = NULL; ++ int small_increase_ok = 0; ++ ++ if (!obj) ++ return YAFFS_FAIL; ++ ++ if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE) ++ return YAFFS_FAIL; ++ ++ dev = obj->my_dev; ++ ++ /* Bail out if not yaffs2 mode */ ++ if (!dev->param.is_yaffs2) ++ return YAFFS_OK; ++ ++ old_file_size = obj->variant.file_variant.file_size; ++ ++ if (new_size <= old_file_size) ++ return YAFFS_OK; ++ ++ increase = new_size - old_file_size; ++ ++ if (increase < YAFFS_SMALL_HOLE_THRESHOLD * dev->data_bytes_per_chunk && ++ yaffs_check_alloc_available(dev, YAFFS_SMALL_HOLE_THRESHOLD + 1)) ++ small_hole = 1; ++ else ++ small_hole = 0; ++ ++ if (small_hole) ++ local_buffer = yaffs_get_temp_buffer(dev); ++ ++ if (local_buffer) { ++ /* fill hole with zero bytes */ ++ loff_t pos = old_file_size; ++ int this_write; ++ int written; ++ memset(local_buffer, 0, dev->data_bytes_per_chunk); ++ small_increase_ok = 1; ++ ++ while (increase > 0 && small_increase_ok) { ++ this_write = increase; ++ if (this_write > (int)dev->data_bytes_per_chunk) ++ this_write = dev->data_bytes_per_chunk; ++ written = ++ yaffs_do_file_wr(obj, local_buffer, pos, this_write, ++ 0); ++ if (written == this_write) { ++ pos += this_write; ++ increase -= this_write; ++ } else { ++ small_increase_ok = 0; ++ } ++ } ++ ++ yaffs_release_temp_buffer(dev, local_buffer); ++ ++ /* If out of space then reverse any chunks we've added */ ++ if (!small_increase_ok) ++ yaffs_resize_file_down(obj, old_file_size); ++ } ++ ++ if (!small_increase_ok && ++ obj->parent && ++ obj->parent->obj_id != YAFFS_OBJECTID_UNLINKED && ++ obj->parent->obj_id != YAFFS_OBJECTID_DELETED) { ++ /* Write a hole start header with the old file size */ ++ yaffs_update_oh(obj, NULL, 0, 1, 0, NULL); ++ } ++ ++ return result; ++} ++ ++/* Yaffs2 scanning */ ++ ++struct yaffs_block_index { ++ int seq; ++ int block; ++}; ++ ++static int yaffs2_ybicmp(const void *a, const void *b) ++{ ++ int aseq = ((struct yaffs_block_index *)a)->seq; ++ int bseq = ((struct yaffs_block_index *)b)->seq; ++ int ablock = ((struct yaffs_block_index *)a)->block; ++ int bblock = ((struct yaffs_block_index *)b)->block; ++ ++ if (aseq == bseq) ++ return ablock - bblock; ++ ++ return aseq - bseq; ++} ++ ++static inline int yaffs2_scan_chunk(struct yaffs_dev *dev, ++ struct yaffs_block_info *bi, ++ int blk, int chunk_in_block, ++ int *found_chunks, ++ u8 *chunk_data, ++ struct list_head *hard_list, ++ int summary_available) ++{ ++ struct yaffs_obj_hdr *oh; ++ struct yaffs_obj *in; ++ struct yaffs_obj *parent; ++ int equiv_id; ++ loff_t file_size; ++ int is_shrink; ++ int is_unlinked; ++ struct yaffs_ext_tags tags; ++ int result; ++ int alloc_failed = 0; ++ int chunk = blk * dev->param.chunks_per_block + chunk_in_block; ++ struct yaffs_file_var *file_var; ++ struct yaffs_hardlink_var *hl_var; ++ struct yaffs_symlink_var *sl_var; ++ ++ if (summary_available) { ++ result = yaffs_summary_fetch(dev, &tags, chunk_in_block); ++ tags.seq_number = bi->seq_number; ++ } ++ ++ if (!summary_available || tags.obj_id == 0) { ++ result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL, &tags); ++ dev->tags_used++; ++ } else { ++ dev->summary_used++; ++ } ++ ++ if (result == YAFFS_FAIL) ++ yaffs_trace(YAFFS_TRACE_SCAN, ++ "Could not get tags for chunk %d\n", chunk); ++ /* Let's have a good look at this chunk... */ ++ ++ if (!tags.chunk_used) { ++ /* An unassigned chunk in the block. ++ * If there are used chunks after this one, then ++ * it is a chunk that was skipped due to failing ++ * the erased check. Just skip it so that it can ++ * be deleted. ++ * But, more typically, We get here when this is ++ * an unallocated chunk and his means that ++ * either the block is empty or this is the one ++ * being allocated from ++ */ ++ ++ if (*found_chunks) { ++ /* This is a chunk that was skipped due ++ * to failing the erased check */ ++ } else if (chunk_in_block == 0) { ++ /* We're looking at the first chunk in ++ * the block so the block is unused */ ++ bi->block_state = YAFFS_BLOCK_STATE_EMPTY; ++ dev->n_erased_blocks++; ++ } else { ++ if (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN || ++ bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING) { ++ if (dev->seq_number == bi->seq_number) { ++ /* Allocating from this block*/ ++ yaffs_trace(YAFFS_TRACE_SCAN, ++ " Allocating from %d %d", ++ blk, chunk_in_block); ++ ++ bi->block_state = ++ YAFFS_BLOCK_STATE_ALLOCATING; ++ dev->alloc_block = blk; ++ dev->alloc_page = chunk_in_block; ++ dev->alloc_block_finder = blk; ++ } else { ++ /* This is a partially written block ++ * that is not the current ++ * allocation block. ++ */ ++ yaffs_trace(YAFFS_TRACE_SCAN, ++ "Partially written block %d detected. gc will fix this.", ++ blk); ++ } ++ } ++ } ++ ++ dev->n_free_chunks++; ++ ++ } else if (tags.ecc_result == ++ YAFFS_ECC_RESULT_UNFIXED) { ++ yaffs_trace(YAFFS_TRACE_SCAN, ++ " Unfixed ECC in chunk(%d:%d), chunk ignored", ++ blk, chunk_in_block); ++ dev->n_free_chunks++; ++ } else if (tags.obj_id > YAFFS_MAX_OBJECT_ID || ++ tags.chunk_id > YAFFS_MAX_CHUNK_ID || ++ tags.obj_id == YAFFS_OBJECTID_SUMMARY || ++ (tags.chunk_id > 0 && ++ tags.n_bytes > dev->data_bytes_per_chunk) || ++ tags.seq_number != bi->seq_number) { ++ yaffs_trace(YAFFS_TRACE_SCAN, ++ "Chunk (%d:%d) with bad tags:obj = %d, chunk_id = %d, n_bytes = %d, ignored", ++ blk, chunk_in_block, tags.obj_id, ++ tags.chunk_id, tags.n_bytes); ++ dev->n_free_chunks++; ++ } else if (tags.chunk_id > 0) { ++ /* chunk_id > 0 so it is a data chunk... */ ++ loff_t endpos; ++ loff_t chunk_base = (tags.chunk_id - 1) * ++ dev->data_bytes_per_chunk; ++ ++ *found_chunks = 1; ++ ++ yaffs_set_chunk_bit(dev, blk, chunk_in_block); ++ bi->pages_in_use++; ++ ++ in = yaffs_find_or_create_by_number(dev, ++ tags.obj_id, ++ YAFFS_OBJECT_TYPE_FILE); ++ if (!in) ++ /* Out of memory */ ++ alloc_failed = 1; ++ ++ if (in && ++ in->variant_type == YAFFS_OBJECT_TYPE_FILE && ++ chunk_base < in->variant.file_variant.shrink_size) { ++ /* This has not been invalidated by ++ * a resize */ ++ if (!yaffs_put_chunk_in_file(in, tags.chunk_id, ++ chunk, -1)) ++ alloc_failed = 1; ++ ++ /* File size is calculated by looking at ++ * the data chunks if we have not ++ * seen an object header yet. ++ * Stop this practice once we find an ++ * object header. ++ */ ++ endpos = chunk_base + tags.n_bytes; ++ ++ if (!in->valid && ++ in->variant.file_variant.stored_size < endpos) { ++ in->variant.file_variant. ++ stored_size = endpos; ++ in->variant.file_variant. ++ file_size = endpos; ++ } ++ } else if (in) { ++ /* This chunk has been invalidated by a ++ * resize, or a past file deletion ++ * so delete the chunk*/ ++ yaffs_chunk_del(dev, chunk, 1, __LINE__); ++ } ++ } else { ++ /* chunk_id == 0, so it is an ObjectHeader. ++ * Thus, we read in the object header and make ++ * the object ++ */ ++ *found_chunks = 1; ++ ++ yaffs_set_chunk_bit(dev, blk, chunk_in_block); ++ bi->pages_in_use++; ++ ++ oh = NULL; ++ in = NULL; ++ ++ if (tags.extra_available) { ++ in = yaffs_find_or_create_by_number(dev, ++ tags.obj_id, ++ tags.extra_obj_type); ++ if (!in) ++ alloc_failed = 1; ++ } ++ ++ if (!in || ++ (!in->valid && dev->param.disable_lazy_load) || ++ tags.extra_shadows || ++ (!in->valid && (tags.obj_id == YAFFS_OBJECTID_ROOT || ++ tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND))) { ++ ++ /* If we don't have valid info then we ++ * need to read the chunk ++ * TODO In future we can probably defer ++ * reading the chunk and living with ++ * invalid data until needed. ++ */ ++ ++ result = yaffs_rd_chunk_tags_nand(dev, ++ chunk, ++ chunk_data, ++ NULL); ++ ++ oh = (struct yaffs_obj_hdr *)chunk_data; ++ ++ yaffs_do_endian_oh(dev, oh); ++ ++ if (dev->param.inband_tags) { ++ /* Fix up the header if they got ++ * corrupted by inband tags */ ++ oh->shadows_obj = ++ oh->inband_shadowed_obj_id; ++ oh->is_shrink = ++ oh->inband_is_shrink; ++ } ++ ++ if (!in) { ++ in = yaffs_find_or_create_by_number(dev, ++ tags.obj_id, oh->type); ++ if (!in) ++ alloc_failed = 1; ++ } ++ } ++ ++ if (!in) { ++ /* TODO Hoosterman we have a problem! */ ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "yaffs tragedy: Could not make object for object %d at chunk %d during scan", ++ tags.obj_id, chunk); ++ return YAFFS_FAIL; ++ } ++ ++ if (in->valid) { ++ /* We have already filled this one. ++ * We have a duplicate that will be ++ * discarded, but we first have to suck ++ * out resize info if it is a file. ++ */ ++ if ((in->variant_type == YAFFS_OBJECT_TYPE_FILE) && ++ ((oh && oh->type == YAFFS_OBJECT_TYPE_FILE) || ++ (tags.extra_available && ++ tags.extra_obj_type == YAFFS_OBJECT_TYPE_FILE) ++ )) { ++ loff_t this_size = (oh) ? ++ yaffs_oh_to_size(dev, oh, 0) : ++ tags.extra_file_size; ++ u32 parent_obj_id = (oh) ? ++ (u32)oh->parent_obj_id : ++ tags.extra_parent_id; ++ ++ is_shrink = (oh) ? ++ oh->is_shrink : ++ tags.extra_is_shrink; ++ ++ /* If it is deleted (unlinked ++ * at start also means deleted) ++ * we treat the file size as ++ * being zeroed at this point. ++ */ ++ if (parent_obj_id == YAFFS_OBJECTID_DELETED || ++ parent_obj_id == YAFFS_OBJECTID_UNLINKED) { ++ this_size = 0; ++ is_shrink = 1; ++ } ++ ++ if (is_shrink && ++ in->variant.file_variant.shrink_size > ++ this_size) ++ in->variant.file_variant.shrink_size = ++ this_size; ++ ++ if (is_shrink) ++ bi->has_shrink_hdr = 1; ++ } ++ /* Use existing - destroy this one. */ ++ yaffs_chunk_del(dev, chunk, 1, __LINE__); ++ } ++ ++ if (!in->valid && in->variant_type != ++ (oh ? oh->type : tags.extra_obj_type)) { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "yaffs tragedy: Bad type, %d != %d, for object %d at chunk %d during scan", ++ oh ? oh->type : tags.extra_obj_type, ++ in->variant_type, tags.obj_id, ++ chunk); ++ in = yaffs_retype_obj(in, oh ? oh->type : tags.extra_obj_type); ++ } ++ ++ if (!in->valid && ++ (tags.obj_id == YAFFS_OBJECTID_ROOT || ++ tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND)) { ++ /* We only load some info, don't fiddle ++ * with directory structure */ ++ in->valid = 1; ++ ++ if (oh) { ++ in->yst_mode = oh->yst_mode; ++ yaffs_load_attribs(in, oh); ++ in->lazy_loaded = 0; ++ } else { ++ in->lazy_loaded = 1; ++ } ++ in->hdr_chunk = chunk; ++ ++ } else if (!in->valid) { ++ /* we need to load this info */ ++ in->valid = 1; ++ in->hdr_chunk = chunk; ++ if (oh) { ++ in->variant_type = oh->type; ++ in->yst_mode = oh->yst_mode; ++ yaffs_load_attribs(in, oh); ++ ++ if (oh->shadows_obj > 0) ++ yaffs_handle_shadowed_obj(dev, ++ oh->shadows_obj, 1); ++ ++ yaffs_set_obj_name_from_oh(in, oh); ++ parent = yaffs_find_or_create_by_number(dev, ++ oh->parent_obj_id, ++ YAFFS_OBJECT_TYPE_DIRECTORY); ++ file_size = yaffs_oh_to_size(dev, oh, 0); ++ is_shrink = oh->is_shrink; ++ equiv_id = oh->equiv_id; ++ } else { ++ in->variant_type = tags.extra_obj_type; ++ parent = yaffs_find_or_create_by_number(dev, ++ tags.extra_parent_id, ++ YAFFS_OBJECT_TYPE_DIRECTORY); ++ file_size = tags.extra_file_size; ++ is_shrink = tags.extra_is_shrink; ++ equiv_id = tags.extra_equiv_id; ++ in->lazy_loaded = 1; ++ } ++ in->dirty = 0; ++ ++ if (!parent) ++ alloc_failed = 1; ++ ++ /* directory stuff... ++ * hook up to parent ++ */ ++ ++ if (parent && ++ parent->variant_type == YAFFS_OBJECT_TYPE_UNKNOWN) { ++ /* Set up as a directory */ ++ parent->variant_type = ++ YAFFS_OBJECT_TYPE_DIRECTORY; ++ INIT_LIST_HEAD(&parent-> ++ variant.dir_variant.children); ++ } else if (!parent || ++ parent->variant_type != ++ YAFFS_OBJECT_TYPE_DIRECTORY) { ++ /* Hoosterman, another problem.... ++ * Trying to use a non-directory as a directory ++ */ ++ ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." ++ ); ++ parent = dev->lost_n_found; ++ } ++ yaffs_add_obj_to_dir(parent, in); ++ ++ is_unlinked = (parent == dev->del_dir) || ++ (parent == dev->unlinked_dir); ++ ++ if (is_shrink) ++ /* Mark the block */ ++ bi->has_shrink_hdr = 1; ++ ++ /* Note re hardlinks. ++ * Since we might scan a hardlink before its equivalent ++ * object is scanned we put them all in a list. ++ * After scanning is complete, we should have all the ++ * objects, so we run through this list and fix up all ++ * the chains. ++ */ ++ ++ switch (in->variant_type) { ++ case YAFFS_OBJECT_TYPE_UNKNOWN: ++ /* Todo got a problem */ ++ break; ++ case YAFFS_OBJECT_TYPE_FILE: ++ file_var = &in->variant.file_variant; ++ if (file_var->stored_size < file_size) { ++ /* This covers the case where the file ++ * size is greater than the data held. ++ * This will happen if the file is ++ * resized to be larger than its ++ * current data extents. ++ */ ++ file_var->file_size = file_size; ++ file_var->stored_size = file_size; ++ } ++ ++ if (file_var->shrink_size > file_size) ++ file_var->shrink_size = file_size; ++ ++ break; ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ hl_var = &in->variant.hardlink_variant; ++ if (!is_unlinked) { ++ hl_var->equiv_id = equiv_id; ++ list_add(&in->hard_links, hard_list); ++ } ++ break; ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ /* Do nothing */ ++ break; ++ case YAFFS_OBJECT_TYPE_SPECIAL: ++ /* Do nothing */ ++ break; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ sl_var = &in->variant.symlink_variant; ++ if (oh) { ++ sl_var->alias = ++ yaffs_clone_str(oh->alias); ++ if (!sl_var->alias) ++ alloc_failed = 1; ++ } ++ break; ++ } ++ } ++ } ++ return alloc_failed ? YAFFS_FAIL : YAFFS_OK; ++} ++ ++int yaffs2_scan_backwards(struct yaffs_dev *dev) ++{ ++ u32 blk; ++ int block_iter; ++ int start_iter; ++ int end_iter; ++ int n_to_scan = 0; ++ enum yaffs_block_state state; ++ int c; ++ LIST_HEAD(hard_list); ++ struct yaffs_block_info *bi; ++ u32 seq_number; ++ int n_blocks = dev->internal_end_block - dev->internal_start_block + 1; ++ u8 *chunk_data; ++ int found_chunks; ++ int alloc_failed = 0; ++ struct yaffs_block_index *block_index = NULL; ++ int alt_block_index = 0; ++ int summary_available; ++ ++ yaffs_trace(YAFFS_TRACE_SCAN, ++ "yaffs2_scan_backwards starts intstartblk %d intendblk %d...", ++ dev->internal_start_block, dev->internal_end_block); ++ ++ dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER; ++ ++ block_index = ++ kmalloc(n_blocks * sizeof(struct yaffs_block_index), GFP_NOFS); ++ ++ if (!block_index) { ++ block_index = ++ vmalloc(n_blocks * sizeof(struct yaffs_block_index)); ++ alt_block_index = 1; ++ } ++ ++ if (!block_index) { ++ yaffs_trace(YAFFS_TRACE_SCAN, ++ "yaffs2_scan_backwards() could not allocate block index!" ++ ); ++ return YAFFS_FAIL; ++ } ++ ++ dev->blocks_in_checkpt = 0; ++ ++ chunk_data = yaffs_get_temp_buffer(dev); ++ ++ /* Scan all the blocks to determine their state */ ++ bi = dev->block_info; ++ for (blk = dev->internal_start_block; blk <= dev->internal_end_block; ++ blk++) { ++ yaffs_clear_chunk_bits(dev, blk); ++ bi->pages_in_use = 0; ++ bi->soft_del_pages = 0; ++ ++ yaffs_query_init_block_state(dev, blk, &state, &seq_number); ++ ++ bi->block_state = state; ++ bi->seq_number = seq_number; ++ ++ if (bi->seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA) ++ bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT; ++ if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK) ++ bi->block_state = YAFFS_BLOCK_STATE_DEAD; ++ ++ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, ++ "Block scanning block %d state %d seq %d", ++ blk, bi->block_state, seq_number); ++ ++ if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) { ++ dev->blocks_in_checkpt++; ++ ++ } else if (bi->block_state == YAFFS_BLOCK_STATE_DEAD) { ++ yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, ++ "block %d is bad", blk); ++ } else if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) { ++ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty "); ++ dev->n_erased_blocks++; ++ dev->n_free_chunks += dev->param.chunks_per_block; ++ } else if (bi->block_state == ++ YAFFS_BLOCK_STATE_NEEDS_SCAN) { ++ /* Determine the highest sequence number */ ++ if (seq_number >= YAFFS_LOWEST_SEQUENCE_NUMBER && ++ seq_number < YAFFS_HIGHEST_SEQUENCE_NUMBER) { ++ block_index[n_to_scan].seq = seq_number; ++ block_index[n_to_scan].block = blk; ++ n_to_scan++; ++ if (seq_number >= dev->seq_number) ++ dev->seq_number = seq_number; ++ } else { ++ /* TODO: Nasty sequence number! */ ++ yaffs_trace(YAFFS_TRACE_SCAN, ++ "Block scanning block %d has bad sequence number %d", ++ blk, seq_number); ++ } ++ } ++ bi++; ++ } ++ ++ yaffs_trace(YAFFS_TRACE_ALWAYS, "%d blocks to be sorted...", n_to_scan); ++ ++ cond_resched(); ++ ++ /* Sort the blocks by sequence number */ ++ sort(block_index, n_to_scan, sizeof(struct yaffs_block_index), ++ yaffs2_ybicmp, NULL); ++ ++ cond_resched(); ++ ++ yaffs_trace(YAFFS_TRACE_SCAN, "...done"); ++ ++ /* Now scan the blocks looking at the data. */ ++ start_iter = 0; ++ end_iter = n_to_scan - 1; ++ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "%d blocks to scan", n_to_scan); ++ ++ /* For each block.... backwards */ ++ for (block_iter = end_iter; ++ !alloc_failed && block_iter >= start_iter; ++ block_iter--) { ++ /* Cooperative multitasking! This loop can run for so ++ long that watchdog timers expire. */ ++ cond_resched(); ++ ++ /* get the block to scan in the correct order */ ++ blk = block_index[block_iter].block; ++ bi = yaffs_get_block_info(dev, blk); ++ ++ summary_available = yaffs_summary_read(dev, dev->sum_tags, blk); ++ ++ /* For each chunk in each block that needs scanning.... */ ++ found_chunks = 0; ++ if (summary_available) ++ c = dev->chunks_per_summary - 1; ++ else ++ c = dev->param.chunks_per_block - 1; ++ ++ for (/* c is already initialised */; ++ !alloc_failed && c >= 0 && ++ (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN || ++ bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING); ++ c--) { ++ /* Scan backwards... ++ * Read the tags and decide what to do ++ */ ++ if (yaffs2_scan_chunk(dev, bi, blk, c, ++ &found_chunks, chunk_data, ++ &hard_list, summary_available) == ++ YAFFS_FAIL) ++ alloc_failed = 1; ++ } ++ ++ if (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN) { ++ /* If we got this far while scanning, then the block ++ * is fully allocated. */ ++ bi->block_state = YAFFS_BLOCK_STATE_FULL; ++ } ++ ++ /* Now let's see if it was dirty */ ++ if (bi->pages_in_use == 0 && ++ !bi->has_shrink_hdr && ++ bi->block_state == YAFFS_BLOCK_STATE_FULL) { ++ yaffs_block_became_dirty(dev, blk); ++ } ++ } ++ ++ yaffs_skip_rest_of_block(dev); ++ ++ if (alt_block_index) ++ vfree(block_index); ++ else ++ kfree(block_index); ++ ++ /* Ok, we've done all the scanning. ++ * Fix up the hard link chains. ++ * We have scanned all the objects, now it's time to add these ++ * hardlinks. ++ */ ++ yaffs_link_fixup(dev, &hard_list); ++ ++ yaffs_release_temp_buffer(dev, chunk_data); ++ ++ if (alloc_failed) ++ return YAFFS_FAIL; ++ ++ yaffs_trace(YAFFS_TRACE_SCAN, "yaffs2_scan_backwards ends"); ++ ++ return YAFFS_OK; ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_yaffs2.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_yaffs2.h.patch new file mode 100644 index 00000000..2b472a1a --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yaffs_yaffs2.h.patch @@ -0,0 +1,42 @@ +diff -drupN a/fs/yaffs2/yaffs_yaffs2.h b/fs/yaffs2/yaffs_yaffs2.h +--- a/fs/yaffs2/yaffs_yaffs2.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yaffs_yaffs2.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,38 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_YAFFS2_H__ ++#define __YAFFS_YAFFS2_H__ ++ ++#include "yaffs_guts.h" ++ ++void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev); ++void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev); ++void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev, ++ struct yaffs_block_info *bi); ++void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no, ++ struct yaffs_block_info *bi); ++int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi); ++u32 yaffs2_find_refresh_block(struct yaffs_dev *dev); ++int yaffs2_checkpt_required(struct yaffs_dev *dev); ++int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev); ++ ++void yaffs2_checkpt_invalidate(struct yaffs_dev *dev); ++int yaffs2_checkpt_save(struct yaffs_dev *dev); ++int yaffs2_checkpt_restore(struct yaffs_dev *dev); ++ ++int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size); ++int yaffs2_scan_backwards(struct yaffs_dev *dev); ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yportenv.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yportenv.h.patch new file mode 100644 index 00000000..cb7b97c1 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-fs_yaffs2_yportenv.h.patch @@ -0,0 +1,96 @@ +diff -drupN a/fs/yaffs2/yportenv.h b/fs/yaffs2/yportenv.h +--- a/fs/yaffs2/yportenv.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/fs/yaffs2/yportenv.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,92 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2018 Aleph One Ltd. ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YPORTENV_H__ ++#define __YPORTENV_H__ ++ ++/* ++ * Define the MTD version in terms of Linux Kernel versions ++ * This allows yaffs to be used independantly of the kernel ++ * as well as with it. ++ */ ++ ++#define MTD_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c)) ++ ++#ifdef YAFFS_OUT_OF_TREE ++#include "moduleconfig.h" ++#endif ++ ++#include ++#define MTD_VERSION_CODE LINUX_VERSION_CODE ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)) ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* These type wrappings are used to support Unicode names in WinCE. */ ++#define YCHAR char ++#define YUCHAR unsigned char ++#define _Y(x) x ++ ++#define YAFFS_LOSTNFOUND_NAME "lost+found" ++#define YAFFS_LOSTNFOUND_PREFIX "obj" ++ ++ ++#define YAFFS_ROOT_MODE 0755 ++#define YAFFS_LOSTNFOUND_MODE 0700 ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,12,0)) ++#define Y_CURRENT_TIME CURRENT_TIME.tv_sec ++#else ++#define Y_CURRENT_TIME current_kernel_time().tv_sec ++#endif ++#define Y_TIME_CONVERT(x) (x).tv_sec ++#else ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,12,0)) ++#define Y_CURRENT_TIME CURRENT_TIME ++#else ++#define Y_CURRENT_TIME current_kernel_time() ++#endif ++#define Y_TIME_CONVERT(x) (x) ++#endif ++ ++#define compile_time_assertion(assertion) \ ++ ({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; }) ++ ++ ++#define yaffs_printf(msk, fmt, ...) \ ++ printk(KERN_DEBUG "yaffs: " fmt "\n", ##__VA_ARGS__) ++ ++#define yaffs_trace(msk, fmt, ...) do { \ ++ if (yaffs_trace_mask & (msk)) \ ++ printk(KERN_DEBUG "yaffs: " fmt "\n", ##__VA_ARGS__); \ ++} while (0) ++ ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_clock_ingenic-t40-fpga.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_clock_ingenic-t40-fpga.h.patch new file mode 100644 index 00000000..6251b0a6 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_clock_ingenic-t40-fpga.h.patch @@ -0,0 +1,134 @@ +diff -drupN a/include/dt-bindings/clock/ingenic-t40-fpga.h b/include/dt-bindings/clock/ingenic-t40-fpga.h +--- a/include/dt-bindings/clock/ingenic-t40-fpga.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/include/dt-bindings/clock/ingenic-t40-fpga.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,130 @@ ++#ifndef _DT_BINDINGS_CLOCK_T40_H ++#define _DT_BINDINGS_CLOCK_T40_H ++ ++/* Fixed Clk */ ++#define CLK_ID_FIEXED 0 ++#define CLK_EXT (CLK_ID_FIEXED + 0) ++#define CLK_RTC_EXT (CLK_ID_FIEXED + 1) ++#define CLK_NR_FIXED (2) ++ ++/* PLL clk */ ++#define CLK_ID_PLL (CLK_ID_FIEXED + CLK_NR_FIXED) ++#define CLK_PLL_APLL (CLK_ID_PLL + 0) ++#define CLK_PLL_MPLL (CLK_ID_PLL + 1) ++#define CLK_PLL_EPLL (CLK_ID_PLL + 2) ++#define CLK_NR_PLL (3) ++ ++/* CPU Clocks */ ++#define CLK_ID_CPCCR (CLK_ID_PLL + CLK_NR_PLL) ++#define CLK_MUX_SCLKA (CLK_ID_CPCCR + 0) ++#define CLK_MUX_CPLL (CLK_ID_CPCCR + 1) ++#define CLK_MUX_H0PLL (CLK_ID_CPCCR + 2) ++#define CLK_MUX_H2PLL (CLK_ID_CPCCR + 3) ++#define CLK_RATE_CPUCLK (CLK_ID_CPCCR + 4) ++#define CLK_RATE_L2CCLK (CLK_ID_CPCCR + 5) ++#define CLK_RATE_H0CLK (CLK_ID_CPCCR + 6) ++#define CLK_RATE_H2CLK (CLK_ID_CPCCR + 7) ++#define CLK_RATE_PCLK (CLK_ID_CPCCR + 8) ++#define CLK_NR_CPCCR (9) ++ ++/* CGU clocks */ ++#define CLK_ID_CGU (CLK_ID_CPCCR + CLK_NR_CPCCR) ++#define CLK_CGU_DDR (CLK_ID_CGU + 0) ++#define CLK_CGU_MAC0 (CLK_ID_CGU + 1) ++#define CLK_CGU_LCD (CLK_ID_CGU + 2) ++#define CLK_CGU_MSC0 (CLK_ID_CGU + 3) ++#define CLK_CGU_MSC1 (CLK_ID_CGU + 4) ++#define CLK_CGU_SFC (CLK_ID_CGU + 5) ++#define CLK_CGU_CIM (CLK_ID_CGU + 6) ++#define CLK_CGU_PWM (CLK_ID_CGU + 7) ++#define CLK_CGU_OST (CLK_ID_CGU + 8) ++#define CLK_CGU_UART4 (CLK_ID_CGU + 9) ++#define CLK_CGU_UART3 (CLK_ID_CGU + 10) ++#define CLK_CGU_UART2 (CLK_ID_CGU + 11) ++#define CLK_CGU_UART1 (CLK_ID_CGU + 12) ++#define CLK_CGU_UART0 (CLK_ID_CGU + 13) ++#define CLK_CGU_SMB3 (CLK_ID_CGU + 14) ++#define CLK_CGU_SMB2 (CLK_ID_CGU + 15) ++#define CLK_CGU_SMB1 (CLK_ID_CGU + 16) ++#define CLK_CGU_SMB0 (CLK_ID_CGU + 17) ++#define CLK_CGU_SSI1 (CLK_ID_CGU + 18) ++#define CLK_CGU_SSI0 (CLK_ID_CGU + 19) ++#define CLK_CGU_PDMA (CLK_ID_CGU + 20) ++#define CLK_CGU_MAC1 (CLK_ID_CGU + 21) ++#define CLK_CGU_MSC2 (CLK_ID_CGU + 22) ++#define CLK_CGU_SMB4 (CLK_ID_CGU + 23) ++#define CLK_NR_CGU (24) ++ ++#define CLK_ID_CGU_AUDIO (CLK_ID_CGU + CLK_NR_CGU) ++#define CLK_CGU_I2S0 (CLK_ID_CGU_AUDIO + 0) ++#define CLK_CGU_I2S1 (CLK_ID_CGU_AUDIO + 1) ++#define CLK_CGU_I2S2 (CLK_ID_CGU_AUDIO + 2) ++#define CLK_CGU_I2S3 (CLK_ID_CGU_AUDIO + 3) ++#define CLK_CGU_SPDIF (CLK_ID_CGU_AUDIO + 4) ++#define CLK_CGU_PCM (CLK_ID_CGU_AUDIO + 5) ++#define CLK_CGU_DMIC (CLK_ID_CGU_AUDIO + 6) ++#define CLK_NR_CGU_AUDIO (7) ++ ++/* Gate Clocks */ ++#define CLK_ID_GATE (CLK_ID_CGU_AUDIO + CLK_NR_CGU_AUDIO) ++#define CLK_GATE_DDR (CLK_ID_GATE + 0) ++#define CLK_GATE_CPU1 (CLK_ID_GATE + 1) ++#define CLK_GATE_AHB0 (CLK_ID_GATE + 2) ++#define CLK_GATE_APB0 (CLK_ID_GATE + 3) ++#define CLK_GATE_RTC (CLK_ID_GATE + 4) ++#define CLK_GATE_SSI1 (CLK_ID_GATE + 5) ++#define CLK_GATE_MAC0 (CLK_ID_GATE + 6) ++#define CLK_GATE_AES (CLK_ID_GATE + 7) ++#define CLK_GATE_LCD (CLK_ID_GATE + 8) ++#define CLK_GATE_CIM (CLK_ID_GATE + 9) ++#define CLK_GATE_PDMA (CLK_ID_GATE + 10) ++#define CLK_GATE_OST (CLK_ID_GATE + 11) ++#define CLK_GATE_SSI0 (CLK_ID_GATE + 12) ++#define CLK_GATE_TCU (CLK_ID_GATE + 13) ++#define CLK_GATE_DTRNG (CLK_ID_GATE + 14) ++#define CLK_GATE_UART2 (CLK_ID_GATE + 15) ++#define CLK_GATE_UART1 (CLK_ID_GATE + 16) ++#define CLK_GATE_UART0 (CLK_ID_GATE + 17) ++#define CLK_GATE_SADC (CLK_ID_GATE + 18) ++#define CLK_GATE_JPEG (CLK_ID_GATE + 19) ++#define CLK_GATE_AUDIO (CLK_ID_GATE + 20) ++#define CLK_GATE_SMB3 (CLK_ID_GATE + 21) ++#define CLK_GATE_SMB2 (CLK_ID_GATE + 22) ++#define CLK_GATE_SMB1 (CLK_ID_GATE + 23) ++#define CLK_GATE_SMB0 (CLK_ID_GATE + 24) ++#define CLK_GATE_SCC (CLK_ID_GATE + 25) ++#define CLK_GATE_MSC1 (CLK_ID_GATE + 26) ++#define CLK_GATE_MSC0 (CLK_ID_GATE + 27) ++#define CLK_GATE_OTG (CLK_ID_GATE + 28) ++#define CLK_GATE_SFC (CLK_ID_GATE + 29) ++#define CLK_GATE_EFUSE (CLK_ID_GATE + 30) ++#define CLK_GATE_NEMC (CLK_ID_GATE + 31) ++#define CLK_GATE_ARB (CLK_ID_GATE + 32) ++#define CLK_GATE_MIPI (CLK_ID_GATE + 33) ++#define CLK_GATE_CPU (CLK_ID_GATE + 34) ++#define CLK_GATE_INTC (CLK_ID_GATE + 35) ++#define CLK_GATE_GPIO (CLK_ID_GATE + 36) ++#define CLK_GATE_SPDIF (CLK_ID_GATE + 37) ++#define CLK_GATE_DMIC (CLK_ID_GATE + 38) ++#define CLK_GATE_PCM (CLK_ID_GATE + 39) ++#define CLK_GATE_I2S3 (CLK_ID_GATE + 40) ++#define CLK_GATE_I2S2 (CLK_ID_GATE + 41) ++#define CLK_GATE_I2S1 (CLK_ID_GATE + 42) ++#define CLK_GATE_I2S0 (CLK_ID_GATE + 43) ++#define CLK_GATE_ROT (CLK_ID_GATE + 44) ++#define CLK_GATE_HASH (CLK_ID_GATE + 45) ++#define CLK_GATE_PWM (CLK_ID_GATE + 46) ++#define CLK_GATE_UART5 (CLK_ID_GATE + 47) ++#define CLK_GATE_UART4 (CLK_ID_GATE + 48) ++#define CLK_GATE_UART3 (CLK_ID_GATE + 49) ++#define CLK_GATE_SMB5 (CLK_ID_GATE + 50) ++#define CLK_GATE_SMB4 (CLK_ID_GATE + 51) ++#define CLK_GATE_USBPHY (CLK_ID_GATE + 52) ++#define CLK_GATE_MAC1 (CLK_ID_GATE + 53) ++#define CLK_GATE_MSC2 (CLK_ID_GATE + 54) ++#define CLK_GATE_VPU (CLK_ID_GATE + 55) ++#define CLK_NR_GATE (56) ++#define CLK_ID_OTHER (CLK_ID_GATE + CLK_NR_GATE) ++ ++#define NR_CLKS (CLK_NR_FIXED + CLK_NR_PLL + CLK_NR_CPCCR + CLK_NR_CGU + CLK_NR_CGU_AUDIO + CLK_NR_GATE) ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_clock_ingenic-t40.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_clock_ingenic-t40.h.patch new file mode 100644 index 00000000..0149f5e1 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_clock_ingenic-t40.h.patch @@ -0,0 +1,140 @@ +diff -drupN a/include/dt-bindings/clock/ingenic-t40.h b/include/dt-bindings/clock/ingenic-t40.h +--- a/include/dt-bindings/clock/ingenic-t40.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/include/dt-bindings/clock/ingenic-t40.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,136 @@ ++#ifndef _DT_BINDINGS_CLOCK_T40_H ++#define _DT_BINDINGS_CLOCK_T40_H ++ ++/* Fixed Clk */ ++#define CLK_ID_FIEXED 0 ++#define CLK_EXT (CLK_ID_FIEXED + 0) ++#define CLK_RTC_EXT (CLK_ID_FIEXED + 1) ++#define CLK_NR_FIXED (2) ++ ++/* PLL clk */ ++#define CLK_ID_PLL (CLK_ID_FIEXED + CLK_NR_FIXED) ++#define CLK_PLL_APLL (CLK_ID_PLL + 0) ++#define CLK_PLL_MPLL (CLK_ID_PLL + 1) ++#define CLK_PLL_VPLL (CLK_ID_PLL + 2) ++#define CLK_PLL_EPLL (CLK_ID_PLL + 3) ++#define CLK_NR_PLL (4) ++ ++/* MUX clk */ ++#define CLK_ID_MUX (CLK_ID_PLL + CLK_NR_PLL) ++#define CLK_MUX_SCLKA (CLK_ID_MUX + 0) ++#define CLK_MUX_CPU_L2C (CLK_ID_MUX + 1) ++#define CLK_MUX_AHB0 (CLK_ID_MUX + 2) ++#define CLK_MUX_AHB2 (CLK_ID_MUX + 3) ++#define CLK_MUX_PCLK (CLK_ID_MUX + 4) ++#define CLK_MUX_DDR (CLK_ID_MUX + 5) ++#define CLK_MUX_MACPHY (CLK_ID_MUX + 6) ++#define CLK_MUX_LCD (CLK_ID_MUX + 7) ++#define CLK_MUX_MSC0 (CLK_ID_MUX + 8) ++#define CLK_MUX_MSC1 (CLK_ID_MUX + 9) ++#define CLK_MUX_SFC (CLK_ID_MUX + 10) ++#define CLK_MUX_SSI (CLK_ID_MUX + 11) ++#define CLK_MUX_CIM0 (CLK_ID_MUX + 12) ++#define CLK_MUX_CIM1 (CLK_ID_MUX + 13) ++#define CLK_MUX_CIM2 (CLK_ID_MUX + 14) ++#define CLK_MUX_ISP (CLK_ID_MUX + 15) ++#define CLK_MUX_RSA (CLK_ID_MUX + 16) ++#define CLK_MUX_EL150 (CLK_ID_MUX + 17) ++#define CLK_MUX_I2ST (CLK_ID_MUX + 18) ++#define CLK_MUX_I2SR (CLK_ID_MUX + 19) ++#define CLK_MUX_BSCALER (CLK_ID_MUX + 20) ++#define CLK_MUX_BT0 (CLK_ID_MUX + 21) ++#define CLK_MUX_BT1 (CLK_ID_MUX + 22) ++ ++#define CLK_NR_MUX (23) ++ ++ ++#define CLK_ID_DIV (CLK_ID_MUX + CLK_NR_MUX) ++#define CLK_DIV_DDR (CLK_ID_DIV + 0) ++#define CLK_DIV_MACPHY (CLK_ID_DIV + 1) ++#define CLK_DIV_LCD (CLK_ID_DIV + 2) ++#define CLK_DIV_MSC0 (CLK_ID_DIV + 3) ++#define CLK_DIV_MSC1 (CLK_ID_DIV + 4) ++#define CLK_DIV_SFC (CLK_ID_DIV + 5) ++#define CLK_DIV_SSI (CLK_ID_DIV + 6) ++#define CLK_DIV_CIM0 (CLK_ID_DIV + 7) ++#define CLK_DIV_CIM1 (CLK_ID_DIV + 8) ++#define CLK_DIV_CIM2 (CLK_ID_DIV + 9) ++#define CLK_DIV_ISP (CLK_ID_DIV + 10) ++#define CLK_DIV_RSA (CLK_ID_DIV + 11) ++#define CLK_DIV_EL150 (CLK_ID_DIV + 12) ++#define CLK_DIV_I2ST (CLK_ID_DIV + 13) ++#define CLK_DIV_I2SR (CLK_ID_DIV + 14) ++#define CLK_DIV_BSCALER (CLK_ID_DIV + 15) ++#define CLK_DIV_BT0 (CLK_ID_DIV + 16) ++#define CLK_DIV_BT1 (CLK_ID_DIV + 17) ++ ++#define CLK_DIV_CPU (CLK_ID_DIV + 18) ++#define CLK_DIV_L2C (CLK_ID_DIV + 19) ++#define CLK_DIV_AHB0 (CLK_ID_DIV + 20) ++#define CLK_DIV_AHB2 (CLK_ID_DIV + 21) ++#define CLK_DIV_APB (CLK_ID_DIV + 22) ++#define CLK_DIV_CPU_L2C (CLK_ID_DIV + 23) ++#define CLK_DIV_CPU_L2C_X1 (CLK_ID_DIV + 24) ++#define CLK_DIV_CPU_L2C_X2 (CLK_ID_DIV + 25) ++ ++#define CLK_NR_DIV (26) ++ ++ ++/* Gate Clocks */ ++#define CLK_ID_GATE (CLK_ID_DIV + CLK_NR_DIV) ++#define CLK_GATE_DDR (CLK_ID_GATE + 0) ++#define CLK_GATE_TCU (CLK_ID_GATE + 1) ++#define CLK_GATE_RESERVER29 (CLK_ID_GATE + 2) ++#define CLK_GATE_DES (CLK_ID_GATE + 3) ++#define CLK_GATE_RSA (CLK_ID_GATE + 4) ++#define CLK_GATE_VO (CLK_ID_GATE + 5) ++#define CLK_GATE_MIPI_CSI (CLK_ID_GATE + 6) ++#define CLK_GATE_LCD (CLK_ID_GATE + 7) ++#define CLK_GATE_ISP (CLK_ID_GATE + 8) ++#define CLK_GATE_PDMA (CLK_ID_GATE + 9) ++#define CLK_GATE_SFC (CLK_ID_GATE + 10) ++#define CLK_GATE_SSI1 (CLK_ID_GATE + 11) ++#define CLK_GATE_HASH (CLK_ID_GATE + 12) ++#define CLK_GATE_SLV (CLK_ID_GATE + 13) ++#define CLK_GATE_UART3 (CLK_ID_GATE + 14) ++#define CLK_GATE_UART2 (CLK_ID_GATE + 15) ++#define CLK_GATE_UART1 (CLK_ID_GATE + 16) ++#define CLK_GATE_UART0 (CLK_ID_GATE + 17) ++#define CLK_GATE_SADC (CLK_ID_GATE + 18) ++#define CLK_GATE_DMIC (CLK_ID_GATE + 19) ++#define CLK_GATE_AIC (CLK_ID_GATE + 20) ++#define CLK_GATE_SMB3 (CLK_ID_GATE + 21) ++#define CLK_GATE_SMB2 (CLK_ID_GATE + 22) ++#define CLK_GATE_SMB1 (CLK_ID_GATE + 23) ++#define CLK_GATE_SMB0 (CLK_ID_GATE + 24) ++#define CLK_GATE_SSI0 (CLK_ID_GATE + 25) ++#define CLK_GATE_MSC1 (CLK_ID_GATE + 26) ++#define CLK_GATE_MSC0 (CLK_ID_GATE + 27) ++#define CLK_GATE_OTG (CLK_ID_GATE + 28) ++#define CLK_GATE_BSCALER (CLK_ID_GATE + 29) ++#define CLK_GATE_EFUSE (CLK_ID_GATE + 30) ++#define CLK_GATE_NEMC (CLK_ID_GATE + 31) ++#define CLK_GATE_CPU (CLK_ID_GATE + 32) ++#define CLK_GATE_APB0 (CLK_ID_GATE + 33) ++#define CLK_GATE_RESERVER13 (CLK_ID_GATE + 34) ++#define CLK_GATE_RESERVER12 (CLK_ID_GATE + 35) ++#define CLK_GATE_OST (CLK_ID_GATE + 36) ++#define CLK_GATE_AHB0 (CLK_ID_GATE + 37) ++#define CLK_GATE_MONITOR (CLK_ID_GATE + 38) ++#define CLK_GATE_I2D (CLK_ID_GATE + 39) ++#define CLK_GATE_MIPI_DSI (CLK_ID_GATE + 40) ++#define CLK_GATE_DRAWBOX (CLK_ID_GATE + 41) ++#define CLK_GATE_AES (CLK_ID_GATE + 42) ++#define CLK_GATE_GMAC (CLK_ID_GATE + 43) ++#define CLK_GATE_AHB1 (CLK_ID_GATE + 44) ++#define CLK_GATE_IPU (CLK_ID_GATE + 45) ++#define CLK_GATE_DTRNG (CLK_ID_GATE + 46) ++#define CLK_GATE_EL150 (CLK_ID_GATE + 47) ++#define CLK_CE_I2ST (CLK_ID_GATE + 48) ++#define CLK_CE_I2SR (CLK_ID_GATE + 49) ++#define CLK_GATE_USBPHY (CLK_ID_GATE + 50) ++#define CLK_NR_GATE (61) ++#define CLK_ID_OTHER (CLK_ID_GATE + CLK_NR_GATE) ++ ++#define NR_CLKS (CLK_NR_FIXED + CLK_NR_PLL + CLK_NR_MUX + CLK_NR_DIV + CLK_NR_GATE) ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_clock_ingenic-tcu.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_clock_ingenic-tcu.h.patch new file mode 100644 index 00000000..07a486c0 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_clock_ingenic-tcu.h.patch @@ -0,0 +1,29 @@ +diff -drupN a/include/dt-bindings/clock/ingenic-tcu.h b/include/dt-bindings/clock/ingenic-tcu.h +--- a/include/dt-bindings/clock/ingenic-tcu.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/include/dt-bindings/clock/ingenic-tcu.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,25 @@ ++#ifndef __DT_BINDINGS_CLOCK_INGENIC_TCU_H__ ++#define __DT_BINDINGS_CLOCK_INGENIC_TCU_H__ ++ ++#define TCU_MODE1 1 ++#define TCU_MODE2 2 ++ ++#define PWM_FUNC 1 ++#define TRACKBALL_FUNC 2 ++#define PWM_AND_TRACKBALL_FUNC (PWM_FUNC | TRACKBALL_FUNC) ++ ++#define NO_PWM_IN 0 ++#define PWM_IN 1 ++ ++ ++#define CHANNEL_BASE_OFF 4 ++#define CHANNEL_ID_OFF 0 ++#define CHANNEL_MODE_OFF (CHANNEL_ID_OFF + CHANNEL_BASE_OFF*2) ++#define CHANNEL_FUNC_OFF (CHANNEL_MODE_OFF + CHANNEL_BASE_OFF) ++#define CHANNEL_IN_OFF (CHANNEL_FUNC_OFF + CHANNEL_BASE_OFF) ++ ++#define CHANNEL_INFO(ID, MODE, FUNC, IN) \ ++ ((ID << CHANNEL_ID_OFF)|(MODE << CHANNEL_MODE_OFF) \ ++ |(FUNC << CHANNEL_FUNC_OFF)|(IN << CHANNEL_IN_OFF)) ++ ++#endif /* __DT_BINDINGS_CLOCK_INGENIC_TCU_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_clock_ingenic-x1000.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_clock_ingenic-x1000.h.patch new file mode 100644 index 00000000..54d98aa6 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_clock_ingenic-x1000.h.patch @@ -0,0 +1,96 @@ +diff -drupN a/include/dt-bindings/clock/ingenic-x1000.h b/include/dt-bindings/clock/ingenic-x1000.h +--- a/include/dt-bindings/clock/ingenic-x1000.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/include/dt-bindings/clock/ingenic-x1000.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,92 @@ ++#ifndef _DT_BINDINGS_CLOCK_X1000_H ++#define _DT_BINDINGS_CLOCK_X1000_H ++ ++ ++/* Fixed Clk */ ++#define CLK_ID_FIEXED 0 ++#define CLK_EXT (CLK_ID_FIEXED + 0) ++#define CLK_RTC_EXT (CLK_ID_FIEXED + 1) ++#define CLK_NR_FIXED 2 ++ ++ ++/* PLL clk */ ++#define CLK_ID_PLL (CLK_ID_FIEXED + CLK_NR_FIXED) ++#define CLK_PLL_APLL (CLK_ID_PLL + 0) ++#define CLK_PLL_MPLL (CLK_ID_PLL + 1) ++#define CLK_NR_PLL (2) ++ ++ ++/* cpccr clocks */ ++#define CLK_ID_CPCCR (CLK_ID_PLL + CLK_NR_PLL) ++#define CLK_MUX_SCLKA (CLK_ID_CPCCR + 0) ++#define CLK_MUX_CPLL (CLK_ID_CPCCR + 1) ++#define CLK_MUX_H0PLL (CLK_ID_CPCCR + 2) ++#define CLK_MUX_H2PLL (CLK_ID_CPCCR + 3) ++#define CLK_RATE_CPUCLK (CLK_ID_CPCCR + 4) ++#define CLK_RATE_L2CCLK (CLK_ID_CPCCR + 5) ++#define CLK_RATE_H0CLK (CLK_ID_CPCCR + 6) ++#define CLK_RATE_H2CLK (CLK_ID_CPCCR + 7) ++#define CLK_RATE_PCLK (CLK_ID_CPCCR + 8) ++#define CLK_NR_CPCCR (9) ++ ++/* cgu clocks */ ++#define CLK_ID_DIV (CLK_ID_CPCCR + CLK_NR_CPCCR) ++#define CLK_CGU_PCM (CLK_ID_DIV + 0) ++#define CLK_CGU_DDR (CLK_ID_DIV + 1) ++#define CLK_CGU_MAC (CLK_ID_DIV + 2) ++#define CLK_CGU_LCD (CLK_ID_DIV + 3) ++#define CLK_CGU_MSCMUX (CLK_ID_DIV + 4) ++#define CLK_CGU_MSC0 (CLK_ID_DIV + 5) ++#define CLK_CGU_MSC1 (CLK_ID_DIV + 6) ++#define CLK_CGU_USB (CLK_ID_DIV + 7) ++#define CLK_CGU_SFC (CLK_ID_DIV + 8) ++#define CLK_CGU_SSI (CLK_ID_DIV + 9) ++#define CLK_CGU_CIM (CLK_ID_DIV + 10) ++#define CLK_CGU_I2S (CLK_ID_DIV + 11) ++#define CLK_NR_CGU (12) ++ ++/* Gate Clocks */ ++#define CLK_ID_GATE (CLK_ID_DIV + CLK_NR_CGU) ++#define CLK_GATE_NEMC (CLK_ID_GATE + 0) ++#define CLK_GATE_EFUSE (CLK_ID_GATE + 1) ++#define CLK_GATE_SFC (CLK_ID_GATE + 2) ++#define CLK_GATE_OTG (CLK_ID_GATE + 3) ++#define CLK_GATE_MSC0 (CLK_ID_GATE + 4) ++#define CLK_GATE_MSC1 (CLK_ID_GATE + 5) ++#define CLK_GATE_SCC (CLK_ID_GATE + 6) ++#define CLK_GATE_I2C0 (CLK_ID_GATE + 7) ++#define CLK_GATE_I2C1 (CLK_ID_GATE + 8) ++#define CLK_GATE_I2C2 (CLK_ID_GATE + 9) ++#define CLK_GATE_I2C3 (CLK_ID_GATE + 10) ++#define CLK_GATE_AIC (CLK_ID_GATE + 11) ++#define CLK_GATE_JPEG (CLK_ID_GATE + 12) ++#define CLK_GATE_SADC (CLK_ID_GATE + 13) ++#define CLK_GATE_UART0 (CLK_ID_GATE + 14) ++#define CLK_GATE_UART1 (CLK_ID_GATE + 15) ++#define CLK_GATE_UART2 (CLK_ID_GATE + 16) ++#define CLK_GATE_DMIC (CLK_ID_GATE + 17) ++#define CLK_GATE_TCU (CLK_ID_GATE + 18) ++#define CLK_GATE_SSI (CLK_ID_GATE + 19) ++#define CLK_GATE_OST (CLK_ID_GATE + 20) ++#define CLK_GATE_PDMA (CLK_ID_GATE + 21) ++#define CLK_GATE_CIM (CLK_ID_GATE + 22) ++#define CLK_GATE_LCD (CLK_ID_GATE + 23) ++#define CLK_GATE_AES (CLK_ID_GATE + 24) ++#define CLK_GATE_MAC (CLK_ID_GATE + 25) ++#define CLK_GATE_PCM (CLK_ID_GATE + 26) ++#define CLK_GATE_RTC (CLK_ID_GATE + 27) ++#define CLK_GATE_APB0 (CLK_ID_GATE + 28) ++#define CLK_GATE_AHB0 (CLK_ID_GATE + 29) ++#define CLK_GATE_CPU (CLK_ID_GATE + 30) ++#define CLK_GATE_DDR (CLK_ID_GATE + 31) ++#define CLK_GATE_SCLKA (CLK_ID_GATE + 32) ++#define CLK_GATE_USBPHY (CLK_ID_GATE + 33) ++#define CLK_GATE_SCLKABUS (CLK_ID_GATE + 34) ++#define CLK_NR_GATE (35) ++ ++#define CLK_ID_OTHER (CLK_ID_GATE + CLK_NR_GATE) ++#define CLK_RTC (CLK_ID_OTHER + 0) ++#define CLK_NR_OTHER (1) ++ ++#define NR_CLKS (CLK_NR_FIXED + CLK_NR_PLL + CLK_NR_CPCCR + CLK_NR_CGU + CLK_NR_GATE + CLK_NR_OTHER) ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_clock_ingenic-x1800.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_clock_ingenic-x1800.h.patch new file mode 100644 index 00000000..c9bf8b45 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_clock_ingenic-x1800.h.patch @@ -0,0 +1,95 @@ +diff -drupN a/include/dt-bindings/clock/ingenic-x1800.h b/include/dt-bindings/clock/ingenic-x1800.h +--- a/include/dt-bindings/clock/ingenic-x1800.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/include/dt-bindings/clock/ingenic-x1800.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,91 @@ ++#ifndef _DT_BINDINGS_CLOCK_X1800_H ++#define _DT_BINDINGS_CLOCK_X1800_H ++ ++ ++/* Fixed Clk */ ++#define CLK_ID_FIEXED 0 ++#define CLK_EXT (CLK_ID_FIEXED + 0) ++#define CLK_RTC_EXT (CLK_ID_FIEXED + 1) ++#define CLK_NR_FIXED 2 ++ ++ ++/* PLL clk */ ++#define CLK_ID_PLL (CLK_ID_FIEXED + CLK_NR_FIXED) ++#define CLK_PLL_APLL (CLK_ID_PLL + 0) ++#define CLK_PLL_MPLL (CLK_ID_PLL + 1) ++#define CLK_NR_PLL (2) ++ ++ ++/* cpccr clocks */ ++#define CLK_ID_CPCCR (CLK_ID_PLL + CLK_NR_PLL) ++#define CLK_MUX_SCLKA (CLK_ID_CPCCR + 0) ++#define CLK_MUX_CPLL (CLK_ID_CPCCR + 1) ++#define CLK_MUX_H0PLL (CLK_ID_CPCCR + 2) ++#define CLK_MUX_H2PLL (CLK_ID_CPCCR + 3) ++#define CLK_RATE_CPUCLK (CLK_ID_CPCCR + 4) ++#define CLK_RATE_L2CCLK (CLK_ID_CPCCR + 5) ++#define CLK_RATE_H0CLK (CLK_ID_CPCCR + 6) ++#define CLK_RATE_H2CLK (CLK_ID_CPCCR + 7) ++#define CLK_RATE_PCLK (CLK_ID_CPCCR + 8) ++#define CLK_NR_CPCCR (9) ++ ++/* cgu clocks */ ++#define CLK_ID_DIV (CLK_ID_CPCCR + CLK_NR_CPCCR) ++#define CLK_CGU_VPU (CLK_ID_DIV + 0) ++#define CLK_CGU_DDR (CLK_ID_DIV + 1) ++#define CLK_CGU_MAC (CLK_ID_DIV + 2) ++#define CLK_CGU_LCD (CLK_ID_DIV + 3) ++#define CLK_CGU_MSCMUX (CLK_ID_DIV + 4) ++#define CLK_CGU_MSC0 (CLK_ID_DIV + 5) ++#define CLK_CGU_MSC1 (CLK_ID_DIV + 6) ++#define CLK_CGU_SFC (CLK_ID_DIV + 7) ++#define CLK_CGU_SSI (CLK_ID_DIV + 8) ++#define CLK_CGU_CIM (CLK_ID_DIV + 9) ++#define CLK_CGU_I2S (CLK_ID_DIV + 10) ++#define CLK_CGU_ISP (CLK_ID_DIV + 11) ++#define CLK_CGU_USB (CLK_ID_DIV + 12) ++#define CLK_NR_CGU (13) ++ ++/* Gate Clocks */ ++#define CLK_ID_GATE (CLK_ID_DIV + CLK_NR_CGU) ++#define CLK_GATE_EFUSE (CLK_ID_GATE + 0) ++#define CLK_GATE_OTG (CLK_ID_GATE + 1) ++#define CLK_GATE_MSC0 (CLK_ID_GATE + 2) ++#define CLK_GATE_MSC1 (CLK_ID_GATE + 3) ++#define CLK_GATE_SSI0 (CLK_ID_GATE + 4) ++#define CLK_GATE_I2C0 (CLK_ID_GATE + 5) ++#define CLK_GATE_I2C1 (CLK_ID_GATE + 6) ++#define CLK_GATE_I2C2 (CLK_ID_GATE + 7) ++#define CLK_GATE_I2C3 (CLK_ID_GATE + 8) ++#define CLK_GATE_AIC (CLK_ID_GATE + 9) ++#define CLK_GATE_DMIC (CLK_ID_GATE + 10) ++#define CLK_GATE_SADC (CLK_ID_GATE + 11) ++#define CLK_GATE_UART0 (CLK_ID_GATE + 12) ++#define CLK_GATE_UART1 (CLK_ID_GATE + 13) ++#define CLK_GATE_UART2 (CLK_ID_GATE + 14) ++#define CLK_GATE_SFC (CLK_ID_GATE + 15) ++#define CLK_GATE_PDMA (CLK_ID_GATE + 16) ++#define CLK_GATE_ISP (CLK_ID_GATE + 17) ++#define CLK_GATE_DES (CLK_ID_GATE + 18) ++#define CLK_GATE_RTC (CLK_ID_GATE + 19) ++#define CLK_GATE_TCU (CLK_ID_GATE + 20) ++#define CLK_GATE_DDR (CLK_ID_GATE + 21) ++#define CLK_GATE_VPU0 (CLK_ID_GATE + 22) ++#define CLK_GATE_IPU (CLK_ID_GATE + 23) ++#define CLK_GATE_MAC (CLK_ID_GATE + 24) ++#define CLK_GATE_AES (CLK_ID_GATE + 25) ++#define CLK_GATE_AHB0 (CLK_ID_GATE + 26) ++#define CLK_GATE_SYS_OST (CLK_ID_GATE + 27) ++#define CLK_GATE_APB0 (CLK_ID_GATE + 28) ++#define CLK_GATE_CPU (CLK_ID_GATE + 29) ++#define CLK_GATE_SCLKA (CLK_ID_GATE + 30) ++#define CLK_GATE_USBPHY (CLK_ID_GATE + 31) ++#define CLK_GATE_SCLKABUS (CLK_ID_GATE + 32) ++#define CLK_NR_GATE (33) ++ ++#define CLK_ID_OTHER (CLK_ID_GATE + CLK_NR_GATE) ++#define CLK_RTC (CLK_ID_OTHER + 0) ++#define CLK_NR_OTHER (1) ++ ++#define NR_CLKS (CLK_NR_FIXED + CLK_NR_PLL + CLK_NR_CPCCR + CLK_NR_CGU + CLK_NR_GATE + CLK_NR_OTHER) ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_clock_ingenic-x2000-v12-fpga.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_clock_ingenic-x2000-v12-fpga.h.patch new file mode 100644 index 00000000..e9b3e2c2 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_clock_ingenic-x2000-v12-fpga.h.patch @@ -0,0 +1,134 @@ +diff -drupN a/include/dt-bindings/clock/ingenic-x2000-v12-fpga.h b/include/dt-bindings/clock/ingenic-x2000-v12-fpga.h +--- a/include/dt-bindings/clock/ingenic-x2000-v12-fpga.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/include/dt-bindings/clock/ingenic-x2000-v12-fpga.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,130 @@ ++#ifndef _DT_BINDINGS_CLOCK_M200_H ++#define _DT_BINDINGS_CLOCK_M200_H ++ ++/* Fixed Clk */ ++#define CLK_ID_FIEXED 0 ++#define CLK_EXT (CLK_ID_FIEXED + 0) ++#define CLK_RTC_EXT (CLK_ID_FIEXED + 1) ++#define CLK_NR_FIXED (2) ++ ++/* PLL clk */ ++#define CLK_ID_PLL (CLK_ID_FIEXED + CLK_NR_FIXED) ++#define CLK_PLL_APLL (CLK_ID_PLL + 0) ++#define CLK_PLL_MPLL (CLK_ID_PLL + 1) ++#define CLK_PLL_EPLL (CLK_ID_PLL + 2) ++#define CLK_NR_PLL (3) ++ ++/* CPU Clocks */ ++#define CLK_ID_CPCCR (CLK_ID_PLL + CLK_NR_PLL) ++#define CLK_MUX_SCLKA (CLK_ID_CPCCR + 0) ++#define CLK_MUX_CPLL (CLK_ID_CPCCR + 1) ++#define CLK_MUX_H0PLL (CLK_ID_CPCCR + 2) ++#define CLK_MUX_H2PLL (CLK_ID_CPCCR + 3) ++#define CLK_RATE_CPUCLK (CLK_ID_CPCCR + 4) ++#define CLK_RATE_L2CCLK (CLK_ID_CPCCR + 5) ++#define CLK_RATE_H0CLK (CLK_ID_CPCCR + 6) ++#define CLK_RATE_H2CLK (CLK_ID_CPCCR + 7) ++#define CLK_RATE_PCLK (CLK_ID_CPCCR + 8) ++#define CLK_NR_CPCCR (9) ++ ++/* CGU clocks */ ++#define CLK_ID_CGU (CLK_ID_CPCCR + CLK_NR_CPCCR) ++#define CLK_CGU_DDR (CLK_ID_CGU + 0) ++#define CLK_CGU_MAC0 (CLK_ID_CGU + 1) ++#define CLK_CGU_LCD (CLK_ID_CGU + 2) ++#define CLK_CGU_MSC0 (CLK_ID_CGU + 3) ++#define CLK_CGU_MSC1 (CLK_ID_CGU + 4) ++#define CLK_CGU_SFC (CLK_ID_CGU + 5) ++#define CLK_CGU_CIM (CLK_ID_CGU + 6) ++#define CLK_CGU_PWM (CLK_ID_CGU + 7) ++#define CLK_CGU_OST (CLK_ID_CGU + 8) ++#define CLK_CGU_UART4 (CLK_ID_CGU + 9) ++#define CLK_CGU_UART3 (CLK_ID_CGU + 10) ++#define CLK_CGU_UART2 (CLK_ID_CGU + 11) ++#define CLK_CGU_UART1 (CLK_ID_CGU + 12) ++#define CLK_CGU_UART0 (CLK_ID_CGU + 13) ++#define CLK_CGU_SMB3 (CLK_ID_CGU + 14) ++#define CLK_CGU_SMB2 (CLK_ID_CGU + 15) ++#define CLK_CGU_SMB1 (CLK_ID_CGU + 16) ++#define CLK_CGU_SMB0 (CLK_ID_CGU + 17) ++#define CLK_CGU_SSI1 (CLK_ID_CGU + 18) ++#define CLK_CGU_SSI0 (CLK_ID_CGU + 19) ++#define CLK_CGU_PDMA (CLK_ID_CGU + 20) ++#define CLK_CGU_MAC1 (CLK_ID_CGU + 21) ++#define CLK_CGU_MSC2 (CLK_ID_CGU + 22) ++#define CLK_CGU_SMB4 (CLK_ID_CGU + 23) ++#define CLK_NR_CGU (24) ++ ++#define CLK_ID_CGU_AUDIO (CLK_ID_CGU + CLK_NR_CGU) ++#define CLK_CGU_I2S0 (CLK_ID_CGU_AUDIO + 0) ++#define CLK_CGU_I2S1 (CLK_ID_CGU_AUDIO + 1) ++#define CLK_CGU_I2S2 (CLK_ID_CGU_AUDIO + 2) ++#define CLK_CGU_I2S3 (CLK_ID_CGU_AUDIO + 3) ++#define CLK_CGU_SPDIF (CLK_ID_CGU_AUDIO + 4) ++#define CLK_CGU_PCM (CLK_ID_CGU_AUDIO + 5) ++#define CLK_CGU_DMIC (CLK_ID_CGU_AUDIO + 6) ++#define CLK_NR_CGU_AUDIO (7) ++ ++/* Gate Clocks */ ++#define CLK_ID_GATE (CLK_ID_CGU_AUDIO + CLK_NR_CGU_AUDIO) ++#define CLK_GATE_DDR (CLK_ID_GATE + 0) ++#define CLK_GATE_CPU1 (CLK_ID_GATE + 1) ++#define CLK_GATE_AHB0 (CLK_ID_GATE + 2) ++#define CLK_GATE_APB0 (CLK_ID_GATE + 3) ++#define CLK_GATE_RTC (CLK_ID_GATE + 4) ++#define CLK_GATE_SSI1 (CLK_ID_GATE + 5) ++#define CLK_GATE_MAC0 (CLK_ID_GATE + 6) ++#define CLK_GATE_AES (CLK_ID_GATE + 7) ++#define CLK_GATE_LCD (CLK_ID_GATE + 8) ++#define CLK_GATE_CIM (CLK_ID_GATE + 9) ++#define CLK_GATE_PDMA (CLK_ID_GATE + 10) ++#define CLK_GATE_OST (CLK_ID_GATE + 11) ++#define CLK_GATE_SSI0 (CLK_ID_GATE + 12) ++#define CLK_GATE_TCU (CLK_ID_GATE + 13) ++#define CLK_GATE_DTRNG (CLK_ID_GATE + 14) ++#define CLK_GATE_UART2 (CLK_ID_GATE + 15) ++#define CLK_GATE_UART1 (CLK_ID_GATE + 16) ++#define CLK_GATE_UART0 (CLK_ID_GATE + 17) ++#define CLK_GATE_SADC (CLK_ID_GATE + 18) ++#define CLK_GATE_JPEG (CLK_ID_GATE + 19) ++#define CLK_GATE_AUDIO (CLK_ID_GATE + 20) ++#define CLK_GATE_SMB3 (CLK_ID_GATE + 21) ++#define CLK_GATE_SMB2 (CLK_ID_GATE + 22) ++#define CLK_GATE_SMB1 (CLK_ID_GATE + 23) ++#define CLK_GATE_SMB0 (CLK_ID_GATE + 24) ++#define CLK_GATE_SCC (CLK_ID_GATE + 25) ++#define CLK_GATE_MSC1 (CLK_ID_GATE + 26) ++#define CLK_GATE_MSC0 (CLK_ID_GATE + 27) ++#define CLK_GATE_OTG (CLK_ID_GATE + 28) ++#define CLK_GATE_SFC (CLK_ID_GATE + 29) ++#define CLK_GATE_EFUSE (CLK_ID_GATE + 30) ++#define CLK_GATE_NEMC (CLK_ID_GATE + 31) ++#define CLK_GATE_ARB (CLK_ID_GATE + 32) ++#define CLK_GATE_MIPI (CLK_ID_GATE + 33) ++#define CLK_GATE_CPU (CLK_ID_GATE + 34) ++#define CLK_GATE_INTC (CLK_ID_GATE + 35) ++#define CLK_GATE_GPIO (CLK_ID_GATE + 36) ++#define CLK_GATE_SPDIF (CLK_ID_GATE + 37) ++#define CLK_GATE_DMIC (CLK_ID_GATE + 38) ++#define CLK_GATE_PCM (CLK_ID_GATE + 39) ++#define CLK_GATE_I2S3 (CLK_ID_GATE + 40) ++#define CLK_GATE_I2S2 (CLK_ID_GATE + 41) ++#define CLK_GATE_I2S1 (CLK_ID_GATE + 42) ++#define CLK_GATE_I2S0 (CLK_ID_GATE + 43) ++#define CLK_GATE_ROT (CLK_ID_GATE + 44) ++#define CLK_GATE_HASH (CLK_ID_GATE + 45) ++#define CLK_GATE_PWM (CLK_ID_GATE + 46) ++#define CLK_GATE_UART5 (CLK_ID_GATE + 47) ++#define CLK_GATE_UART4 (CLK_ID_GATE + 48) ++#define CLK_GATE_UART3 (CLK_ID_GATE + 49) ++#define CLK_GATE_SMB5 (CLK_ID_GATE + 50) ++#define CLK_GATE_SMB4 (CLK_ID_GATE + 51) ++#define CLK_GATE_USBPHY (CLK_ID_GATE + 52) ++#define CLK_GATE_MAC1 (CLK_ID_GATE + 53) ++#define CLK_GATE_MSC2 (CLK_ID_GATE + 54) ++#define CLK_GATE_VPU (CLK_ID_GATE + 55) ++#define CLK_NR_GATE (56) ++#define CLK_ID_OTHER (CLK_ID_GATE + CLK_NR_GATE) ++ ++#define NR_CLKS (CLK_NR_FIXED + CLK_NR_PLL + CLK_NR_CPCCR + CLK_NR_CGU + CLK_NR_CGU_AUDIO + CLK_NR_GATE) ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_clock_ingenic-x2000-v12.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_clock_ingenic-x2000-v12.h.patch new file mode 100644 index 00000000..62fcd700 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_clock_ingenic-x2000-v12.h.patch @@ -0,0 +1,203 @@ +diff -drupN a/include/dt-bindings/clock/ingenic-x2000-v12.h b/include/dt-bindings/clock/ingenic-x2000-v12.h +--- a/include/dt-bindings/clock/ingenic-x2000-v12.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/include/dt-bindings/clock/ingenic-x2000-v12.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,199 @@ ++#ifndef _DT_BINDINGS_CLOCK_X2000_V12_H ++#define _DT_BINDINGS_CLOCK_X2000_V12_H ++ ++/* Fixed Clk */ ++#define CLK_ID_FIEXED 0 ++#define CLK_EXT (CLK_ID_FIEXED + 0) ++#define CLK_RTC_EXT (CLK_ID_FIEXED + 1) ++#define CLK_NR_FIXED (2) ++ ++/* PLL clk */ ++#define CLK_ID_PLL (CLK_ID_FIEXED + CLK_NR_FIXED) ++#define CLK_PLL_APLL (CLK_ID_PLL + 0) ++#define CLK_PLL_MPLL (CLK_ID_PLL + 1) ++#define CLK_PLL_EPLL (CLK_ID_PLL + 2) ++#define CLK_NR_PLL (3) ++ ++/* MUX clk */ ++#define CLK_ID_MUX (CLK_ID_PLL + CLK_NR_PLL) ++#define CLK_MUX_SCLKA (CLK_ID_MUX + 0) ++#define CLK_MUX_CPU_L2C (CLK_ID_MUX + 1) ++#define CLK_MUX_AHB0 (CLK_ID_MUX + 2) ++#define CLK_MUX_AHB2 (CLK_ID_MUX + 3) ++#define CLK_MUX_DDR (CLK_ID_MUX + 4) ++#define CLK_MUX_MACPHY (CLK_ID_MUX + 5) ++#define CLK_MUX_MACTXPHY (CLK_ID_MUX + 6) ++#define CLK_MUX_MACTXPHY1 (CLK_ID_MUX + 7) ++#define CLK_MUX_I2S0 (CLK_ID_MUX + 8) ++#define CLK_MUX_I2S1 (CLK_ID_MUX + 9) ++#define CLK_MUX_I2S2 (CLK_ID_MUX + 10) ++#define CLK_MUX_I2S3 (CLK_ID_MUX + 11) ++#define CLK_MUX_AUDIO_RAM (CLK_ID_MUX + 12) ++#define CLK_MUX_SPDIF (CLK_ID_MUX + 13) ++#define CLK_MUX_PCM (CLK_ID_MUX + 14) ++#define CLK_MUX_DMIC (CLK_ID_MUX + 15) ++#define CLK_MUX_LCD (CLK_ID_MUX + 16) ++#define CLK_MUX_MSC0 (CLK_ID_MUX + 17) ++#define CLK_MUX_MSC1 (CLK_ID_MUX + 18) ++#define CLK_MUX_MSC2 (CLK_ID_MUX + 19) ++#define CLK_MUX_SFC (CLK_ID_MUX + 20) ++#define CLK_MUX_SSI (CLK_ID_MUX + 21) ++#define CLK_MUX_CIM (CLK_ID_MUX + 22) ++#define CLK_MUX_PWM (CLK_ID_MUX + 23) ++#define CLK_MUX_ISP (CLK_ID_MUX + 24) ++#define CLK_MUX_RSA (CLK_ID_MUX + 25) ++#define CLK_MUX_MACPTP (CLK_ID_MUX + 26) ++ ++ ++#define CLK_NR_MUX (27) ++ ++ ++#define CLK_ID_DIV (CLK_ID_MUX + CLK_NR_MUX) ++#define CLK_DIV_DDR (CLK_ID_DIV + 0) ++#define CLK_DIV_MACPHY (CLK_ID_DIV + 1) ++#define CLK_DIV_MACTXPHY (CLK_ID_DIV + 2) ++#define CLK_DIV_MACTXPHY1 (CLK_ID_DIV + 3) ++#define CLK_DIV_I2S0 (CLK_ID_DIV + 4) ++#define CLK_DIV_I2S1 (CLK_ID_DIV + 5) ++#define CLK_DIV_I2S2 (CLK_ID_DIV + 6) ++#define CLK_DIV_I2S3 (CLK_ID_DIV + 7) ++#define CLK_DIV_LCD (CLK_ID_DIV + 8) ++#define CLK_DIV_MSC0 (CLK_ID_DIV + 9) ++#define CLK_DIV_MSC1 (CLK_ID_DIV + 10) ++#define CLK_DIV_MSC2 (CLK_ID_DIV + 11) ++#define CLK_DIV_SFC (CLK_ID_DIV + 12) ++#define CLK_DIV_SSI (CLK_ID_DIV + 13) ++#define CLK_DIV_CIM (CLK_ID_DIV + 14) ++#define CLK_DIV_PWM (CLK_ID_DIV + 15) ++#define CLK_DIV_ISP (CLK_ID_DIV + 16) ++#define CLK_DIV_RSA (CLK_ID_DIV + 17) ++#define CLK_DIV_MACPTP (CLK_ID_DIV + 18) ++ ++#define CLK_DIV_CPU (CLK_ID_DIV + 19) ++#define CLK_DIV_L2C (CLK_ID_DIV + 20) ++#define CLK_DIV_AHB0 (CLK_ID_DIV + 21) ++#define CLK_DIV_AHB2 (CLK_ID_DIV + 22) ++#define CLK_DIV_APB (CLK_ID_DIV + 23) ++#define CLK_DIV_CPU_L2C_X1 (CLK_ID_DIV + 24) ++#define CLK_DIV_CPU_L2C_X2 (CLK_ID_DIV + 25) ++ ++#define CLK_NR_DIV (26) ++ ++ ++/* Gate Clocks */ ++#define CLK_ID_GATE (CLK_ID_DIV + CLK_NR_DIV) ++#define CLK_GATE_DDR (CLK_ID_GATE + 0) ++#define CLK_GATE_IPU (CLK_ID_GATE + 1) ++#define CLK_GATE_AHB0 (CLK_ID_GATE + 2) ++#define CLK_GATE_APB0 (CLK_ID_GATE + 3) ++#define CLK_GATE_RTC (CLK_ID_GATE + 4) ++#define CLK_GATE_SSI1 (CLK_ID_GATE + 5) ++#define CLK_GATE_RSA (CLK_ID_GATE + 6) ++#define CLK_GATE_AES (CLK_ID_GATE + 7) ++#define CLK_GATE_LCD (CLK_ID_GATE + 8) ++#define CLK_GATE_CIM (CLK_ID_GATE + 9) ++#define CLK_GATE_PDMA (CLK_ID_GATE + 10) ++#define CLK_GATE_OST (CLK_ID_GATE + 11) ++#define CLK_GATE_SSI0 (CLK_ID_GATE + 12) ++#define CLK_GATE_TCU (CLK_ID_GATE + 13) ++#define CLK_GATE_DTRNG (CLK_ID_GATE + 14) ++#define CLK_GATE_UART2 (CLK_ID_GATE + 15) ++#define CLK_GATE_UART1 (CLK_ID_GATE + 16) ++#define CLK_GATE_UART0 (CLK_ID_GATE + 17) ++#define CLK_GATE_SADC (CLK_ID_GATE + 18) ++#define CLK_GATE_HELIX (CLK_ID_GATE + 19) ++#define CLK_GATE_AUDIO (CLK_ID_GATE + 20) ++#define CLK_GATE_SMB3 (CLK_ID_GATE + 21) ++#define CLK_GATE_SMB2 (CLK_ID_GATE + 22) ++#define CLK_GATE_SMB1 (CLK_ID_GATE + 23) ++#define CLK_GATE_SMB0 (CLK_ID_GATE + 24) ++#define CLK_GATE_SCC (CLK_ID_GATE + 25) ++#define CLK_GATE_MSC1 (CLK_ID_GATE + 26) ++#define CLK_GATE_MSC0 (CLK_ID_GATE + 27) ++#define CLK_GATE_OTG (CLK_ID_GATE + 28) ++#define CLK_GATE_SFC (CLK_ID_GATE + 29) ++#define CLK_GATE_EFUSE (CLK_ID_GATE + 30) ++#define CLK_GATE_NEMC (CLK_ID_GATE + 31) ++#define CLK_GATE_ARB (CLK_ID_GATE + 32) ++#define CLK_GATE_MIPI_DSI (CLK_ID_GATE + 33) ++#define CLK_GATE_MIPI_CSI (CLK_ID_GATE + 34) ++#define CLK_GATE_INTC (CLK_ID_GATE + 35) ++#define CLK_GATE_MSC2 (CLK_ID_GATE + 36) ++#define CLK_GATE_GMAC1 (CLK_ID_GATE + 37) ++#define CLK_GATE_GMAC0 (CLK_ID_GATE + 38) ++#define CLK_GATE_UART9 (CLK_ID_GATE + 39) ++#define CLK_GATE_UART8 (CLK_ID_GATE + 40) ++#define CLK_GATE_UART7 (CLK_ID_GATE + 41) ++#define CLK_GATE_UATR6 (CLK_ID_GATE + 42) ++#define CLK_GATE_UART5 (CLK_ID_GATE + 43) ++#define CLK_GATE_UART4 (CLK_ID_GATE + 44) ++#define CLK_GATE_UART3 (CLK_ID_GATE + 45) ++#define CLK_GATE_SPDIF (CLK_ID_GATE + 46) ++#define CLK_GATE_DMIC (CLK_ID_GATE + 47) ++#define CLK_GATE_PCM (CLK_ID_GATE + 48) ++#define CLK_GATE_I2S3 (CLK_ID_GATE + 49) ++#define CLK_GATE_I2S2 (CLK_ID_GATE + 50) ++#define CLK_GATE_I2S1 (CLK_ID_GATE + 51) ++#define CLK_GATE_I2S0 (CLK_ID_GATE + 52) ++#define CLK_GATE_ROT (CLK_ID_GATE + 53) ++#define CLK_GATE_HASH (CLK_ID_GATE + 54) ++#define CLK_GATE_PWM (CLK_ID_GATE + 55) ++#define CLK_GATE_FELIX (CLK_ID_GATE + 56) ++#define CLK_GATE_ISP1 (CLK_ID_GATE + 57) ++#define CLK_GATE_ISP0 (CLK_ID_GATE + 58) ++#define CLK_GATE_SMB5 (CLK_ID_GATE + 59) ++#define CLK_GATE_SMB4 (CLK_ID_GATE + 60) ++#define CLK_GATE_USBPHY (CLK_ID_GATE + 61) ++#define CLK_CE_I2S0 (CLK_ID_GATE + 62) ++#define CLK_CE_I2S1 (CLK_ID_GATE + 63) ++#define CLK_CE_I2S2 (CLK_ID_GATE + 64) ++#define CLK_CE_I2S3 (CLK_ID_GATE + 65) ++#define CLK_NR_GATE (66) ++ ++#define POWER_ID (CLK_ID_GATE + CLK_NR_GATE) ++#define POWER_ISP0 (POWER_ID + 0) ++#define POWER_ISP1 (POWER_ID + 1) ++#define POWER_FELIX (POWER_ID + 2) ++#define POWER_HELIX (POWER_ID + 3) ++ ++#define PD_MEM_NEMC (POWER_ID + 4) ++#define PD_MEM_USB (POWER_ID + 5) ++#define PD_MEM_SFC (POWER_ID + 6) ++#define PD_MEM_PDMA_SEC (POWER_ID + 7) ++#define PD_MEM_PDMA (POWER_ID + 8) ++#define PD_MEM_MSC2 (POWER_ID + 9) ++#define PD_MEM_MSC1 (POWER_ID + 10) ++#define PD_MEM_MSC0 (POWER_ID + 11) ++#define PD_MEM_GMAC1 (POWER_ID + 12) ++#define PD_MEM_GMAC0 (POWER_ID + 13) ++#define PD_MEM_DMIC (POWER_ID + 14) ++#define PD_MEM_AUDIO (POWER_ID + 15) ++#define PD_MEM_AES (POWER_ID + 16) ++#define PD_MEM_DSI (POWER_ID + 17) ++#define PD_MEM_SSI1 (POWER_ID + 18) ++#define PD_MEM_SSI0 (POWER_ID + 19) ++#define PD_MEM_UART9 (POWER_ID + 20) ++#define PD_MEM_UART8 (POWER_ID + 21) ++#define PD_MEM_UART7 (POWER_ID + 22) ++#define PD_MEM_UART6 (POWER_ID + 23) ++#define PD_MEM_UART5 (POWER_ID + 24) ++#define PD_MEM_UART4 (POWER_ID + 25) ++#define PD_MEM_UART3 (POWER_ID + 26) ++#define PD_MEM_UART2 (POWER_ID + 27) ++#define PD_MEM_UART1 (POWER_ID + 28) ++#define PD_MEM_UART0 (POWER_ID + 29) ++#define PD_MEM_ROT (POWER_ID + 30) ++#define PD_MEM_CIM (POWER_ID + 31) ++#define PD_MEM_DPU (POWER_ID + 32) ++#define PD_MEM_DDR_CH6 (POWER_ID + 33) ++#define PD_MEM_DDR_CH5 (POWER_ID + 34) ++#define PD_MEM_DDR_CH3 (POWER_ID + 35) ++#define PD_MEM_DDR_CH1 (POWER_ID + 36) ++#define PD_MEM_DDR_CH0 (POWER_ID + 37) ++#define PD_MEM_DDR_TOP (POWER_ID + 38) ++#define CLK_NR_POWER (39) ++ ++#define CLK_ID_OTHER (POWER_ID + CLK_NR_POWER) ++ ++#define NR_CLKS (CLK_NR_FIXED + CLK_NR_PLL + CLK_NR_MUX + CLK_NR_DIV + CLK_NR_GATE + CLK_NR_POWER) ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_clock_ingenic-x2000.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_clock_ingenic-x2000.h.patch new file mode 100644 index 00000000..f1c03235 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_clock_ingenic-x2000.h.patch @@ -0,0 +1,115 @@ +diff -drupN a/include/dt-bindings/clock/ingenic-x2000.h b/include/dt-bindings/clock/ingenic-x2000.h +--- a/include/dt-bindings/clock/ingenic-x2000.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/include/dt-bindings/clock/ingenic-x2000.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,111 @@ ++#ifndef _DT_BINDINGS_CLOCK_M200_H ++#define _DT_BINDINGS_CLOCK_M200_H ++ ++/* Fixed Clk */ ++#define CLK_ID_FIEXED 0 ++#define CLK_EXT (CLK_ID_FIEXED + 0) ++#define CLK_RTC_EXT (CLK_ID_FIEXED + 1) ++#define CLK_NR_FIXED (2) ++ ++/* PLL clk */ ++#define CLK_ID_PLL (CLK_ID_FIEXED + CLK_NR_FIXED) ++#define CLK_PLL_APLL (CLK_ID_PLL + 0) ++#define CLK_PLL_MPLL (CLK_ID_PLL + 1) ++#define CLK_PLL_EPLL (CLK_ID_PLL + 2) ++#define CLK_NR_PLL (3) ++ ++/* CPU Clocks */ ++#define CLK_ID_CPCCR (CLK_ID_PLL + CLK_NR_PLL) ++#define CLK_MUX_SCLKA (CLK_ID_CPCCR + 0) ++#define CLK_MUX_CPLL (CLK_ID_CPCCR + 1) ++#define CLK_MUX_H0PLL (CLK_ID_CPCCR + 2) ++#define CLK_MUX_H2PLL (CLK_ID_CPCCR + 3) ++#define CLK_RATE_CPUCLK (CLK_ID_CPCCR + 4) ++#define CLK_RATE_L2CCLK (CLK_ID_CPCCR + 5) ++#define CLK_RATE_H0CLK (CLK_ID_CPCCR + 6) ++#define CLK_RATE_H2CLK (CLK_ID_CPCCR + 7) ++#define CLK_RATE_PCLK (CLK_ID_CPCCR + 8) ++#define CLK_NR_CPCCR (9) ++ ++/* CGU clocks */ ++#define CLK_ID_CGU (CLK_ID_CPCCR + CLK_NR_CPCCR) ++#define CLK_CGU_DDR (CLK_ID_CGU + 0) ++#define CLK_CGU_MAC (CLK_ID_CGU + 1) ++#define CLK_CGU_LCD (CLK_ID_CGU + 2) ++#define CLK_CGU_MSC0 (CLK_ID_CGU + 3) ++#define CLK_CGU_MSC1 (CLK_ID_CGU + 4) ++#define CLK_CGU_SFC (CLK_ID_CGU + 5) ++#define CLK_CGU_CIM (CLK_ID_CGU + 6) ++#define CLK_CGU_PWM (CLK_ID_CGU + 7) ++#define CLK_NR_CGU (8) ++ ++#define CLK_ID_CGU_AUDIO (CLK_ID_CGU + CLK_NR_CGU) ++#define CLK_CGU_I2S0 (CLK_ID_CGU_AUDIO + 0) ++#define CLK_CGU_I2S1 (CLK_ID_CGU_AUDIO + 1) ++#define CLK_CGU_I2S2 (CLK_ID_CGU_AUDIO + 2) ++#define CLK_CGU_I2S3 (CLK_ID_CGU_AUDIO + 3) ++#define CLK_CGU_SPDIF (CLK_ID_CGU_AUDIO + 4) ++#define CLK_CGU_PCM (CLK_ID_CGU_AUDIO + 5) ++#define CLK_CGU_DMIC (CLK_ID_CGU_AUDIO + 6) ++#define CLK_NR_CGU_AUDIO (7) ++ ++/* Gate Clocks */ ++#define CLK_ID_GATE (CLK_ID_CGU_AUDIO + CLK_NR_CGU_AUDIO) ++#define CLK_GATE_DDR (CLK_ID_GATE + 0) ++#define CLK_GATE_CPU1 (CLK_ID_GATE + 1) ++#define CLK_GATE_AHB0 (CLK_ID_GATE + 2) ++#define CLK_GATE_APB0 (CLK_ID_GATE + 3) ++#define CLK_GATE_RTC (CLK_ID_GATE + 4) ++#define CLK_GATE_SSI1 (CLK_ID_GATE + 5) ++#define CLK_GATE_MAC (CLK_ID_GATE + 6) ++#define CLK_GATE_AES (CLK_ID_GATE + 7) ++#define CLK_GATE_LCD (CLK_ID_GATE + 8) ++#define CLK_GATE_CIM (CLK_ID_GATE + 9) ++#define CLK_GATE_PDMA (CLK_ID_GATE + 10) ++#define CLK_GATE_OST (CLK_ID_GATE + 11) ++#define CLK_GATE_SSI0 (CLK_ID_GATE + 12) ++#define CLK_GATE_TCU (CLK_ID_GATE + 13) ++#define CLK_GATE_DTRNG (CLK_ID_GATE + 14) ++#define CLK_GATE_UART2 (CLK_ID_GATE + 15) ++#define CLK_GATE_UART1 (CLK_ID_GATE + 16) ++#define CLK_GATE_UART0 (CLK_ID_GATE + 17) ++#define CLK_GATE_SADC (CLK_ID_GATE + 18) ++#define CLK_GATE_JPEG (CLK_ID_GATE + 19) ++#define CLK_GATE_AUDIO (CLK_ID_GATE + 20) ++#define CLK_GATE_SMB3 (CLK_ID_GATE + 21) ++#define CLK_GATE_SMB2 (CLK_ID_GATE + 22) ++#define CLK_GATE_SMB1 (CLK_ID_GATE + 23) ++#define CLK_GATE_SMB0 (CLK_ID_GATE + 24) ++#define CLK_GATE_SCC (CLK_ID_GATE + 25) ++#define CLK_GATE_MSC1 (CLK_ID_GATE + 26) ++#define CLK_GATE_MSC0 (CLK_ID_GATE + 27) ++#define CLK_GATE_OTG (CLK_ID_GATE + 28) ++#define CLK_GATE_SFC (CLK_ID_GATE + 29) ++#define CLK_GATE_EFUSE (CLK_ID_GATE + 30) ++#define CLK_GATE_NEMC (CLK_ID_GATE + 31) ++#define CLK_GATE_ARB (CLK_ID_GATE + 32) ++#define CLK_GATE_MIPI (CLK_ID_GATE + 33) ++#define CLK_GATE_CPU (CLK_ID_GATE + 34) ++#define CLK_GATE_INTC (CLK_ID_GATE + 35) ++#define CLK_GATE_GPIO (CLK_ID_GATE + 36) ++#define CLK_GATE_SPDIF (CLK_ID_GATE + 37) ++#define CLK_GATE_DMIC (CLK_ID_GATE + 38) ++#define CLK_GATE_PCM (CLK_ID_GATE + 39) ++#define CLK_GATE_I2S3 (CLK_ID_GATE + 40) ++#define CLK_GATE_I2S2 (CLK_ID_GATE + 41) ++#define CLK_GATE_I2S1 (CLK_ID_GATE + 42) ++#define CLK_GATE_I2S0 (CLK_ID_GATE + 43) ++#define CLK_GATE_ROT (CLK_ID_GATE + 44) ++#define CLK_GATE_HASH (CLK_ID_GATE + 45) ++#define CLK_GATE_PWM (CLK_ID_GATE + 46) ++#define CLK_GATE_UART5 (CLK_ID_GATE + 47) ++#define CLK_GATE_UART4 (CLK_ID_GATE + 48) ++#define CLK_GATE_UART3 (CLK_ID_GATE + 49) ++#define CLK_GATE_SMB5 (CLK_ID_GATE + 50) ++#define CLK_GATE_SMB4 (CLK_ID_GATE + 51) ++#define CLK_GATE_USBPHY (CLK_ID_GATE + 52) ++#define CLK_NR_GATE (53) ++#define CLK_ID_OTHER (CLK_ID_GATE + CLK_NR_GATE) ++ ++#define NR_CLKS (CLK_NR_FIXED + CLK_NR_PLL + CLK_NR_CPCCR + CLK_NR_CGU + CLK_NR_CGU_AUDIO + CLK_NR_GATE) ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_dma_ingenic-pdma.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_dma_ingenic-pdma.h.patch new file mode 100644 index 00000000..ad232cae --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_dma_ingenic-pdma.h.patch @@ -0,0 +1,51 @@ +diff -drupN a/include/dt-bindings/dma/ingenic-pdma.h b/include/dt-bindings/dma/ingenic-pdma.h +--- a/include/dt-bindings/dma/ingenic-pdma.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/include/dt-bindings/dma/ingenic-pdma.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,47 @@ ++#ifndef __INGENIC_PDMA_H__ ++#define __INGENIC_PDMA_H__ ++ ++#define INGENIC_DMA_REQ_AIC_LOOP_RX 0x5 ++#define INGENIC_DMA_REQ_AIC_TX 0x6 ++#define INGENIC_DMA_REQ_AIC_F_RX 0x7 ++#define INGENIC_DMA_REQ_AUTO_TX 0x8 ++#define INGENIC_DMA_REQ_SADC_RX 0x9 ++#define INGENIC_DMA_REQ_DMIC_RX 0xd ++#define INGENIC_DMA_REQ_UART3_TX 0xe ++#define INGENIC_DMA_REQ_UART3_RX 0xf ++#define INGENIC_DMA_REQ_UART2_TX 0x10 ++#define INGENIC_DMA_REQ_UART2_RX 0x11 ++#define INGENIC_DMA_REQ_UART1_TX 0x12 ++#define INGENIC_DMA_REQ_UART1_RX 0x13 ++#define INGENIC_DMA_REQ_UART0_TX 0x14 ++#define INGENIC_DMA_REQ_UART0_RX 0x15 ++#define INGENIC_DMA_REQ_SSI0_TX 0x16 ++#define INGENIC_DMA_REQ_SSI0_RX 0x17 ++#define INGENIC_DMA_REQ_SSI1_TX 0x18 ++#define INGENIC_DMA_REQ_SSI1_RX 0x19 ++#define INGENIC_DMA_REQ_SLV_TX 0x1a ++#define INGENIC_DMA_REQ_SLV_RX 0x1b ++#define INGENIC_DMA_REQ_I2C0_TX 0x24 ++#define INGENIC_DMA_REQ_I2C0_RX 0x25 ++#define INGENIC_DMA_REQ_I2C1_TX 0x26 ++#define INGENIC_DMA_REQ_I2C1_RX 0x27 ++#define INGENIC_DMA_REQ_I2C2_TX 0x28 ++#define INGENIC_DMA_REQ_I2C2_RX 0x29 ++#define INGENIC_DMA_REQ_I2C3_TX 0x2a ++#define INGENIC_DMA_REQ_I2C3_RX 0x2b ++#define INGENIC_DMA_REQ_DES_TX 0x2e ++#define INGENIC_DMA_REQ_DES_RX 0x2f ++ ++#define INGENIC_DMA_TYPE_REQ_MSK 0xff ++#define INGENIC_DMA_TYPE_CH_SFT 8 ++#define INGENIC_DMA_TYPE_CH_MSK (0xff << INGENIC_DMA_TYPE_CH_SFT) ++#define INGENIC_DMA_TYPE_CH_EN (1 << 16) ++#define INGENIC_DMA_TYPE_PROG (1 << 17) ++#define INGENIC_DMA_TYPE_SPEC (1 << 18) ++ ++#define INGENIC_DMA_CH(ch) ((((ch) << INGENIC_DMA_TYPE_CH_SFT) & INGENIC_DMA_TYPE_CH_MSK) | INGENIC_DMA_TYPE_CH_EN) ++#define INGENIC_DMA_TYPE(type) ((type) & INGENIC_DMA_TYPE_REQ_MSK) ++#define INGENIC_DMA_TYPE_CH(type, ch) (INGENIC_DMA_TYPE((type)) | INGENIC_DMA_CH((ch))) ++#define INGENIC_DMA_PG_CH(type, ch) (INGENIC_DMA_TYPE_CH((type), (ch)) | INGENIC_DMA_TYPE_PROG_MSK) ++#define INGENIC_DMA_SP_CH(type, ch) (INGENIC_DMA_PG_CH(type, id) | INGENIC_DMA_TYPE_SPEC_MSK) ++#endif /* __INGENIC_PDMA_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_interrupt-controller_mips-irq.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_interrupt-controller_mips-irq.h.patch new file mode 100644 index 00000000..443bfb59 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_interrupt-controller_mips-irq.h.patch @@ -0,0 +1,20 @@ +diff -drupN a/include/dt-bindings/interrupt-controller/mips-irq.h b/include/dt-bindings/interrupt-controller/mips-irq.h +--- a/include/dt-bindings/interrupt-controller/mips-irq.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/include/dt-bindings/interrupt-controller/mips-irq.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,16 @@ ++#ifndef _DT_BINDINGS_INTERRUPT_CONTROLLER_MIPS_IRQ_H ++#define _DT_BINDINGS_INTERRUPT_CONTROLLER_MIPS_IRQ_H ++ ++#define MIPS_CPU_IRQ_BASE (0) ++ ++#define CORE_INTC_IRQ (MIPS_CPU_IRQ_BASE + 2) ++#define CORE_MAILBOX_IRQ (MIPS_CPU_IRQ_BASE + 3) ++#define CORE_SYS_OST_IRQ (MIPS_CPU_IRQ_BASE + 4) ++ ++#define CORE_IRQS_END (7) ++ ++#define INTC_NR_IRQS (64) ++#define IRQ_INTC_BASE (CORE_IRQS_END + 1) ++#define IRQ_INTC_END (IRQ_INTC_BASE + INTC_NR_IRQS - 1) ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_interrupt-controller_t40-irq.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_interrupt-controller_t40-irq.h.patch new file mode 100644 index 00000000..6048eff4 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_interrupt-controller_t40-irq.h.patch @@ -0,0 +1,78 @@ +diff -drupN a/include/dt-bindings/interrupt-controller/t40-irq.h b/include/dt-bindings/interrupt-controller/t40-irq.h +--- a/include/dt-bindings/interrupt-controller/t40-irq.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/include/dt-bindings/interrupt-controller/t40-irq.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,74 @@ ++#ifndef _DT_BINDINGS_INTERRUPT_CONTROLLER_T40_IRQ_H ++#define _DT_BINDINGS_INTERRUPT_CONTROLLER_T40_IRQ_H ++ ++#include ++ ++#define IRQ_RESERVED0 (0) ++#define IRQ_AIC0 (1) ++#define IRQ_SYS_LEP (2) /* RISC-V */ ++#define IRQ_MIPI_DSI (3) ++#define IRQ_MIPI_RX_4L (4) ++#define IRQ_MIPI_RX_2L (5) ++#define IRQ_IPU (6) ++#define IRQ_SFC (7) ++#define IRQ_SSI1 (8) ++#define IRQ_SSI0 (9) ++#define IRQ_PDMA (10) ++#define IRQ_SSISLV (11) ++#define IRQ_DMIC (12) ++#define IRQ_RESERVED13 (13) ++#define IRQ_GPIO3 (14) ++#define IRQ_GPIO2 (15) ++#define IRQ_GPIO1 (16) ++#define IRQ_GPIO0 (17) ++#define IRQ_GPIO_PORT(N) (IRQ_GPIO0 - (N)) ++#define IRQ_SADC (18) ++#define IRQ_RESERVED19 (19) ++#define IRQ_LCD (20) ++#define IRQ_OTG (21) ++#define IRQ_HASH (22) ++#define IRQ_AES (23) ++#define IRQ_RSA (24) ++#define IRQ_TCU2 (25) ++#define IRQ_TCU1 (26) ++#define IRQ_TCU0 (27) ++#define IRQ_S2_VIC (28) ++#define IRQ_S1_VIC (29) ++#define IRQ_S0_VIC (30) ++#define IRQ_ISP (31) ++ ++#define IRQ_RESERVED32 (32 + 0) ++#define IRQ_RESERVED33 (32 + 1) ++#define IRQ_DTRNG (32 + 2) ++#define IRQ_RESERVED35 (32 + 3) ++#define IRQ_MSC1 (32 + 4) ++#define IRQ_MSC0 (32 + 5) ++#define IRQ_RESERVED38 (32 + 6) ++#define IRQ_BSCALER1 (32 + 7) ++#define IRQ_BSCALER0 (32 + 8) ++#define IRQ_DDR_DWU (32 + 9) ++#define IRQ_DRAW_BOX (32 + 10) ++#define IRQ_VO (32 + 11) ++#define IRQ_HARB2 (32 + 12) ++#define IRQ_I2D (32 + 13) ++#define IRQ_RESERVED46 (32 + 14) ++#define IRQ_CPM (32 + 15) ++#define IRQ_UART3 (32 + 16) ++#define IRQ_UART2 (32 + 17) ++#define IRQ_UART1 (32 + 18) ++#define IRQ_UART0 (32 + 19) ++#define IRQ_DDR (32 + 20) ++#define IRQ_MON (32 + 21) ++#define IRQ_EFUSE (32 + 22) ++#define IRQ_GMAC0 (32 + 23) ++#define IRQ_RESERVED56 (32 + 24) ++#define IRQ_I2C3 (32 + 25) ++#define IRQ_I2C2 (32 + 26) ++#define IRQ_I2C1 (32 + 27) ++#define IRQ_I2C0 (32 + 28) ++#define IRQ_PDMAM (32 + 29) ++#define IRQ_EL150 (32 + 30) ++#define IRQ_RADIX (32 + 31) ++ ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_interrupt-controller_x2000-v12-irq.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_interrupt-controller_x2000-v12-irq.h.patch new file mode 100644 index 00000000..2a57188d --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_interrupt-controller_x2000-v12-irq.h.patch @@ -0,0 +1,76 @@ +diff -drupN a/include/dt-bindings/interrupt-controller/x2000-v12-irq.h b/include/dt-bindings/interrupt-controller/x2000-v12-irq.h +--- a/include/dt-bindings/interrupt-controller/x2000-v12-irq.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/include/dt-bindings/interrupt-controller/x2000-v12-irq.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,72 @@ ++#ifndef _DT_BINDINGS_INTERRUPT_CONTROLLER_X2000_V12_IRQ_H ++#define _DT_BINDINGS_INTERRUPT_CONTROLLER_X2000_V12_IRQ_H ++ ++#include ++ ++#define IRQ_AUDIO (0) ++#define IRQ_OTG (1) ++#define IRQ_RESERVED0_2 (2) ++#define IRQ_PDMA (3) ++#define IRQ_PDMAD (4) ++#define IRQ_PDMAM (5) ++#define IRQ_PWM (6) ++#define IRQ_SFC (7) ++#define IRQ_SSI1 (8) ++#define IRQ_SSI0 (9) ++#define IRQ_MIPI_DSI (10) ++#define IRQ_SADC (11) ++#define IRQ_MIPI_CSI_4 (12) ++#define IRQ_GPIO4 (13) ++#define IRQ_GPIO3 (14) ++#define IRQ_GPIO2 (15) ++#define IRQ_GPIO1 (16) ++#define IRQ_GPIO0 (17) ++#define IRQ_VIC1 (18) ++#define IRQ_VIC0 (19) ++#define IRQ_ISP1 (20) ++#define IRQ_ISP0 (21) ++#define IRQ_HASH (22) ++#define IRQ_AES (23) ++#define IRQ_RSA (24) ++#define IRQ_TCU2 (25) ++#define IRQ_TCU1 (26) ++#define IRQ_TCU0 (27) ++#define IRQ_MIPI_CSI2 (28) ++#define IRQ_ROTATE (29) ++#define IRQ_CIM (30) ++#define IRQ_LCD (31) ++ ++#define IRQ_RTC (32 + 0) ++#define IRQ_SOFT (32 + 1) ++#define IRQ_DTRNG (32 + 2) ++#define IRQ_SCC (32 + 3) ++#define IRQ_MSC1 (32 + 4) ++#define IRQ_MSC0 (32 + 5) ++#define IRQ_UART9 (32 + 6) ++#define IRQ_UART8 (32 + 7) ++#define IRQ_UART7 (32 + 8) ++#define IRQ_UART6 (32 + 9) ++#define IRQ_UART5 (32 + 10) ++#define IRQ_UART4 (32 + 11) ++#define IRQ_UART3 (32 + 12) ++#define IRQ_UART2 (32 + 13) ++#define IRQ_UART1 (32 + 14) ++#define IRQ_UART0 (32 + 15) ++#define IRQ_MSC2 (32 + 16) ++#define IRQ_HARB2 (32 + 17) ++#define IRQ_HARB0 (32 + 18) ++#define IRQ_CPM (32 + 19) ++#define IRQ_DDR (32 + 20) ++#define IRQ_GMAC1 (32 + 21) ++#define IRQ_EFUSE (32 + 22) ++#define IRQ_GMAC0 (32 + 23) ++#define IRQ_I2C5 (32 + 24) ++#define IRQ_I2C4 (32 + 25) ++#define IRQ_I2C3 (32 + 26) ++#define IRQ_I2C2 (32 + 27) ++#define IRQ_I2C1 (32 + 28) ++#define IRQ_I2C0 (32 + 29) ++#define IRQ_HELIX (32 + 30) ++#define IRQ_FELIX (32 + 31) ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_net_ingenic_gmac.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_net_ingenic_gmac.h.patch new file mode 100644 index 00000000..9fdfa88c --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_net_ingenic_gmac.h.patch @@ -0,0 +1,13 @@ +diff -drupN a/include/dt-bindings/net/ingenic_gmac.h b/include/dt-bindings/net/ingenic_gmac.h +--- a/include/dt-bindings/net/ingenic_gmac.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/include/dt-bindings/net/ingenic_gmac.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,9 @@ ++#ifndef __INGENIC_GMAC_H__ ++#define __INGENIC_GMAC_H__ ++ ++#define GMII 0 ++#define RGMII 1 ++#define MII 2 ++#define RMII 4 ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_pinctrl_ingenic-pinctrl.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_pinctrl_ingenic-pinctrl.h.patch new file mode 100644 index 00000000..4ed4fc03 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_pinctrl_ingenic-pinctrl.h.patch @@ -0,0 +1,78 @@ +diff -drupN a/include/dt-bindings/pinctrl/ingenic-pinctrl.h b/include/dt-bindings/pinctrl/ingenic-pinctrl.h +--- a/include/dt-bindings/pinctrl/ingenic-pinctrl.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/include/dt-bindings/pinctrl/ingenic-pinctrl.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,74 @@ ++#ifndef _DT_INGENIC_PINCTL_H__ ++#define _DT_INGENIC_PINCTL_H__ ++#include ++ ++#define PINCTL_FUNCTION0 0 ++#define PINCTL_FUNCTION1 1 ++#define PINCTL_FUNCTION2 2 ++#define PINCTL_FUNCTION3 3 ++#define PINCTL_FUNCHILVL 4 ++#define PINCTL_FUNCLOLVL 5 ++#define PINCTL_FUNCINPUT 6 ++#define PINCTL_FUNCTIONS 7 ++ ++ ++#define PINCTL_CFG_TYPES 1 ++ ++/* Used in device tree for gpio function settings. ingenic,pincfg*/ ++#define PINCTL_CFG_BIAS_DISABLE 1 ++#define PINCTL_CFG_BIAS_HIGH_IMPEDANCE 2 ++#define PINCTL_CFG_BIAS_PULL_DOWN 3 ++#define PINCTL_CFG_BIAS_PULL_PIN_DEFAULT 4 ++#define PINCTL_CFG_BIAS_PULL_UP 5 ++#define PINCTL_CFG_DRIVE_STRENGTH 9 ++#define PINCTL_CFG_FILTER 10 ++#define PINCTL_CFG_INPUT_SCHMITT_ENABLE 11 ++#define PINCTL_CFG_SLEW_RATE 17 ++ ++#define PINCTL_CFG_TYPE_MSK 0xFFFF ++#define PINCTL_CFGVAL_SFT 16 ++#define PINCTL_CFGVAL_MSK (0xFFFF << PINCTL_CFGVAL_SFT) ++ ++#define PINCFG_PACK(type, value) (((value) << PINCTL_CFGVAL_SFT) | type) ++#define PINCFG_UNPACK_TYPE(cfg) ((cfg) & PINCTL_CFG_TYPE_MSK) ++#define PINCFG_UNPACK_VALUE(cfg) (((cfg) & PINCTL_CFGVAL_MSK) >> \ ++ PINCTL_CFGVAL_SFT) ++ ++#define PINCTL_NOBIAS ((0 << PINCTL_CFGVAL_SFT) | PINCTL_CFG_PULL) ++#define PINCTL_PULLEN ((1 << PINCTL_CFGVAL_SFT) | PINCTL_CFG_PULL) ++ ++ ++/* Used in device tree for gpio settings. eg, <&gpb 0, GPIO_ACTIVE_LOW INGENIC_GPIO_PULL_UP | INGENIC_GPIO_DS_0> */ ++#define INGENIC_GPIO_BIAS_MASK 0x7 ++#define INGENIC_GPIO_BIAS_SFT 0 ++#define INGENIC_GPIO_NOBIAS (0 << INGENIC_GPIO_BIAS_SFT) ++#define INGENIC_GPIO_PULLEN (1 << INGENIC_GPIO_BIAS_SFT) ++#define INGENIC_GPIO_PULLUP (2 << INGENIC_GPIO_BIAS_SFT) ++#define INGENIC_GPIO_PULLDOWN (3 << INGENIC_GPIO_BIAS_SFT) ++#define INGENIC_GPIO_HIZ (4 << INGENIC_GPIO_BIAS_SFT) ++ ++#define INGENIC_GPIO_DS_SFT 3 ++#define INGENIC_GPIO_DS_MSK 0x7 ++#define INGENIC_GPIO_DS_0 (0 << INGENIC_GPIO_DS_SFT) ++#define INGENIC_GPIO_DS_1 (1 << INGENIC_GPIO_DS_SFT) ++#define INGENIC_GPIO_DS_2 (2 << INGENIC_GPIO_DS_SFT) ++#define INGENIC_GPIO_DS_3 (3 << INGENIC_GPIO_DS_SFT) ++#define INGENIC_GPIO_DS_4 (4 << INGENIC_GPIO_DS_SFT) ++#define INGENIC_GPIO_DS_5 (5 << INGENIC_GPIO_DS_SFT) ++#define INGENIC_GPIO_DS_6 (6 << INGENIC_GPIO_DS_SFT) ++#define INGENIC_GPIO_DS_7 (7 << INGENIC_GPIO_DS_SFT) ++ ++#define INGENIC_GPIO_SLEW_RATE_SFT 6 ++#define INGENIC_GPIO_SLEW_RATE (1 << INGENIC_GPIO_SLEW_RATE_SFT) ++ ++#define INGENIC_GPIO_SCHMITT_SFT 7 ++#define INGENIC_GPIO_SCHMITT (1 << INGENIC_GPIO_SCHMITT_SFT) ++ ++/* Use in pinctrl drivers.*/ ++#define INGENIC_GPIO_PULL(x) (((x) >> INGENIC_GPIO_BIAS_SFT) & INGENIC_GPIO_BIAS_MASK) ++#define INGENIC_GPIO_DRIVE_STRENGTH(x) (((x) >> INGENIC_GPIO_DS_SFT) & INGENIC_GPIO_DS_MSK) ++#define INGENIC_GPIO_SCHMITT_ENABLE(x) ((x) >> INGENIC_GPIO_SCHMITT_SFT) ++#define INGENIC_GPIO_SLEW_RATE_ENABLE(x) ((x) >> INGENIC_GPIO_SLEW_RATE_SFT) ++ ++ ++#endif /*_DT_INGENIC_PINCTL_H__*/ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_sound_ingenic-baic.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_sound_ingenic-baic.h.patch new file mode 100644 index 00000000..50385d61 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_dt-bindings_sound_ingenic-baic.h.patch @@ -0,0 +1,38 @@ +diff -drupN a/include/dt-bindings/sound/ingenic-baic.h b/include/dt-bindings/sound/ingenic-baic.h +--- a/include/dt-bindings/sound/ingenic-baic.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/include/dt-bindings/sound/ingenic-baic.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,34 @@ ++#ifndef __INGENIC_BAIC_H__ ++#define __INGENIC_BAIC_H__ ++ ++#undef BIT ++#define BIT(n) (1 << (n)) ++#define BAIC_DAIFMT_NO_GRP (0x0 << 0) ++#define BAIC_DAIFMT_I2S_GRP (0x1 << 0) ++#define BAIC_DAIFMT_DSP_GRP (0x2 << 0) ++#define BAIC_DAIFMT_GRP_MSK (0x3 << 0) ++#define BAIC_DAIFMT_MODEA (BIT(0) << 2) /*dsp grp*/ ++#define BAIC_DAIFMT_MODEB (BIT(1) << 2) ++#define BAIC_DAIFMT_PCM (BIT(0) << 4) ++#define BAIC_DAIFMT_DSP (BIT(1) << 4) ++#define BAIC_DAIFMT_TDM2 (BIT(2) << 4) ++#define BAIC_DAIFMT_TDM1 (BIT(3) << 4) ++#define BAIC_DAIFMT_I2S (BIT(4) << 4) /*i2s grp*/ ++#define BAIC_DAIFMT_RIGHTJ (BIT(5) << 4) ++#define BAIC_DAIFMT_LEFTJ (BIT(6) << 4) ++ ++#define BAIC_NO_REPLAY (BIT(7) << 4) /*just support replay or record*/ ++#define BAIC_NO_RECORD (BIT(8) << 4) ++ ++#define BAIC_PCM_MODE (BAIC_DAIFMT_PCM|BAIC_DAIFMT_DSP_GRP|BAIC_DAIFMT_MODEA|BAIC_DAIFMT_MODEB) ++#define BAIC_DSP_MODE (BAIC_DAIFMT_DSP|BAIC_DAIFMT_DSP_GRP|BAIC_DAIFMT_MODEA|BAIC_DAIFMT_MODEB) ++#define BAIC_TDM1_MODE (BAIC_DAIFMT_TDM1|BAIC_DAIFMT_DSP_GRP|BAIC_DAIFMT_MODEA|BAIC_DAIFMT_MODEB) ++#define BAIC_TDM2_MODE (BAIC_DAIFMT_TDM2|BAIC_DAIFMT_DSP_GRP|BAIC_DAIFMT_MODEA|BAIC_DAIFMT_MODEB) ++#define BAIC_I2S_MODE (BAIC_DAIFMT_I2S|BAIC_DAIFMT_RIGHTJ|BAIC_DAIFMT_LEFTJ|BAIC_DAIFMT_I2S_GRP) ++ ++#define BAIC_2AND(x,y) ((x) | (y)) ++#define BAIC_3AND(x,y,z) ((x) | (y) | (z)) ++#define BAIC_4AND(x,y,z,m) ((x) | (y) | (z) | (m)) ++#define BAIC_5AND(x,y,z,m,n) ((x) | (y) | (z) | (m) | (n)) ++ ++#endif /*__INGENIC_BAIC_H__*/ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_clk-provider.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_clk-provider.h.patch new file mode 100644 index 00000000..2c8649a5 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_clk-provider.h.patch @@ -0,0 +1,11 @@ +diff -drupN a/include/linux/clk-provider.h b/include/linux/clk-provider.h +--- a/include/linux/clk-provider.h 2017-10-21 18:09:07.000000000 +0300 ++++ b/include/linux/clk-provider.h 2022-06-09 05:02:35.000000000 +0300 +@@ -652,6 +652,7 @@ struct clk_hw *clk_hw_get_parent_by_inde + unsigned int index); + unsigned int __clk_get_enable_count(struct clk *clk); + unsigned long clk_hw_get_rate(const struct clk_hw *hw); ++void __clk_set_flags(struct clk *clk, unsigned long enable); + unsigned long __clk_get_flags(struct clk *clk); + unsigned long clk_hw_get_flags(const struct clk_hw *hw); + bool clk_hw_is_prepared(const struct clk_hw *hw); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_decompress_bunzip2_mm.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_decompress_bunzip2_mm.h.patch new file mode 100644 index 00000000..ffb1ad25 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_decompress_bunzip2_mm.h.patch @@ -0,0 +1,17 @@ +diff -drupN a/include/linux/decompress/bunzip2_mm.h b/include/linux/decompress/bunzip2_mm.h +--- a/include/linux/decompress/bunzip2_mm.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/include/linux/decompress/bunzip2_mm.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,13 @@ ++#ifndef BUNZIP2_MM_H ++#define BUNZIP2_MM_H ++ ++#ifdef STATIC ++/* Code active when included from pre-boot environment: */ ++#define INIT ++#else ++/* Compile for initramfs/initrd code only */ ++#define INIT __init ++static void(*error)(char *m); ++#endif ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_decompress_inflate_mm.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_decompress_inflate_mm.h.patch new file mode 100644 index 00000000..e06fc56c --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_decompress_inflate_mm.h.patch @@ -0,0 +1,17 @@ +diff -drupN a/include/linux/decompress/inflate_mm.h b/include/linux/decompress/inflate_mm.h +--- a/include/linux/decompress/inflate_mm.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/include/linux/decompress/inflate_mm.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,13 @@ ++#ifndef INFLATE_MM_H ++#define INFLATE_MM_H ++ ++#ifdef STATIC ++/* Code active when included from pre-boot environment: */ ++#define INIT ++#else ++/* Compile for initramfs/initrd code only */ ++#define INIT __init ++static void(*error)(char *m); ++#endif ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_decompress_mm.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_decompress_mm.h.patch new file mode 100644 index 00000000..54cbb867 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_decompress_mm.h.patch @@ -0,0 +1,21 @@ +diff -drupN a/include/linux/decompress/mm.h b/include/linux/decompress/mm.h +--- a/include/linux/decompress/mm.h 2017-10-21 18:09:07.000000000 +0300 ++++ b/include/linux/decompress/mm.h 2022-06-09 05:02:35.000000000 +0300 +@@ -61,7 +61,7 @@ static void free(void *where) + #define large_malloc(a) malloc(a) + #define large_free(a) free(a) + +-#define INIT ++//#define INIT + + #else /* STATIC */ + +@@ -83,7 +83,7 @@ static void free(void *where) + #define large_malloc(a) vmalloc(a) + #define large_free(a) vfree(a) + +-#define INIT __init ++//#define INIT __init + #define STATIC + + #include diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_decompress_unlzma_mm.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_decompress_unlzma_mm.h.patch new file mode 100644 index 00000000..59a2eb05 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_decompress_unlzma_mm.h.patch @@ -0,0 +1,24 @@ +diff -drupN a/include/linux/decompress/unlzma_mm.h b/include/linux/decompress/unlzma_mm.h +--- a/include/linux/decompress/unlzma_mm.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/include/linux/decompress/unlzma_mm.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,20 @@ ++#ifndef UNLZMA_MM_H ++#define UNLZMA_MM_H ++ ++#ifdef STATIC ++ ++/* Code active when included from pre-boot environment: */ ++#define INIT ++ ++#elif defined(CONFIG_DECOMPRESS_LZMA_NEEDED) ++ ++/* Make it available to non initramfs/initrd code */ ++#define INIT ++#include ++#else ++ ++/* Compile for initramfs/initrd code only */ ++#define INIT __init ++#endif ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_decompress_unlzo_mm.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_decompress_unlzo_mm.h.patch new file mode 100644 index 00000000..0ada3b40 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_decompress_unlzo_mm.h.patch @@ -0,0 +1,17 @@ +diff -drupN a/include/linux/decompress/unlzo_mm.h b/include/linux/decompress/unlzo_mm.h +--- a/include/linux/decompress/unlzo_mm.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/include/linux/decompress/unlzo_mm.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,13 @@ ++#ifndef UNLZO_MM_H ++#define UNLZO_MM_H ++ ++#ifdef STATIC ++/* Code active when included from pre-boot environment: */ ++#define INIT ++#else ++/* Compile for initramfs/initrd code only */ ++#define INIT __init ++static void(*error)(char *m); ++#endif ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_dmaengine.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_dmaengine.h.patch new file mode 100644 index 00000000..02199df9 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_dmaengine.h.patch @@ -0,0 +1,19 @@ +diff -drupN a/include/linux/dmaengine.h b/include/linux/dmaengine.h +--- a/include/linux/dmaengine.h 2017-10-21 18:09:07.000000000 +0300 ++++ b/include/linux/dmaengine.h 2022-06-09 05:02:35.000000000 +0300 +@@ -686,6 +686,15 @@ struct dma_device { + int (*device_alloc_chan_resources)(struct dma_chan *chan); + void (*device_free_chan_resources)(struct dma_chan *chan); + ++ /* Legacy Interface For ingenic chips. New DMA Driver should never use.*/ ++ struct dma_async_tx_descriptor *(*device_add_desc)( ++ struct dma_chan *chan, dma_addr_t src,dma_addr_t dst, ++ unsigned cnt,enum dma_transfer_direction direction,int flag); ++ dma_addr_t (*get_current_trans_addr)( ++ struct dma_chan *chan,dma_addr_t *dst_addr, ++ dma_addr_t *src_addr,enum dma_transfer_direction direction); ++ ++ + struct dma_async_tx_descriptor *(*device_prep_dma_memcpy)( + struct dma_chan *chan, dma_addr_t dst, dma_addr_t src, + size_t len, unsigned long flags); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_ingenic_adc.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_ingenic_adc.h.patch new file mode 100644 index 00000000..299277f1 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_ingenic_adc.h.patch @@ -0,0 +1,326 @@ +diff -drupN a/include/linux/ingenic_adc.h b/include/linux/ingenic_adc.h +--- a/include/linux/ingenic_adc.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/include/linux/ingenic_adc.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,322 @@ ++#ifndef __LINUX_INGENIC_ADC_H__ ++#define __LINUX_INGENIC_ADC_H__ ++ ++#include ++ ++/* ++ * SAR A/D Controller(SADC) address definition ++ */ ++#define SADC_BASE 0xb0070000 ++ ++/************************************************************************* ++ * SADC (Smart A/D Controller) ++ *************************************************************************/ ++#define BIT0 (1 << 0) ++#define BIT1 (1 << 1) ++#define BIT2 (1 << 2) ++#define BIT3 (1 << 3) ++#define BIT4 (1 << 4) ++#define BIT5 (1 << 5) ++#define BIT6 (1 << 6) ++#define BIT7 (1 << 7) ++#define BIT8 (1 << 8) ++#define BIT9 (1 << 9) ++#define BIT10 (1 << 10) ++#define BIT11 (1 << 11) ++#define BIT12 (1 << 12) ++#define BIT13 (1 << 13) ++#define BIT14 (1 << 14) ++#define BIT15 (1 << 15) ++#define BIT16 (1 << 16) ++#define BIT17 (1 << 17) ++#define BIT18 (1 << 18) ++#define BIT19 (1 << 19) ++#define BIT20 (1 << 20) ++#define BIT21 (1 << 21) ++#define BIT22 (1 << 22) ++#define BIT23 (1 << 23) ++#define BIT24 (1 << 24) ++#define BIT25 (1 << 25) ++#define BIT26 (1 << 26) ++#define BIT27 (1 << 27) ++#define BIT28 (1 << 28) ++#define BIT29 (1 << 29) ++#define BIT30 (1 << 30) ++#define BIT31 (1 << 31) ++ ++ ++ ++ ++ ++#define SADC_ENA (SADC_BASE + 0x00) /* ADC Enable Register */ ++#define SADC_CFG (SADC_BASE + 0x04) /* ADC Configure Register */ ++#define SADC_CTRL (SADC_BASE + 0x08) /* ADC Control Register */ ++#define SADC_STATE (SADC_BASE + 0x0C) /* ADC Status Register*/ ++#define SADC_SAMETIME (SADC_BASE + 0x10) /* ADC Same Point Time Register */ ++#define SADC_WAITTIME (SADC_BASE + 0x14) /* ADC Wait Time Register */ ++#define SADC_TSDAT (SADC_BASE + 0x18) /* ADC Touch Screen Data Register */ ++#define SADC_BATDAT (SADC_BASE + 0x1C) /* ADC VBAT Data Register */ ++#define SADC_SADDAT (SADC_BASE + 0x20) /* ADC AUX Data Register */ ++#define SADC_FLT (SADC_BASE + 0x24) /* ADC Filter Register */ ++ ++#define REG_SADC_ENA REG8(SADC_ENA) ++#define REG_SADC_CFG REG32(SADC_CFG) ++#define REG_SADC_CTRL REG8(SADC_CTRL) ++#define REG_SADC_STATE REG8(SADC_STATE) ++#define REG_SADC_SAMETIME REG16(SADC_SAMETIME) ++#define REG_SADC_WAITTIME REG16(SADC_WAITTIME) ++#define REG_SADC_TSDAT REG32(SADC_TSDAT) ++#define REG_SADC_BATDAT REG16(SADC_BATDAT) ++#define REG_SADC_SADDAT REG16(SADC_SADDAT) ++#define REG_SADC_ADCLK REG32(SADC_ADCLK) ++#define REG_SADC_FLT REG16(SADC_FLT) ++ #define SADC_FLT_ENA (1 << 15) ++ ++/* ADENA: ADC Enable Register */ ++#define SADC_ENA_POWER (1 << 7) /* SADC Power control bit */ ++#define SADC_ENA_SLP_MD (1 << 6) /* SLEEP mode control */ ++#define SADC_ENA_TSEN (1 << 2) /* Touch Screen Enable */ ++#define SADC_ENA_PBATEN (1 << 1) /* PBAT Enable */ ++#define SADC_ENA_SADCINEN (1 << 0) /* AUX n Enable */ ++ ++/* ADC Configure Register */ ++#define SADC_CFG_SPZZ (1 << 31) ++#define SADC_CFG_TS_DMA (1 << 15) /* Touch Screen DMA Enable */ ++#define SADC_CFG_XYZ_BIT 13 /* XYZ selection */ ++#define SADC_CFG_XYZ_MASK (0x3 << SADC_CFG_XYZ_BIT) ++ #define SADC_CFG_XY (0 << SADC_CFG_XYZ_BIT) ++ #define SADC_CFG_XYZ (1 << SADC_CFG_XYZ_BIT) ++ #define SADC_CFG_XYZ1Z2 (2 << SADC_CFG_XYZ_BIT) ++#define SADC_CFG_SNUM_BIT 10 /* Sample Number */ ++#define SADC_CFG_SNUM(x) (((x) - 1) << SADC_CFG_SNUM_BIT) ++#define SADC_CFG_SNUM_MASK (0x7 << SADC_CFG_SNUM_BIT) ++ #define SADC_CFG_SNUM_1 (0x0 << SADC_CFG_SNUM_BIT) ++ #define SADC_CFG_SNUM_2 (0x1 << SADC_CFG_SNUM_BIT) ++ #define SADC_CFG_SNUM_3 (0x2 << SADC_CFG_SNUM_BIT) ++ #define SADC_CFG_SNUM_4 (0x3 << SADC_CFG_SNUM_BIT) ++ #define SADC_CFG_SNUM_5 (0x4 << SADC_CFG_SNUM_BIT) ++ #define SADC_CFG_SNUM_6 (0x5 << SADC_CFG_SNUM_BIT) ++ #define SADC_CFG_SNUM_8 (0x6 << SADC_CFG_SNUM_BIT) ++ #define SADC_CFG_SNUM_9 (0x7 << SADC_CFG_SNUM_BIT) ++#define SADC_CFG_CMD_BIT 0 /* ADC Command */ ++#define SADC_CFG_CMD_MASK (0x3 << SADC_CFG_CMD_BIT) ++ #define SADC_CFG_CMD_AUX0 (0x0 << SADC_CFG_CMD_BIT) /* AUX voltage */ ++ #define SADC_CFG_CMD_AUX1 (0x1 << SADC_CFG_CMD_BIT) /* AUX1 voltage */ ++ #define SADC_CFG_CMD_AUX2 (0x2 << SADC_CFG_CMD_BIT) /* AUX2 voltage */ ++ #define SADC_CFG_CMD_RESERVED (0x3 << SADC_CFG_CMD_BIT) /* Reserved */ ++ ++/* ADCCTRL: ADC Control Register */ ++#define SADC_CTRL_SLPENDM (1 << 5) /* Sleep Interrupt Mask */ ++#define SADC_CTRL_PENDM (1 << 4) /* Pen Down Interrupt Mask */ ++#define SADC_CTRL_PENUM (1 << 3) /* Pen Up Interrupt Mask */ ++#define SADC_CTRL_TSRDYM (1 << 2) /* Touch Screen Data Ready Interrupt Mask */ ++#define SADC_CTRL_PBATRDYM (1 << 1) /* VBAT Data Ready Interrupt Mask */ ++#define SADC_CTRL_SRDYM (1 << 0) /* AUX Data Ready Interrupt Mask */ ++ ++/* ADSTATE: ADC Status Register */ ++#define SADC_STATE_SLP_RDY (1 << 7) /* Sleep state bit */ ++#define SADC_STATE_SLEEPND (1 << 5) /* Pen Down Interrupt Flag */ ++#define SADC_STATE_PEND (1 << 4) /* Pen Down Interrupt Flag */ ++#define SADC_STATE_PENU (1 << 3) /* Pen Up Interrupt Flag */ ++#define SADC_STATE_TSRDY (1 << 2) /* Touch Screen Data Ready Interrupt Flag */ ++#define SADC_STATE_PBATRDY (1 << 1) /* VBAT Data Ready Interrupt Flag */ ++#define SADC_STATE_SRDY (1 << 0) /* AUX Data Ready Interrupt Flag */ ++ ++/* ADTCH: ADC Touch Screen Data Register */ ++#define SADC_TSDAT_TYPE1 (1 << 31) ++#define SADC_TSDAT_DATA1_BIT 16 ++#define SADC_TSDAT_DATA1_MASK (0xfff << SADC_TSDAT_DATA1_BIT) ++#define SADC_TSDAT_TYPE0 (1 << 15) ++#define SADC_TSDAT_DATA0_BIT 0 ++#define SADC_TSDAT_DATA0_MASK (0xfff << SADC_TSDAT_DATA0_BIT) ++ ++/* ADCLK: ADC Clock Divide Register */ ++#define SADC_ADCLK_CLKDIV_MS 16 ++#define SADC_ADCLK_CLKDIV_MS_MASK (0xffff << SADC_ADCLK_CLKDIV_MS) ++#define SADC_ADCLK_CLKDIV_US 8 ++#define SADC_ADCLK_CLKDIV_US_MASK (0xff << SADC_ADCLK_CLKDIV_US) ++#define SADC_ADCLK_CLKDIV_BIT 0 ++#define SADC_ADCLK_CLKDIV_MASK (0xff << SADC_ADCLK_CLKDIV_BIT) ++ ++/* ++ * SADC registers offset definition ++ */ ++#define SADC_ADENA_OFFSET (0x00) /* rw, 8, 0x00 */ ++#define SADC_ADCFG_OFFSET (0x04) /* rw, 32, 0x0002000c */ ++#define SADC_ADCTRL_OFFSET (0x08) /* rw, 8, 0x3f */ ++#define SADC_ADSTATE_OFFSET (0x0c) /* rw, 8, 0x00 */ ++#define SADC_ADSAME_OFFSET (0x10) /* rw, 16, 0x0000 */ ++#define SADC_ADWAIT_OFFSET (0x14) /* rw, 16, 0x0000 */ ++#define SADC_ADTCH_OFFSET (0x18) /* rw, 32, 0x00000000 */ ++#define SADC_ADVDAT_OFFSET (0x1c) /* rw, 16, 0x0000 */ ++#define SADC_ADADAT_OFFSET (0x20) /* rw, 16, 0x0000 */ ++#define SADC_ADCMD_OFFSET (0x24) /* rw, 32, 0x00000000 */ ++#define SADC_ADCLK_OFFSET (0x28) /* rw, 32, 0x00000000 */ ++ ++/* ++ * SADC registers address definition ++ */ ++#define SADC_ADENA (SADC_BASE + SADC_ADENA_OFFSET) /* ADC Enable Register */ ++#define SADC_ADCFG (SADC_BASE + SADC_ADCFG_OFFSET) /* ADC Configure Register */ ++#define SADC_ADCTRL (SADC_BASE + SADC_ADCTRL_OFFSET) /* ADC Control Register */ ++#define SADC_ADSTATE (SADC_BASE + SADC_ADSTATE_OFFSET)/* ADC Status Register*/ ++#define SADC_ADSAME (SADC_BASE + SADC_ADSAME_OFFSET) /* ADC Same Point Time Register */ ++#define SADC_ADWAIT (SADC_BASE + SADC_ADWAIT_OFFSET) /* ADC Wait Time Register */ ++#define SADC_ADTCH (SADC_BASE + SADC_ADTCH_OFFSET) /* ADC Touch Screen Data Register */ ++#define SADC_ADVDAT (SADC_BASE + SADC_ADVDAT_OFFSET) /* ADC VBAT Data Register */ ++#define SADC_ADADAT (SADC_BASE + SADC_ADADAT_OFFSET) /* ADC AUX Data Register */ ++#define SADC_ADCMD (SADC_BASE + SADC_ADCMD_OFFSET) /* ADC COMMAND Register */ ++#define SADC_ADCLK (SADC_BASE + SADC_ADCLK_OFFSET) /* ADC Clock Divide Register */ ++ ++ ++/* ++ * SADC registers common define ++ */ ++ ++/* ADC Enable Register (ADENA) */ ++#define ADENA_POWER BIT7 ++#define ADENA_SLP_MD BIT6 ++#define ADENA_TCHEN BIT2 ++#define ADENA_PENDEN BIT3 ++#define ADENA_VBATEN BIT1 ++#define ADENA_AUXEN BIT0 ++ ++/* ADC Configure Register (ADCFG) */ ++#define ADCFG_SPZZ BIT31 ++ ++#define ADCFG_CMD_SEL BIT22 ++ ++#define ADCFG_DMA_EN BIT15 ++ ++#define ADCFG_XYZ_LSB 13 ++#define ADCFG_XYZ_MASK BITS_H2L(14, ADCFG_XYZ_LSB) ++#define ADCFG_XYZ_XYS (0x0 << ADCFG_XYZ_LSB) ++#define ADCFG_XYZ_XYD (0x1 << ADCFG_XYZ_LSB) ++#define ADCFG_XYZ_XYZ1Z2 (0x2 << ADCFG_XYZ_LSB) ++#define ADCFG_XYZ_XYZ1Z2X2Y2 (0x3 << ADCFG_XYZ_LSB) ++ ++#define ADCFG_SNUM_LSB 10 ++#define ADCFG_SNUM_MASK BITS_H2L(12, ADCFG_SNUM_LSB) ++#define ADCFG_SNUM(n) (((n) <= 6 ? ((n)-1) : ((n)-2)) << ADCFG_SNUM_LSB) ++ ++#define ADCFG_CMD_LSB 0 ++#define ADCFG_CMD_MASK BITS_H2L(1, ADCFG_CMD_LSB) ++#define ADCFG_CMD_AUX(n) ((n) << ADCFG_CMD_LSB) ++ ++/* ADC Control Register (ADCCTRL) */ ++#define ADCTRL_SLPENDM BIT5 ++#define ADCTRL_PENDM BIT4 ++#define ADCTRL_PENUM BIT3 ++#define ADCTRL_DTCHM BIT2 ++#define ADCTRL_VRDYM BIT1 ++#define ADCTRL_ARDYM BIT0 ++#define ADCTRL_MASK_ALL (ADCTRL_SLPENDM | ADCTRL_PENDM | ADCTRL_PENUM \ ++ | ADCTRL_DTCHM | ADCTRL_VRDYM | ADCTRL_ARDYM) ++ ++/* ADC Status Register (ADSTATE) */ ++#define ADSTATE_SLP_RDY BIT7 ++#define ADSTATE_SLPEND BIT5 ++#define ADSTATE_PEND BIT4 ++#define ADSTATE_PENU BIT3 ++#define ADSTATE_DTCH BIT2 ++#define ADSTATE_VRDY BIT1 ++#define ADSTATE_ARDY BIT0 ++ ++/* ADC Same Point Time Register (ADSAME) */ ++#define ADSAME_SCNT_LSB 0 ++#define ADSAME_SCNT_MASK BITS_H2L(15, ADSAME_SCNT_LSB) ++ ++/* ADC Wait Pen Down Time Register (ADWAIT) */ ++#define ADWAIT_WCNT_LSB 0 ++#define ADWAIT_WCNT_MASK BITS_H2L(15, ADWAIT_WCNT_LSB) ++ ++/* ADC Touch Screen Data Register (ADTCH) */ ++#define ADTCH_TYPE1 BIT31 ++#define ADTCH_TYPE0 BIT15 ++ ++#define ADTCH_DATA1_LSB 16 ++#define ADTCH_DATA1_MASK BITS_H2L(27, ADTCH_DATA1_LSB) ++ ++#define ADTCH_DATA0_LSB 0 ++#define ADTCH_DATA0_MASK BITS_H2L(11, ADTCH_DATA0_LSB) ++ ++/* ADC VBAT Date Register (ADVDAT) */ ++#define ADVDAT_VDATA_LSB 0 ++#define ADVDAT_VDATA_MASK BITS_H2L(11, ADVDAT_VDATA_LSB) ++ ++/* ADC AUX Data Register (ADADAT) */ ++#define ADADAT_ADATA_LSB 0 ++#define ADADAT_ADATA_MASK BITS_H2L(11, ADADAT_ADATA_LSB) ++ ++/* ADC Clock Divide Register (ADCLK) */ ++#define ADCLK_CLKDIV_MS_LSB 16 ++#define ADCLK_CLKDIV_MS_MASK BITS_H2L(31, ADCLK_CLKDIV_MS_LSB) ++ ++#define ADCLK_CLKDIV_US_LSB 8 ++#define ADCLK_CLKDIV_US_MASK BITS_H2L(15, ADCLK_CLKDIV_US_LSB) ++ ++#define ADCLK_CLKDIV_LSB 0 ++#define ADCLK_CLKDIV_MASK BITS_H2L(7, ADCLK_CLKDIV_LSB) ++ ++/* ADC Filter Register (ADFLT) */ ++#define ADFLT_FLT_EN BIT15 ++ ++#define ADFLT_FLT_D_LSB 0 ++#define ADFLT_FLT_D_MASK BITS_H2L(11, ADFLT_FLT_D_LSB) ++ ++/* ADC Command Register (ADCMD) */ ++#define ADCMD_PIL BIT31 ++#define ADCMD_RPU(n) ((n) << 26) ++#define ADCMD_XPSUP BIT25 ++#define ADCMD_YPSUP BIT23 ++#define ADCMD_XNGRU BIT21 ++#define ADCMD_YNGRU BIT20 ++#define ADCMD_VREFNXN BIT18 ++#define ADCMD_VREFNYN BIT16 ++#define ADCMD_VREFPXP BIT12 ++#define ADCMD_VREFPYP BIT11 ++#define ADCMD_XPADC BIT10 ++#define ADCMD_YPADC BIT8 ++struct ingenic_ts_info{ ++ unsigned int x_max; ++ unsigned int x_min; ++ unsigned int y_max; ++ unsigned int y_min; ++ unsigned int z_max; ++ unsigned int z_min; ++ unsigned short x_resolution; ++ unsigned short y_resolution; ++ unsigned short y_r_plate; ++ unsigned short x_r_plate; ++ unsigned short pressure_max; ++ unsigned int use_5_wire; ++ unsigned int support_keypad; ++ unsigned int support_mt_touch; ++ unsigned int support_sleepmode; ++ void *private_data; ++}; ++ ++ ++ ++/* ++ * ingenic_adc_set_config - Configure a ingenic adc device ++ * @dev: Pointer to a ingenic-adc device ++ * @mask: Mask for the config value to be set ++ * @val: Value to be set ++ * ++ * This function can be used by the ingenic ++ * ADC mfd cells to confgure their options in the shared config register. ++ */ ++ ++#if 0 ++ int ingenic_adc_set_config(struct device *dev, uint32_t mask, uint32_t val); ++#endif ++ ++struct ingenic_adc_platform_data{ ++ //struct ingenic_battery_info battery_info; ++ struct ingenic_ts_info ts_info; ++}; ++ ++int adc_write_reg(struct device *dev,uint8_t addr_offset,uint32_t mask,uint32_t val); ++uint32_t adc_read_reg(struct device *dev,uint8_t addr_offset); ++#endif /*ingenic_adc.h*/ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_interrupt.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_interrupt.h.patch new file mode 100644 index 00000000..66390f75 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_interrupt.h.patch @@ -0,0 +1,11 @@ +diff -drupN a/include/linux/interrupt.h b/include/linux/interrupt.h +--- a/include/linux/interrupt.h 2017-10-21 18:09:07.000000000 +0300 ++++ b/include/linux/interrupt.h 2022-06-09 05:02:35.000000000 +0300 +@@ -62,6 +62,7 @@ + * wakeup devices users need to implement wakeup detection in + * their interrupt handlers. + */ ++#define IRQF_DISABLED 0x00000020 + #define IRQF_SHARED 0x00000080 + #define IRQF_PROBE_SHARED 0x00000100 + #define __IRQF_TIMER 0x00000200 diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_mfd_ingenic-tcu.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_mfd_ingenic-tcu.h.patch new file mode 100644 index 00000000..1bfff414 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_mfd_ingenic-tcu.h.patch @@ -0,0 +1,206 @@ +diff -drupN a/include/linux/mfd/ingenic-tcu.h b/include/linux/mfd/ingenic-tcu.h +--- a/include/linux/mfd/ingenic-tcu.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/include/linux/mfd/ingenic-tcu.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,202 @@ ++#ifndef __INGENIC_TCU_H__ ++#define __INGENIC_TCU_H__ ++ ++#include ++ ++#define NR_TCU_CHNS TCU_NR_IRQS ++ ++enum irq_bit { ++ FULL_BIT, ++ HALF_BIT, ++}; ++enum tcu_prescale { ++ TCU_PRESCALE_1, ++ TCU_PRESCALE_4, ++ TCU_PRESCALE_16, ++ TCU_PRESCALE_64, ++ TCU_PRESCALE_256, ++ TCU_PRESCALE_1024 ++}; ++ ++enum tcu_clksrc { ++ TCU_CLKSRC_PCK = 1, ++ TCU_CLKSRC_RTC = 2, ++ TCU_CLKSRC_EXT = 4 ++}; ++ ++enum tcu_irq_type { ++ NULL_IRQ_MODE, ++ FULL_IRQ_MODE, ++ HALF_IRQ_MODE, ++ FULL_HALF_IRQ_MODE, ++}; ++ ++struct info_bits { ++ unsigned int id:CHANNEL_BASE_OFF*2; ++ unsigned int mode:CHANNEL_BASE_OFF; ++ unsigned int func:CHANNEL_BASE_OFF; ++ unsigned int pwmin:CHANNEL_BASE_OFF; ++}; ++ ++struct ingenic_tcu_chn { ++ union { ++ unsigned int chn_info; ++ struct info_bits cib; ++ }; ++ unsigned int index; ++ char virq[2]; ++ char irq_type; ++ char clk_src; ++ ++ char clk_div; ++ char init_level; ++ char shutdown_mode; ++ char pwm_bapass_mode; ++ ++ char is_pwm; ++ char is_count_clear; ++ char pwm_in_en; ++ char work_sleep; ++ ++ int half_num; ++ int full_num; ++ struct device_node *np; ++ void (*enable)(int id); ++ void (*disable)(int id); ++}; ++ ++void tcu_start_counter(int id); ++void tcu_stop_counter(int id); ++void tcu_set_counter(int id, unsigned int val); ++int tcu_get_counter(int id); ++void tcu_enable_counter(int id); ++void tcu_disable_counter(int id); ++ ++/** ++ * ingenic_tcu_set_full_num - set the number of tcu Timer Data FULL Register (TDFR) ++ * ++ * @id: tcu channel id. ++ * @full_num: the number of set TDFR. ++ * ++ */ ++void ingenic_tcu_set_period(int id, uint16_t period); ++/** ++ * ingenic_tcu_set_half_num - set the number of tcu Timer Data FULL Register (TDHR) ++ * ++ * @id: tcu channel id. ++ * @half_num: the number of set TDFR. ++ * ++ */ ++void ingenic_tcu_set_duty(int id, uint16_t duty); ++/** ++ * ingenic_tcu_set_prescale - set clk div of TCU prescale. ++ * Don‘t call the function when the channel is running. ++ * ++ * @id: tcu channel id. ++ * @prescale: the div of clk value. ++ * ++ */ ++void ingenic_tcu_set_prescale(int id, enum tcu_prescale prescale); ++/** ++ * ingenic_tcu_set_pwm_output_init_level - set an initial output level for PWM output. ++ * ++ * @id: tcu channel id. ++ * @level: 0 LOW, 1 HIGH. ++ * ++ */ ++void ingenic_tcu_set_pwm_output_init_level(int id, int level); ++/** ++ * ingenic_tcu_set_clksrc - set clk soruce of the timer clock input. ++ * Don‘t call the function when the channel is running. ++ * ++ * @id: tcu channel id. ++ * @src: the clk source;0 PCLK, 1 RTC, 2 EXT. ++ * ++ */ ++void ingenic_tcu_set_clksrc(int id, enum tcu_clksrc src); ++/** ++ * ingenic_tcu_channel_to_virq - get virtual irq though to tcu channel id ++ * (channel 0 ~ 4, 6 ~ 7 use common hardware irq(TCU2)) ++ * ++ * @tcu_chn: the struct of request cell(TCU channel). ++ * ++ * Search for a virq in a irq domain and save irq to struct ingenic_tcu_chn ++ * ->virq[2]. ++ */ ++void ingenic_tcu_channel_to_virq(struct ingenic_tcu_chn *tcu_chn); ++/** ++ * ingenic_tcu_get_count - get the value of the timer counter (TCNT). ++ * ++ * @id: tcu channel id. ++ * ++ * Returns number of timer counter on sucess, ++ * -EINVAL if The value read from counter 1 or 2 is a false value. ++ * ++ */ ++int ingenic_tcu_get_count(int id); ++/** ++ * ingenic_tcu_config - init the current channel struct. ++ * ++ * @tcu_chn: tcu channel struct. ++ * ++ * Returns 0 on sucess, ++ * Returns < 0 if init failed. ++ * ++ */ ++int ingenic_tcu_config(struct ingenic_tcu_chn *tcu_chn); ++/** ++ * ingenic_tcu_counter_begin - begin counting up, if channel function is pwm, enable pwm. ++ * ++ * @tcu_chn: tcu channel struct. ++ * ++ */ ++int ingenic_tcu_counter_begin(struct ingenic_tcu_chn *tcu_chn); ++/** ++ * ingenic_tcu_counter_stop - stop counting up, if channel function is pwm, disable pwm. ++ * ++ * @tcu_chn: tcu channel struct. ++ * ++ * Explain: ++ * TCU count stop, is the next stop after match, not immediately stop. ++ * If you want to stop immediately, you can use cell->disable. ++ * ++ */ ++void ingenic_tcu_counter_stop(struct ingenic_tcu_chn *tcu_chn); ++ ++/** ++ * ingenic_watchdog_set_count - setwatchdog timer counter. ++ * This function is only used for watchdog. ++ * ++ * @value: the number of set watchdog counter. ++ * ++ */ ++void ingenic_watchdog_set_count(unsigned int value); ++/** ++ * ingenic_watchdog_config - init watchdog. ++ * This function is only used for watchdog. ++ * ++ * @tcsr_val: the number of set watchdog TCSR. ++ * @timeout_value: the number of set watchdog TCNT. ++ * ++ */ ++void ingenic_watchdog_config(unsigned int tcsr_val, unsigned int timeout_value); ++ ++/** ++ * request_cell - request tcu channel cell. ++ * ++ * @id: tcu channel id. ++ * ++ * Returns struct cell on sucess, ++ * NULL if The channel busy. ++ * ++ */ ++struct mfd_cell *request_cell(int id); ++/** ++ * free_cell - free tcu channel cell. ++ * ++ * @id: tcu channel id. ++ * ++ */ ++void free_cell(int id); ++ ++#endif /* __INGENIC_TCU_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_mfd_jz_tcu.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_mfd_jz_tcu.h.patch new file mode 100644 index 00000000..3ec75e77 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_mfd_jz_tcu.h.patch @@ -0,0 +1,157 @@ +diff -drupN a/include/linux/mfd/jz_tcu.h b/include/linux/mfd/jz_tcu.h +--- a/include/linux/mfd/jz_tcu.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/include/linux/mfd/jz_tcu.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,153 @@ ++#ifndef __JZ_TCU_H__ ++#define __JZ_TCU_H__ ++ ++#include ++#include ++ ++#define timeout 500 ++ ++#define TCU_CHN_TDFR 0x0 ++#define TCU_CHN_TDHR 0x4 ++#define TCU_CHN_TCNT 0x8 ++#define TCU_CHN_TCSR 0xc ++ ++#define tcu_readl(tcu,reg) \ ++ __raw_readl((tcu)->iomem + TCU_##reg) ++#define tcu_writel(tcu,reg,value) \ ++ __raw_writel((value), (tcu)->iomem + TCU_##reg) ++ ++#define tcu_chn_readl(tcu_chn,reg) \ ++ __raw_readl((tcu_chn)->tcu->iomem + (tcu_chn)->reg_base + TCU_##reg) ++#define tcu_chn_writel(tcu_chn,reg,value) \ ++ __raw_writel((value), (tcu_chn)->tcu->iomem + (tcu_chn)->reg_base + TCU_##reg) ++ ++enum tcu_prescale { ++ TCU_PRESCALE_1, ++ TCU_PRESCALE_4, ++ TCU_PRESCALE_16, ++ TCU_PRESCALE_64, ++ TCU_PRESCALE_256, ++ TCU_PRESCALE_1024 ++}; ++ ++enum tcu_clksrc { ++ TCU_CLKSRC_PCK = 1, ++ TCU_CLKSRC_RTC = 2, ++ TCU_CLKSRC_EXT = 4 ++}; ++ ++struct jz_tcu { ++ void __iomem *iomem; ++ int irq; ++ int irq_base; ++ spinlock_t lock; ++}; ++ ++struct jzpwm_platform_data { ++ int pwm_gpio[8]; ++}; ++ ++struct jz_tcu_chn { ++ int index; /* Channel number */ ++ u32 reg_base; ++ int is_pwm; ++ ++ enum tcu_irq_mode irq_type; ++ enum tcu_clksrc clk_src; ++ enum tcu_mode tcu_mode; ++ enum tcu_prescale prescale; ++ ++ unsigned int divi_ratio; /* 0/1/2/3/4/5/something else------>1/4/16/64/256/1024/mask */ ++ int half_num; ++ int full_num; ++ int init_level; ++ int shutdown_mode; ++ int pwm_bapass_mode; ++ int pwm_in; ++ ++ int gpio; ++ struct jz_tcu *tcu; ++}; ++ ++static inline void jz_tcu_enable_counter(struct jz_tcu_chn *tcu_chn) ++{ ++ tcu_writel(tcu_chn->tcu, TESR, 1 << tcu_chn->index); ++} ++ ++static inline int jz_tcu_disable_counter(struct jz_tcu_chn *tcu_chn) ++{ ++ int i=0; ++ if (tcu_chn->is_pwm) ++ tcu_chn_writel(tcu_chn, CHN_TCSR, tcu_chn_readl(tcu_chn, CHN_TCSR) & ~(TCSR_PWM_EN)); ++ ++ tcu_writel(tcu_chn->tcu, TECR, 1 << tcu_chn->index); ++ ++ if(tcu_chn->tcu_mode == TCU_MODE_2) { ++ if(tcu_chn->index == 1){ ++ while(tcu_readl(tcu_chn->tcu, TSTR) & TSTR_BUSY1){ ++ i++; ++ if(i>timeout) { ++ printk("the reset of counter is not finished now"); ++ return -1; ++ } ++ } ++ } else { ++ while(tcu_readl(tcu_chn->tcu, TSTR) & TSTR_BUSY2){ ++ i++; ++ if(i>timeout) { ++ printk("the reset of counter is not finished now"); ++ return -1; ++ } ++ } ++ } ++ } ++ return 1; ++} ++ ++static inline void jz_tcu_start_counter(struct jz_tcu_chn *tcu_chn) ++{ ++ tcu_writel(tcu_chn->tcu, TSCR, 1 << tcu_chn->index); ++} ++ ++static inline void jz_tcu_stop_counter(struct jz_tcu_chn *tcu_chn) ++{ ++ tcu_writel(tcu_chn->tcu, TSSR, 1 << tcu_chn->index); ++} ++ ++static inline void jz_tcu_set_count(struct jz_tcu_chn *tcu_chn, u16 cnt) ++{ ++ tcu_chn_writel(tcu_chn, CHN_TCNT, cnt); ++} ++ ++static inline int jz_tcu_get_count(struct jz_tcu_chn *tcu_chn) ++{ ++ int tmp; ++ int i = 0; ++ ++ if (tcu_chn->tcu_mode == TCU_MODE_2){ ++ while(tmp == 0 && i < timeout) { ++ if(tcu_chn->index == 1){ ++ tmp = tcu_readl(tcu_chn->tcu, TSSR) & TSTR_REAL1; ++ } else { ++ tmp = tcu_readl(tcu_chn->tcu, TSSR) & TSTR_REAL2; ++ } ++ i++; ++ } ++ if(tmp == 0) return -EINVAL; /*TCU MODE 2 may not read success*/ ++ } ++ return tcu_chn_readl(tcu_chn, CHN_TCNT); ++} ++ ++static inline void jz_tcu_set_period(struct jz_tcu_chn *tcu_chn, uint16_t period) ++{ ++ tcu_chn_writel(tcu_chn, CHN_TDFR, period); ++} ++ ++static inline void jz_tcu_set_duty(struct jz_tcu_chn *tcu_chn, uint16_t duty) ++{ ++ tcu_chn_writel(tcu_chn, CHN_TDHR, duty); ++} ++ ++void jz_tcu_config_chn(struct jz_tcu_chn *tcu_chn); ++ ++#endif /* __JZ_TCU_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_mfd_rn5t567.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_mfd_rn5t567.h.patch new file mode 100644 index 00000000..901ad056 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_mfd_rn5t567.h.patch @@ -0,0 +1,139 @@ +diff -drupN a/include/linux/mfd/rn5t567.h b/include/linux/mfd/rn5t567.h +--- a/include/linux/mfd/rn5t567.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/include/linux/mfd/rn5t567.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,135 @@ ++/* ++ * MFD core driver for Ricoh RN5T567 PMIC ++ * ++ * Copyright (C) 2014 Beniamino Galvani ++ * ++ * 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. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++#ifndef __LINUX_MFD_RN5T567_H ++#define __LINUX_MFD_RN5T567_H ++ ++#include ++ ++#define RN5T567_LSIVER 0x00 ++#define RN5T567_OTPVER 0x01 ++#define RN5T567_IODAC 0x02 ++#define RN5T567_VINDAC 0x03 ++#define RN5T567_OUT32KEN 0x05 ++#define RN5T567_CPUCNT 0x06 ++#define RN5T567_PSWR 0x07 ++#define RN5T567_PONHIS 0x09 ++#define RN5T567_POFFHIS 0x0a ++#define RN5T567_WATCHDOG 0x0b ++#define RN5T567_WATCHDOGCNT 0x0c ++#define RN5T567_PWRFUNC 0x0d ++#define RN5T567_SLPCNT 0x0e ++#define RN5T567_REPCNT 0x0f ++#define RN5T567_PWRONTIMSET 0x10 ++#define RN5T567_NOETIMSETCNT 0x11 ++#define RN5T567_PWRIREN 0x12 ++#define RN5T567_PWRIRQ 0x13 ++#define RN5T567_PWRMON 0x14 ++#define RN5T567_PWRIRSEL 0x15 ++#define RN5T567_DC1_SLOT 0x16 ++#define RN5T567_DC2_SLOT 0x17 ++#define RN5T567_DC3_SLOT 0x18 ++#define RN5T567_DC4_SLOT 0x19 ++#define RN5T567_LDO1_SLOT 0x1b ++#define RN5T567_LDO2_SLOT 0x1c ++#define RN5T567_LDO3_SLOT 0x1d ++#define RN5T567_LDO4_SLOT 0x1e ++#define RN5T567_LDO5_SLOT 0x1f ++#define RN5T567_PSO0_SLOT 0x25 ++#define RN5T567_PSO1_SLOT 0x26 ++#define RN5T567_PSO2_SLOT 0x27 ++#define RN5T567_PSO3_SLOT 0x28 ++#define RN5T567_LDORTC1_SLOT 0x2a ++#define RN5T567_DC1CTL 0x2c ++#define RN5T567_DC1CTL2 0x2d ++#define RN5T567_DC2CTL 0x2e ++#define RN5T567_DC2CTL2 0x2f ++#define RN5T567_DC3CTL 0x30 ++#define RN5T567_DC3CTL2 0x31 ++#define RN5T567_DC4CTL 0x32 ++#define RN5T567_DC4CTL2 0x33 ++#define RN5T567_DC1DAC 0x36 ++#define RN5T567_DC2DAC 0x37 ++#define RN5T567_DC3DAC 0x38 ++#define RN5T567_DC4DAC 0x39 ++#define RN5T567_DC1DAC_SLP 0x3b ++#define RN5T567_DC2DAC_SLP 0x3c ++#define RN5T567_DC3DAC_SLP 0x3d ++#define RN5T567_DC4DAC_SLP 0x3e ++#define RN5T567_DCIREN 0x40 ++#define RN5T567_DCIRQ 0x41 ++#define RN5T567_DCIRMON 0x42 ++#define RN5T567_LDOEN1 0x44 ++#define RN5T567_LDOEN2 0x45 ++#define RN5T567_LDODIS 0x46 ++#define RN5T567_LDO1DAC 0x4c ++#define RN5T567_LDO2DAC 0x4d ++#define RN5T567_LDO3DAC 0x4e ++#define RN5T567_LDO4DAC 0x4f ++#define RN5T567_LDO5DAC 0x50 ++#define RN5T567_LDORTCDAC 0x56 ++#define RN5T567_LDORTC2DAC 0x57 ++#define RN5T567_LDO1DAC_SLP 0x58 ++#define RN5T567_LDO2DAC_SLP 0x59 ++#define RN5T567_LDO3DAC_SLP 0x5a ++#define RN5T567_LDO4DAC_SLP 0x5b ++#define RN5T567_LDO5DAC_SLP 0x5c ++#define RN5T567_IOSEL 0x90 ++#define RN5T567_IOOUT 0x91 ++#define RN5T567_GPEDGE1 0x92 ++#define RN5T567_EN_GPIR 0x94 ++#define RN5T567_IR_GPR 0x95 ++#define RN5T567_IR_GPF 0x96 ++#define RN5T567_MON_IOIN 0x97 ++#define RN5T567_GPLED_FUNC 0x98 ++#define RN5T567_INTPOL 0x9c ++#define RN5T567_INTEN 0x9d ++#define RN5T567_INTMON 0x9e ++#define RN5T567_PREVINDAC 0xb0 ++#define RN5T567_DIESET 0xbc ++#define RN5T567_MAX_REG RN5T567_DIESET ++#define RN5T567_REG_NUM ((100) - (19)) ++ ++#define RN5T567_REPCNT_REPWRON BIT(0) ++#define RN5T567_SLPCNT_SWPWROFF BIT(0) ++ ++enum { ++ RN5T567_DCDC1 = 0, ++ RN5T567_DCDC2, ++ RN5T567_DCDC3, ++ RN5T567_DCDC4, ++ RN5T567_LDO1, ++ RN5T567_LDO2, ++ RN5T567_LDO3, ++ RN5T567_LDO4, ++ RN5T567_LDO5, ++ RN5T567_LDORTC1, ++ //RN5T567_LDORTC2, ++ RN5T567_REGLATOR_NUM, ++}; ++ ++enum { ++ RN5T567_IRQ_SYSTEM = 0, ++ RN5T567_IRQ_DCDC, ++ RN5T567_IRQ_REV0, ++ RN5T567_IRQ_REV1, ++ RN5T567_IRQ_GPIO, ++ RN5T567_IRQ_WDG, ++ RN5T567_IRQ_REV2, ++ RN5T567_IRQ_REV3, ++ RN5T567_IRQ_NUM, ++}; ++ ++extern int rn5t567_irq_init(struct i2c_client *i2c, struct regmap *regmap); ++extern void rn5t567_irq_deinit(void); ++#endif /* __LINUX_MFD_RN5T567_H */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_seq_file.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_seq_file.h.patch new file mode 100644 index 00000000..089bd4e1 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_seq_file.h.patch @@ -0,0 +1,15 @@ +diff -drupN a/include/linux/seq_file.h b/include/linux/seq_file.h +--- a/include/linux/seq_file.h 2017-10-21 18:09:07.000000000 +0300 ++++ b/include/linux/seq_file.h 2022-06-09 05:02:35.000000000 +0300 +@@ -112,9 +112,9 @@ int seq_release(struct inode *, struct f + int seq_write(struct seq_file *seq, const void *data, size_t len); + + __printf(2, 0) +-void seq_vprintf(struct seq_file *m, const char *fmt, va_list args); ++int seq_vprintf(struct seq_file *m, const char *fmt, va_list args); + __printf(2, 3) +-void seq_printf(struct seq_file *m, const char *fmt, ...); ++int seq_printf(struct seq_file *m, const char *fmt, ...); + void seq_putc(struct seq_file *m, char c); + void seq_puts(struct seq_file *m, const char *s); + void seq_put_decimal_ull(struct seq_file *m, char delimiter, diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_wlan_plat.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_wlan_plat.h.patch new file mode 100644 index 00000000..4e597718 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_linux_wlan_plat.h.patch @@ -0,0 +1,31 @@ +diff -drupN a/include/linux/wlan_plat.h b/include/linux/wlan_plat.h +--- a/include/linux/wlan_plat.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/include/linux/wlan_plat.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,27 @@ ++/* include/linux/wlan_plat.h ++ * ++ * Copyright (C) 2010 Google, Inc. ++ * ++ * This software is licensed under the terms of the GNU General Public ++ * License version 2, as published by the Free Software Foundation, and ++ * may be copied, distributed, and modified under those terms. ++ * ++ * 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. ++ * ++ */ ++#ifndef _LINUX_WLAN_PLAT_H_ ++#define _LINUX_WLAN_PLAT_H_ ++ ++struct wifi_platform_data { ++ int (*set_power)(int val); ++ int (*set_reset)(int val); ++ int (*set_carddetect)(int val); ++ void *(*mem_prealloc)(int section, unsigned long size); ++ int (*get_mac_addr)(unsigned char *buf); ++ void *(*get_country_code)(char *ccode); ++}; ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_soc_xburst_reboot.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_soc_xburst_reboot.h.patch new file mode 100644 index 00000000..7064c851 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_soc_xburst_reboot.h.patch @@ -0,0 +1,33 @@ +diff -drupN a/include/soc/xburst/reboot.h b/include/soc/xburst/reboot.h +--- a/include/soc/xburst/reboot.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/include/soc/xburst/reboot.h 2022-06-09 05:02:35.000000000 +0300 +@@ -0,0 +1,29 @@ ++#ifndef __INGENIC_REBOOT_H__ ++#define __INGENIC_REBOOT_H__ ++ ++enum restart_handler_priority { ++ WDT_RESET_PROR = 0, ++ RTC_HIBERNATE_RESET_PROR, ++}; ++ ++#define REBOOT_CMD_RECOVERY "recovery" ++#define REBOOT_CMD_SOFTBURN "softburn" ++ ++void __weak ingenic_recovery_sign(void) ++{ ++ pr_info("ingenic default recovery sign\n"); ++ return; ++} ++ ++void __weak ingenic_reboot_sign(void) ++{ ++ pr_info("ingenic default reboot sign\n"); ++ return; ++} ++ ++void __weak ingenic_softburn_sign(void) ++{ ++ pr_info("ingenic default softburn sign\n"); ++ return; ++} ++#endif /*__INGENIC_REBOOT_H__*/ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_sound_soc.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_sound_soc.h.patch new file mode 100644 index 00000000..696fe909 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-include_sound_soc.h.patch @@ -0,0 +1,12 @@ +diff -drupN a/include/sound/soc.h b/include/sound/soc.h +--- a/include/sound/soc.h 2017-10-21 18:09:07.000000000 +0300 ++++ b/include/sound/soc.h 2022-06-09 05:02:35.000000000 +0300 +@@ -1411,6 +1411,8 @@ static inline int snd_soc_cache_sync(str + /* component IO */ + int snd_soc_component_read(struct snd_soc_component *component, + unsigned int reg, unsigned int *val); ++unsigned int snd_soc_component_read32(struct snd_soc_component *component, ++ unsigned int reg); + int snd_soc_component_write(struct snd_soc_component *component, + unsigned int reg, unsigned int val); + int snd_soc_component_update_bits(struct snd_soc_component *component, diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-init_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-init_Kconfig.patch new file mode 100644 index 00000000..2ff7c09e --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-init_Kconfig.patch @@ -0,0 +1,32 @@ +diff -drupN a/init/Kconfig b/init/Kconfig +--- a/init/Kconfig 2017-10-21 18:09:07.000000000 +0300 ++++ b/init/Kconfig 2022-06-09 05:02:36.000000000 +0300 +@@ -44,6 +44,9 @@ config INIT_ENV_ARG_LIMIT + Maximum of each of the number of arguments and environment + variables passed to init from the kernel command line. + ++config FAST_BOOT ++ bool "Kernel fast start up" ++ default n + + config CROSS_COMPILE + string "Cross-compiler tool prefix" +@@ -1422,15 +1425,16 @@ config SYSCTL_SYSCALL + + config KALLSYMS + bool "Load all symbols for debugging/ksymoops" if EXPERT ++ depends on !FAST_BOOT + default y + help + Say Y here to let the kernel print out symbolic crash information and +- symbolic stack backtraces. This increases the size of the kernel ++ symbolic stack backtraces. This increases the size of the /kernel + somewhat, as all symbols have to be loaded into the kernel image. + + config KALLSYMS_ALL + bool "Include all symbols in kallsyms" +- depends on DEBUG_KERNEL && KALLSYMS ++ depends on DEBUG_KERNEL && KALLSYMS && !FAST_BOOT + help + Normally kallsyms only contains the symbols of functions for nicer + OOPS messages and backtraces (i.e., symbols from the text and inittext diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-init_main.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-init_main.c.patch new file mode 100644 index 00000000..54a66815 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-init_main.c.patch @@ -0,0 +1,20 @@ +diff -drupN a/init/main.c b/init/main.c +--- a/init/main.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/init/main.c 2022-06-09 05:02:36.000000000 +0300 +@@ -498,6 +498,7 @@ asmlinkage __visible void __init start_k + { + char *command_line; + char *after_dashes; ++ unsigned long flags = 0; + + /* + * Need to run as early as possible, to initialize the +@@ -594,6 +595,8 @@ asmlinkage __visible void __init start_k + perf_event_init(); + profile_init(); + call_function_init(); ++ flags = read_cp0_30_flags(); ++ printk("ERROR epc 0x%lx\n", flags); + WARN(!irqs_disabled(), "Interrupts were enabled early\n"); + early_boot_irqs_disabled = false; + local_irq_enable(); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-lib_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-lib_Kconfig.patch new file mode 100644 index 00000000..ac33c81f --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-lib_Kconfig.patch @@ -0,0 +1,22 @@ +diff -drupN a/lib/Kconfig b/lib/Kconfig +--- a/lib/Kconfig 2017-10-21 18:09:07.000000000 +0300 ++++ b/lib/Kconfig 2022-06-09 05:02:36.000000000 +0300 +@@ -254,6 +254,7 @@ config DECOMPRESS_BZIP2 + + config DECOMPRESS_LZMA + tristate ++ default y + + config DECOMPRESS_XZ + select XZ_DEC +@@ -267,6 +268,10 @@ config DECOMPRESS_LZ4 + select LZ4_DECOMPRESS + tristate + ++config DECOMPRESS_LZMA_NEEDED ++ boolean ++ default y ++ + # + # Generic allocator support is selected if needed + # diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-lib_decompress_bunzip2.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-lib_decompress_bunzip2.c.patch new file mode 100644 index 00000000..e3cb4e50 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-lib_decompress_bunzip2.c.patch @@ -0,0 +1,11 @@ +diff -drupN a/lib/decompress_bunzip2.c b/lib/decompress_bunzip2.c +--- a/lib/decompress_bunzip2.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/lib/decompress_bunzip2.c 2022-06-09 05:02:36.000000000 +0300 +@@ -50,6 +50,7 @@ + #include + #endif /* STATIC */ + ++#include + #include + + #ifndef INT_MAX diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-lib_decompress_inflate.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-lib_decompress_inflate.c.patch new file mode 100644 index 00000000..a00b5844 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-lib_decompress_inflate.c.patch @@ -0,0 +1,11 @@ +diff -drupN a/lib/decompress_inflate.c b/lib/decompress_inflate.c +--- a/lib/decompress_inflate.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/lib/decompress_inflate.c 2022-06-09 05:02:36.000000000 +0300 +@@ -24,6 +24,7 @@ + + #endif /* STATIC */ + ++#include + #include + + #define GZIP_IOBUF_SIZE (16*1024) diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-lib_decompress_unlz4.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-lib_decompress_unlz4.c.patch new file mode 100644 index 00000000..86a9f499 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-lib_decompress_unlz4.c.patch @@ -0,0 +1,14 @@ +diff -drupN a/lib/decompress_unlz4.c b/lib/decompress_unlz4.c +--- a/lib/decompress_unlz4.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/lib/decompress_unlz4.c 2022-06-09 05:02:36.000000000 +0300 +@@ -10,8 +10,10 @@ + + #ifdef STATIC + #define PREBOOT ++#define INIT + #include "lz4/lz4_decompress.c" + #else ++#define INIT __init + #include + #endif + #include diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-lib_decompress_unlzma.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-lib_decompress_unlzma.c.patch new file mode 100644 index 00000000..589b12eb --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-lib_decompress_unlzma.c.patch @@ -0,0 +1,31 @@ +diff -drupN a/lib/decompress_unlzma.c b/lib/decompress_unlzma.c +--- a/lib/decompress_unlzma.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/lib/decompress_unlzma.c 2022-06-09 05:02:36.000000000 +0300 +@@ -35,7 +35,9 @@ + #include + #endif /* STATIC */ + ++#include + #include ++#include + + #define MIN(a, b) (((a) < (b)) ? (a) : (b)) + +@@ -534,7 +536,7 @@ static inline int INIT process_bit1(stru + + + +-STATIC inline int INIT unlzma(unsigned char *buf, long in_len, ++int unlzma(unsigned char *buf, long in_len, + long (*fill)(void*, unsigned long), + long (*flush)(void*, unsigned long), + unsigned char *output, +@@ -666,6 +668,8 @@ exit_0: + return ret; + } + ++EXPORT_SYMBOL(unlzma); ++ + #ifdef PREBOOT + STATIC int INIT __decompress(unsigned char *buf, long in_len, + long (*fill)(void*, unsigned long), diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-lib_decompress_unlzo.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-lib_decompress_unlzo.c.patch new file mode 100644 index 00000000..e5d08f66 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-lib_decompress_unlzo.c.patch @@ -0,0 +1,11 @@ +diff -drupN a/lib/decompress_unlzo.c b/lib/decompress_unlzo.c +--- a/lib/decompress_unlzo.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/lib/decompress_unlzo.c 2022-06-09 05:02:36.000000000 +0300 +@@ -39,6 +39,7 @@ + + #include + #include ++#include + #include + + #include diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-lib_decompress_unxz.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-lib_decompress_unxz.c.patch new file mode 100644 index 00000000..0b206420 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-lib_decompress_unxz.c.patch @@ -0,0 +1,13 @@ +diff -drupN a/lib/decompress_unxz.c b/lib/decompress_unxz.c +--- a/lib/decompress_unxz.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/lib/decompress_unxz.c 2022-06-09 05:02:36.000000000 +0300 +@@ -102,6 +102,9 @@ + */ + #ifdef STATIC + # define XZ_PREBOOT ++# define INIT ++#else ++# define INIT __init + #endif + #ifdef __KERNEL__ + # include diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-scripts_setlocalversion.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-scripts_setlocalversion.patch new file mode 100644 index 00000000..b0913178 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-scripts_setlocalversion.patch @@ -0,0 +1,19 @@ +diff -drupN a/scripts/setlocalversion b/scripts/setlocalversion +--- a/scripts/setlocalversion 2017-10-21 18:09:07.000000000 +0300 ++++ b/scripts/setlocalversion 2022-06-09 05:02:37.000000000 +0300 +@@ -53,7 +53,6 @@ scm_version() + # If only the short version is requested, don't bother + # running further git commands + if $short; then +- echo "+" + return + fi + # If we are past a tagged commit (like +@@ -167,7 +166,6 @@ else + # LOCALVERSION= is not specified + if test "${LOCALVERSION+set}" != "set"; then + scm=$(scm_version --short) +- res="$res${scm:++}" + fi + fi + diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_core_pcm_native.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_core_pcm_native.c.patch new file mode 100644 index 00000000..9ee289c6 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_core_pcm_native.c.patch @@ -0,0 +1,71 @@ +diff -drupN a/sound/core/pcm_native.c b/sound/core/pcm_native.c +--- a/sound/core/pcm_native.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/sound/core/pcm_native.c 2022-06-09 05:02:37.000000000 +0300 +@@ -1757,6 +1757,34 @@ static int snd_pcm_drain(struct snd_pcm_ + return result; + } + ++#ifdef CONFIG_SND_ALSA_COMMON_CODEC ++#include ++ ++extern void common_codec_must_be_mute(struct snd_pcm_substream *substream); ++ ++extern void common_codec_can_be_unmute(struct snd_pcm_substream *substream); ++ ++ ++static void (*codec_must_be_mute)(struct snd_pcm_substream *substream); ++static void (*codec_can_be_unmute)(struct snd_pcm_substream *substream); ++ ++void snd_pcm_set_codec_mute_callback( ++ void (*_codec_must_be_mute)(struct snd_pcm_substream *), ++ void (*_codec_can_be_unmute)(struct snd_pcm_substream *)) ++{ ++ if (_codec_must_be_mute && codec_must_be_mute) ++ panic("mute callback has been set %p %p", _codec_must_be_mute, codec_must_be_mute); ++ ++ if (_codec_can_be_unmute && codec_can_be_unmute) ++ panic("unmute callback has been set %p %p", _codec_can_be_unmute, codec_can_be_unmute); ++ ++ codec_must_be_mute = _codec_must_be_mute; ++ codec_can_be_unmute = _codec_can_be_unmute; ++} ++EXPORT_SYMBOL(snd_pcm_set_codec_mute_callback); ++ ++#endif ++ + /* + * drop ioctl + * +@@ -1776,6 +1804,13 @@ static int snd_pcm_drop(struct snd_pcm_s + runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) + return -EBADFD; + ++#ifdef CONFIG_SND_ALSA_COMMON_CODEC ++ common_codec_must_be_mute(substream); ++ ++ if (codec_must_be_mute) ++ codec_must_be_mute(substream); ++#endif ++ + snd_pcm_stream_lock_irq(substream); + /* resume pause */ + if (runtime->status->state == SNDRV_PCM_STATE_PAUSED) +@@ -2777,8 +2812,16 @@ static int snd_pcm_common_ioctl1(struct + return snd_pcm_prepare(substream, file); + case SNDRV_PCM_IOCTL_RESET: + return snd_pcm_reset(substream); +- case SNDRV_PCM_IOCTL_START: +- return snd_pcm_action_lock_irq(&snd_pcm_action_start, substream, SNDRV_PCM_STATE_RUNNING); ++ case SNDRV_PCM_IOCTL_START: { ++ int ret; ++ ret = snd_pcm_action_lock_irq(&snd_pcm_action_start, substream, SNDRV_PCM_STATE_RUNNING); ++#ifdef CONFIG_SND_ALSA_COMMON_CODEC ++ common_codec_can_be_unmute(substream); ++ if (codec_can_be_unmute) ++ codec_can_be_unmute(substream); ++#endif ++ return ret; ++ } + case SNDRV_PCM_IOCTL_LINK: + return snd_pcm_link(substream, (int)(unsigned long) arg); + case SNDRV_PCM_IOCTL_UNLINK: diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_Kconfig.patch new file mode 100644 index 00000000..414bfd83 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_Kconfig.patch @@ -0,0 +1,11 @@ +diff -drupN a/sound/soc/Kconfig b/sound/soc/Kconfig +--- a/sound/soc/Kconfig 2017-10-21 18:09:07.000000000 +0300 ++++ b/sound/soc/Kconfig 2022-06-09 05:02:37.000000000 +0300 +@@ -67,6 +67,7 @@ source "sound/soc/txx9/Kconfig" + source "sound/soc/ux500/Kconfig" + source "sound/soc/xtensa/Kconfig" + source "sound/soc/zte/Kconfig" ++source "sound/soc/ingenic/Kconfig" + + # Supported codecs + source "sound/soc/codecs/Kconfig" diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_Makefile.patch new file mode 100644 index 00000000..32b69ee8 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_Makefile.patch @@ -0,0 +1,8 @@ +diff -drupN a/sound/soc/Makefile b/sound/soc/Makefile +--- a/sound/soc/Makefile 2017-10-21 18:09:07.000000000 +0300 ++++ b/sound/soc/Makefile 2022-06-09 05:02:37.000000000 +0300 +@@ -47,3 +47,4 @@ obj-$(CONFIG_SND_SOC) += txx9/ + obj-$(CONFIG_SND_SOC) += ux500/ + obj-$(CONFIG_SND_SOC) += xtensa/ + obj-$(CONFIG_SND_SOC) += zte/ ++obj-$(CONFIG_SND_SOC) += ingenic/ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_Kconfig.patch new file mode 100644 index 00000000..81073991 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_Kconfig.patch @@ -0,0 +1,132 @@ +diff -drupN a/sound/soc/ingenic/Kconfig b/sound/soc/ingenic/Kconfig +--- a/sound/soc/ingenic/Kconfig 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/Kconfig 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,128 @@ ++menuconfig SND_ASOC_INGENIC ++ tristate "ASoC support for Ingenic" ++ depends on (MACH_XBURST=y || MACH_XBURST2=y) && SND_SOC ++ help ++ Say 'Y' to enable Alsa drivers of xburst. ++ ++if SND_ASOC_INGENIC ++config SND_ASOC_INGENIC_DEBUG ++ bool "enable ingenic debug message" ++ default n ++config SND_ASOC_INGENIC_VERBOSE ++ bool "enable ingenic verbose debug message" ++ default n ++ ++choice ++ prompt "Audio Version:" ++ depends on SND_ASOC_INGENIC ++config SND_ASOC_INGENIC_AS_V1 ++ bool "AudioSystem Version 1 For Ingenic SOCs" ++ depends on MACH_XBURST ++ help ++ Audio System Verison 1 for SOC X1000. ++ ++config SND_ASOC_INGENIC_AS_V2 ++ bool "AudioSystem Version 2 For Ingenic SOCs" ++ select SND_DYNAMIC_MINORS ++ depends on MACH_XBURST2 ++ help ++ Audio System Version 2 for SOC X2000, ++endchoice ++ ++ ++if SND_ASOC_INGENIC_AS_V1 ++ ++config SND_ASOC_INGENIC_X1000_BOARD ++ tristate ++ ++config SND_ASOC_INGENIC_AIC ++ tristate ++ ++config SND_ASOC_PDMA ++ tristate ++ select DMADEVICES ++ select INGENIC_PDMAC ++ select SND_SOC_GENERIC_DMAENGINE_PCM ++ ++config SND_ASOC_INGENIC_AIC_SPDIF ++ tristate ++ select SND_ASOC_INGENIC_AIC ++ ++config SND_ASOC_INGENIC_AIC_I2S ++ tristate ++ select SND_ASOC_INGENIC_AIC ++ ++config SND_ASOC_INGENIC_DMIC ++ tristate ++ ++config SND_ASOC_INGENIC_PCM ++ tristate ++ ++config SND_ASOC_INGENIC_ICDC_D3 ++ tristate ++ select SND_ASOC_INGENIC_AIC ++ select SND_ASOC_INGENIC_INCODEC ++ ++config SND_ASOC_INGENIC_DUMP_CODEC ++ tristate ++ ++endif ++ ++ ++if SND_ASOC_INGENIC_AS_V2 ++ ++config SND_ASOC_INGENIC_AS_FE ++ tristate ++config SND_ASOC_INGENIC_AS_BAIC ++ tristate ++ ++config SND_ASOC_INGENIC_AS_VIR_FE ++ depends on SND_ASOC_INGENIC_AS_FE ++ bool "enable ingenic virtual FE" ++ default y ++endif ++ ++ ++menu "Ingenic Board Type Select" ++choice ++ prompt "SOC x1000 codec type select" ++ depends on SOC_X1000 ++ depends on SND_ASOC_INGENIC_AS_V1 ++config SND_ASOC_INGENIC_HALLEY2_ICDC ++ bool "Audio support for halley2 with internal codec" ++ select SND_ASOC_PDMA ++ select SND_ASOC_INGENIC_AIC_I2S ++ select SND_ASOC_INGENIC_ICDC_D3 ++ select SND_ASOC_INGENIC_DMIC ++ select SND_ASOC_INGENIC_PCM ++ select SND_ASOC_INGENIC_DUMP_CODEC ++ select SND_ASOC_INGENIC_X1000_BOARD ++ ++config SND_ASOC_INGENIC_HALLEY2_SPDIF ++ bool "Audio support for halley2 with spdif" ++ select SND_ASOC_PDMA ++ select SND_ASOC_INGENIC_DMIC ++ select SND_ASOC_INGENIC_PCM ++ select SND_ASOC_INGENIC_DUMP_CODEC ++ select SND_ASOC_INGENIC_X1000_BOARD ++ select SND_ASOC_INGENIC_AIC_SPDIF ++endchoice ++ ++choice ++ prompt "SOC x2000 codec Type select" ++ depends on SOC_X2000 ++ depends on SND_ASOC_INGENIC_AS_V2 ++config SND_ASOC_INGENIC_SEAL ++ bool "Audio support for x2000 seal board" ++ select SND_ASOC_INGENIC_AS_FE ++ select SND_ASOC_INGENIC_AS_BAIC ++ #select SND_SOC_WM8594 ++ select SND_SOC_AK4458 ++ select SND_SOC_AK5558 ++endchoice ++ ++endmenu ++ ++endif ++ ++source sound/soc/ingenic/ecodec/Kconfig diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_Makefile.patch new file mode 100644 index 00000000..2c9b212d --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_Makefile.patch @@ -0,0 +1,12 @@ +diff -drupN a/sound/soc/ingenic/Makefile b/sound/soc/ingenic/Makefile +--- a/sound/soc/ingenic/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/Makefile 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,8 @@ ++ ++obj-$(CONFIG_SND_ASOC_INGENIC_AS_V1) += as-v1/ ++obj-$(CONFIG_SND_ASOC_INGENIC_AS_V2) += as-v2/ ++ ++obj-y += icodec/ ++obj-y += boards/ ++obj-y += ecodec/ ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_README.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_README.patch new file mode 100644 index 00000000..1491e9d2 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_README.patch @@ -0,0 +1,35 @@ +diff -drupN a/sound/soc/ingenic/README b/sound/soc/ingenic/README +--- a/sound/soc/ingenic/README 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/README 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,31 @@ ++DIRs: ++. ++├── as-v1/ ++├── as-v2/ ++├── boards/ ++├── icodec/ ++├── ecodec/ ++├── Kconfig ++├── Makefile ++└── README ++ ++--- ++as-v1: ++ Audio System Version 1. ++ Support SOCs ++ -X1000 Series. ++--- ++as-v2: Audio System Version 2. ++ Support SOCs ++ -X2000 Series. ++--- ++boards: Boards config. ++icodec: Internal Codecs. ++ecodec: External Codecs. ++ ++ ++## Tested Usable External codecs ++ ++ak4458 ++ak5558 ++wm8594 diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_Makefile.patch new file mode 100644 index 00000000..674e2628 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_Makefile.patch @@ -0,0 +1,12 @@ +diff -drupN a/sound/soc/ingenic/as-v1/Makefile b/sound/soc/ingenic/as-v1/Makefile +--- a/sound/soc/ingenic/as-v1/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/as-v1/Makefile 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,8 @@ ++ ++obj-$(CONFIG_SND_ASOC_INGENIC_DMIC) += asoc-dmic.o ++obj-$(CONFIG_SND_ASOC_INGENIC_PCM) += asoc-pcm.o ++ ++obj-$(CONFIG_SND_ASOC_PDMA) += asoc-dma.o ++obj-$(CONFIG_SND_ASOC_INGENIC_AIC) += asoc-aic.o ++obj-$(CONFIG_SND_ASOC_INGENIC_AIC_I2S) += asoc-i2s.o ++obj-$(CONFIG_SND_ASOC_INGENIC_AIC_SPDIF) += asoc-spdif.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_asoc-aic.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_asoc-aic.c.patch new file mode 100644 index 00000000..ff999638 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_asoc-aic.c.patch @@ -0,0 +1,277 @@ +diff -drupN a/sound/soc/ingenic/as-v1/asoc-aic.c b/sound/soc/ingenic/as-v1/asoc-aic.c +--- a/sound/soc/ingenic/as-v1/asoc-aic.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/as-v1/asoc-aic.c 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,273 @@ ++/* ++ * sound/soc/ingenic/asoc-aic.c ++ * ALSA Soc Audio Layer -- ingenic aic device driver ++ * ++ * Copyright 2014 Ingenic Semiconductor Co.,Ltd ++ * cli ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "asoc-aic.h" ++ ++#define INGENIC_I2S_RATE (24*1000000) ++static const char *aic_no_mode = "no mode"; ++static const char *aic_i2s_mode = "i2s mode"; ++static const char *aic_spdif_mode = "spdif mode"; ++static const char *aic_ac97_mode = "ac97 mode"; ++ ++const char* aic_work_mode_str(enum aic_mode mode) ++{ ++ switch (mode) { ++ default: ++ case AIC_NO_MODE: ++ return aic_no_mode; ++ case AIC_I2S_MODE: ++ return aic_i2s_mode; ++ case AIC_SPDIF_MODE: ++ return aic_spdif_mode; ++ case AIC_AC97_MODE: ++ return aic_ac97_mode; ++ } ++} ++EXPORT_SYMBOL_GPL(aic_work_mode_str); ++ ++enum aic_mode aic_set_work_mode(struct device *aic, ++ enum aic_mode module_mode, bool enable) ++{ ++ struct ingenic_aic *ingenic_aic = dev_get_drvdata(aic); ++ enum aic_mode working_mode; ++ ++ spin_lock(&ingenic_aic->mode_lock); ++ if (module_mode != AIC_AC97_MODE && ++ module_mode != AIC_I2S_MODE && ++ module_mode != AIC_SPDIF_MODE) ++ goto out; ++ ++ if (enable && ingenic_aic->aic_working_mode == AIC_NO_MODE) { ++ ingenic_aic->aic_working_mode = module_mode; ++ } else if (!enable && ingenic_aic->aic_working_mode == module_mode) { ++ ingenic_aic->aic_working_mode = AIC_NO_MODE; ++ } ++out: ++ working_mode = ingenic_aic->aic_working_mode; ++ spin_unlock(&ingenic_aic->mode_lock); ++ return working_mode; ++} ++EXPORT_SYMBOL_GPL(aic_set_work_mode); ++ ++int aic_set_rate(struct device *aic, unsigned long freq) ++{ ++ struct ingenic_aic *ingenic_aic = dev_get_drvdata(aic); ++ int ret; ++ if (ingenic_aic->clk_rate != freq) { ++ ret = clk_set_rate(ingenic_aic->clk, freq); ++ if (ret == -EBUSY) { ++ clk_disable_unprepare(ingenic_aic->clk); ++ ret = clk_set_rate(ingenic_aic->clk, freq); ++ clk_prepare_enable(ingenic_aic->clk); ++ } ++ ingenic_aic->clk_rate = clk_get_rate(ingenic_aic->clk); ++ } ++ return ingenic_aic->clk_rate; ++} ++EXPORT_SYMBOL_GPL(aic_set_rate); ++ ++static irqreturn_t ingenic_aic_irq_thread(int irq, void *dev_id) ++{ ++ struct ingenic_aic *ingenic_aic = (struct ingenic_aic *)dev_id; ++ ++ if ((ingenic_aic->mask & 0x8) && __aic_test_ror(ingenic_aic->dev)) { ++ ingenic_aic->ror++; ++ dev_printk(KERN_DEBUG, ingenic_aic->dev, ++ "recieve fifo [overrun] interrupt time [%d]\n", ++ ingenic_aic->ror); ++ } ++ ++ if ((ingenic_aic->mask & 0x4) && __aic_test_tur(ingenic_aic->dev)) { ++ ingenic_aic->tur++; ++ dev_printk(KERN_DEBUG, ingenic_aic->dev, ++ "transmit fifo [underrun] interrupt time [%d]\n", ++ ingenic_aic->tur); ++ } ++ ++ if ((ingenic_aic->mask & 0x2) && __aic_test_rfs(ingenic_aic->dev)) { ++ dev_printk(KERN_DEBUG, ingenic_aic->dev, ++ "[recieve] fifo at or above threshold interrupt time\n"); ++ } ++ ++ if ((ingenic_aic->mask & 0x1) && __aic_test_tfs(ingenic_aic->dev)) { ++ dev_printk(KERN_DEBUG, ingenic_aic->dev, ++ "[transmit] fifo at or blow threshold interrupt time\n"); ++ } ++ ++ /*sleep, avoid frequently interrupt*/ ++ msleep(200); ++ __aic_clear_all_irq_flag(ingenic_aic->dev); ++ __aic_set_irq_enmask(ingenic_aic->dev, ingenic_aic->mask); ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t ingenic_aic_irq_handler(int irq, void *dev_id) ++{ ++ struct ingenic_aic *ingenic_aic = (struct ingenic_aic *)dev_id; ++ ++ ingenic_aic->mask = __aic_get_irq_enmask(ingenic_aic->dev); ++ if (ingenic_aic->mask && (ingenic_aic->mask & __aic_get_irq_flag(ingenic_aic->dev))) { ++ /*Disable all aic interrupt*/ ++ __aic_set_irq_enmask(ingenic_aic->dev, 0); ++ return IRQ_WAKE_THREAD; ++ } ++ return IRQ_NONE; ++} ++ ++extern int ingenic_dma_pcm_register(struct device *dev, const struct snd_dmaengine_pcm_config *config); ++extern void ingenic_dma_pcm_unregister(struct device *dev); ++ ++static int ingenic_aic_probe(struct platform_device *pdev) ++{ ++ struct ingenic_aic *ingenic_aic; ++ struct resource *res = NULL; ++ struct device_node *subdev_node = NULL; ++ int ret, nr_child, i = 0; ++ ++ nr_child = of_get_child_count(pdev->dev.of_node); ++ ++ ingenic_aic = devm_kzalloc(&pdev->dev, sizeof(struct ingenic_aic) + nr_child * sizeof(void *), ++ GFP_KERNEL); ++ if (!ingenic_aic) ++ return -ENOMEM; ++ ++ ingenic_aic->dev = &pdev->dev; ++ ingenic_aic->subdevs = nr_child; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) ++ return -ENOENT; ++ ++ ingenic_aic->vaddr_base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(ingenic_aic->vaddr_base)) ++ return -ENOMEM; ++ ++ ingenic_aic->clk_gate = devm_clk_get(&pdev->dev, "gate_aic"); ++ if (IS_ERR(ingenic_aic->clk_gate)) ++ return PTR_ERR(ingenic_aic->clk_gate); ++ ++ ingenic_aic->clk = devm_clk_get(&pdev->dev, "cgu_i2s"); ++ if (IS_ERR(ingenic_aic->clk)) ++ return PTR_ERR(ingenic_aic->clk); ++ clk_set_rate(ingenic_aic->clk, INGENIC_I2S_RATE); ++ ++ spin_lock_init(&ingenic_aic->mode_lock); ++ ++ ingenic_aic->irqno = platform_get_irq(pdev, 0); ++ if (ingenic_aic->irqno >= 0) ++ ret = devm_request_threaded_irq(&pdev->dev, ingenic_aic->irqno, ++ ingenic_aic_irq_handler, ingenic_aic_irq_thread, ++ IRQF_SHARED , pdev->name, (void *)ingenic_aic); ++ if (!ret) ++ dev_info(&pdev->dev, "register aic irq\n"); ++ ++ platform_set_drvdata(pdev, (void *)ingenic_aic); ++ ++ clk_prepare_enable(ingenic_aic->clk); ++ clk_prepare_enable(ingenic_aic->clk_gate); ++ ++ for_each_child_of_node(pdev->dev.of_node, subdev_node) ++ ingenic_aic->psubdev[i++] = of_platform_device_create(subdev_node, NULL, &pdev->dev); ++ ++ ret = ingenic_dma_pcm_register(&pdev->dev, NULL); ++ if (ret) { ++ int i; ++ for (i = 0; i < ingenic_aic->subdevs; i++) ++ platform_device_unregister(ingenic_aic->psubdev[i]); ++ clk_disable_unprepare(ingenic_aic->clk_gate); ++ clk_disable_unprepare(ingenic_aic->clk); ++ return ret; ++ } ++ ++ dev_info(&pdev->dev, "Aic core probe success\n"); ++ return 0; ++} ++ ++static int ingenic_aic_remove(struct platform_device *pdev) ++{ ++ struct ingenic_aic * ingenic_aic = platform_get_drvdata(pdev); ++ int i; ++ ++ ingenic_dma_pcm_unregister(&pdev->dev); ++ ++ if (!ingenic_aic) ++ return 0; ++ ++ for (i = 0; i < ingenic_aic->subdevs; i++) ++ platform_device_unregister(ingenic_aic->psubdev[i]); ++ ++ platform_set_drvdata(pdev, NULL); ++ ++ clk_disable_unprepare(ingenic_aic->clk_gate); ++ clk_disable_unprepare(ingenic_aic->clk); ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++int ingenic_aic_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ struct ingenic_aic * ingenic_aic = platform_get_drvdata(pdev); ++ clk_disable(ingenic_aic->clk_gate); ++ return 0; ++} ++ ++int ingenic_aic_resume(struct platform_device *pdev) ++{ ++ struct ingenic_aic * ingenic_aic = platform_get_drvdata(pdev); ++ clk_enable(ingenic_aic->clk_gate); ++ return 0; ++} ++#endif ++ ++static const struct of_device_id aic_dt_match[] = { ++ { .compatible = "ingenic,aic", .data = NULL }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, aic_dt_match); ++ ++static struct platform_driver ingenic_asoc_aic_driver = { ++ .driver = { ++ .name = "asoc-aic", ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(aic_dt_match), ++ }, ++ .probe = ingenic_aic_probe, ++ .remove = ingenic_aic_remove, ++#ifdef CONFIG_PM ++ .suspend = ingenic_aic_suspend, ++ .resume = ingenic_aic_resume, ++#endif ++}; ++module_platform_driver(ingenic_asoc_aic_driver); ++ ++MODULE_DESCRIPTION("INGENIC ASOC AIC core driver"); ++MODULE_AUTHOR("cli"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:ingenic-asoc-aic"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_asoc-aic.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_asoc-aic.h.patch new file mode 100644 index 00000000..bc21326b --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_asoc-aic.h.patch @@ -0,0 +1,638 @@ +diff -drupN a/sound/soc/ingenic/as-v1/asoc-aic.h b/sound/soc/ingenic/as-v1/asoc-aic.h +--- a/sound/soc/ingenic/as-v1/asoc-aic.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/as-v1/asoc-aic.h 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,634 @@ ++/* ++ * sound/soc/ingenic/asoc-aic.h ++ * ALSA Soc Audio Layer -- ingenic aic platform driver ++ * ++ * Copyright 2014 Ingenic Semiconductor Co.,Ltd ++ * cli ++ * ++ * 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. ++ */ ++#ifndef __ASOC_AIC_H__ ++#define __ASOC_AIC_H__ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#define INGENIC_I2S_INNER_CODEC 0 ++#define INGENIC_I2S_EX_CODEC 1 ++ ++ ++struct ingenic_aic_subdev_pdata { ++ dma_addr_t dma_base; ++}; ++ ++enum aic_mode { ++ AIC_NO_MODE = 0, ++ AIC_I2S_MODE, ++ AIC_SPDIF_MODE, ++ AIC_AC97_MODE ++}; ++ ++struct ingenic_aic { ++ struct device *dev; ++ void __iomem *vaddr_base; ++ struct clk *clk; ++ struct clk *clk_gate; ++ unsigned long clk_rate; ++ /*for interrupt*/ ++ int irqno; ++ unsigned int ror; /*counter for debug*/ ++ unsigned int tur; ++ int mask; ++ /*for aic work mode protect*/ ++ spinlock_t mode_lock; ++ enum aic_mode aic_working_mode; ++ /*for subdev*/ ++ int subdevs; ++ struct platform_device* psubdev[]; ++}; ++ ++const char* aic_work_mode_str(enum aic_mode mode); ++int aic_set_rate(struct device *aic, unsigned long freq); ++enum aic_mode aic_set_work_mode(struct device *aic, enum aic_mode module_mode, bool enable); ++ ++static void inline ingenic_aic_write_reg(struct device *dev, unsigned int reg, ++ unsigned int val) ++{ ++ struct ingenic_aic *ingenic_aic = dev_get_drvdata(dev); ++ writel(val, ingenic_aic->vaddr_base + reg); ++} ++ ++static unsigned int inline ingenic_aic_read_reg(struct device *dev, unsigned int reg) ++{ ++ struct ingenic_aic *ingenic_aic = dev_get_drvdata(dev); ++ return readl(ingenic_aic->vaddr_base + reg); ++} ++ ++/* For AC97 and I2S */ ++#define AICFR (0x00) ++#define AICCR (0x04) ++#define ACCR1 (0x08) ++#define ACCR2 (0x0c) ++#define I2SCR (0x10) ++#define AICSR (0x14) ++#define ACSR (0x18) ++#define I2SSR (0x1c) ++#define ACCAR (0x20) ++#define ACCDR (0x24) ++#define ACSAR (0x28) ++#define ACSDR (0x2c) ++#define I2SDIV (0x30) ++#define AICDR (0x34) ++ ++/* For SPDIF */ ++#define SPENA (0x80) ++#define SPCTRL (0x84) ++#define SPSTATE (0x88) ++#define SPCFG1 (0x8c) ++#define SPCFG2 (0x90) ++#define SPFIFO (0x94) ++ ++/* For AICFR */ ++#define AICFR_ENB_BIT (0) ++#define AICFR_ENB_MASK (1 << AICFR_ENB_BIT) ++#define AICFR_SYNCD_BIT (1) ++#define AICFR_SYNCD_MASK (1 << AICFR_SYNCD_BIT) ++#define AICFR_BCKD_BIT (2) ++#define AICFR_BCKD_MASK (1 << AICFR_BCKD_BIT) ++#define AICFR_RST_BIT (3) ++#define AICFR_RST_MASK (1 << AICFR_RST_BIT) ++#define AICFR_AUSEL_BIT (4) ++#define AICFR_AUSEL_MASK (1 << AICFR_AUSEL_BIT) ++#define AICFR_ICDC_BIT (5) ++#define AICFR_ICDC_MASK (1 << AICFR_ICDC_BIT) ++#define AICFR_LSMP_BIT (6) ++#define AICFR_LSMP_MASK (1 << AICFR_LSMP_BIT) ++#define AICFR_CDC_SLV_BIT (7) ++#define AICFR_CDC_SLV_MASK (1 << AICFR_CDC_SLV_BIT) ++#define AICFR_DMODE_BIT (8) ++#define AICFR_DMODE_MASK (1 << AICFR_DMODE_BIT) ++#define AICFR_ISYNCD_BIT (9) ++#define AICFR_ISYNCD_MASK (1 << AICFR_ISYNCD_BIT) ++#define AICFR_IBCKD_BIT (10) ++#define AICFR_IBCKD_MASK (1 << AICFR_IBCKD_BIT) ++#define AICFR_SYSCLKD_BIT (11) ++#define AICFR_SYSCLKD_MASK (1 << AICFR_SYSCLKD_BIT) ++#define AICFR_MSB_BIT (12) ++#define AICFR_MSB_MASK (1 << AICFR_MSB_BIT) ++#define AICFR_TFTH_BIT (16) ++#define AICFR_TFTH_MASK (0x1f << AICFR_TFTH_BIT) ++#define AICFR_RFTH_BIT (24) ++#define AICFR_RFTH_MASK (0x1f << AICFR_RFTH_BIT) ++ ++/* For AICCR */ ++#define AICCR_EREC_BIT (0) ++#define AICCR_EREC_MASK (1 << AICCR_EREC_BIT) ++#define AICCR_ERPL_BIT (1) ++#define AICCR_ERPL_MASK (1 << AICCR_ERPL_BIT) ++#define AICCR_ENLBF_BIT (2) ++#define AICCR_ENLBF_MASK (1 << AICCR_ENLBF_BIT) ++#define AICCR_ETFS_BIT (3) ++#define AICCR_ETFS_MASK (1 << AICCR_ETFS_BIT) ++#define AICCR_ERFS_BIT (4) ++#define AICCR_ERFS_MASK (1 << AICCR_ERFS_BIT) ++#define AICCR_ETUR_BIT (5) ++#define AICCR_ETUR_MASK (1 << AICCR_ETUR_BIT) ++#define AICCR_EROR_BIT (6) ++#define AICCR_EROR_MASK (1 << AICCR_EROR_BIT) ++#define AICCR_EALL_INT_MASK (AICCR_EROR_MASK|AICCR_ETUR_MASK|AICCR_ERFS_MASK|AICCR_ETFS_MASK) ++#define AICCR_RFLUSH_BIT (7) ++#define AICCR_RFLUSH_MASK (1 << AICCR_RFLUSH_BIT) ++#define AICCR_TFLUSH_BIT (8) ++#define AICCR_TFLUSH_MASK (1 << AICCR_TFLUSH_BIT) ++#define AICCR_ASVTSU_BIT (9) ++#define AICCR_ASVTSU_MASK (1 << AICCR_ASVTSU_BIT) ++#define AICCR_ENDSW_BIT (10) ++#define AICCR_ENDSW_MASK (1 << AICCR_ENDSW_BIT) ++#define AICCR_M2S_BIT (11) ++#define AICCR_M2S_MASK (1 << AICCR_M2S_BIT) ++#define AICCR_TDMS_BIT (14) ++#define AICCR_TDMS_MASK (1 << AICCR_TDMS_BIT) ++#define AICCR_RDMS_BIT (15) ++#define AICCR_RDMS_MASK (1 << AICCR_RDMS_BIT) ++#define AICCR_ISS_BIT (16) ++#define AICCR_ISS_MASK (0x7 << AICCR_ISS_BIT) ++#define AICCR_OSS_BIT (19) ++#define AICCR_OSS_MASK (0x7 << AICCR_OSS_BIT) ++#define AICCR_CHANNEL_BIT (24) ++#define AICCR_CHANNEL_MASK (0x7 << AICCR_CHANNEL_BIT) ++#define AICCR_PACK16_BIT (28) ++#define AICCR_PACK16_MASK (1 << AICCR_PACK16_BIT) ++ ++/* For ACCR1 */ ++#define ACCR1_XS_BIT (0) ++#define ACCR1_XS_MASK (0x3ff << ACCR1_XS_BIT) ++#define ACCR1_RS_BIT (16) ++#define ACCR1_RS_MASK (0x3ff << ACCR1_RS_BIT) ++ ++/* For ACCR2 */ ++#define ACCR2_SA_BIT (0) ++#define ACCR2_SA_MASK (1 << ACCR2_SA_BIT) ++#define ACCR2_SS_BIT (1) ++#define ACCR2_SS_MASK (1 << ACCR2_SS_BIT) ++#define ACCR2_SR_BIT (2) ++#define ACCR2_SR_MASK (1 << ACCR2_SR_BIT) ++#define ACCR2_SO_BIT (3) ++#define ACCR2_SO_MASK (1 << ACCR2_SO_BIT) ++#define ACCR2_ECADT_BIT (16) ++#define ACCR2_ECADT_MASK (1 << ACCR2_ECADT_BIT) ++#define ACCR2_ECADR_BIT (17) ++#define ACCR2_ECADR_MASK (1 << ACCR2_ECADR_BIT) ++#define ACCR2_ERSTO_BIT (18) ++#define ACCR2_ERSTO_MASK (1 << ACCR2_ERSTO_BIT) ++ ++/* For I2SCR */ ++#define I2SCR_AMSL_BIT (0) ++#define I2SCR_AMSL_MASK (1 << I2SCR_AMSL_BIT) ++#define I2SCR_ESCLK_BIT (4) ++#define I2SCR_ESCLK_MASK (1 << I2SCR_ESCLK_BIT) ++#define I2SCR_STPBK_BIT (12) ++#define I2SCR_STPBK_MASK (1 << I2SCR_STPBK_BIT) ++#define I2SCR_ISTPBK_BIT (13) ++#define I2SCR_ISTPBK_MASK (1 << I2SCR_ISTPBK_BIT) ++#define I2SCR_SWLH_BIT (16) ++#define I2SCR_SWLH_MASK (1 << I2SCR_SWLH_BIT) ++#define I2SCR_RFIRST_BIT (17) ++#define I2SCR_RFIRST_MASK (1 << I2SCR_RFIRST_BIT) ++ ++/* For AICSR */ ++#define AICSR_TFS_BIT (3) ++#define AICSR_TFS_MASK (1 << AICSR_TFS_BIT) ++#define AICSR_RFS_BIT (4) ++#define AICSR_RFS_MASK (1 << AICSR_RFS_BIT) ++#define AICSR_TUR_BIT (5) ++#define AICSR_TUR_MASK (1 << AICSR_TUR_BIT) ++#define AICSR_ROR_BIT (6) ++#define AICSR_ROR_MASK (1 << AICSR_ROR_BIT) ++#define AICSR_ALL_INT_MASK (AICSR_TFS_MASK|AICSR_RFS_MASK|AICSR_TUR_MASK|AICSR_ROR_MASK) ++#define AICSR_TFL_BIT (8) ++#define AICSR_TFL_MASK (0x3f << AICSR_TFL_BIT) ++#define AICSR_RFL_BIT (24) ++#define AICSR_RFL_MASK (0x3f << AICSR_RFL_BIT) ++ ++/* For ACSR */ ++#define ACSR_CADT_BIT (16) ++#define ACSR_CADT_MASK (1 << ACSR_CADT_BIT) ++#define ACSR_SADR_BIT (17) ++#define ACSR_SADR_MASK (1 << ACSR_SADR_BIT) ++#define ACSR_RSTO_BIT (18) ++#define ACSR_RSTO_MASK (1 << ACSR_RSTO_BIT) ++#define ACSR_CLPM_BIT (19) ++#define ACSR_CLPM_MASK (1 << ACSR_CLPM_BIT) ++#define ACSR_CRDY_BIT (20) ++#define ACSR_CRDY_MASK (1 << ACSR_CRDY_BIT) ++#define ACSR_SLTERR_BIT (21) ++#define ACSR_SLTERR_MASK (1 << ACSR_SLTERR_BIT) ++ ++/* For I2SSR */ ++#define I2SSR_BSY_BIT (2) ++#define I2SSR_BSY_MASK (1 << I2SSR_BSY_BIT) ++#define I2SSR_RBSY_BIT (3) ++#define I2SSR_RBSY_MASK (1 << I2SSR_RBSY_BIT) ++#define I2SSR_TBSY_BIT (4) ++#define I2SSR_TBSY_MASK (1 << I2SSR_TBSY_BIT) ++#define I2SSR_CHBSY_BIT (5) ++#define I2SSR_CHBSY_MASK (1 << I2SSR_CHBSY_BIT) ++ ++/* For ACCAR */ ++#define ACCAR_CAR_BIT (0) ++#define ACCAR_CAR_MASK (0xfffff << ACCAR_CAR_BIT) ++ ++/* For ACCDR */ ++#define ACCDR_CDR_BIT (0) ++#define ACCDR_CDR_MASK (0xfffff << ACCDR_CDR_BIT) ++ ++/* For ACSAR */ ++#define ACSAR_SAR_BIT (0) ++#define ACSAR_SAR_MASK (0xfffff << ACSAR_SAR_BIT) ++ ++/* For ACSDR */ ++#define ACSDR_SDR_BIT (0) ++#define ACSDR_SDR_MASK (0xfffff << ACSDR_SDR_BIT) ++ ++/* For I2SDIV */ ++#define I2SDIV_DV_BIT (0) ++#define I2SDIV_DV_MASK (0x1ff << I2SDIV_DV_BIT) ++#define I2SDIV_IDV_BIT (16) ++#define I2SDIV_IDV_MASK (0x1ff << I2SDIV_IDV_BIT) ++ ++/* For AICDR */ ++#define AICDR_DATA_BIT (0) ++#define AICDR_DATA_MASK (0xfffffff << AICDR_DATA_BIT) ++ ++/* For SPENA */ ++#define SPENA_SPEN_BIT (0) ++#define SPENA_SPEN_MASK (1 << SPENA_SPEN_BIT) ++ ++/* For SPCTRL */ ++#define SPCTRL_M_FFUR_BIT (0) ++#define SPCTRL_M_FFUR_MASK (1 << SPCTRL_M_FFUR_BIT) ++#define SPCTRL_M_TRIG_BIT (1) ++#define SPCTRL_M_TRIG_MASK (1 << SPCTRL_M_TRIG_BIT) ++#define SPCTRL_SPDIF_I2S_BIT (10) ++#define SPCTRL_SPDIF_I2S_MASK (1 << SPCTRL_SPDIF_I2S_BIT) ++#define SPCTRL_SFT_RST_BIT (11) ++#define SPCTRL_SFT_RST_MASK (1 << SPCTRL_SFT_RST_BIT) ++#define SPCTRL_INVALID_BIT (12) ++#define SPCTRL_INVALID_MASK (1 << SPCTRL_INVALID_BIT) ++#define SPCTRL_SIGN_N_BIT (13) ++#define SPCTRL_SIGN_N_MASK (1 << SPCTRL_SIGN_N_BIT) ++#define SPCTRL_D_TYPE_BIT (14) ++#define SPCTRL_D_TYPE_MASK (1 << SPCTRL_D_TYPE_BIT) ++#define SPCTRL_DMA_EN_BIT (15) ++#define SPCTRL_DMA_EN_MASK (1 << SPCTRL_DMA_EN_BIT) ++ ++/* For SPSTATE */ ++#define SPSTATE_F_FFUR_BIT (0) ++#define SPSTATE_F_FFUR_MASK (1 << SPSTATE_F_FFUR_BIT) ++#define SPSTATE_F_TRIG_BIT (1) ++#define SPSTATE_F_TRIG_MASK (1 << SPSTATE_F_TRIG_BIT) ++#define SPSTATE_BUSY_BIT (7) ++#define SPSTATE_BUSY_MASK (1 << SPSTATE_BUSY_BIT) ++#define SPSTATE_FIFO_LVL_BIT (8) ++#define SPSTATE_FIFO_LVL_MASK (0x7f << SPSTATE_FIFO_LVL_BIT) ++ ++/* For SPCFG1 */ ++#define SPCFG1_CH2_NUM_BIT (0) ++#define SPCFG1_CH2_NUM_MASK (0xf << SPCFG1_CH2_NUM_BIT) ++#define SPCFG1_CH1_NUM_BIT (4) ++#define SPCFG1_CH1_NUM_MASK (0xf << SPCFG1_CH1_NUM_BIT) ++#define SPCFG1_SRC_NUM_BIT (8) ++#define SPCFG1_SRC_NUM_MASK (0xf << SPCFG1_SRC_NUM_BIT) ++#define SPCFG1_TRIG_BIT (12) ++#define SPCFG1_TRIG_MASK (0x3 << SPCFG1_TRIG_BIT) ++#define SPCFG1_ZRO_VLD_BIT (16) ++#define SPCFG1_ZRO_VLD_MASK (1 << SPCFG1_ZRO_VLD_BIT) ++#define SPCFG1_INIT_LVL_BIT (17) ++#define SPCFG1_INIT_LVL_MASK (1 << SPCFG1_INIT_LVL_BIT) ++ ++/* For SPCFG2 */ ++#define SPCFG2_CON_PRO_BIT (0) ++#define SPCFG2_CON_PRO_MASK (1 << SPCFG2_CON_PRO_BIT) ++#define SPCFG2_AUDIO_N_BIT (1) ++#define SPCFG2_AUDIO_N_MASK (1 << SPCFG2_AUDIO_N_BIT) ++#define SPCFG2_COPY_N_BIT (2) ++#define SPCFG2_COPY_N_MASK (1 << SPCFG2_COPY_N_BIT) ++#define SPCFG2_PRE_BIT (3) ++#define SPCFG2_PRE_MASK (1 << SPCFG2_PRE_BIT) ++#define SPCFG2_CH_MD_BIT (6) ++#define SPCFG2_CH_MD_MASK (0x3 << SPCFG2_CH_MD_BIT) ++#define SPCFG2_CAT_CODE_BIT (8) ++#define SPCFG2_CAT_CODE_MASK (0xff << SPCFG2_CAT_CODE_BIT) ++#define SPCFG2_CLK_ACU_BIT (16) ++#define SPCFG2_CLK_ACU_MASK (0x3 << SPCFG2_CLK_ACU_BIT) ++#define SPCFG2_MAX_WL_BIT (18) ++#define SPCFG2_MAX_WL_MASK (1 << SPCFG2_MAX_WL_BIT) ++#define SPCFG2_SAMPL_WL_BIT (19) ++#define SPCFG2_SAMPL_WL_MASK (0x7 << SPCFG2_SAMPL_WL_BIT) ++#define SPCFG2_SAMPL_WL_20BITM (0x1 << SPCFG2_SAMPL_WL_BIT) ++#define SPCFG2_SAMPL_WL_21BIT (0x6 << SPCFG2_SAMPL_WL_BIT) ++#define SPCFG2_SAMPL_WL_22BIT (0x2 << SPCFG2_SAMPL_WL_BIT) ++#define SPCFG2_SAMPL_WL_23BIT (0x4 << SPCFG2_SAMPL_WL_BIT) ++#define SPCFG2_SAMPL_WL_24BIT (0x5 << SPCFG2_SAMPL_WL_BIT) ++#define SPCFG2_SAMPL_WL_16BIT (0x1 << SPCFG2_SAMPL_WL_BIT) ++#define SPCFG2_SAMPL_WL_17BIT (0x6 << SPCFG2_SAMPL_WL_BIT) ++#define SPCFG2_SAMPL_WL_18BIT (0x2 << SPCFG2_SAMPL_WL_BIT) ++#define SPCFG2_SAMPL_WL_19BIT (0x4 << SPCFG2_SAMPL_WL_BIT) ++#define SPCFG2_SAMPL_WL_20BITL (0x5 << SPCFG2_SAMPL_WL_BIT) ++#define SPCFG2_ORG_FRQ_BIT (22) ++#define SPCFG2_ORG_FRQ_MASK (0xf << SPCFG2_ORG_FRQ_BIT) ++#define SPCFG2_FS_BIT (26) ++#define SPCFG2_FS_MASK (0xf << SPCFG2_FS_BIT) ++ ++#define SPFIFO_DATA_BIT (0) ++#define SPFIFO_DATA_MASK (0xffffff << SPFIFO_DATA_BIT) ++ ++#define ingenic_aic_set_reg(parent, addr, val, mask, offset) \ ++ do { \ ++ volatile unsigned int reg_tmp; \ ++ reg_tmp = ingenic_aic_read_reg(parent, addr); \ ++ reg_tmp &= ~(mask); \ ++ reg_tmp |= (val << offset) & mask; \ ++ ingenic_aic_write_reg(parent, addr, reg_tmp); \ ++ } while(0) ++ ++#define ingenic_aic_get_reg(parent, addr, mask, offset) \ ++ ((ingenic_aic_read_reg(parent, addr) & mask) >> offset) ++ ++/*For ALL*/ ++/*aic fr*/ ++#define __aic_enable_msb(parent) \ ++ ingenic_aic_set_reg(parent, AICFR, 1, AICFR_MSB_MASK, AICFR_MSB_BIT) ++#define __aic_disable_msb(parent) \ ++ ingenic_aic_set_reg(parent, AICFR, 0, AICFR_MSB_MASK, AICFR_MSB_BIT) ++#define __aic_reset(parent) \ ++ ingenic_aic_set_reg(parent, AICFR, 1, AICFR_RST_MASK, AICFR_RST_BIT) ++/*aic cr*/ ++#define __aic_flush_rxfifo(parent) \ ++ ingenic_aic_set_reg(parent, AICCR, 1, AICCR_RFLUSH_MASK, AICCR_RFLUSH_BIT) ++#define __aic_flush_txfifo(parent) \ ++ ingenic_aic_set_reg(parent, AICCR, 1, AICCR_TFLUSH_MASK, AICCR_TFLUSH_BIT) ++#define __aic_en_ror_int(parent) \ ++ ingenic_aic_set_reg(parent, AICCR, 1, AICCR_EROR_MASK, AICCR_EROR_BIT) ++#define __aic_dis_ror_int(parent) \ ++ ingenic_aic_set_reg(parent, AICCR, 0, AICCR_EROR_MASK, AICCR_EROR_BIT) ++#define __aic_en_tur_int(parent) \ ++ ingenic_aic_set_reg(parent, AICCR, 1, AICCR_ETUR_MASK, AICCR_ETUR_BIT) ++#define __aic_dis_tur_int(parent) \ ++ ingenic_aic_set_reg(parent, AICCR, 0, AICCR_ETUR_MASK, AICCR_ETUR_BIT) ++#define __aic_en_rfs_int(parent) \ ++ ingenic_aic_set_reg(parent, AICCR, 1, AICCR_ERFS_MASK, AICCR_ERFS_BIT) ++#define __aic_dis_rfs_int(parent) \ ++ ingenic_aic_set_reg(parent, AICCR, 0, AICCR_ERFS_MASK, AICCR_ERFS_BIT) ++#define __aic_en_tfs_int(parent) \ ++ ingenic_aic_set_reg(parent, AICCR, 1, AICCR_ETFS_MASK, AICCR_ETFS_BIT) ++#define __aic_dis_tfs_int(parent) \ ++ ingenic_aic_set_reg(parent, AICCR, 0, AICCR_ETFS_MASK, AICCR_ETFS_BIT) ++#define __aic_get_irq_enmask(parent) \ ++ ingenic_aic_get_reg(parent, AICCR, AICCR_EALL_INT_MASK, AICCR_ETFS_BIT) ++#define __aic_set_irq_enmask(parent, mask) \ ++ ingenic_aic_set_reg(parent, AICCR, mask, AICCR_EALL_INT_MASK, AICCR_ETFS_BIT) ++/*aic sr*/ ++#define __aic_read_rfl(parent) \ ++ ingenic_aic_get_reg(parent, AICSR ,AICSR_RFL_MASK, AICSR_RFL_BIT) ++#define __aic_read_tfl(parent) \ ++ ingenic_aic_get_reg(parent, AICSR, AICSR_TFL_MASK, AICSR_TFL_BIT) ++#define __aic_clear_ror(parent) \ ++ ingenic_aic_set_reg(parent, AICSR, 0, AICSR_ROR_MASK, AICSR_ROR_BIT) ++#define __aic_test_ror(parent) \ ++ ingenic_aic_get_reg(parent, AICSR, AICSR_ROR_MASK, AICSR_ROR_BIT) ++#define __aic_clear_tur(parent) \ ++ ingenic_aic_set_reg(parent, AICSR, 0, AICSR_TUR_MASK, AICSR_TUR_BIT) ++#define __aic_test_tur(parent) \ ++ ingenic_aic_get_reg(parent, AICSR, AICSR_TUR_MASK, AICSR_TUR_BIT) ++#define __aic_clear_rfs(parent) \ ++ ingenic_aic_set_reg(parent, AICSR, 0, AICSR_RFS_MASK, AICSR_RFS_BIT) ++#define __aic_test_rfs(parent) \ ++ ingenic_aic_get_reg(parent, AICSR, AICSR_RFS_MASK, AICSR_RFS_BIT) ++#define __aic_clear_tfs(parent) \ ++ ingenic_aic_set_reg(parent, AICSR, 0, AICSR_TFS_MASK, AICSR_TFS_BIT) ++#define __aic_test_tfs(parent) \ ++ ingenic_aic_get_reg(parent, AICSR, AICSR_TFS_MASK, AICSR_TFS_BIT) ++#define __aic_get_irq_flag(parent) \ ++ ingenic_aic_get_reg(parent, AICSR, AICSR_ALL_INT_MASK, AICSR_TFS_BIT) ++#define __aic_clear_all_irq_flag(parent) \ ++ ingenic_aic_set_reg(parent, AICSR, AICSR_ALL_INT_MASK, AICSR_ALL_INT_MASK, AICSR_TFS_BIT) ++/* aic dr*/ ++#define __aic_write_txfifo(parent, n) \ ++ ingenic_aic_write_reg(parent, AICDR, (n)) ++#define __aic_read_rxfifo(parent) \ ++ ingenic_aic_read_reg(parent, AICDR) ++/* For SPFIFO */ ++#define __spdif_test_underrun(parent) \ ++ ingenic_aic_get_reg(parent, SPSTATE, SPSTATE_F_FFUR_MASK, SPSTATE_F_FFUR_BIT) ++#define __spdif_clear_underrun(parent) \ ++ ingenic_aic_set_reg(parent, SPSTATE, 0, SPSTATE_F_FFUR_MASK, SPSTATE_F_FFUR_BIT) ++#define __spdif_is_enable_transmit_dma(parent) \ ++ ingenic_aic_get_reg(parent, SPCTRL, SPCTRL_DMA_EN_MASK, SPCTRL_DMA_EN_BIT) ++#define __spdif_enable_transmit_dma(parent) \ ++ ingenic_aic_set_reg(parent, SPCTRL, 1, SPCTRL_DMA_EN_MASK, SPCTRL_DMA_EN_BIT) ++#define __spdif_disable_transmit_dma(parent) \ ++ ingenic_aic_set_reg(parent, SPCTRL, 0, SPCTRL_DMA_EN_MASK, SPCTRL_DMA_EN_BIT) ++#define __spdif_reset(parent) \ ++ ingenic_aic_set_reg(parent, SPCTRL, 1, SPCTRL_SFT_RST_MASK, SPCTRL_SFT_RST_BIT) ++#define __spdif_get_reset(parent) \ ++ ingenic_aic_get_reg(parent, SPCTRL,SPCTRL_SFT_RST_MASK, SPCTRL_SFT_RST_BIT) ++#define __spdif_enable(parent) \ ++ ingenic_aic_set_reg(parent, SPENA, 1, SPENA_SPEN_MASK, SPENA_SPEN_BIT) ++#define __spdif_disable(parent) \ ++ ingenic_aic_set_reg(parent, SPENA, 0, SPENA_SPEN_MASK, SPENA_SPEN_BIT) ++#define __spdif_set_dtype(parent, n) \ ++ ingenic_aic_set_reg(parent, SPCTRL, n, SPCTRL_D_TYPE_MASK, SPCTRL_D_TYPE_BIT) ++#define __spdif_set_trigger(parent, n) \ ++ ingenic_aic_set_reg(parent, SPCFG1, n, SPCFG1_TRIG_MASK, SPCFG1_TRIG_BIT) ++#define __spdif_set_ch1num(parent, n) \ ++ ingenic_aic_set_reg(parent, SPCFG1, n, SPCFG1_CH1_NUM_MASK, SPCFG1_CH1_NUM_BIT) ++#define __spdif_set_ch2num(parent, n) \ ++ ingenic_aic_set_reg(parent, SPCFG1, n, SPCFG1_CH2_NUM_MASK, SPCFG1_CH2_NUM_BIT) ++#define __spdif_set_srcnum(parent, n) \ ++ ingenic_aic_set_reg(parent, SPCFG1, n, SPCFG1_SRC_NUM_MASK, SPCFG1_SRC_NUM_BIT) ++#define __interface_select_spdif(parent) \ ++ ingenic_aic_set_reg(parent, SPCTRL, 1, SPCTRL_SPDIF_I2S_MASK, SPCTRL_SPDIF_I2S_BIT) ++#define __spdif_play_lastsample(parent) \ ++ ingenic_aic_set_reg(parent, SPCFG1, 1, SPCFG1_ZRO_VLD_MASK, SPCFG1_ZRO_VLD_BIT) ++#define __spdif_init_set_low(parent) \ ++ ingenic_aic_set_reg(parent, SPCFG1, 0, SPCFG1_INIT_LVL_MASK, SPCFG1_INIT_LVL_BIT) ++#define __spdif_choose_consumer(parent) \ ++ ingenic_aic_set_reg(parent, SPCFG2, 0, SPCFG2_CON_PRO_MASK, SPCFG2_CON_PRO_BIT) ++#define __spdif_clear_audion(parent) \ ++ ingenic_aic_set_reg(parent, SPCFG2, 0, SPCFG2_AUDIO_N_MASK, SPCFG2_AUDIO_N_BIT) ++#define __spdif_set_copyn(parent) \ ++ ingenic_aic_set_reg(parent, SPCFG2, 1, SPCFG2_COPY_N_MASK, SPCFG2_COPY_N_BIT) ++#define __spdif_clear_pre(parent) \ ++ ingenic_aic_set_reg(parent, SPCFG2, 0, SPCFG2_PRE_MASK, SPCFG2_PRE_BIT) ++#define __spdif_choose_chmd(parent) \ ++ ingenic_aic_set_reg(parent, SPCFG2, 0, SPCFG2_CH_MD_MASK, SPCFG2_CH_MD_BIT) ++#define __spdif_set_category_code_normal(parent) \ ++ ingenic_aic_set_reg(parent, SPCFG2, 0, SPCFG2_CAT_CODE_MASK, SPCFG2_CAT_CODE_BIT) ++#define __spdif_set_clkacu(parent, n) \ ++ ingenic_aic_set_reg(parent, SPCFG2, n, SPCFG2_CLK_ACU_MASK, SPCFG2_CLK_ACU_BIT) ++#define __spdif_set_sample_size(parent, n) \ ++ ingenic_aic_set_reg(parent, SPCFG2, n, SPCFG2_SAMPL_WL_MASK, SPCFG2_SAMPL_WL_BIT) ++#define __spdif_set_max_wl(parent, n) \ ++ ingenic_aic_set_reg(parent, SPCFG2, n, SPCFG2_MAX_WL_MASK, SPCFG2_MAX_WL_BIT) ++#define __spdif_set_ori_sample_freq(parent, org_frq_tmp) \ ++ ingenic_aic_set_reg(parent, SPCFG2, org_frq_tmp, SPCFG2_ORG_FRQ_MASK, SPCFG2_ORG_FRQ_BIT) ++#define __spdif_set_sample_freq(parent, fs_tmp) \ ++ ingenic_aic_set_reg(parent, SPCFG2, fs_tmp, SPCFG2_FS_MASK, SPCFG2_FS_BIT) ++#define __spdif_set_valid(parent) \ ++ ingenic_aic_set_reg(parent, SPCTRL, 0, SPCTRL_INVALID_MASK, SPCTRL_INVALID_BIT) ++#define __spdif_mask_trig(parent) \ ++ ingenic_aic_set_reg(parent, SPCTRL, 1, SPCTRL_M_TRIG_MASK, SPCTRL_M_TRIG_BIT) ++#define __spdif_disable_underrun_intr(parent) \ ++ ingenic_aic_set_reg(parent, SPCTRL, 1, SPCTRL_M_FFUR_MASK, SPCTRL_M_FFUR_BIT) ++#define __spdif_set_signn(parent) \ ++ ingenic_aic_set_reg(parent, SPCTRL, 1, SPCTRL_SIGN_N_MASK, SPCTRL_SIGN_N_BIT) ++#define __spdif_clear_signn(parent) \ ++ ingenic_aic_set_reg(parent, SPCTRL, 0, SPCTRL_SIGN_N_MASK, SPCTRL_SIGN_N_BIT) ++ ++/* For I2S */ ++/*aic fr*/ ++#define __i2s_is_enable(parent) \ ++ ingenic_aic_get_reg(parent, AICFR, AICFR_ENB_MASK, AICFR_ENB_BIT) ++#define __aic_enable(parent) \ ++ ingenic_aic_set_reg(parent, AICFR, 1, AICFR_ENB_MASK, AICFR_ENB_BIT) ++ ++#define __aic_disable(parent) \ ++ ingenic_aic_set_reg(parent, AICFR, 0, AICFR_ENB_MASK, AICFR_ENB_BIT) ++ ++#define __i2s_external_codec(parent) \ ++ ingenic_aic_set_reg(parent, AICFR, 0, AICFR_ICDC_MASK, AICFR_ICDC_BIT) ++ ++#define __i2s_bclk_output(parent) \ ++ ingenic_aic_set_reg(parent, AICFR, 1, AICFR_BCKD_MASK, AICFR_BCKD_BIT) ++ ++#define __i2s_bclk_input(parent) \ ++ ingenic_aic_set_reg(parent, AICFR, 0, AICFR_BCKD_MASK, AICFR_BCKD_BIT) ++ ++#define __i2s_sync_output(parent) \ ++ ingenic_aic_set_reg(parent, AICFR, 1, AICFR_SYNCD_MASK, AICFR_SYNCD_BIT) ++ ++#define __i2s_sync_input(parent) \ ++ ingenic_aic_set_reg(parent, AICFR, 0, AICFR_SYNCD_MASK, AICFR_SYNCD_BIT) ++ ++#define __aic_select_i2s(parent) \ ++ ingenic_aic_set_reg(parent, AICFR, 1, AICFR_AUSEL_MASK, AICFR_AUSEL_BIT) ++ ++#define __aic_select_internal_codec(parent) \ ++ ingenic_aic_set_reg(parent, AICFR, 1, AICFR_ICDC_MASK, AICFR_ICDC_BIT) ++ ++#define __aic_select_external_codec(parent) \ ++ ingenic_aic_set_reg(parent, AICFR, 0, AICFR_ICDC_MASK, AICFR_ICDC_BIT) ++ ++#define __i2s_play_zero(parent) \ ++ ingenic_aic_set_reg(parent, AICFR, 0, AICFR_LSMP_MASK, AICFR_LSMP_BIT) ++ ++#define __i2s_play_lastsample(parent) \ ++ ingenic_aic_set_reg(parent, AICFR, 1, AICFR_LSMP_MASK, AICFR_LSMP_BIT) ++ ++#define __i2s_codec_slave(parent) \ ++ ingenic_aic_set_reg(parent, AICFR, 1, AICFR_CDC_SLV_MASK, AICFR_CDC_SLV_BIT) ++ ++#define __i2s_codec_master(parent) \ ++ ingenic_aic_set_reg(parent, AICFR, 0, AICFR_CDC_SLV_MASK, AICFR_CDC_SLV_BIT) ++ ++#define __i2s_select_sysclk_output(parent) \ ++ ingenic_aic_set_reg(parent, AICFR, 0, AICFR_SYSCLKD_MASK, AICFR_SYSCLKD_BIT) ++ ++#define __i2s_select_sysclk_input(parent) \ ++ ingenic_aic_set_reg(parent, AICFR, 1, AICFR_SYSCLKD_MASK, AICFR_SYSCLKD_BIT) ++ ++#define __i2s_set_transmit_trigger(parent, n) \ ++ ingenic_aic_set_reg(parent, AICFR, n, AICFR_TFTH_MASK, AICFR_TFTH_BIT) ++ ++#define __i2s_set_receive_trigger(parent, n) \ ++ ingenic_aic_set_reg(parent, AICFR, n, AICFR_RFTH_MASK, AICFR_RFTH_BIT) ++/*aiccr*/ ++#define I2S_SS2REG(n) (((n) > 18 ? (n)/6 : (n)/9)) /* n = 8, 16, 18, 20, 24 */ ++#define __i2s_aic_packet16(parent) \ ++ ingenic_aic_set_reg(parent, AICCR, 1, AICCR_PACK16_MASK, AICCR_PACK16_BIT) ++#define __i2s_aic_unpacket16(parent) \ ++ ingenic_aic_set_reg(parent, AICCR, 0, AICCR_PACK16_MASK, AICCR_PACK16_BIT) ++#define __i2s_channel(parent, n) \ ++ ingenic_aic_set_reg(parent, AICCR, ((n) - 1), AICCR_CHANNEL_MASK, AICCR_CHANNEL_BIT) ++#define __i2s_set_oss(parent, n) \ ++ ingenic_aic_set_reg(parent, AICCR, I2S_SS2REG(n) , AICCR_OSS_MASK, AICCR_OSS_BIT) ++#define __i2s_set_iss(parent, n) \ ++ ingenic_aic_set_reg(parent, AICCR, I2S_SS2REG(n) , AICCR_ISS_MASK, AICCR_ISS_BIT) ++#define __i2s_transmit_dma_is_enable(parent) \ ++ ingenic_aic_get_reg(parent, AICCR, AICCR_TDMS_MASK,AICCR_TDMS_BIT) ++#define __i2s_disable_transmit_dma(parent) \ ++ ingenic_aic_set_reg(parent, AICCR, 0, AICCR_TDMS_MASK, AICCR_TDMS_BIT) ++#define __i2s_enable_transmit_dma(parent) \ ++ ingenic_aic_set_reg(parent, AICCR, 1, AICCR_TDMS_MASK, AICCR_TDMS_BIT) ++#define __i2s_receive_dma_is_enable(parent) \ ++ ingenic_aic_get_reg(parent, AICCR, AICCR_RDMS_MASK,AICCR_RDMS_BIT) ++#define __i2s_disable_receive_dma(parent) \ ++ ingenic_aic_set_reg(parent, AICCR, 0, AICCR_RDMS_MASK, AICCR_RDMS_BIT) ++#define __i2s_enable_receive_dma(parent) \ ++ ingenic_aic_set_reg(parent, AICCR, 1, AICCR_RDMS_MASK, AICCR_RDMS_BIT) ++#define __i2s_m2s_enable(parent) \ ++ ingenic_aic_set_reg(parent, AICCR, 1, AICCR_M2S_MASK, AICCR_M2S_BIT) ++#define __i2s_m2s_disable(parent) \ ++ ingenic_aic_set_reg(parent, AICCR, 0, AICCR_M2S_MASK, AICCR_M2S_BIT) ++#define __i2s_endsw_enable(parent) \ ++ ingenic_aic_set_reg(parent, AICCR, 1, AICCR_ENDSW_MASK, AICCR_ENDSW_BIT) ++#define __i2s_endsw_disable(parent) \ ++ ingenic_aic_set_reg(parent, AICCR, 0, AICCR_ENDSW_MASK, AICCR_ENDSW_BIT) ++#define __i2s_asvtsu_enable(parent) \ ++ ingenic_aic_set_reg(parent, AICCR, 1, AICCR_ASVTSU_MASK, AICCR_ASVTSU_BIT) ++#define __i2s_asvtsu_disable(parent) \ ++ ingenic_aic_set_reg(parent, AICCR, 0, AICCR_ASVTSU_MASK, AICCR_ASVTSU_BIT) ++#define __i2s_enable_replay(parent) \ ++ ingenic_aic_set_reg(parent, AICCR, 1, AICCR_ERPL_MASK, AICCR_ERPL_BIT) ++#define __i2s_enable_record(parent) \ ++ ingenic_aic_set_reg(parent, AICCR, 1, AICCR_EREC_MASK, AICCR_EREC_BIT) ++#define __i2s_enable_loopback(parent) \ ++ ingenic_aic_set_reg(parent, AICCR, 1, AICCR_ENLBF_MASK, AICCR_ENLBF_BIT) ++#define __i2s_disable_replay(parent) \ ++ ingenic_aic_set_reg(parent, AICCR, 0, AICCR_ERPL_MASK, AICCR_ERPL_BIT) ++#define __i2s_disable_record(parent) \ ++ ingenic_aic_set_reg(parent, AICCR, 0, AICCR_EREC_MASK, AICCR_EREC_BIT) ++#define __i2s_disable_loopback(parent) \ ++ ingenic_aic_set_reg(parent, AICCR, 0, AICCR_ENLBF_MASK, AICCR_ENLBF_BIT) ++/*i2scr*/ ++#define __i2s_select_i2s_fmt(parent) \ ++ ingenic_aic_set_reg(parent, I2SCR, 0, I2SCR_AMSL_MASK, I2SCR_AMSL_BIT) ++#define __i2s_select_msb_fmt(parent) \ ++ ingenic_aic_set_reg(parent, I2SCR, 1, I2SCR_AMSL_MASK, I2SCR_AMSL_BIT) ++#define __i2s_enable_sysclk_output(parent) \ ++ ingenic_aic_set_reg(parent, I2SCR, 1, I2SCR_ESCLK_MASK, I2SCR_ESCLK_BIT) ++#define __i2s_disable_sysclk_output(parent) \ ++ ingenic_aic_set_reg(parent, I2SCR, 0, I2SCR_ESCLK_MASK, I2SCR_ESCLK_BIT) ++#define __i2s_send_rfirst(parent) \ ++ ingenic_aic_set_reg(parent, I2SCR, 1, I2SCR_RFIRST_MASK, I2SCR_RFIRST_BIT) ++#define __i2s_stop_bitclk(parent) \ ++ ingenic_aic_set_reg(parent, I2SCR, 1, I2SCR_STPBK_MASK, I2SCR_STPBK_BIT) ++#define __i2s_start_bitclk(parent) \ ++ ingenic_aic_set_reg(parent, I2SCR, 0, I2SCR_STPBK_MASK, I2SCR_STPBK_BIT) ++#define __i2s_select_packed_lrswap(parent) \ ++ ingenic_aic_set_reg(parent, I2SCR, 1, I2SCR_SWLH_MASK, I2SCR_SWLH_BIT) ++#define __i2s_select_packed_lrnorm(parent) \ ++ ingenic_aic_set_reg(parent, I2SCR, 0, I2SCR_SWLH_MASK, I2SCR_SWLH_BIT) ++#define __i2s_send_rfirst(parent) \ ++ ingenic_aic_set_reg(parent, I2SCR, 1, I2SCR_RFIRST_MASK, I2SCR_RFIRST_BIT) ++#define __i2s_send_lfirst(parent) \ ++ ingenic_aic_set_reg(parent, I2SCR, 0, I2SCR_RFIRST_MASK, I2SCR_RFIRST_BIT) ++/*i2ssr*/ ++#define __i2s_transmiter_is_busy(parent) \ ++ (!!(ingenic_aic_read_reg(parent, I2SSR) & I2SSR_TBSY_MASK)) ++#define __i2s_receiver_is_busy(parent) \ ++ (!!(ingenic_aic_read_reg(parent, I2SSR) & I2SSR_TBSY_MASK)) ++ ++/*i2s_div*/ ++#define __i2s_set_idv(parent, div) \ ++ ingenic_aic_set_reg(parent, I2SDIV, div, I2SDIV_IDV_MASK, I2SDIV_IDV_BIT) ++#define __i2s_set_dv(parent, div) \ ++ ingenic_aic_set_reg(parent, I2SDIV, div, I2SDIV_DV_MASK, I2SDIV_DV_BIT) ++#endif /*__ASOC_AIC_H__*/ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_asoc-dma.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_asoc-dma.c.patch new file mode 100644 index 00000000..5618ed61 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_asoc-dma.c.patch @@ -0,0 +1,593 @@ +diff -drupN a/sound/soc/ingenic/as-v1/asoc-dma.c b/sound/soc/ingenic/as-v1/asoc-dma.c +--- a/sound/soc/ingenic/as-v1/asoc-dma.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/as-v1/asoc-dma.c 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,589 @@ ++/* ++ * sound/soc/ingenic/asoc-dma.c ++ * ALSA Soc Audio Layer -- ingenic audio dma platform driver ++ * ++ * Copyright 2014 Ingenic Semiconductor Co.,Ltd ++ * cli ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "asoc-dma.h" ++ ++static int asoc_dma_debug = 0; ++module_param(asoc_dma_debug, int, 0644); ++ ++#define DMA_DEBUG_MSG(msg...) \ ++ do { \ ++ if (asoc_dma_debug) \ ++ printk(KERN_DEBUG"ADMA: " msg); \ ++ } while(0) ++#define DMA_SUBSTREAM_MSG(substream, msg...) \ ++ do { \ ++ if (asoc_dma_debug) { \ ++ printk(KERN_DEBUG"ADMA[%s][%s]:", \ ++ substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? \ ++ "replay" : "record", \ ++ substream->pcm->id); \ ++ printk(KERN_DEBUG msg); \ ++ } \ ++ } while(0) ++ ++#define INGENIC_DMA_BUFFERSIZE_PREALLOC (32 * 1024) ++#define INGENIC_DMA_BUFFERSIZE_MAX (128 * 1024) ++struct ingenic_dma_pcm { ++ struct dma_chan *chan[SNDRV_PCM_STREAM_LAST + 1]; ++ struct snd_soc_platform platform; ++ const struct snd_pcm_hardware *hardware; ++ unsigned int prealloc_buffersize; ++ int no_residue; ++}; ++#define soc_platform_to_ingenicpcm(x) container_of(x, struct ingenic_dma_pcm, platform) ++ ++static int ingenic_pcm_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); ++ struct ingenic_pcm_runtime_data *prtd = substream_to_prtd(substream); ++ struct snd_dmaengine_dai_dma_data *dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); ++ struct dma_slave_config slave_config; ++ int ret; ++ ++ DMA_SUBSTREAM_MSG(substream, "%s enter\n", __func__); ++ ++ memset(&slave_config, 0, sizeof(slave_config)); ++ ++ ret = snd_hwparams_to_dma_slave_config(substream, params, &slave_config); ++ if (ret) ++ return ret; ++ snd_dmaengine_pcm_set_config_from_dai_data(substream, dma_data, &slave_config); ++ ++ ret = dmaengine_slave_config(prtd->dma_chan, &slave_config); ++ if (ret) ++ return ret; ++ ++ while (atomic_read(&prtd->wait_stopdma)) ++ msleep(10); ++ ++ prtd->stopdma_delayed_jiffies = 2 * (params_period_size(params) * HZ /params_rate(params)); ++ return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); ++} ++ ++static int ingenic_pcm_hw_free(struct snd_pcm_substream *substream) ++{ ++ struct ingenic_pcm_runtime_data *prtd = substream_to_prtd(substream); ++ ++ DMA_SUBSTREAM_MSG(substream, "%s enter\n", __func__); ++ ++ while (atomic_read(&prtd->wait_stopdma)) ++ msleep(10); ++ ++ return snd_pcm_lib_free_pages(substream); ++} ++ ++static int ingenic_pcm_prepare(struct snd_pcm_substream *substream) ++{ ++ struct ingenic_pcm_runtime_data *prtd = substream_to_prtd(substream); ++ ++ DMA_SUBSTREAM_MSG(substream, "%s enter\n", __func__); ++ ++ while (atomic_read(&prtd->wait_stopdma)) ++ msleep(10); ++ ++ return 0; ++} ++ ++static void ingenic_pcm_dma_complete(void *data) ++{ ++ struct snd_pcm_substream *substream = data; ++ struct ingenic_pcm_runtime_data *prtd = substream_to_prtd(substream); ++ ++ DMA_SUBSTREAM_MSG(substream,"%s enter period interrupt %d\n", __func__, ++ atomic_read(&prtd->wait_stopdma)); ++ ++ if (!atomic_dec_if_positive(&prtd->wait_stopdma)) { ++ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); ++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai; ++ dmaengine_terminate_all(prtd->dma_chan); ++ if (cpu_dai->driver->ops->trigger) ++ cpu_dai->driver->ops->trigger(substream, SNDRV_PCM_TRIGGER_STOP, cpu_dai); ++ cancel_delayed_work(&prtd->stopdma_delayed_work); ++ return; ++ } ++ ++ if (prtd->file) { ++ prtd->copy_start = substream->runtime->dma_area + prtd->pos; ++ prtd->copy_length = snd_pcm_lib_period_bytes(substream); ++ if (work_pending(&prtd->debug_work)) ++ printk(KERN_WARNING"debug file %s may loss data\n", prtd->file_name); ++ schedule_work(&prtd->debug_work); ++ } ++ ++ prtd->pos += snd_pcm_lib_period_bytes(substream); ++ if (prtd->pos >= snd_pcm_lib_buffer_bytes(substream)) ++ prtd->pos = 0; ++ snd_pcm_period_elapsed(substream); ++ return; ++} ++ ++static int ingenic_pcm_prepare_and_submit(struct snd_pcm_substream *substream) ++{ ++ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); ++ struct ingenic_pcm_runtime_data *prtd = substream_to_prtd(substream); ++ enum dma_transfer_direction direction; ++ struct dma_async_tx_descriptor *desc; ++ unsigned long flags = DMA_CTRL_ACK; ++ ++ direction = snd_pcm_substream_to_dma_direction(substream); ++ ++ if (!substream->runtime->no_period_wakeup) ++ flags |= DMA_PREP_INTERRUPT; ++ ++ prtd->pos = 0; ++ desc = dmaengine_prep_dma_cyclic(prtd->dma_chan, ++ substream->runtime->dma_addr, ++ snd_pcm_lib_buffer_bytes(substream), ++ snd_pcm_lib_period_bytes(substream), direction, flags); ++ if (!desc) { ++ dev_err(rtd->dev, "cannot prepare slave dma\n"); ++ return -ENOMEM; ++ } ++ ++ desc->callback = ingenic_pcm_dma_complete; ++ desc->callback_param = substream; ++ prtd->cookie = dmaengine_submit(desc); ++ return 0; ++} ++ ++static int ingenic_pcm_trigger(struct snd_pcm_substream *substream, int cmd) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ struct ingenic_pcm_runtime_data *prtd = substream_to_prtd(substream); ++ int ret; ++ ++ DMA_SUBSTREAM_MSG(substream,"%s enter cmd %d\n", __func__, cmd); ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ if (atomic_read(&prtd->wait_stopdma)) ++ return -EPIPE; ++ ++ ret = ingenic_pcm_prepare_and_submit(substream); ++ if (ret) ++ return ret; ++ dma_async_issue_pending(prtd->dma_chan); ++ break; ++ case SNDRV_PCM_TRIGGER_RESUME: ++ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: ++ dmaengine_resume(prtd->dma_chan); ++ break; ++ case SNDRV_PCM_TRIGGER_SUSPEND: ++ if (runtime->info & SNDRV_PCM_INFO_PAUSE) ++ dmaengine_pause(prtd->dma_chan); ++ else ++ dmaengine_terminate_all(prtd->dma_chan); ++ break; ++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ++ dmaengine_pause(prtd->dma_chan); ++ break; ++ case SNDRV_PCM_TRIGGER_STOP: ++ ret = dmaengine_terminate_all(prtd->dma_chan); ++ if (ret == -EBUSY) { ++ schedule_delayed_work(&prtd->stopdma_delayed_work, ++ prtd->stopdma_delayed_jiffies); ++ atomic_set(&prtd->wait_stopdma, 1); ++ } ++ break; ++ default: ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static snd_pcm_uframes_t ingenic_pcm_pointer_no_residue(struct snd_pcm_substream *substream) ++{ ++ struct ingenic_pcm_runtime_data *prtd = substream_to_prtd(substream); ++ ++ return bytes_to_frames(substream->runtime, prtd->pos); ++} ++ ++static snd_pcm_uframes_t ingenic_pcm_pointer_residue(struct snd_pcm_substream *substream) ++{ ++ struct ingenic_pcm_runtime_data *prtd = substream_to_prtd(substream); ++ struct dma_tx_state state; ++ enum dma_status status; ++ size_t buf_size; ++ ssize_t pos = 0; ++ ++ status = dmaengine_tx_status(prtd->dma_chan, prtd->cookie, &state); ++ ++ if (status == DMA_IN_PROGRESS || status == DMA_PAUSED) { ++ buf_size = snd_pcm_lib_buffer_bytes(substream); ++ if (state.residue > 0 && state.residue <= buf_size) ++ pos = buf_size - state.residue; ++ } ++ ++ DMA_SUBSTREAM_MSG(substream, "prtd->pos %x really pos %x\n", prtd->pos, pos); ++ return bytes_to_frames(substream->runtime, pos); ++} ++ ++static snd_pcm_uframes_t ingenic_pcm_pointer(struct snd_pcm_substream *substream) ++{ ++ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); ++ struct ingenic_dma_pcm *ingenic_pcm = soc_platform_to_ingenicpcm(rtd->platform); ++ ++ if (ingenic_pcm->no_residue) ++ return ingenic_pcm_pointer_no_residue(substream); ++ ++ return ingenic_pcm_pointer_residue(substream); ++} ++ ++static void debug_work(struct work_struct *debug_work) ++{ ++ struct ingenic_pcm_runtime_data *prtd = ++ container_of(debug_work, struct ingenic_pcm_runtime_data, debug_work); ++ if (!IS_ERR_OR_NULL(prtd->file)) { ++ prtd->old_fs = get_fs(); ++ set_fs(KERNEL_DS); ++ vfs_write(prtd->file, prtd->copy_start, ++ prtd->copy_length, ++ &prtd->file_offset); ++ prtd->file_offset = prtd->file->f_pos; ++ set_fs(prtd->old_fs); ++ } ++} ++ ++static void ingenic_pcm_open_debug_file(struct snd_pcm_substream *substream) ++{ ++ struct ingenic_pcm_runtime_data *prtd = substream_to_prtd(substream); ++#ifdef CONFIG_ANDROID ++ char *file_dir = "/data"; ++#else ++ char *file_dir = "/tmp"; ++#endif ++ prtd->file_name = kzalloc(40*sizeof(char), GFP_KERNEL); ++ if (prtd->file_name) { ++ sprintf(prtd->file_name, "%s/%sd%is%i.pcm", ++ file_dir, ++ substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? ++ "replay" : "record", ++ substream->pcm->device, ++ substream->number); ++ pr_info("open debug file %s \n", prtd->file_name); ++ prtd->file = filp_open(prtd->file_name, ++ O_RDWR | O_APPEND /*| O_CREAT*/, S_IRUSR | S_IWUSR); ++ if (IS_ERR(prtd->file)) { ++ kfree(prtd->file_name); ++ prtd->file_name = NULL; ++ prtd->file = NULL; ++ return; ++ } ++ pr_info("open debug %s success (Poor performance)\n", ++ prtd->file_name); ++ prtd->file_offset =prtd->file->f_pos; ++ INIT_WORK(&prtd->debug_work, debug_work); ++ } ++ return; ++} ++ ++static void ingenic_pcm_close_debug_file(struct snd_pcm_substream *substream) ++{ ++ struct ingenic_pcm_runtime_data *prtd = substream_to_prtd(substream); ++ ++ if (!prtd || !prtd->file) ++ return; ++ ++ flush_work(&prtd->debug_work); ++ filp_close(prtd->file, NULL); ++ kfree(prtd->file_name); ++ return; ++} ++ ++static void stopdma_delayed_work(struct work_struct *work) ++{ ++ struct ingenic_pcm_runtime_data *prtd = container_of(work, struct ingenic_pcm_runtime_data, ++ stopdma_delayed_work.work); ++ ++ DMA_SUBSTREAM_MSG(prtd->substream,"%s delayed work stop dma %d\n", __func__, atomic_read(&prtd->wait_stopdma)); ++ if (!atomic_dec_if_positive(&prtd->wait_stopdma)) { ++ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(prtd->substream); ++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai; ++ dmaengine_terminate_all(prtd->dma_chan); ++ if (cpu_dai->driver->ops->trigger) ++ cpu_dai->driver->ops->trigger(prtd->substream, SNDRV_PCM_TRIGGER_STOP, cpu_dai); ++ } ++ return; ++} ++ ++static int ingenic_pcm_open(struct snd_pcm_substream *substream) ++{ ++ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); ++ struct ingenic_dma_pcm *ingenic_pcm = soc_platform_to_ingenicpcm(rtd->platform); ++ struct dma_chan *chan = ingenic_pcm->chan[substream->stream]; ++ struct dma_slave_caps dma_caps; ++ struct snd_pcm_hardware hw; ++ struct snd_dmaengine_dai_dma_data *dma_data; ++ struct ingenic_pcm_runtime_data *prtd = NULL; ++ u32 addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | ++ BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | ++ BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); ++ int ret; ++ ++ DMA_DEBUG_MSG("%s enter\n", __func__); ++ if (ingenic_pcm->hardware) { ++ ret = snd_soc_set_runtime_hwparams(substream, ingenic_pcm->hardware); ++ if (ret) ++ return ret; ++ } else { ++ int i; ++ dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); ++ memset(&hw, 0, sizeof(hw)); ++ hw.buffer_bytes_max = INGENIC_DMA_BUFFERSIZE_MAX; ++ hw.period_bytes_max = (32 * 1024); ++ hw.period_bytes_min = 1024; ++ hw.periods_max = 64; /*INGENIC PDMA LIMITE*/ ++ hw.periods_min = 4; ++ hw.fifo_size = dma_data->fifo_size; ++ hw.info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | ++ SNDRV_PCM_INFO_INTERLEAVED; ++ ret = dma_get_slave_caps(chan, &dma_caps); ++ if (ret == 0) { ++ if (dma_caps.residue_granularity <= DMA_RESIDUE_GRANULARITY_SEGMENT) ++ hw.info |= SNDRV_PCM_INFO_BATCH; ++ if (dma_caps.residue_granularity == DMA_RESIDUE_GRANULARITY_DESCRIPTOR) ++ ingenic_pcm->no_residue = 1; ++ if (dma_caps.cmd_pause) ++ hw.info |= SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME; ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ addr_widths = dma_caps.dst_addr_widths; ++ else ++ addr_widths = dma_caps.src_addr_widths; ++ } ++ ++ for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) { ++ int bits = snd_pcm_format_physical_width(i); ++ switch (bits) { ++ case 8: ++ case 16: ++ case 24: ++ case 32: ++ case 64: ++ if (addr_widths & (1 << (bits / 8))) ++ hw.formats |= (1LL << i); ++ break; ++ default: ++ /* Unsupported types */ ++ break; ++ } ++ } ++ ++ ret = snd_soc_set_runtime_hwparams(substream, &hw); ++ if (ret) ++ return ret; ++ } ++ ++ ret = snd_pcm_hw_constraint_integer(substream->runtime, ++ SNDRV_PCM_HW_PARAM_PERIODS); ++ if (ret < 0) ++ return ret; ++ ++ prtd = kzalloc(sizeof(*prtd), GFP_KERNEL); ++ if (!prtd) ++ return -ENOMEM; ++ ++ prtd->dma_chan = chan; ++ prtd->substream = substream; ++ INIT_DELAYED_WORK(&prtd->stopdma_delayed_work, stopdma_delayed_work); ++ prtd->stopdma_delayed_jiffies = 0; ++ atomic_set(&prtd->wait_stopdma, 0); ++ substream->runtime->private_data = prtd; ++ ++ ingenic_pcm_open_debug_file(substream); ++ return 0; ++} ++ ++static int ingenic_pcm_close(struct snd_pcm_substream *substream) ++{ ++ struct ingenic_pcm_runtime_data *prtd = substream_to_prtd(substream); ++ ++ DMA_DEBUG_MSG("%s enter\n", __func__); ++ ++ BUG_ON(atomic_read(&prtd->wait_stopdma)); ++ flush_delayed_work(&prtd->stopdma_delayed_work); ++ ++ ingenic_pcm_close_debug_file(substream); ++ ++ substream->private_data = NULL; ++ ++ kfree(prtd); ++ return 0; ++} ++ ++struct snd_pcm_ops ingenic_pcm_ops = { ++ .open = ingenic_pcm_open, ++ .close = ingenic_pcm_close, ++ .ioctl = snd_pcm_lib_ioctl, ++ .hw_params = ingenic_pcm_hw_params, ++ .hw_free = ingenic_pcm_hw_free, ++ .prepare = ingenic_pcm_prepare, ++ .trigger = ingenic_pcm_trigger, ++ .pointer = ingenic_pcm_pointer, ++}; ++ ++static void ingenic_pcm_free(struct snd_pcm *pcm) ++{ ++ snd_pcm_lib_preallocate_free_for_all(pcm); ++} ++ ++static int ingenic_pcm_new(struct snd_soc_pcm_runtime *rtd) ++{ ++ struct ingenic_dma_pcm *ingenic_pcm = soc_platform_to_ingenicpcm(rtd->platform); ++ struct snd_pcm_substream *substream; ++ int ret = -EINVAL; ++ int i; ++ ++ DMA_DEBUG_MSG("%s enter\n", __func__); ++ for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) { ++ substream = rtd->pcm->streams[i].substream; ++ if (!substream) ++ continue; ++ ++ if (!ingenic_pcm->chan[i]) { ++ dev_err(rtd->platform->dev, ++ "Missing dma channel for stream: %d\n", i); ++ ret = -EINVAL; ++ goto err_free; ++ } ++ ++ ret = snd_pcm_lib_preallocate_pages(substream, ++ SNDRV_DMA_TYPE_DEV_IRAM, ++ ingenic_pcm->chan[i]->device->dev, ++ ingenic_pcm->prealloc_buffersize, ++ ingenic_pcm->hardware ? ++ ingenic_pcm->hardware->buffer_bytes_max : ++ INGENIC_DMA_BUFFERSIZE_MAX); ++ if (ret) ++ goto err_free; ++ } ++ return 0; ++ ++err_free: ++ dev_err(rtd->dev, "Failed to alloc dma buffer %d\n", ret); ++ ingenic_pcm_free(rtd->pcm); ++ return ret; ++} ++ ++static struct snd_soc_platform_driver ingenic_pcm_platform_driver = { ++ .ops = &ingenic_pcm_ops, ++ .pcm_new = ingenic_pcm_new, ++ .pcm_free = ingenic_pcm_free, ++}; ++ ++static void ingenic_pcm_release_dma_channel(struct ingenic_dma_pcm *ingenic_pcm) ++{ ++ int i; ++ ++ for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) { ++ if (!ingenic_pcm->chan[i]) ++ continue; ++ dma_release_channel(ingenic_pcm->chan[i]); ++ } ++ ++ return; ++} ++ ++int ingenic_dma_pcm_register(struct device *dev, const struct snd_dmaengine_pcm_config *config) ++{ ++ struct ingenic_dma_pcm *ingenic_pcm; ++ struct dma_chan *chan; ++ const char *name; ++ int ret, i; ++ const char * const ingenic_pcm_dma_channel_names[] = { ++ [SNDRV_PCM_STREAM_PLAYBACK] = "tx", ++ [SNDRV_PCM_STREAM_CAPTURE] = "rx", ++ }; ++ ++ ingenic_pcm = devm_kzalloc(dev, sizeof(struct ingenic_dma_pcm), GFP_KERNEL); ++ if (!ingenic_pcm) ++ return -ENOMEM; ++ ++ if (config && config->pcm_hardware) ++ ingenic_pcm->hardware = config->pcm_hardware; ++ ++ if (config && config->prealloc_buffer_size) ++ ingenic_pcm->prealloc_buffersize = config->prealloc_buffer_size; ++ else ++ ingenic_pcm->prealloc_buffersize = INGENIC_DMA_BUFFERSIZE_PREALLOC; ++ ++ for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) { ++ if (config && config->chan_names[i]) ++ name = config->chan_names[i]; ++ else ++ name = ingenic_pcm_dma_channel_names[i]; ++ chan = dma_request_slave_channel_reason(dev, name); ++ if (IS_ERR(chan)) { ++ if (PTR_ERR(chan) == -EPROBE_DEFER) ++ return -EPROBE_DEFER; ++ ingenic_pcm->chan[i] = NULL; ++ dev_info(dev, "%s channel request failed\n", name); ++ } else { ++ ingenic_pcm->chan[i] = chan; ++ } ++ } ++ ++ ret = snd_soc_add_platform(dev, &ingenic_pcm->platform, &ingenic_pcm_platform_driver); ++ if (ret) { ++ ingenic_pcm_release_dma_channel(ingenic_pcm); ++ dev_err(dev, "Failed to register platfrom\n"); ++ return ret; ++ } ++ ++ dev_info(dev, "Audio dma platfrom probe success\n"); ++ return 0; ++} ++EXPORT_SYMBOL_GPL(ingenic_dma_pcm_register); ++ ++void ingenic_dma_pcm_unregister(struct device *dev) ++{ ++ struct snd_soc_platform *platform; ++ struct ingenic_dma_pcm *ingenic_pcm; ++ ++ platform = snd_soc_lookup_platform(dev); ++ if (!platform) ++ return; ++ ++ ingenic_pcm = soc_platform_to_ingenicpcm(platform); ++ ++ snd_soc_remove_platform(platform); ++ ++ ingenic_pcm_release_dma_channel(ingenic_pcm); ++ return; ++} ++EXPORT_SYMBOL_GPL(ingenic_dma_pcm_unregister); ++ ++MODULE_DESCRIPTION("INGENIC ASOC Platform driver"); ++MODULE_AUTHOR("cli"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:ingenic-asoc-dma"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_asoc-dma.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_asoc-dma.h.patch new file mode 100644 index 00000000..2a39742d --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_asoc-dma.h.patch @@ -0,0 +1,35 @@ +diff -drupN a/sound/soc/ingenic/as-v1/asoc-dma.h b/sound/soc/ingenic/as-v1/asoc-dma.h +--- a/sound/soc/ingenic/as-v1/asoc-dma.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/as-v1/asoc-dma.h 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,31 @@ ++#ifndef __ASOC_DMA_H__ ++#define __ASOC_DMA_H__ ++ ++struct ingenic_pcm_runtime_data { ++ struct snd_pcm_substream *substream; ++ struct dma_chan *dma_chan; ++ dma_cookie_t cookie; ++ unsigned int pos; ++ ++ /* some pdma can not be force stop, when a descriptor is transfering */ ++ struct delayed_work stopdma_delayed_work; ++ unsigned long stopdma_delayed_jiffies; ++ atomic_t wait_stopdma; ++ ++ /* debug interface just use in debug*/ ++ void *copy_start; ++ unsigned int copy_length; ++ struct file *file; ++ loff_t file_offset; ++ mm_segment_t old_fs; ++ char* file_name; ++ struct work_struct debug_work; ++}; ++ ++static inline struct ingenic_pcm_runtime_data *substream_to_prtd( ++ const struct snd_pcm_substream *substream) ++{ ++ return substream->runtime->private_data; ++} ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_asoc-dmic.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_asoc-dmic.c.patch new file mode 100644 index 00000000..14b951b4 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_asoc-dmic.c.patch @@ -0,0 +1,528 @@ +diff -drupN a/sound/soc/ingenic/as-v1/asoc-dmic.c b/sound/soc/ingenic/as-v1/asoc-dmic.c +--- a/sound/soc/ingenic/as-v1/asoc-dmic.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/as-v1/asoc-dmic.c 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,524 @@ ++/* ++ * sound/soc/ingenic/asoc-dmic.c ++ * ALSA Soc Audio Layer -- ingenic dmic (part of aic controller) driver ++ * ++ * Copyright 2014 Ingenic Semiconductor Co.,Ltd ++ * syzhang ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "asoc-dmic.h" ++#include "asoc-aic.h" ++ ++static int ingenic_dmic_debug = 0; ++module_param(ingenic_dmic_debug, int, 0644); ++#define DMIC_DEBUG_MSG(msg...) \ ++ do { \ ++ if (ingenic_dmic_debug) \ ++ printk(KERN_DEBUG"dmic: " msg); \ ++ } while(0) ++ ++#define DMIC_FIFO_DEPTH 64 ++#define INGENIC_DMIC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE) ++#define INGENIC_DMIC_RATE (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000) ++ ++static void dump_registers(struct device *dev) ++{ ++ struct ingenic_dmic *ingenic_dmic = dev_get_drvdata(dev); ++ pr_info("DMICCR0 %p : 0x%08x\n", (ingenic_dmic->vaddr_base+DMICCR0),dmic_read_reg(dev, DMICCR0)); ++ pr_info("DMICGCR %p : 0x%08x\n", (ingenic_dmic->vaddr_base+DMICGCR),dmic_read_reg(dev, DMICGCR)); ++ pr_info("DMICIMR %p : 0x%08x\n", (ingenic_dmic->vaddr_base+DMICIMR),dmic_read_reg(dev, DMICIMR)); ++ pr_info("DMICINTCR %p : 0x%08x\n", (ingenic_dmic->vaddr_base+DMICINTCR),dmic_read_reg(dev, DMICINTCR)); ++ pr_info("DMICTRICR %p : 0x%08x\n", (ingenic_dmic->vaddr_base+DMICTRICR),dmic_read_reg(dev, DMICTRICR)); ++ pr_info("DMICTHRH %p : 0x%08x\n", (ingenic_dmic->vaddr_base+DMICTHRH),dmic_read_reg(dev, DMICTHRH)); ++ pr_info("DMICTHRL %p : 0x%08x\n", (ingenic_dmic->vaddr_base+DMICTHRL),dmic_read_reg(dev, DMICTHRL)); ++ pr_info("DMICTRIMMAX %p : 0x%08x\n", (ingenic_dmic->vaddr_base+DMICTRIMMAX),dmic_read_reg(dev, DMICTRIMMAX)); ++ pr_info("DMICTRINMAX %p : 0x%08x\n", (ingenic_dmic->vaddr_base+DMICTRINMAX),dmic_read_reg(dev, DMICTRINMAX)); ++ pr_info("DMICDR %p : 0x%08x\n", (ingenic_dmic->vaddr_base+DMICDR),dmic_read_reg(dev, DMICDR)); ++ pr_info("DMICFTHR %p : 0x%08x\n", (ingenic_dmic->vaddr_base+DMICFTHR),dmic_read_reg(dev, DMICFTHR)); ++ pr_info("DMICFSR %p : 0x%08x\n", (ingenic_dmic->vaddr_base+DMICFSR),dmic_read_reg(dev, DMICFSR)); ++ pr_info("DMICCGDIS %p : 0x%08x\n", (ingenic_dmic->vaddr_base+DMICCGDIS),dmic_read_reg(dev, DMICCGDIS)); ++ return; ++} ++ ++static int ingenic_dmic_contoller_init(struct snd_soc_dai *dai) ++{ ++ struct device *dev = dai->dev; ++ DMIC_DEBUG_MSG("enter %s\n", __func__); ++ ++ dmic_write_reg(dev, DMICCR0, 0xC8); ++ dmic_write_reg(dev, DMICTRICR, 0x00030000); ++ /*gain: 0, ..., e*/ ++ __dmic_reset(dev); ++ while(__dmic_get_reset(dev)); ++ __dmic_set_sr_8k(dev); ++ __dmic_enable_hpf1(dev); ++ __dmic_set_gcr(dev,8); ++ __dmic_mask_all_int(dev); ++ __dmic_enable_pack(dev); ++ __dmic_disable_sw_lr(dev); ++ __dmic_enable_lp(dev); ++ __dmic_set_request(dev,48); ++ __dmic_set_thr_high(dev,32); ++ __dmic_set_thr_low(dev,16); ++ ++ return 0; ++} ++ ++static int ingenic_dmic_startup(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct ingenic_dmic *ingenic_dmic = dev_get_drvdata(dai->dev); ++ ++ DMIC_DEBUG_MSG("enter %s, substream capture\n",__func__); ++ ++ if (!ingenic_dmic->dmic_mode) { ++ __dmic_enable(ingenic_dmic->dev); ++ } ++ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { ++ ingenic_dmic->dmic_mode |= DMIC_READ; ++ } else { ++ dev_err(dai->dev, "dmic is a capture device\n"); ++ return -EINVAL; ++ } ++ ++ clk_prepare_enable(ingenic_dmic->clk_gate_dmic); ++ regulator_enable(ingenic_dmic->vcc_dmic); ++ ++ ++ ingenic_dmic->en = 1; ++ printk("start set dmic register....\n"); ++ return 0; ++} ++ ++static int dmic_set_rate(struct device *dev, int rate){ ++ DMIC_DEBUG_MSG("enter %s, rate = %d\n",__func__, rate); ++ switch(rate){ ++ case 8000: ++ __dmic_set_sr_8k(dev); ++ break; ++ case 16000: ++ __dmic_set_sr_16k(dev); ++ break; ++ case 48000: ++ __dmic_set_sr_48k(dev); ++ break; ++ default: ++ dev_err(dev,"dmic unsupport rate %d\n",rate); ++ } ++ return 0; ++} ++ ++static int ingenic_dmic_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) ++{ ++ struct device *dev = dai->dev; ++ int channels = params_channels(params); ++ int rate = params_rate(params); ++ struct ingenic_dmic *ingenic_dmic = dev_get_drvdata(dai->dev); ++ int fmt_width = snd_pcm_format_width(params_format(params)); ++ enum dma_slave_buswidth buswidth; ++ int trigger; ++ ++ DMIC_DEBUG_MSG("enter %s, substream = %s\n",__func__,"capture"); ++ ++ if (!((1 << params_format(params)) & INGENIC_DMIC_FORMATS) ++ ||channels < 1||channels > 4|| rate > 48000||rate < 8000 ++ ||fmt_width != 16) { ++ dev_err(dai->dev, "hw params not inval channel %d params %x rate %d fmt_width %d\n", ++ channels, params_format(params),rate,fmt_width); ++ return -EINVAL; ++ } ++ ++ if (ingenic_dmic->unpack_enable) ++ buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; ++ else ++ buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; ++ ++ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { ++ ingenic_dmic->capture_dma_data.addr_width = buswidth; ++ ingenic_dmic->capture_dma_data.maxburst = (DMIC_FIFO_DEPTH * buswidth)/2; ++ trigger = ingenic_dmic->capture_dma_data.maxburst/(int)buswidth; ++ __dmic_set_request(dev, trigger); ++ __dmic_set_chnum(dev, channels - 1); ++ dmic_set_rate(dev,rate); ++// snd_soc_dai_set_dma_data(dai, substream, (void *)&ingenic_dmic->capture_dma_data); ++ } else { ++ dev_err(dai->dev, "DMIC is a capture device\n"); ++ } ++ return 0; ++} ++ ++static void ingenic_dmic_start_substream(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct ingenic_dmic *ingenic_dmic = dev_get_drvdata(dai->dev); ++ DMIC_DEBUG_MSG("enter %s, substream start capture\n", __func__); ++ ++ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { ++// clk_enable(ingenic_dmic->dmic_enable); ++ clk_prepare_enable(ingenic_dmic->clk_gate_dmic); ++ __dmic_enable(ingenic_dmic->dev); ++ __dmic_enable_rdms(ingenic_dmic->dev); ++ } else { ++ dev_err(dai->dev, "DMIC is a capture device\n"); ++ } ++ return; ++} ++ ++static void ingenic_dmic_stop_substream(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct ingenic_dmic *ingenic_dmic = dev_get_drvdata(dai->dev); ++ struct device *dev = dai->dev; ++ DMIC_DEBUG_MSG("enter %s, substream stop capture\n",__func__); ++ ++ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { ++ if (__dmic_is_enable_rdms(dev)) { ++ __dmic_disable_rdms(dev); ++ } ++// clk_disable(ingenic_dmic->dmic_enable); ++ clk_disable_unprepare(ingenic_dmic->clk_gate_dmic); ++ __dmic_disable(ingenic_dmic->dev); ++ }else{ ++ dev_err(dai->dev, "DMIC is a capture device\n"); ++ } ++ return; ++} ++ ++static int ingenic_dmic_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) ++{ ++ struct ingenic_pcm_runtime_data *prtd = substream->runtime->private_data; ++ DMIC_DEBUG_MSG("enter %s, substream capture cmd = %d\n", __func__,cmd); ++ ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ case SNDRV_PCM_TRIGGER_RESUME: ++ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: ++ if (atomic_read(&prtd->wait_stopdma)) ++ return -EPIPE; ++ printk(KERN_DEBUG"dmic start\n"); ++ ingenic_dmic_start_substream(substream, dai); ++ break; ++ case SNDRV_PCM_TRIGGER_STOP: ++ case SNDRV_PCM_TRIGGER_SUSPEND: ++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ++ if (atomic_read(&prtd->wait_stopdma)) ++ return 0; ++ printk(KERN_DEBUG"dmic stop\n"); ++ ingenic_dmic_stop_substream(substream, dai); ++ break; ++ } ++ return 0; ++} ++ ++static void ingenic_dmic_shutdown(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) { ++ struct ingenic_dmic *ingenic_dmic = dev_get_drvdata(dai->dev); ++ struct device *dev = dai->dev; ++ ++ DMIC_DEBUG_MSG("enter %s, substream = capture\n", __func__); ++ ++ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) ++ ingenic_dmic->dmic_mode &= ~DMIC_READ; ++ ++ if (!ingenic_dmic->dmic_mode) { ++ __dmic_disable(dev); ++ } ++ regulator_disable(ingenic_dmic->vcc_dmic); ++ clk_disable_unprepare(ingenic_dmic->clk_gate_dmic); ++ ingenic_dmic->en = 0; ++ return; ++} ++ ++static int ingenic_dmic_probe(struct snd_soc_dai *dai) ++{ ++ struct ingenic_dmic *ingenic_dmic = dev_get_drvdata(dai->dev); ++ snd_soc_dai_init_dma_data(dai, NULL, ++ &ingenic_dmic->capture_dma_data); ++ ++ clk_prepare_enable(ingenic_dmic->clk_gate_dmic); ++ ingenic_dmic_contoller_init(dai); ++ clk_disable_unprepare(ingenic_dmic->clk_gate_dmic); ++ return 0; ++} ++ ++ ++static struct snd_soc_dai_ops ingenic_dmic_dai_ops = { ++ .startup = ingenic_dmic_startup, ++ .trigger = ingenic_dmic_trigger, ++ .hw_params = ingenic_dmic_hw_params, ++ .shutdown = ingenic_dmic_shutdown, ++}; ++ ++#define ingenic_dmic_suspend NULL ++#define ingenic_dmic_resume NULL ++ ++static ssize_t ingenic_dmic_regs_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct ingenic_dmic *ingenic_dmic = dev_get_drvdata(dev); ++ dump_registers(ingenic_dmic->dev); ++ return 0; ++} ++ ++static ssize_t ingenic_dmic_regs_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, ++ size_t count) ++{ ++ struct ingenic_dmic *ingenic_dmic = dev_get_drvdata(dev); ++ const char *start = buf; ++ unsigned int reg, val; ++ int ret_count = 0; ++ ++ while(!isxdigit(*start)) { ++ start++; ++ if (++ret_count >= count) ++ return count; ++ } ++ reg = simple_strtoul(start, (char **)&start, 16); ++ ++ while(!isxdigit(*start)) { ++ start++; ++ if (++ret_count >= count) ++ return count; ++ } ++ val = simple_strtoul(start, (char **)&start, 16); ++ ++ clk_prepare_enable(ingenic_dmic->clk_gate_dmic); ++ regulator_enable(ingenic_dmic->vcc_dmic); ++ ++ dmic_write_reg(ingenic_dmic->dev, reg, val); ++ ++ regulator_disable(ingenic_dmic->vcc_dmic); ++ clk_disable_unprepare(ingenic_dmic->clk_gate_dmic); ++ ++ return count; ++ ++ ++} ++ ++static DEVICE_ATTR(dmic_regs, S_IRUGO | S_IWUSR, ingenic_dmic_regs_show, ingenic_dmic_regs_store); ++static const struct attribute *dump_attrs[] = { ++ &dev_attr_dmic_regs.attr, ++ NULL, ++}; ++static const struct attribute_group dump_attr_group = { ++ .attrs = (struct attribute **)dump_attrs, ++}; ++ ++static struct snd_soc_dai_driver ingenic_dmic_dai = { ++ .probe = ingenic_dmic_probe, ++ .suspend = ingenic_dmic_suspend, ++ .resume = ingenic_dmic_resume, ++ .capture = { ++ .channels_min = 1, ++ .channels_max = 4, ++ .rates = INGENIC_DMIC_RATE, ++ .formats = INGENIC_DMIC_FORMATS, ++ }, ++ .ops = &ingenic_dmic_dai_ops, ++}; ++ ++static const struct snd_soc_component_driver ingenic_dmic_component = { ++ .name = "ingenic-dmic", ++}; ++ ++static int dmic_gain_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); ++ struct ingenic_dmic *ingenic_dmic = snd_soc_codec_get_drvdata(codec); ++ unsigned int value; ++ clk_prepare_enable(ingenic_dmic->clk_gate_dmic); ++ value = dmic_read_reg(ingenic_dmic->dev, DMICGCR); ++ clk_disable_unprepare(ingenic_dmic->clk_gate_dmic); ++ ucontrol->value.integer.value[0] = value; ++ return 0; ++} ++static int dmic_gain_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); ++ struct ingenic_dmic *ingenic_dmic = snd_soc_codec_get_drvdata(codec); ++ unsigned int value = ucontrol->value.integer.value[0]; ++ ++ clk_prepare_enable(ingenic_dmic->clk_gate_dmic); ++ dmic_write_reg(ingenic_dmic->dev, DMICGCR, value); ++ clk_disable_unprepare(ingenic_dmic->clk_gate_dmic); ++ ++ return 0; ++} ++ ++static const DECLARE_TLV_DB_SCALE(dmic_gain_tlv, 0, 300, 0); ++static const struct snd_kcontrol_new dmic_codec_controls[] = { ++ SOC_SINGLE_EXT_TLV("dmic gain", 0, 0, 0xf, 0 , dmic_gain_get, dmic_gain_put, dmic_gain_tlv), ++}; ++ ++ ++static struct snd_soc_dai_driver dmic_codec_dai = { ++ .name = "dmic-codec-hifi", ++ .capture = { ++ .channels_min = 1, ++ .channels_max = 4, ++ .rates = SNDRV_PCM_RATE_48000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_8000, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE, ++ }, ++}; ++ ++static struct snd_soc_codec_driver soc_codec_dev_dmic_codec = { ++ .controls = dmic_codec_controls, ++ .num_controls = ARRAY_SIZE(dmic_codec_controls), ++}; ++ ++extern int ingenic_dma_pcm_register(struct device *dev, const struct snd_dmaengine_pcm_config *config); ++extern void ingenic_dma_pcm_unregister(struct device *dev); ++static int ingenic_dmic_platfrom_probe(struct platform_device *pdev) ++{ ++ struct ingenic_dmic *ingenic_dmic; ++ struct resource *res = NULL; ++ int ret; ++ ++ ingenic_dmic = devm_kzalloc(&pdev->dev, sizeof(struct ingenic_dmic), GFP_KERNEL); ++ if (!ingenic_dmic) ++ return -ENOMEM; ++ ++ ingenic_dmic->dev = &pdev->dev; ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) ++ return -ENOENT; ++ if (!devm_request_mem_region(&pdev->dev, ++ res->start, resource_size(res),pdev->name)) ++ return -EBUSY; ++ ++ ingenic_dmic->res_start = res->start; ++ ingenic_dmic->res_size = resource_size(res); ++ ingenic_dmic->vaddr_base = devm_ioremap_nocache(&pdev->dev, ++ ingenic_dmic->res_start, ingenic_dmic->res_size); ++ if (!ingenic_dmic->vaddr_base) { ++ dev_err(&pdev->dev, "Failed to ioremap mmio memory\n"); ++ return -ENOMEM; ++ } ++ ++ ingenic_dmic->dmic_mode = 0; ++ ingenic_dmic->capture_dma_data.addr = (dma_addr_t)ingenic_dmic->res_start + DMICDR; ++ ++ ingenic_dmic->vcc_dmic = regulator_get(&pdev->dev,"vcc_dmic"); ++ platform_set_drvdata(pdev, (void *)ingenic_dmic); ++ ++ ret = sysfs_create_group(&pdev->dev.kobj, &dump_attr_group); ++ if (ret) ++ dev_info(&pdev->dev, "dmic attr create failed\n"); ++ ++ ingenic_dmic->clk_gate_dmic = clk_get(&pdev->dev, "gate_dmic"); ++ if (IS_ERR_OR_NULL(ingenic_dmic->clk_gate_dmic)) { ++ ret = PTR_ERR(ingenic_dmic->clk_gate_dmic); ++ ingenic_dmic->clk_gate_dmic = NULL; ++ dev_err(&pdev->dev, "Failed to get clock: %d\n", ret); ++ return ret; ++ } ++// clk_prepare_enable(ingenic_dmic->clk_gate_dmic); ++// __dmic_enable(&pdev->dev); ++// printk("XXXXXXXXXXXXXXXXXXXXcgu-i2s%x\n",*(volatile unsigned int*)0xb0000060); ++// printk("XXXXXXXXXXXXXXXXXXXXgate-dmic%x\n",*(volatile unsigned int*)0xb0000020); ++// ingenic_dmic->dmic_enable = clk_get(&pdev->dev, "dmic_enable"); ++// if (IS_ERR_OR_NULL(ingenic_dmic->dmic_enable)) { ++// ret = PTR_ERR(ingenic_dmic->dmic_enable); ++// ingenic_dmic->dmic_enable = NULL; ++// dev_err(&pdev->dev, "Failed to get clock: %d\n", ret); ++// return ret; ++// } ++ ++ ret = snd_soc_register_codec(&pdev->dev, ++ &soc_codec_dev_dmic_codec, &dmic_codec_dai, 1); ++ ret = snd_soc_register_component(&pdev->dev, &ingenic_dmic_component, ++ &ingenic_dmic_dai, 1); ++ if (ret) ++ goto err_register_cpu_dai; ++ dev_dbg(&pdev->dev, "dmic platform probe success\n"); ++ ++ ret = ingenic_dma_pcm_register(&pdev->dev, NULL); ++ ++ return ret; ++ ++err_register_cpu_dai: ++ platform_set_drvdata(pdev, NULL); ++ return ret; ++} ++ ++static int ingenic_dmic_platfom_remove(struct platform_device *pdev) ++{ ++ sysfs_remove_group(&pdev->dev.kobj, &dump_attr_group); ++ snd_soc_unregister_component(&pdev->dev); ++ platform_set_drvdata(pdev, NULL); ++ ingenic_dma_pcm_unregister(&pdev->dev); ++ return 0; ++} ++ ++ ++#ifdef CONFIG_PM ++static int ingenic_dmic_platfom_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ struct ingenic_dmic *ingenic_dmic = platform_get_drvdata(pdev); ++ if(ingenic_dmic->en){ ++ regulator_disable(ingenic_dmic->vcc_dmic); ++ clk_disable_unprepare(ingenic_dmic->clk_gate_dmic); ++ } ++ return 0; ++} ++ ++static int ingenic_dmic_platfom_resume(struct platform_device *pdev) ++{ ++ struct ingenic_dmic *ingenic_dmic = platform_get_drvdata(pdev); ++ if(ingenic_dmic->en){ ++ regulator_enable(ingenic_dmic->vcc_dmic); ++ clk_prepare_enable(ingenic_dmic->clk_gate_dmic); ++ } ++ return 0; ++} ++#endif ++ ++static const struct of_device_id dmic_dt_match[] = { ++ { .compatible = "ingenic,dmic", .data = NULL }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, dmic_dt_match); ++static struct platform_driver ingenic_dmic_plat_driver = { ++ .probe = ingenic_dmic_platfrom_probe, ++ .remove = ingenic_dmic_platfom_remove, ++#ifdef CONFIG_PM ++ .suspend = ingenic_dmic_platfom_suspend, ++ .resume = ingenic_dmic_platfom_resume, ++#endif ++ .driver = { ++ .name = "ingenic-asoc-dmic", ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(dmic_dt_match), ++ }, ++}; ++ ++module_platform_driver(ingenic_dmic_plat_driver); ++MODULE_AUTHOR("siyu.zhang@ingenic.com"); ++MODULE_DESCRIPTION("INGENIC AIC dmic SoC Interface"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:ingenic-dmic"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_asoc-dmic.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_asoc-dmic.h.patch new file mode 100644 index 00000000..5bf2cd5a --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_asoc-dmic.h.patch @@ -0,0 +1,304 @@ +diff -drupN a/sound/soc/ingenic/as-v1/asoc-dmic.h b/sound/soc/ingenic/as-v1/asoc-dmic.h +--- a/sound/soc/ingenic/as-v1/asoc-dmic.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/as-v1/asoc-dmic.h 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,300 @@ ++#ifndef __ASOC_DMIC_H__ ++#define __ASOC_DMIC_H__ ++ ++#include ++#include ++#include "asoc-dma.h" ++ ++ ++struct dma2ddr_info { ++ void *addr; ++ unsigned int cur_pos; ++ unsigned int len; ++}; ++ ++ ++struct dma_fifo { ++ struct circ_buf xfer; ++ size_t n_size; ++ dma_addr_t paddr; ++}; ++ ++struct ingenic_dmic { ++ struct device *dev; ++ resource_size_t res_start; ++ resource_size_t res_size; ++ void __iomem *vaddr_base; ++#define DMIC_READ 0x1 ++ int unpack_enable; ++ int dmic_mode; ++ int en; ++ struct regulator * vcc_dmic; ++ struct clk *clk_gate_dmic; ++ struct clk *dmic_enable; ++// struct clk *aic_clk; ++ /*for dma*/ ++/* struct ingenic_pcm_dma_params rx_dma_data;*/ ++ struct snd_dmaengine_dai_dma_data capture_dma_data; ++ ++ struct dma_fifo *record_fifo; ++ ++ /* fifo transfer data from dma to tcsm */ ++ struct dma_fifo *tcsm_fifo; ++ ++ /* timer to trans data from tcsm to ddr */ ++ struct timer_list record_timer; ++ ++}; ++ ++static void inline dmic_write_reg(struct device *dev, unsigned int reg, ++ unsigned int val) ++{ ++ struct ingenic_dmic *ingenic_dmic = dev_get_drvdata(dev); ++ writel(val, ingenic_dmic->vaddr_base + reg); ++} ++ ++static unsigned int inline dmic_read_reg(struct device *dev, unsigned int reg) ++{ ++ struct ingenic_dmic *ingenic_dmic = dev_get_drvdata(dev); ++ return readl(ingenic_dmic->vaddr_base + reg); ++} ++#define dmic_set_reg(dev, addr, val, mask, offset)\ ++ do { \ ++ int tmp_val = val; \ ++ int read_val = dmic_read_reg(dev, addr); \ ++ read_val &= (~mask); \ ++ tmp_val = ((tmp_val << offset) & mask); \ ++ tmp_val |= read_val; \ ++ dmic_write_reg(dev, addr, tmp_val); \ ++ }while(0) ++ ++#define dmic_get_reg(dev, addr, mask, offset) \ ++ ((dmic_read_reg(dev, addr) & mask) >> offset) ++ ++ ++#define DMICCR0 0x0 ++#define DMICGCR 0x4 ++#define DMICIMR 0x8 ++#define DMICINTCR 0xc ++#define DMICTRICR 0x10 ++#define DMICTHRH 0x14 ++#define DMICTHRL 0x18 ++#define DMICTRIMMAX 0x1c ++#define DMICTRINMAX 0x20 ++#define DMICDR 0x30 ++#define DMICFTHR 0x34 ++#define DMICFSR 0x38 ++#define DMICCGDIS 0x50 ++ ++ ++/* DMICCR0 */ ++#define DMIC_RESET 31 ++#define DMIC_RESET_MASK (0x1 << DMIC_RESET) ++#define DMIC_RESET_TRI 30 ++#define DMIC_RESET_TRI_MASK (0x1 << DMIC_RESET_TRI) ++#define DMIC_CHNUM 16 ++#define DMIC_CHNUM_MASK (0x7 << DMIC_CHNUM) ++#define DMIC_UNPACK_MSB 13 ++#define DMIC_UNPACK_MSB_MASK (0x1 << DMIC_UNPACK_MSB) ++#define DMIC_UNPACK_DIS 12 ++#define DMIC_UNPACK_DIS_MASK (0x1 << DMIC_UNPACK_DIS) ++#define DMIC_SW_LR 11 ++#define DMIC_SW_LR_MASK (0x1 << DMIC_SW_LR) ++#define DMIC_SPLIT_DI 10 ++#define DMIC_SPLIT_DI_MASK (0x1 << DMIC_SPLIT_DI) ++#define DMIC_PACK_EN 8 ++#define DMIC_PACK_EN_MASK (0x1 << DMIC_PACK_EN) ++#define DMIC_SR 6 ++#define DMIC_SR_MASK (0x3 << DMIC_SR) ++#define DMIC_LP_MODE 3 ++#define DMIC_LP_MODE_MASK (0x1 << DMIC_LP_MODE) ++#define DMIC_HPF1_MODE 2 ++#define DMIC_HPF1_MODE_MASK (0x1 << DMIC_HPF1_MODE) ++#define DMIC_TRI_EN 1 ++#define DMIC_TRI_EN_MASK (0x1 << DMIC_TRI_EN) ++#define DMIC_EN 0 ++#define DMIC_EN_MASK (0x1 << DMIC_EN) ++ ++#define __dmic_reset(dev)\ ++ dmic_set_reg(dev,DMICCR0,1,DMIC_RESET_MASK,DMIC_RESET) ++ ++#define __dmic_get_reset(dev)\ ++ dmic_get_reg(dev,DMICCR0,DMIC_RESET_MASK,DMIC_RESET) ++ ++#define __dmic_reset_tri(dev)\ ++ dmic_set_reg(dev,DMICCR0,1,DMIC_RESET_TRI_MASK,DMIC_RESET_TRI) ++ ++#define __dmic_set_chnum(dev,n)\ ++ dmic_set_reg(dev,DMICCR0,n,DMIC_CHNUM_MASK,DMIC_CHNUM) ++ ++#define __dmic_get_chnum(dev,n)\ ++ dmic_set_reg(dev,DMICCR0,DMIC_CHNUM_MASK,DMIC_CHNUM) ++ ++#define __dmic_unpack_msb(dev)\ ++ dmic_set_reg(dev,DMICCR0,1,DMIC_UNPACK_MSB_MASK,DMIC_UNPACK_MSB) ++ ++#define __dmic_unpack_dis(dev)\ ++ dmic_set_reg(dev,DMICCR0,1,DMIC_UNPACK_DIS_MASK,DMIC_UNPACK_DIS) ++ ++#define __dmic_enable_sw_lr(dev)\ ++ dmic_set_reg(dev,DMICCR0,1,DMIC_SW_LR_MASK,DMIC_SW_LR) ++ ++#define __dmic_disable_sw_lr(dev)\ ++ dmic_set_reg(dev,DMICCR0,0,DMIC_SW_LR_MASK,DMIC_SW_LR) ++ ++#define __dmic_split(dev)\ ++ dmic_set_reg(dev,DMICCR0,1,DMIC_SPLIT_DI_MASK,DMIC_SPLIT_DI) ++ ++#define __dmic_enable_pack(dev)\ ++ dmic_set_reg(dev,DMICCR0,1,DMIC_PACK_EN_MASK,DMIC_PACK_EN) ++ ++#define __dmic_set_sr(dev,n)\ ++ dmic_set_reg(dev,DMICCR0,n,DMIC_SR_MASK,DMIC_SR) ++ ++#define __dmic_set_sr_8k(dev)\ ++ __dmic_set_sr(dev,0) ++ ++#define __dmic_set_sr_16k(dev)\ ++ __dmic_set_sr(dev,1) ++ ++#define __dmic_set_sr_48k(dev)\ ++ __dmic_set_sr(dev,2) ++ ++#define __dmic_enable_lp(dev)\ ++ dmic_set_reg(dev,DMICCR0,1,DMIC_LP_MODE_MASK,DMIC_LP_MODE) ++ ++#define __dmic_disable_lp(dev)\ ++ dmic_set_reg(dev,DMICCR0,0,DMIC_LP_MODE_MASK,DMIC_LP_MODE) ++ ++#define __dmic_enable_hpf1(dev)\ ++ dmic_set_reg(dev,DMICCR0,1,DMIC_HPF1_MODE_MASK,DMIC_HPF1_MODE) ++ ++#define __dmic_disable_hpf1(dev)\ ++ dmic_set_reg(dev,DMICCR0,0,DMIC_HPF1_MODE_MASK,DMIC_HPF1_MODE) ++ ++#define __dmic_is_enable_tri(dev)\ ++ dmic_get_reg(dev,DMICCR0,DMIC_TRI_EN_MASK,DMIC_TRI_EN) ++ ++#define __dmic_enable_tri(dev)\ ++ dmic_set_reg(dev,DMICCR0,1,DMIC_TRI_EN_MASK,DMIC_TRI_EN) ++ ++#define __dmic_disable_tri(dev)\ ++ dmic_set_reg(dev,DMICCR0,0,DMIC_TRI_EN_MASK,DMIC_TRI_EN) ++ ++#define __dmic_is_enable(dev)\ ++ dmic_get_reg(dev,DMICCR0,DMIC_EN_MASK,DMIC_EN) ++ ++#define __dmic_enable(dev)\ ++ dmic_set_reg(dev,DMICCR0,1,DMIC_EN_MASK,DMIC_EN) ++ ++#define __dmic_disable(dev)\ ++ dmic_set_reg(dev,DMICCR0,0,DMIC_EN_MASK,DMIC_EN) ++ ++/*DMICGCR*/ ++#define DMIC_GCR 0 ++#define DMIC_GCR_MASK (0Xf << DMIC_GCR) ++ ++#define __dmic_set_gcr(dev,n)\ ++ dmic_set_reg(dev, DMICGCR, n, DMIC_GCR_MASK,DMIC_GCR) ++ ++/* DMICIMR */ ++#define DMIC_FIFO_TRIG_MASK 5 ++#define DMIC_FIFO_TRIG_MSK (1 << DMIC_FIFO_TRIG_MASK) ++#define DMIC_WAKE_MASK 4 ++#define DMIC_WAKE_MSK (1 << DMIC_WAKE_MASK) ++#define DMIC_EMPTY_MASK 3 ++#define DMIC_EMPTY_MSK (1 << DMIC_EMPTY_MASK) ++#define DMIC_FULL_MASK 2 ++#define DMIC_FULL_MSK (1 << DMIC_FULL_MASK) ++#define DMIC_PRERD_MASK 1 ++#define DMIC_PRERD_MSK (1 << DMIC_PRERD_MASK) ++#define DMIC_TRI_MASK 0 ++#define DMIC_TRI_MSK (1 << DMIC_TRI_MASK) ++ ++#define __dmic_mask_all_int(dev)\ ++ dmic_set_reg(dev,DMICIMR, 0x3f, 0x3f, 0) ++ ++ ++/*DMICINTCR*/ ++#define DMIC_FIFO_TRIG_FLAG 4 ++#define DMIC_FIFO_TRIG_FLAG_MASK (1 << DMIC_WAKE_FLAG) ++#define DMIC_WAKE_FLAG 4 ++#define DMIC_WAKE_FLAG_MASK (1 << DMIC_WAKE_FLAG) ++#define DMIC_EMPTY_FLAG 3 ++#define DMIC_EMPTY_FLAG_MASK (1 << DMIC_EMPTY_FLAG) ++#define DMIC_FULL_FLAG 2 ++#define DMIC_FULL_FLAG_MASK (1 << DMIC_FULL_FLAG) ++#define DMIC_PRERD_FLAG 1 ++#define DMIC_PRERD_FLAG_MASK (1 << DMIC_PRERD_FLAG) ++#define DMIC_TRI_FLAG 0 ++#define DMIC_TRI_FLAG_MASK (1 << DMIC_TRI_FLAG) ++ ++/*DMICTRICR*/ ++#define DMIC_TRI_MODE 16 ++#define DMIC_TRI_MODE_MASK (0xf << DMIC_TRI_MODE) ++#define DMIC_TRI_DEBUG 4 ++#define DMIC_TRI_DEBUG_MASK (0x1 << DMIC_TRI_DEBUG) ++#define DMIC_HPF2_EN 3 ++#define DMIC_HPF2_EN_MASK (0x1 << DMIC_HPF2_EN) ++#define DMIC_PREFETCH 1 ++#define DMIC_PREFETCH_MASK (0x3 << DMIC_PREFETCH) ++#define DMIC_TRI_CLR 0 ++#define DMIC_TRI_CLR_MASK (0x1 << DMIC_TRI_CLR) ++ ++#define __dmic_enable_hpf2(dev) \ ++ dmic_set_reg(dev, DMICTRICR, 1, DMIC_HPF2_EN_MASK, DMIC_HPF2_EN) ++ ++#define __dmic_disable_hpf2(dev) \ ++ dmic_set_reg(dev, DMICTRICR, 0, DMIC_HPF2_EN_MASK, DMIC_HPF2_EN) ++ ++/*DMICTHRH*/ ++#define DMIC_THR_H 0 ++#define DMIC_THR_H_MASK (0xfffff << DMIC_THR_H) ++ ++#define __dmic_set_thr_high(dev,n) \ ++ dmic_set_reg(dev, DMICTHRH, n, DMIC_THR_H_MASK, DMIC_THR_H) ++ ++/*DMICTHRL*/ ++#define DMIC_THR_L 0 ++#define DMIC_THR_L_MASK (0xfffff << DMIC_THR_L) ++ ++#define __dmic_set_thr_low(dev,n) \ ++ dmic_set_reg(dev, DMICTHRL, n, DMIC_THR_L_MASK, DMIC_THR_L) ++ ++ ++/* DMICTRIMMAX */ ++#define DMIC_M_MAX 0 ++#define DMIC_M_MAX_MASK (0xffffff << DMIC_M_MAX) ++ ++/* DMICTRINMAX */ ++#define DMIC_N_MAX 0 ++#define DMIC_N_MAX_MASK (0xffff << DMIC_N_MAX) ++ ++/* DMICFTHR */ ++#define DMIC_RDMS 31 ++#define DMIC_RDMS_MASK (0x1 << DMIC_RDMS) ++#define DMIC_FIFO_THR 0 ++#define DMIC_FIFO_THR_MASK (0x3f << DMIC_FIFO_THR) ++ ++#define __dmic_is_enable_rdms(dev)\ ++ dmic_get_reg(dev, DMICFTHR,DMIC_RDMS_MASK,DMIC_RDMS) ++#define __dmic_enable_rdms(dev)\ ++ dmic_set_reg(dev, DMICFTHR,1,DMIC_RDMS_MASK,DMIC_RDMS) ++#define __dmic_disable_rdms(dev)\ ++ dmic_set_reg(dev, DMICFTHR,1,DMIC_RDMS_MASK,DMIC_RDMS) ++#define __dmic_set_request(dev,n) \ ++ dmic_set_reg(dev, DMICFTHR, n, DMIC_FIFO_THR_MASK, DMIC_FIFO_THR) ++ ++/*DMICFSR*/ ++#define DMIC_FULLS 19 ++#define DMIC_FULLS_MASK (0x1 << DMIC_FULLS) ++#define DMIC_TRIGS 18 ++#define DMIC_TRIGS_MASK (0x1 << DMIC_TRIGS) ++#define DMIC_PRERDS 17 ++#define DMIC_PRERDS_MASK (0x1 << DMIC_PRERDS) ++#define DMIC_EMPTYS 16 ++#define DMIC_EMPTYS_MASK (0x1 << DMIC_EMPTYS) ++#define DMIC_FIFO_LVL 0 ++#define DMIC_FIFO_LVL_MASK (0x3f << DMIC_FIFO_LVL) ++ ++#endif /* __ASOC_DMIC_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_asoc-i2s.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_asoc-i2s.c.patch new file mode 100644 index 00000000..05d07d0b --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_asoc-i2s.c.patch @@ -0,0 +1,485 @@ +diff -drupN a/sound/soc/ingenic/as-v1/asoc-i2s.c b/sound/soc/ingenic/as-v1/asoc-i2s.c +--- a/sound/soc/ingenic/as-v1/asoc-i2s.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/as-v1/asoc-i2s.c 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,481 @@ ++/* ++ * sound/soc/ingenic/asoc-i2s.c ++ * ALSA Soc Audio Layer -- ingenic i2s (part of aic controller) driver ++ * ++ * Copyright 2014 Ingenic Semiconductor Co.,Ltd ++ * cli ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "asoc-aic.h" ++#include "asoc-dma.h" ++ ++static int ingenic_i2s_debug = 0; ++module_param(ingenic_i2s_debug, int, 0644); ++#define I2S_DEBUG_MSG(msg...) \ ++ do { \ ++ if (ingenic_i2s_debug) \ ++ pr_debug("I2S: " msg); \ ++ } while(0) ++ ++struct ingenic_i2s { ++ struct device *aic; /*register access device*/ ++#define I2S_WRITE 0x1 ++#define I2S_READ 0x2 ++ int i2s_mode; ++ struct snd_dmaengine_dai_dma_data playback_dma_data; ++ struct snd_dmaengine_dai_dma_data capture_dma_data; ++ struct snd_soc_dai_driver dai_driver; ++ dma_addr_t dma_base; ++ struct clk *cgu_clk; ++ int playback_channels; ++}; ++ ++#define I2S_RFIFO_DEPTH 32 ++#define I2S_TFIFO_DEPTH 64 ++#define TX_FIFO_LEVEL 16 ++ ++static void dump_registers(struct device *aic) ++{ ++ struct ingenic_aic *ingenic_aic = dev_get_drvdata(aic); ++ ++ pr_info("AIC_FR\t\t%p : 0x%08x\n", (ingenic_aic->vaddr_base+AICFR),ingenic_aic_read_reg(aic, AICFR)); ++ pr_info("AIC_CR\t\t%p : 0x%08x\n", (ingenic_aic->vaddr_base+AICCR),ingenic_aic_read_reg(aic, AICCR)); ++ pr_info("AIC_I2SCR\t%p : 0x%08x\n",(ingenic_aic->vaddr_base+I2SCR),ingenic_aic_read_reg(aic, I2SCR)); ++ pr_info("AIC_SR\t\t%p : 0x%08x\n", (ingenic_aic->vaddr_base+AICSR),ingenic_aic_read_reg(aic, AICSR)); ++ pr_info("AIC_I2SSR\t%p : 0x%08x\n",(ingenic_aic->vaddr_base+I2SSR),ingenic_aic_read_reg(aic, I2SSR)); ++ pr_info("AIC_I2SDIV\t%p : 0x%08x\n",(ingenic_aic->vaddr_base+I2SDIV),ingenic_aic_read_reg(aic, I2SDIV)); ++ pr_info("AIC_DR\t\t%p\n", (ingenic_aic->vaddr_base+AICDR)); ++ return; ++} ++ ++static int ingenic_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) ++{ ++ struct ingenic_i2s *ingenic_i2s = dev_get_drvdata(dai->dev); ++ struct device *aic = ingenic_i2s->aic; ++ ++ I2S_DEBUG_MSG("enter %s dai fmt %x\n", __func__, fmt); ++ ++ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { ++ case SND_SOC_DAIFMT_I2S: /*i2s format*/ ++ __i2s_select_i2s_fmt(aic); ++ break; ++ case SND_SOC_DAIFMT_MSB: ++ __i2s_select_msb_fmt(aic); /*msb format*/ ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { ++ case SND_SOC_DAIFMT_NB_NF: ++ __i2s_send_lfirst(aic); ++ break; ++ case SND_SOC_DAIFMT_NB_IF: ++ __i2s_send_rfirst(aic); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { ++ case SND_SOC_DAIFMT_CBM_CFM: /*sync and bit clk (codec master : i2s slave)*/ ++ __i2s_bclk_input(aic); ++ __i2s_sync_input(aic); ++ break; ++ case SND_SOC_DAIFMT_CBS_CFM: ++ __i2s_bclk_output(aic); ++ __i2s_sync_output(aic); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int ingenic_set_sysclk(struct snd_soc_dai *dai, int clk_id, ++ unsigned int freq, int dir) ++{ ++ struct ingenic_i2s *ingenic_i2s = dev_get_drvdata(dai->dev); ++ struct device *aic = ingenic_i2s->aic; ++ ++ I2S_DEBUG_MSG("enter %s clk_id %d req %d clk dir %d\n", __func__, ++ clk_id, freq, dir); ++ ++ if (clk_id == INGENIC_I2S_INNER_CODEC) { ++ __aic_select_internal_codec(aic); ++ } else ++ __aic_select_external_codec(aic); ++ ++ aic_set_rate(aic, freq); ++ ++ if (dir == SND_SOC_CLOCK_OUT) ++ __i2s_select_sysclk_output(aic); ++ else ++ __i2s_select_sysclk_input(aic); ++ return 0; ++} ++ ++static int ingenic_i2s_startup(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct ingenic_i2s *ingenic_i2s = dev_get_drvdata(dai->dev); ++ struct device *aic = ingenic_i2s->aic; ++ enum aic_mode work_mode = AIC_I2S_MODE; ++ ++ I2S_DEBUG_MSG("enter %s, substream = %s\n", __func__, ++ (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? "playback" : "capture"); ++ ++ work_mode = aic_set_work_mode(aic, work_mode, true); ++ if (work_mode != AIC_I2S_MODE) { ++ dev_warn(ingenic_i2s->aic, "Aic now is working on %s mode, open i2s mode failed\n", ++ aic_work_mode_str(work_mode)); ++ return -EBUSY; ++ } ++ ++ if (!ingenic_i2s->i2s_mode) { ++ __aic_select_i2s(aic); ++ __i2s_play_lastsample(aic); ++ __aic_enable(aic); ++ } ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ ingenic_i2s->i2s_mode |= I2S_WRITE; ++ else ++ ingenic_i2s->i2s_mode |= I2S_READ; ++ return 0; ++} ++ ++ ++static int ingenic_i2s_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) ++{ ++ int channels = params_channels(params); ++ int fmt_width = snd_pcm_format_width(params_format(params)); ++ int phys_width = snd_pcm_format_physical_width(params_format(params)); ++ struct ingenic_i2s *ingenic_i2s = dev_get_drvdata(dai->dev); ++ struct device *aic = ingenic_i2s->aic; ++ enum dma_slave_buswidth buswidth; ++ int trigger; ++ ++ I2S_DEBUG_MSG("enter %s, substream = %s\n", __func__, ++ (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? "playback" : "capture"); ++ ++ /* format */ ++ if (phys_width == 8) ++ buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE; ++ else if (phys_width == 16) ++ buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; ++ else if (phys_width == 24) ++ buswidth = DMA_SLAVE_BUSWIDTH_3_BYTES; ++ else if (phys_width == 32) ++ buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; ++ else ++ return -EINVAL; ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ /* channel */ ++ ingenic_i2s->playback_channels = (channels == 1 ? 2 : channels); ++ __i2s_channel(aic, ingenic_i2s->playback_channels); ++ ++ if (channels == 1) ++ __i2s_m2s_enable(aic); /*unavailed ??*/ ++ else ++ __i2s_m2s_disable(aic); ++ ++ ingenic_i2s->playback_dma_data.addr_width = buswidth; ++ ingenic_i2s->playback_dma_data.maxburst = I2S_TFIFO_DEPTH/2; ++ ++ trigger = I2S_TFIFO_DEPTH - (ingenic_i2s->playback_dma_data.maxburst); ++ __i2s_set_oss(aic, fmt_width); ++ __i2s_set_transmit_trigger(aic, (trigger/2)); ++ } else { ++ ingenic_i2s->capture_dma_data.addr_width = buswidth; ++ ingenic_i2s->capture_dma_data.maxburst = I2S_TFIFO_DEPTH/2; ++ ++ trigger = ingenic_i2s->capture_dma_data.maxburst; ++ __i2s_set_iss(aic, fmt_width); ++ __i2s_set_receive_trigger(aic, (trigger/2 - 1)); ++ } ++ ++ return 0; ++} ++ ++static void ingenic_i2s_start_substream(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct ingenic_i2s *ingenic_i2s = dev_get_drvdata(dai->dev); ++ struct device *aic = ingenic_i2s->aic; ++ int level, i, level_d, discard; ++ I2S_DEBUG_MSG("enter %s, substream = %s\n", __func__, ++ (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? "playback" : "capture"); ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ unsigned filled_num; ++ /*Left and right channel will inversion, no sure, just makesure*/ ++ level = __aic_read_tfl(aic); ++ if (level < TX_FIFO_LEVEL) ++ filled_num = TX_FIFO_LEVEL - level; ++ else ++ filled_num = level - (level % ingenic_i2s->playback_channels); ++ for (i= 0; i < filled_num; i++) ++ __aic_write_txfifo(aic, 0x0); ++ ++ __aic_clear_tur(aic); ++ ++ __i2s_enable_transmit_dma(aic); ++ ++ __i2s_enable_replay(aic); ++ ++ I2S_DEBUG_MSG("aic dirty fifo size %d\n", level); ++ if (ingenic_i2s_debug) __aic_en_tur_int(aic); ++ } else { ++ level_d = level = __aic_read_rfl(aic); ++ __aic_clear_ror(aic); ++ ++ __i2s_enable_record(aic); ++ ++ /*Left and right channel will inversion, no sure, just makesure*/ ++ for (i = 0; i < level; i++) ++ discard = __aic_read_rxfifo(aic); ++ ++ __i2s_enable_receive_dma(aic); ++ ++ I2S_DEBUG_MSG("aic dirty fifo size %d\n", level_d); ++ ++ if (ingenic_i2s_debug) ++ __aic_en_ror_int(aic); ++ } ++ return; ++} ++ ++static void ingenic_i2s_stop_substream(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct ingenic_i2s *ingenic_i2s = dev_get_drvdata(dai->dev); ++ struct device *aic = ingenic_i2s->aic; ++ I2S_DEBUG_MSG("enter %s, substream = %s\n", __func__, ++ (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? "playback" : "capture"); ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ if (ingenic_i2s_debug) __aic_dis_tur_int(aic); ++ if (__i2s_transmit_dma_is_enable(aic)) ++ __i2s_disable_transmit_dma(aic); ++ __i2s_disable_replay(aic); ++ } else { ++ if (ingenic_i2s_debug) __aic_dis_ror_int(aic); ++ if (__i2s_receive_dma_is_enable(aic)) ++ __i2s_disable_receive_dma(aic); ++ __i2s_disable_record(aic); ++ } ++ return; ++} ++ ++static int ingenic_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) ++{ ++ struct ingenic_pcm_runtime_data *prtd = substream_to_prtd(substream); ++ ++ I2S_DEBUG_MSG("enter %s, substream = %s cmd = %d\n", __func__, ++ (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? "playback" : "capture", ++ cmd); ++ ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ case SNDRV_PCM_TRIGGER_RESUME: ++ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: ++ if (atomic_read(&prtd->wait_stopdma)) ++ return -EPIPE; ++ I2S_DEBUG_MSG("i2s start\n"); ++ ingenic_i2s_start_substream(substream, dai); ++ break; ++ case SNDRV_PCM_TRIGGER_STOP: ++ case SNDRV_PCM_TRIGGER_SUSPEND: ++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ++ if (atomic_read(&prtd->wait_stopdma)) ++ return 0; ++ I2S_DEBUG_MSG("i2s stop\n"); ++ ingenic_i2s_stop_substream(substream, dai); ++ break; ++ } ++ return 0; ++} ++ ++static void ingenic_i2s_shutdown(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) { ++ struct ingenic_i2s *ingenic_i2s = dev_get_drvdata(dai->dev); ++ struct device *aic = ingenic_i2s->aic; ++ enum aic_mode work_mode = AIC_I2S_MODE; ++ ++ I2S_DEBUG_MSG("enter %s, substream = %s\n", __func__, ++ (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? "playback" : "capture"); ++ ++ work_mode = aic_set_work_mode(ingenic_i2s->aic, work_mode, false); ++ BUG_ON((work_mode != AIC_NO_MODE)); ++ ++ ingenic_i2s_stop_substream(substream, dai); ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ ingenic_i2s->i2s_mode &= ~I2S_WRITE; ++ else ++ ingenic_i2s->i2s_mode &= ~I2S_READ; ++ ++ if (!ingenic_i2s->i2s_mode) ++ __aic_disable(aic); ++ return; ++} ++ ++static int ingenic_i2s_probe(struct snd_soc_dai *dai) ++{ ++ struct ingenic_i2s *ingenic_i2s = dev_get_drvdata(dai->dev); ++ struct device *aic = ingenic_i2s->aic; ++ ++ ingenic_i2s->playback_dma_data.addr = ingenic_i2s->dma_base + AICDR; ++ ingenic_i2s->playback_dma_data.fifo_size = I2S_TFIFO_DEPTH; ++ ingenic_i2s->capture_dma_data.addr = ingenic_i2s->dma_base + AICDR; ++ ingenic_i2s->capture_dma_data.fifo_size = I2S_RFIFO_DEPTH; ++ ++ snd_soc_dai_init_dma_data(dai, &ingenic_i2s->playback_dma_data, ++ &ingenic_i2s->capture_dma_data); ++ ++ /* inner codec(icdc) probe must have mclk*/ ++ __i2s_select_sysclk_output(aic); ++ __aic_select_internal_codec(aic); ++ __aic_select_i2s(aic); ++ __aic_enable(aic); ++ return 0; ++} ++ ++static struct snd_soc_dai_ops ingenic_i2s_dai_ops = { ++ .startup = ingenic_i2s_startup, ++ .trigger = ingenic_i2s_trigger, ++ .hw_params = ingenic_i2s_hw_params, ++ .shutdown = ingenic_i2s_shutdown, ++ .set_fmt = ingenic_set_dai_fmt, ++ .set_sysclk = ingenic_set_sysclk, ++}; ++ ++#define ingenic_i2s_suspend NULL ++#define ingenic_i2s_resume NULL ++ ++static ssize_t ingenic_i2s_regs_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct ingenic_i2s *ingenic_i2s = dev_get_drvdata(dev); ++ dump_registers(ingenic_i2s->aic); ++ return 0; ++} ++ ++static DEVICE_ATTR(i2s_regs, S_IRUGO, ingenic_i2s_regs_show, NULL); ++static const struct attribute *dump_attrs[] = { ++ &dev_attr_i2s_regs.attr, ++ NULL, ++}; ++ ++static const struct attribute_group dump_attr_group = { ++ .attrs = (struct attribute **)dump_attrs, ++}; ++ ++static const struct snd_soc_component_driver ingenic_i2s_component = { ++ .name = "aic-i2s", ++}; ++ ++#define INGENIC_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | \ ++ SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \ ++ SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE | \ ++ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE | \ ++ SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_U24_BE | \ ++ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3LE | \ ++ SNDRV_PCM_FMTBIT_S24_3BE | SNDRV_PCM_FMTBIT_U24_3BE | \ ++ SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_U20_3LE | \ ++ SNDRV_PCM_FMTBIT_S20_3BE | SNDRV_PCM_FMTBIT_U20_3BE | \ ++ SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_U18_3LE | \ ++ SNDRV_PCM_FMTBIT_S18_3BE | SNDRV_PCM_FMTBIT_U18_3BE ) ++ ++static int ingenic_i2s_platfrom_probe(struct platform_device *pdev) ++{ ++ struct device_node *parent = of_get_parent(pdev->dev.of_node); ++ struct resource res; ++ struct ingenic_i2s *ingenic_i2s; ++ int ret; ++ ++ if (!parent) ++ return -ENOMEM; ++ ++ ingenic_i2s = devm_kzalloc(&pdev->dev, sizeof(struct ingenic_i2s), GFP_KERNEL); ++ if (!ingenic_i2s) ++ return -ENOMEM; ++ ++ ret = of_address_to_resource(parent, 0, &res); ++ if (ret) ++ return ret; ++ ++ ingenic_i2s->dma_base = res.start; ++ ingenic_i2s->aic = pdev->dev.parent; ++ ingenic_i2s->i2s_mode = 0; ++ ingenic_i2s->dai_driver.probe = ingenic_i2s_probe; ++ ingenic_i2s->dai_driver.suspend = ingenic_i2s_suspend; ++ ingenic_i2s->dai_driver.resume = ingenic_i2s_resume; ++ ingenic_i2s->dai_driver.ops = &ingenic_i2s_dai_ops; ++ ingenic_i2s->dai_driver.playback.channels_min = 2; ++ ingenic_i2s->dai_driver.playback.channels_max = 2; ++ ingenic_i2s->dai_driver.playback.rates = SNDRV_PCM_RATE_8000_192000; ++ ingenic_i2s->dai_driver.playback.formats = INGENIC_I2S_FORMATS; ++ ingenic_i2s->dai_driver.capture.channels_min = 2; ++ ingenic_i2s->dai_driver.capture.channels_max = 2; ++ ingenic_i2s->dai_driver.capture.rates = SNDRV_PCM_RATE_8000_192000; ++ ingenic_i2s->dai_driver.capture.formats = INGENIC_I2S_FORMATS; ++ ingenic_i2s->playback_channels = 2; /*default value*/ ++ ++ platform_set_drvdata(pdev, (void *)ingenic_i2s); ++ ++ ret = devm_snd_soc_register_component(&pdev->dev, &ingenic_i2s_component, ++ &ingenic_i2s->dai_driver, 1); ++ if (!ret) ++ dev_info(&pdev->dev, "i2s platform probe success\n"); ++ ++ ret = sysfs_create_group(&pdev->dev.kobj, &dump_attr_group); ++ if (ret) ++ dev_info(&pdev->dev, "i2s attr create failed\n"); ++ ++ return ret; ++} ++ ++static const struct of_device_id i2s_dt_match[] = { ++ { .compatible = "ingenic,i2s", .data = NULL }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, i2s_dt_match); ++ ++static struct platform_driver ingenic_i2s_plat_driver = { ++ .probe = ingenic_i2s_platfrom_probe, ++ .driver = { ++ .name = "asoc-aic-i2s", ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(i2s_dt_match), ++ }, ++}; ++module_platform_driver(ingenic_i2s_plat_driver); ++ ++MODULE_AUTHOR("cli "); ++MODULE_DESCRIPTION("INGENIC AIC I2S SoC Interface"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:ingenic-aic-i2s"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_asoc-pcm.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_asoc-pcm.c.patch new file mode 100644 index 00000000..6261db57 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_asoc-pcm.c.patch @@ -0,0 +1,423 @@ +diff -drupN a/sound/soc/ingenic/as-v1/asoc-pcm.c b/sound/soc/ingenic/as-v1/asoc-pcm.c +--- a/sound/soc/ingenic/as-v1/asoc-pcm.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/as-v1/asoc-pcm.c 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,419 @@ ++/* ++ * sound/soc/ingenic/asoc-pcm.c ++ * ALSA Soc Audio Layer -- ingenic pcm (part of aic controller) driver ++ * ++ * Copyright 2014 Ingenic Semiconductor Co.,Ltd ++ * cscheng ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "asoc-pcm.h" ++ ++static int ingenic_pcm_debug = 0; ++module_param(ingenic_pcm_debug, int, 0644); ++#define PCM_DEBUG_MSG(msg...) \ ++ do { \ ++ if (ingenic_pcm_debug) \ ++ printk(KERN_DEBUG"PCM: " msg); \ ++ } while(0) ++ ++#define PCM_RFIFO_DEPTH 16 ++#define PCM_TFIFO_DEPTH 16 ++#define INGENIC_PCM_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE) ++ ++static void dump_registers(struct device *dev) ++{ ++ struct ingenic_pcm *ingenic_pcm = dev_get_drvdata(dev); ++ pr_info("PCMCTL %p : 0x%08x\n", (ingenic_pcm->vaddr_base+PCMCTL),pcm_read_reg(dev, PCMCTL)); ++ pr_info("PCMCFG %p : 0x%08x\n", (ingenic_pcm->vaddr_base+PCMCFG),pcm_read_reg(dev, PCMCFG)); ++ pr_info("PCMINTC %p : 0x%08x\n", (ingenic_pcm->vaddr_base+PCMINTC),pcm_read_reg(dev,PCMINTC)); ++ pr_info("PCMINTS %p : 0x%08x\n",(ingenic_pcm->vaddr_base+PCMINTS),pcm_read_reg(dev, PCMINTS)); ++ pr_info("PCMDIV %p : 0x%08x\n",(ingenic_pcm->vaddr_base+PCMDIV),pcm_read_reg(dev, PCMDIV)); ++ return; ++} ++ ++static int ingenic_pcm_startup(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct device *dev = dai->dev; ++ struct ingenic_pcm *ingenic_pcm = dev_get_drvdata(dai->dev); ++ ++ PCM_DEBUG_MSG("enter %s, substream = %s\n", ++ __func__, ++ (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? "playback" : "capture"); ++ ++ if (!ingenic_pcm->pcm_mode) { ++ clk_prepare_enable(ingenic_pcm->clk_gate); ++#if 1 ++ __pcm_as_slaver(dev); ++#else ++ clk_set_rate(ingenic_pcm->clk, 9600000); ++ clk_prepare_enable(ingenic_pcm->clk); ++ __pcm_as_master(dev); ++ __pcm_set_clkdiv(dev, 9600000/20/8000 - 1); ++ __pcm_set_syndiv(dev, 20 - 1); ++#endif ++ __pcm_set_msb_one_shift_in(dev); ++ __pcm_set_msb_one_shift_out(dev); ++ __pcm_play_lastsample(dev); ++ __pcm_enable(dev); ++ __pcm_clock_enable(dev); ++ } ++ ++ if (substream->stream == ++ SNDRV_PCM_STREAM_PLAYBACK) { ++ __pcm_disable_transmit_dma(dev); ++ __pcm_disable_replay(dev); ++ __pcm_clear_tur(dev); ++ ingenic_pcm->pcm_mode |= PCM_WRITE; ++ } else { ++ __pcm_disable_receive_dma(dev); ++ __pcm_disable_record(dev); ++ __pcm_clear_ror(dev); ++ ingenic_pcm->pcm_mode |= PCM_READ; ++ } ++ printk("start set PCM register....\n"); ++ return 0; ++} ++ ++static int ingenic_pcm_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) ++{ ++ struct device *dev = dai->dev; ++ struct ingenic_pcm *ingenic_pcm = dev_get_drvdata(dai->dev); ++ int fmt_width = snd_pcm_format_width(params_format(params)); ++ enum dma_slave_buswidth buswidth; ++ int trigger; ++ ++ PCM_DEBUG_MSG("enter %s, substream = %s\n", ++ __func__, ++ (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? "playback" : "capture"); ++ ++ if (!((1 << params_format(params)) & INGENIC_PCM_FORMATS) || ++ params_channels(params) != 1) { ++ dev_err(dai->dev, "hw params not inval channel %d params %x\n", ++ params_channels(params), params_format(params)); ++ return -EINVAL; ++ } ++ ++ /* format 8 bit or 16 bit*/ ++ if (fmt_width == 8) ++ buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE; ++ else ++ buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ ingenic_pcm->tx_dma_data.addr_width = buswidth; ++ ingenic_pcm->tx_dma_data.maxburst = (PCM_TFIFO_DEPTH * buswidth)/2; ++ trigger = PCM_TFIFO_DEPTH - (ingenic_pcm->tx_dma_data.maxburst/(int)buswidth); ++ __pcm_set_oss_sample_size(dev, fmt_width == 8 ? 0 : 1); ++ __pcm_set_transmit_trigger(dev, trigger); ++// snd_soc_dai_set_dma_data(dai, substream, (void *)&ingenic_pcm->tx_dma_data); ++ } else { ++ ingenic_pcm->rx_dma_data.addr_width = buswidth; ++ ingenic_pcm->rx_dma_data.maxburst = (PCM_RFIFO_DEPTH * buswidth)/2; ++ trigger = ingenic_pcm->rx_dma_data.maxburst/(int)buswidth; ++ __pcm_set_iss_sample_size(dev, fmt_width == 8 ? 0 : 1); ++ __pcm_set_receive_trigger(dev, trigger); ++// snd_soc_dai_set_dma_data(dai, substream, (void *)&ingenic_pcm->rx_dma_data); ++ } ++ return 0; ++} ++ ++static void ingenic_pcm_start_substream(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct device *dev = dai->dev; ++ PCM_DEBUG_MSG("enter %s, substream = %s\n", ++ __func__, ++ (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? "playback" : "capture"); ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ __pcm_enable_transmit_dma(dev); ++ __pcm_enable_replay(dev); ++ } else { ++ __pcm_enable_record(dev); ++ __pcm_enable_receive_dma(dev); ++ } ++ return; ++} ++ ++static void ingenic_pcm_stop_substream(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct device *dev = dai->dev; ++ int timeout = 150000; ++ PCM_DEBUG_MSG("enter %s, substream = %s\n", ++ __func__, ++ (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? "playback" : "capture"); ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ if (__pcm_transmit_dma_is_enable(dev)) { ++ __pcm_disable_transmit_dma(dev); ++ __pcm_clear_tur(dev); ++ /* Hrtimer mode: stop will be happen in any where, make sure there is ++ * no data transfer on ahb bus before stop dma ++ * Harzard: ++ * In pcm slave mode, the clk maybe stop before here, we will dead here ++ */ ++ while((!__pcm_test_tur(dev)) && (timeout--)){ ++ if(timeout == 0){ ++ printk("wait tansmit fifo under run error\n"); ++ return; ++ } ++ } ++ } ++ __pcm_disable_replay(dev); ++ __pcm_clear_tur(dev); ++ } else { ++ if (__pcm_receive_dma_is_enable(dev)) { ++ __pcm_disable_receive_dma(dev); ++ __pcm_clear_ror(dev); ++ while(!__pcm_test_ror(dev) && timeout--){ ++ if(timeout == 0){ ++ printk("wait tansmit fifo under run error\n"); ++ return; ++ } ++ } ++ } ++ __pcm_disable_record(dev); ++ __pcm_clear_ror(dev); ++ } ++ return; ++} ++ ++static int ingenic_pcm_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) ++{ ++ struct ingenic_pcm_runtime_data *prtd = substream->runtime->private_data; ++ PCM_DEBUG_MSG("enter %s, substream = %s cmd = %d\n", ++ __func__, ++ (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? "playback" : "capture", ++ cmd); ++ ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ case SNDRV_PCM_TRIGGER_RESUME: ++ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: ++ if (atomic_read(&prtd->wait_stopdma)) ++ return -EPIPE; ++ printk(KERN_DEBUG"pcm start\n"); ++ ingenic_pcm_start_substream(substream, dai); ++ break; ++ case SNDRV_PCM_TRIGGER_STOP: ++ case SNDRV_PCM_TRIGGER_SUSPEND: ++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ++ if (atomic_read(&prtd->wait_stopdma)) ++ return 0; ++ printk(KERN_DEBUG"pcm stop\n"); ++ ingenic_pcm_stop_substream(substream, dai); ++ break; ++ } ++ return 0; ++} ++ ++static void ingenic_pcm_shutdown(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) { ++ struct ingenic_pcm *ingenic_pcm = dev_get_drvdata(dai->dev); ++ struct device *dev = dai->dev; ++ ++ PCM_DEBUG_MSG("enter %s, substream = %s\n", ++ __func__, ++ (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? "playback" : "capture"); ++ ingenic_pcm_stop_substream(substream, dai); ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ ingenic_pcm->pcm_mode &= ~PCM_WRITE; ++ else ++ ingenic_pcm->pcm_mode &= ~PCM_READ; ++ ++ if (!ingenic_pcm->pcm_mode) { ++ __pcm_disable(dev); ++ __pcm_clock_disable(dev); ++ clk_disable_unprepare(ingenic_pcm->clk_gate); ++ } ++ return; ++} ++ ++static int ingenic_pcm_probe(struct snd_soc_dai *dai) ++{ ++ struct ingenic_pcm *ingenic_pcm = dev_get_drvdata(dai->dev); ++ ingenic_pcm->rx_dma_data.fifo_size = PCM_RFIFO_DEPTH; ++ ingenic_pcm->tx_dma_data.fifo_size = PCM_TFIFO_DEPTH; ++ snd_soc_dai_init_dma_data(dai, &ingenic_pcm->tx_dma_data, &ingenic_pcm->rx_dma_data); ++ return 0; ++} ++ ++ ++static struct snd_soc_dai_ops ingenic_pcm_dai_ops = { ++ .startup = ingenic_pcm_startup, ++ .trigger = ingenic_pcm_trigger, ++ .hw_params = ingenic_pcm_hw_params, ++ .shutdown = ingenic_pcm_shutdown, ++}; ++ ++#define ingenic_pcm_suspend NULL ++#define ingenic_pcm_resume NULL ++ ++static ssize_t ingenic_pcm_regs_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct ingenic_pcm *ingenic_pcm = dev_get_drvdata(dev); ++ dump_registers(ingenic_pcm->dev); ++ return 0; ++} ++ ++static struct device_attribute ingenic_pcm_sysfs_attrs[] = { ++ __ATTR(pcm_regs, S_IRUGO, ingenic_pcm_regs_show, NULL), ++}; ++ ++static struct snd_soc_dai_driver ingenic_pcm_dai = { ++ .probe = ingenic_pcm_probe, ++ .suspend = ingenic_pcm_suspend, ++ .resume = ingenic_pcm_resume, ++ .playback = { ++ .channels_min = 1, ++ .channels_max = 1, ++ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000, ++ .formats = INGENIC_PCM_FORMATS, ++ }, ++ .capture = { ++ .channels_min = 1, ++ .channels_max = 1, ++ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000, ++ .formats = INGENIC_PCM_FORMATS, ++ }, ++ .ops = &ingenic_pcm_dai_ops, ++}; ++static const struct snd_soc_component_driver ingenic_pcm_component = { ++ .name = "ingenic-pcm", ++}; ++ ++extern int ingenic_dma_pcm_register(struct device *dev, const struct snd_dmaengine_pcm_config *config); ++extern void ingenic_dma_pcm_unregister(struct device *dev); ++static int ingenic_pcm_platfrom_probe(struct platform_device *pdev) ++{ ++ struct ingenic_pcm *ingenic_pcm; ++ struct resource *res = NULL; ++ int i = 0, ret; ++ ++ ingenic_pcm = devm_kzalloc(&pdev->dev, sizeof(struct ingenic_pcm), GFP_KERNEL); ++ if (!ingenic_pcm) ++ return -ENOMEM; ++ ++ ingenic_pcm->dev = &pdev->dev; ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) ++ return -ENOENT; ++ if (!devm_request_mem_region(&pdev->dev, ++ res->start, resource_size(res), ++ pdev->name)) ++ return -EBUSY; ++ ++ ingenic_pcm->res_start = res->start; ++ ingenic_pcm->res_size = resource_size(res); ++ ingenic_pcm->vaddr_base = devm_ioremap_nocache(&pdev->dev, ++ ingenic_pcm->res_start, ingenic_pcm->res_size); ++ if (!ingenic_pcm->vaddr_base) { ++ dev_err(&pdev->dev, "Failed to ioremap mmio memory\n"); ++ return -ENOMEM; ++ } ++ ++ ingenic_pcm->clk_gate = clk_get(&pdev->dev, "gate_pcm"); ++ if (IS_ERR_OR_NULL(ingenic_pcm->clk_gate)) { ++ ret = PTR_ERR(ingenic_pcm->clk_gate); ++ dev_err(&pdev->dev, "Failed to get clock: %d\n", ret); ++ ingenic_pcm->clk_gate = NULL; ++ return ret; ++ } ++ ingenic_pcm->clk = clk_get(&pdev->dev, "cgu_pcm"); ++ if (IS_ERR_OR_NULL(ingenic_pcm->clk)) { ++ ret = PTR_ERR(ingenic_pcm->clk); ++ dev_err(&pdev->dev, "Failed to get clock: %d\n", ret); ++ goto err_get_clk; ++ } ++ platform_set_drvdata(pdev, (void *)ingenic_pcm); ++ ++ ingenic_pcm->pcm_mode = 0; ++ ingenic_pcm->tx_dma_data.addr = (dma_addr_t)ingenic_pcm->res_start + PCMDP; ++ ingenic_pcm->rx_dma_data.addr = (dma_addr_t)ingenic_pcm->res_start + PCMDP; ++ platform_set_drvdata(pdev, (void *)ingenic_pcm); ++ ++ for (; i < ARRAY_SIZE(ingenic_pcm_sysfs_attrs); i++) { ++ ret = device_create_file(&pdev->dev, &ingenic_pcm_sysfs_attrs[i]); ++ if (ret) ++ dev_warn(&pdev->dev,"attribute create failed\n"); ++ } ++ ++ ret = snd_soc_register_component(&pdev->dev, &ingenic_pcm_component, ++ &ingenic_pcm_dai, 1); ++ if (ret) ++ goto err_register_cpu_dai; ++ dev_info(&pdev->dev, "pcm platform probe success\n"); ++ ++ ret = ingenic_dma_pcm_register(&pdev->dev, NULL); ++ ++ return ret; ++ ++err_register_cpu_dai: ++ platform_set_drvdata(pdev, NULL); ++ clk_put(ingenic_pcm->clk); ++ ingenic_pcm->clk = NULL; ++err_get_clk: ++ clk_put(ingenic_pcm->clk_gate); ++ ingenic_pcm->clk_gate = NULL; ++ return ret; ++} ++ ++static int ingenic_pcm_platfom_remove(struct platform_device *pdev) ++{ ++ struct ingenic_pcm *ingenic_pcm = platform_get_drvdata(pdev); ++ int i; ++ for (i = 0; i < ARRAY_SIZE(ingenic_pcm_sysfs_attrs); i++) ++ device_remove_file(&pdev->dev, &ingenic_pcm_sysfs_attrs[i]); ++ snd_soc_unregister_component(&pdev->dev); ++ ingenic_dma_pcm_unregister(&pdev->dev); ++ clk_disable_unprepare(ingenic_pcm->clk_gate); ++ clk_disable_unprepare(ingenic_pcm->clk); ++ clk_put(ingenic_pcm->clk_gate); ++ clk_put(ingenic_pcm->clk); ++ platform_set_drvdata(pdev, NULL); ++ return 0; ++} ++ ++static const struct of_device_id pcm_dt_match[] = { ++ {.compatible = "ingenic,pcm",}, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, pcm_dt_match); ++static struct platform_driver ingenic_pcm_plat_driver = { ++ .probe = ingenic_pcm_platfrom_probe, ++ .remove = ingenic_pcm_platfom_remove, ++ .driver = { ++ .name = "ingenic-asoc-pcm", ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(pcm_dt_match), ++ }, ++}; ++ ++module_platform_driver(ingenic_pcm_plat_driver); ++MODULE_AUTHOR("shicheng.cheng@ingenic.com"); ++MODULE_DESCRIPTION("INGENIC AIC PCM SoC Interface"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:ingenic-pcm"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_asoc-pcm.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_asoc-pcm.h.patch new file mode 100644 index 00000000..241dd8aa --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_asoc-pcm.h.patch @@ -0,0 +1,256 @@ +diff -drupN a/sound/soc/ingenic/as-v1/asoc-pcm.h b/sound/soc/ingenic/as-v1/asoc-pcm.h +--- a/sound/soc/ingenic/as-v1/asoc-pcm.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/as-v1/asoc-pcm.h 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,252 @@ ++ ++#ifndef __ASOC_PCM_H__ ++#define __ASOC_PCM_H__ ++ ++#include ++#include "asoc-dma.h" ++ ++#define PCMCTL 0x00 ++#define PCMCFG 0x04 ++#define PCMDP 0x08 ++#define PCMINTC 0x0C ++#define PCMINTS 0x10 ++#define PCMDIV 0x14 ++ ++struct ingenic_pcm { ++ struct device *dev; ++ resource_size_t res_start; ++ resource_size_t res_size; ++ void __iomem *vaddr_base; ++ struct clk *clk; ++ struct clk *clk_gate; ++#define PCM_READ 0x1 ++#define PCM_WRITE 0X2 ++ int pcm_mode; ++ /*for dma*/ ++ struct snd_dmaengine_dai_dma_data tx_dma_data; ++ struct snd_dmaengine_dai_dma_data rx_dma_data; ++}; ++ ++static void inline pcm_write_reg(struct device *dev, unsigned int reg, ++ unsigned int val) ++{ ++ struct ingenic_pcm *ingenic_pcm = dev_get_drvdata(dev); ++ writel(val, ingenic_pcm->vaddr_base + reg); ++} ++ ++static unsigned int inline pcm_read_reg(struct device *dev, unsigned int reg) ++{ ++ struct ingenic_pcm *ingenic_pcm = dev_get_drvdata(dev); ++ return readl(ingenic_pcm->vaddr_base + reg); ++} ++ ++#define pcm_set_reg(dev, addr, val, mask, offset)\ ++ do { \ ++ int tmp_val = val; \ ++ int read_val = pcm_read_reg(dev, addr); \ ++ read_val &= (~mask); \ ++ tmp_val = ((tmp_val << offset) & mask); \ ++ tmp_val |= read_val; \ ++ pcm_write_reg(dev, addr, tmp_val); \ ++ }while(0) ++ ++#define pcm_get_reg(dev, addr, mask, offset) \ ++ ((pcm_read_reg(dev, addr) & mask) >> offset) ++ ++/*PCMCTL*/ ++#define PCM_ERDMA_OFFSET (9) ++#define PCM_ERDMA_MASK (0x1 << PCM_ERDMA_OFFSET) ++#define PCM_ETDMA_OFFSET (8) ++#define PCM_ETDMA_MASK (0x1 << PCM_ETDMA_OFFSET) ++#define PCM_LSMP_OFFSET (7) ++#define PCM_LSMP_MASK (0x1 << PCM_LSMP_OFFSET) ++#define PCM_ERPL_OFFSET (6) ++#define PCM_ERPL_MASK (0x1 << PCM_ERPL_OFFSET) ++#define PCM_EREC_OFFSET (5) ++#define PCM_EREC_MASK (0x1 << PCM_EREC_OFFSET) ++#define PCM_FLUSH_OFFSET (4) ++#define PCM_FLUSH_MASK (0x1 << PCM_FLUSH_OFFSET) ++#define PCM_RST_OFFSET (3) ++#define PCM_RST_MASK (0x1 << PCM_RST_OFFSET) ++#define PCM_CLKEN_OFFSET (1) ++#define PCM_CLKEN_MASK (0x1 << PCM_CLKEN_OFFSET) ++#define PCM_PCMEN_OFFSET (0) ++#define PCM_PCMEN_MASK (0x1 << PCM_PCMEN_OFFSET) ++ ++#define __pcm_transmit_dma_is_enable(dev) \ ++ pcm_get_reg(dev,PCMCTL,PCM_ETDMA_MASK,PCM_ETDMA_OFFSET) ++#define __pcm_enable_transmit_dma(dev) \ ++ pcm_set_reg(dev,PCMCTL,1,PCM_ETDMA_MASK,PCM_ETDMA_OFFSET) ++#define __pcm_disable_transmit_dma(dev) \ ++ pcm_set_reg(dev,PCMCTL,0,PCM_ETDMA_MASK,PCM_ETDMA_OFFSET) ++ ++#define __pcm_receive_dma_is_enable(dev) \ ++ pcm_get_reg(dev,PCMCTL,PCM_ERDMA_MASK,PCM_ERDMA_OFFSET) ++#define __pcm_enable_receive_dma(dev) \ ++ pcm_set_reg(dev,PCMCTL,1,PCM_ERDMA_MASK,PCM_ERDMA_OFFSET) ++#define __pcm_disable_receive_dma(dev) \ ++ pcm_set_reg(dev,PCMCTL,0,PCM_ERDMA_MASK,PCM_ERDMA_OFFSET) ++ ++#define __pcm_play_zero(dev) \ ++ pcm_set_reg(dev,PCMCTL,0,PCM_LSMP_MASK,PCM_LSMP_OFFSET) ++#define __pcm_play_lastsample(dev) \ ++ pcm_set_reg(dev,PCMCTL,1,PCM_LSMP_MASK,PCM_LSMP_OFFSET) ++ ++#define __pcm_enable_replay(dev) \ ++ pcm_set_reg(dev,PCMCTL,1,PCM_ERPL_MASK,PCM_ERPL_OFFSET) ++#define __pcm_disable_replay(dev) \ ++ pcm_set_reg(dev,PCMCTL,0,PCM_ERPL_MASK,PCM_ERPL_OFFSET) ++#define __pcm_enable_record(dev) \ ++ pcm_set_reg(dev,PCMCTL,1,PCM_EREC_MASK,PCM_EREC_OFFSET) ++#define __pcm_disable_record(dev) \ ++ pcm_set_reg(dev,PCMCTL,0,PCM_EREC_MASK,PCM_EREC_OFFSET) ++ ++#define __pcm_flush_fifo(dev) \ ++ pcm_set_reg(dev, PCMCTL,1,PCM_FLUSH_MASK,PCM_FLUSH_OFFSET) ++ ++#define __pcm_reset(dev) \ ++ pcm_set_reg(dev,PCMCTL,1,PCM_RST_MASK,PCM_RST_OFFSET) ++ ++#define __pcm_clock_enable(dev) \ ++ pcm_set_reg(dev,PCMCTL,1,PCM_CLKEN_MASK,PCM_CLKEN_OFFSET) ++#define __pcm_clock_disable(dev) \ ++ pcm_set_reg(dev,PCMCTL,0,PCM_CLKEN_MASK,PCM_CLKEN_OFFSET) ++ ++#define __pcm_enable(dev) \ ++ pcm_set_reg(dev,PCMCTL,1,PCM_PCMEN_MASK,PCM_PCMEN_OFFSET) ++#define __pcm_disable(dev) \ ++ pcm_set_reg(dev,PCMCTL,0,PCM_PCMEN_MASK,PCM_PCMEN_OFFSET) ++ ++/*PCMCFG*/ ++#define PCM_SLOT_OFFSET (13) ++#define PCM_SLOT_MASK (0x3 << PCM_SLOT_OFFSET) ++#define PCM_ISS_OFFSET (12) ++#define PCM_ISS_MASK (0x1 << PCM_ISS_OFFSET) ++#define PCM_OSS_OFFSET (11) ++#define PCM_OSS_MASK (0x1 << PCM_OSS_OFFSET) ++#define PCM_IMSBPOS_OFFSET (10) ++#define PCM_IMSBPOS_MASK (0x1 << PCM_IMSBPOS_OFFSET) ++#define PCM_OMSBPOS_OFFSET (9) ++#define PCM_OMSBPOS_MASK (0x1 << PCM_OMSBPOS_OFFSET) ++#define PCM_RFTH_OFFSET (5) ++#define PCM_RFTH_MASK (0xf << PCM_RFTH_OFFSET) ++#define PCM_TFTH_OFFSET (1) ++#define PCM_TFTH_MASK (0xf << PCM_TFTH_OFFSET) ++#define PCM_PCMMOD_OFFSET (0) ++#define PCM_PCMMOD_MASK (0x1 << PCM_PCMMOD_OFFSET) ++ ++#define __pcm_set_slot(dev,n) \ ++ pcm_set_reg(dev,PCMCFG,n,PCM_SLOT_MASK,PCM_SLOT_OFFSET) ++ ++#define __pcm_set_oss_sample_size(dev,n) \ ++ pcm_set_reg(dev,PCMCFG,n,PCM_OSS_MASK,PCM_OSS_OFFSET) ++#define __pcm_set_iss_sample_size(dev,n) \ ++ pcm_set_reg(dev,PCMCFG,n,PCM_ISS_MASK,PCM_ISS_OFFSET) ++ ++#define __pcm_set_msb_normal_in(dev) \ ++ pcm_set_reg(dev,PCMCFG,0,PCM_IMSBPOS_MASK,PCM_IMSBPOS_OFFSET) ++#define __pcm_set_msb_one_shift_in(dev) \ ++ pcm_set_reg(dev,PCMCFG,1,PCM_IMSBPOS_MASK,PCM_IMSBPOS_OFFSET) ++ ++#define __pcm_set_msb_normal_out(dev) \ ++ pcm_set_reg(dev,PCMCFG,0,PCM_OMSBPOS_MASK,PCM_OMSBPOS_OFFSET) ++#define __pcm_set_msb_one_shift_out(dev) \ ++ pcm_set_reg(dev,PCMCFG,1,PCM_OMSBPOS_MASK,PCM_OMSBPOS_OFFSET) ++ ++#define __pcm_set_transmit_trigger(dev,n) \ ++ pcm_set_reg(dev,PCMCFG,n,PCM_TFTH_MASK,PCM_TFTH_OFFSET) ++#define __pcm_set_receive_trigger(dev,n) \ ++ pcm_set_reg(dev,PCMCFG,n,PCM_RFTH_MASK,PCM_RFTH_OFFSET) ++ ++#define __pcm_as_master(dev) \ ++ pcm_set_reg(dev,PCMCFG,0,PCM_PCMMOD_MASK,PCM_PCMMOD_OFFSET) ++#define __pcm_as_slaver(dev) \ ++ pcm_set_reg(dev,PCMCFG,1,PCM_PCMMOD_MASK,PCM_PCMMOD_OFFSET) ++ ++/*PCMDP*/ ++#define PCM_PCMDP_OFFSET (0) ++#define PCM_PCMDP_MASK (~0) ++ ++#define __pcm_read_fifo(dev) \ ++ pcm_get_reg(dev,PCMDP,PCM_PCMDP_MASK,PCM_PCMDP_OFFSET); ++ ++/*PCMINTC*/ ++#define PCM_ETFS_OFFSET (3) ++#define PCM_ETFS_MASK (0X1 << PCM_ETFS_OFFSET) ++#define PCM_ETUR_OFFSET (2) ++#define PCM_ETUR_MASK (0x1 << PCM_ETUR_OFFSET) ++#define PCM_ERFS_OFFSET (1) ++#define PCM_ERFS_MASK (0x1 << PCM_ERFS_OFFSET) ++#define PCM_EROR_OFFSET (0) ++#define PCM_EROR_MASK (0x1 << PCM_EROR_OFFSET) ++ ++#define __pcm_enable_receive_intr(dev) \ ++ pcm_set_reg(dev,PCMINTC,1,PCM_ERFS_MASK,PCM_ERFS_OFFSET) ++#define __pcm_disable_receive_intr(dev) \ ++ pcm_set_reg(dev,PCMINTC,0,PCM_ERFS_MASK,PCM_ERFS_OFFSET) ++ ++#define __pcm_enable_underrun_intr(dev) \ ++ pcm_set_reg(dev,PCMINTC,1,PCM_ETUR_MASK,PCM_ETUR_OFFSET) ++#define __pcm_disable_underrun_intr(dev) \ ++ pcm_set_reg(dev,PCMINTC,0,PCM_ETUR_MASK,PCM_ETUR_OFFSET) ++ ++#define __pcm_enable_transmit_intr(dev) \ ++ pcm_set_reg(dev,PCMINTC,1,PCM_ETFS_MASK,PCM_ETFS_OFFSET) ++#define __pcm_disable_transmit_intr(dev) \ ++ pcm_set_reg(dev,PCMINTC,0,PCM_ETFS_MASK,PCM_ETFS_OFFSET) ++ ++#define __pcm_enable_overrun_intr(dev) \ ++ pcm_set_reg(dev,PCMINTC,1,PCM_EROR_MASK,PCM_EROR_OFFSET) ++#define __pcm_disable_overrun_intr(dev) \ ++ pcm_set_reg(dev,PCMINTC,0,PCM_EROR_MASK,PCM_EROR_OFFSET) ++ ++/*PCMINTS*/ ++#define PCM_RSTS_OFFSET (14) ++#define PCM_RSTS_MASK (0x1 << PCM_RSTS_OFFSET) ++#define PCM_TFL_OFFSET (9) ++#define PCM_TFL_MASK (0x1f << PCM_TFL_OFFSET) ++#define PCM_TFS_OFFSET (8) ++#define PCM_TFS_MASK (0x1 << PCM_TFS_OFFSET) ++#define PCM_TUR_OFFSET (7) ++#define PCM_TUR_MASK (0x1 << PCM_TUR_OFFSET) ++#define PCM_RFL_OFFSET (2) ++#define PCM_RFL_MASK (0x1f << PCM_RFL_OFFSET) ++#define PCM_RFS_OFFSET (1) ++#define PCM_RFS_MASK (0x1 << PCM_RFS_OFFSET) ++#define PCM_ROR_OFFSET (0) ++#define PCM_ROR_MASK (0X1 << PCM_ROR_OFFSET) ++ ++#define __pcm_test_rst_complie(dev) \ ++ !pcm_get_reg(dev,PCMINTS,PCM_RSTS_MASK,PCM_RSTS_OFFSET) ++#define __pcm_test_tfl(dev) \ ++ pcm_get_reg(dev,PCMINTS,PCM_TFL_MASK,PCM_TFL_OFFSET) ++#define __pcm_test_tfs(dev) \ ++ pcm_get_reg(dev,PCMINTS,PCM_TFS_MASK,PCM_TFS_OFFSET) ++#define __pcm_test_tur(dev) \ ++ pcm_get_reg(dev,PCMINTS,PCM_TUR_MASK,PCM_TUR_OFFSET) ++#define __pcm_clear_tur(dev) \ ++ pcm_set_reg(dev,PCMINTS,0,PCM_TUR_MASK,PCM_TUR_OFFSET) ++#define __pcm_test_rfl(dev) \ ++ pcm_get_reg(dev,PCMINTS,PCM_RFL_MASK,PCM_RFL_OFFSET) ++#define __pcm_test_rfs(dev) \ ++ pcm_get_reg(dev,PCMINTS,PCM_RFS_MASK,PCM_RFS_OFFSET) ++#define __pcm_clear_ror(dev) \ ++ pcm_set_reg(dev,PCMINTS,0,PCM_ROR_MASK,PCM_ROR_OFFSET) ++#define __pcm_test_ror(dev) \ ++ pcm_get_reg(dev,PCMINTS,PCM_ROR_MASK,PCM_ROR_OFFSET) ++/* PCMDIV */ ++#define PCM_SYNC_OFFSET (11) ++#define PCM_SYNC_MASK (0x3f << PCM_SYNC_OFFSET) ++#define PCM_SYNDIV_OFFSET (6) ++#define PCM_SYNDIV_MASK (0x1f << PCM_SYNDIV_OFFSET) ++#define PCM_CLKDIV_OFFSET (0) ++#define PCM_CLKDIV_MASK (0x3f << PCM_CLKDIV_OFFSET) ++ ++#define __pcm_set_sync(dev,n) \ ++ pcm_set_reg(dev,PCMDIV,n,PCM_SYNC_MASK,PCM_SYNC_OFFSET) ++#define __pcm_set_syndiv(dev,n) \ ++ pcm_set_reg(dev,PCMDIV,n,PCM_SYNDIV_MASK,PCM_SYNDIV_OFFSET) ++#define __pcm_set_clkdiv(dev,n) \ ++ pcm_set_reg(dev,PCMDIV,n,PCM_CLKDIV_MASK,PCM_CLKDIV_OFFSET) ++ ++#endif /* __ASOC_PCM_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_asoc-spdif.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_asoc-spdif.c.patch new file mode 100644 index 00000000..8f83e696 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v1_asoc-spdif.c.patch @@ -0,0 +1,494 @@ +diff -drupN a/sound/soc/ingenic/as-v1/asoc-spdif.c b/sound/soc/ingenic/as-v1/asoc-spdif.c +--- a/sound/soc/ingenic/as-v1/asoc-spdif.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/as-v1/asoc-spdif.c 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,490 @@ ++/* ++ * sound/soc/ingenic/asoc-spdif.c ++ * ALSA Soc Audio Layer -- ingenic spdif (part of aic controller) driver ++ * ++ * Copyright 2014 Ingenic Semiconductor Co.,Ltd ++ * cscheng ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "asoc-aic.h" ++#include "asoc-dma.h" ++ ++#define I2S_CPM_VALID 0xb0000070 ++static int ingenic_spdif_debug = 0; ++module_param(ingenic_spdif_debug, int, 0644); ++#define spdif_DEBUG_MSG(msg...) \ ++ do { \ ++ if (ingenic_spdif_debug) \ ++ printk("SPDIF: " msg); \ ++ } while(0) ++ ++struct ingenic_spdif { ++ struct device *aic; ++ struct snd_dmaengine_dai_dma_data playback_dma_data; ++}; ++ ++struct clk { ++ const char *name; ++ unsigned long rate; ++ struct clk *parent; ++ unsigned long flags; ++ struct clk_ops *ops; ++ int count; ++ struct clk *source; ++}; ++ ++#define SPDIF_TFIFO_DEPTH 32 ++#define INGENIC_SPDIF_FORMATS (SNDRV_PCM_FMTBIT_S24_LE|SNDRV_PCM_FMTBIT_S16_LE) ++#define INGENIC_SPDIF_RATE (SNDRV_PCM_RATE_32000|SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000|SNDRV_PCM_RATE_96000|SNDRV_PCM_RATE_192000) ++ ++static void dump_registers(struct device *aic) ++{ ++ struct ingenic_aic *ingenic_aic = dev_get_drvdata(aic); ++ ++ pr_info("AIC_FR\t\t%p : 0x%08x\n", (ingenic_aic->vaddr_base+AICFR),ingenic_aic_read_reg(aic, AICFR)); ++ pr_info("AIC_CR\t\t%p : 0x%08x\n", (ingenic_aic->vaddr_base+AICCR),ingenic_aic_read_reg(aic, AICCR)); ++ pr_info("AIC_SPCTRL\t%p : 0x%08x\n",(ingenic_aic->vaddr_base+SPCTRL),ingenic_aic_read_reg(aic, SPCTRL)); ++ pr_info("AIC_SR\t\t%p : 0x%08x\n", (ingenic_aic->vaddr_base+AICSR),ingenic_aic_read_reg(aic, AICSR)); ++ pr_info("AIC_SPSTATE\t%p : 0x%08x\n",(ingenic_aic->vaddr_base+SPSTATE),ingenic_aic_read_reg(aic, SPSTATE)); ++ pr_info("AIC_SPCFG1\t%p : 0x%08x\n",(ingenic_aic->vaddr_base+SPCFG1),ingenic_aic_read_reg(aic, SPCFG1)); ++ pr_info("AIC_SPCFG2\t%p : 0x%08x\n",(ingenic_aic->vaddr_base+SPCFG2),ingenic_aic_read_reg(aic, SPCFG2)); ++ return; ++} ++ ++static int ingenic_spdif_startup(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct ingenic_spdif *ingenic_spdif = dev_get_drvdata(dai->dev); ++ struct device *aic = ingenic_spdif->aic; ++ enum aic_mode work_mode = AIC_SPDIF_MODE; ++ ++ spdif_DEBUG_MSG("enter %s, substream = %s\n", ++ __func__, ++ (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? "playback" : "capture"); ++ work_mode = aic_set_work_mode(aic, work_mode, true); ++ if (work_mode != AIC_SPDIF_MODE) { ++ dev_warn(ingenic_spdif->aic, "Aic now is working on %s mode, open spdif mode failed\n", ++ aic_work_mode_str(work_mode)); ++ return -EPERM; ++ } ++ printk("start set AIC register....\n"); ++ return 0; ++} ++ ++static unsigned long spdif_select_ori_sample_freq(struct device *aic,unsigned long sync) ++{ ++ int div = 0; ++ switch(sync) { ++ case 8000: div = 0x6; ++ break; ++ case 11025: div = 0xa; ++ break; ++ case 16000: div = 0x8; ++ break; ++ case 22050: div = 0xb; ++ break; ++ case 24000: div = 0x9; ++ break; ++ case 32000: div = 0xc; ++ break; ++ case 44100: div = 0xf; ++ break; ++ case 48000: div = 0xd; ++ break; ++ case 96000: div = 0x5; ++ break; ++ case 192000: div = 0x1; ++ break; ++ default : ++ div = 0xf; ++ break; ++ } ++ __spdif_set_ori_sample_freq(aic,div); ++ return div; ++} ++ ++static unsigned long spdif_select_sample_freq(struct device* aic,unsigned long sync) ++{ ++ int div = 0; ++ switch(sync) { ++ case 8000: div = 0x9; ++ break; ++ case 11025: div = 0x5; ++ break; ++ case 16000: div = 0x7; ++ break; ++ case 22050: div = 0x4; ++ break; ++ case 24000: div = 0x6; ++ break; ++ case 32000: div = 0x3; ++ break; ++ case 44100: div = 0x0; ++ break; ++ case 48000: div = 0x2; ++ break; ++ case 96000: div = 0xa; ++ break; ++ case 192000: div = 0xe; ++ break; ++ default : ++ div = 0; ++ break; ++ } ++ __spdif_set_sample_freq(aic,div); ++ return div; ++} ++static int ingenic_spdif_set_rate(struct device *aic ,struct ingenic_aic* ingenic_aic, unsigned long sample_rate){ ++ struct clk* cgu_aic_clk = ingenic_aic->clk; ++ ++ __i2s_stop_bitclk(aic); ++ clk_set_rate(cgu_aic_clk, sample_rate); ++ writel(0xa,(volatile void *)I2S_CPM_VALID); ++ __i2s_start_bitclk(aic); ++ spdif_select_ori_sample_freq(aic,sample_rate); ++ spdif_select_sample_freq(aic,sample_rate); ++ ++ return sample_rate; ++} ++ ++static int ingenic_spdif_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) ++{ ++ int channels = params_channels(params); ++ int fmt_width = snd_pcm_format_width(params_format(params)); ++ struct ingenic_spdif *ingenic_spdif = dev_get_drvdata(dai->dev); ++ struct device *aic = ingenic_spdif->aic; ++ struct ingenic_aic *ingenic_aic = dev_get_drvdata(aic); ++ enum dma_slave_buswidth buswidth; ++ int trigger; ++ unsigned long sample_rate = params_rate(params); ++ unsigned long tmp_rate = 0; ++ ++ spdif_DEBUG_MSG("enter %s, substream = %s\n", __func__, ++ (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? "playback" : "capture"); ++ ++ if (!((1 << params_format(params)) & INGENIC_SPDIF_FORMATS) || channels > 2) { ++ dev_err(dai->dev, "hw params not inval channel %d params %x\n", ++ channels, params_format(params)); ++ return -EINVAL; ++ } ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ __i2s_channel(aic, channels); ++ /* format */ ++ if (fmt_width == 16){ ++ buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; ++ __spdif_set_max_wl(aic,0); ++ __spdif_set_sample_size(aic,1); ++ }else if(fmt_width == 24){ ++ buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; ++ __spdif_set_max_wl(aic,1); ++ __spdif_set_sample_size(aic,5); ++ }else{ ++ return -EINVAL; ++ } ++ ++ ingenic_spdif->playback_dma_data.addr_width = buswidth; ++ ingenic_spdif->playback_dma_data.maxburst = (SPDIF_TFIFO_DEPTH * buswidth)/2; ++ trigger = SPDIF_TFIFO_DEPTH - (ingenic_spdif->playback_dma_data.maxburst/(int)buswidth); ++// __i2s_set_transmit_trigger(aic,trigger/2); ++ __spdif_set_trigger(aic, 3); ++// snd_soc_dai_set_dma_data(dai, substream, (void *)&ingenic_spdif->playback_dma_data); ++ ++ } else { ++ printk("spdif is not a capture device!\n"); ++ return -EINVAL; ++ } ++ ++ /* sample rate */ ++ tmp_rate = ingenic_spdif_set_rate(aic,ingenic_aic,sample_rate); ++ if(tmp_rate < 0) ++ printk("set spdif clk failed!!\n"); ++ /* signed transfer */ ++ if(snd_pcm_format_signed(params_format(params))) ++ __spdif_clear_signn(aic); ++ else ++ __spdif_set_signn(aic); ++ return 0; ++} ++ ++static int ingenic_spdif_start_substream(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct ingenic_spdif *ingenic_spdif = dev_get_drvdata(dai->dev); ++ struct device *aic = ingenic_spdif->aic; ++ int rst_test = 0xfff; ++ spdif_DEBUG_MSG("enter %s, substream = %s\n", ++ __func__, ++ (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? "playback" : "capture"); ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ __spdif_reset(aic); ++ while(__spdif_get_reset(aic)) { ++ if (rst_test-- <= 0){ ++ printk("spdif rst err\n"); ++ return -EINVAL; ++ } ++ } ++ __spdif_enable_transmit_dma(aic); ++ __spdif_clear_underrun(aic); ++ __spdif_enable(aic); ++ __aic_enable(aic); ++ } else { ++ printk("spdif is not a capture device!\n"); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static int ingenic_spdif_stop_substream(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct ingenic_spdif *ingenic_spdif = dev_get_drvdata(dai->dev); ++ struct device *aic = ingenic_spdif->aic; ++ spdif_DEBUG_MSG("enter %s, substream = %s\n", ++ __func__, ++ (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? "playback" : "capture"); ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ if (ingenic_spdif_debug) __aic_dis_tur_int(aic); ++ if (__spdif_is_enable_transmit_dma(aic)) { ++ __spdif_disable_transmit_dma(aic); ++ __spdif_clear_underrun(aic); ++ /*hrtime mode: stop will be happen in any where, make sure there is ++ * no data transfer on ahb bus before stop dma ++ */ ++ while(!__spdif_test_underrun(aic)); ++ } ++ __spdif_disable(aic); ++ __spdif_clear_underrun(aic); ++ } else { ++ printk("spdif is not a capture device!\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int ingenic_spdif_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) ++{ ++ struct ingenic_pcm_runtime_data *prtd = substream->runtime->private_data; ++ spdif_DEBUG_MSG("enter %s, substream = %s cmd = %d\n", ++ __func__, ++ (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? "playback" : "capture", ++ cmd); ++ ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ case SNDRV_PCM_TRIGGER_RESUME: ++ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: ++ if (atomic_read(&prtd->wait_stopdma)) ++ return -EPIPE; ++ if(ingenic_spdif_start_substream(substream, dai)) ++ return -EINVAL; ++ break; ++ case SNDRV_PCM_TRIGGER_STOP: ++ case SNDRV_PCM_TRIGGER_SUSPEND: ++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ++ if (atomic_read(&prtd->wait_stopdma)) ++ return 0; ++ ingenic_spdif_stop_substream(substream, dai); ++ break; ++ } ++ /*dump_registers(aic);*/ ++ return 0; ++} ++ ++static void ingenic_spdif_shutdown(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) { ++ struct ingenic_spdif *ingenic_spdif = dev_get_drvdata(dai->dev); ++ struct device *aic = ingenic_spdif->aic; ++ enum aic_mode work_mode = AIC_SPDIF_MODE; ++ ++ spdif_DEBUG_MSG("enter %s, substream = %s\n", ++ __func__,(substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? "playback" : "capture"); ++ work_mode = aic_set_work_mode(ingenic_spdif->aic, work_mode, false); ++ BUG_ON((work_mode != AIC_NO_MODE)); ++ ingenic_spdif_stop_substream(substream, dai); ++ __aic_disable(aic); ++ return; ++} ++ ++static int ingenic_spdif_probe(struct snd_soc_dai *dai) ++{ ++ struct ingenic_spdif *ingenic_spdif = dev_get_drvdata(dai->dev); ++ struct device *aic = ingenic_spdif->aic; ++ unsigned int reg_tmp; ++ snd_soc_dai_init_dma_data(dai, &ingenic_spdif->playback_dma_data, NULL); ++ ++ spdif_DEBUG_MSG("enter %s\n", __func__); ++ ++ ++ __i2s_disable_transmit_dma(aic); ++ __i2s_disable_receive_dma(aic); ++ __i2s_disable_replay(aic); ++ __i2s_disable_record(aic); ++ __i2s_disable_loopback(aic); ++ __aic_disable(aic); ++ ++ ++ reg_tmp = ingenic_aic_read_reg(aic, SPCTRL); ++ reg_tmp |= (SPCTRL_SPDIF_I2S_MASK | SPCTRL_M_TRIG_MASK | ++ SPCTRL_M_FFUR_MASK | SPCTRL_INVALID_MASK); ++ ingenic_aic_write_reg(aic, SPCTRL, reg_tmp); ++ ++ __i2s_stop_bitclk(aic); ++ __i2s_external_codec(aic); ++ __i2s_bclk_output(aic); ++ __i2s_sync_output(aic); ++ __aic_select_i2s(aic); ++ __i2s_send_rfirst(aic); ++ ++ __spdif_set_dtype(aic,0); ++ __spdif_set_ch1num(aic,0); ++ __spdif_set_ch2num(aic,1); ++ __spdif_set_srcnum(aic,0); ++ ++ __interface_select_spdif(aic); ++ __spdif_play_lastsample(aic); ++ __spdif_init_set_low(aic); ++ __spdif_choose_consumer(aic); ++ __spdif_clear_audion(aic); ++ __spdif_set_copyn(aic); ++ __spdif_clear_pre(aic); ++ __spdif_choose_chmd(aic); ++ __spdif_set_category_code_normal(aic); ++ __spdif_set_clkacu(aic, 0); ++ __spdif_set_sample_size(aic, 1); ++ __spdif_set_valid(aic); ++ __spdif_mask_trig(aic); ++ __spdif_disable_underrun_intr(aic); ++ /*select spdif trans*/ ++ printk("spdif cpu dai prob ok\n"); ++ ++ return 0; ++} ++ ++ ++static struct snd_soc_dai_ops ingenic_spdif_dai_ops = { ++ .startup = ingenic_spdif_startup, ++ .trigger = ingenic_spdif_trigger, ++ .hw_params = ingenic_spdif_hw_params, ++ .shutdown = ingenic_spdif_shutdown, ++}; ++ ++#define ingenic_spdif_suspend NULL ++#define ingenic_spdif_resume NULL ++static struct snd_soc_dai_driver ingenic_spdif_dai = { ++ .probe = ingenic_spdif_probe, ++ .suspend = ingenic_spdif_suspend, ++ .resume = ingenic_spdif_resume, ++ .playback = { ++ .channels_min = 1, ++ .channels_max = 2, ++ .rates = INGENIC_SPDIF_RATE, ++ .formats = INGENIC_SPDIF_FORMATS, ++ }, ++ .ops = &ingenic_spdif_dai_ops, ++}; ++ ++static ssize_t ingenic_spdif_regs_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct ingenic_spdif *ingenic_spdif = dev_get_drvdata(dev); ++ dump_registers(ingenic_spdif->aic); ++ return 0; ++} ++ ++static struct device_attribute ingenic_spdif_sysfs_attrs[] = { ++ __ATTR(spdif_regs, S_IRUGO, ingenic_spdif_regs_show, NULL), ++}; ++ ++static const struct snd_soc_component_driver ingenic_spdif_component = { ++ .name = "aic-spdif", ++}; ++ ++static int ingenic_spdif_platfrom_probe(struct platform_device *pdev){ ++// struct ingenic_aic_subdev_pdata *pdata = dev_get_platdata(&pdev->dev); ++ struct device_node *parent = of_get_parent(pdev->dev.of_node); ++ struct resource res; ++ struct ingenic_spdif *ingenic_spdif; ++ int i = 0, ret; ++ ++ if (!parent) ++ return -ENOMEM; ++ ret = of_address_to_resource(parent, 0, &res); ++ if (ret) ++ return ret; ++ ++ ingenic_spdif = devm_kzalloc(&pdev->dev, sizeof(struct ingenic_spdif), GFP_KERNEL); ++ if (!ingenic_spdif) ++ return -ENOMEM; ++ ++ ingenic_spdif->aic = pdev->dev.parent; ++ ++ ingenic_spdif->playback_dma_data.addr = res.start + SPFIFO; ++ platform_set_drvdata(pdev, (void *)ingenic_spdif); ++ ++ for (; i < ARRAY_SIZE(ingenic_spdif_sysfs_attrs); i++) { ++ ret = device_create_file(&pdev->dev, &ingenic_spdif_sysfs_attrs[i]); ++ if (ret) ++ dev_warn(&pdev->dev,"attribute %s create failed %x", ++ ingenic_spdif_sysfs_attrs[i].attr.name, ret); ++ } ++ ret = snd_soc_register_component(&pdev->dev, &ingenic_spdif_component, ++ &ingenic_spdif_dai, 1); ++ if (!ret) ++ dev_dbg(&pdev->dev, "spdif platform probe success\n"); ++ return ret; ++} ++ ++static int ingenic_spdif_platfom_remove(struct platform_device *pdev) ++{ ++ int i; ++ for (i = 0; i < ARRAY_SIZE(ingenic_spdif_sysfs_attrs); i++) ++ device_remove_file(&pdev->dev, &ingenic_spdif_sysfs_attrs[i]); ++ platform_set_drvdata(pdev, NULL); ++ snd_soc_unregister_component(&pdev->dev); ++ return 0; ++} ++static const struct of_device_id spdif_dt_match[] = { ++ { .compatible = "ingenic,spdif", .data = NULL }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, spdif_dt_match); ++static struct platform_driver ingenic_spdif_plat_driver = { ++ .probe = ingenic_spdif_platfrom_probe, ++ .remove = ingenic_spdif_platfom_remove, ++ .driver = { ++ .name = "ingenic-asoc-aic-spdif", ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(spdif_dt_match), ++ }, ++}; ++ ++module_platform_driver(ingenic_spdif_plat_driver); ++MODULE_AUTHOR("shicheng.cheng "); ++MODULE_DESCRIPTION("INGENIC AIC SPDIF SoC Interface"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:ingenic-aic-spdif"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_Makefile.patch new file mode 100644 index 00000000..7072daee --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_Makefile.patch @@ -0,0 +1,14 @@ +diff -drupN a/sound/soc/ingenic/as-v2/Makefile b/sound/soc/ingenic/as-v2/Makefile +--- a/sound/soc/ingenic/as-v2/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/as-v2/Makefile 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,10 @@ ++ccflags-$(CONFIG_SND_ASOC_INGENIC_DEBUG) += -DDEBUG ++ccflags-$(CONFIG_SND_ASOC_INGENIC_VERBOSE) += -DVERBOSE_DEBUG ++ ++snd-asoc-as-fe-objs := as-dma.o as-dsp.o as-mixer.o as-fmtcov.o ++snd-asoc-as-be-baic-objs := as-baic.o as-spdif.o as-dmic.o ++ ++obj-$(CONFIG_SND_ASOC_INGENIC_AS_FE) += snd-asoc-as-fe.o ++obj-$(CONFIG_SND_ASOC_INGENIC_AS_BAIC) += snd-asoc-as-be-baic.o ++ ++obj-$(CONFIG_SND_ASOC_INGENIC_AS_VIR_FE) += as-vir-fe.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-baic.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-baic.c.patch new file mode 100644 index 00000000..5698db12 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-baic.c.patch @@ -0,0 +1,703 @@ +diff -drupN a/sound/soc/ingenic/as-v2/as-baic.c b/sound/soc/ingenic/as-v2/as-baic.c +--- a/sound/soc/ingenic/as-v2/as-baic.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/as-v2/as-baic.c 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,699 @@ ++/* ++ * ALSA Soc Audio Layer -- ingenic as(audio system) baic(Basic Audio Inter- ++ * face Controller) driver ++ * ++ * Copyright 2017 - 2022 Ingenic Semiconductor Co.,Ltd ++ * cli ++ * ++ * 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. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "as-baic.h" ++ ++#ifdef DEBUG ++static int ingenic_baic_debug = 1; ++#else ++static int ingenic_baic_debug = 0; ++#endif ++module_param(ingenic_baic_debug, int, 0644); ++#define BAIC_DEBUG_MSG(msg...) \ ++ do { \ ++ if (ingenic_baic_debug) \ ++ printk(KERN_DEBUG"BAIC: " msg); \ ++ } while(0) ++ ++static int ingenic_baic_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) ++{ ++ struct ingenic_baic *baic = dev_get_drvdata(dai->dev); ++ int id = dai->driver->id; ++ struct ingenic_baic_dai *idai = &baic->dai[id]; ++ u32 baic_cfg = 0; ++ u16 select_mode = 0; ++ bool frame_master = false; ++ ++ BAIC_DEBUG_MSG("enter [BAIC%d] %s dai fmt %x\n", id, __func__, fmt); ++ ++ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { ++ case SND_SOC_DAIFMT_NB_NF: ++ break; ++ case SND_SOC_DAIFMT_NB_IF: ++ baic_cfg |= BAICCFG_ISYNC; ++ break; ++ case SND_SOC_DAIFMT_IB_NF: ++ baic_cfg |= BAICCFG_NEG; ++ break; ++ case SND_SOC_DAIFMT_IB_IF: ++ baic_cfg |= BAICCFG_ISYNC | BAICCFG_NEG; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { ++ case SND_SOC_DAIFMT_I2S: /*i2s format*/ ++ if (!(idai->support_mode & BAIC_DAIFMT_I2S_GRP)) ++ return -EINVAL; ++ baic_cfg |= BAICCFG_MODE_I2S; ++ select_mode = BAIC_DAIFMT_I2S_GRP|BAIC_DAIFMT_I2S; ++ break; ++ case SND_SOC_DAIFMT_MSB: /*msb/left_j format*/ ++ if (!(idai->support_mode & BAIC_DAIFMT_I2S_GRP)) ++ return -EINVAL; ++ baic_cfg |= BAICCFG_MODE_LEFTJ; ++ select_mode = BAIC_DAIFMT_I2S_GRP|BAIC_DAIFMT_LEFTJ; ++ break; ++ case SND_SOC_DAIFMT_LSB: /*lsb/right_j format*/ ++ if (!(idai->support_mode & BAIC_DAIFMT_I2S_GRP)) ++ return -EINVAL; ++ baic_cfg |= BAICCFG_MODE_RIGHTJ; ++ select_mode = BAIC_DAIFMT_I2S_GRP|BAIC_DAIFMT_RIGHTJ; ++ break; ++ case SND_SOC_DAIFMT_DSP_A: /*TDM/PCM/DSP A*/ ++ if (!(idai->support_mode & BAIC_DAIFMT_DSP_GRP)) ++ return -EINVAL; ++ if (!(idai->support_mode & BAIC_DAIFMT_MODEA)) ++ return -EINVAL; ++ ++ if (idai->support_mode & BAIC_DAIFMT_TDM2) { ++ baic_cfg |= BAICCFG_MODE_TDM2A; ++ select_mode = BAIC_DAIFMT_TDM2|BAIC_DAIFMT_MODEA|BAIC_DAIFMT_DSP_GRP; ++ break; ++ } ++ ++ if (idai->support_mode & BAIC_DAIFMT_TDM1) { ++ baic_cfg |= BAICCFG_MODE_TDM1A; ++ select_mode = BAIC_DAIFMT_TDM1|BAIC_DAIFMT_MODEA|BAIC_DAIFMT_DSP_GRP; ++ break; ++ } ++ ++ if (idai->support_mode & BAIC_DAIFMT_DSP) { ++ baic_cfg |= BAICCFG_MODE_DSPA; ++ select_mode = BAIC_DAIFMT_DSP|BAIC_DAIFMT_MODEA|BAIC_DAIFMT_DSP_GRP; ++ break; ++ } ++ ++ if (idai->support_mode & BAIC_DAIFMT_PCM) { ++ baic_cfg |= BAICCFG_MODE_PCMA; ++ select_mode = BAIC_DAIFMT_PCM|BAIC_DAIFMT_MODEA|BAIC_DAIFMT_DSP_GRP; ++ break; ++ } ++ return -EINVAL; ++ case SND_SOC_DAIFMT_DSP_B: /*TDM/PCM/DSP B*/ ++ if (!(idai->support_mode & BAIC_DAIFMT_DSP_GRP)) ++ return -EINVAL; ++ ++ if (!(idai->support_mode & BAIC_DAIFMT_MODEB)) ++ return -EINVAL; ++ ++ if (idai->support_mode & BAIC_DAIFMT_TDM2) { ++ baic_cfg |= BAICCFG_MODE_TDM2B; ++ select_mode = BAIC_DAIFMT_TDM2|BAIC_DAIFMT_MODEB|BAIC_DAIFMT_DSP_GRP; ++ break; ++ } ++ ++ if (idai->support_mode & BAIC_DAIFMT_TDM1) { ++ baic_cfg |= BAICCFG_MODE_TDM1B; ++ select_mode = BAIC_DAIFMT_TDM1|BAIC_DAIFMT_MODEB|BAIC_DAIFMT_DSP_GRP; ++ break; ++ } ++ ++ if (idai->support_mode & BAIC_DAIFMT_DSP) { ++ baic_cfg |= BAICCFG_MODE_DSPB; ++ select_mode = BAIC_DAIFMT_DSP|BAIC_DAIFMT_MODEB|BAIC_DAIFMT_DSP_GRP; ++ break; ++ } ++ ++ if (idai->support_mode & BAIC_DAIFMT_PCM) { ++ baic_cfg |= BAICCFG_MODE_PCMB; ++ select_mode = BAIC_DAIFMT_PCM|BAIC_DAIFMT_MODEB|BAIC_DAIFMT_DSP_GRP; ++ break; ++ } ++ default: ++ pr_err("%s:%d\n", __func__, __LINE__); ++ return -EINVAL; ++ } ++ ++ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { ++ case SND_SOC_DAIFMT_CBM_CFM: ++ break; ++ case SND_SOC_DAIFMT_CBS_CFS: /*codec frame slave */ ++ baic_cfg |= BAICCFG_MASTER; ++ frame_master = true; ++ break; ++ default: ++ pr_err("%s:%d\n", __func__, __LINE__); ++ return -EINVAL; ++ } ++ ++ if (fmt & BAIC_DAIFMT_R) { ++ idai->baic_rcfg = baic_cfg; ++ idai->select_rmode = select_mode; ++ idai->frame_rmaster = frame_master; ++ } else if (fmt & BAIC_DAIFMT_T) { ++ idai->baic_tcfg = baic_cfg; ++ idai->select_tmode = select_mode; ++ idai->frame_tmaster = frame_master; ++ } else { ++ idai->baic_rcfg = baic_cfg; ++ idai->baic_tcfg = baic_cfg; ++ idai->select_rmode = select_mode; ++ idai->select_tmode = select_mode; ++ idai->frame_tmaster = frame_master; ++ idai->frame_rmaster = frame_master; ++ } ++ ++ return 0; ++} ++ ++static int ingenic_baic_set_tdm_slot(struct snd_soc_dai *dai, ++ unsigned int tx_mask, unsigned int rx_mask, ++ int slots, int slot_width) ++{ ++ struct ingenic_baic *baic = dev_get_drvdata(dai->dev); ++ int id = dai->driver->id; ++ struct ingenic_baic_dai *idai = &baic->dai[id]; ++ int baic_cfg = 0, baic_msk = 0; ++ ++ if (!slots) ++ return 0; ++ if (!(idai->support_mode & (BAIC_DAIFMT_TDM2|BAIC_DAIFMT_TDM1|BAIC_DAIFMT_DSP))) ++ goto error; ++ if (!(idai->select_tmode & (BAIC_DAIFMT_TDM2|BAIC_DAIFMT_TDM1|BAIC_DAIFMT_DSP)) && tx_mask) ++ goto error; ++ if (!(idai->select_rmode & (BAIC_DAIFMT_TDM2|BAIC_DAIFMT_TDM1|BAIC_DAIFMT_DSP)) && rx_mask) ++ goto error; ++ ++ baic_cfg = BAICCFG_SLOT(slots)|BAICCFG_SLS(slot_width); ++ baic_msk = BAICCFG_SLOT_MSK|BAICCFG_SLS_MSK; ++ ++ if (tx_mask) { ++ idai->baic_tcfg &= ~baic_msk; ++ idai->baic_tcfg |= baic_cfg; ++ } ++ if (rx_mask) { ++ idai->baic_rcfg &= ~baic_msk; ++ idai->baic_rcfg |= baic_cfg; ++ } ++ return 0; ++error: ++ pr_err("%s:%d\n", __func__, __LINE__); ++ return -EINVAL; ++} ++ ++static int ingenic_baic_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div) ++{ ++ struct ingenic_baic *baic = dev_get_drvdata(dai->dev); ++ int id = dai->driver->id; ++ struct ingenic_baic_dai *idai = &baic->dai[id]; ++ struct ingenic_baic_div *idiv = (div_id & DIVID_DIR_T) ? &idai->tdiv.v : &idai->rdiv.v; ++ u16 select_mode = (div_id & DIVID_DIR_T) ? idai->select_tmode : idai->select_rmode; ++ u16 *bclk_ratio = (div_id & DIVID_DIR_T) ? &idai->bclk_tratio : &idai->bclk_rratio; ++ bool frame_master = (div_id & DIVID_DIR_T) ? idai->frame_tmaster : idai->frame_rmaster; ++ ++ if (!frame_master) ++ return 0; ++ ++ switch (div_id & DIVID_MSK) { ++ case DIVID_SYNC_W: ++ idiv->synl = (BAICDIV_SYNL(div) >> BAICDIV_SYNL_SFT); ++ break; ++ case DIVID_BCLK: ++ idiv->bclkdiv = (BAICDIV_BCLKDIV(div) >> BAICDIV_BCLKDIV_SFT); ++ break; ++ case DIVID_SYNC: ++ if (select_mode & BAIC_DAIFMT_I2S_GRP) ++ idiv->sync_div = BAICDIV_SYNLDIV_I2S(div) >> BAICDIV_SYNLDIV_SFT; ++ else ++ idiv->sync_div = BAICDIV_SYNLDIV_DSP(div) >> BAICDIV_SYNLDIV_SFT; ++ *bclk_ratio = div; ++ break; ++ default: ++ pr_err("%s:%d\n", __func__, __LINE__); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int ingenic_baic_set_sysclk(struct snd_soc_dai *dai, int clk_id, ++ unsigned int freq, int dir) ++{ ++ struct ingenic_baic *baic = dev_get_drvdata(dai->dev); ++ int id = dai->driver->id; ++ struct ingenic_baic_dai *idai = &baic->dai[id]; ++ ++ BAIC_DEBUG_MSG("enter [BAIC%d] %s clk_id %d req %d clk dir %d\n", id, __func__, ++ clk_id, freq, dir); ++ switch (clk_id) { ++ case CLKID_INNER_CODEC: ++ regmap_write(baic->regmap, BAICTLCR(id), BAICTLCR_ICDC); ++ break; ++ case CLKID_SYSCLK: ++ idai->tsysclk = freq; ++ idai->rsysclk = freq; ++ regmap_write(baic->regmap, BAICTLCR(id), ++ idai->split_data_pin ? BAICTLCR_CLK_SPLIT_EN : 0); ++ break; ++ case CLKID_SYSCLK_R: ++ idai->rsysclk = freq; ++ regmap_write(baic->regmap, BAICTLCR(id), ++ idai->split_data_pin ? BAICTLCR_CLK_SPLIT_EN : 0); ++ break; ++ case CLKID_SYSCLK_T: ++ idai->tsysclk = freq; ++ regmap_write(baic->regmap, BAICTLCR(id), ++ idai->split_data_pin ? BAICTLCR_CLK_SPLIT_EN : 0); ++ break; ++ default: ++ pr_err("%s:%d\n", __func__, __LINE__); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static bool ingenic_baic_fmt_check(u16 select_mode, int stream, ++ int fmt_width, int channels, int pin_num) ++{ ++ if (select_mode & BAIC_DAIFMT_I2S_GRP) { ++ if (channels != 1 && ((pin_num * 2) % channels)) ++ return false; ++ if (channels == 1 && stream == SNDRV_PCM_STREAM_CAPTURE) ++ return false; ++ return true; ++ } ++ if (!(select_mode & BAIC_DAIFMT_DSP_GRP)) ++ return false; ++ ++ ++ if (select_mode & BAIC_DAIFMT_TDM1) { ++ if (channels > 8 || (channels != 1 && (channels % 2))) ++ return false; ++ if (fmt_width % 8) ++ return false; ++ return true; ++ } ++ ++ if (select_mode & BAIC_DAIFMT_TDM2) { ++ if (channels != 8) ++ return false; ++ if (fmt_width % 8) ++ return false; ++ return true; ++ } ++ ++ ++ if (select_mode & BAIC_DAIFMT_PCM) { ++ if (channels != 1) ++ return false; ++ switch (fmt_width) { ++ case 8: case 16: case 32: return true; ++ default: ++ return false; ++ } ++ } ++ ++ if (select_mode & BAIC_DAIFMT_DSP) { ++ if (channels != 1 && channels != 2) ++ return false; ++ switch (fmt_width) { ++ case 8: case 16: case 32: return true; ++ default: ++ return false; ++ } ++ } ++ return false; ++} ++ ++static int ingenic_baic_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) ++{ ++ int channels = params_channels(params); ++ int rate = params_rate(params); ++ int fmt_width = snd_pcm_format_width(params_format(params)); ++ struct ingenic_baic *baic = dev_get_drvdata(dai->dev); ++ int id = dai->driver->id; ++ struct ingenic_baic_dai *idai = &baic->dai[id]; ++ unsigned int cfgreg = BAICTCFG(id), divreg = BAICTDIV(id); ++ bool is_out = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? true : false; ++ struct ingenic_baic_div *idiv = is_out ? &idai->tdiv.v : &idai->rdiv.v; ++ u32 *baic_cfg = is_out ? &idai->baic_tcfg : &idai->baic_rcfg; ++ u16 select_mode = is_out ? idai->select_tmode : idai->select_rmode; ++ u16 bclk_ratio = is_out ? idai->bclk_tratio : idai->bclk_rratio; ++ u32 sysclk = is_out ? idai->rsysclk : idai->tsysclk; ++ bool frame_master = is_out ? idai->frame_tmaster : idai->frame_rmaster; ++ ++ BAIC_DEBUG_MSG("enter [BAIC%d] %s, substream = %s, channels %d, rate %d, fmt_width %d\n", ++ id, __func__, (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? "playback" : "capture", ++ channels, rate, fmt_width); ++ ++ if (!ingenic_baic_fmt_check(select_mode, substream->stream, ++ fmt_width, channels, idai->data_pin_num)) ++ return -EINVAL; ++ ++ if ((select_mode & BAIC_DAIFMT_I2S_GRP)) { ++ (*baic_cfg) &= ~BAICCFG_CHANNEL_MSK; ++ (*baic_cfg) |= BAICCFG_CHANNEL(channels); ++ } else if (select_mode & BAIC_DAIFMT_TDM2) { ++ (*baic_cfg) &= ~BAICCFG_CHANNEL_MSK; ++ (*baic_cfg) |= BAICCFG_CHANNEL(4); ++ } ++ (*baic_cfg) &= ~BAICCFG_SS_MSK; ++ (*baic_cfg) |= BAICCFG_SS(fmt_width); ++ ++ if (idai->split_data_pin && !is_out) { ++ cfgreg = BAICRCFG(id); ++ divreg = BAICRDIV(id); ++ } ++ ++ regmap_write(baic->regmap, cfgreg, *baic_cfg); ++ ++ if (!frame_master) ++ return 0; ++ ++ if (!idiv->bclkdiv) { ++ int bclk, div; ++ bclk = rate * bclk_ratio; ++ div = ((sysclk + bclk - 1) / bclk) & (~0x1UL); ++ idiv->bclkdiv = BAICDIV_BCLKDIV(div) >> BAICDIV_BCLKDIV_SFT; ++ } ++ regmap_write(baic->regmap, divreg, is_out ? idai->tdiv.r: idai->rdiv.r); ++ ++ return 0; ++} ++ ++static int ingenic_baic_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) ++{ ++ struct ingenic_baic *baic = dev_get_drvdata(dai->dev); ++ int id = dai->driver->id; ++ ++ BAIC_DEBUG_MSG("enter [BAIC%d] %s, substream = %s cmd = %d\n", id, __func__, ++ (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? "playback" : "capture", ++ cmd); ++ ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ case SNDRV_PCM_TRIGGER_RESUME: ++ BAIC_DEBUG_MSG("baic start\n"); ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ regmap_update_bits(baic->regmap, BAICCCR(id), BAICCCR_TEN, BAICCCR_TEN); ++ else ++ regmap_update_bits(baic->regmap, BAICCCR(id), BAICCCR_REN, BAICCCR_REN); ++ break; ++ case SNDRV_PCM_TRIGGER_STOP: ++ case SNDRV_PCM_TRIGGER_SUSPEND: ++ BAIC_DEBUG_MSG("baic stop\n"); ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ regmap_update_bits(baic->regmap, BAICCCR(id), BAICCCR_TEN, 0); ++ else ++ regmap_update_bits(baic->regmap, BAICCCR(id), BAICCCR_REN, 0); ++ break; ++ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: ++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ++ BAIC_DEBUG_MSG("baic pause\n"); ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ regmap_update_bits(baic->regmap, BAICTCFG(id), BAICCFG_T_PAUSE, BAICCFG_T_PAUSE); ++ regmap_update_bits(baic->regmap, BAICCCR(id), BAICCCR_TEN, 0); ++ } ++ break; ++ } ++ return 0; ++} ++ ++static struct snd_soc_dai_ops ingenic_baic_dai_ops = { ++ .trigger = ingenic_baic_trigger, ++ .hw_params = ingenic_baic_hw_params, ++ .set_fmt = ingenic_baic_set_dai_fmt, ++ .set_sysclk = ingenic_baic_set_sysclk, ++ .set_clkdiv = ingenic_baic_set_clkdiv, ++ .set_tdm_slot = ingenic_baic_set_tdm_slot, ++}; ++ ++#define ingenic_baic_suspend NULL ++#define ingenic_baic_resume NULL ++ ++static const struct snd_soc_component_driver ingenic_baic_component = { ++ .name = "aic-baic", ++}; ++ ++#define INGENIC_BAIC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | \ ++ SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \ ++ SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE | \ ++ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE | \ ++ SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_U24_BE | \ ++ SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE | \ ++ SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE) ++ ++static char *dai_name[] = { ++ "BAIC0", ++ "BAIC1", ++ "BAIC2", ++ "BAIC3", ++ "BAIC4", ++}; ++ ++static char *pname[] = { ++ "BAIC0 playback", ++ "BAIC1 playback", ++ "BAIC2 playback", ++ "BAIC3 playback", ++ "BAIC4 playback", ++}; ++ ++static char *cname[] = { ++ "BAIC0 capture", ++ "BAIC1 capture", ++ "BAIC2 capture", ++ "BAIC3 capture", ++ "BAIC4 capture", ++}; ++ ++static bool ingenic_baic_vailed_reg(struct device *dev, unsigned int reg) ++{ ++ if (unlikely(reg%BAICOFF > BAICMAX)) ++ return false; ++ return true; ++} ++ ++static void ingenic_baic_set_func(struct ingenic_baic *baic, int i) ++{ ++ u16 mode = baic->dai[i].support_mode; ++ ++ if (mode & BAIC_NO_REPLAY) ++ baic->dai_driver[i].capture.stream_name = cname[i]; ++ else if (mode & BAIC_NO_RECORD) ++ baic->dai_driver[i].playback.stream_name = pname[i]; ++ else { ++ baic->dai_driver[i].capture.stream_name = cname[i]; ++ baic->dai_driver[i].playback.stream_name = pname[i]; ++ } ++} ++ ++const char *clk_name[] = { ++ "cgu_i2s0", ++ "cgu_i2s1", ++ "cgu_i2s2", ++ "cgu_i2s3", ++ "cgu_pcm", ++}; ++ ++const char *clk_gate_name[] = { ++ "gate_i2s0", ++ "gate_i2s1", ++ "gate_i2s2", ++ "gate_i2s3", ++ "gate_pcm", ++}; ++ ++static int ingenic_baic_set_clk_rate(struct ingenic_baic *baic, int i, unsigned long rate) ++{ ++ int ret = 0; ++ /* According To CPM: ++ * 0 - 3 use cgu_i2s0 - cgu_i2s3 ++ * 4 select one of cgu_i2s0 - cgu_i2s3 as is parent clk. ++ **/ ++ baic->dai[i].clk = devm_clk_get(baic->dev, clk_name[i]); ++ if(IS_ERR_OR_NULL(baic->dai[i].clk)) { ++ dev_err(baic->dev, "Failed to get clk: %s\n", clk_name[i]); ++ return -EINVAL; ++ } ++ ++ /* Setup PCM's Parent clk. fix to I2S2 */ ++ if(i == 4) { ++ struct clk *parent = devm_clk_get(baic->dev, clk_name[2]); ++ clk_set_parent(baic->dai[i].clk, parent); ++ devm_clk_put(baic->dev, parent); ++ } ++ ++ baic->dai[i].clk_gate = clk_get(baic->dev, clk_gate_name[i]); ++ if(IS_ERR_OR_NULL(baic->dai[i].clk_gate)) { ++ dev_err(baic->dev, "Failed to get clk_gate: %s\n", clk_gate_name[i]); ++ ret = -EINVAL; ++ goto err_gate; ++ } ++ clk_set_rate(baic->dai[i].clk, rate); ++ ++ clk_prepare_enable(baic->dai[i].clk_gate); ++ clk_prepare_enable(baic->dai[i].clk); ++ ++ return ret; ++err_gate: ++ devm_clk_put(baic->dev, baic->dai[i].clk); ++ return ret; ++} ++ ++static int ingenic_baic_platform_probe(struct platform_device *pdev) ++{ ++ struct ingenic_baic *baic; ++ struct resource *res; ++ int ret, i; ++ const __be32 *p; ++ struct property *prop; ++ u32 num_dais, tmp; ++ struct regmap_config regmap_config = { ++ .reg_bits = 32, ++ .reg_stride = 4, ++ .val_bits = 32, ++ .writeable_reg = ingenic_baic_vailed_reg, ++ .readable_reg = ingenic_baic_vailed_reg, ++ .cache_type = REGCACHE_NONE, ++ }; ++ ++ if (of_property_read_u32(pdev->dev.of_node, "ingenic,num-dais", &num_dais)) ++ num_dais = 1; ++ ++ baic = devm_kzalloc(&pdev->dev, sizeof(*baic) + ++ num_dais * sizeof(struct ingenic_baic_dai) + ++ num_dais * sizeof(struct snd_soc_dai_driver), GFP_KERNEL); ++ if (!baic) ++ return -ENOMEM; ++ ++ baic->dai = (struct ingenic_baic_dai *)(baic + 1); ++ baic->dai_driver = (struct snd_soc_dai_driver *)(baic->dai + num_dais); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ baic->io_base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(baic->io_base)) ++ return PTR_ERR(baic->io_base); ++ regmap_config.max_register = resource_size(res) - 0x4; ++ baic->regmap = devm_regmap_init_mmio(&pdev->dev, ++ baic->io_base, ++ ®map_config); ++ if (IS_ERR(baic->regmap)) ++ return PTR_ERR(baic->regmap); ++ baic->dev = &pdev->dev; ++ baic->num_dais = num_dais; ++ ++ i = 0; ++ of_property_for_each_u32(pdev->dev.of_node, "ingenic,dai-mode", prop, p, tmp) { ++ baic->dai[i++].support_mode = (u16)tmp; ++ if (i >= num_dais) ++ break; ++ } ++ ++ i = 0; ++ of_property_for_each_u32(pdev->dev.of_node, "ingenic,dai-pin-num", prop, p, tmp) { ++ if ((u8)tmp <= 1) ++ baic->dai[i].support_mode &= ~BAIC_DAIFMT_TDM2; ++ baic->dai[i++].data_pin_num = (u8)tmp; ++ if (i >= num_dais) ++ break; ++ } ++ ++ of_property_for_each_u32(pdev->dev.of_node, "ingenic,dai-pin-split", prop, p, tmp) { ++ if (tmp >= num_dais) ++ continue; ++ pr_debug("split dai id(%d)\n", tmp); ++ baic->dai[tmp].split_data_pin = true; ++ } ++ ++ for (i = 0; i < num_dais; i++) { ++ baic->dai_driver[i].id = i; ++ baic->dai_driver[i].name = dai_name[i]; ++ baic->dai_driver[i].suspend = ingenic_baic_suspend; ++ baic->dai_driver[i].resume = ingenic_baic_resume; ++ baic->dai_driver[i].ops = &ingenic_baic_dai_ops; ++ ingenic_baic_set_func(baic, i); ++ baic->dai_driver[i].symmetric_rates = baic->dai[i].split_data_pin ? 0 : 1; ++ baic->dai_driver[i].symmetric_channels = baic->dai[i].split_data_pin ? 0 : 1; ++ baic->dai_driver[i].symmetric_samplebits = baic->dai[i].split_data_pin ? 0 : 1; ++ ++ ingenic_baic_set_clk_rate(baic, i, 24000000); ++ } ++ ++ baic->audio_clk = devm_clk_get(baic->dev, "gate_audio"); ++ if(IS_ERR_OR_NULL(baic->audio_clk)) { ++ dev_err(baic->dev, "Failed to get gate_audio clk!\n"); ++ } ++ clk_prepare_enable(baic->audio_clk); ++ ++ ++ platform_set_drvdata(pdev, (void *)baic); ++ ++ ret = devm_snd_soc_register_component(&pdev->dev, &ingenic_baic_component, ++ baic->dai_driver, num_dais); ++ if (!ret) ++ dev_info(&pdev->dev, "baic platform probe success\n"); ++ ++ return ret; ++} ++ ++static int ingenic_baic_platform_remove(struct platform_device *pdev) ++{ ++ return 0; ++} ++ ++static const struct of_device_id ingenic_baic_match_table[] = { ++ { .compatible = "ingenic,as-baic", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, ingenic_baic_match_table); ++ ++#ifdef CONFIG_PM ++static int ingenic_baic_runtime_suspend(struct device *dev) ++{ ++ return 0; ++} ++ ++static int ingenic_baic_runtime_resume(struct device *dev) ++{ ++ return 0; ++} ++#endif ++ ++static const struct dev_pm_ops ingenic_baic_pm_ops = { ++ SET_RUNTIME_PM_OPS(ingenic_baic_runtime_suspend, ++ ingenic_baic_runtime_resume, NULL) ++}; ++ ++ ++static struct platform_driver ingenic_baic_platform_driver = { ++ .driver = { ++ .name = "as-baic", ++ .of_match_table = ingenic_baic_match_table, ++ .pm = &ingenic_baic_pm_ops, ++ }, ++ .probe = ingenic_baic_platform_probe, ++ .remove = ingenic_baic_platform_remove, ++}; ++module_platform_driver(ingenic_baic_platform_driver); ++ ++MODULE_AUTHOR("cli "); ++MODULE_DESCRIPTION("Ingenic AS BAIC SoC Interface"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:ingenic-as-baic"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-baic.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-baic.h.patch new file mode 100644 index 00000000..c1652841 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-baic.h.patch @@ -0,0 +1,167 @@ +diff -drupN a/sound/soc/ingenic/as-v2/as-baic.h b/sound/soc/ingenic/as-v2/as-baic.h +--- a/sound/soc/ingenic/as-v2/as-baic.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/as-v2/as-baic.h 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,163 @@ ++/* ++ * ALSA Soc Audio Layer -- Ingenic AS BAIC Controller ++ * ++ * Copyright 2017 - 2022 Ingenic Semiconductor Co.,Ltd ++ * cli ++ * ++ * 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. ++ */ ++#ifndef __AS_BAIC_H__ ++#define __AS_BAIC_H__ ++ ++#include ++#include ++ ++/*CLKID*/ ++#define CLKID_INNER_CODEC 0x1 ++#define CLKID_SYSCLK 0x2 ++#define CLKID_SYSCLK_T 0x3 ++#define CLKID_SYSCLK_R 0x4 ++ ++#define DIVID_DIR_T BIT(0) ++#define DIVID_SFT (1) ++#define DIVID_MSK GENMASK(2, DIVID_SFT) ++#define DIVID_SYNC_W (0x0 << DIVID_SFT) /*divided by bclk*/ ++#define DIVID_SYNC (0x1 << DIVID_SFT) /*divided by bclk*/ ++#define DIVID_BCLK (0x2 << DIVID_SFT) /*divided by sysclk*/ ++ ++#define BAIC_DAIFMT_T (0x1 << 16) ++#define BAIC_DAIFMT_R (0x2 << 16) ++#define BAIC_DAIFMT_DIR_MSK (0x3 << 16) ++ ++/*REGISTERS*/ ++#define BAICRCTL0 (0x0) ++#define BAICRCFG0 (0x4) ++#define BAICRDIV0 (0x8) ++#define BAICRCGR0 (0xc) ++#define BAICTCTL0 (0x10) ++#define BAICTCFG0 (0x14) ++#define BAICTDIV0 (0x18) ++#define BAICTCGR0 (0x1c) ++#define BAICTLCR0 (0x20) ++#define BAICCCR0 (0x24) ++#define BAICMAX BAICCCR0 ++ ++#define BAICOFF (0x1000) ++#define BAICRCTL(n) (BAICRCTL0 + BAICOFF * (n)) /*BAIC Receiver Control Register (BAICRCTL) description*/ ++#define BAICRCFG(n) (BAICRCFG0 + BAICOFF * (n)) /*BAIC Receiver Configuration Register (BAICRCFG) description*/ ++#define BAICRDIV(n) (BAICRDIV0 + BAICOFF * (n)) /*BAIC Receiver CLK divide register (BAICRDIV) description*/ ++#define BAICRCGR(n) (BAICRCGR0 + BAICOFF * (n)) /*BAIC Receiver CLK Gate Register (BAICRCGR) description(Unused)*/ ++ ++#define BAICTCTL(n) (BAICTCTL0 + BAICOFF * (n)) /*BAIC Transmitter Control Register (BAICTCTL) description*/ ++#define BAICTCFG(n) (BAICTCFG0 + BAICOFF * (n)) /*BAIC Transmitter Configuration Register (BAICTCFG) description*/ ++#define BAICTDIV(n) (BAICTDIV0 + BAICOFF * (n)) /*BAIC Transmitter CLK divide register (BAICTDIV) description*/ ++#define BAICTCGR(n) (BAICTCGR0 + BAICOFF * (n)) /*BAIC Transmitter CLK Gate Register (BAICTCGR) description*/ ++ ++#define BAICTLCR(n) (BAICTLCR0 + BAICOFF * (n)) /*BAIC Top Level Configure Register (BAICTLCR) description*/ ++#define BAICCCR(n) (BAICCCR0 + BAICOFF * (n)) /*BAIC Common Control Register (BAICCCR) description*/ ++ ++#define BAICCTR_RST BIT(0) ++ ++#define BAICCFG_T_PAUSE BIT(31) ++#define BAICCFG_SLOT_SFT (24) ++#define BAICCFG_SLOT_MSK GENMASK(27, BAICCFG_SLOT_SFT) ++#define BAICCFG_SLOT(slot) ((((slot) - 1) << BAICCFG_SLOT_SFT) & BAICCFG_SLOT_MSK) ++#define BAICCFG_SWLR BIT(20) ++#define BAICCFG_CHANNEL_SFT (17) ++#define BAICCFG_CHANNEL_MSK GENMASK(19, BAICCFG_CHANNEL_SFT) ++#define BAICCFG_CHANNEL(ch) ((((ch) >> 1) << BAICCFG_CHANNEL_SFT) & BAICCFG_CHANNEL_MSK) ++#define BAICCFG_SLS_SFT (13) ++#define BAICCFG_SLS_MSK GENMASK(14, BAICCFG_SLS_SFT) ++#define BAICCFG_SLS(sls) (((sls%16) ? 0 : (((sls) >> 5) + 1) << BAICCFG_SLS_SFT) & BAICCFG_SLS_MSK) ++#define BAICCFG_ISYNC BIT(12) ++#define BAICCFG_ASVTSU BIT(11) ++#define BAICCFG_SS_SFT (8) ++#define BAICCFG_SS_MSK GENMASK(10, BAICCFG_SS_SFT) ++#define BAICCFG_SS_8 (0 << BAICCFG_SS_SFT) ++#define BAICCFG_SS_12 (1 << BAICCFG_SS_SFT) ++#define BAICCFG_SS_13 (2 << BAICCFG_SS_SFT) ++#define BAICCFG_SS_16 (3 << BAICCFG_SS_SFT) ++#define BAICCFG_SS_18 (4 << BAICCFG_SS_SFT) ++#define BAICCFG_SS_20 (5 << BAICCFG_SS_SFT) ++#define BAICCFG_SS_24 (6 << BAICCFG_SS_SFT) ++#define BAICCFG_SS_32 (7 << BAICCFG_SS_SFT) ++#define BAICCFG_SS(ss) ((ss <= 8) ? BAICCFG_SS_8 : (ss <= 12) ? BAICCFG_SS_12 : (ss == 13) ? BAICCFG_SS_13 : (ss <= 16) ? BAICCFG_SS_16 : (ss <= 18) ? BAICCFG_SS_18 : (ss <= 20) ? BAICCFG_SS_20 : (ss <= 24) ? BAICCFG_SS_24: BAICCFG_SS_32) ++#define BAICCFG_MODE_SFT (2) ++#define BAICCFG_MODE_MSK GENMASK(5, BAICCFG_MODE_SFT) ++#define BAICCFG_MODE_PCMA (0 << BAICCFG_MODE_SFT) ++#define BAICCFG_MODE_PCMB (1 << BAICCFG_MODE_SFT) ++#define BAICCFG_MODE_DSPA (2 << BAICCFG_MODE_SFT) ++#define BAICCFG_MODE_DSPB (3 << BAICCFG_MODE_SFT) ++#define BAICCFG_MODE_I2S (4 << BAICCFG_MODE_SFT) ++#define BAICCFG_MODE_LEFTJ (5 << BAICCFG_MODE_SFT) ++#define BAICCFG_MODE_RIGHTJ (6 << BAICCFG_MODE_SFT) ++#define BAICCFG_MODE_TDM1A (8 << BAICCFG_MODE_SFT) /*one data pin*/ ++#define BAICCFG_MODE_TDM1B (9 << BAICCFG_MODE_SFT) ++#define BAICCFG_MODE_TDM2A (10 << BAICCFG_MODE_SFT) /*At most four data pin*/ ++#define BAICCFG_MODE_TDM2B (11 << BAICCFG_MODE_SFT) ++#define BAICCFG_NEG BIT(1) /*Use BCLK falling edge receive serial data Master mode*/ ++#define BAICCFG_MASTER BIT(0) ++ ++#define BAICDIV_BCLKDIV_SFT (16) /*BCLK = SYS_CLK / BCLKDIV*/ ++#define BAICDIV_BCLKDIV_MSK GENMASK(23, BAICDIV_BCLKDIV_SFT) ++#define BAICDIV_BCLKDIV(div) (((div) << BAICDIV_BCLKDIV_SFT) & BAICDIV_BCLKDIV_MSK) ++#define BAICDIV_SYNL_SFT (8) /*BAICSYN = ( SYNL + 1 ) * BCLK*/ ++#define BAICDIV_SYNL_MSK GENMASK(15, BAICDIV_SYNL_SFT) ++#define BAICDIV_SYNL(width) ((((width) - 1) << BAICDIV_SYNL_SFT) & BAICDIV_SYNL_MSK) ++#define BAICDIV_SYNLDIV_SFT (0) /*SYNC = BCLK/(8*(SYNCDIV+1))*/ ++#define BAICDIV_SYNLDIV_MSK GENMASK(7, BAICDIV_SYNLDIV_SFT) ++#define BAICDIV_SYNLDIV_I2S(div) (((((div)/16) - 1) << BAICDIV_SYNLDIV_SFT) & BAICDIV_SYNLDIV_MSK) ++#define BAICDIV_SYNLDIV_DSP(div) (((((div)/8) - 1) << BAICDIV_SYNLDIV_SFT) & BAICDIV_SYNLDIV_MSK) ++ ++#define BAICTLCR_ICDC BIT(1) ++#define BAICTLCR_CLK_SPLIT_EN BIT(0) ++ ++#define BAICCCR_TEN BIT(3) ++#define BAICCCR_REN BIT(2) ++ ++/*struct*/ ++struct ingenic_baic_div { ++ uint32_t sync_div:8; ++ uint32_t synl:8; ++ uint32_t bclkdiv:8; ++ uint32_t reserved24_31:8; ++} __attribute__ ((packed)); ++ ++struct ingenic_baic_dai { ++ u16 support_func; ++ u16 support_mode; ++ u8 data_pin_num; ++ bool split_data_pin; ++ bool frame_tmaster; ++ bool frame_rmaster; ++ u32 tsysclk; ++ u32 rsysclk; ++ u16 bclk_tratio; ++ u16 bclk_rratio; ++ u16 select_tmode; ++ u16 select_rmode; ++ u32 baic_tcfg; ++ u32 baic_rcfg; ++ union { ++ struct ingenic_baic_div v; ++ uint32_t r; ++ } rdiv, tdiv; ++ ++ struct clk *clk; ++ struct clk *clk_gate; ++}; ++ ++struct ingenic_baic { ++ struct device *dev; /*register access device*/ ++ struct regmap *regmap; ++ void * __iomem io_base; ++ int num_dais; ++ struct snd_soc_dai_driver *dai_driver; ++ struct ingenic_baic_dai *dai; ++ struct clk *audio_clk; ++}; ++ ++#endif /*__AS_BAIC_H__*/ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-dma.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-dma.c.patch new file mode 100644 index 00000000..d5fdd304 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-dma.c.patch @@ -0,0 +1,729 @@ +diff -drupN a/sound/soc/ingenic/as-v2/as-dma.c b/sound/soc/ingenic/as-v2/as-dma.c +--- a/sound/soc/ingenic/as-v2/as-dma.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/as-v2/as-dma.c 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,725 @@ ++/* ++ * ALSA Soc Audio Layer -- ingenic as(audio system) dma driver ++ * ++ * Copyright 2017 - 2022 Ingenic Semiconductor Co.,Ltd ++ * cli ++ * ++ * 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. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "as-dma.h" ++ ++#ifdef DEBUG ++static int ingenic_dma_debug = 1; ++#else ++static int ingenic_dma_debug = 0; ++#endif ++ ++module_param(ingenic_dma_debug, int, 0644); ++ ++#define DMA_DEBUG_MSG(msg...) \ ++ do { \ ++ if (ingenic_dma_debug) \ ++ printk(KERN_DEBUG"ADMA: " msg); \ ++ } while(0) ++ ++#ifdef VERBOSE_DEBUG ++#define DMA_DEBUG_VERBOSE_MSG(msg...) \ ++ do {\ ++ if (ingenic_dma_debug) \ ++ printk(KERN_DEBUG"ADMA: " msg); \ ++ } while(0) ++#else ++#define DMA_DEBUG_VERBOSE_MSG(msg...) {} ++#endif ++ ++int __attribute__((weak)) ingenic_as_fmtcov_cfg(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ return 0; ++} ++void __attribute__((weak)) ingenic_as_fmtcov_enable(u8 dai_id, bool enable){} ++ ++static const struct snd_pcm_hardware ingenic_as_dma_pcm_hardware = { ++ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | ++ SNDRV_PCM_INFO_MMAP_VALID), ++ .buffer_bytes_max = INGENIC_DMA_BUFFERSIZE_MAX, ++ .period_bytes_min = INGENIC_PERIODS_BYTES_MIN, ++ .period_bytes_max = (INGENIC_DMA_BUFFERSIZE_MAX / INGENIC_PERIODS_MIN), ++ .periods_min = INGENIC_PERIODS_MIN, ++ .periods_max = (INGENIC_DMA_BUFFERSIZE_MAX/INGENIC_PERIODS_BYTES_MIN), ++ .fifo_size = 0, ++ .formats = ~0ULL, ++}; ++ ++static snd_pcm_uframes_t ingenic_as_dma_pointer(struct snd_pcm_substream *substream) ++{ ++ struct ingenic_as_dma_runtime *prtd = substream_to_prtd(substream); ++ struct ingenic_as_dma *as_dma = prtd->as_dma; ++ dma_addr_t now; ++ ssize_t pos; ++ ++ if (likely(substream->runtime && substream->runtime->dma_addr)) { ++ now = readl_relaxed(as_dma->dma_base + DBA(prtd->dai_id)); ++ if (now) ++ pos = (ssize_t)(now - substream->runtime->dma_addr); ++ else ++ pos = 0; ++ } else { ++ WARN("%s: %s has no runtime\n", substream->name); ++ pos = 0; ++ } ++ DMA_DEBUG_VERBOSE_MSG("enter %s[dai%d substream = %s] pos = %x(%d)(now %x dma %x)\n", ++ __func__, prtd->dai_id, ++ (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? ++ "playback" : "capture", ++ pos, pos, now, substream->runtime->dma_addr); ++ if (pos >= snd_pcm_lib_buffer_bytes(substream)) ++ pos = 0; ++ return bytes_to_frames(substream->runtime, pos); ++} ++ ++static int ingenic_as_dma_period_bytes_quirk(struct snd_pcm_hw_params *params, ++ struct snd_pcm_hw_rule *rule) ++{ ++ struct snd_interval *iperiod_bytes = hw_param_interval(params, ++ SNDRV_PCM_HW_PARAM_PERIOD_BYTES); ++ struct snd_interval *iframe_bits = hw_param_interval(params, ++ SNDRV_PCM_HW_PARAM_FRAME_BITS); ++ int align_bytes = DCM_TSZ_MAX_WORD << 2; ++ int min_frame_bytes = iframe_bits->min >> 3; ++ int max_frame_bytes = iframe_bits->max >> 3; ++ int min_period_bytes = iperiod_bytes->min; ++ int max_period_bytes = iperiod_bytes->max; ++ int min_align_bytes, max_align_bytes; ++ struct snd_interval nperiod_bytes; ++ ++ snd_interval_any(&nperiod_bytes); ++ min_align_bytes = lcm(align_bytes, min_frame_bytes); ++ min_period_bytes = (min_period_bytes + min_align_bytes - 1) / min_align_bytes; ++ nperiod_bytes.min = min_period_bytes * min_align_bytes; ++ ++ max_align_bytes = lcm(align_bytes, max_frame_bytes); ++ max_period_bytes = max_period_bytes / max_align_bytes; ++ nperiod_bytes.max = max_period_bytes * max_align_bytes; ++ ++ DMA_DEBUG_MSG("==> %s %d : align_bytes = %d \n\ ++ frame_bytes.min (%d)\t\tframe_bytes.max (%d) \n\ ++ period_bytes.min [%d]\tperiod_bytes.max [%d] \n\ ++ nperiod_bytes.min [%d]\tnperiod_bytes.max [%d]\n", ++ __func__, __LINE__, align_bytes, ++ min_frame_bytes, max_frame_bytes, iperiod_bytes->min, ++ iperiod_bytes->max, nperiod_bytes.min, nperiod_bytes.max); ++ return snd_interval_refine(iperiod_bytes, &nperiod_bytes); ++} ++ ++static int ingenic_as_dma_open(struct snd_pcm_substream *substream) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ struct ingenic_as_dma *as_dma = snd_soc_platform_get_drvdata(rtd->platform); ++ struct ingenic_as_dma_runtime *prtd = NULL; ++ struct snd_pcm_hardware pcm_hardware = ingenic_as_dma_pcm_hardware; ++ int ret; ++ ++ DMA_DEBUG_MSG("enter %s[dai%d substream = %s], process is \"%s\" (pid %i)\n", ++ __func__, rtd->cpu_dai->id, ++ (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? ++ "playback" : "capture", current->comm, current->pid); ++ ++ prtd = kzalloc(sizeof(*prtd), GFP_KERNEL); ++ if (!prtd) ++ return -ENOMEM; ++ ++ ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); ++ if (ret < 0) ++ return ret; ++ ++ ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIOD_BYTES); ++ if (ret < 0) ++ return ret; ++ ++ if (as_dma->dma_fth_quirk) { ++ snd_pcm_hw_rule_add(substream->runtime, 0, ++ SNDRV_PCM_HW_PARAM_PERIOD_BYTES, ++ ingenic_as_dma_period_bytes_quirk, ++ NULL, ++ SNDRV_PCM_HW_PARAM_FRAME_BITS, ++ SNDRV_PCM_HW_PARAM_PERIOD_BYTES, ++ -1); ++ } ++ ++ prtd->as_dma = as_dma; ++ prtd->substream = substream; ++ prtd->dai_id = rtd->cpu_dai->id; ++ runtime->private_data = prtd; ++ ++ spin_lock(&as_dma->lock); ++ as_dma->rtd[prtd->dai_id] = prtd; ++ as_dma->refcnt++; ++ prtd->fifo_depth = as_dma->fifo_depth[prtd->dai_id]; ++ spin_unlock(&as_dma->lock); ++ ++ pcm_hardware.fifo_size = prtd->fifo_depth << 2; ++ snd_soc_set_runtime_hwparams(substream, &pcm_hardware); ++ return 0; ++} ++ ++static int ingenic_as_dma_close(struct snd_pcm_substream *substream) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct ingenic_as_dma_runtime *prtd = substream_to_prtd(substream); ++ struct ingenic_as_dma *as_dma = snd_soc_platform_get_drvdata(rtd->platform); ++ ++ DMA_DEBUG_MSG("enter %s[dai%d substream = %s] process is \"%s\" (pid %i)\n", ++ __func__, rtd->cpu_dai->id, ++ (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? ++ "playback" : "capture", current->comm, current->pid); ++ ++ spin_lock(&as_dma->lock); ++ as_dma->refcnt--; ++ as_dma->rtd[rtd->cpu_dai->id] = NULL; ++ spin_unlock(&as_dma->lock); ++ ++ kfree(prtd); ++ substream->runtime->private_data = NULL; ++ return 0; ++} ++ ++/* RETURN 0 not change, 1 change, < 0 failed */ ++static int ingenic_as_dma_alloc_descs(struct ingenic_as_dma_runtime *prtd, int cnt) ++{ ++ struct ingenic_as_dma *as_dma = prtd->as_dma; ++ int i, old_cnts = prtd->desc_cnts; ++ ++ if (cnt == prtd->desc_cnts) ++ return 0; ++ ++ for (i = cnt; i < old_cnts; i++) { ++ dma_pool_free(as_dma->desc_pool, prtd->descs[i], prtd->descs_phy[i]); ++ prtd->descs[i] = NULL; ++ prtd->descs_phy[i] = 0; ++ prtd->desc_cnts--; ++ } ++ for (i = old_cnts; i < cnt; i++) { ++ prtd->descs[i] = dma_pool_alloc(as_dma->desc_pool, ++ GFP_KERNEL, &prtd->descs_phy[i]); ++ if (!prtd->descs[i]) ++ return -ENOMEM; ++ prtd->desc_cnts++; ++ } ++ ++ return 1; ++} ++ ++static void ingenic_as_dma_free_descs(struct ingenic_as_dma_runtime *prtd) ++{ ++ struct ingenic_as_dma *as_dma = prtd->as_dma; ++ int i; ++ ++ for (i = 0; i < prtd->desc_cnts; i++) { ++ dma_pool_free(as_dma->desc_pool, prtd->descs[i], prtd->descs_phy[i]); ++ prtd->descs[i] = NULL; ++ prtd->descs_phy[i] = 0; ++ } ++ prtd->desc_cnts = 0; ++} ++ ++static void ingenic_as_dma_cyclic_descs_init(struct ingenic_as_dma_runtime *prtd, ++ dma_addr_t dma_addr, int period_bytes) ++{ ++ struct ingenic_as_dma *as_dma = prtd->as_dma; ++ int i, tsz, ts_size; ++ ++ DMA_DEBUG_MSG("%s [dai%d substream %s] args: \n\ ++ fifo_depth(words) = %d, periods_bytes = %d\n", ++ __func__, prtd->dai_id, ++ (prtd->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? ++ "playback" : "capture", ++ prtd->fifo_depth, period_bytes); ++ ++ if (unlikely(!as_dma->dma_fth_quirk)) { ++ tsz = ingenic_as_dma_get_tsz(prtd->fifo_depth, period_bytes, &ts_size); ++ } else { ++ ts_size = DCM_TSZ_MAX_WORD << 2; ++ tsz = DCM_TSZ_MAX; ++ } ++ prtd->tsz_words = ts_size >> 2; ++ DMA_DEBUG_MSG("%s [dai%d substream %s] tsz result: tsz(words) = %d\n", ++ __func__, prtd->dai_id, ++ (prtd->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? ++ "playback" : "capture", ++ prtd->tsz_words); ++ ++ for (i = 0; i < prtd->desc_cnts; i++) { ++ memset(prtd->descs[i], 0, sizeof(prtd->descs[i])); ++ prtd->descs[i]->link = prtd->descs[i]->tie = prtd->descs[i]->bai = 1; ++ prtd->descs[i]->tsz = tsz; ++ prtd->descs[i]->dba = dma_addr + i * period_bytes; ++ prtd->descs[i]->ndoa = *(prtd->descs_phy + ((i + 1)%prtd->desc_cnts)); ++ prtd->descs[i]->dtc = (period_bytes/ts_size); ++ } ++ iob(); ++} ++ ++static int ingenic_as_dma_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct ingenic_as_dma_runtime *prtd = substream_to_prtd(substream); ++ struct ingenic_as_dma *as_dma = prtd->as_dma; ++ bool is_out = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? true : false; ++ int dev_id = rtd->cpu_dai->id; ++ int *x = NULL; ++ int ret; ++ ++ DMA_DEBUG_MSG("%s [dai%d substream %s] periodbyte = %u, rate= %u, channels=%u, \n\ ++ bufferbyte %d, periods %d, fmtwidth %d, periodsize %d\n", ++ __func__, dev_id, ++ (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? ++ "playback" : "capture", ++ params_period_bytes(params), params_rate(params), ++ params_channels(params), params_buffer_bytes(params), ++ params_periods(params), params_width(params), ++ params_period_size(params)); ++ ++ ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); ++ if (ret < 0) ++ return ret; ++ ++ ret = ingenic_as_dma_alloc_descs(prtd, params_periods(params)); ++ if (ret < 0) ++ return ret; ++ ingenic_as_dma_cyclic_descs_init(prtd, ++ substream->runtime->dma_addr, ++ params_period_bytes(params)); ++ ++ x = (int *)prtd->descs[0]; ++ DMA_DEBUG_MSG("%s [dai%d substream %s] DMA buffer addr: 0x%08x \n\ ++ DMA desc[0] addr(0x%p:0x%08x) \n\ ++ DES0(%p: 0x%08x) DES1(%p: 0x%08x)\n\ ++ DES2(%p: 0x%08x) DES3(%p: 0x%08x)\n", ++ __func__, dev_id, ++ (prtd->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? ++ "playback" : "capture", ++ substream->runtime->dma_addr, ++ prtd->descs[0], prtd->descs_phy[0], ++ x, *(x), ++ x + 1, *(x + 1), ++ x + 2, *(x + 2), ++ x + 3, *(x + 3)); ++ ret = ingenic_as_fmtcov_cfg(substream, params); ++ if (ret < 0) ++ return ret; ++ ++ regmap_write(as_dma->fifo_regmap, FFR(dev_id), FFR_FTH(prtd->tsz_words) | (is_out ? 0 : FFR_FIFO_TD)); ++ return 0; ++} ++ ++static int ingenic_as_dma_hw_free(struct snd_pcm_substream *substream) ++{ ++ struct ingenic_as_dma_runtime *prtd = substream_to_prtd(substream); ++ ++ ingenic_as_dma_free_descs(prtd); ++ ++ return snd_pcm_lib_free_pages(substream); ++} ++ ++static int ingenic_as_dma_start(struct ingenic_as_dma *as_dma, int dev_id) ++{ ++ struct ingenic_as_dma_runtime *prtd = as_dma->rtd[dev_id]; ++ ++ regmap_write(as_dma->dma_regmap, DSR(dev_id), DSR_TT_INT|DSR_LTT_INT|DSR_LTT|DSR_TT); ++ ++ regmap_update_bits(as_dma->dma_regmap, DCM(dev_id), DCM_NDES|DCM_TIE, DCM_TIE); ++ ++ /* Note: DMA enable first FIFO enable, read operation ++ * to ensure that the DMA module work ++ * */ ++ regmap_write(as_dma->dma_regmap, DDA(dev_id), prtd->descs_phy[0]); ++ readl_relaxed(as_dma->dma_base + DDA(dev_id)); ++ ++ ingenic_as_fmtcov_enable(dev_id, true); ++ ++ regmap_write(as_dma->dma_regmap, DCR(dev_id), DCR_CTE); ++ ++ regmap_write(as_dma->fifo_regmap, FCR(dev_id), FCR_FIFO_EN); ++ ++ DMA_DEBUG_MSG("%s [dai%d substream %s] dma trigger start dba reg val = 0x%08x\n", ++ __func__, dev_id, ++ (prtd->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? ++ "playback" : "capture", ++ readl_relaxed(as_dma->dma_base + DBA(prtd->dai_id))); ++ ++ if (IS_BUILTIN(CONFIG_FPGA_TEST) || ingenic_dma_debug) { ++ regmap_write(as_dma->fifo_regmap, FSR(dev_id), FSR_TURROR); ++ regmap_update_bits(as_dma->fifo_regmap, FFR(dev_id), FFR_TURRORE, FFR_TURRORE); ++ } ++ return 0; ++} ++ ++static int ingenic_as_dma_stop(struct ingenic_as_dma *as_dma, int dev_id) ++{ ++ u32 val, timeout = 0xfff; ++ ++ if (IS_BUILTIN(CONFIG_FPGA_TEST) || ingenic_dma_debug) { ++ regmap_update_bits(as_dma->fifo_regmap, FFR(dev_id), FFR_TURRORE, 0); ++ regmap_write(as_dma->fifo_regmap, FSR(dev_id), FSR_TURROR); ++ } ++ ++ regmap_update_bits(as_dma->dma_regmap, DCM(dev_id), DCM_TIE, 0); ++ regmap_write(as_dma->dma_regmap, DSR(dev_id), DSR_TT_INT|DSR_LTT_INT|DSR_LTT|DSR_TT); ++ ++ regmap_write(as_dma->fifo_regmap, FCR(dev_id), 0); ++ ++ regmap_write(as_dma->dma_regmap, DCR(dev_id), 0); ++ do { ++ regmap_read(as_dma->dma_regmap, DSR(dev_id), &val); ++ } while ((val & DSR_RST_EN) && (--timeout)); ++ ++ regmap_write(as_dma->dma_regmap, DCR(dev_id), DCR_RESET); ++ udelay(10); ++ ++ ingenic_as_fmtcov_enable(dev_id, false); ++ ++ return 0; ++} ++ ++static int ingenic_as_dma_trigger(struct snd_pcm_substream *substream, int cmd) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct ingenic_as_dma *as_dma = snd_soc_platform_get_drvdata(rtd->platform); ++ ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ case SNDRV_PCM_TRIGGER_RESUME: /*FIXME*/ ++ DMA_DEBUG_MSG("enter %s[dai%d substream = %s] start\n", __func__, ++ rtd->cpu_dai->id, ++ (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? ++ "playback" : "capture"); ++ return ingenic_as_dma_start(as_dma, rtd->cpu_dai->id); ++ case SNDRV_PCM_TRIGGER_STOP: ++ case SNDRV_PCM_TRIGGER_SUSPEND: ++ DMA_DEBUG_MSG("enter %s[dai%d substream = %s] stop\n", __func__, ++ rtd->cpu_dai->id, ++ (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? ++ "playback" : "capture"); ++ return ingenic_as_dma_stop(as_dma, rtd->cpu_dai->id); ++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ++ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: ++ /*JUST stop or resume the be dai*/ ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++static const struct snd_pcm_ops ingenic_as_dma_ops = { ++ .ioctl = snd_pcm_lib_ioctl, ++ .pointer = ingenic_as_dma_pointer, ++ .open = ingenic_as_dma_open, ++ .close = ingenic_as_dma_close, ++ .hw_params = ingenic_as_dma_hw_params, ++ .hw_free = ingenic_as_dma_hw_free, ++ .trigger = ingenic_as_dma_trigger, ++}; ++ ++static int ingenic_as_dma_pcm_new(struct snd_soc_pcm_runtime *rtd) ++{ ++ struct snd_card *card = rtd->card->snd_card; ++ struct snd_pcm *pcm = rtd->pcm; ++ ++ return snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, card->dev, ++ INGENIC_DMA_BUFFERSIZE_PREALLOC, INGENIC_DMA_BUFFERSIZE_MAX); ++} ++ ++static void ingenic_as_dma_pcm_free(struct snd_pcm *pcm) ++{ ++ snd_pcm_lib_preallocate_free_for_all(pcm); ++} ++ ++static const struct snd_soc_platform_driver ingenic_as_dma_platform = { ++ .ops = &ingenic_as_dma_ops, ++ .pcm_new = ingenic_as_dma_pcm_new, ++ .pcm_free = ingenic_as_dma_pcm_free, ++}; ++ ++static irqreturn_t ingenic_as_dma_irq_handler(int irq, void *dev_id) ++{ ++ struct ingenic_as_dma *as_dma = (void *)dev_id; ++ struct ingenic_as_dma_runtime *prtd = NULL; ++ unsigned int dma_status, fifo_status, pending, pending1; ++ struct snd_pcm_substream *substream = NULL; ++ int ch; ++ ++ regmap_read(as_dma->dma_regmap, AIPR, &pending); ++ dev_dbg(as_dma->dev, "interrupt (irq%d) pending %x\n", irq, pending); ++ pending &= AIPR_DMA_INT_MSK; ++ pending1 = pending; ++ ++ while((ch = ffs(pending1))) { ++ ch -= 1; ++ pending1 &= ~BIT(ch); ++ regmap_read(as_dma->dma_regmap, DSR(ch), &dma_status); ++ regmap_write(as_dma->dma_regmap, DSR(ch), dma_status); ++ if (!(dma_status & DSR_TT_INT)) ++ continue; ++ dev_dbg(as_dma->dev, "dma ch(%x) pending %x\n", dma_status, ch); ++ spin_lock(&as_dma->lock); ++ substream = NULL; ++ prtd = as_dma->rtd[ch]; ++ if (likely(prtd)) { ++ substream = prtd->substream; ++ spin_unlock(&as_dma->lock); ++ snd_pcm_period_elapsed(substream); ++ } else { ++ spin_unlock(&as_dma->lock); ++ dev_warn(as_dma->dev, "dma channel(%d) \ ++ stream has been stopped\n", ch); ++ } ++ } ++ ++ if (IS_BUILTIN(CONFIG_FPGA_TEST) || ingenic_dma_debug) { ++ while((ch = ffs(pending))) { /*handle ror/tur debug*/ ++ ch -= 1; ++ pending &= ~BIT(ch); ++ regmap_read(as_dma->fifo_regmap, FSR(ch), &fifo_status); ++ regmap_write(as_dma->fifo_regmap, FSR(ch), fifo_status); ++ if (fifo_status & FSR_TURROR_INT) ++ dev_warn(as_dma->dev, "Fifo %d xrun\n", ch); ++ } ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++ssize_t fifo_depth_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct ingenic_as_dma *as_dma = dev_get_drvdata(dev); ++ ssize_t len = 0; ++ int ch; ++ ++ for (ch = 0; ch < as_dma->chan_cnts; ch++) { ++ len += snprintf(buf + len, PAGE_SIZE - len, ch ? "-%d": "%d", as_dma->fifo_depth[ch]); ++ } ++ return len; ++} ++ ++ssize_t fifo_depth_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct ingenic_as_dma *as_dma = dev_get_drvdata(dev); ++ char *val, *tmp = (char *)vmalloc(strlen(buf) + 1); ++ unsigned long depth, res_depth = as_dma->fifo_total_depth; ++ int ret, ch = 0, res_chs = as_dma->chan_cnts; ++ ++ memcpy(tmp, buf, strlen(buf) + 1); ++ ++ spin_lock(&as_dma->lock); ++ if (as_dma->refcnt) { ++ spin_unlock(&as_dma->lock); ++ return 0; ++ } ++ ++ while (*tmp && res_chs && res_depth) { ++ val = strsep(&tmp, "-"); ++ ret = kstrtoul(val, 10, &depth); ++ WARN_ON(ret); ++ as_dma->fifo_depth[ch++] = min(min(depth, res_depth), ++ (unsigned long)(FAS_FAD >> FAS_FAD_SFT)); ++ res_depth -= depth; ++ res_chs--; ++ } ++ ++ for (;ch < as_dma->chan_cnts; ch++) ++ as_dma->fifo_depth[ch++] = res_depth/res_chs; ++ ++ for (ch = 0; ch < as_dma->chan_cnts; ch++) ++ regmap_write(as_dma->fifo_regmap, FAS(ch), as_dma->fifo_depth[ch]); ++ spin_unlock(&as_dma->lock); ++ return count; ++} ++ ++static DEVICE_ATTR_RW(fifo_depth); ++ ++static struct attribute *ingenic_as_dma_attrs[] = { ++ &dev_attr_fifo_depth.attr, ++ NULL, ++}; ++ ++static struct attribute_group ingenic_as_dma_attr_grp = { ++ .attrs = ingenic_as_dma_attrs, ++}; ++ ++static const struct attribute_group *ingenic_as_dma_groups[] = { ++ &ingenic_as_dma_attr_grp, ++ NULL, ++}; ++ ++static const struct of_device_id ingenic_as_dma_match_table[]; ++static int ingenic_as_dma_probe(struct platform_device *pdev) ++{ ++ struct ingenic_as_dma *as_dma; ++ const struct of_device_id *match; ++ struct resource *res; ++ int ret, chan_cnts, i; ++ u32 fifo_depth; ++ struct regmap_config regmap_config = { ++ .reg_bits = 32, ++ .reg_stride = 4, ++ .val_bits = 32, ++ .cache_type = REGCACHE_NONE, ++ }; ++ ++ match = of_match_node(ingenic_as_dma_match_table, pdev->dev.of_node); ++ if (!match) ++ return -ENODEV; ++ chan_cnts = (int)match->data; ++ ++ as_dma = (struct ingenic_as_dma *)devm_kzalloc(&pdev->dev, sizeof(*as_dma) + ++ (sizeof (*as_dma->rtd) + sizeof(*as_dma->fifo_depth)) * chan_cnts, ++ GFP_KERNEL); ++ if (!as_dma) ++ return -ENOMEM; ++ ++ as_dma->dev = &pdev->dev; ++ as_dma->rtd = (void *)(as_dma + 1); ++ as_dma->fifo_depth = (void *)(as_dma->rtd + chan_cnts); ++ as_dma->chan_cnts = chan_cnts; ++ spin_lock_init(&as_dma->lock); ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma"); ++ as_dma->dma_base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(as_dma->dma_base)) ++ return PTR_ERR(as_dma->dma_base); ++ regmap_config.max_register = resource_size(res) - 0x4; ++ regmap_config.name = res->name; ++ as_dma->dma_regmap = devm_regmap_init_mmio(&pdev->dev, ++ as_dma->dma_base, ++ ®map_config); ++ if (IS_ERR(as_dma->dma_regmap)) ++ return PTR_ERR(as_dma->dma_regmap); ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fifo"); ++ as_dma->fifo_base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(as_dma->fifo_base)) ++ return PTR_ERR(as_dma->fifo_base); ++ regmap_config.max_register = resource_size(res) - 0x4; ++ regmap_config.name = res->name; ++ as_dma->fifo_regmap = devm_regmap_init_mmio(&pdev->dev, ++ as_dma->fifo_base, ++ ®map_config); ++ if (IS_ERR(as_dma->fifo_regmap)) ++ return PTR_ERR(as_dma->fifo_regmap); ++ ++ as_dma->irq = of_irq_get(pdev->dev.of_node, 0); ++ if (as_dma->irq < 0) ++ return as_dma->irq; ++ ++ platform_set_drvdata(pdev, as_dma); ++ ++ regmap_write(as_dma->dma_regmap, DGRR, DGRR_RESET); ++ ++ /*INIT FIFO*/ ++ if (of_property_read_u32(pdev->dev.of_node, "ingenic,fifo_size", &as_dma->fifo_total_depth)) ++ as_dma->fifo_total_depth = INGENIC_DEF_FIFO_DEPTH; ++ ++ as_dma->dma_fth_quirk = of_property_read_bool(pdev->dev.of_node, "ingenic,fth_quirk"); ++ ++ fifo_depth = (as_dma->fifo_total_depth / as_dma->chan_cnts); ++ for (i = 0; i < as_dma->chan_cnts; i++) { ++ as_dma->fifo_depth[i] = fifo_depth; ++ regmap_write(as_dma->fifo_regmap, FAS(i), fifo_depth); ++ } ++ ++ ret = devm_request_threaded_irq(&pdev->dev, as_dma->irq, NULL, ++ ingenic_as_dma_irq_handler, IRQF_SHARED|IRQF_ONESHOT, ++ "as-dma", as_dma); ++ if (ret) ++ return ret; ++ ++ as_dma->desc_pool = dma_pool_create("as_dma_desc_pool", &pdev->dev, ++ sizeof(struct ingenic_as_dma_desc), ++ __alignof__(struct ingenic_as_dma_desc), 0); ++ if (!as_dma->desc_pool) ++ return -ENOMEM; ++ ++ ret = snd_soc_register_platform(&pdev->dev, &ingenic_as_dma_platform); ++ if (ret) { ++ dma_pool_destroy(as_dma->desc_pool); ++ return ret; ++ } ++ ++ ret = sysfs_create_groups(&pdev->dev.kobj, ingenic_as_dma_groups); ++ if (ret) ++ return ret; ++ ++ dev_info(&pdev->dev, "probe success!!!\n"); ++ return 0; ++} ++ ++static int ingenic_as_dma_remove(struct platform_device *pdev) ++{ ++ struct ingenic_as_dma *as_dma = platform_get_drvdata(pdev); ++ ++ snd_soc_unregister_platform(&pdev->dev); ++ ++ dma_pool_destroy(as_dma->desc_pool); ++ ++ platform_set_drvdata(pdev, NULL); ++ return 0; ++} ++ ++static const struct of_device_id ingenic_as_dma_match_table[] = { ++#define INGENIC_AS_DMA_DEF_CHS (10) ++ { .compatible = "ingenic,as-platform", .data = (void*)INGENIC_AS_DMA_DEF_CHS}, ++#undef INGENIC_AS_DMA_DEF_CHS ++ { } ++}; ++MODULE_DEVICE_TABLE(of, ingenic_as_dma_match_table); ++ ++#ifdef CONFIG_PM ++static int ingenic_as_dma_runtime_suspend(struct device *dev) ++{ ++ return 0; ++} ++ ++static int ingenic_as_dma_runtime_resume(struct device *dev) ++{ ++ return 0; ++} ++#endif ++ ++static const struct dev_pm_ops ingenic_as_dma_pm_ops = { ++ SET_RUNTIME_PM_OPS(ingenic_as_dma_runtime_suspend, ++ ingenic_as_dma_runtime_resume, NULL) ++}; ++ ++static struct platform_driver ingenic_as_dma_platform_driver = { ++ .driver = { ++ .name = "as-platform", ++ .of_match_table = ingenic_as_dma_match_table, ++ .pm = &ingenic_as_dma_pm_ops, ++ }, ++ .probe = ingenic_as_dma_probe, ++ .remove = ingenic_as_dma_remove, ++}; ++module_platform_driver(ingenic_as_dma_platform_driver); ++ ++MODULE_AUTHOR("cli "); ++MODULE_DESCRIPTION("Ingenic AS DMA SoC Interface"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:ingenic-as-dma"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-dma.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-dma.h.patch new file mode 100644 index 00000000..2ca1ac1e --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-dma.h.patch @@ -0,0 +1,194 @@ +diff -drupN a/sound/soc/ingenic/as-v2/as-dma.h b/sound/soc/ingenic/as-v2/as-dma.h +--- a/sound/soc/ingenic/as-v2/as-dma.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/as-v2/as-dma.h 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,190 @@ ++/* ++ * ALSA Soc Audio Layer -- Ingenic AS DMA Controller ++ * ++ * Copyright 2017 - 2022 Ingenic Semiconductor Co.,Ltd ++ * cli ++ * ++ * 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. ++ */ ++#ifndef __AS_DMA_H__ ++#define __AS_DMA_H__ ++ ++#include ++ ++/* DMA */ ++#define DMA_CH_OFF (0x18) ++#define DBA(ch) (0x0 + (ch) * DMA_CH_OFF) ++#define DTC(ch) (0x4 + (ch) * DMA_CH_OFF) ++#define DCR(ch) (0x8 + (ch) * DMA_CH_OFF) ++#define DSR(ch) (0xc + (ch) * DMA_CH_OFF) ++#define DCM(ch) (0x10 + (ch) * DMA_CH_OFF) ++#define DDA(ch) (0x14 + (ch) * DMA_CH_OFF) ++#define DGRR (0x100) ++#define DGER (0x104) ++#define AEER (0x108) ++#define AESR (0x10c) ++#define AIPR (0x110) ++ ++#define DTC_TC_SFT (0) ++#define DTC_TC GENMASK(23, DTC_TC_SFT) ++ ++#define DCR_RESET BIT(1) ++#define DCR_CTE BIT(0) ++ ++#define DSR_CDOA_SFT (8) ++#define DSR_CDOA GENMASK(15, DSR_CDOA_SFT) ++#define DSR_TT_INT BIT(5) ++#define DSR_LTT_INT BIT(4) ++#define DSR_TT BIT(3) ++#define DSR_LTT BIT(2) ++#define DSR_RST_EN BIT(1) ++#define DSR_LINK BIT(0) ++ ++#define DCM_NDES BIT(31) ++#define DCM_BAI BIT(8) ++#define DCM_TSZ_SFT (4) ++#define SET_DMA_BURST_SZ(burst) (0x1 << (burst + 1)) ++#define DMA_BURST_4_WORD (0x1) ++#define DMA_BURST_8_WORD (0x2) ++#define DMA_BURST_16_WORD (0x3) ++#define DMA_BURST_32_WORD (0x4) ++#define DCM_TSZ_MAX DMA_BURST_32_WORD ++#define DCM_TSZ_MAX_WORD SET_DMA_BURST_SZ(DCM_TSZ_MAX) ++#define DCM_TSZ_MSK GENMASK(6, DCM_TSZ_SFT) ++#define DCM_TIE BIT(1) ++#define DCM_LTIE BIT(0) ++ ++#define DGRR_RESET BIT(0) ++ ++#define DGER_DMA_EN BIT(0) ++ ++#define AEER_EXP_EN BIT(0) ++ ++#define AESR_EXP BIT(0) ++ ++#define AIPR_MSK GENMASK(11, 0) ++#define AIPR_EXP_INT BIT(11) ++#define AIPR_DIMC_INT BIT(10) ++#define AIPR_DMA_INT_MSK GENMASK(9, 0) ++#define AIPR_DMA_INT(ch) BIT((ch)) ++ ++/* FIFO */ ++#define FIFO_CH_OFF (0x10) ++#define FAS(ch) (0x0 + (ch) * FIFO_CH_OFF) ++#define FCR(ch) (0x4 + (ch) * FIFO_CH_OFF) ++#define FFR(ch) (0x8 + (ch) * FIFO_CH_OFF) ++#define FSR(ch) (0xc + (ch) * FIFO_CH_OFF) ++ ++#define FAS_FAD_SFT (0) ++#define FAS_FAD GENMASK(12, FAS_FAD_SFT) ++ ++#define FCR_FLUSH BIT(2) ++#define FCR_FULL_EN BIT(1) ++#define FCR_FIFO_EN BIT(0) ++ ++#define FFR_FTH_SFT (16) ++#define FFR_FTH_MSK GENMASK(28, FFR_FTH_SFT) ++#define FFR_FTH(n) (((n) << FFR_FTH_SFT) & FFR_FTH_MSK) ++#define FFR_TURRORE BIT(9) ++#define FFR_FSE BIT(8) ++#define FFR_FIFO_TD BIT(7) ++ ++#define FSR_FLEVEL_SFT (16) ++#define FSR_FLEVEL GENMASK(28, FSR_FLEVEL_SFT) ++#define FSR_TURROR_INT BIT(5) ++#define FSR_TFSRFS_INT BIT(4) ++#define FSR_TURROR BIT(2) ++#define FSR_TFSRFS BIT(0) ++ ++struct ingenic_as_dma_desc { ++ /*desc0*/ ++ uint32_t ltie:1; /* Last Transfer Interrupt Enable */ ++ uint32_t tie:1; /* Transfer Interrupt Enable */ ++ uint32_t link:1; /* Enable Descriptor Link Enable */ ++ uint32_t lte:1; /* Last Descriptor Transfer end Status */ ++ uint32_t tsz:3; /* Transfer Data Size (burst)*/ ++ uint32_t reserved0_7:1; ++ uint32_t bai:1; /* Target Address Increment */ ++ uint32_t reserved0_9_31:23; ++ /*desc 1*/ ++ uint32_t dba; /* Bus Address (memory address)*/ ++ /*desc 2*/ ++ uint32_t ndoa; /* Descriptor Next Offset address*/ ++ /*desc 3*/ ++ uint32_t dtc:24; /*Transfer Counter(burst count)*/ ++ uint32_t reserved3_24_31:8; ++} __attribute__ ((packed)); ++ ++#define INGENIC_DEF_FIFO_DEPTH (4096) ++#define INGENIC_PERIODS_MIN (4) ++#define INGENIC_PERIODS_BYTES_MIN (1024) ++#define INGENIC_DMA_BUFFERSIZE_MAX (128 * 1024 * 4) ++#define INGENIC_DMA_BUFFERSIZE_PREALLOC INGENIC_DMA_BUFFERSIZE_MAX ++ ++struct ingenic_as_dma_runtime { ++ struct snd_pcm_substream *substream; ++ u8 dai_id; ++ struct ingenic_as_dma_desc *descs[INGENIC_DMA_BUFFERSIZE_MAX/INGENIC_PERIODS_MIN]; ++ dma_addr_t descs_phy[INGENIC_DMA_BUFFERSIZE_MAX/INGENIC_PERIODS_MIN]; ++ uint8_t desc_cnts; ++ uint32_t fifo_depth; ++ uint32_t tsz_words; ++ struct ingenic_as_dma *as_dma; ++}; ++ ++struct ingenic_as_dma { ++ struct device *dev; ++ struct regmap *dma_regmap; ++ struct regmap *fifo_regmap; ++ void __iomem *dma_base; ++ void __iomem *fifo_base; ++ int irq; ++ int chan_cnts; ++ struct dma_pool *desc_pool; ++ uint32_t fifo_total_depth; ++ bool dma_fth_quirk; ++ ++ spinlock_t lock; ++ struct ingenic_as_dma_runtime **rtd; ++ uint32_t *fifo_depth; ++ int refcnt; ++}; ++ ++static inline struct ingenic_as_dma_runtime *substream_to_prtd( ++ const struct snd_pcm_substream *substream) ++{ ++ return substream->runtime->private_data; ++} ++ ++static inline int ingenic_as_dma_get_tsz(int fifo_depth, ++ int period_sz, int *ts_byte_sz) ++{ ++ int tsz_reg = 0, ts_word_sz = 1; ++ ++ if (period_sz & ((4 << 2) - 1)) { ++ *ts_byte_sz = ts_word_sz << 2; ++ return tsz_reg; ++ } ++ period_sz >>= 2; /*word size*/ ++ ++ period_sz >>= 2; ++ ts_word_sz <<= 2; ++ tsz_reg++; ++ ++ while ((!(period_sz & 0x1)) && ++ (ts_word_sz << 1) <= fifo_depth) { ++ period_sz >>= 1; ++ ts_word_sz <<= 1; ++ tsz_reg++; ++ if (ts_word_sz >= DCM_TSZ_MAX_WORD) ++ break; ++ } ++ ++ if (ts_byte_sz) ++ *ts_byte_sz = ts_word_sz << 2; ++ return tsz_reg; ++} ++#endif /*__AS_DMA_H__*/ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-dmic.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-dmic.c.patch new file mode 100644 index 00000000..192e3a3f --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-dmic.c.patch @@ -0,0 +1,309 @@ +diff -drupN a/sound/soc/ingenic/as-v2/as-dmic.c b/sound/soc/ingenic/as-v2/as-dmic.c +--- a/sound/soc/ingenic/as-v2/as-dmic.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/as-v2/as-dmic.c 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,305 @@ ++/* ++ * ALSA Soc Audio Layer -- ingenic as(audio system) dmic(Basic Audio Inter- ++ * face Controller) driver ++ * ++ * Copyright 2017 - 2022 Ingenic Semiconductor Co.,Ltd ++ * wqshao ++ * ++ * 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. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "as-dmic.h" ++ ++#ifdef DEBUG ++static int ingenic_dmic_debug = 1; ++#else ++static int ingenic_dmic_debug = 0; ++#endif ++module_param(ingenic_dmic_debug, int, 0644); ++#define DMIC_DEBUG_MSG(msg...) \ ++ do { \ ++ if (ingenic_dmic_debug) \ ++ printk(KERN_DEBUG"DMIC: " msg); \ ++ } while(0) ++ ++static int ingenic_dmic_reset(struct ingenic_dmic *dmic) ++{ ++ unsigned int val, time_out = 0xfff; ++ ++ regmap_update_bits(dmic->regmap, DMIC_CR0, DMIC_RESET, DMIC_RESET); ++ do { ++ regmap_read(dmic->regmap, DMIC_CR0, &val); ++ } while((val & DMIC_RESET) && (--time_out)); ++ if(!time_out) { ++ dev_err(dmic->dev, "DMIC reset fail ...\n"); ++ return -EIO; ++ } ++ return 0; ++} ++ ++static int ingenic_dmic_startup(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct ingenic_dmic *dmic = dev_get_drvdata(dai->dev); ++ ++ DMIC_DEBUG_MSG("enter %s\n", __func__); ++ ++ return ingenic_dmic_reset(dmic); ++} ++ ++static int ingenic_dmic_trigger(struct snd_pcm_substream *substream, ++ int cmd, struct snd_soc_dai *dai) ++{ ++ struct ingenic_dmic *dmic = dev_get_drvdata(dai->dev); ++ ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ case SNDRV_PCM_TRIGGER_RESUME: ++ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: ++ DMIC_DEBUG_MSG("start\n"); ++ regmap_update_bits(dmic->regmap, DMIC_CR0, DMIC_EN, DMIC_EN); ++ break; ++ case SNDRV_PCM_TRIGGER_STOP: ++ case SNDRV_PCM_TRIGGER_SUSPEND: ++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ++ DMIC_DEBUG_MSG("stop\n"); ++ regmap_update_bits(dmic->regmap, DMIC_CR0, DMIC_EN, 0); ++ return ingenic_dmic_reset(dmic); ++ break; ++ } ++ return 0; ++} ++ ++static int ingenic_dmic_params_check(int channels, int rate, int fmt_width) ++{ ++ if (channels < 1 && channels > 12) ++ goto error; ++ ++ if ((rate != 8000) && (rate != 16000) ++ && (rate != 48000) && (rate != 96000)) ++ goto error; ++ ++ if ((fmt_width != 16) && (fmt_width != 24)) ++ goto error; ++ ++ return true; ++error: ++ pr_err("%s %d, parameter is illegal!\n", __func__, __LINE__); ++ return false; ++} ++ ++static int ingenic_dmic_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) ++{ ++ int channels = params_channels(params); ++ int rate = params_rate(params); ++ int fmt_width = snd_pcm_format_width(params_format(params)); ++ struct ingenic_dmic *dmic = dev_get_drvdata(dai->dev); ++ u32 dmic_cr = 0; ++ ++ DMIC_DEBUG_MSG("enter %s, substream = %s chl=%d, rate=%d, fmt_width=%d\n",__func__, ++ "capture", channels, rate, fmt_width); ++ ++ if (!ingenic_dmic_params_check(channels, rate, fmt_width)) ++ return -EINVAL; ++ ++ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { ++ dmic_cr = DMIC_SET_CHL(channels); ++ dmic_cr |= DMIC_SET_SR(rate); ++ dmic_cr |= DMIC_SET_OSS(fmt_width); ++ regmap_update_bits(dmic->regmap, DMIC_CR0, CHNUM_MASK|SR_MASK|OSS_MASK, dmic_cr); ++ } else { ++ dev_err(dmic->dev, "DMIC is a capture device\n"); ++ return -ENXIO; ++ } ++ ++ return 0; ++} ++ ++static struct snd_soc_dai_ops ingenic_dmic_dai_ops = { ++ .startup = ingenic_dmic_startup, ++ .trigger = ingenic_dmic_trigger, ++ .hw_params = ingenic_dmic_hw_params, ++}; ++ ++/* ++ * GAIN volume control: ++ * from 0 to 93 dB in 3 dB steps (0dB means no gain is used) ++ * */ ++static const DECLARE_TLV_DB_SCALE(dmic_tlv, 0, 300, 0); ++ ++static const struct snd_kcontrol_new ingenic_dmic_controls[] = { ++ SOC_SINGLE_TLV("DMIC Volume", DMIC_GCR, DGAIN_SFT, 31, 0, dmic_tlv), ++ ++ SOC_SINGLE("DMIC High Pass Filter1 Switch", DMIC_CR0, HPF1_EN_SFT, 1, 0), ++ SOC_SINGLE("DMIC High Pass Filter2 Switch", DMIC_CR0, HPF2_EN_SFT, 1, 0), ++ SOC_SINGLE("DMIC Low Pass Filter Switch", DMIC_CR0, LPF_EN_SFT, 1, 0), ++ ++ SOC_SINGLE("DMIC SW_LR Switch", DMIC_CR0, SW_LR_SFT, 1, 0), ++}; ++ ++struct snd_soc_component_driver ingenic_dmic_component = { ++ .name = "as_dmic", ++ .controls = ingenic_dmic_controls, ++ .num_controls = ARRAY_SIZE(ingenic_dmic_controls), ++}; ++ ++static int ingenic_dmic_probe(struct snd_soc_dai *dai) ++{ ++ struct ingenic_dmic *dmic = dev_get_drvdata(dai->dev); ++ ++ regmap_update_bits(dmic->regmap, DMIC_CR0, HPF2_EN|LPF_EN|HPF1_EN, ++ HPF2_EN|LPF_EN|HPF1_EN); ++ /*gain: 0, ..., 1F*/ ++ regmap_write(dmic->regmap, DMIC_GCR, DMIC_SET_GAIN(4)); ++ ++ return 0; ++} ++ ++#define ingenic_dmic_suspend NULL ++#define ingenic_dmic_resume NULL ++ ++static int ingenic_dmic_clk_init(struct platform_device *pdev, ++ struct ingenic_dmic *dmic) ++{ ++ dmic->clk = devm_clk_get(dmic->dev, "cgu_dmic"); ++ if(IS_ERR_OR_NULL(dmic->clk)) { ++ dev_warn(dmic->dev, "Warning ... Failed to get cgu_dmic!\n"); ++ } ++ ++ /* Setup dmic's Parent clk, fix to i2s2 */ ++ if(dmic->clk) { ++ struct clk *parent; ++ parent = devm_clk_get(dmic->dev, "cgu_i2s2"); ++ clk_set_parent(dmic->clk, parent); ++ devm_clk_put(dmic->dev, parent); ++ } ++ ++ dmic->clk_gate = devm_clk_get(dmic->dev, "gate_dmic"); ++ if(IS_ERR_OR_NULL(dmic->clk_gate)) { ++ dev_warn(dmic->dev, "Warning ... Failed to get gate_dmic!\n"); ++ } ++ ++ if(dmic->clk) { ++ clk_set_rate(dmic->clk, 24000000); ++ clk_prepare_enable(dmic->clk); ++ } ++ if(dmic->clk_gate) { ++ clk_prepare_enable(dmic->clk_gate); ++ } ++ ++ return 0; ++} ++ ++static int ingenic_dmic_platform_probe(struct platform_device *pdev) ++{ ++ struct ingenic_dmic *dmic; ++ struct resource *res; ++ int ret; ++ struct regmap_config regmap_config = { ++ .reg_bits = 32, ++ .reg_stride = 4, ++ .val_bits = 32, ++ .cache_type = REGCACHE_NONE, ++ }; ++ ++ dmic = devm_kzalloc(&pdev->dev, sizeof(struct ingenic_dmic) + ++ sizeof(struct snd_soc_dai_driver), GFP_KERNEL); ++ if (!dmic) ++ return -ENOMEM; ++ ++ dmic->dai_driver = (struct snd_soc_dai_driver*)(dmic + 1); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ dmic->io_base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(dmic->io_base)) ++ return PTR_ERR(dmic->io_base); ++ regmap_config.max_register = resource_size(res) - 0x4; ++ dmic->regmap = devm_regmap_init_mmio(&pdev->dev, ++ dmic->io_base, ++ ®map_config); ++ if (IS_ERR(dmic->regmap)) ++ return PTR_ERR(dmic->regmap); ++ dmic->dev = &pdev->dev; ++ ++ dmic->dai_driver->id = 1; ++ dmic->dai_driver->name = "DMIC"; ++ dmic->dai_driver->probe = ingenic_dmic_probe;; ++ dmic->dai_driver->suspend = ingenic_dmic_suspend; ++ dmic->dai_driver->resume = ingenic_dmic_resume; ++ dmic->dai_driver->ops = &ingenic_dmic_dai_ops; ++ dmic->dai_driver->capture.stream_name = "DMIC capture"; ++ ++ ingenic_dmic_clk_init(pdev, dmic); ++ platform_set_drvdata(pdev, dmic); ++ ++ ret = devm_snd_soc_register_component(&pdev->dev, &ingenic_dmic_component, ++ dmic->dai_driver, 1); ++ if (!ret) ++ dev_info(&pdev->dev, "dmic platform probe success\n"); ++ ++ return ret; ++} ++ ++static int ingenic_dmic_platform_remove(struct platform_device *pdev) ++{ ++ return 0; ++} ++ ++static const struct of_device_id ingenic_dmic_match_table[] = { ++ { .compatible = "ingenic,as-dmic", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, ingenic_dmic_match_table); ++ ++#ifdef CONFIG_PM ++static int ingenic_dmic_runtime_suspend(struct device *dev) ++{ ++ return 0; ++} ++ ++static int ingenic_dmic_runtime_resume(struct device *dev) ++{ ++ return 0; ++} ++#endif ++ ++static const struct dev_pm_ops ingenic_dmic_pm_ops = { ++ SET_RUNTIME_PM_OPS(ingenic_dmic_runtime_suspend, ++ ingenic_dmic_runtime_resume, NULL) ++}; ++ ++ ++static struct platform_driver ingenic_dmic_platform_driver = { ++ .driver = { ++ .name = "as-dmic", ++ .of_match_table = ingenic_dmic_match_table, ++ .pm = &ingenic_dmic_pm_ops, ++ }, ++ .probe = ingenic_dmic_platform_probe, ++ .remove = ingenic_dmic_platform_remove, ++}; ++module_platform_driver(ingenic_dmic_platform_driver); ++ ++MODULE_AUTHOR("wqshao "); ++MODULE_DESCRIPTION("Ingenic AS dmic SoC Interface"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:ingenic-as-dmic"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-dmic.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-dmic.h.patch new file mode 100644 index 00000000..c90597f6 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-dmic.h.patch @@ -0,0 +1,68 @@ +diff -drupN a/sound/soc/ingenic/as-v2/as-dmic.h b/sound/soc/ingenic/as-v2/as-dmic.h +--- a/sound/soc/ingenic/as-v2/as-dmic.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/as-v2/as-dmic.h 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,64 @@ ++/* ++ * ALSA Soc Audio Layer -- ingenic as(audio system) dmic(Basic Audio Inter- ++ * face Controller) driver ++ * ++ * Copyright 2017 - 2022 Ingenic Semiconductor Co.,Ltd ++ * wqshao ++ * ++ * 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. ++ */ ++#ifndef __AS_DMIC_H__ ++#define __AS_DMIC_H__ ++ ++#include ++ ++struct ingenic_dmic { ++ struct device *dev; ++ struct regmap *regmap; ++ void __iomem *io_base; ++ struct snd_soc_dai_driver *dai_driver; ++ struct clk *clk; ++ struct clk *clk_gate; ++}; ++ ++#define DMIC_CR0 (0x0) ++#define DMIC_GCR (0x4) ++#define DMIC_IER (0x8) ++#define DMIC_ICR (0xc) ++#define DMIC_TCR (0x10) ++ ++/* DMIC_CR0 */ ++#define DMIC_RESET BIT(31) ++#define HPF2_EN_SFT (22) ++#define HPF2_EN BIT(22) ++#define LPF_EN_SFT (21) ++#define LPF_EN BIT(21) ++#define HPF1_EN_SFT (20) ++#define HPF1_EN BIT(20) ++#define CHNUM_SFT (16) ++#define CHNUM_MASK GENMASK(19, CHNUM_SFT) ++#define DMIC_SET_CHL(chl) (((chl) - 1) << CHNUM_SFT) ++#define OSS_SFT (12) ++#define OSS_MASK GENMASK(13, OSS_SFT) ++#define OSS_16BIT (0x0 << OSS_SFT) ++#define OSS_24BIT (0x1 << OSS_SFT) ++#define DMIC_SET_OSS(x) ((x == 16) ? OSS_16BIT : (x == 24) ? OSS_24BIT : OSS_16BIT) ++#define SW_LR_SFT (11) ++#define SW_LR BIT(11) ++#define SR_SFT (6) ++#define SR_MASK GENMASK(8, SR_SFT) ++#define SR_8k (0x0 << SR_SFT) ++#define SR_16k (0x1 << SR_SFT) ++#define SR_48k (0x2 << SR_SFT) ++#define SR_96k (0x3 << SR_SFT) ++#define DMIC_SET_SR(r) ((r) == 8000 ? SR_8k : (r == 16000) ? SR_16k : (r == 48000) ? SR_48k : (r == 96000) ? SR_96k : SR_48k) ++#define DMIC_EN BIT(0) ++ ++/* DMIC_GCR */ ++#define DGAIN_SFT (0) ++#define DMIC_SET_GAIN(x) ((x) << DGAIN_SFT) ++ ++#endif //__AS_DMIC_H__ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-dsp.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-dsp.c.patch new file mode 100644 index 00000000..7828799a --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-dsp.c.patch @@ -0,0 +1,482 @@ +diff -drupN a/sound/soc/ingenic/as-v2/as-dsp.c b/sound/soc/ingenic/as-v2/as-dsp.c +--- a/sound/soc/ingenic/as-v2/as-dsp.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/as-v2/as-dsp.c 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,478 @@ ++/* ++ * ALSA Soc Audio Layer -- ingenic as(audio system) dsp (dbus) driver ++ * ++ * Copyright 2017 - 2022 Ingenic Semiconductor Co.,Ltd ++ * cli ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "as-dsp.h" ++ ++static const char *const lo_names[LI_PORT_MAX_NUM] = { ++ "LO0_MUX", "LO1_MUX", "LO2_MUX", "LO3_MUX", "LO4_MUX", ++ "LO5_MUX", "LO6_MUX", "LO7_MUX", "LO8_MUX", "LO9_MUX", ++ "LO10_MUX", "LO11_MUX", "LO12_MUX", "LO13_MUX", "LO14_MUX", ++ "LO15_MUX" ++}; ++ ++#define LO_MUX_ITEMS_CNT (LI_PORT_MAX_NUM + 1) ++static const char *const mux_item_names[LO_MUX_ITEMS_CNT] = { ++ "UNUSED", "LI0", "LI1", "LI2", "LI3", "LI4", ++ "LI5", "LI6", "LI7", "LI8", "LI9", ++ "LI10", "LI11", "LI12", "LI13", "LI14", ++ "LI15" ++}; ++#define LO_PORT_NAME(num) lo_names[num] ++#define LI_PORT_NAME(num) mux_item_names[(num) + 1] ++#define ITEMS_TO_LI_DEVID(item) (u8)(item != 0 ? (item) - 1 : LI_PORT_MAX_NUM) ++ ++static struct ingenic_dsp_port *ingenic_dsp_get_port(struct ingenic_as_dsp *as_dsp, ++ u8 dev_id, bool is_out) ++{ ++ int idx; ++ ++ if (!as_dsp) ++ return NULL; ++ ++ if (!is_out) { ++ if (unlikely(dev_id >= LI_PORT_MAX_NUM)) ++ return NULL; ++ idx = LI_DEVID_TO_IDX(dev_id); ++ } else { ++ if (unlikely(dev_id >= LO_PORT_MAX_NUM)) ++ return NULL; ++ idx = LO_DEVID_TO_IDX(dev_id); ++ } ++ ++ if (as_dsp->port[idx].vaild) ++ return &as_dsp->port[idx]; ++ else ++ return NULL; ++} ++ ++static inline u8 ingenic_timeslot_alloc(struct ingenic_as_dsp *as_dsp) ++{ ++ int id; ++ id = find_first_zero_bit(as_dsp->slot_bitmap, SLOT_NUM); ++ bitmap_set(as_dsp->slot_bitmap, id, 1); ++ return id + 1; /*skip unused slot id 0*/ ++} ++ ++static inline void ingenic_timeslot_free(struct ingenic_as_dsp *as_dsp, u8 id) ++{ ++ if (!id) /*skip unused slot id 0*/ ++ return; ++ bitmap_clear(as_dsp->slot_bitmap, (id - 1), 1); ++} ++ ++/*Must under as_dsp mutex*/ ++static void ingenic_dsp_free_timesolt(struct ingenic_as_dsp *as_dsp, ++ struct ingenic_as_dsp_enum *e) ++{ ++ struct ingenic_dsp_port *lo, *li; ++ unsigned long reg, sft; ++ ++ lo = ingenic_dsp_get_port(as_dsp, e->dev_id, true); ++ if (!lo || !lo->timeslot) ++ return; ++ ++ /*clear target device timeslot*/ ++ reg = ingenic_get_dsp_port_register(e->dev_id, &sft, true); ++ regmap_update_bits(as_dsp->regmap, reg, BSORTT_MSK(sft), 0); ++ lo->timeslot = 0; ++ list_del(&lo->node); ++ ++ li = (struct ingenic_dsp_port *)lo->private; ++ if (li && list_empty(&li->head)) { ++ /*clear source device timeslot*/ ++ reg = ingenic_get_dsp_port_register(li->dev_id, &sft, false); ++ regmap_update_bits(as_dsp->regmap, reg, BSORTT_MSK(sft), 0); ++ ++ /*disable and free timeslot*/ ++ regmap_update_bits(as_dsp->regmap, BTCLR, BT_TSLOT(li->timeslot), BT_TSLOT(li->timeslot)); ++ ++ ingenic_timeslot_free(as_dsp, li->timeslot); ++ ++ li->timeslot = 0; ++ } ++ lo->private = NULL; ++} ++ ++static int ingenic_dsp_request_timesolt(struct ingenic_as_dsp *as_dsp, ++ struct ingenic_as_dsp_enum *e, int item) ++{ ++ struct ingenic_dsp_port *lo, *li; ++ unsigned long reg, sft; ++ ++ /*zero is unused*/ ++ if (item == 0) ++ return 0; ++ ++ li = ingenic_dsp_get_port(as_dsp, ITEMS_TO_LI_DEVID(item), false); ++ lo = ingenic_dsp_get_port(as_dsp, e->dev_id, true); ++ if (!li || !lo) { ++ dev_err(as_dsp->dev, "request timeslot: get %s port(%u) failed\n", ++ li ? "lo" : "li", li ? e->dev_id : ITEMS_TO_LI_DEVID(item)); ++ return -ENODEV; ++ } ++ ++ if (WARN(lo->timeslot, "[as-dsp]request timeslot: lo port (%u)has been request\n", ++ e->dev_id)) ++ return -EBUSY; ++ ++ if (li->timeslot == 0) { ++ /*config bus source timeslot*/ ++ li->timeslot = ingenic_timeslot_alloc(as_dsp); ++ reg = ingenic_get_dsp_port_register(li->dev_id, &sft, false); ++ regmap_update_bits(as_dsp->regmap, reg, BSORTT_MSK(sft), BSORTT(li->timeslot, sft)); ++ } ++ ++ /*config bus target timeslot*/ ++ lo->timeslot = li->timeslot; ++ reg = ingenic_get_dsp_port_register(lo->dev_id, &sft, true); ++ regmap_update_bits(as_dsp->regmap, reg, BSORTT_MSK(sft), BSORTT(lo->timeslot, sft)); ++ ++ /*enable timeslot*/ ++ regmap_update_bits(as_dsp->regmap, BTSET, BT_TSLOT(li->timeslot), BT_TSLOT(li->timeslot)); ++ ++ list_add_tail(&lo->node, &li->head); ++ lo->private = (void *)li; ++ return 0; ++} ++ ++static int ingenic_lomux_dapm_get_enum(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct ingenic_as_dsp_enum *e = (struct ingenic_as_dsp_enum *)kcontrol->private_value; ++ ucontrol->value.enumerated.item[0] = e->value; ++ return 0; ++} ++ ++static int ingenic_lomux_dapm_put_enum(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); ++ struct snd_soc_component *component = snd_soc_dapm_to_component(dapm); ++ struct ingenic_as_dsp *as_dsp = (struct ingenic_as_dsp *)snd_soc_component_get_drvdata(component); ++ struct ingenic_as_dsp_enum *e = (struct ingenic_as_dsp_enum *)kcontrol->private_value; ++ unsigned int item = ucontrol->value.enumerated.item[0]; ++ unsigned int change = 0; ++ ++ if (item >= e->e.items) ++ return -EINVAL; ++ ++ mutex_lock(&as_dsp->dapm_mutex); ++ if (e->value != item) { ++ change = 1; ++ e->value = item; ++ } ++ if (change) { ++ /*free old timeslot*/ ++ ingenic_dsp_free_timesolt(as_dsp, e); ++ ++ /*alloc new timeslot*/ ++ ingenic_dsp_request_timesolt(as_dsp, e, item); ++ ++ snd_soc_dapm_mux_update_power(dapm, kcontrol, item, (struct soc_enum *)e, NULL); ++ } ++ mutex_unlock(&as_dsp->dapm_mutex); ++ ++ return change; ++} ++ ++static struct ingenic_as_dsp_enum lomux_enum[] = { /*not const*/ ++#define LOMUX_SOC_ENUM(_dev_id) \ ++ { \ ++ .e = SOC_ENUM_SINGLE_EXT(LO_MUX_ITEMS_CNT, mux_item_names), \ ++ .dev_id = _dev_id, \ ++ .value = 0, \ ++ } ++ LOMUX_SOC_ENUM(0), ++ LOMUX_SOC_ENUM(1), ++ LOMUX_SOC_ENUM(2), ++ LOMUX_SOC_ENUM(3), ++ LOMUX_SOC_ENUM(4), ++ LOMUX_SOC_ENUM(5), ++ LOMUX_SOC_ENUM(6), ++ LOMUX_SOC_ENUM(7), ++ LOMUX_SOC_ENUM(8), ++ LOMUX_SOC_ENUM(9), ++ LOMUX_SOC_ENUM(10), ++ LOMUX_SOC_ENUM(11), ++ LOMUX_SOC_ENUM(12), ++ LOMUX_SOC_ENUM(13), ++ LOMUX_SOC_ENUM(14), ++ LOMUX_SOC_ENUM(15), ++#undef LOMUX_SOC_ENUM ++}; ++ ++static const struct snd_kcontrol_new lomux_controls[] = { ++#define LOMUX_SOC_DAPM_ENUM_EXT(dev_id) \ ++ SOC_DAPM_ENUM_EXT("route", lomux_enum[(dev_id)], \ ++ ingenic_lomux_dapm_get_enum, \ ++ ingenic_lomux_dapm_put_enum) ++ LOMUX_SOC_DAPM_ENUM_EXT(0), ++ LOMUX_SOC_DAPM_ENUM_EXT(1), ++ LOMUX_SOC_DAPM_ENUM_EXT(2), ++ LOMUX_SOC_DAPM_ENUM_EXT(3), ++ LOMUX_SOC_DAPM_ENUM_EXT(4), ++ LOMUX_SOC_DAPM_ENUM_EXT(5), ++ LOMUX_SOC_DAPM_ENUM_EXT(6), ++ LOMUX_SOC_DAPM_ENUM_EXT(7), ++ LOMUX_SOC_DAPM_ENUM_EXT(8), ++ LOMUX_SOC_DAPM_ENUM_EXT(9), ++ LOMUX_SOC_DAPM_ENUM_EXT(10), ++ LOMUX_SOC_DAPM_ENUM_EXT(11), ++ LOMUX_SOC_DAPM_ENUM_EXT(12), ++ LOMUX_SOC_DAPM_ENUM_EXT(13), ++ LOMUX_SOC_DAPM_ENUM_EXT(14), ++ LOMUX_SOC_DAPM_ENUM_EXT(15), ++#undef LOMUX_SOC_DAPM_ENUM_EXT ++}; ++ ++static int ingenic_as_dsp_widget_event(struct snd_soc_dapm_widget* widget, ++ struct snd_kcontrol *kcontrol, int event) ++{ ++ if (event == SND_SOC_DAPM_PRE_PMU) { ++ struct snd_soc_dapm_context *dapm = widget->dapm; ++ struct snd_soc_component *component = snd_soc_dapm_to_component(dapm); ++ struct ingenic_as_dsp *as_dsp = (struct ingenic_as_dsp *)snd_soc_component_get_drvdata(component); ++ int id , is_out = true; ++ ++ if (widget->id == snd_soc_dapm_aif_in) ++ is_out = false; ++ id = (int)widget->priv; ++ printk("flush %s fifo %d \n", is_out ? "tx" : "rx", id); ++ regmap_update_bits(as_dsp->regmap, BFCR0, BFCR0_DEV_TF_MSK|BFCR0_DEV_RF_MSK, ++ is_out ? BFCR0_DEV_TF(id) : BFCR0_DEV_RF(id)); ++ } ++ return 0; ++} ++ ++static const char *const dai_name[] = { ++ "DMA0", "DMA1", "DMA2", "DMA3", "DMA4", ++ "DMA5", "DMA6", "DMA7", "DMA8", "DMA9" ++}; ++ ++static int ingenic_as_dsp_probe(struct platform_device *pdev) ++{ ++ int ret, i, num_routes, num_widgets, num_dais, id; ++ struct ingenic_as_dsp *as_dsp; ++ struct resource *res; ++ struct property *prop; ++ const __be32 *p; ++ bool full_path = false; ++ struct snd_soc_dapm_route *dapm_routes; ++ struct snd_soc_dapm_widget *dapm_widgets; ++ struct snd_soc_dai_driver *fe_dais; ++ struct regmap_config regmap_config = { ++ .reg_bits = 32, ++ .reg_stride = 4, ++ .val_bits = 32, ++ .cache_type = REGCACHE_NONE, ++ }; ++ ++ as_dsp = devm_kzalloc(&pdev->dev, sizeof(struct ingenic_as_dsp), GFP_KERNEL); ++ if (!as_dsp) ++ return -ENOMEM; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ as_dsp->base_addr = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(as_dsp->base_addr)) ++ return PTR_ERR(as_dsp->base_addr); ++ regmap_config.max_register = resource_size(res) - 0x4; ++ as_dsp->regmap = devm_regmap_init_mmio(&pdev->dev, as_dsp->base_addr, ++ ®map_config); ++ if (IS_ERR(as_dsp->regmap)) ++ return PTR_ERR(as_dsp->regmap); ++ ++ as_dsp->dev = &pdev->dev; ++ mutex_init(&as_dsp->dapm_mutex); ++ bitmap_zero(as_dsp->slot_bitmap, SLOT_NUM); ++ ++ /*init dsp port*/ ++ for (i = 0; i < LI_PORT_MAX_NUM; i++) { ++ as_dsp->port[LI_DEVID_TO_IDX(i)].dev_id = i; ++ INIT_LIST_HEAD(&as_dsp->port[LI_DEVID_TO_IDX(i)].head); ++ } ++ ++ for (i = 0; i < LO_PORT_MAX_NUM; i++) { ++ as_dsp->port[LO_DEVID_TO_IDX(i)].dev_id = i; ++ as_dsp->port[LO_DEVID_TO_IDX(i)].is_out = true; ++ INIT_LIST_HEAD(&as_dsp->port[LO_DEVID_TO_IDX(i)].node); ++ } ++ ++ as_dsp->num_li_ports = of_property_count_u32_elems(pdev->dev.of_node, "ingenic,li-port"); ++ if (as_dsp->num_li_ports <= 0 || as_dsp->num_li_ports > LI_PORT_MAX_NUM) ++ return -EINVAL; ++ as_dsp->num_lo_ports = of_property_count_u32_elems(pdev->dev.of_node, "ingenic,lo-port"); ++ if (as_dsp->num_lo_ports <= 0 || as_dsp->num_lo_ports > LO_PORT_MAX_NUM) ++ return -EINVAL; ++ ++ /*init widgets*/ ++ num_widgets = as_dsp->num_li_ports + as_dsp->num_lo_ports; ++ dapm_widgets = devm_kzalloc(&pdev->dev, ++ sizeof(struct snd_soc_dapm_widget) * num_widgets, ++ GFP_KERNEL); ++ i = 0; ++ of_property_for_each_u32(pdev->dev.of_node, "ingenic,li-port", prop, p, id) { ++ dapm_widgets[i].id = snd_soc_dapm_aif_in; ++ dapm_widgets[i].name = LI_PORT_NAME(id); ++ dapm_widgets[i].reg = SND_SOC_NOPM; ++ dapm_widgets[i].event = ingenic_as_dsp_widget_event; ++ dapm_widgets[i].priv = (void *)id; ++ dapm_widgets[i++].event_flags = SND_SOC_DAPM_PRE_PMU; ++ as_dsp->port[LI_DEVID_TO_IDX(id)].vaild = true; ++ } ++ of_property_for_each_u32(pdev->dev.of_node, "ingenic,lo-port", prop, p, id) { ++ dapm_widgets[i].id = snd_soc_dapm_mux; ++ dapm_widgets[i].name = LO_PORT_NAME(id); ++ dapm_widgets[i].reg = SND_SOC_NOPM; ++ dapm_widgets[i].kcontrol_news = &lomux_controls[id]; ++ dapm_widgets[i].num_kcontrols = 1; ++ dapm_widgets[i].event = ingenic_as_dsp_widget_event; ++ dapm_widgets[i].priv = (void *)id; ++ dapm_widgets[i++].event_flags = SND_SOC_DAPM_PRE_PMU; ++ as_dsp->port[LO_DEVID_TO_IDX(id)].vaild = true; ++ } ++ ++ /*init routes*/ ++ num_routes = of_property_count_strings(pdev->dev.of_node, "ingenic,routes"); ++ num_routes /= 2; ++ if (num_routes <= 0 || num_routes & 0x1) { ++ full_path = true; ++ num_routes = as_dsp->num_li_ports * as_dsp->num_lo_ports; ++ } ++ ++ dapm_routes = devm_kzalloc(&pdev->dev, ++ sizeof(struct snd_soc_dapm_route) * num_routes, ++ GFP_KERNEL); ++ if (!dapm_routes) ++ return -ENOMEM; ++ ++ if (full_path) { ++ struct property *prop1; ++ const __be32 *p1; ++ int id1; ++ i = 0; ++ of_property_for_each_u32(pdev->dev.of_node, "ingenic,lo-port", prop, p, id) { ++ of_property_for_each_u32(pdev->dev.of_node, "ingenic,li-port", prop1, p1, id1) { ++ dapm_routes[i].source = dapm_routes[i].control = LI_PORT_NAME(id1); ++ dapm_routes[i++].sink = LO_PORT_NAME(id); ++ } ++ } ++ } else { ++ for (i = 0; i < num_routes; i++) { ++ of_property_read_string_index(pdev->dev.of_node, "ingenic,routes", ++ 2 * i, &dapm_routes[i].sink); ++ of_property_read_string_index(pdev->dev.of_node, "ingenic,routes", ++ (2 * i) + 1, &dapm_routes[i].source); ++ dapm_routes[i].control = dapm_routes[i].source; ++ } ++ } ++ ++ /*init component driver*/ ++ as_dsp->cmpnt_drv.name = "ingenic-as-dsp"; ++ as_dsp->cmpnt_drv.dapm_widgets = dapm_widgets; ++ as_dsp->cmpnt_drv.num_dapm_widgets = num_widgets; ++ as_dsp->cmpnt_drv.dapm_routes = dapm_routes; ++ as_dsp->cmpnt_drv.num_dapm_routes = num_routes; ++ platform_set_drvdata(pdev, as_dsp); ++ ++ /*init dais*/ ++ if (of_property_read_u32(pdev->dev.of_node, "ingenic,num-dais", &num_dais)) ++ return -ENODEV; ++ ++ if (of_property_read_u32(pdev->dev.of_node, "ingenic,cap-dai-bm", &as_dsp->cap_dai_bitmsk)) ++ return -ENODEV; ++ ++ fe_dais = devm_kzalloc(&pdev->dev, sizeof(*fe_dais) * num_dais, GFP_KERNEL); ++ if (!fe_dais) ++ return -ENOMEM; ++ ++ for (i = 0; i < num_dais; i++) { ++ fe_dais[i].name = dai_name[i]; ++ fe_dais[i].id = i; ++ if ((BIT(i) & as_dsp->cap_dai_bitmsk)) { ++ fe_dais[i].capture.stream_name = dai_name[i]; ++ fe_dais[i].capture.channels_min = 1; ++ fe_dais[i].capture.channels_max = 12; ++ fe_dais[i].capture.rates = SNDRV_PCM_RATE_8000_192000; ++ fe_dais[i].capture.formats = ~0ULL; ++ } else { ++ fe_dais[i].playback.stream_name = dai_name[i]; ++ fe_dais[i].playback.channels_min = 1; ++ fe_dais[i].playback.channels_max = 8; ++ fe_dais[i].playback.rates = SNDRV_PCM_RATE_8000_192000; ++ fe_dais[i].playback.formats = ~0ULL; ++ } ++ } ++ ++ regmap_write(as_dsp->regmap, BFCR2, BFCR2_DEV_DBE_MSK); ++ ++ ret = snd_soc_register_component(&pdev->dev, ++ &as_dsp->cmpnt_drv, ++ fe_dais, num_dais); ++ if (ret) ++ return ret; ++ ++ dev_info(&pdev->dev, "probe success!!\n"); ++ return 0; ++} ++ ++static int ingenic_as_dsp_remove(struct platform_device *pdev) ++{ ++ snd_soc_unregister_component(&pdev->dev); ++ platform_set_drvdata(pdev, NULL); ++ return 0; ++} ++ ++static const struct of_device_id ingenic_as_dsp_match_table[] = { ++ { .compatible = "ingenic,as-dsp", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, ingenic_as_dsp_match_table); ++ ++#ifdef CONFIG_PM ++static int ingenic_as_dsp_runtime_suspend(struct device *dev) ++{ ++ return 0; ++} ++ ++static int ingenic_as_dsp_runtime_resume(struct device *dev) ++{ ++ return 0; ++} ++#endif ++ ++static const struct dev_pm_ops ingenic_as_dsp_pm_ops = { ++ SET_RUNTIME_PM_OPS(ingenic_as_dsp_runtime_suspend, ++ ingenic_as_dsp_runtime_resume, NULL) ++}; ++ ++static struct platform_driver ingenic_as_dsp_platform_driver = { ++ .driver = { ++ .name = "as-dsp", ++ .of_match_table = ingenic_as_dsp_match_table, ++ .pm = &ingenic_as_dsp_pm_ops, ++ }, ++ .probe = ingenic_as_dsp_probe, ++ .remove = ingenic_as_dsp_remove, ++}; ++module_platform_driver(ingenic_as_dsp_platform_driver); ++ ++MODULE_AUTHOR("cli "); ++MODULE_DESCRIPTION("Ingenic AS DSP SoC Interface"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:ingenic-as-dsp"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-dsp.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-dsp.h.patch new file mode 100644 index 00000000..7d07afde --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-dsp.h.patch @@ -0,0 +1,152 @@ +diff -drupN a/sound/soc/ingenic/as-v2/as-dsp.h b/sound/soc/ingenic/as-v2/as-dsp.h +--- a/sound/soc/ingenic/as-v2/as-dsp.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/as-v2/as-dsp.h 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,148 @@ ++/* ++ * ALSA Soc Audio Layer -- Ingenic AS DBUS Controller ++ * ++ * Copyright 2017 - 2022 Ingenic Semiconductor Co.,Ltd ++ * cli ++ * ++ * 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. ++ */ ++#ifndef __AS_FE_DSP_H__ ++#define __AS_FE_DSP_H__ ++ ++#include ++/* BUS */ ++#define BTSET 0x0 /* BUS TimeSlot Set Register */ ++#define BTCLR 0x4 /* BUS TimeSlot Clear Register */ ++#define BTSR 0x8 /* BUS TimeSlot Status Register */ ++#define BFSR 0xc /* BUS FIFO Status Register(TUR/ROR)*/ ++#define BFCR0 0x10 /* BUS FIFO Control Register0(FLUSH FIFO)*/ ++#define BFCR1 0X14 /* BUS FIFO Control Register1(TX ZERO SAMPLE)*/ ++#define BFCR2 0x18 /* BUS FIFO Control Register2(BLOKING RX FIFO)*/ ++#define BST0 0x1c /* BUS Source Timeslot0 */ ++#define BST1 0x20 /* BUS Source Timeslot1 */ ++#define BST2 0x24 /* BUS Source Timeslot2 */ ++#define BTT0 0x28 /* BUS Target Timeslot0 */ ++#define BTT1 0x2c /* BUS Target Timeslot1 */ ++ ++#define BT_TSLOT(slot) BIT(slot) ++ ++#define BFSR_DEV_TUR_SFT (16) ++#define BFSR_DEV_TUR(lo_dev_id) BIT(((lo_dev_id) + BFSR_DEV_TUR_SFT)) ++#define BFSR_DEV_ROR_SFT (0) ++#define BFSR_DEV_ROR(li_dev_id) BIT(((li_dev_id) + BFSR_DEV_ROR_SFT)) ++ ++#define BFCR0_DEV_TF_SFT (16) ++#define BFCR0_DEV_TF_MSK GENMASK(31, BFCR0_DEV_TF_SFT) ++#define BFCR0_DEV_TF(lo_dev_id) BIT(((lo_dev_id) + BFCR0_DEV_TF_SFT)) ++#define BFCR0_DEV_RF_SFT (0) ++#define BFCR0_DEV_RF_MSK GENMASK(15, BFCR0_DEV_RF_SFT) ++#define BFCR0_DEV_RF(li_dev_id) BIT(((li_dev_id) + BFCR0_DEV_RF_SFT)) ++ ++#define BFCR1_DEV_LSMP(lo_dev_id) BIT(lo_dev_id) ++#define BFCR2_DEV_DBE_MSK GENMASK(14, 0) ++#define BFCR2_DEV_DBE(li_dev_id) BIT(li_dev_id) ++ ++#define BST0_DEV0_SUR_SFT (0) ++#define BST0_DEV1_SUR_SFT (5) ++#define BST0_DEV2_SUR_SFT (10) ++#define BST0_DEV3_SUR_SFT (16) ++#define BST0_DEV4_SUR_SFT (21) ++#define BST0_DEV5_SUR_SFT (26) ++ ++#define BST1_DEV6_SUR_SFT (0) ++#define BST1_DEV7_SUR_SFT (5) ++#define BST1_DEV8_SUR_SFT (10) ++#define BST1_DEV9_SUR_SFT (16) ++#define BST1_DEV10_SUR_SFT (21) ++ ++#define BST2_DEV11_SUR_SFT (0) ++#define BST2_DEV12_SUR_SFT (5) ++#define BST2_DEV13_SUR_SFT (10) ++#define BST2_DEV14_SUR_SFT (16) ++ ++#define BTT0_DEV0_TAR_SFT (0) ++#define BTT0_DEV1_TAR_SFT (5) ++#define BTT0_DEV2_TAR_SFT (10) ++#define BTT0_DEV3_TAR_SFT (16) ++#define BTT0_DEV4_TAR_SFT (21) ++#define BTT0_DEV5_TAR_SFT (26) ++ ++#define BTT1_DEV6_TAR_SFT (0) ++#define BTT1_DEV7_TAR_SFT (5) ++#define BTT1_DEV8_TAR_SFT (10) ++#define BTT1_DEV9_TAR_SFT (16) ++#define BTT1_DEV10_TAR_SFT (21) ++#define BTT1_DEV11_TAR_SFT (26) ++ ++#define BSORTT_WITDH (5) ++#define BSORTT_MSK(shift) GENMASK(((shift) + BSORTT_WITDH - 1), shift) ++#define BSORTT(slot, shift) (((slot) << (shift)) & BSORTT_MSK(shift)) ++ ++static inline unsigned long ingenic_get_dsp_port_register(int dev_id, ++ unsigned long *shift, bool is_out) ++{ ++ if (is_out) { ++ u8 reg[12] = {BTT0, BTT0, BTT0, BTT0, BTT0, BTT0, ++ BTT1, BTT1, BTT1, BTT1, BTT1, BTT1}; ++ u8 sft[12] = {BTT0_DEV0_TAR_SFT, BTT0_DEV1_TAR_SFT, BTT0_DEV2_TAR_SFT, ++ BTT0_DEV3_TAR_SFT, BTT0_DEV4_TAR_SFT, BTT0_DEV5_TAR_SFT, ++ BTT1_DEV6_TAR_SFT, BTT1_DEV7_TAR_SFT, BTT1_DEV8_TAR_SFT, ++ BTT1_DEV9_TAR_SFT, BTT1_DEV10_TAR_SFT, BTT1_DEV11_TAR_SFT}; ++ *shift = (unsigned long)sft[dev_id]; ++ return (unsigned long)reg[dev_id]; ++ } else { ++ u8 reg[15] = {BST0, BST0, BST0, BST0, BST0, BST0, ++ BST1, BST1, BST1, BST1, BST1, ++ BST2, BST2, BST2, BST2}; ++ u8 sft[15] = {BST0_DEV0_SUR_SFT, BST0_DEV1_SUR_SFT, BST0_DEV2_SUR_SFT, ++ BST0_DEV3_SUR_SFT, BST0_DEV4_SUR_SFT, BST0_DEV5_SUR_SFT, ++ BST1_DEV6_SUR_SFT, BST1_DEV7_SUR_SFT, BST1_DEV8_SUR_SFT, ++ BST1_DEV9_SUR_SFT, BST1_DEV10_SUR_SFT, BST2_DEV11_SUR_SFT, ++ BST2_DEV12_SUR_SFT, BST2_DEV13_SUR_SFT, BST2_DEV14_SUR_SFT ++ }; ++ *shift = (unsigned long)sft[dev_id]; ++ return (unsigned long)reg[dev_id]; ++ } ++} ++ ++struct ingenic_dsp_port { ++ union { ++ struct list_head node; /* for lineout*/ ++ struct list_head head; /* for linein */ ++ }; ++ u8 dev_id; /*port id*/ ++ u8 timeslot; ++ bool is_out; ++ bool vaild; ++ void *private; ++}; ++ ++#define LI_PORT_MAX_NUM 16 ++#define LO_PORT_MAX_NUM 16 ++#define PORT_MAX_NUM (LI_PORT_MAX_NUM + LO_PORT_MAX_NUM) ++ ++struct ingenic_as_dsp { ++ void * __iomem base_addr; ++ struct regmap *regmap; ++ struct device *dev; ++#define SLOT_NUM (31) ++ unsigned long slot_bitmap[BITS_TO_LONGS(SLOT_NUM)]; ++#define LI_DEVID_TO_IDX(dev_id) (dev_id) ++#define LO_DEVID_TO_IDX(dev_id) ((dev_id) + LI_PORT_MAX_NUM) ++ struct ingenic_dsp_port port[PORT_MAX_NUM]; ++ int num_li_ports; ++ int num_lo_ports; ++ struct snd_soc_component_driver cmpnt_drv; ++ struct mutex dapm_mutex; ++ u32 cap_dai_bitmsk; ++}; ++ ++struct ingenic_as_dsp_enum { ++ struct soc_enum e; ++ u8 dev_id; ++ int value; ++}; ++#endif /*__AS_FE_DSP_H__*/ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-fmtcov.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-fmtcov.c.patch new file mode 100644 index 00000000..a2c74c0a --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-fmtcov.c.patch @@ -0,0 +1,176 @@ +diff -drupN a/sound/soc/ingenic/as-v2/as-fmtcov.c b/sound/soc/ingenic/as-v2/as-fmtcov.c +--- a/sound/soc/ingenic/as-v2/as-fmtcov.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/as-v2/as-fmtcov.c 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,172 @@ ++/* ++ * ALSA Soc Audio Layer -- Ingenic AS fmtcov driver ++ * ++ * Copyright 2017 - 2022 Ingenic Semiconductor Co.,Ltd ++ * wqshao ++ * ++ * 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. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "as-fmtcov.h" ++#include "as-dma.h" ++ ++#ifdef DEBUG ++static int ingenic_fmtcov_debug = 1; ++#else ++static int ingenic_fmtcov_debug = 0; ++#endif ++module_param(ingenic_fmtcov_debug, int, 0644); ++#define FMTCOV_DEBUG_MSG(msg...) \ ++ do { \ ++ if (ingenic_fmtcov_debug) \ ++ printk(KERN_DEBUG"FMTCOV: " msg); \ ++ } while(0) ++ ++static struct ingenic_as_fmtcov *as_fmtcov; ++ ++static bool ingenic_fmt_need_packen(snd_pcm_format_t format) ++{ ++ switch (format) { ++ case SNDRV_PCM_FORMAT_S24_3LE: ++ case SNDRV_PCM_FORMAT_U24_3LE: ++ case SNDRV_PCM_FORMAT_S20_3LE: ++ case SNDRV_PCM_FORMAT_U20_3LE: ++ case SNDRV_PCM_FORMAT_S18_3LE: ++ case SNDRV_PCM_FORMAT_U18_3LE: ++ case SNDRV_PCM_FORMAT_S24_3BE: ++ case SNDRV_PCM_FORMAT_U24_3BE: ++ case SNDRV_PCM_FORMAT_S20_3BE: ++ case SNDRV_PCM_FORMAT_U20_3BE: ++ case SNDRV_PCM_FORMAT_S18_3BE: ++ case SNDRV_PCM_FORMAT_U18_3BE: ++ return true; ++ default: ++ break; ++ } ++ ++ return false; ++} ++ ++static void ingenic_as_fmtcov_fix_match_mod(u8 dai_id, u32 fmtcfg) ++{ ++ as_fmtcov->fmtcfg[dai_id] = fmtcfg; ++} ++ ++int ingenic_spdif_fmtcov_be_fix(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ struct ingenic_as_dma_runtime *prtd = substream_to_prtd(substream); ++ u32 fmtcfg = 0; ++ ++ if (WARN(prtd->dai_id > FMT_CHL_NUM, "[as-fmtcov]: %s dai_id(%d) out of range\n", ++ __func__, prtd->dai_id)) ++ return -ECHRNG; ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ fmtcfg = DFCR_SS(params_width(params)) | DFCR_CHNUM(1); ++ } else { ++ fmtcfg = DFCR_SS(32) | DFCR_CHNUM(1); ++ } ++ if (ingenic_fmt_need_packen(params_format(params))) ++ fmtcfg |= DFCR_PACKEN; ++ ++ ingenic_as_fmtcov_fix_match_mod(prtd->dai_id, fmtcfg); ++ return 0; ++} ++EXPORT_SYMBOL_GPL(ingenic_spdif_fmtcov_be_fix); ++ ++int ingenic_as_fmtcov_cfg(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ struct ingenic_as_dma_runtime *prtd = substream_to_prtd(substream); ++ u32 fmtcfg; ++ ++ if (WARN(prtd->dai_id > FMT_CHL_NUM, "[as-fmtcov]: %s dai_id(%d) out of range\n", ++ __func__, prtd->dai_id)) ++ return -ECHRNG; ++ ++ fmtcfg = DFCR_SS(params_width(params)) | DFCR_CHNUM(params_channels(params)); ++ if (ingenic_fmt_need_packen(params_format(params))) ++ fmtcfg |= DFCR_PACKEN; ++ ++ if (as_fmtcov->fmtcfg[prtd->dai_id]) { ++ fmtcfg = as_fmtcov->fmtcfg[prtd->dai_id]; ++ as_fmtcov->fmtcfg[prtd->dai_id] = 0; ++ } ++ ++ FMTCOV_DEBUG_MSG("enter %s, fmtcov DFCR%d = 0x%08x\n", __func__, prtd->dai_id, fmtcfg); ++ writel_relaxed(fmtcfg, as_fmtcov->io_base + DFCR(prtd->dai_id)); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(ingenic_as_fmtcov_cfg); ++ ++void ingenic_as_fmtcov_enable(u8 dai_id, bool enable) ++{ ++ regmap_update_bits(as_fmtcov->regmap, DFCR(dai_id), DFCR_ENABLE, enable ? DFCR_ENABLE : 0); ++} ++EXPORT_SYMBOL_GPL(ingenic_as_fmtcov_enable); ++ ++static int ingenic_as_fmtcov_platform_probe(struct platform_device *pdev) ++{ ++ struct resource *res; ++ struct regmap_config regmap_config = { ++ .reg_bits = 32, ++ .reg_stride = 4, ++ .val_bits = 32, ++ .cache_type = REGCACHE_NONE, ++ }; ++ ++ as_fmtcov = devm_kzalloc(&pdev->dev, sizeof(struct ingenic_as_fmtcov), GFP_KERNEL); ++ if (!as_fmtcov) ++ return -ENOMEM; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ as_fmtcov->io_base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(as_fmtcov->io_base)) ++ return PTR_ERR(as_fmtcov->io_base); ++ regmap_config.max_register = resource_size(res) - 0x4; ++ as_fmtcov->regmap = devm_regmap_init_mmio(&pdev->dev, as_fmtcov->io_base, ++ ®map_config); ++ if (IS_ERR(as_fmtcov->regmap)) ++ return PTR_ERR(as_fmtcov->regmap); ++ as_fmtcov->dev = &pdev->dev; ++ ++ platform_set_drvdata(pdev, as_fmtcov); ++ return 0; ++} ++ ++static int ingenic_as_fmtcov_platform_remove(struct platform_device *pdev) ++{ ++ return 0; ++} ++ ++static const struct of_device_id ingenic_as_fmtcov_match_table[] = { ++ { .compatible = "ingenic,as-fmtcov", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, ingenic_as_fmtcov_match_table); ++ ++static struct platform_driver ingenic_as_fmtcov_platform_driver = { ++ .driver = { ++ .name = "as-fmtcov", ++ .of_match_table = ingenic_as_fmtcov_match_table, ++ }, ++ .probe = ingenic_as_fmtcov_platform_probe, ++ .remove = ingenic_as_fmtcov_platform_remove, ++}; ++module_platform_driver(ingenic_as_fmtcov_platform_driver); ++ ++MODULE_AUTHOR("wqshao "); ++MODULE_DESCRIPTION("Ingenic AS fmtcov SoC Interface"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:ingenic-as-fmtcov"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-fmtcov.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-fmtcov.h.patch new file mode 100644 index 00000000..5bb439e3 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-fmtcov.h.patch @@ -0,0 +1,61 @@ +diff -drupN a/sound/soc/ingenic/as-v2/as-fmtcov.h b/sound/soc/ingenic/as-v2/as-fmtcov.h +--- a/sound/soc/ingenic/as-v2/as-fmtcov.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/as-v2/as-fmtcov.h 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,57 @@ ++/* ++ * ALSA Soc Audio Layer -- Ingenic AS fmtcov driver ++ * ++ * Copyright 2017 - 2022 Ingenic Semiconductor Co.,Ltd ++ * wqshao ++ * ++ * 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. ++ */ ++#ifndef __AS_fmtcov__ ++#define __AS_fmtcov__ ++ ++#include ++ ++int ingenic_spdif_fmtcov_be_fix(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params); ++ ++int ingenic_as_fmtcov_cfg(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params); ++void ingenic_as_fmtcov_enable(u8 dai_id, bool enable); ++ ++struct ingenic_as_fmtcov { ++ struct regmap *regmap; ++ struct device *dev; ++ void *__iomem io_base; ++ u8 dai_id; ++#define FMT_CHL_NUM 10 ++ u32 fmtcfg[FMT_CHL_NUM]; ++ uint32_t fmtcov_bitmask; ++}; ++ ++/* FORMAT */ ++#define DFCR0 (0x0) ++ ++#define FMTCOV_OFFSET (0x4) ++#define DFCR(n) ((n) * FMTCOV_OFFSET + DFCR0) ++ ++#define DFCR_CHNUM_SFT (12) ++#define DFCR_CHNUM_MSK GENMASK(15, DFCR_CHNUM_SFT) ++#define DFCR_CHNUM(ch) ((((!((ch) % 2) || ((ch) == 1)) ? ((ch) - 1) : (ch)) << DFCR_CHNUM_SFT) & DFCR_CHNUM_MSK) ++#define DFCR_SS_SFT (8) ++#define DFCR_SS_MSK GENMASK(10, DFCR_SS_SFT) ++#define DFCR_SS_8 (0 << DFCR_SS_SFT) ++#define DFCR_SS_12 (1 << DFCR_SS_SFT) ++#define DFCR_SS_13 (2 << DFCR_SS_SFT) ++#define DFCR_SS_16 (3 << DFCR_SS_SFT) ++#define DFCR_SS_18 (4 << DFCR_SS_SFT) ++#define DFCR_SS_20 (5 << DFCR_SS_SFT) ++#define DFCR_SS_24 (6 << DFCR_SS_SFT) ++#define DFCR_SS_32 (7 << DFCR_SS_SFT) ++#define DFCR_SS(ss) ((ss <= 8) ? DFCR_SS_8 : (ss <= 12) ? DFCR_SS_12 : (ss == 13) ? DFCR_SS_13 : (ss <= 16) ? DFCR_SS_16 : (ss <= 18) ? DFCR_SS_18 : (ss <= 20) ? DFCR_SS_20 : (ss <= 24) ? DFCR_SS_24: DFCR_SS_32) ++#define DFCR_PACKEN BIT(2) ++#define DFCR_ENABLE BIT(0) ++ ++#endif /*__AS_fmtcov__*/ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-mixer.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-mixer.c.patch new file mode 100644 index 00000000..bfb9ad78 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-mixer.c.patch @@ -0,0 +1,175 @@ +diff -drupN a/sound/soc/ingenic/as-v2/as-mixer.c b/sound/soc/ingenic/as-v2/as-mixer.c +--- a/sound/soc/ingenic/as-v2/as-mixer.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/as-v2/as-mixer.c 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,171 @@ ++/* ++ * ALSA Soc Audio Layer -- Ingenic AS MIXER driver ++ * ++ * Copyright 2017 - 2022 Ingenic Semiconductor Co.,Ltd ++ * cli ++ * ++ * 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. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "as-mixer.h" ++ ++static int ingenic_as_mixer_widget_event(struct snd_soc_dapm_widget* widget, ++ struct snd_kcontrol *kcontrol, int event) ++{ ++ if (event == SND_SOC_DAPM_PRE_PMU) { ++ struct snd_soc_dapm_context *dapm = widget->dapm; ++ struct snd_soc_component *component = snd_soc_dapm_to_component(dapm); ++ struct ingenic_as_mixer *as_mixer = (struct ingenic_as_mixer *) ++ snd_soc_component_get_drvdata(component); ++ int id = (int)widget->priv; ++ dev_dbg(as_mixer->dev, "reset mixer[%d]\n", id); ++ regmap_update_bits(as_mixer->regmap, MIX_CTL(id), MIX_RESET, MIX_RESET); ++ } ++ return 0; ++} ++ ++static int ingenic_as_mixer_probe(struct snd_soc_component *cmpnt) ++{ ++ struct ingenic_as_mixer *as_mixer = dev_get_drvdata(cmpnt->dev); ++ int i; ++ ++ for (i = 0; i < as_mixer->num_mixers; i++) { ++ snd_soc_component_update_bits(cmpnt, MIX_CFG(i), ++ MIX_CH_MSK|MIX_MODE_MSK, MIX_CH(2)|MIX_MODE_AVG); ++ } ++ return 0; ++} ++ ++static const char * const ingenic_mixer0_mode_src[] = { ++ "Linear weighted plus", ++ "Average", ++ "Clamping", ++ "Nonlinear Distort", ++}; ++ ++static int ingenic_mixer0_mode_values[] = { ++ 0, 1, 2, 3, ++}; ++ ++static SOC_VALUE_ENUM_SINGLE_DECL(ingenic_mixer0_mode, ++ MIX_CFG(0), MIX_MODE_SFT, ++ 0x3, ingenic_mixer0_mode_src, ++ ingenic_mixer0_mode_values); ++ ++static const struct snd_kcontrol_new ingenic_mixer_controls[] = { ++ /* Mixer0 */ ++ SOC_SINGLE("Mixer0 LR_MIX Switch", MIX_CFG(0), MIX_LR_MIX_SFT, 1, 0), ++ SOC_ENUM("Mixer0 MIX_MODE Option", ingenic_mixer0_mode), ++}; ++ ++static int ingenic_as_mixer_platform_probe(struct platform_device *pdev) ++{ ++ struct ingenic_as_mixer *as_mixer; ++ struct resource *res; ++ struct snd_soc_dapm_widget *dapm_widgets; ++ char *dev_name; ++ int i, ret; ++ struct regmap_config regmap_config = { ++ .reg_bits = 32, ++ .reg_stride = 4, ++ .val_bits = 32, ++ .cache_type = REGCACHE_NONE, ++ }; ++ ++ as_mixer = devm_kzalloc(&pdev->dev, sizeof(struct ingenic_as_mixer), GFP_KERNEL); ++ if (!as_mixer) ++ return -ENOMEM; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ as_mixer->io_base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(as_mixer->io_base)) ++ return PTR_ERR(as_mixer->io_base); ++ regmap_config.max_register = resource_size(res) - 0x4; ++ as_mixer->regmap = devm_regmap_init_mmio(&pdev->dev, as_mixer->io_base, ++ ®map_config); ++ if (IS_ERR(as_mixer->regmap)) ++ return PTR_ERR(as_mixer->regmap); ++ as_mixer->dev = &pdev->dev; ++ ++ if (of_property_read_u32(pdev->dev.of_node, "ingenic,num-mixers", ++ &as_mixer->num_mixers)) ++ return -ENODEV; ++ ++ dapm_widgets = devm_kzalloc(&pdev->dev, ++ sizeof(struct snd_soc_dapm_widget) * as_mixer->num_mixers, ++ GFP_KERNEL); ++ if (!dapm_widgets) ++ return -ENOMEM; ++ ++#define NAME_LEN 10 ++ dev_name = devm_kzalloc(&pdev->dev, ++ sizeof(char)*as_mixer->num_mixers*NAME_LEN, ++ GFP_KERNEL); ++ if (!dev_name) ++ return -ENOMEM; ++ ++ for (i = 0; i < as_mixer->num_mixers; i++) { ++ dapm_widgets[i].id = snd_soc_dapm_mixer; ++ snprintf(&dev_name[i * NAME_LEN], NAME_LEN, "MIX%d", i); ++ dapm_widgets[i].name = &dev_name[i * NAME_LEN]; ++ dapm_widgets[i].reg = MIX_CTL(i); ++ dapm_widgets[i].mask = 1; ++ dapm_widgets[i].shift = MIX_EN_SFT; ++ dapm_widgets[i].on_val = 1; ++ dapm_widgets[i].event = ingenic_as_mixer_widget_event; ++ dapm_widgets[i].priv = (void *)i; ++ dapm_widgets[i++].event_flags = SND_SOC_DAPM_PRE_PMU; ++ } ++#undef NAME_LEN ++ ++ as_mixer->cmpnt_drv.name = "ingenic-as-mixer"; ++ as_mixer->cmpnt_drv.controls = ingenic_mixer_controls; ++ as_mixer->cmpnt_drv.num_controls = ARRAY_SIZE(ingenic_mixer_controls); ++ as_mixer->cmpnt_drv.dapm_widgets = dapm_widgets; ++ as_mixer->cmpnt_drv.num_dapm_widgets = as_mixer->num_mixers; ++ as_mixer->cmpnt_drv.probe = ingenic_as_mixer_probe; ++ ++ platform_set_drvdata(pdev, as_mixer); ++ ++ ret = snd_soc_register_component(&pdev->dev, &as_mixer->cmpnt_drv, ++ NULL, 0); ++ if (!ret) ++ dev_info(&pdev->dev, "baic platform probe success\n"); ++ ++ return ret; ++} ++ ++static int ingenic_as_mixer_platform_remove(struct platform_device *pdev) ++{ ++ snd_soc_unregister_component(&pdev->dev); ++ return 0; ++} ++ ++static const struct of_device_id ingenic_as_mixer_match_table[] = { ++ { .compatible = "ingenic,as-mixer", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, ingenic_as_mixer_match_table); ++ ++static struct platform_driver ingenic_as_mixer_platform_driver = { ++ .driver = { ++ .name = "as-mixer", ++ .of_match_table = ingenic_as_mixer_match_table, ++ }, ++ .probe = ingenic_as_mixer_platform_probe, ++ .remove = ingenic_as_mixer_platform_remove, ++}; ++module_platform_driver(ingenic_as_mixer_platform_driver); ++ ++MODULE_AUTHOR("cli "); ++MODULE_DESCRIPTION("Ingenic AS Mixer SoC Interface"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:ingenic-as-mixer"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-mixer.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-mixer.h.patch new file mode 100644 index 00000000..537d6ff6 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-mixer.h.patch @@ -0,0 +1,54 @@ +diff -drupN a/sound/soc/ingenic/as-v2/as-mixer.h b/sound/soc/ingenic/as-v2/as-mixer.h +--- a/sound/soc/ingenic/as-v2/as-mixer.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/as-v2/as-mixer.h 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,50 @@ ++/* ++ * ALSA Soc Audio Layer -- Ingenic AS MIXER driver ++ * ++ * Copyright 2017 - 2022 Ingenic Semiconductor Co.,Ltd ++ * cli ++ * ++ * 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. ++ */ ++#ifndef __AS_MIXER__ ++#define __AS_MIXER__ ++ ++#include ++ ++#define MIX_OFF (0x4) ++#define MIX_CTL0 (0x0) ++#define MIX_CFG0 (0x4) ++ ++#define MIX_CTL(n) (MIX_CTL0 + (n) * MIX_OFF) ++#define MIX_CFG(n) (MIX_CFG0 + (n) * MIX_OFF) ++ ++#define MIX_RESET BIT(1) ++#define MIX_EN_SFT (0) ++#define MIX_EN BIT(MIX_EN_SFT) ++ ++#define MIX_CH_SFT (5) ++#define MIX_CH_MSK GENMASK(6, MIX_CH_SFT) ++#define MIX_CH(n) ((((n) - 1) << MIX_CH_SFT) & MIX_CH_MSK) ++ ++#define MIX_MODE_SFT (3) ++#define MIX_MODE_MSK GENMASK(4, MIX_MODE_SFT) ++#define MIX_MODE_LWP (0 << MIX_MODE_SFT) ++#define MIX_MODE_AVG (1 << MIX_MODE_SFT) ++#define MIX_MODE_CLMP (2 << MIX_MODE_SFT) ++#define MIX_MODE_NOL (3 << MIX_MODE_SFT) ++ ++#define MIX_LR_MIX_SFT (1) ++#define MIX_LR_MIX BIT(MIX_LR_MIX_SFT) ++#define MIX_LAST_SMP BIT(0) ++ ++struct ingenic_as_mixer { ++ struct regmap *regmap; ++ struct device *dev; ++ void *__iomem io_base; ++ u32 num_mixers; ++ struct snd_soc_component_driver cmpnt_drv; ++}; ++#endif /*__AS_MIXER__*/ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-spdif.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-spdif.c.patch new file mode 100644 index 00000000..4e0629b9 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-spdif.c.patch @@ -0,0 +1,457 @@ +diff -drupN a/sound/soc/ingenic/as-v2/as-spdif.c b/sound/soc/ingenic/as-v2/as-spdif.c +--- a/sound/soc/ingenic/as-v2/as-spdif.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/as-v2/as-spdif.c 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,453 @@ ++/* ++ * ALSA Soc Audio Layer -- ingenic as(audio system) spdif(Basic Audio Inter- ++ * face Controller) driver ++ * ++ * Copyright 2017 - 2022 Ingenic Semiconductor Co.,Ltd ++ * wqshao ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "as-spdif.h" ++ ++#ifdef DEBUG ++static int ingenic_spdif_debug = 1; ++#else ++static int ingenic_spdif_debug = 0; ++#endif ++module_param(ingenic_spdif_debug, int, 0644); ++#define SPDIF_DEBUG_MSG(msg...) \ ++ do { \ ++ if (ingenic_spdif_debug) \ ++ printk("SPDIF: " msg); \ ++ } while(0) ++ ++int __attribute__((weak)) ingenic_spdif_fmtcov_be_fix(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ return 0; ++} ++ ++static int ingenic_spdif_startup(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct ingenic_spdif *spdif = dev_get_drvdata(dai->dev); ++ u32 val, ch_cfg, timeout = 0xfff; ++ ++ SPDIF_DEBUG_MSG("enter %s, substream = %s\n",__func__, ++ (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? ++ "playback" : "capture"); ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ regmap_update_bits(spdif->spdif_out_regmap, SPCFG2, ++ SPO_AUDIO_N|SPO_CON_PRO, spdif->non_pcm ? SPO_AUDIO_N : 0); ++ if (!spdif->non_pcm) { ++ ch_cfg = SPO_SET_SCR_NUM(1) | SPO_SET_CH1_NUM(1) | SPO_SET_CH2_NUM(1); ++ regmap_update_bits(spdif->spdif_out_regmap, SPCFG1, ++ SPO_SCR_NUM_MASK|SPO_CH1_NUM_MASK|SPO_CH2_NUM_MASK, ch_cfg); ++ regmap_update_bits(spdif->spdif_out_regmap, SPCFG2, ++ SPO_CAT_CODE_MASK|SPO_CH_MD_MASK, SPO_CAT_CODE_GEN|SPO_CH_MD_0); ++ } ++ regmap_update_bits(spdif->spdif_out_regmap, SPCTRL, SPO_SFT_RST, 1); ++ do { ++ regmap_read(spdif->spdif_out_regmap, SPCTRL, &val); ++ }while((val & SPO_SFT_RST) && --timeout); ++ if (!timeout) ++ goto error; ++ regmap_update_bits(spdif->spdif_out_regmap, SPCTRL, SPO_INVALID, 0); ++ } else { ++ regmap_update_bits(spdif->spdif_in_regmap, SPIENA, SPI_RESET, SPI_RESET); ++ do { ++ regmap_read(spdif->spdif_in_regmap, SPIENA, &val); ++ } while((val & SPI_RESET) && --timeout); ++ if (!timeout) ++ goto error; ++ } ++ ++ return 0; ++error: ++ pr_err("[ERROR]: %s, %d reset fail ...\n", __func__, __LINE__); ++ return -EIO; ++} ++ ++static int ingenic_spdif_start_substream(struct snd_pcm_substream *substream, ++ struct ingenic_spdif *spdif) ++{ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ regmap_write(spdif->spdif_out_regmap, SPENA, SPO_SPEN); ++ else ++ regmap_update_bits(spdif->spdif_in_regmap, SPIENA, SPI_SPIEN, SPI_SPIEN); ++ ++ return 0; ++} ++ ++static int ingenic_spdif_stop_substream(struct snd_pcm_substream *substream, ++ struct ingenic_spdif *spdif) ++{ ++ u32 val, timeout = 0xfff; ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ regmap_write(spdif->spdif_out_regmap, SPENA, 0); ++ do { ++ regmap_read(spdif->spdif_out_regmap, SPENA, &val); ++ } while((val & SPO_SPEN) && --timeout); ++ if (!timeout) ++ goto error; ++ } else { ++ regmap_update_bits(spdif->spdif_in_regmap, SPIENA, SPI_SPIEN, 0); ++ } ++ ++ return 0; ++error: ++ pr_err("[ERROR]: %s,%d disable fail ...\n", __func__, __LINE__); ++ return -EIO; ++} ++ ++static int ingenic_spdif_trigger(struct snd_pcm_substream *substream, ++ int cmd, struct snd_soc_dai *dai) ++{ ++ struct ingenic_spdif *spdif = dev_get_drvdata(dai->dev); ++ ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ case SNDRV_PCM_TRIGGER_RESUME: ++ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: ++ SPDIF_DEBUG_MSG("start\n"); ++ ingenic_spdif_start_substream(substream, spdif); ++ break; ++ case SNDRV_PCM_TRIGGER_STOP: ++ case SNDRV_PCM_TRIGGER_SUSPEND: ++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ++ SPDIF_DEBUG_MSG("stop\n"); ++ ingenic_spdif_stop_substream(substream, spdif); ++ break; ++ } ++ ++ return 0; ++} ++ ++static int ingenic_spdif_div(struct ingenic_spdif *spdif, int stream, unsigned long rate, int channels) ++{ ++ int clk_ratio = stream ? 1280 : 32 * 2 * channels; //fixed 2channels ++ int clk, div, sysclk = spdif->sysclk; ++ ++ clk = rate * clk_ratio; ++ div = ((sysclk + clk - 1) / clk) & (~0x1UL); ++ ++ return div; ++} ++ ++struct sampl_freq { ++ u32 freq; ++#define SPDIF_OUT_FS 0 ++#define SPDIF_OUT_ORG_FRQ 1 ++ int flag; ++ u32 val; ++} sample[] = { ++ /* References : IEC 60958-3 configure */ ++ {22050, SPDIF_OUT_FS, SPO_SET_FS(0x2)}, ++ {24000, SPDIF_OUT_FS, SPO_SET_FS(0x6)}, ++ {32000, SPDIF_OUT_FS, SPO_SET_FS(0xc)}, ++ {44100, SPDIF_OUT_FS, SPO_SET_FS(0x0)}, ++ {48000, SPDIF_OUT_FS, SPO_SET_FS(0x4)}, ++ {88200, SPDIF_OUT_FS, SPO_SET_FS(0x1)}, ++ {96000, SPDIF_OUT_FS, SPO_SET_FS(0x5)}, ++ {192000, SPDIF_OUT_FS, SPO_SET_FS(0x7)}, ++ {176400, SPDIF_OUT_FS, SPO_SET_FS(0x3)}, ++ {768000, SPDIF_OUT_FS, SPO_SET_FS(0x9)}, ++ ++ {8000, SPDIF_OUT_ORG_FRQ, SPO_SET_ORG_FRQ(0x6)}, ++ {11025, SPDIF_OUT_ORG_FRQ, SPO_SET_ORG_FRQ(0x5)}, ++ {12000, SPDIF_OUT_ORG_FRQ, SPO_SET_ORG_FRQ(0x4)}, ++ {16000, SPDIF_OUT_ORG_FRQ, SPO_SET_ORG_FRQ(0x1)}, ++ {22050, SPDIF_OUT_ORG_FRQ, SPO_SET_ORG_FRQ(0xb)}, ++ {24000, SPDIF_OUT_ORG_FRQ, SPO_SET_ORG_FRQ(0x9)}, ++ {32000, SPDIF_OUT_ORG_FRQ, SPO_SET_ORG_FRQ(0x3)}, ++ {44100, SPDIF_OUT_ORG_FRQ, SPO_SET_ORG_FRQ(0xf)}, ++ {48000, SPDIF_OUT_ORG_FRQ, SPO_SET_ORG_FRQ(0xd)}, ++ {88200, SPDIF_OUT_ORG_FRQ, SPO_SET_ORG_FRQ(0xe)}, ++ {96000, SPDIF_OUT_ORG_FRQ, SPO_SET_ORG_FRQ(0xa)}, ++ {176400, SPDIF_OUT_ORG_FRQ, SPO_SET_ORG_FRQ(0xc)}, ++ {192000, SPDIF_OUT_ORG_FRQ, SPO_SET_ORG_FRQ(0x8)}, ++}; ++ ++ ++static int ingenic_spdif_out_set_rate(struct ingenic_spdif *spdif, unsigned long sample_rate) ++{ ++ int i; ++ u32 fs = SPO_SET_FS(0x8), orq_frq = 0; ++ ++ for (i = 0; i < ARRAY_SIZE(sample); i++) { ++ if (sample[i].freq == sample_rate) { ++ if (sample[i].flag == SPDIF_OUT_FS) ++ fs = sample[i].val; ++ else ++ orq_frq = sample[i].val; ++ } ++ } ++ return fs | orq_frq; ++} ++ ++static bool ingenic_spdif_params_check(int channels, int fmt_width) ++{ ++ if (channels != 2) ++ goto error; ++ if (fmt_width < 16 || fmt_width > 24) ++ goto error; ++ ++ return true; ++error: ++ pr_err("[ERROR]: %s %d\n", __func__, __LINE__); ++ return false; ++} ++ ++ ++static int ingenic_spdif_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) ++{ ++ int channels = params_channels(params); ++ int rate = params_rate(params); ++ int fmt_width = snd_pcm_format_width(params_format(params)); ++ struct ingenic_spdif *spdif = dev_get_drvdata(dai->dev); ++ u32 max_wl = 0, div = 0, sampl_wl = 0, rate_reg = 0; ++ ++ SPDIF_DEBUG_MSG("enter %s, substream = %s, channels %d, rate %d, fmt_width %d\n", __func__, ++ (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? "playback" : "capture", ++ channels, rate, fmt_width); ++ ++ if(!ingenic_spdif_params_check(channels, fmt_width)) ++ return -EINVAL; ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ if (!spdif->non_pcm) { ++ max_wl = (1 == fmt_width/10) ? 0 : 1; ++ sampl_wl = SPO_SET_SAMPL_WL(fmt_width, max_wl); ++ rate_reg = ingenic_spdif_out_set_rate(spdif, rate); ++ regmap_update_bits(spdif->spdif_out_regmap, SPCFG2, ++ SPO_FS_MASK|SPO_ORG_FRQ_MASK|SPO_SAMPL_WL_MASK|SPO_MAX_WL, ++ rate_reg|sampl_wl|(max_wl ? SPO_MAX_WL : 0)); ++ } ++ regmap_update_bits(spdif->spdif_out_regmap, SPCTRL, SPO_SIGN_N, ++ snd_pcm_format_signed(params_format(params)) ? 0 : 1); ++ div = ingenic_spdif_div(spdif, substream->stream, rate, channels); ++ if (spdif->out_clk_div) ++ div = spdif->out_clk_div; ++ SPDIF_DEBUG_MSG("SPDIF OUT's clk div %d\n", div); ++ regmap_write(spdif->spdif_out_regmap, SPDIV, SPO_SET_DV(div)); ++ } else { ++ div = ingenic_spdif_div(spdif, substream->stream, rate, channels); ++ if (spdif->in_clk_div) ++ div = spdif->in_clk_div; ++ SPDIF_DEBUG_MSG("SPDIF IN's clk div %d\n", div); ++ regmap_write(spdif->spdif_in_regmap, SPIDIV, SPI_SET_DV(div)); ++ } ++ ++ return ingenic_spdif_fmtcov_be_fix(substream, params); ++} ++ ++static int ingenic_spdif_set_sysclk(struct snd_soc_dai *dai, int clk_id, ++ unsigned int freq, int dir) ++{ ++ struct ingenic_spdif *spdif = dev_get_drvdata(dai->dev); ++ ++ SPDIF_DEBUG_MSG("enter %s, sysclk freq=%d\n", __func__, freq); ++ spdif->sysclk = freq; ++ ++ return 0; ++} ++ ++static int ingenic_spdif_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div) ++{ ++ struct ingenic_spdif *spdif = dev_get_drvdata(dai->dev); ++ ++ switch (div_id) { ++ case SNDRV_PCM_STREAM_PLAYBACK: ++ spdif->out_clk_div = div; ++ break; ++ case SNDRV_PCM_STREAM_CAPTURE: ++ spdif->in_clk_div = div; ++ break; ++ default: ++ pr_err("%s:%d\n", __func__, __LINE__); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static struct snd_soc_dai_ops ingenic_spdif_dai_ops = { ++ .startup = ingenic_spdif_startup, ++ .trigger = ingenic_spdif_trigger, ++ .hw_params = ingenic_spdif_hw_params, ++ .set_sysclk = ingenic_spdif_set_sysclk, ++ .set_clkdiv = ingenic_spdif_set_clkdiv, ++}; ++ ++struct snd_soc_component_driver ingenic_spdif_component = { ++ .name = "spdif", ++}; ++ ++#define ingenic_spdif_suspend NULL ++#define ingenic_spdif_resume NULL ++ ++ ++/* TODO: replace by dts. */ ++static int ingenic_spdif_clk_init(struct platform_device *pdev, struct ingenic_spdif *spdif) ++{ ++ spdif->clk = devm_clk_get(spdif->dev, "cgu_spdif"); ++ if(IS_ERR_OR_NULL(spdif->clk)) { ++ dev_warn(spdif->dev, "Warning ... Failed to get cgu_spdif\n"); ++ } ++ ++ if(spdif->clk) { ++ struct clk *parent; ++ parent = devm_clk_get(spdif->dev, "cgu_i2s0"); ++ clk_set_parent(spdif->clk, parent); ++ devm_clk_put(spdif->dev, parent); ++ } ++ ++ spdif->clk_gate = devm_clk_get(spdif->dev, "gate_spdif"); ++ if(IS_ERR_OR_NULL(spdif->clk_gate)) { ++ dev_warn(spdif->dev, "Warning ... Failed to get gate_spdif\n"); ++ } ++ ++ if(spdif->clk) { ++ clk_set_rate(spdif->clk, 24000000); ++ clk_prepare_enable(spdif->clk); ++ } ++ if(spdif->clk_gate) { ++ clk_prepare_enable(spdif->clk_gate); ++ } ++ ++ return 0; ++} ++ ++static int ingenic_spdif_platform_probe(struct platform_device *pdev) ++{ ++ struct ingenic_spdif *spdif; ++ struct resource *res; ++ int ret; ++ struct regmap_config regmap_config = { ++ .reg_bits = 32, ++ .reg_stride = 4, ++ .val_bits = 32, ++ .cache_type = REGCACHE_NONE, ++ }; ++ ++ spdif = devm_kzalloc(&pdev->dev, sizeof(struct ingenic_spdif) + ++ sizeof(struct snd_soc_dai_driver), GFP_KERNEL); ++ if (!spdif) ++ return -ENOMEM; ++ ++ spdif->dai_driver = (struct snd_soc_dai_driver*)(spdif + 1); ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "out"); ++ spdif->spdif_out_base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(spdif->spdif_out_base)) ++ return PTR_ERR(spdif->spdif_out_base); ++ regmap_config.max_register = resource_size(res) - 0x4; ++ regmap_config.name = res->name; ++ spdif->spdif_out_regmap = devm_regmap_init_mmio(&pdev->dev, ++ spdif->spdif_out_base, ++ ®map_config); ++ if (IS_ERR(spdif->spdif_out_regmap)) ++ return PTR_ERR(spdif->spdif_out_regmap); ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "in"); ++ spdif->spdif_in_base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(spdif->spdif_in_base)) ++ return PTR_ERR(spdif->spdif_in_base); ++ regmap_config.max_register = resource_size(res) - 0x4; ++ regmap_config.name = res->name; ++ spdif->spdif_in_regmap = devm_regmap_init_mmio(&pdev->dev, ++ spdif->spdif_in_base, ++ ®map_config); ++ if (IS_ERR(spdif->spdif_in_regmap)) ++ return PTR_ERR(spdif->spdif_in_regmap); ++ ++ spdif->non_pcm = of_property_read_bool(pdev->dev.of_node, "ingenic,non-pcm"); ++ ++ spdif->dev = &pdev->dev; ++ ++ spdif->dai_driver->id = 1; ++ spdif->dai_driver->name = "SPDIF"; ++ spdif->dai_driver->suspend = ingenic_spdif_suspend; ++ spdif->dai_driver->resume = ingenic_spdif_resume; ++ spdif->dai_driver->ops = &ingenic_spdif_dai_ops; ++ spdif->dai_driver->playback.stream_name = "SPDIF playback"; ++ spdif->dai_driver->capture.stream_name = "SPDIF capture"; ++ ++ ingenic_spdif_clk_init(pdev, spdif); ++ ++ platform_set_drvdata(pdev, spdif); ++ ++ ++ ret = devm_snd_soc_register_component(&pdev->dev, &ingenic_spdif_component, ++ spdif->dai_driver, 1); ++ if (!ret) ++ dev_info(&pdev->dev, "spdif platform probe success\n"); ++ ++ return ret; ++} ++ ++static int ingenic_spdif_platform_remove(struct platform_device *pdev) ++{ ++ return 0; ++} ++ ++static const struct of_device_id ingenic_spdif_match_table[] = { ++ { .compatible = "ingenic,as-spdif", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, ingenic_spdif_match_table); ++ ++#ifdef CONFIG_PM ++static int ingenic_spdif_runtime_suspend(struct device *dev) ++{ ++ return 0; ++} ++ ++static int ingenic_spdif_runtime_resume(struct device *dev) ++{ ++ return 0; ++} ++#endif ++ ++static const struct dev_pm_ops ingenic_spdif_pm_ops = { ++ SET_RUNTIME_PM_OPS(ingenic_spdif_runtime_suspend, ++ ingenic_spdif_runtime_resume, NULL) ++}; ++ ++ ++static struct platform_driver ingenic_spdif_platform_driver = { ++ .driver = { ++ .name = "as-spdif", ++ .of_match_table = ingenic_spdif_match_table, ++ .pm = &ingenic_spdif_pm_ops, ++ }, ++ .probe = ingenic_spdif_platform_probe, ++ .remove = ingenic_spdif_platform_remove, ++}; ++module_platform_driver(ingenic_spdif_platform_driver); ++ ++MODULE_AUTHOR("wqshao "); ++MODULE_DESCRIPTION("Ingenic AS spdif SoC Interface"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:ingenic-as-spdif"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-spdif.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-spdif.h.patch new file mode 100644 index 00000000..d45167b8 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-spdif.h.patch @@ -0,0 +1,103 @@ +diff -drupN a/sound/soc/ingenic/as-v2/as-spdif.h b/sound/soc/ingenic/as-v2/as-spdif.h +--- a/sound/soc/ingenic/as-v2/as-spdif.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/as-v2/as-spdif.h 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,99 @@ ++/* ++ * ALSA Soc Audio Layer -- Ingenic AS BAIC Controller ++ * ++ * Copyright 2017 - 2022 Ingenic Semiconductor Co.,Ltd ++ * wqshao ++ * ++ * 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. ++ */ ++#ifndef __AS_SPDIF_H__ ++#define __AS_SPDIF_H__ ++ ++#include ++ ++struct ingenic_spdif { ++ struct device *dev; ++ struct regmap *spdif_out_regmap; ++ struct regmap *spdif_in_regmap; ++ void __iomem *spdif_out_base; ++ void __iomem *spdif_in_base; ++ bool non_pcm; ++ u32 sysclk; ++ u32 out_clk_div; ++ u32 in_clk_div; ++ struct snd_soc_dai_driver *dai_driver; ++ ++ struct clk *clk; ++ struct clk *clk_gate; ++}; ++ ++/* SPDIF OUT */ ++#define SPENA (0x0) ++#define SPO_SPEN BIT(0) ++ ++#define SPCTRL (0x4) ++#define SPO_D_TYPE BIT(14) ++#define SPO_SIGN_N BIT(13) ++#define SPO_INVALID BIT(12) ++#define SPO_SFT_RST BIT(11) ++ ++#define SPCFG1 (0x8) ++#define SPO_SCR_NUM_SFT (8) ++#define SPO_SCR_NUM_MASK GENMASK(11, SPO_SCR_NUM_SFT) ++#define SPO_SET_SCR_NUM(x) ((x) << SPO_SCR_NUM_SFT) ++#define SPO_CH1_NUM_SFT (4) ++#define SPO_CH1_NUM_MASK GENMASK(7, SPO_CH1_NUM_SFT) ++#define SPO_SET_CH1_NUM(x) ((x) << SPO_CH1_NUM_SFT) ++#define SPO_CH2_NUM_SFT (0) ++#define SPO_CH2_NUM_MASK GENMASK(3, SPO_CH2_NUM_SFT) ++#define SPO_SET_CH2_NUM(x) ((x) << SPO_CH2_NUM_SFT) ++ ++#define SPCFG2 (0xc) ++#define SPO_FS_SFT (26) ++#define SPO_FS_MASK GENMASK(29, SPO_FS_SFT) ++#define SPO_SET_FS(x) ((x) << SPO_FS_SFT) ++#define SPO_ORG_FRQ_SFT (22) ++#define SPO_ORG_FRQ_MASK GENMASK(25, SPO_ORG_FRQ_SFT) ++#define SPO_SET_ORG_FRQ(x) ((x) << SPO_ORG_FRQ_SFT) ++ ++#define SPO_SAMPL_WL_SFT (19) ++#define SPO_SAMPL_WL_MASK GENMASK(21, SPO_SAMPL_WL_SFT) ++#define SAMPL_WL_16 (0x1 << SPO_SAMPL_WL_SFT) ++#define SAMPL_WL_17_21 (0x6 << SPO_SAMPL_WL_SFT) ++#define SAMPL_WL_18_22 (0x2 << SPO_SAMPL_WL_SFT) ++#define SAMPL_WL_19_23 (0x4 << SPO_SAMPL_WL_SFT) ++#define SAMPL_WL_24 (0x6 << SPO_SAMPL_WL_SFT) ++#define SAMPL_WL0_20 (0x5 << SPO_SAMPL_WL_SFT) ++#define SAMPL_WL1_20 (0x1 << SPO_SAMPL_WL_SFT) ++#define SPO_SET_SAMPL_WL(wl, max_wl) (((wl == 16) && !max_wl) ? SAMPL_WL_16 : ((wl == 17) || ( wl == 21)) ? SAMPL_WL_17_21 : ((wl == 18) || (wl == 22)) ? SAMPL_WL_18_22 : ((wl == 19) || (wl == 23)) ? SAMPL_WL_19_23 : (wl == 24) ? SAMPL_WL_24 : (wl == 20) && max_wl ? SAMPL_WL1_20 : SAMPL_WL0_20) ++#define SPO_MAX_WL BIT(18) ++#define SPO_CAT_CODE_SFT (8) ++#define SPO_CAT_CODE_MASK GENMASK(15, SPO_CAT_CODE_SFT) ++#define SPO_CAT_CODE_GEN (0x0 << SPO_CAT_CODE_SFT) ++#define SPO_CAT_CODE_DVD (0x4c << SPO_CAT_CODE_SFT) ++#define SPO_CH_MD_SFT (6) ++#define SPO_CH_MD_MASK GENMASK(7, SPO_CH_MD_SFT) ++#define SPO_CH_MD_0 (0x0 << SPO_CH_MD_SFT) ++#define SPO_AUDIO_N BIT(1) ++#define SPO_CON_PRO BIT(0) ++ ++#define SPDIV (0x10) ++#define SPO_DV_SFT (0) ++#define SPO_SET_DV(x) (((x) > ((1 << 7) - 1) ? ((1 << 7) - 1) : (x)) << SPO_DV_SFT) ++ ++/* SPDIF IN */ ++#define SPIENA (0x0) ++#define SPI_RESET BIT(1) ++#define SPI_SPIEN BIT(0) ++ ++#define SPICFG1 (0x4) ++#define SPICFG2 (0x8) ++#define SPICFG3 (0xc) ++#define SPIDIV (0x10) ++#define SPI_DV_SFT (0) ++#define SPI_SET_DV(x) SPO_SET_DV(x) ++ ++#endif //__AS_SPDIF_H__ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-vir-fe.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-vir-fe.c.patch new file mode 100644 index 00000000..dbfea390 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_as-v2_as-vir-fe.c.patch @@ -0,0 +1,158 @@ +diff -drupN a/sound/soc/ingenic/as-v2/as-vir-fe.c b/sound/soc/ingenic/as-v2/as-vir-fe.c +--- a/sound/soc/ingenic/as-v2/as-vir-fe.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/as-v2/as-vir-fe.c 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,154 @@ ++/* ++ * ALSA Soc Audio Layer -- ingenic as(audio system) Virtual FE (Basic Audio ++ * Interface Controller) driver ++ * ++ * Copyright 2017 - 2022 Ingenic Semiconductor Co.,Ltd ++ * wqshao ++ * ++ * 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. ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++static const struct snd_pcm_hardware ingenic_vir_fe_hardware = { ++ /* Random values to keep userspace happy when checking constraints */ ++ .info = SNDRV_PCM_INFO_INTERLEAVED | ++ SNDRV_PCM_INFO_BLOCK_TRANSFER, ++ .buffer_bytes_max = 128*1024, ++ .period_bytes_min = PAGE_SIZE, ++ .period_bytes_max = PAGE_SIZE*2, ++ .periods_min = 2, ++ .periods_max = 128, ++}; ++ ++static int ingenic_vir_fe_open(struct snd_pcm_substream *substream) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ ++ /* BE's dont need virtual params */ ++ if (!rtd->dai_link->no_pcm) ++ snd_soc_set_runtime_hwparams(substream, &ingenic_vir_fe_hardware); ++ ++ return 0; ++} ++ ++static int ingenic_vir_fe_prepare(struct snd_pcm_substream *substream) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ ++ /* The analog play buffer has data on play music */ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ runtime->stop_threshold = runtime->boundary; ++ ++ return 0; ++} ++ ++static struct snd_pcm_ops ingenic_vir_fe_ops = { ++ .open = ingenic_vir_fe_open, ++ .prepare = ingenic_vir_fe_prepare, ++ .ioctl = snd_pcm_lib_ioctl, ++}; ++ ++static struct snd_soc_platform_driver ingenic_vir_platform = { ++ .ops = &ingenic_vir_fe_ops, ++}; ++ ++#define INGENIC_STUB_RATES SNDRV_PCM_RATE_8000_192000 ++#define INGENIC_STUB_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ ++ SNDRV_PCM_FMTBIT_U8 | \ ++ SNDRV_PCM_FMTBIT_S16_LE | \ ++ SNDRV_PCM_FMTBIT_U16_LE | \ ++ SNDRV_PCM_FMTBIT_S24_LE | \ ++ SNDRV_PCM_FMTBIT_U24_LE | \ ++ SNDRV_PCM_FMTBIT_S32_LE | \ ++ SNDRV_PCM_FMTBIT_U32_LE | \ ++ SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE) ++ ++static struct snd_soc_component_driver ingenic_vir_fe_cmpnt = { ++ .name = "as-vir-fe", ++}; ++ ++#define INGENIC_VIR_FE_MAX 10 ++static int ingenic_as_vir_fe_probe(struct platform_device *pdev) ++{ ++ struct snd_soc_dai_driver *vir_fe_dais; ++ static char dai_name[INGENIC_VIR_FE_MAX][20]; ++ int i, ret, num_dais, cap_dai_bitmsk; ++ ++ if (of_property_read_u32(pdev->dev.of_node, "ingenic,num-dais", &num_dais)) ++ return -ENODEV; ++ ++ if (of_property_read_u32(pdev->dev.of_node, "ingenic,cap-dai-bm", &cap_dai_bitmsk)) ++ return -ENODEV; ++ ++ vir_fe_dais = devm_kzalloc(&pdev->dev, sizeof(*vir_fe_dais) * num_dais, GFP_KERNEL); ++ if (!vir_fe_dais) ++ return -ENOMEM; ++ ++ ++ for (i = 0; i < num_dais; i++) { ++ sprintf(dai_name[i], "Virtual-FE%d", i); ++ vir_fe_dais[i].name = dai_name[i]; ++ vir_fe_dais[i].id = i; ++ if ((BIT(i) & cap_dai_bitmsk)) { ++ vir_fe_dais[i].capture.stream_name = dai_name[i]; ++ vir_fe_dais[i].capture.channels_min = 1; ++ vir_fe_dais[i].capture.channels_max = 384; ++ vir_fe_dais[i].capture.rates = INGENIC_STUB_RATES; ++ vir_fe_dais[i].capture.formats = INGENIC_STUB_FORMATS; ++ } else { ++ vir_fe_dais[i].playback.stream_name = dai_name[i]; ++ vir_fe_dais[i].playback.channels_min = 1; ++ vir_fe_dais[i].playback.channels_max = 384; ++ vir_fe_dais[i].playback.rates = INGENIC_STUB_RATES; ++ vir_fe_dais[i].playback.formats = INGENIC_STUB_FORMATS; ++ } ++ } ++ ++ ret = snd_soc_register_component(&pdev->dev, &ingenic_vir_fe_cmpnt, vir_fe_dais, num_dais); ++ if (ret < 0) ++ return ret; ++ ++ ret = snd_soc_register_platform(&pdev->dev, &ingenic_vir_platform); ++ if (ret < 0) { ++ snd_soc_unregister_component(&pdev->dev); ++ return ret; ++ } ++ ++ dev_info(&pdev->dev, "probe success!!!\n"); ++ return ret; ++} ++ ++static int ingenic_as_vir_fe_remove(struct platform_device *pdev) ++{ ++ snd_soc_unregister_platform(&pdev->dev); ++ snd_soc_unregister_codec(&pdev->dev); ++ return 0; ++} ++ ++static const struct of_device_id ingenic_as_vir_fe_match_table[] = { ++ { .compatible = "ingenic,as-vir-fe", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, ingenic_as_vir_fe_match_table); ++ ++static struct platform_driver ingenic_as_vir_fe_platform_driver = { ++ .driver = { ++ .name = "as-virtual-fe", ++ .of_match_table = ingenic_as_vir_fe_match_table, ++ }, ++ .probe = ingenic_as_vir_fe_probe, ++ .remove = ingenic_as_vir_fe_remove, ++}; ++module_platform_driver(ingenic_as_vir_fe_platform_driver); ++ ++MODULE_AUTHOR("wqshao "); ++MODULE_DESCRIPTION("Ingenic AS Virtual FE SoC Interface"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:ingenic-as-vir-fe"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_boards_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_boards_Makefile.patch new file mode 100644 index 00000000..f350608c --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_boards_Makefile.patch @@ -0,0 +1,9 @@ +diff -drupN a/sound/soc/ingenic/boards/Makefile b/sound/soc/ingenic/boards/Makefile +--- a/sound/soc/ingenic/boards/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/boards/Makefile 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,5 @@ ++## X1000 Supported Boards ++obj-$(CONFIG_SND_ASOC_INGENIC_X1000_BOARD) += x1000-board.o ++ ++## X2000 Supported Boards ++obj-$(CONFIG_SND_ASOC_INGENIC_SEAL) += seal.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_boards_seal.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_boards_seal.c.patch new file mode 100644 index 00000000..a9bc5092 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_boards_seal.c.patch @@ -0,0 +1,517 @@ +diff -drupN a/sound/soc/ingenic/boards/seal.c b/sound/soc/ingenic/boards/seal.c +--- a/sound/soc/ingenic/boards/seal.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/boards/seal.c 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,513 @@ ++ /* ++ * Copyright (C) 2017 Ingenic Semiconductor Co., Ltd. ++ * http://www.ingenic.com ++ * Author: cli ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include "../as-v2/as-baic.h" ++ ++static const struct snd_soc_dapm_route audio_map[] = { ++ { "BAIC0 playback", NULL, "LO0_MUX" }, ++ { "BAIC1 playback", NULL, "LO1_MUX" }, ++ { "SPDIF playback", NULL, "LO2_MUX" }, ++ { "BAIC3 playback", NULL, "LO3_MUX" }, ++ { "BAIC4 playback", NULL, "LO4_MUX" }, ++ ++ { "LI0", NULL, "DMIC capture" }, ++ { "LI1", NULL, "SPDIF capture" }, ++ { "LI2", NULL, "BAIC0 capture" }, ++ { "LI3", NULL, "BAIC1 capture" }, ++ { "LI4", NULL, "BAIC2 capture" }, ++ { "LI6", NULL, "BAIC4 capture" }, ++ ++ { "LI8", NULL, "DMA0" }, ++ { "LI9", NULL, "DMA1" }, ++ { "LI10", NULL, "DMA2" }, ++ { "LI11", NULL, "DMA3" }, ++ { "LI12", NULL, "DMA4" }, ++ ++ { "DMA5", NULL, "LO5_MUX"}, ++ { "DMA6", NULL, "LO6_MUX"}, ++ { "DMA7", NULL, "LO7_MUX"}, ++ { "DMA8", NULL, "LO8_MUX"}, ++ { "DMA9", NULL, "LO9_MUX"}, ++ ++ { "MIX0", NULL, "LO10_MUX"}, ++ { "MIX0", NULL, "LO11_MUX"}, ++ { "LI7", NULL, "MIX0"}, ++ ++ {"SPDIF_OUT", NULL, "SPDIF playback"}, ++ {"SPDIF capture", NULL, "SPDIF_IN"}, ++ {"DMIC capture", NULL, "DMIC"}, ++ ++ {"BAIC1 playback", NULL, "Virtual-FE0"}, ++ {"BAIC4 playback", NULL, "Virtual-FE1"}, ++ {"Virtual-FE2", NULL, "BAIC1 capture"}, ++ {"Virtual-FE3", NULL, "DMIC capture"}, ++}; ++ ++static const struct snd_soc_dapm_widget dapm_widgets[] = { ++ SND_SOC_DAPM_OUTPUT("SPDIF_OUT"), ++ SND_SOC_DAPM_INPUT("SPDIF_IN"), ++ SND_SOC_DAPM_INPUT("DMIC"), ++}; ++ ++static int seal_baic_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai; ++ struct snd_soc_dai *codec_dai = rtd->codec_dai; ++ int id = cpu_dai->driver->id; ++ bool is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? true : false; ++ int bclk_div = 0, sysclk = 0, slot_width = 0, slots = 0, dir = SND_SOC_CLOCK_OUT, ++ sync_div = 0, sync_w_div = 1, tx_msk = 0, rx_msk = 0; ++ int divid_dir = is_playback ? DIVID_DIR_T : 0; ++ int clkid = CLKID_SYSCLK; ++ int ret; ++ ++ switch (id) { ++ case 0: ++ clkid = CLKID_INNER_CODEC; ++ break; ++ case 1: ++ sysclk = 24000000; ++ sync_div = 64; ++ bclk_div = (sysclk + ((params_rate(params) * sync_div) - 1)) ++ / (params_rate(params) * sync_div); ++ bclk_div &= ~0x1; ++ break; ++ case 2: ++ case 3: ++ sysclk = 24000000; ++ slots = params_channels(params); ++ slot_width = 32; ++ sync_div = 256; ++ //sync_div = 64; ++ if (is_playback) ++ tx_msk = (1 << slots) - 1; ++ else ++ rx_msk = (1 << slots) - 1; ++ bclk_div = (sysclk + ((params_rate(params) * sync_div) - 1)) ++ / (params_rate(params) * sync_div); ++ bclk_div &= ~0x1; ++ sync_w_div = 1; ++ ++ snd_soc_dai_set_tdm_slot(codec_dai, tx_msk, rx_msk, slots > 4 ? 8 : 4, slot_width); ++ ++ break; ++ case 4: ++ sysclk = 24000000; ++ slots = params_channels(params); ++ slot_width = 32; ++ sync_div = 64; ++ if (is_playback) ++ tx_msk = (1 << slots) - 1; ++ else ++ rx_msk = (1 << slots) - 1; ++ sync_w_div = 1; ++ break; ++ default: ++ pr_err("x2000 sound hw params baic dai(%d.%s) not exist\n",\ ++ id, is_playback ? "p" : "c"); ++ return -EINVAL; ++ } ++ ++ ret = snd_soc_dai_set_sysclk(cpu_dai, clkid, sysclk, dir); ++ if (ret) ++ return ret; ++ ret = snd_soc_dai_set_clkdiv(cpu_dai, DIVID_SYNC_W|divid_dir, sync_w_div); ++ if (ret) ++ return ret; ++ ret = snd_soc_dai_set_clkdiv(cpu_dai, DIVID_SYNC|divid_dir, sync_div); ++ if (ret) ++ return ret; ++ ret = snd_soc_dai_set_clkdiv(cpu_dai, DIVID_BCLK|divid_dir, bclk_div); ++ if (ret) ++ return ret; ++ ret = snd_soc_dai_set_tdm_slot(cpu_dai, tx_msk, rx_msk, slots, slot_width); ++ if (ret) ++ return ret; ++ return 0; ++}; ++ ++static struct snd_soc_ops seal_baic_ops = { ++ .hw_params = seal_baic_hw_params, ++}; ++ ++static int spdif_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai; ++ u32 sysclk = 0, spdif_out_clk_div = 0, spdif_in_clk_div = 0; ++ int clk_ratio = substream->stream ? 1280 : 32 * 2 * params_channels(params); //fixed 2channels ++ int ret; ++ ++ sysclk = 24000000; ++ ++ spdif_out_clk_div = (sysclk + ((params_rate(params) * clk_ratio) - 1)) ++ / (params_rate(params) * clk_ratio); ++ spdif_out_clk_div &= ~0x1; ++ ++ spdif_in_clk_div = (sysclk + ((params_rate(params) * clk_ratio) - 1)) ++ / (params_rate(params) * clk_ratio); ++ spdif_in_clk_div &= ~0x1; ++ ++ ret = snd_soc_dai_set_sysclk(cpu_dai, 0, sysclk, 0); ++ if (ret) ++ return ret; ++ ret = snd_soc_dai_set_clkdiv(cpu_dai, substream->stream, ++ !(substream->stream) ? spdif_out_clk_div : spdif_in_clk_div); ++ if (ret) ++ return ret; ++ ++ return 0; ++}; ++ ++static struct snd_soc_ops seal_spdif_ops = { ++ .hw_params = spdif_hw_params, ++}; ++ ++static struct snd_soc_dai_link seal_dais[] = { ++ /*FE DAIS*/ ++ [0] = { ++ .name = "DMA0 playback", ++ .stream_name = "DMA0 playback", ++ .platform_name = "134d0000.as-platform", ++ .cpu_dai_name = "DMA0", ++ .codec_dai_name = "snd-soc-dummy-dai", ++ .codec_name = "snd-soc-dummy", ++ .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, ++ .dynamic = 1, ++ .dpcm_playback = 1, ++ }, ++ [1] = { ++ .name = "DMA1 playback", ++ .stream_name = "DMA1 playback", ++ .platform_name = "134d0000.as-platform", ++ .cpu_dai_name = "DMA1", ++ .codec_dai_name = "snd-soc-dummy-dai", ++ .codec_name = "snd-soc-dummy", ++ .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, ++ .dynamic = 1, ++ .dpcm_playback = 1, ++ }, ++ [2] = { ++ .name = "DMA2 playback", ++ .stream_name = "DMA2 playback", ++ .platform_name = "134d0000.as-platform", ++ .cpu_dai_name = "DMA2", ++ .codec_dai_name = "snd-soc-dummy-dai", ++ .codec_name = "snd-soc-dummy", ++ .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, ++ .dynamic = 1, ++ .dpcm_playback = 1, ++ }, ++ [3] = { ++ .name = "DMA3 playback", ++ .stream_name = "DMA3 playback", ++ .platform_name = "134d0000.as-platform", ++ .cpu_dai_name = "DMA3", ++ .codec_dai_name = "snd-soc-dummy-dai", ++ .codec_name = "snd-soc-dummy", ++ .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, ++ .dynamic = 1, ++ .dpcm_playback = 1, ++ }, ++ ++ [4] = { ++ .name = "DMA4 playback", ++ .stream_name = "DMA4 playback", ++ .platform_name = "134d0000.as-platform", ++ .cpu_dai_name = "DMA4", ++ .codec_dai_name = "snd-soc-dummy-dai", ++ .codec_name = "snd-soc-dummy", ++ .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, ++ .dynamic = 1, ++ .dpcm_playback = 1, ++ }, ++ ++ [5] = { ++ .name = "DMA5 capture", ++ .stream_name = "DMA5 capture", ++ .platform_name = "134d0000.as-platform", ++ .cpu_dai_name = "DMA5", ++ .codec_dai_name = "snd-soc-dummy-dai", ++ .codec_name = "snd-soc-dummy", ++ .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, ++ .dynamic = 1, ++ .dpcm_capture = 1, ++ }, ++ ++ [6] = { ++ .name = "DMA6 capture", ++ .stream_name = "DMA6 capture", ++ .platform_name = "134d0000.as-platform", ++ .cpu_dai_name = "DMA6", ++ .codec_dai_name = "snd-soc-dummy-dai", ++ .codec_name = "snd-soc-dummy", ++ .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, ++ .dynamic = 1, ++ .dpcm_capture = 1, ++ }, ++ ++ [7] = { ++ .name = "DMA7 capture", ++ .stream_name = "DMA7 capture", ++ .platform_name = "134d0000.as-platform", ++ .cpu_dai_name = "DMA7", ++ .codec_dai_name = "snd-soc-dummy-dai", ++ .codec_name = "snd-soc-dummy", ++ .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, ++ .dynamic = 1, ++ .dpcm_capture = 1, ++ }, ++ ++ [8] = { ++ .name = "DMA8 capture", ++ .stream_name = "DMA8 capture", ++ .platform_name = "134d0000.as-platform", ++ .cpu_dai_name = "DMA8", ++ .codec_dai_name = "snd-soc-dummy-dai", ++ .codec_name = "snd-soc-dummy", ++ .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, ++ .dynamic = 1, ++ .dpcm_capture = 1, ++ }, ++ ++ [9] = { ++ .name = "DMA9 capture", ++ .stream_name = "DMA9 capture", ++ .platform_name = "134d0000.as-platform", ++ .cpu_dai_name = "DMA9", ++ .codec_dai_name = "snd-soc-dummy-dai", ++ .codec_name = "snd-soc-dummy", ++ .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, ++ .dynamic = 1, ++ .dpcm_capture = 1, ++ }, ++ ++ [10] = { ++ .name = "Dummy DMA0", ++ .stream_name = "Dummy DMA0", ++ .platform_name = "0.as-virtual-fe", ++ .cpu_dai_name = "Virtual-FE0", ++ .codec_dai_name = "snd-soc-dummy-dai", ++ .codec_name = "snd-soc-dummy", ++ .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, ++ .dynamic = 1, ++ .dpcm_playback = 1, ++ }, ++ ++ [11] = { ++ .name = "Dummy DMA1", ++ .stream_name = "Dummy DMA1", ++ .platform_name = "0.as-virtual-fe", ++ .cpu_dai_name = "Virtual-FE1", ++ .codec_dai_name = "snd-soc-dummy-dai", ++ .codec_name = "snd-soc-dummy", ++ .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, ++ .dynamic = 1, ++ .dpcm_playback = 1, ++ }, ++ ++ [12] = { ++ .name = "Dummy DMA2", ++ .stream_name = "Dummy DMA2", ++ .platform_name = "0.as-virtual-fe", ++ .cpu_dai_name = "Virtual-FE2", ++ .codec_dai_name = "snd-soc-dummy-dai", ++ .codec_name = "snd-soc-dummy", ++ .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, ++ .dynamic = 1, ++ .dpcm_capture = 1, ++ }, ++ ++ [13] = { ++ .name = "Dummy DMA3", ++ .stream_name = "Dummy DMA3", ++ .platform_name = "0.as-virtual-fe", ++ .cpu_dai_name = "Virtual-FE3", ++ .codec_dai_name = "snd-soc-dummy-dai", ++ .codec_name = "snd-soc-dummy", ++ .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, ++ .dynamic = 1, ++ .dpcm_capture = 1, ++ }, ++ ++ /*BE DAIS*/ ++ [14] = { ++ .name = "BAIC0", ++ .stream_name = "BAIC0", ++ .cpu_dai_name = "BAIC0", ++ .codec_dai_name = "snd-soc-dummy-dai", ++ .codec_name = "snd-soc-dummy", ++ .ops = &seal_baic_ops, ++ .be_hw_params_fixup = NULL, ++ .dai_fmt = SND_SOC_DAIFMT_I2S|SND_SOC_DAIFMT_NB_NF|SND_SOC_DAIFMT_CBS_CFS, ++ .no_pcm = 1, ++ .dpcm_capture = 1, ++ .dpcm_playback = 1, ++ }, ++ [15] = { ++ .name = "BAIC1", ++ .stream_name = "BAIC1", ++ .cpu_dai_name = "BAIC1", ++ .codec_dai_name = "snd-soc-dummy-dai", ++ .codec_name = "snd-soc-dummy", ++ .ops = &seal_baic_ops, ++ .be_hw_params_fixup = NULL, ++ .dai_fmt = SND_SOC_DAIFMT_I2S|SND_SOC_DAIFMT_NB_NF|SND_SOC_DAIFMT_CBS_CFS, ++ .no_pcm = 1, ++ .dpcm_capture = 1, ++ .dpcm_playback = 1, ++ }, ++ [16] = { ++ .name = "BAIC2", ++ .stream_name = "BAIC2", ++ .cpu_dai_name = "BAIC2", ++ .codec_dai_name = "ak5558.4-0013", // ak5558.4-0013 ++ .codec_name = "ak5558.4-0013", //ak5558.4-0013 ++ .ops = &seal_baic_ops, ++ .be_hw_params_fixup = NULL, ++ //.dai_fmt = SND_SOC_DAIFMT_DSP_A|SND_SOC_DAIFMT_NB_IF|SND_SOC_DAIFMT_CBS_CFS, ++ .dai_fmt = SND_SOC_DAIFMT_DSP_B|SND_SOC_DAIFMT_NB_NF|SND_SOC_DAIFMT_CBS_CFS, ++ .dpcm_capture = 1, ++ .no_pcm = 1, ++ }, ++ [17] = { ++ .name = "BAIC3", ++ .stream_name = "BAIC3", ++ .cpu_dai_name = "BAIC3", ++ .codec_dai_name = "ak4458.4-0010", ++ .codec_name = "ak4458.4-0010", ++ .ops = &seal_baic_ops, ++ .be_hw_params_fixup = NULL, ++ //.dai_fmt = SND_SOC_DAIFMT_DSP_A|SND_SOC_DAIFMT_NB_IF|SND_SOC_DAIFMT_CBS_CFS, ++ .dai_fmt = SND_SOC_DAIFMT_DSP_B|SND_SOC_DAIFMT_NB_NF|SND_SOC_DAIFMT_CBS_CFS, ++ .dpcm_playback = 1, ++ .no_pcm = 1, ++ }, ++ [18] = { ++ .name = "BAIC4", ++ .stream_name = "BAIC4", ++ .cpu_dai_name = "BAIC4", ++ .codec_dai_name = "snd-soc-dummy-dai", ++ .codec_name = "snd-soc-dummy", ++ .ops = &seal_baic_ops, ++ .be_hw_params_fixup = NULL, ++ .dai_fmt = SND_SOC_DAIFMT_DSP_A|SND_SOC_DAIFMT_NB_NF|SND_SOC_DAIFMT_CBS_CFS, ++ .no_pcm = 1, ++ .dpcm_capture = 1, ++ .dpcm_playback = 1, ++ }, ++ [19] = { ++ .name = "SPDIF", ++ .stream_name = "SPDIF", ++ .cpu_dai_name = "SPDIF", ++ .codec_dai_name = "snd-soc-dummy-dai", ++ .codec_name = "snd-soc-dummy", ++ .ops = &seal_spdif_ops, ++ .no_pcm = 1, ++ .dpcm_capture = 1, ++ .dpcm_playback = 1, ++ }, ++ [20] = { ++ .name = "DMIC", ++ .stream_name = "DMIC", ++ .cpu_dai_name = "DMIC", ++ .codec_dai_name = "snd-soc-dummy-dai", ++ .codec_name = "snd-soc-dummy", ++ .no_pcm = 1, ++ .capture_only = 1 ++ }, ++}; ++ ++static struct snd_soc_aux_dev seal_x2000_aux_dev = { ++ .name = "aux_mixer", ++ .codec_name = "134dc000.as-mixer", ++}; ++ ++ ++static int snd_seal_probe(struct platform_device *pdev) ++{ ++ struct snd_soc_card *card; ++ int ret; ++ ++ card = (struct snd_soc_card *)devm_kzalloc(&pdev->dev, ++ sizeof(struct snd_soc_card), GFP_KERNEL); ++ if (!card) ++ return -ENOMEM; ++ ++ card->dapm_widgets = dapm_widgets; ++ card->num_dapm_widgets = ARRAY_SIZE(dapm_widgets); ++ card->dapm_routes = audio_map; ++ card->num_dapm_routes = ARRAY_SIZE(audio_map); ++ card->dai_link = seal_dais; ++ card->num_links = ARRAY_SIZE(seal_dais); ++ card->owner = THIS_MODULE; ++ card->dev = &pdev->dev; ++ card->aux_dev = &seal_x2000_aux_dev; ++ card->num_aux_devs = 1; ++ ++ ret = snd_soc_of_parse_card_name(card, "ingenic,model"); ++ if (ret) ++ return ret; ++ ++ ret = snd_soc_register_card(card); ++ if (ret) { ++ dev_err(&pdev->dev, "snd_soc_register_card failed %d\n", ret); ++ return ret; ++ } ++ ++ platform_set_drvdata(pdev, card); ++ dev_info(&pdev->dev, "Sound Card successed\n"); ++ ++ return ret; ++} ++ ++static int snd_seal_remove(struct platform_device *pdev) ++{ ++ struct snd_soc_card *card = platform_get_drvdata(pdev); ++ snd_soc_unregister_card(card); ++ platform_set_drvdata(pdev, NULL); ++ return 0; ++} ++ ++static const struct of_device_id seal_match_table[] = { ++ { .compatible = "ingenic,seal-sound", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, seal_match_table); ++ ++static struct platform_driver snd_seal_driver = { ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = "x2000-seal", ++ .of_match_table = seal_match_table ++ }, ++ .probe = snd_seal_probe, ++ .remove = snd_seal_remove, ++}; ++module_platform_driver(snd_seal_driver); ++ ++MODULE_AUTHOR("cli"); ++MODULE_DESCRIPTION("ALSA SoC X2000 seal Snd Card"); ++MODULE_LICENSE("GPL"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_boards_x1000-board.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_boards_x1000-board.c.patch new file mode 100644 index 00000000..c67871d6 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_boards_x1000-board.c.patch @@ -0,0 +1,228 @@ +diff -drupN a/sound/soc/ingenic/boards/x1000-board.c b/sound/soc/ingenic/boards/x1000-board.c +--- a/sound/soc/ingenic/boards/x1000-board.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/boards/x1000-board.c 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,224 @@ ++/* ++ * Copyright (C) 2014 Ingenic Semiconductor Co., Ltd. ++ * http://www.ingenic.com ++ * Author: cli ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../as-v1/asoc-aic.h" ++ ++struct x1000_icdc { ++ struct snd_soc_card card; ++ int spk_gpio; ++ int spk_en_level; ++}; ++ ++int x1000_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai; ++ int ret; ++ ++ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S|SND_SOC_DAIFMT_CBM_CFM); ++ if (ret) ++ return ret; ++ ++ ret = snd_soc_dai_set_sysclk(cpu_dai, INGENIC_I2S_INNER_CODEC, ++ 24000000, SND_SOC_CLOCK_OUT); ++ if (ret) ++ return ret; ++ return 0; ++}; ++ ++int x1000_i2s_hw_free(struct snd_pcm_substream *substream) ++{ ++ /*notify release pll*/ ++ return 0; ++}; ++ ++static struct snd_soc_ops x1000_i2s_cdc_ops = { ++ .hw_params = x1000_i2s_hw_params, ++ .hw_free = x1000_i2s_hw_free, ++}; ++ ++static int x1000_spk_power(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) ++{ ++ struct x1000_icdc *x1000 = container_of(w->dapm->card, struct x1000_icdc, card); ++ ++ if (!gpio_is_valid(x1000->spk_gpio)) ++ return 0; ++ ++ if (SND_SOC_DAPM_EVENT_ON(event)) { ++ gpio_direction_output(x1000->spk_gpio, x1000->spk_en_level); ++ printk("gpio speaker enable %d\n", gpio_get_value(x1000->spk_gpio)); ++ } else { ++ gpio_direction_output(x1000->spk_gpio, x1000->spk_en_level); ++ printk("gpio speaker disable %d\n", gpio_get_value(x1000->spk_gpio)); ++ } ++ return 0; ++} ++ ++static const struct snd_soc_dapm_widget x1000_dapm_widgets[] = { ++ SND_SOC_DAPM_SPK("Speaker", x1000_spk_power), ++ SND_SOC_DAPM_MIC("Mic Buildin", NULL), ++ SND_SOC_DAPM_MIC("DMic", NULL), ++}; ++ ++static int x1000_i2s_cdc_dai_link_init(struct snd_soc_pcm_runtime *rtd) ++{ ++ struct snd_soc_card *card = rtd->card; ++ struct snd_soc_dapm_context *dapm = &card->dapm; ++ ++ snd_soc_dapm_enable_pin(dapm, "Speaker"); ++ snd_soc_dapm_enable_pin(dapm, "Mic Buildin"); ++ snd_soc_dapm_enable_pin(dapm, "DMic"); ++ return 0; ++} ++ ++static int snd_x1000_probe(struct platform_device *pdev) ++{ ++ struct device_node *snd_node = pdev->dev.of_node; ++ struct x1000_icdc *x1000; ++ struct snd_soc_card *card; ++ struct snd_soc_dai_link *dai_link; ++ enum of_gpio_flags flags; ++ int num_links; ++ int ret = 0, i; ++ ++ num_links = of_property_count_strings(snd_node, "ingenic,dai-link"); ++ if (num_links < 0) ++ return num_links; ++ BUG_ON(!num_links); ++ ++ x1000 = (struct x1000_icdc *)devm_kzalloc(&pdev->dev, ++ sizeof(struct x1000_icdc) + ++ sizeof(struct snd_soc_dai_link) * num_links, ++ GFP_KERNEL); ++ if (!x1000) ++ return -ENOMEM; ++ card = &x1000->card; ++ dai_link = (struct snd_soc_dai_link *)(x1000 + 1); ++ ++ card->num_dapm_widgets = ARRAY_SIZE(x1000_dapm_widgets); ++ card->dapm_widgets = x1000_dapm_widgets; ++ card->num_links = num_links; ++ card->dai_link = dai_link; ++ card->owner = THIS_MODULE; ++ card->dev = &pdev->dev; ++ ++ ret = snd_soc_of_parse_card_name(card, "ingenic,model"); ++ if (ret) ++ return ret; ++#ifdef CONFIG_SND_ASOC_INGENIC_HALLEY2_ICDC ++ ret = snd_soc_of_parse_audio_routing(card, "ingenic,audio-routing"); ++ if (ret) ++ return ret; ++#endif ++ x1000->spk_gpio = of_get_named_gpio_flags(card->dev->of_node, "ingenic,spken-gpio", 0, &flags); ++ if (gpio_is_valid(x1000->spk_gpio)) { ++ unsigned long init_flags; ++ x1000->spk_en_level = (flags == OF_GPIO_ACTIVE_LOW ? 0 : 1); ++ init_flags = (flags == OF_GPIO_ACTIVE_LOW ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW); ++ ret = devm_gpio_request_one(card->dev, x1000->spk_gpio, init_flags, "Speaker_en"); ++ if (ret) ++ pr_warn("dorado speaker enable pin(%d) request failed\n",x1000->spk_gpio); ++ else ++ pr_info("dorado speaker enable pin(%d) request ok\n", x1000->spk_gpio); ++ } ++ ++ for (i = 0; i < card->num_links; i++) { ++ dai_link[i].cpu_of_node = of_parse_phandle(snd_node, "ingenic,cpu-dai" , i); ++ dai_link[i].platform_of_node = of_parse_phandle(snd_node, "ingenic,platform", i); ++ dai_link[i].codec_of_node = of_parse_phandle(snd_node, "ingenic,codec", i); ++ ret = of_property_read_string_index(snd_node, "ingenic,codec-dai", i, ++ &(dai_link[i].codec_dai_name)); ++ if (ret || !dai_link[i].cpu_of_node || ++ !dai_link[i].codec_of_node || ++ !dai_link[i].platform_of_node) ++ return -ENODEV; ++ ret = of_property_read_string_index(snd_node, "ingenic,dai-link", i, ++ &(dai_link[i].name)); ++ if (ret) ++ return -ENODEV; ++ ret = of_property_read_string_index(snd_node, "ingenic,stream", i, ++ &(dai_link[i].stream_name)); ++ if (ret) ++ dai_link[i].stream_name = dai_link[i].name; ++ ++ dev_dbg(&pdev->dev, "dai_link %s\n", dai_link[i].name); ++ dev_dbg(&pdev->dev, "stream_name %s\n", dai_link[i].stream_name); ++ dev_dbg(&pdev->dev, "cpu %s(%s)\n", dai_link[i].cpu_of_node->name, ++ dai_link[i].cpu_of_node->full_name); ++ dev_dbg(&pdev->dev, "platform %s(%s)\n", dai_link[i].platform_of_node->name, ++ dai_link[i].platform_of_node->full_name); ++ dev_dbg(&pdev->dev, "codec dai %s\n", dai_link[i].codec_dai_name); ++ dev_dbg(&pdev->dev, "codec %s(%s)\n", dai_link[i].codec_of_node->name, ++ dai_link[i].codec_of_node->full_name); ++ ++ if (!strcmp(dai_link[i].name, "i2s-icdc") || ++ !strcmp(dai_link[i].codec_dai_name, "icdc-d3-hifi")) { ++ dai_link->ops = &x1000_i2s_cdc_ops; ++ dai_link->init = x1000_i2s_cdc_dai_link_init; ++ } ++ } ++ ++ ret = snd_soc_register_card(card); ++ if (ret) { ++ dev_err(&pdev->dev, "snd_soc_register_card failed %d\n", ret); ++ return ret; ++ } ++ ++ platform_set_drvdata(pdev, x1000); ++ dev_info(&pdev->dev, "Sound Card successed\n"); ++ return ret; ++} ++ ++static int snd_x1000_remove(struct platform_device *pdev) ++{ ++ struct x1000_icdc *x1000 = platform_get_drvdata(pdev); ++ snd_soc_unregister_card(&x1000->card); ++ platform_set_drvdata(pdev, NULL); ++ return 0; ++} ++ ++static const struct of_device_id sound_dt_match[] = { ++ { .compatible = "ingenic,x1000-sound", .data = NULL }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, sound_dt_match); ++ ++static struct platform_driver snd_x1000_driver = { ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = "x1000-sound", ++ .pm = &snd_soc_pm_ops, ++ .of_match_table = of_match_ptr(sound_dt_match), ++ }, ++ .probe = snd_x1000_probe, ++ .remove = snd_x1000_remove, ++}; ++module_platform_driver(snd_x1000_driver); ++ ++MODULE_AUTHOR("sccheng"); ++MODULE_DESCRIPTION("ALSA SoC x1000 Snd Card"); ++MODULE_LICENSE("GPL"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_ecodec_Kconfig.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_ecodec_Kconfig.patch new file mode 100644 index 00000000..b3ebb0ef --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_ecodec_Kconfig.patch @@ -0,0 +1,16 @@ +diff -drupN a/sound/soc/ingenic/ecodec/Kconfig b/sound/soc/ingenic/ecodec/Kconfig +--- a/sound/soc/ingenic/ecodec/Kconfig 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/ecodec/Kconfig 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,12 @@ ++config SND_SOC_WM8594 ++ depends on I2C ++ tristate ++ ++config SND_SOC_AK4458 ++ depends on I2C ++ tristate ++ ++config SND_SOC_AK5558 ++ depends on I2C ++ tristate ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_ecodec_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_ecodec_Makefile.patch new file mode 100644 index 00000000..c07d3ba3 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_ecodec_Makefile.patch @@ -0,0 +1,9 @@ +diff -drupN a/sound/soc/ingenic/ecodec/Makefile b/sound/soc/ingenic/ecodec/Makefile +--- a/sound/soc/ingenic/ecodec/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/ecodec/Makefile 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,5 @@ ++ ++obj-$(CONFIG_SND_SOC_WM8594) += wm8594.o ++obj-$(CONFIG_SND_SOC_AK4458) += ak4458.o ++obj-$(CONFIG_SND_SOC_AK5558) += ak5558.o ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_ecodec_ak4458.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_ecodec_ak4458.c.patch new file mode 100644 index 00000000..17271e93 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_ecodec_ak4458.c.patch @@ -0,0 +1,689 @@ +diff -drupN a/sound/soc/ingenic/ecodec/ak4458.c b/sound/soc/ingenic/ecodec/ak4458.c +--- a/sound/soc/ingenic/ecodec/ak4458.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/ecodec/ak4458.c 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,685 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// ++// Audio driver for AK4458 DAC ++// ++// Copyright (C) 2016 Asahi Kasei Microdevices Corporation ++// Copyright 2018 NXP ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ak4458.h" ++ ++/* AK4458 Codec Private Data */ ++struct ak4458_priv { ++ struct device *dev; ++ struct regmap *regmap; ++ struct gpio_desc *reset_gpiod; ++ struct gpio_desc *mute_gpiod; ++ int digfil; /* SSLOW, SD, SLOW bits */ ++ int fs; /* sampling rate */ ++ int fmt; ++ int slots; ++ int slot_width; ++}; ++ ++static const struct reg_default ak4458_reg_defaults[] = { ++ { 0x00, 0x0C }, /* 0x00 AK4458_00_CONTROL1 */ ++ { 0x01, 0x22 }, /* 0x01 AK4458_01_CONTROL2 */ ++ { 0x02, 0x00 }, /* 0x02 AK4458_02_CONTROL3 */ ++ { 0x03, 0xFF }, /* 0x03 AK4458_03_LCHATT */ ++ { 0x04, 0xFF }, /* 0x04 AK4458_04_RCHATT */ ++ { 0x05, 0x00 }, /* 0x05 AK4458_05_CONTROL4 */ ++ { 0x06, 0x00 }, /* 0x06 AK4458_06_DSD1 */ ++ { 0x07, 0x03 }, /* 0x07 AK4458_07_CONTROL5 */ ++ { 0x08, 0x00 }, /* 0x08 AK4458_08_SOUND_CONTROL */ ++ { 0x09, 0x00 }, /* 0x09 AK4458_09_DSD2 */ ++ { 0x0A, 0x0D }, /* 0x0A AK4458_0A_CONTROL6 */ ++ { 0x0B, 0x0C }, /* 0x0B AK4458_0B_CONTROL7 */ ++ { 0x0C, 0x00 }, /* 0x0C AK4458_0C_CONTROL8 */ ++ { 0x0D, 0x00 }, /* 0x0D AK4458_0D_CONTROL9 */ ++ { 0x0E, 0x50 }, /* 0x0E AK4458_0E_CONTROL10 */ ++ { 0x0F, 0xFF }, /* 0x0F AK4458_0F_L2CHATT */ ++ { 0x10, 0xFF }, /* 0x10 AK4458_10_R2CHATT */ ++ { 0x11, 0xFF }, /* 0x11 AK4458_11_L3CHATT */ ++ { 0x12, 0xFF }, /* 0x12 AK4458_12_R3CHATT */ ++ { 0x13, 0xFF }, /* 0x13 AK4458_13_L4CHATT */ ++ { 0x14, 0xFF }, /* 0x14 AK4458_14_R4CHATT */ ++}; ++ ++/* ++ * Volume control: ++ * from -127 to 0 dB in 0.5 dB steps (mute instead of -127.5 dB) ++ */ ++static DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1); ++ ++/* ++ * DEM1 bit DEM0 bit Mode ++ * 0 0 44.1kHz ++ * 0 1 OFF (default) ++ * 1 0 48kHz ++ * 1 1 32kHz ++ */ ++static const char * const ak4458_dem_select_texts[] = { ++ "44.1kHz", "OFF", "48kHz", "32kHz" ++}; ++ ++/* ++ * SSLOW, SD, SLOW bits Digital Filter Setting ++ * 0, 0, 0 : Sharp Roll-Off Filter ++ * 0, 0, 1 : Slow Roll-Off Filter ++ * 0, 1, 0 : Short delay Sharp Roll-Off Filter ++ * 0, 1, 1 : Short delay Slow Roll-Off Filter ++ * 1, *, * : Super Slow Roll-Off Filter ++ */ ++static const char * const ak4458_digfil_select_texts[] = { ++ "Sharp Roll-Off Filter", ++ "Slow Roll-Off Filter", ++ "Short delay Sharp Roll-Off Filter", ++ "Short delay Slow Roll-Off Filter", ++ "Super Slow Roll-Off Filter" ++}; ++ ++/* ++ * DZFB: Inverting Enable of DZF ++ * 0: DZF goes H at Zero Detection ++ * 1: DZF goes L at Zero Detection ++ */ ++static const char * const ak4458_dzfb_select_texts[] = {"H", "L"}; ++ ++/* ++ * SC1-0 bits: Sound Mode Setting ++ * 0 0 : Sound Mode 0 ++ * 0 1 : Sound Mode 1 ++ * 1 0 : Sound Mode 2 ++ * 1 1 : Reserved ++ */ ++static const char * const ak4458_sc_select_texts[] = { ++ "Sound Mode 0", "Sound Mode 1", "Sound Mode 2" ++}; ++ ++/* FIR2-0 bits: FIR Filter Mode Setting */ ++static const char * const ak4458_fir_select_texts[] = { ++ "Mode 0", "Mode 1", "Mode 2", "Mode 3", ++ "Mode 4", "Mode 5", "Mode 6", "Mode 7", ++}; ++ ++/* ATS1-0 bits Attenuation Speed */ ++static const char * const ak4458_ats_select_texts[] = { ++ "4080/fs", "2040/fs", "510/fs", "255/fs", ++}; ++ ++/* DIF2 bit Audio Interface Format Setting(BICK fs) */ ++static const char * const ak4458_dif_select_texts[] = {"32fs,48fs", "64fs",}; ++ ++static const struct soc_enum ak4458_dac1_dem_enum = ++ SOC_ENUM_SINGLE(AK4458_01_CONTROL2, 1, ++ ARRAY_SIZE(ak4458_dem_select_texts), ++ ak4458_dem_select_texts); ++static const struct soc_enum ak4458_dac2_dem_enum = ++ SOC_ENUM_SINGLE(AK4458_0A_CONTROL6, 0, ++ ARRAY_SIZE(ak4458_dem_select_texts), ++ ak4458_dem_select_texts); ++static const struct soc_enum ak4458_dac3_dem_enum = ++ SOC_ENUM_SINGLE(AK4458_0E_CONTROL10, 4, ++ ARRAY_SIZE(ak4458_dem_select_texts), ++ ak4458_dem_select_texts); ++static const struct soc_enum ak4458_dac4_dem_enum = ++ SOC_ENUM_SINGLE(AK4458_0E_CONTROL10, 6, ++ ARRAY_SIZE(ak4458_dem_select_texts), ++ ak4458_dem_select_texts); ++static const struct soc_enum ak4458_digfil_enum = ++ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ak4458_digfil_select_texts), ++ ak4458_digfil_select_texts); ++static const struct soc_enum ak4458_dzfb_enum = ++ SOC_ENUM_SINGLE(AK4458_02_CONTROL3, 2, ++ ARRAY_SIZE(ak4458_dzfb_select_texts), ++ ak4458_dzfb_select_texts); ++static const struct soc_enum ak4458_sm_enum = ++ SOC_ENUM_SINGLE(AK4458_08_SOUND_CONTROL, 0, ++ ARRAY_SIZE(ak4458_sc_select_texts), ++ ak4458_sc_select_texts); ++static const struct soc_enum ak4458_fir_enum = ++ SOC_ENUM_SINGLE(AK4458_0C_CONTROL8, 0, ++ ARRAY_SIZE(ak4458_fir_select_texts), ++ ak4458_fir_select_texts); ++static const struct soc_enum ak4458_ats_enum = ++ SOC_ENUM_SINGLE(AK4458_0B_CONTROL7, 6, ++ ARRAY_SIZE(ak4458_ats_select_texts), ++ ak4458_ats_select_texts); ++static const struct soc_enum ak4458_dif_enum = ++ SOC_ENUM_SINGLE(AK4458_00_CONTROL1, 3, ++ ARRAY_SIZE(ak4458_dif_select_texts), ++ ak4458_dif_select_texts); ++ ++static int get_digfil(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); ++ struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component); ++ ++ ucontrol->value.enumerated.item[0] = ak4458->digfil; ++ ++ return 0; ++} ++ ++static int set_digfil(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); ++ struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component); ++ int num; ++ ++ num = ucontrol->value.enumerated.item[0]; ++ if (num > 4) ++ return -EINVAL; ++ ++ ak4458->digfil = num; ++ ++ /* write SD bit */ ++ snd_soc_component_update_bits(component, AK4458_01_CONTROL2, ++ AK4458_SD_MASK, ++ ((ak4458->digfil & 0x02) << 4)); ++ ++ /* write SLOW bit */ ++ snd_soc_component_update_bits(component, AK4458_02_CONTROL3, ++ AK4458_SLOW_MASK, ++ (ak4458->digfil & 0x01)); ++ ++ /* write SSLOW bit */ ++ snd_soc_component_update_bits(component, AK4458_05_CONTROL4, ++ AK4458_SSLOW_MASK, ++ ((ak4458->digfil & 0x04) >> 2)); ++ ++ return 0; ++} ++ ++static const struct snd_kcontrol_new ak4458_snd_controls[] = { ++ SOC_DOUBLE_R_TLV("DAC1 Playback Volume", AK4458_03_LCHATT, ++ AK4458_04_RCHATT, 0, 0xFF, 0, dac_tlv), ++ SOC_DOUBLE_R_TLV("DAC2 Playback Volume", AK4458_0F_L2CHATT, ++ AK4458_10_R2CHATT, 0, 0xFF, 0, dac_tlv), ++ SOC_DOUBLE_R_TLV("DAC3 Playback Volume", AK4458_11_L3CHATT, ++ AK4458_12_R3CHATT, 0, 0xFF, 0, dac_tlv), ++ SOC_DOUBLE_R_TLV("DAC4 Playback Volume", AK4458_13_L4CHATT, ++ AK4458_14_R4CHATT, 0, 0xFF, 0, dac_tlv), ++ SOC_ENUM("AK4458 De-emphasis Response DAC1", ak4458_dac1_dem_enum), ++ SOC_ENUM("AK4458 De-emphasis Response DAC2", ak4458_dac2_dem_enum), ++ SOC_ENUM("AK4458 De-emphasis Response DAC3", ak4458_dac3_dem_enum), ++ SOC_ENUM("AK4458 De-emphasis Response DAC4", ak4458_dac4_dem_enum), ++ SOC_ENUM_EXT("AK4458 Digital Filter Setting", ak4458_digfil_enum, ++ get_digfil, set_digfil), ++ SOC_ENUM("AK4458 Inverting Enable of DZFB", ak4458_dzfb_enum), ++ SOC_ENUM("AK4458 Sound Mode", ak4458_sm_enum), ++ SOC_ENUM("AK4458 FIR Filter Mode Setting", ak4458_fir_enum), ++ SOC_ENUM("AK4458 Attenuation transition Time Setting", ++ ak4458_ats_enum), ++ SOC_ENUM("AK4458 BICK fs Setting", ak4458_dif_enum), ++}; ++ ++/* ak4458 dapm widgets */ ++static const struct snd_soc_dapm_widget ak4458_dapm_widgets[] = { ++ SND_SOC_DAPM_DAC("AK4458 DAC1", NULL, AK4458_0A_CONTROL6, 2, 0),/*pw*/ ++ SND_SOC_DAPM_AIF_IN("AK4458 SDTI", "Playback", 0, SND_SOC_NOPM, 0, 0), ++ SND_SOC_DAPM_OUTPUT("AK4458 AOUTA"), ++ ++ SND_SOC_DAPM_DAC("AK4458 DAC2", NULL, AK4458_0A_CONTROL6, 3, 0),/*pw*/ ++ SND_SOC_DAPM_OUTPUT("AK4458 AOUTB"), ++ ++ SND_SOC_DAPM_DAC("AK4458 DAC3", NULL, AK4458_0B_CONTROL7, 2, 0),/*pw*/ ++ SND_SOC_DAPM_OUTPUT("AK4458 AOUTC"), ++ ++ SND_SOC_DAPM_DAC("AK4458 DAC4", NULL, AK4458_0B_CONTROL7, 3, 0),/*pw*/ ++ SND_SOC_DAPM_OUTPUT("AK4458 AOUTD"), ++}; ++ ++static const struct snd_soc_dapm_route ak4458_intercon[] = { ++ {"AK4458 DAC1", NULL, "AK4458 SDTI"}, ++ {"AK4458 AOUTA", NULL, "AK4458 DAC1"}, ++ ++ {"AK4458 DAC2", NULL, "AK4458 SDTI"}, ++ {"AK4458 AOUTB", NULL, "AK4458 DAC2"}, ++ ++ {"AK4458 DAC3", NULL, "AK4458 SDTI"}, ++ {"AK4458 AOUTC", NULL, "AK4458 DAC3"}, ++ ++ {"AK4458 DAC4", NULL, "AK4458 SDTI"}, ++ {"AK4458 AOUTD", NULL, "AK4458 DAC4"}, ++}; ++ ++static int ak4458_rstn_control(struct snd_soc_component *component, int bit) ++{ ++ int ret; ++ ++ if (bit) ++ ret = snd_soc_component_update_bits(component, ++ AK4458_00_CONTROL1, ++ AK4458_RSTN_MASK, ++ 0x1); ++ else ++ ret = snd_soc_component_update_bits(component, ++ AK4458_00_CONTROL1, ++ AK4458_RSTN_MASK, ++ 0x0); ++ return ret; ++} ++ ++static int ak4458_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params, ++ struct snd_soc_dai *dai) ++{ ++ struct snd_soc_component *component = dai->component; ++ struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component); ++ int pcm_width = max(params_physical_width(params), ak4458->slot_width); ++ int nfs1; ++ u8 format; ++ ++ nfs1 = params_rate(params); ++ ak4458->fs = nfs1; ++ ++ /* Master Clock Frequency Auto Setting Mode Enable */ ++ snd_soc_component_update_bits(component, AK4458_00_CONTROL1, 0x80, 0x80); ++ ++ switch (pcm_width) { ++ case 16: ++ if (ak4458->fmt == SND_SOC_DAIFMT_I2S) ++ format = AK4458_DIF_24BIT_I2S; ++ else ++ format = AK4458_DIF_16BIT_LSB; ++ break; ++ case 24: ++ switch (ak4458->fmt) { ++ case SND_SOC_DAIFMT_I2S: ++ format = AK4458_DIF_24BIT_I2S; ++ break; ++ case SND_SOC_DAIFMT_LEFT_J: ++ format = AK4458_DIF_24BIT_MSB; ++ break; ++ case SND_SOC_DAIFMT_RIGHT_J: ++ format = AK4458_DIF_24BIT_LSB; ++ break; ++ case SND_SOC_DAIFMT_DSP_B: ++ format = AK4458_DIF_24BIT_MSB; ++ break; ++ default: ++ return -EINVAL; ++ } ++ case 32: ++ switch (ak4458->fmt) { ++ case SND_SOC_DAIFMT_I2S: ++ format = AK4458_DIF_32BIT_I2S; ++ break; ++ case SND_SOC_DAIFMT_LEFT_J: ++ format = AK4458_DIF_32BIT_MSB; ++ break; ++ case SND_SOC_DAIFMT_RIGHT_J: ++ format = AK4458_DIF_32BIT_LSB; ++ break; ++ case SND_SOC_DAIFMT_DSP_B: ++ format = AK4458_DIF_32BIT_MSB; ++ break; ++ default: ++ return -EINVAL; ++ } ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ snd_soc_component_update_bits(component, AK4458_00_CONTROL1, ++ AK4458_DIF_MASK, format); ++ ++ ak4458_rstn_control(component, 0); ++ ak4458_rstn_control(component, 1); ++ ++ return 0; ++} ++ ++static int ak4458_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) ++{ ++ struct snd_soc_component *component = dai->component; ++ struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component); ++ ++ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { ++ case SND_SOC_DAIFMT_CBS_CFS: /* Slave Mode */ ++ break; ++ case SND_SOC_DAIFMT_CBM_CFM: /* Master Mode is not supported */ ++ case SND_SOC_DAIFMT_CBS_CFM: ++ case SND_SOC_DAIFMT_CBM_CFS: ++ default: ++ dev_err(component->dev, "Master mode unsupported\n"); ++ return -EINVAL; ++ } ++ ++ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { ++ case SND_SOC_DAIFMT_I2S: ++ case SND_SOC_DAIFMT_LEFT_J: ++ case SND_SOC_DAIFMT_RIGHT_J: ++ case SND_SOC_DAIFMT_DSP_B: ++ ak4458->fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK; ++ break; ++ default: ++ dev_err(component->dev, "Audio format 0x%02X unsupported\n", ++ fmt & SND_SOC_DAIFMT_FORMAT_MASK); ++ return -EINVAL; ++ } ++ ++ ak4458_rstn_control(component, 0); ++ ak4458_rstn_control(component, 1); ++ ++ return 0; ++} ++ ++static const int att_speed[] = { 4080, 2040, 510, 255 }; ++ ++static int ak4458_set_dai_mute(struct snd_soc_dai *dai, int mute) ++{ ++ struct snd_soc_component *component = dai->component; ++ struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component); ++ int nfs, ndt, ret, reg; ++ int ats; ++ ++ nfs = ak4458->fs; ++ ++ reg = snd_soc_component_read32(component, AK4458_0B_CONTROL7); ++ ats = (reg & AK4458_ATS_MASK) >> AK4458_ATS_SHIFT; ++ ++ ndt = att_speed[ats] / (nfs / 1000); ++ ++ if (mute) { ++ ret = snd_soc_component_update_bits(component, AK4458_01_CONTROL2, 0x01, 1); ++ mdelay(ndt); ++ if (ak4458->mute_gpiod) ++ gpiod_set_value_cansleep(ak4458->mute_gpiod, 1); ++ } else { ++ if (ak4458->mute_gpiod) ++ gpiod_set_value_cansleep(ak4458->mute_gpiod, 0); ++ ret = snd_soc_component_update_bits(component, AK4458_01_CONTROL2, 0x01, 0); ++ mdelay(ndt); ++ } ++ ++ return 0; ++} ++ ++static int ak4458_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, ++ unsigned int rx_mask, int slots, int slot_width) ++{ ++ struct snd_soc_component *component = dai->component; ++ struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component); ++ int mode; ++ ++ ak4458->slots = slots; ++ ak4458->slot_width = slot_width; ++ ++ switch (slots * slot_width) { ++ case 128: ++ mode = AK4458_MODE_TDM128; ++ break; ++ case 256: ++ mode = AK4458_MODE_TDM256; ++ break; ++ case 512: ++ mode = AK4458_MODE_TDM512; ++ break; ++ default: ++ mode = AK4458_MODE_NORMAL; ++ break; ++ } ++ ++ snd_soc_component_update_bits(component, AK4458_0A_CONTROL6, ++ AK4458_MODE_MASK, ++ mode); ++ ++ return 0; ++} ++ ++#define AK4458_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ ++ SNDRV_PCM_FMTBIT_S24_LE |\ ++ SNDRV_PCM_FMTBIT_S32_LE) ++ ++static const unsigned int ak4458_rates[] = { ++ 8000, 11025, 16000, 22050, ++ 32000, 44100, 48000, 88200, ++ 96000, 176400, 192000, 352800, ++ 384000, 705600, 768000, 1411200, ++ 2822400, ++}; ++ ++static const struct snd_pcm_hw_constraint_list ak4458_rate_constraints = { ++ .count = ARRAY_SIZE(ak4458_rates), ++ .list = ak4458_rates, ++}; ++ ++static int ak4458_startup(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ int ret; ++ ++ ret = snd_pcm_hw_constraint_list(substream->runtime, 0, ++ SNDRV_PCM_HW_PARAM_RATE, ++ &ak4458_rate_constraints); ++ ++ return ret; ++} ++ ++static struct snd_soc_dai_ops ak4458_dai_ops = { ++ .startup = ak4458_startup, ++ .hw_params = ak4458_hw_params, ++ .set_fmt = ak4458_set_dai_fmt, ++ .digital_mute = ak4458_set_dai_mute, ++ .set_tdm_slot = ak4458_set_tdm_slot, ++}; ++ ++static struct snd_soc_dai_driver ak4458_dai = { ++ .name = "ak4458-aif", ++ .playback = { ++ .stream_name = "Playback", ++ .channels_min = 1, ++ .channels_max = 8, ++ .rates = SNDRV_PCM_RATE_KNOT, ++ .formats = AK4458_FORMATS, ++ }, ++ .ops = &ak4458_dai_ops, ++}; ++ ++static void ak4458_power_off(struct ak4458_priv *ak4458) ++{ ++ if (ak4458->reset_gpiod) { ++ gpiod_set_value_cansleep(ak4458->reset_gpiod, 0); ++ usleep_range(1000, 2000); ++ } ++} ++ ++static void ak4458_power_on(struct ak4458_priv *ak4458) ++{ ++ if (ak4458->reset_gpiod) { ++ gpiod_set_value_cansleep(ak4458->reset_gpiod, 1); ++ usleep_range(1000, 2000); ++ } ++} ++ ++static void ak4458_init(struct snd_soc_component *component) ++{ ++ struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component); ++ ++ /* External Mute ON */ ++ if (ak4458->mute_gpiod) ++ gpiod_set_value_cansleep(ak4458->mute_gpiod, 1); ++ ++ ak4458_power_on(ak4458); ++ ++ snd_soc_component_update_bits(component, AK4458_00_CONTROL1, ++ 0x80, 0x80); /* ACKS bit = 1; 10000000 */ ++ ++ ak4458_rstn_control(component, 1); ++} ++ ++static int ak4458_probe(struct snd_soc_component *component) ++{ ++ struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component); ++ ++ ak4458_init(component); ++ ++ ak4458->fs = 48000; ++ ++ return 0; ++} ++ ++static void ak4458_remove(struct snd_soc_component *component) ++{ ++ struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component); ++ ++ ak4458_power_off(ak4458); ++} ++ ++#ifdef CONFIG_PM ++static int __maybe_unused ak4458_runtime_suspend(struct device *dev) ++{ ++ struct ak4458_priv *ak4458 = dev_get_drvdata(dev); ++ ++ regcache_cache_only(ak4458->regmap, true); ++ ++ ak4458_power_off(ak4458); ++ ++ if (ak4458->mute_gpiod) ++ gpiod_set_value_cansleep(ak4458->mute_gpiod, 0); ++ ++ return 0; ++} ++ ++static int __maybe_unused ak4458_runtime_resume(struct device *dev) ++{ ++ struct ak4458_priv *ak4458 = dev_get_drvdata(dev); ++ ++ if (ak4458->mute_gpiod) ++ gpiod_set_value_cansleep(ak4458->mute_gpiod, 1); ++ ++ ak4458_power_off(ak4458); ++ ak4458_power_on(ak4458); ++ ++ regcache_cache_only(ak4458->regmap, false); ++ regcache_mark_dirty(ak4458->regmap); ++ ++ return regcache_sync(ak4458->regmap); ++} ++#endif /* CONFIG_PM */ ++ ++struct snd_soc_component_driver soc_codec_dev_ak4458 = { ++ .probe = ak4458_probe, ++ .remove = ak4458_remove, ++ .controls = ak4458_snd_controls, ++ .num_controls = ARRAY_SIZE(ak4458_snd_controls), ++ .dapm_widgets = ak4458_dapm_widgets, ++ .num_dapm_widgets = ARRAY_SIZE(ak4458_dapm_widgets), ++ .dapm_routes = ak4458_intercon, ++ .num_dapm_routes = ARRAY_SIZE(ak4458_intercon), ++#if 0 ++ .idle_bias_on = 1, ++ .use_pmdown_time = 1, ++ .endianness = 1, ++ .non_legacy_dai_naming = 1, ++#endif ++}; ++ ++static const struct regmap_config ak4458_regmap = { ++ .reg_bits = 8, ++ .val_bits = 8, ++ ++ .max_register = AK4458_14_R4CHATT, ++ .reg_defaults = ak4458_reg_defaults, ++ .num_reg_defaults = ARRAY_SIZE(ak4458_reg_defaults), ++ .cache_type = REGCACHE_RBTREE, ++}; ++ ++static const struct dev_pm_ops ak4458_pm = { ++ SET_RUNTIME_PM_OPS(ak4458_runtime_suspend, ak4458_runtime_resume, NULL) ++ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, ++ pm_runtime_force_resume) ++}; ++ ++static int ak4458_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) ++{ ++ struct ak4458_priv *ak4458; ++ int ret; ++ ++ ak4458 = devm_kzalloc(&i2c->dev, sizeof(*ak4458), GFP_KERNEL); ++ if (!ak4458) ++ return -ENOMEM; ++ ++ ak4458->regmap = devm_regmap_init_i2c(i2c, &ak4458_regmap); ++ if (IS_ERR(ak4458->regmap)) ++ return PTR_ERR(ak4458->regmap); ++ ++ i2c_set_clientdata(i2c, ak4458); ++ ak4458->dev = &i2c->dev; ++ ++ ak4458->reset_gpiod = devm_gpiod_get_optional(ak4458->dev, "reset", ++ GPIOD_OUT_LOW); ++ if (IS_ERR(ak4458->reset_gpiod)) ++ return PTR_ERR(ak4458->reset_gpiod); ++ ++ ak4458->mute_gpiod = devm_gpiod_get_optional(ak4458->dev, "mute", ++ GPIOD_OUT_LOW); ++ if (IS_ERR(ak4458->mute_gpiod)) ++ return PTR_ERR(ak4458->mute_gpiod); ++ ++ ret = devm_snd_soc_register_component(ak4458->dev, &soc_codec_dev_ak4458, ++ &ak4458_dai, 1); ++ if (ret < 0) { ++ dev_err(ak4458->dev, "Failed to register CODEC: %d\n", ret); ++ return ret; ++ } ++ ++ pm_runtime_enable(&i2c->dev); ++ ++ printk("ak4458 probe ok, dev_name: %s\n", dev_name(ak4458->dev)); ++ ++ return 0; ++} ++ ++static int ak4458_i2c_remove(struct i2c_client *i2c) ++{ ++ pm_runtime_disable(&i2c->dev); ++ ++ return 0; ++} ++ ++static const struct i2c_device_id ak4458_i2c_table[] = { ++ {"ak4458", 0}, ++ {} ++}; ++MODULE_DEVICE_TABLE(i2c, ak4458_i2c_table); ++ ++static const struct of_device_id ak4458_of_match[] = { ++ { .compatible = "asahi-kasei,ak4458", }, ++ { }, ++}; ++ ++static struct i2c_driver ak4458_i2c_driver = { ++ .driver = { ++ .name = "ak4458", ++ .pm = &ak4458_pm, ++ .of_match_table = ak4458_of_match, ++ }, ++ .probe = ak4458_i2c_probe, ++ .remove = ak4458_i2c_remove, ++ .id_table = ak4458_i2c_table, ++}; ++ ++module_i2c_driver(ak4458_i2c_driver); ++ ++MODULE_AUTHOR("Junichi Wakasugi "); ++MODULE_AUTHOR("Mihai Serban "); ++MODULE_DESCRIPTION("ASoC AK4458 DAC driver"); ++MODULE_LICENSE("GPL v2"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_ecodec_ak4458.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_ecodec_ak4458.h.patch new file mode 100644 index 00000000..e50ed7d5 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_ecodec_ak4458.h.patch @@ -0,0 +1,92 @@ +diff -drupN a/sound/soc/ingenic/ecodec/ak4458.h b/sound/soc/ingenic/ecodec/ak4458.h +--- a/sound/soc/ingenic/ecodec/ak4458.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/ecodec/ak4458.h 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,88 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Audio driver for AK4458 ++ * ++ * Copyright (C) 2016 Asahi Kasei Microdevices Corporation ++ * Copyright 2018 NXP ++ */ ++ ++#ifndef _AK4458_H ++#define _AK4458_H ++ ++#include ++ ++/* Settings */ ++ ++#define AK4458_00_CONTROL1 0x00 ++#define AK4458_01_CONTROL2 0x01 ++#define AK4458_02_CONTROL3 0x02 ++#define AK4458_03_LCHATT 0x03 ++#define AK4458_04_RCHATT 0x04 ++#define AK4458_05_CONTROL4 0x05 ++#define AK4458_06_DSD1 0x06 ++#define AK4458_07_CONTROL5 0x07 ++#define AK4458_08_SOUND_CONTROL 0x08 ++#define AK4458_09_DSD2 0x09 ++#define AK4458_0A_CONTROL6 0x0A ++#define AK4458_0B_CONTROL7 0x0B ++#define AK4458_0C_CONTROL8 0x0C ++#define AK4458_0D_CONTROL9 0x0D ++#define AK4458_0E_CONTROL10 0x0E ++#define AK4458_0F_L2CHATT 0x0F ++#define AK4458_10_R2CHATT 0x10 ++#define AK4458_11_L3CHATT 0x11 ++#define AK4458_12_R3CHATT 0x12 ++#define AK4458_13_L4CHATT 0x13 ++#define AK4458_14_R4CHATT 0x14 ++ ++/* Bitfield Definitions */ ++ ++/* AK4458_00_CONTROL1 (0x00) Fields ++ * Addr Register Name D7 D6 D5 D4 D3 D2 D1 D0 ++ * 00H Control 1 ACKS 0 0 0 DIF2 DIF1 DIF0 RSTN ++ */ ++ ++/* Digital Filter (SD, SLOW, SSLOW) */ ++#define AK4458_SD_MASK GENMASK(5, 5) ++#define AK4458_SLOW_MASK GENMASK(0, 0) ++#define AK4458_SSLOW_MASK GENMASK(0, 0) ++ ++/* DIF2 1 0 ++ * x 1 0 MSB justified Figure 3 (default) ++ * x 1 1 I2S Compliment Figure 4 ++ */ ++#define AK4458_DIF_SHIFT 1 ++#define AK4458_DIF_MASK GENMASK(3, 1) ++ ++#define AK4458_DIF_16BIT_LSB (0 << 1) ++#define AK4458_DIF_24BIT_MSB (2 << 1) ++#define AK4458_DIF_24BIT_I2S (3 << 1) ++#define AK4458_DIF_24BIT_LSB (4 << 1) ++#define AK4458_DIF_32BIT_LSB (5 << 1) ++#define AK4458_DIF_32BIT_MSB (6 << 1) ++#define AK4458_DIF_32BIT_I2S (7 << 1) ++ ++/* AK4458_00_CONTROL1 (0x00) D0 bit */ ++#define AK4458_RSTN_MASK GENMASK(0, 0) ++#define AK4458_RSTN (0x1 << 0) ++ ++/* AK4458_0A_CONTROL6 Mode bits */ ++#define AK4458_MODE_SHIFT 6 ++#define AK4458_MODE_MASK GENMASK(7, 6) ++#define AK4458_MODE_NORMAL (0 << AK4458_MODE_SHIFT) ++#define AK4458_MODE_TDM128 (1 << AK4458_MODE_SHIFT) ++#define AK4458_MODE_TDM256 (2 << AK4458_MODE_SHIFT) ++#define AK4458_MODE_TDM512 (3 << AK4458_MODE_SHIFT) ++ ++/* DAC Digital attenuator transition time setting ++ * Table 19 ++ * Mode ATS1 ATS2 ATT speed ++ * 0 0 0 4080/fs ++ * 1 0 1 2040/fs ++ * 2 1 0 510/fs ++ * 3 1 1 255/fs ++ * */ ++#define AK4458_ATS_SHIFT 6 ++#define AK4458_ATS_MASK GENMASK(7, 6) ++ ++#endif /* _AK4458_H */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_ecodec_ak5558.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_ecodec_ak5558.c.patch new file mode 100644 index 00000000..d3304e69 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_ecodec_ak5558.c.patch @@ -0,0 +1,429 @@ +diff -drupN a/sound/soc/ingenic/ecodec/ak5558.c b/sound/soc/ingenic/ecodec/ak5558.c +--- a/sound/soc/ingenic/ecodec/ak5558.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/ecodec/ak5558.c 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,425 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// ++// Audio driver for AK5558 ADC ++// ++// Copyright (C) 2015 Asahi Kasei Microdevices Corporation ++// Copyright 2018 NXP ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ak5558.h" ++ ++/* AK5558 Codec Private Data */ ++struct ak5558_priv { ++ struct snd_soc_component component; ++ struct regmap *regmap; ++ struct i2c_client *i2c; ++ struct gpio_desc *reset_gpiod; /* Reset & Power down GPIO */ ++ int slots; ++ int slot_width; ++}; ++ ++/* ak5558 register cache & default register settings */ ++static const struct reg_default ak5558_reg[] = { ++ { 0x0, 0xFF }, /* 0x00 AK5558_00_POWER_MANAGEMENT1 */ ++ { 0x1, 0x01 }, /* 0x01 AK5558_01_POWER_MANAGEMENT2 */ ++ { 0x2, 0x01 }, /* 0x02 AK5558_02_CONTROL1 */ ++ { 0x3, 0x00 }, /* 0x03 AK5558_03_CONTROL2 */ ++ { 0x4, 0x00 }, /* 0x04 AK5558_04_CONTROL3 */ ++ { 0x5, 0x00 } /* 0x05 AK5558_05_DSD */ ++}; ++ ++static const char * const mono_texts[] = { ++ "8 Slot", "2 Slot", "4 Slot", "1 Slot", ++}; ++ ++static const struct soc_enum ak5558_mono_enum[] = { ++ SOC_ENUM_SINGLE(AK5558_01_POWER_MANAGEMENT2, 1, ++ ARRAY_SIZE(mono_texts), mono_texts), ++}; ++ ++static const char * const digfil_texts[] = { ++ "Sharp Roll-Off", "Show Roll-Off", ++ "Short Delay Sharp Roll-Off", "Short Delay Show Roll-Off", ++}; ++ ++static const struct soc_enum ak5558_adcset_enum[] = { ++ SOC_ENUM_SINGLE(AK5558_04_CONTROL3, 0, ++ ARRAY_SIZE(digfil_texts), digfil_texts), ++}; ++ ++static const struct snd_kcontrol_new ak5558_snd_controls[] = { ++ SOC_ENUM("AK5558 Monaural Mode", ak5558_mono_enum[0]), ++ SOC_ENUM("AK5558 Digital Filter", ak5558_adcset_enum[0]), ++}; ++ ++static const struct snd_soc_dapm_widget ak5558_dapm_widgets[] = { ++ /* Analog Input */ ++ SND_SOC_DAPM_INPUT("AIN1"), ++ SND_SOC_DAPM_INPUT("AIN2"), ++ SND_SOC_DAPM_INPUT("AIN3"), ++ SND_SOC_DAPM_INPUT("AIN4"), ++ SND_SOC_DAPM_INPUT("AIN5"), ++ SND_SOC_DAPM_INPUT("AIN6"), ++ SND_SOC_DAPM_INPUT("AIN7"), ++ SND_SOC_DAPM_INPUT("AIN8"), ++ ++ SND_SOC_DAPM_ADC("ADC Ch1", NULL, AK5558_00_POWER_MANAGEMENT1, 0, 0), ++ SND_SOC_DAPM_ADC("ADC Ch2", NULL, AK5558_00_POWER_MANAGEMENT1, 1, 0), ++ SND_SOC_DAPM_ADC("ADC Ch3", NULL, AK5558_00_POWER_MANAGEMENT1, 2, 0), ++ SND_SOC_DAPM_ADC("ADC Ch4", NULL, AK5558_00_POWER_MANAGEMENT1, 3, 0), ++ SND_SOC_DAPM_ADC("ADC Ch5", NULL, AK5558_00_POWER_MANAGEMENT1, 4, 0), ++ SND_SOC_DAPM_ADC("ADC Ch6", NULL, AK5558_00_POWER_MANAGEMENT1, 5, 0), ++ SND_SOC_DAPM_ADC("ADC Ch7", NULL, AK5558_00_POWER_MANAGEMENT1, 6, 0), ++ SND_SOC_DAPM_ADC("ADC Ch8", NULL, AK5558_00_POWER_MANAGEMENT1, 7, 0), ++ ++ SND_SOC_DAPM_AIF_OUT("SDTO", "Capture", 0, SND_SOC_NOPM, 0, 0), ++}; ++ ++static const struct snd_soc_dapm_route ak5558_intercon[] = { ++ {"ADC Ch1", NULL, "AIN1"}, ++ {"SDTO", NULL, "ADC Ch1"}, ++ ++ {"ADC Ch2", NULL, "AIN2"}, ++ {"SDTO", NULL, "ADC Ch2"}, ++ ++ {"ADC Ch3", NULL, "AIN3"}, ++ {"SDTO", NULL, "ADC Ch3"}, ++ ++ {"ADC Ch4", NULL, "AIN4"}, ++ {"SDTO", NULL, "ADC Ch4"}, ++ ++ {"ADC Ch5", NULL, "AIN5"}, ++ {"SDTO", NULL, "ADC Ch5"}, ++ ++ {"ADC Ch6", NULL, "AIN6"}, ++ {"SDTO", NULL, "ADC Ch6"}, ++ ++ {"ADC Ch7", NULL, "AIN7"}, ++ {"SDTO", NULL, "ADC Ch7"}, ++ ++ {"ADC Ch8", NULL, "AIN8"}, ++ {"SDTO", NULL, "ADC Ch8"}, ++}; ++ ++static int ak5558_set_mcki(struct snd_soc_component *component) ++{ ++ return snd_soc_component_update_bits(component, AK5558_02_CONTROL1, AK5558_CKS, ++ AK5558_CKS_AUTO); ++} ++ ++static int ak5558_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params, ++ struct snd_soc_dai *dai) ++{ ++ struct snd_soc_component *component = dai->component; ++ struct ak5558_priv *ak5558 = snd_soc_component_get_drvdata(component); ++ u8 bits; ++ int pcm_width = max(params_physical_width(params), ak5558->slot_width); ++ ++ /* set master/slave audio interface */ ++ bits = snd_soc_component_read32(component, AK5558_02_CONTROL1); ++ bits &= ~AK5558_BITS; ++ ++ switch (pcm_width) { ++ case 16: ++ bits |= AK5558_DIF_24BIT_MODE; ++ break; ++ case 32: ++ bits |= AK5558_DIF_32BIT_MODE; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ snd_soc_component_update_bits(component, AK5558_02_CONTROL1, AK5558_BITS, bits); ++ ++ return 0; ++} ++ ++static int ak5558_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) ++{ ++ struct snd_soc_component *component = dai->component; ++ u8 format; ++ ++ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { ++ case SND_SOC_DAIFMT_CBS_CFS: ++ break; ++ case SND_SOC_DAIFMT_CBM_CFM: ++ break; ++ case SND_SOC_DAIFMT_CBS_CFM: ++ case SND_SOC_DAIFMT_CBM_CFS: ++ default: ++ dev_err(dai->dev, "Clock mode unsupported"); ++ return -EINVAL; ++ } ++ ++ /* set master/slave audio interface */ ++ format = snd_soc_component_read32(component, AK5558_02_CONTROL1); ++ format &= ~AK5558_DIF; ++ ++ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { ++ case SND_SOC_DAIFMT_I2S: ++ format |= AK5558_DIF_I2S_MODE; ++ break; ++ case SND_SOC_DAIFMT_LEFT_J: ++ format |= AK5558_DIF_MSB_MODE; ++ break; ++ case SND_SOC_DAIFMT_DSP_B: ++ format |= AK5558_DIF_MSB_MODE; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ snd_soc_component_update_bits(component, AK5558_02_CONTROL1, AK5558_DIF, format); ++ ++ return 0; ++} ++ ++static int ak5558_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, ++ unsigned int rx_mask, int slots, ++ int slot_width) ++{ ++ struct snd_soc_component *component = dai->component; ++ struct ak5558_priv *ak5558 = snd_soc_component_get_drvdata(component); ++ int tdm_mode; ++ ++ ak5558->slots = slots; ++ ak5558->slot_width = slot_width; ++ ++ switch (slots * slot_width) { ++ case 128: ++ tdm_mode = AK5558_MODE_TDM128; ++ break; ++ case 256: ++ tdm_mode = AK5558_MODE_TDM256; ++ break; ++ case 512: ++ tdm_mode = AK5558_MODE_TDM512; ++ break; ++ default: ++ tdm_mode = AK5558_MODE_NORMAL; ++ break; ++ } ++ ++ snd_soc_component_update_bits(component, AK5558_03_CONTROL2, AK5558_MODE_BITS, ++ tdm_mode); ++ return 0; ++} ++ ++#define AK5558_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ ++ SNDRV_PCM_FMTBIT_S24_LE |\ ++ SNDRV_PCM_FMTBIT_S32_LE) ++ ++static const unsigned int ak5558_rates[] = { ++ 8000, 11025, 16000, 22050, ++ 32000, 44100, 48000, 88200, ++ 96000, 176400, 192000, 352800, ++ 384000, 705600, 768000, 1411200, ++ 2822400, ++}; ++ ++static const struct snd_pcm_hw_constraint_list ak5558_rate_constraints = { ++ .count = ARRAY_SIZE(ak5558_rates), ++ .list = ak5558_rates, ++}; ++ ++static int ak5558_startup(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ return snd_pcm_hw_constraint_list(substream->runtime, 0, ++ SNDRV_PCM_HW_PARAM_RATE, ++ &ak5558_rate_constraints); ++} ++ ++static struct snd_soc_dai_ops ak5558_dai_ops = { ++ .startup = ak5558_startup, ++ .hw_params = ak5558_hw_params, ++ ++ .set_fmt = ak5558_set_dai_fmt, ++ .set_tdm_slot = ak5558_set_tdm_slot, ++}; ++ ++static struct snd_soc_dai_driver ak5558_dai = { ++ .name = "ak5558-aif", ++ .capture = { ++ .stream_name = "Capture", ++ .channels_min = 1, ++ .channels_max = 8, ++ .rates = SNDRV_PCM_RATE_KNOT, ++ .formats = AK5558_FORMATS, ++ }, ++ .ops = &ak5558_dai_ops, ++}; ++ ++static void ak5558_power_off(struct ak5558_priv *ak5558) ++{ ++ if (!ak5558->reset_gpiod) ++ return; ++ ++ gpiod_set_value_cansleep(ak5558->reset_gpiod, 0); ++ usleep_range(1000, 2000); ++} ++ ++static void ak5558_power_on(struct ak5558_priv *ak5558) ++{ ++ if (!ak5558->reset_gpiod) ++ return; ++ ++ gpiod_set_value_cansleep(ak5558->reset_gpiod, 1); ++ usleep_range(1000, 2000); ++} ++ ++static int ak5558_probe(struct snd_soc_component *component) ++{ ++ struct ak5558_priv *ak5558 = snd_soc_component_get_drvdata(component); ++ ++ ak5558_power_on(ak5558); ++ ak5558_set_mcki(component); ++ return 0; ++} ++ ++static void ak5558_remove(struct snd_soc_component *component) ++{ ++ struct ak5558_priv *ak5558 = snd_soc_component_get_drvdata(component); ++ ++ ak5558_power_off(ak5558); ++} ++ ++static int __maybe_unused ak5558_runtime_suspend(struct device *dev) ++{ ++ struct ak5558_priv *ak5558 = dev_get_drvdata(dev); ++ ++ regcache_cache_only(ak5558->regmap, true); ++ ak5558_power_off(ak5558); ++ ++ return 0; ++} ++ ++static int __maybe_unused ak5558_runtime_resume(struct device *dev) ++{ ++ struct ak5558_priv *ak5558 = dev_get_drvdata(dev); ++ ++ ak5558_power_off(ak5558); ++ ak5558_power_on(ak5558); ++ ++ regcache_cache_only(ak5558->regmap, false); ++ regcache_mark_dirty(ak5558->regmap); ++ ++ return regcache_sync(ak5558->regmap); ++} ++ ++const struct dev_pm_ops ak5558_pm = { ++ SET_RUNTIME_PM_OPS(ak5558_runtime_suspend, ak5558_runtime_resume, NULL) ++ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, ++ pm_runtime_force_resume) ++}; ++ ++struct snd_soc_component_driver soc_codec_dev_ak5558 = { ++ .probe = ak5558_probe, ++ .remove = ak5558_remove, ++ .controls = ak5558_snd_controls, ++ .num_controls = ARRAY_SIZE(ak5558_snd_controls), ++ .dapm_widgets = ak5558_dapm_widgets, ++ .num_dapm_widgets = ARRAY_SIZE(ak5558_dapm_widgets), ++ .dapm_routes = ak5558_intercon, ++ .num_dapm_routes = ARRAY_SIZE(ak5558_intercon), ++#if 0 ++ .idle_bias_on = 1, ++ .use_pmdown_time = 1, ++ .endianness = 1, ++ .non_legacy_dai_naming = 1, ++#endif ++}; ++ ++static const struct regmap_config ak5558_regmap = { ++ .reg_bits = 8, ++ .val_bits = 8, ++ ++ .max_register = AK5558_05_DSD, ++ .reg_defaults = ak5558_reg, ++ .num_reg_defaults = ARRAY_SIZE(ak5558_reg), ++ .cache_type = REGCACHE_RBTREE, ++}; ++ ++static int ak5558_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) ++{ ++ struct ak5558_priv *ak5558; ++ int ret = 0; ++ ++ ak5558 = devm_kzalloc(&i2c->dev, sizeof(*ak5558), GFP_KERNEL); ++ if (!ak5558) ++ return -ENOMEM; ++ ++ ak5558->regmap = devm_regmap_init_i2c(i2c, &ak5558_regmap); ++ if (IS_ERR(ak5558->regmap)) ++ return PTR_ERR(ak5558->regmap); ++ ++ i2c_set_clientdata(i2c, ak5558); ++ ak5558->i2c = i2c; ++ ++ ak5558->reset_gpiod = devm_gpiod_get_optional(&i2c->dev, "reset", ++ GPIOD_OUT_LOW); ++ if (IS_ERR(ak5558->reset_gpiod)) ++ return PTR_ERR(ak5558->reset_gpiod); ++ ++ ret = devm_snd_soc_register_component(&i2c->dev, ++ &soc_codec_dev_ak5558, ++ &ak5558_dai, 1); ++ if (ret) ++ return ret; ++ ++ pm_runtime_enable(&i2c->dev); ++ ++ printk("ak5558 probe ok, dev_name: %s\n", dev_name(&i2c->dev)); ++ return 0; ++} ++ ++static int ak5558_i2c_remove(struct i2c_client *i2c) ++{ ++ pm_runtime_disable(&i2c->dev); ++ ++ return 0; ++} ++ ++static const struct i2c_device_id ak5558_i2c_table[] = { ++ {"ak5558", 0}, ++ {} ++}; ++MODULE_DEVICE_TABLE(i2c, ak4458_i2c_table); ++static const struct of_device_id ak5558_i2c_dt_ids[] = { ++ { .compatible = "asahi-kasei,ak5558"}, ++ { } ++}; ++ ++static struct i2c_driver ak5558_i2c_driver = { ++ .driver = { ++ .name = "ak5558", ++ .of_match_table = of_match_ptr(ak5558_i2c_dt_ids), ++ .pm = &ak5558_pm, ++ }, ++ .probe = ak5558_i2c_probe, ++ .remove = ak5558_i2c_remove, ++ .id_table = ak5558_i2c_table, ++}; ++ ++module_i2c_driver(ak5558_i2c_driver); ++ ++MODULE_AUTHOR("Junichi Wakasugi "); ++MODULE_AUTHOR("Mihai Serban "); ++MODULE_DESCRIPTION("ASoC AK5558 ADC driver"); ++MODULE_LICENSE("GPL v2"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_ecodec_ak5558.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_ecodec_ak5558.h.patch new file mode 100644 index 00000000..970b1ac2 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_ecodec_ak5558.h.patch @@ -0,0 +1,56 @@ +diff -drupN a/sound/soc/ingenic/ecodec/ak5558.h b/sound/soc/ingenic/ecodec/ak5558.h +--- a/sound/soc/ingenic/ecodec/ak5558.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/ecodec/ak5558.h 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,52 @@ ++/* SPDX-License-Identifier: GPL-2.0 ++ * ++ * Audio driver header for AK5558 ++ * ++ * Copyright (C) 2016 Asahi Kasei Microdevices Corporation ++ * Copyright 2018 NXP ++ */ ++ ++#ifndef _AK5558_H ++#define _AK5558_H ++ ++#define AK5558_00_POWER_MANAGEMENT1 0x00 ++#define AK5558_01_POWER_MANAGEMENT2 0x01 ++#define AK5558_02_CONTROL1 0x02 ++#define AK5558_03_CONTROL2 0x03 ++#define AK5558_04_CONTROL3 0x04 ++#define AK5558_05_DSD 0x05 ++ ++/* AK5558_02_CONTROL1 fields */ ++#define AK5558_DIF GENMASK(1, 1) ++#define AK5558_DIF_MSB_MODE (0 << 1) ++#define AK5558_DIF_I2S_MODE (1 << 1) ++ ++#define AK5558_BITS GENMASK(2, 2) ++#define AK5558_DIF_24BIT_MODE (0 << 2) ++#define AK5558_DIF_32BIT_MODE (1 << 2) ++ ++#define AK5558_CKS GENMASK(6, 3) ++#define AK5558_CKS_128FS_192KHZ (0 << 3) ++#define AK5558_CKS_192FS_192KHZ (1 << 3) ++#define AK5558_CKS_256FS_48KHZ (2 << 3) ++#define AK5558_CKS_256FS_96KHZ (3 << 3) ++#define AK5558_CKS_384FS_96KHZ (4 << 3) ++#define AK5558_CKS_384FS_48KHZ (5 << 3) ++#define AK5558_CKS_512FS_48KHZ (6 << 3) ++#define AK5558_CKS_768FS_48KHZ (7 << 3) ++#define AK5558_CKS_64FS_384KHZ (8 << 3) ++#define AK5558_CKS_32FS_768KHZ (9 << 3) ++#define AK5558_CKS_96FS_384KHZ (10 << 3) ++#define AK5558_CKS_48FS_768KHZ (11 << 3) ++#define AK5558_CKS_64FS_768KHZ (12 << 3) ++#define AK5558_CKS_1024FS_16KHZ (13 << 3) ++#define AK5558_CKS_AUTO (15 << 3) ++ ++/* AK5558_03_CONTROL2 fields */ ++#define AK5558_MODE_BITS GENMASK(6, 5) ++#define AK5558_MODE_NORMAL (0 << 5) ++#define AK5558_MODE_TDM128 (1 << 5) ++#define AK5558_MODE_TDM256 (2 << 5) ++#define AK5558_MODE_TDM512 (3 << 5) ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_ecodec_wm8594.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_ecodec_wm8594.c.patch new file mode 100644 index 00000000..cca22421 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_ecodec_wm8594.c.patch @@ -0,0 +1,1084 @@ +diff -drupN a/sound/soc/ingenic/ecodec/wm8594.c b/sound/soc/ingenic/ecodec/wm8594.c +--- a/sound/soc/ingenic/ecodec/wm8594.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/ecodec/wm8594.c 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,1080 @@ ++/* ++ * sound/soc/ingenic/ecodec/wm8594.c ++ * ALSA SoC driver for wm8594 ADC ++ * ++ * Copyright 2017 Ingenic Semiconductor Co.,Ltd ++ * wqshao ++ * ++ * 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. ++ * ++ * Only for x2000 FPGA Audio test. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "wm8594.h" ++ ++#define CODEC_NAME "wm8594" ++ ++#define wm8594_reset(c) wm8594_write(c, WM8594_RESET, 0) ++ ++struct wm8594_priv { ++ struct regmap *regmap; ++ bool powered; ++}; ++ ++static const struct reg_default wm8594_reg_defaults[] = { ++ { 0x00, 0x8594 }, ++ { 0x01, 0x0004 }, ++ { 0x02, 0x008a }, ++ { 0x03, 0x0000 }, ++ { 0x04, 0x0000 }, ++ { 0x05, 0x00c8 }, ++ { 0x06, 0x00c8 }, ++ { 0x07, 0x008a }, ++ { 0x08, 0x0000 }, ++ { 0x09, 0x0000 }, ++ { 0x0a, 0x00c8 }, ++ { 0x0b, 0x00c8 }, ++ { 0x0c, 0x0000 }, ++ { 0x0d, 0x200a }, ++ { 0x0e, 0x0000 }, ++ { 0x0f, 0x0000 }, ++ { 0x10, 0x00c3 }, ++ { 0x11, 0x00c3 }, ++ { 0x13, 0x000c }, ++ { 0x14, 0x000c }, ++ { 0x15, 0x000c }, ++ { 0x16, 0x000c }, ++ { 0x17, 0x000c }, ++ { 0x18, 0x000c }, ++ { 0x19, 0x0003 }, ++ { 0x1a, 0x007e }, ++ { 0x1b, 0x0048 }, ++ { 0x1c, 0x0000 }, ++ { 0x1d, 0x0000 }, ++ { 0x1e, 0x0008 }, ++ { 0x1f, 0x0000 }, ++ { 0x20, 0x0088 }, ++ { 0x21, 0x0163 }, ++ { 0x22, 0x0040 }, ++ { 0x23, 0x0010 }, ++ { 0x24, 0x0002 }, ++}; ++ ++static const struct reg_default wm8594_reg_init[] = { ++ {WM8594_DAC1_CTRL1, 0x008e}, /* ++ * DAC1 cross enable ++ * 32 bits i2s format ++ */ ++ {WM8594_DAC1_CTRL2, 0x001b}, /* ++ * MCLK = 256 * Fs ++ * BLCK = 64 * Fs ++ */ ++ {WM8594_ADC_CTRL1, 0x200a}, /* ++ * ADC cross enable ++ * 32 bits i2s format ++ */ ++ {WM8594_DAC2_CTRL1, 0x008e}, /* ++ * DAC2 cross enable ++ * 32 bits i2s format ++ */ ++ {WM8594_DAC2_CTRL2, 0x001b}, /* ++ * MCLK = 256 * Fs ++ * BLCK = 64 * Fs ++ */ ++ {WM8594_INPUT_CTRL1, 0x09a9}, ++ {WM8594_INPUT_CTRL2, 0x0a9a}, /* ++ * connect PGA1 and PGA2 ++ * to DAC1 ++ */ ++ {WM8594_INPUT_CTRL3, 0x0480}, /* connect ADC to VIN1 */ ++}; ++ ++ ++static unsigned int wm8594_read(struct snd_soc_codec *codec, ++ unsigned int reg) ++{ ++ return snd_soc_read(codec, reg); ++} ++ ++static int wm8594_write(struct snd_soc_codec *codec, ++ unsigned int reg, ++ unsigned int value) ++{ ++ int ret = 0; ++ ret = snd_soc_update_bits(codec, reg, 0xffff, value); ++ if (ret >= 0) { ++ dev_dbg(codec->dev, "%s: reg = 0x%x ; value = 0x%x (change %x)success\n", ++ __func__, reg, value, ret); ++ ret = 0; ++ } else { ++ dev_err(codec->dev, "%s: reg = 0x%x ; value = 0x%x error\n", ++ __func__, reg, value); ++ ret = -EIO; ++ } ++ ++ return ret; ++} ++ ++static int wm8594_vol_update(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct soc_mixer_control *mc = ++ (struct soc_mixer_control *)kcontrol->private_value; ++ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); ++ struct snd_soc_codec *codec = component->codec; ++ unsigned int reg = mc->reg; ++ unsigned int reg2 = mc->rreg; ++ unsigned int shift = mc->shift; ++ unsigned int rshift = mc->rshift; ++ int max = mc->max; ++ unsigned int mask = (1 << fls(max)) - 1; ++ unsigned int invert = mc->invert; ++ int err; ++ bool type_2r = 0; ++ unsigned int val2 = 0; ++ unsigned int val, val_mask; ++ ++ val = (ucontrol->value.integer.value[0] & mask); ++ if (invert) ++ val = max - val; ++ val_mask = mask << shift; ++ val = val << shift; ++ if (snd_soc_volsw_is_stereo(mc)) { ++ val2 = (ucontrol->value.integer.value[1] & mask); ++ if (invert) ++ val2 = max - val2; ++ if (reg == reg2) { ++ val_mask |= mask << rshift; ++ val |= val2 << rshift; ++ } else { ++ val2 = val2 << shift; ++ type_2r = 1; ++ } ++ } ++ ++ err = snd_soc_update_bits(codec, ++ reg, ++ val_mask | 0x100, ++ val | 0x100); ++ if (err < 0) ++ return err; ++ ++ if (type_2r) ++ err = snd_soc_update_bits(codec, ++ reg2, ++ val_mask | 0x100, ++ val2 | 0x100); ++ ++ return err; ++} ++ ++ ++static int wm8594_adc_input_get_switch(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ ++ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); ++ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); ++ int ret = 0; ++ u16 sel = 0; ++ sel = snd_soc_read(codec, WM8594_INPUT_CTRL3); ++ if (sel < 0) ++ return -EIO; ++ switch (sel & 0xf) { ++ case 0x0: ++ /* VIN1L */ ++ ucontrol->value.enumerated.item[0] = 0; ++ break; ++ case 0x1: ++ /* VIN2L */ ++ ucontrol->value.enumerated.item[0] = 1; ++ break; ++ case 0x2: ++ /* VIN3L */ ++ ucontrol->value.enumerated.item[0] = 2; ++ break; ++ case 0x3: ++ /* VIN4L */ ++ ucontrol->value.enumerated.item[0] = 3; ++ break; ++ case 0x4: ++ /* VIN5L */ ++ ucontrol->value.enumerated.item[0] = 4; ++ break; ++ default: ++ ret = -EINVAL; ++ dev_err(codec->dev, "%s: unexpected control value\n", __func__); ++ break; ++ }; ++ return ret; ++} ++ ++static int wm8594_adc_input_set_switch(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ ++ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); ++ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); ++ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; ++ unsigned int *item = ucontrol->value.enumerated.item; ++ int ret = 0; ++ u16 sel = 0; ++ ++ switch (item[0]) { ++ case 0: ++ /* VIN1 */ ++ sel = 0x80; ++ break; ++ case 1: ++ /* VIN2 */ ++ sel = 0x91; ++ break; ++ case 2: ++ /* VIN3 */ ++ sel = 0xa2; ++ break; ++ case 3: ++ /* VIN4 */ ++ sel = 0xb3; ++ break; ++ case 4: ++ /* VIN5 */ ++ sel = 0xc4; ++ break; ++ default: ++ ret = -EINVAL; ++ dev_err(codec->dev, "%s: unexpected control value\n", __func__); ++ goto error; ++ break; ++ } ++ ++ ret = snd_soc_update_bits(codec, WM8594_INPUT_CTRL3, 0xff, sel); ++ if (ret < 0) ++ goto error; ++ if (ret) ++ snd_soc_dapm_mux_update_power(dapm, kcontrol, item[0], e, NULL); ++ ret = 0; ++error: ++ return ret; ++} ++ ++static int wm8594_pga_sel_get_switch(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol, ++ u16 reg_left, u16 shift_left, ++ u16 reg_right, u16 shift_right) ++{ ++ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); ++ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); ++ int ret = 0; ++ u16 sel = 0; ++ sel = snd_soc_read(codec, reg_left); ++ if (sel < 0) ++ sel = 0; ++ sel >>= shift_left; ++ sel &= 0xf; ++ ++ switch (sel) { ++ case 0x0 ... 0x5: ++ ucontrol->value.enumerated.item[0] = sel; ++ break; ++ case 0x9: ++ ucontrol->value.enumerated.item[0] = 6; ++ break; ++ case 0xb: ++ ucontrol->value.enumerated.item[0] = 7; ++ break; ++ default: ++ ret = -EINVAL; ++ dev_err(codec->dev, "%s: unexpected control value\n", __func__); ++ break; ++ }; ++ ++ return ret; ++} ++ ++static int wm8594_pga_sel_set_switch(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol, ++ u16 reg_left, u16 shift_left, ++ u16 reg_right, u16 shift_right) ++{ ++ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); ++ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); ++ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; ++ unsigned int *item = ucontrol->value.enumerated.item; ++ int ret = 0, change = 0; ++ u16 lsel = 0, rsel = 0, lmsk = 0xf << shift_left, ++ rmsk = 0xf << shift_right; ++ ++ switch (item[0]) { ++ case 0: /* no input */ ++ break; ++ case 1 ... 5: /* VIN1 - VIN5 */ ++ lsel = item[0] << shift_left; ++ rsel = item[0] << shift_right; ++ break; ++ case 6: /* DAC1 */ ++ lsel = 0x9 << shift_left; ++ rsel = 0xa << shift_right; ++ break; ++ case 7: ++ lsel = 0xb << shift_left; ++ rsel = 0xc << shift_right; ++ break; ++ default: ++ ret = -EINVAL; ++ dev_err(codec->dev, "%s: unexpected control value\n", __func__); ++ goto error; ++ } ++ ++ if (reg_left == reg_right) { ++ lsel |= rsel; ++ lmsk |= rmsk; ++ ret = snd_soc_update_bits(codec, reg_left, lmsk, lsel); ++ if (ret < 0) ++ goto error; ++ change = ret; ++ } else { ++ ret = snd_soc_update_bits(codec, reg_left, lmsk, lsel); ++ if (ret < 0) ++ goto error; ++ change = ret; ++ ret = snd_soc_update_bits(codec, reg_right, rmsk, rsel); ++ if (ret < 0) ++ goto error; ++ change |= ret; ++ } ++ ++ if (change) { ++ snd_soc_dapm_mux_update_power(dapm, kcontrol, item[0], e, NULL); ++ } ++error: ++ return ret; ++} ++ ++static const DECLARE_TLV_DB_SCALE(dac_tlv, -10000, 50, 0); ++static const DECLARE_TLV_DB_SCALE(adc_tlv, -9750, 50, 0); ++static const DECLARE_TLV_DB_SCALE(pga_tlv, -7400, 50, 0xa0); ++ ++ ++static const struct snd_kcontrol_new wm8594_snd_controls[] = { ++ SOC_DOUBLE_R_EXT_TLV("DAC1 Playback Volume", ++ WM8594_DAC1L_VOL, WM8594_DAC1R_VOL, 0, 224, 0, ++ snd_soc_get_volsw, wm8594_vol_update, dac_tlv), ++ SOC_SINGLE("DAC1 Mute Switch", WM8594_DAC1_CTRL1, 9, 1, 1), ++ ++ SOC_DOUBLE_R_EXT_TLV("DAC2 Playback Volume", ++ WM8594_DAC2L_VOL, WM8594_DAC2R_VOL, 0, 224, 0, ++ snd_soc_get_volsw, wm8594_vol_update, dac_tlv), ++ SOC_SINGLE("DAC2 Mute Switch", WM8594_DAC2_CTRL1, 9, 1, 1), ++ ++ SOC_DOUBLE_R_EXT_TLV("ADC Capture Volume", ++ WM8594_ADCL_VOL, WM8594_ADCR_VOL, 0, 255, 0, ++ snd_soc_get_volsw, wm8594_vol_update, adc_tlv), ++ ++ SOC_DOUBLE_R_EXT_TLV("PGA1 Volume", ++ WM8594_PGA1L_VOL, WM8594_PGA1R_VOL, 0, 160, 1, ++ snd_soc_get_volsw, wm8594_vol_update, pga_tlv), ++ SOC_DOUBLE("PGA1 Mute Switch", WM8594_PGA_CTRL2, 1, 2, 1, 1), ++ ++ SOC_DOUBLE_R_EXT_TLV("PGA2 Volume", ++ WM8594_PGA2L_VOL, WM8594_PGA2R_VOL, 0, 160, 1, ++ snd_soc_get_volsw, wm8594_vol_update, pga_tlv), ++ SOC_DOUBLE("PGA2 Mute Switch", WM8594_PGA_CTRL2, 3, 4, 1, 1), ++ ++ SOC_DOUBLE_R_EXT_TLV("PGA3 Volume", ++ WM8594_PGA3L_VOL, WM8594_PGA3R_VOL, 0, 160, 1, ++ snd_soc_get_volsw, wm8594_vol_update, pga_tlv), ++ SOC_DOUBLE("PGA3 Mute Switch", WM8594_PGA_CTRL2, 5, 4, 1, 1), ++ ++ SOC_SINGLE("PGA Mute All Switch", WM8594_PGA_CTRL2, 0, 1, 1), ++ ++ SOC_SINGLE("ADC Gain Control", WM8594_INPUT_CTRL3, 8, 3, 0), ++}; ++ ++static int wm8594_pcm_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params, ++ struct snd_soc_dai *dai) ++{ ++ struct snd_soc_codec *codec = dai->codec; ++ ++ u16 dac1_ctrl1 = wm8594_read(codec, WM8594_DAC1_CTRL1) & ~0xc; ++ u16 dac2_ctrl1 = wm8594_read(codec, WM8594_DAC2_CTRL1) & ~0xc; ++ ++ u16 adc_ctrl1 = wm8594_read(codec, WM8594_ADC_CTRL1) & ~0xc; ++ ++ u16 add = wm8594_read(codec, WM8594_ADD_CTRL1) & ~0x70; ++ ++ switch (params_format(params)) { ++ case SNDRV_PCM_FORMAT_S16_LE: ++ break; ++ case SNDRV_PCM_FORMAT_S20_3LE: ++ dac1_ctrl1 |= 0x0004; ++ dac2_ctrl1 |= 0x0004; ++ ++ adc_ctrl1 |= 0x0004; ++ break; ++ case SNDRV_PCM_FORMAT_S24_LE: ++ dac1_ctrl1 |= 0x0008; ++ dac2_ctrl1 |= 0x0008; ++ ++ adc_ctrl1 |= 0x0008; ++ break; ++ case SNDRV_PCM_FORMAT_S32_LE: ++ dac1_ctrl1 |= 0x000c; ++ dac2_ctrl1 |= 0x000c; ++ ++ adc_ctrl1 |= 0x000c; ++ break; ++ } ++ ++ /* set sample rate */ ++ switch (params_rate(params)) { ++ case SNDRV_PCM_RATE_32000: ++ break; ++ case SNDRV_PCM_RATE_44100: ++ add |= 0x10; ++ break; ++ case SNDRV_PCM_RATE_88200: ++ add |= 0x30; ++ break; ++ case SNDRV_PCM_RATE_96000: ++ add |= 0x40; ++ break; ++ case SNDRV_PCM_RATE_176400: ++ add |= 0x50; ++ break; ++ case SNDRV_PCM_RATE_192000: ++ add |= 0x60; ++ break; ++ /* 48000 is the default value */ ++ case SNDRV_PCM_RATE_48000: ++ default: ++ add |= 0x20; ++ break; ++ } ++ ++ if(substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ wm8594_write(codec, WM8594_DAC1_CTRL1, dac1_ctrl1); ++ wm8594_write(codec, WM8594_DAC2_CTRL1, dac2_ctrl1); ++ } else { ++ wm8594_write(codec, WM8594_ADC_CTRL1, adc_ctrl1); ++ } ++ wm8594_write(codec, WM8594_ADD_CTRL1, add); ++ return 0; ++} ++ ++static int wm8594_set_dai_fmt(struct snd_soc_dai *codec_dai, ++ unsigned int fmt) ++{ ++ struct snd_soc_codec *codec = codec_dai->codec; ++ ++ u16 dac1_ctrl1 = wm8594_read(codec, WM8594_DAC1_CTRL1) ++ & ~0x33; ++ u16 dac1_ctrl3 = wm8594_read(codec, WM8594_DAC1_CTRL3) & ~0x1; ++ ++ u16 dac2_ctrl1 = wm8594_read(codec, WM8594_DAC2_CTRL1) ++ & ~0x33; ++ u16 dac2_ctrl3 = wm8594_read(codec, WM8594_DAC2_CTRL3) & ~0x1; ++ ++ u16 adc_ctrl1 = wm8594_read(codec, WM8594_ADC_CTRL1) & ~0x33; ++ u16 adc_ctrl3 = wm8594_read(codec, WM8594_ADC_CTRL3) & ~0x1; ++ ++ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { ++ case SND_SOC_DAIFMT_CBM_CFM: ++ dac1_ctrl3 |= 0x0001; ++ dac2_ctrl3 |= 0x0001; ++ adc_ctrl3 |= 0x0001; ++ break; ++ ++ case SND_SOC_DAIFMT_CBS_CFS: ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ ++ /* interface format */ ++ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { ++ case SND_SOC_DAIFMT_I2S: ++ dac1_ctrl1 |= 0x0002; ++ dac2_ctrl1 |= 0x0002; ++ adc_ctrl1 |= 0x0002; ++ break; ++ ++ case SND_SOC_DAIFMT_RIGHT_J: ++ break; ++ ++ case SND_SOC_DAIFMT_LEFT_J: ++ dac1_ctrl1 |= 0x0001; ++ dac2_ctrl1 |= 0x0001; ++ adc_ctrl1 |= 0x0001; ++ break; ++ ++ case SND_SOC_DAIFMT_DSP_A: ++ dac1_ctrl1 |= 0x0003; ++ dac2_ctrl1 |= 0x0003; ++ adc_ctrl1 |= 0x0003; ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ ++ /* clock inversion */ ++ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { ++ case SND_SOC_DAIFMT_NB_NF: ++ break; ++ ++ case SND_SOC_DAIFMT_IB_IF: ++ dac1_ctrl1 |= 0x0030; ++ dac2_ctrl1 |= 0x0030; ++ adc_ctrl1 |= 0x0030; ++ break; ++ ++ case SND_SOC_DAIFMT_IB_NF: ++ dac1_ctrl1 |= 0x0010; ++ dac2_ctrl1 |= 0x0010; ++ adc_ctrl1 |= 0x0010; ++ break; ++ ++ case SND_SOC_DAIFMT_NB_IF: ++ dac1_ctrl1 |= 0x0020; ++ dac2_ctrl1 |= 0x0020; ++ adc_ctrl1 |= 0x0020; ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ ++ wm8594_write(codec, WM8594_DAC1_CTRL1, dac1_ctrl1); ++ wm8594_write(codec, WM8594_DAC1_CTRL3, dac1_ctrl3); ++ ++ wm8594_write(codec, WM8594_DAC2_CTRL1, dac2_ctrl1); ++ wm8594_write(codec, WM8594_DAC2_CTRL3, dac2_ctrl3); ++ ++ wm8594_write(codec, WM8594_ADC_CTRL1, adc_ctrl1); ++ wm8594_write(codec, WM8594_ADC_CTRL3, adc_ctrl3); ++ return 0; ++} ++ ++static int wm8594_mute(struct snd_soc_dai *codec_dai, int mute) ++{ ++ return 0; ++} ++ ++static struct snd_soc_dai_ops wm8594_dai_ops = { ++ .hw_params = wm8594_pcm_hw_params, ++ .set_fmt = wm8594_set_dai_fmt, ++ .digital_mute = wm8594_mute, ++}; ++ ++static int wm8594_power_up(struct snd_soc_codec *codec) ++{ ++ struct wm8594_priv *wm8594 = snd_soc_codec_get_drvdata(codec); ++ u16 bias = 0; ++ u16 dac1 = wm8594_read(codec, WM8594_DAC1_CTRL1) & ~0x100; ++ u16 dac2 = wm8594_read(codec, WM8594_DAC2_CTRL1) & ~0x100; ++ u16 adc = wm8594_read(codec, WM8594_ADC_CTRL1) & ~0x40; ++ ++ if (wm8594->powered) ++ return 0; ++ wm8594->powered = true; ++ ++ /* ++ * set up initial biases ++ * SOFT_ST | FAST_EN | POBCTRL | BUFIO_EN ++ */ ++ bias |= 0x1d; ++ wm8594_write(codec, WM8594_BIAS, bias); ++ ++ /* ++ * enable output drivers to allow the AC coupling capacitors at the ++ * output charge to be precharged to DACVMID ++ * VOUTxL_EN | VOUTxR_EN ++ */ ++ wm8594_write(codec, WM8594_OUTPUT_CTRL3, 0x1fc0); ++ ++ /* ++ * enable DACVMID, 750k selected for pop reduction ++ * VMID_SEL = 10 ++ */ ++ bias |= 0x80; ++ wm8594_write(codec, WM8594_BIAS, bias); ++ ++ /* ++ * wait until DACVMID has fully charged ++ */ ++ ++ mdelay(1500); ++ ++ /* ++ * enable master bias ++ * BIAS_EN ++ */ ++ bias |= 0x20; ++ wm8594_write(codec, WM8594_BIAS, bias); ++ ++ /* ++ * switch output drivers to use the master bias instead of the ++ * power-up (fast) bias ++ * POBCTRL = 0 ++ */ ++ bias &= ~0x1; ++ wm8594_write(codec, WM8594_BIAS, bias); ++ ++ /* ++ * enable all function required for use: ++ * - enable all inputs ++ * - enable codec ++ * - enable dac1, dac2 and adc ++ */ ++ wm8594_write(codec, WM8594_INPUT_CTRL4, 0xff); ++ wm8594_write(codec, WM8594_ENABLE, 0x1); ++ dac1 |= 0x100; ++ wm8594_write(codec, WM8594_DAC1_CTRL1, dac1); ++ dac2 |= 0x100; ++ wm8594_write(codec, WM8594_DAC2_CTRL1, dac2); ++ adc |= 0x40; ++ wm8594_write(codec, WM8594_ADC_CTRL1, adc); ++ ++ /* ++ * unmute PGAs and switch DACVMID to 75k for normal operation ++ */ ++ bias &= ~0xc0; ++ bias |= 0x40; ++ wm8594_write(codec, WM8594_PGA_CTRL2, 0x0); ++ ++ return 0; ++} ++ ++static int wm8594_power_down(struct snd_soc_codec *codec) ++{ ++ struct wm8594_priv *wm8594 = snd_soc_codec_get_drvdata(codec); ++ u16 bias; ++ u16 dac1 = wm8594_read(codec, WM8594_DAC1_CTRL1) & ~0x100; ++ u16 dac2 = wm8594_read(codec, WM8594_DAC2_CTRL1) & ~0x100; ++ u16 adc = wm8594_read(codec, WM8594_ADC_CTRL1) & ~0x40; ++ u16 output = wm8594_read(codec, WM8594_OUTPUT_CTRL3) & ~0x40; ++ ++ if (!wm8594->powered) ++ return 0; ++ wm8594->powered = false; ++ /* ++ * mute all PGAs ++ */ ++ wm8594_write(codec, WM8594_PGA_CTRL2, 0x7f); ++ ++ /* ++ * set biases for power down mode ++ * FAST_EN = 1 ++ * VMID_SEL = 01 ++ * BIAS_EN = 1 ++ * BUFIO_EN = 1 ++ * VMIDTOG = 0 ++ * SOFT_ST = 1 ++ */ ++ bias = 0x7c; ++ wm8594_write(codec, WM8594_BIAS, bias); ++ ++ /* ++ * switch outputs to fast bias ++ * POBCTRL = 1 ++ */ ++ bias |= 0x2; ++ wm8594_write(codec, WM8594_BIAS, bias); ++ ++ /* ++ * power down ++ */ ++ wm8594_write(codec, WM8594_DAC1_CTRL1, dac1); ++ wm8594_write(codec, WM8594_DAC2_CTRL1, dac2); ++ wm8594_write(codec, WM8594_ADC_CTRL1, adc); ++ wm8594_write(codec, WM8594_INPUT_CTRL4, 0x00); ++ wm8594_write(codec, WM8594_ENABLE, 0x0); ++ ++ /* ++ * power down VMID ++ * VMIDSEL = 00 ++ */ ++ bias &= ~0xc0; ++ wm8594_write(codec, WM8594_BIAS, bias); ++ ++ /* ++ * wait for DACVMID to be discharged ++ */ ++ mdelay(1500); ++ ++ ++ /* ++ * clamp outputs to ground ++ * power down outputs ++ */ ++ wm8594_write(codec, WM8594_OUTPUT_CTRL3, output); ++ wm8594_write(codec, WM8594_OUTPUT_CTRL3, 0); ++ ++ /* ++ * disable remaining bias controls ++ */ ++ bias = 0; ++ wm8594_write(codec, WM8594_BIAS, bias); ++ ++ return 0; ++} ++ ++static int wm8594_set_bias_level(struct snd_soc_codec *codec, ++ enum snd_soc_bias_level level) ++{ ++ switch (level) { ++ case SND_SOC_BIAS_PREPARE: ++ break; ++ case SND_SOC_BIAS_STANDBY: ++ wm8594_power_up(codec); ++ break; ++ case SND_SOC_BIAS_ON: ++ break; ++ case SND_SOC_BIAS_OFF: ++ wm8594_power_down(codec); ++ break; ++ } ++ return 0; ++} ++ ++static int wm8594_probe(struct snd_soc_codec *codec) ++{ ++ int i; ++ int ret = 0; ++ dev_dbg(codec->dev, "WM8594 Audio Codec"); ++ ++ ret = wm8594_reset(codec); ++ if (ret != 0) { ++ dev_err(codec->dev, "Failed to reset codec: %d\n", ret); ++ return ret; ++ } ++ ++ /* initialize codec register */ ++ for (i = 0; i < ARRAY_SIZE(wm8594_reg_init); i++) { ++ wm8594_write(codec, wm8594_reg_init[i].reg, ++ wm8594_reg_init[i].def); ++ } ++ return ret; ++} ++ ++static int wm8594_resume(struct snd_soc_codec *codec) ++{ ++ int i; ++ unsigned int value; ++ /* Sync reg_cache with the hardware */ ++ for (i = 0; i < ARRAY_SIZE(wm8594_reg_defaults); i++) { ++ if (wm8594_reg_defaults[i].reg == WM8594_RESET) ++ continue; ++ value = snd_soc_read(codec, wm8594_reg_defaults[i].reg); ++ snd_soc_write(codec, wm8594_reg_defaults[i].reg, value); ++ } ++ return 0; ++} ++ ++static struct regmap *wm8594_get_regmap(struct device *dev) ++{ ++ struct wm8594_priv *wm8594 = dev_get_drvdata(dev); ++ return wm8594->regmap; ++} ++ ++static int wm8594_pga1_sel_get_switch(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ return wm8594_pga_sel_get_switch(kcontrol, ucontrol, ++ WM8594_INPUT_CTRL1, 0, ++ WM8594_INPUT_CTRL1, 4); ++} ++ ++static int wm8594_pga1_sel_set_switch(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ return wm8594_pga_sel_set_switch(kcontrol, ucontrol, ++ WM8594_INPUT_CTRL1, 0, ++ WM8594_INPUT_CTRL1, 4); ++} ++ ++static int wm8594_pga2_sel_get_switch(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ return wm8594_pga_sel_get_switch(kcontrol, ucontrol, ++ WM8594_INPUT_CTRL1, 8, ++ WM8594_INPUT_CTRL2, 0); ++} ++ ++static int wm8594_pga2_sel_set_switch(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ return wm8594_pga_sel_set_switch(kcontrol, ucontrol, ++ WM8594_INPUT_CTRL1, 8, ++ WM8594_INPUT_CTRL2, 0); ++} ++ ++static int wm8594_pga3_sel_get_switch(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ return wm8594_pga_sel_get_switch(kcontrol, ucontrol, ++ WM8594_INPUT_CTRL2, 4, ++ WM8594_INPUT_CTRL2, 8); ++} ++ ++static int wm8594_pga3_sel_set_switch(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ return wm8594_pga_sel_set_switch(kcontrol, ucontrol, ++ WM8594_INPUT_CTRL2, 4, ++ WM8594_INPUT_CTRL2, 8); ++} ++ ++static const char * const wm8594_adc_input_sel_text[] = { ++ "VIN1", "VIN2", "VIN3", "VIN4", "VIN5" ++}; ++ ++static const char * const wm8594_pga_sel_text[] = { ++ "No Input", "VIN1", "VIN2", "VIN3", "VIN4", "VIN5", "DAC1", "DAC2" ++}; ++ ++static const struct soc_enum wm8594_adc_input_sel_enum = ++ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wm8594_adc_input_sel_text), ++ wm8594_adc_input_sel_text); ++ ++static const struct soc_enum wm8594_pga_sel_enum = ++ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wm8594_pga_sel_text), ++ wm8594_pga_sel_text); ++ ++static const struct snd_kcontrol_new wm8594_pga1_controls = ++ SOC_ENUM_EXT("PGA1 Input Selection", wm8594_pga_sel_enum, ++ wm8594_pga1_sel_get_switch, wm8594_pga1_sel_set_switch); ++ ++static const struct snd_kcontrol_new wm8594_pga2_controls = ++ SOC_ENUM_EXT("PGA2 Input Selection", wm8594_pga_sel_enum, ++ wm8594_pga2_sel_get_switch, wm8594_pga2_sel_set_switch); ++ ++static const struct snd_kcontrol_new wm8594_pga3_controls = ++ SOC_ENUM_EXT("PGA3 Input Selection", wm8594_pga_sel_enum, ++ wm8594_pga3_sel_get_switch, wm8594_pga3_sel_set_switch); ++ ++static const struct snd_kcontrol_new wm8594_adc_controls = ++ SOC_ENUM_EXT("ADC Input Selection", wm8594_adc_input_sel_enum, ++ wm8594_adc_input_get_switch, wm8594_adc_input_set_switch); ++ ++static const struct snd_soc_dapm_widget wm8594_dapm_widgets[] = { ++ SND_SOC_DAPM_DAC("DAC1", "Playback", SND_SOC_NOPM, 0, 0), ++ SND_SOC_DAPM_DAC("DAC2", "Playback", SND_SOC_NOPM, 0, 0), ++ ++ SND_SOC_DAPM_MUX("VOUT1_MUX", SND_SOC_NOPM, 0, 0, &wm8594_pga1_controls), ++ SND_SOC_DAPM_MUX("VOUT2_MUX", SND_SOC_NOPM, 0, 0, &wm8594_pga2_controls), ++ SND_SOC_DAPM_MUX("VOUT3_MUX", SND_SOC_NOPM, 0, 0, &wm8594_pga3_controls), ++ ++ SND_SOC_DAPM_OUTPUT("VOUT1"), ++ SND_SOC_DAPM_OUTPUT("VOUT2"), ++ SND_SOC_DAPM_OUTPUT("VOUT3"), ++ ++ SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0), ++ ++ SND_SOC_DAPM_MUX("VIN_MUX", SND_SOC_NOPM, 0, 0, &wm8594_adc_controls), ++ ++ SND_SOC_DAPM_INPUT("AIN1"), ++ SND_SOC_DAPM_INPUT("AIN2"), ++ SND_SOC_DAPM_INPUT("AIN3"), ++ SND_SOC_DAPM_INPUT("AIN4"), ++ SND_SOC_DAPM_INPUT("AIN5"), ++}; ++ ++static const struct snd_soc_dapm_route wm8594_dapm_routes[] = { ++ { "VOUT1", NULL, "VOUT1_MUX" }, ++ { "VOUT2", NULL, "VOUT2_MUX" }, ++ { "VOUT3", NULL, "VOUT3_MUX" }, ++ ++ { "VOUT1_MUX", "DAC1", "DAC1"}, ++ { "VOUT2_MUX", "DAC1", "DAC1"}, ++ { "VOUT3_MUX", "DAC1", "DAC1"}, ++ { "VOUT1_MUX", "DAC2", "DAC2"}, ++ { "VOUT2_MUX", "DAC2", "DAC2"}, ++ { "VOUT3_MUX", "DAC2", "DAC2"}, ++ ++ { "VOUT1_MUX", "VIN1", "AIN1"}, ++ { "VOUT1_MUX", "VIN2", "AIN2"}, ++ { "VOUT1_MUX", "VIN3", "AIN3"}, ++ { "VOUT1_MUX", "VIN4", "AIN4"}, ++ { "VOUT1_MUX", "VIN5", "AIN5"}, ++ ++ { "VOUT2_MUX", "VIN1", "AIN1"}, ++ { "VOUT2_MUX", "VIN2", "AIN2"}, ++ { "VOUT2_MUX", "VIN3", "AIN3"}, ++ { "VOUT2_MUX", "VIN4", "AIN4"}, ++ { "VOUT2_MUX", "VIN5", "AIN5"}, ++ ++ { "VOUT3_MUX", "VIN1", "AIN1"}, ++ { "VOUT3_MUX", "VIN2", "AIN2"}, ++ { "VOUT3_MUX", "VIN3", "AIN3"}, ++ { "VOUT3_MUX", "VIN4", "AIN4"}, ++ { "VOUT3_MUX", "VIN5", "AIN5"}, ++ ++ { "VIN_MUX", "VIN1", "AIN1"}, ++ { "VIN_MUX", "VIN2", "AIN2"}, ++ { "VIN_MUX", "VIN3", "AIN3"}, ++ { "VIN_MUX", "VIN4", "AIN4"}, ++ { "VIN_MUX", "VIN5", "AIN5"}, ++ ++ { "ADC", NULL, "VIN_MUX" }, ++}; ++ ++struct snd_soc_codec_driver soc_codec_dev_wm8594 = { ++ .probe = wm8594_probe, ++ .resume = wm8594_resume, ++ .get_regmap = wm8594_get_regmap, ++ .set_bias_level = wm8594_set_bias_level, ++ .controls = wm8594_snd_controls, ++ .num_controls = ARRAY_SIZE(wm8594_snd_controls), ++ .dapm_widgets = wm8594_dapm_widgets, ++ .num_dapm_widgets = ARRAY_SIZE(wm8594_dapm_widgets), ++ .dapm_routes = wm8594_dapm_routes, ++ .num_dapm_routes = ARRAY_SIZE(wm8594_dapm_routes), ++ .suspend_bias_off = false, ++}; ++ ++#define WM8594_RATES (SNDRV_PCM_RATE_8000 | \ ++ SNDRV_PCM_RATE_11025 | \ ++ SNDRV_PCM_RATE_16000 | \ ++ SNDRV_PCM_RATE_22050 | \ ++ SNDRV_PCM_RATE_32000 | \ ++ SNDRV_PCM_RATE_44100 | \ ++ SNDRV_PCM_RATE_48000 | \ ++ SNDRV_PCM_RATE_96000 | \ ++ SNDRV_PCM_RATE_192000) ++ ++#define WM8594_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ ++ SNDRV_PCM_FMTBIT_S20_3LE | \ ++ SNDRV_PCM_FMTBIT_S24_LE | \ ++ SNDRV_PCM_FMTBIT_S24_3LE | \ ++ SNDRV_PCM_FMTBIT_S32_LE) ++ ++static struct snd_soc_dai_driver wm8594_dai[] = { ++ { ++ .name = "wm8594-hifi", ++ .id = 0, ++ .playback = { ++ .stream_name = "Playback", ++ .channels_min = 2, ++ .channels_max = 2, ++ .rates = WM8594_RATES, ++ .formats = WM8594_FORMATS, ++ }, ++ .capture = { ++ .stream_name = "Capture", ++ .channels_min = 2, ++ .channels_max = 2, ++ .rates = WM8594_RATES, ++ .formats = WM8594_FORMATS, ++ }, ++ .ops = &wm8594_dai_ops, ++ }, ++}; ++ ++static const struct regmap_config wm8903_regmap = { ++ .reg_bits = 8, ++ .val_bits = 16, ++ .max_register = WM8594_CACHEREG_NUM, ++ .cache_type = REGCACHE_RBTREE, ++ .reg_defaults = wm8594_reg_defaults, ++ .num_reg_defaults = ARRAY_SIZE(wm8594_reg_defaults), ++}; ++ ++static int wm8594_i2c_probe(struct i2c_client *i2c, ++ const struct i2c_device_id *id) ++{ ++ struct wm8594_priv *wm8594; ++ int ret; ++ unsigned int devid = 0, version = 0; ++ ++ wm8594 = devm_kzalloc(&i2c->dev, ++ sizeof(struct wm8594_priv), ++ GFP_KERNEL); ++ if (!wm8594) ++ return -ENOMEM; ++ ++ wm8594->regmap = devm_regmap_init_i2c(i2c, &wm8903_regmap); ++ if (IS_ERR(wm8594->regmap)) { ++ ret = PTR_ERR(wm8594->regmap); ++ dev_err(&i2c->dev, "Failed to allocate register map: %d\n", ++ ret); ++ return ret; ++ } ++ wm8594->powered = false; ++ ++ regcache_cache_bypass(wm8594->regmap, true); ++ regmap_read(wm8594->regmap, WM8594_DEVICE_ID, &devid); ++ regmap_read(wm8594->regmap, WM8594_REVISION, &version); ++ regcache_cache_bypass(wm8594->regmap, false); ++ dev_info(&i2c->dev, "DEVID %x, VERSION %x\n", devid & 0xffff, version & 0xff); ++ ++ i2c_set_clientdata(i2c, wm8594); ++ ++ ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8594, ++ wm8594_dai, ARRAY_SIZE(wm8594_dai)); ++ ++ if (ret < 0) { ++ pr_err(CODEC_NAME ": %s failed: ret = %d\n", __func__, ret); ++ return ret; ++ } ++ ++ dev_info(&i2c->dev, "probe success!!!\n"); ++ ++ return ret; ++} ++ ++static int wm8594_i2c_remove(struct i2c_client *client) ++{ ++ snd_soc_unregister_codec(&client->dev); ++ return 0; ++} ++ ++/* ++ * WM8594 2 wires address is determined by pin 45 ++ * state during powerup. ++ * low = 0x1a ++ * high = 0x1c ++ */ ++static const struct i2c_device_id wm8594_i2c_table[] = { ++ {"wm8594", 0}, ++ {} ++}; ++MODULE_DEVICE_TABLE(i2c, wm8594_i2c_table); ++ ++static const struct of_device_id wm8594_of_match[] = { ++ {.compatible = "wlf,wm8594", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, wm8594_of_match); ++ ++static struct i2c_driver wm8594_i2c_driver = { ++ .driver = { ++ .name = "wm8594", ++ .of_match_table = of_match_ptr(wm8594_of_match), ++ }, ++ .probe = wm8594_i2c_probe, ++ .remove = wm8594_i2c_remove, ++ .id_table = wm8594_i2c_table, ++}; ++module_i2c_driver(wm8594_i2c_driver); ++ ++MODULE_DESCRIPTION("ASoC wm8594 driver"); ++MODULE_LICENSE("GPL"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_ecodec_wm8594.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_ecodec_wm8594.h.patch new file mode 100644 index 00000000..b0bc74aa --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_ecodec_wm8594.h.patch @@ -0,0 +1,65 @@ +diff -drupN a/sound/soc/ingenic/ecodec/wm8594.h b/sound/soc/ingenic/ecodec/wm8594.h +--- a/sound/soc/ingenic/ecodec/wm8594.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/ecodec/wm8594.h 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,61 @@ ++/* ++ * sound/soc/ingenic/ecodec/wm8594.c ++ * ALSA SoC driver for wm8594 ADC ++ * ++ * Copyright 2017 Ingenic Semiconductor Co.,Ltd ++ * wqshao ++ * ++ * 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. ++ * ++ * Only for x2000 FPGA SoCs test. ++ */ ++ ++#ifndef _WM8594_H_ ++#define _WM8594_H_ ++ ++#define WM8594_RESET 0x00 ++#define WM8594_DEVICE_ID 0x00 ++#define WM8594_REVISION 0x01 ++#define WM8594_DAC1_CTRL1 0x02 ++#define WM8594_DAC1_CTRL2 0x03 ++#define WM8594_DAC1_CTRL3 0x04 ++#define WM8594_DAC1L_VOL 0x05 ++#define WM8594_DAC1R_VOL 0x06 ++#define WM8594_DAC2_CTRL1 0x07 ++#define WM8594_DAC2_CTRL2 0x08 ++#define WM8594_DAC2_CTRL3 0x09 ++#define WM8594_DAC2L_VOL 0x0a ++#define WM8594_DAC2R_VOL 0x0b ++#define WM8594_ENABLE 0x0c ++#define WM8594_ADC_CTRL1 0x0d ++#define WM8594_ADC_CTRL2 0x0e ++#define WM8594_ADC_CTRL3 0x0f ++#define WM8594_ADCL_VOL 0x10 ++#define WM8594_ADCR_VOL 0x11 ++/* register 0x12 reserved */ ++#define WM8594_PGA1L_VOL 0x13 ++#define WM8594_PGA1R_VOL 0x14 ++#define WM8594_PGA2L_VOL 0x15 ++#define WM8594_PGA2R_VOL 0x16 ++#define WM8594_PGA3L_VOL 0x17 ++#define WM8594_PGA3R_VOL 0x18 ++#define WM8594_PGA_CTRL1 0x19 ++#define WM8594_PGA_CTRL2 0x1a ++#define WM8594_ADD_CTRL1 0x1b ++#define WM8594_INPUT_CTRL1 0x1c ++#define WM8594_INPUT_CTRL2 0x1d ++#define WM8594_INPUT_CTRL3 0x1e ++#define WM8594_INPUT_CTRL4 0x1f ++#define WM8594_OUTPUT_CTRL1 0x20 ++#define WM8594_OUTPUT_CTRL2 0x21 ++#define WM8594_OUTPUT_CTRL3 0x22 ++#define WM8594_BIAS 0x23 ++#define WM8594_PGA_CTRL3 0x24 ++ ++#define WM8594_CACHEREG_NUM 36 ++ ++#endif ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_icodec_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_icodec_Makefile.patch new file mode 100644 index 00000000..aafa896a --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_icodec_Makefile.patch @@ -0,0 +1,7 @@ +diff -drupN a/sound/soc/ingenic/icodec/Makefile b/sound/soc/ingenic/icodec/Makefile +--- a/sound/soc/ingenic/icodec/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/icodec/Makefile 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,3 @@ ++ ++obj-$(CONFIG_SND_ASOC_INGENIC_DUMP_CODEC) += dump.o ++obj-$(CONFIG_SND_ASOC_INGENIC_ICDC_D3) += icdc_d3.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_icodec_dump.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_icodec_dump.c.patch new file mode 100644 index 00000000..210d087f --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_icodec_dump.c.patch @@ -0,0 +1,123 @@ +diff -drupN a/sound/soc/ingenic/icodec/dump.c b/sound/soc/ingenic/icodec/dump.c +--- a/sound/soc/ingenic/icodec/dump.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/icodec/dump.c 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,119 @@ ++/* ++ * sound/soc/ingenic/icodec/dump.c ++ * ALSA SoC Audio driver -- dump codec driver used for devices like bt, hdmi ++ ++ * Copyright 2014 Ingenic Semiconductor Co.,Ltd ++ * cli ++ * ++ * Note: dlv4780 is an internal codec for ingenic SOC ++ * used for dlv4780 m200 and so on ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static const struct snd_soc_dai_driver pcm_dump_dai __initdata = { ++ .name = "pcm-dump", ++ .playback = { ++ .channels_min = 1, ++ .channels_max = 1, ++ .rates = SNDRV_PCM_RATE_8000_192000, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE | ++ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8, ++ }, ++ .capture = { ++ .channels_min = 1, ++ .channels_max = 1, ++ .rates = SNDRV_PCM_RATE_8000_192000, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE | ++ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8, ++ }, ++}; ++ ++static const struct snd_soc_dai_driver spdif_dump_dai __initdata = { ++ .name = "spdif-dump", ++ .playback = { ++ .channels_min = 1, ++ .channels_max = 2, ++ .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | ++ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000, ++ .formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE, ++ }, ++}; ++ ++static const struct snd_soc_dai_driver dmic_dump_dai __initdata = { ++ .name = "dmic-dump", ++ .capture = { ++ .channels_min = 1, ++ .channels_max = 4, ++ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_8000, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE, ++ }, ++}; ++ ++static const struct of_device_id dump_dt_match[]; ++static int dump_platform_probe(struct platform_device *pdev) ++{ ++ struct snd_soc_codec_driver *dump_codec; ++ struct snd_soc_dai_driver *dump_dai; ++ const struct of_device_id *match; ++ int ret = 0; ++ ++ dump_dai = (struct snd_soc_dai_driver *)devm_kzalloc(&pdev->dev, ++ sizeof(struct snd_soc_codec_driver), GFP_KERNEL); ++ if (!dump_dai) ++ return -ENOMEM; ++ match = of_match_node(dump_dt_match, pdev->dev.of_node); ++ if (!match) ++ return -ENODEV; ++ memcpy(dump_dai, match->data, sizeof(struct snd_soc_codec_driver)); ++ ++ dump_codec = (struct snd_soc_codec_driver *)devm_kzalloc(&pdev->dev, ++ sizeof(struct snd_soc_codec_driver), GFP_KERNEL); ++ if (!dump_codec) ++ return -ENOMEM; ++ ++ ret = snd_soc_register_codec(&pdev->dev, dump_codec, dump_dai, 1); ++ dev_dbg(&pdev->dev, "codec dump codec platfrom probe success\n"); ++ return ret; ++} ++ ++static int dump_platform_remove(struct platform_device *pdev) ++{ ++ snd_soc_unregister_codec(&pdev->dev); ++ return 0; ++} ++ ++static const struct of_device_id dump_dt_match[] = { ++ { .compatible = "ingenic,pcm-dump-codec", .data = &pcm_dump_dai}, ++ { .compatible = "ingenic,spdif-dump-codec", .data = &spdif_dump_dai}, ++ { .compatible = "ingenic,dmic-dump-codec", .data = &dmic_dump_dai}, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, dump_dt_match); ++ ++static struct platform_driver dump_driver = { ++ .driver = { ++ .name = "dump codec", ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(dump_dt_match), ++ }, ++ .probe = dump_platform_probe, ++ .remove = dump_platform_remove, ++}; ++module_platform_driver(dump_driver); ++ ++MODULE_DESCRIPTION("Dump Codec Driver"); ++MODULE_AUTHOR("cli"); ++MODULE_LICENSE("GPL"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_icodec_icdc_d3.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_icodec_icdc_d3.c.patch new file mode 100644 index 00000000..56261a0b --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_icodec_icdc_d3.c.patch @@ -0,0 +1,765 @@ +diff -drupN a/sound/soc/ingenic/icodec/icdc_d3.c b/sound/soc/ingenic/icodec/icdc_d3.c +--- a/sound/soc/ingenic/icodec/icdc_d3.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/icodec/icdc_d3.c 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,761 @@ ++/* ++ * sound/soc/ingenic/icodec/icdc_d3.c ++ * ALSA SoC Audio driver -- ingenic internal codec (icdc_d3) driver ++ ++ * Copyright 2014 Ingenic Semiconductor Co.,Ltd ++ * cscheng ++ * ++ * Note: icdc_d3 is an internal codec for ingenic SOC ++ * used for x1000 and so on ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "icdc_d3.h" ++ ++static int icdc_d3_debug = 0; ++module_param(icdc_d3_debug, int, 0644); ++#define DEBUG_MSG(msg...) \ ++ do { \ ++ if (icdc_d3_debug) \ ++ printk("ICDC: " msg); \ ++ } while(0) ++ ++static u8 icdc_d3_reg_defcache[SCODA_MAX_REG_NUM] = { ++/* reg 0x0 ... 0x9 */ ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd3,0xd3, ++/* reg 0xa ... 0x13 */ ++ 0x00,0x30,0x30,0xb0,0xb1,0xb0,0x00,0x00,0x0f,0x40, ++/* reg 0x14 ... 0x1d */ ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0xff, ++/* reg 0x1e ... 0x27 */ ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++/* reg 0x28 ... 0x31 */ ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++/* reg 0x32 ... 0x39 */ ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++/* extern reg */ ++ 0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00, ++ 0x34,0x07,0x44,0x1f,0x00, ++}; ++ ++static int icdc_d3_volatile(struct snd_soc_codec *codec, unsigned int reg) ++{ ++ if (reg > SCODA_MAX_REG_NUM) ++ return 1; ++ ++ switch (reg) { ++ case SCODA_REG_SR: ++ case SCODA_REG_SR2: ++ case SCODA_REG_SIGR: ++ case SCODA_REG_SIGR3: ++ case SCODA_REG_SIGR5: ++ case SCODA_REG_SIGR7: ++ case SCODA_REG_MR: ++ case SCODA_REG_IFR: ++ case SCODA_REG_IFR2: ++ case SCODA_REG_SR_ADC_AGCDGL: ++ case SCODA_REG_SR_ADC_AGCDGR: ++ case SCODA_REG_SR_ADC_AGCAGL: ++ case SCODA_REG_SR_ADC_AGCAGR: ++ case SCODA_REG_SR_TR1: ++ case SCODA_REG_SR_TR2: ++ case SCODA_REG_SR_TR_SRCDAC: ++ return 1; ++ default: ++ return 0; ++ } ++} ++ ++static int icdc_d3_writable(struct snd_soc_codec *codec, unsigned int reg) ++{ ++ if (reg > SCODA_MAX_REG_NUM) ++ return 0; ++ ++ switch (reg) { ++ case SCODA_REG_SR: ++ case SCODA_REG_SR2: ++ case SCODA_REG_SIGR: ++ case SCODA_REG_SIGR3: ++ case SCODA_REG_SIGR5: ++ case SCODA_REG_SIGR7: ++ case SCODA_REG_MR: ++ case SCODA_REG_SR_ADC_AGCDGL: ++ case SCODA_REG_SR_ADC_AGCDGR: ++ case SCODA_REG_SR_ADC_AGCAGL: ++ case SCODA_REG_SR_ADC_AGCAGR: ++ case SCODA_REG_SR_TR1: ++ case SCODA_REG_SR_TR2: ++ case SCODA_REG_SR_TR_SRCDAC: ++ return 0; ++ default: ++ return 1; ++ } ++} ++ ++static int icdc_d3_readable(struct snd_soc_codec *codec, unsigned int reg) ++{ ++ if (reg > SCODA_MAX_REG_NUM) ++ return 0; ++ else ++ return 1; ++} ++ ++static void dump_registers_hazard(struct icdc_d3 *icdc_d3) ++{ ++ int reg = 0; ++ dev_info(icdc_d3->dev, "-------------------register:"); ++ for ( ; reg < SCODA_MAX_REG_NUM; reg++) { ++ if (reg % 8 == 0) ++ printk("\n"); ++ if (icdc_d3_readable(icdc_d3->codec, reg)) ++ printk(" 0x%02x:0x%02x,", reg, icdc_d3_hw_read(icdc_d3, reg)); ++ else ++ printk(" 0x%02x:0x%02x,", reg, 0x0); ++ } ++ printk("\n"); ++ printk("mix_0=%02x\n", icdc_d3_hw_read_extend(icdc_d3, SCODA_MIX_0)); ++ printk("mix_1=%02x\n", icdc_d3_hw_read_extend(icdc_d3, SCODA_MIX_1)); ++ printk("mix_2=%02x\n", icdc_d3_hw_read_extend(icdc_d3, SCODA_MIX_2)); ++ printk("mix_3=%02x\n", icdc_d3_hw_read_extend(icdc_d3, SCODA_MIX_3)); ++ printk("mix_4=%02x\n", icdc_d3_hw_read_extend(icdc_d3, SCODA_MIX_4)); ++ ++ printk("\n"); ++ dev_info(icdc_d3->dev, "----------------------------\n"); ++ return; ++} ++ ++static int icdc_d3_write(struct snd_soc_codec *codec, unsigned int reg, ++ unsigned int value) ++{ ++ struct icdc_d3 *icdc_d3 = snd_soc_codec_get_drvdata(codec); ++ int val = value; ++ BUG_ON(reg > SCODA_MAX_REG_NUM); ++ dev_dbg(icdc_d3->dev,"%s reg = %x value = %x \n",__func__,reg,val); ++ ++ if (icdc_d3_writable(codec, reg)) { ++ if (!icdc_d3_volatile(codec,reg)) { ++ u8 *cache = codec->reg_cache; ++ if((reg == SCODA_REG_GCR_DACL) || (reg == SCODA_REG_GCR_DACR)){ ++ if(val < 32) ++ val = 31 - val; ++ else ++ val = 95 - val; ++ } ++ cache[reg] = val; ++ } ++ return icdc_d3_hw_write(icdc_d3, reg, val); ++ } ++ return 0; ++} ++ ++static unsigned int icdc_d3_read(struct snd_soc_codec *codec, unsigned int reg) ++{ ++ ++ struct icdc_d3 *icdc_d3 = snd_soc_codec_get_drvdata(codec); ++ int val = 0; ++ BUG_ON(reg > SCODA_MAX_REG_NUM); ++ ++ if (!icdc_d3_volatile(codec, reg)) { ++ u8 *cache = codec->reg_cache; ++ val = cache[reg]; ++ if((reg == SCODA_REG_GCR_DACL) || (reg == SCODA_REG_GCR_DACR)){ ++ if(val < 32) ++ val = 31 - val; ++ else ++ val = 95 - val; ++ } ++ return val; ++ } ++ ++ if (icdc_d3_readable(codec, reg)) ++ return icdc_d3_hw_read(icdc_d3, reg); ++ ++ return 0; ++} ++ ++static int icdc_d3_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params, ++ struct snd_soc_dai *dai) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_codec *codec = rtd->codec; ++ int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); ++ int bit_width_sel = 3; ++ int speed_sel = 0; ++ int aicr_reg = playback ? SCODA_REG_AICR_DAC : SCODA_REG_AICR_ADC; ++ int fcr_reg = playback ? SCODA_REG_FCR_DAC : SCODA_REG_FCR_ADC; ++ int sample_attr[] = { 8000, 11025, 12000, 16000, 22050, 24000, 32000,44100, ++ 48000, 88200, 96000, 176400, 192000,}; ++ int speed = params_rate(params); ++ int bit_width = params_format(params); ++ DEBUG_MSG("%s enter set bus width %d , sample rate %d\n", ++ __func__, bit_width, speed); ++ /* bit width */ ++ switch (bit_width) { ++ case SNDRV_PCM_FORMAT_S16_LE: ++ bit_width_sel = 0; ++ break; ++ case SNDRV_PCM_FORMAT_S18_3LE: ++ bit_width_sel = 1; ++ break; ++ case SNDRV_PCM_FORMAT_S20_3LE: ++ bit_width_sel = 2; ++ break; ++ default: ++ case SNDRV_PCM_FORMAT_S24_3LE: ++ bit_width_sel = 3; ++ break; ++ } ++ ++ /*sample rate*/ ++ for (speed_sel = 0; speed > sample_attr[speed_sel]; speed_sel++) ++ ; ++ snd_soc_update_bits(codec, aicr_reg, SCODA_AICR_DAC_ADWL_MASK, ++ (bit_width_sel << SCODA_AICR_DAC_ADWL_SHIFT)); ++ snd_soc_update_bits(codec, fcr_reg, SCODA_FCR_FREQ_MASK, ++ (speed_sel << SCODA_FCR_FREQ_SHIFT)); ++ return 0; ++} ++ ++static int icdc_d3_trigger(struct snd_pcm_substream * stream, int cmd, ++ struct snd_soc_dai *dai) ++{ ++#ifdef DEBUG ++ struct snd_soc_codec *codec = dai->codec; ++ struct icdc_d3 *icdc_d3 = snd_soc_codec_get_drvdata(codec); ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ case SNDRV_PCM_TRIGGER_RESUME: ++ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: ++ dump_registers_hazard(icdc_d3); ++ break; ++ case SNDRV_PCM_TRIGGER_STOP: ++ case SNDRV_PCM_TRIGGER_SUSPEND: ++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ++ dump_registers_hazard(icdc_d3); ++ break; ++ } ++#endif ++ return 0; ++} ++ ++#define DLV4780_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \ ++ SNDRV_PCM_FMTBIT_S20_3LE |SNDRV_PCM_FMTBIT_S24_LE) ++ ++static int ingenic_icdc_startup(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct snd_soc_codec *codec = dai->codec; ++ ++ /*power on codec*/ ++ if (snd_soc_update_bits(codec, SCODA_REG_CR_VIC, SCODA_CR_VIC_SB_MASK, 0)) ++ msleep(250); ++ if (snd_soc_update_bits(codec, SCODA_REG_CR_VIC, SCODA_CR_VIC_SB_SLEEP_MASK, 0)) ++ msleep(400); ++ ++ return 0; ++} ++ ++ ++static void ingenic_icdc_shutdown(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct snd_soc_codec *codec = dai->codec; ++ /*power off codec*/ ++ snd_soc_update_bits(codec, SCODA_REG_CR_VIC, SCODA_CR_VIC_SB_SLEEP_MASK, 1); ++ snd_soc_update_bits(codec, SCODA_REG_CR_VIC, SCODA_CR_VIC_SB_MASK, 1); ++ return; ++} ++ ++ ++int icdc_d3_mute_stream(struct snd_soc_dai *dai, int mute, int stream) ++{ ++ struct snd_soc_codec *codec = dai->codec; ++ ++ if(stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ snd_soc_update_bits(codec, SCODA_REG_CR_DAC, SCODA_CR_DAC_SMUTE_MASK, mute << SCODA_CR_DAC_SMUTE_SHIFT); ++ } else if(stream == SNDRV_PCM_STREAM_CAPTURE) { ++ snd_soc_update_bits(codec, SCODA_REG_CR_ADC, SCODA_CR_ADC_SMUTE_MASK, mute << SCODA_CR_ADC_SMUTE_SHIFT); ++ } ++ return 0; ++} ++ ++ ++static struct snd_soc_dai_ops icdc_d3_dai_ops = { ++ .hw_params = icdc_d3_hw_params, ++ .mute_stream = icdc_d3_mute_stream, ++ .trigger = icdc_d3_trigger, ++ .shutdown = ingenic_icdc_shutdown, ++ .startup = ingenic_icdc_startup, ++}; ++ ++static struct snd_soc_dai_driver icdc_d3_codec_dai = { ++ .name = "icdc-d3-hifi", ++ .playback = { ++ .stream_name = "Playback", ++ .channels_min = 2, ++ .channels_max = 2, ++ .rates = SNDRV_PCM_RATE_8000_192000, ++ .formats = DLV4780_FORMATS, ++ }, ++ .capture = { ++ .stream_name = "Capture", ++ .channels_min = 2, ++ .channels_max = 2, ++ .rates = SNDRV_PCM_RATE_8000_192000, ++ .formats = DLV4780_FORMATS, ++ }, ++ .ops = &icdc_d3_dai_ops, ++}; ++ ++/* unit: 0.01dB */ ++static const DECLARE_TLV_DB_SCALE(dac_tlv, -3100, 100, 0); ++static const DECLARE_TLV_DB_SCALE(mix_tlv, -3100, 100, 0); ++static const DECLARE_TLV_DB_SCALE(adc_tlv, 0, 100, 0); ++static const DECLARE_TLV_DB_SCALE(mic_tlv, 0, 100, 0); ++ ++static const unsigned int icdc_d3_adc_mic_sel_value[] = {0x0, 0x1,}; ++static const unsigned int icdc_d3_mixer_input_sel_value[] = {0x0, 0x5, 0xa, 0xf,}; ++static const unsigned int icdc_d3_mixer_input_sel_value_double[] = {0x0, 0x1, 0x2, 0x3,}; ++static const unsigned int icdc_d3_mixer_mode_sel_value[] = {0x0, 0x1,}; ++ ++static const char *icdc_d3_mixer_input_sel[] = { "Normal Inputs", "Cross Inputs", "Mixed Inputs", "Zero Inputs"}; ++static const char *icdc_d3_adc_mic_sel[] = { "AMIC ON", "DMIC ON"}; ++static const char *icdc_d3_mercury_vir_sel[] = { "MERCURY ON", "MERCURY OFF"}; ++static const char *icdc_d3_titanium_vir_sel[] = { "TITANIUM ON", "TITANIUM OFF"}; ++static const char *icdc_d3_dac_mixer_mode_sel[] = { "PLAYBACK DAC", "PLAYBACK DAC + ADC"}; ++static const char *icdc_d3_adc_mixer_mode_sel[] = { "RECORD INPUT", "RECORD INPUT + DAC"}; ++ ++static const struct soc_enum icdc_d3_enum[] = { ++ SOC_VALUE_ENUM_SINGLE(SCODA_REG_CR_ADC, 6, 0x1, ARRAY_SIZE(icdc_d3_adc_mic_sel),icdc_d3_adc_mic_sel, icdc_d3_adc_mic_sel_value), /*0*/ ++ SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(icdc_d3_mercury_vir_sel), icdc_d3_mercury_vir_sel), /*1*/ ++ SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(icdc_d3_titanium_vir_sel), icdc_d3_titanium_vir_sel), /*2*/ ++ ++ /*select input method*/ ++ SOC_VALUE_ENUM_DOUBLE(SCODA_MIX_0, 6, 4, 0x3, ARRAY_SIZE(icdc_d3_mixer_input_sel),icdc_d3_mixer_input_sel, icdc_d3_mixer_input_sel_value_double), /*3*/ ++ SOC_VALUE_ENUM_DOUBLE(SCODA_MIX_1, 6, 4, 0x3, ARRAY_SIZE(icdc_d3_mixer_input_sel),icdc_d3_mixer_input_sel, icdc_d3_mixer_input_sel_value_double), /*4*/ ++ SOC_VALUE_ENUM_DOUBLE(SCODA_MIX_2, 6, 4, 0x3, ARRAY_SIZE(icdc_d3_mixer_input_sel),icdc_d3_mixer_input_sel, icdc_d3_mixer_input_sel_value_double),/*5*/ ++ SOC_VALUE_ENUM_DOUBLE(SCODA_MIX_3, 6,4, 0x3, ARRAY_SIZE(icdc_d3_mixer_input_sel),icdc_d3_mixer_input_sel, icdc_d3_mixer_input_sel_value_double),/*6*/ ++ SOC_VALUE_ENUM_SINGLE(SCODA_MIX_4, 4, 0xf, ARRAY_SIZE(icdc_d3_mixer_input_sel),icdc_d3_mixer_input_sel, icdc_d3_mixer_input_sel_value),/*7*/ ++ ++ /*select mix mode*/ ++ SOC_VALUE_ENUM_SINGLE(SCODA_MIX_0, 0, 1, ARRAY_SIZE(icdc_d3_dac_mixer_mode_sel),icdc_d3_dac_mixer_mode_sel, icdc_d3_mixer_mode_sel_value),/*8*/ ++ SOC_VALUE_ENUM_SINGLE(SCODA_MIX_4, 0, 1, ARRAY_SIZE(icdc_d3_dac_mixer_mode_sel),icdc_d3_dac_mixer_mode_sel, icdc_d3_mixer_mode_sel_value),/*9*/ ++ SOC_VALUE_ENUM_SINGLE(SCODA_MIX_2, 0, 1, ARRAY_SIZE(icdc_d3_adc_mixer_mode_sel),icdc_d3_adc_mixer_mode_sel, icdc_d3_mixer_mode_sel_value),/*10*/ ++ ++ SOC_VALUE_ENUM_SINGLE(SCODA_MIX_2, 6, 0x3, ARRAY_SIZE(icdc_d3_mixer_input_sel),icdc_d3_mixer_input_sel, icdc_d3_mixer_input_sel_value),/*11*/ ++ SOC_VALUE_ENUM_SINGLE(SCODA_MIX_2, 4, 0x3, ARRAY_SIZE(icdc_d3_mixer_input_sel),icdc_d3_mixer_input_sel, icdc_d3_mixer_input_sel_value),/*12*/ ++}; ++ ++ ++static const struct snd_kcontrol_new icdc_d3_adc_controls = ++ SOC_DAPM_ENUM("Route", icdc_d3_enum[0]); ++ ++static const struct snd_kcontrol_new icdc_d3_mercury_vmux_controls = ++ SOC_DAPM_ENUM("Route", icdc_d3_enum[1]); ++ ++static const struct snd_kcontrol_new icdc_d3_titanium_vmux_controls = ++ SOC_DAPM_ENUM("Route", icdc_d3_enum[2]); ++ ++static const struct snd_kcontrol_new icdc_d3_mercury_aidac_input_sel_controls = ++ SOC_DAPM_ENUM("Route", icdc_d3_enum[3]); ++ ++static const struct snd_kcontrol_new icdc_d3_dac_input_sel_controls = ++ SOC_DAPM_ENUM("Route", icdc_d3_enum[4]); ++ ++static const struct snd_kcontrol_new icdc_d3_aiadc_input_sel_controls = ++ SOC_DAPM_ENUM("Route", icdc_d3_enum[5]); ++ ++static const struct snd_kcontrol_new icdc_d3_adc_input_sel_controls = ++ SOC_DAPM_ENUM("Route", icdc_d3_enum[6]); ++ ++static const struct snd_kcontrol_new icdc_d3_titanium_aidac_input_sel_controls = ++ SOC_DAPM_ENUM("Route", icdc_d3_enum[7]); ++ ++static const struct snd_kcontrol_new icdc_d3_mercury_mixer_mode_sel_controls = ++ SOC_DAPM_ENUM("Route", icdc_d3_enum[8]); ++ ++static const struct snd_kcontrol_new icdc_d3_titanium_mixer_mode_sel_controls = ++ SOC_DAPM_ENUM("Route", icdc_d3_enum[9]); ++ ++static const struct snd_kcontrol_new icdc_d3_aiadc_mixer_mode_sel_controls = ++ SOC_DAPM_ENUM("Route", icdc_d3_enum[10]); ++ ++static const struct snd_kcontrol_new icdc_d3_aiadc_input_sel_controls_l = ++ SOC_DAPM_ENUM("Route", icdc_d3_enum[11]); ++ ++static const struct snd_kcontrol_new icdc_d3_aiadc_input_sel_controls_r = ++ SOC_DAPM_ENUM("Route", icdc_d3_enum[12]); ++ ++static const struct snd_kcontrol_new icdc_d3_snd_controls[] = { ++ /* Volume controls */ ++ SOC_DOUBLE_R_TLV("MERCURY Playback Volume", SCODA_REG_GCR_DACL, SCODA_REG_GCR_DACR, 0, 63, 0, dac_tlv), ++ SOC_DOUBLE_R_TLV("TITANIUM Playback Volume", SCODA_REG_GCR_DACL, SCODA_REG_GCR_DACR, 0, 63, 0, dac_tlv), ++ SOC_DOUBLE_R_TLV("Playback Mixer Volume", SCODA_REG_GCR_MIXDACL, SCODA_REG_GCR_MIXDACR, 0, 31, 1, mix_tlv), ++ SOC_DOUBLE_R_TLV("Digital Capture Volume", SCODA_REG_GCR_ADCL, SCODA_REG_GCR_ADCR, 0, 43, 0, adc_tlv), ++ SOC_DOUBLE_R_TLV("Digital Capture Mixer Volume", SCODA_REG_GCR_MIXADCL, SCODA_REG_GCR_MIXADCR, 0, 31, 1, mix_tlv), ++ SOC_SINGLE_TLV("Mic Volume", SCODA_REG_GCR_MIC1, 0, 4, 0, mic_tlv), ++ ++ /* ADC private controls */ ++ SOC_SINGLE("ADC High Pass Filter Switch", SCODA_REG_FCR_ADC, 6, 1, 0), ++ ++ /* mic private controls */ ++ SOC_SINGLE("Digital Playback mute", SCODA_REG_CR_DAC, 7, 1, 0), ++ /* mixer enable controls */ ++ SOC_SINGLE("mixer Enable", SCODA_REG_CR_MIX, 7, 1, 0), ++}; ++ ++static const struct snd_soc_dapm_widget icdc_d3_dapm_widgets[] = { ++/* ADC */ ++ SND_SOC_DAPM_ADC("ADC", "Capture" , SCODA_REG_AICR_ADC, 4, 1), ++ SND_SOC_DAPM_MUX("ADC Mux", SCODA_REG_CR_ADC, 4, 1, &icdc_d3_adc_controls), ++ SND_SOC_DAPM_MICBIAS("MICBIAS", SCODA_REG_CR_MIC1, 5, 1), ++ SND_SOC_DAPM_PGA("AMIC", SCODA_REG_CR_MIC1, 4, 1, NULL, 0), ++ SND_SOC_DAPM_PGA("DMIC", SCODA_REG_CR_DMIC, 7, 0, NULL, 0), ++ ++/* DAC */ ++ SND_SOC_DAPM_DAC("DAC", "Playback", SCODA_REG_AICR_DAC, 4, 1), ++ ++ SND_SOC_DAPM_MUX("DAC_MERCURY VMux", SND_SOC_NOPM, 0, 0, &icdc_d3_mercury_vmux_controls), ++ SND_SOC_DAPM_PGA("DAC_MERCURY", SCODA_REG_CR_DAC, 4, 1, NULL, 0), ++ ++/* SND_SOC_DAPM_MUX("DAC_TITANIUM VMux", SND_SOC_NOPM, 0, 0, &icdc_d3_titanium_vmux_controls),*/ ++/* SND_SOC_DAPM_PGA("DAC_TITANIUM", SCODA_REG_CR_DAC2, 4, 1, NULL, 0),*/ ++ ++/* MIXER */ ++ SND_SOC_DAPM_MUX("MERCURY AIDAC MIXER Mux", SND_SOC_NOPM, 0, 0, &icdc_d3_dac_input_sel_controls), ++ SND_SOC_DAPM_MUX("DAC Mode Mux", SND_SOC_NOPM, 0, 0, &icdc_d3_mercury_mixer_mode_sel_controls), ++ SND_SOC_DAPM_MUX("MERCURY AIDAC Mux", SND_SOC_NOPM, 0, 0, &icdc_d3_mercury_aidac_input_sel_controls), ++ ++/* ADC */ ++ SND_SOC_DAPM_MUX("ADC Mode Mux", SND_SOC_NOPM, 0, 0, &icdc_d3_aiadc_mixer_mode_sel_controls), ++ SND_SOC_DAPM_MUX("AIADC Mux", SND_SOC_NOPM, 0, 0, &icdc_d3_aiadc_input_sel_controls), ++ SND_SOC_DAPM_MUX("AIADC Mux L", SND_SOC_NOPM, 0, 0, &icdc_d3_aiadc_input_sel_controls_l), ++ SND_SOC_DAPM_MUX("AIADC Mux R", SND_SOC_NOPM, 0, 0, &icdc_d3_aiadc_input_sel_controls_r), ++ SND_SOC_DAPM_MUX("ADC MIXER Mux", SND_SOC_NOPM, 0, 0, &icdc_d3_adc_input_sel_controls), ++ ++/* PINS */ ++ SND_SOC_DAPM_INPUT("AIP"), ++ SND_SOC_DAPM_INPUT("AIN"), ++ SND_SOC_DAPM_INPUT("DMIC IN"), ++ SND_SOC_DAPM_OUTPUT("DO_LO_PWM"), ++ SND_SOC_DAPM_OUTPUT("DO_BO_PWM"), ++}; ++ ++static const struct snd_soc_dapm_route intercon[] = { ++ ++ { "MICBIAS", NULL, "AIP" }, ++ { "MICBIAS", NULL, "AIN" }, ++ { "AMIC", NULL, "MICBIAS" }, ++ { "AMIC", NULL, "MICBIAS" }, ++ ++ /*input*/ ++ { "ADC Mux", "AMIC ON", "AMIC" }, ++ { "ADC Mux", "DMIC ON", "DMIC IN" }, ++ ++ { "ADC Mode Mux" , "RECORD INPUT","ADC Mux"}, ++ { "ADC Mode Mux" , "RECORD INPUT + DAC","ADC Mux"}, ++ ++ { "AIADC Mux" , "Normal Inputs","ADC Mode Mux"}, ++ { "AIADC Mux" , "Cross Inputs","ADC Mode Mux"}, ++ { "AIADC Mux" , "Mixed Inputs","ADC Mode Mux"}, ++ { "AIADC Mux" , "Zero Inputs","ADC Mode Mux"}, ++ { "AIADC Mux L" , "Normal Inputs","ADC Mode Mux"}, ++ { "AIADC Mux L" , "Cross Inputs","ADC Mode Mux"}, ++ { "AIADC Mux L" , "Mixed Inputs","ADC Mode Mux"}, ++ { "AIADC Mux L" , "Zero Inputs","ADC Mode Mux"}, ++ { "AIADC Mux R" , "Normal Inputs","ADC Mode Mux"}, ++ { "AIADC Mux R" , "Cross Inputs","ADC Mode Mux"}, ++ { "AIADC Mux R" , "Mixed Inputs","ADC Mode Mux"}, ++ { "AIADC Mux R" , "Zero Inputs","ADC Mode Mux"}, ++ ++ { "ADC", NULL, "AIADC Mux" }, ++ { "ADC", NULL, "AIADC Mux L" }, ++ { "ADC", NULL, "AIADC Mux R" }, ++ ++ { "ADC MIXER Mux" , "Normal Inputs","ADC Mux"}, ++ { "ADC MIXER Mux" , "Cross Inputs","ADC Mux"}, ++ { "ADC MIXER Mux" , "Mixed Inputs","ADC Mux"}, ++ { "ADC MIXER Mux" , "Zero Inputs","ADC Mux"}, ++ ++ {"DAC Mode Mux", NULL, "ADC MIXER Mux"}, ++ /*output*/ ++ { "DAC_MERCURY" , NULL, "DAC" }, ++ { "DAC_MERCURY VMux" , "MERCURY ON" , "DAC_MERCURY" }, ++ ++ /* select mixer inputs*/ ++ {"MERCURY AIDAC MIXER Mux", "Normal Inputs", "DAC_MERCURY VMux"}, ++ {"MERCURY AIDAC MIXER Mux", "Cross Inputs", "DAC_MERCURY VMux"}, ++ {"MERCURY AIDAC MIXER Mux", "Mixed Inputs", "DAC_MERCURY VMux"}, ++ {"MERCURY AIDAC MIXER Mux", "Zero Inputs", "DAC_MERCURY VMux"}, ++ ++ /*select mixer mode*/ ++ {"DAC Mode Mux", "PLAYBACK DAC", "DAC_MERCURY VMux"}, ++ {"DAC Mode Mux", "PLAYBACK DAC + ADC", "MERCURY AIDAC MIXER Mux"}, ++ ++ /* DAC_MERCURY Vmux->DAC Mux*/ ++ /*select mixer output channels*/ ++ { "MERCURY AIDAC Mux" , "Normal Inputs" , "DAC Mode Mux" }, ++ { "MERCURY AIDAC Mux" , "Cross Inputs" , "DAC Mode Mux" }, ++ { "MERCURY AIDAC Mux" , "Mixed Inputs" , "DAC Mode Mux" }, ++ { "MERCURY AIDAC Mux" , "Zero Inputs" , "DAC Mode Mux" }, ++ ++ { "DO_LO_PWM", NULL, "MERCURY AIDAC Mux" }, ++}; ++ ++#ifdef CONFIG_PM ++static int icdc_d3_suspend(struct snd_soc_codec *codec) ++{ ++ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); ++ ++ snd_soc_update_bits(codec, SCODA_REG_AICR_ADC, SCODA_AICR_ADC_SB_MASK, 1); ++ snd_soc_update_bits(codec, SCODA_REG_AICR_DAC, SCODA_AICR_DAC_SB_MASK, 1); ++ snd_soc_update_bits(codec, SCODA_REG_CR_VIC, SCODA_CR_VIC_SB_SLEEP_MASK, 1); ++ snd_soc_update_bits(codec, SCODA_REG_CR_VIC, SCODA_CR_VIC_SB_MASK, 1); ++ snd_soc_update_bits(codec, SCODA_REG_CR_CK, SCODA_CR_CK_SDCLK_MASK, 1); ++ snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_OFF); ++ return 0; ++} ++ ++static int icdc_d3_resume(struct snd_soc_codec *codec) ++{ ++ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); ++ ++ snd_soc_update_bits(codec, SCODA_REG_CR_CK, SCODA_CR_CK_SDCLK_MASK, 0); ++ ++ if (snd_soc_update_bits(codec, SCODA_REG_CR_VIC, SCODA_CR_VIC_SB_MASK, 0)) ++ msleep(250); ++ if (snd_soc_update_bits(codec, SCODA_REG_CR_VIC, SCODA_CR_VIC_SB_SLEEP_MASK, 0)) { ++ msleep(10); ++ } ++ snd_soc_update_bits(codec, SCODA_REG_AICR_ADC, SCODA_AICR_ADC_SB_MASK, 0); ++ snd_soc_update_bits(codec, SCODA_REG_AICR_DAC, SCODA_AICR_DAC_SB_MASK, 0); ++ snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_STANDBY); ++ return 0; ++} ++#endif ++ ++static int icdc_d3_probe(struct snd_soc_codec *codec) ++{ ++ struct icdc_d3 *icdc_d3 = snd_soc_codec_get_drvdata(codec); ++ dev_info(codec->dev, "codec icdc-d3 probe enter\n"); ++ ++ /* power off codec */ ++ snd_soc_update_bits(codec, SCODA_REG_CR_VIC, SCODA_CR_VIC_SB_SLEEP_MASK, 1); ++ snd_soc_update_bits(codec, SCODA_REG_CR_VIC, SCODA_CR_VIC_SB_MASK, 1); ++ ++#ifdef DEBUG ++ /*dump for debug*/ ++ dump_registers_hazard(icdc_d3); ++#endif ++ /* codec select enable 24M clock*/ ++ snd_soc_update_bits(codec, SCODA_REG_CR_CK , SCODA_CR_CK_MCLK_DIV_MASK, 1 << SCODA_CR_CK_MCLK_DIV_SHIFT); ++ snd_soc_update_bits(codec, SCODA_REG_CR_CK , SCODA_CR_CK_SDCLK_MASK, 0 << SCODA_CR_CK_SDCLK_SHIFT); ++ snd_soc_update_bits(codec, SCODA_REG_CR_CK , SCODA_CR_CRYSTAL_MASK, 0 << SCODA_CR_CRYSTAL_SHIFT); ++ ++ /*codec select Dac/Adc i2s interface*/ ++ snd_soc_update_bits(codec,SCODA_REG_AICR_DAC, SCODA_AICR_DAC_SLAVE_MASK, 0); ++ snd_soc_update_bits(codec,SCODA_REG_AICR_DAC, SCODA_AICR_DAC_AUDIO_MASK, SCODA_AICR_DAC_AUDIOIF_I2S); ++ ++ /*codec generated IRQ is a high level */ ++ snd_soc_update_bits(codec, SCODA_REG_ICR, SCODA_ICR_INT_FORM_MASK, SCODA_ICR_INT_FORM_LOW); ++ ++ /*codec irq mask*/ ++ snd_soc_write(codec, SCODA_REG_IMR, SCODA_IMR_COMMON_MASK); ++ snd_soc_write(codec, SCODA_REG_IMR2, SCODA_IMR2_COMMON_MASK); ++ ++ /*codec clear all irq*/ ++ snd_soc_write(codec, SCODA_REG_IFR, SCODA_IMR_COMMON_MASK); ++ snd_soc_write(codec, SCODA_REG_IFR2, SCODA_IMR2_COMMON_MASK); ++ ++ icdc_d3_write(codec, SCODA_MIX_3, 0x5 << 4); ++ icdc_d3_write(codec, SCODA_MIX_2, 0x1 << 4); ++ ++ icdc_d3->codec = codec; ++ return 0; ++} ++ ++static int icdc_d3_remove(struct snd_soc_codec *codec) ++{ ++ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); ++ dev_info(codec->dev, "codec icdc_d3 remove enter\n"); ++ snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_OFF); ++ return 0; ++} ++ ++static struct snd_soc_codec_driver soc_codec_dev_icdc_d3_codec = { ++ .probe = icdc_d3_probe, ++ .remove = icdc_d3_remove, ++#ifdef CONFIG_PM ++ .suspend = icdc_d3_suspend, ++ .resume = icdc_d3_resume, ++#endif ++ ++ .read = icdc_d3_read, ++ .write = icdc_d3_write, ++ .reg_cache_default = icdc_d3_reg_defcache, ++ .reg_word_size = sizeof(u8), ++ .reg_cache_step = 1, ++ .reg_cache_size = SCODA_MAX_REG_NUM, ++ ++ .controls = icdc_d3_snd_controls, ++ .num_controls = ARRAY_SIZE(icdc_d3_snd_controls), ++ .dapm_widgets = icdc_d3_dapm_widgets, ++ .num_dapm_widgets = ARRAY_SIZE(icdc_d3_dapm_widgets), ++ .dapm_routes = intercon, ++ .num_dapm_routes = ARRAY_SIZE(intercon), ++}; ++ ++/*Just for debug*/ ++static ssize_t hw_regs_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct icdc_d3 *icdc_d3 = dev_get_drvdata(dev); ++ struct snd_soc_codec *codec = icdc_d3->codec; ++ if (!codec) { ++ dev_info(dev, "icdc_d3 is not probe, can not use %s function\n", __func__); ++ return 0; ++ } ++ mutex_lock(&codec->component.io_mutex); ++ dump_registers_hazard(icdc_d3); ++ mutex_unlock(&codec->component.io_mutex); ++ return 0; ++} ++ ++static ssize_t hw_regs_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, ++ size_t count) ++{ ++ struct icdc_d3 *icdc_d3 = dev_get_drvdata(dev); ++ struct snd_soc_codec *codec = icdc_d3->codec; ++ const char *start = buf; ++ unsigned int reg, val; ++ int ret_count = 0; ++ ++ if (!codec) { ++ dev_info(dev, "icdc_d3 is not probe, can not use %s function\n", __func__); ++ return count; ++ } ++ ++ while(!isxdigit(*start)) { ++ start++; ++ if (++ret_count >= count) ++ return count; ++ } ++ reg = simple_strtoul(start, (char **)&start, 16); ++ while(!isxdigit(*start)) { ++ start++; ++ if (++ret_count >= count) ++ return count; ++ } ++ val = simple_strtoul(start, (char **)&start, 16); ++ mutex_lock(&codec->component.io_mutex); ++ icdc_d3_write(codec, reg, val); ++ mutex_unlock(&codec->component.io_mutex); ++ return count; ++} ++ ++static struct device_attribute icdc_d3_sysfs_attrs = ++ __ATTR_RW(hw_regs); ++ ++static int icdc_d3_platform_probe(struct platform_device *pdev) ++{ ++ struct device_node *parent = of_get_parent(pdev->dev.of_node); ++ struct icdc_d3 *icdc_d3 = NULL; ++ int ret = 0; ++ ++ icdc_d3 = (struct icdc_d3*)devm_kzalloc(&pdev->dev, ++ sizeof(struct icdc_d3), GFP_KERNEL); ++ if (!icdc_d3) ++ return -ENOMEM; ++ ++ icdc_d3->mapped_base = of_iomap(parent, 0); ++ if (IS_ERR(icdc_d3->mapped_base)) { ++ dev_err(&pdev->dev, "Failed to ioremap mmio memory\n"); ++ return PTR_ERR(icdc_d3->mapped_base); ++ } ++ ++ icdc_d3->dev = &pdev->dev; ++ icdc_d3->dac_user_mute = 1; ++ icdc_d3->aohp_in_pwsq = 0; ++ spin_lock_init(&icdc_d3->io_lock); ++ platform_set_drvdata(pdev, (void *)icdc_d3); ++ ++ ret = snd_soc_register_codec(&pdev->dev, ++ &soc_codec_dev_icdc_d3_codec, &icdc_d3_codec_dai, 1); ++ if (ret) { ++ dev_err(&pdev->dev, "Faild to register codec\n"); ++ platform_set_drvdata(pdev, NULL); ++ return ret; ++ } ++ ++ ret = device_create_file(&pdev->dev, &icdc_d3_sysfs_attrs); ++ dev_info(&pdev->dev, "codec icdc-d3 platfrom probe success\n"); ++ return 0; ++} ++ ++static int icdc_d3_platform_remove(struct platform_device *pdev) ++{ ++ dev_info(&pdev->dev, "codec icdc-d3 platform remove\n"); ++ snd_soc_unregister_codec(&pdev->dev); ++ platform_set_drvdata(pdev, NULL); ++ return 0; ++} ++ ++static const struct of_device_id codec_dt_match[] = { ++ { .compatible = "ingenic,icdc3", .data = NULL }, ++}; ++MODULE_DEVICE_TABLE(of, codec_dt_match); ++ ++static struct platform_driver icdc_d3_codec_driver = { ++ .driver = { ++ .name = "icdc-d3", ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(codec_dt_match), ++ }, ++ .probe = icdc_d3_platform_probe, ++ .remove = icdc_d3_platform_remove, ++}; ++ ++static int icdc_d3_modinit(void) ++{ ++ return platform_driver_register(&icdc_d3_codec_driver); ++} ++module_init(icdc_d3_modinit); ++ ++static void icdc_d3_exit(void) ++{ ++ platform_driver_unregister(&icdc_d3_codec_driver); ++} ++module_exit(icdc_d3_exit); ++ ++MODULE_DESCRIPTION("iCdc d3 Codec Driver"); ++MODULE_AUTHOR("sccheng"); ++MODULE_LICENSE("GPL"); diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_icodec_icdc_d3.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_icodec_icdc_d3.h.patch new file mode 100644 index 00000000..655a9a33 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_ingenic_icodec_icdc_d3.h.patch @@ -0,0 +1,411 @@ +diff -drupN a/sound/soc/ingenic/icodec/icdc_d3.h b/sound/soc/ingenic/icodec/icdc_d3.h +--- a/sound/soc/ingenic/icodec/icdc_d3.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/sound/soc/ingenic/icodec/icdc_d3.h 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,407 @@ ++/* ++ * sound/soc/ingenic/icodec/icdc_d3.h ++ * ALSA SoC Audio driver -- ingenic internal codec (icdc_d3) driver ++ ++ * Copyright 2015 Ingenic Semiconductor Co.,Ltd ++ * cli ++ * ++ * Note: icdc_d3 is an internal codec for ingenic SOC ++ * ++ * 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. ++ */ ++ ++ ++#ifndef __ICDC_D3_REG_H__ ++#define __ICDC_D3_REG_H__ ++ ++#include ++#include ++#include "../as-v1/asoc-aic.h" ++ ++struct icdc_d3 { ++ struct device *dev; /*aic device used to access register*/ ++ struct snd_soc_codec *codec; ++ spinlock_t io_lock; /*codec hw io lock, ++ Note codec cannot opt in irq context*/ ++ void * __iomem mapped_base; /*vir addr*/ ++ resource_size_t mapped_resstart; /*resource phy addr*/ ++ resource_size_t mapped_ressize; /*resource phy addr size*/ ++ ++ int dac_user_mute; /*dac user mute state*/ ++ /*aohp power on anti pop event*/ ++ volatile int aohp_in_pwsq; /*aohp in power up/down seq*/ ++ int hpl_wished_gain; /*keep original hpl/r gain register value*/ ++ int hpr_wished_gain; ++ int linl_wished_gain; /*keep original hpl/r gain register value*/ ++ int linr_wished_gain; ++ /*codec irq*/ ++ int irqno; ++ int irqflags; ++ int codec_imr; ++ struct work_struct irq_work; ++ /*headphone detect*/ ++ struct snd_soc_jack *jack; ++ int report_mask; ++}; ++ ++/* ++ * Note: icdc_d3 codec just only support detect headphone jack ++ * detected_type: detect event treat as detected_type ++ * example: SND_JACK_HEADSET detect event treat as SND_JACK_HEADSET ++ */ ++int icdc_d3_hp_detect(struct snd_soc_codec *codec, ++ struct snd_soc_jack *jack, int detected_type); ++ ++/* icdc_d3 internal register space */ ++enum { ++ SCODA_REG_SR = 0x0, ++ SCODA_REG_SR2, ++ SCODA_REG_SIGR, ++ SCODA_REG_SIGR2, ++ SCODA_REG_SIGR3, ++ SCODA_REG_SIGR5, ++ SCODA_REG_SIGR7, ++ SCODA_REG_MR, ++ SCODA_REG_AICR_DAC, ++ SCODA_REG_AICR_ADC, ++ SCODA_REG_CR_DMIC, ++ SCODA_REG_CR_MIC1, ++ SCODA_REG_CR_MIC2, ++ SCODA_REG_CR_DAC, ++ SCODA_REG_CR_DAC2, ++ SCODA_REG_CR_ADC, ++ SCODA_REG_CR_MIX, ++ SCODA_REG_DR_MIX, ++ SCODA_REG_CR_VIC, ++ SCODA_REG_CR_CK, ++ SCODA_REG_FCR_DAC, ++ SCODA_REG_SFCCR_DAC, ++ SCODA_REG_SFFCR_DAC, ++ SCODA_REG_FCR_ADC, ++ SCODA_REG_CR_TIMER_MSB, ++ SCODA_REG_CR_TIMER_LSB, ++ SCODA_REG_ICR, ++ SCODA_REG_IMR, ++ SCODA_REG_IFR, ++ SCODA_REG_IMR2, ++ SCODA_REG_IFR2, ++ SCODA_REG_GCR_DACL, ++ SCODA_REG_GCR_DACR, ++ SCODA_REG_GCR_DACL2, ++ SCODA_REG_GCR_DACR2, ++ SCODA_REG_GCR_MIC1, ++ SCODA_REG_GCR_MIC2, ++ SCODA_REG_GCR_ADCL, ++ SCODA_REG_GCR_ADCR, ++ SCODA_REG_GCR_MIXDACL, ++ SCODA_REG_GCR_MIXDACR, ++ SCODA_REG_GCR_MIXADCL, ++ SCODA_REG_GCR_MIXADCR, ++ SCODA_REG_CR_DAC_AGC, ++ SCODA_REG_DR_DAC_AGC, ++ SCODA_REG_CR_DAC2_AGC, ++ SCODA_REG_DR_DAC2_AGC, ++ SCODA_REG_CR_ADC_AGC, ++ SCODA_REG_DR_ADC_AGC, ++ SCODA_REG_SR_ADC_AGCDGL, ++ SCODA_REG_SR_ADC_AGCDGR, ++ SCODA_REG_SR_ADC_AGCAGL, ++ SCODA_REG_SR_ADC_AGCAGR, ++ SCODA_REG_CR_TR, ++ SCODA_REG_DR_TR, ++ SCODA_REG_SR_TR1, ++ SCODA_REG_SR_TR2, ++ SCODA_REG_SR_TR_SRCDAC, ++ ++/* icdc_d3 internal register extend space */ ++ SCODA_MIX_0, ++ SCODA_MIX_1, ++ SCODA_MIX_2, ++ SCODA_MIX_3, ++ SCODA_MIX_4, ++ ++ SCODA_DAC_AGC0, ++ SCODA_DAC_AGC1, ++ SCODA_DAC_AGC2, ++ SCODA_DAC_AGC3, ++ ++ SCODA_DAC2_AGC0, ++ SCODA_DAC2_AGC1, ++ SCODA_DAC2_AGC2, ++ SCODA_DAC2_AGC3, ++ ++ SCODA_ADC_AGC0, ++ SCODA_ADC_AGC1, ++ SCODA_ADC_AGC2, ++ SCODA_ADC_AGC3, ++ SCODA_ADC_AGC4, ++ SCODA_MAX_REG_NUM, ++}; ++ ++/*aicr dac*/ ++#define SCODA_AICR_DAC_ADWL_SHIFT (6) ++#define SCODA_AICR_DAC_ADWL_MASK (0x3 << SCODA_AICR_DAC_ADWL_SHIFT) ++#define SCODA_AICR_DAC_SLAVE_SHIFT (5) ++#define SCODA_AICR_DAC_SLAVE_MASK (0x1 << SCODA_AICR_DAC_SLAVE_SHIFT) ++#define SCODA_AICR_DAC_SLAVE (1 << 5) ++#define SCODA_AICR_DAC_SB_SHIFT (4) ++#define SCODA_AICR_DAC_SB_MASK (0x1 << SCODA_AICR_DAC_SB_SHIFT) ++#define SCODA_AICR_DAC_AUDIOIF_SHIFT (0) ++#define SCODA_AICR_DAC_AUDIO_MASK (0x3 << SCODA_AICR_DAC_AUDIOIF_SHIFT) ++#define SCODA_AICR_DAC_AUDIOIF_I2S (0x3) ++ ++/* aicr adc */ ++#define SCODA_AICR_ADC_ADWL_SHIFT (6) ++#define SCODA_AICR_ADC_ADWL_MASK (0x3 << SCODA_AICR_ADC_ADWL_SHIFT) ++#define SCODA_AICR_ADC_SB_SHIFT (4) ++#define SCODA_AICR_ADC_SB_MASK (0x1 << SCODA_AICR_ADC_SB_SHIFT) ++#define SCODA_AICR_ADC_AUDIOIF_SHIFT (0) ++#define SCODA_AICR_ADC_AUDIO_MASK (0x3 << SCODA_AICR_ADC_AUDIOIF_SHIFT) ++#define SCODA_AICR_ADC_AUDIOIF_I2S (0x3) ++ ++/* cr vic */ ++#define SCODA_CR_VIC_SB_SHIFT (0) ++#define SCODA_CR_VIC_SB_MASK (1 << SCODA_CR_VIC_SB_SHIFT) ++#define SCODA_CR_VIC_SB_SLEEP_SHIFT (1) ++#define SCODA_CR_VIC_SB_SLEEP_MASK (1 << SCODA_CR_VIC_SB_SLEEP_SHIFT) ++ ++/* fcr adc/dac */ ++#define SCODA_FCR_FREQ_SHIFT (0) ++#define SCODA_FCR_FREQ_MASK (0xf << SCODA_FCR_FREQ_SHIFT) ++ ++/* cr dac */ ++#define SCODA_CR_DAC_SMUTE_SHIFT (7) ++#define SCODA_CR_DAC_SMUTE_MASK (0x1 << SCODA_CR_DAC_SMUTE_SHIFT) ++#define SCODA_CR_DAC_SB_SHIFT (4) ++#define SCODA_CR_DAC_SB_MASK (0x1 << SCODA_CR_DAC_SB_SHIFT) ++#define SCODA_CR_DAC_ZERO_SHIFT (0) ++#define SCODA_CR_DAC_ZERO_MASK (0x1 << SCODA_CR_DAC_ZERO_SHIFT) ++ ++/* cr dac */ ++#define SCODA_CR_ADC_SMUTE_SHIFT (7) ++#define SCODA_CR_ADC_SMUTE_MASK (0x1 << SCODA_CR_ADC_SMUTE_SHIFT) ++#define SCODA_CR_ADC_MIC_SEL_SHIFT (6) ++#define SCODA_CR_ADC_MIC_SEL_MASK (0x1 << SCODA_CR_ADC_MIC_SEL_SHIFT) ++#define SCODA_CR_ADC_SB_SHIFT (4) ++#define SCODA_CR_ADC_SB_MASK (0x1 << SCODA_CR_ADC_SB_SHIFT) ++#define SCODA_CR_ADC_ZERO_SHIFT (0) ++#define SCODA_CR_ADC_ZERO_MASK (0x1 << SCODA_CR_ADC_ZERO_SHIFT) ++ ++/* ifr */ ++#define SCODA_IFR_DAC_MUTE_SHIFT (0) ++#define SCODA_IFR_DAC_MUTE_MASK (0x1 << SCODA_IFR_DAC_MUTE_SHIFT) ++#define SCODA_IFR_ADC_MUTE_SHIFT (2) ++#define SCODA_IFR_ADC_MUTE_MASK (0x1 << SCODA_IFR_ADC_MUTE_SHIFT) ++#define SCODA_IFR_ADAS_LOCK_SHIFT (7) ++#define SCODA_IFR_ADAS_LOCK_MASK (0x1 << SCODA_IFR_ADAS_LOCK_SHIFT) ++ ++/* cr ck */ ++#define SCODA_CR_CK_MCLK_DIV_SHIFT (6) ++#define SCODA_CR_CK_MCLK_DIV_MASK (0x1 << SCODA_CR_CK_MCLK_DIV_SHIFT) ++#define SCODA_CR_CK_SDCLK_SHIFT (4) ++#define SCODA_CR_CK_SDCLK_MASK (0x1 << SCODA_CR_CK_SDCLK_SHIFT) ++#define SCODA_CR_CRYSTAL_SHIFT (0) ++#define SCODA_CR_CRYSTAL_MASK (0xf << SCODA_CR_CRYSTAL_SHIFT) ++ ++/* icr */ ++#define SCODA_ICR_INT_FORM_SHIFT (6) ++#define SCODA_ICR_INT_FORM_MASK (0x3 << SCODA_ICR_INT_FORM_SHIFT) ++#define SCODA_ICR_INT_FORM_HIGH (0) ++#define SCODA_ICR_INT_FORM_LOW (1) ++ ++/* imr */ ++#define SCODA_IMR_COMMON_MASK (0xff) ++#define SCODA_IMR2_COMMON_MASK (0xff) ++ ++/*For Codec*/ ++#define RGADW (0xA4) ++#define RGDATA (0xA8) ++ ++static inline void icdc_d3_mapped_reg_set(void __iomem * xreg, int xmask, int xval) ++{ ++ int val = readl(xreg); ++ val &= ~(xmask); ++ val |= xval; ++ writel(val, xreg); ++} ++ ++static inline int icdc_d3_mapped_test_bits(void __iomem * xreg, int xmask, int xval) ++{ ++ int val = readl(xreg); ++ val &= xmask; ++ return (val == xval); ++} ++ ++/* ++ * RGADW ++ */ ++#define SCODA_RGDIN_BIT (0) ++#define SCODA_RGDIN_MASK (0xff << SCODA_RGDIN_BIT) ++#define SCODA_RGADDR_BIT (8) ++#define SCODA_RGADDR_MASK (0x7f << SCODA_RGADDR_BIT) ++#define SCODA_RGWR_BIT (16) ++#define SCODA_RGWR_MASK (0x1 << SCODA_RGWR_BIT) ++ ++#define icdc_d3_test_rw_inval(icdc_d3) \ ++ icdc_d3_mapped_test_bits((icdc_d3->mapped_base + RGADW), SCODA_RGWR_MASK, (1 << SCODA_RGWR_BIT)) ++/* ++ * RGDATA ++ */ ++#define SCODA_RGDOUT_BIT (0) ++#define SCODA_RGDOUT_MASK (0xff << SCODA_RGDOUT_BIT) ++#define SCODA_IRQ_BIT (8) ++#define SCODA_IRQ_MASK (0x1 << SCODA_IRQ_BIT) ++ ++#define icdc_d3_test_irq(icdc_d3) \ ++ icdc_d3_mapped_test_bits((icdc_d3->mapped_base + RGDATA), \ ++ SCODA_IRQ_MASK, (1 << SCODA_IRQ_BIT)) ++ ++static inline u8 icdc_d3_hw_read_normal(struct icdc_d3 *icdc_d3, int reg) ++{ ++ void __iomem * mapped_base = icdc_d3->mapped_base; ++ int reval; ++ int timeout = 0xfffff; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&icdc_d3->io_lock, flags); ++ ++ while(icdc_d3_test_rw_inval(icdc_d3)) { ++ timeout--; ++ if (!timeout) pr_err("icdc_d3 test_rw_inval timeout\n"); ++ } ++ ++ icdc_d3_mapped_reg_set((mapped_base + RGADW), SCODA_RGWR_MASK,(0 << SCODA_RGWR_BIT)); ++ ++ icdc_d3_mapped_reg_set((mapped_base + RGADW), SCODA_RGADDR_MASK,(reg << SCODA_RGADDR_BIT)); ++ ++ reval = readl((mapped_base + RGDATA)); ++ reval = readl((mapped_base + RGDATA)); ++ reval = readl((mapped_base + RGDATA)); ++ reval = readl((mapped_base + RGDATA)); ++ reval = readl((mapped_base + RGDATA)); ++ reval = ((reval & SCODA_RGDOUT_MASK) >> SCODA_RGDOUT_BIT); ++// printk("reg %x = %x\n", reg, reval); ++ spin_unlock_irqrestore(&icdc_d3->io_lock, flags); ++ return (u8) reval; ++} ++ ++static inline int icdc_d3_hw_write_normal(struct icdc_d3 *icdc_d3, int reg, int data) ++{ ++ void __iomem * mapped_base = icdc_d3->mapped_base; ++ int ret = 0; ++ int timeout = 0xfffff; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&icdc_d3->io_lock, flags); ++ ++ while(icdc_d3_test_rw_inval(icdc_d3)) { ++ timeout--; ++ if (!timeout) pr_err("icdc_d3 test_rw_inval timeout\n"); ++ } ++ icdc_d3_mapped_reg_set((mapped_base + RGADW),SCODA_RGDIN_MASK|SCODA_RGADDR_MASK, ++ (data << SCODA_RGDIN_BIT)|(reg << SCODA_RGADDR_BIT)); ++ icdc_d3_mapped_reg_set((mapped_base + RGADW), SCODA_RGWR_MASK , 1 << SCODA_RGWR_BIT); ++ spin_unlock_irqrestore(&icdc_d3->io_lock, flags); ++ if( reg != SCODA_REG_IFR && reg != SCODA_REG_IFR2 ){ ++ ret = icdc_d3_hw_read_normal(icdc_d3, reg); ++ if (data != ret){ ++ printk("icdc write reg %x err exp %x now is %x\n",reg,data,ret); ++ ret = -1; ++ } ++ } ++ return ret; ++} ++ ++static int icdc_d3_hw_write_extend(struct icdc_d3 *icdc_d3, u8 sreg, u8 sdata){ ++ int creg, cdata, dreg; ++ switch (sreg) { ++ case SCODA_MIX_0 ... SCODA_MIX_4: ++ creg = SCODA_REG_CR_MIX; ++ dreg = SCODA_REG_DR_MIX; ++ sreg -= SCODA_MIX_0; ++ break; ++ case SCODA_DAC_AGC0 ... SCODA_DAC_AGC3: ++ creg = SCODA_REG_CR_DAC_AGC; ++ dreg = SCODA_REG_DR_DAC_AGC; ++ sreg -= SCODA_DAC_AGC0; ++ break; ++ case SCODA_DAC2_AGC0 ... SCODA_DAC2_AGC3: ++ creg = SCODA_REG_CR_DAC2_AGC; ++ dreg = SCODA_REG_DR_DAC2_AGC; ++ sreg -= SCODA_DAC2_AGC0; ++ break; ++ case SCODA_ADC_AGC0 ... SCODA_ADC_AGC4: ++ creg = SCODA_REG_CR_ADC_AGC; ++ dreg = SCODA_REG_DR_ADC_AGC; ++ sreg -= SCODA_ADC_AGC0; ++ break; ++ default: ++ return 0; ++ } ++ printk("write extend : sreg: %d [0 - 4], creg: %x sdata: %d\n", sreg, creg, sdata); ++ ++ cdata = (icdc_d3_hw_read_normal(icdc_d3,creg)&(~0x3f))|((sreg&0x3f)|0x40); ++ ++ icdc_d3_hw_write_normal(icdc_d3, creg, cdata); ++ icdc_d3_hw_write_normal(icdc_d3, dreg, sdata); ++ if(sdata!=icdc_d3_hw_read_normal(icdc_d3,dreg)) ++ return -1; ++ return 0; ++} ++ ++ ++static u8 icdc_d3_hw_read_extend(struct icdc_d3 *icdc_d3, u8 sreg) ++{ ++ int creg, cdata, dreg, ddata; ++ switch (sreg) { ++ ++ case SCODA_MIX_0 ... SCODA_MIX_4: ++ creg = SCODA_REG_CR_MIX; ++ dreg = SCODA_REG_DR_MIX; ++ sreg -= SCODA_MIX_0; ++ break; ++ case SCODA_DAC_AGC0 ... SCODA_DAC_AGC3: ++ creg = SCODA_REG_CR_DAC_AGC; ++ dreg = SCODA_REG_DR_DAC_AGC; ++ sreg -= SCODA_DAC_AGC0; ++ break; ++ case SCODA_DAC2_AGC0 ... SCODA_DAC2_AGC3: ++ creg = SCODA_REG_CR_DAC2_AGC; ++ dreg = SCODA_REG_DR_DAC2_AGC; ++ sreg -= SCODA_DAC2_AGC0; ++ break; ++ case SCODA_ADC_AGC0 ... SCODA_ADC_AGC4: ++ creg = SCODA_REG_CR_ADC_AGC; ++ dreg = SCODA_REG_DR_ADC_AGC; ++ sreg -= SCODA_ADC_AGC0; ++ break; ++ default: ++ return 0; ++ } ++ cdata = (icdc_d3_hw_read_normal(icdc_d3,creg)&(~0x7f))|(sreg&0x3f); ++ icdc_d3_hw_write_normal(icdc_d3, creg, cdata); ++ ddata = icdc_d3_hw_read_normal(icdc_d3, dreg); ++ return (u8) ddata; ++} ++ ++ ++static inline u8 icdc_d3_hw_read(struct icdc_d3 *icdc_d3, int reg) ++{ ++ if (reg > SCODA_REG_SR_TR_SRCDAC) ++ return icdc_d3_hw_read_extend(icdc_d3, reg); ++ else ++ return icdc_d3_hw_read_normal(icdc_d3, reg); ++} ++static inline int icdc_d3_hw_write(struct icdc_d3 *icdc_d3, int reg, int data) ++{ ++ if (reg > SCODA_REG_SR_TR_SRCDAC){ ++ return icdc_d3_hw_write_extend(icdc_d3, reg, data); ++ } else { ++ return icdc_d3_hw_write_normal(icdc_d3, reg, data); ++ } ++} ++ ++ ++#endif /* __ICDC_D3_REG_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_soc-io.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_soc-io.c.patch new file mode 100644 index 00000000..a316c795 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-sound_soc_soc-io.c.patch @@ -0,0 +1,23 @@ +diff -drupN a/sound/soc/soc-io.c b/sound/soc/soc-io.c +--- a/sound/soc/soc-io.c 2017-10-21 18:09:07.000000000 +0300 ++++ b/sound/soc/soc-io.c 2022-06-09 05:02:37.000000000 +0300 +@@ -41,6 +41,19 @@ int snd_soc_component_read(struct snd_so + } + EXPORT_SYMBOL_GPL(snd_soc_component_read); + ++unsigned int snd_soc_component_read32(struct snd_soc_component *component, ++ unsigned int reg) ++{ ++ unsigned int val; ++ int ret; ++ ++ ret = snd_soc_component_read(component, reg, &val); ++ if (ret < 0) ++ return -1; ++ return val; ++} ++EXPORT_SYMBOL_GPL(snd_soc_component_read32); ++ + /** + * snd_soc_component_write() - Write register value + * @component: Component to write to diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_Makefile.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_Makefile.patch new file mode 100644 index 00000000..a282fcbe --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_Makefile.patch @@ -0,0 +1,42 @@ +diff -drupN a/tools/pm-sleep/Makefile b/tools/pm-sleep/Makefile +--- a/tools/pm-sleep/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ b/tools/pm-sleep/Makefile 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,38 @@ ++ ++CHIP_TYPE ?= x1000 ++current_dir = $(PWD) ++ ++OBJS=start.o pm_sleep.o uart.o gpio.o #i2c-gpio.o ++ ++LD_FLAGS=-static -n -nostdlib -EL -m elf32ltsmip -T u-boot.lds --gc-sections -pie -Bstatic -Ttext 0 ++ ++CFLAGS := -fPIC -Os -mips32r2 -fvisibility=hidden -fno-common ++CFLAGS += -I$(current_dir)/include -I$(current_dir)/chips/$(CHIP_TYPE)/include ++CFLAGS += -DDEBUG ++ ++ ++PRJ=core_sleep ++BIN=$(PRJ).bin ++HEX=$(PRJ).hex ++DUMP=$(PRJ).dump ++OBJCFLAGS = --gap-fill=0xff ++ ++ ++all:$(HEX) ++ ++$(HEX):$(BIN) ++ @hexdump -v -e '"0x" 1/4 "%08x" "," "\n"' $< > $@ ++ ++$(BIN):$(PRJ) ++ mips-linux-gnu-objdump -D $< > $(DUMP) ++ mips-linux-gnu-objcopy --gap-fill=0xff -O binary $< $@ ++ ++$(PRJ):$(OBJS) ++ mips-linux-gnu-ld -o $(PRJ) $(LD_FLAGS) $^ -Map $(PRJ).map ++ ++start.o:start.S ++ mips-linux-gnu-gcc $(CFLAGS) -o $@ -c $^ ++%.o:%.c ++ mips-linux-gnu-gcc $(CFLAGS) -o $@ -c $^ ++clean: ++ rm $(BIN) $(PRJ) $(OBJS) $(PRJ).map $(HEX) $(DUMP) -rf diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_README.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_README.patch new file mode 100644 index 00000000..7ae73360 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_README.patch @@ -0,0 +1,10 @@ +diff -drupN a/tools/pm-sleep/README b/tools/pm-sleep/README +--- a/tools/pm-sleep/README 1970-01-01 03:00:00.000000000 +0300 ++++ b/tools/pm-sleep/README 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,6 @@ ++ ++pm sleep only support x1000 and m200 ++ ++compile: ++ exprot CHIP_TYPE=m200 ++ make diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_chips_m200_include_cache.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_chips_m200_include_cache.h.patch new file mode 100644 index 00000000..c87d3fd7 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_chips_m200_include_cache.h.patch @@ -0,0 +1,115 @@ +diff -drupN a/tools/pm-sleep/chips/m200/include/cache.h b/tools/pm-sleep/chips/m200/include/cache.h +--- a/tools/pm-sleep/chips/m200/include/cache.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/tools/pm-sleep/chips/m200/include/cache.h 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,111 @@ ++#ifndef __CACHE_H__ ++#define __CACHE_H__ ++ ++#include ++ ++#define K0BASE 0x80000000 ++#define CFG_DCACHE_SIZE 32768 ++#define CFG_ICACHE_SIZE 32768 ++#define CFG_L2CACHE_SIZE (512 * 1024) ++#define CFG_CACHELINE_SIZE 32 ++#define Index_Store_Tag_I 0x08 ++#define Index_Store_Tag_D 0x09 ++#define Index_Invalidate_I 0x00 ++#define Index_Writeback_Inv_D 0x01 ++#define Index_Writeback_Inv_SD 0x03 ++ ++void blast_l1cache_all(void) ++{ ++ unsigned int addr; ++ for (addr = K0BASE; addr < (K0BASE + CFG_ICACHE_SIZE); addr += CFG_CACHELINE_SIZE) ++ { ++ __asm__ __volatile__( ++ ".set push \n\t" ++ ".set noreorder \n\t" ++ ".set mips3 \n\t" ++ "cache %2, 0x000(%0);\n\t" ++ "cache %1, 0x000(%0);\n\t" ++ ".set pop \n\t" ++ : : "r" (addr), "i" (Index_Writeback_Inv_D) ,"i" (Index_Invalidate_I)); ++ } ++ __asm__ __volatile__( ++ ".set push\n\t" ++ ".set noreorder\n\t" ++ ".set mips2\n\t" ++ "sync \n\t" ++ ".set pop"); ++ ++} ++void blast_l2cache_all(void) ++{ ++ unsigned int addr; ++ for (addr = K0BASE; addr < (K0BASE + CFG_L2CACHE_SIZE); addr += CFG_CACHELINE_SIZE) ++ { ++ __asm__ __volatile__( ++ ".set push \n\t" ++ ".set noreorder \n\t" ++ ".set mips3 \n\t" ++ "cache %1, 0x000(%0);\n\t" ++ ".set pop \n\t" ++ : : "r" (addr), "i" (Index_Writeback_Inv_SD)); ++ } ++ __asm__ __volatile__( ++ ".set push\n\t" ++ ".set noreorder\n\t" ++ ".set mips2\n\t" ++ "sync \n\t" ++ "lw $0,0(%0) \n\t" ++ ".set pop":: "r" (0xa0000000)); ++} ++void flush_cache_all(void) ++{ ++ blast_l1cache_all(); ++ blast_l2cache_all(); ++} ++static void __jz_cache_init(void) ++{ ++ register unsigned long addr; ++ asm volatile ("mtc0 $0, $28\n\t"::); ++ ++#if 0 ++ for (addr = K0BASE; addr < (K0BASE + CFG_DCACHE_SIZE); addr += CFG_CACHELINE_SIZE) { ++ asm volatile ( ++ ".set push \n\t" ++ ".set mips32\n\t" ++ " cache %0, 0(%1)\n\t" ++ ".set mips32\n\t" ++ ".set pop \n\t" ++ : ++ : "I" (Index_Store_Tag_D), "r"(addr)); ++ } ++#endif ++ for (addr = K0BASE; addr < (K0BASE + CFG_ICACHE_SIZE); addr += CFG_CACHELINE_SIZE) { ++ asm volatile ( ++ ".set push \n\t" ++ ".set mips32\n\t" ++ " cache %0, 0(%1)\n\t" ++ ".set mips32\n\t" ++ ".set pop \n\t" ++ : ++ : "I" (Index_Store_Tag_I), "r"(addr)); ++ } ++ /* invalidate BTB */ ++ asm volatile ( ++ ".set push \n\t" ++ ".set mips32\n\t" ++ " mfc0 $26, $16, 7\n\t" ++ " nop\n\t" ++ " ori $26, 2\n\t" ++ " mtc0 $26, $16, 7\n\t" ++ " nop\n\t" ++ "nop\n\t" ++ ".set mips32\n\t" ++ ".set pop \n\t" ++ ); ++} ++ ++static void l2cache_enable(void) ++{ ++ write_c0_ecc(0x0); ++} ++#endif /* __CACHE_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_chips_m200_include_cpu.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_chips_m200_include_cpu.h.patch new file mode 100644 index 00000000..3b60453a --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_chips_m200_include_cpu.h.patch @@ -0,0 +1,42 @@ +diff -drupN a/tools/pm-sleep/chips/m200/include/cpu.h b/tools/pm-sleep/chips/m200/include/cpu.h +--- a/tools/pm-sleep/chips/m200/include/cpu.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/tools/pm-sleep/chips/m200/include/cpu.h 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,38 @@ ++#ifndef __CPU_H__ ++#define __CPU_H__ ++static void set_resume_pc(unsigned int resume_pc) { ++ unsigned int cpu_no,opcr; ++ unsigned int reim,ctrl; ++ unsigned int addr; ++ /* Clear previous reset status */ ++ cpm_outl(0,CPM_RSR); ++ ++ /* OPCR.PD and OPCR.L2C_PD */ ++ cpu_no = read_c0_ebase() & 1; ++ ++ opcr = cpm_inl(CPM_OPCR); ++ //p 0 or 1 powerdown ++ opcr &= ~(3<<25); ++ opcr |= (cpu_no + 1) << 25; /* both big and small core power down*/ ++ cpm_outl(opcr,CPM_OPCR); ++ /* serial_put_hex(cpm_inl(CPM_OPCR)); */ ++ /* serial_put_hex(opcr); */ ++ ++ ctrl = get_smp_ctrl(); ++ ctrl |= 1 << (cpu_no + 8); ++ set_smp_ctrl(ctrl); ++ ++ reim = get_smp_reim(); ++ reim &= ~(0xffff << 16); ++ reim |= (unsigned int)resume_pc & (0xffff << 16); ++ set_smp_reim(reim); ++ /* ++ * The function of this register: ++ * store sleep wake RPC low 16bit, ++ * reim store high 16bit ++ */ ++ addr = __read_32bit_c0_register($12, 7); ++ __write_32bit_c0_register($12, 7, (unsigned int)resume_pc & (0xffff)); ++ ++} ++#endif /* __CPU_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_chips_m200_include_cpufreq.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_chips_m200_include_cpufreq.h.patch new file mode 100644 index 00000000..50024112 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_chips_m200_include_cpufreq.h.patch @@ -0,0 +1,60 @@ +diff -drupN a/tools/pm-sleep/chips/m200/include/cpufreq.h b/tools/pm-sleep/chips/m200/include/cpufreq.h +--- a/tools/pm-sleep/chips/m200/include/cpufreq.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/tools/pm-sleep/chips/m200/include/cpufreq.h 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,56 @@ ++#ifndef __CPUFREQ_H__ ++#define __CPUFREQ_H__ ++#include ++#include ++#include ++ ++void scale_cpu_freq(int status, unsigned int *cpccr) ++{ ++ unsigned int val; ++ ++ if(status == SCALE) { ++ /* ++ * (1) SCL_SRC source clock changes APLL to EXCLK ++ * (2) AH0/2 source clock changes MPLL to EXCLK ++ * (3) set PDIV H2DIV H0DIV L2CDIV CDIV = 0 ++ */ ++ val = cpm_inl(CPM_CPCCR); ++ *cpccr = val; ++ ++ val &= ~((3 << 30) | (3 << 28) | (0x3F << 24) | (0xF << 20)); ++ val |= (2 << 30) | (1 << 28) | (0x5 << 24) | (1 << 22) | (3 << 20); ++ cpm_outl(val,CPM_CPCCR); ++ while((cpm_inl(CPM_CPCSR) & 1)) ++ serial_putc('w'); ++ ++ val &= ~(0xFF); ++ val |= 0x00; ++ cpm_outl(val,CPM_CPCCR); ++ while((cpm_inl(CPM_CPCSR) & 1)) ++ serial_putc('g'); ++ val &= ~(0xFFF00); ++ val |= 0x00000; ++ cpm_outl(val,CPM_CPCCR); ++ while((cpm_inl(CPM_CPCSR) & 6)) ++ serial_putc('g'); ++ cpm_outl(cpm_inl(CPM_CPCCR) & ~(7 << 20),CPM_CPCCR); ++ while(cpm_inl(CPM_CPCCR) != 0x95000000) ++ serial_putc('P'); ++ } else if (status == RESTORE){ ++ val = cpm_inl(CPM_CPCCR); ++ val &= ~(0xfffff); ++ val |= *cpccr & 0xfffff; ++ cpm_outl(val,CPM_CPCCR); ++ ++ cpm_outl(*cpccr | (7 << 20),CPM_CPCCR); ++ while((cpm_inl(CPM_CPCSR) & 7)) ++ serial_putc('w'); ++ cpm_outl(cpm_inl(CPM_CPCCR) & ~(7 << 20),CPM_CPCCR); ++ while(cpm_inl(CPM_CPCCR) != *cpccr) ++ serial_putc('P'); ++ } ++ /* serial_put_hex(cpm_inl(CPM_CPCCR)); */ ++ /* serial_putc('K'); */ ++} ++ ++#endif /* __CPUFREQ_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_chips_x1000_include_cache.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_chips_x1000_include_cache.h.patch new file mode 100644 index 00000000..0c509ca3 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_chips_x1000_include_cache.h.patch @@ -0,0 +1,90 @@ +diff -drupN a/tools/pm-sleep/chips/x1000/include/cache.h b/tools/pm-sleep/chips/x1000/include/cache.h +--- a/tools/pm-sleep/chips/x1000/include/cache.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/tools/pm-sleep/chips/x1000/include/cache.h 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,86 @@ ++#ifndef __CACHE_H__ ++#define __CACHE_H__ ++ ++#define K0BASE 0x80000000 ++#define CFG_DCACHE_SIZE 16384 ++#define CFG_ICACHE_SIZE 16384 ++#define CFG_CACHELINE_SIZE 32 ++#define Index_Store_Tag_I 0x08 ++#define Index_Store_Tag_D 0x09 ++#define Index_Invalidate_I 0x00 ++#define Index_Writeback_Inv_D 0x01 ++#define Index_Writeback_Inv_SD 0x03 ++ ++void blast_l1cache_all(void) ++{ ++ unsigned int addr; ++ for (addr = K0BASE; addr < (K0BASE + CFG_ICACHE_SIZE); addr += CFG_CACHELINE_SIZE) ++ { ++ __asm__ __volatile__( ++ ".set push \n\t" ++ ".set noreorder \n\t" ++ ".set mips3 \n\t" ++ "cache %2, 0x000(%0);\n\t" ++ "cache %1, 0x000(%0);\n\t" ++ ".set pop \n\t" ++ : : "r" (addr), "i" (Index_Writeback_Inv_D) ,"i" (Index_Invalidate_I)); ++ } ++ __asm__ __volatile__( ++ ".set push\n\t" ++ ".set noreorder\n\t" ++ ".set mips2\n\t" ++ "sync \n\t" ++ ".set pop"); ++ ++} ++ ++void flush_cache_all(void) ++{ ++ blast_l1cache_all(); ++} ++static void __jz_cache_init(void) ++{ ++ register unsigned long addr; ++ asm volatile ("mtc0 $0, $28\n\t"::); ++ ++ for (addr = K0BASE; addr < (K0BASE + CFG_DCACHE_SIZE); addr += CFG_CACHELINE_SIZE) { ++ asm volatile ( ++ ".set push \n\t" ++ ".set mips32\n\t" ++ " cache %0, 0(%1)\n\t" ++ ".set mips32\n\t" ++ ".set pop \n\t" ++ : ++ : "I" (Index_Store_Tag_D), "r"(addr)); ++ } ++ ++ for (addr = K0BASE; addr < (K0BASE + CFG_ICACHE_SIZE); addr += CFG_CACHELINE_SIZE) { ++ asm volatile ( ++ ".set push \n\t" ++ ".set mips32\n\t" ++ " cache %0, 0(%1)\n\t" ++ ".set mips32\n\t" ++ ".set pop \n\t" ++ : ++ : "I" (Index_Store_Tag_I), "r"(addr)); ++ } ++ /* invalidate BTB */ ++ asm volatile ( ++ ".set push \n\t" ++ ".set mips32\n\t" ++ " mfc0 $26, $16, 7\n\t" ++ " nop\n\t" ++ " ori $26, 2\n\t" ++ " mtc0 $26, $16, 7\n\t" ++ " nop\n\t" ++ "nop\n\t" ++ ".set mips32\n\t" ++ ".set pop \n\t" ++ ); ++} ++static void l2cache_enable(void) ++{ ++ ++} ++ ++#endif /* __CACHE_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_chips_x1000_include_cpu.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_chips_x1000_include_cpu.h.patch new file mode 100644 index 00000000..45072b18 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_chips_x1000_include_cpu.h.patch @@ -0,0 +1,19 @@ +diff -drupN a/tools/pm-sleep/chips/x1000/include/cpu.h b/tools/pm-sleep/chips/x1000/include/cpu.h +--- a/tools/pm-sleep/chips/x1000/include/cpu.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/tools/pm-sleep/chips/x1000/include/cpu.h 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,14 @@ ++#ifndef __CPU_H__ ++#define __CPU_H__ ++static void set_resume_pc(unsigned int resume_pc) ++{ ++ unsigned int cpu_no,opcr; ++ unsigned int reim,ctrl; ++ unsigned int addr; ++ /* set SLBC and SLPC */ ++ cpm_outl(1,CPM_SLBC); ++ cpm_outl((unsigned int)resume_pc,CPM_SLPC); ++ /* Clear previous reset status */ ++ cpm_outl(0,CPM_RSR); ++} ++#endif /* __CPU_H__ */ +Двоичные файлы a/tools/pm-sleep/core_sleep и b/tools/pm-sleep/core_sleep различаются diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_chips_x1000_include_cpufreq.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_chips_x1000_include_cpufreq.h.patch new file mode 100644 index 00000000..e71d8a04 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_chips_x1000_include_cpufreq.h.patch @@ -0,0 +1,36 @@ +diff -drupN a/tools/pm-sleep/chips/x1000/include/cpufreq.h b/tools/pm-sleep/chips/x1000/include/cpufreq.h +--- a/tools/pm-sleep/chips/x1000/include/cpufreq.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/tools/pm-sleep/chips/x1000/include/cpufreq.h 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,32 @@ ++#ifndef __CPUFREQ_H__ ++#define __CPUFREQ_H__ ++#include ++#include ++#include ++ ++void scale_cpu_freq(int status, unsigned int *cpccr) ++{ ++ unsigned int val; ++ ++ if(status == SCALE) { ++ /* ++ * (1) set L2CDIV = 7 CDIV = 3 ++ */ ++ val = cpm_inl(CPM_CPCCR); ++ *cpccr = val; ++ val &= ~(0xff); ++ val |= 0x73; ++ val |= (1 << 22); ++ cpm_outl(val, CPM_CPCCR); ++ while((cpm_inl(CPM_CPCSR) & 1)) ++ serial_putc('U'); ++ } else if (status == RESTORE){ ++ val = *cpccr; ++ val |= (1 << 22); ++ cpm_outl(val, CPM_CPCCR); ++ while((cpm_inl(CPM_CPCSR) & 1)) ++ serial_putc('U'); ++ } ++} ++ ++#endif /* __CPUFREQ_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_core_sleep.dump.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_core_sleep.dump.patch new file mode 100644 index 00000000..e0c6a396 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_core_sleep.dump.patch @@ -0,0 +1,1048 @@ +diff -drupN a/tools/pm-sleep/core_sleep.dump b/tools/pm-sleep/core_sleep.dump +--- a/tools/pm-sleep/core_sleep.dump 1970-01-01 03:00:00.000000000 +0300 ++++ b/tools/pm-sleep/core_sleep.dump 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,1044 @@ ++ ++core_sleep: file format elf32-tradlittlemips ++ ++ ++Disassembly of section .text: ++ ++00000000 <_start>: ++ 0: 27bdfff4 addiu sp,sp,-12 ++ 4: afbc0000 sw gp,0(sp) ++ 8: afbf0004 sw ra,4(sp) ++ c: afb90008 sw t9,8(sp) ++ 10: 04110007 bal 30 ++ 14: 00000000 nop ++ 18: 00008bb0 tge zero,zero,0x22e ++ 1c: 00000c54 0xc54 ++ 20: 00000c1c 0xc1c ++ 24: 00000c1c 0xc1c ++ 28: 00000bc0 sll at,zero,0xf ++ 2c: 00000017 0x17 ++ 30: 8ffc0000 lw gp,0(ra) ++ 34: 0384e021 addu gp,gp,a0 ++ 38: 8feb0014 lw t3,20(ra) ++ 3c: 8fec0010 lw t4,16(ra) ++ 40: 008c6021 addu t4,a0,t4 ++ 44: 218c0008 addi t4,t4,8 ++ 48: 240a0002 li t2,2 ++ 4c: 8d890000 lw t1,0(t4) ++ 50: 01244821 addu t1,t1,a0 ++ 54: ad890000 sw t1,0(t4) ++ 58: 214a0001 addi t2,t2,1 ++ 5c: 014b082a slt at,t2,t3 ++ 60: 1420fffa bnez at,4c ++ 64: 218c0004 addi t4,t4,4 ++ 68: 8fea0004 lw t2,4(ra) ++ 6c: 8fe90008 lw t1,8(ra) ++ 70: 01445021 addu t2,t2,a0 ++ 74: 01244821 addu t1,t1,a0 ++ 78: 1000000a b a4 ++ 7c: 21290008 addi t1,t1,8 ++ 80: 8d2bfffc lw t3,-4(t1) ++ 84: 216bfffd addi t3,t3,-3 ++ 88: 15600006 bnez t3,a4 ++ 8c: 00000000 nop ++ 90: 8d2bfff8 lw t3,-8(t1) ++ 94: 01645821 addu t3,t3,a0 ++ 98: 8d6c0000 lw t4,0(t3) ++ 9c: 01846021 addu t4,t4,a0 ++ a0: ad6c0000 sw t4,0(t3) ++ a4: 012a082a slt at,t1,t2 ++ a8: 1420fff5 bnez at,80 ++ ac: 21290008 addi t1,t1,8 ++ b0: 8f898018 lw t1,-32744(gp) ++ b4: 8f8a8018 lw t2,-32744(gp) ++ b8: ad200000 sw zero,0(t1) ++ bc: 012a082a slt at,t1,t2 ++ c0: 1420fffd bnez at,b8 ++ c4: 21290004 addi t1,t1,4 ++ c8: 8f88801c lw t0,-32740(gp) ++ cc: ad050000 sw a1,0(t0) ++ d0: 00805825 move t3,a0 ++ d4: 8f888020 lw t0,-32736(gp) ++ d8: ad0b0000 sw t3,0(t0) ++ dc: 8f8a8024 lw t2,-32732(gp) ++ e0: ad6a0000 sw t2,0(t3) ++ e4: 256b0004 addiu t3,t3,4 ++ e8: 240affff li t2,-1 ++ ec: 21690040 addi t1,t3,64 ++ f0: ad6a0000 sw t2,0(t3) ++ f4: 256b0004 addiu t3,t3,4 ++ f8: 152bfffd bne t1,t3,f0 ++ fc: 00000000 nop ++ 100: 8fbc0000 lw gp,0(sp) ++ 104: 8fbf0004 lw ra,4(sp) ++ 108: 8fb90008 lw t9,8(sp) ++ 10c: 27bd000c addiu sp,sp,12 ++ 110: 03e00008 jr ra ++ 114: 00000000 nop ++ ... ++ ++00000218 : ++ 218: 04110001 bal 220 ++ 21c: 00000000 nop ++ 220: 27f90004 addiu t9,ra,4 ++ 224: 3c1c0001 lui gp,0x1 ++ 228: 279c898c addiu gp,gp,-30324 ++ 22c: 0399e021 addu gp,gp,t9 ++ 230: 27fdfffc addiu sp,ra,-4 ++ 234: 8f998028 lw t9,-32728(gp) ++ 238: 03200008 jr t9 ++ 23c: 00000000 nop ++ ++00000240 : ++ 240: 04110001 bal 248 ++ 244: 00000000 nop ++ 248: 27f90004 addiu t9,ra,4 ++ 24c: 3c1c0001 lui gp,0x1 ++ 250: 279c8964 addiu gp,gp,-30364 ++ 254: 0399e021 addu gp,gp,t9 ++ 258: 27fdfff0 addiu sp,ra,-16 ++ 25c: 8f99802c lw t9,-32724(gp) ++ 260: 03200008 jr t9 ++ 264: 00000000 nop ++ ++00000268 : ++ 268: 27bdfff0 addiu sp,sp,-16 ++ 26c: afbc0000 sw gp,0(sp) ++ 270: afbf0004 sw ra,4(sp) ++ 274: afb90008 sw t9,8(sp) ++ 278: 0080c825 move t9,a0 ++ 27c: 00a02025 move a0,a1 ++ 280: 0320f809 jalr t9 ++ 284: 00000000 nop ++ 288: 8fbc0000 lw gp,0(sp) ++ 28c: 8fbf0004 lw ra,4(sp) ++ 290: 8fb90008 lw t9,8(sp) ++ 294: 27bd0010 addiu sp,sp,16 ++ 298: 03e00008 jr ra ++ 29c: 00000000 nop ++ ++000002a0 <__jz_cache_init>: ++ 2a0: 4080e000 mtc0 zero,c0_taglo ++ 2a4: 3c028000 lui v0,0x8000 ++ 2a8: 24434000 addiu v1,v0,16384 ++ 2ac: bc490000 cache 0x9,0(v0) ++ 2b0: 24420020 addiu v0,v0,32 ++ 2b4: 1443fffd bne v0,v1,2ac <__jz_cache_init+0xc> ++ 2b8: 00000000 nop ++ 2bc: 3c028000 lui v0,0x8000 ++ 2c0: 24434000 addiu v1,v0,16384 ++ 2c4: bc480000 cache 0x8,0(v0) ++ 2c8: 24420020 addiu v0,v0,32 ++ 2cc: 1443fffd bne v0,v1,2c4 <__jz_cache_init+0x24> ++ 2d0: 00000000 nop ++ 2d4: 401a8007 mfc0 k0,$16,7 ++ 2d8: 00000000 nop ++ 2dc: 375a0002 ori k0,k0,0x2 ++ 2e0: 409a8007 mtc0 k0,$16,7 ++ 2e4: 00000000 nop ++ 2e8: 03e00008 jr ra ++ 2ec: 00000000 nop ++ ++000002f0 : ++ 2f0: 3c1c0001 lui gp,0x1 ++ 2f4: 279c88c0 addiu gp,gp,-30528 ++ 2f8: 0399e021 addu gp,gp,t9 ++ 2fc: 8c820000 lw v0,0(a0) ++ 300: 27bdffe0 addiu sp,sp,-32 ++ 304: 3c030040 lui v1,0x40 ++ 308: 00431025 or v0,v0,v1 ++ 30c: afbc0010 sw gp,16(sp) ++ 310: 3c03b000 lui v1,0xb000 ++ 314: afb00018 sw s0,24(sp) ++ 318: afbf001c sw ra,28(sp) ++ 31c: 3c10b000 lui s0,0xb000 ++ 320: ac620000 sw v0,0(v1) ++ 324: 8e0200d4 lw v0,212(s0) ++ 328: 30420001 andi v0,v0,0x1 ++ 32c: 10400005 beqz v0,344 ++ 330: 8f998030 lw t9,-32720(gp) ++ 334: 041101c5 bal a4c ++ 338: 24040055 li a0,85 ++ 33c: 1000fff9 b 324 ++ 340: 8fbc0010 lw gp,16(sp) ++ 344: 8fbf001c lw ra,28(sp) ++ 348: 8fb00018 lw s0,24(sp) ++ 34c: 03e00008 jr ra ++ 350: 27bd0020 addiu sp,sp,32 ++ ++00000354 : ++ 354: 3c028000 lui v0,0x8000 ++ 358: 24434000 addiu v1,v0,16384 ++ 35c: bc400000 cache 0x0,0(v0) ++ 360: bc410000 cache 0x1,0(v0) ++ 364: 24420020 addiu v0,v0,32 ++ 368: 1443fffc bne v0,v1,35c ++ 36c: 00000000 nop ++ 370: 0000000f sync ++ 374: 03e00008 jr ra ++ 378: 00000000 nop ++ ++0000037c : ++ 37c: 3c1c0001 lui gp,0x1 ++ 380: 279c8834 addiu gp,gp,-30668 ++ 384: 0399e021 addu gp,gp,t9 ++ 388: 8f998034 lw t9,-32716(gp) ++ 38c: 1000fff1 b 354 ++ 390: 00000000 nop ++ ++00000394 : ++ 394: 3c1c0001 lui gp,0x1 ++ 398: 279c881c addiu gp,gp,-30692 ++ 39c: 0399e021 addu gp,gp,t9 ++ 3a0: 27bdffe0 addiu sp,sp,-32 ++ 3a4: afbc0010 sw gp,16(sp) ++ 3a8: afbf001c sw ra,28(sp) ++ 3ac: afb00018 sw s0,24(sp) ++ 3b0: 14800013 bnez a0,400 ++ 3b4: 24020001 li v0,1 ++ 3b8: 3c04b000 lui a0,0xb000 ++ 3bc: 8c820000 lw v0,0(a0) ++ 3c0: 2403ff00 li v1,-256 ++ 3c4: 3c10b000 lui s0,0xb000 ++ 3c8: aca20000 sw v0,0(a1) ++ 3cc: 00431024 and v0,v0,v1 ++ 3d0: 3c030040 lui v1,0x40 ++ 3d4: 24630073 addiu v1,v1,115 ++ 3d8: 00431025 or v0,v0,v1 ++ 3dc: ac820000 sw v0,0(a0) ++ 3e0: 8e0200d4 lw v0,212(s0) ++ 3e4: 30420001 andi v0,v0,0x1 ++ 3e8: 1040000d beqz v0,420 ++ 3ec: 8f998030 lw t9,-32720(gp) ++ 3f0: 04110196 bal a4c ++ 3f4: 24040055 li a0,85 ++ 3f8: 1000fff9 b 3e0 ++ 3fc: 8fbc0010 lw gp,16(sp) ++ 400: 14820008 bne a0,v0,424 ++ 404: 8fbf001c lw ra,28(sp) ++ 408: 8f998038 lw t9,-32712(gp) ++ 40c: 8fb00018 lw s0,24(sp) ++ 410: 00a02025 move a0,a1 ++ 414: 273902f0 addiu t9,t9,752 ++ 418: 1000ffb5 b 2f0 ++ 41c: 27bd0020 addiu sp,sp,32 ++ 420: 8fbf001c lw ra,28(sp) ++ 424: 8fb00018 lw s0,24(sp) ++ 428: 03e00008 jr ra ++ 42c: 27bd0020 addiu sp,sp,32 ++ ++00000430 : ++ 430: 3c1c0001 lui gp,0x1 ++ 434: 279c8780 addiu gp,gp,-30848 ++ 438: 0399e021 addu gp,gp,t9 ++ 43c: 27bdffd8 addiu sp,sp,-40 ++ 440: afb1001c sw s1,28(sp) ++ 444: 8f918020 lw s1,-32736(gp) ++ 448: afbc0010 sw gp,16(sp) ++ 44c: afbf0024 sw ra,36(sp) ++ 450: 8e220000 lw v0,0(s1) ++ 454: afb20020 sw s2,32(sp) ++ 458: afb00018 sw s0,24(sp) ++ 45c: 8f99803c lw t9,-32708(gp) ++ 460: 0411016d bal a18 ++ 464: 9044000b lbu a0,11(v0) ++ 468: 8fbc0010 lw gp,16(sp) ++ 46c: 8f998034 lw t9,-32716(gp) ++ 470: 0411ffb8 bal 354 ++ 474: 00000000 nop ++ 478: 8fbc0010 lw gp,16(sp) ++ 47c: 3c02b000 lui v0,0xb000 ++ 480: 24030001 li v1,1 ++ 484: 8f928040 lw s2,-32704(gp) ++ 488: ac4300c8 sw v1,200(v0) ++ 48c: ac5200cc sw s2,204(v0) ++ 490: ac400008 sw zero,8(v0) ++ 494: 8e220000 lw v0,0(s1) ++ 498: 8c440014 lw a0,20(v0) ++ 49c: 2402ffff li v0,-1 ++ 4a0: 10820004 beq a0,v0,4b4 ++ 4a4: 8f998044 lw t9,-32700(gp) ++ 4a8: 0411ff6f bal 268 ++ 4ac: 00002825 move a1,zero ++ 4b0: 8fbc0010 lw gp,16(sp) ++ 4b4: 40028000 mfc0 v0,c0_config ++ 4b8: 8f848038 lw a0,-32712(gp) ++ 4bc: 24900c28 addiu s0,a0,3112 ++ 4c0: ae020010 sw v0,16(s0) ++ 4c4: 40026000 mfc0 v0,c0_status ++ 4c8: 3c03b301 lui v1,0xb301 ++ 4cc: ae020014 sw v0,20(s0) ++ 4d0: ac601054 sw zero,4180(v1) ++ 4d4: 3c02b34f lui v0,0xb34f ++ 4d8: 8c450304 lw a1,772(v0) ++ 4dc: ac850c28 sw a1,3112(a0) ++ 4e0: ac400304 sw zero,772(v0) ++ 4e4: 8c4400bc lw a0,188(v0) ++ 4e8: ae040004 sw a0,4(s0) ++ 4ec: 8c631004 lw v1,4100(v1) ++ 4f0: 7c630440 ext v1,v1,0x11,0x1 ++ 4f4: 14600002 bnez v1,500 ++ 4f8: 3403f003 li v1,0xf003 ++ 4fc: ac4300bc sw v1,188(v0) ++ 500: 3c04b34f lui a0,0xb34f ++ 504: 8c820008 lw v0,8(a0) ++ 508: 3c03ffff lui v1,0xffff ++ 50c: 246307ff addiu v1,v1,2047 ++ 510: ae020008 sw v0,8(s0) ++ 514: 8f858038 lw a1,-32712(gp) ++ 518: 00431024 and v0,v0,v1 ++ 51c: 3c030002 lui v1,0x2 ++ 520: 24630020 addiu v1,v1,32 ++ 524: 8f998048 lw t9,-32696(gp) ++ 528: 00431025 or v0,v0,v1 ++ 52c: ac820008 sw v0,8(a0) ++ 530: 24a50c34 addiu a1,a1,3124 ++ 534: 0411ff97 bal 394 ++ 538: 00002025 move a0,zero ++ 53c: 8fbc0010 lw gp,16(sp) ++ 540: 40026002 mfc0 v0,c0_srsctl ++ 544: 3c038000 lui v1,0x8000 ++ 548: ae020018 sw v0,24(s0) ++ 54c: 00431025 or v0,v0,v1 ++ 550: 40826002 mtc0 v0,c0_srsctl ++ 554: 8e220000 lw v0,0(s1) ++ 558: 240300ff li v1,255 ++ 55c: 9044000a lbu a0,10(v0) ++ 560: 1083000d beq a0,v1,598 ++ 564: 8f99804c lw t9,-32692(gp) ++ 568: 04110179 bal b50 ++ 56c: 90440009 lbu a0,9(v0) ++ 570: 8fbc0010 lw gp,16(sp) ++ 574: a202001c sb v0,28(s0) ++ 578: 8f828020 lw v0,-32736(gp) ++ 57c: 8f998050 lw t9,-32688(gp) ++ 580: 8c420000 lw v0,0(v0) ++ 584: 9045000a lbu a1,10(v0) ++ 588: 04110159 bal af0 ++ 58c: 90440009 lbu a0,9(v0) ++ 590: 10000003 b 5a0 ++ 594: 8fbc0010 lw gp,16(sp) ++ 598: 2402ffff li v0,-1 ++ 59c: a202001c sb v0,28(s0) ++ 5a0: 8e220000 lw v0,0(s1) ++ 5a4: 8c440018 lw a0,24(v0) ++ 5a8: 2402ffff li v0,-1 ++ 5ac: 10820004 beq a0,v0,5c0 ++ 5b0: 8f998044 lw t9,-32700(gp) ++ 5b4: 0411ff2c bal 268 ++ 5b8: 00002825 move a1,zero ++ 5bc: 8fbc0010 lw gp,16(sp) ++ 5c0: 8e020014 lw v0,20(s0) ++ 5c4: 34420400 ori v0,v0,0x400 ++ 5c8: 40826000 mtc0 v0,c0_status ++ 5cc: 8f998030 lw t9,-32720(gp) ++ 5d0: 0411011e bal a4c ++ 5d4: 24040065 li a0,101 ++ 5d8: 8fbc0010 lw gp,16(sp) ++ 5dc: 0000000f sync ++ 5e0: 00000000 nop ++ 5e4: 42000020 wait ++ ... ++ 5f0: 02400008 jr s2 ++ 5f4: 00000000 nop ++ 5f8: 8f998030 lw t9,-32720(gp) ++ 5fc: 04110113 bal a4c ++ 600: 24040045 li a0,69 ++ 604: 1000fffc b 5f8 ++ 608: 8fbc0010 lw gp,16(sp) ++ ++0000060c : ++ 60c: 3c1c0001 lui gp,0x1 ++ 610: 279c85a4 addiu gp,gp,-31324 ++ 614: 0399e021 addu gp,gp,t9 ++ 618: 8f998030 lw t9,-32720(gp) ++ 61c: 27bdffc0 addiu sp,sp,-64 ++ 620: afbc0010 sw gp,16(sp) ++ 624: afb30028 sw s3,40(sp) ++ 628: afb0001c sw s0,28(sp) ++ 62c: afbf003c sw ra,60(sp) ++ 630: afb70038 sw s7,56(sp) ++ 634: afb60034 sw s6,52(sp) ++ 638: afb50030 sw s5,48(sp) ++ 63c: afb4002c sw s4,44(sp) ++ 640: afb20024 sw s2,36(sp) ++ 644: afb10020 sw s1,32(sp) ++ 648: 04110100 bal a4c ++ 64c: 2404004f li a0,79 ++ 650: 8fbc0010 lw gp,16(sp) ++ 654: 8f938038 lw s3,-32712(gp) ++ 658: 26700c28 addiu s0,s3,3112 ++ 65c: 8e020010 lw v0,16(s0) ++ 660: 40828000 mtc0 v0,c0_config ++ 664: 8e020014 lw v0,20(s0) ++ 668: 40826000 mtc0 v0,c0_status ++ 66c: 8f918020 lw s1,-32736(gp) ++ 670: 8e220000 lw v0,0(s1) ++ 674: 8c43000c lw v1,12(v0) ++ 678: 2402ffff li v0,-1 ++ 67c: 1062000b beq v1,v0,6ac ++ 680: 8f998038 lw t9,-32712(gp) ++ 684: 273902a0 addiu t9,t9,672 ++ 688: 0411ff05 bal 2a0 <__jz_cache_init> ++ 68c: 00000000 nop ++ 690: 8fbc0010 lw gp,16(sp) ++ 694: 8e220000 lw v0,0(s1) ++ 698: 8e05000c lw a1,12(s0) ++ 69c: 8f998044 lw t9,-32700(gp) ++ 6a0: 0411fef1 bal 268 ++ 6a4: 8c44000c lw a0,12(v0) ++ 6a8: 8fbc0010 lw gp,16(sp) ++ 6ac: 8e220000 lw v0,0(s1) ++ 6b0: 90440009 lbu a0,9(v0) ++ 6b4: 240200ff li v0,255 ++ 6b8: 10820004 beq a0,v0,6cc ++ 6bc: 8f998050 lw t9,-32688(gp) ++ 6c0: 0411010b bal af0 ++ 6c4: 9205001c lbu a1,28(s0) ++ 6c8: 8fbc0010 lw gp,16(sp) ++ 6cc: 8f848038 lw a0,-32712(gp) ++ 6d0: 8f998038 lw t9,-32712(gp) ++ 6d4: 273902f0 addiu t9,t9,752 ++ 6d8: 0411ff05 bal 2f0 ++ 6dc: 24840c34 addiu a0,a0,3124 ++ 6e0: 3c02b301 lui v0,0xb301 ++ 6e4: 8c521004 lw s2,4100(v0) ++ 6e8: 3c020002 lui v0,0x2 ++ 6ec: 02429024 and s2,s2,v0 ++ 6f0: 16400060 bnez s2,874 ++ 6f4: 8fbc0010 lw gp,16(sp) ++ 6f8: 3c03b000 lui v1,0xb000 ++ 6fc: 8c6200d0 lw v0,208(v1) ++ 700: 34420002 ori v0,v0,0x2 ++ 704: ac6200d0 sw v0,208(v1) ++ 708: 24020200 li v0,512 ++ 70c: 2442ffff addiu v0,v0,-1 ++ 710: 10400004 beqz v0,724 ++ 714: 3c03b000 lui v1,0xb000 ++ 718: 00000000 nop ++ 71c: 1000fffc b 710 ++ 720: 2442ffff addiu v0,v0,-1 ++ 724: 8c6200d0 lw v0,208(v1) ++ 728: 2404fffd li a0,-3 ++ 72c: 00441024 and v0,v0,a0 ++ 730: ac6200d0 sw v0,208(v1) ++ 734: 24020200 li v0,512 ++ 738: 2442ffff addiu v0,v0,-1 ++ 73c: 10400004 beqz v0,750 ++ 740: 3c03b301 lui v1,0xb301 ++ 744: 00000000 nop ++ 748: 1000fffc b 73c ++ 74c: 2442ffff addiu v0,v0,-1 ++ 750: 8c62102c lw v0,4140(v1) ++ 754: 2404ffef li a0,-17 ++ 758: 00441024 and v0,v0,a0 ++ 75c: ac62102c sw v0,4140(v1) ++ 760: 24020010 li v0,16 ++ 764: 2442ffff addiu v0,v0,-1 ++ 768: 10400004 beqz v0,77c ++ 76c: 3c03b000 lui v1,0xb000 ++ 770: 00000000 nop ++ 774: 1000fffc b 768 ++ 778: 2442ffff addiu v0,v0,-1 ++ 77c: 8c6200d0 lw v0,208(v1) ++ 780: 34420002 ori v0,v0,0x2 ++ 784: ac6200d0 sw v0,208(v1) ++ 788: 24020200 li v0,512 ++ 78c: 2442ffff addiu v0,v0,-1 ++ 790: 10400004 beqz v0,7a4 ++ 794: 3c03b000 lui v1,0xb000 ++ 798: 00000000 nop ++ 79c: 1000fffc b 790 ++ 7a0: 2442ffff addiu v0,v0,-1 ++ 7a4: 8c6200d0 lw v0,208(v1) ++ 7a8: 2404fffd li a0,-3 ++ 7ac: 00441024 and v0,v0,a0 ++ 7b0: ac6200d0 sw v0,208(v1) ++ 7b4: 24020200 li v0,512 ++ 7b8: 2442ffff addiu v0,v0,-1 ++ 7bc: 10400004 beqz v0,7d0 ++ 7c0: 24030017 li v1,23 ++ 7c4: 00000000 nop ++ 7c8: 1000fffc b 7bc ++ 7cc: 2442ffff addiu v0,v0,-1 ++ 7d0: 3c02b301 lui v0,0xb301 ++ 7d4: 3c14b301 lui s4,0xb301 ++ 7d8: ac431004 sw v1,4100(v0) ++ 7dc: 2415000b li s5,11 ++ 7e0: 26971180 addiu s7,s4,4480 ++ 7e4: 8e82100c lw v0,4108(s4) ++ 7e8: 3042000b andi v0,v0,0xb ++ 7ec: 10550079 beq v0,s5,9d4 ++ 7f0: 2696100c addiu s6,s4,4108 ++ 7f4: 8e82100c lw v0,4108(s4) ++ 7f8: 30420060 andi v0,v0,0x60 ++ 7fc: 10400006 beqz v0,818 ++ 800: 8f998054 lw t9,-32684(gp) ++ 804: 8f998030 lw t9,-32720(gp) ++ 808: 04110090 bal a4c ++ 80c: 24040065 li a0,101 ++ 810: 10000070 b 9d4 ++ 814: 8fbc0010 lw gp,16(sp) ++ 818: 8ee40000 lw a0,0(s7) ++ 81c: 0411009a bal a88 ++ 820: 00000000 nop ++ 824: 8fbc0010 lw gp,16(sp) ++ 828: 8ec4017c lw a0,380(s6) ++ 82c: 8f998054 lw t9,-32684(gp) ++ 830: 04110095 bal a88 ++ 834: 00000000 nop ++ 838: 8fbc0010 lw gp,16(sp) ++ 83c: 8e84100c lw a0,4108(s4) ++ 840: 8f998054 lw t9,-32684(gp) ++ 844: 04110090 bal a88 ++ 848: 00000000 nop ++ 84c: 8fbc0010 lw gp,16(sp) ++ 850: 8f998030 lw t9,-32720(gp) ++ 854: 0411007d bal a4c ++ 858: 2404000d li a0,13 ++ 85c: 8fbc0010 lw gp,16(sp) ++ 860: 8f998030 lw t9,-32720(gp) ++ 864: 04110079 bal a4c ++ 868: 2404000a li a0,10 ++ 86c: 1000ffdd b 7e4 ++ 870: 8fbc0010 lw gp,16(sp) ++ 874: 3c05b34f lui a1,0xb34f ++ 878: 8ca40008 lw a0,8(a1) ++ 87c: 3c03fffd lui v1,0xfffd ++ 880: 3463ffdf ori v1,v1,0xffdf ++ 884: 00831824 and v1,a0,v1 ++ 888: 34630002 ori v1,v1,0x2 ++ 88c: aca30008 sw v1,8(a1) ++ 890: 24420081 addiu v0,v0,129 ++ 894: 3c03b301 lui v1,0xb301 ++ 898: ac621004 sw v0,4100(v1) ++ 89c: 3c14b301 lui s4,0xb301 ++ 8a0: 2415001b li s5,27 ++ 8a4: 8e82100c lw v0,4108(s4) ++ 8a8: 3042001b andi v0,v0,0x1b ++ 8ac: 10550017 beq v0,s5,90c ++ 8b0: 00000000 nop ++ 8b4: 8e82100c lw v0,4108(s4) ++ 8b8: 30420060 andi v0,v0,0x60 ++ 8bc: 10400006 beqz v0,8d8 ++ 8c0: 8f998054 lw t9,-32684(gp) ++ 8c4: 8f998030 lw t9,-32720(gp) ++ 8c8: 04110060 bal a4c ++ 8cc: 24040065 li a0,101 ++ 8d0: 1000000e b 90c ++ 8d4: 8fbc0010 lw gp,16(sp) ++ 8d8: 8e84100c lw a0,4108(s4) ++ 8dc: 0411006a bal a88 ++ 8e0: 00000000 nop ++ 8e4: 8fbc0010 lw gp,16(sp) ++ 8e8: 8f998030 lw t9,-32720(gp) ++ 8ec: 04110057 bal a4c ++ 8f0: 2404000d li a0,13 ++ 8f4: 8fbc0010 lw gp,16(sp) ++ 8f8: 8f998030 lw t9,-32720(gp) ++ 8fc: 04110053 bal a4c ++ 900: 2404000a li a0,10 ++ 904: 1000ffe7 b 8a4 ++ 908: 8fbc0010 lw gp,16(sp) ++ 90c: 12400006 beqz s2,928 ++ 910: 3c03b301 lui v1,0xb301 ++ 914: 8e020004 lw v0,4(s0) ++ 918: 1040000d beqz v0,950 ++ 91c: 8e620c28 lw v0,3112(s3) ++ 920: 10000010 b 964 ++ 924: 00000000 nop ++ 928: 8c62102c lw v0,4140(v1) ++ 92c: 34420010 ori v0,v0,0x10 ++ 930: ac62102c sw v0,4140(v1) ++ 934: 24020010 li v0,16 ++ 938: 2442ffff addiu v0,v0,-1 ++ 93c: 1040fff5 beqz v0,914 ++ 940: 00000000 nop ++ 944: 00000000 nop ++ 948: 1000fffc b 93c ++ 94c: 2442ffff addiu v0,v0,-1 ++ 950: 16400004 bnez s2,964 ++ 954: 00000000 nop ++ 958: 3c02b34f lui v0,0xb34f ++ 95c: ac4000bc sw zero,188(v0) ++ 960: 8e620c28 lw v0,3112(s3) ++ 964: 10400003 beqz v0,974 ++ 968: 24030001 li v1,1 ++ 96c: 3c02b34f lui v0,0xb34f ++ 970: ac430304 sw v1,772(v0) ++ 974: 8e030008 lw v1,8(s0) ++ 978: 8f998038 lw t9,-32712(gp) ++ 97c: 3c02b34f lui v0,0xb34f ++ 980: ac430008 sw v1,8(v0) ++ 984: 273902a0 addiu t9,t9,672 ++ 988: 0411fe45 bal 2a0 <__jz_cache_init> ++ 98c: 00000000 nop ++ 990: 8fbc0010 lw gp,16(sp) ++ 994: 8e020018 lw v0,24(s0) ++ 998: 40826002 mtc0 v0,c0_srsctl ++ 99c: 8e220000 lw v0,0(s1) ++ 9a0: 8c440010 lw a0,16(v0) ++ 9a4: 3c020fff lui v0,0xfff ++ 9a8: 3442ffff ori v0,v0,0xffff ++ 9ac: 10820004 beq a0,v0,9c0 ++ 9b0: 8f998044 lw t9,-32700(gp) ++ 9b4: 0411fe2c bal 268 ++ 9b8: 00002825 move a1,zero ++ 9bc: 8fbc0010 lw gp,16(sp) ++ 9c0: 8f998030 lw t9,-32720(gp) ++ 9c4: 04110021 bal a4c ++ 9c8: 24040073 li a0,115 ++ 9cc: 1000fffc b 9c0 ++ 9d0: 8fbc0010 lw gp,16(sp) ++ 9d4: 3c04b34f lui a0,0xb34f ++ 9d8: 8c830008 lw v1,8(a0) ++ 9dc: 3c02fffd lui v0,0xfffd ++ 9e0: 3442ffdf ori v0,v0,0xffdf ++ 9e4: 00621024 and v0,v1,v0 ++ 9e8: 34420002 ori v0,v0,0x2 ++ 9ec: ac820008 sw v0,8(a0) ++ 9f0: 1000ffa8 b 894 ++ 9f4: 24020081 li v0,129 ++ ... ++ ++00000a00 : ++ a00: 00000000 nop ++ a04: 2484ffac addiu a0,a0,-84 ++ a08: 1c80fffd bgtz a0,a00 ++ a0c: 00000000 nop ++ a10: 03e00008 jr ra ++ a14: 00000000 nop ++ ++00000a18 : ++ a18: 3c1c0001 lui gp,0x1 ++ a1c: 279c8198 addiu gp,gp,-32360 ++ a20: 0399e021 addu gp,gp,t9 ++ a24: 240300ff li v1,255 ++ a28: 10830006 beq a0,v1,a44 ++ a2c: 8f828038 lw v0,-32712(gp) ++ a30: 3c03b003 lui v1,0xb003 ++ a34: 00042300 sll a0,a0,0xc ++ a38: 00832021 addu a0,a0,v1 ++ a3c: 03e00008 jr ra ++ a40: ac440c50 sw a0,3152(v0) ++ a44: 03e00008 jr ra ++ a48: ac400c50 sw zero,3152(v0) ++ ++00000a4c : ++ a4c: 3c1c0001 lui gp,0x1 ++ a50: 279c8164 addiu gp,gp,-32412 ++ a54: 0399e021 addu gp,gp,t9 ++ a58: 8f828038 lw v0,-32712(gp) ++ a5c: 8c430c50 lw v1,3152(v0) ++ a60: 10600007 beqz v1,a80 ++ a64: 7c042420 seb a0,a0 ++ a68: ac640000 sw a0,0(v1) ++ a6c: 24040060 li a0,96 ++ a70: 8c620014 lw v0,20(v1) ++ a74: 30420060 andi v0,v0,0x60 ++ a78: 1444fffd bne v0,a0,a70 ++ a7c: 00000000 nop ++ a80: 03e00008 jr ra ++ a84: 00000000 nop ++ ++00000a88 : ++ a88: 3c1c0001 lui gp,0x1 ++ a8c: 279c8128 addiu gp,gp,-32472 ++ a90: 0399e021 addu gp,gp,t9 ++ a94: 8f998030 lw t9,-32720(gp) ++ a98: 27bdffe0 addiu sp,sp,-32 ++ a9c: 00803825 move a3,a0 ++ aa0: 2405001c li a1,28 ++ aa4: afbc0010 sw gp,16(sp) ++ aa8: afbf001c sw ra,28(sp) ++ aac: 2406fffc li a2,-4 ++ ab0: 00a71006 srlv v0,a3,a1 ++ ab4: 3042000f andi v0,v0,0xf ++ ab8: 2c44000a sltiu a0,v0,10 ++ abc: 24430030 addiu v1,v0,48 ++ ac0: 24420037 addiu v0,v0,55 ++ ac4: 0044180a movz v1,v0,a0 ++ ac8: 0411ffe0 bal a4c ++ acc: 00602025 move a0,v1 ++ ad0: 24a5fffc addiu a1,a1,-4 ++ ad4: 14a6fff7 bne a1,a2,ab4 ++ ad8: 00a71006 srlv v0,a3,a1 ++ adc: 8fbf001c lw ra,28(sp) ++ ae0: 03e00008 jr ra ++ ae4: 27bd0020 addiu sp,sp,32 ++ ... ++ ++00000af0 : ++ af0: 3088001f andi t0,a0,0x1f ++ af4: 24030001 li v1,1 ++ af8: 00042143 sra a0,a0,0x5 ++ afc: 3c02b001 lui v0,0xb001 ++ b00: 00042200 sll a0,a0,0x8 ++ b04: 01031804 sllv v1,v1,t0 ++ b08: 24420010 addiu v0,v0,16 ++ b0c: 00031827 nor v1,zero,v1 ++ b10: 00822021 addu a0,a0,v0 ++ b14: 24060003 li a2,3 ++ b18: 2409ffff li t1,-1 ++ b1c: 8c820000 lw v0,0(a0) ++ b20: 24840010 addiu a0,a0,16 ++ b24: 00433824 and a3,v0,v1 ++ b28: 00c51007 srav v0,a1,a2 ++ b2c: 30420001 andi v0,v0,0x1 ++ b30: 01021004 sllv v0,v0,t0 ++ b34: 00471025 or v0,v0,a3 ++ b38: 24c6ffff addiu a2,a2,-1 ++ b3c: ac82fff0 sw v0,-16(a0) ++ b40: 14c9fff6 bne a2,t1,b1c ++ b44: 00000000 nop ++ b48: 03e00008 jr ra ++ b4c: 00000000 nop ++ ++00000b50 : ++ b50: 3087001f andi a3,a0,0x1f ++ b54: 3c02b001 lui v0,0xb001 ++ b58: 00042143 sra a0,a0,0x5 ++ b5c: 24420010 addiu v0,v0,16 ++ b60: 00042200 sll a0,a0,0x8 ++ b64: 00822021 addu a0,a0,v0 ++ b68: 24050003 li a1,3 ++ b6c: 00001025 move v0,zero ++ b70: 2406ffff li a2,-1 ++ b74: 8c830000 lw v1,0(a0) ++ b78: 24840010 addiu a0,a0,16 ++ b7c: 00e31806 srlv v1,v1,a3 ++ b80: 30630001 andi v1,v1,0x1 ++ b84: 00a31804 sllv v1,v1,a1 ++ b88: 24a5ffff addiu a1,a1,-1 ++ b8c: 14a6fff9 bne a1,a2,b74 ++ b90: 00621025 or v0,v1,v0 ++ b94: 03e00008 jr ra ++ b98: 00000000 nop ++ b9c: 00000000 nop ++ ++Disassembly of section .MIPS.abiflags: ++ ++00000ba0 <.MIPS.abiflags>: ++ ba0: 02200000 0x2200000 ++ ba4: 01000101 0x1000101 ++ ... ++ bb0: 00000001 movf zero,zero,$fcc0 ++ bb4: 00000000 nop ++ ++Disassembly of section .rld_map: ++ ++00000bb8 <__RLD_MAP>: ++ bb8: 00000000 nop ++ ++Disassembly of section .got: ++ ++00000bc0 <.got>: ++ bc0: 00000000 nop ++ bc4: 80000000 lb zero,0(zero) ++ bc8: 00000c1c 0xc1c ++ bcc: 00000c24 0xc24 ++ bd0: 00000c20 0xc20 ++ bd4: 00000218 0x218 ++ bd8: 00000430 tge zero,zero,0x10 ++ bdc: 0000060c syscall 0x18 ++ be0: 00000a4c syscall 0x29 ++ be4: 00000354 0x354 ++ be8: 00000000 nop ++ bec: 00000a18 0xa18 ++ bf0: 00000240 sll zero,zero,0x9 ++ bf4: 00000268 0x268 ++ bf8: 00000394 0x394 ++ bfc: 00000b50 0xb50 ++ c00: 00000af0 tge zero,zero,0x2b ++ c04: 00000a88 0xa88 ++ ... ++ ++Disassembly of section .dynsym: ++ ++00000c58 <.dynsym>: ++ ... ++ c74: 00010003 sra zero,at,0x0 ++ c78: 000000ad 0xad ++ c7c: 00000c1c 0xc1c ++ c80: 00000000 nop ++ c84: 00050010 0x50010 ++ c88: 00000001 movf zero,zero,$fcc0 ++ c8c: 00000001 movf zero,zero,$fcc0 ++ c90: 00000000 nop ++ c94: fff10013 sdc3 $17,19(ra) ++ c98: 00000081 0x81 ++ c9c: 00000017 0x17 ++ ca0: 00000000 nop ++ ca4: fff10010 sdc3 $17,16(ra) ++ ca8: 0000003e 0x3e ++ cac: 00000c20 0xc20 ++ cb0: 00000004 sllv zero,zero,zero ++ cb4: 00070211 0x70211 ++ cb8: 00000059 0x59 ++ cbc: 00000240 sll zero,zero,0x9 ++ cc0: 00000028 0x28 ++ cc4: 00010012 0x10012 ++ cc8: 0000004a 0x4a ++ ccc: 00000218 0x218 ++ cd0: 00000028 0x28 ++ cd4: 00010012 0x10012 ++ cd8: 0000007d 0x7d ++ cdc: 00008bb0 tge zero,zero,0x22e ++ ce0: 00000000 nop ++ ce4: fff10010 sdc3 $17,16(ra) ++ ce8: 00000091 0x91 ++ cec: 00000c1c 0xc1c ++ cf0: 00000000 nop ++ cf4: 00050010 0x50010 ++ cf8: 00000028 0x28 ++ cfc: 00000c1c 0xc1c ++ d00: 00000000 nop ++ d04: 00070010 0x70010 ++ d08: 00000075 0x75 ++ ... ++ d14: 00010010 0x10010 ++ d18: 00000012 mflo zero ++ d1c: 00000bb8 0xbb8 ++ d20: 00000000 nop ++ d24: 00030011 0x30011 ++ d28: 000000a2 0xa2 ++ d2c: 00000c1c 0xc1c ++ d30: 00000000 nop ++ d34: 00050010 0x50010 ++ d38: 00000032 tlt zero,zero ++ d3c: 00000c24 0xc24 ++ d40: 00000004 sllv zero,zero,zero ++ d44: 00070211 0x70211 ++ d48: 0000001c 0x1c ++ d4c: 00000c1c 0xc1c ++ d50: 00000000 nop ++ d54: 00070010 0x70010 ++ d58: 00000067 0x67 ++ d5c: 00000268 0x268 ++ d60: 00000038 0x38 ++ d64: 00010012 0x10012 ++ d68: 000000c6 0xc6 ++ d6c: 00000c58 0xc58 ++ d70: 00000000 nop ++ d74: 00060010 0x60010 ++ d78: 000000bd 0xbd ++ d7c: 00000c54 0xc54 ++ d80: 00000000 nop ++ d84: 00050010 0x50010 ++ ++Disassembly of section .rel.dyn: ++ ++00000c1c <__image_copy_end>: ++ ... ++ c24: 00000018 mult zero,zero ++ c28: 00000003 sra zero,zero,0x0 ++ c2c: 0000001c 0x1c ++ c30: 00000003 sra zero,zero,0x0 ++ c34: 00000020 add zero,zero,zero ++ c38: 00000003 sra zero,zero,0x0 ++ c3c: 00000024 and zero,zero,zero ++ c40: 00000003 sra zero,zero,0x0 ++ c44: 00000028 0x28 ++ c48: 00000003 sra zero,zero,0x0 ++ c4c: 0000002c 0x2c ++ c50: 00000003 sra zero,zero,0x0 ++ ++Disassembly of section .deadcode: ++ ++00000c54 <_end-0x4>: ++ c54: ffffffff sdc3 $31,-1(ra) ++ ++Disassembly of section .bss: ++ ++00000c1c <__bss_end>: ++ c1c: 00000000 nop ++ ++00000c20 : ++ c20: 00000000 nop ++ ++00000c24 : ++ c24: 00000000 nop ++ ++00000c28 : ++ ... ++ ++00000c50 : ++ ... ++ ++Disassembly of section .dynstr: ++ ++00000d88 <.dynstr>: ++ d88: 59445f00 0x59445f00 ++ d8c: 494d414e 0x494d414e ++ d90: 494c5f43 0x494c5f43 ++ d94: 4e494b4e c3 0x494b4e ++ d98: 5f5f0047 0x5f5f0047 ++ d9c: 5f444c52 0x5f444c52 ++ da0: 0050414d break 0x50,0x105 ++ da4: 73625f5f udi15 k1,v0,t3,0x1d ++ da8: 74735f73 jalx 1cd7dcc <_gp+0x1ccf21c> ++ dac: 00747261 0x747261 ++ db0: 73625f5f udi15 k1,v0,t3,0x1d ++ db4: 6e655f73 0x6e655f73 ++ db8: 78650064 st.b $w1,101(zero) ++ dbc: 6e726574 0x6e726574 ++ dc0: 6e75665f 0x6e75665f ++ dc4: 5f700063 0x5f700063 ++ dc8: 5f706c73 0x5f706c73 ++ dcc: 61726170 0x61726170 ++ dd0: 6c73006d 0x6c73006d ++ dd4: 5f706565 0x5f706565 ++ dd8: 655f6d70 0x655f6d70 ++ ddc: 7265746e 0x7265746e ++ de0: 656c7300 0x656c7300 ++ de4: 705f7065 0x705f7065 ++ de8: 78655f6d 0x78655f6d ++ dec: 63007469 0x63007469 ++ df0: 5f6c6c61 0x5f6c6c61 ++ df4: 636e7566 0x636e7566 ++ df8: 6e6f6974 0x6e6f6974 ++ dfc: 735f5f00 0x735f5f00 ++ e00: 74726174 jalx 1c985d0 <_gp+0x1c8fa20> ++ e04: 70675f00 0x70675f00 ++ e08: 6d756e00 0x6d756e00 ++ e0c: 746f675f jalx 1bd9d7c <_gp+0x1bd11cc> ++ e10: 746e655f jalx 1b9957c <_gp+0x1b909cc> ++ e14: 73656972 0x73656972 ++ e18: 695f5f00 0x695f5f00 ++ e1c: 6567616d 0x6567616d ++ e20: 706f635f udi15 v1,t7,t4,0xd ++ e24: 6e655f79 0x6e655f79 ++ e28: 5f5f0064 0x5f5f0064 ++ e2c: 74696e69 jalx 1a5b9a4 <_gp+0x1a52df4> ++ e30: 646e655f 0x646e655f ++ e34: 725f5f00 0x725f5f00 ++ e38: 645f6c65 0x645f6c65 ++ e3c: 735f6e79 0x735f6e79 ++ e40: 74726174 jalx 1c985d0 <_gp+0x1c8fa20> ++ e44: 725f5f00 0x725f5f00 ++ e48: 645f6c65 0x645f6c65 ++ e4c: 655f6e79 0x655f6e79 ++ e50: Address 0x0000000000000e50 is out of bounds. ++ ++ ++Disassembly of section .dynamic: ++ ++00000e54 <.dynamic>: ++ e54: 00000004 sllv zero,zero,zero ++ e58: 00000f70 tge zero,zero,0x3d ++ e5c: 00000005 lsa zero,zero,zero,0x1 ++ e60: 00000d88 0xd88 ++ e64: 00000006 srlv zero,zero,zero ++ e68: 00000c58 0xc58 ++ e6c: 0000000a movz zero,zero,zero ++ e70: 000000cb 0xcb ++ e74: 0000000b movn zero,zero,zero ++ e78: 00000010 mfhi zero ++ e7c: 70000035 0x70000035 ++ e80: fffffd3c sdc3 $31,-708(ra) ++ e84: 00000015 0x15 ++ e88: 00000000 nop ++ e8c: 00000016 0x16 ++ e90: 00000000 nop ++ e94: 00000003 sra zero,zero,0x0 ++ e98: 00000bc0 sll at,zero,0xf ++ e9c: 00000011 mthi zero ++ ea0: 00000c1c 0xc1c ++ ea4: 00000012 mflo zero ++ ea8: 00000038 0x38 ++ eac: 00000013 mtlo zero ++ eb0: 00000008 jr zero ++ eb4: 70000001 maddu zero,zero ++ eb8: 00000001 movf zero,zero,$fcc0 ++ ebc: 70000005 msubu zero,zero ++ ec0: 00000002 srl zero,zero,0x0 ++ ec4: 70000006 0x70000006 ++ ec8: 00000000 nop ++ ecc: 7000000a 0x7000000a ++ ed0: 00000017 0x17 ++ ed4: 70000011 udi1 zero,zero,zero,0x0 ++ ed8: 00000013 mtlo zero ++ edc: 70000012 udi2 zero,zero,zero,0x0 ++ ee0: 0000000f sync ++ ee4: 70000013 udi3 zero,zero,zero,0x0 ++ ee8: 00000013 mtlo zero ++ ... ++ ++Disassembly of section .interp: ++ ++00000f1c <.interp>: ++ f1c: 7273752f 0x7273752f ++ f20: 62696c2f 0x62696c2f ++ f24: 62696c2f 0x62696c2f ++ f28: 6f732e63 0x6f732e63 ++ f2c: Address 0x0000000000000f2c is out of bounds. ++ ++ ++Disassembly of section .gnu: ++ ++00000f30 <.gnu>: ++ f30: 00000f41 0xf41 ++ f34: 756e6700 jalx 5b99c00 <_gp+0x5b91050> ++ f38: 00070100 sll zero,a3,0x4 ++ f3c: 01040000 0x1040000 ++ f40: 00000f41 0xf41 ++ f44: 756e6700 jalx 5b99c00 <_gp+0x5b91050> ++ f48: 00070100 sll zero,a3,0x4 ++ f4c: 01040000 0x1040000 ++ f50: 00000f41 0xf41 ++ f54: 756e6700 jalx 5b99c00 <_gp+0x5b91050> ++ f58: 00070100 sll zero,a3,0x4 ++ f5c: 01040000 0x1040000 ++ f60: 00000f41 0xf41 ++ f64: 756e6700 jalx 5b99c00 <_gp+0x5b91050> ++ f68: 00070100 sll zero,a3,0x4 ++ f6c: 01040000 0x1040000 ++ ++Disassembly of section .hash: ++ ++00000f70 <.hash>: ++ f70: 00000011 mthi zero ++ f74: 00000013 mtlo zero ++ f78: 00000000 nop ++ f7c: 0000000d break ++ f80: 00000009 jalr zero,zero ++ f84: 00000010 mfhi zero ++ f88: 00000007 srav zero,zero,zero ++ f8c: 00000004 sllv zero,zero,zero ++ f90: 0000000a movz zero,zero,zero ++ f94: 0000000e 0xe ++ f98: 00000002 srl zero,zero,0x0 ++ ... ++ fa4: 0000000f sync ++ fa8: 00000000 nop ++ fac: 00000011 mthi zero ++ fb0: 00000012 mflo zero ++ ... ++ fcc: 00000003 sra zero,zero,0x0 ++ ... ++ fd8: 00000006 srlv zero,zero,zero ++ fdc: 00000005 lsa zero,zero,zero,0x1 ++ fe0: 00000008 jr zero ++ fe4: 00000000 nop ++ fe8: 00000000 nop ++ fec: 0000000b movn zero,zero,zero ++ ... ++ 1000: 0000000c syscall ++ 1004: 00000000 nop ++ ++Disassembly of section .comment: ++ ++00000000 <.comment>: ++ 0: 3a434347 xori v1,s2,0x4347 ++ 4: 6e492820 0x6e492820 ++ 8: 696e6567 0x696e6567 ++ c: 33722063 andi s2,k1,0x2063 ++ 10: 312e312e andi t6,t1,0x312e ++ 14: 6363672d 0x6363672d ++ 18: 20303235 addi s0,at,12853 ++ 1c: 37313032 ori s1,t9,0x3032 ++ 20: 2d33302e sltiu s3,t1,12334 ++ 24: 20293331 addi t1,at,13105 ++ 28: 2e322e35 sltiu s2,s1,11829 ++ 2c: Address 0x000000000000002c is out of bounds. ++ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_core_sleep.hex.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_core_sleep.hex.patch new file mode 100644 index 00000000..9a734169 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_core_sleep.hex.patch @@ -0,0 +1,1030 @@ +diff -drupN a/tools/pm-sleep/core_sleep.hex b/tools/pm-sleep/core_sleep.hex +--- a/tools/pm-sleep/core_sleep.hex 1970-01-01 03:00:00.000000000 +0300 ++++ b/tools/pm-sleep/core_sleep.hex 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,1026 @@ ++0x27bdfff4, ++0xafbc0000, ++0xafbf0004, ++0xafb90008, ++0x04110007, ++0x00000000, ++0x00008bb0, ++0x00000c54, ++0x00000c1c, ++0x00000c1c, ++0x00000bc0, ++0x00000017, ++0x8ffc0000, ++0x0384e021, ++0x8feb0014, ++0x8fec0010, ++0x008c6021, ++0x218c0008, ++0x240a0002, ++0x8d890000, ++0x01244821, ++0xad890000, ++0x214a0001, ++0x014b082a, ++0x1420fffa, ++0x218c0004, ++0x8fea0004, ++0x8fe90008, ++0x01445021, ++0x01244821, ++0x1000000a, ++0x21290008, ++0x8d2bfffc, ++0x216bfffd, ++0x15600006, ++0x00000000, ++0x8d2bfff8, ++0x01645821, ++0x8d6c0000, ++0x01846021, ++0xad6c0000, ++0x012a082a, ++0x1420fff5, ++0x21290008, ++0x8f898018, ++0x8f8a8018, ++0xad200000, ++0x012a082a, ++0x1420fffd, ++0x21290004, ++0x8f88801c, ++0xad050000, ++0x00805825, ++0x8f888020, ++0xad0b0000, ++0x8f8a8024, ++0xad6a0000, ++0x256b0004, ++0x240affff, ++0x21690040, ++0xad6a0000, ++0x256b0004, ++0x152bfffd, ++0x00000000, ++0x8fbc0000, ++0x8fbf0004, ++0x8fb90008, ++0x27bd000c, ++0x03e00008, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x04110001, ++0x00000000, ++0x27f90004, ++0x3c1c0001, ++0x279c898c, ++0x0399e021, ++0x27fdfffc, ++0x8f998028, ++0x03200008, ++0x00000000, ++0x04110001, ++0x00000000, ++0x27f90004, ++0x3c1c0001, ++0x279c8964, ++0x0399e021, ++0x27fdfff0, ++0x8f99802c, ++0x03200008, ++0x00000000, ++0x27bdfff0, ++0xafbc0000, ++0xafbf0004, ++0xafb90008, ++0x0080c825, ++0x00a02025, ++0x0320f809, ++0x00000000, ++0x8fbc0000, ++0x8fbf0004, ++0x8fb90008, ++0x27bd0010, ++0x03e00008, ++0x00000000, ++0x4080e000, ++0x3c028000, ++0x24434000, ++0xbc490000, ++0x24420020, ++0x1443fffd, ++0x00000000, ++0x3c028000, ++0x24434000, ++0xbc480000, ++0x24420020, ++0x1443fffd, ++0x00000000, ++0x401a8007, ++0x00000000, ++0x375a0002, ++0x409a8007, ++0x00000000, ++0x03e00008, ++0x00000000, ++0x3c1c0001, ++0x279c88c0, ++0x0399e021, ++0x8c820000, ++0x27bdffe0, ++0x3c030040, ++0x00431025, ++0xafbc0010, ++0x3c03b000, ++0xafb00018, ++0xafbf001c, ++0x3c10b000, ++0xac620000, ++0x8e0200d4, ++0x30420001, ++0x10400005, ++0x8f998030, ++0x041101c5, ++0x24040055, ++0x1000fff9, ++0x8fbc0010, ++0x8fbf001c, ++0x8fb00018, ++0x03e00008, ++0x27bd0020, ++0x3c028000, ++0x24434000, ++0xbc400000, ++0xbc410000, ++0x24420020, ++0x1443fffc, ++0x00000000, ++0x0000000f, ++0x03e00008, ++0x00000000, ++0x3c1c0001, ++0x279c8834, ++0x0399e021, ++0x8f998034, ++0x1000fff1, ++0x00000000, ++0x3c1c0001, ++0x279c881c, ++0x0399e021, ++0x27bdffe0, ++0xafbc0010, ++0xafbf001c, ++0xafb00018, ++0x14800013, ++0x24020001, ++0x3c04b000, ++0x8c820000, ++0x2403ff00, ++0x3c10b000, ++0xaca20000, ++0x00431024, ++0x3c030040, ++0x24630073, ++0x00431025, ++0xac820000, ++0x8e0200d4, ++0x30420001, ++0x1040000d, ++0x8f998030, ++0x04110196, ++0x24040055, ++0x1000fff9, ++0x8fbc0010, ++0x14820008, ++0x8fbf001c, ++0x8f998038, ++0x8fb00018, ++0x00a02025, ++0x273902f0, ++0x1000ffb5, ++0x27bd0020, ++0x8fbf001c, ++0x8fb00018, ++0x03e00008, ++0x27bd0020, ++0x3c1c0001, ++0x279c8780, ++0x0399e021, ++0x27bdffd8, ++0xafb1001c, ++0x8f918020, ++0xafbc0010, ++0xafbf0024, ++0x8e220000, ++0xafb20020, ++0xafb00018, ++0x8f99803c, ++0x0411016d, ++0x9044000b, ++0x8fbc0010, ++0x8f998034, ++0x0411ffb8, ++0x00000000, ++0x8fbc0010, ++0x3c02b000, ++0x24030001, ++0x8f928040, ++0xac4300c8, ++0xac5200cc, ++0xac400008, ++0x8e220000, ++0x8c440014, ++0x2402ffff, ++0x10820004, ++0x8f998044, ++0x0411ff6f, ++0x00002825, ++0x8fbc0010, ++0x40028000, ++0x8f848038, ++0x24900c28, ++0xae020010, ++0x40026000, ++0x3c03b301, ++0xae020014, ++0xac601054, ++0x3c02b34f, ++0x8c450304, ++0xac850c28, ++0xac400304, ++0x8c4400bc, ++0xae040004, ++0x8c631004, ++0x7c630440, ++0x14600002, ++0x3403f003, ++0xac4300bc, ++0x3c04b34f, ++0x8c820008, ++0x3c03ffff, ++0x246307ff, ++0xae020008, ++0x8f858038, ++0x00431024, ++0x3c030002, ++0x24630020, ++0x8f998048, ++0x00431025, ++0xac820008, ++0x24a50c34, ++0x0411ff97, ++0x00002025, ++0x8fbc0010, ++0x40026002, ++0x3c038000, ++0xae020018, ++0x00431025, ++0x40826002, ++0x8e220000, ++0x240300ff, ++0x9044000a, ++0x1083000d, ++0x8f99804c, ++0x04110179, ++0x90440009, ++0x8fbc0010, ++0xa202001c, ++0x8f828020, ++0x8f998050, ++0x8c420000, ++0x9045000a, ++0x04110159, ++0x90440009, ++0x10000003, ++0x8fbc0010, ++0x2402ffff, ++0xa202001c, ++0x8e220000, ++0x8c440018, ++0x2402ffff, ++0x10820004, ++0x8f998044, ++0x0411ff2c, ++0x00002825, ++0x8fbc0010, ++0x8e020014, ++0x34420400, ++0x40826000, ++0x8f998030, ++0x0411011e, ++0x24040065, ++0x8fbc0010, ++0x0000000f, ++0x00000000, ++0x42000020, ++0x00000000, ++0x00000000, ++0x02400008, ++0x00000000, ++0x8f998030, ++0x04110113, ++0x24040045, ++0x1000fffc, ++0x8fbc0010, ++0x3c1c0001, ++0x279c85a4, ++0x0399e021, ++0x8f998030, ++0x27bdffc0, ++0xafbc0010, ++0xafb30028, ++0xafb0001c, ++0xafbf003c, ++0xafb70038, ++0xafb60034, ++0xafb50030, ++0xafb4002c, ++0xafb20024, ++0xafb10020, ++0x04110100, ++0x2404004f, ++0x8fbc0010, ++0x8f938038, ++0x26700c28, ++0x8e020010, ++0x40828000, ++0x8e020014, ++0x40826000, ++0x8f918020, ++0x8e220000, ++0x8c43000c, ++0x2402ffff, ++0x1062000b, ++0x8f998038, ++0x273902a0, ++0x0411ff05, ++0x00000000, ++0x8fbc0010, ++0x8e220000, ++0x8e05000c, ++0x8f998044, ++0x0411fef1, ++0x8c44000c, ++0x8fbc0010, ++0x8e220000, ++0x90440009, ++0x240200ff, ++0x10820004, ++0x8f998050, ++0x0411010b, ++0x9205001c, ++0x8fbc0010, ++0x8f848038, ++0x8f998038, ++0x273902f0, ++0x0411ff05, ++0x24840c34, ++0x3c02b301, ++0x8c521004, ++0x3c020002, ++0x02429024, ++0x16400060, ++0x8fbc0010, ++0x3c03b000, ++0x8c6200d0, ++0x34420002, ++0xac6200d0, ++0x24020200, ++0x2442ffff, ++0x10400004, ++0x3c03b000, ++0x00000000, ++0x1000fffc, ++0x2442ffff, ++0x8c6200d0, ++0x2404fffd, ++0x00441024, ++0xac6200d0, ++0x24020200, ++0x2442ffff, ++0x10400004, ++0x3c03b301, ++0x00000000, ++0x1000fffc, ++0x2442ffff, ++0x8c62102c, ++0x2404ffef, ++0x00441024, ++0xac62102c, ++0x24020010, ++0x2442ffff, ++0x10400004, ++0x3c03b000, ++0x00000000, ++0x1000fffc, ++0x2442ffff, ++0x8c6200d0, ++0x34420002, ++0xac6200d0, ++0x24020200, ++0x2442ffff, ++0x10400004, ++0x3c03b000, ++0x00000000, ++0x1000fffc, ++0x2442ffff, ++0x8c6200d0, ++0x2404fffd, ++0x00441024, ++0xac6200d0, ++0x24020200, ++0x2442ffff, ++0x10400004, ++0x24030017, ++0x00000000, ++0x1000fffc, ++0x2442ffff, ++0x3c02b301, ++0x3c14b301, ++0xac431004, ++0x2415000b, ++0x26971180, ++0x8e82100c, ++0x3042000b, ++0x10550079, ++0x2696100c, ++0x8e82100c, ++0x30420060, ++0x10400006, ++0x8f998054, ++0x8f998030, ++0x04110090, ++0x24040065, ++0x10000070, ++0x8fbc0010, ++0x8ee40000, ++0x0411009a, ++0x00000000, ++0x8fbc0010, ++0x8ec4017c, ++0x8f998054, ++0x04110095, ++0x00000000, ++0x8fbc0010, ++0x8e84100c, ++0x8f998054, ++0x04110090, ++0x00000000, ++0x8fbc0010, ++0x8f998030, ++0x0411007d, ++0x2404000d, ++0x8fbc0010, ++0x8f998030, ++0x04110079, ++0x2404000a, ++0x1000ffdd, ++0x8fbc0010, ++0x3c05b34f, ++0x8ca40008, ++0x3c03fffd, ++0x3463ffdf, ++0x00831824, ++0x34630002, ++0xaca30008, ++0x24420081, ++0x3c03b301, ++0xac621004, ++0x3c14b301, ++0x2415001b, ++0x8e82100c, ++0x3042001b, ++0x10550017, ++0x00000000, ++0x8e82100c, ++0x30420060, ++0x10400006, ++0x8f998054, ++0x8f998030, ++0x04110060, ++0x24040065, ++0x1000000e, ++0x8fbc0010, ++0x8e84100c, ++0x0411006a, ++0x00000000, ++0x8fbc0010, ++0x8f998030, ++0x04110057, ++0x2404000d, ++0x8fbc0010, ++0x8f998030, ++0x04110053, ++0x2404000a, ++0x1000ffe7, ++0x8fbc0010, ++0x12400006, ++0x3c03b301, ++0x8e020004, ++0x1040000d, ++0x8e620c28, ++0x10000010, ++0x00000000, ++0x8c62102c, ++0x34420010, ++0xac62102c, ++0x24020010, ++0x2442ffff, ++0x1040fff5, ++0x00000000, ++0x00000000, ++0x1000fffc, ++0x2442ffff, ++0x16400004, ++0x00000000, ++0x3c02b34f, ++0xac4000bc, ++0x8e620c28, ++0x10400003, ++0x24030001, ++0x3c02b34f, ++0xac430304, ++0x8e030008, ++0x8f998038, ++0x3c02b34f, ++0xac430008, ++0x273902a0, ++0x0411fe45, ++0x00000000, ++0x8fbc0010, ++0x8e020018, ++0x40826002, ++0x8e220000, ++0x8c440010, ++0x3c020fff, ++0x3442ffff, ++0x10820004, ++0x8f998044, ++0x0411fe2c, ++0x00002825, ++0x8fbc0010, ++0x8f998030, ++0x04110021, ++0x24040073, ++0x1000fffc, ++0x8fbc0010, ++0x3c04b34f, ++0x8c830008, ++0x3c02fffd, ++0x3442ffdf, ++0x00621024, ++0x34420002, ++0xac820008, ++0x1000ffa8, ++0x24020081, ++0x00000000, ++0x00000000, ++0x00000000, ++0x2484ffac, ++0x1c80fffd, ++0x00000000, ++0x03e00008, ++0x00000000, ++0x3c1c0001, ++0x279c8198, ++0x0399e021, ++0x240300ff, ++0x10830006, ++0x8f828038, ++0x3c03b003, ++0x00042300, ++0x00832021, ++0x03e00008, ++0xac440c50, ++0x03e00008, ++0xac400c50, ++0x3c1c0001, ++0x279c8164, ++0x0399e021, ++0x8f828038, ++0x8c430c50, ++0x10600007, ++0x7c042420, ++0xac640000, ++0x24040060, ++0x8c620014, ++0x30420060, ++0x1444fffd, ++0x00000000, ++0x03e00008, ++0x00000000, ++0x3c1c0001, ++0x279c8128, ++0x0399e021, ++0x8f998030, ++0x27bdffe0, ++0x00803825, ++0x2405001c, ++0xafbc0010, ++0xafbf001c, ++0x2406fffc, ++0x00a71006, ++0x3042000f, ++0x2c44000a, ++0x24430030, ++0x24420037, ++0x0044180a, ++0x0411ffe0, ++0x00602025, ++0x24a5fffc, ++0x14a6fff7, ++0x00a71006, ++0x8fbf001c, ++0x03e00008, ++0x27bd0020, ++0x00000000, ++0x00000000, ++0x3088001f, ++0x24030001, ++0x00042143, ++0x3c02b001, ++0x00042200, ++0x01031804, ++0x24420010, ++0x00031827, ++0x00822021, ++0x24060003, ++0x2409ffff, ++0x8c820000, ++0x24840010, ++0x00433824, ++0x00c51007, ++0x30420001, ++0x01021004, ++0x00471025, ++0x24c6ffff, ++0xac82fff0, ++0x14c9fff6, ++0x00000000, ++0x03e00008, ++0x00000000, ++0x3087001f, ++0x3c02b001, ++0x00042143, ++0x24420010, ++0x00042200, ++0x00822021, ++0x24050003, ++0x00001025, ++0x2406ffff, ++0x8c830000, ++0x24840010, ++0x00e31806, ++0x30630001, ++0x00a31804, ++0x24a5ffff, ++0x14a6fff9, ++0x00621025, ++0x03e00008, ++0x00000000, ++0x00000000, ++0x02200000, ++0x01000101, ++0x00000000, ++0x00000000, ++0x00000001, ++0x00000000, ++0x00000000, ++0xffffffff, ++0x00000000, ++0x80000000, ++0x00000c1c, ++0x00000c24, ++0x00000c20, ++0x00000218, ++0x00000430, ++0x0000060c, ++0x00000a4c, ++0x00000354, ++0x00000000, ++0x00000a18, ++0x00000240, ++0x00000268, ++0x00000394, ++0x00000b50, ++0x00000af0, ++0x00000a88, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000018, ++0x00000003, ++0x0000001c, ++0x00000003, ++0x00000020, ++0x00000003, ++0x00000024, ++0x00000003, ++0x00000028, ++0x00000003, ++0x0000002c, ++0x00000003, ++0xffffffff, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00010003, ++0x000000ad, ++0x00000c1c, ++0x00000000, ++0x00050010, ++0x00000001, ++0x00000001, ++0x00000000, ++0xfff10013, ++0x00000081, ++0x00000017, ++0x00000000, ++0xfff10010, ++0x0000003e, ++0x00000c20, ++0x00000004, ++0x00070211, ++0x00000059, ++0x00000240, ++0x00000028, ++0x00010012, ++0x0000004a, ++0x00000218, ++0x00000028, ++0x00010012, ++0x0000007d, ++0x00008bb0, ++0x00000000, ++0xfff10010, ++0x00000091, ++0x00000c1c, ++0x00000000, ++0x00050010, ++0x00000028, ++0x00000c1c, ++0x00000000, ++0x00070010, ++0x00000075, ++0x00000000, ++0x00000000, ++0x00010010, ++0x00000012, ++0x00000bb8, ++0x00000000, ++0x00030011, ++0x000000a2, ++0x00000c1c, ++0x00000000, ++0x00050010, ++0x00000032, ++0x00000c24, ++0x00000004, ++0x00070211, ++0x0000001c, ++0x00000c1c, ++0x00000000, ++0x00070010, ++0x00000067, ++0x00000268, ++0x00000038, ++0x00010012, ++0x000000c6, ++0x00000c58, ++0x00000000, ++0x00060010, ++0x000000bd, ++0x00000c54, ++0x00000000, ++0x00050010, ++0x59445f00, ++0x494d414e, ++0x494c5f43, ++0x4e494b4e, ++0x5f5f0047, ++0x5f444c52, ++0x0050414d, ++0x73625f5f, ++0x74735f73, ++0x00747261, ++0x73625f5f, ++0x6e655f73, ++0x78650064, ++0x6e726574, ++0x6e75665f, ++0x5f700063, ++0x5f706c73, ++0x61726170, ++0x6c73006d, ++0x5f706565, ++0x655f6d70, ++0x7265746e, ++0x656c7300, ++0x705f7065, ++0x78655f6d, ++0x63007469, ++0x5f6c6c61, ++0x636e7566, ++0x6e6f6974, ++0x735f5f00, ++0x74726174, ++0x70675f00, ++0x6d756e00, ++0x746f675f, ++0x746e655f, ++0x73656972, ++0x695f5f00, ++0x6567616d, ++0x706f635f, ++0x6e655f79, ++0x5f5f0064, ++0x74696e69, ++0x646e655f, ++0x725f5f00, ++0x645f6c65, ++0x735f6e79, ++0x74726174, ++0x725f5f00, ++0x645f6c65, ++0x655f6e79, ++0xff00646e, ++0x00000004, ++0x00000f70, ++0x00000005, ++0x00000d88, ++0x00000006, ++0x00000c58, ++0x0000000a, ++0x000000cb, ++0x0000000b, ++0x00000010, ++0x70000035, ++0xfffffd3c, ++0x00000015, ++0x00000000, ++0x00000016, ++0x00000000, ++0x00000003, ++0x00000bc0, ++0x00000011, ++0x00000c1c, ++0x00000012, ++0x00000038, ++0x00000013, ++0x00000008, ++0x70000001, ++0x00000001, ++0x70000005, ++0x00000002, ++0x70000006, ++0x00000000, ++0x7000000a, ++0x00000017, ++0x70000011, ++0x00000013, ++0x70000012, ++0x0000000f, ++0x70000013, ++0x00000013, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x7273752f, ++0x62696c2f, ++0x62696c2f, ++0x6f732e63, ++0xff00312e, ++0x00000f41, ++0x756e6700, ++0x00070100, ++0x01040000, ++0x00000f41, ++0x756e6700, ++0x00070100, ++0x01040000, ++0x00000f41, ++0x756e6700, ++0x00070100, ++0x01040000, ++0x00000f41, ++0x756e6700, ++0x00070100, ++0x01040000, ++0x00000011, ++0x00000013, ++0x00000000, ++0x0000000d, ++0x00000009, ++0x00000010, ++0x00000007, ++0x00000004, ++0x0000000a, ++0x0000000e, ++0x00000002, ++0x00000000, ++0x00000000, ++0x0000000f, ++0x00000000, ++0x00000011, ++0x00000012, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000003, ++0x00000000, ++0x00000000, ++0x00000006, ++0x00000005, ++0x00000008, ++0x00000000, ++0x00000000, ++0x0000000b, ++0x00000000, ++0x00000000, ++0x00000000, ++0x00000000, ++0x0000000c, ++0x00000000, diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_core_sleep.map.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_core_sleep.map.patch new file mode 100644 index 00000000..7c47df2f --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_core_sleep.map.patch @@ -0,0 +1,195 @@ +diff -drupN a/tools/pm-sleep/core_sleep.map b/tools/pm-sleep/core_sleep.map +--- a/tools/pm-sleep/core_sleep.map 1970-01-01 03:00:00.000000000 +0300 ++++ b/tools/pm-sleep/core_sleep.map 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,191 @@ ++ ++Discarded input sections ++ ++ .data 0x0000000000000000 0x0 start.o ++ .bss 0x0000000000000000 0x0 start.o ++ .reginfo 0x0000000000000000 0x18 start.o ++ .pdr 0x0000000000000000 0x80 start.o ++ .data 0x0000000000000000 0x0 pm_sleep.o ++ .reginfo 0x0000000000000000 0x18 pm_sleep.o ++ .MIPS.abiflags ++ 0x0000000000000000 0x18 pm_sleep.o ++ .pdr 0x0000000000000000 0xe0 pm_sleep.o ++ .data 0x0000000000000000 0x0 uart.o ++ .reginfo 0x0000000000000000 0x18 uart.o ++ .MIPS.abiflags ++ 0x0000000000000000 0x18 uart.o ++ .pdr 0x0000000000000000 0x80 uart.o ++ .data 0x0000000000000000 0x0 gpio.o ++ .bss 0x0000000000000000 0x0 gpio.o ++ .reginfo 0x0000000000000000 0x18 gpio.o ++ .MIPS.abiflags ++ 0x0000000000000000 0x18 gpio.o ++ .pdr 0x0000000000000000 0x40 gpio.o ++ ++Memory Configuration ++ ++Name Origin Length Attributes ++*default* 0x0000000000000000 0xffffffffffffffff ++ ++Linker script and memory map ++ ++ 0x0000000000000000 . = 0x0 ++ 0x0000000000000000 . = ALIGN (0x4) ++ ++.text 0x0000000000000000 0xba0 ++ 0x0000000000000000 __start = . ++ *(.start_section*) ++ *(.text*) ++ .text 0x0000000000000000 0x2a0 start.o ++ 0x0000000000000000 _start ++ 0x0000000000000218 sleep_pm_enter ++ 0x0000000000000240 sleep_pm_exit ++ 0x0000000000000268 call_function ++ .text 0x00000000000002a0 0x760 pm_sleep.o ++ 0x0000000000000354 blast_l1cache_all ++ 0x000000000000037c flush_cache_all ++ 0x0000000000000394 scale_cpu_freq ++ 0x0000000000000430 core_sleep_enter ++ 0x000000000000060c core_sleep_restore ++ .text 0x0000000000000a00 0xf0 uart.o ++ 0x0000000000000a00 udelay ++ 0x0000000000000a18 serial_setid ++ 0x0000000000000a4c serial_putc ++ 0x0000000000000a88 serial_put_hex ++ .text 0x0000000000000af0 0xb0 gpio.o ++ 0x0000000000000af0 set_gpio_func ++ 0x0000000000000b50 get_gpio_func ++ 0x0000000000000ba0 . = ALIGN (0x4) ++ ++.rodata ++ *(SORT(.rodata*)) ++ ++.MIPS.abiflags 0x0000000000000ba0 0x18 ++ .MIPS.abiflags ++ 0x0000000000000ba0 0x18 start.o ++ 0x0000000000000bb8 . = ALIGN (0x4) ++ ++.data ++ *(.data*) ++ ++.got.plt 0x0000000000000bb8 0x0 ++ .got.plt 0x0000000000000bb8 0x0 start.o ++ ++.rld_map 0x0000000000000bb8 0x4 ++ .rld_map 0x0000000000000bb8 0x4 start.o ++ 0x0000000000000bb8 __RLD_MAP ++ 0x0000000000000bbc . = . ++ 0x0000000000008bb0 _gp = (ALIGN (0x10) + 0x7ff0) ++ ++.got 0x0000000000000bc0 0x5c ++ *(.got) ++ .got 0x0000000000000bc0 0x5c start.o ++ 0x0000000000000bc0 _GLOBAL_OFFSET_TABLE_ ++ 0x0000000000000017 num_got_entries = (SIZEOF (.got) >> 0x2) ++ 0x0000000000000c1c . = ALIGN (0x4) ++ ++.sdata ++ *(.sdata*) ++ 0x0000000000000c1c . = ALIGN (0x4) ++ ++.u_boot_list ++ *(SORT(.u_boot_list*)) ++ 0x0000000000000c1c . = ALIGN (0x4) ++ 0x0000000000000c1c __image_copy_end = . ++ 0x0000000000000c1c __init_end = . ++ ++.rel.dyn 0x0000000000000c1c 0x38 ++ 0x0000000000000c1c __rel_dyn_start = . ++ *(.rel.dyn) ++ .rel.dyn 0x0000000000000c1c 0x38 start.o ++ 0x0000000000000c54 __rel_dyn_end = . ++ .rel.plt 0x0000000000000c54 0x0 start.o ++ ++.deadcode 0x0000000000000c54 0x4 ++ 0x0000000000000c54 0x4 LONG 0xffffffff ++ 0x0000000000000c58 _end = . ++ ++.bss 0x0000000000000c1c 0x44 ++ 0x0000000000000c1c __bss_start = . ++ *(.sbss.*) ++ *(.bss.*) ++ *(COMMON) ++ 0x0000000000000c1c . = ALIGN (0x4) ++ 0x0000000000000c1c __bss_end = . ++ *fill* 0x0000000000000c1c 0x4 ++ .bss 0x0000000000000c20 0x30 pm_sleep.o ++ 0x0000000000000c20 p_slp_param ++ 0x0000000000000c24 extern_func ++ .bss 0x0000000000000c50 0x10 uart.o ++ ++.dynsym 0x0000000000000c58 0x130 ++ *(.dynsym) ++ .dynsym 0x0000000000000c58 0x130 start.o ++ ++.dynbss 0x0000000000000d88 0x0 ++ *(.dynbss) ++ .dynbss 0x0000000000000d88 0x0 start.o ++ ++.dynstr 0x0000000000000d88 0xcb ++ *(.dynstr) ++ .dynstr 0x0000000000000d88 0xcb start.o ++ ++.dynamic 0x0000000000000e54 0xc8 ++ *(.dynamic) ++ .dynamic 0x0000000000000e54 0xc8 start.o ++ 0x0000000000000e54 _DYNAMIC ++ ++.plt 0x0000000000000f1c 0x0 ++ *(.plt) ++ .plt 0x0000000000000f1c 0x0 start.o ++ ++.interp 0x0000000000000f1c 0x13 ++ *(.interp) ++ .interp 0x0000000000000f1c 0x13 start.o ++ ++.gnu 0x0000000000000f30 0x40 ++ *(.gnu*) ++ .gnu.attributes ++ 0x0000000000000f30 0x10 start.o ++ .gnu.version_d ++ 0x0000000000000f40 0x0 start.o ++ .gnu.version 0x0000000000000f40 0x0 start.o ++ .gnu.version_r ++ 0x0000000000000f40 0x0 start.o ++ .gnu.attributes ++ 0x0000000000000f40 0x10 pm_sleep.o ++ .gnu.attributes ++ 0x0000000000000f50 0x10 uart.o ++ .gnu.attributes ++ 0x0000000000000f60 0x10 gpio.o ++ ++.MIPS.stubs 0x0000000000000f70 0x0 ++ *(.MIPS.stubs) ++ .MIPS.stubs 0x0000000000000f70 0x0 start.o ++ ++.hash 0x0000000000000f70 0x98 ++ *(.hash) ++ .hash 0x0000000000000f70 0x98 start.o ++Address of section .text set to 0x0 ++LOAD start.o ++LOAD pm_sleep.o ++LOAD uart.o ++LOAD gpio.o ++OUTPUT(core_sleep elf32-tradlittlemips) ++ ++_start_section 0x0000000000000000 0x0 ++ [!provide] PROVIDE (__start__start_section, .) ++ _start_section ++ 0x0000000000000000 0x0 start.o ++ [!provide] PROVIDE (__stop__start_section, .) ++ ++.mdebug.abi32 0x0000000000000000 0x0 ++ .mdebug.abi32 0x0000000000000000 0x0 pm_sleep.o ++ .mdebug.abi32 0x0000000000000000 0x0 uart.o ++ .mdebug.abi32 0x0000000000000000 0x0 gpio.o ++ ++.comment 0x0000000000000000 0x2e ++ .comment 0x0000000000000000 0x2e pm_sleep.o ++ 0x2f (size before relaxing) ++ .comment 0x000000000000002e 0x2f uart.o ++ .comment 0x000000000000002e 0x2f gpio.o diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_gpio.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_gpio.c.patch new file mode 100644 index 00000000..82a3f0a8 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_gpio.c.patch @@ -0,0 +1,71 @@ +diff -drupN a/tools/pm-sleep/gpio.c b/tools/pm-sleep/gpio.c +--- a/tools/pm-sleep/gpio.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/tools/pm-sleep/gpio.c 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,67 @@ ++#include "common.h" ++#include "gpio.h" ++void set_gpio_func(int gpio, int type) { ++ int i; ++ int port = gpio >> 5; ++ int pin = gpio & 0x1f; ++ int addr = GPIO_BASE + PXINT + port * 0x100; ++ int b; ++ for(i = 0;i < 4;i++){ ++ b = REG32(addr + 0x10 * i); ++ b &= ~(1 << pin); ++ b |= (((type >> (3 - i)) & 1) << pin); ++ REG32(addr + 0x10 * i) = b; ++ } ++} ++ ++int get_gpio_func(int gpio) { ++ int i; ++ int ret = 0; ++ int port = gpio >> 5; ++ int pin = gpio & 0x1f; ++ int addr = GPIO_BASE + PXINT + port * 0x100; ++ for(i = 0;i < 4;i++){ ++ ret |= ((REG32(addr + 0x10 * i) >> pin) & 1) << (3 - i); ++ } ++ return ret; ++} ++ ++ ++#if 0 ++#define readl(addr) ({*(volatile unsigned int *)(addr);}) ++ ++#define writel(v,addr) do{*(volatile unsigned int *)(addr) = (v);}while(0) ++ ++ ++int gpio_get_value(unsigned int gpio) ++{ ++ unsigned int port = gpio / 32; ++ unsigned int pin = gpio % 32; ++ unsigned int base = GPIO_BASE + 0x100 * port; ++ return !!(readl(base + PXPIN) & (1 << pin)); ++} ++void gpio_direction_output(unsigned int gpio, int value) ++{ ++ unsigned int port = gpio / 32; ++ unsigned int pin = gpio % 32; ++ unsigned int base = GPIO_BASE + 0x100 * port; ++ writel(1 << pin, base + PXINTC); ++ writel(1 << pin, base + PXMSKS); ++ writel(1 << pin, base + PXPAT1C); ++ if (value) ++ writel(1 << pin, base + PXPAT0S); ++ else ++ writel(1 << pin, base + PXPAT0C); ++ ++} ++void gpio_direction_input(unsigned int gpio) ++{ ++ unsigned int port = gpio / 32; ++ unsigned int pin = gpio % 32; ++ unsigned int base = GPIO_BASE + 0x100 * port; ++ ++ writel(1 << pin, base + PXINTC); ++ writel(1 << pin, base + PXMSKS); ++ writel(1 << pin, base + PXPAT1S); ++} ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_i2c-gpio.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_i2c-gpio.c.patch new file mode 100644 index 00000000..665a98b8 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_i2c-gpio.c.patch @@ -0,0 +1,276 @@ +diff -drupN a/tools/pm-sleep/i2c-gpio.c b/tools/pm-sleep/i2c-gpio.c +--- a/tools/pm-sleep/i2c-gpio.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/tools/pm-sleep/i2c-gpio.c 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,272 @@ ++/* ++ * from ingenic_soft_i2c.c in uboot. ++ */ ++#include "common.h" ++#include "i2c-gpio.h" ++#include "gpio.h" ++ ++#define I2C_ACK 0 /* PD_SDA level to ack a byte */ ++#define I2C_NOACK 1 /* PD_SDA level to noack a byte */ ++ ++ ++#define printf(x,...) ++ ++/*----------------------------------------------------------------------- ++ * Local functions ++ */ ++static void i2c_scl(struct i2c_gpio *i2c,int bit) ++{ ++ gpio_direction_output(i2c->scl,bit); ++} ++ ++static void i2c_sda(struct i2c_gpio *i2c,int bit) ++{ ++ if(bit) { ++ gpio_direction_input(i2c->sda); ++ } else { ++ gpio_direction_output(i2c->sda,bit); ++ } ++} ++ ++static int i2c_read_sda(struct i2c_gpio *i2c) ++{ ++ return gpio_get_value(i2c->sda); ++} ++/*----------------------------------------------------------------------- ++ * START: High -> Low on SDA while SCL is High ++ */ ++static void send_start(struct i2c_gpio *i2c) ++{ ++ ++ udelay(5); ++ i2c_sda(i2c,1); ++ udelay(5); ++ i2c_scl(i2c,1); ++ udelay(5); ++ i2c_sda(i2c,0); ++ udelay(5); ++} ++ ++/*----------------------------------------------------------------------- ++ * STOP: Low -> High on SDA while SCL is High ++ */ ++static void send_stop(struct i2c_gpio *i2c) ++{ ++ i2c_scl(i2c,0); ++ udelay(5); ++ i2c_sda(i2c,0); ++ udelay(5); ++ i2c_scl(i2c,1); ++ udelay(5); ++ i2c_sda(i2c,1); ++ udelay(5); ++} ++ ++/*----------------------------------------------------------------------- ++ * ack should be I2C_ACK or I2C_NOACK ++ */ ++static void send_ack(struct i2c_gpio *i2c,int ack) ++{ ++ i2c_scl(i2c,0); ++ udelay(5); ++ i2c_sda(i2c,ack); ++ udelay(5); ++ i2c_scl(i2c,1); ++ udelay(5*2); ++ i2c_scl(i2c,0); ++ udelay(5); ++} ++ ++/*----------------------------------------------------------------------- ++ * Send a reset sequence consisting of 9 clocks with the data signal high ++ * to clock any confused device back into an idle state. Also send a ++ * at the end of the sequence for belts & suspenders. ++ */ ++/* static inline void send_reset(struct i2c_gpio *i2c) */ ++/* { */ ++/* int j; */ ++ ++/* i2c_scl(i2c,1); */ ++/* i2c_sda(i2c,1); */ ++/* for(j = 0; j < 9; j++) { */ ++/* i2c_scl(i2c,0); */ ++/* udelay(5*2); */ ++/* i2c_scl(i2c,1); */ ++/* udelay(5*2); */ ++/* } */ ++/* send_stop(i2c); */ ++/* } */ ++/*----------------------------------------------------------------------- ++ * Send 8 bits and look for an acknowledgement. ++ */ ++static int write_byte(struct i2c_gpio *i2c,unsigned char data) ++{ ++ int j; ++ int nack; ++ ++ for(j = 0; j < 8; j++) { ++ i2c_scl(i2c,0); ++ udelay(5); ++ i2c_sda(i2c,data & 0x80); ++ udelay(5); ++ i2c_scl(i2c,1); ++ udelay(5*2); ++ data <<= 1; ++ } ++ ++ /* ++ * Look for an (negative logic) and return it. ++ */ ++ i2c_scl(i2c,0); ++ udelay(5); ++ i2c_sda(i2c,1); ++ udelay(5); ++ i2c_scl(i2c,1); ++ udelay(5*2); ++ nack = i2c_read_sda(i2c); ++ i2c_scl(i2c,0); ++ udelay(5); ++ ++ return(nack); /* not a nack is an ack */ ++} ++ ++/*----------------------------------------------------------------------- ++ * if ack == I2C_ACK, ACK the byte so can continue reading, else ++ * send I2C_NOACK to end the read. ++ */ ++static unsigned char read_byte(struct i2c_gpio *i2c,int ack) ++{ ++ int data; ++ int j; ++ ++ /* ++ * Read 8 bits, MSB first. ++ */ ++ i2c_sda(i2c,1); ++ data = 0; ++ for(j = 0; j < 8; j++) { ++ i2c_scl(i2c,0); ++ udelay(5); ++ i2c_scl(i2c,1); ++ udelay(5); ++ data <<= 1; ++ data |= i2c_read_sda(i2c); ++ udelay(5); ++ } ++ send_ack(i2c,ack); ++ ++ return(data); ++} ++ ++/*=====================================================================*/ ++/* Public Functions */ ++/*=====================================================================*/ ++ ++/*----------------------------------------------------------------------- ++ * Initialization ++ */ ++/* void i2c_init(struct i2c_gpio *i2c) */ ++/* { */ ++/* gpio_request(i2c->scl, "soft_i2c"); */ ++/* gpio_request(i2c->sda, "soft_i2c"); */ ++/* gpio_direction_output(i2c->sda,1); */ ++/* gpio_direction_output(i2c->scl,1); */ ++/* send_reset(i2c); */ ++/* } */ ++void i2c_reinit(struct i2c_gpio *i2c) ++{ ++ gpio_direction_output(i2c->sda,1); ++ gpio_direction_output(i2c->scl,1); ++} ++/*----------------------------------------------------------------------- ++ * Read bytes ++ */ ++int i2c_read(struct i2c_gpio *i2c,unsigned char chip, ++ unsigned int addr, int alen, unsigned char *buffer, int len) ++{ ++ int shift; ++#ifdef DEBUG ++ printf("i2c_read: chip %x addr %x alen %d buffer %p len %d\n", ++ chip, addr, alen, buffer, len); ++#endif ++ /* ++ * Do the addressing portion of a write cycle to set the ++ * chip's address pointer. If the address length is zero, ++ * don't do the normal write cycle to set the address pointer, ++ * there is no address pointer in this chip. ++ */ ++ send_start(i2c); ++ if(alen > 0) { ++ if(write_byte(i2c,chip << 1)) { /* write cycle */ ++ send_stop(i2c); ++ printf("i2c_read, no chip responded %02X\n", chip); ++ return 1; ++ } ++ shift = (alen-1) * 8; ++ while(alen-- > 0) { ++ if(write_byte(i2c,addr >> shift)) { ++ printf("i2c_read, address not ed\n"); ++ return 1; ++ } ++ shift -= 8; ++ } ++ ++ /* Some I2C_GPIO chips need a stop/start sequence here, ++ * other chips don't work with a full stop and need ++ * only a start. Default behaviour is to send the ++ * stop/start sequence. ++ */ ++#ifdef CONFIG_SOFT_I2C_READ_REPEATED_START ++ send_start(i2c); ++#else ++ send_stop(i2c); ++ send_start(i2c); ++#endif ++ } ++ /* ++ * Send the chip address again, this time for a read cycle. ++ * Then read the data. On the last byte, we do a NACK instead ++ * of an ACK(len == 0) to terminate the read. ++ */ ++ write_byte(i2c,(chip << 1) | 1); /* read cycle */ ++ while(len-- > 0) { ++ *buffer++ = read_byte(i2c,len == 0); ++ } ++ send_stop(i2c); ++ return 0; ++} ++ ++/*----------------------------------------------------------------------- ++ * Write bytes ++ */ ++int i2c_write(struct i2c_gpio *i2c,unsigned char chip, unsigned int addr, int alen, unsigned char *buffer, int len) ++{ ++ int shift, failures = 0; ++ ++#ifdef DEBUG ++ printf("i2c_write: chip %x addr %x alen %d buffer %p len %d\n", ++ chip, addr, alen, buffer, len); ++#endif ++ send_start(i2c); ++ if(write_byte(i2c,chip << 1)) { /* write cycle */ ++ send_stop(i2c); ++ printf("i2c_write, no chip responded %02X\n", chip); ++ return 1; ++ } ++ shift = (alen-1) * 8; ++ while(alen-- > 0) { ++ if(write_byte(i2c,addr >> shift)) { ++ printf("i2c_write, address not ed\n"); ++ return 1; ++ } ++ shift -= 8; ++ } ++ ++ while(len-- > 0) { ++ if(write_byte(i2c,*buffer++)) { ++ failures++; ++ } ++ } ++ send_stop(i2c); ++ return failures; ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_include_common.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_include_common.h.patch new file mode 100644 index 00000000..f70df01a --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_include_common.h.patch @@ -0,0 +1,9 @@ +diff -drupN a/tools/pm-sleep/include/common.h b/tools/pm-sleep/include/common.h +--- a/tools/pm-sleep/include/common.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/tools/pm-sleep/include/common.h 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,5 @@ ++#ifndef __COMMON_H__ ++#define __COMMON_H__ ++void udelay(int d); ++#define REG32(x) (*(volatile unsigned int *)(x)) ++#endif /* __COMMON_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_include_cpm.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_include_cpm.h.patch new file mode 100644 index 00000000..097552c0 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_include_cpm.h.patch @@ -0,0 +1,97 @@ +diff -drupN a/tools/pm-sleep/include/cpm.h b/tools/pm-sleep/include/cpm.h +--- a/tools/pm-sleep/include/cpm.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/tools/pm-sleep/include/cpm.h 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,93 @@ ++/* ++ * JZSOC CPM register definition. ++ * ++ * CPM (Clock reset and Power control Management) ++ * ++ * Copyright (C) 2010 Ingenic Semiconductor Co., Ltd. ++ */ ++ ++#ifndef __CPM_H__ ++#define __CPM_H__ ++#define CPM_IOBASE 0xb0000000 ++ ++ ++#define CPM_CPCCR (0x00) ++#define CPM_CPCSR (0xd4) ++ ++#define CPM_DDRCDR (0x2c) ++#define CPM_VPUCDR (0x30) ++#define CPM_I2SCDR (0x60) ++#define CPM_LPCDR (0x64) ++#define CPM_MSC0CDR (0x68) ++#define CPM_MSC1CDR (0xa4) ++#define CPM_MSC2CDR (0xa8) ++#define CPM_USBCDR (0x50) ++#define CPM_UHCCDR (0x6c) ++#define CPM_SSICDR (0x74) ++#define CPM_CIMCDR (0x7c) ++#define CPM_PCMCDR (0x84) ++#define CPM_GPUCDR (0x88) ++#define CPM_ISPCDR (0x80) ++#define CPM_BCHCDR (0xac) ++ ++#define CPM_MPHYC (0xe0) ++ ++#define CPM_INTR (0xb0) ++#define CPM_INTRE (0xb4) ++#define CPM_CPSPPR (0x38) ++#define CPM_CPPSR (0x34) ++ ++#define CPM_USBPCR (0x3c) ++#define CPM_USBRDT (0x40) ++#define CPM_USBVBFIL (0x44) ++#define CPM_USBPCR1 (0x48) ++ ++#define CPM_CPAPCR (0x10) ++#define CPM_CPMPCR (0x14) ++#define CPM_CPPCR (0x0c) ++ ++#define CPM_LCR (0x04) ++#define CPM_SPCR0 (0xb8) ++//#define CPM_SPCR1 (0xbc) ++//#define CPM_SPPC (0xc0) ++#define CPM_PSWC0ST (0x90) ++#define CPM_PSWC1ST (0x94) ++#define CPM_PSWC2ST (0x98) ++#define CPM_PSWC3ST (0x9c) ++#define CPM_CLKGR (0x20) ++#define CPM_CLKGR1 (0x28) ++#define CPM_SRBC (0xc4) ++#define CPM_SLBC (0xc8) ++#define CPM_SLPC (0xcc) ++#define CPM_OPCR (0x24) ++#define CPM_RSR (0x08) ++#define CPM_PGR (0xe4) ++ ++#define LCR_LPM_MASK (0x3) ++#define LCR_LPM_SLEEP (0x1) ++ ++#define CPM_LCR_PD_X2D (0x1<<31) ++#define CPM_LCR_PD_VPU (0x1<<30) ++#define CPM_LCR_PD_MASK (0x3<<30) ++#define CPM_LCR_X2DS (0x1<<27) ++#define CPM_LCR_VPUS (0x1<<26) ++#define CPM_LCR_STATUS_MASK (0x3<<26) ++ ++#define OPCR_ERCS (0x1<<2) ++#define OPCR_PD (0x1<<3) ++#define OPCR_IDLE (0x1<<31) ++ ++//#define CLKGR1_VPU (0x1<<2) ++#define CLKGR_VPU (0x1<<19) ++ ++#define cpm_inl(off) REG32(CPM_IOBASE + (off)) ++#define cpm_outl(val,off) REG32(CPM_IOBASE + (off)) = val; ++#define cpm_clear_bit(val,off) do{cpm_outl((cpm_inl(off) & ~(1 << (val))),off);}while(0) ++#define cpm_set_bit(val,off) do{cpm_outl((cpm_inl(off) | (1 << (val))),off);}while(0) ++#define cpm_test_bit(val,off) (cpm_inl(off) & (0x1 << (val))) ++enum { ++ SCALE = 0, ++ RESTORE, ++}; ++#endif ++/* __CPM_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_include_ddr.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_include_ddr.h.patch new file mode 100644 index 00000000..c612df6d --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_include_ddr.h.patch @@ -0,0 +1,106 @@ +diff -drupN a/tools/pm-sleep/include/ddr.h b/tools/pm-sleep/include/ddr.h +--- a/tools/pm-sleep/include/ddr.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/tools/pm-sleep/include/ddr.h 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,102 @@ ++#ifndef _DDR_H_ ++#define _DDR_H_ ++#define DDRC_BASE 0xb34f0000 ++ ++#define DDRP_PIR_INIT (1 << 0) ++#define DDRP_PIR_DLLSRST (1 << 1) ++#define DDRP_PIR_DLLLOCK (1 << 2) ++#define DDRP_PIR_ZCAL (1 << 3) ++#define DDRP_PIR_ITMSRST (1 << 4) ++#define DDRP_PIR_DRAMRST (1 << 5) ++#define DDRP_PIR_DRAMINT (1 << 6) ++#define DDRP_PIR_QSTRN (1 << 7) ++#define DDRP_PIR_EYETRN (1 << 8) ++#define DDRP_PIR_DLLBYP (1 << 17) ++#define DDRP_PIR_LOCKBYP (1 << 29) ++#define DDRP_PGSR_IDONE (1 << 0) ++#define DDRP_PGSR_DLDONE (1 << 1) ++#define DDRP_PGSR_ZCDONE (1 << 2) ++#define DDRP_PGSR_DIDONE (1 << 3) ++#define DDRP_PGSR_DTDONE (1 << 4) ++#define DDRP_PGSR_DTERR (1 << 5) ++#define DDRP_PGSR_DTIERR (1 << 6) ++#define DDRP_PGSR_DFTEERR (1 << 7) ++#define DDRC_AUTOSR_ENABLE (1 << 0) ++ ++ ++#define DDR_PHY_OFFSET (-0x4e0000 + 0x1000) ++ ++#define DDRP_PIR (DDR_PHY_OFFSET + 0x4) /* PHY Initialization Register */ ++#define DDRP_PGCR (DDR_PHY_OFFSET + 0x8) /* PHY General Configuration Register*/ ++#define DDRP_PGSR (DDR_PHY_OFFSET + 0xc) /* PHY General Status Register*/ ++#define DDRP_DLLGCR (DDR_PHY_OFFSET + 0x10) /* DLL General Control Register*/ ++#define DDRP_ACDLLCR (DDR_PHY_OFFSET + 0x14) /* AC DLL Control Register*/ ++#define DDRP_PTR0 (DDR_PHY_OFFSET + 0x18) /* PHY Timing Register 0 */ ++#define DDRP_PTR1 (DDR_PHY_OFFSET + 0x1c) /* PHY Timing Register 1 */ ++#define DDRP_PTR2 (DDR_PHY_OFFSET + 0x20) /* PHY Timing Register 2 */ ++#define DDRP_ACIOCR (DDR_PHY_OFFSET + 0x24) /* AC I/O Configuration Register */ ++#define DDRP_DXCCR (DDR_PHY_OFFSET + 0x28) /* DATX8 Common Configuration Register */ ++#define DDRP_DSGCR (DDR_PHY_OFFSET + 0x2c) /* DDR System General Configuration Register */ ++#define DDRP_DCR (DDR_PHY_OFFSET + 0x30) /* DRAM Configuration Register*/ ++ ++#define DDRP_DTPR0 (DDR_PHY_OFFSET + 0x34) /* DRAM Timing Parameters Register 0 */ ++#define DDRP_DTPR1 (DDR_PHY_OFFSET + 0x38) /* DRAM Timing Parameters Register 1 */ ++#define DDRP_DTPR2 (DDR_PHY_OFFSET + 0x3c) /* DRAM Timing Parameters Register 2 */ ++#define DDRP_MR0 (DDR_PHY_OFFSET + 0x40) /* Mode Register 0 */ ++#define DDRP_MR1 (DDR_PHY_OFFSET + 0x44) /* Mode Register 1 */ ++#define DDRP_MR2 (DDR_PHY_OFFSET + 0x48) /* Mode Register 2 */ ++#define DDRP_MR3 (DDR_PHY_OFFSET + 0x4c) /* Mode Register 3 */ ++#define DDRP_ODTCR (DDR_PHY_OFFSET + 0x50) /* ODT Configure Register */ ++#define DDRP_DTAR (DDR_PHY_OFFSET + 0x54) /* Data Training Address Register */ ++#define DDRP_DTDR0 (DDR_PHY_OFFSET + 0x58) /* Data Training Data Register 0 */ ++#define DDRP_DTDR1 (DDR_PHY_OFFSET + 0x5c) /* Data Training Data Register 1 */ ++ ++#define DDRP_DCUAR (DDR_PHY_OFFSET + 0xc0) /* DCU Address Register */ ++#define DDRP_DCUDR (DDR_PHY_OFFSET + 0xc4) /* DCU Data Register */ ++#define DDRP_DCURR (DDR_PHY_OFFSET + 0xc8) /* DCU Run Register */ ++#define DDRP_DCULR (DDR_PHY_OFFSET + 0xcc) /* DCU Loop Register */ ++#define DDRP_DCUGCR (DDR_PHY_OFFSET + 0xd0) /* DCU Gerneral Configuration Register */ ++#define DDRP_DCUTPR (DDR_PHY_OFFSET + 0xd4) /* DCU Timing Parameters Register */ ++#define DDRP_DCUSR0 (DDR_PHY_OFFSET + 0xd8) /* DCU Status Register 0 */ ++#define DDRP_DCUSR1 (DDR_PHY_OFFSET + 0xdc) /* DCU Status Register 1 */ ++ ++#define DDRP_DXGCR(n) (DDR_PHY_OFFSET + 0x1c0 + n * 0x40) /* DATX8 n General Configuration Register */ ++#define DDRP_DXGSR0(n) (DDR_PHY_OFFSET + 0x1c4 + n * 0x40) /* DATX8 n General Status Register */ ++#define DDRP_DXGSR1(n) (DDR_PHY_OFFSET + 0x1c8 + n * 0x40) /* DATX8 n General Status Register */ ++#define DDRP_DXDLLCR(n) (DDR_PHY_OFFSET + 0x1cc + n * 0x40) /* DATX8 n General Status Register */ ++#define DDRP_DXDQSTR(n) (DDR_PHY_OFFSET + 0x1d4 + n * 0x40) /* DATX8 n DQS Timing Register */ ++#define DDRP_ZQXCR0(n) (DDR_PHY_OFFSET + 0x180 + n * 0x10) /* ZQ impedance Control Register 0 */ ++#define DDRP_ZQXCR1(n) (DDR_PHY_OFFSET + 0x184 + n * 0x10) /* ZQ impedance Control Register 1 */ ++#define DDRP_ZQXSR0(n) (DDR_PHY_OFFSET + 0x188 + n * 0x10) /* ZQ impedance Status Register 0 */ ++#define DDRP_ZQXSR1(n) (DDR_PHY_OFFSET + 0x18c + n * 0x10) /* ZQ impedance Status Register 1 */ ++ ++#define DDRP_DX0GSR (DDR_PHY_OFFSET + 0x71 * 4) ++ ++#define DDRC_STATUS 0x0 ++#define DDRC_CFG 0x4 ++#define DDRC_CTRL 0x8 ++#define DDRC_LMR 0xc ++#define DDRC_REFCNT 0x18 ++#define DDRC_MMAP0 0x24 ++#define DDRC_MMAP1 0x28 ++#define DDRC_DLP 0xbc ++#define DDRC_STRB 0x34 ++#define DDRC_AUTOSR_CNT 0x308 ++#define DDRC_AUTOSR_EN 0x304 ++#define DDRC_TIMING(n) (0x60 + 4 * (n - 1)) ++#define DDRC_REMAP(n) (0x9c + 4 * (n - 1)) ++ ++ ++#define DDRP_DXnDQSTR(n) (DDR_PHY_OFFSET + (0x10 * n + 0x75) * 4) ++#define DDRP_DXnDQTR(n) (DDR_PHY_OFFSET + (0x10 * n + 0x74) * 4) ++ ++#ifndef REG32 ++#define REG32(x) *(volatile unsigned int *)(x) ++#endif ++ ++#define ddr_writel(value, reg) REG32(DDRC_BASE + reg) = (value) ++#define ddr_readl(reg) REG32(DDRC_BASE + reg) ++ ++ ++ ++#endif /* _DDR_H_ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_include_gpio.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_include_gpio.h.patch new file mode 100644 index 00000000..17021241 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_include_gpio.h.patch @@ -0,0 +1,71 @@ +diff -drupN a/tools/pm-sleep/include/gpio.h b/tools/pm-sleep/include/gpio.h +--- a/tools/pm-sleep/include/gpio.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/tools/pm-sleep/include/gpio.h 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,67 @@ ++#ifndef __GPIO_IO_H__ ++#define __GPIO_IO_H__ ++ ++ ++#define GPIO_BASE 0xb0010000 ++ ++#define PXPIN 0x00 /* PIN Level Register */ ++#define PXINT 0x10 /* Port Interrupt Register */ ++#define PXINTS 0x14 /* Port Interrupt Set Register */ ++#define PXINTC 0x18 /* Port Interrupt Clear Register */ ++#define PXMSK 0x20 /* Port Interrupt Mask Reg */ ++#define PXMSKS 0x24 /* Port Interrupt Mask Set Reg */ ++#define PXMSKC 0x28 /* Port Interrupt Mask Clear Reg */ ++#define PXPAT1 0x30 /* Port Pattern 1 Set Reg. */ ++#define PXPAT1S 0x34 /* Port Pattern 1 Set Reg. */ ++#define PXPAT1C 0x38 /* Port Pattern 1 Clear Reg. */ ++#define PXPAT0 0x40 /* Port Pattern 0 Register */ ++#define PXPAT0S 0x44 /* Port Pattern 0 Set Register */ ++#define PXPAT0C 0x48 /* Port Pattern 0 Clear Register */ ++#define PXFLG 0x50 /* Port Flag Register */ ++#define PXFLGC 0x58 /* Port Flag clear Register */ ++#define PXPE 0x70 /* Port Pull Disable Register */ ++#define PXPES 0x74 /* Port Pull Disable Set Register */ ++#define PXPEC 0x78 /* Port Pull Disable Clear Register */ ++enum gpio_function { ++ GPIO_FUNC_0 = 0x00, //0000, GPIO as function 0 / device 0 ++ GPIO_FUNC_1 = 0x01, //0001, GPIO as function 1 / device 1 ++ GPIO_FUNC_2 = 0x02, //0010, GPIO as function 2 / device 2 ++ GPIO_FUNC_3 = 0x03, //0011, GPIO as function 3 / device 3 ++ GPIO_OUTPUT0 = 0x04, //0100, GPIO output low level ++ GPIO_OUTPUT1 = 0x05, //0101, GPIO output high level ++ GPIO_INPUT = 0x06, //0110, GPIO as input ++ GPIO_INT_LO = 0x08, //1000, Low Level trigger interrupt ++ GPIO_INT_HI = 0x09, //1001, High Level trigger interrupt ++ GPIO_INT_FE = 0x0a, //1010, Fall Edge trigger interrupt ++ GPIO_INT_RE = 0x0b, //1011, Rise Edge trigger interrupt ++ GPIO_INPUT_PULL = 0x16, //0001 0110, GPIO as input and enable pull ++}; ++ ++void set_gpio_func(int gpio, int type); ++int get_gpio_func(int gpio); ++#if 1 ++static int gpio_get_value(unsigned int gpio) ++{ ++ unsigned int port = gpio / 32; ++ unsigned int pin = gpio % 32; ++ unsigned int base = GPIO_BASE + 0x100 * port; ++ return !!(REG32(base + PXPIN) & (1 << pin)); ++} ++static inline void gpio_direction_output(unsigned int gpio, int value) ++{ ++ if (value) ++ set_gpio_func(gpio,GPIO_OUTPUT1); ++ else ++ set_gpio_func(gpio,GPIO_OUTPUT0); ++} ++static inline void gpio_direction_input(unsigned int gpio) ++{ ++ set_gpio_func(gpio,GPIO_INPUT); ++} ++#else ++int gpio_get_value(unsigned int gpio); ++void gpio_direction_output(unsigned int gpio, int value); ++void gpio_direction_input(unsigned int gpio); ++#endif ++ ++#endif /* __GPIO_IO_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_include_i2c-gpio.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_include_i2c-gpio.h.patch new file mode 100644 index 00000000..8d31ae4e --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_include_i2c-gpio.h.patch @@ -0,0 +1,23 @@ +diff -drupN a/tools/pm-sleep/include/i2c-gpio.h b/tools/pm-sleep/include/i2c-gpio.h +--- a/tools/pm-sleep/include/i2c-gpio.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/tools/pm-sleep/include/i2c-gpio.h 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,19 @@ ++#ifndef __I2C_GPIO_H ++#define __I2C_GPIO_H ++ ++struct i2c_gpio { ++ unsigned int scl; ++ unsigned int sda; ++}; ++ ++void i2c_init(struct i2c_gpio *i2c); ++ ++int i2c_write(struct i2c_gpio *i2c,unsigned char chip, ++ unsigned int addr, int alen, unsigned char *buffer, int len); ++ ++int i2c_read(struct i2c_gpio *i2c,unsigned char chip, ++ unsigned int addr, int alen, unsigned char *buffer, int len); ++ ++int i2c_probe(struct i2c_gpio *i2c, unsigned char addr); ++ ++#endif /* __I2C_GPIO_H */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_include_mipsregs.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_include_mipsregs.h.patch new file mode 100644 index 00000000..acaedf93 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_include_mipsregs.h.patch @@ -0,0 +1,862 @@ +diff -drupN a/tools/pm-sleep/include/mipsregs.h b/tools/pm-sleep/include/mipsregs.h +--- a/tools/pm-sleep/include/mipsregs.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/tools/pm-sleep/include/mipsregs.h 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,858 @@ ++/* ++ * 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) 1994, 1995, 1996, 1997, 2000, 2001 by Ralf Baechle ++ * Copyright (C) 2000 Silicon Graphics, Inc. ++ * Modified for further R[236]000 support by Paul M. Antoine, 1996. ++ * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com ++ * Copyright (C) 2000, 07 MIPS Technologies, Inc. ++ * Copyright (C) 2003, 2004 Maciej W. Rozycki ++ */ ++#ifndef _ASM_MIPSREGS_H ++#define _ASM_MIPSREGS_H ++ ++/* ++ * Coprocessor 0 register names ++ */ ++#define CP0_INDEX $0 ++#define CP0_RANDOM $1 ++#define CP0_ENTRYLO0 $2 ++#define CP0_ENTRYLO1 $3 ++#define CP0_CONF $3 ++#define CP0_CONTEXT $4 ++#define CP0_PAGEMASK $5 ++#define CP0_WIRED $6 ++#define CP0_INFO $7 ++#define CP0_BADVADDR $8 ++#define CP0_COUNT $9 ++#define CP0_ENTRYHI $10 ++#define CP0_COMPARE $11 ++#define CP0_STATUS $12 ++#define CP0_CAUSE $13 ++#define CP0_EPC $14 ++#define CP0_PRID $15 ++#define CP0_CONFIG $16 ++#define CP0_LLADDR $17 ++#define CP0_WATCHLO $18 ++#define CP0_WATCHHI $19 ++#define CP0_XCONTEXT $20 ++#define CP0_FRAMEMASK $21 ++#define CP0_DIAGNOSTIC $22 ++#define CP0_DEBUG $23 ++#define CP0_DEPC $24 ++#define CP0_PERFORMANCE $25 ++#define CP0_ECC $26 ++#define CP0_CACHEERR $27 ++#define CP0_TAGLO $28 ++#define CP0_TAGHI $29 ++#define CP0_ERROREPC $30 ++#define CP0_DESAVE $31 ++ ++/* ++ * R4640/R4650 cp0 register names. These registers are listed ++ * here only for completeness; without MMU these CPUs are not useable ++ * by Linux. A future ELKS port might take make Linux run on them ++ * though ... ++ */ ++#define CP0_IBASE $0 ++#define CP0_IBOUND $1 ++#define CP0_DBASE $2 ++#define CP0_DBOUND $3 ++#define CP0_CALG $17 ++#define CP0_IWATCH $18 ++#define CP0_DWATCH $19 ++ ++/* ++ * Coprocessor 0 Set 1 register names ++ */ ++#define CP0_S1_DERRADDR0 $26 ++#define CP0_S1_DERRADDR1 $27 ++#define CP0_S1_INTCONTROL $20 ++ ++/* ++ * Coprocessor 0 Set 2 register names ++ */ ++#define CP0_S2_SRSCTL $12 /* MIPSR2 */ ++ ++/* ++ * Coprocessor 0 Set 3 register names ++ */ ++#define CP0_S3_SRSMAP $12 /* MIPSR2 */ ++ ++/* ++ * TX39 Series ++ */ ++#define CP0_TX39_CACHE $7 ++ ++/* ++ * Coprocessor 1 (FPU) register names ++ */ ++#define CP1_REVISION $0 ++#define CP1_STATUS $31 ++ ++/* ++ * FPU Status Register Values ++ */ ++/* ++ * Status Register Values ++ */ ++ ++#define FPU_CSR_FLUSH 0x01000000 /* flush denormalised results to 0 */ ++#define FPU_CSR_COND 0x00800000 /* $fcc0 */ ++#define FPU_CSR_COND0 0x00800000 /* $fcc0 */ ++#define FPU_CSR_COND1 0x02000000 /* $fcc1 */ ++#define FPU_CSR_COND2 0x04000000 /* $fcc2 */ ++#define FPU_CSR_COND3 0x08000000 /* $fcc3 */ ++#define FPU_CSR_COND4 0x10000000 /* $fcc4 */ ++#define FPU_CSR_COND5 0x20000000 /* $fcc5 */ ++#define FPU_CSR_COND6 0x40000000 /* $fcc6 */ ++#define FPU_CSR_COND7 0x80000000 /* $fcc7 */ ++ ++/* ++ * Bits 18 - 20 of the FPU Status Register will be read as 0, ++ * and should be written as zero. ++ */ ++#define FPU_CSR_RSVD 0x001c0000 ++/* ... but FPU2 uses that bits */ ++#define FPU_CSR_NAN2008 0x00040000 ++#define FPU_CSR_ABS2008 0x00080000 ++#define FPU_CSR_MAC2008 0x00100000 ++ ++#define FPU_CSR_DEFAULT 0x00000000 ++ ++/* ++ * X the exception cause indicator ++ * E the exception enable ++ * S the sticky/flag bit ++*/ ++#define FPU_CSR_ALL_X 0x0003f000 ++#define FPU_CSR_UNI_X 0x00020000 ++#define FPU_CSR_INV_X 0x00010000 ++#define FPU_CSR_DIV_X 0x00008000 ++#define FPU_CSR_OVF_X 0x00004000 ++#define FPU_CSR_UDF_X 0x00002000 ++#define FPU_CSR_INE_X 0x00001000 ++ ++#define FPU_CSR_ALL_E 0x00000f80 ++#define FPU_CSR_INV_E 0x00000800 ++#define FPU_CSR_DIV_E 0x00000400 ++#define FPU_CSR_OVF_E 0x00000200 ++#define FPU_CSR_UDF_E 0x00000100 ++#define FPU_CSR_INE_E 0x00000080 ++ ++#define FPU_CSR_ALL_S 0x0000007c ++#define FPU_CSR_INV_S 0x00000040 ++#define FPU_CSR_DIV_S 0x00000020 ++#define FPU_CSR_OVF_S 0x00000010 ++#define FPU_CSR_UDF_S 0x00000008 ++#define FPU_CSR_INE_S 0x00000004 ++ ++/* Bits 0 and 1 of FPU Status Register specify the rounding mode */ ++#define FPU_CSR_RM 0x00000003 ++#define FPU_CSR_RN 0x0 /* nearest */ ++#define FPU_CSR_RZ 0x1 /* towards zero */ ++#define FPU_CSR_RU 0x2 /* towards +Infinity */ ++#define FPU_CSR_RD 0x3 /* towards -Infinity */ ++ ++ ++/* ++ * Macros to access the system control coprocessor ++ */ ++ ++#define __read_32bit_c0_register(source, sel) \ ++({ int __res; \ ++ if (sel == 0) \ ++ __asm__ __volatile__( \ ++ "mfc0\t%0, " #source "\n\t" \ ++ : "=r" (__res)); \ ++ else \ ++ __asm__ __volatile__( \ ++ ".set\tmips32\n\t" \ ++ "mfc0\t%0, " #source ", " #sel "\n\t" \ ++ ".set\tmips0\n\t" \ ++ : "=r" (__res)); \ ++ __res; \ ++}) ++ ++#define __read_64bit_c0_register(source, sel) \ ++({ unsigned long long __res; \ ++ if (sizeof(unsigned long) == 4) \ ++ __res = __read_64bit_c0_split(source, sel); \ ++ else if (sel == 0) \ ++ __asm__ __volatile__( \ ++ ".set\tmips3\n\t" \ ++ "dmfc0\t%0, " #source "\n\t" \ ++ ".set\tmips0" \ ++ : "=r" (__res)); \ ++ else \ ++ __asm__ __volatile__( \ ++ ".set\tmips64\n\t" \ ++ "dmfc0\t%0, " #source ", " #sel "\n\t" \ ++ ".set\tmips0" \ ++ : "=r" (__res)); \ ++ __res; \ ++}) ++ ++#define __write_32bit_c0_register(register, sel, value) \ ++do { \ ++ if (sel == 0) \ ++ __asm__ __volatile__( \ ++ "mtc0\t%z0, " #register "\n\t" \ ++ : : "Jr" ((unsigned int)(value))); \ ++ else \ ++ __asm__ __volatile__( \ ++ ".set\tmips32\n\t" \ ++ "mtc0\t%z0, " #register ", " #sel "\n\t" \ ++ ".set\tmips0" \ ++ : : "Jr" ((unsigned int)(value))); \ ++} while (0) ++ ++#define __write_64bit_c0_register(register, sel, value) \ ++do { \ ++ if (sizeof(unsigned long) == 4) \ ++ __write_64bit_c0_split(register, sel, value); \ ++ else if (sel == 0) \ ++ __asm__ __volatile__( \ ++ ".set\tmips3\n\t" \ ++ "dmtc0\t%z0, " #register "\n\t" \ ++ ".set\tmips0" \ ++ : : "Jr" (value)); \ ++ else \ ++ __asm__ __volatile__( \ ++ ".set\tmips64\n\t" \ ++ "dmtc0\t%z0, " #register ", " #sel "\n\t" \ ++ ".set\tmips0" \ ++ : : "Jr" (value)); \ ++} while (0) ++ ++#define __read_ulong_c0_register(reg, sel) \ ++ ((sizeof(unsigned long) == 4) ? \ ++ (unsigned long) __read_32bit_c0_register(reg, sel) : \ ++ (unsigned long) __read_64bit_c0_register(reg, sel)) ++ ++#define __write_ulong_c0_register(reg, sel, val) \ ++do { \ ++ if (sizeof(unsigned long) == 4) \ ++ __write_32bit_c0_register(reg, sel, val); \ ++ else \ ++ __write_64bit_c0_register(reg, sel, val); \ ++} while (0) ++ ++/* ++ * On RM7000/RM9000 these are uses to access cop0 set 1 registers ++ */ ++#define __read_32bit_c0_ctrl_register(source) \ ++({ int __res; \ ++ __asm__ __volatile__( \ ++ "cfc0\t%0, " #source "\n\t" \ ++ : "=r" (__res)); \ ++ __res; \ ++}) ++ ++#define __write_32bit_c0_ctrl_register(register, value) \ ++do { \ ++ __asm__ __volatile__( \ ++ "ctc0\t%z0, " #register "\n\t" \ ++ : : "Jr" ((unsigned int)(value))); \ ++} while (0) ++ ++/* ++ * These versions are only needed for systems with more than 38 bits of ++ * physical address space running the 32-bit kernel. That's none atm :-) ++ */ ++#define __read_64bit_c0_split(source, sel) \ ++({ \ ++ unsigned long long __val; \ ++ unsigned long __flags; \ ++ \ ++ local_irq_save(__flags); \ ++ if (sel == 0) \ ++ __asm__ __volatile__( \ ++ ".set\tmips64\n\t" \ ++ "dmfc0\t%M0, " #source "\n\t" \ ++ "dsll\t%L0, %M0, 32\n\t" \ ++ "dsra\t%M0, %M0, 32\n\t" \ ++ "dsra\t%L0, %L0, 32\n\t" \ ++ ".set\tmips0" \ ++ : "=r" (__val)); \ ++ else \ ++ __asm__ __volatile__( \ ++ ".set\tmips64\n\t" \ ++ "dmfc0\t%M0, " #source ", " #sel "\n\t" \ ++ "dsll\t%L0, %M0, 32\n\t" \ ++ "dsra\t%M0, %M0, 32\n\t" \ ++ "dsra\t%L0, %L0, 32\n\t" \ ++ ".set\tmips0" \ ++ : "=r" (__val)); \ ++ local_irq_restore(__flags); \ ++ \ ++ __val; \ ++}) ++ ++#define __write_64bit_c0_split(source, sel, val) \ ++do { \ ++ unsigned long __flags; \ ++ \ ++ local_irq_save(__flags); \ ++ if (sel == 0) \ ++ __asm__ __volatile__( \ ++ ".set\tmips64\n\t" \ ++ "dsll\t%L0, %L0, 32\n\t" \ ++ "dsrl\t%L0, %L0, 32\n\t" \ ++ "dsll\t%M0, %M0, 32\n\t" \ ++ "or\t%L0, %L0, %M0\n\t" \ ++ "dmtc0\t%L0, " #source "\n\t" \ ++ ".set\tmips0" \ ++ : : "r" (val)); \ ++ else \ ++ __asm__ __volatile__( \ ++ ".set\tmips64\n\t" \ ++ "dsll\t%L0, %L0, 32\n\t" \ ++ "dsrl\t%L0, %L0, 32\n\t" \ ++ "dsll\t%M0, %M0, 32\n\t" \ ++ "or\t%L0, %L0, %M0\n\t" \ ++ "dmtc0\t%L0, " #source ", " #sel "\n\t" \ ++ ".set\tmips0" \ ++ : : "r" (val)); \ ++ local_irq_restore(__flags); \ ++} while (0) ++ ++#define read_c0_index() __read_32bit_c0_register($0, 0) ++#define write_c0_index(val) __write_32bit_c0_register($0, 0, val) ++ ++#define read_c0_random() __read_32bit_c0_register($1, 0) ++#define write_c0_random(val) __write_32bit_c0_register($1, 0, val) ++ ++#define read_c0_entrylo0() __read_ulong_c0_register($2, 0) ++#define write_c0_entrylo0(val) __write_ulong_c0_register($2, 0, val) ++ ++#define read_c0_entrylo1() __read_ulong_c0_register($3, 0) ++#define write_c0_entrylo1(val) __write_ulong_c0_register($3, 0, val) ++ ++#define read_c0_conf() __read_32bit_c0_register($3, 0) ++#define write_c0_conf(val) __write_32bit_c0_register($3, 0, val) ++ ++#define read_c0_context() __read_ulong_c0_register($4, 0) ++#define write_c0_context(val) __write_ulong_c0_register($4, 0, val) ++ ++#define read_c0_userlocal() __read_ulong_c0_register($4, 2) ++#define write_c0_userlocal(val) __write_ulong_c0_register($4, 2, val) ++ ++#define read_c0_pagemask() __read_32bit_c0_register($5, 0) ++#define write_c0_pagemask(val) __write_32bit_c0_register($5, 0, val) ++ ++#define read_c0_pagegrain() __read_32bit_c0_register($5, 1) ++#define write_c0_pagegrain(val) __write_32bit_c0_register($5, 1, val) ++ ++#define read_c0_wired() __read_32bit_c0_register($6, 0) ++#define write_c0_wired(val) __write_32bit_c0_register($6, 0, val) ++ ++#define read_c0_info() __read_32bit_c0_register($7, 0) ++ ++#define read_c0_cache() __read_32bit_c0_register($7, 0) /* TX39xx */ ++#define write_c0_cache(val) __write_32bit_c0_register($7, 0, val) ++ ++#define read_c0_badvaddr() __read_ulong_c0_register($8, 0) ++#define write_c0_badvaddr(val) __write_ulong_c0_register($8, 0, val) ++ ++#define read_c0_count() __read_32bit_c0_register($9, 0) ++#define write_c0_count(val) __write_32bit_c0_register($9, 0, val) ++ ++#define read_c0_count2() __read_32bit_c0_register($9, 6) /* pnx8550 */ ++#define write_c0_count2(val) __write_32bit_c0_register($9, 6, val) ++ ++#define read_c0_count3() __read_32bit_c0_register($9, 7) /* pnx8550 */ ++#define write_c0_count3(val) __write_32bit_c0_register($9, 7, val) ++ ++#define read_c0_entryhi() __read_ulong_c0_register($10, 0) ++#define write_c0_entryhi(val) __write_ulong_c0_register($10, 0, val) ++ ++#define read_c0_compare() __read_32bit_c0_register($11, 0) ++#define write_c0_compare(val) __write_32bit_c0_register($11, 0, val) ++ ++#define read_c0_compare2() __read_32bit_c0_register($11, 6) /* pnx8550 */ ++#define write_c0_compare2(val) __write_32bit_c0_register($11, 6, val) ++ ++#define read_c0_compare3() __read_32bit_c0_register($11, 7) /* pnx8550 */ ++#define write_c0_compare3(val) __write_32bit_c0_register($11, 7, val) ++ ++#define read_c0_status() __read_32bit_c0_register($12, 0) ++ ++#define write_c0_status(val) __write_32bit_c0_register($12, 0, val) ++ ++#define read_c0_cause() __read_32bit_c0_register($13, 0) ++#define write_c0_cause(val) __write_32bit_c0_register($13, 0, val) ++ ++#define read_c0_epc() __read_ulong_c0_register($14, 0) ++#define write_c0_epc(val) __write_ulong_c0_register($14, 0, val) ++ ++#define read_c0_prid() __read_32bit_c0_register($15, 0) ++#define read_c0_cmgcrbase() __read_ulong_c0_register($15, 3) ++ ++#define read_c0_config() __read_32bit_c0_register($16, 0) ++#define read_c0_config1() __read_32bit_c0_register($16, 1) ++#define read_c0_config2() __read_32bit_c0_register($16, 2) ++#define read_c0_config3() __read_32bit_c0_register($16, 3) ++#define read_c0_config4() __read_32bit_c0_register($16, 4) ++#define read_c0_config5() __read_32bit_c0_register($16, 5) ++#define read_c0_config6() __read_32bit_c0_register($16, 6) ++#define read_c0_config7() __read_32bit_c0_register($16, 7) ++#define write_c0_config(val) __write_32bit_c0_register($16, 0, val) ++#define write_c0_config1(val) __write_32bit_c0_register($16, 1, val) ++#define write_c0_config2(val) __write_32bit_c0_register($16, 2, val) ++#define write_c0_config3(val) __write_32bit_c0_register($16, 3, val) ++#define write_c0_config4(val) __write_32bit_c0_register($16, 4, val) ++#define write_c0_config5(val) __write_32bit_c0_register($16, 5, val) ++#define write_c0_config6(val) __write_32bit_c0_register($16, 6, val) ++#define write_c0_config7(val) __write_32bit_c0_register($16, 7, val) ++ ++/* ++ * The WatchLo register. There may be up to 8 of them. ++ */ ++#define read_c0_watchlo0() __read_ulong_c0_register($18, 0) ++#define read_c0_watchlo1() __read_ulong_c0_register($18, 1) ++#define read_c0_watchlo2() __read_ulong_c0_register($18, 2) ++#define read_c0_watchlo3() __read_ulong_c0_register($18, 3) ++#define read_c0_watchlo4() __read_ulong_c0_register($18, 4) ++#define read_c0_watchlo5() __read_ulong_c0_register($18, 5) ++#define read_c0_watchlo6() __read_ulong_c0_register($18, 6) ++#define read_c0_watchlo7() __read_ulong_c0_register($18, 7) ++#define write_c0_watchlo0(val) __write_ulong_c0_register($18, 0, val) ++#define write_c0_watchlo1(val) __write_ulong_c0_register($18, 1, val) ++#define write_c0_watchlo2(val) __write_ulong_c0_register($18, 2, val) ++#define write_c0_watchlo3(val) __write_ulong_c0_register($18, 3, val) ++#define write_c0_watchlo4(val) __write_ulong_c0_register($18, 4, val) ++#define write_c0_watchlo5(val) __write_ulong_c0_register($18, 5, val) ++#define write_c0_watchlo6(val) __write_ulong_c0_register($18, 6, val) ++#define write_c0_watchlo7(val) __write_ulong_c0_register($18, 7, val) ++ ++/* ++ * The WatchHi register. There may be up to 8 of them. ++ */ ++#define read_c0_watchhi0() __read_32bit_c0_register($19, 0) ++#define read_c0_watchhi1() __read_32bit_c0_register($19, 1) ++#define read_c0_watchhi2() __read_32bit_c0_register($19, 2) ++#define read_c0_watchhi3() __read_32bit_c0_register($19, 3) ++#define read_c0_watchhi4() __read_32bit_c0_register($19, 4) ++#define read_c0_watchhi5() __read_32bit_c0_register($19, 5) ++#define read_c0_watchhi6() __read_32bit_c0_register($19, 6) ++#define read_c0_watchhi7() __read_32bit_c0_register($19, 7) ++ ++#define write_c0_watchhi0(val) __write_32bit_c0_register($19, 0, val) ++#define write_c0_watchhi1(val) __write_32bit_c0_register($19, 1, val) ++#define write_c0_watchhi2(val) __write_32bit_c0_register($19, 2, val) ++#define write_c0_watchhi3(val) __write_32bit_c0_register($19, 3, val) ++#define write_c0_watchhi4(val) __write_32bit_c0_register($19, 4, val) ++#define write_c0_watchhi5(val) __write_32bit_c0_register($19, 5, val) ++#define write_c0_watchhi6(val) __write_32bit_c0_register($19, 6, val) ++#define write_c0_watchhi7(val) __write_32bit_c0_register($19, 7, val) ++ ++#define read_c0_xcontext() __read_ulong_c0_register($20, 0) ++#define write_c0_xcontext(val) __write_ulong_c0_register($20, 0, val) ++ ++#define read_c0_intcontrol() __read_32bit_c0_ctrl_register($20) ++#define write_c0_intcontrol(val) __write_32bit_c0_ctrl_register($20, val) ++ ++#define read_c0_framemask() __read_32bit_c0_register($21, 0) ++#define write_c0_framemask(val) __write_32bit_c0_register($21, 0, val) ++ ++#define read_c0_diag() __read_32bit_c0_register($22, 0) ++#define write_c0_diag(val) __write_32bit_c0_register($22, 0, val) ++ ++#define read_c0_diag1() __read_32bit_c0_register($22, 1) ++#define write_c0_diag1(val) __write_32bit_c0_register($22, 1, val) ++ ++#define read_c0_diag2() __read_32bit_c0_register($22, 2) ++#define write_c0_diag2(val) __write_32bit_c0_register($22, 2, val) ++ ++#define read_c0_diag3() __read_32bit_c0_register($22, 3) ++#define write_c0_diag3(val) __write_32bit_c0_register($22, 3, val) ++ ++#define read_c0_diag4() __read_32bit_c0_register($22, 4) ++#define write_c0_diag4(val) __write_32bit_c0_register($22, 4, val) ++ ++#define read_c0_diag5() __read_32bit_c0_register($22, 5) ++#define write_c0_diag5(val) __write_32bit_c0_register($22, 5, val) ++ ++#define read_c0_debug() __read_32bit_c0_register($23, 0) ++#define write_c0_debug(val) __write_32bit_c0_register($23, 0, val) ++ ++#define read_c0_depc() __read_ulong_c0_register($24, 0) ++#define write_c0_depc(val) __write_ulong_c0_register($24, 0, val) ++ ++/* ++ * MIPS32 / MIPS64 performance counters ++ */ ++#define read_c0_perfctrl0() __read_32bit_c0_register($25, 0) ++#define write_c0_perfctrl0(val) __write_32bit_c0_register($25, 0, val) ++#define read_c0_perfcntr0() __read_32bit_c0_register($25, 1) ++#define write_c0_perfcntr0(val) __write_32bit_c0_register($25, 1, val) ++#define read_c0_perfcntr0_64() __read_64bit_c0_register($25, 1) ++#define write_c0_perfcntr0_64(val) __write_64bit_c0_register($25, 1, val) ++#define read_c0_perfctrl1() __read_32bit_c0_register($25, 2) ++#define write_c0_perfctrl1(val) __write_32bit_c0_register($25, 2, val) ++#define read_c0_perfcntr1() __read_32bit_c0_register($25, 3) ++#define write_c0_perfcntr1(val) __write_32bit_c0_register($25, 3, val) ++#define read_c0_perfcntr1_64() __read_64bit_c0_register($25, 3) ++#define write_c0_perfcntr1_64(val) __write_64bit_c0_register($25, 3, val) ++#define read_c0_perfctrl2() __read_32bit_c0_register($25, 4) ++#define write_c0_perfctrl2(val) __write_32bit_c0_register($25, 4, val) ++#define read_c0_perfcntr2() __read_32bit_c0_register($25, 5) ++#define write_c0_perfcntr2(val) __write_32bit_c0_register($25, 5, val) ++#define read_c0_perfcntr2_64() __read_64bit_c0_register($25, 5) ++#define write_c0_perfcntr2_64(val) __write_64bit_c0_register($25, 5, val) ++#define read_c0_perfctrl3() __read_32bit_c0_register($25, 6) ++#define write_c0_perfctrl3(val) __write_32bit_c0_register($25, 6, val) ++#define read_c0_perfcntr3() __read_32bit_c0_register($25, 7) ++#define write_c0_perfcntr3(val) __write_32bit_c0_register($25, 7, val) ++#define read_c0_perfcntr3_64() __read_64bit_c0_register($25, 7) ++#define write_c0_perfcntr3_64(val) __write_64bit_c0_register($25, 7, val) ++ ++#define read_c0_ecc() __read_32bit_c0_register($26, 0) ++#define write_c0_ecc(val) __write_32bit_c0_register($26, 0, val) ++ ++#define read_c0_derraddr0() __read_ulong_c0_register($26, 1) ++#define write_c0_derraddr0(val) __write_ulong_c0_register($26, 1, val) ++ ++#define read_c0_cacheerr() __read_32bit_c0_register($27, 0) ++ ++#define read_c0_derraddr1() __read_ulong_c0_register($27, 1) ++#define write_c0_derraddr1(val) __write_ulong_c0_register($27, 1, val) ++ ++#define read_c0_taglo() __read_32bit_c0_register($28, 0) ++#define write_c0_taglo(val) __write_32bit_c0_register($28, 0, val) ++ ++#define read_c0_dtaglo() __read_32bit_c0_register($28, 2) ++#define write_c0_dtaglo(val) __write_32bit_c0_register($28, 2, val) ++ ++#define read_c0_ddatalo() __read_32bit_c0_register($28, 3) ++#define write_c0_ddatalo(val) __write_32bit_c0_register($28, 3, val) ++ ++#define read_c0_staglo() __read_32bit_c0_register($28, 4) ++#define write_c0_staglo(val) __write_32bit_c0_register($28, 4, val) ++ ++#define read_c0_taghi() __read_32bit_c0_register($29, 0) ++#define write_c0_taghi(val) __write_32bit_c0_register($29, 0, val) ++ ++#define read_c0_errorepc() __read_ulong_c0_register($30, 0) ++#define write_c0_errorepc(val) __write_ulong_c0_register($30, 0, val) ++ ++/* MIPSR2 */ ++#define read_c0_hwrena() __read_32bit_c0_register($7, 0) ++#define write_c0_hwrena(val) __write_32bit_c0_register($7, 0, val) ++ ++#define read_c0_intctl() __read_32bit_c0_register($12, 1) ++#define write_c0_intctl(val) __write_32bit_c0_register($12, 1, val) ++ ++#define read_c0_srsctl() __read_32bit_c0_register($12, 2) ++#define write_c0_srsctl(val) __write_32bit_c0_register($12, 2, val) ++ ++#define read_c0_srsmap() __read_32bit_c0_register($12, 3) ++#define write_c0_srsmap(val) __write_32bit_c0_register($12, 3, val) ++ ++#define read_c0_ebase() __read_32bit_c0_register($15, 1) ++#define write_c0_ebase(val) __write_32bit_c0_register($15, 1, val) ++ ++/* MIPSR3 */ ++#define read_c0_segctl0() __read_32bit_c0_register($5, 2) ++#define write_c0_segctl0(val) __write_32bit_c0_register($5, 2, val) ++ ++#define read_c0_segctl1() __read_32bit_c0_register($5, 3) ++#define write_c0_segctl1(val) __write_32bit_c0_register($5, 3, val) ++ ++#define read_c0_segctl2() __read_32bit_c0_register($5, 4) ++#define write_c0_segctl2(val) __write_32bit_c0_register($5, 4, val) ++ ++/* Cavium OCTEON (cnMIPS) */ ++#define read_c0_cvmcount() __read_ulong_c0_register($9, 6) ++#define write_c0_cvmcount(val) __write_ulong_c0_register($9, 6, val) ++ ++#define read_c0_cvmctl() __read_64bit_c0_register($9, 7) ++#define write_c0_cvmctl(val) __write_64bit_c0_register($9, 7, val) ++ ++#define read_c0_cvmmemctl() __read_64bit_c0_register($11, 7) ++#define write_c0_cvmmemctl(val) __write_64bit_c0_register($11, 7, val) ++/* ++ * The cacheerr registers are not standardized. On OCTEON, they are ++ * 64 bits wide. ++ */ ++#define read_octeon_c0_icacheerr() __read_64bit_c0_register($27, 0) ++#define write_octeon_c0_icacheerr(val) __write_64bit_c0_register($27, 0, val) ++ ++#define read_octeon_c0_dcacheerr() __read_64bit_c0_register($27, 1) ++#define write_octeon_c0_dcacheerr(val) __write_64bit_c0_register($27, 1, val) ++ ++/* BMIPS3300 */ ++#define read_c0_brcm_config_0() __read_32bit_c0_register($22, 0) ++#define write_c0_brcm_config_0(val) __write_32bit_c0_register($22, 0, val) ++ ++#define read_c0_brcm_bus_pll() __read_32bit_c0_register($22, 4) ++#define write_c0_brcm_bus_pll(val) __write_32bit_c0_register($22, 4, val) ++ ++#define read_c0_brcm_reset() __read_32bit_c0_register($22, 5) ++#define write_c0_brcm_reset(val) __write_32bit_c0_register($22, 5, val) ++ ++/* BMIPS43xx */ ++#define read_c0_brcm_cmt_intr() __read_32bit_c0_register($22, 1) ++#define write_c0_brcm_cmt_intr(val) __write_32bit_c0_register($22, 1, val) ++ ++#define read_c0_brcm_cmt_ctrl() __read_32bit_c0_register($22, 2) ++#define write_c0_brcm_cmt_ctrl(val) __write_32bit_c0_register($22, 2, val) ++ ++#define read_c0_brcm_cmt_local() __read_32bit_c0_register($22, 3) ++#define write_c0_brcm_cmt_local(val) __write_32bit_c0_register($22, 3, val) ++ ++#define read_c0_brcm_config_1() __read_32bit_c0_register($22, 5) ++#define write_c0_brcm_config_1(val) __write_32bit_c0_register($22, 5, val) ++ ++#define read_c0_brcm_cbr() __read_32bit_c0_register($22, 6) ++#define write_c0_brcm_cbr(val) __write_32bit_c0_register($22, 6, val) ++ ++/* BMIPS5000 */ ++#define read_c0_brcm_config() __read_32bit_c0_register($22, 0) ++#define write_c0_brcm_config(val) __write_32bit_c0_register($22, 0, val) ++ ++#define read_c0_brcm_mode() __read_32bit_c0_register($22, 1) ++#define write_c0_brcm_mode(val) __write_32bit_c0_register($22, 1, val) ++ ++#define read_c0_brcm_action() __read_32bit_c0_register($22, 2) ++#define write_c0_brcm_action(val) __write_32bit_c0_register($22, 2, val) ++ ++#define read_c0_brcm_edsp() __read_32bit_c0_register($22, 3) ++#define write_c0_brcm_edsp(val) __write_32bit_c0_register($22, 3, val) ++ ++#define read_c0_brcm_bootvec() __read_32bit_c0_register($22, 4) ++#define write_c0_brcm_bootvec(val) __write_32bit_c0_register($22, 4, val) ++ ++#define read_c0_brcm_sleepcount() __read_32bit_c0_register($22, 7) ++#define write_c0_brcm_sleepcount(val) __write_32bit_c0_register($22, 7, val) ++ ++/* ++ * Macros to access the floating point coprocessor control registers ++ */ ++#define read_32bit_cp1_register(source) \ ++({ \ ++ int __res; \ ++ \ ++ __asm__ __volatile__( \ ++ " .set push \n" \ ++ " .set reorder \n" \ ++ " # gas fails to assemble cfc1 for some archs, \n" \ ++ " # like Octeon. \n" \ ++ " .set mips1 \n" \ ++ " cfc1 %0,"STR(source)" \n" \ ++ " .set pop \n" \ ++ : "=r" (__res)); \ ++ __res; \ ++}) ++ ++#define write_32bit_cp1_register(dest,value) \ ++({ \ ++ __asm__ __volatile__( \ ++ " .set push \n" \ ++ " .set reorder \n" \ ++ " # gas fails to assemble cfc1 for some archs, \n" \ ++ " # like Octeon. \n" \ ++ " .set mips1 \n" \ ++ " ctc1 %0,"STR(dest)" \n" \ ++ " .set pop \n" \ ++ :: "r" (value)); \ ++}) ++ ++/* ++ * Macros to access the DSP ASE registers ++ */ ++ ++#define rddsp(mask) \ ++({ \ ++ unsigned int __res; \ ++ \ ++ __asm__ __volatile__( \ ++ " .set push \n" \ ++ " .set dsp \n" \ ++ " .set noat \n" \ ++ " # rddsp $1, %x1 \n" \ ++ " .word 0x7c000cb8 | (%x1 << 16) \n" \ ++ " move %0, $1 \n" \ ++ " .set pop \n" \ ++ : "=r" (__res) \ ++ : "i" (mask)); \ ++ __res; \ ++}) ++ ++#define wrdsp(val, mask) \ ++do { \ ++ __asm__ __volatile__( \ ++ " .set push \n" \ ++ " .set dsp \n" \ ++ " .set noat \n" \ ++ " move $1, %0 \n" \ ++ " # wrdsp $1, %x1 \n" \ ++ " .word 0x7c2004f8 | (%x1 << 11) \n" \ ++ " .set pop \n" \ ++ : \ ++ : "r" (val), "i" (mask)); \ ++} while (0) ++ ++#define _dsp_mfxxx(ins) \ ++({ \ ++ unsigned long __treg; \ ++ \ ++ __asm__ __volatile__( \ ++ " .set push \n" \ ++ " .set dsp \n" \ ++ " .set noat \n" \ ++ " .word (0x00000810 | %1) \n" \ ++ " move %0, $1 \n" \ ++ " .set pop \n" \ ++ : "=r" (__treg) \ ++ : "i" (ins)); \ ++ __treg; \ ++}) ++ ++#define _dsp_mtxxx(val, ins) \ ++do { \ ++ __asm__ __volatile__( \ ++ " .set push \n" \ ++ " .set dsp \n" \ ++ " .set noat \n" \ ++ " move $1, %0 \n" \ ++ " .word (0x00200011 | %1) \n" \ ++ " .set pop \n" \ ++ : \ ++ : "r" (val), "i" (ins)); \ ++} while (0) ++ ++#define _dsp_mflo(reg) _dsp_mfxxx((reg << 21) | 0x0002) ++#define _dsp_mfhi(reg) _dsp_mfxxx((reg << 21) | 0x0000) ++ ++#define _dsp_mtlo(val, reg) _dsp_mtxxx(val, ((reg << 11) | 0x0002)) ++#define _dsp_mthi(val, reg) _dsp_mtxxx(val, ((reg << 11) | 0x0000)) ++ ++#define mflo0() _dsp_mflo(0) ++#define mflo1() _dsp_mflo(1) ++#define mflo2() _dsp_mflo(2) ++#define mflo3() _dsp_mflo(3) ++ ++#define mfhi0() _dsp_mfhi(0) ++#define mfhi1() _dsp_mfhi(1) ++#define mfhi2() _dsp_mfhi(2) ++#define mfhi3() _dsp_mfhi(3) ++ ++#define mtlo0(x) _dsp_mtlo(x, 0) ++#define mtlo1(x) _dsp_mtlo(x, 1) ++#define mtlo2(x) _dsp_mtlo(x, 2) ++#define mtlo3(x) _dsp_mtlo(x, 3) ++ ++#define mthi0(x) _dsp_mthi(x, 0) ++#define mthi1(x) _dsp_mthi(x, 1) ++#define mthi2(x) _dsp_mthi(x, 2) ++#define mthi3(x) _dsp_mthi(x, 3) ++ ++/* ++ * TLB operations. ++ * ++ * It is responsibility of the caller to take care of any TLB hazards. ++ */ ++static inline void tlb_probe(void) ++{ ++ __asm__ __volatile__( ++ ".set noreorder\n\t" ++ "tlbp\n\t" ++ ".set reorder"); ++} ++ ++static inline void tlb_read(void) ++{ ++ ++ __asm__ __volatile__( ++ ".set noreorder\n\t" ++ "tlbr\n\t" ++ ".set reorder"); ++} ++ ++static inline void tlb_write_indexed(void) ++{ ++ __asm__ __volatile__( ++ ".set noreorder\n\t" ++ "tlbwi\n\t" ++ ".set reorder"); ++} ++ ++static inline void tlb_write_random(void) ++{ ++ __asm__ __volatile__( ++ ".set noreorder\n\t" ++ "tlbwr\n\t" ++ ".set reorder"); ++} ++ ++static inline void tlbinvf(void) ++{ ++ __asm__ __volatile__( ++ ".set push\n\t" ++ ".set noreorder\n\t" ++ ".word 0x42000004\n\t" ++ ".set pop"); ++} ++ ++/* ++ * SMTC Linux requires shutting-down microthread scheduling ++ * during CP0 register read-modify-write sequences. ++ */ ++#define __BUILD_SET_C0(name) \ ++static inline unsigned int \ ++set_c0_##name(unsigned int set) \ ++{ \ ++ unsigned int res, new; \ ++ \ ++ res = read_c0_##name(); \ ++ new = res | set; \ ++ write_c0_##name(new); \ ++ \ ++ return res; \ ++} \ ++ \ ++static inline unsigned int \ ++clear_c0_##name(unsigned int clear) \ ++{ \ ++ unsigned int res, new; \ ++ \ ++ res = read_c0_##name(); \ ++ new = res & ~clear; \ ++ write_c0_##name(new); \ ++ \ ++ return res; \ ++} \ ++ \ ++static inline unsigned int \ ++change_c0_##name(unsigned int change, unsigned int val) \ ++{ \ ++ unsigned int res, new; \ ++ \ ++ res = read_c0_##name(); \ ++ new = res & ~change; \ ++ new |= (val & change); \ ++ write_c0_##name(new); \ ++ \ ++ return res; \ ++} ++ ++ ++__BUILD_SET_C0(status) ++__BUILD_SET_C0(cause) ++__BUILD_SET_C0(config) ++__BUILD_SET_C0(intcontrol) ++__BUILD_SET_C0(intctl) ++__BUILD_SET_C0(srsmap) ++__BUILD_SET_C0(brcm_config_0) ++__BUILD_SET_C0(brcm_bus_pll) ++__BUILD_SET_C0(brcm_reset) ++__BUILD_SET_C0(brcm_cmt_intr) ++__BUILD_SET_C0(brcm_cmt_ctrl) ++__BUILD_SET_C0(brcm_config) ++__BUILD_SET_C0(brcm_mode) ++ ++#endif /* _ASM_MIPSREGS_H */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_include_pm_sleep.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_include_pm_sleep.h.patch new file mode 100644 index 00000000..a511ae8d --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_include_pm_sleep.h.patch @@ -0,0 +1,26 @@ +diff -drupN a/tools/pm-sleep/include/pm_sleep.h b/tools/pm-sleep/include/pm_sleep.h +--- a/tools/pm-sleep/include/pm_sleep.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/tools/pm-sleep/include/pm_sleep.h 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,22 @@ ++#ifndef SLEEP_H ++#define SLEEP_H ++struct sleep_param ++{ ++ unsigned int pm_core_enter; ++ unsigned char pmu_i2c_scl; //default 0xff ++ unsigned char pmu_i2c_sda; //default 0xff ++ unsigned char pmu_addr; //default 0xff ++ unsigned char pmu_reg; //default 0xff ++ unsigned char pmu_register_val; ++ ++ unsigned char pmu_pin; //default 0xff ++ unsigned char pmu_pin_func; //default 0xff ++ unsigned char uart_id; //default 0xff ++ ++ unsigned int prev_resume_pc; //ddr is self-reflash default 0xffffffff ++ unsigned int post_resume_pc; //ddr is ok. default 0xffffffff ++ unsigned int prev_sleep_pc; //after flush cache. default 0xffffffff ++ unsigned int post_sleep_pc; //before wait. default 0xffffffff ++}; ++ ++#endif /* SLEEP_H */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_include_smp_cp0.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_include_smp_cp0.h.patch new file mode 100644 index 00000000..70b1257e --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_include_smp_cp0.h.patch @@ -0,0 +1,50 @@ +diff -drupN a/tools/pm-sleep/include/smp_cp0.h b/tools/pm-sleep/include/smp_cp0.h +--- a/tools/pm-sleep/include/smp_cp0.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/tools/pm-sleep/include/smp_cp0.h 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,46 @@ ++#ifndef __SMP_CP0_H__ ++#define __SMP_CP0_H__ ++#include ++ ++#define get_smp_ctrl() __read_32bit_c0_register($12, 2) ++#define set_smp_ctrl(val) __write_32bit_c0_register($12, 2, val) ++#define get_smp_status() __read_32bit_c0_register($12, 3) ++#define set_smp_status(val) __write_32bit_c0_register($12, 3, val) ++#define get_smp_reim() __read_32bit_c0_register($12, 4) ++#define set_smp_reim(val) __write_32bit_c0_register($12, 4, val) ++#define get_smp_lock() __read_32bit_c0_register($12, 5) ++#define set_smp_lock(val) __write_32bit_c0_register($12, 5, val) ++#define get_smp_val() __read_32bit_c0_register($12, 6) ++#define set_smp_val(val) __write_32bit_c0_register($12, 6, val) ++ ++#define get_smp_mbox0() __read_32bit_c0_register($20, 0) ++#define set_smp_mbox0(val) __write_32bit_c0_register($20, 0, val) ++#define get_smp_mbox1() __read_32bit_c0_register($20, 1) ++#define set_smp_mbox1(val) __write_32bit_c0_register($20, 1, val) ++#define get_smp_mbox2() __read_32bit_c0_register($20, 2) ++#define set_smp_mbox2(val) __write_32bit_c0_register($20, 2, val) ++#define get_smp_mbox3() __read_32bit_c0_register($20, 3) ++#define set_smp_mbox3(val) __write_32bit_c0_register($20, 3, val) ++ ++ ++#define smp_ipi_unmask(mask) do { \ ++ unsigned int reim; \ ++ reim = get_smp_reim(); \ ++ reim |= (mask) & 0xff; \ ++ set_smp_reim(reim); \ ++ } while(0) ++#define smp_ipi_mask(mask) do { \ ++ unsigned int reim; \ ++ reim = get_smp_reim(); \ ++ reim &= ~((mask) & 0xff); \ ++ set_smp_reim(reim); \ ++ } while(0) ++ ++#define smp_clr_pending(mask) do { \ ++ unsigned int stat; \ ++ stat = get_smp_status(); \ ++ stat &= ~((mask) & 0xff); \ ++ set_smp_status(stat); \ ++ } while(0) ++ ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_include_uart.h.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_include_uart.h.patch new file mode 100644 index 00000000..1f7ebaa9 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_include_uart.h.patch @@ -0,0 +1,21 @@ +diff -drupN a/tools/pm-sleep/include/uart.h b/tools/pm-sleep/include/uart.h +--- a/tools/pm-sleep/include/uart.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/tools/pm-sleep/include/uart.h 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,17 @@ ++#ifndef __UART_H__ ++#define __UART_H__ ++#define TCSM_DELAY(x) \ ++ do{ \ ++ register unsigned int i = x; \ ++ while(i--) \ ++ __asm__ volatile(".set push \n\t" \ ++ ".set mips32\n\t" \ ++ "nop\n\t" \ ++ ".set mips32\n\t" \ ++ ".set pop \n\t"); \ ++ }while(0) ++ ++void serial_putc(char x); ++void serial_put_hex(unsigned int x); ++void serial_setid(int uart_id); ++#endif /* __UART_H__ */ diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_pm_sleep.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_pm_sleep.c.patch new file mode 100644 index 00000000..a2a7eaa0 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_pm_sleep.c.patch @@ -0,0 +1,317 @@ +diff -drupN a/tools/pm-sleep/pm_sleep.c b/tools/pm-sleep/pm_sleep.c +--- a/tools/pm-sleep/pm_sleep.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/tools/pm-sleep/pm_sleep.c 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,313 @@ ++ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++unsigned int *extern_func; ++ ++struct sleep_param *p_slp_param; ++extern void scale_cpu_freq(int status, unsigned int *cpccr); ++ ++struct save_register ++{ ++ unsigned int ddr_autosr; ++ unsigned int ddr_dlp; ++ unsigned int ddr_ctrl; ++ unsigned int cpm_cpccr; ++ unsigned int c0_config; ++ unsigned int c0_status; ++ unsigned int smp_cp0_ctrl; ++ ++ ++ unsigned char pmu_pin_func; ++ unsigned char pmu_register_val; ++}; ++ ++static struct save_register g_save_register; ++/* static void i2c_sleep_set_data(void) */ ++/* { */ ++/* struct i2c_gpio i2c; */ ++/* unsigned int ret; */ ++/* if(p_slp_param->pmu_addr != 0xff){ */ ++/* i2c.scl = p_slp_param->pmu_i2c_scl; */ ++/* i2c.sda = p_slp_param->pmu_i2c_sda; */ ++/* ret = i2c_read(&i2c, */ ++/* p_slp_param->pmu_addr, p_slp_param->pmu_reg, 1, */ ++/* &g_save_register.pmu_register_val, 1); */ ++/* if(ret != 0) */ ++/* { */ ++/* p_slp_param->pmu_addr = -1; */ ++/* }else */ ++/* ret = i2c_write(&i2c, */ ++/* p_slp_param->pmu_addr, p_slp_param->pmu_reg, 1, */ ++/* &p_slp_param->pmu_register_val, 1); */ ++/* i2c_reinit(&i2c); */ ++/* } */ ++/* } */ ++/* static int i2c_restore_data(void) */ ++/* { */ ++/* struct i2c_gpio i2c; */ ++/* unsigned char val; */ ++/* int ret = 0; */ ++/* if(p_slp_param->pmu_addr != 0xff){ */ ++ ++/* i2c.scl = p_slp_param->pmu_i2c_scl; */ ++/* i2c.sda = p_slp_param->pmu_i2c_sda; */ ++/* ret = i2c_write(&i2c, */ ++/* p_slp_param->pmu_addr, p_slp_param->pmu_reg, 1, */ ++/* &g_save_register.pmu_register_val, 1); */ ++/* if(ret != 0) */ ++/* return -1; */ ++/* ret = i2c_read(&i2c, */ ++/* p_slp_param->pmu_addr, p_slp_param->pmu_reg, 1, */ ++/* &val, 1); */ ++/* if(ret != 0) */ ++/* return -1; */ ++/* if(val != g_save_register.pmu_register_val) */ ++/* { */ ++/* return -1; */ ++/* } */ ++ ++/* } */ ++/* return 0; */ ++/* } */ ++ ++ ++void sleep_pm_exit(); ++void call_function(unsigned int pc, int arg); ++int set_core_voltage(int vol_mv); ++void core_sleep_enter(void) ++{ ++ unsigned int val; ++ struct save_register *p_save_register = &g_save_register; ++ ++ serial_setid(p_slp_param->uart_id); ++ ++ flush_cache_all(); ++ set_resume_pc((unsigned int)sleep_pm_exit); ++ ++ if(p_slp_param->prev_sleep_pc != 0xffffffff) { ++ /* serial_put_hex(p_slp_param->prev_sleep_pc); */ ++ call_function(p_slp_param->prev_sleep_pc, 0); ++ } ++ ++ p_save_register->c0_config = read_c0_config(); ++ p_save_register->c0_status = read_c0_status(); ++ ++ ddr_writel(0x0, DDRP_DTAR); ++ p_save_register->ddr_autosr = ddr_readl(DDRC_AUTOSR_EN); ++ ddr_writel(0,DDRC_AUTOSR_EN); // exit auto sel-refresh ++ p_save_register->ddr_dlp = ddr_readl(DDRC_DLP); ++ if(!(ddr_readl(DDRP_PIR) & DDRP_PIR_DLLBYP)) ++ { ++ ddr_writel(0xf003 , DDRC_DLP); ++ /* val = ddr_readl(DDRP_DSGCR); */ ++ /* val |= (1 << 4); */ ++ /* ddr_writel(val,DDRP_DSGCR); */ ++ } ++ /** ++ * DDR keep selrefresh,when it exit the sleep state. ++ */ ++ val = ddr_readl(DDRC_CTRL); ++ p_save_register->ddr_ctrl = val; ++ val &= ~(0x1f << 11); // remove power down. ++ val |= (1 << 17) | (1 << 5); // enter to hold ddr state ++ ddr_writel(val,DDRC_CTRL); ++ ++ scale_cpu_freq(SCALE, &p_save_register->cpm_cpccr); ++ ++ // DDR CLK GATE OFF ++ /* cpm_set_bit(31,CPM_CLKGR); */ ++ ++ p_save_register->smp_cp0_ctrl = __read_32bit_c0_register($12, 2); /* cache attr */ ++ __write_32bit_c0_register($12, 2, p_save_register->smp_cp0_ctrl | (1<<31)); ++ ++ /* i2c_sleep_set_data(); */ ++ if(p_slp_param->pmu_pin_func != 0xff) ++ { ++ p_save_register->pmu_pin_func = get_gpio_func(p_slp_param->pmu_pin); ++ set_gpio_func(p_slp_param->pmu_pin,p_slp_param->pmu_pin_func); ++ }else ++ p_save_register->pmu_pin_func = 0xff; ++ ++ if(p_slp_param->post_sleep_pc != 0xffffffff) ++ { ++ /* serial_put_hex(p_slp_param->post_sleep_pc); */ ++ call_function(p_slp_param->post_sleep_pc, 0); ++ } ++ write_c0_status(p_save_register->c0_status | 1 << 10); ++ /* serial_put_hex(cpm_inl(CPM_OPCR)); */ ++ serial_putc('e'); ++ __asm__ volatile(".set push\n\t" ++ ".set mips32\n\t" ++ "sync \n\t" ++ "nop\n\t" ++ "wait\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ "jr %0\n\t" ++ ".set mips32 \n\t" ++ ".set pop\n\t" ++ : ++ :"r" ((unsigned int)sleep_pm_exit)); ++ while(1) ++ serial_putc('E'); ++ ++} ++ ++ ++void core_sleep_restore(void) ++{ ++ int val = 0; ++ int bypassmode = 0; ++ struct save_register *p_save_register = &g_save_register; ++ ++ serial_putc('O'); ++ ++ write_c0_config(p_save_register->c0_config); ++ write_c0_status(p_save_register->c0_status); ++ ++ /* ++ * For voice triger in sleep mode of pmu. ++ */ ++ /* if(i2c_restore_data() != 0) */ ++ /* { */ ++ /* serial_putc('E'); */ ++ /* serial_putc('v'); */ ++ /* __asm__ volatile(".set mips32\n\t" */ ++ /* "wait\n\t" */ ++ /* "nop\n\t" */ ++ /* ".set mips32 \n\t"); */ ++ /* } */ ++ ++ if(p_slp_param->prev_resume_pc != 0xffffffff) ++ { ++ __jz_cache_init(); ++ /* serial_put_hex(p_slp_param->prev_resume_pc); */ ++ call_function(p_slp_param->prev_resume_pc, p_save_register->cpm_cpccr); ++ } ++ ++ if(p_slp_param->pmu_pin != 0xff) ++ { ++ set_gpio_func(p_slp_param->pmu_pin,p_save_register->pmu_pin_func); ++ } ++ ++ scale_cpu_freq(RESTORE, &p_save_register->cpm_cpccr); ++ ++ // DDR CLK GATE ON ++ /* cpm_clear_bit(31,CPM_CLKGR); */ ++ ++ bypassmode = ddr_readl(DDRP_PIR) & DDRP_PIR_DLLBYP; ++ if(!bypassmode) { ++ /** ++ * reset dll of ddr. ++ * WARNING: 2015-01-08 ++ * DDR CLK GATE(CPM_DRCG 0xB00000D0), BIT6 must set to 1 (or 0x40). ++ * If clear BIT6, chip memory will not stable, gpu hang occur. ++ */ ++ /* { */ ++ /* val = ddr_readl(DDRP_DSGCR); */ ++ /* val &= ~(1 << 4); */ ++ /* ddr_writel(val,DDRP_DSGCR); */ ++ /* } */ ++#define CPM_DRCG (0xB00000D0) ++ ++ *(volatile unsigned int *)CPM_DRCG |= (1<<1); ++ TCSM_DELAY(0x1ff); ++ *(volatile unsigned int *)CPM_DRCG &= ~(1<<1); ++ TCSM_DELAY(0x1ff); ++ /* ++ * for disabled ddr enter power down. ++ */ ++ *(volatile unsigned int *)0xb301102c &= ~(1 << 4); ++ TCSM_DELAY(0xf); ++ ++ /* ++ * reset dll of ddr too. ++ */ ++ *(volatile unsigned int *)CPM_DRCG |= (1<<1); ++ TCSM_DELAY(0x1ff); ++ *(volatile unsigned int *)CPM_DRCG &= ~(1<<1); ++ TCSM_DELAY(0x1ff); ++ ++ val = DDRP_PIR_INIT | DDRP_PIR_ITMSRST | DDRP_PIR_DLLSRST | DDRP_PIR_DLLLOCK;// | DDRP_PIR_ZCAL ; ++ ddr_writel(val, DDRP_PIR); ++ val = DDRP_PGSR_IDONE | DDRP_PGSR_DLDONE | DDRP_PGSR_DIDONE;// | DDRP_PGSR_ZCDONE; ++ while ((ddr_readl(DDRP_PGSR) & val) != val) { ++ if(ddr_readl(DDRP_PGSR) & (DDRP_PGSR_DTERR | DDRP_PGSR_DTIERR)) { ++ serial_putc('e'); ++ break; ++ } ++ serial_put_hex(ddr_readl(DDRP_ZQXCR0(0))); ++ serial_put_hex(ddr_readl(DDRP_ZQXSR0(0))); ++ serial_put_hex(ddr_readl(DDRP_PGSR)); ++ serial_putc('\r'); ++ serial_putc('\n'); ++ } ++ } ++ ++ /* exit the ddr selrefresh */ ++ val = ddr_readl(DDRC_CTRL); ++ val |= 1 << 1; ++ val &= ~((1<< 17) | (1 << 5)); // exit to hold ddr state ++ ddr_writel(val,DDRC_CTRL); ++ /* ddr trainning. */ ++ if(!bypassmode){ ++ val = DDRP_PIR_INIT | DDRP_PIR_QSTRN; ++ }else ++ val = DDRP_PIR_INIT | DDRP_PIR_QSTRN | DDRP_PIR_DLLBYP; ++ ddr_writel(val, DDRP_PIR); ++ val = (DDRP_PGSR_IDONE | DDRP_PGSR_DLDONE | DDRP_PGSR_DIDONE | DDRP_PGSR_DTDONE); ++ while ((ddr_readl(DDRP_PGSR) & val) != val) { ++ if(ddr_readl(DDRP_PGSR) & (DDRP_PGSR_DTERR | DDRP_PGSR_DTIERR)) { ++ serial_putc('e'); ++ break; ++ } ++ serial_put_hex(ddr_readl(DDRP_PGSR)); ++ serial_putc('\r'); ++ serial_putc('\n'); ++ } ++ ++ if(!bypassmode) ++ { ++ *(volatile unsigned int *)0xb301102c |= (1 << 4); ++ TCSM_DELAY(0xf); ++ } ++ ++ /* serial_putc('d'); */ ++ /* serial_put_hex(*(unsigned int *)p_slp_param->post_resume_pc); */ ++ ++ if(!p_save_register->ddr_dlp && !bypassmode) ++ { ++ ddr_writel(0x0 , DDRC_DLP); ++ } ++ if(p_save_register->ddr_autosr) { ++ ddr_writel(1,DDRC_AUTOSR_EN); // enter auto sel-refresh ++ } ++ ddr_writel(p_save_register->ddr_ctrl, DDRC_CTRL); ++ ++ l2cache_enable(); ++// dump_ddr_param(); ++ __jz_cache_init(); ++ ++ /* serial_put_hex(*(unsigned int *)p_slp_param->post_resume_pc); */ ++ __write_32bit_c0_register($12, 2,p_save_register->smp_cp0_ctrl); ++ if(p_slp_param->post_resume_pc != 0xfffffff) ++ { ++ call_function(p_slp_param->post_resume_pc, 0); ++ } ++ ++ while(1) ++ serial_putc('s'); ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_start.S.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_start.S.patch new file mode 100644 index 00000000..cea03c6f --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_start.S.patch @@ -0,0 +1,193 @@ +diff -drupN a/tools/pm-sleep/start.S b/tools/pm-sleep/start.S +--- a/tools/pm-sleep/start.S 1970-01-01 03:00:00.000000000 +0300 ++++ b/tools/pm-sleep/start.S 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,189 @@ ++#define zero $0 /* wired zero */ ++#define AT $1 /* assembler temp - uppercase because of ".set at" */ ++#define v0 $2 /* return value */ ++#define v1 $3 ++#define a0 $4 /* argument registers */ ++#define a1 $5 ++#define a2 $6 ++#define a3 $7 ++#define t0 $8 /* caller saved */ ++#define t1 $9 ++#define t2 $10 ++#define t3 $11 ++#define t4 $12 ++#define t5 $13 ++#define t6 $14 ++#define t7 $15 ++#define s0 $16 /* callee saved */ ++#define s1 $17 ++#define s2 $18 ++#define s3 $19 ++#define s4 $20 ++#define s5 $21 ++#define s6 $22 ++#define s7 $23 ++#define t8 $24 /* caller saved */ ++#define t9 $25 ++#define jp $25 /* PIC jump register */ ++#define k0 $26 /* kernel scratch */ ++#define k1 $27 ++#define gp $28 /* global pointer */ ++#define sp $29 /* stack pointer */ ++#define fp $30 /* frame pointer */ ++#define s8 $30 /* same like fp! */ ++#define ra $31 /* return address */ ++ ++ .set noreorder ++ .section _start_section ++ .text ++ .globl _start ++ .ent _start ++_start: ++ //-------- a0 <- load address ++ //------- -T 0 ++ addu sp,sp,-12 ++ sw gp,0(sp) ++ sw ra,4(sp) ++ sw t9,8(sp) ++ /* Initialize $gp */ ++ bal 1f ++ nop ++ .word _gp ++ .word __rel_dyn_end ++ .word __rel_dyn_start ++ .word __image_copy_end ++ .word _GLOBAL_OFFSET_TABLE_ ++ .word num_got_entries ++ ++1: ++ lw gp, 0(ra) ++ addu gp,gp,a0 ++ //---------------------------------------------------------------------- ++ lw t3, 20(ra) # t3 <-- num_got_entries ++ lw t4, 16(ra) # t4 <-- _GLOBAL_OFFSET_TABLE_ ++ addu t4, a0,t4 # t4 now holds relocated _G_O_T_ ++ addi t4, t4, 8 # skipping first two entries ++ li t2, 2 ++1: ++ lw t1, 0(t4) ++ addu t1, a0 ++ sw t1, 0(t4) ++2: ++ addi t2, 1 ++ blt t2, t3, 1b ++ addi t4, 4 ++ //---------------------------------------------------------------------- ++ lw t2, 4(ra) // <- __rel_dyn_end ++ lw t1, 8(ra) // <- __rel_dyn_start ++ ++ addu t2,t2,a0 ++ addu t1,t1,a0 ++ ++ b 2f # skip first reserved entry ++ addi t1, 8 ++ ++1: ++ lw t3, -4(t1) # t3 <-- relocation info ++ ++ sub t3, 3 ++ bnez t3, 2f # skip non R_MIPS_REL32 entries ++ nop ++ ++ lw t3, -8(t1) # t3 <-- location to fix up in FLASH ++ addu t3, a0 # t3 <-- location to fix up in RAM ++ ++ lw t4, 0(t3) # t4 <-- original pointer ++ addu t4, a0 # t4 <-- adjusted pointer ++ sw t4, 0(t3) ++ ++2: ++ blt t1, t2, 1b ++ addi t1, 8 # each rel.dyn entry is 8 bytes ++ ++ ++ la t1, __bss_start # t1 <-- __bss_start ++ la t2, __bss_end # t2 <-- __bss_end ++1: ++ sw zero, 0(t1) ++ blt t1, t2, 1b ++ addi t1, 4 ++ ++ la t0,extern_func ++ sw a1,0(t0) ++ ++ move t3,a0 ++ la t0,p_slp_param ++ sw t3,0(t0) ++ la t2,sleep_pm_enter ++ sw t2,0(t3) ++ ++ addu t3,t3,4 ++ la t2,0xffffffff ++ addi t1,t3,0x40 ++1: ++ sw t2,0(t3) ++ addu t3,t3,4 ++ bne t1,t3,1b ++ nop ++ ++ lw gp,0(sp) ++ lw ra,4(sp) ++ lw t9,8(sp) ++ addu sp,sp,12 ++ jr ra ++ nop ++ .end _start ++ ++ .space 256 ++ .globl sleep_pm_enter ++sleep_pm_enter: ++ .ent sleep_pm_enter ++ .type sleep_pm_enter,@function ++ .set noreorder ++ bal 1f ++ nop ++1: ++ addu t9,ra,4 ++ .cpload t9 ++ addiu sp,ra,-4 ++ la t9,core_sleep_enter ++ jr t9 ++ nop ++ .end sleep_pm_enter ++ ++sleep_pm_exit: ++ .globl sleep_pm_exit ++ .ent sleep_pm_exit ++ .set noreorder ++ bal 1f ++ nop ++1: ++ addu t9,ra,4 ++ .cpload t9 ++ //set sp ++ addiu sp,ra,-16 ++ la t9,core_sleep_restore ++ jr t9 ++ nop ++ .end sleep_pm_exit ++ ++call_function: ++ .globl call_function ++ .ent call_function ++ .set noreorder ++ addu sp,sp,-16 ++ sw gp,0(sp) ++ sw ra,4(sp) ++ sw t9,8(sp) ++ move t9,a0 ++ move a0,a1 ++ ++ jalr t9 ++ nop ++ lw gp,0(sp) ++ lw ra,4(sp) ++ lw t9,8(sp) ++ addu sp,sp,16 ++ jr ra ++ nop ++ .end call_function diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_u-boot.lds.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_u-boot.lds.patch new file mode 100644 index 00000000..f154a0ac --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_u-boot.lds.patch @@ -0,0 +1,97 @@ +diff -drupN a/tools/pm-sleep/u-boot.lds b/tools/pm-sleep/u-boot.lds +--- a/tools/pm-sleep/u-boot.lds 1970-01-01 03:00:00.000000000 +0300 ++++ b/tools/pm-sleep/u-boot.lds 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,93 @@ ++OUTPUT_ARCH(mips) ++ENTRY(_start) ++SECTIONS ++{ ++ . = 0x00000000; ++ . = ALIGN(4); ++ .text : { ++ __start = .; ++ *(.start_section*) ++ *(.text*) ++ } ++ . = ALIGN(4); ++ .rodata : { ++ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) ++ } ++ . = ALIGN(4); ++ .data : { ++ *(.data*) ++ } ++ . = .; ++ _gp = ALIGN(16) + 0x7ff0; ++ .got : { ++ *(.got) ++ } ++ num_got_entries = SIZEOF(.got) >> 2; ++ . = ALIGN(4); ++ .sdata : { ++ *(.sdata*) ++ } ++ . = ALIGN(4); ++ .u_boot_list : { ++ KEEP(*(SORT(.u_boot_list*))); ++ } ++ . = ALIGN(4); ++ __image_copy_end = .; ++ __init_end = .; ++ ++ .rel.dyn : { ++ __rel_dyn_start = .; ++ *(.rel.dyn) ++ __rel_dyn_end = .; ++ } ++ .deadcode : { ++ LONG(0xffffffff); ++ } ++ ++ _end = .; ++ ++ .bss __rel_dyn_start (OVERLAY) : { ++ __bss_start = .; ++ *(.sbss.*) ++ *(.bss.*) ++ *(COMMON) ++ . = ALIGN(4); ++ __bss_end = .; ++ } ++ ++ .dynsym _end : { ++ *(.dynsym) ++ } ++ ++ .dynbss : { ++ *(.dynbss) ++ } ++ ++ .dynstr : { ++ *(.dynstr) ++ } ++ ++ .dynamic : { ++ *(.dynamic) ++ } ++ ++ .plt : { ++ *(.plt) ++ } ++ ++ .interp : { ++ *(.interp) ++ } ++ ++ .gnu : { ++ *(.gnu*) ++ } ++ ++ .MIPS.stubs : { ++ *(.MIPS.stubs) ++ } ++ ++ .hash : { ++ *(.hash) ++ } ++} diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_uart.c.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_uart.c.patch new file mode 100644 index 00000000..854e2b9e --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_uart.c.patch @@ -0,0 +1,64 @@ +diff -drupN a/tools/pm-sleep/uart.c b/tools/pm-sleep/uart.c +--- a/tools/pm-sleep/uart.c 1970-01-01 03:00:00.000000000 +0300 ++++ b/tools/pm-sleep/uart.c 2022-06-09 05:02:37.000000000 +0300 +@@ -0,0 +1,60 @@ ++#include ++#include ++#include ++ ++void udelay(int d) ++{ ++ do{ ++ __asm__ __volatile__ ("nop \n\t"); ++ d -= (1000 + 23)/ 24 * 2; ++ }while(d > 0); ++ ++} ++ ++#ifdef DEBUG ++ ++#define OFF_TDR (0x00) ++#define OFF_LCR (0x0C) ++#define OFF_LSR (0x14) ++ ++#define LSR_TDRQ (1 << 5) ++#define LSR_TEMT (1 << 6) ++ ++static unsigned int U_IOBASE = (0x10030000 + 0xa0000000); ++static unsigned int U_ADDR = 0; ++void serial_setid(int uart_id) ++{ ++ if(uart_id != 0xff) ++ U_ADDR = U_IOBASE + uart_id * 0x1000; ++ else ++ U_ADDR = 0; ++} ++void serial_putc(char x) ++{ ++ if(U_ADDR){ ++ REG32(U_ADDR + OFF_TDR) = x; ++ while ((REG32(U_ADDR + OFF_LSR) & (LSR_TDRQ | LSR_TEMT)) != (LSR_TDRQ | LSR_TEMT)); ++ } ++} ++void serial_put_hex(unsigned int x) ++{ ++ int i; ++ unsigned int d; ++ for(i = 7;i >= 0;i--) { ++ d = (x >> (i * 4)) & 0xf; ++ if(d < 10) d += '0'; ++ else d += 'A' - 10; ++ serial_putc(d); ++ } ++} ++#else ++void serial_setid(int uart_id) ++{ ++} ++void serial_putc(char x) ++{ ++} ++void serial_put_hex(unsigned int x) ++{ ++} ++#endif diff --git a/br-ext-chip-ingenic/board/t40/kernel/patches/00001-change_phy_clk_freq.patch b/br-ext-chip-ingenic/board/t40/kernel/patches/00001-change_phy_clk_freq.patch new file mode 100644 index 00000000..4dde3096 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/patches/00001-change_phy_clk_freq.patch @@ -0,0 +1,12 @@ +diff -Naur a/arch/mips/boot/dts/ingenic/shark.dts b/arch/mips/boot/dts/ingenic/shark.dts +--- a/arch/mips/boot/dts/ingenic/shark.dts 2023-04-21 19:13:07.904606139 +0300 ++++ b/arch/mips/boot/dts/ingenic/shark.dts 2023-04-21 21:14:03.645013643 +0300 +@@ -118,7 +118,7 @@ + ingenic,rst-ms = <10>; + ingenic,mac-mode = ; + ingenic,mode-reg = <0xb00000e4>; +- ingenic,phy-clk-freq = <50000000>; ++ ingenic,phy-clk-freq = <25000000>; + }; + + &sfc { diff --git a/br-ext-chip-ingenic/board/t40/kernel/t40.generic.config b/br-ext-chip-ingenic/board/t40/kernel/t40.generic.config new file mode 100644 index 00000000..60832098 --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/kernel/t40.generic.config @@ -0,0 +1,2244 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/mips 4.4.94 Kernel Configuration +# +CONFIG_MIPS=y + +# +# Machine selection +# +# CONFIG_MIPS_ALCHEMY is not set +# CONFIG_AR7 is not set +# CONFIG_ATH25 is not set +# CONFIG_ATH79 is not set +# CONFIG_BMIPS_GENERIC is not set +# CONFIG_BCM47XX is not set +# CONFIG_BCM63XX is not set +# CONFIG_MIPS_COBALT is not set +# CONFIG_MACH_DECSTATION is not set +# CONFIG_MACH_JAZZ is not set +# CONFIG_MACH_INGENIC is not set +# CONFIG_MACH_XBURST is not set +CONFIG_MACH_XBURST2=y +# CONFIG_LANTIQ is not set +# CONFIG_LASAT is not set +# CONFIG_MACH_LOONGSON32 is not set +# CONFIG_MACH_LOONGSON64 is not set +# CONFIG_MACH_PISTACHIO is not set +# CONFIG_MACH_XILFPGA is not set +# CONFIG_MIPS_MALTA is not set +# CONFIG_MIPS_SEAD3 is not set +# CONFIG_NEC_MARKEINS is not set +# CONFIG_MACH_VR41XX is not set +# CONFIG_NXP_STB220 is not set +# CONFIG_NXP_STB225 is not set +# CONFIG_PMC_MSP is not set +# CONFIG_RALINK is not set +# CONFIG_SGI_IP22 is not set +# CONFIG_SGI_IP27 is not set +# CONFIG_SGI_IP28 is not set +# CONFIG_SGI_IP32 is not set +# CONFIG_SIBYTE_CRHINE is not set +# CONFIG_SIBYTE_CARMEL is not set +# CONFIG_SIBYTE_CRHONE is not set +# CONFIG_SIBYTE_RHONE is not set +# CONFIG_SIBYTE_SWARM is not set +# CONFIG_SIBYTE_LITTLESUR is not set +# CONFIG_SIBYTE_SENTOSA is not set +# CONFIG_SIBYTE_BIGSUR is not set +# CONFIG_SNI_RM is not set +# CONFIG_MACH_TX39XX is not set +# CONFIG_MACH_TX49XX is not set +# CONFIG_MIKROTIK_RB532 is not set +# CONFIG_CAVIUM_OCTEON_SOC is not set +# CONFIG_NLM_XLR_BOARD is not set +# CONFIG_NLM_XLP_BOARD is not set +# CONFIG_MIPS_PARAVIRT is not set +CONFIG_EXTAL_CLOCK=24 + +# +# SOC Type Selection +# +CONFIG_SOC_T40=y +# CONFIG_SOC_X2000_V12 is not set +CONFIG_INGENIC_BUILTIN_DTB=y +CONFIG_DT_T40_SHARK=y +# CONFIG_RAW_BOOT is not set +# CONFIG_FPGA_TEST is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_SCHED_OMIT_FRAME_POINTER=y +# CONFIG_MIPS_CLOCK_VSYSCALL is not set +# CONFIG_ARCH_DMA_ADDR_T_64BIT is not set +CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_DMA_INGENIC_HIGHMEM_FLUSH=y +CONFIG_DMA_NONCOHERENT=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_SYS_HAS_EARLY_PRINTK=y +CONFIG_HOTPLUG_CPU=y +CONFIG_SYS_SUPPORTS_HOTPLUG_CPU=y +# CONFIG_MIPS_MACHINE is not set +# CONFIG_NO_IOPORT_MAP is not set +CONFIG_CPU_LITTLE_ENDIAN=y +CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y +# CONFIG_MIPS_HUGE_TLB_SUPPORT is not set +CONFIG_MIPS_SPRAM=y +CONFIG_MIPS_L1_CACHE_SHIFT=5 + +# +# CPU selection +# +# CONFIG_CPU_MIPS32_R1 is not set +CONFIG_CPU_MIPS32_R2=y +CONFIG_SYS_SUPPORTS_ZBOOT=y +CONFIG_SYS_HAS_CPU_MIPS32_R1=y +CONFIG_SYS_HAS_CPU_MIPS32_R2=y +CONFIG_WEAK_ORDERING=y +CONFIG_WEAK_REORDERING_BEYOND_LLSC=y +CONFIG_CPU_MIPS32=y +CONFIG_CPU_MIPSR2=y +CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y +CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y +CONFIG_CPU_SUPPORTS_CPUFREQ=y +CONFIG_HARDWARE_WATCHPOINTS=y + +# +# Kernel type +# +CONFIG_32BIT=y +CONFIG_PAGE_SIZE_4KB=y +# CONFIG_PAGE_SIZE_16KB is not set +# CONFIG_PAGE_SIZE_64KB is not set +CONFIG_FORCE_MAX_ZONEORDER=15 +CONFIG_BOARD_SCACHE=y +CONFIG_XBURST2_CPU_SCACHE=y +CONFIG_CPU_HAS_PREFETCH=y +CONFIG_CPU_GENERIC_DUMP_TLB=y +CONFIG_CPU_R4K_FPU=y +CONFIG_CPU_R4K_CACHE_TLB=y +CONFIG_CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS=y +# CONFIG_CPU_HAS_MSA is not set +CONFIG_CPU_HAS_SYNC=y +CONFIG_HIGHMEM=y +CONFIG_CPU_SUPPORTS_HIGHMEM=y +CONFIG_SYS_SUPPORTS_HIGHMEM=y +CONFIG_CPU_SUPPORTS_MSA=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_HAVE_MEMBLOCK_NODE_MAP=y +CONFIG_ARCH_DISCARD_MEMBLOCK=y +# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_COMPACTION=y +CONFIG_MIGRATION=y +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +# CONFIG_KSM is not set +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +# CONFIG_CLEANCACHE is not set +# CONFIG_FRONTSWAP is not set +# CONFIG_CMA is not set +# CONFIG_ZPOOL is not set +# CONFIG_ZBUD is not set +# CONFIG_ZSMALLOC is not set +# CONFIG_IDLE_PAGE_TRACKING is not set +CONFIG_SMP=y +CONFIG_SYS_SUPPORTS_SMP=y +CONFIG_NR_CPUS=2 +# CONFIG_HZ_24 is not set +# CONFIG_HZ_48 is not set +CONFIG_HZ_100=y +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +# CONFIG_HZ_1000 is not set +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=100 +CONFIG_SCHED_HRTICK=y +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y +CONFIG_PREEMPT_COUNT=y +# CONFIG_KEXEC is not set +# CONFIG_CRASH_DUMP is not set +# CONFIG_SECCOMP is not set +CONFIG_MIPS_O32_FP64_SUPPORT=y +CONFIG_USE_OF=y +CONFIG_BUILTIN_DTB=y +CONFIG_MIPS_NO_APPENDED_DTB=y +# CONFIG_MIPS_ELF_APPENDED_DTB is not set +# CONFIG_MIPS_RAW_APPENDED_DTB is not set +# CONFIG_MIPS_ZBOOT_APPENDED_DTB is not set +CONFIG_MIPS_CMDLINE_FROM_DTB=y +# CONFIG_MIPS_CMDLINE_DTB_EXTEND is not set +# CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER is not set +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_HAVE_LATENCYTOP_SUPPORT=y +CONFIG_PGTABLE_LEVELS=2 +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_IRQ_WORK=y +CONFIG_BUILDTIME_EXTABLE_SORT=y + +# +# General setup +# +CONFIG_INIT_ENV_ARG_LIMIT=32 +# CONFIG_FAST_BOOT is not set +CONFIG_CROSS_COMPILE="mips-linux-gnu-" +# CONFIG_COMPILE_TEST is not set +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_BZIP2=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_HAVE_KERNEL_LZ4=y +# CONFIG_KERNEL_GZIP is not set +# CONFIG_KERNEL_BZIP2 is not set +CONFIG_KERNEL_LZMA=y +# CONFIG_KERNEL_XZ is not set +# CONFIG_KERNEL_LZO is not set +# CONFIG_KERNEL_LZ4 is not set +CONFIG_DEFAULT_HOSTNAME="openipc" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +CONFIG_CROSS_MEMORY_ATTACH=y +# CONFIG_FHANDLE is not set +CONFIG_USELIB=y +# CONFIG_AUDIT is not set + +# +# IRQ subsystem +# +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_CHIP=y +CONFIG_IRQ_DOMAIN=y +# CONFIG_IRQ_DOMAIN_DEBUG is not set +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_ARCH_CLOCKSOURCE_DATA=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CMOS_UPDATE=y + +# +# Timers subsystem +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ_COMMON=y +# CONFIG_HZ_PERIODIC is not set +# CONFIG_NO_HZ_IDLE is not set +CONFIG_NO_HZ_FULL=y +# CONFIG_NO_HZ_FULL_ALL is not set +# CONFIG_NO_HZ_FULL_SYSIDLE is not set +# CONFIG_NO_HZ is not set +CONFIG_HIGH_RES_TIMERS=y + +# +# CPU/Task time and stats accounting +# +CONFIG_VIRT_CPU_ACCOUNTING=y +CONFIG_VIRT_CPU_ACCOUNTING_GEN=y +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set + +# +# RCU Subsystem +# +CONFIG_PREEMPT_RCU=y +# CONFIG_RCU_EXPERT is not set +CONFIG_SRCU=y +# CONFIG_TASKS_RCU is not set +CONFIG_RCU_STALL_COMMON=y +CONFIG_CONTEXT_TRACKING=y +# CONFIG_CONTEXT_TRACKING_FORCE is not set +# CONFIG_TREE_RCU_TRACE is not set +CONFIG_RCU_NOCB_CPU=y +CONFIG_RCU_NOCB_CPU_NONE=y +# CONFIG_RCU_NOCB_CPU_ZERO is not set +# CONFIG_RCU_NOCB_CPU_ALL is not set +# CONFIG_RCU_EXPEDITE_BOOT is not set +# CONFIG_BUILD_BIN2C is not set +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_LOG_CPU_MAX_BUF_SHIFT=12 +CONFIG_GENERIC_SCHED_CLOCK=y +CONFIG_CGROUPS=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +# CONFIG_CGROUP_PIDS is not set +# CONFIG_CGROUP_DEVICE is not set +# CONFIG_CPUSETS is not set +CONFIG_CGROUP_CPUACCT=y +# CONFIG_MEMCG is not set +CONFIG_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_CFS_BANDWIDTH is not set +CONFIG_RT_GROUP_SCHED=y +# CONFIG_BLK_CGROUP is not set +# CONFIG_CHECKPOINT_RESTORE is not set +# CONFIG_NAMESPACES is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_RELAY is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y +CONFIG_RD_XZ=y +CONFIG_RD_LZO=y +CONFIG_RD_LZ4=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_SYSCTL_EXCEPTION_TRACE=y +CONFIG_BPF=y +CONFIG_EXPERT=y +CONFIG_MULTIUSER=y +CONFIG_SGETMASK_SYSCALL=y +CONFIG_SYSFS_SYSCALL=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +# CONFIG_BPF_SYSCALL is not set +CONFIG_SHMEM=y +CONFIG_AIO=y +# CONFIG_ADVISE_SYSCALLS is not set +# CONFIG_USERFAULTFD is not set +CONFIG_MEMBARRIER=y +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y + +# +# Kernel Performance Events And Counters +# +# CONFIG_PERF_EVENTS is not set +# CONFIG_VM_EVENT_COUNTERS is not set +# CONFIG_SLUB_DEBUG is not set +# CONFIG_COMPAT_BRK is not set +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +CONFIG_SLUB_CPU_PARTIAL=y +# CONFIG_SYSTEM_DATA_VERIFICATION is not set +# CONFIG_PROFILING is not set +CONFIG_HAVE_OPROFILE=y +# CONFIG_KPROBES is not set +# CONFIG_JUMP_LABEL is not set +# CONFIG_UPROBES is not set +# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set +CONFIG_ARCH_USE_BUILTIN_BSWAP=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_ATTRS=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +CONFIG_HAVE_CC_STACKPROTECTOR=y +# CONFIG_CC_STACKPROTECTOR is not set +CONFIG_CC_STACKPROTECTOR_NONE=y +# CONFIG_CC_STACKPROTECTOR_REGULAR is not set +# CONFIG_CC_STACKPROTECTOR_STRONG is not set +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_MODULES_USE_ELF_REL=y +CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +CONFIG_CLONE_BACKWARDS=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +# CONFIG_ARCH_HAS_GCOV_PROFILE_ALL is not set +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +CONFIG_MODULE_FORCE_LOAD=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +# CONFIG_MODULE_SIG is not set +# CONFIG_MODULE_COMPRESS is not set +CONFIG_BLOCK=y +# CONFIG_LBDAF is not set +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_BSGLIB is not set +# CONFIG_BLK_DEV_INTEGRITY is not set +# CONFIG_BLK_CMDLINE_PARSER is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_AIX_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_EFI_PARTITION is not set +# CONFIG_SYSV68_PARTITION is not set +# CONFIG_CMDLINE_PARTITION is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_DEADLINE is not set +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" +CONFIG_UNINLINE_SPIN_UNLOCK=y +CONFIG_FREEZER=y + +# +# Bus options (PCI, PCMCIA, EISA, ISA, TC) +# +CONFIG_MMU=y +# CONFIG_PCCARD is not set + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +CONFIG_ARCH_BINFMT_ELF_STATE=y +CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y +CONFIG_BINFMT_SCRIPT=y +# CONFIG_HAVE_AOUT is not set +# CONFIG_BINFMT_MISC is not set +CONFIG_COREDUMP=y +CONFIG_TRAD_SIGNALS=y + +# +# Power management options +# +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +# CONFIG_SUSPEND_SKIP_SYNC is not set +# CONFIG_HIBERNATION is not set +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +# CONFIG_PM_AUTOSLEEP is not set +# CONFIG_PM_WAKELOCKS is not set +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +CONFIG_PM_CLK=y +# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set +CONFIG_MIPS_EXTERNAL_TIMER=y + +# +# CPU Power Management +# + +# +# CPU Frequency scaling +# +# CONFIG_CPU_FREQ is not set + +# +# CPU Idle +# +# CONFIG_CPU_IDLE is not set +# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +CONFIG_UNIX=y +# CONFIG_UNIX_DIAG is not set +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +CONFIG_NET_IPIP=y +# CONFIG_NET_IPGRE_DEMUX is not set +CONFIG_NET_IP_TUNNEL=y +# CONFIG_IP_MROUTE is not set +# CONFIG_SYN_COOKIES is not set +CONFIG_NET_UDP_TUNNEL=y +CONFIG_NET_FOU=y +# CONFIG_NET_FOU_IP_TUNNELS is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +CONFIG_INET_TUNNEL=y +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_INET_UDP_DIAG is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=y +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +# CONFIG_INET6_AH is not set +# CONFIG_INET6_ESP is not set +# CONFIG_INET6_IPCOMP is not set +# CONFIG_IPV6_MIP6 is not set +# CONFIG_IPV6_ILA is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +CONFIG_INET6_XFRM_MODE_TRANSPORT=y +CONFIG_INET6_XFRM_MODE_TUNNEL=y +CONFIG_INET6_XFRM_MODE_BEET=y +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +# CONFIG_IPV6_VTI is not set +CONFIG_IPV6_SIT=y +# CONFIG_IPV6_SIT_6RD is not set +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_GRE is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set +# CONFIG_IPV6_MROUTE is not set +# CONFIG_NETWORK_SECMARK is not set +CONFIG_NET_PTP_CLASSIFY=y +CONFIG_NETWORK_PHY_TIMESTAMPING=y +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_L2TP is not set +# CONFIG_STP is not set +CONFIG_BRIDGE=y +# CONFIG_BRIDGE_IGMP_SNOOPING is not set +CONFIG_HAVE_NET_DSA=y +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +CONFIG_LLC=y +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_PHONET is not set +# CONFIG_6LOWPAN is not set +# CONFIG_IEEE802154 is not set +# CONFIG_NET_SCHED is not set +# CONFIG_DCB is not set +# CONFIG_BATMAN_ADV is not set +# CONFIG_OPENVSWITCH is not set +# CONFIG_VSOCKETS is not set +# CONFIG_NETLINK_DIAG is not set +# CONFIG_MPLS is not set +# CONFIG_HSR is not set +# CONFIG_NET_SWITCHDEV is not set +# CONFIG_NET_L3_MASTER_DEV is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +# CONFIG_CGROUP_NET_PRIO is not set +# CONFIG_CGROUP_NET_CLASSID is not set +CONFIG_NET_RX_BUSY_POLL=y +CONFIG_BQL=y +CONFIG_BPF_JIT=y +CONFIG_NET_FLOW_LIMIT=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +CONFIG_WIRELESS=y +CONFIG_WEXT_CORE=y +CONFIG_WEXT_PROC=y +CONFIG_CFG80211=m +# CONFIG_NL80211_TESTMODE is not set +# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set +# CONFIG_CFG80211_REG_DEBUG is not set +# CONFIG_CFG80211_CERTIFICATION_ONUS is not set +CONFIG_CFG80211_DEFAULT_PS=y +# CONFIG_CFG80211_DEBUGFS is not set +# CONFIG_CFG80211_INTERNAL_REGDB is not set +CONFIG_CFG80211_CRDA_SUPPORT=y +CONFIG_CFG80211_WEXT=y +# CONFIG_LIB80211 is not set +CONFIG_MAC80211=m +CONFIG_MAC80211_HAS_RC=y +CONFIG_MAC80211_RC_MINSTREL=y +CONFIG_MAC80211_RC_MINSTREL_HT=y +# CONFIG_MAC80211_RC_MINSTREL_VHT is not set +CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y +CONFIG_MAC80211_RC_DEFAULT="minstrel_ht" +# CONFIG_MAC80211_MESH is not set +# CONFIG_MAC80211_DEBUGFS is not set +# CONFIG_MAC80211_MESSAGE_TRACING is not set +# CONFIG_MAC80211_DEBUG_MENU is not set +CONFIG_MAC80211_STA_HASH_MAX_SIZE=0 +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +# CONFIG_RFKILL_REGULATOR is not set +# CONFIG_NET_9P is not set +# CONFIG_CAIF is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_NFC is not set +# CONFIG_LWTUNNEL is not set +CONFIG_HAVE_BPF_JIT=y + +# +# Device Drivers +# +CONFIG_LZMADEVICE=y + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER=y +CONFIG_UEVENT_HELPER_PATH="/sbin/mdev" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_STANDALONE=y +# CONFIG_PREVENT_FIRMWARE_BUILD is not set +CONFIG_FW_LOADER=y +# CONFIG_FIRMWARE_IN_KERNEL is not set +CONFIG_EXTRA_FIRMWARE="" +# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set +# CONFIG_ALLOW_DEV_COREDUMP is not set +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_GENERIC_CPU_DEVICES is not set +CONFIG_REGMAP=y +CONFIG_REGMAP_MMIO=y +# CONFIG_DMA_SHARED_BUFFER is not set + +# +# Bus devices +# +# CONFIG_BRCMSTB_GISB_ARB is not set +# CONFIG_MIPS_CDMM is not set +# CONFIG_CONNECTOR is not set +CONFIG_MTD=y +# CONFIG_MTD_TESTS is not set +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_OF_PARTS=y +# CONFIG_MTD_AR7_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set +# CONFIG_SM_FTL is not set +# CONFIG_MTD_OOPS is not set +# CONFIG_MTD_SWAP is not set +# CONFIG_MTD_PARTITIONED_MASTER is not set + +# +# RAM/ROM/Flash chip drivers +# +# CONFIG_MTD_CFI is not set +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOCG3 is not set +# CONFIG_INGENIC_SFC_V1 is not set +CONFIG_INGENIC_SFC_V2=y +CONFIG_MTD_INGENIC_SFC_V2_NORFLASH=y +# CONFIG_MTD_INGENIC_SFC_V2_NANDFLASH is not set +CONFIG_SPI_STANDARD_MODE=y +# CONFIG_SPI_QUAD_MODE is not set +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_ONENAND is not set + +# +# LPDDR & LPDDR2 PCM memory drivers +# +# CONFIG_MTD_LPDDR is not set +# CONFIG_MTD_SPI_NOR is not set +# CONFIG_MTD_UBI is not set +CONFIG_DTC=y +CONFIG_OF=y +# CONFIG_OF_UNITTEST is not set +CONFIG_OF_FLATTREE=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_IRQ=y +CONFIG_OF_NET=y +CONFIG_OF_MDIO=y +CONFIG_OF_MTD=y +CONFIG_OF_RESERVED_MEM=y +# CONFIG_OF_OVERLAY is not set +CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_NULL_BLK is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=8192 +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_BLK_DEV_HD is not set +# CONFIG_BLK_DEV_RBD is not set + + +# +# Misc devices +# +# CONFIG_SENSORS_LIS3LV02D is not set +# CONFIG_AD525X_DPOT is not set +# CONFIG_DUMMY_IRQ is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_DS1682 is not set +# CONFIG_BMP085_I2C is not set +# CONFIG_USB_SWITCH_FSA9480 is not set +# CONFIG_SRAM is not set +# CONFIG_INGENIC_RSA is not set +CONFIG_RMEM=y +CONFIG_LOGGER=y +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EEPROM_93CX6 is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# CONFIG_SENSORS_LIS3_I2C is not set + +# +# Altera FPGA firmware download module +# +# CONFIG_ALTERA_STAPL is not set + +# +# Intel MIC Bus Driver +# + +# +# SCIF Bus Driver +# + +# +# Intel MIC Host Driver +# + +# +# Intel MIC Card Driver +# + +# +# SCIF Driver +# + +# +# Intel MIC Coprocessor State Management (COSM) Drivers +# +# CONFIG_ECHO is not set +# CONFIG_CXL_BASE is not set +# CONFIG_CXL_KERNEL_API is not set +# CONFIG_CXL_EEH is not set +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_DMA is not set +# CONFIG_SCSI_NETLINK is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set +CONFIG_NETDEVICES=y +CONFIG_NET_CORE=y +# CONFIG_BONDING is not set +# CONFIG_DUMMY is not set +# CONFIG_EQUALIZER is not set +CONFIG_MII=y +# CONFIG_NET_TEAM is not set +# CONFIG_MACVLAN is not set +# CONFIG_IPVLAN is not set +# CONFIG_VXLAN is not set +# CONFIG_GENEVE is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +CONFIG_TUN=m +# CONFIG_TUN_VNET_CROSS_LE is not set +# CONFIG_VETH is not set +# CONFIG_NLMON is not set + +# +# CAIF transport drivers +# + +# +# Distributed Switch Architecture drivers +# +# CONFIG_NET_DSA_MV88E6XXX is not set +# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set +CONFIG_ETHERNET=y +CONFIG_INGENIC_MAC=y +CONFIG_INGENIC_MAC_DMA_INTERFACES=y +# CONFIG_INGENIC_MAC_AXI_BUS is not set +CONFIG_INGENIC_MAC_AHB_BUS=y +# CONFIG_ALTERA_TSE is not set +# CONFIG_NET_VENDOR_ARC is not set +# CONFIG_NET_VENDOR_AURORA is not set +# CONFIG_NET_CADENCE is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_DM9000 is not set +# CONFIG_DNET is not set +# CONFIG_NET_VENDOR_EZCHIP is not set +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_ETHOC is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_RENESAS is not set +# CONFIG_NET_VENDOR_ROCKER is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_STMICRO is not set +CONFIG_NET_VENDOR_SYNOPSYS=y +# CONFIG_SYNOPSYS_DWC_ETH_QOS is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_AQUANTIA_PHY is not set +# CONFIG_AT803X_PHY is not set +# CONFIG_AMD_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_TERANETICS_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_BCM7XXX_PHY is not set +# CONFIG_BCM87XX_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_DP83848_PHY is not set +# CONFIG_DP83867_PHY is not set +# CONFIG_MICROCHIP_PHY is not set +# CONFIG_FIXED_PHY is not set +# CONFIG_MDIO_BITBANG is not set +# CONFIG_MDIO_GPIO is not set +# CONFIG_MDIO_BUS_MUX_GPIO is not set +# CONFIG_MDIO_BUS_MUX_MMIOREG is not set +# CONFIG_MDIO_BCM_UNIMAC is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +CONFIG_USB_NET_DRIVERS=y +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_RTL8152 is not set +# CONFIG_USB_LAN78XX is not set +# CONFIG_USB_USBNET is not set +# CONFIG_USB_IPHETH is not set +CONFIG_WLAN=y +# CONFIG_LIBERTAS_THINFIRM is not set +# CONFIG_AT76C50X_USB is not set +# CONFIG_USB_ZD1201 is not set +# CONFIG_USB_NET_RNDIS_WLAN is not set +# CONFIG_RTL8187 is not set +# CONFIG_MAC80211_HWSIM is not set +# CONFIG_ATH_CARDS is not set +# CONFIG_B43 is not set +# CONFIG_B43LEGACY is not set +# CONFIG_BRCMSMAC is not set +# CONFIG_BRCMFMAC is not set +# CONFIG_HOSTAP is not set +# CONFIG_LIBERTAS is not set +# CONFIG_P54_COMMON is not set +# CONFIG_RT2X00 is not set +# CONFIG_WL_MEDIATEK is not set +CONFIG_RTL_CARDS=m +# CONFIG_RTL8192CU is not set +# CONFIG_RTL8XXXU is not set +# CONFIG_WL_TI is not set +# CONFIG_ZD1211RW is not set +# CONFIG_MWIFIEX is not set +# CONFIG_CW1200 is not set +# CONFIG_RSI_91X is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_ISDN is not set +# CONFIG_NVM is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set +# CONFIG_INPUT_MATRIXKMAP is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_TTY=y +# CONFIG_VT is not set +CONFIG_UNIX98_PTYS=y +CONFIG_DEVPTS_MULTIPLE_INSTANCES=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=16 +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_N_GSM is not set +# CONFIG_TRACE_SINK is not set +CONFIG_DEVMEM=y +# CONFIG_DEVKMEM is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_SC16IS7XX is not set +# CONFIG_SERIAL_BCM63XX is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_SERIAL_ARC is not set +# CONFIG_SERIAL_FSL_LPUART is not set +# CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set +CONFIG_SERIAL_INGENIC_UART=y +CONFIG_SERIAL_INGENIC_CONSOLE=y +CONFIG_SERIAL_INGENIC_LARGE_BAUDRATE=y +CONFIG_SERIAL_INGENIC_MAGIC_SYSRQ=y +# CONFIG_TTY_PRINTK is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_XILLYBUS is not set + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +# CONFIG_I2C_MUX is not set +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_ALGOBIT=m + +# +# I2C Hardware Bus support +# + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_CBUS_GPIO is not set +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +# CONFIG_I2C_EMEV2 is not set +CONFIG_I2C_GPIO=m +# CONFIG_I2C_IMG is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_PXA_PCI is not set +# CONFIG_I2C_RK3X is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set +CONFIG_I2C_INGENIC=y +# CONFIG_I2C_NON_RESTART_MODE is not set +CONFIG_I2C_FIFO_LEN=64 +# CONFIG_I2C_DEBUG_INFO is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_ROBOTFUZZ_OSIF is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_SLAVE is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_SPI is not set +# CONFIG_SPMI is not set +# CONFIG_HSI is not set + +# +# PPS support +# +# CONFIG_PPS is not set + +# +# PPS generators support +# + +# +# PTP clock support +# +# CONFIG_PTP_1588_CLOCK is not set +# CONFIG_DP83640_PHY is not set +CONFIG_PINCTRL=y + +# +# Pin controllers +# +CONFIG_PINMUX=y +CONFIG_PINCONF=y +CONFIG_GENERIC_PINCONF=y +# CONFIG_DEBUG_PINCTRL is not set +# CONFIG_PINCTRL_AMD is not set +# CONFIG_PINCTRL_SINGLE is not set +CONFIG_PINCTRL_INGENIC=y +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIOLIB=y +CONFIG_GPIO_DEVRES=y +CONFIG_OF_GPIO=y +# CONFIG_DEBUG_GPIO is not set +CONFIG_GPIO_SYSFS=y + +# +# Memory mapped GPIO drivers +# +# CONFIG_GPIO_74XX_MMIO is not set +# CONFIG_GPIO_ALTERA is not set +# CONFIG_GPIO_DWAPB is not set +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_GRGPIO is not set +# CONFIG_GPIO_SYSCON is not set +# CONFIG_GPIO_XILINX is not set +# CONFIG_GPIO_ZX is not set + +# +# I2C GPIO expanders +# +# CONFIG_GPIO_ADP5588 is not set +# CONFIG_GPIO_ADNP is not set +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_SX150X is not set + +# +# MFD GPIO expanders +# + +# +# SPI or I2C GPIO expanders +# +# CONFIG_GPIO_MCP23S08 is not set + +# +# USB GPIO expanders +# +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_POWER_AVS is not set +# CONFIG_HWMON is not set +# CONFIG_THERMAL is not set +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_CORE=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +# CONFIG_GPIO_WATCHDOG is not set +# CONFIG_XILINX_WATCHDOG is not set +# CONFIG_CADENCE_WATCHDOG is not set +# CONFIG_DW_WATCHDOG is not set +# CONFIG_MAX63XX_WATCHDOG is not set +CONFIG_INGENIC_WDT=y +# CONFIG_BCM7038_WDT is not set +# CONFIG_IMGPDC_WDT is not set +# CONFIG_MEN_A21_WDT is not set + +# +# USB-based Watchdog Cards +# +# CONFIG_USBPCWATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set +CONFIG_BCMA_POSSIBLE=y + +# +# Broadcom specific AMBA +# +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +CONFIG_MFD_CORE=y +# CONFIG_MFD_AS3711 is not set +# CONFIG_MFD_AS3722 is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_ATMEL_FLEXCOM is not set +# CONFIG_MFD_ATMEL_HLCDC is not set +# CONFIG_MFD_BCM590XX is not set +# CONFIG_MFD_AXP20X is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_I2C is not set +# CONFIG_MFD_DA9055 is not set +# CONFIG_MFD_DA9062 is not set +# CONFIG_MFD_DA9063 is not set +# CONFIG_MFD_DA9150 is not set +# CONFIG_MFD_DLN2 is not set +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_MFD_HI6421_PMIC is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_INTEL_SOC_PMIC is not set +# CONFIG_MFD_INGENIC_SADC_V13 is not set +# CONFIG_MFD_INGENIC_SADC_AUX is not set +CONFIG_MFD_INGENIC_TCU=y +# CONFIG_MFD_KEMPLD is not set +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_MAX14577 is not set +# CONFIG_MFD_MAX77686 is not set +# CONFIG_MFD_MAX77693 is not set +# CONFIG_MFD_MAX77843 is not set +# CONFIG_MFD_MAX8907 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_MFD_MT6397 is not set +# CONFIG_MFD_MENF21BMC is not set +# CONFIG_MFD_VIPERBOARD is not set +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_RT5033 is not set +# CONFIG_MFD_RTSX_USB is not set +# CONFIG_MFD_RC5T583 is not set +# CONFIG_MFD_RN5T567 is not set +# CONFIG_MFD_RK808 is not set +# CONFIG_MFD_RN5T618 is not set +# CONFIG_MFD_SEC_CORE is not set +# CONFIG_MFD_SI476X_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SKY81452 is not set +# CONFIG_MFD_SMSC is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_MFD_STMPE is not set +CONFIG_MFD_SYSCON=y +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_LP3943 is not set +# CONFIG_MFD_LP8788 is not set +# CONFIG_MFD_PALMAS is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS65218 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS80031 is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_ARIZONA_I2C is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8994 is not set +CONFIG_REGULATOR=y +# CONFIG_REGULATOR_DEBUG is not set +CONFIG_REGULATOR_FIXED_VOLTAGE=y +# CONFIG_MEDIA_SUPPORT is not set + +# +# Graphics support +# +# CONFIG_DRM is not set + +# +# Frame buffer Devices +# +# CONFIG_FB is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set +# CONFIG_JZ_I2D is not set +# CONFIG_JZ_IPU is not set +# CONFIG_JZ_BSCALER is not set +# CONFIG_VGASTATE is not set +# CONFIG_SOUND is not set + +# +# HID support +# +CONFIG_HID=y +# CONFIG_HID_BATTERY_STRENGTH is not set +# CONFIG_HIDRAW is not set +# CONFIG_UHID is not set +CONFIG_HID_GENERIC=y + +# +# Special HID drivers +# +# CONFIG_HID_A4TECH is not set +# CONFIG_HID_ACRUX is not set +# CONFIG_HID_APPLE is not set +# CONFIG_HID_AUREAL is not set +# CONFIG_HID_BELKIN is not set +# CONFIG_HID_CHERRY is not set +# CONFIG_HID_CHICONY is not set +# CONFIG_HID_CYPRESS is not set +# CONFIG_HID_DRAGONRISE is not set +# CONFIG_HID_EMS_FF is not set +# CONFIG_HID_ELECOM is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_GEMBIRD is not set +# CONFIG_HID_GFRM is not set +# CONFIG_HID_KEYTOUCH is not set +# CONFIG_HID_KYE is not set +# CONFIG_HID_WALTOP is not set +# CONFIG_HID_GYRATION is not set +# CONFIG_HID_ICADE is not set +# CONFIG_HID_TWINHAN is not set +# CONFIG_HID_KENSINGTON is not set +# CONFIG_HID_LCPOWER is not set +# CONFIG_HID_LENOVO is not set +# CONFIG_HID_LOGITECH is not set +# CONFIG_HID_MAGICMOUSE is not set +# CONFIG_HID_MICROSOFT is not set +# CONFIG_HID_MONTEREY is not set +# CONFIG_HID_MULTITOUCH is not set +# CONFIG_HID_ORTEK is not set +# CONFIG_HID_PANTHERLORD is not set +# CONFIG_HID_PETALYNX is not set +# CONFIG_HID_PICOLCD is not set +# CONFIG_HID_PLANTRONICS is not set +# CONFIG_HID_PRIMAX is not set +# CONFIG_HID_SAITEK is not set +# CONFIG_HID_SAMSUNG is not set +# CONFIG_HID_SPEEDLINK is not set +# CONFIG_HID_STEELSERIES is not set +# CONFIG_HID_SUNPLUS is not set +# CONFIG_HID_RMI is not set +# CONFIG_HID_GREENASIA is not set +# CONFIG_HID_SMARTJOYPLUS is not set +# CONFIG_HID_TIVO is not set +# CONFIG_HID_TOPSEED is not set +# CONFIG_HID_THRUSTMASTER is not set +# CONFIG_HID_WACOM is not set +# CONFIG_HID_XINMO is not set +# CONFIG_HID_ZEROPLUS is not set +# CONFIG_HID_ZYDACRON is not set +# CONFIG_HID_SENSOR_HUB is not set + +# +# USB HID support +# +# CONFIG_USB_HID is not set +# CONFIG_HID_PID is not set + +# +# USB HID Boot Protocol drivers +# +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set + +# +# I2C HID support +# +# CONFIG_I2C_HID is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y + +# +# Miscellaneous USB options +# +CONFIG_USB_DEFAULT_PERSIST=y +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +# CONFIG_USB_ULPI_BUS is not set +# CONFIG_USB_MON is not set +# CONFIG_USB_WUSB_CBAF is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +# CONFIG_USB_XHCI_HCD is not set +# CONFIG_USB_EHCI_HCD is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_FOTG210_HCD is not set +# CONFIG_USB_OHCI_HCD is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_HCD_TEST_MODE is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USBIP_CORE is not set +# CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_DWC3 is not set +CONFIG_USB_DWC2=y +CONFIG_USB_DWC2_HOST=y + +# +# Gadget/Dual-role mode requires USB Gadget support to be enabled +# +CONFIG_USB_DWC2_DMA_BUFFER_MODE=y +# CONFIG_USB_DWC2_DMA_DESCRIPTOR_MODE is not set +# CONFIG_USB_DWC2_HIGHWIDTH_FIFO is not set +# CONFIG_USB_DWC2_DEBUG is not set +# CONFIG_USB_DWC2_TRACK_MISSED_SOFS is not set +# CONFIG_USB_ISP1760 is not set + +# +# USB port drivers +# +CONFIG_USB_SERIAL=m + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_EHSET_TEST_FIXTURE is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_EZUSB_FX2 is not set +# CONFIG_USB_HSIC_USB3503 is not set +# CONFIG_USB_LINK_LAYER_TEST is not set + +# +# USB Physical Layer drivers +# +CONFIG_USB_PHY=y +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_INGENIC_USBPHY is not set +# CONFIG_INGENIC_USBPHY_X1800 is not set +CONFIG_INGENIC_INNOPHY=y +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_ISP1301 is not set +# CONFIG_USB_GADGET is not set +# CONFIG_UWB is not set +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set + +# +# MMC/SD/SDIO Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=8 +CONFIG_MMC_BLOCK_BOUNCE=y +# CONFIG_SDIO_UART is not set +# CONFIG_MMC_TEST is not set + +# +# MMC/SD/SDIO Host Controller Drivers +# +CONFIG_MMC_SDHCI_INGENIC=y +CONFIG_MMC_SDHCI=y +# CONFIG_MMC_SDHCI_PLTFM is not set +# CONFIG_MMC_DW is not set +# CONFIG_MMC_VUB300 is not set +# CONFIG_MMC_USHC is not set +# CONFIG_MMC_USDHI6ROL0 is not set +# CONFIG_MMC_MTK is not set +# CONFIG_MEMSTICK is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_ACCESSIBILITY is not set +CONFIG_RTC_LIB=y +# CONFIG_RTC_CLASS is not set +CONFIG_DMADEVICES=y +# CONFIG_DMADEVICES_DEBUG is not set + +# +# DMA Devices +# +CONFIG_DMA_ENGINE=y +CONFIG_DMA_VIRTUAL_CHANNELS=y +CONFIG_DMA_OF=y +# CONFIG_FSL_EDMA is not set +# CONFIG_IMG_MDC_DMA is not set +# CONFIG_INTEL_IDMA64 is not set +CONFIG_INGENIC_PDMAC=y +# CONFIG_DW_DMAC is not set + +# +# DMA Clients +# +# CONFIG_ASYNC_TX_DMA is not set +# CONFIG_DMATEST is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_UIO is not set +# CONFIG_VIRT_DRIVERS is not set + +# +# Virtio drivers +# +# CONFIG_VIRTIO_MMIO is not set + +# +# Microsoft Hyper-V guest support +# +# CONFIG_STAGING is not set +# CONFIG_MIPS_PLATFORM_DEVICES is not set +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_COMMON_CLK=y + +# +# Common Clock Framework +# +# CONFIG_COMMON_CLK_SI5351 is not set +# CONFIG_COMMON_CLK_SI514 is not set +# CONFIG_COMMON_CLK_SI570 is not set +# CONFIG_COMMON_CLK_CDCE925 is not set +# CONFIG_COMMON_CLK_PWM is not set +# CONFIG_COMMON_CLK_PXA is not set +# CONFIG_COMMON_CLK_CDCE706 is not set +CONFIG_COMMON_CLK_INGENIC=y +CONFIG_INGENIC_CLK_DEBUG_FS=y +CONFIG_CLK_T40=y + +# +# Hardware Spinlock drivers +# + +# +# Clock Source drivers +# +CONFIG_CLKSRC_OF=y +CONFIG_CLKSRC_PROBE=y +# CONFIG_ARM_TIMER_SP804 is not set +# CONFIG_ATMEL_PIT is not set +# CONFIG_SH_TIMER_CMT is not set +# CONFIG_SH_TIMER_MTU2 is not set +# CONFIG_SH_TIMER_TMU is not set +# CONFIG_EM_TIMER_STI is not set +CONFIG_CLKSRC_INGENIC_CORE_OST=y +# CONFIG_MAILBOX is not set +# CONFIG_IOMMU_SUPPORT is not set + +# +# Remoteproc drivers +# +# CONFIG_STE_MODEM_RPROC is not set + +# +# Rpmsg drivers +# + +# +# SOC (System On Chip) specific Drivers +# +# CONFIG_SUNXI_SRAM is not set +# CONFIG_SOC_TI is not set +# CONFIG_PM_DEVFREQ is not set +# CONFIG_EXTCON is not set +# CONFIG_MEMORY is not set +# CONFIG_IIO is not set +CONFIG_PWM=y +CONFIG_PWM_SYSFS=y +# CONFIG_PWM_FSL_FTM is not set +# CONFIG_PWM_IMG is not set +# CONFIG_PWM_INGENIC_V2 is not set +# CONFIG_PWM_PCA9685 is not set +CONFIG_IRQCHIP=y +CONFIG_IRQ_MIPS_CPU=y +CONFIG_IRQ_INGENIC_CPU=y +CONFIG_INGENIC_INTC_CHIP=y +# CONFIG_IPACK_BUS is not set +# CONFIG_RESET_CONTROLLER is not set +# CONFIG_FMC is not set + +# +# PHY Subsystem +# +# CONFIG_GENERIC_PHY is not set +# CONFIG_PHY_PXA_28NM_HSIC is not set +# CONFIG_PHY_PXA_28NM_USB2 is not set +# CONFIG_BCM_KONA_USB2_PHY is not set +# CONFIG_PHY_SAMSUNG_USB2 is not set +# CONFIG_POWERCAP is not set +# CONFIG_MCB is not set + +# +# Performance monitor support +# +# CONFIG_RAS is not set + +# +# Android +# +# CONFIG_ANDROID is not set +# CONFIG_NVMEM is not set +# CONFIG_STM is not set +# CONFIG_STM_DUMMY is not set +# CONFIG_STM_SOURCE_CONSOLE is not set +# CONFIG_INTEL_TH is not set + +# +# FPGA Configuration Support +# +# CONFIG_FPGA is not set + +# +# Firmware Drivers +# +# CONFIG_FIRMWARE_MEMMAP is not set + +# +# File systems +# +# CONFIG_EXT2_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_NILFS2_FS is not set +# CONFIG_F2FS_FS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_FILE_LOCKING=y +# CONFIG_FSNOTIFY is not set +# CONFIG_DNOTIFY is not set +# CONFIG_INOTIFY_USER is not set +# CONFIG_FANOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_QUOTACTL is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set +CONFIG_OVERLAY_FS=y + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +# CONFIG_MSDOS_FS is not set +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +# CONFIG_PROC_PAGE_MONITOR is not set +# CONFIG_PROC_CHILDREN is not set +CONFIG_KERNFS=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMPFS_XATTR=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_CONFIGFS_FS=y +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_YAFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_JFFS2_FS_WRITEBUFFER is not set +# CONFIG_JFFS2_SUMMARY is not set +CONFIG_JFFS2_FS_XATTR=y +CONFIG_JFFS2_FS_POSIX_ACL=y +CONFIG_JFFS2_FS_SECURITY=y +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_ZLIB=y +# CONFIG_JFFS2_LZO is not set +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_JFFS2_CMODE_NONE is not set +CONFIG_JFFS2_CMODE_PRIORITY=y +# CONFIG_JFFS2_CMODE_SIZE is not set +# CONFIG_JFFS2_CMODE_FAVOURLZO is not set +# CONFIG_LOGFS is not set +# CONFIG_CRAMFS is not set +CONFIG_SQUASHFS=y +CONFIG_SQUASHFS_FILE_CACHE=y +# CONFIG_SQUASHFS_FILE_DIRECT is not set +CONFIG_SQUASHFS_DECOMP_SINGLE=y +# CONFIG_SQUASHFS_DECOMP_MULTI is not set +# CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU is not set +# CONFIG_SQUASHFS_XATTR is not set +# CONFIG_SQUASHFS_ZLIB is not set +# CONFIG_SQUASHFS_LZ4 is not set +# CONFIG_SQUASHFS_LZO is not set +CONFIG_SQUASHFS_XZ=y +# CONFIG_SQUASHFS_LZMA is not set +# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set +CONFIG_SQUASHFS_EMBEDDED=y +CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=1 +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_MINIX_FS_NATIVE_ENDIAN is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_PSTORE is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V2=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_SWAP is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +CONFIG_GRACE_PERIOD=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_SUNRPC_DEBUG is not set +# CONFIG_CEPH_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="utf-8" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_ROMAN is not set +# CONFIG_NLS_MAC_CELTIC is not set +# CONFIG_NLS_MAC_CENTEURO is not set +# CONFIG_NLS_MAC_CROATIAN is not set +# CONFIG_NLS_MAC_CYRILLIC is not set +# CONFIG_NLS_MAC_GAELIC is not set +# CONFIG_NLS_MAC_GREEK is not set +# CONFIG_NLS_MAC_ICELAND is not set +# CONFIG_NLS_MAC_INUIT is not set +# CONFIG_NLS_MAC_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +CONFIG_NLS_UTF8=y +# CONFIG_DLM is not set + +# +# Kernel hacking +# +CONFIG_TRACE_IRQFLAGS_SUPPORT=y + +# +# printk and dmesg options +# +CONFIG_PRINTK_TIME=y +CONFIG_MESSAGE_LOGLEVEL_DEFAULT=3 +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_DYNAMIC_DEBUG is not set + +# +# Compile-time checks and compiler options +# +# CONFIG_DEBUG_INFO is not set +# CONFIG_ENABLE_WARN_DEPRECATED is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_FRAME_WARN=1024 +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_READABLE_ASM is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_PAGE_OWNER is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1 +CONFIG_DEBUG_KERNEL=y + +# +# Memory Debugging +# +# CONFIG_PAGE_EXTENSION is not set +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_STATS is not set +CONFIG_HAVE_DEBUG_KMEMLEAK=y +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +# CONFIG_DEBUG_HIGHMEM is not set +CONFIG_HAVE_DEBUG_STACKOVERFLOW=y +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_SHIRQ is not set + +# +# Debug Lockups and Hangs +# +# CONFIG_LOCKUP_DETECTOR is not set +# CONFIG_DETECT_HUNG_TASK is not set +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_ON_OOPS_VALUE=0 +CONFIG_PANIC_TIMEOUT=10 +# CONFIG_SCHED_DEBUG is not set +# CONFIG_SCHED_INFO is not set +# CONFIG_SCHEDSTATS is not set +# CONFIG_SCHED_STACK_END_CHECK is not set +# CONFIG_DEBUG_TIMEKEEPING is not set +# CONFIG_TIMER_STATS is not set +# CONFIG_DEBUG_PREEMPT is not set + +# +# Lock Debugging (spinlocks, mutexes, etc...) +# +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_LOCK_TORTURE_TEST is not set +CONFIG_STACKTRACE=y +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_PI_LIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_CREDENTIALS is not set + +# +# RCU Debugging +# +# CONFIG_PROVE_RCU is not set +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_TORTURE_TEST is not set +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=21 +# CONFIG_RCU_TRACE is not set +# CONFIG_RCU_EQS_DEBUG is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_LATENCYTOP is not set +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACING_SUPPORT=y +# CONFIG_FTRACE is not set + +# +# Runtime Testing +# +# CONFIG_LKDTM is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_RBTREE_TEST is not set +# CONFIG_INTERVAL_TREE_TEST is not set +# CONFIG_PERCPU_TEST is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_TEST_HEXDUMP is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_TEST_PRINTF is not set +# CONFIG_TEST_RHASHTABLE is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_TEST_LKM is not set +# CONFIG_TEST_USER_COPY is not set +# CONFIG_TEST_BPF is not set +# CONFIG_TEST_FIRMWARE is not set +# CONFIG_TEST_UDELAY is not set +# CONFIG_MEMTEST is not set +# CONFIG_TEST_STATIC_KEYS is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +CONFIG_EARLY_PRINTK=y +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_DEBUG_ZBOOT is not set +# CONFIG_SPINLOCK_TEST is not set +# CONFIG_SCACHE_DEBUGFS is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFAULT_SECURITY="" +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_RNG_DEFAULT=y +CONFIG_CRYPTO_PCOMP2=y +CONFIG_CRYPTO_AKCIPHER2=y +# CONFIG_CRYPTO_RSA is not set +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_USER is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +CONFIG_CRYPTO_GF128MUL=y +CONFIG_CRYPTO_NULL=y +CONFIG_CRYPTO_NULL2=y +# CONFIG_CRYPTO_PCRYPT is not set +CONFIG_CRYPTO_WORKQUEUE=y +# CONFIG_CRYPTO_CRYPTD is not set +# CONFIG_CRYPTO_MCRYPTD is not set +CONFIG_CRYPTO_AUTHENC=y +# CONFIG_CRYPTO_TEST is not set + +# +# Authenticated Encryption with Associated Data +# +CONFIG_CRYPTO_CCM=m +CONFIG_CRYPTO_GCM=m +# CONFIG_CRYPTO_CHACHA20POLY1305 is not set +CONFIG_CRYPTO_SEQIV=y +# CONFIG_CRYPTO_ECHAINIV is not set + +# +# Block modes +# +CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_CTR=y +# CONFIG_CRYPTO_CTS is not set +CONFIG_CRYPTO_ECB=y +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set +# CONFIG_CRYPTO_KEYWRAP is not set + +# +# Hash modes +# +# CONFIG_CRYPTO_CMAC is not set +CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_CRC32 is not set +# CONFIG_CRYPTO_CRCT10DIF is not set +CONFIG_CRYPTO_GHASH=m +# CONFIG_CRYPTO_POLY1305 is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_MICHAEL_MIC=y +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_SHA256=y +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_ANUBIS is not set +CONFIG_CRYPTO_ARC4=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_CHACHA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_TWOFISH is not set + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +# CONFIG_CRYPTO_ZLIB is not set +# CONFIG_CRYPTO_LZO is not set +# CONFIG_CRYPTO_842 is not set +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set + +# +# Random Number Generation +# +# CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_DRBG_MENU=y +CONFIG_CRYPTO_DRBG_HMAC=y +# CONFIG_CRYPTO_DRBG_HASH is not set +# CONFIG_CRYPTO_DRBG_CTR is not set +CONFIG_CRYPTO_DRBG=y +CONFIG_CRYPTO_JITTERENTROPY=y +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +# CONFIG_CRYPTO_USER_API_RNG is not set +# CONFIG_CRYPTO_USER_API_AEAD is not set +# CONFIG_CRYPTO_HW is not set + +# +# Certificates for signature checking +# +# CONFIG_BINARY_PRINTF is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +# CONFIG_HAVE_ARCH_BITREVERSE is not set +CONFIG_RATIONAL=y +CONFIG_GENERIC_NET_UTILS=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IO=y +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +# CONFIG_CRC8 is not set +# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set +# CONFIG_RANDOM32_SELFTEST is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_LZ4_DECOMPRESS=y +CONFIG_XZ_DEC=y +# CONFIG_XZ_DEC_X86 is not set +# CONFIG_XZ_DEC_POWERPC is not set +# CONFIG_XZ_DEC_IA64 is not set +# CONFIG_XZ_DEC_ARM is not set +# CONFIG_XZ_DEC_ARMTHUMB is not set +# CONFIG_XZ_DEC_SPARC is not set +# CONFIG_XZ_DEC_BCJ is not set +# CONFIG_XZ_DEC_TEST is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DECOMPRESS_BZIP2=y +CONFIG_DECOMPRESS_LZMA=y +CONFIG_DECOMPRESS_XZ=y +CONFIG_DECOMPRESS_LZO=y +CONFIG_DECOMPRESS_LZ4=y +CONFIG_DECOMPRESS_LZMA_NEEDED=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HAS_DMA=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_NLATTR=y +CONFIG_GENERIC_ATOMIC64=y +CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y +# CONFIG_CORDIC is not set +# CONFIG_DDR is not set +CONFIG_LIBFDT=y +# CONFIG_SG_SPLIT is not set +# CONFIG_ARCH_HAS_SG_CHAIN is not set +# CONFIG_HAVE_KVM is not set +# CONFIG_VIRTUALIZATION is not set diff --git a/br-ext-chip-ingenic/board/t40/t40.config b/br-ext-chip-ingenic/board/t40/t40.config new file mode 100644 index 00000000..0e33baba --- /dev/null +++ b/br-ext-chip-ingenic/board/t40/t40.config @@ -0,0 +1,2 @@ +MEM_START_ADDR=0x? +KERNEL_UPLOAD_ADDR=0x? diff --git a/br-ext-chip-ingenic/configs/t40_lite_defconfig b/br-ext-chip-ingenic/configs/t40_lite_defconfig new file mode 100644 index 00000000..1e67d511 --- /dev/null +++ b/br-ext-chip-ingenic/configs/t40_lite_defconfig @@ -0,0 +1,108 @@ +# Architecture +BR2_mipsel=y +BR2_mips_xburst=y +# BR2_MIPS_SOFT_FLOAT is not set +BR2_MIPS_FP32_MODE_64=y +# BR2_MIPS_FP32_MODE_XX is not set +BR2_MIPS_NAN_LEGACY=y +BR2_MIPS_OABI32=y +BR2_KERNEL_HEADERS_VERSION=y +BR2_DEFAULT_KERNEL_VERSION="4.4.94" +BR2_PACKAGE_HOST_LINUX_HEADERS_CUSTOM_4_4=y + +# Toolchain +BR2_PER_PACKAGE_DIRECTORIES=y +BR2_GCC_VERSION_8_X=y +# BR2_TOOLCHAIN_USES_UCLIBC is not set +# BR2_TOOLCHAIN_BUILDROOT_UCLIBC is not set +# BR2_TOOLCHAIN_BUILDROOT_LIBC="uclibc" +BR2_EXTRA_GCC_CONFIG_OPTIONS="--with-float=hard" +BR2_TOOLCHAIN_USES_MUSL=y +BR2_TOOLCHAIN_BUILDROOT_MUSL=y +BR2_TOOLCHAIN_BUILDROOT_LIBC="musl" +BR2_TOOLCHAIN_BUILDROOT_CXX=y +BR2_TOOLCHAIN_BUILDROOT_LOCALE=y +BR2_TOOLCHAIN_BUILDROOT_USE_SSP=y + +# Kernel +BR2_LINUX_KERNEL=y +BR2_LINUX_KERNEL_CUSTOM_VERSION=y +BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="4.4.94" +BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y +BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="$(BR2_EXTERNAL_INGENIC_PATH)/board/t40/kernel/t40.generic.config" +BR2_LINUX_KERNEL_UIMAGE=y +BR2_LINUX_KERNEL_LZMA=y +BR2_LINUX_KERNEL_EXT_INGENIC_PATCHER=y +BR2_LINUX_KERNEL_EXT_INGENIC_PATCHER_LIST="$(BR2_EXTERNAL_INGENIC_PATH)/board/t40/kernel/patches/ $(BR2_EXTERNAL_INGENIC_PATH)/board/t40/kernel/overlay" + +# Filesystem +# BR2_TARGET_TZ_INFO is not set +BR2_TARGET_ROOTFS_CPIO=y +BR2_TARGET_ROOTFS_SQUASHFS=y +BR2_TARGET_ROOTFS_SQUASHFS4_XZ=y +BR2_ROOTFS_OVERLAY="$(TOPDIR)/../general/overlay" +BR2_ROOTFS_POST_BUILD_SCRIPT="$(TOPDIR)/../scripts/executing_commands_for_$(BR2_TOOLCHAIN_BUILDROOT_LIBC).sh" + +# OpenIPC configuration +BR2_TOOLCHAIN_BUILDROOT_VENDOR="openipc" +BR2_TARGET_GENERIC_ISSUE="Welcome to OpenIPC" +BR2_TARGET_GENERIC_HOSTNAME="openipc-t40" +BR2_GLOBAL_PATCH_DIR="$(TOPDIR)/../general/package/all-patches" + +# OpenIPC packages +BR2_PACKAGE_BUSYBOX_CONFIG="$(TOPDIR)/../general/package/busybox/busybox.config" +BR2_PACKAGE_DROPBEAR_OPENIPC=y +# BR2_PACKAGE_FDK_AAC_OPENIPC is not set +BR2_PACKAGE_FWPRINTENV_OPENIPC=y +# BR2_PACKAGE_INGENIC_OSDRV_T40 is not set +BR2_PACKAGE_HASERL=y +# BR2_PACKAGE_HISI_GPIO is not set +BR2_PACKAGE_IPCTOOL=y +BR2_PACKAGE_JSON_C=y +BR2_PACKAGE_JSONFILTER=y +BR2_PACKAGE_LIBCURL_OPENIPC=y +BR2_PACKAGE_LIBCURL_OPENIPC_CURL=y +# BR2_PACKAGE_LIBCURL_OPENIPC_VERBOSE is not set +# BR2_PACKAGE_LIBCURL_OPENIPC_PROXY_SUPPORT is not set +# BR2_PACKAGE_LIBCURL_OPENIPC_COOKIES_SUPPORT is not set +# BR2_PACKAGE_LIBCURL_OPENIPC_EXTRA_PROTOCOLS_FEATURES is not set +BR2_PACKAGE_LIBCURL_OPENIPC_MBEDTLS=y +BR2_PACKAGE_LIBEVENT_OPENIPC=y +BR2_PACKAGE_LIBEVENT_OPENIPC_REMOVE_PYSCRIPT=y +BR2_PACKAGE_LIBOGG_OPENIPC=y +BR2_PACKAGE_LIBYAML=y +BR2_PACKAGE_MAJESTIC_FONTS=y +# BR2_PACKAGE_MAJESTIC is not set +BR2_PACKAGE_MBEDTLS_OPENIPC=y +# BR2_PACKAGE_MBEDTLS_OPENIPC_PROGRAMS is not set +# BR2_PACKAGE_MBEDTLS_OPENIPC_COMPRESSION is not set +BR2_PACKAGE_MICROBE_WEB=y +# BR2_PACKAGE_MINI_SNMPD is not set +BR2_PACKAGE_MOTORS=y +BR2_PACKAGE_OPUS_OPENIPC=y +BR2_PACKAGE_OPUS_OPENIPC_FIXED_POINT=y +# BR2_PACKAGE_SSHPASS is not set +BR2_PACKAGE_UACME_OPENIPC=y +BR2_PACKAGE_VTUND_OPENIPC=y +BR2_PACKAGE_YAML_CLI=y +BR2_PACKAGE_QUIRC_OPENIPC=y + +# WiFi +BR2_PACKAGE_WIRELESS_TOOLS=y +BR2_PACKAGE_WPA_SUPPLICANT=y +BR2_PACKAGE_WPA_SUPPLICANT_CLI=y +BR2_PACKAGE_WPA_SUPPLICANT_NL80211=y +BR2_PACKAGE_WPA_SUPPLICANT_PASSPHRASE=y +BR2_PACKAGE_LINUX_FIRMWARE_OPENIPC=y +# BR2_PACKAGE_LINUX_FIRMWARE_OPENIPC_MT7601U is not set +# BR2_PACKAGE_RTL8188EU is not set + +# WIREGUARD +BR2_PACKAGE_WIREGUARD_LINUX_COMPAT=y +BR2_PACKAGE_WIREGUARD_TOOLS=y + +# DEBUG +BR2_PACKAGE_HOST_GDB=y +BR2_PACKAGE_GDB=y + +BR2_PACKAGE_ZLIB=y diff --git a/br-ext-chip-ingenic/configs/t40_ultimate_defconfig b/br-ext-chip-ingenic/configs/t40_ultimate_defconfig new file mode 100644 index 00000000..2fbedb41 --- /dev/null +++ b/br-ext-chip-ingenic/configs/t40_ultimate_defconfig @@ -0,0 +1,114 @@ +# Architecture +BR2_mipsel=y +BR2_mips_xburst=y +# BR2_MIPS_SOFT_FLOAT is not set +BR2_MIPS_FP32_MODE_64=y +# BR2_MIPS_FP32_MODE_XX is not set +BR2_MIPS_NAN_LEGACY=y +BR2_MIPS_OABI32=y +BR2_KERNEL_HEADERS_VERSION=y +BR2_DEFAULT_KERNEL_VERSION="4.4.94" +BR2_PACKAGE_HOST_LINUX_HEADERS_CUSTOM_4_4=y + +# Toolchain +BR2_PER_PACKAGE_DIRECTORIES=y +BR2_GCC_VERSION_8_X=y +# BR2_TOOLCHAIN_USES_UCLIBC is not set +# BR2_TOOLCHAIN_BUILDROOT_UCLIBC is not set +# BR2_TOOLCHAIN_BUILDROOT_LIBC="uclibc" +BR2_EXTRA_GCC_CONFIG_OPTIONS="--with-float=hard" +BR2_TOOLCHAIN_USES_MUSL=y +BR2_TOOLCHAIN_BUILDROOT_MUSL=y +BR2_TOOLCHAIN_BUILDROOT_LIBC="musl" +BR2_TOOLCHAIN_BUILDROOT_CXX=y +BR2_TOOLCHAIN_BUILDROOT_LOCALE=y +BR2_TOOLCHAIN_BUILDROOT_USE_SSP=y + +# Kernel +BR2_LINUX_KERNEL=y +BR2_LINUX_KERNEL_CUSTOM_VERSION=y +BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="4.4.94" +BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y +BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="$(BR2_EXTERNAL_INGENIC_PATH)/board/t40/kernel/t40.generic.config" +BR2_LINUX_KERNEL_UIMAGE=y +BR2_LINUX_KERNEL_LZMA=y +BR2_LINUX_KERNEL_EXT_INGENIC_PATCHER=y +BR2_LINUX_KERNEL_EXT_INGENIC_PATCHER_LIST="$(BR2_EXTERNAL_INGENIC_PATH)/board/t40/kernel/patches/ $(BR2_EXTERNAL_INGENIC_PATH)/board/t40/kernel/overlay" + +# Filesystem +# BR2_TARGET_TZ_INFO is not set +BR2_TARGET_ROOTFS_CPIO=y +BR2_TARGET_ROOTFS_SQUASHFS=y +BR2_TARGET_ROOTFS_SQUASHFS4_XZ=y +BR2_ROOTFS_OVERLAY="$(TOPDIR)/../general/overlay" +BR2_ROOTFS_POST_BUILD_SCRIPT="$(TOPDIR)/../scripts/executing_commands_for_$(BR2_TOOLCHAIN_BUILDROOT_LIBC).sh" + +# OpenIPC configuration +BR2_TOOLCHAIN_BUILDROOT_VENDOR="openipc" +BR2_TARGET_GENERIC_ISSUE="Welcome to OpenIPC" +BR2_TARGET_GENERIC_HOSTNAME="openipc-t40" +BR2_GLOBAL_PATCH_DIR="$(TOPDIR)/../general/package/all-patches" + +# OpenIPC packages +BR2_PACKAGE_BUSYBOX_CONFIG="$(TOPDIR)/../general/package/busybox/busybox.config" +BR2_PACKAGE_DROPBEAR_OPENIPC=y +# BR2_PACKAGE_FDK_AAC_OPENIPC is not set +BR2_PACKAGE_FWPRINTENV_OPENIPC=y +# BR2_PACKAGE_INGENIC_OSDRV_T40 is not set +BR2_PACKAGE_HASERL=y +# BR2_PACKAGE_HISI_GPIO is not set +BR2_PACKAGE_IPCTOOL=y +BR2_PACKAGE_JSON_C=y +BR2_PACKAGE_JSONFILTER=y +BR2_PACKAGE_LIBCURL_OPENIPC=y +BR2_PACKAGE_LIBCURL_OPENIPC_CURL=y +# BR2_PACKAGE_LIBCURL_OPENIPC_VERBOSE is not set +# BR2_PACKAGE_LIBCURL_OPENIPC_PROXY_SUPPORT is not set +# BR2_PACKAGE_LIBCURL_OPENIPC_COOKIES_SUPPORT is not set +# BR2_PACKAGE_LIBCURL_OPENIPC_EXTRA_PROTOCOLS_FEATURES is not set +BR2_PACKAGE_LIBCURL_OPENIPC_MBEDTLS=y +BR2_PACKAGE_LIBEVENT_OPENIPC=y +BR2_PACKAGE_LIBEVENT_OPENIPC_REMOVE_PYSCRIPT=y +BR2_PACKAGE_LIBOGG_OPENIPC=y +BR2_PACKAGE_LIBYAML=y +BR2_PACKAGE_MAJESTIC_FONTS=y +# BR2_PACKAGE_MAJESTIC is not set +BR2_PACKAGE_MBEDTLS_OPENIPC=y +# BR2_PACKAGE_MBEDTLS_OPENIPC_PROGRAMS is not set +# BR2_PACKAGE_MBEDTLS_OPENIPC_COMPRESSION is not set +BR2_PACKAGE_MICROBE_WEB=y +# BR2_PACKAGE_MINI_SNMPD is not set +BR2_PACKAGE_MOTORS=y +BR2_PACKAGE_OPUS_OPENIPC=y +BR2_PACKAGE_OPUS_OPENIPC_FIXED_POINT=y +# BR2_PACKAGE_SSHPASS is not set +BR2_PACKAGE_UACME_OPENIPC=y +BR2_PACKAGE_VTUND_OPENIPC=y +BR2_PACKAGE_YAML_CLI=y +BR2_PACKAGE_QUIRC_OPENIPC=y + +# WiFi +BR2_PACKAGE_WIRELESS_TOOLS=y +BR2_PACKAGE_WPA_SUPPLICANT=y +BR2_PACKAGE_WPA_SUPPLICANT_CLI=y +BR2_PACKAGE_WPA_SUPPLICANT_NL80211=y +BR2_PACKAGE_WPA_SUPPLICANT_PASSPHRASE=y +BR2_PACKAGE_LINUX_FIRMWARE_OPENIPC=y +# BR2_PACKAGE_LINUX_FIRMWARE_OPENIPC_MT7601U is not set +# BR2_PACKAGE_RTL8188EU is not set + +# WIREGUARD +BR2_PACKAGE_WIREGUARD_LINUX_COMPAT=y +BR2_PACKAGE_WIREGUARD_TOOLS=y + +# ZEROTIER +BR2_PACKAGE_ZEROTIER_ONE=y + +# NABTO +BR2_PACKAGE_NABTO is not set + +# DEBUG +BR2_PACKAGE_HOST_GDB=y +BR2_PACKAGE_GDB=y + +BR2_PACKAGE_ZLIB=y diff --git a/br-ext-chip-ingenic/package/ingenic-osdrv-t40 b/br-ext-chip-ingenic/package/ingenic-osdrv-t40 new file mode 120000 index 00000000..38487df3 --- /dev/null +++ b/br-ext-chip-ingenic/package/ingenic-osdrv-t40 @@ -0,0 +1 @@ +../../general/package/ingenic-osdrv-t40 \ No newline at end of file diff --git a/general/package/ingenic-osdrv-t40/Config.in b/general/package/ingenic-osdrv-t40/Config.in new file mode 100644 index 00000000..5f47d4af --- /dev/null +++ b/general/package/ingenic-osdrv-t40/Config.in @@ -0,0 +1,6 @@ +config BR2_PACKAGE_INGENIC_OSDRV_T40 + bool "ingenic-osdrv-t40" + help + ingenic-osdrv-t40 - Ingenic kernel modules and libs + + https://openipc.org diff --git a/general/package/ingenic-osdrv-t40/files/script/S95ingenic b/general/package/ingenic-osdrv-t40/files/script/S95ingenic new file mode 100755 index 00000000..005dc6bf --- /dev/null +++ b/general/package/ingenic-osdrv-t40/files/script/S95ingenic @@ -0,0 +1,86 @@ +#!/bin/sh + +DAEMON="majestic" +PIDFILE="/var/run/$DAEMON.pid" + +DAEMON_ARGS="-s" + +# shellcheck source=/dev/null +[ -r "/etc/default/$DAEMON" ] && . "/etc/default/$DAEMON" + +load_majestic() { + printf 'Starting %s: ' "$DAEMON" + [ -f /usr/bin/$DAEMON ] || echo -en "DISABLED, " + # shellcheck disable=SC2086 # we need the word splitting + [ -f /etc/coredump.conf ] && . /etc/coredump.conf + if [ "$coredump_enabled" ]; then + [ "$(yaml-cli -i /etc/majestic.yaml -g .watchdog.timeout)" -lt "30" ] && yaml-cli -i /etc/majestic.yaml -s .watchdog.timeout 30 + ulimit -c unlimited && echo "|/usr/sbin/sendcoredump.sh" >/proc/sys/kernel/core_pattern + fi + start-stop-daemon -b -m -S -q -p "$PIDFILE" -x "/usr/bin/$DAEMON" \ + -- $DAEMON_ARGS + status=$? + if [ "$status" -eq 0 ]; then + echo "OK" + else + echo "FAIL" + fi + return "$status" +} + +# The daemon does not create a pidfile, and use "-m" to instruct start-stop-daemon to create one. +start() { + logger -s -p daemon.info -t ingenic "Check MAC for Ingenic devices" + if [ "$(fw_printenv -n ethaddr)" = "00:00:23:34:45:66" ]; then + logger -s -p daemon.info -t ingenic "The eth0 interface has a lousy MAC, please change it.." + else + logger -s -p daemon.info -t ingenic "The eth0 interface has a correct MAC - $(fw_printenv -n ethaddr)" + fi + # + logger -s -p daemon.info -t ingenic "Loading of kernel modules and initialization of the video system has started" + export TZ=$(cat /etc/TZ) + load_ingenic + # + # + # export SENSOR=$(fw_printenv -n sensor) + export SENSOR=$(cat /proc/jz/sinfo/info | sed -e 's/.*://') + SENSOR=$(cat /proc/jz/sinfo/info | sed -e 's/.*://') + if [ "sensor not found" = "$SENSOR" ]; then + unset SENSOR + else + export SENSOR=$SENSOR + fi + load_majestic +} + +stop() { + printf 'Stopping %s: ' "$DAEMON" + [ -f /usr/bin/$DAEMON ] || echo -en "DISABLED, " + start-stop-daemon -K -q -p "$PIDFILE" + status=$? + if [ "$status" -eq 0 ]; then + rm -f "$PIDFILE" + echo "OK" + else + echo "FAIL" + fi + return "$status" +} + +restart() { + stop + sleep 1 + reload +} + +reload() { + load_majestic +} + +case "$1" in + start|stop|restart|reload) + "$1";; + *) + echo "Usage: $0 {start|stop|restart|reload}" + exit 1 +esac diff --git a/general/package/ingenic-osdrv-t40/files/script/ircut_demo b/general/package/ingenic-osdrv-t40/files/script/ircut_demo new file mode 100755 index 00000000..fe257338 --- /dev/null +++ b/general/package/ingenic-osdrv-t40/files/script/ircut_demo @@ -0,0 +1,27 @@ +if [ ! -d "/sys/class/gpio/gpio49" ] +then +echo 49 > /sys/class/gpio/export +fi +if [ ! -d "/sys/class/gpio/gpio50" ] +then +echo 50 > /sys/class/gpio/export +fi + +echo out > /sys/class/gpio/gpio49/direction +echo out > /sys/class/gpio/gpio50/direction + +echo 0 > /sys/class/gpio/gpio49/active_low +echo 0 > /sys/class/gpio/gpio50/active_low + + +echo 0 > /sys/class/gpio/gpio49/value + +usleep 10000 + +echo $1 > /sys/class/gpio/gpio49/value +echo $2 > /sys/class/gpio/gpio50/value + + +usleep 10000 +echo 0 > /sys/class/gpio/gpio49/value +echo 0 > /sys/class/gpio/gpio50/value diff --git a/general/package/ingenic-osdrv-t40/files/script/load_ingenic b/general/package/ingenic-osdrv-t40/files/script/load_ingenic new file mode 100755 index 00000000..8b668e49 --- /dev/null +++ b/general/package/ingenic-osdrv-t40/files/script/load_ingenic @@ -0,0 +1,87 @@ +#!/bin/sh + +KMOD_PATH=/lib/modules/4.4.94/ingenic + +echo 1 >/proc/sys/vm/overcommit_memory + +check_return() { + if [ $? -ne 0 ]; then + echo err: $1 + echo exit + exit + fi +} + +lsmod | grep "avpu" >/dev/null +if [ $? -ne 0 ]; then + insmod ${KMOD_PATH/%\//}/avpu.ko clk_name='vpll' avpu_clk=400000000 + check_return "insmod avpu" +fi + +lsmod | grep "sinfo" >/dev/null +if [ $? -ne 0 ]; then + insmod ${KMOD_PATH/%\//}/sinfo.ko + check_return "insmod sinfo" +fi +echo 1 >/proc/jz/sinfo/info +check_return "start sinfo" + +if fw_printenv -n sensor >/dev/null; then + export SENSOR=$(fw_printenv -n sensor) + logger -s -p daemon.info -t ingenic "Get data from environment and set SENSOR as ${SENSOR}" +else + SENSOR_INFO=$(cat /proc/jz/sinfo/info) + check_return "get sensor type" + SENSOR=${SENSOR_INFO#*:} + if [ "sensor not found" = "$SENSOR" ]; then + unset SENSOR + fw_setenv sensor + else + logger -s -p daemon.info -t ingenic "Get data from sinfo and set SENSOR as ${SENSOR}" + fw_setenv sensor $SENSOR && logger -s -p daemon.info -t ingenic "Write detected ${SENSOR} to U-Boot ENV" + fi +fi + + +case ${SENSOR} in +"imx415") + ISP_PARAM="350000000" + SENSOR_PARAM="" + ;; +*) + ISP_PARAM="isp_clk=350000000" + SENSOR_PARAM="" + break + ;; +esac + +echo -------------------- +echo "ISP_PARAM: ${ISP_PARAM}" +echo "SENSOR: ${SENSOR}" +echo "SENSOR_PARAM: ${SENSOR_PARAM}" +echo -------------------- + +lsmod | grep "tx_isp" >/dev/null +if [ $? -ne 0 ]; then + insmod ${KMOD_PATH/%\//}/tx-isp-t40.ko ${ISP_PARAM} + check_return "insmod isp drv" +fi + +lsmod | grep "audio" >/dev/null +if [ $? -ne 0 ]; then + insmod ${KMOD_PATH/%\//}/audio.ko + check_return "insmod audio" +fi + +lsmod | grep ${SENSOR} >/dev/null +if [ $? -ne 0 ]; then + insmod ${KMOD_PATH/%\//}/sensor_${SENSOR}_t40.ko ${SENSOR_PARAM} + check_return "insmod sensor drv" +fi +# +# Need for claim gpio +insmod ${KMOD_PATH/%\//}/gpio.ko +echo $(yaml-cli -i /etc/majestic.yaml -g .nightMode.irCutPin1) >/proc/jz/claim/gpio +echo $(yaml-cli -i /etc/majestic.yaml -g .nightMode.irCutPin2) >/proc/jz/claim/gpio +# echo $(yaml-cli -i /etc/majestic.yaml -g .nightMode.irSensorPin) >/proc/jz/claim/gpio +# diff --git a/general/package/ingenic-osdrv-t40/ingenic-osdrv-t40.mk b/general/package/ingenic-osdrv-t40/ingenic-osdrv-t40.mk new file mode 100644 index 00000000..3414c9a7 --- /dev/null +++ b/general/package/ingenic-osdrv-t40/ingenic-osdrv-t40.mk @@ -0,0 +1,24 @@ +################################################################################ +# +# ingenic-osdrv-t40 +# +################################################################################ + +INGENIC_OSDRV_T40_VERSION = +INGENIC_OSDRV_T40_SITE = +INGENIC_OSDRV_T40_LICENSE = MIT +INGENIC_OSDRV_T40_LICENSE_FILES = LICENSE + +define INGENIC_OSDRV_T40_INSTALL_TARGET_CMDS +# $(INSTALL) -m 755 -d $(TARGET_DIR)/etc/init.d +# $(INSTALL) -m 755 -t $(TARGET_DIR)/etc/init.d $(BR2_EXTERNAL_INGENIC_PATH)/package/ingenic-osdrv-t40/files/script/S95ingenic + + $(INSTALL) -m 755 -d $(TARGET_DIR)/usr/bin + $(INSTALL) -m 755 -t $(TARGET_DIR)/usr/bin $(BR2_EXTERNAL_INGENIC_PATH)/package/ingenic-osdrv-t40/files/script/load* + $(INSTALL) -m 755 -t $(TARGET_DIR)/usr/bin $(BR2_EXTERNAL_INGENIC_PATH)/package/ingenic-osdrv-t40/files/script/ircut_demo + +# $(INSTALL) -m 755 -d $(TARGET_DIR)/usr/lib +# $(INSTALL) -m 644 -t $(TARGET_DIR)/usr/lib/ $(BR2_EXTERNAL_INGENIC_PATH)/package/ingenic-osdrv-t40/files/lib/*.so +endef + +$(eval $(generic-package))